Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ACPI: GTDT: Don't corrupt interrupt mappings on watchdow probe failure

When failing the driver probe because of invalid firmware properties,
the GTDT driver unmaps the interrupt that it mapped earlier.

However, it never checks whether the mapping of the interrupt actially
succeeded. Even more, should the firmware report an illegal interrupt
number that overlaps with the GIC SGI range, this can result in an
IPI being unmapped, and subsequent fireworks (as reported by Dann
Frazier).

Rework the driver to have a slightly saner behaviour and actually
check whether the interrupt has been mapped before unmapping things.

Reported-by: dann frazier <dann.frazier@canonical.com>
Fixes: ca9ae5ec4ef0 ("acpi/arm64: Add SBSA Generic Watchdog support in GTDT driver")
Signed-off-by: Marc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/YH87dtTfwYgavusz@xps13.dannf
Cc: <stable@vger.kernel.org>
Cc: Fu Wei <wefu@redhat.com>
Reviewed-by: Sudeep Holla <sudeep.holla@arm.com>
Tested-by: dann frazier <dann.frazier@canonical.com>
Tested-by: Hanjun Guo <guohanjun@huawei.com>
Reviewed-by: Hanjun Guo <guohanjun@huawei.com>
Reviewed-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Link: https://lore.kernel.org/r/20210421164317.1718831-2-maz@kernel.org
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>

authored by

Marc Zyngier and committed by
Catalin Marinas
1ecd5b12 0bca3ec8

+6 -4
+6 -4
drivers/acpi/arm64/gtdt.c
··· 329 329 int index) 330 330 { 331 331 struct platform_device *pdev; 332 - int irq = map_gt_gsi(wd->timer_interrupt, wd->timer_flags); 332 + int irq; 333 333 334 334 /* 335 335 * According to SBSA specification the size of refresh and control ··· 338 338 struct resource res[] = { 339 339 DEFINE_RES_MEM(wd->control_frame_address, SZ_4K), 340 340 DEFINE_RES_MEM(wd->refresh_frame_address, SZ_4K), 341 - DEFINE_RES_IRQ(irq), 341 + {}, 342 342 }; 343 343 int nr_res = ARRAY_SIZE(res); 344 344 ··· 348 348 349 349 if (!(wd->refresh_frame_address && wd->control_frame_address)) { 350 350 pr_err(FW_BUG "failed to get the Watchdog base address.\n"); 351 - acpi_unregister_gsi(wd->timer_interrupt); 352 351 return -EINVAL; 353 352 } 354 353 354 + irq = map_gt_gsi(wd->timer_interrupt, wd->timer_flags); 355 + res[2] = (struct resource)DEFINE_RES_IRQ(irq); 355 356 if (irq <= 0) { 356 357 pr_warn("failed to map the Watchdog interrupt.\n"); 357 358 nr_res--; ··· 365 364 */ 366 365 pdev = platform_device_register_simple("sbsa-gwdt", index, res, nr_res); 367 366 if (IS_ERR(pdev)) { 368 - acpi_unregister_gsi(wd->timer_interrupt); 367 + if (irq > 0) 368 + acpi_unregister_gsi(wd->timer_interrupt); 369 369 return PTR_ERR(pdev); 370 370 } 371 371