hc
2024-05-10 10ebd8556b7990499c896a550e3d416b444211e6
kernel/include/linux/mtd/mtd.h
....@@ -1,20 +1,6 @@
1
+/* SPDX-License-Identifier: GPL-2.0-or-later */
12 /*
23 * Copyright © 1999-2010 David Woodhouse <dwmw2@infradead.org> et al.
3
- *
4
- * This program is free software; you can redistribute it and/or modify
5
- * it under the terms of the GNU General Public License as published by
6
- * the Free Software Foundation; either version 2 of the License, or
7
- * (at your option) any later version.
8
- *
9
- * This program is distributed in the hope that it will be useful,
10
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
- * GNU General Public License for more details.
13
- *
14
- * You should have received a copy of the GNU General Public License
15
- * along with this program; if not, write to the Free Software
16
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
- *
184 */
195
206 #ifndef __MTD_MTD_H__
....@@ -22,9 +8,11 @@
228
239 #include <linux/types.h>
2410 #include <linux/uio.h>
11
+#include <linux/list.h>
2512 #include <linux/notifier.h>
2613 #include <linux/device.h>
2714 #include <linux/of.h>
15
+#include <linux/nvmem-provider.h>
2816
2917 #include <mtd/mtd-abi.h>
3018
....@@ -202,6 +190,46 @@
202190 */
203191 struct mtd_debug_info {
204192 struct dentry *dfs_dir;
193
+
194
+ const char *partname;
195
+ const char *partid;
196
+};
197
+
198
+/**
199
+ * struct mtd_part - MTD partition specific fields
200
+ *
201
+ * @node: list node used to add an MTD partition to the parent partition list
202
+ * @offset: offset of the partition relatively to the parent offset
203
+ * @size: partition size. Should be equal to mtd->size unless
204
+ * MTD_SLC_ON_MLC_EMULATION is set
205
+ * @flags: original flags (before the mtdpart logic decided to tweak them based
206
+ * on flash constraints, like eraseblock/pagesize alignment)
207
+ *
208
+ * This struct is embedded in mtd_info and contains partition-specific
209
+ * properties/fields.
210
+ */
211
+struct mtd_part {
212
+ struct list_head node;
213
+ u64 offset;
214
+ u64 size;
215
+ u32 flags;
216
+};
217
+
218
+/**
219
+ * struct mtd_master - MTD master specific fields
220
+ *
221
+ * @partitions_lock: lock protecting accesses to the partition list. Protects
222
+ * not only the master partition list, but also all
223
+ * sub-partitions.
224
+ * @suspended: et to 1 when the device is suspended, 0 otherwise
225
+ *
226
+ * This struct is embedded in mtd_info and contains master-specific
227
+ * properties/fields. The master is the root MTD device from the MTD partition
228
+ * point of view.
229
+ */
230
+struct mtd_master {
231
+ struct mutex partitions_lock;
232
+ unsigned int suspended : 1;
205233 };
206234
207235 struct mtd_info {
....@@ -328,6 +356,12 @@
328356 int (*_get_device) (struct mtd_info *mtd);
329357 void (*_put_device) (struct mtd_info *mtd);
330358
359
+ /*
360
+ * flag indicates a panic write, low level drivers can take appropriate
361
+ * action if required to ensure writes go through
362
+ */
363
+ bool oops_panic_write;
364
+
331365 struct notifier_block reboot_notifier; /* default mode before reboot */
332366
333367 /* ECC status information */
....@@ -341,7 +375,50 @@
341375 struct device dev;
342376 int usecount;
343377 struct mtd_debug_info dbg;
378
+ struct nvmem_device *nvmem;
379
+
380
+ /*
381
+ * Parent device from the MTD partition point of view.
382
+ *
383
+ * MTD masters do not have any parent, MTD partitions do. The parent
384
+ * MTD device can itself be a partition.
385
+ */
386
+ struct mtd_info *parent;
387
+
388
+ /* List of partitions attached to this MTD device */
389
+ struct list_head partitions;
390
+
391
+ struct mtd_part part;
392
+ struct mtd_master master;
344393 };
394
+
395
+static inline struct mtd_info *mtd_get_master(struct mtd_info *mtd)
396
+{
397
+ while (mtd->parent)
398
+ mtd = mtd->parent;
399
+
400
+ return mtd;
401
+}
402
+
403
+static inline u64 mtd_get_master_ofs(struct mtd_info *mtd, u64 ofs)
404
+{
405
+ while (mtd->parent) {
406
+ ofs += mtd->part.offset;
407
+ mtd = mtd->parent;
408
+ }
409
+
410
+ return ofs;
411
+}
412
+
413
+static inline bool mtd_is_partition(const struct mtd_info *mtd)
414
+{
415
+ return mtd->parent;
416
+}
417
+
418
+static inline bool mtd_has_partitions(const struct mtd_info *mtd)
419
+{
420
+ return !list_empty(&mtd->partitions);
421
+}
345422
346423 int mtd_ooblayout_ecc(struct mtd_info *mtd, int section,
347424 struct mtd_oob_region *oobecc);
....@@ -394,13 +471,16 @@
394471 static inline int mtd_max_bad_blocks(struct mtd_info *mtd,
395472 loff_t ofs, size_t len)
396473 {
397
- if (!mtd->_max_bad_blocks)
474
+ struct mtd_info *master = mtd_get_master(mtd);
475
+
476
+ if (!master->_max_bad_blocks)
398477 return -ENOTSUPP;
399478
400479 if (mtd->size < (len + ofs) || ofs < 0)
401480 return -EINVAL;
402481
403
- return mtd->_max_bad_blocks(mtd, ofs, len);
482
+ return master->_max_bad_blocks(master, mtd_get_master_ofs(mtd, ofs),
483
+ len);
404484 }
405485
406486 int mtd_wunit_to_pairing_info(struct mtd_info *mtd, int wunit,
....@@ -441,8 +521,10 @@
441521
442522 static inline void mtd_sync(struct mtd_info *mtd)
443523 {
444
- if (mtd->_sync)
445
- mtd->_sync(mtd);
524
+ struct mtd_info *master = mtd_get_master(mtd);
525
+
526
+ if (master->_sync)
527
+ master->_sync(master);
446528 }
447529
448530 int mtd_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
....@@ -454,13 +536,31 @@
454536
455537 static inline int mtd_suspend(struct mtd_info *mtd)
456538 {
457
- return mtd->_suspend ? mtd->_suspend(mtd) : 0;
539
+ struct mtd_info *master = mtd_get_master(mtd);
540
+ int ret;
541
+
542
+ if (master->master.suspended)
543
+ return 0;
544
+
545
+ ret = master->_suspend ? master->_suspend(master) : 0;
546
+ if (ret)
547
+ return ret;
548
+
549
+ master->master.suspended = 1;
550
+ return 0;
458551 }
459552
460553 static inline void mtd_resume(struct mtd_info *mtd)
461554 {
462
- if (mtd->_resume)
463
- mtd->_resume(mtd);
555
+ struct mtd_info *master = mtd_get_master(mtd);
556
+
557
+ if (!master->master.suspended)
558
+ return;
559
+
560
+ if (master->_resume)
561
+ master->_resume(master);
562
+
563
+ master->master.suspended = 0;
464564 }
465565
466566 static inline uint32_t mtd_div_by_eb(uint64_t sz, struct mtd_info *mtd)
....@@ -523,7 +623,9 @@
523623
524624 static inline int mtd_wunit_per_eb(struct mtd_info *mtd)
525625 {
526
- return mtd->erasesize / mtd->writesize;
626
+ struct mtd_info *master = mtd_get_master(mtd);
627
+
628
+ return master->erasesize / mtd->writesize;
527629 }
528630
529631 static inline int mtd_offset_to_wunit(struct mtd_info *mtd, loff_t offs)
....@@ -540,7 +642,9 @@
540642
541643 static inline int mtd_has_oob(const struct mtd_info *mtd)
542644 {
543
- return mtd->_read_oob && mtd->_write_oob;
645
+ struct mtd_info *master = mtd_get_master((struct mtd_info *)mtd);
646
+
647
+ return master->_read_oob && master->_write_oob;
544648 }
545649
546650 static inline int mtd_type_is_nand(const struct mtd_info *mtd)
....@@ -550,7 +654,9 @@
550654
551655 static inline int mtd_can_have_bb(const struct mtd_info *mtd)
552656 {
553
- return !!mtd->_block_isbad;
657
+ struct mtd_info *master = mtd_get_master((struct mtd_info *)mtd);
658
+
659
+ return !!master->_block_isbad;
554660 }
555661
556662 /* Kernel-side ioctl definitions */