Skip to content

Commit e45115b

Browse files
rkrcmarbonzini
authored andcommitted
KVM: x86: use physical LAPIC array for logical x2APIC
Logical x2APIC IDs map injectively to physical x2APIC IDs, so we can reuse the physical array for them. This allows us to save space by sizing the logical maps according to the needs of xAPIC. Signed-off-by: Radim Krčmář <[email protected]> Signed-off-by: Paolo Bonzini <[email protected]>
1 parent 64aa47b commit e45115b

File tree

2 files changed

+41
-38
lines changed

2 files changed

+41
-38
lines changed

arch/x86/include/asm/kvm_host.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -683,8 +683,10 @@ struct kvm_apic_map {
683683
struct rcu_head rcu;
684684
u8 mode;
685685
struct kvm_lapic *phys_map[256];
686-
/* first index is cluster id second is cpu id in a cluster */
687-
struct kvm_lapic *logical_map[16][16];
686+
union {
687+
struct kvm_lapic *xapic_flat_map[8];
688+
struct kvm_lapic *xapic_cluster_map[16][4];
689+
};
688690
};
689691

690692
/* Hyper-V emulation context */

arch/x86/kvm/lapic.c

Lines changed: 37 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -115,26 +115,36 @@ static inline int apic_enabled(struct kvm_lapic *apic)
115115
(LVT_MASK | APIC_MODE_MASK | APIC_INPUT_POLARITY | \
116116
APIC_LVT_REMOTE_IRR | APIC_LVT_LEVEL_TRIGGER)
117117

118-
/* The logical map is definitely wrong if we have multiple
119-
* modes at the same time. (Physical map is always right.)
120-
*/
121-
static inline bool kvm_apic_logical_map_valid(struct kvm_apic_map *map)
122-
{
123-
return !(map->mode & (map->mode - 1));
124-
}
125-
126-
static inline void
127-
apic_logical_id(struct kvm_apic_map *map, u32 dest_id, u16 *cid, u16 *lid)
128-
{
129-
unsigned lid_bits;
130-
131-
BUILD_BUG_ON(KVM_APIC_MODE_XAPIC_CLUSTER != 4);
132-
BUILD_BUG_ON(KVM_APIC_MODE_XAPIC_FLAT != 8);
133-
BUILD_BUG_ON(KVM_APIC_MODE_X2APIC != 16);
134-
lid_bits = map->mode;
118+
static inline bool kvm_apic_map_get_logical_dest(struct kvm_apic_map *map,
119+
u32 dest_id, struct kvm_lapic ***cluster, u16 *mask) {
120+
switch (map->mode) {
121+
case KVM_APIC_MODE_X2APIC: {
122+
u32 offset = (dest_id >> 16) * 16;
123+
u32 max_apic_id = ARRAY_SIZE(map->phys_map) - 1;
124+
125+
if (offset <= max_apic_id) {
126+
u8 cluster_size = min(max_apic_id - offset + 1, 16U);
127+
128+
*cluster = &map->phys_map[offset];
129+
*mask = dest_id & (0xffff >> (16 - cluster_size));
130+
} else {
131+
*mask = 0;
132+
}
135133

136-
*cid = dest_id >> lid_bits;
137-
*lid = dest_id & ((1 << lid_bits) - 1);
134+
return true;
135+
}
136+
case KVM_APIC_MODE_XAPIC_FLAT:
137+
*cluster = map->xapic_flat_map;
138+
*mask = dest_id & 0xff;
139+
return true;
140+
case KVM_APIC_MODE_XAPIC_CLUSTER:
141+
*cluster = map->xapic_cluster_map[dest_id >> 4];
142+
*mask = dest_id & 0xf;
143+
return true;
144+
default:
145+
/* Not optimized. */
146+
return false;
147+
}
138148
}
139149

140150
static void recalculate_apic_map(struct kvm *kvm)
@@ -152,7 +162,8 @@ static void recalculate_apic_map(struct kvm *kvm)
152162

153163
kvm_for_each_vcpu(i, vcpu, kvm) {
154164
struct kvm_lapic *apic = vcpu->arch.apic;
155-
u16 cid, lid;
165+
struct kvm_lapic **cluster;
166+
u16 mask;
156167
u32 ldr, aid;
157168

158169
if (!kvm_apic_present(vcpu))
@@ -174,13 +185,11 @@ static void recalculate_apic_map(struct kvm *kvm)
174185
new->mode |= KVM_APIC_MODE_XAPIC_CLUSTER;
175186
}
176187

177-
if (!kvm_apic_logical_map_valid(new))
188+
if (!kvm_apic_map_get_logical_dest(new, ldr, &cluster, &mask))
178189
continue;
179190

180-
apic_logical_id(new, ldr, &cid, &lid);
181-
182-
if (lid && cid < ARRAY_SIZE(new->logical_map))
183-
new->logical_map[cid][ffs(lid) - 1] = apic;
191+
if (mask)
192+
cluster[ffs(mask) - 1] = apic;
184193
}
185194
out:
186195
old = rcu_dereference_protected(kvm->arch.apic_map,
@@ -685,7 +694,6 @@ static inline bool kvm_apic_map_get_dest_lapic(struct kvm *kvm,
685694
{
686695
int i, lowest;
687696
bool x2apic_ipi;
688-
u16 cid;
689697

690698
if (irq->shorthand == APIC_DEST_SELF && src) {
691699
*dst = src;
@@ -711,18 +719,11 @@ static inline bool kvm_apic_map_get_dest_lapic(struct kvm *kvm,
711719
return true;
712720
}
713721

714-
if (!kvm_apic_logical_map_valid(map))
722+
*bitmap = 0;
723+
if (!kvm_apic_map_get_logical_dest(map, irq->dest_id, dst,
724+
(u16 *)bitmap))
715725
return false;
716726

717-
apic_logical_id(map, irq->dest_id, &cid, (u16 *)bitmap);
718-
719-
if (cid >= ARRAY_SIZE(map->logical_map)) {
720-
*bitmap = 0;
721-
return true;
722-
}
723-
724-
*dst = map->logical_map[cid];
725-
726727
if (!kvm_lowest_prio_delivery(irq))
727728
return true;
728729

0 commit comments

Comments
 (0)