2013-08-08 03:41:08

by Tang Chen

[permalink] [raw]
Subject: [PATCH part1 0/5] acpica: Split acpi_gbl_root_table_list initialization into two parts.

[Problem]

The current Linux cannot migrate pages used by the kerenl because
of the kernel direct mapping. In Linux kernel space, va = pa + PAGE_OFFSET.
When the pa is changed, we cannot simply update the pagetable and
keep the va unmodified. So the kernel pages are not migratable.

There are also some other issues will cause the kernel pages not migratable.
For example, the physical address may be cached somewhere and will be used.
It is not to update all the caches.

When doing memory hotplug in Linux, we first migrate all the pages in one
memory device somewhere else, and then remove the device. But if pages are
used by the kernel, they are not migratable. As a result, memory used by
the kernel cannot be hot-removed.

Modifying the kernel direct mapping mechanism is too difficult to do. And
it may cause the kernel performance down and unstable. So we use the following
way to do memory hotplug.


[What we are doing]

In Linux, memory in one numa node is divided into several zones. One of the
zones is ZONE_MOVABLE, which the kernel won't use.

In order to implement memory hotplug in Linux, we are going to arrange all
hotpluggable memory in ZONE_MOVABLE so that the kernel won't use these memory.

To do this, we need ACPI's help.


[How we do this]

In ACPI, SRAT(System Resource Affinity Table) contains NUMA info. The memory
affinities in SRAT record every memory range in the system, and also, flags
specifying if the memory range is hotpluggable.
(Please refer to ACPI spec 5.0 5.2.16)

With the help of SRAT, we have to do the following two things to achieve our
goal:

1. When doing memory hot-add, allow the users arranging hotpluggable as
ZONE_MOVABLE.
(This has been done by the MOVABLE_NODE functionality in Linux.)

2. when the system is booting, prevent bootmem allocator from allocating
hotpluggable memory for the kernel before the memory initialization
finishes.
(This is what we are going to do. And we need to do some modification in
ACPICA. See below.)


[About this patch-set]

There is a bootmem allocator named memblock in Linux. memblock starts to work
at very early time, and SRAT has not been parsed. So we don't know which memory
is hotpluggable. In order to prevent memblock from allocating hotpluggable
memory for the kernel, we need to obtain SRAT memory affinity info earlier.

In the current Linux kernel, the acpica code iterates acpi_gbl_root_table_list,
and install all the acpi tables into it at boot time. Then, it tries to find
if there is any override table in global array acpi_tables_addr. If any, reinstall
the override table into acpi_gbl_root_table_list.

In Linux, global array acpi_tables_addr can be fulfilled by ACPI_INITRD_TABLE_OVERRIDE
mechanism, which allows users to specify their own ACPI tables in initrd file, and
override the ones from firmware.

The whole procedure looks like the following:

setup_arch()
|-> ...... /* Setup direct mapping pagetables */
|->acpi_initrd_override() /* Store all override tables in acpi_tables_addr. */
|...
|->acpi_boot_table_init()
|->acpi_table_init()
| (Linux code)
......................................................................................................
| (ACPICA code)
|->acpi_initialize_tables()
|->acpi_tb_parse_root_table() /* Parse RSDT or XSDT, find all tables in firmware */
|->for (each item in acpi_gbl_root_table_list)
|->acpi_tb_install_table()
|-> ...... /* Install one single table */
|->acpi_tb_table_override() /* Override one single table */

It does the table installation and overriding one by one.

In order to find SRAT at earlier time, we want to initialize acpi_gbl_root_table_list
earlier. But at the same time, keep ACPI_INITRD_TABLE_OVERRIDE procedure works as well.

The basic idea is, split the acpi_gbl_root_table_list initialization procedure into
two steps:
1. Install all tables from firmware, not one by one.
2. Override any table if necessary, not one by one.

After this patch-set, it will work like this:

setup_arch()
|-> ...... /* Install all tables from firmware (Step 1) */
|-> ...... /* Try to find if any override SRAT in initrd file, if yes, use it */
|-> ...... /* Use the SRAT from firmware */
|-> ...... /* memblock starts to work */
|-> ......
|->acpi_initrd_override() /* Initialize acpi_tables_addr with all override table. */
|...
|-> ...... /* Do the table override work for all tables (Step 2) */


In order to achieve this goal, we have to split all the following functions:

ACPICA:
acpi_tb_install_table()
acpi_tb_parse_root_table()
acpi_initialize_tables()

Linux acpi:
acpi_table_init()
acpi_boot_table_init()

Since ACPICA code is not just used by the Linux, so we should keep the ACPICA
side interfaces unmodified, and introduce new functions used in Linux.


Tang Chen (5):
acpi, acpica: Split acpi_tb_install_table() into two parts.
acpi, acpica: Call two new functions instead of
acpi_tb_install_table() in acpi_tb_parse_root_table().
acpi, acpica: Split acpi_tb_parse_root_table() into two parts.
acpi, acpica: Call two new functions instead of
acpi_tb_parse_root_table() in acpi_initialize_tables().
acpi, acpica: Split acpi_initialize_tables() into two parts.

drivers/acpi/acpica/actables.h | 2 +
drivers/acpi/acpica/tbutils.c | 184 +++++++++++++++++++++++++++++++++++-----
drivers/acpi/acpica/tbxface.c | 69 ++++++++++++++--
3 files changed, 228 insertions(+), 27 deletions(-)


2013-08-08 03:41:17

by Tang Chen

[permalink] [raw]
Subject: [PATCH part1 5/5] acpi, acpica: Split acpi_initialize_tables() into two parts.

This patch splits acpi_initialize_tables() into two steps, and
introduces two new functions:
acpi_initialize_tables_firmware() and acpi_tb_root_table_override(),
which work just the same as acpi_initialize_tables() if they are called
in sequence.

Signed-off-by: Tang Chen <[email protected]>
Reviewed-by: Zhang Yanfei <[email protected]>
---
drivers/acpi/acpica/tbxface.c | 64 ++++++++++++++++++++++++++++++++++++----
1 files changed, 57 insertions(+), 7 deletions(-)

diff --git a/drivers/acpi/acpica/tbxface.c b/drivers/acpi/acpica/tbxface.c
index 98e4cad..ecaa5e1 100644
--- a/drivers/acpi/acpica/tbxface.c
+++ b/drivers/acpi/acpica/tbxface.c
@@ -72,8 +72,7 @@ acpi_status acpi_allocate_root_table(u32 initial_table_count)
}

/*******************************************************************************
- *
- * FUNCTION: acpi_initialize_tables
+ * FUNCTION: acpi_initialize_tables_firmware
*
* PARAMETERS: initial_table_array - Pointer to an array of pre-allocated
* struct acpi_table_desc structures. If NULL, the
@@ -86,8 +85,6 @@ acpi_status acpi_allocate_root_table(u32 initial_table_count)
*
* RETURN: Status
*
- * DESCRIPTION: Initialize the table manager, get the RSDP and RSDT/XSDT.
- *
* NOTE: Allows static allocation of the initial table array in order
* to avoid the use of dynamic memory in confined environments
* such as the kernel boot sequence where it may not be available.
@@ -98,8 +95,8 @@ acpi_status acpi_allocate_root_table(u32 initial_table_count)
******************************************************************************/

acpi_status __init
-acpi_initialize_tables(struct acpi_table_desc * initial_table_array,
- u32 initial_table_count, u8 allow_resize)
+acpi_initialize_tables_firmware(struct acpi_table_desc * initial_table_array,
+ u32 initial_table_count, u8 allow_resize)
{
acpi_physical_address rsdp_address;
acpi_status status;
@@ -144,10 +141,63 @@ acpi_initialize_tables(struct acpi_table_desc * initial_table_array,
* in a common, more useable format.
*/
status = acpi_tb_root_table_install(rsdp_address);
+
+ return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_initialize_tables
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Allow host OS to replace any table installed in global root
+ * table list.
+ *
+ ******************************************************************************/
+
+void acpi_initialize_tables_override(void)
+{
+ acpi_tb_root_table_override();
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_initialize_tables
+ *
+ * PARAMETERS: initial_table_array - Pointer to an array of pre-allocated
+ * struct acpi_table_desc structures. If NULL, the
+ * array is dynamically allocated.
+ * initial_table_count - Size of initial_table_array, in number of
+ * struct acpi_table_desc structures
+ * allow_resize - Flag to tell Table Manager if resize of
+ * pre-allocated array is allowed. Ignored
+ * if initial_table_array is NULL.
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Initialize the table manager, get the RSDP and RSDT/XSDT.
+ *
+ ******************************************************************************/
+
+acpi_status __init
+acpi_initialize_tables(struct acpi_table_desc * initial_table_array,
+ u32 initial_table_count, u8 allow_resize)
+{
+ acpi_status status;
+
+ status = acpi_initialize_tables_firmware(initial_table_array,
+ initial_table_count, allow_resize);
if (ACPI_FAILURE(status))
return_ACPI_STATUS(status);

- acpi_tb_root_table_override();
+ /*
+ * Allow host OS to replace any table installed in global root
+ * table list.
+ */
+ acpi_initialize_tables_override();

return_ACPI_STATUS(AE_OK);
}
--
1.7.1

2013-08-08 03:41:15

by Tang Chen

[permalink] [raw]
Subject: [PATCH part1 4/5] acpi, acpica: Call two new functions instead of acpi_tb_parse_root_table() in acpi_initialize_tables().

The previous patch introduces two new functions:
acpi_tb_root_table_install() and acpi_tb_root_table_override(),
which work just the same as acpi_tb_parse_root_table() if they are
called in sequence.

In order to split acpi_initialize_tables(), call thes two functions
in acpi_initialize_tables(). This will keep acpi_initialize_tables()
works as before.

Signed-off-by: Tang Chen <[email protected]>
Reviewed-by: Zhang Yanfei <[email protected]>
---
drivers/acpi/acpica/actables.h | 2 ++
drivers/acpi/acpica/tbxface.c | 9 +++++++--
2 files changed, 9 insertions(+), 2 deletions(-)

diff --git a/drivers/acpi/acpica/actables.h b/drivers/acpi/acpica/actables.h
index 7755e91..641796e 100644
--- a/drivers/acpi/acpica/actables.h
+++ b/drivers/acpi/acpica/actables.h
@@ -120,6 +120,8 @@ void
acpi_tb_install_table(acpi_physical_address address,
char *signature, u32 table_index);

+acpi_status acpi_tb_root_table_install(acpi_physical_address rsdp_address);
+void acpi_tb_root_table_override(void);
acpi_status acpi_tb_parse_root_table(acpi_physical_address rsdp_address);

#endif /* __ACTABLES_H__ */
diff --git a/drivers/acpi/acpica/tbxface.c b/drivers/acpi/acpica/tbxface.c
index ad11162..98e4cad 100644
--- a/drivers/acpi/acpica/tbxface.c
+++ b/drivers/acpi/acpica/tbxface.c
@@ -143,8 +143,13 @@ acpi_initialize_tables(struct acpi_table_desc * initial_table_array,
* Root Table Array. This array contains the information of the RSDT/XSDT
* in a common, more useable format.
*/
- status = acpi_tb_parse_root_table(rsdp_address);
- return_ACPI_STATUS(status);
+ status = acpi_tb_root_table_install(rsdp_address);
+ if (ACPI_FAILURE(status))
+ return_ACPI_STATUS(status);
+
+ acpi_tb_root_table_override();
+
+ return_ACPI_STATUS(AE_OK);
}

/*******************************************************************************
--
1.7.1

2013-08-08 03:41:14

by Tang Chen

[permalink] [raw]
Subject: [PATCH part1 3/5] acpi, acpica: Split acpi_tb_parse_root_table() into two parts.

This patch splits acpi_tb_parse_root_table() into two steps, and
introduces two new functions:
acpi_tb_root_table_install() and acpi_tb_root_table_override().

They are just the same as acpi_tb_parse_root_table() if they are
called in sequence.

Signed-off-by: Tang Chen <[email protected]>
Reviewed-by: Zhang Yanfei <[email protected]>
---
drivers/acpi/acpica/tbutils.c | 57 ++++++++++++++++++++++++++++++++++++++--
1 files changed, 54 insertions(+), 3 deletions(-)

diff --git a/drivers/acpi/acpica/tbutils.c b/drivers/acpi/acpica/tbutils.c
index 9bef44b..8ed9b9a 100644
--- a/drivers/acpi/acpica/tbutils.c
+++ b/drivers/acpi/acpica/tbutils.c
@@ -503,14 +503,16 @@ acpi_tb_get_root_table_entry(u8 *table_entry, u32 table_entry_size)

/*******************************************************************************
*
- * FUNCTION: acpi_tb_parse_root_table
+ * FUNCTION: acpi_tb_root_table_install
*
* PARAMETERS: rsdp - Pointer to the RSDP
*
* RETURN: Status
*
* DESCRIPTION: This function is called to parse the Root System Description
- * Table (RSDT or XSDT)
+ * Table (RSDT or XSDT), and install all the system description
+ * tables defined in the root table into the global root table
+ * list.
*
* NOTE: Tables are mapped (not copied) for efficiency. The FACS must
* be mapped and cannot be copied because it contains the actual
@@ -519,7 +521,7 @@ acpi_tb_get_root_table_entry(u8 *table_entry, u32 table_entry_size)
******************************************************************************/

acpi_status __init
-acpi_tb_parse_root_table(acpi_physical_address rsdp_address)
+acpi_tb_root_table_install(acpi_physical_address rsdp_address)
{
struct acpi_table_rsdp *rsdp;
u32 table_entry_size;
@@ -673,7 +675,31 @@ acpi_tb_parse_root_table(acpi_physical_address rsdp_address)
/* Install tables in firmware into acpi_gbl_root_table_list */
acpi_tb_install_table_firmware(acpi_gbl_root_table_list.
tables[i].address, NULL, i);
+ }
+
+ return_ACPI_STATUS(AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_root_table_override
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: This function is called to allow the host OS to replace any
+ * table that has been installed into the global root table
+ * list.
+ *
+ ******************************************************************************/

+void __init
+acpi_tb_root_table_override(void)
+{
+ int i;
+
+ for (i = 2; i < acpi_gbl_root_table_list.current_table_count; i++) {
/* Override the installed tables if any */
acpi_tb_install_table_override(acpi_gbl_root_table_list.
tables[i].address, NULL, i);
@@ -686,6 +712,31 @@ acpi_tb_parse_root_table(acpi_physical_address rsdp_address)
acpi_tb_parse_fadt(i);
}
}
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_parse_root_table
+ *
+ * PARAMETERS: rsdp - Pointer to the RSDP
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: This function is called to parse the Root System Description
+ * Table (RSDT or XSDT)
+ *
+ ******************************************************************************/
+
+acpi_status __init
+acpi_tb_parse_root_table(acpi_physical_address rsdp_address)
+{
+ acpi_status status;
+
+ status = acpi_tb_root_table_install(rsdp_address);
+ if (ACPI_FAILURE(status))
+ return_ACPI_STATUS(status);
+
+ acpi_tb_root_table_override();

return_ACPI_STATUS(AE_OK);
}
--
1.7.1

2013-08-08 03:41:12

by Tang Chen

[permalink] [raw]
Subject: [PATCH part1 2/5] acpi, acpica: Call two new functions instead of acpi_tb_install_table() in acpi_tb_parse_root_table().

The previous patch introduced two new functions:
acpi_tb_install_table_firmware() and acpi_tb_install_table_override().

They are the same as acpi_tb_install_table() if they are called in sequence.

In order to split acpi_tb_parse_root_table(), we call these two functions
instead of acpi_tb_install_table() in acpi_tb_parse_root_table(). This will
keep acpi_tb_parse_root_table() works as before.

Signed-off-by: Tang Chen <[email protected]>
Reviewed-by: Zhang Yanfei <[email protected]>
---
drivers/acpi/acpica/tbutils.c | 9 +++++++--
1 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/drivers/acpi/acpica/tbutils.c b/drivers/acpi/acpica/tbutils.c
index 2db068c..9bef44b 100644
--- a/drivers/acpi/acpica/tbutils.c
+++ b/drivers/acpi/acpica/tbutils.c
@@ -670,8 +670,13 @@ acpi_tb_parse_root_table(acpi_physical_address rsdp_address)
* the header of each table
*/
for (i = 2; i < acpi_gbl_root_table_list.current_table_count; i++) {
- acpi_tb_install_table(acpi_gbl_root_table_list.tables[i].
- address, NULL, i);
+ /* Install tables in firmware into acpi_gbl_root_table_list */
+ acpi_tb_install_table_firmware(acpi_gbl_root_table_list.
+ tables[i].address, NULL, i);
+
+ /* Override the installed tables if any */
+ acpi_tb_install_table_override(acpi_gbl_root_table_list.
+ tables[i].address, NULL, i);

/* Special case for FADT - get the DSDT and FACS */

--
1.7.1

2013-08-08 03:41:10

by Tang Chen

[permalink] [raw]
Subject: [PATCH part1 1/5] acpi, acpica: Split acpi_tb_install_table() into two parts.

[Problem]

The current Linux cannot migrate pages used by the kerenl because
of the kernel direct mapping. In Linux kernel space, va = pa + PAGE_OFFSET.
When the pa is changed, we cannot simply update the pagetable and
keep the va unmodified. So the kernel pages are not migratable.

There are also some other issues will cause the kernel pages not migratable.
For example, the physical address may be cached somewhere and will be used.
It is not to update all the caches.

When doing memory hotplug in Linux, we first migrate all the pages in one
memory device somewhere else, and then remove the device. But if pages are
used by the kernel, they are not migratable. As a result, memory used by
the kernel cannot be hot-removed.

Modifying the kernel direct mapping mechanism is too difficult to do. And
it may cause the kernel performance down and unstable. So we use the following
way to do memory hotplug.


[What we are doing]

In Linux, memory in one numa node is divided into several zones. One of the
zones is ZONE_MOVABLE, which the kernel won't use.

In order to implement memory hotplug in Linux, we are going to arrange all
hotpluggable memory in ZONE_MOVABLE so that the kernel won't use these memory.

To do this, we need ACPI's help.


[How we do this]

In ACPI, SRAT(System Resource Affinity Table) contains NUMA info. The memory
affinities in SRAT record every memory range in the system, and also, flags
specifying if the memory range is hotpluggable.
(Please refer to ACPI spec 5.0 5.2.16)

With the help of SRAT, we have to do the following two things to achieve our
goal:

1. When doing memory hot-add, allow the users arranging hotpluggable as
ZONE_MOVABLE.
(This has been done by the MOVABLE_NODE functionality in Linux.)

2. when the system is booting, prevent bootmem allocator from allocating
hotpluggable memory for the kernel before the memory initialization
finishes.
(This is what we are going to do. And we need to do some modification in
ACPICA. See below.)


[About this patch-set]

There is a bootmem allocator named memblock in Linux. memblock starts to work
at very early time, and SRAT has not been parsed. So we don't know which memory
is hotpluggable. In order to prevent memblock from allocating hotpluggable
memory for the kernel, we need to obtain SRAT memory affinity info earlier.

In the current Linux kernel, the acpica code iterates acpi_gbl_root_table_list,
and install all the acpi tables into it at boot time. Then, it tries to find
if there is any override table in global array acpi_tables_addr. If any, reinstall
the override table into acpi_gbl_root_table_list.

In Linux, global array acpi_tables_addr can be fulfilled by ACPI_INITRD_TABLE_OVERRIDE
mechanism, which allows users to specify their own ACPI tables in initrd file, and
override the ones from firmware.

The whole procedure looks like the following:

setup_arch()
|-> ...... /* Setup direct mapping pagetables */
|->acpi_initrd_override() /* Store all override tables in acpi_tables_addr. */
|...
|->acpi_boot_table_init()
|->acpi_table_init()
| (Linux code)
-------------------------------------------------------------------------------------------------------
| (ACPICA code)
|->acpi_initialize_tables()
|->acpi_tb_parse_root_table() /* Parse RSDT or XSDT, find all tables in firmware */
|->for (each item in acpi_gbl_root_table_list)
|->acpi_tb_install_table()
|-> ...... /* Install one single table */
|->acpi_tb_table_override() /* Override one single table */

It does the table installation and overriding one by one.

In order to find SRAT at earlier time, we want to initialize acpi_gbl_root_table_list
earlier. But at the same time, keep ACPI_INITRD_TABLE_OVERRIDE procedure works as well.

The basic idea is, split the acpi_gbl_root_table_list initialization procedure into
two steps:
1. Install all tables from firmware, not one by one.
2. Override any table if necessary, not one by one.

After this patch-set, it will work like this:

setup_arch()
|-> ...... /* Install all tables from firmware (Step 1) */
|-> ...... /* Try to find if any override SRAT in initrd file, if yes, use it */
|-> ...... /* Use the SRAT from firmware */
|-> ...... /* memblock starts to work */
|-> ......
|->acpi_initrd_override() /* Initialize acpi_tables_addr with all override table. */
|...
|-> ...... /* Do the table override work for all tables (Step 2) */


In order to achieve this goal, we have to split all the following functions:

ACPICA:
acpi_tb_install_table()
acpi_tb_parse_root_table()
acpi_initialize_tables()

Linux acpi:
acpi_table_init()
acpi_boot_table_init()

Since ACPICA code is not just used by the Linux, so we should keep the ACPICA
side interfaces unmodified, and introduce new functions used in Linux.


This patch split acpi_tb_install_table() into two steps, and introduce two new
functions:
acpi_tb_install_table_firmware() and acpi_tb_install_table_override(),
which will be used later in Linux.

Signed-off-by: Tang Chen <[email protected]>
Reviewed-by: Zhang Yanfei <[email protected]>
---
drivers/acpi/acpica/tbutils.c | 118 +++++++++++++++++++++++++++++++++++-----
1 files changed, 103 insertions(+), 15 deletions(-)

diff --git a/drivers/acpi/acpica/tbutils.c b/drivers/acpi/acpica/tbutils.c
index bffdfc7..2db068c 100644
--- a/drivers/acpi/acpica/tbutils.c
+++ b/drivers/acpi/acpica/tbutils.c
@@ -249,28 +249,25 @@ struct acpi_table_header *acpi_tb_copy_dsdt(u32 table_index)

/*******************************************************************************
*
- * FUNCTION: acpi_tb_install_table
+ * FUNCTION: acpi_tb_install_table_firmware
*
- * PARAMETERS: address - Physical address of DSDT or FACS
+ * PARAMETERS: address - Physical address of the table to be
+ * installed
* signature - Table signature, NULL if no need to
* match
* table_index - Index into root table array
*
* RETURN: None
*
- * DESCRIPTION: Install an ACPI table into the global data structure. The
- * table override mechanism is called to allow the host
- * OS to replace any table before it is installed in the root
- * table array.
+ * DESCRIPTION: Install an ACPI table into the global data structure.
*
******************************************************************************/

void
-acpi_tb_install_table(acpi_physical_address address,
- char *signature, u32 table_index)
+acpi_tb_install_table_firmware(acpi_physical_address address,
+ char *signature, u32 table_index)
{
struct acpi_table_header *table;
- struct acpi_table_header *final_table;
struct acpi_table_desc *table_desc;

if (!address) {
@@ -312,6 +309,74 @@ acpi_tb_install_table(acpi_physical_address address,
table_desc->flags = ACPI_TABLE_ORIGIN_MAPPED;
ACPI_MOVE_32_TO_32(table_desc->signature.ascii, table->signature);

+ acpi_tb_print_table_header(table_desc->address, table);
+
+ /* Set the global integer width (based upon revision of the DSDT) */
+
+ if (table_index == ACPI_TABLE_INDEX_DSDT) {
+ acpi_ut_set_integer_width(table->revision);
+ }
+
+ unmap_and_exit:
+
+ /* Always unmap the table header that we mapped above */
+
+ acpi_os_unmap_memory(table, sizeof(struct acpi_table_header));
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_install_table_override
+ *
+ * PARAMETERS: address - Physical address of the table to be
+ * installed
+ * signature - Table signature, NULL if no need to
+ * match
+ * table_index - Index into root table array
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Override an ACPI table in the global data structure.
+ *
+ ******************************************************************************/
+
+void
+acpi_tb_install_table_override(acpi_physical_address address,
+ char *signature, u32 table_index)
+{
+ struct acpi_table_header *table;
+ struct acpi_table_header *final_table;
+ struct acpi_table_desc *table_desc;
+
+ if (!address) {
+ ACPI_ERROR((AE_INFO,
+ "Null physical address for ACPI table [%s]",
+ signature));
+ return;
+ }
+
+ /* Map just the table header */
+
+ table = acpi_os_map_memory(address, sizeof(struct acpi_table_header));
+ if (!table) {
+ ACPI_ERROR((AE_INFO,
+ "Could not map memory for table [%s] at %p",
+ signature, ACPI_CAST_PTR(void, address)));
+ return;
+ }
+
+ /* If a particular signature is expected (DSDT/FACS), it must match */
+
+ if (signature && !ACPI_COMPARE_NAME(table->signature, signature)) {
+ ACPI_BIOS_ERROR((AE_INFO,
+ "Invalid signature 0x%X for ACPI table, expected [%s]",
+ *ACPI_CAST_PTR(u32, table->signature),
+ signature));
+ goto unmap_and_exit;
+ }
+
+ table_desc = &acpi_gbl_root_table_list.tables[table_index];
+
/*
* ACPI Table Override:
*
@@ -332,12 +397,6 @@ acpi_tb_install_table(acpi_physical_address address,

acpi_tb_print_table_header(table_desc->address, final_table);

- /* Set the global integer width (based upon revision of the DSDT) */
-
- if (table_index == ACPI_TABLE_INDEX_DSDT) {
- acpi_ut_set_integer_width(final_table->revision);
- }
-
/*
* If we have a physical override during this early loading of the ACPI
* tables, unmap the table for now. It will be mapped again later when
@@ -359,6 +418,35 @@ acpi_tb_install_table(acpi_physical_address address,

/*******************************************************************************
*
+ * FUNCTION: acpi_tb_install_table
+ *
+ * PARAMETERS: address - Physical address of DSDT or FACS
+ * signature - Table signature, NULL if no need to
+ * match
+ * table_index - Index into root table array
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Install an ACPI table into the global data structure. The
+ * table override mechanism is called to allow the host
+ * OS to replace any table which has been installed in the root
+ * table array.
+ *
+ ******************************************************************************/
+
+void
+acpi_tb_install_table(acpi_physical_address address,
+ char *signature, u32 table_index)
+{
+ /* Install a table from firmware into acpi_gbl_root_table_list. */
+ acpi_tb_install_table_firmware(address, signature, table_index);
+
+ /* Override an installed table. */
+ acpi_tb_install_table_override(address, signature, table_index);
+}
+
+/*******************************************************************************
+ *
* FUNCTION: acpi_tb_get_root_table_entry
*
* PARAMETERS: table_entry - Pointer to the RSDT/XSDT table entry
--
1.7.1

2013-08-08 14:01:29

by Rafael J. Wysocki

[permalink] [raw]
Subject: Re: [PATCH part1 0/5] acpica: Split acpi_gbl_root_table_list initialization into two parts.

On Thursday, August 08, 2013 11:39:31 AM Tang Chen wrote:
> [Problem]
>
> The current Linux cannot migrate pages used by the kerenl because
> of the kernel direct mapping. In Linux kernel space, va = pa + PAGE_OFFSET.
> When the pa is changed, we cannot simply update the pagetable and
> keep the va unmodified. So the kernel pages are not migratable.
>
> There are also some other issues will cause the kernel pages not migratable.
> For example, the physical address may be cached somewhere and will be used.
> It is not to update all the caches.
>
> When doing memory hotplug in Linux, we first migrate all the pages in one
> memory device somewhere else, and then remove the device. But if pages are
> used by the kernel, they are not migratable. As a result, memory used by
> the kernel cannot be hot-removed.
>
> Modifying the kernel direct mapping mechanism is too difficult to do. And
> it may cause the kernel performance down and unstable. So we use the following
> way to do memory hotplug.
>
>
> [What we are doing]
>
> In Linux, memory in one numa node is divided into several zones. One of the
> zones is ZONE_MOVABLE, which the kernel won't use.
>
> In order to implement memory hotplug in Linux, we are going to arrange all
> hotpluggable memory in ZONE_MOVABLE so that the kernel won't use these memory.
>
> To do this, we need ACPI's help.
>
>
> [How we do this]
>
> In ACPI, SRAT(System Resource Affinity Table) contains NUMA info. The memory
> affinities in SRAT record every memory range in the system, and also, flags
> specifying if the memory range is hotpluggable.
> (Please refer to ACPI spec 5.0 5.2.16)
>
> With the help of SRAT, we have to do the following two things to achieve our
> goal:
>
> 1. When doing memory hot-add, allow the users arranging hotpluggable as
> ZONE_MOVABLE.
> (This has been done by the MOVABLE_NODE functionality in Linux.)
>
> 2. when the system is booting, prevent bootmem allocator from allocating
> hotpluggable memory for the kernel before the memory initialization
> finishes.
> (This is what we are going to do. And we need to do some modification in
> ACPICA. See below.)
>
>
> [About this patch-set]
>
> There is a bootmem allocator named memblock in Linux. memblock starts to work
> at very early time, and SRAT has not been parsed. So we don't know which memory
> is hotpluggable. In order to prevent memblock from allocating hotpluggable
> memory for the kernel, we need to obtain SRAT memory affinity info earlier.
>
> In the current Linux kernel, the acpica code iterates acpi_gbl_root_table_list,
> and install all the acpi tables into it at boot time. Then, it tries to find
> if there is any override table in global array acpi_tables_addr. If any, reinstall
> the override table into acpi_gbl_root_table_list.
>
> In Linux, global array acpi_tables_addr can be fulfilled by ACPI_INITRD_TABLE_OVERRIDE
> mechanism, which allows users to specify their own ACPI tables in initrd file, and
> override the ones from firmware.
>
> The whole procedure looks like the following:
>
> setup_arch()
> |-> ...... /* Setup direct mapping pagetables */
> |->acpi_initrd_override() /* Store all override tables in acpi_tables_addr. */
> |...
> |->acpi_boot_table_init()
> |->acpi_table_init()
> | (Linux code)
> ......................................................................................................
> | (ACPICA code)
> |->acpi_initialize_tables()
> |->acpi_tb_parse_root_table() /* Parse RSDT or XSDT, find all tables in firmware */
> |->for (each item in acpi_gbl_root_table_list)
> |->acpi_tb_install_table()
> |-> ...... /* Install one single table */
> |->acpi_tb_table_override() /* Override one single table */
>
> It does the table installation and overriding one by one.
>
> In order to find SRAT at earlier time, we want to initialize acpi_gbl_root_table_list
> earlier. But at the same time, keep ACPI_INITRD_TABLE_OVERRIDE procedure works as well.
>
> The basic idea is, split the acpi_gbl_root_table_list initialization procedure into
> two steps:
> 1. Install all tables from firmware, not one by one.
> 2. Override any table if necessary, not one by one.
>
> After this patch-set, it will work like this:
>
> setup_arch()
> |-> ...... /* Install all tables from firmware (Step 1) */
> |-> ...... /* Try to find if any override SRAT in initrd file, if yes, use it */
> |-> ...... /* Use the SRAT from firmware */
> |-> ...... /* memblock starts to work */
> |-> ......
> |->acpi_initrd_override() /* Initialize acpi_tables_addr with all override table. */
> |...
> |-> ...... /* Do the table override work for all tables (Step 2) */
>
>
> In order to achieve this goal, we have to split all the following functions:
>
> ACPICA:
> acpi_tb_install_table()
> acpi_tb_parse_root_table()
> acpi_initialize_tables()
>
> Linux acpi:
> acpi_table_init()
> acpi_boot_table_init()
>
> Since ACPICA code is not just used by the Linux, so we should keep the ACPICA
> side interfaces unmodified, and introduce new functions used in Linux.
>
>
> Tang Chen (5):
> acpi, acpica: Split acpi_tb_install_table() into two parts.
> acpi, acpica: Call two new functions instead of
> acpi_tb_install_table() in acpi_tb_parse_root_table().
> acpi, acpica: Split acpi_tb_parse_root_table() into two parts.
> acpi, acpica: Call two new functions instead of
> acpi_tb_parse_root_table() in acpi_initialize_tables().
> acpi, acpica: Split acpi_initialize_tables() into two parts.
>
> drivers/acpi/acpica/actables.h | 2 +
> drivers/acpi/acpica/tbutils.c | 184 +++++++++++++++++++++++++++++++++++-----
> drivers/acpi/acpica/tbxface.c | 69 ++++++++++++++--
> 3 files changed, 228 insertions(+), 27 deletions(-)

OK, thanks for re-organizing the patch series!

Bob, Lv, can you please review this part and let us know what you think?

Rafael

2013-08-14 01:38:32

by Tang Chen

[permalink] [raw]
Subject: Re: [PATCH part1 0/5] acpica: Split acpi_gbl_root_table_list initialization into two parts.

Hi Bob, Rafael,

I think these patches are unnecessary now. mm guys have decided to do
memory hotplug in another way, an easier way that we don't need to touch
ACPICA code.

So please ignore this patch-set.

Thanks for the help and suggestions. :)


On 08/08/2013 11:39 AM, Tang Chen wrote:
> [Problem]
>
> The current Linux cannot migrate pages used by the kerenl because
> of the kernel direct mapping. In Linux kernel space, va = pa + PAGE_OFFSET.
> When the pa is changed, we cannot simply update the pagetable and
> keep the va unmodified. So the kernel pages are not migratable.
>
> There are also some other issues will cause the kernel pages not migratable.
> For example, the physical address may be cached somewhere and will be used.
> It is not to update all the caches.
>
> When doing memory hotplug in Linux, we first migrate all the pages in one
> memory device somewhere else, and then remove the device. But if pages are
> used by the kernel, they are not migratable. As a result, memory used by
> the kernel cannot be hot-removed.
>
> Modifying the kernel direct mapping mechanism is too difficult to do. And
> it may cause the kernel performance down and unstable. So we use the following
> way to do memory hotplug.
>
>
> [What we are doing]
>
> In Linux, memory in one numa node is divided into several zones. One of the
> zones is ZONE_MOVABLE, which the kernel won't use.
>
> In order to implement memory hotplug in Linux, we are going to arrange all
> hotpluggable memory in ZONE_MOVABLE so that the kernel won't use these memory.
>
> To do this, we need ACPI's help.
>
>
> [How we do this]
>
> In ACPI, SRAT(System Resource Affinity Table) contains NUMA info. The memory
> affinities in SRAT record every memory range in the system, and also, flags
> specifying if the memory range is hotpluggable.
> (Please refer to ACPI spec 5.0 5.2.16)
>
> With the help of SRAT, we have to do the following two things to achieve our
> goal:
>
> 1. When doing memory hot-add, allow the users arranging hotpluggable as
> ZONE_MOVABLE.
> (This has been done by the MOVABLE_NODE functionality in Linux.)
>
> 2. when the system is booting, prevent bootmem allocator from allocating
> hotpluggable memory for the kernel before the memory initialization
> finishes.
> (This is what we are going to do. And we need to do some modification in
> ACPICA. See below.)
>
>
> [About this patch-set]
>
> There is a bootmem allocator named memblock in Linux. memblock starts to work
> at very early time, and SRAT has not been parsed. So we don't know which memory
> is hotpluggable. In order to prevent memblock from allocating hotpluggable
> memory for the kernel, we need to obtain SRAT memory affinity info earlier.
>
> In the current Linux kernel, the acpica code iterates acpi_gbl_root_table_list,
> and install all the acpi tables into it at boot time. Then, it tries to find
> if there is any override table in global array acpi_tables_addr. If any, reinstall
> the override table into acpi_gbl_root_table_list.
>
> In Linux, global array acpi_tables_addr can be fulfilled by ACPI_INITRD_TABLE_OVERRIDE
> mechanism, which allows users to specify their own ACPI tables in initrd file, and
> override the ones from firmware.
>
> The whole procedure looks like the following:
>
> setup_arch()
> |-> ...... /* Setup direct mapping pagetables */
> |->acpi_initrd_override() /* Store all override tables in acpi_tables_addr. */
> |...
> |->acpi_boot_table_init()
> |->acpi_table_init()
> | (Linux code)
> ......................................................................................................
> | (ACPICA code)
> |->acpi_initialize_tables()
> |->acpi_tb_parse_root_table() /* Parse RSDT or XSDT, find all tables in firmware */
> |->for (each item in acpi_gbl_root_table_list)
> |->acpi_tb_install_table()
> |-> ...... /* Install one single table */
> |->acpi_tb_table_override() /* Override one single table */
>
> It does the table installation and overriding one by one.
>
> In order to find SRAT at earlier time, we want to initialize acpi_gbl_root_table_list
> earlier. But at the same time, keep ACPI_INITRD_TABLE_OVERRIDE procedure works as well.
>
> The basic idea is, split the acpi_gbl_root_table_list initialization procedure into
> two steps:
> 1. Install all tables from firmware, not one by one.
> 2. Override any table if necessary, not one by one.
>
> After this patch-set, it will work like this:
>
> setup_arch()
> |-> ...... /* Install all tables from firmware (Step 1) */
> |-> ...... /* Try to find if any override SRAT in initrd file, if yes, use it */
> |-> ...... /* Use the SRAT from firmware */
> |-> ...... /* memblock starts to work */
> |-> ......
> |->acpi_initrd_override() /* Initialize acpi_tables_addr with all override table. */
> |...
> |-> ...... /* Do the table override work for all tables (Step 2) */
>
>
> In order to achieve this goal, we have to split all the following functions:
>
> ACPICA:
> acpi_tb_install_table()
> acpi_tb_parse_root_table()
> acpi_initialize_tables()
>
> Linux acpi:
> acpi_table_init()
> acpi_boot_table_init()
>
> Since ACPICA code is not just used by the Linux, so we should keep the ACPICA
> side interfaces unmodified, and introduce new functions used in Linux.
>
>
> Tang Chen (5):
> acpi, acpica: Split acpi_tb_install_table() into two parts.
> acpi, acpica: Call two new functions instead of
> acpi_tb_install_table() in acpi_tb_parse_root_table().
> acpi, acpica: Split acpi_tb_parse_root_table() into two parts.
> acpi, acpica: Call two new functions instead of
> acpi_tb_parse_root_table() in acpi_initialize_tables().
> acpi, acpica: Split acpi_initialize_tables() into two parts.
>
> drivers/acpi/acpica/actables.h | 2 +
> drivers/acpi/acpica/tbutils.c | 184 +++++++++++++++++++++++++++++++++++-----
> drivers/acpi/acpica/tbxface.c | 69 ++++++++++++++--
> 3 files changed, 228 insertions(+), 27 deletions(-)
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
>