Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3b5a5ffa authored by Radim Krčmář's avatar Radim Krčmář Committed by Paolo Bonzini
Browse files

KVM: x86: simplify kvm_apic_map



recalculate_apic_map() uses two passes over all VCPUs.  This is a relic
from time when we selected a global mode in the first pass and set up
the optimized table in the second pass (to have a consistent mode).

Recent changes made mixed mode unoptimized and we can do it in one pass.
Format of logical MDA is a function of the mode, so we encode it in
apic_logical_id() and drop obsoleted variables from the struct.

Signed-off-by: default avatarRadim Krčmář <rkrcmar@redhat.com>
Message-Id: <1423766494-26150-5-git-send-email-rkrcmar@redhat.com>
[Add lid_bits temporary in apic_logical_id. - Paolo]
Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
parent 3548a259
Loading
Loading
Loading
Loading
+0 −3
Original line number Original line Diff line number Diff line
@@ -562,9 +562,6 @@ struct kvm_arch_memory_slot {
struct kvm_apic_map {
struct kvm_apic_map {
	struct rcu_head rcu;
	struct rcu_head rcu;
	u8 mode;
	u8 mode;
	u8 ldr_bits;
	/* fields bellow are used to decode ldr values in different modes */
	u32 cid_shift, cid_mask, lid_mask;
	struct kvm_lapic *phys_map[256];
	struct kvm_lapic *phys_map[256];
	/* first index is cluster id second is cpu id in a cluster */
	/* first index is cluster id second is cpu id in a cluster */
	struct kvm_lapic *logical_map[16][16];
	struct kvm_lapic *logical_map[16][16];
+28 −50
Original line number Original line Diff line number Diff line
@@ -141,6 +141,20 @@ static inline bool kvm_apic_logical_map_valid(struct kvm_apic_map *map)
	return !(map->mode & (map->mode - 1));
	return !(map->mode & (map->mode - 1));
}
}


static inline void
apic_logical_id(struct kvm_apic_map *map, u32 dest_id, u16 *cid, u16 *lid)
{
	unsigned lid_bits;

	BUILD_BUG_ON(KVM_APIC_MODE_XAPIC_CLUSTER !=  4);
	BUILD_BUG_ON(KVM_APIC_MODE_XAPIC_FLAT    !=  8);
	BUILD_BUG_ON(KVM_APIC_MODE_X2APIC        != 16);
	lid_bits = map->mode;

	*cid = dest_id >> lid_bits;
	*lid = dest_id & ((1 << lid_bits) - 1);
}

static void recalculate_apic_map(struct kvm *kvm)
static void recalculate_apic_map(struct kvm *kvm)
{
{
	struct kvm_apic_map *new, *old = NULL;
	struct kvm_apic_map *new, *old = NULL;
@@ -154,49 +168,6 @@ static void recalculate_apic_map(struct kvm *kvm)
	if (!new)
	if (!new)
		goto out;
		goto out;


	new->ldr_bits = 8;
	/* flat mode is default */
	new->cid_shift = 8;
	new->cid_mask = 0;
	new->lid_mask = 0xff;

	kvm_for_each_vcpu(i, vcpu, kvm) {
		struct kvm_lapic *apic = vcpu->arch.apic;

		if (!kvm_apic_present(vcpu))
			continue;

		if (apic_x2apic_mode(apic)) {
			new->ldr_bits = 32;
			new->cid_shift = 16;
			new->cid_mask = new->lid_mask = 0xffff;
			new->mode |= KVM_APIC_MODE_X2APIC;
		} else if (kvm_apic_get_reg(apic, APIC_LDR)) {
			if (kvm_apic_get_reg(apic, APIC_DFR) ==
							APIC_DFR_CLUSTER) {
				new->cid_shift = 4;
				new->cid_mask = 0xf;
				new->lid_mask = 0xf;
				new->mode |= KVM_APIC_MODE_XAPIC_CLUSTER;
			} else {
				new->cid_shift = 8;
				new->cid_mask = 0;
				new->lid_mask = 0xff;
				new->mode |= KVM_APIC_MODE_XAPIC_FLAT;
			}
		}

		/*
		 * All APICs have to be configured in the same mode by an OS.
		 * We take advatage of this while building logical id loockup
		 * table. After reset APICs are in software disabled mode, so if
		 * we find apic with different setting we assume this is the mode
		 * OS wants all apics to be in; build lookup table accordingly.
		 */
		if (kvm_apic_sw_enabled(apic))
			break;
	}

	kvm_for_each_vcpu(i, vcpu, kvm) {
	kvm_for_each_vcpu(i, vcpu, kvm) {
		struct kvm_lapic *apic = vcpu->arch.apic;
		struct kvm_lapic *apic = vcpu->arch.apic;
		u16 cid, lid;
		u16 cid, lid;
@@ -207,15 +178,25 @@ static void recalculate_apic_map(struct kvm *kvm)


		aid = kvm_apic_id(apic);
		aid = kvm_apic_id(apic);
		ldr = kvm_apic_get_reg(apic, APIC_LDR);
		ldr = kvm_apic_get_reg(apic, APIC_LDR);
		cid = apic_cluster_id(new, ldr);
		lid = apic_logical_id(new, ldr);


		if (aid < ARRAY_SIZE(new->phys_map))
		if (aid < ARRAY_SIZE(new->phys_map))
			new->phys_map[aid] = apic;
			new->phys_map[aid] = apic;


		if (!kvm_apic_logical_map_valid(new));
		if (apic_x2apic_mode(apic)) {
			new->mode |= KVM_APIC_MODE_X2APIC;
		} else if (ldr) {
			ldr = GET_APIC_LOGICAL_ID(ldr);
			if (kvm_apic_get_reg(apic, APIC_DFR) == APIC_DFR_FLAT)
				new->mode |= KVM_APIC_MODE_XAPIC_FLAT;
			else
				new->mode |= KVM_APIC_MODE_XAPIC_CLUSTER;
		}

		if (!kvm_apic_logical_map_valid(new))
			continue;
			continue;


		apic_logical_id(new, ldr, &cid, &lid);

		if (lid && cid < ARRAY_SIZE(new->logical_map))
		if (lid && cid < ARRAY_SIZE(new->logical_map))
			new->logical_map[cid][ffs(lid) - 1] = apic;
			new->logical_map[cid][ffs(lid) - 1] = apic;
	}
	}
@@ -732,7 +713,6 @@ bool kvm_irq_delivery_to_apic_fast(struct kvm *kvm, struct kvm_lapic *src,


		dst = &map->phys_map[irq->dest_id];
		dst = &map->phys_map[irq->dest_id];
	} else {
	} else {
		u32 mda = irq->dest_id << (32 - map->ldr_bits);
		u16 cid;
		u16 cid;


		if (!kvm_apic_logical_map_valid(map)) {
		if (!kvm_apic_logical_map_valid(map)) {
@@ -740,15 +720,13 @@ bool kvm_irq_delivery_to_apic_fast(struct kvm *kvm, struct kvm_lapic *src,
			goto out;
			goto out;
		}
		}


		cid = apic_cluster_id(map, mda);
		apic_logical_id(map, irq->dest_id, &cid, (u16 *)&bitmap);


		if (cid >= ARRAY_SIZE(map->logical_map))
		if (cid >= ARRAY_SIZE(map->logical_map))
			goto out;
			goto out;


		dst = map->logical_map[cid];
		dst = map->logical_map[cid];


		bitmap = apic_logical_id(map, mda);

		if (irq->delivery_mode == APIC_DM_LOWEST) {
		if (irq->delivery_mode == APIC_DM_LOWEST) {
			int l = -1;
			int l = -1;
			for_each_set_bit(i, &bitmap, 16) {
			for_each_set_bit(i, &bitmap, 16) {
+0 −15
Original line number Original line Diff line number Diff line
@@ -148,21 +148,6 @@ static inline bool kvm_apic_vid_enabled(struct kvm *kvm)
	return kvm_x86_ops->vm_has_apicv(kvm);
	return kvm_x86_ops->vm_has_apicv(kvm);
}
}


static inline u16 apic_cluster_id(struct kvm_apic_map *map, u32 ldr)
{
	u16 cid;
	ldr >>= 32 - map->ldr_bits;
	cid = (ldr >> map->cid_shift) & map->cid_mask;

	return cid;
}

static inline u16 apic_logical_id(struct kvm_apic_map *map, u32 ldr)
{
	ldr >>= (32 - map->ldr_bits);
	return ldr & map->lid_mask;
}

static inline bool kvm_apic_has_events(struct kvm_vcpu *vcpu)
static inline bool kvm_apic_has_events(struct kvm_vcpu *vcpu)
{
{
	return vcpu->arch.apic->pending_events;
	return vcpu->arch.apic->pending_events;