From 0d6b0d2e38167f4a3aa177191e3a10a9c3681a0c Mon Sep 17 00:00:00 2001 From: =?utf8?q?Pali=20Roh=C3=A1r?= Date: Thu, 3 Oct 2024 21:39:03 +0200 Subject: [PATCH 01/16] cifs: Recognize SFU char/block devices created by Windows NFS server on Windows Server <<2012 MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Windows NFS server versions on Windows Server older than 2012 release use for storing char and block devices modified SFU format, not compatible with the original SFU. Windows NFS server on Windows Server 2012 and new versions use different format (reparse points), not related to SFU-style. SFU / SUA / Interix subsystem stores the major and major numbers as pair of 64-bit integer, but Windows NFS server stores as pair of 32-bit integers. Which makes char and block devices between Windows NFS server <<2012 and Windows SFU/SUA/Interix subsytem incompatible. So improve Linux SMB client. When SFU mode is enabled (mount option -o sfu is specified) then recognize also these kind of char and block devices and its major and minor numbers, which are used by Windows Server versions older than 2012. Signed-off-by: Pali Rohár Signed-off-by: Steve French --- fs/smb/client/inode.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/fs/smb/client/inode.c b/fs/smb/client/inode.c index 72ebd72dd02b..de8063b44072 100644 --- a/fs/smb/client/inode.c +++ b/fs/smb/client/inode.c @@ -598,6 +598,17 @@ cifs_sfu_type(struct cifs_fattr *fattr, const char *path, mjr = le64_to_cpu(*(__le64 *)(pbuf+8)); mnr = le64_to_cpu(*(__le64 *)(pbuf+16)); fattr->cf_rdev = MKDEV(mjr, mnr); + } else if (bytes_read == 16) { + /* + * Windows NFS server before Windows Server 2012 + * stores major and minor number in SFU-modified + * style, just as 32-bit numbers. Recognize it. + */ + __u32 mjr; /* major */ + __u32 mnr; /* minor */ + mjr = le32_to_cpu(*(__le32 *)(pbuf+8)); + mnr = le32_to_cpu(*(__le32 *)(pbuf+12)); + fattr->cf_rdev = MKDEV(mjr, mnr); } } else if (memcmp("IntxCHR\0", pbuf, 8) == 0) { cifs_dbg(FYI, "Char device\n"); @@ -610,6 +621,17 @@ cifs_sfu_type(struct cifs_fattr *fattr, const char *path, mjr = le64_to_cpu(*(__le64 *)(pbuf+8)); mnr = le64_to_cpu(*(__le64 *)(pbuf+16)); fattr->cf_rdev = MKDEV(mjr, mnr); + } else if (bytes_read == 16) { + /* + * Windows NFS server before Windows Server 2012 + * stores major and minor number in SFU-modified + * style, just as 32-bit numbers. Recognize it. + */ + __u32 mjr; /* major */ + __u32 mnr; /* minor */ + mjr = le32_to_cpu(*(__le32 *)(pbuf+8)); + mnr = le32_to_cpu(*(__le32 *)(pbuf+12)); + fattr->cf_rdev = MKDEV(mjr, mnr); } } else if (memcmp("LnxSOCK", pbuf, 8) == 0) { cifs_dbg(FYI, "Socket\n"); -- 2.50.1 From 9ed9d83a51a9636d367c796252409e7b2f4de4d4 Mon Sep 17 00:00:00 2001 From: Steve French Date: Mon, 18 Nov 2024 12:19:46 -0600 Subject: [PATCH 02/16] smb3: request handle caching when caching directories This client was only requesting READ caching, not READ and HANDLE caching in the LeaseState on the open requests we send for directories. To delay closing a handle (e.g. for caching directory contents) we should be requesting HANDLE as well as READ (as we already do for deferred close of files). See MS-SMB2 3.3.1.4 e.g. Cc: stable@vger.kernel.org Signed-off-by: Steve French --- fs/smb/client/smb2ops.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c index 24a2aa04a108..7571fefeb83a 100644 --- a/fs/smb/client/smb2ops.c +++ b/fs/smb/client/smb2ops.c @@ -4080,7 +4080,7 @@ map_oplock_to_lease(u8 oplock) if (oplock == SMB2_OPLOCK_LEVEL_EXCLUSIVE) return SMB2_LEASE_WRITE_CACHING_LE | SMB2_LEASE_READ_CACHING_LE; else if (oplock == SMB2_OPLOCK_LEVEL_II) - return SMB2_LEASE_READ_CACHING_LE; + return SMB2_LEASE_READ_CACHING_LE | SMB2_LEASE_HANDLE_CACHING_LE; else if (oplock == SMB2_OPLOCK_LEVEL_BATCH) return SMB2_LEASE_HANDLE_CACHING_LE | SMB2_LEASE_READ_CACHING_LE | SMB2_LEASE_WRITE_CACHING_LE; -- 2.50.1 From bc925c1216f0848da96ac642fba3cb92ae1f4e06 Mon Sep 17 00:00:00 2001 From: Paulo Alcantara Date: Mon, 18 Nov 2024 12:35:14 -0300 Subject: [PATCH 03/16] smb: client: improve compound padding in encryption After commit f7f291e14dde ("cifs: fix oops during encryption"), the encryption layer can handle vmalloc'd buffers as well as kmalloc'd buffers, so there is no need to inefficiently squash request iovs into a single one to handle padding in compound requests. Cc: David Howells Signed-off-by: Paulo Alcantara (Red Hat) Signed-off-by: Steve French --- fs/smb/client/cifsglob.h | 4 ++-- fs/smb/client/smb2ops.c | 37 +++--------------------------------- fs/smb/client/transport.c | 40 +++++++++++++-------------------------- 3 files changed, 18 insertions(+), 63 deletions(-) diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h index 63d194ebbd7d..fc33dfe7e925 100644 --- a/fs/smb/client/cifsglob.h +++ b/fs/smb/client/cifsglob.h @@ -2230,7 +2230,7 @@ static inline int cifs_get_num_sgs(const struct smb_rqst *rqst, struct kvec *iov = &rqst[i].rq_iov[j]; addr = (unsigned long)iov->iov_base + skip; - if (unlikely(is_vmalloc_addr((void *)addr))) { + if (is_vmalloc_or_module_addr((void *)addr)) { len = iov->iov_len - skip; nents += DIV_ROUND_UP(offset_in_page(addr) + len, PAGE_SIZE); @@ -2257,7 +2257,7 @@ static inline void cifs_sg_set_buf(struct sg_table *sgtable, unsigned int off = offset_in_page(addr); addr &= PAGE_MASK; - if (unlikely(is_vmalloc_addr((void *)addr))) { + if (is_vmalloc_or_module_addr((void *)addr)) { do { unsigned int len = min_t(unsigned int, buflen, PAGE_SIZE - off); diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c index 7571fefeb83a..fa96ebed8310 100644 --- a/fs/smb/client/smb2ops.c +++ b/fs/smb/client/smb2ops.c @@ -2606,7 +2606,7 @@ smb2_set_next_command(struct cifs_tcon *tcon, struct smb_rqst *rqst) struct cifs_ses *ses = tcon->ses; struct TCP_Server_Info *server = ses->server; unsigned long len = smb_rqst_len(server, rqst); - int i, num_padding; + int num_padding; shdr = (struct smb2_hdr *)(rqst->rq_iov[0].iov_base); if (shdr == NULL) { @@ -2615,44 +2615,13 @@ smb2_set_next_command(struct cifs_tcon *tcon, struct smb_rqst *rqst) } /* SMB headers in a compound are 8 byte aligned. */ - - /* No padding needed */ - if (!(len & 7)) - goto finished; - - num_padding = 8 - (len & 7); - if (!smb3_encryption_required(tcon)) { - /* - * If we do not have encryption then we can just add an extra - * iov for the padding. - */ + if (!IS_ALIGNED(len, 8)) { + num_padding = 8 - (len & 7); rqst->rq_iov[rqst->rq_nvec].iov_base = smb2_padding; rqst->rq_iov[rqst->rq_nvec].iov_len = num_padding; rqst->rq_nvec++; len += num_padding; - } else { - /* - * We can not add a small padding iov for the encryption case - * because the encryption framework can not handle the padding - * iovs. - * We have to flatten this into a single buffer and add - * the padding to it. - */ - for (i = 1; i < rqst->rq_nvec; i++) { - memcpy(rqst->rq_iov[0].iov_base + - rqst->rq_iov[0].iov_len, - rqst->rq_iov[i].iov_base, - rqst->rq_iov[i].iov_len); - rqst->rq_iov[0].iov_len += rqst->rq_iov[i].iov_len; - } - memset(rqst->rq_iov[0].iov_base + rqst->rq_iov[0].iov_len, - 0, num_padding); - rqst->rq_iov[0].iov_len += num_padding; - len += num_padding; - rqst->rq_nvec = 1; } - - finished: shdr->NextCommand = cpu_to_le32(len); } diff --git a/fs/smb/client/transport.c b/fs/smb/client/transport.c index 91812150186c..0dc80959ce48 100644 --- a/fs/smb/client/transport.c +++ b/fs/smb/client/transport.c @@ -418,19 +418,16 @@ out: return rc; } -struct send_req_vars { - struct smb2_transform_hdr tr_hdr; - struct smb_rqst rqst[MAX_COMPOUND]; - struct kvec iov; -}; - static int smb_send_rqst(struct TCP_Server_Info *server, int num_rqst, struct smb_rqst *rqst, int flags) { - struct send_req_vars *vars; - struct smb_rqst *cur_rqst; - struct kvec *iov; + struct smb2_transform_hdr tr_hdr; + struct smb_rqst new_rqst[MAX_COMPOUND] = {}; + struct kvec iov = { + .iov_base = &tr_hdr, + .iov_len = sizeof(tr_hdr), + }; int rc; if (flags & CIFS_COMPRESS_REQ) @@ -447,26 +444,15 @@ smb_send_rqst(struct TCP_Server_Info *server, int num_rqst, return -EIO; } - vars = kzalloc(sizeof(*vars), GFP_NOFS); - if (!vars) - return -ENOMEM; - cur_rqst = vars->rqst; - iov = &vars->iov; - - iov->iov_base = &vars->tr_hdr; - iov->iov_len = sizeof(vars->tr_hdr); - cur_rqst[0].rq_iov = iov; - cur_rqst[0].rq_nvec = 1; + new_rqst[0].rq_iov = &iov; + new_rqst[0].rq_nvec = 1; rc = server->ops->init_transform_rq(server, num_rqst + 1, - &cur_rqst[0], rqst); - if (rc) - goto out; - - rc = __smb_send_rqst(server, num_rqst + 1, &cur_rqst[0]); - smb3_free_compound_rqst(num_rqst, &cur_rqst[1]); -out: - kfree(vars); + new_rqst, rqst); + if (!rc) { + rc = __smb_send_rqst(server, num_rqst + 1, new_rqst); + smb3_free_compound_rqst(num_rqst, &new_rqst[1]); + } return rc; } -- 2.50.1 From 9f544d26b15bfc52cf3a6e6a655f759e76c1a01a Mon Sep 17 00:00:00 2001 From: Paulo Alcantara Date: Mon, 18 Nov 2024 12:35:15 -0300 Subject: [PATCH 04/16] smb: client: get rid of bounds check in SMB2_ioctl_init() smb2_set_next_command() no longer squashes request iovs into a single iov, so the bounds check can be dropped. Cc: David Howells Signed-off-by: Paulo Alcantara (Red Hat) Signed-off-by: Steve French --- fs/smb/client/smb2pdu.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c index ab3a2ca66be3..055236835537 100644 --- a/fs/smb/client/smb2pdu.c +++ b/fs/smb/client/smb2pdu.c @@ -3313,15 +3313,6 @@ SMB2_ioctl_init(struct cifs_tcon *tcon, struct TCP_Server_Info *server, return rc; if (indatalen) { - unsigned int len; - - if (WARN_ON_ONCE(smb3_encryption_required(tcon) && - (check_add_overflow(total_len - 1, - ALIGN(indatalen, 8), &len) || - len > MAX_CIFS_SMALL_BUFFER_SIZE))) { - cifs_small_buf_release(req); - return -EIO; - } /* * indatalen is usually small at a couple of bytes max, so * just allocate through generic pool -- 2.50.1 From 0812340811e45ec4039d409049be53056182a552 Mon Sep 17 00:00:00 2001 From: Paulo Alcantara Date: Mon, 18 Nov 2024 12:35:16 -0300 Subject: [PATCH 05/16] smb: client: handle max length for SMB symlinks We can't use PATH_MAX for SMB symlinks because (1) Windows Server will fail FSCTL_SET_REPARSE_POINT with STATUS_IO_REPARSE_DATA_INVALID when input buffer is larger than 16K, as specified in MS-FSA 2.1.5.10.37. (2) The client won't be able to parse large SMB responses that includes SMB symlink path within SMB2_CREATE or SMB2_IOCTL responses. Fix this by defining a maximum length value (4060) for SMB symlinks that both client and server can handle. Cc: David Howells Cc: stable@vger.kernel.org Signed-off-by: Paulo Alcantara (Red Hat) Signed-off-by: Steve French --- fs/smb/client/reparse.c | 5 ++++- fs/smb/client/reparse.h | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/fs/smb/client/reparse.c b/fs/smb/client/reparse.c index 74abbdf5026c..90da1e2b6217 100644 --- a/fs/smb/client/reparse.c +++ b/fs/smb/client/reparse.c @@ -35,6 +35,9 @@ int smb2_create_reparse_symlink(const unsigned int xid, struct inode *inode, u16 len, plen; int rc = 0; + if (strlen(symname) > REPARSE_SYM_PATH_MAX) + return -ENAMETOOLONG; + sym = kstrdup(symname, GFP_KERNEL); if (!sym) return -ENOMEM; @@ -64,7 +67,7 @@ int smb2_create_reparse_symlink(const unsigned int xid, struct inode *inode, if (rc < 0) goto out; - plen = 2 * UniStrnlen((wchar_t *)path, PATH_MAX); + plen = 2 * UniStrnlen((wchar_t *)path, REPARSE_SYM_PATH_MAX); len = sizeof(*buf) + plen * 2; buf = kzalloc(len, GFP_KERNEL); if (!buf) { diff --git a/fs/smb/client/reparse.h b/fs/smb/client/reparse.h index 158e7b7aae64..2a9f4f9f79de 100644 --- a/fs/smb/client/reparse.h +++ b/fs/smb/client/reparse.h @@ -12,6 +12,8 @@ #include "fs_context.h" #include "cifsglob.h" +#define REPARSE_SYM_PATH_MAX 4060 + /* * Used only by cifs.ko to ignore reparse points from files when client or * server doesn't support FSCTL_GET_REPARSE_POINT. -- 2.50.1 From 7afb86733685c64c604d32faf00fa4a1f22c2ab1 Mon Sep 17 00:00:00 2001 From: Paul Aurich Date: Mon, 18 Nov 2024 13:50:26 -0800 Subject: [PATCH 06/16] smb: Don't leak cfid when reconnect races with open_cached_dir open_cached_dir() may either race with the tcon reconnection even before compound_send_recv() or directly trigger a reconnection via SMB2_open_init() or SMB_query_info_init(). The reconnection process invokes invalidate_all_cached_dirs() via cifs_mark_open_files_invalid(), which removes all cfids from the cfids->entries list but doesn't drop a ref if has_lease isn't true. This results in the currently-being-constructed cfid not being on the list, but still having a refcount of 2. It leaks if returned from open_cached_dir(). Fix this by setting cfid->has_lease when the ref is actually taken; the cfid will not be used by other threads until it has a valid time. Addresses these kmemleaks: unreferenced object 0xffff8881090c4000 (size 1024): comm "bash", pid 1860, jiffies 4295126592 hex dump (first 32 bytes): 00 01 00 00 00 00 ad de 22 01 00 00 00 00 ad de ........"....... 00 ca 45 22 81 88 ff ff f8 dc 4f 04 81 88 ff ff ..E"......O..... backtrace (crc 6f58c20f): [] __kmalloc_cache_noprof+0x2be/0x350 [] open_cached_dir+0x993/0x1fb0 [] cifs_readdir+0x15a0/0x1d50 [] iterate_dir+0x28f/0x4b0 [] __x64_sys_getdents64+0xfd/0x200 [] do_syscall_64+0x95/0x1a0 [] entry_SYSCALL_64_after_hwframe+0x76/0x7e unreferenced object 0xffff8881044fdcf8 (size 8): comm "bash", pid 1860, jiffies 4295126592 hex dump (first 8 bytes): 00 cc cc cc cc cc cc cc ........ backtrace (crc 10c106a9): [] __kmalloc_node_track_caller_noprof+0x363/0x480 [] kstrdup+0x36/0x60 [] open_cached_dir+0x9b0/0x1fb0 [] cifs_readdir+0x15a0/0x1d50 [] iterate_dir+0x28f/0x4b0 [] __x64_sys_getdents64+0xfd/0x200 [] do_syscall_64+0x95/0x1a0 [] entry_SYSCALL_64_after_hwframe+0x76/0x7e And addresses these BUG splats when unmounting the SMB filesystem: BUG: Dentry ffff888140590ba0{i=1000000000080,n=/} still in use (2) [unmount of cifs cifs] WARNING: CPU: 3 PID: 3433 at fs/dcache.c:1536 umount_check+0xd0/0x100 Modules linked in: CPU: 3 UID: 0 PID: 3433 Comm: bash Not tainted 6.12.0-rc4-g850925a8133c-dirty #49 Hardware name: VMware, Inc. VMware Virtual Platform/440BX Desktop Reference Platform, BIOS 6.00 11/12/2020 RIP: 0010:umount_check+0xd0/0x100 Code: 8d 7c 24 40 e8 31 5a f4 ff 49 8b 54 24 40 41 56 49 89 e9 45 89 e8 48 89 d9 41 57 48 89 de 48 c7 c7 80 e7 db ac e8 f0 72 9a ff <0f> 0b 58 31 c0 5a 5b 5d 41 5c 41 5d 41 5e 41 5f e9 2b e5 5d 01 41 RSP: 0018:ffff88811cc27978 EFLAGS: 00010286 RAX: 0000000000000000 RBX: ffff888140590ba0 RCX: ffffffffaaf20bae RDX: dffffc0000000000 RSI: 0000000000000008 RDI: ffff8881f6fb6f40 RBP: ffff8881462ec000 R08: 0000000000000001 R09: ffffed1023984ee3 R10: ffff88811cc2771f R11: 00000000016cfcc0 R12: ffff888134383e08 R13: 0000000000000002 R14: ffff8881462ec668 R15: ffffffffaceab4c0 FS: 00007f23bfa98740(0000) GS:ffff8881f6f80000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000556de4a6f808 CR3: 0000000123c80000 CR4: 0000000000350ef0 Call Trace: d_walk+0x6a/0x530 shrink_dcache_for_umount+0x6a/0x200 generic_shutdown_super+0x52/0x2a0 kill_anon_super+0x22/0x40 cifs_kill_sb+0x159/0x1e0 deactivate_locked_super+0x66/0xe0 cleanup_mnt+0x140/0x210 task_work_run+0xfb/0x170 syscall_exit_to_user_mode+0x29f/0x2b0 do_syscall_64+0xa1/0x1a0 entry_SYSCALL_64_after_hwframe+0x76/0x7e RIP: 0033:0x7f23bfb93ae7 Code: ff ff ff ff c3 66 0f 1f 44 00 00 48 8b 0d 11 93 0d 00 f7 d8 64 89 01 b8 ff ff ff ff eb bf 0f 1f 44 00 00 b8 50 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d e9 92 0d 00 f7 d8 64 89 01 48 RSP: 002b:00007ffee9138598 EFLAGS: 00000246 ORIG_RAX: 0000000000000050 RAX: 0000000000000000 RBX: 0000558f1803e9a0 RCX: 00007f23bfb93ae7 RDX: 0000000000000000 RSI: 0000000000000004 RDI: 0000558f1803e9a0 RBP: 0000558f1803e600 R08: 0000000000000007 R09: 0000558f17fab610 R10: d91d5ec34ab757b0 R11: 0000000000000246 R12: 0000000000000001 R13: 0000000000000000 R14: 0000000000000015 R15: 0000000000000000 irq event stamp: 1163486 hardirqs last enabled at (1163485): [] _raw_spin_unlock_irqrestore+0x34/0x60 hardirqs last disabled at (1163486): [] __schedule+0xc7c/0x19a0 softirqs last enabled at (1163482): [] __smb_send_rqst+0x3de/0x990 softirqs last disabled at (1163480): [] release_sock+0x21/0xf0 ---[ end trace 0000000000000000 ]--- VFS: Busy inodes after unmount of cifs (cifs) ------------[ cut here ]------------ kernel BUG at fs/super.c:661! Oops: invalid opcode: 0000 [#1] PREEMPT SMP KASAN NOPTI CPU: 1 UID: 0 PID: 3433 Comm: bash Tainted: G W 6.12.0-rc4-g850925a8133c-dirty #49 Tainted: [W]=WARN Hardware name: VMware, Inc. VMware Virtual Platform/440BX Desktop Reference Platform, BIOS 6.00 11/12/2020 RIP: 0010:generic_shutdown_super+0x290/0x2a0 Code: e8 15 7c f7 ff 48 8b 5d 28 48 89 df e8 09 7c f7 ff 48 8b 0b 48 89 ee 48 8d 95 68 06 00 00 48 c7 c7 80 7f db ac e8 00 69 af ff <0f> 0b 66 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 00 90 90 90 90 90 90 RSP: 0018:ffff88811cc27a50 EFLAGS: 00010246 RAX: 000000000000003e RBX: ffffffffae994420 RCX: 0000000000000027 RDX: 0000000000000000 RSI: ffffffffab06180e RDI: ffff8881f6eb18c8 RBP: ffff8881462ec000 R08: 0000000000000001 R09: ffffed103edd6319 R10: ffff8881f6eb18cb R11: 00000000016d3158 R12: ffff8881462ec9c0 R13: ffff8881462ec050 R14: 0000000000000001 R15: 0000000000000000 FS: 00007f23bfa98740(0000) GS:ffff8881f6e80000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007f8364005d68 CR3: 0000000123c80000 CR4: 0000000000350ef0 Call Trace: kill_anon_super+0x22/0x40 cifs_kill_sb+0x159/0x1e0 deactivate_locked_super+0x66/0xe0 cleanup_mnt+0x140/0x210 task_work_run+0xfb/0x170 syscall_exit_to_user_mode+0x29f/0x2b0 do_syscall_64+0xa1/0x1a0 entry_SYSCALL_64_after_hwframe+0x76/0x7e RIP: 0033:0x7f23bfb93ae7 Modules linked in: ---[ end trace 0000000000000000 ]--- RIP: 0010:generic_shutdown_super+0x290/0x2a0 Code: e8 15 7c f7 ff 48 8b 5d 28 48 89 df e8 09 7c f7 ff 48 8b 0b 48 89 ee 48 8d 95 68 06 00 00 48 c7 c7 80 7f db ac e8 00 69 af ff <0f> 0b 66 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 00 90 90 90 90 90 90 RSP: 0018:ffff88811cc27a50 EFLAGS: 00010246 RAX: 000000000000003e RBX: ffffffffae994420 RCX: 0000000000000027 RDX: 0000000000000000 RSI: ffffffffab06180e RDI: ffff8881f6eb18c8 RBP: ffff8881462ec000 R08: 0000000000000001 R09: ffffed103edd6319 R10: ffff8881f6eb18cb R11: 00000000016d3158 R12: ffff8881462ec9c0 R13: ffff8881462ec050 R14: 0000000000000001 R15: 0000000000000000 FS: 00007f23bfa98740(0000) GS:ffff8881f6e80000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007f8364005d68 CR3: 0000000123c80000 CR4: 0000000000350ef0 This reproduces eventually with an SMB mount and two shells running these loops concurrently - while true; do cd ~; sleep 1; for i in {1..3}; do cd /mnt/test/subdir; echo $PWD; sleep 1; cd ..; echo $PWD; sleep 1; done; echo ...; done - while true; do iptables -F OUTPUT; mount -t cifs -a; for _ in {0..2}; do ls /mnt/test/subdir/ | wc -l; done; iptables -I OUTPUT -p tcp --dport 445 -j DROP; sleep 10 echo "unmounting"; umount -l -t cifs -a; echo "done unmounting"; sleep 20 echo "recovering"; iptables -F OUTPUT; sleep 10; done Fixes: ebe98f1447bb ("cifs: enable caching of directories for which a lease is held") Fixes: 5c86919455c1 ("smb: client: fix use-after-free in smb2_query_info_compound()") Cc: stable@vger.kernel.org Signed-off-by: Paul Aurich Signed-off-by: Steve French --- fs/smb/client/cached_dir.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/fs/smb/client/cached_dir.c b/fs/smb/client/cached_dir.c index adcba1335204..bb9d4c284ce5 100644 --- a/fs/smb/client/cached_dir.c +++ b/fs/smb/client/cached_dir.c @@ -59,6 +59,16 @@ static struct cached_fid *find_or_create_cached_dir(struct cached_fids *cfids, list_add(&cfid->entry, &cfids->entries); cfid->on_list = true; kref_get(&cfid->refcount); + /* + * Set @cfid->has_lease to true during construction so that the lease + * reference can be put in cached_dir_lease_break() due to a potential + * lease break right after the request is sent or while @cfid is still + * being cached, or if a reconnection is triggered during construction. + * Concurrent processes won't be to use it yet due to @cfid->time being + * zero. + */ + cfid->has_lease = true; + spin_unlock(&cfids->cfid_list_lock); return cfid; } @@ -176,12 +186,12 @@ replay_again: return -ENOENT; } /* - * Return cached fid if it has a lease. Otherwise, it is either a new - * entry or laundromat worker removed it from @cfids->entries. Caller - * will put last reference if the latter. + * Return cached fid if it is valid (has a lease and has a time). + * Otherwise, it is either a new entry or laundromat worker removed it + * from @cfids->entries. Caller will put last reference if the latter. */ spin_lock(&cfids->cfid_list_lock); - if (cfid->has_lease) { + if (cfid->has_lease && cfid->time) { spin_unlock(&cfids->cfid_list_lock); *ret_cfid = cfid; kfree(utf16_path); @@ -267,15 +277,6 @@ replay_again: smb2_set_related(&rqst[1]); - /* - * Set @cfid->has_lease to true before sending out compounded request so - * its lease reference can be put in cached_dir_lease_break() due to a - * potential lease break right after the request is sent or while @cfid - * is still being cached. Concurrent processes won't be to use it yet - * due to @cfid->time being zero. - */ - cfid->has_lease = true; - if (retries) { smb2_set_replay(server, &rqst[0]); smb2_set_replay(server, &rqst[1]); -- 2.50.1 From a9685b409a03b73d2980bbfa53eb47555802d0a9 Mon Sep 17 00:00:00 2001 From: Paul Aurich Date: Mon, 18 Nov 2024 13:50:27 -0800 Subject: [PATCH 07/16] smb: prevent use-after-free due to open_cached_dir error paths If open_cached_dir() encounters an error parsing the lease from the server, the error handling may race with receiving a lease break, resulting in open_cached_dir() freeing the cfid while the queued work is pending. Update open_cached_dir() to drop refs rather than directly freeing the cfid. Have cached_dir_lease_break(), cfids_laundromat_worker(), and invalidate_all_cached_dirs() clear has_lease immediately while still holding cfids->cfid_list_lock, and then use this to also simplify the reference counting in cfids_laundromat_worker() and invalidate_all_cached_dirs(). Fixes this KASAN splat (which manually injects an error and lease break in open_cached_dir()): ================================================================== BUG: KASAN: slab-use-after-free in smb2_cached_lease_break+0x27/0xb0 Read of size 8 at addr ffff88811cc24c10 by task kworker/3:1/65 CPU: 3 UID: 0 PID: 65 Comm: kworker/3:1 Not tainted 6.12.0-rc6-g255cf264e6e5-dirty #87 Hardware name: VMware, Inc. VMware Virtual Platform/440BX Desktop Reference Platform, BIOS 6.00 11/12/2020 Workqueue: cifsiod smb2_cached_lease_break Call Trace: dump_stack_lvl+0x77/0xb0 print_report+0xce/0x660 kasan_report+0xd3/0x110 smb2_cached_lease_break+0x27/0xb0 process_one_work+0x50a/0xc50 worker_thread+0x2ba/0x530 kthread+0x17c/0x1c0 ret_from_fork+0x34/0x60 ret_from_fork_asm+0x1a/0x30 Allocated by task 2464: kasan_save_stack+0x33/0x60 kasan_save_track+0x14/0x30 __kasan_kmalloc+0xaa/0xb0 open_cached_dir+0xa7d/0x1fb0 smb2_query_path_info+0x43c/0x6e0 cifs_get_fattr+0x346/0xf10 cifs_get_inode_info+0x157/0x210 cifs_revalidate_dentry_attr+0x2d1/0x460 cifs_getattr+0x173/0x470 vfs_statx_path+0x10f/0x160 vfs_statx+0xe9/0x150 vfs_fstatat+0x5e/0xc0 __do_sys_newfstatat+0x91/0xf0 do_syscall_64+0x95/0x1a0 entry_SYSCALL_64_after_hwframe+0x76/0x7e Freed by task 2464: kasan_save_stack+0x33/0x60 kasan_save_track+0x14/0x30 kasan_save_free_info+0x3b/0x60 __kasan_slab_free+0x51/0x70 kfree+0x174/0x520 open_cached_dir+0x97f/0x1fb0 smb2_query_path_info+0x43c/0x6e0 cifs_get_fattr+0x346/0xf10 cifs_get_inode_info+0x157/0x210 cifs_revalidate_dentry_attr+0x2d1/0x460 cifs_getattr+0x173/0x470 vfs_statx_path+0x10f/0x160 vfs_statx+0xe9/0x150 vfs_fstatat+0x5e/0xc0 __do_sys_newfstatat+0x91/0xf0 do_syscall_64+0x95/0x1a0 entry_SYSCALL_64_after_hwframe+0x76/0x7e Last potentially related work creation: kasan_save_stack+0x33/0x60 __kasan_record_aux_stack+0xad/0xc0 insert_work+0x32/0x100 __queue_work+0x5c9/0x870 queue_work_on+0x82/0x90 open_cached_dir+0x1369/0x1fb0 smb2_query_path_info+0x43c/0x6e0 cifs_get_fattr+0x346/0xf10 cifs_get_inode_info+0x157/0x210 cifs_revalidate_dentry_attr+0x2d1/0x460 cifs_getattr+0x173/0x470 vfs_statx_path+0x10f/0x160 vfs_statx+0xe9/0x150 vfs_fstatat+0x5e/0xc0 __do_sys_newfstatat+0x91/0xf0 do_syscall_64+0x95/0x1a0 entry_SYSCALL_64_after_hwframe+0x76/0x7e The buggy address belongs to the object at ffff88811cc24c00 which belongs to the cache kmalloc-1k of size 1024 The buggy address is located 16 bytes inside of freed 1024-byte region [ffff88811cc24c00, ffff88811cc25000) Cc: stable@vger.kernel.org Signed-off-by: Paul Aurich Signed-off-by: Steve French --- fs/smb/client/cached_dir.c | 70 ++++++++++++++++---------------------- 1 file changed, 29 insertions(+), 41 deletions(-) diff --git a/fs/smb/client/cached_dir.c b/fs/smb/client/cached_dir.c index bb9d4c284ce5..06eb19dabb0e 100644 --- a/fs/smb/client/cached_dir.c +++ b/fs/smb/client/cached_dir.c @@ -348,6 +348,7 @@ oshr_free: SMB2_query_info_free(&rqst[1]); free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base); free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base); +out: if (rc) { spin_lock(&cfids->cfid_list_lock); if (cfid->on_list) { @@ -359,23 +360,14 @@ oshr_free: /* * We are guaranteed to have two references at this * point. One for the caller and one for a potential - * lease. Release the Lease-ref so that the directory - * will be closed when the caller closes the cached - * handle. + * lease. Release one here, and the second below. */ cfid->has_lease = false; - spin_unlock(&cfids->cfid_list_lock); kref_put(&cfid->refcount, smb2_close_cached_fid); - goto out; } spin_unlock(&cfids->cfid_list_lock); - } -out: - if (rc) { - if (cfid->is_open) - SMB2_close(0, cfid->tcon, cfid->fid.persistent_fid, - cfid->fid.volatile_fid); - free_cached_dir(cfid); + + kref_put(&cfid->refcount, smb2_close_cached_fid); } else { *ret_cfid = cfid; atomic_inc(&tcon->num_remote_opens); @@ -513,25 +505,24 @@ void invalidate_all_cached_dirs(struct cifs_tcon *tcon) cfids->num_entries--; cfid->is_open = false; cfid->on_list = false; - /* To prevent race with smb2_cached_lease_break() */ - kref_get(&cfid->refcount); + if (cfid->has_lease) { + /* + * The lease was never cancelled from the server, + * so steal that reference. + */ + cfid->has_lease = false; + } else + kref_get(&cfid->refcount); } spin_unlock(&cfids->cfid_list_lock); list_for_each_entry_safe(cfid, q, &entry, entry) { list_del(&cfid->entry); cancel_work_sync(&cfid->lease_break); - if (cfid->has_lease) { - /* - * We lease was never cancelled from the server so we - * need to drop the reference. - */ - spin_lock(&cfids->cfid_list_lock); - cfid->has_lease = false; - spin_unlock(&cfids->cfid_list_lock); - kref_put(&cfid->refcount, smb2_close_cached_fid); - } - /* Drop the extra reference opened above*/ + /* + * Drop the ref-count from above, either the lease-ref (if there + * was one) or the extra one acquired. + */ kref_put(&cfid->refcount, smb2_close_cached_fid); } } @@ -542,9 +533,6 @@ smb2_cached_lease_break(struct work_struct *work) struct cached_fid *cfid = container_of(work, struct cached_fid, lease_break); - spin_lock(&cfid->cfids->cfid_list_lock); - cfid->has_lease = false; - spin_unlock(&cfid->cfids->cfid_list_lock); kref_put(&cfid->refcount, smb2_close_cached_fid); } @@ -562,6 +550,7 @@ int cached_dir_lease_break(struct cifs_tcon *tcon, __u8 lease_key[16]) !memcmp(lease_key, cfid->fid.lease_key, SMB2_LEASE_KEY_SIZE)) { + cfid->has_lease = false; cfid->time = 0; /* * We found a lease remove it from the list @@ -639,8 +628,14 @@ static void cfids_laundromat_worker(struct work_struct *work) cfid->on_list = false; list_move(&cfid->entry, &entry); cfids->num_entries--; - /* To prevent race with smb2_cached_lease_break() */ - kref_get(&cfid->refcount); + if (cfid->has_lease) { + /* + * Our lease has not yet been cancelled from the + * server. Steal that reference. + */ + cfid->has_lease = false; + } else + kref_get(&cfid->refcount); } } spin_unlock(&cfids->cfid_list_lock); @@ -652,17 +647,10 @@ static void cfids_laundromat_worker(struct work_struct *work) * with it. */ cancel_work_sync(&cfid->lease_break); - if (cfid->has_lease) { - /* - * Our lease has not yet been cancelled from the server - * so we need to drop the reference. - */ - spin_lock(&cfids->cfid_list_lock); - cfid->has_lease = false; - spin_unlock(&cfids->cfid_list_lock); - kref_put(&cfid->refcount, smb2_close_cached_fid); - } - /* Drop the extra reference opened above */ + /* + * Drop the ref-count from above, either the lease-ref (if there + * was one) or the extra one acquired. + */ kref_put(&cfid->refcount, smb2_close_cached_fid); } queue_delayed_work(cifsiod_wq, &cfids->laundromat_work, -- 2.50.1 From 02e9bda80d66cdd53364b9b32166ac0be1ced58f Mon Sep 17 00:00:00 2001 From: Stefan Berger Date: Mon, 14 Oct 2024 10:16:43 -0400 Subject: [PATCH 08/16] tpm: ibmvtpm: Set TPM_OPS_AUTO_STARTUP flag on driver Set the TPM_OPS_AUTO_STARTUP on the driver so that the ibmvtpm driver now uses tpm2_auto_startup and tpm1_auto_startup like many other drivers do. Remove tpm_get_timeouts, tpm2_get_cc_attrs_tbl, and tpm2_sessions_init calls from it since these will all be called in tpm2_auto_startup and tpm1_auto_startup. The exporting of the tpm2_session_init symbol was only necessary while the ibmvtpm driver was calling this function. Since this is not the case anymore, remove this symbol from being exported. What is new for the ibmvtpm driver is that now tpm2_do_selftest and tpm1_do_selftest will be called that send commands to the TPM to perform or continue its selftest. However, the firmware should already have sent these commands so that the TPM will not do much work at this time. Signed-off-by: Stefan Berger Reviewed-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm2-sessions.c | 1 - drivers/char/tpm/tpm_ibmvtpm.c | 15 +-------------- 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/drivers/char/tpm/tpm2-sessions.c b/drivers/char/tpm/tpm2-sessions.c index b0f13c8ea79c..b70165b588ec 100644 --- a/drivers/char/tpm/tpm2-sessions.c +++ b/drivers/char/tpm/tpm2-sessions.c @@ -1390,5 +1390,4 @@ int tpm2_sessions_init(struct tpm_chip *chip) return rc; } -EXPORT_SYMBOL(tpm2_sessions_init); #endif /* CONFIG_TCG_TPM2_HMAC */ diff --git a/drivers/char/tpm/tpm_ibmvtpm.c b/drivers/char/tpm/tpm_ibmvtpm.c index 1e5b107d1f3b..76d048f63d55 100644 --- a/drivers/char/tpm/tpm_ibmvtpm.c +++ b/drivers/char/tpm/tpm_ibmvtpm.c @@ -450,6 +450,7 @@ static bool tpm_ibmvtpm_req_canceled(struct tpm_chip *chip, u8 status) } static const struct tpm_class_ops tpm_ibmvtpm = { + .flags = TPM_OPS_AUTO_STARTUP, .recv = tpm_ibmvtpm_recv, .send = tpm_ibmvtpm_send, .cancel = tpm_ibmvtpm_cancel, @@ -690,20 +691,6 @@ static int tpm_ibmvtpm_probe(struct vio_dev *vio_dev, if (!strcmp(id->compat, "IBM,vtpm20")) chip->flags |= TPM_CHIP_FLAG_TPM2; - rc = tpm_get_timeouts(chip); - if (rc) - goto init_irq_cleanup; - - if (chip->flags & TPM_CHIP_FLAG_TPM2) { - rc = tpm2_get_cc_attrs_tbl(chip); - if (rc) - goto init_irq_cleanup; - - rc = tpm2_sessions_init(chip); - if (rc) - goto init_irq_cleanup; - } - return tpm_chip_register(chip); init_irq_cleanup: do { -- 2.50.1 From 932e3a5e1ea31712c91e6b4c64d0c7f675315ab4 Mon Sep 17 00:00:00 2001 From: Jan Dabros Date: Thu, 10 Oct 2024 09:15:58 +0000 Subject: [PATCH 09/16] char: tpm: cr50: Use generic request/relinquish locality ops Instead of using static functions tpm_cr50_request_locality and tpm_cr50_release_locality register callbacks from tpm class chip->ops created for this purpose. Signed-off-by: Jan Dabros Signed-off-by: Grzegorz Bernacki Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm_tis_i2c_cr50.c | 94 +++++++++++++++++------------ 1 file changed, 54 insertions(+), 40 deletions(-) diff --git a/drivers/char/tpm/tpm_tis_i2c_cr50.c b/drivers/char/tpm/tpm_tis_i2c_cr50.c index adf22992138e..eed1c296a00c 100644 --- a/drivers/char/tpm/tpm_tis_i2c_cr50.c +++ b/drivers/char/tpm/tpm_tis_i2c_cr50.c @@ -17,6 +17,7 @@ */ #include +#include #include #include #include @@ -35,6 +36,7 @@ #define TPM_CR50_I2C_MAX_RETRIES 3 /* Max retries due to I2C errors */ #define TPM_CR50_I2C_RETRY_DELAY_LO 55 /* Min usecs between retries on I2C */ #define TPM_CR50_I2C_RETRY_DELAY_HI 65 /* Max usecs between retries on I2C */ +#define TPM_CR50_I2C_DEFAULT_LOC 0 #define TPM_I2C_ACCESS(l) (0x0000 | ((l) << 4)) #define TPM_I2C_STS(l) (0x0001 | ((l) << 4)) @@ -285,25 +287,26 @@ out: } /** - * tpm_cr50_check_locality() - Verify TPM locality 0 is active. + * tpm_cr50_check_locality() - Verify if required TPM locality is active. * @chip: A TPM chip. + * @loc: Locality to be verified * * Return: - * - 0: Success. + * - loc: Success. * - -errno: A POSIX error code. */ -static int tpm_cr50_check_locality(struct tpm_chip *chip) +static int tpm_cr50_check_locality(struct tpm_chip *chip, int loc) { u8 mask = TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY; u8 buf; int rc; - rc = tpm_cr50_i2c_read(chip, TPM_I2C_ACCESS(0), &buf, sizeof(buf)); + rc = tpm_cr50_i2c_read(chip, TPM_I2C_ACCESS(loc), &buf, sizeof(buf)); if (rc < 0) return rc; if ((buf & mask) == mask) - return 0; + return loc; return -EIO; } @@ -311,48 +314,57 @@ static int tpm_cr50_check_locality(struct tpm_chip *chip) /** * tpm_cr50_release_locality() - Release TPM locality. * @chip: A TPM chip. - * @force: Flag to force release if set. + * @loc: Locality to be released + * + * Return: + * - 0: Success. + * - -errno: A POSIX error code. */ -static void tpm_cr50_release_locality(struct tpm_chip *chip, bool force) +static int tpm_cr50_release_locality(struct tpm_chip *chip, int loc) { u8 mask = TPM_ACCESS_VALID | TPM_ACCESS_REQUEST_PENDING; - u8 addr = TPM_I2C_ACCESS(0); + u8 addr = TPM_I2C_ACCESS(loc); u8 buf; + int rc; - if (tpm_cr50_i2c_read(chip, addr, &buf, sizeof(buf)) < 0) - return; + rc = tpm_cr50_i2c_read(chip, addr, &buf, sizeof(buf)); + if (rc < 0) + return rc; - if (force || (buf & mask) == mask) { + if ((buf & mask) == mask) { buf = TPM_ACCESS_ACTIVE_LOCALITY; - tpm_cr50_i2c_write(chip, addr, &buf, sizeof(buf)); + rc = tpm_cr50_i2c_write(chip, addr, &buf, sizeof(buf)); } + + return rc; } /** - * tpm_cr50_request_locality() - Request TPM locality 0. + * tpm_cr50_request_locality() - Request TPM locality. * @chip: A TPM chip. + * @loc: Locality to be requested. * * Return: - * - 0: Success. + * - loc: Success. * - -errno: A POSIX error code. */ -static int tpm_cr50_request_locality(struct tpm_chip *chip) +static int tpm_cr50_request_locality(struct tpm_chip *chip, int loc) { u8 buf = TPM_ACCESS_REQUEST_USE; unsigned long stop; int rc; - if (!tpm_cr50_check_locality(chip)) - return 0; + if (tpm_cr50_check_locality(chip, loc) == loc) + return loc; - rc = tpm_cr50_i2c_write(chip, TPM_I2C_ACCESS(0), &buf, sizeof(buf)); + rc = tpm_cr50_i2c_write(chip, TPM_I2C_ACCESS(loc), &buf, sizeof(buf)); if (rc < 0) return rc; stop = jiffies + chip->timeout_a; do { - if (!tpm_cr50_check_locality(chip)) - return 0; + if (tpm_cr50_check_locality(chip, loc) == loc) + return loc; msleep(TPM_CR50_TIMEOUT_SHORT_MS); } while (time_before(jiffies, stop)); @@ -373,7 +385,7 @@ static u8 tpm_cr50_i2c_tis_status(struct tpm_chip *chip) { u8 buf[4]; - if (tpm_cr50_i2c_read(chip, TPM_I2C_STS(0), buf, sizeof(buf)) < 0) + if (tpm_cr50_i2c_read(chip, TPM_I2C_STS(chip->locality), buf, sizeof(buf)) < 0) return 0; return buf[0]; @@ -389,7 +401,7 @@ static void tpm_cr50_i2c_tis_set_ready(struct tpm_chip *chip) { u8 buf[4] = { TPM_STS_COMMAND_READY }; - tpm_cr50_i2c_write(chip, TPM_I2C_STS(0), buf, sizeof(buf)); + tpm_cr50_i2c_write(chip, TPM_I2C_STS(chip->locality), buf, sizeof(buf)); msleep(TPM_CR50_TIMEOUT_SHORT_MS); } @@ -419,7 +431,7 @@ static int tpm_cr50_i2c_get_burst_and_status(struct tpm_chip *chip, u8 mask, stop = jiffies + chip->timeout_b; do { - if (tpm_cr50_i2c_read(chip, TPM_I2C_STS(0), buf, sizeof(buf)) < 0) { + if (tpm_cr50_i2c_read(chip, TPM_I2C_STS(chip->locality), buf, sizeof(buf)) < 0) { msleep(TPM_CR50_TIMEOUT_SHORT_MS); continue; } @@ -453,7 +465,7 @@ static int tpm_cr50_i2c_tis_recv(struct tpm_chip *chip, u8 *buf, size_t buf_len) u8 mask = TPM_STS_VALID | TPM_STS_DATA_AVAIL; size_t burstcnt, cur, len, expected; - u8 addr = TPM_I2C_DATA_FIFO(0); + u8 addr = TPM_I2C_DATA_FIFO(chip->locality); u32 status; int rc; @@ -515,7 +527,6 @@ static int tpm_cr50_i2c_tis_recv(struct tpm_chip *chip, u8 *buf, size_t buf_len) goto out_err; } - tpm_cr50_release_locality(chip, false); return cur; out_err: @@ -523,7 +534,6 @@ out_err: if (tpm_cr50_i2c_tis_status(chip) & TPM_STS_COMMAND_READY) tpm_cr50_i2c_tis_set_ready(chip); - tpm_cr50_release_locality(chip, false); return rc; } @@ -545,10 +555,6 @@ static int tpm_cr50_i2c_tis_send(struct tpm_chip *chip, u8 *buf, size_t len) u32 status; int rc; - rc = tpm_cr50_request_locality(chip); - if (rc < 0) - return rc; - /* Wait until TPM is ready for a command */ stop = jiffies + chip->timeout_b; while (!(tpm_cr50_i2c_tis_status(chip) & TPM_STS_COMMAND_READY)) { @@ -577,7 +583,8 @@ static int tpm_cr50_i2c_tis_send(struct tpm_chip *chip, u8 *buf, size_t len) * that is inserted by tpm_cr50_i2c_write() */ limit = min_t(size_t, burstcnt - 1, len); - rc = tpm_cr50_i2c_write(chip, TPM_I2C_DATA_FIFO(0), &buf[sent], limit); + rc = tpm_cr50_i2c_write(chip, TPM_I2C_DATA_FIFO(chip->locality), + &buf[sent], limit); if (rc < 0) { dev_err(&chip->dev, "Write failed\n"); goto out_err; @@ -598,7 +605,7 @@ static int tpm_cr50_i2c_tis_send(struct tpm_chip *chip, u8 *buf, size_t len) } /* Start the TPM command */ - rc = tpm_cr50_i2c_write(chip, TPM_I2C_STS(0), tpm_go, + rc = tpm_cr50_i2c_write(chip, TPM_I2C_STS(chip->locality), tpm_go, sizeof(tpm_go)); if (rc < 0) { dev_err(&chip->dev, "Start command failed\n"); @@ -611,7 +618,6 @@ out_err: if (tpm_cr50_i2c_tis_status(chip) & TPM_STS_COMMAND_READY) tpm_cr50_i2c_tis_set_ready(chip); - tpm_cr50_release_locality(chip, false); return rc; } @@ -650,6 +656,8 @@ static const struct tpm_class_ops cr50_i2c = { .req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID, .req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID, .req_canceled = &tpm_cr50_i2c_req_canceled, + .request_locality = &tpm_cr50_request_locality, + .relinquish_locality = &tpm_cr50_release_locality, }; #ifdef CONFIG_ACPI @@ -684,6 +692,7 @@ static int tpm_cr50_i2c_probe(struct i2c_client *client) u32 vendor; u8 buf[4]; int rc; + int loc; if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) return -ENODEV; @@ -726,24 +735,30 @@ static int tpm_cr50_i2c_probe(struct i2c_client *client) TPM_CR50_TIMEOUT_NOIRQ_MS); } - rc = tpm_cr50_request_locality(chip); - if (rc < 0) { + loc = tpm_cr50_request_locality(chip, TPM_CR50_I2C_DEFAULT_LOC); + if (loc < 0) { dev_err(dev, "Could not request locality\n"); - return rc; + return loc; } /* Read four bytes from DID_VID register */ - rc = tpm_cr50_i2c_read(chip, TPM_I2C_DID_VID(0), buf, sizeof(buf)); + rc = tpm_cr50_i2c_read(chip, TPM_I2C_DID_VID(loc), buf, sizeof(buf)); if (rc < 0) { dev_err(dev, "Could not read vendor id\n"); - tpm_cr50_release_locality(chip, true); + if (tpm_cr50_release_locality(chip, loc)) + dev_err(dev, "Could not release locality\n"); + return rc; + } + + rc = tpm_cr50_release_locality(chip, loc); + if (rc) { + dev_err(dev, "Could not release locality\n"); return rc; } vendor = le32_to_cpup((__le32 *)buf); if (vendor != TPM_CR50_I2C_DID_VID && vendor != TPM_TI50_I2C_DID_VID) { dev_err(dev, "Vendor ID did not match! ID was %08x\n", vendor); - tpm_cr50_release_locality(chip, true); return -ENODEV; } @@ -772,7 +787,6 @@ static void tpm_cr50_i2c_remove(struct i2c_client *client) } tpm_chip_unregister(chip); - tpm_cr50_release_locality(chip, true); } static SIMPLE_DEV_PM_OPS(cr50_i2c_pm, tpm_pm_suspend, tpm_pm_resume); -- 2.50.1 From 44637b0b40f47629ff78a73744755e6535e0970e Mon Sep 17 00:00:00 2001 From: Jan Dabros Date: Thu, 10 Oct 2024 09:15:59 +0000 Subject: [PATCH 10/16] char: tpm: cr50: Move i2c locking to request/relinquish locality ops Move i2c locking primitives to request_locality and relinquish_locality callbacks, what effectively blocks TPM bus for the whole duration of logical TPM operation. With this in place, cr50-equipped TPM may be shared with external CPUs - assuming that underneath i2c controller driver is aware of this setup (see i2c-designware-amdpsp as an example). Signed-off-by: Jan Dabros Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm_tis_i2c_cr50.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/drivers/char/tpm/tpm_tis_i2c_cr50.c b/drivers/char/tpm/tpm_tis_i2c_cr50.c index eed1c296a00c..80b0f41ffb5f 100644 --- a/drivers/char/tpm/tpm_tis_i2c_cr50.c +++ b/drivers/char/tpm/tpm_tis_i2c_cr50.c @@ -201,8 +201,6 @@ static int tpm_cr50_i2c_read(struct tpm_chip *chip, u8 addr, u8 *buffer, size_t }; int rc; - i2c_lock_bus(client->adapter, I2C_LOCK_SEGMENT); - /* Prepare for completion interrupt */ tpm_cr50_i2c_enable_tpm_irq(chip); @@ -221,7 +219,6 @@ static int tpm_cr50_i2c_read(struct tpm_chip *chip, u8 addr, u8 *buffer, size_t out: tpm_cr50_i2c_disable_tpm_irq(chip); - i2c_unlock_bus(client->adapter, I2C_LOCK_SEGMENT); if (rc < 0) return rc; @@ -263,8 +260,6 @@ static int tpm_cr50_i2c_write(struct tpm_chip *chip, u8 addr, u8 *buffer, priv->buf[0] = addr; memcpy(priv->buf + 1, buffer, len); - i2c_lock_bus(client->adapter, I2C_LOCK_SEGMENT); - /* Prepare for completion interrupt */ tpm_cr50_i2c_enable_tpm_irq(chip); @@ -278,7 +273,6 @@ static int tpm_cr50_i2c_write(struct tpm_chip *chip, u8 addr, u8 *buffer, out: tpm_cr50_i2c_disable_tpm_irq(chip); - i2c_unlock_bus(client->adapter, I2C_LOCK_SEGMENT); if (rc < 0) return rc; @@ -322,6 +316,7 @@ static int tpm_cr50_check_locality(struct tpm_chip *chip, int loc) */ static int tpm_cr50_release_locality(struct tpm_chip *chip, int loc) { + struct i2c_client *client = to_i2c_client(chip->dev.parent); u8 mask = TPM_ACCESS_VALID | TPM_ACCESS_REQUEST_PENDING; u8 addr = TPM_I2C_ACCESS(loc); u8 buf; @@ -329,13 +324,15 @@ static int tpm_cr50_release_locality(struct tpm_chip *chip, int loc) rc = tpm_cr50_i2c_read(chip, addr, &buf, sizeof(buf)); if (rc < 0) - return rc; + goto unlock_out; if ((buf & mask) == mask) { buf = TPM_ACCESS_ACTIVE_LOCALITY; rc = tpm_cr50_i2c_write(chip, addr, &buf, sizeof(buf)); } +unlock_out: + i2c_unlock_bus(client->adapter, I2C_LOCK_SEGMENT); return rc; } @@ -350,16 +347,19 @@ static int tpm_cr50_release_locality(struct tpm_chip *chip, int loc) */ static int tpm_cr50_request_locality(struct tpm_chip *chip, int loc) { + struct i2c_client *client = to_i2c_client(chip->dev.parent); u8 buf = TPM_ACCESS_REQUEST_USE; unsigned long stop; int rc; + i2c_lock_bus(client->adapter, I2C_LOCK_SEGMENT); + if (tpm_cr50_check_locality(chip, loc) == loc) return loc; rc = tpm_cr50_i2c_write(chip, TPM_I2C_ACCESS(loc), &buf, sizeof(buf)); if (rc < 0) - return rc; + goto unlock_out; stop = jiffies + chip->timeout_a; do { @@ -369,7 +369,11 @@ static int tpm_cr50_request_locality(struct tpm_chip *chip, int loc) msleep(TPM_CR50_TIMEOUT_SHORT_MS); } while (time_before(jiffies, stop)); - return -ETIMEDOUT; + rc = -ETIMEDOUT; + +unlock_out: + i2c_unlock_bus(client->adapter, I2C_LOCK_SEGMENT); + return rc; } /** -- 2.50.1 From 2e1827de1b0f22b420c9446a3c94e6cce8eb4da4 Mon Sep 17 00:00:00 2001 From: Jett Rink Date: Tue, 10 Sep 2024 19:11:14 +0000 Subject: [PATCH 11/16] char: tpm: cr50: Add new device/vendor ID 0x50666666 Accept another DID:VID for the next generation Google TPM. This TPM has the same Ti50 firmware and fulfills the same interface. Suggested-by: Jarkko Sakkinen Signed-off-by: Jett Rink Reviewed-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm_tis_i2c_cr50.c | 32 +++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/drivers/char/tpm/tpm_tis_i2c_cr50.c b/drivers/char/tpm/tpm_tis_i2c_cr50.c index 80b0f41ffb5f..3b55a7b05c46 100644 --- a/drivers/char/tpm/tpm_tis_i2c_cr50.c +++ b/drivers/char/tpm/tpm_tis_i2c_cr50.c @@ -31,8 +31,9 @@ #define TPM_CR50_MAX_BUFSIZE 64 #define TPM_CR50_TIMEOUT_SHORT_MS 2 /* Short timeout during transactions */ #define TPM_CR50_TIMEOUT_NOIRQ_MS 20 /* Timeout for TPM ready without IRQ */ -#define TPM_CR50_I2C_DID_VID 0x00281ae0L /* Device and vendor ID reg value */ -#define TPM_TI50_I2C_DID_VID 0x504a6666L /* Device and vendor ID reg value */ +#define TPM_CR50_I2C_DID_VID 0x00281ae0L /* Device and vendor ID for Cr50 H1 */ +#define TPM_TI50_DT_I2C_DID_VID 0x504a6666L /* Device and vendor ID for Ti50 DT */ +#define TPM_TI50_OT_I2C_DID_VID 0x50666666L /* Device and vendor ID for TI50 OT */ #define TPM_CR50_I2C_MAX_RETRIES 3 /* Max retries due to I2C errors */ #define TPM_CR50_I2C_RETRY_DELAY_LO 55 /* Min usecs between retries on I2C */ #define TPM_CR50_I2C_RETRY_DELAY_HI 65 /* Max usecs between retries on I2C */ @@ -680,6 +681,27 @@ static const struct of_device_id of_cr50_i2c_match[] = { MODULE_DEVICE_TABLE(of, of_cr50_i2c_match); #endif +/** + * tpm_cr50_vid_to_name() - Maps VID to name. + * @vendor: Vendor identifier to map to name + * + * Return: + * A valid string for the vendor or empty string + */ +static const char *tpm_cr50_vid_to_name(u32 vendor) +{ + switch (vendor) { + case TPM_CR50_I2C_DID_VID: + return "cr50"; + case TPM_TI50_DT_I2C_DID_VID: + return "ti50 DT"; + case TPM_TI50_OT_I2C_DID_VID: + return "ti50 OT"; + default: + return "unknown"; + } +} + /** * tpm_cr50_i2c_probe() - Driver probe function. * @client: I2C client information. @@ -761,13 +783,15 @@ static int tpm_cr50_i2c_probe(struct i2c_client *client) } vendor = le32_to_cpup((__le32 *)buf); - if (vendor != TPM_CR50_I2C_DID_VID && vendor != TPM_TI50_I2C_DID_VID) { + if (vendor != TPM_CR50_I2C_DID_VID && + vendor != TPM_TI50_DT_I2C_DID_VID && + vendor != TPM_TI50_OT_I2C_DID_VID) { dev_err(dev, "Vendor ID did not match! ID was %08x\n", vendor); return -ENODEV; } dev_info(dev, "%s TPM 2.0 (i2c 0x%02x irq %d id 0x%x)\n", - vendor == TPM_TI50_I2C_DID_VID ? "ti50" : "cr50", + tpm_cr50_vid_to_name(vendor), client->addr, client->irq, vendor >> 16); return tpm_chip_register(chip); } -- 2.50.1 From 5578b4347bb5d5dfc8eeb8ee2eb8248658707d9b Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Wed, 6 Nov 2024 20:17:42 +0200 Subject: [PATCH 12/16] tpm: atmel: Drop PPC64 specific MMIO setup The PPC64 specific MMIO setup open codes DT address functions rather than using standard address parsing functions. The open-coded version fails to handle any address translation and is not endian safe. I haven't found any evidence of what platform used this. The only thing that turned up was a PPC405 platform, but that is 32-bit and PPC405 support is being removed as well. CONFIG_TCG_ATMEL is not enabled for any powerpc config and never was. The support was added in 2005 and hasn't been touched since. Rather than try to modernize and fix this code, just remove it. [jarkko: fixed couple of style issues reported by checkpatch.pl --strict and put offset into parentheses in the macro declarations.] Signed-off-by: Rob Herring (Arm) Acked-by: Michael Ellerman Reviewed-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/Kconfig | 2 +- drivers/char/tpm/tpm_atmel.c | 63 +++++++++++++++- drivers/char/tpm/tpm_atmel.h | 140 ----------------------------------- 3 files changed, 61 insertions(+), 144 deletions(-) delete mode 100644 drivers/char/tpm/tpm_atmel.h diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig index cf0be8a7939d..0fc9a510e059 100644 --- a/drivers/char/tpm/Kconfig +++ b/drivers/char/tpm/Kconfig @@ -162,7 +162,7 @@ config TCG_NSC config TCG_ATMEL tristate "Atmel TPM Interface" - depends on PPC64 || HAS_IOPORT_MAP + depends on HAS_IOPORT_MAP depends on HAS_IOPORT help If you have a TPM security chip from Atmel say Yes and it diff --git a/drivers/char/tpm/tpm_atmel.c b/drivers/char/tpm/tpm_atmel.c index 9fb2defa9dc4..54a0360a3c95 100644 --- a/drivers/char/tpm/tpm_atmel.c +++ b/drivers/char/tpm/tpm_atmel.c @@ -15,7 +15,66 @@ */ #include "tpm.h" -#include "tpm_atmel.h" + +struct tpm_atmel_priv { + int region_size; + int have_region; + unsigned long base; + void __iomem *iobase; +}; + +#define atmel_getb(chip, offset) inb(atmel_get_priv(chip)->base + (offset)) +#define atmel_putb(val, chip, offset) \ + outb(val, atmel_get_priv(chip)->base + (offset)) +#define atmel_request_region request_region +#define atmel_release_region release_region +/* Atmel definitions */ +enum tpm_atmel_addr { + TPM_ATMEL_BASE_ADDR_LO = 0x08, + TPM_ATMEL_BASE_ADDR_HI = 0x09 +}; + +static inline int tpm_read_index(int base, int index) +{ + outb(index, base); + return inb(base + 1) & 0xFF; +} + +/* Verify this is a 1.1 Atmel TPM */ +static int atmel_verify_tpm11(void) +{ + /* verify that it is an Atmel part */ + if (tpm_read_index(TPM_ADDR, 4) != 'A' || + tpm_read_index(TPM_ADDR, 5) != 'T' || + tpm_read_index(TPM_ADDR, 6) != 'M' || + tpm_read_index(TPM_ADDR, 7) != 'L') + return 1; + + /* query chip for its version number */ + if (tpm_read_index(TPM_ADDR, 0x00) != 1 || + tpm_read_index(TPM_ADDR, 0x01) != 1) + return 1; + + /* This is an atmel supported part */ + return 0; +} + +/* Determine where to talk to device */ +static void __iomem *atmel_get_base_addr(unsigned long *base, int *region_size) +{ + int lo, hi; + + if (atmel_verify_tpm11() != 0) + return NULL; + + lo = tpm_read_index(TPM_ADDR, TPM_ATMEL_BASE_ADDR_LO); + hi = tpm_read_index(TPM_ADDR, TPM_ATMEL_BASE_ADDR_HI); + + *base = (hi << 8) | lo; + *region_size = 2; + + return ioport_map(*base, *region_size); +} /* write status bits */ enum tpm_atmel_write_status { @@ -142,7 +201,6 @@ static void atml_plat_remove(void) tpm_chip_unregister(chip); if (priv->have_region) atmel_release_region(priv->base, priv->region_size); - atmel_put_base_addr(priv->iobase); platform_device_unregister(pdev); } @@ -211,7 +269,6 @@ static int __init init_atmel(void) err_unreg_dev: platform_device_unregister(pdev); err_rel_reg: - atmel_put_base_addr(iobase); if (have_region) atmel_release_region(base, region_size); diff --git a/drivers/char/tpm/tpm_atmel.h b/drivers/char/tpm/tpm_atmel.h deleted file mode 100644 index 7ac3f69dcf0f..000000000000 --- a/drivers/char/tpm/tpm_atmel.h +++ /dev/null @@ -1,140 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (C) 2005 IBM Corporation - * - * Authors: - * Kylene Hall - * - * Maintained by: - * - * Device driver for TCG/TCPA TPM (trusted platform module). - * Specifications at www.trustedcomputinggroup.org - * - * These difference are required on power because the device must be - * discovered through the device tree and iomap must be used to get - * around the need for holes in the io_page_mask. This does not happen - * automatically because the tpm is not a normal pci device and lives - * under the root node. - */ - -struct tpm_atmel_priv { - int region_size; - int have_region; - unsigned long base; - void __iomem *iobase; -}; - -#ifdef CONFIG_PPC64 - -#include - -#define atmel_getb(priv, offset) readb(priv->iobase + offset) -#define atmel_putb(val, priv, offset) writeb(val, priv->iobase + offset) -#define atmel_request_region request_mem_region -#define atmel_release_region release_mem_region - -static inline void atmel_put_base_addr(void __iomem *iobase) -{ - iounmap(iobase); -} - -static void __iomem * atmel_get_base_addr(unsigned long *base, int *region_size) -{ - struct device_node *dn; - unsigned long address, size; - const unsigned int *reg; - int reglen; - int naddrc; - int nsizec; - - dn = of_find_node_by_name(NULL, "tpm"); - - if (!dn) - return NULL; - - if (!of_device_is_compatible(dn, "AT97SC3201")) { - of_node_put(dn); - return NULL; - } - - reg = of_get_property(dn, "reg", ®len); - naddrc = of_n_addr_cells(dn); - nsizec = of_n_size_cells(dn); - - of_node_put(dn); - - - if (naddrc == 2) - address = ((unsigned long) reg[0] << 32) | reg[1]; - else - address = reg[0]; - - if (nsizec == 2) - size = - ((unsigned long) reg[naddrc] << 32) | reg[naddrc + 1]; - else - size = reg[naddrc]; - - *base = address; - *region_size = size; - return ioremap(*base, *region_size); -} -#else -#define atmel_getb(chip, offset) inb(atmel_get_priv(chip)->base + offset) -#define atmel_putb(val, chip, offset) \ - outb(val, atmel_get_priv(chip)->base + offset) -#define atmel_request_region request_region -#define atmel_release_region release_region -/* Atmel definitions */ -enum tpm_atmel_addr { - TPM_ATMEL_BASE_ADDR_LO = 0x08, - TPM_ATMEL_BASE_ADDR_HI = 0x09 -}; - -static inline int tpm_read_index(int base, int index) -{ - outb(index, base); - return inb(base+1) & 0xFF; -} - -/* Verify this is a 1.1 Atmel TPM */ -static int atmel_verify_tpm11(void) -{ - - /* verify that it is an Atmel part */ - if (tpm_read_index(TPM_ADDR, 4) != 'A' || - tpm_read_index(TPM_ADDR, 5) != 'T' || - tpm_read_index(TPM_ADDR, 6) != 'M' || - tpm_read_index(TPM_ADDR, 7) != 'L') - return 1; - - /* query chip for its version number */ - if (tpm_read_index(TPM_ADDR, 0x00) != 1 || - tpm_read_index(TPM_ADDR, 0x01) != 1) - return 1; - - /* This is an atmel supported part */ - return 0; -} - -static inline void atmel_put_base_addr(void __iomem *iobase) -{ -} - -/* Determine where to talk to device */ -static void __iomem * atmel_get_base_addr(unsigned long *base, int *region_size) -{ - int lo, hi; - - if (atmel_verify_tpm11() != 0) - return NULL; - - lo = tpm_read_index(TPM_ADDR, TPM_ATMEL_BASE_ADDR_LO); - hi = tpm_read_index(TPM_ADDR, TPM_ATMEL_BASE_ADDR_HI); - - *base = (hi << 8) | lo; - *region_size = 2; - - return ioport_map(*base, *region_size); -} -#endif -- 2.50.1 From 50b9d43e6ceaaaa59c54c95aca5f8dfc862fe48e Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Tue, 8 Oct 2024 18:09:47 +0200 Subject: [PATCH 13/16] i2c: qup: use generic device property accessors There's no reason for this driver to use OF-specific property helpers. Drop the last one in favor of the generic variant and no longer include of.h. Signed-off-by: Bartosz Golaszewski Reviewed-by: Neil Armstrong Signed-off-by: Andi Shyti Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-qup.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c index 86ec391616b0..da20b4487c9a 100644 --- a/drivers/i2c/busses/i2c-qup.c +++ b/drivers/i2c/busses/i2c-qup.c @@ -17,9 +17,9 @@ #include #include #include -#include #include #include +#include #include /* QUP Registers */ @@ -1683,7 +1683,7 @@ static int qup_i2c_probe(struct platform_device *pdev) } } - if (of_device_is_compatible(pdev->dev.of_node, "qcom,i2c-qup-v1.1.1")) { + if (device_is_compatible(&pdev->dev, "qcom,i2c-qup-v1.1.1")) { qup->adap.algo = &qup_i2c_algo; qup->adap.quirks = &qup_i2c_quirks; is_qup_v1 = true; -- 2.50.1 From 7c3a833a1da6ab1e29fcb4740edf770aea816c6f Mon Sep 17 00:00:00 2001 From: Yoshihiro Furudera Date: Thu, 24 Oct 2024 07:15:53 +0000 Subject: [PATCH 14/16] i2c: designware: Add ACPI HID for DWAPB I2C controller on FUJITSU-MONAKA Enable DWAPB I2C controller support on FUJITSU-MONAKA. This will be used in the FUJITSU-MONAKA server scheduled for shipment in 2027. The DSDT information obtained when verified using an in-house simulator is presented below. Device (SMB0) { Name (_HID, "FUJI200B") // _HID: Hardware ID Name (_UID, Zero) // _UID: Unique ID ... Name (_CRS, ResourceTemplate () { Memory32Fixed (ReadWrite, 0x2A4B0000, // Address Base 0x00010000, // Address Length ) Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive, ,, ) { 0x00000159, } }) ... } The expression SMB0 is used to indicate SMBus HC#0, a string of up to four characters. Created the SMB0 object according to the following specifications: ACPI Specification 13.2. Accessing the SMBus from ASL Code https://uefi.org/htmlspecs/ACPI_Spec_6_4_html/13_ACPI_System_Mgmt_Bus_Interface_Spec/accessing-the-smbus-from-asl-code.html IPMI Specification Example 4: SSIF Interface(P574) https://www.intel.co.jp/content/www/jp/ja/products/docs/servers/ipmi/ipmi-second-gen-interface-spec-v2-rev1-1.html Signed-off-by: Yoshihiro Furudera Reviewed-by: Andy Shevchenko Acked-by: Jarkko Nikula Signed-off-by: Andi Shyti Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-designware-platdrv.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c index 1643cad6489c..3e12aab6bf2d 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c @@ -349,6 +349,7 @@ static const struct acpi_device_id dw_i2c_acpi_match[] = { { "AMDI0019", ACCESS_INTR_MASK | ARBITRATION_SEMAPHORE }, { "AMDI0510", 0 }, { "APMC0D0F", 0 }, + { "FUJI200B", 0 }, { "HISI02A1", 0 }, { "HISI02A2", 0 }, { "HISI02A3", 0 }, -- 2.50.1 From efdc7828b7cc8cb8a1c2a83ff6f7741ca055b1b1 Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Mon, 11 Nov 2024 01:30:24 +0000 Subject: [PATCH 15/16] dt-bindings: i2c: mv64xxx: Add Allwinner A523 compatible string The I2C controller IP used in the Allwinner A523/T527 SoCs is compatible with the ones used in the other recent Allwinner SoCs. Add the A523 specific compatible string to the list of existing names falling back to the allwinner,sun8i-v536-i2c string. Signed-off-by: Andre Przywara Acked-by: Conor Dooley Signed-off-by: Andi Shyti Signed-off-by: Wolfram Sang --- Documentation/devicetree/bindings/i2c/marvell,mv64xxx-i2c.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/i2c/marvell,mv64xxx-i2c.yaml b/Documentation/devicetree/bindings/i2c/marvell,mv64xxx-i2c.yaml index 984fc1ed3ec6..c4efcef59133 100644 --- a/Documentation/devicetree/bindings/i2c/marvell,mv64xxx-i2c.yaml +++ b/Documentation/devicetree/bindings/i2c/marvell,mv64xxx-i2c.yaml @@ -33,6 +33,7 @@ properties: - allwinner,sun50i-a100-i2c - allwinner,sun50i-h616-i2c - allwinner,sun50i-r329-i2c + - allwinner,sun55i-a523-i2c - const: allwinner,sun8i-v536-i2c - const: allwinner,sun6i-a31-i2c - const: marvell,mv64xxx-i2c -- 2.50.1 From 2eec351eed02da9955ac7a79dd9481f61c355c9a Mon Sep 17 00:00:00 2001 From: =?utf8?q?Th=C3=A9o=20Lebrun?= Date: Wed, 9 Oct 2024 16:01:07 +0200 Subject: [PATCH 16/16] dt-bindings: i2c: nomadik: add mobileye,eyeq6h-i2c bindings MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit After EyeQ5, it is time for Mobileye EyeQ6H to reuse the Nomadik I2C controller. Add a specific compatible because its HW integration is slightly different from EyeQ5. Do NOT add an example as it looks like EyeQ5 from a DT standpoint (without the mobileye,olb property). Reviewed-by: Linus Walleij Signed-off-by: Théo Lebrun Reviewed-by: Rob Herring (Arm) Signed-off-by: Andi Shyti Signed-off-by: Wolfram Sang --- .../devicetree/bindings/i2c/st,nomadik-i2c.yaml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Documentation/devicetree/bindings/i2c/st,nomadik-i2c.yaml b/Documentation/devicetree/bindings/i2c/st,nomadik-i2c.yaml index 44c54b162bb1..7e84465c2009 100644 --- a/Documentation/devicetree/bindings/i2c/st,nomadik-i2c.yaml +++ b/Documentation/devicetree/bindings/i2c/st,nomadik-i2c.yaml @@ -22,6 +22,7 @@ select: enum: - st,nomadik-i2c - mobileye,eyeq5-i2c + - mobileye,eyeq6h-i2c required: - compatible @@ -29,15 +30,15 @@ properties: compatible: oneOf: - items: - - const: st,nomadik-i2c + - enum: + - st,nomadik-i2c + - mobileye,eyeq5-i2c + - mobileye,eyeq6h-i2c - const: arm,primecell - items: - const: stericsson,db8500-i2c - const: st,nomadik-i2c - const: arm,primecell - - items: - - const: mobileye,eyeq5-i2c - - const: arm,primecell reg: maxItems: 1 @@ -54,7 +55,7 @@ properties: - items: - const: mclk - const: apb_pclk - # Clock name in DB8500 or EyeQ5 + # Clock name in DB8500 or EyeQ - items: - const: i2cclk - const: apb_pclk -- 2.50.1