Re: [Xen-devel] [PATCH 1/1] hw/intc/arm_gicv3_its: Fix the VM termination in vm_change_state_handler()
Thanks Julien, sorry for sending to XEN mailing list and it was my mistake. Thanks, Shanker -Original Message- From: Xen-devel [mailto:xen-devel-boun...@lists.xen.org] On Behalf Of Julien Grall Sent: Friday, November 3, 2017 6:51 AM To: Shanker Donthineni <shank...@codeaurora.org>; xen-devel <xen-de...@lists.xensource.com>; Julien Grall <julien.gr...@arm.com>; Stefano Stabellini <sstabell...@kernel.org> Cc: Philip Elcan <pel...@codeaurora.org>; Vikram Sethi <vikr...@codeaurora.org> Subject: Re: [Xen-devel] [PATCH 1/1] hw/intc/arm_gicv3_its: Fix the VM termination in vm_change_state_handler() Hi Shanker, I think you sent this patch to the wrong ML and people. This patch seem KVM specific. Cheers, On 03/11/17 11:33, Shanker Donthineni wrote: > The commit cddafd8f353d ("hw/intc/arm_gicv3_its: Implement state save > /restore") breaks the backward compatibility with the older kernels > where vITS save/restore support is not available. The vmstate function > vm_change_state_handler() should not be registered if the running > kernel doesn't support ITS save/restore feature. Otherwise VM instance > will be killed whenever vmstate callback function is invoked. > > Observed a virtual machine shutdown with QEMU-2.10+linux-4.11 when > testing the reboot command "virsh reboot --mode acpi" instead of > reboot. > > KVM Error: 'KVM_SET_DEVICE_ATTR failed: Group 4 attr 0x01' > > Signed-off-by: Shanker Donthineni <shank...@codeaurora.org> > --- > hw/intc/arm_gicv3_its_kvm.c | 4 ++-- > 1 file changed, 2 insertions(+), 2 deletions(-) > > diff --git a/hw/intc/arm_gicv3_its_kvm.c b/hw/intc/arm_gicv3_its_kvm.c > index 39903d5..9b00ce5 100644 > --- a/hw/intc/arm_gicv3_its_kvm.c > +++ b/hw/intc/arm_gicv3_its_kvm.c > @@ -111,13 +111,13 @@ static void kvm_arm_its_realize(DeviceState *dev, Error > **errp) > error_free(s->migration_blocker); > return; > } > +} else { > +qemu_add_vm_change_state_handler(vm_change_state_handler, s); > } > > kvm_msi_use_devid = true; > kvm_gsi_direct_mapping = false; > kvm_msi_via_irqfd_allowed = kvm_irqfds_enabled(); > - > -qemu_add_vm_change_state_handler(vm_change_state_handler, s); > } > > /** > -- Julien Grall ___ Xen-devel mailing list Xen-devel@lists.xen.org https://lists.xen.org/xen-devel ___ Xen-devel mailing list Xen-devel@lists.xen.org https://lists.xen.org/xen-devel
[Xen-devel] [PATCH 1/1] hw/intc/arm_gicv3_its: Fix the VM termination in vm_change_state_handler()
The commit cddafd8f353d ("hw/intc/arm_gicv3_its: Implement state save /restore") breaks the backward compatibility with the older kernels where vITS save/restore support is not available. The vmstate function vm_change_state_handler() should not be registered if the running kernel doesn't support ITS save/restore feature. Otherwise VM instance will be killed whenever vmstate callback function is invoked. Observed a virtual machine shutdown with QEMU-2.10+linux-4.11 when testing the reboot command "virsh reboot --mode acpi" instead of reboot. KVM Error: 'KVM_SET_DEVICE_ATTR failed: Group 4 attr 0x01' Signed-off-by: Shanker Donthineni <shank...@codeaurora.org> --- hw/intc/arm_gicv3_its_kvm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/intc/arm_gicv3_its_kvm.c b/hw/intc/arm_gicv3_its_kvm.c index 39903d5..9b00ce5 100644 --- a/hw/intc/arm_gicv3_its_kvm.c +++ b/hw/intc/arm_gicv3_its_kvm.c @@ -111,13 +111,13 @@ static void kvm_arm_its_realize(DeviceState *dev, Error **errp) error_free(s->migration_blocker); return; } +} else { +qemu_add_vm_change_state_handler(vm_change_state_handler, s); } kvm_msi_use_devid = true; kvm_gsi_direct_mapping = false; kvm_msi_via_irqfd_allowed = kvm_irqfds_enabled(); - -qemu_add_vm_change_state_handler(vm_change_state_handler, s); } /** -- Qualcomm Datacenter Technologies, Inc. on behalf of the Qualcomm Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project. ___ Xen-devel mailing list Xen-devel@lists.xen.org https://lists.xen.org/xen-devel
Re: [Xen-devel] [PATCH for-4.9] xen/arm: acpi: Map MMIO on fault in stage-2 page table for the hardware domain
Hi Julien, On 03/30/2017 07:58 AM, Julien Grall wrote: > > On 30/03/17 13:52, Shanker Donthineni wrote: >> Hi Julien, > Hi Shanker, > >> On 03/30/2017 07:43 AM, Julien Grall wrote: >>> Shanker: You mentioned offline that you tested the patch. May I add >>> your tested-by? >> Sure add my tested-by. If you want I can test one more time this mailing >> list patch. > The code is the same, but it would not hurt to have another go at it :). > > FWIW, I did some testing on Juno with a small patch to turn the mapping > hypercall into a nop and adding a debug message when mapping: > Tested-by: Shanker Donthineni <shank...@codeaurora.org> This patch has been tested on Qualcomm Datacenter Technologies QDF2400 server platform with ACPI based XEN/DOM0. > diff --git a/xen/arch/arm/p2m.c b/xen/arch/arm/p2m.c > index 626376090d..dd1b0bd2b2 100644 > --- a/xen/arch/arm/p2m.c > +++ b/xen/arch/arm/p2m.c > @@ -1116,6 +1116,8 @@ int map_dev_mmio_region(struct domain *d, > { > int res; > > +return 0; > + > if ( !(nr && iomem_access_permitted(d, mfn_x(mfn), mfn_x(mfn) + nr - 1)) > ) > return 0; > > diff --git a/xen/arch/arm/traps.c b/xen/arch/arm/traps.c > index ebf915bb3b..9e6d2dafc8 100644 > --- a/xen/arch/arm/traps.c > +++ b/xen/arch/arm/traps.c > @@ -2643,7 +2643,11 @@ static void do_trap_data_abort_guest(struct > cpu_user_regs *regs, > return; > > if ( try_map_mmio(_gfn(paddr_to_pfn(info.gpa))) ) > +{ > +gdprintk(XENLOG_DEBUG, "Map %#"PRIpaddr" - %#"PRIpaddr"\n", > + info.gpa, info.gpa + PAGE_SIZE - 1); > return; > +} > > break; > default: > > Cheers, > -- Shanker Donthineni Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project. ___ Xen-devel mailing list Xen-devel@lists.xen.org https://lists.xen.org/xen-devel
Re: [Xen-devel] [PATCH for-4.9] xen/arm: acpi: Map MMIO on fault in stage-2 page table for the hardware domain
Hi Julien, On 03/30/2017 07:43 AM, Julien Grall wrote: > When booting using ACPI, not all MMIOs can be discovered by parsing the > static tables or the UEFI memory map. A lot of them will be described in > the DSDT. However, Xen does not have an AML parser which requires us to > find a different approach. > > During the first discussions on supporting ACPI (see design doc [1]), it > was decided to rely on the hardware domain to make a request to the > hypervisor to map the MMIO region in stage-2 page table before accessing > it. This approach works fine if the OS has limited hooks to modify the > page tables. > > In the case of Linux kernel, notifiers have been added to map > the MMIO regions when adding a new AMBA/platform device. Whilst this is > covering most of the MMIOs, some of them (e.g OpRegion, ECAM...) are not > related to a specific device or the driver is not using the > AMBA/platform API. So more hooks would need to be added in the code. > > Various approaches have been discussed (see [2]), one of them was to > create stage-2 mappings seamlessly in Xen upon hardware memory faults. > This approach was first ruled out because it relies on the hardware > domain to probe the region before any use. So this would not work when > DMA'ing to another device's MMIO region when the device is protected by > an SMMU. It has been pointed out that this is a limited use case compare > to DMA'ing between MMIO and RAM. > > This patch implements this approach. All MMIOs region will be mapped in > stage-2 using p2m_mmio_direct_c (i.e normal memory outer and inner > write-back cacheable). The stage-1 page table will be in control of the > memory attribute. This is fine because the hardware domain is a trusted > domain. > > Note that MMIO will only be mapped on a data abort fault. It is assumed > that it will not be possible to execute code from MMIO > (p2m_mmio_direct_c will forbid that). > > As mentioned above, this solution will cover most of the cases. If a > platform requires to do DMA'ing to another device's MMIO region without > any access performed by the OS. Then it will be expected to have > specific platform code in the hypervisor to map the MMIO at boot time or > the OS to use the existing hypercalls (i.e XENMEM_add_to_add_physmap{,_batch}) > before any access. > > [1] https://lists.xen.org/archives/html/xen-devel/2015-11/msg00488.html > [2] https://marc.info/?l=linux-arm-kernel=148469169210500=2 > > Signed-off-by: Julien Grall <julien.gr...@arm.com> > > --- > This patch is a candidate for Xen 4.9. Whilst the last posting date > was few days ago, I think it would be good to have this patch in the > next release. Although ACPI support for ARM64 is still a technical > preview, it would help servers to test Xen upstream on their platform > with ACPI and provide feedback on missing features. > > All the code is gated by !acpi_disabled and therefore will not be > executed on when using Device Tree. > > RM hat on: I will leave the decision to Stefano. > > Shanker: You mentioned offline that you tested the patch. May I add > your tested-by? Sure add my tested-by. If you want I can test one more time this mailing list patch. -- Shanker Donthineni Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project. ___ Xen-devel mailing list Xen-devel@lists.xen.org https://lists.xen.org/xen-devel
Re: [Xen-devel] [PATCH v2 14/27] ARM: vGICv3: introduce basic ITS emulation bits
r / sizeof(*its->cmdbuf)); > +switch (its_cmd_get_command(cmdptr)) > +{ > +case GITS_CMD_SYNC: > +/* We handle ITS commands synchronously, so we ignore SYNC. */ > + break; > +default: > +gdprintk(XENLOG_G_WARNING, "ITS: unhandled ITS command %ld\n", > + its_cmd_get_command(cmdptr)); > +break; > +} > + > +its->creadr += ITS_CMD_SIZE; > +if ( its->creadr == ITS_CMD_BUFFER_SIZE(its->cbaser) ) > +its->creadr = 0; > +} > +its->cwriter = writer; > + > +spin_unlock(>vcmd_lock); > + > +return 0; > +} > + > +/* > + * ITS registers read access * > + */ > + > +/* > + * The physical address is encoded slightly differently depending on > + * the used page size: the highest four bits are stored in the lowest > + * four bits of the field for 64K pages. > + */ > +static paddr_t get_baser_phys_addr(uint64_t reg) > +{ > +if ( reg & BIT(9) ) > +return (reg & GENMASK(47, 16)) | ((reg & GENMASK(15, 12)) << 36); > +else > +return reg & GENMASK(47, 12); > +} > + > +static int vgic_v3_its_mmio_read(struct vcpu *v, mmio_info_t *info, > + register_t *r, void *priv) > +{ > +struct virt_its *its = priv; > + > +switch ( info->gpa & 0x ) > +{ > +case VREG32(GITS_CTLR): > + if ( info->dabt.size != DABT_WORD ) goto bad_width; > +*r = vgic_reg32_extract(its->enabled | BIT(31), info); > + break; > +case VREG32(GITS_IIDR): > +if ( info->dabt.size != DABT_WORD ) goto bad_width; > +*r = vgic_reg32_extract(GITS_IIDR_VALUE, info); > +break; > +case VREG64(GITS_TYPER): > +if ( info->dabt.size < DABT_WORD ) goto bad_width; > +*r = vgic_reg64_extract(0x1eff1, info); Please don't hard-code Devbits (bits 17-13) value to 16 here. For dom0, at least match to Kconfig option, or use ITS hardware reported value. On Qualcomm server chips, GITS_TYPER.Devbit is set to 32bits. -- Shanker Donthineni Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project. ___ Xen-devel mailing list Xen-devel@lists.xen.org https://lists.xen.org/xen-devel
Re: [Xen-devel] [PATCH v2 05/27] ARM: GICv3 ITS: introduce ITS command handling
cpu, (collection_id & GENMASK(15, 0))); > +cmd[2] |= GITS_VALID_BIT; > +cmd[3] = 0x00; > + > +return its_send_command(its, cmd); > +} > + > +/* Set up the (1:1) collection mapping for the given host CPU. */ > +int gicv3_its_setup_collection(unsigned int cpu) > +{ > +struct host_its *its; > +int ret; > + > +list_for_each_entry(its, _its_list, entry) > +{ > +if ( !its->cmd_buf ) > +continue; > + > +ret = its_send_cmd_mapc(its, cpu, cpu); > +if ( ret ) > +return ret; > + > +ret = its_send_cmd_sync(its, cpu); > +if ( ret ) > +return ret; > + > +ret = gicv3_its_wait_commands(its); > +if ( ret ) > +return ret; > +} > + > +return 0; > +} > + > #define BASER_ATTR_MASK \ > ((0x3UL << GITS_BASER_SHAREABILITY_SHIFT) | \ > (0x7UL << GITS_BASER_OUTER_CACHEABILITY_SHIFT) | \ > @@ -184,22 +326,59 @@ retry: > return -EINVAL; > } > > +/* > + * Before an ITS gets initialized, it should be in a quiescent state, where > + * all outstanding commands and transactions have finished. > + * So if the ITS is already enabled, turn it off and wait for all outstanding > + * operations to get processed by polling the QUIESCENT bit. > + */ > +static int gicv3_disable_its(struct host_its *hw_its) > +{ > +uint32_t reg; > +s_time_t deadline = NOW() + MILLISECS(100); > + > +reg = readl_relaxed(hw_its->its_base + GITS_CTLR); > +if ( (reg & GITS_CTLR_QUIESCENT) && !(reg & GITS_CTLR_ENABLE) ) nit: I prefer changing to 'if ( !(reg & GITS_CTLR_ENABLE) && (reg & GITS_CTLR_QUIESCENT) ) ' because bit GITS_CTLR_QUIESCENT is not valid if ITS hardware is in enabled state. > #endif -- Shanker Donthineni Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project. ___ Xen-devel mailing list Xen-devel@lists.xen.org https://lists.xen.org/xen-devel
Re: [Xen-devel] [PATCH 09/28] ARM: GICv3 ITS: map device and LPIs to the ITS on physdev_op hypercall
Hi Julien, On 02/28/2017 12:29 PM, Julien Grall wrote: On 27/02/17 17:20, Andre Przywara wrote: Hi, Hi Andre, On 24/02/17 19:57, Shanker Donthineni wrote: Hi Julien, On 01/31/2017 10:18 AM, Julien Grall wrote: On 31/01/17 16:02, Jaggi, Manish wrote: On 1/31/2017 8:47 PM, Julien Grall wrote: On 31/01/17 14:08, Jaggi, Manish wrote: Hi Julien, On 1/31/2017 7:16 PM, Julien Grall wrote: On 31/01/17 13:19, Jaggi, Manish wrote: On 1/31/2017 6:13 PM, Julien Grall wrote: On 31/01/17 10:29, Jaggi, Manish wrote: If you please go back to your comment where you wrote "we need to find another way to get the DeviceID", I was referring that we should add that another way in this series so that correct DeviceID is programmed in ITS. This is not the first time I am saying this, just saying "we should add that another way..." is not helpful. You should also provide some details on what you would do. Julien, As you suggested we need to find another way, I assumed you had something in mind. I gave suggestions on my e-mail but you may have missed it... Since we both agree that sbdf!=deviceID, the current series of ITS patches will program the incorrect deviceID so there is a need to have a way to map sbdf with deviceID in xen. One option could be to add a new hypercall to supply sbdf and deviceID to xen. ... as well as the part where I am saying that I am not in favor to implement an hypercall temporarily, and against adding a new hypercall for only a couple of weeks. As you may know PHYSDEV hypercall are part of the stable ABI and once they are added they cannot be removed. So we need to be sure the hypercall is necessary. In this case, the hypercall is not necessary as all the information can be found in the firmware tables. However this is not implemented yet and part of the discussion on PCI Passthrough (see [1]). We need a temporary solution that does not involve any commitment on the ABI until Xen is able to discover PCI. Why can't we handle ITS device creation whenever a virtual ITS driver receives the MAPD command from dom0/domU. In case of dom0, it's straight forward dom0 always passes the real ITS device through MAPD command. This way we can support PCIe devices without hard-coded MSI(x) limit 32, and platform devices transparently. I used the below code to platform and PCIe device MSI(x) functionality on QDF2400 server platform. But this breaks our assumption that no ITS commands can ever be propagated at guest's runtime, which is the cornerstone of this series. I agree that this is unfortunate and allowing it would simplify things, but after long discussions we came to the conclusion that it's not feasible to do so: A malicious guest could flood the virtual ITS with MAPD commands. Xen would need to propagate those to the hardware, which relies on the host command queue to have free slots, which we can't guarantee. For technical reasons we can't reschedule the guest (because this is an MMIO trap), also the domain actually triggering the "final" MAPD might not be the culprit, but an actual legitimate user. So we agreed upon issuing all hardware ITS commands before a guest actually starts (DomUs), respectively on hypercalls for Dom0. I think we can do exceptions for Dom0, since it's not supposed to be malicious. Thank you for summarizing the problem :). Direct VLPI injection feature is included in GICv4 architecture. A new set of VLPI commands are introduced to map ITS vpend/vprop tables, ITTE setup, and maintenance operations for VLPIs. In case of direct VLPI injection, domU/dom0 LPI commands are mapped to VLPI commands. Some of these commands must be applied to a real ITS hardware whenever XEN receives the ITS commands during runtime. Any thought on this, how we are going to support a direct VLPI injection without prolongating dom0/domU ITS commands to hardware at runtime? -- Shanker Donthineni Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project. ___ Xen-devel mailing list Xen-devel@lists.xen.org https://lists.xen.org/xen-devel
Re: [Xen-devel] xen/arm: Hiding SMMUs from Dom0 when using ACPI on Xen
Hi Julien, On 02/27/2017 08:12 AM, Julien Grall wrote: On 27/02/17 13:23, Vijay Kilari wrote: Hi Julien, Hello Vijay, On Wed, Feb 22, 2017 at 7:40 PM, Julien Grall <julien.gr...@arm.com> wrote: Hello, There was few discussions recently about hiding SMMUs from DOM0 when using ACPI. I thought it would be good to have a separate thread for this. When using ACPI, the SMMUs will be described in the IO Remapping Table (IORT). The specification can be found on the ARM website [1]. For a brief summary, the IORT can be used to discover the SMMUs present on the platform and find for a given device the ID to configure components such as ITS (DeviceID) and SMMU (StreamID). The appendix A in the specification gives an example how DeviceID and StreamID can be found. For instance, when a PCI device is both protected by an SMMU and MSI-capable the following translation will happen: RID -> StreamID -> DeviceID Currently, SMMUs are hidden from DOM0 because they are been used by Xen and we don't support stage-1 SMMU. If we pass the IORT as it is, DOM0 will try to initialize SMMU and crash. I first thought about using a Xen specific way (STAO) or extending a flag in IORT. But that is not ideal. So we would have to rewrite the IORT for DOM0. Given that a range of RID can mapped to multiple ranges of DeviceID, we would have to translate RID one by one to find the associated DeviceID. I think this may end up to complex code and have a big IORT table. Why can't we replace Output base of IORT of PCI node with SMMU output base?. I mean similar to PCI node without SMMU, why can't replace output base of PCI node with SMMU's output base?. Because I don't see anything in the spec preventing one RC ID mapping to produce multiple SMMU ID mapping. So which output base would you use? Basically, remove SMMU nodes, and replaces output of the PCIe and named nodes ID mappings with ITS nodes. RID --> StreamID --> dviceID --> ITS device id = RID --> dviceID --> ITS device id The issue I see is RID is [15:0] where is DeviceID is [17:0]. Actuality device id is 32bit field. However, given that DeviceID will be used by DOM0 to only configure the ITS. We have no need to use to have the DOM0 DeviceID equal to the host DeviceID. So I think we could simplify our life by generating DeviceID for each RID range. If DOM0 DeviceID != host Device ID, then we cannot initialize ITS using DOM0 ITS commands (MAPD). So, is it concluded that ITS initializes all the devices with platform specific Device ID's in Xen?. Initializing ITS using DOM0 ITS command is a workaround until we get PCI passthrough done. It would still be possible to implement that with vDeviceID != pDeviceID as Xen would likely have the mapping between the 2 DeviceID. I believe mapping dom0 ITS commands to XEN ITS commands one to one is the better approach. Physical DeviceID is unique per ITS group, not a system wide unique ID. In case of direct VLPI, LPI number has to be programmed whenever dom0/domU calls the MAPTI command but not at the time of PCIe device creation. -- Shanker Donthineni Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project. ___ Xen-devel mailing list Xen-devel@lists.xen.org https://lists.xen.org/xen-devel
Re: [Xen-devel] [PATCH 09/28] ARM: GICv3 ITS: map device and LPIs to the ITS on physdev_op hypercall
Hi Julien, On 01/31/2017 10:18 AM, Julien Grall wrote: On 31/01/17 16:02, Jaggi, Manish wrote: On 1/31/2017 8:47 PM, Julien Grall wrote: On 31/01/17 14:08, Jaggi, Manish wrote: Hi Julien, On 1/31/2017 7:16 PM, Julien Grall wrote: On 31/01/17 13:19, Jaggi, Manish wrote: On 1/31/2017 6:13 PM, Julien Grall wrote: On 31/01/17 10:29, Jaggi, Manish wrote: If you please go back to your comment where you wrote "we need to find another way to get the DeviceID", I was referring that we should add that another way in this series so that correct DeviceID is programmed in ITS. This is not the first time I am saying this, just saying "we should add that another way..." is not helpful. You should also provide some details on what you would do. Julien, As you suggested we need to find another way, I assumed you had something in mind. I gave suggestions on my e-mail but you may have missed it... Since we both agree that sbdf!=deviceID, the current series of ITS patches will program the incorrect deviceID so there is a need to have a way to map sbdf with deviceID in xen. One option could be to add a new hypercall to supply sbdf and deviceID to xen. ... as well as the part where I am saying that I am not in favor to implement an hypercall temporarily, and against adding a new hypercall for only a couple of weeks. As you may know PHYSDEV hypercall are part of the stable ABI and once they are added they cannot be removed. So we need to be sure the hypercall is necessary. In this case, the hypercall is not necessary as all the information can be found in the firmware tables. However this is not implemented yet and part of the discussion on PCI Passthrough (see [1]). We need a temporary solution that does not involve any commitment on the ABI until Xen is able to discover PCI. Why can't we handle ITS device creation whenever a virtual ITS driver receives the MAPD command from dom0/domU. In case of dom0, it's straight forward dom0 always passes the real ITS device through MAPD command. This way we can support PCIe devices without hard-coded MSI(x) limit 32, and platform devices transparently. I used the below code to platform and PCIe device MSI(x) functionality on QDF2400 server platform. @@ -383,10 +384,17 @@ static int its_handle_mapd(struct virt_its *its, uint64_t *cmdptr) int size = its_cmd_get_size(cmdptr); bool valid = its_cmd_get_validbit(cmdptr); paddr_t itt_addr = its_cmd_mask_field(cmdptr, 2, 0, 52) & GENMASK(51, 8); +int ret; if ( !its->dev_table ) return -1; +size = size < 4 ? 4 : size; +ret = gicv3_its_map_guest_device(hardware_domain, devid, devid, size + 1, + valid); +if (ret < 0) + return ret; + -- Shanker Donthineni Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project. ___ Xen-devel mailing list Xen-devel@lists.xen.org https://lists.xen.org/xen-devel
Re: [Xen-devel] [PATCH 07/28] ARM: GICv3 ITS: introduce device mapping
Hi Andre, On 02/22/2017 01:06 AM, Vijay Kilari wrote: Hi Andre, On Tue, Jan 31, 2017 at 12:01 AM, Andre Przywara <andre.przyw...@arm.com> wrote: The ITS uses device IDs to map LPIs to a device. Dom0 will later use those IDs, which we directly pass on to the host. For this we have to map each device that Dom0 may request to a host ITS device with the same identifier. Allocate the respective memory and enter each device into an rbtree to later be able to iterate over it or to easily teardown guests. Signed-off-by: Andre Przywara <andre.przyw...@arm.com> --- xen/arch/arm/gic-v3-its.c| 188 ++- xen/arch/arm/vgic-v3.c | 3 + xen/include/asm-arm/domain.h | 3 + xen/include/asm-arm/gic_v3_its.h | 28 ++ 4 files changed, 221 insertions(+), 1 deletion(-) diff --git a/xen/arch/arm/gic-v3-its.c b/xen/arch/arm/gic-v3-its.c index 6578e8a..4a3a394 100644 --- a/xen/arch/arm/gic-v3-its.c +++ b/xen/arch/arm/gic-v3-its.c @@ -21,8 +21,10 @@ #include #include #include -#include +#include +#include #include +#include #include #include #include @@ -94,6 +96,21 @@ static int its_send_cmd_mapc(struct host_its *its, int collection_id, int cpu) return its_send_command(its, cmd); } +static int its_send_cmd_mapd(struct host_its *its, uint32_t deviceid, + int size, uint64_t itt_addr, bool valid) +{ +uint64_t cmd[4]; + +cmd[0] = GITS_CMD_MAPD | ((uint64_t)deviceid << 32); +cmd[1] = size & GENMASK(4, 0); +cmd[2] = itt_addr & GENMASK(51, 8); +if ( valid ) +cmd[2] |= GITS_VALID_BIT; +cmd[3] = 0x00; + +return its_send_command(its, cmd); +} + /* Set up the (1:1) collection mapping for the given host CPU. */ int gicv3_its_setup_collection(int cpu) { @@ -293,6 +310,7 @@ int gicv3_its_init(struct host_its *hw_its) reg = readq_relaxed(hw_its->its_base + GITS_TYPER); if ( reg & GITS_TYPER_PTA ) hw_its->flags |= HOST_ITS_USES_PTA; +hw_its->itte_size = GITS_TYPER_ITT_SIZE(reg); for ( i = 0; i < GITS_BASER_NR_REGS; i++ ) { @@ -339,6 +357,173 @@ int gicv3_its_init(struct host_its *hw_its) return 0; } +static void remove_mapped_guest_device(struct its_devices *dev) +{ +if ( dev->hw_its ) +its_send_cmd_mapd(dev->hw_its, dev->host_devid, 0, 0, false); + +xfree(dev->itt_addr); +xfree(dev); +} + +int gicv3_its_map_guest_device(struct domain *d, int host_devid, + int guest_devid, int bits, bool valid) +{ +void *itt_addr = NULL; +struct its_devices *dev, *temp; +struct rb_node **new = >arch.vgic.its_devices.rb_node, *parent = NULL; +struct host_its *hw_its; +int ret; + +/* check for already existing mappings */ +spin_lock(>arch.vgic.its_devices_lock); +while (*new) +{ +temp = rb_entry(*new, struct its_devices, rbnode); + +if ( temp->guest_devid == guest_devid ) +{ +if ( !valid ) +rb_erase(>rbnode, >arch.vgic.its_devices); + +spin_unlock(>arch.vgic.its_devices_lock); + +if ( valid ) +return -EBUSY; + +remove_mapped_guest_device(temp); + +return 0; +} + +if ( guest_devid < temp->guest_devid ) +new = &((*new)->rb_right); Shouldn't be rb_left here? +else +new = &((*new)->rb_left); Shouldn't be rb_right here? I found the same thing when I tested ITS feature on Qualcomm platform. +} I see duplicate code in find and inserting node into rb_tree. + +if ( !valid ) +{ +ret = -ENOENT; +goto out_unlock; +} + +/* + * TODO: Work out the correct hardware ITS to use here. + * Maybe a per-platform function: devid -> ITS? + * Or parsing the DT to find the msi_parent? + * Or get Dom0 to give us this information? + * For now just use the first ITS. + */ +hw_its = list_first_entry(_its_list, struct host_its, entry); + +ret = -ENOMEM; + +itt_addr = _xmalloc(BIT(bits) * hw_its->itte_size, 256); Please use _xzalloc() to avoid potential issues with ITS hardware prefetching feature. -- Shanker Donthineni Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project. ___ Xen-devel mailing list Xen-devel@lists.xen.org https://lists.xen.org/xen-devel
Re: [Xen-devel] [PATCH 04/28] ARM: GICv3 ITS: allocate device and collection table
Hi Andre On 02/16/2017 01:03 PM, Shanker Donthineni wrote: Hi Andre, On 01/30/2017 12:31 PM, Andre Przywara wrote: Each ITS maps a pair of a DeviceID (usually the PCI b/d/f triplet) and an EventID (the MSI payload or interrupt ID) to a pair of LPI number and collection ID, which points to the target CPU. This mapping is stored in the device and collection tables, which software has to provide for the ITS to use. Allocate the required memory and hand it the ITS. The maximum number of devices is limited to a compile-time constant exposed in Kconfig. Signed-off-by: Andre Przywara <andre.przyw...@arm.com> --- xen/arch/arm/Kconfig | 14 + xen/arch/arm/gic-v3-its.c| 129 +++ xen/arch/arm/gic-v3.c| 5 ++ xen/include/asm-arm/gic_v3_its.h | 55 - 4 files changed, 202 insertions(+), 1 deletion(-) diff --git a/xen/arch/arm/Kconfig b/xen/arch/arm/Kconfig index 71734a1..81bc233 100644 --- a/xen/arch/arm/Kconfig +++ b/xen/arch/arm/Kconfig @@ -64,6 +64,20 @@ config MAX_PHYS_LPI_BITS This can be overriden on the command line with the max_lpi_bits parameter. +config MAX_PHYS_ITS_DEVICE_BITS +depends on HAS_ITS +int "Number of device bits the ITS supports" +range 1 32 +default "10" +help + Specifies the maximum number of devices which want to use the ITS. + Xen needs to allocates memory for the whole range very early. + The allocation scheme may be sparse, so a much larger number must + be supported to cover devices with a high bus number or those on + separate bus segments. + This can be overriden on the command line with the max_its_device_bits + parameter. + endmenu menu "ARM errata workaround via the alternative framework" diff --git a/xen/arch/arm/gic-v3-its.c b/xen/arch/arm/gic-v3-its.c index ff0f571..c31fef6 100644 --- a/xen/arch/arm/gic-v3-its.c +++ b/xen/arch/arm/gic-v3-its.c @@ -20,9 +20,138 @@ #include #include #include +#include +#include #include #include #include +#include + +#define BASER_ATTR_MASK \ +((0x3UL << GITS_BASER_SHAREABILITY_SHIFT) | \ + (0x7UL << GITS_BASER_OUTER_CACHEABILITY_SHIFT) | \ + (0x7UL << GITS_BASER_INNER_CACHEABILITY_SHIFT)) +#define BASER_RO_MASK (GENMASK(58, 56) | GENMASK(52, 48)) + +static uint64_t encode_phys_addr(paddr_t addr, int page_bits) +{ +uint64_t ret; + +if ( page_bits < 16 ) +return (uint64_t)addr & GENMASK(47, page_bits); + +ret = addr & GENMASK(47, 16); +return ret | (addr & GENMASK(51, 48)) >> (48 - 12); +} + +#define PAGE_BITS(sz) ((sz) * 2 + PAGE_SHIFT) + +static int its_map_baser(void __iomem *basereg, uint64_t regc, int nr_items) +{ +uint64_t attr, reg; +int entry_size = ((regc >> GITS_BASER_ENTRY_SIZE_SHIFT) & 0x1f) + 1; +int pagesz = 0, order, table_size; Please try ITS page sizes in the order 64K, 16K and 4K to cover more ITS devices using a flat table. Similar to Linux ITS driver. +void *buffer = NULL; + +attr = GIC_BASER_InnerShareable << GITS_BASER_SHAREABILITY_SHIFT; +attr |= GIC_BASER_CACHE_SameAsInner << GITS_BASER_OUTER_CACHEABILITY_SHIFT; +attr |= GIC_BASER_CACHE_RaWaWb << GITS_BASER_INNER_CACHEABILITY_SHIFT; + +/* + * Setup the BASE register with the attributes that we like. Then read + * it back and see what sticks (page size, cacheability and shareability + * attributes), retrying if necessary. + */ +while ( 1 ) +{ +table_size = ROUNDUP(nr_items * entry_size, BIT(PAGE_BITS(pagesz))); +order = get_order_from_bytes(table_size); + Limit to 256 ITS pages, ITS spec doesn't support more than 256 ITS pages. /* Maximum of 256 ITS pages are allowed */ if ( (table_size >> PAGE_BITS(pagesz)) > GITS_BASER_PAGES_MAX ) table_size = BIT(PAGE_BITS(pagesz)) * GITS_BASER_PAGES_MAX; +if ( !buffer ) +buffer = alloc_xenheap_pages(order, 0); +if ( !buffer ) +return -ENOMEM; + Please zero memory memset(buffer, 0x00, order << PAGE_SHIFT) -- Shanker Donthineni Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project. ___ Xen-devel mailing list Xen-devel@lists.xen.org https://lists.xen.org/xen-devel
Re: [Xen-devel] [PATCH 04/28] ARM: GICv3 ITS: allocate device and collection table
@@ -42,8 +90,9 @@ void gicv3_its_dt_init(const struct dt_device_node *node); uint64_t gicv3_lpi_get_proptable(void); uint64_t gicv3_lpi_allocate_pendtable(void); -/* Initialize the host structures for LPIs. */ +/* Initialize the host structures for LPIs and the host ITSes. */ int gicv3_lpi_init_host_lpis(unsigned int nr_lpis); +int gicv3_its_init(struct host_its *hw_its); #else @@ -62,6 +111,10 @@ static inline int gicv3_lpi_init_host_lpis(unsigned int nr_lpis) { return 0; } +static inline int gicv3_its_init(struct host_its *hw_its) +{ +return 0; +} #endif /* CONFIG_HAS_ITS */ #endif /* __ASSEMBLY__ */ -- Shanker Donthineni Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project. ___ Xen-devel mailing list Xen-devel@lists.xen.org https://lists.xen.org/xen-devel
Re: [Xen-devel] [PATCH 15/28] ARM: vGICv3: introduce basic ITS emulation bits
ly differently depending on + * the used page size: the highest four bits are stored in the lowest + * four bits of the field for 64K pages. + */ +static paddr_t get_baser_phys_addr(uint64_t reg) +{ +if ( reg & BIT(9) ) +return (reg & GENMASK(47, 16)) | ((reg & GENMASK(15, 12)) << 36); +else +return reg & GENMASK(47, 12); +} + +static int vgic_v3_its_mmio_read(struct vcpu *v, mmio_info_t *info, + register_t *r, void *priv) +{ +struct virt_its *its = priv; + +switch ( info->gpa & 0x ) +{ +case VREG32(GITS_CTLR): +if ( info->dabt.size != DABT_WORD ) goto bad_width; +*r = vgic_reg32_extract(its->enabled | BIT(31), info); + break; +case VREG32(GITS_IIDR): +if ( info->dabt.size != DABT_WORD ) goto bad_width; +*r = vgic_reg32_extract(GITS_IIDR_VALUE, info); +break; +case VREG64(GITS_TYPER): +if ( info->dabt.size < DABT_WORD ) goto bad_width; +*r = vgic_reg64_extract(0x1eff1, info); Why GITS_TYPER is hard-coded here? For DOM0, at least MOVP, ID_bits and Devbits fields should be same as hardware otherwise MSI(x) feature fails for some devices. Shanker Donthineni Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project. ___ Xen-devel mailing list Xen-devel@lists.xen.org https://lists.xen.org/xen-devel
Re: [Xen-devel] [PATCH 04/28] ARM: GICv3 ITS: allocate device and collection table
GITS_BASER_SHAREABILITY_MASK (0x3ULL << GITS_BASER_SHAREABILITY_SHIFT) +#define GITS_BASER_OUTER_CACHEABILITY_MASK (0x7ULL << GITS_BASER_OUTER_CACHEABILITY_SHIFT) +#define GITS_BASER_INNER_CACHEABILITY_MASK (0x7ULL << GITS_BASER_INNER_CACHEABILITY_SHIFT) + #ifndef __ASSEMBLY__ #include @@ -27,6 +74,7 @@ struct host_its { const struct dt_device_node *dt_node; paddr_t addr; paddr_t size; +void __iomem *its_base; }; extern struct list_head host_its_list; @@ -42,8 +90,9 @@ void gicv3_its_dt_init(const struct dt_device_node *node); uint64_t gicv3_lpi_get_proptable(void); uint64_t gicv3_lpi_allocate_pendtable(void); -/* Initialize the host structures for LPIs. */ +/* Initialize the host structures for LPIs and the host ITSes. */ int gicv3_lpi_init_host_lpis(unsigned int nr_lpis); +int gicv3_its_init(struct host_its *hw_its); #else @@ -62,6 +111,10 @@ static inline int gicv3_lpi_init_host_lpis(unsigned int nr_lpis) { return 0; } +static inline int gicv3_its_init(struct host_its *hw_its) +{ +return 0; +} #endif /* CONFIG_HAS_ITS */ #endif /* __ASSEMBLY__ */ -- Shanker Donthineni Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project. ___ Xen-devel mailing list Xen-devel@lists.xen.org https://lists.xen.org/xen-devel
Re: [Xen-devel] [PATCH] arm/acpi: hide watchdog timer in GTDT table for dom0
Hi Julien, We are using Fu's [v5] patch series https://patchwork.codeaurora.org/patch/20325/ in our testing. We thought system crash in xen was related to watchdog timer driver, so removed the watchdog timer sections including GT blocks in GTDT to fix the crash. Let me root cause the issue and update the results to you by end of this week. Thanks, Shanker -- Shanker Donthineni Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project. ___ Xen-devel mailing list Xen-devel@lists.xen.org https://lists.xen.org/xen-devel
Re: [Xen-devel] [PATCH] arm/acpi: hide watchdog timer in GTDT table for dom0
Hi Julien, On 11/30/2016 08:31 AM, Shanker Donthineni wrote: Hi Julien, On 11/30/2016 04:29 AM, Julien Grall wrote: Hi Shanker, On 29/11/2016 02:59, Shanker Donthineni wrote: Either we have to hide the watchdog timer section in GTDT or emulate watchdog timer block for dom0. Otherwise, system gets panic when dom0 accesses its MMIO registers. The current XEN doesn't support virtualization of watchdog timer, so hide the watchdog timer section for dom0. IHMO, the patch description is not really accurate. You are removing the platform timer array that contains watchdog but also Block Timer. Whilst you mention watchdog, you don't have a word on the Block Timer. Sure, I'll include detailed description that has word 'Block Timer' in v2 patch. Taking a step back, DOM0 is not able to use it because it does not request to map the memory region (this is the behavior expected for PCI and AMBA devices). So this is a bug in the kernel for me. Not all the drivers/modules in the Linux kernel are bounded to a device object 'struct device'. The watchdog timer driver is one of this category, neither a PCIe nor a AMBA device. You can find GTDT watchdog timer code at https://lkml.org/lkml/2016/7/25/34. Sorry, right link is https://lkml.org/lkml/2016/7/25/345 Assuming this would be fixed, what would be the drawback to give access to dom0 to the watchdogs? Absolutely no problem. My worry with that change is what if in the future we decide to expose watchdog to DOM0? Linux will still not be ready, unless we have Xen to map those regions at DOM0 build time. That would break the design we have for ACPI. Agree, I was also thinking in the same direction. Let me create a v2 patch that does stage-2 map of MMIO regions at the time of building the dom0 domain to fix the problem. Regards, -- Shanker Donthineni Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project. ___ Xen-devel mailing list Xen-devel@lists.xen.org https://lists.xen.org/xen-devel
Re: [Xen-devel] [PATCH] arm/acpi: hide watchdog timer in GTDT table for dom0
Hi Julien, On 11/30/2016 04:29 AM, Julien Grall wrote: Hi Shanker, On 29/11/2016 02:59, Shanker Donthineni wrote: Either we have to hide the watchdog timer section in GTDT or emulate watchdog timer block for dom0. Otherwise, system gets panic when dom0 accesses its MMIO registers. The current XEN doesn't support virtualization of watchdog timer, so hide the watchdog timer section for dom0. IHMO, the patch description is not really accurate. You are removing the platform timer array that contains watchdog but also Block Timer. Whilst you mention watchdog, you don't have a word on the Block Timer. Sure, I'll include detailed description that has word 'Block Timer'. Taking a step back, DOM0 is not able to use it because it does not request to map the memory region (this is the behavior expected for PCI and AMBA devices). So this is a bug in the kernel for me. Not all the drivers/modules in the Linux kernel are bounded to a device object 'struct device'. The watchdog timer driver is one of this category, neither a PCIe nor a AMBA device. You can find GTDT watchdog timer code at https://lkml.org/lkml/2016/7/25/34. Assuming this would be fixed, what would be the drawback to give access to dom0 to the watchdogs? Absolutely no problem. My worry with that change is what if in the future we decide to expose watchdog to DOM0? Linux will still not be ready, unless we have Xen to map those regions at DOM0 build time. That would break the design we have for ACPI. Agree, I was also thinking in the same direction. Let me create a v2 patch that does stage-2 map of MMIO regions at the time of building the dom0 domain to fix the problem. Regards, -- Shanker Donthineni Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project. ___ Xen-devel mailing list Xen-devel@lists.xen.org https://lists.xen.org/xen-devel
[Xen-devel] [PATCH] arm/acpi: hide watchdog timer in GTDT table for dom0
Either we have to hide the watchdog timer section in GTDT or emulate watchdog timer block for dom0. Otherwise, system gets panic when dom0 accesses its MMIO registers. The current XEN doesn't support virtualization of watchdog timer, so hide the watchdog timer section for dom0. Signed-off-by: Shanker Donthineni <shank...@codeaurora.org> --- xen/arch/arm/domain_build.c | 41 + xen/include/asm-arm/acpi.h | 1 + 2 files changed, 42 insertions(+) diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c index e8a400c..611c803 100644 --- a/xen/arch/arm/domain_build.c +++ b/xen/arch/arm/domain_build.c @@ -1668,6 +1668,8 @@ static int acpi_create_xsdt(struct domain *d, struct membank tbl_add[]) ACPI_SIG_FADT, tbl_add[TBL_FADT].start); acpi_xsdt_modify_entry(xsdt->table_offset_entry, entry_count, ACPI_SIG_MADT, tbl_add[TBL_MADT].start); +acpi_xsdt_modify_entry(xsdt->table_offset_entry, entry_count, + ACPI_SIG_GTDT, tbl_add[TBL_GTDT].start); xsdt->table_offset_entry[entry_count] = tbl_add[TBL_STAO].start; xsdt->header.length = table_size; @@ -1718,6 +1720,41 @@ static int acpi_create_stao(struct domain *d, struct membank tbl_add[]) return 0; } +static int acpi_create_gtdt(struct domain *d, struct membank tbl_add[]) +{ +struct acpi_table_header *table = NULL; +struct acpi_table_gtdt *gtdt = NULL; +u32 table_size = sizeof(struct acpi_table_gtdt); +u32 offset = acpi_get_table_offset(tbl_add, TBL_GTDT); +acpi_status status; +u8 *base_ptr, checksum; + +status = acpi_get_table(ACPI_SIG_GTDT, 0, ); + +if ( ACPI_FAILURE(status) ) +{ +const char *msg = acpi_format_exception(status); + +printk("Failed to get GTDT table, %s\n", msg); +return -EINVAL; +} + +base_ptr = d->arch.efi_acpi_table + offset; +ACPI_MEMCPY(base_ptr, table, sizeof(struct acpi_table_gtdt)); + +gtdt = (struct acpi_table_gtdt *)base_ptr; +gtdt->header.length = table_size; +gtdt->platform_timer_count = 0; +gtdt->platform_timer_offset = table_size; +checksum = acpi_tb_checksum(ACPI_CAST_PTR(u8, gtdt), table_size); +gtdt->header.checksum -= checksum; + +tbl_add[TBL_GTDT].start = d->arch.efi_acpi_gpa + offset; +tbl_add[TBL_GTDT].size = table_size; + +return 0; +} + static int acpi_create_madt(struct domain *d, struct membank tbl_add[]) { struct acpi_table_header *table = NULL; @@ -1909,6 +1946,10 @@ static int prepare_acpi(struct domain *d, struct kernel_info *kinfo) if ( rc != 0 ) return rc; +rc = acpi_create_gtdt(d, tbl_add); +if ( rc != 0 ) +return rc; + rc = acpi_create_xsdt(d, tbl_add); if ( rc != 0 ) return rc; diff --git a/xen/include/asm-arm/acpi.h b/xen/include/asm-arm/acpi.h index 9f954d3..214511c 100644 --- a/xen/include/asm-arm/acpi.h +++ b/xen/include/asm-arm/acpi.h @@ -36,6 +36,7 @@ typedef enum { TBL_FADT, TBL_MADT, TBL_STAO, +TBL_GTDT, TBL_XSDT, TBL_RSDP, TBL_EFIT, -- Qualcomm Datacenter Technologies, Inc. on behalf of the Qualcomm Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project. ___ Xen-devel mailing list Xen-devel@lists.xen.org https://lists.xen.org/xen-devel
Re: [Xen-devel] [PATCH v2 5/6] xen/arm: traps: Avoid unnecessary VA -> IPA translation in abort handlers
On 08/17/2016 06:11 AM, Julien Grall wrote: On 17/08/16 03:19, Shanker Donthineni wrote: Hi Julien, Hello Shanker, On 07/27/2016 12:09 PM, Julien Grall wrote: Translating a VA to a IPA is expensive. Currently, Xen is assuming that HPFAR_EL2 is only valid when the stage-2 data/instruction abort happened during a translation table walk of a first stage translation (i.e S1PTW is set). However, based on the ARM ARM (D7.2.34 in DDI 0487A.j), the register is also valid when the data/instruction abort occured for a translation fault. With this change, the VA -> IPA translation will only happen for permission faults that are not related to a translation table of a first stage translation. Signed-off-by: Julien Grall <julien.gr...@arm.com> --- Changes in v2: - Use fsc in the switch in do_trap_data_abort_guest --- xen/arch/arm/traps.c | 24 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/xen/arch/arm/traps.c b/xen/arch/arm/traps.c index ea105f2..83a30fa 100644 --- a/xen/arch/arm/traps.c +++ b/xen/arch/arm/traps.c @@ -2382,13 +2382,28 @@ static inline paddr_t get_faulting_ipa(vaddr_t gva) return ipa; } +static inline bool hpfar_is_valid(bool s1ptw, uint8_t fsc) +{ +/* + * HPFAR is valid if one of the following cases are true: + * 1. the stage 2 fault happen during a stage 1 page table walk + * (the bit ESR_EL2.S1PTW is set) + * 2. the fault was due to a translation fault + * + * Note that technically HPFAR is valid for other cases, but they + * are currently not supported by Xen. + */ +return s1ptw || (fsc == FSC_FLT_TRANS); Yes, XEN is not supporting the stage 2 access flag but we should handle a stage 2 address size fault. The function hpfar_is_valid indicates whether the register HPFAR is valid. If the function returns false, Xen will use the hardware do the translation. It will only lead to a waste of cycle but this is fine as the address size fault is not a hot path for now. I think we should do some thing like to below to match ARM ARM. return s1ptw || (fsc != FSC_FLT_PERM); This does not match the ARM ARM, with this check you consider that HPFAR will be valid for all the fault but permission ones which is not true. I purposefully choose a white list because it is safer to use the hardware to do the translation more often than the invert. So I don't see why we should handle stage 2 access flag with the current Xen. If you still disagree, please explain why with a concrete example. Agree with you, I have suggested the above change because I saw the same check in Linux KVM. As per ARM ARM, it should be 'return s1ptw || (fsc == FSC_FLT_TRANS) || (fsc == FSC_FLT_ACCESS) || (fsc == 0x00)'; Regards, -- Shanker Donthineni Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project. ___ Xen-devel mailing list Xen-devel@lists.xen.org https://lists.xen.org/xen-devel
Re: [Xen-devel] [RFC 00/22] xen/arm: Rework the P2M code to follow break-before-make sequence
Hi Julien, I have verified this patch series on Qualcomm Server platform QDF2XXX without any issue. Tested-by: Shanker Donthineni <shank...@codeaurora.org> On 08/15/2016 10:06 AM, Edgar E. Iglesias wrote: On Thu, Jul 28, 2016 at 03:51:23PM +0100, Julien Grall wrote: Hello all, The ARM architecture mandates the use of a break-before-make sequence when changing translation entries if the page table is shared between multiple CPUs whenever a valid entry is replaced by another valid entry (see D4.7.1 in ARM DDI 0487A.j for more details). The current P2M code does not respect this sequence and may result to break coherency on some processors. Adapting the current implementation to use break-before-make sequence would imply some code duplication and more TLBs invalidations than necessary. For instance, if we are replacing a 4KB page and the current mapping in the P2M is using a 1GB superpage, the following steps will happen: 1) Shatter the 1GB superpage into a series of 2MB superpages 2) Shatter the 2MB superpage into a series of 4KB superpages 3) Replace the 4KB page As the current implementation is shattering while descending and install the mapping before continuing to the next level, Xen would need to issue 3 TLB invalidation instructions which is clearly inefficient. Furthermore, all the operations which modify the page table are using the same skeleton. It is more complicated to maintain different code paths than having a generic function that set an entry and take care of the break-before- make sequence. The new implementation is based on the x86 EPT one which, I think, fits quite well for the break-before-make sequence whilst keeping the code simple. I sent this patch series as an RFC because there are still some TODOs in the code (mostly sanity check and possible optimization) and I have done limited testing. However, I think it is a good shape to start reviewing, get more feedback and have wider testing on different board. Also, I need to figure out the impact on ARM32 because the domheap is not always mapped. This series has dependencies on some rework sent separately ([1] and [2]). I have provided a branch with all the dependencies and this series applied: git://xenbits.xen.org/people/julieng/xen-unstable.git branch p2m-rfc Hi Julien, FWIW, I gave this a spin on the ZynqMP and it seems to be working fine. I tried dom0 and starting a few additional guests. All looks good. Tested-by: Edgar E. Iglesias <edgar.igles...@xilinx.com> Cheers, Edgar Comments are welcome. Yours sincerely, Cc: Razvan Cojocaru <rcojoc...@bitdefender.com> Cc: Tamas K Lengyel <ta...@tklengyel.com> Cc: Shanker Donthineni <shank...@codeaurora.org> Cc: Dirk Behme <dirk.be...@de.bosch.com> Cc: Edgar E. Iglesias <edgar.igles...@xilinx.com> [1] https://lists.xenproject.org/archives/html/xen-devel/2016-07/msg02936.html [2] https://lists.xenproject.org/archives/html/xen-devel/2016-07/msg02830.html Julien Grall (22): xen/arm: do_trap_instr_abort_guest: Move the IPA computation out of the switch xen/arm: p2m: Store in p2m_domain whether we need to clean the entry xen/arm: p2m: Rename parameter in p2m_{remove,write}_pte... xen/arm: p2m: Use typesafe gfn in p2m_mem_access_radix_set xen/arm: traps: Move MMIO emulation code in a separate helper xen/arm: traps: Check the P2M before injecting a data/instruction abort xen/arm: p2m: Rework p2m_put_l3_page xen/arm: p2m: Invalidate the TLBs when write unlocking the p2m xen/arm: p2m: Change the type of level_shifts from paddr_t to unsigned int xen/arm: p2m: Move the lookup helpers at the top of the file xen/arm: p2m: Introduce p2m_get_root_pointer and use it in __p2m_lookup xen/arm: p2m: Introduce p2m_get_entry and use it to implement __p2m_lookup xen/arm: p2m: Replace all usage of __p2m_lookup with p2m_get_entry xen/arm: p2m: Re-implement p2m_cache_flush using p2m_get_entry xen/arm: p2m: Re-implement relinquish_p2m_mapping using p2m_get_entry xen/arm: p2m: Make p2m_{valid,table,mapping} helpers inline xen/arm: p2m: Introduce a helper to check if an entry is a superpage xen/arm: p2m: Introduce p2m_set_entry and __p2m_set_entry xen/arm: p2m: Re-implement p2m_remove_using using p2m_set_entry xen/arm: p2m: Re-implement p2m_insert_mapping using p2m_set_entry xen/arm: p2m: Re-implement p2m_set_mem_access using p2m_{set,get}_entry xen/arm: p2m: Do not handle shattering in p2m_create_table xen/arch/arm/domain.c |8 +- xen/arch/arm/p2m.c | 1274 ++-- xen/arch/arm/traps.c | 126 +++-- xen/include/asm-arm/p2m.h | 14 + xen/include/asm-arm/page.h |4 + 5 files changed, 742 insertions(+), 684 deletions(-) -- 1.9.1 -- Shanker Donthineni Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm Technologies, Inc. Qualcomm Technologies,
Re: [Xen-devel] [PATCH v2 5/6] xen/arm: traps: Avoid unnecessary VA -> IPA translation in abort handlers
Hi Julien, On 07/27/2016 12:09 PM, Julien Grall wrote: Translating a VA to a IPA is expensive. Currently, Xen is assuming that HPFAR_EL2 is only valid when the stage-2 data/instruction abort happened during a translation table walk of a first stage translation (i.e S1PTW is set). However, based on the ARM ARM (D7.2.34 in DDI 0487A.j), the register is also valid when the data/instruction abort occured for a translation fault. With this change, the VA -> IPA translation will only happen for permission faults that are not related to a translation table of a first stage translation. Signed-off-by: Julien Grall <julien.gr...@arm.com> --- Changes in v2: - Use fsc in the switch in do_trap_data_abort_guest --- xen/arch/arm/traps.c | 24 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/xen/arch/arm/traps.c b/xen/arch/arm/traps.c index ea105f2..83a30fa 100644 --- a/xen/arch/arm/traps.c +++ b/xen/arch/arm/traps.c @@ -2382,13 +2382,28 @@ static inline paddr_t get_faulting_ipa(vaddr_t gva) return ipa; } +static inline bool hpfar_is_valid(bool s1ptw, uint8_t fsc) +{ +/* + * HPFAR is valid if one of the following cases are true: + * 1. the stage 2 fault happen during a stage 1 page table walk + * (the bit ESR_EL2.S1PTW is set) + * 2. the fault was due to a translation fault + * + * Note that technically HPFAR is valid for other cases, but they + * are currently not supported by Xen. + */ +return s1ptw || (fsc == FSC_FLT_TRANS); Yes, XEN is not supporting the stage 2 access flag but we should handle a stage 2 address size fault. I think we should do some thing like to below to match ARM ARM. return s1ptw || (fsc != FSC_FLT_PERM); +} + static void do_trap_instr_abort_guest(struct cpu_user_regs *regs, const union hsr hsr) { int rc; register_t gva = READ_SYSREG(FAR_EL2); +uint8_t fsc = hsr.iabt.ifsc & ~FSC_LL_MASK; -switch ( hsr.iabt.ifsc & ~FSC_LL_MASK ) +switch ( fsc ) { case FSC_FLT_PERM: { @@ -2399,7 +2414,7 @@ static void do_trap_instr_abort_guest(struct cpu_user_regs *regs, .kind = hsr.iabt.s1ptw ? npfec_kind_in_gpt : npfec_kind_with_gla }; -if ( hsr.iabt.s1ptw ) +if ( hpfar_is_valid(hsr.iabt.s1ptw, fsc) ) gpa = get_faulting_ipa(gva); else { @@ -2434,6 +2449,7 @@ static void do_trap_data_abort_guest(struct cpu_user_regs *regs, const struct hsr_dabt dabt = hsr.dabt; int rc; mmio_info_t info; +uint8_t fsc = hsr.dabt.dfsc & ~FSC_LL_MASK; info.dabt = dabt; #ifdef CONFIG_ARM_32 @@ -2442,7 +2458,7 @@ static void do_trap_data_abort_guest(struct cpu_user_regs *regs, info.gva = READ_SYSREG64(FAR_EL2); #endif -if ( dabt.s1ptw ) +if ( hpfar_is_valid(hsr.iabt.s1ptw, fsc) ) info.gpa = get_faulting_ipa(info.gva); else { @@ -2451,7 +2467,7 @@ static void do_trap_data_abort_guest(struct cpu_user_regs *regs, return; /* Try again */ } -switch ( dabt.dfsc & ~FSC_LL_MASK ) +switch ( fsc ) { case FSC_FLT_PERM: { -- Shanker Donthineni Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project. ___ Xen-devel mailing list Xen-devel@lists.xen.org https://lists.xen.org/xen-devel
[Xen-devel] [PATCH V3 2/4] xen: Add generic implementation of binary search
This patch adds the generic implementation of binary search algorithm which is copied from Linux kernel v4.7-rc7. No functional changes. Signed-off-by: Shanker Donthineni <shank...@codeaurora.org> Reviewed-by: Andrew Cooper <andrew.coop...@citrix.com> Reviewed-by: Julien Grall <julien.gr...@arm.com> --- Changes since v2: Fixed the compilation issue due to a missing ';'. Fixed typo. Changes since v1: Removed the header file xen/include/xen/bsearch.h. Defined function bsearch() prototype in the header file xen/lib.h. xen/common/Makefile | 1 + xen/common/bsearch.c | 51 +++ xen/include/xen/lib.h | 3 +++ 3 files changed, 55 insertions(+) create mode 100644 xen/common/bsearch.c diff --git a/xen/common/Makefile b/xen/common/Makefile index dbf00c6..f8123c2 100644 --- a/xen/common/Makefile +++ b/xen/common/Makefile @@ -43,6 +43,7 @@ obj-y += schedule.o obj-y += shutdown.o obj-y += softirq.o obj-y += sort.o +obj-y += bsearch.o obj-y += smp.o obj-y += spinlock.o obj-y += stop_machine.o diff --git a/xen/common/bsearch.c b/xen/common/bsearch.c new file mode 100644 index 000..7090930 --- /dev/null +++ b/xen/common/bsearch.c @@ -0,0 +1,51 @@ +/* + * A generic implementation of binary search for the Linux kernel + * + * Copyright (C) 2008-2009 Ksplice, Inc. + * Author: Tim Abbott <tabb...@ksplice.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; version 2. + */ + +#include + +/* + * bsearch - binary search an array of elements + * @key: pointer to item being searched for + * @base: pointer to first element to search + * @num: number of elements + * @size: size of each element + * @cmp: pointer to comparison function + * + * This function does a binary search on the given array. The + * contents of the array should already be in ascending sorted order + * under the provided comparison function. + * + * Note that the key need not have the same type as the elements in + * the array, e.g. key could be a string and the comparison function + * could compare the string with the struct's name field. However, if + * the key and elements in the array are of the same type, you can use + * the same comparison function for both sort() and bsearch(). + */ +void *bsearch(const void *key, const void *base, size_t num, size_t size, + int (*cmp)(const void *key, const void *elt)) +{ + size_t start = 0, end = num; + int result; + + while (start < end) { + size_t mid = start + (end - start) / 2; + + result = cmp(key, base + mid * size); + if (result < 0) + end = mid; + else if (result > 0) + start = mid + 1; + else + return (void *)base + mid * size; + } + + return NULL; +} diff --git a/xen/include/xen/lib.h b/xen/include/xen/lib.h index b1b0fb2..b90d582 100644 --- a/xen/include/xen/lib.h +++ b/xen/include/xen/lib.h @@ -153,4 +153,7 @@ void dump_execstate(struct cpu_user_regs *); void init_constructors(void); +void *bsearch(const void *key, const void *base, size_t num, size_t size, + int (*cmp)(const void *key, const void *elt)); + #endif /* __LIB_H__ */ -- Qualcomm Datacenter Technologies, Inc. on behalf of the Qualcomm Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project. ___ Xen-devel mailing list Xen-devel@lists.xen.org https://lists.xen.org/xen-devel
[Xen-devel] [PATCH V3 4/4] arm/vgic: Change fixed number of mmio handlers to variable number
Compute the number of mmio handlers that are required for vGICv3 and vGICv2 emulation drivers in vgic_v3_init()/vgic_v2_init(). Augment this variable number of mmio handers to a fixed number MAX_IO_HANDLER and pass it to domain_io_init() to allocate enough memory. New code path: domain_vgic_register() domain_io_init(count + MAX_IO_HANDLER) domain_vgic_init() Signed-off-by: Shanker Donthineni <shank...@codeaurora.org> --- xen/arch/arm/domain.c | 12 +++- xen/arch/arm/vgic-v2.c | 3 ++- xen/arch/arm/vgic-v3.c | 5 - xen/arch/arm/vgic.c| 10 +++--- xen/include/asm-arm/vgic.h | 5 +++-- 5 files changed, 19 insertions(+), 16 deletions(-) diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c index 0170cee..4e5259b 100644 --- a/xen/arch/arm/domain.c +++ b/xen/arch/arm/domain.c @@ -546,7 +546,7 @@ void vcpu_destroy(struct vcpu *v) int arch_domain_create(struct domain *d, unsigned int domcr_flags, struct xen_arch_domainconfig *config) { -int rc, count; +int rc, count = 0; d->arch.relmem = RELMEM_not_started; @@ -569,10 +569,6 @@ int arch_domain_create(struct domain *d, unsigned int domcr_flags, share_xen_page_with_guest( virt_to_page(d->shared_info), d, XENSHARE_writable); -count = MAX_IO_HANDLER; -if ( (rc = domain_io_init(d, count)) != 0 ) -goto fail; - if ( (rc = p2m_alloc_table(d)) != 0 ) goto fail; @@ -609,6 +605,12 @@ int arch_domain_create(struct domain *d, unsigned int domcr_flags, goto fail; } +if ( (rc = domain_vgic_register(d, )) != 0 ) +goto fail; + +if ( (rc = domain_io_init(d, count + MAX_IO_HANDLER)) != 0 ) +goto fail; + if ( (rc = domain_vgic_init(d, config->nr_spis)) != 0 ) goto fail; diff --git a/xen/arch/arm/vgic-v2.c b/xen/arch/arm/vgic-v2.c index 6a5e67b..c6d280e 100644 --- a/xen/arch/arm/vgic-v2.c +++ b/xen/arch/arm/vgic-v2.c @@ -711,7 +711,7 @@ static const struct vgic_ops vgic_v2_ops = { .max_vcpus = 8, }; -int vgic_v2_init(struct domain *d) +int vgic_v2_init(struct domain *d, int *mmio_count) { if ( !vgic_v2_hw.enabled ) { @@ -721,6 +721,7 @@ int vgic_v2_init(struct domain *d) return -ENODEV; } +*mmio_count = 1; /* Only GICD region */ register_vgic_ops(d, _v2_ops); return 0; diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c index be9a9a3..ec038a3 100644 --- a/xen/arch/arm/vgic-v3.c +++ b/xen/arch/arm/vgic-v3.c @@ -1499,7 +1499,7 @@ static const struct vgic_ops v3_ops = { .max_vcpus = 4096, }; -int vgic_v3_init(struct domain *d) +int vgic_v3_init(struct domain *d, int *mmio_count) { if ( !vgic_v3_hw.enabled ) { @@ -1509,6 +1509,9 @@ int vgic_v3_init(struct domain *d) return -ENODEV; } +/* GICD region + number of Redistributors */ +*mmio_count = vgic_v3_rdist_count(d) + 1; + register_vgic_ops(d, _ops); return 0; diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c index a7ccfe7..768cb91 100644 --- a/xen/arch/arm/vgic.c +++ b/xen/arch/arm/vgic.c @@ -88,18 +88,18 @@ static void vgic_rank_init(struct vgic_irq_rank *rank, uint8_t index, rank->vcpu[i] = vcpu; } -static int domain_vgic_register(struct domain *d) +int domain_vgic_register(struct domain *d, int *mmio_count) { switch ( d->arch.vgic.version ) { #ifdef CONFIG_HAS_GICV3 case GIC_V3: -if ( vgic_v3_init(d) ) +if ( vgic_v3_init(d, mmio_count) ) return -ENODEV; break; #endif case GIC_V2: -if ( vgic_v2_init(d) ) +if ( vgic_v2_init(d, mmio_count) ) return -ENODEV; break; default: @@ -124,10 +124,6 @@ int domain_vgic_init(struct domain *d, unsigned int nr_spis) d->arch.vgic.nr_spis = nr_spis; -ret = domain_vgic_register(d); -if ( ret < 0 ) -return ret; - spin_lock_init(>arch.vgic.lock); d->arch.vgic.shared_irqs = diff --git a/xen/include/asm-arm/vgic.h b/xen/include/asm-arm/vgic.h index c3cc4f6..300f461 100644 --- a/xen/include/asm-arm/vgic.h +++ b/xen/include/asm-arm/vgic.h @@ -304,9 +304,10 @@ extern int vgic_emulate(struct cpu_user_regs *regs, union hsr hsr); extern void vgic_disable_irqs(struct vcpu *v, uint32_t r, int n); extern void vgic_enable_irqs(struct vcpu *v, uint32_t r, int n); extern void register_vgic_ops(struct domain *d, const struct vgic_ops *ops); -int vgic_v2_init(struct domain *d); -int vgic_v3_init(struct domain *d); +int vgic_v2_init(struct domain *d, int *mmio_count); +int vgic_v3_init(struct domain *d, int *mmio_count); +extern int domain_vgic_register(struct domain *d, int *mmio_count); extern int vcpu_vgic_free(struct vcpu *v); extern int vgic_to_sgi(struct vcpu *v, register_t sgir, enum gic_sgi_mode irqmode, int virq, -- Qualcomm Datacenter Technologies, Inc. on behalf of the Qual
[Xen-devel] [PATCH V3 0/4] Change fixed mmio handlers to a variable number
The maximum number of mmio handlers that are allowed is limited to a macro MAX_IO_HANDLER(16), which is not enough for supporting per CPU Redistributor regions. We need at least MAX_IO_HANDLER+CONFIG_NR_CPUS mmio handlers in order to support ACPI based XEN boot. This patchset uses the dynamic allocation strategy to allocate memory resource dynamically depends on the number of Redistributor regions that are described in the APCI MADT table. Shanker Donthineni (4): arm/io: Use separate memory allocation for mmio handlers xen: Add generic implementation of binary search xen/arm: io: Use binary search for mmio handler lookup arm/vgic: Change fixed number of mmio handlers to variable number xen/arch/arm/domain.c | 12 +++ xen/arch/arm/io.c | 52 +++--- xen/arch/arm/vgic-v2.c | 3 ++- xen/arch/arm/vgic-v3.c | 5 - xen/arch/arm/vgic.c| 10 +++-- xen/common/Makefile| 1 + xen/common/bsearch.c | 51 + xen/include/asm-arm/mmio.h | 7 +-- xen/include/asm-arm/vgic.h | 5 +++-- xen/include/xen/lib.h | 3 +++ 10 files changed, 115 insertions(+), 34 deletions(-) create mode 100644 xen/common/bsearch.c -- Qualcomm Datacenter Technologies, Inc. on behalf of the Qualcomm Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project. ___ Xen-devel mailing list Xen-devel@lists.xen.org https://lists.xen.org/xen-devel
[Xen-devel] [PATCH V3 3/4] xen/arm: io: Use binary search for mmio handler lookup
As the number of I/O handlers increase, the overhead associated with linear lookup also increases. The system might have maximum of 144 (assuming CONFIG_NR_CPUS=128) mmio handlers. In worst case scenario, it would require 144 iterations for finding a matching handler. Now it is time for us to change from linear (complexity O(n)) to a binary search (complexity O(log n) for reducing mmio handler lookup overhead. Signed-off-by: Shanker Donthineni <shank...@codeaurora.org> --- xen/arch/arm/io.c | 39 --- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/xen/arch/arm/io.c b/xen/arch/arm/io.c index 40330f0..e8aa7fa 100644 --- a/xen/arch/arm/io.c +++ b/xen/arch/arm/io.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -70,27 +71,31 @@ static int handle_write(const struct mmio_handler *handler, struct vcpu *v, handler->priv); } -static const struct mmio_handler *find_mmio_handler(struct domain *d, -paddr_t gpa) +/* This function assumes that mmio regions are not overlapped */ +static int cmp_mmio_handler(const void *key, const void *elem) { -const struct mmio_handler *handler; -unsigned int i; -struct vmmio *vmmio = >arch.vmmio; +const struct mmio_handler *handler0 = key; +const struct mmio_handler *handler1 = elem; -read_lock(>lock); +if ( handler0->addr < handler1->addr ) +return -1; -for ( i = 0; i < vmmio->num_entries; i++ ) -{ -handler = >handlers[i]; +if ( handler0->addr > (handler1->addr + handler1->size) ) +return 1; -if ( (gpa >= handler->addr) && - (gpa < (handler->addr + handler->size)) ) -break; -} +return 0; +} -if ( i == vmmio->num_entries ) -handler = NULL; +static const struct mmio_handler *find_mmio_handler(struct domain *d, +paddr_t gpa) +{ +struct vmmio *vmmio = >arch.vmmio; +struct mmio_handler key = {.addr = gpa}; +const struct mmio_handler *handler; +read_lock(>lock); +handler = bsearch(, vmmio->handlers, vmmio->num_entries, + sizeof(*handler), cmp_mmio_handler); read_unlock(>lock); return handler; @@ -131,6 +136,10 @@ void register_mmio_handler(struct domain *d, vmmio->num_entries++; +/* Sort mmio handlers in ascending order based on base address */ +sort(vmmio->handlers, vmmio->num_entries, sizeof(struct mmio_handler), + cmp_mmio_handler, NULL); + write_unlock(>lock); } -- Qualcomm Datacenter Technologies, Inc. on behalf of the Qualcomm Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project. ___ Xen-devel mailing list Xen-devel@lists.xen.org https://lists.xen.org/xen-devel
[Xen-devel] [PATCH V3 1/4] arm/io: Use separate memory allocation for mmio handlers
The number of mmio handlers are limited to a compile time macro MAX_IO_HANDLER which is 16. This number is not at all sufficient to support per CPU distributor regions. Either it needs to be increased to a bigger number, at least CONFIG_NR_CPUS+16, or allocate a separate memory for mmio handlers dynamically during domain build. This patch uses the dynamic allocation strategy to reduce memory footprint for 'struct domain' instead of static allocation. Signed-off-by: Shanker Donthineni <shank...@codeaurora.org> Acked-by: Julien Grall <julien.gr...@arm.com> --- xen/arch/arm/domain.c | 6 -- xen/arch/arm/io.c | 13 +++-- xen/include/asm-arm/mmio.h | 7 +-- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c index 61fc08e..0170cee 100644 --- a/xen/arch/arm/domain.c +++ b/xen/arch/arm/domain.c @@ -546,7 +546,7 @@ void vcpu_destroy(struct vcpu *v) int arch_domain_create(struct domain *d, unsigned int domcr_flags, struct xen_arch_domainconfig *config) { -int rc; +int rc, count; d->arch.relmem = RELMEM_not_started; @@ -569,7 +569,8 @@ int arch_domain_create(struct domain *d, unsigned int domcr_flags, share_xen_page_with_guest( virt_to_page(d->shared_info), d, XENSHARE_writable); -if ( (rc = domain_io_init(d)) != 0 ) +count = MAX_IO_HANDLER; +if ( (rc = domain_io_init(d, count)) != 0 ) goto fail; if ( (rc = p2m_alloc_table(d)) != 0 ) @@ -663,6 +664,7 @@ void arch_domain_destroy(struct domain *d) free_xenheap_pages(d->arch.efi_acpi_table, get_order_from_bytes(d->arch.efi_acpi_len)); #endif +domain_io_free(d); } void arch_domain_shutdown(struct domain *d) diff --git a/xen/arch/arm/io.c b/xen/arch/arm/io.c index 5a96836..40330f0 100644 --- a/xen/arch/arm/io.c +++ b/xen/arch/arm/io.c @@ -118,7 +118,7 @@ void register_mmio_handler(struct domain *d, struct vmmio *vmmio = >arch.vmmio; struct mmio_handler *handler; -BUG_ON(vmmio->num_entries >= MAX_IO_HANDLER); +BUG_ON(vmmio->num_entries >= vmmio->max_num_entries); write_lock(>lock); @@ -134,14 +134,23 @@ void register_mmio_handler(struct domain *d, write_unlock(>lock); } -int domain_io_init(struct domain *d) +int domain_io_init(struct domain *d, int max_count) { rwlock_init(>arch.vmmio.lock); d->arch.vmmio.num_entries = 0; +d->arch.vmmio.max_num_entries = max_count; +d->arch.vmmio.handlers = xzalloc_array(struct mmio_handler, max_count); +if ( !d->arch.vmmio.handlers ) +return -ENOMEM; return 0; } +void domain_io_free(struct domain *d) +{ +xfree(d->arch.vmmio.handlers); +} + /* * Local variables: * mode: C diff --git a/xen/include/asm-arm/mmio.h b/xen/include/asm-arm/mmio.h index 32f10f2..c620eed 100644 --- a/xen/include/asm-arm/mmio.h +++ b/xen/include/asm-arm/mmio.h @@ -52,15 +52,18 @@ struct mmio_handler { struct vmmio { int num_entries; +int max_num_entries; rwlock_t lock; -struct mmio_handler handlers[MAX_IO_HANDLER]; +struct mmio_handler *handlers; }; extern int handle_mmio(mmio_info_t *info); void register_mmio_handler(struct domain *d, const struct mmio_handler_ops *ops, paddr_t addr, paddr_t size, void *priv); -int domain_io_init(struct domain *d); +int domain_io_init(struct domain *d, int max_count); +void domain_io_free(struct domain *d); + #endif /* __ASM_ARM_MMIO_H__ */ -- Qualcomm Datacenter Technologies, Inc. on behalf of the Qualcomm Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project. ___ Xen-devel mailing list Xen-devel@lists.xen.org https://lists.xen.org/xen-devel
[Xen-devel] [PATCH V2 1/4] arm/io: Use separate memory allocation for mmio handlers
The number of mmio handlers are limited to a compile time macro MAX_IO_HANDLER which is 16. This number is not at all sufficient to support per CPU distributor regions. Either it needs to be increased to a bigger number, at least CONFIG_NR_CPUS+16, or allocate a separate memory for mmio handlers dynamically during domain build. This patch uses the dynamic allocation strategy to reduce memory footprint for 'struct domain' instead of static allocation. Signed-off-by: Shanker Donthineni <shank...@codeaurora.org> Acked-by: Julien Grall <julien.gr...@arm.com> --- xen/arch/arm/domain.c | 6 -- xen/arch/arm/io.c | 13 +++-- xen/include/asm-arm/mmio.h | 7 +-- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c index 61fc08e..0170cee 100644 --- a/xen/arch/arm/domain.c +++ b/xen/arch/arm/domain.c @@ -546,7 +546,7 @@ void vcpu_destroy(struct vcpu *v) int arch_domain_create(struct domain *d, unsigned int domcr_flags, struct xen_arch_domainconfig *config) { -int rc; +int rc, count; d->arch.relmem = RELMEM_not_started; @@ -569,7 +569,8 @@ int arch_domain_create(struct domain *d, unsigned int domcr_flags, share_xen_page_with_guest( virt_to_page(d->shared_info), d, XENSHARE_writable); -if ( (rc = domain_io_init(d)) != 0 ) +count = MAX_IO_HANDLER; +if ( (rc = domain_io_init(d, count)) != 0 ) goto fail; if ( (rc = p2m_alloc_table(d)) != 0 ) @@ -663,6 +664,7 @@ void arch_domain_destroy(struct domain *d) free_xenheap_pages(d->arch.efi_acpi_table, get_order_from_bytes(d->arch.efi_acpi_len)); #endif +domain_io_free(d); } void arch_domain_shutdown(struct domain *d) diff --git a/xen/arch/arm/io.c b/xen/arch/arm/io.c index 5a96836..40330f0 100644 --- a/xen/arch/arm/io.c +++ b/xen/arch/arm/io.c @@ -118,7 +118,7 @@ void register_mmio_handler(struct domain *d, struct vmmio *vmmio = >arch.vmmio; struct mmio_handler *handler; -BUG_ON(vmmio->num_entries >= MAX_IO_HANDLER); +BUG_ON(vmmio->num_entries >= vmmio->max_num_entries); write_lock(>lock); @@ -134,14 +134,23 @@ void register_mmio_handler(struct domain *d, write_unlock(>lock); } -int domain_io_init(struct domain *d) +int domain_io_init(struct domain *d, int max_count) { rwlock_init(>arch.vmmio.lock); d->arch.vmmio.num_entries = 0; +d->arch.vmmio.max_num_entries = max_count; +d->arch.vmmio.handlers = xzalloc_array(struct mmio_handler, max_count); +if ( !d->arch.vmmio.handlers ) +return -ENOMEM; return 0; } +void domain_io_free(struct domain *d) +{ +xfree(d->arch.vmmio.handlers); +} + /* * Local variables: * mode: C diff --git a/xen/include/asm-arm/mmio.h b/xen/include/asm-arm/mmio.h index 32f10f2..c620eed 100644 --- a/xen/include/asm-arm/mmio.h +++ b/xen/include/asm-arm/mmio.h @@ -52,15 +52,18 @@ struct mmio_handler { struct vmmio { int num_entries; +int max_num_entries; rwlock_t lock; -struct mmio_handler handlers[MAX_IO_HANDLER]; +struct mmio_handler *handlers; }; extern int handle_mmio(mmio_info_t *info); void register_mmio_handler(struct domain *d, const struct mmio_handler_ops *ops, paddr_t addr, paddr_t size, void *priv); -int domain_io_init(struct domain *d); +int domain_io_init(struct domain *d, int max_count); +void domain_io_free(struct domain *d); + #endif /* __ASM_ARM_MMIO_H__ */ -- Qualcomm Datacenter Technologies, Inc. on behalf of the Qualcomm Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project. ___ Xen-devel mailing list Xen-devel@lists.xen.org https://lists.xen.org/xen-devel
[Xen-devel] [PATCH V2 2/4] xen: Add generic implementation of binary search
This patch adds the generic implementation of binary search algorithm whcih is copied from Linux kernel v4.7-rc7. No functional changes. Signed-off-by: Shanker Donthineni <shank...@codeaurora.org> Reviewed-by: Andrew Cooper <andrew.coop...@citrix.com> --- Changes since v1: Removed the header file xen/include/xen/bsearch.h. Defined function bsearch() prototype in the header file xen/lib.h. xen/common/Makefile | 1 + xen/common/bsearch.c | 51 +++ xen/include/xen/lib.h | 3 +++ 3 files changed, 55 insertions(+) create mode 100644 xen/common/bsearch.c diff --git a/xen/common/Makefile b/xen/common/Makefile index dbf00c6..f8123c2 100644 --- a/xen/common/Makefile +++ b/xen/common/Makefile @@ -43,6 +43,7 @@ obj-y += schedule.o obj-y += shutdown.o obj-y += softirq.o obj-y += sort.o +obj-y += bsearch.o obj-y += smp.o obj-y += spinlock.o obj-y += stop_machine.o diff --git a/xen/common/bsearch.c b/xen/common/bsearch.c new file mode 100644 index 000..7090930 --- /dev/null +++ b/xen/common/bsearch.c @@ -0,0 +1,51 @@ +/* + * A generic implementation of binary search for the Linux kernel + * + * Copyright (C) 2008-2009 Ksplice, Inc. + * Author: Tim Abbott <tabb...@ksplice.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; version 2. + */ + +#include + +/* + * bsearch - binary search an array of elements + * @key: pointer to item being searched for + * @base: pointer to first element to search + * @num: number of elements + * @size: size of each element + * @cmp: pointer to comparison function + * + * This function does a binary search on the given array. The + * contents of the array should already be in ascending sorted order + * under the provided comparison function. + * + * Note that the key need not have the same type as the elements in + * the array, e.g. key could be a string and the comparison function + * could compare the string with the struct's name field. However, if + * the key and elements in the array are of the same type, you can use + * the same comparison function for both sort() and bsearch(). + */ +void *bsearch(const void *key, const void *base, size_t num, size_t size, + int (*cmp)(const void *key, const void *elt)) +{ + size_t start = 0, end = num; + int result; + + while (start < end) { + size_t mid = start + (end - start) / 2; + + result = cmp(key, base + mid * size); + if (result < 0) + end = mid; + else if (result > 0) + start = mid + 1; + else + return (void *)base + mid * size; + } + + return NULL; +} diff --git a/xen/include/xen/lib.h b/xen/include/xen/lib.h index b1b0fb2..b90d582 100644 --- a/xen/include/xen/lib.h +++ b/xen/include/xen/lib.h @@ -153,4 +153,7 @@ void dump_execstate(struct cpu_user_regs *); void init_constructors(void); +void *bsearch(const void *key, const void *base, size_t num, size_t size, + int (*cmp)(const void *key, const void *elt)) + #endif /* __LIB_H__ */ -- Qualcomm Datacenter Technologies, Inc. on behalf of the Qualcomm Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project. ___ Xen-devel mailing list Xen-devel@lists.xen.org https://lists.xen.org/xen-devel
[Xen-devel] [PATCH V2 0/4] Change fixed mmio handlers to a variable number
The maximum number of mmio handlers that are allowed is limited to a macro MAX_IO_HANDLER(16), which is not enough for supporting per CPU Redistributor regions. We need at least MAX_IO_HANDLER+CONFIG_NR_CPUS mmio handlers in order to support ACPI based XEN boot. This patchset uses the dynamic allocation strategy to allocate memory resource dynamically depends on the number of Redistributor regions that are described in the APCI MADT table. Shanker Donthineni (4): arm/io: Use separate memory allocation for mmio handlers xen: Add generic implementation of binary search xen/arm: io: Use binary search for mmio handler lookup arm/vgic: Change fixed number of mmio handlers to variable number xen/arch/arm/domain.c | 12 +++ xen/arch/arm/io.c | 52 +++--- xen/arch/arm/vgic-v2.c | 3 ++- xen/arch/arm/vgic-v3.c | 5 - xen/arch/arm/vgic.c| 10 +++-- xen/common/Makefile| 1 + xen/common/bsearch.c | 51 + xen/include/asm-arm/mmio.h | 7 +-- xen/include/asm-arm/vgic.h | 5 +++-- xen/include/xen/lib.h | 3 +++ 10 files changed, 115 insertions(+), 34 deletions(-) create mode 100644 xen/common/bsearch.c -- Qualcomm Datacenter Technologies, Inc. on behalf of the Qualcomm Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project. ___ Xen-devel mailing list Xen-devel@lists.xen.org https://lists.xen.org/xen-devel
[Xen-devel] [PATCH V2 4/4] arm/vgic: Change fixed number of mmio handlers to variable number
Compute the number of mmio handlers that are required for vGICv3 and vGICv2 emulation drivers in vgic_v3_init()/vgic_v2_init(). Augment this variable number of mmio handers to a fixed number MAX_IO_HANDLER and pass it to domain_io_init() to allocate enough memory. New code path: domain_vgic_register() domain_io_init(count + MAX_IO_HANDLER) domain_vgic_init() Signed-off-by: Shanker Donthineni <shank...@codeaurora.org> --- xen/arch/arm/domain.c | 12 +++- xen/arch/arm/vgic-v2.c | 3 ++- xen/arch/arm/vgic-v3.c | 5 - xen/arch/arm/vgic.c| 10 +++--- xen/include/asm-arm/vgic.h | 5 +++-- 5 files changed, 19 insertions(+), 16 deletions(-) diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c index 0170cee..4e5259b 100644 --- a/xen/arch/arm/domain.c +++ b/xen/arch/arm/domain.c @@ -546,7 +546,7 @@ void vcpu_destroy(struct vcpu *v) int arch_domain_create(struct domain *d, unsigned int domcr_flags, struct xen_arch_domainconfig *config) { -int rc, count; +int rc, count = 0; d->arch.relmem = RELMEM_not_started; @@ -569,10 +569,6 @@ int arch_domain_create(struct domain *d, unsigned int domcr_flags, share_xen_page_with_guest( virt_to_page(d->shared_info), d, XENSHARE_writable); -count = MAX_IO_HANDLER; -if ( (rc = domain_io_init(d, count)) != 0 ) -goto fail; - if ( (rc = p2m_alloc_table(d)) != 0 ) goto fail; @@ -609,6 +605,12 @@ int arch_domain_create(struct domain *d, unsigned int domcr_flags, goto fail; } +if ( (rc = domain_vgic_register(d, )) != 0 ) +goto fail; + +if ( (rc = domain_io_init(d, count + MAX_IO_HANDLER)) != 0 ) +goto fail; + if ( (rc = domain_vgic_init(d, config->nr_spis)) != 0 ) goto fail; diff --git a/xen/arch/arm/vgic-v2.c b/xen/arch/arm/vgic-v2.c index 6a5e67b..c6d280e 100644 --- a/xen/arch/arm/vgic-v2.c +++ b/xen/arch/arm/vgic-v2.c @@ -711,7 +711,7 @@ static const struct vgic_ops vgic_v2_ops = { .max_vcpus = 8, }; -int vgic_v2_init(struct domain *d) +int vgic_v2_init(struct domain *d, int *mmio_count) { if ( !vgic_v2_hw.enabled ) { @@ -721,6 +721,7 @@ int vgic_v2_init(struct domain *d) return -ENODEV; } +*mmio_count = 1; /* Only GICD region */ register_vgic_ops(d, _v2_ops); return 0; diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c index be9a9a3..ec038a3 100644 --- a/xen/arch/arm/vgic-v3.c +++ b/xen/arch/arm/vgic-v3.c @@ -1499,7 +1499,7 @@ static const struct vgic_ops v3_ops = { .max_vcpus = 4096, }; -int vgic_v3_init(struct domain *d) +int vgic_v3_init(struct domain *d, int *mmio_count) { if ( !vgic_v3_hw.enabled ) { @@ -1509,6 +1509,9 @@ int vgic_v3_init(struct domain *d) return -ENODEV; } +/* GICD region + number of Redistributors */ +*mmio_count = vgic_v3_rdist_count(d) + 1; + register_vgic_ops(d, _ops); return 0; diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c index a7ccfe7..768cb91 100644 --- a/xen/arch/arm/vgic.c +++ b/xen/arch/arm/vgic.c @@ -88,18 +88,18 @@ static void vgic_rank_init(struct vgic_irq_rank *rank, uint8_t index, rank->vcpu[i] = vcpu; } -static int domain_vgic_register(struct domain *d) +int domain_vgic_register(struct domain *d, int *mmio_count) { switch ( d->arch.vgic.version ) { #ifdef CONFIG_HAS_GICV3 case GIC_V3: -if ( vgic_v3_init(d) ) +if ( vgic_v3_init(d, mmio_count) ) return -ENODEV; break; #endif case GIC_V2: -if ( vgic_v2_init(d) ) +if ( vgic_v2_init(d, mmio_count) ) return -ENODEV; break; default: @@ -124,10 +124,6 @@ int domain_vgic_init(struct domain *d, unsigned int nr_spis) d->arch.vgic.nr_spis = nr_spis; -ret = domain_vgic_register(d); -if ( ret < 0 ) -return ret; - spin_lock_init(>arch.vgic.lock); d->arch.vgic.shared_irqs = diff --git a/xen/include/asm-arm/vgic.h b/xen/include/asm-arm/vgic.h index c3cc4f6..300f461 100644 --- a/xen/include/asm-arm/vgic.h +++ b/xen/include/asm-arm/vgic.h @@ -304,9 +304,10 @@ extern int vgic_emulate(struct cpu_user_regs *regs, union hsr hsr); extern void vgic_disable_irqs(struct vcpu *v, uint32_t r, int n); extern void vgic_enable_irqs(struct vcpu *v, uint32_t r, int n); extern void register_vgic_ops(struct domain *d, const struct vgic_ops *ops); -int vgic_v2_init(struct domain *d); -int vgic_v3_init(struct domain *d); +int vgic_v2_init(struct domain *d, int *mmio_count); +int vgic_v3_init(struct domain *d, int *mmio_count); +extern int domain_vgic_register(struct domain *d, int *mmio_count); extern int vcpu_vgic_free(struct vcpu *v); extern int vgic_to_sgi(struct vcpu *v, register_t sgir, enum gic_sgi_mode irqmode, int virq, -- Qualcomm Datacenter Technologies, Inc. on behalf of the Qual
Re: [Xen-devel] [PATCH RESEND 2/4] xen: Add generic implementation of binary search
Hi Andrew, On 07/15/2016 12:42 PM, Andrew Cooper wrote: On 15/07/16 18:35, Shanker Donthineni wrote: This patch adds the generic implementation of binary search algorithm whcih is copied from Linux kernel v4.7-rc7. No functional changes. Signed-off-by: Shanker Donthineni <shank...@codeaurora.org> --- Resend to fix the In-Reply-To/References header feilds. xen/common/Makefile | 1 + xen/common/bsearch.c | 51 +++ xen/include/xen/bsearch.h | 9 + Having a header file for a single is silly (I have no idea why Linux does it like that). I would move it into xen/lib.h which contains a number of other stdlib.h-like functions. With that done, Reviewed-by: Andrew Cooper <andrew.coop...@citrix.com> I'll follow your suggestion. -- Shanker Donthineni Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project. ___ Xen-devel mailing list Xen-devel@lists.xen.org https://lists.xen.org/xen-devel
[Xen-devel] [PATCH RESEND 3/4] xen/arm: io: Use binary search for mmio handler lookup
As the number of I/O handlers increase, the overhead associated with linear lookup also increases. The system might have maximum of 144 (assuming CONFIG_NR_CPUS=128) mmio handlers. In worst case scenario, it would require 144 iterations for finding a matching handler. Now it is time for us to change from linear (complexity O(n)) to a binary search (complexity O(log n) for reducing mmio handler lookup overhead. Signed-off-by: Shanker Donthineni <shank...@codeaurora.org> --- Resend to fix the In-Reply-To/References header feilds. xen/arch/arm/io.c | 40 +--- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/xen/arch/arm/io.c b/xen/arch/arm/io.c index 40330f0..cdc3aa3 100644 --- a/xen/arch/arm/io.c +++ b/xen/arch/arm/io.c @@ -20,6 +20,8 @@ #include #include #include +#include +#include #include #include @@ -70,27 +72,31 @@ static int handle_write(const struct mmio_handler *handler, struct vcpu *v, handler->priv); } -static const struct mmio_handler *find_mmio_handler(struct domain *d, -paddr_t gpa) +/* This function assumes that mmio regions are not overlapped */ +static int cmp_mmio_handler(const void *key, const void *elem) { -const struct mmio_handler *handler; -unsigned int i; -struct vmmio *vmmio = >arch.vmmio; +const struct mmio_handler *handler0 = key; +const struct mmio_handler *handler1 = elem; -read_lock(>lock); +if ( handler0->addr < handler1->addr ) +return -1; -for ( i = 0; i < vmmio->num_entries; i++ ) -{ -handler = >handlers[i]; +if ( handler0->addr > (handler1->addr + handler1->size) ) +return 1; -if ( (gpa >= handler->addr) && - (gpa < (handler->addr + handler->size)) ) -break; -} +return 0; +} -if ( i == vmmio->num_entries ) -handler = NULL; +static const struct mmio_handler *find_mmio_handler(struct domain *d, +paddr_t gpa) +{ +struct vmmio *vmmio = >arch.vmmio; +struct mmio_handler key = {.addr = gpa}; +const struct mmio_handler *handler; +read_lock(>lock); +handler = bsearch(, vmmio->handlers, vmmio->num_entries, + sizeof(*handler), cmp_mmio_handler); read_unlock(>lock); return handler; @@ -131,6 +137,10 @@ void register_mmio_handler(struct domain *d, vmmio->num_entries++; +/* Sort mmio handlers in ascending order based on base address */ +sort(vmmio->handlers, vmmio->num_entries, sizeof(struct mmio_handler), + cmp_mmio_handler, NULL); + write_unlock(>lock); } -- Qualcomm Datacenter Technologies, Inc. on behalf of the Qualcomm Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project. ___ Xen-devel mailing list Xen-devel@lists.xen.org https://lists.xen.org/xen-devel
[Xen-devel] [PATCH RESEND 1/4] arm/io: Use separate memory allocation for mmio handlers
The number of mmio handlers are limited to a compile time macro MAX_IO_HANDLER which is 16. This number is not at all sufficient to support per CPU distributor regions. Either it needs to be increased to a bigger number, at least CONFIG_NR_CPUS+16, or allocate a separate memory for mmio handlers dynamically during domain build. This patch uses the dynamic allocation strategy to reduce memory footprint for 'struct domain' instead of static allocation. Signed-off-by: Shanker Donthineni <shank...@codeaurora.org> Acked-by: Julien Grall <julien.gr...@arm.com> --- Resend to fix the In-Reply-To/References header feilds. xen/arch/arm/domain.c | 6 -- xen/arch/arm/io.c | 13 +++-- xen/include/asm-arm/mmio.h | 7 +-- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c index 61fc08e..0170cee 100644 --- a/xen/arch/arm/domain.c +++ b/xen/arch/arm/domain.c @@ -546,7 +546,7 @@ void vcpu_destroy(struct vcpu *v) int arch_domain_create(struct domain *d, unsigned int domcr_flags, struct xen_arch_domainconfig *config) { -int rc; +int rc, count; d->arch.relmem = RELMEM_not_started; @@ -569,7 +569,8 @@ int arch_domain_create(struct domain *d, unsigned int domcr_flags, share_xen_page_with_guest( virt_to_page(d->shared_info), d, XENSHARE_writable); -if ( (rc = domain_io_init(d)) != 0 ) +count = MAX_IO_HANDLER; +if ( (rc = domain_io_init(d, count)) != 0 ) goto fail; if ( (rc = p2m_alloc_table(d)) != 0 ) @@ -663,6 +664,7 @@ void arch_domain_destroy(struct domain *d) free_xenheap_pages(d->arch.efi_acpi_table, get_order_from_bytes(d->arch.efi_acpi_len)); #endif +domain_io_free(d); } void arch_domain_shutdown(struct domain *d) diff --git a/xen/arch/arm/io.c b/xen/arch/arm/io.c index 5a96836..40330f0 100644 --- a/xen/arch/arm/io.c +++ b/xen/arch/arm/io.c @@ -118,7 +118,7 @@ void register_mmio_handler(struct domain *d, struct vmmio *vmmio = >arch.vmmio; struct mmio_handler *handler; -BUG_ON(vmmio->num_entries >= MAX_IO_HANDLER); +BUG_ON(vmmio->num_entries >= vmmio->max_num_entries); write_lock(>lock); @@ -134,14 +134,23 @@ void register_mmio_handler(struct domain *d, write_unlock(>lock); } -int domain_io_init(struct domain *d) +int domain_io_init(struct domain *d, int max_count) { rwlock_init(>arch.vmmio.lock); d->arch.vmmio.num_entries = 0; +d->arch.vmmio.max_num_entries = max_count; +d->arch.vmmio.handlers = xzalloc_array(struct mmio_handler, max_count); +if ( !d->arch.vmmio.handlers ) +return -ENOMEM; return 0; } +void domain_io_free(struct domain *d) +{ +xfree(d->arch.vmmio.handlers); +} + /* * Local variables: * mode: C diff --git a/xen/include/asm-arm/mmio.h b/xen/include/asm-arm/mmio.h index 32f10f2..c620eed 100644 --- a/xen/include/asm-arm/mmio.h +++ b/xen/include/asm-arm/mmio.h @@ -52,15 +52,18 @@ struct mmio_handler { struct vmmio { int num_entries; +int max_num_entries; rwlock_t lock; -struct mmio_handler handlers[MAX_IO_HANDLER]; +struct mmio_handler *handlers; }; extern int handle_mmio(mmio_info_t *info); void register_mmio_handler(struct domain *d, const struct mmio_handler_ops *ops, paddr_t addr, paddr_t size, void *priv); -int domain_io_init(struct domain *d); +int domain_io_init(struct domain *d, int max_count); +void domain_io_free(struct domain *d); + #endif /* __ASM_ARM_MMIO_H__ */ -- Qualcomm Datacenter Technologies, Inc. on behalf of the Qualcomm Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project. ___ Xen-devel mailing list Xen-devel@lists.xen.org https://lists.xen.org/xen-devel
[Xen-devel] [PATCH RESEND 4/4] arm/vgic: Change fixed number of mmio handlers to variable number
Compute the number of mmio handlers that are required for vGICv3 and vGICv2 emulation drivers in vgic_v3_init()/vgic_v2_init(). Augment this variable number of mmio handers to a fixed number MAX_IO_HANDLER and pass it to domain_io_init() to allocate enough memory. New code path: domain_vgic_register() domain_io_init(count + MAX_IO_HANDLER) domain_vgic_init() Signed-off-by: Shanker Donthineni <shank...@codeaurora.org> --- Resend to fix the In-Reply-To/References header fields. xen/arch/arm/domain.c | 12 +++- xen/arch/arm/vgic-v2.c | 3 ++- xen/arch/arm/vgic-v3.c | 5 - xen/arch/arm/vgic.c| 10 +++--- xen/include/asm-arm/vgic.h | 5 +++-- 5 files changed, 19 insertions(+), 16 deletions(-) diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c index 0170cee..4e5259b 100644 --- a/xen/arch/arm/domain.c +++ b/xen/arch/arm/domain.c @@ -546,7 +546,7 @@ void vcpu_destroy(struct vcpu *v) int arch_domain_create(struct domain *d, unsigned int domcr_flags, struct xen_arch_domainconfig *config) { -int rc, count; +int rc, count = 0; d->arch.relmem = RELMEM_not_started; @@ -569,10 +569,6 @@ int arch_domain_create(struct domain *d, unsigned int domcr_flags, share_xen_page_with_guest( virt_to_page(d->shared_info), d, XENSHARE_writable); -count = MAX_IO_HANDLER; -if ( (rc = domain_io_init(d, count)) != 0 ) -goto fail; - if ( (rc = p2m_alloc_table(d)) != 0 ) goto fail; @@ -609,6 +605,12 @@ int arch_domain_create(struct domain *d, unsigned int domcr_flags, goto fail; } +if ( (rc = domain_vgic_register(d, )) != 0 ) +goto fail; + +if ( (rc = domain_io_init(d, count + MAX_IO_HANDLER)) != 0 ) +goto fail; + if ( (rc = domain_vgic_init(d, config->nr_spis)) != 0 ) goto fail; diff --git a/xen/arch/arm/vgic-v2.c b/xen/arch/arm/vgic-v2.c index 6a5e67b..c6d280e 100644 --- a/xen/arch/arm/vgic-v2.c +++ b/xen/arch/arm/vgic-v2.c @@ -711,7 +711,7 @@ static const struct vgic_ops vgic_v2_ops = { .max_vcpus = 8, }; -int vgic_v2_init(struct domain *d) +int vgic_v2_init(struct domain *d, int *mmio_count) { if ( !vgic_v2_hw.enabled ) { @@ -721,6 +721,7 @@ int vgic_v2_init(struct domain *d) return -ENODEV; } +*mmio_count = 1; /* Only GICD region */ register_vgic_ops(d, _v2_ops); return 0; diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c index be9a9a3..ec038a3 100644 --- a/xen/arch/arm/vgic-v3.c +++ b/xen/arch/arm/vgic-v3.c @@ -1499,7 +1499,7 @@ static const struct vgic_ops v3_ops = { .max_vcpus = 4096, }; -int vgic_v3_init(struct domain *d) +int vgic_v3_init(struct domain *d, int *mmio_count) { if ( !vgic_v3_hw.enabled ) { @@ -1509,6 +1509,9 @@ int vgic_v3_init(struct domain *d) return -ENODEV; } +/* GICD region + number of Redistributors */ +*mmio_count = vgic_v3_rdist_count(d) + 1; + register_vgic_ops(d, _ops); return 0; diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c index a7ccfe7..768cb91 100644 --- a/xen/arch/arm/vgic.c +++ b/xen/arch/arm/vgic.c @@ -88,18 +88,18 @@ static void vgic_rank_init(struct vgic_irq_rank *rank, uint8_t index, rank->vcpu[i] = vcpu; } -static int domain_vgic_register(struct domain *d) +int domain_vgic_register(struct domain *d, int *mmio_count) { switch ( d->arch.vgic.version ) { #ifdef CONFIG_HAS_GICV3 case GIC_V3: -if ( vgic_v3_init(d) ) +if ( vgic_v3_init(d, mmio_count) ) return -ENODEV; break; #endif case GIC_V2: -if ( vgic_v2_init(d) ) +if ( vgic_v2_init(d, mmio_count) ) return -ENODEV; break; default: @@ -124,10 +124,6 @@ int domain_vgic_init(struct domain *d, unsigned int nr_spis) d->arch.vgic.nr_spis = nr_spis; -ret = domain_vgic_register(d); -if ( ret < 0 ) -return ret; - spin_lock_init(>arch.vgic.lock); d->arch.vgic.shared_irqs = diff --git a/xen/include/asm-arm/vgic.h b/xen/include/asm-arm/vgic.h index c3cc4f6..300f461 100644 --- a/xen/include/asm-arm/vgic.h +++ b/xen/include/asm-arm/vgic.h @@ -304,9 +304,10 @@ extern int vgic_emulate(struct cpu_user_regs *regs, union hsr hsr); extern void vgic_disable_irqs(struct vcpu *v, uint32_t r, int n); extern void vgic_enable_irqs(struct vcpu *v, uint32_t r, int n); extern void register_vgic_ops(struct domain *d, const struct vgic_ops *ops); -int vgic_v2_init(struct domain *d); -int vgic_v3_init(struct domain *d); +int vgic_v2_init(struct domain *d, int *mmio_count); +int vgic_v3_init(struct domain *d, int *mmio_count); +extern int domain_vgic_register(struct domain *d, int *mmio_count); extern int vcpu_vgic_free(struct vcpu *v); extern int vgic_to_sgi(struct vcpu *v, register_t sgir, enum gic_sgi_mode irqmode, int virq, --
[Xen-devel] [PATCH RESEND 2/4] xen: Add generic implementation of binary search
This patch adds the generic implementation of binary search algorithm whcih is copied from Linux kernel v4.7-rc7. No functional changes. Signed-off-by: Shanker Donthineni <shank...@codeaurora.org> --- Resend to fix the In-Reply-To/References header feilds. xen/common/Makefile | 1 + xen/common/bsearch.c | 51 +++ xen/include/xen/bsearch.h | 9 + 3 files changed, 61 insertions(+) create mode 100644 xen/common/bsearch.c create mode 100644 xen/include/xen/bsearch.h diff --git a/xen/common/Makefile b/xen/common/Makefile index dbf00c6..f8123c2 100644 --- a/xen/common/Makefile +++ b/xen/common/Makefile @@ -43,6 +43,7 @@ obj-y += schedule.o obj-y += shutdown.o obj-y += softirq.o obj-y += sort.o +obj-y += bsearch.o obj-y += smp.o obj-y += spinlock.o obj-y += stop_machine.o diff --git a/xen/common/bsearch.c b/xen/common/bsearch.c new file mode 100644 index 000..3bcfd72 --- /dev/null +++ b/xen/common/bsearch.c @@ -0,0 +1,51 @@ +/* + * A generic implementation of binary search for the Linux kernel + * + * Copyright (C) 2008-2009 Ksplice, Inc. + * Author: Tim Abbott <tabb...@ksplice.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; version 2. + */ + +#include + +/* + * bsearch - binary search an array of elements + * @key: pointer to item being searched for + * @base: pointer to first element to search + * @num: number of elements + * @size: size of each element + * @cmp: pointer to comparison function + * + * This function does a binary search on the given array. The + * contents of the array should already be in ascending sorted order + * under the provided comparison function. + * + * Note that the key need not have the same type as the elements in + * the array, e.g. key could be a string and the comparison function + * could compare the string with the struct's name field. However, if + * the key and elements in the array are of the same type, you can use + * the same comparison function for both sort() and bsearch(). + */ +void *bsearch(const void *key, const void *base, size_t num, size_t size, + int (*cmp)(const void *key, const void *elt)) +{ + size_t start = 0, end = num; + int result; + + while (start < end) { + size_t mid = start + (end - start) / 2; + + result = cmp(key, base + mid * size); + if (result < 0) + end = mid; + else if (result > 0) + start = mid + 1; + else + return (void *)base + mid * size; + } + + return NULL; +} diff --git a/xen/include/xen/bsearch.h b/xen/include/xen/bsearch.h new file mode 100644 index 000..07cf604 --- /dev/null +++ b/xen/include/xen/bsearch.h @@ -0,0 +1,9 @@ +#ifndef __XEN_BSEARCH_H__ +#define __XEN_BSEARCH_H__ + +#include + +void *bsearch(const void *key, const void *base, size_t num, size_t size, + int (*cmp)(const void *key, const void *elt)); + +#endif /* __XEN_BSEARCH_H__ */ -- Qualcomm Datacenter Technologies, Inc. on behalf of the Qualcomm Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project. ___ Xen-devel mailing list Xen-devel@lists.xen.org https://lists.xen.org/xen-devel
[Xen-devel] [PATCH RESEND 0/4] Change fixed mmio handlers to a variable number
The maximum number of mmio handlers that are allowed is limited to a macro MAX_IO_HANDLER(16), which is not enough for supporting per CPU Redistributor regions. We need at least MAX_IO_HANDLER+CONFIG_NR_CPUS mmio handlers in order to support ACPI based XEN boot. This patchset uses the dynamic allocation strategy to allocate memory resource dynamically depends on the number of Redistributor regions that are described in the APCI MADT table. Shanker Donthineni (4): arm/io: Use separate memory allocation for mmio handlers xen: Add generic implementation of binary search xen/arm: io: Use binary search for mmio handler lookup arm/vgic: Change fixed number of mmio handlers to variable number xen/arch/arm/domain.c | 12 +++ xen/arch/arm/io.c | 53 +++--- xen/arch/arm/vgic-v2.c | 3 ++- xen/arch/arm/vgic-v3.c | 5 - xen/arch/arm/vgic.c| 10 +++-- xen/common/Makefile| 1 + xen/common/bsearch.c | 51 xen/include/asm-arm/mmio.h | 7 -- xen/include/asm-arm/vgic.h | 5 +++-- xen/include/xen/bsearch.h | 9 10 files changed, 122 insertions(+), 34 deletions(-) create mode 100644 xen/common/bsearch.c create mode 100644 xen/include/xen/bsearch.h Changes: Resend to fix the Message-ID, References and In-Reply-To fields. -- Qualcomm Datacenter Technologies, Inc. on behalf of the Qualcomm Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project. ___ Xen-devel mailing list Xen-devel@lists.xen.org https://lists.xen.org/xen-devel
Re: [Xen-devel] [PATCH 0/4] Change fixed mmio handlers to a variable number
Hi Julien, On 07/15/2016 10:32 AM, Julien Grall wrote: Hi Shanker, It looks like this series is not threaded. I looked to the headers, and some patch miss the In-Reply-To/References header or they are wrong. Please try to thread the series, it is much easier to find the associated patch. Sorry for asking more things, I am still leaning the XEN upstream guidelines. Please guide me how do I fix the issue 'thread the series' that you are talking. -- Shanker Donthineni Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project. ___ Xen-devel mailing list Xen-devel@lists.xen.org https://lists.xen.org/xen-devel
[Xen-devel] [PATCH 4/4] arm/vgic: Change fixed number of mmio handlers to variable number
Compute the number of mmio handlers that are required for vGICv3 and vGICv2 emulation drivers in vgic_v3_init()/vgic_v2_init(). Augment this variable number of mmio handers to a fixed number MAX_IO_HANDLER and pass it to domain_io_init() to allocate enough memory. New code path: domain_vgic_register() domain_io_init(count + MAX_IO_HANDLER) domain_vgic_init() Signed-off-by: Shanker Donthineni <shank...@codeaurora.org> --- xen/arch/arm/domain.c | 12 +++- xen/arch/arm/vgic-v2.c | 3 ++- xen/arch/arm/vgic-v3.c | 5 - xen/arch/arm/vgic.c| 10 +++--- xen/include/asm-arm/vgic.h | 5 +++-- 5 files changed, 19 insertions(+), 16 deletions(-) diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c index 0170cee..4e5259b 100644 --- a/xen/arch/arm/domain.c +++ b/xen/arch/arm/domain.c @@ -546,7 +546,7 @@ void vcpu_destroy(struct vcpu *v) int arch_domain_create(struct domain *d, unsigned int domcr_flags, struct xen_arch_domainconfig *config) { -int rc, count; +int rc, count = 0; d->arch.relmem = RELMEM_not_started; @@ -569,10 +569,6 @@ int arch_domain_create(struct domain *d, unsigned int domcr_flags, share_xen_page_with_guest( virt_to_page(d->shared_info), d, XENSHARE_writable); -count = MAX_IO_HANDLER; -if ( (rc = domain_io_init(d, count)) != 0 ) -goto fail; - if ( (rc = p2m_alloc_table(d)) != 0 ) goto fail; @@ -609,6 +605,12 @@ int arch_domain_create(struct domain *d, unsigned int domcr_flags, goto fail; } +if ( (rc = domain_vgic_register(d, )) != 0 ) +goto fail; + +if ( (rc = domain_io_init(d, count + MAX_IO_HANDLER)) != 0 ) +goto fail; + if ( (rc = domain_vgic_init(d, config->nr_spis)) != 0 ) goto fail; diff --git a/xen/arch/arm/vgic-v2.c b/xen/arch/arm/vgic-v2.c index 6a5e67b..c6d280e 100644 --- a/xen/arch/arm/vgic-v2.c +++ b/xen/arch/arm/vgic-v2.c @@ -711,7 +711,7 @@ static const struct vgic_ops vgic_v2_ops = { .max_vcpus = 8, }; -int vgic_v2_init(struct domain *d) +int vgic_v2_init(struct domain *d, int *mmio_count) { if ( !vgic_v2_hw.enabled ) { @@ -721,6 +721,7 @@ int vgic_v2_init(struct domain *d) return -ENODEV; } +*mmio_count = 1; /* Only GICD region */ register_vgic_ops(d, _v2_ops); return 0; diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c index be9a9a3..ec038a3 100644 --- a/xen/arch/arm/vgic-v3.c +++ b/xen/arch/arm/vgic-v3.c @@ -1499,7 +1499,7 @@ static const struct vgic_ops v3_ops = { .max_vcpus = 4096, }; -int vgic_v3_init(struct domain *d) +int vgic_v3_init(struct domain *d, int *mmio_count) { if ( !vgic_v3_hw.enabled ) { @@ -1509,6 +1509,9 @@ int vgic_v3_init(struct domain *d) return -ENODEV; } +/* GICD region + number of Redistributors */ +*mmio_count = vgic_v3_rdist_count(d) + 1; + register_vgic_ops(d, _ops); return 0; diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c index a7ccfe7..768cb91 100644 --- a/xen/arch/arm/vgic.c +++ b/xen/arch/arm/vgic.c @@ -88,18 +88,18 @@ static void vgic_rank_init(struct vgic_irq_rank *rank, uint8_t index, rank->vcpu[i] = vcpu; } -static int domain_vgic_register(struct domain *d) +int domain_vgic_register(struct domain *d, int *mmio_count) { switch ( d->arch.vgic.version ) { #ifdef CONFIG_HAS_GICV3 case GIC_V3: -if ( vgic_v3_init(d) ) +if ( vgic_v3_init(d, mmio_count) ) return -ENODEV; break; #endif case GIC_V2: -if ( vgic_v2_init(d) ) +if ( vgic_v2_init(d, mmio_count) ) return -ENODEV; break; default: @@ -124,10 +124,6 @@ int domain_vgic_init(struct domain *d, unsigned int nr_spis) d->arch.vgic.nr_spis = nr_spis; -ret = domain_vgic_register(d); -if ( ret < 0 ) -return ret; - spin_lock_init(>arch.vgic.lock); d->arch.vgic.shared_irqs = diff --git a/xen/include/asm-arm/vgic.h b/xen/include/asm-arm/vgic.h index c3cc4f6..300f461 100644 --- a/xen/include/asm-arm/vgic.h +++ b/xen/include/asm-arm/vgic.h @@ -304,9 +304,10 @@ extern int vgic_emulate(struct cpu_user_regs *regs, union hsr hsr); extern void vgic_disable_irqs(struct vcpu *v, uint32_t r, int n); extern void vgic_enable_irqs(struct vcpu *v, uint32_t r, int n); extern void register_vgic_ops(struct domain *d, const struct vgic_ops *ops); -int vgic_v2_init(struct domain *d); -int vgic_v3_init(struct domain *d); +int vgic_v2_init(struct domain *d, int *mmio_count); +int vgic_v3_init(struct domain *d, int *mmio_count); +extern int domain_vgic_register(struct domain *d, int *mmio_count); extern int vcpu_vgic_free(struct vcpu *v); extern int vgic_to_sgi(struct vcpu *v, register_t sgir, enum gic_sgi_mode irqmode, int virq, -- Qualcomm Datacenter Technologies, Inc. on behalf of the Qual
[Xen-devel] [PATCH 3/4] xen/arm: io: Use binary search for mmio handler lookup
As the number of I/O handlers increase, the overhead associated with linear lookup also increases. The system might have maximum of 144 (assuming CONFIG_NR_CPUS=128) mmio handlers. In worst case scenario, it would require 144 iterations for finding a matching handler. Now it is time for us to change from linear (complexity O(n)) to a binary search (complexity O(log n) for reducing mmio handler lookup overhead. Signed-off-by: Shanker Donthineni <shank...@codeaurora.org> --- xen/arch/arm/io.c | 40 +--- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/xen/arch/arm/io.c b/xen/arch/arm/io.c index 40330f0..cdc3aa3 100644 --- a/xen/arch/arm/io.c +++ b/xen/arch/arm/io.c @@ -20,6 +20,8 @@ #include #include #include +#include +#include #include #include @@ -70,27 +72,31 @@ static int handle_write(const struct mmio_handler *handler, struct vcpu *v, handler->priv); } -static const struct mmio_handler *find_mmio_handler(struct domain *d, -paddr_t gpa) +/* This function assumes that mmio regions are not overlapped */ +static int cmp_mmio_handler(const void *key, const void *elem) { -const struct mmio_handler *handler; -unsigned int i; -struct vmmio *vmmio = >arch.vmmio; +const struct mmio_handler *handler0 = key; +const struct mmio_handler *handler1 = elem; -read_lock(>lock); +if ( handler0->addr < handler1->addr ) +return -1; -for ( i = 0; i < vmmio->num_entries; i++ ) -{ -handler = >handlers[i]; +if ( handler0->addr > (handler1->addr + handler1->size) ) +return 1; -if ( (gpa >= handler->addr) && - (gpa < (handler->addr + handler->size)) ) -break; -} +return 0; +} -if ( i == vmmio->num_entries ) -handler = NULL; +static const struct mmio_handler *find_mmio_handler(struct domain *d, +paddr_t gpa) +{ +struct vmmio *vmmio = >arch.vmmio; +struct mmio_handler key = {.addr = gpa}; +const struct mmio_handler *handler; +read_lock(>lock); +handler = bsearch(, vmmio->handlers, vmmio->num_entries, + sizeof(*handler), cmp_mmio_handler); read_unlock(>lock); return handler; @@ -131,6 +137,10 @@ void register_mmio_handler(struct domain *d, vmmio->num_entries++; +/* Sort mmio handlers in ascending order based on base address */ +sort(vmmio->handlers, vmmio->num_entries, sizeof(struct mmio_handler), + cmp_mmio_handler, NULL); + write_unlock(>lock); } -- Qualcomm Datacenter Technologies, Inc. on behalf of the Qualcomm Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project. ___ Xen-devel mailing list Xen-devel@lists.xen.org https://lists.xen.org/xen-devel
[Xen-devel] [PATCH 0/4] Change fixed mmio handlers to a variable number
The maximum number of mmio handlers that are allowed is limited to a macro MAX_IO_HANDLER(16), which is not enough for supporting per CPU Redistributor regions. We need at least MAX_IO_HANDLER+CONFIG_NR_CPUS mmio handlers in order to support ACPI based XEN boot. This patchset uses the dynamic allocation strategy to allocate memory resource dynamically depends on the number of Redistributor regions that are described in the APCI MADT table. Shanker Donthineni (4): arm/io: Use separate memory allocation for mmio handlers xen: Add generic implementation of binary search xen/arm: io: Use binary search for mmio handler lookup arm/vgic: Change fixed number of mmio handlers to variable number xen/arch/arm/domain.c | 12 +++ xen/arch/arm/io.c | 53 +++--- xen/arch/arm/vgic-v2.c | 3 ++- xen/arch/arm/vgic-v3.c | 5 - xen/arch/arm/vgic.c| 10 +++-- xen/common/Makefile| 1 + xen/common/bsearch.c | 51 xen/include/asm-arm/mmio.h | 7 -- xen/include/asm-arm/vgic.h | 5 +++-- xen/include/xen/bsearch.h | 9 10 files changed, 122 insertions(+), 34 deletions(-) create mode 100644 xen/common/bsearch.c create mode 100644 xen/include/xen/bsearch.h -- Qualcomm Datacenter Technologies, Inc. on behalf of the Qualcomm Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project. ___ Xen-devel mailing list Xen-devel@lists.xen.org https://lists.xen.org/xen-devel
[Xen-devel] [PATCH 1/4] arm/io: Use separate memory allocation for mmio handlers
The number of mmio handlers are limited to a compile time macro MAX_IO_HANDLER which is 16. This number is not at all sufficient to support per CPU distributor regions. Either it needs to be increased to a bigger number, at least CONFIG_NR_CPUS+16, or allocate a separate memory for mmio handlers dynamically during domain build. This patch uses the dynamic allocation strategy to reduce memory footprint for 'struct domain' instead of static allocation. Signed-off-by: Shanker Donthineni <shank...@codeaurora.org> Acked-by: Julien Grall <julien.gr...@arm.com> --- xen/arch/arm/domain.c | 6 -- xen/arch/arm/io.c | 13 +++-- xen/include/asm-arm/mmio.h | 7 +-- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c index 61fc08e..0170cee 100644 --- a/xen/arch/arm/domain.c +++ b/xen/arch/arm/domain.c @@ -546,7 +546,7 @@ void vcpu_destroy(struct vcpu *v) int arch_domain_create(struct domain *d, unsigned int domcr_flags, struct xen_arch_domainconfig *config) { -int rc; +int rc, count; d->arch.relmem = RELMEM_not_started; @@ -569,7 +569,8 @@ int arch_domain_create(struct domain *d, unsigned int domcr_flags, share_xen_page_with_guest( virt_to_page(d->shared_info), d, XENSHARE_writable); -if ( (rc = domain_io_init(d)) != 0 ) +count = MAX_IO_HANDLER; +if ( (rc = domain_io_init(d, count)) != 0 ) goto fail; if ( (rc = p2m_alloc_table(d)) != 0 ) @@ -663,6 +664,7 @@ void arch_domain_destroy(struct domain *d) free_xenheap_pages(d->arch.efi_acpi_table, get_order_from_bytes(d->arch.efi_acpi_len)); #endif +domain_io_free(d); } void arch_domain_shutdown(struct domain *d) diff --git a/xen/arch/arm/io.c b/xen/arch/arm/io.c index 5a96836..40330f0 100644 --- a/xen/arch/arm/io.c +++ b/xen/arch/arm/io.c @@ -118,7 +118,7 @@ void register_mmio_handler(struct domain *d, struct vmmio *vmmio = >arch.vmmio; struct mmio_handler *handler; -BUG_ON(vmmio->num_entries >= MAX_IO_HANDLER); +BUG_ON(vmmio->num_entries >= vmmio->max_num_entries); write_lock(>lock); @@ -134,14 +134,23 @@ void register_mmio_handler(struct domain *d, write_unlock(>lock); } -int domain_io_init(struct domain *d) +int domain_io_init(struct domain *d, int max_count) { rwlock_init(>arch.vmmio.lock); d->arch.vmmio.num_entries = 0; +d->arch.vmmio.max_num_entries = max_count; +d->arch.vmmio.handlers = xzalloc_array(struct mmio_handler, max_count); +if ( !d->arch.vmmio.handlers ) +return -ENOMEM; return 0; } +void domain_io_free(struct domain *d) +{ +xfree(d->arch.vmmio.handlers); +} + /* * Local variables: * mode: C diff --git a/xen/include/asm-arm/mmio.h b/xen/include/asm-arm/mmio.h index 32f10f2..c620eed 100644 --- a/xen/include/asm-arm/mmio.h +++ b/xen/include/asm-arm/mmio.h @@ -52,15 +52,18 @@ struct mmio_handler { struct vmmio { int num_entries; +int max_num_entries; rwlock_t lock; -struct mmio_handler handlers[MAX_IO_HANDLER]; +struct mmio_handler *handlers; }; extern int handle_mmio(mmio_info_t *info); void register_mmio_handler(struct domain *d, const struct mmio_handler_ops *ops, paddr_t addr, paddr_t size, void *priv); -int domain_io_init(struct domain *d); +int domain_io_init(struct domain *d, int max_count); +void domain_io_free(struct domain *d); + #endif /* __ASM_ARM_MMIO_H__ */ -- Qualcomm Datacenter Technologies, Inc. on behalf of the Qualcomm Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project. ___ Xen-devel mailing list Xen-devel@lists.xen.org https://lists.xen.org/xen-devel
[Xen-devel] [PATCH 2/4] xen: Add generic implementation of binary search
This patch adds the generic implementation of binary search algorithm whcih is copied from Linux kernel v4.7-rc7. No functional changes. Signed-off-by: Shanker Donthineni <shank...@codeaurora.org> --- xen/common/Makefile | 1 + xen/common/bsearch.c | 51 +++ xen/include/xen/bsearch.h | 9 + 3 files changed, 61 insertions(+) create mode 100644 xen/common/bsearch.c create mode 100644 xen/include/xen/bsearch.h diff --git a/xen/common/Makefile b/xen/common/Makefile index dbf00c6..f8123c2 100644 --- a/xen/common/Makefile +++ b/xen/common/Makefile @@ -43,6 +43,7 @@ obj-y += schedule.o obj-y += shutdown.o obj-y += softirq.o obj-y += sort.o +obj-y += bsearch.o obj-y += smp.o obj-y += spinlock.o obj-y += stop_machine.o diff --git a/xen/common/bsearch.c b/xen/common/bsearch.c new file mode 100644 index 000..3bcfd72 --- /dev/null +++ b/xen/common/bsearch.c @@ -0,0 +1,51 @@ +/* + * A generic implementation of binary search for the Linux kernel + * + * Copyright (C) 2008-2009 Ksplice, Inc. + * Author: Tim Abbott <tabb...@ksplice.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; version 2. + */ + +#include + +/* + * bsearch - binary search an array of elements + * @key: pointer to item being searched for + * @base: pointer to first element to search + * @num: number of elements + * @size: size of each element + * @cmp: pointer to comparison function + * + * This function does a binary search on the given array. The + * contents of the array should already be in ascending sorted order + * under the provided comparison function. + * + * Note that the key need not have the same type as the elements in + * the array, e.g. key could be a string and the comparison function + * could compare the string with the struct's name field. However, if + * the key and elements in the array are of the same type, you can use + * the same comparison function for both sort() and bsearch(). + */ +void *bsearch(const void *key, const void *base, size_t num, size_t size, + int (*cmp)(const void *key, const void *elt)) +{ + size_t start = 0, end = num; + int result; + + while (start < end) { + size_t mid = start + (end - start) / 2; + + result = cmp(key, base + mid * size); + if (result < 0) + end = mid; + else if (result > 0) + start = mid + 1; + else + return (void *)base + mid * size; + } + + return NULL; +} diff --git a/xen/include/xen/bsearch.h b/xen/include/xen/bsearch.h new file mode 100644 index 000..07cf604 --- /dev/null +++ b/xen/include/xen/bsearch.h @@ -0,0 +1,9 @@ +#ifndef __XEN_BSEARCH_H__ +#define __XEN_BSEARCH_H__ + +#include + +void *bsearch(const void *key, const void *base, size_t num, size_t size, + int (*cmp)(const void *key, const void *elt)); + +#endif /* __XEN_BSEARCH_H__ */ -- Qualcomm Datacenter Technologies, Inc. on behalf of the Qualcomm Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project. ___ Xen-devel mailing list Xen-devel@lists.xen.org https://lists.xen.org/xen-devel
Re: [Xen-devel] [PATCH V4 10/11] xen/arm: io: Use binary search for mmio handler lookup
Hi Julien, On 07/14/2016 11:46 AM, Julien Grall wrote: Hi Shanker, On 14/07/16 17:18, Shanker Donthineni wrote: As the number of I/O handlers increase, the overhead associated with linear lookup also increases. The system might have maximum of 144 (assuming CONFIG_NR_CPUS=128) mmio handlers. In worst case scenario, it would require 144 iterations for finding a matching handler. Now it is time for us to change from linear (complexity O(n)) to a binary search (complexity O(log n) for reducing mmio handler lookup overhead. Signed-off-by: Shanker Donthineni <shank...@codeaurora.org> --- Changes since v3: Moved the function bsearch() to common file xen/common/bsearch.c. Changes since v2: Converted mmio lookup code to a critical section. Copied the function bsreach() from Linux kernel. xen/arch/arm/io.c | 42 +- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/xen/arch/arm/io.c b/xen/arch/arm/io.c index 40330f0..0471ba8 100644 --- a/xen/arch/arm/io.c +++ b/xen/arch/arm/io.c @@ -20,6 +20,8 @@ #include #include #include +#include +#include #include #include @@ -70,27 +72,29 @@ static int handle_write(const struct mmio_handler *handler, struct vcpu *v, handler->priv); } -static const struct mmio_handler *find_mmio_handler(struct domain *d, -paddr_t gpa) +static int cmp_mmio_handler(const void *key, const void *elem) Would it be worth to mention in a comment that we don't support overlapping? Sure, I'll do. { -const struct mmio_handler *handler; -unsigned int i; -struct vmmio *vmmio = >arch.vmmio; +const struct mmio_handler *handler0 = key; +const struct mmio_handler *handler1 = elem; -read_lock(>lock); +if ( handler0->addr < handler1->addr ) +return -1; -for ( i = 0; i < vmmio->num_entries; i++ ) -{ -handler = >handlers[i]; +if ( handler0->addr > (handler1->addr + handler1->size) ) +return 1; -if ( (gpa >= handler->addr) && - (gpa < (handler->addr + handler->size)) ) -break; -} +return 0; +} -if ( i == vmmio->num_entries ) -handler = NULL; +static const struct mmio_handler *find_mmio_handler(struct vcpu *v, paddr_t gpa) Why have you changed the prototype of find_mmio_handler? As such there is no reason for this change, I'll revert this change in next patchset. +{ +struct vmmio *vmmio = >domain->arch.vmmio; +struct mmio_handler key = {.addr = gpa}; I know it is not currently the case, but should not we take into account the size of the access? I agree with you, we definitely need to consider size of the access for traps/emulation drivers similar to what Linux KVM code does currently. Do you know which emulation drivers are using non aligned accesses? +const struct mmio_handler *handler; +read_lock(>lock); +handler = bsearch(, vmmio->handlers, vmmio->num_entries, + sizeof(*handler), cmp_mmio_handler); read_unlock(>lock); return handler; @@ -99,9 +103,9 @@ static const struct mmio_handler *find_mmio_handler(struct domain *d, int handle_mmio(mmio_info_t *info) { struct vcpu *v = current; -const struct mmio_handler *handler = NULL; +const struct mmio_handler *handler; Why this change? No need to initialize this local variable because the following line always initializes it. I'll revert this change anyway to avoid confusion. -handler = find_mmio_handler(v->domain, info->gpa); +handler = find_mmio_handler(v, info->gpa); ditto. if ( !handler ) return 0; @@ -131,6 +135,10 @@ void register_mmio_handler(struct domain *d, vmmio->num_entries++; +/* Sort mmio handlers in ascending order based on base address */ +sort(vmmio->handlers, vmmio->num_entries, sizeof(struct mmio_handler), +cmp_mmio_handler, NULL); The indentation looks wrong here. I don't quite understand what you mean. It has 8 spaces, do I need more than 8 spaces or something else? + write_unlock(>lock); } -- Shanker Donthineni Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project. ___ Xen-devel mailing list Xen-devel@lists.xen.org https://lists.xen.org/xen-devel
Re: [Xen-devel] [PATCH v2 0/9] xen/arm: Support SPIs routing
Hi Julien, Tested-by: Shanker Donthineni<shank...@codeaurora.org> I have tested this patchset on Qualcomm Technologies QDF2XXX server platform without any issue. On 07/14/2016 11:21 AM, Julien Grall wrote: Hello all, Currently, Xen does not route SPIs to DOM0 when ACPI is inuse after the functionality has been reverted in Xen 4.7 by commit 909bd14. In the previous approach, the SPIs was routed when DOM0 was writing into ISENABLER. However, this has resulted to deadlock (see more details in [1]) as soon as the IRQ was enabled by DOM0. We have multiple solutions to route the IRQ: 1) Rework route_irq_to_guest to avoid the deadlock 2) Route and enable the IRQ outside of the emulation of ISENABLER 3) Remove the dependency on the IRQ type in the routing function and route all the unused IRQs during domain building 4) Add a new hypercall to let DOM0 routing the IRQ I think that 1) and 2) are not resilient because route_irq_to_guest may fail and there is no way to report this error to the guest (except by killing it). Furthermore, in solution 2) enabling the interrupt would need to be defer until the routing has been done. This would require a lot of code duplication. Which leave solution 3) and 4). The solution 4) requires to introduce a new (or re-use one) stable hypercall. I am not sure why we ruled out this solution when we reviewed the ACPI design document. This patch series is implementing the 3rd solution which defer the IRQ type configuration for DOM0 IRQ when ACPI is inuse. However, this will slightly increase the memory usage of Xen (54KB). I am happy to consider any other solutions. I only tested briefly this patch series, Shanker can you give a try on your hardware? A branch with all the patches can be found here: git://xenbits.xen.org/people/julieng/xen-unstable.git branch irq-routing-acpi-v2 Yours sincerely, [1] http://lists.xenproject.org/archives/html/xen-devel/2016-05/msg02633.html Julien Grall (9): xen/arm: gic: Consolidate the IRQ affinity set in a single place xen/arm: gic: Do not configure affinity during routing xen/arm: gic: split set_irq_properties xen/arm: gic: set_type: Pass the type in parameter rather than in desc->arch.type xen/arm: gic: Document how gic_set_irq_type should be called Revert "xen/arm: warn the user that we cannot route SPIs to Dom0 on ACPI" xen/arm: Allow DOM0 to set the IRQ type xen/arm: acpi: route all unused IRQs to DOM0 xen/arm: Fix coding style and update comment in acpi_route_spis xen/arch/arm/domain_build.c | 33 +++-- xen/arch/arm/gic-v2.c | 28 +--- xen/arch/arm/gic-v3.c | 22 ++ xen/arch/arm/gic.c | 36 ++-- xen/arch/arm/irq.c | 17 ++--- xen/arch/arm/vgic.c | 32 ++-- xen/include/asm-arm/gic.h | 14 -- xen/include/asm-arm/irq.h | 6 ++ 8 files changed, 106 insertions(+), 82 deletions(-) -- Shanker Donthineni Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project. ___ Xen-devel mailing list Xen-devel@lists.xen.org https://lists.xen.org/xen-devel
[Xen-devel] [PATCH V4 09/11] xen: Add generic implementation of binary search
This patch adds the generic implementation of binary search algorithm whcih is copied from Linux kernel. Only coding style changes to match the general XEN coding style. No functional changes. Signed-off-by: Shanker Donthineni <shank...@codeaurora.org> --- xen/common/Makefile | 1 + xen/common/bsearch.c | 52 +++ xen/include/xen/bsearch.h | 9 3 files changed, 62 insertions(+) create mode 100644 xen/common/bsearch.c create mode 100644 xen/include/xen/bsearch.h diff --git a/xen/common/Makefile b/xen/common/Makefile index 2a83261..2fa36a4 100644 --- a/xen/common/Makefile +++ b/xen/common/Makefile @@ -41,6 +41,7 @@ obj-y += schedule.o obj-y += shutdown.o obj-y += softirq.o obj-y += sort.o +obj-y += bsearch.o obj-y += smp.o obj-y += spinlock.o obj-y += stop_machine.o diff --git a/xen/common/bsearch.c b/xen/common/bsearch.c new file mode 100644 index 000..0946762 --- /dev/null +++ b/xen/common/bsearch.c @@ -0,0 +1,52 @@ +/* + * A generic implementation of binary search for the Linux kernel + * + * Copyright (C) 2008-2009 Ksplice, Inc. + * Author: Tim Abbott <tabb...@ksplice.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; version 2. + */ + +#include + +/* + * bsearch - binary search an array of elements + * @key: pointer to item being searched for + * @base: pointer to first element to search + * @num: number of elements + * @size: size of each element + * @cmp: pointer to comparison function + * + * This function does a binary search on the given array. The + * contents of the array should already be in ascending sorted order + * under the provided comparison function. + * + * Note that the key need not have the same type as the elements in + * the array, e.g. key could be a string and the comparison function + * could compare the string with the struct's name field. However, if + * the key and elements in the array are of the same type, you can use + * the same comparison function for both sort() and bsearch(). + */ +void *bsearch(const void *key, const void *base, size_t num, size_t size, + int (*cmp)(const void *key, const void *elt)) +{ +size_t start = 0, end = num; +int result; + +while ( start < end ) +{ +size_t mid = start + (end - start) / 2; + +result = cmp(key, base + mid * size); +if ( result < 0 ) +end = mid; +else if ( result > 0 ) +start = mid + 1; +else +return (void *)base + mid * size; +} + +return NULL; +} diff --git a/xen/include/xen/bsearch.h b/xen/include/xen/bsearch.h new file mode 100644 index 000..07cf604 --- /dev/null +++ b/xen/include/xen/bsearch.h @@ -0,0 +1,9 @@ +#ifndef __XEN_BSEARCH_H__ +#define __XEN_BSEARCH_H__ + +#include + +void *bsearch(const void *key, const void *base, size_t num, size_t size, + int (*cmp)(const void *key, const void *elt)); + +#endif /* __XEN_BSEARCH_H__ */ -- Qualcomm Technologies, Inc. on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project ___ Xen-devel mailing list Xen-devel@lists.xen.org https://lists.xen.org/xen-devel
[Xen-devel] [PATCH V4 10/11] xen/arm: io: Use binary search for mmio handler lookup
As the number of I/O handlers increase, the overhead associated with linear lookup also increases. The system might have maximum of 144 (assuming CONFIG_NR_CPUS=128) mmio handlers. In worst case scenario, it would require 144 iterations for finding a matching handler. Now it is time for us to change from linear (complexity O(n)) to a binary search (complexity O(log n) for reducing mmio handler lookup overhead. Signed-off-by: Shanker Donthineni <shank...@codeaurora.org> --- Changes since v3: Moved the function bsearch() to common file xen/common/bsearch.c. Changes since v2: Converted mmio lookup code to a critical section. Copied the function bsreach() from Linux kernel. xen/arch/arm/io.c | 42 +- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/xen/arch/arm/io.c b/xen/arch/arm/io.c index 40330f0..0471ba8 100644 --- a/xen/arch/arm/io.c +++ b/xen/arch/arm/io.c @@ -20,6 +20,8 @@ #include #include #include +#include +#include #include #include @@ -70,27 +72,29 @@ static int handle_write(const struct mmio_handler *handler, struct vcpu *v, handler->priv); } -static const struct mmio_handler *find_mmio_handler(struct domain *d, -paddr_t gpa) +static int cmp_mmio_handler(const void *key, const void *elem) { -const struct mmio_handler *handler; -unsigned int i; -struct vmmio *vmmio = >arch.vmmio; +const struct mmio_handler *handler0 = key; +const struct mmio_handler *handler1 = elem; -read_lock(>lock); +if ( handler0->addr < handler1->addr ) +return -1; -for ( i = 0; i < vmmio->num_entries; i++ ) -{ -handler = >handlers[i]; +if ( handler0->addr > (handler1->addr + handler1->size) ) +return 1; -if ( (gpa >= handler->addr) && - (gpa < (handler->addr + handler->size)) ) -break; -} +return 0; +} -if ( i == vmmio->num_entries ) -handler = NULL; +static const struct mmio_handler *find_mmio_handler(struct vcpu *v, paddr_t gpa) +{ +struct vmmio *vmmio = >domain->arch.vmmio; +struct mmio_handler key = {.addr = gpa}; +const struct mmio_handler *handler; +read_lock(>lock); +handler = bsearch(, vmmio->handlers, vmmio->num_entries, + sizeof(*handler), cmp_mmio_handler); read_unlock(>lock); return handler; @@ -99,9 +103,9 @@ static const struct mmio_handler *find_mmio_handler(struct domain *d, int handle_mmio(mmio_info_t *info) { struct vcpu *v = current; -const struct mmio_handler *handler = NULL; +const struct mmio_handler *handler; -handler = find_mmio_handler(v->domain, info->gpa); +handler = find_mmio_handler(v, info->gpa); if ( !handler ) return 0; @@ -131,6 +135,10 @@ void register_mmio_handler(struct domain *d, vmmio->num_entries++; +/* Sort mmio handlers in ascending order based on base address */ +sort(vmmio->handlers, vmmio->num_entries, sizeof(struct mmio_handler), +cmp_mmio_handler, NULL); + write_unlock(>lock); } -- Qualcomm Technologies, Inc. on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project ___ Xen-devel mailing list Xen-devel@lists.xen.org https://lists.xen.org/xen-devel
[Xen-devel] [PATCH V4 11/11] arm/vgic: Change fixed number of mmio handlers to variable number
Compute the number of mmio handlers that are required for vGICv3 and vGICv2 emulation drivers in vgic_v3_init()/vgic_v2_init(). Augment this variable number of mmio handers to a fixed number MAX_IO_HANDLER and pass it to domain_io_init() to allocate enough memory. New code path: domain_vgic_register() domain_io_init(count + MAX_IO_HANDLER) domain_vgic_init() Signed-off-by: Shanker Donthineni <shank...@codeaurora.org> --- Changes since v3: Removed the variable 'mmio_count' from structure 'arch_domain', handle through a function argument. xen/arch/arm/domain.c | 12 +++- xen/arch/arm/vgic-v2.c | 3 ++- xen/arch/arm/vgic-v3.c | 5 - xen/arch/arm/vgic.c| 10 +++--- xen/include/asm-arm/vgic.h | 5 +++-- 5 files changed, 19 insertions(+), 16 deletions(-) diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c index 4010ff2..ddecd45 100644 --- a/xen/arch/arm/domain.c +++ b/xen/arch/arm/domain.c @@ -527,7 +527,7 @@ void vcpu_destroy(struct vcpu *v) int arch_domain_create(struct domain *d, unsigned int domcr_flags, struct xen_arch_domainconfig *config) { -int rc, count; +int rc, count = 0; d->arch.relmem = RELMEM_not_started; @@ -550,10 +550,6 @@ int arch_domain_create(struct domain *d, unsigned int domcr_flags, share_xen_page_with_guest( virt_to_page(d->shared_info), d, XENSHARE_writable); -count = MAX_IO_HANDLER; -if ( (rc = domain_io_init(d, count)) != 0 ) -goto fail; - if ( (rc = p2m_alloc_table(d)) != 0 ) goto fail; @@ -590,6 +586,12 @@ int arch_domain_create(struct domain *d, unsigned int domcr_flags, goto fail; } +if ( (rc = domain_vgic_register(d, )) != 0 ) +goto fail; + +if ( (rc = domain_io_init(d, count + MAX_IO_HANDLER)) != 0 ) +goto fail; + if ( (rc = domain_vgic_init(d, config->nr_spis)) != 0 ) goto fail; diff --git a/xen/arch/arm/vgic-v2.c b/xen/arch/arm/vgic-v2.c index f5778e6..928f9af 100644 --- a/xen/arch/arm/vgic-v2.c +++ b/xen/arch/arm/vgic-v2.c @@ -711,7 +711,7 @@ static const struct vgic_ops vgic_v2_ops = { .max_vcpus = 8, }; -int vgic_v2_init(struct domain *d) +int vgic_v2_init(struct domain *d, int *mmio_count) { if ( !vgic_v2_hw.enabled ) { @@ -721,6 +721,7 @@ int vgic_v2_init(struct domain *d) return -ENODEV; } +*mmio_count = 1; /* Only GICD region */ register_vgic_ops(d, _v2_ops); return 0; diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c index be9a9a3..f926fe6 100644 --- a/xen/arch/arm/vgic-v3.c +++ b/xen/arch/arm/vgic-v3.c @@ -1499,7 +1499,7 @@ static const struct vgic_ops v3_ops = { .max_vcpus = 4096, }; -int vgic_v3_init(struct domain *d) +int vgic_v3_init(struct domain *d, int *mmio_count) { if ( !vgic_v3_hw.enabled ) { @@ -1509,6 +1509,9 @@ int vgic_v3_init(struct domain *d) return -ENODEV; } +/* GICD region + number of Redistributors */ +*mmio_count = vgic_v3_rdist_count(d) + 1; + register_vgic_ops(d, _ops); return 0; diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c index f5e89af..de8a94d 100644 --- a/xen/arch/arm/vgic.c +++ b/xen/arch/arm/vgic.c @@ -88,18 +88,18 @@ static void vgic_rank_init(struct vgic_irq_rank *rank, uint8_t index, rank->vcpu[i] = vcpu; } -static int domain_vgic_register(struct domain *d) +int domain_vgic_register(struct domain *d, int *mmio_count) { switch ( d->arch.vgic.version ) { #ifdef CONFIG_HAS_GICV3 case GIC_V3: -if ( vgic_v3_init(d) ) +if ( vgic_v3_init(d, mmio_count) ) return -ENODEV; break; #endif case GIC_V2: -if ( vgic_v2_init(d) ) +if ( vgic_v2_init(d, mmio_count) ) return -ENODEV; break; default: @@ -124,10 +124,6 @@ int domain_vgic_init(struct domain *d, unsigned int nr_spis) d->arch.vgic.nr_spis = nr_spis; -ret = domain_vgic_register(d); -if ( ret < 0 ) -return ret; - spin_lock_init(>arch.vgic.lock); d->arch.vgic.shared_irqs = diff --git a/xen/include/asm-arm/vgic.h b/xen/include/asm-arm/vgic.h index c3cc4f6..300f461 100644 --- a/xen/include/asm-arm/vgic.h +++ b/xen/include/asm-arm/vgic.h @@ -304,9 +304,10 @@ extern int vgic_emulate(struct cpu_user_regs *regs, union hsr hsr); extern void vgic_disable_irqs(struct vcpu *v, uint32_t r, int n); extern void vgic_enable_irqs(struct vcpu *v, uint32_t r, int n); extern void register_vgic_ops(struct domain *d, const struct vgic_ops *ops); -int vgic_v2_init(struct domain *d); -int vgic_v3_init(struct domain *d); +int vgic_v2_init(struct domain *d, int *mmio_count); +int vgic_v3_init(struct domain *d, int *mmio_count); +extern int domain_vgic_register(struct domain *d, int *mmio_count); extern int vcpu_vgic_free(struct vcpu *v); extern int vgic_to_sgi(struct vcpu *v, register_t s
[Xen-devel] [PATCH V4 08/11] arm/io: Use separate memory allocation for mmio handlers
The number of mmio handlers are limited to a compile time macro MAX_IO_HANDLER which is 16. This number is not at all sufficient to support per CPU distributor regions. Either it needs to be increased to a bigger number, at least CONFIG_NR_CPUS+16, or allocate a separate memory for mmio handlers dynamically during domain build. This patch uses the dynamic allocation strategy to reduce memory footprint for 'struct domain' instead of static allocation. Signed-off-by: Shanker Donthineni <shank...@codeaurora.org> Acked-by: Julien Grall <julien.gr...@arm.com> --- Changes since v1: Moved registration of vgic_v3/v2 functionality to a new domain_vgic_register() xen/arch/arm/domain.c | 6 -- xen/arch/arm/io.c | 13 +++-- xen/include/asm-arm/mmio.h | 7 +-- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c index 1365b4a..4010ff2 100644 --- a/xen/arch/arm/domain.c +++ b/xen/arch/arm/domain.c @@ -527,7 +527,7 @@ void vcpu_destroy(struct vcpu *v) int arch_domain_create(struct domain *d, unsigned int domcr_flags, struct xen_arch_domainconfig *config) { -int rc; +int rc, count; d->arch.relmem = RELMEM_not_started; @@ -550,7 +550,8 @@ int arch_domain_create(struct domain *d, unsigned int domcr_flags, share_xen_page_with_guest( virt_to_page(d->shared_info), d, XENSHARE_writable); -if ( (rc = domain_io_init(d)) != 0 ) +count = MAX_IO_HANDLER; +if ( (rc = domain_io_init(d, count)) != 0 ) goto fail; if ( (rc = p2m_alloc_table(d)) != 0 ) @@ -644,6 +645,7 @@ void arch_domain_destroy(struct domain *d) free_xenheap_pages(d->arch.efi_acpi_table, get_order_from_bytes(d->arch.efi_acpi_len)); #endif +domain_io_free(d); } void arch_domain_shutdown(struct domain *d) diff --git a/xen/arch/arm/io.c b/xen/arch/arm/io.c index 5a96836..40330f0 100644 --- a/xen/arch/arm/io.c +++ b/xen/arch/arm/io.c @@ -118,7 +118,7 @@ void register_mmio_handler(struct domain *d, struct vmmio *vmmio = >arch.vmmio; struct mmio_handler *handler; -BUG_ON(vmmio->num_entries >= MAX_IO_HANDLER); +BUG_ON(vmmio->num_entries >= vmmio->max_num_entries); write_lock(>lock); @@ -134,14 +134,23 @@ void register_mmio_handler(struct domain *d, write_unlock(>lock); } -int domain_io_init(struct domain *d) +int domain_io_init(struct domain *d, int max_count) { rwlock_init(>arch.vmmio.lock); d->arch.vmmio.num_entries = 0; +d->arch.vmmio.max_num_entries = max_count; +d->arch.vmmio.handlers = xzalloc_array(struct mmio_handler, max_count); +if ( !d->arch.vmmio.handlers ) +return -ENOMEM; return 0; } +void domain_io_free(struct domain *d) +{ +xfree(d->arch.vmmio.handlers); +} + /* * Local variables: * mode: C diff --git a/xen/include/asm-arm/mmio.h b/xen/include/asm-arm/mmio.h index 32f10f2..c620eed 100644 --- a/xen/include/asm-arm/mmio.h +++ b/xen/include/asm-arm/mmio.h @@ -52,15 +52,18 @@ struct mmio_handler { struct vmmio { int num_entries; +int max_num_entries; rwlock_t lock; -struct mmio_handler handlers[MAX_IO_HANDLER]; +struct mmio_handler *handlers; }; extern int handle_mmio(mmio_info_t *info); void register_mmio_handler(struct domain *d, const struct mmio_handler_ops *ops, paddr_t addr, paddr_t size, void *priv); -int domain_io_init(struct domain *d); +int domain_io_init(struct domain *d, int max_count); +void domain_io_free(struct domain *d); + #endif /* __ASM_ARM_MMIO_H__ */ -- Qualcomm Technologies, Inc. on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project ___ Xen-devel mailing list Xen-devel@lists.xen.org https://lists.xen.org/xen-devel
Re: [Xen-devel] [PATCH V3 01/10] arm/gic-v3: Use acpi_table_parse_madt() to parse MADT subtables
Hi Stefano/Juilen On 07/14/2016 09:18 AM, Stefano Stabellini wrote: On Mon, 27 Jun 2016, Shanker Donthineni wrote: The function acpi_table_parse_madt() does the same functionality as function acpi_parse_entries() expect it takes a few arguments. Signed-off-by: Shanker Donthineni <shank...@codeaurora.org> I committed patches 1 to 7 Thanks, I'll post the remaining patches for code review. -- Shanker Donthineni Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project. ___ Xen-devel mailing list Xen-devel@lists.xen.org https://lists.xen.org/xen-devel
Re: [Xen-devel] [PATCH V3 04/10] arm/gic-v3: Parse per-cpu redistributor entry in GICC subtable
On 06/28/2016 08:51 AM, Shanker Donthineni wrote: Hi Julien, On 06/28/2016 05:40 AM, Julien Grall wrote: Hello Shanker, On 27/06/16 21:33, Shanker Donthineni wrote: @@ -1397,6 +1408,36 @@ gic_acpi_parse_madt_distributor(struct acpi_subtable_header *header, } static int __init +gic_acpi_parse_cpu_redistributor(struct acpi_subtable_header *header, + const unsigned long end) +{ +struct acpi_madt_generic_interrupt *processor; +u32 size; + +processor = (struct acpi_madt_generic_interrupt *)header; +if ( !(processor->flags & ACPI_MADT_ENABLED) ) +return 0; You did not answer to my question on previous version of this patch. You said that "Disabled GICC entries should be skipped because its Redistributor region is not always-on power domain." However from my understanding, an usable CPU may have his Redistributor in the not always-on power domain. So the issue would the same, correct? The gicv3_populate_rdist() is not supposed to read GICR registers if the the associated hardware GICR block is in power-off state. The CPU accesses to disabled GICR region leads to either a system hang or an unexpected behavior. The description of flag ACPI_MADT_ENABLED in ACPI-6.1 says "If zero, this processor in unusable, and the operating system support will not attempt to use it". Regards, -- Shanker Donthineni Qualcomm Technologies, Inc. on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project ___ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
Re: [Xen-devel] [PATCH V3 04/10] arm/gic-v3: Parse per-cpu redistributor entry in GICC subtable
Hi Julien, On 06/28/2016 05:40 AM, Julien Grall wrote: Hello Shanker, On 27/06/16 21:33, Shanker Donthineni wrote: @@ -1397,6 +1408,36 @@ gic_acpi_parse_madt_distributor(struct acpi_subtable_header *header, } static int __init +gic_acpi_parse_cpu_redistributor(struct acpi_subtable_header *header, + const unsigned long end) +{ +struct acpi_madt_generic_interrupt *processor; +u32 size; + +processor = (struct acpi_madt_generic_interrupt *)header; +if ( !(processor->flags & ACPI_MADT_ENABLED) ) +return 0; You did not answer to my question on previous version of this patch. You said that "Disabled GICC entries should be skipped because its Redistributor region is not always-on power domain." However from my understanding, an usable CPU may have his Redistributor in the not always-on power domain. So the issue would the same, correct? The gicv3_populate_rdist() is not supposed to read GICR registers if the the associated hardware GICR block is in power-off state. The CPU accesses to disabled GICR region leads to either a system hang or an unexpected behavior. Regards, -- Shanker Donthineni Qualcomm Technologies, Inc. on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project ___ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
Re: [Xen-devel] [PATCH V3 09/10] xen/arm: io: Use binary search for mmio handler lookup
Hi Julien, On 06/28/2016 05:49 AM, Julien Grall wrote: Hi Shanker, On 27/06/16 21:33, Shanker Donthineni wrote: As the number of I/O handlers increase, the overhead associated with linear lookup also increases. The system might have maximum of 144 (assuming CONFIG_NR_CPUS=128) mmio handlers. In worst case scenario, it would require 144 iterations for finding a matching handler. Now it is time for us to change from linear (complexity O(n)) to a binary search (complexity O(log n) for reducing mmio handler lookup overhead. Signed-off-by: Shanker Donthineni <shank...@codeaurora.org> --- Changes since v2: Converted mmio lookup code to a critical section. Copied the function bsreach() from Linux kernel. xen/arch/arm/io.c | 97 +++ 1 file changed, 84 insertions(+), 13 deletions(-) diff --git a/xen/arch/arm/io.c b/xen/arch/arm/io.c index a5b2c2d..c31fdf3 100644 --- a/xen/arch/arm/io.c +++ b/xen/arch/arm/io.c @@ -20,9 +20,50 @@ #include #include #include +#include #include #include +/* + * bsearch - binary search an array of elements + * @key: pointer to item being searched for + * @base: pointer to first element to search + * @num: number of elements + * @size: size of each element + * @cmp: pointer to comparison function + * + * This function does a binary search on the given array. The + * contents of the array should already be in ascending sorted order + * under the provided comparison function. + * + * Note that the key need not have the same type as the elements in + * the array, e.g. key could be a string and the comparison function + * could compare the string with the struct's name field. However, if + * the key and elements in the array are of the same type, you can use + * the same comparison function for both sort() and bsearch(). + */ +static void *bsearch(const void *key, const void *base, size_t num, size_t size, + int (*cmp)(const void *key, const void *elt)) This function is not specific to I/O handlers. So this should be moved to common code. Also please mention in the commit message where the code came from. Should I move to xen/arch/arm folder? +{ +size_t start = 0, end = num; +int result; + +while ( start < end ) +{ +size_t mid = start + (end - start) / 2; + +result = cmp(key, base + mid * size); +if ( result < 0 ) +end = mid; +else if ( result > 0 ) +start = mid + 1; +else +return (void *)base + mid * size; +} + +return NULL; +} + static int handle_read(const struct mmio_handler *handler, struct vcpu *v, mmio_info_t *info) { @@ -70,23 +111,41 @@ static int handle_write(const struct mmio_handler *handler, struct vcpu *v, handler->priv); } -int handle_mmio(mmio_info_t *info) +static int match_mmio_handler(const void *key, const void *elem) { -struct vcpu *v = current; -int i; -const struct mmio_handler *handler = NULL; -const struct vmmio *vmmio = >domain->arch.vmmio; +const struct mmio_handler *handler = elem; +paddr_t addr = (paddr_t)key; -for ( i = 0; i < vmmio->num_entries; i++ ) -{ -handler = >handlers[i]; +if ( addr < handler->addr ) +return -1; -if ( (info->gpa >= handler->addr) && - (info->gpa < (handler->addr + handler->size)) ) -break; -} +if ( addr > (handler->addr + handler->size) ) +return 1; + +return 0; +} -if ( i == vmmio->num_entries ) +static const struct mmio_handler * +find_mmio_handler(struct vcpu *v, paddr_t addr) +{ +struct vmmio *vmmio = >domain->arch.vmmio; +const struct mmio_handler *handler; + +spin_lock(>lock); +handler = bsearch((const void *)addr, vmmio->handlers, vmmio->num_entries, paddr_t is always 64-bit regardless the architecture (ARM64 vs ARM32). So the cast will lead to a compilation error on ARM32. I'll fix. Please try to at least compile test your patch with ARM64, ARM32 and x86 (when you touch common code). Thanks, I'll follow next time. Anyway, I would try to merge the two compare functions (match_mmio_handler, cmp_mmio_handler) which have very similar behavior. Yes, they are not exactly same. One compares only start address and other one compares the range. + sizeof(*handler), match_mmio_handler); +spin_unlock(>lock); + +return handler; +} + +int handle_mmio(mmio_info_t *info) +{ +const struct mmio_handler *handler; +struct vcpu *v = current; + +handler = find_mmio_handler(v, info->gpa); +if ( !handler ) return 0; if ( info->dabt.write ) @@ -95,6 +154,14 @@ int handle_mmio(mmio_info_t *info) return handle_read(handler, v, info); } +static int cmp_mmio_handler(const void *
[Xen-devel] [PATCH V3 03/10] arm/gic-v3: Move GICR subtable parsing into a new function
Add a new function to parse GICR subtable and move the code that is specific to GICR table to a new function without changing the function gicv3_acpi_init() behavior. Signed-off-by: Shanker Donthineni <shank...@codeaurora.org> --- Changes since v2: Changed function gic_acpi_add_rdist_region() protoype. Removed the address validation check in gic_acpi_parse_madt_redistributor(). Edited commit text. Changes since v1: Removed the unnecessary GICR ioremap operation inside GICR table parse code. xen/arch/arm/gic-v3.c | 56 +++ 1 file changed, 34 insertions(+), 22 deletions(-) diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c index 1f8fbc4..efdb56b 100644 --- a/xen/arch/arm/gic-v3.c +++ b/xen/arch/arm/gic-v3.c @@ -1282,6 +1282,14 @@ static int gicv3_iomem_deny_access(const struct domain *d) } #ifdef CONFIG_ACPI +static void __init gic_acpi_add_rdist_region(paddr_t base, paddr_t size) +{ +unsigned int idx = gicv3.rdist_count++; + +gicv3.rdist_regions[idx].base = base; +gicv3.rdist_regions[idx].size = size; +} + static int gicv3_make_hwdom_madt(const struct domain *d, u32 offset) { struct acpi_subtable_header *header; @@ -1387,6 +1395,22 @@ gic_acpi_parse_madt_distributor(struct acpi_subtable_header *header, return 0; } + +static int __init +gic_acpi_parse_madt_redistributor(struct acpi_subtable_header *header, + const unsigned long end) +{ +struct acpi_madt_generic_redistributor *rdist; + +rdist = (struct acpi_madt_generic_redistributor *)header; +if ( BAD_MADT_ENTRY(rdist, end) ) +return -EINVAL; + +gic_acpi_add_rdist_region(rdist->base_address, rdist->length); + +return 0; +} + static int __init gic_acpi_get_madt_redistributor_num(struct acpi_subtable_header *header, const unsigned long end) @@ -1400,7 +1424,7 @@ gic_acpi_get_madt_redistributor_num(struct acpi_subtable_header *header, static void __init gicv3_acpi_init(void) { struct rdist_region *rdist_regs; -int count, i; +int count; /* * Find distributor base address. We expect one distributor entry since @@ -1419,37 +1443,25 @@ static void __init gicv3_acpi_init(void) if ( count <= 0 ) panic("GICv3: No valid GICR entries exists"); -gicv3.rdist_count = count; - -if ( gicv3.rdist_count > MAX_RDIST_COUNT ) +if ( count > MAX_RDIST_COUNT ) panic("GICv3: Number of redistributor regions is more than" "%d (Increase MAX_RDIST_COUNT!!)\n", MAX_RDIST_COUNT); -rdist_regs = xzalloc_array(struct rdist_region, gicv3.rdist_count); +rdist_regs = xzalloc_array(struct rdist_region, count); if ( !rdist_regs ) panic("GICv3: Failed to allocate memory for rdist regions\n"); -for ( i = 0; i < gicv3.rdist_count; i++ ) -{ -struct acpi_subtable_header *header; -struct acpi_madt_generic_redistributor *gic_rdist; - -header = acpi_table_get_entry_madt(ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR, - i); -if ( !header ) -panic("GICv3: Can't get GICR entry"); - -gic_rdist = - container_of(header, struct acpi_madt_generic_redistributor, header); -rdist_regs[i].base = gic_rdist->base_address; -rdist_regs[i].size = gic_rdist->length; -} +gicv3.rdist_regions = rdist_regs; + +/* Parse always-on power domain Re-distributor entries */ +count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR, + gic_acpi_parse_madt_redistributor, count); +if ( count <= 0 ) +panic("GICv3: Can't get Redistributor entry"); /* The vGIC code requires the region to be sorted */ sort(rdist_regs, gicv3.rdist_count, sizeof(*rdist_regs), cmp_rdist, NULL); -gicv3.rdist_regions= rdist_regs; - /* Collect CPU base addresses */ count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_INTERRUPT, gic_acpi_parse_madt_cpu, 0); -- Qualcomm Technologies, Inc. on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project ___ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
[Xen-devel] [PATCH V3 09/10] xen/arm: io: Use binary search for mmio handler lookup
As the number of I/O handlers increase, the overhead associated with linear lookup also increases. The system might have maximum of 144 (assuming CONFIG_NR_CPUS=128) mmio handlers. In worst case scenario, it would require 144 iterations for finding a matching handler. Now it is time for us to change from linear (complexity O(n)) to a binary search (complexity O(log n) for reducing mmio handler lookup overhead. Signed-off-by: Shanker Donthineni <shank...@codeaurora.org> --- Changes since v2: Converted mmio lookup code to a critical section. Copied the function bsreach() from Linux kernel. xen/arch/arm/io.c | 97 +++ 1 file changed, 84 insertions(+), 13 deletions(-) diff --git a/xen/arch/arm/io.c b/xen/arch/arm/io.c index a5b2c2d..c31fdf3 100644 --- a/xen/arch/arm/io.c +++ b/xen/arch/arm/io.c @@ -20,9 +20,50 @@ #include #include #include +#include #include #include +/* + * bsearch - binary search an array of elements + * @key: pointer to item being searched for + * @base: pointer to first element to search + * @num: number of elements + * @size: size of each element + * @cmp: pointer to comparison function + * + * This function does a binary search on the given array. The + * contents of the array should already be in ascending sorted order + * under the provided comparison function. + * + * Note that the key need not have the same type as the elements in + * the array, e.g. key could be a string and the comparison function + * could compare the string with the struct's name field. However, if + * the key and elements in the array are of the same type, you can use + * the same comparison function for both sort() and bsearch(). + */ +static void *bsearch(const void *key, const void *base, size_t num, size_t size, + int (*cmp)(const void *key, const void *elt)) +{ +size_t start = 0, end = num; +int result; + +while ( start < end ) +{ +size_t mid = start + (end - start) / 2; + +result = cmp(key, base + mid * size); +if ( result < 0 ) +end = mid; +else if ( result > 0 ) +start = mid + 1; +else +return (void *)base + mid * size; +} + +return NULL; +} + static int handle_read(const struct mmio_handler *handler, struct vcpu *v, mmio_info_t *info) { @@ -70,23 +111,41 @@ static int handle_write(const struct mmio_handler *handler, struct vcpu *v, handler->priv); } -int handle_mmio(mmio_info_t *info) +static int match_mmio_handler(const void *key, const void *elem) { -struct vcpu *v = current; -int i; -const struct mmio_handler *handler = NULL; -const struct vmmio *vmmio = >domain->arch.vmmio; +const struct mmio_handler *handler = elem; +paddr_t addr = (paddr_t)key; -for ( i = 0; i < vmmio->num_entries; i++ ) -{ -handler = >handlers[i]; +if ( addr < handler->addr ) +return -1; -if ( (info->gpa >= handler->addr) && - (info->gpa < (handler->addr + handler->size)) ) -break; -} +if ( addr > (handler->addr + handler->size) ) +return 1; + +return 0; +} -if ( i == vmmio->num_entries ) +static const struct mmio_handler * +find_mmio_handler(struct vcpu *v, paddr_t addr) +{ +struct vmmio *vmmio = >domain->arch.vmmio; +const struct mmio_handler *handler; + +spin_lock(>lock); +handler = bsearch((const void *)addr, vmmio->handlers, vmmio->num_entries, + sizeof(*handler), match_mmio_handler); +spin_unlock(>lock); + +return handler; +} + +int handle_mmio(mmio_info_t *info) +{ +const struct mmio_handler *handler; +struct vcpu *v = current; + +handler = find_mmio_handler(v, info->gpa); +if ( !handler ) return 0; if ( info->dabt.write ) @@ -95,6 +154,14 @@ int handle_mmio(mmio_info_t *info) return handle_read(handler, v, info); } +static int cmp_mmio_handler(const void *key, const void *elem) +{ +const struct mmio_handler *handler0 = key; +const struct mmio_handler *handler1 = elem; + +return (handler0->addr < handler1->addr) ? -1 : 0; +} + void register_mmio_handler(struct domain *d, const struct mmio_handler_ops *ops, paddr_t addr, paddr_t size, void *priv) @@ -122,6 +189,10 @@ void register_mmio_handler(struct domain *d, vmmio->num_entries++; +/* Sort mmio handlers in ascending order based on base address */ +sort(vmmio->handlers, vmmio->num_entries, sizeof(struct mmio_handler), + cmp_mmio_handler, NULL); + spin_unlock(>lock); } -- Qualcomm Technologies, Inc. on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Cod
[Xen-devel] [PATCH V3 08/10] arm/io: Use separate memory allocation for mmio handlers
The number of mmio handlers are limited to a compile time macro MAX_IO_HANDLER which is 16. This number is not at all sufficient to support per CPU distributor regions. Either it needs to be increased to a bigger number, at least CONFIG_NR_CPUS+16, or allocate a separate memory for mmio handlers dynamically during domain build. This patch uses the dynamic allocation strategy to reduce memory footprint for 'struct domain' instead of static allocation. Signed-off-by: Shanker Donthineni <shank...@codeaurora.org> Acked-by: Julien Grall <julien.gr...@arm.com> --- Changes since v1: Moved registration of vgic_v3/v2 functionality to a new domain_vgic_register(). xen/arch/arm/domain.c | 6 -- xen/arch/arm/io.c | 14 -- xen/include/asm-arm/mmio.h | 6 -- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c index 1365b4a..4010ff2 100644 --- a/xen/arch/arm/domain.c +++ b/xen/arch/arm/domain.c @@ -527,7 +527,7 @@ void vcpu_destroy(struct vcpu *v) int arch_domain_create(struct domain *d, unsigned int domcr_flags, struct xen_arch_domainconfig *config) { -int rc; +int rc, count; d->arch.relmem = RELMEM_not_started; @@ -550,7 +550,8 @@ int arch_domain_create(struct domain *d, unsigned int domcr_flags, share_xen_page_with_guest( virt_to_page(d->shared_info), d, XENSHARE_writable); -if ( (rc = domain_io_init(d)) != 0 ) +count = MAX_IO_HANDLER; +if ( (rc = domain_io_init(d, count)) != 0 ) goto fail; if ( (rc = p2m_alloc_table(d)) != 0 ) @@ -644,6 +645,7 @@ void arch_domain_destroy(struct domain *d) free_xenheap_pages(d->arch.efi_acpi_table, get_order_from_bytes(d->arch.efi_acpi_len)); #endif +domain_io_free(d); } void arch_domain_shutdown(struct domain *d) diff --git a/xen/arch/arm/io.c b/xen/arch/arm/io.c index 0156755..a5b2c2d 100644 --- a/xen/arch/arm/io.c +++ b/xen/arch/arm/io.c @@ -102,7 +102,7 @@ void register_mmio_handler(struct domain *d, struct vmmio *vmmio = >arch.vmmio; struct mmio_handler *handler; -BUG_ON(vmmio->num_entries >= MAX_IO_HANDLER); +BUG_ON(vmmio->num_entries >= vmmio->max_num_entries); spin_lock(>lock); @@ -125,14 +125,24 @@ void register_mmio_handler(struct domain *d, spin_unlock(>lock); } -int domain_io_init(struct domain *d) +int domain_io_init(struct domain *d, int max_count) { spin_lock_init(>arch.vmmio.lock); d->arch.vmmio.num_entries = 0; + d->arch.vmmio.max_num_entries = max_count; + d->arch.vmmio.handlers = xzalloc_array(struct mmio_handler, max_count); + if ( !d->arch.vmmio.handlers ) + return -ENOMEM; + return 0; } +void domain_io_free(struct domain *d) +{ +xfree(d->arch.vmmio.handlers); +} + /* * Local variables: * mode: C diff --git a/xen/include/asm-arm/mmio.h b/xen/include/asm-arm/mmio.h index da1cc2e..276b263 100644 --- a/xen/include/asm-arm/mmio.h +++ b/xen/include/asm-arm/mmio.h @@ -51,15 +51,17 @@ struct mmio_handler { struct vmmio { int num_entries; +int max_num_entries; spinlock_t lock; -struct mmio_handler handlers[MAX_IO_HANDLER]; +struct mmio_handler *handlers; }; extern int handle_mmio(mmio_info_t *info); void register_mmio_handler(struct domain *d, const struct mmio_handler_ops *ops, paddr_t addr, paddr_t size, void *priv); -int domain_io_init(struct domain *d); +int domain_io_init(struct domain *d, int max_count); +void domain_io_free(struct domain *d); #endif /* __ASM_ARM_MMIO_H__ */ -- Qualcomm Technologies, Inc. on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project ___ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
[Xen-devel] [PATCH V3 07/10] arm: vgic: Split vgic_domain_init() functionality into two functions
Separate the code logic that does the registration of vgic_v3/v2 ops to a new function domain_vgic_register(). The intention of this separation is to record the required mmio count in vgic_v3/v2_init() and pass it to function domain_io_init() in a follow-up patch patch. Signed-off-by: Shanker Donthineni <shank...@codeaurora.org> --- Changes since v2: Edited commit text. xen/arch/arm/vgic.c | 33 + 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c index 5df5f01..f5e89af 100644 --- a/xen/arch/arm/vgic.c +++ b/xen/arch/arm/vgic.c @@ -88,19 +88,8 @@ static void vgic_rank_init(struct vgic_irq_rank *rank, uint8_t index, rank->vcpu[i] = vcpu; } -int domain_vgic_init(struct domain *d, unsigned int nr_spis) +static int domain_vgic_register(struct domain *d) { -int i; -int ret; - -d->arch.vgic.ctlr = 0; - -/* Limit the number of virtual SPIs supported to (1020 - 32) = 988 */ -if ( nr_spis > (1020 - NR_LOCAL_IRQS) ) -return -EINVAL; - -d->arch.vgic.nr_spis = nr_spis; - switch ( d->arch.vgic.version ) { #ifdef CONFIG_HAS_GICV3 @@ -119,6 +108,26 @@ int domain_vgic_init(struct domain *d, unsigned int nr_spis) return -ENODEV; } +return 0; +} + +int domain_vgic_init(struct domain *d, unsigned int nr_spis) +{ +int i; +int ret; + +d->arch.vgic.ctlr = 0; + +/* Limit the number of virtual SPIs supported to (1020 - 32) = 988 */ +if ( nr_spis > (1020 - NR_LOCAL_IRQS) ) +return -EINVAL; + +d->arch.vgic.nr_spis = nr_spis; + +ret = domain_vgic_register(d); +if ( ret < 0 ) +return ret; + spin_lock_init(>arch.vgic.lock); d->arch.vgic.shared_irqs = -- Qualcomm Technologies, Inc. on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project ___ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
[Xen-devel] [PATCH V3 04/10] arm/gic-v3: Parse per-cpu redistributor entry in GICC subtable
The redistributor address can be specified either as part of GICC or GICR subtable depending on the power domain. The current driver doesn't support parsing redistributor entry that is defined in GICC subtable. The GIC CPU subtable entry holds the associated Redistributor base address if it is not on always-on power domain. The per CPU Redistributor size is not defined in ACPI specification. Set the GICR region size to SZ_256K if the GIC hardware is capable of Direct Virtual LPI Injection feature, SZ_128K otherwise. This patch adds necessary code to handle both types of Redistributors base addresses. Signed-off-by: Shanker Donthineni <shank...@codeaurora.org> --- Changes since v2: Removed the unnecessary validation checks and edited commit text. xen/arch/arm/gic-v3.c | 68 +++ xen/include/asm-arm/gic.h | 1 + xen/include/asm-arm/gic_v3_defs.h | 1 + 3 files changed, 63 insertions(+), 7 deletions(-) diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c index efdb56b..352799e 100644 --- a/xen/arch/arm/gic-v3.c +++ b/xen/arch/arm/gic-v3.c @@ -659,6 +659,10 @@ static int __init gicv3_populate_rdist(void) smp_processor_id(), i, ptr); return 0; } + +if ( gicv3.rdist_regions[i].single_rdist ) +break; + if ( gicv3.rdist_stride ) ptr += gicv3.rdist_stride; else @@ -1282,14 +1286,21 @@ static int gicv3_iomem_deny_access(const struct domain *d) } #ifdef CONFIG_ACPI -static void __init gic_acpi_add_rdist_region(paddr_t base, paddr_t size) +static void __init +gic_acpi_add_rdist_region(paddr_t base, paddr_t size, bool single_rdist) { unsigned int idx = gicv3.rdist_count++; +gicv3.rdist_regions[idx].single_rdist = single_rdist; gicv3.rdist_regions[idx].base = base; gicv3.rdist_regions[idx].size = size; } +static inline bool gic_dist_supports_dvis(void) +{ +return !!(readl_relaxed(GICD + GICD_TYPER) & GICD_TYPER_DVIS); +} + static int gicv3_make_hwdom_madt(const struct domain *d, u32 offset) { struct acpi_subtable_header *header; @@ -1397,6 +1408,36 @@ gic_acpi_parse_madt_distributor(struct acpi_subtable_header *header, } static int __init +gic_acpi_parse_cpu_redistributor(struct acpi_subtable_header *header, + const unsigned long end) +{ +struct acpi_madt_generic_interrupt *processor; +u32 size; + +processor = (struct acpi_madt_generic_interrupt *)header; +if ( !(processor->flags & ACPI_MADT_ENABLED) ) +return 0; + +size = gic_dist_supports_dvis() ? 4 * SZ_64K : 2 * SZ_64K; +gic_acpi_add_rdist_region(processor->gicr_base_address, size, true); + +return 0; +} + +static int __init +gic_acpi_get_madt_cpu_num(struct acpi_subtable_header *header, + const unsigned long end) +{ +struct acpi_madt_generic_interrupt *cpuif; + +cpuif = (struct acpi_madt_generic_interrupt *)header; +if ( BAD_MADT_ENTRY(cpuif, end) || !cpuif->gicr_base_address ) +return -EINVAL; + +return 0; +} + +static int __init gic_acpi_parse_madt_redistributor(struct acpi_subtable_header *header, const unsigned long end) { @@ -1406,7 +1447,7 @@ gic_acpi_parse_madt_redistributor(struct acpi_subtable_header *header, if ( BAD_MADT_ENTRY(rdist, end) ) return -EINVAL; -gic_acpi_add_rdist_region(rdist->base_address, rdist->length); +gic_acpi_add_rdist_region(rdist->base_address, rdist->length, false); return 0; } @@ -1424,6 +1465,7 @@ gic_acpi_get_madt_redistributor_num(struct acpi_subtable_header *header, static void __init gicv3_acpi_init(void) { struct rdist_region *rdist_regs; +bool gicr_table = true; int count; /* @@ -1440,8 +1482,15 @@ static void __init gicv3_acpi_init(void) /* Get number of redistributor */ count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR, gic_acpi_get_madt_redistributor_num, 0); -if ( count <= 0 ) -panic("GICv3: No valid GICR entries exists"); +/* Count the total number of CPU interface entries */ +if ( count <= 0 ) { +count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_INTERRUPT, + gic_acpi_get_madt_cpu_num, 0); +if (count <= 0) +panic("GICv3: No valid GICR entries exists"); + +gicr_table = false; +} if ( count > MAX_RDIST_COUNT ) panic("GICv3: Number of redistributor regions is more than" @@ -1453,9 +1502,14 @@ static void __init gicv3_acpi_init(void) gicv3.rdist_regions = rdist_regs; -/* Parse always-on power domain Re-distributor entries */ -count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR
[Xen-devel] [PATCH V3 05/10] xen/arm: vgic: Use dynamic memory allocation for vgic_rdist_region
The number of Redistributor regions allowed for dom0 is hardcoded to a define MAX_RDIST_COUNT which is 4. Some systems, especially latest server chips, may have more than 4 redistributors. Either we have to increase MAX_RDIST_COUNT to a bigger number or allocate memory based on the number of redistributors that are found in MADT table. In the worst case scenario, the macro MAX_RDIST_COUNT should be equal to CONFIG_NR_CPUS in order to support per CPU Redistributors. Increasing MAX_RDIST_COUNT has a effect, it blows 'struct domain' size and hits BUILD_BUG_ON() in domain build code path. struct domain *alloc_domain_struct(void) { struct domain *d; BUILD_BUG_ON(sizeof(*d) > PAGE_SIZE); d = alloc_xenheap_pages(0, 0); if ( d == NULL ) return NULL; ... This patch uses the second approach to fix the BUILD_BUG(). Signed-off-by: Shanker Donthineni <shank...@codeaurora.org> --- Changes sicne v2: Edited commit text. xen/arch/arm/vgic-v2.c | 6 ++ xen/arch/arm/vgic-v3.c | 27 --- xen/arch/arm/vgic.c | 1 + xen/include/asm-arm/domain.h | 2 +- xen/include/asm-arm/vgic.h | 2 ++ 5 files changed, 34 insertions(+), 4 deletions(-) diff --git a/xen/arch/arm/vgic-v2.c b/xen/arch/arm/vgic-v2.c index 9adb4a9..f5778e6 100644 --- a/xen/arch/arm/vgic-v2.c +++ b/xen/arch/arm/vgic-v2.c @@ -699,9 +699,15 @@ static int vgic_v2_domain_init(struct domain *d) return 0; } +static void vgic_v2_domain_free(struct domain *d) +{ +/* Nothing to be cleanup for this driver */ +} + static const struct vgic_ops vgic_v2_ops = { .vcpu_init = vgic_v2_vcpu_init, .domain_init = vgic_v2_domain_init, +.domain_free = vgic_v2_domain_free, .max_vcpus = 8, }; diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c index b37a7c0..be9a9a3 100644 --- a/xen/arch/arm/vgic-v3.c +++ b/xen/arch/arm/vgic-v3.c @@ -1391,9 +1391,26 @@ static int vgic_v3_vcpu_init(struct vcpu *v) return 0; } +static inline unsigned int vgic_v3_rdist_count(struct domain *d) +{ +return is_hardware_domain(d) ? vgic_v3_hw.nr_rdist_regions : + GUEST_GICV3_RDIST_REGIONS; +} + static int vgic_v3_domain_init(struct domain *d) { -int i; +struct vgic_rdist_region *rdist_regions; +int rdist_count, i; + +/* Allocate memory for Re-distributor regions */ +rdist_count = vgic_v3_rdist_count(d); + +rdist_regions = xzalloc_array(struct vgic_rdist_region, rdist_count); +if ( !rdist_regions ) +return -ENOMEM; + +d->arch.vgic.nr_regions = rdist_count; +d->arch.vgic.rdist_regions = rdist_regions; /* * Domain 0 gets the hardware address. @@ -1426,7 +1443,6 @@ static int vgic_v3_domain_init(struct domain *d) first_cpu += size / d->arch.vgic.rdist_stride; } -d->arch.vgic.nr_regions = vgic_v3_hw.nr_rdist_regions; } else { @@ -1435,7 +1451,6 @@ static int vgic_v3_domain_init(struct domain *d) /* XXX: Only one Re-distributor region mapped for the guest */ BUILD_BUG_ON(GUEST_GICV3_RDIST_REGIONS != 1); -d->arch.vgic.nr_regions = GUEST_GICV3_RDIST_REGIONS; d->arch.vgic.rdist_stride = GUEST_GICV3_RDIST_STRIDE; /* The first redistributor should contain enough space for all CPUs */ @@ -1467,9 +1482,15 @@ static int vgic_v3_domain_init(struct domain *d) return 0; } +static void vgic_v3_domain_free(struct domain *d) +{ +xfree(d->arch.vgic.rdist_regions); +} + static const struct vgic_ops v3_ops = { .vcpu_init = vgic_v3_vcpu_init, .domain_init = vgic_v3_domain_init, +.domain_free = vgic_v3_domain_free, .emulate_sysreg = vgic_v3_emulate_sysreg, /* * We use both AFF1 and AFF0 in (v)MPIDR. Thus, the max number of CPU diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c index 3e1c572..5df5f01 100644 --- a/xen/arch/arm/vgic.c +++ b/xen/arch/arm/vgic.c @@ -177,6 +177,7 @@ void domain_vgic_free(struct domain *d) } } +d->arch.vgic.handler->domain_free(d); xfree(d->arch.vgic.shared_irqs); xfree(d->arch.vgic.pending_irqs); xfree(d->arch.vgic.allocated_irqs); diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h index 370cdeb..29346c6 100644 --- a/xen/include/asm-arm/domain.h +++ b/xen/include/asm-arm/domain.h @@ -107,7 +107,7 @@ struct arch_domain paddr_t base; /* Base address */ paddr_t size; /* Size */ unsigned int first_cpu; /* First CPU handled */ -} rdist_regions[MAX_RDIST_COUNT]; +} *rdist_regions; int nr_regions; /* Number of rdist regions */ uint32_t rdist_stride; /* Re-Distributor stride */ #endif diff --git a/xen/include/asm-arm/vgic.h b/xen/include/asm-arm/vgic.h index a2fccc0..c3cc4f6 100644 --- a/xen/include/asm-arm/vgic
[Xen-devel] [PATCH v3 06/10] arm/gic-v3: Remove an unused macro MAX_RDIST_COUNT
The macro MAX_RDIST_COUNT is not being used after converting code to handle number of redistributor dynamically. So remove it from header file and the two other panic() messages that are not valid anymore. Signed-off-by: Shanker Donthineni <shank...@codeaurora.org> Acked-by: Julien Grall <julien.gr...@arm.com> --- xen/arch/arm/gic-v3.c | 8 xen/include/asm-arm/gic.h | 1 - 2 files changed, 9 deletions(-) diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c index 352799e..948052b 100644 --- a/xen/arch/arm/gic-v3.c +++ b/xen/arch/arm/gic-v3.c @@ -1200,10 +1200,6 @@ static void __init gicv3_dt_init(void) _count) ) gicv3.rdist_count = 1; -if ( gicv3.rdist_count > MAX_RDIST_COUNT ) -panic("GICv3: Number of redistributor regions is more than" - "%d (Increase MAX_RDIST_COUNT!!)\n", MAX_RDIST_COUNT); - rdist_regs = xzalloc_array(struct rdist_region, gicv3.rdist_count); if ( !rdist_regs ) panic("GICv3: Failed to allocate memory for rdist regions\n"); @@ -1492,10 +1488,6 @@ static void __init gicv3_acpi_init(void) gicr_table = false; } -if ( count > MAX_RDIST_COUNT ) -panic("GICv3: Number of redistributor regions is more than" - "%d (Increase MAX_RDIST_COUNT!!)\n", MAX_RDIST_COUNT); - rdist_regs = xzalloc_array(struct rdist_region, count); if ( !rdist_regs ) panic("GICv3: Failed to allocate memory for rdist regions\n"); diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h index fedf1fa..db7b2d0 100644 --- a/xen/include/asm-arm/gic.h +++ b/xen/include/asm-arm/gic.h @@ -20,7 +20,6 @@ #define NR_GIC_LOCAL_IRQS NR_LOCAL_IRQS #define NR_GIC_SGI 16 -#define MAX_RDIST_COUNT4 #define GICD_CTLR (0x000) #define GICD_TYPER (0x004) -- Qualcomm Technologies, Inc. on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project ___ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
[Xen-devel] [PATCH V3 02/10] arm/gic-v3: Do early GICD ioremap and clean up
For ACPI based XEN boot, the GICD region needs to be accessed inside the function gicv3_acpi_init() in later patch. There is a duplicate panic() message, one in the DTS probe and second one in the ACPI probe path. For these two reasons, move the code that validates the GICD base address and does the region ioremap to a separate function. The following patch accesses the GICD region inside gicv3_acpi_init() for finding per CPU Redistributor size. Signed-off-by: Shanker Donthineni <shank...@codeaurora.org> Acked-by: Julien Grall <julien.gr...@arm.com> --- Changes sicne v1: Edited commit text. xen/arch/arm/gic-v3.c | 23 +-- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c index 166f1c1..1f8fbc4 100644 --- a/xen/arch/arm/gic-v3.c +++ b/xen/arch/arm/gic-v3.c @@ -1169,6 +1169,17 @@ static void __init gicv3_init_v2(void) vgic_v2_setup_hw(dbase, cbase, csize, vbase, 0); } +static void __init gicv3_ioremap_distributor(paddr_t dist_paddr) +{ +if ( dist_paddr & ~PAGE_MASK ) +panic("GICv3: Found unaligned distributor address %"PRIpaddr"", + dbase); + +gicv3.map_dbase = ioremap_nocache(dist_paddr, SZ_64K); +if ( !gicv3.map_dbase ) +panic("GICv3: Failed to ioremap for GIC distributor\n"); +} + static void __init gicv3_dt_init(void) { struct rdist_region *rdist_regs; @@ -1179,9 +1190,7 @@ static void __init gicv3_dt_init(void) if ( res ) panic("GICv3: Cannot find a valid distributor address"); -if ( (dbase & ~PAGE_MASK) ) -panic("GICv3: Found unaligned distributor address %"PRIpaddr"", - dbase); +gicv3_ioremap_distributor(dbase); if ( !dt_property_read_u32(node, "#redistributor-regions", _count) ) @@ -1402,9 +1411,7 @@ static void __init gicv3_acpi_init(void) if ( count <= 0 ) panic("GICv3: No valid GICD entries exists"); -if ( (dbase & ~PAGE_MASK) ) -panic("GICv3: Found unaligned distributor address %"PRIpaddr"", - dbase); +gicv3_ioremap_distributor(dbase); /* Get number of redistributor */ count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR, @@ -1476,10 +1483,6 @@ static int __init gicv3_init(void) else gicv3_acpi_init(); -gicv3.map_dbase = ioremap_nocache(dbase, SZ_64K); -if ( !gicv3.map_dbase ) -panic("GICv3: Failed to ioremap for GIC distributor\n"); - reg = readl_relaxed(GICD + GICD_PIDR2) & GIC_PIDR2_ARCH_MASK; if ( reg != GIC_PIDR2_ARCH_GICv3 && reg != GIC_PIDR2_ARCH_GICv4 ) panic("GICv3: no distributor detected\n"); -- Qualcomm Technologies, Inc. on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project ___ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
[Xen-devel] [PATCH V3 10/10] arm/vgic: Change fixed number of mmio handlers to variable number
Record the number of mmio handlers that are required for vGICv3/2 in variable 'arch_domain.vgic.mmio_count' in vgic_v3/v2_init(). Augment this variable number to a fixed number MAX_IO_HANDLER and pass it to domain_io_init() to allocate enough memory for handlers. New code path: domain_vgic_register() count = MAX_IO_HANDLER + d->arch.vgic.mmio_count; domain_io_init(count) domain_vgic_init() Signed-off-by: Shanker Donthineni <shank...@codeaurora.org> --- xen/arch/arm/domain.c| 11 +++ xen/arch/arm/vgic-v2.c | 1 + xen/arch/arm/vgic-v3.c | 3 +++ xen/arch/arm/vgic.c | 6 +- xen/include/asm-arm/domain.h | 1 + xen/include/asm-arm/vgic.h | 1 + 6 files changed, 14 insertions(+), 9 deletions(-) diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c index 4010ff2..ebc12ac 100644 --- a/xen/arch/arm/domain.c +++ b/xen/arch/arm/domain.c @@ -550,10 +550,6 @@ int arch_domain_create(struct domain *d, unsigned int domcr_flags, share_xen_page_with_guest( virt_to_page(d->shared_info), d, XENSHARE_writable); -count = MAX_IO_HANDLER; -if ( (rc = domain_io_init(d, count)) != 0 ) -goto fail; - if ( (rc = p2m_alloc_table(d)) != 0 ) goto fail; @@ -590,6 +586,13 @@ int arch_domain_create(struct domain *d, unsigned int domcr_flags, goto fail; } +if ( (rc = domain_vgic_register(d)) != 0 ) +goto fail; + +count = MAX_IO_HANDLER + d->arch.vgic.mmio_count; +if ( (rc = domain_io_init(d, count)) != 0 ) +goto fail; + if ( (rc = domain_vgic_init(d, config->nr_spis)) != 0 ) goto fail; diff --git a/xen/arch/arm/vgic-v2.c b/xen/arch/arm/vgic-v2.c index f5778e6..d5367b3 100644 --- a/xen/arch/arm/vgic-v2.c +++ b/xen/arch/arm/vgic-v2.c @@ -721,6 +721,7 @@ int vgic_v2_init(struct domain *d) return -ENODEV; } +d->arch.vgic.mmio_count = 1; /* Only GICD region */ register_vgic_ops(d, _v2_ops); return 0; diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c index be9a9a3..e527f3f 100644 --- a/xen/arch/arm/vgic-v3.c +++ b/xen/arch/arm/vgic-v3.c @@ -1509,6 +1509,9 @@ int vgic_v3_init(struct domain *d) return -ENODEV; } +/* GICD region + number of Re-distributors */ +d->arch.vgic.mmio_count = vgic_v3_rdist_count(d) + 1; + register_vgic_ops(d, _ops); return 0; diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c index f5e89af..0658bfc 100644 --- a/xen/arch/arm/vgic.c +++ b/xen/arch/arm/vgic.c @@ -88,7 +88,7 @@ static void vgic_rank_init(struct vgic_irq_rank *rank, uint8_t index, rank->vcpu[i] = vcpu; } -static int domain_vgic_register(struct domain *d) +int domain_vgic_register(struct domain *d) { switch ( d->arch.vgic.version ) { @@ -124,10 +124,6 @@ int domain_vgic_init(struct domain *d, unsigned int nr_spis) d->arch.vgic.nr_spis = nr_spis; -ret = domain_vgic_register(d); -if ( ret < 0 ) -return ret; - spin_lock_init(>arch.vgic.lock); d->arch.vgic.shared_irqs = diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h index 29346c6..b205461 100644 --- a/xen/include/asm-arm/domain.h +++ b/xen/include/asm-arm/domain.h @@ -111,6 +111,7 @@ struct arch_domain int nr_regions; /* Number of rdist regions */ uint32_t rdist_stride; /* Re-Distributor stride */ #endif +uint32_t mmio_count;/* Number of mmio handlers */ } vgic; struct vuart { diff --git a/xen/include/asm-arm/vgic.h b/xen/include/asm-arm/vgic.h index c3cc4f6..a693f95 100644 --- a/xen/include/asm-arm/vgic.h +++ b/xen/include/asm-arm/vgic.h @@ -307,6 +307,7 @@ extern void register_vgic_ops(struct domain *d, const struct vgic_ops *ops); int vgic_v2_init(struct domain *d); int vgic_v3_init(struct domain *d); +extern int domain_vgic_register(struct domain *d); extern int vcpu_vgic_free(struct vcpu *v); extern int vgic_to_sgi(struct vcpu *v, register_t sgir, enum gic_sgi_mode irqmode, int virq, -- Qualcomm Technologies, Inc. on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project ___ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
Re: [Xen-devel] [PATCH V2 03/10] arm/gic-v3: Fold GICR subtable parsing into a new function
On 06/27/2016 11:09 AM, Julien Grall wrote: On 27/06/16 17:07, Shanker Donthineni wrote: On 06/27/2016 10:41 AM, Julien Grall wrote: On 27/06/16 16:40, Shanker Donthineni wrote: +gicv3.rdist_regions = rdist_regs; + +/* Parse always-on power domain Re-distributor entries */ +count = acpi_parse_entries(ACPI_SIG_MADT, + sizeof(struct acpi_table_madt), + gic_acpi_parse_madt_redistributor, table, + ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR, count); Please use acpi_table_parse_madt here. How do we pass MADT table pointer that we are using to a function acpi_table_parse_madt()? We have already obtained the MADT table address by calling acpi_get_table() at the beginning of the function gicv3_acpi_init(). You don't need to pass it. The function will take care to get the MADT table for you. Are you expecting me to modify current driver to replace acpi_parse_entries() calls with acpi_table_parse_madt() before my changes? No, I was just suggesting to modify the caller you changed/added within the different patch. Code becomes ugly for readability purpose using two set of functions in a single function. Regards, -- Shanker Donthineni Qualcomm Technologies, Inc. on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project ___ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
Re: [Xen-devel] [PATCH V2 03/10] arm/gic-v3: Fold GICR subtable parsing into a new function
be On 06/27/2016 10:41 AM, Julien Grall wrote: On 27/06/16 16:40, Shanker Donthineni wrote: +gicv3.rdist_regions = rdist_regs; + +/* Parse always-on power domain Re-distributor entries */ +count = acpi_parse_entries(ACPI_SIG_MADT, + sizeof(struct acpi_table_madt), + gic_acpi_parse_madt_redistributor, table, + ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR, count); Please use acpi_table_parse_madt here. How do we pass MADT table pointer that we are using to a function acpi_table_parse_madt()? We have already obtained the MADT table address by calling acpi_get_table() at the beginning of the function gicv3_acpi_init(). You don't need to pass it. The function will take care to get the MADT table for you. Are you expecting me to modify current driver to replace acpi_parse_entries() calls with acpi_table_parse_madt() before my changes? Regards, -- Shanker Donthineni Qualcomm Technologies, Inc. on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project ___ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
Re: [Xen-devel] [PATCH V2 03/10] arm/gic-v3: Fold GICR subtable parsing into a new function
On 06/27/2016 06:26 AM, Julien Grall wrote: Hi Shanker, Title: I think you want to say "Move GICR..." rather than "Fold GICR...". On 26/06/16 18:48, Shanker Donthineni wrote: Add a new function for parsing GICR subtable and move the code Add a new function to parse GICR... that is specific to GICR table to new function without changing to a new function the function gicv3_acpi_init() behavior. Signed-off-by: Shanker Donthineni <shank...@codeaurora.org> --- Changes since v1: Removed the unnecessary GICR ioremap operation inside GICR table parse code. xen/arch/arm/gic-v3.c | 61 --- 1 file changed, 39 insertions(+), 22 deletions(-) diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c index 542c4f3..0471fea 100644 --- a/xen/arch/arm/gic-v3.c +++ b/xen/arch/arm/gic-v3.c @@ -1282,6 +1282,14 @@ static int gicv3_iomem_deny_access(const struct domain *d) } #ifdef CONFIG_ACPI +static void __init gic_acpi_add_rdist_region(u64 base_addr, u32 size) Please use paddr_t for both parameter. Also the suffix _addr is pointless. +{ +unsigned int idx = gicv3.rdist_count++; + +gicv3.rdist_regions[idx].base = base_addr; +gicv3.rdist_regions[idx].size = size; +} + static int gicv3_make_hwdom_madt(const struct domain *d, u32 offset) { struct acpi_subtable_header *header; @@ -1387,6 +1395,25 @@ gic_acpi_parse_madt_distributor(struct acpi_subtable_header *header, return 0; } + +static int __init +gic_acpi_parse_madt_redistributor(struct acpi_subtable_header *header, + const unsigned long end) +{ +struct acpi_madt_generic_redistributor *rdist; + +rdist = (struct acpi_madt_generic_redistributor *)header; +if ( BAD_MADT_ENTRY(rdist, end) ) +return -EINVAL; + +if ( !rdist->base_address || !rdist->length ) +return -EINVAL; In the commit message you said that the behavior is unchanged, however this check is not part of the previous code. Anyway, I don't think this check is necessary. + +gic_acpi_add_rdist_region(rdist->base_address, rdist->length); + +return 0; +} + static int __init gic_acpi_get_madt_redistributor_num(struct acpi_subtable_header *header, const unsigned long end) @@ -1402,7 +1429,7 @@ static void __init gicv3_acpi_init(void) struct acpi_table_header *table; struct rdist_region *rdist_regs; acpi_status status; -int count, i; +int count; status = acpi_get_table(ACPI_SIG_MADT, 0, ); @@ -1433,37 +1460,27 @@ static void __init gicv3_acpi_init(void) if ( count <= 0 ) panic("GICv3: No valid GICR entries exists"); -gicv3.rdist_count = count; - -if ( gicv3.rdist_count > MAX_RDIST_COUNT ) +if ( count > MAX_RDIST_COUNT ) panic("GICv3: Number of redistributor regions is more than" "%d (Increase MAX_RDIST_COUNT!!)\n", MAX_RDIST_COUNT); -rdist_regs = xzalloc_array(struct rdist_region, gicv3.rdist_count); +rdist_regs = xzalloc_array(struct rdist_region, count); if ( !rdist_regs ) panic("GICv3: Failed to allocate memory for rdist regions\n"); -for ( i = 0; i < gicv3.rdist_count; i++ ) -{ -struct acpi_subtable_header *header; -struct acpi_madt_generic_redistributor *gic_rdist; - -header = acpi_table_get_entry_madt(ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR, - i); -if ( !header ) -panic("GICv3: Can't get GICR entry"); - -gic_rdist = - container_of(header, struct acpi_madt_generic_redistributor, header); -rdist_regs[i].base = gic_rdist->base_address; -rdist_regs[i].size = gic_rdist->length; -} +gicv3.rdist_regions = rdist_regs; + +/* Parse always-on power domain Re-distributor entries */ +count = acpi_parse_entries(ACPI_SIG_MADT, + sizeof(struct acpi_table_madt), + gic_acpi_parse_madt_redistributor, table, + ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR, count); Please use acpi_table_parse_madt here. How do we pass MADT table pointer that we are using to a function acpi_table_parse_madt()? We have already obtained the MADT table address by calling acpi_get_table() at the beginning of the function gicv3_acpi_init(). +if ( count <= 0 ) +panic("GICv3: Can't get Redistributor entry"); /* The vGIC code requires the region to be sorted */ sort(rdist_regs, gicv3.rdist_count, sizeof(*rdist_regs), cmp_rdist, NULL); -gicv3.rdist_regions= rdist_regs; - /* Collect CPU base addresses */ count = acpi_parse_entries(ACPI_SIG_MADT, sizeof(struct acpi_table_madt), gic_acpi_parse_madt_cpu, table, Regards, -- Shanker Donthineni Qualcomm Technologies, Inc. on behalf of Qualcomm Innovation Ce
Re: [Xen-devel] [PATCH V2 10/10] arm/vgic: Change fixed number of mmio handlers to variable number
On 06/27/2016 08:35 AM, Julien Grall wrote: Hi Shanker, On 26/06/16 18:48, Shanker Donthineni wrote: diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h index 29346c6..b205461 100644 --- a/xen/include/asm-arm/domain.h +++ b/xen/include/asm-arm/domain.h @@ -111,6 +111,7 @@ struct arch_domain int nr_regions; /* Number of rdist regions */ uint32_t rdist_stride; /* Re-Distributor stride */ #endif +uint32_t mmio_count;/* Number of mmio handlers */ Is it necessary to have this value part of the arch_domain? I.e Do we need this value after the initialization? If not, then it might be better to add a parameter to domain_vgic_register uint32_t *pointer. Absolutely, we don't need this variable after the domain build process. I have taken this approach to avoid too many code changes. Your suggestion requires changes to functions vgic_v2/v3_init() prototype for adding a new parameter. } vgic; struct vuart { diff --git a/xen/include/asm-arm/vgic.h b/xen/include/asm-arm/vgic.h index fbb763a..1ce441c 100644 --- a/xen/include/asm-arm/vgic.h +++ b/xen/include/asm-arm/vgic.h @@ -307,6 +307,7 @@ extern void register_vgic_ops(struct domain *d, const struct vgic_ops *ops); int vgic_v2_init(struct domain *d); int vgic_v3_init(struct domain *d); +extern int domain_vgic_register(struct domain *d); extern int vcpu_vgic_free(struct vcpu *v); extern int vgic_to_sgi(struct vcpu *v, register_t sgir, enum gic_sgi_mode irqmode, int virq, Regards, -- Shanker Donthineni Qualcomm Technologies, Inc. on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project ___ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
Re: [Xen-devel] [PATCH V2 09/10] xen/arm: io: Use binary search for mmio handler lookup
On 06/27/2016 08:31 AM, Julien Grall wrote: Hi Shanker, On 26/06/16 18:48, Shanker Donthineni wrote: As the number of I/O handlers increase, the overhead associated with linear lookup also increases. The system might have maximum of 144 (assuming CONFIG_NR_CPUS=128) mmio handlers. In worst case scenario, it would require 144 iterations for finding a matching handler. Now it is time for us to change from linear (complexity O(n)) to a binary search (complexity O(log n) for reducing mmio handler lookup overhead. Signed-off-by: Shanker Donthineni <shank...@codeaurora.org> --- xen/arch/arm/io.c | 50 +++--- 1 file changed, 39 insertions(+), 11 deletions(-) diff --git a/xen/arch/arm/io.c b/xen/arch/arm/io.c index a5b2c2d..abf49fb 100644 --- a/xen/arch/arm/io.c +++ b/xen/arch/arm/io.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -70,23 +71,38 @@ static int handle_write(const struct mmio_handler *handler, struct vcpu *v, handler->priv); } -int handle_mmio(mmio_info_t *info) +const struct mmio_handler *find_mmio_handler(struct vcpu *v, paddr_t addr) { -struct vcpu *v = current; -int i; -const struct mmio_handler *handler = NULL; const struct vmmio *vmmio = >domain->arch.vmmio; +const struct mmio_handler *handler = vmmio->handlers; +unsigned int eidx = vmmio->num_entries; +unsigned int midx = eidx / 2; +unsigned int sidx = 0; -for ( i = 0; i < vmmio->num_entries; i++ ) +/* Do binary search for matching mmio handler */ +while ( sidx != midx ) { -handler = >handlers[i]; - -if ( (info->gpa >= handler->addr) && - (info->gpa < (handler->addr + handler->size)) ) -break; +if ( addr < handler[midx].addr ) +eidx = midx; +else +sidx = midx; +midx = sidx + (eidx - sidx) / 2; This binary search can be simplified. For instance, why do you want to compute midx at the end rather than at the beginning. This would avoid to have "unsigned int midx = eidx / 2" at the beginning. Let me try to use "do while()" loop logic to simplify the above code logic. } -if ( i == vmmio->num_entries ) +if ( (addr >= handler[sidx].addr) && + (addr < (handler[sidx].addr + handler[sidx].size)) ) +return handler + sidx; Please use a temporary variable for handler[sidx]. So it will be easier to read the code. + +return NULL; +} + +int handle_mmio(mmio_info_t *info) +{ +const struct mmio_handler *handler; +struct vcpu *v = current; + +handler = find_mmio_handler(v, info->gpa); I would have expected some locking here. Could you explain why it is safe to looking find the handler with your solution? For what is worth, there was no locking before because register_mmio_handler was always adding the handler at the end of the array. This is not true anymore because you are sorting the array. The function register_mmio_handler() is called only during dom0/domU domain build code path. We don't need locking here until unless some code inserting mmio handlers at runtime. +if ( !handler ) return 0; if ( info->dabt.write ) @@ -95,6 +111,14 @@ int handle_mmio(mmio_info_t *info) return handle_read(handler, v, info); } +static int cmp_mmio_handler(const void *key, const void *elem) +{ +const struct mmio_handler *handler0 = key; +const struct mmio_handler *handler1 = elem; + +return (handler0->addr < handler1->addr) ? -1 : 0; +} + void register_mmio_handler(struct domain *d, const struct mmio_handler_ops *ops, paddr_t addr, paddr_t size, void *priv) @@ -122,6 +146,10 @@ void register_mmio_handler(struct domain *d, vmmio->num_entries++; +/* Sort mmio handlers in ascending order based on base address */ +sort(vmmio->handlers, vmmio->num_entries, sizeof(struct mmio_handler), + cmp_mmio_handler, NULL); + spin_unlock(>lock); } Regards, -- Shanker Donthineni Qualcomm Technologies, Inc. on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project ___ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
Re: [Xen-devel] [PATCH V2 05/10] xen/arm: vgic: Use dynamic memory allocation for vgic_rdist_region
On 06/27/2016 07:38 AM, Julien Grall wrote: Hi Shanker, On 26/06/16 18:48, Shanker Donthineni wrote: The number of Re-distributor regions allowed for dom0 is hardcoded s/Re-distributor/Redistributor/ to a compile time macro MAX_RDIST_COUNT which is 4. On some systems, s/a compile time macro/a define/ s/On some/Some/ especially latest server chips might have more than 4 redistributors. I would add a comma after 'chips'. NIT: s/redistributors/Redistributors/ Either we have to increase MAX_RDIST_COUNT to a bigger number or allocate memory based on number of redistributors that are found in s/based on number/based on the number/ MADT table. In the worst case scenario, the macro MAX_RDIST_COUNT should be equal to CONFIG_NR_CPUS in order to support per CPU Redistributors. Increasing MAX_RDIST_COUNT has side effect, it blows 'struct domain' s/has side/has a/ size and hits BUILD_BUG_ON() in domain build code path. struct domain *alloc_domain_struct(void) { struct domain *d; BUILD_BUG_ON(sizeof(*d) > PAGE_SIZE); d = alloc_xenheap_pages(0, 0); if ( d == NULL ) return NULL; ... This patch uses the second approach to fix the BUILD_BUG(). Signed-off-by: Shanker Donthineni <shank...@codeaurora.org> --- Changes since v1: Keep 'struct vgic_rdist_region' definition inside 'struct arch_domain'. xen/arch/arm/vgic-v2.c | 6 ++ xen/arch/arm/vgic-v3.c | 22 +++--- xen/arch/arm/vgic.c | 1 + xen/include/asm-arm/domain.h | 2 +- xen/include/asm-arm/vgic.h | 2 ++ 5 files changed, 29 insertions(+), 4 deletions(-) diff --git a/xen/arch/arm/vgic-v2.c b/xen/arch/arm/vgic-v2.c index 9adb4a9..f5778e6 100644 --- a/xen/arch/arm/vgic-v2.c +++ b/xen/arch/arm/vgic-v2.c @@ -699,9 +699,15 @@ static int vgic_v2_domain_init(struct domain *d) return 0; } +static void vgic_v2_domain_free(struct domain *d) +{ +/* Nothing to be cleanup for this driver */ +} + static const struct vgic_ops vgic_v2_ops = { .vcpu_init = vgic_v2_vcpu_init, .domain_init = vgic_v2_domain_init, +.domain_free = vgic_v2_domain_free, .max_vcpus = 8, }; diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c index b37a7c0..e877e9e 100644 --- a/xen/arch/arm/vgic-v3.c +++ b/xen/arch/arm/vgic-v3.c @@ -1393,7 +1393,19 @@ static int vgic_v3_vcpu_init(struct vcpu *v) static int vgic_v3_domain_init(struct domain *d) { -int i; +struct vgic_rdist_region *rdist_regions; +int rdist_count, i; + +/* Allocate memory for Re-distributor regions */ +rdist_count = is_hardware_domain(d) ? vgic_v3_hw.nr_rdist_regions : + GUEST_GICV3_RDIST_REGIONS; I would directly introduce the inline helper in this patch, rather than in patch #10. Okay, I'll add a helper function as part of this patch. + +rdist_regions = xzalloc_array(struct vgic_rdist_region, rdist_count); +if ( !rdist_regions ) +return -ENOMEM; + +d->arch.vgic.nr_regions = rdist_count; +d->arch.vgic.rdist_regions = rdist_regions; /* * Domain 0 gets the hardware address. [...] diff --git a/xen/include/asm-arm/vgic.h b/xen/include/asm-arm/vgic.h index a2fccc0..fbb763a 100644 --- a/xen/include/asm-arm/vgic.h +++ b/xen/include/asm-arm/vgic.h @@ -128,6 +128,8 @@ struct vgic_ops { int (*vcpu_init)(struct vcpu *v); /* Domain specific initialization of vGIC */ int (*domain_init)(struct domain *d); +/* Release resources that are allocated by domain_init */ s/are/were/ +void (*domain_free)(struct domain *d); /* vGIC sysreg emulation */ int (*emulate_sysreg)(struct cpu_user_regs *regs, union hsr hsr); /* Maximum number of vCPU supported */ Regards, -- Shanker Donthineni Qualcomm Technologies, Inc. on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project ___ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
Re: [Xen-devel] [PATCH V2 04/10] arm/gic-v3: Parse per-cpu redistributor entry in GICC subtable
On 06/27/2016 06:47 AM, Julien Grall wrote: Hi Shanker, On 26/06/16 18:48, Shanker Donthineni wrote: The redistributor address can be specified either as part of GICC or GICR subtable depending on the power domain. The current driver doesn't support parsing redistributor entry that is defined in GICC subtable. The GIC CPU subtable entry holds the associated Redistributor base address if it is not on always-on power domain. The per CPU Redistributor size is not defined in ACPI specification. Set it's size to SZ_256K if the GIC hardware is capable of Direct s/it's/its/, although I would use "the". Virtual LPI Injection feature otherwise SZ_128K. "Set the size to SZ_256K if the GIC hardware is supporting Direct Virtual LPI injection, SZ_128K otherwise". This patch adds necessary code to handle both types of Redistributors base addresses. Signed-off-by: Shanker Donthineni <shank...@codeaurora.org> --- Changes since v1: Edited commit text and fixed white spaces. Added a new function for parsing per CPU Redistributor entry. xen/arch/arm/gic-v3.c | 84 ++- xen/include/asm-arm/gic.h | 1 + xen/include/asm-arm/gic_v3_defs.h | 1 + 3 files changed, 77 insertions(+), 9 deletions(-) diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c index 0471fea..3977244 100644 --- a/xen/arch/arm/gic-v3.c +++ b/xen/arch/arm/gic-v3.c @@ -659,6 +659,10 @@ static int __init gicv3_populate_rdist(void) smp_processor_id(), i, ptr); return 0; } + +if ( gicv3.rdist_regions[i].single_rdist ) +break; + if ( gicv3.rdist_stride ) ptr += gicv3.rdist_stride; else @@ -1282,14 +1286,21 @@ static int gicv3_iomem_deny_access(const struct domain *d) } #ifdef CONFIG_ACPI -static void __init gic_acpi_add_rdist_region(u64 base_addr, u32 size) +static void __init +gic_acpi_add_rdist_region(u64 base_addr, u32 size, bool single_rdist) { unsigned int idx = gicv3.rdist_count++; +gicv3.rdist_regions[idx].single_rdist = single_rdist; gicv3.rdist_regions[idx].base = base_addr; gicv3.rdist_regions[idx].size = size; } +static inline bool gic_dist_supports_dvis(void) +{ +return !!(readl_relaxed(GICD + GICD_TYPER) & GICD_TYPER_DVIS); +} + static int gicv3_make_hwdom_madt(const struct domain *d, u32 offset) { struct acpi_subtable_header *header; @@ -1397,6 +1408,42 @@ gic_acpi_parse_madt_distributor(struct acpi_subtable_header *header, } static int __init +gic_acpi_parse_cpu_redistributor(struct acpi_subtable_header *header, + const unsigned long end) +{ +struct acpi_madt_generic_interrupt *processor; +u32 size; + +processor = (struct acpi_madt_generic_interrupt *)header; +if ( BAD_MADT_ENTRY(processor, end) ) +return -EINVAL; + +if ( !processor->gicr_base_address ) +return -EINVAL; You already check it in gic_acpi_get_madt_cpu_num, so there is no reason to do it again. Other function just finds the number of valid cpu interfaces. I would prefer to keep the validation check here. + +if ( processor->flags & ACPI_MADT_ENABLED ) +{ +size = gic_dist_supports_dvis() ? 4 * SZ_64K : 2 * SZ_64K; + gic_acpi_add_rdist_region(processor->gicr_base_address, size, true); +} I would revert the condition to avoid one level of indentation. I.e I'll do. if ( !(processor->flags & ACPI_MADT_ENABLED) ) return 0; size = gic_acpi_add... return 0; However, it looks like that the other function that parses GICC within gic-v3.c (see gic_acpi_parse_madt_cpu) does not check if the CPU is usable. Disabled GICC entries should be skipped because its Redistributor region is not always-on power domain. Please look at my review comment to your KVM-ACPI patch http://www.gossamer-threads.com/lists/linux/kernel/2413670. I think we need to have the same parsing behavior on every function. + +return 0; +} + +static int __init +gic_acpi_get_madt_cpu_num(struct acpi_subtable_header *header, +const unsigned long end) +{ +struct acpi_madt_generic_interrupt *cpuif; + +cpuif = (struct acpi_madt_generic_interrupt *)header; +if ( BAD_MADT_ENTRY(cpuif, end) || !cpuif->gicr_base_address ) +return -EINVAL; + +return 0; +} + +static int __init gic_acpi_parse_madt_redistributor(struct acpi_subtable_header *header, const unsigned long end) { @@ -1409,7 +1456,7 @@ gic_acpi_parse_madt_redistributor(struct acpi_subtable_header *header, if ( !rdist->base_address || !rdist->length ) return -EINVAL; -gic_acpi_add_rdist_region(rdist->base_address, rdist->length); +gic_acpi_add_rdist_region(rdist->base_address, rdist-
Re: [Xen-devel] [PATCH V2 03/10] arm/gic-v3: Fold GICR subtable parsing into a new function
On 06/27/2016 06:26 AM, Julien Grall wrote: Hi Shanker, Title: I think you want to say "Move GICR..." rather than "Fold GICR...". On 26/06/16 18:48, Shanker Donthineni wrote: Add a new function for parsing GICR subtable and move the code Add a new function to parse GICR... that is specific to GICR table to new function without changing to a new function the function gicv3_acpi_init() behavior. Signed-off-by: Shanker Donthineni <shank...@codeaurora.org> --- Changes since v1: Removed the unnecessary GICR ioremap operation inside GICR table parse code. xen/arch/arm/gic-v3.c | 61 --- 1 file changed, 39 insertions(+), 22 deletions(-) diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c index 542c4f3..0471fea 100644 --- a/xen/arch/arm/gic-v3.c +++ b/xen/arch/arm/gic-v3.c @@ -1282,6 +1282,14 @@ static int gicv3_iomem_deny_access(const struct domain *d) } #ifdef CONFIG_ACPI +static void __init gic_acpi_add_rdist_region(u64 base_addr, u32 size) Please use paddr_t for both parameter. Also the suffix _addr is pointless. I'll fix. +{ +unsigned int idx = gicv3.rdist_count++; + +gicv3.rdist_regions[idx].base = base_addr; +gicv3.rdist_regions[idx].size = size; +} + static int gicv3_make_hwdom_madt(const struct domain *d, u32 offset) { struct acpi_subtable_header *header; @@ -1387,6 +1395,25 @@ gic_acpi_parse_madt_distributor(struct acpi_subtable_header *header, return 0; } + +static int __init +gic_acpi_parse_madt_redistributor(struct acpi_subtable_header *header, + const unsigned long end) +{ +struct acpi_madt_generic_redistributor *rdist; + +rdist = (struct acpi_madt_generic_redistributor *)header; +if ( BAD_MADT_ENTRY(rdist, end) ) +return -EINVAL; + +if ( !rdist->base_address || !rdist->length ) +return -EINVAL; In the commit message you said that the behavior is unchanged, however this check is not part of the previous code. Anyway, I don't think this check is necessary. Sure, I'll remove the validation check from here. + +gic_acpi_add_rdist_region(rdist->base_address, rdist->length); + +return 0; +} + static int __init gic_acpi_get_madt_redistributor_num(struct acpi_subtable_header *header, const unsigned long end) @@ -1402,7 +1429,7 @@ static void __init gicv3_acpi_init(void) struct acpi_table_header *table; struct rdist_region *rdist_regs; acpi_status status; -int count, i; +int count; status = acpi_get_table(ACPI_SIG_MADT, 0, ); @@ -1433,37 +1460,27 @@ static void __init gicv3_acpi_init(void) if ( count <= 0 ) panic("GICv3: No valid GICR entries exists"); -gicv3.rdist_count = count; - -if ( gicv3.rdist_count > MAX_RDIST_COUNT ) +if ( count > MAX_RDIST_COUNT ) panic("GICv3: Number of redistributor regions is more than" "%d (Increase MAX_RDIST_COUNT!!)\n", MAX_RDIST_COUNT); -rdist_regs = xzalloc_array(struct rdist_region, gicv3.rdist_count); +rdist_regs = xzalloc_array(struct rdist_region, count); if ( !rdist_regs ) panic("GICv3: Failed to allocate memory for rdist regions\n"); -for ( i = 0; i < gicv3.rdist_count; i++ ) -{ -struct acpi_subtable_header *header; -struct acpi_madt_generic_redistributor *gic_rdist; - -header = acpi_table_get_entry_madt(ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR, - i); -if ( !header ) -panic("GICv3: Can't get GICR entry"); - -gic_rdist = - container_of(header, struct acpi_madt_generic_redistributor, header); -rdist_regs[i].base = gic_rdist->base_address; -rdist_regs[i].size = gic_rdist->length; -} +gicv3.rdist_regions = rdist_regs; + +/* Parse always-on power domain Re-distributor entries */ +count = acpi_parse_entries(ACPI_SIG_MADT, + sizeof(struct acpi_table_madt), + gic_acpi_parse_madt_redistributor, table, + ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR, count); Please use acpi_table_parse_madt here. Sure. +if ( count <= 0 ) +panic("GICv3: Can't get Redistributor entry"); /* The vGIC code requires the region to be sorted */ sort(rdist_regs, gicv3.rdist_count, sizeof(*rdist_regs), cmp_rdist, NULL); -gicv3.rdist_regions= rdist_regs; - /* Collect CPU base addresses */ count = acpi_parse_entries(ACPI_SIG_MADT, sizeof(struct acpi_table_madt), gic_acpi_parse_madt_cpu, table, Regards, -- Shanker Donthineni Qualcomm Technologies, Inc. on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project ___ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
Re: [Xen-devel] [PATCH V2 01/10] arm/gic-v3: Fix bug in function cmp_rdist()
On 06/27/2016 06:03 AM, Julien Grall wrote: Hi Shanker, On 26/06/16 18:48, Shanker Donthineni wrote: The cmp_rdist() is always returning value zero irrespective of the input Redistributor base addresses. Both the local variables 'l' and 'r' are pointing to the first argument 'a' causing the logical expression 'l->base < r->base' always evaluated as false which is wrong. Signed-off-by: Shanker Donthineni <shank...@codeaurora.org> --- xen/arch/arm/gic-v3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c index 8d3f149..b89c608 100644 --- a/xen/arch/arm/gic-v3.c +++ b/xen/arch/arm/gic-v3.c @@ -1133,7 +1133,7 @@ static const hw_irq_controller gicv3_guest_irq_type = { static int __init cmp_rdist(const void *a, const void *b) { -const struct rdist_region *l = a, *r = a; +const struct rdist_region *l = a, *r = b; Thank you for spotting the error. The sorting was required because of the way the vGIC emulated the re-distributors. However, this code has been reworked and sorted array is not necessary anymore. So I would directly drop the sorting here. Thanks, I'll drop this patch in patchset-v3. /* We assume that re-distributor regions can never overlap */ return ( l->base < r->base) ? -1 : 0; Regards, -- Shanker Donthineni Qualcomm Technologies, Inc. on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project ___ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
[Xen-devel] [PATCH V2 00/10] Add support for parsing per CPU Redistributor entry
The current driver doesn't support parsing Redistributor entries that are described in the MADT GICC table. Not all the GIC implementors places the Redistributor regions in the always-on power domain. On systems, the UEFI firmware should describe Redistributor base address in the associated GIC CPU Interface (GICC) instead of GIC Redistributor (GICR) table. The maximum number of mmio handlers and struct vgic_rdist_region that holds Redistributor addresses are allocated through a static array with hardcoded size. I don't think this is the right approach and is not scalable for implementing features like this. I have decided to convert static to dynamic allocation based on comments from the below link. Patches #1 fixes the bug in the current driver. Patches #2, #3 and #4 adds support for parsing not always-on power domain Redistributor regions. Patches #5, #6, #7, #8 and #10 refactors the code and allocates the memory for mmio handlers and vgic_rdist_region based on the number of Redistributors required for dom0/domU instead of hardcoded values. Patch #9 changes the linear to binary search to avoid lookup overhead. This pacthset is created on tip of Julien's branch http://xenbits.xen.org/gitweb/?p=people/julieng/xen-unstable.git;a=shortlog;h=refs/heads/irq-routing-acpi-rfc Shanker Donthineni (10): arm/gic-v3: Fix bug in function cmp_rdist() arm/gic-v3: Do early GICD ioremap and clean up arm/gic-v3: Fold GICR subtable parsing into a new function arm/gic-v3: Parse per-cpu redistributor entry in GICC subtable xen/arm: vgic: Use dynamic memory allocation for vgic_rdist_region arm/gic-v3: Remove an unused macro MAX_RDIST_COUNT arm: vgic: Split vgic_domain_init() functionality into two functions arm/io: Use separate memory allocation for mmio handlers xen/arm: io: Use binary search for mmio handler lookup arm/vgic: Change fixed number of mmio handlers to variable number xen/arch/arm/domain.c | 13 +++- xen/arch/arm/gic-v3.c | 158 -- xen/arch/arm/io.c | 64 +++ xen/arch/arm/vgic-v2.c| 7 ++ xen/arch/arm/vgic-v3.c| 30 +++- xen/arch/arm/vgic.c | 30 +--- xen/include/asm-arm/domain.h | 3 +- xen/include/asm-arm/gic.h | 2 +- xen/include/asm-arm/gic_v3_defs.h | 1 + xen/include/asm-arm/mmio.h| 6 +- xen/include/asm-arm/vgic.h| 3 + 11 files changed, 241 insertions(+), 76 deletions(-) -- Qualcomm Technologies, Inc. on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project ___ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
[Xen-devel] [PATCH V2 07/10] arm: vgic: Split vgic_domain_init() functionality into two functions
Separate the code logic that does the registration of vgic_v3/v2 ops to a new fucntion domain_vgic_register(). The intention of this separation is to record the required mmio count in vgic_v3/v2_init() and pass it to function domain_io_init() in the later patch. Signed-off-by: Shanker Donthineni <shank...@codeaurora.org> --- Changes since v1: Moved registration of vgic_v3/v2 functionality to a new domain_vgic_register(). xen/arch/arm/vgic.c | 33 + 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c index 5df5f01..7627eff 100644 --- a/xen/arch/arm/vgic.c +++ b/xen/arch/arm/vgic.c @@ -88,19 +88,8 @@ static void vgic_rank_init(struct vgic_irq_rank *rank, uint8_t index, rank->vcpu[i] = vcpu; } -int domain_vgic_init(struct domain *d, unsigned int nr_spis) +static int domain_vgic_register(struct domain *d) { -int i; -int ret; - -d->arch.vgic.ctlr = 0; - -/* Limit the number of virtual SPIs supported to (1020 - 32) = 988 */ -if ( nr_spis > (1020 - NR_LOCAL_IRQS) ) -return -EINVAL; - -d->arch.vgic.nr_spis = nr_spis; - switch ( d->arch.vgic.version ) { #ifdef CONFIG_HAS_GICV3 @@ -119,6 +108,26 @@ int domain_vgic_init(struct domain *d, unsigned int nr_spis) return -ENODEV; } +return 0; +} + +int domain_vgic_init(struct domain *d, unsigned int nr_spis) +{ +int i; +int ret; + +d->arch.vgic.ctlr = 0; + +/* Limit the number of virtual SPIs supported to (1020 - 32) = 988 */ +if ( nr_spis > (1020 - NR_LOCAL_IRQS) ) +return -EINVAL; + +d->arch.vgic.nr_spis = nr_spis; + +ret = domain_vgic_register(d); +if ( ret < 0) +return ret; + spin_lock_init(>arch.vgic.lock); d->arch.vgic.shared_irqs = -- Qualcomm Technologies, Inc. on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project ___ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
[Xen-devel] [PATCH V2 10/10] arm/vgic: Change fixed number of mmio handlers to variable number
Record the number of mmio handlers that are required for vGICv3/2 in variable 'arch_domain.vgic.mmio_count' in vgic_v3/v2_init(). Augment this variable number to a fixed number MAX_IO_HANDLER and pass it to domain_io_init() to allocate enough memory for handlers. New code path: domain_vgic_register() count = MAX_IO_HANDLER + d->arch.vgic.mmio_count; domain_io_init(count) domain_vgic_init() Signed-off-by: Shanker Donthineni <shank...@codeaurora.org> --- xen/arch/arm/domain.c| 11 +++ xen/arch/arm/vgic-v2.c | 1 + xen/arch/arm/vgic-v3.c | 12 ++-- xen/arch/arm/vgic.c | 6 +- xen/include/asm-arm/domain.h | 1 + xen/include/asm-arm/vgic.h | 1 + 6 files changed, 21 insertions(+), 11 deletions(-) diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c index 4010ff2..ebc12ac 100644 --- a/xen/arch/arm/domain.c +++ b/xen/arch/arm/domain.c @@ -550,10 +550,6 @@ int arch_domain_create(struct domain *d, unsigned int domcr_flags, share_xen_page_with_guest( virt_to_page(d->shared_info), d, XENSHARE_writable); -count = MAX_IO_HANDLER; -if ( (rc = domain_io_init(d, count)) != 0 ) -goto fail; - if ( (rc = p2m_alloc_table(d)) != 0 ) goto fail; @@ -590,6 +586,13 @@ int arch_domain_create(struct domain *d, unsigned int domcr_flags, goto fail; } +if ( (rc = domain_vgic_register(d)) != 0 ) +goto fail; + +count = MAX_IO_HANDLER + d->arch.vgic.mmio_count; +if ( (rc = domain_io_init(d, count)) != 0 ) +goto fail; + if ( (rc = domain_vgic_init(d, config->nr_spis)) != 0 ) goto fail; diff --git a/xen/arch/arm/vgic-v2.c b/xen/arch/arm/vgic-v2.c index f5778e6..d5367b3 100644 --- a/xen/arch/arm/vgic-v2.c +++ b/xen/arch/arm/vgic-v2.c @@ -721,6 +721,7 @@ int vgic_v2_init(struct domain *d) return -ENODEV; } +d->arch.vgic.mmio_count = 1; /* Only GICD region */ register_vgic_ops(d, _v2_ops); return 0; diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c index e877e9e..472deac 100644 --- a/xen/arch/arm/vgic-v3.c +++ b/xen/arch/arm/vgic-v3.c @@ -1391,14 +1391,19 @@ static int vgic_v3_vcpu_init(struct vcpu *v) return 0; } +static inline unsigned int vgic_v3_rdist_count(struct domain *d) +{ +return is_hardware_domain(d) ? vgic_v3_hw.nr_rdist_regions : + GUEST_GICV3_RDIST_REGIONS; +} + static int vgic_v3_domain_init(struct domain *d) { struct vgic_rdist_region *rdist_regions; int rdist_count, i; /* Allocate memory for Re-distributor regions */ -rdist_count = is_hardware_domain(d) ? vgic_v3_hw.nr_rdist_regions : - GUEST_GICV3_RDIST_REGIONS; +rdist_count = vgic_v3_rdist_count(d); rdist_regions = xzalloc_array(struct vgic_rdist_region, rdist_count); if ( !rdist_regions ) @@ -1504,6 +1509,9 @@ int vgic_v3_init(struct domain *d) return -ENODEV; } +/* GICD region + number of Re-distributors */ +d->arch.vgic.mmio_count = vgic_v3_rdist_count(d) + 1; + register_vgic_ops(d, _ops); return 0; diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c index 7627eff..0658bfc 100644 --- a/xen/arch/arm/vgic.c +++ b/xen/arch/arm/vgic.c @@ -88,7 +88,7 @@ static void vgic_rank_init(struct vgic_irq_rank *rank, uint8_t index, rank->vcpu[i] = vcpu; } -static int domain_vgic_register(struct domain *d) +int domain_vgic_register(struct domain *d) { switch ( d->arch.vgic.version ) { @@ -124,10 +124,6 @@ int domain_vgic_init(struct domain *d, unsigned int nr_spis) d->arch.vgic.nr_spis = nr_spis; -ret = domain_vgic_register(d); -if ( ret < 0) -return ret; - spin_lock_init(>arch.vgic.lock); d->arch.vgic.shared_irqs = diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h index 29346c6..b205461 100644 --- a/xen/include/asm-arm/domain.h +++ b/xen/include/asm-arm/domain.h @@ -111,6 +111,7 @@ struct arch_domain int nr_regions; /* Number of rdist regions */ uint32_t rdist_stride; /* Re-Distributor stride */ #endif +uint32_t mmio_count;/* Number of mmio handlers */ } vgic; struct vuart { diff --git a/xen/include/asm-arm/vgic.h b/xen/include/asm-arm/vgic.h index fbb763a..1ce441c 100644 --- a/xen/include/asm-arm/vgic.h +++ b/xen/include/asm-arm/vgic.h @@ -307,6 +307,7 @@ extern void register_vgic_ops(struct domain *d, const struct vgic_ops *ops); int vgic_v2_init(struct domain *d); int vgic_v3_init(struct domain *d); +extern int domain_vgic_register(struct domain *d); extern int vcpu_vgic_free(struct vcpu *v); extern int vgic_to_sgi(struct vcpu *v, register_t sgir, enum gic_sgi_mode irqmode, int virq, -- Qualcomm Technologies, Inc. on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Cen
[Xen-devel] [PATCH V2 03/10] arm/gic-v3: Fold GICR subtable parsing into a new function
Add a new function for parsing GICR subtable and move the code that is specific to GICR table to new function without changing the function gicv3_acpi_init() behavior. Signed-off-by: Shanker Donthineni <shank...@codeaurora.org> --- Changes since v1: Removed the unnecessary GICR ioremap operation inside GICR table parse code. xen/arch/arm/gic-v3.c | 61 --- 1 file changed, 39 insertions(+), 22 deletions(-) diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c index 542c4f3..0471fea 100644 --- a/xen/arch/arm/gic-v3.c +++ b/xen/arch/arm/gic-v3.c @@ -1282,6 +1282,14 @@ static int gicv3_iomem_deny_access(const struct domain *d) } #ifdef CONFIG_ACPI +static void __init gic_acpi_add_rdist_region(u64 base_addr, u32 size) +{ +unsigned int idx = gicv3.rdist_count++; + +gicv3.rdist_regions[idx].base = base_addr; +gicv3.rdist_regions[idx].size = size; +} + static int gicv3_make_hwdom_madt(const struct domain *d, u32 offset) { struct acpi_subtable_header *header; @@ -1387,6 +1395,25 @@ gic_acpi_parse_madt_distributor(struct acpi_subtable_header *header, return 0; } + +static int __init +gic_acpi_parse_madt_redistributor(struct acpi_subtable_header *header, + const unsigned long end) +{ +struct acpi_madt_generic_redistributor *rdist; + +rdist = (struct acpi_madt_generic_redistributor *)header; +if ( BAD_MADT_ENTRY(rdist, end) ) +return -EINVAL; + +if ( !rdist->base_address || !rdist->length ) +return -EINVAL; + +gic_acpi_add_rdist_region(rdist->base_address, rdist->length); + +return 0; +} + static int __init gic_acpi_get_madt_redistributor_num(struct acpi_subtable_header *header, const unsigned long end) @@ -1402,7 +1429,7 @@ static void __init gicv3_acpi_init(void) struct acpi_table_header *table; struct rdist_region *rdist_regs; acpi_status status; -int count, i; +int count; status = acpi_get_table(ACPI_SIG_MADT, 0, ); @@ -1433,37 +1460,27 @@ static void __init gicv3_acpi_init(void) if ( count <= 0 ) panic("GICv3: No valid GICR entries exists"); -gicv3.rdist_count = count; - -if ( gicv3.rdist_count > MAX_RDIST_COUNT ) +if ( count > MAX_RDIST_COUNT ) panic("GICv3: Number of redistributor regions is more than" "%d (Increase MAX_RDIST_COUNT!!)\n", MAX_RDIST_COUNT); -rdist_regs = xzalloc_array(struct rdist_region, gicv3.rdist_count); +rdist_regs = xzalloc_array(struct rdist_region, count); if ( !rdist_regs ) panic("GICv3: Failed to allocate memory for rdist regions\n"); -for ( i = 0; i < gicv3.rdist_count; i++ ) -{ -struct acpi_subtable_header *header; -struct acpi_madt_generic_redistributor *gic_rdist; - -header = acpi_table_get_entry_madt(ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR, - i); -if ( !header ) -panic("GICv3: Can't get GICR entry"); - -gic_rdist = - container_of(header, struct acpi_madt_generic_redistributor, header); -rdist_regs[i].base = gic_rdist->base_address; -rdist_regs[i].size = gic_rdist->length; -} +gicv3.rdist_regions = rdist_regs; + +/* Parse always-on power domain Re-distributor entries */ +count = acpi_parse_entries(ACPI_SIG_MADT, + sizeof(struct acpi_table_madt), + gic_acpi_parse_madt_redistributor, table, + ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR, count); +if ( count <= 0 ) +panic("GICv3: Can't get Redistributor entry"); /* The vGIC code requires the region to be sorted */ sort(rdist_regs, gicv3.rdist_count, sizeof(*rdist_regs), cmp_rdist, NULL); -gicv3.rdist_regions= rdist_regs; - /* Collect CPU base addresses */ count = acpi_parse_entries(ACPI_SIG_MADT, sizeof(struct acpi_table_madt), gic_acpi_parse_madt_cpu, table, -- Qualcomm Technologies, Inc. on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project ___ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
[Xen-devel] [PATCH V2 05/10] xen/arm: vgic: Use dynamic memory allocation for vgic_rdist_region
The number of Re-distributor regions allowed for dom0 is hardcoded to a compile time macro MAX_RDIST_COUNT which is 4. On some systems, especially latest server chips might have more than 4 redistributors. Either we have to increase MAX_RDIST_COUNT to a bigger number or allocate memory based on number of redistributors that are found in MADT table. In the worst case scenario, the macro MAX_RDIST_COUNT should be equal to CONFIG_NR_CPUS in order to support per CPU Redistributors. Increasing MAX_RDIST_COUNT has side effect, it blows 'struct domain' size and hits BUILD_BUG_ON() in domain build code path. struct domain *alloc_domain_struct(void) { struct domain *d; BUILD_BUG_ON(sizeof(*d) > PAGE_SIZE); d = alloc_xenheap_pages(0, 0); if ( d == NULL ) return NULL; ... This patch uses the second approach to fix the BUILD_BUG(). Signed-off-by: Shanker Donthineni <shank...@codeaurora.org> --- Changes since v1: Keep 'struct vgic_rdist_region' definition inside 'struct arch_domain'. xen/arch/arm/vgic-v2.c | 6 ++ xen/arch/arm/vgic-v3.c | 22 +++--- xen/arch/arm/vgic.c | 1 + xen/include/asm-arm/domain.h | 2 +- xen/include/asm-arm/vgic.h | 2 ++ 5 files changed, 29 insertions(+), 4 deletions(-) diff --git a/xen/arch/arm/vgic-v2.c b/xen/arch/arm/vgic-v2.c index 9adb4a9..f5778e6 100644 --- a/xen/arch/arm/vgic-v2.c +++ b/xen/arch/arm/vgic-v2.c @@ -699,9 +699,15 @@ static int vgic_v2_domain_init(struct domain *d) return 0; } +static void vgic_v2_domain_free(struct domain *d) +{ +/* Nothing to be cleanup for this driver */ +} + static const struct vgic_ops vgic_v2_ops = { .vcpu_init = vgic_v2_vcpu_init, .domain_init = vgic_v2_domain_init, +.domain_free = vgic_v2_domain_free, .max_vcpus = 8, }; diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c index b37a7c0..e877e9e 100644 --- a/xen/arch/arm/vgic-v3.c +++ b/xen/arch/arm/vgic-v3.c @@ -1393,7 +1393,19 @@ static int vgic_v3_vcpu_init(struct vcpu *v) static int vgic_v3_domain_init(struct domain *d) { -int i; +struct vgic_rdist_region *rdist_regions; +int rdist_count, i; + +/* Allocate memory for Re-distributor regions */ +rdist_count = is_hardware_domain(d) ? vgic_v3_hw.nr_rdist_regions : + GUEST_GICV3_RDIST_REGIONS; + +rdist_regions = xzalloc_array(struct vgic_rdist_region, rdist_count); +if ( !rdist_regions ) +return -ENOMEM; + +d->arch.vgic.nr_regions = rdist_count; +d->arch.vgic.rdist_regions = rdist_regions; /* * Domain 0 gets the hardware address. @@ -1426,7 +1438,6 @@ static int vgic_v3_domain_init(struct domain *d) first_cpu += size / d->arch.vgic.rdist_stride; } -d->arch.vgic.nr_regions = vgic_v3_hw.nr_rdist_regions; } else { @@ -1435,7 +1446,6 @@ static int vgic_v3_domain_init(struct domain *d) /* XXX: Only one Re-distributor region mapped for the guest */ BUILD_BUG_ON(GUEST_GICV3_RDIST_REGIONS != 1); -d->arch.vgic.nr_regions = GUEST_GICV3_RDIST_REGIONS; d->arch.vgic.rdist_stride = GUEST_GICV3_RDIST_STRIDE; /* The first redistributor should contain enough space for all CPUs */ @@ -1467,9 +1477,15 @@ static int vgic_v3_domain_init(struct domain *d) return 0; } +static void vgic_v3_domain_free(struct domain *d) +{ +xfree(d->arch.vgic.rdist_regions); +} + static const struct vgic_ops v3_ops = { .vcpu_init = vgic_v3_vcpu_init, .domain_init = vgic_v3_domain_init, +.domain_free = vgic_v3_domain_free, .emulate_sysreg = vgic_v3_emulate_sysreg, /* * We use both AFF1 and AFF0 in (v)MPIDR. Thus, the max number of CPU diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c index 3e1c572..5df5f01 100644 --- a/xen/arch/arm/vgic.c +++ b/xen/arch/arm/vgic.c @@ -177,6 +177,7 @@ void domain_vgic_free(struct domain *d) } } +d->arch.vgic.handler->domain_free(d); xfree(d->arch.vgic.shared_irqs); xfree(d->arch.vgic.pending_irqs); xfree(d->arch.vgic.allocated_irqs); diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h index 370cdeb..29346c6 100644 --- a/xen/include/asm-arm/domain.h +++ b/xen/include/asm-arm/domain.h @@ -107,7 +107,7 @@ struct arch_domain paddr_t base; /* Base address */ paddr_t size; /* Size */ unsigned int first_cpu; /* First CPU handled */ -} rdist_regions[MAX_RDIST_COUNT]; +} *rdist_regions; int nr_regions; /* Number of rdist regions */ uint32_t rdist_stride; /* Re-Distributor stride */ #endif diff --git a/xen/include/asm-arm/vgic.h b/xen/include/asm-arm/vgic.h index a2fccc0..fbb763a 100644 --- a/xen/include/asm-arm/vgic.h +++ b/xen/include/asm-arm/vgic.h @@ -128,6 +128,8 @@ struct
[Xen-devel] [PATCH V2 04/10] arm/gic-v3: Parse per-cpu redistributor entry in GICC subtable
The redistributor address can be specified either as part of GICC or GICR subtable depending on the power domain. The current driver doesn't support parsing redistributor entry that is defined in GICC subtable. The GIC CPU subtable entry holds the associated Redistributor base address if it is not on always-on power domain. The per CPU Redistributor size is not defined in ACPI specification. Set it's size to SZ_256K if the GIC hardware is capable of Direct Virtual LPI Injection feature otherwise SZ_128K. This patch adds necessary code to handle both types of Redistributors base addresses. Signed-off-by: Shanker Donthineni <shank...@codeaurora.org> --- Changes since v1: Edited commit text and fixed white spaces. Added a new function for parsing per CPU Redistributor entry. xen/arch/arm/gic-v3.c | 84 ++- xen/include/asm-arm/gic.h | 1 + xen/include/asm-arm/gic_v3_defs.h | 1 + 3 files changed, 77 insertions(+), 9 deletions(-) diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c index 0471fea..3977244 100644 --- a/xen/arch/arm/gic-v3.c +++ b/xen/arch/arm/gic-v3.c @@ -659,6 +659,10 @@ static int __init gicv3_populate_rdist(void) smp_processor_id(), i, ptr); return 0; } + +if ( gicv3.rdist_regions[i].single_rdist ) +break; + if ( gicv3.rdist_stride ) ptr += gicv3.rdist_stride; else @@ -1282,14 +1286,21 @@ static int gicv3_iomem_deny_access(const struct domain *d) } #ifdef CONFIG_ACPI -static void __init gic_acpi_add_rdist_region(u64 base_addr, u32 size) +static void __init +gic_acpi_add_rdist_region(u64 base_addr, u32 size, bool single_rdist) { unsigned int idx = gicv3.rdist_count++; +gicv3.rdist_regions[idx].single_rdist = single_rdist; gicv3.rdist_regions[idx].base = base_addr; gicv3.rdist_regions[idx].size = size; } +static inline bool gic_dist_supports_dvis(void) +{ +return !!(readl_relaxed(GICD + GICD_TYPER) & GICD_TYPER_DVIS); +} + static int gicv3_make_hwdom_madt(const struct domain *d, u32 offset) { struct acpi_subtable_header *header; @@ -1397,6 +1408,42 @@ gic_acpi_parse_madt_distributor(struct acpi_subtable_header *header, } static int __init +gic_acpi_parse_cpu_redistributor(struct acpi_subtable_header *header, + const unsigned long end) +{ +struct acpi_madt_generic_interrupt *processor; +u32 size; + +processor = (struct acpi_madt_generic_interrupt *)header; +if ( BAD_MADT_ENTRY(processor, end) ) +return -EINVAL; + +if ( !processor->gicr_base_address ) +return -EINVAL; + +if ( processor->flags & ACPI_MADT_ENABLED ) +{ +size = gic_dist_supports_dvis() ? 4 * SZ_64K : 2 * SZ_64K; +gic_acpi_add_rdist_region(processor->gicr_base_address, size, true); +} + +return 0; +} + +static int __init +gic_acpi_get_madt_cpu_num(struct acpi_subtable_header *header, +const unsigned long end) +{ +struct acpi_madt_generic_interrupt *cpuif; + +cpuif = (struct acpi_madt_generic_interrupt *)header; +if ( BAD_MADT_ENTRY(cpuif, end) || !cpuif->gicr_base_address ) +return -EINVAL; + +return 0; +} + +static int __init gic_acpi_parse_madt_redistributor(struct acpi_subtable_header *header, const unsigned long end) { @@ -1409,7 +1456,7 @@ gic_acpi_parse_madt_redistributor(struct acpi_subtable_header *header, if ( !rdist->base_address || !rdist->length ) return -EINVAL; -gic_acpi_add_rdist_region(rdist->base_address, rdist->length); +gic_acpi_add_rdist_region(rdist->base_address, rdist->length, false); return 0; } @@ -1428,6 +1475,7 @@ static void __init gicv3_acpi_init(void) { struct acpi_table_header *table; struct rdist_region *rdist_regs; +bool gicr_table = true; acpi_status status; int count; @@ -1457,8 +1505,18 @@ static void __init gicv3_acpi_init(void) count = acpi_parse_entries(ACPI_SIG_MADT, sizeof(struct acpi_table_madt), gic_acpi_get_madt_redistributor_num, table, ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR, 0); -if ( count <= 0 ) -panic("GICv3: No valid GICR entries exists"); + +/* Count the total number of CPU interface entries */ +if (count <= 0) { +count = acpi_parse_entries(ACPI_SIG_MADT, + sizeof(struct acpi_table_madt), + gic_acpi_get_madt_cpu_num, + table, ACPI_MADT_TYPE_GENERIC_INTERRUPT, 0); +if (count <= 0) +panic("GICv3: No valid GICR entries exists"); + +gicr_table = false; +} if ( count > MAX_RDIST
[Xen-devel] [PATCH V2 09/10] xen/arm: io: Use binary search for mmio handler lookup
As the number of I/O handlers increase, the overhead associated with linear lookup also increases. The system might have maximum of 144 (assuming CONFIG_NR_CPUS=128) mmio handlers. In worst case scenario, it would require 144 iterations for finding a matching handler. Now it is time for us to change from linear (complexity O(n)) to a binary search (complexity O(log n) for reducing mmio handler lookup overhead. Signed-off-by: Shanker Donthineni <shank...@codeaurora.org> --- xen/arch/arm/io.c | 50 +++--- 1 file changed, 39 insertions(+), 11 deletions(-) diff --git a/xen/arch/arm/io.c b/xen/arch/arm/io.c index a5b2c2d..abf49fb 100644 --- a/xen/arch/arm/io.c +++ b/xen/arch/arm/io.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -70,23 +71,38 @@ static int handle_write(const struct mmio_handler *handler, struct vcpu *v, handler->priv); } -int handle_mmio(mmio_info_t *info) +const struct mmio_handler *find_mmio_handler(struct vcpu *v, paddr_t addr) { -struct vcpu *v = current; -int i; -const struct mmio_handler *handler = NULL; const struct vmmio *vmmio = >domain->arch.vmmio; +const struct mmio_handler *handler = vmmio->handlers; +unsigned int eidx = vmmio->num_entries; +unsigned int midx = eidx / 2; +unsigned int sidx = 0; -for ( i = 0; i < vmmio->num_entries; i++ ) +/* Do binary search for matching mmio handler */ +while ( sidx != midx ) { -handler = >handlers[i]; - -if ( (info->gpa >= handler->addr) && - (info->gpa < (handler->addr + handler->size)) ) -break; +if ( addr < handler[midx].addr ) +eidx = midx; +else +sidx = midx; +midx = sidx + (eidx - sidx) / 2; } -if ( i == vmmio->num_entries ) +if ( (addr >= handler[sidx].addr) && + (addr < (handler[sidx].addr + handler[sidx].size)) ) +return handler + sidx; + +return NULL; +} + +int handle_mmio(mmio_info_t *info) +{ +const struct mmio_handler *handler; +struct vcpu *v = current; + +handler = find_mmio_handler(v, info->gpa); +if ( !handler ) return 0; if ( info->dabt.write ) @@ -95,6 +111,14 @@ int handle_mmio(mmio_info_t *info) return handle_read(handler, v, info); } +static int cmp_mmio_handler(const void *key, const void *elem) +{ +const struct mmio_handler *handler0 = key; +const struct mmio_handler *handler1 = elem; + +return (handler0->addr < handler1->addr) ? -1 : 0; +} + void register_mmio_handler(struct domain *d, const struct mmio_handler_ops *ops, paddr_t addr, paddr_t size, void *priv) @@ -122,6 +146,10 @@ void register_mmio_handler(struct domain *d, vmmio->num_entries++; +/* Sort mmio handlers in ascending order based on base address */ +sort(vmmio->handlers, vmmio->num_entries, sizeof(struct mmio_handler), + cmp_mmio_handler, NULL); + spin_unlock(>lock); } -- Qualcomm Technologies, Inc. on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project ___ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
[Xen-devel] [PATCH V2 06/10] arm/gic-v3: Remove an unused macro MAX_RDIST_COUNT
The macro MAX_RDIST_COUNT is not being used after converting code to handle number of redistributor dynamically. So remove it from header file and the two other panic() messages that are not valid anymore. Signed-off-by: Shanker Donthineni <shank...@codeaurora.org> --- xen/arch/arm/gic-v3.c | 8 xen/include/asm-arm/gic.h | 1 - 2 files changed, 9 deletions(-) diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c index 3977244..87f4ecf 100644 --- a/xen/arch/arm/gic-v3.c +++ b/xen/arch/arm/gic-v3.c @@ -1200,10 +1200,6 @@ static void __init gicv3_dt_init(void) _count) ) gicv3.rdist_count = 1; -if ( gicv3.rdist_count > MAX_RDIST_COUNT ) -panic("GICv3: Number of redistributor regions is more than" - "%d (Increase MAX_RDIST_COUNT!!)\n", MAX_RDIST_COUNT); - rdist_regs = xzalloc_array(struct rdist_region, gicv3.rdist_count); if ( !rdist_regs ) panic("GICv3: Failed to allocate memory for rdist regions\n"); @@ -1518,10 +1514,6 @@ static void __init gicv3_acpi_init(void) gicr_table = false; } -if ( count > MAX_RDIST_COUNT ) -panic("GICv3: Number of redistributor regions is more than" - "%d (Increase MAX_RDIST_COUNT!!)\n", MAX_RDIST_COUNT); - rdist_regs = xzalloc_array(struct rdist_region, count); if ( !rdist_regs ) panic("GICv3: Failed to allocate memory for rdist regions\n"); diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h index fedf1fa..db7b2d0 100644 --- a/xen/include/asm-arm/gic.h +++ b/xen/include/asm-arm/gic.h @@ -20,7 +20,6 @@ #define NR_GIC_LOCAL_IRQS NR_LOCAL_IRQS #define NR_GIC_SGI 16 -#define MAX_RDIST_COUNT4 #define GICD_CTLR (0x000) #define GICD_TYPER (0x004) -- Qualcomm Technologies, Inc. on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project ___ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
[Xen-devel] [PATCH V2 08/10] arm/io: Use separate memory allocation for mmio handlers
The number of mmio handlers are limited to a compile time macro MAX_IO_HANDLER which is 16. This number is not at all sufficient to support per CPU distributor regions. Either it needs to be increased to a bigger number, at least CONFIG_NR_CPUS+16, or allocate a separate memory for mmio handlers dynamically during domain build. This patch uses the dynamic allocation strategy to reduce memory footprint for 'struct domain' instead of static allocation. Signed-off-by: Shanker Donthineni <shank...@codeaurora.org> --- xen/arch/arm/domain.c | 6 -- xen/arch/arm/io.c | 14 -- xen/include/asm-arm/mmio.h | 6 -- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c index 1365b4a..4010ff2 100644 --- a/xen/arch/arm/domain.c +++ b/xen/arch/arm/domain.c @@ -527,7 +527,7 @@ void vcpu_destroy(struct vcpu *v) int arch_domain_create(struct domain *d, unsigned int domcr_flags, struct xen_arch_domainconfig *config) { -int rc; +int rc, count; d->arch.relmem = RELMEM_not_started; @@ -550,7 +550,8 @@ int arch_domain_create(struct domain *d, unsigned int domcr_flags, share_xen_page_with_guest( virt_to_page(d->shared_info), d, XENSHARE_writable); -if ( (rc = domain_io_init(d)) != 0 ) +count = MAX_IO_HANDLER; +if ( (rc = domain_io_init(d, count)) != 0 ) goto fail; if ( (rc = p2m_alloc_table(d)) != 0 ) @@ -644,6 +645,7 @@ void arch_domain_destroy(struct domain *d) free_xenheap_pages(d->arch.efi_acpi_table, get_order_from_bytes(d->arch.efi_acpi_len)); #endif +domain_io_free(d); } void arch_domain_shutdown(struct domain *d) diff --git a/xen/arch/arm/io.c b/xen/arch/arm/io.c index 0156755..a5b2c2d 100644 --- a/xen/arch/arm/io.c +++ b/xen/arch/arm/io.c @@ -102,7 +102,7 @@ void register_mmio_handler(struct domain *d, struct vmmio *vmmio = >arch.vmmio; struct mmio_handler *handler; -BUG_ON(vmmio->num_entries >= MAX_IO_HANDLER); +BUG_ON(vmmio->num_entries >= vmmio->max_num_entries); spin_lock(>lock); @@ -125,14 +125,24 @@ void register_mmio_handler(struct domain *d, spin_unlock(>lock); } -int domain_io_init(struct domain *d) +int domain_io_init(struct domain *d, int max_count) { spin_lock_init(>arch.vmmio.lock); d->arch.vmmio.num_entries = 0; + d->arch.vmmio.max_num_entries = max_count; + d->arch.vmmio.handlers = xzalloc_array(struct mmio_handler, max_count); + if ( !d->arch.vmmio.handlers ) + return -ENOMEM; + return 0; } +void domain_io_free(struct domain *d) +{ +xfree(d->arch.vmmio.handlers); +} + /* * Local variables: * mode: C diff --git a/xen/include/asm-arm/mmio.h b/xen/include/asm-arm/mmio.h index da1cc2e..276b263 100644 --- a/xen/include/asm-arm/mmio.h +++ b/xen/include/asm-arm/mmio.h @@ -51,15 +51,17 @@ struct mmio_handler { struct vmmio { int num_entries; +int max_num_entries; spinlock_t lock; -struct mmio_handler handlers[MAX_IO_HANDLER]; +struct mmio_handler *handlers; }; extern int handle_mmio(mmio_info_t *info); void register_mmio_handler(struct domain *d, const struct mmio_handler_ops *ops, paddr_t addr, paddr_t size, void *priv); -int domain_io_init(struct domain *d); +int domain_io_init(struct domain *d, int max_count); +void domain_io_free(struct domain *d); #endif /* __ASM_ARM_MMIO_H__ */ -- Qualcomm Technologies, Inc. on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project ___ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
[Xen-devel] [PATCH V2 01/10] arm/gic-v3: Fix bug in function cmp_rdist()
The cmp_rdist() is always returning value zero irrespective of the input Redistributor base addresses. Both the local variables 'l' and 'r' are pointing to the first argument 'a' causing the logical expression 'l->base < r->base' always evaluated as false which is wrong. Signed-off-by: Shanker Donthineni <shank...@codeaurora.org> --- xen/arch/arm/gic-v3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c index 8d3f149..b89c608 100644 --- a/xen/arch/arm/gic-v3.c +++ b/xen/arch/arm/gic-v3.c @@ -1133,7 +1133,7 @@ static const hw_irq_controller gicv3_guest_irq_type = { static int __init cmp_rdist(const void *a, const void *b) { -const struct rdist_region *l = a, *r = a; +const struct rdist_region *l = a, *r = b; /* We assume that re-distributor regions can never overlap */ return ( l->base < r->base) ? -1 : 0; -- Qualcomm Technologies, Inc. on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project ___ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
[Xen-devel] [PATCH V2 02/10] arm/gic-v3: Do early GICD ioremap and clean up
For ACPI based XEN boot, the GICD region needs to be accessed inside the function gicv3_acpi_init() in later pacth. There is a duplicate panic() message, one in the DTS probe and second one in the ACPI probe path. For these two reasons, move the code that validates the GICD base address and does the region ioremap to a separate function. The following pacth accesses the GICD region inside gicv3_acpi_init() for finding per CPU Redistributor size. Signed-off-by: Shanker Donthineni <shank...@codeaurora.org> --- Changes sicne v1: Edited commit text. xen/arch/arm/gic-v3.c | 23 +-- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c index b89c608..542c4f3 100644 --- a/xen/arch/arm/gic-v3.c +++ b/xen/arch/arm/gic-v3.c @@ -1169,6 +1169,17 @@ static void __init gicv3_init_v2(void) vgic_v2_setup_hw(dbase, cbase, csize, vbase, 0); } +static void __init gicv3_ioremap_distributor(paddr_t dist_paddr) +{ +if ( dist_paddr & ~PAGE_MASK ) +panic("GICv3: Found unaligned distributor address %"PRIpaddr"", + dbase); + +gicv3.map_dbase = ioremap_nocache(dist_paddr, SZ_64K); +if ( !gicv3.map_dbase ) +panic("GICv3: Failed to ioremap for GIC distributor\n"); +} + static void __init gicv3_dt_init(void) { struct rdist_region *rdist_regs; @@ -1179,9 +1190,7 @@ static void __init gicv3_dt_init(void) if ( res ) panic("GICv3: Cannot find a valid distributor address"); -if ( (dbase & ~PAGE_MASK) ) -panic("GICv3: Found unaligned distributor address %"PRIpaddr"", - dbase); +gicv3_ioremap_distributor(dbase); if ( !dt_property_read_u32(node, "#redistributor-regions", _count) ) @@ -1415,9 +1424,7 @@ static void __init gicv3_acpi_init(void) if ( count <= 0 ) panic("GICv3: No valid GICD entries exists"); -if ( (dbase & ~PAGE_MASK) ) -panic("GICv3: Found unaligned distributor address %"PRIpaddr"", - dbase); +gicv3_ioremap_distributor(dbase); /* Get number of redistributor */ count = acpi_parse_entries(ACPI_SIG_MADT, sizeof(struct acpi_table_madt), @@ -1491,10 +1498,6 @@ static int __init gicv3_init(void) else gicv3_acpi_init(); -gicv3.map_dbase = ioremap_nocache(dbase, SZ_64K); -if ( !gicv3.map_dbase ) -panic("GICv3: Failed to ioremap for GIC distributor\n"); - reg = readl_relaxed(GICD + GICD_PIDR2) & GIC_PIDR2_ARCH_MASK; if ( reg != GIC_PIDR2_ARCH_GICv3 && reg != GIC_PIDR2_ARCH_GICv4 ) panic("GICv3: no distributor detected\n"); -- Qualcomm Technologies, Inc. on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project ___ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
Re: [Xen-devel] [PATCH 6/8] arm: vgic: Split vgic_domain_init() functionality into two functions
Hi Julien, On 06/21/2016 09:48 AM, Julien Grall wrote: On 21/06/16 15:36, Shanker Donthineni wrote: On 06/21/2016 05:49 AM, Julien Grall wrote: Hello Shanker, On 19/06/16 00:45, Shanker Donthineni wrote: Split code that installs mmio handlers for GICD and Re-distributor regions to a new function. The intension of this separation is to defer steps that registers vgic_v2/v3 mmio handlers. Looking at this patch and the follow-up ones, I don't think this is the right way to go. You differ the registration of the IO handlers just because you are unable to find the size of the handlers array. Is there any better approach? Possibly using a different data structure. I am wondering if the array for the handlers is the best solution here. On another side, it would be possible to find the maximum of handlers before hand. The purpose of this change is to limit size of 'struct domain' less than PAGE_SIZE. I can think of second approach split vgic_init() into two stages, one for vgic registration and the second one for vgic_init(). This also requires a few lines of code changes to vgic_v2/v3_init() and vgic_init(). I am fine as long as vgic_register_ does not do more than counting the number of IO handlers. You could re-use vgic_init_v{2,3} for this purpose. The way we are doing vgic_init() initialization has to be cleaned-up and rearrange a few lines of code for retrieving the number mmio handlers that are required dom0/domU domain. Regards, -- Shanker Donthineni Qualcomm Technologies, Inc. on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project ___ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
Re: [Xen-devel] [PATCH 6/8] arm: vgic: Split vgic_domain_init() functionality into two functions
On 06/21/2016 05:49 AM, Julien Grall wrote: Hello Shanker, On 19/06/16 00:45, Shanker Donthineni wrote: Split code that installs mmio handlers for GICD and Re-distributor regions to a new function. The intension of this separation is to defer steps that registers vgic_v2/v3 mmio handlers. Looking at this patch and the follow-up ones, I don't think this is the right way to go. You differ the registration of the IO handlers just because you are unable to find the size of the handlers array. Is there any better approach? I am wondering if the array for the handlers is the best solution here. On another side, it would be possible to find the maximum of handlers before hand. The purpose of this change is to limit size of 'struct domain' less than PAGE_SIZE. I can think of second approach split vgic_init() into two stages, one for vgic registration and the second one for vgic_init(). This also requires a few lines of code changes to vgic_v2/v3_init() and vgic_init(). int arch_domain_create(struct domain *d, unsigned int domcr_flags, struct xen_arch_domainconfig *config) ... domain_vgic_register(d)); domain_io_init(d, mmio_count); domain_vgic_init(d, config->nr_spis)); diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c index 5df5f01..5b39e0d 100644 --- a/xen/arch/arm/vgic.c +++ b/xen/arch/arm/vgic.c @@ -151,9 +151,12 @@ int domain_vgic_init(struct domain *d, unsigned int nr_spis) for ( i = 0; i < NR_GIC_SGI; i++ ) set_bit(i, d->arch.vgic.allocated_irqs); +d->arch.vgic.handler->domain_register_mmio(d); + return 0; } + Spurious change. void register_vgic_ops(struct domain *d, const struct vgic_ops *ops) { d->arch.vgic.handler = ops; diff --git a/xen/include/asm-arm/vgic.h b/xen/include/asm-arm/vgic.h index fbb763a..8fe65b4 100644 --- a/xen/include/asm-arm/vgic.h +++ b/xen/include/asm-arm/vgic.h @@ -132,6 +132,8 @@ struct vgic_ops { void (*domain_free)(struct domain *d); /* vGIC sysreg emulation */ int (*emulate_sysreg)(struct cpu_user_regs *regs, union hsr hsr); +/* Register mmio handlers */ +void (*domain_register_mmio)(struct domain *d); /* Maximum number of vCPU supported */ const unsigned int max_vcpus; }; Regards, -- Shanker Donthineni Qualcomm Technologies, Inc. on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project ___ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
Re: [Xen-devel] [PATCH 0/8] Add support for parsing per CPU Redistributor entry
On 06/21/2016 08:50 AM, Julien Grall wrote: On 21/06/16 14:37, Shanker Donthineni wrote: On 06/21/2016 04:28 AM, Julien Grall wrote: On 19/06/16 00:45, Shanker Donthineni wrote: The current driver doesn't support parsing Redistributor entries that are described in the MADT GICC table. Not all the GIC implementors places the Redistributor regions in the always-on power domain. On systems, the UEFI firmware should describe Redistributor base address in the associated GIC CPU Interface (GICC) instead of GIC Redistributor (GICR) table. The maximum number of mmio handlers and struct vgic_rdist_region that holds Redistributor addresses are allocated through a static array with hardcoded size. I don't think this is the right approach and is not scalable for implementing features like this. I have decided to convert static to dynamic allocation based on comments from the below link. https://patchwork.kernel.org/patch/9163435/ You addressed only one part of my comment. This series increases the number of I/O handlers but the lookup is still linear (see handle_mmio in arch/arm/io.c). I agree with you, we need to bring binary search algorithm similar to Linux KVM code. I want to keep it this change outside of this patchset. This should be a prerequisite of this series then, not a follow-up. For the functionality and correctness purpose we don't need this change immediately. We are not able to boot XEN on Qualcomm Technologies because of not supporting GICC table parsing for GICR address. I am okay to wait for my patchset if someone adding bseach look ups for mmio handlers. Regards, -- Shanker Donthineni Qualcomm Technologies, Inc. on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project ___ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
Re: [Xen-devel] [PATCH 2/8] arm/gic-v3: Fold GICR subtable parsing into a new function
On 06/21/2016 05:17 AM, Julien Grall wrote: Hello Shanker, On 19/06/16 00:45, Shanker Donthineni wrote: Add a new function for parsing GICR subtable and move the code that is specific to GICR table to new function without changing the function gicv3_acpi_init() behavior. Signed-off-by: Shanker Donthineni <shank...@codeaurora.org> --- xen/arch/arm/gic-v3.c | 64 +-- 1 file changed, 42 insertions(+), 22 deletions(-) diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c index ab1f380..af12ebc 100644 --- a/xen/arch/arm/gic-v3.c +++ b/xen/arch/arm/gic-v3.c @@ -1387,6 +1387,36 @@ gic_acpi_parse_madt_distributor(struct acpi_subtable_header *header, return 0; } + +static int __init +gic_acpi_parse_madt_redistributor(struct acpi_subtable_header *header, + const unsigned long end) +{ +struct acpi_madt_generic_redistributor *rdist; +struct rdist_region *region; + +region = gicv3.rdist_regions + gicv3.rdist_count; +rdist = (struct acpi_madt_generic_redistributor *)header; +if ( BAD_MADT_ENTRY(rdist, end) ) +return -EINVAL; + +if ( !rdist->base_address || !rdist->length ) +return -EINVAL; + +region->base = rdist->base_address; +region->size = rdist->length; + +region->map_base = ioremap_nocache(region->base, region->size); In the commit message you said there is no functional change, however the remapping is not part of gicv3_acpi_init. So why did you add this line here? Thanks for catching coding bug, it was my mistake and this code should not be here. +if ( !region->map_base ) +{ +printk("Unable to map GICR registers\n"); +return -ENOMEM; +} +gicv3.rdist_count++; + +return 0; +} + [...] Regards, -- Shanker Donthineni Qualcomm Technologies, Inc. on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project ___ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
Re: [Xen-devel] [PATCH 3/8] arm/gic-v3: Parse per-cpu redistributor entry in GICC subtable
On 06/21/2016 05:16 AM, Julien Grall wrote: Hello Shanker, On 19/06/16 00:45, Shanker Donthineni wrote: The redistributor address can be specified either as part of GICC or GICR subtable depending on the power domain. The current driver doesn't support parsing redistributor entry that is defined in GICC subtable. The GIC CPU subtable entry holds the associated Redistributor base address if it is not on always-on power domain. This patch adds necessary code to handle both types of Redistributors base addresses. Signed-off-by: Shanker Donthineni <shank...@codeaurora.org> --- xen/arch/arm/gic-v3.c | 97 --- xen/include/asm-arm/gic.h | 2 + xen/include/asm-arm/gic_v3_defs.h | 1 + 3 files changed, 83 insertions(+), 17 deletions(-) diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c index af12ebc..42cf848 100644 --- a/xen/arch/arm/gic-v3.c +++ b/xen/arch/arm/gic-v3.c @@ -659,6 +659,10 @@ static int __init gicv3_populate_rdist(void) smp_processor_id(), i, ptr); return 0; } + +if ( gicv3.rdist_regions[i].single_rdist ) +break; + if ( gicv3.rdist_stride ) ptr += gicv3.rdist_stride; else @@ -1282,6 +1286,11 @@ static int gicv3_iomem_deny_access(const struct domain *d) } #ifdef CONFIG_ACPI +static bool gic_dist_supports_dvis(void) static inline and please use bool_t here. Still learning XEN coding style, I'll fix it. +{ +return !!(readl_relaxed(GICD + GICD_TYPER) & GICD_TYPER_DVIS); +} + static int gicv3_make_hwdom_madt(const struct domain *d, u32 offset) { struct acpi_subtable_header *header; @@ -1393,18 +1402,39 @@ gic_acpi_parse_madt_redistributor(struct acpi_subtable_header *header, const unsigned long end) { struct acpi_madt_generic_redistributor *rdist; +struct acpi_madt_generic_interrupt *processor; struct rdist_region *region; region = gicv3.rdist_regions + gicv3.rdist_count; -rdist = (struct acpi_madt_generic_redistributor *)header; -if ( BAD_MADT_ENTRY(rdist, end) ) -return -EINVAL; +if ( header->type == ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR ) +{ +rdist = (struct acpi_madt_generic_redistributor *)header; +if ( BAD_MADT_ENTRY(rdist, end) ) +return -EINVAL; -if ( !rdist->base_address || !rdist->length ) -return -EINVAL; +if ( !rdist->base_address || !rdist->length ) +return -EINVAL; + +region->base = rdist->base_address; +region->size = rdist->length; +} +else if ( header->type == ACPI_MADT_TYPE_GENERIC_INTERRUPT ) +{ Parsing the GICC and the redistributor is quite different. I would much prefer a function for parsing each table and an helper to add a new redistributor. I'll do. +processor = (struct acpi_madt_generic_interrupt *)header; +if ( BAD_MADT_ENTRY(processor, end) ) +return -EINVAL; + +if ( !(processor->flags & ACPI_MADT_ENABLED) ) +return 0; + +if ( !processor->gicr_base_address ) +return -EINVAL; + +region->base = processor->gicr_base_address; +region->size = gic_dist_supports_dvis() ? SZ_256K : SZ_128K; Please explain in the commit message how you find the size. I would also prefer if you use (4 x SZ_64K) and (2 * SZ_64K) as we do in populate_rdist. +region->single_rdist = true; The indentation looks wrong. + } -region->base = rdist->base_address; -region->size = rdist->length; region->map_base = ioremap_nocache(region->base, region->size); if ( !region->map_base ) @@ -1412,6 +1442,7 @@ gic_acpi_parse_madt_redistributor(struct acpi_subtable_header *header, printk("Unable to map GICR registers\n"); return -ENOMEM; } + Spurious change. gicv3.rdist_count++; return 0; @@ -1421,9 +1452,22 @@ static int __init gic_acpi_get_madt_redistributor_num(struct acpi_subtable_header *header, const unsigned long end) { -/* Nothing to do here since it only wants to get the number of GIC - * redistributors. - */ +struct acpi_madt_generic_redistributor *rdist; +struct acpi_madt_generic_interrupt *cpuif; + +if ( header->type == ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR ) +{ + rdist = (struct acpi_madt_generic_redistributor *)header; + if ( BAD_MADT_ENTRY(rdist, end) || !rdist->base_address ) + return -EINVAL; +} +else if ( header->type == ACPI_MADT_TYPE_GENERIC_INTERRUPT ) +{ + cpuif = (struct acpi_madt_generic_interrupt *)header; + if ( BAD_MADT_ENTRY(cpuif, end) || !cpuif->gicr_base_address ) + return -EINVAL; +} + Ditto for the parsing.
Re: [Xen-devel] [PATCH 0/8] Add support for parsing per CPU Redistributor entry
On 06/21/2016 04:28 AM, Julien Grall wrote: Hello Shanker, On 19/06/16 00:45, Shanker Donthineni wrote: The current driver doesn't support parsing Redistributor entries that are described in the MADT GICC table. Not all the GIC implementors places the Redistributor regions in the always-on power domain. On systems, the UEFI firmware should describe Redistributor base address in the associated GIC CPU Interface (GICC) instead of GIC Redistributor (GICR) table. The maximum number of mmio handlers and struct vgic_rdist_region that holds Redistributor addresses are allocated through a static array with hardcoded size. I don't think this is the right approach and is not scalable for implementing features like this. I have decided to convert static to dynamic allocation based on comments from the below link. https://patchwork.kernel.org/patch/9163435/ You addressed only one part of my comment. This series increases the number of I/O handlers but the lookup is still linear (see handle_mmio in arch/arm/io.c). I agree with you, we need to bring binary search algorithm similar to Linux KVM code. I want to keep it this change outside of this patchset. After this series, the maximum number of I/O handlers is 160. So in the worst case, we have to do 160 iterations before finding an handler or concluding the I/O cannot be emulated. Regards, -- Shanker Donthineni Qualcomm Technologies, Inc. on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project ___ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
[Xen-devel] [PATCH 2/8] arm/gic-v3: Fold GICR subtable parsing into a new function
Add a new function for parsing GICR subtable and move the code that is specific to GICR table to new function without changing the function gicv3_acpi_init() behavior. Signed-off-by: Shanker Donthineni <shank...@codeaurora.org> --- xen/arch/arm/gic-v3.c | 64 +-- 1 file changed, 42 insertions(+), 22 deletions(-) diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c index ab1f380..af12ebc 100644 --- a/xen/arch/arm/gic-v3.c +++ b/xen/arch/arm/gic-v3.c @@ -1387,6 +1387,36 @@ gic_acpi_parse_madt_distributor(struct acpi_subtable_header *header, return 0; } + +static int __init +gic_acpi_parse_madt_redistributor(struct acpi_subtable_header *header, + const unsigned long end) +{ +struct acpi_madt_generic_redistributor *rdist; +struct rdist_region *region; + +region = gicv3.rdist_regions + gicv3.rdist_count; +rdist = (struct acpi_madt_generic_redistributor *)header; +if ( BAD_MADT_ENTRY(rdist, end) ) +return -EINVAL; + +if ( !rdist->base_address || !rdist->length ) +return -EINVAL; + +region->base = rdist->base_address; +region->size = rdist->length; + +region->map_base = ioremap_nocache(region->base, region->size); +if ( !region->map_base ) +{ +printk("Unable to map GICR registers\n"); +return -ENOMEM; +} +gicv3.rdist_count++; + +return 0; +} + static int __init gic_acpi_get_madt_redistributor_num(struct acpi_subtable_header *header, const unsigned long end) @@ -1402,7 +1432,7 @@ static void __init gicv3_acpi_init(void) struct acpi_table_header *table; struct rdist_region *rdist_regs; acpi_status status; -int count, i; +int count; status = acpi_get_table(ACPI_SIG_MADT, 0, ); @@ -1433,37 +1463,27 @@ static void __init gicv3_acpi_init(void) if ( count <= 0 ) panic("GICv3: No valid GICR entries exists"); -gicv3.rdist_count = count; - -if ( gicv3.rdist_count > MAX_RDIST_COUNT ) +if ( count > MAX_RDIST_COUNT ) panic("GICv3: Number of redistributor regions is more than" "%d (Increase MAX_RDIST_COUNT!!)\n", MAX_RDIST_COUNT); -rdist_regs = xzalloc_array(struct rdist_region, gicv3.rdist_count); +rdist_regs = xzalloc_array(struct rdist_region, count); if ( !rdist_regs ) panic("GICv3: Failed to allocate memory for rdist regions\n"); -for ( i = 0; i < gicv3.rdist_count; i++ ) -{ -struct acpi_subtable_header *header; -struct acpi_madt_generic_redistributor *gic_rdist; - -header = acpi_table_get_entry_madt(ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR, - i); -if ( !header ) -panic("GICv3: Can't get GICR entry"); - -gic_rdist = - container_of(header, struct acpi_madt_generic_redistributor, header); -rdist_regs[i].base = gic_rdist->base_address; -rdist_regs[i].size = gic_rdist->length; -} +gicv3.rdist_regions = rdist_regs; + +/* Parse always-on power domain Re-distributor entries */ +count = acpi_parse_entries(ACPI_SIG_MADT, + sizeof(struct acpi_table_madt), + gic_acpi_parse_madt_redistributor, table, + ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR, count); +if ( count <= 0 ) +panic("GICv3: Can't get Redistributor entry"); /* The vGIC code requires the region to be sorted */ sort(rdist_regs, gicv3.rdist_count, sizeof(*rdist_regs), cmp_rdist, NULL); -gicv3.rdist_regions= rdist_regs; - /* Collect CPU base addresses */ count = acpi_parse_entries(ACPI_SIG_MADT, sizeof(struct acpi_table_madt), gic_acpi_parse_madt_cpu, table, -- Qualcomm Technologies, Inc. on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project ___ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
[Xen-devel] [PATCH 6/8] arm: vgic: Split vgic_domain_init() functionality into two functions
Split code that installs mmio handlers for GICD and Re-distributor regions to a new function. The intension of this separation is to defer steps that registers vgic_v2/v3 mmio handlers. Signed-off-by: Shanker Donthineni <shank...@codeaurora.org> --- xen/arch/arm/vgic-v2.c | 10 +++--- xen/arch/arm/vgic-v3.c | 40 +++- xen/arch/arm/vgic.c| 3 +++ xen/include/asm-arm/vgic.h | 2 ++ 4 files changed, 35 insertions(+), 20 deletions(-) diff --git a/xen/arch/arm/vgic-v2.c b/xen/arch/arm/vgic-v2.c index f5778e6..d42b408 100644 --- a/xen/arch/arm/vgic-v2.c +++ b/xen/arch/arm/vgic-v2.c @@ -645,6 +645,12 @@ static int vgic_v2_vcpu_init(struct vcpu *v) return 0; } +static void vgic_v2_domain_register_mmio(struct domain *d) +{ +register_mmio_handler(d, _v2_distr_mmio_handler, d->arch.vgic.dbase, + PAGE_SIZE, NULL); +} + static int vgic_v2_domain_init(struct domain *d) { int ret; @@ -693,9 +699,6 @@ static int vgic_v2_domain_init(struct domain *d) if ( ret ) return ret; -register_mmio_handler(d, _v2_distr_mmio_handler, d->arch.vgic.dbase, - PAGE_SIZE, NULL); - return 0; } @@ -708,6 +711,7 @@ static const struct vgic_ops vgic_v2_ops = { .vcpu_init = vgic_v2_vcpu_init, .domain_init = vgic_v2_domain_init, .domain_free = vgic_v2_domain_free, +.domain_register_mmio = vgic_v2_domain_register_mmio, .max_vcpus = 8, }; diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c index e877e9e..3a5aeb6 100644 --- a/xen/arch/arm/vgic-v3.c +++ b/xen/arch/arm/vgic-v3.c @@ -1391,6 +1391,28 @@ static int vgic_v3_vcpu_init(struct vcpu *v) return 0; } +static void vgic_v3_domain_register_mmio(struct domain *d) +{ +int i; + +/* Register mmio handle for the Distributor */ +register_mmio_handler(d, _distr_mmio_handler, d->arch.vgic.dbase, + SZ_64K, NULL); + +/* + * Register mmio handler per contiguous region occupied by the + * redistributors. The handler will take care to choose which + * redistributor is targeted. + */ +for ( i = 0; i < d->arch.vgic.nr_regions; i++ ) +{ +struct vgic_rdist_region *region = >arch.vgic.rdist_regions[i]; + +register_mmio_handler(d, _rdistr_mmio_handler, + region->base, region->size, region); +} +} + static int vgic_v3_domain_init(struct domain *d) { struct vgic_rdist_region *rdist_regions; @@ -1455,23 +1477,6 @@ static int vgic_v3_domain_init(struct domain *d) d->arch.vgic.rdist_regions[0].first_cpu = 0; } -/* Register mmio handle for the Distributor */ -register_mmio_handler(d, _distr_mmio_handler, d->arch.vgic.dbase, - SZ_64K, NULL); - -/* - * Register mmio handler per contiguous region occupied by the - * redistributors. The handler will take care to choose which - * redistributor is targeted. - */ -for ( i = 0; i < d->arch.vgic.nr_regions; i++ ) -{ -struct vgic_rdist_region *region = >arch.vgic.rdist_regions[i]; - -register_mmio_handler(d, _rdistr_mmio_handler, - region->base, region->size, region); -} - d->arch.vgic.ctlr = VGICD_CTLR_DEFAULT; return 0; @@ -1487,6 +1492,7 @@ static const struct vgic_ops v3_ops = { .domain_init = vgic_v3_domain_init, .domain_free = vgic_v3_domain_free, .emulate_sysreg = vgic_v3_emulate_sysreg, +.domain_register_mmio = vgic_v3_domain_register_mmio, /* * We use both AFF1 and AFF0 in (v)MPIDR. Thus, the max number of CPU * that can be supported is up to 4096(==256*16) in theory. diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c index 5df5f01..5b39e0d 100644 --- a/xen/arch/arm/vgic.c +++ b/xen/arch/arm/vgic.c @@ -151,9 +151,12 @@ int domain_vgic_init(struct domain *d, unsigned int nr_spis) for ( i = 0; i < NR_GIC_SGI; i++ ) set_bit(i, d->arch.vgic.allocated_irqs); +d->arch.vgic.handler->domain_register_mmio(d); + return 0; } + void register_vgic_ops(struct domain *d, const struct vgic_ops *ops) { d->arch.vgic.handler = ops; diff --git a/xen/include/asm-arm/vgic.h b/xen/include/asm-arm/vgic.h index fbb763a..8fe65b4 100644 --- a/xen/include/asm-arm/vgic.h +++ b/xen/include/asm-arm/vgic.h @@ -132,6 +132,8 @@ struct vgic_ops { void (*domain_free)(struct domain *d); /* vGIC sysreg emulation */ int (*emulate_sysreg)(struct cpu_user_regs *regs, union hsr hsr); +/* Register mmio handlers */ +void (*domain_register_mmio)(struct domain *d); /* Maximum number of vCPU supported */ const unsigned int max_vcpus; }; -- Qualcomm Technologies, Inc. on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a m
[Xen-devel] [PATCH 4/8] xen/arm: vgic: Use dynamic memory allocation for vgic_rdist_region
The number of Re-distributor regions allowed for dom0 is hardcoded to a compile time macro MAX_RDIST_COUNT which is 4. On some systems, especially latest server chips might have more than 4 redistributors. Either we have to increase MAX_RDIST_COUNT to a bigger number or allocate memory based on number of redistributors that are found in MADT table. In the worst case scenario, the macro MAX_RDIST_COUNT should be equal to CONFIG_NR_CPUS in order to support per CPU Redistributors. Increasing MAX_RDIST_COUNT has side effect, it blows 'struct domain' size and hits BUILD_BUG_ON() in domain build code path. struct domain *alloc_domain_struct(void) { struct domain *d; BUILD_BUG_ON(sizeof(*d) > PAGE_SIZE); d = alloc_xenheap_pages(0, 0); if ( d == NULL ) return NULL; ... This patch uses the second approach to fix the BUILD_BUG(). Signed-off-by: Shanker Donthineni <shank...@codeaurora.org> --- xen/arch/arm/vgic-v2.c | 6 ++ xen/arch/arm/vgic-v3.c | 22 +++--- xen/arch/arm/vgic.c | 1 + xen/include/asm-arm/domain.h | 12 +++- xen/include/asm-arm/vgic.h | 2 ++ 5 files changed, 35 insertions(+), 8 deletions(-) diff --git a/xen/arch/arm/vgic-v2.c b/xen/arch/arm/vgic-v2.c index 9adb4a9..f5778e6 100644 --- a/xen/arch/arm/vgic-v2.c +++ b/xen/arch/arm/vgic-v2.c @@ -699,9 +699,15 @@ static int vgic_v2_domain_init(struct domain *d) return 0; } +static void vgic_v2_domain_free(struct domain *d) +{ +/* Nothing to be cleanup for this driver */ +} + static const struct vgic_ops vgic_v2_ops = { .vcpu_init = vgic_v2_vcpu_init, .domain_init = vgic_v2_domain_init, +.domain_free = vgic_v2_domain_free, .max_vcpus = 8, }; diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c index b37a7c0..e877e9e 100644 --- a/xen/arch/arm/vgic-v3.c +++ b/xen/arch/arm/vgic-v3.c @@ -1393,7 +1393,19 @@ static int vgic_v3_vcpu_init(struct vcpu *v) static int vgic_v3_domain_init(struct domain *d) { -int i; +struct vgic_rdist_region *rdist_regions; +int rdist_count, i; + +/* Allocate memory for Re-distributor regions */ +rdist_count = is_hardware_domain(d) ? vgic_v3_hw.nr_rdist_regions : + GUEST_GICV3_RDIST_REGIONS; + +rdist_regions = xzalloc_array(struct vgic_rdist_region, rdist_count); +if ( !rdist_regions ) +return -ENOMEM; + +d->arch.vgic.nr_regions = rdist_count; +d->arch.vgic.rdist_regions = rdist_regions; /* * Domain 0 gets the hardware address. @@ -1426,7 +1438,6 @@ static int vgic_v3_domain_init(struct domain *d) first_cpu += size / d->arch.vgic.rdist_stride; } -d->arch.vgic.nr_regions = vgic_v3_hw.nr_rdist_regions; } else { @@ -1435,7 +1446,6 @@ static int vgic_v3_domain_init(struct domain *d) /* XXX: Only one Re-distributor region mapped for the guest */ BUILD_BUG_ON(GUEST_GICV3_RDIST_REGIONS != 1); -d->arch.vgic.nr_regions = GUEST_GICV3_RDIST_REGIONS; d->arch.vgic.rdist_stride = GUEST_GICV3_RDIST_STRIDE; /* The first redistributor should contain enough space for all CPUs */ @@ -1467,9 +1477,15 @@ static int vgic_v3_domain_init(struct domain *d) return 0; } +static void vgic_v3_domain_free(struct domain *d) +{ +xfree(d->arch.vgic.rdist_regions); +} + static const struct vgic_ops v3_ops = { .vcpu_init = vgic_v3_vcpu_init, .domain_init = vgic_v3_domain_init, +.domain_free = vgic_v3_domain_free, .emulate_sysreg = vgic_v3_emulate_sysreg, /* * We use both AFF1 and AFF0 in (v)MPIDR. Thus, the max number of CPU diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c index 3e1c572..5df5f01 100644 --- a/xen/arch/arm/vgic.c +++ b/xen/arch/arm/vgic.c @@ -177,6 +177,7 @@ void domain_vgic_free(struct domain *d) } } +d->arch.vgic.handler->domain_free(d); xfree(d->arch.vgic.shared_irqs); xfree(d->arch.vgic.pending_irqs); xfree(d->arch.vgic.allocated_irqs); diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h index 370cdeb..9492727 100644 --- a/xen/include/asm-arm/domain.h +++ b/xen/include/asm-arm/domain.h @@ -40,6 +40,12 @@ struct vtimer { uint64_t cval; }; +struct vgic_rdist_region { +paddr_t base; /* Base address */ +paddr_t size; /* Size */ +unsigned int first_cpu;/* First CPU handled */ +}; + struct arch_domain { #ifdef CONFIG_ARM_64 @@ -103,11 +109,7 @@ struct arch_domain #ifdef CONFIG_HAS_GICV3 /* GIC V3 addressing */ /* List of contiguous occupied by the redistributors */ -struct vgic_rdist_region { -paddr_t base; /* Base address */ -paddr_t size; /* Size */ -unsigned int first_cpu; /* First CPU handled */ -} rdist_regions[MAX_RD
[Xen-devel] [PATCH 7/8] arm/mmio: Use separate memory allocation for mmio handlers
The number of mmio handlers are limited to a compile time macro MAX_IO_HANDLER which is 16. This number is not at all sufficient to support per CPU distributor regions. Either it needs to be increased to a bigger number, at least CONFIG_NR_CPUS+16, or allocate a separate memory for mmio handlers dynamically during domain build. This patch uses the dynamic allocation strategy to reduce memory footprint for 'struct domain' instead of static allocation. Signed-off-by: Shanker Donthineni <shank...@codeaurora.org> --- xen/arch/arm/domain.c | 6 -- xen/arch/arm/io.c | 14 -- xen/include/asm-arm/mmio.h | 6 -- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c index 1365b4a..4010ff2 100644 --- a/xen/arch/arm/domain.c +++ b/xen/arch/arm/domain.c @@ -527,7 +527,7 @@ void vcpu_destroy(struct vcpu *v) int arch_domain_create(struct domain *d, unsigned int domcr_flags, struct xen_arch_domainconfig *config) { -int rc; +int rc, count; d->arch.relmem = RELMEM_not_started; @@ -550,7 +550,8 @@ int arch_domain_create(struct domain *d, unsigned int domcr_flags, share_xen_page_with_guest( virt_to_page(d->shared_info), d, XENSHARE_writable); -if ( (rc = domain_io_init(d)) != 0 ) +count = MAX_IO_HANDLER; +if ( (rc = domain_io_init(d, count)) != 0 ) goto fail; if ( (rc = p2m_alloc_table(d)) != 0 ) @@ -644,6 +645,7 @@ void arch_domain_destroy(struct domain *d) free_xenheap_pages(d->arch.efi_acpi_table, get_order_from_bytes(d->arch.efi_acpi_len)); #endif +domain_io_free(d); } void arch_domain_shutdown(struct domain *d) diff --git a/xen/arch/arm/io.c b/xen/arch/arm/io.c index 0156755..a5b2c2d 100644 --- a/xen/arch/arm/io.c +++ b/xen/arch/arm/io.c @@ -102,7 +102,7 @@ void register_mmio_handler(struct domain *d, struct vmmio *vmmio = >arch.vmmio; struct mmio_handler *handler; -BUG_ON(vmmio->num_entries >= MAX_IO_HANDLER); +BUG_ON(vmmio->num_entries >= vmmio->max_num_entries); spin_lock(>lock); @@ -125,14 +125,24 @@ void register_mmio_handler(struct domain *d, spin_unlock(>lock); } -int domain_io_init(struct domain *d) +int domain_io_init(struct domain *d, int max_count) { spin_lock_init(>arch.vmmio.lock); d->arch.vmmio.num_entries = 0; + d->arch.vmmio.max_num_entries = max_count; + d->arch.vmmio.handlers = xzalloc_array(struct mmio_handler, max_count); + if ( !d->arch.vmmio.handlers ) + return -ENOMEM; + return 0; } +void domain_io_free(struct domain *d) +{ +xfree(d->arch.vmmio.handlers); +} + /* * Local variables: * mode: C diff --git a/xen/include/asm-arm/mmio.h b/xen/include/asm-arm/mmio.h index da1cc2e..276b263 100644 --- a/xen/include/asm-arm/mmio.h +++ b/xen/include/asm-arm/mmio.h @@ -51,15 +51,17 @@ struct mmio_handler { struct vmmio { int num_entries; +int max_num_entries; spinlock_t lock; -struct mmio_handler handlers[MAX_IO_HANDLER]; +struct mmio_handler *handlers; }; extern int handle_mmio(mmio_info_t *info); void register_mmio_handler(struct domain *d, const struct mmio_handler_ops *ops, paddr_t addr, paddr_t size, void *priv); -int domain_io_init(struct domain *d); +int domain_io_init(struct domain *d, int max_count); +void domain_io_free(struct domain *d); #endif /* __ASM_ARM_MMIO_H__ */ -- Qualcomm Technologies, Inc. on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project ___ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
[Xen-devel] [PATCH 5/8] arm/gic-v3: Remove an unused macro MAX_RDIST_COUNT
The macro MAX_RDIST_COUNT is not being used after converting code to handle number of redistributor dynamically. So remove it from header file and the two other panic() messages that are not valid anymore. Signed-off-by: Shanker Donthineni <shank...@codeaurora.org> --- xen/arch/arm/gic-v3.c | 8 xen/include/asm-arm/gic.h | 1 - 2 files changed, 9 deletions(-) diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c index 42cf848..28c00cf 100644 --- a/xen/arch/arm/gic-v3.c +++ b/xen/arch/arm/gic-v3.c @@ -1200,10 +1200,6 @@ static void __init gicv3_dt_init(void) _count) ) gicv3.rdist_count = 1; -if ( gicv3.rdist_count > MAX_RDIST_COUNT ) -panic("GICv3: Number of redistributor regions is more than" - "%d (Increase MAX_RDIST_COUNT!!)\n", MAX_RDIST_COUNT); - rdist_regs = xzalloc_array(struct rdist_region, gicv3.rdist_count); if ( !rdist_regs ) panic("GICv3: Failed to allocate memory for rdist regions\n"); @@ -1518,10 +1514,6 @@ static void __init gicv3_acpi_init(void) gicr_table = false; } -if ( count > MAX_RDIST_COUNT ) -panic("GICv3: Number of redistributor regions is more than" - "%d (Increase MAX_RDIST_COUNT!!)\n", MAX_RDIST_COUNT); - rdist_regs = xzalloc_array(struct rdist_region, count); if ( !rdist_regs ) panic("GICv3: Failed to allocate memory for rdist regions\n"); diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h index 7f9ad86..3694e07 100644 --- a/xen/include/asm-arm/gic.h +++ b/xen/include/asm-arm/gic.h @@ -20,7 +20,6 @@ #define NR_GIC_LOCAL_IRQS NR_LOCAL_IRQS #define NR_GIC_SGI 16 -#define MAX_RDIST_COUNT4 #define GICD_CTLR (0x000) #define GICD_TYPER (0x004) -- Qualcomm Technologies, Inc. on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project ___ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
[Xen-devel] [PATCH 0/8] Add support for parsing per CPU Redistributor entry
The current driver doesn't support parsing Redistributor entries that are described in the MADT GICC table. Not all the GIC implementors places the Redistributor regions in the always-on power domain. On systems, the UEFI firmware should describe Redistributor base address in the associated GIC CPU Interface (GICC) instead of GIC Redistributor (GICR) table. The maximum number of mmio handlers and struct vgic_rdist_region that holds Redistributor addresses are allocated through a static array with hardcoded size. I don't think this is the right approach and is not scalable for implementing features like this. I have decided to convert static to dynamic allocation based on comments from the below link. https://patchwork.kernel.org/patch/9163435/ Patches #1, #2 and #3 adds support for parsing not always-on power domain Redistributor regions. Patches #4, #5, #6, #7 and #8 refactors the code and allocates the memory for mmio handlers and vgic_rdist_region based on the number of Redistributors required for dom0/domU instead of hardcoded values. This pacthset is created on tip of Julien's branch http://xenbits.xen.org/gitweb/?p=people/julieng/xen-unstable.git;a=shortlog;h=refs/heads/irq-routing-acpi-rfc Shanker Donthineni (8): arm/gic-v3: Add a separate function for mapping GICD region arm/gic-v3: Fold GICR subtable parsing into a new function arm/gic-v3: Parse per-cpu redistributor entry in GICC subtable xen/arm: vgic: Use dynamic memory allocation for vgic_rdist_region arm/gic-v3: Remove an unused macro MAX_RDIST_COUNT arm: vgic: Split vgic_domain_init() functionality into two functions arm/mmio: Use separate memory allocation for mmio handlers arm/vgic: Change fixed number of mmio handlers to variable number xen/arch/arm/domain.c | 12 ++- xen/arch/arm/gic-v3.c | 162 -- xen/arch/arm/io.c | 14 +++- xen/arch/arm/vgic-v2.c| 16 +++- xen/arch/arm/vgic-v3.c| 65 ++- xen/arch/arm/vgic.c | 7 ++ xen/include/asm-arm/domain.h | 13 +-- xen/include/asm-arm/gic.h | 3 +- xen/include/asm-arm/gic_v3_defs.h | 1 + xen/include/asm-arm/mmio.h| 6 +- xen/include/asm-arm/vgic.h| 5 ++ 11 files changed, 226 insertions(+), 78 deletions(-) -- Qualcomm Technologies, Inc. on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project ___ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
[Xen-devel] [PATCH 3/8] arm/gic-v3: Parse per-cpu redistributor entry in GICC subtable
The redistributor address can be specified either as part of GICC or GICR subtable depending on the power domain. The current driver doesn't support parsing redistributor entry that is defined in GICC subtable. The GIC CPU subtable entry holds the associated Redistributor base address if it is not on always-on power domain. This patch adds necessary code to handle both types of Redistributors base addresses. Signed-off-by: Shanker Donthineni <shank...@codeaurora.org> --- xen/arch/arm/gic-v3.c | 97 --- xen/include/asm-arm/gic.h | 2 + xen/include/asm-arm/gic_v3_defs.h | 1 + 3 files changed, 83 insertions(+), 17 deletions(-) diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c index af12ebc..42cf848 100644 --- a/xen/arch/arm/gic-v3.c +++ b/xen/arch/arm/gic-v3.c @@ -659,6 +659,10 @@ static int __init gicv3_populate_rdist(void) smp_processor_id(), i, ptr); return 0; } + +if ( gicv3.rdist_regions[i].single_rdist ) +break; + if ( gicv3.rdist_stride ) ptr += gicv3.rdist_stride; else @@ -1282,6 +1286,11 @@ static int gicv3_iomem_deny_access(const struct domain *d) } #ifdef CONFIG_ACPI +static bool gic_dist_supports_dvis(void) +{ +return !!(readl_relaxed(GICD + GICD_TYPER) & GICD_TYPER_DVIS); +} + static int gicv3_make_hwdom_madt(const struct domain *d, u32 offset) { struct acpi_subtable_header *header; @@ -1393,18 +1402,39 @@ gic_acpi_parse_madt_redistributor(struct acpi_subtable_header *header, const unsigned long end) { struct acpi_madt_generic_redistributor *rdist; +struct acpi_madt_generic_interrupt *processor; struct rdist_region *region; region = gicv3.rdist_regions + gicv3.rdist_count; -rdist = (struct acpi_madt_generic_redistributor *)header; -if ( BAD_MADT_ENTRY(rdist, end) ) -return -EINVAL; +if ( header->type == ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR ) +{ +rdist = (struct acpi_madt_generic_redistributor *)header; +if ( BAD_MADT_ENTRY(rdist, end) ) +return -EINVAL; -if ( !rdist->base_address || !rdist->length ) -return -EINVAL; +if ( !rdist->base_address || !rdist->length ) +return -EINVAL; + +region->base = rdist->base_address; +region->size = rdist->length; +} +else if ( header->type == ACPI_MADT_TYPE_GENERIC_INTERRUPT ) +{ +processor = (struct acpi_madt_generic_interrupt *)header; +if ( BAD_MADT_ENTRY(processor, end) ) +return -EINVAL; + +if ( !(processor->flags & ACPI_MADT_ENABLED) ) +return 0; + +if ( !processor->gicr_base_address ) +return -EINVAL; + +region->base = processor->gicr_base_address; +region->size = gic_dist_supports_dvis() ? SZ_256K : SZ_128K; + region->single_rdist = true; + } -region->base = rdist->base_address; -region->size = rdist->length; region->map_base = ioremap_nocache(region->base, region->size); if ( !region->map_base ) @@ -1412,6 +1442,7 @@ gic_acpi_parse_madt_redistributor(struct acpi_subtable_header *header, printk("Unable to map GICR registers\n"); return -ENOMEM; } + gicv3.rdist_count++; return 0; @@ -1421,9 +1452,22 @@ static int __init gic_acpi_get_madt_redistributor_num(struct acpi_subtable_header *header, const unsigned long end) { -/* Nothing to do here since it only wants to get the number of GIC - * redistributors. - */ +struct acpi_madt_generic_redistributor *rdist; +struct acpi_madt_generic_interrupt *cpuif; + +if ( header->type == ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR ) +{ +rdist = (struct acpi_madt_generic_redistributor *)header; +if ( BAD_MADT_ENTRY(rdist, end) || !rdist->base_address ) +return -EINVAL; +} +else if ( header->type == ACPI_MADT_TYPE_GENERIC_INTERRUPT ) +{ +cpuif = (struct acpi_madt_generic_interrupt *)header; +if ( BAD_MADT_ENTRY(cpuif, end) || !cpuif->gicr_base_address ) +return -EINVAL; +} + return 0; } @@ -1431,6 +1475,7 @@ static void __init gicv3_acpi_init(void) { struct acpi_table_header *table; struct rdist_region *rdist_regs; +bool gicr_table = true; acpi_status status; int count; @@ -1460,8 +1505,18 @@ static void __init gicv3_acpi_init(void) count = acpi_parse_entries(ACPI_SIG_MADT, sizeof(struct acpi_table_madt), gic_acpi_get_madt_redistributor_num, table, ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR, 0); -if ( count <= 0 ) -panic("GICv3: No valid GICR
[Xen-devel] [PATCH 8/8] arm/vgic: Change fixed number of mmio handlers to variable number
Record the number of mmio handlers that are required for vGICv3/2 in variable 'arch_domain.vgic.mmio_count' in vgic_domain_init(). Augment this variable number to a fixed number MAX_IO_HANDLER and pass it to domain_io_init() to allocate enough memory for handlers. New code path: domain_vgic_init() count = MAX_IO_HANDLER + d->arch.vgic.mmio_count; domain_io_init(count) domain_vgic_register_mmio() Signed-off-by: Shanker Donthineni <shank...@codeaurora.org> --- xen/arch/arm/domain.c| 10 ++ xen/arch/arm/vgic-v2.c | 2 ++ xen/arch/arm/vgic-v3.c | 3 +++ xen/arch/arm/vgic.c | 7 +-- xen/include/asm-arm/domain.h | 1 + xen/include/asm-arm/vgic.h | 1 + 6 files changed, 18 insertions(+), 6 deletions(-) diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c index 4010ff2..ef567c8 100644 --- a/xen/arch/arm/domain.c +++ b/xen/arch/arm/domain.c @@ -550,10 +550,6 @@ int arch_domain_create(struct domain *d, unsigned int domcr_flags, share_xen_page_with_guest( virt_to_page(d->shared_info), d, XENSHARE_writable); -count = MAX_IO_HANDLER; -if ( (rc = domain_io_init(d, count)) != 0 ) -goto fail; - if ( (rc = p2m_alloc_table(d)) != 0 ) goto fail; @@ -593,6 +589,12 @@ int arch_domain_create(struct domain *d, unsigned int domcr_flags, if ( (rc = domain_vgic_init(d, config->nr_spis)) != 0 ) goto fail; +count = MAX_IO_HANDLER + d->arch.vgic.mmio_count; +if ( (rc = domain_io_init(d, count)) != 0 ) +goto fail; + +domain_vgic_register_mmio(d); + if ( (rc = domain_vtimer_init(d, config)) != 0 ) goto fail; diff --git a/xen/arch/arm/vgic-v2.c b/xen/arch/arm/vgic-v2.c index d42b408..7ed7d32 100644 --- a/xen/arch/arm/vgic-v2.c +++ b/xen/arch/arm/vgic-v2.c @@ -699,6 +699,8 @@ static int vgic_v2_domain_init(struct domain *d) if ( ret ) return ret; +d->arch.vgic.mmio_count = 1; /* Only GICD region */ + return 0; } diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c index 3a5aeb6..6a5f333 100644 --- a/xen/arch/arm/vgic-v3.c +++ b/xen/arch/arm/vgic-v3.c @@ -1479,6 +1479,9 @@ static int vgic_v3_domain_init(struct domain *d) d->arch.vgic.ctlr = VGICD_CTLR_DEFAULT; +/* GICD region + number of Re-distributors */ +d->arch.vgic.mmio_count = d->arch.vgic.nr_regions + 1; + return 0; } diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c index 5b39e0d..7d34942 100644 --- a/xen/arch/arm/vgic.c +++ b/xen/arch/arm/vgic.c @@ -88,6 +88,11 @@ static void vgic_rank_init(struct vgic_irq_rank *rank, uint8_t index, rank->vcpu[i] = vcpu; } +void domain_vgic_register_mmio(struct domain *d) +{ +d->arch.vgic.handler->domain_register_mmio(d); +} + int domain_vgic_init(struct domain *d, unsigned int nr_spis) { int i; @@ -151,8 +156,6 @@ int domain_vgic_init(struct domain *d, unsigned int nr_spis) for ( i = 0; i < NR_GIC_SGI; i++ ) set_bit(i, d->arch.vgic.allocated_irqs); -d->arch.vgic.handler->domain_register_mmio(d); - return 0; } diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h index 9492727..974cf93 100644 --- a/xen/include/asm-arm/domain.h +++ b/xen/include/asm-arm/domain.h @@ -113,6 +113,7 @@ struct arch_domain int nr_regions; /* Number of rdist regions */ uint32_t rdist_stride; /* Re-Distributor stride */ #endif +uint32_t mmio_count; /* Number of mmio handlers */ } vgic; struct vuart { diff --git a/xen/include/asm-arm/vgic.h b/xen/include/asm-arm/vgic.h index 8fe65b4..0032633 100644 --- a/xen/include/asm-arm/vgic.h +++ b/xen/include/asm-arm/vgic.h @@ -309,6 +309,7 @@ extern void register_vgic_ops(struct domain *d, const struct vgic_ops *ops); int vgic_v2_init(struct domain *d); int vgic_v3_init(struct domain *d); +extern void domain_vgic_register_mmio(struct domain *d); extern int vcpu_vgic_free(struct vcpu *v); extern int vgic_to_sgi(struct vcpu *v, register_t sgir, enum gic_sgi_mode irqmode, int virq, -- Qualcomm Technologies, Inc. on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project ___ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
Re: [Xen-devel] [PATCH V9 2/3] drivers/pl011: Use combination of UARTRIS and UARTMSC instead of UARTMIS
On 06/13/2016 05:30 AM, Stefano Stabellini wrote: On Thu, 9 Jun 2016, Shanker Donthineni wrote: The Masked interrupt status register (UARTMIS) is not described in ARM SBSA 2.x document. Anding of two registers UARTMSC and UARTRIS values gives the same information as register UARTMIS. UARTRIS, UARTMSC and UARTMIS definitions are found in PrimeCell UART PL011 (Revision: r1p4). - 3.3.10 Interrupt mask set/clear register, UARTIMSC - 3.3.11 Raw interrupt status register, UARTRIS - 3.3.12 Masked interrupt status register, UARTMIS This change is necessary for driver to be SBSA compliant v2.x without affecting the current driver functionality. Signed-off-by: Shanker Donthineni <shank...@codeaurora.org> Reviewed-by: Julien Grall <julien.gr...@arm.com> Changes since v8: Fixed white spaces. Changes since v7: Moved comment 'To compatible with SBSA v2.x document, all accesses should be 32-bit' to #3 Changes since v1: Added a new function to return an interrupt status. xen/drivers/char/pl011.c | 10 -- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/xen/drivers/char/pl011.c b/xen/drivers/char/pl011.c index 6a3c21b..7e19c4a 100644 --- a/xen/drivers/char/pl011.c +++ b/xen/drivers/char/pl011.c @@ -53,11 +53,17 @@ static struct pl011 { #define pl011_read(uart, off) readl((uart)->regs + (off)) #define pl011_write(uart, off,val) writel((val), (uart)->regs + (off)) +static unsigned int pl011_intr_status(struct pl011 *uart) Maybe this should be static inline? In any case the series is good, I am happy to queue it up for 4.8. Nice discussion on usage of keyword 'inline', https://www.kernel.org/doc/local/inline.html. -- Shanker Donthineni Qualcomm Technologies, Inc. on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project ___ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
Re: [Xen-devel] [RFC 0/8] xen/arm: acpi: Support SPIs routing
Julien, The problem that was reported earlier related to our platform drivers in domn0 kernel. I have verified your patches and works fine without any dead-lock. On 06/13/2016 06:42 AM, Julien Grall wrote: On 08/06/16 13:34, Julien Grall wrote: On 08/06/16 13:11, Shanker Donthineni wrote: I don't know exactly which of the patch causing the issue. I have noticed a couple of drivers are not receiving SPI interrupts in DOM0. I need to digest your patches before tracing/investigate the problem to get more details. FYI, our system uses both the EDGE and LEVEL interrupts, any major change in your patches? The routing is done when DOM0 is built and the interrupt configuration is deferred. It might be possible to the wrong type is retrieve by __vgic_get_virq_type. I looked at my code again today and add some printk. The IRQ will always be configured correctly with the correct type. It would be good to know if the problem only happen with edge or level interrupts. Regards, -- Shanker Donthineni Qualcomm Technologies, Inc. on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project ___ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
[Xen-devel] [PATCH V9 3/3] arm/acpi: Add Server Base System Architecture UART support
The ARM Server Base System Architecture describes a generic UART interface. It doesn't support clock control registers, modem control, DMA and hardware flow control features. So, extend the driver probe() to handle SBSA interface and skip the accessing PL011 registers that are not described in SBSA document (ARM-DEN-0029 Version 3.0, 6 APPENDIX B: GENERIC UART). Signed-off-by: Shanker Donthineni <shank...@codeaurora.org> Reviewed-by: Julien Grall <julien.gr...@arm.com> --- Changes sicne v8: Simplified condition 'if (spcr->interface_type == ACPI_DBG2_SBSA) || '. Changes sicne v7: Moved comment 'To compatible with SBSA v2.x document, all accesses should be 32-bit' from #2. Changes since v3: Moved non-SBSA related changes to patches 1/3 and 2/3. changes since v2: Edited commit text to include SBSA document version. Remove setting baudrate code completely as per Julien's suggestion. Support both the SBSA interface types ACPI_DBG2_SBSA & ACPI_DBG2_SBSA_32. Replace MIS references with combination of RIS & IMSC. Changes since v1: Don't access UART registers that are not part of SBSA document. Move setting baudrate function to a separate function. xen/drivers/char/pl011.c | 54 ++-- 1 file changed, 39 insertions(+), 15 deletions(-) diff --git a/xen/drivers/char/pl011.c b/xen/drivers/char/pl011.c index 7e19c4a..ab22f7f 100644 --- a/xen/drivers/char/pl011.c +++ b/xen/drivers/char/pl011.c @@ -41,6 +41,7 @@ static struct pl011 { /* struct timer timer; */ /* unsigned int timeout_ms; */ /* bool_t probing, intr_works; */ +bool sbsa; /* ARM SBSA generic interface */ } pl011_com = {0}; /* These parity settings can be ORed directly into the LCR. */ @@ -50,6 +51,7 @@ static struct pl011 { #define PARITY_MARK (PEN|SPS) #define PARITY_SPACE (PEN|EPS|SPS) +/* SBSA v2.x document requires, all reads/writes must be 32-bit accesses */ #define pl011_read(uart, off) readl((uart)->regs + (off)) #define pl011_write(uart, off,val) writel((val), (uart)->regs + (off)) @@ -95,14 +97,17 @@ static void __init pl011_init_preirq(struct serial_port *port) /* No interrupts, please. */ pl011_write(uart, IMSC, 0); -/* Definitely no DMA */ -pl011_write(uart, DMACR, 0x0); - -/* This write must follow FBRD and IBRD writes. */ -pl011_write(uart, LCR_H, (uart->data_bits - 5) << 5 -| FEN -| ((uart->stop_bits - 1) << 3) -| uart->parity); +if ( !uart->sbsa ) +{ +/* Definitely no DMA */ +pl011_write(uart, DMACR, 0x0); + +/* This write must follow FBRD and IBRD writes. */ +pl011_write(uart, LCR_H, (uart->data_bits - 5) << 5 +| FEN +| ((uart->stop_bits - 1) << 3) +| uart->parity); +} /* Clear errors */ pl011_write(uart, RSR, 0); @@ -110,10 +115,13 @@ static void __init pl011_init_preirq(struct serial_port *port) pl011_write(uart, IMSC, 0); pl011_write(uart, ICR, ALLI); -/* Enable the UART for RX and TX; keep RTS and DTR */ -cr = pl011_read(uart, CR); -cr &= RTS | DTR; -pl011_write(uart, CR, cr | RXE | TXE | UARTEN); +if ( !uart->sbsa ) +{ +/* Enable the UART for RX and TX; keep RTS and DTR */ +cr = pl011_read(uart, CR); +cr &= RTS | DTR; +pl011_write(uart, CR, cr | RXE | TXE | UARTEN); +} } static void __init pl011_init_postirq(struct serial_port *port) @@ -215,7 +223,7 @@ static struct uart_driver __read_mostly pl011_driver = { .vuart_info = pl011_vuart, }; -static int __init pl011_uart_init(int irq, u64 addr, u64 size) +static int __init pl011_uart_init(int irq, u64 addr, u64 size, bool sbsa) { struct pl011 *uart; @@ -224,6 +232,7 @@ static int __init pl011_uart_init(int irq, u64 addr, u64 size) uart->data_bits = 8; uart->parity= PARITY_NONE; uart->stop_bits = 1; +uart->sbsa = sbsa; uart->regs = ioremap_nocache(addr, size); if ( !uart->regs ) @@ -272,7 +281,7 @@ static int __init pl011_dt_uart_init(struct dt_device_node *dev, return -EINVAL; } -res = pl011_uart_init(res, addr, size); +res = pl011_uart_init(res, addr, size, false); if ( res < 0 ) { printk("pl011: Unable to initialize\n"); @@ -303,6 +312,7 @@ static int __init pl011_acpi_uart_init(const void *data) acpi_status status; struct acpi_table_spcr *spcr = NULL; int res; +bool sbsa; status = acpi_get_table(ACPI_SIG_SPCR, 0, (struct acpi_table_header **)); @@ -313,11 +323,14 @@ static int __init pl011_acpi_uart_init(const void *data) return -EINVAL;
[Xen-devel] [PATCH V9 1/3] drivers/pl011: Don't configure baudrate
The default baud and clock_hz configuration parameters are hardcoded (commit 60ff980995008caf) for Versatile Express. Other platforms, these default values may not be valid and might cause problems by programming registers IBRD and FBRD incorrectly. So, removing driver logic that sets the baudrate to fix the problem. The behavior is unchanged because the driver was already relying on the boot firmware for setting the correct baudrate. Signed-off-by: Shanker Donthineni <shank...@codeaurora.org> Reviewed-by: Julien Grall <julien.gr...@arm.com> --- Changes since v1: Edited commit text. xen/drivers/char/pl011.c | 21 + 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/xen/drivers/char/pl011.c b/xen/drivers/char/pl011.c index 1212d5c..6a3c21b 100644 --- a/xen/drivers/char/pl011.c +++ b/xen/drivers/char/pl011.c @@ -31,7 +31,7 @@ #include static struct pl011 { -unsigned int baud, clock_hz, data_bits, parity, stop_bits; +unsigned int data_bits, parity, stop_bits; unsigned int irq; void __iomem *regs; /* UART with IRQ line: interrupt-driven I/O. */ @@ -84,7 +84,6 @@ static void pl011_interrupt(int irq, void *data, struct cpu_user_regs *regs) static void __init pl011_init_preirq(struct serial_port *port) { struct pl011 *uart = port->uart; -unsigned int divisor; unsigned int cr; /* No interrupts, please. */ @@ -93,22 +92,6 @@ static void __init pl011_init_preirq(struct serial_port *port) /* Definitely no DMA */ pl011_write(uart, DMACR, 0x0); -/* Line control and baud-rate generator. */ -if ( uart->baud != BAUD_AUTO ) -{ -/* Baud rate specified: program it into the divisor latch. */ -divisor = (uart->clock_hz << 2) / uart->baud; /* clk << 6 / bd << 4 */ -pl011_write(uart, FBRD, divisor & 0x3f); -pl011_write(uart, IBRD, divisor >> 6); -} -else -{ -/* Baud rate already set: read it out from the divisor latch. */ -divisor = (pl011_read(uart, IBRD) << 6) | (pl011_read(uart, FBRD)); -if (!divisor) -panic("pl011: No Baud rate configured\n"); -uart->baud = (uart->clock_hz << 2) / divisor; -} /* This write must follow FBRD and IBRD writes. */ pl011_write(uart, LCR_H, (uart->data_bits - 5) << 5 | FEN @@ -232,8 +215,6 @@ static int __init pl011_uart_init(int irq, u64 addr, u64 size) uart = _com; uart->irq = irq; -uart->clock_hz = 0x16e3600; -uart->baud = BAUD_AUTO; uart->data_bits = 8; uart->parity= PARITY_NONE; uart->stop_bits = 1; -- Qualcomm Technologies, Inc. on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project ___ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
[Xen-devel] [PATCH V9 2/3] drivers/pl011: Use combination of UARTRIS and UARTMSC instead of UARTMIS
The Masked interrupt status register (UARTMIS) is not described in ARM SBSA 2.x document. Anding of two registers UARTMSC and UARTRIS values gives the same information as register UARTMIS. UARTRIS, UARTMSC and UARTMIS definitions are found in PrimeCell UART PL011 (Revision: r1p4). - 3.3.10 Interrupt mask set/clear register, UARTIMSC - 3.3.11 Raw interrupt status register, UARTRIS - 3.3.12 Masked interrupt status register, UARTMIS This change is necessary for driver to be SBSA compliant v2.x without affecting the current driver functionality. Signed-off-by: Shanker Donthineni <shank...@codeaurora.org> Reviewed-by: Julien Grall <julien.gr...@arm.com> --- Changes since v8: Fixed white spaces. Changes since v7: Moved comment 'To compatible with SBSA v2.x document, all accesses should be 32-bit' to #3 Changes since v1: Added a new function to return an interrupt status. xen/drivers/char/pl011.c | 10 -- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/xen/drivers/char/pl011.c b/xen/drivers/char/pl011.c index 6a3c21b..7e19c4a 100644 --- a/xen/drivers/char/pl011.c +++ b/xen/drivers/char/pl011.c @@ -53,11 +53,17 @@ static struct pl011 { #define pl011_read(uart, off) readl((uart)->regs + (off)) #define pl011_write(uart, off,val) writel((val), (uart)->regs + (off)) +static unsigned int pl011_intr_status(struct pl011 *uart) +{ +/* UARTMIS is not documented in SBSA v2.x, so use UARTRIS/UARTIMSC. */ +return (pl011_read(uart, RIS) & pl011_read(uart, IMSC)); +} + static void pl011_interrupt(int irq, void *data, struct cpu_user_regs *regs) { struct serial_port *port = data; struct pl011 *uart = port->uart; -unsigned int status = pl011_read(uart, MIS); +unsigned int status = pl011_intr_status(uart); if ( status ) { @@ -76,7 +82,7 @@ static void pl011_interrupt(int irq, void *data, struct cpu_user_regs *regs) if ( status & (TXI) ) serial_tx_interrupt(port, regs); -status = pl011_read(uart, MIS); +status = pl011_intr_status(uart); } while (status != 0); } } -- Qualcomm Technologies, Inc. on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project ___ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel