1
0
Fork 0
mirror of https://github.com/Ysurac/openmptcprouter.git synced 2025-03-09 15:40:20 +00:00

Fix RUTX support

This commit is contained in:
Ycarus (Yannick Chabanois) 2022-03-07 20:21:35 +01:00
parent 6fc4d11e09
commit 0b14e36374
98 changed files with 11611 additions and 893 deletions

View file

@ -0,0 +1,80 @@
Index: linux-5.4.147/kernel/bpf/syscall.c
===================================================================
--- linux-5.4.147.orig/kernel/bpf/syscall.c
+++ linux-5.4.147/kernel/bpf/syscall.c
@@ -593,6 +593,11 @@ static int map_create(union bpf_attr *at
err = PTR_ERR(btf);
goto free_map;
}
+ if (btf_is_kernel(btf)) {
+ btf_put(btf);
+ err = -EACCES;
+ goto free_map;
+ }
err = map_check_btf(map, btf, attr->btf_key_type_id,
attr->btf_value_type_id);
Index: linux-5.4.147/kernel/bpf/verifier.c
===================================================================
--- linux-5.4.147.orig/kernel/bpf/verifier.c
+++ linux-5.4.147/kernel/bpf/verifier.c
@@ -6959,6 +6959,11 @@ static int check_btf_info(struct bpf_ver
btf = btf_get_by_fd(attr->prog_btf_fd);
if (IS_ERR(btf))
return PTR_ERR(btf);
+ if (btf_is_kernel(btf)) {
+ btf_put(btf);
+ return -EACCES;
+ }
+
env->prog->aux->btf = btf;
err = check_btf_func(env, attr, uattr);
Index: linux-5.4.147/include/linux/btf.h
===================================================================
--- linux-5.4.147.orig/include/linux/btf.h
+++ linux-5.4.147/include/linux/btf.h
@@ -47,6 +47,7 @@ void btf_type_seq_show(const struct btf
struct seq_file *m);
int btf_get_fd_by_id(u32 id);
u32 btf_id(const struct btf *btf);
+bool btf_is_kernel(const struct btf *btf);
bool btf_member_is_reg_int(const struct btf *btf, const struct btf_type *s,
const struct btf_member *m,
u32 expected_offset, u32 expected_size);
Index: linux-5.4.147/kernel/bpf/btf.c
===================================================================
--- linux-5.4.147.orig/kernel/bpf/btf.c
+++ linux-5.4.147/kernel/bpf/btf.c
@@ -212,6 +212,7 @@ struct btf {
refcount_t refcnt;
u32 id;
struct rcu_head rcu;
+ bool kernel_btf;
};
enum verifier_phase {
@@ -352,6 +353,11 @@ static bool btf_type_nosize(const struct
btf_type_is_func(t) || btf_type_is_func_proto(t);
}
+bool btf_is_kernel(const struct btf *btf)
+{
+ return btf->kernel_btf;
+}
+
static bool btf_type_nosize_or_null(const struct btf_type *t)
{
return !t || btf_type_nosize(t);
Index: linux-5.4.147/include/uapi/linux/bpf.h
===================================================================
--- linux-5.4.147.orig/include/uapi/linux/bpf.h
+++ linux-5.4.147/include/uapi/linux/bpf.h
@@ -3275,6 +3275,7 @@ struct bpf_btf_info {
__aligned_u64 btf;
__u32 btf_size;
__u32 id;
+ __u32 kernel_btf;
} __attribute__((aligned(8)));
/* User bpf_sock_addr struct to access socket fields and sockaddr struct passed

View file

@ -0,0 +1,53 @@
From: Bui Quang Minh @ 2021-01-26 8:26 UTC (permalink / raw)
To: ast, daniel, davem, kuba, hawk, john.fastabend, andrii, kafai,
songliubraving, yhs, kpsingh, jakub, lmb
Cc: netdev, bpf, linux-kernel, minhquangbui99
In 32-bit architecture, the result of sizeof() is a 32-bit integer so
the expression becomes the multiplication between 2 32-bit integer which
can potentially leads to integer overflow. As a result,
bpf_map_area_alloc() allocates less memory than needed.
Fix this by casting 1 operand to u64.
Signed-off-by: Bui Quang Minh <minhquangbui99@gmail.com>
---
kernel/bpf/devmap.c | 4 ++--
net/core/sock_map.c | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
Index: linux-5.4.147/kernel/bpf/devmap.c
===================================================================
--- linux-5.4.147.orig/kernel/bpf/devmap.c
+++ linux-5.4.147/kernel/bpf/devmap.c
@@ -94,7 +94,7 @@ static struct hlist_head *dev_map_create
int i;
struct hlist_head *hash;
- hash = bpf_map_area_alloc(entries * sizeof(*hash), numa_node);
+ hash = bpf_map_area_alloc((u64) entries * sizeof(*hash), numa_node);
if (hash != NULL)
for (i = 0; i < entries; i++)
INIT_HLIST_HEAD(&hash[i]);
@@ -159,7 +159,7 @@ static int dev_map_init_map(struct bpf_d
spin_lock_init(&dtab->index_lock);
} else {
- dtab->netdev_map = bpf_map_area_alloc(dtab->map.max_entries *
+ dtab->netdev_map = bpf_map_area_alloc((u64) dtab->map.max_entries *
sizeof(struct bpf_dtab_netdev *),
dtab->map.numa_node);
if (!dtab->netdev_map)
Index: linux-5.4.147/net/core/sock_map.c
===================================================================
--- linux-5.4.147.orig/net/core/sock_map.c
+++ linux-5.4.147/net/core/sock_map.c
@@ -48,7 +48,7 @@ static struct bpf_map *sock_map_alloc(un
if (err)
goto free_stab;
- stab->sks = bpf_map_area_alloc(stab->map.max_entries *
+ stab->sks = bpf_map_area_alloc((u64) stab->map.max_entries *
sizeof(struct sock *),
stab->map.numa_node);
if (stab->sks)

View file

@ -0,0 +1,48 @@
From 05acefb4872dae89e772729efb194af754c877e8 Mon Sep 17 00:00:00 2001
From: Miklos Szeredi <mszeredi@redhat.com>
Date: Tue, 2 Jun 2020 22:20:26 +0200
Subject: ovl: check permission to open real file
Call inode_permission() on real inode before opening regular file on one of
the underlying layers.
In some cases ovl_permission() already checks access to an underlying file,
but it misses the metacopy case, and possibly other ones as well.
Removing the redundant permission check from ovl_permission() should be
considered later.
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
---
fs/overlayfs/file.c | 16 ++++++++++++++--
1 file changed, 14 insertions(+), 2 deletions(-)
Index: linux-5.4.147/fs/overlayfs/file.c
===================================================================
--- linux-5.4.147.orig/fs/overlayfs/file.c
+++ linux-5.4.147/fs/overlayfs/file.c
@@ -34,10 +34,22 @@ static struct file *ovl_open_realfile(co
struct file *realfile;
const struct cred *old_cred;
int flags = file->f_flags | OVL_OPEN_FLAGS;
+ int acc_mode = ACC_MODE(flags);
+ int err;
+
+ if (flags & O_APPEND)
+ acc_mode |= MAY_APPEND;
old_cred = ovl_override_creds(inode->i_sb);
- realfile = open_with_fake_path(&file->f_path, flags, realinode,
- current_cred());
+ err = inode_permission(realinode, MAY_OPEN | acc_mode);
+ if (err) {
+ realfile = ERR_PTR(err);
+ } else if (!inode_owner_or_capable(realinode)) {
+ realfile = ERR_PTR(-EPERM);
+ } else {
+ realfile = open_with_fake_path(&file->f_path, flags, realinode,
+ current_cred());
+ }
revert_creds(old_cred);
pr_debug("open(%p[%pD2/%c], 0%o) -> (%p, 0%o)\n",

View file

@ -0,0 +1,73 @@
From 48bd024b8a40d73ad6b086de2615738da0c7004f Mon Sep 17 00:00:00 2001
From: Miklos Szeredi <mszeredi@redhat.com>
Date: Tue, 2 Jun 2020 22:20:25 +0200
Subject: ovl: switch to mounter creds in readdir
In preparation for more permission checking, override credentials for
directory operations on the underlying filesystems.
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
---
fs/overlayfs/readdir.c | 27 +++++++++++++++++++++------
1 file changed, 21 insertions(+), 6 deletions(-)
Index: linux-5.4.147/fs/overlayfs/readdir.c
===================================================================
--- linux-5.4.147.orig/fs/overlayfs/readdir.c
+++ linux-5.4.147/fs/overlayfs/readdir.c
@@ -732,8 +732,10 @@ static int ovl_iterate(struct file *file
struct ovl_dir_file *od = file->private_data;
struct dentry *dentry = file->f_path.dentry;
struct ovl_cache_entry *p;
+ const struct cred *old_cred;
int err;
+ old_cred = ovl_override_creds(dentry->d_sb);
if (!ctx->pos)
ovl_dir_reset(file);
@@ -747,17 +749,20 @@ static int ovl_iterate(struct file *file
(ovl_same_sb(dentry->d_sb) &&
(ovl_is_impure_dir(file) ||
OVL_TYPE_MERGE(ovl_path_type(dentry->d_parent))))) {
- return ovl_iterate_real(file, ctx);
+ err = ovl_iterate_real(file, ctx);
+ } else {
+ err = iterate_dir(od->realfile, ctx);
}
- return iterate_dir(od->realfile, ctx);
+ goto out;
}
if (!od->cache) {
struct ovl_dir_cache *cache;
cache = ovl_cache_get(dentry);
+ err = PTR_ERR(cache);
if (IS_ERR(cache))
- return PTR_ERR(cache);
+ goto out;
od->cache = cache;
ovl_seek_cursor(od, ctx->pos);
@@ -769,7 +774,7 @@ static int ovl_iterate(struct file *file
if (!p->ino) {
err = ovl_cache_update_ino(&file->f_path, p);
if (err)
- return err;
+ goto out;
}
if (!dir_emit(ctx, p->name, p->len, p->ino, p->type))
break;
@@ -777,7 +782,10 @@ static int ovl_iterate(struct file *file
od->cursor = p->l_node.next;
ctx->pos++;
}
- return 0;
+ err = 0;
+out:
+ revert_creds(old_cred);
+ return err;
}
static loff_t ovl_dir_llseek(struct file *file, loff_t offset, int origin)

View file

@ -0,0 +1,61 @@
From 56230d956739b9cb1cbde439d76227d77979a04d Mon Sep 17 00:00:00 2001
From: Miklos Szeredi <mszeredi@redhat.com>
Date: Tue, 2 Jun 2020 22:20:26 +0200
Subject: ovl: verify permissions in ovl_path_open()
Check permission before opening a real file.
ovl_path_open() is used by readdir and copy-up routines.
ovl_permission() theoretically already checked copy up permissions, but it
doesn't hurt to re-do these checks during the actual copy-up.
For directory reading ovl_permission() only checks access to topmost
underlying layer. Readdir on a merged directory accesses layers below the
topmost one as well. Permission wasn't checked for these layers.
Note: modifying ovl_permission() to perform this check would be far more
complex and hence more bug prone. The result is less precise permissions
returned in access(2). If this turns out to be an issue, we can revisit
this bug.
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
---
fs/overlayfs/util.c | 27 ++++++++++++++++++++++++++-
1 file changed, 26 insertions(+), 1 deletion(-)
Index: linux-5.4.147/fs/overlayfs/util.c
===================================================================
--- linux-5.4.147.orig/fs/overlayfs/util.c
+++ linux-5.4.147/fs/overlayfs/util.c
@@ -475,7 +475,29 @@ bool ovl_is_whiteout(struct dentry *dent
struct file *ovl_path_open(struct path *path, int flags)
{
- return dentry_open(path, flags | O_NOATIME, current_cred());
+ struct inode *inode = d_inode(path->dentry);
+ int err, acc_mode;
+
+ switch (flags & O_ACCMODE) {
+ case O_RDONLY:
+ acc_mode = MAY_READ;
+ break;
+ case O_WRONLY:
+ acc_mode = MAY_WRITE;
+ break;
+ default:
+ BUG();
+ }
+
+ err = inode_permission(inode, acc_mode | MAY_OPEN);
+ if (err)
+ return ERR_PTR(err);
+
+ /* O_NOATIME is an optimization, don't fail if not permitted */
+ if (inode_owner_or_capable(inode))
+ flags |= O_NOATIME;
+
+ return dentry_open(path, flags, current_cred());
}
/* Caller should hold ovl_inode->lock */

View file

@ -0,0 +1,46 @@
From b6650dab404c701d7fe08a108b746542a934da84 Mon Sep 17 00:00:00 2001
From: Miklos Szeredi <mszeredi@redhat.com>
Date: Mon, 14 Dec 2020 15:26:14 +0100
Subject: ovl: do not fail because of O_NOATIME
In case the file cannot be opened with O_NOATIME because of lack of
capabilities, then clear O_NOATIME instead of failing.
Remove WARN_ON(), since it would now trigger if O_NOATIME was cleared.
Noticed by Amir Goldstein.
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
---
fs/overlayfs/file.c | 11 +++--------
1 file changed, 3 insertions(+), 8 deletions(-)
Index: linux-5.4.147/fs/overlayfs/file.c
===================================================================
--- linux-5.4.147.orig/fs/overlayfs/file.c
+++ linux-5.4.147/fs/overlayfs/file.c
@@ -44,9 +44,10 @@ static struct file *ovl_open_realfile(co
err = inode_permission(realinode, MAY_OPEN | acc_mode);
if (err) {
realfile = ERR_PTR(err);
- } else if (!inode_owner_or_capable(realinode)) {
- realfile = ERR_PTR(-EPERM);
} else {
+ if (!inode_owner_or_capable(realinode))
+ flags &= ~O_NOATIME;
+
realfile = open_with_fake_path(&file->f_path, flags, realinode,
current_cred());
}
@@ -66,12 +67,6 @@ static int ovl_change_flags(struct file
struct inode *inode = file_inode(file);
int err;
- flags |= OVL_OPEN_FLAGS;
-
- /* If some flag changed that cannot be changed then something's amiss */
- if (WARN_ON((file->f_flags ^ flags) & ~OVL_SETFL_MASK))
- return -EIO;
-
flags &= OVL_SETFL_MASK;
if (((flags ^ file->f_flags) & O_APPEND) && IS_APPEND(inode))

View file

@ -0,0 +1,17 @@
Index: linux-5.4.124/drivers/net/ppp/pppoe.c
===================================================================
--- linux-5.4.124.orig/drivers/net/ppp/pppoe.c
+++ linux-5.4.124/drivers/net/ppp/pppoe.c
@@ -502,6 +502,12 @@ static int pppoe_disc_rcv(struct sk_buff
if (ph->code != PADT_CODE)
goto abort;
+ // compare the dst addr to the current net device addr and ignore packet if not matching
+ // otherwise it will terminate the connection
+ if(!ether_addr_equal(eth_hdr(skb)->h_dest, dev->dev_addr)) {
+ goto abort;
+ }
+
pn = pppoe_pernet(dev_net(dev));
po = get_item(pn, ph->sid, eth_hdr(skb)->h_source, dev->ifindex);
if (po)

View file

@ -0,0 +1,50 @@
Index: linux-5.4.124/drivers/mtd/spi-nor/spi-nor.c
===================================================================
--- linux-5.4.124.orig/drivers/mtd/spi-nor/spi-nor.c
+++ linux-5.4.124/drivers/mtd/spi-nor/spi-nor.c
@@ -2241,6 +2241,9 @@ static const struct flash_info spi_nor_i
.fixups = &gd25q256_fixups,
},
+ /* Zbit */
+ { "zb25vq128", INFO(0xC84018, 0, 64 * 1024, 64, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+
/* Intel/Numonyx -- xxxs33b */
{ "160s33b", INFO(0x898911, 0, 64 * 1024, 32, 0) },
{ "320s33b", INFO(0x898912, 0, 64 * 1024, 64, 0) },
@@ -2405,6 +2408,7 @@ static const struct flash_info spi_nor_i
{ "m25p32", INFO(0x202016, 0, 64 * 1024, 64, 0) },
{ "m25p64", INFO(0x202017, 0, 64 * 1024, 128, 0) },
{ "m25p128", INFO(0x202018, 0, 256 * 1024, 64, 0) },
+ { "n25q032", INFO(0x20ba16, 0, 64 * 1024, 64, 0) },
{ "m25p05-nonjedec", INFO(0, 0, 32 * 1024, 2, 0) },
{ "m25p10-nonjedec", INFO(0, 0, 32 * 1024, 4, 0) },
@@ -2508,10 +2512,14 @@ static const struct flash_info spi_nor_i
{ "XM25QH128A", INFO(0x207018, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
/* XTX Technology (Shenzhen) Limited */
+ { "XT25F128A", INFO(0x207018, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "xt25f128b", INFO(0x0B4018, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ },
};
+static const struct flash_info spi_nor_unknown_id =
+ { "undefined", INFO(0x0, 0, 64 * 1024, 256, SECT_4K) };
+
static const struct flash_info *spi_nor_read_id(struct spi_nor *nor)
{
int tmp;
@@ -2542,9 +2550,12 @@ static const struct flash_info *spi_nor_
return &spi_nor_ids[tmp];
}
}
+ return &spi_nor_unknown_id; // for Teltonikia RUT devices
+ /*
dev_err(nor->dev, "unrecognized JEDEC id bytes: %*ph\n",
SPI_NOR_MAX_ID_LEN, id);
return ERR_PTR(-ENODEV);
+ */
}
static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len,

View file

@ -0,0 +1,198 @@
From a07e31adf2753cad2fd9790db5bfc047c81e8152 Mon Sep 17 00:00:00 2001
From: Felix Matouschek <felix@matouschek.org>
Date: Fri, 2 Jul 2021 20:31:23 +0200
Subject: [PATCH] mtd: spinand: Add support for XTX XT26G0xA
Add support for XTX Technology XT26G01AXXXXX, XTX26G02AXXXXX and
XTX26G04AXXXXX SPI NAND.
These are 3V, 1G/2G/4Gbit serial SLC NAND flash devices with on-die ECC
(8bit strength per 512bytes).
Tested on Teltonika RUTX10 flashed with OpenWrt.
Datasheets available at
http://www.xtxtech.com/download/?AId=225
https://datasheet.lcsc.com/szlcsc/2005251034_XTX-XT26G01AWSEGA_C558841.pdf
Signed-off-by: Felix Matouschek <felix@matouschek.org>
---
drivers/mtd/nand/spi/Makefile | 2 +-
drivers/mtd/nand/spi/core.c | 1 +
drivers/mtd/nand/spi/xtx.c | 122 ++++++++++++++++++++++++++++++++++
include/linux/mtd/spinand.h | 1 +
4 files changed, 125 insertions(+), 1 deletion(-)
create mode 100644 drivers/mtd/nand/spi/xtx.c
Index: linux-5.4.132/drivers/mtd/nand/spi/Makefile
===================================================================
--- linux-5.4.132.orig/drivers/mtd/nand/spi/Makefile
+++ linux-5.4.132/drivers/mtd/nand/spi/Makefile
@@ -1,3 +1,3 @@
# SPDX-License-Identifier: GPL-2.0
-spinand-objs := core.o gigadevice.o macronix.o micron.o paragon.o toshiba.o winbond.o
+spinand-objs := core.o gigadevice.o macronix.o micron.o paragon.o toshiba.o winbond.o xtx.o
obj-$(CONFIG_MTD_SPI_NAND) += spinand.o
Index: linux-5.4.132/drivers/mtd/nand/spi/core.c
===================================================================
--- linux-5.4.132.orig/drivers/mtd/nand/spi/core.c
+++ linux-5.4.132/drivers/mtd/nand/spi/core.c
@@ -758,6 +758,7 @@ static const struct spinand_manufacturer
&paragon_spinand_manufacturer,
&toshiba_spinand_manufacturer,
&winbond_spinand_manufacturer,
+ &xtx_spinand_manufacturer,
};
static int spinand_manufacturer_detect(struct spinand_device *spinand)
Index: linux-5.4.132/drivers/mtd/nand/spi/xtx.c
===================================================================
--- /dev/null
+++ linux-5.4.132/drivers/mtd/nand/spi/xtx.c
@@ -0,0 +1,134 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Author:
+ * Felix Matouschek <felix@matouschek.org>
+ */
+
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/mtd/spinand.h>
+
+#define SPINAND_MFR_XTX 0x0B
+
+#define XT26G0XA_STATUS_ECC_MASK GENMASK(5, 2)
+#define XT26G0XA_STATUS_ECC_NO_DETECTED (0 << 2)
+#define XT26G0XA_STATUS_ECC_8_CORRECTED (3 << 4)
+#define XT26G0XA_STATUS_ECC_UNCOR_ERROR (2 << 4)
+
+static SPINAND_OP_VARIANTS(read_cache_variants,
+ SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 1, NULL, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
+
+static SPINAND_OP_VARIANTS(write_cache_variants,
+ SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
+ SPINAND_PROG_LOAD(true, 0, NULL, 0));
+
+static SPINAND_OP_VARIANTS(update_cache_variants,
+ SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
+ SPINAND_PROG_LOAD(false, 0, NULL, 0));
+
+static int xt26g0xa_ooblayout_ecc(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *region)
+{
+ if (section)
+ return -ERANGE;
+
+ region->offset = 8;
+ region->length = 40;
+
+ return 0;
+}
+
+static int xt26g0xa_ooblayout_free(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *region)
+{
+ if (section)
+ return -ERANGE;
+
+ region->offset = 1;
+ region->length = 7;
+
+ return 0;
+}
+
+static const struct mtd_ooblayout_ops xt26g0xa_ooblayout = {
+ .ecc = xt26g0xa_ooblayout_ecc,
+ .free = xt26g0xa_ooblayout_free,
+};
+
+static int xt26g0xa_ecc_get_status(struct spinand_device *spinand,
+ u8 status)
+{
+ switch (status & XT26G0XA_STATUS_ECC_MASK) {
+ case XT26G0XA_STATUS_ECC_NO_DETECTED:
+ return 0;
+ case XT26G0XA_STATUS_ECC_8_CORRECTED:
+ return 8;
+ case XT26G0XA_STATUS_ECC_UNCOR_ERROR:
+ return -EBADMSG;
+ default: /* (1 << 2) through (7 << 2) are 1-7 corrected errors */
+ return (status & XT26G0XA_STATUS_ECC_MASK) >> 2;
+ }
+
+ return -EINVAL;
+}
+
+static const struct spinand_info xtx_spinand_table[] = {
+ SPINAND_INFO("XT26G01A", 0xE1,
+ NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
+ NAND_ECCREQ(8, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ SPINAND_HAS_QE_BIT,
+ SPINAND_ECCINFO(&xt26g0xa_ooblayout,
+ xt26g0xa_ecc_get_status)),
+ SPINAND_INFO("XT26G02A", 0xE2,
+ NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 1, 1, 1),
+ NAND_ECCREQ(8, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ SPINAND_HAS_QE_BIT,
+ SPINAND_ECCINFO(&xt26g0xa_ooblayout,
+ xt26g0xa_ecc_get_status)),
+ SPINAND_INFO("XT26G04A", 0xE3,
+ NAND_MEMORG(1, 2048, 64, 128, 2048, 40, 1, 1, 1),
+ NAND_ECCREQ(8, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ SPINAND_HAS_QE_BIT,
+ SPINAND_ECCINFO(&xt26g0xa_ooblayout,
+ xt26g0xa_ecc_get_status)),
+};
+
+static int xtx_spinand_detect(struct spinand_device *spinand)
+{
+ u8 *id = spinand->id.data;
+ int ret;
+
+ if (id[1] != SPINAND_MFR_XTX)
+ return 0;
+
+ ret = spinand_match_and_init(spinand, xtx_spinand_table,
+ ARRAY_SIZE(xtx_spinand_table), id[2]);
+ if (ret)
+ return ret;
+
+ return 1;
+}
+
+static const struct spinand_manufacturer_ops xtx_spinand_manuf_ops = {
+ .detect = xtx_spinand_detect,
+};
+
+const struct spinand_manufacturer xtx_spinand_manufacturer = {
+ .id = SPINAND_MFR_XTX,
+ .name = "XTX",
+ .ops = &xtx_spinand_manuf_ops,
+};
Index: linux-5.4.132/include/linux/mtd/spinand.h
===================================================================
--- linux-5.4.132.orig/include/linux/mtd/spinand.h
+++ linux-5.4.132/include/linux/mtd/spinand.h
@@ -230,6 +230,7 @@ extern const struct spinand_manufacturer
extern const struct spinand_manufacturer paragon_spinand_manufacturer;
extern const struct spinand_manufacturer toshiba_spinand_manufacturer;
extern const struct spinand_manufacturer winbond_spinand_manufacturer;
+extern const struct spinand_manufacturer xtx_spinand_manufacturer;
/**
* struct spinand_op_variants - SPI NAND operation variants