diff mbox

[3/3] ACPI: ARM64: support for ACPI_TABLE_UPGRADE

Message ID 1463486765-31827-4-git-send-email-aleksey.makarov@linaro.org (mailing list archive)
State New, archived
Headers show

Commit Message

Aleksey Makarov May 17, 2016, 12:06 p.m. UTC
From: Jon Masters <jcm@redhat.com>

This patch adds support for ACPI_TABLE_UPGRADE for ARM64

To access initrd image we need to move initialization
of linear mapping a bit earlier.

Signed-off-by: Jon Masters <jcm@redhat.com>
Signed-off-by: Aleksey Makarov <aleksey.makarov@linaro.org>
---
 arch/arm64/kernel/setup.c |  6 ++++--
 drivers/acpi/Kconfig      |  2 +-
 drivers/acpi/tables.c     | 10 +++++++++-
 3 files changed, 14 insertions(+), 4 deletions(-)

Comments

Mark Rutland May 17, 2016, 12:46 p.m. UTC | #1
On Tue, May 17, 2016 at 03:06:03PM +0300, Aleksey Makarov wrote:
> From: Jon Masters <jcm@redhat.com>
> 
> This patch adds support for ACPI_TABLE_UPGRADE for ARM64

This feels like a tool to paper over problems rather than solve them.

If vendors are shipping horrendously broken tables today, clearly no
software has ever really supported them. So why add workarounds?

Why is this necessary? Is there a particular case for this, or is this
just for parity with x86?

IMO it would be better to put pressure on vendors to fix their FW and
provide sensible OS-agnostic update mechanisms.

> To access initrd image we need to move initialization
> of linear mapping a bit earlier.
> 
> Signed-off-by: Jon Masters <jcm@redhat.com>
> Signed-off-by: Aleksey Makarov <aleksey.makarov@linaro.org>
> ---
>  arch/arm64/kernel/setup.c |  6 ++++--
>  drivers/acpi/Kconfig      |  2 +-
>  drivers/acpi/tables.c     | 10 +++++++++-
>  3 files changed, 14 insertions(+), 4 deletions(-)
> 
> diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c
> index feab2ee..1d5e24f 100644
> --- a/arch/arm64/kernel/setup.c
> +++ b/arch/arm64/kernel/setup.c
> @@ -261,11 +261,13 @@ void __init setup_arch(char **cmdline_p)
>  	efi_init();
>  	arm64_memblock_init();
>  
> +	paging_init();
> +
> +	early_initrd_acpi_init();

Do we actually need full paging up here?

Why can we not use fixmap based copying as we do for the other cases
prior to paging_init?

> +
>  	/* Parse the ACPI tables for possible boot-time configuration */
>  	acpi_boot_table_init();
>  
> -	paging_init();
> -
>  	if (acpi_disabled)
>  		unflatten_device_tree();
>  
> diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
> index c204344..ec694c0 100644
> --- a/drivers/acpi/Kconfig
> +++ b/drivers/acpi/Kconfig
> @@ -313,7 +313,7 @@ config ACPI_CUSTOM_DSDT
>  
>  config ACPI_TABLE_UPGRADE
>  	bool "Allow upgrading ACPI tables via initrd"
> -	depends on BLK_DEV_INITRD && X86
> +	depends on BLK_DEV_INITRD && (X86 || ARM64)
>  	default y
>  	help

Perhaps ARCH_HAS_ACPI_TABLE_UPGRADE?

>  	  This option provides functionality to upgrade arbitrary ACPI tables
> diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c
> index 82be84a..c35034d8 100644
> --- a/drivers/acpi/tables.c
> +++ b/drivers/acpi/tables.c
> @@ -482,6 +482,14 @@ static DECLARE_BITMAP(acpi_initrd_installed, NR_ACPI_INITRD_TABLES);
>  
>  #define MAP_CHUNK_SIZE   (NR_FIX_BTMAPS << PAGE_SHIFT)
>  
> +#if defined(CONFIG_X86)
> +#define MAX_PHYS_ACPI_TABLES (max_low_pfn_mapped << PAGE_SHIFT)
> +#elif defined(CONFIG_ARM64)
> +#define MAX_PHYS_ACPI_TABLES PFN_PHYS(max_pfn)
> +#else
> +#error "MAX_PHYS_ACPI_TABLES is not defiend for this architecture"
> +#endif

s/defiend/defined/

This should be defined in an arch-specific header if it is actually
arch-specific.

Thanks,
Mark.

> +
>  static void __init acpi_table_initrd_init(void *data, size_t size)
>  {
>  	int sig, no, table_nr = 0, total_offset = 0;
> @@ -541,7 +549,7 @@ static void __init acpi_table_initrd_init(void *data, size_t size)
>  		return;
>  
>  	acpi_tables_addr =
> -		memblock_find_in_range(0, max_low_pfn_mapped << PAGE_SHIFT,
> +		memblock_find_in_range(0, MAX_PHYS_ACPI_TABLES,
>  				       all_tables_size, PAGE_SIZE);
>  	if (!acpi_tables_addr) {
>  		WARN_ON(1);
> -- 
> 2.8.2
>
Jon Masters May 17, 2016, 4:44 p.m. UTC | #2
Hi Mark,

On 05/17/2016 08:46 AM, Mark Rutland wrote:
> On Tue, May 17, 2016 at 03:06:03PM +0300, Aleksey Makarov wrote:
>> From: Jon Masters <jcm@redhat.com>
>>
>> This patch adds support for ACPI_TABLE_UPGRADE for ARM64
> 
> This feels like a tool to paper over problems rather than solve them.

Generally, it's an arrow in the quiver used to triage problems, and then
solve them by getting firmware updates made.

> If vendors are shipping horrendously broken tables today, clearly no
> software has ever really supported them. So why add workarounds?

That's not (always) the case. These patches help with:

1). During development of a platform, it is much easier to debug
problems with tables if you can test replacement ones without having to
respin the firmware. In the server world, you usually don't have the
firmware source code, so to get it respun could be days-weeks even if
you are working with the authors closely. We have practically used this
feature on a number of platforms already and it will continue.

2). They empower (advanced) users and developers to work around problems
that they find on platforms. Sure, we want firmware to always be fixed
and working well, but it is better if folks have the tools.

> Why is this necessary? Is there a particular case for this, or is this
> just for parity with x86?

The use cases are as above. It's also required for parity with x86
functionality on servers.

> IMO it would be better to put pressure on vendors to fix their FW and
> provide sensible OS-agnostic update mechanisms.

It's easier to put pressure on them after we know what the problems are.
I agree that alternative update mechanisms are also good. We also have
the ability (but it is not implemented on ARM) in GRUB2 to override ACPI
tables, BUT it's kinda atrophied on all arches and requires that you
rebuild GRUB with an additional module. The reality is that by
incorporating this feature we are able to provide the same capability
that already exists on x86 systems for ACPI table triage.

Jon.
Jon Masters May 17, 2016, 4:48 p.m. UTC | #3
On 05/17/2016 12:44 PM, Jon Masters wrote:

> 1). During development of a platform, it is much easier to debug
> problems with tables if you can test replacement ones without having to
> respin the firmware. In the server world, you usually don't have the
> firmware source code, so to get it respun could be days-weeks even if
> you are working with the authors closely. We have practically used this
> feature on a number of platforms already and it will continue.

For example, on one platform we were unable to fully boot RHEL(SA) due
to a bug in one of the ACPI tables. But I was able to boot the system to
a ramdisk containing a uuencode library and then write out the content
of the tables over the serial port, then decompile/patch/recompile, and
override replacement tables on the system. Then we beat the vendor up
with the fixes and the official firmware was corrected.
Aleksey Makarov May 18, 2016, 3:11 p.m. UTC | #4
On 05/17/2016 03:46 PM, Mark Rutland wrote:
> On Tue, May 17, 2016 at 03:06:03PM +0300, Aleksey Makarov wrote:

[...]

>> diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c
>> index feab2ee..1d5e24f 100644
>> --- a/arch/arm64/kernel/setup.c
>> +++ b/arch/arm64/kernel/setup.c
>> @@ -261,11 +261,13 @@ void __init setup_arch(char **cmdline_p)
>>  	efi_init();
>>  	arm64_memblock_init();
>>  
>> +	paging_init();
>> +
>> +	early_initrd_acpi_init();
> 
> Do we actually need full paging up here?
> 
> Why can we not use fixmap based copying as we do for the other cases
> prior to paging_init?

The implementation of the feature acpi_table_initrd_init()
(drivers/acpi/tables.c) works with initrd data represented as an array
in virtual memory.  It uses some library utility to find the redefined
tables in that array and iterates over it to copy the data to new
allocated memory.  So we need to rewrite it considerably to access the
initrd data via fixmap.

In x86 arch, linear kernel memory is already mapped by the time when
early_initrd_acpi_init() and acpi_boot_table_init() are called so I
think that we can just move this mapping one function earlier too.

Is it ok?

I will address your other comments in the next version of the patchset.

Thank you
Aleksey Makarov

>> +
>>  	/* Parse the ACPI tables for possible boot-time configuration */
>>  	acpi_boot_table_init();
>>  
>> -	paging_init();
>> -
>>  	if (acpi_disabled)
>>  		unflatten_device_tree();
>>  
>> diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
>> index c204344..ec694c0 100644
>> --- a/drivers/acpi/Kconfig
>> +++ b/drivers/acpi/Kconfig
>> @@ -313,7 +313,7 @@ config ACPI_CUSTOM_DSDT
>>  
>>  config ACPI_TABLE_UPGRADE
>>  	bool "Allow upgrading ACPI tables via initrd"
>> -	depends on BLK_DEV_INITRD && X86
>> +	depends on BLK_DEV_INITRD && (X86 || ARM64)
>>  	default y
>>  	help
> 
> Perhaps ARCH_HAS_ACPI_TABLE_UPGRADE?
> 
>>  	  This option provides functionality to upgrade arbitrary ACPI tables
>> diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c
>> index 82be84a..c35034d8 100644
>> --- a/drivers/acpi/tables.c
>> +++ b/drivers/acpi/tables.c
>> @@ -482,6 +482,14 @@ static DECLARE_BITMAP(acpi_initrd_installed, NR_ACPI_INITRD_TABLES);
>>  
>>  #define MAP_CHUNK_SIZE   (NR_FIX_BTMAPS << PAGE_SHIFT)
>>  
>> +#if defined(CONFIG_X86)
>> +#define MAX_PHYS_ACPI_TABLES (max_low_pfn_mapped << PAGE_SHIFT)
>> +#elif defined(CONFIG_ARM64)
>> +#define MAX_PHYS_ACPI_TABLES PFN_PHYS(max_pfn)
>> +#else
>> +#error "MAX_PHYS_ACPI_TABLES is not defiend for this architecture"
>> +#endif
> 
> s/defiend/defined/
> 
> This should be defined in an arch-specific header if it is actually
> arch-specific.
> 
> Thanks,
> Mark.
> 
>> +
>>  static void __init acpi_table_initrd_init(void *data, size_t size)
>>  {
>>  	int sig, no, table_nr = 0, total_offset = 0;
>> @@ -541,7 +549,7 @@ static void __init acpi_table_initrd_init(void *data, size_t size)
>>  		return;
>>  
>>  	acpi_tables_addr =
>> -		memblock_find_in_range(0, max_low_pfn_mapped << PAGE_SHIFT,
>> +		memblock_find_in_range(0, MAX_PHYS_ACPI_TABLES,
>>  				       all_tables_size, PAGE_SIZE);
>>  	if (!acpi_tables_addr) {
>>  		WARN_ON(1);
>> -- 
>> 2.8.2
>>
Mark Rutland May 23, 2016, 4:49 p.m. UTC | #5
On Tue, May 17, 2016 at 12:44:02PM -0400, Jon Masters wrote:
> Hi Mark,
> 
> On 05/17/2016 08:46 AM, Mark Rutland wrote:
> > On Tue, May 17, 2016 at 03:06:03PM +0300, Aleksey Makarov wrote:
> >> From: Jon Masters <jcm@redhat.com>
> >>
> >> This patch adds support for ACPI_TABLE_UPGRADE for ARM64
> > 
> > This feels like a tool to paper over problems rather than solve them.
> 
> Generally, it's an arrow in the quiver used to triage problems, and then
> solve them by getting firmware updates made.

Ok. The feature is _hideously_ misnamed for that purpose, however.

> > If vendors are shipping horrendously broken tables today, clearly no
> > software has ever really supported them. So why add workarounds?
> 
> That's not (always) the case. These patches help with:
> 
> 1). During development of a platform, it is much easier to debug
> problems with tables if you can test replacement ones without having to
> respin the firmware. In the server world, you usually don't have the
> firmware source code, so to get it respun could be days-weeks even if
> you are working with the authors closely. We have practically used this
> feature on a number of platforms already and it will continue.

I was under the impression that that was already possible with GRUB
today (though I see below this may not be the case).

> 2). They empower (advanced) users and developers to work around problems
> that they find on platforms. Sure, we want firmware to always be fixed
> and working well, but it is better if folks have the tools.
> 
> > Why is this necessary? Is there a particular case for this, or is this
> > just for parity with x86?
> 
> The use cases are as above. It's also required for parity with x86
> functionality on servers.

Parity for case 1 above, or is this used in other scenarios on x86
today?

> > IMO it would be better to put pressure on vendors to fix their FW and
> > provide sensible OS-agnostic update mechanisms.
> 
> It's easier to put pressure on them after we know what the problems are.
> I agree that alternative update mechanisms are also good. We also have
> the ability (but it is not implemented on ARM) in GRUB2 to override ACPI
> tables, BUT it's kinda atrophied on all arches and requires that you
> rebuild GRUB with an additional module.

This feels like something that could/should be rectified.

> The reality is that by incorporating this feature we are able to
> provide the same capability that already exists on x86 systems for
> ACPI table triage.

To be clear, I do not disagree that this feature can be useful for that
case. I am just concerned that this is easily abused, and the
description implies a more general set of use cases than we would like.

Thanks,
Mark.
Lorenzo Pieralisi May 23, 2016, 5:56 p.m. UTC | #6
On Tue, May 17, 2016 at 12:48:53PM -0400, Jon Masters wrote:
> On 05/17/2016 12:44 PM, Jon Masters wrote:
> 
> > 1). During development of a platform, it is much easier to debug
> > problems with tables if you can test replacement ones without having to
> > respin the firmware. In the server world, you usually don't have the
> > firmware source code, so to get it respun could be days-weeks even if
> > you are working with the authors closely. We have practically used this
> > feature on a number of platforms already and it will continue.
> 
> For example, on one platform we were unable to fully boot RHEL(SA) due
> to a bug in one of the ACPI tables. But I was able to boot the system to
> a ramdisk containing a uuencode library and then write out the content
> of the tables over the serial port, then decompile/patch/recompile, and
> override replacement tables on the system. Then we beat the vendor up
> with the fixes and the official firmware was corrected.

Can you explain to me please why you can't do it with GRUB ?

I am using mainline GRUB and its acpi command all the time to update
static ACPI tables for testing new features (ie IORT) and it works
just fine for me (and you can still override the DSDT, which is
likely to be the main source of bugs, through the CONFIG_ACPI_CUSTOM_DSDT
config option, that works on ARM in mainline with no changes required).

I just want to understand if there is really a compelling reason
for adding this stuff when we can easily implement its features
through something that is usable today without any kernel changes.

Thanks,
Lorenzo
Jon Masters May 23, 2016, 6:29 p.m. UTC | #7
On 05/23/2016 01:56 PM, Lorenzo Pieralisi wrote:
> On Tue, May 17, 2016 at 12:48:53PM -0400, Jon Masters wrote:
>> On 05/17/2016 12:44 PM, Jon Masters wrote:
>>
>>> 1). During development of a platform, it is much easier to debug
>>> problems with tables if you can test replacement ones without having to
>>> respin the firmware. In the server world, you usually don't have the
>>> firmware source code, so to get it respun could be days-weeks even if
>>> you are working with the authors closely. We have practically used this
>>> feature on a number of platforms already and it will continue.
>>
>> For example, on one platform we were unable to fully boot RHEL(SA) due
>> to a bug in one of the ACPI tables. But I was able to boot the system to
>> a ramdisk containing a uuencode library and then write out the content
>> of the tables over the serial port, then decompile/patch/recompile, and
>> override replacement tables on the system. Then we beat the vendor up
>> with the fixes and the official firmware was corrected.
> 
> Can you explain to me please why you can't do it with GRUB ?

It's doable with GRUB (if you rebuild GRUB modules to include it)

> I am using mainline GRUB and its acpi command all the time to update
> static ACPI tables for testing new features (ie IORT) and it works
> just fine for me (and you can still override the DSDT, which is
> likely to be the main source of bugs, through the CONFIG_ACPI_CUSTOM_DSDT
> config option, that works on ARM in mainline with no changes required).
> 
> I just want to understand if there is really a compelling reason
> for adding this stuff when we can easily implement its features
> through something that is usable today without any kernel changes.

We're looking for x86 feature parity in the base platform. Every time
there's a gratuitous differentiation it's a waste of time for folks
trying to figure out what is different on an ARM system. So if we
completely remove the ACPI override feature from the kernel and make
everyone use GRUB instead, then fine, but ARM shouldn't be special.

Jon.
diff mbox

Patch

diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c
index feab2ee..1d5e24f 100644
--- a/arch/arm64/kernel/setup.c
+++ b/arch/arm64/kernel/setup.c
@@ -261,11 +261,13 @@  void __init setup_arch(char **cmdline_p)
 	efi_init();
 	arm64_memblock_init();
 
+	paging_init();
+
+	early_initrd_acpi_init();
+
 	/* Parse the ACPI tables for possible boot-time configuration */
 	acpi_boot_table_init();
 
-	paging_init();
-
 	if (acpi_disabled)
 		unflatten_device_tree();
 
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index c204344..ec694c0 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -313,7 +313,7 @@  config ACPI_CUSTOM_DSDT
 
 config ACPI_TABLE_UPGRADE
 	bool "Allow upgrading ACPI tables via initrd"
-	depends on BLK_DEV_INITRD && X86
+	depends on BLK_DEV_INITRD && (X86 || ARM64)
 	default y
 	help
 	  This option provides functionality to upgrade arbitrary ACPI tables
diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c
index 82be84a..c35034d8 100644
--- a/drivers/acpi/tables.c
+++ b/drivers/acpi/tables.c
@@ -482,6 +482,14 @@  static DECLARE_BITMAP(acpi_initrd_installed, NR_ACPI_INITRD_TABLES);
 
 #define MAP_CHUNK_SIZE   (NR_FIX_BTMAPS << PAGE_SHIFT)
 
+#if defined(CONFIG_X86)
+#define MAX_PHYS_ACPI_TABLES (max_low_pfn_mapped << PAGE_SHIFT)
+#elif defined(CONFIG_ARM64)
+#define MAX_PHYS_ACPI_TABLES PFN_PHYS(max_pfn)
+#else
+#error "MAX_PHYS_ACPI_TABLES is not defiend for this architecture"
+#endif
+
 static void __init acpi_table_initrd_init(void *data, size_t size)
 {
 	int sig, no, table_nr = 0, total_offset = 0;
@@ -541,7 +549,7 @@  static void __init acpi_table_initrd_init(void *data, size_t size)
 		return;
 
 	acpi_tables_addr =
-		memblock_find_in_range(0, max_low_pfn_mapped << PAGE_SHIFT,
+		memblock_find_in_range(0, MAX_PHYS_ACPI_TABLES,
 				       all_tables_size, PAGE_SIZE);
 	if (!acpi_tables_addr) {
 		WARN_ON(1);