int virq;
int irqmode;
enum gic_sgi_mode sgi_mode;
- unsigned long vcpu_mask = 0;
+ struct sgi_target target;
irqmode = (sgir & GICD_SGI_TARGET_LIST_MASK) >> GICD_SGI_TARGET_LIST_SHIFT;
virq = (sgir & GICD_SGI_INTID_MASK);
- vcpu_mask = (sgir & GICD_SGI_TARGET_MASK) >> GICD_SGI_TARGET_SHIFT;
/* Map GIC sgi value to enum value */
switch ( irqmode )
{
case GICD_SGI_TARGET_LIST_VAL:
+ sgi_target_init(&target);
+ target.list = (sgir & GICD_SGI_TARGET_MASK) >> GICD_SGI_TARGET_SHIFT;
sgi_mode = SGI_TARGET_LIST;
break;
case GICD_SGI_TARGET_OTHERS_VAL:
return 0;
}
- return vgic_to_sgi(v, sgir, sgi_mode, virq, vcpu_mask);
+ return vgic_to_sgi(v, sgir, sgi_mode, virq, &target);
}
static int vgic_v2_distr_mmio_write(struct vcpu *v, mmio_info_t *info)
int virq;
int irqmode;
enum gic_sgi_mode sgi_mode;
- unsigned long vcpu_mask = 0;
+ struct sgi_target target;
irqmode = (sgir >> ICH_SGI_IRQMODE_SHIFT) & ICH_SGI_IRQMODE_MASK;
virq = (sgir >> ICH_SGI_IRQ_SHIFT ) & ICH_SGI_IRQ_MASK;
- /* SGI's are injected at Rdist level 0. ignoring affinity 1, 2, 3 */
- vcpu_mask = sgir & ICH_SGI_TARGETLIST_MASK;
/* Map GIC sgi value to enum value */
switch ( irqmode )
{
case ICH_SGI_TARGET_LIST:
+ sgi_target_init(&target);
+ /* We assume that only AFF1 is used in ICC_SGI1R_EL1. */
+ target.aff1 = (sgir >> ICH_SGI_AFFINITY_LEVEL(1)) & ICH_SGI_AFFx_MASK;
+ target.list = sgir & ICH_SGI_TARGETLIST_MASK;
sgi_mode = SGI_TARGET_LIST;
break;
case ICH_SGI_TARGET_OTHERS:
return 0;
}
- return vgic_to_sgi(v, sgir, sgi_mode, virq, vcpu_mask);
+ return vgic_to_sgi(v, sgir, sgi_mode, virq, &target);
}
static int vgic_v3_emulate_sysreg(struct cpu_user_regs *regs, union hsr hsr)
}
}
-/* TODO: unsigned long is used to fit vcpu_mask.*/
int vgic_to_sgi(struct vcpu *v, register_t sgir, enum gic_sgi_mode irqmode, int virq,
- unsigned long vcpu_mask)
+ const struct sgi_target *target)
{
struct domain *d = v->domain;
int vcpuid;
int i;
-
- ASSERT(d->max_vcpus < 8*sizeof(vcpu_mask));
+ unsigned int base;
+ unsigned long int bitmap;
ASSERT( virq < 16 );
{
case SGI_TARGET_LIST:
perfc_incr(vgic_sgi_list);
+ base = target->aff1 << 4;
+ bitmap = target->list;
+ for_each_set_bit( i, &bitmap, sizeof(target->list) * 8 )
+ {
+ vcpuid = base + i;
+ if ( d->vcpu[vcpuid] == NULL || !is_vcpu_online(d->vcpu[vcpuid]) )
+ {
+ gprintk(XENLOG_WARNING, "VGIC: write r=%"PRIregister" \
+ target->list=%hx, wrong CPUTargetList \n",
+ sgir, target->list);
+ continue;
+ }
+ vgic_vcpu_inject_irq(d->vcpu[vcpuid], virq);
+ }
break;
case SGI_TARGET_OTHERS:
- /*
- * We expect vcpu_mask to be 0 for SGI_TARGET_OTHERS and
- * SGI_TARGET_SELF mode. So Force vcpu_mask to 0
- */
perfc_incr(vgic_sgi_others);
- vcpu_mask = 0;
for ( i = 0; i < d->max_vcpus; i++ )
{
if ( i != current->vcpu_id && d->vcpu[i] != NULL &&
is_vcpu_online(d->vcpu[i]) )
- set_bit(i, &vcpu_mask);
+ vgic_vcpu_inject_irq(d->vcpu[i], virq);
}
break;
case SGI_TARGET_SELF:
- /*
- * We expect vcpu_mask to be 0 for SGI_TARGET_OTHERS and
- * SGI_TARGET_SELF mode. So Force vcpu_mask to 0
- */
perfc_incr(vgic_sgi_self);
- vcpu_mask = 0;
- set_bit(current->vcpu_id, &vcpu_mask);
+ vgic_vcpu_inject_irq(d->vcpu[current->vcpu_id], virq);
break;
default:
gprintk(XENLOG_WARNING,
return 0;
}
- for_each_set_bit( vcpuid, &vcpu_mask, d->max_vcpus )
- {
- if ( d->vcpu[vcpuid] != NULL && !is_vcpu_online(d->vcpu[vcpuid]) )
- {
- gprintk(XENLOG_WARNING, "VGIC: write r=%"PRIregister" \
- vcpu_mask=%lx, wrong CPUTargetList\n", sgir, vcpu_mask);
- continue;
- }
- vgic_vcpu_inject_irq(d->vcpu[vcpuid], virq);
- }
return 1;
}
#define ICH_SGI_IRQ_SHIFT 24
#define ICH_SGI_IRQ_MASK 0xf
#define ICH_SGI_TARGETLIST_MASK 0xffff
+#define ICH_SGI_AFFx_MASK 0xff
+#define ICH_SGI_AFFINITY_LEVEL(x) (16 * (x))
struct rdist_region {
paddr_t base;
};
};
+struct sgi_target {
+ uint8_t aff1;
+ uint16_t list;
+};
+
+static inline void sgi_target_init(struct sgi_target *sgi_target)
+{
+ sgi_target->aff1 = 0;
+ sgi_target->list = 0;
+}
+
struct vgic_ops {
/* Initialize vGIC */
int (*vcpu_init)(struct vcpu *v);
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,
- unsigned long vcpu_mask);
+ const struct sgi_target *target);
extern void vgic_migrate_irq(struct vcpu *old, struct vcpu *new, unsigned int irq);
/* Reserve a specific guest vIRQ */