acpica/acpica — pull request #27 by zetalog (2014-04-14 08:02:11+00:00)
Title: Acpica diverg

NOTES:
(
1. Some symbol names in this cover letter are Linux style so that I do not
need to maintain 2 copies of such big cover letter.
)

This series is generated to reduce divergences between Linux and ACPICA.
Before applying this series:
894 Lines; 3.2Kbytes
After applying this series:
696 Lines; 2.6KBytes

There are 3 requirements reported from Linux community and we haven't
addressed all of them in ACPICA yet:

1. Mapping strategy for early boot stage
In Linux during early boot stages, there are booting code using ACPI
tables. During this stage, tables are mapped using early_ioremap(), the
pointers returned by this API are not safe to be used after this stage,
so the mapped pointers should not be stored in acpi_gbl_root_table_list.
This is handled with code invoking acpi_tb_delete_table() here and there
in ACPICA and a global variable acpi_gbl_permanent_mmap in Linux to
distinguish the 2 stages. In Linux, early_acpi_os_unmap_memory() is
implemented to release the early_ioremap() returned pointers for Linux
which finally becomes the reversal of acpi_get_table().
2. Freeing table mappings when no users
There are large tables in the world, it is not good always mapping them
in the virtual address space even there is no users interested in them.
But currently for Linux, it is impossible to achieve this, as the API
acpi_get_table() will always map the tables and never unmap them. So
if someone reads the ACPI tables accesible through Linux
/sys/firmware/acpi/tables, they will never get unmapped.
3. Lacking in table releasing information
The length of mapping is only stored in acpi_gbl_root_table_list, thus
Linux trends to return it using acpi_get_table_with_size() so that it
can properly unmap exact the size of the mapping. But actually, there
are acpi_table_desc.pointer filled not with mapped pointers but filled
with external virtual addresses (ACPI_TABLE_ORIGIN_UNKNOWN/
ACPI_TABLE_ORIGIN_OVERRIDE) or filled with internall allocated virtual
addresses (ACPI_TABLE_ORIGIN_ALLOCATED), it is not sufficient just
returning the length to handle the situations of releasing such
pointers.

This patchset back ports above mentioned Linux specific code (thus they are
divergences) to ACPICA upstream:
1. acpi_get_table_with_size:
This is back ported as new acpi_get_table() with the table index
returned to utilize the information contained in acpi_table_desc.length
and acpi_table_desc.flags to release the returned pointer properly. If
a table is not used in ACPICA, this function simply maps and returns it
without filling acpi_table_desc.pointer so that a balanced reversal can
free the mapping of the returned pointer.
2. early_acpi_os_unmap_memory:
This is back ported as acpi_put_table() as a reversal of
acpi_get_table().
3. acpi_gbl_permanent_mmap:
This flag is useless to ACPICA as there is already code to support this
in ACPICA by always making acpi_table_desc.pointer not filled during
early boot stage.

After applying these series:
1. The effectiveness of acpi_get_table() and acpi_put_table() APIs:
===========================================================================
Stage Early - acpi_initialize_tables()
---------------------------------------------------------------------------
acpi_get_table() acquires an instant mapping and gbl_table_desc remains INSTALLED for all tables.
acpi_put_table() releases the instant mapping is not touched for all tables.
===========================================================================
Stage Late - acpi_load_tables()
---------------------------------------------------------------------------
acpi_get_table() returns internal pointer for DSDT/SSDT/PSDT/OEM/FACS tables.
acpi_put_table() is no op for DSDT/SSDT/PSDT/OEM/FACS tables.
acpi_get_table() acquires an instant mapping and gbl_table_desc remains INSTALLED for other tables.
acpi_put_table() releases the instant mapped gbl_table_desc is not touched for other tables.
===========================================================================

So we can achieve "early boot no-record" and "no-user, no-mapping"
Linux table handling requirements.

Known Issues:
1. Table lifecycle management to reduce more mappings
This is the first step to achive reduced memory mappings, further
improvements can be done to reduce the memory mappings when several
Linux kernel modules are referencing the same tables. While before
applying this patchset, as ACPICA always maintains one single mapping of
the table, there is no such issue. This issue can also be fixed by
implementing lifecycle management of the table validations (Adding
reference counting for acpi_table_desc, validates it when the count is
increased from 0 to 1 and invalidates it when the count is descreased
from 1 to 0). As currently all tables in Linux are used in the one
module per table style, we needn't fix this. To fix this, it can be
done in another patchset so that this patchset can be kept simple.

The patchset has been unit tested in AcpiExec by:
1. Initializing;
2. Executing exc_tbl ASLTS tests;
3. Executing "Load" command.
So that all original AcpiTbInstallTable() and AcpiTbOverrideTable()
invocations are covered.
It has also been linuxized and tested by booting an x86-64 machine with
CONFIG_ACPI enabled. There are "Load" opcodes executed in the kernel log.