@@ -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[] =
@@ -1927,6 +1931,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;
@@ -1958,6 +1972,10 @@ void __init setup_virt_paging(void)
unsigned long val = VTCR_RES1|VTCR_SH0_IS|VTCR_ORGN0_WBWA|VTCR_IRGN0_WBWA;
#ifdef CONFIG_ARM_32
+ if ( p2m_ipa_bits < 40 )
+ panic("P2M: Not able to support %u-bit IPA at the moment\n",
+ p2m_ipa_bits);
+
printk("P2M: 40-bit IPA\n");
p2m_ipa_bits = 40;
val |= VTCR_T0SZ(0x18); /* 40 bit IPA */
@@ -1981,15 +1999,20 @@ 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;
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 )
@@ -2003,6 +2026,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);
@@ -928,12 +928,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.\n");
+ setup_virt_paging();
+
do_initcalls();
/*
@@ -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 )
@@ -1110,7 +1110,11 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain)
reg = TTBCR_TG0_64K;
if (!stage1) {
- reg |= (64 - smmu->s2_input_size) << TTBCR_T0SZ_SHIFT;
+ /*
+ * Xen: The IOMMU share the page-tables with the P2M
+ * which may have restrict the size further.
+ */
+ reg |= (64 - p2m_ipa_bits) << TTBCR_T0SZ_SHIFT;
switch (smmu->s2_output_size) {
case 32:
@@ -2198,14 +2202,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
@@ -159,6 +159,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);