qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH v2 2/2] Add a unique ID in the virt machine to b


From: Diana Madalina Craciun
Subject: Re: [Qemu-devel] [PATCH v2 2/2] Add a unique ID in the virt machine to be used as device ID
Date: Fri, 11 Aug 2017 14:35:28 +0000

Hi Edgar,

On 07/31/2017 06:16 PM, Edgar E. Iglesias wrote:
> On Wed, Jul 26, 2017 at 02:22:28PM +0200, Auger Eric wrote:
>> Hi Diana,
>> On 23/05/2017 13:12, Diana Craciun wrote:
>>> Device IDs are required by the ARM GICv3 ITS for IRQ remapping.
>>> Currently, for PCI devices, the requester ID was used as device
>>> ID in the virt machine. If the system has multiple masters that
>> if the system has multiple root complex?
>>> use MSIs a unique ID accross the platform is needed.
>> across
>>> A static scheme is used and each master is allocated a range of IDs
>>> with the formula:
>>> DeviceID = zero_extend( RequesterID[15:0] ) + 0x10000*Constant (as
>>> recommended by SBSA).
>>>
>>> This ID will be configured in the machine creation and if not configured
>>> the PCI requester ID will be used insteead.
>> instead
>>> Signed-off-by: Diana Craciun <address@hidden>
>>> ---
>>>  hw/arm/virt.c              | 26 ++++++++++++++++++++++++++
>>>  hw/pci-host/gpex.c         |  6 ++++++
>>>  hw/pci/msi.c               |  2 +-
>>>  hw/pci/pci.c               | 25 +++++++++++++++++++++++++
>>>  include/hw/arm/virt.h      |  1 +
>>>  include/hw/pci-host/gpex.h |  2 ++
>>>  include/hw/pci/pci.h       |  8 ++++++++
>>>  kvm-all.c                  |  4 ++--
>>>  8 files changed, 71 insertions(+), 3 deletions(-)
>>>
>>> diff --git a/hw/arm/virt.c b/hw/arm/virt.c
>>> index 5f62a03..a969694 100644
>>> --- a/hw/arm/virt.c
>>> +++ b/hw/arm/virt.c
>>> @@ -110,6 +110,8 @@ static ARMPlatformBusSystemParams platform_bus_params;
>>>  #define RAMLIMIT_GB 255
>>>  #define RAMLIMIT_BYTES (RAMLIMIT_GB * 1024ULL * 1024 * 1024)
>>>  
>>> +#define STREAM_ID_RANGE_SIZE 0x10000
>>> +
>>>  /* Addresses and sizes of our components.
>>>   * 0..128MB is space for a flash device so we can run bootrom code such as 
>>> UEFI.
>>>   * 128MB..256MB is used for miscellaneous device I/O.
>>> @@ -162,6 +164,22 @@ static const int a15irqmap[] = {
>>>      [VIRT_PLATFORM_BUS] = 112, /* ...to 112 + PLATFORM_BUS_NUM_IRQS -1 */
>>>  };
>>>  
>>> +/* Device IDs are required by the ARM GICV3 ITS for IRQ remapping. 
>>> Currently
>>> + * for PCI devices the requester ID was used as device ID. But if the 
>>> system has
>>> + * multiple masters that use MSIs, the requester ID may cause deviceID 
>>> clashes.
>>> + * So a unique number is  needed accross the system.
>>> + * We are using the following formula:
>>> + * DeviceID = zero_extend( RequesterID[15:0] ) + 0x10000*Constant
>>> + * (as recommanded by SBSA). Currently we do not have an SMMU emulation, 
>>> but the
>>> + * same formula can be used for the generation of the streamID as well.
>>> + * For each master the device ID will be derrived from the requester ID 
>>> using
>>> + * the abovemntione formula.
>>> + */
>> I think most of this comment should only be in the commit message. typos
>> in derived and above mentioned.
>>
>> stream id is the terminology for the id space at the input of the smmu.
>> device id is the terminology for the id space at the input of the msi
>> controller I think.
>>
>> RID -> deviceID (no IOMMU)
>> RID -> streamID -> deviceID (IOMMU)
>>
>> I would personally get rid of all streamid uses as the smmu is not yet
>> supported and stick to the
>> Documentation/devicetree/bindings/pci/pci-msi.txt terminology?
>>
>>> +
>>> +static const uint32_t streamidmap[] = {
>>> +    [VIRT_PCIE] = 0,         /* currently only one PCI controller */
>>> +};
>>> +
>>>  static const char *valid_cpus[] = {
>>>      "cortex-a15",
>>>      "cortex-a53",
>>> @@ -980,6 +998,7 @@ static void create_pcie(const VirtMachineState *vms, 
>>> qemu_irq *pic)
>>>      hwaddr base_ecam = vms->memmap[VIRT_PCIE_ECAM].base;
>>>      hwaddr size_ecam = vms->memmap[VIRT_PCIE_ECAM].size;
>>>      hwaddr base = base_mmio;
>>> +    uint32_t stream_id = vms->streamidmap[VIRT_PCIE] * 
>>> STREAM_ID_RANGE_SIZE;
>> msi-base?
>> STREAM_ID_RANGE_SIZE ~ MSI_MAP_LENGTH?
>>>      int nr_pcie_buses = size_ecam / PCIE_MMCFG_SIZE_MIN;
>>>      int irq = vms->irqmap[VIRT_PCIE];
>>>      MemoryRegion *mmio_alias;
>>> @@ -992,6 +1011,7 @@ static void create_pcie(const VirtMachineState *vms, 
>>> qemu_irq *pic)
>>>      PCIHostState *pci;
>>>  
>>>      dev = qdev_create(NULL, TYPE_GPEX_HOST);
>>> +    qdev_prop_set_uint32(dev, "stream-id-base", stream_id);
>>>      qdev_init_nofail(dev);
>>>  
>>>      /* Map only the first size_ecam bytes of ECAM space */
>>> @@ -1056,6 +1076,11 @@ static void create_pcie(const VirtMachineState *vms, 
>>> qemu_irq *pic)
>>>      if (vms->msi_phandle) {
>>>          qemu_fdt_setprop_cells(vms->fdt, nodename, "msi-parent",
>>>                                 vms->msi_phandle);
>>> +        qemu_fdt_setprop_sized_cells(vms->fdt, nodename, "msi-map",
>>> +                                     1, 0,
>>> +                                     1, vms->msi_phandle,
>>> +                                     1, stream_id,
>>> +                                     1, STREAM_ID_RANGE_SIZE);
>>>      }
>>>  
>>>      qemu_fdt_setprop_sized_cells(vms->fdt, nodename, "reg",
>>> @@ -1609,6 +1634,7 @@ static void virt_2_9_instance_init(Object *obj)
>>>  
>>>      vms->memmap = a15memmap;
>>>      vms->irqmap = a15irqmap;
>>> +    vms->streamidmap = streamidmap;
>>>  }
>>>  
>>>  static void virt_machine_2_9_options(MachineClass *mc)
>>> diff --git a/hw/pci-host/gpex.c b/hw/pci-host/gpex.c
>>> index 66055ee..de72408 100644
>>> --- a/hw/pci-host/gpex.c
>>> +++ b/hw/pci-host/gpex.c
>>> @@ -43,6 +43,11 @@ static void gpex_set_irq(void *opaque, int irq_num, int 
>>> level)
>>>      qemu_set_irq(s->irq[irq_num], level);
>>>  }
>>>  
>>> +static Property gpex_props[] = {
>>> +    DEFINE_PROP_UINT32("stream-id-base", GPEXHost, stream_id_base, 0),
>> msi_base_base
>>> +    DEFINE_PROP_END_OF_LIST(),
>>> +};
>>> +
>>>  static void gpex_host_realize(DeviceState *dev, Error **errp)
>>>  {
>>>      PCIHostState *pci = PCI_HOST_BRIDGE(dev);
>>> @@ -83,6 +88,7 @@ static void gpex_host_class_init(ObjectClass *klass, void 
>>> *data)
>>>  
>>>      hc->root_bus_path = gpex_host_root_bus_path;
>>>      dc->realize = gpex_host_realize;
>>> +    dc->props = gpex_props;
>>>      set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
>>>      dc->fw_name = "pci";
>>>  }
>>> diff --git a/hw/pci/msi.c b/hw/pci/msi.c
>>> index 7925851..b60a410 100644
>>> --- a/hw/pci/msi.c
>>> +++ b/hw/pci/msi.c
>>> @@ -336,7 +336,7 @@ void msi_send_message(PCIDevice *dev, MSIMessage msg)
>>>  {
>>>      MemTxAttrs attrs = {};
>>>  
>>> -    attrs.stream_id = pci_requester_id(dev);
>>> +    attrs.stream_id = pci_stream_id(dev);
>>>      address_space_stl_le(&dev->bus_master_as, msg.address, msg.data,
>>>                           attrs, NULL);
>>>  }
>>> diff --git a/hw/pci/pci.c b/hw/pci/pci.c
>>> index 259483b..92e9a2b 100644
>>> --- a/hw/pci/pci.c
>>> +++ b/hw/pci/pci.c
>>> @@ -951,6 +951,30 @@ uint16_t pci_requester_id(PCIDevice *dev)
>>>      return pci_req_id_cache_extract(&dev->requester_id_cache);
>>>  }
>>>  
>>> +static uint32_t pci_get_stream_id_base(PCIDevice *dev)
>>> +{
>>> +    PCIBus *rootbus = pci_device_root_bus(dev);
>>> +    PCIHostState *host_bridge = PCI_HOST_BRIDGE(rootbus->qbus.parent);
>>> +    Error *err = NULL;
>>> +    int64_t stream_id;
>>> +
>>> +    stream_id = object_property_get_int(OBJECT(host_bridge), 
>>> "stream-id-base",
>>> +                                        &err);
>>> +    if (stream_id < 0) {
>>> +        stream_id = 0;
>>> +    }
>>> +
>>> +    return stream_id;
>>> +}
>>> +
>>> +uint32_t pci_stream_id(PCIDevice *dev)
>>> +{
>>> +    /* Stream ID = RequesterID[15:0] + stream_id_base. stream_id_base may
>>> +     * be 0 for devices that are not using any translation between 
>>> requester_id
>>> +     * and stream_id */
>>> +    return  (uint16_t)pci_requester_id(dev) + dev->stream_id_base;
>>> +}
>> I think you should split the changes in virt from pci/gpex generic changes.
>>
>>> +
>>>  /* -1 for devfn means auto assign */
>>>  static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus,
>>>                                           const char *name, int devfn,
>>> @@ -1000,6 +1024,7 @@ static PCIDevice *do_pci_register_device(PCIDevice 
>>> *pci_dev, PCIBus *bus,
>>>  
>>>      pci_dev->devfn = devfn;
>>>      pci_dev->requester_id_cache = pci_req_id_cache_get(pci_dev);
>>> +    pci_dev->stream_id_base = pci_get_stream_id_base(pci_dev);
>> looks strange to me to store the rid base in the end point as this is
>> rather a property of the PCI complex. I acknowledge this is much more
> I agree.

The reason I have changed was to avoid traversing the entire hierarchy
each time the ID is needed (for example each time when a MSI is sent).

> I think that what we need is to add support for allowing PCI RCs
> to transform requesterIDs in transactions attributes according to the
> implementation specifics.

Do you mean that you need more than a linear offset between requesterID
and whatever other ID?

>
> The way we did it when modelling the ZynqMP is by adding support for
> transaction attribute translation in QEMU's IOMMU interface.
> In our PCI RC, we have an IOMMU covering the entire AS that PCI devs DMA into.
> This IOMMU doesn't do address-translation, only RequesterID -> StreamID
> transforms according to how the ZynqMP PCI RC derives StreamIDs from 
> RequesterIDs.

Are there any patches for this support in order for me to better understand?

Thanks,

Diana


> This is useful not only to model PCI RequesterID to AXI Master ID mappings but
> also for modelling things like the ARM TZC (or the Xilinx ZynqMP XMPU/XPPUs).
>
> Cheers,
> Edgar
>
>
>> simple than reworking pci_requester_id() though.
>>>  
>>>      memory_region_init(&pci_dev->bus_master_container_region, 
>>> OBJECT(pci_dev),
>>>                         "bus master container", UINT64_MAX);
>>> diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h
>>> index 33b0ff3..94c007a 100644
>>> --- a/include/hw/arm/virt.h
>>> +++ b/include/hw/arm/virt.h
>>> @@ -99,6 +99,7 @@ typedef struct {
>>>      struct arm_boot_info bootinfo;
>>>      const MemMapEntry *memmap;
>>>      const int *irqmap;
>>> +    const uint32_t *streamidmap;
>>>      int smp_cpus;
>>>      void *fdt;
>>>      int fdt_size;
>>> diff --git a/include/hw/pci-host/gpex.h b/include/hw/pci-host/gpex.h
>>> index 68c9348..47df01a 100644
>>> --- a/include/hw/pci-host/gpex.h
>>> +++ b/include/hw/pci-host/gpex.h
>>> @@ -48,6 +48,8 @@ typedef struct GPEXHost {
>>>  
>>>      GPEXRootState gpex_root;
>>>  
>>> +    uint32_t stream_id_base;
>>> +
>>>      MemoryRegion io_ioport;
>>>      MemoryRegion io_mmio;
>>>      qemu_irq irq[GPEX_NUM_IRQS];
>>> diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h
>>> index a37a2d5..e6e9334 100644
>>> --- a/include/hw/pci/pci.h
>>> +++ b/include/hw/pci/pci.h
>>> @@ -283,6 +283,12 @@ struct PCIDevice {
>>>       * MSI). For conventional PCI root complex, this field is
>>>       * meaningless. */
>>>      PCIReqIDCache requester_id_cache;
>>> +    /* Some platforms need a unique ID for IOMMU source identification
>>> +     * or MSI source identification. QEMU implements a simple scheme:
>>> +     * stream_id =  stream_id_base + requester_id. The stream_id_base will
>>> +     * ensure that all the devices in the system have different stream ID
>>> +     * domains */
>>> +    uint32_t stream_id_base;
>> get rid of IOMMU terminology?
>>
>> Note that when adding other sub-systems you will need to address the
>> ACPI side as the IORT table built by hw/arm/virt-acpi-build.c currently
>> defines an RID mapping for the single root complex.
>>
>> Thanks
>>
>> Eric
>>>      char name[64];
>>>      PCIIORegion io_regions[PCI_NUM_REGIONS];
>>>      AddressSpace bus_master_as;
>>> @@ -737,6 +743,8 @@ static inline uint16_t pci_get_bdf(PCIDevice *dev)
>>>  
>>>  uint16_t pci_requester_id(PCIDevice *dev);
>>>  
>>> +uint32_t pci_stream_id(PCIDevice *dev);
>>> +
>>>  /* DMA access functions */
>>>  static inline AddressSpace *pci_get_address_space(PCIDevice *dev)
>>>  {
>>> diff --git a/kvm-all.c b/kvm-all.c
>>> index 90b8573..5a508c3 100644
>>> --- a/kvm-all.c
>>> +++ b/kvm-all.c
>>> @@ -1280,7 +1280,7 @@ int kvm_irqchip_add_msi_route(KVMState *s, int 
>>> vector, PCIDevice *dev)
>>>      kroute.u.msi.data = le32_to_cpu(msg.data);
>>>      if (kvm_msi_devid_required()) {
>>>          kroute.flags = KVM_MSI_VALID_DEVID;
>>> -        kroute.u.msi.devid = pci_requester_id(dev);
>>> +        kroute.u.msi.devid = pci_stream_id(dev);
>>>      }
>>>      if (kvm_arch_fixup_msi_route(&kroute, msg.address, msg.data, dev)) {
>>>          kvm_irqchip_release_virq(s, virq);
>>> @@ -1317,7 +1317,7 @@ int kvm_irqchip_update_msi_route(KVMState *s, int 
>>> virq, MSIMessage msg,
>>>      kroute.u.msi.data = le32_to_cpu(msg.data);
>>>      if (kvm_msi_devid_required()) {
>>>          kroute.flags = KVM_MSI_VALID_DEVID;
>>> -        kroute.u.msi.devid = pci_requester_id(dev);
>>> +        kroute.u.msi.devid = pci_stream_id(dev);
>>>      }
>>>      if (kvm_arch_fixup_msi_route(&kroute, msg.address, msg.data, dev)) {
>>>          return -EINVAL;
>>>




reply via email to

[Prev in Thread] Current Thread [Next in Thread]