uboot/arch/sandbox/cpu/state.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (c) 2011-2012 The Chromium OS Authors.
   4 */
   5
   6#include <common.h>
   7#include <errno.h>
   8#include <fdtdec.h>
   9#include <os.h>
  10#include <asm/state.h>
  11
  12/* Main state record for the sandbox */
  13static struct sandbox_state main_state;
  14static struct sandbox_state *state;     /* Pointer to current state record */
  15
  16static int state_ensure_space(int extra_size)
  17{
  18        void *blob = state->state_fdt;
  19        int used, size, free;
  20        void *buf;
  21        int ret;
  22
  23        used = fdt_off_dt_strings(blob) + fdt_size_dt_strings(blob);
  24        size = fdt_totalsize(blob);
  25        free = size - used;
  26        if (free > extra_size)
  27                return 0;
  28
  29        size = used + extra_size;
  30        buf = os_malloc(size);
  31        if (!buf)
  32                return -ENOMEM;
  33
  34        ret = fdt_open_into(blob, buf, size);
  35        if (ret) {
  36                os_free(buf);
  37                return -EIO;
  38        }
  39
  40        os_free(blob);
  41        state->state_fdt = buf;
  42        return 0;
  43}
  44
  45static int state_read_file(struct sandbox_state *state, const char *fname)
  46{
  47        loff_t size;
  48        int ret;
  49        int fd;
  50
  51        ret = os_get_filesize(fname, &size);
  52        if (ret < 0) {
  53                printf("Cannot find sandbox state file '%s'\n", fname);
  54                return -ENOENT;
  55        }
  56        state->state_fdt = os_malloc(size);
  57        if (!state->state_fdt) {
  58                puts("No memory to read sandbox state\n");
  59                return -ENOMEM;
  60        }
  61        fd = os_open(fname, OS_O_RDONLY);
  62        if (fd < 0) {
  63                printf("Cannot open sandbox state file '%s'\n", fname);
  64                ret = -EPERM;
  65                goto err_open;
  66        }
  67        if (os_read(fd, state->state_fdt, size) != size) {
  68                printf("Cannot read sandbox state file '%s'\n", fname);
  69                ret = -EIO;
  70                goto err_read;
  71        }
  72        os_close(fd);
  73
  74        return 0;
  75err_read:
  76        os_close(fd);
  77err_open:
  78        os_free(state->state_fdt);
  79        state->state_fdt = NULL;
  80
  81        return ret;
  82}
  83
  84/***
  85 * sandbox_read_state_nodes() - Read state associated with a driver
  86 *
  87 * This looks through all compatible nodes and calls the read function on
  88 * each one, to read in the state.
  89 *
  90 * If nothing is found, it still calls the read function once, to set up a
  91 * single global state for that driver.
  92 *
  93 * @state: Sandbox state
  94 * @io: Method to use for reading state
  95 * @blob: FDT containing state
  96 * @return 0 if OK, -EINVAL if the read function returned failure
  97 */
  98int sandbox_read_state_nodes(struct sandbox_state *state,
  99                             struct sandbox_state_io *io, const void *blob)
 100{
 101        int count;
 102        int node;
 103        int ret;
 104
 105        debug("   - read %s\n", io->name);
 106        if (!io->read)
 107                return 0;
 108
 109        node = -1;
 110        count = 0;
 111        while (blob) {
 112                node = fdt_node_offset_by_compatible(blob, node, io->compat);
 113                if (node < 0)
 114                        return 0;       /* No more */
 115                debug("   - read node '%s'\n", fdt_get_name(blob, node, NULL));
 116                ret = io->read(blob, node);
 117                if (ret) {
 118                        printf("Unable to read state for '%s'\n", io->compat);
 119                        return -EINVAL;
 120                }
 121                count++;
 122        }
 123
 124        /*
 125         * If we got no saved state, call the read function once without a
 126         * node, to set up the global state.
 127         */
 128        if (count == 0) {
 129                debug("   - read global\n");
 130                ret = io->read(NULL, -1);
 131                if (ret) {
 132                        printf("Unable to read global state for '%s'\n",
 133                               io->name);
 134                        return -EINVAL;
 135                }
 136        }
 137
 138        return 0;
 139}
 140
 141int sandbox_read_state(struct sandbox_state *state, const char *fname)
 142{
 143        struct sandbox_state_io *io;
 144        const void *blob;
 145        bool got_err;
 146        int ret;
 147
 148        if (state->read_state && fname) {
 149                ret = state_read_file(state, fname);
 150                if (ret == -ENOENT && state->ignore_missing_state_on_read)
 151                        ret = 0;
 152                if (ret)
 153                        return ret;
 154        }
 155
 156        /* Call all the state read functions */
 157        got_err = false;
 158        blob = state->state_fdt;
 159        io = ll_entry_start(struct sandbox_state_io, state_io);
 160        for (; io < ll_entry_end(struct sandbox_state_io, state_io); io++) {
 161                ret = sandbox_read_state_nodes(state, io, blob);
 162                if (ret < 0)
 163                        got_err = true;
 164        }
 165
 166        if (state->read_state && fname) {
 167                debug("Read sandbox state from '%s'%s\n", fname,
 168                      got_err ? " (with errors)" : "");
 169        }
 170
 171        return got_err ? -1 : 0;
 172}
 173
 174/***
 175 * sandbox_write_state_node() - Write state associated with a driver
 176 *
 177 * This calls the write function to write out global state for that driver.
 178 *
 179 * TODO(sjg@chromium.org): Support writing out state from multiple drivers
 180 * of the same time. We don't need this yet,and it will be much easier to
 181 * do when driver model is available.
 182 *
 183 * @state: Sandbox state
 184 * @io: Method to use for writing state
 185 * @return 0 if OK, -EIO if there is a fatal error (such as out of space
 186 * for adding the data), -EINVAL if the write function failed.
 187 */
 188int sandbox_write_state_node(struct sandbox_state *state,
 189                             struct sandbox_state_io *io)
 190{
 191        void *blob;
 192        int node;
 193        int ret;
 194
 195        if (!io->write)
 196                return 0;
 197
 198        ret = state_ensure_space(SANDBOX_STATE_MIN_SPACE);
 199        if (ret) {
 200                printf("Failed to add more space for state\n");
 201                return -EIO;
 202        }
 203
 204        /* The blob location can change when the size increases */
 205        blob = state->state_fdt;
 206        node = fdt_node_offset_by_compatible(blob, -1, io->compat);
 207        if (node == -FDT_ERR_NOTFOUND) {
 208                node = fdt_add_subnode(blob, 0, io->name);
 209                if (node < 0) {
 210                        printf("Cannot create node '%s': %s\n", io->name,
 211                               fdt_strerror(node));
 212                        return -EIO;
 213                }
 214
 215                if (fdt_setprop_string(blob, node, "compatible", io->compat)) {
 216                        puts("Cannot set compatible\n");
 217                        return -EIO;
 218                }
 219        } else if (node < 0) {
 220                printf("Cannot access node '%s': %s\n", io->name,
 221                       fdt_strerror(node));
 222                return -EIO;
 223        }
 224        debug("Write state for '%s' to node %d\n", io->compat, node);
 225        ret = io->write(blob, node);
 226        if (ret) {
 227                printf("Unable to write state for '%s'\n", io->compat);
 228                return -EINVAL;
 229        }
 230
 231        return 0;
 232}
 233
 234int sandbox_write_state(struct sandbox_state *state, const char *fname)
 235{
 236        struct sandbox_state_io *io;
 237        bool got_err;
 238        int size;
 239        int ret;
 240        int fd;
 241
 242        /* Create a state FDT if we don't have one */
 243        if (!state->state_fdt) {
 244                size = 0x4000;
 245                state->state_fdt = os_malloc(size);
 246                if (!state->state_fdt) {
 247                        puts("No memory to create FDT\n");
 248                        return -ENOMEM;
 249                }
 250                ret = fdt_create_empty_tree(state->state_fdt, size);
 251                if (ret < 0) {
 252                        printf("Cannot create empty state FDT: %s\n",
 253                               fdt_strerror(ret));
 254                        ret = -EIO;
 255                        goto err_create;
 256                }
 257        }
 258
 259        /* Call all the state write funtcions */
 260        got_err = false;
 261        io = ll_entry_start(struct sandbox_state_io, state_io);
 262        ret = 0;
 263        for (; io < ll_entry_end(struct sandbox_state_io, state_io); io++) {
 264                ret = sandbox_write_state_node(state, io);
 265                if (ret == -EIO)
 266                        break;
 267                else if (ret)
 268                        got_err = true;
 269        }
 270
 271        if (ret == -EIO) {
 272                printf("Could not write sandbox state\n");
 273                goto err_create;
 274        }
 275
 276        ret = fdt_pack(state->state_fdt);
 277        if (ret < 0) {
 278                printf("Cannot pack state FDT: %s\n", fdt_strerror(ret));
 279                ret = -EINVAL;
 280                goto err_create;
 281        }
 282        size = fdt_totalsize(state->state_fdt);
 283        fd = os_open(fname, OS_O_WRONLY | OS_O_CREAT);
 284        if (fd < 0) {
 285                printf("Cannot open sandbox state file '%s'\n", fname);
 286                ret = -EIO;
 287                goto err_create;
 288        }
 289        if (os_write(fd, state->state_fdt, size) != size) {
 290                printf("Cannot write sandbox state file '%s'\n", fname);
 291                ret = -EIO;
 292                goto err_write;
 293        }
 294        os_close(fd);
 295
 296        debug("Wrote sandbox state to '%s'%s\n", fname,
 297              got_err ? " (with errors)" : "");
 298
 299        return 0;
 300err_write:
 301        os_close(fd);
 302err_create:
 303        os_free(state->state_fdt);
 304
 305        return ret;
 306}
 307
 308int state_setprop(int node, const char *prop_name, const void *data, int size)
 309{
 310        void *blob;
 311        int len;
 312        int ret;
 313
 314        fdt_getprop(state->state_fdt, node, prop_name, &len);
 315
 316        /* Add space for the new property, its name and some overhead */
 317        ret = state_ensure_space(size - len + strlen(prop_name) + 32);
 318        if (ret)
 319                return ret;
 320
 321        /* This should succeed, barring a mutiny */
 322        blob = state->state_fdt;
 323        ret = fdt_setprop(blob, node, prop_name, data, size);
 324        if (ret) {
 325                printf("%s: Unable to set property '%s' in node '%s': %s\n",
 326                       __func__, prop_name, fdt_get_name(blob, node, NULL),
 327                        fdt_strerror(ret));
 328                return -ENOSPC;
 329        }
 330
 331        return 0;
 332}
 333
 334struct sandbox_state *state_get_current(void)
 335{
 336        assert(state);
 337        return state;
 338}
 339
 340void state_set_skip_delays(bool skip_delays)
 341{
 342        struct sandbox_state *state = state_get_current();
 343
 344        state->skip_delays = skip_delays;
 345}
 346
 347bool state_get_skip_delays(void)
 348{
 349        struct sandbox_state *state = state_get_current();
 350
 351        return state->skip_delays;
 352}
 353
 354void state_reset_for_test(struct sandbox_state *state)
 355{
 356        /* No reset yet, so mark it as such. Always allow power reset */
 357        state->last_sysreset = SYSRESET_COUNT;
 358        state->sysreset_allowed[SYSRESET_POWER] = true;
 359
 360        memset(&state->wdt, '\0', sizeof(state->wdt));
 361        memset(state->spi, '\0', sizeof(state->spi));
 362}
 363
 364int state_init(void)
 365{
 366        state = &main_state;
 367
 368        state->ram_size = CONFIG_SYS_SDRAM_SIZE;
 369        state->ram_buf = os_malloc(state->ram_size);
 370        assert(state->ram_buf);
 371
 372        state_reset_for_test(state);
 373        /*
 374         * Example of how to use GPIOs:
 375         *
 376         * sandbox_gpio_set_direction(170, 0);
 377         * sandbox_gpio_set_value(170, 0);
 378         */
 379        return 0;
 380}
 381
 382int state_uninit(void)
 383{
 384        int err;
 385
 386        state = &main_state;
 387
 388        if (state->write_ram_buf && !state->ram_buf_rm) {
 389                err = os_write_ram_buf(state->ram_buf_fname);
 390                if (err) {
 391                        printf("Failed to write RAM buffer\n");
 392                        return err;
 393                }
 394        }
 395
 396        if (state->write_state) {
 397                if (sandbox_write_state(state, state->state_fname)) {
 398                        printf("Failed to write sandbox state\n");
 399                        return -1;
 400                }
 401        }
 402
 403        /* Delete this at the last moment so as not to upset gdb too much */
 404        if (state->jumped_fname)
 405                os_unlink(state->jumped_fname);
 406
 407        if (state->state_fdt)
 408                os_free(state->state_fdt);
 409        memset(state, '\0', sizeof(*state));
 410
 411        return 0;
 412}
 413