lkml.org 
[lkml]   [2018]   [Nov]   [16]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH v2] mtd: spi-nor: fix selection of uniform erase type in flexible conf
    Date
    There are uniform, non-uniform and flexible erase flash configurations.

    The non-uniform erase types, are the erase types that can _not_ erase
    the entire flash by their own.

    As the code was, in case flashes had flexible erase capabilities
    (support both uniform and non-uniform erase types in the same flash
    configuration) and supported multiple uniform erase type sizes, the
    code did not sort the uniform erase types, and could select a wrong
    erase type size.

    Sort the uniform erase mask in case of flexible erase flash
    configurations, in order to select the best uniform erase type size.

    Uniform, non-uniform, and flexible configurations with just a valid
    uniform erase type, are not affected by this change.

    Uniform erase tested on mx25l3273fm2i-08g and sst26vf064B-104i/sn.
    Non uniform erase tested on sst26vf064B-104i/sn.

    Fixes: 5390a8df769e ("mtd: spi-nor: add support to non-uniform SFDP SPI NOR flash memories")
    Signed-off-by: Tudor Ambarus <tudor.ambarus@microchip.com>
    ---
    v2: drop uneeded change

    drivers/mtd/spi-nor/spi-nor.c | 47 +++++++++++++++++++++++++++++++++----------
    1 file changed, 36 insertions(+), 11 deletions(-)

    diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
    index 69784b3b8ca1..4c7e4dc25006 100644
    --- a/drivers/mtd/spi-nor/spi-nor.c
    +++ b/drivers/mtd/spi-nor/spi-nor.c
    @@ -2529,6 +2529,34 @@ static int spi_nor_map_cmp_erase_type(const void *l, const void *r)
    }

    /**
    + * spi_nor_sort_erase_mask() - sort erase mask
    + * @map: the erase map of the SPI NOR
    + * @erase_mask: the erase type mask to be sorted
    + *
    + * Replicate the sort done for the map's erase types in BFPT: sort the erase
    + * mask in ascending order with the smallest erase type size starting from
    + * BIT(0) in the sorted erase mask.
    + *
    + * Return: sorted erase mask.
    + */
    +static u8 spi_nor_sort_erase_mask(struct spi_nor_erase_map *map, u8 erase_mask)
    +{
    + struct spi_nor_erase_type *erase_type = map->erase_type;
    + int i;
    + u8 sorted_erase_mask = 0;
    +
    + if (!erase_mask)
    + return 0;
    +
    + /* Replicate the sort done for the map's erase types. */
    + for (i = 0; i < SNOR_ERASE_TYPE_MAX; i++)
    + if (erase_type[i].size && erase_mask & BIT(erase_type[i].idx))
    + sorted_erase_mask |= BIT(i);
    +
    + return sorted_erase_mask;
    +}
    +
    +/**
    * spi_nor_regions_sort_erase_types() - sort erase types in each region
    * @map: the erase map of the SPI NOR
    *
    @@ -2543,19 +2571,13 @@ static int spi_nor_map_cmp_erase_type(const void *l, const void *r)
    static void spi_nor_regions_sort_erase_types(struct spi_nor_erase_map *map)
    {
    struct spi_nor_erase_region *region = map->regions;
    - struct spi_nor_erase_type *erase_type = map->erase_type;
    - int i;
    u8 region_erase_mask, sorted_erase_mask;

    while (region) {
    region_erase_mask = region->offset & SNOR_ERASE_TYPE_MASK;

    - /* Replicate the sort done for the map's erase types. */
    - sorted_erase_mask = 0;
    - for (i = 0; i < SNOR_ERASE_TYPE_MAX; i++)
    - if (erase_type[i].size &&
    - region_erase_mask & BIT(erase_type[i].idx))
    - sorted_erase_mask |= BIT(i);
    + sorted_erase_mask = spi_nor_sort_erase_mask(map,
    + region_erase_mask);

    /* Overwrite erase mask. */
    region->offset = (region->offset & ~SNOR_ERASE_TYPE_MASK) |
    @@ -2985,7 +3007,7 @@ static int spi_nor_init_non_uniform_erase_map(struct spi_nor *nor,
    u64 offset;
    u32 region_count;
    int i, j;
    - u8 erase_type;
    + u8 erase_type, uniform_erase_type;

    region_count = SMPT_MAP_REGION_COUNT(*smpt);
    /*
    @@ -2998,7 +3020,7 @@ static int spi_nor_init_non_uniform_erase_map(struct spi_nor *nor,
    return -ENOMEM;
    map->regions = region;

    - map->uniform_erase_type = 0xff;
    + uniform_erase_type = 0xff;
    offset = 0;
    /* Populate regions. */
    for (i = 0; i < region_count; i++) {
    @@ -3013,12 +3035,15 @@ static int spi_nor_init_non_uniform_erase_map(struct spi_nor *nor,
    * Save the erase types that are supported in all regions and
    * can erase the entire flash memory.
    */
    - map->uniform_erase_type &= erase_type;
    + uniform_erase_type &= erase_type;

    offset = (region[i].offset & ~SNOR_ERASE_FLAGS_MASK) +
    region[i].size;
    }

    + map->uniform_erase_type = spi_nor_sort_erase_mask(map,
    + uniform_erase_type);
    +
    spi_nor_region_mark_end(&region[i - 1]);

    return 0;
    --
    2.9.4
    \
     
     \ /
      Last update: 2018-11-16 18:47    [W:2.844 / U:1.164 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site