Message ID | 20211203024311.49865-3-ilkka@os.amperecomputing.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | ACPI: Arm Generic Diagnostic Dump and Reset device | expand |
Hi, On Thu, Dec 02, 2021 at 06:43:11PM -0800, Ilkka Koskinen wrote: > +static int __init agdi_init(void) > +{ > + int ret; > + acpi_status status; > + struct acpi_table_agdi *agdi_table; > + struct agdi_data *pdata; > + struct platform_device *pdev; > + > + if (acpi_disabled) > + return 0; > + > + status = acpi_get_table(ACPI_SIG_AGDI, 0, > + (struct acpi_table_header **) &agdi_table); > + if (ACPI_FAILURE(status)) > + return -ENODEV; > + > + pdata = kzalloc(sizeof(*pdata), GFP_ATOMIC); Why does this need to be GFP_ATOMIC? Also, struct agdi_data is a single int in size, why do you need to kzalloc() it? > + if (!pdata) { > + ret = -ENOMEM; > + goto err_put_table; > + } > + > + if (agdi_table->flags & ACPI_AGDI_SIGNALING_MODE) { > + pr_warn("Interrupt signaling is not supported"); > + ret = -ENODEV; > + goto err_free_pdata; > + } > + > + pdata->sdei_event = agdi_table->sdei_event; > + > + pdev = platform_device_register_data(NULL, "agdi", 0, pdata, sizeof(*pdata)); platform_device_register_data() uses kmemdup() internally with the platform data, meaning it takes a copy of the platform data. There is no need for the pdata allocation to persist past this point. Hence, given that it is a single int in size, you may as well put "struct agdi_data" on the stack. Thanks.
Hi, Thanks for reviewing the patch On Thu, 9 Dec 2021, Russell King (Oracle) wrote: > Hi, > > On Thu, Dec 02, 2021 at 06:43:11PM -0800, Ilkka Koskinen wrote: >> +static int __init agdi_init(void) >> +{ >> + int ret; >> + acpi_status status; >> + struct acpi_table_agdi *agdi_table; >> + struct agdi_data *pdata; >> + struct platform_device *pdev; >> + >> + if (acpi_disabled) >> + return 0; >> + >> + status = acpi_get_table(ACPI_SIG_AGDI, 0, >> + (struct acpi_table_header **) &agdi_table); >> + if (ACPI_FAILURE(status)) >> + return -ENODEV; >> + >> + pdata = kzalloc(sizeof(*pdata), GFP_ATOMIC); > > Why does this need to be GFP_ATOMIC? Also, struct agdi_data is a single > int in size, why do you need to kzalloc() it? There's no reason for that. It should obviously be GFP_KERNEL > >> + if (!pdata) { >> + ret = -ENOMEM; >> + goto err_put_table; >> + } >> + >> + if (agdi_table->flags & ACPI_AGDI_SIGNALING_MODE) { >> + pr_warn("Interrupt signaling is not supported"); >> + ret = -ENODEV; >> + goto err_free_pdata; >> + } >> + >> + pdata->sdei_event = agdi_table->sdei_event; >> + >> + pdev = platform_device_register_data(NULL, "agdi", 0, pdata, sizeof(*pdata)); > > platform_device_register_data() uses kmemdup() internally with the > platform data, meaning it takes a copy of the platform data. There is > no need for the pdata allocation to persist past this point. Hence, > given that it is a single int in size, you may as well put > "struct agdi_data" on the stack. I somehow missed kmemdup() part. I remove the allocation and move pdata to the stack instead. Thanks, Ilkka > > Thanks. > > -- > RMK's Patch system: https://www.armlinux.org.uk/developer/patches/ > FTTP is here! 40Mbps down 10Mbps up. Decent connectivity at last! >
diff --git a/drivers/acpi/arm64/Kconfig b/drivers/acpi/arm64/Kconfig index 6dba187f4f2e..24869ba5b365 100644 --- a/drivers/acpi/arm64/Kconfig +++ b/drivers/acpi/arm64/Kconfig @@ -8,3 +8,11 @@ config ACPI_IORT config ACPI_GTDT bool + +config ACPI_AGDI + bool "Arm Generic Diagnostic Dump and Reset Device Interface" + depends on ARM_SDE_INTERFACE + help + Arm Generic Diagnostic Dump and Reset Device Interface (AGDI) is + a standard that enables issuing a non-maskable diagnostic dump and + reset command. diff --git a/drivers/acpi/arm64/Makefile b/drivers/acpi/arm64/Makefile index 66acbe77f46e..7b9e4045659d 100644 --- a/drivers/acpi/arm64/Makefile +++ b/drivers/acpi/arm64/Makefile @@ -1,4 +1,5 @@ # SPDX-License-Identifier: GPL-2.0-only +obj-$(CONFIG_ACPI_AGDI) += agdi.o obj-$(CONFIG_ACPI_IORT) += iort.o obj-$(CONFIG_ACPI_GTDT) += gtdt.o obj-y += dma.o diff --git a/drivers/acpi/arm64/agdi.c b/drivers/acpi/arm64/agdi.c new file mode 100644 index 000000000000..cdd8811df3d5 --- /dev/null +++ b/drivers/acpi/arm64/agdi.c @@ -0,0 +1,133 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * This file implements handling of + * Arm Generic Diagnostic Dump and Reset Interface table (AGDI) + * + * Copyright (c) 2021, Ampere Computing LLC + */ + +#define pr_fmt(fmt) "ACPI: AGDI: " fmt + +#include <linux/kernel.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/acpi.h> +#include <linux/arm_sdei.h> +#include <linux/io.h> + +struct agdi_data { + int sdei_event; +}; + +static int agdi_sdei_handler(u32 sdei_event, struct pt_regs *regs, void *arg) +{ + nmi_panic(regs, "Arm Generic Diagnostic Dump and Reset SDEI event issued"); + return 0; +} + +static int agdi_sdei_probe(struct platform_device *pdev, + struct agdi_data *adata) +{ + int err; + + err = sdei_event_register(adata->sdei_event, agdi_sdei_handler, pdev); + if (err) { + dev_err(&pdev->dev, "Failed to register for SDEI event %d", + adata->sdei_event); + return err; + } + + err = sdei_event_enable(adata->sdei_event); + if (err) { + sdei_event_unregister(adata->sdei_event); + dev_err(&pdev->dev, "Failed to enable event %d\n", + adata->sdei_event); + return err; + } + + return 0; +} + +static int agdi_probe(struct platform_device *pdev) +{ + struct agdi_data *adata; + + adata = dev_get_platdata(&pdev->dev); + if (!adata) + return -EINVAL; + + return agdi_sdei_probe(pdev, adata); +} + +static int agdi_remove(struct platform_device *pdev) +{ + struct agdi_data *adata = platform_get_drvdata(pdev); + + sdei_event_disable(adata->sdei_event); + sdei_event_unregister(adata->sdei_event); + + return 0; +} + +static struct platform_driver agdi_driver = { + .driver = { + .name = "agdi", + }, + .probe = agdi_probe, + .remove = agdi_remove, +}; + +static int __init agdi_init(void) +{ + int ret; + acpi_status status; + struct acpi_table_agdi *agdi_table; + struct agdi_data *pdata; + struct platform_device *pdev; + + if (acpi_disabled) + return 0; + + status = acpi_get_table(ACPI_SIG_AGDI, 0, + (struct acpi_table_header **) &agdi_table); + if (ACPI_FAILURE(status)) + return -ENODEV; + + pdata = kzalloc(sizeof(*pdata), GFP_ATOMIC); + if (!pdata) { + ret = -ENOMEM; + goto err_put_table; + } + + if (agdi_table->flags & ACPI_AGDI_SIGNALING_MODE) { + pr_warn("Interrupt signaling is not supported"); + ret = -ENODEV; + goto err_free_pdata; + } + + pdata->sdei_event = agdi_table->sdei_event; + + pdev = platform_device_register_data(NULL, "agdi", 0, pdata, sizeof(*pdata)); + if (IS_ERR(pdev)) { + ret = PTR_ERR(pdev); + goto err_free_pdata; + } + + ret = platform_driver_register(&agdi_driver); + if (ret) + goto err_device_unregister; + + acpi_put_table((struct acpi_table_header *)agdi_table); + return 0; + +err_device_unregister: + platform_device_unregister(pdev); +err_free_pdata: + kfree(pdata); +err_put_table: + acpi_put_table((struct acpi_table_header *)agdi_table); + return ret; +} +device_initcall(agdi_init);
ACPI for Arm Components 1.1 Platform Design Document v1.1 [0] specifices Arm Generic Diagnostic Device Interface (AGDI). It allows an admin to issue diagnostic dump and reset via an SDEI event or an interrupt. This patch implements SDEI path. [0] https://developer.arm.com/documentation/den0093/latest/ Signed-off-by: Ilkka Koskinen <ilkka@os.amperecomputing.com> --- drivers/acpi/arm64/Kconfig | 8 +++ drivers/acpi/arm64/Makefile | 1 + drivers/acpi/arm64/agdi.c | 133 ++++++++++++++++++++++++++++++++++++ 3 files changed, 142 insertions(+) create mode 100644 drivers/acpi/arm64/agdi.c