Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/806800/?format=api
{ "id": 806800, "url": "http://patchwork.ozlabs.org/api/patches/806800/?format=api", "web_url": "http://patchwork.ozlabs.org/project/linux-mtd/patch/1503958832-7525-1-git-send-email-andrea.adami@gmail.com/", "project": { "id": 3, "url": "http://patchwork.ozlabs.org/api/projects/3/?format=api", "name": "Linux MTD development", "link_name": "linux-mtd", "list_id": "linux-mtd.lists.infradead.org", "list_email": "linux-mtd@lists.infradead.org", "web_url": null, "scm_url": null, "webscm_url": null, "list_archive_url": "", "list_archive_url_format": "", "commit_url_format": "" }, "msgid": "<1503958832-7525-1-git-send-email-andrea.adami@gmail.com>", "list_archive_url": null, "date": "2017-08-28T22:20:32", "name": "[v7] mtd: sharpslpart: Add sharpslpart partition parser", "commit_ref": null, "pull_url": null, "state": "superseded", "archived": false, "hash": "f649233db46cc03bf577f7cbdcefec4fced86672", "submitter": { "id": 30311, "url": "http://patchwork.ozlabs.org/api/people/30311/?format=api", "name": "Andrea Adami", "email": "andrea.adami@gmail.com" }, "delegate": { "id": 53193, "url": "http://patchwork.ozlabs.org/api/users/53193/?format=api", "username": "computersforpeace", "first_name": "Brian", "last_name": "Norris", "email": "computersforpeace@gmail.com" }, "mbox": "http://patchwork.ozlabs.org/project/linux-mtd/patch/1503958832-7525-1-git-send-email-andrea.adami@gmail.com/mbox/", "series": [ { "id": 273, "url": "http://patchwork.ozlabs.org/api/series/273/?format=api", "web_url": "http://patchwork.ozlabs.org/project/linux-mtd/list/?series=273", "date": "2017-08-28T22:20:32", "name": "[v7] mtd: sharpslpart: Add sharpslpart partition parser", "version": 7, "mbox": "http://patchwork.ozlabs.org/series/273/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/806800/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/806800/checks/", "tags": {}, "related": [], "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=\"ofeOGzbJ\"; \n\tdkim=fail reason=\"signature verification failed\" (2048-bit key;\n\tunprotected) header.d=gmail.com header.i=@gmail.com\n\theader.b=\"qNaxSqV/\"; 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 3xh5p10JLDz9s72\n\tfor <incoming@patchwork.ozlabs.org>;\n\tTue, 29 Aug 2017 08:21:12 +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 1dmSP1-0000DN-J3; Mon, 28 Aug 2017 22:21:03 +0000", "from mail-wr0-x243.google.com ([2a00:1450:400c:c0c::243])\n\tby bombadil.infradead.org with esmtps (Exim 4.87 #1 (Red Hat Linux))\n\tid 1dmSOv-0000Ah-Le\n\tfor linux-mtd@lists.infradead.org; Mon, 28 Aug 2017 22:21:01 +0000", "by mail-wr0-x243.google.com with SMTP id j3so1156458wrb.5\n\tfor <linux-mtd@lists.infradead.org>;\n\tMon, 28 Aug 2017 15:20:36 -0700 (PDT)", "from andrea-ThinkPad-T520.homenet.telecomitalia.it\n\t([95.237.99.235])\n\tby smtp.gmail.com with ESMTPSA id 69sm83439wmp.37.2017.08.28.15.20.33\n\t(version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128);\n\tMon, 28 Aug 2017 15:20:33 -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:MIME-Version:Cc:List-Subscribe:\n\tList-Help:List-Post:List-Archive:List-Unsubscribe:List-Id:Message-Id:Date:\n\tSubject:To:From:Reply-To:Content-ID:Content-Description:Resent-Date:\n\tResent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To:\n\tReferences:List-Owner; bh=k7E6mSPspFKkaNxjn8k70Ix9O9oZjHSWl170ViMniwI=;\n\tb=ofe\n\tOGzbJjxuT91lY5avhdtDycs+op2ErtXH9a6CcL2Fsp6PzckXZgBp2goh2wFtLR0+2AdIAg7gZdH/+\n\t91zievSO3UHXjQ1laCobSw6ZyqSD4xNZmzSNhZAVGy5edzZNZDv0m/NSelp9klEThhmpm7SdAxSGa\n\tXTo/DiQSCkWOFP8U7JbylH+hcBg6TkPHHlKaCWLIgvMXm1F1scRRezWzA+C3AQMY4j1FayysMPW9Y\n\thDCnNFMix1H9001XBFeUyAUxZYcxYRXI3dDETLC3JTbe7Wj8OvBwEe4vs6rVxNnZwhbyCN50dPQMy\n\tnDGr2f4uDDpU2b/KTmrZKnKcSi2hd0A==;", "v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025;\n\th=from:to:cc:subject:date:message-id;\n\tbh=gZQKdetGpu4bAIlq75ORqOaWT6zG4Ef7sOBPe9tYdxg=;\n\tb=qNaxSqV/D5LD82f6Q9MPPWgzwGyqNHqCS8w8XAw21sC4YI/fG3rkHbTmRvx6TkjyVC\n\tdilAara4hbTkqYqiFTibfnHr0ZKVs+WmrRLJZwb0QeLvSk8Dc9s/yktMu8pS7F8ZIwUZ\n\tAtjZQljHFtRoFgptUTBf2A9LwSkDo4x0//naQQsTZY1xFEOqV7yIwkpAEXPQtrIMTwQO\n\tWCy2VY9fEV6+FEnOdZt+f+MeNRO1IHUDanv7c+tRc8pc00axJRcy6l02sOwYbBVbAN/s\n\tmzHBtLXfAOwjhkq6v1n4kyqsrUAHexmWZqEdgYhIW6947o5up86qKPVWOIwwdsnmzqIh\n\tfqag==" ], "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20161025;\n\th=x-gm-message-state:from:to:cc:subject:date:message-id;\n\tbh=gZQKdetGpu4bAIlq75ORqOaWT6zG4Ef7sOBPe9tYdxg=;\n\tb=sCtLtucxI08arjAwB5pw79av0FQHXXIl3SN0IiPSpVM60m5W7xiqAvb1T6GG8/Nzs4\n\tOMAa3wDIbje9X3hGV4m5A3logzoHnDTFpctaVE5EzlhhTR8zcr9atfzIvcxZGAvohe4c\n\tpde6cXwOtqcN8Uj29WFaXwIqi7grUdVYE/EYOp4a45/G8C3EqxkT4oRh2TD/m3khXZSw\n\tt9EiXNUh3WiDriE0BuecZbP6HMrG7sMOFpNL1yWwT7ShgwEC72//uhveqwEdfVN3VPYa\n\tRijhhwa3sitQOiW1ds6aN52vtcrsq+9I8O/pl3zO3i+AtpH3YhYgPeemHSECeohi/RAA\n\tWPcQ==", "X-Gm-Message-State": "AHYfb5jVYNqj+/k0oQ3xIM47Bl6iSDAzzSVqeKNzFWAzT+s4Nh9J547n\n\toVn/KjjiQ25eaFPYiTo=", "X-Received": "by 10.223.153.226 with SMTP id y89mr1267589wrb.46.1503958834951; \n\tMon, 28 Aug 2017 15:20:34 -0700 (PDT)", "From": "Andrea Adami <andrea.adami@gmail.com>", "To": "linux-mtd@lists.infradead.org", "Subject": "[PATCH v7] mtd: sharpslpart: Add sharpslpart partition parser", "Date": "Tue, 29 Aug 2017 00:20:32 +0200", "Message-Id": "<1503958832-7525-1-git-send-email-andrea.adami@gmail.com>", "X-Mailer": "git-send-email 2.7.4", "X-CRM114-Version": "20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 ", "X-CRM114-CacheID": "sfid-20170828_152058_130319_425F8AD8 ", "X-CRM114-Status": "GOOD ( 31.90 )", "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 RCVD_IN_DNSWL_NONE RBL: Sender listed at http://www.dnswl.org/,\n\tno\n\ttrust [2a00:1450:400c:c0c:0:0:0:243 listed in] [list.dnswl.org]\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": "Boris Brezillon <boris.brezillon@free-electrons.com>, Dmitry\n\tEremin-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>, \n\tCyrille Pitchen <cyrille.pitchen@wedev4u.fr>, =?utf-8?b?UmFmYcWCIE1p?=\n\t=?utf-8?b?xYJlY2tp?= <rafal@milecki.pl>,\n\tBrian Norris <computersforpeace@gmail.com>, David Woodhouse\n\t<dwmw2@infradead.org>", "MIME-Version": "1.0", "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" }, "content": "The Sharp SL Series (Zaurus) PXA handhelds have 16/64/128M of NAND flash\nand share the same layout of the first 7M partition, managed by Sharp FTL.\n\nGPL 2.4 sources: http://support.ezaurus.com/developer/source/source_dl.asp\n\nThe purpose of this self-contained patch is to add a common parser and\nremove the hardcoded sizes in the board files (these devices are not yet\nconverted to devicetree).\nUsers will have benefits because the mtdparts= tag will not be necessary\nanymore and they will be free to repartition the little sized flash.\n\nThe obsolete bootloader can not pass the partitioning info to modern\nkernels 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\nIn kernel, under arch/arm/mach-pxa we have already 8 machines:\nMACH_POODLE, MACH_CORGI, MACH_SHEPERD, MACH_HUSKY, MACH_AKITA, MACH_SPITZ,\nMACH_BORZOI, MACH_TOSA.\nLost after the 2.4 vendor kernel are MACH_BOXER and MACH_TERRIER.\n\nAlmost every model has different factory partitioning: add to this the\nunits can be repartitioned by users with userspace tools (nandlogical)\nand installers for popular (back then) linux distributions.\n\nThe Parameter Area in the first (boot) partition extends from 0x00040000 to\n0x0007bfff (176k) and contains two copies of the partition table:\n...\n0x00060000: Partition Info1 16k\n0x00064000: Partition Info2 16k\n0x00668000: Model 16k\n...\n\nThe first 7M partition is managed by the Sharp FTL reserving 5% + 1 blocks\nfor wear-leveling: some blocks are remapped and one layer of translation\n(logical to physical) is necessary.\n\nThere isn't much documentation about this FTL in the 2.4 sources, just the\nMTD methods for reading and writing using logical addresses and the block\nmanagement (wear-leveling, use counter).\nIt seems this FTL was tailored with 16KiB eraesize in mind so to fit one\nparam block exactly, to have two copies of the partition table on two\nblocks.\nLater 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\nnow in the same eraseblock.\n\nFor the purpose of the MTD parser only the read part of the code was taken.\n\nThe NAND drivers that can use this parser are sharpsl.c and tmio_nand.c.\n\nChangelog:\nv1 firt version, initial import of 2.4 sources\nv2 refactor applying many suggested fixes\nv3 put the partition parser types in the platform data\nv4 refactor after ML review\nv5 fix commit messages and texts, remove global, fixes after v4 review\nv6 refactor memory mgmt passing pointer to the FTL, fixes after v5 review\nv7 verify the oob are free for the FTL, renamings, fixes after v6 review\n\nSigned-off-by: Andrea Adami <andrea.adami@gmail.com>\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", "diff": "diff --git a/drivers/mtd/parsers/Kconfig b/drivers/mtd/parsers/Kconfig\nindex 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.\ndiff --git a/drivers/mtd/parsers/Makefile b/drivers/mtd/parsers/Makefile\nindex 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\ndiff --git a/drivers/mtd/parsers/sharpslpart.c b/drivers/mtd/parsers/sharpslpart.c\nnew file mode 100644\nindex 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+\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+\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+ */\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+ */\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\");\n", "prefixes": [ "v7" ] }