From patchwork Sat Aug 5 16:26:33 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Golle X-Patchwork-Id: 131507 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:c44e:0:b0:3f2:4152:657d with SMTP id w14csp549639vqr; Sat, 5 Aug 2023 09:59:31 -0700 (PDT) X-Google-Smtp-Source: AGHT+IEsY+kCxb7s8wX8DC0bh2odLwthYbACJGsdZpoaI7h+KaZnxA0WumqtDTVAYB0L93q0hbyv X-Received: by 2002:a05:6a00:1388:b0:687:1300:22ff with SMTP id t8-20020a056a00138800b00687130022ffmr3539202pfg.1.1691254770707; Sat, 05 Aug 2023 09:59:30 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1691254770; cv=none; d=google.com; s=arc-20160816; b=JYNx7sorxDePxSgM2bZ5n5uBh72Tp2W4wLQ3KvDXw09NQwAADivcfbqH0Z/czk8oqJ 8+DXA25t2jZEV3tEeo1y3HJq39IvSi8/G4wN4rVQ+f/T+ciMS2p1rf+skq8Pn9cjDTk1 lu9W/+KKs/1aLMEmjznZBz5V854FabTFjGsY//qO5pH0Ho/7xuJjAO3gspo2ueJ0tx1J CfiltKpHujpFkF26VPRXNTEUkzlnVcURqbEQdAuiVo25Tu4qN4ObMOo0ZQHZd2n6UVvu 6FVaC7VvwQ9Nj1TlMiaPskb/cttYLAM39GGei+H/SLX35+8dXu7gKAa92Tt2w0e9U3TK us8g== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:in-reply-to:content-disposition:mime-version :references:message-id:subject:to:from:date; bh=6tHDzll50T2gKNSMAIB0HHCIYU8y6KbrScP4vA7BGqY=; fh=WrF5P4rt5GKLKZXFPrBfHwP5VFIZG8GPN/h4vsvn4l4=; b=Yv5J6hXn/g6AGtIe9gCz3rwE1dRh30w37/A8yzT/pPsR/Te6+4a3PwZXbTPtmQ3C72 hsDgtO+lseYIkYH1erMYdspimCN0cpDsfv4qesTKgGhjil8Aszj+SfdKpXZFEEmkUfy1 aueAR0hKQc6EGEFJcMrG/mQOpJfT7Qp2YMHaqEvF6CreBn622/xDlMKYm6zj813QTfp6 hp+4rZmSr3YA4EYcasXgV8juqSA4UYDNJ9QStBODxQa5tcOs/9+kmL6SjP+xnfAQ8aSB /Zw4Dgnhc6AUyStAxXGrrNJETCU9CLVbXaflRYG3G5GOx0PwqDOlcDe7Rs8SJAg0Ep2S INrA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id z16-20020a056a001d9000b0067f69d10241si3306787pfw.176.2023.08.05.09.59.17; Sat, 05 Aug 2023 09:59:30 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229940AbjHEQ1A (ORCPT + 99 others); Sat, 5 Aug 2023 12:27:00 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40058 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229917AbjHEQ05 (ORCPT ); Sat, 5 Aug 2023 12:26:57 -0400 Received: from pidgin.makrotopia.org (pidgin.makrotopia.org [185.142.180.65]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 740D94218 for ; Sat, 5 Aug 2023 09:26:44 -0700 (PDT) Received: from local by pidgin.makrotopia.org with esmtpsa (TLS1.3:TLS_AES_256_GCM_SHA384:256) (Exim 4.96) (envelope-from ) id 1qSK6y-0000fe-35; Sat, 05 Aug 2023 16:26:41 +0000 Date: Sat, 5 Aug 2023 17:26:33 +0100 From: Daniel Golle To: Randy Dunlap , Richard Weinberger , Miquel Raynal , Vignesh Raghavendra , linux-kernel@vger.kernel.org, linux-mtd@lists.infradead.org Subject: [PATCH v2 7/7] mtd: ubi: provide NVMEM layer over UBI volumes Message-ID: <3df11df592be6a8f681fc612217f75c2a04e8186.1691252291.git.daniel@makrotopia.org> References: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_BLOCKED,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1773409162824683037 X-GMAIL-MSGID: 1773409162824683037 In an ideal world we would like UBI to be used where ever possible on a NAND chip. And with UBI support in ARM Trusted Firmware and U-Boot it is possible to achieve an (almost-)all-UBI flash layout. Hence the need for a way to also use UBI volumes to store board-level constants, such as MAC addresses and calibration data of wireless interfaces. Add UBI volume NVMEM driver module exposing UBI volumes as NVMEM providers. Allow UBI devices to have a "volumes" firmware subnode with volumes which may be compatible with "nvmem-cells". Access to UBI volumes via the NVMEM interface at this point is read-only, and it is slow, opening and closing the UBI volume for each access due to limitations of the NVMEM provider API. Signed-off-by: Daniel Golle --- drivers/mtd/ubi/Kconfig | 12 +++ drivers/mtd/ubi/Makefile | 1 + drivers/mtd/ubi/nvmem.c | 189 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 202 insertions(+) create mode 100644 drivers/mtd/ubi/nvmem.c diff --git a/drivers/mtd/ubi/Kconfig b/drivers/mtd/ubi/Kconfig index 184118f9a2969..fb15d4549d55f 100644 --- a/drivers/mtd/ubi/Kconfig +++ b/drivers/mtd/ubi/Kconfig @@ -104,4 +104,16 @@ config MTD_UBI_BLOCK If in doubt, say "N". +config MTD_UBI_NVMEM + tristate "UBI virtual NVMEM" + default n + depends on NVMEM + help + This option enables an additional driver exposing UBI volumes as NVMEM + providers, intended for platforms where UBI is part of the firmware + specification and used to store also e.g. MAC addresses or board- + specific Wi-Fi calibration data. + + If in doubt, say "N". + endif # MTD_UBI diff --git a/drivers/mtd/ubi/Makefile b/drivers/mtd/ubi/Makefile index 543673605ca72..4b51aaf00d1a2 100644 --- a/drivers/mtd/ubi/Makefile +++ b/drivers/mtd/ubi/Makefile @@ -7,3 +7,4 @@ ubi-$(CONFIG_MTD_UBI_FASTMAP) += fastmap.o ubi-$(CONFIG_MTD_UBI_BLOCK) += block.o obj-$(CONFIG_MTD_UBI_GLUEBI) += gluebi.o +obj-$(CONFIG_MTD_UBI_NVMEM) += nvmem.o diff --git a/drivers/mtd/ubi/nvmem.c b/drivers/mtd/ubi/nvmem.c new file mode 100644 index 0000000000000..dd7cc6afb8d00 --- /dev/null +++ b/drivers/mtd/ubi/nvmem.c @@ -0,0 +1,189 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2023 Daniel Golle + */ + +/* UBI NVMEM provider */ +#include "ubi.h" +#include + +/* List of all NVMEM devices */ +static LIST_HEAD(nvmem_devices); +static DEFINE_MUTEX(devices_mutex); + +struct ubi_nvmem { + struct nvmem_device *nvmem; + int ubi_num; + int vol_id; + int usable_leb_size; + struct list_head list; +}; + +static int ubi_nvmem_reg_read(void *priv, unsigned int from, + void *val, size_t bytes) +{ + struct ubi_nvmem *unv = priv; + struct ubi_volume_desc *desc; + int err = 0, lnum, offs, bytes_left; + size_t to_read; + + desc = ubi_open_volume(unv->ubi_num, unv->vol_id, UBI_READONLY); + if (IS_ERR(desc)) + return PTR_ERR(desc); + + lnum = div_u64_rem(from, unv->usable_leb_size, &offs); + bytes_left = bytes; + while (bytes_left) { + to_read = unv->usable_leb_size - offs; + + if (to_read > bytes_left) + to_read = bytes_left; + + err = ubi_read(desc, lnum, val, offs, to_read); + if (err) + break; + + lnum += 1; + offs = 0; + bytes_left -= to_read; + val += to_read; + } + ubi_close_volume(desc); + + if (err) + return err; + + return bytes_left == 0 ? 0 : -EIO; +} + +static int ubi_nvmem_add(struct ubi_volume_info *vi) +{ + struct nvmem_config config = {}; + struct ubi_nvmem *unv; + int ret; + + if (!device_is_compatible(vi->dev, "nvmem-cells")) + return 0; + + unv = kzalloc(sizeof(struct ubi_nvmem), GFP_KERNEL); + if (!unv) + return -ENOMEM; + + config.id = NVMEM_DEVID_NONE; + config.dev = vi->dev; + config.name = dev_name(vi->dev); + config.owner = THIS_MODULE; + config.priv = unv; + config.reg_read = ubi_nvmem_reg_read; + config.size = vi->usable_leb_size * vi->size; + config.word_size = 1; + config.stride = 1; + config.read_only = true; + config.root_only = true; + config.ignore_wp = true; + config.of_node = dev_of_node(vi->dev); + + if (!config.of_node) + config.no_of_node = true; + + unv->ubi_num = vi->ubi_num; + unv->vol_id = vi->vol_id; + unv->usable_leb_size = vi->usable_leb_size; + unv->nvmem = nvmem_register(&config); + if (IS_ERR(unv->nvmem)) { + /* Just ignore if there is no NVMEM support in the kernel */ + if (PTR_ERR(unv->nvmem) == -EOPNOTSUPP) + ret = 0; + else + ret = dev_err_probe(vi->dev, PTR_ERR(unv->nvmem), + "Failed to register NVMEM device\n"); + + kfree(unv); + return ret; + } + + mutex_lock(&devices_mutex); + list_add_tail(&unv->list, &nvmem_devices); + mutex_unlock(&devices_mutex); + + return 0; +} + +static void ubi_nvmem_remove(struct ubi_volume_info *vi) +{ + struct ubi_nvmem *unv_c, *unv = NULL; + + mutex_lock(&devices_mutex); + list_for_each_entry(unv_c, &nvmem_devices, list) + if (unv_c->ubi_num == vi->ubi_num && unv_c->vol_id == vi->vol_id) { + unv = unv_c; + break; + } + + if (!unv) { + mutex_unlock(&devices_mutex); + return; + } + + list_del(&unv->list); + mutex_unlock(&devices_mutex); + nvmem_unregister(unv->nvmem); + kfree(unv); +} + +/** + * nvmem_notify - UBI notification handler. + * @nb: registered notifier block + * @l: notification type + * @ns_ptr: pointer to the &struct ubi_notification object + */ +static int nvmem_notify(struct notifier_block *nb, unsigned long l, + void *ns_ptr) +{ + struct ubi_notification *nt = ns_ptr; + + switch (l) { + case UBI_VOLUME_RESIZED: + ubi_nvmem_remove(&nt->vi); + fallthrough; + case UBI_VOLUME_ADDED: + ubi_nvmem_add(&nt->vi); + break; + case UBI_VOLUME_SHUTDOWN: + ubi_nvmem_remove(&nt->vi); + break; + default: + break; + } + return NOTIFY_OK; +} + +static struct notifier_block nvmem_notifier = { + .notifier_call = nvmem_notify, +}; + +static int __init ubi_nvmem_init(void) +{ + return ubi_register_volume_notifier(&nvmem_notifier, 0); +} + +static void __exit ubi_nvmem_exit(void) +{ + struct ubi_nvmem *unv, *tmp; + + mutex_lock(&devices_mutex); + list_for_each_entry_safe(unv, tmp, &nvmem_devices, list) { + nvmem_unregister(unv->nvmem); + list_del(&unv->list); + kfree(unv); + } + mutex_unlock(&devices_mutex); + + ubi_unregister_volume_notifier(&nvmem_notifier); +} + +module_init(ubi_nvmem_init); +module_exit(ubi_nvmem_exit); +MODULE_DESCRIPTION("NVMEM layer over UBI volumes"); +MODULE_AUTHOR("Daniel Golle"); +MODULE_LICENSE("GPL");