Commit 0e164238 authored by Takahiro Kuwano's avatar Takahiro Kuwano Committed by Tudor Ambarus

mtd: spi-nor: core: rework struct spi_nor_erase_region

Encoding bitmask flags into offset worsen the code readability. The
erase type mask and flags should be stored in dedicated members. Also,
erase_map.uniform_erase_type can be removed as it is redundant.
Signed-off-by: default avatarTakahiro Kuwano <Takahiro.Kuwano@infineon.com>
Suggested-by: default avatarMichael Walle <mwalle@kernel.org>
Reviewed-by: default avatarMichael Walle <mwalle@kernel.org>
Link: https://lore.kernel.org/r/8e5e9e4081ed9f16ea9dce30693304a4b54d19b1.1708404584.git.Takahiro.Kuwano@infineon.com
[ta: remove spi_nor_region_end()]
Signed-off-by: default avatarTudor Ambarus <tudor.ambarus@linaro.org>
parent a956502a
...@@ -1158,7 +1158,7 @@ static u8 spi_nor_convert_3to4_erase(u8 opcode) ...@@ -1158,7 +1158,7 @@ static u8 spi_nor_convert_3to4_erase(u8 opcode)
static bool spi_nor_has_uniform_erase(const struct spi_nor *nor) static bool spi_nor_has_uniform_erase(const struct spi_nor *nor)
{ {
return !!nor->params->erase_map.uniform_erase_type; return !!nor->params->erase_map.uniform_region.erase_mask;
} }
static void spi_nor_set_4byte_opcodes(struct spi_nor *nor) static void spi_nor_set_4byte_opcodes(struct spi_nor *nor)
...@@ -1542,7 +1542,6 @@ spi_nor_find_best_erase_type(const struct spi_nor_erase_map *map, ...@@ -1542,7 +1542,6 @@ spi_nor_find_best_erase_type(const struct spi_nor_erase_map *map,
const struct spi_nor_erase_type *erase; const struct spi_nor_erase_type *erase;
u32 rem; u32 rem;
int i; int i;
u8 erase_mask = region->offset & SNOR_ERASE_TYPE_MASK;
/* /*
* Erase types are ordered by size, with the smallest erase type at * Erase types are ordered by size, with the smallest erase type at
...@@ -1550,7 +1549,7 @@ spi_nor_find_best_erase_type(const struct spi_nor_erase_map *map, ...@@ -1550,7 +1549,7 @@ spi_nor_find_best_erase_type(const struct spi_nor_erase_map *map,
*/ */
for (i = SNOR_ERASE_TYPE_MAX - 1; i >= 0; i--) { for (i = SNOR_ERASE_TYPE_MAX - 1; i >= 0; i--) {
/* Does the erase region support the tested erase type? */ /* Does the erase region support the tested erase type? */
if (!(erase_mask & BIT(i))) if (!(region->erase_mask & BIT(i)))
continue; continue;
erase = &map->erase_type[i]; erase = &map->erase_type[i];
...@@ -1558,7 +1557,7 @@ spi_nor_find_best_erase_type(const struct spi_nor_erase_map *map, ...@@ -1558,7 +1557,7 @@ spi_nor_find_best_erase_type(const struct spi_nor_erase_map *map,
continue; continue;
/* Alignment is not mandatory for overlaid regions */ /* Alignment is not mandatory for overlaid regions */
if (region->offset & SNOR_OVERLAID_REGION && if (region->flags & SNOR_OVERLAID_REGION &&
region->size <= len) region->size <= len)
return erase; return erase;
...@@ -1576,12 +1575,7 @@ spi_nor_find_best_erase_type(const struct spi_nor_erase_map *map, ...@@ -1576,12 +1575,7 @@ spi_nor_find_best_erase_type(const struct spi_nor_erase_map *map,
static u64 spi_nor_region_is_last(const struct spi_nor_erase_region *region) static u64 spi_nor_region_is_last(const struct spi_nor_erase_region *region)
{ {
return region->offset & SNOR_LAST_REGION; return region->flags & SNOR_LAST_REGION;
}
static u64 spi_nor_region_end(const struct spi_nor_erase_region *region)
{
return (region->offset & ~SNOR_ERASE_FLAGS_MASK) + region->size;
} }
/** /**
...@@ -1612,16 +1606,14 @@ static struct spi_nor_erase_region * ...@@ -1612,16 +1606,14 @@ static struct spi_nor_erase_region *
spi_nor_find_erase_region(const struct spi_nor_erase_map *map, u64 addr) spi_nor_find_erase_region(const struct spi_nor_erase_map *map, u64 addr)
{ {
struct spi_nor_erase_region *region = map->regions; struct spi_nor_erase_region *region = map->regions;
u64 region_start = region->offset & ~SNOR_ERASE_FLAGS_MASK; u64 region_end = region->offset + region->size;
u64 region_end = region_start + region->size;
while (addr < region_start || addr >= region_end) { while (addr < region->offset || addr >= region_end) {
region = spi_nor_region_next(region); region = spi_nor_region_next(region);
if (!region) if (!region)
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
region_start = region->offset & ~SNOR_ERASE_FLAGS_MASK; region_end = region->offset + region->size;
region_end = region_start + region->size;
} }
return region; return region;
...@@ -1649,7 +1641,7 @@ spi_nor_init_erase_cmd(const struct spi_nor_erase_region *region, ...@@ -1649,7 +1641,7 @@ spi_nor_init_erase_cmd(const struct spi_nor_erase_region *region,
cmd->opcode = erase->opcode; cmd->opcode = erase->opcode;
cmd->count = 1; cmd->count = 1;
if (region->offset & SNOR_OVERLAID_REGION) if (region->flags & SNOR_OVERLAID_REGION)
cmd->size = region->size; cmd->size = region->size;
else else
cmd->size = erase->size; cmd->size = erase->size;
...@@ -1699,7 +1691,7 @@ static int spi_nor_init_erase_cmd_list(struct spi_nor *nor, ...@@ -1699,7 +1691,7 @@ static int spi_nor_init_erase_cmd_list(struct spi_nor *nor,
if (IS_ERR(region)) if (IS_ERR(region))
return PTR_ERR(region); return PTR_ERR(region);
region_end = spi_nor_region_end(region); region_end = region->offset + region->size;
while (len) { while (len) {
erase = spi_nor_find_best_erase_type(map, region, addr, len); erase = spi_nor_find_best_erase_type(map, region, addr, len);
...@@ -1708,7 +1700,7 @@ static int spi_nor_init_erase_cmd_list(struct spi_nor *nor, ...@@ -1708,7 +1700,7 @@ static int spi_nor_init_erase_cmd_list(struct spi_nor *nor,
if (prev_erase != erase || if (prev_erase != erase ||
erase->size != cmd->size || erase->size != cmd->size ||
region->offset & SNOR_OVERLAID_REGION) { region->flags & SNOR_OVERLAID_REGION) {
cmd = spi_nor_init_erase_cmd(region, erase); cmd = spi_nor_init_erase_cmd(region, erase);
if (IS_ERR(cmd)) { if (IS_ERR(cmd)) {
ret = PTR_ERR(cmd); ret = PTR_ERR(cmd);
...@@ -1727,7 +1719,7 @@ static int spi_nor_init_erase_cmd_list(struct spi_nor *nor, ...@@ -1727,7 +1719,7 @@ static int spi_nor_init_erase_cmd_list(struct spi_nor *nor,
region = spi_nor_region_next(region); region = spi_nor_region_next(region);
if (!region) if (!region)
goto destroy_erase_cmd_list; goto destroy_erase_cmd_list;
region_end = spi_nor_region_end(region); region_end = region->offset + region->size;
} }
prev_erase = erase; prev_erase = erase;
...@@ -2468,12 +2460,11 @@ void spi_nor_mask_erase_type(struct spi_nor_erase_type *erase) ...@@ -2468,12 +2460,11 @@ void spi_nor_mask_erase_type(struct spi_nor_erase_type *erase)
void spi_nor_init_uniform_erase_map(struct spi_nor_erase_map *map, void spi_nor_init_uniform_erase_map(struct spi_nor_erase_map *map,
u8 erase_mask, u64 flash_size) u8 erase_mask, u64 flash_size)
{ {
/* Offset 0 with erase_mask and SNOR_LAST_REGION bit set */ map->uniform_region.offset = 0;
map->uniform_region.offset = (erase_mask & SNOR_ERASE_TYPE_MASK) |
SNOR_LAST_REGION;
map->uniform_region.size = flash_size; map->uniform_region.size = flash_size;
map->uniform_region.erase_mask = erase_mask;
map->uniform_region.flags = SNOR_LAST_REGION;
map->regions = &map->uniform_region; map->regions = &map->uniform_region;
map->uniform_erase_type = erase_mask;
} }
int spi_nor_post_bfpt_fixups(struct spi_nor *nor, int spi_nor_post_bfpt_fixups(struct spi_nor *nor,
...@@ -2560,7 +2551,7 @@ spi_nor_select_uniform_erase(struct spi_nor_erase_map *map) ...@@ -2560,7 +2551,7 @@ spi_nor_select_uniform_erase(struct spi_nor_erase_map *map)
{ {
const struct spi_nor_erase_type *tested_erase, *erase = NULL; const struct spi_nor_erase_type *tested_erase, *erase = NULL;
int i; int i;
u8 uniform_erase_type = map->uniform_erase_type; u8 uniform_erase_type = map->uniform_region.erase_mask;
/* /*
* Search for the biggest erase size, except for when compiled * Search for the biggest erase size, except for when compiled
...@@ -2599,8 +2590,7 @@ spi_nor_select_uniform_erase(struct spi_nor_erase_map *map) ...@@ -2599,8 +2590,7 @@ spi_nor_select_uniform_erase(struct spi_nor_erase_map *map)
return NULL; return NULL;
/* Disable all other Sector Erase commands. */ /* Disable all other Sector Erase commands. */
map->uniform_erase_type &= ~SNOR_ERASE_TYPE_MASK; map->uniform_region.erase_mask = BIT(erase - map->erase_type);
map->uniform_erase_type |= BIT(erase - map->erase_type);
return erase; return erase;
} }
......
...@@ -240,27 +240,25 @@ struct spi_nor_erase_command { ...@@ -240,27 +240,25 @@ struct spi_nor_erase_command {
/** /**
* struct spi_nor_erase_region - Structure to describe a SPI NOR erase region * struct spi_nor_erase_region - Structure to describe a SPI NOR erase region
* @offset: the offset in the data array of erase region start. * @offset: the offset in the data array of erase region start.
* LSB bits are used as a bitmask encoding flags to
* determine if this region is overlaid, if this region is
* the last in the SPI NOR flash memory and to indicate
* all the supported erase commands inside this region.
* The erase types are sorted in ascending order with the
* smallest Erase Type size being at BIT(0).
* @size: the size of the region in bytes. * @size: the size of the region in bytes.
* @erase_mask: bitmask to indicate all the supported erase commands
* inside this region. The erase types are sorted in
* ascending order with the smallest Erase Type size being
* at BIT(0).
* @flags: flags to determine if this region is overlaid, if this
* region is the last in the SPI NOR flash memory
*/ */
struct spi_nor_erase_region { struct spi_nor_erase_region {
u64 offset; u64 offset;
u64 size; u64 size;
u8 erase_mask;
u8 flags;
}; };
#define SNOR_ERASE_TYPE_MAX 4 #define SNOR_ERASE_TYPE_MAX 4
#define SNOR_ERASE_TYPE_MASK GENMASK_ULL(SNOR_ERASE_TYPE_MAX - 1, 0)
#define SNOR_LAST_REGION BIT(4) #define SNOR_LAST_REGION BIT(0)
#define SNOR_OVERLAID_REGION BIT(5) #define SNOR_OVERLAID_REGION BIT(1)
#define SNOR_ERASE_FLAGS_MAX 6
#define SNOR_ERASE_FLAGS_MASK GENMASK_ULL(SNOR_ERASE_FLAGS_MAX - 1, 0)
/** /**
* struct spi_nor_erase_map - Structure to describe the SPI NOR erase map * struct spi_nor_erase_map - Structure to describe the SPI NOR erase map
...@@ -273,17 +271,11 @@ struct spi_nor_erase_region { ...@@ -273,17 +271,11 @@ struct spi_nor_erase_region {
* The erase types are sorted in ascending order, with the * The erase types are sorted in ascending order, with the
* smallest Erase Type size being the first member in the * smallest Erase Type size being the first member in the
* erase_type array. * erase_type array.
* @uniform_erase_type: bitmask encoding erase types that can erase the
* entire memory. This member is completed at init by
* uniform and non-uniform SPI NOR flash memories if they
* support at least one erase type that can erase the
* entire memory.
*/ */
struct spi_nor_erase_map { struct spi_nor_erase_map {
struct spi_nor_erase_region *regions; struct spi_nor_erase_region *regions;
struct spi_nor_erase_region uniform_region; struct spi_nor_erase_region uniform_region;
struct spi_nor_erase_type erase_type[SNOR_ERASE_TYPE_MAX]; struct spi_nor_erase_type erase_type[SNOR_ERASE_TYPE_MAX];
u8 uniform_erase_type;
}; };
/** /**
......
...@@ -147,16 +147,17 @@ static int spi_nor_params_show(struct seq_file *s, void *data) ...@@ -147,16 +147,17 @@ static int spi_nor_params_show(struct seq_file *s, void *data)
for (region = erase_map->regions; for (region = erase_map->regions;
region; region;
region = spi_nor_region_next(region)) { region = spi_nor_region_next(region)) {
u64 start = region->offset & ~SNOR_ERASE_FLAGS_MASK; u64 start = region->offset;
u64 flags = region->offset & SNOR_ERASE_FLAGS_MASK;
u64 end = start + region->size - 1; u64 end = start + region->size - 1;
u8 erase_mask = region->erase_mask;
u8 flags = region->flags;
seq_printf(s, " %08llx-%08llx | [%c%c%c%c] | %s\n", seq_printf(s, " %08llx-%08llx | [%c%c%c%c] | %s\n",
start, end, start, end,
flags & BIT(0) ? '0' : ' ', erase_mask & BIT(0) ? '0' : ' ',
flags & BIT(1) ? '1' : ' ', erase_mask & BIT(1) ? '1' : ' ',
flags & BIT(2) ? '2' : ' ', erase_mask & BIT(2) ? '2' : ' ',
flags & BIT(3) ? '3' : ' ', erase_mask & BIT(3) ? '3' : ' ',
flags & SNOR_OVERLAID_REGION ? "overlaid" : ""); flags & SNOR_OVERLAID_REGION ? "overlaid" : "");
} }
......
...@@ -389,17 +389,14 @@ static u8 spi_nor_sort_erase_mask(struct spi_nor_erase_map *map, u8 erase_mask) ...@@ -389,17 +389,14 @@ static u8 spi_nor_sort_erase_mask(struct spi_nor_erase_map *map, u8 erase_mask)
static void spi_nor_regions_sort_erase_types(struct spi_nor_erase_map *map) 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_region *region = map->regions;
u8 region_erase_mask, sorted_erase_mask; u8 sorted_erase_mask;
while (region) { while (region) {
region_erase_mask = region->offset & SNOR_ERASE_TYPE_MASK;
sorted_erase_mask = spi_nor_sort_erase_mask(map, sorted_erase_mask = spi_nor_sort_erase_mask(map,
region_erase_mask); region->erase_mask);
/* Overwrite erase mask. */ /* Overwrite erase mask. */
region->offset = (region->offset & ~SNOR_ERASE_TYPE_MASK) | region->erase_mask = sorted_erase_mask;
sorted_erase_mask;
region = spi_nor_region_next(region); region = spi_nor_region_next(region);
} }
...@@ -554,8 +551,6 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor, ...@@ -554,8 +551,6 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor,
* selecting the uniform erase. * selecting the uniform erase.
*/ */
spi_nor_regions_sort_erase_types(map); spi_nor_regions_sort_erase_types(map);
map->uniform_erase_type = map->uniform_region.offset &
SNOR_ERASE_TYPE_MASK;
/* Stop here if not JESD216 rev A or later. */ /* Stop here if not JESD216 rev A or later. */
if (bfpt_header->length == BFPT_DWORD_MAX_JESD216) if (bfpt_header->length == BFPT_DWORD_MAX_JESD216)
...@@ -808,12 +803,12 @@ static const u32 *spi_nor_get_map_in_use(struct spi_nor *nor, const u32 *smpt, ...@@ -808,12 +803,12 @@ static const u32 *spi_nor_get_map_in_use(struct spi_nor *nor, const u32 *smpt,
static void spi_nor_region_mark_end(struct spi_nor_erase_region *region) static void spi_nor_region_mark_end(struct spi_nor_erase_region *region)
{ {
region->offset |= SNOR_LAST_REGION; region->flags |= SNOR_LAST_REGION;
} }
static void spi_nor_region_mark_overlay(struct spi_nor_erase_region *region) static void spi_nor_region_mark_overlay(struct spi_nor_erase_region *region)
{ {
region->offset |= SNOR_OVERLAID_REGION; region->flags |= SNOR_OVERLAID_REGION;
} }
/** /**
...@@ -875,9 +870,10 @@ static int spi_nor_init_non_uniform_erase_map(struct spi_nor *nor, ...@@ -875,9 +870,10 @@ static int spi_nor_init_non_uniform_erase_map(struct spi_nor *nor,
/* Populate regions. */ /* Populate regions. */
for (i = 0; i < region_count; i++) { for (i = 0; i < region_count; i++) {
j = i + 1; /* index for the region dword */ j = i + 1; /* index for the region dword */
region[i].offset = offset;
region[i].size = SMPT_MAP_REGION_SIZE(smpt[j]); region[i].size = SMPT_MAP_REGION_SIZE(smpt[j]);
erase_type = SMPT_MAP_REGION_ERASE_TYPE(smpt[j]); erase_type = SMPT_MAP_REGION_ERASE_TYPE(smpt[j]);
region[i].offset = offset | erase_type; region[i].erase_mask = erase_type;
spi_nor_region_check_overlay(&region[i], erase, erase_type); spi_nor_region_check_overlay(&region[i], erase, erase_type);
...@@ -893,21 +889,21 @@ static int spi_nor_init_non_uniform_erase_map(struct spi_nor *nor, ...@@ -893,21 +889,21 @@ static int spi_nor_init_non_uniform_erase_map(struct spi_nor *nor,
*/ */
regions_erase_type |= erase_type; regions_erase_type |= erase_type;
offset = (region[i].offset & ~SNOR_ERASE_FLAGS_MASK) + offset = region[i].offset + region[i].size;
region[i].size;
} }
spi_nor_region_mark_end(&region[i - 1]); spi_nor_region_mark_end(&region[i - 1]);
save_uniform_erase_type = map->uniform_erase_type; save_uniform_erase_type = map->uniform_region.erase_mask;
map->uniform_erase_type = spi_nor_sort_erase_mask(map, map->uniform_region.erase_mask =
uniform_erase_type); spi_nor_sort_erase_mask(map,
uniform_erase_type);
if (!regions_erase_type) { if (!regions_erase_type) {
/* /*
* Roll back to the previous uniform_erase_type mask, SMPT is * Roll back to the previous uniform_erase_type mask, SMPT is
* broken. * broken.
*/ */
map->uniform_erase_type = save_uniform_erase_type; map->uniform_region.erase_mask = save_uniform_erase_type;
return -EINVAL; return -EINVAL;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment