Message ID | 20181120115512.15958-1-tudor.ambarus@microchip.com |
---|---|
State | Changes Requested |
Delegated to: | Boris Brezillon |
Headers | show |
Series | mtd: spi-nor: parse SFDP 4-byte Address Instruction Table | expand |
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 <Tudor.Ambarus@microchip.com> 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 > <Tudor.Ambarus@microchip.com> 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 <Tudor.Ambarus@microchip.com> wrote: > On 11/28/2018 09:57 AM, Boris Brezillon wrote: > > On Tue, 20 Nov 2018 11:55:21 +0000 > > <Tudor.Ambarus@microchip.com> 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
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; }