[PATCH v3 1/5] ACPI: change __init to __ref for early_acpi_os_unmap_memory()
From: Zheng, Lv <hidden>
Date: 2016-02-26 06:39:52
Also in:
linux-acpi, linux-serial, lkml
Hi, Aleksey Though I promised you to have this done in 1 week: https://github.com/zetalog/acpica/commit/a234569 I implemented the idea and tried the cleanup in Linux. But unfortunately the cleanup triggered several locking issues inside of ACPICA table API users. So it doesn't seem to be so easy and quick to make it upstreamed. And I have to continue to test and improve the cleanup. I'm sorry for that, hope you can find substitute solutions before the cleanup is upstreamed. Thanks and best regards -Lv
From: Aleksey Makarov [mailto:aleksey.makarov at linaro.org] Sent: Monday, February 22, 2016 10:58 PM Subject: Re: [PATCH v3 1/5] ACPI: change __init to __ref for early_acpi_os_unmap_memory() Hi, On 02/22/2016 05:24 AM, Zheng, Lv wrote:quoted
Hi,quoted
From: Aleksey Makarov [mailto:aleksey.makarov at linaro.org] Subject: Re: [PATCH v3 1/5] ACPI: change __init to __ref for early_acpi_os_unmap_memory() Hi Lv, On 02/19/2016 05:58 AM, Zheng, Lv wrote:quoted
Hi,quoted
From: Peter Hurley [mailto:peter at hurleysoftware.com] Subject: Re: [PATCH v3 1/5] ACPI: change __init to __ref for early_acpi_os_unmap_memory() On 02/17/2016 07:36 PM, Zheng, Lv wrote:quoted
Hi,quoted
From: Aleksey Makarov [mailto:aleksey.makarov at linaro.org] Subject: Re: [PATCH v3 1/5] ACPI: change __init to __ref for early_acpi_os_unmap_memory() Hi Lv, Thank you for review. On 02/17/2016 05:51 AM, Zheng, Lv wrote: [..]quoted
quoted
quoted
early_acpi_os_unmap_memory() is marked as __init because it calls __acpi_unmap_table(), but only when acpi_gbl_permanent_mmapisquoted
quoted
notquoted
quoted
quoted
quoted
set.quoted
quoted
quoted
acpi_gbl_permanent_mmap is set in __init acpi_early_init() so it is safe to call early_acpi_os_unmap_memory() from anywhere We need this function to be non-__init because we need access to some tables at unpredictable time--it may be before or after acpi_gbl_permanent_mmap is set. For example, SPCR (Serial PortConsolequoted
quoted
quoted
quoted
quoted
Redirection) table is needed each time a new console is registered. It can be quite early (console_initcall) or when a module is inserted. When this table accessed before acpi_gbl_permanent_mmap is set, the pointer should be unmapped. This is exactly what this function does.[Lv Zheng] Why don't you use another API instead ofearly_acpi_os_unmap_memory()quoted
quoted
inquoted
quoted
case you want to unmap things in any cases. acpi_os_unmap_memory() should be the one to match this purpose. It checks acpi_gbl_ppermanent_mmap in acpi_os_unmap_iomem().As far as I understand, there exist two steps in ACPI initialization: 1. Before acpi_gbl_permanent_mmap is set, tables received with acpi_get_table_with_size() are mapped by early_memremap(). If a subsystem gets such a pointeritquoted
quoted
quoted
quoted
quoted
quoted
should be unmapped. 2 After acpi_gbl_permanent_mmap is set this pointer should not beunmappedquoted
quoted
at all.[Lv Zheng] This statement is wrong, this should be: As long as there is a __reference__ to the mapped table, the pointershouldquoted
quoted
quoted
quoted
not be unmapped.quoted
In fact, we have a series to introduce acpi_put_table() to achieve this. So your argument is wrong from very first point.quoted
That exactly what early_acpi_os_unmap_memory() does--it checks acpi_gbl_permanent_mmap. If I had used acpi_os_unmap_memory() afteracpi_gbl_permanent_mmapquoted
quoted
quoted
quoted
hadquoted
quoted
been set, it would have tried to free that pointer with an oops (actually, Icheckedquoted
quoted
thatquoted
quoted
quoted
quoted
and got that oops). So using acpi_os_unmap_memory() is not an option here, but early_acpi_os_unmap_memory() match perfectly.[Lv Zheng] I don't think so. For definition block tables, we know for sure there will always bereferences,quoted
quoted
until "Unload" opcode is invoked by the AML interpreter.quoted
But for the data tables, OSPMs should use them in this way: 1. map the table 2. parse the table and convert it to OS specific structures 3. unmap the table This helps to shrink virtual memory address space usages. So from this point of view, all data tables should be unmapped rightafterquoted
quoted
quoted
quoted
being parsed.quoted
Why do you need the map to be persistent in the kernel address space? You can always map a small table, but what if the table size is very big?quoted
quoted
quoted
And in fact early_acpi_os_unmap_memory() should be removed.I don't think so -- I have explained why. It does different thing. Probably it (and/or other functions in that api) should be renamed.[Lv Zheng] Just let me ask one more question. eary_acpi_os_unmap_memory() is not used inside of ACPICA. How ACPICA can work with just acpi_os_unmap_memory()? You can check drivers/acpi/tbxxx.c. Especially: acpi_tb_release_temp_table() and the code invoking it.quoted
quoted
[Lv Zheng] One more thing is: If you can't switch your driver to use acpi_os_unmap_memory()insteadquoted
quoted
ofquoted
quoted
quoted
quoted
early_acpi_os_unmap_memory(),quoted
then it implies that your driver does have a defect.I still don't understand what defect, sorry.[Lv Zheng] If you can't ensure this sequence for using the data tables: 1. map the table 2. parse the table and convert it to OS specific structure 3. unmap the table It implies there is a bug in the driver or a bug in the ACPI subsystem core.Exactly.[Lv Zheng] So it looks to me: Changing __init to __ref here is entirely not acceptable. This API should stay being invoked during early stage. Otherwise, it may leave us untrackable code that maps tables during earlystage and leaks maps to the late stage.quoted
If Linux contains such kind of code, I'm afraid, it will become impossible tointroduce acpi_put_table() to clean up the mappings.quoted
Because when acpi_put_table() is called during the late stage to free a mapacquired during the early stage, it then obviously will end up with panic. Can you please sugggest a common method to access ACPI tables that works both before *and* after acpi_gbl_permanent_mmap is set and __init code is removed?[Lv Zheng] Do not change __init for now. Currently you should: 1. before acpi_gbl_permanent_mmap is set: acpi_get_table_with_size() parse the table early_acpi_os_unmap_memory() Do your driver early stuff here 2. after acpi_gbl_permanent_mmap is set: acpi_get_table() Parse the table Do your driver late stuff here <- note there is no API now being an inverse of acpi_get_table().That's fine. These are two different methods to access the table. I need one that works in both cases. Of course, they could be combined, but I am not sure if I can access the acpi_gbl_permanent_mmap variable--it seems to be an implementation detail of ACPI code. Instead I am going to use the 1st method once and cache the result like this: static int __init parse(void) { static bool parsed; if (!parsed) { acpi_get_table_with_size() /* parse the table and cache the result */ early_acpi_os_unmap_memory() parse = true; } } arch_initcal(parse()); int __ref the_handler_where_I_need_the_parse_results(void) { parse(); /* use the data */ } I hope you are OK with it.quoted
Besides, I'm about to insert error messages between 1 and 2. If an early map is not release, error message will be prompted to thedevelopers. AFAICS, there is such an error message and I saw it. Refer to check_early_ioremap_leak() at mm/early_ioremap.cquoted
And if you don't follow the above rules, it mean you are trying to lay a mine,waiting for me to step on it.quoted
That's why this change is entirely not acceptable.Ok, I see.quoted
I'm about to send out the cleanup series in 1 week, and will Cc you. You can rebase your code on top of the cleanup series.Thank you Aleksey Makarovquoted
Thanks and best regards -Lvquoted
quoted
Thanks and best regards -Lvquoted
The central problem here is the way Aleksey is trying to hookup a console. What should be happening in this series is: 1. early map SPCR 2. parse the SPCR table 3. call add_preferred_console() to add the SPCR console to the consoletablequoted
quoted
4. unmap SPCR This trivial and unobtrusive method would already have a 8250 console running via SPCR. I've already pointed this out in previous reviews. Further, the above method *will be required anyway* for the DBG2 tabletoquoted
quoted
quoted
quoted
start an earlycon, which I've already pointed out in previous reviews. Then to enable amba-pl011 console via ACPI, add a console match()methodquoted
quoted
quoted
quoted
similar to the 8250 console match() method, univ8250_console_match(). FWIW, PCI earlycon + console support was already submitted once beforebutquoted
quoted
never picked up by GregKH. I think I'll just grab that and re-submit so you would know what to emit for console options in the add_preferred_console(). Regards, Peter Hurleyquoted
quoted
quoted
There is an early bootup requirement in Linux. Maps acquired during the early stage should be freed by the driverduringquoted
quoted
quoted
quoted
thequoted
quoted
early stage.quoted
And the driver should re-acquire the memory map after booting.Exactly. That's why I use early_acpi_os_unmap_memory(). The point isthatquoted
quoted
quoted
quoted
that code can be called *before* acpi_gbl_permanent_mmap is set (at early initializationofquoted
quoted
forquoted
quoted
example 8250 console) or *after* acpi_gbl_permanent_mmap is set (at insertion of a modulethatquoted
quoted
quoted
quoted
registers a console), We just can not tell if the received table pointer should or sould not befreedquoted
quoted
quoted
quoted
with early_memunmap() (actually __acpi_unmap_table() or whatever) without checking acpi_gbl_permanent_mmap, but that's all too low level.[Lv Zheng] The driver should make sure that: Map/unmap is paired during early stage. For late stage, it should be another pair of map/unmap.quoted
Another option, as you describe, is to get this pointer early, don't free it[Lv Zheng] I mean you should free it early.quoted
untill acpi_gbl_permanent_mmap is set, then free it (with early_acpi_os_unmap_memory(), that's ok because acpi_gbl_permanent_mmap is set in an init code), then getthequoted
quoted
quoted
quoted
persistent pointer to the table. The problem with it is that we can not just watch acpi_gbl_permanent_mmap to catch this exact moment. And also accessingacpi_gbl_permanent_mmapquoted
quoted
isquoted
quoted
not good as it probably is an implementation detail (i. e. too lowlevel) of the ACPI code. Or I probably miss what you are suggesting.[Lv Zheng] I mean, you should: During early stage: acpi_os_map_memory() Parse the table. acpi_os_unmap_memory().quoted
quoted
This is because, during early bootup stage, there are only limited slotsavailable for drivers to map memory.quoted
So by changing __init to __ref here, you probably will hide many suchdefects.quoted
quoted
What defects? This funcions checks acpi_gbl_permanent_mmap. BTW, exactly the same thing is done in the beginning of acpi_os_unmap_memory() and than's ok, that function is __ref.quoted
And solving issues in this way doesn't seem to be an improvement.Could you please tell me where I am wrong? I still don't understandyourquoted
quoted
quoted
quoted
point.quoted
[Lv Zheng] But anyway, the defect should be in ACPI subsystem core. The cause should be the API itself - acpi_get_table(). So I agree you can use early_acpi_os_unmap_memory() during theperiodquoted
quoted
thequoted
quoted
root causes are not cleaned up.quoted
But the bottom line is: the driver need to ensure thatearly_acpi_os_unmap_memory() is always invoked.quoted
As long as you can ensure this, I don't have objections for deployingearly_acpi_os_unmap_memory() for now.quoted
Thanks and best regards -Lvquoted
Thank you Aleksey Makarovquoted
Thanks and best regards -Lvquoted
Thanks and best regards -Lvquoted
Signed-off-by: Aleksey Makarov <redacted> --- drivers/acpi/osl.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 67da6fb..8a552cd 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c@@ -497,7 +497,11 @@ void __ref acpi_os_unmap_memory(void*virt,quoted
quoted
quoted
quoted
quoted
quoted
quoted
acpi_size size) } EXPORT_SYMBOL_GPL(acpi_os_unmap_memory); -void __init early_acpi_os_unmap_memory(void __iomem *virt,acpi_sizequoted
quoted
quoted
quoted
size)quoted
+/* + * acpi_gbl_permanent_mmap is set in __init acpi_early_init() + * so it is safe to call early_acpi_os_unmap_memory() fromanywherequoted
quoted
quoted
quoted
quoted
quoted
quoted
+ */ +void __ref early_acpi_os_unmap_memory(void __iomem *virt,acpi_sizequoted
quoted
quoted
quoted
size)quoted
{ if (!acpi_gbl_permanent_mmap) __acpi_unmap_table(virt, size); -- 2.7.1 -- To unsubscribe from this list: send the line "unsubscribe linux-acpi"inquoted
quoted
quoted
quoted
quoted
quoted
quoted
quoted
quoted
the body of a message to majordomo at vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.htmlquoted
quoted
quoted
quoted
quoted
quoted
-- To unsubscribe from this list: send the line "unsubscribe linux-acpi" in the body of a message to majordomo at vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.htmlquoted
quoted
quoted