LCOV - code coverage report
Current view: top level - core - fdt.c (source / functions) Coverage Total Hit
Test: skiboot.info Lines: 63.4 % 101 64
Test Date: 2025-01-15 20:37:39 Functions: 90.9 % 11 10
Branches: - 0 0

             Branch data     Line data    Source code
       1                 :             : // SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
       2                 :             : /*
       3                 :             :  * Produce and consume flattened device trees
       4                 :             :  *
       5                 :             :  * Copyright 2013-2019 IBM Corp.
       6                 :             :  */
       7                 :             : 
       8                 :             : #include <skiboot.h>
       9                 :             : #include <stdarg.h>
      10                 :             : #include <libfdt.h>
      11                 :             : #include <device.h>
      12                 :             : #include <chip.h>
      13                 :             : #include <cpu.h>
      14                 :             : #include <opal.h>
      15                 :             : #include <interrupts.h>
      16                 :             : #include <fsp.h>
      17                 :             : #include <cec.h>
      18                 :             : #include <vpd.h>
      19                 :             : #include <ccan/str/str.h>
      20                 :             : 
      21                 :             : static int fdt_error;
      22                 :             : 
      23                 :             : #undef DEBUG_FDT
      24                 :             : #ifdef DEBUG_FDT
      25                 :             : #define FDT_DBG(fmt, a...)      prlog(PR_DEBUG, "FDT: " fmt, ##a)
      26                 :             : #else
      27                 :             : #define FDT_DBG(fmt, a...)
      28                 :             : #endif
      29                 :             : 
      30                 :        1012 : static void __save_err(int err, const char *str)
      31                 :             : {
      32                 :             :         FDT_DBG("rc: %d from \"%s\"\n", err, str);
      33                 :        1012 :         if (err && !fdt_error) {
      34                 :           0 :                 prerror("FDT: Error %d from \"%s\"\n", err, str);
      35                 :           0 :                 fdt_error = err;
      36                 :             :         }
      37                 :        1012 : }
      38                 :             : 
      39                 :             : #define save_err(...) __save_err(__VA_ARGS__, #__VA_ARGS__)
      40                 :             : 
      41                 :          80 : static void dt_property_cell(void *fdt, const char *name, u32 cell)
      42                 :             : {
      43                 :          80 :         save_err(fdt_property_cell(fdt, name, cell));
      44                 :          80 : }
      45                 :             : 
      46                 :          80 : static void dt_begin_node(void *fdt, const struct dt_node *dn)
      47                 :             : {
      48                 :          80 :         save_err(fdt_begin_node(fdt, dn->name));
      49                 :             : 
      50                 :          80 :         dt_property_cell(fdt, "phandle", dn->phandle);
      51                 :          80 : }
      52                 :             : 
      53                 :         766 : static void dt_property(void *fdt, const struct dt_property *p)
      54                 :             : {
      55                 :         766 :         save_err(fdt_property(fdt, p->name, p->prop, p->len));
      56                 :         766 : }
      57                 :             : 
      58                 :          80 : static void dt_end_node(void *fdt)
      59                 :             : {
      60                 :          80 :         save_err(fdt_end_node(fdt));
      61                 :          80 : }
      62                 :             : 
      63                 :             : #ifdef DEBUG_FDT
      64                 :             : static void dump_fdt(void *fdt)
      65                 :             : {
      66                 :             :         int i, off, depth, err;
      67                 :             : 
      68                 :             :         prlog(PR_INFO, "Device tree %u@%p\n", fdt_totalsize(fdt), fdt);
      69                 :             :         err = fdt_check_header(fdt);
      70                 :             :         if (err) {
      71                 :             :                 prerror("fdt_check_header: %s\n", fdt_strerror(err));
      72                 :             :                 return;
      73                 :             :         }
      74                 :             :         prlog(PR_INFO, "fdt_check_header passed\n");
      75                 :             : 
      76                 :             :         prlog(PR_INFO, "fdt_num_mem_rsv = %u\n", fdt_num_mem_rsv(fdt));
      77                 :             :         for (i = 0; i < fdt_num_mem_rsv(fdt); i++) {
      78                 :             :                 u64 addr, size;
      79                 :             : 
      80                 :             :                 err = fdt_get_mem_rsv(fdt, i, &addr, &size);
      81                 :             :                 if (err) {
      82                 :             :                         prlog(PR_INFO, " ERR %s\n", fdt_strerror(err));
      83                 :             :                         return;
      84                 :             :                 }
      85                 :             :                 prlog(PR_INFO, "  mem_rsv[%i] = %lu@%#lx\n",
      86                 :             :                       i, (long)addr, (long)size);
      87                 :             :         }
      88                 :             : 
      89                 :             :         for (off = fdt_next_node(fdt, 0, &depth);
      90                 :             :              off > 0;
      91                 :             :              off = fdt_next_node(fdt, off, &depth)) {
      92                 :             :                 int len;
      93                 :             :                 const char *name;
      94                 :             : 
      95                 :             :                 name = fdt_get_name(fdt, off, &len);
      96                 :             :                 if (!name) {
      97                 :             :                         prerror("fdt: offset %i no name!\n", off);
      98                 :             :                         return;
      99                 :             :                 }
     100                 :             :                 prlog(PR_INFO, "name: %s [%u]\n", name, off);
     101                 :             :         }
     102                 :             : }
     103                 :             : #endif
     104                 :             : 
     105                 :          80 : static void flatten_dt_properties(void *fdt, const struct dt_node *dn)
     106                 :             : {
     107                 :             :         const struct dt_property *p;
     108                 :             : 
     109                 :         849 :         list_for_each(&dn->properties, p, list) {
     110                 :         769 :                 if (strstarts(p->name, DT_PRIVATE))
     111                 :           3 :                         continue;
     112                 :             : 
     113                 :             :                 FDT_DBG("  prop: %s size: %ld\n", p->name, p->len);
     114                 :         766 :                 dt_property(fdt, p);
     115                 :             :         }
     116                 :          80 : }
     117                 :             : 
     118                 :          80 : static void flatten_dt_node(void *fdt, const struct dt_node *root,
     119                 :             :                             bool exclusive)
     120                 :             : {
     121                 :             :         const struct dt_node *i;
     122                 :             : 
     123                 :          80 :         if (!exclusive) {
     124                 :             :                 FDT_DBG("node: %s\n", root->name);
     125                 :          80 :                 dt_begin_node(fdt, root);
     126                 :          80 :                 flatten_dt_properties(fdt, root);
     127                 :             :         }
     128                 :             : 
     129                 :         159 :         list_for_each(&root->children, i, list)
     130                 :          79 :                 flatten_dt_node(fdt, i, false);
     131                 :             : 
     132                 :          80 :         if (!exclusive)
     133                 :          80 :                 dt_end_node(fdt);
     134                 :          80 : }
     135                 :             : 
     136                 :           1 : static void create_dtb_reservemap(void *fdt, const struct dt_node *root)
     137                 :             : {
     138                 :             :         uint64_t base, size;
     139                 :             :         const __be64 *ranges;
     140                 :             :         const struct dt_property *prop;
     141                 :             :         int i;
     142                 :             : 
     143                 :             :         /* Duplicate the reserved-ranges property into the fdt reservemap */
     144                 :           1 :         prop = dt_find_property(root, "reserved-ranges");
     145                 :           1 :         if (prop) {
     146                 :           1 :                 ranges = (const void *)prop->prop;
     147                 :             : 
     148                 :           4 :                 for (i = 0; i < prop->len / (sizeof(uint64_t) * 2); i++) {
     149                 :           3 :                         base = be64_to_cpu(*(ranges++));
     150                 :           3 :                         size = be64_to_cpu(*(ranges++));
     151                 :           3 :                         save_err(fdt_add_reservemap_entry(fdt, base, size));
     152                 :             :                 }
     153                 :             :         }
     154                 :             : 
     155                 :           1 :         save_err(fdt_finish_reservemap(fdt));
     156                 :           1 : }
     157                 :             : 
     158                 :           1 : static int __create_dtb(void *fdt, size_t len,
     159                 :             :                         const struct dt_node *root,
     160                 :             :                         bool exclusive)
     161                 :             : {
     162                 :           1 :         if (chip_quirk(QUIRK_SLOW_SIM))
     163                 :           0 :                 save_err(fdt_create_with_flags(fdt, len, FDT_CREATE_FLAG_NO_NAME_DEDUP));
     164                 :             :         else
     165                 :           1 :                 save_err(fdt_create_with_flags(fdt, len, 0));
     166                 :           1 :         if (fdt_error)
     167                 :           0 :                 goto err;
     168                 :             : 
     169                 :           1 :         if (root == dt_root && !exclusive)
     170                 :           1 :                 create_dtb_reservemap(fdt, root);
     171                 :             :         else
     172                 :           0 :                 save_err(fdt_finish_reservemap(fdt));
     173                 :             : 
     174                 :           1 :         flatten_dt_node(fdt, root, exclusive);
     175                 :             : 
     176                 :           1 :         save_err(fdt_finish(fdt));
     177                 :           1 :         if (fdt_error) {
     178                 :           0 : err:
     179                 :           0 :                 prerror("dtb: error %s\n", fdt_strerror(fdt_error));
     180                 :           0 :                 return fdt_error;
     181                 :             :         }
     182                 :             : 
     183                 :             : #ifdef DEBUG_FDT
     184                 :             :         dump_fdt(fdt);
     185                 :             : #endif
     186                 :           1 :         return 0;
     187                 :             : }
     188                 :             : 
     189                 :           1 : void *create_dtb(const struct dt_node *root, bool exclusive)
     190                 :             : {
     191                 :           1 :         void *fdt = NULL;
     192                 :           1 :         size_t len = DEVICE_TREE_MAX_SIZE;
     193                 :           1 :         uint32_t old_last_phandle = get_last_phandle();
     194                 :             :         int ret;
     195                 :             : 
     196                 :             :         do {
     197                 :           1 :                 set_last_phandle(old_last_phandle);
     198                 :           1 :                 fdt_error = 0;
     199                 :           1 :                 fdt = malloc(len);
     200                 :           1 :                 if (!fdt) {
     201                 :           0 :                         prerror("dtb: could not malloc %lu\n", (long)len);
     202                 :           0 :                         return NULL;
     203                 :             :                 }
     204                 :             : 
     205                 :           1 :                 ret = __create_dtb(fdt, len, root, exclusive);
     206                 :           1 :                 if (ret) {
     207                 :           0 :                         free(fdt);
     208                 :           0 :                         fdt = NULL;
     209                 :             :                 }
     210                 :             : 
     211                 :           1 :                 len *= 2;
     212                 :           1 :         } while (ret == -FDT_ERR_NOSPACE);
     213                 :             : 
     214                 :           1 :         return fdt;
     215                 :             : }
     216                 :             : 
     217                 :           0 : static int64_t opal_get_device_tree(uint32_t phandle,
     218                 :             :                                     uint64_t buf, uint64_t len)
     219                 :             : {
     220                 :             :         struct dt_node *root;
     221                 :           0 :         void *fdt = (void *)buf;
     222                 :             :         uint32_t old_last_phandle;
     223                 :             :         int64_t totalsize;
     224                 :             :         int ret;
     225                 :             : 
     226                 :           0 :         if (!opal_addr_valid(fdt))
     227                 :           0 :                 return OPAL_PARAMETER;
     228                 :             : 
     229                 :           0 :         root = dt_find_by_phandle(dt_root, phandle);
     230                 :           0 :         if (!root)
     231                 :           0 :                 return OPAL_PARAMETER;
     232                 :             : 
     233                 :           0 :         if (!fdt) {
     234                 :           0 :                 fdt = create_dtb(root, true);
     235                 :           0 :                 if (!fdt)
     236                 :           0 :                         return OPAL_INTERNAL_ERROR;
     237                 :           0 :                 totalsize = fdt_totalsize(fdt);
     238                 :           0 :                 free(fdt);
     239                 :           0 :                 return totalsize;
     240                 :             :         }
     241                 :             : 
     242                 :           0 :         if (!len)
     243                 :           0 :                 return OPAL_PARAMETER;
     244                 :             : 
     245                 :           0 :         fdt_error = 0;
     246                 :           0 :         old_last_phandle = get_last_phandle();
     247                 :           0 :         ret = __create_dtb(fdt, len, root, true);
     248                 :           0 :         if (ret) {
     249                 :           0 :                 set_last_phandle(old_last_phandle);
     250                 :           0 :                 if (ret == -FDT_ERR_NOSPACE)
     251                 :           0 :                         return OPAL_NO_MEM;
     252                 :             : 
     253                 :           0 :                 return OPAL_EMPTY;
     254                 :             :         }
     255                 :             : 
     256                 :           0 :         return OPAL_SUCCESS;
     257                 :             : }
     258                 :             : opal_call(OPAL_GET_DEVICE_TREE, opal_get_device_tree, 3);
        

Generated by: LCOV version 2.0-1