diff mbox

[RFC] hw/i386: Composite Bus and PCI device

Message ID 1465380032-12807-2-git-send-email-davidkiarie4@gmail.com (mailing list archive)
State New, archived
Headers show

Commit Message

David Kiarie June 8, 2016, 10 a.m. UTC
Sample composite SysBus and PCI device similar to AMD IOMMU setup

Signed-off-by: David Kiarie <davidkiarie4@gmail.com>
---
 hw/i386/compositedevice.c | 113 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 113 insertions(+)
 create mode 100644 hw/i386/compositedevice.c

Comments

Eduardo Habkost June 8, 2016, 3:25 p.m. UTC | #1
On Wed, Jun 08, 2016 at 01:00:32PM +0300, David Kiarie wrote:
> Sample composite SysBus and PCI device similar to AMD IOMMU setup
> 
> Signed-off-by: David Kiarie <davidkiarie4@gmail.com>
> ---
>  hw/i386/compositedevice.c | 113 ++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 113 insertions(+)
>  create mode 100644 hw/i386/compositedevice.c

The filename is very generic (hw/i386/compositedevice.c), but it
has lots of AMD-specific names.

Is your plan to provide generic helpers for implementing
SysBus+PCI devices, or is it going to be inside a source file
specific for AMD IOMMU?

> 
> diff --git a/hw/i386/compositedevice.c b/hw/i386/compositedevice.c
> new file mode 100644
> index 0000000..349e98d
> --- /dev/null
> +++ b/hw/i386/compositedevice.c
> @@ -0,0 +1,113 @@
> +#include "qemu/osdep.h"
> +#include "hw/pci/pci.h"
> +#include "hw/i386/x86-iommu.h"
> +#include "hw/pci/msi.h"
> +#include "hw/pci/pci_bus.h"
> +#include "hw/sysbus.h"
> +#include "qom/object.h"
> +#include "hw/i386/pc.h"
> +
> +#define AMDVI_MMIO_SIZE        0x4000
> +#define AMDVI_CAPAB_SIZE       0x18
> +#define AMDVI_CAPAB_REG_SIZE   0x04
> +#define AMDVI_CAPAB_ID_SEC     0xff
> +
> +#define TYPE_AMD_IOMMU_DEVICE "amd-iommu"
> +#define AMD_IOMMU_DEVICE(obj)\
> +    OBJECT_CHECK(AMDVIState, (obj), TYPE_AMD_IOMMU_DEVICE)
> +
> +#define TYPE_AMD_IOMMU_PCI "AMDVI-PCI"
> +#define AMD_IOMMU_PCI(obj)\
> +    OBJECT_CHECK(AMDVIPCIState, (obj), TYPE_AMD_IOMMU_PCI)
> +
> +typedef struct AMDVIPCIState {
> +    PCIDevice dev;
> +    /* PCI specific properties */
> +    uint8_t *capab;              /* capabilities registers       */

Where is this field used?

> +    uint32_t capab_offset;       /* capability offset pointer    */
> +} AMDVIPCIState;
> +
> +typedef struct AMDVIState {
> +    X86IOMMUState iommu;        /* IOMMU bus device             */
> +    AMDVIPCIState *dev;         /* IOMMU PCI device             */
> +
> +    uint8_t mmior[AMDVI_MMIO_SIZE];    /* read/write MMIO              */
> +    uint8_t w1cmask[AMDVI_MMIO_SIZE];  /* read/write 1 clear mask      */
> +    uint8_t romask[AMDVI_MMIO_SIZE];   /* MMIO read/only mask          */
> +} AMDVIState;
> +
> +static void amdvi_init(AMDVIState *s)
> +{
> +    /* reset PCI device */
> +    pci_config_set_vendor_id(s->dev->dev.config, PCI_VENDOR_ID_AMD);
> +    pci_config_set_prog_interface(s->dev->dev.config, 00);
> +    pci_config_set_class(s->dev->dev.config, 0x0806);
> +}
> +
> +static void amdvi_reset(DeviceState *dev)
> +{
> +    AMDVIState *s = AMD_IOMMU_DEVICE(dev);
> +
> +    amdvi_init(s);
> +}
> +
> +static void amdvi_realize(DeviceState *dev, Error **errp)
> +{
> +    AMDVIState *s = AMD_IOMMU_DEVICE(dev);
> +    PCIBus *bus = PC_MACHINE(qdev_get_machine())->bus;
> +
> +    /* This device should take care of IOMMU PCI properties */
> +    PCIDevice *createddev = pci_create_simple(bus, -1, TYPE_AMD_IOMMU_PCI);

This pci_create_simple() call can be basically expanded to:
    DeviceState *dev = object_new(TYPE_AMD_IOMMU_PCI)
    qdev_set_parent_bus(dev, bus);
    qdev_prop_set_int32(dev, "addr", -1);
    qdev_prop_set_bit(dev, "multifunction", false);
    object_property_set_bool(OBJECT(dev), true, "realized", &err);

You can embed AMDVIPCIState inside AMDVIState, instead of
creating the object on realize, and the "addr"/"multifunction"
properties already default to -1/false. The code would look like
this:

  typedef struct AMDVIState {
      X86IOMMUState iommu;
      AMDVIPCIState pci;
      [...]
  } AMDVIState;

  static void amdvi_instance_init(...)
  {
      object_initialize(&s->pci, sizeof(s->pci, TYPE_AMD_IOMMU_PCI);
  }

  static void amdvi_realize(DeviceState *dev, Error **errp)
  {
      [...]
      PCIBus *bus = PC_MACHINE(qdev_get_machine())->bus;
      qdev_set_parent_bus(DEVICE(&s->pci), &bus->qbus);
      object_property_set_bool(OBJECT(&s->pci), true, "realized", &err);
  }

Also, a object_property_add_child(obj, "pci-device", &s->pci)
call would help place the PCI object inside the AMD IOMMU device
in the device tree.

> +    AMDVIPCIState *amdpcidevice = container_of(createddev, AMDVIPCIState, dev);
> +    s->dev = amdpcidevice;

Can't you simply use the AMD_IOMMU_PCI macro here?

> +}
> +
> +static void amdvi_class_init(ObjectClass *klass, void* data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +    X86IOMMUClass *dc_class = X86_IOMMU_CLASS(klass);
> +
> +    dc->reset = amdvi_reset;
> +
> +    dc_class->realize = amdvi_realize;
> +}
> +
> +static const TypeInfo amdvi = {
> +    .name = TYPE_AMD_IOMMU_DEVICE,
> +    .parent = TYPE_X86_IOMMU_DEVICE,
> +    .instance_size = sizeof(AMDVIState),
> +    .class_init = amdvi_class_init
> +};
> +
> +static void amdviPCI_realize(PCIDevice *dev, Error **errp)
> +{
> +    AMDVIPCIState *s = container_of(dev, AMDVIPCIState, dev);

You can use the AMD_IOMMU_PCI macro here.

> +
> +    /* we need to report certain PCI capabilities */
> +    s->capab_offset = pci_add_capability(&s->dev, AMDVI_CAPAB_ID_SEC, 0,
> +                                         AMDVI_CAPAB_SIZE);

What is s->capab_offset used for?

> +    pci_add_capability(&s->dev, PCI_CAP_ID_MSI, 0, AMDVI_CAPAB_REG_SIZE);
> +    pci_add_capability(&s->dev, PCI_CAP_ID_HT, 0, AMDVI_CAPAB_REG_SIZE);
> +}
> +

Do you have any plans to allow TYPE_AMD_IOMMU_PCI to be used
without TYPE_AMD_IOMMU_DEVICE? If it is never going to be
possible, I would do everything inside
amdvi_instance_init()/amdvi_realize().

I think you don't even need to introduce a TYPE_AMD_IOMMU_PCI
type at all (just use TYPE_PCI_DEVICE/PCIState inside
AMDVIState). But I don't know if this would make the device tree
too confusing (probably it will be OK if you use
object_property_add_child() like I suggested above).

> +static void amdviPCI_class_init(ObjectClass *klass, void* data)
> +{
> +    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
> +
> +    k->realize = amdviPCI_realize;

You need to set DEVICE_CLASS(klass)->hotpluggable=false, or
people will be able to manually hotplug TYPE_AMD_IOMMU_PCI
devices.

> +}
> +
> +static const TypeInfo amdviPCI = {
> +    .name = TYPE_AMD_IOMMU_PCI,
> +    .parent = TYPE_PCI_DEVICE,
> +    .instance_size = sizeof(AMDVIPCIState),
> +    .class_init = amdviPCI_class_init
> +};
> +
> +static void amdviPCI_register_types(void)
> +{
> +    type_register_static(&amdviPCI);
> +    type_register_static(&amdvi);
> +}
> +
> +type_init(amdviPCI_register_types);
> -- 
> 2.1.4
>
Jan Kiszka June 10, 2016, 5:30 a.m. UTC | #2
On 2016-06-08 17:25, Eduardo Habkost wrote:
> On Wed, Jun 08, 2016 at 01:00:32PM +0300, David Kiarie wrote:
>> Sample composite SysBus and PCI device similar to AMD IOMMU setup
>>
>> Signed-off-by: David Kiarie <davidkiarie4@gmail.com>
>> ---
>>  hw/i386/compositedevice.c | 113 ++++++++++++++++++++++++++++++++++++++++++++++
>>  1 file changed, 113 insertions(+)
>>  create mode 100644 hw/i386/compositedevice.c
> 
> The filename is very generic (hw/i386/compositedevice.c), but it
> has lots of AMD-specific names.
> 
> Is your plan to provide generic helpers for implementing
> SysBus+PCI devices, or is it going to be inside a source file
> specific for AMD IOMMU?

As far as I understood - David, correct me - this patch is more of a
simplified demonstrator of the architecture to be applied on the actual
AMD IOMMU code. It is not for merge.

Jan
David Kiarie June 11, 2016, 7:36 p.m. UTC | #3
On Fri, Jun 10, 2016 at 8:30 AM, Jan Kiszka <jan.kiszka@web.de> wrote:
> On 2016-06-08 17:25, Eduardo Habkost wrote:
>> On Wed, Jun 08, 2016 at 01:00:32PM +0300, David Kiarie wrote:
>>> Sample composite SysBus and PCI device similar to AMD IOMMU setup
>>>
>>> Signed-off-by: David Kiarie <davidkiarie4@gmail.com>
>>> ---
>>>  hw/i386/compositedevice.c | 113 ++++++++++++++++++++++++++++++++++++++++++++++
>>>  1 file changed, 113 insertions(+)
>>>  create mode 100644 hw/i386/compositedevice.c
>>
>> The filename is very generic (hw/i386/compositedevice.c), but it
>> has lots of AMD-specific names.
>>
>> Is your plan to provide generic helpers for implementing
>> SysBus+PCI devices, or is it going to be inside a source file
>> specific for AMD IOMMU?
>
> As far as I understood - David, correct me - this patch is more of a
> simplified demonstrator of the architecture to be applied on the actual
> AMD IOMMU code. It is not for merge.

Right.

>
> Jan
>
>
diff mbox

Patch

diff --git a/hw/i386/compositedevice.c b/hw/i386/compositedevice.c
new file mode 100644
index 0000000..349e98d
--- /dev/null
+++ b/hw/i386/compositedevice.c
@@ -0,0 +1,113 @@ 
+#include "qemu/osdep.h"
+#include "hw/pci/pci.h"
+#include "hw/i386/x86-iommu.h"
+#include "hw/pci/msi.h"
+#include "hw/pci/pci_bus.h"
+#include "hw/sysbus.h"
+#include "qom/object.h"
+#include "hw/i386/pc.h"
+
+#define AMDVI_MMIO_SIZE        0x4000
+#define AMDVI_CAPAB_SIZE       0x18
+#define AMDVI_CAPAB_REG_SIZE   0x04
+#define AMDVI_CAPAB_ID_SEC     0xff
+
+#define TYPE_AMD_IOMMU_DEVICE "amd-iommu"
+#define AMD_IOMMU_DEVICE(obj)\
+    OBJECT_CHECK(AMDVIState, (obj), TYPE_AMD_IOMMU_DEVICE)
+
+#define TYPE_AMD_IOMMU_PCI "AMDVI-PCI"
+#define AMD_IOMMU_PCI(obj)\
+    OBJECT_CHECK(AMDVIPCIState, (obj), TYPE_AMD_IOMMU_PCI)
+
+typedef struct AMDVIPCIState {
+    PCIDevice dev;
+    /* PCI specific properties */
+    uint8_t *capab;              /* capabilities registers       */
+    uint32_t capab_offset;       /* capability offset pointer    */
+} AMDVIPCIState;
+
+typedef struct AMDVIState {
+    X86IOMMUState iommu;        /* IOMMU bus device             */
+    AMDVIPCIState *dev;         /* IOMMU PCI device             */
+
+    uint8_t mmior[AMDVI_MMIO_SIZE];    /* read/write MMIO              */
+    uint8_t w1cmask[AMDVI_MMIO_SIZE];  /* read/write 1 clear mask      */
+    uint8_t romask[AMDVI_MMIO_SIZE];   /* MMIO read/only mask          */
+} AMDVIState;
+
+static void amdvi_init(AMDVIState *s)
+{
+    /* reset PCI device */
+    pci_config_set_vendor_id(s->dev->dev.config, PCI_VENDOR_ID_AMD);
+    pci_config_set_prog_interface(s->dev->dev.config, 00);
+    pci_config_set_class(s->dev->dev.config, 0x0806);
+}
+
+static void amdvi_reset(DeviceState *dev)
+{
+    AMDVIState *s = AMD_IOMMU_DEVICE(dev);
+
+    amdvi_init(s);
+}
+
+static void amdvi_realize(DeviceState *dev, Error **errp)
+{
+    AMDVIState *s = AMD_IOMMU_DEVICE(dev);
+    PCIBus *bus = PC_MACHINE(qdev_get_machine())->bus;
+
+    /* This device should take care of IOMMU PCI properties */
+    PCIDevice *createddev = pci_create_simple(bus, -1, TYPE_AMD_IOMMU_PCI);
+    AMDVIPCIState *amdpcidevice = container_of(createddev, AMDVIPCIState, dev);
+    s->dev = amdpcidevice;
+}
+
+static void amdvi_class_init(ObjectClass *klass, void* data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    X86IOMMUClass *dc_class = X86_IOMMU_CLASS(klass);
+
+    dc->reset = amdvi_reset;
+
+    dc_class->realize = amdvi_realize;
+}
+
+static const TypeInfo amdvi = {
+    .name = TYPE_AMD_IOMMU_DEVICE,
+    .parent = TYPE_X86_IOMMU_DEVICE,
+    .instance_size = sizeof(AMDVIState),
+    .class_init = amdvi_class_init
+};
+
+static void amdviPCI_realize(PCIDevice *dev, Error **errp)
+{
+    AMDVIPCIState *s = container_of(dev, AMDVIPCIState, dev);
+
+    /* we need to report certain PCI capabilities */
+    s->capab_offset = pci_add_capability(&s->dev, AMDVI_CAPAB_ID_SEC, 0,
+                                         AMDVI_CAPAB_SIZE);
+    pci_add_capability(&s->dev, PCI_CAP_ID_MSI, 0, AMDVI_CAPAB_REG_SIZE);
+    pci_add_capability(&s->dev, PCI_CAP_ID_HT, 0, AMDVI_CAPAB_REG_SIZE);
+}
+
+static void amdviPCI_class_init(ObjectClass *klass, void* data)
+{
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->realize = amdviPCI_realize;
+}
+
+static const TypeInfo amdviPCI = {
+    .name = TYPE_AMD_IOMMU_PCI,
+    .parent = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(AMDVIPCIState),
+    .class_init = amdviPCI_class_init
+};
+
+static void amdviPCI_register_types(void)
+{
+    type_register_static(&amdviPCI);
+    type_register_static(&amdvi);
+}
+
+type_init(amdviPCI_register_types);