[4/6] ACPICA: Add support for using logical addresses of GPE blocks
diff mbox series

Message ID 9373262.piL2bvXoCD@kreacher
State New, archived
Headers show
Series
  • ACPICA / ACPI: OSL: Rework GPE registers access code
Related show

Commit Message

Rafael J. Wysocki Sept. 4, 2020, 5:24 p.m. UTC
From: "Rafael J. Wysocki" <rafael.j.wysocki@intel.com>

The logical address of every GPE block in system memory must be
known before passing it to acpi_ev_initialize_gpe_block(), because
memory cannot be mapped on the fly from an interrupt handler.
Accordingly, the host OS must map every GPE block in system
memory upfront and it can store the logical addresses of GPE
blocks for future use.

If these logical addresses were known to ACPICA, it could use them
instead of the corresponding physical addresses of GPE block for
GPE register accesses and the memory mapping lookups carried out
by acpi_os_read_memory() and acpi_os_write_memory() on every
attempt to access a GPE register would not be necessary any more.

To allow that to happen, introduce the ACPI_GPE_USE_LOGICAL_ADDRESSES
symbol to indicate whether or not the host OS wants ACPICA to use the
logical addresses of GPE registers in system memory directly (which
is the case if this symbol is defined).  Moreover, conditional on
whether ACPI_GPE_USE_LOGICAL_ADDRESSES is defined, introduce two new
global variables for storing the logical addresses of the FADT GPE
blocks 0 and 1, respectively, acpi_gbl_xgpe0_block_logical_address and
acpi_gbl_xgpe1_block_logical_address, make acpi_ev_gpe_initialize()
pass their values instead of the physical addresses of the GPE blocks
in question to acpi_ev_create_gpe_block() and modify
acpi_hw_gpe_read() and acpi_hw_gpe_write() to access memory directly
via the addresses stored in the struct acpi_gpe_address objects,
which are expected to be the logical addresses of GPE registers if
ACPI_GPE_USE_LOGICAL_ADDRESSES is defined.

With the above changes in place, a host OS wanting ACPICA to
access GPE registers directly through their logical addresses
needs to define the ACPI_GPE_USE_LOGICAL_ADDRESSES symbol and
make sure that the logical addresses of the FADT GPE blocks 0
and 1 are stored in acpi_gbl_xgpe0_block_logical_address and
acpi_gbl_xgpe1_block_logical_address, respectively, prior to
calling acpi_ev_gpe_initialize().

[If such a host OS also uses acpi_install_gpe_block() to add
 non-FADT GPE register blocks located in system memory, it must
 pass their logical addresses instead of their physical addresses
 to this function.]

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/acpi/acpica/acglobal.h  |  6 ++++++
 drivers/acpi/acpica/evgpeinit.c | 23 +++++++++++++++++------
 drivers/acpi/acpica/hwgpe.c     | 10 ++++++++++
 3 files changed, 33 insertions(+), 6 deletions(-)

Comments

Matthieu Baerts Oct. 16, 2020, 2:30 p.m. UTC | #1
Hi Rafael,

On 04/09/2020 19:24, Rafael J. Wysocki wrote:
> From: "Rafael J. Wysocki" <rafael.j.wysocki@intel.com>
> 
> The logical address of every GPE block in system memory must be
> known before passing it to acpi_ev_initialize_gpe_block(), because
> memory cannot be mapped on the fly from an interrupt handler.
> Accordingly, the host OS must map every GPE block in system
> memory upfront and it can store the logical addresses of GPE
> blocks for future use.

(...)

> diff --git a/drivers/acpi/acpica/hwgpe.c b/drivers/acpi/acpica/hwgpe.c
> index a0e71f34c77a..37bb67ef3232 100644
> --- a/drivers/acpi/acpica/hwgpe.c
> +++ b/drivers/acpi/acpica/hwgpe.c
> @@ -46,8 +46,13 @@ acpi_status acpi_hw_gpe_read(u64 *value, struct acpi_gpe_address *reg)
>   	u32 value32;
>   
>   	if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
> +#ifdef ACPI_GPE_USE_LOGICAL_ADDRESSES
> +		*value = (u64)ACPI_GET8(reg->address);

Thank you for the patch!

When compiling net-next repo, recently sync with Linus repo, I got an 
error when using i386 arch because of this line above.

Here are the commands I used:


================================================
$ make defconfig KBUILD_DEFCONFIG=i386_defconfig
*** Default configuration is based on 'i386_defconfig'
#
# configuration written to .config
#
$ scripts/config --disable DRM --disable PCCARD --disable ATA --disable 
MD --disable PPS --disable SOUND --disable USB --disable IOMMU_SUPPORT 
--disable INPUT_LEDS --disable AGP --disable VGA_ARB --disable EFI 
--disable WLAN --disable WIRELESS --disable LOGO --disable NFS_FS 
--disable XFRM_USER --disable INET6_AH --disable INET6_ESP --disable 
NETDEVICES -e KUNIT -d KUNIT_DEBUGFS -d KUNIT_TEST -d KUNIT_EXAMPLE_TEST 
-d EXT4_KUNIT_TESTS -d SYSCTL_KUNIT_TEST -d LIST_KUNIT_TEST -d 
LINEAR_RANGES_TEST -d BITS_TEST -d KUNIT_ALL_TESTS -e INET_DIAG -d 
INET_UDP_DIAG -d INET_RAW_DIAG -d INET_DIAG_DESTROY -e MPTCP -e 
MPTCP_IPV6 -e MPTCP_KUNIT_TESTS
$ KCFLAGS=-Werror make -j8 -l8
scripts/kconfig/conf  --syncconfig Kconfig
(...)
   CC      drivers/acpi/acpica/hwgpe.o
In file included from ./include/acpi/acpi.h:24,
                  from drivers/acpi/acpica/hwgpe.c:10:
drivers/acpi/acpica/hwgpe.c: In function 'acpi_hw_gpe_read':
./include/acpi/actypes.h:501:48: error: cast to pointer from integer of 
different size [-Werror=int-to-pointer-cast]
   501 | #define ACPI_CAST_PTR(t, p)             ((t *) (acpi_uintptr_t) 
(p))
       |                                                ^
drivers/acpi/acpica/acmacros.h:18:41: note: in expansion of macro 
'ACPI_CAST_PTR'
    18 | #define ACPI_CAST8(ptr)                 ACPI_CAST_PTR (u8, (ptr))
       |                                         ^~~~~~~~~~~~~
drivers/acpi/acpica/acmacros.h:22:43: note: in expansion of macro 
'ACPI_CAST8'
    22 | #define ACPI_GET8(ptr)                  (*ACPI_CAST8 (ptr))
       |                                           ^~~~~~~~~~
drivers/acpi/acpica/hwgpe.c:50:17: note: in expansion of macro 'ACPI_GET8'
    50 |   *value = (u64)ACPI_GET8(reg->address);
       |                 ^~~~~~~~~
drivers/acpi/acpica/hwgpe.c: In function 'acpi_hw_gpe_write':
./include/acpi/actypes.h:501:48: error: cast to pointer from integer of 
different size [-Werror=int-to-pointer-cast]
   501 | #define ACPI_CAST_PTR(t, p)             ((t *) (acpi_uintptr_t) 
(p))
       |                                                ^
drivers/acpi/acpica/acmacros.h:18:41: note: in expansion of macro 
'ACPI_CAST_PTR'
    18 | #define ACPI_CAST8(ptr)                 ACPI_CAST_PTR (u8, (ptr))
       |                                         ^~~~~~~~~~~~~
drivers/acpi/acpica/acmacros.h:26:43: note: in expansion of macro 
'ACPI_CAST8'
    26 | #define ACPI_SET8(ptr, val)             (*ACPI_CAST8 (ptr) = 
(u8) (val))
       |                                           ^~~~~~~~~~
drivers/acpi/acpica/hwgpe.c:85:3: note: in expansion of macro 'ACPI_SET8'
    85 |   ACPI_SET8(reg->address, value);
       |   ^~~~~~~~~
cc1: all warnings being treated as errors
make[3]: *** [scripts/Makefile.build:283: drivers/acpi/acpica/hwgpe.o] 
Error 1
make[2]: *** [scripts/Makefile.build:500: drivers/acpi/acpica] Error 2
make[1]: *** [scripts/Makefile.build:500: drivers/acpi] Error 2
make: *** [Makefile:1777: drivers] Error 2
================================================


> +		return_ACPI_STATUS(AE_OK);
> +#else
>   		return acpi_os_read_memory((acpi_physical_address)reg->address,
>   					    value, ACPI_GPE_REGISTER_WIDTH);
> +#endif
>   	}
>   
>   	status = acpi_os_read_port((acpi_io_address)reg->address,
> @@ -76,8 +81,13 @@ acpi_status acpi_hw_gpe_read(u64 *value, struct acpi_gpe_address *reg)
>   acpi_status acpi_hw_gpe_write(u64 value, struct acpi_gpe_address *reg)
>   {
>   	if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
> +#ifdef ACPI_GPE_USE_LOGICAL_ADDRESSES
> +		ACPI_SET8(reg->address, value);

(and also because of this line)

By chance, do you already have a fix for that? I didn't see any other 
email related to this issue, I am surprised no bot already reported the 
problem but maybe I didn't look everywhere :)

Cheers,
Matt
Rafael J. Wysocki Oct. 16, 2020, 5:15 p.m. UTC | #2
On Friday, October 16, 2020 4:30:55 PM CEST Matthieu Baerts wrote:
> Hi Rafael,

Hi,

> On 04/09/2020 19:24, Rafael J. Wysocki wrote:
> > From: "Rafael J. Wysocki" <rafael.j.wysocki@intel.com>
> > 
> > The logical address of every GPE block in system memory must be
> > known before passing it to acpi_ev_initialize_gpe_block(), because
> > memory cannot be mapped on the fly from an interrupt handler.
> > Accordingly, the host OS must map every GPE block in system
> > memory upfront and it can store the logical addresses of GPE
> > blocks for future use.
> 
> (...)
> 
> > diff --git a/drivers/acpi/acpica/hwgpe.c b/drivers/acpi/acpica/hwgpe.c
> > index a0e71f34c77a..37bb67ef3232 100644
> > --- a/drivers/acpi/acpica/hwgpe.c
> > +++ b/drivers/acpi/acpica/hwgpe.c
> > @@ -46,8 +46,13 @@ acpi_status acpi_hw_gpe_read(u64 *value, struct acpi_gpe_address *reg)
> >   	u32 value32;
> >   
> >   	if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
> > +#ifdef ACPI_GPE_USE_LOGICAL_ADDRESSES
> > +		*value = (u64)ACPI_GET8(reg->address);
> 
> Thank you for the patch!
> 
> When compiling net-next repo, recently sync with Linus repo, I got an 
> error when using i386 arch because of this line above.
> 
> Here are the commands I used:
> 
> 
> ================================================
> $ make defconfig KBUILD_DEFCONFIG=i386_defconfig
> *** Default configuration is based on 'i386_defconfig'
> #
> # configuration written to .config
> #
> $ scripts/config --disable DRM --disable PCCARD --disable ATA --disable 
> MD --disable PPS --disable SOUND --disable USB --disable IOMMU_SUPPORT 
> --disable INPUT_LEDS --disable AGP --disable VGA_ARB --disable EFI 
> --disable WLAN --disable WIRELESS --disable LOGO --disable NFS_FS 
> --disable XFRM_USER --disable INET6_AH --disable INET6_ESP --disable 
> NETDEVICES -e KUNIT -d KUNIT_DEBUGFS -d KUNIT_TEST -d KUNIT_EXAMPLE_TEST 
> -d EXT4_KUNIT_TESTS -d SYSCTL_KUNIT_TEST -d LIST_KUNIT_TEST -d 
> LINEAR_RANGES_TEST -d BITS_TEST -d KUNIT_ALL_TESTS -e INET_DIAG -d 
> INET_UDP_DIAG -d INET_RAW_DIAG -d INET_DIAG_DESTROY -e MPTCP -e 
> MPTCP_IPV6 -e MPTCP_KUNIT_TESTS
> $ KCFLAGS=-Werror make -j8 -l8
> scripts/kconfig/conf  --syncconfig Kconfig
> (...)
>    CC      drivers/acpi/acpica/hwgpe.o
> In file included from ./include/acpi/acpi.h:24,
>                   from drivers/acpi/acpica/hwgpe.c:10:
> drivers/acpi/acpica/hwgpe.c: In function 'acpi_hw_gpe_read':
> ./include/acpi/actypes.h:501:48: error: cast to pointer from integer of 
> different size [-Werror=int-to-pointer-cast]
>    501 | #define ACPI_CAST_PTR(t, p)             ((t *) (acpi_uintptr_t) 
> (p))
>        |                                                ^
> drivers/acpi/acpica/acmacros.h:18:41: note: in expansion of macro 
> 'ACPI_CAST_PTR'
>     18 | #define ACPI_CAST8(ptr)                 ACPI_CAST_PTR (u8, (ptr))
>        |                                         ^~~~~~~~~~~~~
> drivers/acpi/acpica/acmacros.h:22:43: note: in expansion of macro 
> 'ACPI_CAST8'
>     22 | #define ACPI_GET8(ptr)                  (*ACPI_CAST8 (ptr))
>        |                                           ^~~~~~~~~~
> drivers/acpi/acpica/hwgpe.c:50:17: note: in expansion of macro 'ACPI_GET8'
>     50 |   *value = (u64)ACPI_GET8(reg->address);
>        |                 ^~~~~~~~~
> drivers/acpi/acpica/hwgpe.c: In function 'acpi_hw_gpe_write':
> ./include/acpi/actypes.h:501:48: error: cast to pointer from integer of 
> different size [-Werror=int-to-pointer-cast]
>    501 | #define ACPI_CAST_PTR(t, p)             ((t *) (acpi_uintptr_t) 
> (p))
>        |                                                ^
> drivers/acpi/acpica/acmacros.h:18:41: note: in expansion of macro 
> 'ACPI_CAST_PTR'
>     18 | #define ACPI_CAST8(ptr)                 ACPI_CAST_PTR (u8, (ptr))
>        |                                         ^~~~~~~~~~~~~
> drivers/acpi/acpica/acmacros.h:26:43: note: in expansion of macro 
> 'ACPI_CAST8'
>     26 | #define ACPI_SET8(ptr, val)             (*ACPI_CAST8 (ptr) = 
> (u8) (val))
>        |                                           ^~~~~~~~~~
> drivers/acpi/acpica/hwgpe.c:85:3: note: in expansion of macro 'ACPI_SET8'
>     85 |   ACPI_SET8(reg->address, value);
>        |   ^~~~~~~~~
> cc1: all warnings being treated as errors

This is what causes the build to terminate.

> make[3]: *** [scripts/Makefile.build:283: drivers/acpi/acpica/hwgpe.o] 
> Error 1
> make[2]: *** [scripts/Makefile.build:500: drivers/acpi/acpica] Error 2
> make[1]: *** [scripts/Makefile.build:500: drivers/acpi] Error 2
> make: *** [Makefile:1777: drivers] Error 2
> ================================================
> 
> 
> > +		return_ACPI_STATUS(AE_OK);
> > +#else
> >   		return acpi_os_read_memory((acpi_physical_address)reg->address,
> >   					    value, ACPI_GPE_REGISTER_WIDTH);
> > +#endif
> >   	}
> >   
> >   	status = acpi_os_read_port((acpi_io_address)reg->address,
> > @@ -76,8 +81,13 @@ acpi_status acpi_hw_gpe_read(u64 *value, struct acpi_gpe_address *reg)
> >   acpi_status acpi_hw_gpe_write(u64 value, struct acpi_gpe_address *reg)
> >   {
> >   	if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
> > +#ifdef ACPI_GPE_USE_LOGICAL_ADDRESSES
> > +		ACPI_SET8(reg->address, value);
> 
> (and also because of this line)
> 
> By chance, do you already have a fix for that?

Can you please try the appended patch?

> I didn't see any other 
> email related to this issue, I am surprised no bot already reported the 
> problem but maybe I didn't look everywhere :)

No, they didn't AFAICS.

---
 drivers/acpi/acpica/hwgpe.c |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

Index: linux-pm/drivers/acpi/acpica/hwgpe.c
===================================================================
--- linux-pm.orig/drivers/acpi/acpica/hwgpe.c
+++ linux-pm/drivers/acpi/acpica/hwgpe.c
@@ -47,7 +47,7 @@ acpi_status acpi_hw_gpe_read(u64 *value,
 
 	if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
 #ifdef ACPI_GPE_USE_LOGICAL_ADDRESSES
-		*value = (u64)ACPI_GET8(reg->address);
+		*value = (u64)ACPI_GET8((unsigned long)reg->address);
 		return_ACPI_STATUS(AE_OK);
 #else
 		return acpi_os_read_memory((acpi_physical_address)reg->address,
@@ -82,7 +82,7 @@ acpi_status acpi_hw_gpe_write(u64 value,
 {
 	if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
 #ifdef ACPI_GPE_USE_LOGICAL_ADDRESSES
-		ACPI_SET8(reg->address, value);
+		ACPI_SET8((unsigned long)reg->address, value);
 		return_ACPI_STATUS(AE_OK);
 #else
 		return acpi_os_write_memory((acpi_physical_address)reg->address,
Matthieu Baerts Oct. 16, 2020, 6:12 p.m. UTC | #3
Hi Rafael,

On 16/10/2020 19:15, Rafael J. Wysocki wrote:
> On Friday, October 16, 2020 4:30:55 PM CEST Matthieu Baerts wrote:
>>
>> By chance, do you already have a fix for that?
> 
> Can you please try the appended patch?

Thank you for the patch, this fixes the compilation warning I got.

Reported-and-tested-by: Matthieu Baerts <matthieu.baerts@tessares.net>

Cheers,
Matt

Patch
diff mbox series

diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h
index 1030a0ce1599..5215ff1cbbbe 100644
--- a/drivers/acpi/acpica/acglobal.h
+++ b/drivers/acpi/acpica/acglobal.h
@@ -42,6 +42,12 @@  ACPI_GLOBAL(struct acpi_generic_address, acpi_gbl_xpm1a_enable);
 ACPI_GLOBAL(struct acpi_generic_address, acpi_gbl_xpm1b_status);
 ACPI_GLOBAL(struct acpi_generic_address, acpi_gbl_xpm1b_enable);
 
+#ifdef ACPI_GPE_USE_LOGICAL_ADDRESSES
+ACPI_GLOBAL(void *, acpi_gbl_xgpe0_block_logical_address);
+ACPI_GLOBAL(void *, acpi_gbl_xgpe1_block_logical_address);
+
+#endif				/* ACPI_GPE_USE_LOGICAL_ADDRESSES */
+
 /*
  * Handle both ACPI 1.0 and ACPI 2.0+ Integer widths. The integer width is
  * determined by the revision of the DSDT: If the DSDT revision is less than
diff --git a/drivers/acpi/acpica/evgpeinit.c b/drivers/acpi/acpica/evgpeinit.c
index 6effd8076dcc..6d82d30d8f7b 100644
--- a/drivers/acpi/acpica/evgpeinit.c
+++ b/drivers/acpi/acpica/evgpeinit.c
@@ -32,6 +32,16 @@  ACPI_MODULE_NAME("evgpeinit")
  * kernel boot time as well.
  */
 
+#ifdef ACPI_GPE_USE_LOGICAL_ADDRESSES
+#define ACPI_FADT_GPE_BLOCK_ADDRESS(N)	\
+	acpi_gbl_FADT.xgpe##N##_block.space_id == \
+					ACPI_ADR_SPACE_SYSTEM_MEMORY ? \
+		(u64)acpi_gbl_xgpe##N##_block_logical_address : \
+		acpi_gbl_FADT.xgpe##N##_block.address
+#else
+#define ACPI_FADT_GPE_BLOCK_ADDRESS(N)	acpi_gbl_FADT.xgpe##N##_block.address
+#endif		/* ACPI_GPE_USE_LOGICAL_ADDRESSES */
+
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ev_gpe_initialize
@@ -49,6 +59,7 @@  acpi_status acpi_ev_gpe_initialize(void)
 	u32 register_count1 = 0;
 	u32 gpe_number_max = 0;
 	acpi_status status;
+	u64 address;
 
 	ACPI_FUNCTION_TRACE(ev_gpe_initialize);
 
@@ -85,8 +96,9 @@  acpi_status acpi_ev_gpe_initialize(void)
 	 * If EITHER the register length OR the block address are zero, then that
 	 * particular block is not supported.
 	 */
-	if (acpi_gbl_FADT.gpe0_block_length &&
-	    acpi_gbl_FADT.xgpe0_block.address) {
+	address = ACPI_FADT_GPE_BLOCK_ADDRESS(0);
+
+	if (acpi_gbl_FADT.gpe0_block_length && address) {
 
 		/* GPE block 0 exists (has both length and address > 0) */
 
@@ -97,7 +109,6 @@  acpi_status acpi_ev_gpe_initialize(void)
 		/* Install GPE Block 0 */
 
 		status = acpi_ev_create_gpe_block(acpi_gbl_fadt_gpe_device,
-						  acpi_gbl_FADT.xgpe0_block.
 						  address,
 						  acpi_gbl_FADT.xgpe0_block.
 						  space_id, register_count0, 0,
@@ -110,8 +121,9 @@  acpi_status acpi_ev_gpe_initialize(void)
 		}
 	}
 
-	if (acpi_gbl_FADT.gpe1_block_length &&
-	    acpi_gbl_FADT.xgpe1_block.address) {
+	address = ACPI_FADT_GPE_BLOCK_ADDRESS(1);
+
+	if (acpi_gbl_FADT.gpe1_block_length && address) {
 
 		/* GPE block 1 exists (has both length and address > 0) */
 
@@ -137,7 +149,6 @@  acpi_status acpi_ev_gpe_initialize(void)
 
 			status =
 			    acpi_ev_create_gpe_block(acpi_gbl_fadt_gpe_device,
-						     acpi_gbl_FADT.xgpe1_block.
 						     address,
 						     acpi_gbl_FADT.xgpe1_block.
 						     space_id, register_count1,
diff --git a/drivers/acpi/acpica/hwgpe.c b/drivers/acpi/acpica/hwgpe.c
index a0e71f34c77a..37bb67ef3232 100644
--- a/drivers/acpi/acpica/hwgpe.c
+++ b/drivers/acpi/acpica/hwgpe.c
@@ -46,8 +46,13 @@  acpi_status acpi_hw_gpe_read(u64 *value, struct acpi_gpe_address *reg)
 	u32 value32;
 
 	if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
+#ifdef ACPI_GPE_USE_LOGICAL_ADDRESSES
+		*value = (u64)ACPI_GET8(reg->address);
+		return_ACPI_STATUS(AE_OK);
+#else
 		return acpi_os_read_memory((acpi_physical_address)reg->address,
 					    value, ACPI_GPE_REGISTER_WIDTH);
+#endif
 	}
 
 	status = acpi_os_read_port((acpi_io_address)reg->address,
@@ -76,8 +81,13 @@  acpi_status acpi_hw_gpe_read(u64 *value, struct acpi_gpe_address *reg)
 acpi_status acpi_hw_gpe_write(u64 value, struct acpi_gpe_address *reg)
 {
 	if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
+#ifdef ACPI_GPE_USE_LOGICAL_ADDRESSES
+		ACPI_SET8(reg->address, value);
+		return_ACPI_STATUS(AE_OK);
+#else
 		return acpi_os_write_memory((acpi_physical_address)reg->address,
 					    value, ACPI_GPE_REGISTER_WIDTH);
+#endif
 	}
 
 	return acpi_os_write_port((acpi_io_address)reg->address, (u32)value,