int mrccache_update(struct udevice *sf, struct mrc_region *entry,
		    struct mrc_data_container *cur)
{
	struct mrc_data_container *cache;
	ulong offset;
	ulong base_addr;
	int ret;

	if (!is_mrc_cache(cur))
		return -EINVAL;

	/* Find the last used block */
	base_addr = entry->base + entry->offset;
	debug("Updating MRC cache data\n");
	cache = mrccache_find_current(entry);
	if (cache && (cache->data_size == cur->data_size) &&
	    (!memcmp(cache, cur, cache->data_size + sizeof(*cur)))) {
		debug("MRC data in flash is up to date. No update\n");
		return -EEXIST;
	}

	/* Move to the next block, which will be the first unused block */
	if (cache)
		cache = find_next_mrc_cache(entry, cache);

	/*
	 * If we have got to the end, erase the entire mrc-cache area and start
	 * again at block 0.
	 */
	if (!cache) {
		debug("Erasing the MRC cache region of %x bytes at %x\n",
		      entry->length, entry->offset);

		ret = spi_flash_erase_dm(sf, entry->offset, entry->length);
		if (ret) {
			debug("Failed to erase flash region\n");
			return ret;
		}
		cache = (struct mrc_data_container *)base_addr;
	}

	/* Write the data out */
	offset = (ulong)cache - base_addr + entry->offset;
	debug("Write MRC cache update to flash at %lx\n", offset);
	ret = spi_flash_write_dm(sf, offset, cur->data_size + sizeof(*cur),
				 cur);
	if (ret) {
		debug("Failed to write to SPI flash\n");
		return ret;
	}

	return 0;
}
Example #2
0
static void update_mrc_cache(void *unused)
{
    printk(BIOS_DEBUG, "Updating MRC cache data.\n");
    struct mrc_data_container *current = cbmem_find(CBMEM_ID_MRCDATA);
    struct mrc_data_container *cache, *cache_base;
    u32 cache_size;

    if (!current) {
        printk(BIOS_ERR, "No MRC cache in cbmem. Can't update flash.\n");
        return;
    }
    if (current->mrc_data_size == -1) {
        printk(BIOS_ERR, "MRC cache data in cbmem invalid.\n");
        return;
    }

    cache_size = get_mrc_cache_region(&cache_base);
    if (cache_base == NULL) {
        printk(BIOS_ERR, "%s: could not find MRC cache area\n",
               __func__);
        return;
    }

    /*
     * we need to:
     */
    //  0. compare MRC data to last mrc-cache block (exit if same)
    cache = find_current_mrc_cache_local(cache_base, cache_size);

    if (cache && (cache->mrc_data_size == current->mrc_data_size) &&
            (memcmp(cache, current, cache->mrc_data_size) == 0)) {
        printk(BIOS_DEBUG,
               "MRC data in flash is up to date. No update.\n");
        return;
    }

    //  1. use spi_flash_probe() to find the flash, then
    spi_init();
    struct spi_flash *flash = spi_flash_probe(0, 0);
    if (!flash) {
        printk(BIOS_DEBUG, "Could not find SPI device\n");
        return;
    }

    //  2. look up the first unused block
    if (cache)
        cache = find_next_mrc_cache(cache_base, cache, cache_size);

    /*
     * 3. if no such place exists, erase entire mrc-cache range & use
     * block 0. First time around the erase is not needed, but this is a
     * small overhead for simpler code.
     */
    if (!cache) {
        printk(BIOS_DEBUG,
               "Need to erase the MRC cache region of %d bytes at %p\n",
               cache_size, cache_base);

        flash->erase(flash, to_flash_offset(flash, cache_base), cache_size);

        /* we will start at the beginning again */
        cache = cache_base;
    }
    //  4. write mrc data with flash->write()
    printk(BIOS_DEBUG, "Finally: write MRC cache update to flash at %p\n",
           cache);
    flash->write(flash, to_flash_offset(flash, cache),
                 current->mrc_data_size + sizeof(*current), current);
}