Message ID | 1568224770-25402-1-git-send-email-olekstysh@gmail.com (mailing list archive) |
---|---|
State | Superseded |
Headers | show |
Series | [RFC,V3] xen/arm: Restrict "p2m_ipa_bits" according to the IOMMU requirements | expand |
Hi, On 11/09/2019 18:59, Oleksandr Tyshchenko wrote: > --- > xen/arch/arm/p2m.c | 41 ++++++++++++++++++++++++++++---- > xen/arch/arm/setup.c | 9 +++++-- > xen/drivers/passthrough/arm/ipmmu-vmsa.c | 18 ++------------ > xen/drivers/passthrough/arm/smmu.c | 11 +++------ > xen/include/asm-arm/p2m.h | 9 +++++++ > 5 files changed, 58 insertions(+), 30 deletions(-) > > diff --git a/xen/arch/arm/p2m.c b/xen/arch/arm/p2m.c > index 2374e92..d5e2539 100644 > --- a/xen/arch/arm/p2m.c > +++ b/xen/arch/arm/p2m.c > @@ -34,7 +34,11 @@ static unsigned int __read_mostly max_vmid = MAX_VMID_8_BIT; > > #define P2M_ROOT_PAGES (1<<P2M_ROOT_ORDER) > > -unsigned int __read_mostly p2m_ipa_bits; > +/* > + * Set larger than any possible value, so the number of IPA bits can be > + * restricted by external entity (e.g. IOMMU). > + */ > +unsigned int __read_mostly p2m_ipa_bits = 64; > > /* Helpers to lookup the properties of each level */ > static const paddr_t level_masks[] = > @@ -1912,6 +1916,16 @@ struct page_info *get_page_from_gva(struct vcpu *v, vaddr_t va, > return page; > } > > +void __init p2m_restrict_ipa_bits(unsigned int ipa_bits) > +{ > + /* > + * Calculate the minimum of the maximum IPA bits that any external entity > + * can support. > + */ > + if ( ipa_bits < p2m_ipa_bits ) > + p2m_ipa_bits = ipa_bits; > +} > + > /* VTCR value to be configured by all CPUs. Set only once by the boot CPU */ > static uint32_t __read_mostly vtcr; > > @@ -1966,15 +1980,24 @@ void __init setup_virt_paging(void) > [7] = { 0 } /* Invalid */ > }; > > - unsigned int cpu; > + unsigned int i, cpu; > unsigned int pa_range = 0x10; /* Larger than any possible value */ > bool vmid_8_bit = false; > > + if ( p2m_ipa_bits < 40 ) > + panic("P2M IPA size must be at least 40-bit (p2m_ipa_bits=%u)\n", > + p2m_ipa_bits); Isn't this check meant to be for Arm32? If so, this path is not called by arm32. See the #ifdef CONFIG_ARM_32 above. Also, I would suggest to reword the message to: "P2M: Not able to support %⁻bit IPA at the moment.\n" The rest of the code looks good to me. Cheers,
On 24.09.19 12:36, Julien Grall wrote: > Hi, Hi, Julien > > On 11/09/2019 18:59, Oleksandr Tyshchenko wrote: >> --- >> xen/arch/arm/p2m.c | 41 >> ++++++++++++++++++++++++++++---- >> xen/arch/arm/setup.c | 9 +++++-- >> xen/drivers/passthrough/arm/ipmmu-vmsa.c | 18 ++------------ >> xen/drivers/passthrough/arm/smmu.c | 11 +++------ >> xen/include/asm-arm/p2m.h | 9 +++++++ >> 5 files changed, 58 insertions(+), 30 deletions(-) >> >> diff --git a/xen/arch/arm/p2m.c b/xen/arch/arm/p2m.c >> index 2374e92..d5e2539 100644 >> --- a/xen/arch/arm/p2m.c >> +++ b/xen/arch/arm/p2m.c >> @@ -34,7 +34,11 @@ static unsigned int __read_mostly max_vmid = >> MAX_VMID_8_BIT; >> #define P2M_ROOT_PAGES (1<<P2M_ROOT_ORDER) >> -unsigned int __read_mostly p2m_ipa_bits; >> +/* >> + * Set larger than any possible value, so the number of IPA bits can be >> + * restricted by external entity (e.g. IOMMU). >> + */ >> +unsigned int __read_mostly p2m_ipa_bits = 64; >> /* Helpers to lookup the properties of each level */ >> static const paddr_t level_masks[] = >> @@ -1912,6 +1916,16 @@ struct page_info *get_page_from_gva(struct >> vcpu *v, vaddr_t va, >> return page; >> } >> +void __init p2m_restrict_ipa_bits(unsigned int ipa_bits) >> +{ >> + /* >> + * Calculate the minimum of the maximum IPA bits that any >> external entity >> + * can support. >> + */ >> + if ( ipa_bits < p2m_ipa_bits ) >> + p2m_ipa_bits = ipa_bits; >> +} >> + >> /* VTCR value to be configured by all CPUs. Set only once by the >> boot CPU */ >> static uint32_t __read_mostly vtcr; >> @@ -1966,15 +1980,24 @@ void __init setup_virt_paging(void) >> [7] = { 0 } /* Invalid */ >> }; >> - unsigned int cpu; >> + unsigned int i, cpu; >> unsigned int pa_range = 0x10; /* Larger than any possible value */ >> bool vmid_8_bit = false; >> + if ( p2m_ipa_bits < 40 ) >> + panic("P2M IPA size must be at least 40-bit >> (p2m_ipa_bits=%u)\n", >> + p2m_ipa_bits); > > Isn't this check meant to be for Arm32? If so, this path is not called > by arm32. See the #ifdef CONFIG_ARM_32 above. I will move under #ifdef CONFIG_ARM_32 > > > Also, I would suggest to reword the message to: > > "P2M: Not able to support %⁻bit IPA at the moment.\n" ok > > The rest of the code looks good to me. Shall the non-RFC patch be split into "adding possibility to restrict" and "restrict by the IOMMU drivers"?
Hi, On 24/09/2019 10:55, Oleksandr wrote: > On 24.09.19 12:36, Julien Grall wrote: >> The rest of the code looks good to me. > > > Shall the non-RFC patch be split into "adding possibility to restrict" and > "restrict by the IOMMU drivers"? The patch is fine as it is. No need to split further :). Cheers,
diff --git a/xen/arch/arm/p2m.c b/xen/arch/arm/p2m.c index 2374e92..d5e2539 100644 --- a/xen/arch/arm/p2m.c +++ b/xen/arch/arm/p2m.c @@ -34,7 +34,11 @@ static unsigned int __read_mostly max_vmid = MAX_VMID_8_BIT; #define P2M_ROOT_PAGES (1<<P2M_ROOT_ORDER) -unsigned int __read_mostly p2m_ipa_bits; +/* + * Set larger than any possible value, so the number of IPA bits can be + * restricted by external entity (e.g. IOMMU). + */ +unsigned int __read_mostly p2m_ipa_bits = 64; /* Helpers to lookup the properties of each level */ static const paddr_t level_masks[] = @@ -1912,6 +1916,16 @@ struct page_info *get_page_from_gva(struct vcpu *v, vaddr_t va, return page; } +void __init p2m_restrict_ipa_bits(unsigned int ipa_bits) +{ + /* + * Calculate the minimum of the maximum IPA bits that any external entity + * can support. + */ + if ( ipa_bits < p2m_ipa_bits ) + p2m_ipa_bits = ipa_bits; +} + /* VTCR value to be configured by all CPUs. Set only once by the boot CPU */ static uint32_t __read_mostly vtcr; @@ -1966,15 +1980,24 @@ void __init setup_virt_paging(void) [7] = { 0 } /* Invalid */ }; - unsigned int cpu; + unsigned int i, cpu; unsigned int pa_range = 0x10; /* Larger than any possible value */ bool vmid_8_bit = false; + if ( p2m_ipa_bits < 40 ) + panic("P2M IPA size must be at least 40-bit (p2m_ipa_bits=%u)\n", + p2m_ipa_bits); + for_each_online_cpu ( cpu ) { const struct cpuinfo_arm *info = &cpu_data[cpu]; - if ( info->mm64.pa_range < pa_range ) - pa_range = info->mm64.pa_range; + + /* + * Restrict "p2m_ipa_bits" if needed. As P2M table is always configured + * with IPA bits == PA bits, compare against "pabits". + */ + if ( pa_range_info[info->mm64.pa_range].pabits < p2m_ipa_bits ) + p2m_ipa_bits = pa_range_info[info->mm64.pa_range].pabits; /* Set a flag if the current cpu does not support 16 bit VMIDs. */ if ( info->mm64.vmid_bits != MM64_VMID_16_BITS_SUPPORT ) @@ -1988,6 +2011,16 @@ void __init setup_virt_paging(void) if ( !vmid_8_bit ) max_vmid = MAX_VMID_16_BIT; + /* Choose suitable "pa_range" according to the resulted "p2m_ipa_bits". */ + for ( i = 0; i < ARRAY_SIZE(pa_range_info); i++ ) + { + if ( p2m_ipa_bits == pa_range_info[i].pabits ) + { + pa_range = i; + break; + } + } + /* pa_range is 4 bits, but the defined encodings are only 3 bits */ if ( pa_range >= ARRAY_SIZE(pa_range_info) || !pa_range_info[pa_range].pabits ) panic("Unknown encoding of ID_AA64MMFR0_EL1.PARange %x\n", pa_range); diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c index 51a6677..0e628bc 100644 --- a/xen/arch/arm/setup.c +++ b/xen/arch/arm/setup.c @@ -936,12 +936,17 @@ void __init start_xen(unsigned long boot_phys_offset, printk("Brought up %ld CPUs\n", (long)num_online_cpus()); /* TODO: smp_cpus_done(); */ - setup_virt_paging(); - + /* + * The IOMMU subsystem must be initialized before P2M as we need + * to gather requirements regarding the maximum IPA bits supported by + * each IOMMU device. + */ rc = iommu_setup(); if ( !iommu_enabled && rc != -ENODEV ) panic("Couldn't configure correctly all the IOMMUs."); + setup_virt_paging(); + do_initcalls(); /* diff --git a/xen/drivers/passthrough/arm/ipmmu-vmsa.c b/xen/drivers/passthrough/arm/ipmmu-vmsa.c index ea29e91..efbda39 100644 --- a/xen/drivers/passthrough/arm/ipmmu-vmsa.c +++ b/xen/drivers/passthrough/arm/ipmmu-vmsa.c @@ -844,22 +844,8 @@ static int ipmmu_probe(struct dt_device_node *node) goto out; } - /* - * As 4-level translation table is not supported in IPMMU, we need - * to check IPA size used for P2M table beforehand to be sure it is - * 3-level and the IPMMU will be able to use it. - * - * TODO: First initialize the IOMMU and gather the requirements and - * then initialize the P2M. In the P2M code, take into the account - * the IOMMU requirements and restrict "pa_range" if necessary. - */ - if ( IPMMU_MAX_P2M_IPA_BITS < p2m_ipa_bits ) - { - printk(XENLOG_ERR "ipmmu: P2M IPA size is not supported (P2M=%u IPMMU=%u)!\n", - p2m_ipa_bits, IPMMU_MAX_P2M_IPA_BITS); - ret = -ENODEV; - goto out; - } + /* Set maximum Stage-2 input size supported by the IPMMU. */ + p2m_restrict_ipa_bits(IPMMU_MAX_P2M_IPA_BITS); irq = platform_get_irq(node, 0); if ( irq < 0 ) diff --git a/xen/drivers/passthrough/arm/smmu.c b/xen/drivers/passthrough/arm/smmu.c index 8ae986a..701fe9c 100644 --- a/xen/drivers/passthrough/arm/smmu.c +++ b/xen/drivers/passthrough/arm/smmu.c @@ -2198,14 +2198,9 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu) size = arm_smmu_id_size_to_bits((id >> ID2_IAS_SHIFT) & ID2_IAS_MASK); smmu->s1_output_size = min_t(unsigned long, PHYS_MASK_SHIFT, size); - /* Xen: Stage-2 input size has to match p2m_ipa_bits. */ - if (size < p2m_ipa_bits) { - dev_err(smmu->dev, - "P2M IPA size not supported (P2M=%u SMMU=%lu)!\n", - p2m_ipa_bits, size); - return -ENODEV; - } - smmu->s2_input_size = p2m_ipa_bits; + /* Xen: Set maximum Stage-2 input size supported by the SMMU. */ + p2m_restrict_ipa_bits(size); + smmu->s2_input_size = size; #if 0 /* Stage-2 input size limited due to pgd allocation (PTRS_PER_PGD) */ #ifdef CONFIG_64BIT diff --git a/xen/include/asm-arm/p2m.h b/xen/include/asm-arm/p2m.h index f970c53..0a377ea 100644 --- a/xen/include/asm-arm/p2m.h +++ b/xen/include/asm-arm/p2m.h @@ -165,6 +165,15 @@ void p2m_altp2m_check(struct vcpu *v, uint16_t idx) /* Not supported on ARM. */ } +/* + * Helper to restrict "p2m_ipa_bits" according the external entity + * (e.g. IOMMU) requirements. + * + * Each corresponding driver should report the maximum IPA bits + * (Stage-2 input size) it can support. + */ +void p2m_restrict_ipa_bits(unsigned int ipa_bits); + /* Second stage paging setup, to be called on all CPUs */ void setup_virt_paging(void);