[{"id":1758914,"web_url":"http://patchwork.ozlabs.org/comment/1758914/","msgid":"<20170829004549.3a936874@bbrezillon>","list_archive_url":null,"date":"2017-08-28T22:45:49","subject":"Re: [PATCH v7] mtd: sharpslpart: Add sharpslpart partition parser","submitter":{"id":63120,"url":"http://patchwork.ozlabs.org/api/people/63120/","name":"Boris Brezillon","email":"boris.brezillon@free-electrons.com"},"content":"On Tue, 29 Aug 2017 00:20:32 +0200\nAndrea Adami <andrea.adami@gmail.com> wrote:\n\n> The Sharp SL Series (Zaurus) PXA handhelds have 16/64/128M of NAND flash\n> and share the same layout of the first 7M partition, managed by Sharp FTL.\n> \n> GPL 2.4 sources: http://support.ezaurus.com/developer/source/source_dl.asp\n> \n> The purpose of this self-contained patch is to add a common parser and\n> remove the hardcoded sizes in the board files (these devices are not yet\n> converted to devicetree).\n> Users will have benefits because the mtdparts= tag will not be necessary\n> anymore and they will be free to repartition the little sized flash.\n> \n> The obsolete bootloader can not pass the partitioning info to modern\n> kernels anymore so it has to be read from flash at known logical addresses.\n> (see http://www.h5.dion.ne.jp/~rimemoon/zaurus/memo_006.htm )\n> \n> In kernel, under arch/arm/mach-pxa we have already 8 machines:\n> MACH_POODLE, MACH_CORGI, MACH_SHEPERD, MACH_HUSKY, MACH_AKITA, MACH_SPITZ,\n> MACH_BORZOI, MACH_TOSA.\n> Lost after the 2.4 vendor kernel are MACH_BOXER and MACH_TERRIER.\n> \n> Almost every model has different factory partitioning: add to this the\n> units can be repartitioned by users with userspace tools (nandlogical)\n> and installers for popular (back then) linux distributions.\n> \n> The Parameter Area in the first (boot) partition extends from 0x00040000 to\n> 0x0007bfff (176k) and contains two copies of the partition table:\n> ...\n> 0x00060000: Partition Info1     16k\n> 0x00064000: Partition Info2     16k\n> 0x00668000: Model               16k\n> ...\n> \n> The first 7M partition is managed by the Sharp FTL reserving 5% + 1 blocks\n> for wear-leveling: some blocks are remapped and one layer of translation\n> (logical to physical) is necessary.\n> \n> There isn't much documentation about this FTL in the 2.4 sources, just the\n> MTD methods for reading and writing using logical addresses and the block\n> management (wear-leveling, use counter).\n> It seems this FTL was tailored with 16KiB eraesize in mind so to fit one\n> param block exactly, to have two copies of the partition table on two\n> blocks.\n> Later pxa27x devices have same size but 128KiB erasesize and less blocks\n> (56 vs. 448) but the same schema was adopted, even if the two tables are\n> now in the same eraseblock.\n> \n> For the purpose of the MTD parser only the read part of the code was taken.\n> \n> The NAND drivers that can use this parser are sharpsl.c and tmio_nand.c.\n> \n\nA few nitpicks below. Once fixed you can add\n\nReviewed-by: Boris Brezillon <boris.brezillon@free-electrons.com>\n\n> Changelog:\n> v1 firt version, initial import of 2.4 sources\n> v2 refactor applying many suggested fixes\n> v3 put the partition parser types in the platform data\n> v4 refactor after ML review\n> v5 fix commit messages and texts, remove global, fixes after v4 review\n> v6 refactor memory mgmt passing pointer to the FTL, fixes after v5 review\n> v7 verify the oob are free for the FTL, renamings, fixes after v6 review\n\nThe changelog should not be part of the commit message...\n\n> \n> Signed-off-by: Andrea Adami <andrea.adami@gmail.com>\n> ---\n\n... it should be go here (after the --- separator) so that when we apply\nthe patch it goes away.\n\n>  drivers/mtd/parsers/Kconfig       |   8 +\n>  drivers/mtd/parsers/Makefile      |   1 +\n>  drivers/mtd/parsers/sharpslpart.c | 399 ++++++++++++++++++++++++++++++++++++++\n>  3 files changed, 408 insertions(+)\n>  create mode 100644 drivers/mtd/parsers/sharpslpart.c\n> \n> diff --git a/drivers/mtd/parsers/Kconfig b/drivers/mtd/parsers/Kconfig\n> index d206b3c..ee5ab99 100644\n> --- a/drivers/mtd/parsers/Kconfig\n> +++ b/drivers/mtd/parsers/Kconfig\n> @@ -6,3 +6,11 @@ config MTD_PARSER_TRX\n>  \t  may contain up to 3/4 partitions (depending on the version).\n>  \t  This driver will parse TRX header and report at least two partitions:\n>  \t  kernel and rootfs.\n> +\n> +config MTD_SHARPSL_PARTS\n> +\ttristate \"Sharp SL Series NAND flash partition parser\"\n> +\tdepends on MTD_NAND_SHARPSL || MTD_NAND_TMIO || COMPILE_TEST\n> +\thelp\n> +\t  This provides the read-only FTL logic necessary to read the partition\n> +\t  table from the NAND flash of Sharp SL Series (Zaurus) and the MTD\n> +\t  partition parser using this code.\n> diff --git a/drivers/mtd/parsers/Makefile b/drivers/mtd/parsers/Makefile\n> index 4d9024e..5b1bcc3 100644\n> --- a/drivers/mtd/parsers/Makefile\n> +++ b/drivers/mtd/parsers/Makefile\n> @@ -1 +1,2 @@\n>  obj-$(CONFIG_MTD_PARSER_TRX)\t\t+= parser_trx.o\n> +obj-$(CONFIG_MTD_SHARPSL_PARTS)\t\t+= sharpslpart.o\n> diff --git a/drivers/mtd/parsers/sharpslpart.c b/drivers/mtd/parsers/sharpslpart.c\n> new file mode 100644\n> index 0000000..5fddeba\n> --- /dev/null\n> +++ b/drivers/mtd/parsers/sharpslpart.c\n> @@ -0,0 +1,399 @@\n> +/*\n> + * sharpslpart.c - MTD partition parser for NAND flash using the SHARP FTL\n> + * for logical addressing, as used on the PXA models of the SHARP SL Series.\n> + *\n> + * Copyright (C) 2017 Andrea Adami <andrea.adami@gmail.com>\n> + *\n> + * Based on SHARP GPL 2.4 sources:\n> + *   http://support.ezaurus.com/developer/source/source_dl.asp\n> + *     drivers/mtd/nand/sharp_sl_logical.c\n> + *     linux/include/asm-arm/sharp_nand_logical.h\n> + *\n> + * Copyright (C) 2002 SHARP\n> + *\n> + * This program is free software; you can redistribute it and/or modify\n> + * it under the terms of the GNU General Public License as published by\n> + * the Free Software Foundation; either version 2 of the License, or\n> + * (at your option) any later version.\n> + *\n> + * This program is distributed in the hope that it will be useful,\n> + * but WITHOUT ANY WARRANTY; without even the implied warranty of\n> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n> + * GNU General Public License for more details.\n> + *\n> + */\n> +\n> +#include <linux/kernel.h>\n> +#include <linux/slab.h>\n> +#include <linux/module.h>\n> +#include <linux/types.h>\n> +#include <linux/bitops.h>\n> +#include <linux/mtd/mtd.h>\n> +#include <linux/mtd/partitions.h>\n> +\n> +/* oob structure */\n> +#define NAND_NOOB_LOGADDR_00\t\t8\n> +#define NAND_NOOB_LOGADDR_01\t\t9\n> +#define NAND_NOOB_LOGADDR_10\t\t10\n> +#define NAND_NOOB_LOGADDR_11\t\t11\n> +#define NAND_NOOB_LOGADDR_20\t\t12\n> +#define NAND_NOOB_LOGADDR_21\t\t13\n> +\n> +#define BLOCK_IS_RESERVED\t\t0xffff\n> +#define BLOCK_UNMASK_COMPLEMENT\t\t1\n> +\n> +/* factory defaults */\n> +#define SHARPSL_NAND_PARTS\t\t3\n> +#define SHARPSL_FTL_PART_SIZE\t\t(7 * SZ_1M)\n> +#define SHARPSL_PARTINFO1_LADDR\t\t0x00060000\n> +#define SHARPSL_PARTINFO2_LADDR\t\t0x00064000\n> +\n> +#define BOOT_MAGIC\t\t\t0x424f4f54\n> +#define FSRO_MAGIC\t\t\t0x4653524f\n> +#define FSRW_MAGIC\t\t\t0x46535257\n> +\n> +/**\n> + * struct sharpsl_ftl - Sharp FTL Logical Table\n> + * @logmax:\t\tnumber of logical blocks\n> + * @log2phy:\t\tthe logical-to-physical table\n> + *\n> + * Structure containing the logical-to-physical translation table\n> + * used by the SHARP SL FTL.\n> + */\n> +struct sharpsl_ftl {\n> +\tunsigned int logmax;\n> +\tunsigned int *log2phy;\n> +};\n> +\n> +static int sharpsl_nand_check_ooblayout(struct mtd_info *mtd)\n> +{\n> +\tu8 freebytes = 0;\n> +\tint section = 0;\n> +\n> +\twhile (true) {\n> +\t\tstruct mtd_oob_region oobfree = { };\n> +\t\tint ret, i;\n> +\n> +\t\tret = mtd_ooblayout_free(mtd, section++, &oobfree);\n> +\t\tif (ret)\n> +\t\t\tbreak;\n> +\n> +\t\tif (!oobfree.length || oobfree.offset > 15 ||\n> +\t\t    (oobfree.offset + oobfree.length) < 8)\n> +\t\t\tcontinue;\n> +\n> +\t\ti = oobfree.offset >= 8 ? oobfree.offset : 8;\n> +\t\tfor (; i < oobfree.offset + oobfree.length && i < 16; i++)\n> +\t\t\tfreebytes |= BIT(i - 8);\n> +\n> +\t\tif (freebytes == 0xff)\n> +\t\t\treturn 0;\n\nI think this function deserves a comment explaining what you're doing:\nchecking that bytes 8 to 15 of the OOB area are free.\n\n> +\t}\n> +\n> +\treturn -ENOTSUPP;\n> +}\n> +\n> +static int sharpsl_nand_read_oob(struct mtd_info *mtd, loff_t offs,\n> +\t\t\t\t uint8_t *buf)\n\n\t\t\t\t u8 *buf\n\n> +{\n> +\tstruct mtd_oob_ops ops = { };\n> +\tint ret;\n> +\n> +\tops.mode = MTD_OPS_PLACE_OOB;\n> +\tops.ooblen = mtd->oobsize;\n> +\tops.oobbuf = buf;\n> +\n> +\tret = mtd_read_oob(mtd, offs, &ops);\n> +\tif (ret != 0 || mtd->oobsize != ops.oobretlen)\n> +\t\treturn -1;\n> +\n> +\treturn 0;\n> +}\n> +\n> +/*\n> + * The logical block number assigned to a physical block is stored in the OOB\n> + * of the first page, in 3 16-bit copies with the following layout:\n> + *\n> + * 01234567 89abcdef\n> + * -------- --------\n> + * ECC BB   xyxyxy\n> + *\n> + * When reading we check that the first two copies agree.\n> + * In case of error, matching is tried using the following pairs.\n> + * Reserved values 0xffff mean the block is kept for wear leveling.\n> + *\n> + * 01234567 89abcdef\n> + * -------- --------\n> + * ECC BB   xyxy    oob[8]==oob[10] && oob[9]==oob[11]   -> byte0=8   byte1=9\n> + * ECC BB     xyxy  oob[10]==oob[12] && oob[11]==oob[13] -> byte0=10  byte1=11\n> + * ECC BB   xy  xy  oob[12]==oob[8] && oob[13]==oob[9]   -> byte0=12  byte1=13\n> + *\n\nThere's still an extra/unneeded blank line here.\n\n> + */\n> +static int sharpsl_nand_get_logical_num(u8 *oob)\n> +{\n> +\tu16 us;\n> +\tint good0, good1;\n> +\n> +\tif (oob[NAND_NOOB_LOGADDR_00] == oob[NAND_NOOB_LOGADDR_10] &&\n> +\t    oob[NAND_NOOB_LOGADDR_01] == oob[NAND_NOOB_LOGADDR_11]) {\n> +\t\tgood0 = NAND_NOOB_LOGADDR_00;\n> +\t\tgood1 = NAND_NOOB_LOGADDR_01;\n> +\t} else if (oob[NAND_NOOB_LOGADDR_10] == oob[NAND_NOOB_LOGADDR_20] &&\n> +\t\t   oob[NAND_NOOB_LOGADDR_11] == oob[NAND_NOOB_LOGADDR_21]) {\n> +\t\tgood0 = NAND_NOOB_LOGADDR_10;\n> +\t\tgood1 = NAND_NOOB_LOGADDR_11;\n> +\t} else if (oob[NAND_NOOB_LOGADDR_20] == oob[NAND_NOOB_LOGADDR_00] &&\n> +\t\t   oob[NAND_NOOB_LOGADDR_21] == oob[NAND_NOOB_LOGADDR_01]) {\n> +\t\tgood0 = NAND_NOOB_LOGADDR_20;\n> +\t\tgood1 = NAND_NOOB_LOGADDR_21;\n> +\t} else {\n> +\t\treturn -EINVAL;\n> +\t}\n> +\n> +\tus = oob[good0] | oob[good1] << 8;\n> +\n> +\t/* parity check */\n> +\tif (hweight16(us) & BLOCK_UNMASK_COMPLEMENT)\n> +\t\treturn -EINVAL;\n> +\n> +\t/* reserved */\n> +\tif (us == BLOCK_IS_RESERVED)\n> +\t\treturn BLOCK_IS_RESERVED;\n> +\n> +\treturn (us >> 1) & GENMASK(9, 0);\n> +}\n> +\n> +static int sharpsl_nand_init_ftl(struct mtd_info *mtd, struct sharpsl_ftl *ftl)\n> +{\n> +\tunsigned int block_num, log_num, phymax;\n> +\tloff_t block_adr;\n> +\tu8 *oob;\n> +\tint i, ret;\n> +\n> +\toob = kzalloc(mtd->oobsize, GFP_KERNEL);\n> +\tif (!oob)\n> +\t\treturn -ENOMEM;\n> +\n> +\tphymax = mtd_div_by_eb(SHARPSL_FTL_PART_SIZE, mtd);\n> +\n> +\t/* FTL reserves 5% of the blocks + 1 spare  */\n> +\tftl->logmax = ((phymax * 95) / 100) - 1;\n> +\n> +\tftl->log2phy = kmalloc_array(ftl->logmax, sizeof(*ftl->log2phy),\n> +\t\t\t\t     GFP_KERNEL);\n> +\tif (!ftl->log2phy) {\n> +\t\tret = -ENOMEM;\n> +\t\tgoto exit;\n> +\t}\n> +\n> +\t/* initialize ftl->log2phy */\n> +\tfor (i = 0; i < ftl->logmax; i++)\n> +\t\tftl->log2phy[i] = UINT_MAX;\n> +\n> +\t/* create physical-logical table */\n> +\tfor (block_num = 0; block_num < phymax; block_num++) {\n> +\t\tblock_adr = block_num * mtd->erasesize;\n> +\n> +\t\tif (mtd_block_isbad(mtd, block_adr))\n> +\t\t\tcontinue;\n> +\n> +\t\tif (sharpsl_nand_read_oob(mtd, block_adr, oob))\n> +\t\t\tcontinue;\n> +\n> +\t\t/* get logical block */\n> +\t\tlog_num = sharpsl_nand_get_logical_num(oob);\n> +\n> +\t\t/* cut-off errors and skip the out-of-range values */\n> +\t\tif (log_num > 0 && log_num < ftl->logmax) {\n> +\t\t\tif (ftl->log2phy[log_num] == UINT_MAX)\n> +\t\t\t\tftl->log2phy[log_num] = block_num;\n> +\t\t}\n> +\t}\n> +\n> +\tpr_info(\"Sharp SL FTL: %d blocks used (%d logical, %d reserved)\\n\",\n> +\t\tphymax, ftl->logmax, phymax - ftl->logmax);\n> +\n> +\tret = 0;\n> +exit:\n> +\tkfree(oob);\n> +\treturn ret;\n> +}\n> +\n> +void sharpsl_nand_cleanup_ftl(struct sharpsl_ftl *ftl)\n> +{\n> +\tkfree(ftl->log2phy);\n> +}\n> +\n> +static int sharpsl_nand_read_laddr(struct mtd_info *mtd,\n> +\t\t\t\t   loff_t from,\n> +\t\t\t\t   size_t len,\n> +\t\t\t\t   void *buf,\n> +\t\t\t\t   struct sharpsl_ftl *ftl)\n> +{\n> +\tunsigned int log_num, final_log_num;\n> +\tunsigned int block_num;\n> +\tloff_t block_adr;\n> +\tloff_t block_ofs;\n> +\tsize_t retlen;\n> +\tint err;\n> +\n> +\tlog_num = mtd_div_by_eb((u32)from, mtd);\n> +\tfinal_log_num = mtd_div_by_eb(((u32)from + len - 1), mtd);\n> +\n> +\tif (len <= 0 || log_num >= ftl->logmax || final_log_num > log_num)\n> +\t\treturn -EINVAL;\n> +\n> +\tblock_num = ftl->log2phy[log_num];\n> +\tblock_adr = block_num * mtd->erasesize;\n> +\tblock_ofs = mtd_mod_by_eb((u32)from, mtd);\n> +\n> +\terr = mtd_read(mtd, block_adr + block_ofs, len, &retlen, buf);\n> +\t/* Ignore corrected ECC errors */\n> +\tif (mtd_is_bitflip(err))\n> +\t\terr = 0;\n> +\n> +\tif (!err && retlen != len)\n> +\t\terr = -EIO;\n> +\n> +\tif (err)\n> +\t\tpr_err(\"sharpslpart: error, read failed at %#llx\\n\",\n> +\t\t       block_adr + block_ofs);\n> +\n> +\treturn err;\n> +}\n> +\n> +/*\n> + * MTD Partition Parser\n> + *\n> + * Sample values read from SL-C860\n> + *\n> + * # cat /proc/mtd\n> + * dev:    size   erasesize  name\n> + * mtd0: 006d0000 00020000 \"Filesystem\"\n> + * mtd1: 00700000 00004000 \"smf\"\n> + * mtd2: 03500000 00004000 \"root\"\n> + * mtd3: 04400000 00004000 \"home\"\n> + *\n> + * PARTITIONINFO1\n> + * 0x00060000: 00 00 00 00 00 00 70 00 42 4f 4f 54 00 00 00 00  ......p.BOOT....\n> + * 0x00060010: 00 00 70 00 00 00 c0 03 46 53 52 4f 00 00 00 00  ..p.....FSRO....\n> + * 0x00060020: 00 00 c0 03 00 00 00 04 46 53 52 57 00 00 00 00  ........FSRW....\n> + *\n\nDitto: remove the empty comment line from this comment.\n\n> + */\n> +struct sharpsl_nand_partinfo {\n> +\t__le32 start;\n> +\t__le32 end;\n> +\t__be32 magic;\n> +\tu32 reserved;\n> +};\n> +\n> +static int sharpsl_nand_read_partinfo(struct mtd_info *master,\n> +\t\t\t\t      loff_t from,\n> +\t\t\t\t      size_t len,\n> +\t\t\t\t      struct sharpsl_nand_partinfo *buf,\n> +\t\t\t\t      struct sharpsl_ftl *ftl)\n> +{\n> +\tint ret;\n> +\n> +\tret = sharpsl_nand_read_laddr(master, from, len, buf, ftl);\n> +\tif (ret)\n> +\t\treturn ret;\n> +\n> +\t/* check for magics */\n> +\tif (be32_to_cpu(buf[0].magic) != BOOT_MAGIC ||\n> +\t    be32_to_cpu(buf[1].magic) != FSRO_MAGIC ||\n> +\t    be32_to_cpu(buf[2].magic) != FSRW_MAGIC) {\n> +\t\tpr_err(\"sharpslpart: magic values mismatch\\n\");\n> +\t\treturn -EINVAL;\n> +\t}\n> +\n> +\t/* fixup for hardcoded value 64 MiB (for older models) */\n> +\tbuf[2].end = cpu_to_le32(master->size);\n> +\n> +\t/* extra sanity check */\n> +\tif (le32_to_cpu(buf[0].end) <= le32_to_cpu(buf[0].start) ||\n> +\t    le32_to_cpu(buf[1].start) < le32_to_cpu(buf[0].end) ||\n> +\t    le32_to_cpu(buf[1].end) <= le32_to_cpu(buf[1].start) ||\n> +\t    le32_to_cpu(buf[2].start) < le32_to_cpu(buf[1].end) ||\n> +\t    le32_to_cpu(buf[2].end) <= le32_to_cpu(buf[2].start)) {\n> +\t\tpr_err(\"sharpslpart: partition sizes mismatch\\n\");\n> +\t\treturn -EINVAL;\n> +\t}\n> +\n> +\treturn 0;\n> +}\n> +\n> +static int sharpsl_parse_mtd_partitions(struct mtd_info *master,\n> +\t\t\t\t\tconst struct mtd_partition **pparts,\n> +\t\t\t\t\tstruct mtd_part_parser_data *data)\n> +{\n> +\tstruct sharpsl_ftl ftl;\n> +\tstruct sharpsl_nand_partinfo buf[SHARPSL_NAND_PARTS];\n> +\tstruct mtd_partition *sharpsl_nand_parts;\n> +\tint err;\n> +\n> +\t/* check that OOB bytes 8 to 15 used by the FTL are actually free */\n> +\terr = sharpsl_nand_check_ooblayout(master);\n> +\tif (err)\n> +\t\treturn err;\n> +\n> +\t/* init logical mgmt (FTL) */\n> +\terr = sharpsl_nand_init_ftl(master, &ftl);\n> +\tif (err)\n> +\t\treturn err;\n> +\n> +\t/* read and validate first partition table */\n> +\tpr_info(\"sharpslpart: try reading first partition table\\n\");\n> +\terr = sharpsl_nand_read_partinfo(master,\n> +\t\t\t\t\t SHARPSL_PARTINFO1_LADDR,\n> +\t\t\t\t\t sizeof(buf), buf, &ftl);\n> +\tif (err) {\n> +\t\t/* fallback: read second partition table */\n> +\t\tpr_warn(\"sharpslpart: first partition table is invalid, retry using the second\\n\");\n> +\t\terr = sharpsl_nand_read_partinfo(master,\n> +\t\t\t\t\t\t SHARPSL_PARTINFO2_LADDR,\n> +\t\t\t\t\t\t sizeof(buf), buf, &ftl);\n> +\t}\n> +\n> +\t/* cleanup logical mgmt (FTL) */\n> +\tsharpsl_nand_cleanup_ftl(&ftl);\n> +\n> +\tif (err) {\n> +\t\tpr_err(\"sharpslpart: both partition tables are invalid\\n\");\n> +\t\treturn err;\n> +\t}\n> +\n> +\tsharpsl_nand_parts = kzalloc(sizeof(*sharpsl_nand_parts) *\n> +\t\t\t\t     SHARPSL_NAND_PARTS, GFP_KERNEL);\n> +\tif (!sharpsl_nand_parts)\n> +\t\treturn -ENOMEM;\n> +\n> +\t/* original names */\n> +\tsharpsl_nand_parts[0].name = \"smf\";\n> +\tsharpsl_nand_parts[0].offset = le32_to_cpu(buf[0].start);\n> +\tsharpsl_nand_parts[0].size = le32_to_cpu(buf[0].end) -\n> +\t\t\t\t     le32_to_cpu(buf[0].start);\n> +\n> +\tsharpsl_nand_parts[1].name = \"root\";\n> +\tsharpsl_nand_parts[1].offset = le32_to_cpu(buf[1].start);\n> +\tsharpsl_nand_parts[1].size = le32_to_cpu(buf[1].end) -\n> +\t\t\t\t     le32_to_cpu(buf[1].start);\n> +\n> +\tsharpsl_nand_parts[2].name = \"home\";\n> +\tsharpsl_nand_parts[2].offset = le32_to_cpu(buf[2].start);\n> +\tsharpsl_nand_parts[2].size = le32_to_cpu(buf[2].end) -\n> +\t\t\t\t     le32_to_cpu(buf[2].start);\n> +\n> +\t*pparts = sharpsl_nand_parts;\n> +\treturn SHARPSL_NAND_PARTS;\n> +}\n> +\n> +static struct mtd_part_parser sharpsl_mtd_parser = {\n> +\t.parse_fn = sharpsl_parse_mtd_partitions,\n> +\t.name = \"sharpslpart\",\n> +};\n> +module_mtd_part_parser(sharpsl_mtd_parser);\n> +\n> +MODULE_LICENSE(\"GPL\");\n> +MODULE_AUTHOR(\"Andrea Adami <andrea.adami@gmail.com>\");\n> +MODULE_DESCRIPTION(\"MTD partitioning for NAND flash on Sharp SL Series\");","headers":{"Return-Path":"<linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org>","X-Original-To":"incoming@patchwork.ozlabs.org","Delivered-To":"patchwork-incoming@bilbo.ozlabs.org","Authentication-Results":["ozlabs.org; spf=none (mailfrom)\n\tsmtp.mailfrom=lists.infradead.org (client-ip=65.50.211.133;\n\thelo=bombadil.infradead.org;\n\tenvelope-from=linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org;\n\treceiver=<UNKNOWN>)","ozlabs.org; dkim=pass (2048-bit key;\n\tunprotected) header.d=lists.infradead.org\n\theader.i=@lists.infradead.org header.b=\"AreJFHFv\"; \n\tdkim-atps=neutral"],"Received":["from bombadil.infradead.org (bombadil.infradead.org\n\t[65.50.211.133])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256\n\tbits)) (No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 3xh6MF63v8z9s7v\n\tfor <incoming@patchwork.ozlabs.org>;\n\tTue, 29 Aug 2017 08:46:33 +1000 (AEST)","from localhost ([127.0.0.1] helo=bombadil.infradead.org)\n\tby bombadil.infradead.org with esmtp (Exim 4.87 #1 (Red Hat Linux))\n\tid 1dmSnV-0001wX-Fu; Mon, 28 Aug 2017 22:46:21 +0000","from mail.free-electrons.com ([62.4.15.54])\n\tby bombadil.infradead.org with esmtp (Exim 4.87 #1 (Red Hat Linux))\n\tid 1dmSnO-0001tT-77\n\tfor linux-mtd@lists.infradead.org; Mon, 28 Aug 2017 22:46:19 +0000","by mail.free-electrons.com (Postfix, from userid 110)\n\tid 0BFC420986; Tue, 29 Aug 2017 00:45:50 +0200 (CEST)","from bbrezillon (91-160-177-164.subs.proxad.net [91.160.177.164])\n\tby mail.free-electrons.com (Postfix) with ESMTPSA id 822C12094D;\n\tTue, 29 Aug 2017 00:45:49 +0200 (CEST)"],"DKIM-Signature":"v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed;\n\td=lists.infradead.org; s=bombadil.20170209; h=Sender:\n\tContent-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post:\n\tList-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To:\n\tMessage-ID:Subject:To:From:Date:Reply-To:Content-ID:Content-Description:\n\tResent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:\n\tList-Owner; bh=7hjJNRBT6YfC1RyTM4LugTGdEIRU++I1VuTy5TAMwOo=;\n\tb=AreJFHFvXGm0hL\n\tMs8eUQ5ktjg+YIbIRStmh1bsglwGHSyPjskGLNW0SXfqfaU8i4j5lzlRvLAEk4YcHChq2ZqHkz5G/\n\tdqaFl9+i5IJNMbLtJNBiRaWLJmG5o53pSx7KKZqFTaMmVql5d9KxSqguVyWcqxDynRsmxrzdVVJLV\n\tAQieq4HJcDOjK0rcFS9s0FiU8Yf9B9uPIk0At3A1UhRH4pcxGvAcEQSA6TeKKOExfchY7Qe+Bq20C\n\tip7TiIX3p7CXRkCestLpcQ56y2ATa0Lx7u5M+Cs9o0HdGyFhtTWlbLShBfBcBDKilPxSeejzRYYKN\n\tL4mW37XDQQn8e1INgZKw==;","X-Spam-Checker-Version":"SpamAssassin 3.4.0 (2014-02-07) on\n\tmail.free-electrons.com","X-Spam-Level":"","X-Spam-Status":"No, score=-1.0 required=5.0 tests=ALL_TRUSTED,SHORTCIRCUIT\n\tshortcircuit=ham autolearn=disabled version=3.4.0","Date":"Tue, 29 Aug 2017 00:45:49 +0200","From":"Boris Brezillon <boris.brezillon@free-electrons.com>","To":"Andrea Adami <andrea.adami@gmail.com>","Subject":"Re: [PATCH v7] mtd: sharpslpart: Add sharpslpart partition parser","Message-ID":"<20170829004549.3a936874@bbrezillon>","In-Reply-To":"<1503958832-7525-1-git-send-email-andrea.adami@gmail.com>","References":"<1503958832-7525-1-git-send-email-andrea.adami@gmail.com>","X-Mailer":"Claws Mail 3.14.1 (GTK+ 2.24.31; x86_64-pc-linux-gnu)","MIME-Version":"1.0","X-CRM114-Version":"20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 ","X-CRM114-CacheID":"sfid-20170828_154614_660164_870D6F5C ","X-CRM114-Status":"GOOD (  42.43  )","X-Spam-Score":"-1.9 (-)","X-Spam-Report":"SpamAssassin version 3.4.1 on bombadil.infradead.org summary:\n\tContent analysis details:   (-1.9 points)\n\tpts rule name              description\n\t---- ----------------------\n\t--------------------------------------------------\n\t-0.0 SPF_PASS               SPF: sender matches SPF record\n\t-0.0 RP_MATCHES_RCVD Envelope sender domain matches handover relay\n\tdomain\n\t-1.9 BAYES_00               BODY: Bayes spam probability is 0 to 1%\n\t[score: 0.0000]","X-BeenThere":"linux-mtd@lists.infradead.org","X-Mailman-Version":"2.1.21","Precedence":"list","List-Id":"Linux MTD discussion mailing list <linux-mtd.lists.infradead.org>","List-Unsubscribe":"<http://lists.infradead.org/mailman/options/linux-mtd>,\n\t<mailto:linux-mtd-request@lists.infradead.org?subject=unsubscribe>","List-Archive":"<http://lists.infradead.org/pipermail/linux-mtd/>","List-Post":"<mailto:linux-mtd@lists.infradead.org>","List-Help":"<mailto:linux-mtd-request@lists.infradead.org?subject=help>","List-Subscribe":"<http://lists.infradead.org/mailman/listinfo/linux-mtd>,\n\t<mailto:linux-mtd-request@lists.infradead.org?subject=subscribe>","Cc":"Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>, Richard Weinberger\n\t<richard@nod.at>, Robert Jarzmik <robert.jarzmik@free.fr>, \n\tlinux-kernel@vger.kernel.org, Haojian Zhuang <haojian.zhuang@gmail.com>, \n\tMarek Vasut <marek.vasut@gmail.com>, linux-mtd@lists.infradead.org, \n\tCyrille Pitchen <cyrille.pitchen@wedev4u.fr>, \n\t=?utf-8?b?UmFmYcWCIE1pxYJlY2tp?= <rafal@milecki.pl>,\n\tBrian Norris <computersforpeace@gmail.com>, David Woodhouse\n\t<dwmw2@infradead.org>","Content-Type":"text/plain; charset=\"us-ascii\"","Content-Transfer-Encoding":"7bit","Sender":"\"linux-mtd\" <linux-mtd-bounces@lists.infradead.org>","Errors-To":"linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org"}},{"id":1758936,"web_url":"http://patchwork.ozlabs.org/comment/1758936/","msgid":"<CAAQYJAsRnL_QYMTthFgnAWeWMVCWLLeJK8XZZcyh=tOR_XT4iQ@mail.gmail.com>","list_archive_url":null,"date":"2017-08-28T23:42:02","subject":"Re: [PATCH v7] mtd: sharpslpart: Add sharpslpart partition parser","submitter":{"id":30311,"url":"http://patchwork.ozlabs.org/api/people/30311/","name":"Andrea Adami","email":"andrea.adami@gmail.com"},"content":"On Tue, Aug 29, 2017 at 12:45 AM, Boris Brezillon\n<boris.brezillon@free-electrons.com> wrote:\n> On Tue, 29 Aug 2017 00:20:32 +0200\n> Andrea Adami <andrea.adami@gmail.com> wrote:\n>\n>> The Sharp SL Series (Zaurus) PXA handhelds have 16/64/128M of NAND flash\n>> and share the same layout of the first 7M partition, managed by Sharp FTL.\n>>\n>> GPL 2.4 sources: http://support.ezaurus.com/developer/source/source_dl.asp\n>>\n>> The purpose of this self-contained patch is to add a common parser and\n>> remove the hardcoded sizes in the board files (these devices are not yet\n>> converted to devicetree).\n>> Users will have benefits because the mtdparts= tag will not be necessary\n>> anymore and they will be free to repartition the little sized flash.\n>>\n>> The obsolete bootloader can not pass the partitioning info to modern\n>> kernels anymore so it has to be read from flash at known logical addresses.\n>> (see http://www.h5.dion.ne.jp/~rimemoon/zaurus/memo_006.htm )\n>>\n>> In kernel, under arch/arm/mach-pxa we have already 8 machines:\n>> MACH_POODLE, MACH_CORGI, MACH_SHEPERD, MACH_HUSKY, MACH_AKITA, MACH_SPITZ,\n>> MACH_BORZOI, MACH_TOSA.\n>> Lost after the 2.4 vendor kernel are MACH_BOXER and MACH_TERRIER.\n>>\n>> Almost every model has different factory partitioning: add to this the\n>> units can be repartitioned by users with userspace tools (nandlogical)\n>> and installers for popular (back then) linux distributions.\n>>\n>> The Parameter Area in the first (boot) partition extends from 0x00040000 to\n>> 0x0007bfff (176k) and contains two copies of the partition table:\n>> ...\n>> 0x00060000: Partition Info1     16k\n>> 0x00064000: Partition Info2     16k\n>> 0x00668000: Model               16k\n>> ...\n>>\n>> The first 7M partition is managed by the Sharp FTL reserving 5% + 1 blocks\n>> for wear-leveling: some blocks are remapped and one layer of translation\n>> (logical to physical) is necessary.\n>>\n>> There isn't much documentation about this FTL in the 2.4 sources, just the\n>> MTD methods for reading and writing using logical addresses and the block\n>> management (wear-leveling, use counter).\n>> It seems this FTL was tailored with 16KiB eraesize in mind so to fit one\n>> param block exactly, to have two copies of the partition table on two\n>> blocks.\n>> Later pxa27x devices have same size but 128KiB erasesize and less blocks\n>> (56 vs. 448) but the same schema was adopted, even if the two tables are\n>> now in the same eraseblock.\n>>\n>> For the purpose of the MTD parser only the read part of the code was taken.\n>>\n>> The NAND drivers that can use this parser are sharpsl.c and tmio_nand.c.\n>>\n>\n> A few nitpicks below. Once fixed you can add\n>\n> Reviewed-by: Boris Brezillon <boris.brezillon@free-electrons.com>\n>\nThanks again for your help.\n\n>> Changelog:\n>> v1 firt version, initial import of 2.4 sources\n>> v2 refactor applying many suggested fixes\n>> v3 put the partition parser types in the platform data\n>> v4 refactor after ML review\n>> v5 fix commit messages and texts, remove global, fixes after v4 review\n>> v6 refactor memory mgmt passing pointer to the FTL, fixes after v5 review\n>> v7 verify the oob are free for the FTL, renamings, fixes after v6 review\n>\n> The changelog should not be part of the commit message...\n>\n>>\n>> Signed-off-by: Andrea Adami <andrea.adami@gmail.com>\n>> ---\n>\n> ... it should be go here (after the --- separator) so that when we apply\n> the patch it goes away.\n>\nSorry, I have copied it in the wrong line.\n\n>>  drivers/mtd/parsers/Kconfig       |   8 +\n>>  drivers/mtd/parsers/Makefile      |   1 +\n>>  drivers/mtd/parsers/sharpslpart.c | 399 ++++++++++++++++++++++++++++++++++++++\n>>  3 files changed, 408 insertions(+)\n>>  create mode 100644 drivers/mtd/parsers/sharpslpart.c\n>>\n>> diff --git a/drivers/mtd/parsers/Kconfig b/drivers/mtd/parsers/Kconfig\n>> index d206b3c..ee5ab99 100644\n>> --- a/drivers/mtd/parsers/Kconfig\n>> +++ b/drivers/mtd/parsers/Kconfig\n>> @@ -6,3 +6,11 @@ config MTD_PARSER_TRX\n>>         may contain up to 3/4 partitions (depending on the version).\n>>         This driver will parse TRX header and report at least two partitions:\n>>         kernel and rootfs.\n>> +\n>> +config MTD_SHARPSL_PARTS\n>> +     tristate \"Sharp SL Series NAND flash partition parser\"\n>> +     depends on MTD_NAND_SHARPSL || MTD_NAND_TMIO || COMPILE_TEST\n>> +     help\n>> +       This provides the read-only FTL logic necessary to read the partition\n>> +       table from the NAND flash of Sharp SL Series (Zaurus) and the MTD\n>> +       partition parser using this code.\n>> diff --git a/drivers/mtd/parsers/Makefile b/drivers/mtd/parsers/Makefile\n>> index 4d9024e..5b1bcc3 100644\n>> --- a/drivers/mtd/parsers/Makefile\n>> +++ b/drivers/mtd/parsers/Makefile\n>> @@ -1 +1,2 @@\n>>  obj-$(CONFIG_MTD_PARSER_TRX)         += parser_trx.o\n>> +obj-$(CONFIG_MTD_SHARPSL_PARTS)              += sharpslpart.o\n>> diff --git a/drivers/mtd/parsers/sharpslpart.c b/drivers/mtd/parsers/sharpslpart.c\n>> new file mode 100644\n>> index 0000000..5fddeba\n>> --- /dev/null\n>> +++ b/drivers/mtd/parsers/sharpslpart.c\n>> @@ -0,0 +1,399 @@\n>> +/*\n>> + * sharpslpart.c - MTD partition parser for NAND flash using the SHARP FTL\n>> + * for logical addressing, as used on the PXA models of the SHARP SL Series.\n>> + *\n>> + * Copyright (C) 2017 Andrea Adami <andrea.adami@gmail.com>\n>> + *\n>> + * Based on SHARP GPL 2.4 sources:\n>> + *   http://support.ezaurus.com/developer/source/source_dl.asp\n>> + *     drivers/mtd/nand/sharp_sl_logical.c\n>> + *     linux/include/asm-arm/sharp_nand_logical.h\n>> + *\n>> + * Copyright (C) 2002 SHARP\n>> + *\n>> + * This program is free software; you can redistribute it and/or modify\n>> + * it under the terms of the GNU General Public License as published by\n>> + * the Free Software Foundation; either version 2 of the License, or\n>> + * (at your option) any later version.\n>> + *\n>> + * This program is distributed in the hope that it will be useful,\n>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of\n>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n>> + * GNU General Public License for more details.\n>> + *\n>> + */\n>> +\n>> +#include <linux/kernel.h>\n>> +#include <linux/slab.h>\n>> +#include <linux/module.h>\n>> +#include <linux/types.h>\n>> +#include <linux/bitops.h>\n>> +#include <linux/mtd/mtd.h>\n>> +#include <linux/mtd/partitions.h>\n>> +\n>> +/* oob structure */\n>> +#define NAND_NOOB_LOGADDR_00         8\n>> +#define NAND_NOOB_LOGADDR_01         9\n>> +#define NAND_NOOB_LOGADDR_10         10\n>> +#define NAND_NOOB_LOGADDR_11         11\n>> +#define NAND_NOOB_LOGADDR_20         12\n>> +#define NAND_NOOB_LOGADDR_21         13\n>> +\n>> +#define BLOCK_IS_RESERVED            0xffff\n>> +#define BLOCK_UNMASK_COMPLEMENT              1\n>> +\n>> +/* factory defaults */\n>> +#define SHARPSL_NAND_PARTS           3\n>> +#define SHARPSL_FTL_PART_SIZE                (7 * SZ_1M)\n>> +#define SHARPSL_PARTINFO1_LADDR              0x00060000\n>> +#define SHARPSL_PARTINFO2_LADDR              0x00064000\n>> +\n>> +#define BOOT_MAGIC                   0x424f4f54\n>> +#define FSRO_MAGIC                   0x4653524f\n>> +#define FSRW_MAGIC                   0x46535257\n>> +\n>> +/**\n>> + * struct sharpsl_ftl - Sharp FTL Logical Table\n>> + * @logmax:          number of logical blocks\n>> + * @log2phy:         the logical-to-physical table\n>> + *\n>> + * Structure containing the logical-to-physical translation table\n>> + * used by the SHARP SL FTL.\n>> + */\n>> +struct sharpsl_ftl {\n>> +     unsigned int logmax;\n>> +     unsigned int *log2phy;\n>> +};\n>> +\n>> +static int sharpsl_nand_check_ooblayout(struct mtd_info *mtd)\n>> +{\n>> +     u8 freebytes = 0;\n>> +     int section = 0;\n>> +\n>> +     while (true) {\n>> +             struct mtd_oob_region oobfree = { };\n>> +             int ret, i;\n>> +\n>> +             ret = mtd_ooblayout_free(mtd, section++, &oobfree);\n>> +             if (ret)\n>> +                     break;\n>> +\n>> +             if (!oobfree.length || oobfree.offset > 15 ||\n>> +                 (oobfree.offset + oobfree.length) < 8)\n>> +                     continue;\n>> +\n>> +             i = oobfree.offset >= 8 ? oobfree.offset : 8;\n>> +             for (; i < oobfree.offset + oobfree.length && i < 16; i++)\n>> +                     freebytes |= BIT(i - 8);\n>> +\n>> +             if (freebytes == 0xff)\n>> +                     return 0;\n>\n> I think this function deserves a comment explaining what you're doing:\n> checking that bytes 8 to 15 of the OOB area are free.\n>\nAh, ok, I put the description down before the function call.\nI'll add a short text here as well.\n\n>> +     }\n>> +\n>> +     return -ENOTSUPP;\n>> +}\n>> +\n>> +static int sharpsl_nand_read_oob(struct mtd_info *mtd, loff_t offs,\n>> +                              uint8_t *buf)\n>\n>                                  u8 *buf\n>\nOk, replaced\n\n>> +{\n>> +     struct mtd_oob_ops ops = { };\n>> +     int ret;\n>> +\n>> +     ops.mode = MTD_OPS_PLACE_OOB;\n>> +     ops.ooblen = mtd->oobsize;\n>> +     ops.oobbuf = buf;\n>> +\n>> +     ret = mtd_read_oob(mtd, offs, &ops);\n>> +     if (ret != 0 || mtd->oobsize != ops.oobretlen)\n>> +             return -1;\n>> +\n>> +     return 0;\n>> +}\n>> +\n>> +/*\n>> + * The logical block number assigned to a physical block is stored in the OOB\n>> + * of the first page, in 3 16-bit copies with the following layout:\n>> + *\n>> + * 01234567 89abcdef\n>> + * -------- --------\n>> + * ECC BB   xyxyxy\n>> + *\n>> + * When reading we check that the first two copies agree.\n>> + * In case of error, matching is tried using the following pairs.\n>> + * Reserved values 0xffff mean the block is kept for wear leveling.\n>> + *\n>> + * 01234567 89abcdef\n>> + * -------- --------\n>> + * ECC BB   xyxy    oob[8]==oob[10] && oob[9]==oob[11]   -> byte0=8   byte1=9\n>> + * ECC BB     xyxy  oob[10]==oob[12] && oob[11]==oob[13] -> byte0=10  byte1=11\n>> + * ECC BB   xy  xy  oob[12]==oob[8] && oob[13]==oob[9]   -> byte0=12  byte1=13\n>> + *\n>\n> There's still an extra/unneeded blank line here.\n>\nRemoved\n\n>> + */\n>> +static int sharpsl_nand_get_logical_num(u8 *oob)\n>> +{\n>> +     u16 us;\n>> +     int good0, good1;\n>> +\n>> +     if (oob[NAND_NOOB_LOGADDR_00] == oob[NAND_NOOB_LOGADDR_10] &&\n>> +         oob[NAND_NOOB_LOGADDR_01] == oob[NAND_NOOB_LOGADDR_11]) {\n>> +             good0 = NAND_NOOB_LOGADDR_00;\n>> +             good1 = NAND_NOOB_LOGADDR_01;\n>> +     } else if (oob[NAND_NOOB_LOGADDR_10] == oob[NAND_NOOB_LOGADDR_20] &&\n>> +                oob[NAND_NOOB_LOGADDR_11] == oob[NAND_NOOB_LOGADDR_21]) {\n>> +             good0 = NAND_NOOB_LOGADDR_10;\n>> +             good1 = NAND_NOOB_LOGADDR_11;\n>> +     } else if (oob[NAND_NOOB_LOGADDR_20] == oob[NAND_NOOB_LOGADDR_00] &&\n>> +                oob[NAND_NOOB_LOGADDR_21] == oob[NAND_NOOB_LOGADDR_01]) {\n>> +             good0 = NAND_NOOB_LOGADDR_20;\n>> +             good1 = NAND_NOOB_LOGADDR_21;\n>> +     } else {\n>> +             return -EINVAL;\n>> +     }\n>> +\n>> +     us = oob[good0] | oob[good1] << 8;\n>> +\n>> +     /* parity check */\n>> +     if (hweight16(us) & BLOCK_UNMASK_COMPLEMENT)\n>> +             return -EINVAL;\n>> +\n>> +     /* reserved */\n>> +     if (us == BLOCK_IS_RESERVED)\n>> +             return BLOCK_IS_RESERVED;\n>> +\n>> +     return (us >> 1) & GENMASK(9, 0);\n>> +}\n>> +\n>> +static int sharpsl_nand_init_ftl(struct mtd_info *mtd, struct sharpsl_ftl *ftl)\n>> +{\n>> +     unsigned int block_num, log_num, phymax;\n>> +     loff_t block_adr;\n>> +     u8 *oob;\n>> +     int i, ret;\n>> +\n>> +     oob = kzalloc(mtd->oobsize, GFP_KERNEL);\n>> +     if (!oob)\n>> +             return -ENOMEM;\n>> +\n>> +     phymax = mtd_div_by_eb(SHARPSL_FTL_PART_SIZE, mtd);\n>> +\n>> +     /* FTL reserves 5% of the blocks + 1 spare  */\n>> +     ftl->logmax = ((phymax * 95) / 100) - 1;\n>> +\n>> +     ftl->log2phy = kmalloc_array(ftl->logmax, sizeof(*ftl->log2phy),\n>> +                                  GFP_KERNEL);\n>> +     if (!ftl->log2phy) {\n>> +             ret = -ENOMEM;\n>> +             goto exit;\n>> +     }\n>> +\n>> +     /* initialize ftl->log2phy */\n>> +     for (i = 0; i < ftl->logmax; i++)\n>> +             ftl->log2phy[i] = UINT_MAX;\n>> +\n>> +     /* create physical-logical table */\n>> +     for (block_num = 0; block_num < phymax; block_num++) {\n>> +             block_adr = block_num * mtd->erasesize;\n>> +\n>> +             if (mtd_block_isbad(mtd, block_adr))\n>> +                     continue;\n>> +\n>> +             if (sharpsl_nand_read_oob(mtd, block_adr, oob))\n>> +                     continue;\n>> +\n>> +             /* get logical block */\n>> +             log_num = sharpsl_nand_get_logical_num(oob);\n>> +\n>> +             /* cut-off errors and skip the out-of-range values */\n>> +             if (log_num > 0 && log_num < ftl->logmax) {\n>> +                     if (ftl->log2phy[log_num] == UINT_MAX)\n>> +                             ftl->log2phy[log_num] = block_num;\n>> +             }\n>> +     }\n>> +\n>> +     pr_info(\"Sharp SL FTL: %d blocks used (%d logical, %d reserved)\\n\",\n>> +             phymax, ftl->logmax, phymax - ftl->logmax);\n>> +\n>> +     ret = 0;\n>> +exit:\n>> +     kfree(oob);\n>> +     return ret;\n>> +}\n>> +\n>> +void sharpsl_nand_cleanup_ftl(struct sharpsl_ftl *ftl)\n>> +{\n>> +     kfree(ftl->log2phy);\n>> +}\n>> +\n>> +static int sharpsl_nand_read_laddr(struct mtd_info *mtd,\n>> +                                loff_t from,\n>> +                                size_t len,\n>> +                                void *buf,\n>> +                                struct sharpsl_ftl *ftl)\n>> +{\n>> +     unsigned int log_num, final_log_num;\n>> +     unsigned int block_num;\n>> +     loff_t block_adr;\n>> +     loff_t block_ofs;\n>> +     size_t retlen;\n>> +     int err;\n>> +\n>> +     log_num = mtd_div_by_eb((u32)from, mtd);\n>> +     final_log_num = mtd_div_by_eb(((u32)from + len - 1), mtd);\n>> +\n>> +     if (len <= 0 || log_num >= ftl->logmax || final_log_num > log_num)\n>> +             return -EINVAL;\n>> +\n>> +     block_num = ftl->log2phy[log_num];\n>> +     block_adr = block_num * mtd->erasesize;\n>> +     block_ofs = mtd_mod_by_eb((u32)from, mtd);\n>> +\n>> +     err = mtd_read(mtd, block_adr + block_ofs, len, &retlen, buf);\n>> +     /* Ignore corrected ECC errors */\n>> +     if (mtd_is_bitflip(err))\n>> +             err = 0;\n>> +\n>> +     if (!err && retlen != len)\n>> +             err = -EIO;\n>> +\n>> +     if (err)\n>> +             pr_err(\"sharpslpart: error, read failed at %#llx\\n\",\n>> +                    block_adr + block_ofs);\n>> +\n>> +     return err;\n>> +}\n>> +\n>> +/*\n>> + * MTD Partition Parser\n>> + *\n>> + * Sample values read from SL-C860\n>> + *\n>> + * # cat /proc/mtd\n>> + * dev:    size   erasesize  name\n>> + * mtd0: 006d0000 00020000 \"Filesystem\"\n>> + * mtd1: 00700000 00004000 \"smf\"\n>> + * mtd2: 03500000 00004000 \"root\"\n>> + * mtd3: 04400000 00004000 \"home\"\n>> + *\n>> + * PARTITIONINFO1\n>> + * 0x00060000: 00 00 00 00 00 00 70 00 42 4f 4f 54 00 00 00 00  ......p.BOOT....\n>> + * 0x00060010: 00 00 70 00 00 00 c0 03 46 53 52 4f 00 00 00 00  ..p.....FSRO....\n>> + * 0x00060020: 00 00 c0 03 00 00 00 04 46 53 52 57 00 00 00 00  ........FSRW....\n>> + *\n>\n> Ditto: remove the empty comment line from this comment.\n>\nRemoved\n\n>> + */\n>> +struct sharpsl_nand_partinfo {\n>> +     __le32 start;\n>> +     __le32 end;\n>> +     __be32 magic;\n>> +     u32 reserved;\n>> +};\n>> +\n>> +static int sharpsl_nand_read_partinfo(struct mtd_info *master,\n>> +                                   loff_t from,\n>> +                                   size_t len,\n>> +                                   struct sharpsl_nand_partinfo *buf,\n>> +                                   struct sharpsl_ftl *ftl)\n>> +{\n>> +     int ret;\n>> +\n>> +     ret = sharpsl_nand_read_laddr(master, from, len, buf, ftl);\n>> +     if (ret)\n>> +             return ret;\n>> +\n>> +     /* check for magics */\n>> +     if (be32_to_cpu(buf[0].magic) != BOOT_MAGIC ||\n>> +         be32_to_cpu(buf[1].magic) != FSRO_MAGIC ||\n>> +         be32_to_cpu(buf[2].magic) != FSRW_MAGIC) {\n>> +             pr_err(\"sharpslpart: magic values mismatch\\n\");\n>> +             return -EINVAL;\n>> +     }\n>> +\n>> +     /* fixup for hardcoded value 64 MiB (for older models) */\n>> +     buf[2].end = cpu_to_le32(master->size);\n>> +\n>> +     /* extra sanity check */\n>> +     if (le32_to_cpu(buf[0].end) <= le32_to_cpu(buf[0].start) ||\n>> +         le32_to_cpu(buf[1].start) < le32_to_cpu(buf[0].end) ||\n>> +         le32_to_cpu(buf[1].end) <= le32_to_cpu(buf[1].start) ||\n>> +         le32_to_cpu(buf[2].start) < le32_to_cpu(buf[1].end) ||\n>> +         le32_to_cpu(buf[2].end) <= le32_to_cpu(buf[2].start)) {\n>> +             pr_err(\"sharpslpart: partition sizes mismatch\\n\");\n>> +             return -EINVAL;\n>> +     }\n>> +\n>> +     return 0;\n>> +}\n>> +\n>> +static int sharpsl_parse_mtd_partitions(struct mtd_info *master,\n>> +                                     const struct mtd_partition **pparts,\n>> +                                     struct mtd_part_parser_data *data)\n>> +{\n>> +     struct sharpsl_ftl ftl;\n>> +     struct sharpsl_nand_partinfo buf[SHARPSL_NAND_PARTS];\n>> +     struct mtd_partition *sharpsl_nand_parts;\n>> +     int err;\n>> +\n>> +     /* check that OOB bytes 8 to 15 used by the FTL are actually free */\n>> +     err = sharpsl_nand_check_ooblayout(master);\n>> +     if (err)\n>> +             return err;\n>> +\n>> +     /* init logical mgmt (FTL) */\n>> +     err = sharpsl_nand_init_ftl(master, &ftl);\n>> +     if (err)\n>> +             return err;\n>> +\n>> +     /* read and validate first partition table */\n>> +     pr_info(\"sharpslpart: try reading first partition table\\n\");\n>> +     err = sharpsl_nand_read_partinfo(master,\n>> +                                      SHARPSL_PARTINFO1_LADDR,\n>> +                                      sizeof(buf), buf, &ftl);\n>> +     if (err) {\n>> +             /* fallback: read second partition table */\n>> +             pr_warn(\"sharpslpart: first partition table is invalid, retry using the second\\n\");\n>> +             err = sharpsl_nand_read_partinfo(master,\n>> +                                              SHARPSL_PARTINFO2_LADDR,\n>> +                                              sizeof(buf), buf, &ftl);\n>> +     }\n>> +\n>> +     /* cleanup logical mgmt (FTL) */\n>> +     sharpsl_nand_cleanup_ftl(&ftl);\n>> +\n>> +     if (err) {\n>> +             pr_err(\"sharpslpart: both partition tables are invalid\\n\");\n>> +             return err;\n>> +     }\n>> +\n>> +     sharpsl_nand_parts = kzalloc(sizeof(*sharpsl_nand_parts) *\n>> +                                  SHARPSL_NAND_PARTS, GFP_KERNEL);\n>> +     if (!sharpsl_nand_parts)\n>> +             return -ENOMEM;\n>> +\n>> +     /* original names */\n>> +     sharpsl_nand_parts[0].name = \"smf\";\n>> +     sharpsl_nand_parts[0].offset = le32_to_cpu(buf[0].start);\n>> +     sharpsl_nand_parts[0].size = le32_to_cpu(buf[0].end) -\n>> +                                  le32_to_cpu(buf[0].start);\n>> +\n>> +     sharpsl_nand_parts[1].name = \"root\";\n>> +     sharpsl_nand_parts[1].offset = le32_to_cpu(buf[1].start);\n>> +     sharpsl_nand_parts[1].size = le32_to_cpu(buf[1].end) -\n>> +                                  le32_to_cpu(buf[1].start);\n>> +\n>> +     sharpsl_nand_parts[2].name = \"home\";\n>> +     sharpsl_nand_parts[2].offset = le32_to_cpu(buf[2].start);\n>> +     sharpsl_nand_parts[2].size = le32_to_cpu(buf[2].end) -\n>> +                                  le32_to_cpu(buf[2].start);\n>> +\n>> +     *pparts = sharpsl_nand_parts;\n>> +     return SHARPSL_NAND_PARTS;\n>> +}\n>> +\n>> +static struct mtd_part_parser sharpsl_mtd_parser = {\n>> +     .parse_fn = sharpsl_parse_mtd_partitions,\n>> +     .name = \"sharpslpart\",\n>> +};\n>> +module_mtd_part_parser(sharpsl_mtd_parser);\n>> +\n>> +MODULE_LICENSE(\"GPL\");\n>> +MODULE_AUTHOR(\"Andrea Adami <andrea.adami@gmail.com>\");\n>> +MODULE_DESCRIPTION(\"MTD partitioning for NAND flash on Sharp SL Series\");\n>\nThanks, I'll send v8.\n\nRegards\nAndrea","headers":{"Return-Path":"<linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org>","X-Original-To":"incoming@patchwork.ozlabs.org","Delivered-To":"patchwork-incoming@bilbo.ozlabs.org","Authentication-Results":["ozlabs.org; spf=none (mailfrom)\n\tsmtp.mailfrom=lists.infradead.org (client-ip=65.50.211.133;\n\thelo=bombadil.infradead.org;\n\tenvelope-from=linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org;\n\treceiver=<UNKNOWN>)","ozlabs.org; dkim=pass (2048-bit key;\n\tunprotected) header.d=lists.infradead.org\n\theader.i=@lists.infradead.org header.b=\"jPaJmQNW\"; \n\tdkim=fail reason=\"signature verification failed\" (2048-bit key;\n\tunprotected) header.d=gmail.com header.i=@gmail.com\n\theader.b=\"fZ5WxVTO\"; dkim-atps=neutral"],"Received":["from bombadil.infradead.org (bombadil.infradead.org\n\t[65.50.211.133])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256\n\tbits)) (No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 3xh7c32F9zz9s1h\n\tfor <incoming@patchwork.ozlabs.org>;\n\tTue, 29 Aug 2017 09:42:43 +1000 (AEST)","from localhost ([127.0.0.1] helo=bombadil.infradead.org)\n\tby bombadil.infradead.org with esmtp (Exim 4.87 #1 (Red Hat Linux))\n\tid 1dmTfs-0007nG-LG; Mon, 28 Aug 2017 23:42:32 +0000","from mail-wm0-x244.google.com ([2a00:1450:400c:c09::244])\n\tby bombadil.infradead.org with esmtps (Exim 4.87 #1 (Red Hat Linux))\n\tid 1dmTfm-0007ib-F3\n\tfor linux-mtd@lists.infradead.org; Mon, 28 Aug 2017 23:42:29 +0000","by mail-wm0-x244.google.com with SMTP id x189so2042842wmg.4\n\tfor <linux-mtd@lists.infradead.org>;\n\tMon, 28 Aug 2017 16:42:05 -0700 (PDT)","by 10.80.154.1 with HTTP; Mon, 28 Aug 2017 16:42:02 -0700 (PDT)"],"DKIM-Signature":["v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed;\n\td=lists.infradead.org; s=bombadil.20170209; h=Sender:\n\tContent-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post:\n\tList-Archive:List-Unsubscribe:List-Id:To:Subject:Message-ID:Date:From:\n\tReferences:In-Reply-To:MIME-Version:Reply-To:Content-ID:Content-Description:\n\tResent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:\n\tList-Owner; bh=4BXXAQuYxUTCBy5fI+IiQLUpK8VhWBTBjEJNyCleMqo=;\n\tb=jPaJmQNW2dpgTl\n\t8U/NR4oTN0NWidM5lTuK0yOJl87BzWwThOx68uR1I5vGrI9qJdC7fohTkGs9SYOxXP1/vw/pjLfSm\n\ts6Qtq0EC3XnEv8vjP8h/xucSQrOc5WQDzEB56zZsde7n3ZxLyuclreMac87ZkrlE+8JeDVnMsNrZw\n\tXbuDrX+Zq5goTiYvhdLH6BPTnP+tpiMq55kH5Y+lo8WmUOWN8rDxKnoVJ3JlQb+JZBeYdGGJdyfkd\n\t6or1hSqHDf0Ct8zGElFbjnHB3bpVdayYMsgifvL7Kv2yI+WXpVY/9gRMWm9vPmdvev3B9SKaU3dFI\n\tpbp4v8JwsXtKt55vIKnw==;","v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025;\n\th=mime-version:in-reply-to:references:from:date:message-id:subject:to\n\t:cc; bh=gT4WuB5NX94pQUghXZD8T9cdDzTE9aHKvd/XmJ3TdlE=;\n\tb=fZ5WxVTOjI+43sAz5yQdjINdA9VTNqwxlzdg9PJhoFdjE1GhvHPCH+65l21GnG7tEl\n\tR8MrbM2KMKYxff1ybwzrbwMQAPGL/DLZNcZ/n2BDJczZ5y59v9X1HhNvwPOwSuzprMq6\n\tNZbNVT95wQeMc/zPyfxU6kPvXqVJBmkGOe1FZXZkyj+a+VT/CF0WWi+tdPuE4XxEvSvL\n\to8VWTUwfQlH67loRRpFIrWikdSaQ2MnsJU/xnk51TdBdzdbm5aVNIzK3bnmg+gfj6QpM\n\tvOHYaMT2pNuSC3cIFxoqXdUqJbf0KcAi9026DKDvL/KneNeXZFQXr2ZrGpF99yEWWuNC\n\tAlmA=="],"X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20161025;\n\th=x-gm-message-state:mime-version:in-reply-to:references:from:date\n\t:message-id:subject:to:cc;\n\tbh=gT4WuB5NX94pQUghXZD8T9cdDzTE9aHKvd/XmJ3TdlE=;\n\tb=R+qlPzY6Fg2Bou33LXXF2nALOnp0NHXWeDfmXHW5r711JTK8Y63WazONtHuuFPgBOp\n\tYR5xcJ1edeKC03fsE/bXiGW0Tswd9dZ2FBUOuPLqODWJigrNE7wpEYRZhAtqUzIcG+g3\n\t5Ro5nqXQEz7JbnqgF8Y2YQywuidRKI19m0+Q5HKS36hY5zy3GJ6NmGbr9q6JIrEggil2\n\tneHix0L7jbpzBiGJlnXnfQWh8dYeKNXSFMUi9MwZ5wijikOaRw8PZsbmIlQkluAglD5w\n\tbsH1tilyB7+L4fevDkGt72OYrtfVAUAolZLBih3+bwQuT7zgRykhbXYWNpfcftsudXS3\n\tYM2A==","X-Gm-Message-State":"AHYfb5g0H5bzYXCGfXtnwlxFEecuYQnpcbIKWfp1z1yXVUgjt/uVB42W\n\tV4GtyNqTXGHXLL/wQCqM8BDc15pMFw==","X-Received":"by 10.80.171.94 with SMTP id t30mr1856090edc.240.1503963722819; \n\tMon, 28 Aug 2017 16:42:02 -0700 (PDT)","MIME-Version":"1.0","In-Reply-To":"<20170829004549.3a936874@bbrezillon>","References":"<1503958832-7525-1-git-send-email-andrea.adami@gmail.com>\n\t<20170829004549.3a936874@bbrezillon>","From":"Andrea Adami <andrea.adami@gmail.com>","Date":"Tue, 29 Aug 2017 01:42:02 +0200","Message-ID":"<CAAQYJAsRnL_QYMTthFgnAWeWMVCWLLeJK8XZZcyh=tOR_XT4iQ@mail.gmail.com>","Subject":"Re: [PATCH v7] mtd: sharpslpart: Add sharpslpart partition parser","To":"Boris Brezillon <boris.brezillon@free-electrons.com>","X-CRM114-Version":"20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 ","X-CRM114-CacheID":"sfid-20170828_164226_870671_95B8FC58 ","X-CRM114-Status":"GOOD (  36.29  )","X-Spam-Score":"-2.0 (--)","X-Spam-Report":"SpamAssassin version 3.4.1 on bombadil.infradead.org summary:\n\tContent analysis details:   (-2.0 points)\n\tpts rule name              description\n\t---- ----------------------\n\t--------------------------------------------------\n\t-0.0 SPF_PASS               SPF: sender matches SPF record\n\t0.0 FREEMAIL_FROM Sender email is commonly abused enduser mail\n\tprovider (andrea.adami[at]gmail.com)\n\t-1.9 BAYES_00               BODY: Bayes spam probability is 0 to 1%\n\t[score: 0.0000]\n\t-0.1 DKIM_VALID Message has at least one valid DKIM or DK signature\n\t0.1 DKIM_SIGNED            Message has a DKIM or DK signature,\n\tnot necessarily valid\n\t-0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from\n\tauthor's domain","X-BeenThere":"linux-mtd@lists.infradead.org","X-Mailman-Version":"2.1.21","Precedence":"list","List-Id":"Linux MTD discussion mailing list <linux-mtd.lists.infradead.org>","List-Unsubscribe":"<http://lists.infradead.org/mailman/options/linux-mtd>,\n\t<mailto:linux-mtd-request@lists.infradead.org?subject=unsubscribe>","List-Archive":"<http://lists.infradead.org/pipermail/linux-mtd/>","List-Post":"<mailto:linux-mtd@lists.infradead.org>","List-Help":"<mailto:linux-mtd-request@lists.infradead.org?subject=help>","List-Subscribe":"<http://lists.infradead.org/mailman/listinfo/linux-mtd>,\n\t<mailto:linux-mtd-request@lists.infradead.org?subject=subscribe>","Cc":"Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>, Richard Weinberger\n\t<richard@nod.at>, Robert Jarzmik <robert.jarzmik@free.fr>, \n\tlinux-kernel@vger.kernel.org, Haojian Zhuang <haojian.zhuang@gmail.com>, \n\tMarek Vasut <marek.vasut@gmail.com>, linux-mtd@lists.infradead.org, \n\tCyrille Pitchen <cyrille.pitchen@wedev4u.fr>, \n\t=?utf-8?b?UmFmYcWCIE1pxYJlY2tp?= <rafal@milecki.pl>,\n\tBrian Norris <computersforpeace@gmail.com>, David Woodhouse\n\t<dwmw2@infradead.org>","Content-Type":"text/plain; charset=\"us-ascii\"","Content-Transfer-Encoding":"7bit","Sender":"\"linux-mtd\" <linux-mtd-bounces@lists.infradead.org>","Errors-To":"linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org"}}]