From patchwork Thu Feb 25 20:17:59 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jan Hoffmann X-Patchwork-Id: 1444597 X-Patchwork-Delegate: ynezz@true.cz Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.openwrt.org (client-ip=2001:8b0:10b:1231::1; helo=merlin.infradead.org; envelope-from=openwrt-devel-bounces+incoming=patchwork.ozlabs.org@lists.openwrt.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; secure) header.d=lists.infradead.org header.i=@lists.infradead.org header.a=rsa-sha256 header.s=merlin.20170209 header.b=R7w+GXWE; dkim=fail reason="signature verification failed" (2048-bit key; secure) header.d=3e8.eu header.i=@3e8.eu header.a=rsa-sha256 header.s=mail20170724 header.b=xL0HIkUx; dkim-atps=neutral Received: from merlin.infradead.org (merlin.infradead.org [IPv6:2001:8b0:10b:1231::1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4DmkgK1LJVz9sVV for ; Fri, 26 Feb 2021 07:20:29 +1100 (AEDT) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=merlin.20170209; h=Sender:Content-Transfer-Encoding: Content-Type:Cc:List-Subscribe:List-Help:List-Post:List-Archive: List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To:Message-Id:Date: Subject:To:From:Reply-To:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=UQcbUsuMvJhOyciVvtdYKTWgn+ph1E9iYcYwA60lTKg=; b=R7w+GXWEHbGSKz3WAqGw0l3uy WLnSIFhwv7KYbTRkMmoP+HaGhPNZA6q4WBnC/VRBwFNqpZlnS8PB5MdMNpUiw3lAbwfBvzJllJA06 bEfa9KzbepEVFRwxrkLHRh9tYuJpObkdInQ2P2B/ASoqS2mk9H+aCSNp3XhgcbwOo9KKQESXA9HJw fcMxsxrXZLi14yXk4ZTZJK+PZhqsRIyH2xqA9Y5vRguhw6aapbA4tjx5Tc+D8BSK3UzbDySF7Ao3O QVHjip40mA0GJSrg1/kprcBMq3S9AcugmwPmTaWDNXTRvi7VpLphDeIwDUoOJnpzSZIqkNtd18AOC 3jQh+ApIQ==; Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1lFN5n-0007L5-Cp; Thu, 25 Feb 2021 20:18:35 +0000 Received: from srv4.3e8.eu ([2001:67c:12a0:200::2]) by merlin.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1lFN5i-0007Hb-CK for openwrt-devel@lists.openwrt.org; Thu, 25 Feb 2021 20:18:32 +0000 Received: from localhost.localdomain (p200300c6cf27cba0eb00b3f07c02ac8f.dip0.t-ipconnect.de [IPv6:2003:c6:cf27:cba0:eb00:b3f0:7c02:ac8f]) (using TLSv1.3 with cipher TLS_CHACHA20_POLY1305_SHA256 (256/256 bits)) (No client certificate requested) by srv4.3e8.eu (Postfix) with ESMTPSA id 5B17C600FB; Thu, 25 Feb 2021 21:18:15 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=3e8.eu; s=mail20170724; t=1614284295; bh=mlJN2vRzs/7UyJ8gfoGzfqnpbyLcOXtDTSmZFvF6JFg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=xL0HIkUx9oAFy7RtxnUEk/hUihhMRYEHBlCEXxH6jHZeEIEjCuataCryAxRaaixq4 q4Z1m5CIinf2xYfstHyvxp1/7qYs79BdwvdbHjm1EIy9Uq+SDcy5uk6PfszCj1YL/u GdJJGNDl53aER3HpLYrrmNexeX1EsIpdRYOH0Dr5sj2286w6CS7pID4ok1MKOiERTO 0Cu2DM+/K2EV4Wzb6iYrnIh4pdPmd7ZSDRMDmyxiqHOPx15b6UsOFhiwcQMKFu/FnB BiinIemoeRzwji/q+SpEyvyTymxChy90Z9yZ48FGw3B0KHo2lXPnwARYlicUnxEjax DOvdmYSxX9D3w== From: Jan Hoffmann To: openwrt-devel@lists.openwrt.org Subject: [PATCH v2 1/2] ramips: add Sercomm partition map parser Date: Thu, 25 Feb 2021 21:17:59 +0100 Message-Id: <20210225201800.2478284-2-jan@3e8.eu> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20210225201800.2478284-1-jan@3e8.eu> References: <20200628232747.1367531-1-jan@3e8.eu> <20210225201800.2478284-1-jan@3e8.eu> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20210225_151830_742405_32B30CAC X-CRM114-Status: GOOD ( 29.21 ) X-Spam-Score: -0.2 (/) X-Spam-Report: SpamAssassin version 3.4.4 on merlin.infradead.org summary: Content analysis details: (-0.2 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 SPF_HELO_PASS SPF: HELO matches SPF record -0.0 SPF_PASS SPF: sender matches SPF record 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature X-BeenThere: openwrt-devel@lists.openwrt.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: OpenWrt Development List List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: drvlabo@gmail.com, jan@3e8.eu, jost@1.node1.de Sender: "openwrt-devel" Errors-To: openwrt-devel-bounces+incoming=patchwork.ozlabs.org@lists.openwrt.org This adds an MTD partition parser for the Sercomm partition table that is used in some Netgear routers. This is essentially the same code as proposed in the pull request for Netgear R6350 support by NOGUCHI Hiroshi : https://github.com/openwrt/openwrt/pull/1318 It was originally rejected as it did not seem to work correctly. However, this was only due the NAND driver transparently shifting pages to hide bad blocks, which was fixed in commit 527832e54bf3bc4d699a145ae66f34230246f0a9. Signed-off-by: Jan Hoffmann --- .../ramips/files/drivers/mtd/parsers/scpart.c | 257 ++++++++++++++++++ .../patches-5.4/303-mtd-scpart-parser.patch | 19 ++ 2 files changed, 276 insertions(+) create mode 100644 target/linux/ramips/files/drivers/mtd/parsers/scpart.c create mode 100644 target/linux/ramips/patches-5.4/303-mtd-scpart-parser.patch diff --git a/target/linux/ramips/files/drivers/mtd/parsers/scpart.c b/target/linux/ramips/files/drivers/mtd/parsers/scpart.c new file mode 100644 index 0000000000..36c3c0bb36 --- /dev/null +++ b/target/linux/ramips/files/drivers/mtd/parsers/scpart.c @@ -0,0 +1,257 @@ +/* + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Sercomm/Netgear FLASH partition table. + */ + + +#include +#include +#include +#include +#include + + +#define MOD_NAME "scpart" + +static const char sc_part_magic[] = { + 'S', 'C', 'F', 'L', 'M', 'A', 'P', 'O', 'K', '\0', +}; +#define PART_MAGIC_LEN sizeof(sc_part_magic) + +/* assumes that all fields are set by CPU native endian */ +struct sc_part_desc { + uint32_t part_id; + uint32_t part_offs; + uint32_t part_bytes; +}; +#define ID_ALREADY_FOUND (0xFFFFFFFFUL) + +#define MAP_OFFS_IN_BLK (0x800) + +#define MAP_MIRROR_NUM (2) + +static int scpart_desc_is_valid(struct sc_part_desc *pdesc) +{ + return !!((pdesc->part_id != 0xFFFFFFFFUL) && + (pdesc->part_offs != 0xFFFFFFFFUL) && + (pdesc->part_bytes != 0xFFFFFFFFUL)); +} + +static int scpart_scan_partmap(struct mtd_info *master, loff_t partmap_offs, + struct sc_part_desc **ppdesc) +{ + uint8_t *buf; + loff_t offs; + size_t retlen; + struct sc_part_desc *pdesc = NULL; + struct sc_part_desc *tmpdesc; + int cnt = 0; + int res2; + int res = 0; + + buf = kzalloc(master->erasesize, GFP_KERNEL); + if (!buf) { + res = -ENOMEM; + goto out; + } + + res2 = mtd_read(master, partmap_offs, master->erasesize, &retlen, buf); + if (res2 || (retlen != master->erasesize)) { + res = -EIO; + goto free; + } + + offs = MAP_OFFS_IN_BLK; + while((offs + sizeof(*tmpdesc)) < master->erasesize) { + tmpdesc = (struct sc_part_desc*)&(buf[offs]); + if (!scpart_desc_is_valid(tmpdesc)) + break; + cnt++; + offs += sizeof(*tmpdesc); + } + + if (cnt > 0) { + int bytes = cnt * sizeof(*pdesc); + + pdesc = kzalloc(bytes, GFP_KERNEL); + if (!pdesc) { + res = -ENOMEM; + goto free; + } + memcpy(pdesc, &(buf[MAP_OFFS_IN_BLK]), bytes); + + *ppdesc = pdesc; + res = cnt; + } + + free: + kfree(buf); + + out: + return res; +} + +static int scpart_find_partmap(struct mtd_info *master, + struct sc_part_desc **ppdesc) +{ + loff_t offs; + uint8_t rdbuf[PART_MAGIC_LEN]; + size_t retlen; + int magic_found = 0; + int res2; + int res = 0; + + offs = 0; + while((magic_found < MAP_MIRROR_NUM) && + (offs < master->size) && !mtd_block_isbad(master, offs)) { + res2 = mtd_read(master, offs, PART_MAGIC_LEN, &retlen, rdbuf); + if (res2 || (retlen != PART_MAGIC_LEN)) { + res = -EIO; + goto out; + } + if (!memcmp(rdbuf, sc_part_magic, PART_MAGIC_LEN)) { + pr_debug("%s: signature found at 0x%llx\n", MOD_NAME, offs); + magic_found++; + res = scpart_scan_partmap(master, offs, ppdesc); + if (res > 0) + goto out; + } + offs += master->erasesize; + } + + out: + if (res > 0) + pr_info("%s: valid 'SC PART MAP' found (%d partitions)\n", MOD_NAME, res); + else + pr_info("%s: no valid 'SC PART MAP'\n", MOD_NAME); + + return res; +} + +static int scpart_parse(struct mtd_info *master, + const struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + struct sc_part_desc *scpart_map = NULL; + struct mtd_partition *parts = NULL; + struct device_node *mtd_node; + struct device_node *ofpart_node; + struct device_node *pp; + const char *partname; + int nr_scparts; + int nr_parts = 0; + int n; + int res = 0; + + mtd_node = mtd_get_of_node(master); + if (!mtd_node) + goto out; + + ofpart_node = of_get_child_by_name(mtd_node, "partitions"); + if (!ofpart_node) + goto out; + + nr_scparts = scpart_find_partmap(master, &scpart_map); + if (nr_scparts <= 0) { + res = nr_scparts; + goto free; + } + + for_each_child_of_node(ofpart_node, pp) { + u32 scpart_id; + struct mtd_partition *parts_tmp; + + if(of_property_read_u32(pp, "scpart-id", &scpart_id)) + continue; + + for (n = 0 ; n < nr_scparts ; n++) + if ((scpart_map[n].part_id != ID_ALREADY_FOUND) && + (scpart_id == scpart_map[n].part_id)) + break; + if (n >= nr_scparts) + /* not match */ + continue; + + /* add the partition found in OF into MTD partition array */ + + /* reallocate partition array */ + parts_tmp = parts; + parts = kzalloc((nr_parts + 1) * sizeof(*parts), GFP_KERNEL); + if (!parts) { + kfree(parts_tmp); + res = -ENOMEM; + goto free; + } + if (parts_tmp) { + memcpy(parts, parts_tmp, nr_parts * sizeof(*parts)); + kfree(parts_tmp); + } + + parts[nr_parts].offset = scpart_map[n].part_offs; + parts[nr_parts].size = scpart_map[n].part_bytes; + parts[nr_parts].of_node = pp; + + if (!of_property_read_string(pp, "label", &partname) || + !of_property_read_string(pp, "name", &partname)) + parts[nr_parts].name = partname; + + if (of_property_read_bool(pp, "read-only")) + parts[nr_parts].mask_flags |= MTD_WRITEABLE; + if (of_property_read_bool(pp, "lock")) + parts[nr_parts].mask_flags |= MTD_POWERUP_LOCK; + + /* mark as 'done' */ + scpart_map[n].part_id = ID_ALREADY_FOUND; + + nr_parts++; + } + if (nr_parts > 0) { + *pparts = parts; + res = nr_parts; + } else + pr_info("%s: No partition in OF matches partition ID with 'SC PART MAP'.\n", + MOD_NAME); + + of_node_put(pp); + + free: + kfree(scpart_map); + if (res <= 0) + kfree(parts); + + out: + return res; +} + +static const struct of_device_id scpart_parser_of_match_table[] = { + { .compatible = "sercomm,sc-partitions" }, + {}, +}; +MODULE_DEVICE_TABLE(of, scpart_parser_of_match_table); + +static struct mtd_part_parser scpart_parser = { + .parse_fn = scpart_parse, + .name = "scpart", + .of_match_table = scpart_parser_of_match_table, +}; +module_mtd_part_parser(scpart_parser); + +/* mtd parsers will request the module by parser name */ +MODULE_ALIAS("scpart"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("NOGUCHI Hiroshi "); +MODULE_DESCRIPTION("Parsing code for Sercomm/Netgear partition table"); diff --git a/target/linux/ramips/patches-5.4/303-mtd-scpart-parser.patch b/target/linux/ramips/patches-5.4/303-mtd-scpart-parser.patch new file mode 100644 index 0000000000..f125d9c6af --- /dev/null +++ b/target/linux/ramips/patches-5.4/303-mtd-scpart-parser.patch @@ -0,0 +1,19 @@ +--- a/drivers/mtd/parsers/Kconfig ++++ b/drivers/mtd/parsers/Kconfig +@@ -185,3 +185,9 @@ config MTD_ROUTERBOOT_PARTS + flash, some of which are fixed and some of which are located at + variable offsets. This parser handles both cases via properly + formatted DTS. ++ ++config MTD_SERCOMM_PARTS ++ tristate "SERCOMM partitioning information support" ++ depends on MTD_OF_PARTS ++ help ++ This provides partition table parser for SERCOMM partition map +--- a/drivers/mtd/parsers/Makefile ++++ b/drivers/mtd/parsers/Makefile +@@ -11,3 +11,4 @@ obj-$(CONFIG_MTD_PARSER_TRX) += parser_ + obj-$(CONFIG_MTD_SHARPSL_PARTS) += sharpslpart.o + obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o + obj-$(CONFIG_MTD_ROUTERBOOT_PARTS) += routerbootpart.o ++obj-$(CONFIG_MTD_SERCOMM_PARTS) += scpart.o