From: Cyrille Pitchen <[email protected]>
Add support for SFDP (JESD216B) 4-byte Address Instruction Table. This
table is optional but when available, we parse it to get the 4-byte
address op codes supported by the memory.
Using these op codes is stateless as opposed to entering the 4-byte
address mode or setting the Base Address Register (BAR).
Flashes that have the 4BAIT table declared can now support
SPINOR_OP_PP_1_1_4_4B and SPINOR_OP_PP_1_4_4_4B opcodes.
Tested on MX25L25673G.
Signed-off-by: Cyrille Pitchen <[email protected]>
[[email protected]:
- rework erase and page program logic,
- pass DMA-able buffer to spi_nor_read_sfdp(),
- various minor updates.]
Signed-off-by: Tudor Ambarus <[email protected]>
---
Depends on spi_nor_sort_erase_mask() defined in
"[PATCH v2] mtd: spi-nor: fix selection of uniform erase type in flexible conf".
drivers/mtd/spi-nor/spi-nor.c | 189 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 189 insertions(+)
diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index 4c7e4dc25006..3495557b4948 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -2268,6 +2268,7 @@ struct sfdp_parameter_header {
#define SFDP_BFPT_ID 0xff00 /* Basic Flash Parameter Table */
#define SFDP_SECTOR_MAP_ID 0xff81 /* Sector Map Table */
+#define SFDP_4BAIT_ID 0xff84 /* 4-byte Address Instruction Table */
#define SFDP_SIGNATURE 0x50444653U
#define SFDP_JESD216_MAJOR 1
@@ -3101,6 +3102,190 @@ static int spi_nor_parse_smpt(struct spi_nor *nor,
return ret;
}
+#define SFDP_4BAIT_DWORD_MAX 2
+
+struct sfdp_4bait {
+ /* The hardware capability. */
+ u32 hwcaps;
+
+ /*
+ * The <supported_bit> bit in DWORD1 of the 4BAIT tells us whether
+ * the associated 4-byte address op code is supported.
+ */
+ u32 supported_bit;
+};
+
+/**
+ * spi_nor_parse_4bait() - parse the 4-Byte Address Instruction Table
+ * @nor: pointer to a 'struct spi_nor'.
+ * @param_header: pointer to the 'struct sfdp_parameter_header' describing
+ * the 4-Byte Address Instruction Table length and version.
+ * @params: pointer to the 'struct spi_nor_flash_parameter' to be.
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int spi_nor_parse_4bait(struct spi_nor *nor,
+ const struct sfdp_parameter_header *param_header,
+ struct spi_nor_flash_parameter *params)
+{
+ static const struct sfdp_4bait reads[] = {
+ { SNOR_HWCAPS_READ, BIT(0) },
+ { SNOR_HWCAPS_READ_FAST, BIT(1) },
+ { SNOR_HWCAPS_READ_1_1_2, BIT(2) },
+ { SNOR_HWCAPS_READ_1_2_2, BIT(3) },
+ { SNOR_HWCAPS_READ_1_1_4, BIT(4) },
+ { SNOR_HWCAPS_READ_1_4_4, BIT(5) },
+ { SNOR_HWCAPS_READ_1_1_1_DTR, BIT(13) },
+ { SNOR_HWCAPS_READ_1_2_2_DTR, BIT(14) },
+ { SNOR_HWCAPS_READ_1_4_4_DTR, BIT(15) },
+ };
+ static const struct sfdp_4bait programs[] = {
+ { SNOR_HWCAPS_PP, BIT(6) },
+ { SNOR_HWCAPS_PP_1_1_4, BIT(7) },
+ { SNOR_HWCAPS_PP_1_4_4, BIT(8) },
+ };
+ static const struct sfdp_4bait erases[SNOR_ERASE_TYPE_MAX] = {
+ { 0u /* not used */, BIT(9) },
+ { 0u /* not used */, BIT(10) },
+ { 0u /* not used */, BIT(11) },
+ { 0u /* not used */, BIT(12) },
+ };
+ struct spi_nor_pp_command *params_pp = params->page_programs;
+ struct spi_nor_erase_map *map = &nor->erase_map;
+ struct spi_nor_erase_type *erase_type = map->erase_type;
+ u32 *dwords;
+ size_t len;
+ u32 addr, discard_hwcaps, read_hwcaps, pp_hwcaps, erase_mask;
+ int i, ret;
+
+ if (param_header->major != SFDP_JESD216_MAJOR ||
+ param_header->length < SFDP_4BAIT_DWORD_MAX)
+ return -EINVAL;
+
+ /* Read the 4-byte Address Instruction Table. */
+ len = sizeof(*dwords) * SFDP_4BAIT_DWORD_MAX;
+
+ /* Use a kmalloc'ed bounce buffer to guarantee it is DMA-able. */
+ dwords = kmalloc(len, GFP_KERNEL);
+ if (!dwords)
+ return -ENOMEM;
+
+ addr = SFDP_PARAM_HEADER_PTP(param_header);
+ ret = spi_nor_read_sfdp(nor, addr, len, dwords);
+ if (ret)
+ return ret;
+
+ /* Fix endianness of the 4BAIT DWORDs. */
+ for (i = 0; i < SFDP_4BAIT_DWORD_MAX; i++)
+ dwords[i] = le32_to_cpu(dwords[i]);
+
+ /*
+ * Compute the subset of (Fast) Read commands for which the 4-byte
+ * version is supported.
+ */
+ discard_hwcaps = 0;
+ read_hwcaps = 0;
+ for (i = 0; i < ARRAY_SIZE(reads); i++) {
+ const struct sfdp_4bait *read = &reads[i];
+
+ discard_hwcaps |= read->hwcaps;
+ if ((params->hwcaps.mask & read->hwcaps) &&
+ (dwords[0] & read->supported_bit))
+ read_hwcaps |= read->hwcaps;
+ }
+
+ /*
+ * Compute the subset of Page Program commands for which the 4-byte
+ * version is supported.
+ */
+ pp_hwcaps = 0;
+ for (i = 0; i < ARRAY_SIZE(programs); i++) {
+ const struct sfdp_4bait *program = &programs[i];
+
+ /*
+ * The 4 Byte Address Instruction (Optional) Table is the only
+ * SFDP table that indicates support for Page Program Commands.
+ * Bypass the params->hwcaps.mask and consider 4BAIT the biggest
+ * authority for specifying Page Program support.
+ */
+ discard_hwcaps |= program->hwcaps;
+ if (dwords[0] & program->supported_bit)
+ pp_hwcaps |= program->hwcaps;
+ }
+
+ /*
+ * Compute the subset of Sector Erase commands for which the 4-byte
+ * version is supported.
+ */
+ erase_mask = 0;
+ for (i = 0; i < SNOR_ERASE_TYPE_MAX; i++) {
+ const struct sfdp_4bait *erase = &erases[i];
+
+ if (dwords[0] & erase->supported_bit)
+ erase_mask |= BIT(i);
+ }
+
+ /* Replicate the sort done for the map's erase types in BFPT. */
+ erase_mask = spi_nor_sort_erase_mask(map, erase_mask);
+
+ /*
+ * We need at least one 4-byte op code per read, program and erase
+ * operation; the .read(), .write() and .erase() hooks share the
+ * nor->addr_width value.
+ */
+ if (!read_hwcaps || !pp_hwcaps || !erase_mask)
+ goto out;
+
+ /*
+ * Discard all operations from the 4-byte instruction set which are
+ * not supported by this memory.
+ */
+ params->hwcaps.mask &= ~discard_hwcaps;
+ params->hwcaps.mask |= (read_hwcaps | pp_hwcaps);
+
+ /* Use the 4-byte address instruction set. */
+ for (i = 0; i < SNOR_CMD_READ_MAX; i++) {
+ struct spi_nor_read_command *read_cmd = ¶ms->reads[i];
+
+ read_cmd->opcode = spi_nor_convert_3to4_read(read_cmd->opcode);
+ }
+
+ /* 4BAIT is the only SFDP table that indicates page program support. */
+ if (pp_hwcaps & SNOR_HWCAPS_PP)
+ spi_nor_set_pp_settings(¶ms_pp[SNOR_CMD_PP],
+ SPINOR_OP_PP_4B, SNOR_PROTO_1_1_1);
+ if (pp_hwcaps & SNOR_HWCAPS_PP_1_1_4)
+ spi_nor_set_pp_settings(¶ms_pp[SNOR_CMD_PP_1_1_4],
+ SPINOR_OP_PP_1_1_4_4B,
+ SNOR_PROTO_1_1_4);
+ if (pp_hwcaps & SNOR_HWCAPS_PP_1_4_4)
+ spi_nor_set_pp_settings(¶ms_pp[SNOR_CMD_PP_1_4_4],
+ SPINOR_OP_PP_1_4_4_4B,
+ SNOR_PROTO_1_4_4);
+
+ for (i = 0; i < SNOR_ERASE_TYPE_MAX; i++) {
+ if (erase_mask & BIT(i))
+ erase_type[i].opcode = (dwords[1] >>
+ erase_type[i].idx * 8) & 0xFF;
+ else
+ spi_nor_set_erase_type(&erase_type[i], 0u, 0xFF);
+ }
+
+ /*
+ * We set nor->addr_width here to skip spi_nor_set_4byte_opcodes()
+ * later because this latest function implements a legacy quirk for
+ * the erase size of Spansion memory. However this quirk is no longer
+ * needed with new SFDP compliant memories.
+ */
+ nor->addr_width = 4;
+ nor->flags |= SPI_NOR_4B_OPCODES;
+
+ /* fall through */
+out:
+ kfree(dwords);
+ return ret;
+}
+
/**
* spi_nor_parse_sfdp() - parse the Serial Flash Discoverable Parameters.
* @nor: pointer to a 'struct spi_nor'
@@ -3198,6 +3383,10 @@ static int spi_nor_parse_sfdp(struct spi_nor *nor,
err = spi_nor_parse_smpt(nor, param_header);
break;
+ case SFDP_4BAIT_ID:
+ err = spi_nor_parse_4bait(nor, param_header, params);
+ break;
+
default:
break;
}
--
2.9.4
Hi Cyrille,
Thank you for the patch! Yet something to improve:
[auto build test ERROR on mtd/spi-nor/next]
[also build test ERROR on v4.20-rc3 next-20181120]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
url: https://github.com/0day-ci/linux/commits/Tudor-Ambarus-microchip-com/mtd-spi-nor-parse-SFDP-4-byte-Address-Instruction-Table/20181120-223821
base: git://git.infradead.org/linux-mtd.git spi-nor/next
config: i386-randconfig-x005-201846 (attached as .config)
compiler: gcc-7 (Debian 7.3.0-1) 7.3.0
reproduce:
# save the attached .config to linux build tree
make ARCH=i386
All errors (new ones prefixed by >>):
drivers/mtd//spi-nor/spi-nor.c: In function 'spi_nor_parse_4bait':
>> drivers/mtd//spi-nor/spi-nor.c:3165:15: error: implicit declaration of function 'spi_nor_sort_erase_mask'; did you mean 'spi_nor_set_erase_type'? [-Werror=implicit-function-declaration]
erase_mask = spi_nor_sort_erase_mask(map, erase_mask);
^~~~~~~~~~~~~~~~~~~~~~~
spi_nor_set_erase_type
Cyclomatic Complexity 5 include/linux/compiler.h:__write_once_size
Cyclomatic Complexity 1 include/linux/err.h:ERR_PTR
Cyclomatic Complexity 1 include/linux/err.h:PTR_ERR
Cyclomatic Complexity 1 arch/x86/include/asm/bitops.h:ffs
Cyclomatic Complexity 1 arch/x86/include/asm/bitops.h:fls
Cyclomatic Complexity 2 include/asm-generic/bitops/fls64.h:fls64
Cyclomatic Complexity 1 arch/x86/include/asm/arch_hweight.h:__arch_hweight32
Cyclomatic Complexity 1 include/linux/log2.h:__ilog2_u32
Cyclomatic Complexity 1 include/linux/log2.h:__ilog2_u64
Cyclomatic Complexity 3 include/linux/log2.h:is_power_of_2
Cyclomatic Complexity 1 include/linux/list.h:INIT_LIST_HEAD
Cyclomatic Complexity 1 include/linux/list.h:__list_add_valid
Cyclomatic Complexity 1 include/linux/list.h:__list_del_entry_valid
Cyclomatic Complexity 2 include/linux/list.h:__list_add
Cyclomatic Complexity 1 include/linux/list.h:list_add_tail
Cyclomatic Complexity 1 include/linux/list.h:__list_del
Cyclomatic Complexity 2 include/linux/list.h:__list_del_entry
Cyclomatic Complexity 1 include/linux/list.h:list_del
Cyclomatic Complexity 2 arch/x86/include/asm/div64.h:div_u64_rem
Cyclomatic Complexity 1 include/asm-generic/getorder.h:__get_order
Cyclomatic Complexity 1 include/linux/kobject.h:kobject_name
Cyclomatic Complexity 2 include/linux/device.h:dev_name
Cyclomatic Complexity 1 include/linux/device.h:dev_of_node
Cyclomatic Complexity 67 include/linux/slab.h:kmalloc_large
Cyclomatic Complexity 3 include/linux/slab.h:kmalloc
Cyclomatic Complexity 1 include/linux/mtd/mtd.h:mtd_get_of_node
Cyclomatic Complexity 1 include/linux/mtd/spi-nor.h:spi_nor_get_protocol_data_nbits
Cyclomatic Complexity 1 include/linux/mtd/spi-nor.h:spi_nor_get_protocol_width
Cyclomatic Complexity 1 include/linux/mtd/spi-nor.h:spi_nor_region_is_last
Cyclomatic Complexity 1 include/linux/mtd/spi-nor.h:spi_nor_region_end
Cyclomatic Complexity 1 include/linux/mtd/spi-nor.h:spi_nor_region_mark_end
Cyclomatic Complexity 1 include/linux/mtd/spi-nor.h:spi_nor_region_mark_overlay
Cyclomatic Complexity 1 include/linux/mtd/spi-nor.h:spi_nor_has_uniform_erase
Cyclomatic Complexity 1 include/linux/mtd/spi-nor.h:spi_nor_get_flash_node
Cyclomatic Complexity 1 drivers/mtd//spi-nor/spi-nor.c:write_sr
Cyclomatic Complexity 1 drivers/mtd//spi-nor/spi-nor.c:write_enable
Cyclomatic Complexity 1 drivers/mtd//spi-nor/spi-nor.c:write_disable
Cyclomatic Complexity 1 drivers/mtd//spi-nor/spi-nor.c:mtd_to_spi_nor
Cyclomatic Complexity 3 drivers/mtd//spi-nor/spi-nor.c:spi_nor_convert_opcode
Cyclomatic Complexity 1 drivers/mtd//spi-nor/spi-nor.c:spi_nor_convert_3to4_read
Cyclomatic Complexity 1 drivers/mtd//spi-nor/spi-nor.c:spi_nor_convert_3to4_program
Cyclomatic Complexity 1 drivers/mtd//spi-nor/spi-nor.c:spi_nor_convert_3to4_erase
Cyclomatic Complexity 4 drivers/mtd//spi-nor/spi-nor.c:spi_nor_set_4byte_opcodes
Cyclomatic Complexity 8 drivers/mtd//spi-nor/spi-nor.c:set_4byte
Cyclomatic Complexity 1 drivers/mtd//spi-nor/spi-nor.c:erase_chip
Cyclomatic Complexity 2 drivers/mtd//spi-nor/spi-nor.c:spi_nor_s3an_addr_convert
Cyclomatic Complexity 4 drivers/mtd//spi-nor/spi-nor.c:spi_nor_erase_sector
Cyclomatic Complexity 1 drivers/mtd//spi-nor/spi-nor.c:spi_nor_div_by_erase_size
Cyclomatic Complexity 6 drivers/mtd//spi-nor/spi-nor.c:spi_nor_find_best_erase_type
Cyclomatic Complexity 2 drivers/mtd//spi-nor/spi-nor.c:spi_nor_region_next
Cyclomatic Complexity 3 drivers/mtd//spi-nor/spi-nor.c:spi_nor_find_erase_region
Cyclomatic Complexity 3 drivers/mtd//spi-nor/spi-nor.c:spi_nor_init_erase_cmd
Cyclomatic Complexity 4 drivers/mtd//spi-nor/spi-nor.c:stm_get_locked_range
Cyclomatic Complexity 7 drivers/mtd//spi-nor/spi-nor.c:stm_check_lock_status_sr
Cyclomatic Complexity 1 drivers/mtd//spi-nor/spi-nor.c:stm_is_locked_sr
Cyclomatic Complexity 1 drivers/mtd//spi-nor/spi-nor.c:stm_is_unlocked_sr
Cyclomatic Complexity 1 drivers/mtd//spi-nor/spi-nor.c:spi_nor_set_read_settings
Cyclomatic Complexity 1 drivers/mtd//spi-nor/spi-nor.c:spi_nor_set_pp_settings
Cyclomatic Complexity 4 drivers/mtd//spi-nor/spi-nor.c:spi_nor_read_raw
Cyclomatic Complexity 1 drivers/mtd//spi-nor/spi-nor.c:spi_nor_read_sfdp
Cyclomatic Complexity 1 drivers/mtd//spi-nor/spi-nor.c:spi_nor_set_read_settings_from_bfpt
Cyclomatic Complexity 1 drivers/mtd//spi-nor/spi-nor.c:spi_nor_set_erase_type
Cyclomatic Complexity 1 drivers/mtd//spi-nor/spi-nor.c:spi_nor_set_erase_settings_from_bfpt
Cyclomatic Complexity 1 drivers/mtd//spi-nor/spi-nor.c:spi_nor_map_cmp_erase_type
Cyclomatic Complexity 5 drivers/mtd//spi-nor/spi-nor.c:spi_nor_regions_sort_erase_types
Cyclomatic Complexity 1 drivers/mtd//spi-nor/spi-nor.c:spi_nor_init_uniform_erase_map
Cyclomatic Complexity 4 drivers/mtd//spi-nor/spi-nor.c:spi_nor_smpt_addr_width
Cyclomatic Complexity 2 drivers/mtd//spi-nor/spi-nor.c:spi_nor_smpt_read_dummy
Cyclomatic Complexity 5 drivers/mtd//spi-nor/spi-nor.c:spi_nor_get_map_in_use
Cyclomatic Complexity 4 drivers/mtd//spi-nor/spi-nor.c:spi_nor_region_check_overlay
Cyclomatic Complexity 3 drivers/mtd//spi-nor/spi-nor.c:spi_nor_hwcaps2cmd
Cyclomatic Complexity 1 drivers/mtd//spi-nor/spi-nor.c:spi_nor_hwcaps_read2cmd
Cyclomatic Complexity 1 drivers/mtd//spi-nor/spi-nor.c:spi_nor_hwcaps_pp2cmd
Cyclomatic Complexity 3 drivers/mtd//spi-nor/spi-nor.c:spi_nor_select_read
Cyclomatic Complexity 3 drivers/mtd//spi-nor/spi-nor.c:spi_nor_select_pp
Cyclomatic Complexity 7 drivers/mtd//spi-nor/spi-nor.c:spi_nor_select_uniform_erase
Cyclomatic Complexity 6 drivers/mtd//spi-nor/spi-nor.c:spi_nor_select_erase
Cyclomatic Complexity 2 drivers/mtd//spi-nor/spi-nor.c:s3an_sr_ready
Cyclomatic Complexity 2 drivers/mtd//spi-nor/spi-nor.c:read_cr
Cyclomatic Complexity 9 drivers/mtd//spi-nor/spi-nor.c:spi_nor_setup
Cyclomatic Complexity 4 drivers/mtd//spi-nor/spi-nor.c:s3an_nor_scan
Cyclomatic Complexity 65 include/linux/log2.h:__order_base_2
Cyclomatic Complexity 3 drivers/mtd//spi-nor/spi-nor.c:spi_nor_lock_and_prep
Cyclomatic Complexity 2 drivers/mtd//spi-nor/spi-nor.c:spi_nor_unlock_and_unprep
Cyclomatic Complexity 2 drivers/mtd//spi-nor/spi-nor.c:spi_nor_is_locked
Cyclomatic Complexity 2 drivers/mtd//spi-nor/spi-nor.c:spi_nor_unlock
Cyclomatic Complexity 2 drivers/mtd//spi-nor/spi-nor.c:spi_nor_lock
Cyclomatic Complexity 2 drivers/mtd//spi-nor/spi-nor.c:read_sr
Cyclomatic Complexity 5 drivers/mtd//spi-nor/spi-nor.c:spi_nor_sr_ready
Cyclomatic Complexity 2 drivers/mtd//spi-nor/spi-nor.c:stm_is_locked
Cyclomatic Complexity 2 drivers/mtd//spi-nor/spi-nor.c:read_fsr
Cyclomatic Complexity 5 drivers/mtd//spi-nor/spi-nor.c:spi_nor_fsr_ready
Cyclomatic Complexity 5 drivers/mtd//spi-nor/spi-nor.c:spi_nor_ready
Cyclomatic Complexity 7 drivers/mtd//spi-nor/spi-nor.c:spi_nor_wait_till_ready_with_timeout
Cyclomatic Complexity 1 drivers/mtd//spi-nor/spi-nor.c:spi_nor_wait_till_ready
Cyclomatic Complexity 74 drivers/mtd//spi-nor/spi-nor.c:spi_nor_write
Cyclomatic Complexity 5 drivers/mtd//spi-nor/spi-nor.c:write_sr_and_check
vim +3165 drivers/mtd//spi-nor/spi-nor.c
3053
3054 /**
3055 * spi_nor_parse_4bait() - parse the 4-Byte Address Instruction Table
3056 * @nor: pointer to a 'struct spi_nor'.
3057 * @param_header: pointer to the 'struct sfdp_parameter_header' describing
3058 * the 4-Byte Address Instruction Table length and version.
3059 * @params: pointer to the 'struct spi_nor_flash_parameter' to be.
3060 *
3061 * Return: 0 on success, -errno otherwise.
3062 */
3063 static int spi_nor_parse_4bait(struct spi_nor *nor,
3064 const struct sfdp_parameter_header *param_header,
3065 struct spi_nor_flash_parameter *params)
3066 {
3067 static const struct sfdp_4bait reads[] = {
3068 { SNOR_HWCAPS_READ, BIT(0) },
3069 { SNOR_HWCAPS_READ_FAST, BIT(1) },
3070 { SNOR_HWCAPS_READ_1_1_2, BIT(2) },
3071 { SNOR_HWCAPS_READ_1_2_2, BIT(3) },
3072 { SNOR_HWCAPS_READ_1_1_4, BIT(4) },
3073 { SNOR_HWCAPS_READ_1_4_4, BIT(5) },
3074 { SNOR_HWCAPS_READ_1_1_1_DTR, BIT(13) },
3075 { SNOR_HWCAPS_READ_1_2_2_DTR, BIT(14) },
3076 { SNOR_HWCAPS_READ_1_4_4_DTR, BIT(15) },
3077 };
3078 static const struct sfdp_4bait programs[] = {
3079 { SNOR_HWCAPS_PP, BIT(6) },
3080 { SNOR_HWCAPS_PP_1_1_4, BIT(7) },
3081 { SNOR_HWCAPS_PP_1_4_4, BIT(8) },
3082 };
3083 static const struct sfdp_4bait erases[SNOR_ERASE_TYPE_MAX] = {
3084 { 0u /* not used */, BIT(9) },
3085 { 0u /* not used */, BIT(10) },
3086 { 0u /* not used */, BIT(11) },
3087 { 0u /* not used */, BIT(12) },
3088 };
3089 struct spi_nor_pp_command *params_pp = params->page_programs;
3090 struct spi_nor_erase_map *map = &nor->erase_map;
3091 struct spi_nor_erase_type *erase_type = map->erase_type;
3092 u32 *dwords;
3093 size_t len;
3094 u32 addr, discard_hwcaps, read_hwcaps, pp_hwcaps, erase_mask;
3095 int i, ret;
3096
3097 if (param_header->major != SFDP_JESD216_MAJOR ||
3098 param_header->length < SFDP_4BAIT_DWORD_MAX)
3099 return -EINVAL;
3100
3101 /* Read the 4-byte Address Instruction Table. */
3102 len = sizeof(*dwords) * SFDP_4BAIT_DWORD_MAX;
3103
3104 /* Use a kmalloc'ed bounce buffer to guarantee it is DMA-able. */
3105 dwords = kmalloc(len, GFP_KERNEL);
3106 if (!dwords)
3107 return -ENOMEM;
3108
3109 addr = SFDP_PARAM_HEADER_PTP(param_header);
3110 ret = spi_nor_read_sfdp(nor, addr, len, dwords);
3111 if (ret)
3112 return ret;
3113
3114 /* Fix endianness of the 4BAIT DWORDs. */
3115 for (i = 0; i < SFDP_4BAIT_DWORD_MAX; i++)
3116 dwords[i] = le32_to_cpu(dwords[i]);
3117
3118 /*
3119 * Compute the subset of (Fast) Read commands for which the 4-byte
3120 * version is supported.
3121 */
3122 discard_hwcaps = 0;
3123 read_hwcaps = 0;
3124 for (i = 0; i < ARRAY_SIZE(reads); i++) {
3125 const struct sfdp_4bait *read = &reads[i];
3126
3127 discard_hwcaps |= read->hwcaps;
3128 if ((params->hwcaps.mask & read->hwcaps) &&
3129 (dwords[0] & read->supported_bit))
3130 read_hwcaps |= read->hwcaps;
3131 }
3132
3133 /*
3134 * Compute the subset of Page Program commands for which the 4-byte
3135 * version is supported.
3136 */
3137 pp_hwcaps = 0;
3138 for (i = 0; i < ARRAY_SIZE(programs); i++) {
3139 const struct sfdp_4bait *program = &programs[i];
3140
3141 /*
3142 * The 4 Byte Address Instruction (Optional) Table is the only
3143 * SFDP table that indicates support for Page Program Commands.
3144 * Bypass the params->hwcaps.mask and consider 4BAIT the biggest
3145 * authority for specifying Page Program support.
3146 */
3147 discard_hwcaps |= program->hwcaps;
3148 if (dwords[0] & program->supported_bit)
3149 pp_hwcaps |= program->hwcaps;
3150 }
3151
3152 /*
3153 * Compute the subset of Sector Erase commands for which the 4-byte
3154 * version is supported.
3155 */
3156 erase_mask = 0;
3157 for (i = 0; i < SNOR_ERASE_TYPE_MAX; i++) {
3158 const struct sfdp_4bait *erase = &erases[i];
3159
3160 if (dwords[0] & erase->supported_bit)
3161 erase_mask |= BIT(i);
3162 }
3163
3164 /* Replicate the sort done for the map's erase types in BFPT. */
> 3165 erase_mask = spi_nor_sort_erase_mask(map, erase_mask);
3166
3167 /*
3168 * We need at least one 4-byte op code per read, program and erase
3169 * operation; the .read(), .write() and .erase() hooks share the
3170 * nor->addr_width value.
3171 */
3172 if (!read_hwcaps || !pp_hwcaps || !erase_mask)
3173 goto out;
3174
3175 /*
3176 * Discard all operations from the 4-byte instruction set which are
3177 * not supported by this memory.
3178 */
3179 params->hwcaps.mask &= ~discard_hwcaps;
3180 params->hwcaps.mask |= (read_hwcaps | pp_hwcaps);
3181
3182 /* Use the 4-byte address instruction set. */
3183 for (i = 0; i < SNOR_CMD_READ_MAX; i++) {
3184 struct spi_nor_read_command *read_cmd = ¶ms->reads[i];
3185
3186 read_cmd->opcode = spi_nor_convert_3to4_read(read_cmd->opcode);
3187 }
3188
3189 /* 4BAIT is the only SFDP table that indicates page program support. */
3190 if (pp_hwcaps & SNOR_HWCAPS_PP)
3191 spi_nor_set_pp_settings(¶ms_pp[SNOR_CMD_PP],
3192 SPINOR_OP_PP_4B, SNOR_PROTO_1_1_1);
3193 if (pp_hwcaps & SNOR_HWCAPS_PP_1_1_4)
3194 spi_nor_set_pp_settings(¶ms_pp[SNOR_CMD_PP_1_1_4],
3195 SPINOR_OP_PP_1_1_4_4B,
3196 SNOR_PROTO_1_1_4);
3197 if (pp_hwcaps & SNOR_HWCAPS_PP_1_4_4)
3198 spi_nor_set_pp_settings(¶ms_pp[SNOR_CMD_PP_1_4_4],
3199 SPINOR_OP_PP_1_4_4_4B,
3200 SNOR_PROTO_1_4_4);
3201
3202 for (i = 0; i < SNOR_ERASE_TYPE_MAX; i++) {
3203 if (erase_mask & BIT(i))
3204 erase_type[i].opcode = (dwords[1] >>
3205 erase_type[i].idx * 8) & 0xFF;
3206 else
3207 spi_nor_set_erase_type(&erase_type[i], 0u, 0xFF);
3208 }
3209
3210 /*
3211 * We set nor->addr_width here to skip spi_nor_set_4byte_opcodes()
3212 * later because this latest function implements a legacy quirk for
3213 * the erase size of Spansion memory. However this quirk is no longer
3214 * needed with new SFDP compliant memories.
3215 */
3216 nor->addr_width = 4;
3217 nor->flags |= SPI_NOR_4B_OPCODES;
3218
3219 /* fall through */
3220 out:
3221 kfree(dwords);
3222 return ret;
3223 }
3224
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
On 11/20/2018 05:35 PM, kbuild test robot wrote:
> Hi Cyrille,
>
> Thank you for the patch! Yet something to improve:
>
> [auto build test ERROR on mtd/spi-nor/next]
> [also build test ERROR on v4.20-rc3 next-20181120]
> [if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
>
> url: https://github.com/0day-ci/linux/commits/Tudor-Ambarus-microchip-com/mtd-spi-nor-parse-SFDP-4-byte-Address-Instruction-Table/20181120-223821
> base: git://git.infradead.org/linux-mtd.git spi-nor/next
> config: i386-randconfig-x005-201846 (attached as .config)
> compiler: gcc-7 (Debian 7.3.0-1) 7.3.0
> reproduce:
> # save the attached .config to linux build tree
> make ARCH=i386
>
> All errors (new ones prefixed by >>):
>
> drivers/mtd//spi-nor/spi-nor.c: In function 'spi_nor_parse_4bait':
>>> drivers/mtd//spi-nor/spi-nor.c:3165:15: error: implicit declaration of function 'spi_nor_sort_erase_mask'; did you mean 'spi_nor_set_erase_type'? [-Werror=implicit-function-declaration]
> erase_mask = spi_nor_sort_erase_mask(map, erase_mask);
> ^~~~~~~~~~~~~~~~~~~~~~~
That's fine. I already specified that this patch depends on the
spi_nor_sort_erase_mask() function introduced in
https://patchwork.ozlabs.org/patch/999105/
Thanks!
ta
Hi Cyrille,
Thank you for the patch! Yet something to improve:
[auto build test ERROR on mtd/spi-nor/next]
[also build test ERROR on v4.20-rc3 next-20181120]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
url: https://github.com/0day-ci/linux/commits/Tudor-Ambarus-microchip-com/mtd-spi-nor-parse-SFDP-4-byte-Address-Instruction-Table/20181120-223821
base: git://git.infradead.org/linux-mtd.git spi-nor/next
config: nds32-allyesconfig (attached as .config)
compiler: nds32le-linux-gcc (GCC) 6.4.0
reproduce:
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
GCC_VERSION=6.4.0 make.cross ARCH=nds32
All errors (new ones prefixed by >>):
drivers/mtd//spi-nor/spi-nor.c: In function 'spi_nor_parse_4bait':
>> drivers/mtd//spi-nor/spi-nor.c:3165:15: error: implicit declaration of function 'spi_nor_sort_erase_mask' [-Werror=implicit-function-declaration]
erase_mask = spi_nor_sort_erase_mask(map, erase_mask);
^~~~~~~~~~~~~~~~~~~~~~~
cc1: some warnings being treated as errors
vim +/spi_nor_sort_erase_mask +3165 drivers/mtd//spi-nor/spi-nor.c
3053
3054 /**
3055 * spi_nor_parse_4bait() - parse the 4-Byte Address Instruction Table
3056 * @nor: pointer to a 'struct spi_nor'.
3057 * @param_header: pointer to the 'struct sfdp_parameter_header' describing
3058 * the 4-Byte Address Instruction Table length and version.
3059 * @params: pointer to the 'struct spi_nor_flash_parameter' to be.
3060 *
3061 * Return: 0 on success, -errno otherwise.
3062 */
3063 static int spi_nor_parse_4bait(struct spi_nor *nor,
3064 const struct sfdp_parameter_header *param_header,
3065 struct spi_nor_flash_parameter *params)
3066 {
3067 static const struct sfdp_4bait reads[] = {
3068 { SNOR_HWCAPS_READ, BIT(0) },
3069 { SNOR_HWCAPS_READ_FAST, BIT(1) },
3070 { SNOR_HWCAPS_READ_1_1_2, BIT(2) },
3071 { SNOR_HWCAPS_READ_1_2_2, BIT(3) },
3072 { SNOR_HWCAPS_READ_1_1_4, BIT(4) },
3073 { SNOR_HWCAPS_READ_1_4_4, BIT(5) },
3074 { SNOR_HWCAPS_READ_1_1_1_DTR, BIT(13) },
3075 { SNOR_HWCAPS_READ_1_2_2_DTR, BIT(14) },
3076 { SNOR_HWCAPS_READ_1_4_4_DTR, BIT(15) },
3077 };
3078 static const struct sfdp_4bait programs[] = {
3079 { SNOR_HWCAPS_PP, BIT(6) },
3080 { SNOR_HWCAPS_PP_1_1_4, BIT(7) },
3081 { SNOR_HWCAPS_PP_1_4_4, BIT(8) },
3082 };
3083 static const struct sfdp_4bait erases[SNOR_ERASE_TYPE_MAX] = {
3084 { 0u /* not used */, BIT(9) },
3085 { 0u /* not used */, BIT(10) },
3086 { 0u /* not used */, BIT(11) },
3087 { 0u /* not used */, BIT(12) },
3088 };
3089 struct spi_nor_pp_command *params_pp = params->page_programs;
3090 struct spi_nor_erase_map *map = &nor->erase_map;
3091 struct spi_nor_erase_type *erase_type = map->erase_type;
3092 u32 *dwords;
3093 size_t len;
3094 u32 addr, discard_hwcaps, read_hwcaps, pp_hwcaps, erase_mask;
3095 int i, ret;
3096
3097 if (param_header->major != SFDP_JESD216_MAJOR ||
3098 param_header->length < SFDP_4BAIT_DWORD_MAX)
3099 return -EINVAL;
3100
3101 /* Read the 4-byte Address Instruction Table. */
3102 len = sizeof(*dwords) * SFDP_4BAIT_DWORD_MAX;
3103
3104 /* Use a kmalloc'ed bounce buffer to guarantee it is DMA-able. */
3105 dwords = kmalloc(len, GFP_KERNEL);
3106 if (!dwords)
3107 return -ENOMEM;
3108
3109 addr = SFDP_PARAM_HEADER_PTP(param_header);
3110 ret = spi_nor_read_sfdp(nor, addr, len, dwords);
3111 if (ret)
3112 return ret;
3113
3114 /* Fix endianness of the 4BAIT DWORDs. */
3115 for (i = 0; i < SFDP_4BAIT_DWORD_MAX; i++)
3116 dwords[i] = le32_to_cpu(dwords[i]);
3117
3118 /*
3119 * Compute the subset of (Fast) Read commands for which the 4-byte
3120 * version is supported.
3121 */
3122 discard_hwcaps = 0;
3123 read_hwcaps = 0;
3124 for (i = 0; i < ARRAY_SIZE(reads); i++) {
3125 const struct sfdp_4bait *read = &reads[i];
3126
3127 discard_hwcaps |= read->hwcaps;
3128 if ((params->hwcaps.mask & read->hwcaps) &&
3129 (dwords[0] & read->supported_bit))
3130 read_hwcaps |= read->hwcaps;
3131 }
3132
3133 /*
3134 * Compute the subset of Page Program commands for which the 4-byte
3135 * version is supported.
3136 */
3137 pp_hwcaps = 0;
3138 for (i = 0; i < ARRAY_SIZE(programs); i++) {
3139 const struct sfdp_4bait *program = &programs[i];
3140
3141 /*
3142 * The 4 Byte Address Instruction (Optional) Table is the only
3143 * SFDP table that indicates support for Page Program Commands.
3144 * Bypass the params->hwcaps.mask and consider 4BAIT the biggest
3145 * authority for specifying Page Program support.
3146 */
3147 discard_hwcaps |= program->hwcaps;
3148 if (dwords[0] & program->supported_bit)
3149 pp_hwcaps |= program->hwcaps;
3150 }
3151
3152 /*
3153 * Compute the subset of Sector Erase commands for which the 4-byte
3154 * version is supported.
3155 */
3156 erase_mask = 0;
3157 for (i = 0; i < SNOR_ERASE_TYPE_MAX; i++) {
3158 const struct sfdp_4bait *erase = &erases[i];
3159
3160 if (dwords[0] & erase->supported_bit)
3161 erase_mask |= BIT(i);
3162 }
3163
3164 /* Replicate the sort done for the map's erase types in BFPT. */
> 3165 erase_mask = spi_nor_sort_erase_mask(map, erase_mask);
3166
3167 /*
3168 * We need at least one 4-byte op code per read, program and erase
3169 * operation; the .read(), .write() and .erase() hooks share the
3170 * nor->addr_width value.
3171 */
3172 if (!read_hwcaps || !pp_hwcaps || !erase_mask)
3173 goto out;
3174
3175 /*
3176 * Discard all operations from the 4-byte instruction set which are
3177 * not supported by this memory.
3178 */
3179 params->hwcaps.mask &= ~discard_hwcaps;
3180 params->hwcaps.mask |= (read_hwcaps | pp_hwcaps);
3181
3182 /* Use the 4-byte address instruction set. */
3183 for (i = 0; i < SNOR_CMD_READ_MAX; i++) {
3184 struct spi_nor_read_command *read_cmd = ¶ms->reads[i];
3185
3186 read_cmd->opcode = spi_nor_convert_3to4_read(read_cmd->opcode);
3187 }
3188
3189 /* 4BAIT is the only SFDP table that indicates page program support. */
3190 if (pp_hwcaps & SNOR_HWCAPS_PP)
3191 spi_nor_set_pp_settings(¶ms_pp[SNOR_CMD_PP],
3192 SPINOR_OP_PP_4B, SNOR_PROTO_1_1_1);
3193 if (pp_hwcaps & SNOR_HWCAPS_PP_1_1_4)
3194 spi_nor_set_pp_settings(¶ms_pp[SNOR_CMD_PP_1_1_4],
3195 SPINOR_OP_PP_1_1_4_4B,
3196 SNOR_PROTO_1_1_4);
3197 if (pp_hwcaps & SNOR_HWCAPS_PP_1_4_4)
3198 spi_nor_set_pp_settings(¶ms_pp[SNOR_CMD_PP_1_4_4],
3199 SPINOR_OP_PP_1_4_4_4B,
3200 SNOR_PROTO_1_4_4);
3201
3202 for (i = 0; i < SNOR_ERASE_TYPE_MAX; i++) {
3203 if (erase_mask & BIT(i))
3204 erase_type[i].opcode = (dwords[1] >>
3205 erase_type[i].idx * 8) & 0xFF;
3206 else
3207 spi_nor_set_erase_type(&erase_type[i], 0u, 0xFF);
3208 }
3209
3210 /*
3211 * We set nor->addr_width here to skip spi_nor_set_4byte_opcodes()
3212 * later because this latest function implements a legacy quirk for
3213 * the erase size of Spansion memory. However this quirk is no longer
3214 * needed with new SFDP compliant memories.
3215 */
3216 nor->addr_width = 4;
3217 nor->flags |= SPI_NOR_4B_OPCODES;
3218
3219 /* fall through */
3220 out:
3221 kfree(dwords);
3222 return ret;
3223 }
3224
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
On Tue, 20 Nov 2018 11:55:21 +0000
<[email protected]> wrote:
> +
> + /*
> + * We set nor->addr_width here to skip spi_nor_set_4byte_opcodes()
> + * later because this latest function implements a legacy quirk for
> + * the erase size of Spansion memory. However this quirk is no longer
> + * needed with new SFDP compliant memories.
> + */
> + nor->addr_width = 4;
> + nor->flags |= SPI_NOR_4B_OPCODES;
You mean SNOR_F_4B_OPCODES (the one introduced here [1]), because
SPI_NOR_4B_OPCODES should only be used for flash_info->flags and might
soon conflict with another SNOR_F_ flag?
[1]http://patchwork.ozlabs.org/patch/991476/
On 11/28/2018 09:57 AM, Boris Brezillon wrote:
> On Tue, 20 Nov 2018 11:55:21 +0000
> <[email protected]> wrote:
>
>> +
>> + /*
>> + * We set nor->addr_width here to skip spi_nor_set_4byte_opcodes()
>> + * later because this latest function implements a legacy quirk for
>> + * the erase size of Spansion memory. However this quirk is no longer
>> + * needed with new SFDP compliant memories.
>> + */
>> + nor->addr_width = 4;
>> + nor->flags |= SPI_NOR_4B_OPCODES;
>
> You mean SNOR_F_4B_OPCODES (the one introduced here [1]), because
> SPI_NOR_4B_OPCODES should only be used for flash_info->flags and might
> soon conflict with another SNOR_F_ flag?
>
yes, you're right.
> [1]http://patchwork.ozlabs.org/patch/991476/
>
Can you apply your patch? Will submit a new version afterwards.
Thanks,
ta
On Wed, 28 Nov 2018 14:17:12 +0000
<[email protected]> wrote:
> On 11/28/2018 09:57 AM, Boris Brezillon wrote:
> > On Tue, 20 Nov 2018 11:55:21 +0000
> > <[email protected]> wrote:
> >
> >> +
> >> + /*
> >> + * We set nor->addr_width here to skip spi_nor_set_4byte_opcodes()
> >> + * later because this latest function implements a legacy quirk for
> >> + * the erase size of Spansion memory. However this quirk is no longer
> >> + * needed with new SFDP compliant memories.
> >> + */
> >> + nor->addr_width = 4;
> >> + nor->flags |= SPI_NOR_4B_OPCODES;
> >
> > You mean SNOR_F_4B_OPCODES (the one introduced here [1]), because
> > SPI_NOR_4B_OPCODES should only be used for flash_info->flags and might
> > soon conflict with another SNOR_F_ flag?
> >
>
> yes, you're right.
>
> > [1]http://patchwork.ozlabs.org/patch/991476/
> >
>
> Can you apply your patch? Will submit a new version afterwards.
Actually, I realized setting SNOR_F_4B_OPCODES when the BFPT advertises
4_BYTES_ONLY is incorrect as 4bytes only can mean "use the 3B opcodes
but pass address on 4 bytes". Here is a new version of this patch [1].
Feel free to pick it up and send it along with your "SFDP 4-byte Address
Instruction Table" patch (I have not reason to send it alone since the
problem I was trying to solve is no longer fixed by [1]).
[1]https://github.com/bbrezillon/linux-0day/commit/a953b6b435ec67bca00d6666f472db5f6dca4f63