Hi, On 02/22/2016 05:24 AM, Zheng, Lv wrote: > Hi, > >> From: Aleksey Makarov [mailto:aleksey.makarov@xxxxxxxxxx] >> 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: >>> Hi, >>> >>>> From: Peter Hurley [mailto:peter@xxxxxxxxxxxxxxxxxx] >>>> 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: >>>>> Hi, >>>>> >>>>>> From: Aleksey Makarov [mailto:aleksey.makarov@xxxxxxxxxx] >>>>>> 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: >>>>>> >>>>>> [..] >>>>>> >>>>>>>>> early_acpi_os_unmap_memory() is marked as __init because it calls >>>>>>>>> __acpi_unmap_table(), but only when acpi_gbl_permanent_mmap is >> not >>>>>> set. >>>>>>>>> >>>>>>>>> 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 Port >>>> Console >>>>>>>>> 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 of >>>> early_acpi_os_unmap_memory() >>>>>> in >>>>>>>> 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 pointer it >>>>>> should be unmapped. >>>>>> >>>>>> 2 After acpi_gbl_permanent_mmap is set this pointer should not be >>>> unmapped >>>>>> at all. >>>>>> >>>>> [Lv Zheng] >>>>> This statement is wrong, this should be: >>>>> As long as there is a __reference__ to the mapped table, the pointer should >>>> not be unmapped. >>>>> In fact, we have a series to introduce acpi_put_table() to achieve this. >>>>> So your argument is wrong from very first point. >>>>> >>>>>> That exactly what early_acpi_os_unmap_memory() does--it checks >>>>>> acpi_gbl_permanent_mmap. >>>>>> If I had used acpi_os_unmap_memory() after acpi_gbl_permanent_mmap >>>> had >>>>>> been set, >>>>>> it would have tried to free that pointer with an oops (actually, I checked >> that >>>>>> 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 be >> references, >>>> until "Unload" opcode is invoked by the AML interpreter. >>>>> 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 right after >>>> being parsed. >>>>> 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? >>>>> >>>>>> >>>>>>>> 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. >>>>> >>>>>>> [Lv Zheng] >>>>>>> One more thing is: >>>>>>> If you can't switch your driver to use acpi_os_unmap_memory() instead >> of >>>>>> early_acpi_os_unmap_memory(), >>>>>>> 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 early >> stage and leaks maps to the late stage. >>> If Linux contains such kind of code, I'm afraid, it will become impossible to >> introduce acpi_put_table() to clean up the mappings. >>> Because when acpi_put_table() is called during the late stage to free a map >> acquired 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. > 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 the developers. AFAICS, there is such an error message and I saw it. Refer to check_early_ioremap_leak() at mm/early_ioremap.c > 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. > That's why this change is entirely not acceptable. Ok, I see. > 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 Makarov > > Thanks and best regards > -Lv > >> >>> Thanks and best regards >>> -Lv >>> >>>> 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 console >> table >>>> 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 table to >>>> start an earlycon, which I've already pointed out in previous reviews. >>>> >>>> Then to enable amba-pl011 console via ACPI, add a console match() method >>>> similar to the 8250 console match() method, univ8250_console_match(). >>>> >>>> FWIW, PCI earlycon + console support was already submitted once before >> but >>>> 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 Hurley >>>> >>>> >>>>>>> There is an early bootup requirement in Linux. >>>>>>> Maps acquired during the early stage should be freed by the driver during >>>> the >>>>>> early stage. >>>>>>> And the driver should re-acquire the memory map after booting. >>>>>> >>>>>> Exactly. That's why I use early_acpi_os_unmap_memory(). The point is >> that >>>>>> that code can be >>>>>> called *before* acpi_gbl_permanent_mmap is set (at early initialization >> of >>>> for >>>>>> example 8250 console) >>>>>> or *after* acpi_gbl_permanent_mmap is set (at insertion of a module >> that >>>>>> registers a console), >>>>>> We just can not tell if the received table pointer should or sould not be >> freed >>>>>> 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. >>>>> >>>>>> >>>>>> Another option, as you describe, is to get this pointer early, don't free it >>>>> [Lv Zheng] >>>>> I mean you should free it early. >>>>> >>>>>> 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 get >> the >>>>>> 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 accessing >> acpi_gbl_permanent_mmap >>>> is >>>>>> 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(). >>>>> >>>>>>> This is because, during early bootup stage, there are only limited slots >>>>>> available for drivers to map memory. >>>>>>> So by changing __init to __ref here, you probably will hide many such >>>> defects. >>>>>> >>>>>> 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. >>>>>> >>>>>>> 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 understand your >>>> point. >>>>> [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 the period >> the >>>> root causes are not cleaned up. >>>>> But the bottom line is: the driver need to ensure that >>>> early_acpi_os_unmap_memory() is always invoked. >>>>> As long as you can ensure this, I don't have objections for deploying >>>> early_acpi_os_unmap_memory() for now. >>>>> >>>>> Thanks and best regards >>>>> -Lv >>>>> >>>>>> >>>>>> Thank you >>>>>> Aleksey Makarov >>>>>> >>>>>>> >>>>>>> Thanks and best regards >>>>>>> -Lv >>>>>>> >>>>>>>> >>>>>>>> Thanks and best regards >>>>>>>> -Lv >>>>>>>> >>>>>>>>> >>>>>>>>> Signed-off-by: Aleksey Makarov <aleksey.makarov@xxxxxxxxxx> >>>>>>>>> --- >>>>>>>>> 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, >>>>>>>>> acpi_size size) >>>>>>>>> } >>>>>>>>> EXPORT_SYMBOL_GPL(acpi_os_unmap_memory); >>>>>>>>> >>>>>>>>> -void __init early_acpi_os_unmap_memory(void __iomem *virt, >>>> acpi_size >>>>>>>> size) >>>>>>>>> +/* >>>>>>>>> + * acpi_gbl_permanent_mmap is set in __init acpi_early_init() >>>>>>>>> + * so it is safe to call early_acpi_os_unmap_memory() from >> anywhere >>>>>>>>> + */ >>>>>>>>> +void __ref early_acpi_os_unmap_memory(void __iomem *virt, >>>> acpi_size >>>>>>>> size) >>>>>>>>> { >>>>>>>>> if (!acpi_gbl_permanent_mmap) >>>>>>>>> __acpi_unmap_table(virt, size); >>>>>>>>> -- >>>>>>>>> 2.7.1 >>>>>>>>> >>>>>>>>> -- >>>>>>>>> To unsubscribe from this list: send the line "unsubscribe linux-acpi" in >>>>>>>>> the body of a message to majordomo@xxxxxxxxxxxxxxx >>>>>>>>> More majordomo info at http://vger.kernel.org/majordomo- >> info.html >>>>>>>> -- >>>>>>>> To unsubscribe from this list: send the line "unsubscribe linux-acpi" in >>>>>>>> the body of a message to majordomo@xxxxxxxxxxxxxxx >>>>>>>> More majordomo info at http://vger.kernel.org/majordomo-info.html >>> -- To unsubscribe from this list: send the line "unsubscribe linux-serial" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html