[PATCH 0/6] lmb: Fix reserving the same region multiple times

Since commit 1d9aa4a283da ("lmb: Fix the allocation of overlapping memory areas with !LMB_NONE") the lmb_add_region_flags() returns -1 when the caller tries to add the already existing region with !LMB_NONE flags (it was returning 0 before that patch). That causes boot_fdt_reserve_region() function to print erroneous error messages when it's called consequently more than one time.
Make lmb_add_region_flags() return -EEXIST when the already added region with !LMB_NONE flags is being added, and then check that error code in boot_fdt_reserve_region() to avoid printing the misleading error messages.
I didn't want to change lmb_add_region_flags() behavior back to always returning 0 on attempts to add already existing regions with !LMB_NONE flags, as the unit tests in test/lib/lmb.c would break, and also commit 1d9aa4a283da ("lmb: Fix the allocation of overlapping memory areas with !LMB_NONE") specifically states that behavior is expected and required for efi_allocate_pages() calls with type=EFI_ALLOCATE_ADDRESS.
All unit tests pass in sandbox U-Boot, with a small test modification in [PATCH 2/6]. I also made a bit of LMB cleanups in this series, while at it. Only [PATCH 6/6] introduces an actual functional change.
Sam Protsenko (6): lmb: Fix flags data type in lmb_add_region_flags() lmb: Return -EEXIST in lmb_add_region_flags() if region already added lmb: Make const flag_str[] in lmb_print_region_flags() more const lmb: Improve coding style lmb: Improve kernel-doc comments boot: fdt: Handle already reserved memory in boot_fdt_reserve_region()
boot/image-fdt.c | 2 +- include/lmb.h | 125 ++++++++++++++++++++++++++++------------------- lib/lmb.c | 105 +++++++++++++-------------------------- test/lib/lmb.c | 2 +- 4 files changed, 109 insertions(+), 125 deletions(-)

rgnflags variable in lmb_add_region_flags() has incorrect type: it's declared as phys_size_t when it should be enum lmb_flags. That copy-paste mistake was firstly introduced in commit 59c0ea5df33f ("lmb: Add support of flags for no-map properties"), and then copied further into commit ed17a33fed29 ("lmb: make LMB memory map persistent and global"). Fix it by using the correct type to match struct lmb_region field.
No functional change.
Fixes: ed17a33fed29 ("lmb: make LMB memory map persistent and global") Fixes: 59c0ea5df33f ("lmb: Add support of flags for no-map properties") Signed-off-by: Sam Protsenko semen.protsenko@linaro.org --- lib/lmb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/lmb.c b/lib/lmb.c index b03237bc06cb..713f072f75ee 100644 --- a/lib/lmb.c +++ b/lib/lmb.c @@ -200,7 +200,7 @@ static long lmb_add_region_flags(struct alist *lmb_rgn_lst, phys_addr_t base, for (i = 0; i < lmb_rgn_lst->count; i++) { phys_addr_t rgnbase = rgn[i].base; phys_size_t rgnsize = rgn[i].size; - phys_size_t rgnflags = rgn[i].flags; + enum lmb_flags rgnflags = rgn[i].flags;
ret = lmb_addrs_adjacent(base, size, rgnbase, rgnsize); if (ret > 0) {

On Sun, 8 Dec 2024 at 02:21, Sam Protsenko semen.protsenko@linaro.org wrote:
rgnflags variable in lmb_add_region_flags() has incorrect type: it's declared as phys_size_t when it should be enum lmb_flags. That copy-paste mistake was firstly introduced in commit 59c0ea5df33f ("lmb: Add support of flags for no-map properties"), and then copied further into commit ed17a33fed29 ("lmb: make LMB memory map persistent and global"). Fix it by using the correct type to match struct lmb_region field.
No functional change.
Fixes: ed17a33fed29 ("lmb: make LMB memory map persistent and global") Fixes: 59c0ea5df33f ("lmb: Add support of flags for no-map properties") Signed-off-by: Sam Protsenko semen.protsenko@linaro.org
lib/lmb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/lmb.c b/lib/lmb.c index b03237bc06cb..713f072f75ee 100644 --- a/lib/lmb.c +++ b/lib/lmb.c @@ -200,7 +200,7 @@ static long lmb_add_region_flags(struct alist *lmb_rgn_lst, phys_addr_t base, for (i = 0; i < lmb_rgn_lst->count; i++) { phys_addr_t rgnbase = rgn[i].base; phys_size_t rgnsize = rgn[i].size;
phys_size_t rgnflags = rgn[i].flags;
enum lmb_flags rgnflags = rgn[i].flags; ret = lmb_addrs_adjacent(base, size, rgnbase, rgnsize); if (ret > 0) {
-- 2.39.5
Reviewed-by: Ilias Apalodimas ilias.apalodimas@linaro.org

On Sun, 8 Dec 2024 at 05:51, Sam Protsenko semen.protsenko@linaro.org wrote:
rgnflags variable in lmb_add_region_flags() has incorrect type: it's declared as phys_size_t when it should be enum lmb_flags. That copy-paste mistake was firstly introduced in commit 59c0ea5df33f ("lmb: Add support of flags for no-map properties"), and then copied further into commit ed17a33fed29 ("lmb: make LMB memory map persistent and global"). Fix it by using the correct type to match struct lmb_region field.
No functional change.
Fixes: ed17a33fed29 ("lmb: make LMB memory map persistent and global") Fixes: 59c0ea5df33f ("lmb: Add support of flags for no-map properties") Signed-off-by: Sam Protsenko semen.protsenko@linaro.org
So this is the right code for sure. But is this fixing any issue? I suspect not. If so, the Fixes tag should be removed when applying.
Acked-by: Sughosh Ganu sughosh.ganu@linaro.org
-sughosh
lib/lmb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/lmb.c b/lib/lmb.c index b03237bc06cb..713f072f75ee 100644 --- a/lib/lmb.c +++ b/lib/lmb.c @@ -200,7 +200,7 @@ static long lmb_add_region_flags(struct alist *lmb_rgn_lst, phys_addr_t base, for (i = 0; i < lmb_rgn_lst->count; i++) { phys_addr_t rgnbase = rgn[i].base; phys_size_t rgnsize = rgn[i].size;
phys_size_t rgnflags = rgn[i].flags;
enum lmb_flags rgnflags = rgn[i].flags; ret = lmb_addrs_adjacent(base, size, rgnbase, rgnsize); if (ret > 0) {
-- 2.39.5

An attempt to add the already added LMB region (with exactly the same start address, size and flags) using lmb_add_region_flags() ends up in lmb_addrs_overlap() check, which eventually leads to either returning 0 if 'flags' is LMB_NONE, or -1 otherwise. It makes it impossible for the user of this function to catch the case when the region is already added and differentiate it from regular errors. That in turn may lead to incorrect error handling in the caller code, like reporting misleading errors or interrupting the normal code path where it could be treated as the normal case. An example is boot_fdt_reserve_region() function, which might be called twice (e.g. during board startup in initr_lmb(), and then during 'booti' command booting the OS), thus trying to reserve exactly the same memory regions described in device tree twice, which produces an error message on second call.
Implement the detection of cases when the already added region is trying to be added again, and return -EEXIST error code in case the region exists and it's not LMB_NONE; for LMB_NONE return 0, to conform to unit tests (specifically test_alloc_addr() in test/lib/lmb.c) and the preferred behavior described in commit 1d9aa4a283da ("lmb: Fix the allocation of overlapping memory areas with !LMB_NONE"). The change of lmb_add_region_flags() return values is described in the table below:
Return case Pre-1d9 1d9 New ----------------------------------------------------------- Added successfully 0 0 0 Failed to add -1 -1 -1 Already added, flags == LMB_NONE 0 0 0 Already added, flags != LMB_NONE 0 -1 -EEXIST
Rework all affected functions and their documentation. Also fix the corresponding unit test which checks reserving the same region with the same flags to account for the changed return value.
No functional change is intended (by this patch itself).
Fixes: 1d9aa4a283da ("lmb: Fix the allocation of overlapping memory areas with !LMB_NONE") Signed-off-by: Sam Protsenko semen.protsenko@linaro.org --- lib/lmb.c | 18 ++++++++++++++---- test/lib/lmb.c | 2 +- 2 files changed, 15 insertions(+), 5 deletions(-)
diff --git a/lib/lmb.c b/lib/lmb.c index 713f072f75ee..ce0dc49345fb 100644 --- a/lib/lmb.c +++ b/lib/lmb.c @@ -183,8 +183,10 @@ static long lmb_resize_regions(struct alist *lmb_rgn_lst, * the function might resize an already existing region or coalesce two * adjacent regions. * - * - * Returns: 0 if the region addition successful, -1 on failure + * Return: + * * %0 - Added successfully, or it's already added (only if LMB_NONE) + * * %-EEXIST - The region is already added, and flags != LMB_NONE + * * %-1 - Failure */ static long lmb_add_region_flags(struct alist *lmb_rgn_lst, phys_addr_t base, phys_size_t size, enum lmb_flags flags) @@ -202,6 +204,14 @@ static long lmb_add_region_flags(struct alist *lmb_rgn_lst, phys_addr_t base, phys_size_t rgnsize = rgn[i].size; enum lmb_flags rgnflags = rgn[i].flags;
+ /* Already have this region, so we're done */ + if (base == rgnbase && size == rgnsize && flags == rgnflags) { + if (flags == LMB_NONE) + return 0; + else + return -EEXIST; + } + ret = lmb_addrs_adjacent(base, size, rgnbase, rgnsize); if (ret > 0) { if (flags != rgnflags) @@ -667,7 +677,7 @@ long lmb_add(phys_addr_t base, phys_size_t size) * * Free up a region of memory. * - * Return: 0 if successful, -1 on failure + * Return: 0 if successful, negative error code on failure */ long lmb_free_flags(phys_addr_t base, phys_size_t size, uint flags) @@ -818,7 +828,7 @@ static phys_addr_t _lmb_alloc_addr(phys_addr_t base, phys_size_t size, lmb_memory[rgn].size, base + size - 1, 1)) { /* ok, reserve the memory */ - if (lmb_reserve_flags(base, size, flags) >= 0) + if (!lmb_reserve_flags(base, size, flags)) return base; } } diff --git a/test/lib/lmb.c b/test/lib/lmb.c index 0bd29e2a4fe7..48c3c966f8f2 100644 --- a/test/lib/lmb.c +++ b/test/lib/lmb.c @@ -754,7 +754,7 @@ static int lib_test_lmb_flags(struct unit_test_state *uts)
/* reserve again, same flag */ ret = lmb_reserve_flags(0x40010000, 0x10000, LMB_NOMAP); - ut_asserteq(ret, -1L); + ut_asserteq(ret, -EEXIST); ASSERT_LMB(mem_lst, used_lst, ram, ram_size, 1, 0x40010000, 0x10000, 0, 0, 0, 0);

Hi Sam,
On Sun, 8 Dec 2024 at 02:21, Sam Protsenko semen.protsenko@linaro.org wrote:
An attempt to add the already added LMB region (with exactly the same start address, size and flags) using lmb_add_region_flags() ends up in lmb_addrs_overlap() check, which eventually leads to either returning 0 if 'flags' is LMB_NONE, or -1 otherwise. It makes it impossible for the user of this function to catch the case when the region is already added and differentiate it from regular errors. That in turn may lead to incorrect error handling in the caller code, like reporting misleading errors or interrupting the normal code path where it could be treated as the normal case. An example is boot_fdt_reserve_region() function, which might be called twice (e.g. during board startup in initr_lmb(), and then during 'booti' command booting the OS), thus trying to reserve exactly the same memory regions described in device tree twice, which produces an error message on second call.
Implement the detection of cases when the already added region is trying to be added again, and return -EEXIST error code in case the region exists and it's not LMB_NONE; for LMB_NONE return 0, to conform to unit tests (specifically test_alloc_addr() in test/lib/lmb.c) and the preferred behavior described in commit 1d9aa4a283da ("lmb: Fix the allocation of overlapping memory areas with !LMB_NONE"). The change of lmb_add_region_flags() return values is described in the table below:
Return case Pre-1d9 1d9 New ----------------------------------------------------------- Added successfully 0 0 0 Failed to add -1 -1 -1 Already added, flags == LMB_NONE 0 0 0 Already added, flags != LMB_NONE 0 -1 -EEXIST
Rework all affected functions and their documentation. Also fix the corresponding unit test which checks reserving the same region with the same flags to account for the changed return value.
No functional change is intended (by this patch itself).
Fixes: 1d9aa4a283da ("lmb: Fix the allocation of overlapping memory areas with !LMB_NONE") Signed-off-by: Sam Protsenko semen.protsenko@linaro.org
lib/lmb.c | 18 ++++++++++++++---- test/lib/lmb.c | 2 +- 2 files changed, 15 insertions(+), 5 deletions(-)
diff --git a/lib/lmb.c b/lib/lmb.c index 713f072f75ee..ce0dc49345fb 100644 --- a/lib/lmb.c +++ b/lib/lmb.c @@ -183,8 +183,10 @@ static long lmb_resize_regions(struct alist *lmb_rgn_lst,
- the function might resize an already existing region or coalesce two
- adjacent regions.
- Returns: 0 if the region addition successful, -1 on failure
- Return:
- %0 - Added successfully, or it's already added (only if LMB_NONE)
- %-EEXIST - The region is already added, and flags != LMB_NONE
*/
- %-1 - Failure
static long lmb_add_region_flags(struct alist *lmb_rgn_lst, phys_addr_t base, phys_size_t size, enum lmb_flags flags) @@ -202,6 +204,14 @@ static long lmb_add_region_flags(struct alist *lmb_rgn_lst, phys_addr_t base, phys_size_t rgnsize = rgn[i].size; enum lmb_flags rgnflags = rgn[i].flags;
/* Already have this region, so we're done */
if (base == rgnbase && size == rgnsize && flags == rgnflags) {
if (flags == LMB_NONE)
return 0;
else
return -EEXIST;
}
The change looks sane and I did plan to clean up LMB after the release with similar logic. But I wonder should we return -EEXIST here or a few lines below in 'else if (lmb_addrs_overlap(base, size, rgnbase, rgnsize)) {'
There are two cases we return -1 there, we could return -EEXIST. Something like diff --git a/lib/lmb.c b/lib/lmb.c index 3a765c11bee6..f3d5b616c376 100644 --- a/lib/lmb.c +++ b/lib/lmb.c @@ -226,7 +226,7 @@ static long lmb_add_region_flags(struct alist *lmb_rgn_lst, phys_addr_t base, coalesced++; break; } else { - return -1; + return -EEXIST; } } }
I am not sure about the lmb_resize_regions() failure, I think we should return a different error
ret = lmb_addrs_adjacent(base, size, rgnbase, rgnsize); if (ret > 0) { if (flags != rgnflags)
@@ -667,7 +677,7 @@ long lmb_add(phys_addr_t base, phys_size_t size)
- Free up a region of memory.
- Return: 0 if successful, -1 on failure
*/
- Return: 0 if successful, negative error code on failure
long lmb_free_flags(phys_addr_t base, phys_size_t size, uint flags) @@ -818,7 +828,7 @@ static phys_addr_t _lmb_alloc_addr(phys_addr_t base, phys_size_t size, lmb_memory[rgn].size, base + size - 1, 1)) { /* ok, reserve the memory */
if (lmb_reserve_flags(base, size, flags) >= 0)
if (!lmb_reserve_flags(base, size, flags)) return base; } }
diff --git a/test/lib/lmb.c b/test/lib/lmb.c index 0bd29e2a4fe7..48c3c966f8f2 100644 --- a/test/lib/lmb.c +++ b/test/lib/lmb.c @@ -754,7 +754,7 @@ static int lib_test_lmb_flags(struct unit_test_state *uts)
/* reserve again, same flag */ ret = lmb_reserve_flags(0x40010000, 0x10000, LMB_NOMAP);
ut_asserteq(ret, -1L);
ut_asserteq(ret, -EEXIST); ASSERT_LMB(mem_lst, used_lst, ram, ram_size, 1, 0x40010000, 0x10000, 0, 0, 0, 0);
-- 2.39.5
Other than that it looks good thanks for fixing this! Regards /Ilias

On Sun, 8 Dec 2024 at 12:20, Ilias Apalodimas ilias.apalodimas@linaro.org wrote:
Hi Sam,
On Sun, 8 Dec 2024 at 02:21, Sam Protsenko semen.protsenko@linaro.org wrote:
An attempt to add the already added LMB region (with exactly the same start address, size and flags) using lmb_add_region_flags() ends up in lmb_addrs_overlap() check, which eventually leads to either returning 0 if 'flags' is LMB_NONE, or -1 otherwise. It makes it impossible for the user of this function to catch the case when the region is already added and differentiate it from regular errors. That in turn may lead to incorrect error handling in the caller code, like reporting misleading errors or interrupting the normal code path where it could be treated as the normal case. An example is boot_fdt_reserve_region() function, which might be called twice (e.g. during board startup in initr_lmb(), and then during 'booti' command booting the OS), thus trying to reserve exactly the same memory regions described in device tree twice, which produces an error message on second call.
Implement the detection of cases when the already added region is trying to be added again, and return -EEXIST error code in case the region exists and it's not LMB_NONE; for LMB_NONE return 0, to conform to unit tests (specifically test_alloc_addr() in test/lib/lmb.c) and the preferred behavior described in commit 1d9aa4a283da ("lmb: Fix the allocation of overlapping memory areas with !LMB_NONE"). The change of lmb_add_region_flags() return values is described in the table below:
Return case Pre-1d9 1d9 New ----------------------------------------------------------- Added successfully 0 0 0 Failed to add -1 -1 -1 Already added, flags == LMB_NONE 0 0 0 Already added, flags != LMB_NONE 0 -1 -EEXIST
Rework all affected functions and their documentation. Also fix the corresponding unit test which checks reserving the same region with the same flags to account for the changed return value.
No functional change is intended (by this patch itself).
Fixes: 1d9aa4a283da ("lmb: Fix the allocation of overlapping memory areas with !LMB_NONE") Signed-off-by: Sam Protsenko semen.protsenko@linaro.org
lib/lmb.c | 18 ++++++++++++++---- test/lib/lmb.c | 2 +- 2 files changed, 15 insertions(+), 5 deletions(-)
diff --git a/lib/lmb.c b/lib/lmb.c index 713f072f75ee..ce0dc49345fb 100644 --- a/lib/lmb.c +++ b/lib/lmb.c @@ -183,8 +183,10 @@ static long lmb_resize_regions(struct alist *lmb_rgn_lst,
- the function might resize an already existing region or coalesce two
- adjacent regions.
- Returns: 0 if the region addition successful, -1 on failure
- Return:
- %0 - Added successfully, or it's already added (only if LMB_NONE)
- %-EEXIST - The region is already added, and flags != LMB_NONE
*/
- %-1 - Failure
static long lmb_add_region_flags(struct alist *lmb_rgn_lst, phys_addr_t base, phys_size_t size, enum lmb_flags flags) @@ -202,6 +204,14 @@ static long lmb_add_region_flags(struct alist *lmb_rgn_lst, phys_addr_t base, phys_size_t rgnsize = rgn[i].size; enum lmb_flags rgnflags = rgn[i].flags;
/* Already have this region, so we're done */
if (base == rgnbase && size == rgnsize && flags == rgnflags) {
if (flags == LMB_NONE)
return 0;
else
return -EEXIST;
}
The change looks sane and I did plan to clean up LMB after the release with similar logic. But I wonder should we return -EEXIST here or a few lines below in 'else if (lmb_addrs_overlap(base, size, rgnbase, rgnsize)) {'
There are two cases we return -1 there, we could return -EEXIST. Something like diff --git a/lib/lmb.c b/lib/lmb.c index 3a765c11bee6..f3d5b616c376 100644 --- a/lib/lmb.c +++ b/lib/lmb.c @@ -226,7 +226,7 @@ static long lmb_add_region_flags(struct alist *lmb_rgn_lst, phys_addr_t base, coalesced++; break; } else {
return -1;
return -EEXIST; } } }
+1 for this approach. Otherwise we are effectively reverting 1d9aa4a283da.
Sam, can you please check if this change also fixes the issue that you see. Thanks.
-sughosh
I am not sure about the lmb_resize_regions() failure, I think we should return a different error
ret = lmb_addrs_adjacent(base, size, rgnbase, rgnsize); if (ret > 0) { if (flags != rgnflags)
@@ -667,7 +677,7 @@ long lmb_add(phys_addr_t base, phys_size_t size)
- Free up a region of memory.
- Return: 0 if successful, -1 on failure
*/
- Return: 0 if successful, negative error code on failure
long lmb_free_flags(phys_addr_t base, phys_size_t size, uint flags) @@ -818,7 +828,7 @@ static phys_addr_t _lmb_alloc_addr(phys_addr_t base, phys_size_t size, lmb_memory[rgn].size, base + size - 1, 1)) { /* ok, reserve the memory */
if (lmb_reserve_flags(base, size, flags) >= 0)
if (!lmb_reserve_flags(base, size, flags)) return base; } }
diff --git a/test/lib/lmb.c b/test/lib/lmb.c index 0bd29e2a4fe7..48c3c966f8f2 100644 --- a/test/lib/lmb.c +++ b/test/lib/lmb.c @@ -754,7 +754,7 @@ static int lib_test_lmb_flags(struct unit_test_state *uts)
/* reserve again, same flag */ ret = lmb_reserve_flags(0x40010000, 0x10000, LMB_NOMAP);
ut_asserteq(ret, -1L);
ut_asserteq(ret, -EEXIST); ASSERT_LMB(mem_lst, used_lst, ram, ram_size, 1, 0x40010000, 0x10000, 0, 0, 0, 0);
-- 2.39.5
Other than that it looks good thanks for fixing this! Regards /Ilias

On Mon, Dec 9, 2024 at 1:08 AM Sughosh Ganu sughosh.ganu@linaro.org wrote:
On Sun, 8 Dec 2024 at 12:20, Ilias Apalodimas ilias.apalodimas@linaro.org wrote:
Hi Sam,
On Sun, 8 Dec 2024 at 02:21, Sam Protsenko semen.protsenko@linaro.org wrote:
An attempt to add the already added LMB region (with exactly the same start address, size and flags) using lmb_add_region_flags() ends up in lmb_addrs_overlap() check, which eventually leads to either returning 0 if 'flags' is LMB_NONE, or -1 otherwise. It makes it impossible for the user of this function to catch the case when the region is already added and differentiate it from regular errors. That in turn may lead to incorrect error handling in the caller code, like reporting misleading errors or interrupting the normal code path where it could be treated as the normal case. An example is boot_fdt_reserve_region() function, which might be called twice (e.g. during board startup in initr_lmb(), and then during 'booti' command booting the OS), thus trying to reserve exactly the same memory regions described in device tree twice, which produces an error message on second call.
Implement the detection of cases when the already added region is trying to be added again, and return -EEXIST error code in case the region exists and it's not LMB_NONE; for LMB_NONE return 0, to conform to unit tests (specifically test_alloc_addr() in test/lib/lmb.c) and the preferred behavior described in commit 1d9aa4a283da ("lmb: Fix the allocation of overlapping memory areas with !LMB_NONE"). The change of lmb_add_region_flags() return values is described in the table below:
Return case Pre-1d9 1d9 New ----------------------------------------------------------- Added successfully 0 0 0 Failed to add -1 -1 -1 Already added, flags == LMB_NONE 0 0 0 Already added, flags != LMB_NONE 0 -1 -EEXIST
Rework all affected functions and their documentation. Also fix the corresponding unit test which checks reserving the same region with the same flags to account for the changed return value.
No functional change is intended (by this patch itself).
Fixes: 1d9aa4a283da ("lmb: Fix the allocation of overlapping memory areas with !LMB_NONE") Signed-off-by: Sam Protsenko semen.protsenko@linaro.org
lib/lmb.c | 18 ++++++++++++++---- test/lib/lmb.c | 2 +- 2 files changed, 15 insertions(+), 5 deletions(-)
diff --git a/lib/lmb.c b/lib/lmb.c index 713f072f75ee..ce0dc49345fb 100644 --- a/lib/lmb.c +++ b/lib/lmb.c @@ -183,8 +183,10 @@ static long lmb_resize_regions(struct alist *lmb_rgn_lst,
- the function might resize an already existing region or coalesce two
- adjacent regions.
- Returns: 0 if the region addition successful, -1 on failure
- Return:
- %0 - Added successfully, or it's already added (only if LMB_NONE)
- %-EEXIST - The region is already added, and flags != LMB_NONE
*/
- %-1 - Failure
static long lmb_add_region_flags(struct alist *lmb_rgn_lst, phys_addr_t base, phys_size_t size, enum lmb_flags flags) @@ -202,6 +204,14 @@ static long lmb_add_region_flags(struct alist *lmb_rgn_lst, phys_addr_t base, phys_size_t rgnsize = rgn[i].size; enum lmb_flags rgnflags = rgn[i].flags;
/* Already have this region, so we're done */
if (base == rgnbase && size == rgnsize && flags == rgnflags) {
if (flags == LMB_NONE)
return 0;
else
return -EEXIST;
}
The change looks sane and I did plan to clean up LMB after the release with similar logic. But I wonder should we return -EEXIST here or a few lines below in 'else if (lmb_addrs_overlap(base, size, rgnbase, rgnsize)) {'
There are two cases we return -1 there, we could return -EEXIST. Something like diff --git a/lib/lmb.c b/lib/lmb.c index 3a765c11bee6..f3d5b616c376 100644 --- a/lib/lmb.c +++ b/lib/lmb.c @@ -226,7 +226,7 @@ static long lmb_add_region_flags(struct alist *lmb_rgn_lst, phys_addr_t base, coalesced++; break; } else {
return -1;
return -EEXIST; } } }
+1 for this approach. Otherwise we are effectively reverting 1d9aa4a283da.
I'll send v2 soon, addressing all comments and including this suggestion.
Sam, can you please check if this change also fixes the issue that you see. Thanks.
Indeed. Three birds with one stone :) Meaning the sandbox one is fixed as well. That was a really good suggestion, to move -EEXIST. Thanks for letting me know about fixed cases!
-sughosh
I am not sure about the lmb_resize_regions() failure, I think we should return a different error
ret = lmb_addrs_adjacent(base, size, rgnbase, rgnsize); if (ret > 0) { if (flags != rgnflags)
@@ -667,7 +677,7 @@ long lmb_add(phys_addr_t base, phys_size_t size)
- Free up a region of memory.
- Return: 0 if successful, -1 on failure
*/
- Return: 0 if successful, negative error code on failure
long lmb_free_flags(phys_addr_t base, phys_size_t size, uint flags) @@ -818,7 +828,7 @@ static phys_addr_t _lmb_alloc_addr(phys_addr_t base, phys_size_t size, lmb_memory[rgn].size, base + size - 1, 1)) { /* ok, reserve the memory */
if (lmb_reserve_flags(base, size, flags) >= 0)
if (!lmb_reserve_flags(base, size, flags)) return base; } }
diff --git a/test/lib/lmb.c b/test/lib/lmb.c index 0bd29e2a4fe7..48c3c966f8f2 100644 --- a/test/lib/lmb.c +++ b/test/lib/lmb.c @@ -754,7 +754,7 @@ static int lib_test_lmb_flags(struct unit_test_state *uts)
/* reserve again, same flag */ ret = lmb_reserve_flags(0x40010000, 0x10000, LMB_NOMAP);
ut_asserteq(ret, -1L);
ut_asserteq(ret, -EEXIST); ASSERT_LMB(mem_lst, used_lst, ram, ram_size, 1, 0x40010000, 0x10000, 0, 0, 0, 0);
-- 2.39.5
Other than that it looks good thanks for fixing this! Regards /Ilias

On Sun, Dec 8, 2024 at 12:50 AM Ilias Apalodimas ilias.apalodimas@linaro.org wrote:
Hi Sam,
On Sun, 8 Dec 2024 at 02:21, Sam Protsenko semen.protsenko@linaro.org wrote:
An attempt to add the already added LMB region (with exactly the same start address, size and flags) using lmb_add_region_flags() ends up in lmb_addrs_overlap() check, which eventually leads to either returning 0 if 'flags' is LMB_NONE, or -1 otherwise. It makes it impossible for the user of this function to catch the case when the region is already added and differentiate it from regular errors. That in turn may lead to incorrect error handling in the caller code, like reporting misleading errors or interrupting the normal code path where it could be treated as the normal case. An example is boot_fdt_reserve_region() function, which might be called twice (e.g. during board startup in initr_lmb(), and then during 'booti' command booting the OS), thus trying to reserve exactly the same memory regions described in device tree twice, which produces an error message on second call.
Implement the detection of cases when the already added region is trying to be added again, and return -EEXIST error code in case the region exists and it's not LMB_NONE; for LMB_NONE return 0, to conform to unit tests (specifically test_alloc_addr() in test/lib/lmb.c) and the preferred behavior described in commit 1d9aa4a283da ("lmb: Fix the allocation of overlapping memory areas with !LMB_NONE"). The change of lmb_add_region_flags() return values is described in the table below:
Return case Pre-1d9 1d9 New ----------------------------------------------------------- Added successfully 0 0 0 Failed to add -1 -1 -1 Already added, flags == LMB_NONE 0 0 0 Already added, flags != LMB_NONE 0 -1 -EEXIST
Rework all affected functions and their documentation. Also fix the corresponding unit test which checks reserving the same region with the same flags to account for the changed return value.
No functional change is intended (by this patch itself).
Fixes: 1d9aa4a283da ("lmb: Fix the allocation of overlapping memory areas with !LMB_NONE") Signed-off-by: Sam Protsenko semen.protsenko@linaro.org
lib/lmb.c | 18 ++++++++++++++---- test/lib/lmb.c | 2 +- 2 files changed, 15 insertions(+), 5 deletions(-)
diff --git a/lib/lmb.c b/lib/lmb.c index 713f072f75ee..ce0dc49345fb 100644 --- a/lib/lmb.c +++ b/lib/lmb.c @@ -183,8 +183,10 @@ static long lmb_resize_regions(struct alist *lmb_rgn_lst,
- the function might resize an already existing region or coalesce two
- adjacent regions.
- Returns: 0 if the region addition successful, -1 on failure
- Return:
- %0 - Added successfully, or it's already added (only if LMB_NONE)
- %-EEXIST - The region is already added, and flags != LMB_NONE
*/
- %-1 - Failure
static long lmb_add_region_flags(struct alist *lmb_rgn_lst, phys_addr_t base, phys_size_t size, enum lmb_flags flags) @@ -202,6 +204,14 @@ static long lmb_add_region_flags(struct alist *lmb_rgn_lst, phys_addr_t base, phys_size_t rgnsize = rgn[i].size; enum lmb_flags rgnflags = rgn[i].flags;
/* Already have this region, so we're done */
if (base == rgnbase && size == rgnsize && flags == rgnflags) {
if (flags == LMB_NONE)
return 0;
else
return -EEXIST;
}
The change looks sane and I did plan to clean up LMB after the release with similar logic. But I wonder should we return -EEXIST here or a few lines below in 'else if (lmb_addrs_overlap(base, size, rgnbase, rgnsize)) {'
Yes, that makes sense. That's actually the exact line of code I initially debugged the problem to. Adding the "exactly the same region" corner case was a bad idea, because it misses the case when a region was coalesced with some other region, and is now contained inside of a bigger block. I will rework that in v2.
There are two cases we return -1 there, we could return -EEXIST. Something like diff --git a/lib/lmb.c b/lib/lmb.c index 3a765c11bee6..f3d5b616c376 100644 --- a/lib/lmb.c +++ b/lib/lmb.c @@ -226,7 +226,7 @@ static long lmb_add_region_flags(struct alist *lmb_rgn_lst, phys_addr_t base, coalesced++; break; } else {
return -1;
return -EEXIST; } } }
I am not sure about the lmb_resize_regions() failure, I think we should return a different error
No, that seems like a different case. I think all 'region exists' cases for !LMB_NONE are handled in the code you referenced above, and all LMB_NONE cases are handled below, in "if (coalesced) return 0;" code.
Right now it looks like only LMB_NONE regions can be merged. I wonder if it's intended, because it's not mentioned in corresponding LMB_* flags documentation, other than LMB_NOOVERWRITE. Also, commit "lmb: allow for resizing lmb regions" only mentions LMB_NOOVERWRITE. Anyways, that's out of scope here I guess.
ret = lmb_addrs_adjacent(base, size, rgnbase, rgnsize); if (ret > 0) { if (flags != rgnflags)
@@ -667,7 +677,7 @@ long lmb_add(phys_addr_t base, phys_size_t size)
- Free up a region of memory.
- Return: 0 if successful, -1 on failure
*/
- Return: 0 if successful, negative error code on failure
long lmb_free_flags(phys_addr_t base, phys_size_t size, uint flags) @@ -818,7 +828,7 @@ static phys_addr_t _lmb_alloc_addr(phys_addr_t base, phys_size_t size, lmb_memory[rgn].size, base + size - 1, 1)) { /* ok, reserve the memory */
if (lmb_reserve_flags(base, size, flags) >= 0)
if (!lmb_reserve_flags(base, size, flags)) return base; } }
diff --git a/test/lib/lmb.c b/test/lib/lmb.c index 0bd29e2a4fe7..48c3c966f8f2 100644 --- a/test/lib/lmb.c +++ b/test/lib/lmb.c @@ -754,7 +754,7 @@ static int lib_test_lmb_flags(struct unit_test_state *uts)
/* reserve again, same flag */ ret = lmb_reserve_flags(0x40010000, 0x10000, LMB_NOMAP);
ut_asserteq(ret, -1L);
ut_asserteq(ret, -EEXIST); ASSERT_LMB(mem_lst, used_lst, ram, ram_size, 1, 0x40010000, 0x10000, 0, 0, 0, 0);
-- 2.39.5
Other than that it looks good thanks for fixing this! Regards /Ilias

flag_str[] is a pointer to const. Make it also a const pointer. Improve a style a bit while a it, to make this line fit 80 characters limit.
No functional change.
Signed-off-by: Sam Protsenko semen.protsenko@linaro.org --- lib/lmb.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/lib/lmb.c b/lib/lmb.c index ce0dc49345fb..1642ce48bbbd 100644 --- a/lib/lmb.c +++ b/lib/lmb.c @@ -482,7 +482,8 @@ static int lmb_map_update_notify(phys_addr_t addr, phys_size_t size, u8 op,
static void lmb_print_region_flags(enum lmb_flags flags) { - const char *flag_str[] = { "none", "no-map", "no-overwrite", "no-notify" }; + const char * const flag_str[] = { "none", "no-map", "no-overwrite", + "no-notify" }; unsigned int pflags = flags & (LMB_NOMAP | LMB_NOOVERWRITE | LMB_NONOTIFY);

On Sun, 8 Dec 2024 at 02:21, Sam Protsenko semen.protsenko@linaro.org wrote:
flag_str[] is a pointer to const. Make it also a const pointer. Improve a style a bit while a it, to make this line fit 80 characters limit.
No functional change.
Signed-off-by: Sam Protsenko semen.protsenko@linaro.org
lib/lmb.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/lib/lmb.c b/lib/lmb.c index ce0dc49345fb..1642ce48bbbd 100644 --- a/lib/lmb.c +++ b/lib/lmb.c @@ -482,7 +482,8 @@ static int lmb_map_update_notify(phys_addr_t addr, phys_size_t size, u8 op,
static void lmb_print_region_flags(enum lmb_flags flags) {
const char *flag_str[] = { "none", "no-map", "no-overwrite", "no-notify" };
const char * const flag_str[] = { "none", "no-map", "no-overwrite",
"no-notify" }; unsigned int pflags = flags & (LMB_NOMAP | LMB_NOOVERWRITE | LMB_NONOTIFY);
-- 2.39.5
Reviewed-by: Ilias Apalodimas ilias.apalodimas@linaro.org

Fix checkpatch warnings. No functional change.
Signed-off-by: Sam Protsenko semen.protsenko@linaro.org --- lib/lmb.c | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-)
diff --git a/lib/lmb.c b/lib/lmb.c index 1642ce48bbbd..8c1c9b0f67c8 100644 --- a/lib/lmb.c +++ b/lib/lmb.c @@ -57,7 +57,6 @@ static long lmb_regions_overlap(struct alist *lmb_rgn_lst, unsigned long r1, unsigned long r2) { struct lmb_region *rgn = lmb_rgn_lst->data; - phys_addr_t base1 = rgn[r1].base; phys_size_t size1 = rgn[r1].size; phys_addr_t base2 = rgn[r2].base; @@ -70,11 +69,11 @@ static long lmb_regions_adjacent(struct alist *lmb_rgn_lst, unsigned long r1, unsigned long r2) { struct lmb_region *rgn = lmb_rgn_lst->data; - phys_addr_t base1 = rgn[r1].base; phys_size_t size1 = rgn[r1].size; phys_addr_t base2 = rgn[r2].base; phys_size_t size2 = rgn[r2].size; + return lmb_addrs_adjacent(base1, size1, base2, size2); }
@@ -235,9 +234,9 @@ static long lmb_add_region_flags(struct alist *lmb_rgn_lst, phys_addr_t base,
coalesced++; break; - } else { - return -1; } + + return -1; } }
@@ -288,14 +287,17 @@ static long _lmb_free(struct alist *lmb_rgn_lst, phys_addr_t base, phys_addr_t end = base + size - 1; int i;
- rgnbegin = rgnend = 0; /* supress gcc warnings */ + /* Suppress GCC warnings */ + rgnbegin = 0; + rgnend = 0; + rgn = lmb_rgn_lst->data; /* Find the region where (base, size) belongs to */ for (i = 0; i < lmb_rgn_lst->count; i++) { rgnbegin = rgn[i].base; rgnend = rgnbegin + rgn[i].size - 1;
- if ((rgnbegin <= base) && (end <= rgnend)) + if (rgnbegin <= base && end <= rgnend) break; }
@@ -304,7 +306,7 @@ static long _lmb_free(struct alist *lmb_rgn_lst, phys_addr_t base, return -1;
/* Check to see if we are removing entire region */ - if ((rgnbegin == base) && (rgnend == end)) { + if (rgnbegin == base && rgnend == end) { lmb_remove_region(lmb_rgn_lst, i); return 0; } @@ -340,6 +342,7 @@ static long lmb_overlaps_region(struct alist *lmb_rgn_lst, phys_addr_t base, for (i = 0; i < lmb_rgn_lst->count; i++) { phys_addr_t rgnbase = rgn[i].base; phys_size_t rgnsize = rgn[i].size; + if (lmb_addrs_overlap(base, size, rgnbase, rgnsize)) break; } @@ -715,7 +718,7 @@ long lmb_reserve(phys_addr_t base, phys_size_t size) }
static phys_addr_t _lmb_alloc_base(phys_size_t size, ulong align, - phys_addr_t max_addr, enum lmb_flags flags) + phys_addr_t max_addr, enum lmb_flags flags) { int ret; long i, rgn; @@ -730,16 +733,18 @@ static phys_addr_t _lmb_alloc_base(phys_size_t size, ulong align,
if (lmbsize < size) continue; - if (max_addr == LMB_ALLOC_ANYWHERE) + + if (max_addr == LMB_ALLOC_ANYWHERE) { base = lmb_align_down(lmbbase + lmbsize - size, align); - else if (lmbbase < max_addr) { + } else if (lmbbase < max_addr) { base = lmbbase + lmbsize; if (base < lmbbase) base = -1; base = min(base, max_addr); base = lmb_align_down(base - size, align); - } else + } else { continue; + }
while (base && lmbbase <= base) { rgn = lmb_overlaps_region(&lmb.used_mem, base, size); @@ -813,7 +818,7 @@ phys_addr_t lmb_alloc_base_flags(phys_size_t size, ulong align, }
static phys_addr_t _lmb_alloc_addr(phys_addr_t base, phys_size_t size, - enum lmb_flags flags) + enum lmb_flags flags) { long rgn; struct lmb_region *lmb_memory = lmb.free_mem.data;

On Sun, 8 Dec 2024 at 02:21, Sam Protsenko semen.protsenko@linaro.org wrote:
Fix checkpatch warnings. No functional change.
Signed-off-by: Sam Protsenko semen.protsenko@linaro.org
lib/lmb.c | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-)
diff --git a/lib/lmb.c b/lib/lmb.c index 1642ce48bbbd..8c1c9b0f67c8 100644 --- a/lib/lmb.c +++ b/lib/lmb.c @@ -57,7 +57,6 @@ static long lmb_regions_overlap(struct alist *lmb_rgn_lst, unsigned long r1, unsigned long r2) { struct lmb_region *rgn = lmb_rgn_lst->data;
phys_addr_t base1 = rgn[r1].base; phys_size_t size1 = rgn[r1].size; phys_addr_t base2 = rgn[r2].base;
@@ -70,11 +69,11 @@ static long lmb_regions_adjacent(struct alist *lmb_rgn_lst, unsigned long r1, unsigned long r2) { struct lmb_region *rgn = lmb_rgn_lst->data;
phys_addr_t base1 = rgn[r1].base; phys_size_t size1 = rgn[r1].size; phys_addr_t base2 = rgn[r2].base; phys_size_t size2 = rgn[r2].size;
return lmb_addrs_adjacent(base1, size1, base2, size2);
}
@@ -235,9 +234,9 @@ static long lmb_add_region_flags(struct alist *lmb_rgn_lst, phys_addr_t base,
coalesced++; break;
} else {
return -1; }
return -1; } }
@@ -288,14 +287,17 @@ static long _lmb_free(struct alist *lmb_rgn_lst, phys_addr_t base, phys_addr_t end = base + size - 1; int i;
rgnbegin = rgnend = 0; /* supress gcc warnings */
/* Suppress GCC warnings */
rgnbegin = 0;
rgnend = 0;
rgn = lmb_rgn_lst->data; /* Find the region where (base, size) belongs to */ for (i = 0; i < lmb_rgn_lst->count; i++) { rgnbegin = rgn[i].base; rgnend = rgnbegin + rgn[i].size - 1;
if ((rgnbegin <= base) && (end <= rgnend))
if (rgnbegin <= base && end <= rgnend) break; }
@@ -304,7 +306,7 @@ static long _lmb_free(struct alist *lmb_rgn_lst, phys_addr_t base, return -1;
/* Check to see if we are removing entire region */
if ((rgnbegin == base) && (rgnend == end)) {
if (rgnbegin == base && rgnend == end) { lmb_remove_region(lmb_rgn_lst, i); return 0; }
@@ -340,6 +342,7 @@ static long lmb_overlaps_region(struct alist *lmb_rgn_lst, phys_addr_t base, for (i = 0; i < lmb_rgn_lst->count; i++) { phys_addr_t rgnbase = rgn[i].base; phys_size_t rgnsize = rgn[i].size;
if (lmb_addrs_overlap(base, size, rgnbase, rgnsize)) break; }
@@ -715,7 +718,7 @@ long lmb_reserve(phys_addr_t base, phys_size_t size) }
static phys_addr_t _lmb_alloc_base(phys_size_t size, ulong align,
phys_addr_t max_addr, enum lmb_flags flags)
phys_addr_t max_addr, enum lmb_flags flags)
{ int ret; long i, rgn; @@ -730,16 +733,18 @@ static phys_addr_t _lmb_alloc_base(phys_size_t size, ulong align,
if (lmbsize < size) continue;
if (max_addr == LMB_ALLOC_ANYWHERE)
if (max_addr == LMB_ALLOC_ANYWHERE) { base = lmb_align_down(lmbbase + lmbsize - size, align);
else if (lmbbase < max_addr) {
} else if (lmbbase < max_addr) { base = lmbbase + lmbsize; if (base < lmbbase) base = -1; base = min(base, max_addr); base = lmb_align_down(base - size, align);
} else
} else { continue;
} while (base && lmbbase <= base) { rgn = lmb_overlaps_region(&lmb.used_mem, base, size);
@@ -813,7 +818,7 @@ phys_addr_t lmb_alloc_base_flags(phys_size_t size, ulong align, }
static phys_addr_t _lmb_alloc_addr(phys_addr_t base, phys_size_t size,
enum lmb_flags flags)
enum lmb_flags flags)
{ long rgn; struct lmb_region *lmb_memory = lmb.free_mem.data; -- 2.39.5
Acked-by: Ilias Apalodimas ilias.apalodimas@linaro.org

Fix warnings from kernel-doc script. Improve and unify overall style of kernel-doc comments in lmb source files. Move all kernel-doc comments for public functions into the header, as recommended in U-Boot documentation, which also takes care of existing duplication. While at it, do a bit of cosmetic cleanups as well.
No functional change.
Signed-off-by: Sam Protsenko semen.protsenko@linaro.org --- include/lmb.h | 125 ++++++++++++++++++++++++++++++-------------------- lib/lmb.c | 55 ---------------------- 2 files changed, 74 insertions(+), 106 deletions(-)
diff --git a/include/lmb.h b/include/lmb.h index f221f0cce8f7..03d5fac6aa79 100644 --- a/include/lmb.h +++ b/include/lmb.h @@ -1,6 +1,13 @@ /* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Logical memory blocks. + * + * Copyright (C) 2001 Peter Bergner, IBM Corp. + */ + #ifndef _LINUX_LMB_H #define _LINUX_LMB_H + #ifdef __KERNEL__
#include <alist.h> @@ -8,21 +15,15 @@ #include <asm/u-boot.h> #include <linux/bitops.h>
-/* - * Logical memory blocks. - * - * Copyright (C) 2001 Peter Bergner, IBM Corp. - */ - -#define LMB_ALLOC_ANYWHERE 0 -#define LMB_ALIST_INITIAL_SIZE 4 +#define LMB_ALLOC_ANYWHERE 0 +#define LMB_ALIST_INITIAL_SIZE 4
/** - * enum lmb_flags - definition of memory region attributes - * @LMB_NONE: no special request - * @LMB_NOMAP: don't add to mmu configuration - * @LMB_NOOVERWRITE: the memory region cannot be overwritten/re-reserved - * @LMB_NONOTIFY: do not notify other modules of changes to this memory region + * enum lmb_flags - Definition of memory region attributes + * @LMB_NONE: No special request + * @LMB_NOMAP: Don't add to MMU configuration + * @LMB_NOOVERWRITE: The memory region cannot be overwritten/re-reserved + * @LMB_NONOTIFY: Do not notify other modules of changes to this memory region */ enum lmb_flags { LMB_NONE = 0, @@ -32,11 +33,10 @@ enum lmb_flags { };
/** - * struct lmb_region - Description of one region. - * - * @base: Base address of the region. - * @size: Size of the region - * @flags: memory region attributes + * struct lmb_region - Description of one region + * @base: Base address of the region + * @size: Size of the region + * @flags: Memory region attributes */ struct lmb_region { phys_addr_t base; @@ -46,10 +46,9 @@ struct lmb_region {
/** * struct lmb - The LMB structure - * - * @free_mem: List of free memory regions - * @used_mem: List of used/reserved memory regions - * @test: Is structure being used for LMB tests + * @free_mem: List of free memory regions + * @used_mem: List of used/reserved memory regions + * @test: Is structure being used for LMB tests */ struct lmb { struct alist free_mem; @@ -58,51 +57,77 @@ struct lmb { };
/** - * lmb_init() - Initialise the LMB module + * lmb_init() - Initialise the LMB module. + * + * Return: 0 on success, negative error code on failure. * * Initialise the LMB lists needed for keeping the memory map. There - * are two lists, in form of alloced list data structure. One for the + * are two lists, in form of allocated list data structure. One for the * available memory, and one for the used memory. Initialise the two * lists as part of board init. Add memory to the available memory * list and reserve common areas by adding them to the used memory * list. - * - * Return: 0 on success, -ve on error */ int lmb_init(void);
/** - * lmb_add_memory() - Add memory range for LMB allocations + * lmb_add_memory() - Add memory range for LMB allocations. * * Add the entire available memory range to the pool of memory that * can be used by the LMB module for allocations. - * - * Return: None */ void lmb_add_memory(void);
long lmb_add(phys_addr_t base, phys_size_t size); -long lmb_reserve(phys_addr_t base, phys_size_t size); + /** - * lmb_reserve_flags - Reserve one region with a specific flags bitfield. + * lmb_reserve() - Reserve a memory region (with no special flags) + * @base: Base address of the memory region + * @size: Size of the memory region * - * @base: base address of the memory region - * @size: size of the memory region - * @flags: flags for the memory region - * Return: 0 if OK, > 0 for coalesced region or a negative error code. + * Return: 0 on success, negative error code on failure. + */ +long lmb_reserve(phys_addr_t base, phys_size_t size); + +/** + * lmb_reserve_flags() - Reserve one region with a specific flags bitfield + * @base: Base address of the memory region + * @size: Size of the memory region + * @flags: Flags for the memory region + * + * Return: + * * %0 - Added successfully, or it's already added (only if LMB_NONE) + * * %-EEXIST - The region is already added, and flags != LMB_NONE + * * %-1 - Failure */ long lmb_reserve_flags(phys_addr_t base, phys_size_t size, enum lmb_flags flags); + phys_addr_t lmb_alloc(phys_size_t size, ulong align); phys_addr_t lmb_alloc_base(phys_size_t size, ulong align, phys_addr_t max_addr); phys_addr_t lmb_alloc_addr(phys_addr_t base, phys_size_t size); phys_size_t lmb_get_free_size(phys_addr_t addr);
+/** + * lmb_alloc_base_flags() - Allocate specified memory region with specified + * attributes + * @size: Size of the region requested + * @align: Alignment of the memory region requested + * @max_addr: Maximum address of the requested region + * @flags: Memory region attributes to be set + * + * Allocate a region of memory with the attributes specified through the + * parameter. The max_addr parameter is used to specify the maximum address + * below which the requested region should be allocated. + * + * Return: Base address on success, 0 on error. + */ phys_addr_t lmb_alloc_base_flags(phys_size_t size, ulong align, phys_addr_t max_addr, uint flags);
/** - * lmb_alloc_addr_flags() - Allocate specified memory address with specified attributes + * lmb_alloc_addr_flags() - Allocate specified memory address with specified + * attributes * @base: Base Address requested * @size: Size of the region requested * @flags: Memory region attributes to be set @@ -111,20 +136,21 @@ phys_addr_t lmb_alloc_base_flags(phys_size_t size, ulong align, * parameter. The base parameter is used to specify the base address * of the requested region. * - * Return: base address on success, 0 on error + * Return: Base address on success, 0 on error. */ phys_addr_t lmb_alloc_addr_flags(phys_addr_t base, phys_size_t size, uint flags);
/** - * lmb_is_reserved_flags() - test if address is in reserved region with flag bits set + * lmb_is_reserved_flags() - Test if address is in reserved region with flag + * bits set + * @addr: Address to be tested + * @flags: Bitmap with bits to be tested * * The function checks if a reserved region comprising @addr exists which has * all flag bits set which are set in @flags. * - * @addr: address to be tested - * @flags: bitmap with bits to be tested - * Return: 1 if matching reservation exists, 0 otherwise + * Return: 1 if matching reservation exists, 0 otherwise. */ int lmb_is_reserved_flags(phys_addr_t addr, int flags);
@@ -134,9 +160,7 @@ int lmb_is_reserved_flags(phys_addr_t addr, int flags); * @size: Size of the region to be freed * @flags: Memory region attributes * - * Free up a region of memory. - * - * Return: 0 if successful, -1 on failure + * Return: 0 on success, negative error code on failure. */ long lmb_free_flags(phys_addr_t base, phys_size_t size, uint flags);
@@ -160,7 +184,7 @@ static inline int lmb_read_check(phys_addr_t addr, phys_size_t len) * io_lmb_setup() - Initialize LMB struct * @io_lmb: IO LMB to initialize * - * Returns: 0 on success, negative error code on failure + * Return: 0 on success, negative error code on failure. */ int io_lmb_setup(struct lmb *io_lmb);
@@ -178,12 +202,13 @@ void io_lmb_teardown(struct lmb *io_lmb); * * Add the IOVA space [base, base + size] to be managed by io_lmb. * - * Returns: 0 if the region addition was successful, -1 on failure + * Return: 0 on success, negative error code on failure. */ long io_lmb_add(struct lmb *io_lmb, phys_addr_t base, phys_size_t size);
/** - * io_lmb_alloc() - Allocate specified IO memory address with specified alignment + * io_lmb_alloc() - Allocate specified IO memory address with specified + * alignment * @io_lmb: LMB to alloc from * @size: Size of the region requested * @align: Required address and size alignment @@ -191,7 +216,7 @@ long io_lmb_add(struct lmb *io_lmb, phys_addr_t base, phys_size_t size); * Allocate a region of IO memory. The base parameter is used to specify the * base address of the requested region. * - * Return: base IO address on success, 0 on error + * Return: Base IO address on success, 0 on error. */ phys_addr_t io_lmb_alloc(struct lmb *io_lmb, phys_size_t size, ulong align);
@@ -201,9 +226,7 @@ phys_addr_t io_lmb_alloc(struct lmb *io_lmb, phys_size_t size, ulong align); * @base: Base Address of region to be freed * @size: Size of the region to be freed * - * Free up a region of IOVA space. - * - * Return: 0 if successful, -1 on failure + * Return: 0 on success, negative error code on failure. */ long io_lmb_free(struct lmb *io_lmb, phys_addr_t base, phys_size_t size);
diff --git a/lib/lmb.c b/lib/lmb.c index 8c1c9b0f67c8..eee3bd37d446 100644 --- a/lib/lmb.c +++ b/lib/lmb.c @@ -609,14 +609,6 @@ static __maybe_unused void lmb_reserve_common_spl(void) } }
-/** - * lmb_add_memory() - Add memory range for LMB allocations - * - * Add the entire available memory range to the pool of memory that - * can be used by the LMB module for allocations. - * - * Return: None - */ void lmb_add_memory(void) { int i; @@ -673,16 +665,6 @@ long lmb_add(phys_addr_t base, phys_size_t size) return lmb_map_update_notify(base, size, MAP_OP_ADD, LMB_NONE); }
-/** - * lmb_free_flags() - Free up a region of memory - * @base: Base Address of region to be freed - * @size: Size of the region to be freed - * @flags: Memory region attributes - * - * Free up a region of memory. - * - * Return: 0 if successful, negative error code on failure - */ long lmb_free_flags(phys_addr_t base, phys_size_t size, uint flags) { @@ -790,19 +772,6 @@ phys_addr_t lmb_alloc_base(phys_size_t size, ulong align, phys_addr_t max_addr) return alloc; }
-/** - * lmb_alloc_base_flags() - Allocate specified memory region with specified attributes - * @size: Size of the region requested - * @align: Alignment of the memory region requested - * @max_addr: Maximum address of the requested region - * @flags: Memory region attributes to be set - * - * Allocate a region of memory with the attributes specified through the - * parameter. The max_addr parameter is used to specify the maximum address - * below which the requested region should be allocated. - * - * Return: base address on success, 0 on error - */ phys_addr_t lmb_alloc_base_flags(phys_size_t size, ulong align, phys_addr_t max_addr, uint flags) { @@ -851,18 +820,6 @@ phys_addr_t lmb_alloc_addr(phys_addr_t base, phys_size_t size) return _lmb_alloc_addr(base, size, LMB_NONE); }
-/** - * lmb_alloc_addr_flags() - Allocate specified memory address with specified attributes - * @base: Base Address requested - * @size: Size of the region requested - * @flags: Memory region attributes to be set - * - * Allocate a region of memory with the attributes specified through the - * parameter. The base parameter is used to specify the base address - * of the requested region. - * - * Return: base address on success, 0 on error - */ phys_addr_t lmb_alloc_addr_flags(phys_addr_t base, phys_size_t size, uint flags) { @@ -935,18 +892,6 @@ static int lmb_setup(bool test) return 0; }
-/** - * lmb_init() - Initialise the LMB module - * - * Initialise the LMB lists needed for keeping the memory map. There - * are two lists, in form of alloced list data structure. One for the - * available memory, and one for the used memory. Initialise the two - * lists as part of board init. Add memory to the available memory - * list and reserve common areas by adding them to the used memory - * list. - * - * Return: 0 on success, -ve on error - */ int lmb_init(void) { int ret;

There was a discussion recently on whether this should be in the .h or .c
But I don't really mind as long as we have a common policy
On Sun, 8 Dec 2024 at 02:21, Sam Protsenko semen.protsenko@linaro.org wrote:
Fix warnings from kernel-doc script. Improve and unify overall style of kernel-doc comments in lmb source files. Move all kernel-doc comments for public functions into the header, as recommended in U-Boot documentation, which also takes care of existing duplication. While at it, do a bit of cosmetic cleanups as well.
No functional change.
Signed-off-by: Sam Protsenko semen.protsenko@linaro.org
include/lmb.h | 125 ++++++++++++++++++++++++++++++-------------------- lib/lmb.c | 55 ---------------------- 2 files changed, 74 insertions(+), 106 deletions(-)
diff --git a/include/lmb.h b/include/lmb.h index f221f0cce8f7..03d5fac6aa79 100644 --- a/include/lmb.h +++ b/include/lmb.h @@ -1,6 +1,13 @@ /* SPDX-License-Identifier: GPL-2.0+ */ +/*
- Logical memory blocks.
- Copyright (C) 2001 Peter Bergner, IBM Corp.
- */
#ifndef _LINUX_LMB_H #define _LINUX_LMB_H
#ifdef __KERNEL__
#include <alist.h> @@ -8,21 +15,15 @@ #include <asm/u-boot.h> #include <linux/bitops.h>
-/*
- Logical memory blocks.
- Copyright (C) 2001 Peter Bergner, IBM Corp.
- */
-#define LMB_ALLOC_ANYWHERE 0 -#define LMB_ALIST_INITIAL_SIZE 4 +#define LMB_ALLOC_ANYWHERE 0 +#define LMB_ALIST_INITIAL_SIZE 4
/**
- enum lmb_flags - definition of memory region attributes
- @LMB_NONE: no special request
- @LMB_NOMAP: don't add to mmu configuration
- @LMB_NOOVERWRITE: the memory region cannot be overwritten/re-reserved
- @LMB_NONOTIFY: do not notify other modules of changes to this memory region
- enum lmb_flags - Definition of memory region attributes
- @LMB_NONE: No special request
- @LMB_NOMAP: Don't add to MMU configuration
- @LMB_NOOVERWRITE: The memory region cannot be overwritten/re-reserved
*/
- @LMB_NONOTIFY: Do not notify other modules of changes to this memory region
enum lmb_flags { LMB_NONE = 0, @@ -32,11 +33,10 @@ enum lmb_flags { };
/**
- struct lmb_region - Description of one region.
- @base: Base address of the region.
- @size: Size of the region
- @flags: memory region attributes
- struct lmb_region - Description of one region
- @base: Base address of the region
- @size: Size of the region
*/
- @flags: Memory region attributes
struct lmb_region { phys_addr_t base; @@ -46,10 +46,9 @@ struct lmb_region {
/**
- struct lmb - The LMB structure
- @free_mem: List of free memory regions
- @used_mem: List of used/reserved memory regions
- @test: Is structure being used for LMB tests
- @free_mem: List of free memory regions
- @used_mem: List of used/reserved memory regions
*/
- @test: Is structure being used for LMB tests
struct lmb { struct alist free_mem; @@ -58,51 +57,77 @@ struct lmb { };
/**
- lmb_init() - Initialise the LMB module
- lmb_init() - Initialise the LMB module.
- Return: 0 on success, negative error code on failure.
- Initialise the LMB lists needed for keeping the memory map. There
- are two lists, in form of alloced list data structure. One for the
- are two lists, in form of allocated list data structure. One for the
- available memory, and one for the used memory. Initialise the two
- lists as part of board init. Add memory to the available memory
- list and reserve common areas by adding them to the used memory
- list.
*/
- Return: 0 on success, -ve on error
int lmb_init(void);
/**
- lmb_add_memory() - Add memory range for LMB allocations
- lmb_add_memory() - Add memory range for LMB allocations.
- Add the entire available memory range to the pool of memory that
- can be used by the LMB module for allocations.
*/
- Return: None
void lmb_add_memory(void);
long lmb_add(phys_addr_t base, phys_size_t size); -long lmb_reserve(phys_addr_t base, phys_size_t size);
/**
- lmb_reserve_flags - Reserve one region with a specific flags bitfield.
- lmb_reserve() - Reserve a memory region (with no special flags)
- @base: Base address of the memory region
- @size: Size of the memory region
- @base: base address of the memory region
- @size: size of the memory region
- @flags: flags for the memory region
- Return: 0 if OK, > 0 for coalesced region or a negative error code.
- Return: 0 on success, negative error code on failure.
- */
+long lmb_reserve(phys_addr_t base, phys_size_t size);
+/**
- lmb_reserve_flags() - Reserve one region with a specific flags bitfield
- @base: Base address of the memory region
- @size: Size of the memory region
- @flags: Flags for the memory region
- Return:
- %0 - Added successfully, or it's already added (only if LMB_NONE)
- %-EEXIST - The region is already added, and flags != LMB_NONE
*/
- %-1 - Failure
long lmb_reserve_flags(phys_addr_t base, phys_size_t size, enum lmb_flags flags);
phys_addr_t lmb_alloc(phys_size_t size, ulong align); phys_addr_t lmb_alloc_base(phys_size_t size, ulong align, phys_addr_t max_addr); phys_addr_t lmb_alloc_addr(phys_addr_t base, phys_size_t size); phys_size_t lmb_get_free_size(phys_addr_t addr);
+/**
- lmb_alloc_base_flags() - Allocate specified memory region with specified
attributes
- @size: Size of the region requested
- @align: Alignment of the memory region requested
- @max_addr: Maximum address of the requested region
- @flags: Memory region attributes to be set
- Allocate a region of memory with the attributes specified through the
- parameter. The max_addr parameter is used to specify the maximum address
- below which the requested region should be allocated.
- Return: Base address on success, 0 on error.
- */
phys_addr_t lmb_alloc_base_flags(phys_size_t size, ulong align, phys_addr_t max_addr, uint flags);
/**
- lmb_alloc_addr_flags() - Allocate specified memory address with specified attributes
- lmb_alloc_addr_flags() - Allocate specified memory address with specified
attributes
- @base: Base Address requested
- @size: Size of the region requested
- @flags: Memory region attributes to be set
@@ -111,20 +136,21 @@ phys_addr_t lmb_alloc_base_flags(phys_size_t size, ulong align,
- parameter. The base parameter is used to specify the base address
- of the requested region.
- Return: base address on success, 0 on error
*/
- Return: Base address on success, 0 on error.
phys_addr_t lmb_alloc_addr_flags(phys_addr_t base, phys_size_t size, uint flags);
/**
- lmb_is_reserved_flags() - test if address is in reserved region with flag bits set
- lmb_is_reserved_flags() - Test if address is in reserved region with flag
bits set
- @addr: Address to be tested
- @flags: Bitmap with bits to be tested
- The function checks if a reserved region comprising @addr exists which has
- all flag bits set which are set in @flags.
- @addr: address to be tested
- @flags: bitmap with bits to be tested
- Return: 1 if matching reservation exists, 0 otherwise
*/
- Return: 1 if matching reservation exists, 0 otherwise.
int lmb_is_reserved_flags(phys_addr_t addr, int flags);
@@ -134,9 +160,7 @@ int lmb_is_reserved_flags(phys_addr_t addr, int flags);
- @size: Size of the region to be freed
- @flags: Memory region attributes
- Free up a region of memory.
- Return: 0 if successful, -1 on failure
*/
- Return: 0 on success, negative error code on failure.
long lmb_free_flags(phys_addr_t base, phys_size_t size, uint flags);
@@ -160,7 +184,7 @@ static inline int lmb_read_check(phys_addr_t addr, phys_size_t len)
- io_lmb_setup() - Initialize LMB struct
- @io_lmb: IO LMB to initialize
- Returns: 0 on success, negative error code on failure
*/
- Return: 0 on success, negative error code on failure.
int io_lmb_setup(struct lmb *io_lmb);
@@ -178,12 +202,13 @@ void io_lmb_teardown(struct lmb *io_lmb);
- Add the IOVA space [base, base + size] to be managed by io_lmb.
- Returns: 0 if the region addition was successful, -1 on failure
*/
- Return: 0 on success, negative error code on failure.
long io_lmb_add(struct lmb *io_lmb, phys_addr_t base, phys_size_t size);
/**
- io_lmb_alloc() - Allocate specified IO memory address with specified alignment
- io_lmb_alloc() - Allocate specified IO memory address with specified
alignment
- @io_lmb: LMB to alloc from
- @size: Size of the region requested
- @align: Required address and size alignment
@@ -191,7 +216,7 @@ long io_lmb_add(struct lmb *io_lmb, phys_addr_t base, phys_size_t size);
- Allocate a region of IO memory. The base parameter is used to specify the
- base address of the requested region.
- Return: base IO address on success, 0 on error
*/
- Return: Base IO address on success, 0 on error.
phys_addr_t io_lmb_alloc(struct lmb *io_lmb, phys_size_t size, ulong align);
@@ -201,9 +226,7 @@ phys_addr_t io_lmb_alloc(struct lmb *io_lmb, phys_size_t size, ulong align);
- @base: Base Address of region to be freed
- @size: Size of the region to be freed
- Free up a region of IOVA space.
- Return: 0 if successful, -1 on failure
*/
- Return: 0 on success, negative error code on failure.
long io_lmb_free(struct lmb *io_lmb, phys_addr_t base, phys_size_t size);
diff --git a/lib/lmb.c b/lib/lmb.c index 8c1c9b0f67c8..eee3bd37d446 100644 --- a/lib/lmb.c +++ b/lib/lmb.c @@ -609,14 +609,6 @@ static __maybe_unused void lmb_reserve_common_spl(void) } }
-/**
- lmb_add_memory() - Add memory range for LMB allocations
- Add the entire available memory range to the pool of memory that
- can be used by the LMB module for allocations.
- Return: None
- */
void lmb_add_memory(void) { int i; @@ -673,16 +665,6 @@ long lmb_add(phys_addr_t base, phys_size_t size) return lmb_map_update_notify(base, size, MAP_OP_ADD, LMB_NONE); }
-/**
- lmb_free_flags() - Free up a region of memory
- @base: Base Address of region to be freed
- @size: Size of the region to be freed
- @flags: Memory region attributes
- Free up a region of memory.
- Return: 0 if successful, negative error code on failure
- */
long lmb_free_flags(phys_addr_t base, phys_size_t size, uint flags) { @@ -790,19 +772,6 @@ phys_addr_t lmb_alloc_base(phys_size_t size, ulong align, phys_addr_t max_addr) return alloc; }
-/**
- lmb_alloc_base_flags() - Allocate specified memory region with specified attributes
- @size: Size of the region requested
- @align: Alignment of the memory region requested
- @max_addr: Maximum address of the requested region
- @flags: Memory region attributes to be set
- Allocate a region of memory with the attributes specified through the
- parameter. The max_addr parameter is used to specify the maximum address
- below which the requested region should be allocated.
- Return: base address on success, 0 on error
- */
phys_addr_t lmb_alloc_base_flags(phys_size_t size, ulong align, phys_addr_t max_addr, uint flags) { @@ -851,18 +820,6 @@ phys_addr_t lmb_alloc_addr(phys_addr_t base, phys_size_t size) return _lmb_alloc_addr(base, size, LMB_NONE); }
-/**
- lmb_alloc_addr_flags() - Allocate specified memory address with specified attributes
- @base: Base Address requested
- @size: Size of the region requested
- @flags: Memory region attributes to be set
- Allocate a region of memory with the attributes specified through the
- parameter. The base parameter is used to specify the base address
- of the requested region.
- Return: base address on success, 0 on error
- */
phys_addr_t lmb_alloc_addr_flags(phys_addr_t base, phys_size_t size, uint flags) { @@ -935,18 +892,6 @@ static int lmb_setup(bool test) return 0; }
-/**
- lmb_init() - Initialise the LMB module
- Initialise the LMB lists needed for keeping the memory map. There
- are two lists, in form of alloced list data structure. One for the
- available memory, and one for the used memory. Initialise the two
- lists as part of board init. Add memory to the available memory
- list and reserve common areas by adding them to the used memory
- list.
- Return: 0 on success, -ve on error
- */
int lmb_init(void) { int ret; -- 2.39.5
Acked-by: Ilias Apalodimas ilias.apalodimas@linaro.org

On Sun, Dec 8, 2024 at 12:57 AM Ilias Apalodimas ilias.apalodimas@linaro.org wrote:
There was a discussion recently on whether this should be in the .h or .c
Thanks for reviewing this series! As for the comments -- I just followed the U-Boot guidelines from doc/develop/codingstyle.rst:
Non-trivial functions should have a comment which describes what they do. If it is an exported function, put the comment in the header file so the API is in one place. If it is a static function, put it in the C file.
Personally I don't have a strong opinion on this one. I noticed the kernel sticks to documenting public APIs in .c files, but U-Boot does that in headers instead. In my private projects, I usually provide doxy comments in the header for libraries which might be shipped as a binary plus the header file, but OTOH for firmwares and other self-sustained stuff I stick to kernel style. But in any case, I believe if we want change things the other way around, we should change the documentation first, and then rework all U-Boot source code to conform to that. That's out of scope of this patch, of course. But I'll extend the commit message to reflect this discussion and make it more clear.
But I don't really mind as long as we have a common policy
Agreed, that's the most important thing. It's easy to move things around when everything is clean and tidy in the first place.
On Sun, 8 Dec 2024 at 02:21, Sam Protsenko semen.protsenko@linaro.org wrote:
Fix warnings from kernel-doc script. Improve and unify overall style of kernel-doc comments in lmb source files. Move all kernel-doc comments for public functions into the header, as recommended in U-Boot documentation, which also takes care of existing duplication. While at it, do a bit of cosmetic cleanups as well.
No functional change.
Signed-off-by: Sam Protsenko semen.protsenko@linaro.org
include/lmb.h | 125 ++++++++++++++++++++++++++++++-------------------- lib/lmb.c | 55 ---------------------- 2 files changed, 74 insertions(+), 106 deletions(-)
diff --git a/include/lmb.h b/include/lmb.h index f221f0cce8f7..03d5fac6aa79 100644 --- a/include/lmb.h +++ b/include/lmb.h @@ -1,6 +1,13 @@ /* SPDX-License-Identifier: GPL-2.0+ */ +/*
- Logical memory blocks.
- Copyright (C) 2001 Peter Bergner, IBM Corp.
- */
#ifndef _LINUX_LMB_H #define _LINUX_LMB_H
#ifdef __KERNEL__
#include <alist.h> @@ -8,21 +15,15 @@ #include <asm/u-boot.h> #include <linux/bitops.h>
-/*
- Logical memory blocks.
- Copyright (C) 2001 Peter Bergner, IBM Corp.
- */
-#define LMB_ALLOC_ANYWHERE 0 -#define LMB_ALIST_INITIAL_SIZE 4 +#define LMB_ALLOC_ANYWHERE 0 +#define LMB_ALIST_INITIAL_SIZE 4
/**
- enum lmb_flags - definition of memory region attributes
- @LMB_NONE: no special request
- @LMB_NOMAP: don't add to mmu configuration
- @LMB_NOOVERWRITE: the memory region cannot be overwritten/re-reserved
- @LMB_NONOTIFY: do not notify other modules of changes to this memory region
- enum lmb_flags - Definition of memory region attributes
- @LMB_NONE: No special request
- @LMB_NOMAP: Don't add to MMU configuration
- @LMB_NOOVERWRITE: The memory region cannot be overwritten/re-reserved
*/
- @LMB_NONOTIFY: Do not notify other modules of changes to this memory region
enum lmb_flags { LMB_NONE = 0, @@ -32,11 +33,10 @@ enum lmb_flags { };
/**
- struct lmb_region - Description of one region.
- @base: Base address of the region.
- @size: Size of the region
- @flags: memory region attributes
- struct lmb_region - Description of one region
- @base: Base address of the region
- @size: Size of the region
*/
- @flags: Memory region attributes
struct lmb_region { phys_addr_t base; @@ -46,10 +46,9 @@ struct lmb_region {
/**
- struct lmb - The LMB structure
- @free_mem: List of free memory regions
- @used_mem: List of used/reserved memory regions
- @test: Is structure being used for LMB tests
- @free_mem: List of free memory regions
- @used_mem: List of used/reserved memory regions
*/
- @test: Is structure being used for LMB tests
struct lmb { struct alist free_mem; @@ -58,51 +57,77 @@ struct lmb { };
/**
- lmb_init() - Initialise the LMB module
- lmb_init() - Initialise the LMB module.
- Return: 0 on success, negative error code on failure.
- Initialise the LMB lists needed for keeping the memory map. There
- are two lists, in form of alloced list data structure. One for the
- are two lists, in form of allocated list data structure. One for the
- available memory, and one for the used memory. Initialise the two
- lists as part of board init. Add memory to the available memory
- list and reserve common areas by adding them to the used memory
- list.
*/
- Return: 0 on success, -ve on error
int lmb_init(void);
/**
- lmb_add_memory() - Add memory range for LMB allocations
- lmb_add_memory() - Add memory range for LMB allocations.
- Add the entire available memory range to the pool of memory that
- can be used by the LMB module for allocations.
*/
- Return: None
void lmb_add_memory(void);
long lmb_add(phys_addr_t base, phys_size_t size); -long lmb_reserve(phys_addr_t base, phys_size_t size);
/**
- lmb_reserve_flags - Reserve one region with a specific flags bitfield.
- lmb_reserve() - Reserve a memory region (with no special flags)
- @base: Base address of the memory region
- @size: Size of the memory region
- @base: base address of the memory region
- @size: size of the memory region
- @flags: flags for the memory region
- Return: 0 if OK, > 0 for coalesced region or a negative error code.
- Return: 0 on success, negative error code on failure.
- */
+long lmb_reserve(phys_addr_t base, phys_size_t size);
+/**
- lmb_reserve_flags() - Reserve one region with a specific flags bitfield
- @base: Base address of the memory region
- @size: Size of the memory region
- @flags: Flags for the memory region
- Return:
- %0 - Added successfully, or it's already added (only if LMB_NONE)
- %-EEXIST - The region is already added, and flags != LMB_NONE
*/
- %-1 - Failure
long lmb_reserve_flags(phys_addr_t base, phys_size_t size, enum lmb_flags flags);
phys_addr_t lmb_alloc(phys_size_t size, ulong align); phys_addr_t lmb_alloc_base(phys_size_t size, ulong align, phys_addr_t max_addr); phys_addr_t lmb_alloc_addr(phys_addr_t base, phys_size_t size); phys_size_t lmb_get_free_size(phys_addr_t addr);
+/**
- lmb_alloc_base_flags() - Allocate specified memory region with specified
attributes
- @size: Size of the region requested
- @align: Alignment of the memory region requested
- @max_addr: Maximum address of the requested region
- @flags: Memory region attributes to be set
- Allocate a region of memory with the attributes specified through the
- parameter. The max_addr parameter is used to specify the maximum address
- below which the requested region should be allocated.
- Return: Base address on success, 0 on error.
- */
phys_addr_t lmb_alloc_base_flags(phys_size_t size, ulong align, phys_addr_t max_addr, uint flags);
/**
- lmb_alloc_addr_flags() - Allocate specified memory address with specified attributes
- lmb_alloc_addr_flags() - Allocate specified memory address with specified
attributes
- @base: Base Address requested
- @size: Size of the region requested
- @flags: Memory region attributes to be set
@@ -111,20 +136,21 @@ phys_addr_t lmb_alloc_base_flags(phys_size_t size, ulong align,
- parameter. The base parameter is used to specify the base address
- of the requested region.
- Return: base address on success, 0 on error
*/
- Return: Base address on success, 0 on error.
phys_addr_t lmb_alloc_addr_flags(phys_addr_t base, phys_size_t size, uint flags);
/**
- lmb_is_reserved_flags() - test if address is in reserved region with flag bits set
- lmb_is_reserved_flags() - Test if address is in reserved region with flag
bits set
- @addr: Address to be tested
- @flags: Bitmap with bits to be tested
- The function checks if a reserved region comprising @addr exists which has
- all flag bits set which are set in @flags.
- @addr: address to be tested
- @flags: bitmap with bits to be tested
- Return: 1 if matching reservation exists, 0 otherwise
*/
- Return: 1 if matching reservation exists, 0 otherwise.
int lmb_is_reserved_flags(phys_addr_t addr, int flags);
@@ -134,9 +160,7 @@ int lmb_is_reserved_flags(phys_addr_t addr, int flags);
- @size: Size of the region to be freed
- @flags: Memory region attributes
- Free up a region of memory.
- Return: 0 if successful, -1 on failure
*/
- Return: 0 on success, negative error code on failure.
long lmb_free_flags(phys_addr_t base, phys_size_t size, uint flags);
@@ -160,7 +184,7 @@ static inline int lmb_read_check(phys_addr_t addr, phys_size_t len)
- io_lmb_setup() - Initialize LMB struct
- @io_lmb: IO LMB to initialize
- Returns: 0 on success, negative error code on failure
*/
- Return: 0 on success, negative error code on failure.
int io_lmb_setup(struct lmb *io_lmb);
@@ -178,12 +202,13 @@ void io_lmb_teardown(struct lmb *io_lmb);
- Add the IOVA space [base, base + size] to be managed by io_lmb.
- Returns: 0 if the region addition was successful, -1 on failure
*/
- Return: 0 on success, negative error code on failure.
long io_lmb_add(struct lmb *io_lmb, phys_addr_t base, phys_size_t size);
/**
- io_lmb_alloc() - Allocate specified IO memory address with specified alignment
- io_lmb_alloc() - Allocate specified IO memory address with specified
alignment
- @io_lmb: LMB to alloc from
- @size: Size of the region requested
- @align: Required address and size alignment
@@ -191,7 +216,7 @@ long io_lmb_add(struct lmb *io_lmb, phys_addr_t base, phys_size_t size);
- Allocate a region of IO memory. The base parameter is used to specify the
- base address of the requested region.
- Return: base IO address on success, 0 on error
*/
- Return: Base IO address on success, 0 on error.
phys_addr_t io_lmb_alloc(struct lmb *io_lmb, phys_size_t size, ulong align);
@@ -201,9 +226,7 @@ phys_addr_t io_lmb_alloc(struct lmb *io_lmb, phys_size_t size, ulong align);
- @base: Base Address of region to be freed
- @size: Size of the region to be freed
- Free up a region of IOVA space.
- Return: 0 if successful, -1 on failure
*/
- Return: 0 on success, negative error code on failure.
long io_lmb_free(struct lmb *io_lmb, phys_addr_t base, phys_size_t size);
diff --git a/lib/lmb.c b/lib/lmb.c index 8c1c9b0f67c8..eee3bd37d446 100644 --- a/lib/lmb.c +++ b/lib/lmb.c @@ -609,14 +609,6 @@ static __maybe_unused void lmb_reserve_common_spl(void) } }
-/**
- lmb_add_memory() - Add memory range for LMB allocations
- Add the entire available memory range to the pool of memory that
- can be used by the LMB module for allocations.
- Return: None
- */
void lmb_add_memory(void) { int i; @@ -673,16 +665,6 @@ long lmb_add(phys_addr_t base, phys_size_t size) return lmb_map_update_notify(base, size, MAP_OP_ADD, LMB_NONE); }
-/**
- lmb_free_flags() - Free up a region of memory
- @base: Base Address of region to be freed
- @size: Size of the region to be freed
- @flags: Memory region attributes
- Free up a region of memory.
- Return: 0 if successful, negative error code on failure
- */
long lmb_free_flags(phys_addr_t base, phys_size_t size, uint flags) { @@ -790,19 +772,6 @@ phys_addr_t lmb_alloc_base(phys_size_t size, ulong align, phys_addr_t max_addr) return alloc; }
-/**
- lmb_alloc_base_flags() - Allocate specified memory region with specified attributes
- @size: Size of the region requested
- @align: Alignment of the memory region requested
- @max_addr: Maximum address of the requested region
- @flags: Memory region attributes to be set
- Allocate a region of memory with the attributes specified through the
- parameter. The max_addr parameter is used to specify the maximum address
- below which the requested region should be allocated.
- Return: base address on success, 0 on error
- */
phys_addr_t lmb_alloc_base_flags(phys_size_t size, ulong align, phys_addr_t max_addr, uint flags) { @@ -851,18 +820,6 @@ phys_addr_t lmb_alloc_addr(phys_addr_t base, phys_size_t size) return _lmb_alloc_addr(base, size, LMB_NONE); }
-/**
- lmb_alloc_addr_flags() - Allocate specified memory address with specified attributes
- @base: Base Address requested
- @size: Size of the region requested
- @flags: Memory region attributes to be set
- Allocate a region of memory with the attributes specified through the
- parameter. The base parameter is used to specify the base address
- of the requested region.
- Return: base address on success, 0 on error
- */
phys_addr_t lmb_alloc_addr_flags(phys_addr_t base, phys_size_t size, uint flags) { @@ -935,18 +892,6 @@ static int lmb_setup(bool test) return 0; }
-/**
- lmb_init() - Initialise the LMB module
- Initialise the LMB lists needed for keeping the memory map. There
- are two lists, in form of alloced list data structure. One for the
- available memory, and one for the used memory. Initialise the two
- lists as part of board init. Add memory to the available memory
- list and reserve common areas by adding them to the used memory
- list.
- Return: 0 on success, -ve on error
- */
int lmb_init(void) { int ret; -- 2.39.5
Acked-by: Ilias Apalodimas ilias.apalodimas@linaro.org

The boot_fdt_add_mem_rsv_regions() function can be called twice, e.g. first time during the board init (as a part of LMB init), and then when booting the OS with 'booti' command:
lmb_add_region_flags lmb_reserve_flags boot_fdt_reserve_region boot_fdt_add_mem_rsv_regions ^ | +-----------------------+ | (1) | (2) lmb_reserve_common image_setup_linux lmb_init ... initr_lmb do_booti board_init_r 'booti'
That consequently leads to the attempt of reserving the same memory areas (described in the 'reserved-memory' dts node) in LMB. The lmb_add_region_flags() returns -EEXIST error code in such cases, but boot_fdt_reserve_region() handles all negative error codes as a failure to reserve fdt memory region, printing corresponding error messages, which are essentially harmless, but misleading. For example, this is the output of 'booti' command on E850-96 board:
=> booti $loadaddr - $fdtaddr ... ERROR: reserving fdt memory region failed (addr=bab00000 size=5500000 flags=2) ERROR: reserving fdt memory region failed (addr=f0000000 size=200000 flags=4) ... Starting kernel ...
The mentioned false positive error messages are observed starting with commit 1d9aa4a283da ("lmb: Fix the allocation of overlapping memory areas with !LMB_NONE"), which removes the check for the already added memory regions in lmb_add_region_flags(), making it return -1 for !LMB_NONE cases. Another commit 827dee587b75 ("fdt: lmb: add reserved regions as no-overwrite") changes flags used for reserving memory in boot_fdt_add_mem_rsv_regions() from LMB_NONE to LMB_NOOVERWRITE. So together with the patch mentioned earlier, it makes lmb_add_region_flags() return -1 when called from boot_fdt_reserve_region().
Since then, the different patch was implemented, adding the check back and returning -EEXIST error code in described cases, which is:
lmb: Return -EEXIST in lmb_add_region_flags() if region already added
Handle -EEXIST error code as a normal (successful) case in lmb_reserve_flags() and don't print any messages.
Fixes: 1d9aa4a283da ("lmb: Fix the allocation of overlapping memory areas with !LMB_NONE") Signed-off-by: Sam Protsenko semen.protsenko@linaro.org --- boot/image-fdt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/boot/image-fdt.c b/boot/image-fdt.c index 3d5b6f9e2dc7..73c43c30684f 100644 --- a/boot/image-fdt.c +++ b/boot/image-fdt.c @@ -77,7 +77,7 @@ static void boot_fdt_reserve_region(u64 addr, u64 size, enum lmb_flags flags) debug(" reserving fdt memory region: addr=%llx size=%llx flags=%x\n", (unsigned long long)addr, (unsigned long long)size, flags); - } else { + } else if (ret != -EEXIST) { puts("ERROR: reserving fdt memory region failed "); printf("(addr=%llx size=%llx flags=%x)\n", (unsigned long long)addr,

On Sun, 8 Dec 2024 at 02:21, Sam Protsenko semen.protsenko@linaro.org wrote:
The boot_fdt_add_mem_rsv_regions() function can be called twice, e.g. first time during the board init (as a part of LMB init), and then when booting the OS with 'booti' command:
lmb_add_region_flags lmb_reserve_flags boot_fdt_reserve_region boot_fdt_add_mem_rsv_regions ^ | +-----------------------+ | (1) | (2) lmb_reserve_common image_setup_linux lmb_init ... initr_lmb do_booti board_init_r 'booti'
That consequently leads to the attempt of reserving the same memory areas (described in the 'reserved-memory' dts node) in LMB. The lmb_add_region_flags() returns -EEXIST error code in such cases, but boot_fdt_reserve_region() handles all negative error codes as a failure to reserve fdt memory region, printing corresponding error messages, which are essentially harmless, but misleading. For example, this is the output of 'booti' command on E850-96 board:
=> booti $loadaddr - $fdtaddr ... ERROR: reserving fdt memory region failed (addr=bab00000 size=5500000 flags=2) ERROR: reserving fdt memory region failed (addr=f0000000 size=200000 flags=4) ... Starting kernel ...
The mentioned false positive error messages are observed starting with commit 1d9aa4a283da ("lmb: Fix the allocation of overlapping memory areas with !LMB_NONE"), which removes the check for the already added memory regions in lmb_add_region_flags(), making it return -1 for !LMB_NONE cases. Another commit 827dee587b75 ("fdt: lmb: add reserved regions as no-overwrite") changes flags used for reserving memory in boot_fdt_add_mem_rsv_regions() from LMB_NONE to LMB_NOOVERWRITE. So together with the patch mentioned earlier, it makes lmb_add_region_flags() return -1 when called from boot_fdt_reserve_region().
Since then, the different patch was implemented, adding the check back and returning -EEXIST error code in described cases, which is:
lmb: Return -EEXIST in lmb_add_region_flags() if region already added
Handle -EEXIST error code as a normal (successful) case in lmb_reserve_flags() and don't print any messages.
Fixes: 1d9aa4a283da ("lmb: Fix the allocation of overlapping memory areas with !LMB_NONE") Signed-off-by: Sam Protsenko semen.protsenko@linaro.org
boot/image-fdt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/boot/image-fdt.c b/boot/image-fdt.c index 3d5b6f9e2dc7..73c43c30684f 100644 --- a/boot/image-fdt.c +++ b/boot/image-fdt.c @@ -77,7 +77,7 @@ static void boot_fdt_reserve_region(u64 addr, u64 size, enum lmb_flags flags) debug(" reserving fdt memory region: addr=%llx size=%llx flags=%x\n", (unsigned long long)addr, (unsigned long long)size, flags);
} else {
} else if (ret != -EEXIST) { puts("ERROR: reserving fdt memory region failed "); printf("(addr=%llx size=%llx flags=%x)\n", (unsigned long long)addr,
-- 2.39.5
Reviewed-by: Ilias Apalodimas ilias.apalodimas@linaro.org

Hi Sam,
On Sun, 8 Dec 2024 at 02:21, Sam Protsenko semen.protsenko@linaro.org wrote:
Since commit 1d9aa4a283da ("lmb: Fix the allocation of overlapping memory areas with !LMB_NONE") the lmb_add_region_flags() returns -1 when the caller tries to add the already existing region with !LMB_NONE flags (it was returning 0 before that patch). That causes boot_fdt_reserve_region() function to print erroneous error messages when it's called consequently more than one time.
Make lmb_add_region_flags() return -EEXIST when the already added region with !LMB_NONE flags is being added, and then check that error code in boot_fdt_reserve_region() to avoid printing the misleading error messages.
Thanks for cathing this. It's a print only error, but still misleading
I didn't want to change lmb_add_region_flags() behavior back to always returning 0 on attempts to add already existing regions with !LMB_NONE flags, as the unit tests in test/lib/lmb.c would break, and also commit 1d9aa4a283da ("lmb: Fix the allocation of overlapping memory areas with !LMB_NONE") specifically states that behavior is expected and required for efi_allocate_pages() calls with type=EFI_ALLOCATE_ADDRESS.
TBH it's not only the EFI code that needs this. I don't think returning 0 for a region that's already allocated and the flags that happen to match is a good idea to begin with. The code should be as precise as possible.
Thanks /Ilias
All unit tests pass in sandbox U-Boot, with a small test modification in [PATCH 2/6]. I also made a bit of LMB cleanups in this series, while at it. Only [PATCH 6/6] introduces an actual functional change.
Sam Protsenko (6): lmb: Fix flags data type in lmb_add_region_flags() lmb: Return -EEXIST in lmb_add_region_flags() if region already added lmb: Make const flag_str[] in lmb_print_region_flags() more const lmb: Improve coding style lmb: Improve kernel-doc comments boot: fdt: Handle already reserved memory in boot_fdt_reserve_region()
boot/image-fdt.c | 2 +- include/lmb.h | 125 ++++++++++++++++++++++++++++------------------- lib/lmb.c | 105 +++++++++++++-------------------------- test/lib/lmb.c | 2 +- 4 files changed, 109 insertions(+), 125 deletions(-)
-- 2.39.5
participants (3)
-
Ilias Apalodimas
-
Sam Protsenko
-
Sughosh Ganu