Hi Sam,

Thanks for re-spinning this, one small issue below but otherwise LGTM.

I'm picking up your first patch, so you only need to re-send this one.

On 22/01/2025 11:27, Sam Day wrote:
> qcom_parse_memory is updated to return a -ENODATA error if the passed
> FDT does not contain a /memory node, or that node is incomplete (size=0)
> 
> board_fdt_blob_setup first tries to call qcom_parse_memory with the
> internal FDT (if present+valid). If that fails, it tries again with the
> external FDT (again, if present+valid).
> 
> When booting with an internal FDT from upstream, it's likely that this
> change results in a slight performance hit, since virtually all upstream
> qcom DTs lack a fully specified memory node. The impact should be
> negligible, though.
> 
> qcom_parse_memory was given a detailed docstring adapted from Caleb's
> original commit message that introduced the function.
> 
> Signed-off-by: Sam Day <[email protected]>
> ---
>  arch/arm/mach-snapdragon/board.c | 93 
> +++++++++++++++++++++++++++-------------
>  1 file changed, 63 insertions(+), 30 deletions(-)
> 
> diff --git a/arch/arm/mach-snapdragon/board.c 
> b/arch/arm/mach-snapdragon/board.c
> index 
> 2ef936aab757c7045729a2dd91944f4f9bff917e..ad3bc4b1a998049cd10e3d3fa032009347d77314
>  100644
> --- a/arch/arm/mach-snapdragon/board.c
> +++ b/arch/arm/mach-snapdragon/board.c
> @@ -88,7 +88,29 @@ int dram_init_banksize(void)
>       return 0;
>  }
>  
> -static void qcom_parse_memory(const void *fdt)
> +/**
> + * The generic memory parsing code in U-Boot lacks a few things that we
> + * need on Qualcomm:
> + *
> + * 1. It sets gd->ram_size and gd->ram_base to represent a single memory 
> block
> + * 2. setup_dest_addr() later relocates U-Boot to ram_base + ram_size, the 
> end
> + *    of that first memory block.
> + *
> + * This results in all memory beyond U-Boot being unusable in Linux when 
> booting
> + * with EFI.
> + *
> + * Since the ranges in the memory node may be out of order, the only way for 
> us
> + * to correctly determine the relocation address for U-Boot is to parse all
> + * memory regions and find the highest valid address.
> + *
> + * We can't use fdtdec_setup_memory_banksize() since it stores the result in
> + * gd->bd, which is not yet allocated.
> + *
> + * @fdt: FDT blob to parse /memory node from
> + *
> + * Return: 0 on success or -ENODATA if /memory node is missing or incomplete
> + */
> +static int qcom_parse_memory(const void *fdt)
>  {
>       int offset;
>       const fdt64_t *memory;
> @@ -97,16 +119,12 @@ static void qcom_parse_memory(const void *fdt)
>       int i, j, banks;
>  
>       offset = fdt_path_offset(fdt, "/memory");
> -     if (offset < 0) {
> -             log_err("No memory node found in device tree!\n");
> -             return;
> -     }
> +     if (offset < 0)
> +             return -ENODATA;
>  
>       memory = fdt_getprop(fdt, offset, "reg", &memsize);
> -     if (!memory) {
> -             log_err("No memory configuration was provided by the previous 
> bootloader!\n");
> -             return;
> -     }
> +     if (!memory)
> +             return -ENODATA;
>  
>       banks = min(memsize / (2 * sizeof(u64)), (ulong)CONFIG_NR_DRAM_BANKS);
>  
> @@ -119,7 +137,6 @@ static void qcom_parse_memory(const void *fdt)
>       for (i = 0, j = 0; i < banks * 2; i += 2, j++) {
>               prevbl_ddr_banks[j].start = get_unaligned_be64(&memory[i]);
>               prevbl_ddr_banks[j].size = get_unaligned_be64(&memory[i + 1]);
> -             /* SM8650 boards sometimes have empty regions! */
>               if (!prevbl_ddr_banks[j].size) {
>                       j--;
>                       continue;
> @@ -127,13 +144,16 @@ static void qcom_parse_memory(const void *fdt)
>               ram_end = max(ram_end, prevbl_ddr_banks[j].start + 
> prevbl_ddr_banks[j].size);
>       }
>  
> +     if (!j)
> +             return -ENODATA;

I think this should be
        if (!banks || !prevbl_ddr_banks[0].size)

That way it will properly detect the typical case where the source dts
has a single entry with a 0 size.

With that change:

Reviewed-by: Caleb Connolly <[email protected]>

Kind regards,
> +
>       /* Sort our RAM banks -_- */
>       qsort(prevbl_ddr_banks, banks, sizeof(prevbl_ddr_banks[0]), 
> ddr_bank_cmp);
>  
>       gd->ram_base = prevbl_ddr_banks[0].start;
>       gd->ram_size = ram_end - gd->ram_base;
> -     debug("ram_base = %#011lx, ram_size = %#011llx, ram_end = %#011llx\n",
> -           gd->ram_base, gd->ram_size, ram_end);
> +
> +     return 0;
>  }
>  
>  static void show_psci_version(void)
> @@ -153,13 +173,14 @@ static void show_psci_version(void)
>   */
>  int board_fdt_blob_setup(void **fdtp)
>  {
> -     struct fdt_header *fdt;
> +     struct fdt_header *external_fdt, *internal_fdt;
>       bool internal_valid, external_valid;
> -     int ret = 0;
> +     int ret = -ENODATA;
>  
> -     fdt = (struct fdt_header *)get_prev_bl_fdt_addr();
> -     external_valid = fdt && !fdt_check_header(fdt);
> -     internal_valid = !fdt_check_header(*fdtp);
> +     internal_fdt = (struct fdt_header *)*fdtp;
> +     external_fdt = (struct fdt_header *)get_prev_bl_fdt_addr();
> +     external_valid = external_fdt && !fdt_check_header(external_fdt);
> +     internal_valid = !fdt_check_header(internal_fdt);
>  
>       /*
>        * There is no point returning an error here, U-Boot can't do anything 
> useful in this situation.
> @@ -167,24 +188,36 @@ int board_fdt_blob_setup(void **fdtp)
>        */
>       if (!internal_valid && !external_valid)
>               panic("Internal FDT is invalid and no external FDT was 
> provided! (fdt=%#llx)\n",
> -                   (phys_addr_t)fdt);
> +                   (phys_addr_t)external_fdt);
> +
> +     /* Prefer memory information from internal DT if it's present */
> +     if (internal_valid)
> +             ret = qcom_parse_memory(internal_fdt);
> +
> +     if (ret < 0 && external_valid) {
> +             /* No internal FDT or it lacks a proper /memory node.
> +              * The previous bootloader handed us something, let's try that.
> +              */
> +             if (internal_valid)
> +                     debug("No memory info in internal FDT, falling back to 
> external\n");
> +
> +             ret = qcom_parse_memory(external_fdt);
> +     }
> +
> +     if (ret < 0)
> +             panic("No valid memory ranges found!\n");
> +
> +     debug("ram_base = %#011lx, ram_size = %#011llx\n",
> +           gd->ram_base, gd->ram_size);
>  
>       if (internal_valid) {
>               debug("Using built in FDT\n");
> -             ret = -EEXIST;
> -     } else {
> -             debug("Using external FDT\n");
> -             /* So we can use it before returning */
> -             *fdtp = fdt;
> +             return -EEXIST;
>       }
>  
> -     /*
> -      * Parse the /memory node while we're here,
> -      * this makes it easy to do other things early.
> -      */
> -     qcom_parse_memory(*fdtp);
> -
> -     return ret;
> +     debug("Using external FDT\n");
> +     *fdtp = external_fdt;
> +     return 0;
>  }
>  
>  void reset_cpu(void)
> 

-- 
// Caleb (they/them)

Reply via email to