Skip to content

Commit f3cf936

Browse files
Sainath Grandhiwenlingz
authored andcommitted
hv: Handle holes in GSI i.e. Global System Interrupt for multiple IO-APICs
MADT is used to specify the GSI base for each IO-APIC and the number of interrupt pins per IO-APIC is programmed into Max. Redir. Entry register of that IO-APIC. On platforms with multiple IO-APICs, there can be holes in the GSI space. For example, on a platform with 2 IO-APICs, the following configuration has a hole (from 24 to 31) in the GSI space. IO-APIC 1: GSI base - 0, number of pins - 24 IO-APIC 2: GSI base - 32, number of pins - 8 This patch also adjusts the size for variables used to represent the total number of IO-APICs on the system from uint16_t to uint8_t as the ACPI MADT uses only 8-bits to indicate the unique IO-APIC IDs. Tracked-On: #4151 Signed-off-by: Sainath Grandhi <sainath.grandhi@intel.com> Acked-by: Eddie Dong <eddie.dong@Intel.com>
1 parent ec86921 commit f3cf936

File tree

7 files changed

+114
-125
lines changed

7 files changed

+114
-125
lines changed

hypervisor/arch/x86/ioapic.c

Lines changed: 72 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -15,43 +15,18 @@
1515
#include <acpi.h>
1616
#include <logmsg.h>
1717

18-
#define IOAPIC_INVALID_ID 0xFFU
19-
2018
#define NR_MAX_GSI (CONFIG_MAX_IOAPIC_NUM * CONFIG_MAX_IOAPIC_LINES)
2119

2220
static struct gsi_table gsi_table_data[NR_MAX_GSI];
23-
static uint32_t ioapic_nr_gsi;
21+
static uint32_t ioapic_max_nr_gsi;
2422
static spinlock_t ioapic_lock;
2523

2624
static union ioapic_rte saved_rte[CONFIG_MAX_IOAPIC_NUM][CONFIG_MAX_IOAPIC_LINES];
2725

28-
/*
29-
* the irq to ioapic pin mapping should extract from ACPI MADT table
30-
* hardcoded here
31-
*/
32-
static const uint32_t legacy_irq_to_pin[NR_LEGACY_IRQ] = {
33-
2U, /* IRQ0*/
34-
1U, /* IRQ1*/
35-
0U, /* IRQ2 connected to Pin0 (ExtInt source of PIC) if existing */
36-
3U, /* IRQ3*/
37-
4U, /* IRQ4*/
38-
5U, /* IRQ5*/
39-
6U, /* IRQ6*/
40-
7U, /* IRQ7*/
41-
8U, /* IRQ8*/
42-
9U, /* IRQ9*/
43-
10U, /* IRQ10*/
44-
11U, /* IRQ11*/
45-
12U, /* IRQ12*/
46-
13U, /* IRQ13*/
47-
14U, /* IRQ14*/
48-
15U, /* IRQ15*/
49-
};
50-
51-
static const uint32_t legacy_irq_trigger_mode[NR_LEGACY_IRQ] = {
52-
IOAPIC_RTE_TRGRMODE_EDGE, /* IRQ0*/
53-
IOAPIC_RTE_TRGRMODE_EDGE, /* IRQ1*/
26+
static const uint32_t legacy_irq_trigger_mode[NR_LEGACY_PIN] = {
5427
IOAPIC_RTE_TRGRMODE_EDGE, /* IRQ2*/
28+
IOAPIC_RTE_TRGRMODE_EDGE, /* IRQ1*/
29+
IOAPIC_RTE_TRGRMODE_EDGE, /* IRQ0*/
5530
IOAPIC_RTE_TRGRMODE_EDGE, /* IRQ3*/
5631
IOAPIC_RTE_TRGRMODE_EDGE, /* IRQ4*/
5732
IOAPIC_RTE_TRGRMODE_EDGE, /* IRQ5*/
@@ -87,7 +62,7 @@ static const uint32_t pic_ioapic_pin_map[NR_LEGACY_PIN] = {
8762
};
8863

8964
static struct ioapic_info ioapic_array[CONFIG_MAX_IOAPIC_NUM];
90-
static uint16_t ioapic_num;
65+
static uint8_t ioapic_num;
9166

9267
uint32_t get_pic_pin_from_ioapic_pin(uint32_t pin_index)
9368
{
@@ -104,12 +79,12 @@ uint32_t get_pic_pin_from_ioapic_pin(uint32_t pin_index)
10479
void *gsi_to_ioapic_base(uint32_t gsi)
10580
{
10681

107-
return gsi_table_data[gsi].addr;
82+
return gsi_table_data[gsi].ioapic_info.base_addr;
10883
}
10984

110-
uint32_t ioapic_get_nr_gsi(void)
85+
uint32_t get_max_nr_gsi(void)
11186
{
112-
return ioapic_nr_gsi;
87+
return ioapic_max_nr_gsi;
11388
}
11489

11590
static void *map_ioapic(uint64_t ioapic_paddr)
@@ -211,7 +186,7 @@ create_rte_for_gsi_irq(uint32_t irq, uint32_t vr)
211186

212187
rte.full = 0UL;
213188

214-
if (irq < NR_LEGACY_IRQ) {
189+
if (irq < NR_LEGACY_PIN) {
215190
rte = create_rte_for_legacy_irq(irq, vr);
216191
} else {
217192
/* irq default masked, level trig */
@@ -238,7 +213,7 @@ static void ioapic_set_routing(uint32_t gsi, uint32_t vr)
238213

239214
ioapic_base = gsi_to_ioapic_base(gsi);
240215
rte = create_rte_for_gsi_irq(gsi, vr);
241-
ioapic_set_rte_entry(ioapic_base, gsi_table_data[gsi].pin, rte);
216+
ioapic_set_rte_entry(ioapic_base, gsi_table_data[gsi].ioapic_info.pin, rte);
242217

243218
if (rte.bits.trigger_mode == IOAPIC_RTE_TRGRMODE_LEVEL) {
244219
set_irq_trigger_mode(gsi, true);
@@ -247,62 +222,71 @@ static void ioapic_set_routing(uint32_t gsi, uint32_t vr)
247222
}
248223

249224
dev_dbg(DBG_LEVEL_IRQ, "GSI: irq:%d pin:%hhu rte:%lx",
250-
gsi, gsi_table_data[gsi].pin,
225+
gsi, gsi_table_data[gsi].ioapic_info.pin,
251226
rte.full);
252227
}
253228

254-
/**
229+
/*
255230
* @pre rte != NULL
231+
* @pre is_ioapic_irq(irq) == true
256232
*/
257233
void ioapic_get_rte(uint32_t irq, union ioapic_rte *rte)
258234
{
259235
void *addr;
260236

261-
if (ioapic_irq_is_gsi(irq)) {
262-
addr = gsi_to_ioapic_base(irq);
263-
ioapic_get_rte_entry(addr, gsi_table_data[irq].pin, rte);
264-
}
237+
addr = gsi_to_ioapic_base(irq);
238+
ioapic_get_rte_entry(addr, gsi_table_data[irq].ioapic_info.pin, rte);
265239
}
266240

241+
/*
242+
* @pre is_ioapic_irq(irq) == true
243+
*/
267244
void ioapic_set_rte(uint32_t irq, union ioapic_rte rte)
268245
{
269246
void *addr;
270247

271-
if (ioapic_irq_is_gsi(irq)) {
272-
addr = gsi_to_ioapic_base(irq);
273-
ioapic_set_rte_entry(addr, gsi_table_data[irq].pin, rte);
248+
addr = gsi_to_ioapic_base(irq);
249+
ioapic_set_rte_entry(addr, gsi_table_data[irq].ioapic_info.pin, rte);
274250

275-
dev_dbg(DBG_LEVEL_IRQ, "GSI: irq:%d pin:%hhu rte:%lx",
276-
irq, gsi_table_data[irq].pin,
277-
rte.full);
278-
}
251+
dev_dbg(DBG_LEVEL_IRQ, "GSI: irq:%d pin:%hhu rte:%lx",
252+
irq, gsi_table_data[irq].ioapic_info.pin,
253+
rte.full);
279254
}
280255

281-
bool ioapic_irq_is_gsi(uint32_t irq)
256+
/*
257+
* Checks if the gsi is valid
258+
* 1) gsi < NR_MAX_GSI
259+
* 2) gsi is valid on the platform according to ACPI MADT info
260+
*/
261+
bool is_gsi_valid(uint32_t gsi)
282262
{
283-
return irq < ioapic_nr_gsi;
263+
264+
return (gsi < NR_MAX_GSI) && (gsi_table_data[gsi].is_valid);
284265
}
285266

286-
uint32_t ioapic_irq_to_pin(uint32_t irq)
287-
{
288-
uint32_t ret;
267+
/*
268+
* IO-APIC gsi and irq are identity mapped in ioapic_setup_irqs
269+
* So #gsi = #irq for ACRN
270+
*/
289271

290-
if (ioapic_irq_is_gsi(irq)) {
291-
ret = gsi_table_data[irq].pin;
292-
} else {
293-
ret = INVALID_INTERRUPT_PIN;
294-
}
272+
bool is_ioapic_irq(uint32_t irq)
273+
{
295274

296-
return ret;
275+
return is_gsi_valid(irq);
297276
}
298277

299-
bool ioapic_is_pin_valid(uint32_t pin)
278+
/*
279+
*@pre gsi < NR_MAX_GSI
280+
*@pre is_gsi_valid(gsi) == true
281+
*/
282+
283+
uint32_t gsi_to_ioapic_pin(uint32_t gsi)
300284
{
301-
return (pin != INVALID_INTERRUPT_PIN);
285+
return gsi_table_data[gsi].ioapic_info.pin;
302286
}
303287

304288
/*
305-
*@pre ioapic_irq_is_gsi(gsi) == true
289+
*@pre is_gsi_valid(gsi) == true
306290
*/
307291
uint32_t ioapic_gsi_to_irq(uint32_t gsi)
308292
{
@@ -316,23 +300,21 @@ ioapic_irq_gsi_mask_unmask(uint32_t irq, bool mask)
316300
uint32_t pin;
317301
union ioapic_rte rte;
318302

319-
if (ioapic_irq_is_gsi(irq)) {
320-
addr = gsi_to_ioapic_base(irq);
321-
pin = gsi_table_data[irq].pin;
303+
addr = gsi_to_ioapic_base(irq);
304+
pin = gsi_table_data[irq].ioapic_info.pin;
322305

323-
if (addr != NULL) {
324-
ioapic_get_rte_entry(addr, pin, &rte);
325-
if (mask) {
326-
rte.bits.intr_mask = IOAPIC_RTE_MASK_SET;
327-
} else {
328-
rte.bits.intr_mask = IOAPIC_RTE_MASK_CLR;
329-
}
330-
ioapic_set_rte_entry(addr, pin, rte);
331-
dev_dbg(DBG_LEVEL_PTIRQ, "update: irq:%d pin:%hhu rte:%lx",
332-
irq, pin, rte.full);
306+
if (addr != NULL) {
307+
ioapic_get_rte_entry(addr, pin, &rte);
308+
if (mask) {
309+
rte.bits.intr_mask = IOAPIC_RTE_MASK_SET;
333310
} else {
334-
dev_dbg(DBG_LEVEL_PTIRQ, "NULL Address returned from gsi_table_data");
311+
rte.bits.intr_mask = IOAPIC_RTE_MASK_CLR;
335312
}
313+
ioapic_set_rte_entry(addr, pin, rte);
314+
dev_dbg(DBG_LEVEL_PTIRQ, "update: irq:%d pin:%hhu rte:%lx",
315+
irq, pin, rte.full);
316+
} else {
317+
dev_dbg(DBG_LEVEL_PTIRQ, "NULL Address returned from gsi_table_data");
336318
}
337319
}
338320

@@ -364,17 +346,13 @@ ioapic_nr_pins(void *ioapic_base)
364346
return nr_pins;
365347
}
366348

349+
/*
350+
* @pre is_ioapic_irq(irq) == true
351+
*/
367352
uint8_t ioapic_irq_to_ioapic_id(uint32_t irq)
368353
{
369-
uint8_t ret;
370-
371-
if (ioapic_irq_is_gsi(irq)) {
372-
ret = gsi_table_data[irq].ioapic_id;
373-
} else {
374-
ret = IOAPIC_INVALID_ID;
375-
}
376354

377-
return ret;
355+
return gsi_table_data[irq].ioapic_info.acpi_id;
378356
}
379357

380358
int32_t init_ioapic_id_info(void)
@@ -385,7 +363,7 @@ int32_t init_ioapic_id_info(void)
385363
uint32_t nr_pins, gsi;
386364

387365
ioapic_num = parse_madt_ioapic(&ioapic_array[0]);
388-
if (ioapic_num <= (uint16_t)CONFIG_MAX_IOAPIC_NUM) {
366+
if (ioapic_num <= (uint8_t)CONFIG_MAX_IOAPIC_NUM) {
389367
/*
390368
* Iterate thru all the IO-APICs on the platform
391369
* Check the number of pins available on each IOAPIC is less
@@ -415,7 +393,7 @@ int32_t init_ioapic_id_info(void)
415393
*/
416394

417395
if (ret == 0) {
418-
if (gsi < (uint32_t) NR_LEGACY_IRQ) {
396+
if (gsi < (uint32_t) NR_LEGACY_PIN) {
419397
pr_err ("Total pin count (%x) is less than NR_LEGACY_IRQ!", gsi);
420398
ret = -EINVAL;
421399
}
@@ -446,16 +424,13 @@ void ioapic_setup_irqs(void)
446424
addr = map_ioapic(ioapic_array[ioapic_id].addr);
447425

448426
nr_pins = ioapic_array[ioapic_id].nr_pins;
427+
gsi = ioapic_array[ioapic_id].gsi_base;
449428
for (pin = 0U; pin < nr_pins; pin++) {
450-
gsi_table_data[gsi].ioapic_id = ioapic_array[ioapic_id].id;
451-
gsi_table_data[gsi].addr = addr;
452-
453-
if (gsi < NR_LEGACY_IRQ) {
454-
gsi_table_data[gsi].pin =
455-
legacy_irq_to_pin[gsi] & 0xffU;
456-
} else {
457-
gsi_table_data[gsi].pin = pin;
458-
}
429+
gsi_table_data[gsi].is_valid = true;
430+
gsi_table_data[gsi].ioapic_info.acpi_id = ioapic_array[ioapic_id].id;
431+
gsi_table_data[gsi].ioapic_info.base_addr = addr;
432+
gsi_table_data[gsi].ioapic_info.pin = pin;
433+
gsi_table_data[gsi].ioapic_info.index = ioapic_id;
459434

460435
/* pinned irq before use it */
461436
if (alloc_irq_num(gsi) == IRQ_INVALID) {
@@ -467,7 +442,7 @@ void ioapic_setup_irqs(void)
467442
/* assign vector for this GSI
468443
* for legacy irq, reserved vector and never free
469444
*/
470-
if (gsi < NR_LEGACY_IRQ) {
445+
if (gsi < NR_LEGACY_PIN) {
471446
vr = alloc_irq_vector(gsi);
472447
if (vr == VECTOR_INVALID) {
473448
pr_err("failed to alloc VR");
@@ -484,7 +459,7 @@ void ioapic_setup_irqs(void)
484459
}
485460

486461
/* system max gsi numbers */
487-
ioapic_nr_gsi = gsi;
462+
ioapic_max_nr_gsi = gsi;
488463
}
489464

490465
void suspend_ioapic(void)

hypervisor/arch/x86/irq.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ static void free_irq_num(uint32_t irq)
8282
uint64_t rflags;
8383

8484
if (irq < NR_IRQS) {
85-
if (!ioapic_irq_is_gsi(irq)) {
85+
if (!is_ioapic_irq(irq)) {
8686
spinlock_irqsave_obtain(&irq_alloc_spinlock, &rflags);
8787
(void)bitmap_test_and_clear_nolock((uint16_t)(irq & 0x3FU),
8888
irq_alloc_bitmap + (irq >> 6U));
@@ -301,15 +301,15 @@ static inline bool irq_need_mask(const struct irq_desc *desc)
301301
{
302302
/* level triggered gsi should be masked */
303303
return (((desc->flags & IRQF_LEVEL) != 0U)
304-
&& ioapic_irq_is_gsi(desc->irq));
304+
&& is_ioapic_irq(desc->irq));
305305
}
306306

307307
static inline bool irq_need_unmask(const struct irq_desc *desc)
308308
{
309309
/* level triggered gsi for non-ptdev should be unmasked */
310310
return (((desc->flags & IRQF_LEVEL) != 0U)
311311
&& ((desc->flags & IRQF_PT) == 0U)
312-
&& ioapic_irq_is_gsi(desc->irq));
312+
&& is_ioapic_irq(desc->irq));
313313
}
314314

315315
static inline void handle_irq(const struct irq_desc *desc)

hypervisor/boot/acpi_base.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -209,14 +209,14 @@ local_parse_madt(struct acpi_table_madt *madt, uint32_t lapic_id_array[MAX_PCPU_
209209
return pcpu_num;
210210
}
211211

212-
static uint16_t
212+
static uint8_t
213213
ioapic_parse_madt(void *madt, struct ioapic_info *ioapic_id_array)
214214
{
215215
struct acpi_madt_ioapic *ioapic;
216216
struct acpi_table_madt *madt_ptr;
217217
void *first, *end, *iterator;
218218
struct acpi_subtable_header *entry;
219-
uint16_t ioapic_idx = 0U;
219+
uint8_t ioapic_idx = 0U;
220220

221221
madt_ptr = (struct acpi_table_madt *)madt;
222222

@@ -261,9 +261,9 @@ uint16_t parse_madt(uint32_t lapic_id_array[MAX_PCPU_NUM])
261261
return ret;
262262
}
263263

264-
uint16_t parse_madt_ioapic(struct ioapic_info *ioapic_id_array)
264+
uint8_t parse_madt_ioapic(struct ioapic_info *ioapic_id_array)
265265
{
266-
uint16_t ret = 0U;
266+
uint8_t ret = 0U;
267267
struct acpi_table_rsdp *rsdp = NULL;
268268

269269
rsdp = get_rsdp();

hypervisor/boot/include/acpi.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ void *get_acpi_tbl(const char *signature);
203203

204204
struct ioapic_info;
205205
uint16_t parse_madt(uint32_t lapic_id_array[MAX_PCPU_NUM]);
206-
uint16_t parse_madt_ioapic(struct ioapic_info *ioapic_id_array);
206+
uint8_t parse_madt_ioapic(struct ioapic_info *ioapic_id_array);
207207

208208
#ifdef CONFIG_ACPI_PARSE_ENABLED
209209
int32_t acpi_fixup(void);

hypervisor/common/hypercall.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -908,7 +908,7 @@ int32_t hcall_set_ptdev_intr_info(struct acrn_vm *vm, uint16_t vmid, uint64_t pa
908908
if ((vdev != NULL) && (vdev->pdev->bdf.value == irq.phys_bdf)) {
909909
if ((((!irq.intx.pic_pin) && (irq.intx.virt_pin < vioapic_pincount(target_vm))) ||
910910
((irq.intx.pic_pin) && (irq.intx.virt_pin < vpic_pincount()))) &&
911-
ioapic_irq_is_gsi(irq.intx.phys_pin)) {
911+
is_gsi_valid(irq.intx.phys_pin)) {
912912
ret = ptirq_add_intx_remapping(target_vm, irq.intx.virt_pin,
913913
irq.intx.phys_pin, irq.intx.pic_pin);
914914
} else {

0 commit comments

Comments
 (0)