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

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
Loading
Loading
Loading
Loading
+16 −26
Original line number Diff line number Diff line
@@ -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)
{
	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)
@@ -1542,7 +1542,6 @@ spi_nor_find_best_erase_type(const struct spi_nor_erase_map *map,
	const struct spi_nor_erase_type *erase;
	u32 rem;
	int i;
	u8 erase_mask = region->offset & SNOR_ERASE_TYPE_MASK;

	/*
	 * 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,
	 */
	for (i = SNOR_ERASE_TYPE_MAX - 1; i >= 0; i--) {
		/* Does the erase region support the tested erase type? */
		if (!(erase_mask & BIT(i)))
		if (!(region->erase_mask & BIT(i)))
			continue;

		erase = &map->erase_type[i];
@@ -1558,7 +1557,7 @@ spi_nor_find_best_erase_type(const struct spi_nor_erase_map *map,
			continue;

		/* Alignment is not mandatory for overlaid regions */
		if (region->offset & SNOR_OVERLAID_REGION &&
		if (region->flags & SNOR_OVERLAID_REGION &&
		    region->size <= len)
			return erase;

@@ -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)
{
	return region->offset & 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;
	return region->flags & SNOR_LAST_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)
{
	struct spi_nor_erase_region *region = map->regions;
	u64 region_start = region->offset & ~SNOR_ERASE_FLAGS_MASK;
	u64 region_end = region_start + region->size;
	u64 region_end = region->offset + region->size;

	while (addr < region_start || addr >= region_end) {
	while (addr < region->offset || addr >= region_end) {
		region = spi_nor_region_next(region);
		if (!region)
			return ERR_PTR(-EINVAL);

		region_start = region->offset & ~SNOR_ERASE_FLAGS_MASK;
		region_end = region_start + region->size;
		region_end = region->offset + region->size;
	}

	return region;
@@ -1649,7 +1641,7 @@ spi_nor_init_erase_cmd(const struct spi_nor_erase_region *region,
	cmd->opcode = erase->opcode;
	cmd->count = 1;

	if (region->offset & SNOR_OVERLAID_REGION)
	if (region->flags & SNOR_OVERLAID_REGION)
		cmd->size = region->size;
	else
		cmd->size = erase->size;
@@ -1699,7 +1691,7 @@ static int spi_nor_init_erase_cmd_list(struct spi_nor *nor,
	if (IS_ERR(region))
		return PTR_ERR(region);

	region_end = spi_nor_region_end(region);
	region_end = region->offset + region->size;

	while (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,

		if (prev_erase != erase ||
		    erase->size != cmd->size ||
		    region->offset & SNOR_OVERLAID_REGION) {
		    region->flags & SNOR_OVERLAID_REGION) {
			cmd = spi_nor_init_erase_cmd(region, erase);
			if (IS_ERR(cmd)) {
				ret = PTR_ERR(cmd);
@@ -1727,7 +1719,7 @@ static int spi_nor_init_erase_cmd_list(struct spi_nor *nor,
			region = spi_nor_region_next(region);
			if (!region)
				goto destroy_erase_cmd_list;
			region_end = spi_nor_region_end(region);
			region_end = region->offset + region->size;
		}

		prev_erase = 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,
				    u8 erase_mask, u64 flash_size)
{
	/* Offset 0 with erase_mask and SNOR_LAST_REGION bit set */
	map->uniform_region.offset = (erase_mask & SNOR_ERASE_TYPE_MASK) |
				     SNOR_LAST_REGION;
	map->uniform_region.offset = 0;
	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->uniform_erase_type = erase_mask;
}

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)
{
	const struct spi_nor_erase_type *tested_erase, *erase = NULL;
	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
@@ -2599,8 +2590,7 @@ spi_nor_select_uniform_erase(struct spi_nor_erase_map *map)
		return NULL;

	/* Disable all other Sector Erase commands. */
	map->uniform_erase_type &= ~SNOR_ERASE_TYPE_MASK;
	map->uniform_erase_type |= BIT(erase - map->erase_type);
	map->uniform_region.erase_mask = BIT(erase - map->erase_type);
	return erase;
}

+10 −18
Original line number Diff line number Diff line
@@ -240,27 +240,25 @@ struct spi_nor_erase_command {
/**
 * struct spi_nor_erase_region - Structure to describe a SPI NOR erase region
 * @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.
 * @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 {
	u64		offset;
	u64		size;
	u8		erase_mask;
	u8		flags;
};

#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_OVERLAID_REGION	BIT(5)

#define SNOR_ERASE_FLAGS_MAX	6
#define SNOR_ERASE_FLAGS_MASK	GENMASK_ULL(SNOR_ERASE_FLAGS_MAX - 1, 0)
#define SNOR_LAST_REGION	BIT(0)
#define SNOR_OVERLAID_REGION	BIT(1)

/**
 * struct spi_nor_erase_map - Structure to describe the SPI NOR erase map
@@ -273,17 +271,11 @@ struct spi_nor_erase_region {
 *			The erase types are sorted in ascending order, with the
 *			smallest Erase Type size being the first member in the
 *			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_region	*regions;
	struct spi_nor_erase_region	uniform_region;
	struct spi_nor_erase_type	erase_type[SNOR_ERASE_TYPE_MAX];
	u8				uniform_erase_type;
};

/**
+7 −6
Original line number Diff line number Diff line
@@ -147,16 +147,17 @@ static int spi_nor_params_show(struct seq_file *s, void *data)
	for (region = erase_map->regions;
	     region;
	     region = spi_nor_region_next(region)) {
		u64 start = region->offset & ~SNOR_ERASE_FLAGS_MASK;
		u64 flags = region->offset & SNOR_ERASE_FLAGS_MASK;
		u64 start = region->offset;
		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",
			   start, end,
			   flags & BIT(0) ? '0' : ' ',
			   flags & BIT(1) ? '1' : ' ',
			   flags & BIT(2) ? '2' : ' ',
			   flags & BIT(3) ? '3' : ' ',
			   erase_mask & BIT(0) ? '0' : ' ',
			   erase_mask & BIT(1) ? '1' : ' ',
			   erase_mask & BIT(2) ? '2' : ' ',
			   erase_mask & BIT(3) ? '3' : ' ',
			   flags & SNOR_OVERLAID_REGION ? "overlaid" : "");
	}

+13 −17
Original line number Diff line number Diff line
@@ -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)
{
	struct spi_nor_erase_region *region = map->regions;
	u8 region_erase_mask, sorted_erase_mask;
	u8 sorted_erase_mask;

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

		sorted_erase_mask = spi_nor_sort_erase_mask(map,
							    region_erase_mask);
							    region->erase_mask);

		/* Overwrite erase mask. */
		region->offset = (region->offset & ~SNOR_ERASE_TYPE_MASK) |
				 sorted_erase_mask;
		region->erase_mask = sorted_erase_mask;

		region = spi_nor_region_next(region);
	}
@@ -554,8 +551,6 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor,
	 * selecting the uniform erase.
	 */
	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. */
	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,

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)
{
	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,
	/* Populate regions. */
	for (i = 0; i < region_count; i++) {
		j = i + 1; /* index for the region dword */
		region[i].offset = offset;
		region[i].size = SMPT_MAP_REGION_SIZE(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);

@@ -893,13 +889,13 @@ static int spi_nor_init_non_uniform_erase_map(struct spi_nor *nor,
		 */
		regions_erase_type |= erase_type;

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

	save_uniform_erase_type = map->uniform_erase_type;
	map->uniform_erase_type = spi_nor_sort_erase_mask(map,
	save_uniform_erase_type = map->uniform_region.erase_mask;
	map->uniform_region.erase_mask =
				spi_nor_sort_erase_mask(map,
							uniform_erase_type);

	if (!regions_erase_type) {
@@ -907,7 +903,7 @@ static int spi_nor_init_non_uniform_erase_map(struct spi_nor *nor,
		 * Roll back to the previous uniform_erase_type mask, SMPT is
		 * broken.
		 */
		map->uniform_erase_type = save_uniform_erase_type;
		map->uniform_region.erase_mask = save_uniform_erase_type;
		return -EINVAL;
	}