LCOV - code coverage report
Current view: top level - core - fdt.c (source / functions) Hit Total Coverage
Test: skiboot.info Lines: 64 101 63.4 %
Date: 2024-01-02 21:04:04 Functions: 10 11 90.9 %
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 1.14