[RFC PATCH 09/31] lmb: allow for resizing lmb regions

Sughosh Ganu sughosh.ganu at linaro.org
Tue Jun 11 11:50:09 CEST 2024


On Tue, 11 Jun 2024 at 14:47, Heinrich Schuchardt <xypron.glpk at gmx.de> wrote:
>
> On 07.06.24 20:52, Sughosh Ganu wrote:
> > Allow for resizing of LMB regions if the region attributes match. The
> > current code returns a failure status on detecting an overlapping
> > address. This worked up until now since the LMB calls were not
> > persistent and global -- the LMB memory map was specific and private
> > to a given caller of the LMB API's.
> >
> > With the change in the LMB code to make the LMB reservations
> > persistent, there needs to be a check on whether the memory region can
> > be resized, and then do it if so. To distinguish between memory that
> > cannot be resized, add a new flag, LMB_NOOVERWRITE. Reserving a region
> > of memory with this attribute would indicate that the region cannot be
> > resized.
> >
> > Signed-off-by: Sughosh Ganu <sughosh.ganu at linaro.org>
> > ---
> >   include/lmb.h |   1 +
> >   lib/lmb.c     | 120 ++++++++++++++++++++++++++++++++++++++++++++------
> >   2 files changed, 107 insertions(+), 14 deletions(-)
> >
> > diff --git a/include/lmb.h b/include/lmb.h
> > index 03bce2a50c..1d4cd255d2 100644
> > --- a/include/lmb.h
> > +++ b/include/lmb.h
> > @@ -20,6 +20,7 @@
> >   enum lmb_flags {
> >       LMB_NONE                = 0x0,
> >       LMB_NOMAP               = 0x4,
> > +     LMB_NOOVERWRITE         = 0x8,
>
> Please, add the missing description for the new value. Using the first
> available bit (0x01) would be expected.
>
> Using the BIT macro would make it clearer that these are bits of a bitmap:
>
> enum lmb_flags {
>         LMB_NONE                = BIT(0),
>         LMB_NOOVERWRITE         = BIT(1),
> };

Noted. Will change.

-sughosh

>
> Best regards
>
> Heinrich
>
>
> >   };
> >
> >   /**
> > diff --git a/lib/lmb.c b/lib/lmb.c
> > index de5a2cf23b..0a4f3d5bcd 100644
> > --- a/lib/lmb.c
> > +++ b/lib/lmb.c
> > @@ -260,12 +260,88 @@ void lmb_add_memory(struct bd_info *bd)
> >       }
> >   }
> >
> > +static bool lmb_region_flags_match(struct lmb_region *rgn, unsigned long r1,
> > +                                enum lmb_flags flags)
> > +{
> > +     return rgn->region[r1].flags == flags;
> > +}
> > +
> > +static long lmb_merge_overlap_regions(struct lmb_region *rgn, unsigned long i,
> > +                                   phys_addr_t base, phys_size_t size,
> > +                                   enum lmb_flags flags)
> > +{
> > +     phys_size_t rgnsize;
> > +     unsigned long rgn_cnt, idx;
> > +     phys_addr_t rgnbase, rgnend;
> > +     phys_addr_t mergebase, mergeend;
> > +
> > +     rgn_cnt = 0;
> > +     idx = i;
> > +     /*
> > +      * First thing to do is to identify how many regions does
> > +      * the requested region overlap.
> > +      * If the flags match, combine all these overlapping
> > +      * regions into a single region, and remove the merged
> > +      * regions.
> > +      */
> > +     while (idx < rgn->cnt - 1) {
> > +             rgnbase = rgn->region[idx].base;
> > +             rgnsize = rgn->region[idx].size;
> > +
> > +             if (lmb_addrs_overlap(base, size, rgnbase,
> > +                                   rgnsize)) {
> > +                     if (!lmb_region_flags_match(rgn, idx, flags))
> > +                             return -1;
> > +                     rgn_cnt++;
> > +                     idx++;
> > +             }
> > +     }
> > +
> > +     /* The merged region's base and size */
> > +     rgnbase = rgn->region[i].base;
> > +     mergebase = min(base, rgnbase);
> > +     rgnend = rgn->region[idx].base + rgn->region[idx].size;
> > +     mergeend = max(rgnend, (base + size));
> > +
> > +     rgn->region[i].base = mergebase;
> > +     rgn->region[i].size = mergeend - mergebase;
> > +
> > +     /* Now remove the merged regions */
> > +     while (--rgn_cnt)
> > +             lmb_remove_region(rgn, i + 1);
> > +
> > +     return 0;
> > +}
> > +
> > +static long lmb_resize_regions(struct lmb_region *rgn, unsigned long i,
> > +                            phys_addr_t base, phys_size_t size,
> > +                            enum lmb_flags flags)
> > +{
> > +     long ret = 0;
> > +     phys_addr_t rgnend;
> > +
> > +     if (i == rgn->cnt - 1 ||
> > +             base + size < rgn->region[i + 1].base) {
> > +             if (!lmb_region_flags_match(rgn, i, flags))
> > +                     return -1;
> > +
> > +             rgnend = rgn->region[i].base + rgn->region[i].size;
> > +             rgn->region[i].base = min(base, rgn->region[i].base);
> > +             rgnend = max(base + size, rgnend);
> > +             rgn->region[i].size = rgnend - rgn->region[i].base;
> > +     } else {
> > +             ret = lmb_merge_overlap_regions(rgn, i, base, size, flags);
> > +     }
> > +
> > +     return ret;
> > +}
> > +
> >   /* This routine called with relocation disabled. */
> >   static long lmb_add_region_flags(struct lmb_region *rgn, phys_addr_t base,
> >                                phys_size_t size, enum lmb_flags flags)
> >   {
> >       unsigned long coalesced = 0;
> > -     long adjacent, i;
> > +     long ret, i;
> >
> >       if (rgn->cnt == 0) {
> >               rgn->region[0].base = base;
> > @@ -290,23 +366,32 @@ static long lmb_add_region_flags(struct lmb_region *rgn, phys_addr_t base,
> >                               return -1; /* regions with new flags */
> >               }
> >
> > -             adjacent = lmb_addrs_adjacent(base, size, rgnbase, rgnsize);
> > -             if (adjacent > 0) {
> > +             ret = lmb_addrs_adjacent(base, size, rgnbase, rgnsize);
> > +             if (ret > 0) {
> >                       if (flags != rgnflags)
> >                               break;
> >                       rgn->region[i].base -= size;
> >                       rgn->region[i].size += size;
> >                       coalesced++;
> >                       break;
> > -             } else if (adjacent < 0) {
> > +             } else if (ret < 0) {
> >                       if (flags != rgnflags)
> >                               break;
> >                       rgn->region[i].size += size;
> >                       coalesced++;
> >                       break;
> >               } else if (lmb_addrs_overlap(base, size, rgnbase, rgnsize)) {
> > -                     /* regions overlap */
> > -                     return -1;
> > +                     if (flags == LMB_NONE) {
> > +                             ret = lmb_resize_regions(rgn, i, base, size,
> > +                                                      flags);
> > +                             if (ret < 0)
> > +                                     return -1;
> > +
> > +                             coalesced++;
> > +                             break;
> > +                     } else {
> > +                             return -1;
> > +                     }
> >               }
> >       }
> >
> > @@ -448,7 +533,7 @@ static phys_addr_t lmb_align_down(phys_addr_t addr, phys_size_t size)
> >   }
> >
> >   static phys_addr_t __lmb_alloc_base(phys_size_t size, ulong align,
> > -                                 phys_addr_t max_addr)
> > +                                 phys_addr_t max_addr, enum lmb_flags flags)
> >   {
> >       long i, rgn;
> >       phys_addr_t base = 0;
> > @@ -498,7 +583,7 @@ phys_addr_t lmb_alloc_base(phys_size_t size, ulong align, phys_addr_t max_addr)
> >   {
> >       phys_addr_t alloc;
> >
> > -     alloc = __lmb_alloc_base(size, align, max_addr);
> > +     alloc = __lmb_alloc_base(size, align, max_addr, LMB_NONE);
> >
> >       if (alloc == 0)
> >               printf("ERROR: Failed to allocate 0x%lx bytes below 0x%lx.\n",
> > @@ -507,11 +592,8 @@ phys_addr_t lmb_alloc_base(phys_size_t size, ulong align, phys_addr_t max_addr)
> >       return alloc;
> >   }
> >
> > -/*
> > - * Try to allocate a specific address range: must be in defined memory but not
> > - * reserved
> > - */
> > -phys_addr_t lmb_alloc_addr(phys_addr_t base, phys_size_t size)
> > +static phys_addr_t __lmb_alloc_addr(phys_addr_t base, phys_size_t size,
> > +                                 enum lmb_flags flags)
> >   {
> >       long rgn;
> >
> > @@ -526,13 +608,23 @@ phys_addr_t lmb_alloc_addr(phys_addr_t base, phys_size_t size)
> >                                     lmb.memory.region[rgn].size,
> >                                     base + size - 1, 1)) {
> >                       /* ok, reserve the memory */
> > -                     if (lmb_reserve(base, size) >= 0)
> > +                     if (lmb_reserve_flags(base, size, flags) >= 0)
> >                               return base;
> >               }
> >       }
> > +
> >       return 0;
> >   }
> >
> > +/*
> > + * Try to allocate a specific address range: must be in defined memory but not
> > + * reserved
> > + */
> > +phys_addr_t lmb_alloc_addr(phys_addr_t base, phys_size_t size)
> > +{
> > +     return __lmb_alloc_addr(base, size, LMB_NONE);
> > +}
> > +
> >   /* Return number of bytes from a given address that are free */
> >   phys_size_t lmb_get_free_size(phys_addr_t addr)
> >   {
>


More information about the U-Boot mailing list