From nobody Tue Feb 10 23:01:16 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.11]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8DD571E2843 for ; Wed, 1 Jan 2025 15:50:39 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.11 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1735746641; cv=none; b=qr1Yi/n0omlaczVxEP6UVs9JHCi1pwNFJBiZUxq5syly3JJ7MCpGcdEdWy9cpAk9b/IBUWzFlJCqX67xnhMGIANHXMM/jEXV9s8O8bGYgvbXJTMkJSmxKXDkRxqMYd3A4ORhnNQUQQB+N/rvq46x5O8i5UhGH9NF6RJUhsUCZOw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1735746641; c=relaxed/simple; bh=NSkYDIr+t/AV04AKsrvBwo0MXWMMgwJl7QqvpeHpJ0M=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=V/+poGqBX1MvUjvZn/IENX45gaAZ2ppLwCLsKdAkVcm78b5aKjmbUwvcUmSaMmTFAnZN2/qYBhZOvB0jiwNykRzRu5Zb5WWr8c0ckrSPFDZ/NkobCBbrxwySy5ZwUCH4ydZUIKnHanqFvuIfc0Yuox7JVn0Wsjn5uREYh9krz1k= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=iHYnrwwn; arc=none smtp.client-ip=198.175.65.11 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="iHYnrwwn" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1735746639; x=1767282639; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=NSkYDIr+t/AV04AKsrvBwo0MXWMMgwJl7QqvpeHpJ0M=; b=iHYnrwwn+I3IMEeJTy8XLtRYfLJ+75aQBeMVO/Ftgf/TgTvt+4UBN71T jzvAOq1iEgDfJ1akqDSQvHBDGRXufmII4yesWvgNgGM6k1ObZYYIeEqWv YA1GK+MKUkMYsTqntMeUCfKf/zNaeR8KowsWrBp6MZjurYwLdhm9BqeAy uby+ONHjmMHkq6pYQRnEZngBx07exE0ONEIU0RtPFRR3J6gtEU5m6j+Yy IcRAzOufeXHfatsXz6vvySA4ZjBUDn5FrHwGsj2nbtYCzeBq4UX9aBXLL 0cxwcVPs3Ej1hsfwckYTtPsGndsMEy+RZPe4Evb108SzIteKKt4cjk21a Q==; X-CSE-ConnectionGUID: LBNx/i1yTrm2K1GOOWYE+g== X-CSE-MsgGUID: jhN8sLvmRq+9FzSnwvn2Iw== X-IronPort-AV: E=McAfee;i="6700,10204,11302"; a="46485521" X-IronPort-AV: E=Sophos;i="6.12,282,1728975600"; d="scan'208";a="46485521" Received: from orviesa002.jf.intel.com ([10.64.159.142]) by orvoesa103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 01 Jan 2025 07:50:39 -0800 X-CSE-ConnectionGUID: l3vGDItzTkGBKPWdsWWv9A== X-CSE-MsgGUID: gOIFcbg6RrmQOixzKCobhg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.12,282,1728975600"; d="scan'208";a="132138907" Received: from sannilnx-dsk.jer.intel.com ([10.12.231.107]) by orviesa002-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 01 Jan 2025 07:50:34 -0800 From: Alexander Usyskin To: Miquel Raynal , Richard Weinberger , Vignesh Raghavendra , Lucas De Marchi , =?UTF-8?q?Thomas=20Hellstr=C3=B6m?= , Rodrigo Vivi , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , Jani Nikula , Joonas Lahtinen , Tvrtko Ursulin , Karthik Poosa Cc: Reuven Abliyev , Oren Weil , linux-mtd@lists.infradead.org, dri-devel@lists.freedesktop.org, intel-gfx@lists.freedesktop.org, linux-kernel@vger.kernel.org, Alexander Usyskin Subject: [PATCH v4 01/11] mtd: core: always create master device Date: Wed, 1 Jan 2025 17:39:15 +0200 Message-ID: <20250101153925.865703-2-alexander.usyskin@intel.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250101153925.865703-1-alexander.usyskin@intel.com> References: <20250101153925.865703-1-alexander.usyskin@intel.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Create master device without partition when CONFIG_MTD_PARTITIONED_MASTER flag is unset. This streamlines device tree and allows to anchor runtime power management on master device in all cases. Signed-off-by: Alexander Usyskin --- drivers/mtd/mtdcore.c | 123 ++++++++++++++++++++++++++++++++---------- drivers/mtd/mtdpart.c | 6 +-- 2 files changed, 95 insertions(+), 34 deletions(-) diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 724f917f91ba..bbc502ef75de 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -68,7 +68,13 @@ static struct class mtd_class =3D { .pm =3D MTD_CLS_PM_OPS, }; =20 +static struct class mtd_master_class =3D { + .name =3D "mtd_master", + .pm =3D MTD_CLS_PM_OPS, +}; + static DEFINE_IDR(mtd_idr); +static DEFINE_IDR(mtd_master_idr); =20 /* These are exported solely for the purpose of mtd_blkdevs.c. You should not use them for _anything_ else */ @@ -83,8 +89,9 @@ EXPORT_SYMBOL_GPL(__mtd_next_device); =20 static LIST_HEAD(mtd_notifiers); =20 - +#define MTD_MASTER_DEVS 255 #define MTD_DEVT(index) MKDEV(MTD_CHAR_MAJOR, (index)*2) +static dev_t mtd_master_devt; =20 /* REVISIT once MTD uses the driver model better, whoever allocates * the mtd_info will probably want to use the release() hook... @@ -104,6 +111,17 @@ static void mtd_release(struct device *dev) device_destroy(&mtd_class, index + 1); } =20 +static void mtd_master_release(struct device *dev) +{ + struct mtd_info *mtd =3D dev_get_drvdata(dev); + + idr_remove(&mtd_master_idr, mtd->index); + of_node_put(mtd_get_of_node(mtd)); + + if (mtd_is_partition(mtd)) + release_mtd_partition(mtd); +} + static void mtd_device_release(struct kref *kref) { struct mtd_info *mtd =3D container_of(kref, struct mtd_info, refcnt); @@ -367,6 +385,11 @@ static const struct device_type mtd_devtype =3D { .release =3D mtd_release, }; =20 +static const struct device_type mtd_master_devtype =3D { + .name =3D "mtd_master", + .release =3D mtd_master_release, +}; + static bool mtd_expert_analysis_mode; =20 #ifdef CONFIG_DEBUG_FS @@ -639,12 +662,12 @@ static void mtd_check_of_node(struct mtd_info *mtd) * notify each currently active MTD 'user' of its arrival. Returns * zero on success or non-zero on failure. */ - int add_mtd_device(struct mtd_info *mtd) { struct device_node *np =3D mtd_get_of_node(mtd); struct mtd_info *master =3D mtd_get_master(mtd); struct mtd_notifier *not; + bool partitioned =3D true; int i, error, ofidx; =20 /* @@ -655,6 +678,11 @@ int add_mtd_device(struct mtd_info *mtd) if (WARN_ONCE(mtd->dev.type, "MTD already registered\n")) return -EEXIST; =20 + if ((master =3D=3D mtd) && !IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER)) { + partitioned =3D false; + pr_debug("mtd: unpartitioned master %s\n", mtd->name); + } + BUG_ON(mtd->writesize =3D=3D 0); =20 /* @@ -687,10 +715,17 @@ int add_mtd_device(struct mtd_info *mtd) ofidx =3D -1; if (np) ofidx =3D of_alias_get_id(np, "mtd"); - if (ofidx >=3D 0) - i =3D idr_alloc(&mtd_idr, mtd, ofidx, ofidx + 1, GFP_KERNEL); - else - i =3D idr_alloc(&mtd_idr, mtd, 0, 0, GFP_KERNEL); + if (partitioned) { + if (ofidx >=3D 0) + i =3D idr_alloc(&mtd_idr, mtd, ofidx, ofidx + 1, GFP_KERNEL); + else + i =3D idr_alloc(&mtd_idr, mtd, 0, 0, GFP_KERNEL); + } else { + if (ofidx >=3D 0) + i =3D idr_alloc(&mtd_master_idr, mtd, ofidx, ofidx + 1, GFP_KERNEL); + else + i =3D idr_alloc(&mtd_master_idr, mtd, 0, 0, GFP_KERNEL); + } if (i < 0) { error =3D i; goto fail_locked; @@ -738,15 +773,23 @@ int add_mtd_device(struct mtd_info *mtd) /* Caller should have set dev.parent to match the * physical device, if appropriate. */ - mtd->dev.type =3D &mtd_devtype; - mtd->dev.class =3D &mtd_class; - mtd->dev.devt =3D MTD_DEVT(i); - dev_set_name(&mtd->dev, "mtd%d", i); + if (partitioned) { + mtd->dev.type =3D &mtd_devtype; + mtd->dev.class =3D &mtd_class; + mtd->dev.devt =3D MTD_DEVT(i); + dev_set_name(&mtd->dev, "mtd%d", i); + } else { + mtd->dev.type =3D &mtd_master_devtype; + mtd->dev.class =3D &mtd_master_class; + mtd->dev.devt =3D MKDEV(MAJOR(mtd_master_devt), i); + dev_set_name(&mtd->dev, "mtd_master%d", i); + } dev_set_drvdata(&mtd->dev, mtd); mtd_check_of_node(mtd); of_node_get(mtd_get_of_node(mtd)); error =3D device_register(&mtd->dev); if (error) { + pr_err("mtd: %s device_register fail %d\n", mtd->name, error); put_device(&mtd->dev); goto fail_added; } @@ -758,8 +801,10 @@ int add_mtd_device(struct mtd_info *mtd) =20 mtd_debugfs_populate(mtd); =20 - device_create(&mtd_class, mtd->dev.parent, MTD_DEVT(i) + 1, NULL, - "mtd%dro", i); + if (partitioned) { + device_create(&mtd_class, mtd->dev.parent, MTD_DEVT(i) + 1, NULL, + "mtd%dro", i); + } =20 pr_debug("mtd: Giving out device %d to %s\n", i, mtd->name); /* No need to get a refcount on the module containing @@ -769,13 +814,16 @@ int add_mtd_device(struct mtd_info *mtd) =20 mutex_unlock(&mtd_table_mutex); =20 - if (of_property_read_bool(mtd_get_of_node(mtd), "linux,rootfs")) { - if (IS_BUILTIN(CONFIG_MTD)) { - pr_info("mtd: setting mtd%d (%s) as root device\n", mtd->index, mtd->na= me); - ROOT_DEV =3D MKDEV(MTD_BLOCK_MAJOR, mtd->index); - } else { - pr_warn("mtd: can't set mtd%d (%s) as root device - mtd must be builtin= \n", - mtd->index, mtd->name); + if (partitioned) { + if (of_property_read_bool(mtd_get_of_node(mtd), "linux,rootfs")) { + if (IS_BUILTIN(CONFIG_MTD)) { + pr_info("mtd: setting mtd%d (%s) as root device\n", + mtd->index, mtd->name); + ROOT_DEV =3D MKDEV(MTD_BLOCK_MAJOR, mtd->index); + } else { + pr_warn("mtd: can't set mtd%d (%s) as root device - mtd must be builti= n\n", + mtd->index, mtd->name); + } } } =20 @@ -790,7 +838,10 @@ int add_mtd_device(struct mtd_info *mtd) device_unregister(&mtd->dev); fail_added: of_node_put(mtd_get_of_node(mtd)); - idr_remove(&mtd_idr, i); + if (partitioned) + idr_remove(&mtd_idr, i); + else + idr_remove(&mtd_master_idr, i); fail_locked: mutex_unlock(&mtd_table_mutex); return error; @@ -1061,11 +1112,10 @@ int mtd_device_parse_register(struct mtd_info *mtd,= const char * const *types, if (ret) goto out; =20 - if (IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER)) { - ret =3D add_mtd_device(mtd); - if (ret) - goto out; - } + /* Master device */ + ret =3D add_mtd_device(mtd); + if (ret) + goto out; =20 /* Prefer parsed partitions over driver-provided fallback */ ret =3D parse_mtd_partitions(mtd, types, parser_data); @@ -1261,8 +1311,7 @@ int __get_mtd_device(struct mtd_info *mtd) mtd =3D mtd->parent; } =20 - if (IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER)) - kref_get(&master->refcnt); + kref_get(&master->refcnt); =20 return 0; } @@ -1356,8 +1405,7 @@ void __put_mtd_device(struct mtd_info *mtd) mtd =3D parent; } =20 - if (IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER)) - kref_put(&master->refcnt, mtd_device_release); + kref_put(&master->refcnt, mtd_device_release); =20 module_put(master->owner); =20 @@ -2524,6 +2572,16 @@ static int __init init_mtd(void) if (ret) goto err_reg; =20 + ret =3D class_register(&mtd_master_class); + if (ret) + goto err_reg2; + + ret =3D alloc_chrdev_region(&mtd_master_devt, 0, MTD_MASTER_DEVS, "mtd_ma= ster"); + if (ret < 0) { + pr_err("unable to allocate char dev region\n"); + goto err_chrdev; + } + mtd_bdi =3D mtd_bdi_init("mtd"); if (IS_ERR(mtd_bdi)) { ret =3D PTR_ERR(mtd_bdi); @@ -2548,6 +2606,10 @@ static int __init init_mtd(void) bdi_unregister(mtd_bdi); bdi_put(mtd_bdi); err_bdi: + unregister_chrdev_region(mtd_master_devt, MTD_MASTER_DEVS); +err_chrdev: + class_unregister(&mtd_master_class); +err_reg2: class_unregister(&mtd_class); err_reg: pr_err("Error registering mtd class or bdi: %d\n", ret); @@ -2561,9 +2623,12 @@ static void __exit cleanup_mtd(void) if (proc_mtd) remove_proc_entry("mtd", NULL); class_unregister(&mtd_class); + class_unregister(&mtd_master_class); + unregister_chrdev_region(mtd_master_devt, MTD_MASTER_DEVS); bdi_unregister(mtd_bdi); bdi_put(mtd_bdi); idr_destroy(&mtd_idr); + idr_destroy(&mtd_master_idr); } =20 module_init(init_mtd); diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index 6811a714349d..268c3d5ccdea 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -86,8 +86,7 @@ static struct mtd_info *allocate_partition(struct mtd_inf= o *parent, * parent conditional on that option. Note, this is a way to * distinguish between the parent and its partitions in sysfs. */ - child->dev.parent =3D IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER) || mtd_is= _partition(parent) ? - &parent->dev : parent->dev.parent; + child->dev.parent =3D &parent->dev; child->dev.of_node =3D part->of_node; child->parent =3D parent; child->part.offset =3D part->offset; @@ -590,9 +589,6 @@ static int mtd_part_of_parse(struct mtd_info *master, int ret, err =3D 0; =20 dev =3D &master->dev; - /* Use parent device (controller) if the top level MTD is not registered = */ - if (!IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER) && !mtd_is_partition(maste= r)) - dev =3D master->dev.parent; =20 np =3D mtd_get_of_node(master); if (mtd_is_partition(master)) --=20 2.43.0