xen/arm: make domain_max_vcpus return value from vgic_ops
authorChen Baozi <baozich@gmail.com>
Tue, 30 Jun 2015 08:00:21 +0000 (16:00 +0800)
committerIan Campbell <ian.campbell@citrix.com>
Fri, 3 Jul 2015 10:11:27 +0000 (11:11 +0100)
Each vGIC driver supports different maximum numbers of vCPU. For
example, GICv2 is limited to 8 vCPUs, while GICv3 can support up
to 4096 vCPUs if we use both AFF0 and AFF1. Thus, domain_max_vcpus
should depend on not only MAX_VIRT_CPUS but also the version
of vGIC that the guest uses.

Since evtchn_init would call domain_max_vcpus to allocate poll_mask
when the vgic_ops haven't been initialised yet, we make it return
MAX_VIRT_CPUS at that time. On ARM32, event channel doesn't need
to allocate the poll_mask because MAX_VIRT_CPUS < BITS_PER_LONG,
while allocating more memory (2 unsigned long rather than 1) only
for poll_mask on arm64 with GICv2 looks not so expensive.

We didn't keep it as the old static inline form because it will break
compilation when access the member of struct domain:

In file included from xen/include/xen/domain.h:6:0,
                 from xen/include/xen/sched.h:10,
                 from arm64/asm-offsets.c:10:
xen/include/asm/domain.h: In function ‘domain_max_vcpus’:
xen/include/asm/domain.h:266:10: error: dereferencing pointer to incomplete type
     if (d->arch.vgic.version == GIC_V2)
          ^

Signed-off-by: Chen Baozi <baozich@gmail.com>
Acked-by: Ian Campbell <ian.campbell@citrix.com>
xen/arch/arm/domain.c
xen/arch/arm/vgic-v2.c
xen/arch/arm/vgic-v3.c
xen/include/asm-arm/domain.h
xen/include/asm-arm/vgic.h

index 7ed6db8bacc8d303a0331b371fe36bb0295ef7a5..d741e4ff4b1c54001d2a19b455b4489acce685e6 100644 (file)
@@ -881,6 +881,20 @@ void vcpu_block_unless_event_pending(struct vcpu *v)
         vcpu_unblock(current);
 }
 
+unsigned int domain_max_vcpus(const struct domain *d)
+{
+    /*
+     * Since evtchn_init would call domain_max_vcpus for poll_mask
+     * allocation when the vgic_ops haven't been initialised yet,
+     * we return MAX_VIRT_CPUS if d->arch.vgic.handler is null.
+     */
+    if ( !d->arch.vgic.handler )
+        return MAX_VIRT_CPUS;
+    else
+        return min_t(unsigned int, MAX_VIRT_CPUS,
+                     d->arch.vgic.handler->max_vcpus);
+}
+
 /*
  * Local variables:
  * mode: C
index fe5b17d71a51e7d33a1b780bb6cf1aa94eb472e5..524787b0a87cabb790821576b9368615517f8ede 100644 (file)
@@ -600,6 +600,7 @@ static const struct vgic_ops vgic_v2_ops = {
     .domain_init = vgic_v2_domain_init,
     .get_irq_priority = vgic_v2_get_irq_priority,
     .get_target_vcpu = vgic_v2_get_target_vcpu,
+    .max_vcpus = 8,
 };
 
 int vgic_v2_init(struct domain *d)
index 6b5548834cf68d1e1bb1e0b776c3bb472fa8f90c..dbb1ba0cf6a58337fc2ea4ca6823564ba1d179a8 100644 (file)
@@ -1224,6 +1224,11 @@ static const struct vgic_ops v3_ops = {
     .get_irq_priority = vgic_v3_get_irq_priority,
     .get_target_vcpu  = vgic_v3_get_target_vcpu,
     .emulate_sysreg  = vgic_v3_emulate_sysreg,
+    /*
+     * 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.
+     */
+    .max_vcpus = 4096,
 };
 
 int vgic_v3_init(struct domain *d)
index d74a5c2b47c0596ff00e28a46339926463fd6279..8f5a6898afbc10ad8b75bb876ffd1ec4b7217525 100644 (file)
@@ -259,10 +259,7 @@ struct arch_vcpu
 void vcpu_show_execution_state(struct vcpu *);
 void vcpu_show_registers(const struct vcpu *);
 
-static inline unsigned int domain_max_vcpus(const struct domain *d)
-{
-    return MAX_VIRT_CPUS;
-}
+unsigned int domain_max_vcpus(const struct domain *);
 
 /*
  * Due to the restriction of GICv3, the number of vCPUs in AFF0 is
index 154556ee1c2ac482ae0579e0f55785763803febc..41cadb12998f124f8b74bb548e6e7e0ee37d4cf2 100644 (file)
@@ -121,6 +121,8 @@ struct vgic_ops {
     struct vcpu *(*get_target_vcpu)(struct vcpu *v, unsigned int irq);
     /* vGIC sysreg emulation */
     int (*emulate_sysreg)(struct cpu_user_regs *regs, union hsr hsr);
+    /* Maximum number of vCPU supported */
+    const unsigned int max_vcpus;
 };
 
 /* Number of ranks of interrupt registers for a domain */