From a115b5716fc9a64652aa9cb332070087178ffafa Mon Sep 17 00:00:00 2001 From: Maxime Coquelin Date: Tue, 9 Jan 2024 12:10:23 +0100 Subject: vduse: validate block features only with block devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch is preliminary work to enable network device type support to VDUSE. As VIRTIO_BLK_F_CONFIG_WCE shares the same value as VIRTIO_NET_F_HOST_TSO4, we need to restrict its check to Virtio-blk device type. Acked-by: Jason Wang Reviewed-by: Xie Yongji Reviewed-by: Eugenio Pérez Signed-off-by: Maxime Coquelin Message-Id: <20240109111025.1320976-2-maxime.coquelin@redhat.com> Signed-off-by: Michael S. Tsirkin --- drivers/vdpa/vdpa_user/vduse_dev.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/vdpa/vdpa_user/vduse_dev.c b/drivers/vdpa/vdpa_user/vduse_dev.c index 73c89701fc9d..7c3d117b22de 100644 --- a/drivers/vdpa/vdpa_user/vduse_dev.c +++ b/drivers/vdpa/vdpa_user/vduse_dev.c @@ -1705,13 +1705,14 @@ static bool device_is_allowed(u32 device_id) return false; } -static bool features_is_valid(u64 features) +static bool features_is_valid(struct vduse_dev_config *config) { - if (!(features & (1ULL << VIRTIO_F_ACCESS_PLATFORM))) + if (!(config->features & BIT_ULL(VIRTIO_F_ACCESS_PLATFORM))) return false; /* Now we only support read-only configuration space */ - if (features & (1ULL << VIRTIO_BLK_F_CONFIG_WCE)) + if ((config->device_id == VIRTIO_ID_BLOCK) && + (config->features & BIT_ULL(VIRTIO_BLK_F_CONFIG_WCE))) return false; return true; @@ -1738,7 +1739,7 @@ static bool vduse_validate_config(struct vduse_dev_config *config) if (!device_is_allowed(config->device_id)) return false; - if (!features_is_valid(config->features)) + if (!features_is_valid(config)) return false; return true; -- cgit v1.2.3-59-g8ed1b From 56e71885b0349241c07631a7b979b61e81afab6a Mon Sep 17 00:00:00 2001 From: Maxime Coquelin Date: Tue, 9 Jan 2024 12:10:24 +0100 Subject: vduse: Temporarily fail if control queue feature requested MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Virtio-net driver control queue implementation is not safe when used with VDUSE. If the VDUSE application does not reply to control queue messages, it currently ends up hanging the kernel thread sending this command. Some work is on-going to make the control queue implementation robust with VDUSE. Until it is completed, let's fail features check if control-queue feature is requested. Signed-off-by: Maxime Coquelin Message-Id: <20240109111025.1320976-3-maxime.coquelin@redhat.com> Signed-off-by: Michael S. Tsirkin Acked-by: Eugenio Pérez Reviewed-by: Xie Yongji Acked-by: Jason Wang --- drivers/vdpa/vdpa_user/vduse_dev.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/vdpa/vdpa_user/vduse_dev.c b/drivers/vdpa/vdpa_user/vduse_dev.c index 7c3d117b22de..ac8b5b52e3dc 100644 --- a/drivers/vdpa/vdpa_user/vduse_dev.c +++ b/drivers/vdpa/vdpa_user/vduse_dev.c @@ -8,6 +8,7 @@ * */ +#include "linux/virtio_net.h" #include #include #include @@ -28,6 +29,7 @@ #include #include #include +#include #include #include "iova_domain.h" @@ -1714,6 +1716,9 @@ static bool features_is_valid(struct vduse_dev_config *config) if ((config->device_id == VIRTIO_ID_BLOCK) && (config->features & BIT_ULL(VIRTIO_BLK_F_CONFIG_WCE))) return false; + else if ((config->device_id == VIRTIO_ID_NET) && + (config->features & BIT_ULL(VIRTIO_NET_F_CTRL_VQ))) + return false; return true; } -- cgit v1.2.3-59-g8ed1b From 894452180d732413fd29fa95a4820560fa44ca4a Mon Sep 17 00:00:00 2001 From: Maxime Coquelin Date: Tue, 9 Jan 2024 12:10:25 +0100 Subject: vduse: enable Virtio-net device type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds Virtio-net device type to the supported devices types. Initialization fails if the device does not support VIRTIO_F_VERSION_1 feature, in order to guarantee the configuration space is read-only. It also fails with -EPERM if the CAP_NET_ADMIN is missing. Acked-by: Jason Wang Reviewed-by: Eugenio Pérez Signed-off-by: Maxime Coquelin Message-Id: <20240109111025.1320976-4-maxime.coquelin@redhat.com> Signed-off-by: Michael S. Tsirkin Reviewed-by: Xie Yongji --- drivers/vdpa/vdpa_user/vduse_dev.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/vdpa/vdpa_user/vduse_dev.c b/drivers/vdpa/vdpa_user/vduse_dev.c index ac8b5b52e3dc..7ae99691efdf 100644 --- a/drivers/vdpa/vdpa_user/vduse_dev.c +++ b/drivers/vdpa/vdpa_user/vduse_dev.c @@ -143,6 +143,7 @@ static struct workqueue_struct *vduse_irq_bound_wq; static u32 allowed_device_id[] = { VIRTIO_ID_BLOCK, + VIRTIO_ID_NET, }; static inline struct vduse_dev *vdpa_to_vduse(struct vdpa_device *vdpa) @@ -1720,6 +1721,10 @@ static bool features_is_valid(struct vduse_dev_config *config) (config->features & BIT_ULL(VIRTIO_NET_F_CTRL_VQ))) return false; + if ((config->device_id == VIRTIO_ID_NET) && + !(config->features & BIT_ULL(VIRTIO_F_VERSION_1))) + return false; + return true; } @@ -1827,6 +1832,10 @@ static int vduse_create_dev(struct vduse_dev_config *config, int ret; struct vduse_dev *dev; + ret = -EPERM; + if ((config->device_id == VIRTIO_ID_NET) && !capable(CAP_NET_ADMIN)) + goto err; + ret = -EEXIST; if (vduse_find_dev(config->name)) goto err; @@ -2070,6 +2079,7 @@ static const struct vdpa_mgmtdev_ops vdpa_dev_mgmtdev_ops = { static struct virtio_device_id id_table[] = { { VIRTIO_ID_BLOCK, VIRTIO_DEV_ANY_ID }, + { VIRTIO_ID_NET, VIRTIO_DEV_ANY_ID }, { 0 }, }; -- cgit v1.2.3-59-g8ed1b From a9f4c6c999008c92e2aba6d4f50f2b2d10ed7fd0 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 31 Jan 2024 17:57:54 -0300 Subject: perf trace: Collect sys_nanosleep first argument That is a 'struct timespec' passed from userspace to the kernel as we can see with a system wide syscall tracing: root@number:~# perf trace -e nanosleep 0.000 (10.102 ms): podman/9150 nanosleep(rqtp: { .tv_sec: 0, .tv_nsec: 10000000 }) = 0 38.924 (10.077 ms): podman/2195174 nanosleep(rqtp: { .tv_sec: 0, .tv_nsec: 10000000 }) = 0 100.177 (10.107 ms): podman/9150 nanosleep(rqtp: { .tv_sec: 0, .tv_nsec: 10000000 }) = 0 139.171 (10.063 ms): podman/2195174 nanosleep(rqtp: { .tv_sec: 0, .tv_nsec: 10000000 }) = 0 200.603 (10.105 ms): podman/9150 nanosleep(rqtp: { .tv_sec: 0, .tv_nsec: 10000000 }) = 0 239.399 (10.064 ms): podman/2195174 nanosleep(rqtp: { .tv_sec: 0, .tv_nsec: 10000000 }) = 0 300.994 (10.096 ms): podman/9150 nanosleep(rqtp: { .tv_sec: 0, .tv_nsec: 10000000 }) = 0 339.584 (10.067 ms): podman/2195174 nanosleep(rqtp: { .tv_sec: 0, .tv_nsec: 10000000 }) = 0 401.335 (10.057 ms): podman/9150 nanosleep(rqtp: { .tv_sec: 0, .tv_nsec: 10000000 }) = 0 439.758 (10.166 ms): podman/2195174 nanosleep(rqtp: { .tv_sec: 0, .tv_nsec: 10000000 }) = 0 501.814 (10.110 ms): podman/9150 nanosleep(rqtp: { .tv_sec: 0, .tv_nsec: 10000000 }) = 0 539.983 (10.227 ms): podman/2195174 nanosleep(rqtp: { .tv_sec: 0, .tv_nsec: 10000000 }) = 0 602.284 (10.199 ms): podman/9150 nanosleep(rqtp: { .tv_sec: 0, .tv_nsec: 10000000 }) = 0 640.208 (10.105 ms): podman/2195174 nanosleep(rqtp: { .tv_sec: 0, .tv_nsec: 10000000 }) = 0 702.662 (10.163 ms): podman/9150 nanosleep(rqtp: { .tv_sec: 0, .tv_nsec: 10000000 }) = 0 740.440 (10.107 ms): podman/2195174 nanosleep(rqtp: { .tv_sec: 0, .tv_nsec: 10000000 }) = 0 802.993 (10.159 ms): podman/9150 nanosleep(rqtp: { .tv_sec: 0, .tv_nsec: 10000000 }) = 0 ^Croot@number:~# strace -p 9150 -e nanosleep If we then use the ptrace method to look at that podman process: root@number:~# strace -p 9150 -e nanosleep strace: Process 9150 attached nanosleep({tv_sec=0, tv_nsec=10000000}, NULL) = 0 nanosleep({tv_sec=0, tv_nsec=10000000}, NULL) = 0 nanosleep({tv_sec=0, tv_nsec=10000000}, NULL) = 0 nanosleep({tv_sec=0, tv_nsec=10000000}, NULL) = 0 nanosleep({tv_sec=0, tv_nsec=10000000}, NULL) = 0 nanosleep({tv_sec=0, tv_nsec=10000000}, NULL) = 0 nanosleep({tv_sec=0, tv_nsec=10000000}, NULL) = 0 ^Cstrace: Process 9150 detached root@number:~# With some changes we can get something closer to the strace output, still in system wide mode: root@number:~# perf config trace.show_arg_names=false root@number:~# perf config trace.show_duration=false root@number:~# perf config trace.show_timestamp=false root@number:~# perf config trace.show_zeros=true root@number:~# perf config trace.args_alignment=0 root@number:~# perf trace -e nanosleep --max-events=10 podman/2195174 nanosleep({ .tv_sec: 0, .tv_nsec: 10000000 }, NULL) = 0 podman/9150 nanosleep({ .tv_sec: 0, .tv_nsec: 10000000 }, NULL) = 0 podman/2195174 nanosleep({ .tv_sec: 0, .tv_nsec: 10000000 }, NULL) = 0 podman/9150 nanosleep({ .tv_sec: 0, .tv_nsec: 10000000 }, NULL) = 0 podman/2195174 nanosleep({ .tv_sec: 0, .tv_nsec: 10000000 }, NULL) = 0 podman/9150 nanosleep({ .tv_sec: 0, .tv_nsec: 10000000 }, NULL) = 0 podman/2195174 nanosleep({ .tv_sec: 0, .tv_nsec: 10000000 }, NULL) = 0 podman/9150 nanosleep({ .tv_sec: 0, .tv_nsec: 10000000 }, NULL) = 0 podman/2195174 nanosleep({ .tv_sec: 0, .tv_nsec: 10000000 }, NULL) = 0 podman/9150 nanosleep({ .tv_sec: 0, .tv_nsec: 10000000 }, NULL) = 0 root@number:~# root@number:~# perf config trace.show_arg_names=false trace.show_duration=false trace.show_timestamp=false trace.show_zeros=true trace.args_alignment=0 root@number:~# cat ~/.perfconfig # this file is auto-generated. [trace] show_arg_names = false show_duration = false show_timestamp = false show_zeros = true args_alignment = 0 root@number:~# This will not get reused by any other syscall as nanosleep is the only one to have as its first argument a 'struct timespec" pointer argument passed from userspace to the kernel: root@number:~# grep timespec /sys/kernel/tracing/events/syscalls/sys_enter_*/format | grep offset:16 /sys/kernel/tracing/events/syscalls/sys_enter_nanosleep/format: field:struct __kernel_timespec * rqtp; offset:16; size:8; signed:0; root@number:~# BTF based pretty printing will simplify all this, but then lets just get the low hanging fruits first. Reviewed-by: Ian Rogers Cc: Adrian Hunter Cc: Jiri Olsa Cc: Namhyung Kim Link: https://lore.kernel.org/lkml/Zbq72dJRpOlfRWnf@kernel.org/ Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-trace.c | 2 ++ .../perf/util/bpf_skel/augmented_raw_syscalls.bpf.c | 21 +++++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 90eaff8c0f6e..8fb032caeaf5 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -1049,6 +1049,8 @@ static const struct syscall_fmt syscall_fmts[] = { .arg = { [3] = { .scnprintf = SCA_MREMAP_FLAGS, /* flags */ }, }, }, { .name = "name_to_handle_at", .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, }, + { .name = "nanosleep", + .arg = { [0] = { .scnprintf = SCA_TIMESPEC, /* req */ }, }, }, { .name = "newfstatat", .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, }, { .name = "open", diff --git a/tools/perf/util/bpf_skel/augmented_raw_syscalls.bpf.c b/tools/perf/util/bpf_skel/augmented_raw_syscalls.bpf.c index 2872f9bc0785..0acbd74e8c76 100644 --- a/tools/perf/util/bpf_skel/augmented_raw_syscalls.bpf.c +++ b/tools/perf/util/bpf_skel/augmented_raw_syscalls.bpf.c @@ -341,6 +341,27 @@ failure: return 1; /* Failure: don't filter */ } +SEC("tp/syscalls/sys_enter_nanosleep") +int sys_enter_nanosleep(struct syscall_enter_args *args) +{ + struct augmented_args_payload *augmented_args = augmented_args_payload(); + const void *req_arg = (const void *)args->args[0]; + unsigned int len = sizeof(augmented_args->args); + __u32 size = sizeof(struct timespec64); + + if (augmented_args == NULL) + goto failure; + + if (size > sizeof(augmented_args->__data)) + goto failure; + + bpf_probe_read_user(&augmented_args->__data, size, req_arg); + + return augmented__output(args, augmented_args, len + size); +failure: + return 1; /* Failure: don't filter */ +} + static pid_t getpid(void) { return bpf_get_current_pid_tgid(); -- cgit v1.2.3-59-g8ed1b From 4b3761eebb1c5c1bacec66fafff51eb65c4139bc Mon Sep 17 00:00:00 2001 From: Bhaskar Chowdhury Date: Sat, 20 Mar 2021 04:58:24 +0530 Subject: perf c2c: Fix a punctuation s/dont/don\'t/ Signed-off-by: Bhaskar Chowdhury Acked-by: Randy Dunlap Cc: Alexander Shishkin Cc: Ingo Molnar Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20210319232824.742-1-unixbhaskar@gmail.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-c2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/builtin-c2c.c b/tools/perf/builtin-c2c.c index 16b40f5d43db..14f228c7c869 100644 --- a/tools/perf/builtin-c2c.c +++ b/tools/perf/builtin-c2c.c @@ -2050,7 +2050,7 @@ static int hpp_list__parse(struct perf_hpp_list *hpp_list, perf_hpp__setup_output_field(hpp_list); /* - * We dont need other sorting keys other than those + * We don't need other sorting keys other than those * we already specified. It also really slows down * the processing a lot with big number of output * fields, so switching this off for c2c. -- cgit v1.2.3-59-g8ed1b From 5d8c646038f2f173db79692607c313b195062759 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 11 Mar 2024 17:49:01 -0300 Subject: perf beauty: Fix dependency of tables using uapi/linux/mount.h Several such tables were depending on uapi/linux/fs.h, cut and paste error when they were introduced, fix it. Cc: Ian Rogers Cc: Jiri Olsa Cc: Adrian Hunter Cc: Namhyung Kim Link: https://lore.kernel.org/lkml/Ze9vjxv42PN_QGZv@x1 Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Makefile.perf | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index 04d89d2ed209..d3a568abc389 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -499,19 +499,19 @@ $(fadvise_advice_array): $(linux_uapi_dir)/in.h $(fadvise_advice_tbl) fsmount_arrays := $(beauty_outdir)/fsmount_arrays.c fsmount_tbls := $(srctree)/tools/perf/trace/beauty/fsmount.sh -$(fsmount_arrays): $(linux_uapi_dir)/fs.h $(fsmount_tbls) +$(fsmount_arrays): $(linux_uapi_dir)/mount.h $(fsmount_tbls) $(Q)$(SHELL) '$(fsmount_tbls)' $(linux_uapi_dir) > $@ fspick_arrays := $(beauty_outdir)/fspick_arrays.c fspick_tbls := $(srctree)/tools/perf/trace/beauty/fspick.sh -$(fspick_arrays): $(linux_uapi_dir)/fs.h $(fspick_tbls) +$(fspick_arrays): $(linux_uapi_dir)/mount.h $(fspick_tbls) $(Q)$(SHELL) '$(fspick_tbls)' $(linux_uapi_dir) > $@ fsconfig_arrays := $(beauty_outdir)/fsconfig_arrays.c fsconfig_tbls := $(srctree)/tools/perf/trace/beauty/fsconfig.sh -$(fsconfig_arrays): $(linux_uapi_dir)/fs.h $(fsconfig_tbls) +$(fsconfig_arrays): $(linux_uapi_dir)/mount.h $(fsconfig_tbls) $(Q)$(SHELL) '$(fsconfig_tbls)' $(linux_uapi_dir) > $@ pkey_alloc_access_rights_array := $(beauty_outdir)/pkey_alloc_access_rights_array.c @@ -597,13 +597,13 @@ $(mremap_flags_array): $(linux_uapi_dir)/mman.h $(mremap_flags_tbl) mount_flags_array := $(beauty_outdir)/mount_flags_array.c mount_flags_tbl := $(srctree)/tools/perf/trace/beauty/mount_flags.sh -$(mount_flags_array): $(linux_uapi_dir)/fs.h $(mount_flags_tbl) +$(mount_flags_array): $(linux_uapi_dir)/mount.h $(mount_flags_tbl) $(Q)$(SHELL) '$(mount_flags_tbl)' $(linux_uapi_dir) > $@ move_mount_flags_array := $(beauty_outdir)/move_mount_flags_array.c move_mount_flags_tbl := $(srctree)/tools/perf/trace/beauty/move_mount_flags.sh -$(move_mount_flags_array): $(linux_uapi_dir)/fs.h $(move_mount_flags_tbl) +$(move_mount_flags_array): $(linux_uapi_dir)/mount.h $(move_mount_flags_tbl) $(Q)$(SHELL) '$(move_mount_flags_tbl)' $(linux_uapi_dir) > $@ -- cgit v1.2.3-59-g8ed1b From faf7217a397f041f146a4cf6d9f1c9bd99cd5ca4 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 11 Mar 2024 17:07:33 -0300 Subject: perf beauty: Move uapi/linux/fs.h copy out of the directory used to build perf It is mostly used only to generate string tables, not to build perf, so move it to the tools/perf/trace/beauty/include/ hierarchy, that is used just for scraping. The only case where it was being used to build was in tools/perf/trace/beauty/sync_file_range.c, because some older systems doesn't have the SYNC_FILE_RANGE_WRITE_AND_WAIT define, just use the system's linux/fs.h header instead, defining it if not available. This is a something that should've have happened, as happened with the linux/socket.h scrapper, do it now as Ian suggested while doing an audit/refactor session in the headers used by perf. No other tools/ living code uses it, just coming from either 'make install_headers' or from the system /usr/include/ directory. Suggested-by: Ian Rogers Reviewed-by: Ian Rogers Cc: Adrian Hunter Cc: Jiri Olsa Cc: Namhyung Kim Link: https://lore.kernel.org/lkml/CAP-5=fWZVrpRufO4w-S4EcSi9STXcTAN2ERLwTSN7yrSSA-otQ@mail.gmail.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/include/uapi/linux/fs.h | 368 ------------------------ tools/perf/Makefile.perf | 9 +- tools/perf/check-headers.sh | 2 +- tools/perf/trace/beauty/include/uapi/linux/fs.h | 368 ++++++++++++++++++++++++ tools/perf/trace/beauty/rename_flags.sh | 2 +- tools/perf/trace/beauty/sync_file_range.c | 11 +- tools/perf/trace/beauty/sync_file_range.sh | 2 +- 7 files changed, 386 insertions(+), 376 deletions(-) delete mode 100644 tools/include/uapi/linux/fs.h create mode 100644 tools/perf/trace/beauty/include/uapi/linux/fs.h diff --git a/tools/include/uapi/linux/fs.h b/tools/include/uapi/linux/fs.h deleted file mode 100644 index 48ad69f7722e..000000000000 --- a/tools/include/uapi/linux/fs.h +++ /dev/null @@ -1,368 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -#ifndef _UAPI_LINUX_FS_H -#define _UAPI_LINUX_FS_H - -/* - * This file has definitions for some important file table structures - * and constants and structures used by various generic file system - * ioctl's. Please do not make any changes in this file before - * sending patches for review to linux-fsdevel@vger.kernel.org and - * linux-api@vger.kernel.org. - */ - -#include -#include -#include -#ifndef __KERNEL__ -#include -#endif - -/* Use of MS_* flags within the kernel is restricted to core mount(2) code. */ -#if !defined(__KERNEL__) -#include -#endif - -/* - * It's silly to have NR_OPEN bigger than NR_FILE, but you can change - * the file limit at runtime and only root can increase the per-process - * nr_file rlimit, so it's safe to set up a ridiculously high absolute - * upper limit on files-per-process. - * - * Some programs (notably those using select()) may have to be - * recompiled to take full advantage of the new limits.. - */ - -/* Fixed constants first: */ -#undef NR_OPEN -#define INR_OPEN_CUR 1024 /* Initial setting for nfile rlimits */ -#define INR_OPEN_MAX 4096 /* Hard limit for nfile rlimits */ - -#define BLOCK_SIZE_BITS 10 -#define BLOCK_SIZE (1< /dev/null beauty_linux_dir := $(srctree)/tools/perf/trace/beauty/include/linux/ +beauty_uapi_linux_dir := $(srctree)/tools/perf/trace/beauty/include/uapi/linux/ linux_uapi_dir := $(srctree)/tools/include/uapi/linux asm_generic_uapi_dir := $(srctree)/tools/include/uapi/asm-generic arch_asm_uapi_dir := $(srctree)/tools/arch/$(SRCARCH)/include/uapi/asm/ @@ -647,8 +648,8 @@ $(x86_arch_MSRs_array): $(x86_arch_asm_dir)/msr-index.h $(x86_arch_MSRs_tbl) rename_flags_array := $(beauty_outdir)/rename_flags_array.c rename_flags_tbl := $(srctree)/tools/perf/trace/beauty/rename_flags.sh -$(rename_flags_array): $(linux_uapi_dir)/fs.h $(rename_flags_tbl) - $(Q)$(SHELL) '$(rename_flags_tbl)' $(linux_uapi_dir) > $@ +$(rename_flags_array): $(beauty_uapi_linux_dir)/fs.h $(rename_flags_tbl) + $(Q)$(SHELL) '$(rename_flags_tbl)' $(beauty_uapi_linux_dir) > $@ arch_errno_name_array := $(beauty_outdir)/arch_errno_name_array.c arch_errno_hdr_dir := $(srctree)/tools @@ -660,8 +661,8 @@ $(arch_errno_name_array): $(arch_errno_tbl) sync_file_range_arrays := $(beauty_outdir)/sync_file_range_arrays.c sync_file_range_tbls := $(srctree)/tools/perf/trace/beauty/sync_file_range.sh -$(sync_file_range_arrays): $(linux_uapi_dir)/fs.h $(sync_file_range_tbls) - $(Q)$(SHELL) '$(sync_file_range_tbls)' $(linux_uapi_dir) > $@ +$(sync_file_range_arrays): $(beauty_uapi_linux_dir)/fs.h $(sync_file_range_tbls) + $(Q)$(SHELL) '$(sync_file_range_tbls)' $(beauty_uapi_linux_dir) > $@ TESTS_CORESIGHT_DIR := $(srctree)/tools/perf/tests/shell/coresight diff --git a/tools/perf/check-headers.sh b/tools/perf/check-headers.sh index 66ba33dbcef2..015f74137b75 100755 --- a/tools/perf/check-headers.sh +++ b/tools/perf/check-headers.sh @@ -11,7 +11,6 @@ FILES=( "include/uapi/drm/i915_drm.h" "include/uapi/linux/fadvise.h" "include/uapi/linux/fcntl.h" - "include/uapi/linux/fs.h" "include/uapi/linux/fscrypt.h" "include/uapi/linux/kcmp.h" "include/uapi/linux/kvm.h" @@ -98,6 +97,7 @@ SYNC_CHECK_FILES=( declare -a BEAUTY_FILES BEAUTY_FILES=( "include/linux/socket.h" + "include/uapi/linux/fs.h" ) declare -a FAILURES diff --git a/tools/perf/trace/beauty/include/uapi/linux/fs.h b/tools/perf/trace/beauty/include/uapi/linux/fs.h new file mode 100644 index 000000000000..48ad69f7722e --- /dev/null +++ b/tools/perf/trace/beauty/include/uapi/linux/fs.h @@ -0,0 +1,368 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _UAPI_LINUX_FS_H +#define _UAPI_LINUX_FS_H + +/* + * This file has definitions for some important file table structures + * and constants and structures used by various generic file system + * ioctl's. Please do not make any changes in this file before + * sending patches for review to linux-fsdevel@vger.kernel.org and + * linux-api@vger.kernel.org. + */ + +#include +#include +#include +#ifndef __KERNEL__ +#include +#endif + +/* Use of MS_* flags within the kernel is restricted to core mount(2) code. */ +#if !defined(__KERNEL__) +#include +#endif + +/* + * It's silly to have NR_OPEN bigger than NR_FILE, but you can change + * the file limit at runtime and only root can increase the per-process + * nr_file rlimit, so it's safe to set up a ridiculously high absolute + * upper limit on files-per-process. + * + * Some programs (notably those using select()) may have to be + * recompiled to take full advantage of the new limits.. + */ + +/* Fixed constants first: */ +#undef NR_OPEN +#define INR_OPEN_CUR 1024 /* Initial setting for nfile rlimits */ +#define INR_OPEN_MAX 4096 /* Hard limit for nfile rlimits */ + +#define BLOCK_SIZE_BITS 10 +#define BLOCK_SIZE (1< # SPDX-License-Identifier: LGPL-2.1 -[ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/linux/ +[ $# -eq 1 ] && header_dir=$1 || header_dir=tools/perf/trace/beauty/include/uapi/linux/ fs_header=${header_dir}/fs.h diff --git a/tools/perf/trace/beauty/sync_file_range.c b/tools/perf/trace/beauty/sync_file_range.c index 1c425f04047d..3e8f50ff4fc7 100644 --- a/tools/perf/trace/beauty/sync_file_range.c +++ b/tools/perf/trace/beauty/sync_file_range.c @@ -7,7 +7,16 @@ #include "trace/beauty/beauty.h" #include -#include +#include + +#ifndef SYNC_FILE_RANGE_WRITE_AND_WAIT +#define SYNC_FILE_RANGE_WAIT_BEFORE 1 +#define SYNC_FILE_RANGE_WRITE 2 +#define SYNC_FILE_RANGE_WAIT_AFTER 4 +#define SYNC_FILE_RANGE_WRITE_AND_WAIT (SYNC_FILE_RANGE_WRITE | \ + SYNC_FILE_RANGE_WAIT_BEFORE | \ + SYNC_FILE_RANGE_WAIT_AFTER) +#endif static size_t sync_file_range__scnprintf_flags(unsigned long flags, char *bf, size_t size, bool show_prefix) { diff --git a/tools/perf/trace/beauty/sync_file_range.sh b/tools/perf/trace/beauty/sync_file_range.sh index 90bf633be879..b1084c4cab63 100755 --- a/tools/perf/trace/beauty/sync_file_range.sh +++ b/tools/perf/trace/beauty/sync_file_range.sh @@ -2,7 +2,7 @@ # SPDX-License-Identifier: LGPL-2.1 if [ $# -ne 1 ] ; then - linux_header_dir=tools/include/uapi/linux + linux_header_dir=tools/perf/trace/beauty/include/uapi/linux/ else linux_header_dir=$1 fi -- cgit v1.2.3-59-g8ed1b From 22916d2cbad9a20d3fbca7cda015efcf10427297 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 12 Mar 2024 13:53:39 -0300 Subject: perf beauty: Don't include uapi/linux/mount.h, use sys/mount.h instead The tools/include/uapi/linux/mount.h file is mostly used for scrapping defines into id->string tables, this is the only place were it is being directly used, stop doing so. Define MOUNT_ATTR_RELATIME and MOUNT_ATTR__ATIME if not available in the system's headers. Cc: Adrian Hunter Cc: Ian Rogers Cc: Jiri Olsa Cc: Namhyung Kim Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/trace/beauty/fsmount.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tools/perf/trace/beauty/fsmount.c b/tools/perf/trace/beauty/fsmount.c index 30c8c082a3c3..28c2c16fc1a8 100644 --- a/tools/perf/trace/beauty/fsmount.c +++ b/tools/perf/trace/beauty/fsmount.c @@ -7,7 +7,14 @@ #include "trace/beauty/beauty.h" #include -#include +#include + +#ifndef MOUNT_ATTR__ATIME +#define MOUNT_ATTR__ATIME 0x00000070 /* Setting on how atime should be updated */ +#endif +#ifndef MOUNT_ATTR_RELATIME +#define MOUNT_ATTR_RELATIME 0x00000000 /* - Update atime relative to mtime/ctime. */ +#endif static size_t fsmount__scnprintf_attr_flags(unsigned long flags, char *bf, size_t size, bool show_prefix) { -- cgit v1.2.3-59-g8ed1b From ab3316119f9d0b3a1c4b90809ea37ab7927de72b Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 11 Mar 2024 17:07:33 -0300 Subject: perf beauty: Move uapi/linux/mount.h copy out of the directory used to build perf It is mostly used only to generate string tables, not to build perf, so move it to the tools/perf/trace/beauty/include/ hierarchy, that is used just for scraping. This is a something that should've have happened, as happened with the linux/socket.h scrapper, do it now as Ian suggested while doing an audit/refactor session in the headers used by perf. No other tools/ living code uses it, just coming from either 'make install_headers' or from the system /usr/include/ directory. Suggested-by: Ian Rogers Cc: Adrian Hunter Cc: Jiri Olsa Cc: Namhyung Kim Link: https://lore.kernel.org/lkml/CAP-5=fWZVrpRufO4w-S4EcSi9STXcTAN2ERLwTSN7yrSSA-otQ@mail.gmail.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/include/uapi/linux/mount.h | 211 --------------------- tools/perf/Makefile.perf | 21 +- tools/perf/check-headers.sh | 2 +- tools/perf/trace/beauty/fsconfig.sh | 6 +- tools/perf/trace/beauty/fsmount.sh | 6 +- tools/perf/trace/beauty/fspick.sh | 6 +- tools/perf/trace/beauty/include/uapi/linux/mount.h | 211 +++++++++++++++++++++ tools/perf/trace/beauty/mount_flags.sh | 6 +- tools/perf/trace/beauty/move_mount_flags.sh | 6 +- 9 files changed, 237 insertions(+), 238 deletions(-) delete mode 100644 tools/include/uapi/linux/mount.h create mode 100644 tools/perf/trace/beauty/include/uapi/linux/mount.h diff --git a/tools/include/uapi/linux/mount.h b/tools/include/uapi/linux/mount.h deleted file mode 100644 index ad5478dbad00..000000000000 --- a/tools/include/uapi/linux/mount.h +++ /dev/null @@ -1,211 +0,0 @@ -#ifndef _UAPI_LINUX_MOUNT_H -#define _UAPI_LINUX_MOUNT_H - -#include - -/* - * These are the fs-independent mount-flags: up to 32 flags are supported - * - * Usage of these is restricted within the kernel to core mount(2) code and - * callers of sys_mount() only. Filesystems should be using the SB_* - * equivalent instead. - */ -#define MS_RDONLY 1 /* Mount read-only */ -#define MS_NOSUID 2 /* Ignore suid and sgid bits */ -#define MS_NODEV 4 /* Disallow access to device special files */ -#define MS_NOEXEC 8 /* Disallow program execution */ -#define MS_SYNCHRONOUS 16 /* Writes are synced at once */ -#define MS_REMOUNT 32 /* Alter flags of a mounted FS */ -#define MS_MANDLOCK 64 /* Allow mandatory locks on an FS */ -#define MS_DIRSYNC 128 /* Directory modifications are synchronous */ -#define MS_NOSYMFOLLOW 256 /* Do not follow symlinks */ -#define MS_NOATIME 1024 /* Do not update access times. */ -#define MS_NODIRATIME 2048 /* Do not update directory access times */ -#define MS_BIND 4096 -#define MS_MOVE 8192 -#define MS_REC 16384 -#define MS_VERBOSE 32768 /* War is peace. Verbosity is silence. - MS_VERBOSE is deprecated. */ -#define MS_SILENT 32768 -#define MS_POSIXACL (1<<16) /* VFS does not apply the umask */ -#define MS_UNBINDABLE (1<<17) /* change to unbindable */ -#define MS_PRIVATE (1<<18) /* change to private */ -#define MS_SLAVE (1<<19) /* change to slave */ -#define MS_SHARED (1<<20) /* change to shared */ -#define MS_RELATIME (1<<21) /* Update atime relative to mtime/ctime. */ -#define MS_KERNMOUNT (1<<22) /* this is a kern_mount call */ -#define MS_I_VERSION (1<<23) /* Update inode I_version field */ -#define MS_STRICTATIME (1<<24) /* Always perform atime updates */ -#define MS_LAZYTIME (1<<25) /* Update the on-disk [acm]times lazily */ - -/* These sb flags are internal to the kernel */ -#define MS_SUBMOUNT (1<<26) -#define MS_NOREMOTELOCK (1<<27) -#define MS_NOSEC (1<<28) -#define MS_BORN (1<<29) -#define MS_ACTIVE (1<<30) -#define MS_NOUSER (1<<31) - -/* - * Superblock flags that can be altered by MS_REMOUNT - */ -#define MS_RMT_MASK (MS_RDONLY|MS_SYNCHRONOUS|MS_MANDLOCK|MS_I_VERSION|\ - MS_LAZYTIME) - -/* - * Old magic mount flag and mask - */ -#define MS_MGC_VAL 0xC0ED0000 -#define MS_MGC_MSK 0xffff0000 - -/* - * open_tree() flags. - */ -#define OPEN_TREE_CLONE 1 /* Clone the target tree and attach the clone */ -#define OPEN_TREE_CLOEXEC O_CLOEXEC /* Close the file on execve() */ - -/* - * move_mount() flags. - */ -#define MOVE_MOUNT_F_SYMLINKS 0x00000001 /* Follow symlinks on from path */ -#define MOVE_MOUNT_F_AUTOMOUNTS 0x00000002 /* Follow automounts on from path */ -#define MOVE_MOUNT_F_EMPTY_PATH 0x00000004 /* Empty from path permitted */ -#define MOVE_MOUNT_T_SYMLINKS 0x00000010 /* Follow symlinks on to path */ -#define MOVE_MOUNT_T_AUTOMOUNTS 0x00000020 /* Follow automounts on to path */ -#define MOVE_MOUNT_T_EMPTY_PATH 0x00000040 /* Empty to path permitted */ -#define MOVE_MOUNT_SET_GROUP 0x00000100 /* Set sharing group instead */ -#define MOVE_MOUNT_BENEATH 0x00000200 /* Mount beneath top mount */ -#define MOVE_MOUNT__MASK 0x00000377 - -/* - * fsopen() flags. - */ -#define FSOPEN_CLOEXEC 0x00000001 - -/* - * fspick() flags. - */ -#define FSPICK_CLOEXEC 0x00000001 -#define FSPICK_SYMLINK_NOFOLLOW 0x00000002 -#define FSPICK_NO_AUTOMOUNT 0x00000004 -#define FSPICK_EMPTY_PATH 0x00000008 - -/* - * The type of fsconfig() call made. - */ -enum fsconfig_command { - FSCONFIG_SET_FLAG = 0, /* Set parameter, supplying no value */ - FSCONFIG_SET_STRING = 1, /* Set parameter, supplying a string value */ - FSCONFIG_SET_BINARY = 2, /* Set parameter, supplying a binary blob value */ - FSCONFIG_SET_PATH = 3, /* Set parameter, supplying an object by path */ - FSCONFIG_SET_PATH_EMPTY = 4, /* Set parameter, supplying an object by (empty) path */ - FSCONFIG_SET_FD = 5, /* Set parameter, supplying an object by fd */ - FSCONFIG_CMD_CREATE = 6, /* Create new or reuse existing superblock */ - FSCONFIG_CMD_RECONFIGURE = 7, /* Invoke superblock reconfiguration */ - FSCONFIG_CMD_CREATE_EXCL = 8, /* Create new superblock, fail if reusing existing superblock */ -}; - -/* - * fsmount() flags. - */ -#define FSMOUNT_CLOEXEC 0x00000001 - -/* - * Mount attributes. - */ -#define MOUNT_ATTR_RDONLY 0x00000001 /* Mount read-only */ -#define MOUNT_ATTR_NOSUID 0x00000002 /* Ignore suid and sgid bits */ -#define MOUNT_ATTR_NODEV 0x00000004 /* Disallow access to device special files */ -#define MOUNT_ATTR_NOEXEC 0x00000008 /* Disallow program execution */ -#define MOUNT_ATTR__ATIME 0x00000070 /* Setting on how atime should be updated */ -#define MOUNT_ATTR_RELATIME 0x00000000 /* - Update atime relative to mtime/ctime. */ -#define MOUNT_ATTR_NOATIME 0x00000010 /* - Do not update access times. */ -#define MOUNT_ATTR_STRICTATIME 0x00000020 /* - Always perform atime updates */ -#define MOUNT_ATTR_NODIRATIME 0x00000080 /* Do not update directory access times */ -#define MOUNT_ATTR_IDMAP 0x00100000 /* Idmap mount to @userns_fd in struct mount_attr. */ -#define MOUNT_ATTR_NOSYMFOLLOW 0x00200000 /* Do not follow symlinks */ - -/* - * mount_setattr() - */ -struct mount_attr { - __u64 attr_set; - __u64 attr_clr; - __u64 propagation; - __u64 userns_fd; -}; - -/* List of all mount_attr versions. */ -#define MOUNT_ATTR_SIZE_VER0 32 /* sizeof first published struct */ - - -/* - * Structure for getting mount/superblock/filesystem info with statmount(2). - * - * The interface is similar to statx(2): individual fields or groups can be - * selected with the @mask argument of statmount(). Kernel will set the @mask - * field according to the supported fields. - * - * If string fields are selected, then the caller needs to pass a buffer that - * has space after the fixed part of the structure. Nul terminated strings are - * copied there and offsets relative to @str are stored in the relevant fields. - * If the buffer is too small, then EOVERFLOW is returned. The actually used - * size is returned in @size. - */ -struct statmount { - __u32 size; /* Total size, including strings */ - __u32 __spare1; - __u64 mask; /* What results were written */ - __u32 sb_dev_major; /* Device ID */ - __u32 sb_dev_minor; - __u64 sb_magic; /* ..._SUPER_MAGIC */ - __u32 sb_flags; /* SB_{RDONLY,SYNCHRONOUS,DIRSYNC,LAZYTIME} */ - __u32 fs_type; /* [str] Filesystem type */ - __u64 mnt_id; /* Unique ID of mount */ - __u64 mnt_parent_id; /* Unique ID of parent (for root == mnt_id) */ - __u32 mnt_id_old; /* Reused IDs used in proc/.../mountinfo */ - __u32 mnt_parent_id_old; - __u64 mnt_attr; /* MOUNT_ATTR_... */ - __u64 mnt_propagation; /* MS_{SHARED,SLAVE,PRIVATE,UNBINDABLE} */ - __u64 mnt_peer_group; /* ID of shared peer group */ - __u64 mnt_master; /* Mount receives propagation from this ID */ - __u64 propagate_from; /* Propagation from in current namespace */ - __u32 mnt_root; /* [str] Root of mount relative to root of fs */ - __u32 mnt_point; /* [str] Mountpoint relative to current root */ - __u64 __spare2[50]; - char str[]; /* Variable size part containing strings */ -}; - -/* - * Structure for passing mount ID and miscellaneous parameters to statmount(2) - * and listmount(2). - * - * For statmount(2) @param represents the request mask. - * For listmount(2) @param represents the last listed mount id (or zero). - */ -struct mnt_id_req { - __u32 size; - __u32 spare; - __u64 mnt_id; - __u64 param; -}; - -/* List of all mnt_id_req versions. */ -#define MNT_ID_REQ_SIZE_VER0 24 /* sizeof first published struct */ - -/* - * @mask bits for statmount(2) - */ -#define STATMOUNT_SB_BASIC 0x00000001U /* Want/got sb_... */ -#define STATMOUNT_MNT_BASIC 0x00000002U /* Want/got mnt_... */ -#define STATMOUNT_PROPAGATE_FROM 0x00000004U /* Want/got propagate_from */ -#define STATMOUNT_MNT_ROOT 0x00000008U /* Want/got mnt_root */ -#define STATMOUNT_MNT_POINT 0x00000010U /* Want/got mnt_point */ -#define STATMOUNT_FS_TYPE 0x00000020U /* Want/got fs_type */ - -/* - * Special @mnt_id values that can be passed to listmount - */ -#define LSMT_ROOT 0xffffffffffffffff /* root mount */ - -#endif /* _UAPI_LINUX_MOUNT_H */ diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index 643e9fa6ec89..523c3b7d6c9d 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -500,20 +500,20 @@ $(fadvise_advice_array): $(linux_uapi_dir)/in.h $(fadvise_advice_tbl) fsmount_arrays := $(beauty_outdir)/fsmount_arrays.c fsmount_tbls := $(srctree)/tools/perf/trace/beauty/fsmount.sh -$(fsmount_arrays): $(linux_uapi_dir)/mount.h $(fsmount_tbls) - $(Q)$(SHELL) '$(fsmount_tbls)' $(linux_uapi_dir) > $@ +$(fsmount_arrays): $(beauty_uapi_linux_dir)/mount.h $(fsmount_tbls) + $(Q)$(SHELL) '$(fsmount_tbls)' $(beauty_uapi_linux_dir) > $@ fspick_arrays := $(beauty_outdir)/fspick_arrays.c fspick_tbls := $(srctree)/tools/perf/trace/beauty/fspick.sh -$(fspick_arrays): $(linux_uapi_dir)/mount.h $(fspick_tbls) - $(Q)$(SHELL) '$(fspick_tbls)' $(linux_uapi_dir) > $@ +$(fspick_arrays): $(beauty_uapi_linux_dir)/mount.h $(fspick_tbls) + $(Q)$(SHELL) '$(fspick_tbls)' $(beauty_uapi_linux_dir) > $@ fsconfig_arrays := $(beauty_outdir)/fsconfig_arrays.c fsconfig_tbls := $(srctree)/tools/perf/trace/beauty/fsconfig.sh -$(fsconfig_arrays): $(linux_uapi_dir)/mount.h $(fsconfig_tbls) - $(Q)$(SHELL) '$(fsconfig_tbls)' $(linux_uapi_dir) > $@ +$(fsconfig_arrays): $(beauty_uapi_linux_dir)/mount.h $(fsconfig_tbls) + $(Q)$(SHELL) '$(fsconfig_tbls)' $(beauty_uapi_linux_dir) > $@ pkey_alloc_access_rights_array := $(beauty_outdir)/pkey_alloc_access_rights_array.c asm_generic_hdr_dir := $(srctree)/tools/include/uapi/asm-generic/ @@ -598,15 +598,14 @@ $(mremap_flags_array): $(linux_uapi_dir)/mman.h $(mremap_flags_tbl) mount_flags_array := $(beauty_outdir)/mount_flags_array.c mount_flags_tbl := $(srctree)/tools/perf/trace/beauty/mount_flags.sh -$(mount_flags_array): $(linux_uapi_dir)/mount.h $(mount_flags_tbl) - $(Q)$(SHELL) '$(mount_flags_tbl)' $(linux_uapi_dir) > $@ +$(mount_flags_array): $(beauty_uapi_linux_dir)/mount.h $(mount_flags_tbl) + $(Q)$(SHELL) '$(mount_flags_tbl)' $(beauty_uapi_linux_dir) > $@ move_mount_flags_array := $(beauty_outdir)/move_mount_flags_array.c move_mount_flags_tbl := $(srctree)/tools/perf/trace/beauty/move_mount_flags.sh -$(move_mount_flags_array): $(linux_uapi_dir)/mount.h $(move_mount_flags_tbl) - $(Q)$(SHELL) '$(move_mount_flags_tbl)' $(linux_uapi_dir) > $@ - +$(move_mount_flags_array): $(beauty_uapi_linux_dir)/mount.h $(move_mount_flags_tbl) + $(Q)$(SHELL) '$(move_mount_flags_tbl)' $(beauty_uapi_linux_dir) > $@ mmap_prot_array := $(beauty_outdir)/mmap_prot_array.c mmap_prot_tbl := $(srctree)/tools/perf/trace/beauty/mmap_prot.sh diff --git a/tools/perf/check-headers.sh b/tools/perf/check-headers.sh index 015f74137b75..c2c26d6b87ef 100755 --- a/tools/perf/check-headers.sh +++ b/tools/perf/check-headers.sh @@ -15,7 +15,6 @@ FILES=( "include/uapi/linux/kcmp.h" "include/uapi/linux/kvm.h" "include/uapi/linux/in.h" - "include/uapi/linux/mount.h" "include/uapi/linux/openat2.h" "include/uapi/linux/perf_event.h" "include/uapi/linux/prctl.h" @@ -98,6 +97,7 @@ declare -a BEAUTY_FILES BEAUTY_FILES=( "include/linux/socket.h" "include/uapi/linux/fs.h" + "include/uapi/linux/mount.h" ) declare -a FAILURES diff --git a/tools/perf/trace/beauty/fsconfig.sh b/tools/perf/trace/beauty/fsconfig.sh index bc6ef7bb7a5f..09cee79de00c 100755 --- a/tools/perf/trace/beauty/fsconfig.sh +++ b/tools/perf/trace/beauty/fsconfig.sh @@ -2,12 +2,12 @@ # SPDX-License-Identifier: LGPL-2.1 if [ $# -ne 1 ] ; then - linux_header_dir=tools/include/uapi/linux + beauty_uapi_linux_dir=tools/perf/trace/beauty/include/uapi/linux/ else - linux_header_dir=$1 + beauty_uapi_linux_dir=$1 fi -linux_mount=${linux_header_dir}/mount.h +linux_mount=${beauty_uapi_linux_dir}/mount.h printf "static const char *fsconfig_cmds[] = {\n" ms='[[:space:]]*' diff --git a/tools/perf/trace/beauty/fsmount.sh b/tools/perf/trace/beauty/fsmount.sh index cba8897a751f..6b67a54cdeee 100755 --- a/tools/perf/trace/beauty/fsmount.sh +++ b/tools/perf/trace/beauty/fsmount.sh @@ -2,12 +2,12 @@ # SPDX-License-Identifier: LGPL-2.1 if [ $# -ne 1 ] ; then - linux_header_dir=tools/include/uapi/linux + beauty_uapi_linux_dir=tools/perf/trace/beauty/include/uapi/linux/ else - linux_header_dir=$1 + beauty_uapi_linux_dir=$1 fi -linux_mount=${linux_header_dir}/mount.h +linux_mount=${beauty_uapi_linux_dir}/mount.h # Remove MOUNT_ATTR_RELATIME as it is zeros, handle it a special way in the beautifier # Only handle MOUNT_ATTR_ followed by a capital letter/num as __ is special case diff --git a/tools/perf/trace/beauty/fspick.sh b/tools/perf/trace/beauty/fspick.sh index 1f088329b96e..0d9951c22b95 100755 --- a/tools/perf/trace/beauty/fspick.sh +++ b/tools/perf/trace/beauty/fspick.sh @@ -2,12 +2,12 @@ # SPDX-License-Identifier: LGPL-2.1 if [ $# -ne 1 ] ; then - linux_header_dir=tools/include/uapi/linux + beauty_uapi_linux_dir=tools/perf/trace/beauty/include/uapi/linux/ else - linux_header_dir=$1 + beauty_uapi_linux_dir=$1 fi -linux_mount=${linux_header_dir}/mount.h +linux_mount=${beauty_uapi_linux_dir}/mount.h printf "static const char *fspick_flags[] = {\n" regex='^[[:space:]]*#[[:space:]]*define[[:space:]]+FSPICK_([[:alnum:]_]+)[[:space:]]+(0x[[:xdigit:]]+)[[:space:]]*.*' diff --git a/tools/perf/trace/beauty/include/uapi/linux/mount.h b/tools/perf/trace/beauty/include/uapi/linux/mount.h new file mode 100644 index 000000000000..ad5478dbad00 --- /dev/null +++ b/tools/perf/trace/beauty/include/uapi/linux/mount.h @@ -0,0 +1,211 @@ +#ifndef _UAPI_LINUX_MOUNT_H +#define _UAPI_LINUX_MOUNT_H + +#include + +/* + * These are the fs-independent mount-flags: up to 32 flags are supported + * + * Usage of these is restricted within the kernel to core mount(2) code and + * callers of sys_mount() only. Filesystems should be using the SB_* + * equivalent instead. + */ +#define MS_RDONLY 1 /* Mount read-only */ +#define MS_NOSUID 2 /* Ignore suid and sgid bits */ +#define MS_NODEV 4 /* Disallow access to device special files */ +#define MS_NOEXEC 8 /* Disallow program execution */ +#define MS_SYNCHRONOUS 16 /* Writes are synced at once */ +#define MS_REMOUNT 32 /* Alter flags of a mounted FS */ +#define MS_MANDLOCK 64 /* Allow mandatory locks on an FS */ +#define MS_DIRSYNC 128 /* Directory modifications are synchronous */ +#define MS_NOSYMFOLLOW 256 /* Do not follow symlinks */ +#define MS_NOATIME 1024 /* Do not update access times. */ +#define MS_NODIRATIME 2048 /* Do not update directory access times */ +#define MS_BIND 4096 +#define MS_MOVE 8192 +#define MS_REC 16384 +#define MS_VERBOSE 32768 /* War is peace. Verbosity is silence. + MS_VERBOSE is deprecated. */ +#define MS_SILENT 32768 +#define MS_POSIXACL (1<<16) /* VFS does not apply the umask */ +#define MS_UNBINDABLE (1<<17) /* change to unbindable */ +#define MS_PRIVATE (1<<18) /* change to private */ +#define MS_SLAVE (1<<19) /* change to slave */ +#define MS_SHARED (1<<20) /* change to shared */ +#define MS_RELATIME (1<<21) /* Update atime relative to mtime/ctime. */ +#define MS_KERNMOUNT (1<<22) /* this is a kern_mount call */ +#define MS_I_VERSION (1<<23) /* Update inode I_version field */ +#define MS_STRICTATIME (1<<24) /* Always perform atime updates */ +#define MS_LAZYTIME (1<<25) /* Update the on-disk [acm]times lazily */ + +/* These sb flags are internal to the kernel */ +#define MS_SUBMOUNT (1<<26) +#define MS_NOREMOTELOCK (1<<27) +#define MS_NOSEC (1<<28) +#define MS_BORN (1<<29) +#define MS_ACTIVE (1<<30) +#define MS_NOUSER (1<<31) + +/* + * Superblock flags that can be altered by MS_REMOUNT + */ +#define MS_RMT_MASK (MS_RDONLY|MS_SYNCHRONOUS|MS_MANDLOCK|MS_I_VERSION|\ + MS_LAZYTIME) + +/* + * Old magic mount flag and mask + */ +#define MS_MGC_VAL 0xC0ED0000 +#define MS_MGC_MSK 0xffff0000 + +/* + * open_tree() flags. + */ +#define OPEN_TREE_CLONE 1 /* Clone the target tree and attach the clone */ +#define OPEN_TREE_CLOEXEC O_CLOEXEC /* Close the file on execve() */ + +/* + * move_mount() flags. + */ +#define MOVE_MOUNT_F_SYMLINKS 0x00000001 /* Follow symlinks on from path */ +#define MOVE_MOUNT_F_AUTOMOUNTS 0x00000002 /* Follow automounts on from path */ +#define MOVE_MOUNT_F_EMPTY_PATH 0x00000004 /* Empty from path permitted */ +#define MOVE_MOUNT_T_SYMLINKS 0x00000010 /* Follow symlinks on to path */ +#define MOVE_MOUNT_T_AUTOMOUNTS 0x00000020 /* Follow automounts on to path */ +#define MOVE_MOUNT_T_EMPTY_PATH 0x00000040 /* Empty to path permitted */ +#define MOVE_MOUNT_SET_GROUP 0x00000100 /* Set sharing group instead */ +#define MOVE_MOUNT_BENEATH 0x00000200 /* Mount beneath top mount */ +#define MOVE_MOUNT__MASK 0x00000377 + +/* + * fsopen() flags. + */ +#define FSOPEN_CLOEXEC 0x00000001 + +/* + * fspick() flags. + */ +#define FSPICK_CLOEXEC 0x00000001 +#define FSPICK_SYMLINK_NOFOLLOW 0x00000002 +#define FSPICK_NO_AUTOMOUNT 0x00000004 +#define FSPICK_EMPTY_PATH 0x00000008 + +/* + * The type of fsconfig() call made. + */ +enum fsconfig_command { + FSCONFIG_SET_FLAG = 0, /* Set parameter, supplying no value */ + FSCONFIG_SET_STRING = 1, /* Set parameter, supplying a string value */ + FSCONFIG_SET_BINARY = 2, /* Set parameter, supplying a binary blob value */ + FSCONFIG_SET_PATH = 3, /* Set parameter, supplying an object by path */ + FSCONFIG_SET_PATH_EMPTY = 4, /* Set parameter, supplying an object by (empty) path */ + FSCONFIG_SET_FD = 5, /* Set parameter, supplying an object by fd */ + FSCONFIG_CMD_CREATE = 6, /* Create new or reuse existing superblock */ + FSCONFIG_CMD_RECONFIGURE = 7, /* Invoke superblock reconfiguration */ + FSCONFIG_CMD_CREATE_EXCL = 8, /* Create new superblock, fail if reusing existing superblock */ +}; + +/* + * fsmount() flags. + */ +#define FSMOUNT_CLOEXEC 0x00000001 + +/* + * Mount attributes. + */ +#define MOUNT_ATTR_RDONLY 0x00000001 /* Mount read-only */ +#define MOUNT_ATTR_NOSUID 0x00000002 /* Ignore suid and sgid bits */ +#define MOUNT_ATTR_NODEV 0x00000004 /* Disallow access to device special files */ +#define MOUNT_ATTR_NOEXEC 0x00000008 /* Disallow program execution */ +#define MOUNT_ATTR__ATIME 0x00000070 /* Setting on how atime should be updated */ +#define MOUNT_ATTR_RELATIME 0x00000000 /* - Update atime relative to mtime/ctime. */ +#define MOUNT_ATTR_NOATIME 0x00000010 /* - Do not update access times. */ +#define MOUNT_ATTR_STRICTATIME 0x00000020 /* - Always perform atime updates */ +#define MOUNT_ATTR_NODIRATIME 0x00000080 /* Do not update directory access times */ +#define MOUNT_ATTR_IDMAP 0x00100000 /* Idmap mount to @userns_fd in struct mount_attr. */ +#define MOUNT_ATTR_NOSYMFOLLOW 0x00200000 /* Do not follow symlinks */ + +/* + * mount_setattr() + */ +struct mount_attr { + __u64 attr_set; + __u64 attr_clr; + __u64 propagation; + __u64 userns_fd; +}; + +/* List of all mount_attr versions. */ +#define MOUNT_ATTR_SIZE_VER0 32 /* sizeof first published struct */ + + +/* + * Structure for getting mount/superblock/filesystem info with statmount(2). + * + * The interface is similar to statx(2): individual fields or groups can be + * selected with the @mask argument of statmount(). Kernel will set the @mask + * field according to the supported fields. + * + * If string fields are selected, then the caller needs to pass a buffer that + * has space after the fixed part of the structure. Nul terminated strings are + * copied there and offsets relative to @str are stored in the relevant fields. + * If the buffer is too small, then EOVERFLOW is returned. The actually used + * size is returned in @size. + */ +struct statmount { + __u32 size; /* Total size, including strings */ + __u32 __spare1; + __u64 mask; /* What results were written */ + __u32 sb_dev_major; /* Device ID */ + __u32 sb_dev_minor; + __u64 sb_magic; /* ..._SUPER_MAGIC */ + __u32 sb_flags; /* SB_{RDONLY,SYNCHRONOUS,DIRSYNC,LAZYTIME} */ + __u32 fs_type; /* [str] Filesystem type */ + __u64 mnt_id; /* Unique ID of mount */ + __u64 mnt_parent_id; /* Unique ID of parent (for root == mnt_id) */ + __u32 mnt_id_old; /* Reused IDs used in proc/.../mountinfo */ + __u32 mnt_parent_id_old; + __u64 mnt_attr; /* MOUNT_ATTR_... */ + __u64 mnt_propagation; /* MS_{SHARED,SLAVE,PRIVATE,UNBINDABLE} */ + __u64 mnt_peer_group; /* ID of shared peer group */ + __u64 mnt_master; /* Mount receives propagation from this ID */ + __u64 propagate_from; /* Propagation from in current namespace */ + __u32 mnt_root; /* [str] Root of mount relative to root of fs */ + __u32 mnt_point; /* [str] Mountpoint relative to current root */ + __u64 __spare2[50]; + char str[]; /* Variable size part containing strings */ +}; + +/* + * Structure for passing mount ID and miscellaneous parameters to statmount(2) + * and listmount(2). + * + * For statmount(2) @param represents the request mask. + * For listmount(2) @param represents the last listed mount id (or zero). + */ +struct mnt_id_req { + __u32 size; + __u32 spare; + __u64 mnt_id; + __u64 param; +}; + +/* List of all mnt_id_req versions. */ +#define MNT_ID_REQ_SIZE_VER0 24 /* sizeof first published struct */ + +/* + * @mask bits for statmount(2) + */ +#define STATMOUNT_SB_BASIC 0x00000001U /* Want/got sb_... */ +#define STATMOUNT_MNT_BASIC 0x00000002U /* Want/got mnt_... */ +#define STATMOUNT_PROPAGATE_FROM 0x00000004U /* Want/got propagate_from */ +#define STATMOUNT_MNT_ROOT 0x00000008U /* Want/got mnt_root */ +#define STATMOUNT_MNT_POINT 0x00000010U /* Want/got mnt_point */ +#define STATMOUNT_FS_TYPE 0x00000020U /* Want/got fs_type */ + +/* + * Special @mnt_id values that can be passed to listmount + */ +#define LSMT_ROOT 0xffffffffffffffff /* root mount */ + +#endif /* _UAPI_LINUX_MOUNT_H */ diff --git a/tools/perf/trace/beauty/mount_flags.sh b/tools/perf/trace/beauty/mount_flags.sh index 730099a9a67c..ff578f7b451b 100755 --- a/tools/perf/trace/beauty/mount_flags.sh +++ b/tools/perf/trace/beauty/mount_flags.sh @@ -1,15 +1,15 @@ #!/bin/sh # SPDX-License-Identifier: LGPL-2.1 -[ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/linux/ +[ $# -eq 1 ] && beauty_uapi_linux_dir=$1 || beauty_uapi_linux_dir=tools/perf/trace/beauty/include/uapi/linux/ printf "static const char *mount_flags[] = {\n" regex='^[[:space:]]*#[[:space:]]*define[[:space:]]+MS_([[:alnum:]_]+)[[:space:]]+([[:digit:]]+)[[:space:]]*.*' -grep -E $regex ${header_dir}/mount.h | grep -E -v '(MSK|VERBOSE|MGC_VAL)\>' | \ +grep -E $regex ${beauty_uapi_linux_dir}/mount.h | grep -E -v '(MSK|VERBOSE|MGC_VAL)\>' | \ sed -r "s/$regex/\2 \2 \1/g" | sort -n | \ xargs printf "\t[%s ? (ilog2(%s) + 1) : 0] = \"%s\",\n" regex='^[[:space:]]*#[[:space:]]*define[[:space:]]+MS_([[:alnum:]_]+)[[:space:]]+\(1<<([[:digit:]]+)\)[[:space:]]*.*' -grep -E $regex ${header_dir}/mount.h | \ +grep -E $regex ${beauty_uapi_linux_dir}/mount.h | \ sed -r "s/$regex/\2 \1/g" | \ xargs printf "\t[%s + 1] = \"%s\",\n" printf "};\n" diff --git a/tools/perf/trace/beauty/move_mount_flags.sh b/tools/perf/trace/beauty/move_mount_flags.sh index ce5e632d1448..c0dde9020bc3 100755 --- a/tools/perf/trace/beauty/move_mount_flags.sh +++ b/tools/perf/trace/beauty/move_mount_flags.sh @@ -2,12 +2,12 @@ # SPDX-License-Identifier: LGPL-2.1 if [ $# -ne 1 ] ; then - linux_header_dir=tools/include/uapi/linux + beauty_uapi_linux_dir=tools/perf/trace/beauty/include/uapi/linux/ else - linux_header_dir=$1 + beauty_uapi_linux_dir=$1 fi -linux_mount=${linux_header_dir}/mount.h +linux_mount=${beauty_uapi_linux_dir}/mount.h printf "static const char *move_mount_flags[] = {\n" regex='^[[:space:]]*#[[:space:]]*define[[:space:]]+MOVE_MOUNT_([^_]+[[:alnum:]_]+)[[:space:]]+(0x[[:xdigit:]]+)[[:space:]]*.*' -- cgit v1.2.3-59-g8ed1b From 44512bd6136ec7bb31e4dfaaf49313d91539af6f Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 11 Mar 2024 17:07:33 -0300 Subject: perf beauty: Move uapi/linux/usbdevice_fs.h copy out of the directory used to build perf It is mostly used only to generate string tables, not to build perf, so move it to the tools/perf/trace/beauty/include/ hierarchy, that is used just for scraping. This is a something that should've have happened, as happened with the linux/socket.h scrapper, do it now as Ian suggested while doing an audit/refactor session in the headers used by perf. No other tools/ living code uses it, just coming from either 'make install_headers' or from the system /usr/include/ directory. Suggested-by: Ian Rogers Reviewed-by: Ian Rogers Cc: Adrian Hunter Cc: Jiri Olsa Cc: Namhyung Kim Link: https://lore.kernel.org/lkml/CAP-5=fWZVrpRufO4w-S4EcSi9STXcTAN2ERLwTSN7yrSSA-otQ@mail.gmail.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/include/uapi/linux/usbdevice_fs.h | 231 --------------------- tools/perf/Makefile.perf | 4 +- tools/perf/check-headers.sh | 2 +- .../trace/beauty/include/uapi/linux/usbdevice_fs.h | 231 +++++++++++++++++++++ tools/perf/trace/beauty/usbdevfs_ioctl.sh | 6 +- 5 files changed, 237 insertions(+), 237 deletions(-) delete mode 100644 tools/include/uapi/linux/usbdevice_fs.h create mode 100644 tools/perf/trace/beauty/include/uapi/linux/usbdevice_fs.h diff --git a/tools/include/uapi/linux/usbdevice_fs.h b/tools/include/uapi/linux/usbdevice_fs.h deleted file mode 100644 index 74a84e02422a..000000000000 --- a/tools/include/uapi/linux/usbdevice_fs.h +++ /dev/null @@ -1,231 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ -/*****************************************************************************/ - -/* - * usbdevice_fs.h -- USB device file system. - * - * Copyright (C) 2000 - * Thomas Sailer (sailer@ife.ee.ethz.ch) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * History: - * 0.1 04.01.2000 Created - */ - -/*****************************************************************************/ - -#ifndef _UAPI_LINUX_USBDEVICE_FS_H -#define _UAPI_LINUX_USBDEVICE_FS_H - -#include -#include - -/* --------------------------------------------------------------------- */ - -/* usbdevfs ioctl codes */ - -struct usbdevfs_ctrltransfer { - __u8 bRequestType; - __u8 bRequest; - __u16 wValue; - __u16 wIndex; - __u16 wLength; - __u32 timeout; /* in milliseconds */ - void __user *data; -}; - -struct usbdevfs_bulktransfer { - unsigned int ep; - unsigned int len; - unsigned int timeout; /* in milliseconds */ - void __user *data; -}; - -struct usbdevfs_setinterface { - unsigned int interface; - unsigned int altsetting; -}; - -struct usbdevfs_disconnectsignal { - unsigned int signr; - void __user *context; -}; - -#define USBDEVFS_MAXDRIVERNAME 255 - -struct usbdevfs_getdriver { - unsigned int interface; - char driver[USBDEVFS_MAXDRIVERNAME + 1]; -}; - -struct usbdevfs_connectinfo { - unsigned int devnum; - unsigned char slow; -}; - -struct usbdevfs_conninfo_ex { - __u32 size; /* Size of the structure from the kernel's */ - /* point of view. Can be used by userspace */ - /* to determine how much data can be */ - /* used/trusted. */ - __u32 busnum; /* USB bus number, as enumerated by the */ - /* kernel, the device is connected to. */ - __u32 devnum; /* Device address on the bus. */ - __u32 speed; /* USB_SPEED_* constants from ch9.h */ - __u8 num_ports; /* Number of ports the device is connected */ - /* to on the way to the root hub. It may */ - /* be bigger than size of 'ports' array so */ - /* userspace can detect overflows. */ - __u8 ports[7]; /* List of ports on the way from the root */ - /* hub to the device. Current limit in */ - /* USB specification is 7 tiers (root hub, */ - /* 5 intermediate hubs, device), which */ - /* gives at most 6 port entries. */ -}; - -#define USBDEVFS_URB_SHORT_NOT_OK 0x01 -#define USBDEVFS_URB_ISO_ASAP 0x02 -#define USBDEVFS_URB_BULK_CONTINUATION 0x04 -#define USBDEVFS_URB_NO_FSBR 0x20 /* Not used */ -#define USBDEVFS_URB_ZERO_PACKET 0x40 -#define USBDEVFS_URB_NO_INTERRUPT 0x80 - -#define USBDEVFS_URB_TYPE_ISO 0 -#define USBDEVFS_URB_TYPE_INTERRUPT 1 -#define USBDEVFS_URB_TYPE_CONTROL 2 -#define USBDEVFS_URB_TYPE_BULK 3 - -struct usbdevfs_iso_packet_desc { - unsigned int length; - unsigned int actual_length; - unsigned int status; -}; - -struct usbdevfs_urb { - unsigned char type; - unsigned char endpoint; - int status; - unsigned int flags; - void __user *buffer; - int buffer_length; - int actual_length; - int start_frame; - union { - int number_of_packets; /* Only used for isoc urbs */ - unsigned int stream_id; /* Only used with bulk streams */ - }; - int error_count; - unsigned int signr; /* signal to be sent on completion, - or 0 if none should be sent. */ - void __user *usercontext; - struct usbdevfs_iso_packet_desc iso_frame_desc[]; -}; - -/* ioctls for talking directly to drivers */ -struct usbdevfs_ioctl { - int ifno; /* interface 0..N ; negative numbers reserved */ - int ioctl_code; /* MUST encode size + direction of data so the - * macros in give correct values */ - void __user *data; /* param buffer (in, or out) */ -}; - -/* You can do most things with hubs just through control messages, - * except find out what device connects to what port. */ -struct usbdevfs_hub_portinfo { - char nports; /* number of downstream ports in this hub */ - char port [127]; /* e.g. port 3 connects to device 27 */ -}; - -/* System and bus capability flags */ -#define USBDEVFS_CAP_ZERO_PACKET 0x01 -#define USBDEVFS_CAP_BULK_CONTINUATION 0x02 -#define USBDEVFS_CAP_NO_PACKET_SIZE_LIM 0x04 -#define USBDEVFS_CAP_BULK_SCATTER_GATHER 0x08 -#define USBDEVFS_CAP_REAP_AFTER_DISCONNECT 0x10 -#define USBDEVFS_CAP_MMAP 0x20 -#define USBDEVFS_CAP_DROP_PRIVILEGES 0x40 -#define USBDEVFS_CAP_CONNINFO_EX 0x80 -#define USBDEVFS_CAP_SUSPEND 0x100 - -/* USBDEVFS_DISCONNECT_CLAIM flags & struct */ - -/* disconnect-and-claim if the driver matches the driver field */ -#define USBDEVFS_DISCONNECT_CLAIM_IF_DRIVER 0x01 -/* disconnect-and-claim except when the driver matches the driver field */ -#define USBDEVFS_DISCONNECT_CLAIM_EXCEPT_DRIVER 0x02 - -struct usbdevfs_disconnect_claim { - unsigned int interface; - unsigned int flags; - char driver[USBDEVFS_MAXDRIVERNAME + 1]; -}; - -struct usbdevfs_streams { - unsigned int num_streams; /* Not used by USBDEVFS_FREE_STREAMS */ - unsigned int num_eps; - unsigned char eps[]; -}; - -/* - * USB_SPEED_* values returned by USBDEVFS_GET_SPEED are defined in - * linux/usb/ch9.h - */ - -#define USBDEVFS_CONTROL _IOWR('U', 0, struct usbdevfs_ctrltransfer) -#define USBDEVFS_CONTROL32 _IOWR('U', 0, struct usbdevfs_ctrltransfer32) -#define USBDEVFS_BULK _IOWR('U', 2, struct usbdevfs_bulktransfer) -#define USBDEVFS_BULK32 _IOWR('U', 2, struct usbdevfs_bulktransfer32) -#define USBDEVFS_RESETEP _IOR('U', 3, unsigned int) -#define USBDEVFS_SETINTERFACE _IOR('U', 4, struct usbdevfs_setinterface) -#define USBDEVFS_SETCONFIGURATION _IOR('U', 5, unsigned int) -#define USBDEVFS_GETDRIVER _IOW('U', 8, struct usbdevfs_getdriver) -#define USBDEVFS_SUBMITURB _IOR('U', 10, struct usbdevfs_urb) -#define USBDEVFS_SUBMITURB32 _IOR('U', 10, struct usbdevfs_urb32) -#define USBDEVFS_DISCARDURB _IO('U', 11) -#define USBDEVFS_REAPURB _IOW('U', 12, void *) -#define USBDEVFS_REAPURB32 _IOW('U', 12, __u32) -#define USBDEVFS_REAPURBNDELAY _IOW('U', 13, void *) -#define USBDEVFS_REAPURBNDELAY32 _IOW('U', 13, __u32) -#define USBDEVFS_DISCSIGNAL _IOR('U', 14, struct usbdevfs_disconnectsignal) -#define USBDEVFS_DISCSIGNAL32 _IOR('U', 14, struct usbdevfs_disconnectsignal32) -#define USBDEVFS_CLAIMINTERFACE _IOR('U', 15, unsigned int) -#define USBDEVFS_RELEASEINTERFACE _IOR('U', 16, unsigned int) -#define USBDEVFS_CONNECTINFO _IOW('U', 17, struct usbdevfs_connectinfo) -#define USBDEVFS_IOCTL _IOWR('U', 18, struct usbdevfs_ioctl) -#define USBDEVFS_IOCTL32 _IOWR('U', 18, struct usbdevfs_ioctl32) -#define USBDEVFS_HUB_PORTINFO _IOR('U', 19, struct usbdevfs_hub_portinfo) -#define USBDEVFS_RESET _IO('U', 20) -#define USBDEVFS_CLEAR_HALT _IOR('U', 21, unsigned int) -#define USBDEVFS_DISCONNECT _IO('U', 22) -#define USBDEVFS_CONNECT _IO('U', 23) -#define USBDEVFS_CLAIM_PORT _IOR('U', 24, unsigned int) -#define USBDEVFS_RELEASE_PORT _IOR('U', 25, unsigned int) -#define USBDEVFS_GET_CAPABILITIES _IOR('U', 26, __u32) -#define USBDEVFS_DISCONNECT_CLAIM _IOR('U', 27, struct usbdevfs_disconnect_claim) -#define USBDEVFS_ALLOC_STREAMS _IOR('U', 28, struct usbdevfs_streams) -#define USBDEVFS_FREE_STREAMS _IOR('U', 29, struct usbdevfs_streams) -#define USBDEVFS_DROP_PRIVILEGES _IOW('U', 30, __u32) -#define USBDEVFS_GET_SPEED _IO('U', 31) -/* - * Returns struct usbdevfs_conninfo_ex; length is variable to allow - * extending size of the data returned. - */ -#define USBDEVFS_CONNINFO_EX(len) _IOC(_IOC_READ, 'U', 32, len) -#define USBDEVFS_FORBID_SUSPEND _IO('U', 33) -#define USBDEVFS_ALLOW_SUSPEND _IO('U', 34) -#define USBDEVFS_WAIT_FOR_RESUME _IO('U', 35) - -#endif /* _UAPI_LINUX_USBDEVICE_FS_H */ diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index 523c3b7d6c9d..53ec3765b4b2 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -623,8 +623,8 @@ $(prctl_option_array): $(prctl_hdr_dir)/prctl.h $(prctl_option_tbl) usbdevfs_ioctl_array := $(beauty_ioctl_outdir)/usbdevfs_ioctl_array.c usbdevfs_ioctl_tbl := $(srctree)/tools/perf/trace/beauty/usbdevfs_ioctl.sh -$(usbdevfs_ioctl_array): $(linux_uapi_dir)/usbdevice_fs.h $(usbdevfs_ioctl_tbl) - $(Q)$(SHELL) '$(usbdevfs_ioctl_tbl)' $(linux_uapi_dir) > $@ +$(usbdevfs_ioctl_array): $(beauty_uapi_linux_dir)/usbdevice_fs.h $(usbdevfs_ioctl_tbl) + $(Q)$(SHELL) '$(usbdevfs_ioctl_tbl)' $(beauty_uapi_linux_dir) > $@ x86_arch_prctl_code_array := $(beauty_outdir)/x86_arch_prctl_code_array.c x86_arch_prctl_code_tbl := $(srctree)/tools/perf/trace/beauty/x86_arch_prctl.sh diff --git a/tools/perf/check-headers.sh b/tools/perf/check-headers.sh index c2c26d6b87ef..356ddb76a954 100755 --- a/tools/perf/check-headers.sh +++ b/tools/perf/check-headers.sh @@ -21,7 +21,6 @@ FILES=( "include/uapi/linux/sched.h" "include/uapi/linux/seccomp.h" "include/uapi/linux/stat.h" - "include/uapi/linux/usbdevice_fs.h" "include/uapi/linux/vhost.h" "include/uapi/sound/asound.h" "include/linux/bits.h" @@ -98,6 +97,7 @@ BEAUTY_FILES=( "include/linux/socket.h" "include/uapi/linux/fs.h" "include/uapi/linux/mount.h" + "include/uapi/linux/usbdevice_fs.h" ) declare -a FAILURES diff --git a/tools/perf/trace/beauty/include/uapi/linux/usbdevice_fs.h b/tools/perf/trace/beauty/include/uapi/linux/usbdevice_fs.h new file mode 100644 index 000000000000..74a84e02422a --- /dev/null +++ b/tools/perf/trace/beauty/include/uapi/linux/usbdevice_fs.h @@ -0,0 +1,231 @@ +/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ +/*****************************************************************************/ + +/* + * usbdevice_fs.h -- USB device file system. + * + * Copyright (C) 2000 + * Thomas Sailer (sailer@ife.ee.ethz.ch) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * History: + * 0.1 04.01.2000 Created + */ + +/*****************************************************************************/ + +#ifndef _UAPI_LINUX_USBDEVICE_FS_H +#define _UAPI_LINUX_USBDEVICE_FS_H + +#include +#include + +/* --------------------------------------------------------------------- */ + +/* usbdevfs ioctl codes */ + +struct usbdevfs_ctrltransfer { + __u8 bRequestType; + __u8 bRequest; + __u16 wValue; + __u16 wIndex; + __u16 wLength; + __u32 timeout; /* in milliseconds */ + void __user *data; +}; + +struct usbdevfs_bulktransfer { + unsigned int ep; + unsigned int len; + unsigned int timeout; /* in milliseconds */ + void __user *data; +}; + +struct usbdevfs_setinterface { + unsigned int interface; + unsigned int altsetting; +}; + +struct usbdevfs_disconnectsignal { + unsigned int signr; + void __user *context; +}; + +#define USBDEVFS_MAXDRIVERNAME 255 + +struct usbdevfs_getdriver { + unsigned int interface; + char driver[USBDEVFS_MAXDRIVERNAME + 1]; +}; + +struct usbdevfs_connectinfo { + unsigned int devnum; + unsigned char slow; +}; + +struct usbdevfs_conninfo_ex { + __u32 size; /* Size of the structure from the kernel's */ + /* point of view. Can be used by userspace */ + /* to determine how much data can be */ + /* used/trusted. */ + __u32 busnum; /* USB bus number, as enumerated by the */ + /* kernel, the device is connected to. */ + __u32 devnum; /* Device address on the bus. */ + __u32 speed; /* USB_SPEED_* constants from ch9.h */ + __u8 num_ports; /* Number of ports the device is connected */ + /* to on the way to the root hub. It may */ + /* be bigger than size of 'ports' array so */ + /* userspace can detect overflows. */ + __u8 ports[7]; /* List of ports on the way from the root */ + /* hub to the device. Current limit in */ + /* USB specification is 7 tiers (root hub, */ + /* 5 intermediate hubs, device), which */ + /* gives at most 6 port entries. */ +}; + +#define USBDEVFS_URB_SHORT_NOT_OK 0x01 +#define USBDEVFS_URB_ISO_ASAP 0x02 +#define USBDEVFS_URB_BULK_CONTINUATION 0x04 +#define USBDEVFS_URB_NO_FSBR 0x20 /* Not used */ +#define USBDEVFS_URB_ZERO_PACKET 0x40 +#define USBDEVFS_URB_NO_INTERRUPT 0x80 + +#define USBDEVFS_URB_TYPE_ISO 0 +#define USBDEVFS_URB_TYPE_INTERRUPT 1 +#define USBDEVFS_URB_TYPE_CONTROL 2 +#define USBDEVFS_URB_TYPE_BULK 3 + +struct usbdevfs_iso_packet_desc { + unsigned int length; + unsigned int actual_length; + unsigned int status; +}; + +struct usbdevfs_urb { + unsigned char type; + unsigned char endpoint; + int status; + unsigned int flags; + void __user *buffer; + int buffer_length; + int actual_length; + int start_frame; + union { + int number_of_packets; /* Only used for isoc urbs */ + unsigned int stream_id; /* Only used with bulk streams */ + }; + int error_count; + unsigned int signr; /* signal to be sent on completion, + or 0 if none should be sent. */ + void __user *usercontext; + struct usbdevfs_iso_packet_desc iso_frame_desc[]; +}; + +/* ioctls for talking directly to drivers */ +struct usbdevfs_ioctl { + int ifno; /* interface 0..N ; negative numbers reserved */ + int ioctl_code; /* MUST encode size + direction of data so the + * macros in give correct values */ + void __user *data; /* param buffer (in, or out) */ +}; + +/* You can do most things with hubs just through control messages, + * except find out what device connects to what port. */ +struct usbdevfs_hub_portinfo { + char nports; /* number of downstream ports in this hub */ + char port [127]; /* e.g. port 3 connects to device 27 */ +}; + +/* System and bus capability flags */ +#define USBDEVFS_CAP_ZERO_PACKET 0x01 +#define USBDEVFS_CAP_BULK_CONTINUATION 0x02 +#define USBDEVFS_CAP_NO_PACKET_SIZE_LIM 0x04 +#define USBDEVFS_CAP_BULK_SCATTER_GATHER 0x08 +#define USBDEVFS_CAP_REAP_AFTER_DISCONNECT 0x10 +#define USBDEVFS_CAP_MMAP 0x20 +#define USBDEVFS_CAP_DROP_PRIVILEGES 0x40 +#define USBDEVFS_CAP_CONNINFO_EX 0x80 +#define USBDEVFS_CAP_SUSPEND 0x100 + +/* USBDEVFS_DISCONNECT_CLAIM flags & struct */ + +/* disconnect-and-claim if the driver matches the driver field */ +#define USBDEVFS_DISCONNECT_CLAIM_IF_DRIVER 0x01 +/* disconnect-and-claim except when the driver matches the driver field */ +#define USBDEVFS_DISCONNECT_CLAIM_EXCEPT_DRIVER 0x02 + +struct usbdevfs_disconnect_claim { + unsigned int interface; + unsigned int flags; + char driver[USBDEVFS_MAXDRIVERNAME + 1]; +}; + +struct usbdevfs_streams { + unsigned int num_streams; /* Not used by USBDEVFS_FREE_STREAMS */ + unsigned int num_eps; + unsigned char eps[]; +}; + +/* + * USB_SPEED_* values returned by USBDEVFS_GET_SPEED are defined in + * linux/usb/ch9.h + */ + +#define USBDEVFS_CONTROL _IOWR('U', 0, struct usbdevfs_ctrltransfer) +#define USBDEVFS_CONTROL32 _IOWR('U', 0, struct usbdevfs_ctrltransfer32) +#define USBDEVFS_BULK _IOWR('U', 2, struct usbdevfs_bulktransfer) +#define USBDEVFS_BULK32 _IOWR('U', 2, struct usbdevfs_bulktransfer32) +#define USBDEVFS_RESETEP _IOR('U', 3, unsigned int) +#define USBDEVFS_SETINTERFACE _IOR('U', 4, struct usbdevfs_setinterface) +#define USBDEVFS_SETCONFIGURATION _IOR('U', 5, unsigned int) +#define USBDEVFS_GETDRIVER _IOW('U', 8, struct usbdevfs_getdriver) +#define USBDEVFS_SUBMITURB _IOR('U', 10, struct usbdevfs_urb) +#define USBDEVFS_SUBMITURB32 _IOR('U', 10, struct usbdevfs_urb32) +#define USBDEVFS_DISCARDURB _IO('U', 11) +#define USBDEVFS_REAPURB _IOW('U', 12, void *) +#define USBDEVFS_REAPURB32 _IOW('U', 12, __u32) +#define USBDEVFS_REAPURBNDELAY _IOW('U', 13, void *) +#define USBDEVFS_REAPURBNDELAY32 _IOW('U', 13, __u32) +#define USBDEVFS_DISCSIGNAL _IOR('U', 14, struct usbdevfs_disconnectsignal) +#define USBDEVFS_DISCSIGNAL32 _IOR('U', 14, struct usbdevfs_disconnectsignal32) +#define USBDEVFS_CLAIMINTERFACE _IOR('U', 15, unsigned int) +#define USBDEVFS_RELEASEINTERFACE _IOR('U', 16, unsigned int) +#define USBDEVFS_CONNECTINFO _IOW('U', 17, struct usbdevfs_connectinfo) +#define USBDEVFS_IOCTL _IOWR('U', 18, struct usbdevfs_ioctl) +#define USBDEVFS_IOCTL32 _IOWR('U', 18, struct usbdevfs_ioctl32) +#define USBDEVFS_HUB_PORTINFO _IOR('U', 19, struct usbdevfs_hub_portinfo) +#define USBDEVFS_RESET _IO('U', 20) +#define USBDEVFS_CLEAR_HALT _IOR('U', 21, unsigned int) +#define USBDEVFS_DISCONNECT _IO('U', 22) +#define USBDEVFS_CONNECT _IO('U', 23) +#define USBDEVFS_CLAIM_PORT _IOR('U', 24, unsigned int) +#define USBDEVFS_RELEASE_PORT _IOR('U', 25, unsigned int) +#define USBDEVFS_GET_CAPABILITIES _IOR('U', 26, __u32) +#define USBDEVFS_DISCONNECT_CLAIM _IOR('U', 27, struct usbdevfs_disconnect_claim) +#define USBDEVFS_ALLOC_STREAMS _IOR('U', 28, struct usbdevfs_streams) +#define USBDEVFS_FREE_STREAMS _IOR('U', 29, struct usbdevfs_streams) +#define USBDEVFS_DROP_PRIVILEGES _IOW('U', 30, __u32) +#define USBDEVFS_GET_SPEED _IO('U', 31) +/* + * Returns struct usbdevfs_conninfo_ex; length is variable to allow + * extending size of the data returned. + */ +#define USBDEVFS_CONNINFO_EX(len) _IOC(_IOC_READ, 'U', 32, len) +#define USBDEVFS_FORBID_SUSPEND _IO('U', 33) +#define USBDEVFS_ALLOW_SUSPEND _IO('U', 34) +#define USBDEVFS_WAIT_FOR_RESUME _IO('U', 35) + +#endif /* _UAPI_LINUX_USBDEVICE_FS_H */ diff --git a/tools/perf/trace/beauty/usbdevfs_ioctl.sh b/tools/perf/trace/beauty/usbdevfs_ioctl.sh index b39cfb3720b8..12a30a9a8e0c 100755 --- a/tools/perf/trace/beauty/usbdevfs_ioctl.sh +++ b/tools/perf/trace/beauty/usbdevfs_ioctl.sh @@ -1,21 +1,21 @@ #!/bin/sh # SPDX-License-Identifier: LGPL-2.1 -[ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/linux/ +[ $# -eq 1 ] && beauty_uapi_linux_dir=$1 || beauty_uapi_linux_dir=tools/perf/trace/beauty/include/uapi/linux/ # also as: # #define USBDEVFS_CONNINFO_EX(len) _IOC(_IOC_READ, 'U', 32, len) printf "static const char *usbdevfs_ioctl_cmds[] = {\n" regex="^#[[:space:]]*define[[:space:]]+USBDEVFS_(\w+)(\(\w+\))?[[:space:]]+_IO[CWR]{0,2}\([[:space:]]*(_IOC_\w+,[[:space:]]*)?'U'[[:space:]]*,[[:space:]]*([[:digit:]]+).*" -grep -E "$regex" ${header_dir}/usbdevice_fs.h | grep -E -v 'USBDEVFS_\w+32[[:space:]]' | \ +grep -E "$regex" ${beauty_uapi_linux_dir}/usbdevice_fs.h | grep -E -v 'USBDEVFS_\w+32[[:space:]]' | \ sed -r "s/$regex/\4 \1/g" | \ sort | xargs printf "\t[%s] = \"%s\",\n" printf "};\n\n" printf "#if 0\n" printf "static const char *usbdevfs_ioctl_32_cmds[] = {\n" regex="^#[[:space:]]*define[[:space:]]+USBDEVFS_(\w+)[[:space:]]+_IO[WR]{0,2}\([[:space:]]*'U'[[:space:]]*,[[:space:]]*([[:digit:]]+).*" -grep -E $regex ${header_dir}/usbdevice_fs.h | grep -E 'USBDEVFS_\w+32[[:space:]]' | \ +grep -E $regex ${beauty_uapi_linux_dir}/usbdevice_fs.h | grep -E 'USBDEVFS_\w+32[[:space:]]' | \ sed -r "s/$regex/\2 \1/g" | \ sort | xargs printf "\t[%s] = \"%s\",\n" printf "};\n" -- cgit v1.2.3-59-g8ed1b From 7050e33e86ad03d26d7b969bba1d48ee159be496 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 11 Mar 2024 17:07:33 -0300 Subject: perf beauty: Move uapi/sound/asound.h copy out of the directory used to build perf It is used only to generate string tables, not to build perf, so move it to the tools/perf/trace/beauty/include/ hierarchy, that is used just for scraping. This is a something that should've have happened, as happened with the linux/socket.h scrapper, do it now as Ian suggested while doing an audit/refactor session in the headers used by perf. Suggested-by: Ian Rogers Reviewed-by: Ian Rogers Cc: Adrian Hunter Cc: Jiri Olsa Cc: Namhyung Kim Link: https://lore.kernel.org/lkml/CAP-5=fWZVrpRufO4w-S4EcSi9STXcTAN2ERLwTSN7yrSSA-otQ@mail.gmail.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/include/uapi/sound/asound.h | 1252 -------------------- tools/perf/Makefile.perf | 9 +- tools/perf/check-headers.sh | 2 +- .../perf/trace/beauty/include/uapi/sound/asound.h | 1252 ++++++++++++++++++++ tools/perf/trace/beauty/sndrv_ctl_ioctl.sh | 4 +- tools/perf/trace/beauty/sndrv_pcm_ioctl.sh | 4 +- 6 files changed, 1262 insertions(+), 1261 deletions(-) delete mode 100644 tools/include/uapi/sound/asound.h create mode 100644 tools/perf/trace/beauty/include/uapi/sound/asound.h diff --git a/tools/include/uapi/sound/asound.h b/tools/include/uapi/sound/asound.h deleted file mode 100644 index d5b9cfbd9cea..000000000000 --- a/tools/include/uapi/sound/asound.h +++ /dev/null @@ -1,1252 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ -/* - * Advanced Linux Sound Architecture - ALSA - Driver - * Copyright (c) 1994-2003 by Jaroslav Kysela , - * Abramo Bagnara - */ - -#ifndef _UAPI__SOUND_ASOUND_H -#define _UAPI__SOUND_ASOUND_H - -#if defined(__KERNEL__) || defined(__linux__) -#include -#include -#else -#include -#include -#endif - -#ifndef __KERNEL__ -#include -#include -#endif - -/* - * protocol version - */ - -#define SNDRV_PROTOCOL_VERSION(major, minor, subminor) (((major)<<16)|((minor)<<8)|(subminor)) -#define SNDRV_PROTOCOL_MAJOR(version) (((version)>>16)&0xffff) -#define SNDRV_PROTOCOL_MINOR(version) (((version)>>8)&0xff) -#define SNDRV_PROTOCOL_MICRO(version) ((version)&0xff) -#define SNDRV_PROTOCOL_INCOMPATIBLE(kversion, uversion) \ - (SNDRV_PROTOCOL_MAJOR(kversion) != SNDRV_PROTOCOL_MAJOR(uversion) || \ - (SNDRV_PROTOCOL_MAJOR(kversion) == SNDRV_PROTOCOL_MAJOR(uversion) && \ - SNDRV_PROTOCOL_MINOR(kversion) != SNDRV_PROTOCOL_MINOR(uversion))) - -/**************************************************************************** - * * - * Digital audio interface * - * * - ****************************************************************************/ - -#define AES_IEC958_STATUS_SIZE 24 - -struct snd_aes_iec958 { - unsigned char status[AES_IEC958_STATUS_SIZE]; /* AES/IEC958 channel status bits */ - unsigned char subcode[147]; /* AES/IEC958 subcode bits */ - unsigned char pad; /* nothing */ - unsigned char dig_subframe[4]; /* AES/IEC958 subframe bits */ -}; - -/**************************************************************************** - * * - * CEA-861 Audio InfoFrame. Used in HDMI and DisplayPort * - * * - ****************************************************************************/ - -struct snd_cea_861_aud_if { - unsigned char db1_ct_cc; /* coding type and channel count */ - unsigned char db2_sf_ss; /* sample frequency and size */ - unsigned char db3; /* not used, all zeros */ - unsigned char db4_ca; /* channel allocation code */ - unsigned char db5_dminh_lsv; /* downmix inhibit & level-shit values */ -}; - -/**************************************************************************** - * * - * Section for driver hardware dependent interface - /dev/snd/hw? * - * * - ****************************************************************************/ - -#define SNDRV_HWDEP_VERSION SNDRV_PROTOCOL_VERSION(1, 0, 1) - -enum { - SNDRV_HWDEP_IFACE_OPL2 = 0, - SNDRV_HWDEP_IFACE_OPL3, - SNDRV_HWDEP_IFACE_OPL4, - SNDRV_HWDEP_IFACE_SB16CSP, /* Creative Signal Processor */ - SNDRV_HWDEP_IFACE_EMU10K1, /* FX8010 processor in EMU10K1 chip */ - SNDRV_HWDEP_IFACE_YSS225, /* Yamaha FX processor */ - SNDRV_HWDEP_IFACE_ICS2115, /* Wavetable synth */ - SNDRV_HWDEP_IFACE_SSCAPE, /* Ensoniq SoundScape ISA card (MC68EC000) */ - SNDRV_HWDEP_IFACE_VX, /* Digigram VX cards */ - SNDRV_HWDEP_IFACE_MIXART, /* Digigram miXart cards */ - SNDRV_HWDEP_IFACE_USX2Y, /* Tascam US122, US224 & US428 usb */ - SNDRV_HWDEP_IFACE_EMUX_WAVETABLE, /* EmuX wavetable */ - SNDRV_HWDEP_IFACE_BLUETOOTH, /* Bluetooth audio */ - SNDRV_HWDEP_IFACE_USX2Y_PCM, /* Tascam US122, US224 & US428 rawusb pcm */ - SNDRV_HWDEP_IFACE_PCXHR, /* Digigram PCXHR */ - SNDRV_HWDEP_IFACE_SB_RC, /* SB Extigy/Audigy2NX remote control */ - SNDRV_HWDEP_IFACE_HDA, /* HD-audio */ - SNDRV_HWDEP_IFACE_USB_STREAM, /* direct access to usb stream */ - SNDRV_HWDEP_IFACE_FW_DICE, /* TC DICE FireWire device */ - SNDRV_HWDEP_IFACE_FW_FIREWORKS, /* Echo Audio Fireworks based device */ - SNDRV_HWDEP_IFACE_FW_BEBOB, /* BridgeCo BeBoB based device */ - SNDRV_HWDEP_IFACE_FW_OXFW, /* Oxford OXFW970/971 based device */ - SNDRV_HWDEP_IFACE_FW_DIGI00X, /* Digidesign Digi 002/003 family */ - SNDRV_HWDEP_IFACE_FW_TASCAM, /* TASCAM FireWire series */ - SNDRV_HWDEP_IFACE_LINE6, /* Line6 USB processors */ - SNDRV_HWDEP_IFACE_FW_MOTU, /* MOTU FireWire series */ - SNDRV_HWDEP_IFACE_FW_FIREFACE, /* RME Fireface series */ - - /* Don't forget to change the following: */ - SNDRV_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_FW_FIREFACE -}; - -struct snd_hwdep_info { - unsigned int device; /* WR: device number */ - int card; /* R: card number */ - unsigned char id[64]; /* ID (user selectable) */ - unsigned char name[80]; /* hwdep name */ - int iface; /* hwdep interface */ - unsigned char reserved[64]; /* reserved for future */ -}; - -/* generic DSP loader */ -struct snd_hwdep_dsp_status { - unsigned int version; /* R: driver-specific version */ - unsigned char id[32]; /* R: driver-specific ID string */ - unsigned int num_dsps; /* R: number of DSP images to transfer */ - unsigned int dsp_loaded; /* R: bit flags indicating the loaded DSPs */ - unsigned int chip_ready; /* R: 1 = initialization finished */ - unsigned char reserved[16]; /* reserved for future use */ -}; - -struct snd_hwdep_dsp_image { - unsigned int index; /* W: DSP index */ - unsigned char name[64]; /* W: ID (e.g. file name) */ - unsigned char __user *image; /* W: binary image */ - size_t length; /* W: size of image in bytes */ - unsigned long driver_data; /* W: driver-specific data */ -}; - -#define SNDRV_HWDEP_IOCTL_PVERSION _IOR ('H', 0x00, int) -#define SNDRV_HWDEP_IOCTL_INFO _IOR ('H', 0x01, struct snd_hwdep_info) -#define SNDRV_HWDEP_IOCTL_DSP_STATUS _IOR('H', 0x02, struct snd_hwdep_dsp_status) -#define SNDRV_HWDEP_IOCTL_DSP_LOAD _IOW('H', 0x03, struct snd_hwdep_dsp_image) - -/***************************************************************************** - * * - * Digital Audio (PCM) interface - /dev/snd/pcm?? * - * * - *****************************************************************************/ - -#define SNDRV_PCM_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 16) - -typedef unsigned long snd_pcm_uframes_t; -typedef signed long snd_pcm_sframes_t; - -enum { - SNDRV_PCM_CLASS_GENERIC = 0, /* standard mono or stereo device */ - SNDRV_PCM_CLASS_MULTI, /* multichannel device */ - SNDRV_PCM_CLASS_MODEM, /* software modem class */ - SNDRV_PCM_CLASS_DIGITIZER, /* digitizer class */ - /* Don't forget to change the following: */ - SNDRV_PCM_CLASS_LAST = SNDRV_PCM_CLASS_DIGITIZER, -}; - -enum { - SNDRV_PCM_SUBCLASS_GENERIC_MIX = 0, /* mono or stereo subdevices are mixed together */ - SNDRV_PCM_SUBCLASS_MULTI_MIX, /* multichannel subdevices are mixed together */ - /* Don't forget to change the following: */ - SNDRV_PCM_SUBCLASS_LAST = SNDRV_PCM_SUBCLASS_MULTI_MIX, -}; - -enum { - SNDRV_PCM_STREAM_PLAYBACK = 0, - SNDRV_PCM_STREAM_CAPTURE, - SNDRV_PCM_STREAM_LAST = SNDRV_PCM_STREAM_CAPTURE, -}; - -typedef int __bitwise snd_pcm_access_t; -#define SNDRV_PCM_ACCESS_MMAP_INTERLEAVED ((__force snd_pcm_access_t) 0) /* interleaved mmap */ -#define SNDRV_PCM_ACCESS_MMAP_NONINTERLEAVED ((__force snd_pcm_access_t) 1) /* noninterleaved mmap */ -#define SNDRV_PCM_ACCESS_MMAP_COMPLEX ((__force snd_pcm_access_t) 2) /* complex mmap */ -#define SNDRV_PCM_ACCESS_RW_INTERLEAVED ((__force snd_pcm_access_t) 3) /* readi/writei */ -#define SNDRV_PCM_ACCESS_RW_NONINTERLEAVED ((__force snd_pcm_access_t) 4) /* readn/writen */ -#define SNDRV_PCM_ACCESS_LAST SNDRV_PCM_ACCESS_RW_NONINTERLEAVED - -typedef int __bitwise snd_pcm_format_t; -#define SNDRV_PCM_FORMAT_S8 ((__force snd_pcm_format_t) 0) -#define SNDRV_PCM_FORMAT_U8 ((__force snd_pcm_format_t) 1) -#define SNDRV_PCM_FORMAT_S16_LE ((__force snd_pcm_format_t) 2) -#define SNDRV_PCM_FORMAT_S16_BE ((__force snd_pcm_format_t) 3) -#define SNDRV_PCM_FORMAT_U16_LE ((__force snd_pcm_format_t) 4) -#define SNDRV_PCM_FORMAT_U16_BE ((__force snd_pcm_format_t) 5) -#define SNDRV_PCM_FORMAT_S24_LE ((__force snd_pcm_format_t) 6) /* low three bytes */ -#define SNDRV_PCM_FORMAT_S24_BE ((__force snd_pcm_format_t) 7) /* low three bytes */ -#define SNDRV_PCM_FORMAT_U24_LE ((__force snd_pcm_format_t) 8) /* low three bytes */ -#define SNDRV_PCM_FORMAT_U24_BE ((__force snd_pcm_format_t) 9) /* low three bytes */ -/* - * For S32/U32 formats, 'msbits' hardware parameter is often used to deliver information about the - * available bit count in most significant bit. It's for the case of so-called 'left-justified' or - * `right-padding` sample which has less width than 32 bit. - */ -#define SNDRV_PCM_FORMAT_S32_LE ((__force snd_pcm_format_t) 10) -#define SNDRV_PCM_FORMAT_S32_BE ((__force snd_pcm_format_t) 11) -#define SNDRV_PCM_FORMAT_U32_LE ((__force snd_pcm_format_t) 12) -#define SNDRV_PCM_FORMAT_U32_BE ((__force snd_pcm_format_t) 13) -#define SNDRV_PCM_FORMAT_FLOAT_LE ((__force snd_pcm_format_t) 14) /* 4-byte float, IEEE-754 32-bit, range -1.0 to 1.0 */ -#define SNDRV_PCM_FORMAT_FLOAT_BE ((__force snd_pcm_format_t) 15) /* 4-byte float, IEEE-754 32-bit, range -1.0 to 1.0 */ -#define SNDRV_PCM_FORMAT_FLOAT64_LE ((__force snd_pcm_format_t) 16) /* 8-byte float, IEEE-754 64-bit, range -1.0 to 1.0 */ -#define SNDRV_PCM_FORMAT_FLOAT64_BE ((__force snd_pcm_format_t) 17) /* 8-byte float, IEEE-754 64-bit, range -1.0 to 1.0 */ -#define SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE ((__force snd_pcm_format_t) 18) /* IEC-958 subframe, Little Endian */ -#define SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE ((__force snd_pcm_format_t) 19) /* IEC-958 subframe, Big Endian */ -#define SNDRV_PCM_FORMAT_MU_LAW ((__force snd_pcm_format_t) 20) -#define SNDRV_PCM_FORMAT_A_LAW ((__force snd_pcm_format_t) 21) -#define SNDRV_PCM_FORMAT_IMA_ADPCM ((__force snd_pcm_format_t) 22) -#define SNDRV_PCM_FORMAT_MPEG ((__force snd_pcm_format_t) 23) -#define SNDRV_PCM_FORMAT_GSM ((__force snd_pcm_format_t) 24) -#define SNDRV_PCM_FORMAT_S20_LE ((__force snd_pcm_format_t) 25) /* in four bytes, LSB justified */ -#define SNDRV_PCM_FORMAT_S20_BE ((__force snd_pcm_format_t) 26) /* in four bytes, LSB justified */ -#define SNDRV_PCM_FORMAT_U20_LE ((__force snd_pcm_format_t) 27) /* in four bytes, LSB justified */ -#define SNDRV_PCM_FORMAT_U20_BE ((__force snd_pcm_format_t) 28) /* in four bytes, LSB justified */ -/* gap in the numbering for a future standard linear format */ -#define SNDRV_PCM_FORMAT_SPECIAL ((__force snd_pcm_format_t) 31) -#define SNDRV_PCM_FORMAT_S24_3LE ((__force snd_pcm_format_t) 32) /* in three bytes */ -#define SNDRV_PCM_FORMAT_S24_3BE ((__force snd_pcm_format_t) 33) /* in three bytes */ -#define SNDRV_PCM_FORMAT_U24_3LE ((__force snd_pcm_format_t) 34) /* in three bytes */ -#define SNDRV_PCM_FORMAT_U24_3BE ((__force snd_pcm_format_t) 35) /* in three bytes */ -#define SNDRV_PCM_FORMAT_S20_3LE ((__force snd_pcm_format_t) 36) /* in three bytes */ -#define SNDRV_PCM_FORMAT_S20_3BE ((__force snd_pcm_format_t) 37) /* in three bytes */ -#define SNDRV_PCM_FORMAT_U20_3LE ((__force snd_pcm_format_t) 38) /* in three bytes */ -#define SNDRV_PCM_FORMAT_U20_3BE ((__force snd_pcm_format_t) 39) /* in three bytes */ -#define SNDRV_PCM_FORMAT_S18_3LE ((__force snd_pcm_format_t) 40) /* in three bytes */ -#define SNDRV_PCM_FORMAT_S18_3BE ((__force snd_pcm_format_t) 41) /* in three bytes */ -#define SNDRV_PCM_FORMAT_U18_3LE ((__force snd_pcm_format_t) 42) /* in three bytes */ -#define SNDRV_PCM_FORMAT_U18_3BE ((__force snd_pcm_format_t) 43) /* in three bytes */ -#define SNDRV_PCM_FORMAT_G723_24 ((__force snd_pcm_format_t) 44) /* 8 samples in 3 bytes */ -#define SNDRV_PCM_FORMAT_G723_24_1B ((__force snd_pcm_format_t) 45) /* 1 sample in 1 byte */ -#define SNDRV_PCM_FORMAT_G723_40 ((__force snd_pcm_format_t) 46) /* 8 Samples in 5 bytes */ -#define SNDRV_PCM_FORMAT_G723_40_1B ((__force snd_pcm_format_t) 47) /* 1 sample in 1 byte */ -#define SNDRV_PCM_FORMAT_DSD_U8 ((__force snd_pcm_format_t) 48) /* DSD, 1-byte samples DSD (x8) */ -#define SNDRV_PCM_FORMAT_DSD_U16_LE ((__force snd_pcm_format_t) 49) /* DSD, 2-byte samples DSD (x16), little endian */ -#define SNDRV_PCM_FORMAT_DSD_U32_LE ((__force snd_pcm_format_t) 50) /* DSD, 4-byte samples DSD (x32), little endian */ -#define SNDRV_PCM_FORMAT_DSD_U16_BE ((__force snd_pcm_format_t) 51) /* DSD, 2-byte samples DSD (x16), big endian */ -#define SNDRV_PCM_FORMAT_DSD_U32_BE ((__force snd_pcm_format_t) 52) /* DSD, 4-byte samples DSD (x32), big endian */ -#define SNDRV_PCM_FORMAT_LAST SNDRV_PCM_FORMAT_DSD_U32_BE -#define SNDRV_PCM_FORMAT_FIRST SNDRV_PCM_FORMAT_S8 - -#ifdef SNDRV_LITTLE_ENDIAN -#define SNDRV_PCM_FORMAT_S16 SNDRV_PCM_FORMAT_S16_LE -#define SNDRV_PCM_FORMAT_U16 SNDRV_PCM_FORMAT_U16_LE -#define SNDRV_PCM_FORMAT_S24 SNDRV_PCM_FORMAT_S24_LE -#define SNDRV_PCM_FORMAT_U24 SNDRV_PCM_FORMAT_U24_LE -#define SNDRV_PCM_FORMAT_S32 SNDRV_PCM_FORMAT_S32_LE -#define SNDRV_PCM_FORMAT_U32 SNDRV_PCM_FORMAT_U32_LE -#define SNDRV_PCM_FORMAT_FLOAT SNDRV_PCM_FORMAT_FLOAT_LE -#define SNDRV_PCM_FORMAT_FLOAT64 SNDRV_PCM_FORMAT_FLOAT64_LE -#define SNDRV_PCM_FORMAT_IEC958_SUBFRAME SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE -#define SNDRV_PCM_FORMAT_S20 SNDRV_PCM_FORMAT_S20_LE -#define SNDRV_PCM_FORMAT_U20 SNDRV_PCM_FORMAT_U20_LE -#endif -#ifdef SNDRV_BIG_ENDIAN -#define SNDRV_PCM_FORMAT_S16 SNDRV_PCM_FORMAT_S16_BE -#define SNDRV_PCM_FORMAT_U16 SNDRV_PCM_FORMAT_U16_BE -#define SNDRV_PCM_FORMAT_S24 SNDRV_PCM_FORMAT_S24_BE -#define SNDRV_PCM_FORMAT_U24 SNDRV_PCM_FORMAT_U24_BE -#define SNDRV_PCM_FORMAT_S32 SNDRV_PCM_FORMAT_S32_BE -#define SNDRV_PCM_FORMAT_U32 SNDRV_PCM_FORMAT_U32_BE -#define SNDRV_PCM_FORMAT_FLOAT SNDRV_PCM_FORMAT_FLOAT_BE -#define SNDRV_PCM_FORMAT_FLOAT64 SNDRV_PCM_FORMAT_FLOAT64_BE -#define SNDRV_PCM_FORMAT_IEC958_SUBFRAME SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE -#define SNDRV_PCM_FORMAT_S20 SNDRV_PCM_FORMAT_S20_BE -#define SNDRV_PCM_FORMAT_U20 SNDRV_PCM_FORMAT_U20_BE -#endif - -typedef int __bitwise snd_pcm_subformat_t; -#define SNDRV_PCM_SUBFORMAT_STD ((__force snd_pcm_subformat_t) 0) -#define SNDRV_PCM_SUBFORMAT_MSBITS_MAX ((__force snd_pcm_subformat_t) 1) -#define SNDRV_PCM_SUBFORMAT_MSBITS_20 ((__force snd_pcm_subformat_t) 2) -#define SNDRV_PCM_SUBFORMAT_MSBITS_24 ((__force snd_pcm_subformat_t) 3) -#define SNDRV_PCM_SUBFORMAT_LAST SNDRV_PCM_SUBFORMAT_MSBITS_24 - -#define SNDRV_PCM_INFO_MMAP 0x00000001 /* hardware supports mmap */ -#define SNDRV_PCM_INFO_MMAP_VALID 0x00000002 /* period data are valid during transfer */ -#define SNDRV_PCM_INFO_DOUBLE 0x00000004 /* Double buffering needed for PCM start/stop */ -#define SNDRV_PCM_INFO_BATCH 0x00000010 /* double buffering */ -#define SNDRV_PCM_INFO_SYNC_APPLPTR 0x00000020 /* need the explicit sync of appl_ptr update */ -#define SNDRV_PCM_INFO_PERFECT_DRAIN 0x00000040 /* silencing at the end of stream is not required */ -#define SNDRV_PCM_INFO_INTERLEAVED 0x00000100 /* channels are interleaved */ -#define SNDRV_PCM_INFO_NONINTERLEAVED 0x00000200 /* channels are not interleaved */ -#define SNDRV_PCM_INFO_COMPLEX 0x00000400 /* complex frame organization (mmap only) */ -#define SNDRV_PCM_INFO_BLOCK_TRANSFER 0x00010000 /* hardware transfer block of samples */ -#define SNDRV_PCM_INFO_OVERRANGE 0x00020000 /* hardware supports ADC (capture) overrange detection */ -#define SNDRV_PCM_INFO_RESUME 0x00040000 /* hardware supports stream resume after suspend */ -#define SNDRV_PCM_INFO_PAUSE 0x00080000 /* pause ioctl is supported */ -#define SNDRV_PCM_INFO_HALF_DUPLEX 0x00100000 /* only half duplex */ -#define SNDRV_PCM_INFO_JOINT_DUPLEX 0x00200000 /* playback and capture stream are somewhat correlated */ -#define SNDRV_PCM_INFO_SYNC_START 0x00400000 /* pcm support some kind of sync go */ -#define SNDRV_PCM_INFO_NO_PERIOD_WAKEUP 0x00800000 /* period wakeup can be disabled */ -#define SNDRV_PCM_INFO_HAS_WALL_CLOCK 0x01000000 /* (Deprecated)has audio wall clock for audio/system time sync */ -#define SNDRV_PCM_INFO_HAS_LINK_ATIME 0x01000000 /* report hardware link audio time, reset on startup */ -#define SNDRV_PCM_INFO_HAS_LINK_ABSOLUTE_ATIME 0x02000000 /* report absolute hardware link audio time, not reset on startup */ -#define SNDRV_PCM_INFO_HAS_LINK_ESTIMATED_ATIME 0x04000000 /* report estimated link audio time */ -#define SNDRV_PCM_INFO_HAS_LINK_SYNCHRONIZED_ATIME 0x08000000 /* report synchronized audio/system time */ -#define SNDRV_PCM_INFO_EXPLICIT_SYNC 0x10000000 /* needs explicit sync of pointers and data */ -#define SNDRV_PCM_INFO_NO_REWINDS 0x20000000 /* hardware can only support monotonic changes of appl_ptr */ -#define SNDRV_PCM_INFO_DRAIN_TRIGGER 0x40000000 /* internal kernel flag - trigger in drain */ -#define SNDRV_PCM_INFO_FIFO_IN_FRAMES 0x80000000 /* internal kernel flag - FIFO size is in frames */ - -#if (__BITS_PER_LONG == 32 && defined(__USE_TIME_BITS64)) || defined __KERNEL__ -#define __SND_STRUCT_TIME64 -#endif - -typedef int __bitwise snd_pcm_state_t; -#define SNDRV_PCM_STATE_OPEN ((__force snd_pcm_state_t) 0) /* stream is open */ -#define SNDRV_PCM_STATE_SETUP ((__force snd_pcm_state_t) 1) /* stream has a setup */ -#define SNDRV_PCM_STATE_PREPARED ((__force snd_pcm_state_t) 2) /* stream is ready to start */ -#define SNDRV_PCM_STATE_RUNNING ((__force snd_pcm_state_t) 3) /* stream is running */ -#define SNDRV_PCM_STATE_XRUN ((__force snd_pcm_state_t) 4) /* stream reached an xrun */ -#define SNDRV_PCM_STATE_DRAINING ((__force snd_pcm_state_t) 5) /* stream is draining */ -#define SNDRV_PCM_STATE_PAUSED ((__force snd_pcm_state_t) 6) /* stream is paused */ -#define SNDRV_PCM_STATE_SUSPENDED ((__force snd_pcm_state_t) 7) /* hardware is suspended */ -#define SNDRV_PCM_STATE_DISCONNECTED ((__force snd_pcm_state_t) 8) /* hardware is disconnected */ -#define SNDRV_PCM_STATE_LAST SNDRV_PCM_STATE_DISCONNECTED - -enum { - SNDRV_PCM_MMAP_OFFSET_DATA = 0x00000000, - SNDRV_PCM_MMAP_OFFSET_STATUS_OLD = 0x80000000, - SNDRV_PCM_MMAP_OFFSET_CONTROL_OLD = 0x81000000, - SNDRV_PCM_MMAP_OFFSET_STATUS_NEW = 0x82000000, - SNDRV_PCM_MMAP_OFFSET_CONTROL_NEW = 0x83000000, -#ifdef __SND_STRUCT_TIME64 - SNDRV_PCM_MMAP_OFFSET_STATUS = SNDRV_PCM_MMAP_OFFSET_STATUS_NEW, - SNDRV_PCM_MMAP_OFFSET_CONTROL = SNDRV_PCM_MMAP_OFFSET_CONTROL_NEW, -#else - SNDRV_PCM_MMAP_OFFSET_STATUS = SNDRV_PCM_MMAP_OFFSET_STATUS_OLD, - SNDRV_PCM_MMAP_OFFSET_CONTROL = SNDRV_PCM_MMAP_OFFSET_CONTROL_OLD, -#endif -}; - -union snd_pcm_sync_id { - unsigned char id[16]; - unsigned short id16[8]; - unsigned int id32[4]; -}; - -struct snd_pcm_info { - unsigned int device; /* RO/WR (control): device number */ - unsigned int subdevice; /* RO/WR (control): subdevice number */ - int stream; /* RO/WR (control): stream direction */ - int card; /* R: card number */ - unsigned char id[64]; /* ID (user selectable) */ - unsigned char name[80]; /* name of this device */ - unsigned char subname[32]; /* subdevice name */ - int dev_class; /* SNDRV_PCM_CLASS_* */ - int dev_subclass; /* SNDRV_PCM_SUBCLASS_* */ - unsigned int subdevices_count; - unsigned int subdevices_avail; - union snd_pcm_sync_id sync; /* hardware synchronization ID */ - unsigned char reserved[64]; /* reserved for future... */ -}; - -typedef int snd_pcm_hw_param_t; -#define SNDRV_PCM_HW_PARAM_ACCESS 0 /* Access type */ -#define SNDRV_PCM_HW_PARAM_FORMAT 1 /* Format */ -#define SNDRV_PCM_HW_PARAM_SUBFORMAT 2 /* Subformat */ -#define SNDRV_PCM_HW_PARAM_FIRST_MASK SNDRV_PCM_HW_PARAM_ACCESS -#define SNDRV_PCM_HW_PARAM_LAST_MASK SNDRV_PCM_HW_PARAM_SUBFORMAT - -#define SNDRV_PCM_HW_PARAM_SAMPLE_BITS 8 /* Bits per sample */ -#define SNDRV_PCM_HW_PARAM_FRAME_BITS 9 /* Bits per frame */ -#define SNDRV_PCM_HW_PARAM_CHANNELS 10 /* Channels */ -#define SNDRV_PCM_HW_PARAM_RATE 11 /* Approx rate */ -#define SNDRV_PCM_HW_PARAM_PERIOD_TIME 12 /* Approx distance between - * interrupts in us - */ -#define SNDRV_PCM_HW_PARAM_PERIOD_SIZE 13 /* Approx frames between - * interrupts - */ -#define SNDRV_PCM_HW_PARAM_PERIOD_BYTES 14 /* Approx bytes between - * interrupts - */ -#define SNDRV_PCM_HW_PARAM_PERIODS 15 /* Approx interrupts per - * buffer - */ -#define SNDRV_PCM_HW_PARAM_BUFFER_TIME 16 /* Approx duration of buffer - * in us - */ -#define SNDRV_PCM_HW_PARAM_BUFFER_SIZE 17 /* Size of buffer in frames */ -#define SNDRV_PCM_HW_PARAM_BUFFER_BYTES 18 /* Size of buffer in bytes */ -#define SNDRV_PCM_HW_PARAM_TICK_TIME 19 /* Approx tick duration in us */ -#define SNDRV_PCM_HW_PARAM_FIRST_INTERVAL SNDRV_PCM_HW_PARAM_SAMPLE_BITS -#define SNDRV_PCM_HW_PARAM_LAST_INTERVAL SNDRV_PCM_HW_PARAM_TICK_TIME - -#define SNDRV_PCM_HW_PARAMS_NORESAMPLE (1<<0) /* avoid rate resampling */ -#define SNDRV_PCM_HW_PARAMS_EXPORT_BUFFER (1<<1) /* export buffer */ -#define SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP (1<<2) /* disable period wakeups */ -#define SNDRV_PCM_HW_PARAMS_NO_DRAIN_SILENCE (1<<3) /* suppress drain with the filling - * of the silence samples - */ - -struct snd_interval { - unsigned int min, max; - unsigned int openmin:1, - openmax:1, - integer:1, - empty:1; -}; - -#define SNDRV_MASK_MAX 256 - -struct snd_mask { - __u32 bits[(SNDRV_MASK_MAX+31)/32]; -}; - -struct snd_pcm_hw_params { - unsigned int flags; - struct snd_mask masks[SNDRV_PCM_HW_PARAM_LAST_MASK - - SNDRV_PCM_HW_PARAM_FIRST_MASK + 1]; - struct snd_mask mres[5]; /* reserved masks */ - struct snd_interval intervals[SNDRV_PCM_HW_PARAM_LAST_INTERVAL - - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL + 1]; - struct snd_interval ires[9]; /* reserved intervals */ - unsigned int rmask; /* W: requested masks */ - unsigned int cmask; /* R: changed masks */ - unsigned int info; /* R: Info flags for returned setup */ - unsigned int msbits; /* R: used most significant bits */ - unsigned int rate_num; /* R: rate numerator */ - unsigned int rate_den; /* R: rate denominator */ - snd_pcm_uframes_t fifo_size; /* R: chip FIFO size in frames */ - unsigned char reserved[64]; /* reserved for future */ -}; - -enum { - SNDRV_PCM_TSTAMP_NONE = 0, - SNDRV_PCM_TSTAMP_ENABLE, - SNDRV_PCM_TSTAMP_LAST = SNDRV_PCM_TSTAMP_ENABLE, -}; - -struct snd_pcm_sw_params { - int tstamp_mode; /* timestamp mode */ - unsigned int period_step; - unsigned int sleep_min; /* min ticks to sleep */ - snd_pcm_uframes_t avail_min; /* min avail frames for wakeup */ - snd_pcm_uframes_t xfer_align; /* obsolete: xfer size need to be a multiple */ - snd_pcm_uframes_t start_threshold; /* min hw_avail frames for automatic start */ - /* - * The following two thresholds alleviate playback buffer underruns; when - * hw_avail drops below the threshold, the respective action is triggered: - */ - snd_pcm_uframes_t stop_threshold; /* - stop playback */ - snd_pcm_uframes_t silence_threshold; /* - pre-fill buffer with silence */ - snd_pcm_uframes_t silence_size; /* max size of silence pre-fill; when >= boundary, - * fill played area with silence immediately */ - snd_pcm_uframes_t boundary; /* pointers wrap point */ - unsigned int proto; /* protocol version */ - unsigned int tstamp_type; /* timestamp type (req. proto >= 2.0.12) */ - unsigned char reserved[56]; /* reserved for future */ -}; - -struct snd_pcm_channel_info { - unsigned int channel; - __kernel_off_t offset; /* mmap offset */ - unsigned int first; /* offset to first sample in bits */ - unsigned int step; /* samples distance in bits */ -}; - -enum { - /* - * first definition for backwards compatibility only, - * maps to wallclock/link time for HDAudio playback and DEFAULT/DMA time for everything else - */ - SNDRV_PCM_AUDIO_TSTAMP_TYPE_COMPAT = 0, - - /* timestamp definitions */ - SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT = 1, /* DMA time, reported as per hw_ptr */ - SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK = 2, /* link time reported by sample or wallclock counter, reset on startup */ - SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_ABSOLUTE = 3, /* link time reported by sample or wallclock counter, not reset on startup */ - SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_ESTIMATED = 4, /* link time estimated indirectly */ - SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_SYNCHRONIZED = 5, /* link time synchronized with system time */ - SNDRV_PCM_AUDIO_TSTAMP_TYPE_LAST = SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_SYNCHRONIZED -}; - -#ifndef __KERNEL__ -/* explicit padding avoids incompatibility between i386 and x86-64 */ -typedef struct { unsigned char pad[sizeof(time_t) - sizeof(int)]; } __time_pad; - -struct snd_pcm_status { - snd_pcm_state_t state; /* stream state */ - __time_pad pad1; /* align to timespec */ - struct timespec trigger_tstamp; /* time when stream was started/stopped/paused */ - struct timespec tstamp; /* reference timestamp */ - snd_pcm_uframes_t appl_ptr; /* appl ptr */ - snd_pcm_uframes_t hw_ptr; /* hw ptr */ - snd_pcm_sframes_t delay; /* current delay in frames */ - snd_pcm_uframes_t avail; /* number of frames available */ - snd_pcm_uframes_t avail_max; /* max frames available on hw since last status */ - snd_pcm_uframes_t overrange; /* count of ADC (capture) overrange detections from last status */ - snd_pcm_state_t suspended_state; /* suspended stream state */ - __u32 audio_tstamp_data; /* needed for 64-bit alignment, used for configs/report to/from userspace */ - struct timespec audio_tstamp; /* sample counter, wall clock, PHC or on-demand sync'ed */ - struct timespec driver_tstamp; /* useful in case reference system tstamp is reported with delay */ - __u32 audio_tstamp_accuracy; /* in ns units, only valid if indicated in audio_tstamp_data */ - unsigned char reserved[52-2*sizeof(struct timespec)]; /* must be filled with zero */ -}; -#endif - -/* - * For mmap operations, we need the 64-bit layout, both for compat mode, - * and for y2038 compatibility. For 64-bit applications, the two definitions - * are identical, so we keep the traditional version. - */ -#ifdef __SND_STRUCT_TIME64 -#define __snd_pcm_mmap_status64 snd_pcm_mmap_status -#define __snd_pcm_mmap_control64 snd_pcm_mmap_control -#define __snd_pcm_sync_ptr64 snd_pcm_sync_ptr -#ifdef __KERNEL__ -#define __snd_timespec64 __kernel_timespec -#else -#define __snd_timespec64 timespec -#endif -struct __snd_timespec { - __s32 tv_sec; - __s32 tv_nsec; -}; -#else -#define __snd_pcm_mmap_status snd_pcm_mmap_status -#define __snd_pcm_mmap_control snd_pcm_mmap_control -#define __snd_pcm_sync_ptr snd_pcm_sync_ptr -#define __snd_timespec timespec -struct __snd_timespec64 { - __s64 tv_sec; - __s64 tv_nsec; -}; - -#endif - -struct __snd_pcm_mmap_status { - snd_pcm_state_t state; /* RO: state - SNDRV_PCM_STATE_XXXX */ - int pad1; /* Needed for 64 bit alignment */ - snd_pcm_uframes_t hw_ptr; /* RO: hw ptr (0...boundary-1) */ - struct __snd_timespec tstamp; /* Timestamp */ - snd_pcm_state_t suspended_state; /* RO: suspended stream state */ - struct __snd_timespec audio_tstamp; /* from sample counter or wall clock */ -}; - -struct __snd_pcm_mmap_control { - snd_pcm_uframes_t appl_ptr; /* RW: appl ptr (0...boundary-1) */ - snd_pcm_uframes_t avail_min; /* RW: min available frames for wakeup */ -}; - -#define SNDRV_PCM_SYNC_PTR_HWSYNC (1<<0) /* execute hwsync */ -#define SNDRV_PCM_SYNC_PTR_APPL (1<<1) /* get appl_ptr from driver (r/w op) */ -#define SNDRV_PCM_SYNC_PTR_AVAIL_MIN (1<<2) /* get avail_min from driver */ - -struct __snd_pcm_sync_ptr { - unsigned int flags; - union { - struct __snd_pcm_mmap_status status; - unsigned char reserved[64]; - } s; - union { - struct __snd_pcm_mmap_control control; - unsigned char reserved[64]; - } c; -}; - -#if defined(__BYTE_ORDER) ? __BYTE_ORDER == __BIG_ENDIAN : defined(__BIG_ENDIAN) -typedef char __pad_before_uframe[sizeof(__u64) - sizeof(snd_pcm_uframes_t)]; -typedef char __pad_after_uframe[0]; -#endif - -#if defined(__BYTE_ORDER) ? __BYTE_ORDER == __LITTLE_ENDIAN : defined(__LITTLE_ENDIAN) -typedef char __pad_before_uframe[0]; -typedef char __pad_after_uframe[sizeof(__u64) - sizeof(snd_pcm_uframes_t)]; -#endif - -struct __snd_pcm_mmap_status64 { - snd_pcm_state_t state; /* RO: state - SNDRV_PCM_STATE_XXXX */ - __u32 pad1; /* Needed for 64 bit alignment */ - __pad_before_uframe __pad1; - snd_pcm_uframes_t hw_ptr; /* RO: hw ptr (0...boundary-1) */ - __pad_after_uframe __pad2; - struct __snd_timespec64 tstamp; /* Timestamp */ - snd_pcm_state_t suspended_state;/* RO: suspended stream state */ - __u32 pad3; /* Needed for 64 bit alignment */ - struct __snd_timespec64 audio_tstamp; /* sample counter or wall clock */ -}; - -struct __snd_pcm_mmap_control64 { - __pad_before_uframe __pad1; - snd_pcm_uframes_t appl_ptr; /* RW: appl ptr (0...boundary-1) */ - __pad_before_uframe __pad2; // This should be __pad_after_uframe, but binary - // backwards compatibility constraints prevent a fix. - - __pad_before_uframe __pad3; - snd_pcm_uframes_t avail_min; /* RW: min available frames for wakeup */ - __pad_after_uframe __pad4; -}; - -struct __snd_pcm_sync_ptr64 { - __u32 flags; - __u32 pad1; - union { - struct __snd_pcm_mmap_status64 status; - unsigned char reserved[64]; - } s; - union { - struct __snd_pcm_mmap_control64 control; - unsigned char reserved[64]; - } c; -}; - -struct snd_xferi { - snd_pcm_sframes_t result; - void __user *buf; - snd_pcm_uframes_t frames; -}; - -struct snd_xfern { - snd_pcm_sframes_t result; - void __user * __user *bufs; - snd_pcm_uframes_t frames; -}; - -enum { - SNDRV_PCM_TSTAMP_TYPE_GETTIMEOFDAY = 0, /* gettimeofday equivalent */ - SNDRV_PCM_TSTAMP_TYPE_MONOTONIC, /* posix_clock_monotonic equivalent */ - SNDRV_PCM_TSTAMP_TYPE_MONOTONIC_RAW, /* monotonic_raw (no NTP) */ - SNDRV_PCM_TSTAMP_TYPE_LAST = SNDRV_PCM_TSTAMP_TYPE_MONOTONIC_RAW, -}; - -/* channel positions */ -enum { - SNDRV_CHMAP_UNKNOWN = 0, - SNDRV_CHMAP_NA, /* N/A, silent */ - SNDRV_CHMAP_MONO, /* mono stream */ - /* this follows the alsa-lib mixer channel value + 3 */ - SNDRV_CHMAP_FL, /* front left */ - SNDRV_CHMAP_FR, /* front right */ - SNDRV_CHMAP_RL, /* rear left */ - SNDRV_CHMAP_RR, /* rear right */ - SNDRV_CHMAP_FC, /* front center */ - SNDRV_CHMAP_LFE, /* LFE */ - SNDRV_CHMAP_SL, /* side left */ - SNDRV_CHMAP_SR, /* side right */ - SNDRV_CHMAP_RC, /* rear center */ - /* new definitions */ - SNDRV_CHMAP_FLC, /* front left center */ - SNDRV_CHMAP_FRC, /* front right center */ - SNDRV_CHMAP_RLC, /* rear left center */ - SNDRV_CHMAP_RRC, /* rear right center */ - SNDRV_CHMAP_FLW, /* front left wide */ - SNDRV_CHMAP_FRW, /* front right wide */ - SNDRV_CHMAP_FLH, /* front left high */ - SNDRV_CHMAP_FCH, /* front center high */ - SNDRV_CHMAP_FRH, /* front right high */ - SNDRV_CHMAP_TC, /* top center */ - SNDRV_CHMAP_TFL, /* top front left */ - SNDRV_CHMAP_TFR, /* top front right */ - SNDRV_CHMAP_TFC, /* top front center */ - SNDRV_CHMAP_TRL, /* top rear left */ - SNDRV_CHMAP_TRR, /* top rear right */ - SNDRV_CHMAP_TRC, /* top rear center */ - /* new definitions for UAC2 */ - SNDRV_CHMAP_TFLC, /* top front left center */ - SNDRV_CHMAP_TFRC, /* top front right center */ - SNDRV_CHMAP_TSL, /* top side left */ - SNDRV_CHMAP_TSR, /* top side right */ - SNDRV_CHMAP_LLFE, /* left LFE */ - SNDRV_CHMAP_RLFE, /* right LFE */ - SNDRV_CHMAP_BC, /* bottom center */ - SNDRV_CHMAP_BLC, /* bottom left center */ - SNDRV_CHMAP_BRC, /* bottom right center */ - SNDRV_CHMAP_LAST = SNDRV_CHMAP_BRC, -}; - -#define SNDRV_CHMAP_POSITION_MASK 0xffff -#define SNDRV_CHMAP_PHASE_INVERSE (0x01 << 16) -#define SNDRV_CHMAP_DRIVER_SPEC (0x02 << 16) - -#define SNDRV_PCM_IOCTL_PVERSION _IOR('A', 0x00, int) -#define SNDRV_PCM_IOCTL_INFO _IOR('A', 0x01, struct snd_pcm_info) -#define SNDRV_PCM_IOCTL_TSTAMP _IOW('A', 0x02, int) -#define SNDRV_PCM_IOCTL_TTSTAMP _IOW('A', 0x03, int) -#define SNDRV_PCM_IOCTL_USER_PVERSION _IOW('A', 0x04, int) -#define SNDRV_PCM_IOCTL_HW_REFINE _IOWR('A', 0x10, struct snd_pcm_hw_params) -#define SNDRV_PCM_IOCTL_HW_PARAMS _IOWR('A', 0x11, struct snd_pcm_hw_params) -#define SNDRV_PCM_IOCTL_HW_FREE _IO('A', 0x12) -#define SNDRV_PCM_IOCTL_SW_PARAMS _IOWR('A', 0x13, struct snd_pcm_sw_params) -#define SNDRV_PCM_IOCTL_STATUS _IOR('A', 0x20, struct snd_pcm_status) -#define SNDRV_PCM_IOCTL_DELAY _IOR('A', 0x21, snd_pcm_sframes_t) -#define SNDRV_PCM_IOCTL_HWSYNC _IO('A', 0x22) -#define __SNDRV_PCM_IOCTL_SYNC_PTR _IOWR('A', 0x23, struct __snd_pcm_sync_ptr) -#define __SNDRV_PCM_IOCTL_SYNC_PTR64 _IOWR('A', 0x23, struct __snd_pcm_sync_ptr64) -#define SNDRV_PCM_IOCTL_SYNC_PTR _IOWR('A', 0x23, struct snd_pcm_sync_ptr) -#define SNDRV_PCM_IOCTL_STATUS_EXT _IOWR('A', 0x24, struct snd_pcm_status) -#define SNDRV_PCM_IOCTL_CHANNEL_INFO _IOR('A', 0x32, struct snd_pcm_channel_info) -#define SNDRV_PCM_IOCTL_PREPARE _IO('A', 0x40) -#define SNDRV_PCM_IOCTL_RESET _IO('A', 0x41) -#define SNDRV_PCM_IOCTL_START _IO('A', 0x42) -#define SNDRV_PCM_IOCTL_DROP _IO('A', 0x43) -#define SNDRV_PCM_IOCTL_DRAIN _IO('A', 0x44) -#define SNDRV_PCM_IOCTL_PAUSE _IOW('A', 0x45, int) -#define SNDRV_PCM_IOCTL_REWIND _IOW('A', 0x46, snd_pcm_uframes_t) -#define SNDRV_PCM_IOCTL_RESUME _IO('A', 0x47) -#define SNDRV_PCM_IOCTL_XRUN _IO('A', 0x48) -#define SNDRV_PCM_IOCTL_FORWARD _IOW('A', 0x49, snd_pcm_uframes_t) -#define SNDRV_PCM_IOCTL_WRITEI_FRAMES _IOW('A', 0x50, struct snd_xferi) -#define SNDRV_PCM_IOCTL_READI_FRAMES _IOR('A', 0x51, struct snd_xferi) -#define SNDRV_PCM_IOCTL_WRITEN_FRAMES _IOW('A', 0x52, struct snd_xfern) -#define SNDRV_PCM_IOCTL_READN_FRAMES _IOR('A', 0x53, struct snd_xfern) -#define SNDRV_PCM_IOCTL_LINK _IOW('A', 0x60, int) -#define SNDRV_PCM_IOCTL_UNLINK _IO('A', 0x61) - -/***************************************************************************** - * * - * MIDI v1.0 interface * - * * - *****************************************************************************/ - -/* - * Raw MIDI section - /dev/snd/midi?? - */ - -#define SNDRV_RAWMIDI_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 4) - -enum { - SNDRV_RAWMIDI_STREAM_OUTPUT = 0, - SNDRV_RAWMIDI_STREAM_INPUT, - SNDRV_RAWMIDI_STREAM_LAST = SNDRV_RAWMIDI_STREAM_INPUT, -}; - -#define SNDRV_RAWMIDI_INFO_OUTPUT 0x00000001 -#define SNDRV_RAWMIDI_INFO_INPUT 0x00000002 -#define SNDRV_RAWMIDI_INFO_DUPLEX 0x00000004 -#define SNDRV_RAWMIDI_INFO_UMP 0x00000008 - -struct snd_rawmidi_info { - unsigned int device; /* RO/WR (control): device number */ - unsigned int subdevice; /* RO/WR (control): subdevice number */ - int stream; /* WR: stream */ - int card; /* R: card number */ - unsigned int flags; /* SNDRV_RAWMIDI_INFO_XXXX */ - unsigned char id[64]; /* ID (user selectable) */ - unsigned char name[80]; /* name of device */ - unsigned char subname[32]; /* name of active or selected subdevice */ - unsigned int subdevices_count; - unsigned int subdevices_avail; - unsigned char reserved[64]; /* reserved for future use */ -}; - -#define SNDRV_RAWMIDI_MODE_FRAMING_MASK (7<<0) -#define SNDRV_RAWMIDI_MODE_FRAMING_SHIFT 0 -#define SNDRV_RAWMIDI_MODE_FRAMING_NONE (0<<0) -#define SNDRV_RAWMIDI_MODE_FRAMING_TSTAMP (1<<0) -#define SNDRV_RAWMIDI_MODE_CLOCK_MASK (7<<3) -#define SNDRV_RAWMIDI_MODE_CLOCK_SHIFT 3 -#define SNDRV_RAWMIDI_MODE_CLOCK_NONE (0<<3) -#define SNDRV_RAWMIDI_MODE_CLOCK_REALTIME (1<<3) -#define SNDRV_RAWMIDI_MODE_CLOCK_MONOTONIC (2<<3) -#define SNDRV_RAWMIDI_MODE_CLOCK_MONOTONIC_RAW (3<<3) - -#define SNDRV_RAWMIDI_FRAMING_DATA_LENGTH 16 - -struct snd_rawmidi_framing_tstamp { - /* For now, frame_type is always 0. Midi 2.0 is expected to add new - * types here. Applications are expected to skip unknown frame types. - */ - __u8 frame_type; - __u8 length; /* number of valid bytes in data field */ - __u8 reserved[2]; - __u32 tv_nsec; /* nanoseconds */ - __u64 tv_sec; /* seconds */ - __u8 data[SNDRV_RAWMIDI_FRAMING_DATA_LENGTH]; -} __packed; - -struct snd_rawmidi_params { - int stream; - size_t buffer_size; /* queue size in bytes */ - size_t avail_min; /* minimum avail bytes for wakeup */ - unsigned int no_active_sensing: 1; /* do not send active sensing byte in close() */ - unsigned int mode; /* For input data only, frame incoming data */ - unsigned char reserved[12]; /* reserved for future use */ -}; - -#ifndef __KERNEL__ -struct snd_rawmidi_status { - int stream; - __time_pad pad1; - struct timespec tstamp; /* Timestamp */ - size_t avail; /* available bytes */ - size_t xruns; /* count of overruns since last status (in bytes) */ - unsigned char reserved[16]; /* reserved for future use */ -}; -#endif - -/* UMP EP info flags */ -#define SNDRV_UMP_EP_INFO_STATIC_BLOCKS 0x01 - -/* UMP EP Protocol / JRTS capability bits */ -#define SNDRV_UMP_EP_INFO_PROTO_MIDI_MASK 0x0300 -#define SNDRV_UMP_EP_INFO_PROTO_MIDI1 0x0100 /* MIDI 1.0 */ -#define SNDRV_UMP_EP_INFO_PROTO_MIDI2 0x0200 /* MIDI 2.0 */ -#define SNDRV_UMP_EP_INFO_PROTO_JRTS_MASK 0x0003 -#define SNDRV_UMP_EP_INFO_PROTO_JRTS_TX 0x0001 /* JRTS Transmit */ -#define SNDRV_UMP_EP_INFO_PROTO_JRTS_RX 0x0002 /* JRTS Receive */ - -/* UMP Endpoint information */ -struct snd_ump_endpoint_info { - int card; /* card number */ - int device; /* device number */ - unsigned int flags; /* additional info */ - unsigned int protocol_caps; /* protocol capabilities */ - unsigned int protocol; /* current protocol */ - unsigned int num_blocks; /* # of function blocks */ - unsigned short version; /* UMP major/minor version */ - unsigned short family_id; /* MIDI device family ID */ - unsigned short model_id; /* MIDI family model ID */ - unsigned int manufacturer_id; /* MIDI manufacturer ID */ - unsigned char sw_revision[4]; /* software revision */ - unsigned short padding; - unsigned char name[128]; /* endpoint name string */ - unsigned char product_id[128]; /* unique product id string */ - unsigned char reserved[32]; -} __packed; - -/* UMP direction */ -#define SNDRV_UMP_DIR_INPUT 0x01 -#define SNDRV_UMP_DIR_OUTPUT 0x02 -#define SNDRV_UMP_DIR_BIDIRECTION 0x03 - -/* UMP block info flags */ -#define SNDRV_UMP_BLOCK_IS_MIDI1 (1U << 0) /* MIDI 1.0 port w/o restrict */ -#define SNDRV_UMP_BLOCK_IS_LOWSPEED (1U << 1) /* 31.25Kbps B/W MIDI1 port */ - -/* UMP block user-interface hint */ -#define SNDRV_UMP_BLOCK_UI_HINT_UNKNOWN 0x00 -#define SNDRV_UMP_BLOCK_UI_HINT_RECEIVER 0x01 -#define SNDRV_UMP_BLOCK_UI_HINT_SENDER 0x02 -#define SNDRV_UMP_BLOCK_UI_HINT_BOTH 0x03 - -/* UMP groups and blocks */ -#define SNDRV_UMP_MAX_GROUPS 16 -#define SNDRV_UMP_MAX_BLOCKS 32 - -/* UMP Block information */ -struct snd_ump_block_info { - int card; /* card number */ - int device; /* device number */ - unsigned char block_id; /* block ID (R/W) */ - unsigned char direction; /* UMP direction */ - unsigned char active; /* Activeness */ - unsigned char first_group; /* first group ID */ - unsigned char num_groups; /* number of groups */ - unsigned char midi_ci_version; /* MIDI-CI support version */ - unsigned char sysex8_streams; /* max number of sysex8 streams */ - unsigned char ui_hint; /* user interface hint */ - unsigned int flags; /* various info flags */ - unsigned char name[128]; /* block name string */ - unsigned char reserved[32]; -} __packed; - -#define SNDRV_RAWMIDI_IOCTL_PVERSION _IOR('W', 0x00, int) -#define SNDRV_RAWMIDI_IOCTL_INFO _IOR('W', 0x01, struct snd_rawmidi_info) -#define SNDRV_RAWMIDI_IOCTL_USER_PVERSION _IOW('W', 0x02, int) -#define SNDRV_RAWMIDI_IOCTL_PARAMS _IOWR('W', 0x10, struct snd_rawmidi_params) -#define SNDRV_RAWMIDI_IOCTL_STATUS _IOWR('W', 0x20, struct snd_rawmidi_status) -#define SNDRV_RAWMIDI_IOCTL_DROP _IOW('W', 0x30, int) -#define SNDRV_RAWMIDI_IOCTL_DRAIN _IOW('W', 0x31, int) -/* Additional ioctls for UMP rawmidi devices */ -#define SNDRV_UMP_IOCTL_ENDPOINT_INFO _IOR('W', 0x40, struct snd_ump_endpoint_info) -#define SNDRV_UMP_IOCTL_BLOCK_INFO _IOR('W', 0x41, struct snd_ump_block_info) - -/* - * Timer section - /dev/snd/timer - */ - -#define SNDRV_TIMER_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 7) - -enum { - SNDRV_TIMER_CLASS_NONE = -1, - SNDRV_TIMER_CLASS_SLAVE = 0, - SNDRV_TIMER_CLASS_GLOBAL, - SNDRV_TIMER_CLASS_CARD, - SNDRV_TIMER_CLASS_PCM, - SNDRV_TIMER_CLASS_LAST = SNDRV_TIMER_CLASS_PCM, -}; - -/* slave timer classes */ -enum { - SNDRV_TIMER_SCLASS_NONE = 0, - SNDRV_TIMER_SCLASS_APPLICATION, - SNDRV_TIMER_SCLASS_SEQUENCER, /* alias */ - SNDRV_TIMER_SCLASS_OSS_SEQUENCER, /* alias */ - SNDRV_TIMER_SCLASS_LAST = SNDRV_TIMER_SCLASS_OSS_SEQUENCER, -}; - -/* global timers (device member) */ -#define SNDRV_TIMER_GLOBAL_SYSTEM 0 -#define SNDRV_TIMER_GLOBAL_RTC 1 /* unused */ -#define SNDRV_TIMER_GLOBAL_HPET 2 -#define SNDRV_TIMER_GLOBAL_HRTIMER 3 - -/* info flags */ -#define SNDRV_TIMER_FLG_SLAVE (1<<0) /* cannot be controlled */ - -struct snd_timer_id { - int dev_class; - int dev_sclass; - int card; - int device; - int subdevice; -}; - -struct snd_timer_ginfo { - struct snd_timer_id tid; /* requested timer ID */ - unsigned int flags; /* timer flags - SNDRV_TIMER_FLG_* */ - int card; /* card number */ - unsigned char id[64]; /* timer identification */ - unsigned char name[80]; /* timer name */ - unsigned long reserved0; /* reserved for future use */ - unsigned long resolution; /* average period resolution in ns */ - unsigned long resolution_min; /* minimal period resolution in ns */ - unsigned long resolution_max; /* maximal period resolution in ns */ - unsigned int clients; /* active timer clients */ - unsigned char reserved[32]; -}; - -struct snd_timer_gparams { - struct snd_timer_id tid; /* requested timer ID */ - unsigned long period_num; /* requested precise period duration (in seconds) - numerator */ - unsigned long period_den; /* requested precise period duration (in seconds) - denominator */ - unsigned char reserved[32]; -}; - -struct snd_timer_gstatus { - struct snd_timer_id tid; /* requested timer ID */ - unsigned long resolution; /* current period resolution in ns */ - unsigned long resolution_num; /* precise current period resolution (in seconds) - numerator */ - unsigned long resolution_den; /* precise current period resolution (in seconds) - denominator */ - unsigned char reserved[32]; -}; - -struct snd_timer_select { - struct snd_timer_id id; /* bind to timer ID */ - unsigned char reserved[32]; /* reserved */ -}; - -struct snd_timer_info { - unsigned int flags; /* timer flags - SNDRV_TIMER_FLG_* */ - int card; /* card number */ - unsigned char id[64]; /* timer identificator */ - unsigned char name[80]; /* timer name */ - unsigned long reserved0; /* reserved for future use */ - unsigned long resolution; /* average period resolution in ns */ - unsigned char reserved[64]; /* reserved */ -}; - -#define SNDRV_TIMER_PSFLG_AUTO (1<<0) /* auto start, otherwise one-shot */ -#define SNDRV_TIMER_PSFLG_EXCLUSIVE (1<<1) /* exclusive use, precise start/stop/pause/continue */ -#define SNDRV_TIMER_PSFLG_EARLY_EVENT (1<<2) /* write early event to the poll queue */ - -struct snd_timer_params { - unsigned int flags; /* flags - SNDRV_TIMER_PSFLG_* */ - unsigned int ticks; /* requested resolution in ticks */ - unsigned int queue_size; /* total size of queue (32-1024) */ - unsigned int reserved0; /* reserved, was: failure locations */ - unsigned int filter; /* event filter (bitmask of SNDRV_TIMER_EVENT_*) */ - unsigned char reserved[60]; /* reserved */ -}; - -#ifndef __KERNEL__ -struct snd_timer_status { - struct timespec tstamp; /* Timestamp - last update */ - unsigned int resolution; /* current period resolution in ns */ - unsigned int lost; /* counter of master tick lost */ - unsigned int overrun; /* count of read queue overruns */ - unsigned int queue; /* used queue size */ - unsigned char reserved[64]; /* reserved */ -}; -#endif - -#define SNDRV_TIMER_IOCTL_PVERSION _IOR('T', 0x00, int) -#define SNDRV_TIMER_IOCTL_NEXT_DEVICE _IOWR('T', 0x01, struct snd_timer_id) -#define SNDRV_TIMER_IOCTL_TREAD_OLD _IOW('T', 0x02, int) -#define SNDRV_TIMER_IOCTL_GINFO _IOWR('T', 0x03, struct snd_timer_ginfo) -#define SNDRV_TIMER_IOCTL_GPARAMS _IOW('T', 0x04, struct snd_timer_gparams) -#define SNDRV_TIMER_IOCTL_GSTATUS _IOWR('T', 0x05, struct snd_timer_gstatus) -#define SNDRV_TIMER_IOCTL_SELECT _IOW('T', 0x10, struct snd_timer_select) -#define SNDRV_TIMER_IOCTL_INFO _IOR('T', 0x11, struct snd_timer_info) -#define SNDRV_TIMER_IOCTL_PARAMS _IOW('T', 0x12, struct snd_timer_params) -#define SNDRV_TIMER_IOCTL_STATUS _IOR('T', 0x14, struct snd_timer_status) -/* The following four ioctls are changed since 1.0.9 due to confliction */ -#define SNDRV_TIMER_IOCTL_START _IO('T', 0xa0) -#define SNDRV_TIMER_IOCTL_STOP _IO('T', 0xa1) -#define SNDRV_TIMER_IOCTL_CONTINUE _IO('T', 0xa2) -#define SNDRV_TIMER_IOCTL_PAUSE _IO('T', 0xa3) -#define SNDRV_TIMER_IOCTL_TREAD64 _IOW('T', 0xa4, int) - -#if __BITS_PER_LONG == 64 -#define SNDRV_TIMER_IOCTL_TREAD SNDRV_TIMER_IOCTL_TREAD_OLD -#else -#define SNDRV_TIMER_IOCTL_TREAD ((sizeof(__kernel_long_t) >= sizeof(time_t)) ? \ - SNDRV_TIMER_IOCTL_TREAD_OLD : \ - SNDRV_TIMER_IOCTL_TREAD64) -#endif - -struct snd_timer_read { - unsigned int resolution; - unsigned int ticks; -}; - -enum { - SNDRV_TIMER_EVENT_RESOLUTION = 0, /* val = resolution in ns */ - SNDRV_TIMER_EVENT_TICK, /* val = ticks */ - SNDRV_TIMER_EVENT_START, /* val = resolution in ns */ - SNDRV_TIMER_EVENT_STOP, /* val = 0 */ - SNDRV_TIMER_EVENT_CONTINUE, /* val = resolution in ns */ - SNDRV_TIMER_EVENT_PAUSE, /* val = 0 */ - SNDRV_TIMER_EVENT_EARLY, /* val = 0, early event */ - SNDRV_TIMER_EVENT_SUSPEND, /* val = 0 */ - SNDRV_TIMER_EVENT_RESUME, /* val = resolution in ns */ - /* master timer events for slave timer instances */ - SNDRV_TIMER_EVENT_MSTART = SNDRV_TIMER_EVENT_START + 10, - SNDRV_TIMER_EVENT_MSTOP = SNDRV_TIMER_EVENT_STOP + 10, - SNDRV_TIMER_EVENT_MCONTINUE = SNDRV_TIMER_EVENT_CONTINUE + 10, - SNDRV_TIMER_EVENT_MPAUSE = SNDRV_TIMER_EVENT_PAUSE + 10, - SNDRV_TIMER_EVENT_MSUSPEND = SNDRV_TIMER_EVENT_SUSPEND + 10, - SNDRV_TIMER_EVENT_MRESUME = SNDRV_TIMER_EVENT_RESUME + 10, -}; - -#ifndef __KERNEL__ -struct snd_timer_tread { - int event; - __time_pad pad1; - struct timespec tstamp; - unsigned int val; - __time_pad pad2; -}; -#endif - -/**************************************************************************** - * * - * Section for driver control interface - /dev/snd/control? * - * * - ****************************************************************************/ - -#define SNDRV_CTL_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 9) - -struct snd_ctl_card_info { - int card; /* card number */ - int pad; /* reserved for future (was type) */ - unsigned char id[16]; /* ID of card (user selectable) */ - unsigned char driver[16]; /* Driver name */ - unsigned char name[32]; /* Short name of soundcard */ - unsigned char longname[80]; /* name + info text about soundcard */ - unsigned char reserved_[16]; /* reserved for future (was ID of mixer) */ - unsigned char mixername[80]; /* visual mixer identification */ - unsigned char components[128]; /* card components / fine identification, delimited with one space (AC97 etc..) */ -}; - -typedef int __bitwise snd_ctl_elem_type_t; -#define SNDRV_CTL_ELEM_TYPE_NONE ((__force snd_ctl_elem_type_t) 0) /* invalid */ -#define SNDRV_CTL_ELEM_TYPE_BOOLEAN ((__force snd_ctl_elem_type_t) 1) /* boolean type */ -#define SNDRV_CTL_ELEM_TYPE_INTEGER ((__force snd_ctl_elem_type_t) 2) /* integer type */ -#define SNDRV_CTL_ELEM_TYPE_ENUMERATED ((__force snd_ctl_elem_type_t) 3) /* enumerated type */ -#define SNDRV_CTL_ELEM_TYPE_BYTES ((__force snd_ctl_elem_type_t) 4) /* byte array */ -#define SNDRV_CTL_ELEM_TYPE_IEC958 ((__force snd_ctl_elem_type_t) 5) /* IEC958 (S/PDIF) setup */ -#define SNDRV_CTL_ELEM_TYPE_INTEGER64 ((__force snd_ctl_elem_type_t) 6) /* 64-bit integer type */ -#define SNDRV_CTL_ELEM_TYPE_LAST SNDRV_CTL_ELEM_TYPE_INTEGER64 - -typedef int __bitwise snd_ctl_elem_iface_t; -#define SNDRV_CTL_ELEM_IFACE_CARD ((__force snd_ctl_elem_iface_t) 0) /* global control */ -#define SNDRV_CTL_ELEM_IFACE_HWDEP ((__force snd_ctl_elem_iface_t) 1) /* hardware dependent device */ -#define SNDRV_CTL_ELEM_IFACE_MIXER ((__force snd_ctl_elem_iface_t) 2) /* virtual mixer device */ -#define SNDRV_CTL_ELEM_IFACE_PCM ((__force snd_ctl_elem_iface_t) 3) /* PCM device */ -#define SNDRV_CTL_ELEM_IFACE_RAWMIDI ((__force snd_ctl_elem_iface_t) 4) /* RawMidi device */ -#define SNDRV_CTL_ELEM_IFACE_TIMER ((__force snd_ctl_elem_iface_t) 5) /* timer device */ -#define SNDRV_CTL_ELEM_IFACE_SEQUENCER ((__force snd_ctl_elem_iface_t) 6) /* sequencer client */ -#define SNDRV_CTL_ELEM_IFACE_LAST SNDRV_CTL_ELEM_IFACE_SEQUENCER - -#define SNDRV_CTL_ELEM_ACCESS_READ (1<<0) -#define SNDRV_CTL_ELEM_ACCESS_WRITE (1<<1) -#define SNDRV_CTL_ELEM_ACCESS_READWRITE (SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE) -#define SNDRV_CTL_ELEM_ACCESS_VOLATILE (1<<2) /* control value may be changed without a notification */ -/* (1 << 3) is unused. */ -#define SNDRV_CTL_ELEM_ACCESS_TLV_READ (1<<4) /* TLV read is possible */ -#define SNDRV_CTL_ELEM_ACCESS_TLV_WRITE (1<<5) /* TLV write is possible */ -#define SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE (SNDRV_CTL_ELEM_ACCESS_TLV_READ|SNDRV_CTL_ELEM_ACCESS_TLV_WRITE) -#define SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND (1<<6) /* TLV command is possible */ -#define SNDRV_CTL_ELEM_ACCESS_INACTIVE (1<<8) /* control does actually nothing, but may be updated */ -#define SNDRV_CTL_ELEM_ACCESS_LOCK (1<<9) /* write lock */ -#define SNDRV_CTL_ELEM_ACCESS_OWNER (1<<10) /* write lock owner */ -#define SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK (1<<28) /* kernel use a TLV callback */ -#define SNDRV_CTL_ELEM_ACCESS_USER (1<<29) /* user space element */ -/* bits 30 and 31 are obsoleted (for indirect access) */ - -/* for further details see the ACPI and PCI power management specification */ -#define SNDRV_CTL_POWER_D0 0x0000 /* full On */ -#define SNDRV_CTL_POWER_D1 0x0100 /* partial On */ -#define SNDRV_CTL_POWER_D2 0x0200 /* partial On */ -#define SNDRV_CTL_POWER_D3 0x0300 /* Off */ -#define SNDRV_CTL_POWER_D3hot (SNDRV_CTL_POWER_D3|0x0000) /* Off, with power */ -#define SNDRV_CTL_POWER_D3cold (SNDRV_CTL_POWER_D3|0x0001) /* Off, without power */ - -#define SNDRV_CTL_ELEM_ID_NAME_MAXLEN 44 - -struct snd_ctl_elem_id { - unsigned int numid; /* numeric identifier, zero = invalid */ - snd_ctl_elem_iface_t iface; /* interface identifier */ - unsigned int device; /* device/client number */ - unsigned int subdevice; /* subdevice (substream) number */ - unsigned char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; /* ASCII name of item */ - unsigned int index; /* index of item */ -}; - -struct snd_ctl_elem_list { - unsigned int offset; /* W: first element ID to get */ - unsigned int space; /* W: count of element IDs to get */ - unsigned int used; /* R: count of element IDs set */ - unsigned int count; /* R: count of all elements */ - struct snd_ctl_elem_id __user *pids; /* R: IDs */ - unsigned char reserved[50]; -}; - -struct snd_ctl_elem_info { - struct snd_ctl_elem_id id; /* W: element ID */ - snd_ctl_elem_type_t type; /* R: value type - SNDRV_CTL_ELEM_TYPE_* */ - unsigned int access; /* R: value access (bitmask) - SNDRV_CTL_ELEM_ACCESS_* */ - unsigned int count; /* count of values */ - __kernel_pid_t owner; /* owner's PID of this control */ - union { - struct { - long min; /* R: minimum value */ - long max; /* R: maximum value */ - long step; /* R: step (0 variable) */ - } integer; - struct { - long long min; /* R: minimum value */ - long long max; /* R: maximum value */ - long long step; /* R: step (0 variable) */ - } integer64; - struct { - unsigned int items; /* R: number of items */ - unsigned int item; /* W: item number */ - char name[64]; /* R: value name */ - __u64 names_ptr; /* W: names list (ELEM_ADD only) */ - unsigned int names_length; - } enumerated; - unsigned char reserved[128]; - } value; - unsigned char reserved[64]; -}; - -struct snd_ctl_elem_value { - struct snd_ctl_elem_id id; /* W: element ID */ - unsigned int indirect: 1; /* W: indirect access - obsoleted */ - union { - union { - long value[128]; - long *value_ptr; /* obsoleted */ - } integer; - union { - long long value[64]; - long long *value_ptr; /* obsoleted */ - } integer64; - union { - unsigned int item[128]; - unsigned int *item_ptr; /* obsoleted */ - } enumerated; - union { - unsigned char data[512]; - unsigned char *data_ptr; /* obsoleted */ - } bytes; - struct snd_aes_iec958 iec958; - } value; /* RO */ - unsigned char reserved[128]; -}; - -struct snd_ctl_tlv { - unsigned int numid; /* control element numeric identification */ - unsigned int length; /* in bytes aligned to 4 */ - unsigned int tlv[]; /* first TLV */ -}; - -#define SNDRV_CTL_IOCTL_PVERSION _IOR('U', 0x00, int) -#define SNDRV_CTL_IOCTL_CARD_INFO _IOR('U', 0x01, struct snd_ctl_card_info) -#define SNDRV_CTL_IOCTL_ELEM_LIST _IOWR('U', 0x10, struct snd_ctl_elem_list) -#define SNDRV_CTL_IOCTL_ELEM_INFO _IOWR('U', 0x11, struct snd_ctl_elem_info) -#define SNDRV_CTL_IOCTL_ELEM_READ _IOWR('U', 0x12, struct snd_ctl_elem_value) -#define SNDRV_CTL_IOCTL_ELEM_WRITE _IOWR('U', 0x13, struct snd_ctl_elem_value) -#define SNDRV_CTL_IOCTL_ELEM_LOCK _IOW('U', 0x14, struct snd_ctl_elem_id) -#define SNDRV_CTL_IOCTL_ELEM_UNLOCK _IOW('U', 0x15, struct snd_ctl_elem_id) -#define SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS _IOWR('U', 0x16, int) -#define SNDRV_CTL_IOCTL_ELEM_ADD _IOWR('U', 0x17, struct snd_ctl_elem_info) -#define SNDRV_CTL_IOCTL_ELEM_REPLACE _IOWR('U', 0x18, struct snd_ctl_elem_info) -#define SNDRV_CTL_IOCTL_ELEM_REMOVE _IOWR('U', 0x19, struct snd_ctl_elem_id) -#define SNDRV_CTL_IOCTL_TLV_READ _IOWR('U', 0x1a, struct snd_ctl_tlv) -#define SNDRV_CTL_IOCTL_TLV_WRITE _IOWR('U', 0x1b, struct snd_ctl_tlv) -#define SNDRV_CTL_IOCTL_TLV_COMMAND _IOWR('U', 0x1c, struct snd_ctl_tlv) -#define SNDRV_CTL_IOCTL_HWDEP_NEXT_DEVICE _IOWR('U', 0x20, int) -#define SNDRV_CTL_IOCTL_HWDEP_INFO _IOR('U', 0x21, struct snd_hwdep_info) -#define SNDRV_CTL_IOCTL_PCM_NEXT_DEVICE _IOR('U', 0x30, int) -#define SNDRV_CTL_IOCTL_PCM_INFO _IOWR('U', 0x31, struct snd_pcm_info) -#define SNDRV_CTL_IOCTL_PCM_PREFER_SUBDEVICE _IOW('U', 0x32, int) -#define SNDRV_CTL_IOCTL_RAWMIDI_NEXT_DEVICE _IOWR('U', 0x40, int) -#define SNDRV_CTL_IOCTL_RAWMIDI_INFO _IOWR('U', 0x41, struct snd_rawmidi_info) -#define SNDRV_CTL_IOCTL_RAWMIDI_PREFER_SUBDEVICE _IOW('U', 0x42, int) -#define SNDRV_CTL_IOCTL_UMP_NEXT_DEVICE _IOWR('U', 0x43, int) -#define SNDRV_CTL_IOCTL_UMP_ENDPOINT_INFO _IOWR('U', 0x44, struct snd_ump_endpoint_info) -#define SNDRV_CTL_IOCTL_UMP_BLOCK_INFO _IOWR('U', 0x45, struct snd_ump_block_info) -#define SNDRV_CTL_IOCTL_POWER _IOWR('U', 0xd0, int) -#define SNDRV_CTL_IOCTL_POWER_STATE _IOR('U', 0xd1, int) - -/* - * Read interface. - */ - -enum sndrv_ctl_event_type { - SNDRV_CTL_EVENT_ELEM = 0, - SNDRV_CTL_EVENT_LAST = SNDRV_CTL_EVENT_ELEM, -}; - -#define SNDRV_CTL_EVENT_MASK_VALUE (1<<0) /* element value was changed */ -#define SNDRV_CTL_EVENT_MASK_INFO (1<<1) /* element info was changed */ -#define SNDRV_CTL_EVENT_MASK_ADD (1<<2) /* element was added */ -#define SNDRV_CTL_EVENT_MASK_TLV (1<<3) /* element TLV tree was changed */ -#define SNDRV_CTL_EVENT_MASK_REMOVE (~0U) /* element was removed */ - -struct snd_ctl_event { - int type; /* event type - SNDRV_CTL_EVENT_* */ - union { - struct { - unsigned int mask; - struct snd_ctl_elem_id id; - } elem; - unsigned char data8[60]; - } data; -}; - -/* - * Control names - */ - -#define SNDRV_CTL_NAME_NONE "" -#define SNDRV_CTL_NAME_PLAYBACK "Playback " -#define SNDRV_CTL_NAME_CAPTURE "Capture " - -#define SNDRV_CTL_NAME_IEC958_NONE "" -#define SNDRV_CTL_NAME_IEC958_SWITCH "Switch" -#define SNDRV_CTL_NAME_IEC958_VOLUME "Volume" -#define SNDRV_CTL_NAME_IEC958_DEFAULT "Default" -#define SNDRV_CTL_NAME_IEC958_MASK "Mask" -#define SNDRV_CTL_NAME_IEC958_CON_MASK "Con Mask" -#define SNDRV_CTL_NAME_IEC958_PRO_MASK "Pro Mask" -#define SNDRV_CTL_NAME_IEC958_PCM_STREAM "PCM Stream" -#define SNDRV_CTL_NAME_IEC958(expl,direction,what) "IEC958 " expl SNDRV_CTL_NAME_##direction SNDRV_CTL_NAME_IEC958_##what - -#endif /* _UAPI__SOUND_ASOUND_H */ diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index 53ec3765b4b2..757777d96860 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -473,6 +473,7 @@ arm64-sysreg-defs-clean: beauty_linux_dir := $(srctree)/tools/perf/trace/beauty/include/linux/ beauty_uapi_linux_dir := $(srctree)/tools/perf/trace/beauty/include/uapi/linux/ +beauty_uapi_sound_dir := $(srctree)/tools/perf/trace/beauty/include/uapi/sound/ linux_uapi_dir := $(srctree)/tools/include/uapi/linux asm_generic_uapi_dir := $(srctree)/tools/include/uapi/asm-generic arch_asm_uapi_dir := $(srctree)/tools/arch/$(SRCARCH)/include/uapi/asm/ @@ -526,15 +527,15 @@ sndrv_ctl_ioctl_array := $(beauty_ioctl_outdir)/sndrv_ctl_ioctl_array.c sndrv_ctl_hdr_dir := $(srctree)/tools/include/uapi/sound sndrv_ctl_ioctl_tbl := $(srctree)/tools/perf/trace/beauty/sndrv_ctl_ioctl.sh -$(sndrv_ctl_ioctl_array): $(sndrv_ctl_hdr_dir)/asound.h $(sndrv_ctl_ioctl_tbl) - $(Q)$(SHELL) '$(sndrv_ctl_ioctl_tbl)' $(sndrv_ctl_hdr_dir) > $@ +$(sndrv_ctl_ioctl_array): $(beauty_uapi_sound_dir)/asound.h $(sndrv_ctl_ioctl_tbl) + $(Q)$(SHELL) '$(sndrv_ctl_ioctl_tbl)' $(beauty_uapi_sound_dir) > $@ sndrv_pcm_ioctl_array := $(beauty_ioctl_outdir)/sndrv_pcm_ioctl_array.c sndrv_pcm_hdr_dir := $(srctree)/tools/include/uapi/sound sndrv_pcm_ioctl_tbl := $(srctree)/tools/perf/trace/beauty/sndrv_pcm_ioctl.sh -$(sndrv_pcm_ioctl_array): $(sndrv_pcm_hdr_dir)/asound.h $(sndrv_pcm_ioctl_tbl) - $(Q)$(SHELL) '$(sndrv_pcm_ioctl_tbl)' $(sndrv_pcm_hdr_dir) > $@ +$(sndrv_pcm_ioctl_array): $(beauty_uapi_sound_dir)/asound.h $(sndrv_pcm_ioctl_tbl) + $(Q)$(SHELL) '$(sndrv_pcm_ioctl_tbl)' $(beauty_uapi_sound_dir) > $@ kcmp_type_array := $(beauty_outdir)/kcmp_type_array.c kcmp_hdr_dir := $(srctree)/tools/include/uapi/linux/ diff --git a/tools/perf/check-headers.sh b/tools/perf/check-headers.sh index 356ddb76a954..93ad7a787a19 100755 --- a/tools/perf/check-headers.sh +++ b/tools/perf/check-headers.sh @@ -22,7 +22,6 @@ FILES=( "include/uapi/linux/seccomp.h" "include/uapi/linux/stat.h" "include/uapi/linux/vhost.h" - "include/uapi/sound/asound.h" "include/linux/bits.h" "include/vdso/bits.h" "include/linux/const.h" @@ -98,6 +97,7 @@ BEAUTY_FILES=( "include/uapi/linux/fs.h" "include/uapi/linux/mount.h" "include/uapi/linux/usbdevice_fs.h" + "include/uapi/sound/asound.h" ) declare -a FAILURES diff --git a/tools/perf/trace/beauty/include/uapi/sound/asound.h b/tools/perf/trace/beauty/include/uapi/sound/asound.h new file mode 100644 index 000000000000..d5b9cfbd9cea --- /dev/null +++ b/tools/perf/trace/beauty/include/uapi/sound/asound.h @@ -0,0 +1,1252 @@ +/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ +/* + * Advanced Linux Sound Architecture - ALSA - Driver + * Copyright (c) 1994-2003 by Jaroslav Kysela , + * Abramo Bagnara + */ + +#ifndef _UAPI__SOUND_ASOUND_H +#define _UAPI__SOUND_ASOUND_H + +#if defined(__KERNEL__) || defined(__linux__) +#include +#include +#else +#include +#include +#endif + +#ifndef __KERNEL__ +#include +#include +#endif + +/* + * protocol version + */ + +#define SNDRV_PROTOCOL_VERSION(major, minor, subminor) (((major)<<16)|((minor)<<8)|(subminor)) +#define SNDRV_PROTOCOL_MAJOR(version) (((version)>>16)&0xffff) +#define SNDRV_PROTOCOL_MINOR(version) (((version)>>8)&0xff) +#define SNDRV_PROTOCOL_MICRO(version) ((version)&0xff) +#define SNDRV_PROTOCOL_INCOMPATIBLE(kversion, uversion) \ + (SNDRV_PROTOCOL_MAJOR(kversion) != SNDRV_PROTOCOL_MAJOR(uversion) || \ + (SNDRV_PROTOCOL_MAJOR(kversion) == SNDRV_PROTOCOL_MAJOR(uversion) && \ + SNDRV_PROTOCOL_MINOR(kversion) != SNDRV_PROTOCOL_MINOR(uversion))) + +/**************************************************************************** + * * + * Digital audio interface * + * * + ****************************************************************************/ + +#define AES_IEC958_STATUS_SIZE 24 + +struct snd_aes_iec958 { + unsigned char status[AES_IEC958_STATUS_SIZE]; /* AES/IEC958 channel status bits */ + unsigned char subcode[147]; /* AES/IEC958 subcode bits */ + unsigned char pad; /* nothing */ + unsigned char dig_subframe[4]; /* AES/IEC958 subframe bits */ +}; + +/**************************************************************************** + * * + * CEA-861 Audio InfoFrame. Used in HDMI and DisplayPort * + * * + ****************************************************************************/ + +struct snd_cea_861_aud_if { + unsigned char db1_ct_cc; /* coding type and channel count */ + unsigned char db2_sf_ss; /* sample frequency and size */ + unsigned char db3; /* not used, all zeros */ + unsigned char db4_ca; /* channel allocation code */ + unsigned char db5_dminh_lsv; /* downmix inhibit & level-shit values */ +}; + +/**************************************************************************** + * * + * Section for driver hardware dependent interface - /dev/snd/hw? * + * * + ****************************************************************************/ + +#define SNDRV_HWDEP_VERSION SNDRV_PROTOCOL_VERSION(1, 0, 1) + +enum { + SNDRV_HWDEP_IFACE_OPL2 = 0, + SNDRV_HWDEP_IFACE_OPL3, + SNDRV_HWDEP_IFACE_OPL4, + SNDRV_HWDEP_IFACE_SB16CSP, /* Creative Signal Processor */ + SNDRV_HWDEP_IFACE_EMU10K1, /* FX8010 processor in EMU10K1 chip */ + SNDRV_HWDEP_IFACE_YSS225, /* Yamaha FX processor */ + SNDRV_HWDEP_IFACE_ICS2115, /* Wavetable synth */ + SNDRV_HWDEP_IFACE_SSCAPE, /* Ensoniq SoundScape ISA card (MC68EC000) */ + SNDRV_HWDEP_IFACE_VX, /* Digigram VX cards */ + SNDRV_HWDEP_IFACE_MIXART, /* Digigram miXart cards */ + SNDRV_HWDEP_IFACE_USX2Y, /* Tascam US122, US224 & US428 usb */ + SNDRV_HWDEP_IFACE_EMUX_WAVETABLE, /* EmuX wavetable */ + SNDRV_HWDEP_IFACE_BLUETOOTH, /* Bluetooth audio */ + SNDRV_HWDEP_IFACE_USX2Y_PCM, /* Tascam US122, US224 & US428 rawusb pcm */ + SNDRV_HWDEP_IFACE_PCXHR, /* Digigram PCXHR */ + SNDRV_HWDEP_IFACE_SB_RC, /* SB Extigy/Audigy2NX remote control */ + SNDRV_HWDEP_IFACE_HDA, /* HD-audio */ + SNDRV_HWDEP_IFACE_USB_STREAM, /* direct access to usb stream */ + SNDRV_HWDEP_IFACE_FW_DICE, /* TC DICE FireWire device */ + SNDRV_HWDEP_IFACE_FW_FIREWORKS, /* Echo Audio Fireworks based device */ + SNDRV_HWDEP_IFACE_FW_BEBOB, /* BridgeCo BeBoB based device */ + SNDRV_HWDEP_IFACE_FW_OXFW, /* Oxford OXFW970/971 based device */ + SNDRV_HWDEP_IFACE_FW_DIGI00X, /* Digidesign Digi 002/003 family */ + SNDRV_HWDEP_IFACE_FW_TASCAM, /* TASCAM FireWire series */ + SNDRV_HWDEP_IFACE_LINE6, /* Line6 USB processors */ + SNDRV_HWDEP_IFACE_FW_MOTU, /* MOTU FireWire series */ + SNDRV_HWDEP_IFACE_FW_FIREFACE, /* RME Fireface series */ + + /* Don't forget to change the following: */ + SNDRV_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_FW_FIREFACE +}; + +struct snd_hwdep_info { + unsigned int device; /* WR: device number */ + int card; /* R: card number */ + unsigned char id[64]; /* ID (user selectable) */ + unsigned char name[80]; /* hwdep name */ + int iface; /* hwdep interface */ + unsigned char reserved[64]; /* reserved for future */ +}; + +/* generic DSP loader */ +struct snd_hwdep_dsp_status { + unsigned int version; /* R: driver-specific version */ + unsigned char id[32]; /* R: driver-specific ID string */ + unsigned int num_dsps; /* R: number of DSP images to transfer */ + unsigned int dsp_loaded; /* R: bit flags indicating the loaded DSPs */ + unsigned int chip_ready; /* R: 1 = initialization finished */ + unsigned char reserved[16]; /* reserved for future use */ +}; + +struct snd_hwdep_dsp_image { + unsigned int index; /* W: DSP index */ + unsigned char name[64]; /* W: ID (e.g. file name) */ + unsigned char __user *image; /* W: binary image */ + size_t length; /* W: size of image in bytes */ + unsigned long driver_data; /* W: driver-specific data */ +}; + +#define SNDRV_HWDEP_IOCTL_PVERSION _IOR ('H', 0x00, int) +#define SNDRV_HWDEP_IOCTL_INFO _IOR ('H', 0x01, struct snd_hwdep_info) +#define SNDRV_HWDEP_IOCTL_DSP_STATUS _IOR('H', 0x02, struct snd_hwdep_dsp_status) +#define SNDRV_HWDEP_IOCTL_DSP_LOAD _IOW('H', 0x03, struct snd_hwdep_dsp_image) + +/***************************************************************************** + * * + * Digital Audio (PCM) interface - /dev/snd/pcm?? * + * * + *****************************************************************************/ + +#define SNDRV_PCM_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 16) + +typedef unsigned long snd_pcm_uframes_t; +typedef signed long snd_pcm_sframes_t; + +enum { + SNDRV_PCM_CLASS_GENERIC = 0, /* standard mono or stereo device */ + SNDRV_PCM_CLASS_MULTI, /* multichannel device */ + SNDRV_PCM_CLASS_MODEM, /* software modem class */ + SNDRV_PCM_CLASS_DIGITIZER, /* digitizer class */ + /* Don't forget to change the following: */ + SNDRV_PCM_CLASS_LAST = SNDRV_PCM_CLASS_DIGITIZER, +}; + +enum { + SNDRV_PCM_SUBCLASS_GENERIC_MIX = 0, /* mono or stereo subdevices are mixed together */ + SNDRV_PCM_SUBCLASS_MULTI_MIX, /* multichannel subdevices are mixed together */ + /* Don't forget to change the following: */ + SNDRV_PCM_SUBCLASS_LAST = SNDRV_PCM_SUBCLASS_MULTI_MIX, +}; + +enum { + SNDRV_PCM_STREAM_PLAYBACK = 0, + SNDRV_PCM_STREAM_CAPTURE, + SNDRV_PCM_STREAM_LAST = SNDRV_PCM_STREAM_CAPTURE, +}; + +typedef int __bitwise snd_pcm_access_t; +#define SNDRV_PCM_ACCESS_MMAP_INTERLEAVED ((__force snd_pcm_access_t) 0) /* interleaved mmap */ +#define SNDRV_PCM_ACCESS_MMAP_NONINTERLEAVED ((__force snd_pcm_access_t) 1) /* noninterleaved mmap */ +#define SNDRV_PCM_ACCESS_MMAP_COMPLEX ((__force snd_pcm_access_t) 2) /* complex mmap */ +#define SNDRV_PCM_ACCESS_RW_INTERLEAVED ((__force snd_pcm_access_t) 3) /* readi/writei */ +#define SNDRV_PCM_ACCESS_RW_NONINTERLEAVED ((__force snd_pcm_access_t) 4) /* readn/writen */ +#define SNDRV_PCM_ACCESS_LAST SNDRV_PCM_ACCESS_RW_NONINTERLEAVED + +typedef int __bitwise snd_pcm_format_t; +#define SNDRV_PCM_FORMAT_S8 ((__force snd_pcm_format_t) 0) +#define SNDRV_PCM_FORMAT_U8 ((__force snd_pcm_format_t) 1) +#define SNDRV_PCM_FORMAT_S16_LE ((__force snd_pcm_format_t) 2) +#define SNDRV_PCM_FORMAT_S16_BE ((__force snd_pcm_format_t) 3) +#define SNDRV_PCM_FORMAT_U16_LE ((__force snd_pcm_format_t) 4) +#define SNDRV_PCM_FORMAT_U16_BE ((__force snd_pcm_format_t) 5) +#define SNDRV_PCM_FORMAT_S24_LE ((__force snd_pcm_format_t) 6) /* low three bytes */ +#define SNDRV_PCM_FORMAT_S24_BE ((__force snd_pcm_format_t) 7) /* low three bytes */ +#define SNDRV_PCM_FORMAT_U24_LE ((__force snd_pcm_format_t) 8) /* low three bytes */ +#define SNDRV_PCM_FORMAT_U24_BE ((__force snd_pcm_format_t) 9) /* low three bytes */ +/* + * For S32/U32 formats, 'msbits' hardware parameter is often used to deliver information about the + * available bit count in most significant bit. It's for the case of so-called 'left-justified' or + * `right-padding` sample which has less width than 32 bit. + */ +#define SNDRV_PCM_FORMAT_S32_LE ((__force snd_pcm_format_t) 10) +#define SNDRV_PCM_FORMAT_S32_BE ((__force snd_pcm_format_t) 11) +#define SNDRV_PCM_FORMAT_U32_LE ((__force snd_pcm_format_t) 12) +#define SNDRV_PCM_FORMAT_U32_BE ((__force snd_pcm_format_t) 13) +#define SNDRV_PCM_FORMAT_FLOAT_LE ((__force snd_pcm_format_t) 14) /* 4-byte float, IEEE-754 32-bit, range -1.0 to 1.0 */ +#define SNDRV_PCM_FORMAT_FLOAT_BE ((__force snd_pcm_format_t) 15) /* 4-byte float, IEEE-754 32-bit, range -1.0 to 1.0 */ +#define SNDRV_PCM_FORMAT_FLOAT64_LE ((__force snd_pcm_format_t) 16) /* 8-byte float, IEEE-754 64-bit, range -1.0 to 1.0 */ +#define SNDRV_PCM_FORMAT_FLOAT64_BE ((__force snd_pcm_format_t) 17) /* 8-byte float, IEEE-754 64-bit, range -1.0 to 1.0 */ +#define SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE ((__force snd_pcm_format_t) 18) /* IEC-958 subframe, Little Endian */ +#define SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE ((__force snd_pcm_format_t) 19) /* IEC-958 subframe, Big Endian */ +#define SNDRV_PCM_FORMAT_MU_LAW ((__force snd_pcm_format_t) 20) +#define SNDRV_PCM_FORMAT_A_LAW ((__force snd_pcm_format_t) 21) +#define SNDRV_PCM_FORMAT_IMA_ADPCM ((__force snd_pcm_format_t) 22) +#define SNDRV_PCM_FORMAT_MPEG ((__force snd_pcm_format_t) 23) +#define SNDRV_PCM_FORMAT_GSM ((__force snd_pcm_format_t) 24) +#define SNDRV_PCM_FORMAT_S20_LE ((__force snd_pcm_format_t) 25) /* in four bytes, LSB justified */ +#define SNDRV_PCM_FORMAT_S20_BE ((__force snd_pcm_format_t) 26) /* in four bytes, LSB justified */ +#define SNDRV_PCM_FORMAT_U20_LE ((__force snd_pcm_format_t) 27) /* in four bytes, LSB justified */ +#define SNDRV_PCM_FORMAT_U20_BE ((__force snd_pcm_format_t) 28) /* in four bytes, LSB justified */ +/* gap in the numbering for a future standard linear format */ +#define SNDRV_PCM_FORMAT_SPECIAL ((__force snd_pcm_format_t) 31) +#define SNDRV_PCM_FORMAT_S24_3LE ((__force snd_pcm_format_t) 32) /* in three bytes */ +#define SNDRV_PCM_FORMAT_S24_3BE ((__force snd_pcm_format_t) 33) /* in three bytes */ +#define SNDRV_PCM_FORMAT_U24_3LE ((__force snd_pcm_format_t) 34) /* in three bytes */ +#define SNDRV_PCM_FORMAT_U24_3BE ((__force snd_pcm_format_t) 35) /* in three bytes */ +#define SNDRV_PCM_FORMAT_S20_3LE ((__force snd_pcm_format_t) 36) /* in three bytes */ +#define SNDRV_PCM_FORMAT_S20_3BE ((__force snd_pcm_format_t) 37) /* in three bytes */ +#define SNDRV_PCM_FORMAT_U20_3LE ((__force snd_pcm_format_t) 38) /* in three bytes */ +#define SNDRV_PCM_FORMAT_U20_3BE ((__force snd_pcm_format_t) 39) /* in three bytes */ +#define SNDRV_PCM_FORMAT_S18_3LE ((__force snd_pcm_format_t) 40) /* in three bytes */ +#define SNDRV_PCM_FORMAT_S18_3BE ((__force snd_pcm_format_t) 41) /* in three bytes */ +#define SNDRV_PCM_FORMAT_U18_3LE ((__force snd_pcm_format_t) 42) /* in three bytes */ +#define SNDRV_PCM_FORMAT_U18_3BE ((__force snd_pcm_format_t) 43) /* in three bytes */ +#define SNDRV_PCM_FORMAT_G723_24 ((__force snd_pcm_format_t) 44) /* 8 samples in 3 bytes */ +#define SNDRV_PCM_FORMAT_G723_24_1B ((__force snd_pcm_format_t) 45) /* 1 sample in 1 byte */ +#define SNDRV_PCM_FORMAT_G723_40 ((__force snd_pcm_format_t) 46) /* 8 Samples in 5 bytes */ +#define SNDRV_PCM_FORMAT_G723_40_1B ((__force snd_pcm_format_t) 47) /* 1 sample in 1 byte */ +#define SNDRV_PCM_FORMAT_DSD_U8 ((__force snd_pcm_format_t) 48) /* DSD, 1-byte samples DSD (x8) */ +#define SNDRV_PCM_FORMAT_DSD_U16_LE ((__force snd_pcm_format_t) 49) /* DSD, 2-byte samples DSD (x16), little endian */ +#define SNDRV_PCM_FORMAT_DSD_U32_LE ((__force snd_pcm_format_t) 50) /* DSD, 4-byte samples DSD (x32), little endian */ +#define SNDRV_PCM_FORMAT_DSD_U16_BE ((__force snd_pcm_format_t) 51) /* DSD, 2-byte samples DSD (x16), big endian */ +#define SNDRV_PCM_FORMAT_DSD_U32_BE ((__force snd_pcm_format_t) 52) /* DSD, 4-byte samples DSD (x32), big endian */ +#define SNDRV_PCM_FORMAT_LAST SNDRV_PCM_FORMAT_DSD_U32_BE +#define SNDRV_PCM_FORMAT_FIRST SNDRV_PCM_FORMAT_S8 + +#ifdef SNDRV_LITTLE_ENDIAN +#define SNDRV_PCM_FORMAT_S16 SNDRV_PCM_FORMAT_S16_LE +#define SNDRV_PCM_FORMAT_U16 SNDRV_PCM_FORMAT_U16_LE +#define SNDRV_PCM_FORMAT_S24 SNDRV_PCM_FORMAT_S24_LE +#define SNDRV_PCM_FORMAT_U24 SNDRV_PCM_FORMAT_U24_LE +#define SNDRV_PCM_FORMAT_S32 SNDRV_PCM_FORMAT_S32_LE +#define SNDRV_PCM_FORMAT_U32 SNDRV_PCM_FORMAT_U32_LE +#define SNDRV_PCM_FORMAT_FLOAT SNDRV_PCM_FORMAT_FLOAT_LE +#define SNDRV_PCM_FORMAT_FLOAT64 SNDRV_PCM_FORMAT_FLOAT64_LE +#define SNDRV_PCM_FORMAT_IEC958_SUBFRAME SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE +#define SNDRV_PCM_FORMAT_S20 SNDRV_PCM_FORMAT_S20_LE +#define SNDRV_PCM_FORMAT_U20 SNDRV_PCM_FORMAT_U20_LE +#endif +#ifdef SNDRV_BIG_ENDIAN +#define SNDRV_PCM_FORMAT_S16 SNDRV_PCM_FORMAT_S16_BE +#define SNDRV_PCM_FORMAT_U16 SNDRV_PCM_FORMAT_U16_BE +#define SNDRV_PCM_FORMAT_S24 SNDRV_PCM_FORMAT_S24_BE +#define SNDRV_PCM_FORMAT_U24 SNDRV_PCM_FORMAT_U24_BE +#define SNDRV_PCM_FORMAT_S32 SNDRV_PCM_FORMAT_S32_BE +#define SNDRV_PCM_FORMAT_U32 SNDRV_PCM_FORMAT_U32_BE +#define SNDRV_PCM_FORMAT_FLOAT SNDRV_PCM_FORMAT_FLOAT_BE +#define SNDRV_PCM_FORMAT_FLOAT64 SNDRV_PCM_FORMAT_FLOAT64_BE +#define SNDRV_PCM_FORMAT_IEC958_SUBFRAME SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE +#define SNDRV_PCM_FORMAT_S20 SNDRV_PCM_FORMAT_S20_BE +#define SNDRV_PCM_FORMAT_U20 SNDRV_PCM_FORMAT_U20_BE +#endif + +typedef int __bitwise snd_pcm_subformat_t; +#define SNDRV_PCM_SUBFORMAT_STD ((__force snd_pcm_subformat_t) 0) +#define SNDRV_PCM_SUBFORMAT_MSBITS_MAX ((__force snd_pcm_subformat_t) 1) +#define SNDRV_PCM_SUBFORMAT_MSBITS_20 ((__force snd_pcm_subformat_t) 2) +#define SNDRV_PCM_SUBFORMAT_MSBITS_24 ((__force snd_pcm_subformat_t) 3) +#define SNDRV_PCM_SUBFORMAT_LAST SNDRV_PCM_SUBFORMAT_MSBITS_24 + +#define SNDRV_PCM_INFO_MMAP 0x00000001 /* hardware supports mmap */ +#define SNDRV_PCM_INFO_MMAP_VALID 0x00000002 /* period data are valid during transfer */ +#define SNDRV_PCM_INFO_DOUBLE 0x00000004 /* Double buffering needed for PCM start/stop */ +#define SNDRV_PCM_INFO_BATCH 0x00000010 /* double buffering */ +#define SNDRV_PCM_INFO_SYNC_APPLPTR 0x00000020 /* need the explicit sync of appl_ptr update */ +#define SNDRV_PCM_INFO_PERFECT_DRAIN 0x00000040 /* silencing at the end of stream is not required */ +#define SNDRV_PCM_INFO_INTERLEAVED 0x00000100 /* channels are interleaved */ +#define SNDRV_PCM_INFO_NONINTERLEAVED 0x00000200 /* channels are not interleaved */ +#define SNDRV_PCM_INFO_COMPLEX 0x00000400 /* complex frame organization (mmap only) */ +#define SNDRV_PCM_INFO_BLOCK_TRANSFER 0x00010000 /* hardware transfer block of samples */ +#define SNDRV_PCM_INFO_OVERRANGE 0x00020000 /* hardware supports ADC (capture) overrange detection */ +#define SNDRV_PCM_INFO_RESUME 0x00040000 /* hardware supports stream resume after suspend */ +#define SNDRV_PCM_INFO_PAUSE 0x00080000 /* pause ioctl is supported */ +#define SNDRV_PCM_INFO_HALF_DUPLEX 0x00100000 /* only half duplex */ +#define SNDRV_PCM_INFO_JOINT_DUPLEX 0x00200000 /* playback and capture stream are somewhat correlated */ +#define SNDRV_PCM_INFO_SYNC_START 0x00400000 /* pcm support some kind of sync go */ +#define SNDRV_PCM_INFO_NO_PERIOD_WAKEUP 0x00800000 /* period wakeup can be disabled */ +#define SNDRV_PCM_INFO_HAS_WALL_CLOCK 0x01000000 /* (Deprecated)has audio wall clock for audio/system time sync */ +#define SNDRV_PCM_INFO_HAS_LINK_ATIME 0x01000000 /* report hardware link audio time, reset on startup */ +#define SNDRV_PCM_INFO_HAS_LINK_ABSOLUTE_ATIME 0x02000000 /* report absolute hardware link audio time, not reset on startup */ +#define SNDRV_PCM_INFO_HAS_LINK_ESTIMATED_ATIME 0x04000000 /* report estimated link audio time */ +#define SNDRV_PCM_INFO_HAS_LINK_SYNCHRONIZED_ATIME 0x08000000 /* report synchronized audio/system time */ +#define SNDRV_PCM_INFO_EXPLICIT_SYNC 0x10000000 /* needs explicit sync of pointers and data */ +#define SNDRV_PCM_INFO_NO_REWINDS 0x20000000 /* hardware can only support monotonic changes of appl_ptr */ +#define SNDRV_PCM_INFO_DRAIN_TRIGGER 0x40000000 /* internal kernel flag - trigger in drain */ +#define SNDRV_PCM_INFO_FIFO_IN_FRAMES 0x80000000 /* internal kernel flag - FIFO size is in frames */ + +#if (__BITS_PER_LONG == 32 && defined(__USE_TIME_BITS64)) || defined __KERNEL__ +#define __SND_STRUCT_TIME64 +#endif + +typedef int __bitwise snd_pcm_state_t; +#define SNDRV_PCM_STATE_OPEN ((__force snd_pcm_state_t) 0) /* stream is open */ +#define SNDRV_PCM_STATE_SETUP ((__force snd_pcm_state_t) 1) /* stream has a setup */ +#define SNDRV_PCM_STATE_PREPARED ((__force snd_pcm_state_t) 2) /* stream is ready to start */ +#define SNDRV_PCM_STATE_RUNNING ((__force snd_pcm_state_t) 3) /* stream is running */ +#define SNDRV_PCM_STATE_XRUN ((__force snd_pcm_state_t) 4) /* stream reached an xrun */ +#define SNDRV_PCM_STATE_DRAINING ((__force snd_pcm_state_t) 5) /* stream is draining */ +#define SNDRV_PCM_STATE_PAUSED ((__force snd_pcm_state_t) 6) /* stream is paused */ +#define SNDRV_PCM_STATE_SUSPENDED ((__force snd_pcm_state_t) 7) /* hardware is suspended */ +#define SNDRV_PCM_STATE_DISCONNECTED ((__force snd_pcm_state_t) 8) /* hardware is disconnected */ +#define SNDRV_PCM_STATE_LAST SNDRV_PCM_STATE_DISCONNECTED + +enum { + SNDRV_PCM_MMAP_OFFSET_DATA = 0x00000000, + SNDRV_PCM_MMAP_OFFSET_STATUS_OLD = 0x80000000, + SNDRV_PCM_MMAP_OFFSET_CONTROL_OLD = 0x81000000, + SNDRV_PCM_MMAP_OFFSET_STATUS_NEW = 0x82000000, + SNDRV_PCM_MMAP_OFFSET_CONTROL_NEW = 0x83000000, +#ifdef __SND_STRUCT_TIME64 + SNDRV_PCM_MMAP_OFFSET_STATUS = SNDRV_PCM_MMAP_OFFSET_STATUS_NEW, + SNDRV_PCM_MMAP_OFFSET_CONTROL = SNDRV_PCM_MMAP_OFFSET_CONTROL_NEW, +#else + SNDRV_PCM_MMAP_OFFSET_STATUS = SNDRV_PCM_MMAP_OFFSET_STATUS_OLD, + SNDRV_PCM_MMAP_OFFSET_CONTROL = SNDRV_PCM_MMAP_OFFSET_CONTROL_OLD, +#endif +}; + +union snd_pcm_sync_id { + unsigned char id[16]; + unsigned short id16[8]; + unsigned int id32[4]; +}; + +struct snd_pcm_info { + unsigned int device; /* RO/WR (control): device number */ + unsigned int subdevice; /* RO/WR (control): subdevice number */ + int stream; /* RO/WR (control): stream direction */ + int card; /* R: card number */ + unsigned char id[64]; /* ID (user selectable) */ + unsigned char name[80]; /* name of this device */ + unsigned char subname[32]; /* subdevice name */ + int dev_class; /* SNDRV_PCM_CLASS_* */ + int dev_subclass; /* SNDRV_PCM_SUBCLASS_* */ + unsigned int subdevices_count; + unsigned int subdevices_avail; + union snd_pcm_sync_id sync; /* hardware synchronization ID */ + unsigned char reserved[64]; /* reserved for future... */ +}; + +typedef int snd_pcm_hw_param_t; +#define SNDRV_PCM_HW_PARAM_ACCESS 0 /* Access type */ +#define SNDRV_PCM_HW_PARAM_FORMAT 1 /* Format */ +#define SNDRV_PCM_HW_PARAM_SUBFORMAT 2 /* Subformat */ +#define SNDRV_PCM_HW_PARAM_FIRST_MASK SNDRV_PCM_HW_PARAM_ACCESS +#define SNDRV_PCM_HW_PARAM_LAST_MASK SNDRV_PCM_HW_PARAM_SUBFORMAT + +#define SNDRV_PCM_HW_PARAM_SAMPLE_BITS 8 /* Bits per sample */ +#define SNDRV_PCM_HW_PARAM_FRAME_BITS 9 /* Bits per frame */ +#define SNDRV_PCM_HW_PARAM_CHANNELS 10 /* Channels */ +#define SNDRV_PCM_HW_PARAM_RATE 11 /* Approx rate */ +#define SNDRV_PCM_HW_PARAM_PERIOD_TIME 12 /* Approx distance between + * interrupts in us + */ +#define SNDRV_PCM_HW_PARAM_PERIOD_SIZE 13 /* Approx frames between + * interrupts + */ +#define SNDRV_PCM_HW_PARAM_PERIOD_BYTES 14 /* Approx bytes between + * interrupts + */ +#define SNDRV_PCM_HW_PARAM_PERIODS 15 /* Approx interrupts per + * buffer + */ +#define SNDRV_PCM_HW_PARAM_BUFFER_TIME 16 /* Approx duration of buffer + * in us + */ +#define SNDRV_PCM_HW_PARAM_BUFFER_SIZE 17 /* Size of buffer in frames */ +#define SNDRV_PCM_HW_PARAM_BUFFER_BYTES 18 /* Size of buffer in bytes */ +#define SNDRV_PCM_HW_PARAM_TICK_TIME 19 /* Approx tick duration in us */ +#define SNDRV_PCM_HW_PARAM_FIRST_INTERVAL SNDRV_PCM_HW_PARAM_SAMPLE_BITS +#define SNDRV_PCM_HW_PARAM_LAST_INTERVAL SNDRV_PCM_HW_PARAM_TICK_TIME + +#define SNDRV_PCM_HW_PARAMS_NORESAMPLE (1<<0) /* avoid rate resampling */ +#define SNDRV_PCM_HW_PARAMS_EXPORT_BUFFER (1<<1) /* export buffer */ +#define SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP (1<<2) /* disable period wakeups */ +#define SNDRV_PCM_HW_PARAMS_NO_DRAIN_SILENCE (1<<3) /* suppress drain with the filling + * of the silence samples + */ + +struct snd_interval { + unsigned int min, max; + unsigned int openmin:1, + openmax:1, + integer:1, + empty:1; +}; + +#define SNDRV_MASK_MAX 256 + +struct snd_mask { + __u32 bits[(SNDRV_MASK_MAX+31)/32]; +}; + +struct snd_pcm_hw_params { + unsigned int flags; + struct snd_mask masks[SNDRV_PCM_HW_PARAM_LAST_MASK - + SNDRV_PCM_HW_PARAM_FIRST_MASK + 1]; + struct snd_mask mres[5]; /* reserved masks */ + struct snd_interval intervals[SNDRV_PCM_HW_PARAM_LAST_INTERVAL - + SNDRV_PCM_HW_PARAM_FIRST_INTERVAL + 1]; + struct snd_interval ires[9]; /* reserved intervals */ + unsigned int rmask; /* W: requested masks */ + unsigned int cmask; /* R: changed masks */ + unsigned int info; /* R: Info flags for returned setup */ + unsigned int msbits; /* R: used most significant bits */ + unsigned int rate_num; /* R: rate numerator */ + unsigned int rate_den; /* R: rate denominator */ + snd_pcm_uframes_t fifo_size; /* R: chip FIFO size in frames */ + unsigned char reserved[64]; /* reserved for future */ +}; + +enum { + SNDRV_PCM_TSTAMP_NONE = 0, + SNDRV_PCM_TSTAMP_ENABLE, + SNDRV_PCM_TSTAMP_LAST = SNDRV_PCM_TSTAMP_ENABLE, +}; + +struct snd_pcm_sw_params { + int tstamp_mode; /* timestamp mode */ + unsigned int period_step; + unsigned int sleep_min; /* min ticks to sleep */ + snd_pcm_uframes_t avail_min; /* min avail frames for wakeup */ + snd_pcm_uframes_t xfer_align; /* obsolete: xfer size need to be a multiple */ + snd_pcm_uframes_t start_threshold; /* min hw_avail frames for automatic start */ + /* + * The following two thresholds alleviate playback buffer underruns; when + * hw_avail drops below the threshold, the respective action is triggered: + */ + snd_pcm_uframes_t stop_threshold; /* - stop playback */ + snd_pcm_uframes_t silence_threshold; /* - pre-fill buffer with silence */ + snd_pcm_uframes_t silence_size; /* max size of silence pre-fill; when >= boundary, + * fill played area with silence immediately */ + snd_pcm_uframes_t boundary; /* pointers wrap point */ + unsigned int proto; /* protocol version */ + unsigned int tstamp_type; /* timestamp type (req. proto >= 2.0.12) */ + unsigned char reserved[56]; /* reserved for future */ +}; + +struct snd_pcm_channel_info { + unsigned int channel; + __kernel_off_t offset; /* mmap offset */ + unsigned int first; /* offset to first sample in bits */ + unsigned int step; /* samples distance in bits */ +}; + +enum { + /* + * first definition for backwards compatibility only, + * maps to wallclock/link time for HDAudio playback and DEFAULT/DMA time for everything else + */ + SNDRV_PCM_AUDIO_TSTAMP_TYPE_COMPAT = 0, + + /* timestamp definitions */ + SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT = 1, /* DMA time, reported as per hw_ptr */ + SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK = 2, /* link time reported by sample or wallclock counter, reset on startup */ + SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_ABSOLUTE = 3, /* link time reported by sample or wallclock counter, not reset on startup */ + SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_ESTIMATED = 4, /* link time estimated indirectly */ + SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_SYNCHRONIZED = 5, /* link time synchronized with system time */ + SNDRV_PCM_AUDIO_TSTAMP_TYPE_LAST = SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_SYNCHRONIZED +}; + +#ifndef __KERNEL__ +/* explicit padding avoids incompatibility between i386 and x86-64 */ +typedef struct { unsigned char pad[sizeof(time_t) - sizeof(int)]; } __time_pad; + +struct snd_pcm_status { + snd_pcm_state_t state; /* stream state */ + __time_pad pad1; /* align to timespec */ + struct timespec trigger_tstamp; /* time when stream was started/stopped/paused */ + struct timespec tstamp; /* reference timestamp */ + snd_pcm_uframes_t appl_ptr; /* appl ptr */ + snd_pcm_uframes_t hw_ptr; /* hw ptr */ + snd_pcm_sframes_t delay; /* current delay in frames */ + snd_pcm_uframes_t avail; /* number of frames available */ + snd_pcm_uframes_t avail_max; /* max frames available on hw since last status */ + snd_pcm_uframes_t overrange; /* count of ADC (capture) overrange detections from last status */ + snd_pcm_state_t suspended_state; /* suspended stream state */ + __u32 audio_tstamp_data; /* needed for 64-bit alignment, used for configs/report to/from userspace */ + struct timespec audio_tstamp; /* sample counter, wall clock, PHC or on-demand sync'ed */ + struct timespec driver_tstamp; /* useful in case reference system tstamp is reported with delay */ + __u32 audio_tstamp_accuracy; /* in ns units, only valid if indicated in audio_tstamp_data */ + unsigned char reserved[52-2*sizeof(struct timespec)]; /* must be filled with zero */ +}; +#endif + +/* + * For mmap operations, we need the 64-bit layout, both for compat mode, + * and for y2038 compatibility. For 64-bit applications, the two definitions + * are identical, so we keep the traditional version. + */ +#ifdef __SND_STRUCT_TIME64 +#define __snd_pcm_mmap_status64 snd_pcm_mmap_status +#define __snd_pcm_mmap_control64 snd_pcm_mmap_control +#define __snd_pcm_sync_ptr64 snd_pcm_sync_ptr +#ifdef __KERNEL__ +#define __snd_timespec64 __kernel_timespec +#else +#define __snd_timespec64 timespec +#endif +struct __snd_timespec { + __s32 tv_sec; + __s32 tv_nsec; +}; +#else +#define __snd_pcm_mmap_status snd_pcm_mmap_status +#define __snd_pcm_mmap_control snd_pcm_mmap_control +#define __snd_pcm_sync_ptr snd_pcm_sync_ptr +#define __snd_timespec timespec +struct __snd_timespec64 { + __s64 tv_sec; + __s64 tv_nsec; +}; + +#endif + +struct __snd_pcm_mmap_status { + snd_pcm_state_t state; /* RO: state - SNDRV_PCM_STATE_XXXX */ + int pad1; /* Needed for 64 bit alignment */ + snd_pcm_uframes_t hw_ptr; /* RO: hw ptr (0...boundary-1) */ + struct __snd_timespec tstamp; /* Timestamp */ + snd_pcm_state_t suspended_state; /* RO: suspended stream state */ + struct __snd_timespec audio_tstamp; /* from sample counter or wall clock */ +}; + +struct __snd_pcm_mmap_control { + snd_pcm_uframes_t appl_ptr; /* RW: appl ptr (0...boundary-1) */ + snd_pcm_uframes_t avail_min; /* RW: min available frames for wakeup */ +}; + +#define SNDRV_PCM_SYNC_PTR_HWSYNC (1<<0) /* execute hwsync */ +#define SNDRV_PCM_SYNC_PTR_APPL (1<<1) /* get appl_ptr from driver (r/w op) */ +#define SNDRV_PCM_SYNC_PTR_AVAIL_MIN (1<<2) /* get avail_min from driver */ + +struct __snd_pcm_sync_ptr { + unsigned int flags; + union { + struct __snd_pcm_mmap_status status; + unsigned char reserved[64]; + } s; + union { + struct __snd_pcm_mmap_control control; + unsigned char reserved[64]; + } c; +}; + +#if defined(__BYTE_ORDER) ? __BYTE_ORDER == __BIG_ENDIAN : defined(__BIG_ENDIAN) +typedef char __pad_before_uframe[sizeof(__u64) - sizeof(snd_pcm_uframes_t)]; +typedef char __pad_after_uframe[0]; +#endif + +#if defined(__BYTE_ORDER) ? __BYTE_ORDER == __LITTLE_ENDIAN : defined(__LITTLE_ENDIAN) +typedef char __pad_before_uframe[0]; +typedef char __pad_after_uframe[sizeof(__u64) - sizeof(snd_pcm_uframes_t)]; +#endif + +struct __snd_pcm_mmap_status64 { + snd_pcm_state_t state; /* RO: state - SNDRV_PCM_STATE_XXXX */ + __u32 pad1; /* Needed for 64 bit alignment */ + __pad_before_uframe __pad1; + snd_pcm_uframes_t hw_ptr; /* RO: hw ptr (0...boundary-1) */ + __pad_after_uframe __pad2; + struct __snd_timespec64 tstamp; /* Timestamp */ + snd_pcm_state_t suspended_state;/* RO: suspended stream state */ + __u32 pad3; /* Needed for 64 bit alignment */ + struct __snd_timespec64 audio_tstamp; /* sample counter or wall clock */ +}; + +struct __snd_pcm_mmap_control64 { + __pad_before_uframe __pad1; + snd_pcm_uframes_t appl_ptr; /* RW: appl ptr (0...boundary-1) */ + __pad_before_uframe __pad2; // This should be __pad_after_uframe, but binary + // backwards compatibility constraints prevent a fix. + + __pad_before_uframe __pad3; + snd_pcm_uframes_t avail_min; /* RW: min available frames for wakeup */ + __pad_after_uframe __pad4; +}; + +struct __snd_pcm_sync_ptr64 { + __u32 flags; + __u32 pad1; + union { + struct __snd_pcm_mmap_status64 status; + unsigned char reserved[64]; + } s; + union { + struct __snd_pcm_mmap_control64 control; + unsigned char reserved[64]; + } c; +}; + +struct snd_xferi { + snd_pcm_sframes_t result; + void __user *buf; + snd_pcm_uframes_t frames; +}; + +struct snd_xfern { + snd_pcm_sframes_t result; + void __user * __user *bufs; + snd_pcm_uframes_t frames; +}; + +enum { + SNDRV_PCM_TSTAMP_TYPE_GETTIMEOFDAY = 0, /* gettimeofday equivalent */ + SNDRV_PCM_TSTAMP_TYPE_MONOTONIC, /* posix_clock_monotonic equivalent */ + SNDRV_PCM_TSTAMP_TYPE_MONOTONIC_RAW, /* monotonic_raw (no NTP) */ + SNDRV_PCM_TSTAMP_TYPE_LAST = SNDRV_PCM_TSTAMP_TYPE_MONOTONIC_RAW, +}; + +/* channel positions */ +enum { + SNDRV_CHMAP_UNKNOWN = 0, + SNDRV_CHMAP_NA, /* N/A, silent */ + SNDRV_CHMAP_MONO, /* mono stream */ + /* this follows the alsa-lib mixer channel value + 3 */ + SNDRV_CHMAP_FL, /* front left */ + SNDRV_CHMAP_FR, /* front right */ + SNDRV_CHMAP_RL, /* rear left */ + SNDRV_CHMAP_RR, /* rear right */ + SNDRV_CHMAP_FC, /* front center */ + SNDRV_CHMAP_LFE, /* LFE */ + SNDRV_CHMAP_SL, /* side left */ + SNDRV_CHMAP_SR, /* side right */ + SNDRV_CHMAP_RC, /* rear center */ + /* new definitions */ + SNDRV_CHMAP_FLC, /* front left center */ + SNDRV_CHMAP_FRC, /* front right center */ + SNDRV_CHMAP_RLC, /* rear left center */ + SNDRV_CHMAP_RRC, /* rear right center */ + SNDRV_CHMAP_FLW, /* front left wide */ + SNDRV_CHMAP_FRW, /* front right wide */ + SNDRV_CHMAP_FLH, /* front left high */ + SNDRV_CHMAP_FCH, /* front center high */ + SNDRV_CHMAP_FRH, /* front right high */ + SNDRV_CHMAP_TC, /* top center */ + SNDRV_CHMAP_TFL, /* top front left */ + SNDRV_CHMAP_TFR, /* top front right */ + SNDRV_CHMAP_TFC, /* top front center */ + SNDRV_CHMAP_TRL, /* top rear left */ + SNDRV_CHMAP_TRR, /* top rear right */ + SNDRV_CHMAP_TRC, /* top rear center */ + /* new definitions for UAC2 */ + SNDRV_CHMAP_TFLC, /* top front left center */ + SNDRV_CHMAP_TFRC, /* top front right center */ + SNDRV_CHMAP_TSL, /* top side left */ + SNDRV_CHMAP_TSR, /* top side right */ + SNDRV_CHMAP_LLFE, /* left LFE */ + SNDRV_CHMAP_RLFE, /* right LFE */ + SNDRV_CHMAP_BC, /* bottom center */ + SNDRV_CHMAP_BLC, /* bottom left center */ + SNDRV_CHMAP_BRC, /* bottom right center */ + SNDRV_CHMAP_LAST = SNDRV_CHMAP_BRC, +}; + +#define SNDRV_CHMAP_POSITION_MASK 0xffff +#define SNDRV_CHMAP_PHASE_INVERSE (0x01 << 16) +#define SNDRV_CHMAP_DRIVER_SPEC (0x02 << 16) + +#define SNDRV_PCM_IOCTL_PVERSION _IOR('A', 0x00, int) +#define SNDRV_PCM_IOCTL_INFO _IOR('A', 0x01, struct snd_pcm_info) +#define SNDRV_PCM_IOCTL_TSTAMP _IOW('A', 0x02, int) +#define SNDRV_PCM_IOCTL_TTSTAMP _IOW('A', 0x03, int) +#define SNDRV_PCM_IOCTL_USER_PVERSION _IOW('A', 0x04, int) +#define SNDRV_PCM_IOCTL_HW_REFINE _IOWR('A', 0x10, struct snd_pcm_hw_params) +#define SNDRV_PCM_IOCTL_HW_PARAMS _IOWR('A', 0x11, struct snd_pcm_hw_params) +#define SNDRV_PCM_IOCTL_HW_FREE _IO('A', 0x12) +#define SNDRV_PCM_IOCTL_SW_PARAMS _IOWR('A', 0x13, struct snd_pcm_sw_params) +#define SNDRV_PCM_IOCTL_STATUS _IOR('A', 0x20, struct snd_pcm_status) +#define SNDRV_PCM_IOCTL_DELAY _IOR('A', 0x21, snd_pcm_sframes_t) +#define SNDRV_PCM_IOCTL_HWSYNC _IO('A', 0x22) +#define __SNDRV_PCM_IOCTL_SYNC_PTR _IOWR('A', 0x23, struct __snd_pcm_sync_ptr) +#define __SNDRV_PCM_IOCTL_SYNC_PTR64 _IOWR('A', 0x23, struct __snd_pcm_sync_ptr64) +#define SNDRV_PCM_IOCTL_SYNC_PTR _IOWR('A', 0x23, struct snd_pcm_sync_ptr) +#define SNDRV_PCM_IOCTL_STATUS_EXT _IOWR('A', 0x24, struct snd_pcm_status) +#define SNDRV_PCM_IOCTL_CHANNEL_INFO _IOR('A', 0x32, struct snd_pcm_channel_info) +#define SNDRV_PCM_IOCTL_PREPARE _IO('A', 0x40) +#define SNDRV_PCM_IOCTL_RESET _IO('A', 0x41) +#define SNDRV_PCM_IOCTL_START _IO('A', 0x42) +#define SNDRV_PCM_IOCTL_DROP _IO('A', 0x43) +#define SNDRV_PCM_IOCTL_DRAIN _IO('A', 0x44) +#define SNDRV_PCM_IOCTL_PAUSE _IOW('A', 0x45, int) +#define SNDRV_PCM_IOCTL_REWIND _IOW('A', 0x46, snd_pcm_uframes_t) +#define SNDRV_PCM_IOCTL_RESUME _IO('A', 0x47) +#define SNDRV_PCM_IOCTL_XRUN _IO('A', 0x48) +#define SNDRV_PCM_IOCTL_FORWARD _IOW('A', 0x49, snd_pcm_uframes_t) +#define SNDRV_PCM_IOCTL_WRITEI_FRAMES _IOW('A', 0x50, struct snd_xferi) +#define SNDRV_PCM_IOCTL_READI_FRAMES _IOR('A', 0x51, struct snd_xferi) +#define SNDRV_PCM_IOCTL_WRITEN_FRAMES _IOW('A', 0x52, struct snd_xfern) +#define SNDRV_PCM_IOCTL_READN_FRAMES _IOR('A', 0x53, struct snd_xfern) +#define SNDRV_PCM_IOCTL_LINK _IOW('A', 0x60, int) +#define SNDRV_PCM_IOCTL_UNLINK _IO('A', 0x61) + +/***************************************************************************** + * * + * MIDI v1.0 interface * + * * + *****************************************************************************/ + +/* + * Raw MIDI section - /dev/snd/midi?? + */ + +#define SNDRV_RAWMIDI_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 4) + +enum { + SNDRV_RAWMIDI_STREAM_OUTPUT = 0, + SNDRV_RAWMIDI_STREAM_INPUT, + SNDRV_RAWMIDI_STREAM_LAST = SNDRV_RAWMIDI_STREAM_INPUT, +}; + +#define SNDRV_RAWMIDI_INFO_OUTPUT 0x00000001 +#define SNDRV_RAWMIDI_INFO_INPUT 0x00000002 +#define SNDRV_RAWMIDI_INFO_DUPLEX 0x00000004 +#define SNDRV_RAWMIDI_INFO_UMP 0x00000008 + +struct snd_rawmidi_info { + unsigned int device; /* RO/WR (control): device number */ + unsigned int subdevice; /* RO/WR (control): subdevice number */ + int stream; /* WR: stream */ + int card; /* R: card number */ + unsigned int flags; /* SNDRV_RAWMIDI_INFO_XXXX */ + unsigned char id[64]; /* ID (user selectable) */ + unsigned char name[80]; /* name of device */ + unsigned char subname[32]; /* name of active or selected subdevice */ + unsigned int subdevices_count; + unsigned int subdevices_avail; + unsigned char reserved[64]; /* reserved for future use */ +}; + +#define SNDRV_RAWMIDI_MODE_FRAMING_MASK (7<<0) +#define SNDRV_RAWMIDI_MODE_FRAMING_SHIFT 0 +#define SNDRV_RAWMIDI_MODE_FRAMING_NONE (0<<0) +#define SNDRV_RAWMIDI_MODE_FRAMING_TSTAMP (1<<0) +#define SNDRV_RAWMIDI_MODE_CLOCK_MASK (7<<3) +#define SNDRV_RAWMIDI_MODE_CLOCK_SHIFT 3 +#define SNDRV_RAWMIDI_MODE_CLOCK_NONE (0<<3) +#define SNDRV_RAWMIDI_MODE_CLOCK_REALTIME (1<<3) +#define SNDRV_RAWMIDI_MODE_CLOCK_MONOTONIC (2<<3) +#define SNDRV_RAWMIDI_MODE_CLOCK_MONOTONIC_RAW (3<<3) + +#define SNDRV_RAWMIDI_FRAMING_DATA_LENGTH 16 + +struct snd_rawmidi_framing_tstamp { + /* For now, frame_type is always 0. Midi 2.0 is expected to add new + * types here. Applications are expected to skip unknown frame types. + */ + __u8 frame_type; + __u8 length; /* number of valid bytes in data field */ + __u8 reserved[2]; + __u32 tv_nsec; /* nanoseconds */ + __u64 tv_sec; /* seconds */ + __u8 data[SNDRV_RAWMIDI_FRAMING_DATA_LENGTH]; +} __packed; + +struct snd_rawmidi_params { + int stream; + size_t buffer_size; /* queue size in bytes */ + size_t avail_min; /* minimum avail bytes for wakeup */ + unsigned int no_active_sensing: 1; /* do not send active sensing byte in close() */ + unsigned int mode; /* For input data only, frame incoming data */ + unsigned char reserved[12]; /* reserved for future use */ +}; + +#ifndef __KERNEL__ +struct snd_rawmidi_status { + int stream; + __time_pad pad1; + struct timespec tstamp; /* Timestamp */ + size_t avail; /* available bytes */ + size_t xruns; /* count of overruns since last status (in bytes) */ + unsigned char reserved[16]; /* reserved for future use */ +}; +#endif + +/* UMP EP info flags */ +#define SNDRV_UMP_EP_INFO_STATIC_BLOCKS 0x01 + +/* UMP EP Protocol / JRTS capability bits */ +#define SNDRV_UMP_EP_INFO_PROTO_MIDI_MASK 0x0300 +#define SNDRV_UMP_EP_INFO_PROTO_MIDI1 0x0100 /* MIDI 1.0 */ +#define SNDRV_UMP_EP_INFO_PROTO_MIDI2 0x0200 /* MIDI 2.0 */ +#define SNDRV_UMP_EP_INFO_PROTO_JRTS_MASK 0x0003 +#define SNDRV_UMP_EP_INFO_PROTO_JRTS_TX 0x0001 /* JRTS Transmit */ +#define SNDRV_UMP_EP_INFO_PROTO_JRTS_RX 0x0002 /* JRTS Receive */ + +/* UMP Endpoint information */ +struct snd_ump_endpoint_info { + int card; /* card number */ + int device; /* device number */ + unsigned int flags; /* additional info */ + unsigned int protocol_caps; /* protocol capabilities */ + unsigned int protocol; /* current protocol */ + unsigned int num_blocks; /* # of function blocks */ + unsigned short version; /* UMP major/minor version */ + unsigned short family_id; /* MIDI device family ID */ + unsigned short model_id; /* MIDI family model ID */ + unsigned int manufacturer_id; /* MIDI manufacturer ID */ + unsigned char sw_revision[4]; /* software revision */ + unsigned short padding; + unsigned char name[128]; /* endpoint name string */ + unsigned char product_id[128]; /* unique product id string */ + unsigned char reserved[32]; +} __packed; + +/* UMP direction */ +#define SNDRV_UMP_DIR_INPUT 0x01 +#define SNDRV_UMP_DIR_OUTPUT 0x02 +#define SNDRV_UMP_DIR_BIDIRECTION 0x03 + +/* UMP block info flags */ +#define SNDRV_UMP_BLOCK_IS_MIDI1 (1U << 0) /* MIDI 1.0 port w/o restrict */ +#define SNDRV_UMP_BLOCK_IS_LOWSPEED (1U << 1) /* 31.25Kbps B/W MIDI1 port */ + +/* UMP block user-interface hint */ +#define SNDRV_UMP_BLOCK_UI_HINT_UNKNOWN 0x00 +#define SNDRV_UMP_BLOCK_UI_HINT_RECEIVER 0x01 +#define SNDRV_UMP_BLOCK_UI_HINT_SENDER 0x02 +#define SNDRV_UMP_BLOCK_UI_HINT_BOTH 0x03 + +/* UMP groups and blocks */ +#define SNDRV_UMP_MAX_GROUPS 16 +#define SNDRV_UMP_MAX_BLOCKS 32 + +/* UMP Block information */ +struct snd_ump_block_info { + int card; /* card number */ + int device; /* device number */ + unsigned char block_id; /* block ID (R/W) */ + unsigned char direction; /* UMP direction */ + unsigned char active; /* Activeness */ + unsigned char first_group; /* first group ID */ + unsigned char num_groups; /* number of groups */ + unsigned char midi_ci_version; /* MIDI-CI support version */ + unsigned char sysex8_streams; /* max number of sysex8 streams */ + unsigned char ui_hint; /* user interface hint */ + unsigned int flags; /* various info flags */ + unsigned char name[128]; /* block name string */ + unsigned char reserved[32]; +} __packed; + +#define SNDRV_RAWMIDI_IOCTL_PVERSION _IOR('W', 0x00, int) +#define SNDRV_RAWMIDI_IOCTL_INFO _IOR('W', 0x01, struct snd_rawmidi_info) +#define SNDRV_RAWMIDI_IOCTL_USER_PVERSION _IOW('W', 0x02, int) +#define SNDRV_RAWMIDI_IOCTL_PARAMS _IOWR('W', 0x10, struct snd_rawmidi_params) +#define SNDRV_RAWMIDI_IOCTL_STATUS _IOWR('W', 0x20, struct snd_rawmidi_status) +#define SNDRV_RAWMIDI_IOCTL_DROP _IOW('W', 0x30, int) +#define SNDRV_RAWMIDI_IOCTL_DRAIN _IOW('W', 0x31, int) +/* Additional ioctls for UMP rawmidi devices */ +#define SNDRV_UMP_IOCTL_ENDPOINT_INFO _IOR('W', 0x40, struct snd_ump_endpoint_info) +#define SNDRV_UMP_IOCTL_BLOCK_INFO _IOR('W', 0x41, struct snd_ump_block_info) + +/* + * Timer section - /dev/snd/timer + */ + +#define SNDRV_TIMER_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 7) + +enum { + SNDRV_TIMER_CLASS_NONE = -1, + SNDRV_TIMER_CLASS_SLAVE = 0, + SNDRV_TIMER_CLASS_GLOBAL, + SNDRV_TIMER_CLASS_CARD, + SNDRV_TIMER_CLASS_PCM, + SNDRV_TIMER_CLASS_LAST = SNDRV_TIMER_CLASS_PCM, +}; + +/* slave timer classes */ +enum { + SNDRV_TIMER_SCLASS_NONE = 0, + SNDRV_TIMER_SCLASS_APPLICATION, + SNDRV_TIMER_SCLASS_SEQUENCER, /* alias */ + SNDRV_TIMER_SCLASS_OSS_SEQUENCER, /* alias */ + SNDRV_TIMER_SCLASS_LAST = SNDRV_TIMER_SCLASS_OSS_SEQUENCER, +}; + +/* global timers (device member) */ +#define SNDRV_TIMER_GLOBAL_SYSTEM 0 +#define SNDRV_TIMER_GLOBAL_RTC 1 /* unused */ +#define SNDRV_TIMER_GLOBAL_HPET 2 +#define SNDRV_TIMER_GLOBAL_HRTIMER 3 + +/* info flags */ +#define SNDRV_TIMER_FLG_SLAVE (1<<0) /* cannot be controlled */ + +struct snd_timer_id { + int dev_class; + int dev_sclass; + int card; + int device; + int subdevice; +}; + +struct snd_timer_ginfo { + struct snd_timer_id tid; /* requested timer ID */ + unsigned int flags; /* timer flags - SNDRV_TIMER_FLG_* */ + int card; /* card number */ + unsigned char id[64]; /* timer identification */ + unsigned char name[80]; /* timer name */ + unsigned long reserved0; /* reserved for future use */ + unsigned long resolution; /* average period resolution in ns */ + unsigned long resolution_min; /* minimal period resolution in ns */ + unsigned long resolution_max; /* maximal period resolution in ns */ + unsigned int clients; /* active timer clients */ + unsigned char reserved[32]; +}; + +struct snd_timer_gparams { + struct snd_timer_id tid; /* requested timer ID */ + unsigned long period_num; /* requested precise period duration (in seconds) - numerator */ + unsigned long period_den; /* requested precise period duration (in seconds) - denominator */ + unsigned char reserved[32]; +}; + +struct snd_timer_gstatus { + struct snd_timer_id tid; /* requested timer ID */ + unsigned long resolution; /* current period resolution in ns */ + unsigned long resolution_num; /* precise current period resolution (in seconds) - numerator */ + unsigned long resolution_den; /* precise current period resolution (in seconds) - denominator */ + unsigned char reserved[32]; +}; + +struct snd_timer_select { + struct snd_timer_id id; /* bind to timer ID */ + unsigned char reserved[32]; /* reserved */ +}; + +struct snd_timer_info { + unsigned int flags; /* timer flags - SNDRV_TIMER_FLG_* */ + int card; /* card number */ + unsigned char id[64]; /* timer identificator */ + unsigned char name[80]; /* timer name */ + unsigned long reserved0; /* reserved for future use */ + unsigned long resolution; /* average period resolution in ns */ + unsigned char reserved[64]; /* reserved */ +}; + +#define SNDRV_TIMER_PSFLG_AUTO (1<<0) /* auto start, otherwise one-shot */ +#define SNDRV_TIMER_PSFLG_EXCLUSIVE (1<<1) /* exclusive use, precise start/stop/pause/continue */ +#define SNDRV_TIMER_PSFLG_EARLY_EVENT (1<<2) /* write early event to the poll queue */ + +struct snd_timer_params { + unsigned int flags; /* flags - SNDRV_TIMER_PSFLG_* */ + unsigned int ticks; /* requested resolution in ticks */ + unsigned int queue_size; /* total size of queue (32-1024) */ + unsigned int reserved0; /* reserved, was: failure locations */ + unsigned int filter; /* event filter (bitmask of SNDRV_TIMER_EVENT_*) */ + unsigned char reserved[60]; /* reserved */ +}; + +#ifndef __KERNEL__ +struct snd_timer_status { + struct timespec tstamp; /* Timestamp - last update */ + unsigned int resolution; /* current period resolution in ns */ + unsigned int lost; /* counter of master tick lost */ + unsigned int overrun; /* count of read queue overruns */ + unsigned int queue; /* used queue size */ + unsigned char reserved[64]; /* reserved */ +}; +#endif + +#define SNDRV_TIMER_IOCTL_PVERSION _IOR('T', 0x00, int) +#define SNDRV_TIMER_IOCTL_NEXT_DEVICE _IOWR('T', 0x01, struct snd_timer_id) +#define SNDRV_TIMER_IOCTL_TREAD_OLD _IOW('T', 0x02, int) +#define SNDRV_TIMER_IOCTL_GINFO _IOWR('T', 0x03, struct snd_timer_ginfo) +#define SNDRV_TIMER_IOCTL_GPARAMS _IOW('T', 0x04, struct snd_timer_gparams) +#define SNDRV_TIMER_IOCTL_GSTATUS _IOWR('T', 0x05, struct snd_timer_gstatus) +#define SNDRV_TIMER_IOCTL_SELECT _IOW('T', 0x10, struct snd_timer_select) +#define SNDRV_TIMER_IOCTL_INFO _IOR('T', 0x11, struct snd_timer_info) +#define SNDRV_TIMER_IOCTL_PARAMS _IOW('T', 0x12, struct snd_timer_params) +#define SNDRV_TIMER_IOCTL_STATUS _IOR('T', 0x14, struct snd_timer_status) +/* The following four ioctls are changed since 1.0.9 due to confliction */ +#define SNDRV_TIMER_IOCTL_START _IO('T', 0xa0) +#define SNDRV_TIMER_IOCTL_STOP _IO('T', 0xa1) +#define SNDRV_TIMER_IOCTL_CONTINUE _IO('T', 0xa2) +#define SNDRV_TIMER_IOCTL_PAUSE _IO('T', 0xa3) +#define SNDRV_TIMER_IOCTL_TREAD64 _IOW('T', 0xa4, int) + +#if __BITS_PER_LONG == 64 +#define SNDRV_TIMER_IOCTL_TREAD SNDRV_TIMER_IOCTL_TREAD_OLD +#else +#define SNDRV_TIMER_IOCTL_TREAD ((sizeof(__kernel_long_t) >= sizeof(time_t)) ? \ + SNDRV_TIMER_IOCTL_TREAD_OLD : \ + SNDRV_TIMER_IOCTL_TREAD64) +#endif + +struct snd_timer_read { + unsigned int resolution; + unsigned int ticks; +}; + +enum { + SNDRV_TIMER_EVENT_RESOLUTION = 0, /* val = resolution in ns */ + SNDRV_TIMER_EVENT_TICK, /* val = ticks */ + SNDRV_TIMER_EVENT_START, /* val = resolution in ns */ + SNDRV_TIMER_EVENT_STOP, /* val = 0 */ + SNDRV_TIMER_EVENT_CONTINUE, /* val = resolution in ns */ + SNDRV_TIMER_EVENT_PAUSE, /* val = 0 */ + SNDRV_TIMER_EVENT_EARLY, /* val = 0, early event */ + SNDRV_TIMER_EVENT_SUSPEND, /* val = 0 */ + SNDRV_TIMER_EVENT_RESUME, /* val = resolution in ns */ + /* master timer events for slave timer instances */ + SNDRV_TIMER_EVENT_MSTART = SNDRV_TIMER_EVENT_START + 10, + SNDRV_TIMER_EVENT_MSTOP = SNDRV_TIMER_EVENT_STOP + 10, + SNDRV_TIMER_EVENT_MCONTINUE = SNDRV_TIMER_EVENT_CONTINUE + 10, + SNDRV_TIMER_EVENT_MPAUSE = SNDRV_TIMER_EVENT_PAUSE + 10, + SNDRV_TIMER_EVENT_MSUSPEND = SNDRV_TIMER_EVENT_SUSPEND + 10, + SNDRV_TIMER_EVENT_MRESUME = SNDRV_TIMER_EVENT_RESUME + 10, +}; + +#ifndef __KERNEL__ +struct snd_timer_tread { + int event; + __time_pad pad1; + struct timespec tstamp; + unsigned int val; + __time_pad pad2; +}; +#endif + +/**************************************************************************** + * * + * Section for driver control interface - /dev/snd/control? * + * * + ****************************************************************************/ + +#define SNDRV_CTL_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 9) + +struct snd_ctl_card_info { + int card; /* card number */ + int pad; /* reserved for future (was type) */ + unsigned char id[16]; /* ID of card (user selectable) */ + unsigned char driver[16]; /* Driver name */ + unsigned char name[32]; /* Short name of soundcard */ + unsigned char longname[80]; /* name + info text about soundcard */ + unsigned char reserved_[16]; /* reserved for future (was ID of mixer) */ + unsigned char mixername[80]; /* visual mixer identification */ + unsigned char components[128]; /* card components / fine identification, delimited with one space (AC97 etc..) */ +}; + +typedef int __bitwise snd_ctl_elem_type_t; +#define SNDRV_CTL_ELEM_TYPE_NONE ((__force snd_ctl_elem_type_t) 0) /* invalid */ +#define SNDRV_CTL_ELEM_TYPE_BOOLEAN ((__force snd_ctl_elem_type_t) 1) /* boolean type */ +#define SNDRV_CTL_ELEM_TYPE_INTEGER ((__force snd_ctl_elem_type_t) 2) /* integer type */ +#define SNDRV_CTL_ELEM_TYPE_ENUMERATED ((__force snd_ctl_elem_type_t) 3) /* enumerated type */ +#define SNDRV_CTL_ELEM_TYPE_BYTES ((__force snd_ctl_elem_type_t) 4) /* byte array */ +#define SNDRV_CTL_ELEM_TYPE_IEC958 ((__force snd_ctl_elem_type_t) 5) /* IEC958 (S/PDIF) setup */ +#define SNDRV_CTL_ELEM_TYPE_INTEGER64 ((__force snd_ctl_elem_type_t) 6) /* 64-bit integer type */ +#define SNDRV_CTL_ELEM_TYPE_LAST SNDRV_CTL_ELEM_TYPE_INTEGER64 + +typedef int __bitwise snd_ctl_elem_iface_t; +#define SNDRV_CTL_ELEM_IFACE_CARD ((__force snd_ctl_elem_iface_t) 0) /* global control */ +#define SNDRV_CTL_ELEM_IFACE_HWDEP ((__force snd_ctl_elem_iface_t) 1) /* hardware dependent device */ +#define SNDRV_CTL_ELEM_IFACE_MIXER ((__force snd_ctl_elem_iface_t) 2) /* virtual mixer device */ +#define SNDRV_CTL_ELEM_IFACE_PCM ((__force snd_ctl_elem_iface_t) 3) /* PCM device */ +#define SNDRV_CTL_ELEM_IFACE_RAWMIDI ((__force snd_ctl_elem_iface_t) 4) /* RawMidi device */ +#define SNDRV_CTL_ELEM_IFACE_TIMER ((__force snd_ctl_elem_iface_t) 5) /* timer device */ +#define SNDRV_CTL_ELEM_IFACE_SEQUENCER ((__force snd_ctl_elem_iface_t) 6) /* sequencer client */ +#define SNDRV_CTL_ELEM_IFACE_LAST SNDRV_CTL_ELEM_IFACE_SEQUENCER + +#define SNDRV_CTL_ELEM_ACCESS_READ (1<<0) +#define SNDRV_CTL_ELEM_ACCESS_WRITE (1<<1) +#define SNDRV_CTL_ELEM_ACCESS_READWRITE (SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE) +#define SNDRV_CTL_ELEM_ACCESS_VOLATILE (1<<2) /* control value may be changed without a notification */ +/* (1 << 3) is unused. */ +#define SNDRV_CTL_ELEM_ACCESS_TLV_READ (1<<4) /* TLV read is possible */ +#define SNDRV_CTL_ELEM_ACCESS_TLV_WRITE (1<<5) /* TLV write is possible */ +#define SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE (SNDRV_CTL_ELEM_ACCESS_TLV_READ|SNDRV_CTL_ELEM_ACCESS_TLV_WRITE) +#define SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND (1<<6) /* TLV command is possible */ +#define SNDRV_CTL_ELEM_ACCESS_INACTIVE (1<<8) /* control does actually nothing, but may be updated */ +#define SNDRV_CTL_ELEM_ACCESS_LOCK (1<<9) /* write lock */ +#define SNDRV_CTL_ELEM_ACCESS_OWNER (1<<10) /* write lock owner */ +#define SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK (1<<28) /* kernel use a TLV callback */ +#define SNDRV_CTL_ELEM_ACCESS_USER (1<<29) /* user space element */ +/* bits 30 and 31 are obsoleted (for indirect access) */ + +/* for further details see the ACPI and PCI power management specification */ +#define SNDRV_CTL_POWER_D0 0x0000 /* full On */ +#define SNDRV_CTL_POWER_D1 0x0100 /* partial On */ +#define SNDRV_CTL_POWER_D2 0x0200 /* partial On */ +#define SNDRV_CTL_POWER_D3 0x0300 /* Off */ +#define SNDRV_CTL_POWER_D3hot (SNDRV_CTL_POWER_D3|0x0000) /* Off, with power */ +#define SNDRV_CTL_POWER_D3cold (SNDRV_CTL_POWER_D3|0x0001) /* Off, without power */ + +#define SNDRV_CTL_ELEM_ID_NAME_MAXLEN 44 + +struct snd_ctl_elem_id { + unsigned int numid; /* numeric identifier, zero = invalid */ + snd_ctl_elem_iface_t iface; /* interface identifier */ + unsigned int device; /* device/client number */ + unsigned int subdevice; /* subdevice (substream) number */ + unsigned char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; /* ASCII name of item */ + unsigned int index; /* index of item */ +}; + +struct snd_ctl_elem_list { + unsigned int offset; /* W: first element ID to get */ + unsigned int space; /* W: count of element IDs to get */ + unsigned int used; /* R: count of element IDs set */ + unsigned int count; /* R: count of all elements */ + struct snd_ctl_elem_id __user *pids; /* R: IDs */ + unsigned char reserved[50]; +}; + +struct snd_ctl_elem_info { + struct snd_ctl_elem_id id; /* W: element ID */ + snd_ctl_elem_type_t type; /* R: value type - SNDRV_CTL_ELEM_TYPE_* */ + unsigned int access; /* R: value access (bitmask) - SNDRV_CTL_ELEM_ACCESS_* */ + unsigned int count; /* count of values */ + __kernel_pid_t owner; /* owner's PID of this control */ + union { + struct { + long min; /* R: minimum value */ + long max; /* R: maximum value */ + long step; /* R: step (0 variable) */ + } integer; + struct { + long long min; /* R: minimum value */ + long long max; /* R: maximum value */ + long long step; /* R: step (0 variable) */ + } integer64; + struct { + unsigned int items; /* R: number of items */ + unsigned int item; /* W: item number */ + char name[64]; /* R: value name */ + __u64 names_ptr; /* W: names list (ELEM_ADD only) */ + unsigned int names_length; + } enumerated; + unsigned char reserved[128]; + } value; + unsigned char reserved[64]; +}; + +struct snd_ctl_elem_value { + struct snd_ctl_elem_id id; /* W: element ID */ + unsigned int indirect: 1; /* W: indirect access - obsoleted */ + union { + union { + long value[128]; + long *value_ptr; /* obsoleted */ + } integer; + union { + long long value[64]; + long long *value_ptr; /* obsoleted */ + } integer64; + union { + unsigned int item[128]; + unsigned int *item_ptr; /* obsoleted */ + } enumerated; + union { + unsigned char data[512]; + unsigned char *data_ptr; /* obsoleted */ + } bytes; + struct snd_aes_iec958 iec958; + } value; /* RO */ + unsigned char reserved[128]; +}; + +struct snd_ctl_tlv { + unsigned int numid; /* control element numeric identification */ + unsigned int length; /* in bytes aligned to 4 */ + unsigned int tlv[]; /* first TLV */ +}; + +#define SNDRV_CTL_IOCTL_PVERSION _IOR('U', 0x00, int) +#define SNDRV_CTL_IOCTL_CARD_INFO _IOR('U', 0x01, struct snd_ctl_card_info) +#define SNDRV_CTL_IOCTL_ELEM_LIST _IOWR('U', 0x10, struct snd_ctl_elem_list) +#define SNDRV_CTL_IOCTL_ELEM_INFO _IOWR('U', 0x11, struct snd_ctl_elem_info) +#define SNDRV_CTL_IOCTL_ELEM_READ _IOWR('U', 0x12, struct snd_ctl_elem_value) +#define SNDRV_CTL_IOCTL_ELEM_WRITE _IOWR('U', 0x13, struct snd_ctl_elem_value) +#define SNDRV_CTL_IOCTL_ELEM_LOCK _IOW('U', 0x14, struct snd_ctl_elem_id) +#define SNDRV_CTL_IOCTL_ELEM_UNLOCK _IOW('U', 0x15, struct snd_ctl_elem_id) +#define SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS _IOWR('U', 0x16, int) +#define SNDRV_CTL_IOCTL_ELEM_ADD _IOWR('U', 0x17, struct snd_ctl_elem_info) +#define SNDRV_CTL_IOCTL_ELEM_REPLACE _IOWR('U', 0x18, struct snd_ctl_elem_info) +#define SNDRV_CTL_IOCTL_ELEM_REMOVE _IOWR('U', 0x19, struct snd_ctl_elem_id) +#define SNDRV_CTL_IOCTL_TLV_READ _IOWR('U', 0x1a, struct snd_ctl_tlv) +#define SNDRV_CTL_IOCTL_TLV_WRITE _IOWR('U', 0x1b, struct snd_ctl_tlv) +#define SNDRV_CTL_IOCTL_TLV_COMMAND _IOWR('U', 0x1c, struct snd_ctl_tlv) +#define SNDRV_CTL_IOCTL_HWDEP_NEXT_DEVICE _IOWR('U', 0x20, int) +#define SNDRV_CTL_IOCTL_HWDEP_INFO _IOR('U', 0x21, struct snd_hwdep_info) +#define SNDRV_CTL_IOCTL_PCM_NEXT_DEVICE _IOR('U', 0x30, int) +#define SNDRV_CTL_IOCTL_PCM_INFO _IOWR('U', 0x31, struct snd_pcm_info) +#define SNDRV_CTL_IOCTL_PCM_PREFER_SUBDEVICE _IOW('U', 0x32, int) +#define SNDRV_CTL_IOCTL_RAWMIDI_NEXT_DEVICE _IOWR('U', 0x40, int) +#define SNDRV_CTL_IOCTL_RAWMIDI_INFO _IOWR('U', 0x41, struct snd_rawmidi_info) +#define SNDRV_CTL_IOCTL_RAWMIDI_PREFER_SUBDEVICE _IOW('U', 0x42, int) +#define SNDRV_CTL_IOCTL_UMP_NEXT_DEVICE _IOWR('U', 0x43, int) +#define SNDRV_CTL_IOCTL_UMP_ENDPOINT_INFO _IOWR('U', 0x44, struct snd_ump_endpoint_info) +#define SNDRV_CTL_IOCTL_UMP_BLOCK_INFO _IOWR('U', 0x45, struct snd_ump_block_info) +#define SNDRV_CTL_IOCTL_POWER _IOWR('U', 0xd0, int) +#define SNDRV_CTL_IOCTL_POWER_STATE _IOR('U', 0xd1, int) + +/* + * Read interface. + */ + +enum sndrv_ctl_event_type { + SNDRV_CTL_EVENT_ELEM = 0, + SNDRV_CTL_EVENT_LAST = SNDRV_CTL_EVENT_ELEM, +}; + +#define SNDRV_CTL_EVENT_MASK_VALUE (1<<0) /* element value was changed */ +#define SNDRV_CTL_EVENT_MASK_INFO (1<<1) /* element info was changed */ +#define SNDRV_CTL_EVENT_MASK_ADD (1<<2) /* element was added */ +#define SNDRV_CTL_EVENT_MASK_TLV (1<<3) /* element TLV tree was changed */ +#define SNDRV_CTL_EVENT_MASK_REMOVE (~0U) /* element was removed */ + +struct snd_ctl_event { + int type; /* event type - SNDRV_CTL_EVENT_* */ + union { + struct { + unsigned int mask; + struct snd_ctl_elem_id id; + } elem; + unsigned char data8[60]; + } data; +}; + +/* + * Control names + */ + +#define SNDRV_CTL_NAME_NONE "" +#define SNDRV_CTL_NAME_PLAYBACK "Playback " +#define SNDRV_CTL_NAME_CAPTURE "Capture " + +#define SNDRV_CTL_NAME_IEC958_NONE "" +#define SNDRV_CTL_NAME_IEC958_SWITCH "Switch" +#define SNDRV_CTL_NAME_IEC958_VOLUME "Volume" +#define SNDRV_CTL_NAME_IEC958_DEFAULT "Default" +#define SNDRV_CTL_NAME_IEC958_MASK "Mask" +#define SNDRV_CTL_NAME_IEC958_CON_MASK "Con Mask" +#define SNDRV_CTL_NAME_IEC958_PRO_MASK "Pro Mask" +#define SNDRV_CTL_NAME_IEC958_PCM_STREAM "PCM Stream" +#define SNDRV_CTL_NAME_IEC958(expl,direction,what) "IEC958 " expl SNDRV_CTL_NAME_##direction SNDRV_CTL_NAME_IEC958_##what + +#endif /* _UAPI__SOUND_ASOUND_H */ diff --git a/tools/perf/trace/beauty/sndrv_ctl_ioctl.sh b/tools/perf/trace/beauty/sndrv_ctl_ioctl.sh index e0803b957593..572939a12884 100755 --- a/tools/perf/trace/beauty/sndrv_ctl_ioctl.sh +++ b/tools/perf/trace/beauty/sndrv_ctl_ioctl.sh @@ -1,9 +1,9 @@ #!/bin/sh # SPDX-License-Identifier: LGPL-2.1 -[ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/sound/ +[ $# -eq 1 ] && beauty_uapi_sound_dir=$1 || beauty_uapi_sound_dir=tools/perf/trace/beauty/include/uapi/sound/ printf "static const char *sndrv_ctl_ioctl_cmds[] = {\n" -grep "^#define[\t ]\+SNDRV_CTL_IOCTL_" $header_dir/asound.h | \ +grep "^#define[\t ]\+SNDRV_CTL_IOCTL_" $beauty_uapi_sound_dir/asound.h | \ sed -r 's/^#define +SNDRV_CTL_IOCTL_([A-Z0-9_]+)[\t ]+_IO[RW]*\( *.U., *(0x[[:xdigit:]]+),?.*/\t[\2] = \"\1\",/g' printf "};\n" diff --git a/tools/perf/trace/beauty/sndrv_pcm_ioctl.sh b/tools/perf/trace/beauty/sndrv_pcm_ioctl.sh index 7a464a7bf913..33afae9a1c07 100755 --- a/tools/perf/trace/beauty/sndrv_pcm_ioctl.sh +++ b/tools/perf/trace/beauty/sndrv_pcm_ioctl.sh @@ -1,9 +1,9 @@ #!/bin/sh # SPDX-License-Identifier: LGPL-2.1 -[ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/sound/ +[ $# -eq 1 ] && beauty_uapi_sound_dir=$1 || beauty_uapi_sound_dir=tools/perf/trace/beauty/include/uapi/sound/ printf "static const char *sndrv_pcm_ioctl_cmds[] = {\n" -grep "^#define[\t ]\+SNDRV_PCM_IOCTL_" $header_dir/asound.h | \ +grep "^#define[\t ]\+SNDRV_PCM_IOCTL_" $beauty_uapi_sound_dir/asound.h | \ sed -r 's/^#define +SNDRV_PCM_IOCTL_([A-Z0-9_]+)[\t ]+_IO[RW]*\( *.A., *(0x[[:xdigit:]]+),?.*/\t[\2] = \"\1\",/g' printf "};\n" -- cgit v1.2.3-59-g8ed1b From c8bfe3fad4f86a029da7157bae9699c816f0c309 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 11 Mar 2024 17:07:33 -0300 Subject: perf beauty: Move arch/x86/include/asm/irq_vectors.h copy out of the directory used to build perf It is used only to generate string tables, not to build perf, so move it to the tools/perf/trace/beauty/include/ hierarchy, that is used just for scraping. This is a something that should've have happened, as happened with the linux/socket.h scrapper, do it now as Ian suggested while doing an audit/refactor session in the headers used by perf. No other tools/ living code uses it. Suggested-by: Ian Rogers Reviewed-by: Ian Rogers Cc: Adrian Hunter Cc: Jiri Olsa Cc: Namhyung Kim Link: https://lore.kernel.org/lkml/CAP-5=fWZVrpRufO4w-S4EcSi9STXcTAN2ERLwTSN7yrSSA-otQ@mail.gmail.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/arch/x86/include/asm/irq_vectors.h | 142 --------------------- tools/perf/Makefile.perf | 6 +- tools/perf/check-headers.sh | 2 +- .../beauty/arch/x86/include/asm/irq_vectors.h | 142 +++++++++++++++++++++ .../trace/beauty/tracepoints/x86_irq_vectors.sh | 6 +- 5 files changed, 150 insertions(+), 148 deletions(-) delete mode 100644 tools/arch/x86/include/asm/irq_vectors.h create mode 100644 tools/perf/trace/beauty/arch/x86/include/asm/irq_vectors.h diff --git a/tools/arch/x86/include/asm/irq_vectors.h b/tools/arch/x86/include/asm/irq_vectors.h deleted file mode 100644 index 3f73ac3ed3a0..000000000000 --- a/tools/arch/x86/include/asm/irq_vectors.h +++ /dev/null @@ -1,142 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _ASM_X86_IRQ_VECTORS_H -#define _ASM_X86_IRQ_VECTORS_H - -#include -/* - * Linux IRQ vector layout. - * - * There are 256 IDT entries (per CPU - each entry is 8 bytes) which can - * be defined by Linux. They are used as a jump table by the CPU when a - * given vector is triggered - by a CPU-external, CPU-internal or - * software-triggered event. - * - * Linux sets the kernel code address each entry jumps to early during - * bootup, and never changes them. This is the general layout of the - * IDT entries: - * - * Vectors 0 ... 31 : system traps and exceptions - hardcoded events - * Vectors 32 ... 127 : device interrupts - * Vector 128 : legacy int80 syscall interface - * Vectors 129 ... LOCAL_TIMER_VECTOR-1 - * Vectors LOCAL_TIMER_VECTOR ... 255 : special interrupts - * - * 64-bit x86 has per CPU IDT tables, 32-bit has one shared IDT table. - * - * This file enumerates the exact layout of them: - */ - -/* This is used as an interrupt vector when programming the APIC. */ -#define NMI_VECTOR 0x02 - -/* - * IDT vectors usable for external interrupt sources start at 0x20. - * (0x80 is the syscall vector, 0x30-0x3f are for ISA) - */ -#define FIRST_EXTERNAL_VECTOR 0x20 - -#define IA32_SYSCALL_VECTOR 0x80 - -/* - * Vectors 0x30-0x3f are used for ISA interrupts. - * round up to the next 16-vector boundary - */ -#define ISA_IRQ_VECTOR(irq) (((FIRST_EXTERNAL_VECTOR + 16) & ~15) + irq) - -/* - * Special IRQ vectors used by the SMP architecture, 0xf0-0xff - * - * some of the following vectors are 'rare', they are merged - * into a single vector (CALL_FUNCTION_VECTOR) to save vector space. - * TLB, reschedule and local APIC vectors are performance-critical. - */ - -#define SPURIOUS_APIC_VECTOR 0xff -/* - * Sanity check - */ -#if ((SPURIOUS_APIC_VECTOR & 0x0F) != 0x0F) -# error SPURIOUS_APIC_VECTOR definition error -#endif - -#define ERROR_APIC_VECTOR 0xfe -#define RESCHEDULE_VECTOR 0xfd -#define CALL_FUNCTION_VECTOR 0xfc -#define CALL_FUNCTION_SINGLE_VECTOR 0xfb -#define THERMAL_APIC_VECTOR 0xfa -#define THRESHOLD_APIC_VECTOR 0xf9 -#define REBOOT_VECTOR 0xf8 - -/* - * Generic system vector for platform specific use - */ -#define X86_PLATFORM_IPI_VECTOR 0xf7 - -/* - * IRQ work vector: - */ -#define IRQ_WORK_VECTOR 0xf6 - -/* 0xf5 - unused, was UV_BAU_MESSAGE */ -#define DEFERRED_ERROR_VECTOR 0xf4 - -/* Vector on which hypervisor callbacks will be delivered */ -#define HYPERVISOR_CALLBACK_VECTOR 0xf3 - -/* Vector for KVM to deliver posted interrupt IPI */ -#if IS_ENABLED(CONFIG_KVM) -#define POSTED_INTR_VECTOR 0xf2 -#define POSTED_INTR_WAKEUP_VECTOR 0xf1 -#define POSTED_INTR_NESTED_VECTOR 0xf0 -#endif - -#define MANAGED_IRQ_SHUTDOWN_VECTOR 0xef - -#if IS_ENABLED(CONFIG_HYPERV) -#define HYPERV_REENLIGHTENMENT_VECTOR 0xee -#define HYPERV_STIMER0_VECTOR 0xed -#endif - -#define LOCAL_TIMER_VECTOR 0xec - -#define NR_VECTORS 256 - -#ifdef CONFIG_X86_LOCAL_APIC -#define FIRST_SYSTEM_VECTOR LOCAL_TIMER_VECTOR -#else -#define FIRST_SYSTEM_VECTOR NR_VECTORS -#endif - -#define NR_EXTERNAL_VECTORS (FIRST_SYSTEM_VECTOR - FIRST_EXTERNAL_VECTOR) -#define NR_SYSTEM_VECTORS (NR_VECTORS - FIRST_SYSTEM_VECTOR) - -/* - * Size the maximum number of interrupts. - * - * If the irq_desc[] array has a sparse layout, we can size things - * generously - it scales up linearly with the maximum number of CPUs, - * and the maximum number of IO-APICs, whichever is higher. - * - * In other cases we size more conservatively, to not create too large - * static arrays. - */ - -#define NR_IRQS_LEGACY 16 - -#define CPU_VECTOR_LIMIT (64 * NR_CPUS) -#define IO_APIC_VECTOR_LIMIT (32 * MAX_IO_APICS) - -#if defined(CONFIG_X86_IO_APIC) && defined(CONFIG_PCI_MSI) -#define NR_IRQS \ - (CPU_VECTOR_LIMIT > IO_APIC_VECTOR_LIMIT ? \ - (NR_VECTORS + CPU_VECTOR_LIMIT) : \ - (NR_VECTORS + IO_APIC_VECTOR_LIMIT)) -#elif defined(CONFIG_X86_IO_APIC) -#define NR_IRQS (NR_VECTORS + IO_APIC_VECTOR_LIMIT) -#elif defined(CONFIG_PCI_MSI) -#define NR_IRQS (NR_VECTORS + CPU_VECTOR_LIMIT) -#else -#define NR_IRQS NR_IRQS_LEGACY -#endif - -#endif /* _ASM_X86_IRQ_VECTORS_H */ diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index 757777d96860..c75342b21089 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -474,6 +474,8 @@ arm64-sysreg-defs-clean: beauty_linux_dir := $(srctree)/tools/perf/trace/beauty/include/linux/ beauty_uapi_linux_dir := $(srctree)/tools/perf/trace/beauty/include/uapi/linux/ beauty_uapi_sound_dir := $(srctree)/tools/perf/trace/beauty/include/uapi/sound/ +beauty_arch_asm_dir := $(srctree)/tools/perf/trace/beauty/arch/x86/include/asm/ + linux_uapi_dir := $(srctree)/tools/include/uapi/linux asm_generic_uapi_dir := $(srctree)/tools/include/uapi/asm-generic arch_asm_uapi_dir := $(srctree)/tools/arch/$(SRCARCH)/include/uapi/asm/ @@ -636,8 +638,8 @@ $(x86_arch_prctl_code_array): $(x86_arch_asm_uapi_dir)/prctl.h $(x86_arch_prctl_ x86_arch_irq_vectors_array := $(beauty_outdir)/x86_arch_irq_vectors_array.c x86_arch_irq_vectors_tbl := $(srctree)/tools/perf/trace/beauty/tracepoints/x86_irq_vectors.sh -$(x86_arch_irq_vectors_array): $(x86_arch_asm_dir)/irq_vectors.h $(x86_arch_irq_vectors_tbl) - $(Q)$(SHELL) '$(x86_arch_irq_vectors_tbl)' $(x86_arch_asm_dir) > $@ +$(x86_arch_irq_vectors_array): $(beauty_arch_asm_dir)/irq_vectors.h $(x86_arch_irq_vectors_tbl) + $(Q)$(SHELL) '$(x86_arch_irq_vectors_tbl)' $(beauty_arch_asm_dir) > $@ x86_arch_MSRs_array := $(beauty_outdir)/x86_arch_MSRs_array.c x86_arch_MSRs_tbl := $(srctree)/tools/perf/trace/beauty/tracepoints/x86_msr.sh diff --git a/tools/perf/check-headers.sh b/tools/perf/check-headers.sh index 93ad7a787a19..b35eba5e99c8 100755 --- a/tools/perf/check-headers.sh +++ b/tools/perf/check-headers.sh @@ -34,7 +34,6 @@ FILES=( "arch/x86/include/asm/cpufeatures.h" "arch/x86/include/asm/inat_types.h" "arch/x86/include/asm/emulate_prefix.h" - "arch/x86/include/asm/irq_vectors.h" "arch/x86/include/asm/msr-index.h" "arch/x86/include/uapi/asm/prctl.h" "arch/x86/lib/x86-opcode-map.txt" @@ -93,6 +92,7 @@ SYNC_CHECK_FILES=( declare -a BEAUTY_FILES BEAUTY_FILES=( + "arch/x86/include/asm/irq_vectors.h" "include/linux/socket.h" "include/uapi/linux/fs.h" "include/uapi/linux/mount.h" diff --git a/tools/perf/trace/beauty/arch/x86/include/asm/irq_vectors.h b/tools/perf/trace/beauty/arch/x86/include/asm/irq_vectors.h new file mode 100644 index 000000000000..3f73ac3ed3a0 --- /dev/null +++ b/tools/perf/trace/beauty/arch/x86/include/asm/irq_vectors.h @@ -0,0 +1,142 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _ASM_X86_IRQ_VECTORS_H +#define _ASM_X86_IRQ_VECTORS_H + +#include +/* + * Linux IRQ vector layout. + * + * There are 256 IDT entries (per CPU - each entry is 8 bytes) which can + * be defined by Linux. They are used as a jump table by the CPU when a + * given vector is triggered - by a CPU-external, CPU-internal or + * software-triggered event. + * + * Linux sets the kernel code address each entry jumps to early during + * bootup, and never changes them. This is the general layout of the + * IDT entries: + * + * Vectors 0 ... 31 : system traps and exceptions - hardcoded events + * Vectors 32 ... 127 : device interrupts + * Vector 128 : legacy int80 syscall interface + * Vectors 129 ... LOCAL_TIMER_VECTOR-1 + * Vectors LOCAL_TIMER_VECTOR ... 255 : special interrupts + * + * 64-bit x86 has per CPU IDT tables, 32-bit has one shared IDT table. + * + * This file enumerates the exact layout of them: + */ + +/* This is used as an interrupt vector when programming the APIC. */ +#define NMI_VECTOR 0x02 + +/* + * IDT vectors usable for external interrupt sources start at 0x20. + * (0x80 is the syscall vector, 0x30-0x3f are for ISA) + */ +#define FIRST_EXTERNAL_VECTOR 0x20 + +#define IA32_SYSCALL_VECTOR 0x80 + +/* + * Vectors 0x30-0x3f are used for ISA interrupts. + * round up to the next 16-vector boundary + */ +#define ISA_IRQ_VECTOR(irq) (((FIRST_EXTERNAL_VECTOR + 16) & ~15) + irq) + +/* + * Special IRQ vectors used by the SMP architecture, 0xf0-0xff + * + * some of the following vectors are 'rare', they are merged + * into a single vector (CALL_FUNCTION_VECTOR) to save vector space. + * TLB, reschedule and local APIC vectors are performance-critical. + */ + +#define SPURIOUS_APIC_VECTOR 0xff +/* + * Sanity check + */ +#if ((SPURIOUS_APIC_VECTOR & 0x0F) != 0x0F) +# error SPURIOUS_APIC_VECTOR definition error +#endif + +#define ERROR_APIC_VECTOR 0xfe +#define RESCHEDULE_VECTOR 0xfd +#define CALL_FUNCTION_VECTOR 0xfc +#define CALL_FUNCTION_SINGLE_VECTOR 0xfb +#define THERMAL_APIC_VECTOR 0xfa +#define THRESHOLD_APIC_VECTOR 0xf9 +#define REBOOT_VECTOR 0xf8 + +/* + * Generic system vector for platform specific use + */ +#define X86_PLATFORM_IPI_VECTOR 0xf7 + +/* + * IRQ work vector: + */ +#define IRQ_WORK_VECTOR 0xf6 + +/* 0xf5 - unused, was UV_BAU_MESSAGE */ +#define DEFERRED_ERROR_VECTOR 0xf4 + +/* Vector on which hypervisor callbacks will be delivered */ +#define HYPERVISOR_CALLBACK_VECTOR 0xf3 + +/* Vector for KVM to deliver posted interrupt IPI */ +#if IS_ENABLED(CONFIG_KVM) +#define POSTED_INTR_VECTOR 0xf2 +#define POSTED_INTR_WAKEUP_VECTOR 0xf1 +#define POSTED_INTR_NESTED_VECTOR 0xf0 +#endif + +#define MANAGED_IRQ_SHUTDOWN_VECTOR 0xef + +#if IS_ENABLED(CONFIG_HYPERV) +#define HYPERV_REENLIGHTENMENT_VECTOR 0xee +#define HYPERV_STIMER0_VECTOR 0xed +#endif + +#define LOCAL_TIMER_VECTOR 0xec + +#define NR_VECTORS 256 + +#ifdef CONFIG_X86_LOCAL_APIC +#define FIRST_SYSTEM_VECTOR LOCAL_TIMER_VECTOR +#else +#define FIRST_SYSTEM_VECTOR NR_VECTORS +#endif + +#define NR_EXTERNAL_VECTORS (FIRST_SYSTEM_VECTOR - FIRST_EXTERNAL_VECTOR) +#define NR_SYSTEM_VECTORS (NR_VECTORS - FIRST_SYSTEM_VECTOR) + +/* + * Size the maximum number of interrupts. + * + * If the irq_desc[] array has a sparse layout, we can size things + * generously - it scales up linearly with the maximum number of CPUs, + * and the maximum number of IO-APICs, whichever is higher. + * + * In other cases we size more conservatively, to not create too large + * static arrays. + */ + +#define NR_IRQS_LEGACY 16 + +#define CPU_VECTOR_LIMIT (64 * NR_CPUS) +#define IO_APIC_VECTOR_LIMIT (32 * MAX_IO_APICS) + +#if defined(CONFIG_X86_IO_APIC) && defined(CONFIG_PCI_MSI) +#define NR_IRQS \ + (CPU_VECTOR_LIMIT > IO_APIC_VECTOR_LIMIT ? \ + (NR_VECTORS + CPU_VECTOR_LIMIT) : \ + (NR_VECTORS + IO_APIC_VECTOR_LIMIT)) +#elif defined(CONFIG_X86_IO_APIC) +#define NR_IRQS (NR_VECTORS + IO_APIC_VECTOR_LIMIT) +#elif defined(CONFIG_PCI_MSI) +#define NR_IRQS (NR_VECTORS + CPU_VECTOR_LIMIT) +#else +#define NR_IRQS NR_IRQS_LEGACY +#endif + +#endif /* _ASM_X86_IRQ_VECTORS_H */ diff --git a/tools/perf/trace/beauty/tracepoints/x86_irq_vectors.sh b/tools/perf/trace/beauty/tracepoints/x86_irq_vectors.sh index 87dc68c7de0c..d8e927dd2bb7 100755 --- a/tools/perf/trace/beauty/tracepoints/x86_irq_vectors.sh +++ b/tools/perf/trace/beauty/tracepoints/x86_irq_vectors.sh @@ -3,12 +3,12 @@ # (C) 2019, Arnaldo Carvalho de Melo if [ $# -ne 1 ] ; then - arch_x86_header_dir=tools/arch/x86/include/asm/ + beauty_arch_asm_dir=tools/perf/trace/beauty/arch/x86/include/asm/ else - arch_x86_header_dir=$1 + beauty_arch_asm_dir=$1 fi -x86_irq_vectors=${arch_x86_header_dir}/irq_vectors.h +x86_irq_vectors=${beauty_arch_asm_dir}/irq_vectors.h # FIRST_EXTERNAL_VECTOR is not that useful, find what is its number # and then replace whatever is using it and that is useful, which at -- cgit v1.2.3-59-g8ed1b From f324b73c2c05832b7c3c1071b87f588b28e45d28 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 14 Mar 2024 17:39:29 -0300 Subject: perf beauty: Stop using the copy of uapi/linux/prctl.h Use the system one, nothing used in that file isn't available in the supported, active distros. Cc: Adrian Hunter Cc: Jiri Olsa Cc: Namhyung Kim To: Ian Rogers Link: https://lore.kernel.org/lkml/20240315204835.748716-3-acme@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/trace/beauty/prctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/trace/beauty/prctl.c b/tools/perf/trace/beauty/prctl.c index 6fe5ad5f5d3a..7d1aa9fd03da 100644 --- a/tools/perf/trace/beauty/prctl.c +++ b/tools/perf/trace/beauty/prctl.c @@ -7,7 +7,7 @@ #include "trace/beauty/beauty.h" #include -#include +#include #include "trace/beauty/generated/prctl_option_array.c" -- cgit v1.2.3-59-g8ed1b From eb01fe7abbe2d0b38824d2a93fdb4cc3eaf2ccc1 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 11 Mar 2024 17:07:33 -0300 Subject: perf beauty: Move prctl.h files (uapi/linux and x86's) copy out of the directory used to build perf It is used only to generate string tables, not to build perf, so move it to the tools/perf/trace/beauty/{include,arch}/ hierarchies, that is used just for scraping. This is a something that should've have happened, as happened with the linux/socket.h scrapper, do it now as Ian suggested while doing an audit/refactor session in the headers used by perf. No other tools/ living code uses it, just coming from either 'make install_headers' or from the system /usr/include/ directory. Suggested-by: Ian Rogers Cc: Adrian Hunter Cc: Jiri Olsa Cc: Namhyung Kim Link: https://lore.kernel.org/lkml/20240315204835.748716-3-acme@kernel.org Link: https://lore.kernel.org/lkml/CAP-5=fWZVrpRufO4w-S4EcSi9STXcTAN2ERLwTSN7yrSSA-otQ@mail.gmail.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/arch/x86/include/uapi/asm/prctl.h | 43 --- tools/include/uapi/linux/prctl.h | 309 --------------------- tools/perf/Makefile.perf | 11 +- tools/perf/check-headers.sh | 4 +- .../trace/beauty/arch/x86/include/uapi/asm/prctl.h | 43 +++ tools/perf/trace/beauty/include/uapi/linux/prctl.h | 309 +++++++++++++++++++++ tools/perf/trace/beauty/prctl_option.sh | 6 +- tools/perf/trace/beauty/x86_arch_prctl.sh | 4 +- 8 files changed, 364 insertions(+), 365 deletions(-) delete mode 100644 tools/arch/x86/include/uapi/asm/prctl.h delete mode 100644 tools/include/uapi/linux/prctl.h create mode 100644 tools/perf/trace/beauty/arch/x86/include/uapi/asm/prctl.h create mode 100644 tools/perf/trace/beauty/include/uapi/linux/prctl.h diff --git a/tools/arch/x86/include/uapi/asm/prctl.h b/tools/arch/x86/include/uapi/asm/prctl.h deleted file mode 100644 index 384e2cc6ac19..000000000000 --- a/tools/arch/x86/include/uapi/asm/prctl.h +++ /dev/null @@ -1,43 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -#ifndef _ASM_X86_PRCTL_H -#define _ASM_X86_PRCTL_H - -#define ARCH_SET_GS 0x1001 -#define ARCH_SET_FS 0x1002 -#define ARCH_GET_FS 0x1003 -#define ARCH_GET_GS 0x1004 - -#define ARCH_GET_CPUID 0x1011 -#define ARCH_SET_CPUID 0x1012 - -#define ARCH_GET_XCOMP_SUPP 0x1021 -#define ARCH_GET_XCOMP_PERM 0x1022 -#define ARCH_REQ_XCOMP_PERM 0x1023 -#define ARCH_GET_XCOMP_GUEST_PERM 0x1024 -#define ARCH_REQ_XCOMP_GUEST_PERM 0x1025 - -#define ARCH_XCOMP_TILECFG 17 -#define ARCH_XCOMP_TILEDATA 18 - -#define ARCH_MAP_VDSO_X32 0x2001 -#define ARCH_MAP_VDSO_32 0x2002 -#define ARCH_MAP_VDSO_64 0x2003 - -/* Don't use 0x3001-0x3004 because of old glibcs */ - -#define ARCH_GET_UNTAG_MASK 0x4001 -#define ARCH_ENABLE_TAGGED_ADDR 0x4002 -#define ARCH_GET_MAX_TAG_BITS 0x4003 -#define ARCH_FORCE_TAGGED_SVA 0x4004 - -#define ARCH_SHSTK_ENABLE 0x5001 -#define ARCH_SHSTK_DISABLE 0x5002 -#define ARCH_SHSTK_LOCK 0x5003 -#define ARCH_SHSTK_UNLOCK 0x5004 -#define ARCH_SHSTK_STATUS 0x5005 - -/* ARCH_SHSTK_ features bits */ -#define ARCH_SHSTK_SHSTK (1ULL << 0) -#define ARCH_SHSTK_WRSS (1ULL << 1) - -#endif /* _ASM_X86_PRCTL_H */ diff --git a/tools/include/uapi/linux/prctl.h b/tools/include/uapi/linux/prctl.h deleted file mode 100644 index 370ed14b1ae0..000000000000 --- a/tools/include/uapi/linux/prctl.h +++ /dev/null @@ -1,309 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -#ifndef _LINUX_PRCTL_H -#define _LINUX_PRCTL_H - -#include - -/* Values to pass as first argument to prctl() */ - -#define PR_SET_PDEATHSIG 1 /* Second arg is a signal */ -#define PR_GET_PDEATHSIG 2 /* Second arg is a ptr to return the signal */ - -/* Get/set current->mm->dumpable */ -#define PR_GET_DUMPABLE 3 -#define PR_SET_DUMPABLE 4 - -/* Get/set unaligned access control bits (if meaningful) */ -#define PR_GET_UNALIGN 5 -#define PR_SET_UNALIGN 6 -# define PR_UNALIGN_NOPRINT 1 /* silently fix up unaligned user accesses */ -# define PR_UNALIGN_SIGBUS 2 /* generate SIGBUS on unaligned user access */ - -/* Get/set whether or not to drop capabilities on setuid() away from - * uid 0 (as per security/commoncap.c) */ -#define PR_GET_KEEPCAPS 7 -#define PR_SET_KEEPCAPS 8 - -/* Get/set floating-point emulation control bits (if meaningful) */ -#define PR_GET_FPEMU 9 -#define PR_SET_FPEMU 10 -# define PR_FPEMU_NOPRINT 1 /* silently emulate fp operations accesses */ -# define PR_FPEMU_SIGFPE 2 /* don't emulate fp operations, send SIGFPE instead */ - -/* Get/set floating-point exception mode (if meaningful) */ -#define PR_GET_FPEXC 11 -#define PR_SET_FPEXC 12 -# define PR_FP_EXC_SW_ENABLE 0x80 /* Use FPEXC for FP exception enables */ -# define PR_FP_EXC_DIV 0x010000 /* floating point divide by zero */ -# define PR_FP_EXC_OVF 0x020000 /* floating point overflow */ -# define PR_FP_EXC_UND 0x040000 /* floating point underflow */ -# define PR_FP_EXC_RES 0x080000 /* floating point inexact result */ -# define PR_FP_EXC_INV 0x100000 /* floating point invalid operation */ -# define PR_FP_EXC_DISABLED 0 /* FP exceptions disabled */ -# define PR_FP_EXC_NONRECOV 1 /* async non-recoverable exc. mode */ -# define PR_FP_EXC_ASYNC 2 /* async recoverable exception mode */ -# define PR_FP_EXC_PRECISE 3 /* precise exception mode */ - -/* Get/set whether we use statistical process timing or accurate timestamp - * based process timing */ -#define PR_GET_TIMING 13 -#define PR_SET_TIMING 14 -# define PR_TIMING_STATISTICAL 0 /* Normal, traditional, - statistical process timing */ -# define PR_TIMING_TIMESTAMP 1 /* Accurate timestamp based - process timing */ - -#define PR_SET_NAME 15 /* Set process name */ -#define PR_GET_NAME 16 /* Get process name */ - -/* Get/set process endian */ -#define PR_GET_ENDIAN 19 -#define PR_SET_ENDIAN 20 -# define PR_ENDIAN_BIG 0 -# define PR_ENDIAN_LITTLE 1 /* True little endian mode */ -# define PR_ENDIAN_PPC_LITTLE 2 /* "PowerPC" pseudo little endian */ - -/* Get/set process seccomp mode */ -#define PR_GET_SECCOMP 21 -#define PR_SET_SECCOMP 22 - -/* Get/set the capability bounding set (as per security/commoncap.c) */ -#define PR_CAPBSET_READ 23 -#define PR_CAPBSET_DROP 24 - -/* Get/set the process' ability to use the timestamp counter instruction */ -#define PR_GET_TSC 25 -#define PR_SET_TSC 26 -# define PR_TSC_ENABLE 1 /* allow the use of the timestamp counter */ -# define PR_TSC_SIGSEGV 2 /* throw a SIGSEGV instead of reading the TSC */ - -/* Get/set securebits (as per security/commoncap.c) */ -#define PR_GET_SECUREBITS 27 -#define PR_SET_SECUREBITS 28 - -/* - * Get/set the timerslack as used by poll/select/nanosleep - * A value of 0 means "use default" - */ -#define PR_SET_TIMERSLACK 29 -#define PR_GET_TIMERSLACK 30 - -#define PR_TASK_PERF_EVENTS_DISABLE 31 -#define PR_TASK_PERF_EVENTS_ENABLE 32 - -/* - * Set early/late kill mode for hwpoison memory corruption. - * This influences when the process gets killed on a memory corruption. - */ -#define PR_MCE_KILL 33 -# define PR_MCE_KILL_CLEAR 0 -# define PR_MCE_KILL_SET 1 - -# define PR_MCE_KILL_LATE 0 -# define PR_MCE_KILL_EARLY 1 -# define PR_MCE_KILL_DEFAULT 2 - -#define PR_MCE_KILL_GET 34 - -/* - * Tune up process memory map specifics. - */ -#define PR_SET_MM 35 -# define PR_SET_MM_START_CODE 1 -# define PR_SET_MM_END_CODE 2 -# define PR_SET_MM_START_DATA 3 -# define PR_SET_MM_END_DATA 4 -# define PR_SET_MM_START_STACK 5 -# define PR_SET_MM_START_BRK 6 -# define PR_SET_MM_BRK 7 -# define PR_SET_MM_ARG_START 8 -# define PR_SET_MM_ARG_END 9 -# define PR_SET_MM_ENV_START 10 -# define PR_SET_MM_ENV_END 11 -# define PR_SET_MM_AUXV 12 -# define PR_SET_MM_EXE_FILE 13 -# define PR_SET_MM_MAP 14 -# define PR_SET_MM_MAP_SIZE 15 - -/* - * This structure provides new memory descriptor - * map which mostly modifies /proc/pid/stat[m] - * output for a task. This mostly done in a - * sake of checkpoint/restore functionality. - */ -struct prctl_mm_map { - __u64 start_code; /* code section bounds */ - __u64 end_code; - __u64 start_data; /* data section bounds */ - __u64 end_data; - __u64 start_brk; /* heap for brk() syscall */ - __u64 brk; - __u64 start_stack; /* stack starts at */ - __u64 arg_start; /* command line arguments bounds */ - __u64 arg_end; - __u64 env_start; /* environment variables bounds */ - __u64 env_end; - __u64 *auxv; /* auxiliary vector */ - __u32 auxv_size; /* vector size */ - __u32 exe_fd; /* /proc/$pid/exe link file */ -}; - -/* - * Set specific pid that is allowed to ptrace the current task. - * A value of 0 mean "no process". - */ -#define PR_SET_PTRACER 0x59616d61 -# define PR_SET_PTRACER_ANY ((unsigned long)-1) - -#define PR_SET_CHILD_SUBREAPER 36 -#define PR_GET_CHILD_SUBREAPER 37 - -/* - * If no_new_privs is set, then operations that grant new privileges (i.e. - * execve) will either fail or not grant them. This affects suid/sgid, - * file capabilities, and LSMs. - * - * Operations that merely manipulate or drop existing privileges (setresuid, - * capset, etc.) will still work. Drop those privileges if you want them gone. - * - * Changing LSM security domain is considered a new privilege. So, for example, - * asking selinux for a specific new context (e.g. with runcon) will result - * in execve returning -EPERM. - * - * See Documentation/userspace-api/no_new_privs.rst for more details. - */ -#define PR_SET_NO_NEW_PRIVS 38 -#define PR_GET_NO_NEW_PRIVS 39 - -#define PR_GET_TID_ADDRESS 40 - -#define PR_SET_THP_DISABLE 41 -#define PR_GET_THP_DISABLE 42 - -/* - * No longer implemented, but left here to ensure the numbers stay reserved: - */ -#define PR_MPX_ENABLE_MANAGEMENT 43 -#define PR_MPX_DISABLE_MANAGEMENT 44 - -#define PR_SET_FP_MODE 45 -#define PR_GET_FP_MODE 46 -# define PR_FP_MODE_FR (1 << 0) /* 64b FP registers */ -# define PR_FP_MODE_FRE (1 << 1) /* 32b compatibility */ - -/* Control the ambient capability set */ -#define PR_CAP_AMBIENT 47 -# define PR_CAP_AMBIENT_IS_SET 1 -# define PR_CAP_AMBIENT_RAISE 2 -# define PR_CAP_AMBIENT_LOWER 3 -# define PR_CAP_AMBIENT_CLEAR_ALL 4 - -/* arm64 Scalable Vector Extension controls */ -/* Flag values must be kept in sync with ptrace NT_ARM_SVE interface */ -#define PR_SVE_SET_VL 50 /* set task vector length */ -# define PR_SVE_SET_VL_ONEXEC (1 << 18) /* defer effect until exec */ -#define PR_SVE_GET_VL 51 /* get task vector length */ -/* Bits common to PR_SVE_SET_VL and PR_SVE_GET_VL */ -# define PR_SVE_VL_LEN_MASK 0xffff -# define PR_SVE_VL_INHERIT (1 << 17) /* inherit across exec */ - -/* Per task speculation control */ -#define PR_GET_SPECULATION_CTRL 52 -#define PR_SET_SPECULATION_CTRL 53 -/* Speculation control variants */ -# define PR_SPEC_STORE_BYPASS 0 -# define PR_SPEC_INDIRECT_BRANCH 1 -# define PR_SPEC_L1D_FLUSH 2 -/* Return and control values for PR_SET/GET_SPECULATION_CTRL */ -# define PR_SPEC_NOT_AFFECTED 0 -# define PR_SPEC_PRCTL (1UL << 0) -# define PR_SPEC_ENABLE (1UL << 1) -# define PR_SPEC_DISABLE (1UL << 2) -# define PR_SPEC_FORCE_DISABLE (1UL << 3) -# define PR_SPEC_DISABLE_NOEXEC (1UL << 4) - -/* Reset arm64 pointer authentication keys */ -#define PR_PAC_RESET_KEYS 54 -# define PR_PAC_APIAKEY (1UL << 0) -# define PR_PAC_APIBKEY (1UL << 1) -# define PR_PAC_APDAKEY (1UL << 2) -# define PR_PAC_APDBKEY (1UL << 3) -# define PR_PAC_APGAKEY (1UL << 4) - -/* Tagged user address controls for arm64 */ -#define PR_SET_TAGGED_ADDR_CTRL 55 -#define PR_GET_TAGGED_ADDR_CTRL 56 -# define PR_TAGGED_ADDR_ENABLE (1UL << 0) -/* MTE tag check fault modes */ -# define PR_MTE_TCF_NONE 0UL -# define PR_MTE_TCF_SYNC (1UL << 1) -# define PR_MTE_TCF_ASYNC (1UL << 2) -# define PR_MTE_TCF_MASK (PR_MTE_TCF_SYNC | PR_MTE_TCF_ASYNC) -/* MTE tag inclusion mask */ -# define PR_MTE_TAG_SHIFT 3 -# define PR_MTE_TAG_MASK (0xffffUL << PR_MTE_TAG_SHIFT) -/* Unused; kept only for source compatibility */ -# define PR_MTE_TCF_SHIFT 1 - -/* Control reclaim behavior when allocating memory */ -#define PR_SET_IO_FLUSHER 57 -#define PR_GET_IO_FLUSHER 58 - -/* Dispatch syscalls to a userspace handler */ -#define PR_SET_SYSCALL_USER_DISPATCH 59 -# define PR_SYS_DISPATCH_OFF 0 -# define PR_SYS_DISPATCH_ON 1 -/* The control values for the user space selector when dispatch is enabled */ -# define SYSCALL_DISPATCH_FILTER_ALLOW 0 -# define SYSCALL_DISPATCH_FILTER_BLOCK 1 - -/* Set/get enabled arm64 pointer authentication keys */ -#define PR_PAC_SET_ENABLED_KEYS 60 -#define PR_PAC_GET_ENABLED_KEYS 61 - -/* Request the scheduler to share a core */ -#define PR_SCHED_CORE 62 -# define PR_SCHED_CORE_GET 0 -# define PR_SCHED_CORE_CREATE 1 /* create unique core_sched cookie */ -# define PR_SCHED_CORE_SHARE_TO 2 /* push core_sched cookie to pid */ -# define PR_SCHED_CORE_SHARE_FROM 3 /* pull core_sched cookie to pid */ -# define PR_SCHED_CORE_MAX 4 -# define PR_SCHED_CORE_SCOPE_THREAD 0 -# define PR_SCHED_CORE_SCOPE_THREAD_GROUP 1 -# define PR_SCHED_CORE_SCOPE_PROCESS_GROUP 2 - -/* arm64 Scalable Matrix Extension controls */ -/* Flag values must be in sync with SVE versions */ -#define PR_SME_SET_VL 63 /* set task vector length */ -# define PR_SME_SET_VL_ONEXEC (1 << 18) /* defer effect until exec */ -#define PR_SME_GET_VL 64 /* get task vector length */ -/* Bits common to PR_SME_SET_VL and PR_SME_GET_VL */ -# define PR_SME_VL_LEN_MASK 0xffff -# define PR_SME_VL_INHERIT (1 << 17) /* inherit across exec */ - -/* Memory deny write / execute */ -#define PR_SET_MDWE 65 -# define PR_MDWE_REFUSE_EXEC_GAIN (1UL << 0) -# define PR_MDWE_NO_INHERIT (1UL << 1) - -#define PR_GET_MDWE 66 - -#define PR_SET_VMA 0x53564d41 -# define PR_SET_VMA_ANON_NAME 0 - -#define PR_GET_AUXV 0x41555856 - -#define PR_SET_MEMORY_MERGE 67 -#define PR_GET_MEMORY_MERGE 68 - -#define PR_RISCV_V_SET_CONTROL 69 -#define PR_RISCV_V_GET_CONTROL 70 -# define PR_RISCV_V_VSTATE_CTRL_DEFAULT 0 -# define PR_RISCV_V_VSTATE_CTRL_OFF 1 -# define PR_RISCV_V_VSTATE_CTRL_ON 2 -# define PR_RISCV_V_VSTATE_CTRL_INHERIT (1 << 4) -# define PR_RISCV_V_VSTATE_CTRL_CUR_MASK 0x3 -# define PR_RISCV_V_VSTATE_CTRL_NEXT_MASK 0xc -# define PR_RISCV_V_VSTATE_CTRL_MASK 0x1f - -#endif /* _LINUX_PRCTL_H */ diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index c75342b21089..b36c0c68c346 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -475,11 +475,11 @@ beauty_linux_dir := $(srctree)/tools/perf/trace/beauty/include/linux/ beauty_uapi_linux_dir := $(srctree)/tools/perf/trace/beauty/include/uapi/linux/ beauty_uapi_sound_dir := $(srctree)/tools/perf/trace/beauty/include/uapi/sound/ beauty_arch_asm_dir := $(srctree)/tools/perf/trace/beauty/arch/x86/include/asm/ +beauty_x86_arch_asm_uapi_dir := $(srctree)/tools/perf/trace/beauty/arch/x86/include/uapi/asm/ linux_uapi_dir := $(srctree)/tools/include/uapi/linux asm_generic_uapi_dir := $(srctree)/tools/include/uapi/asm-generic arch_asm_uapi_dir := $(srctree)/tools/arch/$(SRCARCH)/include/uapi/asm/ -x86_arch_asm_uapi_dir := $(srctree)/tools/arch/x86/include/uapi/asm/ x86_arch_asm_dir := $(srctree)/tools/arch/x86/include/asm/ beauty_outdir := $(OUTPUT)trace/beauty/generated @@ -617,11 +617,10 @@ $(mmap_prot_array): $(asm_generic_uapi_dir)/mman.h $(asm_generic_uapi_dir)/mman- $(Q)$(SHELL) '$(mmap_prot_tbl)' $(asm_generic_uapi_dir) $(arch_asm_uapi_dir) > $@ prctl_option_array := $(beauty_outdir)/prctl_option_array.c -prctl_hdr_dir := $(srctree)/tools/include/uapi/linux/ prctl_option_tbl := $(srctree)/tools/perf/trace/beauty/prctl_option.sh -$(prctl_option_array): $(prctl_hdr_dir)/prctl.h $(prctl_option_tbl) - $(Q)$(SHELL) '$(prctl_option_tbl)' $(prctl_hdr_dir) > $@ +$(prctl_option_array): $(beauty_uapi_linux_dir)/prctl.h $(prctl_option_tbl) + $(Q)$(SHELL) '$(prctl_option_tbl)' $(beauty_uapi_linux_dir) > $@ usbdevfs_ioctl_array := $(beauty_ioctl_outdir)/usbdevfs_ioctl_array.c usbdevfs_ioctl_tbl := $(srctree)/tools/perf/trace/beauty/usbdevfs_ioctl.sh @@ -632,8 +631,8 @@ $(usbdevfs_ioctl_array): $(beauty_uapi_linux_dir)/usbdevice_fs.h $(usbdevfs_ioct x86_arch_prctl_code_array := $(beauty_outdir)/x86_arch_prctl_code_array.c x86_arch_prctl_code_tbl := $(srctree)/tools/perf/trace/beauty/x86_arch_prctl.sh -$(x86_arch_prctl_code_array): $(x86_arch_asm_uapi_dir)/prctl.h $(x86_arch_prctl_code_tbl) - $(Q)$(SHELL) '$(x86_arch_prctl_code_tbl)' $(x86_arch_asm_uapi_dir) > $@ +$(x86_arch_prctl_code_array): $(beauty_x86_arch_asm_uapi_dir)/prctl.h $(x86_arch_prctl_code_tbl) + $(Q)$(SHELL) '$(x86_arch_prctl_code_tbl)' $(beauty_x86_arch_asm_uapi_dir) > $@ x86_arch_irq_vectors_array := $(beauty_outdir)/x86_arch_irq_vectors_array.c x86_arch_irq_vectors_tbl := $(srctree)/tools/perf/trace/beauty/tracepoints/x86_irq_vectors.sh diff --git a/tools/perf/check-headers.sh b/tools/perf/check-headers.sh index b35eba5e99c8..03d00110a48f 100755 --- a/tools/perf/check-headers.sh +++ b/tools/perf/check-headers.sh @@ -17,7 +17,6 @@ FILES=( "include/uapi/linux/in.h" "include/uapi/linux/openat2.h" "include/uapi/linux/perf_event.h" - "include/uapi/linux/prctl.h" "include/uapi/linux/sched.h" "include/uapi/linux/seccomp.h" "include/uapi/linux/stat.h" @@ -35,7 +34,6 @@ FILES=( "arch/x86/include/asm/inat_types.h" "arch/x86/include/asm/emulate_prefix.h" "arch/x86/include/asm/msr-index.h" - "arch/x86/include/uapi/asm/prctl.h" "arch/x86/lib/x86-opcode-map.txt" "arch/x86/tools/gen-insn-attr-x86.awk" "arch/arm/include/uapi/asm/perf_regs.h" @@ -93,9 +91,11 @@ SYNC_CHECK_FILES=( declare -a BEAUTY_FILES BEAUTY_FILES=( "arch/x86/include/asm/irq_vectors.h" + "arch/x86/include/uapi/asm/prctl.h" "include/linux/socket.h" "include/uapi/linux/fs.h" "include/uapi/linux/mount.h" + "include/uapi/linux/prctl.h" "include/uapi/linux/usbdevice_fs.h" "include/uapi/sound/asound.h" ) diff --git a/tools/perf/trace/beauty/arch/x86/include/uapi/asm/prctl.h b/tools/perf/trace/beauty/arch/x86/include/uapi/asm/prctl.h new file mode 100644 index 000000000000..384e2cc6ac19 --- /dev/null +++ b/tools/perf/trace/beauty/arch/x86/include/uapi/asm/prctl.h @@ -0,0 +1,43 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _ASM_X86_PRCTL_H +#define _ASM_X86_PRCTL_H + +#define ARCH_SET_GS 0x1001 +#define ARCH_SET_FS 0x1002 +#define ARCH_GET_FS 0x1003 +#define ARCH_GET_GS 0x1004 + +#define ARCH_GET_CPUID 0x1011 +#define ARCH_SET_CPUID 0x1012 + +#define ARCH_GET_XCOMP_SUPP 0x1021 +#define ARCH_GET_XCOMP_PERM 0x1022 +#define ARCH_REQ_XCOMP_PERM 0x1023 +#define ARCH_GET_XCOMP_GUEST_PERM 0x1024 +#define ARCH_REQ_XCOMP_GUEST_PERM 0x1025 + +#define ARCH_XCOMP_TILECFG 17 +#define ARCH_XCOMP_TILEDATA 18 + +#define ARCH_MAP_VDSO_X32 0x2001 +#define ARCH_MAP_VDSO_32 0x2002 +#define ARCH_MAP_VDSO_64 0x2003 + +/* Don't use 0x3001-0x3004 because of old glibcs */ + +#define ARCH_GET_UNTAG_MASK 0x4001 +#define ARCH_ENABLE_TAGGED_ADDR 0x4002 +#define ARCH_GET_MAX_TAG_BITS 0x4003 +#define ARCH_FORCE_TAGGED_SVA 0x4004 + +#define ARCH_SHSTK_ENABLE 0x5001 +#define ARCH_SHSTK_DISABLE 0x5002 +#define ARCH_SHSTK_LOCK 0x5003 +#define ARCH_SHSTK_UNLOCK 0x5004 +#define ARCH_SHSTK_STATUS 0x5005 + +/* ARCH_SHSTK_ features bits */ +#define ARCH_SHSTK_SHSTK (1ULL << 0) +#define ARCH_SHSTK_WRSS (1ULL << 1) + +#endif /* _ASM_X86_PRCTL_H */ diff --git a/tools/perf/trace/beauty/include/uapi/linux/prctl.h b/tools/perf/trace/beauty/include/uapi/linux/prctl.h new file mode 100644 index 000000000000..370ed14b1ae0 --- /dev/null +++ b/tools/perf/trace/beauty/include/uapi/linux/prctl.h @@ -0,0 +1,309 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _LINUX_PRCTL_H +#define _LINUX_PRCTL_H + +#include + +/* Values to pass as first argument to prctl() */ + +#define PR_SET_PDEATHSIG 1 /* Second arg is a signal */ +#define PR_GET_PDEATHSIG 2 /* Second arg is a ptr to return the signal */ + +/* Get/set current->mm->dumpable */ +#define PR_GET_DUMPABLE 3 +#define PR_SET_DUMPABLE 4 + +/* Get/set unaligned access control bits (if meaningful) */ +#define PR_GET_UNALIGN 5 +#define PR_SET_UNALIGN 6 +# define PR_UNALIGN_NOPRINT 1 /* silently fix up unaligned user accesses */ +# define PR_UNALIGN_SIGBUS 2 /* generate SIGBUS on unaligned user access */ + +/* Get/set whether or not to drop capabilities on setuid() away from + * uid 0 (as per security/commoncap.c) */ +#define PR_GET_KEEPCAPS 7 +#define PR_SET_KEEPCAPS 8 + +/* Get/set floating-point emulation control bits (if meaningful) */ +#define PR_GET_FPEMU 9 +#define PR_SET_FPEMU 10 +# define PR_FPEMU_NOPRINT 1 /* silently emulate fp operations accesses */ +# define PR_FPEMU_SIGFPE 2 /* don't emulate fp operations, send SIGFPE instead */ + +/* Get/set floating-point exception mode (if meaningful) */ +#define PR_GET_FPEXC 11 +#define PR_SET_FPEXC 12 +# define PR_FP_EXC_SW_ENABLE 0x80 /* Use FPEXC for FP exception enables */ +# define PR_FP_EXC_DIV 0x010000 /* floating point divide by zero */ +# define PR_FP_EXC_OVF 0x020000 /* floating point overflow */ +# define PR_FP_EXC_UND 0x040000 /* floating point underflow */ +# define PR_FP_EXC_RES 0x080000 /* floating point inexact result */ +# define PR_FP_EXC_INV 0x100000 /* floating point invalid operation */ +# define PR_FP_EXC_DISABLED 0 /* FP exceptions disabled */ +# define PR_FP_EXC_NONRECOV 1 /* async non-recoverable exc. mode */ +# define PR_FP_EXC_ASYNC 2 /* async recoverable exception mode */ +# define PR_FP_EXC_PRECISE 3 /* precise exception mode */ + +/* Get/set whether we use statistical process timing or accurate timestamp + * based process timing */ +#define PR_GET_TIMING 13 +#define PR_SET_TIMING 14 +# define PR_TIMING_STATISTICAL 0 /* Normal, traditional, + statistical process timing */ +# define PR_TIMING_TIMESTAMP 1 /* Accurate timestamp based + process timing */ + +#define PR_SET_NAME 15 /* Set process name */ +#define PR_GET_NAME 16 /* Get process name */ + +/* Get/set process endian */ +#define PR_GET_ENDIAN 19 +#define PR_SET_ENDIAN 20 +# define PR_ENDIAN_BIG 0 +# define PR_ENDIAN_LITTLE 1 /* True little endian mode */ +# define PR_ENDIAN_PPC_LITTLE 2 /* "PowerPC" pseudo little endian */ + +/* Get/set process seccomp mode */ +#define PR_GET_SECCOMP 21 +#define PR_SET_SECCOMP 22 + +/* Get/set the capability bounding set (as per security/commoncap.c) */ +#define PR_CAPBSET_READ 23 +#define PR_CAPBSET_DROP 24 + +/* Get/set the process' ability to use the timestamp counter instruction */ +#define PR_GET_TSC 25 +#define PR_SET_TSC 26 +# define PR_TSC_ENABLE 1 /* allow the use of the timestamp counter */ +# define PR_TSC_SIGSEGV 2 /* throw a SIGSEGV instead of reading the TSC */ + +/* Get/set securebits (as per security/commoncap.c) */ +#define PR_GET_SECUREBITS 27 +#define PR_SET_SECUREBITS 28 + +/* + * Get/set the timerslack as used by poll/select/nanosleep + * A value of 0 means "use default" + */ +#define PR_SET_TIMERSLACK 29 +#define PR_GET_TIMERSLACK 30 + +#define PR_TASK_PERF_EVENTS_DISABLE 31 +#define PR_TASK_PERF_EVENTS_ENABLE 32 + +/* + * Set early/late kill mode for hwpoison memory corruption. + * This influences when the process gets killed on a memory corruption. + */ +#define PR_MCE_KILL 33 +# define PR_MCE_KILL_CLEAR 0 +# define PR_MCE_KILL_SET 1 + +# define PR_MCE_KILL_LATE 0 +# define PR_MCE_KILL_EARLY 1 +# define PR_MCE_KILL_DEFAULT 2 + +#define PR_MCE_KILL_GET 34 + +/* + * Tune up process memory map specifics. + */ +#define PR_SET_MM 35 +# define PR_SET_MM_START_CODE 1 +# define PR_SET_MM_END_CODE 2 +# define PR_SET_MM_START_DATA 3 +# define PR_SET_MM_END_DATA 4 +# define PR_SET_MM_START_STACK 5 +# define PR_SET_MM_START_BRK 6 +# define PR_SET_MM_BRK 7 +# define PR_SET_MM_ARG_START 8 +# define PR_SET_MM_ARG_END 9 +# define PR_SET_MM_ENV_START 10 +# define PR_SET_MM_ENV_END 11 +# define PR_SET_MM_AUXV 12 +# define PR_SET_MM_EXE_FILE 13 +# define PR_SET_MM_MAP 14 +# define PR_SET_MM_MAP_SIZE 15 + +/* + * This structure provides new memory descriptor + * map which mostly modifies /proc/pid/stat[m] + * output for a task. This mostly done in a + * sake of checkpoint/restore functionality. + */ +struct prctl_mm_map { + __u64 start_code; /* code section bounds */ + __u64 end_code; + __u64 start_data; /* data section bounds */ + __u64 end_data; + __u64 start_brk; /* heap for brk() syscall */ + __u64 brk; + __u64 start_stack; /* stack starts at */ + __u64 arg_start; /* command line arguments bounds */ + __u64 arg_end; + __u64 env_start; /* environment variables bounds */ + __u64 env_end; + __u64 *auxv; /* auxiliary vector */ + __u32 auxv_size; /* vector size */ + __u32 exe_fd; /* /proc/$pid/exe link file */ +}; + +/* + * Set specific pid that is allowed to ptrace the current task. + * A value of 0 mean "no process". + */ +#define PR_SET_PTRACER 0x59616d61 +# define PR_SET_PTRACER_ANY ((unsigned long)-1) + +#define PR_SET_CHILD_SUBREAPER 36 +#define PR_GET_CHILD_SUBREAPER 37 + +/* + * If no_new_privs is set, then operations that grant new privileges (i.e. + * execve) will either fail or not grant them. This affects suid/sgid, + * file capabilities, and LSMs. + * + * Operations that merely manipulate or drop existing privileges (setresuid, + * capset, etc.) will still work. Drop those privileges if you want them gone. + * + * Changing LSM security domain is considered a new privilege. So, for example, + * asking selinux for a specific new context (e.g. with runcon) will result + * in execve returning -EPERM. + * + * See Documentation/userspace-api/no_new_privs.rst for more details. + */ +#define PR_SET_NO_NEW_PRIVS 38 +#define PR_GET_NO_NEW_PRIVS 39 + +#define PR_GET_TID_ADDRESS 40 + +#define PR_SET_THP_DISABLE 41 +#define PR_GET_THP_DISABLE 42 + +/* + * No longer implemented, but left here to ensure the numbers stay reserved: + */ +#define PR_MPX_ENABLE_MANAGEMENT 43 +#define PR_MPX_DISABLE_MANAGEMENT 44 + +#define PR_SET_FP_MODE 45 +#define PR_GET_FP_MODE 46 +# define PR_FP_MODE_FR (1 << 0) /* 64b FP registers */ +# define PR_FP_MODE_FRE (1 << 1) /* 32b compatibility */ + +/* Control the ambient capability set */ +#define PR_CAP_AMBIENT 47 +# define PR_CAP_AMBIENT_IS_SET 1 +# define PR_CAP_AMBIENT_RAISE 2 +# define PR_CAP_AMBIENT_LOWER 3 +# define PR_CAP_AMBIENT_CLEAR_ALL 4 + +/* arm64 Scalable Vector Extension controls */ +/* Flag values must be kept in sync with ptrace NT_ARM_SVE interface */ +#define PR_SVE_SET_VL 50 /* set task vector length */ +# define PR_SVE_SET_VL_ONEXEC (1 << 18) /* defer effect until exec */ +#define PR_SVE_GET_VL 51 /* get task vector length */ +/* Bits common to PR_SVE_SET_VL and PR_SVE_GET_VL */ +# define PR_SVE_VL_LEN_MASK 0xffff +# define PR_SVE_VL_INHERIT (1 << 17) /* inherit across exec */ + +/* Per task speculation control */ +#define PR_GET_SPECULATION_CTRL 52 +#define PR_SET_SPECULATION_CTRL 53 +/* Speculation control variants */ +# define PR_SPEC_STORE_BYPASS 0 +# define PR_SPEC_INDIRECT_BRANCH 1 +# define PR_SPEC_L1D_FLUSH 2 +/* Return and control values for PR_SET/GET_SPECULATION_CTRL */ +# define PR_SPEC_NOT_AFFECTED 0 +# define PR_SPEC_PRCTL (1UL << 0) +# define PR_SPEC_ENABLE (1UL << 1) +# define PR_SPEC_DISABLE (1UL << 2) +# define PR_SPEC_FORCE_DISABLE (1UL << 3) +# define PR_SPEC_DISABLE_NOEXEC (1UL << 4) + +/* Reset arm64 pointer authentication keys */ +#define PR_PAC_RESET_KEYS 54 +# define PR_PAC_APIAKEY (1UL << 0) +# define PR_PAC_APIBKEY (1UL << 1) +# define PR_PAC_APDAKEY (1UL << 2) +# define PR_PAC_APDBKEY (1UL << 3) +# define PR_PAC_APGAKEY (1UL << 4) + +/* Tagged user address controls for arm64 */ +#define PR_SET_TAGGED_ADDR_CTRL 55 +#define PR_GET_TAGGED_ADDR_CTRL 56 +# define PR_TAGGED_ADDR_ENABLE (1UL << 0) +/* MTE tag check fault modes */ +# define PR_MTE_TCF_NONE 0UL +# define PR_MTE_TCF_SYNC (1UL << 1) +# define PR_MTE_TCF_ASYNC (1UL << 2) +# define PR_MTE_TCF_MASK (PR_MTE_TCF_SYNC | PR_MTE_TCF_ASYNC) +/* MTE tag inclusion mask */ +# define PR_MTE_TAG_SHIFT 3 +# define PR_MTE_TAG_MASK (0xffffUL << PR_MTE_TAG_SHIFT) +/* Unused; kept only for source compatibility */ +# define PR_MTE_TCF_SHIFT 1 + +/* Control reclaim behavior when allocating memory */ +#define PR_SET_IO_FLUSHER 57 +#define PR_GET_IO_FLUSHER 58 + +/* Dispatch syscalls to a userspace handler */ +#define PR_SET_SYSCALL_USER_DISPATCH 59 +# define PR_SYS_DISPATCH_OFF 0 +# define PR_SYS_DISPATCH_ON 1 +/* The control values for the user space selector when dispatch is enabled */ +# define SYSCALL_DISPATCH_FILTER_ALLOW 0 +# define SYSCALL_DISPATCH_FILTER_BLOCK 1 + +/* Set/get enabled arm64 pointer authentication keys */ +#define PR_PAC_SET_ENABLED_KEYS 60 +#define PR_PAC_GET_ENABLED_KEYS 61 + +/* Request the scheduler to share a core */ +#define PR_SCHED_CORE 62 +# define PR_SCHED_CORE_GET 0 +# define PR_SCHED_CORE_CREATE 1 /* create unique core_sched cookie */ +# define PR_SCHED_CORE_SHARE_TO 2 /* push core_sched cookie to pid */ +# define PR_SCHED_CORE_SHARE_FROM 3 /* pull core_sched cookie to pid */ +# define PR_SCHED_CORE_MAX 4 +# define PR_SCHED_CORE_SCOPE_THREAD 0 +# define PR_SCHED_CORE_SCOPE_THREAD_GROUP 1 +# define PR_SCHED_CORE_SCOPE_PROCESS_GROUP 2 + +/* arm64 Scalable Matrix Extension controls */ +/* Flag values must be in sync with SVE versions */ +#define PR_SME_SET_VL 63 /* set task vector length */ +# define PR_SME_SET_VL_ONEXEC (1 << 18) /* defer effect until exec */ +#define PR_SME_GET_VL 64 /* get task vector length */ +/* Bits common to PR_SME_SET_VL and PR_SME_GET_VL */ +# define PR_SME_VL_LEN_MASK 0xffff +# define PR_SME_VL_INHERIT (1 << 17) /* inherit across exec */ + +/* Memory deny write / execute */ +#define PR_SET_MDWE 65 +# define PR_MDWE_REFUSE_EXEC_GAIN (1UL << 0) +# define PR_MDWE_NO_INHERIT (1UL << 1) + +#define PR_GET_MDWE 66 + +#define PR_SET_VMA 0x53564d41 +# define PR_SET_VMA_ANON_NAME 0 + +#define PR_GET_AUXV 0x41555856 + +#define PR_SET_MEMORY_MERGE 67 +#define PR_GET_MEMORY_MERGE 68 + +#define PR_RISCV_V_SET_CONTROL 69 +#define PR_RISCV_V_GET_CONTROL 70 +# define PR_RISCV_V_VSTATE_CTRL_DEFAULT 0 +# define PR_RISCV_V_VSTATE_CTRL_OFF 1 +# define PR_RISCV_V_VSTATE_CTRL_ON 2 +# define PR_RISCV_V_VSTATE_CTRL_INHERIT (1 << 4) +# define PR_RISCV_V_VSTATE_CTRL_CUR_MASK 0x3 +# define PR_RISCV_V_VSTATE_CTRL_NEXT_MASK 0xc +# define PR_RISCV_V_VSTATE_CTRL_MASK 0x1f + +#endif /* _LINUX_PRCTL_H */ diff --git a/tools/perf/trace/beauty/prctl_option.sh b/tools/perf/trace/beauty/prctl_option.sh index 9455d9672f14..e049f5e9c011 100755 --- a/tools/perf/trace/beauty/prctl_option.sh +++ b/tools/perf/trace/beauty/prctl_option.sh @@ -1,18 +1,18 @@ #!/bin/sh # SPDX-License-Identifier: LGPL-2.1 -[ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/linux/ +[ $# -eq 1 ] && beauty_uapi_linux_dir=$1 || beauty_uapi_linux_dir=tools/perf/trace/beauty/include/uapi/linux/ printf "static const char *prctl_options[] = {\n" regex='^#define[[:space:]]{1}PR_(\w+)[[:space:]]*([[:xdigit:]]+)([[:space:]]*/.*)?$' -grep -E $regex ${header_dir}/prctl.h | grep -v PR_SET_PTRACER | \ +grep -E $regex ${beauty_uapi_linux_dir}/prctl.h | grep -v PR_SET_PTRACER | \ sed -E "s%$regex%\2 \1%g" | \ sort -n | xargs printf "\t[%s] = \"%s\",\n" printf "};\n" printf "static const char *prctl_set_mm_options[] = {\n" regex='^#[[:space:]]+define[[:space:]]+PR_SET_MM_(\w+)[[:space:]]*([[:digit:]]+).*' -grep -E $regex ${header_dir}/prctl.h | \ +grep -E $regex ${beauty_uapi_linux_dir}/prctl.h | \ sed -r "s/$regex/\2 \1/g" | \ sort -n | xargs printf "\t[%s] = \"%s\",\n" printf "};\n" diff --git a/tools/perf/trace/beauty/x86_arch_prctl.sh b/tools/perf/trace/beauty/x86_arch_prctl.sh index b1596df251f0..b714ffa3cb7a 100755 --- a/tools/perf/trace/beauty/x86_arch_prctl.sh +++ b/tools/perf/trace/beauty/x86_arch_prctl.sh @@ -2,9 +2,9 @@ # Copyright (C) 2018, Red Hat Inc, Arnaldo Carvalho de Melo # SPDX-License-Identifier: LGPL-2.1 -[ $# -eq 1 ] && x86_header_dir=$1 || x86_header_dir=tools/arch/x86/include/uapi/asm/ +[ $# -eq 1 ] && beauty_x86_arch_asm_uapi_dir=$1 || beauty_x86_arch_asm_uapi_dir=tools/perf/trace/beauty/arch/x86/include/uapi/asm/ -prctl_arch_header=${x86_header_dir}/prctl.h +prctl_arch_header=${beauty_x86_arch_asm_uapi_dir}/prctl.h print_range () { idx=$1 -- cgit v1.2.3-59-g8ed1b From 6652830c87be8446a0e9b47f83af8990fee2f274 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 15 Mar 2024 16:06:01 -0300 Subject: perf beauty: Use the system linux/fcntl.h instead of a copy from the kernel Builds ok all the way back to these older distros: 1 almalinux:8 : Ok gcc (GCC) 8.5.0 20210514 (Red Hat 8.5.0-20) , clang version 16.0.6 (Red Hat 16.0.6-2.module_el8.9.0+3621+df7f7146) flex 2.6.1 3 alpine:3.15 : Ok gcc (Alpine 10.3.1_git20211027) 10.3.1 20211027 , Alpine clang version 12.0.1 flex 2.6.4 15 debian:10 : Ok gcc (Debian 8.3.0-6) 8.3.0 , Debian clang version 11.0.1-2~deb10u1 flex 2.6.4 32 opensuse:15.4 : Ok gcc (SUSE Linux) 7.5.0 , clang version 15.0.7 flex 2.6.4 23 fedora:35 : Ok gcc (GCC) 11.3.1 20220421 (Red Hat 11.3.1-3) , clang version 13.0.1 (Fedora 13.0.1-1.fc35) flex 2.6.4 38 ubuntu:18.04 : Ok gcc (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0 flex 2.6.4 Cc: Adrian Hunter Cc: Ian Rogers Cc: Jiri Olsa Cc: Namhyung Kim Link: https://lore.kernel.org/lkml/20240315204835.748716-4-acme@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/trace/beauty/fcntl.c | 2 +- tools/perf/trace/beauty/flock.c | 2 +- tools/perf/trace/beauty/statx.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/perf/trace/beauty/fcntl.c b/tools/perf/trace/beauty/fcntl.c index 56ef83b3d130..d075904dccce 100644 --- a/tools/perf/trace/beauty/fcntl.c +++ b/tools/perf/trace/beauty/fcntl.c @@ -7,7 +7,7 @@ #include "trace/beauty/beauty.h" #include -#include +#include static size_t fcntl__scnprintf_getfd(unsigned long val, char *bf, size_t size, bool show_prefix) { diff --git a/tools/perf/trace/beauty/flock.c b/tools/perf/trace/beauty/flock.c index c14274edd6d9..a6514a6f07cf 100644 --- a/tools/perf/trace/beauty/flock.c +++ b/tools/perf/trace/beauty/flock.c @@ -2,7 +2,7 @@ #include "trace/beauty/beauty.h" #include -#include +#include #ifndef LOCK_MAND #define LOCK_MAND 32 diff --git a/tools/perf/trace/beauty/statx.c b/tools/perf/trace/beauty/statx.c index dc5943a6352d..d1ccc93316bd 100644 --- a/tools/perf/trace/beauty/statx.c +++ b/tools/perf/trace/beauty/statx.c @@ -8,7 +8,7 @@ #include "trace/beauty/beauty.h" #include #include -#include +#include #include size_t syscall_arg__scnprintf_statx_flags(char *bf, size_t size, struct syscall_arg *arg) -- cgit v1.2.3-59-g8ed1b From 8a1ad4413519b10fbe5e73300b198498a0b28806 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 15 Mar 2024 16:18:14 -0300 Subject: tools headers: Remove now unused copies of uapi/{fcntl,openat2}.h and asm/fcntl.h These were used to build perf to provide defines not available in older distros, but this was back in 2017, nowadays all the distros that are supported and I have build containers for work using just the system headers, so ditch them. Some of these older distros may not have things that are used in 'perf trace', but then they also don't have libtraceevent packages, so don't build 'perf trace'. Cc: Adrian Hunter Cc: Ian Rogers Cc: Jiri Olsa Cc: Namhyung Kim Link: https://lore.kernel.org/lkml/20240315204835.748716-5-acme@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/include/uapi/asm-generic/fcntl.h | 221 --------------------------------- tools/include/uapi/linux/fcntl.h | 123 ------------------ tools/include/uapi/linux/openat2.h | 43 ------- tools/perf/check-headers.sh | 2 - 4 files changed, 389 deletions(-) delete mode 100644 tools/include/uapi/asm-generic/fcntl.h delete mode 100644 tools/include/uapi/linux/fcntl.h delete mode 100644 tools/include/uapi/linux/openat2.h diff --git a/tools/include/uapi/asm-generic/fcntl.h b/tools/include/uapi/asm-generic/fcntl.h deleted file mode 100644 index 1c7a0f6632c0..000000000000 --- a/tools/include/uapi/asm-generic/fcntl.h +++ /dev/null @@ -1,221 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -#ifndef _ASM_GENERIC_FCNTL_H -#define _ASM_GENERIC_FCNTL_H - -#include - -/* - * FMODE_EXEC is 0x20 - * FMODE_NONOTIFY is 0x4000000 - * These cannot be used by userspace O_* until internal and external open - * flags are split. - * -Eric Paris - */ - -/* - * When introducing new O_* bits, please check its uniqueness in fcntl_init(). - */ - -#define O_ACCMODE 00000003 -#define O_RDONLY 00000000 -#define O_WRONLY 00000001 -#define O_RDWR 00000002 -#ifndef O_CREAT -#define O_CREAT 00000100 /* not fcntl */ -#endif -#ifndef O_EXCL -#define O_EXCL 00000200 /* not fcntl */ -#endif -#ifndef O_NOCTTY -#define O_NOCTTY 00000400 /* not fcntl */ -#endif -#ifndef O_TRUNC -#define O_TRUNC 00001000 /* not fcntl */ -#endif -#ifndef O_APPEND -#define O_APPEND 00002000 -#endif -#ifndef O_NONBLOCK -#define O_NONBLOCK 00004000 -#endif -#ifndef O_DSYNC -#define O_DSYNC 00010000 /* used to be O_SYNC, see below */ -#endif -#ifndef FASYNC -#define FASYNC 00020000 /* fcntl, for BSD compatibility */ -#endif -#ifndef O_DIRECT -#define O_DIRECT 00040000 /* direct disk access hint */ -#endif -#ifndef O_LARGEFILE -#define O_LARGEFILE 00100000 -#endif -#ifndef O_DIRECTORY -#define O_DIRECTORY 00200000 /* must be a directory */ -#endif -#ifndef O_NOFOLLOW -#define O_NOFOLLOW 00400000 /* don't follow links */ -#endif -#ifndef O_NOATIME -#define O_NOATIME 01000000 -#endif -#ifndef O_CLOEXEC -#define O_CLOEXEC 02000000 /* set close_on_exec */ -#endif - -/* - * Before Linux 2.6.33 only O_DSYNC semantics were implemented, but using - * the O_SYNC flag. We continue to use the existing numerical value - * for O_DSYNC semantics now, but using the correct symbolic name for it. - * This new value is used to request true Posix O_SYNC semantics. It is - * defined in this strange way to make sure applications compiled against - * new headers get at least O_DSYNC semantics on older kernels. - * - * This has the nice side-effect that we can simply test for O_DSYNC - * wherever we do not care if O_DSYNC or O_SYNC is used. - * - * Note: __O_SYNC must never be used directly. - */ -#ifndef O_SYNC -#define __O_SYNC 04000000 -#define O_SYNC (__O_SYNC|O_DSYNC) -#endif - -#ifndef O_PATH -#define O_PATH 010000000 -#endif - -#ifndef __O_TMPFILE -#define __O_TMPFILE 020000000 -#endif - -/* a horrid kludge trying to make sure that this will fail on old kernels */ -#define O_TMPFILE (__O_TMPFILE | O_DIRECTORY) - -#ifndef O_NDELAY -#define O_NDELAY O_NONBLOCK -#endif - -#define F_DUPFD 0 /* dup */ -#define F_GETFD 1 /* get close_on_exec */ -#define F_SETFD 2 /* set/clear close_on_exec */ -#define F_GETFL 3 /* get file->f_flags */ -#define F_SETFL 4 /* set file->f_flags */ -#ifndef F_GETLK -#define F_GETLK 5 -#define F_SETLK 6 -#define F_SETLKW 7 -#endif -#ifndef F_SETOWN -#define F_SETOWN 8 /* for sockets. */ -#define F_GETOWN 9 /* for sockets. */ -#endif -#ifndef F_SETSIG -#define F_SETSIG 10 /* for sockets. */ -#define F_GETSIG 11 /* for sockets. */ -#endif - -#if __BITS_PER_LONG == 32 || defined(__KERNEL__) -#ifndef F_GETLK64 -#define F_GETLK64 12 /* using 'struct flock64' */ -#define F_SETLK64 13 -#define F_SETLKW64 14 -#endif -#endif /* __BITS_PER_LONG == 32 || defined(__KERNEL__) */ - -#ifndef F_SETOWN_EX -#define F_SETOWN_EX 15 -#define F_GETOWN_EX 16 -#endif - -#ifndef F_GETOWNER_UIDS -#define F_GETOWNER_UIDS 17 -#endif - -/* - * Open File Description Locks - * - * Usually record locks held by a process are released on *any* close and are - * not inherited across a fork(). - * - * These cmd values will set locks that conflict with process-associated - * record locks, but are "owned" by the open file description, not the - * process. This means that they are inherited across fork() like BSD (flock) - * locks, and they are only released automatically when the last reference to - * the open file against which they were acquired is put. - */ -#define F_OFD_GETLK 36 -#define F_OFD_SETLK 37 -#define F_OFD_SETLKW 38 - -#define F_OWNER_TID 0 -#define F_OWNER_PID 1 -#define F_OWNER_PGRP 2 - -struct f_owner_ex { - int type; - __kernel_pid_t pid; -}; - -/* for F_[GET|SET]FL */ -#define FD_CLOEXEC 1 /* actually anything with low bit set goes */ - -/* for posix fcntl() and lockf() */ -#ifndef F_RDLCK -#define F_RDLCK 0 -#define F_WRLCK 1 -#define F_UNLCK 2 -#endif - -/* for old implementation of bsd flock () */ -#ifndef F_EXLCK -#define F_EXLCK 4 /* or 3 */ -#define F_SHLCK 8 /* or 4 */ -#endif - -/* operations for bsd flock(), also used by the kernel implementation */ -#define LOCK_SH 1 /* shared lock */ -#define LOCK_EX 2 /* exclusive lock */ -#define LOCK_NB 4 /* or'd with one of the above to prevent - blocking */ -#define LOCK_UN 8 /* remove lock */ - -/* - * LOCK_MAND support has been removed from the kernel. We leave the symbols - * here to not break legacy builds, but these should not be used in new code. - */ -#define LOCK_MAND 32 /* This is a mandatory flock ... */ -#define LOCK_READ 64 /* which allows concurrent read operations */ -#define LOCK_WRITE 128 /* which allows concurrent write operations */ -#define LOCK_RW 192 /* which allows concurrent read & write ops */ - -#define F_LINUX_SPECIFIC_BASE 1024 - -#ifndef HAVE_ARCH_STRUCT_FLOCK -struct flock { - short l_type; - short l_whence; - __kernel_off_t l_start; - __kernel_off_t l_len; - __kernel_pid_t l_pid; -#ifdef __ARCH_FLOCK_EXTRA_SYSID - __ARCH_FLOCK_EXTRA_SYSID -#endif -#ifdef __ARCH_FLOCK_PAD - __ARCH_FLOCK_PAD -#endif -}; - -struct flock64 { - short l_type; - short l_whence; - __kernel_loff_t l_start; - __kernel_loff_t l_len; - __kernel_pid_t l_pid; -#ifdef __ARCH_FLOCK64_PAD - __ARCH_FLOCK64_PAD -#endif -}; -#endif /* HAVE_ARCH_STRUCT_FLOCK */ - -#endif /* _ASM_GENERIC_FCNTL_H */ diff --git a/tools/include/uapi/linux/fcntl.h b/tools/include/uapi/linux/fcntl.h deleted file mode 100644 index 282e90aeb163..000000000000 --- a/tools/include/uapi/linux/fcntl.h +++ /dev/null @@ -1,123 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -#ifndef _UAPI_LINUX_FCNTL_H -#define _UAPI_LINUX_FCNTL_H - -#include -#include - -#define F_SETLEASE (F_LINUX_SPECIFIC_BASE + 0) -#define F_GETLEASE (F_LINUX_SPECIFIC_BASE + 1) - -/* - * Cancel a blocking posix lock; internal use only until we expose an - * asynchronous lock api to userspace: - */ -#define F_CANCELLK (F_LINUX_SPECIFIC_BASE + 5) - -/* Create a file descriptor with FD_CLOEXEC set. */ -#define F_DUPFD_CLOEXEC (F_LINUX_SPECIFIC_BASE + 6) - -/* - * Request nofications on a directory. - * See below for events that may be notified. - */ -#define F_NOTIFY (F_LINUX_SPECIFIC_BASE+2) - -/* - * Set and get of pipe page size array - */ -#define F_SETPIPE_SZ (F_LINUX_SPECIFIC_BASE + 7) -#define F_GETPIPE_SZ (F_LINUX_SPECIFIC_BASE + 8) - -/* - * Set/Get seals - */ -#define F_ADD_SEALS (F_LINUX_SPECIFIC_BASE + 9) -#define F_GET_SEALS (F_LINUX_SPECIFIC_BASE + 10) - -/* - * Types of seals - */ -#define F_SEAL_SEAL 0x0001 /* prevent further seals from being set */ -#define F_SEAL_SHRINK 0x0002 /* prevent file from shrinking */ -#define F_SEAL_GROW 0x0004 /* prevent file from growing */ -#define F_SEAL_WRITE 0x0008 /* prevent writes */ -#define F_SEAL_FUTURE_WRITE 0x0010 /* prevent future writes while mapped */ -#define F_SEAL_EXEC 0x0020 /* prevent chmod modifying exec bits */ -/* (1U << 31) is reserved for signed error codes */ - -/* - * Set/Get write life time hints. {GET,SET}_RW_HINT operate on the - * underlying inode, while {GET,SET}_FILE_RW_HINT operate only on - * the specific file. - */ -#define F_GET_RW_HINT (F_LINUX_SPECIFIC_BASE + 11) -#define F_SET_RW_HINT (F_LINUX_SPECIFIC_BASE + 12) -#define F_GET_FILE_RW_HINT (F_LINUX_SPECIFIC_BASE + 13) -#define F_SET_FILE_RW_HINT (F_LINUX_SPECIFIC_BASE + 14) - -/* - * Valid hint values for F_{GET,SET}_RW_HINT. 0 is "not set", or can be - * used to clear any hints previously set. - */ -#define RWH_WRITE_LIFE_NOT_SET 0 -#define RWH_WRITE_LIFE_NONE 1 -#define RWH_WRITE_LIFE_SHORT 2 -#define RWH_WRITE_LIFE_MEDIUM 3 -#define RWH_WRITE_LIFE_LONG 4 -#define RWH_WRITE_LIFE_EXTREME 5 - -/* - * The originally introduced spelling is remained from the first - * versions of the patch set that introduced the feature, see commit - * v4.13-rc1~212^2~51. - */ -#define RWF_WRITE_LIFE_NOT_SET RWH_WRITE_LIFE_NOT_SET - -/* - * Types of directory notifications that may be requested. - */ -#define DN_ACCESS 0x00000001 /* File accessed */ -#define DN_MODIFY 0x00000002 /* File modified */ -#define DN_CREATE 0x00000004 /* File created */ -#define DN_DELETE 0x00000008 /* File removed */ -#define DN_RENAME 0x00000010 /* File renamed */ -#define DN_ATTRIB 0x00000020 /* File changed attibutes */ -#define DN_MULTISHOT 0x80000000 /* Don't remove notifier */ - -/* - * The constants AT_REMOVEDIR and AT_EACCESS have the same value. AT_EACCESS is - * meaningful only to faccessat, while AT_REMOVEDIR is meaningful only to - * unlinkat. The two functions do completely different things and therefore, - * the flags can be allowed to overlap. For example, passing AT_REMOVEDIR to - * faccessat would be undefined behavior and thus treating it equivalent to - * AT_EACCESS is valid undefined behavior. - */ -#define AT_FDCWD -100 /* Special value used to indicate - openat should use the current - working directory. */ -#define AT_SYMLINK_NOFOLLOW 0x100 /* Do not follow symbolic links. */ -#define AT_EACCESS 0x200 /* Test access permitted for - effective IDs, not real IDs. */ -#define AT_REMOVEDIR 0x200 /* Remove directory instead of - unlinking file. */ -#define AT_SYMLINK_FOLLOW 0x400 /* Follow symbolic links. */ -#define AT_NO_AUTOMOUNT 0x800 /* Suppress terminal automount traversal */ -#define AT_EMPTY_PATH 0x1000 /* Allow empty relative pathname */ - -#define AT_STATX_SYNC_TYPE 0x6000 /* Type of synchronisation required from statx() */ -#define AT_STATX_SYNC_AS_STAT 0x0000 /* - Do whatever stat() does */ -#define AT_STATX_FORCE_SYNC 0x2000 /* - Force the attributes to be sync'd with the server */ -#define AT_STATX_DONT_SYNC 0x4000 /* - Don't sync attributes with the server */ - -#define AT_RECURSIVE 0x8000 /* Apply to the entire subtree */ - -/* Flags for name_to_handle_at(2). We reuse AT_ flag space to save bits... */ -#define AT_HANDLE_FID AT_REMOVEDIR /* file handle is needed to - compare object identity and may not - be usable to open_by_handle_at(2) */ -#if defined(__KERNEL__) -#define AT_GETATTR_NOSEC 0x80000000 -#endif - -#endif /* _UAPI_LINUX_FCNTL_H */ diff --git a/tools/include/uapi/linux/openat2.h b/tools/include/uapi/linux/openat2.h deleted file mode 100644 index a5feb7604948..000000000000 --- a/tools/include/uapi/linux/openat2.h +++ /dev/null @@ -1,43 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -#ifndef _UAPI_LINUX_OPENAT2_H -#define _UAPI_LINUX_OPENAT2_H - -#include - -/* - * Arguments for how openat2(2) should open the target path. If only @flags and - * @mode are non-zero, then openat2(2) operates very similarly to openat(2). - * - * However, unlike openat(2), unknown or invalid bits in @flags result in - * -EINVAL rather than being silently ignored. @mode must be zero unless one of - * {O_CREAT, O_TMPFILE} are set. - * - * @flags: O_* flags. - * @mode: O_CREAT/O_TMPFILE file mode. - * @resolve: RESOLVE_* flags. - */ -struct open_how { - __u64 flags; - __u64 mode; - __u64 resolve; -}; - -/* how->resolve flags for openat2(2). */ -#define RESOLVE_NO_XDEV 0x01 /* Block mount-point crossings - (includes bind-mounts). */ -#define RESOLVE_NO_MAGICLINKS 0x02 /* Block traversal through procfs-style - "magic-links". */ -#define RESOLVE_NO_SYMLINKS 0x04 /* Block traversal through all symlinks - (implies OEXT_NO_MAGICLINKS) */ -#define RESOLVE_BENEATH 0x08 /* Block "lexical" trickery like - "..", symlinks, and absolute - paths which escape the dirfd. */ -#define RESOLVE_IN_ROOT 0x10 /* Make all jumps to "/" and ".." - be scoped inside the dirfd - (similar to chroot(2)). */ -#define RESOLVE_CACHED 0x20 /* Only complete if resolution can be - completed through cached lookup. May - return -EAGAIN if that's not - possible. */ - -#endif /* _UAPI_LINUX_OPENAT2_H */ diff --git a/tools/perf/check-headers.sh b/tools/perf/check-headers.sh index 03d00110a48f..4ea674df11f8 100755 --- a/tools/perf/check-headers.sh +++ b/tools/perf/check-headers.sh @@ -10,12 +10,10 @@ FILES=( "include/uapi/drm/drm.h" "include/uapi/drm/i915_drm.h" "include/uapi/linux/fadvise.h" - "include/uapi/linux/fcntl.h" "include/uapi/linux/fscrypt.h" "include/uapi/linux/kcmp.h" "include/uapi/linux/kvm.h" "include/uapi/linux/in.h" - "include/uapi/linux/openat2.h" "include/uapi/linux/perf_event.h" "include/uapi/linux/sched.h" "include/uapi/linux/seccomp.h" -- cgit v1.2.3-59-g8ed1b From a672af9139a843eb7a48fd7846bb6df8f81b5f86 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 15 Mar 2024 16:18:14 -0300 Subject: tools headers: Remove almost unused copy of uapi/stat.h, add few conditional defines These were used to build perf to provide defines not available in older distros, but this was back in 2017, nowadays most the distros that are supported and I have build containers for work using just the system headers, so ditch them. For the few that don't have STATX_MNT_ID{_UNIQUE}, or STATX_MNT_DIOALIGN add them conditionally. Some of these older distros may not have things that are used in 'perf trace', but then they also don't have libtraceevent packages, so don't build 'perf trace'. Cc: Adrian Hunter Cc: Ian Rogers Cc: Jiri Olsa Cc: Namhyung Kim Link: https://lore.kernel.org/lkml/20240315204835.748716-6-acme@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/include/uapi/linux/stat.h | 195 ---------------------------------------- tools/perf/check-headers.sh | 1 - tools/perf/trace/beauty/statx.c | 12 ++- 3 files changed, 11 insertions(+), 197 deletions(-) delete mode 100644 tools/include/uapi/linux/stat.h diff --git a/tools/include/uapi/linux/stat.h b/tools/include/uapi/linux/stat.h deleted file mode 100644 index 2f2ee82d5517..000000000000 --- a/tools/include/uapi/linux/stat.h +++ /dev/null @@ -1,195 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -#ifndef _UAPI_LINUX_STAT_H -#define _UAPI_LINUX_STAT_H - -#include - -#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) - -#define S_IFMT 00170000 -#define S_IFSOCK 0140000 -#define S_IFLNK 0120000 -#define S_IFREG 0100000 -#define S_IFBLK 0060000 -#define S_IFDIR 0040000 -#define S_IFCHR 0020000 -#define S_IFIFO 0010000 -#define S_ISUID 0004000 -#define S_ISGID 0002000 -#define S_ISVTX 0001000 - -#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) -#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) -#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) -#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) -#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) -#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) -#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) - -#define S_IRWXU 00700 -#define S_IRUSR 00400 -#define S_IWUSR 00200 -#define S_IXUSR 00100 - -#define S_IRWXG 00070 -#define S_IRGRP 00040 -#define S_IWGRP 00020 -#define S_IXGRP 00010 - -#define S_IRWXO 00007 -#define S_IROTH 00004 -#define S_IWOTH 00002 -#define S_IXOTH 00001 - -#endif - -/* - * Timestamp structure for the timestamps in struct statx. - * - * tv_sec holds the number of seconds before (negative) or after (positive) - * 00:00:00 1st January 1970 UTC. - * - * tv_nsec holds a number of nanoseconds (0..999,999,999) after the tv_sec time. - * - * __reserved is held in case we need a yet finer resolution. - */ -struct statx_timestamp { - __s64 tv_sec; - __u32 tv_nsec; - __s32 __reserved; -}; - -/* - * Structures for the extended file attribute retrieval system call - * (statx()). - * - * The caller passes a mask of what they're specifically interested in as a - * parameter to statx(). What statx() actually got will be indicated in - * st_mask upon return. - * - * For each bit in the mask argument: - * - * - if the datum is not supported: - * - * - the bit will be cleared, and - * - * - the datum will be set to an appropriate fabricated value if one is - * available (eg. CIFS can take a default uid and gid), otherwise - * - * - the field will be cleared; - * - * - otherwise, if explicitly requested: - * - * - the datum will be synchronised to the server if AT_STATX_FORCE_SYNC is - * set or if the datum is considered out of date, and - * - * - the field will be filled in and the bit will be set; - * - * - otherwise, if not requested, but available in approximate form without any - * effort, it will be filled in anyway, and the bit will be set upon return - * (it might not be up to date, however, and no attempt will be made to - * synchronise the internal state first); - * - * - otherwise the field and the bit will be cleared before returning. - * - * Items in STATX_BASIC_STATS may be marked unavailable on return, but they - * will have values installed for compatibility purposes so that stat() and - * co. can be emulated in userspace. - */ -struct statx { - /* 0x00 */ - __u32 stx_mask; /* What results were written [uncond] */ - __u32 stx_blksize; /* Preferred general I/O size [uncond] */ - __u64 stx_attributes; /* Flags conveying information about the file [uncond] */ - /* 0x10 */ - __u32 stx_nlink; /* Number of hard links */ - __u32 stx_uid; /* User ID of owner */ - __u32 stx_gid; /* Group ID of owner */ - __u16 stx_mode; /* File mode */ - __u16 __spare0[1]; - /* 0x20 */ - __u64 stx_ino; /* Inode number */ - __u64 stx_size; /* File size */ - __u64 stx_blocks; /* Number of 512-byte blocks allocated */ - __u64 stx_attributes_mask; /* Mask to show what's supported in stx_attributes */ - /* 0x40 */ - struct statx_timestamp stx_atime; /* Last access time */ - struct statx_timestamp stx_btime; /* File creation time */ - struct statx_timestamp stx_ctime; /* Last attribute change time */ - struct statx_timestamp stx_mtime; /* Last data modification time */ - /* 0x80 */ - __u32 stx_rdev_major; /* Device ID of special file [if bdev/cdev] */ - __u32 stx_rdev_minor; - __u32 stx_dev_major; /* ID of device containing file [uncond] */ - __u32 stx_dev_minor; - /* 0x90 */ - __u64 stx_mnt_id; - __u32 stx_dio_mem_align; /* Memory buffer alignment for direct I/O */ - __u32 stx_dio_offset_align; /* File offset alignment for direct I/O */ - /* 0xa0 */ - __u64 __spare3[12]; /* Spare space for future expansion */ - /* 0x100 */ -}; - -/* - * Flags to be stx_mask - * - * Query request/result mask for statx() and struct statx::stx_mask. - * - * These bits should be set in the mask argument of statx() to request - * particular items when calling statx(). - */ -#define STATX_TYPE 0x00000001U /* Want/got stx_mode & S_IFMT */ -#define STATX_MODE 0x00000002U /* Want/got stx_mode & ~S_IFMT */ -#define STATX_NLINK 0x00000004U /* Want/got stx_nlink */ -#define STATX_UID 0x00000008U /* Want/got stx_uid */ -#define STATX_GID 0x00000010U /* Want/got stx_gid */ -#define STATX_ATIME 0x00000020U /* Want/got stx_atime */ -#define STATX_MTIME 0x00000040U /* Want/got stx_mtime */ -#define STATX_CTIME 0x00000080U /* Want/got stx_ctime */ -#define STATX_INO 0x00000100U /* Want/got stx_ino */ -#define STATX_SIZE 0x00000200U /* Want/got stx_size */ -#define STATX_BLOCKS 0x00000400U /* Want/got stx_blocks */ -#define STATX_BASIC_STATS 0x000007ffU /* The stuff in the normal stat struct */ -#define STATX_BTIME 0x00000800U /* Want/got stx_btime */ -#define STATX_MNT_ID 0x00001000U /* Got stx_mnt_id */ -#define STATX_DIOALIGN 0x00002000U /* Want/got direct I/O alignment info */ -#define STATX_MNT_ID_UNIQUE 0x00004000U /* Want/got extended stx_mount_id */ - -#define STATX__RESERVED 0x80000000U /* Reserved for future struct statx expansion */ - -#ifndef __KERNEL__ -/* - * This is deprecated, and shall remain the same value in the future. To avoid - * confusion please use the equivalent (STATX_BASIC_STATS | STATX_BTIME) - * instead. - */ -#define STATX_ALL 0x00000fffU -#endif - -/* - * Attributes to be found in stx_attributes and masked in stx_attributes_mask. - * - * These give information about the features or the state of a file that might - * be of use to ordinary userspace programs such as GUIs or ls rather than - * specialised tools. - * - * Note that the flags marked [I] correspond to the FS_IOC_SETFLAGS flags - * semantically. Where possible, the numerical value is picked to correspond - * also. Note that the DAX attribute indicates that the file is in the CPU - * direct access state. It does not correspond to the per-inode flag that - * some filesystems support. - * - */ -#define STATX_ATTR_COMPRESSED 0x00000004 /* [I] File is compressed by the fs */ -#define STATX_ATTR_IMMUTABLE 0x00000010 /* [I] File is marked immutable */ -#define STATX_ATTR_APPEND 0x00000020 /* [I] File is append-only */ -#define STATX_ATTR_NODUMP 0x00000040 /* [I] File is not to be dumped */ -#define STATX_ATTR_ENCRYPTED 0x00000800 /* [I] File requires key to decrypt in fs */ -#define STATX_ATTR_AUTOMOUNT 0x00001000 /* Dir: Automount trigger */ -#define STATX_ATTR_MOUNT_ROOT 0x00002000 /* Root of a mount */ -#define STATX_ATTR_VERITY 0x00100000 /* [I] Verity protected file */ -#define STATX_ATTR_DAX 0x00200000 /* File is currently in DAX state */ - - -#endif /* _UAPI_LINUX_STAT_H */ diff --git a/tools/perf/check-headers.sh b/tools/perf/check-headers.sh index 4ea674df11f8..859cd6f35b0a 100755 --- a/tools/perf/check-headers.sh +++ b/tools/perf/check-headers.sh @@ -17,7 +17,6 @@ FILES=( "include/uapi/linux/perf_event.h" "include/uapi/linux/sched.h" "include/uapi/linux/seccomp.h" - "include/uapi/linux/stat.h" "include/uapi/linux/vhost.h" "include/linux/bits.h" "include/vdso/bits.h" diff --git a/tools/perf/trace/beauty/statx.c b/tools/perf/trace/beauty/statx.c index d1ccc93316bd..1f7e34ed4e02 100644 --- a/tools/perf/trace/beauty/statx.c +++ b/tools/perf/trace/beauty/statx.c @@ -9,7 +9,17 @@ #include #include #include -#include +#include + +#ifndef STATX_MNT_ID +#define STATX_MNT_ID 0x00001000U +#endif +#ifndef STATX_DIOALIGN +#define STATX_DIOALIGN 0x00002000U +#endif +#ifndef STATX_MNT_ID_UNIQUE +#define STATX_MNT_ID_UNIQUE 0x00004000U +#endif size_t syscall_arg__scnprintf_statx_flags(char *bf, size_t size, struct syscall_arg *arg) { -- cgit v1.2.3-59-g8ed1b From 36f65f9b7a454be6e2a329ca959c70c2f2529e9e Mon Sep 17 00:00:00 2001 From: James Clark Date: Tue, 12 Mar 2024 13:25:07 +0000 Subject: perf docs arm_spe: Clarify more SPE requirements related to KPTI The question of exactly when KPTI needs to be disabled comes up a lot because it doesn't always need to be done. Add the relevant kernel function and some examples that describe the behavior. Also describe the interrupt requirement and that no error message will be printed if this isn't met. Reviewed-by: Ian Rogers Signed-off-by: James Clark Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ingo Molnar Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20240312132508.423320-1-james.clark@arm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-arm-spe.txt | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/tools/perf/Documentation/perf-arm-spe.txt b/tools/perf/Documentation/perf-arm-spe.txt index bf03222e9a68..0a3eda482307 100644 --- a/tools/perf/Documentation/perf-arm-spe.txt +++ b/tools/perf/Documentation/perf-arm-spe.txt @@ -116,6 +116,15 @@ Depending on CPU model, the kernel may need to be booted with page table isolati (kpti=off). If KPTI needs to be disabled, this will fail with a console message "profiling buffer inaccessible. Try passing 'kpti=off' on the kernel command line". +For the full criteria that determine whether KPTI needs to be forced off or not, see function +unmap_kernel_at_el0() in the kernel sources. Common cases where it's not required +are on the CPUs in kpti_safe_list, or on Arm v8.5+ where FEAT_E0PD is mandatory. + +The SPE interrupt must also be described by the firmware. If the module is loaded and KPTI is +disabled (or isn't required to be disabled) but the SPE PMU still doesn't show in +/sys/bus/event_source/devices/, then it's possible that the SPE interrupt isn't described by +ACPI or DT. In this case no warning will be printed by the driver. + Capturing SPE with perf command-line tools ------------------------------------------ @@ -199,7 +208,8 @@ Common errors - "Cannot find PMU `arm_spe'. Missing kernel support?" - Module not built or loaded, KPTI not disabled (see above), or running on a VM + Module not built or loaded, KPTI not disabled, interrupt not described by firmware, + or running on a VM. See 'Kernel Requirements' above. - "Arm SPE CONTEXT packets not found in the traces." -- cgit v1.2.3-59-g8ed1b From d4a98b45fbe6d06f4b79ed90d0bb05ced8674c23 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 15 Mar 2024 09:13:33 +0200 Subject: perf script: Show also errors for --insn-trace option The trace could be misleading if trace errors are not taken into account, so display them also by adding the itrace "e" option. Note --call-trace and --call-ret-trace already add the itrace "e" option. Fixes: b585ebdb5912cf14 ("perf script: Add --insn-trace for instruction decoding") Reviewed-by: Andi Kleen Signed-off-by: Adrian Hunter Cc: Andi Kleen Cc: Ian Rogers Cc: Jiri Olsa Cc: Namhyung Kim Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20240315071334.3478-1-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-script.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 37088cc0ff1b..2e7148d667bd 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -3806,7 +3806,7 @@ static int parse_insn_trace(const struct option *opt __maybe_unused, if (ret < 0) return ret; - itrace_parse_synth_opts(opt, "i0ns", 0); + itrace_parse_synth_opts(opt, "i0nse", 0); symbol_conf.nanosecs = true; return 0; } -- cgit v1.2.3-59-g8ed1b From bb69c912c4e8005cf1ee6c63782d2fc28838dee2 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 15 Mar 2024 09:13:34 +0200 Subject: perf auxtrace: Fix multiple use of --itrace option If the --itrace option is used more than once, the options are combined, but "i" and "y" (sub-)options can be corrupted because itrace_do_parse_synth_opts() incorrectly overwrites the period type and period with default values. For example, with: --itrace=i0ns --itrace=e The processing of "--itrace=e", resets the "i" period from 0 nanoseconds to the default 100 microseconds. Fix by performing the default setting of period type and period only if "i" or "y" are present in the currently processed --itrace value. Fixes: f6986c95af84ff2a ("perf session: Add instruction tracing options") Signed-off-by: Adrian Hunter Cc: Adrian Hunter Cc: Andi Kleen Cc: Ian Rogers Cc: Jiri Olsa Cc: Namhyung Kim Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20240315071334.3478-2-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/auxtrace.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c index 3684e6009b63..ef314a5797e3 100644 --- a/tools/perf/util/auxtrace.c +++ b/tools/perf/util/auxtrace.c @@ -1466,6 +1466,7 @@ int itrace_do_parse_synth_opts(struct itrace_synth_opts *synth_opts, char *endptr; bool period_type_set = false; bool period_set = false; + bool iy = false; synth_opts->set = true; @@ -1484,6 +1485,7 @@ int itrace_do_parse_synth_opts(struct itrace_synth_opts *synth_opts, switch (*p++) { case 'i': case 'y': + iy = true; if (p[-1] == 'y') synth_opts->cycles = true; else @@ -1649,7 +1651,7 @@ int itrace_do_parse_synth_opts(struct itrace_synth_opts *synth_opts, } } out: - if (synth_opts->instructions || synth_opts->cycles) { + if (iy) { if (!period_type_set) synth_opts->period_type = PERF_ITRACE_DEFAULT_PERIOD_TYPE; -- cgit v1.2.3-59-g8ed1b From efae55bb78cf8722c7df01cd974197dfd13ece39 Mon Sep 17 00:00:00 2001 From: Ethan Adams Date: Thu, 14 Mar 2024 15:20:12 -0700 Subject: perf build: Fix out of tree build related to installation of sysreg-defs It seems that a previous modification to sysreg-defs, which corrected emitting the header to the specified output directory, exposed missing subdir, prefix variables. This breaks out of tree builds of perf as the file is now built into the output directory, but still tries to descend into output directory as a subdir. Fixes: a29ee6aea7030786 ("perf build: Ensure sysreg-defs Makefile respects output dir") Reviewed-by: Oliver Upton Reviewed-by: Tycho Andersen Signed-off-by: Ethan Adams Tested-by: Tycho Andersen Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20240314222012.47193-1-j.ethan.adams@gmail.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Makefile.perf | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index b36c0c68c346..f5654d06e313 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -458,18 +458,19 @@ SHELL = $(SHELL_PATH) arm64_gen_sysreg_dir := $(srctree)/tools/arch/arm64/tools ifneq ($(OUTPUT),) - arm64_gen_sysreg_outdir := $(OUTPUT) + arm64_gen_sysreg_outdir := $(abspath $(OUTPUT)) else arm64_gen_sysreg_outdir := $(CURDIR) endif arm64-sysreg-defs: FORCE - $(Q)$(MAKE) -C $(arm64_gen_sysreg_dir) O=$(arm64_gen_sysreg_outdir) + $(Q)$(MAKE) -C $(arm64_gen_sysreg_dir) O=$(arm64_gen_sysreg_outdir) \ + prefix= subdir= arm64-sysreg-defs-clean: $(call QUIET_CLEAN,arm64-sysreg-defs) $(Q)$(MAKE) -C $(arm64_gen_sysreg_dir) O=$(arm64_gen_sysreg_outdir) \ - clean > /dev/null + prefix= subdir= clean > /dev/null beauty_linux_dir := $(srctree)/tools/perf/trace/beauty/include/linux/ beauty_uapi_linux_dir := $(srctree)/tools/perf/trace/beauty/include/uapi/linux/ -- cgit v1.2.3-59-g8ed1b From b6b4a62d8525c3093c3273dc6b2e6831adbfc4b2 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Fri, 2 Feb 2024 15:40:50 -0800 Subject: libperf cpumap: Add any, empty and min helpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Additional helpers to better replace perf_cpu_map__has_any_cpu_or_is_empty(). Signed-off-by: Ian Rogers Acked-by: Namhyung Kim Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Alexandre Ghiti Cc: Andrew Jones Cc: André Almeida Cc: Athira Rajeev Cc: Atish Patra Cc: Changbin Du Cc: Darren Hart Cc: Davidlohr Bueso Cc: Huacai Chen Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: John Garry Cc: K Prateek Nayak Cc: Kajol Jain Cc: Kan Liang Cc: Leo Yan Cc: Mark Rutland Cc: Mike Leach Cc: Nick Desaulniers Cc: Paolo Bonzini Cc: Paran Lee Cc: Peter Zijlstra Cc: Ravi Bangoria Cc: Sandipan Das Cc: Sean Christopherson Cc: Steinar H. Gunderson Cc: Suzuki Poulouse Cc: Thomas Gleixner Cc: Will Deacon Cc: Yang Jihong Cc: Yang Li Cc: Yanteng Si Link: https://lore.kernel.org/r/20240202234057.2085863-2-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/lib/perf/cpumap.c | 27 +++++++++++++++++++++++++++ tools/lib/perf/include/perf/cpumap.h | 16 ++++++++++++++++ tools/lib/perf/libperf.map | 4 ++++ 3 files changed, 47 insertions(+) diff --git a/tools/lib/perf/cpumap.c b/tools/lib/perf/cpumap.c index 4adcd7920d03..ba49552952c5 100644 --- a/tools/lib/perf/cpumap.c +++ b/tools/lib/perf/cpumap.c @@ -316,6 +316,19 @@ bool perf_cpu_map__has_any_cpu_or_is_empty(const struct perf_cpu_map *map) return map ? __perf_cpu_map__cpu(map, 0).cpu == -1 : true; } +bool perf_cpu_map__is_any_cpu_or_is_empty(const struct perf_cpu_map *map) +{ + if (!map) + return true; + + return __perf_cpu_map__nr(map) == 1 && __perf_cpu_map__cpu(map, 0).cpu == -1; +} + +bool perf_cpu_map__is_empty(const struct perf_cpu_map *map) +{ + return map == NULL; +} + int perf_cpu_map__idx(const struct perf_cpu_map *cpus, struct perf_cpu cpu) { int low, high; @@ -372,6 +385,20 @@ bool perf_cpu_map__has_any_cpu(const struct perf_cpu_map *map) return map && __perf_cpu_map__cpu(map, 0).cpu == -1; } +struct perf_cpu perf_cpu_map__min(const struct perf_cpu_map *map) +{ + struct perf_cpu cpu, result = { + .cpu = -1 + }; + int idx; + + perf_cpu_map__for_each_cpu_skip_any(cpu, idx, map) { + result = cpu; + break; + } + return result; +} + struct perf_cpu perf_cpu_map__max(const struct perf_cpu_map *map) { struct perf_cpu result = { diff --git a/tools/lib/perf/include/perf/cpumap.h b/tools/lib/perf/include/perf/cpumap.h index 228c6c629b0c..90457d17fb2f 100644 --- a/tools/lib/perf/include/perf/cpumap.h +++ b/tools/lib/perf/include/perf/cpumap.h @@ -61,6 +61,22 @@ LIBPERF_API int perf_cpu_map__nr(const struct perf_cpu_map *cpus); * perf_cpu_map__has_any_cpu_or_is_empty - is map either empty or has the "any CPU"/dummy value. */ LIBPERF_API bool perf_cpu_map__has_any_cpu_or_is_empty(const struct perf_cpu_map *map); +/** + * perf_cpu_map__is_any_cpu_or_is_empty - is map either empty or the "any CPU"/dummy value. + */ +LIBPERF_API bool perf_cpu_map__is_any_cpu_or_is_empty(const struct perf_cpu_map *map); +/** + * perf_cpu_map__is_empty - does the map contain no values and it doesn't + * contain the special "any CPU"/dummy value. + */ +LIBPERF_API bool perf_cpu_map__is_empty(const struct perf_cpu_map *map); +/** + * perf_cpu_map__min - the minimum CPU value or -1 if empty or just the "any CPU"/dummy value. + */ +LIBPERF_API struct perf_cpu perf_cpu_map__min(const struct perf_cpu_map *map); +/** + * perf_cpu_map__max - the maximum CPU value or -1 if empty or just the "any CPU"/dummy value. + */ LIBPERF_API struct perf_cpu perf_cpu_map__max(const struct perf_cpu_map *map); LIBPERF_API bool perf_cpu_map__has(const struct perf_cpu_map *map, struct perf_cpu cpu); LIBPERF_API bool perf_cpu_map__equal(const struct perf_cpu_map *lhs, diff --git a/tools/lib/perf/libperf.map b/tools/lib/perf/libperf.map index 10b3f3722642..2aa79b696032 100644 --- a/tools/lib/perf/libperf.map +++ b/tools/lib/perf/libperf.map @@ -10,6 +10,10 @@ LIBPERF_0.0.1 { perf_cpu_map__nr; perf_cpu_map__cpu; perf_cpu_map__has_any_cpu_or_is_empty; + perf_cpu_map__is_any_cpu_or_is_empty; + perf_cpu_map__is_empty; + perf_cpu_map__has_any_cpu; + perf_cpu_map__min; perf_cpu_map__max; perf_cpu_map__has; perf_thread_map__new_array; -- cgit v1.2.3-59-g8ed1b From dcd45b376d0ab07b987fa968a01e7a5b0c4bf837 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Fri, 2 Feb 2024 15:40:51 -0800 Subject: libperf cpumap: Ensure empty cpumap is NULL from alloc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Potential corner cases could cause a cpumap to be allocated with size 0, but an empty cpumap should be represented as NULL. Add a path in perf_cpu_map__alloc() to ensure this. Suggested-by: James Clark Signed-off-by: Ian Rogers Acked-by: Namhyung Kim Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Alexandre Ghiti Cc: Andrew Jones Cc: André Almeida Cc: Athira Rajeev Cc: Atish Patra Cc: Changbin Du Cc: Darren Hart Cc: Davidlohr Bueso Cc: Huacai Chen Cc: Ingo Molnar Cc: Jiri Olsa Cc: John Garry Cc: K Prateek Nayak Cc: Kajol Jain Cc: Kan Liang Cc: Leo Yan Cc: Mark Rutland Cc: Mike Leach Cc: Nick Desaulniers Cc: Paolo Bonzini Cc: Paran Lee Cc: Peter Zijlstra Cc: Ravi Bangoria Cc: Sandipan Das Cc: Sean Christopherson Cc: Steinar H. Gunderson Cc: Suzuki Poulouse Cc: Thomas Gleixner Cc: Will Deacon Cc: Yang Jihong Cc: Yang Li Cc: Yanteng Si Closes: https://lore.kernel.org/lkml/2cd09e7c-eb88-6726-6169-647dcd0a8101@arm.com/ Link: https://lore.kernel.org/r/20240202234057.2085863-3-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/lib/perf/cpumap.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tools/lib/perf/cpumap.c b/tools/lib/perf/cpumap.c index ba49552952c5..cae799ad44e1 100644 --- a/tools/lib/perf/cpumap.c +++ b/tools/lib/perf/cpumap.c @@ -18,9 +18,13 @@ void perf_cpu_map__set_nr(struct perf_cpu_map *map, int nr_cpus) struct perf_cpu_map *perf_cpu_map__alloc(int nr_cpus) { - RC_STRUCT(perf_cpu_map) *cpus = malloc(sizeof(*cpus) + sizeof(struct perf_cpu) * nr_cpus); + RC_STRUCT(perf_cpu_map) *cpus; struct perf_cpu_map *result; + if (nr_cpus == 0) + return NULL; + + cpus = malloc(sizeof(*cpus) + sizeof(struct perf_cpu) * nr_cpus); if (ADD_RC_CHK(result, cpus)) { cpus->nr = nr_cpus; refcount_set(&cpus->refcnt, 1); -- cgit v1.2.3-59-g8ed1b From e28ee1239daa147a30c287ff0ad34ccadcc01de0 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Fri, 2 Feb 2024 15:40:52 -0800 Subject: perf arm-spe/cs-etm: Directly iterate CPU maps MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rather than iterate all CPUs and see if they are in CPU maps, directly iterate the CPU map. Similarly make use of the intersect function taking care for when "any" CPU is specified. Switch perf_cpu_map__has_any_cpu_or_is_empty() to more appropriate alternatives. Reviewed-by: James Clark Signed-off-by: Ian Rogers Acked-by: Namhyung Kim Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Alexandre Ghiti Cc: Andrew Jones Cc: André Almeida Cc: Athira Rajeev Cc: Atish Patra Cc: Changbin Du Cc: Darren Hart Cc: Davidlohr Bueso Cc: Huacai Chen Cc: Ingo Molnar Cc: Jiri Olsa Cc: John Garry Cc: K Prateek Nayak Cc: Kajol Jain Cc: Kan Liang Cc: Leo Yan Cc: Mark Rutland Cc: Mike Leach Cc: Nick Desaulniers Cc: Paolo Bonzini Cc: Paran Lee Cc: Peter Zijlstra Cc: Ravi Bangoria Cc: Sandipan Das Cc: Sean Christopherson Cc: Steinar H. Gunderson Cc: Suzuki Poulouse Cc: Thomas Gleixner Cc: Will Deacon Cc: Yang Jihong Cc: Yang Li Cc: Yanteng Si Link: https://lore.kernel.org/r/20240202234057.2085863-4-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/arch/arm/util/cs-etm.c | 114 +++++++++++++++-------------------- tools/perf/arch/arm64/util/arm-spe.c | 4 +- 2 files changed, 51 insertions(+), 67 deletions(-) diff --git a/tools/perf/arch/arm/util/cs-etm.c b/tools/perf/arch/arm/util/cs-etm.c index 77e6663c1703..07be32d99805 100644 --- a/tools/perf/arch/arm/util/cs-etm.c +++ b/tools/perf/arch/arm/util/cs-etm.c @@ -197,38 +197,37 @@ static int cs_etm_validate_timestamp(struct auxtrace_record *itr, static int cs_etm_validate_config(struct auxtrace_record *itr, struct evsel *evsel) { - int i, err = -EINVAL; + int idx, err = 0; struct perf_cpu_map *event_cpus = evsel->evlist->core.user_requested_cpus; - struct perf_cpu_map *online_cpus = perf_cpu_map__new_online_cpus(); - - /* Set option of each CPU we have */ - for (i = 0; i < cpu__max_cpu().cpu; i++) { - struct perf_cpu cpu = { .cpu = i, }; + struct perf_cpu_map *intersect_cpus; + struct perf_cpu cpu; - /* - * In per-cpu case, do the validation for CPUs to work with. - * In per-thread case, the CPU map is empty. Since the traced - * program can run on any CPUs in this case, thus don't skip - * validation. - */ - if (!perf_cpu_map__has_any_cpu_or_is_empty(event_cpus) && - !perf_cpu_map__has(event_cpus, cpu)) - continue; + /* + * Set option of each CPU we have. In per-cpu case, do the validation + * for CPUs to work with. In per-thread case, the CPU map has the "any" + * CPU value. Since the traced program can run on any CPUs in this case, + * thus don't skip validation. + */ + if (!perf_cpu_map__has_any_cpu(event_cpus)) { + struct perf_cpu_map *online_cpus = perf_cpu_map__new_online_cpus(); - if (!perf_cpu_map__has(online_cpus, cpu)) - continue; + intersect_cpus = perf_cpu_map__intersect(event_cpus, online_cpus); + perf_cpu_map__put(online_cpus); + } else { + intersect_cpus = perf_cpu_map__new_online_cpus(); + } - err = cs_etm_validate_context_id(itr, evsel, i); + perf_cpu_map__for_each_cpu_skip_any(cpu, idx, intersect_cpus) { + err = cs_etm_validate_context_id(itr, evsel, cpu.cpu); if (err) - goto out; - err = cs_etm_validate_timestamp(itr, evsel, i); + break; + + err = cs_etm_validate_timestamp(itr, evsel, cpu.cpu); if (err) - goto out; + break; } - err = 0; -out: - perf_cpu_map__put(online_cpus); + perf_cpu_map__put(intersect_cpus); return err; } @@ -435,7 +434,7 @@ static int cs_etm_recording_options(struct auxtrace_record *itr, * Also the case of per-cpu mmaps, need the contextID in order to be notified * when a context switch happened. */ - if (!perf_cpu_map__has_any_cpu_or_is_empty(cpus)) { + if (!perf_cpu_map__is_any_cpu_or_is_empty(cpus)) { evsel__set_config_if_unset(cs_etm_pmu, cs_etm_evsel, "timestamp", 1); evsel__set_config_if_unset(cs_etm_pmu, cs_etm_evsel, @@ -461,7 +460,7 @@ static int cs_etm_recording_options(struct auxtrace_record *itr, evsel->core.attr.sample_period = 1; /* In per-cpu case, always need the time of mmap events etc */ - if (!perf_cpu_map__has_any_cpu_or_is_empty(cpus)) + if (!perf_cpu_map__is_any_cpu_or_is_empty(cpus)) evsel__set_sample_bit(evsel, TIME); err = cs_etm_validate_config(itr, cs_etm_evsel); @@ -533,45 +532,31 @@ static size_t cs_etm_info_priv_size(struct auxtrace_record *itr __maybe_unused, struct evlist *evlist __maybe_unused) { - int i; + int idx; int etmv3 = 0, etmv4 = 0, ete = 0; struct perf_cpu_map *event_cpus = evlist->core.user_requested_cpus; - struct perf_cpu_map *online_cpus = perf_cpu_map__new_online_cpus(); - - /* cpu map is not empty, we have specific CPUs to work with */ - if (!perf_cpu_map__has_any_cpu_or_is_empty(event_cpus)) { - for (i = 0; i < cpu__max_cpu().cpu; i++) { - struct perf_cpu cpu = { .cpu = i, }; + struct perf_cpu_map *intersect_cpus; + struct perf_cpu cpu; - if (!perf_cpu_map__has(event_cpus, cpu) || - !perf_cpu_map__has(online_cpus, cpu)) - continue; + if (!perf_cpu_map__has_any_cpu(event_cpus)) { + /* cpu map is not "any" CPU , we have specific CPUs to work with */ + struct perf_cpu_map *online_cpus = perf_cpu_map__new_online_cpus(); - if (cs_etm_is_ete(itr, i)) - ete++; - else if (cs_etm_is_etmv4(itr, i)) - etmv4++; - else - etmv3++; - } + intersect_cpus = perf_cpu_map__intersect(event_cpus, online_cpus); + perf_cpu_map__put(online_cpus); } else { - /* get configuration for all CPUs in the system */ - for (i = 0; i < cpu__max_cpu().cpu; i++) { - struct perf_cpu cpu = { .cpu = i, }; - - if (!perf_cpu_map__has(online_cpus, cpu)) - continue; - - if (cs_etm_is_ete(itr, i)) - ete++; - else if (cs_etm_is_etmv4(itr, i)) - etmv4++; - else - etmv3++; - } + /* Event can be "any" CPU so count all online CPUs. */ + intersect_cpus = perf_cpu_map__new_online_cpus(); } - - perf_cpu_map__put(online_cpus); + perf_cpu_map__for_each_cpu_skip_any(cpu, idx, intersect_cpus) { + if (cs_etm_is_ete(itr, cpu.cpu)) + ete++; + else if (cs_etm_is_etmv4(itr, cpu.cpu)) + etmv4++; + else + etmv3++; + } + perf_cpu_map__put(intersect_cpus); return (CS_ETM_HEADER_SIZE + (ete * CS_ETE_PRIV_SIZE) + @@ -813,16 +798,15 @@ static int cs_etm_info_fill(struct auxtrace_record *itr, if (!session->evlist->core.nr_mmaps) return -EINVAL; - /* If the cpu_map is empty all online CPUs are involved */ - if (perf_cpu_map__has_any_cpu_or_is_empty(event_cpus)) { + /* If the cpu_map has the "any" CPU all online CPUs are involved */ + if (perf_cpu_map__has_any_cpu(event_cpus)) { cpu_map = online_cpus; } else { /* Make sure all specified CPUs are online */ - for (i = 0; i < perf_cpu_map__nr(event_cpus); i++) { - struct perf_cpu cpu = { .cpu = i, }; + struct perf_cpu cpu; - if (perf_cpu_map__has(event_cpus, cpu) && - !perf_cpu_map__has(online_cpus, cpu)) + perf_cpu_map__for_each_cpu(cpu, i, event_cpus) { + if (!perf_cpu_map__has(online_cpus, cpu)) return -EINVAL; } diff --git a/tools/perf/arch/arm64/util/arm-spe.c b/tools/perf/arch/arm64/util/arm-spe.c index 51ccbfd3d246..0b52e67edb3b 100644 --- a/tools/perf/arch/arm64/util/arm-spe.c +++ b/tools/perf/arch/arm64/util/arm-spe.c @@ -232,7 +232,7 @@ static int arm_spe_recording_options(struct auxtrace_record *itr, * In the case of per-cpu mmaps, sample CPU for AUX event; * also enable the timestamp tracing for samples correlation. */ - if (!perf_cpu_map__has_any_cpu_or_is_empty(cpus)) { + if (!perf_cpu_map__is_any_cpu_or_is_empty(cpus)) { evsel__set_sample_bit(arm_spe_evsel, CPU); evsel__set_config_if_unset(arm_spe_pmu, arm_spe_evsel, "ts_enable", 1); @@ -265,7 +265,7 @@ static int arm_spe_recording_options(struct auxtrace_record *itr, tracking_evsel->core.attr.sample_period = 1; /* In per-cpu case, always need the time of mmap events etc */ - if (!perf_cpu_map__has_any_cpu_or_is_empty(cpus)) { + if (!perf_cpu_map__is_any_cpu_or_is_empty(cpus)) { evsel__set_sample_bit(tracking_evsel, TIME); evsel__set_sample_bit(tracking_evsel, CPU); -- cgit v1.2.3-59-g8ed1b From 291dcd774b644875c9eb2a56b272919fe35c5c6f Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Fri, 2 Feb 2024 15:40:53 -0800 Subject: perf intel-pt/intel-bts: Switch perf_cpu_map__has_any_cpu_or_is_empty use MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Switch perf_cpu_map__has_any_cpu_or_is_empty() to perf_cpu_map__is_any_cpu_or_is_empty() as a CPU map may contain CPUs as well as the dummy event and perf_cpu_map__is_any_cpu_or_is_empty() is a more correct alternative. Signed-off-by: Ian Rogers Acked-by: Namhyung Kim Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Alexandre Ghiti Cc: Andrew Jones Cc: André Almeida Cc: Athira Rajeev Cc: Atish Patra Cc: Changbin Du Cc: Darren Hart Cc: Davidlohr Bueso Cc: Huacai Chen Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: John Garry Cc: K Prateek Nayak Cc: Kajol Jain Cc: Kan Liang Cc: Leo Yan Cc: Mark Rutland Cc: Mike Leach Cc: Nick Desaulniers Cc: Paolo Bonzini Cc: Paran Lee Cc: Peter Zijlstra Cc: Ravi Bangoria Cc: Sandipan Das Cc: Sean Christopherson Cc: Steinar H. Gunderson Cc: Suzuki Poulouse Cc: Thomas Gleixner Cc: Will Deacon Cc: Yang Jihong Cc: Yang Li Cc: Yanteng Si Link: https://lore.kernel.org/r/20240202234057.2085863-5-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/arch/x86/util/intel-bts.c | 4 ++-- tools/perf/arch/x86/util/intel-pt.c | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tools/perf/arch/x86/util/intel-bts.c b/tools/perf/arch/x86/util/intel-bts.c index af8ae4647585..34696f3d3d5d 100644 --- a/tools/perf/arch/x86/util/intel-bts.c +++ b/tools/perf/arch/x86/util/intel-bts.c @@ -143,7 +143,7 @@ static int intel_bts_recording_options(struct auxtrace_record *itr, if (!opts->full_auxtrace) return 0; - if (opts->full_auxtrace && !perf_cpu_map__has_any_cpu_or_is_empty(cpus)) { + if (opts->full_auxtrace && !perf_cpu_map__is_any_cpu_or_is_empty(cpus)) { pr_err(INTEL_BTS_PMU_NAME " does not support per-cpu recording\n"); return -EINVAL; } @@ -224,7 +224,7 @@ static int intel_bts_recording_options(struct auxtrace_record *itr, * In the case of per-cpu mmaps, we need the CPU on the * AUX event. */ - if (!perf_cpu_map__has_any_cpu_or_is_empty(cpus)) + if (!perf_cpu_map__is_any_cpu_or_is_empty(cpus)) evsel__set_sample_bit(intel_bts_evsel, CPU); } diff --git a/tools/perf/arch/x86/util/intel-pt.c b/tools/perf/arch/x86/util/intel-pt.c index d199619df3ab..6de7e2d21075 100644 --- a/tools/perf/arch/x86/util/intel-pt.c +++ b/tools/perf/arch/x86/util/intel-pt.c @@ -369,7 +369,7 @@ static int intel_pt_info_fill(struct auxtrace_record *itr, ui__warning("Intel Processor Trace: TSC not available\n"); } - per_cpu_mmaps = !perf_cpu_map__has_any_cpu_or_is_empty(session->evlist->core.user_requested_cpus); + per_cpu_mmaps = !perf_cpu_map__is_any_cpu_or_is_empty(session->evlist->core.user_requested_cpus); auxtrace_info->type = PERF_AUXTRACE_INTEL_PT; auxtrace_info->priv[INTEL_PT_PMU_TYPE] = intel_pt_pmu->type; @@ -774,7 +774,7 @@ static int intel_pt_recording_options(struct auxtrace_record *itr, * Per-cpu recording needs sched_switch events to distinguish different * threads. */ - if (have_timing_info && !perf_cpu_map__has_any_cpu_or_is_empty(cpus) && + if (have_timing_info && !perf_cpu_map__is_any_cpu_or_is_empty(cpus) && !record_opts__no_switch_events(opts)) { if (perf_can_record_switch_events()) { bool cpu_wide = !target__none(&opts->target) && @@ -832,7 +832,7 @@ static int intel_pt_recording_options(struct auxtrace_record *itr, * In the case of per-cpu mmaps, we need the CPU on the * AUX event. */ - if (!perf_cpu_map__has_any_cpu_or_is_empty(cpus)) + if (!perf_cpu_map__is_any_cpu_or_is_empty(cpus)) evsel__set_sample_bit(intel_pt_evsel, CPU); } @@ -858,7 +858,7 @@ static int intel_pt_recording_options(struct auxtrace_record *itr, tracking_evsel->immediate = true; /* In per-cpu case, always need the time of mmap events etc */ - if (!perf_cpu_map__has_any_cpu_or_is_empty(cpus)) { + if (!perf_cpu_map__is_any_cpu_or_is_empty(cpus)) { evsel__set_sample_bit(tracking_evsel, TIME); /* And the CPU for switch events */ evsel__set_sample_bit(tracking_evsel, CPU); @@ -870,7 +870,7 @@ static int intel_pt_recording_options(struct auxtrace_record *itr, * Warn the user when we do not have enough information to decode i.e. * per-cpu with no sched_switch (except workload-only). */ - if (!ptr->have_sched_switch && !perf_cpu_map__has_any_cpu_or_is_empty(cpus) && + if (!ptr->have_sched_switch && !perf_cpu_map__is_any_cpu_or_is_empty(cpus) && !target__none(&opts->target) && !intel_pt_evsel->core.attr.exclude_user) ui__warning("Intel Processor Trace decoding will not be possible except for kernel tracing!\n"); -- cgit v1.2.3-59-g8ed1b From 3e5deb708c8f3f7d645f567b2ba38d8045fa11ba Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Fri, 2 Feb 2024 15:40:54 -0800 Subject: perf cpumap: Clean up use of perf_cpu_map__has_any_cpu_or_is_empty MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Most uses of what was perf_cpu_map__empty but is now perf_cpu_map__has_any_cpu_or_is_empty want to do something with the CPU map if it contains CPUs. Replace uses of perf_cpu_map__has_any_cpu_or_is_empty with other helpers so that CPUs within the map can be handled. Reviewed-by: James Clark Signed-off-by: Ian Rogers Acked-by: Namhyung Kim Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Alexandre Ghiti Cc: Andrew Jones Cc: André Almeida Cc: Athira Rajeev Cc: Atish Patra Cc: Changbin Du Cc: Darren Hart Cc: Davidlohr Bueso Cc: Huacai Chen Cc: Ingo Molnar Cc: Jiri Olsa Cc: John Garry Cc: K Prateek Nayak Cc: Kajol Jain Cc: Kan Liang Cc: Leo Yan Cc: Mark Rutland Cc: Mike Leach Cc: Nick Desaulniers Cc: Paolo Bonzini Cc: Paran Lee Cc: Peter Zijlstra Cc: Ravi Bangoria Cc: Sandipan Das Cc: Sean Christopherson Cc: Steinar H. Gunderson Cc: Suzuki Poulouse Cc: Thomas Gleixner Cc: Will Deacon Cc: Yang Jihong Cc: Yang Li Cc: Yanteng Si Link: https://lore.kernel.org/r/20240202234057.2085863-6-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-c2c.c | 6 +----- tools/perf/builtin-stat.c | 9 ++++----- tools/perf/util/auxtrace.c | 4 ++-- tools/perf/util/record.c | 2 +- tools/perf/util/stat.c | 2 +- 5 files changed, 9 insertions(+), 14 deletions(-) diff --git a/tools/perf/builtin-c2c.c b/tools/perf/builtin-c2c.c index 14f228c7c869..1f1d17df9b9a 100644 --- a/tools/perf/builtin-c2c.c +++ b/tools/perf/builtin-c2c.c @@ -2319,11 +2319,7 @@ static int setup_nodes(struct perf_session *session) nodes[node] = set; - /* empty node, skip */ - if (perf_cpu_map__has_any_cpu_or_is_empty(map)) - continue; - - perf_cpu_map__for_each_cpu(cpu, idx, map) { + perf_cpu_map__for_each_cpu_skip_any(cpu, idx, map) { __set_bit(cpu.cpu, set); if (WARN_ONCE(cpu2node[cpu.cpu] != -1, "node/cpu topology bug")) diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 6bba1a89d030..a47ced077fa6 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -1319,10 +1319,9 @@ static int cpu__get_cache_id_from_map(struct perf_cpu cpu, char *map) * be the first online CPU in the cache domain else use the * first online CPU of the cache domain as the ID. */ - if (perf_cpu_map__has_any_cpu_or_is_empty(cpu_map)) + id = perf_cpu_map__min(cpu_map).cpu; + if (id == -1) id = cpu.cpu; - else - id = perf_cpu_map__cpu(cpu_map, 0).cpu; /* Free the perf_cpu_map used to find the cache ID */ perf_cpu_map__put(cpu_map); @@ -1642,7 +1641,7 @@ static int perf_stat_init_aggr_mode(void) * taking the highest cpu number to be the size of * the aggregation translate cpumap. */ - if (!perf_cpu_map__has_any_cpu_or_is_empty(evsel_list->core.user_requested_cpus)) + if (!perf_cpu_map__is_any_cpu_or_is_empty(evsel_list->core.user_requested_cpus)) nr = perf_cpu_map__max(evsel_list->core.user_requested_cpus).cpu; else nr = 0; @@ -2334,7 +2333,7 @@ int process_stat_config_event(struct perf_session *session, perf_event__read_stat_config(&stat_config, &event->stat_config); - if (perf_cpu_map__has_any_cpu_or_is_empty(st->cpus)) { + if (perf_cpu_map__is_empty(st->cpus)) { if (st->aggr_mode != AGGR_UNSET) pr_warning("warning: processing task data, aggregation mode not set\n"); } else if (st->aggr_mode != AGGR_UNSET) { diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c index ef314a5797e3..cfa2153d4611 100644 --- a/tools/perf/util/auxtrace.c +++ b/tools/perf/util/auxtrace.c @@ -174,7 +174,7 @@ void auxtrace_mmap_params__set_idx(struct auxtrace_mmap_params *mp, struct evlist *evlist, struct evsel *evsel, int idx) { - bool per_cpu = !perf_cpu_map__has_any_cpu_or_is_empty(evlist->core.user_requested_cpus); + bool per_cpu = !perf_cpu_map__has_any_cpu(evlist->core.user_requested_cpus); mp->mmap_needed = evsel->needs_auxtrace_mmap; @@ -648,7 +648,7 @@ int auxtrace_parse_snapshot_options(struct auxtrace_record *itr, static int evlist__enable_event_idx(struct evlist *evlist, struct evsel *evsel, int idx) { - bool per_cpu_mmaps = !perf_cpu_map__has_any_cpu_or_is_empty(evlist->core.user_requested_cpus); + bool per_cpu_mmaps = !perf_cpu_map__has_any_cpu(evlist->core.user_requested_cpus); if (per_cpu_mmaps) { struct perf_cpu evlist_cpu = perf_cpu_map__cpu(evlist->core.all_cpus, idx); diff --git a/tools/perf/util/record.c b/tools/perf/util/record.c index 87e817b3cf7e..e867de8ddaaa 100644 --- a/tools/perf/util/record.c +++ b/tools/perf/util/record.c @@ -237,7 +237,7 @@ bool evlist__can_select_event(struct evlist *evlist, const char *str) evsel = evlist__last(temp_evlist); - if (!evlist || perf_cpu_map__has_any_cpu_or_is_empty(evlist->core.user_requested_cpus)) { + if (!evlist || perf_cpu_map__is_any_cpu_or_is_empty(evlist->core.user_requested_cpus)) { struct perf_cpu_map *cpus = perf_cpu_map__new_online_cpus(); if (cpus) diff --git a/tools/perf/util/stat.c b/tools/perf/util/stat.c index b0bcf92f0f9c..0bd5467389e4 100644 --- a/tools/perf/util/stat.c +++ b/tools/perf/util/stat.c @@ -315,7 +315,7 @@ static int check_per_pkg(struct evsel *counter, struct perf_counts_values *vals, if (!counter->per_pkg) return 0; - if (perf_cpu_map__has_any_cpu_or_is_empty(cpus)) + if (perf_cpu_map__is_any_cpu_or_is_empty(cpus)) return 0; if (!mask) { -- cgit v1.2.3-59-g8ed1b From 4ddccd0048089eb324330fa3a0036e41c31355d3 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Fri, 2 Feb 2024 15:40:55 -0800 Subject: perf arm64 header: Remove unnecessary CPU map get and put MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In both cases the CPU map is known owned by either the caller or a PMU. Reviewed-by: James Clark Signed-off-by: Ian Rogers Acked-by: Namhyung Kim Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Alexandre Ghiti Cc: Andrew Jones Cc: André Almeida Cc: Athira Rajeev Cc: Atish Patra Cc: Changbin Du Cc: Darren Hart Cc: Davidlohr Bueso Cc: Huacai Chen Cc: Ingo Molnar Cc: Jiri Olsa Cc: John Garry Cc: K Prateek Nayak Cc: Kajol Jain Cc: Kan Liang Cc: Leo Yan Cc: Mark Rutland Cc: Mike Leach Cc: Nick Desaulniers Cc: Paolo Bonzini Cc: Paran Lee Cc: Peter Zijlstra Cc: Ravi Bangoria Cc: Sandipan Das Cc: Sean Christopherson Cc: Steinar H. Gunderson Cc: Suzuki Poulouse Cc: Thomas Gleixner Cc: Will Deacon Cc: Yang Jihong Cc: Yang Li Cc: Yanteng Si Link: https://lore.kernel.org/r/20240202234057.2085863-7-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/arch/arm64/util/header.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/tools/perf/arch/arm64/util/header.c b/tools/perf/arch/arm64/util/header.c index 97037499152e..a9de0b5187dd 100644 --- a/tools/perf/arch/arm64/util/header.c +++ b/tools/perf/arch/arm64/util/header.c @@ -25,8 +25,6 @@ static int _get_cpuid(char *buf, size_t sz, struct perf_cpu_map *cpus) if (!sysfs || sz < MIDR_SIZE) return EINVAL; - cpus = perf_cpu_map__get(cpus); - for (cpu = 0; cpu < perf_cpu_map__nr(cpus); cpu++) { char path[PATH_MAX]; FILE *file; @@ -51,7 +49,6 @@ static int _get_cpuid(char *buf, size_t sz, struct perf_cpu_map *cpus) break; } - perf_cpu_map__put(cpus); return ret; } -- cgit v1.2.3-59-g8ed1b From 954ac1b4a79a06736fd85a183f34c18c152286c6 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Fri, 2 Feb 2024 15:40:56 -0800 Subject: perf stat: Remove duplicate cpus_map_matched function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use libperf's perf_cpu_map__equal() that performs the same function. Reviewed-by: James Clark Signed-off-by: Ian Rogers Acked-by: Namhyung Kim Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Alexandre Ghiti Cc: Andrew Jones Cc: André Almeida Cc: Athira Rajeev Cc: Atish Patra Cc: Changbin Du Cc: Darren Hart Cc: Davidlohr Bueso Cc: Huacai Chen Cc: Ingo Molnar Cc: Jiri Olsa Cc: John Garry Cc: K Prateek Nayak Cc: Kajol Jain Cc: Kan Liang Cc: Leo Yan Cc: Mark Rutland Cc: Mike Leach Cc: Nick Desaulniers Cc: Paolo Bonzini Cc: Paran Lee Cc: Peter Zijlstra Cc: Ravi Bangoria Cc: Sandipan Das Cc: Sean Christopherson Cc: Steinar H. Gunderson Cc: Suzuki Poulouse Cc: Thomas Gleixner Cc: Will Deacon Cc: Yang Jihong Cc: Yang Li Cc: Yanteng Si Link: https://lore.kernel.org/r/20240202234057.2085863-8-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-stat.c | 22 +--------------------- 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index a47ced077fa6..65388c57bb5d 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -164,26 +164,6 @@ static struct perf_stat_config stat_config = { .iostat_run = false, }; -static bool cpus_map_matched(struct evsel *a, struct evsel *b) -{ - if (!a->core.cpus && !b->core.cpus) - return true; - - if (!a->core.cpus || !b->core.cpus) - return false; - - if (perf_cpu_map__nr(a->core.cpus) != perf_cpu_map__nr(b->core.cpus)) - return false; - - for (int i = 0; i < perf_cpu_map__nr(a->core.cpus); i++) { - if (perf_cpu_map__cpu(a->core.cpus, i).cpu != - perf_cpu_map__cpu(b->core.cpus, i).cpu) - return false; - } - - return true; -} - static void evlist__check_cpu_maps(struct evlist *evlist) { struct evsel *evsel, *warned_leader = NULL; @@ -194,7 +174,7 @@ static void evlist__check_cpu_maps(struct evlist *evlist) /* Check that leader matches cpus with each member. */ if (leader == evsel) continue; - if (cpus_map_matched(leader, evsel)) + if (perf_cpu_map__equal(leader->core.cpus, evsel->core.cpus)) continue; /* If there's mismatch disable the group and warn user. */ -- cgit v1.2.3-59-g8ed1b From 71bc3ac8e8c93f769d1a2040153fe6d6b8093fa7 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Fri, 2 Feb 2024 15:40:57 -0800 Subject: perf cpumap: Use perf_cpu_map__for_each_cpu when possible MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rather than manually iterating the CPU map, use perf_cpu_map__for_each_cpu(). When possible tidy local variables. Reviewed-by: James Clark Signed-off-by: Ian Rogers Acked-by: Namhyung Kim Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Alexandre Ghiti Cc: Andrew Jones Cc: André Almeida Cc: Athira Rajeev Cc: Atish Patra Cc: Changbin Du Cc: Darren Hart Cc: Davidlohr Bueso Cc: Huacai Chen Cc: Ingo Molnar Cc: Jiri Olsa Cc: John Garry Cc: K Prateek Nayak Cc: Kajol Jain Cc: Kan Liang Cc: Leo Yan Cc: Mark Rutland Cc: Mike Leach Cc: Nick Desaulniers Cc: Paolo Bonzini Cc: Paran Lee Cc: Peter Zijlstra Cc: Ravi Bangoria Cc: Sandipan Das Cc: Sean Christopherson Cc: Steinar H. Gunderson Cc: Suzuki Poulouse Cc: Thomas Gleixner Cc: Will Deacon Cc: Yang Jihong Cc: Yang Li Cc: Yanteng Si Link: https://lore.kernel.org/r/20240202234057.2085863-9-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/arch/arm64/util/header.c | 10 ++--- tools/perf/tests/bitmap.c | 13 +++--- tools/perf/tests/topology.c | 46 +++++++++++----------- tools/perf/util/bpf_kwork.c | 16 ++++---- tools/perf/util/bpf_kwork_top.c | 12 +++--- tools/perf/util/cpumap.c | 12 +++--- .../util/scripting-engines/trace-event-python.c | 12 +++--- tools/perf/util/session.c | 5 +-- tools/perf/util/svghelper.c | 20 +++++----- 9 files changed, 72 insertions(+), 74 deletions(-) diff --git a/tools/perf/arch/arm64/util/header.c b/tools/perf/arch/arm64/util/header.c index a9de0b5187dd..741df3614a09 100644 --- a/tools/perf/arch/arm64/util/header.c +++ b/tools/perf/arch/arm64/util/header.c @@ -4,8 +4,6 @@ #include #include #include -#include -#include #include #include #include "debug.h" @@ -19,18 +17,18 @@ static int _get_cpuid(char *buf, size_t sz, struct perf_cpu_map *cpus) { const char *sysfs = sysfs__mountpoint(); - int cpu; - int ret = EINVAL; + struct perf_cpu cpu; + int idx, ret = EINVAL; if (!sysfs || sz < MIDR_SIZE) return EINVAL; - for (cpu = 0; cpu < perf_cpu_map__nr(cpus); cpu++) { + perf_cpu_map__for_each_cpu(cpu, idx, cpus) { char path[PATH_MAX]; FILE *file; scnprintf(path, PATH_MAX, "%s/devices/system/cpu/cpu%d" MIDR, - sysfs, RC_CHK_ACCESS(cpus)->map[cpu].cpu); + sysfs, cpu.cpu); file = fopen(path, "r"); if (!file) { diff --git a/tools/perf/tests/bitmap.c b/tools/perf/tests/bitmap.c index 0173f5402a35..98956e0e0765 100644 --- a/tools/perf/tests/bitmap.c +++ b/tools/perf/tests/bitmap.c @@ -11,18 +11,19 @@ static unsigned long *get_bitmap(const char *str, int nbits) { struct perf_cpu_map *map = perf_cpu_map__new(str); - unsigned long *bm = NULL; - int i; + unsigned long *bm; bm = bitmap_zalloc(nbits); if (map && bm) { - for (i = 0; i < perf_cpu_map__nr(map); i++) - __set_bit(perf_cpu_map__cpu(map, i).cpu, bm); + int i; + struct perf_cpu cpu; + + perf_cpu_map__for_each_cpu(cpu, i, map) + __set_bit(cpu.cpu, bm); } - if (map) - perf_cpu_map__put(map); + perf_cpu_map__put(map); return bm; } diff --git a/tools/perf/tests/topology.c b/tools/perf/tests/topology.c index 2a842f53fbb5..a8cb5ba898ab 100644 --- a/tools/perf/tests/topology.c +++ b/tools/perf/tests/topology.c @@ -68,6 +68,7 @@ static int check_cpu_topology(char *path, struct perf_cpu_map *map) }; int i; struct aggr_cpu_id id; + struct perf_cpu cpu; session = perf_session__new(&data, NULL); TEST_ASSERT_VAL("can't get session", !IS_ERR(session)); @@ -113,8 +114,7 @@ static int check_cpu_topology(char *path, struct perf_cpu_map *map) TEST_ASSERT_VAL("Session header CPU map not set", session->header.env.cpu); for (i = 0; i < session->header.env.nr_cpus_avail; i++) { - struct perf_cpu cpu = { .cpu = i }; - + cpu.cpu = i; if (!perf_cpu_map__has(map, cpu)) continue; pr_debug("CPU %d, core %d, socket %d\n", i, @@ -123,48 +123,48 @@ static int check_cpu_topology(char *path, struct perf_cpu_map *map) } // Test that CPU ID contains socket, die, core and CPU - for (i = 0; i < perf_cpu_map__nr(map); i++) { - id = aggr_cpu_id__cpu(perf_cpu_map__cpu(map, i), NULL); + perf_cpu_map__for_each_cpu(cpu, i, map) { + id = aggr_cpu_id__cpu(cpu, NULL); TEST_ASSERT_VAL("Cpu map - CPU ID doesn't match", - perf_cpu_map__cpu(map, i).cpu == id.cpu.cpu); + cpu.cpu == id.cpu.cpu); TEST_ASSERT_VAL("Cpu map - Core ID doesn't match", - session->header.env.cpu[perf_cpu_map__cpu(map, i).cpu].core_id == id.core); + session->header.env.cpu[cpu.cpu].core_id == id.core); TEST_ASSERT_VAL("Cpu map - Socket ID doesn't match", - session->header.env.cpu[perf_cpu_map__cpu(map, i).cpu].socket_id == + session->header.env.cpu[cpu.cpu].socket_id == id.socket); TEST_ASSERT_VAL("Cpu map - Die ID doesn't match", - session->header.env.cpu[perf_cpu_map__cpu(map, i).cpu].die_id == id.die); + session->header.env.cpu[cpu.cpu].die_id == id.die); TEST_ASSERT_VAL("Cpu map - Node ID is set", id.node == -1); TEST_ASSERT_VAL("Cpu map - Thread IDX is set", id.thread_idx == -1); } // Test that core ID contains socket, die and core - for (i = 0; i < perf_cpu_map__nr(map); i++) { - id = aggr_cpu_id__core(perf_cpu_map__cpu(map, i), NULL); + perf_cpu_map__for_each_cpu(cpu, i, map) { + id = aggr_cpu_id__core(cpu, NULL); TEST_ASSERT_VAL("Core map - Core ID doesn't match", - session->header.env.cpu[perf_cpu_map__cpu(map, i).cpu].core_id == id.core); + session->header.env.cpu[cpu.cpu].core_id == id.core); TEST_ASSERT_VAL("Core map - Socket ID doesn't match", - session->header.env.cpu[perf_cpu_map__cpu(map, i).cpu].socket_id == + session->header.env.cpu[cpu.cpu].socket_id == id.socket); TEST_ASSERT_VAL("Core map - Die ID doesn't match", - session->header.env.cpu[perf_cpu_map__cpu(map, i).cpu].die_id == id.die); + session->header.env.cpu[cpu.cpu].die_id == id.die); TEST_ASSERT_VAL("Core map - Node ID is set", id.node == -1); TEST_ASSERT_VAL("Core map - Thread IDX is set", id.thread_idx == -1); } // Test that die ID contains socket and die - for (i = 0; i < perf_cpu_map__nr(map); i++) { - id = aggr_cpu_id__die(perf_cpu_map__cpu(map, i), NULL); + perf_cpu_map__for_each_cpu(cpu, i, map) { + id = aggr_cpu_id__die(cpu, NULL); TEST_ASSERT_VAL("Die map - Socket ID doesn't match", - session->header.env.cpu[perf_cpu_map__cpu(map, i).cpu].socket_id == + session->header.env.cpu[cpu.cpu].socket_id == id.socket); TEST_ASSERT_VAL("Die map - Die ID doesn't match", - session->header.env.cpu[perf_cpu_map__cpu(map, i).cpu].die_id == id.die); + session->header.env.cpu[cpu.cpu].die_id == id.die); TEST_ASSERT_VAL("Die map - Node ID is set", id.node == -1); TEST_ASSERT_VAL("Die map - Core is set", id.core == -1); @@ -173,10 +173,10 @@ static int check_cpu_topology(char *path, struct perf_cpu_map *map) } // Test that socket ID contains only socket - for (i = 0; i < perf_cpu_map__nr(map); i++) { - id = aggr_cpu_id__socket(perf_cpu_map__cpu(map, i), NULL); + perf_cpu_map__for_each_cpu(cpu, i, map) { + id = aggr_cpu_id__socket(cpu, NULL); TEST_ASSERT_VAL("Socket map - Socket ID doesn't match", - session->header.env.cpu[perf_cpu_map__cpu(map, i).cpu].socket_id == + session->header.env.cpu[cpu.cpu].socket_id == id.socket); TEST_ASSERT_VAL("Socket map - Node ID is set", id.node == -1); @@ -187,10 +187,10 @@ static int check_cpu_topology(char *path, struct perf_cpu_map *map) } // Test that node ID contains only node - for (i = 0; i < perf_cpu_map__nr(map); i++) { - id = aggr_cpu_id__node(perf_cpu_map__cpu(map, i), NULL); + perf_cpu_map__for_each_cpu(cpu, i, map) { + id = aggr_cpu_id__node(cpu, NULL); TEST_ASSERT_VAL("Node map - Node ID doesn't match", - cpu__get_node(perf_cpu_map__cpu(map, i)) == id.node); + cpu__get_node(cpu) == id.node); TEST_ASSERT_VAL("Node map - Socket is set", id.socket == -1); TEST_ASSERT_VAL("Node map - Die ID is set", id.die == -1); TEST_ASSERT_VAL("Node map - Core is set", id.core == -1); diff --git a/tools/perf/util/bpf_kwork.c b/tools/perf/util/bpf_kwork.c index 6eb2c78fd7f4..44f0f708a15d 100644 --- a/tools/perf/util/bpf_kwork.c +++ b/tools/perf/util/bpf_kwork.c @@ -147,12 +147,12 @@ static bool valid_kwork_class_type(enum kwork_class_type type) static int setup_filters(struct perf_kwork *kwork) { - u8 val = 1; - int i, nr_cpus, key, fd; - struct perf_cpu_map *map; - if (kwork->cpu_list != NULL) { - fd = bpf_map__fd(skel->maps.perf_kwork_cpu_filter); + int idx, nr_cpus; + struct perf_cpu_map *map; + struct perf_cpu cpu; + int fd = bpf_map__fd(skel->maps.perf_kwork_cpu_filter); + if (fd < 0) { pr_debug("Invalid cpu filter fd\n"); return -1; @@ -165,8 +165,8 @@ static int setup_filters(struct perf_kwork *kwork) } nr_cpus = libbpf_num_possible_cpus(); - for (i = 0; i < perf_cpu_map__nr(map); i++) { - struct perf_cpu cpu = perf_cpu_map__cpu(map, i); + perf_cpu_map__for_each_cpu(cpu, idx, map) { + u8 val = 1; if (cpu.cpu >= nr_cpus) { perf_cpu_map__put(map); @@ -181,6 +181,8 @@ static int setup_filters(struct perf_kwork *kwork) } if (kwork->profile_name != NULL) { + int key, fd; + if (strlen(kwork->profile_name) >= MAX_KWORKNAME) { pr_err("Requested name filter %s too large, limit to %d\n", kwork->profile_name, MAX_KWORKNAME - 1); diff --git a/tools/perf/util/bpf_kwork_top.c b/tools/perf/util/bpf_kwork_top.c index 035e02272790..22a3b00a1e23 100644 --- a/tools/perf/util/bpf_kwork_top.c +++ b/tools/perf/util/bpf_kwork_top.c @@ -122,11 +122,11 @@ static bool valid_kwork_class_type(enum kwork_class_type type) static int setup_filters(struct perf_kwork *kwork) { - u8 val = 1; - int i, nr_cpus, fd; - struct perf_cpu_map *map; - if (kwork->cpu_list) { + int idx, nr_cpus, fd; + struct perf_cpu_map *map; + struct perf_cpu cpu; + fd = bpf_map__fd(skel->maps.kwork_top_cpu_filter); if (fd < 0) { pr_debug("Invalid cpu filter fd\n"); @@ -140,8 +140,8 @@ static int setup_filters(struct perf_kwork *kwork) } nr_cpus = libbpf_num_possible_cpus(); - for (i = 0; i < perf_cpu_map__nr(map); i++) { - struct perf_cpu cpu = perf_cpu_map__cpu(map, i); + perf_cpu_map__for_each_cpu(cpu, idx, map) { + u8 val = 1; if (cpu.cpu >= nr_cpus) { perf_cpu_map__put(map); diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c index 356e30c42cd8..6a270d640acb 100644 --- a/tools/perf/util/cpumap.c +++ b/tools/perf/util/cpumap.c @@ -655,10 +655,10 @@ static char hex_char(unsigned char val) size_t cpu_map__snprint_mask(struct perf_cpu_map *map, char *buf, size_t size) { - int i, cpu; + int idx; char *ptr = buf; unsigned char *bitmap; - struct perf_cpu last_cpu = perf_cpu_map__cpu(map, perf_cpu_map__nr(map) - 1); + struct perf_cpu c, last_cpu = perf_cpu_map__max(map); if (buf == NULL) return 0; @@ -669,12 +669,10 @@ size_t cpu_map__snprint_mask(struct perf_cpu_map *map, char *buf, size_t size) return 0; } - for (i = 0; i < perf_cpu_map__nr(map); i++) { - cpu = perf_cpu_map__cpu(map, i).cpu; - bitmap[cpu / 8] |= 1 << (cpu % 8); - } + perf_cpu_map__for_each_cpu(c, idx, map) + bitmap[c.cpu / 8] |= 1 << (c.cpu % 8); - for (cpu = last_cpu.cpu / 4 * 4; cpu >= 0; cpu -= 4) { + for (int cpu = last_cpu.cpu / 4 * 4; cpu >= 0; cpu -= 4) { unsigned char bits = bitmap[cpu / 8]; if (cpu % 8) diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index b4f0f60e60a6..8aa301948de5 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -1699,13 +1699,15 @@ static void python_process_stat(struct perf_stat_config *config, { struct perf_thread_map *threads = counter->core.threads; struct perf_cpu_map *cpus = counter->core.cpus; - int cpu, thread; - for (thread = 0; thread < perf_thread_map__nr(threads); thread++) { - for (cpu = 0; cpu < perf_cpu_map__nr(cpus); cpu++) { - process_stat(counter, perf_cpu_map__cpu(cpus, cpu), + for (int thread = 0; thread < perf_thread_map__nr(threads); thread++) { + int idx; + struct perf_cpu cpu; + + perf_cpu_map__for_each_cpu(cpu, idx, cpus) { + process_stat(counter, cpu, perf_thread_map__pid(threads, thread), tstamp, - perf_counts(counter->counts, cpu, thread)); + perf_counts(counter->counts, idx, thread)); } } } diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 06d0bd7fb459..02a932a83c51 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -2749,6 +2749,7 @@ int perf_session__cpu_bitmap(struct perf_session *session, int i, err = -1; struct perf_cpu_map *map; int nr_cpus = min(session->header.env.nr_cpus_avail, MAX_NR_CPUS); + struct perf_cpu cpu; for (i = 0; i < PERF_TYPE_MAX; ++i) { struct evsel *evsel; @@ -2770,9 +2771,7 @@ int perf_session__cpu_bitmap(struct perf_session *session, return -1; } - for (i = 0; i < perf_cpu_map__nr(map); i++) { - struct perf_cpu cpu = perf_cpu_map__cpu(map, i); - + perf_cpu_map__for_each_cpu(cpu, i, map) { if (cpu.cpu >= nr_cpus) { pr_err("Requested CPU %d too large. " "Consider raising MAX_NR_CPUS\n", cpu.cpu); diff --git a/tools/perf/util/svghelper.c b/tools/perf/util/svghelper.c index 1892e9b6aa7f..2b04f47f4db0 100644 --- a/tools/perf/util/svghelper.c +++ b/tools/perf/util/svghelper.c @@ -725,26 +725,24 @@ static void scan_core_topology(int *map, struct topology *t, int nr_cpus) static int str_to_bitmap(char *s, cpumask_t *b, int nr_cpus) { - int i; - int ret = 0; - struct perf_cpu_map *m; - struct perf_cpu c; + int idx, ret = 0; + struct perf_cpu_map *map; + struct perf_cpu cpu; - m = perf_cpu_map__new(s); - if (!m) + map = perf_cpu_map__new(s); + if (!map) return -1; - for (i = 0; i < perf_cpu_map__nr(m); i++) { - c = perf_cpu_map__cpu(m, i); - if (c.cpu >= nr_cpus) { + perf_cpu_map__for_each_cpu(cpu, idx, map) { + if (cpu.cpu >= nr_cpus) { ret = -1; break; } - __set_bit(c.cpu, cpumask_bits(b)); + __set_bit(cpu.cpu, cpumask_bits(b)); } - perf_cpu_map__put(m); + perf_cpu_map__put(map); return ret; } -- cgit v1.2.3-59-g8ed1b From b508965d35321534e84daf8946b2cc5f64517db9 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Mon, 18 Mar 2024 22:50:53 -0700 Subject: perf dwarf-aux: Remove unused pc argument It's not used, let's get rid of it. Signed-off-by: Namhyung Kim Reviewed-by: Arnaldo Carvalho de Melo Cc: Adrian Hunter Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Linus Torvalds Cc: Masami Hiramatsu Cc: Peter Zijlstra Cc: Stephane Eranian Link: https://lore.kernel.org/r/20240319055115.4063940-2-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate-data.c | 4 ++-- tools/perf/util/dwarf-aux.c | 7 ++----- tools/perf/util/dwarf-aux.h | 6 ++---- 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c index 30c4d19fcf11..59ce5f4f4a40 100644 --- a/tools/perf/util/annotate-data.c +++ b/tools/perf/util/annotate-data.c @@ -263,7 +263,7 @@ static int find_data_type_die(struct debuginfo *di, u64 pc, u64 addr, offset = loc->offset; if (reg == DWARF_REG_PC) { - if (die_find_variable_by_addr(&cu_die, pc, addr, &var_die, &offset)) { + if (die_find_variable_by_addr(&cu_die, addr, &var_die, &offset)) { ret = check_variable(&var_die, type_die, offset, /*is_pointer=*/false); loc->offset = offset; @@ -312,7 +312,7 @@ retry: /* Search from the inner-most scope to the outer */ for (i = nr_scopes - 1; i >= 0; i--) { if (reg == DWARF_REG_PC) { - if (!die_find_variable_by_addr(&scopes[i], pc, addr, + if (!die_find_variable_by_addr(&scopes[i], addr, &var_die, &offset)) continue; } else { diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c index 2791126069b4..e84d0d6a7750 100644 --- a/tools/perf/util/dwarf-aux.c +++ b/tools/perf/util/dwarf-aux.c @@ -1456,7 +1456,6 @@ static int __die_find_var_addr_cb(Dwarf_Die *die_mem, void *arg) /** * die_find_variable_by_addr - Find variable located at given address * @sc_die: a scope DIE - * @pc: the program address to find * @addr: the data address to find * @die_mem: a buffer to save the resulting DIE * @offset: the offset in the resulting type @@ -1464,12 +1463,10 @@ static int __die_find_var_addr_cb(Dwarf_Die *die_mem, void *arg) * Find the variable DIE located at the given address (in PC-relative mode). * This is usually for global variables. */ -Dwarf_Die *die_find_variable_by_addr(Dwarf_Die *sc_die, Dwarf_Addr pc, - Dwarf_Addr addr, Dwarf_Die *die_mem, - int *offset) +Dwarf_Die *die_find_variable_by_addr(Dwarf_Die *sc_die, Dwarf_Addr addr, + Dwarf_Die *die_mem, int *offset) { struct find_var_data data = { - .pc = pc, .addr = addr, }; Dwarf_Die *result; diff --git a/tools/perf/util/dwarf-aux.h b/tools/perf/util/dwarf-aux.h index 85dd527ae1f7..9973801a20c1 100644 --- a/tools/perf/util/dwarf-aux.h +++ b/tools/perf/util/dwarf-aux.h @@ -146,9 +146,8 @@ Dwarf_Die *die_find_variable_by_reg(Dwarf_Die *sc_die, Dwarf_Addr pc, int reg, Dwarf_Die *die_mem); /* Find a (global) variable located in the 'addr' */ -Dwarf_Die *die_find_variable_by_addr(Dwarf_Die *sc_die, Dwarf_Addr pc, - Dwarf_Addr addr, Dwarf_Die *die_mem, - int *offset); +Dwarf_Die *die_find_variable_by_addr(Dwarf_Die *sc_die, Dwarf_Addr addr, + Dwarf_Die *die_mem, int *offset); #else /* HAVE_DWARF_GETLOCATIONS_SUPPORT */ @@ -170,7 +169,6 @@ static inline Dwarf_Die *die_find_variable_by_reg(Dwarf_Die *sc_die __maybe_unus } static inline Dwarf_Die *die_find_variable_by_addr(Dwarf_Die *sc_die __maybe_unused, - Dwarf_Addr pc __maybe_unused, Dwarf_Addr addr __maybe_unused, Dwarf_Die *die_mem __maybe_unused, int *offset __maybe_unused) -- cgit v1.2.3-59-g8ed1b From 932dcc2c39aedf54ef291bc0b4129a54f5fe1e84 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Mon, 18 Mar 2024 22:50:54 -0700 Subject: perf dwarf-aux: Add die_collect_vars() The die_collect_vars() is to find all variable information in the scope including function parameters. The struct die_var_type is to save the type of the variable with the location (reg and offset) as well as where it's defined in the code (addr). Signed-off-by: Namhyung Kim Acked-by: Masami Hiramatsu Cc: Adrian Hunter Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Stephane Eranian Link: https://lore.kernel.org/r/20240319055115.4063940-3-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/dwarf-aux.c | 118 +++++++++++++++++++++++++++++++++----------- tools/perf/util/dwarf-aux.h | 17 +++++++ 2 files changed, 107 insertions(+), 28 deletions(-) diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c index e84d0d6a7750..785aa7a3d725 100644 --- a/tools/perf/util/dwarf-aux.c +++ b/tools/perf/util/dwarf-aux.c @@ -1136,6 +1136,40 @@ int die_get_varname(Dwarf_Die *vr_die, struct strbuf *buf) return ret < 0 ? ret : strbuf_addf(buf, "\t%s", dwarf_diename(vr_die)); } +#if defined(HAVE_DWARF_GETLOCATIONS_SUPPORT) || defined(HAVE_DWARF_CFI_SUPPORT) +static int reg_from_dwarf_op(Dwarf_Op *op) +{ + switch (op->atom) { + case DW_OP_reg0 ... DW_OP_reg31: + return op->atom - DW_OP_reg0; + case DW_OP_breg0 ... DW_OP_breg31: + return op->atom - DW_OP_breg0; + case DW_OP_regx: + case DW_OP_bregx: + return op->number; + default: + break; + } + return -1; +} + +static int offset_from_dwarf_op(Dwarf_Op *op) +{ + switch (op->atom) { + case DW_OP_reg0 ... DW_OP_reg31: + case DW_OP_regx: + return 0; + case DW_OP_breg0 ... DW_OP_breg31: + return op->number; + case DW_OP_bregx: + return op->number2; + default: + break; + } + return -1; +} +#endif /* HAVE_DWARF_GETLOCATIONS_SUPPORT || HAVE_DWARF_CFI_SUPPORT */ + #ifdef HAVE_DWARF_GETLOCATIONS_SUPPORT /** * die_get_var_innermost_scope - Get innermost scope range of given variable DIE @@ -1476,41 +1510,69 @@ Dwarf_Die *die_find_variable_by_addr(Dwarf_Die *sc_die, Dwarf_Addr addr, *offset = data.offset; return result; } -#endif /* HAVE_DWARF_GETLOCATIONS_SUPPORT */ -#ifdef HAVE_DWARF_CFI_SUPPORT -static int reg_from_dwarf_op(Dwarf_Op *op) +static int __die_collect_vars_cb(Dwarf_Die *die_mem, void *arg) { - switch (op->atom) { - case DW_OP_reg0 ... DW_OP_reg31: - return op->atom - DW_OP_reg0; - case DW_OP_breg0 ... DW_OP_breg31: - return op->atom - DW_OP_breg0; - case DW_OP_regx: - case DW_OP_bregx: - return op->number; - default: - break; - } - return -1; + struct die_var_type **var_types = arg; + Dwarf_Die type_die; + int tag = dwarf_tag(die_mem); + Dwarf_Attribute attr; + Dwarf_Addr base, start, end; + Dwarf_Op *ops; + size_t nops; + struct die_var_type *vt; + + if (tag != DW_TAG_variable && tag != DW_TAG_formal_parameter) + return DIE_FIND_CB_SIBLING; + + if (dwarf_attr(die_mem, DW_AT_location, &attr) == NULL) + return DIE_FIND_CB_SIBLING; + + /* + * Only collect the first location as it can reconstruct the + * remaining state by following the instructions. + * start = 0 means it covers the whole range. + */ + if (dwarf_getlocations(&attr, 0, &base, &start, &end, &ops, &nops) <= 0) + return DIE_FIND_CB_SIBLING; + + if (die_get_real_type(die_mem, &type_die) == NULL) + return DIE_FIND_CB_SIBLING; + + vt = malloc(sizeof(*vt)); + if (vt == NULL) + return DIE_FIND_CB_END; + + vt->die_off = dwarf_dieoffset(&type_die); + vt->addr = start; + vt->reg = reg_from_dwarf_op(ops); + vt->offset = offset_from_dwarf_op(ops); + vt->next = *var_types; + *var_types = vt; + + return DIE_FIND_CB_SIBLING; } -static int offset_from_dwarf_op(Dwarf_Op *op) +/** + * die_collect_vars - Save all variables and parameters + * @sc_die: a scope DIE + * @var_types: a pointer to save the resulting list + * + * Save all variables and parameters in the @sc_die and save them to @var_types. + * The @var_types is a singly-linked list containing type and location info. + * Actual type can be retrieved using dwarf_offdie() with 'die_off' later. + * + * Callers should free @var_types. + */ +void die_collect_vars(Dwarf_Die *sc_die, struct die_var_type **var_types) { - switch (op->atom) { - case DW_OP_reg0 ... DW_OP_reg31: - case DW_OP_regx: - return 0; - case DW_OP_breg0 ... DW_OP_breg31: - return op->number; - case DW_OP_bregx: - return op->number2; - default: - break; - } - return -1; + Dwarf_Die die_mem; + + die_find_child(sc_die, __die_collect_vars_cb, (void *)var_types, &die_mem); } +#endif /* HAVE_DWARF_GETLOCATIONS_SUPPORT */ +#ifdef HAVE_DWARF_CFI_SUPPORT /** * die_get_cfa - Get frame base information * @dwarf: a Dwarf info diff --git a/tools/perf/util/dwarf-aux.h b/tools/perf/util/dwarf-aux.h index 9973801a20c1..cd171b06fd4c 100644 --- a/tools/perf/util/dwarf-aux.h +++ b/tools/perf/util/dwarf-aux.h @@ -135,6 +135,15 @@ void die_skip_prologue(Dwarf_Die *sp_die, Dwarf_Die *cu_die, /* Get the list of including scopes */ int die_get_scopes(Dwarf_Die *cu_die, Dwarf_Addr pc, Dwarf_Die **scopes); +/* Variable type information */ +struct die_var_type { + struct die_var_type *next; + u64 die_off; + u64 addr; + int reg; + int offset; +}; + #ifdef HAVE_DWARF_GETLOCATIONS_SUPPORT /* Get byte offset range of given variable DIE */ @@ -149,6 +158,9 @@ Dwarf_Die *die_find_variable_by_reg(Dwarf_Die *sc_die, Dwarf_Addr pc, int reg, Dwarf_Die *die_find_variable_by_addr(Dwarf_Die *sc_die, Dwarf_Addr addr, Dwarf_Die *die_mem, int *offset); +/* Save all variables and parameters in this scope */ +void die_collect_vars(Dwarf_Die *sc_die, struct die_var_type **var_types); + #else /* HAVE_DWARF_GETLOCATIONS_SUPPORT */ static inline int die_get_var_range(Dwarf_Die *sp_die __maybe_unused, @@ -176,6 +188,11 @@ static inline Dwarf_Die *die_find_variable_by_addr(Dwarf_Die *sc_die __maybe_unu return NULL; } +static inline void die_collect_vars(Dwarf_Die *sc_die __maybe_unused, + struct die_var_type **var_types __maybe_unused) +{ +} + #endif /* HAVE_DWARF_GETLOCATIONS_SUPPORT */ #ifdef HAVE_DWARF_CFI_SUPPORT -- cgit v1.2.3-59-g8ed1b From 437683a9941891c17059d99561eb3ce85e0f51fa Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Mon, 18 Mar 2024 22:50:55 -0700 Subject: perf dwarf-aux: Handle type transfer for memory access We want to track type states as instructions are executed. Each instruction can access compound types like struct or union and load/ store its members to a different location. The die_deref_ptr_type() is to find a type of memory access with a pointer variable. If it points to a compound type like struct, the target memory is a member in the struct. The access will happen with an offset indicating which member it refers. Let's follow the DWARF info to figure out the type of the pointer target. For example, say we have the following code. struct foo { int a; int b; }; struct foo *p = malloc(sizeof(*p)); p->b = 0; The last pointer access should produce x86 asm like below: mov 0x0, 4(%rbx) And we know %rbx register has a pointer to struct foo. Then offset 4 should return the debug info of member 'b'. Also variables of compound types can be accessed directly without a pointer. The die_get_member_type() is to handle a such case. Signed-off-by: Namhyung Kim Acked-by: Masami Hiramatsu Cc: Adrian Hunter Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Stephane Eranian Link: https://lore.kernel.org/r/20240319055115.4063940-4-namhyung@kernel.org [ Check if die_get_real_type() returned NULL ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/dwarf-aux.c | 113 ++++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/dwarf-aux.h | 6 +++ 2 files changed, 119 insertions(+) diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c index 785aa7a3d725..09fd6f1f0ed8 100644 --- a/tools/perf/util/dwarf-aux.c +++ b/tools/perf/util/dwarf-aux.c @@ -1838,3 +1838,116 @@ int die_get_scopes(Dwarf_Die *cu_die, Dwarf_Addr pc, Dwarf_Die **scopes) *scopes = data.scopes; return data.nr; } + +static int __die_find_member_offset_cb(Dwarf_Die *die_mem, void *arg) +{ + Dwarf_Die type_die; + Dwarf_Word size, loc; + Dwarf_Word offset = (long)arg; + int tag = dwarf_tag(die_mem); + + if (tag != DW_TAG_member) + return DIE_FIND_CB_SIBLING; + + /* Unions might not have location */ + if (die_get_data_member_location(die_mem, &loc) < 0) + loc = 0; + + if (offset == loc) + return DIE_FIND_CB_END; + + if (die_get_real_type(die_mem, &type_die) == NULL) { + // TODO: add a pr_debug_dtp() later for this unlikely failure + return DIE_FIND_CB_SIBLING; + } + + if (dwarf_aggregate_size(&type_die, &size) < 0) + size = 0; + + if (loc < offset && offset < (loc + size)) + return DIE_FIND_CB_END; + + return DIE_FIND_CB_SIBLING; +} + +/** + * die_get_member_type - Return type info of struct member + * @type_die: a type DIE + * @offset: offset in the type + * @die_mem: a buffer to save the resulting DIE + * + * This function returns a type of a member in @type_die where it's located at + * @offset if it's a struct. For now, it just returns the first matching + * member in a union. For other types, it'd return the given type directly + * if it's within the size of the type or NULL otherwise. + */ +Dwarf_Die *die_get_member_type(Dwarf_Die *type_die, int offset, + Dwarf_Die *die_mem) +{ + Dwarf_Die *member; + Dwarf_Die mb_type; + int tag; + + tag = dwarf_tag(type_die); + /* If it's not a compound type, return the type directly */ + if (tag != DW_TAG_structure_type && tag != DW_TAG_union_type) { + Dwarf_Word size; + + if (dwarf_aggregate_size(type_die, &size) < 0) + size = 0; + + if ((unsigned)offset >= size) + return NULL; + + *die_mem = *type_die; + return die_mem; + } + + mb_type = *type_die; + /* TODO: Handle union types better? */ + while (tag == DW_TAG_structure_type || tag == DW_TAG_union_type) { + member = die_find_child(&mb_type, __die_find_member_offset_cb, + (void *)(long)offset, die_mem); + if (member == NULL) + return NULL; + + if (die_get_real_type(member, &mb_type) == NULL) + return NULL; + + tag = dwarf_tag(&mb_type); + + if (tag == DW_TAG_structure_type || tag == DW_TAG_union_type) { + Dwarf_Word loc; + + /* Update offset for the start of the member struct */ + if (die_get_data_member_location(member, &loc) == 0) + offset -= loc; + } + } + *die_mem = mb_type; + return die_mem; +} + +/** + * die_deref_ptr_type - Return type info for pointer access + * @ptr_die: a pointer type DIE + * @offset: access offset for the pointer + * @die_mem: a buffer to save the resulting DIE + * + * This function follows the pointer in @ptr_die with given @offset + * and saves the resulting type in @die_mem. If the pointer points + * a struct type, actual member at the offset would be returned. + */ +Dwarf_Die *die_deref_ptr_type(Dwarf_Die *ptr_die, int offset, + Dwarf_Die *die_mem) +{ + Dwarf_Die type_die; + + if (dwarf_tag(ptr_die) != DW_TAG_pointer_type) + return NULL; + + if (die_get_real_type(ptr_die, &type_die) == NULL) + return NULL; + + return die_get_member_type(&type_die, offset, die_mem); +} diff --git a/tools/perf/util/dwarf-aux.h b/tools/perf/util/dwarf-aux.h index cd171b06fd4c..16c916311bc0 100644 --- a/tools/perf/util/dwarf-aux.h +++ b/tools/perf/util/dwarf-aux.h @@ -144,6 +144,12 @@ struct die_var_type { int offset; }; +/* Return type info of a member at offset */ +Dwarf_Die *die_get_member_type(Dwarf_Die *type_die, int offset, Dwarf_Die *die_mem); + +/* Return type info where the pointer and offset point to */ +Dwarf_Die *die_deref_ptr_type(Dwarf_Die *ptr_die, int offset, Dwarf_Die *die_mem); + #ifdef HAVE_DWARF_GETLOCATIONS_SUPPORT /* Get byte offset range of given variable DIE */ -- cgit v1.2.3-59-g8ed1b From 7a838c2fd2ac81e10bedcd912153a74ca662b309 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Mon, 18 Mar 2024 22:50:56 -0700 Subject: perf dwarf-aux: Add die_find_func_rettype() The die_find_func_rettype() is to find a debug entry for the given function name and sets the type information of the return value. By convention, it'd return the pointer to the type die (should be the same as the given mem_die argument) if found, or NULL otherwise. Signed-off-by: Namhyung Kim Cc: Adrian Hunter Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Linus Torvalds Cc: Masami Hiramatsu Cc: Peter Zijlstra Cc: Stephane Eranian Link: https://lore.kernel.org/r/20240319055115.4063940-5-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/dwarf-aux.c | 43 +++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/dwarf-aux.h | 4 ++++ 2 files changed, 47 insertions(+) diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c index 09fd6f1f0ed8..d4ec239c5adb 100644 --- a/tools/perf/util/dwarf-aux.c +++ b/tools/perf/util/dwarf-aux.c @@ -696,6 +696,49 @@ Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr, return die_mem; } +static int __die_find_func_rettype_cb(Dwarf_Die *die_mem, void *data) +{ + const char *func_name; + + if (dwarf_tag(die_mem) != DW_TAG_subprogram) + return DIE_FIND_CB_SIBLING; + + func_name = dwarf_diename(die_mem); + if (func_name && !strcmp(func_name, data)) + return DIE_FIND_CB_END; + + return DIE_FIND_CB_SIBLING; +} + +/** + * die_find_func_rettype - Search a return type of function + * @cu_die: a CU DIE + * @name: target function name + * @die_mem: a buffer for result DIE + * + * Search a non-inlined function which matches to @name and stores the + * return type of the function to @die_mem and returns it if found. + * Returns NULL if failed. Note that it doesn't needs to find a + * definition of the function, so it doesn't match with address. + * Most likely, it can find a declaration at the top level. Thus the + * callback function continues to sibling entries only. + */ +Dwarf_Die *die_find_func_rettype(Dwarf_Die *cu_die, const char *name, + Dwarf_Die *die_mem) +{ + Dwarf_Die tmp_die; + + cu_die = die_find_child(cu_die, __die_find_func_rettype_cb, + (void *)name, &tmp_die); + if (!cu_die) + return NULL; + + if (die_get_real_type(&tmp_die, die_mem) == NULL) + return NULL; + + return die_mem; +} + struct __instance_walk_param { void *addr; int (*callback)(Dwarf_Die *, void *); diff --git a/tools/perf/util/dwarf-aux.h b/tools/perf/util/dwarf-aux.h index 16c916311bc0..b0f25fbf9668 100644 --- a/tools/perf/util/dwarf-aux.h +++ b/tools/perf/util/dwarf-aux.h @@ -94,6 +94,10 @@ Dwarf_Die *die_find_top_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr, Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr, Dwarf_Die *die_mem); +/* Search a non-inlined function by name and returns its return type */ +Dwarf_Die *die_find_func_rettype(Dwarf_Die *sp_die, const char *name, + Dwarf_Die *die_mem); + /* Walk on the instances of given DIE */ int die_walk_instances(Dwarf_Die *in_die, int (*callback)(Dwarf_Die *, void *), void *data); -- cgit v1.2.3-59-g8ed1b From 52a09bc24c6a4deeeb8030476a7663b6696d73f0 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Mon, 18 Mar 2024 22:50:57 -0700 Subject: perf map: Add map__objdump_2rip() Sometimes we want to convert an address in objdump output to map-relative address to match with a sample data. Let's add map__objdump_2rip() for that. Signed-off-by: Namhyung Kim Cc: Adrian Hunter Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Linus Torvalds Cc: Masami Hiramatsu Cc: Peter Zijlstra Cc: Stephane Eranian Link: https://lore.kernel.org/r/20240319055115.4063940-6-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/map.c | 17 +++++++++++++++++ tools/perf/util/map.h | 3 +++ 2 files changed, 20 insertions(+) diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index 14a5ea70d81e..a5d57c201a30 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c @@ -587,6 +587,23 @@ u64 map__objdump_2mem(struct map *map, u64 ip) return ip + map__reloc(map); } +/* convert objdump address to relative address. (To be removed) */ +u64 map__objdump_2rip(struct map *map, u64 ip) +{ + const struct dso *dso = map__dso(map); + + if (!dso->adjust_symbols) + return ip; + + if (dso->rel) + return ip + map__pgoff(map); + + if (dso->kernel == DSO_SPACE__USER) + return ip - dso->text_offset; + + return map__map_ip(map, ip + map__reloc(map)); +} + bool map__contains_symbol(const struct map *map, const struct symbol *sym) { u64 ip = map__unmap_ip(map, sym->start); diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h index 49756716cb13..65e2609fa1b1 100644 --- a/tools/perf/util/map.h +++ b/tools/perf/util/map.h @@ -132,6 +132,9 @@ u64 map__rip_2objdump(struct map *map, u64 rip); /* objdump address -> memory address */ u64 map__objdump_2mem(struct map *map, u64 ip); +/* objdump address -> rip */ +u64 map__objdump_2rip(struct map *map, u64 ip); + struct symbol; struct thread; -- cgit v1.2.3-59-g8ed1b From a3f4d5b57dd8fd2a749be261d7253616f15671b5 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Mon, 18 Mar 2024 22:50:58 -0700 Subject: perf annotate-data: Introduce 'struct data_loc_info' The find_data_type() needs many information to describe the location of the data. Add the new 'struct data_loc_info' to pass those information at once. No functional changes intended. Signed-off-by: Namhyung Kim Cc: Adrian Hunter Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Linus Torvalds Cc: Masami Hiramatsu Cc: Peter Zijlstra Cc: Stephane Eranian Link: https://lore.kernel.org/r/20240319055115.4063940-7-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate-data.c | 83 ++++++++++++++++++++++------------------- tools/perf/util/annotate-data.h | 38 ++++++++++++++++--- tools/perf/util/annotate.c | 30 +++++++-------- 3 files changed, 91 insertions(+), 60 deletions(-) diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c index 59ce5f4f4a40..ff81d164aa57 100644 --- a/tools/perf/util/annotate-data.c +++ b/tools/perf/util/annotate-data.c @@ -239,21 +239,28 @@ static int check_variable(Dwarf_Die *var_die, Dwarf_Die *type_die, int offset, } /* The result will be saved in @type_die */ -static int find_data_type_die(struct debuginfo *di, u64 pc, u64 addr, - const char *var_name, struct annotated_op_loc *loc, - Dwarf_Die *type_die) +static int find_data_type_die(struct data_loc_info *dloc, Dwarf_Die *type_die) { + struct annotated_op_loc *loc = dloc->op; Dwarf_Die cu_die, var_die; Dwarf_Die *scopes = NULL; int reg, offset; int ret = -1; int i, nr_scopes; int fbreg = -1; - bool is_fbreg = false; int fb_offset = 0; + bool is_fbreg = false; + u64 pc; + + /* + * IP is a relative instruction address from the start of the map, as + * it can be randomized/relocated, it needs to translate to PC which is + * a file address for DWARF processing. + */ + pc = map__rip_2objdump(dloc->ms->map, dloc->ip); /* Get a compile_unit for this address */ - if (!find_cu_die(di, pc, &cu_die)) { + if (!find_cu_die(dloc->di, pc, &cu_die)) { pr_debug("cannot find CU for address %" PRIx64 "\n", pc); ann_data_stat.no_cuinfo++; return -1; @@ -263,18 +270,19 @@ static int find_data_type_die(struct debuginfo *di, u64 pc, u64 addr, offset = loc->offset; if (reg == DWARF_REG_PC) { - if (die_find_variable_by_addr(&cu_die, addr, &var_die, &offset)) { + if (die_find_variable_by_addr(&cu_die, dloc->var_addr, &var_die, + &offset)) { ret = check_variable(&var_die, type_die, offset, /*is_pointer=*/false); - loc->offset = offset; + dloc->type_offset = offset; goto out; } - if (var_name && die_find_variable_at(&cu_die, var_name, pc, - &var_die)) { - ret = check_variable(&var_die, type_die, 0, + if (dloc->var_name && + die_find_variable_at(&cu_die, dloc->var_name, pc, &var_die)) { + ret = check_variable(&var_die, type_die, dloc->type_offset, /*is_pointer=*/false); - /* loc->offset will be updated by the caller */ + /* dloc->type_offset was updated by the caller */ goto out; } } @@ -291,10 +299,11 @@ static int find_data_type_die(struct debuginfo *di, u64 pc, u64 addr, dwarf_formblock(&attr, &block) == 0 && block.length == 1) { switch (*block.data) { case DW_OP_reg0 ... DW_OP_reg31: - fbreg = *block.data - DW_OP_reg0; + fbreg = dloc->fbreg = *block.data - DW_OP_reg0; break; case DW_OP_call_frame_cfa: - if (die_get_cfa(di->dbg, pc, &fbreg, + dloc->fb_cfa = true; + if (die_get_cfa(dloc->di->dbg, pc, &fbreg, &fb_offset) < 0) fbreg = -1; break; @@ -312,7 +321,7 @@ retry: /* Search from the inner-most scope to the outer */ for (i = nr_scopes - 1; i >= 0; i--) { if (reg == DWARF_REG_PC) { - if (!die_find_variable_by_addr(&scopes[i], addr, + if (!die_find_variable_by_addr(&scopes[i], dloc->var_addr, &var_die, &offset)) continue; } else { @@ -325,7 +334,7 @@ retry: /* Found a variable, see if it's correct */ ret = check_variable(&var_die, type_die, offset, reg != DWARF_REG_PC && !is_fbreg); - loc->offset = offset; + dloc->type_offset = offset; goto out; } @@ -344,50 +353,46 @@ out: /** * find_data_type - Return a data type at the location - * @ms: map and symbol at the location - * @ip: instruction address of the memory access - * @loc: instruction operand location - * @addr: data address of the memory access - * @var_name: global variable name + * @dloc: data location * * This functions searches the debug information of the binary to get the data - * type it accesses. The exact location is expressed by (@ip, reg, offset) - * for pointer variables or (@ip, @addr) for global variables. Note that global - * variables might update the @loc->offset after finding the start of the variable. - * If it cannot find a global variable by address, it tried to fine a declaration - * of the variable using @var_name. In that case, @loc->offset won't be updated. + * type it accesses. The exact location is expressed by (ip, reg, offset) + * for pointer variables or (ip, addr) for global variables. Note that global + * variables might update the @dloc->type_offset after finding the start of the + * variable. If it cannot find a global variable by address, it tried to find + * a declaration of the variable using var_name. In that case, @dloc->offset + * won't be updated. * * It return %NULL if not found. */ -struct annotated_data_type *find_data_type(struct map_symbol *ms, u64 ip, - struct annotated_op_loc *loc, u64 addr, - const char *var_name) +struct annotated_data_type *find_data_type(struct data_loc_info *dloc) { struct annotated_data_type *result = NULL; - struct dso *dso = map__dso(ms->map); - struct debuginfo *di; + struct dso *dso = map__dso(dloc->ms->map); Dwarf_Die type_die; - u64 pc; - di = debuginfo__new(dso->long_name); - if (di == NULL) { + dloc->di = debuginfo__new(dso->long_name); + if (dloc->di == NULL) { pr_debug("cannot get the debug info\n"); return NULL; } /* - * IP is a relative instruction address from the start of the map, as - * it can be randomized/relocated, it needs to translate to PC which is - * a file address for DWARF processing. + * The type offset is the same as instruction offset by default. + * But when finding a global variable, the offset won't be valid. */ - pc = map__rip_2objdump(ms->map, ip); - if (find_data_type_die(di, pc, addr, var_name, loc, &type_die) < 0) + if (dloc->var_name == NULL) + dloc->type_offset = dloc->op->offset; + + dloc->fbreg = -1; + + if (find_data_type_die(dloc, &type_die) < 0) goto out; result = dso__findnew_data_type(dso, &type_die); out: - debuginfo__delete(di); + debuginfo__delete(dloc->di); return result; } diff --git a/tools/perf/util/annotate-data.h b/tools/perf/util/annotate-data.h index 1b0db8e8c40e..ad6493ea2c8e 100644 --- a/tools/perf/util/annotate-data.h +++ b/tools/perf/util/annotate-data.h @@ -8,6 +8,7 @@ #include struct annotated_op_loc; +struct debuginfo; struct evsel; struct map_symbol; @@ -72,6 +73,35 @@ struct annotated_data_type { extern struct annotated_data_type unknown_type; extern struct annotated_data_type stackop_type; +/** + * struct data_loc_info - Data location information + * @ms: Map and Symbol info + * @ip: Instruction address + * @var_addr: Data address (for global variables) + * @var_name: Variable name (for global variables) + * @op: Instruction operand location (regs and offset) + * @di: Debug info + * @fbreg: Frame base register + * @fb_cfa: Whether the frame needs to check CFA + * @type_offset: Final offset in the type + */ +struct data_loc_info { + /* These are input field, should be filled by caller */ + struct map_symbol *ms; + u64 ip; + u64 var_addr; + const char *var_name; + struct annotated_op_loc *op; + + /* These are used internally */ + struct debuginfo *di; + int fbreg; + bool fb_cfa; + + /* This is for the result */ + int type_offset; +}; + /** * struct annotated_data_stat - Debug statistics * @total: Total number of entry @@ -106,9 +136,7 @@ extern struct annotated_data_stat ann_data_stat; #ifdef HAVE_DWARF_SUPPORT /* Returns data type at the location (ip, reg, offset) */ -struct annotated_data_type *find_data_type(struct map_symbol *ms, u64 ip, - struct annotated_op_loc *loc, u64 addr, - const char *var_name); +struct annotated_data_type *find_data_type(struct data_loc_info *dloc); /* Update type access histogram at the given offset */ int annotated_data_type__update_samples(struct annotated_data_type *adt, @@ -121,9 +149,7 @@ void annotated_data_type__tree_delete(struct rb_root *root); #else /* HAVE_DWARF_SUPPORT */ static inline struct annotated_data_type * -find_data_type(struct map_symbol *ms __maybe_unused, u64 ip __maybe_unused, - struct annotated_op_loc *loc __maybe_unused, - u64 addr __maybe_unused, const char *var_name __maybe_unused) +find_data_type(struct data_loc_info *dloc __maybe_unused) { return NULL; } diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index ac002d907d81..a15ff6758210 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -3816,9 +3816,7 @@ struct annotated_data_type *hist_entry__get_data_type(struct hist_entry *he) struct annotated_op_loc *op_loc; struct annotated_data_type *mem_type; struct annotated_item_stat *istat; - u64 ip = he->ip, addr = 0; - const char *var_name = NULL; - int var_offset; + u64 ip = he->ip; int i; ann_data_stat.total++; @@ -3871,51 +3869,53 @@ retry: } for_each_insn_op_loc(&loc, i, op_loc) { + struct data_loc_info dloc = { + .ms = ms, + /* Recalculate IP for LOCK prefix or insn fusion */ + .ip = ms->sym->start + dl->al.offset, + .op = op_loc, + }; + if (!op_loc->mem_ref) continue; /* Recalculate IP because of LOCK prefix or insn fusion */ ip = ms->sym->start + dl->al.offset; - var_offset = op_loc->offset; - /* PC-relative addressing */ if (op_loc->reg1 == DWARF_REG_PC) { struct addr_location al; struct symbol *var; u64 map_addr; - addr = annotate_calc_pcrel(ms, ip, op_loc->offset, dl); + dloc.var_addr = annotate_calc_pcrel(ms, ip, op_loc->offset, dl); /* Kernel symbols might be relocated */ - map_addr = addr + map__reloc(ms->map); + map_addr = dloc.var_addr + map__reloc(ms->map); addr_location__init(&al); var = thread__find_symbol_fb(he->thread, he->cpumode, map_addr, &al); if (var) { - var_name = var->name; + dloc.var_name = var->name; /* Calculate type offset from the start of variable */ - var_offset = map_addr - map__unmap_ip(al.map, var->start); + dloc.type_offset = map_addr - map__unmap_ip(al.map, var->start); } addr_location__exit(&al); } - mem_type = find_data_type(ms, ip, op_loc, addr, var_name); + mem_type = find_data_type(&dloc); if (mem_type) istat->good++; else istat->bad++; - if (mem_type && var_name) - op_loc->offset = var_offset; - if (symbol_conf.annotate_data_sample) { annotated_data_type__update_samples(mem_type, evsel, - op_loc->offset, + dloc.type_offset, he->stat.nr_events, he->stat.period); } - he->mem_type_off = op_loc->offset; + he->mem_type_off = dloc.type_offset; return mem_type; } -- cgit v1.2.3-59-g8ed1b From 5cdd3fd7995a7a07b1654ea37e0fcc3c64f0cc44 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Mon, 18 Mar 2024 22:50:59 -0700 Subject: perf annotate: Add annotate_get_basic_blocks() The annotate_get_basic_blocks() is to find a list of basic blocks from the source instruction to the destination instruction in a function. It'll be used to find variables in a scope. Use BFS (Breadth First Search) to find a shortest path to carry the variable/register state minimally. Also change find_disasm_line() to be used in annotate_get_basic_blocks() and add 'allow_update' argument to control if it can update the IP. Signed-off-by: Namhyung Kim Cc: Adrian Hunter Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Linus Torvalds Cc: Masami Hiramatsu Cc: Peter Zijlstra Cc: Stephane Eranian Link: https://lore.kernel.org/r/20240319055115.4063940-8-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 222 ++++++++++++++++++++++++++++++++++++++++++++- tools/perf/util/annotate.h | 16 ++++ 2 files changed, 235 insertions(+), 3 deletions(-) diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index a15ff6758210..aa005c13ff67 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -3714,7 +3714,8 @@ static void symbol__ensure_annotate(struct map_symbol *ms, struct evsel *evsel) } } -static struct disasm_line *find_disasm_line(struct symbol *sym, u64 ip) +static struct disasm_line *find_disasm_line(struct symbol *sym, u64 ip, + bool allow_update) { struct disasm_line *dl; struct annotation *notes; @@ -3727,7 +3728,8 @@ static struct disasm_line *find_disasm_line(struct symbol *sym, u64 ip) * llvm-objdump places "lock" in a separate line and * in that case, we want to get the next line. */ - if (!strcmp(dl->ins.name, "lock") && *dl->ops.raw == '\0') { + if (!strcmp(dl->ins.name, "lock") && + *dl->ops.raw == '\0' && allow_update) { ip++; continue; } @@ -3843,7 +3845,7 @@ struct annotated_data_type *hist_entry__get_data_type(struct hist_entry *he) * Get a disasm to extract the location from the insn. * This is too slow... */ - dl = find_disasm_line(ms->sym, ip); + dl = find_disasm_line(ms->sym, ip, /*allow_update=*/true); if (dl == NULL) { ann_data_stat.no_insn++; return NULL; @@ -3937,3 +3939,217 @@ retry: istat->bad++; return NULL; } + +/* Basic block traversal (BFS) data structure */ +struct basic_block_data { + struct list_head queue; + struct list_head visited; +}; + +/* + * During the traversal, it needs to know the parent block where the current + * block block started from. Note that single basic block can be parent of + * two child basic blocks (in case of condition jump). + */ +struct basic_block_link { + struct list_head node; + struct basic_block_link *parent; + struct annotated_basic_block *bb; +}; + +/* Check any of basic block in the list already has the offset */ +static bool basic_block_has_offset(struct list_head *head, s64 offset) +{ + struct basic_block_link *link; + + list_for_each_entry(link, head, node) { + s64 begin_offset = link->bb->begin->al.offset; + s64 end_offset = link->bb->end->al.offset; + + if (begin_offset <= offset && offset <= end_offset) + return true; + } + return false; +} + +static bool is_new_basic_block(struct basic_block_data *bb_data, + struct disasm_line *dl) +{ + s64 offset = dl->al.offset; + + if (basic_block_has_offset(&bb_data->visited, offset)) + return false; + if (basic_block_has_offset(&bb_data->queue, offset)) + return false; + return true; +} + +/* Add a basic block starting from dl and link it to the parent */ +static int add_basic_block(struct basic_block_data *bb_data, + struct basic_block_link *parent, + struct disasm_line *dl) +{ + struct annotated_basic_block *bb; + struct basic_block_link *link; + + if (dl == NULL) + return -1; + + if (!is_new_basic_block(bb_data, dl)) + return 0; + + bb = zalloc(sizeof(*bb)); + if (bb == NULL) + return -1; + + bb->begin = dl; + bb->end = dl; + INIT_LIST_HEAD(&bb->list); + + link = malloc(sizeof(*link)); + if (link == NULL) { + free(bb); + return -1; + } + + link->bb = bb; + link->parent = parent; + list_add_tail(&link->node, &bb_data->queue); + return 0; +} + +/* Returns true when it finds the target in the current basic block */ +static bool process_basic_block(struct basic_block_data *bb_data, + struct basic_block_link *link, + struct symbol *sym, u64 target) +{ + struct disasm_line *dl, *next_dl, *last_dl; + struct annotation *notes = symbol__annotation(sym); + bool found = false; + + dl = link->bb->begin; + /* Check if it's already visited */ + if (basic_block_has_offset(&bb_data->visited, dl->al.offset)) + return false; + + last_dl = list_last_entry(¬es->src->source, + struct disasm_line, al.node); + + list_for_each_entry_from(dl, ¬es->src->source, al.node) { + /* Found the target instruction */ + if (sym->start + dl->al.offset == target) { + found = true; + break; + } + /* End of the function, finish the block */ + if (dl == last_dl) + break; + /* 'return' instruction finishes the block */ + if (dl->ins.ops == &ret_ops) + break; + /* normal instructions are part of the basic block */ + if (dl->ins.ops != &jump_ops) + continue; + /* jump to a different function, tail call or return */ + if (dl->ops.target.outside) + break; + /* jump instruction creates new basic block(s) */ + next_dl = find_disasm_line(sym, sym->start + dl->ops.target.offset, + /*allow_update=*/false); + add_basic_block(bb_data, link, next_dl); + + /* + * FIXME: determine conditional jumps properly. + * Conditional jumps create another basic block with the + * next disasm line. + */ + if (!strstr(dl->ins.name, "jmp")) { + next_dl = list_next_entry(dl, al.node); + add_basic_block(bb_data, link, next_dl); + } + break; + + } + link->bb->end = dl; + return found; +} + +/* + * It founds a target basic block, build a proper linked list of basic blocks + * by following the link recursively. + */ +static void link_found_basic_blocks(struct basic_block_link *link, + struct list_head *head) +{ + while (link) { + struct basic_block_link *parent = link->parent; + + list_move(&link->bb->list, head); + list_del(&link->node); + free(link); + + link = parent; + } +} + +static void delete_basic_blocks(struct basic_block_data *bb_data) +{ + struct basic_block_link *link, *tmp; + + list_for_each_entry_safe(link, tmp, &bb_data->queue, node) { + list_del(&link->node); + free(link->bb); + free(link); + } + + list_for_each_entry_safe(link, tmp, &bb_data->visited, node) { + list_del(&link->node); + free(link->bb); + free(link); + } +} + +/** + * annotate_get_basic_blocks - Get basic blocks for given address range + * @sym: symbol to annotate + * @src: source address + * @dst: destination address + * @head: list head to save basic blocks + * + * This function traverses disasm_lines from @src to @dst and save them in a + * list of annotated_basic_block to @head. It uses BFS to find the shortest + * path between two. The basic_block_link is to maintain parent links so + * that it can build a list of blocks from the start. + */ +int annotate_get_basic_blocks(struct symbol *sym, s64 src, s64 dst, + struct list_head *head) +{ + struct basic_block_data bb_data = { + .queue = LIST_HEAD_INIT(bb_data.queue), + .visited = LIST_HEAD_INIT(bb_data.visited), + }; + struct basic_block_link *link; + struct disasm_line *dl; + int ret = -1; + + dl = find_disasm_line(sym, src, /*allow_update=*/false); + if (dl == NULL) + return -1; + + if (add_basic_block(&bb_data, /*parent=*/NULL, dl) < 0) + return -1; + + /* Find shortest path from src to dst using BFS */ + while (!list_empty(&bb_data.queue)) { + link = list_first_entry(&bb_data.queue, struct basic_block_link, node); + + if (process_basic_block(&bb_data, link, sym, dst)) { + link_found_basic_blocks(link, head); + ret = 0; + break; + } + list_move(&link->node, &bb_data.visited); + } + delete_basic_blocks(&bb_data); + return ret; +} diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 13cc659e508c..0928663fddee 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -561,4 +561,20 @@ extern struct list_head ann_insn_stat; u64 annotate_calc_pcrel(struct map_symbol *ms, u64 ip, int offset, struct disasm_line *dl); +/** + * struct annotated_basic_block - Basic block of instructions + * @list: List node + * @begin: start instruction in the block + * @end: end instruction in the block + */ +struct annotated_basic_block { + struct list_head list; + struct disasm_line *begin; + struct disasm_line *end; +}; + +/* Get a list of basic blocks from src to dst addresses */ +int annotate_get_basic_blocks(struct symbol *sym, s64 src, s64 dst, + struct list_head *head); + #endif /* __PERF_ANNOTATE_H */ -- cgit v1.2.3-59-g8ed1b From 90429524f3e7342e98fd3a14deaa46f1dd3f6ffe Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Mon, 18 Mar 2024 22:51:00 -0700 Subject: perf annotate-data: Add debug messages Add a new debug option "type-profile" to enable the detailed info during the type analysis especially for instruction tracking. You can use this before the command name like 'report' or 'annotate'. $ perf --debug type-profile annotate --data-type Committer testing: First get some memory events: $ perf mem record ls Then, without data-type profiling debug: $ perf annotate --data-type | head Annotate type: 'struct rtld_global' in /usr/lib64/ld-linux-x86-64.so.2 (1 samples): ============================================================================ samples offset size field 1 0 4336 struct rtld_global { 0 0 0 struct link_namespaces* _dl_ns; 0 2560 8 size_t _dl_nns; 0 2568 40 __rtld_lock_recursive_t _dl_load_lock { 0 2568 40 pthread_mutex_t mutex { 0 2568 40 struct __pthread_mutex_s __data { 0 2568 4 int __lock; $ And with only data-type profiling: $ perf --debug type-profile annotate --data-type | head ----------------------------------------------------------- find_data_type_die [1e67] for reg13873052 (PC) offset=0x150e2 in dl_main CU die offset: 0x29cd3 found PC-rel by addr=0x34020 offset=0x20 ----------------------------------------------------------- find_data_type_die [2e] for reg12 offset=0 in __GI___readdir64 CU die offset: 0x137a45 frame base: cfa=1 fbreg=-1 found "__futex" in scope=2/2 (die: 0x137ad5) 0(reg12) type=int (die:2a) ----------------------------------------------------------- find_data_type_die [52] for reg5 offset=0 in __memmove_avx_unaligned_erms CU die offset: 0x1124ed no variable found Annotate type: 'struct rtld_global' in /usr/lib64/ld-linux-x86-64.so.2 (1 samples): ============================================================================ samples offset size field 1 0 4336 struct rtld_global { 0 0 0 struct link_namespaces* _dl_ns; 0 2560 8 size_t _dl_nns; 0 2568 40 __rtld_lock_recursive_t _dl_load_lock { 0 2568 40 pthread_mutex_t mutex { 0 2568 40 struct __pthread_mutex_s __data { 0 2568 4 int __lock; $ Signed-off-by: Namhyung Kim Tested-by: Arnaldo Carvalho de Melo Cc: Adrian Hunter Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Linus Torvalds Cc: Masami Hiramatsu Cc: Peter Zijlstra Cc: Stephane Eranian Link: https://lore.kernel.org/r/20240319055115.4063940-9-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate-data.c | 74 +++++++++++++++++++++++++++++++++++++---- tools/perf/util/debug.c | 3 ++ tools/perf/util/debug.h | 1 + 3 files changed, 71 insertions(+), 7 deletions(-) diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c index ff81d164aa57..f482ccfdaa91 100644 --- a/tools/perf/util/annotate-data.c +++ b/tools/perf/util/annotate-data.c @@ -23,6 +23,29 @@ #include "symbol.h" #include "symbol_conf.h" +#define pr_debug_dtp(fmt, ...) \ +do { \ + if (debug_type_profile) \ + pr_info(fmt, ##__VA_ARGS__); \ + else \ + pr_debug3(fmt, ##__VA_ARGS__); \ +} while (0) + +static void pr_debug_type_name(Dwarf_Die *die) +{ + struct strbuf sb; + char *str; + + if (!debug_type_profile && verbose < 3) + return; + + strbuf_init(&sb, 32); + die_get_typename_from_type(die, &sb); + str = strbuf_detach(&sb, NULL); + pr_info(" type=%s (die:%lx)\n", str, (long)dwarf_dieoffset(die)); + free(str); +} + /* * Compare type name and size to maintain them in a tree. * I'm not sure if DWARF would have information of a single type in many @@ -201,7 +224,7 @@ static int check_variable(Dwarf_Die *var_die, Dwarf_Die *type_die, int offset, /* Get the type of the variable */ if (die_get_real_type(var_die, type_die) == NULL) { - pr_debug("variable has no type\n"); + pr_debug_dtp("variable has no type\n"); ann_data_stat.no_typeinfo++; return -1; } @@ -215,7 +238,7 @@ static int check_variable(Dwarf_Die *var_die, Dwarf_Die *type_die, int offset, if ((dwarf_tag(type_die) != DW_TAG_pointer_type && dwarf_tag(type_die) != DW_TAG_array_type) || die_get_real_type(type_die, type_die) == NULL) { - pr_debug("no pointer or no type\n"); + pr_debug_dtp("no pointer or no type\n"); ann_data_stat.no_typeinfo++; return -1; } @@ -223,14 +246,15 @@ static int check_variable(Dwarf_Die *var_die, Dwarf_Die *type_die, int offset, /* Get the size of the actual type */ if (dwarf_aggregate_size(type_die, &size) < 0) { - pr_debug("type size is unknown\n"); + pr_debug_dtp("type size is unknown\n"); ann_data_stat.invalid_size++; return -1; } /* Minimal sanity check */ if ((unsigned)offset >= size) { - pr_debug("offset: %d is bigger than size: %" PRIu64 "\n", offset, size); + pr_debug_dtp("offset: %d is bigger than size: %"PRIu64"\n", + offset, size); ann_data_stat.bad_offset++; return -1; } @@ -251,6 +275,19 @@ static int find_data_type_die(struct data_loc_info *dloc, Dwarf_Die *type_die) int fb_offset = 0; bool is_fbreg = false; u64 pc; + char buf[64]; + + if (dloc->op->multi_regs) + snprintf(buf, sizeof(buf), " or reg%d", dloc->op->reg2); + else if (dloc->op->reg1 == DWARF_REG_PC) + snprintf(buf, sizeof(buf), " (PC)"); + else + buf[0] = '\0'; + + pr_debug_dtp("-----------------------------------------------------------\n"); + pr_debug_dtp("%s [%"PRIx64"] for reg%d%s offset=%#x in %s\n", + __func__, dloc->ip - dloc->ms->sym->start, + dloc->op->reg1, buf, dloc->op->offset, dloc->ms->sym->name); /* * IP is a relative instruction address from the start of the map, as @@ -261,7 +298,7 @@ static int find_data_type_die(struct data_loc_info *dloc, Dwarf_Die *type_die) /* Get a compile_unit for this address */ if (!find_cu_die(dloc->di, pc, &cu_die)) { - pr_debug("cannot find CU for address %" PRIx64 "\n", pc); + pr_debug_dtp("cannot find CU for address %"PRIx64"\n", pc); ann_data_stat.no_cuinfo++; return -1; } @@ -269,12 +306,17 @@ static int find_data_type_die(struct data_loc_info *dloc, Dwarf_Die *type_die) reg = loc->reg1; offset = loc->offset; + pr_debug_dtp("CU die offset: %#lx\n", (long)dwarf_dieoffset(&cu_die)); + if (reg == DWARF_REG_PC) { if (die_find_variable_by_addr(&cu_die, dloc->var_addr, &var_die, &offset)) { ret = check_variable(&var_die, type_die, offset, /*is_pointer=*/false); dloc->type_offset = offset; + + pr_debug_dtp("found PC-rel by addr=%#"PRIx64" offset=%#x\n", + dloc->var_addr, offset); goto out; } @@ -310,6 +352,9 @@ static int find_data_type_die(struct data_loc_info *dloc, Dwarf_Die *type_die) default: break; } + + pr_debug_dtp("frame base: cfa=%d fbreg=%d\n", + dloc->fb_cfa, fbreg); } } @@ -334,6 +379,19 @@ retry: /* Found a variable, see if it's correct */ ret = check_variable(&var_die, type_die, offset, reg != DWARF_REG_PC && !is_fbreg); + if (ret == 0) { + pr_debug_dtp("found \"%s\" in scope=%d/%d (die: %#lx) ", + dwarf_diename(&var_die), i+1, nr_scopes, + (long)dwarf_dieoffset(&scopes[i])); + if (reg == DWARF_REG_PC) + pr_debug_dtp("%#x(PC) offset=%#x", loc->offset, offset); + else if (reg == DWARF_REG_FB || is_fbreg) + pr_debug_dtp("%#x(reg%d) stack fb_offset=%#x offset=%#x", + loc->offset, reg, fb_offset, offset); + else + pr_debug_dtp("%#x(reg%d)", loc->offset, reg); + pr_debug_type_name(type_die); + } dloc->type_offset = offset; goto out; } @@ -343,8 +401,10 @@ retry: goto retry; } - if (ret < 0) + if (ret < 0) { + pr_debug_dtp("no variable found\n"); ann_data_stat.no_var++; + } out: free(scopes); @@ -373,7 +433,7 @@ struct annotated_data_type *find_data_type(struct data_loc_info *dloc) dloc->di = debuginfo__new(dso->long_name); if (dloc->di == NULL) { - pr_debug("cannot get the debug info\n"); + pr_debug_dtp("cannot get the debug info\n"); return NULL; } diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c index c39ee0fcb8cf..d633d15329fa 100644 --- a/tools/perf/util/debug.c +++ b/tools/perf/util/debug.c @@ -41,6 +41,7 @@ static int redirect_to_stderr; int debug_data_convert; static FILE *_debug_file; bool debug_display_time; +int debug_type_profile; FILE *debug_file(void) { @@ -231,6 +232,7 @@ static struct sublevel_option debug_opts[] = { { .name = "data-convert", .value_ptr = &debug_data_convert }, { .name = "perf-event-open", .value_ptr = &debug_peo_args }, { .name = "kmaps", .value_ptr = &debug_kmaps }, + { .name = "type-profile", .value_ptr = &debug_type_profile }, { .name = NULL, } }; @@ -270,6 +272,7 @@ int perf_quiet_option(void) redirect_to_stderr = 0; debug_peo_args = 0; debug_kmaps = 0; + debug_type_profile = 0; return 0; } diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h index 35a7a5ae762e..a4026d1fd6a3 100644 --- a/tools/perf/util/debug.h +++ b/tools/perf/util/debug.h @@ -14,6 +14,7 @@ extern int debug_peo_args; extern bool quiet, dump_trace; extern int debug_ordered_events; extern int debug_data_convert; +extern int debug_type_profile; #ifndef pr_fmt #define pr_fmt(fmt) fmt -- cgit v1.2.3-59-g8ed1b From 06b2ce75386df04b7aea53818ed3c42ee50ec426 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Mon, 18 Mar 2024 22:51:01 -0700 Subject: perf annotate-data: Maintain variable type info As it collected basic block and variable information in each scope, it now can build a state table to find matching variable at the location. The struct type_state is to keep the type info saved in each register and stack slot. The update_var_state() updates the table when it finds variables in the current address. It expects die_collect_vars() filled a list of variables with type info and starting address. Signed-off-by: Namhyung Kim Cc: Adrian Hunter Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Linus Torvalds Cc: Masami Hiramatsu Cc: Peter Zijlstra Cc: Stephane Eranian Link: https://lore.kernel.org/r/20240319055115.4063940-10-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate-data.c | 173 ++++++++++++++++++++++++++++++++++++++++ tools/perf/util/dwarf-aux.c | 4 + 2 files changed, 177 insertions(+) diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c index f482ccfdaa91..8eaa06f1cee5 100644 --- a/tools/perf/util/annotate-data.c +++ b/tools/perf/util/annotate-data.c @@ -46,6 +46,62 @@ static void pr_debug_type_name(Dwarf_Die *die) free(str); } +/* Type information in a register, valid when ok is true */ +struct type_state_reg { + Dwarf_Die type; + bool ok; +}; + +/* Type information in a stack location, dynamically allocated */ +struct type_state_stack { + struct list_head list; + Dwarf_Die type; + int offset; + int size; + bool compound; +}; + +/* FIXME: This should be arch-dependent */ +#define TYPE_STATE_MAX_REGS 16 + +/* + * State table to maintain type info in each register and stack location. + * It'll be updated when new variable is allocated or type info is moved + * to a new location (register or stack). As it'd be used with the + * shortest path of basic blocks, it only maintains a single table. + */ +struct type_state { + struct type_state_reg regs[TYPE_STATE_MAX_REGS]; + struct list_head stack_vars; +}; + +static bool has_reg_type(struct type_state *state, int reg) +{ + return (unsigned)reg < ARRAY_SIZE(state->regs); +} + +/* These declarations will be remove once they are changed to static */ +void init_type_state(struct type_state *state, struct arch *arch __maybe_unused); +void exit_type_state(struct type_state *state); +void update_var_state(struct type_state *state, struct data_loc_info *dloc, + u64 addr, u64 insn_offset, struct die_var_type *var_types); + +void init_type_state(struct type_state *state, struct arch *arch __maybe_unused) +{ + memset(state, 0, sizeof(*state)); + INIT_LIST_HEAD(&state->stack_vars); +} + +void exit_type_state(struct type_state *state) +{ + struct type_state_stack *stack, *tmp; + + list_for_each_entry_safe(stack, tmp, &state->stack_vars, list) { + list_del(&stack->list); + free(stack); + } +} + /* * Compare type name and size to maintain them in a tree. * I'm not sure if DWARF would have information of a single type in many @@ -262,6 +318,123 @@ static int check_variable(Dwarf_Die *var_die, Dwarf_Die *type_die, int offset, return 0; } +static struct type_state_stack *find_stack_state(struct type_state *state, + int offset) +{ + struct type_state_stack *stack; + + list_for_each_entry(stack, &state->stack_vars, list) { + if (offset == stack->offset) + return stack; + + if (stack->compound && stack->offset < offset && + offset < stack->offset + stack->size) + return stack; + } + return NULL; +} + +static void set_stack_state(struct type_state_stack *stack, int offset, + Dwarf_Die *type_die) +{ + int tag; + Dwarf_Word size; + + if (dwarf_aggregate_size(type_die, &size) < 0) + size = 0; + + tag = dwarf_tag(type_die); + + stack->type = *type_die; + stack->size = size; + stack->offset = offset; + + switch (tag) { + case DW_TAG_structure_type: + case DW_TAG_union_type: + stack->compound = true; + break; + default: + stack->compound = false; + break; + } +} + +static struct type_state_stack *findnew_stack_state(struct type_state *state, + int offset, Dwarf_Die *type_die) +{ + struct type_state_stack *stack = find_stack_state(state, offset); + + if (stack) { + set_stack_state(stack, offset, type_die); + return stack; + } + + stack = malloc(sizeof(*stack)); + if (stack) { + set_stack_state(stack, offset, type_die); + list_add(&stack->list, &state->stack_vars); + } + return stack; +} + +/** + * update_var_state - Update type state using given variables + * @state: type state table + * @dloc: data location info + * @addr: instruction address to match with variable + * @insn_offset: instruction offset (for debug) + * @var_types: list of variables with type info + * + * This function fills the @state table using @var_types info. Each variable + * is used only at the given location and updates an entry in the table. + */ +void update_var_state(struct type_state *state, struct data_loc_info *dloc, + u64 addr, u64 insn_offset, struct die_var_type *var_types) +{ + Dwarf_Die mem_die; + struct die_var_type *var; + int fbreg = dloc->fbreg; + int fb_offset = 0; + + if (dloc->fb_cfa) { + if (die_get_cfa(dloc->di->dbg, addr, &fbreg, &fb_offset) < 0) + fbreg = -1; + } + + for (var = var_types; var != NULL; var = var->next) { + if (var->addr != addr) + continue; + /* Get the type DIE using the offset */ + if (!dwarf_offdie(dloc->di->dbg, var->die_off, &mem_die)) + continue; + + if (var->reg == DWARF_REG_FB) { + findnew_stack_state(state, var->offset, &mem_die); + + pr_debug_dtp("var [%"PRIx64"] -%#x(stack) type=", + insn_offset, -var->offset); + pr_debug_type_name(&mem_die); + } else if (var->reg == fbreg) { + findnew_stack_state(state, var->offset - fb_offset, &mem_die); + + pr_debug_dtp("var [%"PRIx64"] -%#x(stack) type=", + insn_offset, -var->offset + fb_offset); + pr_debug_type_name(&mem_die); + } else if (has_reg_type(state, var->reg) && var->offset == 0) { + struct type_state_reg *reg; + + reg = &state->regs[var->reg]; + reg->type = mem_die; + reg->ok = true; + + pr_debug_dtp("var [%"PRIx64"] reg%d type=", + insn_offset, var->reg); + pr_debug_type_name(&mem_die); + } + } +} + /* The result will be saved in @type_die */ static int find_data_type_die(struct data_loc_info *dloc, Dwarf_Die *type_die) { diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c index d4ec239c5adb..7dad99ee3ff3 100644 --- a/tools/perf/util/dwarf-aux.c +++ b/tools/perf/util/dwarf-aux.c @@ -9,6 +9,7 @@ #include #include "debug.h" #include "dwarf-aux.h" +#include "dwarf-regs.h" #include "strbuf.h" #include "string2.h" @@ -1190,6 +1191,8 @@ static int reg_from_dwarf_op(Dwarf_Op *op) case DW_OP_regx: case DW_OP_bregx: return op->number; + case DW_OP_fbreg: + return DWARF_REG_FB; default: break; } @@ -1203,6 +1206,7 @@ static int offset_from_dwarf_op(Dwarf_Op *op) case DW_OP_regx: return 0; case DW_OP_breg0 ... DW_OP_breg31: + case DW_OP_fbreg: return op->number; case DW_OP_bregx: return op->number2; -- cgit v1.2.3-59-g8ed1b From 4f903455befa257c50422a4570c4dca0020a1fc8 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Mon, 18 Mar 2024 22:51:02 -0700 Subject: perf annotate-data: Add update_insn_state() The update_insn_state() function is to update the type state table after processing each instruction. For now, it handles MOV (on x86) insn to transfer type info from the source location to the target. The location can be a register or a stack slot. Check carefully when memory reference happens and fetch the type correctly. It basically ignores write to a memory since it doesn't change the type info. One exception is writes to (new) stack slots for register spilling. Signed-off-by: Namhyung Kim Cc: Adrian Hunter Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Linus Torvalds Cc: Masami Hiramatsu Cc: Peter Zijlstra Cc: Stephane Eranian Link: https://lore.kernel.org/r/20240319055115.4063940-11-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate-data.c | 161 +++++++++++++++++++++++++++++++++++++++- tools/perf/util/annotate-data.h | 2 + tools/perf/util/annotate.c | 1 + 3 files changed, 161 insertions(+), 3 deletions(-) diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c index 8eaa06f1cee5..592437b6c097 100644 --- a/tools/perf/util/annotate-data.c +++ b/tools/perf/util/annotate-data.c @@ -71,7 +71,9 @@ struct type_state_stack { * shortest path of basic blocks, it only maintains a single table. */ struct type_state { + /* state of general purpose registers */ struct type_state_reg regs[TYPE_STATE_MAX_REGS]; + /* state of stack location */ struct list_head stack_vars; }; @@ -85,6 +87,8 @@ void init_type_state(struct type_state *state, struct arch *arch __maybe_unused) void exit_type_state(struct type_state *state); void update_var_state(struct type_state *state, struct data_loc_info *dloc, u64 addr, u64 insn_offset, struct die_var_type *var_types); +void update_insn_state(struct type_state *state, struct data_loc_info *dloc, + struct disasm_line *dl); void init_type_state(struct type_state *state, struct arch *arch __maybe_unused) { @@ -412,13 +416,13 @@ void update_var_state(struct type_state *state, struct data_loc_info *dloc, if (var->reg == DWARF_REG_FB) { findnew_stack_state(state, var->offset, &mem_die); - pr_debug_dtp("var [%"PRIx64"] -%#x(stack) type=", + pr_debug_dtp("var [%"PRIx64"] -%#x(stack)", insn_offset, -var->offset); pr_debug_type_name(&mem_die); } else if (var->reg == fbreg) { findnew_stack_state(state, var->offset - fb_offset, &mem_die); - pr_debug_dtp("var [%"PRIx64"] -%#x(stack) type=", + pr_debug_dtp("var [%"PRIx64"] -%#x(stack)", insn_offset, -var->offset + fb_offset); pr_debug_type_name(&mem_die); } else if (has_reg_type(state, var->reg) && var->offset == 0) { @@ -428,13 +432,164 @@ void update_var_state(struct type_state *state, struct data_loc_info *dloc, reg->type = mem_die; reg->ok = true; - pr_debug_dtp("var [%"PRIx64"] reg%d type=", + pr_debug_dtp("var [%"PRIx64"] reg%d", insn_offset, var->reg); pr_debug_type_name(&mem_die); } } } +static void update_insn_state_x86(struct type_state *state, + struct data_loc_info *dloc, + struct disasm_line *dl) +{ + struct annotated_insn_loc loc; + struct annotated_op_loc *src = &loc.ops[INSN_OP_SOURCE]; + struct annotated_op_loc *dst = &loc.ops[INSN_OP_TARGET]; + struct type_state_reg *tsr; + Dwarf_Die type_die; + u32 insn_offset = dl->al.offset; + int fbreg = dloc->fbreg; + int fboff = 0; + + if (annotate_get_insn_location(dloc->arch, dl, &loc) < 0) + return; + + if (strncmp(dl->ins.name, "mov", 3)) + return; + + if (dloc->fb_cfa) { + u64 ip = dloc->ms->sym->start + dl->al.offset; + u64 pc = map__rip_2objdump(dloc->ms->map, ip); + + if (die_get_cfa(dloc->di->dbg, pc, &fbreg, &fboff) < 0) + fbreg = -1; + } + + /* Case 1. register to register transfers */ + if (!src->mem_ref && !dst->mem_ref) { + if (!has_reg_type(state, dst->reg1)) + return; + + tsr = &state->regs[dst->reg1]; + if (!has_reg_type(state, src->reg1) || + !state->regs[src->reg1].ok) { + tsr->ok = false; + return; + } + + tsr->type = state->regs[src->reg1].type; + tsr->ok = true; + + pr_debug_dtp("mov [%x] reg%d -> reg%d", + insn_offset, src->reg1, dst->reg1); + pr_debug_type_name(&tsr->type); + } + /* Case 2. memory to register transers */ + if (src->mem_ref && !dst->mem_ref) { + int sreg = src->reg1; + + if (!has_reg_type(state, dst->reg1)) + return; + + tsr = &state->regs[dst->reg1]; + +retry: + /* Check stack variables with offset */ + if (sreg == fbreg) { + struct type_state_stack *stack; + int offset = src->offset - fboff; + + stack = find_stack_state(state, offset); + if (stack == NULL) { + tsr->ok = false; + return; + } else if (!stack->compound) { + tsr->type = stack->type; + tsr->ok = true; + } else if (die_get_member_type(&stack->type, + offset - stack->offset, + &type_die)) { + tsr->type = type_die; + tsr->ok = true; + } else { + tsr->ok = false; + return; + } + + pr_debug_dtp("mov [%x] -%#x(stack) -> reg%d", + insn_offset, -offset, dst->reg1); + pr_debug_type_name(&tsr->type); + } + /* And then dereference the pointer if it has one */ + else if (has_reg_type(state, sreg) && state->regs[sreg].ok && + die_deref_ptr_type(&state->regs[sreg].type, + src->offset, &type_die)) { + tsr->type = type_die; + tsr->ok = true; + + pr_debug_dtp("mov [%x] %#x(reg%d) -> reg%d", + insn_offset, src->offset, sreg, dst->reg1); + pr_debug_type_name(&tsr->type); + } + /* Or try another register if any */ + else if (src->multi_regs && sreg == src->reg1 && + src->reg1 != src->reg2) { + sreg = src->reg2; + goto retry; + } + /* It failed to get a type info, mark it as invalid */ + else { + tsr->ok = false; + } + } + /* Case 3. register to memory transfers */ + if (!src->mem_ref && dst->mem_ref) { + if (!has_reg_type(state, src->reg1) || + !state->regs[src->reg1].ok) + return; + + /* Check stack variables with offset */ + if (dst->reg1 == fbreg) { + struct type_state_stack *stack; + int offset = dst->offset - fboff; + + stack = find_stack_state(state, offset); + if (stack) { + /* + * The source register is likely to hold a type + * of member if it's a compound type. Do not + * update the stack variable type since we can + * get the member type later by using the + * die_get_member_type(). + */ + if (!stack->compound) + set_stack_state(stack, offset, + &state->regs[src->reg1].type); + } else { + findnew_stack_state(state, offset, + &state->regs[src->reg1].type); + } + + pr_debug_dtp("mov [%x] reg%d -> -%#x(stack)", + insn_offset, src->reg1, -offset); + pr_debug_type_name(&state->regs[src->reg1].type); + } + /* + * Ignore other transfers since it'd set a value in a struct + * and won't change the type. + */ + } + /* Case 4. memory to memory transfers (not handled for now) */ +} + +void update_insn_state(struct type_state *state, struct data_loc_info *dloc, + struct disasm_line *dl) +{ + if (arch__is(dloc->arch, "x86")) + update_insn_state_x86(state, dloc, dl); +} + /* The result will be saved in @type_die */ static int find_data_type_die(struct data_loc_info *dloc, Dwarf_Die *type_die) { diff --git a/tools/perf/util/annotate-data.h b/tools/perf/util/annotate-data.h index ad6493ea2c8e..7324cafe2c7b 100644 --- a/tools/perf/util/annotate-data.h +++ b/tools/perf/util/annotate-data.h @@ -75,6 +75,7 @@ extern struct annotated_data_type stackop_type; /** * struct data_loc_info - Data location information + * @arch: CPU architecture info * @ms: Map and Symbol info * @ip: Instruction address * @var_addr: Data address (for global variables) @@ -87,6 +88,7 @@ extern struct annotated_data_type stackop_type; */ struct data_loc_info { /* These are input field, should be filled by caller */ + struct arch *arch; struct map_symbol *ms; u64 ip; u64 var_addr; diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index aa005c13ff67..9777df5dc2e3 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -3872,6 +3872,7 @@ retry: for_each_insn_op_loc(&loc, i, op_loc) { struct data_loc_info dloc = { + .arch = arch, .ms = ms, /* Recalculate IP for LOCK prefix or insn fusion */ .ip = ms->sym->start + dl->al.offset, -- cgit v1.2.3-59-g8ed1b From 1ebb5e17ef21b492ee60654d4e22cbfb3763661f Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Mon, 18 Mar 2024 22:51:03 -0700 Subject: perf annotate-data: Add get_global_var_type() Accessing global variable is common when it tracks execution later. Factor out the common code into a function for later use. It adds thread and cpumode to struct data_loc_info to find (global) symbols if needed. Also remove var_name as it's retrieved in the helper function. Signed-off-by: Namhyung Kim Cc: Adrian Hunter Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Linus Torvalds Cc: Masami Hiramatsu Cc: Peter Zijlstra Cc: Stephane Eranian Link: https://lore.kernel.org/r/20240319055115.4063940-12-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate-data.c | 62 +++++++++++++++++++++++++++++++---------- tools/perf/util/annotate-data.h | 7 +++-- tools/perf/util/annotate.c | 21 +++----------- 3 files changed, 57 insertions(+), 33 deletions(-) diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c index 592437b6c097..3b661e693410 100644 --- a/tools/perf/util/annotate-data.c +++ b/tools/perf/util/annotate-data.c @@ -22,6 +22,7 @@ #include "strbuf.h" #include "symbol.h" #include "symbol_conf.h" +#include "thread.h" #define pr_debug_dtp(fmt, ...) \ do { \ @@ -382,6 +383,50 @@ static struct type_state_stack *findnew_stack_state(struct type_state *state, return stack; } +static bool get_global_var_type(Dwarf_Die *cu_die, struct data_loc_info *dloc, + u64 ip, u64 var_addr, int *var_offset, + Dwarf_Die *type_die) +{ + u64 pc, mem_addr; + int offset; + bool is_pointer = false; + const char *var_name = NULL; + Dwarf_Die var_die; + struct addr_location al; + struct symbol *sym; + + /* Try to get the variable by address first */ + if (die_find_variable_by_addr(cu_die, var_addr, &var_die, &offset) && + check_variable(&var_die, type_die, offset, is_pointer) == 0) { + *var_offset = offset; + return true; + } + + /* Kernel symbols might be relocated */ + mem_addr = var_addr + map__reloc(dloc->ms->map); + + addr_location__init(&al); + sym = thread__find_symbol_fb(dloc->thread, dloc->cpumode, + mem_addr, &al); + if (sym) { + var_name = sym->name; + /* Calculate type offset from the start of variable */ + *var_offset = mem_addr - map__unmap_ip(al.map, sym->start); + } + addr_location__exit(&al); + if (var_name == NULL) + return false; + + pc = map__rip_2objdump(dloc->ms->map, ip); + + /* Try to get the name of global variable */ + if (die_find_variable_at(cu_die, var_name, pc, &var_die) && + check_variable(&var_die, type_die, *var_offset, is_pointer) == 0) + return true; + + return false; +} + /** * update_var_state - Update type state using given variables * @state: type state table @@ -637,24 +682,14 @@ static int find_data_type_die(struct data_loc_info *dloc, Dwarf_Die *type_die) pr_debug_dtp("CU die offset: %#lx\n", (long)dwarf_dieoffset(&cu_die)); if (reg == DWARF_REG_PC) { - if (die_find_variable_by_addr(&cu_die, dloc->var_addr, &var_die, - &offset)) { - ret = check_variable(&var_die, type_die, offset, - /*is_pointer=*/false); + if (get_global_var_type(&cu_die, dloc, dloc->ip, dloc->var_addr, + &offset, type_die)) { dloc->type_offset = offset; pr_debug_dtp("found PC-rel by addr=%#"PRIx64" offset=%#x\n", dloc->var_addr, offset); goto out; } - - if (dloc->var_name && - die_find_variable_at(&cu_die, dloc->var_name, pc, &var_die)) { - ret = check_variable(&var_die, type_die, dloc->type_offset, - /*is_pointer=*/false); - /* dloc->type_offset was updated by the caller */ - goto out; - } } /* Get a list of nested scopes - i.e. (inlined) functions and blocks. */ @@ -769,8 +804,7 @@ struct annotated_data_type *find_data_type(struct data_loc_info *dloc) * The type offset is the same as instruction offset by default. * But when finding a global variable, the offset won't be valid. */ - if (dloc->var_name == NULL) - dloc->type_offset = dloc->op->offset; + dloc->type_offset = dloc->op->offset; dloc->fbreg = -1; diff --git a/tools/perf/util/annotate-data.h b/tools/perf/util/annotate-data.h index 7324cafe2c7b..acfbd1748d02 100644 --- a/tools/perf/util/annotate-data.h +++ b/tools/perf/util/annotate-data.h @@ -11,6 +11,7 @@ struct annotated_op_loc; struct debuginfo; struct evsel; struct map_symbol; +struct thread; /** * struct annotated_member - Type of member field @@ -76,10 +77,11 @@ extern struct annotated_data_type stackop_type; /** * struct data_loc_info - Data location information * @arch: CPU architecture info + * @thread: Thread info * @ms: Map and Symbol info * @ip: Instruction address * @var_addr: Data address (for global variables) - * @var_name: Variable name (for global variables) + * @cpumode: CPU execution mode * @op: Instruction operand location (regs and offset) * @di: Debug info * @fbreg: Frame base register @@ -89,10 +91,11 @@ extern struct annotated_data_type stackop_type; struct data_loc_info { /* These are input field, should be filled by caller */ struct arch *arch; + struct thread *thread; struct map_symbol *ms; u64 ip; u64 var_addr; - const char *var_name; + u8 cpumode; struct annotated_op_loc *op; /* These are used internally */ diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 9777df5dc2e3..abb641aa8ec0 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -3873,9 +3873,11 @@ retry: for_each_insn_op_loc(&loc, i, op_loc) { struct data_loc_info dloc = { .arch = arch, + .thread = he->thread, .ms = ms, /* Recalculate IP for LOCK prefix or insn fusion */ .ip = ms->sym->start + dl->al.offset, + .cpumode = he->cpumode, .op = op_loc, }; @@ -3887,23 +3889,8 @@ retry: /* PC-relative addressing */ if (op_loc->reg1 == DWARF_REG_PC) { - struct addr_location al; - struct symbol *var; - u64 map_addr; - - dloc.var_addr = annotate_calc_pcrel(ms, ip, op_loc->offset, dl); - /* Kernel symbols might be relocated */ - map_addr = dloc.var_addr + map__reloc(ms->map); - - addr_location__init(&al); - var = thread__find_symbol_fb(he->thread, he->cpumode, - map_addr, &al); - if (var) { - dloc.var_name = var->name; - /* Calculate type offset from the start of variable */ - dloc.type_offset = map_addr - map__unmap_ip(al.map, var->start); - } - addr_location__exit(&al); + dloc.var_addr = annotate_calc_pcrel(ms, dloc.ip, + op_loc->offset, dl); } mem_type = find_data_type(&dloc); -- cgit v1.2.3-59-g8ed1b From 0a41e5d6849b4f705c377d34799485b546764970 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Mon, 18 Mar 2024 22:51:04 -0700 Subject: perf annotate-data: Handle global variable access When updating the instruction states, it also needs to handle global variable accesses. Same as it does for PC-relative addressing, it can look up the type by address (if it's defined in the same file), or by name after finding the symbol by address (for declarations). Signed-off-by: Namhyung Kim Cc: Adrian Hunter Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Linus Torvalds Cc: Masami Hiramatsu Cc: Peter Zijlstra Cc: Stephane Eranian Link: https://lore.kernel.org/r/20240319055115.4063940-13-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate-data.c | 46 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 42 insertions(+), 4 deletions(-) diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c index 3b661e693410..2cc9f56e3eea 100644 --- a/tools/perf/util/annotate-data.c +++ b/tools/perf/util/annotate-data.c @@ -89,7 +89,7 @@ void exit_type_state(struct type_state *state); void update_var_state(struct type_state *state, struct data_loc_info *dloc, u64 addr, u64 insn_offset, struct die_var_type *var_types); void update_insn_state(struct type_state *state, struct data_loc_info *dloc, - struct disasm_line *dl); + Dwarf_Die *cu_die, struct disasm_line *dl); void init_type_state(struct type_state *state, struct arch *arch __maybe_unused) { @@ -485,7 +485,7 @@ void update_var_state(struct type_state *state, struct data_loc_info *dloc, } static void update_insn_state_x86(struct type_state *state, - struct data_loc_info *dloc, + struct data_loc_info *dloc, Dwarf_Die *cu_die, struct disasm_line *dl) { struct annotated_insn_loc loc; @@ -577,6 +577,29 @@ retry: insn_offset, src->offset, sreg, dst->reg1); pr_debug_type_name(&tsr->type); } + /* Or check if it's a global variable */ + else if (sreg == DWARF_REG_PC) { + struct map_symbol *ms = dloc->ms; + u64 ip = ms->sym->start + dl->al.offset; + u64 addr; + int offset; + + addr = annotate_calc_pcrel(ms, ip, src->offset, dl); + + if (!get_global_var_type(cu_die, dloc, ip, addr, &offset, + &type_die) || + !die_get_member_type(&type_die, offset, &type_die)) { + tsr->ok = false; + return; + } + + tsr->type = type_die; + tsr->ok = true; + + pr_debug_dtp("mov [%x] global addr=%"PRIx64" -> reg%d", + insn_offset, addr, dst->reg1); + pr_debug_type_name(&type_die); + } /* Or try another register if any */ else if (src->multi_regs && sreg == src->reg1 && src->reg1 != src->reg2) { @@ -628,11 +651,26 @@ retry: /* Case 4. memory to memory transfers (not handled for now) */ } +/** + * update_insn_state - Update type state for an instruction + * @state: type state table + * @dloc: data location info + * @cu_die: compile unit debug entry + * @dl: disasm line for the instruction + * + * This function updates the @state table for the target operand of the + * instruction at @dl if it transfers the type like MOV on x86. Since it + * tracks the type, it won't care about the values like in arithmetic + * instructions like ADD/SUB/MUL/DIV and INC/DEC. + * + * Note that ops->reg2 is only available when both mem_ref and multi_regs + * are true. + */ void update_insn_state(struct type_state *state, struct data_loc_info *dloc, - struct disasm_line *dl) + Dwarf_Die *cu_die, struct disasm_line *dl) { if (arch__is(dloc->arch, "x86")) - update_insn_state_x86(state, dloc, dl); + update_insn_state_x86(state, dloc, cu_die, dl); } /* The result will be saved in @type_die */ -- cgit v1.2.3-59-g8ed1b From cffb7910afbdf73ca5b2fdf8a617584a7dcecf14 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Mon, 18 Mar 2024 22:51:05 -0700 Subject: perf annotate-data: Handle call instructions When updating instruction states, the call instruction should play a role since it changes the register states. For simplicity, mark some registers as caller-saved registers (should be arch-dependent), and invalidate them all after a function call. If the function returns something, the designated register (ret_reg) will have the type info. Signed-off-by: Namhyung Kim Cc: Adrian Hunter Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Linus Torvalds Cc: Masami Hiramatsu Cc: Peter Zijlstra Cc: Stephane Eranian Link: https://lore.kernel.org/r/20240319055115.4063940-14-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate-data.c | 54 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c index 2cc9f56e3eea..6bcf22e523cb 100644 --- a/tools/perf/util/annotate-data.c +++ b/tools/perf/util/annotate-data.c @@ -47,10 +47,14 @@ static void pr_debug_type_name(Dwarf_Die *die) free(str); } -/* Type information in a register, valid when ok is true */ +/* + * Type information in a register, valid when @ok is true. + * The @caller_saved registers are invalidated after a function call. + */ struct type_state_reg { Dwarf_Die type; bool ok; + bool caller_saved; }; /* Type information in a stack location, dynamically allocated */ @@ -76,6 +80,8 @@ struct type_state { struct type_state_reg regs[TYPE_STATE_MAX_REGS]; /* state of stack location */ struct list_head stack_vars; + /* return value register */ + int ret_reg; }; static bool has_reg_type(struct type_state *state, int reg) @@ -91,10 +97,23 @@ void update_var_state(struct type_state *state, struct data_loc_info *dloc, void update_insn_state(struct type_state *state, struct data_loc_info *dloc, Dwarf_Die *cu_die, struct disasm_line *dl); -void init_type_state(struct type_state *state, struct arch *arch __maybe_unused) +void init_type_state(struct type_state *state, struct arch *arch) { memset(state, 0, sizeof(*state)); INIT_LIST_HEAD(&state->stack_vars); + + if (arch__is(arch, "x86")) { + state->regs[0].caller_saved = true; + state->regs[1].caller_saved = true; + state->regs[2].caller_saved = true; + state->regs[4].caller_saved = true; + state->regs[5].caller_saved = true; + state->regs[8].caller_saved = true; + state->regs[9].caller_saved = true; + state->regs[10].caller_saved = true; + state->regs[11].caller_saved = true; + state->ret_reg = 0; + } } void exit_type_state(struct type_state *state) @@ -500,6 +519,37 @@ static void update_insn_state_x86(struct type_state *state, if (annotate_get_insn_location(dloc->arch, dl, &loc) < 0) return; + if (ins__is_call(&dl->ins)) { + struct symbol *func = dl->ops.target.sym; + + if (func == NULL) + return; + + /* __fentry__ will preserve all registers */ + if (!strcmp(func->name, "__fentry__")) + return; + + pr_debug_dtp("call [%x] %s\n", insn_offset, func->name); + + /* Otherwise invalidate caller-saved registers after call */ + for (unsigned i = 0; i < ARRAY_SIZE(state->regs); i++) { + if (state->regs[i].caller_saved) + state->regs[i].ok = false; + } + + /* Update register with the return type (if any) */ + if (die_find_func_rettype(cu_die, func->name, &type_die)) { + tsr = &state->regs[state->ret_reg]; + tsr->type = type_die; + tsr->ok = true; + + pr_debug_dtp("call [%x] return -> reg%d", + insn_offset, state->ret_reg); + pr_debug_type_name(&type_die); + } + return; + } + if (strncmp(dl->ins.name, "mov", 3)) return; -- cgit v1.2.3-59-g8ed1b From eb8a55e01de9a671e130b4c0e5b483997f4f491f Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Mon, 18 Mar 2024 22:51:06 -0700 Subject: perf annotate-data: Implement instruction tracking If it failed to find a variable for the location directly, it might be due to a missing variable in the source code. For example, accessing pointer variables in a chain can result in the case like below: struct foo *foo = ...; int i = foo->bar->baz; The DWARF debug information is created for each variable so it'd have one for 'foo'. But there's no variable for 'foo->bar' and then it cannot know the type of 'bar' and 'baz'. The above source code can be compiled to the follow x86 instructions: mov 0x8(%rax), %rcx mov 0x4(%rcx), %rdx <=== PMU sample mov %rdx, -4(%rbp) Let's say 'foo' is located in the %rax and it has a pointer to struct foo. But perf sample is captured in the second instruction and there is no variable or type info for the %rcx. It'd be great if compiler could generate debug info for %rcx, but we should handle it on our side. So this patch implements the logic to iterate instructions and update the type table for each location. As it already collected a list of scopes including the target instruction, we can use it to construct the type table smartly. +---------------- scope[0] subprogram | | +-------------- scope[1] lexical_block | | | | +------------ scope[2] inlined_subroutine | | | | | | +---------- scope[3] inlined_subroutine | | | | | | | | +-------- scope[4] lexical_block | | | | | | | | | | *** target instruction ... Image the target instruction has 5 scopes, each scope will have its own variables and parameters. Then it can start with the innermost scope (4). So it'd search the shortest path from the start of scope[4] to the target address and build a list of basic blocks. Then it iterates the basic blocks with the variables in the scope and update the table. If it finds a type at the target instruction, then returns it. Otherwise, it moves to the upper scope[3]. Now it'd search the shortest path from the start of scope[3] to the start of scope[4]. Then connect it to the existing basic block list. Then it'd iterate the blocks with variables for both scopes. It can repeat this until it finds a type at the target instruction or reaches to the top scope[0]. As the basic blocks contain the shortest path, it won't worry about branches and can update the table simply. The final check will be done by find_matching_type() in the next patch. Signed-off-by: Namhyung Kim Cc: Adrian Hunter Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Linus Torvalds Cc: Masami Hiramatsu Cc: Peter Zijlstra Cc: Stephane Eranian Link: https://lore.kernel.org/r/20240319055115.4063940-15-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-annotate.c | 1 + tools/perf/util/annotate-data.c | 223 +++++++++++++++++++++++++++++++++++++--- tools/perf/util/annotate-data.h | 1 + 3 files changed, 211 insertions(+), 14 deletions(-) diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 6c1cc797692d..f677671409b1 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -430,6 +430,7 @@ static void print_annotate_data_stat(struct annotated_data_stat *s) PRINT_STAT(no_typeinfo); PRINT_STAT(invalid_size); PRINT_STAT(bad_offset); + PRINT_STAT(insn_track); printf("\n"); #undef PRINT_STAT diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c index 6bcf22e523cb..13ba65693367 100644 --- a/tools/perf/util/annotate-data.c +++ b/tools/perf/util/annotate-data.c @@ -89,15 +89,7 @@ static bool has_reg_type(struct type_state *state, int reg) return (unsigned)reg < ARRAY_SIZE(state->regs); } -/* These declarations will be remove once they are changed to static */ -void init_type_state(struct type_state *state, struct arch *arch __maybe_unused); -void exit_type_state(struct type_state *state); -void update_var_state(struct type_state *state, struct data_loc_info *dloc, - u64 addr, u64 insn_offset, struct die_var_type *var_types); -void update_insn_state(struct type_state *state, struct data_loc_info *dloc, - Dwarf_Die *cu_die, struct disasm_line *dl); - -void init_type_state(struct type_state *state, struct arch *arch) +static void init_type_state(struct type_state *state, struct arch *arch) { memset(state, 0, sizeof(*state)); INIT_LIST_HEAD(&state->stack_vars); @@ -116,7 +108,7 @@ void init_type_state(struct type_state *state, struct arch *arch) } } -void exit_type_state(struct type_state *state) +static void exit_type_state(struct type_state *state) { struct type_state_stack *stack, *tmp; @@ -457,8 +449,8 @@ static bool get_global_var_type(Dwarf_Die *cu_die, struct data_loc_info *dloc, * This function fills the @state table using @var_types info. Each variable * is used only at the given location and updates an entry in the table. */ -void update_var_state(struct type_state *state, struct data_loc_info *dloc, - u64 addr, u64 insn_offset, struct die_var_type *var_types) +static void update_var_state(struct type_state *state, struct data_loc_info *dloc, + u64 addr, u64 insn_offset, struct die_var_type *var_types) { Dwarf_Die mem_die; struct die_var_type *var; @@ -716,13 +708,207 @@ retry: * Note that ops->reg2 is only available when both mem_ref and multi_regs * are true. */ -void update_insn_state(struct type_state *state, struct data_loc_info *dloc, - Dwarf_Die *cu_die, struct disasm_line *dl) +static void update_insn_state(struct type_state *state, struct data_loc_info *dloc, + Dwarf_Die *cu_die, struct disasm_line *dl) { if (arch__is(dloc->arch, "x86")) update_insn_state_x86(state, dloc, cu_die, dl); } +/* + * Prepend this_blocks (from the outer scope) to full_blocks, removing + * duplicate disasm line. + */ +static void prepend_basic_blocks(struct list_head *this_blocks, + struct list_head *full_blocks) +{ + struct annotated_basic_block *first_bb, *last_bb; + + last_bb = list_last_entry(this_blocks, typeof(*last_bb), list); + first_bb = list_first_entry(full_blocks, typeof(*first_bb), list); + + if (list_empty(full_blocks)) + goto out; + + /* Last insn in this_blocks should be same as first insn in full_blocks */ + if (last_bb->end != first_bb->begin) { + pr_debug("prepend basic blocks: mismatched disasm line %"PRIx64" -> %"PRIx64"\n", + last_bb->end->al.offset, first_bb->begin->al.offset); + goto out; + } + + /* Is the basic block have only one disasm_line? */ + if (last_bb->begin == last_bb->end) { + list_del(&last_bb->list); + free(last_bb); + goto out; + } + + /* Point to the insn before the last when adding this block to full_blocks */ + last_bb->end = list_prev_entry(last_bb->end, al.node); + +out: + list_splice(this_blocks, full_blocks); +} + +static void delete_basic_blocks(struct list_head *basic_blocks) +{ + struct annotated_basic_block *bb, *tmp; + + list_for_each_entry_safe(bb, tmp, basic_blocks, list) { + list_del(&bb->list); + free(bb); + } +} + +/* Make sure all variables have a valid start address */ +static void fixup_var_address(struct die_var_type *var_types, u64 addr) +{ + while (var_types) { + /* + * Some variables have no address range meaning it's always + * available in the whole scope. Let's adjust the start + * address to the start of the scope. + */ + if (var_types->addr == 0) + var_types->addr = addr; + + var_types = var_types->next; + } +} + +static void delete_var_types(struct die_var_type *var_types) +{ + while (var_types) { + struct die_var_type *next = var_types->next; + + free(var_types); + var_types = next; + } +} + +/* It's at the target address, check if it has a matching type */ +static bool find_matching_type(struct type_state *state __maybe_unused, + struct data_loc_info *dloc __maybe_unused, + int reg __maybe_unused, + Dwarf_Die *type_die __maybe_unused) +{ + /* TODO */ + return false; +} + +/* Iterate instructions in basic blocks and update type table */ +static bool find_data_type_insn(struct data_loc_info *dloc, int reg, + struct list_head *basic_blocks, + struct die_var_type *var_types, + Dwarf_Die *cu_die, Dwarf_Die *type_die) +{ + struct type_state state; + struct symbol *sym = dloc->ms->sym; + struct annotation *notes = symbol__annotation(sym); + struct annotated_basic_block *bb; + bool found = false; + + init_type_state(&state, dloc->arch); + + list_for_each_entry(bb, basic_blocks, list) { + struct disasm_line *dl = bb->begin; + + pr_debug_dtp("bb: [%"PRIx64" - %"PRIx64"]\n", + bb->begin->al.offset, bb->end->al.offset); + + list_for_each_entry_from(dl, ¬es->src->source, al.node) { + u64 this_ip = sym->start + dl->al.offset; + u64 addr = map__rip_2objdump(dloc->ms->map, this_ip); + + /* Update variable type at this address */ + update_var_state(&state, dloc, addr, dl->al.offset, var_types); + + if (this_ip == dloc->ip) { + found = find_matching_type(&state, dloc, reg, + type_die); + goto out; + } + + /* Update type table after processing the instruction */ + update_insn_state(&state, dloc, cu_die, dl); + if (dl == bb->end) + break; + } + } + +out: + exit_type_state(&state); + return found; +} + +/* + * Construct a list of basic blocks for each scope with variables and try to find + * the data type by updating a type state table through instructions. + */ +static int find_data_type_block(struct data_loc_info *dloc, int reg, + Dwarf_Die *cu_die, Dwarf_Die *scopes, + int nr_scopes, Dwarf_Die *type_die) +{ + LIST_HEAD(basic_blocks); + struct die_var_type *var_types = NULL; + u64 src_ip, dst_ip, prev_dst_ip; + int ret = -1; + + /* TODO: other architecture support */ + if (!arch__is(dloc->arch, "x86")) + return -1; + + prev_dst_ip = dst_ip = dloc->ip; + for (int i = nr_scopes - 1; i >= 0; i--) { + Dwarf_Addr base, start, end; + LIST_HEAD(this_blocks); + + if (dwarf_ranges(&scopes[i], 0, &base, &start, &end) < 0) + break; + + pr_debug_dtp("scope: [%d/%d] (die:%lx)\n", + i + 1, nr_scopes, (long)dwarf_dieoffset(&scopes[i])); + src_ip = map__objdump_2rip(dloc->ms->map, start); + +again: + /* Get basic blocks for this scope */ + if (annotate_get_basic_blocks(dloc->ms->sym, src_ip, dst_ip, + &this_blocks) < 0) { + /* Try previous block if they are not connected */ + if (prev_dst_ip != dst_ip) { + dst_ip = prev_dst_ip; + goto again; + } + + pr_debug_dtp("cannot find a basic block from %"PRIx64" to %"PRIx64"\n", + src_ip - dloc->ms->sym->start, + dst_ip - dloc->ms->sym->start); + continue; + } + prepend_basic_blocks(&this_blocks, &basic_blocks); + + /* Get variable info for this scope and add to var_types list */ + die_collect_vars(&scopes[i], &var_types); + fixup_var_address(var_types, start); + + /* Find from start of this scope to the target instruction */ + if (find_data_type_insn(dloc, reg, &basic_blocks, var_types, + cu_die, type_die)) { + ret = 0; + break; + } + + /* Go up to the next scope and find blocks to the start */ + prev_dst_ip = dst_ip; + dst_ip = src_ip; + } + + delete_basic_blocks(&basic_blocks); + delete_var_types(var_types); + return ret; +} + /* The result will be saved in @type_die */ static int find_data_type_die(struct data_loc_info *dloc, Dwarf_Die *type_die) { @@ -847,6 +1033,15 @@ retry: goto out; } + if (reg != DWARF_REG_PC) { + ret = find_data_type_block(dloc, reg, &cu_die, scopes, + nr_scopes, type_die); + if (ret == 0) { + ann_data_stat.insn_track++; + goto out; + } + } + if (loc->multi_regs && reg == loc->reg1 && loc->reg1 != loc->reg2) { reg = loc->reg2; goto retry; diff --git a/tools/perf/util/annotate-data.h b/tools/perf/util/annotate-data.h index acfbd1748d02..ae0f87aed804 100644 --- a/tools/perf/util/annotate-data.h +++ b/tools/perf/util/annotate-data.h @@ -135,6 +135,7 @@ struct annotated_data_stat { int no_typeinfo; int invalid_size; int bad_offset; + int insn_track; }; extern struct annotated_data_stat ann_data_stat; -- cgit v1.2.3-59-g8ed1b From bdc80ace07106a62b51d1752869df29dbd65ad2c Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Mon, 18 Mar 2024 22:51:07 -0700 Subject: perf annotate-data: Check register state for type As instruction tracking updates the type state for each register, check the final type info for the target register at the given instruction. Signed-off-by: Namhyung Kim Cc: Adrian Hunter Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Linus Torvalds Cc: Masami Hiramatsu Cc: Peter Zijlstra Cc: Stephane Eranian Link: https://lore.kernel.org/r/20240319055115.4063940-16-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate-data.c | 88 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 81 insertions(+), 7 deletions(-) diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c index 13ba65693367..f5329a78a97d 100644 --- a/tools/perf/util/annotate-data.c +++ b/tools/perf/util/annotate-data.c @@ -788,12 +788,83 @@ static void delete_var_types(struct die_var_type *var_types) } /* It's at the target address, check if it has a matching type */ -static bool find_matching_type(struct type_state *state __maybe_unused, - struct data_loc_info *dloc __maybe_unused, - int reg __maybe_unused, - Dwarf_Die *type_die __maybe_unused) +static bool check_matching_type(struct type_state *state, + struct data_loc_info *dloc, int reg, + Dwarf_Die *type_die) { - /* TODO */ + Dwarf_Word size; + u32 insn_offset = dloc->ip - dloc->ms->sym->start; + + pr_debug_dtp("chk [%x] reg%d offset=%#x ok=%d", + insn_offset, reg, dloc->op->offset, state->regs[reg].ok); + + if (state->regs[reg].ok) { + int tag = dwarf_tag(&state->regs[reg].type); + + pr_debug_dtp("\n"); + + /* + * Normal registers should hold a pointer (or array) to + * dereference a memory location. + */ + if (tag != DW_TAG_pointer_type && tag != DW_TAG_array_type) + return false; + + /* Remove the pointer and get the target type */ + if (die_get_real_type(&state->regs[reg].type, type_die) == NULL) + return false; + + dloc->type_offset = dloc->op->offset; + + /* Get the size of the actual type */ + if (dwarf_aggregate_size(type_die, &size) < 0 || + (unsigned)dloc->type_offset >= size) + return false; + + return true; + } + + if (reg == dloc->fbreg) { + struct type_state_stack *stack; + + pr_debug_dtp(" fbreg\n"); + + stack = find_stack_state(state, dloc->type_offset); + if (stack == NULL) + return false; + + *type_die = stack->type; + /* Update the type offset from the start of slot */ + dloc->type_offset -= stack->offset; + + return true; + } + + if (dloc->fb_cfa) { + struct type_state_stack *stack; + u64 pc = map__rip_2objdump(dloc->ms->map, dloc->ip); + int fbreg, fboff; + + pr_debug_dtp(" cfa\n"); + + if (die_get_cfa(dloc->di->dbg, pc, &fbreg, &fboff) < 0) + fbreg = -1; + + if (reg != fbreg) + return false; + + stack = find_stack_state(state, dloc->type_offset - fboff); + if (stack == NULL) + return false; + + *type_die = stack->type; + /* Update the type offset from the start of slot */ + dloc->type_offset -= fboff + stack->offset; + + return true; + } + + pr_debug_dtp("\n"); return false; } @@ -825,8 +896,8 @@ static bool find_data_type_insn(struct data_loc_info *dloc, int reg, update_var_state(&state, dloc, addr, dl->al.offset, var_types); if (this_ip == dloc->ip) { - found = find_matching_type(&state, dloc, reg, - type_die); + found = check_matching_type(&state, dloc, reg, + type_die); goto out; } @@ -896,6 +967,9 @@ again: if (find_data_type_insn(dloc, reg, &basic_blocks, var_types, cu_die, type_die)) { ret = 0; + pr_debug_dtp("found by insn track: %#x(reg%d) type-offset=%#x", + dloc->op->offset, reg, dloc->type_offset); + pr_debug_type_name(type_die); break; } -- cgit v1.2.3-59-g8ed1b From cbaf89a8c5b467f99dd930f24a698f3fa338b012 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Mon, 18 Mar 2024 22:51:08 -0700 Subject: perf annotate: Parse x86 segment register location Add a segment field in the struct annotated_insn_loc and save it for the segment based addressing like %gs:0x28. For simplicity it now handles %gs register only. Signed-off-by: Namhyung Kim Cc: Adrian Hunter Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Linus Torvalds Cc: Masami Hiramatsu Cc: Peter Zijlstra Cc: Stephane Eranian Link: https://lore.kernel.org/r/20240319055115.4063940-17-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 36 ++++++++++++++++++++++++++++++++---- tools/perf/util/annotate.h | 15 +++++++++++++++ 2 files changed, 47 insertions(+), 4 deletions(-) diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index abb641aa8ec0..3aa3a3b987ad 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -94,6 +94,7 @@ struct arch { char skip_functions_char; char register_char; char memory_ref_char; + char imm_char; } objdump; }; @@ -211,6 +212,7 @@ static struct arch architectures[] = { .comment_char = '#', .register_char = '%', .memory_ref_char = '(', + .imm_char = '$', }, }, { @@ -3585,6 +3587,12 @@ static int extract_reg_offset(struct arch *arch, const char *str, * %gs:0x18(%rbx). In that case it should skip the part. */ if (*str == arch->objdump.register_char) { + if (arch__is(arch, "x86")) { + /* FIXME: Handle other segment registers */ + if (!strncmp(str, "%gs:", 4)) + op_loc->segment = INSN_SEG_X86_GS; + } + while (*str && !isdigit(*str) && *str != arch->objdump.memory_ref_char) str++; @@ -3681,12 +3689,32 @@ int annotate_get_insn_location(struct arch *arch, struct disasm_line *dl, op_loc->multi_regs = multi_regs; extract_reg_offset(arch, insn_str, op_loc); } else { - char *s = strdup(insn_str); + char *s, *p = NULL; + + if (arch__is(arch, "x86")) { + /* FIXME: Handle other segment registers */ + if (!strncmp(insn_str, "%gs:", 4)) { + op_loc->segment = INSN_SEG_X86_GS; + op_loc->offset = strtol(insn_str + 4, + &p, 0); + if (p && p != insn_str + 4) + op_loc->imm = true; + continue; + } + } + + s = strdup(insn_str); + if (s == NULL) + return -1; - if (s) { + if (*s == arch->objdump.register_char) op_loc->reg1 = get_dwarf_regnum(s, 0); - free(s); + else if (*s == arch->objdump.imm_char) { + op_loc->offset = strtol(s + 1, &p, 0); + if (p && p != s + 1) + op_loc->imm = true; } + free(s); } } @@ -3881,7 +3909,7 @@ retry: .op = op_loc, }; - if (!op_loc->mem_ref) + if (!op_loc->mem_ref && op_loc->segment == INSN_SEG_NONE) continue; /* Recalculate IP because of LOCK prefix or insn fusion */ diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 0928663fddee..14980b65f812 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -511,15 +511,19 @@ int annotate_check_args(void); * @reg1: First register in the operand * @reg2: Second register in the operand * @offset: Memory access offset in the operand + * @segment: Segment selector register * @mem_ref: Whether the operand accesses memory * @multi_regs: Whether the second register is used + * @imm: Whether the operand is an immediate value (in offset) */ struct annotated_op_loc { int reg1; int reg2; int offset; + u8 segment; bool mem_ref; bool multi_regs; + bool imm; }; enum annotated_insn_ops { @@ -529,6 +533,17 @@ enum annotated_insn_ops { INSN_OP_MAX, }; +enum annotated_x86_segment { + INSN_SEG_NONE = 0, + + INSN_SEG_X86_CS, + INSN_SEG_X86_DS, + INSN_SEG_X86_ES, + INSN_SEG_X86_FS, + INSN_SEG_X86_GS, + INSN_SEG_X86_SS, +}; + /** * struct annotated_insn_loc - Location info of instruction * @ops: Array of location info for source and target operands -- cgit v1.2.3-59-g8ed1b From 02e17ca917423c622da10ac6bd0924c17462962e Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Mon, 18 Mar 2024 22:51:09 -0700 Subject: perf annotate-data: Handle this-cpu variables in kernel On x86, the kernel gets the current task using the current macro like below: #define current get_current() static __always_inline struct task_struct *get_current(void) { return this_cpu_read_stable(pcpu_hot.current_task); } So it returns the current_task field of struct pcpu_hot which is the first member. On my build, it's located at 0x32940. $ nm vmlinux | grep pcpu_hot 0000000000032940 D pcpu_hot And the current macro generates the instructions like below: mov %gs:0x32940, %rcx So the %gs segment register points to the beginning of the per-cpu region of this cpu and it points the variable with a constant. Let's update the instruction location info to have a segment register and handle %gs in kernel to look up a global variable. Pretend it as a global variable by changing the register number to DWARF_REG_PC. Signed-off-by: Namhyung Kim Cc: Adrian Hunter Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Linus Torvalds Cc: Masami Hiramatsu Cc: Peter Zijlstra Cc: Stephane Eranian Link: https://lore.kernel.org/r/20240319055115.4063940-18-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate-data.c | 21 +++++++++++++++++++-- tools/perf/util/annotate.c | 7 +++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c index f5329a78a97d..d57622ddd5d3 100644 --- a/tools/perf/util/annotate-data.c +++ b/tools/perf/util/annotate-data.c @@ -790,7 +790,7 @@ static void delete_var_types(struct die_var_type *var_types) /* It's at the target address, check if it has a matching type */ static bool check_matching_type(struct type_state *state, struct data_loc_info *dloc, int reg, - Dwarf_Die *type_die) + Dwarf_Die *cu_die, Dwarf_Die *type_die) { Dwarf_Word size; u32 insn_offset = dloc->ip - dloc->ms->sym->start; @@ -864,6 +864,23 @@ static bool check_matching_type(struct type_state *state, return true; } + if (map__dso(dloc->ms->map)->kernel && arch__is(dloc->arch, "x86")) { + u64 addr; + int offset; + + if (dloc->op->segment == INSN_SEG_X86_GS && dloc->op->imm) { + pr_debug_dtp(" this-cpu var\n"); + + addr = dloc->op->offset; + + if (get_global_var_type(cu_die, dloc, dloc->ip, addr, + &offset, type_die)) { + dloc->type_offset = offset; + return true; + } + } + } + pr_debug_dtp("\n"); return false; } @@ -897,7 +914,7 @@ static bool find_data_type_insn(struct data_loc_info *dloc, int reg, if (this_ip == dloc->ip) { found = check_matching_type(&state, dloc, reg, - type_die); + cu_die, type_die); goto out; } diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 3aa3a3b987ad..e4121acb4f88 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -3921,6 +3921,13 @@ retry: op_loc->offset, dl); } + /* This CPU access in kernel - pretend PC-relative addressing */ + if (map__dso(ms->map)->kernel && arch__is(arch, "x86") && + op_loc->segment == INSN_SEG_X86_GS && op_loc->imm) { + dloc.var_addr = op_loc->offset; + op_loc->reg1 = DWARF_REG_PC; + } + mem_type = find_data_type(&dloc); if (mem_type) istat->good++; -- cgit v1.2.3-59-g8ed1b From ad62edbfc55b23347539c8c6fff9a70de17c4b95 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Mon, 18 Mar 2024 22:51:10 -0700 Subject: perf annotate-data: Track instructions with a this-cpu variable Like global variables, this per-cpu variables should be tracked correctly. Factor our get_global_var_type() to handle both global and per-cpu (for this cpu) variables in the same manner. Signed-off-by: Namhyung Kim Cc: Adrian Hunter Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Linus Torvalds Cc: Masami Hiramatsu Cc: Peter Zijlstra Cc: Stephane Eranian Link: https://lore.kernel.org/r/20240319055115.4063940-19-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate-data.c | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c index d57622ddd5d3..48fea0c716ef 100644 --- a/tools/perf/util/annotate-data.c +++ b/tools/perf/util/annotate-data.c @@ -553,12 +553,41 @@ static void update_insn_state_x86(struct type_state *state, fbreg = -1; } - /* Case 1. register to register transfers */ + /* Case 1. register to register or segment:offset to register transfers */ if (!src->mem_ref && !dst->mem_ref) { if (!has_reg_type(state, dst->reg1)) return; tsr = &state->regs[dst->reg1]; + if (map__dso(dloc->ms->map)->kernel && + src->segment == INSN_SEG_X86_GS && src->imm) { + u64 ip = dloc->ms->sym->start + dl->al.offset; + u64 var_addr; + int offset; + + /* + * In kernel, %gs points to a per-cpu region for the + * current CPU. Access with a constant offset should + * be treated as a global variable access. + */ + var_addr = src->offset; + + if (!get_global_var_type(cu_die, dloc, ip, var_addr, + &offset, &type_die) || + !die_get_member_type(&type_die, offset, &type_die)) { + tsr->ok = false; + return; + } + + tsr->type = type_die; + tsr->ok = true; + + pr_debug_dtp("mov [%x] this-cpu addr=%#"PRIx64" -> reg%d", + insn_offset, var_addr, dst->reg1); + pr_debug_type_name(&tsr->type); + return; + } + if (!has_reg_type(state, src->reg1) || !state->regs[src->reg1].ok) { tsr->ok = false; -- cgit v1.2.3-59-g8ed1b From f5b095924d0c1c2f0698df07c54887d92c39fd3a Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Mon, 18 Mar 2024 22:51:11 -0700 Subject: perf annotate-data: Support general per-cpu access This is to support per-cpu variable access often without a matching DWARF entry. For some reason, I cannot find debug info of per-cpu variables sometimes. They have more complex pattern to calculate the address of per-cpu variables like below. 2b7d: mov -0x1e0(%rbp),%rax ; rax = cpu 2b84: mov -0x7da0f7e0(,%rax,8),%rcx ; rcx = __per_cpu_offset[cpu] * 2b8c: mov 0x34870(%rcx),%rax ; *(__per_cpu_offset[cpu] + 0x34870) Let's assume the rax register has a number for a CPU at 2b7d. The next instruction is to get the per-cpu offset' for that cpu. The offset -0x7da0f7e0 is 0xffffffff825f0820 in u64 which is the address of the '__per_cpu_offset' array in my system. So it'd get the actual offset of that CPU's per-cpu region and save it to the rcx register. Then, at 2b8c, accesses using rcx can be handled same as the global variable access. To handle this case, it should check if the offset of the instruction matches to the address of '__per_cpu_offset'. Signed-off-by: Namhyung Kim Cc: Adrian Hunter Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Linus Torvalds Cc: Masami Hiramatsu Cc: Peter Zijlstra Cc: Stephane Eranian Link: https://lore.kernel.org/r/20240319055115.4063940-20-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate-data.c | 213 +++++++++++++++++++++++++++++++--------- 1 file changed, 169 insertions(+), 44 deletions(-) diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c index 48fea0c716ef..83b5aa00f01c 100644 --- a/tools/perf/util/annotate-data.c +++ b/tools/perf/util/annotate-data.c @@ -24,6 +24,12 @@ #include "symbol_conf.h" #include "thread.h" +enum type_state_kind { + TSR_KIND_INVALID = 0, + TSR_KIND_TYPE, + TSR_KIND_PERCPU_BASE, +}; + #define pr_debug_dtp(fmt, ...) \ do { \ if (debug_type_profile) \ @@ -32,7 +38,7 @@ do { \ pr_debug3(fmt, ##__VA_ARGS__); \ } while (0) -static void pr_debug_type_name(Dwarf_Die *die) +static void pr_debug_type_name(Dwarf_Die *die, enum type_state_kind kind) { struct strbuf sb; char *str; @@ -40,6 +46,18 @@ static void pr_debug_type_name(Dwarf_Die *die) if (!debug_type_profile && verbose < 3) return; + switch (kind) { + case TSR_KIND_INVALID: + pr_info("\n"); + return; + case TSR_KIND_PERCPU_BASE: + pr_info(" percpu base\n"); + return; + case TSR_KIND_TYPE: + default: + break; + } + strbuf_init(&sb, 32); die_get_typename_from_type(die, &sb); str = strbuf_detach(&sb, NULL); @@ -53,8 +71,10 @@ static void pr_debug_type_name(Dwarf_Die *die) */ struct type_state_reg { Dwarf_Die type; + u32 imm_value; bool ok; bool caller_saved; + u8 kind; }; /* Type information in a stack location, dynamically allocated */ @@ -64,6 +84,7 @@ struct type_state_stack { int offset; int size; bool compound; + u8 kind; }; /* FIXME: This should be arch-dependent */ @@ -82,6 +103,8 @@ struct type_state { struct list_head stack_vars; /* return value register */ int ret_reg; + /* stack pointer register */ + int stack_reg; }; static bool has_reg_type(struct type_state *state, int reg) @@ -105,6 +128,7 @@ static void init_type_state(struct type_state *state, struct arch *arch) state->regs[10].caller_saved = true; state->regs[11].caller_saved = true; state->ret_reg = 0; + state->stack_reg = 7; } } @@ -350,7 +374,7 @@ static struct type_state_stack *find_stack_state(struct type_state *state, return NULL; } -static void set_stack_state(struct type_state_stack *stack, int offset, +static void set_stack_state(struct type_state_stack *stack, int offset, u8 kind, Dwarf_Die *type_die) { int tag; @@ -364,6 +388,7 @@ static void set_stack_state(struct type_state_stack *stack, int offset, stack->type = *type_die; stack->size = size; stack->offset = offset; + stack->kind = kind; switch (tag) { case DW_TAG_structure_type: @@ -377,34 +402,60 @@ static void set_stack_state(struct type_state_stack *stack, int offset, } static struct type_state_stack *findnew_stack_state(struct type_state *state, - int offset, Dwarf_Die *type_die) + int offset, u8 kind, + Dwarf_Die *type_die) { struct type_state_stack *stack = find_stack_state(state, offset); if (stack) { - set_stack_state(stack, offset, type_die); + set_stack_state(stack, offset, kind, type_die); return stack; } stack = malloc(sizeof(*stack)); if (stack) { - set_stack_state(stack, offset, type_die); + set_stack_state(stack, offset, kind, type_die); list_add(&stack->list, &state->stack_vars); } return stack; } +static bool get_global_var_info(struct data_loc_info *dloc, u64 addr, + const char **var_name, int *var_offset) +{ + struct addr_location al; + struct symbol *sym; + u64 mem_addr; + + /* Kernel symbols might be relocated */ + mem_addr = addr + map__reloc(dloc->ms->map); + + addr_location__init(&al); + sym = thread__find_symbol_fb(dloc->thread, dloc->cpumode, + mem_addr, &al); + if (sym) { + *var_name = sym->name; + /* Calculate type offset from the start of variable */ + *var_offset = mem_addr - map__unmap_ip(al.map, sym->start); + } else { + *var_name = NULL; + } + addr_location__exit(&al); + if (*var_name == NULL) + return false; + + return true; +} + static bool get_global_var_type(Dwarf_Die *cu_die, struct data_loc_info *dloc, u64 ip, u64 var_addr, int *var_offset, Dwarf_Die *type_die) { - u64 pc, mem_addr; + u64 pc; int offset; bool is_pointer = false; - const char *var_name = NULL; + const char *var_name; Dwarf_Die var_die; - struct addr_location al; - struct symbol *sym; /* Try to get the variable by address first */ if (die_find_variable_by_addr(cu_die, var_addr, &var_die, &offset) && @@ -413,19 +464,7 @@ static bool get_global_var_type(Dwarf_Die *cu_die, struct data_loc_info *dloc, return true; } - /* Kernel symbols might be relocated */ - mem_addr = var_addr + map__reloc(dloc->ms->map); - - addr_location__init(&al); - sym = thread__find_symbol_fb(dloc->thread, dloc->cpumode, - mem_addr, &al); - if (sym) { - var_name = sym->name; - /* Calculate type offset from the start of variable */ - *var_offset = mem_addr - map__unmap_ip(al.map, sym->start); - } - addr_location__exit(&al); - if (var_name == NULL) + if (!get_global_var_info(dloc, var_addr, &var_name, var_offset)) return false; pc = map__rip_2objdump(dloc->ms->map, ip); @@ -470,27 +509,30 @@ static void update_var_state(struct type_state *state, struct data_loc_info *dlo continue; if (var->reg == DWARF_REG_FB) { - findnew_stack_state(state, var->offset, &mem_die); + findnew_stack_state(state, var->offset, TSR_KIND_TYPE, + &mem_die); pr_debug_dtp("var [%"PRIx64"] -%#x(stack)", insn_offset, -var->offset); - pr_debug_type_name(&mem_die); + pr_debug_type_name(&mem_die, TSR_KIND_TYPE); } else if (var->reg == fbreg) { - findnew_stack_state(state, var->offset - fb_offset, &mem_die); + findnew_stack_state(state, var->offset - fb_offset, + TSR_KIND_TYPE, &mem_die); pr_debug_dtp("var [%"PRIx64"] -%#x(stack)", insn_offset, -var->offset + fb_offset); - pr_debug_type_name(&mem_die); + pr_debug_type_name(&mem_die, TSR_KIND_TYPE); } else if (has_reg_type(state, var->reg) && var->offset == 0) { struct type_state_reg *reg; reg = &state->regs[var->reg]; reg->type = mem_die; + reg->kind = TSR_KIND_TYPE; reg->ok = true; pr_debug_dtp("var [%"PRIx64"] reg%d", insn_offset, var->reg); - pr_debug_type_name(&mem_die); + pr_debug_type_name(&mem_die, TSR_KIND_TYPE); } } } @@ -533,11 +575,12 @@ static void update_insn_state_x86(struct type_state *state, if (die_find_func_rettype(cu_die, func->name, &type_die)) { tsr = &state->regs[state->ret_reg]; tsr->type = type_die; + tsr->kind = TSR_KIND_TYPE; tsr->ok = true; pr_debug_dtp("call [%x] return -> reg%d", insn_offset, state->ret_reg); - pr_debug_type_name(&type_die); + pr_debug_type_name(&type_die, tsr->kind); } return; } @@ -580,11 +623,12 @@ static void update_insn_state_x86(struct type_state *state, } tsr->type = type_die; + tsr->kind = TSR_KIND_TYPE; tsr->ok = true; pr_debug_dtp("mov [%x] this-cpu addr=%#"PRIx64" -> reg%d", insn_offset, var_addr, dst->reg1); - pr_debug_type_name(&tsr->type); + pr_debug_type_name(&tsr->type, tsr->kind); return; } @@ -595,11 +639,12 @@ static void update_insn_state_x86(struct type_state *state, } tsr->type = state->regs[src->reg1].type; + tsr->kind = state->regs[src->reg1].kind; tsr->ok = true; pr_debug_dtp("mov [%x] reg%d -> reg%d", insn_offset, src->reg1, dst->reg1); - pr_debug_type_name(&tsr->type); + pr_debug_type_name(&tsr->type, tsr->kind); } /* Case 2. memory to register transers */ if (src->mem_ref && !dst->mem_ref) { @@ -622,11 +667,13 @@ retry: return; } else if (!stack->compound) { tsr->type = stack->type; + tsr->kind = stack->kind; tsr->ok = true; } else if (die_get_member_type(&stack->type, offset - stack->offset, &type_die)) { tsr->type = type_die; + tsr->kind = TSR_KIND_TYPE; tsr->ok = true; } else { tsr->ok = false; @@ -635,18 +682,20 @@ retry: pr_debug_dtp("mov [%x] -%#x(stack) -> reg%d", insn_offset, -offset, dst->reg1); - pr_debug_type_name(&tsr->type); + pr_debug_type_name(&tsr->type, tsr->kind); } /* And then dereference the pointer if it has one */ else if (has_reg_type(state, sreg) && state->regs[sreg].ok && + state->regs[sreg].kind == TSR_KIND_TYPE && die_deref_ptr_type(&state->regs[sreg].type, src->offset, &type_die)) { tsr->type = type_die; + tsr->kind = TSR_KIND_TYPE; tsr->ok = true; pr_debug_dtp("mov [%x] %#x(reg%d) -> reg%d", insn_offset, src->offset, sreg, dst->reg1); - pr_debug_type_name(&tsr->type); + pr_debug_type_name(&tsr->type, tsr->kind); } /* Or check if it's a global variable */ else if (sreg == DWARF_REG_PC) { @@ -665,11 +714,37 @@ retry: } tsr->type = type_die; + tsr->kind = TSR_KIND_TYPE; tsr->ok = true; pr_debug_dtp("mov [%x] global addr=%"PRIx64" -> reg%d", insn_offset, addr, dst->reg1); - pr_debug_type_name(&type_die); + pr_debug_type_name(&type_die, tsr->kind); + } + /* And check percpu access with base register */ + else if (has_reg_type(state, sreg) && + state->regs[sreg].kind == TSR_KIND_PERCPU_BASE) { + u64 ip = dloc->ms->sym->start + dl->al.offset; + int offset; + + /* + * In kernel, %gs points to a per-cpu region for the + * current CPU. Access with a constant offset should + * be treated as a global variable access. + */ + if (get_global_var_type(cu_die, dloc, ip, src->offset, + &offset, &type_die) && + die_get_member_type(&type_die, offset, &type_die)) { + tsr->type = type_die; + tsr->kind = TSR_KIND_TYPE; + tsr->ok = true; + + pr_debug_dtp("mov [%x] percpu %#x(reg%d) -> reg%d type=", + insn_offset, src->offset, sreg, dst->reg1); + pr_debug_type_name(&tsr->type, tsr->kind); + } else { + tsr->ok = false; + } } /* Or try another register if any */ else if (src->multi_regs && sreg == src->reg1 && @@ -677,8 +752,22 @@ retry: sreg = src->reg2; goto retry; } - /* It failed to get a type info, mark it as invalid */ else { + int offset; + const char *var_name = NULL; + + /* it might be per-cpu variable (in kernel) access */ + if (src->offset < 0) { + if (get_global_var_info(dloc, (s64)src->offset, + &var_name, &offset) && + !strcmp(var_name, "__per_cpu_offset")) { + tsr->kind = TSR_KIND_PERCPU_BASE; + + pr_debug_dtp("mov [%x] percpu base reg%d\n", + insn_offset, dst->reg1); + } + } + tsr->ok = false; } } @@ -693,6 +782,8 @@ retry: struct type_state_stack *stack; int offset = dst->offset - fboff; + tsr = &state->regs[src->reg1]; + stack = find_stack_state(state, offset); if (stack) { /* @@ -703,16 +794,16 @@ retry: * die_get_member_type(). */ if (!stack->compound) - set_stack_state(stack, offset, - &state->regs[src->reg1].type); + set_stack_state(stack, offset, tsr->kind, + &tsr->type); } else { - findnew_stack_state(state, offset, - &state->regs[src->reg1].type); + findnew_stack_state(state, offset, tsr->kind, + &tsr->type); } pr_debug_dtp("mov [%x] reg%d -> -%#x(stack)", insn_offset, src->reg1, -offset); - pr_debug_type_name(&state->regs[src->reg1].type); + pr_debug_type_name(&tsr->type, tsr->kind); } /* * Ignore other transfers since it'd set a value in a struct @@ -824,10 +915,11 @@ static bool check_matching_type(struct type_state *state, Dwarf_Word size; u32 insn_offset = dloc->ip - dloc->ms->sym->start; - pr_debug_dtp("chk [%x] reg%d offset=%#x ok=%d", - insn_offset, reg, dloc->op->offset, state->regs[reg].ok); + pr_debug_dtp("chk [%x] reg%d offset=%#x ok=%d kind=%d", + insn_offset, reg, dloc->op->offset, + state->regs[reg].ok, state->regs[reg].kind); - if (state->regs[reg].ok) { + if (state->regs[reg].ok && state->regs[reg].kind == TSR_KIND_TYPE) { int tag = dwarf_tag(&state->regs[reg].type); pr_debug_dtp("\n"); @@ -893,10 +985,25 @@ static bool check_matching_type(struct type_state *state, return true; } + if (state->regs[reg].kind == TSR_KIND_PERCPU_BASE) { + u64 var_addr = dloc->op->offset; + int var_offset; + + pr_debug_dtp(" percpu var\n"); + + if (get_global_var_type(cu_die, dloc, dloc->ip, var_addr, + &var_offset, type_die)) { + dloc->type_offset = var_offset; + return true; + } + return false; + } + if (map__dso(dloc->ms->map)->kernel && arch__is(dloc->arch, "x86")) { u64 addr; int offset; + /* Direct this-cpu access like "%gs:0x34740" */ if (dloc->op->segment == INSN_SEG_X86_GS && dloc->op->imm) { pr_debug_dtp(" this-cpu var\n"); @@ -907,6 +1014,24 @@ static bool check_matching_type(struct type_state *state, dloc->type_offset = offset; return true; } + return false; + } + + /* Access to per-cpu base like "-0x7dcf0500(,%rdx,8)" */ + if (dloc->op->offset < 0 && reg != state->stack_reg) { + const char *var_name = NULL; + + addr = (s64) dloc->op->offset; + + if (get_global_var_info(dloc, addr, &var_name, &offset) && + !strcmp(var_name, "__per_cpu_offset") && offset == 0 && + get_global_var_type(cu_die, dloc, dloc->ip, addr, + &offset, type_die)) { + pr_debug_dtp(" percpu base\n"); + + dloc->type_offset = offset; + return true; + } } } @@ -1015,7 +1140,7 @@ again: ret = 0; pr_debug_dtp("found by insn track: %#x(reg%d) type-offset=%#x", dloc->op->offset, reg, dloc->type_offset); - pr_debug_type_name(type_die); + pr_debug_type_name(type_die, TSR_KIND_TYPE); break; } @@ -1147,7 +1272,7 @@ retry: loc->offset, reg, fb_offset, offset); else pr_debug_dtp("%#x(reg%d)", loc->offset, reg); - pr_debug_type_name(type_die); + pr_debug_type_name(type_die, TSR_KIND_TYPE); } dloc->type_offset = offset; goto out; -- cgit v1.2.3-59-g8ed1b From eb9190afaed6afd5ed54bb0a3269eec338663858 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Mon, 18 Mar 2024 22:51:12 -0700 Subject: perf annotate-data: Handle ADD instructions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are different patterns for percpu variable access using a constant value added to the base.  2aeb:  mov    -0x7da0f7e0(,%rax,8),%r14 # r14 = __per_cpu_offset[cpu]  2af3:  mov    $0x34740,%rax # rax = address of runqueues * 2afa:  add    %rax,%r14 # r14 = &per_cpu(runqueues, cpu)  2bfd:  cmpl   $0x0,0x10(%r14) # cpu_rq(cpu)->has_blocked_load  2b03:  je     0x2b36 At the first instruction, r14 has the __per_cpu_offset. And then rax has an immediate value and then added to r14 to calculate the address of a per-cpu variable. So it needs to track the immediate values and ADD instructions. Similar but a little different case is to use "this_cpu_off" instead of "__per_cpu_offset" for the current CPU. This time the variable address comes with PC-rel addressing. 89: mov $0x34740,%rax # rax = address of runqueues * 90: add %gs:0x7f015f60(%rip),%rax # 19a78 98: incl 0xd8c(%rax) # cpu_rq(cpu)->sched_count Signed-off-by: Namhyung Kim Cc: Adrian Hunter Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Linus Torvalds Cc: Masami Hiramatsu Cc: Peter Zijlstra Cc: Stephane Eranian Link: https://lore.kernel.org/r/20240319055115.4063940-21-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate-data.c | 107 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 105 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c index 83b5aa00f01c..bd10a576cfbf 100644 --- a/tools/perf/util/annotate-data.c +++ b/tools/perf/util/annotate-data.c @@ -28,6 +28,8 @@ enum type_state_kind { TSR_KIND_INVALID = 0, TSR_KIND_TYPE, TSR_KIND_PERCPU_BASE, + TSR_KIND_CONST, + TSR_KIND_POINTER, }; #define pr_debug_dtp(fmt, ...) \ @@ -53,6 +55,13 @@ static void pr_debug_type_name(Dwarf_Die *die, enum type_state_kind kind) case TSR_KIND_PERCPU_BASE: pr_info(" percpu base\n"); return; + case TSR_KIND_CONST: + pr_info(" constant\n"); + return; + case TSR_KIND_POINTER: + pr_info(" pointer"); + /* it also prints the type info */ + break; case TSR_KIND_TYPE: default: break; @@ -393,7 +402,7 @@ static void set_stack_state(struct type_state_stack *stack, int offset, u8 kind, switch (tag) { case DW_TAG_structure_type: case DW_TAG_union_type: - stack->compound = true; + stack->compound = (kind != TSR_KIND_POINTER); break; default: stack->compound = false; @@ -585,6 +594,58 @@ static void update_insn_state_x86(struct type_state *state, return; } + if (!strncmp(dl->ins.name, "add", 3)) { + u64 imm_value = -1ULL; + int offset; + const char *var_name = NULL; + struct map_symbol *ms = dloc->ms; + u64 ip = ms->sym->start + dl->al.offset; + + if (!has_reg_type(state, dst->reg1)) + return; + + tsr = &state->regs[dst->reg1]; + + if (src->imm) + imm_value = src->offset; + else if (has_reg_type(state, src->reg1) && + state->regs[src->reg1].kind == TSR_KIND_CONST) + imm_value = state->regs[src->reg1].imm_value; + else if (src->reg1 == DWARF_REG_PC) { + u64 var_addr = annotate_calc_pcrel(dloc->ms, ip, + src->offset, dl); + + if (get_global_var_info(dloc, var_addr, + &var_name, &offset) && + !strcmp(var_name, "this_cpu_off") && + tsr->kind == TSR_KIND_CONST) { + tsr->kind = TSR_KIND_PERCPU_BASE; + imm_value = tsr->imm_value; + } + } + else + return; + + if (tsr->kind != TSR_KIND_PERCPU_BASE) + return; + + if (get_global_var_type(cu_die, dloc, ip, imm_value, &offset, + &type_die) && offset == 0) { + /* + * This is not a pointer type, but it should be treated + * as a pointer. + */ + tsr->type = type_die; + tsr->kind = TSR_KIND_POINTER; + tsr->ok = true; + + pr_debug_dtp("add [%x] percpu %#"PRIx64" -> reg%d", + insn_offset, imm_value, dst->reg1); + pr_debug_type_name(&tsr->type, tsr->kind); + } + return; + } + if (strncmp(dl->ins.name, "mov", 3)) return; @@ -632,6 +693,16 @@ static void update_insn_state_x86(struct type_state *state, return; } + if (src->imm) { + tsr->kind = TSR_KIND_CONST; + tsr->imm_value = src->offset; + tsr->ok = true; + + pr_debug_dtp("mov [%x] imm=%#x -> reg%d\n", + insn_offset, tsr->imm_value, dst->reg1); + return; + } + if (!has_reg_type(state, src->reg1) || !state->regs[src->reg1].ok) { tsr->ok = false; @@ -739,13 +810,26 @@ retry: tsr->kind = TSR_KIND_TYPE; tsr->ok = true; - pr_debug_dtp("mov [%x] percpu %#x(reg%d) -> reg%d type=", + pr_debug_dtp("mov [%x] percpu %#x(reg%d) -> reg%d", insn_offset, src->offset, sreg, dst->reg1); pr_debug_type_name(&tsr->type, tsr->kind); } else { tsr->ok = false; } } + /* And then dereference the calculated pointer if it has one */ + else if (has_reg_type(state, sreg) && state->regs[sreg].ok && + state->regs[sreg].kind == TSR_KIND_POINTER && + die_get_member_type(&state->regs[sreg].type, + src->offset, &type_die)) { + tsr->type = type_die; + tsr->kind = TSR_KIND_TYPE; + tsr->ok = true; + + pr_debug_dtp("mov [%x] pointer %#x(reg%d) -> reg%d", + insn_offset, src->offset, sreg, dst->reg1); + pr_debug_type_name(&tsr->type, tsr->kind); + } /* Or try another register if any */ else if (src->multi_regs && sreg == src->reg1 && src->reg1 != src->reg2) { @@ -999,6 +1083,25 @@ static bool check_matching_type(struct type_state *state, return false; } + if (state->regs[reg].ok && state->regs[reg].kind == TSR_KIND_POINTER) { + pr_debug_dtp(" percpu ptr\n"); + + /* + * It's actaully pointer but the address was calculated using + * some arithmetic. So it points to the actual type already. + */ + *type_die = state->regs[reg].type; + + dloc->type_offset = dloc->op->offset; + + /* Get the size of the actual type */ + if (dwarf_aggregate_size(type_die, &size) < 0 || + (unsigned)dloc->type_offset >= size) + return false; + + return true; + } + if (map__dso(dloc->ms->map)->kernel && arch__is(dloc->arch, "x86")) { u64 addr; int offset; -- cgit v1.2.3-59-g8ed1b From b3c95109c131fcc959d2473e7c384d8cc62d23d0 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Mon, 18 Mar 2024 22:51:13 -0700 Subject: perf annotate-data: Add stack canary type When the stack protector is enabled, compiler would generate code to check stack overflow with a special value called 'stack carary' at runtime. On x86_64, GCC hard-codes the stack canary as %gs:40. While there's a definition of fixed_percpu_data in asm/processor.h, it seems that the header is not included everywhere and many places it cannot find the type info. As it's in the well-known location (at %gs:40), let's add a pseudo stack canary type to handle it specially. Signed-off-by: Namhyung Kim Cc: Adrian Hunter Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Linus Torvalds Cc: Masami Hiramatsu Cc: Peter Zijlstra Cc: Stephane Eranian Link: https://lore.kernel.org/r/20240319055115.4063940-22-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate-data.c | 46 +++++++++++++++++++++++++++++++++++++++++ tools/perf/util/annotate-data.h | 1 + tools/perf/util/annotate.c | 25 ++++++++++++++++++++++ 3 files changed, 72 insertions(+) diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c index bd10a576cfbf..633fe125fcd8 100644 --- a/tools/perf/util/annotate-data.c +++ b/tools/perf/util/annotate-data.c @@ -30,6 +30,7 @@ enum type_state_kind { TSR_KIND_PERCPU_BASE, TSR_KIND_CONST, TSR_KIND_POINTER, + TSR_KIND_CANARY, }; #define pr_debug_dtp(fmt, ...) \ @@ -62,6 +63,9 @@ static void pr_debug_type_name(Dwarf_Die *die, enum type_state_kind kind) pr_info(" pointer"); /* it also prints the type info */ break; + case TSR_KIND_CANARY: + pr_info(" stack canary\n"); + return; case TSR_KIND_TYPE: default: break; @@ -676,6 +680,15 @@ static void update_insn_state_x86(struct type_state *state, */ var_addr = src->offset; + if (var_addr == 40) { + tsr->kind = TSR_KIND_CANARY; + tsr->ok = true; + + pr_debug_dtp("mov [%x] stack canary -> reg%d\n", + insn_offset, dst->reg1); + return; + } + if (!get_global_var_type(cu_die, dloc, ip, var_addr, &offset, &type_die) || !die_get_member_type(&type_die, offset, &type_die)) { @@ -991,6 +1004,16 @@ static void delete_var_types(struct die_var_type *var_types) } } +/* should match to is_stack_canary() in util/annotate.c */ +static void setup_stack_canary(struct data_loc_info *dloc) +{ + if (arch__is(dloc->arch, "x86")) { + dloc->op->segment = INSN_SEG_X86_GS; + dloc->op->imm = true; + dloc->op->offset = 40; + } +} + /* It's at the target address, check if it has a matching type */ static bool check_matching_type(struct type_state *state, struct data_loc_info *dloc, int reg, @@ -1038,6 +1061,11 @@ static bool check_matching_type(struct type_state *state, if (stack == NULL) return false; + if (stack->kind == TSR_KIND_CANARY) { + setup_stack_canary(dloc); + return false; + } + *type_die = stack->type; /* Update the type offset from the start of slot */ dloc->type_offset -= stack->offset; @@ -1062,6 +1090,11 @@ static bool check_matching_type(struct type_state *state, if (stack == NULL) return false; + if (stack->kind == TSR_KIND_CANARY) { + setup_stack_canary(dloc); + return false; + } + *type_die = stack->type; /* Update the type offset from the start of slot */ dloc->type_offset -= fboff + stack->offset; @@ -1102,6 +1135,19 @@ static bool check_matching_type(struct type_state *state, return true; } + if (state->regs[reg].ok && state->regs[reg].kind == TSR_KIND_CANARY) { + pr_debug_dtp(" stack canary\n"); + + /* + * This is a saved value of the stack canary which will be handled + * in the outer logic when it returns failure here. Pretend it's + * from the stack canary directly. + */ + setup_stack_canary(dloc); + + return false; + } + if (map__dso(dloc->ms->map)->kernel && arch__is(dloc->arch, "x86")) { u64 addr; int offset; diff --git a/tools/perf/util/annotate-data.h b/tools/perf/util/annotate-data.h index ae0f87aed804..1b5a152163b5 100644 --- a/tools/perf/util/annotate-data.h +++ b/tools/perf/util/annotate-data.h @@ -73,6 +73,7 @@ struct annotated_data_type { extern struct annotated_data_type unknown_type; extern struct annotated_data_type stackop_type; +extern struct annotated_data_type canary_type; /** * struct data_loc_info - Data location information diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index e4121acb4f88..64e54ff1aa1d 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -118,6 +118,13 @@ struct annotated_data_type stackop_type = { }, }; +struct annotated_data_type canary_type = { + .self = { + .type_name = (char *)"(stack canary)", + .children = LIST_HEAD_INIT(canary_type.self.children), + }, +}; + static int arch__grow_instructions(struct arch *arch) { struct ins *new_instructions; @@ -3803,6 +3810,18 @@ static bool is_stack_operation(struct arch *arch, struct disasm_line *dl) return false; } +static bool is_stack_canary(struct arch *arch, struct annotated_op_loc *loc) +{ + /* On x86_64, %gs:40 is used for stack canary */ + if (arch__is(arch, "x86")) { + if (loc->segment == INSN_SEG_X86_GS && loc->imm && + loc->offset == 40) + return true; + } + + return false; +} + u64 annotate_calc_pcrel(struct map_symbol *ms, u64 ip, int offset, struct disasm_line *dl) { @@ -3929,6 +3948,12 @@ retry: } mem_type = find_data_type(&dloc); + + if (mem_type == NULL && is_stack_canary(arch, op_loc)) { + mem_type = &canary_type; + dloc.type_offset = 0; + } + if (mem_type) istat->good++; else -- cgit v1.2.3-59-g8ed1b From 55ee3d005d62279d3951a26d5c211a4d9aebc222 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Mon, 18 Mar 2024 22:51:14 -0700 Subject: perf annotate-data: Add a cache for global variable types They are often searched by many different places. Let's add a cache for them to reduce the duplicate DWARF access. Signed-off-by: Namhyung Kim Cc: Adrian Hunter Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Linus Torvalds Cc: Masami Hiramatsu Cc: Peter Zijlstra Cc: Stephane Eranian Link: https://lore.kernel.org/r/20240319055115.4063940-23-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate-data.c | 107 ++++++++++++++++++++++++++++++++++++++-- tools/perf/util/annotate-data.h | 7 +++ tools/perf/util/dso.c | 2 + tools/perf/util/dso.h | 6 ++- 4 files changed, 118 insertions(+), 4 deletions(-) diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c index 633fe125fcd8..969e2f82079c 100644 --- a/tools/perf/util/annotate-data.c +++ b/tools/perf/util/annotate-data.c @@ -433,6 +433,91 @@ static struct type_state_stack *findnew_stack_state(struct type_state *state, return stack; } +/* Maintain a cache for quick global variable lookup */ +struct global_var_entry { + struct rb_node node; + char *name; + u64 start; + u64 end; + u64 die_offset; +}; + +static int global_var_cmp(const void *_key, const struct rb_node *node) +{ + const u64 addr = (uintptr_t)_key; + struct global_var_entry *gvar; + + gvar = rb_entry(node, struct global_var_entry, node); + + if (gvar->start <= addr && addr < gvar->end) + return 0; + return gvar->start > addr ? -1 : 1; +} + +static bool global_var_less(struct rb_node *node_a, const struct rb_node *node_b) +{ + struct global_var_entry *gvar_a, *gvar_b; + + gvar_a = rb_entry(node_a, struct global_var_entry, node); + gvar_b = rb_entry(node_b, struct global_var_entry, node); + + return gvar_a->start < gvar_b->start; +} + +static struct global_var_entry *global_var__find(struct data_loc_info *dloc, u64 addr) +{ + struct dso *dso = map__dso(dloc->ms->map); + struct rb_node *node; + + node = rb_find((void *)(uintptr_t)addr, &dso->global_vars, global_var_cmp); + if (node == NULL) + return NULL; + + return rb_entry(node, struct global_var_entry, node); +} + +static bool global_var__add(struct data_loc_info *dloc, u64 addr, + const char *name, Dwarf_Die *type_die) +{ + struct dso *dso = map__dso(dloc->ms->map); + struct global_var_entry *gvar; + Dwarf_Word size; + + if (dwarf_aggregate_size(type_die, &size) < 0) + return false; + + gvar = malloc(sizeof(*gvar)); + if (gvar == NULL) + return false; + + gvar->name = strdup(name); + if (gvar->name == NULL) { + free(gvar); + return false; + } + + gvar->start = addr; + gvar->end = addr + size; + gvar->die_offset = dwarf_dieoffset(type_die); + + rb_add(&gvar->node, &dso->global_vars, global_var_less); + return true; +} + +void global_var_type__tree_delete(struct rb_root *root) +{ + struct global_var_entry *gvar; + + while (!RB_EMPTY_ROOT(root)) { + struct rb_node *node = rb_first(root); + + rb_erase(node, root); + gvar = rb_entry(node, struct global_var_entry, node); + free(gvar->name); + free(gvar); + } +} + static bool get_global_var_info(struct data_loc_info *dloc, u64 addr, const char **var_name, int *var_offset) { @@ -467,14 +552,25 @@ static bool get_global_var_type(Dwarf_Die *cu_die, struct data_loc_info *dloc, u64 pc; int offset; bool is_pointer = false; - const char *var_name; + const char *var_name = NULL; + struct global_var_entry *gvar; Dwarf_Die var_die; + gvar = global_var__find(dloc, var_addr); + if (gvar) { + if (!dwarf_offdie(dloc->di->dbg, gvar->die_offset, type_die)) + return false; + + *var_offset = var_addr - gvar->start; + return true; + } + /* Try to get the variable by address first */ if (die_find_variable_by_addr(cu_die, var_addr, &var_die, &offset) && check_variable(&var_die, type_die, offset, is_pointer) == 0) { + var_name = dwarf_diename(&var_die); *var_offset = offset; - return true; + goto ok; } if (!get_global_var_info(dloc, var_addr, &var_name, var_offset)) @@ -485,9 +581,14 @@ static bool get_global_var_type(Dwarf_Die *cu_die, struct data_loc_info *dloc, /* Try to get the name of global variable */ if (die_find_variable_at(cu_die, var_name, pc, &var_die) && check_variable(&var_die, type_die, *var_offset, is_pointer) == 0) - return true; + goto ok; return false; + +ok: + /* The address should point to the start of the variable */ + global_var__add(dloc, var_addr - *var_offset, var_name, type_die); + return true; } /** diff --git a/tools/perf/util/annotate-data.h b/tools/perf/util/annotate-data.h index 1b5a152163b5..fe1e53d6e8c7 100644 --- a/tools/perf/util/annotate-data.h +++ b/tools/perf/util/annotate-data.h @@ -153,6 +153,9 @@ int annotated_data_type__update_samples(struct annotated_data_type *adt, /* Release all data type information in the tree */ void annotated_data_type__tree_delete(struct rb_root *root); +/* Release all global variable information in the tree */ +void global_var_type__tree_delete(struct rb_root *root); + #else /* HAVE_DWARF_SUPPORT */ static inline struct annotated_data_type * @@ -175,6 +178,10 @@ static inline void annotated_data_type__tree_delete(struct rb_root *root __maybe { } +static inline void global_var_type__tree_delete(struct rb_root *root __maybe_unused) +{ +} + #endif /* HAVE_DWARF_SUPPORT */ #endif /* _PERF_ANNOTATE_DATA_H */ diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c index 22fd5fa806ed..6e2a7198b382 100644 --- a/tools/perf/util/dso.c +++ b/tools/perf/util/dso.c @@ -1329,6 +1329,7 @@ struct dso *dso__new_id(const char *name, struct dso_id *id) dso->inlined_nodes = RB_ROOT_CACHED; dso->srclines = RB_ROOT_CACHED; dso->data_types = RB_ROOT; + dso->global_vars = RB_ROOT; dso->data.fd = -1; dso->data.status = DSO_DATA_STATUS_UNKNOWN; dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND; @@ -1373,6 +1374,7 @@ void dso__delete(struct dso *dso) dso->symbol_names_len = 0; zfree(&dso->symbol_names); annotated_data_type__tree_delete(&dso->data_types); + global_var_type__tree_delete(&dso->global_vars); if (dso->short_name_allocated) { zfree((char **)&dso->short_name); diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h index ce9f3849a773..2cdcd1e2ef8b 100644 --- a/tools/perf/util/dso.h +++ b/tools/perf/util/dso.h @@ -154,7 +154,8 @@ struct dso { size_t symbol_names_len; struct rb_root_cached inlined_nodes; struct rb_root_cached srclines; - struct rb_root data_types; + struct rb_root data_types; + struct rb_root global_vars; struct { u64 addr; @@ -411,4 +412,7 @@ int dso__strerror_load(struct dso *dso, char *buf, size_t buflen); void reset_fd_limit(void); +u64 dso__find_global_type(struct dso *dso, u64 addr); +u64 dso__findnew_global_type(struct dso *dso, u64 addr, u64 offset); + #endif /* __PERF_DSO */ -- cgit v1.2.3-59-g8ed1b From bd62de08084c24a4ff1b1875d53cc4cc1ea2312d Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Mon, 18 Mar 2024 22:51:15 -0700 Subject: perf annotate-data: Do not retry for invalid types In some cases, it was able to find a type or location info (for per-cpu variable) but cannot match because of invalid offset or missing global information. In those cases, it's meaningless to go to the outer scope and retry because there will be no additional information. Let's change the return type of find_matching_type() and bail out if it returns -1 for the cases. Signed-off-by: Namhyung Kim Cc: Adrian Hunter Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Linus Torvalds Cc: Masami Hiramatsu Cc: Peter Zijlstra Cc: Stephane Eranian Link: https://lore.kernel.org/r/20240319055115.4063940-24-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate-data.c | 83 ++++++++++++++++++++++++----------------- 1 file changed, 48 insertions(+), 35 deletions(-) diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c index 969e2f82079c..043d80791bd0 100644 --- a/tools/perf/util/annotate-data.c +++ b/tools/perf/util/annotate-data.c @@ -1115,10 +1115,15 @@ static void setup_stack_canary(struct data_loc_info *dloc) } } -/* It's at the target address, check if it has a matching type */ -static bool check_matching_type(struct type_state *state, - struct data_loc_info *dloc, int reg, - Dwarf_Die *cu_die, Dwarf_Die *type_die) +/* + * It's at the target address, check if it has a matching type. + * It returns 1 if found, 0 if not or -1 if not found but no need to + * repeat the search. The last case is for per-cpu variables which + * are similar to global variables and no additional info is needed. + */ +static int check_matching_type(struct type_state *state, + struct data_loc_info *dloc, int reg, + Dwarf_Die *cu_die, Dwarf_Die *type_die) { Dwarf_Word size; u32 insn_offset = dloc->ip - dloc->ms->sym->start; @@ -1137,20 +1142,20 @@ static bool check_matching_type(struct type_state *state, * dereference a memory location. */ if (tag != DW_TAG_pointer_type && tag != DW_TAG_array_type) - return false; + return -1; /* Remove the pointer and get the target type */ if (die_get_real_type(&state->regs[reg].type, type_die) == NULL) - return false; + return -1; dloc->type_offset = dloc->op->offset; /* Get the size of the actual type */ if (dwarf_aggregate_size(type_die, &size) < 0 || (unsigned)dloc->type_offset >= size) - return false; + return -1; - return true; + return 1; } if (reg == dloc->fbreg) { @@ -1160,18 +1165,18 @@ static bool check_matching_type(struct type_state *state, stack = find_stack_state(state, dloc->type_offset); if (stack == NULL) - return false; + return 0; if (stack->kind == TSR_KIND_CANARY) { setup_stack_canary(dloc); - return false; + return -1; } *type_die = stack->type; /* Update the type offset from the start of slot */ dloc->type_offset -= stack->offset; - return true; + return 1; } if (dloc->fb_cfa) { @@ -1185,22 +1190,22 @@ static bool check_matching_type(struct type_state *state, fbreg = -1; if (reg != fbreg) - return false; + return 0; stack = find_stack_state(state, dloc->type_offset - fboff); if (stack == NULL) - return false; + return 0; if (stack->kind == TSR_KIND_CANARY) { setup_stack_canary(dloc); - return false; + return -1; } *type_die = stack->type; /* Update the type offset from the start of slot */ dloc->type_offset -= fboff + stack->offset; - return true; + return 1; } if (state->regs[reg].kind == TSR_KIND_PERCPU_BASE) { @@ -1212,9 +1217,10 @@ static bool check_matching_type(struct type_state *state, if (get_global_var_type(cu_die, dloc, dloc->ip, var_addr, &var_offset, type_die)) { dloc->type_offset = var_offset; - return true; + return 1; } - return false; + /* No need to retry per-cpu (global) variables */ + return -1; } if (state->regs[reg].ok && state->regs[reg].kind == TSR_KIND_POINTER) { @@ -1231,9 +1237,9 @@ static bool check_matching_type(struct type_state *state, /* Get the size of the actual type */ if (dwarf_aggregate_size(type_die, &size) < 0 || (unsigned)dloc->type_offset >= size) - return false; + return -1; - return true; + return 1; } if (state->regs[reg].ok && state->regs[reg].kind == TSR_KIND_CANARY) { @@ -1246,7 +1252,7 @@ static bool check_matching_type(struct type_state *state, */ setup_stack_canary(dloc); - return false; + return -1; } if (map__dso(dloc->ms->map)->kernel && arch__is(dloc->arch, "x86")) { @@ -1262,9 +1268,9 @@ static bool check_matching_type(struct type_state *state, if (get_global_var_type(cu_die, dloc, dloc->ip, addr, &offset, type_die)) { dloc->type_offset = offset; - return true; + return 1; } - return false; + return -1; } /* Access to per-cpu base like "-0x7dcf0500(,%rdx,8)" */ @@ -1280,26 +1286,28 @@ static bool check_matching_type(struct type_state *state, pr_debug_dtp(" percpu base\n"); dloc->type_offset = offset; - return true; + return 1; } + pr_debug_dtp(" negative offset\n"); + return -1; } } pr_debug_dtp("\n"); - return false; + return 0; } /* Iterate instructions in basic blocks and update type table */ -static bool find_data_type_insn(struct data_loc_info *dloc, int reg, - struct list_head *basic_blocks, - struct die_var_type *var_types, - Dwarf_Die *cu_die, Dwarf_Die *type_die) +static int find_data_type_insn(struct data_loc_info *dloc, int reg, + struct list_head *basic_blocks, + struct die_var_type *var_types, + Dwarf_Die *cu_die, Dwarf_Die *type_die) { struct type_state state; struct symbol *sym = dloc->ms->sym; struct annotation *notes = symbol__annotation(sym); struct annotated_basic_block *bb; - bool found = false; + int ret = 0; init_type_state(&state, dloc->arch); @@ -1317,8 +1325,8 @@ static bool find_data_type_insn(struct data_loc_info *dloc, int reg, update_var_state(&state, dloc, addr, dl->al.offset, var_types); if (this_ip == dloc->ip) { - found = check_matching_type(&state, dloc, reg, - cu_die, type_die); + ret = check_matching_type(&state, dloc, reg, + cu_die, type_die); goto out; } @@ -1331,7 +1339,7 @@ static bool find_data_type_insn(struct data_loc_info *dloc, int reg, out: exit_type_state(&state); - return found; + return ret; } /* @@ -1355,6 +1363,7 @@ static int find_data_type_block(struct data_loc_info *dloc, int reg, for (int i = nr_scopes - 1; i >= 0; i--) { Dwarf_Addr base, start, end; LIST_HEAD(this_blocks); + int found; if (dwarf_ranges(&scopes[i], 0, &base, &start, &end) < 0) break; @@ -1385,15 +1394,19 @@ again: fixup_var_address(var_types, start); /* Find from start of this scope to the target instruction */ - if (find_data_type_insn(dloc, reg, &basic_blocks, var_types, - cu_die, type_die)) { - ret = 0; + found = find_data_type_insn(dloc, reg, &basic_blocks, var_types, + cu_die, type_die); + if (found > 0) { pr_debug_dtp("found by insn track: %#x(reg%d) type-offset=%#x", dloc->op->offset, reg, dloc->type_offset); pr_debug_type_name(type_die, TSR_KIND_TYPE); + ret = 0; break; } + if (found < 0) + break; + /* Go up to the next scope and find blocks to the start */ prev_dst_ip = dst_ip; dst_ip = src_ip; -- cgit v1.2.3-59-g8ed1b From 2316ef589181b5b2fd6cbced24439ba4ac096bd8 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 19 Mar 2024 14:49:32 -0300 Subject: perf beauty: Introduce scrape script for 'clone' syscall 'flags' argument It was using the first variation on producing a string representation for a binary flag, one that used the copy of uapi/linux/sched.h with preprocessor tricks that had to be updated everytime a new flag was introduced. Use the more recent scrape script + strarray + strarray__scnprintf_flags() combo. $ tools/perf/trace/beauty/clone.sh | head -5 static const char *clone_flags[] = { [ilog2(0x00000100) + 1] = "VM", [ilog2(0x00000200) + 1] = "FS", [ilog2(0x00000400) + 1] = "FILES", [ilog2(0x00000800) + 1] = "SIGHAND", $ Now we can move uapi/linux/sched.h from tools/include/, that is used for building perf to the scrape only directory tools/perf/trace/beauty/include. Reviewed-by: Ian Rogers Cc: Adrian Hunter Cc: Jiri Olsa Cc: Namhyung Kim Link: https://lore.kernel.org/lkml/ZfnULIn3XKDq0bpc@x1 Signed-off-by: Arnaldo Carvalho de Melo --- tools/include/uapi/linux/sched.h | 148 --------------------- tools/perf/Makefile.perf | 14 +- tools/perf/check-headers.sh | 2 +- tools/perf/trace/beauty/clone.c | 46 +------ tools/perf/trace/beauty/clone.sh | 17 +++ tools/perf/trace/beauty/include/uapi/linux/sched.h | 148 +++++++++++++++++++++ 6 files changed, 182 insertions(+), 193 deletions(-) delete mode 100644 tools/include/uapi/linux/sched.h create mode 100755 tools/perf/trace/beauty/clone.sh create mode 100644 tools/perf/trace/beauty/include/uapi/linux/sched.h diff --git a/tools/include/uapi/linux/sched.h b/tools/include/uapi/linux/sched.h deleted file mode 100644 index 3bac0a8ceab2..000000000000 --- a/tools/include/uapi/linux/sched.h +++ /dev/null @@ -1,148 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -#ifndef _UAPI_LINUX_SCHED_H -#define _UAPI_LINUX_SCHED_H - -#include - -/* - * cloning flags: - */ -#define CSIGNAL 0x000000ff /* signal mask to be sent at exit */ -#define CLONE_VM 0x00000100 /* set if VM shared between processes */ -#define CLONE_FS 0x00000200 /* set if fs info shared between processes */ -#define CLONE_FILES 0x00000400 /* set if open files shared between processes */ -#define CLONE_SIGHAND 0x00000800 /* set if signal handlers and blocked signals shared */ -#define CLONE_PIDFD 0x00001000 /* set if a pidfd should be placed in parent */ -#define CLONE_PTRACE 0x00002000 /* set if we want to let tracing continue on the child too */ -#define CLONE_VFORK 0x00004000 /* set if the parent wants the child to wake it up on mm_release */ -#define CLONE_PARENT 0x00008000 /* set if we want to have the same parent as the cloner */ -#define CLONE_THREAD 0x00010000 /* Same thread group? */ -#define CLONE_NEWNS 0x00020000 /* New mount namespace group */ -#define CLONE_SYSVSEM 0x00040000 /* share system V SEM_UNDO semantics */ -#define CLONE_SETTLS 0x00080000 /* create a new TLS for the child */ -#define CLONE_PARENT_SETTID 0x00100000 /* set the TID in the parent */ -#define CLONE_CHILD_CLEARTID 0x00200000 /* clear the TID in the child */ -#define CLONE_DETACHED 0x00400000 /* Unused, ignored */ -#define CLONE_UNTRACED 0x00800000 /* set if the tracing process can't force CLONE_PTRACE on this clone */ -#define CLONE_CHILD_SETTID 0x01000000 /* set the TID in the child */ -#define CLONE_NEWCGROUP 0x02000000 /* New cgroup namespace */ -#define CLONE_NEWUTS 0x04000000 /* New utsname namespace */ -#define CLONE_NEWIPC 0x08000000 /* New ipc namespace */ -#define CLONE_NEWUSER 0x10000000 /* New user namespace */ -#define CLONE_NEWPID 0x20000000 /* New pid namespace */ -#define CLONE_NEWNET 0x40000000 /* New network namespace */ -#define CLONE_IO 0x80000000 /* Clone io context */ - -/* Flags for the clone3() syscall. */ -#define CLONE_CLEAR_SIGHAND 0x100000000ULL /* Clear any signal handler and reset to SIG_DFL. */ -#define CLONE_INTO_CGROUP 0x200000000ULL /* Clone into a specific cgroup given the right permissions. */ - -/* - * cloning flags intersect with CSIGNAL so can be used with unshare and clone3 - * syscalls only: - */ -#define CLONE_NEWTIME 0x00000080 /* New time namespace */ - -#ifndef __ASSEMBLY__ -/** - * struct clone_args - arguments for the clone3 syscall - * @flags: Flags for the new process as listed above. - * All flags are valid except for CSIGNAL and - * CLONE_DETACHED. - * @pidfd: If CLONE_PIDFD is set, a pidfd will be - * returned in this argument. - * @child_tid: If CLONE_CHILD_SETTID is set, the TID of the - * child process will be returned in the child's - * memory. - * @parent_tid: If CLONE_PARENT_SETTID is set, the TID of - * the child process will be returned in the - * parent's memory. - * @exit_signal: The exit_signal the parent process will be - * sent when the child exits. - * @stack: Specify the location of the stack for the - * child process. - * Note, @stack is expected to point to the - * lowest address. The stack direction will be - * determined by the kernel and set up - * appropriately based on @stack_size. - * @stack_size: The size of the stack for the child process. - * @tls: If CLONE_SETTLS is set, the tls descriptor - * is set to tls. - * @set_tid: Pointer to an array of type *pid_t. The size - * of the array is defined using @set_tid_size. - * This array is used to select PIDs/TIDs for - * newly created processes. The first element in - * this defines the PID in the most nested PID - * namespace. Each additional element in the array - * defines the PID in the parent PID namespace of - * the original PID namespace. If the array has - * less entries than the number of currently - * nested PID namespaces only the PIDs in the - * corresponding namespaces are set. - * @set_tid_size: This defines the size of the array referenced - * in @set_tid. This cannot be larger than the - * kernel's limit of nested PID namespaces. - * @cgroup: If CLONE_INTO_CGROUP is specified set this to - * a file descriptor for the cgroup. - * - * The structure is versioned by size and thus extensible. - * New struct members must go at the end of the struct and - * must be properly 64bit aligned. - */ -struct clone_args { - __aligned_u64 flags; - __aligned_u64 pidfd; - __aligned_u64 child_tid; - __aligned_u64 parent_tid; - __aligned_u64 exit_signal; - __aligned_u64 stack; - __aligned_u64 stack_size; - __aligned_u64 tls; - __aligned_u64 set_tid; - __aligned_u64 set_tid_size; - __aligned_u64 cgroup; -}; -#endif - -#define CLONE_ARGS_SIZE_VER0 64 /* sizeof first published struct */ -#define CLONE_ARGS_SIZE_VER1 80 /* sizeof second published struct */ -#define CLONE_ARGS_SIZE_VER2 88 /* sizeof third published struct */ - -/* - * Scheduling policies - */ -#define SCHED_NORMAL 0 -#define SCHED_FIFO 1 -#define SCHED_RR 2 -#define SCHED_BATCH 3 -/* SCHED_ISO: reserved but not implemented yet */ -#define SCHED_IDLE 5 -#define SCHED_DEADLINE 6 - -/* Can be ORed in to make sure the process is reverted back to SCHED_NORMAL on fork */ -#define SCHED_RESET_ON_FORK 0x40000000 - -/* - * For the sched_{set,get}attr() calls - */ -#define SCHED_FLAG_RESET_ON_FORK 0x01 -#define SCHED_FLAG_RECLAIM 0x02 -#define SCHED_FLAG_DL_OVERRUN 0x04 -#define SCHED_FLAG_KEEP_POLICY 0x08 -#define SCHED_FLAG_KEEP_PARAMS 0x10 -#define SCHED_FLAG_UTIL_CLAMP_MIN 0x20 -#define SCHED_FLAG_UTIL_CLAMP_MAX 0x40 - -#define SCHED_FLAG_KEEP_ALL (SCHED_FLAG_KEEP_POLICY | \ - SCHED_FLAG_KEEP_PARAMS) - -#define SCHED_FLAG_UTIL_CLAMP (SCHED_FLAG_UTIL_CLAMP_MIN | \ - SCHED_FLAG_UTIL_CLAMP_MAX) - -#define SCHED_FLAG_ALL (SCHED_FLAG_RESET_ON_FORK | \ - SCHED_FLAG_RECLAIM | \ - SCHED_FLAG_DL_OVERRUN | \ - SCHED_FLAG_KEEP_ALL | \ - SCHED_FLAG_UTIL_CLAMP) - -#endif /* _UAPI_LINUX_SCHED_H */ diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index f5654d06e313..ccd2dcbc64f7 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -485,13 +485,20 @@ x86_arch_asm_dir := $(srctree)/tools/arch/x86/include/asm/ beauty_outdir := $(OUTPUT)trace/beauty/generated beauty_ioctl_outdir := $(beauty_outdir)/ioctl -drm_ioctl_array := $(beauty_ioctl_outdir)/drm_ioctl_array.c -drm_hdr_dir := $(srctree)/tools/include/uapi/drm -drm_ioctl_tbl := $(srctree)/tools/perf/trace/beauty/drm_ioctl.sh # Create output directory if not already present $(shell [ -d '$(beauty_ioctl_outdir)' ] || mkdir -p '$(beauty_ioctl_outdir)') +clone_flags_array := $(beauty_outdir)/clone_flags_array.c +clone_flags_tbl := $(srctree)/tools/perf/trace/beauty/clone.sh + +$(clone_flags_array): $(beauty_uapi_linux_dir)/sched.h $(clone_flags_tbl) + $(Q)$(SHELL) '$(clone_flags_tbl)' $(beauty_uapi_linux_dir) > $@ + +drm_ioctl_array := $(beauty_ioctl_outdir)/drm_ioctl_array.c +drm_hdr_dir := $(srctree)/tools/include/uapi/drm +drm_ioctl_tbl := $(srctree)/tools/perf/trace/beauty/drm_ioctl.sh + $(drm_ioctl_array): $(drm_hdr_dir)/drm.h $(drm_hdr_dir)/i915_drm.h $(drm_ioctl_tbl) $(Q)$(SHELL) '$(drm_ioctl_tbl)' $(drm_hdr_dir) > $@ @@ -765,6 +772,7 @@ build-dir = $(or $(__build-dir),.) prepare: $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)common-cmds.h archheaders \ arm64-sysreg-defs \ + $(clone_flags_array) \ $(drm_ioctl_array) \ $(fadvise_advice_array) \ $(fsconfig_arrays) \ diff --git a/tools/perf/check-headers.sh b/tools/perf/check-headers.sh index 859cd6f35b0a..413c9b747216 100755 --- a/tools/perf/check-headers.sh +++ b/tools/perf/check-headers.sh @@ -15,7 +15,6 @@ FILES=( "include/uapi/linux/kvm.h" "include/uapi/linux/in.h" "include/uapi/linux/perf_event.h" - "include/uapi/linux/sched.h" "include/uapi/linux/seccomp.h" "include/uapi/linux/vhost.h" "include/linux/bits.h" @@ -93,6 +92,7 @@ BEAUTY_FILES=( "include/uapi/linux/fs.h" "include/uapi/linux/mount.h" "include/uapi/linux/prctl.h" + "include/uapi/linux/sched.h" "include/uapi/linux/usbdevice_fs.h" "include/uapi/sound/asound.h" ) diff --git a/tools/perf/trace/beauty/clone.c b/tools/perf/trace/beauty/clone.c index f4db894e0af6..c9fa8f7e82b9 100644 --- a/tools/perf/trace/beauty/clone.c +++ b/tools/perf/trace/beauty/clone.c @@ -7,52 +7,16 @@ #include "trace/beauty/beauty.h" #include +#include #include -#include +#include static size_t clone__scnprintf_flags(unsigned long flags, char *bf, size_t size, bool show_prefix) { - const char *prefix = "CLONE_"; - int printed = 0; +#include "trace/beauty/generated/clone_flags_array.c" + static DEFINE_STRARRAY(clone_flags, "CLONE_"); -#define P_FLAG(n) \ - if (flags & CLONE_##n) { \ - printed += scnprintf(bf + printed, size - printed, "%s%s%s", printed ? "|" : "", show_prefix ? prefix : "", #n); \ - flags &= ~CLONE_##n; \ - } - - P_FLAG(VM); - P_FLAG(FS); - P_FLAG(FILES); - P_FLAG(SIGHAND); - P_FLAG(PIDFD); - P_FLAG(PTRACE); - P_FLAG(VFORK); - P_FLAG(PARENT); - P_FLAG(THREAD); - P_FLAG(NEWNS); - P_FLAG(SYSVSEM); - P_FLAG(SETTLS); - P_FLAG(PARENT_SETTID); - P_FLAG(CHILD_CLEARTID); - P_FLAG(DETACHED); - P_FLAG(UNTRACED); - P_FLAG(CHILD_SETTID); - P_FLAG(NEWCGROUP); - P_FLAG(NEWUTS); - P_FLAG(NEWIPC); - P_FLAG(NEWUSER); - P_FLAG(NEWPID); - P_FLAG(NEWNET); - P_FLAG(IO); - P_FLAG(CLEAR_SIGHAND); - P_FLAG(INTO_CGROUP); -#undef P_FLAG - - if (flags) - printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags); - - return printed; + return strarray__scnprintf_flags(&strarray__clone_flags, bf, size, show_prefix, flags); } size_t syscall_arg__scnprintf_clone_flags(char *bf, size_t size, struct syscall_arg *arg) diff --git a/tools/perf/trace/beauty/clone.sh b/tools/perf/trace/beauty/clone.sh new file mode 100755 index 000000000000..18b6c0d75693 --- /dev/null +++ b/tools/perf/trace/beauty/clone.sh @@ -0,0 +1,17 @@ +#!/bin/sh +# SPDX-License-Identifier: LGPL-2.1 + +if [ $# -ne 1 ] ; then + beauty_uapi_linux_dir=tools/perf/trace/beauty/include/uapi/linux/ +else + beauty_uapi_linux_dir=$1 +fi + +linux_sched=${beauty_uapi_linux_dir}/sched.h + +printf "static const char *clone_flags[] = {\n" +regex='^[[:space:]]*#[[:space:]]*define[[:space:]]+CLONE_([^_]+[[:alnum:]_]+)[[:space:]]+(0x[[:xdigit:]]+)[[:space:]]*.*' +grep -E $regex ${linux_sched} | \ + sed -r "s/$regex/\2 \1/g" | \ + xargs printf "\t[ilog2(%s) + 1] = \"%s\",\n" +printf "};\n" diff --git a/tools/perf/trace/beauty/include/uapi/linux/sched.h b/tools/perf/trace/beauty/include/uapi/linux/sched.h new file mode 100644 index 000000000000..3bac0a8ceab2 --- /dev/null +++ b/tools/perf/trace/beauty/include/uapi/linux/sched.h @@ -0,0 +1,148 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _UAPI_LINUX_SCHED_H +#define _UAPI_LINUX_SCHED_H + +#include + +/* + * cloning flags: + */ +#define CSIGNAL 0x000000ff /* signal mask to be sent at exit */ +#define CLONE_VM 0x00000100 /* set if VM shared between processes */ +#define CLONE_FS 0x00000200 /* set if fs info shared between processes */ +#define CLONE_FILES 0x00000400 /* set if open files shared between processes */ +#define CLONE_SIGHAND 0x00000800 /* set if signal handlers and blocked signals shared */ +#define CLONE_PIDFD 0x00001000 /* set if a pidfd should be placed in parent */ +#define CLONE_PTRACE 0x00002000 /* set if we want to let tracing continue on the child too */ +#define CLONE_VFORK 0x00004000 /* set if the parent wants the child to wake it up on mm_release */ +#define CLONE_PARENT 0x00008000 /* set if we want to have the same parent as the cloner */ +#define CLONE_THREAD 0x00010000 /* Same thread group? */ +#define CLONE_NEWNS 0x00020000 /* New mount namespace group */ +#define CLONE_SYSVSEM 0x00040000 /* share system V SEM_UNDO semantics */ +#define CLONE_SETTLS 0x00080000 /* create a new TLS for the child */ +#define CLONE_PARENT_SETTID 0x00100000 /* set the TID in the parent */ +#define CLONE_CHILD_CLEARTID 0x00200000 /* clear the TID in the child */ +#define CLONE_DETACHED 0x00400000 /* Unused, ignored */ +#define CLONE_UNTRACED 0x00800000 /* set if the tracing process can't force CLONE_PTRACE on this clone */ +#define CLONE_CHILD_SETTID 0x01000000 /* set the TID in the child */ +#define CLONE_NEWCGROUP 0x02000000 /* New cgroup namespace */ +#define CLONE_NEWUTS 0x04000000 /* New utsname namespace */ +#define CLONE_NEWIPC 0x08000000 /* New ipc namespace */ +#define CLONE_NEWUSER 0x10000000 /* New user namespace */ +#define CLONE_NEWPID 0x20000000 /* New pid namespace */ +#define CLONE_NEWNET 0x40000000 /* New network namespace */ +#define CLONE_IO 0x80000000 /* Clone io context */ + +/* Flags for the clone3() syscall. */ +#define CLONE_CLEAR_SIGHAND 0x100000000ULL /* Clear any signal handler and reset to SIG_DFL. */ +#define CLONE_INTO_CGROUP 0x200000000ULL /* Clone into a specific cgroup given the right permissions. */ + +/* + * cloning flags intersect with CSIGNAL so can be used with unshare and clone3 + * syscalls only: + */ +#define CLONE_NEWTIME 0x00000080 /* New time namespace */ + +#ifndef __ASSEMBLY__ +/** + * struct clone_args - arguments for the clone3 syscall + * @flags: Flags for the new process as listed above. + * All flags are valid except for CSIGNAL and + * CLONE_DETACHED. + * @pidfd: If CLONE_PIDFD is set, a pidfd will be + * returned in this argument. + * @child_tid: If CLONE_CHILD_SETTID is set, the TID of the + * child process will be returned in the child's + * memory. + * @parent_tid: If CLONE_PARENT_SETTID is set, the TID of + * the child process will be returned in the + * parent's memory. + * @exit_signal: The exit_signal the parent process will be + * sent when the child exits. + * @stack: Specify the location of the stack for the + * child process. + * Note, @stack is expected to point to the + * lowest address. The stack direction will be + * determined by the kernel and set up + * appropriately based on @stack_size. + * @stack_size: The size of the stack for the child process. + * @tls: If CLONE_SETTLS is set, the tls descriptor + * is set to tls. + * @set_tid: Pointer to an array of type *pid_t. The size + * of the array is defined using @set_tid_size. + * This array is used to select PIDs/TIDs for + * newly created processes. The first element in + * this defines the PID in the most nested PID + * namespace. Each additional element in the array + * defines the PID in the parent PID namespace of + * the original PID namespace. If the array has + * less entries than the number of currently + * nested PID namespaces only the PIDs in the + * corresponding namespaces are set. + * @set_tid_size: This defines the size of the array referenced + * in @set_tid. This cannot be larger than the + * kernel's limit of nested PID namespaces. + * @cgroup: If CLONE_INTO_CGROUP is specified set this to + * a file descriptor for the cgroup. + * + * The structure is versioned by size and thus extensible. + * New struct members must go at the end of the struct and + * must be properly 64bit aligned. + */ +struct clone_args { + __aligned_u64 flags; + __aligned_u64 pidfd; + __aligned_u64 child_tid; + __aligned_u64 parent_tid; + __aligned_u64 exit_signal; + __aligned_u64 stack; + __aligned_u64 stack_size; + __aligned_u64 tls; + __aligned_u64 set_tid; + __aligned_u64 set_tid_size; + __aligned_u64 cgroup; +}; +#endif + +#define CLONE_ARGS_SIZE_VER0 64 /* sizeof first published struct */ +#define CLONE_ARGS_SIZE_VER1 80 /* sizeof second published struct */ +#define CLONE_ARGS_SIZE_VER2 88 /* sizeof third published struct */ + +/* + * Scheduling policies + */ +#define SCHED_NORMAL 0 +#define SCHED_FIFO 1 +#define SCHED_RR 2 +#define SCHED_BATCH 3 +/* SCHED_ISO: reserved but not implemented yet */ +#define SCHED_IDLE 5 +#define SCHED_DEADLINE 6 + +/* Can be ORed in to make sure the process is reverted back to SCHED_NORMAL on fork */ +#define SCHED_RESET_ON_FORK 0x40000000 + +/* + * For the sched_{set,get}attr() calls + */ +#define SCHED_FLAG_RESET_ON_FORK 0x01 +#define SCHED_FLAG_RECLAIM 0x02 +#define SCHED_FLAG_DL_OVERRUN 0x04 +#define SCHED_FLAG_KEEP_POLICY 0x08 +#define SCHED_FLAG_KEEP_PARAMS 0x10 +#define SCHED_FLAG_UTIL_CLAMP_MIN 0x20 +#define SCHED_FLAG_UTIL_CLAMP_MAX 0x40 + +#define SCHED_FLAG_KEEP_ALL (SCHED_FLAG_KEEP_POLICY | \ + SCHED_FLAG_KEEP_PARAMS) + +#define SCHED_FLAG_UTIL_CLAMP (SCHED_FLAG_UTIL_CLAMP_MIN | \ + SCHED_FLAG_UTIL_CLAMP_MAX) + +#define SCHED_FLAG_ALL (SCHED_FLAG_RESET_ON_FORK | \ + SCHED_FLAG_RECLAIM | \ + SCHED_FLAG_DL_OVERRUN | \ + SCHED_FLAG_KEEP_ALL | \ + SCHED_FLAG_UTIL_CLAMP) + +#endif /* _UAPI_LINUX_SCHED_H */ -- cgit v1.2.3-59-g8ed1b From 525615ef6df476d5fe277d311c645b4c179d56db Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 7 Mar 2024 16:19:10 -0800 Subject: perf list: Add tracepoint encoding to detailed output The tracepoint id holds the config value and is probed in determining what an event is. Add reading of the id so that we can display the event encoding as: $ perf list --details ... alarmtimer:alarmtimer_cancel [Tracepoint event] tracepoint/config=0x18c/ ... Signed-off-by: Ian Rogers Tested-by: Arnaldo Carvalho de Melo Tested-by: Kan Liang Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Ravi Bangoria Cc: Yang Jihong Link: https://lore.kernel.org/r/20240308001915.4060155-2-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/print-events.c | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/tools/perf/util/print-events.c b/tools/perf/util/print-events.c index 7b54e9385442..e0d2b49bab66 100644 --- a/tools/perf/util/print-events.c +++ b/tools/perf/util/print-events.c @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -92,34 +93,48 @@ void print_tracepoint_events(const struct print_callbacks *print_cb __maybe_unus evt_items = scandirat(events_fd, sys_dirent->d_name, &evt_namelist, NULL, alphasort); for (int j = 0; j < evt_items; j++) { + /* + * Buffer sized at twice the max filename length + 1 + * separator + 1 \0 terminator. + */ + char buf[NAME_MAX * 2 + 2]; + /* 16 possible hex digits and 22 other characters and \0. */ + char encoding[16 + 22]; struct dirent *evt_dirent = evt_namelist[j]; - char evt_path[MAXPATHLEN]; - int evt_fd; + struct io id; + __u64 config; if (evt_dirent->d_type != DT_DIR || !strcmp(evt_dirent->d_name, ".") || !strcmp(evt_dirent->d_name, "..")) goto next_evt; - snprintf(evt_path, sizeof(evt_path), "%s/id", evt_dirent->d_name); - evt_fd = openat(dir_fd, evt_path, O_RDONLY); - if (evt_fd < 0) + snprintf(buf, sizeof(buf), "%s/id", evt_dirent->d_name); + io__init(&id, openat(dir_fd, buf, O_RDONLY), buf, sizeof(buf)); + + if (id.fd < 0) + goto next_evt; + + if (io__get_dec(&id, &config) < 0) { + close(id.fd); goto next_evt; - close(evt_fd); + } + close(id.fd); - snprintf(evt_path, MAXPATHLEN, "%s:%s", + snprintf(buf, sizeof(buf), "%s:%s", sys_dirent->d_name, evt_dirent->d_name); + snprintf(encoding, sizeof(encoding), "tracepoint/config=0x%llx/", config); print_cb->print_event(print_state, /*topic=*/NULL, - /*pmu_name=*/NULL, - evt_path, + /*pmu_name=*/NULL, /* really "tracepoint" */ + /*event_name=*/buf, /*event_alias=*/NULL, /*scale_unit=*/NULL, /*deprecated=*/false, "Tracepoint event", /*desc=*/NULL, /*long_desc=*/NULL, - /*encoding_desc=*/NULL); + encoding); next_evt: free(evt_namelist[j]); } -- cgit v1.2.3-59-g8ed1b From 39aa4ff61fd310704d04063fc3f2842011e03b4d Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 7 Mar 2024 16:19:11 -0800 Subject: perf pmu: Drop "default_core" from alias names "default_core" is used by jevents.py for json events' PMU name when none is specified. On x86 the "default_core" is typically the PMU "cpu". When creating an alias see if the event's PMU name is "default_core" in which case don't record it. This means in places like "perf list" the PMU's name will be used in its place. Before: $ perf list --details ... cache: l1d.replacement [Counts the number of cache lines replaced in L1 data cache] default_core/event=0x51,period=0x186a3,umask=0x1/ ... After: $ perf list --details ... cache: l1d.replacement [Counts the number of cache lines replaced in L1 data cache. Unit: cpu] cpu/event=0x51,period=0x186a3,umask=0x1/ ... Signed-off-by: Ian Rogers Tested-by: Kan Liang Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Ravi Bangoria Cc: Yang Jihong Link: https://lore.kernel.org/r/20240308001915.4060155-3-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/pmu.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index f39cbbc1a7ec..24be587e3537 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c @@ -518,7 +518,8 @@ static int perf_pmu__new_alias(struct perf_pmu *pmu, const char *name, unit = pe->unit; perpkg = pe->perpkg; deprecated = pe->deprecated; - pmu_name = pe->pmu; + if (pe->pmu && strcmp(pe->pmu, "default_core")) + pmu_name = pe->pmu; } alias = zalloc(sizeof(*alias)); -- cgit v1.2.3-59-g8ed1b From aa1f4ad287a70b07b441f608aed5a5ea066f18b6 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 7 Mar 2024 16:19:12 -0800 Subject: perf list: Allow wordwrap to wrap on commas A raw event encoding may be a block with terms separated by commas. If wrapping such a string it would be useful to break at the commas, so add this ability to wordwrap. Signed-off-by: Ian Rogers Tested-by: Kan Liang Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Ravi Bangoria Cc: Yang Jihong Link: https://lore.kernel.org/r/20240308001915.4060155-4-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-list.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/tools/perf/builtin-list.c b/tools/perf/builtin-list.c index 02bf608d585e..e0fe3d178d63 100644 --- a/tools/perf/builtin-list.c +++ b/tools/perf/builtin-list.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -76,26 +77,38 @@ static void default_print_start(void *ps) static void default_print_end(void *print_state __maybe_unused) {} +static const char *skip_spaces_or_commas(const char *str) +{ + while (isspace(*str) || *str == ',') + ++str; + return str; +} + static void wordwrap(FILE *fp, const char *s, int start, int max, int corr) { int column = start; int n; bool saw_newline = false; + bool comma = false; while (*s) { - int wlen = strcspn(s, " \t\n"); + int wlen = strcspn(s, " ,\t\n"); + const char *sep = comma ? "," : " "; if ((column + wlen >= max && column > start) || saw_newline) { - fprintf(fp, "\n%*s", start, ""); + fprintf(fp, comma ? ",\n%*s" : "\n%*s", start, ""); column = start + corr; } - n = fprintf(fp, "%s%.*s", column > start ? " " : "", wlen, s); + if (column <= start) + sep = ""; + n = fprintf(fp, "%s%.*s", sep, wlen, s); if (n <= 0) break; saw_newline = s[wlen] == '\n'; s += wlen; + comma = s[0] == ','; column += n; - s = skip_spaces(s); + s = skip_spaces_or_commas(s); } } -- cgit v1.2.3-59-g8ed1b From 4ccf3bb703ed01a872de7d39db53f477d44ade0b Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 7 Mar 2024 16:19:13 -0800 Subject: perf list: Give more details about raw event encodings List all the PMUs, not just the first core one, and list real format specifiers with value ranges. Before: $ perf list ... rNNN [Raw hardware event descriptor] cpu/t1=v1[,t2=v2,t3 ...]/modifier [Raw hardware event descriptor] [(see 'man perf-list' on how to encode it)] mem:[/len][:access] [Hardware breakpoint] ... After: $ perf list ... rNNN [Raw event descriptor] cpu/event=0..255,pc,edge,.../modifier [Raw event descriptor] [(see 'man perf-list' or 'man perf-record' on how to encode it)] breakpoint//modifier [Raw event descriptor] cstate_core/event=0..0xffffffffffffffff/modifier [Raw event descriptor] cstate_pkg/event=0..0xffffffffffffffff/modifier [Raw event descriptor] i915/i915_eventid=0..0x1fffff/modifier [Raw event descriptor] intel_bts//modifier [Raw event descriptor] intel_pt/ptw,event,cyc_thresh=0..15,.../modifier [Raw event descriptor] kprobe/retprobe/modifier [Raw event descriptor] msr/event=0..0xffffffffffffffff/modifier [Raw event descriptor] power/event=0..255/modifier [Raw event descriptor] software//modifier [Raw event descriptor] tracepoint//modifier [Raw event descriptor] uncore_arb/event=0..255,edge,inv,.../modifier [Raw event descriptor] uncore_cbox/event=0..255,edge,inv,.../modifier [Raw event descriptor] uncore_clock/event=0..255/modifier [Raw event descriptor] uncore_imc_free_running/event=0..255,umask=0..255/modifier[Raw event descriptor] uprobe/ref_ctr_offset=0..0xffffffff,retprobe/modifier[Raw event descriptor] mem:[/len][:access] [Hardware breakpoint] ... With '--details' provide more details on the formats encoding: cpu/event=0..255,pc,edge,.../modifier [Raw event descriptor] [(see 'man perf-list' or 'man perf-record' on how to encode it)] cpu/event=0..255,pc,edge,offcore_rsp=0..0xffffffffffffffff,ldlat=0..0xffff,inv, umask=0..255,frontend=0..0xffffff,cmask=0..255,config=0..0xffffffffffffffff, config1=0..0xffffffffffffffff,config2=0..0xffffffffffffffff,config3=0..0xffffffffffffffff, name=string,period=number,freq=number,branch_type=(u|k|hv|any|...),time, call-graph=(fp|dwarf|lbr),stack-size=number,max-stack=number,nr=number,inherit,no-inherit, overwrite,no-overwrite,percore,aux-output,aux-sample-size=number/modifier breakpoint//modifier [Raw event descriptor] breakpoint//modifier cstate_core/event=0..0xffffffffffffffff/modifier [Raw event descriptor] cstate_core/event=0..0xffffffffffffffff/modifier cstate_pkg/event=0..0xffffffffffffffff/modifier [Raw event descriptor] cstate_pkg/event=0..0xffffffffffffffff/modifier i915/i915_eventid=0..0x1fffff/modifier [Raw event descriptor] i915/i915_eventid=0..0x1fffff/modifier intel_bts//modifier [Raw event descriptor] intel_bts//modifier intel_pt/ptw,event,cyc_thresh=0..15,.../modifier [Raw event descriptor] intel_pt/ptw,event,cyc_thresh=0..15,pt,notnt,branch,tsc,pwr_evt,fup_on_ptw,cyc,noretcomp, mtc,psb_period=0..15,mtc_period=0..15/modifier kprobe/retprobe/modifier [Raw event descriptor] kprobe/retprobe/modifier msr/event=0..0xffffffffffffffff/modifier [Raw event descriptor] msr/event=0..0xffffffffffffffff/modifier power/event=0..255/modifier [Raw event descriptor] power/event=0..255/modifier software//modifier [Raw event descriptor] software//modifier tracepoint//modifier [Raw event descriptor] tracepoint//modifier uncore_arb/event=0..255,edge,inv,.../modifier [Raw event descriptor] uncore_arb/event=0..255,edge,inv,umask=0..255,cmask=0..31/modifier uncore_cbox/event=0..255,edge,inv,.../modifier [Raw event descriptor] uncore_cbox/event=0..255,edge,inv,umask=0..255,cmask=0..31/modifier uncore_clock/event=0..255/modifier [Raw event descriptor] uncore_clock/event=0..255/modifier uncore_imc_free_running/event=0..255,umask=0..255/modifier[Raw event descriptor] uncore_imc_free_running/event=0..255,umask=0..255/modifier uprobe/ref_ctr_offset=0..0xffffffff,retprobe/modifier[Raw event descriptor] uprobe/ref_ctr_offset=0..0xffffffff,retprobe/modifier Committer notes: Address this build error in various distros: 55 58.44 ubuntu:24.04 : FAIL gcc version 13.2.0 (Ubuntu 13.2.0-17ubuntu2) util/pmu.c:1638:70: error: '_Static_assert' with no message is a C2x extension [-Werror,-Wc2x-extensions] 1638 | _Static_assert(ARRAY_SIZE(terms) == __PARSE_EVENTS__TERM_TYPE_NR - 6); | ^ | , "" 1 error generated. Signed-off-by: Ian Rogers Tested-by: Arnaldo Carvalho de Melo Tested-by: Kan Liang Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Ravi Bangoria Cc: Yang Jihong Link: https://lore.kernel.org/r/20240308001915.4060155-5-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/pmu.c | 62 +++++++++++++++++++++++++++- tools/perf/util/pmu.h | 3 ++ tools/perf/util/pmus.c | 94 ++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/pmus.h | 1 + tools/perf/util/print-events.c | 20 +-------- 5 files changed, 161 insertions(+), 19 deletions(-) diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index 24be587e3537..81952c6cd3c6 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c @@ -1603,6 +1603,62 @@ bool perf_pmu__has_format(const struct perf_pmu *pmu, const char *name) return false; } +int perf_pmu__for_each_format(struct perf_pmu *pmu, void *state, pmu_format_callback cb) +{ + static const char *const terms[] = { + "config=0..0xffffffffffffffff", + "config1=0..0xffffffffffffffff", + "config2=0..0xffffffffffffffff", + "config3=0..0xffffffffffffffff", + "name=string", + "period=number", + "freq=number", + "branch_type=(u|k|hv|any|...)", + "time", + "call-graph=(fp|dwarf|lbr)", + "stack-size=number", + "max-stack=number", + "nr=number", + "inherit", + "no-inherit", + "overwrite", + "no-overwrite", + "percore", + "aux-output", + "aux-sample-size=number", + }; + struct perf_pmu_format *format; + int ret; + + /* + * max-events and driver-config are missing above as are the internal + * types user, metric-id, raw, legacy cache and hardware. Assert against + * the enum parse_events__term_type so they are kept in sync. + */ + _Static_assert(ARRAY_SIZE(terms) == __PARSE_EVENTS__TERM_TYPE_NR - 6, + "perf_pmu__for_each_format()'s terms must be kept in sync with enum parse_events__term_type"); + list_for_each_entry(format, &pmu->format, list) { + perf_pmu_format__load(pmu, format); + ret = cb(state, format->name, (int)format->value, format->bits); + if (ret) + return ret; + } + if (!pmu->is_core) + return 0; + + for (size_t i = 0; i < ARRAY_SIZE(terms); i++) { + int config = PERF_PMU_FORMAT_VALUE_CONFIG; + + if (i < PERF_PMU_FORMAT_VALUE_CONFIG_END) + config = i; + + ret = cb(state, terms[i], config, /*bits=*/NULL); + if (ret) + return ret; + } + return 0; +} + bool is_pmu_core(const char *name) { return !strcmp(name, "cpu") || !strcmp(name, "cpum_cf") || is_sysfs_pmu_core(name); @@ -1697,8 +1753,12 @@ int perf_pmu__for_each_event(struct perf_pmu *pmu, bool skip_duplicate_pmus, pmu_add_cpu_aliases(pmu); list_for_each_entry(event, &pmu->aliases, list) { size_t buf_used; + int pmu_name_len; info.pmu_name = event->pmu_name ?: pmu->name; + pmu_name_len = skip_duplicate_pmus + ? pmu_name_len_no_suffix(info.pmu_name, /*num=*/NULL) + : (int)strlen(info.pmu_name); info.alias = NULL; if (event->desc) { info.name = event->name; @@ -1723,7 +1783,7 @@ int perf_pmu__for_each_event(struct perf_pmu *pmu, bool skip_duplicate_pmus, info.encoding_desc = buf + buf_used; parse_events_terms__to_strbuf(&event->terms, &sb); buf_used += snprintf(buf + buf_used, sizeof(buf) - buf_used, - "%s/%s/", info.pmu_name, sb.buf) + 1; + "%.*s/%s/", pmu_name_len, info.pmu_name, sb.buf) + 1; info.topic = event->topic; info.str = sb.buf; info.deprecated = event->deprecated; diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h index e35d985206db..9f5284b29ecf 100644 --- a/tools/perf/util/pmu.h +++ b/tools/perf/util/pmu.h @@ -196,6 +196,8 @@ struct pmu_event_info { }; typedef int (*pmu_event_callback)(void *state, struct pmu_event_info *info); +typedef int (*pmu_format_callback)(void *state, const char *name, int config, + const unsigned long *bits); void pmu_add_sys_aliases(struct perf_pmu *pmu); int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, @@ -215,6 +217,7 @@ int perf_pmu__find_event(struct perf_pmu *pmu, const char *event, void *state, p int perf_pmu__format_parse(struct perf_pmu *pmu, int dirfd, bool eager_load); void perf_pmu_format__set_value(void *format, int config, unsigned long *bits); bool perf_pmu__has_format(const struct perf_pmu *pmu, const char *name); +int perf_pmu__for_each_format(struct perf_pmu *pmu, void *state, pmu_format_callback cb); bool is_pmu_core(const char *name); bool perf_pmu__supports_legacy_cache(const struct perf_pmu *pmu); diff --git a/tools/perf/util/pmus.c b/tools/perf/util/pmus.c index 16505071d362..2fd369e45832 100644 --- a/tools/perf/util/pmus.c +++ b/tools/perf/util/pmus.c @@ -16,6 +16,7 @@ #include "pmus.h" #include "pmu.h" #include "print-events.h" +#include "strbuf.h" /* * core_pmus: A PMU belongs to core_pmus if it's name is "cpu" or it's sysfs @@ -503,6 +504,99 @@ void perf_pmus__print_pmu_events(const struct print_callbacks *print_cb, void *p zfree(&aliases); } +struct build_format_string_args { + struct strbuf short_string; + struct strbuf long_string; + int num_formats; +}; + +static int build_format_string(void *state, const char *name, int config, + const unsigned long *bits) +{ + struct build_format_string_args *args = state; + unsigned int num_bits; + int ret1, ret2 = 0; + + (void)config; + args->num_formats++; + if (args->num_formats > 1) { + strbuf_addch(&args->long_string, ','); + if (args->num_formats < 4) + strbuf_addch(&args->short_string, ','); + } + num_bits = bits ? bitmap_weight(bits, PERF_PMU_FORMAT_BITS) : 0; + if (num_bits <= 1) { + ret1 = strbuf_addf(&args->long_string, "%s", name); + if (args->num_formats < 4) + ret2 = strbuf_addf(&args->short_string, "%s", name); + } else if (num_bits > 8) { + ret1 = strbuf_addf(&args->long_string, "%s=0..0x%llx", name, + ULLONG_MAX >> (64 - num_bits)); + if (args->num_formats < 4) { + ret2 = strbuf_addf(&args->short_string, "%s=0..0x%llx", name, + ULLONG_MAX >> (64 - num_bits)); + } + } else { + ret1 = strbuf_addf(&args->long_string, "%s=0..%llu", name, + ULLONG_MAX >> (64 - num_bits)); + if (args->num_formats < 4) { + ret2 = strbuf_addf(&args->short_string, "%s=0..%llu", name, + ULLONG_MAX >> (64 - num_bits)); + } + } + return ret1 < 0 ? ret1 : (ret2 < 0 ? ret2 : 0); +} + +void perf_pmus__print_raw_pmu_events(const struct print_callbacks *print_cb, void *print_state) +{ + bool skip_duplicate_pmus = print_cb->skip_duplicate_pmus(print_state); + struct perf_pmu *(*scan_fn)(struct perf_pmu *); + struct perf_pmu *pmu = NULL; + + if (skip_duplicate_pmus) + scan_fn = perf_pmus__scan_skip_duplicates; + else + scan_fn = perf_pmus__scan; + + while ((pmu = scan_fn(pmu)) != NULL) { + struct build_format_string_args format_args = { + .short_string = STRBUF_INIT, + .long_string = STRBUF_INIT, + .num_formats = 0, + }; + int len = pmu_name_len_no_suffix(pmu->name, /*num=*/NULL); + const char *desc = "(see 'man perf-list' or 'man perf-record' on how to encode it)"; + + if (!pmu->is_core) + desc = NULL; + + strbuf_addf(&format_args.short_string, "%.*s/", len, pmu->name); + strbuf_addf(&format_args.long_string, "%.*s/", len, pmu->name); + perf_pmu__for_each_format(pmu, &format_args, build_format_string); + + if (format_args.num_formats > 3) + strbuf_addf(&format_args.short_string, ",.../modifier"); + else + strbuf_addf(&format_args.short_string, "/modifier"); + + strbuf_addf(&format_args.long_string, "/modifier"); + print_cb->print_event(print_state, + /*topic=*/NULL, + /*pmu_name=*/NULL, + format_args.short_string.buf, + /*event_alias=*/NULL, + /*scale_unit=*/NULL, + /*deprecated=*/false, + "Raw event descriptor", + desc, + /*long_desc=*/NULL, + format_args.long_string.buf); + + strbuf_release(&format_args.short_string); + strbuf_release(&format_args.long_string); + } +} + bool perf_pmus__have_event(const char *pname, const char *name) { struct perf_pmu *pmu = perf_pmus__find(pname); diff --git a/tools/perf/util/pmus.h b/tools/perf/util/pmus.h index 94d2a08d894b..eec599d8aebd 100644 --- a/tools/perf/util/pmus.h +++ b/tools/perf/util/pmus.h @@ -18,6 +18,7 @@ struct perf_pmu *perf_pmus__scan_core(struct perf_pmu *pmu); const struct perf_pmu *perf_pmus__pmu_for_pmu_filter(const char *str); void perf_pmus__print_pmu_events(const struct print_callbacks *print_cb, void *print_state); +void perf_pmus__print_raw_pmu_events(const struct print_callbacks *print_cb, void *print_state); bool perf_pmus__have_event(const char *pname, const char *name); int perf_pmus__num_core_pmus(void); bool perf_pmus__supports_extended_type(void); diff --git a/tools/perf/util/print-events.c b/tools/perf/util/print-events.c index e0d2b49bab66..3f38c27f0157 100644 --- a/tools/perf/util/print-events.c +++ b/tools/perf/util/print-events.c @@ -39,7 +39,7 @@ static const char * const event_type_descriptors[] = { "Software event", "Tracepoint event", "Hardware cache event", - "Raw hardware event descriptor", + "Raw event descriptor", "Hardware breakpoint", }; @@ -416,8 +416,6 @@ void print_symbol_events(const struct print_callbacks *print_cb, void *print_sta */ void print_events(const struct print_callbacks *print_cb, void *print_state) { - char *tmp; - print_symbol_events(print_cb, print_state, PERF_TYPE_HARDWARE, event_symbols_hw, PERF_COUNT_HW_MAX); print_symbol_events(print_cb, print_state, PERF_TYPE_SOFTWARE, @@ -441,21 +439,7 @@ void print_events(const struct print_callbacks *print_cb, void *print_state) /*long_desc=*/NULL, /*encoding_desc=*/NULL); - if (asprintf(&tmp, "%s/t1=v1[,t2=v2,t3 ...]/modifier", - perf_pmus__scan_core(/*pmu=*/NULL)->name) > 0) { - print_cb->print_event(print_state, - /*topic=*/NULL, - /*pmu_name=*/NULL, - tmp, - /*event_alias=*/NULL, - /*scale_unit=*/NULL, - /*deprecated=*/false, - event_type_descriptors[PERF_TYPE_RAW], - "(see 'man perf-list' on how to encode it)", - /*long_desc=*/NULL, - /*encoding_desc=*/NULL); - free(tmp); - } + perf_pmus__print_raw_pmu_events(print_cb, print_state); print_cb->print_event(print_state, /*topic=*/NULL, -- cgit v1.2.3-59-g8ed1b From 7093882067e2e2f88d3449c35c5f0f3f566c8a26 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 7 Mar 2024 16:19:14 -0800 Subject: perf tools: Use pmus to describe type from attribute When dumping a perf_event_attr, use pmus to find the PMU and its name by the type number. This allows dynamically added PMUs to be described. Before: $ perf stat -vv -e data_read true ... perf_event_attr: type 24 size 136 config 0x20ff sample_type IDENTIFIER read_format TOTAL_TIME_ENABLED|TOTAL_TIME_RUNNING disabled 1 inherit 1 exclude_guest 1 ... After: $ perf stat -vv -e data_read true ... perf_event_attr: type 24 (uncore_imc_free_running_0) size 136 config 0x20ff sample_type IDENTIFIER read_format TOTAL_TIME_ENABLED|TOTAL_TIME_RUNNING disabled 1 inherit 1 exclude_guest 1 ... However, it also means that when we have a PMU name we prefer it to a hard coded name: Before: $ perf stat -vv -e faults true ... perf_event_attr: type 1 (PERF_TYPE_SOFTWARE) size 136 config 0x2 (PERF_COUNT_SW_PAGE_FAULTS) sample_type IDENTIFIER read_format TOTAL_TIME_ENABLED|TOTAL_TIME_RUNNING disabled 1 inherit 1 enable_on_exec 1 exclude_guest 1 ... After: $ perf stat -vv -e faults true ... perf_event_attr: type 1 (software) size 136 config 0x2 (PERF_COUNT_SW_PAGE_FAULTS) sample_type IDENTIFIER read_format TOTAL_TIME_ENABLED|TOTAL_TIME_RUNNING disabled 1 inherit 1 enable_on_exec 1 exclude_guest 1 ... It feels more consistent to do this, rather than only prefer a PMU name when a hard coded name isn't available. Signed-off-by: Ian Rogers Tested-by: Arnaldo Carvalho de Melo Tested-by: Kan Liang Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Ravi Bangoria Cc: Yang Jihong Link: https://lore.kernel.org/r/20240308001915.4060155-6-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/perf_event_attr_fprintf.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/tools/perf/util/perf_event_attr_fprintf.c b/tools/perf/util/perf_event_attr_fprintf.c index 8f04d3b7f3ec..29e66835da3a 100644 --- a/tools/perf/util/perf_event_attr_fprintf.c +++ b/tools/perf/util/perf_event_attr_fprintf.c @@ -7,6 +7,8 @@ #include #include #include "util/evsel_fprintf.h" +#include "util/pmu.h" +#include "util/pmus.h" #include "trace-event.h" struct bit_names { @@ -75,9 +77,12 @@ static void __p_read_format(char *buf, size_t size, u64 value) } #define ENUM_ID_TO_STR_CASE(x) case x: return (#x); -static const char *stringify_perf_type_id(u64 value) +static const char *stringify_perf_type_id(struct perf_pmu *pmu, u32 type) { - switch (value) { + if (pmu) + return pmu->name; + + switch (type) { ENUM_ID_TO_STR_CASE(PERF_TYPE_HARDWARE) ENUM_ID_TO_STR_CASE(PERF_TYPE_SOFTWARE) ENUM_ID_TO_STR_CASE(PERF_TYPE_TRACEPOINT) @@ -175,9 +180,9 @@ do { \ #define print_id_unsigned(_s) PRINT_ID(_s, "%"PRIu64) #define print_id_hex(_s) PRINT_ID(_s, "%#"PRIx64) -static void __p_type_id(char *buf, size_t size, u64 value) +static void __p_type_id(struct perf_pmu *pmu, char *buf, size_t size, u64 value) { - print_id_unsigned(stringify_perf_type_id(value)); + print_id_unsigned(stringify_perf_type_id(pmu, value)); } static void __p_config_hw_id(char *buf, size_t size, u64 value) @@ -246,7 +251,7 @@ static void __p_config_id(char *buf, size_t size, u32 type, u64 value) #define p_sample_type(val) __p_sample_type(buf, BUF_SIZE, val) #define p_branch_sample_type(val) __p_branch_sample_type(buf, BUF_SIZE, val) #define p_read_format(val) __p_read_format(buf, BUF_SIZE, val) -#define p_type_id(val) __p_type_id(buf, BUF_SIZE, val) +#define p_type_id(val) __p_type_id(pmu, buf, BUF_SIZE, val) #define p_config_id(val) __p_config_id(buf, BUF_SIZE, attr->type, val) #define PRINT_ATTRn(_n, _f, _p, _a) \ @@ -262,6 +267,7 @@ do { \ int perf_event_attr__fprintf(FILE *fp, struct perf_event_attr *attr, attr__fprintf_f attr__fprintf, void *priv) { + struct perf_pmu *pmu = perf_pmus__find_by_type(attr->type); char buf[BUF_SIZE]; int ret = 0; -- cgit v1.2.3-59-g8ed1b From 67ee8e71daabb8632931b7559e5c8a4b69a427f8 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 7 Mar 2024 16:19:15 -0800 Subject: perf tools: Add/use PMU reverse lookup from config to name Add perf_pmu__name_from_config that does a reverse lookup from a config number to an alias name. The lookup is expensive as the config is computed for every alias by filling in a perf_event_attr, but this is only done when verbose output is enabled. The lookup also only considers config, and not config1, config2 or config3. An example of the output: $ perf stat -vv -e data_read true ... perf_event_attr: type 24 (uncore_imc_free_running_0) size 136 config 0x20ff (data_read) sample_type IDENTIFIER read_format TOTAL_TIME_ENABLED|TOTAL_TIME_RUNNING disabled 1 inherit 1 exclude_guest 1 ... Committer notes: Fix the python binding build by adding dummies for not strictly needed perf_pmu__name_from_config() and perf_pmus__find_by_type(). Signed-off-by: Ian Rogers Tested-by: Arnaldo Carvalho de Melo Tested-by: Kan Liang Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Ravi Bangoria Cc: Yang Jihong Link: https://lore.kernel.org/r/20240308001915.4060155-7-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/perf_event_attr_fprintf.c | 10 ++++++++-- tools/perf/util/pmu.c | 18 ++++++++++++++++++ tools/perf/util/pmu.h | 1 + tools/perf/util/python.c | 10 ++++++++++ 4 files changed, 37 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/perf_event_attr_fprintf.c b/tools/perf/util/perf_event_attr_fprintf.c index 29e66835da3a..59fbbba79697 100644 --- a/tools/perf/util/perf_event_attr_fprintf.c +++ b/tools/perf/util/perf_event_attr_fprintf.c @@ -222,8 +222,14 @@ static void __p_config_tracepoint_id(char *buf, size_t size, u64 value) } #endif -static void __p_config_id(char *buf, size_t size, u32 type, u64 value) +static void __p_config_id(struct perf_pmu *pmu, char *buf, size_t size, u32 type, u64 value) { + const char *name = perf_pmu__name_from_config(pmu, value); + + if (name) { + print_id_hex(name); + return; + } switch (type) { case PERF_TYPE_HARDWARE: return __p_config_hw_id(buf, size, value); @@ -252,7 +258,7 @@ static void __p_config_id(char *buf, size_t size, u32 type, u64 value) #define p_branch_sample_type(val) __p_branch_sample_type(buf, BUF_SIZE, val) #define p_read_format(val) __p_read_format(buf, BUF_SIZE, val) #define p_type_id(val) __p_type_id(pmu, buf, BUF_SIZE, val) -#define p_config_id(val) __p_config_id(buf, BUF_SIZE, attr->type, val) +#define p_config_id(val) __p_config_id(pmu, buf, BUF_SIZE, attr->type, val) #define PRINT_ATTRn(_n, _f, _p, _a) \ do { \ diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index 81952c6cd3c6..ab30f22eaf10 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c @@ -2146,3 +2146,21 @@ void perf_pmu__delete(struct perf_pmu *pmu) zfree(&pmu->id); free(pmu); } + +const char *perf_pmu__name_from_config(struct perf_pmu *pmu, u64 config) +{ + struct perf_pmu_alias *event; + + if (!pmu) + return NULL; + + pmu_add_cpu_aliases(pmu); + list_for_each_entry(event, &pmu->aliases, list) { + struct perf_event_attr attr = {.config = 0,}; + int ret = perf_pmu__config(pmu, &attr, &event->terms, NULL); + + if (ret == 0 && config == attr.config) + return event->name; + } + return NULL; +} diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h index 9f5284b29ecf..152700f78455 100644 --- a/tools/perf/util/pmu.h +++ b/tools/perf/util/pmu.h @@ -276,5 +276,6 @@ struct perf_pmu *perf_pmu__lookup(struct list_head *pmus, int dirfd, const char struct perf_pmu *perf_pmu__create_placeholder_core_pmu(struct list_head *core_pmus); void perf_pmu__delete(struct perf_pmu *pmu); struct perf_pmu *perf_pmus__find_core_pmu(void); +const char *perf_pmu__name_from_config(struct perf_pmu *pmu, u64 config); #endif /* __PMU_H */ diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index 075c0f79b1b9..0aeb97c11c03 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c @@ -103,6 +103,16 @@ int perf_pmu__scan_file(const struct perf_pmu *pmu, const char *name, const char return EOF; } +const char *perf_pmu__name_from_config(struct perf_pmu *pmu __maybe_unused, u64 config __maybe_unused) +{ + return NULL; +} + +struct perf_pmu *perf_pmus__find_by_type(unsigned int type __maybe_unused) +{ + return NULL; +} + int perf_pmus__num_core_pmus(void) { return 1; -- cgit v1.2.3-59-g8ed1b From 88ce0106a1f603bf360cb397e8fe293f8298fabb Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 29 Feb 2024 23:46:36 -0800 Subject: perf record: Delete session after stopping sideband thread The session has a header in it which contains a perf env with bpf_progs. The bpf_progs are accessed by the sideband thread and so the sideband thread must be stopped before the session is deleted, to avoid a use after free. This error was detected by AddressSanitizer in the following: ==2054673==ERROR: AddressSanitizer: heap-use-after-free on address 0x61d000161e00 at pc 0x55769289de54 bp 0x7f9df36d4ab0 sp 0x7f9df36d4aa8 READ of size 8 at 0x61d000161e00 thread T1 #0 0x55769289de53 in __perf_env__insert_bpf_prog_info util/env.c:42 #1 0x55769289dbb1 in perf_env__insert_bpf_prog_info util/env.c:29 #2 0x557692bbae29 in perf_env__add_bpf_info util/bpf-event.c:483 #3 0x557692bbb01a in bpf_event__sb_cb util/bpf-event.c:512 #4 0x5576928b75f4 in perf_evlist__poll_thread util/sideband_evlist.c:68 #5 0x7f9df96a63eb in start_thread nptl/pthread_create.c:444 #6 0x7f9df9726a4b in clone3 ../sysdeps/unix/sysv/linux/x86_64/clone3.S:81 0x61d000161e00 is located 384 bytes inside of 2136-byte region [0x61d000161c80,0x61d0001624d8) freed by thread T0 here: #0 0x7f9dfa6d7288 in __interceptor_free libsanitizer/asan/asan_malloc_linux.cpp:52 #1 0x557692978d50 in perf_session__delete util/session.c:319 #2 0x557692673959 in __cmd_record tools/perf/builtin-record.c:2884 #3 0x55769267a9f0 in cmd_record tools/perf/builtin-record.c:4259 #4 0x55769286710c in run_builtin tools/perf/perf.c:349 #5 0x557692867678 in handle_internal_command tools/perf/perf.c:402 #6 0x557692867a40 in run_argv tools/perf/perf.c:446 #7 0x557692867fae in main tools/perf/perf.c:562 #8 0x7f9df96456c9 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58 Fixes: 657ee5531903339b ("perf evlist: Introduce side band thread") Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Athira Rajeev Cc: Christian Brauner Cc: Disha Goel Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Kajol Jain Cc: Kan Liang Cc: K Prateek Nayak Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Song Liu Cc: Tim Chen Cc: Yicong Yang Link: https://lore.kernel.org/r/20240301074639.2260708-1-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-record.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index ff7e1d6cfcd2..40d2c1c48666 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -2881,10 +2881,10 @@ out_delete_session: } #endif zstd_fini(&session->zstd_data); - perf_session__delete(session); - if (!opts->no_bpf_event) evlist__stop_sb_thread(rec->sb_evlist); + + perf_session__delete(session); return status; } -- cgit v1.2.3-59-g8ed1b From f68c981be0628e141615aa30575efb687da09a2e Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 29 Feb 2024 23:46:37 -0800 Subject: perf test: Stat output per thread of just the parent process Per-thread mode requires either system-wide (-a), a pid (-p) or a tid (-t). The stat output tests were using system-wide mode but this is racy when threads are starting and exiting - something that happens a lot when running the tests in parallel (perf test -p). Avoid the race conditions by using pid mode with the pid of the parent process. Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Athira Rajeev Cc: Christian Brauner Cc: Disha Goel Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: K Prateek Nayak Cc: Kajol Jain Cc: Kan Liang Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Song Liu Cc: Tim Chen Cc: Yicong Yang Link: https://lore.kernel.org/r/20240301074639.2260708-2-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/shell/lib/stat_output.sh | 2 +- tools/perf/tests/shell/stat+json_output.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/perf/tests/shell/lib/stat_output.sh b/tools/perf/tests/shell/lib/stat_output.sh index c81d6a9f7983..9a176ceae4a3 100644 --- a/tools/perf/tests/shell/lib/stat_output.sh +++ b/tools/perf/tests/shell/lib/stat_output.sh @@ -79,7 +79,7 @@ check_per_thread() echo "[Skip] paranoid and not root" return fi - perf stat --per-thread -a $2 true + perf stat --per-thread -p $$ $2 true commachecker --per-thread echo "[Success]" } diff --git a/tools/perf/tests/shell/stat+json_output.sh b/tools/perf/tests/shell/stat+json_output.sh index 2b9c6212dffc..6b630d33c328 100755 --- a/tools/perf/tests/shell/stat+json_output.sh +++ b/tools/perf/tests/shell/stat+json_output.sh @@ -105,7 +105,7 @@ check_per_thread() echo "[Skip] paranoia and not root" return fi - perf stat -j --per-thread -a -o "${stat_output}" true + perf stat -j --per-thread -p $$ -o "${stat_output}" true $PYTHON $pythonchecker --per-thread --file "${stat_output}" echo "[Success]" } -- cgit v1.2.3-59-g8ed1b From e120f7091a25460a19967380725558c36bca7c6c Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 29 Feb 2024 23:46:38 -0800 Subject: perf test: Use a single fd for the child process out/err Switch from dumping err then out, to a single file descriptor for both of them. This allows the err and output to be correctly interleaved in verbose output. Fixes: b482f5f8e0168f1e ("perf tests: Add option to run tests in parallel") Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Athira Rajeev Cc: Christian Brauner Cc: Disha Goel Cc: Ian Rogers Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Kajol Jain Cc: Kan Liang Cc: K Prateek Nayak Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Song Liu Cc: Tim Chen Cc: Yicong Yang Link: https://lore.kernel.org/r/20240301074639.2260708-3-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/builtin-test.c | 37 ++++++------------------------------- 1 file changed, 6 insertions(+), 31 deletions(-) diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c index d13ee7683d9d..e05b370b1e2b 100644 --- a/tools/perf/tests/builtin-test.c +++ b/tools/perf/tests/builtin-test.c @@ -274,11 +274,8 @@ static int finish_test(struct child_test *child_test, int width) struct test_suite *t = child_test->test; int i = child_test->test_num; int subi = child_test->subtest; - int out = child_test->process.out; int err = child_test->process.err; - bool out_done = out <= 0; bool err_done = err <= 0; - struct strbuf out_output = STRBUF_INIT; struct strbuf err_output = STRBUF_INIT; int ret; @@ -290,11 +287,9 @@ static int finish_test(struct child_test *child_test, int width) pr_info("%3d: %-*s:\n", i + 1, width, test_description(t, -1)); /* - * Busy loop reading from the child's stdout and stderr that are set to - * be non-blocking until EOF. + * Busy loop reading from the child's stdout/stderr that are set to be + * non-blocking until EOF. */ - if (!out_done) - fcntl(out, F_SETFL, O_NONBLOCK); if (!err_done) fcntl(err, F_SETFL, O_NONBLOCK); if (verbose > 1) { @@ -303,11 +298,8 @@ static int finish_test(struct child_test *child_test, int width) else pr_info("%3d: %s:\n", i + 1, test_description(t, -1)); } - while (!out_done || !err_done) { - struct pollfd pfds[2] = { - { .fd = out, - .events = POLLIN | POLLERR | POLLHUP | POLLNVAL, - }, + while (!err_done) { + struct pollfd pfds[1] = { { .fd = err, .events = POLLIN | POLLERR | POLLHUP | POLLNVAL, }, @@ -317,21 +309,7 @@ static int finish_test(struct child_test *child_test, int width) /* Poll to avoid excessive spinning, timeout set for 1000ms. */ poll(pfds, ARRAY_SIZE(pfds), /*timeout=*/1000); - if (!out_done && pfds[0].revents) { - errno = 0; - len = read(out, buf, sizeof(buf) - 1); - - if (len <= 0) { - out_done = errno != EAGAIN; - } else { - buf[len] = '\0'; - if (verbose > 1) - fprintf(stdout, "%s", buf); - else - strbuf_addstr(&out_output, buf); - } - } - if (!err_done && pfds[1].revents) { + if (!err_done && pfds[0].revents) { errno = 0; len = read(err, buf, sizeof(buf) - 1); @@ -354,14 +332,10 @@ static int finish_test(struct child_test *child_test, int width) pr_info("%3d.%1d: %s:\n", i + 1, subi + 1, test_description(t, subi)); else pr_info("%3d: %s:\n", i + 1, test_description(t, -1)); - fprintf(stdout, "%s", out_output.buf); fprintf(stderr, "%s", err_output.buf); } - strbuf_release(&out_output); strbuf_release(&err_output); print_test_result(t, i, subi, ret, width); - if (out > 0) - close(out); if (err > 0) close(err); return 0; @@ -394,6 +368,7 @@ static int start_test(struct test_suite *test, int i, int subi, struct child_tes (*child)->process.no_stdout = 1; (*child)->process.no_stderr = 1; } else { + (*child)->process.stdout_to_stderr = 1; (*child)->process.out = -1; (*child)->process.err = -1; } -- cgit v1.2.3-59-g8ed1b From 5f2f051a9386aa6d62d081a9889ca321ca8c309b Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 29 Feb 2024 23:46:39 -0800 Subject: perf test: Read child test 10 times a second rather than 1 Make the perf test output smoother by timing out the poll of the child process after 100ms rather than 1s. Signed-off-by: Ian Rogers Tested-by: Arnaldo Carvalho de Melo Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Athira Rajeev Cc: Christian Brauner Cc: Disha Goel Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: K Prateek Nayak Cc: Kajol Jain Cc: Kan Liang Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Song Liu Cc: Tim Chen Cc: Yicong Yang Link: https://lore.kernel.org/r/20240301074639.2260708-4-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/builtin-test.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c index e05b370b1e2b..ddb2f4e38ea5 100644 --- a/tools/perf/tests/builtin-test.c +++ b/tools/perf/tests/builtin-test.c @@ -307,8 +307,8 @@ static int finish_test(struct child_test *child_test, int width) char buf[512]; ssize_t len; - /* Poll to avoid excessive spinning, timeout set for 1000ms. */ - poll(pfds, ARRAY_SIZE(pfds), /*timeout=*/1000); + /* Poll to avoid excessive spinning, timeout set for 100ms. */ + poll(pfds, ARRAY_SIZE(pfds), /*timeout=*/100); if (!err_done && pfds[0].revents) { errno = 0; len = read(err, buf, sizeof(buf) - 1); -- cgit v1.2.3-59-g8ed1b From f664d5159de275d3453ee5699b3376575c6aa156 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Fri, 1 Mar 2024 12:13:05 -0800 Subject: perf tools: Suggest inbuilt commands for unknown command The existing unknown command code looks for perf scripts like perf-archive.sh and perf-iostat.sh, however, inbuilt commands aren't suggested. Add the inbuilt commands so they may be suggested too. Before: $ perf reccord perf: 'reccord' is not a perf-command. See 'perf --help'. $ After: $ perf reccord perf: 'reccord' is not a perf-command. See 'perf --help'. Did you mean this? record $ Signed-off-by: Ian Rogers Tested-by: Arnaldo Carvalho de Melo Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ingo Molnar Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20240301201306.2680986-1-irogers@google.com [ Added some fixes from Ian to problems I noticed while testing ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin.h | 4 +++- tools/perf/perf.c | 23 ++++++++++++++----- tools/perf/util/help-unknown-cmd.c | 45 ++++++++++++++++++-------------------- 3 files changed, 41 insertions(+), 31 deletions(-) diff --git a/tools/perf/builtin.h b/tools/perf/builtin.h index f2ab5bae2150..f4375deabfa3 100644 --- a/tools/perf/builtin.h +++ b/tools/perf/builtin.h @@ -2,8 +2,10 @@ #ifndef BUILTIN_H #define BUILTIN_H +struct cmdnames; + void list_common_cmds_help(void); -const char *help_unknown_cmd(const char *cmd); +const char *help_unknown_cmd(const char *cmd, struct cmdnames *main_cmds); int cmd_annotate(int argc, const char **argv); int cmd_bench(int argc, const char **argv); diff --git a/tools/perf/perf.c b/tools/perf/perf.c index 921bee0a6437..bd3f80b5bb46 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c @@ -18,6 +18,7 @@ #include #include "util/parse-events.h" #include +#include #include "util/debug.h" #include "util/event.h" #include "util/util.h" // usage() @@ -458,7 +459,7 @@ static int libperf_print(enum libperf_print_level level, int main(int argc, const char **argv) { - int err; + int err, done_help = 0; const char *cmd; char sbuf[STRERR_BUFSIZE]; @@ -557,22 +558,32 @@ int main(int argc, const char **argv) pthread__block_sigwinch(); while (1) { - static int done_help; - run_argv(&argc, &argv); if (errno != ENOENT) break; if (!done_help) { - cmd = argv[0] = help_unknown_cmd(cmd); + struct cmdnames main_cmds = {}; + + for (unsigned int i = 0; i < ARRAY_SIZE(commands); i++) { + add_cmdname(&main_cmds, + commands[i].cmd, + strlen(commands[i].cmd)); + } + cmd = argv[0] = help_unknown_cmd(cmd, &main_cmds); + clean_cmdnames(&main_cmds); done_help = 1; + if (!cmd) + break; } else break; } - fprintf(stderr, "Failed to run command '%s': %s\n", - cmd, str_error_r(errno, sbuf, sizeof(sbuf))); + if (cmd) { + fprintf(stderr, "Failed to run command '%s': %s\n", + cmd, str_error_r(errno, sbuf, sizeof(sbuf))); + } out: if (debug_fp) fclose(debug_fp); diff --git a/tools/perf/util/help-unknown-cmd.c b/tools/perf/util/help-unknown-cmd.c index eab99ea6ac01..2ba3369f1620 100644 --- a/tools/perf/util/help-unknown-cmd.c +++ b/tools/perf/util/help-unknown-cmd.c @@ -52,46 +52,44 @@ static int add_cmd_list(struct cmdnames *cmds, struct cmdnames *old) return 0; } -const char *help_unknown_cmd(const char *cmd) +const char *help_unknown_cmd(const char *cmd, struct cmdnames *main_cmds) { unsigned int i, n = 0, best_similarity = 0; - struct cmdnames main_cmds, other_cmds; + struct cmdnames other_cmds; - memset(&main_cmds, 0, sizeof(main_cmds)); - memset(&other_cmds, 0, sizeof(main_cmds)); + memset(&other_cmds, 0, sizeof(other_cmds)); perf_config(perf_unknown_cmd_config, NULL); - load_command_list("perf-", &main_cmds, &other_cmds); + load_command_list("perf-", main_cmds, &other_cmds); - if (add_cmd_list(&main_cmds, &other_cmds) < 0) { + if (add_cmd_list(main_cmds, &other_cmds) < 0) { fprintf(stderr, "ERROR: Failed to allocate command list for unknown command.\n"); goto end; } - qsort(main_cmds.names, main_cmds.cnt, - sizeof(main_cmds.names), cmdname_compare); - uniq(&main_cmds); + qsort(main_cmds->names, main_cmds->cnt, + sizeof(main_cmds->names), cmdname_compare); + uniq(main_cmds); - if (main_cmds.cnt) { + if (main_cmds->cnt) { /* This reuses cmdname->len for similarity index */ - for (i = 0; i < main_cmds.cnt; ++i) - main_cmds.names[i]->len = - levenshtein(cmd, main_cmds.names[i]->name, 0, 2, 1, 4); + for (i = 0; i < main_cmds->cnt; ++i) + main_cmds->names[i]->len = + levenshtein(cmd, main_cmds->names[i]->name, 0, 2, 1, 4); - qsort(main_cmds.names, main_cmds.cnt, - sizeof(*main_cmds.names), levenshtein_compare); + qsort(main_cmds->names, main_cmds->cnt, + sizeof(*main_cmds->names), levenshtein_compare); - best_similarity = main_cmds.names[0]->len; + best_similarity = main_cmds->names[0]->len; n = 1; - while (n < main_cmds.cnt && best_similarity == main_cmds.names[n]->len) + while (n < main_cmds->cnt && best_similarity == main_cmds->names[n]->len) ++n; } if (autocorrect && n == 1) { - const char *assumed = main_cmds.names[0]->name; + const char *assumed = main_cmds->names[0]->name; - main_cmds.names[0] = NULL; - clean_cmdnames(&main_cmds); + main_cmds->names[0] = NULL; clean_cmdnames(&other_cmds); fprintf(stderr, "WARNING: You called a perf program named '%s', " "which does not exist.\n" @@ -107,15 +105,14 @@ const char *help_unknown_cmd(const char *cmd) fprintf(stderr, "perf: '%s' is not a perf-command. See 'perf --help'.\n", cmd); - if (main_cmds.cnt && best_similarity < 6) { + if (main_cmds->cnt && best_similarity < 6) { fprintf(stderr, "\nDid you mean %s?\n", n < 2 ? "this": "one of these"); for (i = 0; i < n; i++) - fprintf(stderr, "\t%s\n", main_cmds.names[i]->name); + fprintf(stderr, "\t%s\n", main_cmds->names[i]->name); } end: - clean_cmdnames(&main_cmds); clean_cmdnames(&other_cmds); - exit(1); + return NULL; } -- cgit v1.2.3-59-g8ed1b From 7aea01eaf4f301bd652a25d543bcba6c23cb4b85 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Fri, 1 Mar 2024 12:13:06 -0800 Subject: perf help: Lower levenshtein penality for deleting character The levenshtein penalty for deleting a character was far higher than subsituting or inserting a character. Lower the penalty to match that of inserting a character. Before: $ perf recccord perf: 'recccord' is not a perf-command. See 'perf --help'. $ After: $ perf recccord perf: 'recccord' is not a perf-command. See 'perf --help'. Did you mean this? record $ Signed-off-by: Ian Rogers Tested-by: Arnaldo Carvalho de Melo Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ingo Molnar Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20240301201306.2680986-2-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/help-unknown-cmd.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/tools/perf/util/help-unknown-cmd.c b/tools/perf/util/help-unknown-cmd.c index 2ba3369f1620..a0a46e34f8d1 100644 --- a/tools/perf/util/help-unknown-cmd.c +++ b/tools/perf/util/help-unknown-cmd.c @@ -73,10 +73,14 @@ const char *help_unknown_cmd(const char *cmd, struct cmdnames *main_cmds) if (main_cmds->cnt) { /* This reuses cmdname->len for similarity index */ - for (i = 0; i < main_cmds->cnt; ++i) + for (i = 0; i < main_cmds->cnt; ++i) { main_cmds->names[i]->len = - levenshtein(cmd, main_cmds->names[i]->name, 0, 2, 1, 4); - + levenshtein(cmd, main_cmds->names[i]->name, + /*swap_penalty=*/0, + /*substition_penality=*/2, + /*insertion_penality=*/1, + /*deletion_penalty=*/1); + } qsort(main_cmds->names, main_cmds->cnt, sizeof(*main_cmds->names), levenshtein_compare); -- cgit v1.2.3-59-g8ed1b From 4cef0e7ae76b877e67909b16b3044f0b4a504f32 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Fri, 1 Mar 2024 09:47:11 -0800 Subject: perf tests: Run tests in parallel by default Switch from running tests sequentially to running in parallel by default. Change the opt-in '-p' or '--parallel' flag to '-S' or '--sequential'. On an 8 core tigerlake an address sanitizer run time changes from: 326.54user 622.73system 6:59.91elapsed 226%CPU to: 973.02user 583.98system 3:01.17elapsed 859%CPU So over twice as fast, saving 4 minutes. Signed-off-by: Ian Rogers Tested-by: Arnaldo Carvalho de Melo Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Kan Liang Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20240301174711.2646944-1-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/builtin-test.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c index ddb2f4e38ea5..73f53b02f733 100644 --- a/tools/perf/tests/builtin-test.c +++ b/tools/perf/tests/builtin-test.c @@ -39,8 +39,8 @@ * making them easier to debug. */ static bool dont_fork; -/* Fork the tests in parallel and then wait for their completion. */ -static bool parallel; +/* Don't fork the tests in parallel and wait for their completion. */ +static bool sequential; const char *dso_to_test; const char *test_objdump_path = "objdump"; @@ -374,7 +374,7 @@ static int start_test(struct test_suite *test, int i, int subi, struct child_tes } (*child)->process.no_exec_cmd = run_test_child; err = start_command(&(*child)->process); - if (err || parallel) + if (err || !sequential) return err; return finish_test(*child, width); } @@ -440,7 +440,7 @@ static int __cmd_test(int argc, const char *argv[], struct intlist *skiplist) int err = start_test(t, curr, -1, &child_tests[child_test_num++], width); if (err) { - /* TODO: if parallel waitpid the already forked children. */ + /* TODO: if !sequential waitpid the already forked children. */ free(child_tests); return err; } @@ -460,7 +460,7 @@ static int __cmd_test(int argc, const char *argv[], struct intlist *skiplist) } } for (i = 0; i < child_test_num; i++) { - if (parallel) { + if (!sequential) { int ret = finish_test(child_tests[i], width); if (ret) @@ -536,8 +536,8 @@ int cmd_test(int argc, const char **argv) "be more verbose (show symbol address, etc)"), OPT_BOOLEAN('F', "dont-fork", &dont_fork, "Do not fork for testcase"), - OPT_BOOLEAN('p', "parallel", ¶llel, - "Run the tests altogether in parallel"), + OPT_BOOLEAN('S', "sequential", &sequential, + "Run the tests one after another rather than in parallel"), OPT_STRING('w', "workload", &workload, "work", "workload to run for testing"), OPT_STRING(0, "dso", &dso_to_test, "dso", "dso to test"), OPT_STRING(0, "objdump", &test_objdump_path, "path", @@ -564,6 +564,9 @@ int cmd_test(int argc, const char **argv) if (workload) return run_workload(workload, argc, argv); + if (dont_fork) + sequential = true; + symbol_conf.priv_size = sizeof(int); symbol_conf.try_vmlinux_path = true; -- cgit v1.2.3-59-g8ed1b From 3d6cfbaf279ddec9d92d434268ac7aab1a4935ca Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 19 Mar 2024 14:49:32 -0300 Subject: perf beauty: Introduce scrape script for various fs syscalls 'flags' arguments It was using the first variation on producing a string representation for a binary flag, one that used the system's fcntl.h and preprocessor tricks that had to be updated everytime a new flag was introduced. Use the more recent scrape script + strarray + strarray__scnprintf_flags() combo. $ tools/perf/trace/beauty/fs_at_flags.sh static const char *fs_at_flags[] = { [ilog2(0x100) + 1] = "SYMLINK_NOFOLLOW", [ilog2(0x200) + 1] = "REMOVEDIR", [ilog2(0x400) + 1] = "SYMLINK_FOLLOW", [ilog2(0x800) + 1] = "NO_AUTOMOUNT", [ilog2(0x1000) + 1] = "EMPTY_PATH", [ilog2(0x0000) + 1] = "STATX_SYNC_AS_STAT", [ilog2(0x2000) + 1] = "STATX_FORCE_SYNC", [ilog2(0x4000) + 1] = "STATX_DONT_SYNC", [ilog2(0x8000) + 1] = "RECURSIVE", [ilog2(0x80000000) + 1] = "GETATTR_NOSEC", }; $ Now we need a copy of uapi/linux/fcntl.h from tools/include/ in the scrape only directory tools/perf/trace/beauty/include and will use that fs_at_flags array for other fs syscalls. Reviewed-by: Ian Rogers Cc: Adrian Hunter Cc: Jiri Olsa Cc: Namhyung Kim Link: https://lore.kernel.org/lkml/20240320193115.811899-2-acme@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Makefile.perf | 7 ++ tools/perf/builtin-trace.c | 2 +- tools/perf/check-headers.sh | 1 + tools/perf/trace/beauty/Build | 1 + tools/perf/trace/beauty/beauty.h | 4 +- tools/perf/trace/beauty/fs_at_flags.c | 26 +++++ tools/perf/trace/beauty/fs_at_flags.sh | 21 ++++ tools/perf/trace/beauty/include/uapi/linux/fcntl.h | 123 +++++++++++++++++++++ tools/perf/trace/beauty/statx.c | 31 ------ 9 files changed, 182 insertions(+), 34 deletions(-) create mode 100644 tools/perf/trace/beauty/fs_at_flags.c create mode 100755 tools/perf/trace/beauty/fs_at_flags.sh create mode 100644 tools/perf/trace/beauty/include/uapi/linux/fcntl.h diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index ccd2dcbc64f7..73d5603450b0 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -489,6 +489,12 @@ beauty_ioctl_outdir := $(beauty_outdir)/ioctl # Create output directory if not already present $(shell [ -d '$(beauty_ioctl_outdir)' ] || mkdir -p '$(beauty_ioctl_outdir)') +fs_at_flags_array := $(beauty_outdir)/fs_at_flags_array.c +fs_at_flags_tbl := $(srctree)/tools/perf/trace/beauty/fs_at_flags.sh + +$(fs_at_flags_array): $(beauty_uapi_linux_dir)/fcntl.h $(fs_at_flags_tbl) + $(Q)$(SHELL) '$(fs_at_flags_tbl)' $(beauty_uapi_linux_dir) > $@ + clone_flags_array := $(beauty_outdir)/clone_flags_array.c clone_flags_tbl := $(srctree)/tools/perf/trace/beauty/clone.sh @@ -772,6 +778,7 @@ build-dir = $(or $(__build-dir),.) prepare: $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)common-cmds.h archheaders \ arm64-sysreg-defs \ + $(fs_at_flags_array) \ $(clone_flags_array) \ $(drm_ioctl_array) \ $(fadvise_advice_array) \ diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 8fb032caeaf5..8417387aafa8 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -1144,7 +1144,7 @@ static const struct syscall_fmt syscall_fmts[] = { { .name = "stat", .alias = "newstat", }, { .name = "statx", .arg = { [0] = { .scnprintf = SCA_FDAT, /* fdat */ }, - [2] = { .scnprintf = SCA_STATX_FLAGS, /* flags */ } , + [2] = { .scnprintf = SCA_FS_AT_FLAGS, /* flags */ } , [3] = { .scnprintf = SCA_STATX_MASK, /* mask */ }, }, }, { .name = "swapoff", .arg = { [0] = { .scnprintf = SCA_FILENAME, /* specialfile */ }, }, }, diff --git a/tools/perf/check-headers.sh b/tools/perf/check-headers.sh index 413c9b747216..d23a84fdf3ef 100755 --- a/tools/perf/check-headers.sh +++ b/tools/perf/check-headers.sh @@ -89,6 +89,7 @@ BEAUTY_FILES=( "arch/x86/include/asm/irq_vectors.h" "arch/x86/include/uapi/asm/prctl.h" "include/linux/socket.h" + "include/uapi/linux/fcntl.h" "include/uapi/linux/fs.h" "include/uapi/linux/mount.h" "include/uapi/linux/prctl.h" diff --git a/tools/perf/trace/beauty/Build b/tools/perf/trace/beauty/Build index d11ce256f511..d8ce1b698983 100644 --- a/tools/perf/trace/beauty/Build +++ b/tools/perf/trace/beauty/Build @@ -1,6 +1,7 @@ perf-y += clone.o perf-y += fcntl.o perf-y += flock.o +perf-y += fs_at_flags.o perf-y += fsmount.o perf-y += fspick.o ifeq ($(SRCARCH),$(filter $(SRCARCH),x86)) diff --git a/tools/perf/trace/beauty/beauty.h b/tools/perf/trace/beauty/beauty.h index 9feb794f5c6e..c94ae8701bc6 100644 --- a/tools/perf/trace/beauty/beauty.h +++ b/tools/perf/trace/beauty/beauty.h @@ -234,8 +234,8 @@ size_t syscall_arg__scnprintf_socket_protocol(char *bf, size_t size, struct sysc size_t syscall_arg__scnprintf_socket_level(char *bf, size_t size, struct syscall_arg *arg); #define SCA_SK_LEVEL syscall_arg__scnprintf_socket_level -size_t syscall_arg__scnprintf_statx_flags(char *bf, size_t size, struct syscall_arg *arg); -#define SCA_STATX_FLAGS syscall_arg__scnprintf_statx_flags +size_t syscall_arg__scnprintf_fs_at_flags(char *bf, size_t size, struct syscall_arg *arg); +#define SCA_FS_AT_FLAGS syscall_arg__scnprintf_fs_at_flags size_t syscall_arg__scnprintf_statx_mask(char *bf, size_t size, struct syscall_arg *arg); #define SCA_STATX_MASK syscall_arg__scnprintf_statx_mask diff --git a/tools/perf/trace/beauty/fs_at_flags.c b/tools/perf/trace/beauty/fs_at_flags.c new file mode 100644 index 000000000000..2a099953d993 --- /dev/null +++ b/tools/perf/trace/beauty/fs_at_flags.c @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: LGPL-2.1 +/* + * trace/beauty/fs_at_flags.c + * + * Copyright (C) 2017, Red Hat Inc, Arnaldo Carvalho de Melo + */ + +#include "trace/beauty/beauty.h" +#include +#include + +#include "trace/beauty/generated/fs_at_flags_array.c" +static DEFINE_STRARRAY(fs_at_flags, "AT_"); + +static size_t fs_at__scnprintf_flags(unsigned long flags, char *bf, size_t size, bool show_prefix) +{ + return strarray__scnprintf_flags(&strarray__fs_at_flags, bf, size, show_prefix, flags); +} + +size_t syscall_arg__scnprintf_fs_at_flags(char *bf, size_t size, struct syscall_arg *arg) +{ + bool show_prefix = arg->show_string_prefix; + int flags = arg->val; + + return fs_at__scnprintf_flags(flags, bf, size, show_prefix); +} diff --git a/tools/perf/trace/beauty/fs_at_flags.sh b/tools/perf/trace/beauty/fs_at_flags.sh new file mode 100755 index 000000000000..456f59addf74 --- /dev/null +++ b/tools/perf/trace/beauty/fs_at_flags.sh @@ -0,0 +1,21 @@ +#!/bin/sh +# SPDX-License-Identifier: LGPL-2.1 + +if [ $# -ne 1 ] ; then + beauty_uapi_linux_dir=tools/perf/trace/beauty/include/uapi/linux/ +else + beauty_uapi_linux_dir=$1 +fi + +linux_fcntl=${beauty_uapi_linux_dir}/fcntl.h + +printf "static const char *fs_at_flags[] = {\n" +regex='^[[:space:]]*#[[:space:]]*define[[:space:]]+AT_([^_]+[[:alnum:]_]+)[[:space:]]+(0x[[:xdigit:]]+)[[:space:]]*.*' +# AT_EACCESS is only meaningful to faccessat, so we will special case it there... +# AT_STATX_SYNC_TYPE is not a bit, its a mask of AT_STATX_SYNC_AS_STAT, AT_STATX_FORCE_SYNC and AT_STATX_DONT_SYNC +grep -E $regex ${linux_fcntl} | \ + grep -v AT_EACCESS | \ + grep -v AT_STATX_SYNC_TYPE | \ + sed -r "s/$regex/\2 \1/g" | \ + xargs printf "\t[ilog2(%s) + 1] = \"%s\",\n" +printf "};\n" diff --git a/tools/perf/trace/beauty/include/uapi/linux/fcntl.h b/tools/perf/trace/beauty/include/uapi/linux/fcntl.h new file mode 100644 index 000000000000..282e90aeb163 --- /dev/null +++ b/tools/perf/trace/beauty/include/uapi/linux/fcntl.h @@ -0,0 +1,123 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _UAPI_LINUX_FCNTL_H +#define _UAPI_LINUX_FCNTL_H + +#include +#include + +#define F_SETLEASE (F_LINUX_SPECIFIC_BASE + 0) +#define F_GETLEASE (F_LINUX_SPECIFIC_BASE + 1) + +/* + * Cancel a blocking posix lock; internal use only until we expose an + * asynchronous lock api to userspace: + */ +#define F_CANCELLK (F_LINUX_SPECIFIC_BASE + 5) + +/* Create a file descriptor with FD_CLOEXEC set. */ +#define F_DUPFD_CLOEXEC (F_LINUX_SPECIFIC_BASE + 6) + +/* + * Request nofications on a directory. + * See below for events that may be notified. + */ +#define F_NOTIFY (F_LINUX_SPECIFIC_BASE+2) + +/* + * Set and get of pipe page size array + */ +#define F_SETPIPE_SZ (F_LINUX_SPECIFIC_BASE + 7) +#define F_GETPIPE_SZ (F_LINUX_SPECIFIC_BASE + 8) + +/* + * Set/Get seals + */ +#define F_ADD_SEALS (F_LINUX_SPECIFIC_BASE + 9) +#define F_GET_SEALS (F_LINUX_SPECIFIC_BASE + 10) + +/* + * Types of seals + */ +#define F_SEAL_SEAL 0x0001 /* prevent further seals from being set */ +#define F_SEAL_SHRINK 0x0002 /* prevent file from shrinking */ +#define F_SEAL_GROW 0x0004 /* prevent file from growing */ +#define F_SEAL_WRITE 0x0008 /* prevent writes */ +#define F_SEAL_FUTURE_WRITE 0x0010 /* prevent future writes while mapped */ +#define F_SEAL_EXEC 0x0020 /* prevent chmod modifying exec bits */ +/* (1U << 31) is reserved for signed error codes */ + +/* + * Set/Get write life time hints. {GET,SET}_RW_HINT operate on the + * underlying inode, while {GET,SET}_FILE_RW_HINT operate only on + * the specific file. + */ +#define F_GET_RW_HINT (F_LINUX_SPECIFIC_BASE + 11) +#define F_SET_RW_HINT (F_LINUX_SPECIFIC_BASE + 12) +#define F_GET_FILE_RW_HINT (F_LINUX_SPECIFIC_BASE + 13) +#define F_SET_FILE_RW_HINT (F_LINUX_SPECIFIC_BASE + 14) + +/* + * Valid hint values for F_{GET,SET}_RW_HINT. 0 is "not set", or can be + * used to clear any hints previously set. + */ +#define RWH_WRITE_LIFE_NOT_SET 0 +#define RWH_WRITE_LIFE_NONE 1 +#define RWH_WRITE_LIFE_SHORT 2 +#define RWH_WRITE_LIFE_MEDIUM 3 +#define RWH_WRITE_LIFE_LONG 4 +#define RWH_WRITE_LIFE_EXTREME 5 + +/* + * The originally introduced spelling is remained from the first + * versions of the patch set that introduced the feature, see commit + * v4.13-rc1~212^2~51. + */ +#define RWF_WRITE_LIFE_NOT_SET RWH_WRITE_LIFE_NOT_SET + +/* + * Types of directory notifications that may be requested. + */ +#define DN_ACCESS 0x00000001 /* File accessed */ +#define DN_MODIFY 0x00000002 /* File modified */ +#define DN_CREATE 0x00000004 /* File created */ +#define DN_DELETE 0x00000008 /* File removed */ +#define DN_RENAME 0x00000010 /* File renamed */ +#define DN_ATTRIB 0x00000020 /* File changed attibutes */ +#define DN_MULTISHOT 0x80000000 /* Don't remove notifier */ + +/* + * The constants AT_REMOVEDIR and AT_EACCESS have the same value. AT_EACCESS is + * meaningful only to faccessat, while AT_REMOVEDIR is meaningful only to + * unlinkat. The two functions do completely different things and therefore, + * the flags can be allowed to overlap. For example, passing AT_REMOVEDIR to + * faccessat would be undefined behavior and thus treating it equivalent to + * AT_EACCESS is valid undefined behavior. + */ +#define AT_FDCWD -100 /* Special value used to indicate + openat should use the current + working directory. */ +#define AT_SYMLINK_NOFOLLOW 0x100 /* Do not follow symbolic links. */ +#define AT_EACCESS 0x200 /* Test access permitted for + effective IDs, not real IDs. */ +#define AT_REMOVEDIR 0x200 /* Remove directory instead of + unlinking file. */ +#define AT_SYMLINK_FOLLOW 0x400 /* Follow symbolic links. */ +#define AT_NO_AUTOMOUNT 0x800 /* Suppress terminal automount traversal */ +#define AT_EMPTY_PATH 0x1000 /* Allow empty relative pathname */ + +#define AT_STATX_SYNC_TYPE 0x6000 /* Type of synchronisation required from statx() */ +#define AT_STATX_SYNC_AS_STAT 0x0000 /* - Do whatever stat() does */ +#define AT_STATX_FORCE_SYNC 0x2000 /* - Force the attributes to be sync'd with the server */ +#define AT_STATX_DONT_SYNC 0x4000 /* - Don't sync attributes with the server */ + +#define AT_RECURSIVE 0x8000 /* Apply to the entire subtree */ + +/* Flags for name_to_handle_at(2). We reuse AT_ flag space to save bits... */ +#define AT_HANDLE_FID AT_REMOVEDIR /* file handle is needed to + compare object identity and may not + be usable to open_by_handle_at(2) */ +#if defined(__KERNEL__) +#define AT_GETATTR_NOSEC 0x80000000 +#endif + +#endif /* _UAPI_LINUX_FCNTL_H */ diff --git a/tools/perf/trace/beauty/statx.c b/tools/perf/trace/beauty/statx.c index 1f7e34ed4e02..4e0059fd0211 100644 --- a/tools/perf/trace/beauty/statx.c +++ b/tools/perf/trace/beauty/statx.c @@ -8,7 +8,6 @@ #include "trace/beauty/beauty.h" #include #include -#include #include #ifndef STATX_MNT_ID @@ -21,36 +20,6 @@ #define STATX_MNT_ID_UNIQUE 0x00004000U #endif -size_t syscall_arg__scnprintf_statx_flags(char *bf, size_t size, struct syscall_arg *arg) -{ - bool show_prefix = arg->show_string_prefix; - const char *prefix = "AT_"; - int printed = 0, flags = arg->val; - - if (flags == 0) - return scnprintf(bf, size, "%s%s", show_prefix ? "AT_STATX_" : "", "SYNC_AS_STAT"); -#define P_FLAG(n) \ - if (flags & AT_##n) { \ - printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", show_prefix ? prefix : "", #n); \ - flags &= ~AT_##n; \ - } - - P_FLAG(SYMLINK_NOFOLLOW); - P_FLAG(REMOVEDIR); - P_FLAG(SYMLINK_FOLLOW); - P_FLAG(NO_AUTOMOUNT); - P_FLAG(EMPTY_PATH); - P_FLAG(STATX_FORCE_SYNC); - P_FLAG(STATX_DONT_SYNC); - -#undef P_FLAG - - if (flags) - printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags); - - return printed; -} - size_t syscall_arg__scnprintf_statx_mask(char *bf, size_t size, struct syscall_arg *arg) { bool show_prefix = arg->show_string_prefix; -- cgit v1.2.3-59-g8ed1b From f122b3d6d179455ec77dc17690bea7e970433254 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 19 Mar 2024 14:49:32 -0300 Subject: perf beauty: Introduce scrape script for the 'statx' syscall 'mask' argument It was using the first variation on producing a string representation for a binary flag, one that used the system's stat.h and preprocessor tricks that had to be updated everytime a new flag was introduced. Use the more recent scrape script + strarray + strarray__scnprintf_flags() combo. $ tools/perf/trace/beauty/statx_mask.sh static const char *statx_mask[] = { [ilog2(0x00000001) + 1] = "TYPE", [ilog2(0x00000002) + 1] = "MODE", [ilog2(0x00000004) + 1] = "NLINK", [ilog2(0x00000008) + 1] = "UID", [ilog2(0x00000010) + 1] = "GID", [ilog2(0x00000020) + 1] = "ATIME", [ilog2(0x00000040) + 1] = "MTIME", [ilog2(0x00000080) + 1] = "CTIME", [ilog2(0x00000100) + 1] = "INO", [ilog2(0x00000200) + 1] = "SIZE", [ilog2(0x00000400) + 1] = "BLOCKS", [ilog2(0x00000800) + 1] = "BTIME", [ilog2(0x00001000) + 1] = "MNT_ID", [ilog2(0x00002000) + 1] = "DIOALIGN", [ilog2(0x00004000) + 1] = "MNT_ID_UNIQUE", }; $ Now we need a copy of uapi/linux/stat.h from tools/include/ in the scrape only directory tools/perf/trace/beauty/include. Reviewed-by: Ian Rogers Cc: Adrian Hunter Cc: Jiri Olsa Cc: Namhyung Kim Link: https://lore.kernel.org/lkml/20240320193115.811899-3-acme@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Makefile.perf | 7 + tools/perf/check-headers.sh | 1 + tools/perf/trace/beauty/include/uapi/linux/stat.h | 195 ++++++++++++++++++++++ tools/perf/trace/beauty/statx.c | 50 +----- tools/perf/trace/beauty/statx_mask.sh | 23 +++ 5 files changed, 235 insertions(+), 41 deletions(-) create mode 100644 tools/perf/trace/beauty/include/uapi/linux/stat.h create mode 100755 tools/perf/trace/beauty/statx_mask.sh diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index 73d5603450b0..0d2dbdfc44df 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -673,6 +673,12 @@ arch_errno_tbl := $(srctree)/tools/perf/trace/beauty/arch_errno_names.sh $(arch_errno_name_array): $(arch_errno_tbl) $(Q)$(SHELL) '$(arch_errno_tbl)' '$(patsubst -%,,$(CC))' $(arch_errno_hdr_dir) > $@ +statx_mask_array := $(beauty_outdir)/statx_mask_array.c +statx_mask_tbl := $(srctree)/tools/perf/trace/beauty/statx_mask.sh + +$(statx_mask_array): $(beauty_uapi_linux_dir)/stat.h $(statx_mask_tbl) + $(Q)$(SHELL) '$(statx_mask_tbl)' $(beauty_uapi_linux_dir) > $@ + sync_file_range_arrays := $(beauty_outdir)/sync_file_range_arrays.c sync_file_range_tbls := $(srctree)/tools/perf/trace/beauty/sync_file_range.sh @@ -807,6 +813,7 @@ prepare: $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)common-cmds.h archheaders \ $(x86_arch_prctl_code_array) \ $(rename_flags_array) \ $(arch_errno_name_array) \ + $(statx_mask_array) \ $(sync_file_range_arrays) \ $(LIBAPI) \ $(LIBPERF) \ diff --git a/tools/perf/check-headers.sh b/tools/perf/check-headers.sh index d23a84fdf3ef..76726a5a7c78 100755 --- a/tools/perf/check-headers.sh +++ b/tools/perf/check-headers.sh @@ -94,6 +94,7 @@ BEAUTY_FILES=( "include/uapi/linux/mount.h" "include/uapi/linux/prctl.h" "include/uapi/linux/sched.h" + "include/uapi/linux/stat.h" "include/uapi/linux/usbdevice_fs.h" "include/uapi/sound/asound.h" ) diff --git a/tools/perf/trace/beauty/include/uapi/linux/stat.h b/tools/perf/trace/beauty/include/uapi/linux/stat.h new file mode 100644 index 000000000000..2f2ee82d5517 --- /dev/null +++ b/tools/perf/trace/beauty/include/uapi/linux/stat.h @@ -0,0 +1,195 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _UAPI_LINUX_STAT_H +#define _UAPI_LINUX_STAT_H + +#include + +#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) + +#define S_IFMT 00170000 +#define S_IFSOCK 0140000 +#define S_IFLNK 0120000 +#define S_IFREG 0100000 +#define S_IFBLK 0060000 +#define S_IFDIR 0040000 +#define S_IFCHR 0020000 +#define S_IFIFO 0010000 +#define S_ISUID 0004000 +#define S_ISGID 0002000 +#define S_ISVTX 0001000 + +#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) +#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) +#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) +#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) +#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) +#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) + +#define S_IRWXU 00700 +#define S_IRUSR 00400 +#define S_IWUSR 00200 +#define S_IXUSR 00100 + +#define S_IRWXG 00070 +#define S_IRGRP 00040 +#define S_IWGRP 00020 +#define S_IXGRP 00010 + +#define S_IRWXO 00007 +#define S_IROTH 00004 +#define S_IWOTH 00002 +#define S_IXOTH 00001 + +#endif + +/* + * Timestamp structure for the timestamps in struct statx. + * + * tv_sec holds the number of seconds before (negative) or after (positive) + * 00:00:00 1st January 1970 UTC. + * + * tv_nsec holds a number of nanoseconds (0..999,999,999) after the tv_sec time. + * + * __reserved is held in case we need a yet finer resolution. + */ +struct statx_timestamp { + __s64 tv_sec; + __u32 tv_nsec; + __s32 __reserved; +}; + +/* + * Structures for the extended file attribute retrieval system call + * (statx()). + * + * The caller passes a mask of what they're specifically interested in as a + * parameter to statx(). What statx() actually got will be indicated in + * st_mask upon return. + * + * For each bit in the mask argument: + * + * - if the datum is not supported: + * + * - the bit will be cleared, and + * + * - the datum will be set to an appropriate fabricated value if one is + * available (eg. CIFS can take a default uid and gid), otherwise + * + * - the field will be cleared; + * + * - otherwise, if explicitly requested: + * + * - the datum will be synchronised to the server if AT_STATX_FORCE_SYNC is + * set or if the datum is considered out of date, and + * + * - the field will be filled in and the bit will be set; + * + * - otherwise, if not requested, but available in approximate form without any + * effort, it will be filled in anyway, and the bit will be set upon return + * (it might not be up to date, however, and no attempt will be made to + * synchronise the internal state first); + * + * - otherwise the field and the bit will be cleared before returning. + * + * Items in STATX_BASIC_STATS may be marked unavailable on return, but they + * will have values installed for compatibility purposes so that stat() and + * co. can be emulated in userspace. + */ +struct statx { + /* 0x00 */ + __u32 stx_mask; /* What results were written [uncond] */ + __u32 stx_blksize; /* Preferred general I/O size [uncond] */ + __u64 stx_attributes; /* Flags conveying information about the file [uncond] */ + /* 0x10 */ + __u32 stx_nlink; /* Number of hard links */ + __u32 stx_uid; /* User ID of owner */ + __u32 stx_gid; /* Group ID of owner */ + __u16 stx_mode; /* File mode */ + __u16 __spare0[1]; + /* 0x20 */ + __u64 stx_ino; /* Inode number */ + __u64 stx_size; /* File size */ + __u64 stx_blocks; /* Number of 512-byte blocks allocated */ + __u64 stx_attributes_mask; /* Mask to show what's supported in stx_attributes */ + /* 0x40 */ + struct statx_timestamp stx_atime; /* Last access time */ + struct statx_timestamp stx_btime; /* File creation time */ + struct statx_timestamp stx_ctime; /* Last attribute change time */ + struct statx_timestamp stx_mtime; /* Last data modification time */ + /* 0x80 */ + __u32 stx_rdev_major; /* Device ID of special file [if bdev/cdev] */ + __u32 stx_rdev_minor; + __u32 stx_dev_major; /* ID of device containing file [uncond] */ + __u32 stx_dev_minor; + /* 0x90 */ + __u64 stx_mnt_id; + __u32 stx_dio_mem_align; /* Memory buffer alignment for direct I/O */ + __u32 stx_dio_offset_align; /* File offset alignment for direct I/O */ + /* 0xa0 */ + __u64 __spare3[12]; /* Spare space for future expansion */ + /* 0x100 */ +}; + +/* + * Flags to be stx_mask + * + * Query request/result mask for statx() and struct statx::stx_mask. + * + * These bits should be set in the mask argument of statx() to request + * particular items when calling statx(). + */ +#define STATX_TYPE 0x00000001U /* Want/got stx_mode & S_IFMT */ +#define STATX_MODE 0x00000002U /* Want/got stx_mode & ~S_IFMT */ +#define STATX_NLINK 0x00000004U /* Want/got stx_nlink */ +#define STATX_UID 0x00000008U /* Want/got stx_uid */ +#define STATX_GID 0x00000010U /* Want/got stx_gid */ +#define STATX_ATIME 0x00000020U /* Want/got stx_atime */ +#define STATX_MTIME 0x00000040U /* Want/got stx_mtime */ +#define STATX_CTIME 0x00000080U /* Want/got stx_ctime */ +#define STATX_INO 0x00000100U /* Want/got stx_ino */ +#define STATX_SIZE 0x00000200U /* Want/got stx_size */ +#define STATX_BLOCKS 0x00000400U /* Want/got stx_blocks */ +#define STATX_BASIC_STATS 0x000007ffU /* The stuff in the normal stat struct */ +#define STATX_BTIME 0x00000800U /* Want/got stx_btime */ +#define STATX_MNT_ID 0x00001000U /* Got stx_mnt_id */ +#define STATX_DIOALIGN 0x00002000U /* Want/got direct I/O alignment info */ +#define STATX_MNT_ID_UNIQUE 0x00004000U /* Want/got extended stx_mount_id */ + +#define STATX__RESERVED 0x80000000U /* Reserved for future struct statx expansion */ + +#ifndef __KERNEL__ +/* + * This is deprecated, and shall remain the same value in the future. To avoid + * confusion please use the equivalent (STATX_BASIC_STATS | STATX_BTIME) + * instead. + */ +#define STATX_ALL 0x00000fffU +#endif + +/* + * Attributes to be found in stx_attributes and masked in stx_attributes_mask. + * + * These give information about the features or the state of a file that might + * be of use to ordinary userspace programs such as GUIs or ls rather than + * specialised tools. + * + * Note that the flags marked [I] correspond to the FS_IOC_SETFLAGS flags + * semantically. Where possible, the numerical value is picked to correspond + * also. Note that the DAX attribute indicates that the file is in the CPU + * direct access state. It does not correspond to the per-inode flag that + * some filesystems support. + * + */ +#define STATX_ATTR_COMPRESSED 0x00000004 /* [I] File is compressed by the fs */ +#define STATX_ATTR_IMMUTABLE 0x00000010 /* [I] File is marked immutable */ +#define STATX_ATTR_APPEND 0x00000020 /* [I] File is append-only */ +#define STATX_ATTR_NODUMP 0x00000040 /* [I] File is not to be dumped */ +#define STATX_ATTR_ENCRYPTED 0x00000800 /* [I] File requires key to decrypt in fs */ +#define STATX_ATTR_AUTOMOUNT 0x00001000 /* Dir: Automount trigger */ +#define STATX_ATTR_MOUNT_ROOT 0x00002000 /* Root of a mount */ +#define STATX_ATTR_VERITY 0x00100000 /* [I] Verity protected file */ +#define STATX_ATTR_DAX 0x00200000 /* File is currently in DAX state */ + + +#endif /* _UAPI_LINUX_STAT_H */ diff --git a/tools/perf/trace/beauty/statx.c b/tools/perf/trace/beauty/statx.c index 4e0059fd0211..24843e614b93 100644 --- a/tools/perf/trace/beauty/statx.c +++ b/tools/perf/trace/beauty/statx.c @@ -6,52 +6,20 @@ */ #include "trace/beauty/beauty.h" -#include #include -#include +#include -#ifndef STATX_MNT_ID -#define STATX_MNT_ID 0x00001000U -#endif -#ifndef STATX_DIOALIGN -#define STATX_DIOALIGN 0x00002000U -#endif -#ifndef STATX_MNT_ID_UNIQUE -#define STATX_MNT_ID_UNIQUE 0x00004000U -#endif +static size_t statx__scnprintf_mask(unsigned long mask, char *bf, size_t size, bool show_prefix) +{ + #include "trace/beauty/generated/statx_mask_array.c" + static DEFINE_STRARRAY(statx_mask, "STATX_"); + return strarray__scnprintf_flags(&strarray__statx_mask, bf, size, show_prefix, mask); +} size_t syscall_arg__scnprintf_statx_mask(char *bf, size_t size, struct syscall_arg *arg) { bool show_prefix = arg->show_string_prefix; - const char *prefix = "STATX_"; - int printed = 0, flags = arg->val; - -#define P_FLAG(n) \ - if (flags & STATX_##n) { \ - printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", show_prefix ? prefix : "", #n); \ - flags &= ~STATX_##n; \ - } - - P_FLAG(TYPE); - P_FLAG(MODE); - P_FLAG(NLINK); - P_FLAG(UID); - P_FLAG(GID); - P_FLAG(ATIME); - P_FLAG(MTIME); - P_FLAG(CTIME); - P_FLAG(INO); - P_FLAG(SIZE); - P_FLAG(BLOCKS); - P_FLAG(BTIME); - P_FLAG(MNT_ID); - P_FLAG(DIOALIGN); - P_FLAG(MNT_ID_UNIQUE); - -#undef P_FLAG - - if (flags) - printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags); + int mask = arg->val; - return printed; + return statx__scnprintf_mask(mask, bf, size, show_prefix); } diff --git a/tools/perf/trace/beauty/statx_mask.sh b/tools/perf/trace/beauty/statx_mask.sh new file mode 100755 index 000000000000..18c802ed0c71 --- /dev/null +++ b/tools/perf/trace/beauty/statx_mask.sh @@ -0,0 +1,23 @@ +#!/bin/sh +# SPDX-License-Identifier: LGPL-2.1 + +if [ $# -ne 1 ] ; then + beauty_uapi_linux_dir=tools/perf/trace/beauty/include/uapi/linux/ +else + beauty_uapi_linux_dir=$1 +fi + +linux_stat=${beauty_uapi_linux_dir}/stat.h + +printf "static const char *statx_mask[] = {\n" +regex='^[[:space:]]*#[[:space:]]*define[[:space:]]+STATX_([^_]+[[:alnum:]_]+)[[:space:]]+(0x[[:xdigit:]]+)[[:space:]]*.*' +# STATX_BASIC_STATS its a bitmask formed by the mask in the normal stat struct +# STATX_ALL is another bitmask and deprecated +# STATX_ATTR_*: Attributes to be found in stx_attributes and masked in stx_attributes_mask +grep -E $regex ${linux_stat} | \ + grep -v STATX_ALL | \ + grep -v STATX_BASIC_STATS | \ + grep -v '\ Date: Tue, 19 Mar 2024 14:49:32 -0300 Subject: perf beauty: Introduce faccessat2 flags scnprintf routine The fsaccessat and fsaccessat2 now have beautifiers for its arguments. Reviewed-by: Ian Rogers Cc: Adrian Hunter Cc: Jiri Olsa Cc: Namhyung Kim Link: https://lore.kernel.org/lkml/20240320193115.811899-4-acme@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-trace.c | 9 +++++++++ tools/perf/trace/beauty/beauty.h | 3 +++ tools/perf/trace/beauty/fs_at_flags.c | 24 ++++++++++++++++++++++++ 3 files changed, 36 insertions(+) diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 8417387aafa8..58546e8af9fc 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -947,6 +947,15 @@ static const struct syscall_fmt syscall_fmts[] = { .arg = { [1] = STRARRAY(op, epoll_ctl_ops), }, }, { .name = "eventfd2", .arg = { [1] = { .scnprintf = SCA_EFD_FLAGS, /* flags */ }, }, }, + { .name = "faccessat", + .arg = { [0] = { .scnprintf = SCA_FDAT, /* dirfd */ }, + [1] = { .scnprintf = SCA_FILENAME, /* pathname */ }, + [2] = { .scnprintf = SCA_ACCMODE, /* mode */ }, }, }, + { .name = "faccessat2", + .arg = { [0] = { .scnprintf = SCA_FDAT, /* dirfd */ }, + [1] = { .scnprintf = SCA_FILENAME, /* pathname */ }, + [2] = { .scnprintf = SCA_ACCMODE, /* mode */ }, + [3] = { .scnprintf = SCA_FACCESSAT2_FLAGS, /* flags */ }, }, }, { .name = "fchmodat", .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, }, { .name = "fchownat", diff --git a/tools/perf/trace/beauty/beauty.h b/tools/perf/trace/beauty/beauty.h index c94ae8701bc6..78d10d92d351 100644 --- a/tools/perf/trace/beauty/beauty.h +++ b/tools/perf/trace/beauty/beauty.h @@ -237,6 +237,9 @@ size_t syscall_arg__scnprintf_socket_level(char *bf, size_t size, struct syscall size_t syscall_arg__scnprintf_fs_at_flags(char *bf, size_t size, struct syscall_arg *arg); #define SCA_FS_AT_FLAGS syscall_arg__scnprintf_fs_at_flags +size_t syscall_arg__scnprintf_faccessat2_flags(char *bf, size_t size, struct syscall_arg *arg); +#define SCA_FACCESSAT2_FLAGS syscall_arg__scnprintf_faccessat2_flags + size_t syscall_arg__scnprintf_statx_mask(char *bf, size_t size, struct syscall_arg *arg); #define SCA_STATX_MASK syscall_arg__scnprintf_statx_mask diff --git a/tools/perf/trace/beauty/fs_at_flags.c b/tools/perf/trace/beauty/fs_at_flags.c index 2a099953d993..c1365e8f0b96 100644 --- a/tools/perf/trace/beauty/fs_at_flags.c +++ b/tools/perf/trace/beauty/fs_at_flags.c @@ -7,6 +7,7 @@ #include "trace/beauty/beauty.h" #include +#include #include #include "trace/beauty/generated/fs_at_flags_array.c" @@ -24,3 +25,26 @@ size_t syscall_arg__scnprintf_fs_at_flags(char *bf, size_t size, struct syscall_ return fs_at__scnprintf_flags(flags, bf, size, show_prefix); } + +static size_t faccessat2__scnprintf_flags(unsigned long flags, char *bf, size_t size, bool show_prefix) +{ + int printed = 0; + + // AT_EACCESS is the same as AT_REMOVEDIR, that is in fs_at_flags_array, + // special case it here. + if (flags & AT_EACCESS) { + flags &= ~AT_EACCESS; + printed += scnprintf(bf + printed, size - printed, "%sEACCESS%s", + show_prefix ? strarray__fs_at_flags.prefix : "", flags ? "|" : ""); + } + + return strarray__scnprintf_flags(&strarray__fs_at_flags, bf + printed, size - printed, show_prefix, flags); +} + +size_t syscall_arg__scnprintf_faccessat2_flags(char *bf, size_t size, struct syscall_arg *arg) +{ + bool show_prefix = arg->show_string_prefix; + int flags = arg->val; + + return faccessat2__scnprintf_flags(flags, bf, size, show_prefix); +} -- cgit v1.2.3-59-g8ed1b From 4d92328290274c6bf9060ba384ccabbf7e72918b Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 20 Mar 2024 16:15:20 -0300 Subject: perf trace: Beautify the 'flags' arg of unlinkat Reusing the fs_at_flags array done for the 'stat' syscall. Reviewed-by: Ian Rogers Cc: Adrian Hunter Cc: Jiri Olsa Cc: Namhyung Kim Link: https://lore.kernel.org/lkml/20240320193115.811899-5-acme@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-trace.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 58546e8af9fc..ef0dfffd99fd 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -1171,7 +1171,9 @@ static const struct syscall_fmt syscall_fmts[] = { .arg = { [0] = { .scnprintf = SCA_FILENAME, /* name */ }, }, }, { .name = "uname", .alias = "newuname", }, { .name = "unlinkat", - .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, }, + .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, + [1] = { .scnprintf = SCA_FILENAME, /* pathname */ }, + [2] = { .scnprintf = SCA_FS_AT_FLAGS, /* flags */ }, }, }, { .name = "utimensat", .arg = { [0] = { .scnprintf = SCA_FDAT, /* dirfd */ }, }, }, { .name = "wait4", .errpid = true, -- cgit v1.2.3-59-g8ed1b From 0831638e8c279a08094fb6cc7aa201580ef74db2 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 20 Mar 2024 16:25:19 -0300 Subject: perf trace: Fix 'newfstatat'/'fstatat' argument pretty printing There were needless two entries, one for 'newfstatat' and another for 'fstatat', keep just one and pretty print its 'flags' argument using the fs_at_flags scnprintf that is also used by other FS syscalls such as 'stat', now: root@number:~# perf trace -e newfstatat --max-events=5 0.000 ( 0.010 ms): abrt-dump-jour/1400 newfstatat(dfd: 7, filename: "", statbuf: 0x7fff0d127000, flag: EMPTY_PATH) = 0 0.020 ( 0.003 ms): abrt-dump-jour/1400 newfstatat(dfd: 9, filename: "", statbuf: 0x55752507b0e8, flag: EMPTY_PATH) = 0 0.039 ( 0.004 ms): abrt-dump-jour/1400 newfstatat(dfd: 19, filename: "", statbuf: 0x557525061378, flag: EMPTY_PATH) = 0 0.047 ( 0.003 ms): abrt-dump-jour/1400 newfstatat(dfd: 20, filename: "", statbuf: 0x5575250b8cc8, flag: EMPTY_PATH) = 0 0.053 ( 0.003 ms): abrt-dump-jour/1400 newfstatat(dfd: 22, filename: "", statbuf: 0x5575250535d8, flag: EMPTY_PATH) = 0 root@number:~# Reviewed-by: Ian Rogers Cc: Adrian Hunter Cc: Jiri Olsa Cc: Namhyung Kim Link: https://lore.kernel.org/lkml/20240320193115.811899-6-acme@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-trace.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index ef0dfffd99fd..d3ec244e692a 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -978,7 +978,6 @@ static const struct syscall_fmt syscall_fmts[] = { [1] = { .scnprintf = SCA_FILENAME, /* path */ }, [2] = { .scnprintf = SCA_FSPICK_FLAGS, /* flags */ }, }, }, { .name = "fstat", .alias = "newfstat", }, - { .name = "fstatat", .alias = "newfstatat", }, { .name = "futex", .arg = { [1] = { .scnprintf = SCA_FUTEX_OP, /* op */ }, [5] = { .scnprintf = SCA_FUTEX_VAL3, /* val3 */ }, }, }, @@ -1060,8 +1059,10 @@ static const struct syscall_fmt syscall_fmts[] = { .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, }, { .name = "nanosleep", .arg = { [0] = { .scnprintf = SCA_TIMESPEC, /* req */ }, }, }, - { .name = "newfstatat", - .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, }, + { .name = "newfstatat", .alias = "fstatat", + .arg = { [0] = { .scnprintf = SCA_FDAT, /* dirfd */ }, + [1] = { .scnprintf = SCA_FILENAME, /* pathname */ }, + [3] = { .scnprintf = SCA_FS_AT_FLAGS, /* flags */ }, }, }, { .name = "open", .arg = { [1] = { .scnprintf = SCA_OPEN_FLAGS, /* flags */ }, }, }, { .name = "open_by_handle_at", -- cgit v1.2.3-59-g8ed1b From 581037151910126a7934e369e4b6ac70eda9a703 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 21 Mar 2024 11:13:30 -0300 Subject: perf probe: Add missing libgen.h header needed for using basename() This prototype is obtained indirectly, by luck, from some other header in probe-event.c in most systems, but recently exploded on alpine:edge: 8 13.39 alpine:edge : FAIL gcc version 13.2.1 20240309 (Alpine 13.2.1_git20240309) util/probe-event.c: In function 'convert_exec_to_group': util/probe-event.c:225:16: error: implicit declaration of function 'basename' [-Werror=implicit-function-declaration] 225 | ptr1 = basename(exec_copy); | ^~~~~~~~ util/probe-event.c:225:14: error: assignment to 'char *' from 'int' makes pointer from integer without a cast [-Werror=int-conversion] 225 | ptr1 = basename(exec_copy); | ^ cc1: all warnings being treated as errors make[3]: *** [/git/perf-6.8.0/tools/build/Makefile.build:158: util] Error 2 Fix it by adding the libgen.h header where basename() is prototyped. Fixes: fb7345bbf7fad9bf ("perf probe: Support basic dwarf-based operations on uprobe events") Cc: Masami Hiramatsu Cc: Adrian Hunter Cc: Ian Rogers Cc: Jiri Olsa Cc: Namhyung Kim Link: https://lore.kernel.org/lkml/ Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/probe-event.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 2a0ad9ecf0a2..5c12459e9765 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include -- cgit v1.2.3-59-g8ed1b From 4376424acd154c455b92695c6e85504601509919 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Wed, 20 Mar 2024 23:00:05 -0700 Subject: perf vendor events intel: Update cascadelakex to 1.21 Update events from 1.20 to 1.21 as released in: https://github.com/intel/perfmon/commit/fcfdba3be8f3be81ad6b509fdebf953ead92dc2c Largely fixes spelling and descriptions. Reviewed-by: Kan Liang Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Caleb Biggers Cc: Edward Baker Cc: Ingo Molnar Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Perry Taylor Cc: Peter Zijlstra Cc: Samantha Alt Cc: Weilin Wang Link: https://lore.kernel.org/r/20240321060016.1464787-2-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/pmu-events/arch/x86/cascadelakex/frontend.json | 10 +++++----- tools/perf/pmu-events/arch/x86/cascadelakex/memory.json | 2 +- tools/perf/pmu-events/arch/x86/cascadelakex/other.json | 2 +- tools/perf/pmu-events/arch/x86/cascadelakex/pipeline.json | 2 +- .../arch/x86/cascadelakex/uncore-interconnect.json | 14 +++++++------- .../pmu-events/arch/x86/cascadelakex/virtual-memory.json | 2 +- tools/perf/pmu-events/arch/x86/mapfile.csv | 2 +- 7 files changed, 17 insertions(+), 17 deletions(-) diff --git a/tools/perf/pmu-events/arch/x86/cascadelakex/frontend.json b/tools/perf/pmu-events/arch/x86/cascadelakex/frontend.json index 095904c77001..d6f543471b24 100644 --- a/tools/perf/pmu-events/arch/x86/cascadelakex/frontend.json +++ b/tools/perf/pmu-events/arch/x86/cascadelakex/frontend.json @@ -19,7 +19,7 @@ "BriefDescription": "Decode Stream Buffer (DSB)-to-MITE switches", "EventCode": "0xAB", "EventName": "DSB2MITE_SWITCHES.COUNT", - "PublicDescription": "This event counts the number of the Decode Stream Buffer (DSB)-to-MITE switches including all misses because of missing Decode Stream Buffer (DSB) cache and u-arch forced misses.\nNote: Invoking MITE requires two or three cycles delay.", + "PublicDescription": "This event counts the number of the Decode Stream Buffer (DSB)-to-MITE switches including all misses because of missing Decode Stream Buffer (DSB) cache and u-arch forced misses. Note: Invoking MITE requires two or three cycles delay.", "SampleAfterValue": "2000003", "UMask": "0x1" }, @@ -267,11 +267,11 @@ "UMask": "0x4" }, { - "BriefDescription": "Cycles Decode Stream Buffer (DSB) is delivering 4 Uops [This event is alias to IDQ.DSB_CYCLES_OK]", + "BriefDescription": "Cycles Decode Stream Buffer (DSB) is delivering 4 or more Uops [This event is alias to IDQ.DSB_CYCLES_OK]", "CounterMask": "4", "EventCode": "0x79", "EventName": "IDQ.ALL_DSB_CYCLES_4_UOPS", - "PublicDescription": "Counts the number of cycles 4 uops were delivered to Instruction Decode Queue (IDQ) from the Decode Stream Buffer (DSB) path. Count includes uops that may 'bypass' the IDQ. [This event is alias to IDQ.DSB_CYCLES_OK]", + "PublicDescription": "Counts the number of cycles 4 or more uops were delivered to Instruction Decode Queue (IDQ) from the Decode Stream Buffer (DSB) path. Count includes uops that may 'bypass' the IDQ. [This event is alias to IDQ.DSB_CYCLES_OK]", "SampleAfterValue": "2000003", "UMask": "0x18" }, @@ -321,11 +321,11 @@ "UMask": "0x18" }, { - "BriefDescription": "Cycles Decode Stream Buffer (DSB) is delivering 4 Uops [This event is alias to IDQ.ALL_DSB_CYCLES_4_UOPS]", + "BriefDescription": "Cycles Decode Stream Buffer (DSB) is delivering 4 or more Uops [This event is alias to IDQ.ALL_DSB_CYCLES_4_UOPS]", "CounterMask": "4", "EventCode": "0x79", "EventName": "IDQ.DSB_CYCLES_OK", - "PublicDescription": "Counts the number of cycles 4 uops were delivered to Instruction Decode Queue (IDQ) from the Decode Stream Buffer (DSB) path. Count includes uops that may 'bypass' the IDQ. [This event is alias to IDQ.ALL_DSB_CYCLES_4_UOPS]", + "PublicDescription": "Counts the number of cycles 4 or more uops were delivered to Instruction Decode Queue (IDQ) from the Decode Stream Buffer (DSB) path. Count includes uops that may 'bypass' the IDQ. [This event is alias to IDQ.ALL_DSB_CYCLES_4_UOPS]", "SampleAfterValue": "2000003", "UMask": "0x18" }, diff --git a/tools/perf/pmu-events/arch/x86/cascadelakex/memory.json b/tools/perf/pmu-events/arch/x86/cascadelakex/memory.json index a00ad0aaf1ba..c69b2c33334b 100644 --- a/tools/perf/pmu-events/arch/x86/cascadelakex/memory.json +++ b/tools/perf/pmu-events/arch/x86/cascadelakex/memory.json @@ -6866,7 +6866,7 @@ "BriefDescription": "Number of times an RTM execution aborted due to any reasons (multiple categories may count as one).", "EventCode": "0xC9", "EventName": "RTM_RETIRED.ABORTED", - "PEBS": "1", + "PEBS": "2", "PublicDescription": "Number of times RTM abort was triggered.", "SampleAfterValue": "2000003", "UMask": "0x4" diff --git a/tools/perf/pmu-events/arch/x86/cascadelakex/other.json b/tools/perf/pmu-events/arch/x86/cascadelakex/other.json index 3ab5e91a4c1c..95d42ac36717 100644 --- a/tools/perf/pmu-events/arch/x86/cascadelakex/other.json +++ b/tools/perf/pmu-events/arch/x86/cascadelakex/other.json @@ -19,7 +19,7 @@ "BriefDescription": "Core cycles where the core was running in a manner where Turbo may be clipped to the AVX512 turbo schedule.", "EventCode": "0x28", "EventName": "CORE_POWER.LVL2_TURBO_LICENSE", - "PublicDescription": "Core cycles where the core was running with power-delivery for license level 2 (introduced in Skylake Server michroarchtecture). This includes high current AVX 512-bit instructions.", + "PublicDescription": "Core cycles where the core was running with power-delivery for license level 2 (introduced in Skylake Server microarchitecture). This includes high current AVX 512-bit instructions.", "SampleAfterValue": "200003", "UMask": "0x20" }, diff --git a/tools/perf/pmu-events/arch/x86/cascadelakex/pipeline.json b/tools/perf/pmu-events/arch/x86/cascadelakex/pipeline.json index 66d686cc933e..c50ddf5b40dd 100644 --- a/tools/perf/pmu-events/arch/x86/cascadelakex/pipeline.json +++ b/tools/perf/pmu-events/arch/x86/cascadelakex/pipeline.json @@ -396,7 +396,7 @@ "Errata": "SKL091, SKL044", "EventCode": "0xC0", "EventName": "INST_RETIRED.NOP", - "PEBS": "1", + "PEBS": "2", "SampleAfterValue": "2000003", "UMask": "0x2" }, diff --git a/tools/perf/pmu-events/arch/x86/cascadelakex/uncore-interconnect.json b/tools/perf/pmu-events/arch/x86/cascadelakex/uncore-interconnect.json index 1a342dff1503..3fe9ce483bbe 100644 --- a/tools/perf/pmu-events/arch/x86/cascadelakex/uncore-interconnect.json +++ b/tools/perf/pmu-events/arch/x86/cascadelakex/uncore-interconnect.json @@ -38,7 +38,7 @@ "EventCode": "0x10", "EventName": "UNC_I_COHERENT_OPS.CLFLUSH", "PerPkg": "1", - "PublicDescription": "Counts the number of coherency related operations servied by the IRP", + "PublicDescription": "Counts the number of coherency related operations serviced by the IRP", "UMask": "0x80", "Unit": "IRP" }, @@ -47,7 +47,7 @@ "EventCode": "0x10", "EventName": "UNC_I_COHERENT_OPS.CRD", "PerPkg": "1", - "PublicDescription": "Counts the number of coherency related operations servied by the IRP", + "PublicDescription": "Counts the number of coherency related operations serviced by the IRP", "UMask": "0x2", "Unit": "IRP" }, @@ -56,7 +56,7 @@ "EventCode": "0x10", "EventName": "UNC_I_COHERENT_OPS.DRD", "PerPkg": "1", - "PublicDescription": "Counts the number of coherency related operations servied by the IRP", + "PublicDescription": "Counts the number of coherency related operations serviced by the IRP", "UMask": "0x4", "Unit": "IRP" }, @@ -65,7 +65,7 @@ "EventCode": "0x10", "EventName": "UNC_I_COHERENT_OPS.PCIDCAHINT", "PerPkg": "1", - "PublicDescription": "Counts the number of coherency related operations servied by the IRP", + "PublicDescription": "Counts the number of coherency related operations serviced by the IRP", "UMask": "0x20", "Unit": "IRP" }, @@ -74,7 +74,7 @@ "EventCode": "0x10", "EventName": "UNC_I_COHERENT_OPS.PCIRDCUR", "PerPkg": "1", - "PublicDescription": "Counts the number of coherency related operations servied by the IRP", + "PublicDescription": "Counts the number of coherency related operations serviced by the IRP", "UMask": "0x1", "Unit": "IRP" }, @@ -101,7 +101,7 @@ "EventCode": "0x10", "EventName": "UNC_I_COHERENT_OPS.WBMTOI", "PerPkg": "1", - "PublicDescription": "Counts the number of coherency related operations servied by the IRP", + "PublicDescription": "Counts the number of coherency related operations serviced by the IRP", "UMask": "0x40", "Unit": "IRP" }, @@ -500,7 +500,7 @@ "EventCode": "0x11", "EventName": "UNC_I_TRANSACTIONS.WRITES", "PerPkg": "1", - "PublicDescription": "Counts the number of Inbound transactions from the IRP to the Uncore. This can be filtered based on request type in addition to the source queue. Note the special filtering equation. We do OR-reduction on the request type. If the SOURCE bit is set, then we also do AND qualification based on the source portID.; Trackes only write requests. Each write request should have a prefetch, so there is no need to explicitly track these requests. For writes that are tickled and have to retry, the counter will be incremented for each retry.", + "PublicDescription": "Counts the number of Inbound transactions from the IRP to the Uncore. This can be filtered based on request type in addition to the source queue. Note the special filtering equation. We do OR-reduction on the request type. If the SOURCE bit is set, then we also do AND qualification based on the source portID.; Tracks only write requests. Each write request should have a prefetch, so there is no need to explicitly track these requests. For writes that are tickled and have to retry, the counter will be incremented for each retry.", "UMask": "0x2", "Unit": "IRP" }, diff --git a/tools/perf/pmu-events/arch/x86/cascadelakex/virtual-memory.json b/tools/perf/pmu-events/arch/x86/cascadelakex/virtual-memory.json index f59405877ae8..73feadaf7674 100644 --- a/tools/perf/pmu-events/arch/x86/cascadelakex/virtual-memory.json +++ b/tools/perf/pmu-events/arch/x86/cascadelakex/virtual-memory.json @@ -205,7 +205,7 @@ "BriefDescription": "Counts 1 per cycle for each PMH that is busy with a page walk for an instruction fetch request. EPT page walk duration are excluded in Skylake.", "EventCode": "0x85", "EventName": "ITLB_MISSES.WALK_PENDING", - "PublicDescription": "Counts 1 per cycle for each PMH (Page Miss Handler) that is busy with a page walk for an instruction fetch request. EPT page walk duration are excluded in Skylake michroarchitecture.", + "PublicDescription": "Counts 1 per cycle for each PMH (Page Miss Handler) that is busy with a page walk for an instruction fetch request. EPT page walk duration are excluded in Skylake microarchitecture.", "SampleAfterValue": "100003", "UMask": "0x10" }, diff --git a/tools/perf/pmu-events/arch/x86/mapfile.csv b/tools/perf/pmu-events/arch/x86/mapfile.csv index 5297d25f4e03..281419d2edeb 100644 --- a/tools/perf/pmu-events/arch/x86/mapfile.csv +++ b/tools/perf/pmu-events/arch/x86/mapfile.csv @@ -5,7 +5,7 @@ GenuineIntel-6-(1C|26|27|35|36),v5,bonnell,core GenuineIntel-6-(3D|47),v29,broadwell,core GenuineIntel-6-56,v11,broadwellde,core GenuineIntel-6-4F,v22,broadwellx,core -GenuineIntel-6-55-[56789ABCDEF],v1.20,cascadelakex,core +GenuineIntel-6-55-[56789ABCDEF],v1.21,cascadelakex,core GenuineIntel-6-9[6C],v1.04,elkhartlake,core GenuineIntel-6-CF,v1.03,emeraldrapids,core GenuineIntel-6-5[CF],v13,goldmont,core -- cgit v1.2.3-59-g8ed1b From 36f353a1ebf88280f58d1ebfe2731251d9159456 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Wed, 20 Mar 2024 23:00:06 -0700 Subject: perf vendor events intel: Update emeraldrapids to 1.06 Update events from 1.03 to 1.96 as released in: https://github.com/intel/perfmon/commit/21a8be3ea7918749141db4036fb65a2343cd865d Fixes spelling and descriptions. Adds cache miss latency events UNC_CHA_TOR_(INSERTS|OCCUPANCY).IO_(PCIRDCUR|ITOM|ITOMCACHENEAR)_(LOCAL|REMOTE). Reviewed-by: Kan Liang Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Caleb Biggers Cc: Edward Baker Cc: Ingo Molnar Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Perry Taylor Cc: Peter Zijlstra Cc: Samantha Alt Cc: Weilin Wang Link: https://lore.kernel.org/r/20240321060016.1464787-3-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- .../arch/x86/emeraldrapids/frontend.json | 2 +- .../pmu-events/arch/x86/emeraldrapids/memory.json | 1 + .../arch/x86/emeraldrapids/pipeline.json | 3 + .../arch/x86/emeraldrapids/uncore-cache.json | 112 ++++++++++++++++++++- .../x86/emeraldrapids/uncore-interconnect.json | 26 ++--- tools/perf/pmu-events/arch/x86/mapfile.csv | 2 +- 6 files changed, 129 insertions(+), 17 deletions(-) diff --git a/tools/perf/pmu-events/arch/x86/emeraldrapids/frontend.json b/tools/perf/pmu-events/arch/x86/emeraldrapids/frontend.json index 9e53da55d0c1..93d99318a623 100644 --- a/tools/perf/pmu-events/arch/x86/emeraldrapids/frontend.json +++ b/tools/perf/pmu-events/arch/x86/emeraldrapids/frontend.json @@ -267,7 +267,7 @@ "CounterMask": "6", "EventCode": "0x79", "EventName": "IDQ.DSB_CYCLES_OK", - "PublicDescription": "Counts the number of cycles where optimal number of uops was delivered to the Instruction Decode Queue (IDQ) from the MITE (legacy decode pipeline) path. During these cycles uops are not being delivered from the Decode Stream Buffer (DSB).", + "PublicDescription": "Counts the number of cycles where optimal number of uops was delivered to the Instruction Decode Queue (IDQ) from the DSB (Decode Stream Buffer) path. Count includes uops that may 'bypass' the IDQ.", "SampleAfterValue": "2000003", "UMask": "0x8" }, diff --git a/tools/perf/pmu-events/arch/x86/emeraldrapids/memory.json b/tools/perf/pmu-events/arch/x86/emeraldrapids/memory.json index e8bf7c9c44e1..5420f529f491 100644 --- a/tools/perf/pmu-events/arch/x86/emeraldrapids/memory.json +++ b/tools/perf/pmu-events/arch/x86/emeraldrapids/memory.json @@ -264,6 +264,7 @@ "BriefDescription": "Number of times an RTM execution aborted.", "EventCode": "0xc9", "EventName": "RTM_RETIRED.ABORTED", + "PEBS": "1", "PublicDescription": "Counts the number of times RTM abort was triggered.", "SampleAfterValue": "100003", "UMask": "0x4" diff --git a/tools/perf/pmu-events/arch/x86/emeraldrapids/pipeline.json b/tools/perf/pmu-events/arch/x86/emeraldrapids/pipeline.json index 1f8200fb8964..e2086bedeca8 100644 --- a/tools/perf/pmu-events/arch/x86/emeraldrapids/pipeline.json +++ b/tools/perf/pmu-events/arch/x86/emeraldrapids/pipeline.json @@ -428,6 +428,7 @@ "BriefDescription": "INST_RETIRED.MACRO_FUSED", "EventCode": "0xc0", "EventName": "INST_RETIRED.MACRO_FUSED", + "PEBS": "1", "SampleAfterValue": "2000003", "UMask": "0x10" }, @@ -435,6 +436,7 @@ "BriefDescription": "Retired NOP instructions.", "EventCode": "0xc0", "EventName": "INST_RETIRED.NOP", + "PEBS": "1", "PublicDescription": "Counts all retired NOP or ENDBR32/64 instructions", "SampleAfterValue": "2000003", "UMask": "0x2" @@ -451,6 +453,7 @@ "BriefDescription": "Iterations of Repeat string retired instructions.", "EventCode": "0xc0", "EventName": "INST_RETIRED.REP_ITERATION", + "PEBS": "1", "PublicDescription": "Number of iterations of Repeat (REP) string retired instructions such as MOVS, CMPS, and SCAS. Each has a byte, word, and doubleword version and string instructions can be repeated using a repetition prefix, REP, that allows their architectural execution to be repeated a number of times as specified by the RCX register. Note the number of iterations is implementation-dependent.", "SampleAfterValue": "2000003", "UMask": "0x8" diff --git a/tools/perf/pmu-events/arch/x86/emeraldrapids/uncore-cache.json b/tools/perf/pmu-events/arch/x86/emeraldrapids/uncore-cache.json index 86a8f3b7fe1d..141dab46682e 100644 --- a/tools/perf/pmu-events/arch/x86/emeraldrapids/uncore-cache.json +++ b/tools/perf/pmu-events/arch/x86/emeraldrapids/uncore-cache.json @@ -4197,6 +4197,42 @@ "UMask": "0xcd43ff04", "Unit": "CHA" }, + { + "BriefDescription": "ItoMCacheNear (partial write) transactions from an IO device that addresses memory on the local socket", + "EventCode": "0x35", + "EventName": "UNC_CHA_TOR_INSERTS.IO_ITOMCACHENEAR_LOCAL", + "PerPkg": "1", + "PublicDescription": "TOR Inserts : ItoMCacheNears, indicating a partial write request, from IO Devices that missed the LLC : Counts the number of entries successfully inserted into the TOR that match qualifications specified by the subevent. Does not include addressless requests such as locks and interrupts.", + "UMask": "0xcd42ff04", + "Unit": "CHA" + }, + { + "BriefDescription": "ItoMCacheNear (partial write) transactions from an IO device that addresses memory on a remote socket", + "EventCode": "0x35", + "EventName": "UNC_CHA_TOR_INSERTS.IO_ITOMCACHENEAR_REMOTE", + "PerPkg": "1", + "PublicDescription": "TOR Inserts : ItoMCacheNears, indicating a partial write request, from IO Devices that missed the LLC : Counts the number of entries successfully inserted into the TOR that match qualifications specified by the subevent. Does not include addressless requests such as locks and interrupts.", + "UMask": "0xcd437f04", + "Unit": "CHA" + }, + { + "BriefDescription": "ItoM (write) transactions from an IO device that addresses memory on the local socket", + "EventCode": "0x35", + "EventName": "UNC_CHA_TOR_INSERTS.IO_ITOM_LOCAL", + "PerPkg": "1", + "PublicDescription": "Counts the number of entries successfully inserted into the TOR that match qualifications specified by the subevent. Does not include addressless requests such as locks and interrupts.", + "UMask": "0xcc42ff04", + "Unit": "CHA" + }, + { + "BriefDescription": "ItoM (write) transactions from an IO device that addresses memory on a remote socket", + "EventCode": "0x35", + "EventName": "UNC_CHA_TOR_INSERTS.IO_ITOM_REMOTE", + "PerPkg": "1", + "PublicDescription": "Counts the number of entries successfully inserted into the TOR that match qualifications specified by the subevent. Does not include addressless requests such as locks and interrupts.", + "UMask": "0xcc437f04", + "Unit": "CHA" + }, { "BriefDescription": "TOR Inserts; Misses from local IO", "EventCode": "0x35", @@ -4207,7 +4243,7 @@ "Unit": "CHA" }, { - "BriefDescription": "TOR Inserts; ItoM misses from local IO", + "BriefDescription": "TOR Inserts : ItoM, indicating a full cacheline write request, from IO Devices that missed the LLC", "EventCode": "0x35", "EventName": "UNC_CHA_TOR_INSERTS.IO_MISS_ITOM", "PerPkg": "1", @@ -4225,7 +4261,7 @@ "Unit": "CHA" }, { - "BriefDescription": "TOR Inserts; RdCur and FsRdCur misses from local IO", + "BriefDescription": "TOR Inserts; RdCur and FsRdCur requests from local IO that miss LLC", "EventCode": "0x35", "EventName": "UNC_CHA_TOR_INSERTS.IO_MISS_PCIRDCUR", "PerPkg": "1", @@ -4251,6 +4287,24 @@ "UMask": "0xc8f3ff04", "Unit": "CHA" }, + { + "BriefDescription": "PCIRDCUR (read) transactions from an IO device that addresses memory on a remote socket", + "EventCode": "0x35", + "EventName": "UNC_CHA_TOR_INSERTS.IO_PCIRDCUR_LOCAL", + "PerPkg": "1", + "PublicDescription": "Counts the number of entries successfully inserted into the TOR that match qualifications specified by the subevent. Does not include addressless requests such as locks and interrupts.", + "UMask": "0xc8f2ff04", + "Unit": "CHA" + }, + { + "BriefDescription": "PCIRDCUR (read) transactions from an IO device that addresses memory on the local socket", + "EventCode": "0x35", + "EventName": "UNC_CHA_TOR_INSERTS.IO_PCIRDCUR_REMOTE", + "PerPkg": "1", + "PublicDescription": "Counts the number of entries successfully inserted into the TOR that match qualifications specified by the subevent. Does not include addressless requests such as locks and interrupts.", + "UMask": "0xc8f37f04", + "Unit": "CHA" + }, { "BriefDescription": "TOR Inserts; RFO from local IO", "EventCode": "0x35", @@ -5713,6 +5767,42 @@ "UMask": "0xcd43fe04", "Unit": "CHA" }, + { + "BriefDescription": "TOR Occupancy : ItoMCacheNears, indicating a partial write request, from IO Devices that missed the LLC and targets local memory", + "EventCode": "0x36", + "EventName": "UNC_CHA_TOR_OCCUPANCY.IO_MISS_ITOMCACHENEAR_LOCAL", + "PerPkg": "1", + "PublicDescription": "For each cycle, this event accumulates the number of valid entries in the TOR that match qualifications specified by the subevent. Does not include addressless requests such as locks and interrupts.", + "UMask": "0xcd42fe04", + "Unit": "CHA" + }, + { + "BriefDescription": "TOR Occupancy : ItoMCacheNears, indicating a partial write request, from IO Devices that missed the LLC and targets remote memory", + "EventCode": "0x36", + "EventName": "UNC_CHA_TOR_OCCUPANCY.IO_MISS_ITOMCACHENEAR_REMOTE", + "PerPkg": "1", + "PublicDescription": "For each cycle, this event accumulates the number of valid entries in the TOR that match qualifications specified by the subevent. Does not include addressless requests such as locks and interrupts.", + "UMask": "0xcd437e04", + "Unit": "CHA" + }, + { + "BriefDescription": "TOR Occupancy; ITOM misses from local IO and targets local memory", + "EventCode": "0x36", + "EventName": "UNC_CHA_TOR_OCCUPANCY.IO_MISS_ITOM_LOCAL", + "PerPkg": "1", + "PublicDescription": "For each cycle, this event accumulates the number of valid entries in the TOR that match qualifications specified by the subevent. Does not include addressless requests such as locks and interrupts.", + "UMask": "0xcc42fe04", + "Unit": "CHA" + }, + { + "BriefDescription": "TOR Occupancy; ITOM misses from local IO and targets remote memory", + "EventCode": "0x36", + "EventName": "UNC_CHA_TOR_OCCUPANCY.IO_MISS_ITOM_REMOTE", + "PerPkg": "1", + "PublicDescription": "For each cycle, this event accumulates the number of valid entries in the TOR that match qualifications specified by the subevent. Does not include addressless requests such as locks and interrupts.", + "UMask": "0xcc437e04", + "Unit": "CHA" + }, { "BriefDescription": "TOR Occupancy; RdCur and FsRdCur misses from local IO", "EventCode": "0x36", @@ -5722,6 +5812,24 @@ "UMask": "0xc8f3fe04", "Unit": "CHA" }, + { + "BriefDescription": "TOR Occupancy; RdCur and FsRdCur misses from local IO and targets local memory", + "EventCode": "0x36", + "EventName": "UNC_CHA_TOR_OCCUPANCY.IO_MISS_PCIRDCUR_LOCAL", + "PerPkg": "1", + "PublicDescription": "For each cycle, this event accumulates the number of valid entries in the TOR that match qualifications specified by the subevent. Does not include addressless requests such as locks and interrupts.", + "UMask": "0xc8f2fe04", + "Unit": "CHA" + }, + { + "BriefDescription": "TOR Occupancy; RdCur and FsRdCur misses from local IO and targets remote memory", + "EventCode": "0x36", + "EventName": "UNC_CHA_TOR_OCCUPANCY.IO_MISS_PCIRDCUR_REMOTE", + "PerPkg": "1", + "PublicDescription": "For each cycle, this event accumulates the number of valid entries in the TOR that match qualifications specified by the subevent. Does not include addressless requests such as locks and interrupts.", + "UMask": "0xc8f37e04", + "Unit": "CHA" + }, { "BriefDescription": "TOR Occupancy; RFO misses from local IO", "EventCode": "0x36", diff --git a/tools/perf/pmu-events/arch/x86/emeraldrapids/uncore-interconnect.json b/tools/perf/pmu-events/arch/x86/emeraldrapids/uncore-interconnect.json index 65d088556bae..22bb490e9666 100644 --- a/tools/perf/pmu-events/arch/x86/emeraldrapids/uncore-interconnect.json +++ b/tools/perf/pmu-events/arch/x86/emeraldrapids/uncore-interconnect.json @@ -4888,7 +4888,7 @@ "Unit": "MDF" }, { - "BriefDescription": "Number of cycles incoming messages from the vertical ring that are bounced at the SBO\r\nIngress (V-EMIB) (AD)", + "BriefDescription": "Number of cycles incoming messages from the vertical ring that are bounced at the SBO Ingress (V-EMIB) (AD)", "EventCode": "0x4B", "EventName": "UNC_MDF_CRS_TxR_V_BOUNCES.AD", "PerPkg": "1", @@ -4897,7 +4897,7 @@ "Unit": "MDF" }, { - "BriefDescription": "Number of cycles incoming messages from the vertical ring that are bounced at the SBO\r\nIngress (V-EMIB) (AK)", + "BriefDescription": "Number of cycles incoming messages from the vertical ring that are bounced at the SBO Ingress (V-EMIB) (AK)", "EventCode": "0x4B", "EventName": "UNC_MDF_CRS_TxR_V_BOUNCES.AK", "PerPkg": "1", @@ -4906,7 +4906,7 @@ "Unit": "MDF" }, { - "BriefDescription": "Number of cycles incoming messages from the vertical ring that are bounced at the SBO\r\nIngress (V-EMIB) (AKC)", + "BriefDescription": "Number of cycles incoming messages from the vertical ring that are bounced at the SBO Ingress (V-EMIB) (AKC)", "EventCode": "0x4B", "EventName": "UNC_MDF_CRS_TxR_V_BOUNCES.AKC", "PerPkg": "1", @@ -4915,7 +4915,7 @@ "Unit": "MDF" }, { - "BriefDescription": "Number of cycles incoming messages from the vertical ring that are bounced at the SBO\r\nIngress (V-EMIB) (BL)", + "BriefDescription": "Number of cycles incoming messages from the vertical ring that are bounced at the SBO Ingress (V-EMIB) (BL)", "EventCode": "0x4B", "EventName": "UNC_MDF_CRS_TxR_V_BOUNCES.BL", "PerPkg": "1", @@ -4924,7 +4924,7 @@ "Unit": "MDF" }, { - "BriefDescription": "Number of cycles incoming messages from the vertical ring that are bounced at the SBO\r\nIngress (V-EMIB) (IV)", + "BriefDescription": "Number of cycles incoming messages from the vertical ring that are bounced at the SBO Ingress (V-EMIB) (IV)", "EventCode": "0x4B", "EventName": "UNC_MDF_CRS_TxR_V_BOUNCES.IV", "PerPkg": "1", @@ -5291,7 +5291,7 @@ "EventCode": "0x05", "EventName": "UNC_UPI_RxL_BASIC_HDR_MATCH.NCB", "PerPkg": "1", - "PublicDescription": "Matches on Receive path of a UPI Port : Non-Coherent Bypass : Matches on Receive path of a UPI port.\r\nMatch based on UMask specific bits:\r\nZ: Message Class (3-bit)\r\nY: Message Class Enable\r\nW: Opcode (4-bit)\r\nV: Opcode Enable\r\nU: Local Enable\r\nT: Remote Enable\r\nS: Data Hdr Enable\r\nR: Non-Data Hdr Enable\r\nQ: Dual Slot Hdr Enable\r\nP: Single Slot Hdr Enable\r\nLink Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases.\r\nNote: If Message Class is disabled, we expect opcode to also be disabled.", + "PublicDescription": "Matches on Receive path of a UPI Port : Non-Coherent Bypass : Matches on Receive path of a UPI port. Match based on UMask specific bits: Z: Message Class (3-bit) Y: Message Class Enable W: Opcode (4-bit) V: Opcode Enable U: Local Enable T: Remote Enable S: Data Hdr Enable R: Non-Data Hdr Enable Q: Dual Slot Hdr Enable P: Single Slot Hdr Enable Link Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases. Note: If Message Class is disabled, we expect opcode to also be disabled.", "UMask": "0xe", "Unit": "UPI" }, @@ -5300,7 +5300,7 @@ "EventCode": "0x05", "EventName": "UNC_UPI_RxL_BASIC_HDR_MATCH.NCB_OPC", "PerPkg": "1", - "PublicDescription": "Matches on Receive path of a UPI Port : Non-Coherent Bypass, Match Opcode : Matches on Receive path of a UPI port.\r\nMatch based on UMask specific bits:\r\nZ: Message Class (3-bit)\r\nY: Message Class Enable\r\nW: Opcode (4-bit)\r\nV: Opcode Enable\r\nU: Local Enable\r\nT: Remote Enable\r\nS: Data Hdr Enable\r\nR: Non-Data Hdr Enable\r\nQ: Dual Slot Hdr Enable\r\nP: Single Slot Hdr Enable\r\nLink Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases.\r\nNote: If Message Class is disabled, we expect opcode to also be disabled.", + "PublicDescription": "Matches on Receive path of a UPI Port : Non-Coherent Bypass, Match Opcode : Matches on Receive path of a UPI port. Match based on UMask specific bits: Z: Message Class (3-bit) Y: Message Class Enable W: Opcode (4-bit) V: Opcode Enable U: Local Enable T: Remote Enable S: Data Hdr Enable R: Non-Data Hdr Enable Q: Dual Slot Hdr Enable P: Single Slot Hdr Enable Link Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases. Note: If Message Class is disabled, we expect opcode to also be disabled.", "UMask": "0x10e", "Unit": "UPI" }, @@ -5309,7 +5309,7 @@ "EventCode": "0x05", "EventName": "UNC_UPI_RxL_BASIC_HDR_MATCH.NCS", "PerPkg": "1", - "PublicDescription": "Matches on Receive path of a UPI Port : Non-Coherent Standard : Matches on Receive path of a UPI port.\r\nMatch based on UMask specific bits:\r\nZ: Message Class (3-bit)\r\nY: Message Class Enable\r\nW: Opcode (4-bit)\r\nV: Opcode Enable\r\nU: Local Enable\r\nT: Remote Enable\r\nS: Data Hdr Enable\r\nR: Non-Data Hdr Enable\r\nQ: Dual Slot Hdr Enable\r\nP: Single Slot Hdr Enable\r\nLink Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases.\r\nNote: If Message Class is disabled, we expect opcode to also be disabled.", + "PublicDescription": "Matches on Receive path of a UPI Port : Non-Coherent Standard : Matches on Receive path of a UPI port. Match based on UMask specific bits: Z: Message Class (3-bit) Y: Message Class Enable W: Opcode (4-bit) V: Opcode Enable U: Local Enable T: Remote Enable S: Data Hdr Enable R: Non-Data Hdr Enable Q: Dual Slot Hdr Enable P: Single Slot Hdr Enable Link Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases. Note: If Message Class is disabled, we expect opcode to also be disabled.", "UMask": "0xf", "Unit": "UPI" }, @@ -5318,7 +5318,7 @@ "EventCode": "0x05", "EventName": "UNC_UPI_RxL_BASIC_HDR_MATCH.NCS_OPC", "PerPkg": "1", - "PublicDescription": "Matches on Receive path of a UPI Port : Non-Coherent Standard, Match Opcode : Matches on Receive path of a UPI port.\r\nMatch based on UMask specific bits:\r\nZ: Message Class (3-bit)\r\nY: Message Class Enable\r\nW: Opcode (4-bit)\r\nV: Opcode Enable\r\nU: Local Enable\r\nT: Remote Enable\r\nS: Data Hdr Enable\r\nR: Non-Data Hdr Enable\r\nQ: Dual Slot Hdr Enable\r\nP: Single Slot Hdr Enable\r\nLink Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases.\r\nNote: If Message Class is disabled, we expect opcode to also be disabled.", + "PublicDescription": "Matches on Receive path of a UPI Port : Non-Coherent Standard, Match Opcode : Matches on Receive path of a UPI port. Match based on UMask specific bits: Z: Message Class (3-bit) Y: Message Class Enable W: Opcode (4-bit) V: Opcode Enable U: Local Enable T: Remote Enable S: Data Hdr Enable R: Non-Data Hdr Enable Q: Dual Slot Hdr Enable P: Single Slot Hdr Enable Link Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases. Note: If Message Class is disabled, we expect opcode to also be disabled.", "UMask": "0x10f", "Unit": "UPI" }, @@ -5763,7 +5763,7 @@ "EventCode": "0x04", "EventName": "UNC_UPI_TxL_BASIC_HDR_MATCH.NCB", "PerPkg": "1", - "PublicDescription": "Matches on Transmit path of a UPI Port : Non-Coherent Bypass : Matches on Transmit path of a UPI port.\r\nMatch based on UMask specific bits:\r\nZ: Message Class (3-bit)\r\nY: Message Class Enable\r\nW: Opcode (4-bit)\r\nV: Opcode Enable\r\nU: Local Enable\r\nT: Remote Enable\r\nS: Data Hdr Enable\r\nR: Non-Data Hdr Enable\r\nQ: Dual Slot Hdr Enable\r\nP: Single Slot Hdr Enable\r\nLink Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases.\r\nNote: If Message Class is disabled, we expect opcode to also be disabled.", + "PublicDescription": "Matches on Transmit path of a UPI Port : Non-Coherent Bypass : Matches on Transmit path of a UPI port. Match based on UMask specific bits: Z: Message Class (3-bit) Y: Message Class Enable W: Opcode (4-bit) V: Opcode Enable U: Local Enable T: Remote Enable S: Data Hdr Enable R: Non-Data Hdr Enable Q: Dual Slot Hdr Enable P: Single Slot Hdr Enable Link Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases. Note: If Message Class is disabled, we expect opcode to also be disabled.", "UMask": "0xe", "Unit": "UPI" }, @@ -5772,7 +5772,7 @@ "EventCode": "0x04", "EventName": "UNC_UPI_TxL_BASIC_HDR_MATCH.NCB_OPC", "PerPkg": "1", - "PublicDescription": "Matches on Transmit path of a UPI Port : Non-Coherent Bypass, Match Opcode : Matches on Transmit path of a UPI port.\r\nMatch based on UMask specific bits:\r\nZ: Message Class (3-bit)\r\nY: Message Class Enable\r\nW: Opcode (4-bit)\r\nV: Opcode Enable\r\nU: Local Enable\r\nT: Remote Enable\r\nS: Data Hdr Enable\r\nR: Non-Data Hdr Enable\r\nQ: Dual Slot Hdr Enable\r\nP: Single Slot Hdr Enable\r\nLink Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases.\r\nNote: If Message Class is disabled, we expect opcode to also be disabled.", + "PublicDescription": "Matches on Transmit path of a UPI Port : Non-Coherent Bypass, Match Opcode : Matches on Transmit path of a UPI port. Match based on UMask specific bits: Z: Message Class (3-bit) Y: Message Class Enable W: Opcode (4-bit) V: Opcode Enable U: Local Enable T: Remote Enable S: Data Hdr Enable R: Non-Data Hdr Enable Q: Dual Slot Hdr Enable P: Single Slot Hdr Enable Link Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases. Note: If Message Class is disabled, we expect opcode to also be disabled.", "UMask": "0x10e", "Unit": "UPI" }, @@ -5781,7 +5781,7 @@ "EventCode": "0x04", "EventName": "UNC_UPI_TxL_BASIC_HDR_MATCH.NCS", "PerPkg": "1", - "PublicDescription": "Matches on Transmit path of a UPI Port : Non-Coherent Standard : Matches on Transmit path of a UPI port.\r\nMatch based on UMask specific bits:\r\nZ: Message Class (3-bit)\r\nY: Message Class Enable\r\nW: Opcode (4-bit)\r\nV: Opcode Enable\r\nU: Local Enable\r\nT: Remote Enable\r\nS: Data Hdr Enable\r\nR: Non-Data Hdr Enable\r\nQ: Dual Slot Hdr Enable\r\nP: Single Slot Hdr Enable\r\nLink Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases.\r\nNote: If Message Class is disabled, we expect opcode to also be disabled.", + "PublicDescription": "Matches on Transmit path of a UPI Port : Non-Coherent Standard : Matches on Transmit path of a UPI port. Match based on UMask specific bits: Z: Message Class (3-bit) Y: Message Class Enable W: Opcode (4-bit) V: Opcode Enable U: Local Enable T: Remote Enable S: Data Hdr Enable R: Non-Data Hdr Enable Q: Dual Slot Hdr Enable P: Single Slot Hdr Enable Link Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases. Note: If Message Class is disabled, we expect opcode to also be disabled.", "UMask": "0xf", "Unit": "UPI" }, @@ -5790,7 +5790,7 @@ "EventCode": "0x04", "EventName": "UNC_UPI_TxL_BASIC_HDR_MATCH.NCS_OPC", "PerPkg": "1", - "PublicDescription": "Matches on Transmit path of a UPI Port : Non-Coherent Standard, Match Opcode : Matches on Transmit path of a UPI port.\r\nMatch based on UMask specific bits:\r\nZ: Message Class (3-bit)\r\nY: Message Class Enable\r\nW: Opcode (4-bit)\r\nV: Opcode Enable\r\nU: Local Enable\r\nT: Remote Enable\r\nS: Data Hdr Enable\r\nR: Non-Data Hdr Enable\r\nQ: Dual Slot Hdr Enable\r\nP: Single Slot Hdr Enable\r\nLink Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases.\r\nNote: If Message Class is disabled, we expect opcode to also be disabled.", + "PublicDescription": "Matches on Transmit path of a UPI Port : Non-Coherent Standard, Match Opcode : Matches on Transmit path of a UPI port. Match based on UMask specific bits: Z: Message Class (3-bit) Y: Message Class Enable W: Opcode (4-bit) V: Opcode Enable U: Local Enable T: Remote Enable S: Data Hdr Enable R: Non-Data Hdr Enable Q: Dual Slot Hdr Enable P: Single Slot Hdr Enable Link Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases. Note: If Message Class is disabled, we expect opcode to also be disabled.", "UMask": "0x10f", "Unit": "UPI" }, diff --git a/tools/perf/pmu-events/arch/x86/mapfile.csv b/tools/perf/pmu-events/arch/x86/mapfile.csv index 281419d2edeb..85b89b1098cf 100644 --- a/tools/perf/pmu-events/arch/x86/mapfile.csv +++ b/tools/perf/pmu-events/arch/x86/mapfile.csv @@ -7,7 +7,7 @@ GenuineIntel-6-56,v11,broadwellde,core GenuineIntel-6-4F,v22,broadwellx,core GenuineIntel-6-55-[56789ABCDEF],v1.21,cascadelakex,core GenuineIntel-6-9[6C],v1.04,elkhartlake,core -GenuineIntel-6-CF,v1.03,emeraldrapids,core +GenuineIntel-6-CF,v1.06,emeraldrapids,core GenuineIntel-6-5[CF],v13,goldmont,core GenuineIntel-6-7A,v1.01,goldmontplus,core GenuineIntel-6-B6,v1.01,grandridge,core -- cgit v1.2.3-59-g8ed1b From a02dc01cef3717720edb97c4ce9bc8f86ee67a83 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Wed, 20 Mar 2024 23:00:07 -0700 Subject: perf vendor events intel: Update grandridge to 1.02 Update events from 1.01 to 1.02 as released in: https://github.com/intel/perfmon/commit/b2a81e803add1ba0af68a442c975683d226d868c Fixes spelling and descriptions. Adds topdown events and uncore cache UNC_CHA_TOR_OCCUPANCY.IA_HIT_DRD_OPT, UNC_CHA_TOR_OCCUPANCY.IA_MISS_DRD_OPT, UNC_CHA_TOR_OCCUPANCY.IA_DRD_OPT. Reviewed-by: Kan Liang Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Caleb Biggers Cc: Edward Baker Cc: Ingo Molnar Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Perry Taylor Cc: Peter Zijlstra Cc: Samantha Alt Cc: Weilin Wang Link: https://lore.kernel.org/r/20240321060016.1464787-4-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- .../pmu-events/arch/x86/grandridge/pipeline.json | 43 +++++++++++++++++++--- .../arch/x86/grandridge/uncore-cache.json | 28 +++++++++++++- tools/perf/pmu-events/arch/x86/mapfile.csv | 2 +- 3 files changed, 66 insertions(+), 7 deletions(-) diff --git a/tools/perf/pmu-events/arch/x86/grandridge/pipeline.json b/tools/perf/pmu-events/arch/x86/grandridge/pipeline.json index daa0639bb1ca..90292dc03d33 100644 --- a/tools/perf/pmu-events/arch/x86/grandridge/pipeline.json +++ b/tools/perf/pmu-events/arch/x86/grandridge/pipeline.json @@ -249,10 +249,17 @@ "UMask": "0x1" }, { - "BriefDescription": "Counts the number of issue slots that were not consumed by the backend because allocation is stalled due to a mispredicted jump or a machine clear.", + "BriefDescription": "Counts the number of issue slots that were not consumed by the backend because allocation is stalled due to a mispredicted jump or a machine clear. [This event is alias to TOPDOWN_BAD_SPECULATION.ALL_P]", "EventCode": "0x73", "EventName": "TOPDOWN_BAD_SPECULATION.ALL", - "PublicDescription": "Counts the total number of issue slots that were not consumed by the backend because allocation is stalled due to a mispredicted jump or a machine clear. Only issue slots wasted due to fast nukes such as memory ordering nukes are counted. Other nukes are not accounted for. Counts all issue slots blocked during this recovery window, including relevant microcode flows, and while uops are not yet available in the instruction queue (IQ) or until an FE_BOUND event occurs besides OTHER and CISC. Also includes the issue slots that were consumed by the backend but were thrown away because they were younger than the mispredict or machine clear.", + "PublicDescription": "Counts the total number of issue slots that were not consumed by the backend because allocation is stalled due to a mispredicted jump or a machine clear. Only issue slots wasted due to fast nukes such as memory ordering nukes are counted. Other nukes are not accounted for. Counts all issue slots blocked during this recovery window, including relevant microcode flows, and while uops are not yet available in the instruction queue (IQ) or until an FE_BOUND event occurs besides OTHER and CISC. Also includes the issue slots that were consumed by the backend but were thrown away because they were younger than the mispredict or machine clear. [This event is alias to TOPDOWN_BAD_SPECULATION.ALL_P]", + "SampleAfterValue": "1000003" + }, + { + "BriefDescription": "Counts the number of issue slots that were not consumed by the backend because allocation is stalled due to a mispredicted jump or a machine clear. [This event is alias to TOPDOWN_BAD_SPECULATION.ALL]", + "EventCode": "0x73", + "EventName": "TOPDOWN_BAD_SPECULATION.ALL_P", + "PublicDescription": "Counts the total number of issue slots that were not consumed by the backend because allocation is stalled due to a mispredicted jump or a machine clear. Only issue slots wasted due to fast nukes such as memory ordering nukes are counted. Other nukes are not accounted for. Counts all issue slots blocked during this recovery window, including relevant microcode flows, and while uops are not yet available in the instruction queue (IQ) or until an FE_BOUND event occurs besides OTHER and CISC. Also includes the issue slots that were consumed by the backend but were thrown away because they were younger than the mispredict or machine clear. [This event is alias to TOPDOWN_BAD_SPECULATION.ALL]", "SampleAfterValue": "1000003" }, { @@ -284,7 +291,7 @@ "UMask": "0x1" }, { - "BriefDescription": "Counts the number of retirement slots not consumed due to backend stalls", + "BriefDescription": "Counts the number of retirement slots not consumed due to backend stalls [This event is alias to TOPDOWN_BE_BOUND.ALL_P]", "EventCode": "0x74", "EventName": "TOPDOWN_BE_BOUND.ALL", "SampleAfterValue": "1000003" @@ -296,6 +303,12 @@ "SampleAfterValue": "1000003", "UMask": "0x1" }, + { + "BriefDescription": "Counts the number of retirement slots not consumed due to backend stalls [This event is alias to TOPDOWN_BE_BOUND.ALL]", + "EventCode": "0x74", + "EventName": "TOPDOWN_BE_BOUND.ALL_P", + "SampleAfterValue": "1000003" + }, { "BriefDescription": "Counts the number of issue slots every cycle that were not consumed by the backend due to memory reservation stall (scheduler not being able to accept another uop). This could be caused by RSV full or load/store buffer block.", "EventCode": "0x74", @@ -317,6 +330,13 @@ "SampleAfterValue": "1000003", "UMask": "0x20" }, + { + "BriefDescription": "Counts the number of issue slots every cycle that were not consumed by the backend due to ROB full", + "EventCode": "0x74", + "EventName": "TOPDOWN_BE_BOUND.REORDER_BUFFER", + "SampleAfterValue": "1000003", + "UMask": "0x40" + }, { "BriefDescription": "Counts the number of issue slots every cycle that were not consumed by the backend due to iq/jeu scoreboards or ms scb", "EventCode": "0x74", @@ -325,11 +345,17 @@ "UMask": "0x10" }, { - "BriefDescription": "Counts the number of retirement slots not consumed due to front end stalls", + "BriefDescription": "Counts the number of retirement slots not consumed due to front end stalls [This event is alias to TOPDOWN_FE_BOUND.ALL_P]", "EventCode": "0x71", "EventName": "TOPDOWN_FE_BOUND.ALL", "SampleAfterValue": "1000003" }, + { + "BriefDescription": "Counts the number of retirement slots not consumed due to front end stalls [This event is alias to TOPDOWN_FE_BOUND.ALL]", + "EventCode": "0x71", + "EventName": "TOPDOWN_FE_BOUND.ALL_P", + "SampleAfterValue": "1000003" + }, { "BriefDescription": "Counts the number of issue slots every cycle that were not delivered by the frontend due to BAClear", "EventCode": "0x71", @@ -402,12 +428,19 @@ "UMask": "0x4" }, { - "BriefDescription": "Counts the number of consumed retirement slots. Similar to UOPS_RETIRED.ALL", + "BriefDescription": "Counts the number of consumed retirement slots. Similar to UOPS_RETIRED.ALL [This event is alias to TOPDOWN_RETIRING.ALL_P]", "EventCode": "0x72", "EventName": "TOPDOWN_RETIRING.ALL", "PEBS": "1", "SampleAfterValue": "1000003" }, + { + "BriefDescription": "Counts the number of consumed retirement slots. Similar to UOPS_RETIRED.ALL [This event is alias to TOPDOWN_RETIRING.ALL]", + "EventCode": "0x72", + "EventName": "TOPDOWN_RETIRING.ALL_P", + "PEBS": "1", + "SampleAfterValue": "1000003" + }, { "BriefDescription": "Counts the number of uops issued by the front end every cycle.", "EventCode": "0x0e", diff --git a/tools/perf/pmu-events/arch/x86/grandridge/uncore-cache.json b/tools/perf/pmu-events/arch/x86/grandridge/uncore-cache.json index 74dfd9272cef..36614429dd72 100644 --- a/tools/perf/pmu-events/arch/x86/grandridge/uncore-cache.json +++ b/tools/perf/pmu-events/arch/x86/grandridge/uncore-cache.json @@ -5,7 +5,6 @@ "EventName": "UNC_CHACMS_CLOCKTICKS", "PerPkg": "1", "PortMask": "0x000", - "PublicDescription": "UNC_CHACMS_CLOCKTICKS", "Unit": "CHACMS" }, { @@ -1216,6 +1215,15 @@ "UMask": "0xc88fff01", "Unit": "CHA" }, + { + "BriefDescription": "TOR Occupancy for Data read opt from local IA that miss the cache", + "EventCode": "0x36", + "EventName": "UNC_CHA_TOR_OCCUPANCY.IA_DRD_OPT", + "PerPkg": "1", + "PublicDescription": "TOR Occupancy : DRd_Opts issued by iA Cores", + "UMask": "0xc827ff01", + "Unit": "CHA" + }, { "BriefDescription": "TOR Occupancy for Data read opt prefetch from local IA that miss the cache", "EventCode": "0x36", @@ -1252,6 +1260,15 @@ "UMask": "0xc88ffd01", "Unit": "CHA" }, + { + "BriefDescription": "TOR Occupancy for Data read opt from local IA that hit the cache", + "EventCode": "0x36", + "EventName": "UNC_CHA_TOR_OCCUPANCY.IA_HIT_DRD_OPT", + "PerPkg": "1", + "PublicDescription": "TOR Occupancy : DRd_Opts issued by iA Cores that hit the LLC", + "UMask": "0xc827fd01", + "Unit": "CHA" + }, { "BriefDescription": "TOR Occupancy for Data read opt prefetch from local IA that hit the cache", "EventCode": "0x36", @@ -1405,6 +1422,15 @@ "UMask": "0xc88efe01", "Unit": "CHA" }, + { + "BriefDescription": "TOR Occupancy for Data read opt from local IA that miss the cache", + "EventCode": "0x36", + "EventName": "UNC_CHA_TOR_OCCUPANCY.IA_MISS_DRD_OPT", + "PerPkg": "1", + "PublicDescription": "TOR Occupancy : DRd_Opt issued by iA Cores that missed the LLC", + "UMask": "0xc827fe01", + "Unit": "CHA" + }, { "BriefDescription": "TOR Occupancy for Data read opt prefetch from local IA that miss the cache", "EventCode": "0x36", diff --git a/tools/perf/pmu-events/arch/x86/mapfile.csv b/tools/perf/pmu-events/arch/x86/mapfile.csv index 85b89b1098cf..650c28574576 100644 --- a/tools/perf/pmu-events/arch/x86/mapfile.csv +++ b/tools/perf/pmu-events/arch/x86/mapfile.csv @@ -10,7 +10,7 @@ GenuineIntel-6-9[6C],v1.04,elkhartlake,core GenuineIntel-6-CF,v1.06,emeraldrapids,core GenuineIntel-6-5[CF],v13,goldmont,core GenuineIntel-6-7A,v1.01,goldmontplus,core -GenuineIntel-6-B6,v1.01,grandridge,core +GenuineIntel-6-B6,v1.02,grandridge,core GenuineIntel-6-A[DE],v1.01,graniterapids,core GenuineIntel-6-(3C|45|46),v35,haswell,core GenuineIntel-6-3F,v28,haswellx,core -- cgit v1.2.3-59-g8ed1b From 5157c2042eec305929d26acfaea1c237561d3d63 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Wed, 20 Mar 2024 23:00:08 -0700 Subject: perf vendor events intel: Update icelakex to 1.24 Update events from 1.23 to 1.24 as released in: https://github.com/intel/perfmon/commit/d883888ae60882028e387b6fe1ebf683beb693fa Fixes spelling and descriptions. Adds the uncore events UNC_CHA_TOR_INSERTS.IO_PCIRDCUR_LOCAL and UNC_CHA_TOR_INSERTS.IO_PCIRDCUR_REMOTE, while removing UNC_IIO_NUM_REQ_FROM_CPU.IRP. Reviewed-by: Kan Liang Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Caleb Biggers Cc: Edward Baker Cc: Ingo Molnar Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Perry Taylor Cc: Peter Zijlstra Cc: Samantha Alt Cc: Weilin Wang Link: https://lore.kernel.org/r/20240321060016.1464787-5-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- .../pmu-events/arch/x86/icelakex/frontend.json | 2 +- .../perf/pmu-events/arch/x86/icelakex/memory.json | 1 + .../pmu-events/arch/x86/icelakex/uncore-cache.json | 22 +++++++- .../arch/x86/icelakex/uncore-interconnect.json | 64 +++++++++++----------- .../pmu-events/arch/x86/icelakex/uncore-io.json | 11 ---- tools/perf/pmu-events/arch/x86/mapfile.csv | 2 +- 6 files changed, 55 insertions(+), 47 deletions(-) diff --git a/tools/perf/pmu-events/arch/x86/icelakex/frontend.json b/tools/perf/pmu-events/arch/x86/icelakex/frontend.json index f6edc4222f42..66669d062e68 100644 --- a/tools/perf/pmu-events/arch/x86/icelakex/frontend.json +++ b/tools/perf/pmu-events/arch/x86/icelakex/frontend.json @@ -282,7 +282,7 @@ "CounterMask": "5", "EventCode": "0x79", "EventName": "IDQ.DSB_CYCLES_OK", - "PublicDescription": "Counts the number of cycles where optimal number of uops was delivered to the Instruction Decode Queue (IDQ) from the MITE (legacy decode pipeline) path. During these cycles uops are not being delivered from the Decode Stream Buffer (DSB).", + "PublicDescription": "Counts the number of cycles where optimal number of uops was delivered to the Instruction Decode Queue (IDQ) from the DSB (Decode Stream Buffer) path. Count includes uops that may 'bypass' the IDQ.", "SampleAfterValue": "2000003", "UMask": "0x8" }, diff --git a/tools/perf/pmu-events/arch/x86/icelakex/memory.json b/tools/perf/pmu-events/arch/x86/icelakex/memory.json index f36ac04f8d76..875b584b8443 100644 --- a/tools/perf/pmu-events/arch/x86/icelakex/memory.json +++ b/tools/perf/pmu-events/arch/x86/icelakex/memory.json @@ -319,6 +319,7 @@ "BriefDescription": "Number of times an RTM execution aborted.", "EventCode": "0xc9", "EventName": "RTM_RETIRED.ABORTED", + "PEBS": "1", "PublicDescription": "Counts the number of times RTM abort was triggered.", "SampleAfterValue": "100003", "UMask": "0x4" diff --git a/tools/perf/pmu-events/arch/x86/icelakex/uncore-cache.json b/tools/perf/pmu-events/arch/x86/icelakex/uncore-cache.json index b6ce14ebf844..a950ba3ddcb4 100644 --- a/tools/perf/pmu-events/arch/x86/icelakex/uncore-cache.json +++ b/tools/perf/pmu-events/arch/x86/icelakex/uncore-cache.json @@ -1580,7 +1580,7 @@ "Unit": "CHA" }, { - "BriefDescription": "This event is deprecated. Refer to new event UNC_CHA_LLC_LOOKUP.CODE_READ", + "BriefDescription": "This event is deprecated.", "Deprecated": "1", "EventCode": "0x34", "EventName": "UNC_CHA_LLC_LOOKUP.CODE", @@ -1677,7 +1677,7 @@ "Unit": "CHA" }, { - "BriefDescription": "This event is deprecated. Refer to new event UNC_CHA_LLC_LOOKUP.DATA_READ", + "BriefDescription": "This event is deprecated.", "Deprecated": "1", "EventCode": "0x34", "EventName": "UNC_CHA_LLC_LOOKUP.DATA_READ_ALL", @@ -6782,6 +6782,24 @@ "UMask": "0xc8f3ff04", "Unit": "CHA" }, + { + "BriefDescription": "PCIRDCUR (read) transactions from an IO device that addresses memory on the local socket", + "EventCode": "0x35", + "EventName": "UNC_CHA_TOR_INSERTS.IO_PCIRDCUR_LOCAL", + "PerPkg": "1", + "PublicDescription": "TOR Inserts : PCIRdCurs issued by IO Devices and targets local memory : Counts the number of entries successfully inserted into the TOR that match qualifications specified by the subevent. Does not include addressless requests such as locks and interrupts.", + "UMask": "0xc8f2ff04", + "Unit": "CHA" + }, + { + "BriefDescription": "PCIRDCUR (read) transactions from an IO device that addresses memory on a remote socket", + "EventCode": "0x35", + "EventName": "UNC_CHA_TOR_INSERTS.IO_PCIRDCUR_REMOTE", + "PerPkg": "1", + "PublicDescription": "TOR Inserts : PCIRdCurs issued by IO Devices and targets remote memory : Counts the number of entries successfully inserted into the TOR that match qualifications specified by the subevent. Does not include addressless requests such as locks and interrupts.", + "UMask": "0xc8f37f04", + "Unit": "CHA" + }, { "BriefDescription": "TOR Inserts : RFOs issued by IO Devices", "EventCode": "0x35", diff --git a/tools/perf/pmu-events/arch/x86/icelakex/uncore-interconnect.json b/tools/perf/pmu-events/arch/x86/icelakex/uncore-interconnect.json index a066a009c511..6997e6f7d366 100644 --- a/tools/perf/pmu-events/arch/x86/icelakex/uncore-interconnect.json +++ b/tools/perf/pmu-events/arch/x86/icelakex/uncore-interconnect.json @@ -13523,7 +13523,7 @@ "EventCode": "0x05", "EventName": "UNC_UPI_RxL_BASIC_HDR_MATCH.NCB", "PerPkg": "1", - "PublicDescription": "Matches on Receive path of a UPI Port : Non-Coherent Bypass : Matches on Receive path of a UPI port.\r\nMatch based on UMask specific bits:\r\nZ: Message Class (3-bit)\r\nY: Message Class Enable\r\nW: Opcode (4-bit)\r\nV: Opcode Enable\r\nU: Local Enable\r\nT: Remote Enable\r\nS: Data Hdr Enable\r\nR: Non-Data Hdr Enable\r\nQ: Dual Slot Hdr Enable\r\nP: Single Slot Hdr Enable\r\nLink Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases.\r\nNote: If Message Class is disabled, we expect opcode to also be disabled.", + "PublicDescription": "Matches on Receive path of a UPI Port : Non-Coherent Bypass : Matches on Receive path of a UPI port. Match based on UMask specific bits: Z: Message Class (3-bit) Y: Message Class Enable W: Opcode (4-bit) V: Opcode Enable U: Local Enable T: Remote Enable S: Data Hdr Enable R: Non-Data Hdr Enable Q: Dual Slot Hdr Enable P: Single Slot Hdr Enable Link Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases. Note: If Message Class is disabled, we expect opcode to also be disabled.", "UMask": "0xe", "Unit": "UPI" }, @@ -13532,7 +13532,7 @@ "EventCode": "0x05", "EventName": "UNC_UPI_RxL_BASIC_HDR_MATCH.NCB_OPC", "PerPkg": "1", - "PublicDescription": "Matches on Receive path of a UPI Port : Non-Coherent Bypass, Match Opcode : Matches on Receive path of a UPI port.\r\nMatch based on UMask specific bits:\r\nZ: Message Class (3-bit)\r\nY: Message Class Enable\r\nW: Opcode (4-bit)\r\nV: Opcode Enable\r\nU: Local Enable\r\nT: Remote Enable\r\nS: Data Hdr Enable\r\nR: Non-Data Hdr Enable\r\nQ: Dual Slot Hdr Enable\r\nP: Single Slot Hdr Enable\r\nLink Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases.\r\nNote: If Message Class is disabled, we expect opcode to also be disabled.", + "PublicDescription": "Matches on Receive path of a UPI Port : Non-Coherent Bypass, Match Opcode : Matches on Receive path of a UPI port. Match based on UMask specific bits: Z: Message Class (3-bit) Y: Message Class Enable W: Opcode (4-bit) V: Opcode Enable U: Local Enable T: Remote Enable S: Data Hdr Enable R: Non-Data Hdr Enable Q: Dual Slot Hdr Enable P: Single Slot Hdr Enable Link Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases. Note: If Message Class is disabled, we expect opcode to also be disabled.", "UMask": "0x10e", "Unit": "UPI" }, @@ -13541,7 +13541,7 @@ "EventCode": "0x05", "EventName": "UNC_UPI_RxL_BASIC_HDR_MATCH.NCS", "PerPkg": "1", - "PublicDescription": "Matches on Receive path of a UPI Port : Non-Coherent Standard : Matches on Receive path of a UPI port.\r\nMatch based on UMask specific bits:\r\nZ: Message Class (3-bit)\r\nY: Message Class Enable\r\nW: Opcode (4-bit)\r\nV: Opcode Enable\r\nU: Local Enable\r\nT: Remote Enable\r\nS: Data Hdr Enable\r\nR: Non-Data Hdr Enable\r\nQ: Dual Slot Hdr Enable\r\nP: Single Slot Hdr Enable\r\nLink Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases.\r\nNote: If Message Class is disabled, we expect opcode to also be disabled.", + "PublicDescription": "Matches on Receive path of a UPI Port : Non-Coherent Standard : Matches on Receive path of a UPI port. Match based on UMask specific bits: Z: Message Class (3-bit) Y: Message Class Enable W: Opcode (4-bit) V: Opcode Enable U: Local Enable T: Remote Enable S: Data Hdr Enable R: Non-Data Hdr Enable Q: Dual Slot Hdr Enable P: Single Slot Hdr Enable Link Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases. Note: If Message Class is disabled, we expect opcode to also be disabled.", "UMask": "0xf", "Unit": "UPI" }, @@ -13550,7 +13550,7 @@ "EventCode": "0x05", "EventName": "UNC_UPI_RxL_BASIC_HDR_MATCH.NCS_OPC", "PerPkg": "1", - "PublicDescription": "Matches on Receive path of a UPI Port : Non-Coherent Standard, Match Opcode : Matches on Receive path of a UPI port.\r\nMatch based on UMask specific bits:\r\nZ: Message Class (3-bit)\r\nY: Message Class Enable\r\nW: Opcode (4-bit)\r\nV: Opcode Enable\r\nU: Local Enable\r\nT: Remote Enable\r\nS: Data Hdr Enable\r\nR: Non-Data Hdr Enable\r\nQ: Dual Slot Hdr Enable\r\nP: Single Slot Hdr Enable\r\nLink Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases.\r\nNote: If Message Class is disabled, we expect opcode to also be disabled.", + "PublicDescription": "Matches on Receive path of a UPI Port : Non-Coherent Standard, Match Opcode : Matches on Receive path of a UPI port. Match based on UMask specific bits: Z: Message Class (3-bit) Y: Message Class Enable W: Opcode (4-bit) V: Opcode Enable U: Local Enable T: Remote Enable S: Data Hdr Enable R: Non-Data Hdr Enable Q: Dual Slot Hdr Enable P: Single Slot Hdr Enable Link Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases. Note: If Message Class is disabled, we expect opcode to also be disabled.", "UMask": "0x10f", "Unit": "UPI" }, @@ -13559,7 +13559,7 @@ "EventCode": "0x05", "EventName": "UNC_UPI_RxL_BASIC_HDR_MATCH.REQ", "PerPkg": "1", - "PublicDescription": "Matches on Receive path of a UPI Port : Request : Matches on Receive path of a UPI port.\r\nMatch based on UMask specific bits:\r\nZ: Message Class (3-bit)\r\nY: Message Class Enable\r\nW: Opcode (4-bit)\r\nV: Opcode Enable\r\nU: Local Enable\r\nT: Remote Enable\r\nS: Data Hdr Enable\r\nR: Non-Data Hdr Enable\r\nQ: Dual Slot Hdr Enable\r\nP: Single Slot Hdr Enable\r\nLink Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases.\r\nNote: If Message Class is disabled, we expect opcode to also be disabled.", + "PublicDescription": "Matches on Receive path of a UPI Port : Request : Matches on Receive path of a UPI port. Match based on UMask specific bits: Z: Message Class (3-bit) Y: Message Class Enable W: Opcode (4-bit) V: Opcode Enable U: Local Enable T: Remote Enable S: Data Hdr Enable R: Non-Data Hdr Enable Q: Dual Slot Hdr Enable P: Single Slot Hdr Enable Link Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases. Note: If Message Class is disabled, we expect opcode to also be disabled.", "UMask": "0x8", "Unit": "UPI" }, @@ -13568,7 +13568,7 @@ "EventCode": "0x05", "EventName": "UNC_UPI_RxL_BASIC_HDR_MATCH.REQ_OPC", "PerPkg": "1", - "PublicDescription": "Matches on Receive path of a UPI Port : Request, Match Opcode : Matches on Receive path of a UPI port.\r\nMatch based on UMask specific bits:\r\nZ: Message Class (3-bit)\r\nY: Message Class Enable\r\nW: Opcode (4-bit)\r\nV: Opcode Enable\r\nU: Local Enable\r\nT: Remote Enable\r\nS: Data Hdr Enable\r\nR: Non-Data Hdr Enable\r\nQ: Dual Slot Hdr Enable\r\nP: Single Slot Hdr Enable\r\nLink Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases.\r\nNote: If Message Class is disabled, we expect opcode to also be disabled.", + "PublicDescription": "Matches on Receive path of a UPI Port : Request, Match Opcode : Matches on Receive path of a UPI port. Match based on UMask specific bits: Z: Message Class (3-bit) Y: Message Class Enable W: Opcode (4-bit) V: Opcode Enable U: Local Enable T: Remote Enable S: Data Hdr Enable R: Non-Data Hdr Enable Q: Dual Slot Hdr Enable P: Single Slot Hdr Enable Link Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases. Note: If Message Class is disabled, we expect opcode to also be disabled.", "UMask": "0x108", "Unit": "UPI" }, @@ -13577,7 +13577,7 @@ "EventCode": "0x05", "EventName": "UNC_UPI_RxL_BASIC_HDR_MATCH.RSPCNFLT", "PerPkg": "1", - "PublicDescription": "Matches on Receive path of a UPI Port : Response - Conflict : Matches on Receive path of a UPI port.\r\nMatch based on UMask specific bits:\r\nZ: Message Class (3-bit)\r\nY: Message Class Enable\r\nW: Opcode (4-bit)\r\nV: Opcode Enable\r\nU: Local Enable\r\nT: Remote Enable\r\nS: Data Hdr Enable\r\nR: Non-Data Hdr Enable\r\nQ: Dual Slot Hdr Enable\r\nP: Single Slot Hdr Enable\r\nLink Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases.\r\nNote: If Message Class is disabled, we expect opcode to also be disabled.", + "PublicDescription": "Matches on Receive path of a UPI Port : Response - Conflict : Matches on Receive path of a UPI port. Match based on UMask specific bits: Z: Message Class (3-bit) Y: Message Class Enable W: Opcode (4-bit) V: Opcode Enable U: Local Enable T: Remote Enable S: Data Hdr Enable R: Non-Data Hdr Enable Q: Dual Slot Hdr Enable P: Single Slot Hdr Enable Link Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases. Note: If Message Class is disabled, we expect opcode to also be disabled.", "UMask": "0x1aa", "Unit": "UPI" }, @@ -13586,7 +13586,7 @@ "EventCode": "0x05", "EventName": "UNC_UPI_RxL_BASIC_HDR_MATCH.RSPI", "PerPkg": "1", - "PublicDescription": "Matches on Receive path of a UPI Port : Response - Invalid : Matches on Receive path of a UPI port.\r\nMatch based on UMask specific bits:\r\nZ: Message Class (3-bit)\r\nY: Message Class Enable\r\nW: Opcode (4-bit)\r\nV: Opcode Enable\r\nU: Local Enable\r\nT: Remote Enable\r\nS: Data Hdr Enable\r\nR: Non-Data Hdr Enable\r\nQ: Dual Slot Hdr Enable\r\nP: Single Slot Hdr Enable\r\nLink Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases.\r\nNote: If Message Class is disabled, we expect opcode to also be disabled.", + "PublicDescription": "Matches on Receive path of a UPI Port : Response - Invalid : Matches on Receive path of a UPI port. Match based on UMask specific bits: Z: Message Class (3-bit) Y: Message Class Enable W: Opcode (4-bit) V: Opcode Enable U: Local Enable T: Remote Enable S: Data Hdr Enable R: Non-Data Hdr Enable Q: Dual Slot Hdr Enable P: Single Slot Hdr Enable Link Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases. Note: If Message Class is disabled, we expect opcode to also be disabled.", "UMask": "0x12a", "Unit": "UPI" }, @@ -13595,7 +13595,7 @@ "EventCode": "0x05", "EventName": "UNC_UPI_RxL_BASIC_HDR_MATCH.RSP_DATA", "PerPkg": "1", - "PublicDescription": "Matches on Receive path of a UPI Port : Response - Data : Matches on Receive path of a UPI port.\r\nMatch based on UMask specific bits:\r\nZ: Message Class (3-bit)\r\nY: Message Class Enable\r\nW: Opcode (4-bit)\r\nV: Opcode Enable\r\nU: Local Enable\r\nT: Remote Enable\r\nS: Data Hdr Enable\r\nR: Non-Data Hdr Enable\r\nQ: Dual Slot Hdr Enable\r\nP: Single Slot Hdr Enable\r\nLink Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases.\r\nNote: If Message Class is disabled, we expect opcode to also be disabled.", + "PublicDescription": "Matches on Receive path of a UPI Port : Response - Data : Matches on Receive path of a UPI port. Match based on UMask specific bits: Z: Message Class (3-bit) Y: Message Class Enable W: Opcode (4-bit) V: Opcode Enable U: Local Enable T: Remote Enable S: Data Hdr Enable R: Non-Data Hdr Enable Q: Dual Slot Hdr Enable P: Single Slot Hdr Enable Link Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases. Note: If Message Class is disabled, we expect opcode to also be disabled.", "UMask": "0xc", "Unit": "UPI" }, @@ -13604,7 +13604,7 @@ "EventCode": "0x05", "EventName": "UNC_UPI_RxL_BASIC_HDR_MATCH.RSP_DATA_OPC", "PerPkg": "1", - "PublicDescription": "Matches on Receive path of a UPI Port : Response - Data, Match Opcode : Matches on Receive path of a UPI port.\r\nMatch based on UMask specific bits:\r\nZ: Message Class (3-bit)\r\nY: Message Class Enable\r\nW: Opcode (4-bit)\r\nV: Opcode Enable\r\nU: Local Enable\r\nT: Remote Enable\r\nS: Data Hdr Enable\r\nR: Non-Data Hdr Enable\r\nQ: Dual Slot Hdr Enable\r\nP: Single Slot Hdr Enable\r\nLink Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases.\r\nNote: If Message Class is disabled, we expect opcode to also be disabled.", + "PublicDescription": "Matches on Receive path of a UPI Port : Response - Data, Match Opcode : Matches on Receive path of a UPI port. Match based on UMask specific bits: Z: Message Class (3-bit) Y: Message Class Enable W: Opcode (4-bit) V: Opcode Enable U: Local Enable T: Remote Enable S: Data Hdr Enable R: Non-Data Hdr Enable Q: Dual Slot Hdr Enable P: Single Slot Hdr Enable Link Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases. Note: If Message Class is disabled, we expect opcode to also be disabled.", "UMask": "0x10c", "Unit": "UPI" }, @@ -13613,7 +13613,7 @@ "EventCode": "0x05", "EventName": "UNC_UPI_RxL_BASIC_HDR_MATCH.RSP_NODATA", "PerPkg": "1", - "PublicDescription": "Matches on Receive path of a UPI Port : Response - No Data : Matches on Receive path of a UPI port.\r\nMatch based on UMask specific bits:\r\nZ: Message Class (3-bit)\r\nY: Message Class Enable\r\nW: Opcode (4-bit)\r\nV: Opcode Enable\r\nU: Local Enable\r\nT: Remote Enable\r\nS: Data Hdr Enable\r\nR: Non-Data Hdr Enable\r\nQ: Dual Slot Hdr Enable\r\nP: Single Slot Hdr Enable\r\nLink Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases.\r\nNote: If Message Class is disabled, we expect opcode to also be disabled.", + "PublicDescription": "Matches on Receive path of a UPI Port : Response - No Data : Matches on Receive path of a UPI port. Match based on UMask specific bits: Z: Message Class (3-bit) Y: Message Class Enable W: Opcode (4-bit) V: Opcode Enable U: Local Enable T: Remote Enable S: Data Hdr Enable R: Non-Data Hdr Enable Q: Dual Slot Hdr Enable P: Single Slot Hdr Enable Link Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases. Note: If Message Class is disabled, we expect opcode to also be disabled.", "UMask": "0xa", "Unit": "UPI" }, @@ -13622,7 +13622,7 @@ "EventCode": "0x05", "EventName": "UNC_UPI_RxL_BASIC_HDR_MATCH.RSP_NODATA_OPC", "PerPkg": "1", - "PublicDescription": "Matches on Receive path of a UPI Port : Response - No Data, Match Opcode : Matches on Receive path of a UPI port.\r\nMatch based on UMask specific bits:\r\nZ: Message Class (3-bit)\r\nY: Message Class Enable\r\nW: Opcode (4-bit)\r\nV: Opcode Enable\r\nU: Local Enable\r\nT: Remote Enable\r\nS: Data Hdr Enable\r\nR: Non-Data Hdr Enable\r\nQ: Dual Slot Hdr Enable\r\nP: Single Slot Hdr Enable\r\nLink Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases.\r\nNote: If Message Class is disabled, we expect opcode to also be disabled.", + "PublicDescription": "Matches on Receive path of a UPI Port : Response - No Data, Match Opcode : Matches on Receive path of a UPI port. Match based on UMask specific bits: Z: Message Class (3-bit) Y: Message Class Enable W: Opcode (4-bit) V: Opcode Enable U: Local Enable T: Remote Enable S: Data Hdr Enable R: Non-Data Hdr Enable Q: Dual Slot Hdr Enable P: Single Slot Hdr Enable Link Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases. Note: If Message Class is disabled, we expect opcode to also be disabled.", "UMask": "0x10a", "Unit": "UPI" }, @@ -13631,7 +13631,7 @@ "EventCode": "0x05", "EventName": "UNC_UPI_RxL_BASIC_HDR_MATCH.SNP", "PerPkg": "1", - "PublicDescription": "Matches on Receive path of a UPI Port : Snoop : Matches on Receive path of a UPI port.\r\nMatch based on UMask specific bits:\r\nZ: Message Class (3-bit)\r\nY: Message Class Enable\r\nW: Opcode (4-bit)\r\nV: Opcode Enable\r\nU: Local Enable\r\nT: Remote Enable\r\nS: Data Hdr Enable\r\nR: Non-Data Hdr Enable\r\nQ: Dual Slot Hdr Enable\r\nP: Single Slot Hdr Enable\r\nLink Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases.\r\nNote: If Message Class is disabled, we expect opcode to also be disabled.", + "PublicDescription": "Matches on Receive path of a UPI Port : Snoop : Matches on Receive path of a UPI port. Match based on UMask specific bits: Z: Message Class (3-bit) Y: Message Class Enable W: Opcode (4-bit) V: Opcode Enable U: Local Enable T: Remote Enable S: Data Hdr Enable R: Non-Data Hdr Enable Q: Dual Slot Hdr Enable P: Single Slot Hdr Enable Link Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases. Note: If Message Class is disabled, we expect opcode to also be disabled.", "UMask": "0x9", "Unit": "UPI" }, @@ -13640,7 +13640,7 @@ "EventCode": "0x05", "EventName": "UNC_UPI_RxL_BASIC_HDR_MATCH.SNP_OPC", "PerPkg": "1", - "PublicDescription": "Matches on Receive path of a UPI Port : Snoop, Match Opcode : Matches on Receive path of a UPI port.\r\nMatch based on UMask specific bits:\r\nZ: Message Class (3-bit)\r\nY: Message Class Enable\r\nW: Opcode (4-bit)\r\nV: Opcode Enable\r\nU: Local Enable\r\nT: Remote Enable\r\nS: Data Hdr Enable\r\nR: Non-Data Hdr Enable\r\nQ: Dual Slot Hdr Enable\r\nP: Single Slot Hdr Enable\r\nLink Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases.\r\nNote: If Message Class is disabled, we expect opcode to also be disabled.", + "PublicDescription": "Matches on Receive path of a UPI Port : Snoop, Match Opcode : Matches on Receive path of a UPI port. Match based on UMask specific bits: Z: Message Class (3-bit) Y: Message Class Enable W: Opcode (4-bit) V: Opcode Enable U: Local Enable T: Remote Enable S: Data Hdr Enable R: Non-Data Hdr Enable Q: Dual Slot Hdr Enable P: Single Slot Hdr Enable Link Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases. Note: If Message Class is disabled, we expect opcode to also be disabled.", "UMask": "0x109", "Unit": "UPI" }, @@ -13649,7 +13649,7 @@ "EventCode": "0x05", "EventName": "UNC_UPI_RxL_BASIC_HDR_MATCH.WB", "PerPkg": "1", - "PublicDescription": "Matches on Receive path of a UPI Port : Writeback : Matches on Receive path of a UPI port.\r\nMatch based on UMask specific bits:\r\nZ: Message Class (3-bit)\r\nY: Message Class Enable\r\nW: Opcode (4-bit)\r\nV: Opcode Enable\r\nU: Local Enable\r\nT: Remote Enable\r\nS: Data Hdr Enable\r\nR: Non-Data Hdr Enable\r\nQ: Dual Slot Hdr Enable\r\nP: Single Slot Hdr Enable\r\nLink Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases.\r\nNote: If Message Class is disabled, we expect opcode to also be disabled.", + "PublicDescription": "Matches on Receive path of a UPI Port : Writeback : Matches on Receive path of a UPI port. Match based on UMask specific bits: Z: Message Class (3-bit) Y: Message Class Enable W: Opcode (4-bit) V: Opcode Enable U: Local Enable T: Remote Enable S: Data Hdr Enable R: Non-Data Hdr Enable Q: Dual Slot Hdr Enable P: Single Slot Hdr Enable Link Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases. Note: If Message Class is disabled, we expect opcode to also be disabled.", "UMask": "0xd", "Unit": "UPI" }, @@ -13658,7 +13658,7 @@ "EventCode": "0x05", "EventName": "UNC_UPI_RxL_BASIC_HDR_MATCH.WB_OPC", "PerPkg": "1", - "PublicDescription": "Matches on Receive path of a UPI Port : Writeback, Match Opcode : Matches on Receive path of a UPI port.\r\nMatch based on UMask specific bits:\r\nZ: Message Class (3-bit)\r\nY: Message Class Enable\r\nW: Opcode (4-bit)\r\nV: Opcode Enable\r\nU: Local Enable\r\nT: Remote Enable\r\nS: Data Hdr Enable\r\nR: Non-Data Hdr Enable\r\nQ: Dual Slot Hdr Enable\r\nP: Single Slot Hdr Enable\r\nLink Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases.\r\nNote: If Message Class is disabled, we expect opcode to also be disabled.", + "PublicDescription": "Matches on Receive path of a UPI Port : Writeback, Match Opcode : Matches on Receive path of a UPI port. Match based on UMask specific bits: Z: Message Class (3-bit) Y: Message Class Enable W: Opcode (4-bit) V: Opcode Enable U: Local Enable T: Remote Enable S: Data Hdr Enable R: Non-Data Hdr Enable Q: Dual Slot Hdr Enable P: Single Slot Hdr Enable Link Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases. Note: If Message Class is disabled, we expect opcode to also be disabled.", "UMask": "0x10d", "Unit": "UPI" }, @@ -14038,7 +14038,7 @@ "EventCode": "0x04", "EventName": "UNC_UPI_TxL_BASIC_HDR_MATCH.NCB", "PerPkg": "1", - "PublicDescription": "Matches on Transmit path of a UPI Port : Non-Coherent Bypass : Matches on Transmit path of a UPI port.\r\nMatch based on UMask specific bits:\r\nZ: Message Class (3-bit)\r\nY: Message Class Enable\r\nW: Opcode (4-bit)\r\nV: Opcode Enable\r\nU: Local Enable\r\nT: Remote Enable\r\nS: Data Hdr Enable\r\nR: Non-Data Hdr Enable\r\nQ: Dual Slot Hdr Enable\r\nP: Single Slot Hdr Enable\r\nLink Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases.\r\nNote: If Message Class is disabled, we expect opcode to also be disabled.", + "PublicDescription": "Matches on Transmit path of a UPI Port : Non-Coherent Bypass : Matches on Transmit path of a UPI port. Match based on UMask specific bits: Z: Message Class (3-bit) Y: Message Class Enable W: Opcode (4-bit) V: Opcode Enable U: Local Enable T: Remote Enable S: Data Hdr Enable R: Non-Data Hdr Enable Q: Dual Slot Hdr Enable P: Single Slot Hdr Enable Link Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases. Note: If Message Class is disabled, we expect opcode to also be disabled.", "UMask": "0xe", "Unit": "UPI" }, @@ -14047,7 +14047,7 @@ "EventCode": "0x04", "EventName": "UNC_UPI_TxL_BASIC_HDR_MATCH.NCB_OPC", "PerPkg": "1", - "PublicDescription": "Matches on Transmit path of a UPI Port : Non-Coherent Bypass, Match Opcode : Matches on Transmit path of a UPI port.\r\nMatch based on UMask specific bits:\r\nZ: Message Class (3-bit)\r\nY: Message Class Enable\r\nW: Opcode (4-bit)\r\nV: Opcode Enable\r\nU: Local Enable\r\nT: Remote Enable\r\nS: Data Hdr Enable\r\nR: Non-Data Hdr Enable\r\nQ: Dual Slot Hdr Enable\r\nP: Single Slot Hdr Enable\r\nLink Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases.\r\nNote: If Message Class is disabled, we expect opcode to also be disabled.", + "PublicDescription": "Matches on Transmit path of a UPI Port : Non-Coherent Bypass, Match Opcode : Matches on Transmit path of a UPI port. Match based on UMask specific bits: Z: Message Class (3-bit) Y: Message Class Enable W: Opcode (4-bit) V: Opcode Enable U: Local Enable T: Remote Enable S: Data Hdr Enable R: Non-Data Hdr Enable Q: Dual Slot Hdr Enable P: Single Slot Hdr Enable Link Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases. Note: If Message Class is disabled, we expect opcode to also be disabled.", "UMask": "0x10e", "Unit": "UPI" }, @@ -14056,7 +14056,7 @@ "EventCode": "0x04", "EventName": "UNC_UPI_TxL_BASIC_HDR_MATCH.NCS", "PerPkg": "1", - "PublicDescription": "Matches on Transmit path of a UPI Port : Non-Coherent Standard : Matches on Transmit path of a UPI port.\r\nMatch based on UMask specific bits:\r\nZ: Message Class (3-bit)\r\nY: Message Class Enable\r\nW: Opcode (4-bit)\r\nV: Opcode Enable\r\nU: Local Enable\r\nT: Remote Enable\r\nS: Data Hdr Enable\r\nR: Non-Data Hdr Enable\r\nQ: Dual Slot Hdr Enable\r\nP: Single Slot Hdr Enable\r\nLink Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases.\r\nNote: If Message Class is disabled, we expect opcode to also be disabled.", + "PublicDescription": "Matches on Transmit path of a UPI Port : Non-Coherent Standard : Matches on Transmit path of a UPI port. Match based on UMask specific bits: Z: Message Class (3-bit) Y: Message Class Enable W: Opcode (4-bit) V: Opcode Enable U: Local Enable T: Remote Enable S: Data Hdr Enable R: Non-Data Hdr Enable Q: Dual Slot Hdr Enable P: Single Slot Hdr Enable Link Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases. Note: If Message Class is disabled, we expect opcode to also be disabled.", "UMask": "0xf", "Unit": "UPI" }, @@ -14065,7 +14065,7 @@ "EventCode": "0x04", "EventName": "UNC_UPI_TxL_BASIC_HDR_MATCH.NCS_OPC", "PerPkg": "1", - "PublicDescription": "Matches on Transmit path of a UPI Port : Non-Coherent Standard, Match Opcode : Matches on Transmit path of a UPI port.\r\nMatch based on UMask specific bits:\r\nZ: Message Class (3-bit)\r\nY: Message Class Enable\r\nW: Opcode (4-bit)\r\nV: Opcode Enable\r\nU: Local Enable\r\nT: Remote Enable\r\nS: Data Hdr Enable\r\nR: Non-Data Hdr Enable\r\nQ: Dual Slot Hdr Enable\r\nP: Single Slot Hdr Enable\r\nLink Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases.\r\nNote: If Message Class is disabled, we expect opcode to also be disabled.", + "PublicDescription": "Matches on Transmit path of a UPI Port : Non-Coherent Standard, Match Opcode : Matches on Transmit path of a UPI port. Match based on UMask specific bits: Z: Message Class (3-bit) Y: Message Class Enable W: Opcode (4-bit) V: Opcode Enable U: Local Enable T: Remote Enable S: Data Hdr Enable R: Non-Data Hdr Enable Q: Dual Slot Hdr Enable P: Single Slot Hdr Enable Link Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases. Note: If Message Class is disabled, we expect opcode to also be disabled.", "UMask": "0x10f", "Unit": "UPI" }, @@ -14074,7 +14074,7 @@ "EventCode": "0x04", "EventName": "UNC_UPI_TxL_BASIC_HDR_MATCH.REQ", "PerPkg": "1", - "PublicDescription": "Matches on Transmit path of a UPI Port : Request : Matches on Transmit path of a UPI port.\r\nMatch based on UMask specific bits:\r\nZ: Message Class (3-bit)\r\nY: Message Class Enable\r\nW: Opcode (4-bit)\r\nV: Opcode Enable\r\nU: Local Enable\r\nT: Remote Enable\r\nS: Data Hdr Enable\r\nR: Non-Data Hdr Enable\r\nQ: Dual Slot Hdr Enable\r\nP: Single Slot Hdr Enable\r\nLink Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases.\r\nNote: If Message Class is disabled, we expect opcode to also be disabled.", + "PublicDescription": "Matches on Transmit path of a UPI Port : Request : Matches on Transmit path of a UPI port. Match based on UMask specific bits: Z: Message Class (3-bit) Y: Message Class Enable W: Opcode (4-bit) V: Opcode Enable U: Local Enable T: Remote Enable S: Data Hdr Enable R: Non-Data Hdr Enable Q: Dual Slot Hdr Enable P: Single Slot Hdr Enable Link Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases. Note: If Message Class is disabled, we expect opcode to also be disabled.", "UMask": "0x8", "Unit": "UPI" }, @@ -14083,7 +14083,7 @@ "EventCode": "0x04", "EventName": "UNC_UPI_TxL_BASIC_HDR_MATCH.REQ_OPC", "PerPkg": "1", - "PublicDescription": "Matches on Transmit path of a UPI Port : Request, Match Opcode : Matches on Transmit path of a UPI port.\r\nMatch based on UMask specific bits:\r\nZ: Message Class (3-bit)\r\nY: Message Class Enable\r\nW: Opcode (4-bit)\r\nV: Opcode Enable\r\nU: Local Enable\r\nT: Remote Enable\r\nS: Data Hdr Enable\r\nR: Non-Data Hdr Enable\r\nQ: Dual Slot Hdr Enable\r\nP: Single Slot Hdr Enable\r\nLink Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases.\r\nNote: If Message Class is disabled, we expect opcode to also be disabled.", + "PublicDescription": "Matches on Transmit path of a UPI Port : Request, Match Opcode : Matches on Transmit path of a UPI port. Match based on UMask specific bits: Z: Message Class (3-bit) Y: Message Class Enable W: Opcode (4-bit) V: Opcode Enable U: Local Enable T: Remote Enable S: Data Hdr Enable R: Non-Data Hdr Enable Q: Dual Slot Hdr Enable P: Single Slot Hdr Enable Link Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases. Note: If Message Class is disabled, we expect opcode to also be disabled.", "UMask": "0x108", "Unit": "UPI" }, @@ -14092,7 +14092,7 @@ "EventCode": "0x04", "EventName": "UNC_UPI_TxL_BASIC_HDR_MATCH.RSPCNFLT", "PerPkg": "1", - "PublicDescription": "Matches on Transmit path of a UPI Port : Response - Conflict : Matches on Transmit path of a UPI port.\r\nMatch based on UMask specific bits:\r\nZ: Message Class (3-bit)\r\nY: Message Class Enable\r\nW: Opcode (4-bit)\r\nV: Opcode Enable\r\nU: Local Enable\r\nT: Remote Enable\r\nS: Data Hdr Enable\r\nR: Non-Data Hdr Enable\r\nQ: Dual Slot Hdr Enable\r\nP: Single Slot Hdr Enable\r\nLink Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases.\r\nNote: If Message Class is disabled, we expect opcode to also be disabled.", + "PublicDescription": "Matches on Transmit path of a UPI Port : Response - Conflict : Matches on Transmit path of a UPI port. Match based on UMask specific bits: Z: Message Class (3-bit) Y: Message Class Enable W: Opcode (4-bit) V: Opcode Enable U: Local Enable T: Remote Enable S: Data Hdr Enable R: Non-Data Hdr Enable Q: Dual Slot Hdr Enable P: Single Slot Hdr Enable Link Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases. Note: If Message Class is disabled, we expect opcode to also be disabled.", "UMask": "0x1aa", "Unit": "UPI" }, @@ -14101,7 +14101,7 @@ "EventCode": "0x04", "EventName": "UNC_UPI_TxL_BASIC_HDR_MATCH.RSPI", "PerPkg": "1", - "PublicDescription": "Matches on Transmit path of a UPI Port : Response - Invalid : Matches on Transmit path of a UPI port.\r\nMatch based on UMask specific bits:\r\nZ: Message Class (3-bit)\r\nY: Message Class Enable\r\nW: Opcode (4-bit)\r\nV: Opcode Enable\r\nU: Local Enable\r\nT: Remote Enable\r\nS: Data Hdr Enable\r\nR: Non-Data Hdr Enable\r\nQ: Dual Slot Hdr Enable\r\nP: Single Slot Hdr Enable\r\nLink Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases.\r\nNote: If Message Class is disabled, we expect opcode to also be disabled.", + "PublicDescription": "Matches on Transmit path of a UPI Port : Response - Invalid : Matches on Transmit path of a UPI port. Match based on UMask specific bits: Z: Message Class (3-bit) Y: Message Class Enable W: Opcode (4-bit) V: Opcode Enable U: Local Enable T: Remote Enable S: Data Hdr Enable R: Non-Data Hdr Enable Q: Dual Slot Hdr Enable P: Single Slot Hdr Enable Link Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases. Note: If Message Class is disabled, we expect opcode to also be disabled.", "UMask": "0x12a", "Unit": "UPI" }, @@ -14110,7 +14110,7 @@ "EventCode": "0x04", "EventName": "UNC_UPI_TxL_BASIC_HDR_MATCH.RSP_DATA", "PerPkg": "1", - "PublicDescription": "Matches on Transmit path of a UPI Port : Response - Data : Matches on Transmit path of a UPI port.\r\nMatch based on UMask specific bits:\r\nZ: Message Class (3-bit)\r\nY: Message Class Enable\r\nW: Opcode (4-bit)\r\nV: Opcode Enable\r\nU: Local Enable\r\nT: Remote Enable\r\nS: Data Hdr Enable\r\nR: Non-Data Hdr Enable\r\nQ: Dual Slot Hdr Enable\r\nP: Single Slot Hdr Enable\r\nLink Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases.\r\nNote: If Message Class is disabled, we expect opcode to also be disabled.", + "PublicDescription": "Matches on Transmit path of a UPI Port : Response - Data : Matches on Transmit path of a UPI port. Match based on UMask specific bits: Z: Message Class (3-bit) Y: Message Class Enable W: Opcode (4-bit) V: Opcode Enable U: Local Enable T: Remote Enable S: Data Hdr Enable R: Non-Data Hdr Enable Q: Dual Slot Hdr Enable P: Single Slot Hdr Enable Link Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases. Note: If Message Class is disabled, we expect opcode to also be disabled.", "UMask": "0xc", "Unit": "UPI" }, @@ -14119,7 +14119,7 @@ "EventCode": "0x04", "EventName": "UNC_UPI_TxL_BASIC_HDR_MATCH.RSP_DATA_OPC", "PerPkg": "1", - "PublicDescription": "Matches on Transmit path of a UPI Port : Response - Data, Match Opcode : Matches on Transmit path of a UPI port.\r\nMatch based on UMask specific bits:\r\nZ: Message Class (3-bit)\r\nY: Message Class Enable\r\nW: Opcode (4-bit)\r\nV: Opcode Enable\r\nU: Local Enable\r\nT: Remote Enable\r\nS: Data Hdr Enable\r\nR: Non-Data Hdr Enable\r\nQ: Dual Slot Hdr Enable\r\nP: Single Slot Hdr Enable\r\nLink Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases.\r\nNote: If Message Class is disabled, we expect opcode to also be disabled.", + "PublicDescription": "Matches on Transmit path of a UPI Port : Response - Data, Match Opcode : Matches on Transmit path of a UPI port. Match based on UMask specific bits: Z: Message Class (3-bit) Y: Message Class Enable W: Opcode (4-bit) V: Opcode Enable U: Local Enable T: Remote Enable S: Data Hdr Enable R: Non-Data Hdr Enable Q: Dual Slot Hdr Enable P: Single Slot Hdr Enable Link Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases. Note: If Message Class is disabled, we expect opcode to also be disabled.", "UMask": "0x10c", "Unit": "UPI" }, @@ -14128,7 +14128,7 @@ "EventCode": "0x04", "EventName": "UNC_UPI_TxL_BASIC_HDR_MATCH.RSP_NODATA", "PerPkg": "1", - "PublicDescription": "Matches on Transmit path of a UPI Port : Response - No Data : Matches on Transmit path of a UPI port.\r\nMatch based on UMask specific bits:\r\nZ: Message Class (3-bit)\r\nY: Message Class Enable\r\nW: Opcode (4-bit)\r\nV: Opcode Enable\r\nU: Local Enable\r\nT: Remote Enable\r\nS: Data Hdr Enable\r\nR: Non-Data Hdr Enable\r\nQ: Dual Slot Hdr Enable\r\nP: Single Slot Hdr Enable\r\nLink Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases.\r\nNote: If Message Class is disabled, we expect opcode to also be disabled.", + "PublicDescription": "Matches on Transmit path of a UPI Port : Response - No Data : Matches on Transmit path of a UPI port. Match based on UMask specific bits: Z: Message Class (3-bit) Y: Message Class Enable W: Opcode (4-bit) V: Opcode Enable U: Local Enable T: Remote Enable S: Data Hdr Enable R: Non-Data Hdr Enable Q: Dual Slot Hdr Enable P: Single Slot Hdr Enable Link Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases. Note: If Message Class is disabled, we expect opcode to also be disabled.", "UMask": "0xa", "Unit": "UPI" }, @@ -14137,7 +14137,7 @@ "EventCode": "0x04", "EventName": "UNC_UPI_TxL_BASIC_HDR_MATCH.RSP_NODATA_OPC", "PerPkg": "1", - "PublicDescription": "Matches on Transmit path of a UPI Port : Response - No Data, Match Opcode : Matches on Transmit path of a UPI port.\r\nMatch based on UMask specific bits:\r\nZ: Message Class (3-bit)\r\nY: Message Class Enable\r\nW: Opcode (4-bit)\r\nV: Opcode Enable\r\nU: Local Enable\r\nT: Remote Enable\r\nS: Data Hdr Enable\r\nR: Non-Data Hdr Enable\r\nQ: Dual Slot Hdr Enable\r\nP: Single Slot Hdr Enable\r\nLink Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases.\r\nNote: If Message Class is disabled, we expect opcode to also be disabled.", + "PublicDescription": "Matches on Transmit path of a UPI Port : Response - No Data, Match Opcode : Matches on Transmit path of a UPI port. Match based on UMask specific bits: Z: Message Class (3-bit) Y: Message Class Enable W: Opcode (4-bit) V: Opcode Enable U: Local Enable T: Remote Enable S: Data Hdr Enable R: Non-Data Hdr Enable Q: Dual Slot Hdr Enable P: Single Slot Hdr Enable Link Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases. Note: If Message Class is disabled, we expect opcode to also be disabled.", "UMask": "0x10a", "Unit": "UPI" }, @@ -14146,7 +14146,7 @@ "EventCode": "0x04", "EventName": "UNC_UPI_TxL_BASIC_HDR_MATCH.SNP", "PerPkg": "1", - "PublicDescription": "Matches on Transmit path of a UPI Port : Snoop : Matches on Transmit path of a UPI port.\r\nMatch based on UMask specific bits:\r\nZ: Message Class (3-bit)\r\nY: Message Class Enable\r\nW: Opcode (4-bit)\r\nV: Opcode Enable\r\nU: Local Enable\r\nT: Remote Enable\r\nS: Data Hdr Enable\r\nR: Non-Data Hdr Enable\r\nQ: Dual Slot Hdr Enable\r\nP: Single Slot Hdr Enable\r\nLink Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases.\r\nNote: If Message Class is disabled, we expect opcode to also be disabled.", + "PublicDescription": "Matches on Transmit path of a UPI Port : Snoop : Matches on Transmit path of a UPI port. Match based on UMask specific bits: Z: Message Class (3-bit) Y: Message Class Enable W: Opcode (4-bit) V: Opcode Enable U: Local Enable T: Remote Enable S: Data Hdr Enable R: Non-Data Hdr Enable Q: Dual Slot Hdr Enable P: Single Slot Hdr Enable Link Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases. Note: If Message Class is disabled, we expect opcode to also be disabled.", "UMask": "0x9", "Unit": "UPI" }, @@ -14155,7 +14155,7 @@ "EventCode": "0x04", "EventName": "UNC_UPI_TxL_BASIC_HDR_MATCH.SNP_OPC", "PerPkg": "1", - "PublicDescription": "Matches on Transmit path of a UPI Port : Snoop, Match Opcode : Matches on Transmit path of a UPI port.\r\nMatch based on UMask specific bits:\r\nZ: Message Class (3-bit)\r\nY: Message Class Enable\r\nW: Opcode (4-bit)\r\nV: Opcode Enable\r\nU: Local Enable\r\nT: Remote Enable\r\nS: Data Hdr Enable\r\nR: Non-Data Hdr Enable\r\nQ: Dual Slot Hdr Enable\r\nP: Single Slot Hdr Enable\r\nLink Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases.\r\nNote: If Message Class is disabled, we expect opcode to also be disabled.", + "PublicDescription": "Matches on Transmit path of a UPI Port : Snoop, Match Opcode : Matches on Transmit path of a UPI port. Match based on UMask specific bits: Z: Message Class (3-bit) Y: Message Class Enable W: Opcode (4-bit) V: Opcode Enable U: Local Enable T: Remote Enable S: Data Hdr Enable R: Non-Data Hdr Enable Q: Dual Slot Hdr Enable P: Single Slot Hdr Enable Link Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases. Note: If Message Class is disabled, we expect opcode to also be disabled.", "UMask": "0x109", "Unit": "UPI" }, @@ -14164,7 +14164,7 @@ "EventCode": "0x04", "EventName": "UNC_UPI_TxL_BASIC_HDR_MATCH.WB", "PerPkg": "1", - "PublicDescription": "Matches on Transmit path of a UPI Port : Writeback : Matches on Transmit path of a UPI port.\r\nMatch based on UMask specific bits:\r\nZ: Message Class (3-bit)\r\nY: Message Class Enable\r\nW: Opcode (4-bit)\r\nV: Opcode Enable\r\nU: Local Enable\r\nT: Remote Enable\r\nS: Data Hdr Enable\r\nR: Non-Data Hdr Enable\r\nQ: Dual Slot Hdr Enable\r\nP: Single Slot Hdr Enable\r\nLink Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases.\r\nNote: If Message Class is disabled, we expect opcode to also be disabled.", + "PublicDescription": "Matches on Transmit path of a UPI Port : Writeback : Matches on Transmit path of a UPI port. Match based on UMask specific bits: Z: Message Class (3-bit) Y: Message Class Enable W: Opcode (4-bit) V: Opcode Enable U: Local Enable T: Remote Enable S: Data Hdr Enable R: Non-Data Hdr Enable Q: Dual Slot Hdr Enable P: Single Slot Hdr Enable Link Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases. Note: If Message Class is disabled, we expect opcode to also be disabled.", "UMask": "0xd", "Unit": "UPI" }, @@ -14173,7 +14173,7 @@ "EventCode": "0x04", "EventName": "UNC_UPI_TxL_BASIC_HDR_MATCH.WB_OPC", "PerPkg": "1", - "PublicDescription": "Matches on Transmit path of a UPI Port : Writeback, Match Opcode : Matches on Transmit path of a UPI port.\r\nMatch based on UMask specific bits:\r\nZ: Message Class (3-bit)\r\nY: Message Class Enable\r\nW: Opcode (4-bit)\r\nV: Opcode Enable\r\nU: Local Enable\r\nT: Remote Enable\r\nS: Data Hdr Enable\r\nR: Non-Data Hdr Enable\r\nQ: Dual Slot Hdr Enable\r\nP: Single Slot Hdr Enable\r\nLink Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases.\r\nNote: If Message Class is disabled, we expect opcode to also be disabled.", + "PublicDescription": "Matches on Transmit path of a UPI Port : Writeback, Match Opcode : Matches on Transmit path of a UPI port. Match based on UMask specific bits: Z: Message Class (3-bit) Y: Message Class Enable W: Opcode (4-bit) V: Opcode Enable U: Local Enable T: Remote Enable S: Data Hdr Enable R: Non-Data Hdr Enable Q: Dual Slot Hdr Enable P: Single Slot Hdr Enable Link Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases. Note: If Message Class is disabled, we expect opcode to also be disabled.", "UMask": "0x10d", "Unit": "UPI" }, diff --git a/tools/perf/pmu-events/arch/x86/icelakex/uncore-io.json b/tools/perf/pmu-events/arch/x86/icelakex/uncore-io.json index 9cef8862c428..1b8a719b81a5 100644 --- a/tools/perf/pmu-events/arch/x86/icelakex/uncore-io.json +++ b/tools/perf/pmu-events/arch/x86/icelakex/uncore-io.json @@ -2476,17 +2476,6 @@ "UMask": "0x10", "Unit": "IIO" }, - { - "BriefDescription": "Number requests sent to PCIe from main die : From IRP", - "EventCode": "0xC2", - "EventName": "UNC_IIO_NUM_REQ_FROM_CPU.IRP", - "FCMask": "0x07", - "PerPkg": "1", - "PortMask": "0xFF", - "PublicDescription": "Number requests sent to PCIe from main die : From IRP : Captures Posted/Non-posted allocations from IRP. i.e. either non-confined P2P traffic or from the CPU", - "UMask": "0x1", - "Unit": "IIO" - }, { "BriefDescription": "Number requests sent to PCIe from main die : From ITC", "EventCode": "0xC2", diff --git a/tools/perf/pmu-events/arch/x86/mapfile.csv b/tools/perf/pmu-events/arch/x86/mapfile.csv index 650c28574576..a219dc3bd1ef 100644 --- a/tools/perf/pmu-events/arch/x86/mapfile.csv +++ b/tools/perf/pmu-events/arch/x86/mapfile.csv @@ -15,7 +15,7 @@ GenuineIntel-6-A[DE],v1.01,graniterapids,core GenuineIntel-6-(3C|45|46),v35,haswell,core GenuineIntel-6-3F,v28,haswellx,core GenuineIntel-6-7[DE],v1.21,icelake,core -GenuineIntel-6-6[AC],v1.23,icelakex,core +GenuineIntel-6-6[AC],v1.24,icelakex,core GenuineIntel-6-3A,v24,ivybridge,core GenuineIntel-6-3E,v24,ivytown,core GenuineIntel-6-2D,v24,jaketown,core -- cgit v1.2.3-59-g8ed1b From 3670ffbda1892bdab2328225b614c0be18885fea Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Wed, 20 Mar 2024 23:00:09 -0700 Subject: perf vendor events intel: Update lunarlake to 1.01 Update events from 1.00 to 1.01 as released in: https://github.com/intel/perfmon/commit/56ab8d837ac566d51a4d8748b6b4b817a22c9b84 Various encoding and description updates. Adds the events CPU_CLK_UNHALTED.CORE, CPU_CLK_UNHALTED.CORE_P, CPU_CLK_UNHALTED.REF_TSC_P, CPU_CLK_UNHALTED.THREAD, MISC_RETIRED.LBR_INSERTS, TOPDOWN_BAD_SPECULATION.ALL_P, TOPDOWN_BE_BOUND.ALL_P, TOPDOWN_FE_BOUND.ALL_P, TOPDOWN_RETIRING.ALL_P. Reviewed-by: Kan Liang Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Caleb Biggers Cc: Edward Baker Cc: Ingo Molnar Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Perry Taylor Cc: Peter Zijlstra Cc: Samantha Alt Cc: Weilin Wang Link: https://lore.kernel.org/r/20240321060016.1464787-6-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- .../perf/pmu-events/arch/x86/lunarlake/cache.json | 24 ++--- .../pmu-events/arch/x86/lunarlake/frontend.json | 2 +- .../perf/pmu-events/arch/x86/lunarlake/memory.json | 4 +- .../perf/pmu-events/arch/x86/lunarlake/other.json | 4 +- .../pmu-events/arch/x86/lunarlake/pipeline.json | 109 ++++++++++++++++++--- tools/perf/pmu-events/arch/x86/mapfile.csv | 2 +- 6 files changed, 113 insertions(+), 32 deletions(-) diff --git a/tools/perf/pmu-events/arch/x86/lunarlake/cache.json b/tools/perf/pmu-events/arch/x86/lunarlake/cache.json index 1823149067b5..fb48be357c4e 100644 --- a/tools/perf/pmu-events/arch/x86/lunarlake/cache.json +++ b/tools/perf/pmu-events/arch/x86/lunarlake/cache.json @@ -31,7 +31,7 @@ "EventCode": "0x2e", "EventName": "LONGEST_LAT_CACHE.REFERENCE", "PublicDescription": "Counts the number of cacheable memory requests that access the Last Level Cache (LLC). Requests include demand loads, reads for ownership (RFO), instruction fetches and L1 HW prefetches. If the platform has an L3 cache, the LLC is the L3 cache, otherwise it is the L2 cache. Counts on a per core basis.", - "SampleAfterValue": "1000003", + "SampleAfterValue": "200003", "UMask": "0x4f", "Unit": "cpu_atom" }, @@ -94,7 +94,7 @@ "MSRIndex": "0x3F6", "MSRValue": "0x400", "PEBS": "2", - "SampleAfterValue": "1000003", + "SampleAfterValue": "200003", "UMask": "0x5", "Unit": "cpu_atom" }, @@ -106,7 +106,7 @@ "MSRIndex": "0x3F6", "MSRValue": "0x80", "PEBS": "2", - "SampleAfterValue": "1000003", + "SampleAfterValue": "200003", "UMask": "0x5", "Unit": "cpu_atom" }, @@ -118,7 +118,7 @@ "MSRIndex": "0x3F6", "MSRValue": "0x10", "PEBS": "2", - "SampleAfterValue": "1000003", + "SampleAfterValue": "200003", "UMask": "0x5", "Unit": "cpu_atom" }, @@ -130,7 +130,7 @@ "MSRIndex": "0x3F6", "MSRValue": "0x800", "PEBS": "2", - "SampleAfterValue": "1000003", + "SampleAfterValue": "200003", "UMask": "0x5", "Unit": "cpu_atom" }, @@ -142,7 +142,7 @@ "MSRIndex": "0x3F6", "MSRValue": "0x100", "PEBS": "2", - "SampleAfterValue": "1000003", + "SampleAfterValue": "200003", "UMask": "0x5", "Unit": "cpu_atom" }, @@ -154,7 +154,7 @@ "MSRIndex": "0x3F6", "MSRValue": "0x20", "PEBS": "2", - "SampleAfterValue": "1000003", + "SampleAfterValue": "200003", "UMask": "0x5", "Unit": "cpu_atom" }, @@ -166,7 +166,7 @@ "MSRIndex": "0x3F6", "MSRValue": "0x4", "PEBS": "2", - "SampleAfterValue": "1000003", + "SampleAfterValue": "200003", "UMask": "0x5", "Unit": "cpu_atom" }, @@ -178,7 +178,7 @@ "MSRIndex": "0x3F6", "MSRValue": "0x200", "PEBS": "2", - "SampleAfterValue": "1000003", + "SampleAfterValue": "200003", "UMask": "0x5", "Unit": "cpu_atom" }, @@ -190,7 +190,7 @@ "MSRIndex": "0x3F6", "MSRValue": "0x40", "PEBS": "2", - "SampleAfterValue": "1000003", + "SampleAfterValue": "200003", "UMask": "0x5", "Unit": "cpu_atom" }, @@ -202,7 +202,7 @@ "MSRIndex": "0x3F6", "MSRValue": "0x8", "PEBS": "2", - "SampleAfterValue": "1000003", + "SampleAfterValue": "200003", "UMask": "0x5", "Unit": "cpu_atom" }, @@ -212,7 +212,7 @@ "EventCode": "0xd0", "EventName": "MEM_UOPS_RETIRED.STORE_LATENCY", "PEBS": "2", - "SampleAfterValue": "1000003", + "SampleAfterValue": "200003", "UMask": "0x6", "Unit": "cpu_atom" } diff --git a/tools/perf/pmu-events/arch/x86/lunarlake/frontend.json b/tools/perf/pmu-events/arch/x86/lunarlake/frontend.json index 5e4ef81b43d6..3a24934e8d6e 100644 --- a/tools/perf/pmu-events/arch/x86/lunarlake/frontend.json +++ b/tools/perf/pmu-events/arch/x86/lunarlake/frontend.json @@ -19,7 +19,7 @@ "BriefDescription": "This event counts a subset of the Topdown Slots event that were no operation was delivered to the back-end pipeline due to instruction fetch limitations when the back-end could have accepted more operations. Common examples include instruction cache misses or x86 instruction decode limitations.", "EventCode": "0x9c", "EventName": "IDQ_BUBBLES.CORE", - "PublicDescription": "This event counts a subset of the Topdown Slots event that were no operation was delivered to the back-end pipeline due to instruction fetch limitations when the back-end could have accepted more operations. Common examples include instruction cache misses or x86 instruction decode limitations.\nSoftware can use this event as the numerator for the Frontend Bound metric (or top-level category) of the Top-down Microarchitecture Analysis method.", + "PublicDescription": "This event counts a subset of the Topdown Slots event that were no operation was delivered to the back-end pipeline due to instruction fetch limitations when the back-end could have accepted more operations. Common examples include instruction cache misses or x86 instruction decode limitations. Software can use this event as the numerator for the Frontend Bound metric (or top-level category) of the Top-down Microarchitecture Analysis method.", "SampleAfterValue": "1000003", "UMask": "0x1", "Unit": "cpu_core" diff --git a/tools/perf/pmu-events/arch/x86/lunarlake/memory.json b/tools/perf/pmu-events/arch/x86/lunarlake/memory.json index 51d70ba00bd4..9c188d80b7b9 100644 --- a/tools/perf/pmu-events/arch/x86/lunarlake/memory.json +++ b/tools/perf/pmu-events/arch/x86/lunarlake/memory.json @@ -155,7 +155,7 @@ "EventCode": "0x2A,0x2B", "EventName": "OCR.DEMAND_DATA_RD.L3_MISS", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x3FBFC00001", + "MSRValue": "0xFE7F8000001", "SampleAfterValue": "100003", "UMask": "0x1", "Unit": "cpu_core" @@ -175,7 +175,7 @@ "EventCode": "0x2A,0x2B", "EventName": "OCR.DEMAND_RFO.L3_MISS", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x3FBFC00002", + "MSRValue": "0xFE7F8000002", "SampleAfterValue": "100003", "UMask": "0x1", "Unit": "cpu_core" diff --git a/tools/perf/pmu-events/arch/x86/lunarlake/other.json b/tools/perf/pmu-events/arch/x86/lunarlake/other.json index 69adaed5686d..377f717db6cc 100644 --- a/tools/perf/pmu-events/arch/x86/lunarlake/other.json +++ b/tools/perf/pmu-events/arch/x86/lunarlake/other.json @@ -24,7 +24,7 @@ "EventCode": "0xB7", "EventName": "OCR.DEMAND_DATA_RD.DRAM", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x184000001", + "MSRValue": "0x1FBC000001", "SampleAfterValue": "100003", "UMask": "0x1", "Unit": "cpu_atom" @@ -34,7 +34,7 @@ "EventCode": "0x2A,0x2B", "EventName": "OCR.DEMAND_DATA_RD.DRAM", "MSRIndex": "0x1a6,0x1a7", - "MSRValue": "0x184000001", + "MSRValue": "0x1E780000001", "SampleAfterValue": "100003", "UMask": "0x1", "Unit": "cpu_core" diff --git a/tools/perf/pmu-events/arch/x86/lunarlake/pipeline.json b/tools/perf/pmu-events/arch/x86/lunarlake/pipeline.json index 2bde664fdc0f..2c9f85ec8c4a 100644 --- a/tools/perf/pmu-events/arch/x86/lunarlake/pipeline.json +++ b/tools/perf/pmu-events/arch/x86/lunarlake/pipeline.json @@ -38,10 +38,18 @@ { "BriefDescription": "Fixed Counter: Counts the number of unhalted core clock cycles", "EventName": "CPU_CLK_UNHALTED.CORE", - "SampleAfterValue": "1000003", + "SampleAfterValue": "2000003", "UMask": "0x2", "Unit": "cpu_atom" }, + { + "BriefDescription": "Core cycles when the core is not in a halt state.", + "EventName": "CPU_CLK_UNHALTED.CORE", + "PublicDescription": "Counts the number of core cycles while the core is not in a halt state. The core enters the halt state when it is running the HLT instruction. This event is a component in many key event ratios. The core frequency may change from time to time due to transitions associated with Enhanced Intel SpeedStep Technology or TM2. For this reason this event may have a changing ratio with regards to time. When the core frequency is constant, this event can approximate elapsed time while the core was not in the halt state. It is counted on a dedicated fixed counter, leaving the programmable counters available for other events.", + "SampleAfterValue": "2000003", + "UMask": "0x2", + "Unit": "cpu_core" + }, { "BriefDescription": "Counts the number of unhalted core clock cycles [This event is alias to CPU_CLK_UNHALTED.THREAD_P]", "EventCode": "0x3c", @@ -49,10 +57,18 @@ "SampleAfterValue": "2000003", "Unit": "cpu_atom" }, + { + "BriefDescription": "Thread cycles when thread is not in halt state [This event is alias to CPU_CLK_UNHALTED.THREAD_P]", + "EventCode": "0x3c", + "EventName": "CPU_CLK_UNHALTED.CORE_P", + "PublicDescription": "This is an architectural event that counts the number of thread cycles while the thread is not in a halt state. The thread enters the halt state when it is running the HLT instruction. The core frequency may change from time to time due to power or thermal throttling. For this reason, this event may have a changing ratio with regards to wall clock time. [This event is alias to CPU_CLK_UNHALTED.THREAD_P]", + "SampleAfterValue": "2000003", + "Unit": "cpu_core" + }, { "BriefDescription": "Fixed Counter: Counts the number of unhalted reference clock cycles", "EventName": "CPU_CLK_UNHALTED.REF_TSC", - "SampleAfterValue": "1000003", + "SampleAfterValue": "2000003", "UMask": "0x3", "Unit": "cpu_atom" }, @@ -64,6 +80,15 @@ "UMask": "0x3", "Unit": "cpu_core" }, + { + "BriefDescription": "Counts the number of unhalted reference clock cycles", + "EventCode": "0x3c", + "EventName": "CPU_CLK_UNHALTED.REF_TSC_P", + "PublicDescription": "Counts the number of reference cycles that the core is not in a halt state. The core enters the halt state when it is running the HLT instruction. This event is not affected by core frequency changes and increments at a fixed frequency that is also used for the Time Stamp Counter (TSC). This event uses a programmable general purpose performance counter.", + "SampleAfterValue": "2000003", + "UMask": "0x1", + "Unit": "cpu_atom" + }, { "BriefDescription": "Reference cycles when the core is not in halt state.", "EventCode": "0x3c", @@ -74,9 +99,16 @@ "Unit": "cpu_core" }, { - "BriefDescription": "Core cycles when the thread is not in halt state", + "BriefDescription": "Fixed Counter: Counts the number of unhalted core clock cycles", + "EventName": "CPU_CLK_UNHALTED.THREAD", + "SampleAfterValue": "2000003", + "UMask": "0x2", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Core cycles when the thread is not in a halt state.", "EventName": "CPU_CLK_UNHALTED.THREAD", - "PublicDescription": "Counts the number of core cycles while the thread is not in a halt state. The thread enters the halt state when it is running the HLT instruction. This event is a component in many key event ratios. The core frequency may change from time to time due to transitions associated with Enhanced Intel SpeedStep Technology or TM2. For this reason this event may have a changing ratio with regards to time. When the core frequency is constant, this event can approximate elapsed time while the core was not in the halt state. It is counted on a dedicated fixed counter, leaving the eight programmable counters available for other events.", + "PublicDescription": "Counts the number of core cycles while the thread is not in a halt state. The thread enters the halt state when it is running the HLT instruction. This event is a component in many key event ratios. The core frequency may change from time to time due to transitions associated with Enhanced Intel SpeedStep Technology or TM2. For this reason this event may have a changing ratio with regards to time. When the core frequency is constant, this event can approximate elapsed time while the core was not in the halt state. It is counted on a dedicated fixed counter, leaving the programmable counters available for other events.", "SampleAfterValue": "2000003", "UMask": "0x2", "Unit": "cpu_core" @@ -89,10 +121,10 @@ "Unit": "cpu_atom" }, { - "BriefDescription": "Thread cycles when thread is not in halt state", + "BriefDescription": "Thread cycles when thread is not in halt state [This event is alias to CPU_CLK_UNHALTED.CORE_P]", "EventCode": "0x3c", "EventName": "CPU_CLK_UNHALTED.THREAD_P", - "PublicDescription": "This is an architectural event that counts the number of thread cycles while the thread is not in a halt state. The thread enters the halt state when it is running the HLT instruction. The core frequency may change from time to time due to power or thermal throttling. For this reason, this event may have a changing ratio with regards to wall clock time.", + "PublicDescription": "This is an architectural event that counts the number of thread cycles while the thread is not in a halt state. The thread enters the halt state when it is running the HLT instruction. The core frequency may change from time to time due to power or thermal throttling. For this reason, this event may have a changing ratio with regards to wall clock time. [This event is alias to CPU_CLK_UNHALTED.CORE_P]", "SampleAfterValue": "2000003", "Unit": "cpu_core" }, @@ -100,7 +132,7 @@ "BriefDescription": "Fixed Counter: Counts the number of instructions retired", "EventName": "INST_RETIRED.ANY", "PEBS": "1", - "SampleAfterValue": "1000003", + "SampleAfterValue": "2000003", "UMask": "0x1", "Unit": "cpu_atom" }, @@ -148,11 +180,29 @@ "UMask": "0x82", "Unit": "cpu_core" }, + { + "BriefDescription": "Counts the number of LBR entries recorded. Requires LBRs to be enabled in IA32_LBR_CTL.", + "EventCode": "0xe4", + "EventName": "MISC_RETIRED.LBR_INSERTS", + "PEBS": "1", + "SampleAfterValue": "1000003", + "UMask": "0x1", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "LBR record is inserted", + "EventCode": "0xe4", + "EventName": "MISC_RETIRED.LBR_INSERTS", + "PEBS": "1", + "SampleAfterValue": "1000003", + "UMask": "0x1", + "Unit": "cpu_core" + }, { "BriefDescription": "This event counts a subset of the Topdown Slots event that were not consumed by the back-end pipeline due to lack of back-end resources, as a result of memory subsystem delays, execution units limitations, or other conditions.", "EventCode": "0xa4", "EventName": "TOPDOWN.BACKEND_BOUND_SLOTS", - "PublicDescription": "This event counts a subset of the Topdown Slots event that were not consumed by the back-end pipeline due to lack of back-end resources, as a result of memory subsystem delays, execution units limitations, or other conditions.\nSoftware can use this event as the numerator for the Backend Bound metric (or top-level category) of the Top-down Microarchitecture Analysis method.", + "PublicDescription": "This event counts a subset of the Topdown Slots event that were not consumed by the back-end pipeline due to lack of back-end resources, as a result of memory subsystem delays, execution units limitations, or other conditions. Software can use this event as the numerator for the Backend Bound metric (or top-level category) of the Top-down Microarchitecture Analysis method.", "SampleAfterValue": "10000003", "UMask": "0x2", "Unit": "cpu_core" @@ -175,21 +225,35 @@ "Unit": "cpu_core" }, { - "BriefDescription": "Fixed Counter: Counts the number of issue slots that were not consumed by the backend because allocation is stalled due to a mispredicted jump or a machine clear.", + "BriefDescription": "Counts the number of issue slots that were not consumed by the backend because allocation is stalled due to a mispredicted jump or a machine clear. [This event is alias to TOPDOWN_BAD_SPECULATION.ALL_P]", + "EventCode": "0x73", "EventName": "TOPDOWN_BAD_SPECULATION.ALL", - "PublicDescription": "Fixed Counter: Counts the number of issue slots that were not consumed by the backend because allocation is stalled due to a mispredicted jump or a machine clear. Counts all issue slots blocked during this recovery window including relevant microcode flows and while uops are not yet available in the IQ. Also, includes the issue slots that were consumed by the backend but were thrown away because they were younger than the mispredict or machine clear.", "SampleAfterValue": "1000003", - "UMask": "0x5", "Unit": "cpu_atom" }, { - "BriefDescription": "Counts the number of retirement slots not consumed due to backend stalls", + "BriefDescription": "Counts the number of issue slots that were not consumed by the backend because allocation is stalled due to a mispredicted jump or a machine clear. [This event is alias to TOPDOWN_BAD_SPECULATION.ALL]", + "EventCode": "0x73", + "EventName": "TOPDOWN_BAD_SPECULATION.ALL_P", + "SampleAfterValue": "1000003", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of retirement slots not consumed due to backend stalls [This event is alias to TOPDOWN_BE_BOUND.ALL_P]", "EventCode": "0xa4", "EventName": "TOPDOWN_BE_BOUND.ALL", "SampleAfterValue": "1000003", "UMask": "0x2", "Unit": "cpu_atom" }, + { + "BriefDescription": "Counts the number of retirement slots not consumed due to backend stalls [This event is alias to TOPDOWN_BE_BOUND.ALL]", + "EventCode": "0xa4", + "EventName": "TOPDOWN_BE_BOUND.ALL_P", + "SampleAfterValue": "1000003", + "UMask": "0x2", + "Unit": "cpu_atom" + }, { "BriefDescription": "Fixed Counter: Counts the number of retirement slots not consumed due to front end stalls", "EventName": "TOPDOWN_FE_BOUND.ALL", @@ -198,18 +262,35 @@ "Unit": "cpu_atom" }, { - "BriefDescription": "Fixed Counter: Counts the number of consumed retirement slots. Similar to UOPS_RETIRED.ALL", + "BriefDescription": "Counts the number of retirement slots not consumed due to front end stalls", + "EventCode": "0x9c", + "EventName": "TOPDOWN_FE_BOUND.ALL_P", + "SampleAfterValue": "1000003", + "UMask": "0x1", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Fixed Counter: Counts the number of consumed retirement slots.", "EventName": "TOPDOWN_RETIRING.ALL", "PEBS": "1", "SampleAfterValue": "1000003", "UMask": "0x7", "Unit": "cpu_atom" }, + { + "BriefDescription": "Counts the number of consumed retirement slots.", + "EventCode": "0xc2", + "EventName": "TOPDOWN_RETIRING.ALL_P", + "PEBS": "1", + "SampleAfterValue": "1000003", + "UMask": "0x2", + "Unit": "cpu_atom" + }, { "BriefDescription": "This event counts a subset of the Topdown Slots event that are utilized by operations that eventually get retired (committed) by the processor pipeline. Usually, this event positively correlates with higher performance for example, as measured by the instructions-per-cycle metric.", "EventCode": "0xc2", "EventName": "UOPS_RETIRED.SLOTS", - "PublicDescription": "This event counts a subset of the Topdown Slots event that are utilized by operations that eventually get retired (committed) by the processor pipeline. Usually, this event positively correlates with higher performance for example, as measured by the instructions-per-cycle metric.\nSoftware can use this event as the numerator for the Retiring metric (or top-level category) of the Top-down Microarchitecture Analysis method.", + "PublicDescription": "This event counts a subset of the Topdown Slots event that are utilized by operations that eventually get retired (committed) by the processor pipeline. Usually, this event positively correlates with higher performance for example, as measured by the instructions-per-cycle metric. Software can use this event as the numerator for the Retiring metric (or top-level category) of the Top-down Microarchitecture Analysis method.", "SampleAfterValue": "2000003", "UMask": "0x2", "Unit": "cpu_core" diff --git a/tools/perf/pmu-events/arch/x86/mapfile.csv b/tools/perf/pmu-events/arch/x86/mapfile.csv index a219dc3bd1ef..710f8dfefeed 100644 --- a/tools/perf/pmu-events/arch/x86/mapfile.csv +++ b/tools/perf/pmu-events/arch/x86/mapfile.csv @@ -20,7 +20,7 @@ GenuineIntel-6-3A,v24,ivybridge,core GenuineIntel-6-3E,v24,ivytown,core GenuineIntel-6-2D,v24,jaketown,core GenuineIntel-6-(57|85),v16,knightslanding,core -GenuineIntel-6-BD,v1.00,lunarlake,core +GenuineIntel-6-BD,v1.01,lunarlake,core GenuineIntel-6-A[AC],v1.07,meteorlake,core GenuineIntel-6-1[AEF],v4,nehalemep,core GenuineIntel-6-2E,v4,nehalemex,core -- cgit v1.2.3-59-g8ed1b From 84d0e8c6db884733aaf59b7a224ed0dc208afeed Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Wed, 20 Mar 2024 23:00:10 -0700 Subject: perf vendor events intel: Update meteorlake to 1.08 Update events from 1.07 to 1.08 as released in: https://github.com/intel/perfmon/commit/f0f8f3e163d9eb84e6ce8e2108a22cb43b2527e5 Various description updates. Adds topdown, offcore and uncore events OCR.DEMAND_DATA_RD.L3_HIT, OCR.DEMAND_DATA_RD.L3_HIT.SNOOP_HIT_NO_FWD, OCR.DEMAND_RFO.L3_HIT, OCR.DEMAND_DATA_RD.L3_MISS, OCR.DEMAND_RFO.L3_MISS, OCR.DEMAND_DATA_RD.ANY_RESPONSE, OCR.DEMAND_DATA_RD.DRAM, OCR.DEMAND_RFO.ANY_RESPONSE, OCR.DEMAND_RFO.DRAM, TOPDOWN_BAD_SPECULATION.ALL_P, TOPDOWN_BE_BOUND.ALL_P, TOPDOWN_FE_BOUND.ALL_P, TOPDOWN_RETIRING.ALL_P, UNC_ARB_DAT_OCCUPANCY.RD and UNC_HAC_ARB_COH_TRK_REQUESTS.ALL. Reviewed-by: Kan Liang Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Caleb Biggers Cc: Edward Baker Cc: Ingo Molnar Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Perry Taylor Cc: Peter Zijlstra Cc: Samantha Alt Cc: Weilin Wang Link: https://lore.kernel.org/r/20240321060016.1464787-7-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/pmu-events/arch/x86/mapfile.csv | 2 +- .../perf/pmu-events/arch/x86/meteorlake/cache.json | 30 +++++++++++++++ .../pmu-events/arch/x86/meteorlake/frontend.json | 4 +- .../pmu-events/arch/x86/meteorlake/memory.json | 20 ++++++++++ .../perf/pmu-events/arch/x86/meteorlake/other.json | 42 ++++++++++++++++++++- .../pmu-events/arch/x86/meteorlake/pipeline.json | 44 ++++++++++++++++++---- .../arch/x86/meteorlake/uncore-interconnect.json | 22 +++++++++-- 7 files changed, 150 insertions(+), 14 deletions(-) diff --git a/tools/perf/pmu-events/arch/x86/mapfile.csv b/tools/perf/pmu-events/arch/x86/mapfile.csv index 710f8dfefeed..fedaacbe981a 100644 --- a/tools/perf/pmu-events/arch/x86/mapfile.csv +++ b/tools/perf/pmu-events/arch/x86/mapfile.csv @@ -21,7 +21,7 @@ GenuineIntel-6-3E,v24,ivytown,core GenuineIntel-6-2D,v24,jaketown,core GenuineIntel-6-(57|85),v16,knightslanding,core GenuineIntel-6-BD,v1.01,lunarlake,core -GenuineIntel-6-A[AC],v1.07,meteorlake,core +GenuineIntel-6-A[AC],v1.08,meteorlake,core GenuineIntel-6-1[AEF],v4,nehalemep,core GenuineIntel-6-2E,v4,nehalemex,core GenuineIntel-6-A7,v1.02,rocketlake,core diff --git a/tools/perf/pmu-events/arch/x86/meteorlake/cache.json b/tools/perf/pmu-events/arch/x86/meteorlake/cache.json index 47861a6dd8e9..af7acb15f661 100644 --- a/tools/perf/pmu-events/arch/x86/meteorlake/cache.json +++ b/tools/perf/pmu-events/arch/x86/meteorlake/cache.json @@ -966,6 +966,16 @@ "UMask": "0x3", "Unit": "cpu_core" }, + { + "BriefDescription": "Counts demand data reads that were supplied by the L3 cache.", + "EventCode": "0xB7", + "EventName": "OCR.DEMAND_DATA_RD.L3_HIT", + "MSRIndex": "0x1a6,0x1a7", + "MSRValue": "0x3F803C0001", + "SampleAfterValue": "100003", + "UMask": "0x1", + "Unit": "cpu_atom" + }, { "BriefDescription": "Counts demand data reads that were supplied by the L3 cache where a snoop was sent, the snoop hit, and modified data was forwarded.", "EventCode": "0xB7", @@ -986,6 +996,16 @@ "UMask": "0x1", "Unit": "cpu_core" }, + { + "BriefDescription": "Counts demand data reads that were supplied by the L3 cache where a snoop was sent, the snoop hit, but no data was forwarded.", + "EventCode": "0xB7", + "EventName": "OCR.DEMAND_DATA_RD.L3_HIT.SNOOP_HIT_NO_FWD", + "MSRIndex": "0x1a6,0x1a7", + "MSRValue": "0x4003C0001", + "SampleAfterValue": "100003", + "UMask": "0x1", + "Unit": "cpu_atom" + }, { "BriefDescription": "Counts demand data reads that were supplied by the L3 cache where a snoop was sent, the snoop hit, and non-modified data was forwarded.", "EventCode": "0xB7", @@ -1006,6 +1026,16 @@ "UMask": "0x1", "Unit": "cpu_core" }, + { + "BriefDescription": "Counts demand reads for ownership (RFO) and software prefetches for exclusive ownership (PREFETCHW) that were supplied by the L3 cache.", + "EventCode": "0xB7", + "EventName": "OCR.DEMAND_RFO.L3_HIT", + "MSRIndex": "0x1a6,0x1a7", + "MSRValue": "0x3F803C0002", + "SampleAfterValue": "100003", + "UMask": "0x1", + "Unit": "cpu_atom" + }, { "BriefDescription": "Counts demand reads for ownership (RFO) and software prefetches for exclusive ownership (PREFETCHW) that were supplied by the L3 cache where a snoop was sent, the snoop hit, and modified data was forwarded.", "EventCode": "0xB7", diff --git a/tools/perf/pmu-events/arch/x86/meteorlake/frontend.json b/tools/perf/pmu-events/arch/x86/meteorlake/frontend.json index 9da8689eda81..f3b7b211afb5 100644 --- a/tools/perf/pmu-events/arch/x86/meteorlake/frontend.json +++ b/tools/perf/pmu-events/arch/x86/meteorlake/frontend.json @@ -378,7 +378,7 @@ "CounterMask": "6", "EventCode": "0x79", "EventName": "IDQ.DSB_CYCLES_OK", - "PublicDescription": "Counts the number of cycles where optimal number of uops was delivered to the Instruction Decode Queue (IDQ) from the MITE (legacy decode pipeline) path. During these cycles uops are not being delivered from the Decode Stream Buffer (DSB).", + "PublicDescription": "Counts the number of cycles where optimal number of uops was delivered to the Instruction Decode Queue (IDQ) from the DSB (Decode Stream Buffer) path. Count includes uops that may 'bypass' the IDQ.", "SampleAfterValue": "2000003", "UMask": "0x8", "Unit": "cpu_core" @@ -455,7 +455,7 @@ "BriefDescription": "This event counts a subset of the Topdown Slots event that were no operation was delivered to the back-end pipeline due to instruction fetch limitations when the back-end could have accepted more operations. Common examples include instruction cache misses or x86 instruction decode limitations.", "EventCode": "0x9c", "EventName": "IDQ_BUBBLES.CORE", - "PublicDescription": "This event counts a subset of the Topdown Slots event that were no operation was delivered to the back-end pipeline due to instruction fetch limitations when the back-end could have accepted more operations. Common examples include instruction cache misses or x86 instruction decode limitations.\nThe count may be distributed among unhalted logical processors (hyper-threads) who share the same physical core, in processors that support Intel Hyper-Threading Technology. Software can use this event as the numerator for the Frontend Bound metric (or top-level category) of the Top-down Microarchitecture Analysis method.", + "PublicDescription": "This event counts a subset of the Topdown Slots event that were no operation was delivered to the back-end pipeline due to instruction fetch limitations when the back-end could have accepted more operations. Common examples include instruction cache misses or x86 instruction decode limitations. The count may be distributed among unhalted logical processors (hyper-threads) who share the same physical core, in processors that support Intel Hyper-Threading Technology. Software can use this event as the numerator for the Frontend Bound metric (or top-level category) of the Top-down Microarchitecture Analysis method.", "SampleAfterValue": "1000003", "UMask": "0x1", "Unit": "cpu_core" diff --git a/tools/perf/pmu-events/arch/x86/meteorlake/memory.json b/tools/perf/pmu-events/arch/x86/meteorlake/memory.json index a5b83293f157..617d0e255fd5 100644 --- a/tools/perf/pmu-events/arch/x86/meteorlake/memory.json +++ b/tools/perf/pmu-events/arch/x86/meteorlake/memory.json @@ -296,6 +296,16 @@ "UMask": "0x4", "Unit": "cpu_atom" }, + { + "BriefDescription": "Counts demand data reads that were not supplied by the L3 cache.", + "EventCode": "0xB7", + "EventName": "OCR.DEMAND_DATA_RD.L3_MISS", + "MSRIndex": "0x1a6,0x1a7", + "MSRValue": "0x3FBFC00001", + "SampleAfterValue": "100003", + "UMask": "0x1", + "Unit": "cpu_atom" + }, { "BriefDescription": "Counts demand data reads that were not supplied by the L3 cache.", "EventCode": "0x2A,0x2B", @@ -306,6 +316,16 @@ "UMask": "0x1", "Unit": "cpu_core" }, + { + "BriefDescription": "Counts demand reads for ownership (RFO) and software prefetches for exclusive ownership (PREFETCHW) that were not supplied by the L3 cache.", + "EventCode": "0xB7", + "EventName": "OCR.DEMAND_RFO.L3_MISS", + "MSRIndex": "0x1a6,0x1a7", + "MSRValue": "0x3FBFC00002", + "SampleAfterValue": "100003", + "UMask": "0x1", + "Unit": "cpu_atom" + }, { "BriefDescription": "Counts demand read for ownership (RFO) requests and software prefetches for exclusive ownership (PREFETCHW) that were not supplied by the L3 cache.", "EventCode": "0x2A,0x2B", diff --git a/tools/perf/pmu-events/arch/x86/meteorlake/other.json b/tools/perf/pmu-events/arch/x86/meteorlake/other.json index 7effc1f271e7..0bc2cb2eabb3 100644 --- a/tools/perf/pmu-events/arch/x86/meteorlake/other.json +++ b/tools/perf/pmu-events/arch/x86/meteorlake/other.json @@ -17,6 +17,16 @@ "UMask": "0x1", "Unit": "cpu_atom" }, + { + "BriefDescription": "Counts demand data reads that have any type of response.", + "EventCode": "0xB7", + "EventName": "OCR.DEMAND_DATA_RD.ANY_RESPONSE", + "MSRIndex": "0x1a6,0x1a7", + "MSRValue": "0x10001", + "SampleAfterValue": "100003", + "UMask": "0x1", + "Unit": "cpu_atom" + }, { "BriefDescription": "Counts demand data reads that have any type of response.", "EventCode": "0x2A,0x2B", @@ -27,6 +37,16 @@ "UMask": "0x1", "Unit": "cpu_core" }, + { + "BriefDescription": "Counts demand data reads that were supplied by DRAM.", + "EventCode": "0xB7", + "EventName": "OCR.DEMAND_DATA_RD.DRAM", + "MSRIndex": "0x1a6,0x1a7", + "MSRValue": "0x184000001", + "SampleAfterValue": "100003", + "UMask": "0x1", + "Unit": "cpu_atom" + }, { "BriefDescription": "Counts demand data reads that were supplied by DRAM.", "EventCode": "0x2A,0x2B", @@ -37,6 +57,16 @@ "UMask": "0x1", "Unit": "cpu_core" }, + { + "BriefDescription": "Counts demand reads for ownership (RFO) and software prefetches for exclusive ownership (PREFETCHW) that have any type of response.", + "EventCode": "0xB7", + "EventName": "OCR.DEMAND_RFO.ANY_RESPONSE", + "MSRIndex": "0x1a6,0x1a7", + "MSRValue": "0x10002", + "SampleAfterValue": "100003", + "UMask": "0x1", + "Unit": "cpu_atom" + }, { "BriefDescription": "Counts demand read for ownership (RFO) requests and software prefetches for exclusive ownership (PREFETCHW) that have any type of response.", "EventCode": "0x2A,0x2B", @@ -47,6 +77,16 @@ "UMask": "0x1", "Unit": "cpu_core" }, + { + "BriefDescription": "Counts demand reads for ownership (RFO) and software prefetches for exclusive ownership (PREFETCHW) that were supplied by DRAM.", + "EventCode": "0xB7", + "EventName": "OCR.DEMAND_RFO.DRAM", + "MSRIndex": "0x1a6,0x1a7", + "MSRValue": "0x184000002", + "SampleAfterValue": "100003", + "UMask": "0x1", + "Unit": "cpu_atom" + }, { "BriefDescription": "Counts streaming stores that have any type of response.", "EventCode": "0xB7", @@ -97,7 +137,7 @@ "Unit": "cpu_core" }, { - "BriefDescription": "Counts the number of issue slots in a UMWAIT or TPAUSE instruction where no uop issues due to the instruction putting the CPU into the C0.1 activity state. For Tremont, UMWAIT and TPAUSE will only put the CPU into C0.1 activity state (not C0.2 activity state)", + "BriefDescription": "Counts the number of issue slots in a UMWAIT or TPAUSE instruction where no uop issues due to the instruction putting the CPU into the C0.1 activity state.", "EventCode": "0x75", "EventName": "SERIALIZATION.C01_MS_SCB", "SampleAfterValue": "200003", diff --git a/tools/perf/pmu-events/arch/x86/meteorlake/pipeline.json b/tools/perf/pmu-events/arch/x86/meteorlake/pipeline.json index 24bbfcebd2be..5ff4a7a32250 100644 --- a/tools/perf/pmu-events/arch/x86/meteorlake/pipeline.json +++ b/tools/perf/pmu-events/arch/x86/meteorlake/pipeline.json @@ -1067,7 +1067,7 @@ "BriefDescription": "This event counts a subset of the Topdown Slots event that were not consumed by the back-end pipeline due to lack of back-end resources, as a result of memory subsystem delays, execution units limitations, or other conditions.", "EventCode": "0xa4", "EventName": "TOPDOWN.BACKEND_BOUND_SLOTS", - "PublicDescription": "This event counts a subset of the Topdown Slots event that were not consumed by the back-end pipeline due to lack of back-end resources, as a result of memory subsystem delays, execution units limitations, or other conditions.\nThe count is distributed among unhalted logical processors (hyper-threads) who share the same physical core, in processors that support Intel Hyper-Threading Technology. Software can use this event as the numerator for the Backend Bound metric (or top-level category) of the Top-down Microarchitecture Analysis method.", + "PublicDescription": "This event counts a subset of the Topdown Slots event that were not consumed by the back-end pipeline due to lack of back-end resources, as a result of memory subsystem delays, execution units limitations, or other conditions. The count is distributed among unhalted logical processors (hyper-threads) who share the same physical core, in processors that support Intel Hyper-Threading Technology. Software can use this event as the numerator for the Backend Bound metric (or top-level category) of the Top-down Microarchitecture Analysis method.", "SampleAfterValue": "10000003", "UMask": "0x2", "Unit": "cpu_core" @@ -1116,10 +1116,18 @@ "Unit": "cpu_core" }, { - "BriefDescription": "Counts the number of issue slots that were not consumed by the backend because allocation is stalled due to a mispredicted jump or a machine clear.", + "BriefDescription": "Counts the number of issue slots that were not consumed by the backend because allocation is stalled due to a mispredicted jump or a machine clear. [This event is alias to TOPDOWN_BAD_SPECULATION.ALL_P]", "EventCode": "0x73", "EventName": "TOPDOWN_BAD_SPECULATION.ALL", - "PublicDescription": "Counts the total number of issue slots that were not consumed by the backend because allocation is stalled due to a mispredicted jump or a machine clear. Only issue slots wasted due to fast nukes such as memory ordering nukes are counted. Other nukes are not accounted for. Counts all issue slots blocked during this recovery window, including relevant microcode flows, and while uops are not yet available in the instruction queue (IQ) or until an FE_BOUND event occurs besides OTHER and CISC. Also includes the issue slots that were consumed by the backend but were thrown away because they were younger than the mispredict or machine clear.", + "PublicDescription": "Counts the total number of issue slots that were not consumed by the backend because allocation is stalled due to a mispredicted jump or a machine clear. Only issue slots wasted due to fast nukes such as memory ordering nukes are counted. Other nukes are not accounted for. Counts all issue slots blocked during this recovery window, including relevant microcode flows, and while uops are not yet available in the instruction queue (IQ) or until an FE_BOUND event occurs besides OTHER and CISC. Also includes the issue slots that were consumed by the backend but were thrown away because they were younger than the mispredict or machine clear. [This event is alias to TOPDOWN_BAD_SPECULATION.ALL_P]", + "SampleAfterValue": "1000003", + "Unit": "cpu_atom" + }, + { + "BriefDescription": "Counts the number of issue slots that were not consumed by the backend because allocation is stalled due to a mispredicted jump or a machine clear. [This event is alias to TOPDOWN_BAD_SPECULATION.ALL]", + "EventCode": "0x73", + "EventName": "TOPDOWN_BAD_SPECULATION.ALL_P", + "PublicDescription": "Counts the total number of issue slots that were not consumed by the backend because allocation is stalled due to a mispredicted jump or a machine clear. Only issue slots wasted due to fast nukes such as memory ordering nukes are counted. Other nukes are not accounted for. Counts all issue slots blocked during this recovery window, including relevant microcode flows, and while uops are not yet available in the instruction queue (IQ) or until an FE_BOUND event occurs besides OTHER and CISC. Also includes the issue slots that were consumed by the backend but were thrown away because they were younger than the mispredict or machine clear. [This event is alias to TOPDOWN_BAD_SPECULATION.ALL]", "SampleAfterValue": "1000003", "Unit": "cpu_atom" }, @@ -1156,7 +1164,7 @@ "Unit": "cpu_atom" }, { - "BriefDescription": "Counts the number of retirement slots not consumed due to backend stalls", + "BriefDescription": "Counts the number of retirement slots not consumed due to backend stalls [This event is alias to TOPDOWN_BE_BOUND.ALL_P]", "EventCode": "0x74", "EventName": "TOPDOWN_BE_BOUND.ALL", "SampleAfterValue": "1000003", @@ -1170,6 +1178,13 @@ "UMask": "0x1", "Unit": "cpu_atom" }, + { + "BriefDescription": "Counts the number of retirement slots not consumed due to backend stalls [This event is alias to TOPDOWN_BE_BOUND.ALL]", + "EventCode": "0x74", + "EventName": "TOPDOWN_BE_BOUND.ALL_P", + "SampleAfterValue": "1000003", + "Unit": "cpu_atom" + }, { "BriefDescription": "Counts the number of issue slots every cycle that were not consumed by the backend due to memory reservation stall (scheduler not being able to accept another uop). This could be caused by RSV full or load/store buffer block.", "EventCode": "0x74", @@ -1211,12 +1226,19 @@ "Unit": "cpu_atom" }, { - "BriefDescription": "Counts the number of retirement slots not consumed due to front end stalls", + "BriefDescription": "Counts the number of retirement slots not consumed due to front end stalls [This event is alias to TOPDOWN_FE_BOUND.ALL_P]", "EventCode": "0x71", "EventName": "TOPDOWN_FE_BOUND.ALL", "SampleAfterValue": "1000003", "Unit": "cpu_atom" }, + { + "BriefDescription": "Counts the number of retirement slots not consumed due to front end stalls [This event is alias to TOPDOWN_FE_BOUND.ALL]", + "EventCode": "0x71", + "EventName": "TOPDOWN_FE_BOUND.ALL_P", + "SampleAfterValue": "1000003", + "Unit": "cpu_atom" + }, { "BriefDescription": "Counts the number of issue slots every cycle that were not delivered by the frontend due to BAClear", "EventCode": "0x71", @@ -1299,13 +1321,21 @@ "Unit": "cpu_atom" }, { - "BriefDescription": "Counts the number of consumed retirement slots. Similar to UOPS_RETIRED.ALL", + "BriefDescription": "Counts the number of consumed retirement slots. Similar to UOPS_RETIRED.ALL [This event is alias to TOPDOWN_RETIRING.ALL_P]", "EventCode": "0x72", "EventName": "TOPDOWN_RETIRING.ALL", "PEBS": "1", "SampleAfterValue": "1000003", "Unit": "cpu_atom" }, + { + "BriefDescription": "Counts the number of consumed retirement slots. Similar to UOPS_RETIRED.ALL [This event is alias to TOPDOWN_RETIRING.ALL]", + "EventCode": "0x72", + "EventName": "TOPDOWN_RETIRING.ALL_P", + "PEBS": "1", + "SampleAfterValue": "1000003", + "Unit": "cpu_atom" + }, { "BriefDescription": "Number of non dec-by-all uops decoded by decoder", "EventCode": "0x76", @@ -1591,7 +1621,7 @@ "BriefDescription": "This event counts a subset of the Topdown Slots event that are utilized by operations that eventually get retired (committed) by the processor pipeline. Usually, this event positively correlates with higher performance for example, as measured by the instructions-per-cycle metric.", "EventCode": "0xc2", "EventName": "UOPS_RETIRED.SLOTS", - "PublicDescription": "This event counts a subset of the Topdown Slots event that are utilized by operations that eventually get retired (committed) by the processor pipeline. Usually, this event positively correlates with higher performance for example, as measured by the instructions-per-cycle metric.\nSoftware can use this event as the numerator for the Retiring metric (or top-level category) of the Top-down Microarchitecture Analysis method.", + "PublicDescription": "This event counts a subset of the Topdown Slots event that are utilized by operations that eventually get retired (committed) by the processor pipeline. Usually, this event positively correlates with higher performance for example, as measured by the instructions-per-cycle metric. Software can use this event as the numerator for the Retiring metric (or top-level category) of the Top-down Microarchitecture Analysis method.", "SampleAfterValue": "2000003", "UMask": "0x2", "Unit": "cpu_core" diff --git a/tools/perf/pmu-events/arch/x86/meteorlake/uncore-interconnect.json b/tools/perf/pmu-events/arch/x86/meteorlake/uncore-interconnect.json index 08b5c7574cfc..901d8510f90f 100644 --- a/tools/perf/pmu-events/arch/x86/meteorlake/uncore-interconnect.json +++ b/tools/perf/pmu-events/arch/x86/meteorlake/uncore-interconnect.json @@ -1,4 +1,20 @@ [ + { + "BriefDescription": "Each cycle counts number of coherent reads pending on data return from memory controller that were issued by any core.", + "EventCode": "0x85", + "EventName": "UNC_ARB_DAT_OCCUPANCY.RD", + "PerPkg": "1", + "UMask": "0x2", + "Unit": "ARB" + }, + { + "BriefDescription": "Number of entries allocated. Account for Any type: e.g. Snoop, etc.", + "EventCode": "0x84", + "EventName": "UNC_HAC_ARB_COH_TRK_REQUESTS.ALL", + "PerPkg": "1", + "UMask": "0x1", + "Unit": "HAC_ARB" + }, { "BriefDescription": "Number of all coherent Data Read entries. Doesn't include prefetches", "EventCode": "0x81", @@ -9,7 +25,7 @@ }, { "BriefDescription": "Number of all CMI transactions", - "EventCode": "0x8a", + "EventCode": "0x8A", "EventName": "UNC_HAC_ARB_TRANSACTIONS.ALL", "PerPkg": "1", "UMask": "0x1", @@ -17,7 +33,7 @@ }, { "BriefDescription": "Number of all CMI reads", - "EventCode": "0x8a", + "EventCode": "0x8A", "EventName": "UNC_HAC_ARB_TRANSACTIONS.READS", "PerPkg": "1", "UMask": "0x2", @@ -25,7 +41,7 @@ }, { "BriefDescription": "Number of all CMI writes not including Mflush", - "EventCode": "0x8a", + "EventCode": "0x8A", "EventName": "UNC_HAC_ARB_TRANSACTIONS.WRITES", "PerPkg": "1", "UMask": "0x4", -- cgit v1.2.3-59-g8ed1b From 2edee9e666bb1cdb60d5d16f510ad9b51c84c33e Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Wed, 20 Mar 2024 23:00:11 -0700 Subject: perf vendor events intel: Update sapphirerapids to 1.20 Update events from 1.17 to 1.20 as released in: https://github.com/intel/perfmon/commit/6f674057745acf0125395638ca6be36458a59bda Various description updates. Adds uncore events UNC_CHA_TOR_INSERTS.IO_ITOMCACHENEAR_LOCAL, UNC_CHA_TOR_INSERTS.IO_ITOMCACHENEAR_REMOTE, UNC_CHA_TOR_INSERTS.IO_ITOM_LOCAL, UNC_CHA_TOR_INSERTS.IO_ITOM_REMOTE, UNC_CHA_TOR_INSERTS.IO_PCIRDCUR_LOCAL, UNC_CHA_TOR_INSERTS.IO_PCIRDCUR_REMOTE, UNC_CHA_TOR_OCCUPANCY.IO_MISS_ITOMCACHENEAR_LOCAL, UNC_CHA_TOR_OCCUPANCY.IO_MISS_ITOMCACHENEAR_REMOTE, UNC_CHA_TOR_OCCUPANCY.IO_MISS_ITOM_LOCAL, UNC_CHA_TOR_OCCUPANCY.IO_MISS_ITOM_REMOTE, UNC_CHA_TOR_OCCUPANCY.IO_MISS_PCIRDCUR_LOCAL, UNC_CHA_TOR_OCCUPANCY.IO_MISS_PCIRDCUR_REMOTE and removes core events AMX_OPS_RETIRED.BF16 and AMX_OPS_RETIRED.INT8. Reviewed-by: Kan Liang Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Caleb Biggers Cc: Edward Baker Cc: Ingo Molnar Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Perry Taylor Cc: Peter Zijlstra Cc: Samantha Alt Cc: Weilin Wang Link: https://lore.kernel.org/r/20240321060016.1464787-8-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/pmu-events/arch/x86/mapfile.csv | 2 +- .../pmu-events/arch/x86/sapphirerapids/cache.json | 1 + .../arch/x86/sapphirerapids/frontend.json | 2 +- .../pmu-events/arch/x86/sapphirerapids/memory.json | 1 + .../arch/x86/sapphirerapids/pipeline.json | 19 +--- .../arch/x86/sapphirerapids/uncore-cache.json | 112 ++++++++++++++++++++- .../x86/sapphirerapids/uncore-interconnect.json | 26 ++--- 7 files changed, 130 insertions(+), 33 deletions(-) diff --git a/tools/perf/pmu-events/arch/x86/mapfile.csv b/tools/perf/pmu-events/arch/x86/mapfile.csv index fedaacbe981a..e5de35c96358 100644 --- a/tools/perf/pmu-events/arch/x86/mapfile.csv +++ b/tools/perf/pmu-events/arch/x86/mapfile.csv @@ -26,7 +26,7 @@ GenuineIntel-6-1[AEF],v4,nehalemep,core GenuineIntel-6-2E,v4,nehalemex,core GenuineIntel-6-A7,v1.02,rocketlake,core GenuineIntel-6-2A,v19,sandybridge,core -GenuineIntel-6-8F,v1.17,sapphirerapids,core +GenuineIntel-6-8F,v1.20,sapphirerapids,core GenuineIntel-6-AF,v1.01,sierraforest,core GenuineIntel-6-(37|4A|4C|4D|5A),v15,silvermont,core GenuineIntel-6-(4E|5E|8E|9E|A5|A6),v58,skylake,core diff --git a/tools/perf/pmu-events/arch/x86/sapphirerapids/cache.json b/tools/perf/pmu-events/arch/x86/sapphirerapids/cache.json index 9606e76b98d6..b0447aad0dfc 100644 --- a/tools/perf/pmu-events/arch/x86/sapphirerapids/cache.json +++ b/tools/perf/pmu-events/arch/x86/sapphirerapids/cache.json @@ -432,6 +432,7 @@ "BriefDescription": "Retired load instructions with remote Intel(R) Optane(TM) DC persistent memory as the data source where the data request missed all caches.", "EventCode": "0xd3", "EventName": "MEM_LOAD_L3_MISS_RETIRED.REMOTE_PMM", + "PEBS": "1", "PublicDescription": "Counts retired load instructions with remote Intel(R) Optane(TM) DC persistent memory as the data source and the data request missed L3.", "SampleAfterValue": "100007", "UMask": "0x10" diff --git a/tools/perf/pmu-events/arch/x86/sapphirerapids/frontend.json b/tools/perf/pmu-events/arch/x86/sapphirerapids/frontend.json index 9e53da55d0c1..93d99318a623 100644 --- a/tools/perf/pmu-events/arch/x86/sapphirerapids/frontend.json +++ b/tools/perf/pmu-events/arch/x86/sapphirerapids/frontend.json @@ -267,7 +267,7 @@ "CounterMask": "6", "EventCode": "0x79", "EventName": "IDQ.DSB_CYCLES_OK", - "PublicDescription": "Counts the number of cycles where optimal number of uops was delivered to the Instruction Decode Queue (IDQ) from the MITE (legacy decode pipeline) path. During these cycles uops are not being delivered from the Decode Stream Buffer (DSB).", + "PublicDescription": "Counts the number of cycles where optimal number of uops was delivered to the Instruction Decode Queue (IDQ) from the DSB (Decode Stream Buffer) path. Count includes uops that may 'bypass' the IDQ.", "SampleAfterValue": "2000003", "UMask": "0x8" }, diff --git a/tools/perf/pmu-events/arch/x86/sapphirerapids/memory.json b/tools/perf/pmu-events/arch/x86/sapphirerapids/memory.json index e8bf7c9c44e1..5420f529f491 100644 --- a/tools/perf/pmu-events/arch/x86/sapphirerapids/memory.json +++ b/tools/perf/pmu-events/arch/x86/sapphirerapids/memory.json @@ -264,6 +264,7 @@ "BriefDescription": "Number of times an RTM execution aborted.", "EventCode": "0xc9", "EventName": "RTM_RETIRED.ABORTED", + "PEBS": "1", "PublicDescription": "Counts the number of times RTM abort was triggered.", "SampleAfterValue": "100003", "UMask": "0x4" diff --git a/tools/perf/pmu-events/arch/x86/sapphirerapids/pipeline.json b/tools/perf/pmu-events/arch/x86/sapphirerapids/pipeline.json index 2cfe814d2015..e2086bedeca8 100644 --- a/tools/perf/pmu-events/arch/x86/sapphirerapids/pipeline.json +++ b/tools/perf/pmu-events/arch/x86/sapphirerapids/pipeline.json @@ -1,20 +1,4 @@ [ - { - "BriefDescription": "AMX retired arithmetic BF16 operations.", - "EventCode": "0xce", - "EventName": "AMX_OPS_RETIRED.BF16", - "PublicDescription": "Number of AMX-based retired arithmetic bfloat16 (BF16) floating-point operations. Counts TDPBF16PS FP instructions. SW to use operation multiplier of 4", - "SampleAfterValue": "1000003", - "UMask": "0x2" - }, - { - "BriefDescription": "AMX retired arithmetic integer 8-bit operations.", - "EventCode": "0xce", - "EventName": "AMX_OPS_RETIRED.INT8", - "PublicDescription": "Number of AMX-based retired arithmetic integer operations of 8-bit width source operands. Counts TDPB[SS,UU,US,SU]D instructions. SW should use operation multiplier of 8.", - "SampleAfterValue": "1000003", - "UMask": "0x1" - }, { "BriefDescription": "This event is deprecated. Refer to new event ARITH.DIV_ACTIVE", "CounterMask": "1", @@ -444,6 +428,7 @@ "BriefDescription": "INST_RETIRED.MACRO_FUSED", "EventCode": "0xc0", "EventName": "INST_RETIRED.MACRO_FUSED", + "PEBS": "1", "SampleAfterValue": "2000003", "UMask": "0x10" }, @@ -451,6 +436,7 @@ "BriefDescription": "Retired NOP instructions.", "EventCode": "0xc0", "EventName": "INST_RETIRED.NOP", + "PEBS": "1", "PublicDescription": "Counts all retired NOP or ENDBR32/64 instructions", "SampleAfterValue": "2000003", "UMask": "0x2" @@ -467,6 +453,7 @@ "BriefDescription": "Iterations of Repeat string retired instructions.", "EventCode": "0xc0", "EventName": "INST_RETIRED.REP_ITERATION", + "PEBS": "1", "PublicDescription": "Number of iterations of Repeat (REP) string retired instructions such as MOVS, CMPS, and SCAS. Each has a byte, word, and doubleword version and string instructions can be repeated using a repetition prefix, REP, that allows their architectural execution to be repeated a number of times as specified by the RCX register. Note the number of iterations is implementation-dependent.", "SampleAfterValue": "2000003", "UMask": "0x8" diff --git a/tools/perf/pmu-events/arch/x86/sapphirerapids/uncore-cache.json b/tools/perf/pmu-events/arch/x86/sapphirerapids/uncore-cache.json index cf6fa70f37c1..25a2b9695135 100644 --- a/tools/perf/pmu-events/arch/x86/sapphirerapids/uncore-cache.json +++ b/tools/perf/pmu-events/arch/x86/sapphirerapids/uncore-cache.json @@ -4143,6 +4143,42 @@ "UMask": "0xcd43ff04", "Unit": "CHA" }, + { + "BriefDescription": "ItoMCacheNear (partial write) transactions from an IO device that addresses memory on the local socket", + "EventCode": "0x35", + "EventName": "UNC_CHA_TOR_INSERTS.IO_ITOMCACHENEAR_LOCAL", + "PerPkg": "1", + "PublicDescription": "TOR Inserts : ItoMCacheNears, indicating a partial write request, from IO Devices that missed the LLC : Counts the number of entries successfully inserted into the TOR that match qualifications specified by the subevent. Does not include addressless requests such as locks and interrupts.", + "UMask": "0xcd42ff04", + "Unit": "CHA" + }, + { + "BriefDescription": "ItoMCacheNear (partial write) transactions from an IO device that addresses memory on a remote socket", + "EventCode": "0x35", + "EventName": "UNC_CHA_TOR_INSERTS.IO_ITOMCACHENEAR_REMOTE", + "PerPkg": "1", + "PublicDescription": "TOR Inserts : ItoMCacheNears, indicating a partial write request, from IO Devices that missed the LLC : Counts the number of entries successfully inserted into the TOR that match qualifications specified by the subevent. Does not include addressless requests such as locks and interrupts.", + "UMask": "0xcd437f04", + "Unit": "CHA" + }, + { + "BriefDescription": "ItoM (write) transactions from an IO device that addresses memory on the local socket", + "EventCode": "0x35", + "EventName": "UNC_CHA_TOR_INSERTS.IO_ITOM_LOCAL", + "PerPkg": "1", + "PublicDescription": "Counts the number of entries successfully inserted into the TOR that match qualifications specified by the subevent. Does not include addressless requests such as locks and interrupts.", + "UMask": "0xcc42ff04", + "Unit": "CHA" + }, + { + "BriefDescription": "ItoM (write) transactions from an IO device that addresses memory on a remote socket", + "EventCode": "0x35", + "EventName": "UNC_CHA_TOR_INSERTS.IO_ITOM_REMOTE", + "PerPkg": "1", + "PublicDescription": "Counts the number of entries successfully inserted into the TOR that match qualifications specified by the subevent. Does not include addressless requests such as locks and interrupts.", + "UMask": "0xcc437f04", + "Unit": "CHA" + }, { "BriefDescription": "TOR Inserts; Misses from local IO", "EventCode": "0x35", @@ -4153,7 +4189,7 @@ "Unit": "CHA" }, { - "BriefDescription": "TOR Inserts; ItoM misses from local IO", + "BriefDescription": "TOR Inserts : ItoM, indicating a full cacheline write request, from IO Devices that missed the LLC", "EventCode": "0x35", "EventName": "UNC_CHA_TOR_INSERTS.IO_MISS_ITOM", "PerPkg": "1", @@ -4171,7 +4207,7 @@ "Unit": "CHA" }, { - "BriefDescription": "TOR Inserts; RdCur and FsRdCur misses from local IO", + "BriefDescription": "TOR Inserts; RdCur and FsRdCur requests from local IO that miss LLC", "EventCode": "0x35", "EventName": "UNC_CHA_TOR_INSERTS.IO_MISS_PCIRDCUR", "PerPkg": "1", @@ -4197,6 +4233,24 @@ "UMask": "0xc8f3ff04", "Unit": "CHA" }, + { + "BriefDescription": "PCIRDCUR (read) transactions from an IO device that addresses memory on a remote socket", + "EventCode": "0x35", + "EventName": "UNC_CHA_TOR_INSERTS.IO_PCIRDCUR_LOCAL", + "PerPkg": "1", + "PublicDescription": "Counts the number of entries successfully inserted into the TOR that match qualifications specified by the subevent. Does not include addressless requests such as locks and interrupts.", + "UMask": "0xc8f2ff04", + "Unit": "CHA" + }, + { + "BriefDescription": "PCIRDCUR (read) transactions from an IO device that addresses memory on the local socket", + "EventCode": "0x35", + "EventName": "UNC_CHA_TOR_INSERTS.IO_PCIRDCUR_REMOTE", + "PerPkg": "1", + "PublicDescription": "Counts the number of entries successfully inserted into the TOR that match qualifications specified by the subevent. Does not include addressless requests such as locks and interrupts.", + "UMask": "0xc8f37f04", + "Unit": "CHA" + }, { "BriefDescription": "TOR Inserts; RFO from local IO", "EventCode": "0x35", @@ -5565,6 +5619,42 @@ "UMask": "0xcd43fe04", "Unit": "CHA" }, + { + "BriefDescription": "TOR Occupancy : ItoMCacheNears, indicating a partial write request, from IO Devices that missed the LLC and targets local memory", + "EventCode": "0x36", + "EventName": "UNC_CHA_TOR_OCCUPANCY.IO_MISS_ITOMCACHENEAR_LOCAL", + "PerPkg": "1", + "PublicDescription": "For each cycle, this event accumulates the number of valid entries in the TOR that match qualifications specified by the subevent. Does not include addressless requests such as locks and interrupts.", + "UMask": "0xcd42fe04", + "Unit": "CHA" + }, + { + "BriefDescription": "TOR Occupancy : ItoMCacheNears, indicating a partial write request, from IO Devices that missed the LLC and targets remote memory", + "EventCode": "0x36", + "EventName": "UNC_CHA_TOR_OCCUPANCY.IO_MISS_ITOMCACHENEAR_REMOTE", + "PerPkg": "1", + "PublicDescription": "For each cycle, this event accumulates the number of valid entries in the TOR that match qualifications specified by the subevent. Does not include addressless requests such as locks and interrupts.", + "UMask": "0xcd437e04", + "Unit": "CHA" + }, + { + "BriefDescription": "TOR Occupancy; ITOM misses from local IO and targets local memory", + "EventCode": "0x36", + "EventName": "UNC_CHA_TOR_OCCUPANCY.IO_MISS_ITOM_LOCAL", + "PerPkg": "1", + "PublicDescription": "For each cycle, this event accumulates the number of valid entries in the TOR that match qualifications specified by the subevent. Does not include addressless requests such as locks and interrupts.", + "UMask": "0xcc42fe04", + "Unit": "CHA" + }, + { + "BriefDescription": "TOR Occupancy; ITOM misses from local IO and targets remote memory", + "EventCode": "0x36", + "EventName": "UNC_CHA_TOR_OCCUPANCY.IO_MISS_ITOM_REMOTE", + "PerPkg": "1", + "PublicDescription": "For each cycle, this event accumulates the number of valid entries in the TOR that match qualifications specified by the subevent. Does not include addressless requests such as locks and interrupts.", + "UMask": "0xcc437e04", + "Unit": "CHA" + }, { "BriefDescription": "TOR Occupancy; RdCur and FsRdCur misses from local IO", "EventCode": "0x36", @@ -5574,6 +5664,24 @@ "UMask": "0xc8f3fe04", "Unit": "CHA" }, + { + "BriefDescription": "TOR Occupancy; RdCur and FsRdCur misses from local IO and targets local memory", + "EventCode": "0x36", + "EventName": "UNC_CHA_TOR_OCCUPANCY.IO_MISS_PCIRDCUR_LOCAL", + "PerPkg": "1", + "PublicDescription": "For each cycle, this event accumulates the number of valid entries in the TOR that match qualifications specified by the subevent. Does not include addressless requests such as locks and interrupts.", + "UMask": "0xc8f2fe04", + "Unit": "CHA" + }, + { + "BriefDescription": "TOR Occupancy; RdCur and FsRdCur misses from local IO and targets remote memory", + "EventCode": "0x36", + "EventName": "UNC_CHA_TOR_OCCUPANCY.IO_MISS_PCIRDCUR_REMOTE", + "PerPkg": "1", + "PublicDescription": "For each cycle, this event accumulates the number of valid entries in the TOR that match qualifications specified by the subevent. Does not include addressless requests such as locks and interrupts.", + "UMask": "0xc8f37e04", + "Unit": "CHA" + }, { "BriefDescription": "TOR Occupancy; RFO misses from local IO", "EventCode": "0x36", diff --git a/tools/perf/pmu-events/arch/x86/sapphirerapids/uncore-interconnect.json b/tools/perf/pmu-events/arch/x86/sapphirerapids/uncore-interconnect.json index 65d088556bae..22bb490e9666 100644 --- a/tools/perf/pmu-events/arch/x86/sapphirerapids/uncore-interconnect.json +++ b/tools/perf/pmu-events/arch/x86/sapphirerapids/uncore-interconnect.json @@ -4888,7 +4888,7 @@ "Unit": "MDF" }, { - "BriefDescription": "Number of cycles incoming messages from the vertical ring that are bounced at the SBO\r\nIngress (V-EMIB) (AD)", + "BriefDescription": "Number of cycles incoming messages from the vertical ring that are bounced at the SBO Ingress (V-EMIB) (AD)", "EventCode": "0x4B", "EventName": "UNC_MDF_CRS_TxR_V_BOUNCES.AD", "PerPkg": "1", @@ -4897,7 +4897,7 @@ "Unit": "MDF" }, { - "BriefDescription": "Number of cycles incoming messages from the vertical ring that are bounced at the SBO\r\nIngress (V-EMIB) (AK)", + "BriefDescription": "Number of cycles incoming messages from the vertical ring that are bounced at the SBO Ingress (V-EMIB) (AK)", "EventCode": "0x4B", "EventName": "UNC_MDF_CRS_TxR_V_BOUNCES.AK", "PerPkg": "1", @@ -4906,7 +4906,7 @@ "Unit": "MDF" }, { - "BriefDescription": "Number of cycles incoming messages from the vertical ring that are bounced at the SBO\r\nIngress (V-EMIB) (AKC)", + "BriefDescription": "Number of cycles incoming messages from the vertical ring that are bounced at the SBO Ingress (V-EMIB) (AKC)", "EventCode": "0x4B", "EventName": "UNC_MDF_CRS_TxR_V_BOUNCES.AKC", "PerPkg": "1", @@ -4915,7 +4915,7 @@ "Unit": "MDF" }, { - "BriefDescription": "Number of cycles incoming messages from the vertical ring that are bounced at the SBO\r\nIngress (V-EMIB) (BL)", + "BriefDescription": "Number of cycles incoming messages from the vertical ring that are bounced at the SBO Ingress (V-EMIB) (BL)", "EventCode": "0x4B", "EventName": "UNC_MDF_CRS_TxR_V_BOUNCES.BL", "PerPkg": "1", @@ -4924,7 +4924,7 @@ "Unit": "MDF" }, { - "BriefDescription": "Number of cycles incoming messages from the vertical ring that are bounced at the SBO\r\nIngress (V-EMIB) (IV)", + "BriefDescription": "Number of cycles incoming messages from the vertical ring that are bounced at the SBO Ingress (V-EMIB) (IV)", "EventCode": "0x4B", "EventName": "UNC_MDF_CRS_TxR_V_BOUNCES.IV", "PerPkg": "1", @@ -5291,7 +5291,7 @@ "EventCode": "0x05", "EventName": "UNC_UPI_RxL_BASIC_HDR_MATCH.NCB", "PerPkg": "1", - "PublicDescription": "Matches on Receive path of a UPI Port : Non-Coherent Bypass : Matches on Receive path of a UPI port.\r\nMatch based on UMask specific bits:\r\nZ: Message Class (3-bit)\r\nY: Message Class Enable\r\nW: Opcode (4-bit)\r\nV: Opcode Enable\r\nU: Local Enable\r\nT: Remote Enable\r\nS: Data Hdr Enable\r\nR: Non-Data Hdr Enable\r\nQ: Dual Slot Hdr Enable\r\nP: Single Slot Hdr Enable\r\nLink Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases.\r\nNote: If Message Class is disabled, we expect opcode to also be disabled.", + "PublicDescription": "Matches on Receive path of a UPI Port : Non-Coherent Bypass : Matches on Receive path of a UPI port. Match based on UMask specific bits: Z: Message Class (3-bit) Y: Message Class Enable W: Opcode (4-bit) V: Opcode Enable U: Local Enable T: Remote Enable S: Data Hdr Enable R: Non-Data Hdr Enable Q: Dual Slot Hdr Enable P: Single Slot Hdr Enable Link Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases. Note: If Message Class is disabled, we expect opcode to also be disabled.", "UMask": "0xe", "Unit": "UPI" }, @@ -5300,7 +5300,7 @@ "EventCode": "0x05", "EventName": "UNC_UPI_RxL_BASIC_HDR_MATCH.NCB_OPC", "PerPkg": "1", - "PublicDescription": "Matches on Receive path of a UPI Port : Non-Coherent Bypass, Match Opcode : Matches on Receive path of a UPI port.\r\nMatch based on UMask specific bits:\r\nZ: Message Class (3-bit)\r\nY: Message Class Enable\r\nW: Opcode (4-bit)\r\nV: Opcode Enable\r\nU: Local Enable\r\nT: Remote Enable\r\nS: Data Hdr Enable\r\nR: Non-Data Hdr Enable\r\nQ: Dual Slot Hdr Enable\r\nP: Single Slot Hdr Enable\r\nLink Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases.\r\nNote: If Message Class is disabled, we expect opcode to also be disabled.", + "PublicDescription": "Matches on Receive path of a UPI Port : Non-Coherent Bypass, Match Opcode : Matches on Receive path of a UPI port. Match based on UMask specific bits: Z: Message Class (3-bit) Y: Message Class Enable W: Opcode (4-bit) V: Opcode Enable U: Local Enable T: Remote Enable S: Data Hdr Enable R: Non-Data Hdr Enable Q: Dual Slot Hdr Enable P: Single Slot Hdr Enable Link Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases. Note: If Message Class is disabled, we expect opcode to also be disabled.", "UMask": "0x10e", "Unit": "UPI" }, @@ -5309,7 +5309,7 @@ "EventCode": "0x05", "EventName": "UNC_UPI_RxL_BASIC_HDR_MATCH.NCS", "PerPkg": "1", - "PublicDescription": "Matches on Receive path of a UPI Port : Non-Coherent Standard : Matches on Receive path of a UPI port.\r\nMatch based on UMask specific bits:\r\nZ: Message Class (3-bit)\r\nY: Message Class Enable\r\nW: Opcode (4-bit)\r\nV: Opcode Enable\r\nU: Local Enable\r\nT: Remote Enable\r\nS: Data Hdr Enable\r\nR: Non-Data Hdr Enable\r\nQ: Dual Slot Hdr Enable\r\nP: Single Slot Hdr Enable\r\nLink Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases.\r\nNote: If Message Class is disabled, we expect opcode to also be disabled.", + "PublicDescription": "Matches on Receive path of a UPI Port : Non-Coherent Standard : Matches on Receive path of a UPI port. Match based on UMask specific bits: Z: Message Class (3-bit) Y: Message Class Enable W: Opcode (4-bit) V: Opcode Enable U: Local Enable T: Remote Enable S: Data Hdr Enable R: Non-Data Hdr Enable Q: Dual Slot Hdr Enable P: Single Slot Hdr Enable Link Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases. Note: If Message Class is disabled, we expect opcode to also be disabled.", "UMask": "0xf", "Unit": "UPI" }, @@ -5318,7 +5318,7 @@ "EventCode": "0x05", "EventName": "UNC_UPI_RxL_BASIC_HDR_MATCH.NCS_OPC", "PerPkg": "1", - "PublicDescription": "Matches on Receive path of a UPI Port : Non-Coherent Standard, Match Opcode : Matches on Receive path of a UPI port.\r\nMatch based on UMask specific bits:\r\nZ: Message Class (3-bit)\r\nY: Message Class Enable\r\nW: Opcode (4-bit)\r\nV: Opcode Enable\r\nU: Local Enable\r\nT: Remote Enable\r\nS: Data Hdr Enable\r\nR: Non-Data Hdr Enable\r\nQ: Dual Slot Hdr Enable\r\nP: Single Slot Hdr Enable\r\nLink Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases.\r\nNote: If Message Class is disabled, we expect opcode to also be disabled.", + "PublicDescription": "Matches on Receive path of a UPI Port : Non-Coherent Standard, Match Opcode : Matches on Receive path of a UPI port. Match based on UMask specific bits: Z: Message Class (3-bit) Y: Message Class Enable W: Opcode (4-bit) V: Opcode Enable U: Local Enable T: Remote Enable S: Data Hdr Enable R: Non-Data Hdr Enable Q: Dual Slot Hdr Enable P: Single Slot Hdr Enable Link Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases. Note: If Message Class is disabled, we expect opcode to also be disabled.", "UMask": "0x10f", "Unit": "UPI" }, @@ -5763,7 +5763,7 @@ "EventCode": "0x04", "EventName": "UNC_UPI_TxL_BASIC_HDR_MATCH.NCB", "PerPkg": "1", - "PublicDescription": "Matches on Transmit path of a UPI Port : Non-Coherent Bypass : Matches on Transmit path of a UPI port.\r\nMatch based on UMask specific bits:\r\nZ: Message Class (3-bit)\r\nY: Message Class Enable\r\nW: Opcode (4-bit)\r\nV: Opcode Enable\r\nU: Local Enable\r\nT: Remote Enable\r\nS: Data Hdr Enable\r\nR: Non-Data Hdr Enable\r\nQ: Dual Slot Hdr Enable\r\nP: Single Slot Hdr Enable\r\nLink Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases.\r\nNote: If Message Class is disabled, we expect opcode to also be disabled.", + "PublicDescription": "Matches on Transmit path of a UPI Port : Non-Coherent Bypass : Matches on Transmit path of a UPI port. Match based on UMask specific bits: Z: Message Class (3-bit) Y: Message Class Enable W: Opcode (4-bit) V: Opcode Enable U: Local Enable T: Remote Enable S: Data Hdr Enable R: Non-Data Hdr Enable Q: Dual Slot Hdr Enable P: Single Slot Hdr Enable Link Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases. Note: If Message Class is disabled, we expect opcode to also be disabled.", "UMask": "0xe", "Unit": "UPI" }, @@ -5772,7 +5772,7 @@ "EventCode": "0x04", "EventName": "UNC_UPI_TxL_BASIC_HDR_MATCH.NCB_OPC", "PerPkg": "1", - "PublicDescription": "Matches on Transmit path of a UPI Port : Non-Coherent Bypass, Match Opcode : Matches on Transmit path of a UPI port.\r\nMatch based on UMask specific bits:\r\nZ: Message Class (3-bit)\r\nY: Message Class Enable\r\nW: Opcode (4-bit)\r\nV: Opcode Enable\r\nU: Local Enable\r\nT: Remote Enable\r\nS: Data Hdr Enable\r\nR: Non-Data Hdr Enable\r\nQ: Dual Slot Hdr Enable\r\nP: Single Slot Hdr Enable\r\nLink Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases.\r\nNote: If Message Class is disabled, we expect opcode to also be disabled.", + "PublicDescription": "Matches on Transmit path of a UPI Port : Non-Coherent Bypass, Match Opcode : Matches on Transmit path of a UPI port. Match based on UMask specific bits: Z: Message Class (3-bit) Y: Message Class Enable W: Opcode (4-bit) V: Opcode Enable U: Local Enable T: Remote Enable S: Data Hdr Enable R: Non-Data Hdr Enable Q: Dual Slot Hdr Enable P: Single Slot Hdr Enable Link Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases. Note: If Message Class is disabled, we expect opcode to also be disabled.", "UMask": "0x10e", "Unit": "UPI" }, @@ -5781,7 +5781,7 @@ "EventCode": "0x04", "EventName": "UNC_UPI_TxL_BASIC_HDR_MATCH.NCS", "PerPkg": "1", - "PublicDescription": "Matches on Transmit path of a UPI Port : Non-Coherent Standard : Matches on Transmit path of a UPI port.\r\nMatch based on UMask specific bits:\r\nZ: Message Class (3-bit)\r\nY: Message Class Enable\r\nW: Opcode (4-bit)\r\nV: Opcode Enable\r\nU: Local Enable\r\nT: Remote Enable\r\nS: Data Hdr Enable\r\nR: Non-Data Hdr Enable\r\nQ: Dual Slot Hdr Enable\r\nP: Single Slot Hdr Enable\r\nLink Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases.\r\nNote: If Message Class is disabled, we expect opcode to also be disabled.", + "PublicDescription": "Matches on Transmit path of a UPI Port : Non-Coherent Standard : Matches on Transmit path of a UPI port. Match based on UMask specific bits: Z: Message Class (3-bit) Y: Message Class Enable W: Opcode (4-bit) V: Opcode Enable U: Local Enable T: Remote Enable S: Data Hdr Enable R: Non-Data Hdr Enable Q: Dual Slot Hdr Enable P: Single Slot Hdr Enable Link Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases. Note: If Message Class is disabled, we expect opcode to also be disabled.", "UMask": "0xf", "Unit": "UPI" }, @@ -5790,7 +5790,7 @@ "EventCode": "0x04", "EventName": "UNC_UPI_TxL_BASIC_HDR_MATCH.NCS_OPC", "PerPkg": "1", - "PublicDescription": "Matches on Transmit path of a UPI Port : Non-Coherent Standard, Match Opcode : Matches on Transmit path of a UPI port.\r\nMatch based on UMask specific bits:\r\nZ: Message Class (3-bit)\r\nY: Message Class Enable\r\nW: Opcode (4-bit)\r\nV: Opcode Enable\r\nU: Local Enable\r\nT: Remote Enable\r\nS: Data Hdr Enable\r\nR: Non-Data Hdr Enable\r\nQ: Dual Slot Hdr Enable\r\nP: Single Slot Hdr Enable\r\nLink Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases.\r\nNote: If Message Class is disabled, we expect opcode to also be disabled.", + "PublicDescription": "Matches on Transmit path of a UPI Port : Non-Coherent Standard, Match Opcode : Matches on Transmit path of a UPI port. Match based on UMask specific bits: Z: Message Class (3-bit) Y: Message Class Enable W: Opcode (4-bit) V: Opcode Enable U: Local Enable T: Remote Enable S: Data Hdr Enable R: Non-Data Hdr Enable Q: Dual Slot Hdr Enable P: Single Slot Hdr Enable Link Layer control types are excluded (LL CTRL, slot NULL, LLCRD) even under specific opcode match_en cases. Note: If Message Class is disabled, we expect opcode to also be disabled.", "UMask": "0x10f", "Unit": "UPI" }, -- cgit v1.2.3-59-g8ed1b From bf270b15c0e73bbd150f9010f601257952279d5c Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Wed, 20 Mar 2024 23:00:12 -0700 Subject: perf vendor events intel: Update sierraforest to 1.02 Update events from 1.01 to 1.02 as released in: https://github.com/intel/perfmon/commit/451dd41ae627b56433ad4065bf3632789eb70834 Various description updates. Adds topdown events TOPDOWN_BAD_SPECULATION.ALL_P, TOPDOWN_BE_BOUND.ALL_P, TOPDOWN_FE_BOUND.ALL_P and TOPDOWN_RETIRING.ALL_P. Reviewed-by: Kan Liang Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Caleb Biggers Cc: Edward Baker Cc: Ingo Molnar Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Perry Taylor Cc: Peter Zijlstra Cc: Samantha Alt Cc: Weilin Wang Link: https://lore.kernel.org/r/20240321060016.1464787-9-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/pmu-events/arch/x86/mapfile.csv | 2 +- .../pmu-events/arch/x86/sierraforest/pipeline.json | 36 +++++++++++++++++++--- 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/tools/perf/pmu-events/arch/x86/mapfile.csv b/tools/perf/pmu-events/arch/x86/mapfile.csv index e5de35c96358..ac32377ab01a 100644 --- a/tools/perf/pmu-events/arch/x86/mapfile.csv +++ b/tools/perf/pmu-events/arch/x86/mapfile.csv @@ -27,7 +27,7 @@ GenuineIntel-6-2E,v4,nehalemex,core GenuineIntel-6-A7,v1.02,rocketlake,core GenuineIntel-6-2A,v19,sandybridge,core GenuineIntel-6-8F,v1.20,sapphirerapids,core -GenuineIntel-6-AF,v1.01,sierraforest,core +GenuineIntel-6-AF,v1.02,sierraforest,core GenuineIntel-6-(37|4A|4C|4D|5A),v15,silvermont,core GenuineIntel-6-(4E|5E|8E|9E|A5|A6),v58,skylake,core GenuineIntel-6-55-[01234],v1.32,skylakex,core diff --git a/tools/perf/pmu-events/arch/x86/sierraforest/pipeline.json b/tools/perf/pmu-events/arch/x86/sierraforest/pipeline.json index ba9843110f07..90292dc03d33 100644 --- a/tools/perf/pmu-events/arch/x86/sierraforest/pipeline.json +++ b/tools/perf/pmu-events/arch/x86/sierraforest/pipeline.json @@ -249,10 +249,17 @@ "UMask": "0x1" }, { - "BriefDescription": "Counts the number of issue slots that were not consumed by the backend because allocation is stalled due to a mispredicted jump or a machine clear.", + "BriefDescription": "Counts the number of issue slots that were not consumed by the backend because allocation is stalled due to a mispredicted jump or a machine clear. [This event is alias to TOPDOWN_BAD_SPECULATION.ALL_P]", "EventCode": "0x73", "EventName": "TOPDOWN_BAD_SPECULATION.ALL", - "PublicDescription": "Counts the total number of issue slots that were not consumed by the backend because allocation is stalled due to a mispredicted jump or a machine clear. Only issue slots wasted due to fast nukes such as memory ordering nukes are counted. Other nukes are not accounted for. Counts all issue slots blocked during this recovery window, including relevant microcode flows, and while uops are not yet available in the instruction queue (IQ) or until an FE_BOUND event occurs besides OTHER and CISC. Also includes the issue slots that were consumed by the backend but were thrown away because they were younger than the mispredict or machine clear.", + "PublicDescription": "Counts the total number of issue slots that were not consumed by the backend because allocation is stalled due to a mispredicted jump or a machine clear. Only issue slots wasted due to fast nukes such as memory ordering nukes are counted. Other nukes are not accounted for. Counts all issue slots blocked during this recovery window, including relevant microcode flows, and while uops are not yet available in the instruction queue (IQ) or until an FE_BOUND event occurs besides OTHER and CISC. Also includes the issue slots that were consumed by the backend but were thrown away because they were younger than the mispredict or machine clear. [This event is alias to TOPDOWN_BAD_SPECULATION.ALL_P]", + "SampleAfterValue": "1000003" + }, + { + "BriefDescription": "Counts the number of issue slots that were not consumed by the backend because allocation is stalled due to a mispredicted jump or a machine clear. [This event is alias to TOPDOWN_BAD_SPECULATION.ALL]", + "EventCode": "0x73", + "EventName": "TOPDOWN_BAD_SPECULATION.ALL_P", + "PublicDescription": "Counts the total number of issue slots that were not consumed by the backend because allocation is stalled due to a mispredicted jump or a machine clear. Only issue slots wasted due to fast nukes such as memory ordering nukes are counted. Other nukes are not accounted for. Counts all issue slots blocked during this recovery window, including relevant microcode flows, and while uops are not yet available in the instruction queue (IQ) or until an FE_BOUND event occurs besides OTHER and CISC. Also includes the issue slots that were consumed by the backend but were thrown away because they were younger than the mispredict or machine clear. [This event is alias to TOPDOWN_BAD_SPECULATION.ALL]", "SampleAfterValue": "1000003" }, { @@ -284,7 +291,7 @@ "UMask": "0x1" }, { - "BriefDescription": "Counts the number of retirement slots not consumed due to backend stalls", + "BriefDescription": "Counts the number of retirement slots not consumed due to backend stalls [This event is alias to TOPDOWN_BE_BOUND.ALL_P]", "EventCode": "0x74", "EventName": "TOPDOWN_BE_BOUND.ALL", "SampleAfterValue": "1000003" @@ -296,6 +303,12 @@ "SampleAfterValue": "1000003", "UMask": "0x1" }, + { + "BriefDescription": "Counts the number of retirement slots not consumed due to backend stalls [This event is alias to TOPDOWN_BE_BOUND.ALL]", + "EventCode": "0x74", + "EventName": "TOPDOWN_BE_BOUND.ALL_P", + "SampleAfterValue": "1000003" + }, { "BriefDescription": "Counts the number of issue slots every cycle that were not consumed by the backend due to memory reservation stall (scheduler not being able to accept another uop). This could be caused by RSV full or load/store buffer block.", "EventCode": "0x74", @@ -332,11 +345,17 @@ "UMask": "0x10" }, { - "BriefDescription": "Counts the number of retirement slots not consumed due to front end stalls", + "BriefDescription": "Counts the number of retirement slots not consumed due to front end stalls [This event is alias to TOPDOWN_FE_BOUND.ALL_P]", "EventCode": "0x71", "EventName": "TOPDOWN_FE_BOUND.ALL", "SampleAfterValue": "1000003" }, + { + "BriefDescription": "Counts the number of retirement slots not consumed due to front end stalls [This event is alias to TOPDOWN_FE_BOUND.ALL]", + "EventCode": "0x71", + "EventName": "TOPDOWN_FE_BOUND.ALL_P", + "SampleAfterValue": "1000003" + }, { "BriefDescription": "Counts the number of issue slots every cycle that were not delivered by the frontend due to BAClear", "EventCode": "0x71", @@ -409,12 +428,19 @@ "UMask": "0x4" }, { - "BriefDescription": "Counts the number of consumed retirement slots. Similar to UOPS_RETIRED.ALL", + "BriefDescription": "Counts the number of consumed retirement slots. Similar to UOPS_RETIRED.ALL [This event is alias to TOPDOWN_RETIRING.ALL_P]", "EventCode": "0x72", "EventName": "TOPDOWN_RETIRING.ALL", "PEBS": "1", "SampleAfterValue": "1000003" }, + { + "BriefDescription": "Counts the number of consumed retirement slots. Similar to UOPS_RETIRED.ALL [This event is alias to TOPDOWN_RETIRING.ALL]", + "EventCode": "0x72", + "EventName": "TOPDOWN_RETIRING.ALL_P", + "PEBS": "1", + "SampleAfterValue": "1000003" + }, { "BriefDescription": "Counts the number of uops issued by the front end every cycle.", "EventCode": "0x0e", -- cgit v1.2.3-59-g8ed1b From d70cc755caef9c6f0ed05c9346df052decf250bd Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Wed, 20 Mar 2024 23:00:13 -0700 Subject: perf vendor events intel: Update skylakex to 1.33 Update events from 1.32 to 1.33 as released in: https://github.com/intel/perfmon/commit/3fe7390dd18496c35ec3a9cf17de0473fd5485cb Various description updates. Adds the event OFFCORE_RESPONSE.ALL_READS.L3_HIT.HIT_OTHER_CORE_FWD. Reviewed-by: Kan Liang Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Caleb Biggers Cc: Edward Baker Cc: Ingo Molnar Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Perry Taylor Cc: Peter Zijlstra Cc: Samantha Alt Cc: Weilin Wang Link: https://lore.kernel.org/r/20240321060016.1464787-10-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/pmu-events/arch/x86/mapfile.csv | 2 +- tools/perf/pmu-events/arch/x86/skylakex/cache.json | 9 +++++++++ tools/perf/pmu-events/arch/x86/skylakex/frontend.json | 10 +++++----- tools/perf/pmu-events/arch/x86/skylakex/memory.json | 2 +- tools/perf/pmu-events/arch/x86/skylakex/other.json | 2 +- tools/perf/pmu-events/arch/x86/skylakex/pipeline.json | 2 +- .../pmu-events/arch/x86/skylakex/uncore-interconnect.json | 14 +++++++------- tools/perf/pmu-events/arch/x86/skylakex/uncore-io.json | 2 +- .../perf/pmu-events/arch/x86/skylakex/virtual-memory.json | 2 +- 9 files changed, 27 insertions(+), 18 deletions(-) diff --git a/tools/perf/pmu-events/arch/x86/mapfile.csv b/tools/perf/pmu-events/arch/x86/mapfile.csv index ac32377ab01a..e67e7906b2cf 100644 --- a/tools/perf/pmu-events/arch/x86/mapfile.csv +++ b/tools/perf/pmu-events/arch/x86/mapfile.csv @@ -30,7 +30,7 @@ GenuineIntel-6-8F,v1.20,sapphirerapids,core GenuineIntel-6-AF,v1.02,sierraforest,core GenuineIntel-6-(37|4A|4C|4D|5A),v15,silvermont,core GenuineIntel-6-(4E|5E|8E|9E|A5|A6),v58,skylake,core -GenuineIntel-6-55-[01234],v1.32,skylakex,core +GenuineIntel-6-55-[01234],v1.33,skylakex,core GenuineIntel-6-86,v1.21,snowridgex,core GenuineIntel-6-8[CD],v1.15,tigerlake,core GenuineIntel-6-2C,v5,westmereep-dp,core diff --git a/tools/perf/pmu-events/arch/x86/skylakex/cache.json b/tools/perf/pmu-events/arch/x86/skylakex/cache.json index d28d8822a51a..14229f4b29d8 100644 --- a/tools/perf/pmu-events/arch/x86/skylakex/cache.json +++ b/tools/perf/pmu-events/arch/x86/skylakex/cache.json @@ -763,6 +763,15 @@ "SampleAfterValue": "100003", "UMask": "0x1" }, + { + "BriefDescription": "OFFCORE_RESPONSE.ALL_READS.L3_HIT.HIT_OTHER_CORE_FWD hit in the L3 and the snoop to one of the sibling cores hits the line in E/S/F state and the line is forwarded.", + "EventCode": "0xB7, 0xBB", + "EventName": "OFFCORE_RESPONSE.ALL_READS.L3_HIT.HIT_OTHER_CORE_FWD", + "MSRIndex": "0x1a6,0x1a7", + "MSRValue": "0x8003C07F7", + "SampleAfterValue": "100003", + "UMask": "0x1" + }, { "BriefDescription": "Counts all demand & prefetch RFOs that have any response type.", "EventCode": "0xB7, 0xBB", diff --git a/tools/perf/pmu-events/arch/x86/skylakex/frontend.json b/tools/perf/pmu-events/arch/x86/skylakex/frontend.json index 095904c77001..d6f543471b24 100644 --- a/tools/perf/pmu-events/arch/x86/skylakex/frontend.json +++ b/tools/perf/pmu-events/arch/x86/skylakex/frontend.json @@ -19,7 +19,7 @@ "BriefDescription": "Decode Stream Buffer (DSB)-to-MITE switches", "EventCode": "0xAB", "EventName": "DSB2MITE_SWITCHES.COUNT", - "PublicDescription": "This event counts the number of the Decode Stream Buffer (DSB)-to-MITE switches including all misses because of missing Decode Stream Buffer (DSB) cache and u-arch forced misses.\nNote: Invoking MITE requires two or three cycles delay.", + "PublicDescription": "This event counts the number of the Decode Stream Buffer (DSB)-to-MITE switches including all misses because of missing Decode Stream Buffer (DSB) cache and u-arch forced misses. Note: Invoking MITE requires two or three cycles delay.", "SampleAfterValue": "2000003", "UMask": "0x1" }, @@ -267,11 +267,11 @@ "UMask": "0x4" }, { - "BriefDescription": "Cycles Decode Stream Buffer (DSB) is delivering 4 Uops [This event is alias to IDQ.DSB_CYCLES_OK]", + "BriefDescription": "Cycles Decode Stream Buffer (DSB) is delivering 4 or more Uops [This event is alias to IDQ.DSB_CYCLES_OK]", "CounterMask": "4", "EventCode": "0x79", "EventName": "IDQ.ALL_DSB_CYCLES_4_UOPS", - "PublicDescription": "Counts the number of cycles 4 uops were delivered to Instruction Decode Queue (IDQ) from the Decode Stream Buffer (DSB) path. Count includes uops that may 'bypass' the IDQ. [This event is alias to IDQ.DSB_CYCLES_OK]", + "PublicDescription": "Counts the number of cycles 4 or more uops were delivered to Instruction Decode Queue (IDQ) from the Decode Stream Buffer (DSB) path. Count includes uops that may 'bypass' the IDQ. [This event is alias to IDQ.DSB_CYCLES_OK]", "SampleAfterValue": "2000003", "UMask": "0x18" }, @@ -321,11 +321,11 @@ "UMask": "0x18" }, { - "BriefDescription": "Cycles Decode Stream Buffer (DSB) is delivering 4 Uops [This event is alias to IDQ.ALL_DSB_CYCLES_4_UOPS]", + "BriefDescription": "Cycles Decode Stream Buffer (DSB) is delivering 4 or more Uops [This event is alias to IDQ.ALL_DSB_CYCLES_4_UOPS]", "CounterMask": "4", "EventCode": "0x79", "EventName": "IDQ.DSB_CYCLES_OK", - "PublicDescription": "Counts the number of cycles 4 uops were delivered to Instruction Decode Queue (IDQ) from the Decode Stream Buffer (DSB) path. Count includes uops that may 'bypass' the IDQ. [This event is alias to IDQ.ALL_DSB_CYCLES_4_UOPS]", + "PublicDescription": "Counts the number of cycles 4 or more uops were delivered to Instruction Decode Queue (IDQ) from the Decode Stream Buffer (DSB) path. Count includes uops that may 'bypass' the IDQ. [This event is alias to IDQ.ALL_DSB_CYCLES_4_UOPS]", "SampleAfterValue": "2000003", "UMask": "0x18" }, diff --git a/tools/perf/pmu-events/arch/x86/skylakex/memory.json b/tools/perf/pmu-events/arch/x86/skylakex/memory.json index 2b797dbc75fe..dba3cd6b3690 100644 --- a/tools/perf/pmu-events/arch/x86/skylakex/memory.json +++ b/tools/perf/pmu-events/arch/x86/skylakex/memory.json @@ -864,7 +864,7 @@ "BriefDescription": "Number of times an RTM execution aborted due to any reasons (multiple categories may count as one).", "EventCode": "0xC9", "EventName": "RTM_RETIRED.ABORTED", - "PEBS": "1", + "PEBS": "2", "PublicDescription": "Number of times RTM abort was triggered.", "SampleAfterValue": "2000003", "UMask": "0x4" diff --git a/tools/perf/pmu-events/arch/x86/skylakex/other.json b/tools/perf/pmu-events/arch/x86/skylakex/other.json index cda8a7a45f0c..2511d722327a 100644 --- a/tools/perf/pmu-events/arch/x86/skylakex/other.json +++ b/tools/perf/pmu-events/arch/x86/skylakex/other.json @@ -19,7 +19,7 @@ "BriefDescription": "Core cycles where the core was running in a manner where Turbo may be clipped to the AVX512 turbo schedule.", "EventCode": "0x28", "EventName": "CORE_POWER.LVL2_TURBO_LICENSE", - "PublicDescription": "Core cycles where the core was running with power-delivery for license level 2 (introduced in Skylake Server michroarchtecture). This includes high current AVX 512-bit instructions.", + "PublicDescription": "Core cycles where the core was running with power-delivery for license level 2 (introduced in Skylake Server microarchitecture). This includes high current AVX 512-bit instructions.", "SampleAfterValue": "200003", "UMask": "0x20" }, diff --git a/tools/perf/pmu-events/arch/x86/skylakex/pipeline.json b/tools/perf/pmu-events/arch/x86/skylakex/pipeline.json index 66d686cc933e..c50ddf5b40dd 100644 --- a/tools/perf/pmu-events/arch/x86/skylakex/pipeline.json +++ b/tools/perf/pmu-events/arch/x86/skylakex/pipeline.json @@ -396,7 +396,7 @@ "Errata": "SKL091, SKL044", "EventCode": "0xC0", "EventName": "INST_RETIRED.NOP", - "PEBS": "1", + "PEBS": "2", "SampleAfterValue": "2000003", "UMask": "0x2" }, diff --git a/tools/perf/pmu-events/arch/x86/skylakex/uncore-interconnect.json b/tools/perf/pmu-events/arch/x86/skylakex/uncore-interconnect.json index 3eece8a728b5..f32d4d9d283a 100644 --- a/tools/perf/pmu-events/arch/x86/skylakex/uncore-interconnect.json +++ b/tools/perf/pmu-events/arch/x86/skylakex/uncore-interconnect.json @@ -38,7 +38,7 @@ "EventCode": "0x10", "EventName": "UNC_I_COHERENT_OPS.CLFLUSH", "PerPkg": "1", - "PublicDescription": "Counts the number of coherency related operations servied by the IRP", + "PublicDescription": "Counts the number of coherency related operations serviced by the IRP", "UMask": "0x80", "Unit": "IRP" }, @@ -47,7 +47,7 @@ "EventCode": "0x10", "EventName": "UNC_I_COHERENT_OPS.CRD", "PerPkg": "1", - "PublicDescription": "Counts the number of coherency related operations servied by the IRP", + "PublicDescription": "Counts the number of coherency related operations serviced by the IRP", "UMask": "0x2", "Unit": "IRP" }, @@ -56,7 +56,7 @@ "EventCode": "0x10", "EventName": "UNC_I_COHERENT_OPS.DRD", "PerPkg": "1", - "PublicDescription": "Counts the number of coherency related operations servied by the IRP", + "PublicDescription": "Counts the number of coherency related operations serviced by the IRP", "UMask": "0x4", "Unit": "IRP" }, @@ -65,7 +65,7 @@ "EventCode": "0x10", "EventName": "UNC_I_COHERENT_OPS.PCIDCAHINT", "PerPkg": "1", - "PublicDescription": "Counts the number of coherency related operations servied by the IRP", + "PublicDescription": "Counts the number of coherency related operations serviced by the IRP", "UMask": "0x20", "Unit": "IRP" }, @@ -74,7 +74,7 @@ "EventCode": "0x10", "EventName": "UNC_I_COHERENT_OPS.PCIRDCUR", "PerPkg": "1", - "PublicDescription": "Counts the number of coherency related operations servied by the IRP", + "PublicDescription": "Counts the number of coherency related operations serviced by the IRP", "UMask": "0x1", "Unit": "IRP" }, @@ -101,7 +101,7 @@ "EventCode": "0x10", "EventName": "UNC_I_COHERENT_OPS.WBMTOI", "PerPkg": "1", - "PublicDescription": "Counts the number of coherency related operations servied by the IRP", + "PublicDescription": "Counts the number of coherency related operations serviced by the IRP", "UMask": "0x40", "Unit": "IRP" }, @@ -500,7 +500,7 @@ "EventCode": "0x11", "EventName": "UNC_I_TRANSACTIONS.WRITES", "PerPkg": "1", - "PublicDescription": "Counts the number of Inbound transactions from the IRP to the Uncore. This can be filtered based on request type in addition to the source queue. Note the special filtering equation. We do OR-reduction on the request type. If the SOURCE bit is set, then we also do AND qualification based on the source portID.; Trackes only write requests. Each write request should have a prefetch, so there is no need to explicitly track these requests. For writes that are tickled and have to retry, the counter will be incremented for each retry.", + "PublicDescription": "Counts the number of Inbound transactions from the IRP to the Uncore. This can be filtered based on request type in addition to the source queue. Note the special filtering equation. We do OR-reduction on the request type. If the SOURCE bit is set, then we also do AND qualification based on the source portID.; Tracks only write requests. Each write request should have a prefetch, so there is no need to explicitly track these requests. For writes that are tickled and have to retry, the counter will be incremented for each retry.", "UMask": "0x2", "Unit": "IRP" }, diff --git a/tools/perf/pmu-events/arch/x86/skylakex/uncore-io.json b/tools/perf/pmu-events/arch/x86/skylakex/uncore-io.json index 2a3a709018bb..743c91f3d2f0 100644 --- a/tools/perf/pmu-events/arch/x86/skylakex/uncore-io.json +++ b/tools/perf/pmu-events/arch/x86/skylakex/uncore-io.json @@ -34,7 +34,7 @@ "EventCode": "0x1", "EventName": "UNC_IIO_CLOCKTICKS", "PerPkg": "1", - "PublicDescription": "Counts clockticks of the 1GHz trafiic controller clock in the IIO unit.", + "PublicDescription": "Counts clockticks of the 1GHz traffic controller clock in the IIO unit.", "Unit": "IIO" }, { diff --git a/tools/perf/pmu-events/arch/x86/skylakex/virtual-memory.json b/tools/perf/pmu-events/arch/x86/skylakex/virtual-memory.json index f59405877ae8..73feadaf7674 100644 --- a/tools/perf/pmu-events/arch/x86/skylakex/virtual-memory.json +++ b/tools/perf/pmu-events/arch/x86/skylakex/virtual-memory.json @@ -205,7 +205,7 @@ "BriefDescription": "Counts 1 per cycle for each PMH that is busy with a page walk for an instruction fetch request. EPT page walk duration are excluded in Skylake.", "EventCode": "0x85", "EventName": "ITLB_MISSES.WALK_PENDING", - "PublicDescription": "Counts 1 per cycle for each PMH (Page Miss Handler) that is busy with a page walk for an instruction fetch request. EPT page walk duration are excluded in Skylake michroarchitecture.", + "PublicDescription": "Counts 1 per cycle for each PMH (Page Miss Handler) that is busy with a page walk for an instruction fetch request. EPT page walk duration are excluded in Skylake microarchitecture.", "SampleAfterValue": "100003", "UMask": "0x10" }, -- cgit v1.2.3-59-g8ed1b From 70e7028c5b94c8d71b8df27ab663cdd72185af44 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Wed, 20 Mar 2024 23:00:14 -0700 Subject: perf vendor events intel: Update skylake to v58 Update events from: https://github.com/intel/perfmon/commit/f2e5136e062a91ae554dc40530132e66f9271848 This change didn't increase the version number from v58. Updates various descriptions. Reviewed-by: Kan Liang Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Caleb Biggers Cc: Edward Baker Cc: Ingo Molnar Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Perry Taylor Cc: Peter Zijlstra Cc: Samantha Alt Cc: Weilin Wang Link: https://lore.kernel.org/r/20240321060016.1464787-11-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/pmu-events/arch/x86/skylake/frontend.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tools/perf/pmu-events/arch/x86/skylake/frontend.json b/tools/perf/pmu-events/arch/x86/skylake/frontend.json index 095904c77001..d6f543471b24 100644 --- a/tools/perf/pmu-events/arch/x86/skylake/frontend.json +++ b/tools/perf/pmu-events/arch/x86/skylake/frontend.json @@ -19,7 +19,7 @@ "BriefDescription": "Decode Stream Buffer (DSB)-to-MITE switches", "EventCode": "0xAB", "EventName": "DSB2MITE_SWITCHES.COUNT", - "PublicDescription": "This event counts the number of the Decode Stream Buffer (DSB)-to-MITE switches including all misses because of missing Decode Stream Buffer (DSB) cache and u-arch forced misses.\nNote: Invoking MITE requires two or three cycles delay.", + "PublicDescription": "This event counts the number of the Decode Stream Buffer (DSB)-to-MITE switches including all misses because of missing Decode Stream Buffer (DSB) cache and u-arch forced misses. Note: Invoking MITE requires two or three cycles delay.", "SampleAfterValue": "2000003", "UMask": "0x1" }, @@ -267,11 +267,11 @@ "UMask": "0x4" }, { - "BriefDescription": "Cycles Decode Stream Buffer (DSB) is delivering 4 Uops [This event is alias to IDQ.DSB_CYCLES_OK]", + "BriefDescription": "Cycles Decode Stream Buffer (DSB) is delivering 4 or more Uops [This event is alias to IDQ.DSB_CYCLES_OK]", "CounterMask": "4", "EventCode": "0x79", "EventName": "IDQ.ALL_DSB_CYCLES_4_UOPS", - "PublicDescription": "Counts the number of cycles 4 uops were delivered to Instruction Decode Queue (IDQ) from the Decode Stream Buffer (DSB) path. Count includes uops that may 'bypass' the IDQ. [This event is alias to IDQ.DSB_CYCLES_OK]", + "PublicDescription": "Counts the number of cycles 4 or more uops were delivered to Instruction Decode Queue (IDQ) from the Decode Stream Buffer (DSB) path. Count includes uops that may 'bypass' the IDQ. [This event is alias to IDQ.DSB_CYCLES_OK]", "SampleAfterValue": "2000003", "UMask": "0x18" }, @@ -321,11 +321,11 @@ "UMask": "0x18" }, { - "BriefDescription": "Cycles Decode Stream Buffer (DSB) is delivering 4 Uops [This event is alias to IDQ.ALL_DSB_CYCLES_4_UOPS]", + "BriefDescription": "Cycles Decode Stream Buffer (DSB) is delivering 4 or more Uops [This event is alias to IDQ.ALL_DSB_CYCLES_4_UOPS]", "CounterMask": "4", "EventCode": "0x79", "EventName": "IDQ.DSB_CYCLES_OK", - "PublicDescription": "Counts the number of cycles 4 uops were delivered to Instruction Decode Queue (IDQ) from the Decode Stream Buffer (DSB) path. Count includes uops that may 'bypass' the IDQ. [This event is alias to IDQ.ALL_DSB_CYCLES_4_UOPS]", + "PublicDescription": "Counts the number of cycles 4 or more uops were delivered to Instruction Decode Queue (IDQ) from the Decode Stream Buffer (DSB) path. Count includes uops that may 'bypass' the IDQ. [This event is alias to IDQ.ALL_DSB_CYCLES_4_UOPS]", "SampleAfterValue": "2000003", "UMask": "0x18" }, -- cgit v1.2.3-59-g8ed1b From 7bce27f8d33ac370f74a2f9c36608c2ce7cd2fa7 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Wed, 20 Mar 2024 23:00:15 -0700 Subject: perf vendor events intel: Update snowridgex to 1.22 Update events from 1.21 to 1.22 as released in: https://github.com/intel/perfmon/commit/ba4f96039f96231b51e3eb69d5a21e2b00f6de5b Updates various descriptions and removes the event UNC_IIO_NUM_REQ_FROM_CPU.IRP. Reviewed-by: Kan Liang Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Caleb Biggers Cc: Edward Baker Cc: Ingo Molnar Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Perry Taylor Cc: Peter Zijlstra Cc: Samantha Alt Cc: Weilin Wang Link: https://lore.kernel.org/r/20240321060016.1464787-12-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/pmu-events/arch/x86/mapfile.csv | 2 +- tools/perf/pmu-events/arch/x86/snowridgex/uncore-cache.json | 4 ++-- .../pmu-events/arch/x86/snowridgex/uncore-interconnect.json | 6 +++--- tools/perf/pmu-events/arch/x86/snowridgex/uncore-io.json | 11 ----------- 4 files changed, 6 insertions(+), 17 deletions(-) diff --git a/tools/perf/pmu-events/arch/x86/mapfile.csv b/tools/perf/pmu-events/arch/x86/mapfile.csv index e67e7906b2cf..c372e3594a69 100644 --- a/tools/perf/pmu-events/arch/x86/mapfile.csv +++ b/tools/perf/pmu-events/arch/x86/mapfile.csv @@ -31,7 +31,7 @@ GenuineIntel-6-AF,v1.02,sierraforest,core GenuineIntel-6-(37|4A|4C|4D|5A),v15,silvermont,core GenuineIntel-6-(4E|5E|8E|9E|A5|A6),v58,skylake,core GenuineIntel-6-55-[01234],v1.33,skylakex,core -GenuineIntel-6-86,v1.21,snowridgex,core +GenuineIntel-6-86,v1.22,snowridgex,core GenuineIntel-6-8[CD],v1.15,tigerlake,core GenuineIntel-6-2C,v5,westmereep-dp,core GenuineIntel-6-25,v4,westmereep-sp,core diff --git a/tools/perf/pmu-events/arch/x86/snowridgex/uncore-cache.json b/tools/perf/pmu-events/arch/x86/snowridgex/uncore-cache.json index a68a5bb05c22..4090e4da1bd0 100644 --- a/tools/perf/pmu-events/arch/x86/snowridgex/uncore-cache.json +++ b/tools/perf/pmu-events/arch/x86/snowridgex/uncore-cache.json @@ -1444,7 +1444,7 @@ "Unit": "CHA" }, { - "BriefDescription": "This event is deprecated. Refer to new event UNC_CHA_LLC_LOOKUP.DATA_READ_LOCAL", + "BriefDescription": "This event is deprecated.", "Deprecated": "1", "EventCode": "0x34", "EventName": "UNC_CHA_LLC_LOOKUP.DMND_READ_LOCAL", @@ -1638,7 +1638,7 @@ "Unit": "CHA" }, { - "BriefDescription": "This event is deprecated. Refer to new event UNC_CHA_LLC_LOOKUP.RFO_LOCAL", + "BriefDescription": "This event is deprecated.", "Deprecated": "1", "EventCode": "0x34", "EventName": "UNC_CHA_LLC_LOOKUP.RFO_PREF_LOCAL", diff --git a/tools/perf/pmu-events/arch/x86/snowridgex/uncore-interconnect.json b/tools/perf/pmu-events/arch/x86/snowridgex/uncore-interconnect.json index 7e2895f7fe3d..7cc3635b118b 100644 --- a/tools/perf/pmu-events/arch/x86/snowridgex/uncore-interconnect.json +++ b/tools/perf/pmu-events/arch/x86/snowridgex/uncore-interconnect.json @@ -38,7 +38,7 @@ "EventCode": "0x10", "EventName": "UNC_I_COHERENT_OPS.CLFLUSH", "PerPkg": "1", - "PublicDescription": "Coherent Ops : CLFlush : Counts the number of coherency related operations servied by the IRP", + "PublicDescription": "Coherent Ops : CLFlush : Counts the number of coherency related operations serviced by the IRP", "UMask": "0x80", "Unit": "IRP" }, @@ -65,7 +65,7 @@ "EventCode": "0x10", "EventName": "UNC_I_COHERENT_OPS.WBMTOI", "PerPkg": "1", - "PublicDescription": "Coherent Ops : WbMtoI : Counts the number of coherency related operations servied by the IRP", + "PublicDescription": "Coherent Ops : WbMtoI : Counts the number of coherency related operations serviced by the IRP", "UMask": "0x40", "Unit": "IRP" }, @@ -454,7 +454,7 @@ "EventCode": "0x11", "EventName": "UNC_I_TRANSACTIONS.WRITES", "PerPkg": "1", - "PublicDescription": "Inbound Transaction Count : Writes : Counts the number of Inbound transactions from the IRP to the Uncore. This can be filtered based on request type in addition to the source queue. Note the special filtering equation. We do OR-reduction on the request type. If the SOURCE bit is set, then we also do AND qualification based on the source portID. : Trackes only write requests. Each write request should have a prefetch, so there is no need to explicitly track these requests. For writes that are tickled and have to retry, the counter will be incremented for each retry.", + "PublicDescription": "Inbound Transaction Count : Writes : Counts the number of Inbound transactions from the IRP to the Uncore. This can be filtered based on request type in addition to the source queue. Note the special filtering equation. We do OR-reduction on the request type. If the SOURCE bit is set, then we also do AND qualification based on the source portID. : Tracks only write requests. Each write request should have a prefetch, so there is no need to explicitly track these requests. For writes that are tickled and have to retry, the counter will be incremented for each retry.", "UMask": "0x2", "Unit": "IRP" }, diff --git a/tools/perf/pmu-events/arch/x86/snowridgex/uncore-io.json b/tools/perf/pmu-events/arch/x86/snowridgex/uncore-io.json index ecdd6f0f8e8f..de156e499f56 100644 --- a/tools/perf/pmu-events/arch/x86/snowridgex/uncore-io.json +++ b/tools/perf/pmu-events/arch/x86/snowridgex/uncore-io.json @@ -2505,17 +2505,6 @@ "UMask": "0x10", "Unit": "IIO" }, - { - "BriefDescription": "Number requests sent to PCIe from main die : From IRP", - "EventCode": "0xC2", - "EventName": "UNC_IIO_NUM_REQ_FROM_CPU.IRP", - "FCMask": "0x07", - "PerPkg": "1", - "PortMask": "0xFF", - "PublicDescription": "Number requests sent to PCIe from main die : From IRP : Captures Posted/Non-posted allocations from IRP. i.e. either non-confined P2P traffic or from the CPU", - "UMask": "0x1", - "Unit": "IIO" - }, { "BriefDescription": "Number requests sent to PCIe from main die : From ITC", "EventCode": "0xC2", -- cgit v1.2.3-59-g8ed1b From af34a16d3090f8a2f7eac24290209dacb9471132 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Wed, 20 Mar 2024 23:00:16 -0700 Subject: perf vendor events intel: Remove info metrics erroneously in TopdownL1 Bug affected server metrics only. This doesn't impact default metrics but if the TopdownL1 metric group is specified. Passes on the fix in: https://github.com/intel/perfmon/commit/b09f0a3953234ec592b4a872b87764c78da05d8b Reviewed-by: Kan Liang Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Caleb Biggers Cc: Edward Baker Cc: Ingo Molnar Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Perry Taylor Cc: Peter Zijlstra Cc: Samantha Alt Cc: Weilin Wang Link: https://lore.kernel.org/r/20240321060016.1464787-13-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- .../arch/x86/broadwellx/bdx-metrics.json | 35 +++--- .../arch/x86/cascadelakex/clx-metrics.json | 85 ++++++--------- .../pmu-events/arch/x86/haswellx/hsx-metrics.json | 35 +++--- .../pmu-events/arch/x86/icelakex/icx-metrics.json | 95 +++++++--------- .../arch/x86/sapphirerapids/spr-metrics.json | 119 ++++++++------------- .../pmu-events/arch/x86/skylakex/skx-metrics.json | 85 ++++++--------- 6 files changed, 181 insertions(+), 273 deletions(-) diff --git a/tools/perf/pmu-events/arch/x86/broadwellx/bdx-metrics.json b/tools/perf/pmu-events/arch/x86/broadwellx/bdx-metrics.json index f2d378c9d68f..0aed533da882 100644 --- a/tools/perf/pmu-events/arch/x86/broadwellx/bdx-metrics.json +++ b/tools/perf/pmu-events/arch/x86/broadwellx/bdx-metrics.json @@ -732,9 +732,8 @@ { "BriefDescription": "Average Parallel L2 cache miss data reads", "MetricExpr": "tma_info_memory_latency_data_l2_mlp", - "MetricGroup": "Memory_BW;Offcore;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_data_l2_mlp", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Memory_BW;Offcore", + "MetricName": "tma_info_memory_data_l2_mlp" }, { "BriefDescription": "", @@ -745,9 +744,8 @@ { "BriefDescription": "Average per-core data fill bandwidth to the L1 data cache [GB / sec]", "MetricExpr": "64 * L1D.REPLACEMENT / 1e9 / (duration_time * 1e3 / 1e3)", - "MetricGroup": "Mem;MemoryBW;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_l1d_cache_fill_bw_2t", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Mem;MemoryBW", + "MetricName": "tma_info_memory_l1d_cache_fill_bw_2t" }, { "BriefDescription": "L1 cache true misses per kilo instruction for retired demand loads", @@ -764,9 +762,8 @@ { "BriefDescription": "Average per-core data fill bandwidth to the L2 cache [GB / sec]", "MetricExpr": "64 * L2_LINES_IN.ALL / 1e9 / (duration_time * 1e3 / 1e3)", - "MetricGroup": "Mem;MemoryBW;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_l2_cache_fill_bw_2t", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Mem;MemoryBW", + "MetricName": "tma_info_memory_l2_cache_fill_bw_2t" }, { "BriefDescription": "L2 cache hits per kilo instruction for all request types (including speculative)", @@ -807,9 +804,8 @@ { "BriefDescription": "Average per-core data fill bandwidth to the L3 cache [GB / sec]", "MetricExpr": "64 * LONGEST_LAT_CACHE.MISS / 1e9 / (duration_time * 1e3 / 1e3)", - "MetricGroup": "Mem;MemoryBW;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_l3_cache_fill_bw_2t", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Mem;MemoryBW", + "MetricName": "tma_info_memory_l3_cache_fill_bw_2t" }, { "BriefDescription": "L3 cache true misses per kilo instruction for retired demand loads", @@ -838,16 +834,14 @@ { "BriefDescription": "Average Latency for L2 cache miss demand Loads", "MetricExpr": "OFFCORE_REQUESTS_OUTSTANDING.DEMAND_DATA_RD / OFFCORE_REQUESTS.DEMAND_DATA_RD", - "MetricGroup": "Memory_Lat;Offcore;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_load_l2_miss_latency", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Memory_Lat;Offcore", + "MetricName": "tma_info_memory_load_l2_miss_latency" }, { "BriefDescription": "Average Parallel L2 cache miss demand Loads", "MetricExpr": "OFFCORE_REQUESTS_OUTSTANDING.DEMAND_DATA_RD / OFFCORE_REQUESTS_OUTSTANDING.CYCLES_WITH_DEMAND_DATA_RD", - "MetricGroup": "Memory_BW;Offcore;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_load_l2_mlp", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Memory_BW;Offcore", + "MetricName": "tma_info_memory_load_l2_mlp" }, { "BriefDescription": "Actual Average Latency for L1 data-cache miss demand load operations (in core cycles)", @@ -867,9 +861,8 @@ { "BriefDescription": "Utilization of the core's Page Walker(s) serving STLB misses triggered by instruction/Load/Store accesses", "MetricExpr": "tma_info_memory_tlb_page_walks_utilization", - "MetricGroup": "Mem;MemoryTLB;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_page_walks_utilization", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Mem;MemoryTLB", + "MetricName": "tma_info_memory_page_walks_utilization" }, { "BriefDescription": "Utilization of the core's Page Walker(s) serving STLB misses triggered by instruction/Load/Store accesses", diff --git a/tools/perf/pmu-events/arch/x86/cascadelakex/clx-metrics.json b/tools/perf/pmu-events/arch/x86/cascadelakex/clx-metrics.json index 7f88b156f73b..297046818efe 100644 --- a/tools/perf/pmu-events/arch/x86/cascadelakex/clx-metrics.json +++ b/tools/perf/pmu-events/arch/x86/cascadelakex/clx-metrics.json @@ -670,23 +670,20 @@ { "BriefDescription": "Probability of Core Bound bottleneck hidden by SMT-profiling artifacts", "MetricExpr": "(100 * (1 - tma_core_bound / (((EXE_ACTIVITY.EXE_BOUND_0_PORTS + tma_core_bound * RS_EVENTS.EMPTY_CYCLES) / CPU_CLK_UNHALTED.THREAD * (CYCLE_ACTIVITY.STALLS_TOTAL - CYCLE_ACTIVITY.STALLS_MEM_ANY) / CPU_CLK_UNHALTED.THREAD * CPU_CLK_UNHALTED.THREAD + (EXE_ACTIVITY.1_PORTS_UTIL + tma_retiring * EXE_ACTIVITY.2_PORTS_UTIL)) / CPU_CLK_UNHALTED.THREAD if ARITH.DIVIDER_ACTIVE < CYCLE_ACTIVITY.STALLS_TOTAL - CYCLE_ACTIVITY.STALLS_MEM_ANY else (EXE_ACTIVITY.1_PORTS_UTIL + tma_retiring * EXE_ACTIVITY.2_PORTS_UTIL) / CPU_CLK_UNHALTED.THREAD) if tma_core_bound < (((EXE_ACTIVITY.EXE_BOUND_0_PORTS + tma_core_bound * RS_EVENTS.EMPTY_CYCLES) / CPU_CLK_UNHALTED.THREAD * (CYCLE_ACTIVITY.STALLS_TOTAL - CYCLE_ACTIVITY.STALLS_MEM_ANY) / CPU_CLK_UNHALTED.THREAD * CPU_CLK_UNHALTED.THREAD + (EXE_ACTIVITY.1_PORTS_UTIL + tma_retiring * EXE_ACTIVITY.2_PORTS_UTIL)) / CPU_CLK_UNHALTED.THREAD if ARITH.DIVIDER_ACTIVE < CYCLE_ACTIVITY.STALLS_TOTAL - CYCLE_ACTIVITY.STALLS_MEM_ANY else (EXE_ACTIVITY.1_PORTS_UTIL + tma_retiring * EXE_ACTIVITY.2_PORTS_UTIL) / CPU_CLK_UNHALTED.THREAD) else 1) if tma_info_system_smt_2t_utilization > 0.5 else 0)", - "MetricGroup": "Cor;SMT;TopdownL1;tma_L1_group", - "MetricName": "tma_info_botlnk_core_bound_likely", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Cor;SMT", + "MetricName": "tma_info_botlnk_core_bound_likely" }, { "BriefDescription": "Total pipeline cost of DSB (uop cache) misses - subset of the Instruction_Fetch_BW Bottleneck.", "MetricExpr": "100 * (100 * (tma_fetch_latency * (DSB2MITE_SWITCHES.PENALTY_CYCLES / CPU_CLK_UNHALTED.THREAD) / ((ICACHE_16B.IFDATA_STALL + 2 * cpu@ICACHE_16B.IFDATA_STALL\\,cmask\\=0x1\\,edge\\=0x1@) / CPU_CLK_UNHALTED.THREAD + ICACHE_TAG.STALLS / CPU_CLK_UNHALTED.THREAD + (INT_MISC.CLEAR_RESTEER_CYCLES / CPU_CLK_UNHALTED.THREAD + 9 * BACLEARS.ANY / CPU_CLK_UNHALTED.THREAD) + min(2 * IDQ.MS_SWITCHES / CPU_CLK_UNHALTED.THREAD, 1) + DECODE.LCP / CPU_CLK_UNHALTED.THREAD + DSB2MITE_SWITCHES.PENALTY_CYCLES / CPU_CLK_UNHALTED.THREAD) + tma_fetch_bandwidth * tma_mite / (tma_mite + tma_dsb)))", - "MetricGroup": "DSBmiss;Fed;TopdownL1;tma_L1_group", - "MetricName": "tma_info_botlnk_dsb_misses", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "DSBmiss;Fed", + "MetricName": "tma_info_botlnk_dsb_misses" }, { "BriefDescription": "Total pipeline cost of Instruction Cache misses - subset of the Big_Code Bottleneck.", "MetricExpr": "100 * (100 * (tma_fetch_latency * ((ICACHE_16B.IFDATA_STALL + 2 * cpu@ICACHE_16B.IFDATA_STALL\\,cmask\\=0x1\\,edge\\=0x1@) / CPU_CLK_UNHALTED.THREAD) / ((ICACHE_16B.IFDATA_STALL + 2 * cpu@ICACHE_16B.IFDATA_STALL\\,cmask\\=0x1\\,edge\\=0x1@) / CPU_CLK_UNHALTED.THREAD + ICACHE_TAG.STALLS / CPU_CLK_UNHALTED.THREAD + (INT_MISC.CLEAR_RESTEER_CYCLES / CPU_CLK_UNHALTED.THREAD + 9 * BACLEARS.ANY / CPU_CLK_UNHALTED.THREAD) + min(2 * IDQ.MS_SWITCHES / CPU_CLK_UNHALTED.THREAD, 1) + DECODE.LCP / CPU_CLK_UNHALTED.THREAD + DSB2MITE_SWITCHES.PENALTY_CYCLES / CPU_CLK_UNHALTED.THREAD)))", - "MetricGroup": "Fed;FetchLat;IcMiss;TopdownL1;tma_L1_group", - "MetricName": "tma_info_botlnk_ic_misses", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Fed;FetchLat;IcMiss", + "MetricName": "tma_info_botlnk_ic_misses" }, { "BriefDescription": "Probability of Core Bound bottleneck hidden by SMT-profiling artifacts", @@ -1045,9 +1042,8 @@ { "BriefDescription": "STLB (2nd level TLB) code speculative misses per kilo instruction (misses of any page-size that complete the page walk)", "MetricExpr": "tma_info_memory_tlb_code_stlb_mpki", - "MetricGroup": "Fed;MemoryTLB;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_code_stlb_mpki", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Fed;MemoryTLB", + "MetricName": "tma_info_memory_code_stlb_mpki" }, { "BriefDescription": "Average per-core data fill bandwidth to the L1 data cache [GB / sec]", @@ -1088,9 +1084,8 @@ { "BriefDescription": "Average Parallel L2 cache miss data reads", "MetricExpr": "tma_info_memory_latency_data_l2_mlp", - "MetricGroup": "Memory_BW;Offcore;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_data_l2_mlp", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Memory_BW;Offcore", + "MetricName": "tma_info_memory_data_l2_mlp" }, { "BriefDescription": "Fill Buffer (FB) hits per kilo instructions for retired demand loads (L1D misses that merge into ongoing miss-handling entries)", @@ -1107,9 +1102,8 @@ { "BriefDescription": "Average per-core data fill bandwidth to the L1 data cache [GB / sec]", "MetricExpr": "64 * L1D.REPLACEMENT / 1e9 / (duration_time * 1e3 / 1e3)", - "MetricGroup": "Mem;MemoryBW;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_l1d_cache_fill_bw_2t", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Mem;MemoryBW", + "MetricName": "tma_info_memory_l1d_cache_fill_bw_2t" }, { "BriefDescription": "L1 cache true misses per kilo instruction for retired demand loads", @@ -1132,23 +1126,20 @@ { "BriefDescription": "Average per-core data fill bandwidth to the L2 cache [GB / sec]", "MetricExpr": "64 * L2_LINES_IN.ALL / 1e9 / (duration_time * 1e3 / 1e3)", - "MetricGroup": "Mem;MemoryBW;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_l2_cache_fill_bw_2t", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Mem;MemoryBW", + "MetricName": "tma_info_memory_l2_cache_fill_bw_2t" }, { "BriefDescription": "Rate of non silent evictions from the L2 cache per Kilo instruction", "MetricExpr": "1e3 * L2_LINES_OUT.NON_SILENT / INST_RETIRED.ANY", - "MetricGroup": "L2Evicts;Mem;Server;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_l2_evictions_nonsilent_pki", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "L2Evicts;Mem;Server", + "MetricName": "tma_info_memory_l2_evictions_nonsilent_pki" }, { "BriefDescription": "Rate of silent evictions from the L2 cache per Kilo instruction where the evicted lines are dropped (no writeback to L3 or memory)", "MetricExpr": "1e3 * L2_LINES_OUT.SILENT / INST_RETIRED.ANY", - "MetricGroup": "L2Evicts;Mem;Server;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_l2_evictions_silent_pki", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "L2Evicts;Mem;Server", + "MetricName": "tma_info_memory_l2_evictions_silent_pki" }, { "BriefDescription": "L2 cache hits per kilo instruction for all request types (including speculative)", @@ -1189,9 +1180,8 @@ { "BriefDescription": "Average per-core data access bandwidth to the L3 cache [GB / sec]", "MetricExpr": "64 * OFFCORE_REQUESTS.ALL_REQUESTS / 1e9 / (duration_time * 1e3 / 1e3)", - "MetricGroup": "Mem;MemoryBW;Offcore;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_l3_cache_access_bw_2t", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Mem;MemoryBW;Offcore", + "MetricName": "tma_info_memory_l3_cache_access_bw_2t" }, { "BriefDescription": "", @@ -1202,9 +1192,8 @@ { "BriefDescription": "Average per-core data fill bandwidth to the L3 cache [GB / sec]", "MetricExpr": "64 * LONGEST_LAT_CACHE.MISS / 1e9 / (duration_time * 1e3 / 1e3)", - "MetricGroup": "Mem;MemoryBW;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_l3_cache_fill_bw_2t", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Mem;MemoryBW", + "MetricName": "tma_info_memory_l3_cache_fill_bw_2t" }, { "BriefDescription": "L3 cache true misses per kilo instruction for retired demand loads", @@ -1233,16 +1222,14 @@ { "BriefDescription": "Average Latency for L2 cache miss demand Loads", "MetricExpr": "OFFCORE_REQUESTS_OUTSTANDING.DEMAND_DATA_RD / OFFCORE_REQUESTS.DEMAND_DATA_RD", - "MetricGroup": "Memory_Lat;Offcore;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_load_l2_miss_latency", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Memory_Lat;Offcore", + "MetricName": "tma_info_memory_load_l2_miss_latency" }, { "BriefDescription": "Average Parallel L2 cache miss demand Loads", "MetricExpr": "OFFCORE_REQUESTS_OUTSTANDING.DEMAND_DATA_RD / OFFCORE_REQUESTS_OUTSTANDING.CYCLES_WITH_DEMAND_DATA_RD", - "MetricGroup": "Memory_BW;Offcore;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_load_l2_mlp", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Memory_BW;Offcore", + "MetricName": "tma_info_memory_load_l2_mlp" }, { "BriefDescription": "Actual Average Latency for L1 data-cache miss demand load operations (in core cycles)", @@ -1253,9 +1240,8 @@ { "BriefDescription": "STLB (2nd level TLB) data load speculative misses per kilo instruction (misses of any page-size that complete the page walk)", "MetricExpr": "tma_info_memory_tlb_load_stlb_mpki", - "MetricGroup": "Mem;MemoryTLB;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_load_stlb_mpki", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Mem;MemoryTLB", + "MetricName": "tma_info_memory_load_stlb_mpki" }, { "BriefDescription": "Un-cacheable retired load per kilo instruction", @@ -1273,16 +1259,14 @@ { "BriefDescription": "Utilization of the core's Page Walker(s) serving STLB misses triggered by instruction/Load/Store accesses", "MetricExpr": "tma_info_memory_tlb_page_walks_utilization", - "MetricGroup": "Mem;MemoryTLB;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_page_walks_utilization", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Mem;MemoryTLB", + "MetricName": "tma_info_memory_page_walks_utilization" }, { "BriefDescription": "STLB (2nd level TLB) data store speculative misses per kilo instruction (misses of any page-size that complete the page walk)", "MetricExpr": "tma_info_memory_tlb_store_stlb_mpki", - "MetricGroup": "Mem;MemoryTLB;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_store_stlb_mpki", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Mem;MemoryTLB", + "MetricName": "tma_info_memory_store_stlb_mpki" }, { "BriefDescription": "STLB (2nd level TLB) code speculative misses per kilo instruction (misses of any page-size that complete the page walk)", @@ -1313,9 +1297,8 @@ { "BriefDescription": "Un-cacheable retired load per kilo instruction", "MetricExpr": "1e3 * MEM_LOAD_MISC_RETIRED.UC / INST_RETIRED.ANY", - "MetricGroup": "Mem;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_uc_load_pki", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Mem", + "MetricName": "tma_info_memory_uc_load_pki" }, { "BriefDescription": "", diff --git a/tools/perf/pmu-events/arch/x86/haswellx/hsx-metrics.json b/tools/perf/pmu-events/arch/x86/haswellx/hsx-metrics.json index 21e2cb5e3178..83d50d80a148 100644 --- a/tools/perf/pmu-events/arch/x86/haswellx/hsx-metrics.json +++ b/tools/perf/pmu-events/arch/x86/haswellx/hsx-metrics.json @@ -618,9 +618,8 @@ { "BriefDescription": "Average Parallel L2 cache miss data reads", "MetricExpr": "tma_info_memory_latency_data_l2_mlp", - "MetricGroup": "Memory_BW;Offcore;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_data_l2_mlp", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Memory_BW;Offcore", + "MetricName": "tma_info_memory_data_l2_mlp" }, { "BriefDescription": "", @@ -631,9 +630,8 @@ { "BriefDescription": "Average per-core data fill bandwidth to the L1 data cache [GB / sec]", "MetricExpr": "64 * L1D.REPLACEMENT / 1e9 / (duration_time * 1e3 / 1e3)", - "MetricGroup": "Mem;MemoryBW;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_l1d_cache_fill_bw_2t", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Mem;MemoryBW", + "MetricName": "tma_info_memory_l1d_cache_fill_bw_2t" }, { "BriefDescription": "L1 cache true misses per kilo instruction for retired demand loads", @@ -650,9 +648,8 @@ { "BriefDescription": "Average per-core data fill bandwidth to the L2 cache [GB / sec]", "MetricExpr": "64 * L2_LINES_IN.ALL / 1e9 / (duration_time * 1e3 / 1e3)", - "MetricGroup": "Mem;MemoryBW;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_l2_cache_fill_bw_2t", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Mem;MemoryBW", + "MetricName": "tma_info_memory_l2_cache_fill_bw_2t" }, { "BriefDescription": "L2 cache true misses per kilo instruction for retired demand loads", @@ -669,9 +666,8 @@ { "BriefDescription": "Average per-core data fill bandwidth to the L3 cache [GB / sec]", "MetricExpr": "64 * LONGEST_LAT_CACHE.MISS / 1e9 / (duration_time * 1e3 / 1e3)", - "MetricGroup": "Mem;MemoryBW;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_l3_cache_fill_bw_2t", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Mem;MemoryBW", + "MetricName": "tma_info_memory_l3_cache_fill_bw_2t" }, { "BriefDescription": "L3 cache true misses per kilo instruction for retired demand loads", @@ -700,16 +696,14 @@ { "BriefDescription": "Average Latency for L2 cache miss demand Loads", "MetricExpr": "OFFCORE_REQUESTS_OUTSTANDING.DEMAND_DATA_RD / OFFCORE_REQUESTS.DEMAND_DATA_RD", - "MetricGroup": "Memory_Lat;Offcore;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_load_l2_miss_latency", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Memory_Lat;Offcore", + "MetricName": "tma_info_memory_load_l2_miss_latency" }, { "BriefDescription": "Average Parallel L2 cache miss demand Loads", "MetricExpr": "OFFCORE_REQUESTS_OUTSTANDING.DEMAND_DATA_RD / OFFCORE_REQUESTS_OUTSTANDING.CYCLES_WITH_DEMAND_DATA_RD", - "MetricGroup": "Memory_BW;Offcore;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_load_l2_mlp", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Memory_BW;Offcore", + "MetricName": "tma_info_memory_load_l2_mlp" }, { "BriefDescription": "Actual Average Latency for L1 data-cache miss demand load operations (in core cycles)", @@ -729,9 +723,8 @@ { "BriefDescription": "Utilization of the core's Page Walker(s) serving STLB misses triggered by instruction/Load/Store accesses", "MetricExpr": "tma_info_memory_tlb_page_walks_utilization", - "MetricGroup": "Mem;MemoryTLB;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_page_walks_utilization", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Mem;MemoryTLB", + "MetricName": "tma_info_memory_page_walks_utilization" }, { "BriefDescription": "Utilization of the core's Page Walker(s) serving STLB misses triggered by instruction/Load/Store accesses", diff --git a/tools/perf/pmu-events/arch/x86/icelakex/icx-metrics.json b/tools/perf/pmu-events/arch/x86/icelakex/icx-metrics.json index c015b8277dc7..769ba12bef87 100644 --- a/tools/perf/pmu-events/arch/x86/icelakex/icx-metrics.json +++ b/tools/perf/pmu-events/arch/x86/icelakex/icx-metrics.json @@ -667,23 +667,20 @@ { "BriefDescription": "Probability of Core Bound bottleneck hidden by SMT-profiling artifacts", "MetricExpr": "(100 * (1 - max(0, topdown\\-be\\-bound / (topdown\\-fe\\-bound + topdown\\-bad\\-spec + topdown\\-retiring + topdown\\-be\\-bound) + 5 * INT_MISC.CLEARS_COUNT / slots - (CYCLE_ACTIVITY.STALLS_MEM_ANY + EXE_ACTIVITY.BOUND_ON_STORES) / (CYCLE_ACTIVITY.STALLS_TOTAL + (EXE_ACTIVITY.1_PORTS_UTIL + topdown\\-retiring / (topdown\\-fe\\-bound + topdown\\-bad\\-spec + topdown\\-retiring + topdown\\-be\\-bound) * EXE_ACTIVITY.2_PORTS_UTIL) + EXE_ACTIVITY.BOUND_ON_STORES) * (topdown\\-be\\-bound / (topdown\\-fe\\-bound + topdown\\-bad\\-spec + topdown\\-retiring + topdown\\-be\\-bound) + 5 * INT_MISC.CLEARS_COUNT / slots)) / (((cpu@EXE_ACTIVITY.3_PORTS_UTIL\\,umask\\=0x80@ + max(0, topdown\\-be\\-bound / (topdown\\-fe\\-bound + topdown\\-bad\\-spec + topdown\\-retiring + topdown\\-be\\-bound) + 5 * INT_MISC.CLEARS_COUNT / slots - (CYCLE_ACTIVITY.STALLS_MEM_ANY + EXE_ACTIVITY.BOUND_ON_STORES) / (CYCLE_ACTIVITY.STALLS_TOTAL + (EXE_ACTIVITY.1_PORTS_UTIL + topdown\\-retiring / (topdown\\-fe\\-bound + topdown\\-bad\\-spec + topdown\\-retiring + topdown\\-be\\-bound) * EXE_ACTIVITY.2_PORTS_UTIL) + EXE_ACTIVITY.BOUND_ON_STORES) * (topdown\\-be\\-bound / (topdown\\-fe\\-bound + topdown\\-bad\\-spec + topdown\\-retiring + topdown\\-be\\-bound) + 5 * INT_MISC.CLEARS_COUNT / slots)) * RS_EVENTS.EMPTY_CYCLES) / CPU_CLK_UNHALTED.THREAD * (CYCLE_ACTIVITY.STALLS_TOTAL - CYCLE_ACTIVITY.STALLS_MEM_ANY) / CPU_CLK_UNHALTED.THREAD * CPU_CLK_UNHALTED.THREAD + (EXE_ACTIVITY.1_PORTS_UTIL + topdown\\-retiring / (topdown\\-fe\\-bound + topdown\\-bad\\-spec + topdown\\-retiring + topdown\\-be\\-bound) * EXE_ACTIVITY.2_PORTS_UTIL)) / CPU_CLK_UNHALTED.THREAD if ARITH.DIVIDER_ACTIVE < CYCLE_ACTIVITY.STALLS_TOTAL - CYCLE_ACTIVITY.STALLS_MEM_ANY else (EXE_ACTIVITY.1_PORTS_UTIL + topdown\\-retiring / (topdown\\-fe\\-bound + topdown\\-bad\\-spec + topdown\\-retiring + topdown\\-be\\-bound) * EXE_ACTIVITY.2_PORTS_UTIL) / CPU_CLK_UNHALTED.THREAD) if max(0, topdown\\-be\\-bound / (topdown\\-fe\\-bound + topdown\\-bad\\-spec + topdown\\-retiring + topdown\\-be\\-bound) + 5 * INT_MISC.CLEARS_COUNT / slots - (CYCLE_ACTIVITY.STALLS_MEM_ANY + EXE_ACTIVITY.BOUND_ON_STORES) / (CYCLE_ACTIVITY.STALLS_TOTAL + (EXE_ACTIVITY.1_PORTS_UTIL + topdown\\-retiring / (topdown\\-fe\\-bound + topdown\\-bad\\-spec + topdown\\-retiring + topdown\\-be\\-bound) * EXE_ACTIVITY.2_PORTS_UTIL) + EXE_ACTIVITY.BOUND_ON_STORES) * (topdown\\-be\\-bound / (topdown\\-fe\\-bound + topdown\\-bad\\-spec + topdown\\-retiring + topdown\\-be\\-bound) + 5 * INT_MISC.CLEARS_COUNT / slots)) < (((cpu@EXE_ACTIVITY.3_PORTS_UTIL\\,umask\\=0x80@ + max(0, topdown\\-be\\-bound / (topdown\\-fe\\-bound + topdown\\-bad\\-spec + topdown\\-retiring + topdown\\-be\\-bound) + 5 * INT_MISC.CLEARS_COUNT / slots - (CYCLE_ACTIVITY.STALLS_MEM_ANY + EXE_ACTIVITY.BOUND_ON_STORES) / (CYCLE_ACTIVITY.STALLS_TOTAL + (EXE_ACTIVITY.1_PORTS_UTIL + topdown\\-retiring / (topdown\\-fe\\-bound + topdown\\-bad\\-spec + topdown\\-retiring + topdown\\-be\\-bound) * EXE_ACTIVITY.2_PORTS_UTIL) + EXE_ACTIVITY.BOUND_ON_STORES) * (topdown\\-be\\-bound / (topdown\\-fe\\-bound + topdown\\-bad\\-spec + topdown\\-retiring + topdown\\-be\\-bound) + 5 * INT_MISC.CLEARS_COUNT / slots)) * RS_EVENTS.EMPTY_CYCLES) / CPU_CLK_UNHALTED.THREAD * (CYCLE_ACTIVITY.STALLS_TOTAL - CYCLE_ACTIVITY.STALLS_MEM_ANY) / CPU_CLK_UNHALTED.THREAD * CPU_CLK_UNHALTED.THREAD + (EXE_ACTIVITY.1_PORTS_UTIL + topdown\\-retiring / (topdown\\-fe\\-bound + topdown\\-bad\\-spec + topdown\\-retiring + topdown\\-be\\-bound) * EXE_ACTIVITY.2_PORTS_UTIL)) / CPU_CLK_UNHALTED.THREAD if ARITH.DIVIDER_ACTIVE < CYCLE_ACTIVITY.STALLS_TOTAL - CYCLE_ACTIVITY.STALLS_MEM_ANY else (EXE_ACTIVITY.1_PORTS_UTIL + topdown\\-retiring / (topdown\\-fe\\-bound + topdown\\-bad\\-spec + topdown\\-retiring + topdown\\-be\\-bound) * EXE_ACTIVITY.2_PORTS_UTIL) / CPU_CLK_UNHALTED.THREAD) else 1) if tma_info_system_smt_2t_utilization > 0.5 else 0)", - "MetricGroup": "Cor;SMT;TopdownL1;tma_L1_group", - "MetricName": "tma_info_botlnk_core_bound_likely", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Cor;SMT", + "MetricName": "tma_info_botlnk_core_bound_likely" }, { "BriefDescription": "Total pipeline cost of DSB (uop cache) misses - subset of the Instruction_Fetch_BW Bottleneck.", "MetricExpr": "100 * (100 * ((5 * IDQ_UOPS_NOT_DELIVERED.CYCLES_0_UOPS_DELIV.CORE - INT_MISC.UOP_DROPPING) / slots * (DSB2MITE_SWITCHES.PENALTY_CYCLES / CPU_CLK_UNHALTED.THREAD) / (ICACHE_DATA.STALLS / CPU_CLK_UNHALTED.THREAD + ICACHE_TAG.STALLS / CPU_CLK_UNHALTED.THREAD + (INT_MISC.CLEAR_RESTEER_CYCLES / CPU_CLK_UNHALTED.THREAD + 10 * BACLEARS.ANY / CPU_CLK_UNHALTED.THREAD) + min(3 * IDQ.MS_SWITCHES / CPU_CLK_UNHALTED.THREAD, 1) + DECODE.LCP / CPU_CLK_UNHALTED.THREAD + DSB2MITE_SWITCHES.PENALTY_CYCLES / CPU_CLK_UNHALTED.THREAD) + max(0, topdown\\-fe\\-bound / (topdown\\-fe\\-bound + topdown\\-bad\\-spec + topdown\\-retiring + topdown\\-be\\-bound) - INT_MISC.UOP_DROPPING / slots - (5 * IDQ_UOPS_NOT_DELIVERED.CYCLES_0_UOPS_DELIV.CORE - INT_MISC.UOP_DROPPING) / slots) * ((IDQ.MITE_CYCLES_ANY - IDQ.MITE_CYCLES_OK) / (CPU_CLK_UNHALTED.DISTRIBUTED if #SMT_on else CPU_CLK_UNHALTED.THREAD) / 2) / ((IDQ.MITE_CYCLES_ANY - IDQ.MITE_CYCLES_OK) / (CPU_CLK_UNHALTED.DISTRIBUTED if #SMT_on else CPU_CLK_UNHALTED.THREAD) / 2 + (IDQ.DSB_CYCLES_ANY - IDQ.DSB_CYCLES_OK) / (CPU_CLK_UNHALTED.DISTRIBUTED if #SMT_on else CPU_CLK_UNHALTED.THREAD) / 2)))", - "MetricGroup": "DSBmiss;Fed;TopdownL1;tma_L1_group", - "MetricName": "tma_info_botlnk_dsb_misses", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "DSBmiss;Fed", + "MetricName": "tma_info_botlnk_dsb_misses" }, { "BriefDescription": "Total pipeline cost of Instruction Cache misses - subset of the Big_Code Bottleneck.", "MetricExpr": "100 * (100 * ((5 * IDQ_UOPS_NOT_DELIVERED.CYCLES_0_UOPS_DELIV.CORE - INT_MISC.UOP_DROPPING) / slots * (ICACHE_DATA.STALLS / CPU_CLK_UNHALTED.THREAD) / (ICACHE_DATA.STALLS / CPU_CLK_UNHALTED.THREAD + ICACHE_TAG.STALLS / CPU_CLK_UNHALTED.THREAD + (INT_MISC.CLEAR_RESTEER_CYCLES / CPU_CLK_UNHALTED.THREAD + 10 * BACLEARS.ANY / CPU_CLK_UNHALTED.THREAD) + min(3 * IDQ.MS_SWITCHES / CPU_CLK_UNHALTED.THREAD, 1) + DECODE.LCP / CPU_CLK_UNHALTED.THREAD + DSB2MITE_SWITCHES.PENALTY_CYCLES / CPU_CLK_UNHALTED.THREAD)))", - "MetricGroup": "Fed;FetchLat;IcMiss;TopdownL1;tma_L1_group", - "MetricName": "tma_info_botlnk_ic_misses", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Fed;FetchLat;IcMiss", + "MetricName": "tma_info_botlnk_ic_misses" }, { "BriefDescription": "Probability of Core Bound bottleneck hidden by SMT-profiling artifacts", @@ -1045,16 +1042,14 @@ { "BriefDescription": "\"Bus lock\" per kilo instruction", "MetricExpr": "tma_info_memory_mix_bus_lock_pki", - "MetricGroup": "Mem;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_bus_lock_pki", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Mem", + "MetricName": "tma_info_memory_bus_lock_pki" }, { "BriefDescription": "STLB (2nd level TLB) code speculative misses per kilo instruction (misses of any page-size that complete the page walk)", "MetricExpr": "tma_info_memory_tlb_code_stlb_mpki", - "MetricGroup": "Fed;MemoryTLB;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_code_stlb_mpki", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Fed;MemoryTLB", + "MetricName": "tma_info_memory_code_stlb_mpki" }, { "BriefDescription": "Average per-core data fill bandwidth to the L1 data cache [GB / sec]", @@ -1095,9 +1090,8 @@ { "BriefDescription": "Average Parallel L2 cache miss data reads", "MetricExpr": "tma_info_memory_latency_data_l2_mlp", - "MetricGroup": "Memory_BW;Offcore;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_data_l2_mlp", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Memory_BW;Offcore", + "MetricName": "tma_info_memory_data_l2_mlp" }, { "BriefDescription": "Fill Buffer (FB) hits per kilo instructions for retired demand loads (L1D misses that merge into ongoing miss-handling entries)", @@ -1114,9 +1108,8 @@ { "BriefDescription": "Average per-core data fill bandwidth to the L1 data cache [GB / sec]", "MetricExpr": "64 * L1D.REPLACEMENT / 1e9 / (duration_time * 1e3 / 1e3)", - "MetricGroup": "Mem;MemoryBW;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_l1d_cache_fill_bw_2t", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Mem;MemoryBW", + "MetricName": "tma_info_memory_l1d_cache_fill_bw_2t" }, { "BriefDescription": "L1 cache true misses per kilo instruction for retired demand loads", @@ -1139,23 +1132,20 @@ { "BriefDescription": "Average per-core data fill bandwidth to the L2 cache [GB / sec]", "MetricExpr": "64 * L2_LINES_IN.ALL / 1e9 / (duration_time * 1e3 / 1e3)", - "MetricGroup": "Mem;MemoryBW;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_l2_cache_fill_bw_2t", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Mem;MemoryBW", + "MetricName": "tma_info_memory_l2_cache_fill_bw_2t" }, { "BriefDescription": "Rate of non silent evictions from the L2 cache per Kilo instruction", "MetricExpr": "1e3 * L2_LINES_OUT.NON_SILENT / INST_RETIRED.ANY", - "MetricGroup": "L2Evicts;Mem;Server;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_l2_evictions_nonsilent_pki", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "L2Evicts;Mem;Server", + "MetricName": "tma_info_memory_l2_evictions_nonsilent_pki" }, { "BriefDescription": "Rate of silent evictions from the L2 cache per Kilo instruction where the evicted lines are dropped (no writeback to L3 or memory)", "MetricExpr": "1e3 * L2_LINES_OUT.SILENT / INST_RETIRED.ANY", - "MetricGroup": "L2Evicts;Mem;Server;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_l2_evictions_silent_pki", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "L2Evicts;Mem;Server", + "MetricName": "tma_info_memory_l2_evictions_silent_pki" }, { "BriefDescription": "L2 cache hits per kilo instruction for all demand loads (including speculative)", @@ -1190,9 +1180,8 @@ { "BriefDescription": "Average per-core data access bandwidth to the L3 cache [GB / sec]", "MetricExpr": "64 * OFFCORE_REQUESTS.ALL_REQUESTS / 1e9 / (duration_time * 1e3 / 1e3)", - "MetricGroup": "Mem;MemoryBW;Offcore;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_l3_cache_access_bw_2t", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Mem;MemoryBW;Offcore", + "MetricName": "tma_info_memory_l3_cache_access_bw_2t" }, { "BriefDescription": "", @@ -1203,9 +1192,8 @@ { "BriefDescription": "Average per-core data fill bandwidth to the L3 cache [GB / sec]", "MetricExpr": "64 * LONGEST_LAT_CACHE.MISS / 1e9 / (duration_time * 1e3 / 1e3)", - "MetricGroup": "Mem;MemoryBW;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_l3_cache_fill_bw_2t", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Mem;MemoryBW", + "MetricName": "tma_info_memory_l3_cache_fill_bw_2t" }, { "BriefDescription": "L3 cache true misses per kilo instruction for retired demand loads", @@ -1240,23 +1228,20 @@ { "BriefDescription": "Average Latency for L2 cache miss demand Loads", "MetricExpr": "OFFCORE_REQUESTS_OUTSTANDING.DEMAND_DATA_RD / OFFCORE_REQUESTS.DEMAND_DATA_RD", - "MetricGroup": "Memory_Lat;Offcore;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_load_l2_miss_latency", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Memory_Lat;Offcore", + "MetricName": "tma_info_memory_load_l2_miss_latency" }, { "BriefDescription": "Average Parallel L2 cache miss demand Loads", "MetricExpr": "OFFCORE_REQUESTS_OUTSTANDING.DEMAND_DATA_RD / cpu@OFFCORE_REQUESTS_OUTSTANDING.DEMAND_DATA_RD\\,cmask\\=0x1@", - "MetricGroup": "Memory_BW;Offcore;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_load_l2_mlp", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Memory_BW;Offcore", + "MetricName": "tma_info_memory_load_l2_mlp" }, { "BriefDescription": "Average Latency for L3 cache miss demand Loads", "MetricExpr": "cpu@OFFCORE_REQUESTS_OUTSTANDING.DEMAND_DATA_RD\\,umask\\=0x10@ / OFFCORE_REQUESTS.L3_MISS_DEMAND_DATA_RD", - "MetricGroup": "Memory_Lat;Offcore;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_load_l3_miss_latency", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Memory_Lat;Offcore", + "MetricName": "tma_info_memory_load_l3_miss_latency" }, { "BriefDescription": "Actual Average Latency for L1 data-cache miss demand load operations (in core cycles)", @@ -1267,9 +1252,8 @@ { "BriefDescription": "STLB (2nd level TLB) data load speculative misses per kilo instruction (misses of any page-size that complete the page walk)", "MetricExpr": "tma_info_memory_tlb_load_stlb_mpki", - "MetricGroup": "Mem;MemoryTLB;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_load_stlb_mpki", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Mem;MemoryTLB", + "MetricName": "tma_info_memory_load_stlb_mpki" }, { "BriefDescription": "\"Bus lock\" per kilo instruction", @@ -1293,16 +1277,14 @@ { "BriefDescription": "Utilization of the core's Page Walker(s) serving STLB misses triggered by instruction/Load/Store accesses", "MetricExpr": "(ITLB_MISSES.WALK_PENDING + DTLB_LOAD_MISSES.WALK_PENDING + DTLB_STORE_MISSES.WALK_PENDING) / (2 * (CPU_CLK_UNHALTED.DISTRIBUTED if #SMT_on else CPU_CLK_UNHALTED.THREAD))", - "MetricGroup": "Mem;MemoryTLB;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_page_walks_utilization", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Mem;MemoryTLB", + "MetricName": "tma_info_memory_page_walks_utilization" }, { "BriefDescription": "STLB (2nd level TLB) data store speculative misses per kilo instruction (misses of any page-size that complete the page walk)", "MetricExpr": "tma_info_memory_tlb_store_stlb_mpki", - "MetricGroup": "Mem;MemoryTLB;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_store_stlb_mpki", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Mem;MemoryTLB", + "MetricName": "tma_info_memory_store_stlb_mpki" }, { "BriefDescription": "STLB (2nd level TLB) code speculative misses per kilo instruction (misses of any page-size that complete the page walk)", @@ -1332,9 +1314,8 @@ { "BriefDescription": "Un-cacheable retired load per kilo instruction", "MetricExpr": "1e3 * MEM_LOAD_MISC_RETIRED.UC / INST_RETIRED.ANY", - "MetricGroup": "Mem;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_uc_load_pki", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Mem", + "MetricName": "tma_info_memory_uc_load_pki" }, { "BriefDescription": "", diff --git a/tools/perf/pmu-events/arch/x86/sapphirerapids/spr-metrics.json b/tools/perf/pmu-events/arch/x86/sapphirerapids/spr-metrics.json index 6f0e6360e989..f8c0eac8b828 100644 --- a/tools/perf/pmu-events/arch/x86/sapphirerapids/spr-metrics.json +++ b/tools/perf/pmu-events/arch/x86/sapphirerapids/spr-metrics.json @@ -727,23 +727,20 @@ { "BriefDescription": "Probability of Core Bound bottleneck hidden by SMT-profiling artifacts", "MetricExpr": "(100 * (1 - max(0, topdown\\-be\\-bound / (topdown\\-fe\\-bound + topdown\\-bad\\-spec + topdown\\-retiring + topdown\\-be\\-bound) - topdown\\-mem\\-bound / (topdown\\-fe\\-bound + topdown\\-bad\\-spec + topdown\\-retiring + topdown\\-be\\-bound)) / (((cpu@EXE_ACTIVITY.3_PORTS_UTIL\\,umask\\=0x80@ + cpu@RS.EMPTY\\,umask\\=0x1@) / CPU_CLK_UNHALTED.THREAD * (CYCLE_ACTIVITY.STALLS_TOTAL - EXE_ACTIVITY.BOUND_ON_LOADS) / CPU_CLK_UNHALTED.THREAD * CPU_CLK_UNHALTED.THREAD + (EXE_ACTIVITY.1_PORTS_UTIL + topdown\\-retiring / (topdown\\-fe\\-bound + topdown\\-bad\\-spec + topdown\\-retiring + topdown\\-be\\-bound) * cpu@EXE_ACTIVITY.2_PORTS_UTIL\\,umask\\=0xc@)) / CPU_CLK_UNHALTED.THREAD if ARITH.DIV_ACTIVE < CYCLE_ACTIVITY.STALLS_TOTAL - EXE_ACTIVITY.BOUND_ON_LOADS else (EXE_ACTIVITY.1_PORTS_UTIL + topdown\\-retiring / (topdown\\-fe\\-bound + topdown\\-bad\\-spec + topdown\\-retiring + topdown\\-be\\-bound) * cpu@EXE_ACTIVITY.2_PORTS_UTIL\\,umask\\=0xc@) / CPU_CLK_UNHALTED.THREAD) if max(0, topdown\\-be\\-bound / (topdown\\-fe\\-bound + topdown\\-bad\\-spec + topdown\\-retiring + topdown\\-be\\-bound) - topdown\\-mem\\-bound / (topdown\\-fe\\-bound + topdown\\-bad\\-spec + topdown\\-retiring + topdown\\-be\\-bound)) < (((cpu@EXE_ACTIVITY.3_PORTS_UTIL\\,umask\\=0x80@ + cpu@RS.EMPTY\\,umask\\=0x1@) / CPU_CLK_UNHALTED.THREAD * (CYCLE_ACTIVITY.STALLS_TOTAL - EXE_ACTIVITY.BOUND_ON_LOADS) / CPU_CLK_UNHALTED.THREAD * CPU_CLK_UNHALTED.THREAD + (EXE_ACTIVITY.1_PORTS_UTIL + topdown\\-retiring / (topdown\\-fe\\-bound + topdown\\-bad\\-spec + topdown\\-retiring + topdown\\-be\\-bound) * cpu@EXE_ACTIVITY.2_PORTS_UTIL\\,umask\\=0xc@)) / CPU_CLK_UNHALTED.THREAD if ARITH.DIV_ACTIVE < CYCLE_ACTIVITY.STALLS_TOTAL - EXE_ACTIVITY.BOUND_ON_LOADS else (EXE_ACTIVITY.1_PORTS_UTIL + topdown\\-retiring / (topdown\\-fe\\-bound + topdown\\-bad\\-spec + topdown\\-retiring + topdown\\-be\\-bound) * cpu@EXE_ACTIVITY.2_PORTS_UTIL\\,umask\\=0xc@) / CPU_CLK_UNHALTED.THREAD) else 1) if tma_info_system_smt_2t_utilization > 0.5 else 0) + 0 * slots", - "MetricGroup": "Cor;SMT;TopdownL1;tma_L1_group", - "MetricName": "tma_info_botlnk_core_bound_likely", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Cor;SMT", + "MetricName": "tma_info_botlnk_core_bound_likely" }, { "BriefDescription": "Total pipeline cost of DSB (uop cache) misses - subset of the Instruction_Fetch_BW Bottleneck.", "MetricExpr": "100 * (100 * ((topdown\\-fetch\\-lat / (topdown\\-fe\\-bound + topdown\\-bad\\-spec + topdown\\-retiring + topdown\\-be\\-bound) - INT_MISC.UOP_DROPPING / slots) * (DSB2MITE_SWITCHES.PENALTY_CYCLES / CPU_CLK_UNHALTED.THREAD) / (ICACHE_DATA.STALLS / CPU_CLK_UNHALTED.THREAD + ICACHE_TAG.STALLS / CPU_CLK_UNHALTED.THREAD + (INT_MISC.CLEAR_RESTEER_CYCLES / CPU_CLK_UNHALTED.THREAD + INT_MISC.UNKNOWN_BRANCH_CYCLES / CPU_CLK_UNHALTED.THREAD) + min(3 * cpu@UOPS_RETIRED.MS\\,cmask\\=0x1\\,edge\\=0x1@ / (UOPS_RETIRED.SLOTS / UOPS_ISSUED.ANY) / CPU_CLK_UNHALTED.THREAD, 1) + DECODE.LCP / CPU_CLK_UNHALTED.THREAD + DSB2MITE_SWITCHES.PENALTY_CYCLES / CPU_CLK_UNHALTED.THREAD) + max(0, topdown\\-fe\\-bound / (topdown\\-fe\\-bound + topdown\\-bad\\-spec + topdown\\-retiring + topdown\\-be\\-bound) - INT_MISC.UOP_DROPPING / slots - (topdown\\-fetch\\-lat / (topdown\\-fe\\-bound + topdown\\-bad\\-spec + topdown\\-retiring + topdown\\-be\\-bound) - INT_MISC.UOP_DROPPING / slots)) * ((IDQ.MITE_CYCLES_ANY - IDQ.MITE_CYCLES_OK) / (CPU_CLK_UNHALTED.DISTRIBUTED if #SMT_on else CPU_CLK_UNHALTED.THREAD) / 2) / ((IDQ.MITE_CYCLES_ANY - IDQ.MITE_CYCLES_OK) / (CPU_CLK_UNHALTED.DISTRIBUTED if #SMT_on else CPU_CLK_UNHALTED.THREAD) / 2 + (IDQ.DSB_CYCLES_ANY - IDQ.DSB_CYCLES_OK) / (CPU_CLK_UNHALTED.DISTRIBUTED if #SMT_on else CPU_CLK_UNHALTED.THREAD) / 2)))", - "MetricGroup": "DSBmiss;Fed;TopdownL1;tma_L1_group", - "MetricName": "tma_info_botlnk_dsb_misses", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "DSBmiss;Fed", + "MetricName": "tma_info_botlnk_dsb_misses" }, { "BriefDescription": "Total pipeline cost of Instruction Cache misses - subset of the Big_Code Bottleneck.", "MetricExpr": "100 * (100 * ((topdown\\-fetch\\-lat / (topdown\\-fe\\-bound + topdown\\-bad\\-spec + topdown\\-retiring + topdown\\-be\\-bound) - INT_MISC.UOP_DROPPING / slots) * (ICACHE_DATA.STALLS / CPU_CLK_UNHALTED.THREAD) / (ICACHE_DATA.STALLS / CPU_CLK_UNHALTED.THREAD + ICACHE_TAG.STALLS / CPU_CLK_UNHALTED.THREAD + (INT_MISC.CLEAR_RESTEER_CYCLES / CPU_CLK_UNHALTED.THREAD + INT_MISC.UNKNOWN_BRANCH_CYCLES / CPU_CLK_UNHALTED.THREAD) + min(3 * cpu@UOPS_RETIRED.MS\\,cmask\\=0x1\\,edge\\=0x1@ / (UOPS_RETIRED.SLOTS / UOPS_ISSUED.ANY) / CPU_CLK_UNHALTED.THREAD, 1) + DECODE.LCP / CPU_CLK_UNHALTED.THREAD + DSB2MITE_SWITCHES.PENALTY_CYCLES / CPU_CLK_UNHALTED.THREAD)))", - "MetricGroup": "Fed;FetchLat;IcMiss;TopdownL1;tma_L1_group", - "MetricName": "tma_info_botlnk_ic_misses", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Fed;FetchLat;IcMiss", + "MetricName": "tma_info_botlnk_ic_misses" }, { "BriefDescription": "Probability of Core Bound bottleneck hidden by SMT-profiling artifacts", @@ -1113,16 +1110,14 @@ { "BriefDescription": "\"Bus lock\" per kilo instruction", "MetricExpr": "tma_info_memory_mix_bus_lock_pki", - "MetricGroup": "Mem;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_bus_lock_pki", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Mem", + "MetricName": "tma_info_memory_bus_lock_pki" }, { "BriefDescription": "STLB (2nd level TLB) code speculative misses per kilo instruction (misses of any page-size that complete the page walk)", "MetricExpr": "tma_info_memory_tlb_code_stlb_mpki", - "MetricGroup": "Fed;MemoryTLB;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_code_stlb_mpki", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Fed;MemoryTLB", + "MetricName": "tma_info_memory_code_stlb_mpki" }, { "BriefDescription": "Average per-core data fill bandwidth to the L1 data cache [GB / sec]", @@ -1163,9 +1158,8 @@ { "BriefDescription": "Average Parallel L2 cache miss data reads", "MetricExpr": "tma_info_memory_latency_data_l2_mlp", - "MetricGroup": "Memory_BW;Offcore;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_data_l2_mlp", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Memory_BW;Offcore", + "MetricName": "tma_info_memory_data_l2_mlp" }, { "BriefDescription": "Fill Buffer (FB) hits per kilo instructions for retired demand loads (L1D misses that merge into ongoing miss-handling entries)", @@ -1182,9 +1176,8 @@ { "BriefDescription": "Average per-core data fill bandwidth to the L1 data cache [GB / sec]", "MetricExpr": "64 * L1D.REPLACEMENT / 1e9 / (duration_time * 1e3 / 1e3)", - "MetricGroup": "Mem;MemoryBW;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_l1d_cache_fill_bw_2t", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Mem;MemoryBW", + "MetricName": "tma_info_memory_l1d_cache_fill_bw_2t" }, { "BriefDescription": "L1 cache true misses per kilo instruction for retired demand loads", @@ -1207,23 +1200,20 @@ { "BriefDescription": "Average per-core data fill bandwidth to the L2 cache [GB / sec]", "MetricExpr": "64 * L2_LINES_IN.ALL / 1e9 / (duration_time * 1e3 / 1e3)", - "MetricGroup": "Mem;MemoryBW;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_l2_cache_fill_bw_2t", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Mem;MemoryBW", + "MetricName": "tma_info_memory_l2_cache_fill_bw_2t" }, { "BriefDescription": "Rate of non silent evictions from the L2 cache per Kilo instruction", "MetricExpr": "1e3 * L2_LINES_OUT.NON_SILENT / INST_RETIRED.ANY", - "MetricGroup": "L2Evicts;Mem;Server;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_l2_evictions_nonsilent_pki", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "L2Evicts;Mem;Server", + "MetricName": "tma_info_memory_l2_evictions_nonsilent_pki" }, { "BriefDescription": "Rate of silent evictions from the L2 cache per Kilo instruction where the evicted lines are dropped (no writeback to L3 or memory)", "MetricExpr": "1e3 * L2_LINES_OUT.SILENT / INST_RETIRED.ANY", - "MetricGroup": "L2Evicts;Mem;Server;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_l2_evictions_silent_pki", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "L2Evicts;Mem;Server", + "MetricName": "tma_info_memory_l2_evictions_silent_pki" }, { "BriefDescription": "L2 cache hits per kilo instruction for all request types (including speculative)", @@ -1264,9 +1254,8 @@ { "BriefDescription": "Average per-core data access bandwidth to the L3 cache [GB / sec]", "MetricExpr": "64 * OFFCORE_REQUESTS.ALL_REQUESTS / 1e9 / (duration_time * 1e3 / 1e3)", - "MetricGroup": "Mem;MemoryBW;Offcore;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_l3_cache_access_bw_2t", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Mem;MemoryBW;Offcore", + "MetricName": "tma_info_memory_l3_cache_access_bw_2t" }, { "BriefDescription": "", @@ -1277,9 +1266,8 @@ { "BriefDescription": "Average per-core data fill bandwidth to the L3 cache [GB / sec]", "MetricExpr": "64 * LONGEST_LAT_CACHE.MISS / 1e9 / (duration_time * 1e3 / 1e3)", - "MetricGroup": "Mem;MemoryBW;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_l3_cache_fill_bw_2t", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Mem;MemoryBW", + "MetricName": "tma_info_memory_l3_cache_fill_bw_2t" }, { "BriefDescription": "L3 cache true misses per kilo instruction for retired demand loads", @@ -1314,23 +1302,20 @@ { "BriefDescription": "Average Latency for L2 cache miss demand Loads", "MetricExpr": "OFFCORE_REQUESTS_OUTSTANDING.DEMAND_DATA_RD / OFFCORE_REQUESTS.DEMAND_DATA_RD", - "MetricGroup": "Memory_Lat;Offcore;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_load_l2_miss_latency", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Memory_Lat;Offcore", + "MetricName": "tma_info_memory_load_l2_miss_latency" }, { "BriefDescription": "Average Parallel L2 cache miss demand Loads", "MetricExpr": "OFFCORE_REQUESTS_OUTSTANDING.DEMAND_DATA_RD / cpu@OFFCORE_REQUESTS_OUTSTANDING.DEMAND_DATA_RD\\,cmask\\=0x1@", - "MetricGroup": "Memory_BW;Offcore;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_load_l2_mlp", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Memory_BW;Offcore", + "MetricName": "tma_info_memory_load_l2_mlp" }, { "BriefDescription": "Average Latency for L3 cache miss demand Loads", "MetricExpr": "OFFCORE_REQUESTS_OUTSTANDING.L3_MISS_DEMAND_DATA_RD / OFFCORE_REQUESTS.L3_MISS_DEMAND_DATA_RD", - "MetricGroup": "Memory_Lat;Offcore;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_load_l3_miss_latency", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Memory_Lat;Offcore", + "MetricName": "tma_info_memory_load_l3_miss_latency" }, { "BriefDescription": "Actual Average Latency for L1 data-cache miss demand load operations (in core cycles)", @@ -1341,9 +1326,8 @@ { "BriefDescription": "STLB (2nd level TLB) data load speculative misses per kilo instruction (misses of any page-size that complete the page walk)", "MetricExpr": "tma_info_memory_tlb_load_stlb_mpki", - "MetricGroup": "Mem;MemoryTLB;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_load_stlb_mpki", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Mem;MemoryTLB", + "MetricName": "tma_info_memory_load_stlb_mpki" }, { "BriefDescription": "\"Bus lock\" per kilo instruction", @@ -1385,53 +1369,46 @@ { "BriefDescription": "Off-core accesses per kilo instruction for modified write requests", "MetricExpr": "1e3 * OCR.MODIFIED_WRITE.ANY_RESPONSE / INST_RETIRED.ANY", - "MetricGroup": "Offcore;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_offcore_mwrite_any_pki", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Offcore", + "MetricName": "tma_info_memory_offcore_mwrite_any_pki" }, { "BriefDescription": "Off-core accesses per kilo instruction for reads-to-core requests (speculative; including in-core HW prefetches)", "MetricExpr": "1e3 * OCR.READS_TO_CORE.ANY_RESPONSE / INST_RETIRED.ANY", - "MetricGroup": "CacheHits;Offcore;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_offcore_read_any_pki", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "CacheHits;Offcore", + "MetricName": "tma_info_memory_offcore_read_any_pki" }, { "BriefDescription": "L3 cache misses per kilo instruction for reads-to-core requests (speculative; including in-core HW prefetches)", "MetricExpr": "1e3 * OCR.READS_TO_CORE.L3_MISS / INST_RETIRED.ANY", - "MetricGroup": "Offcore;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_offcore_read_l3m_pki", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Offcore", + "MetricName": "tma_info_memory_offcore_read_l3m_pki" }, { "BriefDescription": "Utilization of the core's Page Walker(s) serving STLB misses triggered by instruction/Load/Store accesses", "MetricExpr": "(ITLB_MISSES.WALK_PENDING + DTLB_LOAD_MISSES.WALK_PENDING + DTLB_STORE_MISSES.WALK_PENDING) / (4 * (CPU_CLK_UNHALTED.DISTRIBUTED if #SMT_on else CPU_CLK_UNHALTED.THREAD))", - "MetricGroup": "Mem;MemoryTLB;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_page_walks_utilization", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Mem;MemoryTLB", + "MetricName": "tma_info_memory_page_walks_utilization" }, { "BriefDescription": "Average DRAM BW for Reads-to-Core (R2C) covering for memory attached to local- and remote-socket", "MetricExpr": "64 * OCR.READS_TO_CORE.DRAM / 1e9 / (duration_time * 1e3 / 1e3)", - "MetricGroup": "HPC;Mem;MemoryBW;SoC;TopdownL1;tma_L1_group", + "MetricGroup": "HPC;Mem;MemoryBW;SoC", "MetricName": "tma_info_memory_r2c_dram_bw", - "MetricgroupNoGroup": "TopdownL1", "PublicDescription": "Average DRAM BW for Reads-to-Core (R2C) covering for memory attached to local- and remote-socket. See R2C_Offcore_BW." }, { "BriefDescription": "Average L3-cache miss BW for Reads-to-Core (R2C)", "MetricExpr": "64 * OCR.READS_TO_CORE.L3_MISS / 1e9 / (duration_time * 1e3 / 1e3)", - "MetricGroup": "HPC;Mem;MemoryBW;SoC;TopdownL1;tma_L1_group", + "MetricGroup": "HPC;Mem;MemoryBW;SoC", "MetricName": "tma_info_memory_r2c_l3m_bw", - "MetricgroupNoGroup": "TopdownL1", "PublicDescription": "Average L3-cache miss BW for Reads-to-Core (R2C). This covering going to DRAM or other memory off-chip memory tears. See R2C_Offcore_BW." }, { "BriefDescription": "Average Off-core access BW for Reads-to-Core (R2C)", "MetricExpr": "64 * OCR.READS_TO_CORE.ANY_RESPONSE / 1e9 / (duration_time * 1e3 / 1e3)", - "MetricGroup": "HPC;Mem;MemoryBW;SoC;TopdownL1;tma_L1_group", + "MetricGroup": "HPC;Mem;MemoryBW;SoC", "MetricName": "tma_info_memory_r2c_offcore_bw", - "MetricgroupNoGroup": "TopdownL1", "PublicDescription": "Average Off-core access BW for Reads-to-Core (R2C). R2C account for demand or prefetch load/RFO/code access that fill data into the Core caches." }, { @@ -1458,9 +1435,8 @@ { "BriefDescription": "STLB (2nd level TLB) data store speculative misses per kilo instruction (misses of any page-size that complete the page walk)", "MetricExpr": "tma_info_memory_tlb_store_stlb_mpki", - "MetricGroup": "Mem;MemoryTLB;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_store_stlb_mpki", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Mem;MemoryTLB", + "MetricName": "tma_info_memory_store_stlb_mpki" }, { "BriefDescription": "STLB (2nd level TLB) code speculative misses per kilo instruction (misses of any page-size that complete the page walk)", @@ -1490,9 +1466,8 @@ { "BriefDescription": "Un-cacheable retired load per kilo instruction", "MetricExpr": "1e3 * MEM_LOAD_MISC_RETIRED.UC / INST_RETIRED.ANY", - "MetricGroup": "Mem;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_uc_load_pki", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Mem", + "MetricName": "tma_info_memory_uc_load_pki" }, { "BriefDescription": "", diff --git a/tools/perf/pmu-events/arch/x86/skylakex/skx-metrics.json b/tools/perf/pmu-events/arch/x86/skylakex/skx-metrics.json index 025e836a1c80..8126f952a30c 100644 --- a/tools/perf/pmu-events/arch/x86/skylakex/skx-metrics.json +++ b/tools/perf/pmu-events/arch/x86/skylakex/skx-metrics.json @@ -652,23 +652,20 @@ { "BriefDescription": "Probability of Core Bound bottleneck hidden by SMT-profiling artifacts", "MetricExpr": "(100 * (1 - tma_core_bound / (((EXE_ACTIVITY.EXE_BOUND_0_PORTS + tma_core_bound * RS_EVENTS.EMPTY_CYCLES) / CPU_CLK_UNHALTED.THREAD * (CYCLE_ACTIVITY.STALLS_TOTAL - CYCLE_ACTIVITY.STALLS_MEM_ANY) / CPU_CLK_UNHALTED.THREAD * CPU_CLK_UNHALTED.THREAD + (EXE_ACTIVITY.1_PORTS_UTIL + tma_retiring * EXE_ACTIVITY.2_PORTS_UTIL)) / CPU_CLK_UNHALTED.THREAD if ARITH.DIVIDER_ACTIVE < CYCLE_ACTIVITY.STALLS_TOTAL - CYCLE_ACTIVITY.STALLS_MEM_ANY else (EXE_ACTIVITY.1_PORTS_UTIL + tma_retiring * EXE_ACTIVITY.2_PORTS_UTIL) / CPU_CLK_UNHALTED.THREAD) if tma_core_bound < (((EXE_ACTIVITY.EXE_BOUND_0_PORTS + tma_core_bound * RS_EVENTS.EMPTY_CYCLES) / CPU_CLK_UNHALTED.THREAD * (CYCLE_ACTIVITY.STALLS_TOTAL - CYCLE_ACTIVITY.STALLS_MEM_ANY) / CPU_CLK_UNHALTED.THREAD * CPU_CLK_UNHALTED.THREAD + (EXE_ACTIVITY.1_PORTS_UTIL + tma_retiring * EXE_ACTIVITY.2_PORTS_UTIL)) / CPU_CLK_UNHALTED.THREAD if ARITH.DIVIDER_ACTIVE < CYCLE_ACTIVITY.STALLS_TOTAL - CYCLE_ACTIVITY.STALLS_MEM_ANY else (EXE_ACTIVITY.1_PORTS_UTIL + tma_retiring * EXE_ACTIVITY.2_PORTS_UTIL) / CPU_CLK_UNHALTED.THREAD) else 1) if tma_info_system_smt_2t_utilization > 0.5 else 0)", - "MetricGroup": "Cor;SMT;TopdownL1;tma_L1_group", - "MetricName": "tma_info_botlnk_core_bound_likely", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Cor;SMT", + "MetricName": "tma_info_botlnk_core_bound_likely" }, { "BriefDescription": "Total pipeline cost of DSB (uop cache) misses - subset of the Instruction_Fetch_BW Bottleneck.", "MetricExpr": "100 * (100 * (tma_fetch_latency * (DSB2MITE_SWITCHES.PENALTY_CYCLES / CPU_CLK_UNHALTED.THREAD) / ((ICACHE_16B.IFDATA_STALL + 2 * cpu@ICACHE_16B.IFDATA_STALL\\,cmask\\=0x1\\,edge\\=0x1@) / CPU_CLK_UNHALTED.THREAD + ICACHE_TAG.STALLS / CPU_CLK_UNHALTED.THREAD + (INT_MISC.CLEAR_RESTEER_CYCLES / CPU_CLK_UNHALTED.THREAD + 9 * BACLEARS.ANY / CPU_CLK_UNHALTED.THREAD) + min(2 * IDQ.MS_SWITCHES / CPU_CLK_UNHALTED.THREAD, 1) + DECODE.LCP / CPU_CLK_UNHALTED.THREAD + DSB2MITE_SWITCHES.PENALTY_CYCLES / CPU_CLK_UNHALTED.THREAD) + tma_fetch_bandwidth * tma_mite / (tma_mite + tma_dsb)))", - "MetricGroup": "DSBmiss;Fed;TopdownL1;tma_L1_group", - "MetricName": "tma_info_botlnk_dsb_misses", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "DSBmiss;Fed", + "MetricName": "tma_info_botlnk_dsb_misses" }, { "BriefDescription": "Total pipeline cost of Instruction Cache misses - subset of the Big_Code Bottleneck.", "MetricExpr": "100 * (100 * (tma_fetch_latency * ((ICACHE_16B.IFDATA_STALL + 2 * cpu@ICACHE_16B.IFDATA_STALL\\,cmask\\=0x1\\,edge\\=0x1@) / CPU_CLK_UNHALTED.THREAD) / ((ICACHE_16B.IFDATA_STALL + 2 * cpu@ICACHE_16B.IFDATA_STALL\\,cmask\\=0x1\\,edge\\=0x1@) / CPU_CLK_UNHALTED.THREAD + ICACHE_TAG.STALLS / CPU_CLK_UNHALTED.THREAD + (INT_MISC.CLEAR_RESTEER_CYCLES / CPU_CLK_UNHALTED.THREAD + 9 * BACLEARS.ANY / CPU_CLK_UNHALTED.THREAD) + min(2 * IDQ.MS_SWITCHES / CPU_CLK_UNHALTED.THREAD, 1) + DECODE.LCP / CPU_CLK_UNHALTED.THREAD + DSB2MITE_SWITCHES.PENALTY_CYCLES / CPU_CLK_UNHALTED.THREAD)))", - "MetricGroup": "Fed;FetchLat;IcMiss;TopdownL1;tma_L1_group", - "MetricName": "tma_info_botlnk_ic_misses", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Fed;FetchLat;IcMiss", + "MetricName": "tma_info_botlnk_ic_misses" }, { "BriefDescription": "Probability of Core Bound bottleneck hidden by SMT-profiling artifacts", @@ -1021,9 +1018,8 @@ { "BriefDescription": "STLB (2nd level TLB) code speculative misses per kilo instruction (misses of any page-size that complete the page walk)", "MetricExpr": "tma_info_memory_tlb_code_stlb_mpki", - "MetricGroup": "Fed;MemoryTLB;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_code_stlb_mpki", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Fed;MemoryTLB", + "MetricName": "tma_info_memory_code_stlb_mpki" }, { "BriefDescription": "Average per-core data fill bandwidth to the L1 data cache [GB / sec]", @@ -1064,9 +1060,8 @@ { "BriefDescription": "Average Parallel L2 cache miss data reads", "MetricExpr": "tma_info_memory_latency_data_l2_mlp", - "MetricGroup": "Memory_BW;Offcore;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_data_l2_mlp", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Memory_BW;Offcore", + "MetricName": "tma_info_memory_data_l2_mlp" }, { "BriefDescription": "Fill Buffer (FB) hits per kilo instructions for retired demand loads (L1D misses that merge into ongoing miss-handling entries)", @@ -1083,9 +1078,8 @@ { "BriefDescription": "Average per-core data fill bandwidth to the L1 data cache [GB / sec]", "MetricExpr": "64 * L1D.REPLACEMENT / 1e9 / (duration_time * 1e3 / 1e3)", - "MetricGroup": "Mem;MemoryBW;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_l1d_cache_fill_bw_2t", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Mem;MemoryBW", + "MetricName": "tma_info_memory_l1d_cache_fill_bw_2t" }, { "BriefDescription": "L1 cache true misses per kilo instruction for retired demand loads", @@ -1108,23 +1102,20 @@ { "BriefDescription": "Average per-core data fill bandwidth to the L2 cache [GB / sec]", "MetricExpr": "64 * L2_LINES_IN.ALL / 1e9 / (duration_time * 1e3 / 1e3)", - "MetricGroup": "Mem;MemoryBW;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_l2_cache_fill_bw_2t", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Mem;MemoryBW", + "MetricName": "tma_info_memory_l2_cache_fill_bw_2t" }, { "BriefDescription": "Rate of non silent evictions from the L2 cache per Kilo instruction", "MetricExpr": "1e3 * L2_LINES_OUT.NON_SILENT / INST_RETIRED.ANY", - "MetricGroup": "L2Evicts;Mem;Server;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_l2_evictions_nonsilent_pki", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "L2Evicts;Mem;Server", + "MetricName": "tma_info_memory_l2_evictions_nonsilent_pki" }, { "BriefDescription": "Rate of silent evictions from the L2 cache per Kilo instruction where the evicted lines are dropped (no writeback to L3 or memory)", "MetricExpr": "1e3 * L2_LINES_OUT.SILENT / INST_RETIRED.ANY", - "MetricGroup": "L2Evicts;Mem;Server;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_l2_evictions_silent_pki", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "L2Evicts;Mem;Server", + "MetricName": "tma_info_memory_l2_evictions_silent_pki" }, { "BriefDescription": "L2 cache hits per kilo instruction for all request types (including speculative)", @@ -1165,9 +1156,8 @@ { "BriefDescription": "Average per-core data access bandwidth to the L3 cache [GB / sec]", "MetricExpr": "64 * OFFCORE_REQUESTS.ALL_REQUESTS / 1e9 / (duration_time * 1e3 / 1e3)", - "MetricGroup": "Mem;MemoryBW;Offcore;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_l3_cache_access_bw_2t", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Mem;MemoryBW;Offcore", + "MetricName": "tma_info_memory_l3_cache_access_bw_2t" }, { "BriefDescription": "", @@ -1178,9 +1168,8 @@ { "BriefDescription": "Average per-core data fill bandwidth to the L3 cache [GB / sec]", "MetricExpr": "64 * LONGEST_LAT_CACHE.MISS / 1e9 / (duration_time * 1e3 / 1e3)", - "MetricGroup": "Mem;MemoryBW;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_l3_cache_fill_bw_2t", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Mem;MemoryBW", + "MetricName": "tma_info_memory_l3_cache_fill_bw_2t" }, { "BriefDescription": "L3 cache true misses per kilo instruction for retired demand loads", @@ -1209,16 +1198,14 @@ { "BriefDescription": "Average Latency for L2 cache miss demand Loads", "MetricExpr": "OFFCORE_REQUESTS_OUTSTANDING.DEMAND_DATA_RD / OFFCORE_REQUESTS.DEMAND_DATA_RD", - "MetricGroup": "Memory_Lat;Offcore;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_load_l2_miss_latency", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Memory_Lat;Offcore", + "MetricName": "tma_info_memory_load_l2_miss_latency" }, { "BriefDescription": "Average Parallel L2 cache miss demand Loads", "MetricExpr": "OFFCORE_REQUESTS_OUTSTANDING.DEMAND_DATA_RD / OFFCORE_REQUESTS_OUTSTANDING.CYCLES_WITH_DEMAND_DATA_RD", - "MetricGroup": "Memory_BW;Offcore;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_load_l2_mlp", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Memory_BW;Offcore", + "MetricName": "tma_info_memory_load_l2_mlp" }, { "BriefDescription": "Actual Average Latency for L1 data-cache miss demand load operations (in core cycles)", @@ -1229,9 +1216,8 @@ { "BriefDescription": "STLB (2nd level TLB) data load speculative misses per kilo instruction (misses of any page-size that complete the page walk)", "MetricExpr": "tma_info_memory_tlb_load_stlb_mpki", - "MetricGroup": "Mem;MemoryTLB;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_load_stlb_mpki", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Mem;MemoryTLB", + "MetricName": "tma_info_memory_load_stlb_mpki" }, { "BriefDescription": "Un-cacheable retired load per kilo instruction", @@ -1249,16 +1235,14 @@ { "BriefDescription": "Utilization of the core's Page Walker(s) serving STLB misses triggered by instruction/Load/Store accesses", "MetricExpr": "tma_info_memory_tlb_page_walks_utilization", - "MetricGroup": "Mem;MemoryTLB;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_page_walks_utilization", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Mem;MemoryTLB", + "MetricName": "tma_info_memory_page_walks_utilization" }, { "BriefDescription": "STLB (2nd level TLB) data store speculative misses per kilo instruction (misses of any page-size that complete the page walk)", "MetricExpr": "tma_info_memory_tlb_store_stlb_mpki", - "MetricGroup": "Mem;MemoryTLB;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_store_stlb_mpki", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Mem;MemoryTLB", + "MetricName": "tma_info_memory_store_stlb_mpki" }, { "BriefDescription": "STLB (2nd level TLB) code speculative misses per kilo instruction (misses of any page-size that complete the page walk)", @@ -1289,9 +1273,8 @@ { "BriefDescription": "Un-cacheable retired load per kilo instruction", "MetricExpr": "1e3 * MEM_LOAD_MISC_RETIRED.UC / INST_RETIRED.ANY", - "MetricGroup": "Mem;TopdownL1;tma_L1_group", - "MetricName": "tma_info_memory_uc_load_pki", - "MetricgroupNoGroup": "TopdownL1" + "MetricGroup": "Mem", + "MetricName": "tma_info_memory_uc_load_pki" }, { "BriefDescription": "", -- cgit v1.2.3-59-g8ed1b From 2a5049b75d22c971e73501784f10548c1d69c407 Mon Sep 17 00:00:00 2001 From: Anne Macedo Date: Tue, 19 Mar 2024 14:36:26 +0000 Subject: perf lock contention: Trim backtrace by skipping traceiter functions The 'perf lock contention' program currently shows the caller of the locks as __traceiter_contention_begin+0x??. This caller can be ignored, as it is from the traceiter itself. Instead, it should show the real callers for the locks. When fiddling with the --stack-skip parameter, the actual callers for the locks start to show up. However, just ignore the __traceiter_contention_begin and the __traceiter_contention_end symbols so the actual callers will show up. Before this patch is applied: sudo perf lock con -a -b -- sleep 3 contended total wait max wait avg wait type caller 8 2.33 s 2.28 s 291.18 ms rwlock:W __traceiter_contention_begin+0x44 4 2.33 s 2.28 s 582.35 ms rwlock:W __traceiter_contention_begin+0x44 7 140.30 ms 46.77 ms 20.04 ms rwlock:W __traceiter_contention_begin+0x44 2 63.35 ms 33.76 ms 31.68 ms mutex trace_contention_begin+0x84 2 46.74 ms 46.73 ms 23.37 ms rwlock:W __traceiter_contention_begin+0x44 1 13.54 us 13.54 us 13.54 us mutex trace_contention_begin+0x84 1 3.67 us 3.67 us 3.67 us rwsem:R __traceiter_contention_begin+0x44 Before this patch is applied - using --stack-skip 5 sudo perf lock con --stack-skip 5 -a -b -- sleep 3 contended total wait max wait avg wait type caller 2 2.24 s 2.24 s 1.12 s rwlock:W do_epoll_wait+0x5a0 4 1.65 s 824.21 ms 412.08 ms rwlock:W do_exit+0x338 2 824.35 ms 824.29 ms 412.17 ms spinlock get_signal+0x108 2 824.14 ms 824.14 ms 412.07 ms rwlock:W release_task+0x68 1 25.22 ms 25.22 ms 25.22 ms mutex cgroup_kn_lock_live+0x58 1 24.71 us 24.71 us 24.71 us spinlock do_exit+0x44 1 22.04 us 22.04 us 22.04 us rwsem:R lock_mm_and_find_vma+0xb0 After this patch is applied: sudo ./perf lock con -a -b -- sleep 3 contended total wait max wait avg wait type caller 4 4.13 s 2.07 s 1.03 s rwlock:W release_task+0x68 2 2.07 s 2.07 s 1.03 s rwlock:R mm_update_next_owner+0x50 2 2.07 s 2.07 s 1.03 s rwlock:W do_exit+0x338 1 41.56 ms 41.56 ms 41.56 ms mutex cgroup_kn_lock_live+0x58 2 36.12 us 18.83 us 18.06 us rwlock:W do_exit+0x338 Signed-off-by: Anne Macedo Acked-by: Namhyung Kim Tested-by: Arnaldo Carvalho de Melo Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Mark Rutland Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20240319143629.3422590-1-retpolanne@posteo.net Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/machine.c | 24 ++++++++++++++++++++++++ tools/perf/util/machine.h | 2 +- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index 527517db3182..5eb9044bc223 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -3266,6 +3266,17 @@ bool machine__is_lock_function(struct machine *machine, u64 addr) sym = machine__find_kernel_symbol_by_name(machine, "__lock_text_end", &kmap); machine->lock.text_end = map__unmap_ip(kmap, sym->start); + + sym = machine__find_kernel_symbol_by_name(machine, "__traceiter_contention_begin", &kmap); + if (sym) { + machine->traceiter.text_start = map__unmap_ip(kmap, sym->start); + machine->traceiter.text_end = map__unmap_ip(kmap, sym->end); + } + sym = machine__find_kernel_symbol_by_name(machine, "trace_contention_begin", &kmap); + if (sym) { + machine->trace.text_start = map__unmap_ip(kmap, sym->start); + machine->trace.text_end = map__unmap_ip(kmap, sym->end); + } } /* failed to get kernel symbols */ @@ -3280,5 +3291,18 @@ bool machine__is_lock_function(struct machine *machine, u64 addr) if (machine->lock.text_start <= addr && addr < machine->lock.text_end) return true; + /* traceiter functions currently don't have their own section + * but we consider them lock functions + */ + if (machine->traceiter.text_start != 0) { + if (machine->traceiter.text_start <= addr && addr < machine->traceiter.text_end) + return true; + } + + if (machine->trace.text_start != 0) { + if (machine->trace.text_start <= addr && addr < machine->trace.text_end) + return true; + } + return false; } diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h index e28c787616fe..4312f6db6de0 100644 --- a/tools/perf/util/machine.h +++ b/tools/perf/util/machine.h @@ -49,7 +49,7 @@ struct machine { struct { u64 text_start; u64 text_end; - } sched, lock; + } sched, lock, traceiter, trace; pid_t *current_tid; size_t current_tid_sz; union { /* Tool specific area */ -- cgit v1.2.3-59-g8ed1b From b3ad832d8da583ff4237b04a1ba23cdbf8918907 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 21 Mar 2024 09:02:48 -0700 Subject: perf dso: Reorder members to save space in 'struct dso' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Save 40 bytes and move from 8 to 7 cache lines. Make member dwfl dependent on being a powerpc build. Squeeze bits of int/enum types when appropriate. Remove holes/padding by reordering variables. Before: struct dso { struct mutex lock; /* 0 40 */ struct list_head node; /* 40 16 */ struct rb_node rb_node __attribute__((__aligned__(8))); /* 56 24 */ /* --- cacheline 1 boundary (64 bytes) was 16 bytes ago --- */ struct rb_root * root; /* 80 8 */ struct rb_root_cached symbols; /* 88 16 */ struct symbol * * symbol_names; /* 104 8 */ size_t symbol_names_len; /* 112 8 */ struct rb_root_cached inlined_nodes; /* 120 16 */ /* --- cacheline 2 boundary (128 bytes) was 8 bytes ago --- */ struct rb_root_cached srclines; /* 136 16 */ struct { u64 addr; /* 152 8 */ struct symbol * symbol; /* 160 8 */ } last_find_result; /* 152 16 */ void * a2l; /* 168 8 */ char * symsrc_filename; /* 176 8 */ unsigned int a2l_fails; /* 184 4 */ enum dso_space_type kernel; /* 188 4 */ /* --- cacheline 3 boundary (192 bytes) --- */ _Bool is_kmod; /* 192 1 */ /* XXX 3 bytes hole, try to pack */ enum dso_swap_type needs_swap; /* 196 4 */ enum dso_binary_type symtab_type; /* 200 4 */ enum dso_binary_type binary_type; /* 204 4 */ enum dso_load_errno load_errno; /* 208 4 */ u8 adjust_symbols:1; /* 212: 0 1 */ u8 has_build_id:1; /* 212: 1 1 */ u8 header_build_id:1; /* 212: 2 1 */ u8 has_srcline:1; /* 212: 3 1 */ u8 hit:1; /* 212: 4 1 */ u8 annotate_warned:1; /* 212: 5 1 */ u8 auxtrace_warned:1; /* 212: 6 1 */ u8 short_name_allocated:1; /* 212: 7 1 */ u8 long_name_allocated:1; /* 213: 0 1 */ u8 is_64_bit:1; /* 213: 1 1 */ /* XXX 6 bits hole, try to pack */ _Bool sorted_by_name; /* 214 1 */ _Bool loaded; /* 215 1 */ u8 rel; /* 216 1 */ /* XXX 7 bytes hole, try to pack */ struct build_id bid; /* 224 32 */ /* --- cacheline 4 boundary (256 bytes) --- */ u64 text_offset; /* 256 8 */ u64 text_end; /* 264 8 */ const char * short_name; /* 272 8 */ const char * long_name; /* 280 8 */ u16 long_name_len; /* 288 2 */ u16 short_name_len; /* 290 2 */ /* XXX 4 bytes hole, try to pack */ void * dwfl; /* 296 8 */ struct auxtrace_cache * auxtrace_cache; /* 304 8 */ int comp; /* 312 4 */ /* XXX 4 bytes hole, try to pack */ /* --- cacheline 5 boundary (320 bytes) --- */ struct { struct rb_root cache; /* 320 8 */ int fd; /* 328 4 */ int status; /* 332 4 */ u32 status_seen; /* 336 4 */ /* XXX 4 bytes hole, try to pack */ u64 file_size; /* 344 8 */ struct list_head open_entry; /* 352 16 */ u64 elf_base_addr; /* 368 8 */ u64 debug_frame_offset; /* 376 8 */ /* --- cacheline 6 boundary (384 bytes) --- */ u64 eh_frame_hdr_addr; /* 384 8 */ u64 eh_frame_hdr_offset; /* 392 8 */ } data; /* 320 80 */ struct { u32 id; /* 400 4 */ u32 sub_id; /* 404 4 */ struct perf_env * env; /* 408 8 */ } bpf_prog; /* 400 16 */ union { void * priv; /* 416 8 */ u64 db_id; /* 416 8 */ }; /* 416 8 */ struct nsinfo * nsinfo; /* 424 8 */ struct dso_id id; /* 432 24 */ /* --- cacheline 7 boundary (448 bytes) was 8 bytes ago --- */ refcount_t refcnt; /* 456 4 */ char name[]; /* 460 0 */ /* size: 464, cachelines: 8, members: 49 */ /* sum members: 440, holes: 4, sum holes: 18 */ /* sum bitfield members: 10 bits, bit holes: 1, sum bit holes: 6 bits */ /* padding: 4 */ /* forced alignments: 1 */ /* last cacheline: 16 bytes */ } __attribute__((__aligned__(8))); After: struct dso { struct mutex lock; /* 0 40 */ struct list_head node; /* 40 16 */ struct rb_node rb_node __attribute__((__aligned__(8))); /* 56 24 */ /* --- cacheline 1 boundary (64 bytes) was 16 bytes ago --- */ struct rb_root * root; /* 80 8 */ struct rb_root_cached symbols; /* 88 16 */ struct symbol * * symbol_names; /* 104 8 */ size_t symbol_names_len; /* 112 8 */ struct rb_root_cached inlined_nodes; /* 120 16 */ /* --- cacheline 2 boundary (128 bytes) was 8 bytes ago --- */ struct rb_root_cached srclines; /* 136 16 */ struct { u64 addr; /* 152 8 */ struct symbol * symbol; /* 160 8 */ } last_find_result; /* 152 16 */ struct build_id bid; /* 168 32 */ /* --- cacheline 3 boundary (192 bytes) was 8 bytes ago --- */ u64 text_offset; /* 200 8 */ u64 text_end; /* 208 8 */ const char * short_name; /* 216 8 */ const char * long_name; /* 224 8 */ void * a2l; /* 232 8 */ char * symsrc_filename; /* 240 8 */ struct nsinfo * nsinfo; /* 248 8 */ /* --- cacheline 4 boundary (256 bytes) --- */ struct auxtrace_cache * auxtrace_cache; /* 256 8 */ union { void * priv; /* 264 8 */ u64 db_id; /* 264 8 */ }; /* 264 8 */ struct { struct perf_env * env; /* 272 8 */ u32 id; /* 280 4 */ u32 sub_id; /* 284 4 */ } bpf_prog; /* 272 16 */ struct { struct rb_root cache; /* 288 8 */ struct list_head open_entry; /* 296 16 */ u64 file_size; /* 312 8 */ /* --- cacheline 5 boundary (320 bytes) --- */ u64 elf_base_addr; /* 320 8 */ u64 debug_frame_offset; /* 328 8 */ u64 eh_frame_hdr_addr; /* 336 8 */ u64 eh_frame_hdr_offset; /* 344 8 */ int fd; /* 352 4 */ int status; /* 356 4 */ u32 status_seen; /* 360 4 */ } data; /* 288 80 */ /* XXX last struct has 4 bytes of padding */ struct dso_id id; /* 368 24 */ /* --- cacheline 6 boundary (384 bytes) was 8 bytes ago --- */ unsigned int a2l_fails; /* 392 4 */ int comp; /* 396 4 */ refcount_t refcnt; /* 400 4 */ enum dso_load_errno load_errno; /* 404 4 */ u16 long_name_len; /* 408 2 */ u16 short_name_len; /* 410 2 */ enum dso_binary_type symtab_type:8; /* 412: 0 4 */ enum dso_binary_type binary_type:8; /* 412: 8 4 */ enum dso_space_type kernel:2; /* 412:16 4 */ enum dso_swap_type needs_swap:2; /* 412:18 4 */ /* Bitfield combined with next fields */ _Bool is_kmod:1; /* 414: 4 1 */ u8 adjust_symbols:1; /* 414: 5 1 */ u8 has_build_id:1; /* 414: 6 1 */ u8 header_build_id:1; /* 414: 7 1 */ u8 has_srcline:1; /* 415: 0 1 */ u8 hit:1; /* 415: 1 1 */ u8 annotate_warned:1; /* 415: 2 1 */ u8 auxtrace_warned:1; /* 415: 3 1 */ u8 short_name_allocated:1; /* 415: 4 1 */ u8 long_name_allocated:1; /* 415: 5 1 */ u8 is_64_bit:1; /* 415: 6 1 */ /* XXX 1 bit hole, try to pack */ _Bool sorted_by_name; /* 416 1 */ _Bool loaded; /* 417 1 */ u8 rel; /* 418 1 */ char name[]; /* 419 0 */ /* size: 424, cachelines: 7, members: 48 */ /* sum members: 415 */ /* sum bitfield members: 31 bits, bit holes: 1, sum bit holes: 1 bits */ /* padding: 5 */ /* paddings: 1, sum paddings: 4 */ /* forced alignments: 1 */ /* last cacheline: 40 bytes */ } __attribute__((__aligned__(8))); Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Ahelenia Ziemiańska Cc: Alexander Shishkin Cc: Andi Kleen Cc: Athira Rajeev Cc: Ben Gainey Cc: Changbin Du Cc: Chengen Du Cc: Colin Ian King Cc: Ilkka Koskinen Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: K Prateek Nayak Cc: Kan Liang Cc: Leo Yan Cc: Li Dong Cc: Liam Howlett Cc: Mark Rutland Cc: Markus Elfring Cc: Masami Hiramatsu Cc: Miguel Ojeda Cc: Namhyung Kim Cc: Paran Lee Cc: Peter Zijlstra Cc: Ravi Bangoria Cc: Song Liu Cc: Sun Haiyong Cc: Yanteng Si Cc: zhaimingbing Link: https://lore.kernel.org/r/20240321160300.1635121-2-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/dso.h | 84 +++++++++++++++++++++++++-------------------------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h index 2cdcd1e2ef8b..17dab230a2ca 100644 --- a/tools/perf/util/dso.h +++ b/tools/perf/util/dso.h @@ -161,66 +161,66 @@ struct dso { u64 addr; struct symbol *symbol; } last_find_result; - void *a2l; - char *symsrc_filename; - unsigned int a2l_fails; - enum dso_space_type kernel; - bool is_kmod; - enum dso_swap_type needs_swap; - enum dso_binary_type symtab_type; - enum dso_binary_type binary_type; - enum dso_load_errno load_errno; - u8 adjust_symbols:1; - u8 has_build_id:1; - u8 header_build_id:1; - u8 has_srcline:1; - u8 hit:1; - u8 annotate_warned:1; - u8 auxtrace_warned:1; - u8 short_name_allocated:1; - u8 long_name_allocated:1; - u8 is_64_bit:1; - bool sorted_by_name; - bool loaded; - u8 rel; struct build_id bid; u64 text_offset; u64 text_end; const char *short_name; const char *long_name; - u16 long_name_len; - u16 short_name_len; + void *a2l; + char *symsrc_filename; +#if defined(__powerpc__) void *dwfl; /* DWARF debug info */ +#endif + struct nsinfo *nsinfo; struct auxtrace_cache *auxtrace_cache; - int comp; - + union { /* Tool specific area */ + void *priv; + u64 db_id; + }; + /* bpf prog information */ + struct { + struct perf_env *env; + u32 id; + u32 sub_id; + } bpf_prog; /* dso data file */ struct { struct rb_root cache; - int fd; - int status; - u32 status_seen; - u64 file_size; struct list_head open_entry; + u64 file_size; u64 elf_base_addr; u64 debug_frame_offset; u64 eh_frame_hdr_addr; u64 eh_frame_hdr_offset; + int fd; + int status; + u32 status_seen; } data; - /* bpf prog information */ - struct { - u32 id; - u32 sub_id; - struct perf_env *env; - } bpf_prog; - - union { /* Tool specific area */ - void *priv; - u64 db_id; - }; - struct nsinfo *nsinfo; struct dso_id id; + unsigned int a2l_fails; + int comp; refcount_t refcnt; + enum dso_load_errno load_errno; + u16 long_name_len; + u16 short_name_len; + enum dso_binary_type symtab_type:8; + enum dso_binary_type binary_type:8; + enum dso_space_type kernel:2; + enum dso_swap_type needs_swap:2; + bool is_kmod:1; + u8 adjust_symbols:1; + u8 has_build_id:1; + u8 header_build_id:1; + u8 has_srcline:1; + u8 hit:1; + u8 annotate_warned:1; + u8 auxtrace_warned:1; + u8 short_name_allocated:1; + u8 long_name_allocated:1; + u8 is_64_bit:1; + bool sorted_by_name; + bool loaded; + u8 rel; char name[]; }; -- cgit v1.2.3-59-g8ed1b From 4962e1949608fed932d661ef45803a5bee69bebe Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 11 Mar 2024 17:07:33 -0300 Subject: perf beauty: Move uapi/linux/vhost.h copy out of the directory used to build perf It is only used to generate string tables, not to build perf, so move it to the tools/perf/trace/beauty/include/ hierarchy, that is used just for scraping. This is a something that should've have happened, as happened with the linux/socket.h scrapper, do it now as Ian suggested while doing an audit/refactor session in the headers used by perf. No other tools/ living code uses it, just coming from either 'make install_headers' or from the system /usr/include/ directory. Suggested-by: Ian Rogers Cc: Adrian Hunter Cc: Jiri Olsa Cc: Namhyung Kim Link: https://lore.kernel.org/lkml/CAP-5=fWZVrpRufO4w-S4EcSi9STXcTAN2ERLwTSN7yrSSA-otQ@mail.gmail.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/include/uapi/linux/vhost.h | 230 --------------------- tools/perf/Makefile.perf | 5 +- tools/perf/check-headers.sh | 2 +- tools/perf/trace/beauty/include/uapi/linux/vhost.h | 230 +++++++++++++++++++++ tools/perf/trace/beauty/vhost_virtio_ioctl.sh | 6 +- 5 files changed, 236 insertions(+), 237 deletions(-) delete mode 100644 tools/include/uapi/linux/vhost.h create mode 100644 tools/perf/trace/beauty/include/uapi/linux/vhost.h diff --git a/tools/include/uapi/linux/vhost.h b/tools/include/uapi/linux/vhost.h deleted file mode 100644 index 649560c685f1..000000000000 --- a/tools/include/uapi/linux/vhost.h +++ /dev/null @@ -1,230 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -#ifndef _LINUX_VHOST_H -#define _LINUX_VHOST_H -/* Userspace interface for in-kernel virtio accelerators. */ - -/* vhost is used to reduce the number of system calls involved in virtio. - * - * Existing virtio net code is used in the guest without modification. - * - * This header includes interface used by userspace hypervisor for - * device configuration. - */ - -#include -#include -#include - -#define VHOST_FILE_UNBIND -1 - -/* ioctls */ - -#define VHOST_VIRTIO 0xAF - -/* Features bitmask for forward compatibility. Transport bits are used for - * vhost specific features. */ -#define VHOST_GET_FEATURES _IOR(VHOST_VIRTIO, 0x00, __u64) -#define VHOST_SET_FEATURES _IOW(VHOST_VIRTIO, 0x00, __u64) - -/* Set current process as the (exclusive) owner of this file descriptor. This - * must be called before any other vhost command. Further calls to - * VHOST_OWNER_SET fail until VHOST_OWNER_RESET is called. */ -#define VHOST_SET_OWNER _IO(VHOST_VIRTIO, 0x01) -/* Give up ownership, and reset the device to default values. - * Allows subsequent call to VHOST_OWNER_SET to succeed. */ -#define VHOST_RESET_OWNER _IO(VHOST_VIRTIO, 0x02) - -/* Set up/modify memory layout */ -#define VHOST_SET_MEM_TABLE _IOW(VHOST_VIRTIO, 0x03, struct vhost_memory) - -/* Write logging setup. */ -/* Memory writes can optionally be logged by setting bit at an offset - * (calculated from the physical address) from specified log base. - * The bit is set using an atomic 32 bit operation. */ -/* Set base address for logging. */ -#define VHOST_SET_LOG_BASE _IOW(VHOST_VIRTIO, 0x04, __u64) -/* Specify an eventfd file descriptor to signal on log write. */ -#define VHOST_SET_LOG_FD _IOW(VHOST_VIRTIO, 0x07, int) -/* By default, a device gets one vhost_worker that its virtqueues share. This - * command allows the owner of the device to create an additional vhost_worker - * for the device. It can later be bound to 1 or more of its virtqueues using - * the VHOST_ATTACH_VRING_WORKER command. - * - * This must be called after VHOST_SET_OWNER and the caller must be the owner - * of the device. The new thread will inherit caller's cgroups and namespaces, - * and will share the caller's memory space. The new thread will also be - * counted against the caller's RLIMIT_NPROC value. - * - * The worker's ID used in other commands will be returned in - * vhost_worker_state. - */ -#define VHOST_NEW_WORKER _IOR(VHOST_VIRTIO, 0x8, struct vhost_worker_state) -/* Free a worker created with VHOST_NEW_WORKER if it's not attached to any - * virtqueue. If userspace is not able to call this for workers its created, - * the kernel will free all the device's workers when the device is closed. - */ -#define VHOST_FREE_WORKER _IOW(VHOST_VIRTIO, 0x9, struct vhost_worker_state) - -/* Ring setup. */ -/* Set number of descriptors in ring. This parameter can not - * be modified while ring is running (bound to a device). */ -#define VHOST_SET_VRING_NUM _IOW(VHOST_VIRTIO, 0x10, struct vhost_vring_state) -/* Set addresses for the ring. */ -#define VHOST_SET_VRING_ADDR _IOW(VHOST_VIRTIO, 0x11, struct vhost_vring_addr) -/* Base value where queue looks for available descriptors */ -#define VHOST_SET_VRING_BASE _IOW(VHOST_VIRTIO, 0x12, struct vhost_vring_state) -/* Get accessor: reads index, writes value in num */ -#define VHOST_GET_VRING_BASE _IOWR(VHOST_VIRTIO, 0x12, struct vhost_vring_state) - -/* Set the vring byte order in num. Valid values are VHOST_VRING_LITTLE_ENDIAN - * or VHOST_VRING_BIG_ENDIAN (other values return -EINVAL). - * The byte order cannot be changed while the device is active: trying to do so - * returns -EBUSY. - * This is a legacy only API that is simply ignored when VIRTIO_F_VERSION_1 is - * set. - * Not all kernel configurations support this ioctl, but all configurations that - * support SET also support GET. - */ -#define VHOST_VRING_LITTLE_ENDIAN 0 -#define VHOST_VRING_BIG_ENDIAN 1 -#define VHOST_SET_VRING_ENDIAN _IOW(VHOST_VIRTIO, 0x13, struct vhost_vring_state) -#define VHOST_GET_VRING_ENDIAN _IOW(VHOST_VIRTIO, 0x14, struct vhost_vring_state) -/* Attach a vhost_worker created with VHOST_NEW_WORKER to one of the device's - * virtqueues. - * - * This will replace the virtqueue's existing worker. If the replaced worker - * is no longer attached to any virtqueues, it can be freed with - * VHOST_FREE_WORKER. - */ -#define VHOST_ATTACH_VRING_WORKER _IOW(VHOST_VIRTIO, 0x15, \ - struct vhost_vring_worker) -/* Return the vring worker's ID */ -#define VHOST_GET_VRING_WORKER _IOWR(VHOST_VIRTIO, 0x16, \ - struct vhost_vring_worker) - -/* The following ioctls use eventfd file descriptors to signal and poll - * for events. */ - -/* Set eventfd to poll for added buffers */ -#define VHOST_SET_VRING_KICK _IOW(VHOST_VIRTIO, 0x20, struct vhost_vring_file) -/* Set eventfd to signal when buffers have beed used */ -#define VHOST_SET_VRING_CALL _IOW(VHOST_VIRTIO, 0x21, struct vhost_vring_file) -/* Set eventfd to signal an error */ -#define VHOST_SET_VRING_ERR _IOW(VHOST_VIRTIO, 0x22, struct vhost_vring_file) -/* Set busy loop timeout (in us) */ -#define VHOST_SET_VRING_BUSYLOOP_TIMEOUT _IOW(VHOST_VIRTIO, 0x23, \ - struct vhost_vring_state) -/* Get busy loop timeout (in us) */ -#define VHOST_GET_VRING_BUSYLOOP_TIMEOUT _IOW(VHOST_VIRTIO, 0x24, \ - struct vhost_vring_state) - -/* Set or get vhost backend capability */ - -#define VHOST_SET_BACKEND_FEATURES _IOW(VHOST_VIRTIO, 0x25, __u64) -#define VHOST_GET_BACKEND_FEATURES _IOR(VHOST_VIRTIO, 0x26, __u64) - -/* VHOST_NET specific defines */ - -/* Attach virtio net ring to a raw socket, or tap device. - * The socket must be already bound to an ethernet device, this device will be - * used for transmit. Pass fd -1 to unbind from the socket and the transmit - * device. This can be used to stop the ring (e.g. for migration). */ -#define VHOST_NET_SET_BACKEND _IOW(VHOST_VIRTIO, 0x30, struct vhost_vring_file) - -/* VHOST_SCSI specific defines */ - -#define VHOST_SCSI_SET_ENDPOINT _IOW(VHOST_VIRTIO, 0x40, struct vhost_scsi_target) -#define VHOST_SCSI_CLEAR_ENDPOINT _IOW(VHOST_VIRTIO, 0x41, struct vhost_scsi_target) -/* Changing this breaks userspace. */ -#define VHOST_SCSI_GET_ABI_VERSION _IOW(VHOST_VIRTIO, 0x42, int) -/* Set and get the events missed flag */ -#define VHOST_SCSI_SET_EVENTS_MISSED _IOW(VHOST_VIRTIO, 0x43, __u32) -#define VHOST_SCSI_GET_EVENTS_MISSED _IOW(VHOST_VIRTIO, 0x44, __u32) - -/* VHOST_VSOCK specific defines */ - -#define VHOST_VSOCK_SET_GUEST_CID _IOW(VHOST_VIRTIO, 0x60, __u64) -#define VHOST_VSOCK_SET_RUNNING _IOW(VHOST_VIRTIO, 0x61, int) - -/* VHOST_VDPA specific defines */ - -/* Get the device id. The device ids follow the same definition of - * the device id defined in virtio-spec. - */ -#define VHOST_VDPA_GET_DEVICE_ID _IOR(VHOST_VIRTIO, 0x70, __u32) -/* Get and set the status. The status bits follow the same definition - * of the device status defined in virtio-spec. - */ -#define VHOST_VDPA_GET_STATUS _IOR(VHOST_VIRTIO, 0x71, __u8) -#define VHOST_VDPA_SET_STATUS _IOW(VHOST_VIRTIO, 0x72, __u8) -/* Get and set the device config. The device config follows the same - * definition of the device config defined in virtio-spec. - */ -#define VHOST_VDPA_GET_CONFIG _IOR(VHOST_VIRTIO, 0x73, \ - struct vhost_vdpa_config) -#define VHOST_VDPA_SET_CONFIG _IOW(VHOST_VIRTIO, 0x74, \ - struct vhost_vdpa_config) -/* Enable/disable the ring. */ -#define VHOST_VDPA_SET_VRING_ENABLE _IOW(VHOST_VIRTIO, 0x75, \ - struct vhost_vring_state) -/* Get the max ring size. */ -#define VHOST_VDPA_GET_VRING_NUM _IOR(VHOST_VIRTIO, 0x76, __u16) - -/* Set event fd for config interrupt*/ -#define VHOST_VDPA_SET_CONFIG_CALL _IOW(VHOST_VIRTIO, 0x77, int) - -/* Get the valid iova range */ -#define VHOST_VDPA_GET_IOVA_RANGE _IOR(VHOST_VIRTIO, 0x78, \ - struct vhost_vdpa_iova_range) -/* Get the config size */ -#define VHOST_VDPA_GET_CONFIG_SIZE _IOR(VHOST_VIRTIO, 0x79, __u32) - -/* Get the count of all virtqueues */ -#define VHOST_VDPA_GET_VQS_COUNT _IOR(VHOST_VIRTIO, 0x80, __u32) - -/* Get the number of virtqueue groups. */ -#define VHOST_VDPA_GET_GROUP_NUM _IOR(VHOST_VIRTIO, 0x81, __u32) - -/* Get the number of address spaces. */ -#define VHOST_VDPA_GET_AS_NUM _IOR(VHOST_VIRTIO, 0x7A, unsigned int) - -/* Get the group for a virtqueue: read index, write group in num, - * The virtqueue index is stored in the index field of - * vhost_vring_state. The group for this specific virtqueue is - * returned via num field of vhost_vring_state. - */ -#define VHOST_VDPA_GET_VRING_GROUP _IOWR(VHOST_VIRTIO, 0x7B, \ - struct vhost_vring_state) -/* Set the ASID for a virtqueue group. The group index is stored in - * the index field of vhost_vring_state, the ASID associated with this - * group is stored at num field of vhost_vring_state. - */ -#define VHOST_VDPA_SET_GROUP_ASID _IOW(VHOST_VIRTIO, 0x7C, \ - struct vhost_vring_state) - -/* Suspend a device so it does not process virtqueue requests anymore - * - * After the return of ioctl the device must preserve all the necessary state - * (the virtqueue vring base plus the possible device specific states) that is - * required for restoring in the future. The device must not change its - * configuration after that point. - */ -#define VHOST_VDPA_SUSPEND _IO(VHOST_VIRTIO, 0x7D) - -/* Resume a device so it can resume processing virtqueue requests - * - * After the return of this ioctl the device will have restored all the - * necessary states and it is fully operational to continue processing the - * virtqueue descriptors. - */ -#define VHOST_VDPA_RESUME _IO(VHOST_VIRTIO, 0x7E) - -/* Get the group for the descriptor table including driver & device areas - * of a virtqueue: read index, write group in num. - * The virtqueue index is stored in the index field of vhost_vring_state. - * The group ID of the descriptor table for this specific virtqueue - * is returned via num field of vhost_vring_state. - */ -#define VHOST_VDPA_GET_VRING_DESC_GROUP _IOWR(VHOST_VIRTIO, 0x7F, \ - struct vhost_vring_state) -#endif diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index 0d2dbdfc44df..5c35c0d89306 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -580,11 +580,10 @@ $(sockaddr_arrays): $(beauty_linux_dir)/socket.h $(sockaddr_tbl) $(Q)$(SHELL) '$(sockaddr_tbl)' $(beauty_linux_dir) > $@ vhost_virtio_ioctl_array := $(beauty_ioctl_outdir)/vhost_virtio_ioctl_array.c -vhost_virtio_hdr_dir := $(srctree)/tools/include/uapi/linux vhost_virtio_ioctl_tbl := $(srctree)/tools/perf/trace/beauty/vhost_virtio_ioctl.sh -$(vhost_virtio_ioctl_array): $(vhost_virtio_hdr_dir)/vhost.h $(vhost_virtio_ioctl_tbl) - $(Q)$(SHELL) '$(vhost_virtio_ioctl_tbl)' $(vhost_virtio_hdr_dir) > $@ +$(vhost_virtio_ioctl_array): $(beauty_uapi_linux_dir)/vhost.h $(vhost_virtio_ioctl_tbl) + $(Q)$(SHELL) '$(vhost_virtio_ioctl_tbl)' $(beauty_uapi_linux_dir) > $@ perf_ioctl_array := $(beauty_ioctl_outdir)/perf_ioctl_array.c perf_hdr_dir := $(srctree)/tools/include/uapi/linux diff --git a/tools/perf/check-headers.sh b/tools/perf/check-headers.sh index 76726a5a7c78..95a3a404bc6f 100755 --- a/tools/perf/check-headers.sh +++ b/tools/perf/check-headers.sh @@ -16,7 +16,6 @@ FILES=( "include/uapi/linux/in.h" "include/uapi/linux/perf_event.h" "include/uapi/linux/seccomp.h" - "include/uapi/linux/vhost.h" "include/linux/bits.h" "include/vdso/bits.h" "include/linux/const.h" @@ -96,6 +95,7 @@ BEAUTY_FILES=( "include/uapi/linux/sched.h" "include/uapi/linux/stat.h" "include/uapi/linux/usbdevice_fs.h" + "include/uapi/linux/vhost.h" "include/uapi/sound/asound.h" ) diff --git a/tools/perf/trace/beauty/include/uapi/linux/vhost.h b/tools/perf/trace/beauty/include/uapi/linux/vhost.h new file mode 100644 index 000000000000..649560c685f1 --- /dev/null +++ b/tools/perf/trace/beauty/include/uapi/linux/vhost.h @@ -0,0 +1,230 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _LINUX_VHOST_H +#define _LINUX_VHOST_H +/* Userspace interface for in-kernel virtio accelerators. */ + +/* vhost is used to reduce the number of system calls involved in virtio. + * + * Existing virtio net code is used in the guest without modification. + * + * This header includes interface used by userspace hypervisor for + * device configuration. + */ + +#include +#include +#include + +#define VHOST_FILE_UNBIND -1 + +/* ioctls */ + +#define VHOST_VIRTIO 0xAF + +/* Features bitmask for forward compatibility. Transport bits are used for + * vhost specific features. */ +#define VHOST_GET_FEATURES _IOR(VHOST_VIRTIO, 0x00, __u64) +#define VHOST_SET_FEATURES _IOW(VHOST_VIRTIO, 0x00, __u64) + +/* Set current process as the (exclusive) owner of this file descriptor. This + * must be called before any other vhost command. Further calls to + * VHOST_OWNER_SET fail until VHOST_OWNER_RESET is called. */ +#define VHOST_SET_OWNER _IO(VHOST_VIRTIO, 0x01) +/* Give up ownership, and reset the device to default values. + * Allows subsequent call to VHOST_OWNER_SET to succeed. */ +#define VHOST_RESET_OWNER _IO(VHOST_VIRTIO, 0x02) + +/* Set up/modify memory layout */ +#define VHOST_SET_MEM_TABLE _IOW(VHOST_VIRTIO, 0x03, struct vhost_memory) + +/* Write logging setup. */ +/* Memory writes can optionally be logged by setting bit at an offset + * (calculated from the physical address) from specified log base. + * The bit is set using an atomic 32 bit operation. */ +/* Set base address for logging. */ +#define VHOST_SET_LOG_BASE _IOW(VHOST_VIRTIO, 0x04, __u64) +/* Specify an eventfd file descriptor to signal on log write. */ +#define VHOST_SET_LOG_FD _IOW(VHOST_VIRTIO, 0x07, int) +/* By default, a device gets one vhost_worker that its virtqueues share. This + * command allows the owner of the device to create an additional vhost_worker + * for the device. It can later be bound to 1 or more of its virtqueues using + * the VHOST_ATTACH_VRING_WORKER command. + * + * This must be called after VHOST_SET_OWNER and the caller must be the owner + * of the device. The new thread will inherit caller's cgroups and namespaces, + * and will share the caller's memory space. The new thread will also be + * counted against the caller's RLIMIT_NPROC value. + * + * The worker's ID used in other commands will be returned in + * vhost_worker_state. + */ +#define VHOST_NEW_WORKER _IOR(VHOST_VIRTIO, 0x8, struct vhost_worker_state) +/* Free a worker created with VHOST_NEW_WORKER if it's not attached to any + * virtqueue. If userspace is not able to call this for workers its created, + * the kernel will free all the device's workers when the device is closed. + */ +#define VHOST_FREE_WORKER _IOW(VHOST_VIRTIO, 0x9, struct vhost_worker_state) + +/* Ring setup. */ +/* Set number of descriptors in ring. This parameter can not + * be modified while ring is running (bound to a device). */ +#define VHOST_SET_VRING_NUM _IOW(VHOST_VIRTIO, 0x10, struct vhost_vring_state) +/* Set addresses for the ring. */ +#define VHOST_SET_VRING_ADDR _IOW(VHOST_VIRTIO, 0x11, struct vhost_vring_addr) +/* Base value where queue looks for available descriptors */ +#define VHOST_SET_VRING_BASE _IOW(VHOST_VIRTIO, 0x12, struct vhost_vring_state) +/* Get accessor: reads index, writes value in num */ +#define VHOST_GET_VRING_BASE _IOWR(VHOST_VIRTIO, 0x12, struct vhost_vring_state) + +/* Set the vring byte order in num. Valid values are VHOST_VRING_LITTLE_ENDIAN + * or VHOST_VRING_BIG_ENDIAN (other values return -EINVAL). + * The byte order cannot be changed while the device is active: trying to do so + * returns -EBUSY. + * This is a legacy only API that is simply ignored when VIRTIO_F_VERSION_1 is + * set. + * Not all kernel configurations support this ioctl, but all configurations that + * support SET also support GET. + */ +#define VHOST_VRING_LITTLE_ENDIAN 0 +#define VHOST_VRING_BIG_ENDIAN 1 +#define VHOST_SET_VRING_ENDIAN _IOW(VHOST_VIRTIO, 0x13, struct vhost_vring_state) +#define VHOST_GET_VRING_ENDIAN _IOW(VHOST_VIRTIO, 0x14, struct vhost_vring_state) +/* Attach a vhost_worker created with VHOST_NEW_WORKER to one of the device's + * virtqueues. + * + * This will replace the virtqueue's existing worker. If the replaced worker + * is no longer attached to any virtqueues, it can be freed with + * VHOST_FREE_WORKER. + */ +#define VHOST_ATTACH_VRING_WORKER _IOW(VHOST_VIRTIO, 0x15, \ + struct vhost_vring_worker) +/* Return the vring worker's ID */ +#define VHOST_GET_VRING_WORKER _IOWR(VHOST_VIRTIO, 0x16, \ + struct vhost_vring_worker) + +/* The following ioctls use eventfd file descriptors to signal and poll + * for events. */ + +/* Set eventfd to poll for added buffers */ +#define VHOST_SET_VRING_KICK _IOW(VHOST_VIRTIO, 0x20, struct vhost_vring_file) +/* Set eventfd to signal when buffers have beed used */ +#define VHOST_SET_VRING_CALL _IOW(VHOST_VIRTIO, 0x21, struct vhost_vring_file) +/* Set eventfd to signal an error */ +#define VHOST_SET_VRING_ERR _IOW(VHOST_VIRTIO, 0x22, struct vhost_vring_file) +/* Set busy loop timeout (in us) */ +#define VHOST_SET_VRING_BUSYLOOP_TIMEOUT _IOW(VHOST_VIRTIO, 0x23, \ + struct vhost_vring_state) +/* Get busy loop timeout (in us) */ +#define VHOST_GET_VRING_BUSYLOOP_TIMEOUT _IOW(VHOST_VIRTIO, 0x24, \ + struct vhost_vring_state) + +/* Set or get vhost backend capability */ + +#define VHOST_SET_BACKEND_FEATURES _IOW(VHOST_VIRTIO, 0x25, __u64) +#define VHOST_GET_BACKEND_FEATURES _IOR(VHOST_VIRTIO, 0x26, __u64) + +/* VHOST_NET specific defines */ + +/* Attach virtio net ring to a raw socket, or tap device. + * The socket must be already bound to an ethernet device, this device will be + * used for transmit. Pass fd -1 to unbind from the socket and the transmit + * device. This can be used to stop the ring (e.g. for migration). */ +#define VHOST_NET_SET_BACKEND _IOW(VHOST_VIRTIO, 0x30, struct vhost_vring_file) + +/* VHOST_SCSI specific defines */ + +#define VHOST_SCSI_SET_ENDPOINT _IOW(VHOST_VIRTIO, 0x40, struct vhost_scsi_target) +#define VHOST_SCSI_CLEAR_ENDPOINT _IOW(VHOST_VIRTIO, 0x41, struct vhost_scsi_target) +/* Changing this breaks userspace. */ +#define VHOST_SCSI_GET_ABI_VERSION _IOW(VHOST_VIRTIO, 0x42, int) +/* Set and get the events missed flag */ +#define VHOST_SCSI_SET_EVENTS_MISSED _IOW(VHOST_VIRTIO, 0x43, __u32) +#define VHOST_SCSI_GET_EVENTS_MISSED _IOW(VHOST_VIRTIO, 0x44, __u32) + +/* VHOST_VSOCK specific defines */ + +#define VHOST_VSOCK_SET_GUEST_CID _IOW(VHOST_VIRTIO, 0x60, __u64) +#define VHOST_VSOCK_SET_RUNNING _IOW(VHOST_VIRTIO, 0x61, int) + +/* VHOST_VDPA specific defines */ + +/* Get the device id. The device ids follow the same definition of + * the device id defined in virtio-spec. + */ +#define VHOST_VDPA_GET_DEVICE_ID _IOR(VHOST_VIRTIO, 0x70, __u32) +/* Get and set the status. The status bits follow the same definition + * of the device status defined in virtio-spec. + */ +#define VHOST_VDPA_GET_STATUS _IOR(VHOST_VIRTIO, 0x71, __u8) +#define VHOST_VDPA_SET_STATUS _IOW(VHOST_VIRTIO, 0x72, __u8) +/* Get and set the device config. The device config follows the same + * definition of the device config defined in virtio-spec. + */ +#define VHOST_VDPA_GET_CONFIG _IOR(VHOST_VIRTIO, 0x73, \ + struct vhost_vdpa_config) +#define VHOST_VDPA_SET_CONFIG _IOW(VHOST_VIRTIO, 0x74, \ + struct vhost_vdpa_config) +/* Enable/disable the ring. */ +#define VHOST_VDPA_SET_VRING_ENABLE _IOW(VHOST_VIRTIO, 0x75, \ + struct vhost_vring_state) +/* Get the max ring size. */ +#define VHOST_VDPA_GET_VRING_NUM _IOR(VHOST_VIRTIO, 0x76, __u16) + +/* Set event fd for config interrupt*/ +#define VHOST_VDPA_SET_CONFIG_CALL _IOW(VHOST_VIRTIO, 0x77, int) + +/* Get the valid iova range */ +#define VHOST_VDPA_GET_IOVA_RANGE _IOR(VHOST_VIRTIO, 0x78, \ + struct vhost_vdpa_iova_range) +/* Get the config size */ +#define VHOST_VDPA_GET_CONFIG_SIZE _IOR(VHOST_VIRTIO, 0x79, __u32) + +/* Get the count of all virtqueues */ +#define VHOST_VDPA_GET_VQS_COUNT _IOR(VHOST_VIRTIO, 0x80, __u32) + +/* Get the number of virtqueue groups. */ +#define VHOST_VDPA_GET_GROUP_NUM _IOR(VHOST_VIRTIO, 0x81, __u32) + +/* Get the number of address spaces. */ +#define VHOST_VDPA_GET_AS_NUM _IOR(VHOST_VIRTIO, 0x7A, unsigned int) + +/* Get the group for a virtqueue: read index, write group in num, + * The virtqueue index is stored in the index field of + * vhost_vring_state. The group for this specific virtqueue is + * returned via num field of vhost_vring_state. + */ +#define VHOST_VDPA_GET_VRING_GROUP _IOWR(VHOST_VIRTIO, 0x7B, \ + struct vhost_vring_state) +/* Set the ASID for a virtqueue group. The group index is stored in + * the index field of vhost_vring_state, the ASID associated with this + * group is stored at num field of vhost_vring_state. + */ +#define VHOST_VDPA_SET_GROUP_ASID _IOW(VHOST_VIRTIO, 0x7C, \ + struct vhost_vring_state) + +/* Suspend a device so it does not process virtqueue requests anymore + * + * After the return of ioctl the device must preserve all the necessary state + * (the virtqueue vring base plus the possible device specific states) that is + * required for restoring in the future. The device must not change its + * configuration after that point. + */ +#define VHOST_VDPA_SUSPEND _IO(VHOST_VIRTIO, 0x7D) + +/* Resume a device so it can resume processing virtqueue requests + * + * After the return of this ioctl the device will have restored all the + * necessary states and it is fully operational to continue processing the + * virtqueue descriptors. + */ +#define VHOST_VDPA_RESUME _IO(VHOST_VIRTIO, 0x7E) + +/* Get the group for the descriptor table including driver & device areas + * of a virtqueue: read index, write group in num. + * The virtqueue index is stored in the index field of vhost_vring_state. + * The group ID of the descriptor table for this specific virtqueue + * is returned via num field of vhost_vring_state. + */ +#define VHOST_VDPA_GET_VRING_DESC_GROUP _IOWR(VHOST_VIRTIO, 0x7F, \ + struct vhost_vring_state) +#endif diff --git a/tools/perf/trace/beauty/vhost_virtio_ioctl.sh b/tools/perf/trace/beauty/vhost_virtio_ioctl.sh index 2dd0a3b1f55a..e4f395e7650a 100755 --- a/tools/perf/trace/beauty/vhost_virtio_ioctl.sh +++ b/tools/perf/trace/beauty/vhost_virtio_ioctl.sh @@ -1,18 +1,18 @@ #!/bin/sh # SPDX-License-Identifier: LGPL-2.1 -[ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/linux/ +[ $# -eq 1 ] && beauty_uapi_linux_dir=$1 || beauty_uapi_linux_dir=tools/perf/trace/beauty/include/uapi/linux printf "static const char *vhost_virtio_ioctl_cmds[] = {\n" regex='^#[[:space:]]*define[[:space:]]+VHOST_(\w+)[[:space:]]+_IOW?\([[:space:]]*VHOST_VIRTIO[[:space:]]*,[[:space:]]*(0x[[:xdigit:]]+).*' -grep -E $regex ${header_dir}/vhost.h | \ +grep -E $regex ${beauty_uapi_linux_dir}/vhost.h | \ sed -r "s/$regex/\2 \1/g" | \ sort | xargs printf "\t[%s] = \"%s\",\n" printf "};\n" printf "static const char *vhost_virtio_ioctl_read_cmds[] = {\n" regex='^#[[:space:]]*define[[:space:]]+VHOST_(\w+)[[:space:]]+_IOW?R\([[:space:]]*VHOST_VIRTIO[[:space:]]*,[[:space:]]*(0x[[:xdigit:]]+).*' -grep -E $regex ${header_dir}/vhost.h | \ +grep -E $regex ${beauty_uapi_linux_dir}/vhost.h | \ sed -r "s/$regex/\2 \1/g" | \ sort | xargs printf "\t[%s] = \"%s\",\n" printf "};\n" -- cgit v1.2.3-59-g8ed1b From 8b39a723ef1fa3737e11832ca11183bbaeda2498 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 7 Mar 2024 16:35:47 +0200 Subject: w1: gpio: Make use of device properties Convert the module to be property provider agnostic and allow it to be used on non-OF platforms. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240307143644.3787260-2-andriy.shevchenko@linux.intel.com Signed-off-by: Krzysztof Kozlowski --- drivers/w1/masters/w1-gpio.c | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/drivers/w1/masters/w1-gpio.c b/drivers/w1/masters/w1-gpio.c index 34128e6bbbfa..8ea53c757c99 100644 --- a/drivers/w1/masters/w1-gpio.c +++ b/drivers/w1/masters/w1-gpio.c @@ -6,13 +6,13 @@ */ #include +#include #include #include +#include #include #include -#include #include -#include #include #include @@ -63,20 +63,11 @@ static u8 w1_gpio_read_bit(void *data) return gpiod_get_value(ddata->gpiod) ? 1 : 0; } -#if defined(CONFIG_OF) -static const struct of_device_id w1_gpio_dt_ids[] = { - { .compatible = "w1-gpio" }, - {} -}; -MODULE_DEVICE_TABLE(of, w1_gpio_dt_ids); -#endif - static int w1_gpio_probe(struct platform_device *pdev) { struct w1_bus_master *master; struct w1_gpio_ddata *ddata; struct device *dev = &pdev->dev; - struct device_node *np = dev->of_node; /* Enforce open drain mode by default */ enum gpiod_flags gflags = GPIOD_OUT_LOW_OPEN_DRAIN; int err; @@ -91,7 +82,7 @@ static int w1_gpio_probe(struct platform_device *pdev) * driver it high/low like we are in full control of the line and * open drain will happen transparently. */ - if (of_property_present(np, "linux,open-drain")) + if (device_property_present(dev, "linux,open-drain")) gflags = GPIOD_OUT_LOW; master = devm_kzalloc(dev, sizeof(struct w1_bus_master), @@ -152,10 +143,16 @@ static void w1_gpio_remove(struct platform_device *pdev) w1_remove_master_device(master); } +static const struct of_device_id w1_gpio_dt_ids[] = { + { .compatible = "w1-gpio" }, + {} +}; +MODULE_DEVICE_TABLE(of, w1_gpio_dt_ids); + static struct platform_driver w1_gpio_driver = { .driver = { .name = "w1-gpio", - .of_match_table = of_match_ptr(w1_gpio_dt_ids), + .of_match_table = w1_gpio_dt_ids, }, .probe = w1_gpio_probe, .remove_new = w1_gpio_remove, -- cgit v1.2.3-59-g8ed1b From 9e085c045868a6a727b3bd0fc7840ccc9e04d3a3 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 7 Mar 2024 16:35:48 +0200 Subject: w1: gpio: Switch to use dev_err_probe() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Switch to use dev_err_probe() to simplify the error path and unify a message template. Signed-off-by: Andy Shevchenko Acked-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20240307143644.3787260-3-andriy.shevchenko@linux.intel.com Signed-off-by: Krzysztof Kozlowski --- drivers/w1/masters/w1-gpio.c | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/drivers/w1/masters/w1-gpio.c b/drivers/w1/masters/w1-gpio.c index 8ea53c757c99..a5ac34b32f54 100644 --- a/drivers/w1/masters/w1-gpio.c +++ b/drivers/w1/masters/w1-gpio.c @@ -91,18 +91,14 @@ static int w1_gpio_probe(struct platform_device *pdev) return -ENOMEM; ddata->gpiod = devm_gpiod_get_index(dev, NULL, 0, gflags); - if (IS_ERR(ddata->gpiod)) { - dev_err(dev, "gpio_request (pin) failed\n"); - return PTR_ERR(ddata->gpiod); - } + if (IS_ERR(ddata->gpiod)) + return dev_err_probe(dev, PTR_ERR(ddata->gpiod), "gpio_request (pin) failed\n"); ddata->pullup_gpiod = devm_gpiod_get_index_optional(dev, NULL, 1, GPIOD_OUT_LOW); - if (IS_ERR(ddata->pullup_gpiod)) { - dev_err(dev, "gpio_request_one " - "(ext_pullup_enable_pin) failed\n"); - return PTR_ERR(ddata->pullup_gpiod); - } + if (IS_ERR(ddata->pullup_gpiod)) + return dev_err_probe(dev, PTR_ERR(ddata->pullup_gpiod), + "gpio_request (ext_pullup_enable_pin) failed\n"); master->data = ddata; master->read_bit = w1_gpio_read_bit; @@ -119,10 +115,8 @@ static int w1_gpio_probe(struct platform_device *pdev) master->set_pullup = w1_gpio_set_pullup; err = w1_add_master_device(master); - if (err) { - dev_err(dev, "w1_add_master device failed\n"); - return err; - } + if (err) + return dev_err_probe(dev, err, "w1_add_master device failed\n"); if (ddata->pullup_gpiod) gpiod_set_value(ddata->pullup_gpiod, 1); -- cgit v1.2.3-59-g8ed1b From ef2b810e1152d77686032e7dc064ff89b4350b00 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 7 Mar 2024 16:35:49 +0200 Subject: w1: gpio: Use sizeof(*pointer) instead of sizeof(type) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It is preferred to use sizeof(*pointer) instead of sizeof(type). The type of the variable can change and one needs not change the former (unlike the latter). No functional change intended. Signed-off-by: Andy Shevchenko Acked-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20240307143644.3787260-4-andriy.shevchenko@linux.intel.com Signed-off-by: Krzysztof Kozlowski --- drivers/w1/masters/w1-gpio.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/w1/masters/w1-gpio.c b/drivers/w1/masters/w1-gpio.c index a5ac34b32f54..3881f2eaed2f 100644 --- a/drivers/w1/masters/w1-gpio.c +++ b/drivers/w1/masters/w1-gpio.c @@ -85,8 +85,7 @@ static int w1_gpio_probe(struct platform_device *pdev) if (device_property_present(dev, "linux,open-drain")) gflags = GPIOD_OUT_LOW; - master = devm_kzalloc(dev, sizeof(struct w1_bus_master), - GFP_KERNEL); + master = devm_kzalloc(dev, sizeof(*master), GFP_KERNEL); if (!master) return -ENOMEM; -- cgit v1.2.3-59-g8ed1b From 540d3f15c0aa2baf7e9b48a4e516391c179daab2 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 7 Mar 2024 16:35:50 +0200 Subject: w1: gpio: Remove duplicate NULL checks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gpiod_set_value() is NULL-aware, no need to check that in the caller. Signed-off-by: Andy Shevchenko Acked-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20240307143644.3787260-5-andriy.shevchenko@linux.intel.com Signed-off-by: Krzysztof Kozlowski --- drivers/w1/masters/w1-gpio.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/w1/masters/w1-gpio.c b/drivers/w1/masters/w1-gpio.c index 3881f2eaed2f..8fd9fedd8c56 100644 --- a/drivers/w1/masters/w1-gpio.c +++ b/drivers/w1/masters/w1-gpio.c @@ -117,8 +117,7 @@ static int w1_gpio_probe(struct platform_device *pdev) if (err) return dev_err_probe(dev, err, "w1_add_master device failed\n"); - if (ddata->pullup_gpiod) - gpiod_set_value(ddata->pullup_gpiod, 1); + gpiod_set_value(ddata->pullup_gpiod, 1); platform_set_drvdata(pdev, master); @@ -130,8 +129,7 @@ static void w1_gpio_remove(struct platform_device *pdev) struct w1_bus_master *master = platform_get_drvdata(pdev); struct w1_gpio_ddata *ddata = master->data; - if (ddata->pullup_gpiod) - gpiod_set_value(ddata->pullup_gpiod, 0); + gpiod_set_value(ddata->pullup_gpiod, 0); w1_remove_master_device(master); } -- cgit v1.2.3-59-g8ed1b From cde37a5bdb0ed2c4c7b86ef688e5fdb697525a57 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 7 Mar 2024 16:35:51 +0200 Subject: w1: gpio: Don't use "proxy" headers Update header inclusions to follow IWYU (Include What You Use) principle. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240307143644.3787260-6-andriy.shevchenko@linux.intel.com Signed-off-by: Krzysztof Kozlowski --- drivers/w1/masters/w1-gpio.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/w1/masters/w1-gpio.c b/drivers/w1/masters/w1-gpio.c index 8fd9fedd8c56..a39fa8bf866a 100644 --- a/drivers/w1/masters/w1-gpio.c +++ b/drivers/w1/masters/w1-gpio.c @@ -5,15 +5,15 @@ * Copyright (C) 2007 Ville Syrjala */ -#include +#include +#include +#include +#include #include #include #include #include -#include -#include -#include -#include +#include #include -- cgit v1.2.3-59-g8ed1b From 6594d9c2d1ddc54375d8742403bd1bd8edecb2d3 Mon Sep 17 00:00:00 2001 From: Ayush Tiwari Date: Tue, 19 Mar 2024 00:36:25 +0530 Subject: staging: greybus: Constify gb_audio_module_type Constify static struct kobj_type gb_audio_module_type to prevent modification of data shared across many instances and to address the checkpatch warning that "gb_audio_module_type" should be const. The "gb_audio_module_type" struct is only used in one place: err = kobject_init_and_add(&m->kobj, &gb_audio_module_type, NULL, ... so checkpatch is correct that it can be made const. Signed-off-by: Ayush Tiwari Reviewed-by: Dan Carpenter Link: https://lore.kernel.org/r/ZfiQsZBrHfImIJfc@ayush-HP-Pavilion-Gaming-Laptop-15-ec0xxx Signed-off-by: Greg Kroah-Hartman --- drivers/staging/greybus/audio_manager_module.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/greybus/audio_manager_module.c b/drivers/staging/greybus/audio_manager_module.c index 5f9dcbdbc191..4a4dfb42f50f 100644 --- a/drivers/staging/greybus/audio_manager_module.c +++ b/drivers/staging/greybus/audio_manager_module.c @@ -144,7 +144,7 @@ static struct attribute *gb_audio_module_default_attrs[] = { }; ATTRIBUTE_GROUPS(gb_audio_module_default); -static struct kobj_type gb_audio_module_type = { +static const struct kobj_type gb_audio_module_type = { .sysfs_ops = &gb_audio_module_sysfs_ops, .release = gb_audio_module_release, .default_groups = gb_audio_module_default_groups, -- cgit v1.2.3-59-g8ed1b From 8baa558953e9791d84a30e4d4a03667dd7123794 Mon Sep 17 00:00:00 2001 From: Dorine Tipo Date: Sun, 10 Mar 2024 10:47:14 +0000 Subject: staging: greybus: Add blank line after struct declaration Add a blank line after the loopback_class struct declaration to improve code readability and adherence to coding style guidelines Signed-off-by: Dorine Tipo Acked-by: Julia Lawall Link: https://lore.kernel.org/r/20240310104714.22224-1-dorine.a.tipo@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/greybus/loopback.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/staging/greybus/loopback.c b/drivers/staging/greybus/loopback.c index bb33379b5297..4313d3bbc23a 100644 --- a/drivers/staging/greybus/loopback.c +++ b/drivers/staging/greybus/loopback.c @@ -101,6 +101,7 @@ struct gb_loopback { static struct class loopback_class = { .name = "gb_loopback", }; + static DEFINE_IDA(loopback_ida); /* Min/max values in jiffies */ -- cgit v1.2.3-59-g8ed1b From d1a2e2cb79ca39ae879f3b839a84543f3995b96c Mon Sep 17 00:00:00 2001 From: Ariel Silver Date: Sat, 9 Mar 2024 19:47:22 +0200 Subject: Staging: rtl8192e: Declare variable with static Fixed sparse warning: "'dm_rx_path_sel_table' was not declared. Should it be static?" As dm_rx_path_sel_table is used only in rtl_dm.c it should be static. Signed-off-by: Ariel Silver Tested-by: Philipp Hortmann Link: https://lore.kernel.org/r/20240309174722.3463-1-arielsilver77@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/rtl_dm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c index c34087af973c..4c67bfe0e8ec 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c @@ -144,7 +144,7 @@ const u8 dm_cck_tx_bb_gain_ch14[CCK_TX_BB_GAIN_TABLE_LEN][8] = { /*------------------------Define global variable-----------------------------*/ struct dig_t dm_digtable; -struct drx_path_sel dm_rx_path_sel_table; +static struct drx_path_sel dm_rx_path_sel_table; /*------------------------Define global variable-----------------------------*/ -- cgit v1.2.3-59-g8ed1b From 44ab88bf413b5c254507e1ed865e8ba071dfc99a Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Tue, 12 Mar 2024 06:18:16 +0100 Subject: staging: rtl8192e: replace variable with direct return Remove the variable rt_status from rtl92e_send_cmd_pkt() and return true/false directly to improve readability. Signed-off-by: Michael Straube Reviewed-by: Dan Carpenter Link: https://lore.kernel.org/r/20240312051816.18717-1-straube.linux@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.c index 7f0c160bc741..e470b49b0ff7 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.c @@ -11,7 +11,6 @@ bool rtl92e_send_cmd_pkt(struct net_device *dev, u32 type, const void *data, u32 len) { - bool rt_status = true; struct r8192_priv *priv = rtllib_priv(dev); u16 frag_length = 0, frag_offset = 0; struct sk_buff *skb; @@ -37,10 +36,8 @@ bool rtl92e_send_cmd_pkt(struct net_device *dev, u32 type, const void *data, else skb = dev_alloc_skb(frag_length + 4); - if (!skb) { - rt_status = false; - goto Failed; - } + if (!skb) + return false; memcpy((unsigned char *)(skb->cb), &dev, sizeof(dev)); tcb_desc = (struct cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE); @@ -77,6 +74,6 @@ bool rtl92e_send_cmd_pkt(struct net_device *dev, u32 type, const void *data, } while (frag_offset < len); rtl92e_writeb(dev, TP_POLL, TP_POLL_CQ); -Failed: - return rt_status; + + return true; } -- cgit v1.2.3-59-g8ed1b From c1fa09771a09ccf2432fdeb8e5cc7c377db1d502 Mon Sep 17 00:00:00 2001 From: Tree Davies Date: Sun, 10 Mar 2024 16:55:42 -0700 Subject: Staging: rtl8192e: Rename variable ReturnPoint Rename variable ReturnPoint to return_point to fix checkpatch warning Avoid CamelCase. Signed-off-by: Tree Davies Reviewed-by: Dan Carpenter Link: https://lore.kernel.org/r/20240310235552.4217-2-tdavies@darkphysics.net Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 2 +- drivers/staging/rtl8192e/rtllib.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index 649b529657ba..08d057ab8f74 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -964,7 +964,7 @@ static void _rtl92e_watchdog_wq_cb(void *data) MAC80211_NOLINK) && (ieee->rf_power_state == rf_on) && !ieee->is_set_key && (!ieee->proto_stoppping) && !ieee->wx_set_enc) { - if (ieee->pwr_save_ctrl.ReturnPoint == IPS_CALLBACK_NONE) + if (ieee->pwr_save_ctrl.return_point == IPS_CALLBACK_NONE) rtl92e_ips_enter(dev); } } diff --git a/drivers/staging/rtl8192e/rtllib.h b/drivers/staging/rtl8192e/rtllib.h index 6fbf11ac168f..b2b8947da89d 100644 --- a/drivers/staging/rtl8192e/rtllib.h +++ b/drivers/staging/rtl8192e/rtllib.h @@ -1051,7 +1051,7 @@ enum rt_rf_power_state { struct rt_pwr_save_ctrl { bool bSwRfProcessing; enum rt_rf_power_state eInactivePowerState; - enum ips_callback_function ReturnPoint; + enum ips_callback_function return_point; bool bLeisurePs; u8 lps_idle_count; -- cgit v1.2.3-59-g8ed1b From abfbd0f1fa839291cf58ebd8b139b860761af145 Mon Sep 17 00:00:00 2001 From: Tree Davies Date: Sun, 10 Mar 2024 16:55:43 -0700 Subject: Staging: rtl8192e: Rename variable TimeStampLow Rename variable TimeStampLow to time_stamp_low to fix checkpatch warning Avoid CamelCase. Signed-off-by: Tree Davies Reviewed-by: Dan Carpenter Link: https://lore.kernel.org/r/20240310235552.4217-3-tdavies@darkphysics.net Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | 2 +- drivers/staging/rtl8192e/rtllib.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index e3ed709a7674..480315404969 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -1659,7 +1659,7 @@ bool rtl92e_get_rx_stats(struct net_device *dev, struct rtllib_rx_stats *stats, stats->bFirstMPDU = (pDrvInfo->PartAggr == 1) && (pDrvInfo->FirstAGGR == 1); - stats->TimeStampLow = pDrvInfo->TSFL; + stats->time_stamp_low = pDrvInfo->TSFL; stats->TimeStampHigh = rtl92e_readl(dev, TSFR + 4); _rtl92e_translate_rx_signal_stats(dev, skb, stats, pdesc, pDrvInfo); diff --git a/drivers/staging/rtl8192e/rtllib.h b/drivers/staging/rtl8192e/rtllib.h index b2b8947da89d..72264e1ef877 100644 --- a/drivers/staging/rtl8192e/rtllib.h +++ b/drivers/staging/rtl8192e/rtllib.h @@ -482,7 +482,7 @@ struct rtllib_rx_stats { u16 bCRC:1; u16 bICV:1; u16 Decrypted:1; - u32 TimeStampLow; + u32 time_stamp_low; u32 TimeStampHigh; u8 RxDrvInfoSize; -- cgit v1.2.3-59-g8ed1b From 5f6479090534efbadc762464e48d9056729dd642 Mon Sep 17 00:00:00 2001 From: Tree Davies Date: Sun, 10 Mar 2024 16:55:44 -0700 Subject: Staging: rtl8192e: Rename variable TimeStampHigh Rename variable TimeStampHigh to time_stamp_high to fix checkpatch warning Avoid CamelCase. Signed-off-by: Tree Davies Reviewed-by: Dan Carpenter Link: https://lore.kernel.org/r/20240310235552.4217-4-tdavies@darkphysics.net Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | 2 +- drivers/staging/rtl8192e/rtllib.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index 480315404969..15b0ac6e6eef 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -1660,7 +1660,7 @@ bool rtl92e_get_rx_stats(struct net_device *dev, struct rtllib_rx_stats *stats, (pDrvInfo->FirstAGGR == 1); stats->time_stamp_low = pDrvInfo->TSFL; - stats->TimeStampHigh = rtl92e_readl(dev, TSFR + 4); + stats->time_stamp_high = rtl92e_readl(dev, TSFR + 4); _rtl92e_translate_rx_signal_stats(dev, skb, stats, pdesc, pDrvInfo); skb_trim(skb, skb->len - S_CRC_LEN); diff --git a/drivers/staging/rtl8192e/rtllib.h b/drivers/staging/rtl8192e/rtllib.h index 72264e1ef877..e165f1e32e7f 100644 --- a/drivers/staging/rtl8192e/rtllib.h +++ b/drivers/staging/rtl8192e/rtllib.h @@ -483,7 +483,7 @@ struct rtllib_rx_stats { u16 bICV:1; u16 Decrypted:1; u32 time_stamp_low; - u32 TimeStampHigh; + u32 time_stamp_high; u8 RxDrvInfoSize; u8 RxBufShift; -- cgit v1.2.3-59-g8ed1b From 7ea8ae9e19a07d37fc00786d46189f27b092b5be Mon Sep 17 00:00:00 2001 From: Tree Davies Date: Sun, 10 Mar 2024 16:55:45 -0700 Subject: Staging: rtl8192e: Rename variable Frame_Order Rename variable Frame_Order frame_order to fix checkpatch warning Avoid CamelCase. Signed-off-by: Tree Davies Reviewed-by: Dan Carpenter Link: https://lore.kernel.org/r/20240310235552.4217-5-tdavies@darkphysics.net Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl819x_HTProc.c | 2 +- drivers/staging/rtl8192e/rtllib.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/rtl8192e/rtl819x_HTProc.c b/drivers/staging/rtl8192e/rtl819x_HTProc.c index fa96a2c2c916..dd0e2931b9ca 100644 --- a/drivers/staging/rtl8192e/rtl819x_HTProc.c +++ b/drivers/staging/rtl8192e/rtl819x_HTProc.c @@ -625,7 +625,7 @@ EXPORT_SYMBOL(HT_update_self_and_peer_setting); u8 ht_c_check(struct rtllib_device *ieee, u8 *pFrame) { if (ieee->ht_info->current_ht_support) { - if ((IsQoSDataFrame(pFrame) && Frame_Order(pFrame)) == 1) { + if ((IsQoSDataFrame(pFrame) && frame_order(pFrame)) == 1) { netdev_dbg(ieee->dev, "HT CONTROL FILED EXIST!!\n"); return true; } diff --git a/drivers/staging/rtl8192e/rtllib.h b/drivers/staging/rtl8192e/rtllib.h index e165f1e32e7f..748bb25cbd23 100644 --- a/drivers/staging/rtl8192e/rtllib.h +++ b/drivers/staging/rtl8192e/rtllib.h @@ -343,7 +343,7 @@ enum rt_op_mode { #define IsQoSDataFrame(pframe) \ ((*(u16 *)pframe&(IEEE80211_STYPE_QOS_DATA|RTLLIB_FTYPE_DATA)) == \ (IEEE80211_STYPE_QOS_DATA|RTLLIB_FTYPE_DATA)) -#define Frame_Order(pframe) (*(u16 *)pframe&IEEE80211_FCTL_ORDER) +#define frame_order(pframe) (*(u16 *)pframe&IEEE80211_FCTL_ORDER) #define SN_LESS(a, b) (((a-b)&0x800) != 0) #define SN_EQUAL(a, b) (a == b) #define MAX_DEV_ADDR_SIZE 8 -- cgit v1.2.3-59-g8ed1b From c3f253ef02eaa80493bbe24c618812fc2d86408b Mon Sep 17 00:00:00 2001 From: Tree Davies Date: Sun, 10 Mar 2024 16:55:46 -0700 Subject: Staging: rtl8192e: Rename variable aSifsTime Rename variable aSifsTime to asifs_time to fix checkpatch warning Avoid CamelCase. Signed-off-by: Tree Davies Reviewed-by: Dan Carpenter Link: https://lore.kernel.org/r/20240310235552.4217-6-tdavies@darkphysics.net Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | 2 +- drivers/staging/rtl8192e/rtllib.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index 15b0ac6e6eef..dcb78cd2e840 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -130,7 +130,7 @@ void rtl92e_set_reg(struct net_device *dev, u8 variable, u8 *val) &priv->rtllib->current_network.qos_data.parameters; u1bAIFS = qop->aifs[pAcParam] * - ((mode & (WIRELESS_MODE_G | WIRELESS_MODE_N_24G)) ? 9 : 20) + aSifsTime; + ((mode & (WIRELESS_MODE_G | WIRELESS_MODE_N_24G)) ? 9 : 20) + asifs_time; rtl92e_dm_init_edca_turbo(dev); diff --git a/drivers/staging/rtl8192e/rtllib.h b/drivers/staging/rtl8192e/rtllib.h index 748bb25cbd23..640fb8abcfa3 100644 --- a/drivers/staging/rtl8192e/rtllib.h +++ b/drivers/staging/rtl8192e/rtllib.h @@ -299,7 +299,7 @@ enum rt_op_mode { RT_OP_MODE_NO_LINK, }; -#define aSifsTime \ +#define asifs_time \ ((priv->rtllib->current_network.mode == WIRELESS_MODE_N_24G) ? 16 : 10) #define MGMT_QUEUE_NUM 5 -- cgit v1.2.3-59-g8ed1b From 8f3d126901b744e12523912aa5d5491be3eda846 Mon Sep 17 00:00:00 2001 From: Tree Davies Date: Sun, 10 Mar 2024 16:55:47 -0700 Subject: Staging: rtl8192e: Rename variable posHTCap Rename variable posHTCap to pos_ht_cap to fix checkpatch warning Avoid CamelCase. Signed-off-by: Tree Davies Reviewed-by: Dan Carpenter Link: https://lore.kernel.org/r/20240310235552.4217-7-tdavies@darkphysics.net Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl819x_HTProc.c | 2 +- drivers/staging/rtl8192e/rtllib.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/rtl8192e/rtl819x_HTProc.c b/drivers/staging/rtl8192e/rtl819x_HTProc.c index dd0e2931b9ca..1c3ef1b7ebd8 100644 --- a/drivers/staging/rtl8192e/rtl819x_HTProc.c +++ b/drivers/staging/rtl8192e/rtl819x_HTProc.c @@ -235,7 +235,7 @@ void ht_construct_capability_element(struct rtllib_device *ieee, u8 *pos_ht_cap, if (!pos_ht_cap || !ht) { netdev_warn(ieee->dev, - "%s(): posHTCap and ht_info are null\n", __func__); + "%s(): pos_ht_cap and ht_info are null\n", __func__); return; } memset(pos_ht_cap, 0, *len); diff --git a/drivers/staging/rtl8192e/rtllib.h b/drivers/staging/rtl8192e/rtllib.h index 640fb8abcfa3..525242b0313f 100644 --- a/drivers/staging/rtl8192e/rtllib.h +++ b/drivers/staging/rtl8192e/rtllib.h @@ -1736,7 +1736,7 @@ void ht_set_connect_bw_mode(struct rtllib_device *ieee, enum ht_extchnl_offset Offset); void ht_update_default_setting(struct rtllib_device *ieee); void ht_construct_capability_element(struct rtllib_device *ieee, - u8 *posHTCap, u8 *len, + u8 *pos_ht_cap, u8 *len, u8 isEncrypt, bool bAssoc); void ht_construct_rt2rt_agg_element(struct rtllib_device *ieee, u8 *posRT2RTAgg, u8 *len); -- cgit v1.2.3-59-g8ed1b From 9c46c813905a7fda51b18111c03b690a0e307c9f Mon Sep 17 00:00:00 2001 From: Tree Davies Date: Sun, 10 Mar 2024 16:55:48 -0700 Subject: Staging: rtl8192e: Rename variable bRTSUseShortPreamble Rename variable bRTSUseShortPreamble to rts_use_short_preamble to fix checkpatch warning Avoid CamelCase. Signed-off-by: Tree Davies Reviewed-by: Dan Carpenter Link: https://lore.kernel.org/r/20240310235552.4217-8-tdavies@darkphysics.net Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | 2 +- drivers/staging/rtl8192e/rtllib.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index dcb78cd2e840..41373c013299 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -900,7 +900,7 @@ void rtl92e_fill_tx_desc(struct net_device *dev, struct tx_desc *pdesc, pTxFwInfo->RtsBandwidth = 0; pTxFwInfo->RtsSubcarrier = cb_desc->RTSSC; pTxFwInfo->RtsShort = (pTxFwInfo->RtsHT == 0) ? - (cb_desc->bRTSUseShortPreamble ? 1 : 0) : + (cb_desc->rts_use_short_preamble ? 1 : 0) : (cb_desc->bRTSUseShortGI ? 1 : 0); if (priv->current_chnl_bw == HT_CHANNEL_WIDTH_20_40) { if (cb_desc->bPacketBW) { diff --git a/drivers/staging/rtl8192e/rtllib.h b/drivers/staging/rtl8192e/rtllib.h index 525242b0313f..cf75d1225501 100644 --- a/drivers/staging/rtl8192e/rtllib.h +++ b/drivers/staging/rtl8192e/rtllib.h @@ -121,7 +121,7 @@ struct cb_desc { u8 bRTSBW:1; u8 bPacketBW:1; - u8 bRTSUseShortPreamble:1; + u8 rts_use_short_preamble:1; u8 bRTSUseShortGI:1; u8 multicast:1; u8 bBroadcast:1; -- cgit v1.2.3-59-g8ed1b From 9cfe5964787fed5933e3695043f24ba28a5199fe Mon Sep 17 00:00:00 2001 From: Tree Davies Date: Sun, 10 Mar 2024 16:55:49 -0700 Subject: Staging: rtl8192e: Rename variable pBssHT Rename variable pBssHT to bss_ht to fix checkpatch warning Avoid CamelCase. Signed-off-by: Tree Davies Reviewed-by: Dan Carpenter Link: https://lore.kernel.org/r/20240310235552.4217-9-tdavies@darkphysics.net Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl819x_HTProc.c | 20 ++++++++++---------- drivers/staging/rtl8192e/rtllib.h | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/staging/rtl8192e/rtl819x_HTProc.c b/drivers/staging/rtl8192e/rtl819x_HTProc.c index 1c3ef1b7ebd8..618523bacc8e 100644 --- a/drivers/staging/rtl8192e/rtl819x_HTProc.c +++ b/drivers/staging/rtl8192e/rtl819x_HTProc.c @@ -543,19 +543,19 @@ void ht_initialize_ht_info(struct rtllib_device *ieee) } } -void ht_initialize_bss_desc(struct bss_ht *pBssHT) +void ht_initialize_bss_desc(struct bss_ht *bss_ht) { - pBssHT->bd_support_ht = false; - memset(pBssHT->bd_ht_cap_buf, 0, sizeof(pBssHT->bd_ht_cap_buf)); - pBssHT->bd_ht_cap_len = 0; - memset(pBssHT->bd_ht_info_buf, 0, sizeof(pBssHT->bd_ht_info_buf)); - pBssHT->bd_ht_info_len = 0; + bss_ht->bd_support_ht = false; + memset(bss_ht->bd_ht_cap_buf, 0, sizeof(bss_ht->bd_ht_cap_buf)); + bss_ht->bd_ht_cap_len = 0; + memset(bss_ht->bd_ht_info_buf, 0, sizeof(bss_ht->bd_ht_info_buf)); + bss_ht->bd_ht_info_len = 0; - pBssHT->bd_ht_spec_ver = HT_SPEC_VER_IEEE; + bss_ht->bd_ht_spec_ver = HT_SPEC_VER_IEEE; - pBssHT->bd_rt2rt_aggregation = false; - pBssHT->bd_rt2rt_long_slot_time = false; - pBssHT->rt2rt_ht_mode = (enum rt_ht_capability)0; + bss_ht->bd_rt2rt_aggregation = false; + bss_ht->bd_rt2rt_long_slot_time = false; + bss_ht->rt2rt_ht_mode = (enum rt_ht_capability)0; } void ht_reset_self_and_save_peer_setting(struct rtllib_device *ieee, diff --git a/drivers/staging/rtl8192e/rtllib.h b/drivers/staging/rtl8192e/rtllib.h index cf75d1225501..3819a859710d 100644 --- a/drivers/staging/rtl8192e/rtllib.h +++ b/drivers/staging/rtl8192e/rtllib.h @@ -1742,7 +1742,7 @@ void ht_construct_rt2rt_agg_element(struct rtllib_device *ieee, u8 *posRT2RTAgg, u8 *len); void ht_on_assoc_rsp(struct rtllib_device *ieee); void ht_initialize_ht_info(struct rtllib_device *ieee); -void ht_initialize_bss_desc(struct bss_ht *pBssHT); +void ht_initialize_bss_desc(struct bss_ht *bss_ht); void ht_reset_self_and_save_peer_setting(struct rtllib_device *ieee, struct rtllib_network *pNetwork); void HT_update_self_and_peer_setting(struct rtllib_device *ieee, -- cgit v1.2.3-59-g8ed1b From decc6f8ce18fc4017625678af417685839d06628 Mon Sep 17 00:00:00 2001 From: Tree Davies Date: Sun, 10 Mar 2024 16:55:50 -0700 Subject: Staging: rtl8192e: Rename variable bAllowAllDA Rename variable bAllowAllDA to allow_all_da to fix checkpatch warning Avoid CamelCase. Signed-off-by: Tree Davies Reviewed-by: Dan Carpenter Link: https://lore.kernel.org/r/20240310235552.4217-10-tdavies@darkphysics.net Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | 4 ++-- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h | 2 +- drivers/staging/rtl8192e/rtllib.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index 41373c013299..e3276d2c3616 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -702,12 +702,12 @@ void rtl92e_link_change(struct net_device *dev) } } -void rtl92e_set_monitor_mode(struct net_device *dev, bool bAllowAllDA, +void rtl92e_set_monitor_mode(struct net_device *dev, bool allow_all_da, bool WriteIntoReg) { struct r8192_priv *priv = rtllib_priv(dev); - if (bAllowAllDA) + if (allow_all_da) priv->receive_config |= RCR_AAP; else priv->receive_config &= ~RCR_AAP; diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h index 878c96236824..1224f190937e 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h @@ -21,7 +21,7 @@ void rtl92e_set_reg(struct net_device *dev, u8 variable, u8 *val); void rtl92e_get_eeprom_size(struct net_device *dev); bool rtl92e_start_adapter(struct net_device *dev); void rtl92e_link_change(struct net_device *dev); -void rtl92e_set_monitor_mode(struct net_device *dev, bool bAllowAllDA, +void rtl92e_set_monitor_mode(struct net_device *dev, bool allow_all_da, bool WriteIntoReg); void rtl92e_fill_tx_desc(struct net_device *dev, struct tx_desc *pdesc, struct cb_desc *cb_desc, struct sk_buff *skb); diff --git a/drivers/staging/rtl8192e/rtllib.h b/drivers/staging/rtl8192e/rtllib.h index 3819a859710d..393fff7e6a8d 100644 --- a/drivers/staging/rtl8192e/rtllib.h +++ b/drivers/staging/rtl8192e/rtllib.h @@ -1477,7 +1477,7 @@ struct rtllib_device { void (*set_hw_reg_handler)(struct net_device *dev, u8 variable, u8 *val); void (*allow_all_dest_addr_handler)(struct net_device *dev, - bool bAllowAllDA, + bool allow_all_da, bool WriteIntoReg); void (*rtllib_ips_leave_wq)(struct net_device *dev); -- cgit v1.2.3-59-g8ed1b From ab8e210d16b10e01b40fedde18de413434310784 Mon Sep 17 00:00:00 2001 From: Tree Davies Date: Sun, 10 Mar 2024 16:55:51 -0700 Subject: Staging: rtl8192e: Rename variable WriteIntoReg Rename variable WriteIntoReg to write_into_reg to fix checkpatch warning Avoid CamelCase. Signed-off-by: Tree Davies Reviewed-by: Dan Carpenter Link: https://lore.kernel.org/r/20240310235552.4217-11-tdavies@darkphysics.net Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | 4 ++-- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h | 2 +- drivers/staging/rtl8192e/rtllib.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index e3276d2c3616..fdf8fc66939d 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -703,7 +703,7 @@ void rtl92e_link_change(struct net_device *dev) } void rtl92e_set_monitor_mode(struct net_device *dev, bool allow_all_da, - bool WriteIntoReg) + bool write_into_reg) { struct r8192_priv *priv = rtllib_priv(dev); @@ -712,7 +712,7 @@ void rtl92e_set_monitor_mode(struct net_device *dev, bool allow_all_da, else priv->receive_config &= ~RCR_AAP; - if (WriteIntoReg) + if (write_into_reg) rtl92e_writel(dev, RCR, priv->receive_config); } diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h index 1224f190937e..9d9c5051c7fe 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h @@ -22,7 +22,7 @@ void rtl92e_get_eeprom_size(struct net_device *dev); bool rtl92e_start_adapter(struct net_device *dev); void rtl92e_link_change(struct net_device *dev); void rtl92e_set_monitor_mode(struct net_device *dev, bool allow_all_da, - bool WriteIntoReg); + bool write_into_reg); void rtl92e_fill_tx_desc(struct net_device *dev, struct tx_desc *pdesc, struct cb_desc *cb_desc, struct sk_buff *skb); void rtl92e_fill_tx_cmd_desc(struct net_device *dev, struct tx_desc_cmd *entry, diff --git a/drivers/staging/rtl8192e/rtllib.h b/drivers/staging/rtl8192e/rtllib.h index 393fff7e6a8d..0809af3fd041 100644 --- a/drivers/staging/rtl8192e/rtllib.h +++ b/drivers/staging/rtl8192e/rtllib.h @@ -1478,7 +1478,7 @@ struct rtllib_device { void (*allow_all_dest_addr_handler)(struct net_device *dev, bool allow_all_da, - bool WriteIntoReg); + bool write_into_reg); void (*rtllib_ips_leave_wq)(struct net_device *dev); void (*rtllib_ips_leave)(struct net_device *dev); -- cgit v1.2.3-59-g8ed1b From bf812e0a36f775ea77e4e6455f0b3a1ab1a61961 Mon Sep 17 00:00:00 2001 From: "Felix N. Kimbu" Date: Wed, 13 Mar 2024 05:45:00 +0100 Subject: staging: wlan-ng: Rename 'foo' to 'rc' in p80211conv.c Rename identifier 'foo' to 'rc' in skb_p80211_to_ether() and skb_ether_to_p80211() to match the common kernel coding style. Signed-off-by: Felix N. Kimbu Reviewed-by: Dan Carpenter Link: https://lore.kernel.org/r/ZfEvTF7qwYZORGsY@MOLeToid Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wlan-ng/p80211conv.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/drivers/staging/wlan-ng/p80211conv.c b/drivers/staging/wlan-ng/p80211conv.c index 8336435eccc2..7401a6cacb7f 100644 --- a/drivers/staging/wlan-ng/p80211conv.c +++ b/drivers/staging/wlan-ng/p80211conv.c @@ -93,7 +93,7 @@ int skb_ether_to_p80211(struct wlandevice *wlandev, u32 ethconv, struct wlan_ethhdr e_hdr; struct wlan_llc *e_llc; struct wlan_snap *e_snap; - int foo; + int rc; memcpy(&e_hdr, skb->data, sizeof(e_hdr)); @@ -185,14 +185,14 @@ int skb_ether_to_p80211(struct wlandevice *wlandev, u32 ethconv, p80211_wep->data = kmalloc(skb->len, GFP_ATOMIC); if (!p80211_wep->data) return -ENOMEM; - foo = wep_encrypt(wlandev, skb->data, p80211_wep->data, - skb->len, - wlandev->hostwep & HOSTWEP_DEFAULTKEY_MASK, - p80211_wep->iv, p80211_wep->icv); - if (foo) { + rc = wep_encrypt(wlandev, skb->data, p80211_wep->data, + skb->len, + wlandev->hostwep & HOSTWEP_DEFAULTKEY_MASK, + p80211_wep->iv, p80211_wep->icv); + if (rc) { netdev_warn(wlandev->netdev, "Host en-WEP failed, dropping frame (%d).\n", - foo); + rc); kfree(p80211_wep->data); return 2; } @@ -265,7 +265,7 @@ int skb_p80211_to_ether(struct wlandevice *wlandev, u32 ethconv, struct wlan_llc *e_llc; struct wlan_snap *e_snap; - int foo; + int rc; payload_length = skb->len - WLAN_HDR_A3_LEN - WLAN_CRC_LEN; payload_offset = WLAN_HDR_A3_LEN; @@ -305,15 +305,15 @@ int skb_p80211_to_ether(struct wlandevice *wlandev, u32 ethconv, "WEP frame too short (%u).\n", skb->len); return 1; } - foo = wep_decrypt(wlandev, skb->data + payload_offset + 4, - payload_length - 8, -1, - skb->data + payload_offset, - skb->data + payload_offset + - payload_length - 4); - if (foo) { + rc = wep_decrypt(wlandev, skb->data + payload_offset + 4, + payload_length - 8, -1, + skb->data + payload_offset, + skb->data + payload_offset + + payload_length - 4); + if (rc) { /* de-wep failed, drop skb. */ netdev_dbg(netdev, "Host de-WEP failed, dropping frame (%d).\n", - foo); + rc); wlandev->rx.decrypt_err++; return 2; } -- cgit v1.2.3-59-g8ed1b From f119f9e050940070c3da3a7476b1bf7a63c803c4 Mon Sep 17 00:00:00 2001 From: Ayush Tiwari Date: Wed, 13 Mar 2024 15:53:38 +0530 Subject: staging: rtl8712: rename tmpVal to avg_val Rename tmpVal to avg_val in process_link_qual() to reflect the intended use of the variable and conform to the kernel coding style. Signed-off-by: Ayush Tiwari Reviewed-by: Dan Carpenter Reviewed-by: Fabio M. De Francesco Link: https://lore.kernel.org/r/ZfF+qu+CGHlpHrtY@ayush-HP-Pavilion-Gaming-Laptop-15-ec0xxx Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8712/rtl8712_recv.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/staging/rtl8712/rtl8712_recv.c b/drivers/staging/rtl8712/rtl8712_recv.c index a3c4713c59b3..1fabc5137a4c 100644 --- a/drivers/staging/rtl8712/rtl8712_recv.c +++ b/drivers/staging/rtl8712/rtl8712_recv.c @@ -861,7 +861,7 @@ static void query_rx_phy_status(struct _adapter *padapter, static void process_link_qual(struct _adapter *padapter, union recv_frame *prframe) { - u32 last_evm = 0, tmpVal; + u32 last_evm = 0, avg_val; struct rx_pkt_attrib *pattrib; struct smooth_rssi_data *sqd = &padapter->recvpriv.signal_qual_data; @@ -883,8 +883,8 @@ static void process_link_qual(struct _adapter *padapter, sqd->index = 0; /* <1> Showed on UI for user, in percentage. */ - tmpVal = sqd->total_val / sqd->total_num; - padapter->recvpriv.signal = (u8)tmpVal; + avg_val = sqd->total_val / sqd->total_num; + padapter->recvpriv.signal = (u8)avg_val; } } -- cgit v1.2.3-59-g8ed1b From 26743707e13ed88612a98c303d924d3d623ee88c Mon Sep 17 00:00:00 2001 From: "Felix N. Kimbu" Date: Wed, 13 Mar 2024 11:58:27 +0100 Subject: staging: wlan-ng: Rename 'wlan_unsetup' to 'wlan_teardown' Rename function identifier 'wlan_unsetup' to 'wlan_teardown' in files p80211netdev.c, p80211netdev.h and prism2usb.c, a pairing function for 'wlan_setup' to match common kernel coding style. Signed-off-by: Felix N. Kimbu Reviewed-by: Dan Carpenter Link: https://lore.kernel.org/r/ZfGG093fyjI4G/ci@MOLeToid Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wlan-ng/p80211netdev.c | 4 ++-- drivers/staging/wlan-ng/p80211netdev.h | 2 +- drivers/staging/wlan-ng/prism2usb.c | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/staging/wlan-ng/p80211netdev.c b/drivers/staging/wlan-ng/p80211netdev.c index 8634fc89a6c2..284c1c12e1d1 100644 --- a/drivers/staging/wlan-ng/p80211netdev.c +++ b/drivers/staging/wlan-ng/p80211netdev.c @@ -689,7 +689,7 @@ int wlan_setup(struct wlandevice *wlandev, struct device *physdev) } /*---------------------------------------------------------------- - * wlan_unsetup + * wlan_teardown * * This function is paired with the wlan_setup routine. It should * be called after unregister_wlandev. Basically, all it does is @@ -708,7 +708,7 @@ int wlan_setup(struct wlandevice *wlandev, struct device *physdev) * context of the kernel startup code. *---------------------------------------------------------------- */ -void wlan_unsetup(struct wlandevice *wlandev) +void wlan_teardown(struct wlandevice *wlandev) { struct wireless_dev *wdev; diff --git a/drivers/staging/wlan-ng/p80211netdev.h b/drivers/staging/wlan-ng/p80211netdev.h index 485f2c697f5f..e3eefb67aae1 100644 --- a/drivers/staging/wlan-ng/p80211netdev.h +++ b/drivers/staging/wlan-ng/p80211netdev.h @@ -204,7 +204,7 @@ int wep_encrypt(struct wlandevice *wlandev, u8 *buf, u8 *dst, u32 len, int keynum, u8 *iv, u8 *icv); int wlan_setup(struct wlandevice *wlandev, struct device *physdev); -void wlan_unsetup(struct wlandevice *wlandev); +void wlan_teardown(struct wlandevice *wlandev); int register_wlandev(struct wlandevice *wlandev); int unregister_wlandev(struct wlandevice *wlandev); void p80211netdev_rx(struct wlandevice *wlandev, struct sk_buff *skb); diff --git a/drivers/staging/wlan-ng/prism2usb.c b/drivers/staging/wlan-ng/prism2usb.c index 0e0ccef4871e..416127e5d713 100644 --- a/drivers/staging/wlan-ng/prism2usb.c +++ b/drivers/staging/wlan-ng/prism2usb.c @@ -128,7 +128,7 @@ static int prism2sta_probe_usb(struct usb_interface *interface, failed_register: usb_put_dev(dev); failed_reset: - wlan_unsetup(wlandev); + wlan_teardown(wlandev); failed: kfree(wlandev); kfree(hw); @@ -208,7 +208,7 @@ static void prism2sta_disconnect_usb(struct usb_interface *interface) /* Unhook the wlandev */ unregister_wlandev(wlandev); - wlan_unsetup(wlandev); + wlan_teardown(wlandev); usb_put_dev(hw->usb); -- cgit v1.2.3-59-g8ed1b From f7841bc3e347773e95549c96ae6ca403b42f40f8 Mon Sep 17 00:00:00 2001 From: Dorine Tipo Date: Sat, 16 Mar 2024 20:42:07 +0000 Subject: staging: vt6655: Remove unused declaration of RFbAL7230SelectChannelPostProcess() Remove unused function RFbAL7230SelectChannelPostProcess declared in rf.h but has no associated implementation. Commit dd2837bdea0e removed the RFbAL7230SelectChannelPostProcess() but accidentally forgot to delete the declaration in the header file. Fixes: dd2837bdea0e ("staging: vt6655: Remove unused byRFType in rf.c") Signed-off-by: Dorine Tipo Tested-by: Philipp Hortmann Link: https://lore.kernel.org/r/20240316204207.1779-1-dorine.a.tipo@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6655/rf.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/staging/vt6655/rf.h b/drivers/staging/vt6655/rf.h index 6f842ac00526..8eef100c7ef2 100644 --- a/drivers/staging/vt6655/rf.h +++ b/drivers/staging/vt6655/rf.h @@ -68,8 +68,4 @@ bool RFbRawSetPower(struct vnt_private *priv, unsigned char byPwr, void RFvRSSITodBm(struct vnt_private *priv, unsigned char byCurrRSSI, long *pldBm); -/* {{ RobertYu: 20050104 */ -bool RFbAL7230SelectChannelPostProcess(struct vnt_private *priv, u16 byOldChannel, u16 byNewChannel); -/* }} RobertYu */ - #endif /* __RF_H__ */ -- cgit v1.2.3-59-g8ed1b From b50e41c0e5e074e5f8bf153b7c71584e93ed00ba Mon Sep 17 00:00:00 2001 From: Ayush Tiwari Date: Thu, 21 Mar 2024 12:27:41 +0530 Subject: staging: rtl8712: Fix line length exceeding 100 columns Split the argument list of the kthread_run function call across two lines to address the checkpatch warning "line length exceeds 100 columns". Signed-off-by: Ayush Tiwari Reviewed-by: Dan Carpenter Link: https://lore.kernel.org/r/ZfvaZd92bnoZ9M1m@ayush-HP-Pavilion-Gaming-Laptop-15-ec0xxx Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8712/os_intfs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/staging/rtl8712/os_intfs.c b/drivers/staging/rtl8712/os_intfs.c index 7554613fe7e1..1b11f8b04e13 100644 --- a/drivers/staging/rtl8712/os_intfs.c +++ b/drivers/staging/rtl8712/os_intfs.c @@ -221,7 +221,8 @@ struct net_device *r8712_init_netdev(void) static u32 start_drv_threads(struct _adapter *padapter) { - padapter->cmd_thread = kthread_run(r8712_cmd_thread, padapter, "%s", padapter->pnetdev->name); + padapter->cmd_thread = kthread_run(r8712_cmd_thread, padapter, "%s", + padapter->pnetdev->name); if (IS_ERR(padapter->cmd_thread)) return _FAIL; return _SUCCESS; -- cgit v1.2.3-59-g8ed1b From d6b86fdecdddf66e9251f5258460df7cf179848c Mon Sep 17 00:00:00 2001 From: "Felix N. Kimbu" Date: Sat, 23 Mar 2024 07:08:05 +0100 Subject: staging: pi433: Correct comment typos in pi433_if.c Correct typos in comments accross driver file pi433_if.c. Signed-off-by: Felix N. Kimbu Link: https://lore.kernel.org/r/Zf5xxbEpFfU5GMiY@MOLeToid Signed-off-by: Greg Kroah-Hartman --- drivers/staging/pi433/pi433_if.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/staging/pi433/pi433_if.c b/drivers/staging/pi433/pi433_if.c index b6c4917d515e..81de98c0245a 100644 --- a/drivers/staging/pi433/pi433_if.c +++ b/drivers/staging/pi433/pi433_if.c @@ -10,7 +10,7 @@ * devices, basing on HopeRfs rf69. * * The driver can also be extended, to support other modules of - * HopeRf with a similar interace - e. g. RFM69HCW, RFM12, RFM95, ... + * HopeRf with a similar interface - e. g. RFM69HCW, RFM12, RFM95, ... * * Copyright (C) 2016 Wolf-Entwicklungen * Marcus Wolf @@ -68,7 +68,7 @@ static const struct class pi433_class = { */ /* * rx config is device specific - * so we have just one rx config, ebedded in device struct + * so we have just one rx config, embedded in device struct */ struct pi433_device { /* device handling related values */ @@ -647,7 +647,7 @@ static int pi433_tx_thread(void *data) /* * prevent race conditions - * irq will be reenabled after tx config is set + * irq will be re-enabled after tx config is set */ disable_irq(device->irq_num[DIO0]); device->tx_active = true; @@ -923,7 +923,7 @@ static long pi433_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) case PI433_IOC_WR_RX_CFG: mutex_lock(&device->rx_lock); - /* during pendig read request, change of config not allowed */ + /* during pending read request, change of config not allowed */ if (device->rx_active) { mutex_unlock(&device->rx_lock); return -EAGAIN; -- cgit v1.2.3-59-g8ed1b From 242d724fae21fd9a5a3ea3d91093d693042509e7 Mon Sep 17 00:00:00 2001 From: Ayush Tiwari Date: Mon, 25 Mar 2024 02:39:09 +0530 Subject: staging: rtl8712: Remove additional space Remove additional whitespaces in SwLedOn() between u8 and LedCfg to conform to common kernel coding style. Signed-off-by: Ayush Tiwari Link: https://lore.kernel.org/r/ZgCWdfJit4Ly14NB@ayush-HP-Pavilion-Gaming-Laptop-15-ec0xxx Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8712/rtl8712_led.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/rtl8712/rtl8712_led.c b/drivers/staging/rtl8712/rtl8712_led.c index d5fc9026b036..6d9be5dec4e7 100644 --- a/drivers/staging/rtl8712/rtl8712_led.c +++ b/drivers/staging/rtl8712/rtl8712_led.c @@ -107,7 +107,7 @@ static void DeInitLed871x(struct LED_871x *pLed) */ static void SwLedOn(struct _adapter *padapter, struct LED_871x *pLed) { - u8 LedCfg; + u8 LedCfg; if (padapter->surprise_removed || padapter->driver_stopped) return; -- cgit v1.2.3-59-g8ed1b From c61be40b3b36eb0895f42c5ac717d5f7fb473878 Mon Sep 17 00:00:00 2001 From: Ayush Tiwari Date: Mon, 25 Mar 2024 02:46:15 +0530 Subject: staging: rtl8712: Add space between operands and operator Add whitespace in union recvstat between operator '>>' and operands 'RXDESC_SIZE' and '2' to conform to common kernel coding style. Signed-off-by: Ayush Tiwari Link: https://lore.kernel.org/r/ZgCYHwYOmqfwMeU0@ayush-HP-Pavilion-Gaming-Laptop-15-ec0xxx Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8712/rtl8712_recv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/rtl8712/rtl8712_recv.h b/drivers/staging/rtl8712/rtl8712_recv.h index f4d20b0efd4e..a1360dcf91ce 100644 --- a/drivers/staging/rtl8712/rtl8712_recv.h +++ b/drivers/staging/rtl8712/rtl8712_recv.h @@ -82,7 +82,7 @@ struct phy_stat { union recvstat { struct recv_stat recv_stat; - unsigned int value[RXDESC_SIZE>>2]; + unsigned int value[RXDESC_SIZE >> 2]; }; struct recv_buf { -- cgit v1.2.3-59-g8ed1b From d81060d69e3be189cd7ad105e9a9b237573285ba Mon Sep 17 00:00:00 2001 From: Umang Jain Date: Thu, 21 Mar 2024 18:37:33 +0530 Subject: staging: vc04_services: Remove unused function declarations vchiq_loud_error-* are not implemented hence, remove their declarations. This seem to be remnants of custom logging helpers which were removed earlier. Signed-off-by: Umang Jain Reviewed-by: Laurent Pinchart Reviewed-by: Kieran Bingham Link: https://lore.kernel.org/r/20240321130737.898154-2-umang.jain@ideasonboard.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h index c8527551b58c..5fbf173d9c56 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h @@ -470,12 +470,6 @@ vchiq_bulk_transfer(struct vchiq_instance *instance, unsigned int handle, void * extern void vchiq_dump_state(struct seq_file *f, struct vchiq_state *state); -extern void -vchiq_loud_error_header(void); - -extern void -vchiq_loud_error_footer(void); - extern void request_poll(struct vchiq_state *state, struct vchiq_service *service, int poll_type); -- cgit v1.2.3-59-g8ed1b From 57c0b41bbe7b43c519f5824a964a406d1e7f60a3 Mon Sep 17 00:00:00 2001 From: Umang Jain Date: Thu, 21 Mar 2024 18:37:34 +0530 Subject: staging: vc04_services: vchiq_arm: Use appropriate dev_* log helpers Re-evaluate logs on error code paths and fix a few error logs with appropriate dev_* logging helpers. No functional changes intended in this patch. Signed-off-by: Umang Jain Reviewed-by: Kieran Bingham Link: https://lore.kernel.org/r/20240321130737.898154-3-umang.jain@ideasonboard.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c index 1579bd4e5263..b3021739b170 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c @@ -1317,7 +1317,7 @@ vchiq_keepalive_thread_func(void *v) long rc = 0, uc = 0; if (wait_for_completion_interruptible(&arm_state->ka_evt)) { - dev_err(state->dev, "suspend: %s: interrupted\n", __func__); + dev_dbg(state->dev, "suspend: %s: interrupted\n", __func__); flush_signals(current); continue; } @@ -1753,7 +1753,7 @@ static int vchiq_probe(struct platform_device *pdev) */ err = vchiq_register_chrdev(&pdev->dev); if (err) { - dev_warn(&pdev->dev, "arm: Failed to initialize vchiq cdev\n"); + dev_err(&pdev->dev, "arm: Failed to initialize vchiq cdev\n"); goto error_exit; } @@ -1763,7 +1763,7 @@ static int vchiq_probe(struct platform_device *pdev) return 0; failed_platform_init: - dev_warn(&pdev->dev, "arm: Could not initialize vchiq platform\n"); + dev_err(&pdev->dev, "arm: Could not initialize vchiq platform\n"); error_exit: return err; } -- cgit v1.2.3-59-g8ed1b From ff6643de78d12d9174d574b25794f8ab4b8c5ac6 Mon Sep 17 00:00:00 2001 From: Umang Jain Date: Thu, 21 Mar 2024 18:37:35 +0530 Subject: staging: vc04_services: Do not log error on kzalloc() Do not log any error for kzalloc() error path. kzalloc() already reports such errors. Signed-off-by: Umang Jain Reviewed-by: Kieran Bingham Link: https://lore.kernel.org/r/20240321130737.898154-4-umang.jain@ideasonboard.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c index b3021739b170..ad506016fc93 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c @@ -690,7 +690,6 @@ int vchiq_initialise(struct vchiq_instance **instance_out) instance = kzalloc(sizeof(*instance), GFP_KERNEL); if (!instance) { - dev_err(state->dev, "core: %s: Cannot allocate vchiq instance\n", __func__); ret = -ENOMEM; goto failed; } @@ -956,10 +955,8 @@ vchiq_blocking_bulk_transfer(struct vchiq_instance *instance, unsigned int handl } } else { waiter = kzalloc(sizeof(*waiter), GFP_KERNEL); - if (!waiter) { - dev_err(service->state->dev, "core: %s: - Out of memory\n", __func__); + if (!waiter) return -ENOMEM; - } } status = vchiq_bulk_transfer(instance, handle, data, NULL, size, -- cgit v1.2.3-59-g8ed1b From bf1894900b53f9047eb9b96c89717a9a22329f6a Mon Sep 17 00:00:00 2001 From: Umang Jain Date: Thu, 21 Mar 2024 18:37:36 +0530 Subject: staging: vc04_services: Implement vchiq_bus .remove Implement the struct vchiq_bus .remove() so that cleanup paths can be executed by the devices registered to this bus, when being removed. Signed-off-by: Umang Jain Reviewed-by: Kieran Bingham Link: https://lore.kernel.org/r/20240321130737.898154-5-umang.jain@ideasonboard.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vc04_services/interface/vchiq_arm/vchiq_bus.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_bus.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_bus.c index 68f830d75531..93609716df84 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_bus.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_bus.c @@ -37,11 +37,21 @@ static int vchiq_bus_probe(struct device *dev) return driver->probe(device); } +static void vchiq_bus_remove(struct device *dev) +{ + struct vchiq_device *device = to_vchiq_device(dev); + struct vchiq_driver *driver = to_vchiq_driver(dev->driver); + + if (driver->remove) + driver->remove(device); +} + const struct bus_type vchiq_bus_type = { .name = "vchiq-bus", .match = vchiq_bus_type_match, .uevent = vchiq_bus_uevent, .probe = vchiq_bus_probe, + .remove = vchiq_bus_remove, }; static void vchiq_device_release(struct device *dev) -- cgit v1.2.3-59-g8ed1b From d9c60badccc183eb971e0941bb86f9475d4b9551 Mon Sep 17 00:00:00 2001 From: Umang Jain Date: Thu, 21 Mar 2024 18:37:37 +0530 Subject: staging: vc04_services: vchiq_core: Stop kthreads on shutdown The various kthreads thread functions (slot_handler_func, sync_func, recycle_func) in vchiq_core and vchiq_keepalive_thread_func in vchiq_arm should be stopped on vchiq_shutdown(). This also address the following TODO item: * Fix kernel module support hence drop it from the TODO item list. Signed-off-by: Umang Jain Reviewed-by: Kieran Bingham Link: https://lore.kernel.org/r/20240321130737.898154-6-umang.jain@ideasonboard.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vc04_services/interface/TODO | 7 ------- drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c | 8 ++++++-- drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c | 10 +++++++--- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/drivers/staging/vc04_services/interface/TODO b/drivers/staging/vc04_services/interface/TODO index 05eb5140d096..57a2d6761f9b 100644 --- a/drivers/staging/vc04_services/interface/TODO +++ b/drivers/staging/vc04_services/interface/TODO @@ -16,13 +16,6 @@ some of the ones we want: to manage these buffers as dmabufs so that we can zero-copy import camera images into vc4 for rendering/display. -* Fix kernel module support - -Even the VPU firmware doesn't support a VCHI re-connect, the driver -should properly handle a module unload. This also includes that all -resources must be freed (kthreads, debugfs entries, ...) and global -variables avoided. - * Documentation A short top-down description of this driver's architecture (function of diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c index ad506016fc93..1d21f9cfbfe5 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c @@ -726,8 +726,9 @@ void free_bulk_waiter(struct vchiq_instance *instance) int vchiq_shutdown(struct vchiq_instance *instance) { - int status = 0; struct vchiq_state *state = instance->state; + struct vchiq_arm_state *arm_state; + int status = 0; if (mutex_lock_killable(&state->mutex)) return -EAGAIN; @@ -739,6 +740,9 @@ int vchiq_shutdown(struct vchiq_instance *instance) dev_dbg(state->dev, "core: (%p): returning %d\n", instance, status); + arm_state = vchiq_platform_get_arm_state(state); + kthread_stop(arm_state->ka_thread); + free_bulk_waiter(instance); kfree(instance); @@ -1310,7 +1314,7 @@ vchiq_keepalive_thread_func(void *v) goto shutdown; } - while (1) { + while (!kthread_should_stop()) { long rc = 0, uc = 0; if (wait_for_completion_interruptible(&arm_state->ka_evt)) { diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c index 76c27778154a..953ccd87f425 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c @@ -1936,7 +1936,7 @@ slot_handler_func(void *v) DEBUG_INITIALISE(local); - while (1) { + while (!kthread_should_stop()) { DEBUG_COUNT(SLOT_HANDLER_COUNT); DEBUG_TRACE(SLOT_HANDLER_LINE); remote_event_wait(&state->trigger_event, &local->trigger); @@ -1978,7 +1978,7 @@ recycle_func(void *v) if (!found) return -ENOMEM; - while (1) { + while (!kthread_should_stop()) { remote_event_wait(&state->recycle_event, &local->recycle); process_free_queue(state, found, length); @@ -1997,7 +1997,7 @@ sync_func(void *v) state->remote->slot_sync); int svc_fourcc; - while (1) { + while (!kthread_should_stop()) { struct vchiq_service *service; int msgid, size; int type; @@ -2844,6 +2844,10 @@ vchiq_shutdown_internal(struct vchiq_state *state, struct vchiq_instance *instan (void)vchiq_remove_service(instance, service->handle); vchiq_service_put(service); } + + kthread_stop(state->sync_thread); + kthread_stop(state->recycle_thread); + kthread_stop(state->slot_handler_thread); } int -- cgit v1.2.3-59-g8ed1b From 77fc5151f9c0e6068f1567b73d33e75a0c35333d Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 17 Feb 2024 16:42:35 +0000 Subject: device property: Move fwnode_handle_put() into property.h By having this function as static inline in the header, the compiler is able to see if can optmize the call out if (IS_ERR_OR_NULL(fwnode)) This will allow a simpler DEFINE_FREE() call in the following patch. Suggested-by: Sakari Ailus Reviewed-by: Sakari Ailus Acked-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20240217164249.921878-2-jic23@kernel.org Signed-off-by: Jonathan Cameron --- drivers/base/property.c | 14 -------------- include/linux/property.h | 14 +++++++++++++- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/drivers/base/property.c b/drivers/base/property.c index 7324a704a9a1..6a3a434d0d6f 100644 --- a/drivers/base/property.c +++ b/drivers/base/property.c @@ -868,20 +868,6 @@ struct fwnode_handle *fwnode_handle_get(struct fwnode_handle *fwnode) } EXPORT_SYMBOL_GPL(fwnode_handle_get); -/** - * fwnode_handle_put - Drop reference to a device node - * @fwnode: Pointer to the device node to drop the reference to. - * - * This has to be used when terminating device_for_each_child_node() iteration - * with break or return to prevent stale device node references from being left - * behind. - */ -void fwnode_handle_put(struct fwnode_handle *fwnode) -{ - fwnode_call_void_op(fwnode, put); -} -EXPORT_SYMBOL_GPL(fwnode_handle_put); - /** * fwnode_device_is_available - check if a device is available for use * @fwnode: Pointer to the fwnode of the device. diff --git a/include/linux/property.h b/include/linux/property.h index 3a1045eb786c..93d992a92f59 100644 --- a/include/linux/property.h +++ b/include/linux/property.h @@ -180,7 +180,19 @@ struct fwnode_handle *device_get_named_child_node(const struct device *dev, const char *childname); struct fwnode_handle *fwnode_handle_get(struct fwnode_handle *fwnode); -void fwnode_handle_put(struct fwnode_handle *fwnode); + +/** + * fwnode_handle_put - Drop reference to a device node + * @fwnode: Pointer to the device node to drop the reference to. + * + * This has to be used when terminating device_for_each_child_node() iteration + * with break or return to prevent stale device node references from being left + * behind. + */ +static inline void fwnode_handle_put(struct fwnode_handle *fwnode) +{ + fwnode_call_void_op(fwnode, put); +} int fwnode_irq_get(const struct fwnode_handle *fwnode, unsigned int index); int fwnode_irq_get_byname(const struct fwnode_handle *fwnode, const char *name); -- cgit v1.2.3-59-g8ed1b From 59ed5e2d505bf5f9b4af64d0021cd0c96aec1f7c Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 17 Feb 2024 16:42:36 +0000 Subject: device property: Add cleanup.h based fwnode_handle_put() scope based cleanup. Useful where the fwnode_handle was obtained from a call such as fwnode_find_reference() as it will safely do nothing if IS_ERR() is true and will automatically release the reference on the variable leaving scope. Reviewed-by: Andy Shevchenko Acked-by: Greg Kroah-Hartman Reviewed-by: Sakari Ailus Link: https://lore.kernel.org/r/20240217164249.921878-3-jic23@kernel.org Signed-off-by: Jonathan Cameron --- include/linux/property.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/linux/property.h b/include/linux/property.h index 93d992a92f59..1322f0cce77a 100644 --- a/include/linux/property.h +++ b/include/linux/property.h @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -194,6 +195,8 @@ static inline void fwnode_handle_put(struct fwnode_handle *fwnode) fwnode_call_void_op(fwnode, put); } +DEFINE_FREE(fwnode_handle, struct fwnode_handle *, fwnode_handle_put(_T)) + int fwnode_irq_get(const struct fwnode_handle *fwnode, unsigned int index); int fwnode_irq_get_byname(const struct fwnode_handle *fwnode, const char *name); -- cgit v1.2.3-59-g8ed1b From 365130fd47af6d4317aa16a407874b699ab8d8cb Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 17 Feb 2024 16:42:38 +0000 Subject: device property: Introduce device_for_each_child_node_scoped() Similar to recently propose for_each_child_of_node_scoped() this new version of the loop macro instantiates a new local struct fwnode_handle * that uses the __free(fwnode_handle) auto cleanup handling so that if a reference to a node is held on early exit from the loop the reference will be released. If the loop runs to completion, the child pointer will be NULL and no action will be taken. The reason this is useful is that it removes the need for fwnode_handle_put() on early loop exits. If there is a need to retain the reference, then return_ptr(child) or no_free_ptr(child) may be used to safely disable the auto cleanup. Acked-by: Greg Kroah-Hartman Reviewed-by: Sakari Ailus Link: https://lore.kernel.org/r/20240217164249.921878-5-jic23@kernel.org Signed-off-by: Jonathan Cameron --- include/linux/property.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/linux/property.h b/include/linux/property.h index 1322f0cce77a..61fc20e5f81f 100644 --- a/include/linux/property.h +++ b/include/linux/property.h @@ -175,6 +175,11 @@ struct fwnode_handle *device_get_next_child_node(const struct device *dev, for (child = device_get_next_child_node(dev, NULL); child; \ child = device_get_next_child_node(dev, child)) +#define device_for_each_child_node_scoped(dev, child) \ + for (struct fwnode_handle *child __free(fwnode_handle) = \ + device_get_next_child_node(dev, NULL); \ + child; child = device_get_next_child_node(dev, child)) + struct fwnode_handle *fwnode_get_named_child_node(const struct fwnode_handle *fwnode, const char *childname); struct fwnode_handle *device_get_named_child_node(const struct device *dev, -- cgit v1.2.3-59-g8ed1b From 1693d2a7459183dcc8e7e89d849076f082f3d4c9 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 17 Feb 2024 16:42:39 +0000 Subject: iio: adc: max11410: Use device_for_each_child_node_scoped() Switching to the _scoped() version removes the need for manual calling of fwnode_handle_put() in the paths where the code exits the loop early. In this case that's all in error paths. Reviewed-by: Nuno Sa Link: https://lore.kernel.org/r/20240217164249.921878-6-jic23@kernel.org Signed-off-by: Jonathan Cameron --- drivers/iio/adc/max11410.c | 27 +++++++-------------------- 1 file changed, 7 insertions(+), 20 deletions(-) diff --git a/drivers/iio/adc/max11410.c b/drivers/iio/adc/max11410.c index 6af829349b4e..45368850b220 100644 --- a/drivers/iio/adc/max11410.c +++ b/drivers/iio/adc/max11410.c @@ -696,7 +696,6 @@ static int max11410_parse_channels(struct max11410_state *st, struct device *dev = &st->spi_dev->dev; struct max11410_channel_config *cfg; struct iio_chan_spec *channels; - struct fwnode_handle *child; u32 reference, sig_path; const char *node_name; u32 inputs[2], scale; @@ -720,7 +719,7 @@ static int max11410_parse_channels(struct max11410_state *st, if (!st->channels) return -ENOMEM; - device_for_each_child_node(dev, child) { + device_for_each_child_node_scoped(dev, child) { node_name = fwnode_get_name(child); if (fwnode_property_present(child, "diff-channels")) { ret = fwnode_property_read_u32_array(child, @@ -735,47 +734,37 @@ static int max11410_parse_channels(struct max11410_state *st, inputs[1] = 0; chanspec.differential = 0; } - if (ret) { - fwnode_handle_put(child); + if (ret) return ret; - } if (inputs[0] > MAX11410_CHANNEL_INDEX_MAX || - inputs[1] > MAX11410_CHANNEL_INDEX_MAX) { - fwnode_handle_put(child); + inputs[1] > MAX11410_CHANNEL_INDEX_MAX) return dev_err_probe(&indio_dev->dev, -EINVAL, "Invalid channel index for %s, should be less than %d\n", node_name, MAX11410_CHANNEL_INDEX_MAX + 1); - } cfg = &st->channels[chan_idx]; reference = MAX11410_REFSEL_AVDD_AGND; fwnode_property_read_u32(child, "adi,reference", &reference); - if (reference > MAX11410_REFSEL_MAX) { - fwnode_handle_put(child); + if (reference > MAX11410_REFSEL_MAX) return dev_err_probe(&indio_dev->dev, -EINVAL, "Invalid adi,reference value for %s, should be less than %d.\n", node_name, MAX11410_REFSEL_MAX + 1); - } if (!max11410_get_vrefp(st, reference) || - (!max11410_get_vrefn(st, reference) && reference <= 2)) { - fwnode_handle_put(child); + (!max11410_get_vrefn(st, reference) && reference <= 2)) return dev_err_probe(&indio_dev->dev, -EINVAL, "Invalid VREF configuration for %s, either specify corresponding VREF regulators or change adi,reference property.\n", node_name); - } sig_path = MAX11410_PGA_SIG_PATH_BUFFERED; fwnode_property_read_u32(child, "adi,input-mode", &sig_path); - if (sig_path > MAX11410_SIG_PATH_MAX) { - fwnode_handle_put(child); + if (sig_path > MAX11410_SIG_PATH_MAX) return dev_err_probe(&indio_dev->dev, -EINVAL, "Invalid adi,input-mode value for %s, should be less than %d.\n", node_name, MAX11410_SIG_PATH_MAX + 1); - } fwnode_property_read_u32(child, "settling-time-us", &cfg->settling_time_us); @@ -793,10 +782,8 @@ static int max11410_parse_channels(struct max11410_state *st, cfg->scale_avail = devm_kcalloc(dev, MAX11410_SCALE_AVAIL_SIZE * 2, sizeof(*cfg->scale_avail), GFP_KERNEL); - if (!cfg->scale_avail) { - fwnode_handle_put(child); + if (!cfg->scale_avail) return -ENOMEM; - } scale = max11410_get_scale(st, *cfg); for (i = 0; i < MAX11410_SCALE_AVAIL_SIZE; i++) { -- cgit v1.2.3-59-g8ed1b From 2fe97fccbd3f1da3f64818c123264db7cd2a257b Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 17 Feb 2024 16:42:46 +0000 Subject: iio: addac: ad74413r: Use device_for_each_child_node_scoped() Switching to the _scoped() version removes the need for manual calling of fwnode_handle_put() in the paths where the code exits the loop early. In this case that's all in error paths. The use of fwnode_for_each_available_child_node() here is assumed to have been down to a false assumption that device_for_each_child_node() doesn't check avaialble - so this transition to the scoped device_for_each_child_node_scoped() is equivalent. Cc: Rasmus Villemoes Reviewed-by: Nuno Sa Link: https://lore.kernel.org/r/20240217164249.921878-13-jic23@kernel.org Signed-off-by: Jonathan Cameron --- drivers/iio/addac/ad74413r.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/iio/addac/ad74413r.c b/drivers/iio/addac/ad74413r.c index 7af3e4b8fe3b..cd26a16dc0ff 100644 --- a/drivers/iio/addac/ad74413r.c +++ b/drivers/iio/addac/ad74413r.c @@ -1255,21 +1255,15 @@ static int ad74413r_parse_channel_config(struct iio_dev *indio_dev, static int ad74413r_parse_channel_configs(struct iio_dev *indio_dev) { struct ad74413r_state *st = iio_priv(indio_dev); - struct fwnode_handle *channel_node = NULL; int ret; - fwnode_for_each_available_child_node(dev_fwnode(st->dev), channel_node) { + device_for_each_child_node_scoped(st->dev, channel_node) { ret = ad74413r_parse_channel_config(indio_dev, channel_node); if (ret) - goto put_channel_node; + return ret; } return 0; - -put_channel_node: - fwnode_handle_put(channel_node); - - return ret; } static int ad74413r_setup_channels(struct iio_dev *indio_dev) -- cgit v1.2.3-59-g8ed1b From 8a85e72eaedc26acb5de768dc1bf53c7b4e3ada5 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 17 Feb 2024 16:42:49 +0000 Subject: iio: dac: ltc2688: Use device_for_each_child_node_scoped() Switching to the _scoped() version removes the need for manual calling of fwnode_handle_put() in the paths where the code exits the loop early. In this case that's all in error paths. Reviewed-by: Andy Shevchenko Tested-by: Nuno Sa Reviewed-by: Nuno Sa Link: https://lore.kernel.org/r/20240217164249.921878-16-jic23@kernel.org Signed-off-by: Jonathan Cameron --- drivers/iio/dac/ltc2688.c | 28 ++++++++-------------------- 1 file changed, 8 insertions(+), 20 deletions(-) diff --git a/drivers/iio/dac/ltc2688.c b/drivers/iio/dac/ltc2688.c index fc8eb53c65be..c4b1ba30f935 100644 --- a/drivers/iio/dac/ltc2688.c +++ b/drivers/iio/dac/ltc2688.c @@ -746,26 +746,21 @@ static int ltc2688_span_lookup(const struct ltc2688_state *st, int min, int max) static int ltc2688_channel_config(struct ltc2688_state *st) { struct device *dev = &st->spi->dev; - struct fwnode_handle *child; u32 reg, clk_input, val, tmp[2]; int ret, span; - device_for_each_child_node(dev, child) { + device_for_each_child_node_scoped(dev, child) { struct ltc2688_chan *chan; ret = fwnode_property_read_u32(child, "reg", ®); - if (ret) { - fwnode_handle_put(child); + if (ret) return dev_err_probe(dev, ret, "Failed to get reg property\n"); - } - if (reg >= LTC2688_DAC_CHANNELS) { - fwnode_handle_put(child); + if (reg >= LTC2688_DAC_CHANNELS) return dev_err_probe(dev, -EINVAL, "reg bigger than: %d\n", LTC2688_DAC_CHANNELS); - } val = 0; chan = &st->channels[reg]; @@ -786,12 +781,10 @@ static int ltc2688_channel_config(struct ltc2688_state *st) if (!ret) { span = ltc2688_span_lookup(st, (int)tmp[0] / 1000, tmp[1] / 1000); - if (span < 0) { - fwnode_handle_put(child); - return dev_err_probe(dev, -EINVAL, + if (span < 0) + return dev_err_probe(dev, span, "output range not valid:[%d %d]\n", tmp[0], tmp[1]); - } val |= FIELD_PREP(LTC2688_CH_SPAN_MSK, span); } @@ -800,17 +793,14 @@ static int ltc2688_channel_config(struct ltc2688_state *st) &clk_input); if (!ret) { if (clk_input >= LTC2688_CH_TGP_MAX) { - fwnode_handle_put(child); return dev_err_probe(dev, -EINVAL, "toggle-dither-input inv value(%d)\n", clk_input); } ret = ltc2688_tgp_clk_setup(st, chan, child, clk_input); - if (ret) { - fwnode_handle_put(child); + if (ret) return ret; - } /* * 0 means software toggle which is the default mode. @@ -844,11 +834,9 @@ static int ltc2688_channel_config(struct ltc2688_state *st) ret = regmap_write(st->regmap, LTC2688_CMD_CH_SETTING(reg), val); - if (ret) { - fwnode_handle_put(child); - return dev_err_probe(dev, -EINVAL, + if (ret) + return dev_err_probe(dev, ret, "failed to set chan settings\n"); - } } return 0; -- cgit v1.2.3-59-g8ed1b From 39d5790d0be1e5e82ded824f6b531bdcf5316390 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 18 Feb 2024 17:27:24 +0000 Subject: iio: adc: fsl-imx25-gcq: Switch from of specific handing to fwnode based. Using the generic firmware data access functions from property.h provides a number of advantages: 1) Works with different firmware types. 2) Doesn't provide a 'bad' example for new IIO drivers. 3) Lets us use the new _scoped() loops with automatic reference count cleanup for fwnode_handle Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240218172731.1023367-2-jic23@kernel.org Signed-off-by: Jonathan Cameron --- drivers/iio/adc/fsl-imx25-gcq.c | 54 ++++++++++++++++------------------------- 1 file changed, 21 insertions(+), 33 deletions(-) diff --git a/drivers/iio/adc/fsl-imx25-gcq.c b/drivers/iio/adc/fsl-imx25-gcq.c index 68c813de0605..534e73a24eb4 100644 --- a/drivers/iio/adc/fsl-imx25-gcq.c +++ b/drivers/iio/adc/fsl-imx25-gcq.c @@ -12,8 +12,9 @@ #include #include #include -#include +#include #include +#include #include #include @@ -198,8 +199,6 @@ static int mx25_gcq_ext_regulator_setup(struct device *dev, static int mx25_gcq_setup_cfgs(struct platform_device *pdev, struct mx25_gcq_priv *priv) { - struct device_node *np = pdev->dev.of_node; - struct device_node *child; struct device *dev = &pdev->dev; int ret, i; @@ -216,37 +215,30 @@ static int mx25_gcq_setup_cfgs(struct platform_device *pdev, MX25_ADCQ_CFG_IN(i) | MX25_ADCQ_CFG_REFN_NGND2); - for_each_child_of_node(np, child) { + device_for_each_child_node_scoped(dev, child) { u32 reg; u32 refp = MX25_ADCQ_CFG_REFP_INT; u32 refn = MX25_ADCQ_CFG_REFN_NGND2; - ret = of_property_read_u32(child, "reg", ®); - if (ret) { - dev_err(dev, "Failed to get reg property\n"); - of_node_put(child); - return ret; - } + ret = fwnode_property_read_u32(child, "reg", ®); + if (ret) + return dev_err_probe(dev, ret, + "Failed to get reg property\n"); - if (reg >= MX25_NUM_CFGS) { - dev_err(dev, + if (reg >= MX25_NUM_CFGS) + return dev_err_probe(dev, -EINVAL, "reg value is greater than the number of available configuration registers\n"); - of_node_put(child); - return -EINVAL; - } - of_property_read_u32(child, "fsl,adc-refp", &refp); - of_property_read_u32(child, "fsl,adc-refn", &refn); + fwnode_property_read_u32(child, "fsl,adc-refp", &refp); + fwnode_property_read_u32(child, "fsl,adc-refn", &refn); switch (refp) { case MX25_ADC_REFP_EXT: case MX25_ADC_REFP_XP: case MX25_ADC_REFP_YP: ret = mx25_gcq_ext_regulator_setup(&pdev->dev, priv, refp); - if (ret) { - of_node_put(child); + if (ret) return ret; - } priv->channel_vref_mv[reg] = regulator_get_voltage(priv->vref[refp]); /* Conversion from uV to mV */ @@ -256,9 +248,8 @@ static int mx25_gcq_setup_cfgs(struct platform_device *pdev, priv->channel_vref_mv[reg] = 2500; break; default: - dev_err(dev, "Invalid positive reference %d\n", refp); - of_node_put(child); - return -EINVAL; + return dev_err_probe(dev, -EINVAL, + "Invalid positive reference %d\n", refp); } /* @@ -268,16 +259,13 @@ static int mx25_gcq_setup_cfgs(struct platform_device *pdev, refp = MX25_ADCQ_CFG_REFP(refp); refn = MX25_ADCQ_CFG_REFN(refn); - if ((refp & MX25_ADCQ_CFG_REFP_MASK) != refp) { - dev_err(dev, "Invalid fsl,adc-refp property value\n"); - of_node_put(child); - return -EINVAL; - } - if ((refn & MX25_ADCQ_CFG_REFN_MASK) != refn) { - dev_err(dev, "Invalid fsl,adc-refn property value\n"); - of_node_put(child); - return -EINVAL; - } + if ((refp & MX25_ADCQ_CFG_REFP_MASK) != refp) + return dev_err_probe(dev, -EINVAL, + "Invalid fsl,adc-refp property value\n"); + + if ((refn & MX25_ADCQ_CFG_REFN_MASK) != refn) + return dev_err_probe(dev, -EINVAL, + "Invalid fsl,adc-refn property value\n"); regmap_update_bits(priv->regs, MX25_ADCQ_CFG(reg), MX25_ADCQ_CFG_REFP_MASK | -- cgit v1.2.3-59-g8ed1b From f84aec5a6bb509b38c855ef9b40c7c458b87b4b0 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 18 Feb 2024 17:27:25 +0000 Subject: iio: adc: fsl-imx25-gcq: Use devm_* and dev_err_probe() to simplify probe Custom callbacks are need for regulators (so there is a handle to read the voltage from) and the clk because it is retrieved from the parent rather than directly from firmware description. Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240218172731.1023367-3-jic23@kernel.org Signed-off-by: Jonathan Cameron --- drivers/iio/adc/fsl-imx25-gcq.c | 86 +++++++++++++++++------------------------ 1 file changed, 35 insertions(+), 51 deletions(-) diff --git a/drivers/iio/adc/fsl-imx25-gcq.c b/drivers/iio/adc/fsl-imx25-gcq.c index 534e73a24eb4..394396b91630 100644 --- a/drivers/iio/adc/fsl-imx25-gcq.c +++ b/drivers/iio/adc/fsl-imx25-gcq.c @@ -282,6 +282,17 @@ static int mx25_gcq_setup_cfgs(struct platform_device *pdev, return 0; } +static void mx25_gcq_reg_disable(void *reg) +{ + regulator_disable(reg); +} + +/* Custom handling needed as this driver doesn't own the clock */ +static void mx25_gcq_clk_disable(void *clk) +{ + clk_disable_unprepare(clk); +} + static int mx25_gcq_probe(struct platform_device *pdev) { struct iio_dev *indio_dev; @@ -303,10 +314,9 @@ static int mx25_gcq_probe(struct platform_device *pdev) return PTR_ERR(mem); priv->regs = devm_regmap_init_mmio(dev, mem, &mx25_gcq_regconfig); - if (IS_ERR(priv->regs)) { - dev_err(dev, "Failed to initialize regmap\n"); - return PTR_ERR(priv->regs); - } + if (IS_ERR(priv->regs)) + return dev_err_probe(dev, PTR_ERR(priv->regs), + "Failed to initialize regmap\n"); mutex_init(&priv->lock); @@ -322,69 +332,44 @@ static int mx25_gcq_probe(struct platform_device *pdev) ret = regulator_enable(priv->vref[i]); if (ret) - goto err_regulator_disable; + return ret; + + ret = devm_add_action_or_reset(dev, mx25_gcq_reg_disable, + priv->vref[i]); + if (ret) + return ret; } priv->clk = tsadc->clk; ret = clk_prepare_enable(priv->clk); - if (ret) { - dev_err(dev, "Failed to enable clock\n"); - goto err_vref_disable; - } + if (ret) + return dev_err_probe(dev, ret, "Failed to enable clock\n"); + + ret = devm_add_action_or_reset(dev, mx25_gcq_clk_disable, + priv->clk); + if (ret) + return ret; ret = platform_get_irq(pdev, 0); if (ret < 0) - goto err_clk_unprepare; + return ret; priv->irq = ret; - ret = request_irq(priv->irq, mx25_gcq_irq, 0, pdev->name, priv); - if (ret) { - dev_err(dev, "Failed requesting IRQ\n"); - goto err_clk_unprepare; - } + ret = devm_request_irq(dev, priv->irq, mx25_gcq_irq, 0, pdev->name, + priv); + if (ret) + return dev_err_probe(dev, ret, "Failed requesting IRQ\n"); indio_dev->channels = mx25_gcq_channels; indio_dev->num_channels = ARRAY_SIZE(mx25_gcq_channels); indio_dev->info = &mx25_gcq_iio_info; indio_dev->name = driver_name; - ret = iio_device_register(indio_dev); - if (ret) { - dev_err(dev, "Failed to register iio device\n"); - goto err_irq_free; - } - - platform_set_drvdata(pdev, indio_dev); + ret = devm_iio_device_register(dev, indio_dev); + if (ret) + return dev_err_probe(dev, ret, "Failed to register iio device\n"); return 0; - -err_irq_free: - free_irq(priv->irq, priv); -err_clk_unprepare: - clk_disable_unprepare(priv->clk); -err_vref_disable: - i = 4; -err_regulator_disable: - for (; i-- > 0;) { - if (priv->vref[i]) - regulator_disable(priv->vref[i]); - } - return ret; -} - -static void mx25_gcq_remove(struct platform_device *pdev) -{ - struct iio_dev *indio_dev = platform_get_drvdata(pdev); - struct mx25_gcq_priv *priv = iio_priv(indio_dev); - int i; - - iio_device_unregister(indio_dev); - free_irq(priv->irq, priv); - clk_disable_unprepare(priv->clk); - for (i = 4; i-- > 0;) { - if (priv->vref[i]) - regulator_disable(priv->vref[i]); - } } static const struct of_device_id mx25_gcq_ids[] = { @@ -399,7 +384,6 @@ static struct platform_driver mx25_gcq_driver = { .of_match_table = mx25_gcq_ids, }, .probe = mx25_gcq_probe, - .remove_new = mx25_gcq_remove, }; module_platform_driver(mx25_gcq_driver); -- cgit v1.2.3-59-g8ed1b From a6eaf02b82744b424b9b2c74847282deb2c6f77b Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 18 Feb 2024 17:27:26 +0000 Subject: iio: adc: ad7124: Switch from of specific to fwnode based property handling Using the generic firmware data access functions from property.h provides a number of advantages: 1) Works with different firmware types. 2) Doesn't provide a 'bad' example for new IIO drivers. 3) Lets us use the new _scoped() loops with automatic reference count cleanup for fwnode_handle Cc: Lars-Peter Clausen Cc: Michael Hennerich Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240218172731.1023367-4-jic23@kernel.org Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7124.c | 55 ++++++++++++++++++++---------------------------- 1 file changed, 23 insertions(+), 32 deletions(-) diff --git a/drivers/iio/adc/ad7124.c b/drivers/iio/adc/ad7124.c index b9b206fcd748..e7b1d517d3de 100644 --- a/drivers/iio/adc/ad7124.c +++ b/drivers/iio/adc/ad7124.c @@ -14,7 +14,8 @@ #include #include #include -#include +#include +#include #include #include @@ -807,22 +808,19 @@ static int ad7124_check_chip_id(struct ad7124_state *st) return 0; } -static int ad7124_of_parse_channel_config(struct iio_dev *indio_dev, - struct device_node *np) +static int ad7124_parse_channel_config(struct iio_dev *indio_dev, + struct device *dev) { struct ad7124_state *st = iio_priv(indio_dev); struct ad7124_channel_config *cfg; struct ad7124_channel *channels; - struct device_node *child; struct iio_chan_spec *chan; unsigned int ain[2], channel = 0, tmp; int ret; - st->num_channels = of_get_available_child_count(np); - if (!st->num_channels) { - dev_err(indio_dev->dev.parent, "no channel children\n"); - return -ENODEV; - } + st->num_channels = device_get_child_node_count(dev); + if (!st->num_channels) + return dev_err_probe(dev, -ENODEV, "no channel children\n"); chan = devm_kcalloc(indio_dev->dev.parent, st->num_channels, sizeof(*chan), GFP_KERNEL); @@ -838,39 +836,38 @@ static int ad7124_of_parse_channel_config(struct iio_dev *indio_dev, indio_dev->num_channels = st->num_channels; st->channels = channels; - for_each_available_child_of_node(np, child) { + device_for_each_child_node_scoped(dev, child) { cfg = &st->channels[channel].cfg; - ret = of_property_read_u32(child, "reg", &channel); + ret = fwnode_property_read_u32(child, "reg", &channel); if (ret) - goto err; + return ret; - if (channel >= indio_dev->num_channels) { - dev_err(indio_dev->dev.parent, + if (channel >= indio_dev->num_channels) + return dev_err_probe(dev, -EINVAL, "Channel index >= number of channels\n"); - ret = -EINVAL; - goto err; - } - ret = of_property_read_u32_array(child, "diff-channels", - ain, 2); + ret = fwnode_property_read_u32_array(child, "diff-channels", + ain, 2); if (ret) - goto err; + return ret; st->channels[channel].nr = channel; st->channels[channel].ain = AD7124_CHANNEL_AINP(ain[0]) | AD7124_CHANNEL_AINM(ain[1]); - cfg->bipolar = of_property_read_bool(child, "bipolar"); + cfg->bipolar = fwnode_property_read_bool(child, "bipolar"); - ret = of_property_read_u32(child, "adi,reference-select", &tmp); + ret = fwnode_property_read_u32(child, "adi,reference-select", &tmp); if (ret) cfg->refsel = AD7124_INT_REF; else cfg->refsel = tmp; - cfg->buf_positive = of_property_read_bool(child, "adi,buffered-positive"); - cfg->buf_negative = of_property_read_bool(child, "adi,buffered-negative"); + cfg->buf_positive = + fwnode_property_read_bool(child, "adi,buffered-positive"); + cfg->buf_negative = + fwnode_property_read_bool(child, "adi,buffered-negative"); chan[channel] = ad7124_channel_template; chan[channel].address = channel; @@ -880,10 +877,6 @@ static int ad7124_of_parse_channel_config(struct iio_dev *indio_dev, } return 0; -err: - of_node_put(child); - - return ret; } static int ad7124_setup(struct ad7124_state *st) @@ -943,9 +936,7 @@ static int ad7124_probe(struct spi_device *spi) struct iio_dev *indio_dev; int i, ret; - info = of_device_get_match_data(&spi->dev); - if (!info) - info = (void *)spi_get_device_id(spi)->driver_data; + info = spi_get_device_match_data(spi); if (!info) return -ENODEV; @@ -965,7 +956,7 @@ static int ad7124_probe(struct spi_device *spi) if (ret < 0) return ret; - ret = ad7124_of_parse_channel_config(indio_dev, spi->dev.of_node); + ret = ad7124_parse_channel_config(indio_dev, &spi->dev); if (ret < 0) return ret; -- cgit v1.2.3-59-g8ed1b From bb134d2fbc86a729af21096734b85f717c690fcd Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 18 Feb 2024 17:27:27 +0000 Subject: iio: adc: ad7292: Switch from of specific to fwnode property handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reduces the wrong of device tree only IIO drivers that might be copied by converting over this simple case. Makes use of the new _scoped() handling to automatically release the fwnode_handle on early exit from the loop. Cc: Nuno Sá Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240218172731.1023367-5-jic23@kernel.org Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7292.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/iio/adc/ad7292.c b/drivers/iio/adc/ad7292.c index cccacec5db6d..6aadd14f459d 100644 --- a/drivers/iio/adc/ad7292.c +++ b/drivers/iio/adc/ad7292.c @@ -8,7 +8,8 @@ #include #include #include -#include +#include +#include #include #include @@ -260,7 +261,6 @@ static int ad7292_probe(struct spi_device *spi) { struct ad7292_state *st; struct iio_dev *indio_dev; - struct device_node *child; bool diff_channels = false; int ret; @@ -305,12 +305,11 @@ static int ad7292_probe(struct spi_device *spi) indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &ad7292_info; - for_each_available_child_of_node(spi->dev.of_node, child) { - diff_channels = of_property_read_bool(child, "diff-channels"); - if (diff_channels) { - of_node_put(child); + device_for_each_child_node_scoped(&spi->dev, child) { + diff_channels = fwnode_property_read_bool(child, + "diff-channels"); + if (diff_channels) break; - } } if (diff_channels) { -- cgit v1.2.3-59-g8ed1b From c3708c829a0662af429897a90aed46b70f14a50b Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 18 Feb 2024 17:27:28 +0000 Subject: iio: adc: ad7192: Convert from of specific to fwnode property handling Enables use of with other firmwware types. Removes a case of device tree specific handlers that might get copied into new drivers. Cc: Alisa-Dariana Roman Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240218172731.1023367-6-jic23@kernel.org Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7192.c | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/drivers/iio/adc/ad7192.c b/drivers/iio/adc/ad7192.c index adc3cbe92d6e..7bcc7e2aa2a2 100644 --- a/drivers/iio/adc/ad7192.c +++ b/drivers/iio/adc/ad7192.c @@ -17,7 +17,9 @@ #include #include #include -#include +#include +#include +#include #include #include @@ -364,19 +366,19 @@ static inline bool ad7192_valid_external_frequency(u32 freq) freq <= AD7192_EXT_FREQ_MHZ_MAX); } -static int ad7192_of_clock_select(struct ad7192_state *st) +static int ad7192_clock_select(struct ad7192_state *st) { - struct device_node *np = st->sd.spi->dev.of_node; + struct device *dev = &st->sd.spi->dev; unsigned int clock_sel; clock_sel = AD7192_CLK_INT; /* use internal clock */ if (!st->mclk) { - if (of_property_read_bool(np, "adi,int-clock-output-enable")) + if (device_property_read_bool(dev, "adi,int-clock-output-enable")) clock_sel = AD7192_CLK_INT_CO; } else { - if (of_property_read_bool(np, "adi,clock-xtal")) + if (device_property_read_bool(dev, "adi,clock-xtal")) clock_sel = AD7192_CLK_EXT_MCLK1_2; else clock_sel = AD7192_CLK_EXT_MCLK2; @@ -385,7 +387,7 @@ static int ad7192_of_clock_select(struct ad7192_state *st) return clock_sel; } -static int ad7192_setup(struct iio_dev *indio_dev, struct device_node *np) +static int ad7192_setup(struct iio_dev *indio_dev, struct device *dev) { struct ad7192_state *st = iio_priv(indio_dev); bool rej60_en, refin2_en; @@ -407,7 +409,7 @@ static int ad7192_setup(struct iio_dev *indio_dev, struct device_node *np) id = FIELD_GET(AD7192_ID_MASK, id); if (id != st->chip_info->chip_id) - dev_warn(&st->sd.spi->dev, "device ID query failed (0x%X != 0x%X)\n", + dev_warn(dev, "device ID query failed (0x%X != 0x%X)\n", id, st->chip_info->chip_id); st->mode = FIELD_PREP(AD7192_MODE_SEL_MASK, AD7192_MODE_IDLE) | @@ -416,30 +418,30 @@ static int ad7192_setup(struct iio_dev *indio_dev, struct device_node *np) st->conf = FIELD_PREP(AD7192_CONF_GAIN_MASK, 0); - rej60_en = of_property_read_bool(np, "adi,rejection-60-Hz-enable"); + rej60_en = device_property_read_bool(dev, "adi,rejection-60-Hz-enable"); if (rej60_en) st->mode |= AD7192_MODE_REJ60; - refin2_en = of_property_read_bool(np, "adi,refin2-pins-enable"); + refin2_en = device_property_read_bool(dev, "adi,refin2-pins-enable"); if (refin2_en && st->chip_info->chip_id != CHIPID_AD7195) st->conf |= AD7192_CONF_REFSEL; st->conf &= ~AD7192_CONF_CHOP; - buf_en = of_property_read_bool(np, "adi,buffer-enable"); + buf_en = device_property_read_bool(dev, "adi,buffer-enable"); if (buf_en) st->conf |= AD7192_CONF_BUF; - bipolar = of_property_read_bool(np, "bipolar"); + bipolar = device_property_read_bool(dev, "bipolar"); if (!bipolar) st->conf |= AD7192_CONF_UNIPOLAR; - burnout_curr_en = of_property_read_bool(np, - "adi,burnout-currents-enable"); + burnout_curr_en = device_property_read_bool(dev, + "adi,burnout-currents-enable"); if (burnout_curr_en && buf_en) { st->conf |= AD7192_CONF_BURN; } else if (burnout_curr_en) { - dev_warn(&st->sd.spi->dev, + dev_warn(dev, "Can't enable burnout currents: see CHOP or buffer\n"); } @@ -1117,9 +1119,7 @@ static int ad7192_probe(struct spi_device *spi) } st->int_vref_mv = ret / 1000; - st->chip_info = of_device_get_match_data(&spi->dev); - if (!st->chip_info) - st->chip_info = (void *)spi_get_device_id(spi)->driver_data; + st->chip_info = spi_get_device_match_data(spi); indio_dev->name = st->chip_info->name; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->channels = st->chip_info->channels; @@ -1140,7 +1140,7 @@ static int ad7192_probe(struct spi_device *spi) if (IS_ERR(st->mclk)) return PTR_ERR(st->mclk); - st->clock_sel = ad7192_of_clock_select(st); + st->clock_sel = ad7192_clock_select(st); if (st->clock_sel == AD7192_CLK_EXT_MCLK1_2 || st->clock_sel == AD7192_CLK_EXT_MCLK2) { @@ -1152,7 +1152,7 @@ static int ad7192_probe(struct spi_device *spi) } } - ret = ad7192_setup(indio_dev, spi->dev.of_node); + ret = ad7192_setup(indio_dev, &spi->dev); if (ret) return ret; -- cgit v1.2.3-59-g8ed1b From 13c524162b3aa98ed1de7e528a1831dd4646451b Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 18 Feb 2024 17:27:29 +0000 Subject: iio: accel: mma8452: Switch from of specific to fwnode property handling. In this case only use was to get an irq so easily converted. Also include linux/mod_devicetable.h for struct of_device_id definition. Using the generic firmware handling, this driver may be used with other firmware types. This also removes an example that might get copied into other drivers leaving them unable to be used with alternative firmware types. Cc: Haibo Chen Reviewed-and-tested-by: Haibo Chen Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240218172731.1023367-7-jic23@kernel.org Signed-off-by: Jonathan Cameron --- drivers/iio/accel/mma8452.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c index d3fd0318e47b..62e6369e2269 100644 --- a/drivers/iio/accel/mma8452.c +++ b/drivers/iio/accel/mma8452.c @@ -19,6 +19,8 @@ */ #include +#include +#include #include #include #include @@ -28,8 +30,6 @@ #include #include #include -#include -#include #include #include @@ -1642,7 +1642,7 @@ static int mma8452_probe(struct i2c_client *client) if (client->irq) { int irq2; - irq2 = of_irq_get_byname(client->dev.of_node, "INT2"); + irq2 = fwnode_irq_get_byname(dev_fwnode(&client->dev), "INT2"); if (irq2 == client->irq) { dev_dbg(&client->dev, "using interrupt line INT2\n"); -- cgit v1.2.3-59-g8ed1b From 2936e7d8c1177a4c77d6b88c96039f7370806638 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 18 Feb 2024 17:27:30 +0000 Subject: iio: accel: fxls8962af: Switch from of specific to fwnode based properties. Only the irq was retrieved using an of specific accessor. Switch to the fwnode equivalent and adjust headers. Also include missing mod_devicetable.h and irq.h. Cc: Sean Nyekjaer Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240218172731.1023367-8-jic23@kernel.org Signed-off-by: Jonathan Cameron --- drivers/iio/accel/fxls8962af-core.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/iio/accel/fxls8962af-core.c b/drivers/iio/accel/fxls8962af-core.c index be8a15cb945f..4fbc01bda62e 100644 --- a/drivers/iio/accel/fxls8962af-core.c +++ b/drivers/iio/accel/fxls8962af-core.c @@ -15,9 +15,11 @@ #include #include #include +#include #include -#include +#include #include +#include #include #include @@ -1062,12 +1064,12 @@ static void fxls8962af_pm_disable(void *dev_ptr) fxls8962af_standby(iio_priv(indio_dev)); } -static void fxls8962af_get_irq(struct device_node *of_node, +static void fxls8962af_get_irq(struct device *dev, enum fxls8962af_int_pin *pin) { int irq; - irq = of_irq_get_byname(of_node, "INT2"); + irq = fwnode_irq_get_byname(dev_fwnode(dev), "INT2"); if (irq > 0) { *pin = FXLS8962AF_PIN_INT2; return; @@ -1086,7 +1088,7 @@ static int fxls8962af_irq_setup(struct iio_dev *indio_dev, int irq) u8 int_pin_sel; int ret; - fxls8962af_get_irq(dev->of_node, &int_pin); + fxls8962af_get_irq(dev, &int_pin); switch (int_pin) { case FXLS8962AF_PIN_INT1: int_pin_sel = FXLS8962AF_INT_PIN_SEL_INT1; -- cgit v1.2.3-59-g8ed1b From e1186ee3f48eb29c296f30232ab0c0997c0c6a06 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 18 Feb 2024 17:27:31 +0000 Subject: iio: adc: hx711: Switch from of specific to fwnode property handling. Allows driver to be used with other firmware types and removes an example that might be copied into new IIO drivers. Cc: Andreas Klinger Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240218172731.1023367-9-jic23@kernel.org Signed-off-by: Jonathan Cameron --- drivers/iio/adc/hx711.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/iio/adc/hx711.c b/drivers/iio/adc/hx711.c index c80c55fb8c6c..fef97c1d226a 100644 --- a/drivers/iio/adc/hx711.c +++ b/drivers/iio/adc/hx711.c @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include #include @@ -459,7 +459,6 @@ static const struct iio_chan_spec hx711_chan_spec[] = { static int hx711_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct device_node *np = dev->of_node; struct hx711_data *hx711_data; struct iio_dev *indio_dev; int ret; @@ -533,7 +532,7 @@ static int hx711_probe(struct platform_device *pdev) hx711_data->gain_chan_a = 128; hx711_data->clock_frequency = 400000; - ret = of_property_read_u32(np, "clock-frequency", + ret = device_property_read_u32(&pdev->dev, "clock-frequency", &hx711_data->clock_frequency); /* -- cgit v1.2.3-59-g8ed1b From 8ca555bd059a4e645b5cf0ec09c3e002a3d347af Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 24 Feb 2024 12:32:07 +0000 Subject: iio: temp: ltc2983: Use __free(fwnode_handle) and device_for_each_node_scoped() This use of the new cleanup.h scope based freeing infrastructure allows us to exit directly from error conditions and in the good path with the reference obtained from fwnode_find_reference() (which may be an error pointer) automatically released. Similarly the _scoped() version of device_for_each_child_node() removes the need for the manual calling of fwnode_handl_put() in paths where the code exits the loop early. Tidy up some unusual indentation in a dev_dbg() whilst here. Reviewed-by: Nuno Sa Link: https://lore.kernel.org/r/20240224123215.161469-2-jic23@kernel.org Signed-off-by: Jonathan Cameron --- drivers/iio/temperature/ltc2983.c | 137 ++++++++++++++------------------------ 1 file changed, 50 insertions(+), 87 deletions(-) diff --git a/drivers/iio/temperature/ltc2983.c b/drivers/iio/temperature/ltc2983.c index 39447c786af3..3c4524d57b8e 100644 --- a/drivers/iio/temperature/ltc2983.c +++ b/drivers/iio/temperature/ltc2983.c @@ -657,7 +657,6 @@ ltc2983_thermocouple_new(const struct fwnode_handle *child, struct ltc2983_data const struct ltc2983_sensor *sensor) { struct ltc2983_thermocouple *thermo; - struct fwnode_handle *ref; u32 oc_current; int ret; @@ -704,7 +703,8 @@ ltc2983_thermocouple_new(const struct fwnode_handle *child, struct ltc2983_data return ERR_PTR(-EINVAL); } - ref = fwnode_find_reference(child, "adi,cold-junction-handle", 0); + struct fwnode_handle *ref __free(fwnode_handle) = + fwnode_find_reference(child, "adi,cold-junction-handle", 0); if (IS_ERR(ref)) { ref = NULL; } else { @@ -715,7 +715,7 @@ ltc2983_thermocouple_new(const struct fwnode_handle *child, struct ltc2983_data * the error right away. */ dev_err(&st->spi->dev, "Property reg must be given\n"); - goto fail; + return ERR_PTR(ret); } } @@ -726,22 +726,15 @@ ltc2983_thermocouple_new(const struct fwnode_handle *child, struct ltc2983_data thermo->custom = __ltc2983_custom_sensor_new(st, child, propname, false, 16384, true); - if (IS_ERR(thermo->custom)) { - ret = PTR_ERR(thermo->custom); - goto fail; - } + if (IS_ERR(thermo->custom)) + return ERR_CAST(thermo->custom); } /* set common parameters */ thermo->sensor.fault_handler = ltc2983_thermocouple_fault_handler; thermo->sensor.assign_chan = ltc2983_thermocouple_assign_chan; - fwnode_handle_put(ref); return &thermo->sensor; - -fail: - fwnode_handle_put(ref); - return ERR_PTR(ret); } static struct ltc2983_sensor * @@ -751,14 +744,14 @@ ltc2983_rtd_new(const struct fwnode_handle *child, struct ltc2983_data *st, struct ltc2983_rtd *rtd; int ret = 0; struct device *dev = &st->spi->dev; - struct fwnode_handle *ref; u32 excitation_current = 0, n_wires = 0; rtd = devm_kzalloc(dev, sizeof(*rtd), GFP_KERNEL); if (!rtd) return ERR_PTR(-ENOMEM); - ref = fwnode_find_reference(child, "adi,rsense-handle", 0); + struct fwnode_handle *ref __free(fwnode_handle) = + fwnode_find_reference(child, "adi,rsense-handle", 0); if (IS_ERR(ref)) { dev_err(dev, "Property adi,rsense-handle missing or invalid"); return ERR_CAST(ref); @@ -767,7 +760,7 @@ ltc2983_rtd_new(const struct fwnode_handle *child, struct ltc2983_data *st, ret = fwnode_property_read_u32(ref, "reg", &rtd->r_sense_chan); if (ret) { dev_err(dev, "Property reg must be given\n"); - goto fail; + return ERR_PTR(ret); } ret = fwnode_property_read_u32(child, "adi,number-of-wires", &n_wires); @@ -788,8 +781,7 @@ ltc2983_rtd_new(const struct fwnode_handle *child, struct ltc2983_data *st, break; default: dev_err(dev, "Invalid number of wires:%u\n", n_wires); - ret = -EINVAL; - goto fail; + return ERR_PTR(-EINVAL); } } @@ -799,8 +791,7 @@ ltc2983_rtd_new(const struct fwnode_handle *child, struct ltc2983_data *st, if (n_wires == 2 || n_wires == 3) { dev_err(dev, "Rotation not allowed for 2/3 Wire RTDs"); - ret = -EINVAL; - goto fail; + return ERR_PTR(-EINVAL); } rtd->sensor_config |= LTC2983_RTD_C_ROTATE(1); } else { @@ -830,16 +821,14 @@ ltc2983_rtd_new(const struct fwnode_handle *child, struct ltc2983_data *st, "Invalid rsense chann:%d to use in kelvin rsense", rtd->r_sense_chan); - ret = -EINVAL; - goto fail; + return ERR_PTR(-EINVAL); } if (sensor->chan < min || sensor->chan > max) { dev_err(dev, "Invalid chann:%d for the rtd config", sensor->chan); - ret = -EINVAL; - goto fail; + return ERR_PTR(-EINVAL); } } else { /* same as differential case */ @@ -847,8 +836,7 @@ ltc2983_rtd_new(const struct fwnode_handle *child, struct ltc2983_data *st, dev_err(&st->spi->dev, "Invalid chann:%d for RTD", sensor->chan); - ret = -EINVAL; - goto fail; + return ERR_PTR(-EINVAL); } } @@ -857,10 +845,8 @@ ltc2983_rtd_new(const struct fwnode_handle *child, struct ltc2983_data *st, rtd->custom = __ltc2983_custom_sensor_new(st, child, "adi,custom-rtd", false, 2048, false); - if (IS_ERR(rtd->custom)) { - ret = PTR_ERR(rtd->custom); - goto fail; - } + if (IS_ERR(rtd->custom)) + return ERR_CAST(rtd->custom); } /* set common parameters */ @@ -902,18 +888,13 @@ ltc2983_rtd_new(const struct fwnode_handle *child, struct ltc2983_data *st, dev_err(&st->spi->dev, "Invalid value for excitation current(%u)", excitation_current); - ret = -EINVAL; - goto fail; + return ERR_PTR(-EINVAL); } } fwnode_property_read_u32(child, "adi,rtd-curve", &rtd->rtd_curve); - fwnode_handle_put(ref); return &rtd->sensor; -fail: - fwnode_handle_put(ref); - return ERR_PTR(ret); } static struct ltc2983_sensor * @@ -922,7 +903,6 @@ ltc2983_thermistor_new(const struct fwnode_handle *child, struct ltc2983_data *s { struct ltc2983_thermistor *thermistor; struct device *dev = &st->spi->dev; - struct fwnode_handle *ref; u32 excitation_current = 0; int ret = 0; @@ -930,7 +910,8 @@ ltc2983_thermistor_new(const struct fwnode_handle *child, struct ltc2983_data *s if (!thermistor) return ERR_PTR(-ENOMEM); - ref = fwnode_find_reference(child, "adi,rsense-handle", 0); + struct fwnode_handle *ref __free(fwnode_handle) = + fwnode_find_reference(child, "adi,rsense-handle", 0); if (IS_ERR(ref)) { dev_err(dev, "Property adi,rsense-handle missing or invalid"); return ERR_CAST(ref); @@ -939,7 +920,7 @@ ltc2983_thermistor_new(const struct fwnode_handle *child, struct ltc2983_data *s ret = fwnode_property_read_u32(ref, "reg", &thermistor->r_sense_chan); if (ret) { dev_err(dev, "rsense channel must be configured...\n"); - goto fail; + return ERR_PTR(ret); } if (fwnode_property_read_bool(child, "adi,single-ended")) { @@ -959,8 +940,7 @@ ltc2983_thermistor_new(const struct fwnode_handle *child, struct ltc2983_data *s dev_err(&st->spi->dev, "Invalid chann:%d for differential thermistor", sensor->chan); - ret = -EINVAL; - goto fail; + return ERR_PTR(-EINVAL); } /* check custom sensor */ @@ -979,10 +959,8 @@ ltc2983_thermistor_new(const struct fwnode_handle *child, struct ltc2983_data *s propname, steinhart, 64, false); - if (IS_ERR(thermistor->custom)) { - ret = PTR_ERR(thermistor->custom); - goto fail; - } + if (IS_ERR(thermistor->custom)) + return ERR_CAST(thermistor->custom); } /* set common parameters */ thermistor->sensor.fault_handler = ltc2983_common_fault_handler; @@ -1006,8 +984,7 @@ ltc2983_thermistor_new(const struct fwnode_handle *child, struct ltc2983_data *s LTC2983_SENSOR_THERMISTOR_STEINHART) { dev_err(&st->spi->dev, "Auto Range not allowed for custom sensors\n"); - ret = -EINVAL; - goto fail; + return ERR_PTR(-EINVAL); } thermistor->excitation_current = 0x0c; break; @@ -1048,16 +1025,11 @@ ltc2983_thermistor_new(const struct fwnode_handle *child, struct ltc2983_data *s dev_err(&st->spi->dev, "Invalid value for excitation current(%u)", excitation_current); - ret = -EINVAL; - goto fail; + return ERR_PTR(-EINVAL); } } - fwnode_handle_put(ref); return &thermistor->sensor; -fail: - fwnode_handle_put(ref); - return ERR_PTR(ret); } static struct ltc2983_sensor * @@ -1350,8 +1322,7 @@ static irqreturn_t ltc2983_irq_handler(int irq, void *data) static int ltc2983_parse_fw(struct ltc2983_data *st) { struct device *dev = &st->spi->dev; - struct fwnode_handle *child; - int ret = 0, chan = 0, channel_avail_mask = 0; + int ret, chan = 0, channel_avail_mask = 0; device_property_read_u32(dev, "adi,mux-delay-config-us", &st->mux_delay_config); @@ -1369,38 +1340,35 @@ static int ltc2983_parse_fw(struct ltc2983_data *st) return -ENOMEM; st->iio_channels = st->num_channels; - device_for_each_child_node(dev, child) { + device_for_each_child_node_scoped(dev, child) { struct ltc2983_sensor sensor; ret = fwnode_property_read_u32(child, "reg", &sensor.chan); - if (ret) { - dev_err(dev, "reg property must given for child nodes\n"); - goto put_child; - } + if (ret) + return dev_err_probe(dev, ret, + "reg property must given for child nodes\n"); /* check if we have a valid channel */ if (sensor.chan < LTC2983_MIN_CHANNELS_NR || - sensor.chan > st->info->max_channels_nr) { - ret = -EINVAL; - dev_err(dev, "chan:%d must be from %u to %u\n", sensor.chan, - LTC2983_MIN_CHANNELS_NR, st->info->max_channels_nr); - goto put_child; - } else if (channel_avail_mask & BIT(sensor.chan)) { - ret = -EINVAL; - dev_err(dev, "chan:%d already in use\n", sensor.chan); - goto put_child; - } + sensor.chan > st->info->max_channels_nr) + return dev_err_probe(dev, -EINVAL, + "chan:%d must be from %u to %u\n", + sensor.chan, + LTC2983_MIN_CHANNELS_NR, + st->info->max_channels_nr); + + if (channel_avail_mask & BIT(sensor.chan)) + return dev_err_probe(dev, -EINVAL, + "chan:%d already in use\n", + sensor.chan); ret = fwnode_property_read_u32(child, "adi,sensor-type", &sensor.type); - if (ret) { - dev_err(dev, + if (ret) + return dev_err_probe(dev, ret, "adi,sensor-type property must given for child nodes\n"); - goto put_child; - } dev_dbg(dev, "Create new sensor, type %u, chann %u", - sensor.type, - sensor.chan); + sensor.type, sensor.chan); if (sensor.type >= LTC2983_SENSOR_THERMOCOUPLE && sensor.type <= LTC2983_SENSOR_THERMOCOUPLE_CUSTOM) { @@ -1427,17 +1395,15 @@ static int ltc2983_parse_fw(struct ltc2983_data *st) sensor.type == LTC2983_SENSOR_ACTIVE_TEMP) { st->sensors[chan] = ltc2983_temp_new(child, st, &sensor); } else { - dev_err(dev, "Unknown sensor type %d\n", sensor.type); - ret = -EINVAL; - goto put_child; + return dev_err_probe(dev, -EINVAL, + "Unknown sensor type %d\n", + sensor.type); } - if (IS_ERR(st->sensors[chan])) { - dev_err(dev, "Failed to create sensor %ld", - PTR_ERR(st->sensors[chan])); - ret = PTR_ERR(st->sensors[chan]); - goto put_child; - } + if (IS_ERR(st->sensors[chan])) + return dev_err_probe(dev, PTR_ERR(st->sensors[chan]), + "Failed to create sensor\n"); + /* set generic sensor parameters */ st->sensors[chan]->chan = sensor.chan; st->sensors[chan]->type = sensor.type; @@ -1447,9 +1413,6 @@ static int ltc2983_parse_fw(struct ltc2983_data *st) } return 0; -put_child: - fwnode_handle_put(child); - return ret; } static int ltc2983_eeprom_cmd(struct ltc2983_data *st, unsigned int cmd, -- cgit v1.2.3-59-g8ed1b From 5cfb5587f9145ea4e6de4e5c87f9bc60b6587e3b Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 24 Feb 2024 12:32:10 +0000 Subject: iio: adc: rzg2l_adc: Use device_for_each_child_node_scoped() Switching to the _scoped() version removes the need for manual calling of fwnode_handle_put() in the paths where the code exits the loop early. In this case that's all in error paths. Cc: Lad Prabhakar Reviewed-by: Lad Prabhakar Link: https://lore.kernel.org/r/20240224123215.161469-5-jic23@kernel.org Signed-off-by: Jonathan Cameron --- drivers/iio/adc/rzg2l_adc.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/iio/adc/rzg2l_adc.c b/drivers/iio/adc/rzg2l_adc.c index 0921ff2d9b3a..cd3a7e46ea53 100644 --- a/drivers/iio/adc/rzg2l_adc.c +++ b/drivers/iio/adc/rzg2l_adc.c @@ -302,7 +302,6 @@ static irqreturn_t rzg2l_adc_isr(int irq, void *dev_id) static int rzg2l_adc_parse_properties(struct platform_device *pdev, struct rzg2l_adc *adc) { struct iio_chan_spec *chan_array; - struct fwnode_handle *fwnode; struct rzg2l_adc_data *data; unsigned int channel; int num_channels; @@ -330,17 +329,13 @@ static int rzg2l_adc_parse_properties(struct platform_device *pdev, struct rzg2l return -ENOMEM; i = 0; - device_for_each_child_node(&pdev->dev, fwnode) { + device_for_each_child_node_scoped(&pdev->dev, fwnode) { ret = fwnode_property_read_u32(fwnode, "reg", &channel); - if (ret) { - fwnode_handle_put(fwnode); + if (ret) return ret; - } - if (channel >= RZG2L_ADC_MAX_CHANNELS) { - fwnode_handle_put(fwnode); + if (channel >= RZG2L_ADC_MAX_CHANNELS) return -EINVAL; - } chan_array[i].type = IIO_VOLTAGE; chan_array[i].indexed = 1; -- cgit v1.2.3-59-g8ed1b From 582021f4e9f8003146aeec2125fafeadfe1139f8 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 25 Feb 2024 14:27:14 +0000 Subject: iio: adc: rcar-gyroadc: use for_each_available_child_node_scoped() Using automated cleanup to replace of_node_put() handling allows for a simplfied flow by enabling direct returns on errors. Non available child nodes should never have been considered; that is ones where status != okay and was defined. Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20240225142714.286440-5-jic23@kernel.org Signed-off-by: Jonathan Cameron --- drivers/iio/adc/rcar-gyroadc.c | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/drivers/iio/adc/rcar-gyroadc.c b/drivers/iio/adc/rcar-gyroadc.c index d524f2e8e927..15a21d2860e7 100644 --- a/drivers/iio/adc/rcar-gyroadc.c +++ b/drivers/iio/adc/rcar-gyroadc.c @@ -318,7 +318,6 @@ static int rcar_gyroadc_parse_subdevs(struct iio_dev *indio_dev) struct rcar_gyroadc *priv = iio_priv(indio_dev); struct device *dev = priv->dev; struct device_node *np = dev->of_node; - struct device_node *child; struct regulator *vref; unsigned int reg; unsigned int adcmode = -1, childmode; @@ -326,7 +325,7 @@ static int rcar_gyroadc_parse_subdevs(struct iio_dev *indio_dev) unsigned int num_channels; int ret, first = 1; - for_each_child_of_node(np, child) { + for_each_available_child_of_node_scoped(np, child) { of_id = of_match_node(rcar_gyroadc_child_match, child); if (!of_id) { dev_err(dev, "Ignoring unsupported ADC \"%pOFn\".", @@ -352,7 +351,7 @@ static int rcar_gyroadc_parse_subdevs(struct iio_dev *indio_dev) num_channels = ARRAY_SIZE(rcar_gyroadc_iio_channels_3); break; default: - goto err_e_inval; + return -EINVAL; } /* @@ -369,7 +368,7 @@ static int rcar_gyroadc_parse_subdevs(struct iio_dev *indio_dev) dev_err(dev, "Failed to get child reg property of ADC \"%pOFn\".\n", child); - goto err_of_node_put; + return ret; } /* Channel number is too high. */ @@ -377,7 +376,7 @@ static int rcar_gyroadc_parse_subdevs(struct iio_dev *indio_dev) dev_err(dev, "Only %i channels supported with %pOFn, but reg = <%i>.\n", num_channels, child, reg); - goto err_e_inval; + return -EINVAL; } } @@ -386,7 +385,7 @@ static int rcar_gyroadc_parse_subdevs(struct iio_dev *indio_dev) dev_err(dev, "Channel %i uses different ADC mode than the rest.\n", reg); - goto err_e_inval; + return -EINVAL; } /* Channel is valid, grab the regulator. */ @@ -396,8 +395,7 @@ static int rcar_gyroadc_parse_subdevs(struct iio_dev *indio_dev) if (IS_ERR(vref)) { dev_dbg(dev, "Channel %i 'vref' supply not connected.\n", reg); - ret = PTR_ERR(vref); - goto err_of_node_put; + return PTR_ERR(vref); } priv->vref[reg] = vref; @@ -422,7 +420,6 @@ static int rcar_gyroadc_parse_subdevs(struct iio_dev *indio_dev) * we can stop parsing here. */ if (childmode == RCAR_GYROADC_MODE_SELECT_1_MB88101A) { - of_node_put(child); break; } } @@ -433,12 +430,6 @@ static int rcar_gyroadc_parse_subdevs(struct iio_dev *indio_dev) } return 0; - -err_e_inval: - ret = -EINVAL; -err_of_node_put: - of_node_put(child); - return ret; } static void rcar_gyroadc_deinit_supplies(struct iio_dev *indio_dev) -- cgit v1.2.3-59-g8ed1b From 9266dba06876dd2d7e2f1709a19a8b1b3eb6caef Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 28 Feb 2024 22:30:23 +0200 Subject: iio: adc: spear_adc: Make use of device properties Convert the module to be property provider agnostic and allow it to be used on non-OF platforms. Include mod_devicetable.h explicitly to replace the dropped of.h which included mod_devicetable.h indirectly. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240228203023.3609181-1-andriy.shevchenko@linux.intel.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/spear_adc.c | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/drivers/iio/adc/spear_adc.c b/drivers/iio/adc/spear_adc.c index 71362c2ddf89..b6dd096391c1 100644 --- a/drivers/iio/adc/spear_adc.c +++ b/drivers/iio/adc/spear_adc.c @@ -5,8 +5,10 @@ * Copyright 2012 Stefan Roese */ +#include #include #include +#include #include #include #include @@ -15,8 +17,6 @@ #include #include #include -#include -#include #include #include @@ -70,7 +70,7 @@ struct adc_regs_spear6xx { }; struct spear_adc_state { - struct device_node *np; + struct device *dev; struct adc_regs_spear3xx __iomem *adc_base_spear3xx; struct adc_regs_spear6xx __iomem *adc_base_spear6xx; struct clk *clk; @@ -123,7 +123,7 @@ static void spear_adc_set_ctrl(struct spear_adc_state *st, int n, static u32 spear_adc_get_average(struct spear_adc_state *st) { - if (of_device_is_compatible(st->np, "st,spear600-adc")) { + if (device_is_compatible(st->dev, "st,spear600-adc")) { return __raw_readl(&st->adc_base_spear6xx->average.msb) & SPEAR_ADC_DATA_MASK; } else { @@ -134,7 +134,7 @@ static u32 spear_adc_get_average(struct spear_adc_state *st) static void spear_adc_set_scanrate(struct spear_adc_state *st, u32 rate) { - if (of_device_is_compatible(st->np, "st,spear600-adc")) { + if (device_is_compatible(st->dev, "st,spear600-adc")) { __raw_writel(SPEAR600_ADC_SCAN_RATE_LO(rate), &st->adc_base_spear6xx->scan_rate_lo); __raw_writel(SPEAR600_ADC_SCAN_RATE_HI(rate), @@ -266,7 +266,6 @@ static const struct iio_info spear_adc_info = { static int spear_adc_probe(struct platform_device *pdev) { - struct device_node *np = pdev->dev.of_node; struct device *dev = &pdev->dev; struct spear_adc_state *st; struct iio_dev *indio_dev = NULL; @@ -279,11 +278,10 @@ static int spear_adc_probe(struct platform_device *pdev) "failed allocating iio device\n"); st = iio_priv(indio_dev); + st->dev = dev; mutex_init(&st->lock); - st->np = np; - /* * SPEAr600 has a different register layout than other SPEAr SoC's * (e.g. SPEAr3xx). Let's provide two register base addresses @@ -310,8 +308,7 @@ static int spear_adc_probe(struct platform_device *pdev) if (ret < 0) return dev_err_probe(dev, ret, "failed requesting interrupt\n"); - if (of_property_read_u32(np, "sampling-frequency", - &st->sampling_freq)) + if (device_property_read_u32(dev, "sampling-frequency", &st->sampling_freq)) return dev_err_probe(dev, -EINVAL, "sampling-frequency missing in DT\n"); @@ -319,13 +316,13 @@ static int spear_adc_probe(struct platform_device *pdev) * Optional avg_samples defaults to 0, resulting in single data * conversion */ - of_property_read_u32(np, "average-samples", &st->avg_samples); + device_property_read_u32(dev, "average-samples", &st->avg_samples); /* * Optional vref_external defaults to 0, resulting in internal vref * selection */ - of_property_read_u32(np, "vref-external", &st->vref_external); + device_property_read_u32(dev, "vref-external", &st->vref_external); spear_adc_configure(st); @@ -346,19 +343,17 @@ static int spear_adc_probe(struct platform_device *pdev) return 0; } -#ifdef CONFIG_OF static const struct of_device_id spear_adc_dt_ids[] = { { .compatible = "st,spear600-adc", }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, spear_adc_dt_ids); -#endif static struct platform_driver spear_adc_driver = { .probe = spear_adc_probe, .driver = { .name = SPEAR_ADC_MOD_NAME, - .of_match_table = of_match_ptr(spear_adc_dt_ids), + .of_match_table = spear_adc_dt_ids, }, }; -- cgit v1.2.3-59-g8ed1b From 3d50d03f21949625534c81b744b8e42765623e9e Mon Sep 17 00:00:00 2001 From: Dumitru Ceclan Date: Wed, 28 Feb 2024 13:06:18 +0200 Subject: dt-bindings: adc: add AD7173 The AD7173 family offer a complete integrated Sigma-Delta ADC solution which can be used in high precision, low noise single channel applications or higher speed multiplexed applications. The Sigma-Delta ADC is intended primarily for measurement of signals close to DC but also delivers outstanding performance with input bandwidths out to ~10kHz. Reviewed-by: Conor Dooley Signed-off-by: Dumitru Ceclan Link: https://lore.kernel.org/r/20240228110622.25114-1-mitrutzceclan@gmail.com Signed-off-by: Jonathan Cameron --- .../devicetree/bindings/iio/adc/adi,ad7173.yaml | 246 +++++++++++++++++++++ 1 file changed, 246 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/adc/adi,ad7173.yaml diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7173.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7173.yaml new file mode 100644 index 000000000000..36f16a325bc5 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7173.yaml @@ -0,0 +1,246 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +# Copyright 2023 Analog Devices Inc. +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/adc/adi,ad7173.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices AD7173 ADC + +maintainers: + - Ceclan Dumitru + +description: | + Analog Devices AD717x ADC's: + The AD717x family offer a complete integrated Sigma-Delta ADC solution which + can be used in high precision, low noise single channel applications + (Life Science measurements) or higher speed multiplexed applications + (Factory Automation PLC Input modules). The Sigma-Delta ADC is intended + primarily for measurement of signals close to DC but also delivers + outstanding performance with input bandwidths out to ~10kHz. + + Datasheets for supported chips: + https://www.analog.com/media/en/technical-documentation/data-sheets/AD7172-2.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/AD7173-8.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/AD7175-2.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/AD7176-2.pdf + +properties: + compatible: + enum: + - adi,ad7172-2 + - adi,ad7173-8 + - adi,ad7175-2 + - adi,ad7176-2 + + reg: + maxItems: 1 + + interrupts: + minItems: 1 + items: + - description: | + Ready: multiplexed with SPI data out. While SPI CS is low, + can be used to indicate the completion of a conversion. + + - description: | + Error: The three error bits in the status register (ADC_ERROR, CRC_ERROR, + and REG_ERROR) are OR'ed, inverted, and mapped to the ERROR pin. + Therefore, the ERROR pin indicates that an error has occurred. + + interrupt-names: + minItems: 1 + items: + - const: rdy + - const: err + + '#address-cells': + const: 1 + + '#size-cells': + const: 0 + + spi-max-frequency: + maximum: 20000000 + + gpio-controller: + description: Marks the device node as a GPIO controller. + + '#gpio-cells': + const: 2 + description: + The first cell is the GPIO number and the second cell specifies + GPIO flags, as defined in . + + vref-supply: + description: | + Differential external reference supply used for conversion. The reference + voltage (Vref) specified here must be the voltage difference between the + REF+ and REF- pins: Vref = (REF+) - (REF-). + + vref2-supply: + description: | + Differential external reference supply used for conversion. The reference + voltage (Vref2) specified here must be the voltage difference between the + REF2+ and REF2- pins: Vref2 = (REF2+) - (REF2-). + + avdd-supply: + description: Avdd supply, can be used as reference for conversion. + This supply is referenced to AVSS, voltage specified here + represents (AVDD1 - AVSS). + + avdd2-supply: + description: Avdd2 supply, used as the input to the internal voltage regulator. + This supply is referenced to AVSS, voltage specified here + represents (AVDD2 - AVSS). + + iovdd-supply: + description: iovdd supply, used for the chip digital interface. + + clocks: + maxItems: 1 + description: | + Optional external clock source. Can include one clock source: external + clock or external crystal. + + clock-names: + enum: + - ext-clk + - xtal + + '#clock-cells': + const: 0 + +patternProperties: + "^channel@[0-9a-f]$": + type: object + $ref: adc.yaml + unevaluatedProperties: false + + properties: + reg: + minimum: 0 + maximum: 15 + + diff-channels: + items: + minimum: 0 + maximum: 31 + + adi,reference-select: + description: | + Select the reference source to use when converting on + the specific channel. Valid values are: + vref : REF+ /REF− + vref2 : REF2+ /REF2− + refout-avss: REFOUT/AVSS (Internal reference) + avdd : AVDD /AVSS + + External reference ref2 only available on ad7173-8. + If not specified, internal reference used. + $ref: /schemas/types.yaml#/definitions/string + enum: + - vref + - vref2 + - refout-avss + - avdd + default: refout-avss + + required: + - reg + - diff-channels + +required: + - compatible + - reg + +allOf: + - $ref: /schemas/spi/spi-peripheral-props.yaml# + + - if: + properties: + compatible: + not: + contains: + const: adi,ad7173-8 + then: + properties: + vref2-supply: false + patternProperties: + "^channel@[0-9a-f]$": + properties: + adi,reference-select: + enum: + - vref + - refout-avss + - avdd + reg: + maximum: 3 + + - if: + anyOf: + - required: [clock-names] + - required: [clocks] + then: + properties: + '#clock-cells': false + +unevaluatedProperties: false + +examples: + - | + #include + #include + + spi { + #address-cells = <1>; + #size-cells = <0>; + + adc@0 { + compatible = "adi,ad7173-8"; + reg = <0>; + + #address-cells = <1>; + #size-cells = <0>; + + interrupts = <25 IRQ_TYPE_EDGE_FALLING>; + interrupt-names = "rdy"; + interrupt-parent = <&gpio>; + spi-max-frequency = <5000000>; + gpio-controller; + #gpio-cells = <2>; + #clock-cells = <0>; + + vref-supply = <&dummy_regulator>; + + channel@0 { + reg = <0>; + bipolar; + diff-channels = <0 1>; + adi,reference-select = "vref"; + }; + + channel@1 { + reg = <1>; + diff-channels = <2 3>; + }; + + channel@2 { + reg = <2>; + bipolar; + diff-channels = <4 5>; + }; + + channel@3 { + reg = <3>; + bipolar; + diff-channels = <6 7>; + }; + + channel@4 { + reg = <4>; + diff-channels = <8 9>; + adi,reference-select = "avdd"; + }; + }; + }; -- cgit v1.2.3-59-g8ed1b From 7b0c9f8fa3d25622c21eeaa2c095c8a36b8b08b7 Mon Sep 17 00:00:00 2001 From: Dumitru Ceclan Date: Wed, 28 Feb 2024 13:06:19 +0200 Subject: iio: adc: ad_sigma_delta: Add optional irq selection Add optional irq_num attribute to ad_sigma_delta_info structure for selecting the used interrupt line for ADC's conversion completion. Signed-off-by: Dumitru Ceclan Reviewed-by: Nuno Sa Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240228110622.25114-2-mitrutzceclan@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad_sigma_delta.c | 23 ++++++++++++++--------- include/linux/iio/adc/ad_sigma_delta.h | 3 +++ 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/drivers/iio/adc/ad_sigma_delta.c b/drivers/iio/adc/ad_sigma_delta.c index a602429cdde4..97a05f325df7 100644 --- a/drivers/iio/adc/ad_sigma_delta.c +++ b/drivers/iio/adc/ad_sigma_delta.c @@ -222,11 +222,11 @@ int ad_sd_calibrate(struct ad_sigma_delta *sigma_delta, goto out; sigma_delta->irq_dis = false; - enable_irq(sigma_delta->spi->irq); + enable_irq(sigma_delta->irq_line); timeout = wait_for_completion_timeout(&sigma_delta->completion, 2 * HZ); if (timeout == 0) { sigma_delta->irq_dis = true; - disable_irq_nosync(sigma_delta->spi->irq); + disable_irq_nosync(sigma_delta->irq_line); ret = -EIO; } else { ret = 0; @@ -295,7 +295,7 @@ int ad_sigma_delta_single_conversion(struct iio_dev *indio_dev, ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_SINGLE); sigma_delta->irq_dis = false; - enable_irq(sigma_delta->spi->irq); + enable_irq(sigma_delta->irq_line); ret = wait_for_completion_interruptible_timeout( &sigma_delta->completion, HZ); @@ -315,7 +315,7 @@ int ad_sigma_delta_single_conversion(struct iio_dev *indio_dev, out: if (!sigma_delta->irq_dis) { - disable_irq_nosync(sigma_delta->spi->irq); + disable_irq_nosync(sigma_delta->irq_line); sigma_delta->irq_dis = true; } @@ -396,7 +396,7 @@ static int ad_sd_buffer_postenable(struct iio_dev *indio_dev) goto err_unlock; sigma_delta->irq_dis = false; - enable_irq(sigma_delta->spi->irq); + enable_irq(sigma_delta->irq_line); return 0; @@ -414,7 +414,7 @@ static int ad_sd_buffer_postdisable(struct iio_dev *indio_dev) wait_for_completion_timeout(&sigma_delta->completion, HZ); if (!sigma_delta->irq_dis) { - disable_irq_nosync(sigma_delta->spi->irq); + disable_irq_nosync(sigma_delta->irq_line); sigma_delta->irq_dis = true; } @@ -516,7 +516,7 @@ static irqreturn_t ad_sd_trigger_handler(int irq, void *p) irq_handled: iio_trigger_notify_done(indio_dev->trig); sigma_delta->irq_dis = false; - enable_irq(sigma_delta->spi->irq); + enable_irq(sigma_delta->irq_line); return IRQ_HANDLED; } @@ -587,13 +587,13 @@ static int devm_ad_sd_probe_trigger(struct device *dev, struct iio_dev *indio_de sigma_delta->irq_dis = true; /* the IRQ core clears IRQ_DISABLE_UNLAZY flag when freeing an IRQ */ - irq_set_status_flags(sigma_delta->spi->irq, IRQ_DISABLE_UNLAZY); + irq_set_status_flags(sigma_delta->irq_line, IRQ_DISABLE_UNLAZY); /* Allow overwriting the flags from firmware */ if (!irq_flags) irq_flags = sigma_delta->info->irq_flags; - ret = devm_request_irq(dev, sigma_delta->spi->irq, + ret = devm_request_irq(dev, sigma_delta->irq_line, ad_sd_data_rdy_trig_poll, irq_flags | IRQF_NO_AUTOEN, indio_dev->name, @@ -673,6 +673,11 @@ int ad_sd_init(struct ad_sigma_delta *sigma_delta, struct iio_dev *indio_dev, } } + if (info->irq_line) + sigma_delta->irq_line = info->irq_line; + else + sigma_delta->irq_line = spi->irq; + iio_device_set_drvdata(indio_dev, sigma_delta); return 0; diff --git a/include/linux/iio/adc/ad_sigma_delta.h b/include/linux/iio/adc/ad_sigma_delta.h index 719cf9cc6e1a..383614ebd760 100644 --- a/include/linux/iio/adc/ad_sigma_delta.h +++ b/include/linux/iio/adc/ad_sigma_delta.h @@ -48,6 +48,7 @@ struct iio_dev; * be used. * @irq_flags: flags for the interrupt used by the triggered buffer * @num_slots: Number of sequencer slots + * @irq_line: IRQ for reading conversions. If 0, spi->irq will be used */ struct ad_sigma_delta_info { int (*set_channel)(struct ad_sigma_delta *, unsigned int channel); @@ -62,6 +63,7 @@ struct ad_sigma_delta_info { unsigned int data_reg; unsigned long irq_flags; unsigned int num_slots; + int irq_line; }; /** @@ -89,6 +91,7 @@ struct ad_sigma_delta { unsigned int active_slots; unsigned int current_slot; unsigned int num_slots; + int irq_line; bool status_appended; /* map slots to channels in order to know what to expect from devices */ unsigned int *slots; -- cgit v1.2.3-59-g8ed1b From 76a1e6a4280211b1ceffec4f79f96e492c661229 Mon Sep 17 00:00:00 2001 From: Dumitru Ceclan Date: Wed, 28 Feb 2024 13:06:20 +0200 Subject: iio: adc: ad7173: add AD7173 driver The AD7173 family offer a complete integrated Sigma-Delta ADC solution which can be used in high precision, low noise single channel applications or higher speed multiplexed applications. The Sigma-Delta ADC is intended primarily for measurement of signals close to DC but also delivers outstanding performance with input bandwidths out to ~10kHz. Reviewed-by: Andy Shevchenko Reviewed-by: Michael Walle # for gpio-regmap Signed-off-by: Dumitru Ceclan Reviewed-by: Nuno Sa Link: https://lore.kernel.org/r/20240228110622.25114-3-mitrutzceclan@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/Kconfig | 17 + drivers/iio/adc/Makefile | 1 + drivers/iio/adc/ad7173.c | 1116 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1134 insertions(+) create mode 100644 drivers/iio/adc/ad7173.c diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 0d9282fa67f5..91286ab83bd0 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -70,6 +70,23 @@ config AD7124 To compile this driver as a module, choose M here: the module will be called ad7124. +config AD7173 + tristate "Analog Devices AD7173 driver" + depends on SPI_MASTER + select AD_SIGMA_DELTA + select GPIO_REGMAP if GPIOLIB + select REGMAP_SPI if GPIOLIB + help + Say yes here to build support for Analog Devices AD7173 and similar ADC + Currently supported models: + - AD7172-2 + - AD7173-8 + - AD7175-2 + - AD7176-2 + + To compile this driver as a module, choose M here: the module will be + called ad7173. + config AD7192 tristate "Analog Devices AD7190 AD7192 AD7193 AD7195 ADC driver" depends on SPI diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index b3c434722364..717e964afed9 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_AD7091R) += ad7091r-base.o obj-$(CONFIG_AD7091R5) += ad7091r5.o obj-$(CONFIG_AD7091R8) += ad7091r8.o obj-$(CONFIG_AD7124) += ad7124.o +obj-$(CONFIG_AD7173) += ad7173.o obj-$(CONFIG_AD7192) += ad7192.o obj-$(CONFIG_AD7266) += ad7266.o obj-$(CONFIG_AD7280) += ad7280a.o diff --git a/drivers/iio/adc/ad7173.c b/drivers/iio/adc/ad7173.c new file mode 100644 index 000000000000..b42fbe28a325 --- /dev/null +++ b/drivers/iio/adc/ad7173.c @@ -0,0 +1,1116 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * AD7172-2/AD7173-8/AD7175-2/AD7176-2 SPI ADC driver + * Copyright (C) 2015, 2024 Analog Devices, Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#define AD7173_REG_COMMS 0x00 +#define AD7173_REG_ADC_MODE 0x01 +#define AD7173_REG_INTERFACE_MODE 0x02 +#define AD7173_REG_CRC 0x03 +#define AD7173_REG_DATA 0x04 +#define AD7173_REG_GPIO 0x06 +#define AD7173_REG_ID 0x07 +#define AD7173_REG_CH(x) (0x10 + (x)) +#define AD7173_REG_SETUP(x) (0x20 + (x)) +#define AD7173_REG_FILTER(x) (0x28 + (x)) +#define AD7173_REG_OFFSET(x) (0x30 + (x)) +#define AD7173_REG_GAIN(x) (0x38 + (x)) + +#define AD7173_RESET_LENGTH BITS_TO_BYTES(64) + +#define AD7173_CH_ENABLE BIT(15) +#define AD7173_CH_SETUP_SEL_MASK GENMASK(14, 12) +#define AD7173_CH_SETUP_AINPOS_MASK GENMASK(9, 5) +#define AD7173_CH_SETUP_AINNEG_MASK GENMASK(4, 0) + +#define AD7173_CH_ADDRESS(pos, neg) \ + (FIELD_PREP(AD7173_CH_SETUP_AINPOS_MASK, pos) | \ + FIELD_PREP(AD7173_CH_SETUP_AINNEG_MASK, neg)) +#define AD7173_AIN_TEMP_POS 17 +#define AD7173_AIN_TEMP_NEG 18 + +#define AD7172_ID 0x00d0 +#define AD7173_ID 0x30d0 +#define AD7175_ID 0x0cd0 +#define AD7176_ID 0x0c90 +#define AD7173_ID_MASK GENMASK(15, 4) + +#define AD7173_ADC_MODE_REF_EN BIT(15) +#define AD7173_ADC_MODE_SING_CYC BIT(13) +#define AD7173_ADC_MODE_MODE_MASK GENMASK(6, 4) +#define AD7173_ADC_MODE_CLOCKSEL_MASK GENMASK(3, 2) +#define AD7173_ADC_MODE_CLOCKSEL_INT 0x0 +#define AD7173_ADC_MODE_CLOCKSEL_INT_OUTPUT 0x1 +#define AD7173_ADC_MODE_CLOCKSEL_EXT 0x2 +#define AD7173_ADC_MODE_CLOCKSEL_XTAL 0x3 + +#define AD7173_GPIO_PDSW BIT(14) +#define AD7173_GPIO_OP_EN2_3 BIT(13) +#define AD7173_GPIO_MUX_IO BIT(12) +#define AD7173_GPIO_SYNC_EN BIT(11) +#define AD7173_GPIO_ERR_EN BIT(10) +#define AD7173_GPIO_ERR_DAT BIT(9) +#define AD7173_GPIO_GP_DATA3 BIT(7) +#define AD7173_GPIO_GP_DATA2 BIT(6) +#define AD7173_GPIO_IP_EN1 BIT(5) +#define AD7173_GPIO_IP_EN0 BIT(4) +#define AD7173_GPIO_OP_EN1 BIT(3) +#define AD7173_GPIO_OP_EN0 BIT(2) +#define AD7173_GPIO_GP_DATA1 BIT(1) +#define AD7173_GPIO_GP_DATA0 BIT(0) + +#define AD7173_GPO12_DATA(x) BIT((x) + 0) +#define AD7173_GPO23_DATA(x) BIT((x) + 4) +#define AD7173_GPO_DATA(x) ((x) < 2 ? AD7173_GPO12_DATA(x) : AD7173_GPO23_DATA(x)) + +#define AD7173_INTERFACE_DATA_STAT BIT(6) +#define AD7173_INTERFACE_DATA_STAT_EN(x) \ + FIELD_PREP(AD7173_INTERFACE_DATA_STAT, x) + +#define AD7173_SETUP_BIPOLAR BIT(12) +#define AD7173_SETUP_AREF_BUF_MASK GENMASK(11, 10) +#define AD7173_SETUP_AIN_BUF_MASK GENMASK(9, 8) + +#define AD7173_SETUP_REF_SEL_MASK GENMASK(5, 4) +#define AD7173_SETUP_REF_SEL_AVDD1_AVSS 0x3 +#define AD7173_SETUP_REF_SEL_INT_REF 0x2 +#define AD7173_SETUP_REF_SEL_EXT_REF2 0x1 +#define AD7173_SETUP_REF_SEL_EXT_REF 0x0 +#define AD7173_VOLTAGE_INT_REF_uV 2500000 +#define AD7173_TEMP_SENSIIVITY_uV_per_C 477 + +#define AD7173_FILTER_ODR0_MASK GENMASK(5, 0) +#define AD7173_MAX_CONFIGS 8 + +enum ad7173_ids { + ID_AD7172_2, + ID_AD7173_8, + ID_AD7175_2, + ID_AD7176_2, +}; + +struct ad7173_device_info { + const unsigned int *sinc5_data_rates; + unsigned int num_sinc5_data_rates; + unsigned int num_channels; + unsigned int num_configs; + unsigned int num_inputs; + unsigned int clock; + unsigned int id; + char *name; + bool has_temp; + u8 num_gpios; +}; + +struct ad7173_channel_config { + u8 cfg_slot; + bool live; + + /* Following fields are used to compare equality. */ + struct_group(config_props, + bool bipolar; + bool input_buf; + u8 odr; + u8 ref_sel; + ); +}; + +struct ad7173_channel { + unsigned int chan_reg; + unsigned int ain; + struct ad7173_channel_config cfg; +}; + +struct ad7173_state { + struct ad_sigma_delta sd; + const struct ad7173_device_info *info; + struct ad7173_channel *channels; + struct regulator_bulk_data regulators[3]; + unsigned int adc_mode; + unsigned int interface_mode; + unsigned int num_channels; + struct ida cfg_slots_status; + unsigned long long config_usage_counter; + unsigned long long *config_cnts; + struct clk *ext_clk; + struct clk_hw int_clk_hw; +#if IS_ENABLED(CONFIG_GPIOLIB) + struct regmap *reg_gpiocon_regmap; + struct gpio_regmap *gpio_regmap; +#endif +}; + +static const unsigned int ad7173_sinc5_data_rates[] = { + 6211000, 6211000, 6211000, 6211000, 6211000, 6211000, 5181000, 4444000, /* 0-7 */ + 3115000, 2597000, 1007000, 503800, 381000, 200300, 100500, 59520, /* 8-15 */ + 49680, 20010, 16333, 10000, 5000, 2500, 1250, /* 16-22 */ +}; + +static const unsigned int ad7175_sinc5_data_rates[] = { + 50000000, 41667000, 31250000, 27778000, /* 0-3 */ + 20833000, 17857000, 12500000, 10000000, /* 4-7 */ + 5000000, 2500000, 1000000, 500000, /* 8-11 */ + 397500, 200000, 100000, 59920, /* 12-15 */ + 49960, 20000, 16666, 10000, /* 16-19 */ + 5000, /* 20 */ +}; + +static const struct ad7173_device_info ad7173_device_info[] = { + [ID_AD7172_2] = { + .name = "ad7172-2", + .id = AD7172_ID, + .num_inputs = 5, + .num_channels = 4, + .num_configs = 4, + .num_gpios = 2, + .has_temp = true, + .clock = 2 * HZ_PER_MHZ, + .sinc5_data_rates = ad7173_sinc5_data_rates, + .num_sinc5_data_rates = ARRAY_SIZE(ad7173_sinc5_data_rates), + }, + [ID_AD7173_8] = { + .name = "ad7173-8", + .id = AD7173_ID, + .num_inputs = 17, + .num_channels = 16, + .num_configs = 8, + .num_gpios = 4, + .has_temp = true, + .clock = 2 * HZ_PER_MHZ, + .sinc5_data_rates = ad7173_sinc5_data_rates, + .num_sinc5_data_rates = ARRAY_SIZE(ad7173_sinc5_data_rates), + }, + [ID_AD7175_2] = { + .name = "ad7175-2", + .id = AD7175_ID, + .num_inputs = 5, + .num_channels = 4, + .num_configs = 4, + .num_gpios = 2, + .has_temp = true, + .clock = 16 * HZ_PER_MHZ, + .sinc5_data_rates = ad7175_sinc5_data_rates, + .num_sinc5_data_rates = ARRAY_SIZE(ad7175_sinc5_data_rates), + }, + [ID_AD7176_2] = { + .name = "ad7176-2", + .id = AD7176_ID, + .num_inputs = 5, + .num_channels = 4, + .num_configs = 4, + .num_gpios = 2, + .has_temp = false, + .clock = 16 * HZ_PER_MHZ, + .sinc5_data_rates = ad7175_sinc5_data_rates, + .num_sinc5_data_rates = ARRAY_SIZE(ad7175_sinc5_data_rates), + }, +}; + +static const char *const ad7173_ref_sel_str[] = { + [AD7173_SETUP_REF_SEL_EXT_REF] = "vref", + [AD7173_SETUP_REF_SEL_EXT_REF2] = "vref2", + [AD7173_SETUP_REF_SEL_INT_REF] = "refout-avss", + [AD7173_SETUP_REF_SEL_AVDD1_AVSS] = "avdd", +}; + +static const char *const ad7173_clk_sel[] = { + "ext-clk", "xtal" +}; + +#if IS_ENABLED(CONFIG_GPIOLIB) + +static const struct regmap_range ad7173_range_gpio[] = { + regmap_reg_range(AD7173_REG_GPIO, AD7173_REG_GPIO), +}; + +static const struct regmap_access_table ad7173_access_table = { + .yes_ranges = ad7173_range_gpio, + .n_yes_ranges = ARRAY_SIZE(ad7173_range_gpio), +}; + +static const struct regmap_config ad7173_regmap_config = { + .reg_bits = 8, + .val_bits = 16, + .rd_table = &ad7173_access_table, + .wr_table = &ad7173_access_table, + .read_flag_mask = BIT(6), +}; + +static int ad7173_mask_xlate(struct gpio_regmap *gpio, unsigned int base, + unsigned int offset, unsigned int *reg, + unsigned int *mask) +{ + *mask = AD7173_GPO_DATA(offset); + *reg = base; + return 0; +} + +static void ad7173_gpio_disable(void *data) +{ + struct ad7173_state *st = data; + unsigned int mask; + + mask = AD7173_GPIO_OP_EN0 | AD7173_GPIO_OP_EN1 | AD7173_GPIO_OP_EN2_3; + regmap_update_bits(st->reg_gpiocon_regmap, AD7173_REG_GPIO, mask, ~mask); +} + +static int ad7173_gpio_init(struct ad7173_state *st) +{ + struct gpio_regmap_config gpio_regmap = {}; + struct device *dev = &st->sd.spi->dev; + unsigned int mask; + int ret; + + st->reg_gpiocon_regmap = devm_regmap_init_spi(st->sd.spi, &ad7173_regmap_config); + ret = PTR_ERR_OR_ZERO(st->reg_gpiocon_regmap); + if (ret) + return dev_err_probe(dev, ret, "Unable to init regmap\n"); + + mask = AD7173_GPIO_OP_EN0 | AD7173_GPIO_OP_EN1 | AD7173_GPIO_OP_EN2_3; + regmap_update_bits(st->reg_gpiocon_regmap, AD7173_REG_GPIO, mask, mask); + + ret = devm_add_action_or_reset(dev, ad7173_gpio_disable, st); + if (ret) + return ret; + + gpio_regmap.parent = dev; + gpio_regmap.regmap = st->reg_gpiocon_regmap; + gpio_regmap.ngpio = st->info->num_gpios; + gpio_regmap.reg_set_base = AD7173_REG_GPIO; + gpio_regmap.reg_mask_xlate = ad7173_mask_xlate; + + st->gpio_regmap = devm_gpio_regmap_register(dev, &gpio_regmap); + ret = PTR_ERR_OR_ZERO(st->gpio_regmap); + if (ret) + return dev_err_probe(dev, ret, "Unable to init gpio-regmap\n"); + + return 0; +} +#else +static int ad7173_gpio_init(struct ad7173_state *st) +{ + return 0; +} +#endif /* CONFIG_GPIOLIB */ + +static struct ad7173_state *ad_sigma_delta_to_ad7173(struct ad_sigma_delta *sd) +{ + return container_of(sd, struct ad7173_state, sd); +} + +static struct ad7173_state *clk_hw_to_ad7173(struct clk_hw *hw) +{ + return container_of(hw, struct ad7173_state, int_clk_hw); +} + +static void ad7173_ida_destroy(void *data) +{ + struct ad7173_state *st = data; + + ida_destroy(&st->cfg_slots_status); +} + +static void ad7173_reset_usage_cnts(struct ad7173_state *st) +{ + memset64(st->config_cnts, 0, st->info->num_configs); + st->config_usage_counter = 0; +} + +static struct ad7173_channel_config * +ad7173_find_live_config(struct ad7173_state *st, struct ad7173_channel_config *cfg) +{ + struct ad7173_channel_config *cfg_aux; + ptrdiff_t cmp_size; + int i; + + cmp_size = sizeof_field(struct ad7173_channel_config, config_props); + for (i = 0; i < st->num_channels; i++) { + cfg_aux = &st->channels[i].cfg; + + if (cfg_aux->live && + !memcmp(&cfg->config_props, &cfg_aux->config_props, cmp_size)) + return cfg_aux; + } + return NULL; +} + +/* Could be replaced with a generic LRU implementation */ +static int ad7173_free_config_slot_lru(struct ad7173_state *st) +{ + int i, lru_position = 0; + + for (i = 1; i < st->info->num_configs; i++) + if (st->config_cnts[i] < st->config_cnts[lru_position]) + lru_position = i; + + for (i = 0; i < st->num_channels; i++) + if (st->channels[i].cfg.cfg_slot == lru_position) + st->channels[i].cfg.live = false; + + ida_free(&st->cfg_slots_status, lru_position); + return ida_alloc(&st->cfg_slots_status, GFP_KERNEL); +} + +/* Could be replaced with a generic LRU implementation */ +static int ad7173_load_config(struct ad7173_state *st, + struct ad7173_channel_config *cfg) +{ + unsigned int config; + int free_cfg_slot, ret; + + free_cfg_slot = ida_alloc_range(&st->cfg_slots_status, 0, + st->info->num_configs - 1, GFP_KERNEL); + if (free_cfg_slot < 0) + free_cfg_slot = ad7173_free_config_slot_lru(st); + + cfg->cfg_slot = free_cfg_slot; + config = FIELD_PREP(AD7173_SETUP_REF_SEL_MASK, cfg->ref_sel); + + if (cfg->bipolar) + config |= AD7173_SETUP_BIPOLAR; + + if (cfg->input_buf) + config |= AD7173_SETUP_AIN_BUF_MASK; + + ret = ad_sd_write_reg(&st->sd, AD7173_REG_SETUP(free_cfg_slot), 2, config); + if (ret) + return ret; + + return ad_sd_write_reg(&st->sd, AD7173_REG_FILTER(free_cfg_slot), 2, + AD7173_FILTER_ODR0_MASK & cfg->odr); +} + +static int ad7173_config_channel(struct ad7173_state *st, int addr) +{ + struct ad7173_channel_config *cfg = &st->channels[addr].cfg; + struct ad7173_channel_config *live_cfg; + int ret; + + if (!cfg->live) { + live_cfg = ad7173_find_live_config(st, cfg); + if (live_cfg) { + cfg->cfg_slot = live_cfg->cfg_slot; + } else { + ret = ad7173_load_config(st, cfg); + if (ret) + return ret; + cfg->live = true; + } + } + + if (st->config_usage_counter == U64_MAX) + ad7173_reset_usage_cnts(st); + + st->config_usage_counter++; + st->config_cnts[cfg->cfg_slot] = st->config_usage_counter; + + return 0; +} + +static int ad7173_set_channel(struct ad_sigma_delta *sd, unsigned int channel) +{ + struct ad7173_state *st = ad_sigma_delta_to_ad7173(sd); + unsigned int val; + int ret; + + ret = ad7173_config_channel(st, channel); + if (ret) + return ret; + + val = AD7173_CH_ENABLE | + FIELD_PREP(AD7173_CH_SETUP_SEL_MASK, st->channels[channel].cfg.cfg_slot) | + st->channels[channel].ain; + + return ad_sd_write_reg(&st->sd, AD7173_REG_CH(channel), 2, val); +} + +static int ad7173_set_mode(struct ad_sigma_delta *sd, + enum ad_sigma_delta_mode mode) +{ + struct ad7173_state *st = ad_sigma_delta_to_ad7173(sd); + + st->adc_mode &= ~AD7173_ADC_MODE_MODE_MASK; + st->adc_mode |= FIELD_PREP(AD7173_ADC_MODE_MODE_MASK, mode); + + return ad_sd_write_reg(&st->sd, AD7173_REG_ADC_MODE, 2, st->adc_mode); +} + +static int ad7173_append_status(struct ad_sigma_delta *sd, bool append) +{ + struct ad7173_state *st = ad_sigma_delta_to_ad7173(sd); + unsigned int interface_mode = st->interface_mode; + int ret; + + interface_mode |= AD7173_INTERFACE_DATA_STAT_EN(append); + ret = ad_sd_write_reg(&st->sd, AD7173_REG_INTERFACE_MODE, 2, interface_mode); + if (ret) + return ret; + + st->interface_mode = interface_mode; + + return 0; +} + +static int ad7173_disable_all(struct ad_sigma_delta *sd) +{ + struct ad7173_state *st = ad_sigma_delta_to_ad7173(sd); + int ret; + int i; + + for (i = 0; i < st->num_channels; i++) { + ret = ad_sd_write_reg(sd, AD7173_REG_CH(i), 2, 0); + if (ret < 0) + return ret; + } + + return 0; +} + +static struct ad_sigma_delta_info ad7173_sigma_delta_info = { + .set_channel = ad7173_set_channel, + .append_status = ad7173_append_status, + .disable_all = ad7173_disable_all, + .set_mode = ad7173_set_mode, + .has_registers = true, + .addr_shift = 0, + .read_mask = BIT(6), + .status_ch_mask = GENMASK(3, 0), + .data_reg = AD7173_REG_DATA, +}; + +static int ad7173_setup(struct iio_dev *indio_dev) +{ + struct ad7173_state *st = iio_priv(indio_dev); + struct device *dev = &st->sd.spi->dev; + u8 buf[AD7173_RESET_LENGTH]; + unsigned int id; + int ret; + + /* reset the serial interface */ + memset(buf, 0xff, AD7173_RESET_LENGTH); + ret = spi_write_then_read(st->sd.spi, buf, sizeof(buf), NULL, 0); + if (ret < 0) + return ret; + + /* datasheet recommends a delay of at least 500us after reset */ + fsleep(500); + + ret = ad_sd_read_reg(&st->sd, AD7173_REG_ID, 2, &id); + if (ret) + return ret; + + id &= AD7173_ID_MASK; + if (id != st->info->id) + dev_warn(dev, "Unexpected device id: 0x%04X, expected: 0x%04X\n", + id, st->info->id); + + st->adc_mode |= AD7173_ADC_MODE_SING_CYC; + st->interface_mode = 0x0; + + st->config_usage_counter = 0; + st->config_cnts = devm_kcalloc(dev, st->info->num_configs, + sizeof(*st->config_cnts), GFP_KERNEL); + if (!st->config_cnts) + return -ENOMEM; + + /* All channels are enabled by default after a reset */ + return ad7173_disable_all(&st->sd); +} + +static unsigned int ad7173_get_ref_voltage_milli(struct ad7173_state *st, + u8 reference_select) +{ + int vref; + + switch (reference_select) { + case AD7173_SETUP_REF_SEL_EXT_REF: + vref = regulator_get_voltage(st->regulators[0].consumer); + break; + + case AD7173_SETUP_REF_SEL_EXT_REF2: + vref = regulator_get_voltage(st->regulators[1].consumer); + break; + + case AD7173_SETUP_REF_SEL_INT_REF: + vref = AD7173_VOLTAGE_INT_REF_uV; + break; + + case AD7173_SETUP_REF_SEL_AVDD1_AVSS: + vref = regulator_get_voltage(st->regulators[2].consumer); + break; + + default: + return -EINVAL; + } + + if (vref < 0) + return vref; + + return vref / (MICRO / MILLI); +} + +static int ad7173_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long info) +{ + struct ad7173_state *st = iio_priv(indio_dev); + struct ad7173_channel *ch = &st->channels[chan->address]; + unsigned int reg; + u64 temp; + int ret; + + switch (info) { + case IIO_CHAN_INFO_RAW: + ret = ad_sigma_delta_single_conversion(indio_dev, chan, val); + if (ret < 0) + return ret; + + /* disable channel after single conversion */ + ret = ad_sd_write_reg(&st->sd, AD7173_REG_CH(chan->address), 2, 0); + if (ret < 0) + return ret; + + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + if (chan->type == IIO_TEMP) { + temp = AD7173_VOLTAGE_INT_REF_uV * MILLI; + temp /= AD7173_TEMP_SENSIIVITY_uV_per_C; + *val = temp; + *val2 = chan->scan_type.realbits; + } else { + *val = ad7173_get_ref_voltage_milli(st, ch->cfg.ref_sel); + *val2 = chan->scan_type.realbits - !!(ch->cfg.bipolar); + } + return IIO_VAL_FRACTIONAL_LOG2; + case IIO_CHAN_INFO_OFFSET: + if (chan->type == IIO_TEMP) { + /* 0 Kelvin -> raw sample */ + temp = -ABSOLUTE_ZERO_MILLICELSIUS; + temp *= AD7173_TEMP_SENSIIVITY_uV_per_C; + temp <<= chan->scan_type.realbits; + temp = DIV_U64_ROUND_CLOSEST(temp, + AD7173_VOLTAGE_INT_REF_uV * + MILLI); + *val = -temp; + } else { + *val = -BIT(chan->scan_type.realbits - 1); + } + return IIO_VAL_INT; + case IIO_CHAN_INFO_SAMP_FREQ: + reg = st->channels[chan->address].cfg.odr; + + *val = st->info->sinc5_data_rates[reg] / MILLI; + *val2 = (st->info->sinc5_data_rates[reg] % MILLI) * (MICRO / MILLI); + + return IIO_VAL_INT_PLUS_MICRO; + default: + return -EINVAL; + } +} + +static int ad7173_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long info) +{ + struct ad7173_state *st = iio_priv(indio_dev); + struct ad7173_channel_config *cfg; + unsigned int freq, i, reg; + int ret; + + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + return ret; + + switch (info) { + case IIO_CHAN_INFO_SAMP_FREQ: + freq = val * MILLI + val2 / MILLI; + for (i = 0; i < st->info->num_sinc5_data_rates - 1; i++) + if (freq >= st->info->sinc5_data_rates[i]) + break; + + cfg = &st->channels[chan->address].cfg; + cfg->odr = i; + + if (!cfg->live) + break; + + ret = ad_sd_read_reg(&st->sd, AD7173_REG_FILTER(cfg->cfg_slot), 2, ®); + if (ret) + break; + reg &= ~AD7173_FILTER_ODR0_MASK; + reg |= FIELD_PREP(AD7173_FILTER_ODR0_MASK, i); + ret = ad_sd_write_reg(&st->sd, AD7173_REG_FILTER(cfg->cfg_slot), 2, reg); + break; + + default: + ret = -EINVAL; + break; + } + + iio_device_release_direct_mode(indio_dev); + return ret; +} + +static int ad7173_update_scan_mode(struct iio_dev *indio_dev, + const unsigned long *scan_mask) +{ + struct ad7173_state *st = iio_priv(indio_dev); + int i, ret; + + for (i = 0; i < indio_dev->num_channels; i++) { + if (test_bit(i, scan_mask)) + ret = ad7173_set_channel(&st->sd, i); + else + ret = ad_sd_write_reg(&st->sd, AD7173_REG_CH(i), 2, 0); + if (ret < 0) + return ret; + } + + return 0; +} + +static int ad7173_debug_reg_access(struct iio_dev *indio_dev, unsigned int reg, + unsigned int writeval, unsigned int *readval) +{ + struct ad7173_state *st = iio_priv(indio_dev); + u8 reg_size; + + if (reg == AD7173_REG_COMMS) + reg_size = 1; + else if (reg == AD7173_REG_CRC || reg == AD7173_REG_DATA || + reg >= AD7173_REG_OFFSET(0)) + reg_size = 3; + else + reg_size = 2; + + if (readval) + return ad_sd_read_reg(&st->sd, reg, reg_size, readval); + + return ad_sd_write_reg(&st->sd, reg, reg_size, writeval); +} + +static const struct iio_info ad7173_info = { + .read_raw = &ad7173_read_raw, + .write_raw = &ad7173_write_raw, + .debugfs_reg_access = &ad7173_debug_reg_access, + .validate_trigger = ad_sd_validate_trigger, + .update_scan_mode = ad7173_update_scan_mode, +}; + +static const struct iio_chan_spec ad7173_channel_template = { + .type = IIO_VOLTAGE, + .indexed = 1, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE), + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), + .scan_type = { + .sign = 'u', + .realbits = 24, + .storagebits = 32, + .endianness = IIO_BE, + }, +}; + +static const struct iio_chan_spec ad7173_temp_iio_channel_template = { + .type = IIO_TEMP, + .indexed = 1, + .channel = AD7173_AIN_TEMP_POS, + .channel2 = AD7173_AIN_TEMP_NEG, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_OFFSET), + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), + .scan_type = { + .sign = 'u', + .realbits = 24, + .storagebits = 32, + .endianness = IIO_BE, + }, +}; + +static void ad7173_disable_regulators(void *data) +{ + struct ad7173_state *st = data; + + regulator_bulk_disable(ARRAY_SIZE(st->regulators), st->regulators); +} + +static void ad7173_clk_disable_unprepare(void *clk) +{ + clk_disable_unprepare(clk); +} + +static unsigned long ad7173_sel_clk(struct ad7173_state *st, + unsigned int clk_sel) +{ + int ret; + + st->adc_mode &= !AD7173_ADC_MODE_CLOCKSEL_MASK; + st->adc_mode |= FIELD_PREP(AD7173_ADC_MODE_CLOCKSEL_MASK, clk_sel); + ret = ad_sd_write_reg(&st->sd, AD7173_REG_ADC_MODE, 0x2, st->adc_mode); + + return ret; +} + +static unsigned long ad7173_clk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct ad7173_state *st = clk_hw_to_ad7173(hw); + + return st->info->clock / HZ_PER_KHZ; +} + +static int ad7173_clk_output_is_enabled(struct clk_hw *hw) +{ + struct ad7173_state *st = clk_hw_to_ad7173(hw); + u32 clk_sel; + + clk_sel = FIELD_GET(AD7173_ADC_MODE_CLOCKSEL_MASK, st->adc_mode); + return clk_sel == AD7173_ADC_MODE_CLOCKSEL_INT_OUTPUT; +} + +static int ad7173_clk_output_prepare(struct clk_hw *hw) +{ + struct ad7173_state *st = clk_hw_to_ad7173(hw); + + return ad7173_sel_clk(st, AD7173_ADC_MODE_CLOCKSEL_INT_OUTPUT); +} + +static void ad7173_clk_output_unprepare(struct clk_hw *hw) +{ + struct ad7173_state *st = clk_hw_to_ad7173(hw); + + ad7173_sel_clk(st, AD7173_ADC_MODE_CLOCKSEL_INT); +} + +static const struct clk_ops ad7173_int_clk_ops = { + .recalc_rate = ad7173_clk_recalc_rate, + .is_enabled = ad7173_clk_output_is_enabled, + .prepare = ad7173_clk_output_prepare, + .unprepare = ad7173_clk_output_unprepare, +}; + +static int ad7173_register_clk_provider(struct iio_dev *indio_dev) +{ + struct ad7173_state *st = iio_priv(indio_dev); + struct device *dev = indio_dev->dev.parent; + struct fwnode_handle *fwnode = dev_fwnode(dev); + struct clk_init_data init = {}; + int ret; + + if (!IS_ENABLED(CONFIG_COMMON_CLK)) + return 0; + + init.name = fwnode_get_name(fwnode); + init.ops = &ad7173_int_clk_ops; + + st->int_clk_hw.init = &init; + ret = devm_clk_hw_register(dev, &st->int_clk_hw); + if (ret) + return ret; + + return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, + &st->int_clk_hw); +} + +static int ad7173_fw_parse_channel_config(struct iio_dev *indio_dev) +{ + struct ad7173_channel *chans_st_arr, *chan_st_priv; + struct ad7173_state *st = iio_priv(indio_dev); + struct device *dev = indio_dev->dev.parent; + struct iio_chan_spec *chan_arr, *chan; + unsigned int ain[2], chan_index = 0; + struct fwnode_handle *child; + int ref_sel, ret; + + chan_arr = devm_kcalloc(dev, sizeof(*indio_dev->channels), + st->num_channels, GFP_KERNEL); + if (!chan_arr) + return -ENOMEM; + + chans_st_arr = devm_kcalloc(dev, st->num_channels, sizeof(*st->channels), + GFP_KERNEL); + if (!chans_st_arr) + return -ENOMEM; + + indio_dev->channels = chan_arr; + st->channels = chans_st_arr; + + if (st->info->has_temp) { + chan_arr[chan_index] = ad7173_temp_iio_channel_template; + chan_st_priv = &chans_st_arr[chan_index]; + chan_st_priv->ain = + AD7173_CH_ADDRESS(chan_arr[chan_index].channel, + chan_arr[chan_index].channel2); + chan_st_priv->cfg.bipolar = false; + chan_st_priv->cfg.input_buf = true; + chan_st_priv->cfg.ref_sel = AD7173_SETUP_REF_SEL_INT_REF; + st->adc_mode |= AD7173_ADC_MODE_REF_EN; + + chan_index++; + } + + device_for_each_child_node(dev, child) { + chan = &chan_arr[chan_index]; + chan_st_priv = &chans_st_arr[chan_index]; + ret = fwnode_property_read_u32_array(child, "diff-channels", + ain, ARRAY_SIZE(ain)); + if (ret) { + fwnode_handle_put(child); + return ret; + } + + if (ain[0] >= st->info->num_inputs || + ain[1] >= st->info->num_inputs) { + fwnode_handle_put(child); + return dev_err_probe(dev, -EINVAL, + "Input pin number out of range for pair (%d %d).\n", + ain[0], ain[1]); + } + + ret = fwnode_property_match_property_string(child, + "adi,reference-select", + ad7173_ref_sel_str, + ARRAY_SIZE(ad7173_ref_sel_str)); + if (ret < 0) + ref_sel = AD7173_SETUP_REF_SEL_INT_REF; + else + ref_sel = ret; + + if (ref_sel == AD7173_SETUP_REF_SEL_EXT_REF2 && + st->info->id != AD7173_ID) { + fwnode_handle_put(child); + return dev_err_probe(dev, -EINVAL, + "External reference 2 is only available on ad7173-8\n"); + } + + ret = ad7173_get_ref_voltage_milli(st, ref_sel); + if (ret < 0) { + fwnode_handle_put(child); + return dev_err_probe(dev, ret, + "Cannot use reference %u\n", ref_sel); + } + if (ref_sel == AD7173_SETUP_REF_SEL_INT_REF) + st->adc_mode |= AD7173_ADC_MODE_REF_EN; + chan_st_priv->cfg.ref_sel = ref_sel; + + *chan = ad7173_channel_template; + chan->address = chan_index; + chan->scan_index = chan_index; + chan->channel = ain[0]; + chan->channel2 = ain[1]; + chan->differential = true; + + chan_st_priv->ain = AD7173_CH_ADDRESS(ain[0], ain[1]); + chan_st_priv->chan_reg = chan_index; + chan_st_priv->cfg.input_buf = true; + chan_st_priv->cfg.odr = 0; + + chan_st_priv->cfg.bipolar = fwnode_property_read_bool(child, "bipolar"); + if (chan_st_priv->cfg.bipolar) + chan->info_mask_separate |= BIT(IIO_CHAN_INFO_OFFSET); + + chan_index++; + } + return 0; +} + +static int ad7173_fw_parse_device_config(struct iio_dev *indio_dev) +{ + struct ad7173_state *st = iio_priv(indio_dev); + struct device *dev = indio_dev->dev.parent; + unsigned int num_channels; + int ret; + + st->regulators[0].supply = ad7173_ref_sel_str[AD7173_SETUP_REF_SEL_EXT_REF]; + st->regulators[1].supply = ad7173_ref_sel_str[AD7173_SETUP_REF_SEL_EXT_REF2]; + st->regulators[2].supply = ad7173_ref_sel_str[AD7173_SETUP_REF_SEL_AVDD1_AVSS]; + + /* + * If a regulator is not available, it will be set to a dummy regulator. + * Each channel reference is checked with regulator_get_voltage() before + * setting attributes so if any channel uses a dummy supply the driver + * probe will fail. + */ + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(st->regulators), + st->regulators); + if (ret) + return dev_err_probe(dev, ret, "Failed to get regulators\n"); + + ret = regulator_bulk_enable(ARRAY_SIZE(st->regulators), st->regulators); + if (ret) + return dev_err_probe(dev, ret, "Failed to enable regulators\n"); + + ret = devm_add_action_or_reset(dev, ad7173_disable_regulators, st); + if (ret) + return dev_err_probe(dev, ret, + "Failed to add regulators disable action\n"); + + ret = device_property_match_property_string(dev, "clock-names", + ad7173_clk_sel, + ARRAY_SIZE(ad7173_clk_sel)); + if (ret < 0) { + st->adc_mode |= FIELD_PREP(AD7173_ADC_MODE_CLOCKSEL_MASK, + AD7173_ADC_MODE_CLOCKSEL_INT); + ad7173_register_clk_provider(indio_dev); + } else { + st->adc_mode |= FIELD_PREP(AD7173_ADC_MODE_CLOCKSEL_MASK, + AD7173_ADC_MODE_CLOCKSEL_EXT + ret); + st->ext_clk = devm_clk_get(dev, ad7173_clk_sel[ret]); + if (IS_ERR(st->ext_clk)) + return dev_err_probe(dev, PTR_ERR(st->ext_clk), + "Failed to get external clock\n"); + + ret = clk_prepare_enable(st->ext_clk); + if (ret) + return dev_err_probe(dev, ret, + "Failed to enable external clock\n"); + + ret = devm_add_action_or_reset(dev, ad7173_clk_disable_unprepare, + st->ext_clk); + if (ret) + return ret; + } + + ret = fwnode_irq_get_byname(dev_fwnode(dev), "rdy"); + if (ret < 0) + return dev_err_probe(dev, ret, "Interrupt 'rdy' is required\n"); + + ad7173_sigma_delta_info.irq_line = ret; + + num_channels = device_get_child_node_count(dev); + + if (st->info->has_temp) + num_channels++; + + if (num_channels == 0) + return dev_err_probe(dev, -ENODATA, "No channels specified\n"); + indio_dev->num_channels = num_channels; + st->num_channels = num_channels; + + return ad7173_fw_parse_channel_config(indio_dev); +} + +static int ad7173_probe(struct spi_device *spi) +{ + struct device *dev = &spi->dev; + struct ad7173_state *st; + struct iio_dev *indio_dev; + int ret; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; + + st = iio_priv(indio_dev); + st->info = spi_get_device_match_data(spi); + if (!st->info) + return -ENODEV; + + ida_init(&st->cfg_slots_status); + ret = devm_add_action_or_reset(dev, ad7173_ida_destroy, st); + if (ret) + return ret; + + indio_dev->name = st->info->name; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->info = &ad7173_info; + + spi->mode = SPI_MODE_3; + spi_setup(spi); + + ad7173_sigma_delta_info.num_slots = st->info->num_configs; + ret = ad_sd_init(&st->sd, indio_dev, spi, &ad7173_sigma_delta_info); + if (ret) + return ret; + + ret = ad7173_fw_parse_device_config(indio_dev); + if (ret) + return ret; + + ret = devm_ad_sd_setup_buffer_and_trigger(dev, indio_dev); + if (ret) + return ret; + + ret = ad7173_setup(indio_dev); + if (ret) + return ret; + + ret = devm_iio_device_register(dev, indio_dev); + if (ret) + return ret; + + if (IS_ENABLED(CONFIG_GPIOLIB)) + return ad7173_gpio_init(st); + + return 0; +} + +static const struct of_device_id ad7173_of_match[] = { + { .compatible = "adi,ad7172-2", + .data = &ad7173_device_info[ID_AD7172_2]}, + { .compatible = "adi,ad7173-8", + .data = &ad7173_device_info[ID_AD7173_8]}, + { .compatible = "adi,ad7175-2", + .data = &ad7173_device_info[ID_AD7175_2]}, + { .compatible = "adi,ad7176-2", + .data = &ad7173_device_info[ID_AD7176_2]}, + { } +}; +MODULE_DEVICE_TABLE(of, ad7173_of_match); + +static const struct spi_device_id ad7173_id_table[] = { + { "ad7172-2", (kernel_ulong_t)&ad7173_device_info[ID_AD7172_2]}, + { "ad7173-8", (kernel_ulong_t)&ad7173_device_info[ID_AD7173_8]}, + { "ad7175-2", (kernel_ulong_t)&ad7173_device_info[ID_AD7175_2]}, + { "ad7176-2", (kernel_ulong_t)&ad7173_device_info[ID_AD7176_2]}, + { } +}; +MODULE_DEVICE_TABLE(spi, ad7173_id_table); + +static struct spi_driver ad7173_driver = { + .driver = { + .name = "ad7173", + .of_match_table = ad7173_of_match, + }, + .probe = ad7173_probe, + .id_table = ad7173_id_table, +}; +module_spi_driver(ad7173_driver); + +MODULE_IMPORT_NS(IIO_AD_SIGMA_DELTA); +MODULE_AUTHOR("Lars-Peter Clausen "); +MODULE_AUTHOR("Dumitru Ceclan "); +MODULE_DESCRIPTION("Analog Devices AD7172/AD7173/AD7175/AD7176 ADC driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3-59-g8ed1b From ba7352d019e7814fec475f429207a70b54e66e11 Mon Sep 17 00:00:00 2001 From: Javier Carrasco Date: Sun, 3 Mar 2024 23:34:40 +0100 Subject: io: light: st_uvis25: drop casting to void in dev_set_drvdata The C standard specifies that there is no need to cast from a pointer to void [1]. Therefore, it can be safely dropped. [1] C Standard Committee: https://c0x.shape-of-code.com/6.3.2.3.html Signed-off-by: Javier Carrasco Link: https://lore.kernel.org/r/20240303-void_in_dev_set_drvdata-v1-2-ae39027d740b@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/light/st_uvis25_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/light/st_uvis25_core.c b/drivers/iio/light/st_uvis25_core.c index 50f95c5d2060..d4e17079b2f4 100644 --- a/drivers/iio/light/st_uvis25_core.c +++ b/drivers/iio/light/st_uvis25_core.c @@ -291,7 +291,7 @@ int st_uvis25_probe(struct device *dev, int irq, struct regmap *regmap) if (!iio_dev) return -ENOMEM; - dev_set_drvdata(dev, (void *)iio_dev); + dev_set_drvdata(dev, iio_dev); hw = iio_priv(iio_dev); hw->irq = irq; -- cgit v1.2.3-59-g8ed1b From 8c5b0ea6179d40dac239f772da706c2b779d29aa Mon Sep 17 00:00:00 2001 From: Javier Carrasco Date: Sun, 3 Mar 2024 23:34:41 +0100 Subject: iio: humidity: hts211: drop casting to void in dev_set_drvdata The C standard specifies that there is no need to cast from a pointer to void [1]. Therefore, it can be safely dropped. [1] C Standard Committee: https://c0x.shape-of-code.com/6.3.2.3.html Signed-off-by: Javier Carrasco Link: https://lore.kernel.org/r/20240303-void_in_dev_set_drvdata-v1-3-ae39027d740b@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/humidity/hts221_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/humidity/hts221_core.c b/drivers/iio/humidity/hts221_core.c index 2a413da87b76..87627d116eff 100644 --- a/drivers/iio/humidity/hts221_core.c +++ b/drivers/iio/humidity/hts221_core.c @@ -573,7 +573,7 @@ int hts221_probe(struct device *dev, int irq, const char *name, if (!iio_dev) return -ENOMEM; - dev_set_drvdata(dev, (void *)iio_dev); + dev_set_drvdata(dev, iio_dev); hw = iio_priv(iio_dev); hw->name = name; -- cgit v1.2.3-59-g8ed1b From cb98410db73f2584c8d8437472a7d4727f7c53fc Mon Sep 17 00:00:00 2001 From: Javier Carrasco Date: Sun, 3 Mar 2024 23:34:42 +0100 Subject: iio: imu: st_lsm6dsx: drop casting to void in dev_set_drvdata The C standard specifies that there is no need to cast from a pointer to void [1]. Therefore, it can be safely dropped. [1] C Standard Committee: https://c0x.shape-of-code.com/6.3.2.3.html Signed-off-by: Javier Carrasco Link: https://lore.kernel.org/r/20240303-void_in_dev_set_drvdata-v1-4-ae39027d740b@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c index 0716986f9812..937ff9c5a74c 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c @@ -2726,7 +2726,7 @@ int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id, if (!hw) return -ENOMEM; - dev_set_drvdata(dev, (void *)hw); + dev_set_drvdata(dev, hw); mutex_init(&hw->fifo_lock); mutex_init(&hw->conf_lock); -- cgit v1.2.3-59-g8ed1b From f0245ab389330cbc1d187e358a5b890d9f5383db Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 4 Mar 2024 16:04:32 +0200 Subject: iio: core: Leave private pointer NULL when no private data supplied In iio_device_alloc() when size of the private data is 0, the private pointer is calculated to point behind the valid data. Leave it NULL when no private data supplied. Fixes: 6d4ebd565d15 ("iio: core: wrap IIO device into an iio_dev_opaque object") Signed-off-by: Andy Shevchenko Reviewed-by: David Lechner Link: https://lore.kernel.org/r/20240304140650.977784-2-andriy.shevchenko@linux.intel.com Signed-off-by: Jonathan Cameron --- drivers/iio/industrialio-core.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index 4302093b92c7..8684ba246969 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -1654,8 +1654,10 @@ struct iio_dev *iio_device_alloc(struct device *parent, int sizeof_priv) return NULL; indio_dev = &iio_dev_opaque->indio_dev; - indio_dev->priv = (char *)iio_dev_opaque + - ALIGN(sizeof(struct iio_dev_opaque), IIO_DMA_MINALIGN); + + if (sizeof_priv) + indio_dev->priv = (char *)iio_dev_opaque + + ALIGN(sizeof(*iio_dev_opaque), IIO_DMA_MINALIGN); indio_dev->dev.parent = parent; indio_dev->dev.type = &iio_device_type; -- cgit v1.2.3-59-g8ed1b From 5c4e411566dfd76202c1af0d4ca04438e544ca28 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 4 Mar 2024 16:04:33 +0200 Subject: iio: core: Calculate alloc_size only once in iio_device_alloc() No need to rewrite the value, instead use 'else' branch. This will also help further refactoring the code later on. Signed-off-by: Andy Shevchenko Reviewed-by: David Lechner Link: https://lore.kernel.org/r/20240304140650.977784-3-andriy.shevchenko@linux.intel.com Signed-off-by: Jonathan Cameron --- drivers/iio/industrialio-core.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index 8684ba246969..c7ad88932015 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -1643,11 +1643,10 @@ struct iio_dev *iio_device_alloc(struct device *parent, int sizeof_priv) struct iio_dev *indio_dev; size_t alloc_size; - alloc_size = sizeof(struct iio_dev_opaque); - if (sizeof_priv) { - alloc_size = ALIGN(alloc_size, IIO_DMA_MINALIGN); - alloc_size += sizeof_priv; - } + if (sizeof_priv) + alloc_size = ALIGN(sizeof(*iio_dev_opaque), IIO_DMA_MINALIGN) + sizeof_priv; + else + alloc_size = sizeof(*iio_dev_opaque); iio_dev_opaque = kzalloc(alloc_size, GFP_KERNEL); if (!iio_dev_opaque) -- cgit v1.2.3-59-g8ed1b From 9278524c48658a0ddccf69a0c185129951d15853 Mon Sep 17 00:00:00 2001 From: Subhajit Ghosh Date: Sat, 9 Mar 2024 21:20:27 +1030 Subject: dt-bindings: iio: light: Merge APDS9300 and APDS9960 schemas Merge very similar schemas for APDS9300 and APDS9960. Suggested-by: Krzysztof Kozlowski Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/all/4e785d2e-d310-4592-a75a-13549938dcef@linaro.org/ Signed-off-by: Subhajit Ghosh Link: https://lore.kernel.org/r/20240309105031.10313-2-subhajit.ghosh@tweaklogic.com Signed-off-by: Jonathan Cameron --- .../bindings/iio/light/avago,apds9300.yaml | 11 ++++-- .../bindings/iio/light/avago,apds9960.yaml | 44 ---------------------- 2 files changed, 7 insertions(+), 48 deletions(-) delete mode 100644 Documentation/devicetree/bindings/iio/light/avago,apds9960.yaml diff --git a/Documentation/devicetree/bindings/iio/light/avago,apds9300.yaml b/Documentation/devicetree/bindings/iio/light/avago,apds9300.yaml index 206af44f2c43..c610780346e8 100644 --- a/Documentation/devicetree/bindings/iio/light/avago,apds9300.yaml +++ b/Documentation/devicetree/bindings/iio/light/avago,apds9300.yaml @@ -4,17 +4,20 @@ $id: http://devicetree.org/schemas/iio/light/avago,apds9300.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: Avago APDS9300 ambient light sensor +title: Avago Gesture/RGB/ALS/Proximity sensors maintainers: - - Jonathan Cameron + - Subhajit Ghosh description: | - Datasheet at https://www.avagotech.com/docs/AV02-1077EN + Datasheet: https://www.avagotech.com/docs/AV02-1077EN + Datasheet: https://www.avagotech.com/docs/AV02-4191EN properties: compatible: - const: avago,apds9300 + enum: + - avago,apds9300 + - avago,apds9960 reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/iio/light/avago,apds9960.yaml b/Documentation/devicetree/bindings/iio/light/avago,apds9960.yaml deleted file mode 100644 index f06e0fda5629..000000000000 --- a/Documentation/devicetree/bindings/iio/light/avago,apds9960.yaml +++ /dev/null @@ -1,44 +0,0 @@ -# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) -%YAML 1.2 ---- -$id: http://devicetree.org/schemas/iio/light/avago,apds9960.yaml# -$schema: http://devicetree.org/meta-schemas/core.yaml# - -title: Avago APDS9960 gesture/RGB/ALS/proximity sensor - -maintainers: - - Matt Ranostay - -description: | - Datasheet at https://www.avagotech.com/docs/AV02-4191EN - -properties: - compatible: - const: avago,apds9960 - - reg: - maxItems: 1 - - interrupts: - maxItems: 1 - -additionalProperties: false - -required: - - compatible - - reg - -examples: - - | - i2c { - #address-cells = <1>; - #size-cells = <0>; - - light-sensor@39 { - compatible = "avago,apds9960"; - reg = <0x39>; - interrupt-parent = <&gpio1>; - interrupts = <16 1>; - }; - }; -... -- cgit v1.2.3-59-g8ed1b From 59ee18822a24ebbf23327895436b705e39c857fd Mon Sep 17 00:00:00 2001 From: Subhajit Ghosh Date: Sat, 9 Mar 2024 21:20:28 +1030 Subject: dt-bindings: iio: light: adps9300: Add missing vdd-supply All devices covered by the binding have a vdd supply. Acked-by: Conor Dooley Signed-off-by: Subhajit Ghosh Link: https://lore.kernel.org/r/20240309105031.10313-3-subhajit.ghosh@tweaklogic.com Signed-off-by: Jonathan Cameron --- Documentation/devicetree/bindings/iio/light/avago,apds9300.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/iio/light/avago,apds9300.yaml b/Documentation/devicetree/bindings/iio/light/avago,apds9300.yaml index c610780346e8..a328c8a1daef 100644 --- a/Documentation/devicetree/bindings/iio/light/avago,apds9300.yaml +++ b/Documentation/devicetree/bindings/iio/light/avago,apds9300.yaml @@ -25,6 +25,8 @@ properties: interrupts: maxItems: 1 + vdd-supply: true + additionalProperties: false required: @@ -42,6 +44,7 @@ examples: reg = <0x39>; interrupt-parent = <&gpio2>; interrupts = <29 8>; + vdd-supply = <®ulator_3v3>; }; }; ... -- cgit v1.2.3-59-g8ed1b From 2f8608f71bfecd9aaeb571ea688e66e4ba225d12 Mon Sep 17 00:00:00 2001 From: Subhajit Ghosh Date: Sat, 9 Mar 2024 21:20:29 +1030 Subject: dt-bindings: iio: light: adps9300: Update interrupt definitions Include irq.h and irq level macro in the example for readability Acked-by: Conor Dooley Signed-off-by: Subhajit Ghosh Link: https://lore.kernel.org/r/20240309105031.10313-4-subhajit.ghosh@tweaklogic.com Signed-off-by: Jonathan Cameron --- Documentation/devicetree/bindings/iio/light/avago,apds9300.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/iio/light/avago,apds9300.yaml b/Documentation/devicetree/bindings/iio/light/avago,apds9300.yaml index a328c8a1daef..e07a074f6acf 100644 --- a/Documentation/devicetree/bindings/iio/light/avago,apds9300.yaml +++ b/Documentation/devicetree/bindings/iio/light/avago,apds9300.yaml @@ -35,6 +35,8 @@ required: examples: - | + #include + i2c { #address-cells = <1>; #size-cells = <0>; @@ -43,7 +45,7 @@ examples: compatible = "avago,apds9300"; reg = <0x39>; interrupt-parent = <&gpio2>; - interrupts = <29 8>; + interrupts = <29 IRQ_TYPE_LEVEL_LOW>; vdd-supply = <®ulator_3v3>; }; }; -- cgit v1.2.3-59-g8ed1b From f31f1f27b0e37badd68b68aa8b426108520cc814 Mon Sep 17 00:00:00 2001 From: Subhajit Ghosh Date: Sat, 9 Mar 2024 21:20:30 +1030 Subject: dt-bindings: iio: light: Avago APDS9306 Extend avago,apds9300.yaml schema file to support apds9306 device. Acked-by: Conor Dooley Signed-off-by: Subhajit Ghosh Link: https://lore.kernel.org/r/20240309105031.10313-5-subhajit.ghosh@tweaklogic.com Signed-off-by: Jonathan Cameron --- Documentation/devicetree/bindings/iio/light/avago,apds9300.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/iio/light/avago,apds9300.yaml b/Documentation/devicetree/bindings/iio/light/avago,apds9300.yaml index e07a074f6acf..b750096530bc 100644 --- a/Documentation/devicetree/bindings/iio/light/avago,apds9300.yaml +++ b/Documentation/devicetree/bindings/iio/light/avago,apds9300.yaml @@ -12,11 +12,13 @@ maintainers: description: | Datasheet: https://www.avagotech.com/docs/AV02-1077EN Datasheet: https://www.avagotech.com/docs/AV02-4191EN + Datasheet: https://www.avagotech.com/docs/AV02-4755EN properties: compatible: enum: - avago,apds9300 + - avago,apds9306 - avago,apds9960 reg: -- cgit v1.2.3-59-g8ed1b From 620d1e6c7a3fcc54c641f091e07b9040f13def19 Mon Sep 17 00:00:00 2001 From: Subhajit Ghosh Date: Sat, 9 Mar 2024 21:20:31 +1030 Subject: iio: light: Add support for APDS9306 Light Sensor Driver support for Avago (Broadcom) APDS9306 Ambient Light Sensor. It has two channels - ALS and CLEAR. The ALS (Ambient Light Sensor) channel approximates the response of the human-eye providing direct read out where the output count is proportional to ambient light levels. It is internally temperature compensated and rejects 50Hz and 60Hz flicker caused by artificial light sources. Hardware interrupt configuration is optional. It is a low power device with 20 bit resolution and has configurable adaptive interrupt mode and interrupt persistence mode. The device also features inbuilt hardware gain, multiple integration time selection options and sampling frequency selection options. This driver also uses the IIO GTS (Gain Time Scale) Helpers Namespace for Scales, Gains and Integration time implementation. Signed-off-by: Subhajit Ghosh Link: https://lore.kernel.org/r/20240309105031.10313-6-subhajit.ghosh@tweaklogic.com Signed-off-by: Jonathan Cameron --- drivers/iio/light/Kconfig | 12 + drivers/iio/light/Makefile | 1 + drivers/iio/light/apds9306.c | 1355 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1368 insertions(+) create mode 100644 drivers/iio/light/apds9306.c diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig index fd5a9879a582..9a587d403118 100644 --- a/drivers/iio/light/Kconfig +++ b/drivers/iio/light/Kconfig @@ -73,6 +73,18 @@ config APDS9300 To compile this driver as a module, choose M here: the module will be called apds9300. +config APDS9306 + tristate "Avago APDS9306 Ambient Light Sensor" + depends on I2C + select REGMAP_I2C + select IIO_GTS_HELPER + help + If you say Y or M here, you get support for Avago APDS9306 + Ambient Light Sensor. + + If built as a dynamically linked module, it will be called + apds9306. + config APDS9960 tristate "Avago APDS9960 gesture/RGB/ALS/proximity sensor" select REGMAP_I2C diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile index 2e5fdb33e0e9..a30f906e91ba 100644 --- a/drivers/iio/light/Makefile +++ b/drivers/iio/light/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_ADUX1020) += adux1020.o obj-$(CONFIG_AL3010) += al3010.o obj-$(CONFIG_AL3320A) += al3320a.o obj-$(CONFIG_APDS9300) += apds9300.o +obj-$(CONFIG_APDS9306) += apds9306.o obj-$(CONFIG_APDS9960) += apds9960.o obj-$(CONFIG_AS73211) += as73211.o obj-$(CONFIG_BH1750) += bh1750.o diff --git a/drivers/iio/light/apds9306.c b/drivers/iio/light/apds9306.c new file mode 100644 index 000000000000..4d8490602cd7 --- /dev/null +++ b/drivers/iio/light/apds9306.c @@ -0,0 +1,1355 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * APDS-9306/APDS-9306-065 Ambient Light Sensor + * I2C Address: 0x52 + * Datasheet: https://docs.broadcom.com/doc/AV02-4755EN + * + * Copyright (C) 2024 Subhajit Ghosh + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#define APDS9306_MAIN_CTRL_REG 0x00 +#define APDS9306_ALS_MEAS_RATE_REG 0x04 +#define APDS9306_ALS_GAIN_REG 0x05 +#define APDS9306_PART_ID_REG 0x06 +#define APDS9306_MAIN_STATUS_REG 0x07 +#define APDS9306_CLEAR_DATA_0_REG 0x0A +#define APDS9306_CLEAR_DATA_1_REG 0x0B +#define APDS9306_CLEAR_DATA_2_REG 0x0C +#define APDS9306_ALS_DATA_0_REG 0x0D +#define APDS9306_ALS_DATA_1_REG 0x0E +#define APDS9306_ALS_DATA_2_REG 0x0F +#define APDS9306_INT_CFG_REG 0x19 +#define APDS9306_INT_PERSISTENCE_REG 0x1A +#define APDS9306_ALS_THRES_UP_0_REG 0x21 +#define APDS9306_ALS_THRES_UP_1_REG 0x22 +#define APDS9306_ALS_THRES_UP_2_REG 0x23 +#define APDS9306_ALS_THRES_LOW_0_REG 0x24 +#define APDS9306_ALS_THRES_LOW_1_REG 0x25 +#define APDS9306_ALS_THRES_LOW_2_REG 0x26 +#define APDS9306_ALS_THRES_VAR_REG 0x27 + +#define APDS9306_ALS_INT_STAT_MASK BIT(4) +#define APDS9306_ALS_DATA_STAT_MASK BIT(3) + +#define APDS9306_ALS_THRES_VAL_MAX (BIT(20) - 1) +#define APDS9306_ALS_THRES_VAR_VAL_MAX (BIT(3) - 1) +#define APDS9306_ALS_PERSIST_VAL_MAX (BIT(4) - 1) +#define APDS9306_ALS_READ_DATA_DELAY_US (20 * USEC_PER_MSEC) +#define APDS9306_NUM_REPEAT_RATES 7 +#define APDS9306_INT_SRC_CLEAR 0 +#define APDS9306_INT_SRC_ALS 1 +#define APDS9306_SAMP_FREQ_10HZ 0 + +/** + * struct part_id_gts_multiplier - Part no. and corresponding gts multiplier + * + * GTS (Gain Time Scale) are helper functions for Light sensors which along + * with hardware gains also has gains associated with Integration times. + * + * There are two variants of the device with slightly different characteristics, + * they have same ADC count for different Lux levels as mentioned in the + * datasheet. This multiplier array is used to store the derived Lux per count + * value for the two variants to be used by the GTS helper functions. + * + * @part_id: Part ID of the device + * @max_scale_int: Multiplier for iio_init_iio_gts() + * @max_scale_nano: Multiplier for iio_init_iio_gts() + */ +struct part_id_gts_multiplier { + int part_id; + int max_scale_int; + int max_scale_nano; +}; + +/* + * As per the datasheet, at HW Gain = 3x, Integration time 100mS (32x), + * typical 2000 ADC counts are observed for 49.8 uW per sq cm (340.134 lux) + * for apds9306 and 43 uW per sq cm (293.69 lux) for apds9306-065. + * Assuming lux per count is linear across all integration time ranges. + * + * Lux = (raw + offset) * scale; offset can be any value by userspace. + * HG = Hardware Gain; ITG = Gain by changing integration time. + * Scale table by IIO GTS Helpers = (1 / HG) * (1 / ITG) * Multiplier. + * + * The Lux values provided in the datasheet are at ITG=32x and HG=3x, + * at typical 2000 count for both variants of the device. + * + * Lux per ADC count at 3x and 32x for apds9306 = 340.134 / 2000 + * Lux per ADC count at 3x and 32x for apds9306-065 = 293.69 / 2000 + * + * The Multiplier for the scale table provided to userspace: + * IIO GTS scale Multiplier for apds9306 = (340.134 / 2000) * 32 * 3 = 16.326432 + * and for apds9306-065 = (293.69 / 2000) * 32 * 3 = 14.09712 + */ +static const struct part_id_gts_multiplier apds9306_gts_mul[] = { + { + .part_id = 0xB1, + .max_scale_int = 16, + .max_scale_nano = 3264320, + }, { + .part_id = 0xB3, + .max_scale_int = 14, + .max_scale_nano = 9712000, + }, +}; + +static const int apds9306_repeat_rate_freq[APDS9306_NUM_REPEAT_RATES][2] = { + { 40, 0 }, + { 20, 0 }, + { 10, 0 }, + { 5, 0 }, + { 2, 0 }, + { 1, 0 }, + { 0, 500000 }, +}; + +static const int apds9306_repeat_rate_period[APDS9306_NUM_REPEAT_RATES] = { + 25000, 50000, 100000, 200000, 500000, 1000000, 2000000, +}; + +/** + * struct apds9306_regfields - apds9306 regmap fields definitions + * + * @sw_reset: Software reset regfield + * @en: Enable regfield + * @intg_time: Resolution regfield + * @repeat_rate: Measurement Rate regfield + * @gain: Hardware gain regfield + * @int_src: Interrupt channel regfield + * @int_thresh_var_en: Interrupt variance threshold regfield + * @int_en: Interrupt enable regfield + * @int_persist_val: Interrupt persistence regfield + * @int_thresh_var_val: Interrupt threshold variance value regfield + */ +struct apds9306_regfields { + struct regmap_field *sw_reset; + struct regmap_field *en; + struct regmap_field *intg_time; + struct regmap_field *repeat_rate; + struct regmap_field *gain; + struct regmap_field *int_src; + struct regmap_field *int_thresh_var_en; + struct regmap_field *int_en; + struct regmap_field *int_persist_val; + struct regmap_field *int_thresh_var_val; +}; + +/** + * struct apds9306_data - apds9306 private data and registers definitions + * + * @dev: Pointer to the device structure + * @gts: IIO Gain Time Scale structure + * @mutex: Lock for protecting adc reads, device settings changes where + * some calculations are required before or after setting or + * getting the raw settings values from regmap writes or reads + * respectively. + * @regmap: Regmap structure pointer + * @rf: Regmap register fields structure + * @nlux_per_count: Nano lux per ADC count for a particular model + * @read_data_available: Flag set by IRQ handler for ADC data available + */ +struct apds9306_data { + struct device *dev; + struct iio_gts gts; + + struct mutex mutex; + + struct regmap *regmap; + struct apds9306_regfields rf; + + int nlux_per_count; + int read_data_available; +}; + +/* + * Available scales with gain 1x - 18x, timings 3.125, 25, 50, 100, 200, 400 ms + * Time impacts to gain: 1x, 8x, 16x, 32x, 64x, 128x + */ +#define APDS9306_GSEL_1X 0x00 +#define APDS9306_GSEL_3X 0x01 +#define APDS9306_GSEL_6X 0x02 +#define APDS9306_GSEL_9X 0x03 +#define APDS9306_GSEL_18X 0x04 + +static const struct iio_gain_sel_pair apds9306_gains[] = { + GAIN_SCALE_GAIN(1, APDS9306_GSEL_1X), + GAIN_SCALE_GAIN(3, APDS9306_GSEL_3X), + GAIN_SCALE_GAIN(6, APDS9306_GSEL_6X), + GAIN_SCALE_GAIN(9, APDS9306_GSEL_9X), + GAIN_SCALE_GAIN(18, APDS9306_GSEL_18X), +}; + +#define APDS9306_MEAS_MODE_400MS 0x00 +#define APDS9306_MEAS_MODE_200MS 0x01 +#define APDS9306_MEAS_MODE_100MS 0x02 +#define APDS9306_MEAS_MODE_50MS 0x03 +#define APDS9306_MEAS_MODE_25MS 0x04 +#define APDS9306_MEAS_MODE_3125US 0x05 + +static const struct iio_itime_sel_mul apds9306_itimes[] = { + GAIN_SCALE_ITIME_US(400000, APDS9306_MEAS_MODE_400MS, BIT(7)), + GAIN_SCALE_ITIME_US(200000, APDS9306_MEAS_MODE_200MS, BIT(6)), + GAIN_SCALE_ITIME_US(100000, APDS9306_MEAS_MODE_100MS, BIT(5)), + GAIN_SCALE_ITIME_US(50000, APDS9306_MEAS_MODE_50MS, BIT(4)), + GAIN_SCALE_ITIME_US(25000, APDS9306_MEAS_MODE_25MS, BIT(3)), + GAIN_SCALE_ITIME_US(3125, APDS9306_MEAS_MODE_3125US, BIT(0)), +}; + +static const struct iio_event_spec apds9306_event_spec[] = { + { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_RISING, + .mask_shared_by_all = BIT(IIO_EV_INFO_VALUE), + }, { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_FALLING, + .mask_shared_by_all = BIT(IIO_EV_INFO_VALUE), + }, { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_EITHER, + .mask_shared_by_all = BIT(IIO_EV_INFO_PERIOD), + .mask_separate = BIT(IIO_EV_INFO_ENABLE), + }, { + .type = IIO_EV_TYPE_THRESH_ADAPTIVE, + .mask_shared_by_all = BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_ENABLE), + }, +}; + +static const struct iio_chan_spec apds9306_channels_with_events[] = { + { + .type = IIO_LIGHT, + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME) | + BIT(IIO_CHAN_INFO_SAMP_FREQ), + .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME) | + BIT(IIO_CHAN_INFO_SAMP_FREQ), + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE), + .info_mask_separate_available = BIT(IIO_CHAN_INFO_SCALE), + .event_spec = apds9306_event_spec, + .num_event_specs = ARRAY_SIZE(apds9306_event_spec), + }, { + .type = IIO_INTENSITY, + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME) | + BIT(IIO_CHAN_INFO_SAMP_FREQ), + .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME) | + BIT(IIO_CHAN_INFO_SAMP_FREQ), + .channel2 = IIO_MOD_LIGHT_CLEAR, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .modified = 1, + .event_spec = apds9306_event_spec, + .num_event_specs = ARRAY_SIZE(apds9306_event_spec), + }, +}; + +static const struct iio_chan_spec apds9306_channels_without_events[] = { + { + .type = IIO_LIGHT, + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME) | + BIT(IIO_CHAN_INFO_SAMP_FREQ), + .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME) | + BIT(IIO_CHAN_INFO_SAMP_FREQ), + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE), + .info_mask_separate_available = BIT(IIO_CHAN_INFO_SCALE), + }, { + .type = IIO_INTENSITY, + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME) | + BIT(IIO_CHAN_INFO_SAMP_FREQ), + .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME) | + BIT(IIO_CHAN_INFO_SAMP_FREQ), + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .modified = 1, + .channel2 = IIO_MOD_LIGHT_CLEAR, + }, +}; + +/* INT_PERSISTENCE available */ +static IIO_CONST_ATTR(thresh_either_period_available, "[0 1 15]"); + +/* ALS_THRESH_VAR available */ +static IIO_CONST_ATTR(thresh_adaptive_either_values_available, "[0 1 7]"); + +static struct attribute *apds9306_event_attributes[] = { + &iio_const_attr_thresh_either_period_available.dev_attr.attr, + &iio_const_attr_thresh_adaptive_either_values_available.dev_attr.attr, + NULL +}; + +static const struct attribute_group apds9306_event_attr_group = { + .attrs = apds9306_event_attributes, +}; + +static const struct regmap_range apds9306_readable_ranges[] = { + regmap_reg_range(APDS9306_MAIN_CTRL_REG, APDS9306_ALS_THRES_VAR_REG) +}; + +static const struct regmap_range apds9306_writable_ranges[] = { + regmap_reg_range(APDS9306_MAIN_CTRL_REG, APDS9306_ALS_GAIN_REG), + regmap_reg_range(APDS9306_INT_CFG_REG, APDS9306_ALS_THRES_VAR_REG) +}; + +static const struct regmap_range apds9306_volatile_ranges[] = { + regmap_reg_range(APDS9306_MAIN_STATUS_REG, APDS9306_MAIN_STATUS_REG), + regmap_reg_range(APDS9306_CLEAR_DATA_0_REG, APDS9306_ALS_DATA_2_REG) +}; + +static const struct regmap_range apds9306_precious_ranges[] = { + regmap_reg_range(APDS9306_MAIN_STATUS_REG, APDS9306_MAIN_STATUS_REG) +}; + +static const struct regmap_access_table apds9306_readable_table = { + .yes_ranges = apds9306_readable_ranges, + .n_yes_ranges = ARRAY_SIZE(apds9306_readable_ranges) +}; + +static const struct regmap_access_table apds9306_writable_table = { + .yes_ranges = apds9306_writable_ranges, + .n_yes_ranges = ARRAY_SIZE(apds9306_writable_ranges) +}; + +static const struct regmap_access_table apds9306_volatile_table = { + .yes_ranges = apds9306_volatile_ranges, + .n_yes_ranges = ARRAY_SIZE(apds9306_volatile_ranges) +}; + +static const struct regmap_access_table apds9306_precious_table = { + .yes_ranges = apds9306_precious_ranges, + .n_yes_ranges = ARRAY_SIZE(apds9306_precious_ranges) +}; + +static const struct regmap_config apds9306_regmap = { + .name = "apds9306_regmap", + .reg_bits = 8, + .val_bits = 8, + .rd_table = &apds9306_readable_table, + .wr_table = &apds9306_writable_table, + .volatile_table = &apds9306_volatile_table, + .precious_table = &apds9306_precious_table, + .max_register = APDS9306_ALS_THRES_VAR_REG, + .cache_type = REGCACHE_RBTREE, +}; + +static const struct reg_field apds9306_rf_sw_reset = + REG_FIELD(APDS9306_MAIN_CTRL_REG, 4, 4); + +static const struct reg_field apds9306_rf_en = + REG_FIELD(APDS9306_MAIN_CTRL_REG, 1, 1); + +static const struct reg_field apds9306_rf_intg_time = + REG_FIELD(APDS9306_ALS_MEAS_RATE_REG, 4, 6); + +static const struct reg_field apds9306_rf_repeat_rate = + REG_FIELD(APDS9306_ALS_MEAS_RATE_REG, 0, 2); + +static const struct reg_field apds9306_rf_gain = + REG_FIELD(APDS9306_ALS_GAIN_REG, 0, 2); + +static const struct reg_field apds9306_rf_int_src = + REG_FIELD(APDS9306_INT_CFG_REG, 4, 5); + +static const struct reg_field apds9306_rf_int_thresh_var_en = + REG_FIELD(APDS9306_INT_CFG_REG, 3, 3); + +static const struct reg_field apds9306_rf_int_en = + REG_FIELD(APDS9306_INT_CFG_REG, 2, 2); + +static const struct reg_field apds9306_rf_int_persist_val = + REG_FIELD(APDS9306_INT_PERSISTENCE_REG, 4, 7); + +static const struct reg_field apds9306_rf_int_thresh_var_val = + REG_FIELD(APDS9306_ALS_THRES_VAR_REG, 0, 2); + +static int apds9306_regfield_init(struct apds9306_data *data) +{ + struct device *dev = data->dev; + struct regmap *regmap = data->regmap; + struct regmap_field *tmp; + struct apds9306_regfields *rf = &data->rf; + + tmp = devm_regmap_field_alloc(dev, regmap, apds9306_rf_sw_reset); + if (IS_ERR(tmp)) + return PTR_ERR(tmp); + rf->sw_reset = tmp; + + tmp = devm_regmap_field_alloc(dev, regmap, apds9306_rf_en); + if (IS_ERR(tmp)) + return PTR_ERR(tmp); + rf->en = tmp; + + tmp = devm_regmap_field_alloc(dev, regmap, apds9306_rf_intg_time); + if (IS_ERR(tmp)) + return PTR_ERR(tmp); + rf->intg_time = tmp; + + tmp = devm_regmap_field_alloc(dev, regmap, apds9306_rf_repeat_rate); + if (IS_ERR(tmp)) + return PTR_ERR(tmp); + rf->repeat_rate = tmp; + + tmp = devm_regmap_field_alloc(dev, regmap, apds9306_rf_gain); + if (IS_ERR(tmp)) + return PTR_ERR(tmp); + rf->gain = tmp; + + tmp = devm_regmap_field_alloc(dev, regmap, apds9306_rf_int_src); + if (IS_ERR(tmp)) + return PTR_ERR(tmp); + rf->int_src = tmp; + + tmp = devm_regmap_field_alloc(dev, regmap, apds9306_rf_int_thresh_var_en); + if (IS_ERR(tmp)) + return PTR_ERR(tmp); + rf->int_thresh_var_en = tmp; + + tmp = devm_regmap_field_alloc(dev, regmap, apds9306_rf_int_en); + if (IS_ERR(tmp)) + return PTR_ERR(tmp); + rf->int_en = tmp; + + tmp = devm_regmap_field_alloc(dev, regmap, apds9306_rf_int_persist_val); + if (IS_ERR(tmp)) + return PTR_ERR(tmp); + rf->int_persist_val = tmp; + + tmp = devm_regmap_field_alloc(dev, regmap, apds9306_rf_int_thresh_var_val); + if (IS_ERR(tmp)) + return PTR_ERR(tmp); + rf->int_thresh_var_val = tmp; + + return 0; +} + +static int apds9306_power_state(struct apds9306_data *data, bool state) +{ + struct apds9306_regfields *rf = &data->rf; + int ret; + + /* Reset not included as it causes ugly I2C bus error */ + if (state) { + ret = regmap_field_write(rf->en, 1); + if (ret) + return ret; + /* 5ms wake up time */ + fsleep(5000); + return 0; + } + + return regmap_field_write(rf->en, 0); +} + +static int apds9306_read_data(struct apds9306_data *data, int *val, int reg) +{ + struct device *dev = data->dev; + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct apds9306_regfields *rf = &data->rf; + u64 ev_code; + int ret, delay, intg_time, intg_time_idx, repeat_rate_idx, int_src; + int status = 0; + u8 buff[3]; + + ret = pm_runtime_resume_and_get(data->dev); + if (ret) + return ret; + + ret = regmap_field_read(rf->intg_time, &intg_time_idx); + if (ret) + return ret; + + ret = regmap_field_read(rf->repeat_rate, &repeat_rate_idx); + if (ret) + return ret; + + ret = regmap_field_read(rf->int_src, &int_src); + if (ret) + return ret; + + intg_time = iio_gts_find_int_time_by_sel(&data->gts, intg_time_idx); + if (intg_time < 0) + return intg_time; + + /* Whichever is greater - integration time period or sampling period. */ + delay = max(intg_time, apds9306_repeat_rate_period[repeat_rate_idx]); + + /* + * Clear stale data flag that might have been set by the interrupt + * handler if it got data available flag set in the status reg. + */ + data->read_data_available = 0; + + /* + * If this function runs parallel with the interrupt handler, either + * this reads and clears the status registers or the interrupt handler + * does. The interrupt handler sets a flag for read data available + * in our private structure which we read here. + */ + ret = regmap_read_poll_timeout(data->regmap, APDS9306_MAIN_STATUS_REG, + status, data->read_data_available || + (status & (APDS9306_ALS_DATA_STAT_MASK | + APDS9306_ALS_INT_STAT_MASK)), + APDS9306_ALS_READ_DATA_DELAY_US, delay * 2); + if (ret) + return ret; + + /* If we reach here before the interrupt handler we push an event */ + if ((status & APDS9306_ALS_INT_STAT_MASK)) { + if (int_src == APDS9306_INT_SRC_ALS) + ev_code = IIO_UNMOD_EVENT_CODE(IIO_LIGHT, 0, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_EITHER); + else + ev_code = IIO_MOD_EVENT_CODE(IIO_INTENSITY, 0, + IIO_MOD_LIGHT_CLEAR, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_EITHER); + + iio_push_event(indio_dev, ev_code, iio_get_time_ns(indio_dev)); + } + + ret = regmap_bulk_read(data->regmap, reg, buff, sizeof(buff)); + if (ret) { + dev_err_ratelimited(dev, "read data failed\n"); + return ret; + } + + *val = get_unaligned_le24(&buff); + + pm_runtime_mark_last_busy(data->dev); + pm_runtime_put_autosuspend(data->dev); + + return 0; +} + +static int apds9306_intg_time_get(struct apds9306_data *data, int *val2) +{ + struct apds9306_regfields *rf = &data->rf; + int ret, intg_time_idx; + + ret = regmap_field_read(rf->intg_time, &intg_time_idx); + if (ret) + return ret; + + ret = iio_gts_find_int_time_by_sel(&data->gts, intg_time_idx); + if (ret < 0) + return ret; + + *val2 = ret; + + return 0; +} + +static int apds9306_intg_time_set(struct apds9306_data *data, int val2) +{ + struct device *dev = data->dev; + struct apds9306_regfields *rf = &data->rf; + int ret, intg_old, gain_old, gain_new, gain_new_closest, intg_time_idx; + int gain_idx; + bool ok; + + if (!iio_gts_valid_time(&data->gts, val2)) { + dev_err_ratelimited(dev, "Unsupported integration time %u\n", val2); + return -EINVAL; + } + + ret = regmap_field_read(rf->intg_time, &intg_time_idx); + if (ret) + return ret; + + ret = regmap_field_read(rf->gain, &gain_idx); + if (ret) + return ret; + + intg_old = iio_gts_find_int_time_by_sel(&data->gts, intg_time_idx); + if (ret < 0) + return ret; + + if (intg_old == val2) + return 0; + + gain_old = iio_gts_find_gain_by_sel(&data->gts, gain_idx); + if (gain_old < 0) + return gain_old; + + iio_gts_find_new_gain_by_old_gain_time(&data->gts, gain_old, intg_old, + val2, &gain_new); + + if (gain_new < 0) { + dev_err_ratelimited(dev, "Unsupported gain with time\n"); + return gain_new; + } + + gain_new_closest = iio_find_closest_gain_low(&data->gts, gain_new, &ok); + if (gain_new_closest < 0) { + gain_new_closest = iio_gts_get_min_gain(&data->gts); + if (gain_new_closest < 0) + return gain_new_closest; + } + if (!ok) + dev_dbg(dev, "Unable to find optimum gain, setting minimum"); + + ret = iio_gts_find_sel_by_int_time(&data->gts, val2); + if (ret < 0) + return ret; + + ret = regmap_field_write(rf->intg_time, ret); + if (ret) + return ret; + + ret = iio_gts_find_sel_by_gain(&data->gts, gain_new_closest); + if (ret < 0) + return ret; + + return regmap_field_write(rf->gain, ret); +} + +static int apds9306_sampling_freq_get(struct apds9306_data *data, int *val, + int *val2) +{ + struct apds9306_regfields *rf = &data->rf; + int ret, repeat_rate_idx; + + ret = regmap_field_read(rf->repeat_rate, &repeat_rate_idx); + if (ret) + return ret; + + if (repeat_rate_idx > ARRAY_SIZE(apds9306_repeat_rate_freq)) + return -EINVAL; + + *val = apds9306_repeat_rate_freq[repeat_rate_idx][0]; + *val2 = apds9306_repeat_rate_freq[repeat_rate_idx][1]; + + return 0; +} + +static int apds9306_sampling_freq_set(struct apds9306_data *data, int val, + int val2) +{ + struct apds9306_regfields *rf = &data->rf; + int i; + + for (i = 0; i < ARRAY_SIZE(apds9306_repeat_rate_freq); i++) { + if (apds9306_repeat_rate_freq[i][0] == val && + apds9306_repeat_rate_freq[i][1] == val2) + return regmap_field_write(rf->repeat_rate, i); + } + + return -EINVAL; +} + +static int apds9306_scale_get(struct apds9306_data *data, int *val, int *val2) +{ + struct apds9306_regfields *rf = &data->rf; + int gain, intg, ret, intg_time_idx, gain_idx; + + ret = regmap_field_read(rf->gain, &gain_idx); + if (ret) + return ret; + + ret = regmap_field_read(rf->intg_time, &intg_time_idx); + if (ret) + return ret; + + gain = iio_gts_find_gain_by_sel(&data->gts, gain_idx); + if (gain < 0) + return gain; + + intg = iio_gts_find_int_time_by_sel(&data->gts, intg_time_idx); + if (intg < 0) + return intg; + + return iio_gts_get_scale(&data->gts, gain, intg, val, val2); +} + +static int apds9306_scale_set(struct apds9306_data *data, int val, int val2) +{ + struct apds9306_regfields *rf = &data->rf; + int i, ret, time_sel, gain_sel, intg_time_idx; + + ret = regmap_field_read(rf->intg_time, &intg_time_idx); + if (ret) + return ret; + + ret = iio_gts_find_gain_sel_for_scale_using_time(&data->gts, + intg_time_idx, val, val2, &gain_sel); + if (ret) { + for (i = 0; i < data->gts.num_itime; i++) { + time_sel = data->gts.itime_table[i].sel; + + if (time_sel == intg_time_idx) + continue; + + ret = iio_gts_find_gain_sel_for_scale_using_time(&data->gts, + time_sel, val, val2, &gain_sel); + if (!ret) + break; + } + if (ret) + return -EINVAL; + + ret = regmap_field_write(rf->intg_time, time_sel); + if (ret) + return ret; + } + + return regmap_field_write(rf->gain, gain_sel); +} + +static int apds9306_event_period_get(struct apds9306_data *data, int *val) +{ + struct apds9306_regfields *rf = &data->rf; + int period, ret; + + ret = regmap_field_read(rf->int_persist_val, &period); + if (ret) + return ret; + + if (!in_range(period, 0, APDS9306_ALS_PERSIST_VAL_MAX)) + return -EINVAL; + + *val = period; + + return ret; +} + +static int apds9306_event_period_set(struct apds9306_data *data, int val) +{ + struct apds9306_regfields *rf = &data->rf; + + if (!in_range(val, 0, APDS9306_ALS_PERSIST_VAL_MAX)) + return -EINVAL; + + return regmap_field_write(rf->int_persist_val, val); +} + +static int apds9306_event_thresh_get(struct apds9306_data *data, int dir, + int *val) +{ + int var, ret; + u8 buff[3]; + + if (dir == IIO_EV_DIR_RISING) + var = APDS9306_ALS_THRES_UP_0_REG; + else if (dir == IIO_EV_DIR_FALLING) + var = APDS9306_ALS_THRES_LOW_0_REG; + else + return -EINVAL; + + ret = regmap_bulk_read(data->regmap, var, buff, sizeof(buff)); + if (ret) + return ret; + + *val = get_unaligned_le24(&buff); + + return 0; +} + +static int apds9306_event_thresh_set(struct apds9306_data *data, int dir, + int val) +{ + int var; + u8 buff[3]; + + if (dir == IIO_EV_DIR_RISING) + var = APDS9306_ALS_THRES_UP_0_REG; + else if (dir == IIO_EV_DIR_FALLING) + var = APDS9306_ALS_THRES_LOW_0_REG; + else + return -EINVAL; + + if (!in_range(val, 0, APDS9306_ALS_THRES_VAL_MAX)) + return -EINVAL; + + put_unaligned_le24(val, buff); + + return regmap_bulk_write(data->regmap, var, buff, sizeof(buff)); +} + +static int apds9306_event_thresh_adaptive_get(struct apds9306_data *data, int *val) +{ + struct apds9306_regfields *rf = &data->rf; + int thr_adpt, ret; + + ret = regmap_field_read(rf->int_thresh_var_val, &thr_adpt); + if (ret) + return ret; + + if (!in_range(thr_adpt, 0, APDS9306_ALS_THRES_VAR_VAL_MAX)) + return -EINVAL; + + *val = thr_adpt; + + return ret; +} + +static int apds9306_event_thresh_adaptive_set(struct apds9306_data *data, int val) +{ + struct apds9306_regfields *rf = &data->rf; + + if (!in_range(val, 0, APDS9306_ALS_THRES_VAR_VAL_MAX)) + return -EINVAL; + + return regmap_field_write(rf->int_thresh_var_val, val); +} + +static int apds9306_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val, + int *val2, long mask) +{ + struct apds9306_data *data = iio_priv(indio_dev); + int ret, reg; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + if (chan->channel2 == IIO_MOD_LIGHT_CLEAR) + reg = APDS9306_CLEAR_DATA_0_REG; + else + reg = APDS9306_ALS_DATA_0_REG; + /* + * Changing device parameters during adc operation, resets + * the ADC which has to avoided. + */ + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + return ret; + ret = apds9306_read_data(data, val, reg); + iio_device_release_direct_mode(indio_dev); + if (ret) + return ret; + + return IIO_VAL_INT; + case IIO_CHAN_INFO_INT_TIME: + ret = apds9306_intg_time_get(data, val2); + if (ret) + return ret; + *val = 0; + + return IIO_VAL_INT_PLUS_MICRO; + case IIO_CHAN_INFO_SAMP_FREQ: + ret = apds9306_sampling_freq_get(data, val, val2); + if (ret) + return ret; + + return IIO_VAL_INT_PLUS_MICRO; + case IIO_CHAN_INFO_SCALE: + ret = apds9306_scale_get(data, val, val2); + if (ret) + return ret; + + return IIO_VAL_INT_PLUS_NANO; + default: + return -EINVAL; + } +}; + +static int apds9306_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, + long mask) +{ + struct apds9306_data *data = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_INT_TIME: + return iio_gts_avail_times(&data->gts, vals, type, length); + case IIO_CHAN_INFO_SCALE: + return iio_gts_all_avail_scales(&data->gts, vals, type, length); + case IIO_CHAN_INFO_SAMP_FREQ: + *length = ARRAY_SIZE(apds9306_repeat_rate_freq) * 2; + *vals = (const int *)apds9306_repeat_rate_freq; + *type = IIO_VAL_INT_PLUS_MICRO; + + return IIO_AVAIL_LIST; + default: + return -EINVAL; + } +} + +static int apds9306_write_raw_get_fmt(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + long mask) +{ + switch (mask) { + case IIO_CHAN_INFO_SCALE: + return IIO_VAL_INT_PLUS_NANO; + case IIO_CHAN_INFO_INT_TIME: + return IIO_VAL_INT_PLUS_MICRO; + case IIO_CHAN_INFO_SAMP_FREQ: + return IIO_VAL_INT_PLUS_MICRO; + default: + return -EINVAL; + } +} + +static int apds9306_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int val, + int val2, long mask) +{ + struct apds9306_data *data = iio_priv(indio_dev); + + guard(mutex)(&data->mutex); + + switch (mask) { + case IIO_CHAN_INFO_INT_TIME: + if (val) + return -EINVAL; + return apds9306_intg_time_set(data, val2); + case IIO_CHAN_INFO_SCALE: + return apds9306_scale_set(data, val, val2); + case IIO_CHAN_INFO_SAMP_FREQ: + return apds9306_sampling_freq_set(data, val, val2); + default: + return -EINVAL; + } +} + +static irqreturn_t apds9306_irq_handler(int irq, void *priv) +{ + struct iio_dev *indio_dev = priv; + struct apds9306_data *data = iio_priv(indio_dev); + struct apds9306_regfields *rf = &data->rf; + u64 ev_code; + int ret, status, int_src; + + /* + * The interrupt line is released and the interrupt flag is + * cleared as a result of reading the status register. All the + * status flags are cleared as a result of this read. + */ + ret = regmap_read(data->regmap, APDS9306_MAIN_STATUS_REG, &status); + if (ret < 0) { + dev_err_ratelimited(data->dev, "status reg read failed\n"); + return IRQ_HANDLED; + } + + ret = regmap_field_read(rf->int_src, &int_src); + if (ret) + return ret; + + if ((status & APDS9306_ALS_INT_STAT_MASK)) { + if (int_src == APDS9306_INT_SRC_ALS) + ev_code = IIO_UNMOD_EVENT_CODE(IIO_LIGHT, 0, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_EITHER); + else + ev_code = IIO_MOD_EVENT_CODE(IIO_INTENSITY, 0, + IIO_MOD_LIGHT_CLEAR, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_EITHER); + + iio_push_event(indio_dev, ev_code, iio_get_time_ns(indio_dev)); + } + + /* + * If a one-shot read through sysfs is underway at the same time + * as this interrupt handler is executing and a read data available + * flag was set, this flag is set to inform read_poll_timeout() + * to exit. + */ + if ((status & APDS9306_ALS_DATA_STAT_MASK)) + data->read_data_available = 1; + + return IRQ_HANDLED; +} + +static int apds9306_read_event(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int *val, int *val2) +{ + struct apds9306_data *data = iio_priv(indio_dev); + int ret; + + switch (type) { + case IIO_EV_TYPE_THRESH: + if (dir == IIO_EV_DIR_EITHER && info == IIO_EV_INFO_PERIOD) + ret = apds9306_event_period_get(data, val); + else + ret = apds9306_event_thresh_get(data, dir, val); + if (ret) + return ret; + + return IIO_VAL_INT; + case IIO_EV_TYPE_THRESH_ADAPTIVE: + ret = apds9306_event_thresh_adaptive_get(data, val); + if (ret) + return ret; + + return IIO_VAL_INT; + default: + return -EINVAL; + } +} + +static int apds9306_write_event(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int val, int val2) +{ + struct apds9306_data *data = iio_priv(indio_dev); + + switch (type) { + case IIO_EV_TYPE_THRESH: + if (dir == IIO_EV_DIR_EITHER && info == IIO_EV_INFO_PERIOD) + return apds9306_event_period_set(data, val); + + return apds9306_event_thresh_set(data, dir, val); + case IIO_EV_TYPE_THRESH_ADAPTIVE: + return apds9306_event_thresh_adaptive_set(data, val); + default: + return -EINVAL; + } +} + +static int apds9306_read_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir) +{ + struct apds9306_data *data = iio_priv(indio_dev); + struct apds9306_regfields *rf = &data->rf; + int int_en, int_src, ret; + + switch (type) { + case IIO_EV_TYPE_THRESH: { + guard(mutex)(&data->mutex); + + ret = regmap_field_read(rf->int_src, &int_src); + if (ret) + return ret; + + ret = regmap_field_read(rf->int_en, &int_en); + if (ret) + return ret; + + if (chan->type == IIO_LIGHT) + return int_en && (int_src == APDS9306_INT_SRC_ALS); + + if (chan->type == IIO_INTENSITY) + return int_en && (int_src == APDS9306_INT_SRC_CLEAR); + + return -EINVAL; + } + case IIO_EV_TYPE_THRESH_ADAPTIVE: + ret = regmap_field_read(rf->int_thresh_var_en, &int_en); + if (ret) + return ret; + + return int_en; + default: + return -EINVAL; + } +} + +static int apds9306_write_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + int state) +{ + struct apds9306_data *data = iio_priv(indio_dev); + struct apds9306_regfields *rf = &data->rf; + int ret, val; + + state = !!state; + + switch (type) { + case IIO_EV_TYPE_THRESH: { + guard(mutex)(&data->mutex); + + /* + * If interrupt is enabled, the channel is set before enabling + * the interrupt. In case of disable, no need to switch + * channels. In case of different channel is selected while + * interrupt in on, just change the channel. + */ + if (state) { + if (chan->type == IIO_LIGHT) + val = 1; + else if (chan->type == IIO_INTENSITY) + val = 0; + else + return -EINVAL; + + ret = regmap_field_write(rf->int_src, val); + if (ret) + return ret; + } + + ret = regmap_field_read(rf->int_en, &val); + if (ret) + return ret; + + if (val == state) + return 0; + + ret = regmap_field_write(rf->int_en, state); + if (ret) + return ret; + + if (state) + return pm_runtime_resume_and_get(data->dev); + + pm_runtime_mark_last_busy(data->dev); + pm_runtime_put_autosuspend(data->dev); + + return 0; + } + case IIO_EV_TYPE_THRESH_ADAPTIVE: + return regmap_field_write(rf->int_thresh_var_en, state); + default: + return -EINVAL; + } +} + +static const struct iio_info apds9306_info_no_events = { + .read_avail = apds9306_read_avail, + .read_raw = apds9306_read_raw, + .write_raw = apds9306_write_raw, + .write_raw_get_fmt = apds9306_write_raw_get_fmt, +}; + +static const struct iio_info apds9306_info = { + .read_avail = apds9306_read_avail, + .read_raw = apds9306_read_raw, + .write_raw = apds9306_write_raw, + .write_raw_get_fmt = apds9306_write_raw_get_fmt, + .read_event_value = apds9306_read_event, + .write_event_value = apds9306_write_event, + .read_event_config = apds9306_read_event_config, + .write_event_config = apds9306_write_event_config, + .event_attrs = &apds9306_event_attr_group, +}; + +static int apds9306_init_iio_gts(struct apds9306_data *data) +{ + int i, ret, part_id; + + ret = regmap_read(data->regmap, APDS9306_PART_ID_REG, &part_id); + if (ret) + return ret; + + for (i = 0; i < ARRAY_SIZE(apds9306_gts_mul); i++) + if (part_id == apds9306_gts_mul[i].part_id) + break; + + if (i == ARRAY_SIZE(apds9306_gts_mul)) + return -ENOENT; + + return devm_iio_init_iio_gts(data->dev, + apds9306_gts_mul[i].max_scale_int, + apds9306_gts_mul[i].max_scale_nano, + apds9306_gains, ARRAY_SIZE(apds9306_gains), + apds9306_itimes, ARRAY_SIZE(apds9306_itimes), + &data->gts); +} + +static void apds9306_powerdown(void *ptr) +{ + struct apds9306_data *data = (struct apds9306_data *)ptr; + struct apds9306_regfields *rf = &data->rf; + int ret; + + ret = regmap_field_write(rf->int_thresh_var_en, 0); + if (ret) + return; + + ret = regmap_field_write(rf->int_en, 0); + if (ret) + return; + + apds9306_power_state(data, false); +} + +static int apds9306_device_init(struct apds9306_data *data) +{ + struct apds9306_regfields *rf = &data->rf; + int ret; + + ret = apds9306_init_iio_gts(data); + if (ret) + return ret; + + ret = regmap_field_write(rf->intg_time, APDS9306_MEAS_MODE_100MS); + if (ret) + return ret; + + ret = regmap_field_write(rf->repeat_rate, APDS9306_SAMP_FREQ_10HZ); + if (ret) + return ret; + + ret = regmap_field_write(rf->gain, APDS9306_GSEL_3X); + if (ret) + return ret; + + ret = regmap_field_write(rf->int_src, APDS9306_INT_SRC_ALS); + if (ret) + return ret; + + ret = regmap_field_write(rf->int_en, 0); + if (ret) + return ret; + + return regmap_field_write(rf->int_thresh_var_en, 0); +} + +static int apds9306_pm_init(struct apds9306_data *data) +{ + struct device *dev = data->dev; + int ret; + + ret = apds9306_power_state(data, true); + if (ret) + return ret; + + ret = pm_runtime_set_active(dev); + if (ret) + return ret; + + ret = devm_pm_runtime_enable(dev); + if (ret) + return ret; + + pm_runtime_set_autosuspend_delay(dev, 5000); + pm_runtime_use_autosuspend(dev); + pm_runtime_get(dev); + + return 0; +} + +static int apds9306_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct apds9306_data *data; + struct iio_dev *indio_dev; + int ret; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + data = iio_priv(indio_dev); + + mutex_init(&data->mutex); + + data->regmap = devm_regmap_init_i2c(client, &apds9306_regmap); + if (IS_ERR(data->regmap)) + return dev_err_probe(dev, PTR_ERR(data->regmap), + "regmap initialization failed\n"); + + data->dev = dev; + i2c_set_clientdata(client, indio_dev); + + ret = apds9306_regfield_init(data); + if (ret) + return dev_err_probe(dev, ret, "regfield initialization failed\n"); + + ret = devm_regulator_get_enable(dev, "vdd"); + if (ret) + return dev_err_probe(dev, ret, "Failed to enable regulator\n"); + + indio_dev->name = "apds9306"; + indio_dev->modes = INDIO_DIRECT_MODE; + if (client->irq) { + indio_dev->info = &apds9306_info; + indio_dev->channels = apds9306_channels_with_events; + indio_dev->num_channels = ARRAY_SIZE(apds9306_channels_with_events); + ret = devm_request_threaded_irq(dev, client->irq, NULL, + apds9306_irq_handler, IRQF_ONESHOT, + "apds9306_event", indio_dev); + if (ret) + return dev_err_probe(dev, ret, + "failed to assign interrupt.\n"); + } else { + indio_dev->info = &apds9306_info_no_events; + indio_dev->channels = apds9306_channels_without_events; + indio_dev->num_channels = + ARRAY_SIZE(apds9306_channels_without_events); + } + + ret = apds9306_pm_init(data); + if (ret) + return dev_err_probe(dev, ret, "failed pm init\n"); + + ret = apds9306_device_init(data); + if (ret) + return dev_err_probe(dev, ret, "failed to init device\n"); + + ret = devm_add_action_or_reset(dev, apds9306_powerdown, data); + if (ret) + return dev_err_probe(dev, ret, "failed to add action or reset\n"); + + ret = devm_iio_device_register(dev, indio_dev); + if (ret) + return dev_err_probe(dev, ret, "failed iio device registration\n"); + + pm_runtime_put_autosuspend(dev); + + return 0; +} + +static int apds9306_runtime_suspend(struct device *dev) +{ + struct apds9306_data *data = iio_priv(dev_get_drvdata(dev)); + + return apds9306_power_state(data, false); +} + +static int apds9306_runtime_resume(struct device *dev) +{ + struct apds9306_data *data = iio_priv(dev_get_drvdata(dev)); + + return apds9306_power_state(data, true); +} + +static DEFINE_RUNTIME_DEV_PM_OPS(apds9306_pm_ops, + apds9306_runtime_suspend, + apds9306_runtime_resume, + NULL); + +static const struct of_device_id apds9306_of_match[] = { + { .compatible = "avago,apds9306" }, + { } +}; +MODULE_DEVICE_TABLE(of, apds9306_of_match); + +static struct i2c_driver apds9306_driver = { + .driver = { + .name = "apds9306", + .pm = pm_ptr(&apds9306_pm_ops), + .of_match_table = apds9306_of_match, + }, + .probe = apds9306_probe, +}; +module_i2c_driver(apds9306_driver); + +MODULE_AUTHOR("Subhajit Ghosh "); +MODULE_DESCRIPTION("APDS9306 Ambient Light Sensor driver"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(IIO_GTS_HELPER); -- cgit v1.2.3-59-g8ed1b From 88a1ffc690676b16f64ae8254253489b907c68e7 Mon Sep 17 00:00:00 2001 From: Dumitru Ceclan Date: Wed, 6 Mar 2024 13:09:54 +0200 Subject: dt-bindings: adc: ad7173: add support for additional models Add support for: AD7172-2, AD7175-8, AD7177-2. AD7172-4 does not feature an internal reference, check for external reference presence. Signed-off-by: Dumitru Ceclan Reviewed-by: Conor Dooley Link: https://lore.kernel.org/r/20240306110956.13167-2-mitrutzceclan@gmail.com Signed-off-by: Jonathan Cameron --- .../devicetree/bindings/iio/adc/adi,ad7173.yaml | 39 ++++++++++++++++++++-- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7173.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7173.yaml index 36f16a325bc5..ea6cfcd0aff4 100644 --- a/Documentation/devicetree/bindings/iio/adc/adi,ad7173.yaml +++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7173.yaml @@ -21,17 +21,23 @@ description: | Datasheets for supported chips: https://www.analog.com/media/en/technical-documentation/data-sheets/AD7172-2.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/AD7172-4.pdf https://www.analog.com/media/en/technical-documentation/data-sheets/AD7173-8.pdf https://www.analog.com/media/en/technical-documentation/data-sheets/AD7175-2.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/AD7175-8.pdf https://www.analog.com/media/en/technical-documentation/data-sheets/AD7176-2.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/AD7177-2.pdf properties: compatible: enum: - adi,ad7172-2 + - adi,ad7172-4 - adi,ad7173-8 - adi,ad7175-2 + - adi,ad7175-8 - adi,ad7176-2 + - adi,ad7177-2 reg: maxItems: 1 @@ -136,8 +142,10 @@ patternProperties: refout-avss: REFOUT/AVSS (Internal reference) avdd : AVDD /AVSS - External reference ref2 only available on ad7173-8. - If not specified, internal reference used. + External reference ref2 only available on ad7173-8 and ad7172-4. + Internal reference refout-avss not available on ad7172-4. + + If not specified, internal reference used (if available). $ref: /schemas/types.yaml#/definitions/string enum: - vref @@ -157,12 +165,17 @@ required: allOf: - $ref: /schemas/spi/spi-peripheral-props.yaml# + # Only ad7172-4, ad7173-8 and ad7175-8 support vref2 + # Other models have [0-3] channel registers - if: properties: compatible: not: contains: - const: adi,ad7173-8 + enum: + - adi,ad7172-4 + - adi,ad7173-8 + - adi,ad7175-8 then: properties: vref2-supply: false @@ -177,6 +190,26 @@ allOf: reg: maximum: 3 + # Model ad7172-4 does not support internal reference + - if: + properties: + compatible: + contains: + const: adi,ad7172-4 + then: + patternProperties: + "^channel@[0-9a-f]$": + properties: + reg: + maximum: 7 + adi,reference-select: + enum: + - vref + - vref2 + - avdd + required: + - adi,reference-select + - if: anyOf: - required: [clock-names] -- cgit v1.2.3-59-g8ed1b From 393310526b4aaeb291d68c5b34f78f1bddae487a Mon Sep 17 00:00:00 2001 From: Dumitru Ceclan Date: Wed, 6 Mar 2024 13:09:55 +0200 Subject: iio: adc: ad7173: improve chip id's defines Rename to AD7172_2_ID to avoid confusion with _4 model. Reorder id's by reg value. Signed-off-by: Dumitru Ceclan Link: https://lore.kernel.org/r/20240306110956.13167-3-mitrutzceclan@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7173.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/iio/adc/ad7173.c b/drivers/iio/adc/ad7173.c index b42fbe28a325..59a55d2944a7 100644 --- a/drivers/iio/adc/ad7173.c +++ b/drivers/iio/adc/ad7173.c @@ -61,10 +61,10 @@ #define AD7173_AIN_TEMP_POS 17 #define AD7173_AIN_TEMP_NEG 18 -#define AD7172_ID 0x00d0 -#define AD7173_ID 0x30d0 +#define AD7172_2_ID 0x00d0 #define AD7175_ID 0x0cd0 #define AD7176_ID 0x0c90 +#define AD7173_ID 0x30d0 #define AD7173_ID_MASK GENMASK(15, 4) #define AD7173_ADC_MODE_REF_EN BIT(15) @@ -190,7 +190,7 @@ static const unsigned int ad7175_sinc5_data_rates[] = { static const struct ad7173_device_info ad7173_device_info[] = { [ID_AD7172_2] = { .name = "ad7172-2", - .id = AD7172_ID, + .id = AD7172_2_ID, .num_inputs = 5, .num_channels = 4, .num_configs = 4, -- cgit v1.2.3-59-g8ed1b From 37ae8381ccda3c79d100677d29b233e207700b2b Mon Sep 17 00:00:00 2001 From: Dumitru Ceclan Date: Wed, 6 Mar 2024 13:09:56 +0200 Subject: iio: adc: ad7173: add support for additional models Add support for Analog Devices AD7172-2, AD7175-8, AD7177-2. Signed-off-by: Dumitru Ceclan Link: https://lore.kernel.org/r/20240306110956.13167-4-mitrutzceclan@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7173.c | 86 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 80 insertions(+), 6 deletions(-) diff --git a/drivers/iio/adc/ad7173.c b/drivers/iio/adc/ad7173.c index 59a55d2944a7..4ff6ce46b02c 100644 --- a/drivers/iio/adc/ad7173.c +++ b/drivers/iio/adc/ad7173.c @@ -1,6 +1,11 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * AD7172-2/AD7173-8/AD7175-2/AD7176-2 SPI ADC driver + * AD717x family SPI ADC driver + * + * Supported devices: + * AD7172-2/AD7172-4/AD7173-8/AD7175-2 + * AD7175-8/AD7176-2/AD7177-2 + * * Copyright (C) 2015, 2024 Analog Devices, Inc. */ @@ -64,7 +69,11 @@ #define AD7172_2_ID 0x00d0 #define AD7175_ID 0x0cd0 #define AD7176_ID 0x0c90 +#define AD7175_2_ID 0x0cd0 +#define AD7172_4_ID 0x2050 #define AD7173_ID 0x30d0 +#define AD7175_8_ID 0x3cd0 +#define AD7177_ID 0x4fd0 #define AD7173_ID_MASK GENMASK(15, 4) #define AD7173_ADC_MODE_REF_EN BIT(15) @@ -110,20 +119,25 @@ #define AD7173_SETUP_REF_SEL_EXT_REF 0x0 #define AD7173_VOLTAGE_INT_REF_uV 2500000 #define AD7173_TEMP_SENSIIVITY_uV_per_C 477 +#define AD7177_ODR_START_VALUE 0x07 #define AD7173_FILTER_ODR0_MASK GENMASK(5, 0) #define AD7173_MAX_CONFIGS 8 enum ad7173_ids { ID_AD7172_2, + ID_AD7172_4, ID_AD7173_8, ID_AD7175_2, + ID_AD7175_8, ID_AD7176_2, + ID_AD7177_2, }; struct ad7173_device_info { const unsigned int *sinc5_data_rates; unsigned int num_sinc5_data_rates; + unsigned int odr_start_value; unsigned int num_channels; unsigned int num_configs; unsigned int num_inputs; @@ -131,6 +145,8 @@ struct ad7173_device_info { unsigned int id; char *name; bool has_temp; + bool has_int_ref; + bool has_ref2; u8 num_gpios; }; @@ -196,6 +212,19 @@ static const struct ad7173_device_info ad7173_device_info[] = { .num_configs = 4, .num_gpios = 2, .has_temp = true, + .has_int_ref = true, + .clock = 2 * HZ_PER_MHZ, + .sinc5_data_rates = ad7173_sinc5_data_rates, + .num_sinc5_data_rates = ARRAY_SIZE(ad7173_sinc5_data_rates), + }, + [ID_AD7172_4] = { + .id = AD7172_4_ID, + .num_inputs = 9, + .num_channels = 8, + .num_configs = 8, + .num_gpios = 4, + .has_temp = false, + .has_ref2 = true, .clock = 2 * HZ_PER_MHZ, .sinc5_data_rates = ad7173_sinc5_data_rates, .num_sinc5_data_rates = ARRAY_SIZE(ad7173_sinc5_data_rates), @@ -208,18 +237,34 @@ static const struct ad7173_device_info ad7173_device_info[] = { .num_configs = 8, .num_gpios = 4, .has_temp = true, + .has_int_ref = true, + .has_ref2 = true, .clock = 2 * HZ_PER_MHZ, .sinc5_data_rates = ad7173_sinc5_data_rates, .num_sinc5_data_rates = ARRAY_SIZE(ad7173_sinc5_data_rates), }, [ID_AD7175_2] = { .name = "ad7175-2", - .id = AD7175_ID, + .id = AD7175_2_ID, .num_inputs = 5, .num_channels = 4, .num_configs = 4, .num_gpios = 2, .has_temp = true, + .has_int_ref = true, + .clock = 16 * HZ_PER_MHZ, + .sinc5_data_rates = ad7175_sinc5_data_rates, + .num_sinc5_data_rates = ARRAY_SIZE(ad7175_sinc5_data_rates), + }, + [ID_AD7175_8] = { + .id = AD7175_8_ID, + .num_inputs = 17, + .num_channels = 16, + .num_configs = 8, + .num_gpios = 4, + .has_temp = true, + .has_int_ref = true, + .has_ref2 = true, .clock = 16 * HZ_PER_MHZ, .sinc5_data_rates = ad7175_sinc5_data_rates, .num_sinc5_data_rates = ARRAY_SIZE(ad7175_sinc5_data_rates), @@ -232,7 +277,21 @@ static const struct ad7173_device_info ad7173_device_info[] = { .num_configs = 4, .num_gpios = 2, .has_temp = false, + .has_int_ref = true, + .clock = 16 * HZ_PER_MHZ, + .sinc5_data_rates = ad7175_sinc5_data_rates, + .num_sinc5_data_rates = ARRAY_SIZE(ad7175_sinc5_data_rates), + }, + [ID_AD7177_2] = { + .id = AD7177_ID, + .num_inputs = 5, + .num_channels = 4, + .num_configs = 4, + .num_gpios = 2, + .has_temp = true, + .has_int_ref = true, .clock = 16 * HZ_PER_MHZ, + .odr_start_value = AD7177_ODR_START_VALUE, .sinc5_data_rates = ad7175_sinc5_data_rates, .num_sinc5_data_rates = ARRAY_SIZE(ad7175_sinc5_data_rates), }, @@ -656,7 +715,7 @@ static int ad7173_write_raw(struct iio_dev *indio_dev, switch (info) { case IIO_CHAN_INFO_SAMP_FREQ: freq = val * MILLI + val2 / MILLI; - for (i = 0; i < st->info->num_sinc5_data_rates - 1; i++) + for (i = st->info->odr_start_value; i < st->info->num_sinc5_data_rates - 1; i++) if (freq >= st->info->sinc5_data_rates[i]) break; @@ -908,11 +967,17 @@ static int ad7173_fw_parse_channel_config(struct iio_dev *indio_dev) else ref_sel = ret; - if (ref_sel == AD7173_SETUP_REF_SEL_EXT_REF2 && - st->info->id != AD7173_ID) { + if (ref_sel == AD7173_SETUP_REF_SEL_INT_REF && + !st->info->has_int_ref) { + fwnode_handle_put(child); + return dev_err_probe(dev, -EINVAL, + "Internal reference is not available on current model.\n"); + } + + if (ref_sel == AD7173_SETUP_REF_SEL_EXT_REF2 && !st->info->has_ref2) { fwnode_handle_put(child); return dev_err_probe(dev, -EINVAL, - "External reference 2 is only available on ad7173-8\n"); + "External reference 2 is not available on current model.\n"); } ret = ad7173_get_ref_voltage_milli(st, ref_sel); @@ -1080,21 +1145,30 @@ static int ad7173_probe(struct spi_device *spi) static const struct of_device_id ad7173_of_match[] = { { .compatible = "adi,ad7172-2", .data = &ad7173_device_info[ID_AD7172_2]}, + { .compatible = "adi,ad7172-4", + .data = &ad7173_device_info[ID_AD7172_4]}, { .compatible = "adi,ad7173-8", .data = &ad7173_device_info[ID_AD7173_8]}, { .compatible = "adi,ad7175-2", .data = &ad7173_device_info[ID_AD7175_2]}, + { .compatible = "adi,ad7175-8", + .data = &ad7173_device_info[ID_AD7175_8]}, { .compatible = "adi,ad7176-2", .data = &ad7173_device_info[ID_AD7176_2]}, + { .compatible = "adi,ad7177-2", + .data = &ad7173_device_info[ID_AD7177_2]}, { } }; MODULE_DEVICE_TABLE(of, ad7173_of_match); static const struct spi_device_id ad7173_id_table[] = { { "ad7172-2", (kernel_ulong_t)&ad7173_device_info[ID_AD7172_2]}, + { "ad7172-4", (kernel_ulong_t)&ad7173_device_info[ID_AD7172_4]}, { "ad7173-8", (kernel_ulong_t)&ad7173_device_info[ID_AD7173_8]}, { "ad7175-2", (kernel_ulong_t)&ad7173_device_info[ID_AD7175_2]}, + { "ad7175-8", (kernel_ulong_t)&ad7173_device_info[ID_AD7175_8]}, { "ad7176-2", (kernel_ulong_t)&ad7173_device_info[ID_AD7176_2]}, + { "ad7177-2", (kernel_ulong_t)&ad7173_device_info[ID_AD7177_2]}, { } }; MODULE_DEVICE_TABLE(spi, ad7173_id_table); -- cgit v1.2.3-59-g8ed1b From 1c5aa559a695fcb1a49da4217b8f8f8bfc5b393a Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 4 Mar 2024 16:40:06 +0200 Subject: iio: adc: twl4030-madc: Make use of device properties Convert the module to be property provider agnostic and allow it to be used on non-OF platforms. Include mod_devicetable.h explicitly to replace the dropped of.h which included mod_devicetable.h indirectly. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240304144037.1036390-1-andriy.shevchenko@linux.intel.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/twl4030-madc.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/drivers/iio/adc/twl4030-madc.c b/drivers/iio/adc/twl4030-madc.c index 4a247ca25a44..0253064fadec 100644 --- a/drivers/iio/adc/twl4030-madc.c +++ b/drivers/iio/adc/twl4030-madc.c @@ -19,10 +19,12 @@ #include #include #include +#include +#include #include +#include #include #include -#include #include #include #include @@ -30,7 +32,6 @@ #include #include #include -#include #include #include @@ -744,14 +745,14 @@ static int twl4030_madc_set_power(struct twl4030_madc_data *madc, int on) */ static int twl4030_madc_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; + struct twl4030_madc_platform_data *pdata = dev_get_platdata(dev); struct twl4030_madc_data *madc; - struct twl4030_madc_platform_data *pdata = dev_get_platdata(&pdev->dev); - struct device_node *np = pdev->dev.of_node; int irq, ret; u8 regval; struct iio_dev *iio_dev = NULL; - if (!pdata && !np) { + if (!pdata && !dev_fwnode(dev)) { dev_err(&pdev->dev, "neither platform data nor Device Tree node available\n"); return -EINVAL; } @@ -779,7 +780,7 @@ static int twl4030_madc_probe(struct platform_device *pdev) if (pdata) madc->use_second_irq = (pdata->irq_line != 1); else - madc->use_second_irq = of_property_read_bool(np, + madc->use_second_irq = device_property_read_bool(dev, "ti,system-uses-second-madc-irq"); madc->imr = madc->use_second_irq ? TWL4030_MADC_IMR2 : @@ -905,20 +906,18 @@ static void twl4030_madc_remove(struct platform_device *pdev) regulator_disable(madc->usb3v1); } -#ifdef CONFIG_OF static const struct of_device_id twl_madc_of_match[] = { { .compatible = "ti,twl4030-madc", }, - { }, + { } }; MODULE_DEVICE_TABLE(of, twl_madc_of_match); -#endif static struct platform_driver twl4030_madc_driver = { .probe = twl4030_madc_probe, .remove_new = twl4030_madc_remove, .driver = { .name = "twl4030_madc", - .of_match_table = of_match_ptr(twl_madc_of_match), + .of_match_table = twl_madc_of_match, }, }; -- cgit v1.2.3-59-g8ed1b From 59346366e56f8abf72ed2eb081da4abbfd4d5575 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Mon, 4 Mar 2024 13:48:46 -0600 Subject: dt-bindings: iio: adc: add ad7944 ADCs This adds a new binding for the Analog Devices, Inc. AD7944, AD7985, and AD7986 ADCs. Reviewed-by: Rob Herring Signed-off-by: David Lechner Link: https://lore.kernel.org/r/20240304-ad7944-mainline-v5-1-f0a38cea8901@baylibre.com Signed-off-by: Jonathan Cameron --- .../devicetree/bindings/iio/adc/adi,ad7944.yaml | 213 +++++++++++++++++++++ MAINTAINERS | 8 + 2 files changed, 221 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/adc/adi,ad7944.yaml diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7944.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7944.yaml new file mode 100644 index 000000000000..d17d184842d3 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7944.yaml @@ -0,0 +1,213 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/adc/adi,ad7944.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices PulSAR LFCSP Analog to Digital Converters + +maintainers: + - Michael Hennerich + - Nuno Sá + +description: | + A family of pin-compatible single channel differential analog to digital + converters with SPI support in a LFCSP package. + + * https://www.analog.com/en/products/ad7944.html + * https://www.analog.com/en/products/ad7985.html + * https://www.analog.com/en/products/ad7986.html + +$ref: /schemas/spi/spi-peripheral-props.yaml# + +properties: + compatible: + enum: + - adi,ad7944 + - adi,ad7985 + - adi,ad7986 + + reg: + maxItems: 1 + + spi-max-frequency: + maximum: 111111111 + + spi-cpol: true + spi-cpha: true + + adi,spi-mode: + $ref: /schemas/types.yaml#/definitions/string + enum: [ single, chain ] + description: | + This property indicates the SPI wiring configuration. + + When this property is omitted, it is assumed that the device is using what + the datasheet calls "4-wire mode". This is the conventional SPI mode used + when there are multiple devices on the same bus. In this mode, the CNV + line is used to initiate the conversion and the SDI line is connected to + CS on the SPI controller. + + When this property is present, it indicates that the device is using one + of the following alternative wiring configurations: + + * single: The datasheet calls this "3-wire mode". (NOTE: The datasheet's + definition of 3-wire mode is NOT at all related to the standard + spi-3wire property!) This mode is often used when the ADC is the only + device on the bus. In this mode, SDI is tied to VIO, and the CNV line + can be connected to the CS line of the SPI controller or to a GPIO, in + which case the CS line of the controller is unused. + * chain: The datasheet calls this "chain mode". This mode is used to save + on wiring when multiple ADCs are used. In this mode, the SDI line of + one chip is tied to the SDO of the next chip in the chain and the SDI of + the last chip in the chain is tied to GND. Only the first chip in the + chain is connected to the SPI bus. The CNV line of all chips are tied + together. The CS line of the SPI controller can be used as the CNV line + only if it is active high. + + '#daisy-chained-devices': true + + avdd-supply: + description: A 2.5V supply that powers the analog circuitry. + + dvdd-supply: + description: A 2.5V supply that powers the digital circuitry. + + vio-supply: + description: + A 1.8V to 2.7V supply for the digital inputs and outputs. + + bvdd-supply: + description: + A voltage supply for the buffered power. When using an external reference + without an internal buffer (PDREF high, REFIN low), this should be + connected to the same supply as ref-supply. Otherwise, when using an + internal reference or an external reference with an internal buffer, this + is connected to a 5V supply. + + ref-supply: + description: + Voltage regulator for the external reference voltage (REF). This property + is omitted when using an internal reference. + + refin-supply: + description: + Voltage regulator for the reference buffer input (REFIN). When using an + external buffer with internal reference, this should be connected to a + 1.2V external reference voltage supply. Otherwise, this property is + omitted. + + cnv-gpios: + description: + The Convert Input (CNV). This input has multiple functions. It initiates + the conversions and selects the SPI mode of the device (chain or CS). In + 'single' mode, this property is omitted if the CNV pin is connected to the + CS line of the SPI controller. + maxItems: 1 + + turbo-gpios: + description: + GPIO connected to the TURBO line. If omitted, it is assumed that the TURBO + line is hard-wired and the state is determined by the adi,always-turbo + property. + maxItems: 1 + + adi,always-turbo: + type: boolean + description: + When present, this property indicates that the TURBO line is hard-wired + and the state is always high. If neither this property nor turbo-gpios is + present, the TURBO line is assumed to be hard-wired and the state is + always low. + + interrupts: + description: + The SDO pin can also function as a busy indicator. This node should be + connected to an interrupt that is triggered when the SDO line goes low + while the SDI line is high and the CNV line is low ('single' mode) or the + SDI line is low and the CNV line is high ('multi' mode); or when the SDO + line goes high while the SDI and CNV lines are high (chain mode), + maxItems: 1 + +required: + - compatible + - reg + - avdd-supply + - dvdd-supply + - vio-supply + - bvdd-supply + +allOf: + # ref-supply and refin-supply are mutually exclusive (neither is also valid) + - if: + required: + - ref-supply + then: + properties: + refin-supply: false + - if: + required: + - refin-supply + then: + properties: + ref-supply: false + # in '4-wire' mode, cnv-gpios is required, for other modes it is optional + - if: + not: + required: + - adi,spi-mode + then: + required: + - cnv-gpios + # chain mode has lower SCLK max rate and doesn't work when TURBO is enabled + - if: + required: + - adi,spi-mode + properties: + adi,spi-mode: + const: chain + then: + properties: + spi-max-frequency: + maximum: 90909090 + adi,always-turbo: false + required: + - '#daisy-chained-devices' + else: + properties: + '#daisy-chained-devices': false + # turbo-gpios and adi,always-turbo are mutually exclusive + - if: + required: + - turbo-gpios + then: + properties: + adi,always-turbo: false + - if: + required: + - adi,always-turbo + then: + properties: + turbo-gpios: false + +unevaluatedProperties: false + +examples: + - | + #include + spi { + #address-cells = <1>; + #size-cells = <0>; + adc@0 { + compatible = "adi,ad7944"; + reg = <0>; + spi-cpha; + spi-max-frequency = <111111111>; + avdd-supply = <&supply_2_5V>; + dvdd-supply = <&supply_2_5V>; + vio-supply = <&supply_1_8V>; + bvdd-supply = <&supply_5V>; + cnv-gpios = <&gpio 0 GPIO_ACTIVE_HIGH>; + turbo-gpios = <&gpio 1 GPIO_ACTIVE_HIGH>; + }; + }; diff --git a/MAINTAINERS b/MAINTAINERS index aa3b947fb080..6c14216ddb75 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -441,6 +441,14 @@ W: http://wiki.analog.com/AD7879 W: https://ez.analog.com/linux-software-drivers F: drivers/input/touchscreen/ad7879.c +AD7944 ADC DRIVER (AD7944/AD7985/AD7986) +M: Michael Hennerich +M: Nuno Sá +R: David Lechner +S: Supported +W: https://ez.analog.com/linux-software-drivers +F: Documentation/devicetree/bindings/iio/adc/adi,ad7944.yaml + ADAFRUIT MINI I2C GAMEPAD M: Anshul Dalal L: linux-input@vger.kernel.org -- cgit v1.2.3-59-g8ed1b From d1efcf8871db514ae349a24790afd1632ba31030 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Mon, 4 Mar 2024 13:48:47 -0600 Subject: iio: adc: ad7944: add driver for AD7944/AD7985/AD7986 This adds a driver for the Analog Devices Inc. AD7944, AD7985, and AD7986 ADCs. These are a family of pin-compatible ADCs that can sample at rates up to 2.5 MSPS. The initial driver adds support for sampling at lower rates using the usual IIO triggered buffer and can handle all 3 possible reference voltage configurations. Signed-off-by: David Lechner Reviewed-by: Nuno Sa Link: https://lore.kernel.org/r/20240304-ad7944-mainline-v5-2-f0a38cea8901@baylibre.com Signed-off-by: Jonathan Cameron --- MAINTAINERS | 1 + drivers/iio/adc/Kconfig | 10 ++ drivers/iio/adc/Makefile | 1 + drivers/iio/adc/ad7944.c | 416 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 428 insertions(+) create mode 100644 drivers/iio/adc/ad7944.c diff --git a/MAINTAINERS b/MAINTAINERS index 6c14216ddb75..eefd1a8906bf 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -448,6 +448,7 @@ R: David Lechner S: Supported W: https://ez.analog.com/linux-software-drivers F: Documentation/devicetree/bindings/iio/adc/adi,ad7944.yaml +F: drivers/iio/adc/ad7944.c ADAFRUIT MINI I2C GAMEPAD M: Anshul Dalal diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 91286ab83bd0..8db68b80b391 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -281,6 +281,16 @@ config AD7923 To compile this driver as a module, choose M here: the module will be called ad7923. +config AD7944 + tristate "Analog Devices AD7944 and similar ADCs driver" + depends on SPI + help + Say yes here to build support for Analog Devices + AD7944, AD7985, AD7986 ADCs. + + To compile this driver as a module, choose M here: the + module will be called ad7944 + config AD7949 tristate "Analog Devices AD7949 and similar ADCs driver" depends on SPI diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 717e964afed9..edb32ce2af02 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -29,6 +29,7 @@ obj-$(CONFIG_AD7780) += ad7780.o obj-$(CONFIG_AD7791) += ad7791.o obj-$(CONFIG_AD7793) += ad7793.o obj-$(CONFIG_AD7887) += ad7887.o +obj-$(CONFIG_AD7944) += ad7944.o obj-$(CONFIG_AD7949) += ad7949.o obj-$(CONFIG_AD799X) += ad799x.o obj-$(CONFIG_AD9467) += ad9467.o diff --git a/drivers/iio/adc/ad7944.c b/drivers/iio/adc/ad7944.c new file mode 100644 index 000000000000..adb007cdd287 --- /dev/null +++ b/drivers/iio/adc/ad7944.c @@ -0,0 +1,416 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Analog Devices AD7944/85/86 PulSAR ADC family driver. + * + * Copyright 2024 Analog Devices, Inc. + * Copyright 2024 BayLibre, SAS + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define AD7944_INTERNAL_REF_MV 4096 + +struct ad7944_timing_spec { + /* Normal mode max conversion time (t_{CONV}). */ + unsigned int conv_ns; + /* TURBO mode max conversion time (t_{CONV}). */ + unsigned int turbo_conv_ns; +}; + +struct ad7944_adc { + struct spi_device *spi; + /* Chip-specific timing specifications. */ + const struct ad7944_timing_spec *timing_spec; + /* GPIO connected to CNV pin. */ + struct gpio_desc *cnv; + /* Optional GPIO to enable turbo mode. */ + struct gpio_desc *turbo; + /* Indicates TURBO is hard-wired to be always enabled. */ + bool always_turbo; + /* Reference voltage (millivolts). */ + unsigned int ref_mv; + + /* + * DMA (thus cache coherency maintenance) requires the + * transfer buffers to live in their own cache lines. + */ + struct { + union { + u16 u16; + u32 u32; + } raw; + u64 timestamp __aligned(8); + } sample __aligned(IIO_DMA_MINALIGN); +}; + +static const struct ad7944_timing_spec ad7944_timing_spec = { + .conv_ns = 420, + .turbo_conv_ns = 320, +}; + +static const struct ad7944_timing_spec ad7986_timing_spec = { + .conv_ns = 500, + .turbo_conv_ns = 400, +}; + +struct ad7944_chip_info { + const char *name; + const struct ad7944_timing_spec *timing_spec; + const struct iio_chan_spec channels[2]; +}; + +/* + * AD7944_DEFINE_CHIP_INFO - Define a chip info structure for a specific chip + * @_name: The name of the chip + * @_ts: The timing specification for the chip + * @_bits: The number of bits in the conversion result + * @_diff: Whether the chip is true differential or not + */ +#define AD7944_DEFINE_CHIP_INFO(_name, _ts, _bits, _diff) \ +static const struct ad7944_chip_info _name##_chip_info = { \ + .name = #_name, \ + .timing_spec = &_ts##_timing_spec, \ + .channels = { \ + { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .differential = _diff, \ + .channel = 0, \ + .channel2 = _diff ? 1 : 0, \ + .scan_index = 0, \ + .scan_type.sign = _diff ? 's' : 'u', \ + .scan_type.realbits = _bits, \ + .scan_type.storagebits = _bits > 16 ? 32 : 16, \ + .scan_type.endianness = IIO_CPU, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) \ + | BIT(IIO_CHAN_INFO_SCALE), \ + }, \ + IIO_CHAN_SOFT_TIMESTAMP(1), \ + }, \ +} + +/* pseudo-differential with ground sense */ +AD7944_DEFINE_CHIP_INFO(ad7944, ad7944, 14, 0); +AD7944_DEFINE_CHIP_INFO(ad7985, ad7944, 16, 0); +/* fully differential */ +AD7944_DEFINE_CHIP_INFO(ad7986, ad7986, 18, 1); + +/* + * ad7944_4wire_mode_conversion - Perform a 4-wire mode conversion and acquisition + * @adc: The ADC device structure + * @chan: The channel specification + * Return: 0 on success, a negative error code on failure + * + * Upon successful return adc->sample.raw will contain the conversion result. + */ +static int ad7944_4wire_mode_conversion(struct ad7944_adc *adc, + const struct iio_chan_spec *chan) +{ + unsigned int t_conv_ns = adc->always_turbo ? adc->timing_spec->turbo_conv_ns + : adc->timing_spec->conv_ns; + struct spi_transfer xfers[] = { + { + /* + * NB: can get better performance from some SPI + * controllers if we use the same bits_per_word + * in every transfer. + */ + .bits_per_word = chan->scan_type.realbits, + /* + * CS has to be high for full conversion time to avoid + * triggering the busy indication. + */ + .cs_off = 1, + .delay = { + .value = t_conv_ns, + .unit = SPI_DELAY_UNIT_NSECS, + }, + + }, + { + .rx_buf = &adc->sample.raw, + .len = BITS_TO_BYTES(chan->scan_type.storagebits), + .bits_per_word = chan->scan_type.realbits, + }, + }; + int ret; + + /* + * In 4-wire mode, the CNV line is held high for the entire conversion + * and acquisition process. + */ + gpiod_set_value_cansleep(adc->cnv, 1); + ret = spi_sync_transfer(adc->spi, xfers, ARRAY_SIZE(xfers)); + gpiod_set_value_cansleep(adc->cnv, 0); + + return ret; +} + +static int ad7944_single_conversion(struct ad7944_adc *adc, + const struct iio_chan_spec *chan, + int *val) +{ + int ret; + + ret = ad7944_4wire_mode_conversion(adc, chan); + if (ret) + return ret; + + if (chan->scan_type.storagebits > 16) + *val = adc->sample.raw.u32; + else + *val = adc->sample.raw.u16; + + if (chan->scan_type.sign == 's') + *val = sign_extend32(*val, chan->scan_type.realbits - 1); + + return IIO_VAL_INT; +} + +static int ad7944_read_raw(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + int *val, int *val2, long info) +{ + struct ad7944_adc *adc = iio_priv(indio_dev); + int ret; + + switch (info) { + case IIO_CHAN_INFO_RAW: + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + return ret; + + ret = ad7944_single_conversion(adc, chan, val); + iio_device_release_direct_mode(indio_dev); + return ret; + + case IIO_CHAN_INFO_SCALE: + switch (chan->type) { + case IIO_VOLTAGE: + *val = adc->ref_mv; + + if (chan->scan_type.sign == 's') + *val2 = chan->scan_type.realbits - 1; + else + *val2 = chan->scan_type.realbits; + + return IIO_VAL_FRACTIONAL_LOG2; + default: + return -EINVAL; + } + + default: + return -EINVAL; + } +} + +static const struct iio_info ad7944_iio_info = { + .read_raw = &ad7944_read_raw, +}; + +static irqreturn_t ad7944_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct ad7944_adc *adc = iio_priv(indio_dev); + int ret; + + ret = ad7944_4wire_mode_conversion(adc, &indio_dev->channels[0]); + if (ret) + goto out; + + iio_push_to_buffers_with_timestamp(indio_dev, &adc->sample.raw, + pf->timestamp); + +out: + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} + +static const char * const ad7944_power_supplies[] = { + "avdd", "dvdd", "bvdd", "vio" +}; + +static void ad7944_ref_disable(void *ref) +{ + regulator_disable(ref); +} + +static int ad7944_probe(struct spi_device *spi) +{ + const struct ad7944_chip_info *chip_info; + struct device *dev = &spi->dev; + struct iio_dev *indio_dev; + struct ad7944_adc *adc; + bool have_refin = false; + struct regulator *ref; + int ret; + + /* + * driver currently only supports the conventional "4-wire" mode and + * not other special wiring configurations. + */ + if (device_property_present(dev, "adi,spi-mode")) + return dev_err_probe(dev, -EINVAL, + "adi,spi-mode is not currently supported\n"); + + indio_dev = devm_iio_device_alloc(dev, sizeof(*adc)); + if (!indio_dev) + return -ENOMEM; + + adc = iio_priv(indio_dev); + adc->spi = spi; + + chip_info = spi_get_device_match_data(spi); + if (!chip_info) + return dev_err_probe(dev, -EINVAL, "no chip info\n"); + + adc->timing_spec = chip_info->timing_spec; + + /* + * Some chips use unusual word sizes, so check now instead of waiting + * for the first xfer. + */ + if (!spi_is_bpw_supported(spi, chip_info->channels[0].scan_type.realbits)) + return dev_err_probe(dev, -EINVAL, + "SPI host does not support %d bits per word\n", + chip_info->channels[0].scan_type.realbits); + + ret = devm_regulator_bulk_get_enable(dev, + ARRAY_SIZE(ad7944_power_supplies), + ad7944_power_supplies); + if (ret) + return dev_err_probe(dev, ret, + "failed to get and enable supplies\n"); + + /* + * Sort out what is being used for the reference voltage. Options are: + * - internal reference: neither REF or REFIN is connected + * - internal reference with external buffer: REF not connected, REFIN + * is connected + * - external reference: REF is connected, REFIN is not connected + */ + + ref = devm_regulator_get_optional(dev, "ref"); + if (IS_ERR(ref)) { + if (PTR_ERR(ref) != -ENODEV) + return dev_err_probe(dev, PTR_ERR(ref), + "failed to get REF supply\n"); + + ref = NULL; + } + + ret = devm_regulator_get_enable_optional(dev, "refin"); + if (ret == 0) + have_refin = true; + else if (ret != -ENODEV) + return dev_err_probe(dev, ret, + "failed to get and enable REFIN supply\n"); + + if (have_refin && ref) + return dev_err_probe(dev, -EINVAL, + "cannot have both refin and ref supplies\n"); + + if (ref) { + ret = regulator_enable(ref); + if (ret) + return dev_err_probe(dev, ret, + "failed to enable REF supply\n"); + + ret = devm_add_action_or_reset(dev, ad7944_ref_disable, ref); + if (ret) + return ret; + + ret = regulator_get_voltage(ref); + if (ret < 0) + return dev_err_probe(dev, ret, + "failed to get REF voltage\n"); + + /* external reference */ + adc->ref_mv = ret / 1000; + } else { + /* internal reference */ + adc->ref_mv = AD7944_INTERNAL_REF_MV; + } + + /* + * CNV gpio is required in 4-wire mode which is the only currently + * supported mode. + */ + adc->cnv = devm_gpiod_get(dev, "cnv", GPIOD_OUT_LOW); + if (IS_ERR(adc->cnv)) + return dev_err_probe(dev, PTR_ERR(adc->cnv), + "failed to get CNV GPIO\n"); + + adc->turbo = devm_gpiod_get_optional(dev, "turbo", GPIOD_OUT_LOW); + if (IS_ERR(adc->turbo)) + return dev_err_probe(dev, PTR_ERR(adc->turbo), + "failed to get TURBO GPIO\n"); + + adc->always_turbo = device_property_present(dev, "adi,always-turbo"); + + if (adc->turbo && adc->always_turbo) + return dev_err_probe(dev, -EINVAL, + "cannot have both turbo-gpios and adi,always-turbo\n"); + + indio_dev->name = chip_info->name; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->info = &ad7944_iio_info; + indio_dev->channels = chip_info->channels; + indio_dev->num_channels = ARRAY_SIZE(chip_info->channels); + + ret = devm_iio_triggered_buffer_setup(dev, indio_dev, + iio_pollfunc_store_time, + ad7944_trigger_handler, NULL); + if (ret) + return ret; + + return devm_iio_device_register(dev, indio_dev); +} + +static const struct of_device_id ad7944_of_match[] = { + { .compatible = "adi,ad7944", .data = &ad7944_chip_info }, + { .compatible = "adi,ad7985", .data = &ad7985_chip_info }, + { .compatible = "adi,ad7986", .data = &ad7986_chip_info }, + { } +}; +MODULE_DEVICE_TABLE(of, ad7944_of_match); + +static const struct spi_device_id ad7944_spi_id[] = { + { "ad7944", (kernel_ulong_t)&ad7944_chip_info }, + { "ad7985", (kernel_ulong_t)&ad7985_chip_info }, + { "ad7986", (kernel_ulong_t)&ad7986_chip_info }, + { } + +}; +MODULE_DEVICE_TABLE(spi, ad7944_spi_id); + +static struct spi_driver ad7944_driver = { + .driver = { + .name = "ad7944", + .of_match_table = ad7944_of_match, + }, + .probe = ad7944_probe, + .id_table = ad7944_spi_id, +}; +module_spi_driver(ad7944_driver); + +MODULE_AUTHOR("David Lechner "); +MODULE_DESCRIPTION("Analog Devices AD7944 PulSAR ADC family driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3-59-g8ed1b From f764c293a1f8a4ee849d377a804e3940a208ad0b Mon Sep 17 00:00:00 2001 From: Javier Carrasco Date: Sun, 3 Mar 2024 22:54:20 +0100 Subject: iio: humidity: hdc3020: add power management The HDC3020 sensor carries out periodic measurements during normal operation, but as long as the power supply is enabled, it will carry on in low-power modes. In order to avoid that and reduce power consumption, the device can be switched to Trigger-on Demand mode, and if possible, turn off its regulator. According to the datasheet, the maximum "Power Up Ready" is 5 ms. Add resume/suspend pm operations to manage measurement mode and regulator state. Signed-off-by: Javier Carrasco Link: https://lore.kernel.org/r/20240303-hdc3020-pm-v3-1-48bc02b5241b@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/humidity/hdc3020.c | 95 +++++++++++++++++++++++++++++++++--------- 1 file changed, 76 insertions(+), 19 deletions(-) diff --git a/drivers/iio/humidity/hdc3020.c b/drivers/iio/humidity/hdc3020.c index 1e5d0d4797b1..7f93024b850c 100644 --- a/drivers/iio/humidity/hdc3020.c +++ b/drivers/iio/humidity/hdc3020.c @@ -20,6 +20,8 @@ #include #include #include +#include +#include #include #include @@ -68,6 +70,7 @@ struct hdc3020_data { struct i2c_client *client; + struct regulator *vdd_supply; /* * Ensure that the sensor configuration (currently only heater is * supported) will not be changed during the process of reading @@ -551,9 +554,45 @@ static const struct iio_info hdc3020_info = { .write_event_value = hdc3020_write_thresh, }; -static void hdc3020_stop(void *data) +static int hdc3020_power_off(struct hdc3020_data *data) { - hdc3020_exec_cmd((struct hdc3020_data *)data, HDC3020_EXIT_AUTO); + hdc3020_exec_cmd(data, HDC3020_EXIT_AUTO); + + return regulator_disable(data->vdd_supply); +} + +static int hdc3020_power_on(struct hdc3020_data *data) +{ + int ret; + + ret = regulator_enable(data->vdd_supply); + if (ret) + return ret; + + fsleep(5000); + + if (data->client->irq) { + /* + * The alert output is activated by default upon power up, + * hardware reset, and soft reset. Clear the status register. + */ + ret = hdc3020_exec_cmd(data, HDC3020_S_STATUS); + if (ret) { + hdc3020_power_off(data); + return ret; + } + } + + ret = hdc3020_exec_cmd(data, HDC3020_S_AUTO_10HZ_MOD0); + if (ret) + hdc3020_power_off(data); + + return ret; +} + +static void hdc3020_exit(void *data) +{ + hdc3020_power_off(data); } static int hdc3020_probe(struct i2c_client *client) @@ -569,6 +608,8 @@ static int hdc3020_probe(struct i2c_client *client) if (!indio_dev) return -ENOMEM; + dev_set_drvdata(&client->dev, indio_dev); + data = iio_priv(indio_dev); data->client = client; mutex_init(&data->lock); @@ -580,6 +621,20 @@ static int hdc3020_probe(struct i2c_client *client) indio_dev->info = &hdc3020_info; indio_dev->channels = hdc3020_channels; indio_dev->num_channels = ARRAY_SIZE(hdc3020_channels); + + data->vdd_supply = devm_regulator_get(&client->dev, "vdd"); + if (IS_ERR(data->vdd_supply)) + return dev_err_probe(&client->dev, PTR_ERR(data->vdd_supply), + "Unable to get VDD regulator\n"); + + ret = hdc3020_power_on(data); + if (ret) + return dev_err_probe(&client->dev, ret, "Power on failed\n"); + + ret = devm_add_action_or_reset(&data->client->dev, hdc3020_exit, data); + if (ret) + return ret; + if (client->irq) { ret = devm_request_threaded_irq(&client->dev, client->irq, NULL, hdc3020_interrupt_handler, @@ -588,25 +643,8 @@ static int hdc3020_probe(struct i2c_client *client) if (ret) return dev_err_probe(&client->dev, ret, "Failed to request IRQ\n"); - - /* - * The alert output is activated by default upon power up, - * hardware reset, and soft reset. Clear the status register. - */ - ret = hdc3020_exec_cmd(data, HDC3020_S_STATUS); - if (ret) - return ret; } - ret = hdc3020_exec_cmd(data, HDC3020_S_AUTO_10HZ_MOD0); - if (ret) - return dev_err_probe(&client->dev, ret, - "Unable to set up measurement\n"); - - ret = devm_add_action_or_reset(&data->client->dev, hdc3020_stop, data); - if (ret) - return ret; - ret = devm_iio_device_register(&data->client->dev, indio_dev); if (ret) return dev_err_probe(&client->dev, ret, "Failed to add device"); @@ -614,6 +652,24 @@ static int hdc3020_probe(struct i2c_client *client) return 0; } +static int hdc3020_suspend(struct device *dev) +{ + struct iio_dev *iio_dev = dev_get_drvdata(dev); + struct hdc3020_data *data = iio_priv(iio_dev); + + return hdc3020_power_off(data); +} + +static int hdc3020_resume(struct device *dev) +{ + struct iio_dev *iio_dev = dev_get_drvdata(dev); + struct hdc3020_data *data = iio_priv(iio_dev); + + return hdc3020_power_on(data); +} + +static DEFINE_SIMPLE_DEV_PM_OPS(hdc3020_pm_ops, hdc3020_suspend, hdc3020_resume); + static const struct i2c_device_id hdc3020_id[] = { { "hdc3020" }, { "hdc3021" }, @@ -633,6 +689,7 @@ MODULE_DEVICE_TABLE(of, hdc3020_dt_ids); static struct i2c_driver hdc3020_driver = { .driver = { .name = "hdc3020", + .pm = pm_sleep_ptr(&hdc3020_pm_ops), .of_match_table = hdc3020_dt_ids, }, .probe = hdc3020_probe, -- cgit v1.2.3-59-g8ed1b From 137166ef5fc5a10fbc7bceee20d770e6a930f4cc Mon Sep 17 00:00:00 2001 From: Javier Carrasco Date: Sun, 3 Mar 2024 22:54:21 +0100 Subject: dt-bindings: iio: humidity: hdc3020: add reset-gpios The HDC3020 provides an active low reset signal that is still not described in the bindings. Add reset-gpios to the bindings and the example. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Javier Carrasco Link: https://lore.kernel.org/r/20240303-hdc3020-pm-v3-2-48bc02b5241b@gmail.com Signed-off-by: Jonathan Cameron --- Documentation/devicetree/bindings/iio/humidity/ti,hdc3020.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Documentation/devicetree/bindings/iio/humidity/ti,hdc3020.yaml b/Documentation/devicetree/bindings/iio/humidity/ti,hdc3020.yaml index 8b5dedd1a598..b375d307513f 100644 --- a/Documentation/devicetree/bindings/iio/humidity/ti,hdc3020.yaml +++ b/Documentation/devicetree/bindings/iio/humidity/ti,hdc3020.yaml @@ -34,6 +34,9 @@ properties: reg: maxItems: 1 + reset-gpios: + maxItems: 1 + required: - compatible - reg @@ -43,6 +46,7 @@ additionalProperties: false examples: - | + #include #include i2c { #address-cells = <1>; @@ -54,5 +58,6 @@ examples: vdd-supply = <&vcc_3v3>; interrupt-parent = <&gpio3>; interrupts = <23 IRQ_TYPE_EDGE_RISING>; + reset-gpios = <&gpio3 27 GPIO_ACTIVE_LOW>; }; }; -- cgit v1.2.3-59-g8ed1b From e264b086f40a3d74a405227db8b624b4b15906e0 Mon Sep 17 00:00:00 2001 From: Javier Carrasco Date: Sun, 3 Mar 2024 22:54:22 +0100 Subject: iio: humidity: hdc3020: add reset management The HDC3020 provides an active low reset signal that must be handled if connected. Asserting this signal turns the device into Trigger-on Demand measurement mode, reducing its power consumption when no measurements are required like in low-power modes. According to the datasheet, the longest "Reset Ready" is 3 ms, which is only taken into account if the reset signal is defined. Signed-off-by: Javier Carrasco Link: https://lore.kernel.org/r/20240303-hdc3020-pm-v3-3-48bc02b5241b@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/humidity/hdc3020.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/iio/humidity/hdc3020.c b/drivers/iio/humidity/hdc3020.c index 7f93024b850c..cdc4789213ba 100644 --- a/drivers/iio/humidity/hdc3020.c +++ b/drivers/iio/humidity/hdc3020.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -70,6 +71,7 @@ struct hdc3020_data { struct i2c_client *client; + struct gpio_desc *reset_gpio; struct regulator *vdd_supply; /* * Ensure that the sensor configuration (currently only heater is @@ -558,6 +560,9 @@ static int hdc3020_power_off(struct hdc3020_data *data) { hdc3020_exec_cmd(data, HDC3020_EXIT_AUTO); + if (data->reset_gpio) + gpiod_set_value_cansleep(data->reset_gpio, 1); + return regulator_disable(data->vdd_supply); } @@ -571,6 +576,11 @@ static int hdc3020_power_on(struct hdc3020_data *data) fsleep(5000); + if (data->reset_gpio) { + gpiod_set_value_cansleep(data->reset_gpio, 0); + fsleep(3000); + } + if (data->client->irq) { /* * The alert output is activated by default upon power up, @@ -627,6 +637,12 @@ static int hdc3020_probe(struct i2c_client *client) return dev_err_probe(&client->dev, PTR_ERR(data->vdd_supply), "Unable to get VDD regulator\n"); + data->reset_gpio = devm_gpiod_get_optional(&client->dev, "reset", + GPIOD_OUT_HIGH); + if (IS_ERR(data->reset_gpio)) + return dev_err_probe(&client->dev, PTR_ERR(data->reset_gpio), + "Cannot get reset GPIO\n"); + ret = hdc3020_power_on(data); if (ret) return dev_err_probe(&client->dev, ret, "Power on failed\n"); -- cgit v1.2.3-59-g8ed1b From 0b70c0844955a7d0fd24048e53fdd62e94f4e0e9 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Maneyrol Date: Mon, 11 Mar 2024 16:05:54 +0000 Subject: iio: imu: inv_mpu6050: add WoM (Wake-on-Motion) sensor WoM is a threshold test on accel value comparing actual sample with previous one. It maps best to roc rising event. Add support of a new WOM sensor and functions for handling the associated roc_rising event. The event value is in SI units. Ensure WOM is stopped and restarted at suspend-resume, handle usage with buffer data ready interrupt, and handle change in sampling rate impacting already set roc value. Signed-off-by: Jean-Baptiste Maneyrol Link: https://lore.kernel.org/r/20240311160557.437337-2-inv.git-commit@tdk.com Signed-off-by: Jonathan Cameron --- drivers/iio/imu/inv_mpu6050/inv_mpu_core.c | 282 +++++++++++++++++++++++++- drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h | 20 +- drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c | 6 +- drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c | 14 +- 4 files changed, 309 insertions(+), 13 deletions(-) diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c index 0e94e5335e93..46607d404e59 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c @@ -15,6 +15,8 @@ #include #include #include +#include +#include #include #include #include @@ -332,7 +334,7 @@ static int inv_mpu6050_clock_switch(struct inv_mpu6050_state *st, int inv_mpu6050_switch_engine(struct inv_mpu6050_state *st, bool en, unsigned int mask) { - unsigned int sleep; + unsigned int sleep, val; u8 pwr_mgmt2, user_ctrl; int ret; @@ -345,6 +347,14 @@ int inv_mpu6050_switch_engine(struct inv_mpu6050_state *st, bool en, mask &= ~INV_MPU6050_SENSOR_TEMP; if (mask & INV_MPU6050_SENSOR_MAGN && en == st->chip_config.magn_en) mask &= ~INV_MPU6050_SENSOR_MAGN; + if (mask & INV_MPU6050_SENSOR_WOM && en == st->chip_config.wom_en) + mask &= ~INV_MPU6050_SENSOR_WOM; + + /* force accel on if WoM is on and not going off */ + if (!en && (mask & INV_MPU6050_SENSOR_ACCL) && st->chip_config.wom_en && + !(mask & INV_MPU6050_SENSOR_WOM)) + mask &= ~INV_MPU6050_SENSOR_ACCL; + if (mask == 0) return 0; @@ -439,6 +449,16 @@ int inv_mpu6050_switch_engine(struct inv_mpu6050_state *st, bool en, } } + /* enable/disable accel intelligence control */ + if (mask & INV_MPU6050_SENSOR_WOM) { + val = en ? INV_MPU6500_BIT_ACCEL_INTEL_EN | + INV_MPU6500_BIT_ACCEL_INTEL_MODE : 0; + ret = regmap_write(st->map, INV_MPU6500_REG_ACCEL_INTEL_CTRL, val); + if (ret) + return ret; + st->chip_config.wom_en = en; + } + return 0; } @@ -893,6 +913,239 @@ error_write_raw_unlock: return result; } +static u64 inv_mpu6050_convert_wom_to_roc(unsigned int threshold, unsigned int freq_div) +{ + /* 4mg per LSB converted in m/s² in micro (1000000) */ + const unsigned int convert = 4U * 9807U; + u64 value; + + value = threshold * convert; + + /* compute the differential by multiplying by the frequency */ + return div_u64(value * INV_MPU6050_INTERNAL_FREQ_HZ, freq_div); +} + +static unsigned int inv_mpu6050_convert_roc_to_wom(u64 roc, unsigned int freq_div) +{ + /* 4mg per LSB converted in m/s² in micro (1000000) */ + const unsigned int convert = 4U * 9807U; + u64 value; + + /* return 0 only if roc is 0 */ + if (roc == 0) + return 0; + + value = div_u64(roc * freq_div, convert * INV_MPU6050_INTERNAL_FREQ_HZ); + + /* limit value to 8 bits and prevent 0 */ + return min(255, max(1, value)); +} + +static int inv_mpu6050_set_wom_int(struct inv_mpu6050_state *st, bool on) +{ + unsigned int reg_val, val; + + switch (st->chip_type) { + case INV_MPU6050: + case INV_MPU6500: + case INV_MPU6515: + case INV_MPU6880: + case INV_MPU6000: + case INV_MPU9150: + case INV_MPU9250: + case INV_MPU9255: + reg_val = INV_MPU6500_BIT_WOM_INT_EN; + break; + default: + reg_val = INV_ICM20608_BIT_WOM_INT_EN; + break; + } + + val = on ? reg_val : 0; + + return regmap_update_bits(st->map, st->reg->int_enable, reg_val, val); +} + +static int inv_mpu6050_set_wom_threshold(struct inv_mpu6050_state *st, u64 value, + unsigned int freq_div) +{ + unsigned int threshold; + int result; + + /* convert roc to wom threshold and convert back to handle clipping */ + threshold = inv_mpu6050_convert_roc_to_wom(value, freq_div); + value = inv_mpu6050_convert_wom_to_roc(threshold, freq_div); + + dev_dbg(regmap_get_device(st->map), "wom_threshold: 0x%x\n", threshold); + + switch (st->chip_type) { + case INV_ICM20609: + case INV_ICM20689: + case INV_ICM20600: + case INV_ICM20602: + case INV_ICM20690: + st->data[0] = threshold; + st->data[1] = threshold; + st->data[2] = threshold; + result = regmap_bulk_write(st->map, INV_ICM20609_REG_ACCEL_WOM_X_THR, + st->data, 3); + break; + default: + result = regmap_write(st->map, INV_MPU6500_REG_WOM_THRESHOLD, threshold); + break; + } + if (result) + return result; + + st->chip_config.roc_threshold = value; + + return 0; +} + +static int inv_mpu6050_enable_wom(struct inv_mpu6050_state *st, bool en) +{ + struct device *pdev = regmap_get_device(st->map); + unsigned int mask; + int result; + + if (en) { + result = pm_runtime_resume_and_get(pdev); + if (result) + return result; + + mask = INV_MPU6050_SENSOR_ACCL | INV_MPU6050_SENSOR_WOM; + result = inv_mpu6050_switch_engine(st, true, mask); + if (result) + goto error_suspend; + + result = inv_mpu6050_set_wom_int(st, true); + if (result) + goto error_suspend; + } else { + result = inv_mpu6050_set_wom_int(st, false); + if (result) + dev_err(pdev, "error %d disabling WoM interrupt bit", result); + + /* disable only WoM and let accel be disabled by autosuspend */ + result = inv_mpu6050_switch_engine(st, false, INV_MPU6050_SENSOR_WOM); + if (result) { + dev_err(pdev, "error %d disabling WoM force off", result); + /* force WoM off */ + st->chip_config.wom_en = false; + } + + pm_runtime_mark_last_busy(pdev); + pm_runtime_put_autosuspend(pdev); + } + + return result; + +error_suspend: + pm_runtime_mark_last_busy(pdev); + pm_runtime_put_autosuspend(pdev); + return result; +} + +static int inv_mpu6050_read_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir) +{ + struct inv_mpu6050_state *st = iio_priv(indio_dev); + + /* support only WoM (accel roc rising) event */ + if (chan->type != IIO_ACCEL || type != IIO_EV_TYPE_ROC || + dir != IIO_EV_DIR_RISING) + return -EINVAL; + + guard(mutex)(&st->lock); + + return st->chip_config.wom_en ? 1 : 0; +} + +static int inv_mpu6050_write_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + int state) +{ + struct inv_mpu6050_state *st = iio_priv(indio_dev); + int enable; + + /* support only WoM (accel roc rising) event */ + if (chan->type != IIO_ACCEL || type != IIO_EV_TYPE_ROC || + dir != IIO_EV_DIR_RISING) + return -EINVAL; + + enable = !!state; + + guard(mutex)(&st->lock); + + if (st->chip_config.wom_en == enable) + return 0; + + return inv_mpu6050_enable_wom(st, enable); +} + +static int inv_mpu6050_read_event_value(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int *val, int *val2) +{ + struct inv_mpu6050_state *st = iio_priv(indio_dev); + u32 rem; + + /* support only WoM (accel roc rising) event value */ + if (chan->type != IIO_ACCEL || type != IIO_EV_TYPE_ROC || + dir != IIO_EV_DIR_RISING || info != IIO_EV_INFO_VALUE) + return -EINVAL; + + guard(mutex)(&st->lock); + + /* return value in micro */ + *val = div_u64_rem(st->chip_config.roc_threshold, 1000000U, &rem); + *val2 = rem; + + return IIO_VAL_INT_PLUS_MICRO; +} + +static int inv_mpu6050_write_event_value(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int val, int val2) +{ + struct inv_mpu6050_state *st = iio_priv(indio_dev); + struct device *pdev = regmap_get_device(st->map); + u64 value; + int result; + + /* support only WoM (accel roc rising) event value */ + if (chan->type != IIO_ACCEL || type != IIO_EV_TYPE_ROC || + dir != IIO_EV_DIR_RISING || info != IIO_EV_INFO_VALUE) + return -EINVAL; + + if (val < 0 || val2 < 0) + return -EINVAL; + + guard(mutex)(&st->lock); + + result = pm_runtime_resume_and_get(pdev); + if (result) + return result; + + value = (u64)val * 1000000ULL + (u64)val2; + result = inv_mpu6050_set_wom_threshold(st, value, INV_MPU6050_FREQ_DIVIDER(st)); + + pm_runtime_mark_last_busy(pdev); + pm_runtime_put_autosuspend(pdev); + + return result; +} + /* * inv_mpu6050_set_lpf() - set low pass filer based on fifo rate. * @@ -989,6 +1242,12 @@ inv_mpu6050_fifo_rate_store(struct device *dev, struct device_attribute *attr, if (result) goto fifo_rate_fail_power_off; + /* update wom threshold since roc is dependent on sampling frequency */ + result = inv_mpu6050_set_wom_threshold(st, st->chip_config.roc_threshold, + INV_MPU6050_FREQ_DIVIDER(st)); + if (result) + goto fifo_rate_fail_power_off; + pm_runtime_mark_last_busy(pdev); fifo_rate_fail_power_off: pm_runtime_put_autosuspend(pdev); @@ -1326,6 +1585,10 @@ static const struct iio_info mpu_info = { .write_raw = &inv_mpu6050_write_raw, .write_raw_get_fmt = &inv_write_raw_get_fmt, .attrs = &inv_attribute_group, + .read_event_config = inv_mpu6050_read_event_config, + .write_event_config = inv_mpu6050_write_event_config, + .read_event_value = inv_mpu6050_read_event_value, + .write_event_value = inv_mpu6050_write_event_value, .validate_trigger = inv_mpu6050_validate_trigger, .debugfs_reg_access = &inv_mpu6050_reg_access, }; @@ -1706,6 +1969,12 @@ static int inv_mpu_resume(struct device *dev) if (result) goto out_unlock; + if (st->chip_config.wom_en) { + result = inv_mpu6050_set_wom_int(st, true); + if (result) + goto out_unlock; + } + if (iio_buffer_enabled(indio_dev)) result = inv_mpu6050_prepare_fifo(st, true); @@ -1735,6 +2004,12 @@ static int inv_mpu_suspend(struct device *dev) goto out_unlock; } + if (st->chip_config.wom_en) { + result = inv_mpu6050_set_wom_int(st, false); + if (result) + goto out_unlock; + } + if (st->chip_config.accl_en) st->suspended_sensors |= INV_MPU6050_SENSOR_ACCL; if (st->chip_config.gyro_en) @@ -1743,6 +2018,8 @@ static int inv_mpu_suspend(struct device *dev) st->suspended_sensors |= INV_MPU6050_SENSOR_TEMP; if (st->chip_config.magn_en) st->suspended_sensors |= INV_MPU6050_SENSOR_MAGN; + if (st->chip_config.wom_en) + st->suspended_sensors |= INV_MPU6050_SENSOR_WOM; result = inv_mpu6050_switch_engine(st, false, st->suspended_sensors); if (result) goto out_unlock; @@ -1767,7 +2044,8 @@ static int inv_mpu_runtime_suspend(struct device *dev) mutex_lock(&st->lock); sensors = INV_MPU6050_SENSOR_ACCL | INV_MPU6050_SENSOR_GYRO | - INV_MPU6050_SENSOR_TEMP | INV_MPU6050_SENSOR_MAGN; + INV_MPU6050_SENSOR_TEMP | INV_MPU6050_SENSOR_MAGN | + INV_MPU6050_SENSOR_WOM; ret = inv_mpu6050_switch_engine(st, false, sensors); if (ret) goto out_unlock; diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h index 5950e2419ebb..58bb5242ae0a 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h @@ -88,11 +88,12 @@ enum inv_devices { INV_NUM_PARTS }; -/* chip sensors mask: accelerometer, gyroscope, temperature, magnetometer */ +/* chip sensors mask: accelerometer, gyroscope, temperature, magnetometer, WoM */ #define INV_MPU6050_SENSOR_ACCL BIT(0) #define INV_MPU6050_SENSOR_GYRO BIT(1) #define INV_MPU6050_SENSOR_TEMP BIT(2) #define INV_MPU6050_SENSOR_MAGN BIT(3) +#define INV_MPU6050_SENSOR_WOM BIT(4) /** * struct inv_mpu6050_chip_config - Cached chip configuration data. @@ -104,11 +105,13 @@ enum inv_devices { * @gyro_en: gyro engine enabled * @temp_en: temperature sensor enabled * @magn_en: magn engine (i2c master) enabled + * @wom_en: Wake-on-Motion enabled * @accl_fifo_enable: enable accel data output * @gyro_fifo_enable: enable gyro data output * @temp_fifo_enable: enable temp data output * @magn_fifo_enable: enable magn data output * @divider: chip sample rate divider (sample rate divider - 1) + * @roc_threshold: save ROC threshold (WoM) set value */ struct inv_mpu6050_chip_config { unsigned int clk:3; @@ -119,12 +122,14 @@ struct inv_mpu6050_chip_config { unsigned int gyro_en:1; unsigned int temp_en:1; unsigned int magn_en:1; + unsigned int wom_en:1; unsigned int accl_fifo_enable:1; unsigned int gyro_fifo_enable:1; unsigned int temp_fifo_enable:1; unsigned int magn_fifo_enable:1; u8 divider; u8 user_ctrl; + u64 roc_threshold; }; /* @@ -256,12 +261,16 @@ struct inv_mpu6050_state { #define INV_MPU6050_REG_INT_ENABLE 0x38 #define INV_MPU6050_BIT_DATA_RDY_EN 0x01 #define INV_MPU6050_BIT_DMP_INT_EN 0x02 +#define INV_MPU6500_BIT_WOM_INT_EN BIT(6) +#define INV_ICM20608_BIT_WOM_INT_EN GENMASK(7, 5) #define INV_MPU6050_REG_RAW_ACCEL 0x3B #define INV_MPU6050_REG_TEMPERATURE 0x41 #define INV_MPU6050_REG_RAW_GYRO 0x43 #define INV_MPU6050_REG_INT_STATUS 0x3A +#define INV_MPU6500_BIT_WOM_INT BIT(6) +#define INV_ICM20608_BIT_WOM_INT GENMASK(7, 5) #define INV_MPU6050_BIT_FIFO_OVERFLOW_INT 0x10 #define INV_MPU6050_BIT_RAW_DATA_RDY_INT 0x01 @@ -301,6 +310,11 @@ struct inv_mpu6050_state { #define INV_MPU6050_BIT_PWR_ACCL_STBY 0x38 #define INV_MPU6050_BIT_PWR_GYRO_STBY 0x07 +/* ICM20609 registers */ +#define INV_ICM20609_REG_ACCEL_WOM_X_THR 0x20 +#define INV_ICM20609_REG_ACCEL_WOM_Y_THR 0x21 +#define INV_ICM20609_REG_ACCEL_WOM_Z_THR 0x22 + /* ICM20602 register */ #define INV_ICM20602_REG_I2C_IF 0x70 #define INV_ICM20602_BIT_I2C_IF_DIS 0x40 @@ -320,6 +334,10 @@ struct inv_mpu6050_state { /* mpu6500 registers */ #define INV_MPU6500_REG_ACCEL_CONFIG_2 0x1D #define INV_ICM20689_BITS_FIFO_SIZE_MAX 0xC0 +#define INV_MPU6500_REG_WOM_THRESHOLD 0x1F +#define INV_MPU6500_REG_ACCEL_INTEL_CTRL 0x69 +#define INV_MPU6500_BIT_ACCEL_INTEL_EN BIT(7) +#define INV_MPU6500_BIT_ACCEL_INTEL_MODE BIT(6) #define INV_MPU6500_REG_ACCEL_OFFSET 0x77 /* delay time in milliseconds */ diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c index d4f9b5d8d28d..f1620d5f4423 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c @@ -33,10 +33,8 @@ static int inv_reset_fifo(struct iio_dev *indio_dev) reset_fifo_fail: dev_err(regmap_get_device(st->map), "reset fifo failed %d\n", result); - result = regmap_write(st->map, st->reg->int_enable, - INV_MPU6050_BIT_DATA_RDY_EN); - - return result; + return regmap_update_bits(st->map, st->reg->int_enable, + INV_MPU6050_BIT_DATA_RDY_EN, INV_MPU6050_BIT_DATA_RDY_EN); } /* diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c index e6e6e94452a3..30bcba334239 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c @@ -135,11 +135,13 @@ int inv_mpu6050_prepare_fifo(struct inv_mpu6050_state *st, bool enable) ret = regmap_write(st->map, st->reg->user_ctrl, d); if (ret) return ret; - /* enable interrupt */ - ret = regmap_write(st->map, st->reg->int_enable, - INV_MPU6050_BIT_DATA_RDY_EN); + /* enable data interrupt */ + ret = regmap_update_bits(st->map, st->reg->int_enable, + INV_MPU6050_BIT_DATA_RDY_EN, INV_MPU6050_BIT_DATA_RDY_EN); } else { - ret = regmap_write(st->map, st->reg->int_enable, 0); + /* disable data interrupt */ + ret = regmap_update_bits(st->map, st->reg->int_enable, + INV_MPU6050_BIT_DATA_RDY_EN, 0); if (ret) return ret; ret = regmap_write(st->map, st->reg->fifo_en, 0); @@ -172,9 +174,9 @@ static int inv_mpu6050_set_enable(struct iio_dev *indio_dev, bool enable) return result; /* * In case autosuspend didn't trigger, turn off first not - * required sensors. + * required sensors excepted WoM */ - result = inv_mpu6050_switch_engine(st, false, ~scan); + result = inv_mpu6050_switch_engine(st, false, ~scan & ~INV_MPU6050_SENSOR_WOM); if (result) goto error_power_off; result = inv_mpu6050_switch_engine(st, true, scan); -- cgit v1.2.3-59-g8ed1b From d0e79bebce8b11f100a9c9b43852c2ed98dcac51 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Maneyrol Date: Mon, 11 Mar 2024 16:05:55 +0000 Subject: iio: imu: inv_mpu6050: add WoM event as accel event Add WoM (roc rising) event as accel x_or_y_or_z event for all chips >= MPU-6500. This requires to create new MPU-6500 channels as default and MPU-6050 channels for older chips. Signed-off-by: Jean-Baptiste Maneyrol Link: https://lore.kernel.org/r/20240311160557.437337-3-inv.git-commit@tdk.com Signed-off-by: Jonathan Cameron --- drivers/iio/imu/inv_mpu6050/inv_mpu_core.c | 67 ++++++++++++++++++++++++++---- 1 file changed, 59 insertions(+), 8 deletions(-) diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c index 46607d404e59..eb341b87c8f3 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c @@ -1348,6 +1348,15 @@ static const struct iio_chan_spec_ext_info inv_ext_info[] = { { } }; +static const struct iio_event_spec inv_wom_events[] = { + { + .type = IIO_EV_TYPE_ROC, + .dir = IIO_EV_DIR_RISING, + .mask_separate = BIT(IIO_EV_INFO_ENABLE) | + BIT(IIO_EV_INFO_VALUE), + }, +}; + #define INV_MPU6050_CHAN(_type, _channel2, _index) \ { \ .type = _type, \ @@ -1383,7 +1392,17 @@ static const struct iio_chan_spec_ext_info inv_ext_info[] = { }, \ } -static const struct iio_chan_spec inv_mpu_channels[] = { +#define INV_MPU6050_EVENT_CHAN(_type, _channel2, _events, _events_nb) \ +{ \ + .type = _type, \ + .modified = 1, \ + .channel2 = _channel2, \ + .event_spec = _events, \ + .num_event_specs = _events_nb, \ + .scan_index = -1, \ +} + +static const struct iio_chan_spec inv_mpu6050_channels[] = { IIO_CHAN_SOFT_TIMESTAMP(INV_MPU6050_SCAN_TIMESTAMP), INV_MPU6050_TEMP_CHAN(INV_MPU6050_SCAN_TEMP), @@ -1397,6 +1416,23 @@ static const struct iio_chan_spec inv_mpu_channels[] = { INV_MPU6050_CHAN(IIO_ACCEL, IIO_MOD_Z, INV_MPU6050_SCAN_ACCL_Z), }; +static const struct iio_chan_spec inv_mpu6500_channels[] = { + IIO_CHAN_SOFT_TIMESTAMP(INV_MPU6050_SCAN_TIMESTAMP), + + INV_MPU6050_TEMP_CHAN(INV_MPU6050_SCAN_TEMP), + + INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_X, INV_MPU6050_SCAN_GYRO_X), + INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_Y, INV_MPU6050_SCAN_GYRO_Y), + INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_Z, INV_MPU6050_SCAN_GYRO_Z), + + INV_MPU6050_CHAN(IIO_ACCEL, IIO_MOD_X, INV_MPU6050_SCAN_ACCL_X), + INV_MPU6050_CHAN(IIO_ACCEL, IIO_MOD_Y, INV_MPU6050_SCAN_ACCL_Y), + INV_MPU6050_CHAN(IIO_ACCEL, IIO_MOD_Z, INV_MPU6050_SCAN_ACCL_Z), + + INV_MPU6050_EVENT_CHAN(IIO_ACCEL, IIO_MOD_X_OR_Y_OR_Z, + inv_wom_events, ARRAY_SIZE(inv_wom_events)), +}; + #define INV_MPU6050_SCAN_MASK_3AXIS_ACCEL \ (BIT(INV_MPU6050_SCAN_ACCL_X) \ | BIT(INV_MPU6050_SCAN_ACCL_Y) \ @@ -1876,6 +1912,12 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name, return result; switch (chip_type) { + case INV_MPU6000: + case INV_MPU6050: + indio_dev->channels = inv_mpu6050_channels; + indio_dev->num_channels = ARRAY_SIZE(inv_mpu6050_channels); + indio_dev->available_scan_masks = inv_mpu_scan_masks; + break; case INV_MPU9150: indio_dev->channels = inv_mpu9150_channels; indio_dev->num_channels = ARRAY_SIZE(inv_mpu9150_channels); @@ -1889,13 +1931,13 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name, break; case INV_ICM20600: case INV_ICM20602: - indio_dev->channels = inv_mpu_channels; - indio_dev->num_channels = ARRAY_SIZE(inv_mpu_channels); + indio_dev->channels = inv_mpu6500_channels; + indio_dev->num_channels = ARRAY_SIZE(inv_mpu6500_channels); indio_dev->available_scan_masks = inv_icm20602_scan_masks; break; default: - indio_dev->channels = inv_mpu_channels; - indio_dev->num_channels = ARRAY_SIZE(inv_mpu_channels); + indio_dev->channels = inv_mpu6500_channels; + indio_dev->num_channels = ARRAY_SIZE(inv_mpu6500_channels); indio_dev->available_scan_masks = inv_mpu_scan_masks; break; } @@ -1904,9 +1946,18 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name, * auxiliary device in use. Otherwise Going back to 6-axis only. */ if (st->magn_disabled) { - indio_dev->channels = inv_mpu_channels; - indio_dev->num_channels = ARRAY_SIZE(inv_mpu_channels); - indio_dev->available_scan_masks = inv_mpu_scan_masks; + switch (chip_type) { + case INV_MPU9150: + indio_dev->channels = inv_mpu6050_channels; + indio_dev->num_channels = ARRAY_SIZE(inv_mpu6050_channels); + indio_dev->available_scan_masks = inv_mpu_scan_masks; + break; + default: + indio_dev->channels = inv_mpu6500_channels; + indio_dev->num_channels = ARRAY_SIZE(inv_mpu6500_channels); + indio_dev->available_scan_masks = inv_mpu_scan_masks; + break; + } } indio_dev->info = &mpu_info; -- cgit v1.2.3-59-g8ed1b From 5537f653d9be09a591063395c0d9ae97c6a4b23f Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Maneyrol Date: Mon, 11 Mar 2024 16:05:56 +0000 Subject: iio: imu: inv_mpu6050: add new interrupt handler for WoM events Add new interrupt handler for generating WoM event from int status register bits. Launch from interrupt the trigger poll function for data buffer. Signed-off-by: Jean-Baptiste Maneyrol Link: https://lore.kernel.org/r/20240311160557.437337-4-inv.git-commit@tdk.com Signed-off-by: Jonathan Cameron --- drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h | 2 + drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c | 11 ----- drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c | 69 +++++++++++++++++++++++++-- 3 files changed, 66 insertions(+), 16 deletions(-) diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h index 58bb5242ae0a..f48a8f642c3e 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h @@ -185,6 +185,7 @@ struct inv_mpu6050_hw { * @magn_orient: magnetometer sensor chip orientation if available. * @suspended_sensors: sensors mask of sensors turned off for suspend * @data: read buffer used for bulk reads. + * @it_timestamp: interrupt timestamp. */ struct inv_mpu6050_state { struct mutex lock; @@ -210,6 +211,7 @@ struct inv_mpu6050_state { unsigned int suspended_sensors; bool level_shifter; u8 *data; + s64 it_timestamp; }; /*register and associated bit definition*/ diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c index f1620d5f4423..86465226f7e1 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c @@ -51,21 +51,10 @@ irqreturn_t inv_mpu6050_read_fifo(int irq, void *p) u32 fifo_period; s64 timestamp; u8 data[INV_MPU6050_OUTPUT_DATA_SIZE]; - int int_status; size_t i, nb; mutex_lock(&st->lock); - /* ack interrupt and check status */ - result = regmap_read(st->map, st->reg->int_status, &int_status); - if (result) { - dev_err(regmap_get_device(st->map), - "failed to ack interrupt\n"); - goto flush_fifo; - } - if (!(int_status & INV_MPU6050_BIT_RAW_DATA_RDY_INT)) - goto end_session; - if (!(st->chip_config.accl_fifo_enable | st->chip_config.gyro_fifo_enable | st->chip_config.magn_fifo_enable)) diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c index 30bcba334239..1b603567ccc8 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c @@ -6,6 +6,7 @@ #include #include +#include #include "inv_mpu_iio.h" @@ -228,6 +229,65 @@ static const struct iio_trigger_ops inv_mpu_trigger_ops = { .set_trigger_state = &inv_mpu_data_rdy_trigger_set_state, }; +static irqreturn_t inv_mpu6050_interrupt_timestamp(int irq, void *p) +{ + struct iio_dev *indio_dev = p; + struct inv_mpu6050_state *st = iio_priv(indio_dev); + + st->it_timestamp = iio_get_time_ns(indio_dev); + + return IRQ_WAKE_THREAD; +} + +static irqreturn_t inv_mpu6050_interrupt_handle(int irq, void *p) +{ + struct iio_dev *indio_dev = p; + struct inv_mpu6050_state *st = iio_priv(indio_dev); + unsigned int int_status, wom_bits; + u64 ev_code; + int result; + + switch (st->chip_type) { + case INV_MPU6050: + case INV_MPU6500: + case INV_MPU6515: + case INV_MPU6880: + case INV_MPU6000: + case INV_MPU9150: + case INV_MPU9250: + case INV_MPU9255: + wom_bits = INV_MPU6500_BIT_WOM_INT; + break; + default: + wom_bits = INV_ICM20608_BIT_WOM_INT; + break; + } + + scoped_guard(mutex, &st->lock) { + /* ack interrupt and check status */ + result = regmap_read(st->map, st->reg->int_status, &int_status); + if (result) { + dev_err(regmap_get_device(st->map), "failed to ack interrupt\n"); + return IRQ_HANDLED; + } + + /* handle WoM event */ + if (st->chip_config.wom_en && (int_status & wom_bits)) { + ev_code = IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_X_OR_Y_OR_Z, + IIO_EV_TYPE_ROC, IIO_EV_DIR_RISING); + iio_push_event(indio_dev, ev_code, st->it_timestamp); + } + } + + /* handle raw data interrupt */ + if (int_status & INV_MPU6050_BIT_RAW_DATA_RDY_INT) { + indio_dev->pollfunc->timestamp = st->it_timestamp; + iio_trigger_poll_nested(st->trig); + } + + return IRQ_HANDLED; +} + int inv_mpu6050_probe_trigger(struct iio_dev *indio_dev, int irq_type) { int ret; @@ -240,11 +300,10 @@ int inv_mpu6050_probe_trigger(struct iio_dev *indio_dev, int irq_type) if (!st->trig) return -ENOMEM; - ret = devm_request_irq(&indio_dev->dev, st->irq, - &iio_trigger_generic_data_rdy_poll, - irq_type, - "inv_mpu", - st->trig); + ret = devm_request_threaded_irq(&indio_dev->dev, st->irq, + &inv_mpu6050_interrupt_timestamp, + &inv_mpu6050_interrupt_handle, + irq_type, "inv_mpu", indio_dev); if (ret) return ret; -- cgit v1.2.3-59-g8ed1b From 305914d018077a125b0541b196ed080804f72106 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Maneyrol Date: Mon, 11 Mar 2024 16:05:57 +0000 Subject: iio: imu: inv_mpu6050: add WoM suspend wakeup with low-power mode Add wakeup from suspend for WoM when enabled and put accel in low-power mode when suspended. Requires rewriting pwr_mgmt_1 register handling and factorize out accel LPF settings. Use a low-power rate similar to the chip sampling rate but always lower for a best match of the sampling rate while saving power and adjust threshold to follow the required roc value. Signed-off-by: Jean-Baptiste Maneyrol Link: https://lore.kernel.org/r/20240311160557.437337-5-inv.git-commit@tdk.com Signed-off-by: Jonathan Cameron --- drivers/iio/imu/inv_mpu6050/inv_mpu_core.c | 203 +++++++++++++++++++++-------- drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h | 14 ++ 2 files changed, 166 insertions(+), 51 deletions(-) diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c index eb341b87c8f3..14d95f34e981 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c @@ -289,7 +289,7 @@ static const struct inv_mpu6050_hw hw_info[] = { }; static int inv_mpu6050_pwr_mgmt_1_write(struct inv_mpu6050_state *st, bool sleep, - int clock, int temp_dis) + bool cycle, int clock, int temp_dis) { u8 val; @@ -303,6 +303,8 @@ static int inv_mpu6050_pwr_mgmt_1_write(struct inv_mpu6050_state *st, bool sleep val |= INV_MPU6050_BIT_TEMP_DIS; if (sleep) val |= INV_MPU6050_BIT_SLEEP; + if (cycle) + val |= INV_MPU6050_BIT_CYCLE; dev_dbg(regmap_get_device(st->map), "pwr_mgmt_1: 0x%x\n", val); return regmap_write(st->map, st->reg->pwr_mgmt_1, val); @@ -318,7 +320,7 @@ static int inv_mpu6050_clock_switch(struct inv_mpu6050_state *st, case INV_MPU6000: case INV_MPU9150: /* old chips: switch clock manually */ - ret = inv_mpu6050_pwr_mgmt_1_write(st, false, clock, -1); + ret = inv_mpu6050_pwr_mgmt_1_write(st, false, false, clock, -1); if (ret) return ret; st->chip_config.clk = clock; @@ -360,7 +362,7 @@ int inv_mpu6050_switch_engine(struct inv_mpu6050_state *st, bool en, /* turn on/off temperature sensor */ if (mask & INV_MPU6050_SENSOR_TEMP) { - ret = inv_mpu6050_pwr_mgmt_1_write(st, false, -1, !en); + ret = inv_mpu6050_pwr_mgmt_1_write(st, false, false, -1, !en); if (ret) return ret; st->chip_config.temp_en = en; @@ -467,7 +469,7 @@ static int inv_mpu6050_set_power_itg(struct inv_mpu6050_state *st, { int result; - result = inv_mpu6050_pwr_mgmt_1_write(st, !power_on, -1, -1); + result = inv_mpu6050_pwr_mgmt_1_write(st, !power_on, false, -1, -1); if (result) return result; @@ -497,22 +499,9 @@ static int inv_mpu6050_set_gyro_fsr(struct inv_mpu6050_state *st, return regmap_write(st->map, st->reg->gyro_config, data); } -/* - * inv_mpu6050_set_lpf_regs() - set low pass filter registers, chip dependent - * - * MPU60xx/MPU9150 use only 1 register for accelerometer + gyroscope - * MPU6500 and above have a dedicated register for accelerometer - */ -static int inv_mpu6050_set_lpf_regs(struct inv_mpu6050_state *st, - enum inv_mpu6050_filter_e val) +static int inv_mpu6050_set_accel_lpf_regs(struct inv_mpu6050_state *st, + enum inv_mpu6050_filter_e val) { - int result; - - result = regmap_write(st->map, st->reg->lpf, val); - if (result) - return result; - - /* set accel lpf */ switch (st->chip_type) { case INV_MPU6050: case INV_MPU6000: @@ -531,6 +520,25 @@ static int inv_mpu6050_set_lpf_regs(struct inv_mpu6050_state *st, return regmap_write(st->map, st->reg->accel_lpf, val); } +/* + * inv_mpu6050_set_lpf_regs() - set low pass filter registers, chip dependent + * + * MPU60xx/MPU9150 use only 1 register for accelerometer + gyroscope + * MPU6500 and above have a dedicated register for accelerometer + */ +static int inv_mpu6050_set_lpf_regs(struct inv_mpu6050_state *st, + enum inv_mpu6050_filter_e val) +{ + int result; + + result = regmap_write(st->map, st->reg->lpf, val); + if (result) + return result; + + /* set accel lpf */ + return inv_mpu6050_set_accel_lpf_regs(st, val); +} + /* * inv_mpu6050_init_config() - Initialize hardware, disable FIFO. * @@ -1002,6 +1010,84 @@ static int inv_mpu6050_set_wom_threshold(struct inv_mpu6050_state *st, u64 value return 0; } +static int inv_mpu6050_set_lp_odr(struct inv_mpu6050_state *st, unsigned int freq_div, + unsigned int *lp_div) +{ + static const unsigned int freq_dividers[] = {2, 4, 8, 16, 32, 64, 128, 256}; + static const unsigned int reg_values[] = { + INV_MPU6050_LPOSC_500HZ, INV_MPU6050_LPOSC_250HZ, + INV_MPU6050_LPOSC_125HZ, INV_MPU6050_LPOSC_62HZ, + INV_MPU6050_LPOSC_31HZ, INV_MPU6050_LPOSC_16HZ, + INV_MPU6050_LPOSC_8HZ, INV_MPU6050_LPOSC_4HZ, + }; + unsigned int val, i; + + switch (st->chip_type) { + case INV_ICM20609: + case INV_ICM20689: + case INV_ICM20600: + case INV_ICM20602: + case INV_ICM20690: + /* nothing to do */ + *lp_div = INV_MPU6050_FREQ_DIVIDER(st); + return 0; + default: + break; + } + + /* found the nearest superior frequency divider */ + i = ARRAY_SIZE(reg_values) - 1; + val = reg_values[i]; + *lp_div = freq_dividers[i]; + for (i = 0; i < ARRAY_SIZE(freq_dividers); ++i) { + if (freq_div <= freq_dividers[i]) { + val = reg_values[i]; + *lp_div = freq_dividers[i]; + break; + } + } + + dev_dbg(regmap_get_device(st->map), "lp_odr: 0x%x\n", val); + return regmap_write(st->map, INV_MPU6500_REG_LP_ODR, val); +} + +static int inv_mpu6050_set_wom_lp(struct inv_mpu6050_state *st, bool on) +{ + unsigned int lp_div; + int result; + + if (on) { + /* set low power ODR */ + result = inv_mpu6050_set_lp_odr(st, INV_MPU6050_FREQ_DIVIDER(st), &lp_div); + if (result) + return result; + /* disable accel low pass filter */ + result = inv_mpu6050_set_accel_lpf_regs(st, INV_MPU6050_FILTER_NOLPF); + if (result) + return result; + /* update wom threshold with new low-power frequency divider */ + result = inv_mpu6050_set_wom_threshold(st, st->chip_config.roc_threshold, lp_div); + if (result) + return result; + /* set cycle mode */ + result = inv_mpu6050_pwr_mgmt_1_write(st, false, true, -1, -1); + } else { + /* disable cycle mode */ + result = inv_mpu6050_pwr_mgmt_1_write(st, false, false, -1, -1); + if (result) + return result; + /* restore wom threshold */ + result = inv_mpu6050_set_wom_threshold(st, st->chip_config.roc_threshold, + INV_MPU6050_FREQ_DIVIDER(st)); + if (result) + return result; + /* restore accel low pass filter */ + result = inv_mpu6050_set_accel_lpf_regs(st, st->chip_config.lpf); + } + + return result; +} + static int inv_mpu6050_enable_wom(struct inv_mpu6050_state *st, bool en) { struct device *pdev = regmap_get_device(st->map); @@ -1836,6 +1922,7 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name, irq_type); return -EINVAL; } + device_set_wakeup_capable(dev, true); st->vdd_supply = devm_regulator_get(dev, "vdd"); if (IS_ERR(st->vdd_supply)) @@ -2001,16 +2088,27 @@ static int inv_mpu_resume(struct device *dev) { struct iio_dev *indio_dev = dev_get_drvdata(dev); struct inv_mpu6050_state *st = iio_priv(indio_dev); + bool wakeup; int result; - mutex_lock(&st->lock); - result = inv_mpu_core_enable_regulator_vddio(st); - if (result) - goto out_unlock; + guard(mutex)(&st->lock); - result = inv_mpu6050_set_power_itg(st, true); - if (result) - goto out_unlock; + wakeup = device_may_wakeup(dev) && st->chip_config.wom_en; + + if (wakeup) { + enable_irq(st->irq); + disable_irq_wake(st->irq); + result = inv_mpu6050_set_wom_lp(st, false); + if (result) + return result; + } else { + result = inv_mpu_core_enable_regulator_vddio(st); + if (result) + return result; + result = inv_mpu6050_set_power_itg(st, true); + if (result) + return result; + } pm_runtime_disable(dev); pm_runtime_set_active(dev); @@ -2018,20 +2116,17 @@ static int inv_mpu_resume(struct device *dev) result = inv_mpu6050_switch_engine(st, true, st->suspended_sensors); if (result) - goto out_unlock; + return result; - if (st->chip_config.wom_en) { + if (st->chip_config.wom_en && !wakeup) { result = inv_mpu6050_set_wom_int(st, true); if (result) - goto out_unlock; + return result; } if (iio_buffer_enabled(indio_dev)) result = inv_mpu6050_prepare_fifo(st, true); -out_unlock: - mutex_unlock(&st->lock); - return result; } @@ -2039,29 +2134,30 @@ static int inv_mpu_suspend(struct device *dev) { struct iio_dev *indio_dev = dev_get_drvdata(dev); struct inv_mpu6050_state *st = iio_priv(indio_dev); + bool wakeup; int result; - mutex_lock(&st->lock); + guard(mutex)(&st->lock); st->suspended_sensors = 0; - if (pm_runtime_suspended(dev)) { - result = 0; - goto out_unlock; - } + if (pm_runtime_suspended(dev)) + return 0; if (iio_buffer_enabled(indio_dev)) { result = inv_mpu6050_prepare_fifo(st, false); if (result) - goto out_unlock; + return result; } - if (st->chip_config.wom_en) { + wakeup = device_may_wakeup(dev) && st->chip_config.wom_en; + + if (st->chip_config.wom_en && !wakeup) { result = inv_mpu6050_set_wom_int(st, false); if (result) - goto out_unlock; + return result; } - if (st->chip_config.accl_en) + if (st->chip_config.accl_en && !wakeup) st->suspended_sensors |= INV_MPU6050_SENSOR_ACCL; if (st->chip_config.gyro_en) st->suspended_sensors |= INV_MPU6050_SENSOR_GYRO; @@ -2069,21 +2165,26 @@ static int inv_mpu_suspend(struct device *dev) st->suspended_sensors |= INV_MPU6050_SENSOR_TEMP; if (st->chip_config.magn_en) st->suspended_sensors |= INV_MPU6050_SENSOR_MAGN; - if (st->chip_config.wom_en) + if (st->chip_config.wom_en && !wakeup) st->suspended_sensors |= INV_MPU6050_SENSOR_WOM; result = inv_mpu6050_switch_engine(st, false, st->suspended_sensors); if (result) - goto out_unlock; - - result = inv_mpu6050_set_power_itg(st, false); - if (result) - goto out_unlock; + return result; - inv_mpu_core_disable_regulator_vddio(st); -out_unlock: - mutex_unlock(&st->lock); + if (wakeup) { + result = inv_mpu6050_set_wom_lp(st, true); + if (result) + return result; + enable_irq_wake(st->irq); + disable_irq(st->irq); + } else { + result = inv_mpu6050_set_power_itg(st, false); + if (result) + return result; + inv_mpu_core_disable_regulator_vddio(st); + } - return result; + return 0; } static int inv_mpu_runtime_suspend(struct device *dev) diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h index f48a8f642c3e..e1c0c5146876 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h @@ -305,6 +305,7 @@ struct inv_mpu6050_state { #define INV_MPU6050_REG_PWR_MGMT_1 0x6B #define INV_MPU6050_BIT_H_RESET 0x80 #define INV_MPU6050_BIT_SLEEP 0x40 +#define INV_MPU6050_BIT_CYCLE 0x20 #define INV_MPU6050_BIT_TEMP_DIS 0x08 #define INV_MPU6050_BIT_CLK_MASK 0x7 @@ -336,6 +337,7 @@ struct inv_mpu6050_state { /* mpu6500 registers */ #define INV_MPU6500_REG_ACCEL_CONFIG_2 0x1D #define INV_ICM20689_BITS_FIFO_SIZE_MAX 0xC0 +#define INV_MPU6500_REG_LP_ODR 0x1E #define INV_MPU6500_REG_WOM_THRESHOLD 0x1F #define INV_MPU6500_REG_ACCEL_INTEL_CTRL 0x69 #define INV_MPU6500_BIT_ACCEL_INTEL_EN BIT(7) @@ -452,6 +454,18 @@ enum inv_mpu6050_filter_e { NUM_MPU6050_FILTER }; +enum inv_mpu6050_lposc_e { + INV_MPU6050_LPOSC_4HZ = 4, + INV_MPU6050_LPOSC_8HZ, + INV_MPU6050_LPOSC_16HZ, + INV_MPU6050_LPOSC_31HZ, + INV_MPU6050_LPOSC_62HZ, + INV_MPU6050_LPOSC_125HZ, + INV_MPU6050_LPOSC_250HZ, + INV_MPU6050_LPOSC_500HZ, + NUM_MPU6050_LPOSC, +}; + /* IIO attribute address */ enum INV_MPU6050_IIO_ATTR_ADDR { ATTR_GYRO_MATRIX, -- cgit v1.2.3-59-g8ed1b From 42ea59925387e8468f490155ffdc382aba2539ae Mon Sep 17 00:00:00 2001 From: Nuno Sa Date: Thu, 29 Feb 2024 16:10:25 +0100 Subject: iio: core: move to cleanup.h magic Use the new cleanup magic for handling mutexes in IIO. This allows us to greatly simplify some code paths. Note that we keep the plain mutex calls in the iio_device_release|acquire() APIs since in there the macros would likely not help much (as we want to keep the lock acquired when he leave the APIs). Signed-off-by: Nuno Sa Link: https://lore.kernel.org/r/20240229-iio-use-cleanup-magic-v3-1-c3d34889ae3c@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/industrialio-core.c | 34 +++++++++++++--------------------- 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index c7ad88932015..fa7cc051b4c4 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -1810,31 +1811,24 @@ static long iio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) struct iio_dev *indio_dev = ib->indio_dev; struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); struct iio_ioctl_handler *h; - int ret = -ENODEV; - - mutex_lock(&iio_dev_opaque->info_exist_lock); + int ret; + guard(mutex)(&iio_dev_opaque->info_exist_lock); /* * The NULL check here is required to prevent crashing when a device * is being removed while userspace would still have open file handles * to try to access this device. */ if (!indio_dev->info) - goto out_unlock; + return -ENODEV; list_for_each_entry(h, &iio_dev_opaque->ioctl_handlers, entry) { ret = h->ioctl(indio_dev, filp, cmd, arg); if (ret != IIO_IOCTL_UNHANDLED) - break; + return ret; } - if (ret == IIO_IOCTL_UNHANDLED) - ret = -ENODEV; - -out_unlock: - mutex_unlock(&iio_dev_opaque->info_exist_lock); - - return ret; + return -ENODEV; } static const struct file_operations iio_buffer_fileops = { @@ -2062,18 +2056,16 @@ void iio_device_unregister(struct iio_dev *indio_dev) cdev_device_del(&iio_dev_opaque->chrdev, &indio_dev->dev); - mutex_lock(&iio_dev_opaque->info_exist_lock); - - iio_device_unregister_debugfs(indio_dev); + scoped_guard(mutex, &iio_dev_opaque->info_exist_lock) { + iio_device_unregister_debugfs(indio_dev); - iio_disable_all_buffers(indio_dev); + iio_disable_all_buffers(indio_dev); - indio_dev->info = NULL; + indio_dev->info = NULL; - iio_device_wakeup_eventset(indio_dev); - iio_buffer_wakeup_poll(indio_dev); - - mutex_unlock(&iio_dev_opaque->info_exist_lock); + iio_device_wakeup_eventset(indio_dev); + iio_buffer_wakeup_poll(indio_dev); + } iio_buffers_free_sysfs_and_mask(indio_dev); } -- cgit v1.2.3-59-g8ed1b From 095be2d5305580122810d5dcad14d61a4d10c023 Mon Sep 17 00:00:00 2001 From: Nuno Sa Date: Thu, 29 Feb 2024 16:10:26 +0100 Subject: iio: trigger: move to the cleanup.h magic Use the new cleanup magic for handling mutexes in IIO. This allows us to greatly simplify some code paths. Signed-off-by: Nuno Sa Link: https://lore.kernel.org/r/20240229-iio-use-cleanup-magic-v3-2-c3d34889ae3c@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/industrialio-trigger.c | 71 ++++++++++++++++---------------------- 1 file changed, 30 insertions(+), 41 deletions(-) diff --git a/drivers/iio/industrialio-trigger.c b/drivers/iio/industrialio-trigger.c index 18f83158f637..16de57846bd9 100644 --- a/drivers/iio/industrialio-trigger.c +++ b/drivers/iio/industrialio-trigger.c @@ -4,6 +4,7 @@ * Copyright (c) 2008 Jonathan Cameron */ +#include #include #include #include @@ -80,19 +81,18 @@ int iio_trigger_register(struct iio_trigger *trig_info) goto error_unregister_id; /* Add to list of available triggers held by the IIO core */ - mutex_lock(&iio_trigger_list_lock); - if (__iio_trigger_find_by_name(trig_info->name)) { - pr_err("Duplicate trigger name '%s'\n", trig_info->name); - ret = -EEXIST; - goto error_device_del; + scoped_guard(mutex, &iio_trigger_list_lock) { + if (__iio_trigger_find_by_name(trig_info->name)) { + pr_err("Duplicate trigger name '%s'\n", trig_info->name); + ret = -EEXIST; + goto error_device_del; + } + list_add_tail(&trig_info->list, &iio_trigger_list); } - list_add_tail(&trig_info->list, &iio_trigger_list); - mutex_unlock(&iio_trigger_list_lock); return 0; error_device_del: - mutex_unlock(&iio_trigger_list_lock); device_del(&trig_info->dev); error_unregister_id: ida_free(&iio_trigger_ida, trig_info->id); @@ -102,9 +102,8 @@ EXPORT_SYMBOL(iio_trigger_register); void iio_trigger_unregister(struct iio_trigger *trig_info) { - mutex_lock(&iio_trigger_list_lock); - list_del(&trig_info->list); - mutex_unlock(&iio_trigger_list_lock); + scoped_guard(mutex, &iio_trigger_list_lock) + list_del(&trig_info->list); ida_free(&iio_trigger_ida, trig_info->id); /* Possible issue in here */ @@ -120,12 +119,11 @@ int iio_trigger_set_immutable(struct iio_dev *indio_dev, struct iio_trigger *tri return -EINVAL; iio_dev_opaque = to_iio_dev_opaque(indio_dev); - mutex_lock(&iio_dev_opaque->mlock); + guard(mutex)(&iio_dev_opaque->mlock); WARN_ON(iio_dev_opaque->trig_readonly); indio_dev->trig = iio_trigger_get(trig); iio_dev_opaque->trig_readonly = true; - mutex_unlock(&iio_dev_opaque->mlock); return 0; } @@ -145,18 +143,14 @@ static struct iio_trigger *__iio_trigger_find_by_name(const char *name) static struct iio_trigger *iio_trigger_acquire_by_name(const char *name) { - struct iio_trigger *trig = NULL, *iter; + struct iio_trigger *iter; - mutex_lock(&iio_trigger_list_lock); + guard(mutex)(&iio_trigger_list_lock); list_for_each_entry(iter, &iio_trigger_list, list) - if (sysfs_streq(iter->name, name)) { - trig = iter; - iio_trigger_get(trig); - break; - } - mutex_unlock(&iio_trigger_list_lock); + if (sysfs_streq(iter->name, name)) + return iio_trigger_get(iter); - return trig; + return NULL; } static void iio_reenable_work_fn(struct work_struct *work) @@ -259,22 +253,21 @@ static int iio_trigger_get_irq(struct iio_trigger *trig) { int ret; - mutex_lock(&trig->pool_lock); - ret = bitmap_find_free_region(trig->pool, - CONFIG_IIO_CONSUMERS_PER_TRIGGER, - ilog2(1)); - mutex_unlock(&trig->pool_lock); - if (ret >= 0) - ret += trig->subirq_base; + scoped_guard(mutex, &trig->pool_lock) { + ret = bitmap_find_free_region(trig->pool, + CONFIG_IIO_CONSUMERS_PER_TRIGGER, + ilog2(1)); + if (ret < 0) + return ret; + } - return ret; + return ret + trig->subirq_base; } static void iio_trigger_put_irq(struct iio_trigger *trig, int irq) { - mutex_lock(&trig->pool_lock); + guard(mutex)(&trig->pool_lock); clear_bit(irq - trig->subirq_base, trig->pool); - mutex_unlock(&trig->pool_lock); } /* Complexity in here. With certain triggers (datardy) an acknowledgement @@ -451,16 +444,12 @@ static ssize_t current_trigger_store(struct device *dev, struct iio_trigger *trig; int ret; - mutex_lock(&iio_dev_opaque->mlock); - if (iio_dev_opaque->currentmode == INDIO_BUFFER_TRIGGERED) { - mutex_unlock(&iio_dev_opaque->mlock); - return -EBUSY; - } - if (iio_dev_opaque->trig_readonly) { - mutex_unlock(&iio_dev_opaque->mlock); - return -EPERM; + scoped_guard(mutex, &iio_dev_opaque->mlock) { + if (iio_dev_opaque->currentmode == INDIO_BUFFER_TRIGGERED) + return -EBUSY; + if (iio_dev_opaque->trig_readonly) + return -EPERM; } - mutex_unlock(&iio_dev_opaque->mlock); trig = iio_trigger_acquire_by_name(buf); if (oldtrig == trig) { -- cgit v1.2.3-59-g8ed1b From 714b5b4c2c2431d830f0d5e9e85282beef40c747 Mon Sep 17 00:00:00 2001 From: Nuno Sa Date: Thu, 29 Feb 2024 16:10:27 +0100 Subject: iio: buffer: iio: core: move to the cleanup.h magic Use the new cleanup magic for handling mutexes in IIO. This allows us to greatly simplify some code paths. Signed-off-by: Nuno Sa Link: https://lore.kernel.org/r/20240229-iio-use-cleanup-magic-v3-3-c3d34889ae3c@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/industrialio-buffer.c | 120 +++++++++++++++----------------------- 1 file changed, 47 insertions(+), 73 deletions(-) diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c index b581a7e80566..1d950a3e153b 100644 --- a/drivers/iio/industrialio-buffer.c +++ b/drivers/iio/industrialio-buffer.c @@ -10,6 +10,7 @@ * - Alternative access techniques? */ #include +#include #include #include #include @@ -533,28 +534,26 @@ static ssize_t iio_scan_el_store(struct device *dev, ret = kstrtobool(buf, &state); if (ret < 0) return ret; - mutex_lock(&iio_dev_opaque->mlock); - if (iio_buffer_is_active(buffer)) { - ret = -EBUSY; - goto error_ret; - } + + guard(mutex)(&iio_dev_opaque->mlock); + if (iio_buffer_is_active(buffer)) + return -EBUSY; + ret = iio_scan_mask_query(indio_dev, buffer, this_attr->address); if (ret < 0) - goto error_ret; - if (!state && ret) { - ret = iio_scan_mask_clear(buffer, this_attr->address); - if (ret) - goto error_ret; - } else if (state && !ret) { - ret = iio_scan_mask_set(indio_dev, buffer, this_attr->address); - if (ret) - goto error_ret; - } + return ret; -error_ret: - mutex_unlock(&iio_dev_opaque->mlock); + if (state && ret) + return len; - return ret < 0 ? ret : len; + if (state) + ret = iio_scan_mask_set(indio_dev, buffer, this_attr->address); + else + ret = iio_scan_mask_clear(buffer, this_attr->address); + if (ret) + return ret; + + return len; } static ssize_t iio_scan_el_ts_show(struct device *dev, @@ -581,16 +580,13 @@ static ssize_t iio_scan_el_ts_store(struct device *dev, if (ret < 0) return ret; - mutex_lock(&iio_dev_opaque->mlock); - if (iio_buffer_is_active(buffer)) { - ret = -EBUSY; - goto error_ret; - } + guard(mutex)(&iio_dev_opaque->mlock); + if (iio_buffer_is_active(buffer)) + return -EBUSY; + buffer->scan_timestamp = state; -error_ret: - mutex_unlock(&iio_dev_opaque->mlock); - return ret ? ret : len; + return len; } static int iio_buffer_add_channel_sysfs(struct iio_dev *indio_dev, @@ -674,21 +670,16 @@ static ssize_t length_store(struct device *dev, struct device_attribute *attr, if (val == buffer->length) return len; - mutex_lock(&iio_dev_opaque->mlock); - if (iio_buffer_is_active(buffer)) { - ret = -EBUSY; - } else { - buffer->access->set_length(buffer, val); - ret = 0; - } - if (ret) - goto out; + guard(mutex)(&iio_dev_opaque->mlock); + if (iio_buffer_is_active(buffer)) + return -EBUSY; + + buffer->access->set_length(buffer, val); + if (buffer->length && buffer->length < buffer->watermark) buffer->watermark = buffer->length; -out: - mutex_unlock(&iio_dev_opaque->mlock); - return ret ? ret : len; + return len; } static ssize_t enable_show(struct device *dev, struct device_attribute *attr, @@ -1268,7 +1259,6 @@ int iio_update_buffers(struct iio_dev *indio_dev, struct iio_buffer *remove_buffer) { struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); - int ret; if (insert_buffer == remove_buffer) return 0; @@ -1277,8 +1267,8 @@ int iio_update_buffers(struct iio_dev *indio_dev, insert_buffer->direction == IIO_BUFFER_DIRECTION_OUT) return -EINVAL; - mutex_lock(&iio_dev_opaque->info_exist_lock); - mutex_lock(&iio_dev_opaque->mlock); + guard(mutex)(&iio_dev_opaque->info_exist_lock); + guard(mutex)(&iio_dev_opaque->mlock); if (insert_buffer && iio_buffer_is_active(insert_buffer)) insert_buffer = NULL; @@ -1286,23 +1276,13 @@ int iio_update_buffers(struct iio_dev *indio_dev, if (remove_buffer && !iio_buffer_is_active(remove_buffer)) remove_buffer = NULL; - if (!insert_buffer && !remove_buffer) { - ret = 0; - goto out_unlock; - } - - if (!indio_dev->info) { - ret = -ENODEV; - goto out_unlock; - } - - ret = __iio_update_buffers(indio_dev, insert_buffer, remove_buffer); + if (!insert_buffer && !remove_buffer) + return 0; -out_unlock: - mutex_unlock(&iio_dev_opaque->mlock); - mutex_unlock(&iio_dev_opaque->info_exist_lock); + if (!indio_dev->info) + return -ENODEV; - return ret; + return __iio_update_buffers(indio_dev, insert_buffer, remove_buffer); } EXPORT_SYMBOL_GPL(iio_update_buffers); @@ -1326,22 +1306,22 @@ static ssize_t enable_store(struct device *dev, struct device_attribute *attr, if (ret < 0) return ret; - mutex_lock(&iio_dev_opaque->mlock); + guard(mutex)(&iio_dev_opaque->mlock); /* Find out if it is in the list */ inlist = iio_buffer_is_active(buffer); /* Already in desired state */ if (inlist == requested_state) - goto done; + return len; if (requested_state) ret = __iio_update_buffers(indio_dev, buffer, NULL); else ret = __iio_update_buffers(indio_dev, NULL, buffer); + if (ret) + return ret; -done: - mutex_unlock(&iio_dev_opaque->mlock); - return (ret < 0) ? ret : len; + return len; } static ssize_t watermark_show(struct device *dev, struct device_attribute *attr, @@ -1368,23 +1348,17 @@ static ssize_t watermark_store(struct device *dev, if (!val) return -EINVAL; - mutex_lock(&iio_dev_opaque->mlock); + guard(mutex)(&iio_dev_opaque->mlock); - if (val > buffer->length) { - ret = -EINVAL; - goto out; - } + if (val > buffer->length) + return -EINVAL; - if (iio_buffer_is_active(buffer)) { - ret = -EBUSY; - goto out; - } + if (iio_buffer_is_active(buffer)) + return -EBUSY; buffer->watermark = val; -out: - mutex_unlock(&iio_dev_opaque->mlock); - return ret ? ret : len; + return len; } static ssize_t data_available_show(struct device *dev, -- cgit v1.2.3-59-g8ed1b From 3092bde731ca8c499fa8a4a9e987904abfbf55bf Mon Sep 17 00:00:00 2001 From: Nuno Sa Date: Thu, 29 Feb 2024 16:10:28 +0100 Subject: iio: inkern: move to the cleanup.h magic Use the new cleanup magic for handling mutexes in IIO. This allows us to greatly simplify some code paths. While at it, also use __free(kfree) where allocations are done and drop obvious comment in iio_channel_read_min(). Signed-off-by: Nuno Sa Link: https://lore.kernel.org/r/20240229-iio-use-cleanup-magic-v3-4-c3d34889ae3c@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/inkern.c | 263 +++++++++++++++++---------------------------------- 1 file changed, 89 insertions(+), 174 deletions(-) diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c index 7a1f6713318a..52d773261828 100644 --- a/drivers/iio/inkern.c +++ b/drivers/iio/inkern.c @@ -3,6 +3,7 @@ * * Copyright (c) 2011 Jonathan Cameron */ +#include #include #include #include @@ -43,13 +44,14 @@ static int iio_map_array_unregister_locked(struct iio_dev *indio_dev) int iio_map_array_register(struct iio_dev *indio_dev, struct iio_map *maps) { - int i = 0, ret = 0; struct iio_map_internal *mapi; + int i = 0; + int ret; if (!maps) return 0; - mutex_lock(&iio_map_list_lock); + guard(mutex)(&iio_map_list_lock); while (maps[i].consumer_dev_name) { mapi = kzalloc(sizeof(*mapi), GFP_KERNEL); if (!mapi) { @@ -61,11 +63,10 @@ int iio_map_array_register(struct iio_dev *indio_dev, struct iio_map *maps) list_add_tail(&mapi->l, &iio_map_list); i++; } -error_ret: - if (ret) - iio_map_array_unregister_locked(indio_dev); - mutex_unlock(&iio_map_list_lock); + return 0; +error_ret: + iio_map_array_unregister_locked(indio_dev); return ret; } EXPORT_SYMBOL_GPL(iio_map_array_register); @@ -75,13 +76,8 @@ EXPORT_SYMBOL_GPL(iio_map_array_register); */ int iio_map_array_unregister(struct iio_dev *indio_dev) { - int ret; - - mutex_lock(&iio_map_list_lock); - ret = iio_map_array_unregister_locked(indio_dev); - mutex_unlock(&iio_map_list_lock); - - return ret; + guard(mutex)(&iio_map_list_lock); + return iio_map_array_unregister_locked(indio_dev); } EXPORT_SYMBOL_GPL(iio_map_array_unregister); @@ -183,25 +179,21 @@ err_put: static struct iio_channel *fwnode_iio_channel_get(struct fwnode_handle *fwnode, int index) { - struct iio_channel *channel; int err; if (index < 0) return ERR_PTR(-EINVAL); - channel = kzalloc(sizeof(*channel), GFP_KERNEL); + struct iio_channel *channel __free(kfree) = + kzalloc(sizeof(*channel), GFP_KERNEL); if (!channel) return ERR_PTR(-ENOMEM); err = __fwnode_iio_channel_get(channel, fwnode, index); if (err) - goto err_free_channel; + return ERR_PTR(err); - return channel; - -err_free_channel: - kfree(channel); - return ERR_PTR(err); + return_ptr(channel); } static struct iio_channel * @@ -291,7 +283,6 @@ EXPORT_SYMBOL_GPL(fwnode_iio_channel_get_by_name); static struct iio_channel *fwnode_iio_channel_get_all(struct device *dev) { struct fwnode_handle *fwnode = dev_fwnode(dev); - struct iio_channel *chans; int i, mapind, nummaps = 0; int ret; @@ -307,7 +298,8 @@ static struct iio_channel *fwnode_iio_channel_get_all(struct device *dev) return ERR_PTR(-ENODEV); /* NULL terminated array to save passing size */ - chans = kcalloc(nummaps + 1, sizeof(*chans), GFP_KERNEL); + struct iio_channel *chans __free(kfree) = + kcalloc(nummaps + 1, sizeof(*chans), GFP_KERNEL); if (!chans) return ERR_PTR(-ENOMEM); @@ -317,12 +309,11 @@ static struct iio_channel *fwnode_iio_channel_get_all(struct device *dev) if (ret) goto error_free_chans; } - return chans; + return_ptr(chans); error_free_chans: for (i = 0; i < mapind; i++) iio_device_put(chans[i].indio_dev); - kfree(chans); return ERR_PTR(ret); } @@ -330,28 +321,28 @@ static struct iio_channel *iio_channel_get_sys(const char *name, const char *channel_name) { struct iio_map_internal *c_i = NULL, *c = NULL; - struct iio_channel *channel; int err; if (!(name || channel_name)) return ERR_PTR(-ENODEV); /* first find matching entry the channel map */ - mutex_lock(&iio_map_list_lock); - list_for_each_entry(c_i, &iio_map_list, l) { - if ((name && strcmp(name, c_i->map->consumer_dev_name) != 0) || - (channel_name && - strcmp(channel_name, c_i->map->consumer_channel) != 0)) - continue; - c = c_i; - iio_device_get(c->indio_dev); - break; + scoped_guard(mutex, &iio_map_list_lock) { + list_for_each_entry(c_i, &iio_map_list, l) { + if ((name && strcmp(name, c_i->map->consumer_dev_name) != 0) || + (channel_name && + strcmp(channel_name, c_i->map->consumer_channel) != 0)) + continue; + c = c_i; + iio_device_get(c->indio_dev); + break; + } } - mutex_unlock(&iio_map_list_lock); if (!c) return ERR_PTR(-ENODEV); - channel = kzalloc(sizeof(*channel), GFP_KERNEL); + struct iio_channel *channel __free(kfree) = + kzalloc(sizeof(*channel), GFP_KERNEL); if (!channel) { err = -ENOMEM; goto error_no_mem; @@ -366,14 +357,12 @@ static struct iio_channel *iio_channel_get_sys(const char *name, if (!channel->channel) { err = -EINVAL; - goto error_no_chan; + goto error_no_mem; } } - return channel; + return_ptr(channel); -error_no_chan: - kfree(channel); error_no_mem: iio_device_put(c->indio_dev); return ERR_PTR(err); @@ -450,8 +439,8 @@ EXPORT_SYMBOL_GPL(devm_fwnode_iio_channel_get_by_name); struct iio_channel *iio_channel_get_all(struct device *dev) { const char *name; - struct iio_channel *chans; struct iio_map_internal *c = NULL; + struct iio_channel *fw_chans; int nummaps = 0; int mapind = 0; int i, ret; @@ -459,17 +448,17 @@ struct iio_channel *iio_channel_get_all(struct device *dev) if (!dev) return ERR_PTR(-EINVAL); - chans = fwnode_iio_channel_get_all(dev); + fw_chans = fwnode_iio_channel_get_all(dev); /* * We only want to carry on if the error is -ENODEV. Anything else * should be reported up the stack. */ - if (!IS_ERR(chans) || PTR_ERR(chans) != -ENODEV) - return chans; + if (!IS_ERR(fw_chans) || PTR_ERR(fw_chans) != -ENODEV) + return fw_chans; name = dev_name(dev); - mutex_lock(&iio_map_list_lock); + guard(mutex)(&iio_map_list_lock); /* first count the matching maps */ list_for_each_entry(c, &iio_map_list, l) if (name && strcmp(name, c->map->consumer_dev_name) != 0) @@ -477,17 +466,14 @@ struct iio_channel *iio_channel_get_all(struct device *dev) else nummaps++; - if (nummaps == 0) { - ret = -ENODEV; - goto error_ret; - } + if (nummaps == 0) + return ERR_PTR(-ENODEV); /* NULL terminated array to save passing size */ - chans = kcalloc(nummaps + 1, sizeof(*chans), GFP_KERNEL); - if (!chans) { - ret = -ENOMEM; - goto error_ret; - } + struct iio_channel *chans __free(kfree) = + kcalloc(nummaps + 1, sizeof(*chans), GFP_KERNEL); + if (!chans) + return ERR_PTR(-ENOMEM); /* for each map fill in the chans element */ list_for_each_entry(c, &iio_map_list, l) { @@ -509,17 +495,12 @@ struct iio_channel *iio_channel_get_all(struct device *dev) ret = -ENODEV; goto error_free_chans; } - mutex_unlock(&iio_map_list_lock); - return chans; + return_ptr(chans); error_free_chans: for (i = 0; i < nummaps; i++) iio_device_put(chans[i].indio_dev); - kfree(chans); -error_ret: - mutex_unlock(&iio_map_list_lock); - return ERR_PTR(ret); } EXPORT_SYMBOL_GPL(iio_channel_get_all); @@ -590,38 +571,24 @@ static int iio_channel_read(struct iio_channel *chan, int *val, int *val2, int iio_read_channel_raw(struct iio_channel *chan, int *val) { struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(chan->indio_dev); - int ret; - mutex_lock(&iio_dev_opaque->info_exist_lock); - if (!chan->indio_dev->info) { - ret = -ENODEV; - goto err_unlock; - } - - ret = iio_channel_read(chan, val, NULL, IIO_CHAN_INFO_RAW); -err_unlock: - mutex_unlock(&iio_dev_opaque->info_exist_lock); + guard(mutex)(&iio_dev_opaque->info_exist_lock); + if (!chan->indio_dev->info) + return -ENODEV; - return ret; + return iio_channel_read(chan, val, NULL, IIO_CHAN_INFO_RAW); } EXPORT_SYMBOL_GPL(iio_read_channel_raw); int iio_read_channel_average_raw(struct iio_channel *chan, int *val) { struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(chan->indio_dev); - int ret; - mutex_lock(&iio_dev_opaque->info_exist_lock); - if (!chan->indio_dev->info) { - ret = -ENODEV; - goto err_unlock; - } - - ret = iio_channel_read(chan, val, NULL, IIO_CHAN_INFO_AVERAGE_RAW); -err_unlock: - mutex_unlock(&iio_dev_opaque->info_exist_lock); + guard(mutex)(&iio_dev_opaque->info_exist_lock); + if (!chan->indio_dev->info) + return -ENODEV; - return ret; + return iio_channel_read(chan, val, NULL, IIO_CHAN_INFO_AVERAGE_RAW); } EXPORT_SYMBOL_GPL(iio_read_channel_average_raw); @@ -708,20 +675,13 @@ int iio_convert_raw_to_processed(struct iio_channel *chan, int raw, int *processed, unsigned int scale) { struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(chan->indio_dev); - int ret; - mutex_lock(&iio_dev_opaque->info_exist_lock); - if (!chan->indio_dev->info) { - ret = -ENODEV; - goto err_unlock; - } - - ret = iio_convert_raw_to_processed_unlocked(chan, raw, processed, - scale); -err_unlock: - mutex_unlock(&iio_dev_opaque->info_exist_lock); + guard(mutex)(&iio_dev_opaque->info_exist_lock); + if (!chan->indio_dev->info) + return -ENODEV; - return ret; + return iio_convert_raw_to_processed_unlocked(chan, raw, processed, + scale); } EXPORT_SYMBOL_GPL(iio_convert_raw_to_processed); @@ -729,19 +689,12 @@ int iio_read_channel_attribute(struct iio_channel *chan, int *val, int *val2, enum iio_chan_info_enum attribute) { struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(chan->indio_dev); - int ret; - mutex_lock(&iio_dev_opaque->info_exist_lock); - if (!chan->indio_dev->info) { - ret = -ENODEV; - goto err_unlock; - } - - ret = iio_channel_read(chan, val, val2, attribute); -err_unlock: - mutex_unlock(&iio_dev_opaque->info_exist_lock); + guard(mutex)(&iio_dev_opaque->info_exist_lock); + if (!chan->indio_dev->info) + return -ENODEV; - return ret; + return iio_channel_read(chan, val, val2, attribute); } EXPORT_SYMBOL_GPL(iio_read_channel_attribute); @@ -757,30 +710,26 @@ int iio_read_channel_processed_scale(struct iio_channel *chan, int *val, struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(chan->indio_dev); int ret; - mutex_lock(&iio_dev_opaque->info_exist_lock); - if (!chan->indio_dev->info) { - ret = -ENODEV; - goto err_unlock; - } + guard(mutex)(&iio_dev_opaque->info_exist_lock); + if (!chan->indio_dev->info) + return -ENODEV; if (iio_channel_has_info(chan->channel, IIO_CHAN_INFO_PROCESSED)) { ret = iio_channel_read(chan, val, NULL, IIO_CHAN_INFO_PROCESSED); if (ret < 0) - goto err_unlock; + return ret; *val *= scale; + + return 0; } else { ret = iio_channel_read(chan, val, NULL, IIO_CHAN_INFO_RAW); if (ret < 0) - goto err_unlock; - ret = iio_convert_raw_to_processed_unlocked(chan, *val, val, - scale); - } + return ret; -err_unlock: - mutex_unlock(&iio_dev_opaque->info_exist_lock); - - return ret; + return iio_convert_raw_to_processed_unlocked(chan, *val, val, + scale); + } } EXPORT_SYMBOL_GPL(iio_read_channel_processed_scale); @@ -813,19 +762,12 @@ int iio_read_avail_channel_attribute(struct iio_channel *chan, enum iio_chan_info_enum attribute) { struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(chan->indio_dev); - int ret; - - mutex_lock(&iio_dev_opaque->info_exist_lock); - if (!chan->indio_dev->info) { - ret = -ENODEV; - goto err_unlock; - } - ret = iio_channel_read_avail(chan, vals, type, length, attribute); -err_unlock: - mutex_unlock(&iio_dev_opaque->info_exist_lock); + guard(mutex)(&iio_dev_opaque->info_exist_lock); + if (!chan->indio_dev->info) + return -ENODEV; - return ret; + return iio_channel_read_avail(chan, vals, type, length, attribute); } EXPORT_SYMBOL_GPL(iio_read_avail_channel_attribute); @@ -892,20 +834,13 @@ static int iio_channel_read_max(struct iio_channel *chan, int iio_read_max_channel_raw(struct iio_channel *chan, int *val) { struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(chan->indio_dev); - int ret; int type; - mutex_lock(&iio_dev_opaque->info_exist_lock); - if (!chan->indio_dev->info) { - ret = -ENODEV; - goto err_unlock; - } - - ret = iio_channel_read_max(chan, val, NULL, &type, IIO_CHAN_INFO_RAW); -err_unlock: - mutex_unlock(&iio_dev_opaque->info_exist_lock); + guard(mutex)(&iio_dev_opaque->info_exist_lock); + if (!chan->indio_dev->info) + return -ENODEV; - return ret; + return iio_channel_read_max(chan, val, NULL, &type, IIO_CHAN_INFO_RAW); } EXPORT_SYMBOL_GPL(iio_read_max_channel_raw); @@ -955,40 +890,27 @@ static int iio_channel_read_min(struct iio_channel *chan, int iio_read_min_channel_raw(struct iio_channel *chan, int *val) { struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(chan->indio_dev); - int ret; int type; - mutex_lock(&iio_dev_opaque->info_exist_lock); - if (!chan->indio_dev->info) { - ret = -ENODEV; - goto err_unlock; - } - - ret = iio_channel_read_min(chan, val, NULL, &type, IIO_CHAN_INFO_RAW); -err_unlock: - mutex_unlock(&iio_dev_opaque->info_exist_lock); + guard(mutex)(&iio_dev_opaque->info_exist_lock); + if (!chan->indio_dev->info) + return -ENODEV; - return ret; + return iio_channel_read_min(chan, val, NULL, &type, IIO_CHAN_INFO_RAW); } EXPORT_SYMBOL_GPL(iio_read_min_channel_raw); int iio_get_channel_type(struct iio_channel *chan, enum iio_chan_type *type) { struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(chan->indio_dev); - int ret = 0; - /* Need to verify underlying driver has not gone away */ - mutex_lock(&iio_dev_opaque->info_exist_lock); - if (!chan->indio_dev->info) { - ret = -ENODEV; - goto err_unlock; - } + guard(mutex)(&iio_dev_opaque->info_exist_lock); + if (!chan->indio_dev->info) + return -ENODEV; *type = chan->channel->type; -err_unlock: - mutex_unlock(&iio_dev_opaque->info_exist_lock); - return ret; + return 0; } EXPORT_SYMBOL_GPL(iio_get_channel_type); @@ -1003,19 +925,12 @@ int iio_write_channel_attribute(struct iio_channel *chan, int val, int val2, enum iio_chan_info_enum attribute) { struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(chan->indio_dev); - int ret; - mutex_lock(&iio_dev_opaque->info_exist_lock); - if (!chan->indio_dev->info) { - ret = -ENODEV; - goto err_unlock; - } + guard(mutex)(&iio_dev_opaque->info_exist_lock); + if (!chan->indio_dev->info) + return -ENODEV; - ret = iio_channel_write(chan, val, val2, attribute); -err_unlock: - mutex_unlock(&iio_dev_opaque->info_exist_lock); - - return ret; + return iio_channel_write(chan, val, val2, attribute); } EXPORT_SYMBOL_GPL(iio_write_channel_attribute); -- cgit v1.2.3-59-g8ed1b From fcdb03e4310695013f6a6c5a29485b02b13e2662 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 15 Mar 2024 09:14:36 +0000 Subject: iio: accel: adxl367: Remove second semicolon There is a statement with two semicolons. Remove the second one, it is redundant. Signed-off-by: Colin Ian King Reviewed-by: Nuno Sa Link: https://lore.kernel.org/r/20240315091436.2430227-1-colin.i.king@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/accel/adxl367.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/accel/adxl367.c b/drivers/iio/accel/adxl367.c index 210228affb80..5cf4828a5eb5 100644 --- a/drivers/iio/accel/adxl367.c +++ b/drivers/iio/accel/adxl367.c @@ -621,7 +621,7 @@ static int _adxl367_set_odr(struct adxl367_state *st, enum adxl367_odr odr) static int adxl367_set_odr(struct iio_dev *indio_dev, enum adxl367_odr odr) { iio_device_claim_direct_scoped(return -EBUSY, indio_dev) { - struct adxl367_state *st = iio_priv(indio_dev);; + struct adxl367_state *st = iio_priv(indio_dev); int ret; guard(mutex)(&st->lock); -- cgit v1.2.3-59-g8ed1b From 346ae0e8276fe6fc5f0b7496e53343e1739ff5b0 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 14 Mar 2024 12:43:38 -0500 Subject: iio: adc: ad7944: Add support for "3-wire mode" This adds support for AD7944 ADCs wired in "3-wire mode". (NOTE: 3-wire is the datasheet name for this wiring configuration and has nothing to do with SPI_3WIRE.) In the 3-wire mode, the SPI controller CS line can be wired to the CNV line on the ADC and used to trigger conversions rather that using a separate GPIO line. The turbo/chain mode compatibility check at the end of the probe function is technically can't be triggered right now but adding it now anyway so that we don't forget to add it later when support for daisy-chaining is added. Reviewed-by: Nuno Sa Signed-off-by: David Lechner Link: https://lore.kernel.org/r/20240314-mainline-ad7944-3-wire-mode-v2-1-d469da0705d2@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7944.c | 157 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 139 insertions(+), 18 deletions(-) diff --git a/drivers/iio/adc/ad7944.c b/drivers/iio/adc/ad7944.c index adb007cdd287..d5ec6b5a41c7 100644 --- a/drivers/iio/adc/ad7944.c +++ b/drivers/iio/adc/ad7944.c @@ -32,8 +32,25 @@ struct ad7944_timing_spec { unsigned int turbo_conv_ns; }; +enum ad7944_spi_mode { + /* datasheet calls this "4-wire mode" */ + AD7944_SPI_MODE_DEFAULT, + /* datasheet calls this "3-wire mode" (not related to SPI_3WIRE!) */ + AD7944_SPI_MODE_SINGLE, + /* datasheet calls this "chain mode" */ + AD7944_SPI_MODE_CHAIN, +}; + +/* maps adi,spi-mode property value to enum */ +static const char * const ad7944_spi_modes[] = { + [AD7944_SPI_MODE_DEFAULT] = "", + [AD7944_SPI_MODE_SINGLE] = "single", + [AD7944_SPI_MODE_CHAIN] = "chain", +}; + struct ad7944_adc { struct spi_device *spi; + enum ad7944_spi_mode spi_mode; /* Chip-specific timing specifications. */ const struct ad7944_timing_spec *timing_spec; /* GPIO connected to CNV pin. */ @@ -58,6 +75,9 @@ struct ad7944_adc { } sample __aligned(IIO_DMA_MINALIGN); }; +/* quite time before CNV rising edge */ +#define T_QUIET_NS 20 + static const struct ad7944_timing_spec ad7944_timing_spec = { .conv_ns = 420, .turbo_conv_ns = 320, @@ -110,6 +130,65 @@ AD7944_DEFINE_CHIP_INFO(ad7985, ad7944, 16, 0); /* fully differential */ AD7944_DEFINE_CHIP_INFO(ad7986, ad7986, 18, 1); +/* + * ad7944_3wire_cs_mode_conversion - Perform a 3-wire CS mode conversion and + * acquisition + * @adc: The ADC device structure + * @chan: The channel specification + * Return: 0 on success, a negative error code on failure + * + * This performs a conversion and reads data when the chip is wired in 3-wire + * mode with the CNV line on the ADC tied to the CS line on the SPI controller. + * + * Upon successful return adc->sample.raw will contain the conversion result. + */ +static int ad7944_3wire_cs_mode_conversion(struct ad7944_adc *adc, + const struct iio_chan_spec *chan) +{ + unsigned int t_conv_ns = adc->always_turbo ? adc->timing_spec->turbo_conv_ns + : adc->timing_spec->conv_ns; + struct spi_transfer xfers[] = { + { + /* + * NB: can get better performance from some SPI + * controllers if we use the same bits_per_word + * in every transfer. + */ + .bits_per_word = chan->scan_type.realbits, + /* + * CS is tied to CNV and we need a low to high + * transition to start the conversion, so place CNV + * low for t_QUIET to prepare for this. + */ + .delay = { + .value = T_QUIET_NS, + .unit = SPI_DELAY_UNIT_NSECS, + }, + + }, + { + .bits_per_word = chan->scan_type.realbits, + /* + * CS has to be high for full conversion time to avoid + * triggering the busy indication. + */ + .cs_off = 1, + .delay = { + .value = t_conv_ns, + .unit = SPI_DELAY_UNIT_NSECS, + }, + }, + { + /* Then we can read the data during the acquisition phase */ + .rx_buf = &adc->sample.raw, + .len = BITS_TO_BYTES(chan->scan_type.storagebits), + .bits_per_word = chan->scan_type.realbits, + }, + }; + + return spi_sync_transfer(adc->spi, xfers, ARRAY_SIZE(xfers)); +} + /* * ad7944_4wire_mode_conversion - Perform a 4-wire mode conversion and acquisition * @adc: The ADC device structure @@ -167,9 +246,22 @@ static int ad7944_single_conversion(struct ad7944_adc *adc, { int ret; - ret = ad7944_4wire_mode_conversion(adc, chan); - if (ret) - return ret; + switch (adc->spi_mode) { + case AD7944_SPI_MODE_DEFAULT: + ret = ad7944_4wire_mode_conversion(adc, chan); + if (ret) + return ret; + + break; + case AD7944_SPI_MODE_SINGLE: + ret = ad7944_3wire_cs_mode_conversion(adc, chan); + if (ret) + return ret; + + break; + default: + return -EOPNOTSUPP; + } if (chan->scan_type.storagebits > 16) *val = adc->sample.raw.u32; @@ -230,9 +322,23 @@ static irqreturn_t ad7944_trigger_handler(int irq, void *p) struct ad7944_adc *adc = iio_priv(indio_dev); int ret; - ret = ad7944_4wire_mode_conversion(adc, &indio_dev->channels[0]); - if (ret) + switch (adc->spi_mode) { + case AD7944_SPI_MODE_DEFAULT: + ret = ad7944_4wire_mode_conversion(adc, &indio_dev->channels[0]); + if (ret) + goto out; + + break; + case AD7944_SPI_MODE_SINGLE: + ret = ad7944_3wire_cs_mode_conversion(adc, &indio_dev->channels[0]); + if (ret) + goto out; + + break; + default: + /* not supported */ goto out; + } iio_push_to_buffers_with_timestamp(indio_dev, &adc->sample.raw, pf->timestamp); @@ -260,16 +366,9 @@ static int ad7944_probe(struct spi_device *spi) struct ad7944_adc *adc; bool have_refin = false; struct regulator *ref; + const char *str_val; int ret; - /* - * driver currently only supports the conventional "4-wire" mode and - * not other special wiring configurations. - */ - if (device_property_present(dev, "adi,spi-mode")) - return dev_err_probe(dev, -EINVAL, - "adi,spi-mode is not currently supported\n"); - indio_dev = devm_iio_device_alloc(dev, sizeof(*adc)); if (!indio_dev) return -ENOMEM; @@ -283,6 +382,22 @@ static int ad7944_probe(struct spi_device *spi) adc->timing_spec = chip_info->timing_spec; + if (device_property_read_string(dev, "adi,spi-mode", &str_val) == 0) { + ret = sysfs_match_string(ad7944_spi_modes, str_val); + if (ret < 0) + return dev_err_probe(dev, -EINVAL, + "unsupported adi,spi-mode\n"); + + adc->spi_mode = ret; + } else { + /* absence of adi,spi-mode property means default mode */ + adc->spi_mode = AD7944_SPI_MODE_DEFAULT; + } + + if (adc->spi_mode == AD7944_SPI_MODE_CHAIN) + return dev_err_probe(dev, -EINVAL, + "chain mode is not implemented\n"); + /* * Some chips use unusual word sizes, so check now instead of waiting * for the first xfer. @@ -349,15 +464,17 @@ static int ad7944_probe(struct spi_device *spi) adc->ref_mv = AD7944_INTERNAL_REF_MV; } - /* - * CNV gpio is required in 4-wire mode which is the only currently - * supported mode. - */ - adc->cnv = devm_gpiod_get(dev, "cnv", GPIOD_OUT_LOW); + adc->cnv = devm_gpiod_get_optional(dev, "cnv", GPIOD_OUT_LOW); if (IS_ERR(adc->cnv)) return dev_err_probe(dev, PTR_ERR(adc->cnv), "failed to get CNV GPIO\n"); + if (!adc->cnv && adc->spi_mode == AD7944_SPI_MODE_DEFAULT) + return dev_err_probe(&spi->dev, -EINVAL, "CNV GPIO is required\n"); + if (adc->cnv && adc->spi_mode != AD7944_SPI_MODE_DEFAULT) + return dev_err_probe(&spi->dev, -EINVAL, + "CNV GPIO in single and chain mode is not currently supported\n"); + adc->turbo = devm_gpiod_get_optional(dev, "turbo", GPIOD_OUT_LOW); if (IS_ERR(adc->turbo)) return dev_err_probe(dev, PTR_ERR(adc->turbo), @@ -369,6 +486,10 @@ static int ad7944_probe(struct spi_device *spi) return dev_err_probe(dev, -EINVAL, "cannot have both turbo-gpios and adi,always-turbo\n"); + if (adc->spi_mode == AD7944_SPI_MODE_CHAIN && adc->always_turbo) + return dev_err_probe(dev, -EINVAL, + "cannot have both chain mode and always turbo\n"); + indio_dev->name = chip_info->name; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &ad7944_iio_info; -- cgit v1.2.3-59-g8ed1b From a1ba19a1ae7cd1e324685ded4ab563e78fe68648 Mon Sep 17 00:00:00 2001 From: Rui Miguel Silva Date: Mon, 25 Mar 2024 22:09:55 +0000 Subject: greybus: lights: check return of get_channel_from_mode If channel for the given node is not found we return null from get_channel_from_mode. Make sure we validate the return pointer before using it in two of the missing places. This was originally reported in [0]: Found by Linux Verification Center (linuxtesting.org) with SVACE. [0] https://lore.kernel.org/all/20240301190425.120605-1-m.lobanov@rosalinux.ru Fixes: 2870b52bae4c ("greybus: lights: add lights implementation") Reported-by: Mikhail Lobanov Suggested-by: Mikhail Lobanov Suggested-by: Alex Elder Signed-off-by: Rui Miguel Silva Link: https://lore.kernel.org/r/20240325221549.2185265-1-rmfrfs@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/greybus/light.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/staging/greybus/light.c b/drivers/staging/greybus/light.c index a5c2fe963866..00360f4a0485 100644 --- a/drivers/staging/greybus/light.c +++ b/drivers/staging/greybus/light.c @@ -142,6 +142,9 @@ static int __gb_lights_flash_brightness_set(struct gb_channel *channel) channel = get_channel_from_mode(channel->light, GB_CHANNEL_MODE_TORCH); + if (!channel) + return -EINVAL; + /* For not flash we need to convert brightness to intensity */ intensity = channel->intensity_uA.min + (channel->intensity_uA.step * channel->led->brightness); @@ -528,7 +531,10 @@ static int gb_lights_light_v4l2_register(struct gb_light *light) } channel_flash = get_channel_from_mode(light, GB_CHANNEL_MODE_FLASH); - WARN_ON(!channel_flash); + if (!channel_flash) { + dev_err(dev, "failed to get flash channel from mode\n"); + return -EINVAL; + } fled = &channel_flash->fled; -- cgit v1.2.3-59-g8ed1b From 83144b76344e3b753ef50b28efc0a6117b7a3a1e Mon Sep 17 00:00:00 2001 From: Ayush Tiwari Date: Mon, 25 Mar 2024 23:19:08 +0530 Subject: staging: rtl8712: rename backupPMKIDList to backup_PMKID_list Rename backupPMKIDList to backup_PMKID_list and remove extra spaces between RT_PMKID_LIST and backupPMKIDList to address checkpatch warnings and match the common kernel coding style. Signed-off-by: Ayush Tiwari Link: https://lore.kernel.org/r/5d3930cb847fd311afdd16c8fb947133ec49b55e.1711388443.git.ayushtiw0110@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8712/mlme_linux.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/staging/rtl8712/mlme_linux.c b/drivers/staging/rtl8712/mlme_linux.c index b9f5104f3bf7..a009ec1a5c11 100644 --- a/drivers/staging/rtl8712/mlme_linux.c +++ b/drivers/staging/rtl8712/mlme_linux.c @@ -84,7 +84,7 @@ void r8712_os_indicate_connect(struct _adapter *adapter) netif_carrier_on(adapter->pnetdev); } -static struct RT_PMKID_LIST backupPMKIDList[NUM_PMKID_CACHE]; +static struct RT_PMKID_LIST backup_PMKID_list[NUM_PMKID_CACHE]; void r8712_os_indicate_disconnect(struct _adapter *adapter) { u8 backupPMKIDIndex = 0; @@ -99,7 +99,7 @@ void r8712_os_indicate_disconnect(struct _adapter *adapter) * disconnect with AP for 60 seconds. */ - memcpy(&backupPMKIDList[0], + memcpy(&backup_PMKID_list[0], &adapter->securitypriv.PMKIDList[0], sizeof(struct RT_PMKID_LIST) * NUM_PMKID_CACHE); backupPMKIDIndex = adapter->securitypriv.PMKIDIndex; @@ -113,7 +113,7 @@ void r8712_os_indicate_disconnect(struct _adapter *adapter) * for the following connection. */ memcpy(&adapter->securitypriv.PMKIDList[0], - &backupPMKIDList[0], + &backup_PMKID_list[0], sizeof(struct RT_PMKID_LIST) * NUM_PMKID_CACHE); adapter->securitypriv.PMKIDIndex = backupPMKIDIndex; adapter->securitypriv.btkip_countermeasure = -- cgit v1.2.3-59-g8ed1b From a212650fa295fff5e2b231f8473d39bc47f3ad2a Mon Sep 17 00:00:00 2001 From: Ayush Tiwari Date: Mon, 25 Mar 2024 23:20:22 +0530 Subject: staging: rtl8712: rename backupPMKIDIndex to backup_PMKID_index Rename variable backupPMKIDIndex to backup_PMKID_index to address checkpatch warning 'Avoid Camelcase' and to ensure adherence to coding style guidelines. Signed-off-by: Ayush Tiwari Link: https://lore.kernel.org/r/2902ed6252d6773fecd32254383eefe8b0c465aa.1711388443.git.ayushtiw0110@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8712/mlme_linux.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/staging/rtl8712/mlme_linux.c b/drivers/staging/rtl8712/mlme_linux.c index a009ec1a5c11..ac8196d24ce0 100644 --- a/drivers/staging/rtl8712/mlme_linux.c +++ b/drivers/staging/rtl8712/mlme_linux.c @@ -87,7 +87,7 @@ void r8712_os_indicate_connect(struct _adapter *adapter) static struct RT_PMKID_LIST backup_PMKID_list[NUM_PMKID_CACHE]; void r8712_os_indicate_disconnect(struct _adapter *adapter) { - u8 backupPMKIDIndex = 0; + u8 backup_PMKID_index = 0; u8 backupTKIPCountermeasure = 0x00; r8712_indicate_wx_disassoc_event(adapter); @@ -102,7 +102,7 @@ void r8712_os_indicate_disconnect(struct _adapter *adapter) memcpy(&backup_PMKID_list[0], &adapter->securitypriv.PMKIDList[0], sizeof(struct RT_PMKID_LIST) * NUM_PMKID_CACHE); - backupPMKIDIndex = adapter->securitypriv.PMKIDIndex; + backup_PMKID_index = adapter->securitypriv.PMKIDIndex; backupTKIPCountermeasure = adapter->securitypriv.btkip_countermeasure; memset((unsigned char *)&adapter->securitypriv, 0, @@ -115,7 +115,7 @@ void r8712_os_indicate_disconnect(struct _adapter *adapter) memcpy(&adapter->securitypriv.PMKIDList[0], &backup_PMKID_list[0], sizeof(struct RT_PMKID_LIST) * NUM_PMKID_CACHE); - adapter->securitypriv.PMKIDIndex = backupPMKIDIndex; + adapter->securitypriv.PMKIDIndex = backup_PMKID_index; adapter->securitypriv.btkip_countermeasure = backupTKIPCountermeasure; } else { /*reset values in securitypriv*/ -- cgit v1.2.3-59-g8ed1b From 26a73b4d30d29f572163f7399e39d56677607b55 Mon Sep 17 00:00:00 2001 From: Ayush Tiwari Date: Mon, 25 Mar 2024 23:22:47 +0530 Subject: staging: rtl8712: rename backupTKIPCountermeasure to backup_TKIP_countermeasure Rename variable backupTKIPCountermeasure to backup_TKIP_countermeasure to address checkpatch warning 'Avoid Camelcase' and to ensure adherence to coding style guidelines. Signed-off-by: Ayush Tiwari Link: https://lore.kernel.org/r/3fd64e6671d3f86c49fd8c6ba9ef64c4f0e0b75e.1711388443.git.ayushtiw0110@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8712/mlme_linux.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/staging/rtl8712/mlme_linux.c b/drivers/staging/rtl8712/mlme_linux.c index ac8196d24ce0..436816d14cdf 100644 --- a/drivers/staging/rtl8712/mlme_linux.c +++ b/drivers/staging/rtl8712/mlme_linux.c @@ -88,7 +88,7 @@ static struct RT_PMKID_LIST backup_PMKID_list[NUM_PMKID_CACHE]; void r8712_os_indicate_disconnect(struct _adapter *adapter) { u8 backup_PMKID_index = 0; - u8 backupTKIPCountermeasure = 0x00; + u8 backup_TKIP_countermeasure = 0x00; r8712_indicate_wx_disassoc_event(adapter); netif_carrier_off(adapter->pnetdev); @@ -103,7 +103,7 @@ void r8712_os_indicate_disconnect(struct _adapter *adapter) &adapter->securitypriv.PMKIDList[0], sizeof(struct RT_PMKID_LIST) * NUM_PMKID_CACHE); backup_PMKID_index = adapter->securitypriv.PMKIDIndex; - backupTKIPCountermeasure = + backup_TKIP_countermeasure = adapter->securitypriv.btkip_countermeasure; memset((unsigned char *)&adapter->securitypriv, 0, sizeof(struct security_priv)); @@ -117,7 +117,7 @@ void r8712_os_indicate_disconnect(struct _adapter *adapter) sizeof(struct RT_PMKID_LIST) * NUM_PMKID_CACHE); adapter->securitypriv.PMKIDIndex = backup_PMKID_index; adapter->securitypriv.btkip_countermeasure = - backupTKIPCountermeasure; + backup_TKIP_countermeasure; } else { /*reset values in securitypriv*/ struct security_priv *sec_priv = &adapter->securitypriv; -- cgit v1.2.3-59-g8ed1b From 7a700d8f2431b681f2dae1118d62177719912f5d Mon Sep 17 00:00:00 2001 From: Michael Grzeschik Date: Wed, 21 Feb 2024 23:08:31 +0100 Subject: usb: gadget: uvc: fix try format returns on uncompressed formats When setting uncompressed formats, the values of bytesperline and sizeimage can already be determined by using the v4l2_fill_pixfmt helper function. We change the try_fmt function to use the helper instead. Signed-off-by: Michael Grzeschik Link: https://lore.kernel.org/r/20240221-uvc-gadget-uncompressed-v1-1-f55e97287cae@pengutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/function/uvc_v4l2.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/drivers/usb/gadget/function/uvc_v4l2.c b/drivers/usb/gadget/function/uvc_v4l2.c index c7e5fa4f29e0..a024aecb76dc 100644 --- a/drivers/usb/gadget/function/uvc_v4l2.c +++ b/drivers/usb/gadget/function/uvc_v4l2.c @@ -260,12 +260,26 @@ uvc_v4l2_try_format(struct file *file, void *fh, struct v4l2_format *fmt) if (!uframe) return -EINVAL; - fmt->fmt.pix.width = uframe->frame.w_width; - fmt->fmt.pix.height = uframe->frame.w_height; + if (uformat->type == UVCG_UNCOMPRESSED) { + struct uvcg_uncompressed *u = + to_uvcg_uncompressed(&uformat->group.cg_item); + if (!u) + return 0; + + v4l2_fill_pixfmt(&fmt->fmt.pix, fmt->fmt.pix.pixelformat, + uframe->frame.w_width, uframe->frame.w_height); + + if (fmt->fmt.pix.sizeimage != (uvc_v4l2_get_bytesperline(uformat, uframe) * + uframe->frame.w_height)) + return -EINVAL; + } else { + fmt->fmt.pix.width = uframe->frame.w_width; + fmt->fmt.pix.height = uframe->frame.w_height; + fmt->fmt.pix.bytesperline = uvc_v4l2_get_bytesperline(uformat, uframe); + fmt->fmt.pix.sizeimage = uvc_get_frame_size(uformat, uframe); + fmt->fmt.pix.pixelformat = to_uvc_format(uformat)->fcc; + } fmt->fmt.pix.field = V4L2_FIELD_NONE; - fmt->fmt.pix.bytesperline = uvc_v4l2_get_bytesperline(uformat, uframe); - fmt->fmt.pix.sizeimage = uvc_get_frame_size(uformat, uframe); - fmt->fmt.pix.pixelformat = to_uvc_format(uformat)->fcc; fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB; fmt->fmt.pix.priv = 0; -- cgit v1.2.3-59-g8ed1b From f7a7f80ccc8df017507e2b1e1dd652361374d25b Mon Sep 17 00:00:00 2001 From: Michael Grzeschik Date: Wed, 21 Feb 2024 23:14:47 +0100 Subject: usb: gadget: uvc: configfs: ensure guid to be valid before set When setting the guid via configfs it is possible to test if its value is one of the kernel supported ones by calling uvc_format_by_guid on it. If the result is NULL, we know the guid is unsupported and can be ignored. Signed-off-by: Michael Grzeschik Link: https://lore.kernel.org/r/20240221-uvc-gadget-configfs-guid-v1-1-f0678ca62ebb@pengutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/function/uvc_configfs.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c index 7e704b2bcfd1..6535e5948b2e 100644 --- a/drivers/usb/gadget/function/uvc_configfs.c +++ b/drivers/usb/gadget/function/uvc_configfs.c @@ -13,6 +13,7 @@ #include "uvc_configfs.h" #include +#include #include /* ----------------------------------------------------------------------------- @@ -2260,6 +2261,8 @@ static ssize_t uvcg_uncompressed_guid_format_store(struct config_item *item, struct f_uvc_opts *opts; struct config_item *opts_item; struct mutex *su_mutex = &ch->fmt.group.cg_subsys->su_mutex; + const struct uvc_format_desc *format; + u8 tmpguidFormat[sizeof(ch->desc.guidFormat)]; int ret; mutex_lock(su_mutex); /* for navigating configfs hierarchy */ @@ -2273,7 +2276,16 @@ static ssize_t uvcg_uncompressed_guid_format_store(struct config_item *item, goto end; } - memcpy(ch->desc.guidFormat, page, + memcpy(tmpguidFormat, page, + min(sizeof(tmpguidFormat), len)); + + format = uvc_format_by_guid(tmpguidFormat); + if (!format) { + ret = -EINVAL; + goto end; + } + + memcpy(ch->desc.guidFormat, tmpguidFormat, min(sizeof(ch->desc.guidFormat), len)); ret = sizeof(ch->desc.guidFormat); -- cgit v1.2.3-59-g8ed1b From 2f550553e23c889b54440bf05e2484d84105e48d Mon Sep 17 00:00:00 2001 From: Hardik Gajjar Date: Fri, 1 Mar 2024 13:47:08 +0100 Subject: usb: gadget: f_fs: Add the missing get_alt callback The Apple CarLife iAP gadget has a descriptor in userspace with two alternate settings. The host sends the set_alt request to configure alt_setting 0 or 1, and this is verified by the subsequent get_alt request. This patch implements and sets the get_alt callback. Without the get_alt callback, composite.c abruptly concludes the USB_REQ_GET/SET_INTERFACE request, assuming only one alt setting for the endpoint. unlike the uvc and ncm, f_fs gadget is fully implemented in userspace, and driver just reset the eps and generate the event. so no additional adaptaion associated with this change is not required in set_alt callback Signed-off-by: Hardik Gajjar Link: https://lore.kernel.org/r/20240301124708.120394-1-hgajjar@de.adit-jv.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/function/f_fs.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index bffbc1dc651f..d3a7f7bae07b 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -45,6 +45,7 @@ #include "configfs.h" #define FUNCTIONFS_MAGIC 0xa647361 /* Chosen by a honest dice roll ;) */ +#define MAX_ALT_SETTINGS 2 /* Allow up to 2 alt settings to be set. */ MODULE_IMPORT_NS(DMA_BUF); @@ -80,6 +81,7 @@ struct ffs_function { short *interfaces_nums; struct usb_function function; + int cur_alt[MAX_CONFIG_INTERFACES]; }; @@ -103,6 +105,7 @@ static int __must_check ffs_func_eps_enable(struct ffs_function *func); static int ffs_func_bind(struct usb_configuration *, struct usb_function *); static int ffs_func_set_alt(struct usb_function *, unsigned, unsigned); +static int ffs_func_get_alt(struct usb_function *f, unsigned int intf); static void ffs_func_disable(struct usb_function *); static int ffs_func_setup(struct usb_function *, const struct usb_ctrlrequest *); @@ -3704,6 +3707,15 @@ static void ffs_reset_work(struct work_struct *work) ffs_data_reset(ffs); } +static int ffs_func_get_alt(struct usb_function *f, + unsigned int interface) +{ + struct ffs_function *func = ffs_func_from_usb(f); + int intf = ffs_func_revmap_intf(func, interface); + + return (intf < 0) ? intf : func->cur_alt[interface]; +} + static int ffs_func_set_alt(struct usb_function *f, unsigned interface, unsigned alt) { @@ -3711,6 +3723,9 @@ static int ffs_func_set_alt(struct usb_function *f, struct ffs_data *ffs = func->ffs; int ret = 0, intf; + if (alt > MAX_ALT_SETTINGS) + return -EINVAL; + if (alt != (unsigned)-1) { intf = ffs_func_revmap_intf(func, interface); if (intf < 0) @@ -3738,8 +3753,10 @@ static int ffs_func_set_alt(struct usb_function *f, ffs->func = func; ret = ffs_func_eps_enable(func); - if (ret >= 0) + if (ret >= 0) { ffs_event_add(ffs, FUNCTIONFS_ENABLE); + func->cur_alt[interface] = alt; + } return ret; } @@ -4066,6 +4083,7 @@ static struct usb_function *ffs_alloc(struct usb_function_instance *fi) func->function.bind = ffs_func_bind; func->function.unbind = ffs_func_unbind; func->function.set_alt = ffs_func_set_alt; + func->function.get_alt = ffs_func_get_alt; func->function.disable = ffs_func_disable; func->function.setup = ffs_func_setup; func->function.req_match = ffs_func_req_match; -- cgit v1.2.3-59-g8ed1b From 0ef40f399aa2be8c04aee9b7430705612c104ce5 Mon Sep 17 00:00:00 2001 From: Roy Luo Date: Thu, 7 Mar 2024 03:09:22 +0000 Subject: USB: gadget: core: create sysfs link between udc and gadget udc device and gadget device are tightly coupled, yet there's no good way to corelate the two. Add a sysfs link in udc that points to the corresponding gadget device. An example use case: userspace configures a f_midi configfs driver and bind the udc device, then it tries to locate the corresponding midi device, which is a child device of the gadget device. The gadget device that's associated to the udc device has to be identified in order to index the midi device. Having a sysfs link would make things much easier. Signed-off-by: Roy Luo Link: https://lore.kernel.org/r/20240307030922.3573161-1-royluo@google.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/udc/core.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c index 9d4150124fdb..76d890f9a40f 100644 --- a/drivers/usb/gadget/udc/core.c +++ b/drivers/usb/gadget/udc/core.c @@ -1424,8 +1424,16 @@ int usb_add_gadget(struct usb_gadget *gadget) if (ret) goto err_free_id; + ret = sysfs_create_link(&udc->dev.kobj, + &gadget->dev.kobj, "gadget"); + if (ret) + goto err_del_gadget; + return 0; + err_del_gadget: + device_del(&gadget->dev); + err_free_id: ida_free(&gadget_id_numbers, gadget->id_number); @@ -1534,6 +1542,7 @@ void usb_del_gadget(struct usb_gadget *gadget) mutex_unlock(&udc_lock); kobject_uevent(&udc->dev.kobj, KOBJ_REMOVE); + sysfs_remove_link(&udc->dev.kobj, "gadget"); flush_work(&gadget->work); device_del(&gadget->dev); ida_free(&gadget_id_numbers, gadget->id_number); -- cgit v1.2.3-59-g8ed1b From 1f855c5e68629f2e1bb2e6f013917c20a0a88cff Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Fri, 8 Mar 2024 09:51:18 +0100 Subject: usb: chipidea: npcm: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/91311e53e9432ae84d5720485c3b436fb7f06227.1709886922.git.u.kleine-koenig@pengutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/usb/chipidea/ci_hdrc_npcm.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/usb/chipidea/ci_hdrc_npcm.c b/drivers/usb/chipidea/ci_hdrc_npcm.c index e4a191e02ceb..b14127873c55 100644 --- a/drivers/usb/chipidea/ci_hdrc_npcm.c +++ b/drivers/usb/chipidea/ci_hdrc_npcm.c @@ -80,15 +80,13 @@ clk_err: return ret; } -static int npcm_udc_remove(struct platform_device *pdev) +static void npcm_udc_remove(struct platform_device *pdev) { struct npcm_udc_data *ci = platform_get_drvdata(pdev); pm_runtime_disable(&pdev->dev); ci_hdrc_remove_device(ci->ci); clk_disable_unprepare(ci->core_clk); - - return 0; } static const struct of_device_id npcm_udc_dt_match[] = { @@ -100,7 +98,7 @@ MODULE_DEVICE_TABLE(of, npcm_udc_dt_match); static struct platform_driver npcm_udc_driver = { .probe = npcm_udc_probe, - .remove = npcm_udc_remove, + .remove_new = npcm_udc_remove, .driver = { .name = "npcm_udc", .of_match_table = npcm_udc_dt_match, -- cgit v1.2.3-59-g8ed1b From 110000b5408dd7aae44b9922bb9ff5c76a461212 Mon Sep 17 00:00:00 2001 From: Dingyan Li <18500469033@163.com> Date: Sat, 9 Mar 2024 11:37:09 +0800 Subject: USB: Use EHCI control transfer pid macros instead of constant values. Macros with good names offer better readability. Besides, also move the definition to ehci.h. Signed-off-by: Dingyan Li <18500469033@163.com> Reviewed-by: Alan Stern Link: https://lore.kernel.org/r/20240309033709.14604-1-18500469033@163.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-dbg.c | 10 +++++----- drivers/usb/host/ehci-q.c | 20 ++++++++------------ drivers/usb/host/ehci.h | 8 +++++++- 3 files changed, 20 insertions(+), 18 deletions(-) diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c index c063fb042926..435001128221 100644 --- a/drivers/usb/host/ehci-dbg.c +++ b/drivers/usb/host/ehci-dbg.c @@ -430,13 +430,13 @@ static void qh_lines(struct ehci_hcd *ehci, struct ehci_qh *qh, mark = '/'; } switch ((scratch >> 8) & 0x03) { - case 0: + case PID_CODE_OUT: type = "out"; break; - case 1: + case PID_CODE_IN: type = "in"; break; - case 2: + case PID_CODE_SETUP: type = "setup"; break; default: @@ -602,10 +602,10 @@ static unsigned output_buf_tds_dir(char *buf, struct ehci_hcd *ehci, list_for_each_entry(qtd, &qh->qtd_list, qtd_list) { temp++; switch ((hc32_to_cpu(ehci, qtd->hw_token) >> 8) & 0x03) { - case 0: + case PID_CODE_OUT: type = "out"; continue; - case 1: + case PID_CODE_IN: type = "in"; continue; } diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index 666f5c4db25a..ba37a9fcab92 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -27,10 +27,6 @@ /*-------------------------------------------------------------------------*/ -/* PID Codes that are used here, from EHCI specification, Table 3-16. */ -#define PID_CODE_IN 1 -#define PID_CODE_SETUP 2 - /* fill a qtd, returning how much of the buffer we were able to queue up */ static unsigned int @@ -230,7 +226,7 @@ static int qtd_copy_status ( /* fs/ls interrupt xfer missed the complete-split */ status = -EPROTO; } else if (token & QTD_STS_DBE) { - status = (QTD_PID (token) == 1) /* IN ? */ + status = (QTD_PID(token) == PID_CODE_IN) /* IN ? */ ? -ENOSR /* hc couldn't read data */ : -ECOMM; /* hc couldn't write data */ } else if (token & QTD_STS_XACT) { @@ -606,7 +602,7 @@ qh_urb_transaction ( /* SETUP pid */ qtd_fill(ehci, qtd, urb->setup_dma, sizeof (struct usb_ctrlrequest), - token | (2 /* "setup" */ << 8), 8); + token | (PID_CODE_SETUP << 8), 8); /* ... and always at least one more pid */ token ^= QTD_TOGGLE; @@ -620,7 +616,7 @@ qh_urb_transaction ( /* for zero length DATA stages, STATUS is always IN */ if (len == 0) - token |= (1 /* "in" */ << 8); + token |= (PID_CODE_IN << 8); } /* @@ -642,7 +638,7 @@ qh_urb_transaction ( } if (is_input) - token |= (1 /* "in" */ << 8); + token |= (PID_CODE_IN << 8); /* else it's already initted to "out" pid (0 << 8) */ maxpacket = usb_endpoint_maxp(&urb->ep->desc); @@ -709,7 +705,7 @@ qh_urb_transaction ( if (usb_pipecontrol (urb->pipe)) { one_more = 1; - token ^= 0x0100; /* "in" <--> "out" */ + token ^= (PID_CODE_IN << 8); /* "in" <--> "out" */ token |= QTD_TOGGLE; /* force DATA1 */ } else if (usb_pipeout(urb->pipe) && (urb->transfer_flags & URB_ZERO_PACKET) @@ -1203,7 +1199,7 @@ static int ehci_submit_single_step_set_feature( /* SETUP pid, and interrupt after SETUP completion */ qtd_fill(ehci, qtd, urb->setup_dma, sizeof(struct usb_ctrlrequest), - QTD_IOC | token | (2 /* "setup" */ << 8), 8); + QTD_IOC | token | (PID_CODE_SETUP << 8), 8); submit_async(ehci, urb, &qtd_list, GFP_ATOMIC); return 0; /*Return now; we shall come back after 15 seconds*/ @@ -1216,7 +1212,7 @@ static int ehci_submit_single_step_set_feature( token ^= QTD_TOGGLE; /*We need to start IN with DATA-1 Pid-sequence*/ buf = urb->transfer_dma; - token |= (1 /* "in" */ << 8); /*This is IN stage*/ + token |= (PID_CODE_IN << 8); /*This is IN stage*/ maxpacket = usb_endpoint_maxp(&urb->ep->desc); @@ -1229,7 +1225,7 @@ static int ehci_submit_single_step_set_feature( qtd->hw_alt_next = EHCI_LIST_END(ehci); /* STATUS stage for GetDesc control request */ - token ^= 0x0100; /* "in" <--> "out" */ + token ^= (PID_CODE_IN << 8); /* "in" <--> "out" */ token |= QTD_TOGGLE; /* force DATA1 */ qtd_prev = qtd; diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index 1441e3400796..d7a3c8d13f6b 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -321,10 +321,16 @@ struct ehci_qtd { size_t length; /* length of buffer */ } __aligned(32); +/* PID Codes that are used here, from EHCI specification, Table 3-16. */ +#define PID_CODE_OUT 0 +#define PID_CODE_IN 1 +#define PID_CODE_SETUP 2 + /* mask NakCnt+T in qh->hw_alt_next */ #define QTD_MASK(ehci) cpu_to_hc32(ehci, ~0x1f) -#define IS_SHORT_READ(token) (QTD_LENGTH(token) != 0 && QTD_PID(token) == 1) +#define IS_SHORT_READ(token) (QTD_LENGTH(token) != 0 && \ + QTD_PID(token) == PID_CODE_IN) /*-------------------------------------------------------------------------*/ -- cgit v1.2.3-59-g8ed1b From 7a3124273585f72be1caf8feaba873a4b6356d4d Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sun, 10 Mar 2024 17:19:44 +0100 Subject: usb: dwc2: Remove cat_printf() cat_printf() implements the newly introduced seq_buf API. Use the latter to save some line of code. Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/abf3d0361ea291468d121062207a766b0c3228f2.1710087556.git.christophe.jaillet@wanadoo.fr Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc2/hcd_queue.c | 52 +++++++------------------------------------- 1 file changed, 8 insertions(+), 44 deletions(-) diff --git a/drivers/usb/dwc2/hcd_queue.c b/drivers/usb/dwc2/hcd_queue.c index 0d4495c6b9f7..238c6fd50e75 100644 --- a/drivers/usb/dwc2/hcd_queue.c +++ b/drivers/usb/dwc2/hcd_queue.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -359,41 +360,6 @@ static unsigned long *dwc2_get_ls_map(struct dwc2_hsotg *hsotg, } #ifdef DWC2_PRINT_SCHEDULE -/* - * cat_printf() - A printf() + strcat() helper - * - * This is useful for concatenating a bunch of strings where each string is - * constructed using printf. - * - * @buf: The destination buffer; will be updated to point after the printed - * data. - * @size: The number of bytes in the buffer (includes space for '\0'). - * @fmt: The format for printf. - * @...: The args for printf. - */ -static __printf(3, 4) -void cat_printf(char **buf, size_t *size, const char *fmt, ...) -{ - va_list args; - int i; - - if (*size == 0) - return; - - va_start(args, fmt); - i = vsnprintf(*buf, *size, fmt, args); - va_end(args); - - if (i >= *size) { - (*buf)[*size - 1] = '\0'; - *buf += *size; - *size = 0; - } else { - *buf += i; - *size -= i; - } -} - /* * pmap_print() - Print the given periodic map * @@ -416,9 +382,7 @@ static void pmap_print(unsigned long *map, int bits_per_period, int period; for (period = 0; period < periods_in_map; period++) { - char tmp[64]; - char *buf = tmp; - size_t buf_size = sizeof(tmp); + DECLARE_SEQ_BUF(buf, 64); int period_start = period * bits_per_period; int period_end = period_start + bits_per_period; int start = 0; @@ -442,19 +406,19 @@ static void pmap_print(unsigned long *map, int bits_per_period, continue; if (!printed) - cat_printf(&buf, &buf_size, "%s %d: ", - period_name, period); + seq_buf_printf(&buf, "%s %d: ", + period_name, period); else - cat_printf(&buf, &buf_size, ", "); + seq_buf_puts(&buf, ", "); printed = true; - cat_printf(&buf, &buf_size, "%d %s -%3d %s", start, - units, start + count - 1, units); + seq_buf_printf(&buf, "%d %s -%3d %s", start, + units, start + count - 1, units); count = 0; } if (printed) - print_fn(tmp, print_data); + print_fn(seq_buf_str(&buf), print_data); } } -- cgit v1.2.3-59-g8ed1b From 10cfb14d2a2b67751cef93a1c75d3797ec433c52 Mon Sep 17 00:00:00 2001 From: Bo Liu Date: Sat, 9 Mar 2024 02:17:57 -0500 Subject: usb: typec: stusb160x: convert to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. Signed-off-by: Bo Liu Acked-by: Heikki Krogerus Link: https://lore.kernel.org/r/20240309071757.3152-1-liubo03@inspur.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/stusb160x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/typec/stusb160x.c b/drivers/usb/typec/stusb160x.c index 3ab118df1bd4..f3140fc04c12 100644 --- a/drivers/usb/typec/stusb160x.c +++ b/drivers/usb/typec/stusb160x.c @@ -234,7 +234,7 @@ static const struct regmap_config stusb1600_regmap_config = { .readable_reg = stusb160x_reg_readable, .volatile_reg = stusb160x_reg_volatile, .precious_reg = stusb160x_reg_precious, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; static bool stusb160x_get_vconn(struct stusb160x *chip) -- cgit v1.2.3-59-g8ed1b From 9dc28ea21eb40b9d023297ad9d513252260b1d63 Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Fri, 15 Mar 2024 17:04:22 +0100 Subject: usb: typec: ptn36502: switch to DRM_AUX_BRIDGE Switch to using the new DRM_AUX_BRIDGE helper to create the transparent DRM bridge device instead of handcoding corresponding functionality. Signed-off-by: Luca Weiss Reviewed-by: Dmitry Baryshkov Reviewed-by: Heikki Krogerus Link: https://lore.kernel.org/r/20240315-ptn36502-aux-v1-1-c9d3c828ff2e@fairphone.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/mux/Kconfig | 2 +- drivers/usb/typec/mux/ptn36502.c | 44 ++-------------------------------------- 2 files changed, 3 insertions(+), 43 deletions(-) diff --git a/drivers/usb/typec/mux/Kconfig b/drivers/usb/typec/mux/Kconfig index 399c7b0983df..4827e86fed6d 100644 --- a/drivers/usb/typec/mux/Kconfig +++ b/drivers/usb/typec/mux/Kconfig @@ -60,7 +60,7 @@ config TYPEC_MUX_PTN36502 tristate "NXP PTN36502 Type-C redriver driver" depends on I2C depends on DRM || DRM=n - select DRM_PANEL_BRIDGE if DRM + select DRM_AUX_BRIDGE if DRM_BRIDGE select REGMAP_I2C help Say Y or M if your system has a NXP PTN36502 Type-C redriver chip diff --git a/drivers/usb/typec/mux/ptn36502.c b/drivers/usb/typec/mux/ptn36502.c index 72ae38a1b2be..0ec86ef32a87 100644 --- a/drivers/usb/typec/mux/ptn36502.c +++ b/drivers/usb/typec/mux/ptn36502.c @@ -8,7 +8,7 @@ * Copyright (C) 2023 Dmitry Baryshkov */ -#include +#include #include #include #include @@ -68,8 +68,6 @@ struct ptn36502 { struct typec_switch *typec_switch; - struct drm_bridge bridge; - struct mutex lock; /* protect non-concurrent retimer & switch */ enum typec_orientation orientation; @@ -283,44 +281,6 @@ static int ptn36502_detect(struct ptn36502 *ptn) return 0; } -#if IS_ENABLED(CONFIG_OF) && IS_ENABLED(CONFIG_DRM_PANEL_BRIDGE) -static int ptn36502_bridge_attach(struct drm_bridge *bridge, - enum drm_bridge_attach_flags flags) -{ - struct ptn36502 *ptn = container_of(bridge, struct ptn36502, bridge); - struct drm_bridge *next_bridge; - - if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) - return -EINVAL; - - next_bridge = devm_drm_of_get_bridge(&ptn->client->dev, ptn->client->dev.of_node, 0, 0); - if (IS_ERR(next_bridge)) { - dev_err(&ptn->client->dev, "failed to acquire drm_bridge: %pe\n", next_bridge); - return PTR_ERR(next_bridge); - } - - return drm_bridge_attach(bridge->encoder, next_bridge, bridge, - DRM_BRIDGE_ATTACH_NO_CONNECTOR); -} - -static const struct drm_bridge_funcs ptn36502_bridge_funcs = { - .attach = ptn36502_bridge_attach, -}; - -static int ptn36502_register_bridge(struct ptn36502 *ptn) -{ - ptn->bridge.funcs = &ptn36502_bridge_funcs; - ptn->bridge.of_node = ptn->client->dev.of_node; - - return devm_drm_bridge_add(&ptn->client->dev, &ptn->bridge); -} -#else -static int ptn36502_register_bridge(struct ptn36502 *ptn) -{ - return 0; -} -#endif - static const struct regmap_config ptn36502_regmap = { .max_register = 0x0d, .reg_bits = 8, @@ -369,7 +329,7 @@ static int ptn36502_probe(struct i2c_client *client) if (ret) goto err_disable_regulator; - ret = ptn36502_register_bridge(ptn); + ret = drm_aux_bridge_register(dev); if (ret) goto err_disable_regulator; -- cgit v1.2.3-59-g8ed1b From c58ab9249df78bbe3561418fced5a553b68f9070 Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Mon, 18 Mar 2024 23:10:34 +0000 Subject: usb: gadget: u_ether: replace deprecated strncpy with strscpy strncpy() is deprecated for use on NUL-terminated destination strings [1] and as such we should prefer more robust and less ambiguous string interfaces. Let's use the new 2-argument strscpy() as this guarantees NUL-termination on the destination buffer and also uses the destination buffer's size to bound the operation. Link: https://www.kernel.org/doc/html/latest/process/deprecated.html#strncpy-on-nul-terminated-strings [1] Link: https://manpages.debian.org/testing/linux-manual-4.8/strscpy.9.en.html [2] Link: https://github.com/KSPP/linux/issues/90 Cc: linux-hardening@vger.kernel.org Signed-off-by: Justin Stitt Reviewed-by: Kees Cook Link: https://lore.kernel.org/r/20240318-strncpy-drivers-usb-gadget-function-u_ether-c-v1-1-e8543a1db24a@google.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/function/u_ether.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c index 444212c0b5a9..11dd0b9e847f 100644 --- a/drivers/usb/gadget/function/u_ether.c +++ b/drivers/usb/gadget/function/u_ether.c @@ -1032,7 +1032,7 @@ int gether_set_ifname(struct net_device *net, const char *name, int len) if (!p || p[1] != 'd' || strchr(p + 2, '%')) return -EINVAL; - strncpy(net->name, tmp, sizeof(net->name)); + strscpy(net->name, tmp); dev->ifname_set = true; return 0; -- cgit v1.2.3-59-g8ed1b From 3b5eac68995396e174e3d4d5714ad106cb13dba0 Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Mon, 18 Mar 2024 23:31:53 +0000 Subject: usb: gadget: mv_u3d: replace deprecated strncpy with strscpy strncpy() is deprecated for use on NUL-terminated destination strings [1] and as such we should prefer more robust and less ambiguous string interfaces. Let's opt for the new 2-argument version of strscpy() which guarantees NUL-termination on the destination buffer and simplifies snytax. The NUL-padding behavior that strncpy() provides is not required as u3d->eps is already zero-allocated: | u3d->eps = kzalloc(size, GFP_KERNEL); Link: https://www.kernel.org/doc/html/latest/process/deprecated.html#strncpy-on-nul-terminated-strings [1] Link: https://manpages.debian.org/testing/linux-manual-4.8/strscpy.9.en.html [2] Link: https://github.com/KSPP/linux/issues/90 Cc: linux-hardening@vger.kernel.org Signed-off-by: Justin Stitt Reviewed-by: Kees Cook Link: https://lore.kernel.org/r/20240318-strncpy-drivers-usb-gadget-udc-mv_u3d_core-c-v1-1-64f8dcdb7c07@google.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/udc/mv_u3d_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/udc/mv_u3d_core.c b/drivers/usb/gadget/udc/mv_u3d_core.c index 2a421f0ff931..e1dd5cf25d08 100644 --- a/drivers/usb/gadget/udc/mv_u3d_core.c +++ b/drivers/usb/gadget/udc/mv_u3d_core.c @@ -1307,7 +1307,7 @@ static int mv_u3d_eps_init(struct mv_u3d *u3d) /* initialize ep0, ep0 in/out use eps[1] */ ep = &u3d->eps[1]; ep->u3d = u3d; - strncpy(ep->name, "ep0", sizeof(ep->name)); + strscpy(ep->name, "ep0"); ep->ep.name = ep->name; ep->ep.ops = &mv_u3d_ep_ops; ep->wedge = 0; @@ -1337,7 +1337,7 @@ static int mv_u3d_eps_init(struct mv_u3d *u3d) ep->ep.caps.dir_out = true; } ep->u3d = u3d; - strncpy(ep->name, name, sizeof(ep->name)); + strscpy(ep->name, name); ep->ep.name = ep->name; ep->ep.caps.type_iso = true; -- cgit v1.2.3-59-g8ed1b From 799d9c2750b885ad46d5eea9fb1a331b31e1cde5 Mon Sep 17 00:00:00 2001 From: Minas Harutyunyan Date: Wed, 13 Mar 2024 09:19:02 +0000 Subject: usb: dwc2: Add core new versions definition Added new versions definition for HSOTG core v5.00a and IOT HS device core v5.00. Signed-off-by: Minas Harutyunyan Link: https://lore.kernel.org/r/7fc17fe275a54c8a9e00cd00ffc19e62418c1f84.1708948356.git.Minas.Harutyunyan@synopsys.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc2/core.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h index c92a1da46a01..0c10bd0c32fd 100644 --- a/drivers/usb/dwc2/core.h +++ b/drivers/usb/dwc2/core.h @@ -1097,8 +1097,10 @@ struct dwc2_hsotg { #define DWC2_CORE_REV_3_10a 0x4f54310a #define DWC2_CORE_REV_4_00a 0x4f54400a #define DWC2_CORE_REV_4_20a 0x4f54420a +#define DWC2_CORE_REV_5_00a 0x4f54500a #define DWC2_FS_IOT_REV_1_00a 0x5531100a #define DWC2_HS_IOT_REV_1_00a 0x5532100a +#define DWC2_HS_IOT_REV_5_00a 0x5532500a #define DWC2_CORE_REV_MASK 0x0000ffff /* DWC OTG HW Core ID */ -- cgit v1.2.3-59-g8ed1b From f73220f7fda1034b17fd5739965b73066ba6e305 Mon Sep 17 00:00:00 2001 From: Minas Harutyunyan Date: Wed, 13 Mar 2024 09:19:18 +0000 Subject: usb: dwc2: New bit definition in GOTGCTL register Added new bit EUSB2_DISC_SUPP in GOTGCTL register. This bit applicable in device mode of HSOTG and HS IOT cores v5.00 or higher. This bit used for Device Disconnect detection with eUSB2 PHY. Signed-off-by: Minas Harutyunyan Link: https://lore.kernel.org/r/21e4401895d586afa23c3fa3d3518bd4b7ebd4d5.1708948356.git.Minas.Harutyunyan@synopsys.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc2/hw.h | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/dwc2/hw.h b/drivers/usb/dwc2/hw.h index 13abdd5f6752..c1d5d46c33e3 100644 --- a/drivers/usb/dwc2/hw.h +++ b/drivers/usb/dwc2/hw.h @@ -11,6 +11,7 @@ #define HSOTG_REG(x) (x) #define GOTGCTL HSOTG_REG(0x000) +#define GOTGCTL_EUSB2_DISC_SUPP BIT(28) #define GOTGCTL_CHIRPEN BIT(27) #define GOTGCTL_MULT_VALID_BC_MASK (0x1f << 22) #define GOTGCTL_MULT_VALID_BC_SHIFT 22 -- cgit v1.2.3-59-g8ed1b From bc5d81b8012ce51e0ed137500d92c6b146e45732 Mon Sep 17 00:00:00 2001 From: Minas Harutyunyan Date: Wed, 13 Mar 2024 09:19:32 +0000 Subject: usb: dwc2: Add new parameter eusb2_disc Added new parameter eusb2_disc to list of core parameters which specify whether eUSB2 PHY disconnect support flow applicable or no. Set to false as default value and checked core version if set to true. This parameter applicable in device mode of HSOTG and HS IOT cores v5.00 or higher. Added print this parameter in show parameters of debugfs. Signed-off-by: Minas Harutyunyan Link: https://lore.kernel.org/r/e77cc4312bda797d1ddaa4351d86c65a69c8b926.1708948356.git.Minas.Harutyunyan@synopsys.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc2/core.h | 6 ++++++ drivers/usb/dwc2/debugfs.c | 1 + drivers/usb/dwc2/params.c | 22 ++++++++++++++++++++++ 3 files changed, 29 insertions(+) diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h index 0c10bd0c32fd..16d6ac97f23b 100644 --- a/drivers/usb/dwc2/core.h +++ b/drivers/usb/dwc2/core.h @@ -288,6 +288,11 @@ enum dwc2_ep0_state { * core has been configured to work at either data path * width. * 8 or 16 (default 16 if available) + * @eusb2_disc: Specifies whether eUSB2 PHY disconnect support flow + * applicable or no. Applicable in device mode of HSOTG + * and HS IOT cores v5.00 or higher. + * 0 - eUSB2 PHY disconnect support flow not applicable + * 1 - eUSB2 PHY disconnect support flow applicable * @phy_ulpi_ddr: Specifies whether the ULPI operates at double or single * data rate. This parameter is only applicable if phy_type * is ULPI. @@ -442,6 +447,7 @@ struct dwc2_core_params { #define DWC2_SPEED_PARAM_LOW 2 u8 phy_utmi_width; + bool eusb2_disc; bool phy_ulpi_ddr; bool phy_ulpi_ext_vbus; bool enable_dynamic_fifo; diff --git a/drivers/usb/dwc2/debugfs.c b/drivers/usb/dwc2/debugfs.c index 1d72ece9cfe4..7c82ab590401 100644 --- a/drivers/usb/dwc2/debugfs.c +++ b/drivers/usb/dwc2/debugfs.c @@ -686,6 +686,7 @@ static int params_show(struct seq_file *seq, void *v) print_param(seq, p, host_channels); print_param(seq, p, phy_type); print_param(seq, p, phy_utmi_width); + print_param(seq, p, eusb2_disc); print_param(seq, p, phy_ulpi_ddr); print_param(seq, p, phy_ulpi_ext_vbus); print_param(seq, p, i2c_enable); diff --git a/drivers/usb/dwc2/params.c b/drivers/usb/dwc2/params.c index eb677c3cfd0b..c47524483f48 100644 --- a/drivers/usb/dwc2/params.c +++ b/drivers/usb/dwc2/params.c @@ -475,6 +475,7 @@ static void dwc2_set_default_params(struct dwc2_hsotg *hsotg) dwc2_set_param_lpm(hsotg); p->phy_ulpi_ddr = false; p->phy_ulpi_ext_vbus = false; + p->eusb2_disc = false; p->enable_dynamic_fifo = hw->enable_dynamic_fifo; p->en_multiple_tx_fifo = hw->en_multiple_tx_fifo; @@ -737,6 +738,25 @@ static void dwc2_check_param_tx_fifo_sizes(struct dwc2_hsotg *hsotg) } } +static void dwc2_check_param_eusb2_disc(struct dwc2_hsotg *hsotg) +{ + u32 gsnpsid; + + if (!hsotg->params.eusb2_disc) + return; + gsnpsid = dwc2_readl(hsotg, GSNPSID); + /* + * eusb2_disc not supported by FS IOT devices. + * For other cores, it supported starting from version 5.00a + */ + if ((gsnpsid & ~DWC2_CORE_REV_MASK) == DWC2_FS_IOT_ID || + (gsnpsid & DWC2_CORE_REV_MASK) < + (DWC2_CORE_REV_5_00a & DWC2_CORE_REV_MASK)) { + hsotg->params.eusb2_disc = false; + return; + } +} + #define CHECK_RANGE(_param, _min, _max, _def) do { \ if ((int)(hsotg->params._param) < (_min) || \ (hsotg->params._param) > (_max)) { \ @@ -765,6 +785,8 @@ static void dwc2_check_params(struct dwc2_hsotg *hsotg) dwc2_check_param_speed(hsotg); dwc2_check_param_phy_utmi_width(hsotg); dwc2_check_param_power_down(hsotg); + dwc2_check_param_eusb2_disc(hsotg); + CHECK_BOOL(enable_dynamic_fifo, hw->enable_dynamic_fifo); CHECK_BOOL(en_multiple_tx_fifo, hw->en_multiple_tx_fifo); CHECK_BOOL(i2c_enable, hw->i2c_enable); -- cgit v1.2.3-59-g8ed1b From 7fd22e5bcaa5b1224fe3fb2196c26f1a14e843ff Mon Sep 17 00:00:00 2001 From: Minas Harutyunyan Date: Wed, 13 Mar 2024 09:19:42 +0000 Subject: usb: dwc2: Add eUSB2 PHY disconnect flow support To support eUSB2 PHY disconnect flow required in Soft disconnect state set GOTGCTL_EUSB2_DISC_SUPP bit, if applicable. On Session End Detected interrupt clear PCGCTL_GATEHCLK and PCGCTL_STOPPCLK bits if eusb2_disc parameter true. Signed-off-by: Minas Harutyunyan Link: https://lore.kernel.org/r/9d50b83df693cda8c391313e90048df8dd611c04.1708948356.git.Minas.Harutyunyan@synopsys.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc2/core_intr.c | 21 ++++++++++++++++++--- drivers/usb/dwc2/gadget.c | 5 ++++- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/drivers/usb/dwc2/core_intr.c b/drivers/usb/dwc2/core_intr.c index 158ede753854..bb6bb771375a 100644 --- a/drivers/usb/dwc2/core_intr.c +++ b/drivers/usb/dwc2/core_intr.c @@ -84,6 +84,7 @@ static void dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg) u32 gotgint; u32 gotgctl; u32 gintmsk; + u32 pcgctl; gotgint = dwc2_readl(hsotg, GOTGINT); gotgctl = dwc2_readl(hsotg, GOTGCTL); @@ -96,8 +97,22 @@ static void dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg) dwc2_op_state_str(hsotg)); gotgctl = dwc2_readl(hsotg, GOTGCTL); - if (dwc2_is_device_mode(hsotg)) + if (dwc2_is_device_mode(hsotg)) { + if (hsotg->params.eusb2_disc) { + /* Clear the Gate hclk. */ + pcgctl = dwc2_readl(hsotg, PCGCTL); + pcgctl &= ~PCGCTL_GATEHCLK; + dwc2_writel(hsotg, pcgctl, PCGCTL); + udelay(5); + + /* Clear Phy Clock bit. */ + pcgctl = dwc2_readl(hsotg, PCGCTL); + pcgctl &= ~PCGCTL_STOPPCLK; + dwc2_writel(hsotg, pcgctl, PCGCTL); + udelay(5); + } dwc2_hsotg_disconnect(hsotg); + } if (hsotg->op_state == OTG_STATE_B_HOST) { hsotg->op_state = OTG_STATE_B_PERIPHERAL; @@ -117,7 +132,7 @@ static void dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg) * disconnected */ /* Reset to a clean state */ - hsotg->lx_state = DWC2_L0; + hsotg->lx_state = DWC2_L3; } gotgctl = dwc2_readl(hsotg, GOTGCTL); @@ -286,7 +301,7 @@ static void dwc2_handle_session_req_intr(struct dwc2_hsotg *hsotg) hsotg->lx_state); if (dwc2_is_device_mode(hsotg)) { - if (hsotg->lx_state == DWC2_L2) { + if (hsotg->lx_state != DWC2_L0) { if (hsotg->in_ppd) { ret = dwc2_exit_partial_power_down(hsotg, 0, true); diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index b517a7216de2..680737d471c1 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -3420,8 +3420,11 @@ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg, dwc2_hsotg_init_fifo(hsotg); - if (!is_usb_reset) + if (!is_usb_reset) { dwc2_set_bit(hsotg, DCTL, DCTL_SFTDISCON); + if (hsotg->params.eusb2_disc) + dwc2_set_bit(hsotg, GOTGCTL, GOTGCTL_EUSB2_DISC_SUPP); + } dcfg |= DCFG_EPMISCNT(1); -- cgit v1.2.3-59-g8ed1b From 535a88dc7d61b740bba4fdbe2b0b5a517d8d1820 Mon Sep 17 00:00:00 2001 From: Minas Harutyunyan Date: Wed, 13 Mar 2024 09:19:52 +0000 Subject: usb: dwc2: New bit definition in GPWRDN register Added new bit ULPI_LATCH_EN_DURING_HIB_ENTRY in GPWRDN register. This bit applicable HSOTG cores v5.00 or higher. Affects Hibernation Entry and Exit sequence (for both Host and Device) when using ULPI PHY. Signed-off-by: Minas Harutyunyan Link: https://lore.kernel.org/r/56d05a4f5750aaa58d8c5bab7705814942a985bd.1708948356.git.Minas.Harutyunyan@synopsys.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc2/hw.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/dwc2/hw.h b/drivers/usb/dwc2/hw.h index c1d5d46c33e3..5e449393b0d7 100644 --- a/drivers/usb/dwc2/hw.h +++ b/drivers/usb/dwc2/hw.h @@ -333,6 +333,8 @@ #define GLPMCFG_LPMCAP BIT(0) #define GPWRDN HSOTG_REG(0x0058) + +#define GPWRDN_ULPI_LATCH_EN_DURING_HIB_ENTRY BIT(29) #define GPWRDN_MULT_VAL_ID_BC_MASK (0x1f << 24) #define GPWRDN_MULT_VAL_ID_BC_SHIFT 24 #define GPWRDN_ADP_INT BIT(23) -- cgit v1.2.3-59-g8ed1b From 4483ef3c1685290251f7caf18377f793e0901460 Mon Sep 17 00:00:00 2001 From: Minas Harutyunyan Date: Wed, 13 Mar 2024 09:20:03 +0000 Subject: usb: dwc2: Add hibernation updates for ULPI PHY Added programmming of ULPI_LATCH_EN_DURING_HIB_ENTRY bit in GPWRDN register when using ULPI PHY during entry/exit to/from hibernation. This bit set to 1 during entering to hibernation if ULPI PHY used. On exiting from hibernation this bit reset to 0. Applicable for both host and device modes. Signed-off-by: Minas Harutyunyan Link: https://lore.kernel.org/r/e024cb39a7177ec201c873df25ca6365f2e55947.1708948356.git.Minas.Harutyunyan@synopsys.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc2/core.c | 5 +++++ drivers/usb/dwc2/core_intr.c | 5 +++++ drivers/usb/dwc2/gadget.c | 23 +++++++++++++++++++++++ drivers/usb/dwc2/hcd.c | 10 ++++++++++ 4 files changed, 43 insertions(+) diff --git a/drivers/usb/dwc2/core.c b/drivers/usb/dwc2/core.c index 5635e4d7ec88..b7a76eb089c9 100644 --- a/drivers/usb/dwc2/core.c +++ b/drivers/usb/dwc2/core.c @@ -249,6 +249,11 @@ void dwc2_hib_restore_common(struct dwc2_hsotg *hsotg, int rem_wakeup, dwc2_writel(hsotg, gpwrdn, GPWRDN); udelay(10); + /* Reset ULPI latch */ + gpwrdn = dwc2_readl(hsotg, GPWRDN); + gpwrdn &= ~GPWRDN_ULPI_LATCH_EN_DURING_HIB_ENTRY; + dwc2_writel(hsotg, gpwrdn, GPWRDN); + /* Disable PMU interrupt */ gpwrdn = dwc2_readl(hsotg, GPWRDN); gpwrdn &= ~GPWRDN_PMUINTSEL; diff --git a/drivers/usb/dwc2/core_intr.c b/drivers/usb/dwc2/core_intr.c index bb6bb771375a..aee779898c06 100644 --- a/drivers/usb/dwc2/core_intr.c +++ b/drivers/usb/dwc2/core_intr.c @@ -705,6 +705,11 @@ static inline void dwc_handle_gpwrdn_disc_det(struct dwc2_hsotg *hsotg, gpwrdn_tmp &= ~GPWRDN_PMUINTSEL; dwc2_writel(hsotg, gpwrdn_tmp, GPWRDN); + /* Reset ULPI latch */ + gpwrdn = dwc2_readl(hsotg, GPWRDN); + gpwrdn &= ~GPWRDN_ULPI_LATCH_EN_DURING_HIB_ENTRY; + dwc2_writel(hsotg, gpwrdn, GPWRDN); + /* De-assert Wakeup Logic */ gpwrdn_tmp = dwc2_readl(hsotg, GPWRDN); gpwrdn_tmp &= ~GPWRDN_PMUACTV; diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index 680737d471c1..f67e69999e3e 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -5309,6 +5309,8 @@ void dwc2_gadget_program_ref_clk(struct dwc2_hsotg *hsotg) int dwc2_gadget_enter_hibernation(struct dwc2_hsotg *hsotg) { u32 gpwrdn; + u32 gusbcfg; + u32 pcgcctl; int ret = 0; /* Change to L2(suspend) state */ @@ -5328,6 +5330,22 @@ int dwc2_gadget_enter_hibernation(struct dwc2_hsotg *hsotg) } gpwrdn = GPWRDN_PWRDNRSTN; + udelay(10); + gusbcfg = dwc2_readl(hsotg, GUSBCFG); + if (gusbcfg & GUSBCFG_ULPI_UTMI_SEL) { + /* ULPI interface */ + gpwrdn |= GPWRDN_ULPI_LATCH_EN_DURING_HIB_ENTRY; + } + dwc2_writel(hsotg, gpwrdn, GPWRDN); + udelay(10); + + /* Suspend the Phy Clock */ + pcgcctl = dwc2_readl(hsotg, PCGCTL); + pcgcctl |= PCGCTL_STOPPCLK; + dwc2_writel(hsotg, pcgcctl, PCGCTL); + udelay(10); + + gpwrdn = dwc2_readl(hsotg, GPWRDN); gpwrdn |= GPWRDN_PMUACTV; dwc2_writel(hsotg, gpwrdn, GPWRDN); udelay(10); @@ -5428,6 +5446,11 @@ int dwc2_gadget_exit_hibernation(struct dwc2_hsotg *hsotg, if (reset) dwc2_clear_bit(hsotg, DCFG, DCFG_DEVADDR_MASK); + /* Reset ULPI latch */ + gpwrdn = dwc2_readl(hsotg, GPWRDN); + gpwrdn &= ~GPWRDN_ULPI_LATCH_EN_DURING_HIB_ENTRY; + dwc2_writel(hsotg, gpwrdn, GPWRDN); + /* De-assert Wakeup Logic */ gpwrdn = dwc2_readl(hsotg, GPWRDN); gpwrdn &= ~GPWRDN_PMUACTV; diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c index 35c7a4df8e71..cc75a7062910 100644 --- a/drivers/usb/dwc2/hcd.c +++ b/drivers/usb/dwc2/hcd.c @@ -5503,6 +5503,11 @@ int dwc2_host_enter_hibernation(struct dwc2_hsotg *hsotg) gusbcfg = dwc2_readl(hsotg, GUSBCFG); if (gusbcfg & GUSBCFG_ULPI_UTMI_SEL) { /* ULPI interface */ + udelay(10); + gpwrdn = dwc2_readl(hsotg, GPWRDN); + gpwrdn |= GPWRDN_ULPI_LATCH_EN_DURING_HIB_ENTRY; + dwc2_writel(hsotg, gpwrdn, GPWRDN); + udelay(10); /* Suspend the Phy Clock */ pcgcctl = dwc2_readl(hsotg, PCGCTL); pcgcctl |= PCGCTL_STOPPCLK; @@ -5609,6 +5614,11 @@ int dwc2_host_exit_hibernation(struct dwc2_hsotg *hsotg, int rem_wakeup, dwc2_writel(hsotg, gr->gusbcfg, GUSBCFG); dwc2_writel(hsotg, hr->hcfg, HCFG); + /* Reset ULPI latch */ + gpwrdn = dwc2_readl(hsotg, GPWRDN); + gpwrdn &= ~GPWRDN_ULPI_LATCH_EN_DURING_HIB_ENTRY; + dwc2_writel(hsotg, gpwrdn, GPWRDN); + /* De-assert Wakeup Logic */ gpwrdn = dwc2_readl(hsotg, GPWRDN); gpwrdn &= ~GPWRDN_PMUACTV; -- cgit v1.2.3-59-g8ed1b From f8453bbde06c5d515b8487eb443d26307b2eec23 Mon Sep 17 00:00:00 2001 From: Minas Harutyunyan Date: Wed, 13 Mar 2024 09:20:12 +0000 Subject: usb: dwc2: New bitfield definition and programming in GRSTCTL Added new bitfield GRSTCTL_CLOCK_SWITH_TIMER in GRSTCTL register. This bitfield applicable HSOTG cores v5.00 or higher and not applicable to HS/FS IOT devices. This bitfield must be programmed to 3'b010 if core will be used in Low-speed and core configured for any HS/FS PHY interface. This bitfield must be programmed to 3'b111 if core configured to use either: - HS PHY interface UTMI or ULPI - FS PHY any interface Signed-off-by: Minas Harutyunyan Link: https://lore.kernel.org/r/0616838cfee958774c9321c6eeeda4be92f900d8.1708948356.git.Minas.Harutyunyan@synopsys.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc2/core.c | 37 +++++++++++++++++++++++++++++++++++++ drivers/usb/dwc2/hw.h | 11 +++++++++++ 2 files changed, 48 insertions(+) diff --git a/drivers/usb/dwc2/core.c b/drivers/usb/dwc2/core.c index b7a76eb089c9..9919ab725d54 100644 --- a/drivers/usb/dwc2/core.c +++ b/drivers/usb/dwc2/core.c @@ -980,6 +980,41 @@ void dwc2_init_fs_ls_pclk_sel(struct dwc2_hsotg *hsotg) dwc2_writel(hsotg, hcfg, HCFG); } +static void dwc2_set_clock_switch_timer(struct dwc2_hsotg *hsotg) +{ + u32 grstctl, gsnpsid, val = 0; + + gsnpsid = dwc2_readl(hsotg, GSNPSID); + + /* + * Applicable only to HSOTG core v5.00a or higher. + * Not applicable to HS/FS IOT devices. + */ + if ((gsnpsid & ~DWC2_CORE_REV_MASK) != DWC2_OTG_ID || + gsnpsid < DWC2_CORE_REV_5_00a) + return; + + if ((hsotg->hw_params.hs_phy_type == GHWCFG2_HS_PHY_TYPE_UTMI && + hsotg->hw_params.fs_phy_type == GHWCFG2_FS_PHY_TYPE_NOT_SUPPORTED) || + (hsotg->hw_params.hs_phy_type == GHWCFG2_HS_PHY_TYPE_ULPI && + hsotg->hw_params.fs_phy_type == GHWCFG2_FS_PHY_TYPE_NOT_SUPPORTED) || + (hsotg->hw_params.hs_phy_type == GHWCFG2_HS_PHY_TYPE_NOT_SUPPORTED && + hsotg->hw_params.fs_phy_type != GHWCFG2_FS_PHY_TYPE_NOT_SUPPORTED)) { + val = GRSTCTL_CLOCK_SWITH_TIMER_VALUE_DIS; + } + + if (hsotg->params.speed == DWC2_SPEED_PARAM_LOW && + hsotg->hw_params.hs_phy_type != GHWCFG2_HS_PHY_TYPE_NOT_SUPPORTED && + hsotg->hw_params.fs_phy_type != GHWCFG2_FS_PHY_TYPE_NOT_SUPPORTED) { + val = GRSTCTL_CLOCK_SWITH_TIMER_VALUE_147; + } + + grstctl = dwc2_readl(hsotg, GRSTCTL); + grstctl &= ~GRSTCTL_CLOCK_SWITH_TIMER_MASK; + grstctl |= GRSTCTL_CLOCK_SWITH_TIMER(val); + dwc2_writel(hsotg, grstctl, GRSTCTL); +} + static int dwc2_fs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy) { u32 usbcfg, ggpio, i2cctl; @@ -997,6 +1032,8 @@ static int dwc2_fs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy) usbcfg |= GUSBCFG_PHYSEL; dwc2_writel(hsotg, usbcfg, GUSBCFG); + dwc2_set_clock_switch_timer(hsotg); + /* Reset after a PHY select */ retval = dwc2_core_reset(hsotg, false); diff --git a/drivers/usb/dwc2/hw.h b/drivers/usb/dwc2/hw.h index 5e449393b0d7..48699caa8739 100644 --- a/drivers/usb/dwc2/hw.h +++ b/drivers/usb/dwc2/hw.h @@ -99,6 +99,17 @@ #define GRSTCTL_AHBIDLE BIT(31) #define GRSTCTL_DMAREQ BIT(30) #define GRSTCTL_CSFTRST_DONE BIT(29) +#define GRSTCTL_CLOCK_SWITH_TIMER_MASK (0x7 << 11) +#define GRSTCTL_CLOCK_SWITH_TIMER_SHIFT 11 +#define GRSTCTL_CLOCK_SWITH_TIMER_VALUE_19 0x0 +#define GRSTCTL_CLOCK_SWITH_TIMER_VALUE_15 0x1 +#define GRSTCTL_CLOCK_SWITH_TIMER_VALUE_147 0x2 +#define GRSTCTL_CLOCK_SWITH_TIMER_VALUE_50 0x3 +#define GRSTCTL_CLOCK_SWITH_TIMER_VALUE_100 0x4 +#define GRSTCTL_CLOCK_SWITH_TIMER_VALUE_125 0x5 +#define GRSTCTL_CLOCK_SWITH_TIMER_VALUE_200 0x6 +#define GRSTCTL_CLOCK_SWITH_TIMER_VALUE_DIS 0x7 +#define GRSTCTL_CLOCK_SWITH_TIMER(_x) ((_x) << 11) #define GRSTCTL_TXFNUM_MASK (0x1f << 6) #define GRSTCTL_TXFNUM_SHIFT 6 #define GRSTCTL_TXFNUM_LIMIT 0x1f -- cgit v1.2.3-59-g8ed1b From 16fac242177c5eb374bb2caacc28793732857369 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 23 Mar 2024 07:57:03 +0100 Subject: usb: gadget: u_audio: Fix the size of a buffer in a strscpy() call The size given to strscpy() is not consistent with the destination buffer that is used. The size is related to 'driver' and the buffer is 'mixername'. sizeof(card->mixername) is 80 and sizeof(card->driver) is 16, so in theory this could lead to unneeded string truncation. In practice, this is not the case because g_audio_setup() has only 2 callers. 'card_name' is either "UAC1_Gadget" or "UAC2_Gadget". Anyway, using the correct size is cleaner and more future proof. In order to be less verbose, use the new 2-argument version of strscpy() which computes auto-magically the size of the destination. Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/bf8a9353319566624f653531b80e5caf3d346ba1.1711176700.git.christophe.jaillet@wanadoo.fr Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/function/u_audio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/function/u_audio.c b/drivers/usb/gadget/function/u_audio.c index 4a42574b4a7f..00ff623b4ebb 100644 --- a/drivers/usb/gadget/function/u_audio.c +++ b/drivers/usb/gadget/function/u_audio.c @@ -1257,7 +1257,7 @@ int g_audio_setup(struct g_audio *g_audio, const char *pcm_name, if ((c_chmask && g_audio->in_ep_fback) || (p_chmask && params->p_fu.id) || (c_chmask && params->c_fu.id)) - strscpy(card->mixername, card_name, sizeof(card->driver)); + strscpy(card->mixername, card_name); if (c_chmask && g_audio->in_ep_fback) { kctl = snd_ctl_new1(&u_audio_controls[UAC_FBACK_CTRL], -- cgit v1.2.3-59-g8ed1b From 39c34568d786ae97180faf79ecfd31c3d0671ba6 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 23 Mar 2024 07:57:04 +0100 Subject: usb: gadget: u_audio: Use the 2-argument version of strscpy() In order to be consistent with other strscpy() usage in this file and less verbose, use the new 2-argument version of strscpy() which computes auto-magically the size of the destination. Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/e7fd0ec5a8b37799271c6d74c325cfb980d44181.1711176701.git.christophe.jaillet@wanadoo.fr Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/function/u_audio.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/usb/gadget/function/u_audio.c b/drivers/usb/gadget/function/u_audio.c index 00ff623b4ebb..5dba7ed9b0a1 100644 --- a/drivers/usb/gadget/function/u_audio.c +++ b/drivers/usb/gadget/function/u_audio.c @@ -1243,7 +1243,7 @@ int g_audio_setup(struct g_audio *g_audio, const char *pcm_name, if (err < 0) goto snd_fail; - strscpy(pcm->name, pcm_name, sizeof(pcm->name)); + strscpy(pcm->name, pcm_name); pcm->private_data = uac; uac->pcm = pcm; @@ -1386,8 +1386,8 @@ int g_audio_setup(struct g_audio *g_audio, const char *pcm_name, prm->snd_kctl_rate = kctl; } - strscpy(card->driver, card_name, sizeof(card->driver)); - strscpy(card->shortname, card_name, sizeof(card->shortname)); + strscpy(card->driver, card_name); + strscpy(card->shortname, card_name); sprintf(card->longname, "%s %i", card_name, card->dev->id); snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, -- cgit v1.2.3-59-g8ed1b From 54ada48481a134b5953bc37cafd1ad89cd68c133 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 23 Mar 2024 07:57:05 +0100 Subject: usb: gadget: u_audio: Use snprintf() instead of sprintf() In order to be consistent with other s[n]printf() usage in this file, switch to snprintf() here as well. Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/5703e697687e4a39059bf90659969ffc86b2cfbd.1711176701.git.christophe.jaillet@wanadoo.fr Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/function/u_audio.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/usb/gadget/function/u_audio.c b/drivers/usb/gadget/function/u_audio.c index 5dba7ed9b0a1..1a634646bd24 100644 --- a/drivers/usb/gadget/function/u_audio.c +++ b/drivers/usb/gadget/function/u_audio.c @@ -1388,7 +1388,8 @@ int g_audio_setup(struct g_audio *g_audio, const char *pcm_name, strscpy(card->driver, card_name); strscpy(card->shortname, card_name); - sprintf(card->longname, "%s %i", card_name, card->dev->id); + snprintf(card->longname, sizeof(card->longname), "%s %i", + card_name, card->dev->id); snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, NULL, 0, BUFF_SIZE_MAX); -- cgit v1.2.3-59-g8ed1b From 8e7142817bd6c52758d3b01167048cd346546616 Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Fri, 22 Mar 2024 09:01:33 +0100 Subject: dt-bindings: usb: qcom,pmic-typec: Add support for the PM7250B PMIC The PM6150 PMIC has the same Type-C register block as the PM8150B. Define corresponding compatible string, having the qcom,pm8150b-vbus-reg as a fallback. Signed-off-by: Luca Weiss Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20240322-fp4-tcpm-v1-2-c5644099d57b@fairphone.com Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/usb/qcom,pmic-typec.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/usb/qcom,pmic-typec.yaml b/Documentation/devicetree/bindings/usb/qcom,pmic-typec.yaml index d9694570c419..0cdc60b76fbd 100644 --- a/Documentation/devicetree/bindings/usb/qcom,pmic-typec.yaml +++ b/Documentation/devicetree/bindings/usb/qcom,pmic-typec.yaml @@ -21,6 +21,7 @@ properties: - items: - enum: - qcom,pm6150-typec + - qcom,pm7250b-typec - const: qcom,pm8150b-typec - items: - enum: -- cgit v1.2.3-59-g8ed1b From 3dfbd2d26b646271c4a0291dd7325d5b06a17a21 Mon Sep 17 00:00:00 2001 From: Stafford Horne Date: Sun, 10 Mar 2024 11:21:26 +0000 Subject: riscv: Remove unused asm/signal.h file When riscv moved to common entry the definition and usage of do_work_pending was removed. This unused header file remains. Remove the header file as it is not used. I have tested compiling the kernel with this patch applied and saw no issues. Noticed when auditing how different ports handle signals related to saving FPU state. Fixes: f0bddf50586d ("riscv: entry: Convert to generic entry") Signed-off-by: Stafford Horne Reviewed-by: Guo Ren Link: https://lore.kernel.org/r/20240310112129.376134-1-shorne@gmail.com Signed-off-by: Palmer Dabbelt --- arch/riscv/include/asm/signal.h | 12 ------------ 1 file changed, 12 deletions(-) delete mode 100644 arch/riscv/include/asm/signal.h diff --git a/arch/riscv/include/asm/signal.h b/arch/riscv/include/asm/signal.h deleted file mode 100644 index 956ae0a01bad..000000000000 --- a/arch/riscv/include/asm/signal.h +++ /dev/null @@ -1,12 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ - -#ifndef __ASM_SIGNAL_H -#define __ASM_SIGNAL_H - -#include -#include - -asmlinkage __visible -void do_work_pending(struct pt_regs *regs, unsigned long thread_info_flags); - -#endif -- cgit v1.2.3-59-g8ed1b From 20952655235dd9b1447829591774f1d8561f7c6a Mon Sep 17 00:00:00 2001 From: Philipp Hortmann Date: Tue, 26 Mar 2024 09:47:42 +0100 Subject: staging: wlan-ng: Remove broken driver prism2_usb Driver has a throughput of 200 to 800kByte/s in non encrypted transmission. All encrypted modes are not working. WLAN without WPA2 is useless these days. Driver is unused since April 2021 as a bug broke the function. Find fix for bug in link below. Remove driver because of its low performance and unusability. Link: https://lore.kernel.org/linux-staging/5fa18cb8-3c51-4ac6-811e-63ae74f82f17@gmail.com/ Signed-off-by: Philipp Hortmann Link: https://lore.kernel.org/r/20240326084742.GA16228@matrix-ESPRIMO-P710 Signed-off-by: Greg Kroah-Hartman --- drivers/staging/Kconfig | 2 - drivers/staging/Makefile | 1 - drivers/staging/wlan-ng/Kconfig | 13 - drivers/staging/wlan-ng/Makefile | 8 - drivers/staging/wlan-ng/README | 8 - drivers/staging/wlan-ng/TODO | 16 - drivers/staging/wlan-ng/cfg80211.c | 718 ----- drivers/staging/wlan-ng/hfa384x.h | 1236 --------- drivers/staging/wlan-ng/hfa384x_usb.c | 3880 ---------------------------- drivers/staging/wlan-ng/p80211conv.c | 643 ----- drivers/staging/wlan-ng/p80211conv.h | 141 - drivers/staging/wlan-ng/p80211hdr.h | 189 -- drivers/staging/wlan-ng/p80211ioctl.h | 69 - drivers/staging/wlan-ng/p80211metadef.h | 227 -- drivers/staging/wlan-ng/p80211metastruct.h | 236 -- drivers/staging/wlan-ng/p80211mgmt.h | 199 -- drivers/staging/wlan-ng/p80211msg.h | 39 - drivers/staging/wlan-ng/p80211netdev.c | 988 ------- drivers/staging/wlan-ng/p80211netdev.h | 212 -- drivers/staging/wlan-ng/p80211req.c | 223 -- drivers/staging/wlan-ng/p80211req.h | 33 - drivers/staging/wlan-ng/p80211types.h | 292 --- drivers/staging/wlan-ng/p80211wep.c | 207 -- drivers/staging/wlan-ng/prism2fw.c | 1213 --------- drivers/staging/wlan-ng/prism2mgmt.c | 1315 ---------- drivers/staging/wlan-ng/prism2mgmt.h | 89 - drivers/staging/wlan-ng/prism2mib.c | 742 ------ drivers/staging/wlan-ng/prism2sta.c | 1945 -------------- drivers/staging/wlan-ng/prism2usb.c | 299 --- 29 files changed, 15183 deletions(-) delete mode 100644 drivers/staging/wlan-ng/Kconfig delete mode 100644 drivers/staging/wlan-ng/Makefile delete mode 100644 drivers/staging/wlan-ng/README delete mode 100644 drivers/staging/wlan-ng/TODO delete mode 100644 drivers/staging/wlan-ng/cfg80211.c delete mode 100644 drivers/staging/wlan-ng/hfa384x.h delete mode 100644 drivers/staging/wlan-ng/hfa384x_usb.c delete mode 100644 drivers/staging/wlan-ng/p80211conv.c delete mode 100644 drivers/staging/wlan-ng/p80211conv.h delete mode 100644 drivers/staging/wlan-ng/p80211hdr.h delete mode 100644 drivers/staging/wlan-ng/p80211ioctl.h delete mode 100644 drivers/staging/wlan-ng/p80211metadef.h delete mode 100644 drivers/staging/wlan-ng/p80211metastruct.h delete mode 100644 drivers/staging/wlan-ng/p80211mgmt.h delete mode 100644 drivers/staging/wlan-ng/p80211msg.h delete mode 100644 drivers/staging/wlan-ng/p80211netdev.c delete mode 100644 drivers/staging/wlan-ng/p80211netdev.h delete mode 100644 drivers/staging/wlan-ng/p80211req.c delete mode 100644 drivers/staging/wlan-ng/p80211req.h delete mode 100644 drivers/staging/wlan-ng/p80211types.h delete mode 100644 drivers/staging/wlan-ng/p80211wep.c delete mode 100644 drivers/staging/wlan-ng/prism2fw.c delete mode 100644 drivers/staging/wlan-ng/prism2mgmt.c delete mode 100644 drivers/staging/wlan-ng/prism2mgmt.h delete mode 100644 drivers/staging/wlan-ng/prism2mib.c delete mode 100644 drivers/staging/wlan-ng/prism2sta.c delete mode 100644 drivers/staging/wlan-ng/prism2usb.c diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index 5175b1c4f161..8e0e9ab37302 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -24,8 +24,6 @@ menuconfig STAGING if STAGING -source "drivers/staging/wlan-ng/Kconfig" - source "drivers/staging/olpc_dcon/Kconfig" source "drivers/staging/rtl8192e/Kconfig" diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index 67399c0ad871..471b483e9042 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -2,7 +2,6 @@ # Makefile for staging directory obj-y += media/ -obj-$(CONFIG_PRISM2_USB) += wlan-ng/ obj-$(CONFIG_FB_OLPC_DCON) += olpc_dcon/ obj-$(CONFIG_RTL8192E) += rtl8192e/ obj-$(CONFIG_RTL8723BS) += rtl8723bs/ diff --git a/drivers/staging/wlan-ng/Kconfig b/drivers/staging/wlan-ng/Kconfig deleted file mode 100644 index 082c16a31616..000000000000 --- a/drivers/staging/wlan-ng/Kconfig +++ /dev/null @@ -1,13 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -config PRISM2_USB - tristate "Prism2.5/3 USB driver" - depends on WLAN && USB && CFG80211 - select WIRELESS_EXT - select WEXT_PRIV - select CRC32 - help - This is the wlan-ng prism 2.5/3 USB driver for a wide range of - old USB wireless devices. - - To compile this driver as a module, choose M here: the module - will be called prism2_usb. diff --git a/drivers/staging/wlan-ng/Makefile b/drivers/staging/wlan-ng/Makefile deleted file mode 100644 index 1d24b0f86eee..000000000000 --- a/drivers/staging/wlan-ng/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -obj-$(CONFIG_PRISM2_USB) += prism2_usb.o - -prism2_usb-y := prism2usb.o \ - p80211conv.o \ - p80211req.o \ - p80211wep.o \ - p80211netdev.o diff --git a/drivers/staging/wlan-ng/README b/drivers/staging/wlan-ng/README deleted file mode 100644 index d0621f827c01..000000000000 --- a/drivers/staging/wlan-ng/README +++ /dev/null @@ -1,8 +0,0 @@ -TODO: - - checkpatch.pl cleanups - - sparse warnings - - move to use the in-kernel wireless stack - -Please send any patches or complaints about this driver to Greg -Kroah-Hartman and don't bother the upstream wireless -kernel developers about it, they want nothing to do with it. diff --git a/drivers/staging/wlan-ng/TODO b/drivers/staging/wlan-ng/TODO deleted file mode 100644 index ab9d5d145b3b..000000000000 --- a/drivers/staging/wlan-ng/TODO +++ /dev/null @@ -1,16 +0,0 @@ -To-do list: - -* Correct the coding style according to Linux guidelines; please read the document - at https://www.kernel.org/doc/html/latest/process/coding-style.html. -* Remove unnecessary debugging/printing macros; for those that are still needed - use the proper kernel API (pr_debug(), dev_dbg(), netdev_dbg()). -* Remove dead code such as unusued functions, variables, fields, etc.. -* Use in-kernel API and remove unnecessary wrappers where possible. -* Fix bugs due to code that sleeps in atomic context. -* Remove the HAL layer and migrate its functionality into the relevant parts of - the driver. -* Switch to use LIB80211. -* Switch to use MAC80211. -* Switch to use CFG80211. -* Improve the error handling of various functions, particularly those that use - existing kernel APIs. diff --git a/drivers/staging/wlan-ng/cfg80211.c b/drivers/staging/wlan-ng/cfg80211.c deleted file mode 100644 index 471bb310176f..000000000000 --- a/drivers/staging/wlan-ng/cfg80211.c +++ /dev/null @@ -1,718 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* cfg80211 Interface for prism2_usb module */ -#include "hfa384x.h" -#include "prism2mgmt.h" - -/* Prism2 channel/frequency/bitrate declarations */ -static const struct ieee80211_channel prism2_channels[] = { - { .center_freq = 2412 }, - { .center_freq = 2417 }, - { .center_freq = 2422 }, - { .center_freq = 2427 }, - { .center_freq = 2432 }, - { .center_freq = 2437 }, - { .center_freq = 2442 }, - { .center_freq = 2447 }, - { .center_freq = 2452 }, - { .center_freq = 2457 }, - { .center_freq = 2462 }, - { .center_freq = 2467 }, - { .center_freq = 2472 }, - { .center_freq = 2484 }, -}; - -static const struct ieee80211_rate prism2_rates[] = { - { .bitrate = 10 }, - { .bitrate = 20 }, - { .bitrate = 55 }, - { .bitrate = 110 } -}; - -#define PRISM2_NUM_CIPHER_SUITES 2 -static const u32 prism2_cipher_suites[PRISM2_NUM_CIPHER_SUITES] = { - WLAN_CIPHER_SUITE_WEP40, - WLAN_CIPHER_SUITE_WEP104 -}; - -/* prism2 device private data */ -struct prism2_wiphy_private { - struct wlandevice *wlandev; - - struct ieee80211_supported_band band; - struct ieee80211_channel channels[ARRAY_SIZE(prism2_channels)]; - struct ieee80211_rate rates[ARRAY_SIZE(prism2_rates)]; - - struct cfg80211_scan_request *scan_request; -}; - -static const void * const prism2_wiphy_privid = &prism2_wiphy_privid; - -/* Helper Functions */ -static int prism2_result2err(int prism2_result) -{ - int err = 0; - - switch (prism2_result) { - case P80211ENUM_resultcode_invalid_parameters: - err = -EINVAL; - break; - case P80211ENUM_resultcode_implementation_failure: - err = -EIO; - break; - case P80211ENUM_resultcode_not_supported: - err = -EOPNOTSUPP; - break; - default: - err = 0; - break; - } - - return err; -} - -static int prism2_domibset_uint32(struct wlandevice *wlandev, - u32 did, u32 data) -{ - struct p80211msg_dot11req_mibset msg; - struct p80211item_uint32 *mibitem = - (struct p80211item_uint32 *)&msg.mibattribute.data; - - msg.msgcode = DIDMSG_DOT11REQ_MIBSET; - mibitem->did = did; - mibitem->data = data; - - return p80211req_dorequest(wlandev, (u8 *)&msg); -} - -static int prism2_domibset_pstr32(struct wlandevice *wlandev, - u32 did, u8 len, const u8 *data) -{ - struct p80211msg_dot11req_mibset msg; - struct p80211item_pstr32 *mibitem = - (struct p80211item_pstr32 *)&msg.mibattribute.data; - - msg.msgcode = DIDMSG_DOT11REQ_MIBSET; - mibitem->did = did; - mibitem->data.len = len; - memcpy(mibitem->data.data, data, len); - - return p80211req_dorequest(wlandev, (u8 *)&msg); -} - -/* The interface functions, called by the cfg80211 layer */ -static int prism2_change_virtual_intf(struct wiphy *wiphy, - struct net_device *dev, - enum nl80211_iftype type, - struct vif_params *params) -{ - struct wlandevice *wlandev = dev->ml_priv; - u32 data; - int result; - int err = 0; - - switch (type) { - case NL80211_IFTYPE_ADHOC: - if (wlandev->macmode == WLAN_MACMODE_IBSS_STA) - goto exit; - wlandev->macmode = WLAN_MACMODE_IBSS_STA; - data = 0; - break; - case NL80211_IFTYPE_STATION: - if (wlandev->macmode == WLAN_MACMODE_ESS_STA) - goto exit; - wlandev->macmode = WLAN_MACMODE_ESS_STA; - data = 1; - break; - default: - netdev_warn(dev, "Operation mode: %d not support\n", type); - return -EOPNOTSUPP; - } - - /* Set Operation mode to the PORT TYPE RID */ - result = prism2_domibset_uint32(wlandev, - DIDMIB_P2_STATIC_CNFPORTTYPE, - data); - - if (result) - err = -EFAULT; - - dev->ieee80211_ptr->iftype = type; - -exit: - return err; -} - -static int prism2_add_key(struct wiphy *wiphy, struct net_device *dev, - int link_id, u8 key_index, bool pairwise, - const u8 *mac_addr, struct key_params *params) -{ - struct wlandevice *wlandev = dev->ml_priv; - u32 did; - - if (key_index >= NUM_WEPKEYS) - return -EINVAL; - - if (params->cipher != WLAN_CIPHER_SUITE_WEP40 && - params->cipher != WLAN_CIPHER_SUITE_WEP104) { - pr_debug("Unsupported cipher suite\n"); - return -EFAULT; - } - - if (prism2_domibset_uint32(wlandev, - DIDMIB_DOT11SMT_PRIVACYTABLE_WEPDEFAULTKEYID, - key_index)) - return -EFAULT; - - /* send key to driver */ - did = didmib_dot11smt_wepdefaultkeystable_key(key_index + 1); - - if (prism2_domibset_pstr32(wlandev, did, params->key_len, params->key)) - return -EFAULT; - return 0; -} - -static int prism2_get_key(struct wiphy *wiphy, struct net_device *dev, - int link_id, u8 key_index, bool pairwise, - const u8 *mac_addr, void *cookie, - void (*callback)(void *cookie, struct key_params*)) -{ - struct wlandevice *wlandev = dev->ml_priv; - struct key_params params; - int len; - - if (key_index >= NUM_WEPKEYS) - return -EINVAL; - - len = wlandev->wep_keylens[key_index]; - memset(¶ms, 0, sizeof(params)); - - if (len == 13) - params.cipher = WLAN_CIPHER_SUITE_WEP104; - else if (len == 5) - params.cipher = WLAN_CIPHER_SUITE_WEP104; - else - return -ENOENT; - params.key_len = len; - params.key = wlandev->wep_keys[key_index]; - params.seq_len = 0; - - callback(cookie, ¶ms); - - return 0; -} - -static int prism2_del_key(struct wiphy *wiphy, struct net_device *dev, - int link_id, u8 key_index, bool pairwise, - const u8 *mac_addr) -{ - struct wlandevice *wlandev = dev->ml_priv; - u32 did; - int err = 0; - int result = 0; - - /* There is no direct way in the hardware (AFAIK) of removing - * a key, so we will cheat by setting the key to a bogus value - */ - - if (key_index >= NUM_WEPKEYS) - return -EINVAL; - - /* send key to driver */ - did = didmib_dot11smt_wepdefaultkeystable_key(key_index + 1); - result = prism2_domibset_pstr32(wlandev, did, 13, "0000000000000"); - - if (result) - err = -EFAULT; - - return err; -} - -static int prism2_set_default_key(struct wiphy *wiphy, struct net_device *dev, - int link_id, u8 key_index, bool unicast, - bool multicast) -{ - struct wlandevice *wlandev = dev->ml_priv; - - return prism2_domibset_uint32(wlandev, - DIDMIB_DOT11SMT_PRIVACYTABLE_WEPDEFAULTKEYID, - key_index); -} - -static int prism2_get_station(struct wiphy *wiphy, struct net_device *dev, - const u8 *mac, struct station_info *sinfo) -{ - struct wlandevice *wlandev = dev->ml_priv; - struct p80211msg_lnxreq_commsquality quality; - int result; - - memset(sinfo, 0, sizeof(*sinfo)); - - if (!wlandev || (wlandev->msdstate != WLAN_MSD_RUNNING)) - return -EOPNOTSUPP; - - /* build request message */ - quality.msgcode = DIDMSG_LNXREQ_COMMSQUALITY; - quality.dbm.data = P80211ENUM_truth_true; - quality.dbm.status = P80211ENUM_msgitem_status_data_ok; - - /* send message to nsd */ - if (!wlandev->mlmerequest) - return -EOPNOTSUPP; - - result = wlandev->mlmerequest(wlandev, (struct p80211msg *)&quality); - - if (result == 0) { - sinfo->txrate.legacy = quality.txrate.data; - sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); - sinfo->signal = quality.level.data; - sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL); - } - - return result; -} - -static int prism2_scan(struct wiphy *wiphy, - struct cfg80211_scan_request *request) -{ - struct net_device *dev; - struct prism2_wiphy_private *priv = wiphy_priv(wiphy); - struct wlandevice *wlandev; - struct p80211msg_dot11req_scan msg1; - struct p80211msg_dot11req_scan_results *msg2; - struct cfg80211_bss *bss; - struct cfg80211_scan_info info = {}; - - int result; - int err = 0; - int numbss = 0; - int i = 0; - u8 ie_buf[46]; - int ie_len; - - if (!request) - return -EINVAL; - - dev = request->wdev->netdev; - wlandev = dev->ml_priv; - - if (priv->scan_request && priv->scan_request != request) - return -EBUSY; - - if (wlandev->macmode == WLAN_MACMODE_ESS_AP) { - netdev_err(dev, "Can't scan in AP mode\n"); - return -EOPNOTSUPP; - } - - msg2 = kzalloc(sizeof(*msg2), GFP_KERNEL); - if (!msg2) - return -ENOMEM; - - priv->scan_request = request; - - memset(&msg1, 0x00, sizeof(msg1)); - msg1.msgcode = DIDMSG_DOT11REQ_SCAN; - msg1.bsstype.data = P80211ENUM_bsstype_any; - - memset(&msg1.bssid.data.data, 0xFF, sizeof(msg1.bssid.data.data)); - msg1.bssid.data.len = 6; - - if (request->n_ssids > 0) { - msg1.scantype.data = P80211ENUM_scantype_active; - msg1.ssid.data.len = request->ssids->ssid_len; - memcpy(msg1.ssid.data.data, - request->ssids->ssid, request->ssids->ssid_len); - } else { - msg1.scantype.data = 0; - } - msg1.probedelay.data = 0; - - for (i = 0; - (i < request->n_channels) && i < ARRAY_SIZE(prism2_channels); - i++) - msg1.channellist.data.data[i] = - ieee80211_frequency_to_channel(request->channels[i]->center_freq); - msg1.channellist.data.len = request->n_channels; - - msg1.maxchanneltime.data = 250; - msg1.minchanneltime.data = 200; - - result = p80211req_dorequest(wlandev, (u8 *)&msg1); - if (result) { - err = prism2_result2err(msg1.resultcode.data); - goto exit; - } - /* Now retrieve scan results */ - numbss = msg1.numbss.data; - - for (i = 0; i < numbss; i++) { - int freq; - - msg2->msgcode = DIDMSG_DOT11REQ_SCAN_RESULTS; - msg2->bssindex.data = i; - - result = p80211req_dorequest(wlandev, (u8 *)&msg2); - if ((result != 0) || - (msg2->resultcode.data != P80211ENUM_resultcode_success)) { - break; - } - - ie_buf[0] = WLAN_EID_SSID; - ie_buf[1] = msg2->ssid.data.len; - ie_len = ie_buf[1] + 2; - memcpy(&ie_buf[2], &msg2->ssid.data.data, msg2->ssid.data.len); - freq = ieee80211_channel_to_frequency(msg2->dschannel.data, - NL80211_BAND_2GHZ); - bss = cfg80211_inform_bss(wiphy, - ieee80211_get_channel(wiphy, freq), - CFG80211_BSS_FTYPE_UNKNOWN, - (const u8 *)&msg2->bssid.data.data, - msg2->timestamp.data, msg2->capinfo.data, - msg2->beaconperiod.data, - ie_buf, - ie_len, - (msg2->signal.data - 65536) * 100, /* Conversion to signed type */ - GFP_KERNEL); - - if (!bss) { - err = -ENOMEM; - goto exit; - } - - cfg80211_put_bss(wiphy, bss); - } - - if (result) - err = prism2_result2err(msg2->resultcode.data); - -exit: - info.aborted = !!(err); - cfg80211_scan_done(request, &info); - priv->scan_request = NULL; - kfree(msg2); - return err; -} - -static int prism2_set_wiphy_params(struct wiphy *wiphy, u32 changed) -{ - struct prism2_wiphy_private *priv = wiphy_priv(wiphy); - struct wlandevice *wlandev = priv->wlandev; - u32 data; - int result; - int err = 0; - - if (changed & WIPHY_PARAM_RTS_THRESHOLD) { - if (wiphy->rts_threshold == -1) - data = 2347; - else - data = wiphy->rts_threshold; - - result = prism2_domibset_uint32(wlandev, - DIDMIB_DOT11MAC_OPERATIONTABLE_RTSTHRESHOLD, - data); - if (result) { - err = -EFAULT; - goto exit; - } - } - - if (changed & WIPHY_PARAM_FRAG_THRESHOLD) { - if (wiphy->frag_threshold == -1) - data = 2346; - else - data = wiphy->frag_threshold; - - result = prism2_domibset_uint32(wlandev, - DIDMIB_DOT11MAC_OPERATIONTABLE_FRAGMENTATIONTHRESHOLD, - data); - if (result) { - err = -EFAULT; - goto exit; - } - } - -exit: - return err; -} - -static int prism2_connect(struct wiphy *wiphy, struct net_device *dev, - struct cfg80211_connect_params *sme) -{ - struct wlandevice *wlandev = dev->ml_priv; - struct ieee80211_channel *channel = sme->channel; - struct p80211msg_lnxreq_autojoin msg_join; - u32 did; - int length = sme->ssid_len; - int chan = -1; - int is_wep = (sme->crypto.cipher_group == WLAN_CIPHER_SUITE_WEP40) || - (sme->crypto.cipher_group == WLAN_CIPHER_SUITE_WEP104); - int result; - int err = 0; - - /* Set the channel */ - if (channel) { - chan = ieee80211_frequency_to_channel(channel->center_freq); - result = prism2_domibset_uint32(wlandev, - DIDMIB_DOT11PHY_DSSSTABLE_CURRENTCHANNEL, - chan); - if (result) - goto exit; - } - - /* Set the authorization */ - if ((sme->auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM) || - ((sme->auth_type == NL80211_AUTHTYPE_AUTOMATIC) && !is_wep)) - msg_join.authtype.data = P80211ENUM_authalg_opensystem; - else if ((sme->auth_type == NL80211_AUTHTYPE_SHARED_KEY) || - ((sme->auth_type == NL80211_AUTHTYPE_AUTOMATIC) && is_wep)) - msg_join.authtype.data = P80211ENUM_authalg_sharedkey; - else - netdev_warn(dev, - "Unhandled authorisation type for connect (%d)\n", - sme->auth_type); - - /* Set the encryption - we only support wep */ - if (is_wep) { - if (sme->key) { - if (sme->key_idx >= NUM_WEPKEYS) - return -EINVAL; - - result = prism2_domibset_uint32(wlandev, - DIDMIB_DOT11SMT_PRIVACYTABLE_WEPDEFAULTKEYID, - sme->key_idx); - if (result) - goto exit; - - /* send key to driver */ - did = didmib_dot11smt_wepdefaultkeystable_key(sme->key_idx + 1); - result = prism2_domibset_pstr32(wlandev, - did, sme->key_len, - (u8 *)sme->key); - if (result) - goto exit; - } - - /* Assume we should set privacy invoked and exclude unencrypted - * We could possible use sme->privacy here, but the assumption - * seems reasonable anyways - */ - result = prism2_domibset_uint32(wlandev, - DIDMIB_DOT11SMT_PRIVACYTABLE_PRIVACYINVOKED, - P80211ENUM_truth_true); - if (result) - goto exit; - - result = prism2_domibset_uint32(wlandev, - DIDMIB_DOT11SMT_PRIVACYTABLE_EXCLUDEUNENCRYPTED, - P80211ENUM_truth_true); - if (result) - goto exit; - - } else { - /* Assume we should unset privacy invoked - * and exclude unencrypted - */ - result = prism2_domibset_uint32(wlandev, - DIDMIB_DOT11SMT_PRIVACYTABLE_PRIVACYINVOKED, - P80211ENUM_truth_false); - if (result) - goto exit; - - result = prism2_domibset_uint32(wlandev, - DIDMIB_DOT11SMT_PRIVACYTABLE_EXCLUDEUNENCRYPTED, - P80211ENUM_truth_false); - if (result) - goto exit; - } - - /* Now do the actual join. Note there is no way that I can - * see to request a specific bssid - */ - msg_join.msgcode = DIDMSG_LNXREQ_AUTOJOIN; - - memcpy(msg_join.ssid.data.data, sme->ssid, length); - msg_join.ssid.data.len = length; - - result = p80211req_dorequest(wlandev, (u8 *)&msg_join); - -exit: - if (result) - err = -EFAULT; - - return err; -} - -static int prism2_disconnect(struct wiphy *wiphy, struct net_device *dev, - u16 reason_code) -{ - struct wlandevice *wlandev = dev->ml_priv; - struct p80211msg_lnxreq_autojoin msg_join; - int result; - int err = 0; - - /* Do a join, with a bogus ssid. Thats the only way I can think of */ - msg_join.msgcode = DIDMSG_LNXREQ_AUTOJOIN; - - memcpy(msg_join.ssid.data.data, "---", 3); - msg_join.ssid.data.len = 3; - - result = p80211req_dorequest(wlandev, (u8 *)&msg_join); - - if (result) - err = -EFAULT; - - return err; -} - -static int prism2_join_ibss(struct wiphy *wiphy, struct net_device *dev, - struct cfg80211_ibss_params *params) -{ - return -EOPNOTSUPP; -} - -static int prism2_leave_ibss(struct wiphy *wiphy, struct net_device *dev) -{ - return -EOPNOTSUPP; -} - -static int prism2_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev, - enum nl80211_tx_power_setting type, int mbm) -{ - struct prism2_wiphy_private *priv = wiphy_priv(wiphy); - struct wlandevice *wlandev = priv->wlandev; - u32 data; - int result; - int err = 0; - - if (type == NL80211_TX_POWER_AUTOMATIC) - data = 30; - else - data = MBM_TO_DBM(mbm); - - result = prism2_domibset_uint32(wlandev, - DIDMIB_DOT11PHY_TXPOWERTABLE_CURRENTTXPOWERLEVEL, - data); - - if (result) { - err = -EFAULT; - goto exit; - } - -exit: - return err; -} - -static int prism2_get_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev, - int *dbm) -{ - struct prism2_wiphy_private *priv = wiphy_priv(wiphy); - struct wlandevice *wlandev = priv->wlandev; - struct p80211msg_dot11req_mibget msg; - struct p80211item_uint32 *mibitem; - int result; - int err = 0; - - mibitem = (struct p80211item_uint32 *)&msg.mibattribute.data; - msg.msgcode = DIDMSG_DOT11REQ_MIBGET; - mibitem->did = DIDMIB_DOT11PHY_TXPOWERTABLE_CURRENTTXPOWERLEVEL; - - result = p80211req_dorequest(wlandev, (u8 *)&msg); - - if (result) { - err = -EFAULT; - goto exit; - } - - *dbm = mibitem->data; - -exit: - return err; -} - -/* Interface callback functions, passing data back up to the cfg80211 layer */ -void prism2_connect_result(struct wlandevice *wlandev, u8 failed) -{ - u16 status = failed ? - WLAN_STATUS_UNSPECIFIED_FAILURE : WLAN_STATUS_SUCCESS; - - cfg80211_connect_result(wlandev->netdev, wlandev->bssid, - NULL, 0, NULL, 0, status, GFP_KERNEL); -} - -void prism2_disconnected(struct wlandevice *wlandev) -{ - cfg80211_disconnected(wlandev->netdev, 0, NULL, - 0, false, GFP_KERNEL); -} - -void prism2_roamed(struct wlandevice *wlandev) -{ - struct cfg80211_roam_info roam_info = { - .links[0].bssid = wlandev->bssid, - }; - - cfg80211_roamed(wlandev->netdev, &roam_info, GFP_KERNEL); -} - -/* Structures for declaring wiphy interface */ -static const struct cfg80211_ops prism2_usb_cfg_ops = { - .change_virtual_intf = prism2_change_virtual_intf, - .add_key = prism2_add_key, - .get_key = prism2_get_key, - .del_key = prism2_del_key, - .set_default_key = prism2_set_default_key, - .get_station = prism2_get_station, - .scan = prism2_scan, - .set_wiphy_params = prism2_set_wiphy_params, - .connect = prism2_connect, - .disconnect = prism2_disconnect, - .join_ibss = prism2_join_ibss, - .leave_ibss = prism2_leave_ibss, - .set_tx_power = prism2_set_tx_power, - .get_tx_power = prism2_get_tx_power, -}; - -/* Functions to create/free wiphy interface */ -static struct wiphy *wlan_create_wiphy(struct device *dev, - struct wlandevice *wlandev) -{ - struct wiphy *wiphy; - struct prism2_wiphy_private *priv; - - wiphy = wiphy_new(&prism2_usb_cfg_ops, sizeof(*priv)); - if (!wiphy) - return NULL; - - priv = wiphy_priv(wiphy); - priv->wlandev = wlandev; - memcpy(priv->channels, prism2_channels, sizeof(prism2_channels)); - memcpy(priv->rates, prism2_rates, sizeof(prism2_rates)); - priv->band.channels = priv->channels; - priv->band.n_channels = ARRAY_SIZE(prism2_channels); - priv->band.bitrates = priv->rates; - priv->band.n_bitrates = ARRAY_SIZE(prism2_rates); - priv->band.band = NL80211_BAND_2GHZ; - priv->band.ht_cap.ht_supported = false; - wiphy->bands[NL80211_BAND_2GHZ] = &priv->band; - - set_wiphy_dev(wiphy, dev); - wiphy->privid = prism2_wiphy_privid; - wiphy->max_scan_ssids = 1; - wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) - | BIT(NL80211_IFTYPE_ADHOC); - wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; - wiphy->n_cipher_suites = PRISM2_NUM_CIPHER_SUITES; - wiphy->cipher_suites = prism2_cipher_suites; - - if (wiphy_register(wiphy) < 0) { - wiphy_free(wiphy); - return NULL; - } - - return wiphy; -} - -static void wlan_free_wiphy(struct wiphy *wiphy) -{ - wiphy_unregister(wiphy); - wiphy_free(wiphy); -} diff --git a/drivers/staging/wlan-ng/hfa384x.h b/drivers/staging/wlan-ng/hfa384x.h deleted file mode 100644 index a4799589e469..000000000000 --- a/drivers/staging/wlan-ng/hfa384x.h +++ /dev/null @@ -1,1236 +0,0 @@ -/* SPDX-License-Identifier: (GPL-2.0 OR MPL-1.1) */ -/* - * - * Defines the constants and data structures for the hfa384x - * - * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. - * -------------------------------------------------------------------- - * - * linux-wlan - * - * -------------------------------------------------------------------- - * - * Inquiries regarding the linux-wlan Open Source project can be - * made directly to: - * - * AbsoluteValue Systems Inc. - * info@linux-wlan.com - * http://www.linux-wlan.com - * - * -------------------------------------------------------------------- - * - * Portions of the development of this software were funded by - * Intersil Corporation as part of PRISM(R) chipset product development. - * - * -------------------------------------------------------------------- - * - * [Implementation and usage notes] - * - * [References] - * CW10 Programmer's Manual v1.5 - * IEEE 802.11 D10.0 - * - * -------------------------------------------------------------------- - */ - -#ifndef _HFA384x_H -#define _HFA384x_H - -#define HFA384x_FIRMWARE_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + (c)) - -#include -#include - -/*--- Mins & Maxs -----------------------------------*/ -#define HFA384x_PORTID_MAX ((u16)7) -#define HFA384x_NUMPORTS_MAX ((u16)(HFA384x_PORTID_MAX + 1)) -#define HFA384x_PDR_LEN_MAX ((u16)512) /* in bytes, from EK */ -#define HFA384x_PDA_RECS_MAX ((u16)200) /* a guess */ -#define HFA384x_PDA_LEN_MAX ((u16)1024) /* in bytes, from EK*/ -#define HFA384x_SCANRESULT_MAX ((u16)31) -#define HFA384x_HSCANRESULT_MAX ((u16)31) -#define HFA384x_CHINFORESULT_MAX ((u16)16) -#define HFA384x_RID_GUESSING_MAXLEN 2048 /* I'm not really sure */ -#define HFA384x_RIDDATA_MAXLEN HFA384x_RID_GUESSING_MAXLEN -#define HFA384x_USB_RWMEM_MAXLEN 2048 - -/*--- Support Constants -----------------------------*/ -#define HFA384x_PORTTYPE_IBSS ((u16)0) -#define HFA384x_PORTTYPE_BSS ((u16)1) -#define HFA384x_PORTTYPE_PSUEDOIBSS ((u16)3) -#define HFA384x_WEPFLAGS_PRIVINVOKED ((u16)BIT(0)) -#define HFA384x_WEPFLAGS_EXCLUDE ((u16)BIT(1)) -#define HFA384x_WEPFLAGS_DISABLE_TXCRYPT ((u16)BIT(4)) -#define HFA384x_WEPFLAGS_DISABLE_RXCRYPT ((u16)BIT(7)) -#define HFA384x_ROAMMODE_HOSTSCAN_HOSTROAM ((u16)3) -#define HFA384x_PORTSTATUS_DISABLED ((u16)1) -#define HFA384x_RATEBIT_1 ((u16)1) -#define HFA384x_RATEBIT_2 ((u16)2) -#define HFA384x_RATEBIT_5dot5 ((u16)4) -#define HFA384x_RATEBIT_11 ((u16)8) - -/*--- MAC Internal memory constants and macros ------*/ -/* masks and macros used to manipulate MAC internal memory addresses. */ -/* MAC internal memory addresses are 23 bit quantities. The MAC uses - * a paged address space where the upper 16 bits are the page number - * and the lower 7 bits are the offset. There are various Host API - * elements that require two 16-bit quantities to specify a MAC - * internal memory address. Unfortunately, some of the API's use a - * page/offset format where the offset value is JUST the lower seven - * bits and the page is the remaining 16 bits. Some of the API's - * assume that the 23 bit address has been split at the 16th bit. We - * refer to these two formats as AUX format and CMD format. The - * macros below help handle some of this. - */ - -/* Mask bits for discarding unwanted pieces in a flat address */ -#define HFA384x_ADDR_FLAT_AUX_PAGE_MASK (0x007fff80) -#define HFA384x_ADDR_FLAT_AUX_OFF_MASK (0x0000007f) -#define HFA384x_ADDR_FLAT_CMD_PAGE_MASK (0xffff0000) -#define HFA384x_ADDR_FLAT_CMD_OFF_MASK (0x0000ffff) - -/* Mask bits for discarding unwanted pieces in AUX format - * 16-bit address parts - */ -#define HFA384x_ADDR_AUX_PAGE_MASK (0xffff) -#define HFA384x_ADDR_AUX_OFF_MASK (0x007f) - -/* Make a 32-bit flat address from AUX format 16-bit page and offset */ -#define HFA384x_ADDR_AUX_MKFLAT(p, o) \ - ((((u32)(((u16)(p)) & HFA384x_ADDR_AUX_PAGE_MASK)) << 7) | \ - ((u32)(((u16)(o)) & HFA384x_ADDR_AUX_OFF_MASK))) - -/* Make CMD format offset and page from a 32-bit flat address */ -#define HFA384x_ADDR_CMD_MKPAGE(f) \ - ((u16)((((u32)(f)) & HFA384x_ADDR_FLAT_CMD_PAGE_MASK) >> 16)) -#define HFA384x_ADDR_CMD_MKOFF(f) \ - ((u16)(((u32)(f)) & HFA384x_ADDR_FLAT_CMD_OFF_MASK)) - -/*--- Controller Memory addresses -------------------*/ -#define HFA3842_PDA_BASE (0x007f0000UL) -#define HFA3841_PDA_BASE (0x003f0000UL) -#define HFA3841_PDA_BOGUS_BASE (0x00390000UL) - -/*--- Driver Download states -----------------------*/ -#define HFA384x_DLSTATE_DISABLED 0 -#define HFA384x_DLSTATE_RAMENABLED 1 -#define HFA384x_DLSTATE_FLASHENABLED 2 - -/*--- Register Field Masks --------------------------*/ -#define HFA384x_CMD_AINFO ((u16)GENMASK(14, 8)) -#define HFA384x_CMD_MACPORT ((u16)GENMASK(10, 8)) -#define HFA384x_CMD_PROGMODE ((u16)GENMASK(9, 8)) -#define HFA384x_CMD_CMDCODE ((u16)GENMASK(5, 0)) -#define HFA384x_STATUS_RESULT ((u16)GENMASK(14, 8)) - -/*--- Command Code Constants --------------------------*/ -/*--- Controller Commands --------------------------*/ -#define HFA384x_CMDCODE_INIT ((u16)0x00) -#define HFA384x_CMDCODE_ENABLE ((u16)0x01) -#define HFA384x_CMDCODE_DISABLE ((u16)0x02) - -/*--- Regulate Commands --------------------------*/ -#define HFA384x_CMDCODE_INQ ((u16)0x11) - -/*--- Configure Commands --------------------------*/ -#define HFA384x_CMDCODE_DOWNLD ((u16)0x22) - -/*--- Debugging Commands -----------------------------*/ -#define HFA384x_CMDCODE_MONITOR ((u16)(0x38)) -#define HFA384x_MONITOR_ENABLE ((u16)(0x0b)) -#define HFA384x_MONITOR_DISABLE ((u16)(0x0f)) - -/*--- Result Codes --------------------------*/ -#define HFA384x_CMD_ERR ((u16)(0x7F)) - -/*--- Programming Modes -------------------------- - * MODE 0: Disable programming - * MODE 1: Enable volatile memory programming - * MODE 2: Enable non-volatile memory programming - * MODE 3: Program non-volatile memory section - *------------------------------------------------- - */ -#define HFA384x_PROGMODE_DISABLE ((u16)0x00) -#define HFA384x_PROGMODE_RAM ((u16)0x01) -#define HFA384x_PROGMODE_NV ((u16)0x02) -#define HFA384x_PROGMODE_NVWRITE ((u16)0x03) - -/*--- Record ID Constants --------------------------*/ -/*-------------------------------------------------------------------- - * Configuration RIDs: Network Parameters, Static Configuration Entities - *-------------------------------------------------------------------- - */ -#define HFA384x_RID_CNFPORTTYPE ((u16)0xFC00) -#define HFA384x_RID_CNFOWNMACADDR ((u16)0xFC01) -#define HFA384x_RID_CNFDESIREDSSID ((u16)0xFC02) -#define HFA384x_RID_CNFOWNCHANNEL ((u16)0xFC03) -#define HFA384x_RID_CNFOWNSSID ((u16)0xFC04) -#define HFA384x_RID_CNFMAXDATALEN ((u16)0xFC07) - -/*-------------------------------------------------------------------- - * Configuration RID lengths: Network Params, Static Config Entities - * This is the length of JUST the DATA part of the RID (does not - * include the len or code fields) - *-------------------------------------------------------------------- - */ -#define HFA384x_RID_CNFOWNMACADDR_LEN ((u16)6) -#define HFA384x_RID_CNFDESIREDSSID_LEN ((u16)34) -#define HFA384x_RID_CNFOWNSSID_LEN ((u16)34) - -/*-------------------------------------------------------------------- - * Configuration RIDs: Network Parameters, Dynamic Configuration Entities - *-------------------------------------------------------------------- - */ -#define HFA384x_RID_CREATEIBSS ((u16)0xFC81) -#define HFA384x_RID_FRAGTHRESH ((u16)0xFC82) -#define HFA384x_RID_RTSTHRESH ((u16)0xFC83) -#define HFA384x_RID_TXRATECNTL ((u16)0xFC84) -#define HFA384x_RID_PROMISCMODE ((u16)0xFC85) - -/*---------------------------------------------------------------------- - * Information RIDs: NIC Information - *---------------------------------------------------------------------- - */ -#define HFA384x_RID_MAXLOADTIME ((u16)0xFD00) -#define HFA384x_RID_DOWNLOADBUFFER ((u16)0xFD01) -#define HFA384x_RID_PRIIDENTITY ((u16)0xFD02) -#define HFA384x_RID_PRISUPRANGE ((u16)0xFD03) -#define HFA384x_RID_PRI_CFIACTRANGES ((u16)0xFD04) -#define HFA384x_RID_NICSERIALNUMBER ((u16)0xFD0A) -#define HFA384x_RID_NICIDENTITY ((u16)0xFD0B) -#define HFA384x_RID_MFISUPRANGE ((u16)0xFD0C) -#define HFA384x_RID_CFISUPRANGE ((u16)0xFD0D) -#define HFA384x_RID_STAIDENTITY ((u16)0xFD20) -#define HFA384x_RID_STASUPRANGE ((u16)0xFD21) -#define HFA384x_RID_STA_MFIACTRANGES ((u16)0xFD22) -#define HFA384x_RID_STA_CFIACTRANGES ((u16)0xFD23) - -/*---------------------------------------------------------------------- - * Information RID Lengths: NIC Information - * This is the length of JUST the DATA part of the RID (does not - * include the len or code fields) - *--------------------------------------------------------------------- - */ -#define HFA384x_RID_NICSERIALNUMBER_LEN ((u16)12) - -/*-------------------------------------------------------------------- - * Information RIDs: MAC Information - *-------------------------------------------------------------------- - */ -#define HFA384x_RID_PORTSTATUS ((u16)0xFD40) -#define HFA384x_RID_CURRENTSSID ((u16)0xFD41) -#define HFA384x_RID_CURRENTBSSID ((u16)0xFD42) -#define HFA384x_RID_CURRENTTXRATE ((u16)0xFD44) -#define HFA384x_RID_SHORTRETRYLIMIT ((u16)0xFD48) -#define HFA384x_RID_LONGRETRYLIMIT ((u16)0xFD49) -#define HFA384x_RID_MAXTXLIFETIME ((u16)0xFD4A) -#define HFA384x_RID_PRIVACYOPTIMP ((u16)0xFD4F) -#define HFA384x_RID_DBMCOMMSQUALITY ((u16)0xFD51) - -/*-------------------------------------------------------------------- - * Information RID Lengths: MAC Information - * This is the length of JUST the DATA part of the RID (does not - * include the len or code fields) - *-------------------------------------------------------------------- - */ -#define HFA384x_RID_DBMCOMMSQUALITY_LEN \ - ((u16)sizeof(struct hfa384x_dbmcommsquality)) -#define HFA384x_RID_JOINREQUEST_LEN \ - ((u16)sizeof(struct hfa384x_join_request_data)) - -/*-------------------------------------------------------------------- - * Information RIDs: Modem Information - *-------------------------------------------------------------------- - */ -#define HFA384x_RID_CURRENTCHANNEL ((u16)0xFDC1) - -/*-------------------------------------------------------------------- - * API ENHANCEMENTS (NOT ALREADY IMPLEMENTED) - *-------------------------------------------------------------------- - */ -#define HFA384x_RID_CNFWEPDEFAULTKEYID ((u16)0xFC23) -#define HFA384x_RID_CNFWEPDEFAULTKEY0 ((u16)0xFC24) -#define HFA384x_RID_CNFWEPDEFAULTKEY1 ((u16)0xFC25) -#define HFA384x_RID_CNFWEPDEFAULTKEY2 ((u16)0xFC26) -#define HFA384x_RID_CNFWEPDEFAULTKEY3 ((u16)0xFC27) -#define HFA384x_RID_CNFWEPFLAGS ((u16)0xFC28) -#define HFA384x_RID_CNFAUTHENTICATION ((u16)0xFC2A) -#define HFA384x_RID_CNFROAMINGMODE ((u16)0xFC2D) -#define HFA384x_RID_CNFAPBCNINT ((u16)0xFC33) -#define HFA384x_RID_CNFDBMADJUST ((u16)0xFC46) -#define HFA384x_RID_CNFWPADATA ((u16)0xFC48) -#define HFA384x_RID_CNFBASICRATES ((u16)0xFCB3) -#define HFA384x_RID_CNFSUPPRATES ((u16)0xFCB4) -#define HFA384x_RID_CNFPASSIVESCANCTRL ((u16)0xFCBA) -#define HFA384x_RID_TXPOWERMAX ((u16)0xFCBE) -#define HFA384x_RID_JOINREQUEST ((u16)0xFCE2) -#define HFA384x_RID_AUTHENTICATESTA ((u16)0xFCE3) -#define HFA384x_RID_HOSTSCAN ((u16)0xFCE5) - -#define HFA384x_RID_CNFWEPDEFAULTKEY_LEN ((u16)6) -#define HFA384x_RID_CNFWEP128DEFAULTKEY_LEN ((u16)14) - -/*-------------------------------------------------------------------- - * PD Record codes - *-------------------------------------------------------------------- - */ -#define HFA384x_PDR_PCB_PARTNUM ((u16)0x0001) -#define HFA384x_PDR_PDAVER ((u16)0x0002) -#define HFA384x_PDR_NIC_SERIAL ((u16)0x0003) -#define HFA384x_PDR_MKK_MEASUREMENTS ((u16)0x0004) -#define HFA384x_PDR_NIC_RAMSIZE ((u16)0x0005) -#define HFA384x_PDR_MFISUPRANGE ((u16)0x0006) -#define HFA384x_PDR_CFISUPRANGE ((u16)0x0007) -#define HFA384x_PDR_NICID ((u16)0x0008) -#define HFA384x_PDR_MAC_ADDRESS ((u16)0x0101) -#define HFA384x_PDR_REGDOMAIN ((u16)0x0103) -#define HFA384x_PDR_ALLOWED_CHANNEL ((u16)0x0104) -#define HFA384x_PDR_DEFAULT_CHANNEL ((u16)0x0105) -#define HFA384x_PDR_TEMPTYPE ((u16)0x0107) -#define HFA384x_PDR_IFR_SETTING ((u16)0x0200) -#define HFA384x_PDR_RFR_SETTING ((u16)0x0201) -#define HFA384x_PDR_HFA3861_BASELINE ((u16)0x0202) -#define HFA384x_PDR_HFA3861_SHADOW ((u16)0x0203) -#define HFA384x_PDR_HFA3861_IFRF ((u16)0x0204) -#define HFA384x_PDR_HFA3861_CHCALSP ((u16)0x0300) -#define HFA384x_PDR_HFA3861_CHCALI ((u16)0x0301) -#define HFA384x_PDR_MAX_TX_POWER ((u16)0x0302) -#define HFA384x_PDR_MASTER_CHAN_LIST ((u16)0x0303) -#define HFA384x_PDR_3842_NIC_CONFIG ((u16)0x0400) -#define HFA384x_PDR_USB_ID ((u16)0x0401) -#define HFA384x_PDR_PCI_ID ((u16)0x0402) -#define HFA384x_PDR_PCI_IFCONF ((u16)0x0403) -#define HFA384x_PDR_PCI_PMCONF ((u16)0x0404) -#define HFA384x_PDR_RFENRGY ((u16)0x0406) -#define HFA384x_PDR_USB_POWER_TYPE ((u16)0x0407) -#define HFA384x_PDR_USB_MAX_POWER ((u16)0x0409) -#define HFA384x_PDR_USB_MANUFACTURER ((u16)0x0410) -#define HFA384x_PDR_USB_PRODUCT ((u16)0x0411) -#define HFA384x_PDR_ANT_DIVERSITY ((u16)0x0412) -#define HFA384x_PDR_HFO_DELAY ((u16)0x0413) -#define HFA384x_PDR_SCALE_THRESH ((u16)0x0414) - -#define HFA384x_PDR_HFA3861_MANF_TESTSP ((u16)0x0900) -#define HFA384x_PDR_HFA3861_MANF_TESTI ((u16)0x0901) -#define HFA384x_PDR_END_OF_PDA ((u16)0x0000) - -/*--- Register Test/Get/Set Field macros ------------------------*/ - -#define HFA384x_CMD_AINFO_SET(value) ((u16)((u16)(value) << 8)) -#define HFA384x_CMD_MACPORT_SET(value) \ - ((u16)HFA384x_CMD_AINFO_SET(value)) -#define HFA384x_CMD_PROGMODE_SET(value) \ - ((u16)HFA384x_CMD_AINFO_SET((u16)value)) -#define HFA384x_CMD_CMDCODE_SET(value) ((u16)(value)) - -#define HFA384x_STATUS_RESULT_SET(value) (((u16)(value)) << 8) - -/* Host Maintained State Info */ -#define HFA384x_STATE_PREINIT 0 -#define HFA384x_STATE_INIT 1 -#define HFA384x_STATE_RUNNING 2 - -/*-------------------------------------------------------------*/ -/* Commonly used basic types */ -struct hfa384x_bytestr { - __le16 len; - u8 data[]; -} __packed; - -struct hfa384x_bytestr32 { - __le16 len; - u8 data[32]; -} __packed; - -/*-------------------------------------------------------------------- - * Configuration Record Structures: - * Network Parameters, Static Configuration Entities - *-------------------------------------------------------------------- - */ - -/*-- Hardware/Firmware Component Information ----------*/ -struct hfa384x_compident { - u16 id; - u16 variant; - u16 major; - u16 minor; -} __packed; - -struct hfa384x_caplevel { - u16 role; - u16 id; - u16 variant; - u16 bottom; - u16 top; -} __packed; - -/*-- Configuration Record: cnfAuthentication --*/ -#define HFA384x_CNFAUTHENTICATION_OPENSYSTEM 0x0001 -#define HFA384x_CNFAUTHENTICATION_SHAREDKEY 0x0002 -#define HFA384x_CNFAUTHENTICATION_LEAP 0x0004 - -/*-------------------------------------------------------------------- - * Configuration Record Structures: - * Network Parameters, Dynamic Configuration Entities - *-------------------------------------------------------------------- - */ - -#define HFA384x_CREATEIBSS_JOINCREATEIBSS 0 - -/*-- Configuration Record: HostScanRequest (data portion only) --*/ -struct hfa384x_host_scan_request_data { - __le16 channel_list; - __le16 tx_rate; - struct hfa384x_bytestr32 ssid; -} __packed; - -/*-- Configuration Record: JoinRequest (data portion only) --*/ -struct hfa384x_join_request_data { - u8 bssid[WLAN_BSSID_LEN]; - u16 channel; -} __packed; - -/*-- Configuration Record: authenticateStation (data portion only) --*/ -struct hfa384x_authenticate_station_data { - u8 address[ETH_ALEN]; - __le16 status; - __le16 algorithm; -} __packed; - -/*-- Configuration Record: WPAData (data portion only) --*/ -struct hfa384x_wpa_data { - __le16 datalen; - u8 data[]; /* max 80 */ -} __packed; - -/*-------------------------------------------------------------------- - * Information Record Structures: NIC Information - *-------------------------------------------------------------------- - */ - -/*-- Information Record: DownLoadBuffer --*/ -/* NOTE: The page and offset are in AUX format */ -struct hfa384x_downloadbuffer { - u16 page; - u16 offset; - u16 len; -} __packed; - -/*-------------------------------------------------------------------- - * Information Record Structures: NIC Information - *-------------------------------------------------------------------- - */ - -#define HFA384x_PSTATUS_CONN_IBSS ((u16)3) - -/*-- Information Record: commsquality --*/ -struct hfa384x_commsquality { - __le16 cq_curr_bss; - __le16 asl_curr_bss; - __le16 anl_curr_fc; -} __packed; - -/*-- Information Record: dmbcommsquality --*/ -struct hfa384x_dbmcommsquality { - u16 cq_dbm_curr_bss; - u16 asl_dbm_curr_bss; - u16 anl_dbm_curr_fc; -} __packed; - -/*-------------------------------------------------------------------- - * FRAME STRUCTURES: Communication Frames - *-------------------------------------------------------------------- - * Communication Frames: Transmit Frames - *-------------------------------------------------------------------- - */ -/*-- Communication Frame: Transmit Frame Structure --*/ -struct hfa384x_tx_frame { - u16 status; - u16 reserved1; - u16 reserved2; - u32 sw_support; - u8 tx_retrycount; - u8 tx_rate; - u16 tx_control; - - /*-- 802.11 Header Information --*/ - struct p80211_hdr hdr; - __le16 data_len; /* little endian format */ - - /*-- 802.3 Header Information --*/ - - u8 dest_addr[6]; - u8 src_addr[6]; - u16 data_length; /* big endian format */ -} __packed; -/*-------------------------------------------------------------------- - * Communication Frames: Field Masks for Transmit Frames - *-------------------------------------------------------------------- - */ -/*-- Status Field --*/ -#define HFA384x_TXSTATUS_ACKERR ((u16)BIT(5)) -#define HFA384x_TXSTATUS_FORMERR ((u16)BIT(3)) -#define HFA384x_TXSTATUS_DISCON ((u16)BIT(2)) -#define HFA384x_TXSTATUS_AGEDERR ((u16)BIT(1)) -#define HFA384x_TXSTATUS_RETRYERR ((u16)BIT(0)) -/*-- Transmit Control Field --*/ -#define HFA384x_TX_MACPORT ((u16)GENMASK(10, 8)) -#define HFA384x_TX_STRUCTYPE ((u16)GENMASK(4, 3)) -#define HFA384x_TX_TXEX ((u16)BIT(2)) -#define HFA384x_TX_TXOK ((u16)BIT(1)) -/*-------------------------------------------------------------------- - * Communication Frames: Test/Get/Set Field Values for Transmit Frames - *-------------------------------------------------------------------- - */ -/*-- Status Field --*/ -#define HFA384x_TXSTATUS_ISERROR(v) \ - (((u16)(v)) & \ - (HFA384x_TXSTATUS_ACKERR | HFA384x_TXSTATUS_FORMERR | \ - HFA384x_TXSTATUS_DISCON | HFA384x_TXSTATUS_AGEDERR | \ - HFA384x_TXSTATUS_RETRYERR)) - -#define HFA384x_TX_SET(v, m, s) ((((u16)(v)) << ((u16)(s))) & ((u16)(m))) - -#define HFA384x_TX_MACPORT_SET(v) HFA384x_TX_SET(v, HFA384x_TX_MACPORT, 8) -#define HFA384x_TX_STRUCTYPE_SET(v) HFA384x_TX_SET(v, \ - HFA384x_TX_STRUCTYPE, 3) -#define HFA384x_TX_TXEX_SET(v) HFA384x_TX_SET(v, HFA384x_TX_TXEX, 2) -#define HFA384x_TX_TXOK_SET(v) HFA384x_TX_SET(v, HFA384x_TX_TXOK, 1) -/*-------------------------------------------------------------------- - * Communication Frames: Receive Frames - *-------------------------------------------------------------------- - */ -/*-- Communication Frame: Receive Frame Structure --*/ -struct hfa384x_rx_frame { - /*-- MAC rx descriptor (hfa384x byte order) --*/ - u16 status; - u32 time; - u8 silence; - u8 signal; - u8 rate; - u8 rx_flow; - u16 reserved1; - u16 reserved2; - - /*-- 802.11 Header Information (802.11 byte order) --*/ - struct p80211_hdr hdr; - __le16 data_len; /* hfa384x (little endian) format */ - - /*-- 802.3 Header Information --*/ - u8 dest_addr[6]; - u8 src_addr[6]; - u16 data_length; /* IEEE? (big endian) format */ -} __packed; -/*-------------------------------------------------------------------- - * Communication Frames: Field Masks for Receive Frames - *-------------------------------------------------------------------- - */ - -/*-- Status Fields --*/ -#define HFA384x_RXSTATUS_MACPORT ((u16)GENMASK(10, 8)) -#define HFA384x_RXSTATUS_FCSERR ((u16)BIT(0)) -/*-------------------------------------------------------------------- - * Communication Frames: Test/Get/Set Field Values for Receive Frames - *-------------------------------------------------------------------- - */ -#define HFA384x_RXSTATUS_MACPORT_GET(value) ((u16)((((u16)(value)) \ - & HFA384x_RXSTATUS_MACPORT) >> 8)) -#define HFA384x_RXSTATUS_ISFCSERR(value) ((u16)(((u16)(value)) \ - & HFA384x_RXSTATUS_FCSERR)) -/*-------------------------------------------------------------------- - * FRAME STRUCTURES: Information Types and Information Frame Structures - *-------------------------------------------------------------------- - * Information Types - *-------------------------------------------------------------------- - */ -#define HFA384x_IT_HANDOVERADDR ((u16)0xF000UL) -#define HFA384x_IT_COMMTALLIES ((u16)0xF100UL) -#define HFA384x_IT_SCANRESULTS ((u16)0xF101UL) -#define HFA384x_IT_CHINFORESULTS ((u16)0xF102UL) -#define HFA384x_IT_HOSTSCANRESULTS ((u16)0xF103UL) -#define HFA384x_IT_LINKSTATUS ((u16)0xF200UL) -#define HFA384x_IT_ASSOCSTATUS ((u16)0xF201UL) -#define HFA384x_IT_AUTHREQ ((u16)0xF202UL) -#define HFA384x_IT_PSUSERCNT ((u16)0xF203UL) -#define HFA384x_IT_KEYIDCHANGED ((u16)0xF204UL) -#define HFA384x_IT_ASSOCREQ ((u16)0xF205UL) -#define HFA384x_IT_MICFAILURE ((u16)0xF206UL) - -/*-------------------------------------------------------------------- - * Information Frames Structures - *-------------------------------------------------------------------- - * Information Frames: Notification Frame Structures - *-------------------------------------------------------------------- - */ - -/*-- Inquiry Frame, Diagnose: Communication Tallies --*/ -struct hfa384x_comm_tallies_16 { - __le16 txunicastframes; - __le16 txmulticastframes; - __le16 txfragments; - __le16 txunicastoctets; - __le16 txmulticastoctets; - __le16 txdeferredtrans; - __le16 txsingleretryframes; - __le16 txmultipleretryframes; - __le16 txretrylimitexceeded; - __le16 txdiscards; - __le16 rxunicastframes; - __le16 rxmulticastframes; - __le16 rxfragments; - __le16 rxunicastoctets; - __le16 rxmulticastoctets; - __le16 rxfcserrors; - __le16 rxdiscardsnobuffer; - __le16 txdiscardswrongsa; - __le16 rxdiscardswepundecr; - __le16 rxmsginmsgfrag; - __le16 rxmsginbadmsgfrag; -} __packed; - -struct hfa384x_comm_tallies_32 { - __le32 txunicastframes; - __le32 txmulticastframes; - __le32 txfragments; - __le32 txunicastoctets; - __le32 txmulticastoctets; - __le32 txdeferredtrans; - __le32 txsingleretryframes; - __le32 txmultipleretryframes; - __le32 txretrylimitexceeded; - __le32 txdiscards; - __le32 rxunicastframes; - __le32 rxmulticastframes; - __le32 rxfragments; - __le32 rxunicastoctets; - __le32 rxmulticastoctets; - __le32 rxfcserrors; - __le32 rxdiscardsnobuffer; - __le32 txdiscardswrongsa; - __le32 rxdiscardswepundecr; - __le32 rxmsginmsgfrag; - __le32 rxmsginbadmsgfrag; -} __packed; - -/*-- Inquiry Frame, Diagnose: Scan Results & Subfields--*/ -struct hfa384x_scan_result_sub { - u16 chid; - u16 anl; - u16 sl; - u8 bssid[WLAN_BSSID_LEN]; - u16 bcnint; - u16 capinfo; - struct hfa384x_bytestr32 ssid; - u8 supprates[10]; /* 802.11 info element */ - u16 proberesp_rate; -} __packed; - -struct hfa384x_scan_result { - u16 rsvd; - u16 scanreason; - struct hfa384x_scan_result_sub result[HFA384x_SCANRESULT_MAX]; -} __packed; - -/*-- Inquiry Frame, Diagnose: ChInfo Results & Subfields--*/ -struct hfa384x_ch_info_result_sub { - u16 chid; - u16 anl; - u16 pnl; - u16 active; -} __packed; - -#define HFA384x_CHINFORESULT_BSSACTIVE BIT(0) -#define HFA384x_CHINFORESULT_PCFACTIVE BIT(1) - -struct hfa384x_ch_info_result { - u16 scanchannels; - struct hfa384x_ch_info_result_sub result[HFA384x_CHINFORESULT_MAX]; -} __packed; - -/*-- Inquiry Frame, Diagnose: Host Scan Results & Subfields--*/ -struct hfa384x_hscan_result_sub { - __le16 chid; - __le16 anl; - __le16 sl; - u8 bssid[WLAN_BSSID_LEN]; - __le16 bcnint; - __le16 capinfo; - struct hfa384x_bytestr32 ssid; - u8 supprates[10]; /* 802.11 info element */ - u16 proberesp_rate; - __le16 atim; -} __packed; - -struct hfa384x_hscan_result { - u16 nresult; - u16 rsvd; - struct hfa384x_hscan_result_sub result[HFA384x_HSCANRESULT_MAX]; -} __packed; - -/*-- Unsolicited Frame, MAC Mgmt: LinkStatus --*/ - -#define HFA384x_LINK_NOTCONNECTED ((u16)0) -#define HFA384x_LINK_CONNECTED ((u16)1) -#define HFA384x_LINK_DISCONNECTED ((u16)2) -#define HFA384x_LINK_AP_CHANGE ((u16)3) -#define HFA384x_LINK_AP_OUTOFRANGE ((u16)4) -#define HFA384x_LINK_AP_INRANGE ((u16)5) -#define HFA384x_LINK_ASSOCFAIL ((u16)6) - -struct hfa384x_link_status { - __le16 linkstatus; -} __packed; - -/*-- Unsolicited Frame, MAC Mgmt: AssociationStatus (--*/ - -#define HFA384x_ASSOCSTATUS_STAASSOC ((u16)1) -#define HFA384x_ASSOCSTATUS_REASSOC ((u16)2) -#define HFA384x_ASSOCSTATUS_AUTHFAIL ((u16)5) - -struct hfa384x_assoc_status { - u16 assocstatus; - u8 sta_addr[ETH_ALEN]; - /* old_ap_addr is only valid if assocstatus == 2 */ - u8 old_ap_addr[ETH_ALEN]; - u16 reason; - u16 reserved; -} __packed; - -/*-- Unsolicited Frame, MAC Mgmt: AuthRequest (AP Only) --*/ - -struct hfa384x_auth_request { - u8 sta_addr[ETH_ALEN]; - __le16 algorithm; -} __packed; - -/*-- Unsolicited Frame, MAC Mgmt: PSUserCount (AP Only) --*/ - -struct hfa384x_ps_user_count { - __le16 usercnt; -} __packed; - -struct hfa384x_key_id_changed { - u8 sta_addr[ETH_ALEN]; - u16 keyid; -} __packed; - -/*-- Collection of all Inf frames ---------------*/ -union hfa384x_infodata { - struct hfa384x_comm_tallies_16 commtallies16; - struct hfa384x_comm_tallies_32 commtallies32; - struct hfa384x_scan_result scanresult; - struct hfa384x_ch_info_result chinforesult; - struct hfa384x_hscan_result hscanresult; - struct hfa384x_link_status linkstatus; - struct hfa384x_assoc_status assocstatus; - struct hfa384x_auth_request authreq; - struct hfa384x_ps_user_count psusercnt; - struct hfa384x_key_id_changed keyidchanged; -} __packed; - -struct hfa384x_inf_frame { - u16 framelen; - u16 infotype; - union hfa384x_infodata info; -} __packed; - -/*-------------------------------------------------------------------- - * USB Packet structures and constants. - *-------------------------------------------------------------------- - */ - -/* Should be sent to the bulkout endpoint */ -#define HFA384x_USB_TXFRM 0 -#define HFA384x_USB_CMDREQ 1 -#define HFA384x_USB_WRIDREQ 2 -#define HFA384x_USB_RRIDREQ 3 -#define HFA384x_USB_WMEMREQ 4 -#define HFA384x_USB_RMEMREQ 5 - -/* Received from the bulkin endpoint */ -#define HFA384x_USB_ISTXFRM(a) (((a) & 0x9000) == 0x1000) -#define HFA384x_USB_ISRXFRM(a) (!((a) & 0x9000)) -#define HFA384x_USB_INFOFRM 0x8000 -#define HFA384x_USB_CMDRESP 0x8001 -#define HFA384x_USB_WRIDRESP 0x8002 -#define HFA384x_USB_RRIDRESP 0x8003 -#define HFA384x_USB_WMEMRESP 0x8004 -#define HFA384x_USB_RMEMRESP 0x8005 -#define HFA384x_USB_BUFAVAIL 0x8006 -#define HFA384x_USB_ERROR 0x8007 - -/*------------------------------------*/ -/* Request (bulk OUT) packet contents */ - -struct hfa384x_usb_txfrm { - struct hfa384x_tx_frame desc; - u8 data[WLAN_DATA_MAXLEN]; -} __packed; - -struct hfa384x_usb_cmdreq { - __le16 type; - __le16 cmd; - __le16 parm0; - __le16 parm1; - __le16 parm2; - u8 pad[54]; -} __packed; - -struct hfa384x_usb_wridreq { - __le16 type; - __le16 frmlen; - __le16 rid; - u8 data[HFA384x_RIDDATA_MAXLEN]; -} __packed; - -struct hfa384x_usb_rridreq { - __le16 type; - __le16 frmlen; - __le16 rid; - u8 pad[58]; -} __packed; - -struct hfa384x_usb_wmemreq { - __le16 type; - __le16 frmlen; - __le16 offset; - __le16 page; - u8 data[HFA384x_USB_RWMEM_MAXLEN]; -} __packed; - -struct hfa384x_usb_rmemreq { - __le16 type; - __le16 frmlen; - __le16 offset; - __le16 page; - u8 pad[56]; -} __packed; - -/*------------------------------------*/ -/* Response (bulk IN) packet contents */ - -struct hfa384x_usb_rxfrm { - struct hfa384x_rx_frame desc; - u8 data[WLAN_DATA_MAXLEN]; -} __packed; - -struct hfa384x_usb_infofrm { - u16 type; - struct hfa384x_inf_frame info; -} __packed; - -struct hfa384x_usb_statusresp { - u16 type; - __le16 status; - __le16 resp0; - __le16 resp1; - __le16 resp2; -} __packed; - -struct hfa384x_usb_rridresp { - u16 type; - __le16 frmlen; - __le16 rid; - u8 data[HFA384x_RIDDATA_MAXLEN]; -} __packed; - -struct hfa384x_usb_rmemresp { - u16 type; - u16 frmlen; - u8 data[HFA384x_USB_RWMEM_MAXLEN]; -} __packed; - -struct hfa384x_usb_bufavail { - u16 type; - u16 frmlen; -} __packed; - -struct hfa384x_usb_error { - u16 type; - u16 errortype; -} __packed; - -/*----------------------------------------------------------*/ -/* Unions for packaging all the known packet types together */ - -union hfa384x_usbout { - __le16 type; - struct hfa384x_usb_txfrm txfrm; - struct hfa384x_usb_cmdreq cmdreq; - struct hfa384x_usb_wridreq wridreq; - struct hfa384x_usb_rridreq rridreq; - struct hfa384x_usb_wmemreq wmemreq; - struct hfa384x_usb_rmemreq rmemreq; -} __packed; - -union hfa384x_usbin { - __le16 type; - struct hfa384x_usb_rxfrm rxfrm; - struct hfa384x_usb_txfrm txfrm; - struct hfa384x_usb_infofrm infofrm; - struct hfa384x_usb_statusresp cmdresp; - struct hfa384x_usb_statusresp wridresp; - struct hfa384x_usb_rridresp rridresp; - struct hfa384x_usb_statusresp wmemresp; - struct hfa384x_usb_rmemresp rmemresp; - struct hfa384x_usb_bufavail bufavail; - struct hfa384x_usb_error usberror; - u8 boguspad[3000]; -} __packed; - -/*-------------------------------------------------------------------- - * PD record structures. - *-------------------------------------------------------------------- - */ - -struct hfa384x_pdr_mfisuprange { - u16 id; - u16 variant; - u16 bottom; - u16 top; -} __packed; - -struct hfa384x_pdr_cfisuprange { - u16 id; - u16 variant; - u16 bottom; - u16 top; -} __packed; - -struct hfa384x_pdr_nicid { - u16 id; - u16 variant; - u16 major; - u16 minor; -} __packed; - -struct hfa384x_pdrec { - __le16 len; /* in words */ - __le16 code; - union pdr { - struct hfa384x_pdr_mfisuprange mfisuprange; - struct hfa384x_pdr_cfisuprange cfisuprange; - struct hfa384x_pdr_nicid nicid; - - } data; -} __packed; - -#ifdef __KERNEL__ -/*-------------------------------------------------------------------- - * --- MAC state structure, argument to all functions -- - * --- Also, a collection of support types -- - *-------------------------------------------------------------------- - */ -struct hfa384x_cmdresult { - u16 status; - u16 resp0; - u16 resp1; - u16 resp2; -}; - -/* USB Control Exchange (CTLX): - * A queue of the structure below is maintained for all of the - * Request/Response type USB packets supported by Prism2. - */ -/* The following hfa384x_* structures are arguments to - * the usercb() for the different CTLX types. - */ -struct hfa384x_rridresult { - u16 rid; - const void *riddata; - unsigned int riddata_len; -}; - -enum ctlx_state { - CTLX_START = 0, /* Start state, not queued */ - - CTLX_COMPLETE, /* CTLX successfully completed */ - CTLX_REQ_FAILED, /* OUT URB completed w/ error */ - - CTLX_PENDING, /* Queued, data valid */ - CTLX_REQ_SUBMITTED, /* OUT URB submitted */ - CTLX_REQ_COMPLETE, /* OUT URB complete */ - CTLX_RESP_COMPLETE /* IN URB received */ -}; - -struct hfa384x_usbctlx; -struct hfa384x; - -typedef void (*ctlx_cmdcb_t) (struct hfa384x *, const struct hfa384x_usbctlx *); - -typedef void (*ctlx_usercb_t) (struct hfa384x *hw, - void *ctlxresult, void *usercb_data); - -struct hfa384x_usbctlx { - struct list_head list; - - size_t outbufsize; - union hfa384x_usbout outbuf; /* pkt buf for OUT */ - union hfa384x_usbin inbuf; /* pkt buf for IN(a copy) */ - - enum ctlx_state state; /* Tracks running state */ - - struct completion done; - int reapable; /* Food for the reaper task */ - - ctlx_cmdcb_t cmdcb; /* Async command callback */ - ctlx_usercb_t usercb; /* Async user callback, */ - void *usercb_data; /* at CTLX completion */ -}; - -struct hfa384x_usbctlxq { - spinlock_t lock; - struct list_head pending; - struct list_head active; - struct list_head completing; - struct list_head reapable; -}; - -struct hfa384x_metacmd { - u16 cmd; - - u16 parm0; - u16 parm1; - u16 parm2; - - struct hfa384x_cmdresult result; -}; - -#define MAX_GRP_ADDR 32 -#define WLAN_COMMENT_MAX 80 /* Max. length of user comment string. */ - -#define WLAN_AUTH_MAX 60 /* Max. # of authenticated stations. */ -#define WLAN_ACCESS_MAX 60 /* Max. # of stations in an access list. */ -#define WLAN_ACCESS_NONE 0 /* No stations may be authenticated. */ -#define WLAN_ACCESS_ALL 1 /* All stations may be authenticated. */ -#define WLAN_ACCESS_ALLOW 2 /* Authenticate only "allowed" stations. */ -#define WLAN_ACCESS_DENY 3 /* Do not authenticate "denied" stations. */ - -/* XXX These are going away ASAP */ -struct prism2sta_authlist { - unsigned int cnt; - u8 addr[WLAN_AUTH_MAX][ETH_ALEN]; - u8 assoc[WLAN_AUTH_MAX]; -}; - -struct prism2sta_accesslist { - unsigned int modify; - unsigned int cnt; - u8 addr[WLAN_ACCESS_MAX][ETH_ALEN]; - unsigned int cnt1; - u8 addr1[WLAN_ACCESS_MAX][ETH_ALEN]; -}; - -struct hfa384x { - /* USB support data */ - struct usb_device *usb; - struct urb rx_urb; - struct sk_buff *rx_urb_skb; - struct urb tx_urb; - struct urb ctlx_urb; - union hfa384x_usbout txbuff; - struct hfa384x_usbctlxq ctlxq; - struct timer_list reqtimer; - struct timer_list resptimer; - - struct timer_list throttle; - - struct work_struct reaper_bh; - struct work_struct completion_bh; - - struct work_struct usb_work; - - unsigned long usb_flags; -#define THROTTLE_RX 0 -#define THROTTLE_TX 1 -#define WORK_RX_HALT 2 -#define WORK_TX_HALT 3 -#define WORK_RX_RESUME 4 -#define WORK_TX_RESUME 5 - - unsigned short req_timer_done:1; - unsigned short resp_timer_done:1; - - int endp_in; - int endp_out; - - int sniff_fcs; - int sniff_channel; - int sniff_truncate; - int sniffhdr; - - wait_queue_head_t cmdq; /* wait queue itself */ - - /* Controller state */ - u32 state; - u32 isap; - u8 port_enabled[HFA384x_NUMPORTS_MAX]; - - /* Download support */ - unsigned int dlstate; - struct hfa384x_downloadbuffer bufinfo; - u16 dltimeout; - - int scanflag; /* to signal scan complete */ - int join_ap; /* are we joined to a specific ap */ - int join_retries; /* number of join retries till we fail */ - struct hfa384x_join_request_data joinreq;/* join request saved data */ - - struct wlandevice *wlandev; - /* Timer to allow for the deferred processing of linkstatus messages */ - struct work_struct link_bh; - - struct work_struct commsqual_bh; - struct hfa384x_commsquality qual; - struct timer_list commsqual_timer; - - u16 link_status; - u16 link_status_new; - struct sk_buff_head authq; - - u32 txrate; - - /* And here we have stuff that used to be in priv */ - - /* State variables */ - unsigned int presniff_port_type; - u16 presniff_wepflags; - u32 dot11_desired_bss_type; - - int dbmadjust; - - /* Group Addresses - right now, there are up to a total - * of MAX_GRP_ADDR group addresses - */ - u8 dot11_grp_addr[MAX_GRP_ADDR][ETH_ALEN]; - unsigned int dot11_grpcnt; - - /* Component Identities */ - struct hfa384x_compident ident_nic; - struct hfa384x_compident ident_pri_fw; - struct hfa384x_compident ident_sta_fw; - struct hfa384x_compident ident_ap_fw; - u16 mm_mods; - - /* Supplier compatibility ranges */ - struct hfa384x_caplevel cap_sup_mfi; - struct hfa384x_caplevel cap_sup_cfi; - struct hfa384x_caplevel cap_sup_pri; - struct hfa384x_caplevel cap_sup_sta; - struct hfa384x_caplevel cap_sup_ap; - - /* Actor compatibility ranges */ - struct hfa384x_caplevel cap_act_pri_cfi; /* - * pri f/w to controller - * interface - */ - - struct hfa384x_caplevel cap_act_sta_cfi; /* - * sta f/w to controller - * interface - */ - - struct hfa384x_caplevel cap_act_sta_mfi; /* - * sta f/w to modem interface - */ - - struct hfa384x_caplevel cap_act_ap_cfi; /* - * ap f/w to controller - * interface - */ - - struct hfa384x_caplevel cap_act_ap_mfi; /* ap f/w to modem interface */ - - u32 psusercount; /* Power save user count. */ - struct hfa384x_comm_tallies_32 tallies; /* Communication tallies. */ - u8 comment[WLAN_COMMENT_MAX + 1]; /* User comment */ - - /* Channel Info request results (AP only) */ - struct { - atomic_t done; - u8 count; - struct hfa384x_ch_info_result results; - } channel_info; - - struct hfa384x_inf_frame *scanresults; - - struct prism2sta_authlist authlist; /* - * Authenticated station list. - */ - unsigned int accessmode; /* Access mode. */ - struct prism2sta_accesslist allow; /* Allowed station list. */ - struct prism2sta_accesslist deny; /* Denied station list. */ - -}; - -void hfa384x_create(struct hfa384x *hw, struct usb_device *usb); -void hfa384x_destroy(struct hfa384x *hw); - -int hfa384x_corereset(struct hfa384x *hw, int holdtime, int settletime, - int genesis); -int hfa384x_drvr_disable(struct hfa384x *hw, u16 macport); -int hfa384x_drvr_enable(struct hfa384x *hw, u16 macport); -int hfa384x_drvr_flashdl_enable(struct hfa384x *hw); -int hfa384x_drvr_flashdl_disable(struct hfa384x *hw); -int hfa384x_drvr_flashdl_write(struct hfa384x *hw, u32 daddr, void *buf, - u32 len); -int hfa384x_drvr_getconfig(struct hfa384x *hw, u16 rid, void *buf, u16 len); -int hfa384x_drvr_ramdl_enable(struct hfa384x *hw, u32 exeaddr); -int hfa384x_drvr_ramdl_disable(struct hfa384x *hw); -int hfa384x_drvr_ramdl_write(struct hfa384x *hw, u32 daddr, void *buf, u32 len); -int hfa384x_drvr_readpda(struct hfa384x *hw, void *buf, unsigned int len); -int hfa384x_drvr_setconfig(struct hfa384x *hw, u16 rid, void *buf, u16 len); - -static inline int -hfa384x_drvr_getconfig16(struct hfa384x *hw, u16 rid, void *val) -{ - int result = 0; - - result = hfa384x_drvr_getconfig(hw, rid, val, sizeof(u16)); - if (result == 0) - le16_to_cpus(val); - return result; -} - -static inline int hfa384x_drvr_setconfig16(struct hfa384x *hw, u16 rid, u16 val) -{ - __le16 value = cpu_to_le16(val); - - return hfa384x_drvr_setconfig(hw, rid, &value, sizeof(value)); -} - -int -hfa384x_drvr_setconfig_async(struct hfa384x *hw, - u16 rid, - void *buf, - u16 len, ctlx_usercb_t usercb, void *usercb_data); - -static inline int -hfa384x_drvr_setconfig16_async(struct hfa384x *hw, u16 rid, u16 val) -{ - __le16 value = cpu_to_le16(val); - - return hfa384x_drvr_setconfig_async(hw, rid, &value, sizeof(value), - NULL, NULL); -} - -int hfa384x_drvr_start(struct hfa384x *hw); -int hfa384x_drvr_stop(struct hfa384x *hw); -int -hfa384x_drvr_txframe(struct hfa384x *hw, struct sk_buff *skb, - struct p80211_hdr *p80211_hdr, - struct p80211_metawep *p80211_wep); -void hfa384x_tx_timeout(struct wlandevice *wlandev); - -int hfa384x_cmd_initialize(struct hfa384x *hw); -int hfa384x_cmd_enable(struct hfa384x *hw, u16 macport); -int hfa384x_cmd_disable(struct hfa384x *hw, u16 macport); -int hfa384x_cmd_allocate(struct hfa384x *hw, u16 len); -int hfa384x_cmd_monitor(struct hfa384x *hw, u16 enable); -int -hfa384x_cmd_download(struct hfa384x *hw, - u16 mode, u16 lowaddr, u16 highaddr, u16 codelen); - -#endif /*__KERNEL__ */ - -#endif /*_HFA384x_H */ diff --git a/drivers/staging/wlan-ng/hfa384x_usb.c b/drivers/staging/wlan-ng/hfa384x_usb.c deleted file mode 100644 index 35650f911ebc..000000000000 --- a/drivers/staging/wlan-ng/hfa384x_usb.c +++ /dev/null @@ -1,3880 +0,0 @@ -// SPDX-License-Identifier: (GPL-2.0 OR MPL-1.1) -/* - * - * Functions that talk to the USB variant of the Intersil hfa384x MAC - * - * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. - * -------------------------------------------------------------------- - * - * linux-wlan - * - * -------------------------------------------------------------------- - * - * Inquiries regarding the linux-wlan Open Source project can be - * made directly to: - * - * AbsoluteValue Systems Inc. - * info@linux-wlan.com - * http://www.linux-wlan.com - * - * -------------------------------------------------------------------- - * - * Portions of the development of this software were funded by - * Intersil Corporation as part of PRISM(R) chipset product development. - * - * -------------------------------------------------------------------- - * - * This file implements functions that correspond to the prism2/hfa384x - * 802.11 MAC hardware and firmware host interface. - * - * The functions can be considered to represent several levels of - * abstraction. The lowest level functions are simply C-callable wrappers - * around the register accesses. The next higher level represents C-callable - * prism2 API functions that match the Intersil documentation as closely - * as is reasonable. The next higher layer implements common sequences - * of invocations of the API layer (e.g. write to bap, followed by cmd). - * - * Common sequences: - * hfa384x_drvr_xxx Highest level abstractions provided by the - * hfa384x code. They are driver defined wrappers - * for common sequences. These functions generally - * use the services of the lower levels. - * - * hfa384x_drvr_xxxconfig An example of the drvr level abstraction. These - * functions are wrappers for the RID get/set - * sequence. They call copy_[to|from]_bap() and - * cmd_access(). These functions operate on the - * RIDs and buffers without validation. The caller - * is responsible for that. - * - * API wrapper functions: - * hfa384x_cmd_xxx functions that provide access to the f/w commands. - * The function arguments correspond to each command - * argument, even command arguments that get packed - * into single registers. These functions _just_ - * issue the command by setting the cmd/parm regs - * & reading the status/resp regs. Additional - * activities required to fully use a command - * (read/write from/to bap, get/set int status etc.) - * are implemented separately. Think of these as - * C-callable prism2 commands. - * - * Lowest Layer Functions: - * hfa384x_docmd_xxx These functions implement the sequence required - * to issue any prism2 command. Primarily used by the - * hfa384x_cmd_xxx functions. - * - * hfa384x_bap_xxx BAP read/write access functions. - * Note: we usually use BAP0 for non-interrupt context - * and BAP1 for interrupt context. - * - * hfa384x_dl_xxx download related functions. - * - * Driver State Issues: - * Note that there are two pairs of functions that manage the - * 'initialized' and 'running' states of the hw/MAC combo. The four - * functions are create(), destroy(), start(), and stop(). create() - * sets up the data structures required to support the hfa384x_* - * functions and destroy() cleans them up. The start() function gets - * the actual hardware running and enables the interrupts. The stop() - * function shuts the hardware down. The sequence should be: - * create() - * start() - * . - * . Do interesting things w/ the hardware - * . - * stop() - * destroy() - * - * Note that destroy() can be called without calling stop() first. - * -------------------------------------------------------------------- - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "p80211types.h" -#include "p80211hdr.h" -#include "p80211mgmt.h" -#include "p80211conv.h" -#include "p80211msg.h" -#include "p80211netdev.h" -#include "p80211req.h" -#include "p80211metadef.h" -#include "p80211metastruct.h" -#include "hfa384x.h" -#include "prism2mgmt.h" - -enum cmd_mode { - DOWAIT = 0, - DOASYNC -}; - -#define THROTTLE_JIFFIES (HZ / 8) -#define URB_ASYNC_UNLINK 0 -#define USB_QUEUE_BULK 0 - -#define ROUNDUP64(a) (((a) + 63) & ~63) - -#ifdef DEBUG_USB -static void dbprint_urb(struct urb *urb); -#endif - -static void hfa384x_int_rxmonitor(struct wlandevice *wlandev, - struct hfa384x_usb_rxfrm *rxfrm); - -static void hfa384x_usb_defer(struct work_struct *data); - -static int submit_rx_urb(struct hfa384x *hw, gfp_t flags); - -static int submit_tx_urb(struct hfa384x *hw, struct urb *tx_urb, gfp_t flags); - -/*---------------------------------------------------*/ -/* Callbacks */ -static void hfa384x_usbout_callback(struct urb *urb); -static void hfa384x_ctlxout_callback(struct urb *urb); -static void hfa384x_usbin_callback(struct urb *urb); - -static void -hfa384x_usbin_txcompl(struct wlandevice *wlandev, union hfa384x_usbin *usbin); - -static void hfa384x_usbin_rx(struct wlandevice *wlandev, struct sk_buff *skb); - -static void hfa384x_usbin_info(struct wlandevice *wlandev, - union hfa384x_usbin *usbin); - -static void hfa384x_usbin_ctlx(struct hfa384x *hw, union hfa384x_usbin *usbin, - int urb_status); - -/*---------------------------------------------------*/ -/* Functions to support the prism2 usb command queue */ - -static void hfa384x_usbctlxq_run(struct hfa384x *hw); - -static void hfa384x_usbctlx_reqtimerfn(struct timer_list *t); - -static void hfa384x_usbctlx_resptimerfn(struct timer_list *t); - -static void hfa384x_usb_throttlefn(struct timer_list *t); - -static void hfa384x_usbctlx_completion_task(struct work_struct *work); - -static void hfa384x_usbctlx_reaper_task(struct work_struct *work); - -static int hfa384x_usbctlx_submit(struct hfa384x *hw, - struct hfa384x_usbctlx *ctlx); - -static void unlocked_usbctlx_complete(struct hfa384x *hw, - struct hfa384x_usbctlx *ctlx); - -struct usbctlx_completor { - int (*complete)(struct usbctlx_completor *completor); -}; - -static int -hfa384x_usbctlx_complete_sync(struct hfa384x *hw, - struct hfa384x_usbctlx *ctlx, - struct usbctlx_completor *completor); - -static int -unlocked_usbctlx_cancel_async(struct hfa384x *hw, struct hfa384x_usbctlx *ctlx); - -static void hfa384x_cb_status(struct hfa384x *hw, - const struct hfa384x_usbctlx *ctlx); - -static int -usbctlx_get_status(const struct hfa384x_usb_statusresp *cmdresp, - struct hfa384x_cmdresult *result); - -static void -usbctlx_get_rridresult(const struct hfa384x_usb_rridresp *rridresp, - struct hfa384x_rridresult *result); - -/*---------------------------------------------------*/ -/* Low level req/resp CTLX formatters and submitters */ -static inline int -hfa384x_docmd(struct hfa384x *hw, - struct hfa384x_metacmd *cmd); - -static int -hfa384x_dorrid(struct hfa384x *hw, - enum cmd_mode mode, - u16 rid, - void *riddata, - unsigned int riddatalen, - ctlx_cmdcb_t cmdcb, ctlx_usercb_t usercb, void *usercb_data); - -static int -hfa384x_dowrid(struct hfa384x *hw, - enum cmd_mode mode, - u16 rid, - void *riddata, - unsigned int riddatalen, - ctlx_cmdcb_t cmdcb, ctlx_usercb_t usercb, void *usercb_data); - -static int -hfa384x_dormem(struct hfa384x *hw, - u16 page, - u16 offset, - void *data, - unsigned int len); - -static int -hfa384x_dowmem(struct hfa384x *hw, - u16 page, - u16 offset, - void *data, - unsigned int len); - -static int hfa384x_isgood_pdrcode(u16 pdrcode); - -static inline const char *ctlxstr(enum ctlx_state s) -{ - static const char * const ctlx_str[] = { - "Initial state", - "Complete", - "Request failed", - "Request pending", - "Request packet submitted", - "Request packet completed", - "Response packet completed" - }; - - return ctlx_str[s]; -}; - -static inline struct hfa384x_usbctlx *get_active_ctlx(struct hfa384x *hw) -{ - return list_entry(hw->ctlxq.active.next, struct hfa384x_usbctlx, list); -} - -#ifdef DEBUG_USB -void dbprint_urb(struct urb *urb) -{ - pr_debug("urb->pipe=0x%08x\n", urb->pipe); - pr_debug("urb->status=0x%08x\n", urb->status); - pr_debug("urb->transfer_flags=0x%08x\n", urb->transfer_flags); - pr_debug("urb->transfer_buffer=0x%08x\n", - (unsigned int)urb->transfer_buffer); - pr_debug("urb->transfer_buffer_length=0x%08x\n", - urb->transfer_buffer_length); - pr_debug("urb->actual_length=0x%08x\n", urb->actual_length); - pr_debug("urb->setup_packet(ctl)=0x%08x\n", - (unsigned int)urb->setup_packet); - pr_debug("urb->start_frame(iso/irq)=0x%08x\n", urb->start_frame); - pr_debug("urb->interval(irq)=0x%08x\n", urb->interval); - pr_debug("urb->error_count(iso)=0x%08x\n", urb->error_count); - pr_debug("urb->context=0x%08x\n", (unsigned int)urb->context); - pr_debug("urb->complete=0x%08x\n", (unsigned int)urb->complete); -} -#endif - -/*---------------------------------------------------------------- - * submit_rx_urb - * - * Listen for input data on the BULK-IN pipe. If the pipe has - * stalled then schedule it to be reset. - * - * Arguments: - * hw device struct - * memflags memory allocation flags - * - * Returns: - * error code from submission - * - * Call context: - * Any - *---------------------------------------------------------------- - */ -static int submit_rx_urb(struct hfa384x *hw, gfp_t memflags) -{ - struct sk_buff *skb; - int result; - - skb = dev_alloc_skb(sizeof(union hfa384x_usbin)); - if (!skb) { - result = -ENOMEM; - goto done; - } - - /* Post the IN urb */ - usb_fill_bulk_urb(&hw->rx_urb, hw->usb, - hw->endp_in, - skb->data, sizeof(union hfa384x_usbin), - hfa384x_usbin_callback, hw->wlandev); - - hw->rx_urb_skb = skb; - - result = -ENOLINK; - if (!hw->wlandev->hwremoved && - !test_bit(WORK_RX_HALT, &hw->usb_flags)) { - result = usb_submit_urb(&hw->rx_urb, memflags); - - /* Check whether we need to reset the RX pipe */ - if (result == -EPIPE) { - netdev_warn(hw->wlandev->netdev, - "%s rx pipe stalled: requesting reset\n", - hw->wlandev->netdev->name); - if (!test_and_set_bit(WORK_RX_HALT, &hw->usb_flags)) - schedule_work(&hw->usb_work); - } - } - - /* Don't leak memory if anything should go wrong */ - if (result != 0) { - dev_kfree_skb(skb); - hw->rx_urb_skb = NULL; - } - -done: - return result; -} - -/*---------------------------------------------------------------- - * submit_tx_urb - * - * Prepares and submits the URB of transmitted data. If the - * submission fails then it will schedule the output pipe to - * be reset. - * - * Arguments: - * hw device struct - * tx_urb URB of data for transmission - * memflags memory allocation flags - * - * Returns: - * error code from submission - * - * Call context: - * Any - *---------------------------------------------------------------- - */ -static int submit_tx_urb(struct hfa384x *hw, struct urb *tx_urb, gfp_t memflags) -{ - struct net_device *netdev = hw->wlandev->netdev; - int result; - - result = -ENOLINK; - if (netif_running(netdev)) { - if (!hw->wlandev->hwremoved && - !test_bit(WORK_TX_HALT, &hw->usb_flags)) { - result = usb_submit_urb(tx_urb, memflags); - - /* Test whether we need to reset the TX pipe */ - if (result == -EPIPE) { - netdev_warn(hw->wlandev->netdev, - "%s tx pipe stalled: requesting reset\n", - netdev->name); - set_bit(WORK_TX_HALT, &hw->usb_flags); - schedule_work(&hw->usb_work); - } else if (result == 0) { - netif_stop_queue(netdev); - } - } - } - - return result; -} - -/*---------------------------------------------------------------- - * hfa394x_usb_defer - * - * There are some things that the USB stack cannot do while - * in interrupt context, so we arrange this function to run - * in process context. - * - * Arguments: - * hw device structure - * - * Returns: - * nothing - * - * Call context: - * process (by design) - *---------------------------------------------------------------- - */ -static void hfa384x_usb_defer(struct work_struct *data) -{ - struct hfa384x *hw = container_of(data, struct hfa384x, usb_work); - struct net_device *netdev = hw->wlandev->netdev; - - /* Don't bother trying to reset anything if the plug - * has been pulled ... - */ - if (hw->wlandev->hwremoved) - return; - - /* Reception has stopped: try to reset the input pipe */ - if (test_bit(WORK_RX_HALT, &hw->usb_flags)) { - int ret; - - usb_kill_urb(&hw->rx_urb); /* Cannot be holding spinlock! */ - - ret = usb_clear_halt(hw->usb, hw->endp_in); - if (ret != 0) { - netdev_err(hw->wlandev->netdev, - "Failed to clear rx pipe for %s: err=%d\n", - netdev->name, ret); - } else { - netdev_info(hw->wlandev->netdev, "%s rx pipe reset complete.\n", - netdev->name); - clear_bit(WORK_RX_HALT, &hw->usb_flags); - set_bit(WORK_RX_RESUME, &hw->usb_flags); - } - } - - /* Resume receiving data back from the device. */ - if (test_bit(WORK_RX_RESUME, &hw->usb_flags)) { - int ret; - - ret = submit_rx_urb(hw, GFP_KERNEL); - if (ret != 0) { - netdev_err(hw->wlandev->netdev, - "Failed to resume %s rx pipe.\n", - netdev->name); - } else { - clear_bit(WORK_RX_RESUME, &hw->usb_flags); - } - } - - /* Transmission has stopped: try to reset the output pipe */ - if (test_bit(WORK_TX_HALT, &hw->usb_flags)) { - int ret; - - usb_kill_urb(&hw->tx_urb); - ret = usb_clear_halt(hw->usb, hw->endp_out); - if (ret != 0) { - netdev_err(hw->wlandev->netdev, - "Failed to clear tx pipe for %s: err=%d\n", - netdev->name, ret); - } else { - netdev_info(hw->wlandev->netdev, "%s tx pipe reset complete.\n", - netdev->name); - clear_bit(WORK_TX_HALT, &hw->usb_flags); - set_bit(WORK_TX_RESUME, &hw->usb_flags); - - /* Stopping the BULK-OUT pipe also blocked - * us from sending any more CTLX URBs, so - * we need to re-run our queue ... - */ - hfa384x_usbctlxq_run(hw); - } - } - - /* Resume transmitting. */ - if (test_and_clear_bit(WORK_TX_RESUME, &hw->usb_flags)) - netif_wake_queue(hw->wlandev->netdev); -} - -/*---------------------------------------------------------------- - * hfa384x_create - * - * Sets up the struct hfa384x data structure for use. Note this - * does _not_ initialize the actual hardware, just the data structures - * we use to keep track of its state. - * - * Arguments: - * hw device structure - * irq device irq number - * iobase i/o base address for register access - * membase memory base address for register access - * - * Returns: - * nothing - * - * Side effects: - * - * Call context: - * process - *---------------------------------------------------------------- - */ -void hfa384x_create(struct hfa384x *hw, struct usb_device *usb) -{ - hw->usb = usb; - - /* Set up the waitq */ - init_waitqueue_head(&hw->cmdq); - - /* Initialize the command queue */ - spin_lock_init(&hw->ctlxq.lock); - INIT_LIST_HEAD(&hw->ctlxq.pending); - INIT_LIST_HEAD(&hw->ctlxq.active); - INIT_LIST_HEAD(&hw->ctlxq.completing); - INIT_LIST_HEAD(&hw->ctlxq.reapable); - - /* Initialize the authentication queue */ - skb_queue_head_init(&hw->authq); - - INIT_WORK(&hw->reaper_bh, hfa384x_usbctlx_reaper_task); - INIT_WORK(&hw->completion_bh, hfa384x_usbctlx_completion_task); - INIT_WORK(&hw->link_bh, prism2sta_processing_defer); - INIT_WORK(&hw->usb_work, hfa384x_usb_defer); - - timer_setup(&hw->throttle, hfa384x_usb_throttlefn, 0); - - timer_setup(&hw->resptimer, hfa384x_usbctlx_resptimerfn, 0); - - timer_setup(&hw->reqtimer, hfa384x_usbctlx_reqtimerfn, 0); - - usb_init_urb(&hw->rx_urb); - usb_init_urb(&hw->tx_urb); - usb_init_urb(&hw->ctlx_urb); - - hw->link_status = HFA384x_LINK_NOTCONNECTED; - hw->state = HFA384x_STATE_INIT; - - INIT_WORK(&hw->commsqual_bh, prism2sta_commsqual_defer); - timer_setup(&hw->commsqual_timer, prism2sta_commsqual_timer, 0); -} - -/*---------------------------------------------------------------- - * hfa384x_destroy - * - * Partner to hfa384x_create(). This function cleans up the hw - * structure so that it can be freed by the caller using a simple - * kfree. Currently, this function is just a placeholder. If, at some - * point in the future, an hw in the 'shutdown' state requires a 'deep' - * kfree, this is where it should be done. Note that if this function - * is called on a _running_ hw structure, the drvr_stop() function is - * called. - * - * Arguments: - * hw device structure - * - * Returns: - * nothing, this function is not allowed to fail. - * - * Side effects: - * - * Call context: - * process - *---------------------------------------------------------------- - */ -void hfa384x_destroy(struct hfa384x *hw) -{ - struct sk_buff *skb; - - if (hw->state == HFA384x_STATE_RUNNING) - hfa384x_drvr_stop(hw); - hw->state = HFA384x_STATE_PREINIT; - - kfree(hw->scanresults); - hw->scanresults = NULL; - - /* Now to clean out the auth queue */ - while ((skb = skb_dequeue(&hw->authq))) - dev_kfree_skb(skb); -} - -static struct hfa384x_usbctlx *usbctlx_alloc(void) -{ - struct hfa384x_usbctlx *ctlx; - - ctlx = kzalloc(sizeof(*ctlx), - in_interrupt() ? GFP_ATOMIC : GFP_KERNEL); - if (ctlx) - init_completion(&ctlx->done); - - return ctlx; -} - -static int -usbctlx_get_status(const struct hfa384x_usb_statusresp *cmdresp, - struct hfa384x_cmdresult *result) -{ - result->status = le16_to_cpu(cmdresp->status); - result->resp0 = le16_to_cpu(cmdresp->resp0); - result->resp1 = le16_to_cpu(cmdresp->resp1); - result->resp2 = le16_to_cpu(cmdresp->resp2); - - pr_debug("cmdresult:status=0x%04x resp0=0x%04x resp1=0x%04x resp2=0x%04x\n", - result->status, result->resp0, result->resp1, result->resp2); - - return result->status & HFA384x_STATUS_RESULT; -} - -static void -usbctlx_get_rridresult(const struct hfa384x_usb_rridresp *rridresp, - struct hfa384x_rridresult *result) -{ - result->rid = le16_to_cpu(rridresp->rid); - result->riddata = rridresp->data; - result->riddata_len = ((le16_to_cpu(rridresp->frmlen) - 1) * 2); -} - -/*---------------------------------------------------------------- - * Completor object: - * This completor must be passed to hfa384x_usbctlx_complete_sync() - * when processing a CTLX that returns a struct hfa384x_cmdresult structure. - *---------------------------------------------------------------- - */ -struct usbctlx_cmd_completor { - struct usbctlx_completor head; - - const struct hfa384x_usb_statusresp *cmdresp; - struct hfa384x_cmdresult *result; -}; - -static inline int usbctlx_cmd_completor_fn(struct usbctlx_completor *head) -{ - struct usbctlx_cmd_completor *complete; - - complete = (struct usbctlx_cmd_completor *)head; - return usbctlx_get_status(complete->cmdresp, complete->result); -} - -static inline struct usbctlx_completor * -init_cmd_completor(struct usbctlx_cmd_completor *completor, - const struct hfa384x_usb_statusresp *cmdresp, - struct hfa384x_cmdresult *result) -{ - completor->head.complete = usbctlx_cmd_completor_fn; - completor->cmdresp = cmdresp; - completor->result = result; - return &completor->head; -} - -/*---------------------------------------------------------------- - * Completor object: - * This completor must be passed to hfa384x_usbctlx_complete_sync() - * when processing a CTLX that reads a RID. - *---------------------------------------------------------------- - */ -struct usbctlx_rrid_completor { - struct usbctlx_completor head; - - const struct hfa384x_usb_rridresp *rridresp; - void *riddata; - unsigned int riddatalen; -}; - -static int usbctlx_rrid_completor_fn(struct usbctlx_completor *head) -{ - struct usbctlx_rrid_completor *complete; - struct hfa384x_rridresult rridresult; - - complete = (struct usbctlx_rrid_completor *)head; - usbctlx_get_rridresult(complete->rridresp, &rridresult); - - /* Validate the length, note body len calculation in bytes */ - if (rridresult.riddata_len != complete->riddatalen) { - pr_warn("RID len mismatch, rid=0x%04x hlen=%d fwlen=%d\n", - rridresult.rid, - complete->riddatalen, rridresult.riddata_len); - return -ENODATA; - } - - memcpy(complete->riddata, rridresult.riddata, complete->riddatalen); - return 0; -} - -static inline struct usbctlx_completor * -init_rrid_completor(struct usbctlx_rrid_completor *completor, - const struct hfa384x_usb_rridresp *rridresp, - void *riddata, - unsigned int riddatalen) -{ - completor->head.complete = usbctlx_rrid_completor_fn; - completor->rridresp = rridresp; - completor->riddata = riddata; - completor->riddatalen = riddatalen; - return &completor->head; -} - -/*---------------------------------------------------------------- - * Completor object: - * Interprets the results of a synchronous RID-write - *---------------------------------------------------------------- - */ -#define init_wrid_completor init_cmd_completor - -/*---------------------------------------------------------------- - * Completor object: - * Interprets the results of a synchronous memory-write - *---------------------------------------------------------------- - */ -#define init_wmem_completor init_cmd_completor - -/*---------------------------------------------------------------- - * Completor object: - * Interprets the results of a synchronous memory-read - *---------------------------------------------------------------- - */ -struct usbctlx_rmem_completor { - struct usbctlx_completor head; - - const struct hfa384x_usb_rmemresp *rmemresp; - void *data; - unsigned int len; -}; - -static int usbctlx_rmem_completor_fn(struct usbctlx_completor *head) -{ - struct usbctlx_rmem_completor *complete = - (struct usbctlx_rmem_completor *)head; - - pr_debug("rmemresp:len=%d\n", complete->rmemresp->frmlen); - memcpy(complete->data, complete->rmemresp->data, complete->len); - return 0; -} - -static inline struct usbctlx_completor * -init_rmem_completor(struct usbctlx_rmem_completor *completor, - struct hfa384x_usb_rmemresp *rmemresp, - void *data, - unsigned int len) -{ - completor->head.complete = usbctlx_rmem_completor_fn; - completor->rmemresp = rmemresp; - completor->data = data; - completor->len = len; - return &completor->head; -} - -/*---------------------------------------------------------------- - * hfa384x_cb_status - * - * Ctlx_complete handler for async CMD type control exchanges. - * mark the hw struct as such. - * - * Note: If the handling is changed here, it should probably be - * changed in docmd as well. - * - * Arguments: - * hw hw struct - * ctlx completed CTLX - * - * Returns: - * nothing - * - * Side effects: - * - * Call context: - * interrupt - *---------------------------------------------------------------- - */ -static void hfa384x_cb_status(struct hfa384x *hw, - const struct hfa384x_usbctlx *ctlx) -{ - if (ctlx->usercb) { - struct hfa384x_cmdresult cmdresult; - - if (ctlx->state != CTLX_COMPLETE) { - memset(&cmdresult, 0, sizeof(cmdresult)); - cmdresult.status = - HFA384x_STATUS_RESULT_SET(HFA384x_CMD_ERR); - } else { - usbctlx_get_status(&ctlx->inbuf.cmdresp, &cmdresult); - } - - ctlx->usercb(hw, &cmdresult, ctlx->usercb_data); - } -} - -/*---------------------------------------------------------------- - * hfa384x_cmd_initialize - * - * Issues the initialize command and sets the hw->state based - * on the result. - * - * Arguments: - * hw device structure - * - * Returns: - * 0 success - * >0 f/w reported error - f/w status code - * <0 driver reported error - * - * Side effects: - * - * Call context: - * process - *---------------------------------------------------------------- - */ -int hfa384x_cmd_initialize(struct hfa384x *hw) -{ - int result = 0; - int i; - struct hfa384x_metacmd cmd; - - cmd.cmd = HFA384x_CMDCODE_INIT; - cmd.parm0 = 0; - cmd.parm1 = 0; - cmd.parm2 = 0; - - result = hfa384x_docmd(hw, &cmd); - - pr_debug("cmdresp.init: status=0x%04x, resp0=0x%04x, resp1=0x%04x, resp2=0x%04x\n", - cmd.result.status, - cmd.result.resp0, cmd.result.resp1, cmd.result.resp2); - if (result == 0) { - for (i = 0; i < HFA384x_NUMPORTS_MAX; i++) - hw->port_enabled[i] = 0; - } - - hw->link_status = HFA384x_LINK_NOTCONNECTED; - - return result; -} - -/*---------------------------------------------------------------- - * hfa384x_cmd_disable - * - * Issues the disable command to stop communications on one of - * the MACs 'ports'. - * - * Arguments: - * hw device structure - * macport MAC port number (host order) - * - * Returns: - * 0 success - * >0 f/w reported failure - f/w status code - * <0 driver reported error (timeout|bad arg) - * - * Side effects: - * - * Call context: - * process - *---------------------------------------------------------------- - */ -int hfa384x_cmd_disable(struct hfa384x *hw, u16 macport) -{ - struct hfa384x_metacmd cmd; - - cmd.cmd = HFA384x_CMD_CMDCODE_SET(HFA384x_CMDCODE_DISABLE) | - HFA384x_CMD_MACPORT_SET(macport); - cmd.parm0 = 0; - cmd.parm1 = 0; - cmd.parm2 = 0; - - return hfa384x_docmd(hw, &cmd); -} - -/*---------------------------------------------------------------- - * hfa384x_cmd_enable - * - * Issues the enable command to enable communications on one of - * the MACs 'ports'. - * - * Arguments: - * hw device structure - * macport MAC port number - * - * Returns: - * 0 success - * >0 f/w reported failure - f/w status code - * <0 driver reported error (timeout|bad arg) - * - * Side effects: - * - * Call context: - * process - *---------------------------------------------------------------- - */ -int hfa384x_cmd_enable(struct hfa384x *hw, u16 macport) -{ - struct hfa384x_metacmd cmd; - - cmd.cmd = HFA384x_CMD_CMDCODE_SET(HFA384x_CMDCODE_ENABLE) | - HFA384x_CMD_MACPORT_SET(macport); - cmd.parm0 = 0; - cmd.parm1 = 0; - cmd.parm2 = 0; - - return hfa384x_docmd(hw, &cmd); -} - -/*---------------------------------------------------------------- - * hfa384x_cmd_monitor - * - * Enables the 'monitor mode' of the MAC. Here's the description of - * monitor mode that I've received thus far: - * - * "The "monitor mode" of operation is that the MAC passes all - * frames for which the PLCP checks are correct. All received - * MPDUs are passed to the host with MAC Port = 7, with a - * receive status of good, FCS error, or undecryptable. Passing - * certain MPDUs is a violation of the 802.11 standard, but useful - * for a debugging tool." Normal communication is not possible - * while monitor mode is enabled. - * - * Arguments: - * hw device structure - * enable a code (0x0b|0x0f) that enables/disables - * monitor mode. (host order) - * - * Returns: - * 0 success - * >0 f/w reported failure - f/w status code - * <0 driver reported error (timeout|bad arg) - * - * Side effects: - * - * Call context: - * process - *---------------------------------------------------------------- - */ -int hfa384x_cmd_monitor(struct hfa384x *hw, u16 enable) -{ - struct hfa384x_metacmd cmd; - - cmd.cmd = HFA384x_CMD_CMDCODE_SET(HFA384x_CMDCODE_MONITOR) | - HFA384x_CMD_AINFO_SET(enable); - cmd.parm0 = 0; - cmd.parm1 = 0; - cmd.parm2 = 0; - - return hfa384x_docmd(hw, &cmd); -} - -/*---------------------------------------------------------------- - * hfa384x_cmd_download - * - * Sets the controls for the MAC controller code/data download - * process. The arguments set the mode and address associated - * with a download. Note that the aux registers should be enabled - * prior to setting one of the download enable modes. - * - * Arguments: - * hw device structure - * mode 0 - Disable programming and begin code exec - * 1 - Enable volatile mem programming - * 2 - Enable non-volatile mem programming - * 3 - Program non-volatile section from NV download - * buffer. - * (host order) - * lowaddr - * highaddr For mode 1, sets the high & low order bits of - * the "destination address". This address will be - * the execution start address when download is - * subsequently disabled. - * For mode 2, sets the high & low order bits of - * the destination in NV ram. - * For modes 0 & 3, should be zero. (host order) - * NOTE: these are CMD format. - * codelen Length of the data to write in mode 2, - * zero otherwise. (host order) - * - * Returns: - * 0 success - * >0 f/w reported failure - f/w status code - * <0 driver reported error (timeout|bad arg) - * - * Side effects: - * - * Call context: - * process - *---------------------------------------------------------------- - */ -int hfa384x_cmd_download(struct hfa384x *hw, u16 mode, u16 lowaddr, - u16 highaddr, u16 codelen) -{ - struct hfa384x_metacmd cmd; - - pr_debug("mode=%d, lowaddr=0x%04x, highaddr=0x%04x, codelen=%d\n", - mode, lowaddr, highaddr, codelen); - - cmd.cmd = (HFA384x_CMD_CMDCODE_SET(HFA384x_CMDCODE_DOWNLD) | - HFA384x_CMD_PROGMODE_SET(mode)); - - cmd.parm0 = lowaddr; - cmd.parm1 = highaddr; - cmd.parm2 = codelen; - - return hfa384x_docmd(hw, &cmd); -} - -/*---------------------------------------------------------------- - * hfa384x_corereset - * - * Perform a reset of the hfa38xx MAC core. We assume that the hw - * structure is in its "created" state. That is, it is initialized - * with proper values. Note that if a reset is done after the - * device has been active for awhile, the caller might have to clean - * up some leftover cruft in the hw structure. - * - * Arguments: - * hw device structure - * holdtime how long (in ms) to hold the reset - * settletime how long (in ms) to wait after releasing - * the reset - * - * Returns: - * nothing - * - * Side effects: - * - * Call context: - * process - *---------------------------------------------------------------- - */ -int hfa384x_corereset(struct hfa384x *hw, int holdtime, - int settletime, int genesis) -{ - int result; - - result = usb_reset_device(hw->usb); - if (result < 0) { - netdev_err(hw->wlandev->netdev, "usb_reset_device() failed, result=%d.\n", - result); - } - - return result; -} - -/*---------------------------------------------------------------- - * hfa384x_usbctlx_complete_sync - * - * Waits for a synchronous CTLX object to complete, - * and then handles the response. - * - * Arguments: - * hw device structure - * ctlx CTLX ptr - * completor functor object to decide what to - * do with the CTLX's result. - * - * Returns: - * 0 Success - * -ERESTARTSYS Interrupted by a signal - * -EIO CTLX failed - * -ENODEV Adapter was unplugged - * ??? Result from completor - * - * Side effects: - * - * Call context: - * process - *---------------------------------------------------------------- - */ -static int hfa384x_usbctlx_complete_sync(struct hfa384x *hw, - struct hfa384x_usbctlx *ctlx, - struct usbctlx_completor *completor) -{ - unsigned long flags; - int result; - - result = wait_for_completion_interruptible(&ctlx->done); - - spin_lock_irqsave(&hw->ctlxq.lock, flags); - - /* - * We can only handle the CTLX if the USB disconnect - * function has not run yet ... - */ -cleanup: - if (hw->wlandev->hwremoved) { - spin_unlock_irqrestore(&hw->ctlxq.lock, flags); - result = -ENODEV; - } else if (result != 0) { - int runqueue = 0; - - /* - * We were probably interrupted, so delete - * this CTLX asynchronously, kill the timers - * and the URB, and then start the next - * pending CTLX. - * - * NOTE: We can only delete the timers and - * the URB if this CTLX is active. - */ - if (ctlx == get_active_ctlx(hw)) { - spin_unlock_irqrestore(&hw->ctlxq.lock, flags); - - del_timer_sync(&hw->reqtimer); - del_timer_sync(&hw->resptimer); - hw->req_timer_done = 1; - hw->resp_timer_done = 1; - usb_kill_urb(&hw->ctlx_urb); - - spin_lock_irqsave(&hw->ctlxq.lock, flags); - - runqueue = 1; - - /* - * This scenario is so unlikely that I'm - * happy with a grubby "goto" solution ... - */ - if (hw->wlandev->hwremoved) - goto cleanup; - } - - /* - * The completion task will send this CTLX - * to the reaper the next time it runs. We - * are no longer in a hurry. - */ - ctlx->reapable = 1; - ctlx->state = CTLX_REQ_FAILED; - list_move_tail(&ctlx->list, &hw->ctlxq.completing); - - spin_unlock_irqrestore(&hw->ctlxq.lock, flags); - - if (runqueue) - hfa384x_usbctlxq_run(hw); - } else { - if (ctlx->state == CTLX_COMPLETE) { - result = completor->complete(completor); - } else { - netdev_warn(hw->wlandev->netdev, "CTLX[%d] error: state(%s)\n", - le16_to_cpu(ctlx->outbuf.type), - ctlxstr(ctlx->state)); - result = -EIO; - } - - list_del(&ctlx->list); - spin_unlock_irqrestore(&hw->ctlxq.lock, flags); - kfree(ctlx); - } - - return result; -} - -/*---------------------------------------------------------------- - * hfa384x_docmd - * - * Constructs a command CTLX and submits it. - * - * NOTE: Any changes to the 'post-submit' code in this function - * need to be carried over to hfa384x_cbcmd() since the handling - * is virtually identical. - * - * Arguments: - * hw device structure - * cmd cmd structure. Includes all arguments and result - * data points. All in host order. in host order - * - * Returns: - * 0 success - * -EIO CTLX failure - * -ERESTARTSYS Awakened on signal - * >0 command indicated error, Status and Resp0-2 are - * in hw structure. - * - * Side effects: - * - * - * Call context: - * process - *---------------------------------------------------------------- - */ -static inline int -hfa384x_docmd(struct hfa384x *hw, - struct hfa384x_metacmd *cmd) -{ - int result; - struct hfa384x_usbctlx *ctlx; - - ctlx = usbctlx_alloc(); - if (!ctlx) { - result = -ENOMEM; - goto done; - } - - /* Initialize the command */ - ctlx->outbuf.cmdreq.type = cpu_to_le16(HFA384x_USB_CMDREQ); - ctlx->outbuf.cmdreq.cmd = cpu_to_le16(cmd->cmd); - ctlx->outbuf.cmdreq.parm0 = cpu_to_le16(cmd->parm0); - ctlx->outbuf.cmdreq.parm1 = cpu_to_le16(cmd->parm1); - ctlx->outbuf.cmdreq.parm2 = cpu_to_le16(cmd->parm2); - - ctlx->outbufsize = sizeof(ctlx->outbuf.cmdreq); - - pr_debug("cmdreq: cmd=0x%04x parm0=0x%04x parm1=0x%04x parm2=0x%04x\n", - cmd->cmd, cmd->parm0, cmd->parm1, cmd->parm2); - - ctlx->reapable = DOWAIT; - ctlx->cmdcb = NULL; - ctlx->usercb = NULL; - ctlx->usercb_data = NULL; - - result = hfa384x_usbctlx_submit(hw, ctlx); - if (result != 0) { - kfree(ctlx); - } else { - struct usbctlx_cmd_completor cmd_completor; - struct usbctlx_completor *completor; - - completor = init_cmd_completor(&cmd_completor, - &ctlx->inbuf.cmdresp, - &cmd->result); - - result = hfa384x_usbctlx_complete_sync(hw, ctlx, completor); - } - -done: - return result; -} - -/*---------------------------------------------------------------- - * hfa384x_dorrid - * - * Constructs a read rid CTLX and issues it. - * - * NOTE: Any changes to the 'post-submit' code in this function - * need to be carried over to hfa384x_cbrrid() since the handling - * is virtually identical. - * - * Arguments: - * hw device structure - * mode DOWAIT or DOASYNC - * rid Read RID number (host order) - * riddata Caller supplied buffer that MAC formatted RID.data - * record will be written to for DOWAIT calls. Should - * be NULL for DOASYNC calls. - * riddatalen Buffer length for DOWAIT calls. Zero for DOASYNC calls. - * cmdcb command callback for async calls, NULL for DOWAIT calls - * usercb user callback for async calls, NULL for DOWAIT calls - * usercb_data user supplied data pointer for async calls, NULL - * for DOWAIT calls - * - * Returns: - * 0 success - * -EIO CTLX failure - * -ERESTARTSYS Awakened on signal - * -ENODATA riddatalen != macdatalen - * >0 command indicated error, Status and Resp0-2 are - * in hw structure. - * - * Side effects: - * - * Call context: - * interrupt (DOASYNC) - * process (DOWAIT or DOASYNC) - *---------------------------------------------------------------- - */ -static int -hfa384x_dorrid(struct hfa384x *hw, - enum cmd_mode mode, - u16 rid, - void *riddata, - unsigned int riddatalen, - ctlx_cmdcb_t cmdcb, ctlx_usercb_t usercb, void *usercb_data) -{ - int result; - struct hfa384x_usbctlx *ctlx; - - ctlx = usbctlx_alloc(); - if (!ctlx) { - result = -ENOMEM; - goto done; - } - - /* Initialize the command */ - ctlx->outbuf.rridreq.type = cpu_to_le16(HFA384x_USB_RRIDREQ); - ctlx->outbuf.rridreq.frmlen = - cpu_to_le16(sizeof(ctlx->outbuf.rridreq.rid)); - ctlx->outbuf.rridreq.rid = cpu_to_le16(rid); - - ctlx->outbufsize = sizeof(ctlx->outbuf.rridreq); - - ctlx->reapable = mode; - ctlx->cmdcb = cmdcb; - ctlx->usercb = usercb; - ctlx->usercb_data = usercb_data; - - /* Submit the CTLX */ - result = hfa384x_usbctlx_submit(hw, ctlx); - if (result != 0) { - kfree(ctlx); - } else if (mode == DOWAIT) { - struct usbctlx_rrid_completor completor; - - result = - hfa384x_usbctlx_complete_sync(hw, ctlx, - init_rrid_completor - (&completor, - &ctlx->inbuf.rridresp, - riddata, riddatalen)); - } - -done: - return result; -} - -/*---------------------------------------------------------------- - * hfa384x_dowrid - * - * Constructs a write rid CTLX and issues it. - * - * NOTE: Any changes to the 'post-submit' code in this function - * need to be carried over to hfa384x_cbwrid() since the handling - * is virtually identical. - * - * Arguments: - * hw device structure - * enum cmd_mode DOWAIT or DOASYNC - * rid RID code - * riddata Data portion of RID formatted for MAC - * riddatalen Length of the data portion in bytes - * cmdcb command callback for async calls, NULL for DOWAIT calls - * usercb user callback for async calls, NULL for DOWAIT calls - * usercb_data user supplied data pointer for async calls - * - * Returns: - * 0 success - * -ETIMEDOUT timed out waiting for register ready or - * command completion - * >0 command indicated error, Status and Resp0-2 are - * in hw structure. - * - * Side effects: - * - * Call context: - * interrupt (DOASYNC) - * process (DOWAIT or DOASYNC) - *---------------------------------------------------------------- - */ -static int -hfa384x_dowrid(struct hfa384x *hw, - enum cmd_mode mode, - u16 rid, - void *riddata, - unsigned int riddatalen, - ctlx_cmdcb_t cmdcb, ctlx_usercb_t usercb, void *usercb_data) -{ - int result; - struct hfa384x_usbctlx *ctlx; - - ctlx = usbctlx_alloc(); - if (!ctlx) { - result = -ENOMEM; - goto done; - } - - /* Initialize the command */ - ctlx->outbuf.wridreq.type = cpu_to_le16(HFA384x_USB_WRIDREQ); - ctlx->outbuf.wridreq.frmlen = cpu_to_le16((sizeof - (ctlx->outbuf.wridreq.rid) + - riddatalen + 1) / 2); - ctlx->outbuf.wridreq.rid = cpu_to_le16(rid); - memcpy(ctlx->outbuf.wridreq.data, riddata, riddatalen); - - ctlx->outbufsize = sizeof(ctlx->outbuf.wridreq.type) + - sizeof(ctlx->outbuf.wridreq.frmlen) + - sizeof(ctlx->outbuf.wridreq.rid) + riddatalen; - - ctlx->reapable = mode; - ctlx->cmdcb = cmdcb; - ctlx->usercb = usercb; - ctlx->usercb_data = usercb_data; - - /* Submit the CTLX */ - result = hfa384x_usbctlx_submit(hw, ctlx); - if (result != 0) { - kfree(ctlx); - } else if (mode == DOWAIT) { - struct usbctlx_cmd_completor completor; - struct hfa384x_cmdresult wridresult; - - result = hfa384x_usbctlx_complete_sync(hw, - ctlx, - init_wrid_completor - (&completor, - &ctlx->inbuf.wridresp, - &wridresult)); - } - -done: - return result; -} - -/*---------------------------------------------------------------- - * hfa384x_dormem - * - * Constructs a readmem CTLX and issues it. - * - * NOTE: Any changes to the 'post-submit' code in this function - * need to be carried over to hfa384x_cbrmem() since the handling - * is virtually identical. - * - * Arguments: - * hw device structure - * page MAC address space page (CMD format) - * offset MAC address space offset - * data Ptr to data buffer to receive read - * len Length of the data to read (max == 2048) - * - * Returns: - * 0 success - * -ETIMEDOUT timed out waiting for register ready or - * command completion - * >0 command indicated error, Status and Resp0-2 are - * in hw structure. - * - * Side effects: - * - * Call context: - * process (DOWAIT) - *---------------------------------------------------------------- - */ -static int -hfa384x_dormem(struct hfa384x *hw, - u16 page, - u16 offset, - void *data, - unsigned int len) -{ - int result; - struct hfa384x_usbctlx *ctlx; - - ctlx = usbctlx_alloc(); - if (!ctlx) { - result = -ENOMEM; - goto done; - } - - /* Initialize the command */ - ctlx->outbuf.rmemreq.type = cpu_to_le16(HFA384x_USB_RMEMREQ); - ctlx->outbuf.rmemreq.frmlen = - cpu_to_le16(sizeof(ctlx->outbuf.rmemreq.offset) + - sizeof(ctlx->outbuf.rmemreq.page) + len); - ctlx->outbuf.rmemreq.offset = cpu_to_le16(offset); - ctlx->outbuf.rmemreq.page = cpu_to_le16(page); - - ctlx->outbufsize = sizeof(ctlx->outbuf.rmemreq); - - pr_debug("type=0x%04x frmlen=%d offset=0x%04x page=0x%04x\n", - ctlx->outbuf.rmemreq.type, - ctlx->outbuf.rmemreq.frmlen, - ctlx->outbuf.rmemreq.offset, ctlx->outbuf.rmemreq.page); - - pr_debug("pktsize=%zd\n", ROUNDUP64(sizeof(ctlx->outbuf.rmemreq))); - - ctlx->reapable = DOWAIT; - ctlx->cmdcb = NULL; - ctlx->usercb = NULL; - ctlx->usercb_data = NULL; - - result = hfa384x_usbctlx_submit(hw, ctlx); - if (result != 0) { - kfree(ctlx); - } else { - struct usbctlx_rmem_completor completor; - - result = - hfa384x_usbctlx_complete_sync(hw, ctlx, - init_rmem_completor - (&completor, - &ctlx->inbuf.rmemresp, data, - len)); - } - -done: - return result; -} - -/*---------------------------------------------------------------- - * hfa384x_dowmem - * - * Constructs a writemem CTLX and issues it. - * - * NOTE: Any changes to the 'post-submit' code in this function - * need to be carried over to hfa384x_cbwmem() since the handling - * is virtually identical. - * - * Arguments: - * hw device structure - * page MAC address space page (CMD format) - * offset MAC address space offset - * data Ptr to data buffer containing write data - * len Length of the data to read (max == 2048) - * - * Returns: - * 0 success - * -ETIMEDOUT timed out waiting for register ready or - * command completion - * >0 command indicated error, Status and Resp0-2 are - * in hw structure. - * - * Side effects: - * - * Call context: - * interrupt (DOWAIT) - * process (DOWAIT) - *---------------------------------------------------------------- - */ -static int -hfa384x_dowmem(struct hfa384x *hw, - u16 page, - u16 offset, - void *data, - unsigned int len) -{ - int result; - struct hfa384x_usbctlx *ctlx; - - pr_debug("page=0x%04x offset=0x%04x len=%d\n", page, offset, len); - - ctlx = usbctlx_alloc(); - if (!ctlx) { - result = -ENOMEM; - goto done; - } - - /* Initialize the command */ - ctlx->outbuf.wmemreq.type = cpu_to_le16(HFA384x_USB_WMEMREQ); - ctlx->outbuf.wmemreq.frmlen = - cpu_to_le16(sizeof(ctlx->outbuf.wmemreq.offset) + - sizeof(ctlx->outbuf.wmemreq.page) + len); - ctlx->outbuf.wmemreq.offset = cpu_to_le16(offset); - ctlx->outbuf.wmemreq.page = cpu_to_le16(page); - memcpy(ctlx->outbuf.wmemreq.data, data, len); - - ctlx->outbufsize = sizeof(ctlx->outbuf.wmemreq.type) + - sizeof(ctlx->outbuf.wmemreq.frmlen) + - sizeof(ctlx->outbuf.wmemreq.offset) + - sizeof(ctlx->outbuf.wmemreq.page) + len; - - ctlx->reapable = DOWAIT; - ctlx->cmdcb = NULL; - ctlx->usercb = NULL; - ctlx->usercb_data = NULL; - - result = hfa384x_usbctlx_submit(hw, ctlx); - if (result != 0) { - kfree(ctlx); - } else { - struct usbctlx_cmd_completor completor; - struct hfa384x_cmdresult wmemresult; - - result = hfa384x_usbctlx_complete_sync(hw, - ctlx, - init_wmem_completor - (&completor, - &ctlx->inbuf.wmemresp, - &wmemresult)); - } - -done: - return result; -} - -/*---------------------------------------------------------------- - * hfa384x_drvr_disable - * - * Issues the disable command to stop communications on one of - * the MACs 'ports'. Only macport 0 is valid for stations. - * APs may also disable macports 1-6. Only ports that have been - * previously enabled may be disabled. - * - * Arguments: - * hw device structure - * macport MAC port number (host order) - * - * Returns: - * 0 success - * >0 f/w reported failure - f/w status code - * <0 driver reported error (timeout|bad arg) - * - * Side effects: - * - * Call context: - * process - *---------------------------------------------------------------- - */ -int hfa384x_drvr_disable(struct hfa384x *hw, u16 macport) -{ - int result = 0; - - if ((!hw->isap && macport != 0) || - (hw->isap && !(macport <= HFA384x_PORTID_MAX)) || - !(hw->port_enabled[macport])) { - result = -EINVAL; - } else { - result = hfa384x_cmd_disable(hw, macport); - if (result == 0) - hw->port_enabled[macport] = 0; - } - return result; -} - -/*---------------------------------------------------------------- - * hfa384x_drvr_enable - * - * Issues the enable command to enable communications on one of - * the MACs 'ports'. Only macport 0 is valid for stations. - * APs may also enable macports 1-6. Only ports that are currently - * disabled may be enabled. - * - * Arguments: - * hw device structure - * macport MAC port number - * - * Returns: - * 0 success - * >0 f/w reported failure - f/w status code - * <0 driver reported error (timeout|bad arg) - * - * Side effects: - * - * Call context: - * process - *---------------------------------------------------------------- - */ -int hfa384x_drvr_enable(struct hfa384x *hw, u16 macport) -{ - int result = 0; - - if ((!hw->isap && macport != 0) || - (hw->isap && !(macport <= HFA384x_PORTID_MAX)) || - (hw->port_enabled[macport])) { - result = -EINVAL; - } else { - result = hfa384x_cmd_enable(hw, macport); - if (result == 0) - hw->port_enabled[macport] = 1; - } - return result; -} - -/*---------------------------------------------------------------- - * hfa384x_drvr_flashdl_enable - * - * Begins the flash download state. Checks to see that we're not - * already in a download state and that a port isn't enabled. - * Sets the download state and retrieves the flash download - * buffer location, buffer size, and timeout length. - * - * Arguments: - * hw device structure - * - * Returns: - * 0 success - * >0 f/w reported error - f/w status code - * <0 driver reported error - * - * Side effects: - * - * Call context: - * process - *---------------------------------------------------------------- - */ -int hfa384x_drvr_flashdl_enable(struct hfa384x *hw) -{ - int result = 0; - int i; - - /* Check that a port isn't active */ - for (i = 0; i < HFA384x_PORTID_MAX; i++) { - if (hw->port_enabled[i]) { - pr_debug("called when port enabled.\n"); - return -EINVAL; - } - } - - /* Check that we're not already in a download state */ - if (hw->dlstate != HFA384x_DLSTATE_DISABLED) - return -EINVAL; - - /* Retrieve the buffer loc&size and timeout */ - result = hfa384x_drvr_getconfig(hw, HFA384x_RID_DOWNLOADBUFFER, - &hw->bufinfo, sizeof(hw->bufinfo)); - if (result) - return result; - - le16_to_cpus(&hw->bufinfo.page); - le16_to_cpus(&hw->bufinfo.offset); - le16_to_cpus(&hw->bufinfo.len); - result = hfa384x_drvr_getconfig16(hw, HFA384x_RID_MAXLOADTIME, - &hw->dltimeout); - if (result) - return result; - - le16_to_cpus(&hw->dltimeout); - - pr_debug("flashdl_enable\n"); - - hw->dlstate = HFA384x_DLSTATE_FLASHENABLED; - - return result; -} - -/*---------------------------------------------------------------- - * hfa384x_drvr_flashdl_disable - * - * Ends the flash download state. Note that this will cause the MAC - * firmware to restart. - * - * Arguments: - * hw device structure - * - * Returns: - * 0 success - * >0 f/w reported error - f/w status code - * <0 driver reported error - * - * Side effects: - * - * Call context: - * process - *---------------------------------------------------------------- - */ -int hfa384x_drvr_flashdl_disable(struct hfa384x *hw) -{ - /* Check that we're already in the download state */ - if (hw->dlstate != HFA384x_DLSTATE_FLASHENABLED) - return -EINVAL; - - pr_debug("flashdl_enable\n"); - - /* There isn't much we can do at this point, so I don't */ - /* bother w/ the return value */ - hfa384x_cmd_download(hw, HFA384x_PROGMODE_DISABLE, 0, 0, 0); - hw->dlstate = HFA384x_DLSTATE_DISABLED; - - return 0; -} - -/*---------------------------------------------------------------- - * hfa384x_drvr_flashdl_write - * - * Performs a FLASH download of a chunk of data. First checks to see - * that we're in the FLASH download state, then sets the download - * mode, uses the aux functions to 1) copy the data to the flash - * buffer, 2) sets the download 'write flash' mode, 3) readback and - * compare. Lather rinse, repeat as many times an necessary to get - * all the given data into flash. - * When all data has been written using this function (possibly - * repeatedly), call drvr_flashdl_disable() to end the download state - * and restart the MAC. - * - * Arguments: - * hw device structure - * daddr Card address to write to. (host order) - * buf Ptr to data to write. - * len Length of data (host order). - * - * Returns: - * 0 success - * >0 f/w reported error - f/w status code - * <0 driver reported error - * - * Side effects: - * - * Call context: - * process - *---------------------------------------------------------------- - */ -int hfa384x_drvr_flashdl_write(struct hfa384x *hw, u32 daddr, - void *buf, u32 len) -{ - int result = 0; - u32 dlbufaddr; - int nburns; - u32 burnlen; - u32 burndaddr; - u16 burnlo; - u16 burnhi; - int nwrites; - u8 *writebuf; - u16 writepage; - u16 writeoffset; - u32 writelen; - int i; - int j; - - pr_debug("daddr=0x%08x len=%d\n", daddr, len); - - /* Check that we're in the flash download state */ - if (hw->dlstate != HFA384x_DLSTATE_FLASHENABLED) - return -EINVAL; - - netdev_info(hw->wlandev->netdev, - "Download %d bytes to flash @0x%06x\n", len, daddr); - - /* Convert to flat address for arithmetic */ - /* NOTE: dlbuffer RID stores the address in AUX format */ - dlbufaddr = - HFA384x_ADDR_AUX_MKFLAT(hw->bufinfo.page, hw->bufinfo.offset); - pr_debug("dlbuf.page=0x%04x dlbuf.offset=0x%04x dlbufaddr=0x%08x\n", - hw->bufinfo.page, hw->bufinfo.offset, dlbufaddr); - /* Calculations to determine how many fills of the dlbuffer to do - * and how many USB wmemreq's to do for each fill. At this point - * in time, the dlbuffer size and the wmemreq size are the same. - * Therefore, nwrites should always be 1. The extra complexity - * here is a hedge against future changes. - */ - - /* Figure out how many times to do the flash programming */ - nburns = len / hw->bufinfo.len; - nburns += (len % hw->bufinfo.len) ? 1 : 0; - - /* For each flash program cycle, how many USB wmemreq's are needed? */ - nwrites = hw->bufinfo.len / HFA384x_USB_RWMEM_MAXLEN; - nwrites += (hw->bufinfo.len % HFA384x_USB_RWMEM_MAXLEN) ? 1 : 0; - - /* For each burn */ - for (i = 0; i < nburns; i++) { - /* Get the dest address and len */ - burnlen = (len - (hw->bufinfo.len * i)) > hw->bufinfo.len ? - hw->bufinfo.len : (len - (hw->bufinfo.len * i)); - burndaddr = daddr + (hw->bufinfo.len * i); - burnlo = HFA384x_ADDR_CMD_MKOFF(burndaddr); - burnhi = HFA384x_ADDR_CMD_MKPAGE(burndaddr); - - netdev_info(hw->wlandev->netdev, "Writing %d bytes to flash @0x%06x\n", - burnlen, burndaddr); - - /* Set the download mode */ - result = hfa384x_cmd_download(hw, HFA384x_PROGMODE_NV, - burnlo, burnhi, burnlen); - if (result) { - netdev_err(hw->wlandev->netdev, - "download(NV,lo=%x,hi=%x,len=%x) cmd failed, result=%d. Aborting d/l\n", - burnlo, burnhi, burnlen, result); - goto exit_proc; - } - - /* copy the data to the flash download buffer */ - for (j = 0; j < nwrites; j++) { - writebuf = buf + - (i * hw->bufinfo.len) + - (j * HFA384x_USB_RWMEM_MAXLEN); - - writepage = HFA384x_ADDR_CMD_MKPAGE(dlbufaddr + - (j * HFA384x_USB_RWMEM_MAXLEN)); - writeoffset = HFA384x_ADDR_CMD_MKOFF(dlbufaddr + - (j * HFA384x_USB_RWMEM_MAXLEN)); - - writelen = burnlen - (j * HFA384x_USB_RWMEM_MAXLEN); - writelen = writelen > HFA384x_USB_RWMEM_MAXLEN ? - HFA384x_USB_RWMEM_MAXLEN : writelen; - - result = hfa384x_dowmem(hw, - writepage, - writeoffset, - writebuf, writelen); - } - - /* set the download 'write flash' mode */ - result = hfa384x_cmd_download(hw, - HFA384x_PROGMODE_NVWRITE, - 0, 0, 0); - if (result) { - netdev_err(hw->wlandev->netdev, - "download(NVWRITE,lo=%x,hi=%x,len=%x) cmd failed, result=%d. Aborting d/l\n", - burnlo, burnhi, burnlen, result); - goto exit_proc; - } - - /* TODO: We really should do a readback and compare. */ - } - -exit_proc: - - /* Leave the firmware in the 'post-prog' mode. flashdl_disable will */ - /* actually disable programming mode. Remember, that will cause the */ - /* the firmware to effectively reset itself. */ - - return result; -} - -/*---------------------------------------------------------------- - * hfa384x_drvr_getconfig - * - * Performs the sequence necessary to read a config/info item. - * - * Arguments: - * hw device structure - * rid config/info record id (host order) - * buf host side record buffer. Upon return it will - * contain the body portion of the record (minus the - * RID and len). - * len buffer length (in bytes, should match record length) - * - * Returns: - * 0 success - * >0 f/w reported error - f/w status code - * <0 driver reported error - * -ENODATA length mismatch between argument and retrieved - * record. - * - * Side effects: - * - * Call context: - * process - *---------------------------------------------------------------- - */ -int hfa384x_drvr_getconfig(struct hfa384x *hw, u16 rid, void *buf, u16 len) -{ - return hfa384x_dorrid(hw, DOWAIT, rid, buf, len, NULL, NULL, NULL); -} - -/*---------------------------------------------------------------- - * hfa384x_drvr_setconfig_async - * - * Performs the sequence necessary to write a config/info item. - * - * Arguments: - * hw device structure - * rid config/info record id (in host order) - * buf host side record buffer - * len buffer length (in bytes) - * usercb completion callback - * usercb_data completion callback argument - * - * Returns: - * 0 success - * >0 f/w reported error - f/w status code - * <0 driver reported error - * - * Side effects: - * - * Call context: - * process - *---------------------------------------------------------------- - */ -int -hfa384x_drvr_setconfig_async(struct hfa384x *hw, - u16 rid, - void *buf, - u16 len, ctlx_usercb_t usercb, void *usercb_data) -{ - return hfa384x_dowrid(hw, DOASYNC, rid, buf, len, hfa384x_cb_status, - usercb, usercb_data); -} - -/*---------------------------------------------------------------- - * hfa384x_drvr_ramdl_disable - * - * Ends the ram download state. - * - * Arguments: - * hw device structure - * - * Returns: - * 0 success - * >0 f/w reported error - f/w status code - * <0 driver reported error - * - * Side effects: - * - * Call context: - * process - *---------------------------------------------------------------- - */ -int hfa384x_drvr_ramdl_disable(struct hfa384x *hw) -{ - /* Check that we're already in the download state */ - if (hw->dlstate != HFA384x_DLSTATE_RAMENABLED) - return -EINVAL; - - pr_debug("ramdl_disable()\n"); - - /* There isn't much we can do at this point, so I don't */ - /* bother w/ the return value */ - hfa384x_cmd_download(hw, HFA384x_PROGMODE_DISABLE, 0, 0, 0); - hw->dlstate = HFA384x_DLSTATE_DISABLED; - - return 0; -} - -/*---------------------------------------------------------------- - * hfa384x_drvr_ramdl_enable - * - * Begins the ram download state. Checks to see that we're not - * already in a download state and that a port isn't enabled. - * Sets the download state and calls cmd_download with the - * ENABLE_VOLATILE subcommand and the exeaddr argument. - * - * Arguments: - * hw device structure - * exeaddr the card execution address that will be - * jumped to when ramdl_disable() is called - * (host order). - * - * Returns: - * 0 success - * >0 f/w reported error - f/w status code - * <0 driver reported error - * - * Side effects: - * - * Call context: - * process - *---------------------------------------------------------------- - */ -int hfa384x_drvr_ramdl_enable(struct hfa384x *hw, u32 exeaddr) -{ - int result = 0; - u16 lowaddr; - u16 hiaddr; - int i; - - /* Check that a port isn't active */ - for (i = 0; i < HFA384x_PORTID_MAX; i++) { - if (hw->port_enabled[i]) { - netdev_err(hw->wlandev->netdev, - "Can't download with a macport enabled.\n"); - return -EINVAL; - } - } - - /* Check that we're not already in a download state */ - if (hw->dlstate != HFA384x_DLSTATE_DISABLED) { - netdev_err(hw->wlandev->netdev, - "Download state not disabled.\n"); - return -EINVAL; - } - - pr_debug("ramdl_enable, exeaddr=0x%08x\n", exeaddr); - - /* Call the download(1,addr) function */ - lowaddr = HFA384x_ADDR_CMD_MKOFF(exeaddr); - hiaddr = HFA384x_ADDR_CMD_MKPAGE(exeaddr); - - result = hfa384x_cmd_download(hw, HFA384x_PROGMODE_RAM, - lowaddr, hiaddr, 0); - - if (result == 0) { - /* Set the download state */ - hw->dlstate = HFA384x_DLSTATE_RAMENABLED; - } else { - pr_debug("cmd_download(0x%04x, 0x%04x) failed, result=%d.\n", - lowaddr, hiaddr, result); - } - - return result; -} - -/*---------------------------------------------------------------- - * hfa384x_drvr_ramdl_write - * - * Performs a RAM download of a chunk of data. First checks to see - * that we're in the RAM download state, then uses the [read|write]mem USB - * commands to 1) copy the data, 2) readback and compare. The download - * state is unaffected. When all data has been written using - * this function, call drvr_ramdl_disable() to end the download state - * and restart the MAC. - * - * Arguments: - * hw device structure - * daddr Card address to write to. (host order) - * buf Ptr to data to write. - * len Length of data (host order). - * - * Returns: - * 0 success - * >0 f/w reported error - f/w status code - * <0 driver reported error - * - * Side effects: - * - * Call context: - * process - *---------------------------------------------------------------- - */ -int hfa384x_drvr_ramdl_write(struct hfa384x *hw, u32 daddr, void *buf, u32 len) -{ - int result = 0; - int nwrites; - u8 *data = buf; - int i; - u32 curraddr; - u16 currpage; - u16 curroffset; - u16 currlen; - - /* Check that we're in the ram download state */ - if (hw->dlstate != HFA384x_DLSTATE_RAMENABLED) - return -EINVAL; - - netdev_info(hw->wlandev->netdev, "Writing %d bytes to ram @0x%06x\n", - len, daddr); - - /* How many dowmem calls? */ - nwrites = len / HFA384x_USB_RWMEM_MAXLEN; - nwrites += len % HFA384x_USB_RWMEM_MAXLEN ? 1 : 0; - - /* Do blocking wmem's */ - for (i = 0; i < nwrites; i++) { - /* make address args */ - curraddr = daddr + (i * HFA384x_USB_RWMEM_MAXLEN); - currpage = HFA384x_ADDR_CMD_MKPAGE(curraddr); - curroffset = HFA384x_ADDR_CMD_MKOFF(curraddr); - currlen = len - (i * HFA384x_USB_RWMEM_MAXLEN); - if (currlen > HFA384x_USB_RWMEM_MAXLEN) - currlen = HFA384x_USB_RWMEM_MAXLEN; - - /* Do blocking ctlx */ - result = hfa384x_dowmem(hw, - currpage, - curroffset, - data + (i * HFA384x_USB_RWMEM_MAXLEN), - currlen); - - if (result) - break; - - /* TODO: We really should have a readback. */ - } - - return result; -} - -/*---------------------------------------------------------------- - * hfa384x_drvr_readpda - * - * Performs the sequence to read the PDA space. Note there is no - * drvr_writepda() function. Writing a PDA is - * generally implemented by a calling component via calls to - * cmd_download and writing to the flash download buffer via the - * aux regs. - * - * Arguments: - * hw device structure - * buf buffer to store PDA in - * len buffer length - * - * Returns: - * 0 success - * >0 f/w reported error - f/w status code - * <0 driver reported error - * -ETIMEDOUT timeout waiting for the cmd regs to become - * available, or waiting for the control reg - * to indicate the Aux port is enabled. - * -ENODATA the buffer does NOT contain a valid PDA. - * Either the card PDA is bad, or the auxdata - * reads are giving us garbage. - * - * - * Side effects: - * - * Call context: - * process or non-card interrupt. - *---------------------------------------------------------------- - */ -int hfa384x_drvr_readpda(struct hfa384x *hw, void *buf, unsigned int len) -{ - int result = 0; - __le16 *pda = buf; - int pdaok = 0; - int morepdrs = 1; - int currpdr = 0; /* word offset of the current pdr */ - size_t i; - u16 pdrlen; /* pdr length in bytes, host order */ - u16 pdrcode; /* pdr code, host order */ - u16 currpage; - u16 curroffset; - struct pdaloc { - u32 cardaddr; - u16 auxctl; - } pdaloc[] = { - { - HFA3842_PDA_BASE, 0}, { - HFA3841_PDA_BASE, 0}, { - HFA3841_PDA_BOGUS_BASE, 0} - }; - - /* Read the pda from each known address. */ - for (i = 0; i < ARRAY_SIZE(pdaloc); i++) { - /* Make address */ - currpage = HFA384x_ADDR_CMD_MKPAGE(pdaloc[i].cardaddr); - curroffset = HFA384x_ADDR_CMD_MKOFF(pdaloc[i].cardaddr); - - /* units of bytes */ - result = hfa384x_dormem(hw, currpage, curroffset, buf, - len); - - if (result) { - netdev_warn(hw->wlandev->netdev, - "Read from index %zd failed, continuing\n", - i); - continue; - } - - /* Test for garbage */ - pdaok = 1; /* initially assume good */ - morepdrs = 1; - while (pdaok && morepdrs) { - pdrlen = le16_to_cpu(pda[currpdr]) * 2; - pdrcode = le16_to_cpu(pda[currpdr + 1]); - /* Test the record length */ - if (pdrlen > HFA384x_PDR_LEN_MAX || pdrlen == 0) { - netdev_err(hw->wlandev->netdev, - "pdrlen invalid=%d\n", pdrlen); - pdaok = 0; - break; - } - /* Test the code */ - if (!hfa384x_isgood_pdrcode(pdrcode)) { - netdev_err(hw->wlandev->netdev, "pdrcode invalid=%d\n", - pdrcode); - pdaok = 0; - break; - } - /* Test for completion */ - if (pdrcode == HFA384x_PDR_END_OF_PDA) - morepdrs = 0; - - /* Move to the next pdr (if necessary) */ - if (morepdrs) { - /* note the access to pda[], need words here */ - currpdr += le16_to_cpu(pda[currpdr]) + 1; - } - } - if (pdaok) { - netdev_info(hw->wlandev->netdev, - "PDA Read from 0x%08x in %s space.\n", - pdaloc[i].cardaddr, - pdaloc[i].auxctl == 0 ? "EXTDS" : - pdaloc[i].auxctl == 1 ? "NV" : - pdaloc[i].auxctl == 2 ? "PHY" : - pdaloc[i].auxctl == 3 ? "ICSRAM" : - ""); - break; - } - } - result = pdaok ? 0 : -ENODATA; - - if (result) - pr_debug("Failure: pda is not okay\n"); - - return result; -} - -/*---------------------------------------------------------------- - * hfa384x_drvr_setconfig - * - * Performs the sequence necessary to write a config/info item. - * - * Arguments: - * hw device structure - * rid config/info record id (in host order) - * buf host side record buffer - * len buffer length (in bytes) - * - * Returns: - * 0 success - * >0 f/w reported error - f/w status code - * <0 driver reported error - * - * Side effects: - * - * Call context: - * process - *---------------------------------------------------------------- - */ -int hfa384x_drvr_setconfig(struct hfa384x *hw, u16 rid, void *buf, u16 len) -{ - return hfa384x_dowrid(hw, DOWAIT, rid, buf, len, NULL, NULL, NULL); -} - -/*---------------------------------------------------------------- - * hfa384x_drvr_start - * - * Issues the MAC initialize command, sets up some data structures, - * and enables the interrupts. After this function completes, the - * low-level stuff should be ready for any/all commands. - * - * Arguments: - * hw device structure - * Returns: - * 0 success - * >0 f/w reported error - f/w status code - * <0 driver reported error - * - * Side effects: - * - * Call context: - * process - *---------------------------------------------------------------- - */ -int hfa384x_drvr_start(struct hfa384x *hw) -{ - int result, result1, result2; - u16 status; - - might_sleep(); - - /* Clear endpoint stalls - but only do this if the endpoint - * is showing a stall status. Some prism2 cards seem to behave - * badly if a clear_halt is called when the endpoint is already - * ok - */ - result = - usb_get_std_status(hw->usb, USB_RECIP_ENDPOINT, hw->endp_in, - &status); - if (result < 0) { - netdev_err(hw->wlandev->netdev, "Cannot get bulk in endpoint status.\n"); - goto done; - } - if ((status == 1) && usb_clear_halt(hw->usb, hw->endp_in)) - netdev_err(hw->wlandev->netdev, "Failed to reset bulk in endpoint.\n"); - - result = - usb_get_std_status(hw->usb, USB_RECIP_ENDPOINT, hw->endp_out, - &status); - if (result < 0) { - netdev_err(hw->wlandev->netdev, "Cannot get bulk out endpoint status.\n"); - goto done; - } - if ((status == 1) && usb_clear_halt(hw->usb, hw->endp_out)) - netdev_err(hw->wlandev->netdev, "Failed to reset bulk out endpoint.\n"); - - /* Synchronous unlink, in case we're trying to restart the driver */ - usb_kill_urb(&hw->rx_urb); - - /* Post the IN urb */ - result = submit_rx_urb(hw, GFP_KERNEL); - if (result != 0) { - netdev_err(hw->wlandev->netdev, - "Fatal, failed to submit RX URB, result=%d\n", - result); - goto done; - } - - /* Call initialize twice, with a 1 second sleep in between. - * This is a nasty work-around since many prism2 cards seem to - * need time to settle after an init from cold. The second - * call to initialize in theory is not necessary - but we call - * it anyway as a double insurance policy: - * 1) If the first init should fail, the second may well succeed - * and the card can still be used - * 2) It helps ensures all is well with the card after the first - * init and settle time. - */ - result1 = hfa384x_cmd_initialize(hw); - msleep(1000); - result = hfa384x_cmd_initialize(hw); - result2 = result; - if (result1 != 0) { - if (result2 != 0) { - netdev_err(hw->wlandev->netdev, - "cmd_initialize() failed on two attempts, results %d and %d\n", - result1, result2); - usb_kill_urb(&hw->rx_urb); - goto done; - } else { - pr_debug("First cmd_initialize() failed (result %d),\n", - result1); - pr_debug("but second attempt succeeded. All should be ok\n"); - } - } else if (result2 != 0) { - netdev_warn(hw->wlandev->netdev, "First cmd_initialize() succeeded, but second attempt failed (result=%d)\n", - result2); - netdev_warn(hw->wlandev->netdev, - "Most likely the card will be functional\n"); - goto done; - } - - hw->state = HFA384x_STATE_RUNNING; - -done: - return result; -} - -/*---------------------------------------------------------------- - * hfa384x_drvr_stop - * - * Shuts down the MAC to the point where it is safe to unload the - * driver. Any subsystem that may be holding a data or function - * ptr into the driver must be cleared/deinitialized. - * - * Arguments: - * hw device structure - * Returns: - * 0 success - * >0 f/w reported error - f/w status code - * <0 driver reported error - * - * Side effects: - * - * Call context: - * process - *---------------------------------------------------------------- - */ -int hfa384x_drvr_stop(struct hfa384x *hw) -{ - int i; - - might_sleep(); - - /* There's no need for spinlocks here. The USB "disconnect" - * function sets this "removed" flag and then calls us. - */ - if (!hw->wlandev->hwremoved) { - /* Call initialize to leave the MAC in its 'reset' state */ - hfa384x_cmd_initialize(hw); - - /* Cancel the rxurb */ - usb_kill_urb(&hw->rx_urb); - } - - hw->link_status = HFA384x_LINK_NOTCONNECTED; - hw->state = HFA384x_STATE_INIT; - - del_timer_sync(&hw->commsqual_timer); - - /* Clear all the port status */ - for (i = 0; i < HFA384x_NUMPORTS_MAX; i++) - hw->port_enabled[i] = 0; - - return 0; -} - -/*---------------------------------------------------------------- - * hfa384x_drvr_txframe - * - * Takes a frame from prism2sta and queues it for transmission. - * - * Arguments: - * hw device structure - * skb packet buffer struct. Contains an 802.11 - * data frame. - * p80211_hdr points to the 802.11 header for the packet. - * Returns: - * 0 Success and more buffs available - * 1 Success but no more buffs - * 2 Allocation failure - * 4 Buffer full or queue busy - * - * Side effects: - * - * Call context: - * interrupt - *---------------------------------------------------------------- - */ -int hfa384x_drvr_txframe(struct hfa384x *hw, struct sk_buff *skb, - struct p80211_hdr *p80211_hdr, - struct p80211_metawep *p80211_wep) -{ - int usbpktlen = sizeof(struct hfa384x_tx_frame); - int result; - int ret; - char *ptr; - - if (hw->tx_urb.status == -EINPROGRESS) { - netdev_warn(hw->wlandev->netdev, "TX URB already in use\n"); - result = 3; - goto exit; - } - - /* Build Tx frame structure */ - /* Set up the control field */ - memset(&hw->txbuff.txfrm.desc, 0, sizeof(hw->txbuff.txfrm.desc)); - - /* Setup the usb type field */ - hw->txbuff.type = cpu_to_le16(HFA384x_USB_TXFRM); - - /* Set up the sw_support field to identify this frame */ - hw->txbuff.txfrm.desc.sw_support = 0x0123; - -/* Tx complete and Tx exception disable per dleach. Might be causing - * buf depletion - */ -/* #define DOEXC SLP -- doboth breaks horribly under load, doexc less so. */ -#if defined(DOBOTH) - hw->txbuff.txfrm.desc.tx_control = - HFA384x_TX_MACPORT_SET(0) | HFA384x_TX_STRUCTYPE_SET(1) | - HFA384x_TX_TXEX_SET(1) | HFA384x_TX_TXOK_SET(1); -#elif defined(DOEXC) - hw->txbuff.txfrm.desc.tx_control = - HFA384x_TX_MACPORT_SET(0) | HFA384x_TX_STRUCTYPE_SET(1) | - HFA384x_TX_TXEX_SET(1) | HFA384x_TX_TXOK_SET(0); -#else - hw->txbuff.txfrm.desc.tx_control = - HFA384x_TX_MACPORT_SET(0) | HFA384x_TX_STRUCTYPE_SET(1) | - HFA384x_TX_TXEX_SET(0) | HFA384x_TX_TXOK_SET(0); -#endif - cpu_to_le16s(&hw->txbuff.txfrm.desc.tx_control); - - /* copy the header over to the txdesc */ - hw->txbuff.txfrm.desc.hdr = *p80211_hdr; - - /* if we're using host WEP, increase size by IV+ICV */ - if (p80211_wep->data) { - hw->txbuff.txfrm.desc.data_len = cpu_to_le16(skb->len + 8); - usbpktlen += 8; - } else { - hw->txbuff.txfrm.desc.data_len = cpu_to_le16(skb->len); - } - - usbpktlen += skb->len; - - /* copy over the WEP IV if we are using host WEP */ - ptr = hw->txbuff.txfrm.data; - if (p80211_wep->data) { - memcpy(ptr, p80211_wep->iv, sizeof(p80211_wep->iv)); - ptr += sizeof(p80211_wep->iv); - memcpy(ptr, p80211_wep->data, skb->len); - } else { - memcpy(ptr, skb->data, skb->len); - } - /* copy over the packet data */ - ptr += skb->len; - - /* copy over the WEP ICV if we are using host WEP */ - if (p80211_wep->data) - memcpy(ptr, p80211_wep->icv, sizeof(p80211_wep->icv)); - - /* Send the USB packet */ - usb_fill_bulk_urb(&hw->tx_urb, hw->usb, - hw->endp_out, - &hw->txbuff, ROUNDUP64(usbpktlen), - hfa384x_usbout_callback, hw->wlandev); - hw->tx_urb.transfer_flags |= USB_QUEUE_BULK; - - result = 1; - ret = submit_tx_urb(hw, &hw->tx_urb, GFP_ATOMIC); - if (ret != 0) { - netdev_err(hw->wlandev->netdev, - "submit_tx_urb() failed, error=%d\n", ret); - result = 3; - } - -exit: - return result; -} - -void hfa384x_tx_timeout(struct wlandevice *wlandev) -{ - struct hfa384x *hw = wlandev->priv; - unsigned long flags; - - spin_lock_irqsave(&hw->ctlxq.lock, flags); - - if (!hw->wlandev->hwremoved) { - int sched; - - sched = !test_and_set_bit(WORK_TX_HALT, &hw->usb_flags); - sched |= !test_and_set_bit(WORK_RX_HALT, &hw->usb_flags); - if (sched) - schedule_work(&hw->usb_work); - } - - spin_unlock_irqrestore(&hw->ctlxq.lock, flags); -} - -/*---------------------------------------------------------------- - * hfa384x_usbctlx_reaper_task - * - * Deferred work callback to delete dead CTLX objects - * - * Arguments: - * work contains ptr to a struct hfa384x - * - * Returns: - * - * Call context: - * Task - *---------------------------------------------------------------- - */ -static void hfa384x_usbctlx_reaper_task(struct work_struct *work) -{ - struct hfa384x *hw = container_of(work, struct hfa384x, reaper_bh); - struct hfa384x_usbctlx *ctlx, *temp; - unsigned long flags; - - spin_lock_irqsave(&hw->ctlxq.lock, flags); - - /* This list is guaranteed to be empty if someone - * has unplugged the adapter. - */ - list_for_each_entry_safe(ctlx, temp, &hw->ctlxq.reapable, list) { - list_del(&ctlx->list); - kfree(ctlx); - } - - spin_unlock_irqrestore(&hw->ctlxq.lock, flags); -} - -/*---------------------------------------------------------------- - * hfa384x_usbctlx_completion_task - * - * Deferred work callback to call completion handlers for returned CTLXs - * - * Arguments: - * work contains ptr to a struct hfa384x - * - * Returns: - * Nothing - * - * Call context: - * Task - *---------------------------------------------------------------- - */ -static void hfa384x_usbctlx_completion_task(struct work_struct *work) -{ - struct hfa384x *hw = container_of(work, struct hfa384x, completion_bh); - struct hfa384x_usbctlx *ctlx, *temp; - unsigned long flags; - - int reap = 0; - - spin_lock_irqsave(&hw->ctlxq.lock, flags); - - /* This list is guaranteed to be empty if someone - * has unplugged the adapter ... - */ - list_for_each_entry_safe(ctlx, temp, &hw->ctlxq.completing, list) { - /* Call the completion function that this - * command was assigned, assuming it has one. - */ - if (ctlx->cmdcb) { - spin_unlock_irqrestore(&hw->ctlxq.lock, flags); - ctlx->cmdcb(hw, ctlx); - spin_lock_irqsave(&hw->ctlxq.lock, flags); - - /* Make sure we don't try and complete - * this CTLX more than once! - */ - ctlx->cmdcb = NULL; - - /* Did someone yank the adapter out - * while our list was (briefly) unlocked? - */ - if (hw->wlandev->hwremoved) { - reap = 0; - break; - } - } - - /* - * "Reapable" CTLXs are ones which don't have any - * threads waiting for them to die. Hence they must - * be delivered to The Reaper! - */ - if (ctlx->reapable) { - /* Move the CTLX off the "completing" list (hopefully) - * on to the "reapable" list where the reaper task - * can find it. And "reapable" means that this CTLX - * isn't sitting on a wait-queue somewhere. - */ - list_move_tail(&ctlx->list, &hw->ctlxq.reapable); - reap = 1; - } - - complete(&ctlx->done); - } - spin_unlock_irqrestore(&hw->ctlxq.lock, flags); - - if (reap) - schedule_work(&hw->reaper_bh); -} - -/*---------------------------------------------------------------- - * unlocked_usbctlx_cancel_async - * - * Mark the CTLX dead asynchronously, and ensure that the - * next command on the queue is run afterwards. - * - * Arguments: - * hw ptr to the struct hfa384x structure - * ctlx ptr to a CTLX structure - * - * Returns: - * 0 the CTLX's URB is inactive - * -EINPROGRESS the URB is currently being unlinked - * - * Call context: - * Either process or interrupt, but presumably interrupt - *---------------------------------------------------------------- - */ -static int unlocked_usbctlx_cancel_async(struct hfa384x *hw, - struct hfa384x_usbctlx *ctlx) -{ - int ret; - - /* - * Try to delete the URB containing our request packet. - * If we succeed, then its completion handler will be - * called with a status of -ECONNRESET. - */ - hw->ctlx_urb.transfer_flags |= URB_ASYNC_UNLINK; - ret = usb_unlink_urb(&hw->ctlx_urb); - - if (ret != -EINPROGRESS) { - /* - * The OUT URB had either already completed - * or was still in the pending queue, so the - * URB's completion function will not be called. - * We will have to complete the CTLX ourselves. - */ - ctlx->state = CTLX_REQ_FAILED; - unlocked_usbctlx_complete(hw, ctlx); - ret = 0; - } - - return ret; -} - -/*---------------------------------------------------------------- - * unlocked_usbctlx_complete - * - * A CTLX has completed. It may have been successful, it may not - * have been. At this point, the CTLX should be quiescent. The URBs - * aren't active and the timers should have been stopped. - * - * The CTLX is migrated to the "completing" queue, and the completing - * work is scheduled. - * - * Arguments: - * hw ptr to a struct hfa384x structure - * ctlx ptr to a ctlx structure - * - * Returns: - * nothing - * - * Side effects: - * - * Call context: - * Either, assume interrupt - *---------------------------------------------------------------- - */ -static void unlocked_usbctlx_complete(struct hfa384x *hw, - struct hfa384x_usbctlx *ctlx) -{ - /* Timers have been stopped, and ctlx should be in - * a terminal state. Retire it from the "active" - * queue. - */ - list_move_tail(&ctlx->list, &hw->ctlxq.completing); - schedule_work(&hw->completion_bh); - - switch (ctlx->state) { - case CTLX_COMPLETE: - case CTLX_REQ_FAILED: - /* This are the correct terminating states. */ - break; - - default: - netdev_err(hw->wlandev->netdev, "CTLX[%d] not in a terminating state(%s)\n", - le16_to_cpu(ctlx->outbuf.type), - ctlxstr(ctlx->state)); - break; - } /* switch */ -} - -/*---------------------------------------------------------------- - * hfa384x_usbctlxq_run - * - * Checks to see if the head item is running. If not, starts it. - * - * Arguments: - * hw ptr to struct hfa384x - * - * Returns: - * nothing - * - * Side effects: - * - * Call context: - * any - *---------------------------------------------------------------- - */ -static void hfa384x_usbctlxq_run(struct hfa384x *hw) -{ - unsigned long flags; - - /* acquire lock */ - spin_lock_irqsave(&hw->ctlxq.lock, flags); - - /* Only one active CTLX at any one time, because there's no - * other (reliable) way to match the response URB to the - * correct CTLX. - * - * Don't touch any of these CTLXs if the hardware - * has been removed or the USB subsystem is stalled. - */ - if (!list_empty(&hw->ctlxq.active) || - test_bit(WORK_TX_HALT, &hw->usb_flags) || hw->wlandev->hwremoved) - goto unlock; - - while (!list_empty(&hw->ctlxq.pending)) { - struct hfa384x_usbctlx *head; - int result; - - /* This is the first pending command */ - head = list_entry(hw->ctlxq.pending.next, - struct hfa384x_usbctlx, list); - - /* We need to split this off to avoid a race condition */ - list_move_tail(&head->list, &hw->ctlxq.active); - - /* Fill the out packet */ - usb_fill_bulk_urb(&hw->ctlx_urb, hw->usb, - hw->endp_out, - &head->outbuf, ROUNDUP64(head->outbufsize), - hfa384x_ctlxout_callback, hw); - hw->ctlx_urb.transfer_flags |= USB_QUEUE_BULK; - - /* Now submit the URB and update the CTLX's state */ - result = usb_submit_urb(&hw->ctlx_urb, GFP_ATOMIC); - if (result == 0) { - /* This CTLX is now running on the active queue */ - head->state = CTLX_REQ_SUBMITTED; - - /* Start the OUT wait timer */ - hw->req_timer_done = 0; - hw->reqtimer.expires = jiffies + HZ; - add_timer(&hw->reqtimer); - - /* Start the IN wait timer */ - hw->resp_timer_done = 0; - hw->resptimer.expires = jiffies + 2 * HZ; - add_timer(&hw->resptimer); - - break; - } - - if (result == -EPIPE) { - /* The OUT pipe needs resetting, so put - * this CTLX back in the "pending" queue - * and schedule a reset ... - */ - netdev_warn(hw->wlandev->netdev, - "%s tx pipe stalled: requesting reset\n", - hw->wlandev->netdev->name); - list_move(&head->list, &hw->ctlxq.pending); - set_bit(WORK_TX_HALT, &hw->usb_flags); - schedule_work(&hw->usb_work); - break; - } - - if (result == -ESHUTDOWN) { - netdev_warn(hw->wlandev->netdev, "%s urb shutdown!\n", - hw->wlandev->netdev->name); - break; - } - - netdev_err(hw->wlandev->netdev, "Failed to submit CTLX[%d]: error=%d\n", - le16_to_cpu(head->outbuf.type), result); - unlocked_usbctlx_complete(hw, head); - } /* while */ - -unlock: - spin_unlock_irqrestore(&hw->ctlxq.lock, flags); -} - -/*---------------------------------------------------------------- - * hfa384x_usbin_callback - * - * Callback for URBs on the BULKIN endpoint. - * - * Arguments: - * urb ptr to the completed urb - * - * Returns: - * nothing - * - * Side effects: - * - * Call context: - * interrupt - *---------------------------------------------------------------- - */ -static void hfa384x_usbin_callback(struct urb *urb) -{ - struct wlandevice *wlandev = urb->context; - struct hfa384x *hw; - union hfa384x_usbin *usbin; - struct sk_buff *skb = NULL; - int result; - int urb_status; - u16 type; - - enum USBIN_ACTION { - HANDLE, - RESUBMIT, - ABORT - } action; - - if (!wlandev || !wlandev->netdev || wlandev->hwremoved) - goto exit; - - hw = wlandev->priv; - if (!hw) - goto exit; - - skb = hw->rx_urb_skb; - if (!skb || (skb->data != urb->transfer_buffer)) { - WARN_ON(1); - return; - } - - hw->rx_urb_skb = NULL; - - /* Check for error conditions within the URB */ - switch (urb->status) { - case 0: - action = HANDLE; - - /* Check for short packet */ - if (urb->actual_length == 0) { - wlandev->netdev->stats.rx_errors++; - wlandev->netdev->stats.rx_length_errors++; - action = RESUBMIT; - } - break; - - case -EPIPE: - netdev_warn(hw->wlandev->netdev, "%s rx pipe stalled: requesting reset\n", - wlandev->netdev->name); - if (!test_and_set_bit(WORK_RX_HALT, &hw->usb_flags)) - schedule_work(&hw->usb_work); - wlandev->netdev->stats.rx_errors++; - action = ABORT; - break; - - case -EILSEQ: - case -ETIMEDOUT: - case -EPROTO: - if (!test_and_set_bit(THROTTLE_RX, &hw->usb_flags) && - !timer_pending(&hw->throttle)) { - mod_timer(&hw->throttle, jiffies + THROTTLE_JIFFIES); - } - wlandev->netdev->stats.rx_errors++; - action = ABORT; - break; - - case -EOVERFLOW: - wlandev->netdev->stats.rx_over_errors++; - action = RESUBMIT; - break; - - case -ENODEV: - case -ESHUTDOWN: - pr_debug("status=%d, device removed.\n", urb->status); - action = ABORT; - break; - - case -ENOENT: - case -ECONNRESET: - pr_debug("status=%d, urb explicitly unlinked.\n", urb->status); - action = ABORT; - break; - - default: - pr_debug("urb status=%d, transfer flags=0x%x\n", - urb->status, urb->transfer_flags); - wlandev->netdev->stats.rx_errors++; - action = RESUBMIT; - break; - } - - /* Save values from the RX URB before reposting overwrites it. */ - urb_status = urb->status; - usbin = (union hfa384x_usbin *)urb->transfer_buffer; - - if (action != ABORT) { - /* Repost the RX URB */ - result = submit_rx_urb(hw, GFP_ATOMIC); - - if (result != 0) { - netdev_err(hw->wlandev->netdev, - "Fatal, failed to resubmit rx_urb. error=%d\n", - result); - } - } - - /* Handle any USB-IN packet */ - /* Note: the check of the sw_support field, the type field doesn't - * have bit 12 set like the docs suggest. - */ - type = le16_to_cpu(usbin->type); - if (HFA384x_USB_ISRXFRM(type)) { - if (action == HANDLE) { - if (usbin->txfrm.desc.sw_support == 0x0123) { - hfa384x_usbin_txcompl(wlandev, usbin); - } else { - skb_put(skb, sizeof(*usbin)); - hfa384x_usbin_rx(wlandev, skb); - skb = NULL; - } - } - goto exit; - } - if (HFA384x_USB_ISTXFRM(type)) { - if (action == HANDLE) - hfa384x_usbin_txcompl(wlandev, usbin); - goto exit; - } - switch (type) { - case HFA384x_USB_INFOFRM: - if (action == ABORT) - goto exit; - if (action == HANDLE) - hfa384x_usbin_info(wlandev, usbin); - break; - - case HFA384x_USB_CMDRESP: - case HFA384x_USB_WRIDRESP: - case HFA384x_USB_RRIDRESP: - case HFA384x_USB_WMEMRESP: - case HFA384x_USB_RMEMRESP: - /* ALWAYS, ALWAYS, ALWAYS handle this CTLX!!!! */ - hfa384x_usbin_ctlx(hw, usbin, urb_status); - break; - - case HFA384x_USB_BUFAVAIL: - pr_debug("Received BUFAVAIL packet, frmlen=%d\n", - usbin->bufavail.frmlen); - break; - - case HFA384x_USB_ERROR: - pr_debug("Received USB_ERROR packet, errortype=%d\n", - usbin->usberror.errortype); - break; - - default: - pr_debug("Unrecognized USBIN packet, type=%x, status=%d\n", - usbin->type, urb_status); - break; - } /* switch */ - -exit: - - if (skb) - dev_kfree_skb(skb); -} - -/*---------------------------------------------------------------- - * hfa384x_usbin_ctlx - * - * We've received a URB containing a Prism2 "response" message. - * This message needs to be matched up with a CTLX on the active - * queue and our state updated accordingly. - * - * Arguments: - * hw ptr to struct hfa384x - * usbin ptr to USB IN packet - * urb_status status of this Bulk-In URB - * - * Returns: - * nothing - * - * Side effects: - * - * Call context: - * interrupt - *---------------------------------------------------------------- - */ -static void hfa384x_usbin_ctlx(struct hfa384x *hw, union hfa384x_usbin *usbin, - int urb_status) -{ - struct hfa384x_usbctlx *ctlx; - int run_queue = 0; - unsigned long flags; - -retry: - spin_lock_irqsave(&hw->ctlxq.lock, flags); - - /* There can be only one CTLX on the active queue - * at any one time, and this is the CTLX that the - * timers are waiting for. - */ - if (list_empty(&hw->ctlxq.active)) - goto unlock; - - /* Remove the "response timeout". It's possible that - * we are already too late, and that the timeout is - * already running. And that's just too bad for us, - * because we could lose our CTLX from the active - * queue here ... - */ - if (del_timer(&hw->resptimer) == 0) { - if (hw->resp_timer_done == 0) { - spin_unlock_irqrestore(&hw->ctlxq.lock, flags); - goto retry; - } - } else { - hw->resp_timer_done = 1; - } - - ctlx = get_active_ctlx(hw); - - if (urb_status != 0) { - /* - * Bad CTLX, so get rid of it. But we only - * remove it from the active queue if we're no - * longer expecting the OUT URB to complete. - */ - if (unlocked_usbctlx_cancel_async(hw, ctlx) == 0) - run_queue = 1; - } else { - const __le16 intype = (usbin->type & ~cpu_to_le16(0x8000)); - - /* - * Check that our message is what we're expecting ... - */ - if (ctlx->outbuf.type != intype) { - netdev_warn(hw->wlandev->netdev, - "Expected IN[%d], received IN[%d] - ignored.\n", - le16_to_cpu(ctlx->outbuf.type), - le16_to_cpu(intype)); - goto unlock; - } - - /* This URB has succeeded, so grab the data ... */ - memcpy(&ctlx->inbuf, usbin, sizeof(ctlx->inbuf)); - - switch (ctlx->state) { - case CTLX_REQ_SUBMITTED: - /* - * We have received our response URB before - * our request has been acknowledged. Odd, - * but our OUT URB is still alive... - */ - pr_debug("Causality violation: please reboot Universe\n"); - ctlx->state = CTLX_RESP_COMPLETE; - break; - - case CTLX_REQ_COMPLETE: - /* - * This is the usual path: our request - * has already been acknowledged, and - * now we have received the reply too. - */ - ctlx->state = CTLX_COMPLETE; - unlocked_usbctlx_complete(hw, ctlx); - run_queue = 1; - break; - - default: - /* - * Throw this CTLX away ... - */ - netdev_err(hw->wlandev->netdev, - "Matched IN URB, CTLX[%d] in invalid state(%s). Discarded.\n", - le16_to_cpu(ctlx->outbuf.type), - ctlxstr(ctlx->state)); - if (unlocked_usbctlx_cancel_async(hw, ctlx) == 0) - run_queue = 1; - break; - } /* switch */ - } - -unlock: - spin_unlock_irqrestore(&hw->ctlxq.lock, flags); - - if (run_queue) - hfa384x_usbctlxq_run(hw); -} - -/*---------------------------------------------------------------- - * hfa384x_usbin_txcompl - * - * At this point we have the results of a previous transmit. - * - * Arguments: - * wlandev wlan device - * usbin ptr to the usb transfer buffer - * - * Returns: - * nothing - * - * Side effects: - * - * Call context: - * interrupt - *---------------------------------------------------------------- - */ -static void hfa384x_usbin_txcompl(struct wlandevice *wlandev, - union hfa384x_usbin *usbin) -{ - u16 status; - - status = le16_to_cpu(usbin->type); /* yeah I know it says type... */ - - /* Was there an error? */ - if (HFA384x_TXSTATUS_ISERROR(status)) - netdev_dbg(wlandev->netdev, "TxExc status=0x%x.\n", status); - else - prism2sta_ev_tx(wlandev, status); -} - -/*---------------------------------------------------------------- - * hfa384x_usbin_rx - * - * At this point we have a successful received a rx frame packet. - * - * Arguments: - * wlandev wlan device - * usbin ptr to the usb transfer buffer - * - * Returns: - * nothing - * - * Side effects: - * - * Call context: - * interrupt - *---------------------------------------------------------------- - */ -static void hfa384x_usbin_rx(struct wlandevice *wlandev, struct sk_buff *skb) -{ - union hfa384x_usbin *usbin = (union hfa384x_usbin *)skb->data; - struct hfa384x *hw = wlandev->priv; - int hdrlen; - struct p80211_rxmeta *rxmeta; - u16 data_len; - u16 fc; - u16 status; - - /* Byte order convert once up front. */ - le16_to_cpus(&usbin->rxfrm.desc.status); - le32_to_cpus(&usbin->rxfrm.desc.time); - - /* Now handle frame based on port# */ - status = HFA384x_RXSTATUS_MACPORT_GET(usbin->rxfrm.desc.status); - - switch (status) { - case 0: - fc = le16_to_cpu(usbin->rxfrm.desc.hdr.frame_control); - - /* If exclude and we receive an unencrypted, drop it */ - if ((wlandev->hostwep & HOSTWEP_EXCLUDEUNENCRYPTED) && - !WLAN_GET_FC_ISWEP(fc)) { - break; - } - - data_len = le16_to_cpu(usbin->rxfrm.desc.data_len); - - /* How much header data do we have? */ - hdrlen = p80211_headerlen(fc); - - /* Pull off the descriptor */ - skb_pull(skb, sizeof(struct hfa384x_rx_frame)); - - /* Now shunt the header block up against the data block - * with an "overlapping" copy - */ - memmove(skb_push(skb, hdrlen), - &usbin->rxfrm.desc.hdr, hdrlen); - - skb->dev = wlandev->netdev; - - /* And set the frame length properly */ - skb_trim(skb, data_len + hdrlen); - - /* The prism2 series does not return the CRC */ - memset(skb_put(skb, WLAN_CRC_LEN), 0xff, WLAN_CRC_LEN); - - skb_reset_mac_header(skb); - - /* Attach the rxmeta, set some stuff */ - p80211skb_rxmeta_attach(wlandev, skb); - rxmeta = p80211skb_rxmeta(skb); - rxmeta->mactime = usbin->rxfrm.desc.time; - rxmeta->rxrate = usbin->rxfrm.desc.rate; - rxmeta->signal = usbin->rxfrm.desc.signal - hw->dbmadjust; - rxmeta->noise = usbin->rxfrm.desc.silence - hw->dbmadjust; - - p80211netdev_rx(wlandev, skb); - - break; - - case 7: - if (!HFA384x_RXSTATUS_ISFCSERR(usbin->rxfrm.desc.status)) { - /* Copy to wlansnif skb */ - hfa384x_int_rxmonitor(wlandev, &usbin->rxfrm); - dev_kfree_skb(skb); - } else { - pr_debug("Received monitor frame: FCSerr set\n"); - } - break; - - default: - netdev_warn(hw->wlandev->netdev, - "Received frame on unsupported port=%d\n", - status); - break; - } -} - -/*---------------------------------------------------------------- - * hfa384x_int_rxmonitor - * - * Helper function for int_rx. Handles monitor frames. - * Note that this function allocates space for the FCS and sets it - * to 0xffffffff. The hfa384x doesn't give us the FCS value but the - * higher layers expect it. 0xffffffff is used as a flag to indicate - * the FCS is bogus. - * - * Arguments: - * wlandev wlan device structure - * rxfrm rx descriptor read from card in int_rx - * - * Returns: - * nothing - * - * Side effects: - * Allocates an skb and passes it up via the PF_PACKET interface. - * Call context: - * interrupt - *---------------------------------------------------------------- - */ -static void hfa384x_int_rxmonitor(struct wlandevice *wlandev, - struct hfa384x_usb_rxfrm *rxfrm) -{ - struct hfa384x_rx_frame *rxdesc = &rxfrm->desc; - unsigned int hdrlen = 0; - unsigned int datalen = 0; - unsigned int skblen = 0; - u8 *datap; - u16 fc; - struct sk_buff *skb; - struct hfa384x *hw = wlandev->priv; - - /* Remember the status, time, and data_len fields are in host order */ - /* Figure out how big the frame is */ - fc = le16_to_cpu(rxdesc->hdr.frame_control); - hdrlen = p80211_headerlen(fc); - datalen = le16_to_cpu(rxdesc->data_len); - - /* Allocate an ind message+framesize skb */ - skblen = sizeof(struct p80211_caphdr) + hdrlen + datalen + WLAN_CRC_LEN; - - /* sanity check the length */ - if (skblen > - (sizeof(struct p80211_caphdr) + - WLAN_HDR_A4_LEN + WLAN_DATA_MAXLEN + WLAN_CRC_LEN)) { - pr_debug("overlen frm: len=%zd\n", - skblen - sizeof(struct p80211_caphdr)); - - return; - } - - skb = dev_alloc_skb(skblen); - if (!skb) - return; - - /* only prepend the prism header if in the right mode */ - if ((wlandev->netdev->type == ARPHRD_IEEE80211_PRISM) && - (hw->sniffhdr != 0)) { - struct p80211_caphdr *caphdr; - /* The NEW header format! */ - datap = skb_put(skb, sizeof(struct p80211_caphdr)); - caphdr = (struct p80211_caphdr *)datap; - - caphdr->version = htonl(P80211CAPTURE_VERSION); - caphdr->length = htonl(sizeof(struct p80211_caphdr)); - caphdr->mactime = __cpu_to_be64(rxdesc->time * 1000); - caphdr->hosttime = __cpu_to_be64(jiffies); - caphdr->phytype = htonl(4); /* dss_dot11_b */ - caphdr->channel = htonl(hw->sniff_channel); - caphdr->datarate = htonl(rxdesc->rate); - caphdr->antenna = htonl(0); /* unknown */ - caphdr->priority = htonl(0); /* unknown */ - caphdr->ssi_type = htonl(3); /* rssi_raw */ - caphdr->ssi_signal = htonl(rxdesc->signal); - caphdr->ssi_noise = htonl(rxdesc->silence); - caphdr->preamble = htonl(0); /* unknown */ - caphdr->encoding = htonl(1); /* cck */ - } - - /* Copy the 802.11 header to the skb - * (ctl frames may be less than a full header) - */ - skb_put_data(skb, &rxdesc->hdr.frame_control, hdrlen); - - /* If any, copy the data from the card to the skb */ - if (datalen > 0) { - datap = skb_put_data(skb, rxfrm->data, datalen); - - /* check for unencrypted stuff if WEP bit set. */ - if (*(datap - hdrlen + 1) & 0x40) /* wep set */ - if ((*(datap) == 0xaa) && (*(datap + 1) == 0xaa)) - /* clear wep; it's the 802.2 header! */ - *(datap - hdrlen + 1) &= 0xbf; - } - - if (hw->sniff_fcs) { - /* Set the FCS */ - datap = skb_put(skb, WLAN_CRC_LEN); - memset(datap, 0xff, WLAN_CRC_LEN); - } - - /* pass it back up */ - p80211netdev_rx(wlandev, skb); -} - -/*---------------------------------------------------------------- - * hfa384x_usbin_info - * - * At this point we have a successful received a Prism2 info frame. - * - * Arguments: - * wlandev wlan device - * usbin ptr to the usb transfer buffer - * - * Returns: - * nothing - * - * Side effects: - * - * Call context: - * interrupt - *---------------------------------------------------------------- - */ -static void hfa384x_usbin_info(struct wlandevice *wlandev, - union hfa384x_usbin *usbin) -{ - le16_to_cpus(&usbin->infofrm.info.framelen); - prism2sta_ev_info(wlandev, &usbin->infofrm.info); -} - -/*---------------------------------------------------------------- - * hfa384x_usbout_callback - * - * Callback for URBs on the BULKOUT endpoint. - * - * Arguments: - * urb ptr to the completed urb - * - * Returns: - * nothing - * - * Side effects: - * - * Call context: - * interrupt - *---------------------------------------------------------------- - */ -static void hfa384x_usbout_callback(struct urb *urb) -{ - struct wlandevice *wlandev = urb->context; - -#ifdef DEBUG_USB - dbprint_urb(urb); -#endif - - if (wlandev && wlandev->netdev) { - switch (urb->status) { - case 0: - prism2sta_ev_alloc(wlandev); - break; - - case -EPIPE: { - struct hfa384x *hw = wlandev->priv; - - netdev_warn(hw->wlandev->netdev, - "%s tx pipe stalled: requesting reset\n", - wlandev->netdev->name); - if (!test_and_set_bit(WORK_TX_HALT, &hw->usb_flags)) - schedule_work(&hw->usb_work); - wlandev->netdev->stats.tx_errors++; - break; - } - - case -EPROTO: - case -ETIMEDOUT: - case -EILSEQ: { - struct hfa384x *hw = wlandev->priv; - - if (!test_and_set_bit(THROTTLE_TX, &hw->usb_flags) && - !timer_pending(&hw->throttle)) { - mod_timer(&hw->throttle, - jiffies + THROTTLE_JIFFIES); - } - wlandev->netdev->stats.tx_errors++; - netif_stop_queue(wlandev->netdev); - break; - } - - case -ENOENT: - case -ESHUTDOWN: - /* Ignorable errors */ - break; - - default: - netdev_info(wlandev->netdev, "unknown urb->status=%d\n", - urb->status); - wlandev->netdev->stats.tx_errors++; - break; - } /* switch */ - } -} - -/*---------------------------------------------------------------- - * hfa384x_ctlxout_callback - * - * Callback for control data on the BULKOUT endpoint. - * - * Arguments: - * urb ptr to the completed urb - * - * Returns: - * nothing - * - * Side effects: - * - * Call context: - * interrupt - *---------------------------------------------------------------- - */ -static void hfa384x_ctlxout_callback(struct urb *urb) -{ - struct hfa384x *hw = urb->context; - int delete_resptimer = 0; - int timer_ok = 1; - int run_queue = 0; - struct hfa384x_usbctlx *ctlx; - unsigned long flags; - - pr_debug("urb->status=%d\n", urb->status); -#ifdef DEBUG_USB - dbprint_urb(urb); -#endif - if ((urb->status == -ESHUTDOWN) || - (urb->status == -ENODEV) || !hw) - return; - -retry: - spin_lock_irqsave(&hw->ctlxq.lock, flags); - - /* - * Only one CTLX at a time on the "active" list, and - * none at all if we are unplugged. However, we can - * rely on the disconnect function to clean everything - * up if someone unplugged the adapter. - */ - if (list_empty(&hw->ctlxq.active)) { - spin_unlock_irqrestore(&hw->ctlxq.lock, flags); - return; - } - - /* - * Having something on the "active" queue means - * that we have timers to worry about ... - */ - if (del_timer(&hw->reqtimer) == 0) { - if (hw->req_timer_done == 0) { - /* - * This timer was actually running while we - * were trying to delete it. Let it terminate - * gracefully instead. - */ - spin_unlock_irqrestore(&hw->ctlxq.lock, flags); - goto retry; - } - } else { - hw->req_timer_done = 1; - } - - ctlx = get_active_ctlx(hw); - - if (urb->status == 0) { - /* Request portion of a CTLX is successful */ - switch (ctlx->state) { - case CTLX_REQ_SUBMITTED: - /* This OUT-ACK received before IN */ - ctlx->state = CTLX_REQ_COMPLETE; - break; - - case CTLX_RESP_COMPLETE: - /* IN already received before this OUT-ACK, - * so this command must now be complete. - */ - ctlx->state = CTLX_COMPLETE; - unlocked_usbctlx_complete(hw, ctlx); - run_queue = 1; - break; - - default: - /* This is NOT a valid CTLX "success" state! */ - netdev_err(hw->wlandev->netdev, - "Illegal CTLX[%d] success state(%s, %d) in OUT URB\n", - le16_to_cpu(ctlx->outbuf.type), - ctlxstr(ctlx->state), urb->status); - break; - } /* switch */ - } else { - /* If the pipe has stalled then we need to reset it */ - if ((urb->status == -EPIPE) && - !test_and_set_bit(WORK_TX_HALT, &hw->usb_flags)) { - netdev_warn(hw->wlandev->netdev, - "%s tx pipe stalled: requesting reset\n", - hw->wlandev->netdev->name); - schedule_work(&hw->usb_work); - } - - /* If someone cancels the OUT URB then its status - * should be either -ECONNRESET or -ENOENT. - */ - ctlx->state = CTLX_REQ_FAILED; - unlocked_usbctlx_complete(hw, ctlx); - delete_resptimer = 1; - run_queue = 1; - } - -delresp: - if (delete_resptimer) { - timer_ok = del_timer(&hw->resptimer); - if (timer_ok != 0) - hw->resp_timer_done = 1; - } - - spin_unlock_irqrestore(&hw->ctlxq.lock, flags); - - if (!timer_ok && (hw->resp_timer_done == 0)) { - spin_lock_irqsave(&hw->ctlxq.lock, flags); - goto delresp; - } - - if (run_queue) - hfa384x_usbctlxq_run(hw); -} - -/*---------------------------------------------------------------- - * hfa384x_usbctlx_reqtimerfn - * - * Timer response function for CTLX request timeouts. If this - * function is called, it means that the callback for the OUT - * URB containing a Prism2.x XXX_Request was never called. - * - * Arguments: - * data a ptr to the struct hfa384x - * - * Returns: - * nothing - * - * Side effects: - * - * Call context: - * interrupt - *---------------------------------------------------------------- - */ -static void hfa384x_usbctlx_reqtimerfn(struct timer_list *t) -{ - struct hfa384x *hw = from_timer(hw, t, reqtimer); - unsigned long flags; - - spin_lock_irqsave(&hw->ctlxq.lock, flags); - - hw->req_timer_done = 1; - - /* Removing the hardware automatically empties - * the active list ... - */ - if (!list_empty(&hw->ctlxq.active)) { - /* - * We must ensure that our URB is removed from - * the system, if it hasn't already expired. - */ - hw->ctlx_urb.transfer_flags |= URB_ASYNC_UNLINK; - if (usb_unlink_urb(&hw->ctlx_urb) == -EINPROGRESS) { - struct hfa384x_usbctlx *ctlx = get_active_ctlx(hw); - - ctlx->state = CTLX_REQ_FAILED; - - /* This URB was active, but has now been - * cancelled. It will now have a status of - * -ECONNRESET in the callback function. - * - * We are cancelling this CTLX, so we're - * not going to need to wait for a response. - * The URB's callback function will check - * that this timer is truly dead. - */ - if (del_timer(&hw->resptimer) != 0) - hw->resp_timer_done = 1; - } - } - - spin_unlock_irqrestore(&hw->ctlxq.lock, flags); -} - -/*---------------------------------------------------------------- - * hfa384x_usbctlx_resptimerfn - * - * Timer response function for CTLX response timeouts. If this - * function is called, it means that the callback for the IN - * URB containing a Prism2.x XXX_Response was never called. - * - * Arguments: - * data a ptr to the struct hfa384x - * - * Returns: - * nothing - * - * Side effects: - * - * Call context: - * interrupt - *---------------------------------------------------------------- - */ -static void hfa384x_usbctlx_resptimerfn(struct timer_list *t) -{ - struct hfa384x *hw = from_timer(hw, t, resptimer); - unsigned long flags; - - spin_lock_irqsave(&hw->ctlxq.lock, flags); - - hw->resp_timer_done = 1; - - /* The active list will be empty if the - * adapter has been unplugged ... - */ - if (!list_empty(&hw->ctlxq.active)) { - struct hfa384x_usbctlx *ctlx = get_active_ctlx(hw); - - if (unlocked_usbctlx_cancel_async(hw, ctlx) == 0) { - spin_unlock_irqrestore(&hw->ctlxq.lock, flags); - hfa384x_usbctlxq_run(hw); - return; - } - } - spin_unlock_irqrestore(&hw->ctlxq.lock, flags); -} - -/*---------------------------------------------------------------- - * hfa384x_usb_throttlefn - * - * - * Arguments: - * data ptr to hw - * - * Returns: - * Nothing - * - * Side effects: - * - * Call context: - * Interrupt - *---------------------------------------------------------------- - */ -static void hfa384x_usb_throttlefn(struct timer_list *t) -{ - struct hfa384x *hw = from_timer(hw, t, throttle); - unsigned long flags; - - spin_lock_irqsave(&hw->ctlxq.lock, flags); - - pr_debug("flags=0x%lx\n", hw->usb_flags); - if (!hw->wlandev->hwremoved) { - bool rx_throttle = test_and_clear_bit(THROTTLE_RX, &hw->usb_flags) && - !test_and_set_bit(WORK_RX_RESUME, &hw->usb_flags); - bool tx_throttle = test_and_clear_bit(THROTTLE_TX, &hw->usb_flags) && - !test_and_set_bit(WORK_TX_RESUME, &hw->usb_flags); - /* - * We need to check BOTH the RX and the TX throttle controls, - * so we use the bitwise OR instead of the logical OR. - */ - if (rx_throttle | tx_throttle) - schedule_work(&hw->usb_work); - } - - spin_unlock_irqrestore(&hw->ctlxq.lock, flags); -} - -/*---------------------------------------------------------------- - * hfa384x_usbctlx_submit - * - * Called from the doxxx functions to submit a CTLX to the queue - * - * Arguments: - * hw ptr to the hw struct - * ctlx ctlx structure to enqueue - * - * Returns: - * -ENODEV if the adapter is unplugged - * 0 - * - * Side effects: - * - * Call context: - * process or interrupt - *---------------------------------------------------------------- - */ -static int hfa384x_usbctlx_submit(struct hfa384x *hw, - struct hfa384x_usbctlx *ctlx) -{ - unsigned long flags; - - spin_lock_irqsave(&hw->ctlxq.lock, flags); - - if (hw->wlandev->hwremoved) { - spin_unlock_irqrestore(&hw->ctlxq.lock, flags); - return -ENODEV; - } - - ctlx->state = CTLX_PENDING; - list_add_tail(&ctlx->list, &hw->ctlxq.pending); - spin_unlock_irqrestore(&hw->ctlxq.lock, flags); - hfa384x_usbctlxq_run(hw); - - return 0; -} - -/*---------------------------------------------------------------- - * hfa384x_isgood_pdrcore - * - * Quick check of PDR codes. - * - * Arguments: - * pdrcode PDR code number (host order) - * - * Returns: - * zero not good. - * one is good. - * - * Side effects: - * - * Call context: - *---------------------------------------------------------------- - */ -static int hfa384x_isgood_pdrcode(u16 pdrcode) -{ - switch (pdrcode) { - case HFA384x_PDR_END_OF_PDA: - case HFA384x_PDR_PCB_PARTNUM: - case HFA384x_PDR_PDAVER: - case HFA384x_PDR_NIC_SERIAL: - case HFA384x_PDR_MKK_MEASUREMENTS: - case HFA384x_PDR_NIC_RAMSIZE: - case HFA384x_PDR_MFISUPRANGE: - case HFA384x_PDR_CFISUPRANGE: - case HFA384x_PDR_NICID: - case HFA384x_PDR_MAC_ADDRESS: - case HFA384x_PDR_REGDOMAIN: - case HFA384x_PDR_ALLOWED_CHANNEL: - case HFA384x_PDR_DEFAULT_CHANNEL: - case HFA384x_PDR_TEMPTYPE: - case HFA384x_PDR_IFR_SETTING: - case HFA384x_PDR_RFR_SETTING: - case HFA384x_PDR_HFA3861_BASELINE: - case HFA384x_PDR_HFA3861_SHADOW: - case HFA384x_PDR_HFA3861_IFRF: - case HFA384x_PDR_HFA3861_CHCALSP: - case HFA384x_PDR_HFA3861_CHCALI: - case HFA384x_PDR_3842_NIC_CONFIG: - case HFA384x_PDR_USB_ID: - case HFA384x_PDR_PCI_ID: - case HFA384x_PDR_PCI_IFCONF: - case HFA384x_PDR_PCI_PMCONF: - case HFA384x_PDR_RFENRGY: - case HFA384x_PDR_HFA3861_MANF_TESTSP: - case HFA384x_PDR_HFA3861_MANF_TESTI: - /* code is OK */ - return 1; - default: - if (pdrcode < 0x1000) { - /* code is OK, but we don't know exactly what it is */ - pr_debug("Encountered unknown PDR#=0x%04x, assuming it's ok.\n", - pdrcode); - return 1; - } - break; - } - /* bad code */ - pr_debug("Encountered unknown PDR#=0x%04x, (>=0x1000), assuming it's bad.\n", - pdrcode); - return 0; -} diff --git a/drivers/staging/wlan-ng/p80211conv.c b/drivers/staging/wlan-ng/p80211conv.c deleted file mode 100644 index 7401a6cacb7f..000000000000 --- a/drivers/staging/wlan-ng/p80211conv.c +++ /dev/null @@ -1,643 +0,0 @@ -// SPDX-License-Identifier: (GPL-2.0 OR MPL-1.1) -/* - * - * Ether/802.11 conversions and packet buffer routines - * - * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. - * -------------------------------------------------------------------- - * - * linux-wlan - * - * -------------------------------------------------------------------- - * - * Inquiries regarding the linux-wlan Open Source project can be - * made directly to: - * - * AbsoluteValue Systems Inc. - * info@linux-wlan.com - * http://www.linux-wlan.com - * - * -------------------------------------------------------------------- - * - * Portions of the development of this software were funded by - * Intersil Corporation as part of PRISM(R) chipset product development. - * - * -------------------------------------------------------------------- - * - * This file defines the functions that perform Ethernet to/from - * 802.11 frame conversions. - * - * -------------------------------------------------------------------- - * - *================================================================ - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "p80211types.h" -#include "p80211hdr.h" -#include "p80211conv.h" -#include "p80211mgmt.h" -#include "p80211msg.h" -#include "p80211netdev.h" -#include "p80211ioctl.h" -#include "p80211req.h" - -static const u8 oui_rfc1042[] = { 0x00, 0x00, 0x00 }; -static const u8 oui_8021h[] = { 0x00, 0x00, 0xf8 }; - -/*---------------------------------------------------------------- - * p80211pb_ether_to_80211 - * - * Uses the contents of the ether frame and the etherconv setting - * to build the elements of the 802.11 frame. - * - * We don't actually set - * up the frame header here. That's the MAC's job. We're only handling - * conversion of DIXII or 802.3+LLC frames to something that works - * with 802.11. - * - * Note -- 802.11 header is NOT part of the skb. Likewise, the 802.11 - * FCS is also not present and will need to be added elsewhere. - * - * Arguments: - * ethconv Conversion type to perform - * skb skbuff containing the ether frame - * p80211_hdr 802.11 header - * - * Returns: - * 0 on success, non-zero otherwise - * - * Call context: - * May be called in interrupt or non-interrupt context - *---------------------------------------------------------------- - */ -int skb_ether_to_p80211(struct wlandevice *wlandev, u32 ethconv, - struct sk_buff *skb, struct p80211_hdr *p80211_hdr, - struct p80211_metawep *p80211_wep) -{ - __le16 fc; - u16 proto; - struct wlan_ethhdr e_hdr; - struct wlan_llc *e_llc; - struct wlan_snap *e_snap; - int rc; - - memcpy(&e_hdr, skb->data, sizeof(e_hdr)); - - if (skb->len <= 0) { - pr_debug("zero-length skb!\n"); - return 1; - } - - if (ethconv == WLAN_ETHCONV_ENCAP) { /* simplest case */ - pr_debug("ENCAP len: %d\n", skb->len); - /* here, we don't care what kind of ether frm. Just stick it */ - /* in the 80211 payload */ - /* which is to say, leave the skb alone. */ - } else { - /* step 1: classify ether frame, DIX or 802.3? */ - proto = ntohs(e_hdr.type); - if (proto <= ETH_DATA_LEN) { - pr_debug("802.3 len: %d\n", skb->len); - /* codes <= 1500 reserved for 802.3 lengths */ - /* it's 802.3, pass ether payload unchanged, */ - - /* trim off ethernet header */ - skb_pull(skb, ETH_HLEN); - - /* leave off any PAD octets. */ - skb_trim(skb, proto); - } else { - pr_debug("DIXII len: %d\n", skb->len); - /* it's DIXII, time for some conversion */ - - /* trim off ethernet header */ - skb_pull(skb, ETH_HLEN); - - /* tack on SNAP */ - e_snap = skb_push(skb, sizeof(struct wlan_snap)); - e_snap->type = htons(proto); - if (ethconv == WLAN_ETHCONV_8021h && - p80211_stt_findproto(proto)) { - memcpy(e_snap->oui, oui_8021h, - WLAN_IEEE_OUI_LEN); - } else { - memcpy(e_snap->oui, oui_rfc1042, - WLAN_IEEE_OUI_LEN); - } - - /* tack on llc */ - e_llc = skb_push(skb, sizeof(struct wlan_llc)); - e_llc->dsap = 0xAA; /* SNAP, see IEEE 802 */ - e_llc->ssap = 0xAA; - e_llc->ctl = 0x03; - } - } - - /* Set up the 802.11 header */ - /* It's a data frame */ - fc = cpu_to_le16(WLAN_SET_FC_FTYPE(WLAN_FTYPE_DATA) | - WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_DATAONLY)); - - switch (wlandev->macmode) { - case WLAN_MACMODE_IBSS_STA: - memcpy(p80211_hdr->address1, &e_hdr.daddr, ETH_ALEN); - memcpy(p80211_hdr->address2, wlandev->netdev->dev_addr, ETH_ALEN); - memcpy(p80211_hdr->address3, wlandev->bssid, ETH_ALEN); - break; - case WLAN_MACMODE_ESS_STA: - fc |= cpu_to_le16(WLAN_SET_FC_TODS(1)); - memcpy(p80211_hdr->address1, wlandev->bssid, ETH_ALEN); - memcpy(p80211_hdr->address2, wlandev->netdev->dev_addr, ETH_ALEN); - memcpy(p80211_hdr->address3, &e_hdr.daddr, ETH_ALEN); - break; - case WLAN_MACMODE_ESS_AP: - fc |= cpu_to_le16(WLAN_SET_FC_FROMDS(1)); - memcpy(p80211_hdr->address1, &e_hdr.daddr, ETH_ALEN); - memcpy(p80211_hdr->address2, wlandev->bssid, ETH_ALEN); - memcpy(p80211_hdr->address3, &e_hdr.saddr, ETH_ALEN); - break; - default: - netdev_err(wlandev->netdev, - "Error: Converting eth to wlan in unknown mode.\n"); - return 1; - } - - p80211_wep->data = NULL; - - if ((wlandev->hostwep & HOSTWEP_PRIVACYINVOKED) && - (wlandev->hostwep & HOSTWEP_ENCRYPT)) { - /* XXXX need to pick keynum other than default? */ - - p80211_wep->data = kmalloc(skb->len, GFP_ATOMIC); - if (!p80211_wep->data) - return -ENOMEM; - rc = wep_encrypt(wlandev, skb->data, p80211_wep->data, - skb->len, - wlandev->hostwep & HOSTWEP_DEFAULTKEY_MASK, - p80211_wep->iv, p80211_wep->icv); - if (rc) { - netdev_warn(wlandev->netdev, - "Host en-WEP failed, dropping frame (%d).\n", - rc); - kfree(p80211_wep->data); - return 2; - } - fc |= cpu_to_le16(WLAN_SET_FC_ISWEP(1)); - } - - /* skb->nh.raw = skb->data; */ - - p80211_hdr->frame_control = fc; - p80211_hdr->duration_id = 0; - p80211_hdr->sequence_control = 0; - - return 0; -} - -/* jkriegl: from orinoco, modified */ -static void orinoco_spy_gather(struct wlandevice *wlandev, char *mac, - struct p80211_rxmeta *rxmeta) -{ - int i; - - /* Gather wireless spy statistics: for each packet, compare the - * source address with out list, and if match, get the stats... - */ - - for (i = 0; i < wlandev->spy_number; i++) { - if (!memcmp(wlandev->spy_address[i], mac, ETH_ALEN)) { - wlandev->spy_stat[i].level = rxmeta->signal; - wlandev->spy_stat[i].noise = rxmeta->noise; - wlandev->spy_stat[i].qual = - (rxmeta->signal > - rxmeta->noise) ? (rxmeta->signal - - rxmeta->noise) : 0; - wlandev->spy_stat[i].updated = 0x7; - } - } -} - -/*---------------------------------------------------------------- - * p80211pb_80211_to_ether - * - * Uses the contents of a received 802.11 frame and the etherconv - * setting to build an ether frame. - * - * This function extracts the src and dest address from the 802.11 - * frame to use in the construction of the eth frame. - * - * Arguments: - * ethconv Conversion type to perform - * skb Packet buffer containing the 802.11 frame - * - * Returns: - * 0 on success, non-zero otherwise - * - * Call context: - * May be called in interrupt or non-interrupt context - *---------------------------------------------------------------- - */ -int skb_p80211_to_ether(struct wlandevice *wlandev, u32 ethconv, - struct sk_buff *skb) -{ - struct net_device *netdev = wlandev->netdev; - u16 fc; - unsigned int payload_length; - unsigned int payload_offset; - u8 daddr[ETH_ALEN]; - u8 saddr[ETH_ALEN]; - struct p80211_hdr *w_hdr; - struct wlan_ethhdr *e_hdr; - struct wlan_llc *e_llc; - struct wlan_snap *e_snap; - - int rc; - - payload_length = skb->len - WLAN_HDR_A3_LEN - WLAN_CRC_LEN; - payload_offset = WLAN_HDR_A3_LEN; - - w_hdr = (struct p80211_hdr *)skb->data; - - /* setup some vars for convenience */ - fc = le16_to_cpu(w_hdr->frame_control); - if ((WLAN_GET_FC_TODS(fc) == 0) && (WLAN_GET_FC_FROMDS(fc) == 0)) { - ether_addr_copy(daddr, w_hdr->address1); - ether_addr_copy(saddr, w_hdr->address2); - } else if ((WLAN_GET_FC_TODS(fc) == 0) && - (WLAN_GET_FC_FROMDS(fc) == 1)) { - ether_addr_copy(daddr, w_hdr->address1); - ether_addr_copy(saddr, w_hdr->address3); - } else if ((WLAN_GET_FC_TODS(fc) == 1) && - (WLAN_GET_FC_FROMDS(fc) == 0)) { - ether_addr_copy(daddr, w_hdr->address3); - ether_addr_copy(saddr, w_hdr->address2); - } else { - payload_offset = WLAN_HDR_A4_LEN; - if (payload_length < WLAN_HDR_A4_LEN - WLAN_HDR_A3_LEN) { - netdev_err(netdev, "A4 frame too short!\n"); - return 1; - } - payload_length -= (WLAN_HDR_A4_LEN - WLAN_HDR_A3_LEN); - ether_addr_copy(daddr, w_hdr->address3); - ether_addr_copy(saddr, w_hdr->address4); - } - - /* perform de-wep if necessary.. */ - if ((wlandev->hostwep & HOSTWEP_PRIVACYINVOKED) && - WLAN_GET_FC_ISWEP(fc) && - (wlandev->hostwep & HOSTWEP_DECRYPT)) { - if (payload_length <= 8) { - netdev_err(netdev, - "WEP frame too short (%u).\n", skb->len); - return 1; - } - rc = wep_decrypt(wlandev, skb->data + payload_offset + 4, - payload_length - 8, -1, - skb->data + payload_offset, - skb->data + payload_offset + - payload_length - 4); - if (rc) { - /* de-wep failed, drop skb. */ - netdev_dbg(netdev, "Host de-WEP failed, dropping frame (%d).\n", - rc); - wlandev->rx.decrypt_err++; - return 2; - } - - /* subtract the IV+ICV length off the payload */ - payload_length -= 8; - /* chop off the IV */ - skb_pull(skb, 4); - /* chop off the ICV. */ - skb_trim(skb, skb->len - 4); - - wlandev->rx.decrypt++; - } - - e_hdr = (struct wlan_ethhdr *)(skb->data + payload_offset); - - e_llc = (struct wlan_llc *)(skb->data + payload_offset); - e_snap = - (struct wlan_snap *)(skb->data + payload_offset + - sizeof(struct wlan_llc)); - - /* Test for the various encodings */ - if ((payload_length >= sizeof(struct wlan_ethhdr)) && - (e_llc->dsap != 0xaa || e_llc->ssap != 0xaa) && - ((!ether_addr_equal_unaligned(daddr, e_hdr->daddr)) || - (!ether_addr_equal_unaligned(saddr, e_hdr->saddr)))) { - netdev_dbg(netdev, "802.3 ENCAP len: %d\n", payload_length); - /* 802.3 Encapsulated */ - /* Test for an overlength frame */ - if (payload_length > (netdev->mtu + ETH_HLEN)) { - /* A bogus length ethfrm has been encap'd. */ - /* Is someone trying an oflow attack? */ - netdev_err(netdev, "ENCAP frame too large (%d > %d)\n", - payload_length, netdev->mtu + ETH_HLEN); - return 1; - } - - /* Chop off the 802.11 header. it's already sane. */ - skb_pull(skb, payload_offset); - /* chop off the 802.11 CRC */ - skb_trim(skb, skb->len - WLAN_CRC_LEN); - - } else if ((payload_length >= sizeof(struct wlan_llc) + - sizeof(struct wlan_snap)) && - (e_llc->dsap == 0xaa) && - (e_llc->ssap == 0xaa) && - (e_llc->ctl == 0x03) && - (((memcmp(e_snap->oui, oui_rfc1042, - WLAN_IEEE_OUI_LEN) == 0) && - (ethconv == WLAN_ETHCONV_8021h) && - (p80211_stt_findproto(be16_to_cpu(e_snap->type)))) || - (memcmp(e_snap->oui, oui_rfc1042, WLAN_IEEE_OUI_LEN) != - 0))) { - netdev_dbg(netdev, "SNAP+RFC1042 len: %d\n", payload_length); - /* it's a SNAP + RFC1042 frame && protocol is in STT */ - /* build 802.3 + RFC1042 */ - - /* Test for an overlength frame */ - if (payload_length > netdev->mtu) { - /* A bogus length ethfrm has been sent. */ - /* Is someone trying an oflow attack? */ - netdev_err(netdev, "SNAP frame too large (%d > %d)\n", - payload_length, netdev->mtu); - return 1; - } - - /* chop 802.11 header from skb. */ - skb_pull(skb, payload_offset); - - /* create 802.3 header at beginning of skb. */ - e_hdr = skb_push(skb, ETH_HLEN); - ether_addr_copy(e_hdr->daddr, daddr); - ether_addr_copy(e_hdr->saddr, saddr); - e_hdr->type = htons(payload_length); - - /* chop off the 802.11 CRC */ - skb_trim(skb, skb->len - WLAN_CRC_LEN); - - } else if ((payload_length >= sizeof(struct wlan_llc) + - sizeof(struct wlan_snap)) && - (e_llc->dsap == 0xaa) && - (e_llc->ssap == 0xaa) && - (e_llc->ctl == 0x03)) { - netdev_dbg(netdev, "802.1h/RFC1042 len: %d\n", payload_length); - /* it's an 802.1h frame || (an RFC1042 && protocol not in STT) - * build a DIXII + RFC894 - */ - - /* Test for an overlength frame */ - if ((payload_length - sizeof(struct wlan_llc) - - sizeof(struct wlan_snap)) - > netdev->mtu) { - /* A bogus length ethfrm has been sent. */ - /* Is someone trying an oflow attack? */ - netdev_err(netdev, "DIXII frame too large (%ld > %d)\n", - (long)(payload_length - - sizeof(struct wlan_llc) - - sizeof(struct wlan_snap)), netdev->mtu); - return 1; - } - - /* chop 802.11 header from skb. */ - skb_pull(skb, payload_offset); - - /* chop llc header from skb. */ - skb_pull(skb, sizeof(struct wlan_llc)); - - /* chop snap header from skb. */ - skb_pull(skb, sizeof(struct wlan_snap)); - - /* create 802.3 header at beginning of skb. */ - e_hdr = skb_push(skb, ETH_HLEN); - e_hdr->type = e_snap->type; - ether_addr_copy(e_hdr->daddr, daddr); - ether_addr_copy(e_hdr->saddr, saddr); - - /* chop off the 802.11 CRC */ - skb_trim(skb, skb->len - WLAN_CRC_LEN); - } else { - netdev_dbg(netdev, "NON-ENCAP len: %d\n", payload_length); - /* any NON-ENCAP */ - /* it's a generic 80211+LLC or IPX 'Raw 802.3' */ - /* build an 802.3 frame */ - /* allocate space and setup hostbuf */ - - /* Test for an overlength frame */ - if (payload_length > netdev->mtu) { - /* A bogus length ethfrm has been sent. */ - /* Is someone trying an oflow attack? */ - netdev_err(netdev, "OTHER frame too large (%d > %d)\n", - payload_length, netdev->mtu); - return 1; - } - - /* Chop off the 802.11 header. */ - skb_pull(skb, payload_offset); - - /* create 802.3 header at beginning of skb. */ - e_hdr = skb_push(skb, ETH_HLEN); - ether_addr_copy(e_hdr->daddr, daddr); - ether_addr_copy(e_hdr->saddr, saddr); - e_hdr->type = htons(payload_length); - - /* chop off the 802.11 CRC */ - skb_trim(skb, skb->len - WLAN_CRC_LEN); - } - - /* - * Note that eth_type_trans() expects an skb w/ skb->data pointing - * at the MAC header, it then sets the following skb members: - * skb->mac_header, - * skb->data, and - * skb->pkt_type. - * It then _returns_ the value that _we're_ supposed to stuff in - * skb->protocol. This is nuts. - */ - skb->protocol = eth_type_trans(skb, netdev); - - /* jkriegl: process signal and noise as set in hfa384x_int_rx() */ - /* jkriegl: only process signal/noise if requested by iwspy */ - if (wlandev->spy_number) - orinoco_spy_gather(wlandev, eth_hdr(skb)->h_source, - p80211skb_rxmeta(skb)); - - /* Free the metadata */ - p80211skb_rxmeta_detach(skb); - - return 0; -} - -/*---------------------------------------------------------------- - * p80211_stt_findproto - * - * Searches the 802.1h Selective Translation Table for a given - * protocol. - * - * Arguments: - * proto protocol number (in host order) to search for. - * - * Returns: - * 1 - if the table is empty or a match is found. - * 0 - if the table is non-empty and a match is not found. - * - * Call context: - * May be called in interrupt or non-interrupt context - *---------------------------------------------------------------- - */ -int p80211_stt_findproto(u16 proto) -{ - /* Always return found for now. This is the behavior used by the */ - /* Zoom Win95 driver when 802.1h mode is selected */ - /* TODO: If necessary, add an actual search we'll probably - * need this to match the CMAC's way of doing things. - * Need to do some testing to confirm. - */ - - if (proto == ETH_P_AARP) /* APPLETALK */ - return 1; - - return 0; -} - -/*---------------------------------------------------------------- - * p80211skb_rxmeta_detach - * - * Disconnects the frmmeta and rxmeta from an skb. - * - * Arguments: - * wlandev The wlandev this skb belongs to. - * skb The skb we're attaching to. - * - * Returns: - * 0 on success, non-zero otherwise - * - * Call context: - * May be called in interrupt or non-interrupt context - *---------------------------------------------------------------- - */ -void p80211skb_rxmeta_detach(struct sk_buff *skb) -{ - struct p80211_rxmeta *rxmeta; - struct p80211_frmmeta *frmmeta; - - /* Sanity checks */ - if (!skb) { /* bad skb */ - pr_debug("Called w/ null skb.\n"); - return; - } - frmmeta = p80211skb_frmmeta(skb); - if (!frmmeta) { /* no magic */ - pr_debug("Called w/ bad frmmeta magic.\n"); - return; - } - rxmeta = frmmeta->rx; - if (!rxmeta) { /* bad meta ptr */ - pr_debug("Called w/ bad rxmeta ptr.\n"); - return; - } - - /* Free rxmeta */ - kfree(rxmeta); - - /* Clear skb->cb */ - memset(skb->cb, 0, sizeof(skb->cb)); -} - -/*---------------------------------------------------------------- - * p80211skb_rxmeta_attach - * - * Allocates a p80211rxmeta structure, initializes it, and attaches - * it to an skb. - * - * Arguments: - * wlandev The wlandev this skb belongs to. - * skb The skb we're attaching to. - * - * Returns: - * 0 on success, non-zero otherwise - * - * Call context: - * May be called in interrupt or non-interrupt context - *---------------------------------------------------------------- - */ -int p80211skb_rxmeta_attach(struct wlandevice *wlandev, struct sk_buff *skb) -{ - int result = 0; - struct p80211_rxmeta *rxmeta; - struct p80211_frmmeta *frmmeta; - - /* If these already have metadata, we error out! */ - if (p80211skb_rxmeta(skb)) { - netdev_err(wlandev->netdev, - "%s: RXmeta already attached!\n", wlandev->name); - result = 0; - goto exit; - } - - /* Allocate the rxmeta */ - rxmeta = kzalloc(sizeof(*rxmeta), GFP_ATOMIC); - - if (!rxmeta) { - result = 1; - goto exit; - } - - /* Initialize the rxmeta */ - rxmeta->wlandev = wlandev; - rxmeta->hosttime = jiffies; - - /* Overlay a frmmeta_t onto skb->cb */ - memset(skb->cb, 0, sizeof(struct p80211_frmmeta)); - frmmeta = (struct p80211_frmmeta *)(skb->cb); - frmmeta->magic = P80211_FRMMETA_MAGIC; - frmmeta->rx = rxmeta; -exit: - return result; -} - -/*---------------------------------------------------------------- - * p80211skb_free - * - * Frees an entire p80211skb by checking and freeing the meta struct - * and then freeing the skb. - * - * Arguments: - * wlandev The wlandev this skb belongs to. - * skb The skb we're attaching to. - * - * Returns: - * 0 on success, non-zero otherwise - * - * Call context: - * May be called in interrupt or non-interrupt context - *---------------------------------------------------------------- - */ -void p80211skb_free(struct wlandevice *wlandev, struct sk_buff *skb) -{ - struct p80211_frmmeta *meta; - - meta = p80211skb_frmmeta(skb); - if (meta && meta->rx) - p80211skb_rxmeta_detach(skb); - else - netdev_err(wlandev->netdev, - "Freeing an skb (%p) w/ no frmmeta.\n", skb); - dev_kfree_skb(skb); -} diff --git a/drivers/staging/wlan-ng/p80211conv.h b/drivers/staging/wlan-ng/p80211conv.h deleted file mode 100644 index 45234769f45d..000000000000 --- a/drivers/staging/wlan-ng/p80211conv.h +++ /dev/null @@ -1,141 +0,0 @@ -/* SPDX-License-Identifier: (GPL-2.0 OR MPL-1.1) */ -/* - * - * Ether/802.11 conversions and packet buffer routines - * - * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. - * -------------------------------------------------------------------- - * - * linux-wlan - * - * -------------------------------------------------------------------- - * - * Inquiries regarding the linux-wlan Open Source project can be - * made directly to: - * - * AbsoluteValue Systems Inc. - * info@linux-wlan.com - * http://www.linux-wlan.com - * - * -------------------------------------------------------------------- - * - * Portions of the development of this software were funded by - * Intersil Corporation as part of PRISM(R) chipset product development. - * - * -------------------------------------------------------------------- - * - * This file declares the functions, types and macros that perform - * Ethernet to/from 802.11 frame conversions. - * - * -------------------------------------------------------------------- - */ - -#ifndef _LINUX_P80211CONV_H -#define _LINUX_P80211CONV_H - -#define WLAN_IEEE_OUI_LEN 3 - -#define WLAN_ETHCONV_ENCAP 1 -#define WLAN_ETHCONV_8021h 3 - -#define P80211CAPTURE_VERSION 0x80211001 - -#define P80211_FRMMETA_MAGIC 0x802110 - -struct p80211_rxmeta { - struct wlandevice *wlandev; - - u64 mactime; /* Hi-rez MAC-supplied time value */ - u64 hosttime; /* Best-rez host supplied time value */ - - unsigned int rxrate; /* Receive data rate in 100kbps */ - unsigned int priority; /* 0-15, 0=contention, 6=CF */ - int signal; /* An SSI, see p80211netdev.h */ - int noise; /* An SSI, see p80211netdev.h */ - unsigned int channel; /* Receive channel (mostly for snifs) */ - unsigned int preamble; /* P80211ENUM_preambletype_* */ - unsigned int encoding; /* P80211ENUM_encoding_* */ - -}; - -struct p80211_frmmeta { - unsigned int magic; - struct p80211_rxmeta *rx; -}; - -void p80211skb_free(struct wlandevice *wlandev, struct sk_buff *skb); -int p80211skb_rxmeta_attach(struct wlandevice *wlandev, struct sk_buff *skb); -void p80211skb_rxmeta_detach(struct sk_buff *skb); - -static inline struct p80211_frmmeta *p80211skb_frmmeta(struct sk_buff *skb) -{ - struct p80211_frmmeta *frmmeta = (struct p80211_frmmeta *)skb->cb; - - return frmmeta->magic == P80211_FRMMETA_MAGIC ? frmmeta : NULL; -} - -static inline struct p80211_rxmeta *p80211skb_rxmeta(struct sk_buff *skb) -{ - struct p80211_frmmeta *frmmeta = p80211skb_frmmeta(skb); - - return frmmeta ? frmmeta->rx : NULL; -} - -/* - * Frame capture header. (See doc/capturefrm.txt) - */ -struct p80211_caphdr { - __be32 version; - __be32 length; - __be64 mactime; - __be64 hosttime; - __be32 phytype; - __be32 channel; - __be32 datarate; - __be32 antenna; - __be32 priority; - __be32 ssi_type; - __be32 ssi_signal; - __be32 ssi_noise; - __be32 preamble; - __be32 encoding; -}; - -struct p80211_metawep { - void *data; - u8 iv[4]; - u8 icv[4]; -}; - -/* local ether header type */ -struct wlan_ethhdr { - u8 daddr[ETH_ALEN]; - u8 saddr[ETH_ALEN]; - __be16 type; -} __packed; - -/* local llc header type */ -struct wlan_llc { - u8 dsap; - u8 ssap; - u8 ctl; -} __packed; - -/* local snap header type */ -struct wlan_snap { - u8 oui[WLAN_IEEE_OUI_LEN]; - __be16 type; -} __packed; - -/* Circular include trick */ -struct wlandevice; - -int skb_p80211_to_ether(struct wlandevice *wlandev, u32 ethconv, - struct sk_buff *skb); -int skb_ether_to_p80211(struct wlandevice *wlandev, u32 ethconv, - struct sk_buff *skb, struct p80211_hdr *p80211_hdr, - struct p80211_metawep *p80211_wep); - -int p80211_stt_findproto(u16 proto); - -#endif diff --git a/drivers/staging/wlan-ng/p80211hdr.h b/drivers/staging/wlan-ng/p80211hdr.h deleted file mode 100644 index 7ea1c8ec05ed..000000000000 --- a/drivers/staging/wlan-ng/p80211hdr.h +++ /dev/null @@ -1,189 +0,0 @@ -/* SPDX-License-Identifier: (GPL-2.0 OR MPL-1.1) */ -/* - * - * Macros, types, and functions for handling 802.11 MAC headers - * - * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. - * -------------------------------------------------------------------- - * - * linux-wlan - * - * -------------------------------------------------------------------- - * - * Inquiries regarding the linux-wlan Open Source project can be - * made directly to: - * - * AbsoluteValue Systems Inc. - * info@linux-wlan.com - * http://www.linux-wlan.com - * - * -------------------------------------------------------------------- - * - * Portions of the development of this software were funded by - * Intersil Corporation as part of PRISM(R) chipset product development. - * - * -------------------------------------------------------------------- - * - * This file declares the constants and types used in the interface - * between a wlan driver and the user mode utilities. - * - * Note: - * - Constant values are always in HOST byte order. To assign - * values to multi-byte fields they _must_ be converted to - * ieee byte order. To retrieve multi-byte values from incoming - * frames, they must be converted to host order. - * - * All functions declared here are implemented in p80211.c - * -------------------------------------------------------------------- - */ - -#ifndef _P80211HDR_H -#define _P80211HDR_H - -#include - -/*--- Sizes -----------------------------------------------*/ -#define WLAN_CRC_LEN 4 -#define WLAN_BSSID_LEN 6 -#define WLAN_HDR_A3_LEN 24 -#define WLAN_HDR_A4_LEN 30 -#define WLAN_SSID_MAXLEN 32 -#define WLAN_DATA_MAXLEN 2312 -#define WLAN_WEP_IV_LEN 4 -#define WLAN_WEP_ICV_LEN 4 - -/*--- Frame Control Field -------------------------------------*/ -/* Frame Types */ -#define WLAN_FTYPE_MGMT 0x00 -#define WLAN_FTYPE_CTL 0x01 -#define WLAN_FTYPE_DATA 0x02 - -/* Frame subtypes */ -/* Management */ -#define WLAN_FSTYPE_ASSOCREQ 0x00 -#define WLAN_FSTYPE_ASSOCRESP 0x01 -#define WLAN_FSTYPE_REASSOCREQ 0x02 -#define WLAN_FSTYPE_REASSOCRESP 0x03 -#define WLAN_FSTYPE_PROBEREQ 0x04 -#define WLAN_FSTYPE_PROBERESP 0x05 -#define WLAN_FSTYPE_BEACON 0x08 -#define WLAN_FSTYPE_ATIM 0x09 -#define WLAN_FSTYPE_DISASSOC 0x0a -#define WLAN_FSTYPE_AUTHEN 0x0b -#define WLAN_FSTYPE_DEAUTHEN 0x0c - -/* Control */ -#define WLAN_FSTYPE_BLOCKACKREQ 0x8 -#define WLAN_FSTYPE_BLOCKACK 0x9 -#define WLAN_FSTYPE_PSPOLL 0x0a -#define WLAN_FSTYPE_RTS 0x0b -#define WLAN_FSTYPE_CTS 0x0c -#define WLAN_FSTYPE_ACK 0x0d -#define WLAN_FSTYPE_CFEND 0x0e -#define WLAN_FSTYPE_CFENDCFACK 0x0f - -/* Data */ -#define WLAN_FSTYPE_DATAONLY 0x00 -#define WLAN_FSTYPE_DATA_CFACK 0x01 -#define WLAN_FSTYPE_DATA_CFPOLL 0x02 -#define WLAN_FSTYPE_DATA_CFACK_CFPOLL 0x03 -#define WLAN_FSTYPE_NULL 0x04 -#define WLAN_FSTYPE_CFACK 0x05 -#define WLAN_FSTYPE_CFPOLL 0x06 -#define WLAN_FSTYPE_CFACK_CFPOLL 0x07 - -/*--- FC Macros ----------------------------------------------*/ -/* Macros to get/set the bitfields of the Frame Control Field */ -/* GET_FC_??? - takes the host byte-order value of an FC */ -/* and retrieves the value of one of the */ -/* bitfields and moves that value so its lsb is */ -/* in bit 0. */ -/* SET_FC_??? - takes a host order value for one of the FC */ -/* bitfields and moves it to the proper bit */ -/* location for ORing into a host order FC. */ -/* To send the FC produced from SET_FC_???, */ -/* one must put the bytes in IEEE order. */ -/* e.g. */ -/* printf("the frame subtype is %x", */ -/* GET_FC_FTYPE( ieee2host( rx.fc ))) */ -/* */ -/* tx.fc = host2ieee( SET_FC_FTYPE(WLAN_FTYP_CTL) | */ -/* SET_FC_FSTYPE(WLAN_FSTYPE_RTS) ); */ -/*------------------------------------------------------------*/ - -#define WLAN_GET_FC_FTYPE(n) ((((u16)(n)) & GENMASK(3, 2)) >> 2) -#define WLAN_GET_FC_FSTYPE(n) ((((u16)(n)) & GENMASK(7, 4)) >> 4) -#define WLAN_GET_FC_TODS(n) ((((u16)(n)) & (BIT(8))) >> 8) -#define WLAN_GET_FC_FROMDS(n) ((((u16)(n)) & (BIT(9))) >> 9) -#define WLAN_GET_FC_ISWEP(n) ((((u16)(n)) & (BIT(14))) >> 14) - -#define WLAN_SET_FC_FTYPE(n) (((u16)(n)) << 2) -#define WLAN_SET_FC_FSTYPE(n) (((u16)(n)) << 4) -#define WLAN_SET_FC_TODS(n) (((u16)(n)) << 8) -#define WLAN_SET_FC_FROMDS(n) (((u16)(n)) << 9) -#define WLAN_SET_FC_ISWEP(n) (((u16)(n)) << 14) - -#define DOT11_RATE5_ISBASIC_GET(r) (((u8)(r)) & BIT(7)) - -/* Generic 802.11 Header types */ - -struct p80211_hdr { - __le16 frame_control; - u16 duration_id; - u8 address1[ETH_ALEN]; - u8 address2[ETH_ALEN]; - u8 address3[ETH_ALEN]; - u16 sequence_control; - u8 address4[ETH_ALEN]; -} __packed; - -/* Frame and header length macros */ - -static inline u16 wlan_ctl_framelen(u16 fstype) -{ - switch (fstype) { - case WLAN_FSTYPE_BLOCKACKREQ: - return 24; - case WLAN_FSTYPE_BLOCKACK: - return 152; - case WLAN_FSTYPE_PSPOLL: - case WLAN_FSTYPE_RTS: - case WLAN_FSTYPE_CFEND: - case WLAN_FSTYPE_CFENDCFACK: - return 20; - case WLAN_FSTYPE_CTS: - case WLAN_FSTYPE_ACK: - return 14; - default: - return 4; - } -} - -#define WLAN_FCS_LEN 4 - -/* ftcl in HOST order */ -static inline u16 p80211_headerlen(u16 fctl) -{ - u16 hdrlen = 0; - - switch (WLAN_GET_FC_FTYPE(fctl)) { - case WLAN_FTYPE_MGMT: - hdrlen = WLAN_HDR_A3_LEN; - break; - case WLAN_FTYPE_DATA: - hdrlen = WLAN_HDR_A3_LEN; - if (WLAN_GET_FC_TODS(fctl) && WLAN_GET_FC_FROMDS(fctl)) - hdrlen += ETH_ALEN; - break; - case WLAN_FTYPE_CTL: - hdrlen = wlan_ctl_framelen(WLAN_GET_FC_FSTYPE(fctl)) - - WLAN_FCS_LEN; - break; - default: - hdrlen = WLAN_HDR_A3_LEN; - } - - return hdrlen; -} - -#endif /* _P80211HDR_H */ diff --git a/drivers/staging/wlan-ng/p80211ioctl.h b/drivers/staging/wlan-ng/p80211ioctl.h deleted file mode 100644 index 176e327a45bc..000000000000 --- a/drivers/staging/wlan-ng/p80211ioctl.h +++ /dev/null @@ -1,69 +0,0 @@ -/* SPDX-License-Identifier: (GPL-2.0 OR MPL-1.1) */ -/* - * - * Declares constants and types for the p80211 ioctls - * - * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. - * -------------------------------------------------------------------- - * - * linux-wlan - * - * -------------------------------------------------------------------- - * - * Inquiries regarding the linux-wlan Open Source project can be - * made directly to: - * - * AbsoluteValue Systems Inc. - * info@linux-wlan.com - * http://www.linux-wlan.com - * - * -------------------------------------------------------------------- - * - * Portions of the development of this software were funded by - * Intersil Corporation as part of PRISM(R) chipset product development. - * - * -------------------------------------------------------------------- - * - * While this file is called 'ioctl' is purpose goes a little beyond - * that. This file defines the types and contants used to implement - * the p80211 request/confirm/indicate interfaces on Linux. The - * request/confirm interface is, in fact, normally implemented as an - * ioctl. The indicate interface on the other hand, is implemented - * using the Linux 'netlink' interface. - * - * The reason I say that request/confirm is 'normally' implemented - * via ioctl is that we're reserving the right to be able to send - * request commands via the netlink interface. This will be necessary - * if we ever need to send request messages when there aren't any - * wlan network devices present (i.e. sending a message that only p80211 - * cares about. - * -------------------------------------------------------------------- - */ - -#ifndef _P80211IOCTL_H -#define _P80211IOCTL_H - -/* p80211 ioctl "request" codes. See argument 2 of ioctl(2). */ - -#define P80211_IFTEST (SIOCDEVPRIVATE + 0) -#define P80211_IFREQ (SIOCDEVPRIVATE + 1) - -/*----------------------------------------------------------------*/ -/* Magic number, a quick test to see we're getting the desired struct */ - -#define P80211_IOCTL_MAGIC (0x4a2d464dUL) - -/*----------------------------------------------------------------*/ -/* A ptr to the following structure type is passed as the third */ -/* argument to the ioctl system call when issuing a request to */ -/* the p80211 module. */ - -struct p80211ioctl_req { - char name[WLAN_DEVNAMELEN_MAX]; - char __user *data; - u32 magic; - u16 len; - u32 result; -} __packed; - -#endif /* _P80211IOCTL_H */ diff --git a/drivers/staging/wlan-ng/p80211metadef.h b/drivers/staging/wlan-ng/p80211metadef.h deleted file mode 100644 index 1cbb4b67a9a6..000000000000 --- a/drivers/staging/wlan-ng/p80211metadef.h +++ /dev/null @@ -1,227 +0,0 @@ -/* SPDX-License-Identifier: (GPL-2.0 OR MPL-1.1) */ -/* -------------------------------------------------------------------- - * - * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. - * -------------------------------------------------------------------- - * - * linux-wlan - * - * -------------------------------------------------------------------- - * - * Inquiries regarding the linux-wlan Open Source project can be - * made directly to: - * - * AbsoluteValue Systems Inc. - * info@linux-wlan.com - * http://www.linux-wlan.com - * - * -------------------------------------------------------------------- - * - * Portions of the development of this software were funded by - * Intersil Corporation as part of PRISM(R) chipset product development. - * - * -------------------------------------------------------------------- - */ - -#ifndef _P80211MKMETADEF_H -#define _P80211MKMETADEF_H - -#define DIDMSG_DOT11REQ_MIBGET \ - (P80211DID_MKSECTION(1) | \ - P80211DID_MKGROUP(1)) -#define DIDMSG_DOT11REQ_MIBGET_MIBATTRIBUTE \ - (P80211DID_MKSECTION(1) | \ - P80211DID_MKGROUP(1) | \ - P80211DID_MKITEM(1) | 0x00000000) -#define DIDMSG_DOT11REQ_MIBGET_RESULTCODE \ - (P80211DID_MKSECTION(1) | \ - P80211DID_MKGROUP(1) | \ - P80211DID_MKITEM(2) | 0x00000000) -#define DIDMSG_DOT11REQ_MIBSET \ - (P80211DID_MKSECTION(1) | \ - P80211DID_MKGROUP(2)) -#define DIDMSG_DOT11REQ_MIBSET_MIBATTRIBUTE \ - (P80211DID_MKSECTION(1) | \ - P80211DID_MKGROUP(2) | \ - P80211DID_MKITEM(1) | 0x00000000) -#define DIDMSG_DOT11REQ_MIBSET_RESULTCODE \ - (P80211DID_MKSECTION(1) | \ - P80211DID_MKGROUP(2) | \ - P80211DID_MKITEM(2) | 0x00000000) -#define DIDMSG_DOT11REQ_SCAN \ - (P80211DID_MKSECTION(1) | \ - P80211DID_MKGROUP(4)) -#define DIDMSG_DOT11REQ_SCAN_RESULTS \ - (P80211DID_MKSECTION(1) | \ - P80211DID_MKGROUP(5)) -#define DIDMSG_DOT11REQ_START \ - (P80211DID_MKSECTION(1) | \ - P80211DID_MKGROUP(13)) -#define DIDMSG_DOT11IND_AUTHENTICATE \ - (P80211DID_MKSECTION(2) | \ - P80211DID_MKGROUP(1)) -#define DIDMSG_DOT11IND_ASSOCIATE \ - (P80211DID_MKSECTION(2) | \ - P80211DID_MKGROUP(3)) -#define DIDMSG_LNXREQ_IFSTATE \ - (P80211DID_MKSECTION(3) | \ - P80211DID_MKGROUP(1)) -#define DIDMSG_LNXREQ_WLANSNIFF \ - (P80211DID_MKSECTION(3) | \ - P80211DID_MKGROUP(2)) -#define DIDMSG_LNXREQ_HOSTWEP \ - (P80211DID_MKSECTION(3) | \ - P80211DID_MKGROUP(3)) -#define DIDMSG_LNXREQ_COMMSQUALITY \ - (P80211DID_MKSECTION(3) | \ - P80211DID_MKGROUP(4)) -#define DIDMSG_LNXREQ_AUTOJOIN \ - (P80211DID_MKSECTION(3) | \ - P80211DID_MKGROUP(5)) -#define DIDMSG_P2REQ_READPDA \ - (P80211DID_MKSECTION(5) | \ - P80211DID_MKGROUP(2)) -#define DIDMSG_P2REQ_READPDA_PDA \ - (P80211DID_MKSECTION(5) | \ - P80211DID_MKGROUP(2) | \ - P80211DID_MKITEM(1) | 0x00000000) -#define DIDMSG_P2REQ_READPDA_RESULTCODE \ - (P80211DID_MKSECTION(5) | \ - P80211DID_MKGROUP(2) | \ - P80211DID_MKITEM(2) | 0x00000000) -#define DIDMSG_P2REQ_RAMDL_STATE \ - (P80211DID_MKSECTION(5) | \ - P80211DID_MKGROUP(11)) -#define DIDMSG_P2REQ_RAMDL_STATE_ENABLE \ - (P80211DID_MKSECTION(5) | \ - P80211DID_MKGROUP(11) | \ - P80211DID_MKITEM(1) | 0x00000000) -#define DIDMSG_P2REQ_RAMDL_STATE_EXEADDR \ - (P80211DID_MKSECTION(5) | \ - P80211DID_MKGROUP(11) | \ - P80211DID_MKITEM(2) | 0x00000000) -#define DIDMSG_P2REQ_RAMDL_STATE_RESULTCODE \ - (P80211DID_MKSECTION(5) | \ - P80211DID_MKGROUP(11) | \ - P80211DID_MKITEM(3) | 0x00000000) -#define DIDMSG_P2REQ_RAMDL_WRITE \ - (P80211DID_MKSECTION(5) | \ - P80211DID_MKGROUP(12)) -#define DIDMSG_P2REQ_RAMDL_WRITE_ADDR \ - (P80211DID_MKSECTION(5) | \ - P80211DID_MKGROUP(12) | \ - P80211DID_MKITEM(1) | 0x00000000) -#define DIDMSG_P2REQ_RAMDL_WRITE_LEN \ - (P80211DID_MKSECTION(5) | \ - P80211DID_MKGROUP(12) | \ - P80211DID_MKITEM(2) | 0x00000000) -#define DIDMSG_P2REQ_RAMDL_WRITE_DATA \ - (P80211DID_MKSECTION(5) | \ - P80211DID_MKGROUP(12) | \ - P80211DID_MKITEM(3) | 0x00000000) -#define DIDMSG_P2REQ_RAMDL_WRITE_RESULTCODE \ - (P80211DID_MKSECTION(5) | \ - P80211DID_MKGROUP(12) | \ - P80211DID_MKITEM(4) | 0x00000000) -#define DIDMSG_P2REQ_FLASHDL_STATE \ - (P80211DID_MKSECTION(5) | \ - P80211DID_MKGROUP(13)) -#define DIDMSG_P2REQ_FLASHDL_WRITE \ - (P80211DID_MKSECTION(5) | \ - P80211DID_MKGROUP(14)) -#define DIDMIB_CAT_DOT11SMT \ - P80211DID_MKSECTION(1) -#define DIDMIB_DOT11SMT_WEPDEFAULTKEYSTABLE \ - (P80211DID_MKSECTION(1) | \ - P80211DID_MKGROUP(4)) -#define didmib_dot11smt_wepdefaultkeystable_key(_i) \ - (DIDMIB_DOT11SMT_WEPDEFAULTKEYSTABLE | \ - P80211DID_MKITEM(_i) | 0x0c000000) -#define DIDMIB_DOT11SMT_PRIVACYTABLE \ - (P80211DID_MKSECTION(1) | \ - P80211DID_MKGROUP(6)) -#define DIDMIB_DOT11SMT_PRIVACYTABLE_PRIVACYINVOKED \ - (P80211DID_MKSECTION(1) | \ - P80211DID_MKGROUP(6) | \ - P80211DID_MKITEM(1) | 0x18000000) -#define DIDMIB_DOT11SMT_PRIVACYTABLE_WEPDEFAULTKEYID \ - (P80211DID_MKSECTION(1) | \ - P80211DID_MKGROUP(6) | \ - P80211DID_MKITEM(2) | 0x18000000) -#define DIDMIB_DOT11SMT_PRIVACYTABLE_EXCLUDEUNENCRYPTED \ - (P80211DID_MKSECTION(1) | \ - P80211DID_MKGROUP(6) | \ - P80211DID_MKITEM(4) | 0x18000000) -#define DIDMIB_DOT11MAC_OPERATIONTABLE \ - (P80211DID_MKSECTION(2) | \ - P80211DID_MKGROUP(1)) -#define DIDMIB_DOT11MAC_OPERATIONTABLE_MACADDRESS \ - (P80211DID_MKSECTION(2) | \ - P80211DID_MKGROUP(1) | \ - P80211DID_MKITEM(1) | 0x18000000) -#define DIDMIB_DOT11MAC_OPERATIONTABLE_RTSTHRESHOLD \ - (P80211DID_MKSECTION(2) | \ - P80211DID_MKGROUP(1) | \ - P80211DID_MKITEM(2) | 0x18000000) -#define DIDMIB_DOT11MAC_OPERATIONTABLE_SHORTRETRYLIMIT \ - (P80211DID_MKSECTION(2) | \ - P80211DID_MKGROUP(1) | \ - P80211DID_MKITEM(3) | 0x10000000) -#define DIDMIB_DOT11MAC_OPERATIONTABLE_LONGRETRYLIMIT \ - (P80211DID_MKSECTION(2) | \ - P80211DID_MKGROUP(1) | \ - P80211DID_MKITEM(4) | 0x10000000) -#define DIDMIB_DOT11MAC_OPERATIONTABLE_FRAGMENTATIONTHRESHOLD \ - (P80211DID_MKSECTION(2) | \ - P80211DID_MKGROUP(1) | \ - P80211DID_MKITEM(5) | 0x18000000) -#define DIDMIB_DOT11MAC_OPERATIONTABLE_MAXTRANSMITMSDULIFETIME \ - (P80211DID_MKSECTION(2) | \ - P80211DID_MKGROUP(1) | \ - P80211DID_MKITEM(6) | 0x10000000) -#define DIDMIB_CAT_DOT11PHY \ - P80211DID_MKSECTION(3) -#define DIDMIB_DOT11PHY_OPERATIONTABLE \ - (P80211DID_MKSECTION(3) | \ - P80211DID_MKGROUP(1)) -#define DIDMIB_DOT11PHY_TXPOWERTABLE_CURRENTTXPOWERLEVEL \ - (P80211DID_MKSECTION(3) | \ - P80211DID_MKGROUP(3) | \ - P80211DID_MKITEM(10) | 0x18000000) -#define DIDMIB_DOT11PHY_DSSSTABLE \ - (P80211DID_MKSECTION(3) | \ - P80211DID_MKGROUP(5)) -#define DIDMIB_DOT11PHY_DSSSTABLE_CURRENTCHANNEL \ - (P80211DID_MKSECTION(3) | \ - P80211DID_MKGROUP(5) | \ - P80211DID_MKITEM(1) | 0x10000000) -#define DIDMIB_CAT_LNX \ - P80211DID_MKSECTION(4) -#define DIDMIB_LNX_CONFIGTABLE \ - (P80211DID_MKSECTION(4) | \ - P80211DID_MKGROUP(1)) -#define DIDMIB_LNX_CONFIGTABLE_RSNAIE \ - (P80211DID_MKSECTION(4) | \ - P80211DID_MKGROUP(1) | \ - P80211DID_MKITEM(1) | 0x18000000) -#define DIDMIB_CAT_P2 \ - P80211DID_MKSECTION(5) -#define DIDMIB_P2_STATIC \ - (P80211DID_MKSECTION(5) | \ - P80211DID_MKGROUP(2)) -#define DIDMIB_P2_STATIC_CNFPORTTYPE \ - (P80211DID_MKSECTION(5) | \ - P80211DID_MKGROUP(2) | \ - P80211DID_MKITEM(1) | 0x18000000) -#define DIDMIB_P2_NIC_PRISUPRANGE \ - (P80211DID_MKSECTION(5) | \ - P80211DID_MKGROUP(5) | \ - P80211DID_MKITEM(6) | 0x10000000) -#define DIDMIB_P2_MAC \ - (P80211DID_MKSECTION(5) | \ - P80211DID_MKGROUP(6)) -#define DIDMIB_P2_MAC_CURRENTTXRATE \ - (P80211DID_MKSECTION(5) | \ - P80211DID_MKGROUP(6) | \ - P80211DID_MKITEM(12) | 0x10000000) -#endif diff --git a/drivers/staging/wlan-ng/p80211metastruct.h b/drivers/staging/wlan-ng/p80211metastruct.h deleted file mode 100644 index a52217c9b953..000000000000 --- a/drivers/staging/wlan-ng/p80211metastruct.h +++ /dev/null @@ -1,236 +0,0 @@ -/* SPDX-License-Identifier: (GPL-2.0 OR MPL-1.1) */ -/* -------------------------------------------------------------------- - * - * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. - * -------------------------------------------------------------------- - * - * linux-wlan - * - * -------------------------------------------------------------------- - * - * Inquiries regarding the linux-wlan Open Source project can be - * made directly to: - * - * AbsoluteValue Systems Inc. - * info@linux-wlan.com - * http://www.linux-wlan.com - * - * -------------------------------------------------------------------- - * - * Portions of the development of this software were funded by - * Intersil Corporation as part of PRISM(R) chipset product development. - * - * -------------------------------------------------------------------- - */ - -#ifndef _P80211MKMETASTRUCT_H -#define _P80211MKMETASTRUCT_H - -struct p80211msg_dot11req_mibget { - u32 msgcode; - u32 msglen; - u8 devname[WLAN_DEVNAMELEN_MAX]; - struct p80211item_unk392 mibattribute; - struct p80211item_uint32 resultcode; -} __packed; - -struct p80211msg_dot11req_mibset { - u32 msgcode; - u32 msglen; - u8 devname[WLAN_DEVNAMELEN_MAX]; - struct p80211item_unk392 mibattribute; - struct p80211item_uint32 resultcode; -} __packed; - -struct p80211msg_dot11req_scan { - u32 msgcode; - u32 msglen; - u8 devname[WLAN_DEVNAMELEN_MAX]; - struct p80211item_uint32 bsstype; - struct p80211item_pstr6 bssid; - u8 pad_0C[1]; - struct p80211item_pstr32 ssid; - u8 pad_1D[3]; - struct p80211item_uint32 scantype; - struct p80211item_uint32 probedelay; - struct p80211item_pstr14 channellist; - u8 pad_2C[1]; - struct p80211item_uint32 minchanneltime; - struct p80211item_uint32 maxchanneltime; - struct p80211item_uint32 resultcode; - struct p80211item_uint32 numbss; - struct p80211item_uint32 append; -} __packed; - -struct p80211msg_dot11req_scan_results { - u32 msgcode; - u32 msglen; - u8 devname[WLAN_DEVNAMELEN_MAX]; - struct p80211item_uint32 bssindex; - struct p80211item_uint32 resultcode; - struct p80211item_uint32 signal; - struct p80211item_uint32 noise; - struct p80211item_pstr6 bssid; - u8 pad_3C[1]; - struct p80211item_pstr32 ssid; - u8 pad_4D[3]; - struct p80211item_uint32 bsstype; - struct p80211item_uint32 beaconperiod; - struct p80211item_uint32 dtimperiod; - struct p80211item_uint32 timestamp; - struct p80211item_uint32 localtime; - struct p80211item_uint32 fhdwelltime; - struct p80211item_uint32 fhhopset; - struct p80211item_uint32 fhhoppattern; - struct p80211item_uint32 fhhopindex; - struct p80211item_uint32 dschannel; - struct p80211item_uint32 cfpcount; - struct p80211item_uint32 cfpperiod; - struct p80211item_uint32 cfpmaxduration; - struct p80211item_uint32 cfpdurremaining; - struct p80211item_uint32 ibssatimwindow; - struct p80211item_uint32 cfpollable; - struct p80211item_uint32 cfpollreq; - struct p80211item_uint32 privacy; - struct p80211item_uint32 capinfo; - struct p80211item_uint32 basicrate[8]; - struct p80211item_uint32 supprate[8]; -} __packed; - -struct p80211msg_dot11req_start { - u32 msgcode; - u32 msglen; - u8 devname[WLAN_DEVNAMELEN_MAX]; - struct p80211item_pstr32 ssid; - u8 pad_12D[3]; - struct p80211item_uint32 bsstype; - struct p80211item_uint32 beaconperiod; - struct p80211item_uint32 dtimperiod; - struct p80211item_uint32 cfpperiod; - struct p80211item_uint32 cfpmaxduration; - struct p80211item_uint32 fhdwelltime; - struct p80211item_uint32 fhhopset; - struct p80211item_uint32 fhhoppattern; - struct p80211item_uint32 dschannel; - struct p80211item_uint32 ibssatimwindow; - struct p80211item_uint32 probedelay; - struct p80211item_uint32 cfpollable; - struct p80211item_uint32 cfpollreq; - struct p80211item_uint32 basicrate1; - struct p80211item_uint32 basicrate2; - struct p80211item_uint32 basicrate3; - struct p80211item_uint32 basicrate4; - struct p80211item_uint32 basicrate5; - struct p80211item_uint32 basicrate6; - struct p80211item_uint32 basicrate7; - struct p80211item_uint32 basicrate8; - struct p80211item_uint32 operationalrate1; - struct p80211item_uint32 operationalrate2; - struct p80211item_uint32 operationalrate3; - struct p80211item_uint32 operationalrate4; - struct p80211item_uint32 operationalrate5; - struct p80211item_uint32 operationalrate6; - struct p80211item_uint32 operationalrate7; - struct p80211item_uint32 operationalrate8; - struct p80211item_uint32 resultcode; -} __packed; - -struct p80211msg_lnxreq_ifstate { - u32 msgcode; - u32 msglen; - u8 devname[WLAN_DEVNAMELEN_MAX]; - struct p80211item_uint32 ifstate; - struct p80211item_uint32 resultcode; -} __packed; - -struct p80211msg_lnxreq_wlansniff { - u32 msgcode; - u32 msglen; - u8 devname[WLAN_DEVNAMELEN_MAX]; - struct p80211item_uint32 enable; - struct p80211item_uint32 channel; - struct p80211item_uint32 prismheader; - struct p80211item_uint32 wlanheader; - struct p80211item_uint32 keepwepflags; - struct p80211item_uint32 stripfcs; - struct p80211item_uint32 packet_trunc; - struct p80211item_uint32 resultcode; -} __packed; - -struct p80211msg_lnxreq_hostwep { - u32 msgcode; - u32 msglen; - u8 devname[WLAN_DEVNAMELEN_MAX]; - struct p80211item_uint32 resultcode; - struct p80211item_uint32 decrypt; - struct p80211item_uint32 encrypt; -} __packed; - -struct p80211msg_lnxreq_commsquality { - u32 msgcode; - u32 msglen; - u8 devname[WLAN_DEVNAMELEN_MAX]; - struct p80211item_uint32 resultcode; - struct p80211item_uint32 dbm; - struct p80211item_uint32 link; - struct p80211item_uint32 level; - struct p80211item_uint32 noise; - struct p80211item_uint32 txrate; -} __packed; - -struct p80211msg_lnxreq_autojoin { - u32 msgcode; - u32 msglen; - u8 devname[WLAN_DEVNAMELEN_MAX]; - struct p80211item_pstr32 ssid; - u8 pad_19D[3]; - struct p80211item_uint32 authtype; - struct p80211item_uint32 resultcode; -} __packed; - -struct p80211msg_p2req_readpda { - u32 msgcode; - u32 msglen; - u8 devname[WLAN_DEVNAMELEN_MAX]; - struct p80211item_unk1024 pda; - struct p80211item_uint32 resultcode; -} __packed; - -struct p80211msg_p2req_ramdl_state { - u32 msgcode; - u32 msglen; - u8 devname[WLAN_DEVNAMELEN_MAX]; - struct p80211item_uint32 enable; - struct p80211item_uint32 exeaddr; - struct p80211item_uint32 resultcode; -} __packed; - -struct p80211msg_p2req_ramdl_write { - u32 msgcode; - u32 msglen; - u8 devname[WLAN_DEVNAMELEN_MAX]; - struct p80211item_uint32 addr; - struct p80211item_uint32 len; - struct p80211item_unk4096 data; - struct p80211item_uint32 resultcode; -} __packed; - -struct p80211msg_p2req_flashdl_state { - u32 msgcode; - u32 msglen; - u8 devname[WLAN_DEVNAMELEN_MAX]; - struct p80211item_uint32 enable; - struct p80211item_uint32 resultcode; -} __packed; - -struct p80211msg_p2req_flashdl_write { - u32 msgcode; - u32 msglen; - u8 devname[WLAN_DEVNAMELEN_MAX]; - struct p80211item_uint32 addr; - struct p80211item_uint32 len; - struct p80211item_unk4096 data; - struct p80211item_uint32 resultcode; -} __packed; - -#endif diff --git a/drivers/staging/wlan-ng/p80211mgmt.h b/drivers/staging/wlan-ng/p80211mgmt.h deleted file mode 100644 index 7ffc202d9007..000000000000 --- a/drivers/staging/wlan-ng/p80211mgmt.h +++ /dev/null @@ -1,199 +0,0 @@ -/* SPDX-License-Identifier: (GPL-2.0 OR MPL-1.1) */ -/* - * - * Macros, types, and functions to handle 802.11 mgmt frames - * - * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. - * -------------------------------------------------------------------- - * - * linux-wlan - * - * -------------------------------------------------------------------- - * - * Inquiries regarding the linux-wlan Open Source project can be - * made directly to: - * - * AbsoluteValue Systems Inc. - * info@linux-wlan.com - * http://www.linux-wlan.com - * - * -------------------------------------------------------------------- - * - * Portions of the development of this software were funded by - * Intersil Corporation as part of PRISM(R) chipset product development. - * - * -------------------------------------------------------------------- - * - * This file declares the constants and types used in the interface - * between a wlan driver and the user mode utilities. - * - * Notes: - * - Constant values are always in HOST byte order. To assign - * values to multi-byte fields they _must_ be converted to - * ieee byte order. To retrieve multi-byte values from incoming - * frames, they must be converted to host order. - * - * - The len member of the frame structure does NOT!!! include - * the MAC CRC. Therefore, the len field on rx'd frames should - * have 4 subtracted from it. - * - * All functions declared here are implemented in p80211.c - * - * The types, macros, and functions defined here are primarily - * used for encoding and decoding management frames. They are - * designed to follow these patterns of use: - * - * DECODE: - * 1) a frame of length len is received into buffer b - * 2) using the hdr structure and macros, we determine the type - * 3) an appropriate mgmt frame structure, mf, is allocated and zeroed - * 4) mf.hdr = b - * mf.buf = b - * mf.len = len - * 5) call mgmt_decode( mf ) - * 6) the frame field pointers in mf are now set. Note that any - * multi-byte frame field values accessed using the frame field - * pointers are in ieee byte order and will have to be converted - * to host order. - * - * ENCODE: - * 1) Library client allocates buffer space for maximum length - * frame of the desired type - * 2) Library client allocates a mgmt frame structure, called mf, - * of the desired type - * 3) Set the following: - * mf.type = - * mf.buf = - * 4) call mgmt_encode( mf ) - * 5) all of the fixed field pointers and fixed length information element - * pointers in mf are now set to their respective locations in the - * allocated space (fortunately, all variable length information elements - * fall at the end of their respective frames). - * 5a) The length field is set to include the last of the fixed and fixed - * length fields. It may have to be updated for optional or variable - * length information elements. - * 6) Optional and variable length information elements are special cases - * and must be handled individually by the client code. - * -------------------------------------------------------------------- - */ - -#ifndef _P80211MGMT_H -#define _P80211MGMT_H - -#ifndef _P80211HDR_H -#include "p80211hdr.h" -#endif - -/*-- Information Element IDs --------------------*/ -#define WLAN_EID_SSID 0 -#define WLAN_EID_SUPP_RATES 1 -#define WLAN_EID_FH_PARMS 2 -#define WLAN_EID_DS_PARMS 3 -#define WLAN_EID_CF_PARMS 4 -#define WLAN_EID_TIM 5 -#define WLAN_EID_IBSS_PARMS 6 -/*-- values 7-15 reserved --*/ -#define WLAN_EID_CHALLENGE 16 -/*-- values 17-31 reserved for challenge text extension --*/ -/*-- values 32-255 reserved --*/ - -/*-- Reason Codes -------------------------------*/ -#define WLAN_MGMT_REASON_RSVD 0 -#define WLAN_MGMT_REASON_UNSPEC 1 -#define WLAN_MGMT_REASON_PRIOR_AUTH_INVALID 2 -#define WLAN_MGMT_REASON_DEAUTH_LEAVING 3 -#define WLAN_MGMT_REASON_DISASSOC_INACTIVE 4 -#define WLAN_MGMT_REASON_DISASSOC_AP_BUSY 5 -#define WLAN_MGMT_REASON_CLASS2_NONAUTH 6 -#define WLAN_MGMT_REASON_CLASS3_NONASSOC 7 -#define WLAN_MGMT_REASON_DISASSOC_STA_HASLEFT 8 -#define WLAN_MGMT_REASON_CANT_ASSOC_NONAUTH 9 - -/*-- Status Codes -------------------------------*/ -#define WLAN_MGMT_STATUS_SUCCESS 0 -#define WLAN_MGMT_STATUS_UNSPEC_FAILURE 1 -#define WLAN_MGMT_STATUS_CAPS_UNSUPPORTED 10 -#define WLAN_MGMT_STATUS_REASSOC_NO_ASSOC 11 -#define WLAN_MGMT_STATUS_ASSOC_DENIED_UNSPEC 12 -#define WLAN_MGMT_STATUS_UNSUPPORTED_AUTHALG 13 -#define WLAN_MGMT_STATUS_RX_AUTH_NOSEQ 14 -#define WLAN_MGMT_STATUS_CHALLENGE_FAIL 15 -#define WLAN_MGMT_STATUS_AUTH_TIMEOUT 16 -#define WLAN_MGMT_STATUS_ASSOC_DENIED_BUSY 17 -#define WLAN_MGMT_STATUS_ASSOC_DENIED_RATES 18 - /* p80211b additions */ -#define WLAN_MGMT_STATUS_ASSOC_DENIED_NOSHORT 19 -#define WLAN_MGMT_STATUS_ASSOC_DENIED_NOPBCC 20 -#define WLAN_MGMT_STATUS_ASSOC_DENIED_NOAGILITY 21 - -/*-- Auth Algorithm Field ---------------------------*/ -#define WLAN_AUTH_ALG_OPENSYSTEM 0 -#define WLAN_AUTH_ALG_SHAREDKEY 1 - -/*-- Management Frame Field Offsets -------------*/ -/* Note: Not all fields are listed because of variable lengths, */ -/* see the code in p80211.c to see how we search for fields */ -/* Note: These offsets are from the start of the frame data */ - -#define WLAN_BEACON_OFF_TS 0 -#define WLAN_BEACON_OFF_BCN_int 8 -#define WLAN_BEACON_OFF_CAPINFO 10 -#define WLAN_BEACON_OFF_SSID 12 - -#define WLAN_DISASSOC_OFF_REASON 0 - -#define WLAN_ASSOCREQ_OFF_CAP_INFO 0 -#define WLAN_ASSOCREQ_OFF_LISTEN_int 2 -#define WLAN_ASSOCREQ_OFF_SSID 4 - -#define WLAN_ASSOCRESP_OFF_CAP_INFO 0 -#define WLAN_ASSOCRESP_OFF_STATUS 2 -#define WLAN_ASSOCRESP_OFF_AID 4 -#define WLAN_ASSOCRESP_OFF_SUPP_RATES 6 - -#define WLAN_REASSOCREQ_OFF_CAP_INFO 0 -#define WLAN_REASSOCREQ_OFF_LISTEN_int 2 -#define WLAN_REASSOCREQ_OFF_CURR_AP 4 -#define WLAN_REASSOCREQ_OFF_SSID 10 - -#define WLAN_REASSOCRESP_OFF_CAP_INFO 0 -#define WLAN_REASSOCRESP_OFF_STATUS 2 -#define WLAN_REASSOCRESP_OFF_AID 4 -#define WLAN_REASSOCRESP_OFF_SUPP_RATES 6 - -#define WLAN_PROBEREQ_OFF_SSID 0 - -#define WLAN_PROBERESP_OFF_TS 0 -#define WLAN_PROBERESP_OFF_BCN_int 8 -#define WLAN_PROBERESP_OFF_CAP_INFO 10 -#define WLAN_PROBERESP_OFF_SSID 12 - -#define WLAN_AUTHEN_OFF_AUTH_ALG 0 -#define WLAN_AUTHEN_OFF_AUTH_SEQ 2 -#define WLAN_AUTHEN_OFF_STATUS 4 -#define WLAN_AUTHEN_OFF_CHALLENGE 6 - -#define WLAN_DEAUTHEN_OFF_REASON 0 - -/*-- Capability Field ---------------------------*/ -#define WLAN_GET_MGMT_CAP_INFO_ESS(n) ((n) & BIT(0)) -#define WLAN_GET_MGMT_CAP_INFO_IBSS(n) (((n) & BIT(1)) >> 1) -#define WLAN_GET_MGMT_CAP_INFO_CFPOLLABLE(n) (((n) & BIT(2)) >> 2) -#define WLAN_GET_MGMT_CAP_INFO_CFPOLLREQ(n) (((n) & BIT(3)) >> 3) -#define WLAN_GET_MGMT_CAP_INFO_PRIVACY(n) (((n) & BIT(4)) >> 4) - /* p80211b additions */ -#define WLAN_GET_MGMT_CAP_INFO_SHORT(n) (((n) & BIT(5)) >> 5) -#define WLAN_GET_MGMT_CAP_INFO_PBCC(n) (((n) & BIT(6)) >> 6) -#define WLAN_GET_MGMT_CAP_INFO_AGILITY(n) (((n) & BIT(7)) >> 7) - -#define WLAN_SET_MGMT_CAP_INFO_ESS(n) (n) -#define WLAN_SET_MGMT_CAP_INFO_IBSS(n) ((n) << 1) -#define WLAN_SET_MGMT_CAP_INFO_CFPOLLABLE(n) ((n) << 2) -#define WLAN_SET_MGMT_CAP_INFO_CFPOLLREQ(n) ((n) << 3) -#define WLAN_SET_MGMT_CAP_INFO_PRIVACY(n) ((n) << 4) - /* p80211b additions */ -#define WLAN_SET_MGMT_CAP_INFO_SHORT(n) ((n) << 5) -#define WLAN_SET_MGMT_CAP_INFO_PBCC(n) ((n) << 6) -#define WLAN_SET_MGMT_CAP_INFO_AGILITY(n) ((n) << 7) - -#endif /* _P80211MGMT_H */ diff --git a/drivers/staging/wlan-ng/p80211msg.h b/drivers/staging/wlan-ng/p80211msg.h deleted file mode 100644 index d56bc6079ed4..000000000000 --- a/drivers/staging/wlan-ng/p80211msg.h +++ /dev/null @@ -1,39 +0,0 @@ -/* SPDX-License-Identifier: (GPL-2.0 OR MPL-1.1) */ -/* - * - * Macros, constants, types, and funcs for req and ind messages - * - * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. - * -------------------------------------------------------------------- - * - * linux-wlan - * - * -------------------------------------------------------------------- - * - * Inquiries regarding the linux-wlan Open Source project can be - * made directly to: - * - * AbsoluteValue Systems Inc. - * info@linux-wlan.com - * http://www.linux-wlan.com - * - * -------------------------------------------------------------------- - * - * Portions of the development of this software were funded by - * Intersil Corporation as part of PRISM(R) chipset product development. - * - * -------------------------------------------------------------------- - */ - -#ifndef _P80211MSG_H -#define _P80211MSG_H - -#define WLAN_DEVNAMELEN_MAX 16 - -struct p80211msg { - u32 msgcode; - u32 msglen; - u8 devname[WLAN_DEVNAMELEN_MAX]; -} __packed; - -#endif /* _P80211MSG_H */ diff --git a/drivers/staging/wlan-ng/p80211netdev.c b/drivers/staging/wlan-ng/p80211netdev.c deleted file mode 100644 index 284c1c12e1d1..000000000000 --- a/drivers/staging/wlan-ng/p80211netdev.c +++ /dev/null @@ -1,988 +0,0 @@ -// SPDX-License-Identifier: (GPL-2.0 OR MPL-1.1) -/* - * - * Linux Kernel net device interface - * - * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. - * -------------------------------------------------------------------- - * - * linux-wlan - * - * -------------------------------------------------------------------- - * - * Inquiries regarding the linux-wlan Open Source project can be - * made directly to: - * - * AbsoluteValue Systems Inc. - * info@linux-wlan.com - * http://www.linux-wlan.com - * - * -------------------------------------------------------------------- - * - * Portions of the development of this software were funded by - * Intersil Corporation as part of PRISM(R) chipset product development. - * - * -------------------------------------------------------------------- - * - * The functions required for a Linux network device are defined here. - * - * -------------------------------------------------------------------- - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef SIOCETHTOOL -#include -#endif - -#include -#include -#include - -#include "p80211types.h" -#include "p80211hdr.h" -#include "p80211conv.h" -#include "p80211mgmt.h" -#include "p80211msg.h" -#include "p80211netdev.h" -#include "p80211ioctl.h" -#include "p80211req.h" -#include "p80211metastruct.h" -#include "p80211metadef.h" - -#include "cfg80211.c" - -/* netdevice method functions */ -static int p80211knetdev_init(struct net_device *netdev); -static int p80211knetdev_open(struct net_device *netdev); -static int p80211knetdev_stop(struct net_device *netdev); -static netdev_tx_t p80211knetdev_hard_start_xmit(struct sk_buff *skb, - struct net_device *netdev); -static void p80211knetdev_set_multicast_list(struct net_device *dev); -static int p80211knetdev_siocdevprivate(struct net_device *dev, struct ifreq *ifr, - void __user *data, int cmd); -static int p80211knetdev_set_mac_address(struct net_device *dev, void *addr); -static void p80211knetdev_tx_timeout(struct net_device *netdev, unsigned int txqueue); -static int p80211_rx_typedrop(struct wlandevice *wlandev, u16 fc); - -int wlan_watchdog = 5000; -module_param(wlan_watchdog, int, 0644); -MODULE_PARM_DESC(wlan_watchdog, "transmit timeout in milliseconds"); - -int wlan_wext_write = 1; -module_param(wlan_wext_write, int, 0644); -MODULE_PARM_DESC(wlan_wext_write, "enable write wireless extensions"); - -/*---------------------------------------------------------------- - * p80211knetdev_init - * - * Init method for a Linux netdevice. Called in response to - * register_netdev. - * - * Arguments: - * none - * - * Returns: - * nothing - *---------------------------------------------------------------- - */ -static int p80211knetdev_init(struct net_device *netdev) -{ - /* Called in response to register_netdev */ - /* This is usually the probe function, but the probe has */ - /* already been done by the MSD and the create_kdev */ - /* function. All we do here is return success */ - return 0; -} - -/*---------------------------------------------------------------- - * p80211knetdev_open - * - * Linux netdevice open method. Following a successful call here, - * the device is supposed to be ready for tx and rx. In our - * situation that may not be entirely true due to the state of the - * MAC below. - * - * Arguments: - * netdev Linux network device structure - * - * Returns: - * zero on success, non-zero otherwise - *---------------------------------------------------------------- - */ -static int p80211knetdev_open(struct net_device *netdev) -{ - int result = 0; /* success */ - struct wlandevice *wlandev = netdev->ml_priv; - - /* Check to make sure the MSD is running */ - if (wlandev->msdstate != WLAN_MSD_RUNNING) - return -ENODEV; - - /* Tell the MSD to open */ - if (wlandev->open) { - result = wlandev->open(wlandev); - if (result == 0) { - netif_start_queue(wlandev->netdev); - wlandev->state = WLAN_DEVICE_OPEN; - } - } else { - result = -EAGAIN; - } - - return result; -} - -/*---------------------------------------------------------------- - * p80211knetdev_stop - * - * Linux netdevice stop (close) method. Following this call, - * no frames should go up or down through this interface. - * - * Arguments: - * netdev Linux network device structure - * - * Returns: - * zero on success, non-zero otherwise - *---------------------------------------------------------------- - */ -static int p80211knetdev_stop(struct net_device *netdev) -{ - int result = 0; - struct wlandevice *wlandev = netdev->ml_priv; - - if (wlandev->close) - result = wlandev->close(wlandev); - - netif_stop_queue(wlandev->netdev); - wlandev->state = WLAN_DEVICE_CLOSED; - - return result; -} - -/*---------------------------------------------------------------- - * p80211netdev_rx - * - * Frame receive function called by the mac specific driver. - * - * Arguments: - * wlandev WLAN network device structure - * skb skbuff containing a full 802.11 frame. - * Returns: - * nothing - * Side effects: - * - *---------------------------------------------------------------- - */ -void p80211netdev_rx(struct wlandevice *wlandev, struct sk_buff *skb) -{ - /* Enqueue for post-irq processing */ - skb_queue_tail(&wlandev->nsd_rxq, skb); - tasklet_schedule(&wlandev->rx_bh); -} - -#define CONV_TO_ETHER_SKIPPED 0x01 -#define CONV_TO_ETHER_FAILED 0x02 - -/** - * p80211_convert_to_ether - conversion from 802.11 frame to ethernet frame - * @wlandev: pointer to WLAN device - * @skb: pointer to socket buffer - * - * Returns: 0 if conversion succeeded - * CONV_TO_ETHER_FAILED if conversion failed - * CONV_TO_ETHER_SKIPPED if frame is ignored - */ -static int p80211_convert_to_ether(struct wlandevice *wlandev, - struct sk_buff *skb) -{ - struct p80211_hdr *hdr; - - hdr = (struct p80211_hdr *)skb->data; - if (p80211_rx_typedrop(wlandev, le16_to_cpu(hdr->frame_control))) - return CONV_TO_ETHER_SKIPPED; - - /* perform mcast filtering: allow my local address through but reject - * anything else that isn't multicast - */ - if (wlandev->netdev->flags & IFF_ALLMULTI) { - if (!ether_addr_equal_unaligned(wlandev->netdev->dev_addr, - hdr->address1)) { - if (!is_multicast_ether_addr(hdr->address1)) - return CONV_TO_ETHER_SKIPPED; - } - } - - if (skb_p80211_to_ether(wlandev, wlandev->ethconv, skb) == 0) { - wlandev->netdev->stats.rx_packets++; - wlandev->netdev->stats.rx_bytes += skb->len; - netif_rx(skb); - return 0; - } - - netdev_dbg(wlandev->netdev, "%s failed.\n", __func__); - return CONV_TO_ETHER_FAILED; -} - -/** - * p80211netdev_rx_bh - deferred processing of all received frames - * - * @t: pointer to the tasklet associated with this handler - */ -static void p80211netdev_rx_bh(struct tasklet_struct *t) -{ - struct wlandevice *wlandev = from_tasklet(wlandev, t, rx_bh); - struct sk_buff *skb = NULL; - struct net_device *dev = wlandev->netdev; - - /* Let's empty our queue */ - while ((skb = skb_dequeue(&wlandev->nsd_rxq))) { - if (wlandev->state == WLAN_DEVICE_OPEN) { - if (dev->type != ARPHRD_ETHER) { - /* RAW frame; we shouldn't convert it */ - /* XXX Append the Prism Header here instead. */ - - /* set up various data fields */ - skb->dev = dev; - skb_reset_mac_header(skb); - skb->ip_summed = CHECKSUM_NONE; - skb->pkt_type = PACKET_OTHERHOST; - skb->protocol = htons(ETH_P_80211_RAW); - - dev->stats.rx_packets++; - dev->stats.rx_bytes += skb->len; - netif_rx(skb); - continue; - } else { - if (!p80211_convert_to_ether(wlandev, skb)) - continue; - } - } - dev_kfree_skb(skb); - } -} - -/*---------------------------------------------------------------- - * p80211knetdev_hard_start_xmit - * - * Linux netdevice method for transmitting a frame. - * - * Arguments: - * skb Linux sk_buff containing the frame. - * netdev Linux netdevice. - * - * Side effects: - * If the lower layers report that buffers are full. netdev->tbusy - * will be set to prevent higher layers from sending more traffic. - * - * Note: If this function returns non-zero, higher layers retain - * ownership of the skb. - * - * Returns: - * zero on success, non-zero on failure. - *---------------------------------------------------------------- - */ -static netdev_tx_t p80211knetdev_hard_start_xmit(struct sk_buff *skb, - struct net_device *netdev) -{ - int result = 0; - int txresult; - struct wlandevice *wlandev = netdev->ml_priv; - struct p80211_hdr p80211_hdr; - struct p80211_metawep p80211_wep; - - p80211_wep.data = NULL; - - if (!skb) - return NETDEV_TX_OK; - - if (wlandev->state != WLAN_DEVICE_OPEN) { - result = 1; - goto failed; - } - - memset(&p80211_hdr, 0, sizeof(p80211_hdr)); - memset(&p80211_wep, 0, sizeof(p80211_wep)); - - if (netif_queue_stopped(netdev)) { - netdev_dbg(netdev, "called when queue stopped.\n"); - result = 1; - goto failed; - } - - netif_stop_queue(netdev); - - /* Check to see that a valid mode is set */ - switch (wlandev->macmode) { - case WLAN_MACMODE_IBSS_STA: - case WLAN_MACMODE_ESS_STA: - case WLAN_MACMODE_ESS_AP: - break; - default: - /* Mode isn't set yet, just drop the frame - * and return success . - * TODO: we need a saner way to handle this - */ - if (be16_to_cpu(skb->protocol) != ETH_P_80211_RAW) { - netif_start_queue(wlandev->netdev); - netdev_notice(netdev, "Tx attempt prior to association, frame dropped.\n"); - netdev->stats.tx_dropped++; - result = 0; - goto failed; - } - break; - } - - /* Check for raw transmits */ - if (be16_to_cpu(skb->protocol) == ETH_P_80211_RAW) { - if (!capable(CAP_NET_ADMIN)) { - result = 1; - goto failed; - } - /* move the header over */ - memcpy(&p80211_hdr, skb->data, sizeof(p80211_hdr)); - skb_pull(skb, sizeof(p80211_hdr)); - } else { - if (skb_ether_to_p80211 - (wlandev, wlandev->ethconv, skb, &p80211_hdr, - &p80211_wep) != 0) { - /* convert failed */ - netdev_dbg(netdev, "ether_to_80211(%d) failed.\n", - wlandev->ethconv); - result = 1; - goto failed; - } - } - if (!wlandev->txframe) { - result = 1; - goto failed; - } - - netif_trans_update(netdev); - - netdev->stats.tx_packets++; - /* count only the packet payload */ - netdev->stats.tx_bytes += skb->len; - - txresult = wlandev->txframe(wlandev, skb, &p80211_hdr, &p80211_wep); - - if (txresult == 0) { - /* success and more buf */ - /* avail, re: hw_txdata */ - netif_wake_queue(wlandev->netdev); - result = NETDEV_TX_OK; - } else if (txresult == 1) { - /* success, no more avail */ - netdev_dbg(netdev, "txframe success, no more bufs\n"); - /* netdev->tbusy = 1; don't set here, irqhdlr */ - /* may have already cleared it */ - result = NETDEV_TX_OK; - } else if (txresult == 2) { - /* alloc failure, drop frame */ - netdev_dbg(netdev, "txframe returned alloc_fail\n"); - result = NETDEV_TX_BUSY; - } else { - /* buffer full or queue busy, drop frame. */ - netdev_dbg(netdev, "txframe returned full or busy\n"); - result = NETDEV_TX_BUSY; - } - -failed: - /* Free up the WEP buffer if it's not the same as the skb */ - if ((p80211_wep.data) && (p80211_wep.data != skb->data)) - kfree_sensitive(p80211_wep.data); - - /* we always free the skb here, never in a lower level. */ - if (!result) - dev_kfree_skb(skb); - - return result; -} - -/*---------------------------------------------------------------- - * p80211knetdev_set_multicast_list - * - * Called from higher layers whenever there's a need to set/clear - * promiscuous mode or rewrite the multicast list. - * - * Arguments: - * none - * - * Returns: - * nothing - *---------------------------------------------------------------- - */ -static void p80211knetdev_set_multicast_list(struct net_device *dev) -{ - struct wlandevice *wlandev = dev->ml_priv; - - /* TODO: real multicast support as well */ - - if (wlandev->set_multicast_list) - wlandev->set_multicast_list(wlandev, dev); -} - -/*---------------------------------------------------------------- - * p80211knetdev_siocdevprivate - * - * Handle an ioctl call on one of our devices. Everything Linux - * ioctl specific is done here. Then we pass the contents of the - * ifr->data to the request message handler. - * - * Arguments: - * dev Linux kernel netdevice - * ifr Our private ioctl request structure, typed for the - * generic struct ifreq so we can use ptr to func - * w/o cast. - * - * Returns: - * zero on success, a negative errno on failure. Possible values: - * -ENETDOWN Device isn't up. - * -EBUSY cmd already in progress - * -ETIME p80211 cmd timed out (MSD may have its own timers) - * -EFAULT memory fault copying msg from user buffer - * -ENOMEM unable to allocate kernel msg buffer - * -EINVAL bad magic, it the cmd really for us? - * -EintR sleeping on cmd, awakened by signal, cmd cancelled. - * - * Call Context: - * Process thread (ioctl caller). TODO: SMP support may require - * locks. - *---------------------------------------------------------------- - */ -static int p80211knetdev_siocdevprivate(struct net_device *dev, - struct ifreq *ifr, - void __user *data, int cmd) -{ - int result = 0; - struct p80211ioctl_req *req = (struct p80211ioctl_req *)ifr; - struct wlandevice *wlandev = dev->ml_priv; - u8 *msgbuf; - - netdev_dbg(dev, "rx'd ioctl, cmd=%d, len=%d\n", cmd, req->len); - - if (in_compat_syscall()) - return -EOPNOTSUPP; - - /* Test the magic, assume ifr is good if it's there */ - if (req->magic != P80211_IOCTL_MAGIC) { - result = -EINVAL; - goto bail; - } - - if (cmd == P80211_IFTEST) { - result = 0; - goto bail; - } else if (cmd != P80211_IFREQ) { - result = -EINVAL; - goto bail; - } - - msgbuf = memdup_user(data, req->len); - if (IS_ERR(msgbuf)) { - result = PTR_ERR(msgbuf); - goto bail; - } - - result = p80211req_dorequest(wlandev, msgbuf); - - if (result == 0) { - if (copy_to_user(data, msgbuf, req->len)) - result = -EFAULT; - } - kfree(msgbuf); - -bail: - /* If allocate,copyfrom or copyto fails, return errno */ - return result; -} - -/*---------------------------------------------------------------- - * p80211knetdev_set_mac_address - * - * Handles the ioctl for changing the MACAddress of a netdevice - * - * references: linux/netdevice.h and drivers/net/net_init.c - * - * NOTE: [MSM] We only prevent address changes when the netdev is - * up. We don't control anything based on dot11 state. If the - * address is changed on a STA that's currently associated, you - * will probably lose the ability to send and receive data frames. - * Just be aware. Therefore, this should usually only be done - * prior to scan/join/auth/assoc. - * - * Arguments: - * dev netdevice struct - * addr the new MACAddress (a struct) - * - * Returns: - * zero on success, a negative errno on failure. Possible values: - * -EBUSY device is bussy (cmd not possible) - * -and errors returned by: p80211req_dorequest(..) - * - * by: Collin R. Mulliner - *---------------------------------------------------------------- - */ -static int p80211knetdev_set_mac_address(struct net_device *dev, void *addr) -{ - struct sockaddr *new_addr = addr; - struct p80211msg_dot11req_mibset dot11req; - struct p80211item_unk392 *mibattr; - struct p80211item_pstr6 *macaddr; - struct p80211item_uint32 *resultcode; - int result; - - /* If we're running, we don't allow MAC address changes */ - if (netif_running(dev)) - return -EBUSY; - - /* Set up some convenience pointers. */ - mibattr = &dot11req.mibattribute; - macaddr = (struct p80211item_pstr6 *)&mibattr->data; - resultcode = &dot11req.resultcode; - - /* Set up a dot11req_mibset */ - memset(&dot11req, 0, sizeof(dot11req)); - dot11req.msgcode = DIDMSG_DOT11REQ_MIBSET; - dot11req.msglen = sizeof(dot11req); - memcpy(dot11req.devname, - ((struct wlandevice *)dev->ml_priv)->name, - WLAN_DEVNAMELEN_MAX - 1); - - /* Set up the mibattribute argument */ - mibattr->did = DIDMSG_DOT11REQ_MIBSET_MIBATTRIBUTE; - mibattr->status = P80211ENUM_msgitem_status_data_ok; - mibattr->len = sizeof(mibattr->data); - - macaddr->did = DIDMIB_DOT11MAC_OPERATIONTABLE_MACADDRESS; - macaddr->status = P80211ENUM_msgitem_status_data_ok; - macaddr->len = sizeof(macaddr->data); - macaddr->data.len = ETH_ALEN; - memcpy(&macaddr->data.data, new_addr->sa_data, ETH_ALEN); - - /* Set up the resultcode argument */ - resultcode->did = DIDMSG_DOT11REQ_MIBSET_RESULTCODE; - resultcode->status = P80211ENUM_msgitem_status_no_value; - resultcode->len = sizeof(resultcode->data); - resultcode->data = 0; - - /* now fire the request */ - result = p80211req_dorequest(dev->ml_priv, (u8 *)&dot11req); - - /* If the request wasn't successful, report an error and don't - * change the netdev address - */ - if (result != 0 || resultcode->data != P80211ENUM_resultcode_success) { - netdev_err(dev, "Low-level driver failed dot11req_mibset(dot11MACAddress).\n"); - result = -EADDRNOTAVAIL; - } else { - /* everything's ok, change the addr in netdev */ - eth_hw_addr_set(dev, new_addr->sa_data); - } - - return result; -} - -static const struct net_device_ops p80211_netdev_ops = { - .ndo_init = p80211knetdev_init, - .ndo_open = p80211knetdev_open, - .ndo_stop = p80211knetdev_stop, - .ndo_start_xmit = p80211knetdev_hard_start_xmit, - .ndo_set_rx_mode = p80211knetdev_set_multicast_list, - .ndo_siocdevprivate = p80211knetdev_siocdevprivate, - .ndo_set_mac_address = p80211knetdev_set_mac_address, - .ndo_tx_timeout = p80211knetdev_tx_timeout, - .ndo_validate_addr = eth_validate_addr, -}; - -/*---------------------------------------------------------------- - * wlan_setup - * - * Roughly matches the functionality of ether_setup. Here - * we set up any members of the wlandevice structure that are common - * to all devices. Additionally, we allocate a linux 'struct device' - * and perform the same setup as ether_setup. - * - * Note: It's important that the caller have setup the wlandev->name - * ptr prior to calling this function. - * - * Arguments: - * wlandev ptr to the wlandev structure for the - * interface. - * physdev ptr to usb device - * Returns: - * zero on success, non-zero otherwise. - * Call Context: - * Should be process thread. We'll assume it might be - * interrupt though. When we add support for statically - * compiled drivers, this function will be called in the - * context of the kernel startup code. - *---------------------------------------------------------------- - */ -int wlan_setup(struct wlandevice *wlandev, struct device *physdev) -{ - int result = 0; - struct net_device *netdev; - struct wiphy *wiphy; - struct wireless_dev *wdev; - - /* Set up the wlandev */ - wlandev->state = WLAN_DEVICE_CLOSED; - wlandev->ethconv = WLAN_ETHCONV_8021h; - wlandev->macmode = WLAN_MACMODE_NONE; - - /* Set up the rx queue */ - skb_queue_head_init(&wlandev->nsd_rxq); - tasklet_setup(&wlandev->rx_bh, p80211netdev_rx_bh); - - /* Allocate and initialize the wiphy struct */ - wiphy = wlan_create_wiphy(physdev, wlandev); - if (!wiphy) { - dev_err(physdev, "Failed to alloc wiphy.\n"); - return 1; - } - - /* Allocate and initialize the struct device */ - netdev = alloc_netdev(sizeof(struct wireless_dev), "wlan%d", - NET_NAME_UNKNOWN, ether_setup); - if (!netdev) { - dev_err(physdev, "Failed to alloc netdev.\n"); - wlan_free_wiphy(wiphy); - result = 1; - } else { - wlandev->netdev = netdev; - netdev->ml_priv = wlandev; - netdev->netdev_ops = &p80211_netdev_ops; - wdev = netdev_priv(netdev); - wdev->wiphy = wiphy; - wdev->iftype = NL80211_IFTYPE_STATION; - netdev->ieee80211_ptr = wdev; - netdev->min_mtu = 68; - /* 2312 is max 802.11 payload, 20 is overhead, - * (ether + llc + snap) and another 8 for wep. - */ - netdev->max_mtu = (2312 - 20 - 8); - - netif_stop_queue(netdev); - netif_carrier_off(netdev); - } - - return result; -} - -/*---------------------------------------------------------------- - * wlan_teardown - * - * This function is paired with the wlan_setup routine. It should - * be called after unregister_wlandev. Basically, all it does is - * free the 'struct device' that's associated with the wlandev. - * We do it here because the 'struct device' isn't allocated - * explicitly in the driver code, it's done in wlan_setup. To - * do the free in the driver might seem like 'magic'. - * - * Arguments: - * wlandev ptr to the wlandev structure for the - * interface. - * Call Context: - * Should be process thread. We'll assume it might be - * interrupt though. When we add support for statically - * compiled drivers, this function will be called in the - * context of the kernel startup code. - *---------------------------------------------------------------- - */ -void wlan_teardown(struct wlandevice *wlandev) -{ - struct wireless_dev *wdev; - - tasklet_kill(&wlandev->rx_bh); - - if (wlandev->netdev) { - wdev = netdev_priv(wlandev->netdev); - if (wdev->wiphy) - wlan_free_wiphy(wdev->wiphy); - free_netdev(wlandev->netdev); - wlandev->netdev = NULL; - } -} - -/*---------------------------------------------------------------- - * register_wlandev - * - * Roughly matches the functionality of register_netdev. This function - * is called after the driver has successfully probed and set up the - * resources for the device. It's now ready to become a named device - * in the Linux system. - * - * First we allocate a name for the device (if not already set), then - * we call the Linux function register_netdevice. - * - * Arguments: - * wlandev ptr to the wlandev structure for the - * interface. - * Returns: - * zero on success, non-zero otherwise. - * Call Context: - * Can be either interrupt or not. - *---------------------------------------------------------------- - */ -int register_wlandev(struct wlandevice *wlandev) -{ - return register_netdev(wlandev->netdev); -} - -/*---------------------------------------------------------------- - * unregister_wlandev - * - * Roughly matches the functionality of unregister_netdev. This - * function is called to remove a named device from the system. - * - * First we tell linux that the device should no longer exist. - * Then we remove it from the list of known wlan devices. - * - * Arguments: - * wlandev ptr to the wlandev structure for the - * interface. - * Returns: - * zero on success, non-zero otherwise. - * Call Context: - * Can be either interrupt or not. - *---------------------------------------------------------------- - */ -int unregister_wlandev(struct wlandevice *wlandev) -{ - struct sk_buff *skb; - - unregister_netdev(wlandev->netdev); - - /* Now to clean out the rx queue */ - while ((skb = skb_dequeue(&wlandev->nsd_rxq))) - dev_kfree_skb(skb); - - return 0; -} - -/*---------------------------------------------------------------- - * p80211netdev_hwremoved - * - * Hardware removed notification. This function should be called - * immediately after an MSD has detected that the underlying hardware - * has been yanked out from under us. The primary things we need - * to do are: - * - Mark the wlandev - * - Prevent any further traffic from the knetdev i/f - * - Prevent any further requests from mgmt i/f - * - If there are any waitq'd mgmt requests or mgmt-frame exchanges, - * shut them down. - * - Call the MSD hwremoved function. - * - * The remainder of the cleanup will be handled by unregister(). - * Our primary goal here is to prevent as much tickling of the MSD - * as possible since the MSD is already in a 'wounded' state. - * - * TODO: As new features are added, this function should be - * updated. - * - * Arguments: - * wlandev WLAN network device structure - * Returns: - * nothing - * Side effects: - * - * Call context: - * Usually interrupt. - *---------------------------------------------------------------- - */ -void p80211netdev_hwremoved(struct wlandevice *wlandev) -{ - wlandev->hwremoved = 1; - if (wlandev->state == WLAN_DEVICE_OPEN) - netif_stop_queue(wlandev->netdev); - - netif_device_detach(wlandev->netdev); -} - -/*---------------------------------------------------------------- - * p80211_rx_typedrop - * - * Classifies the frame, increments the appropriate counter, and - * returns 0|1|2 indicating whether the driver should handle, ignore, or - * drop the frame - * - * Arguments: - * wlandev wlan device structure - * fc frame control field - * - * Returns: - * zero if the frame should be handled by the driver, - * one if the frame should be ignored - * anything else means we drop it. - * - * Side effects: - * - * Call context: - * interrupt - *---------------------------------------------------------------- - */ -static int p80211_rx_typedrop(struct wlandevice *wlandev, u16 fc) -{ - u16 ftype; - u16 fstype; - int drop = 0; - /* Classify frame, increment counter */ - ftype = WLAN_GET_FC_FTYPE(fc); - fstype = WLAN_GET_FC_FSTYPE(fc); - switch (ftype) { - case WLAN_FTYPE_MGMT: - if ((wlandev->netdev->flags & IFF_PROMISC) || - (wlandev->netdev->flags & IFF_ALLMULTI)) { - drop = 1; - break; - } - netdev_dbg(wlandev->netdev, "rx'd mgmt:\n"); - wlandev->rx.mgmt++; - switch (fstype) { - case WLAN_FSTYPE_ASSOCREQ: - wlandev->rx.assocreq++; - break; - case WLAN_FSTYPE_ASSOCRESP: - wlandev->rx.assocresp++; - break; - case WLAN_FSTYPE_REASSOCREQ: - wlandev->rx.reassocreq++; - break; - case WLAN_FSTYPE_REASSOCRESP: - wlandev->rx.reassocresp++; - break; - case WLAN_FSTYPE_PROBEREQ: - wlandev->rx.probereq++; - break; - case WLAN_FSTYPE_PROBERESP: - wlandev->rx.proberesp++; - break; - case WLAN_FSTYPE_BEACON: - wlandev->rx.beacon++; - break; - case WLAN_FSTYPE_ATIM: - wlandev->rx.atim++; - break; - case WLAN_FSTYPE_DISASSOC: - wlandev->rx.disassoc++; - break; - case WLAN_FSTYPE_AUTHEN: - wlandev->rx.authen++; - break; - case WLAN_FSTYPE_DEAUTHEN: - wlandev->rx.deauthen++; - break; - default: - wlandev->rx.mgmt_unknown++; - break; - } - drop = 2; - break; - - case WLAN_FTYPE_CTL: - if ((wlandev->netdev->flags & IFF_PROMISC) || - (wlandev->netdev->flags & IFF_ALLMULTI)) { - drop = 1; - break; - } - netdev_dbg(wlandev->netdev, "rx'd ctl:\n"); - wlandev->rx.ctl++; - switch (fstype) { - case WLAN_FSTYPE_PSPOLL: - wlandev->rx.pspoll++; - break; - case WLAN_FSTYPE_RTS: - wlandev->rx.rts++; - break; - case WLAN_FSTYPE_CTS: - wlandev->rx.cts++; - break; - case WLAN_FSTYPE_ACK: - wlandev->rx.ack++; - break; - case WLAN_FSTYPE_CFEND: - wlandev->rx.cfend++; - break; - case WLAN_FSTYPE_CFENDCFACK: - wlandev->rx.cfendcfack++; - break; - default: - wlandev->rx.ctl_unknown++; - break; - } - drop = 2; - break; - - case WLAN_FTYPE_DATA: - wlandev->rx.data++; - switch (fstype) { - case WLAN_FSTYPE_DATAONLY: - wlandev->rx.dataonly++; - break; - case WLAN_FSTYPE_DATA_CFACK: - wlandev->rx.data_cfack++; - break; - case WLAN_FSTYPE_DATA_CFPOLL: - wlandev->rx.data_cfpoll++; - break; - case WLAN_FSTYPE_DATA_CFACK_CFPOLL: - wlandev->rx.data__cfack_cfpoll++; - break; - case WLAN_FSTYPE_NULL: - netdev_dbg(wlandev->netdev, "rx'd data:null\n"); - wlandev->rx.null++; - break; - case WLAN_FSTYPE_CFACK: - netdev_dbg(wlandev->netdev, "rx'd data:cfack\n"); - wlandev->rx.cfack++; - break; - case WLAN_FSTYPE_CFPOLL: - netdev_dbg(wlandev->netdev, "rx'd data:cfpoll\n"); - wlandev->rx.cfpoll++; - break; - case WLAN_FSTYPE_CFACK_CFPOLL: - netdev_dbg(wlandev->netdev, "rx'd data:cfack_cfpoll\n"); - wlandev->rx.cfack_cfpoll++; - break; - default: - wlandev->rx.data_unknown++; - break; - } - - break; - } - return drop; -} - -static void p80211knetdev_tx_timeout(struct net_device *netdev, unsigned int txqueue) -{ - struct wlandevice *wlandev = netdev->ml_priv; - - if (wlandev->tx_timeout) { - wlandev->tx_timeout(wlandev); - } else { - netdev_warn(netdev, "Implement tx_timeout for %s\n", - wlandev->nsdname); - netif_wake_queue(wlandev->netdev); - } -} diff --git a/drivers/staging/wlan-ng/p80211netdev.h b/drivers/staging/wlan-ng/p80211netdev.h deleted file mode 100644 index e3eefb67aae1..000000000000 --- a/drivers/staging/wlan-ng/p80211netdev.h +++ /dev/null @@ -1,212 +0,0 @@ -/* SPDX-License-Identifier: (GPL-2.0 OR MPL-1.1) */ -/* - * - * WLAN net device structure and functions - * - * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. - * -------------------------------------------------------------------- - * - * linux-wlan - * - * -------------------------------------------------------------------- - * - * Inquiries regarding the linux-wlan Open Source project can be - * made directly to: - * - * AbsoluteValue Systems Inc. - * info@linux-wlan.com - * http://www.linux-wlan.com - * - * -------------------------------------------------------------------- - * - * Portions of the development of this software were funded by - * Intersil Corporation as part of PRISM(R) chipset product development. - * - * -------------------------------------------------------------------- - * - * This file declares the structure type that represents each wlan - * interface. - * - * -------------------------------------------------------------------- - */ - -#ifndef _LINUX_P80211NETDEV_H -#define _LINUX_P80211NETDEV_H - -#include -#include -#include - -#define WLAN_RELEASE "0.3.0-staging" - -#define WLAN_DEVICE_CLOSED 0 -#define WLAN_DEVICE_OPEN 1 - -#define WLAN_MACMODE_NONE 0 -#define WLAN_MACMODE_IBSS_STA 1 -#define WLAN_MACMODE_ESS_STA 2 -#define WLAN_MACMODE_ESS_AP 3 - -/* MSD States */ -#define WLAN_MSD_HWPRESENT_PENDING 1 -#define WLAN_MSD_HWFAIL 2 -#define WLAN_MSD_HWPRESENT 3 -#define WLAN_MSD_FWLOAD_PENDING 4 -#define WLAN_MSD_FWLOAD 5 -#define WLAN_MSD_RUNNING_PENDING 6 -#define WLAN_MSD_RUNNING 7 - -#ifndef ETH_P_ECONET -#define ETH_P_ECONET 0x0018 /* needed for 2.2.x kernels */ -#endif - -#define ETH_P_80211_RAW (ETH_P_ECONET + 1) - -#ifndef ARPHRD_IEEE80211 -#define ARPHRD_IEEE80211 801 /* kernel 2.4.6 */ -#endif - -#ifndef ARPHRD_IEEE80211_PRISM /* kernel 2.4.18 */ -#define ARPHRD_IEEE80211_PRISM 802 -#endif - -/*--- NSD Capabilities Flags ------------------------------*/ -#define P80211_NSDCAP_HARDWAREWEP 0x01 /* hardware wep engine */ -#define P80211_NSDCAP_SHORT_PREAMBLE 0x10 /* hardware supports */ -#define P80211_NSDCAP_HWFRAGMENT 0x80 /* nsd handles frag/defrag */ -#define P80211_NSDCAP_AUTOJOIN 0x100 /* nsd does autojoin */ -#define P80211_NSDCAP_NOSCAN 0x200 /* nsd can scan */ - -/* Received frame statistics */ -struct p80211_frmrx { - u32 mgmt; - u32 assocreq; - u32 assocresp; - u32 reassocreq; - u32 reassocresp; - u32 probereq; - u32 proberesp; - u32 beacon; - u32 atim; - u32 disassoc; - u32 authen; - u32 deauthen; - u32 mgmt_unknown; - u32 ctl; - u32 pspoll; - u32 rts; - u32 cts; - u32 ack; - u32 cfend; - u32 cfendcfack; - u32 ctl_unknown; - u32 data; - u32 dataonly; - u32 data_cfack; - u32 data_cfpoll; - u32 data__cfack_cfpoll; - u32 null; - u32 cfack; - u32 cfpoll; - u32 cfack_cfpoll; - u32 data_unknown; - u32 decrypt; - u32 decrypt_err; -}; - -/* WEP stuff */ -#define NUM_WEPKEYS 4 -#define MAX_KEYLEN 32 - -#define HOSTWEP_DEFAULTKEY_MASK GENMASK(1, 0) -#define HOSTWEP_SHAREDKEY BIT(3) -#define HOSTWEP_DECRYPT BIT(4) -#define HOSTWEP_ENCRYPT BIT(5) -#define HOSTWEP_PRIVACYINVOKED BIT(6) -#define HOSTWEP_EXCLUDEUNENCRYPTED BIT(7) - -extern int wlan_watchdog; -extern int wlan_wext_write; - -/* WLAN device type */ -struct wlandevice { - void *priv; /* private data for MSD */ - - /* Subsystem State */ - char name[WLAN_DEVNAMELEN_MAX]; /* Dev name, from register_wlandev() */ - char *nsdname; - - u32 state; /* Device I/F state (open/closed) */ - u32 msdstate; /* state of underlying driver */ - u32 hwremoved; /* Has the hw been yanked out? */ - - /* Hardware config */ - unsigned int irq; - unsigned int iobase; - unsigned int membase; - u32 nsdcaps; /* NSD Capabilities flags */ - - /* Config vars */ - unsigned int ethconv; - - /* device methods (init by MSD, used by p80211 */ - int (*open)(struct wlandevice *wlandev); - int (*close)(struct wlandevice *wlandev); - void (*reset)(struct wlandevice *wlandev); - int (*txframe)(struct wlandevice *wlandev, struct sk_buff *skb, - struct p80211_hdr *p80211_hdr, - struct p80211_metawep *p80211_wep); - int (*mlmerequest)(struct wlandevice *wlandev, struct p80211msg *msg); - int (*set_multicast_list)(struct wlandevice *wlandev, - struct net_device *dev); - void (*tx_timeout)(struct wlandevice *wlandev); - - /* 802.11 State */ - u8 bssid[WLAN_BSSID_LEN]; - struct p80211pstr32 ssid; - u32 macmode; - int linkstatus; - - /* WEP State */ - u8 wep_keys[NUM_WEPKEYS][MAX_KEYLEN]; - u8 wep_keylens[NUM_WEPKEYS]; - int hostwep; - - /* Request/Confirm i/f state (used by p80211) */ - unsigned long request_pending; /* flag, access atomically */ - - /* netlink socket */ - /* queue for indications waiting for cmd completion */ - /* Linux netdevice and support */ - struct net_device *netdev; /* ptr to linux netdevice */ - - /* Rx bottom half */ - struct tasklet_struct rx_bh; - - struct sk_buff_head nsd_rxq; - - /* 802.11 device statistics */ - struct p80211_frmrx rx; - - struct iw_statistics wstats; - - /* jkriegl: iwspy fields */ - u8 spy_number; - char spy_address[IW_MAX_SPY][ETH_ALEN]; - struct iw_quality spy_stat[IW_MAX_SPY]; -}; - -/* WEP stuff */ -int wep_change_key(struct wlandevice *wlandev, int keynum, u8 *key, int keylen); -int wep_decrypt(struct wlandevice *wlandev, u8 *buf, u32 len, int key_override, - u8 *iv, u8 *icv); -int wep_encrypt(struct wlandevice *wlandev, u8 *buf, u8 *dst, u32 len, - int keynum, u8 *iv, u8 *icv); - -int wlan_setup(struct wlandevice *wlandev, struct device *physdev); -void wlan_teardown(struct wlandevice *wlandev); -int register_wlandev(struct wlandevice *wlandev); -int unregister_wlandev(struct wlandevice *wlandev); -void p80211netdev_rx(struct wlandevice *wlandev, struct sk_buff *skb); -void p80211netdev_hwremoved(struct wlandevice *wlandev); -#endif diff --git a/drivers/staging/wlan-ng/p80211req.c b/drivers/staging/wlan-ng/p80211req.c deleted file mode 100644 index 6ec559ffd2f9..000000000000 --- a/drivers/staging/wlan-ng/p80211req.c +++ /dev/null @@ -1,223 +0,0 @@ -// SPDX-License-Identifier: (GPL-2.0 OR MPL-1.1) -/* - * - * Request/Indication/MacMgmt interface handling functions - * - * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. - * -------------------------------------------------------------------- - * - * linux-wlan - * - * -------------------------------------------------------------------- - * - * Inquiries regarding the linux-wlan Open Source project can be - * made directly to: - * - * AbsoluteValue Systems Inc. - * info@linux-wlan.com - * http://www.linux-wlan.com - * - * -------------------------------------------------------------------- - * - * Portions of the development of this software were funded by - * Intersil Corporation as part of PRISM(R) chipset product development. - * - * -------------------------------------------------------------------- - * - * This file contains the functions, types, and macros to support the - * MLME request interface that's implemented via the device ioctls. - * - * -------------------------------------------------------------------- - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "p80211types.h" -#include "p80211hdr.h" -#include "p80211mgmt.h" -#include "p80211conv.h" -#include "p80211msg.h" -#include "p80211netdev.h" -#include "p80211ioctl.h" -#include "p80211metadef.h" -#include "p80211metastruct.h" -#include "p80211req.h" - -static void p80211req_handlemsg(struct wlandevice *wlandev, - struct p80211msg *msg); -static void p80211req_mibset_mibget(struct wlandevice *wlandev, - struct p80211msg_dot11req_mibget *mib_msg, - int isget); - -static void p80211req_handle_action(struct wlandevice *wlandev, u32 *data, - int isget, u32 flag) -{ - if (isget) { - if (wlandev->hostwep & flag) - *data = P80211ENUM_truth_true; - else - *data = P80211ENUM_truth_false; - } else { - wlandev->hostwep &= ~flag; - if (*data == P80211ENUM_truth_true) - wlandev->hostwep |= flag; - } -} - -/*---------------------------------------------------------------- - * p80211req_dorequest - * - * Handles an MLME request/confirm message. - * - * Arguments: - * wlandev WLAN device struct - * msgbuf Buffer containing a request message - * - * Returns: - * 0 on success, an errno otherwise - * - * Call context: - * Potentially blocks the caller, so it's a good idea to - * not call this function from an interrupt context. - *---------------------------------------------------------------- - */ -int p80211req_dorequest(struct wlandevice *wlandev, u8 *msgbuf) -{ - struct p80211msg *msg = (struct p80211msg *)msgbuf; - - /* Check to make sure the MSD is running */ - if (!((wlandev->msdstate == WLAN_MSD_HWPRESENT && - msg->msgcode == DIDMSG_LNXREQ_IFSTATE) || - wlandev->msdstate == WLAN_MSD_RUNNING || - wlandev->msdstate == WLAN_MSD_FWLOAD)) { - return -ENODEV; - } - - /* Check Permissions */ - if (!capable(CAP_NET_ADMIN) && - (msg->msgcode != DIDMSG_DOT11REQ_MIBGET)) { - netdev_err(wlandev->netdev, - "%s: only dot11req_mibget allowed for non-root.\n", - wlandev->name); - return -EPERM; - } - - /* Check for busy status */ - if (test_and_set_bit(1, &wlandev->request_pending)) - return -EBUSY; - - /* Allow p80211 to look at msg and handle if desired. */ - /* So far, all p80211 msgs are immediate, no waitq/timer necessary */ - /* This may change. */ - p80211req_handlemsg(wlandev, msg); - - /* Pass it down to wlandev via wlandev->mlmerequest */ - if (wlandev->mlmerequest) - wlandev->mlmerequest(wlandev, msg); - - clear_bit(1, &wlandev->request_pending); - return 0; /* if result==0, msg->status still may contain an err */ -} - -/*---------------------------------------------------------------- - * p80211req_handlemsg - * - * p80211 message handler. Primarily looks for messages that - * belong to p80211 and then dispatches the appropriate response. - * TODO: we don't do anything yet. Once the linuxMIB is better - * defined we'll need a get/set handler. - * - * Arguments: - * wlandev WLAN device struct - * msg message structure - * - * Returns: - * nothing (any results are set in the status field of the msg) - * - * Call context: - * Process thread - *---------------------------------------------------------------- - */ -static void p80211req_handlemsg(struct wlandevice *wlandev, - struct p80211msg *msg) -{ - switch (msg->msgcode) { - case DIDMSG_LNXREQ_HOSTWEP: { - struct p80211msg_lnxreq_hostwep *req = - (struct p80211msg_lnxreq_hostwep *)msg; - wlandev->hostwep &= - ~(HOSTWEP_DECRYPT | HOSTWEP_ENCRYPT); - if (req->decrypt.data == P80211ENUM_truth_true) - wlandev->hostwep |= HOSTWEP_DECRYPT; - if (req->encrypt.data == P80211ENUM_truth_true) - wlandev->hostwep |= HOSTWEP_ENCRYPT; - - break; - } - case DIDMSG_DOT11REQ_MIBGET: - case DIDMSG_DOT11REQ_MIBSET: { - int isget = (msg->msgcode == DIDMSG_DOT11REQ_MIBGET); - struct p80211msg_dot11req_mibget *mib_msg = - (struct p80211msg_dot11req_mibget *)msg; - p80211req_mibset_mibget(wlandev, mib_msg, isget); - break; - } - } /* switch msg->msgcode */ -} - -static void p80211req_mibset_mibget(struct wlandevice *wlandev, - struct p80211msg_dot11req_mibget *mib_msg, - int isget) -{ - struct p80211itemd *mibitem = - (struct p80211itemd *)mib_msg->mibattribute.data; - struct p80211pstrd *pstr = (struct p80211pstrd *)mibitem->data; - u8 *key = mibitem->data + sizeof(struct p80211pstrd); - - switch (mibitem->did) { - case didmib_dot11smt_wepdefaultkeystable_key(1): - case didmib_dot11smt_wepdefaultkeystable_key(2): - case didmib_dot11smt_wepdefaultkeystable_key(3): - case didmib_dot11smt_wepdefaultkeystable_key(4): - if (!isget) - wep_change_key(wlandev, - P80211DID_ITEM(mibitem->did) - 1, - key, pstr->len); - break; - - case DIDMIB_DOT11SMT_PRIVACYTABLE_WEPDEFAULTKEYID: { - u32 *data = (u32 *)mibitem->data; - - if (isget) { - *data = wlandev->hostwep & HOSTWEP_DEFAULTKEY_MASK; - } else { - wlandev->hostwep &= ~(HOSTWEP_DEFAULTKEY_MASK); - wlandev->hostwep |= (*data & HOSTWEP_DEFAULTKEY_MASK); - } - break; - } - case DIDMIB_DOT11SMT_PRIVACYTABLE_PRIVACYINVOKED: { - u32 *data = (u32 *)mibitem->data; - - p80211req_handle_action(wlandev, data, isget, - HOSTWEP_PRIVACYINVOKED); - break; - } - case DIDMIB_DOT11SMT_PRIVACYTABLE_EXCLUDEUNENCRYPTED: { - u32 *data = (u32 *)mibitem->data; - - p80211req_handle_action(wlandev, data, isget, - HOSTWEP_EXCLUDEUNENCRYPTED); - break; - } - } -} diff --git a/drivers/staging/wlan-ng/p80211req.h b/drivers/staging/wlan-ng/p80211req.h deleted file mode 100644 index 39213f73913c..000000000000 --- a/drivers/staging/wlan-ng/p80211req.h +++ /dev/null @@ -1,33 +0,0 @@ -/* SPDX-License-Identifier: (GPL-2.0 OR MPL-1.1) */ -/* - * - * Request handling functions - * - * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. - * -------------------------------------------------------------------- - * - * linux-wlan - * - * -------------------------------------------------------------------- - * - * Inquiries regarding the linux-wlan Open Source project can be - * made directly to: - * - * AbsoluteValue Systems Inc. - * info@linux-wlan.com - * http://www.linux-wlan.com - * - * -------------------------------------------------------------------- - * - * Portions of the development of this software were funded by - * Intersil Corporation as part of PRISM(R) chipset product development. - * - * -------------------------------------------------------------------- - */ - -#ifndef _LINUX_P80211REQ_H -#define _LINUX_P80211REQ_H - -int p80211req_dorequest(struct wlandevice *wlandev, u8 *msgbuf); - -#endif diff --git a/drivers/staging/wlan-ng/p80211types.h b/drivers/staging/wlan-ng/p80211types.h deleted file mode 100644 index 5e4ea5f92058..000000000000 --- a/drivers/staging/wlan-ng/p80211types.h +++ /dev/null @@ -1,292 +0,0 @@ -/* SPDX-License-Identifier: (GPL-2.0 OR MPL-1.1) */ -/* - * - * - * Macros, constants, types, and funcs for p80211 data types - * - * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. - * -------------------------------------------------------------------- - * - * linux-wlan - * - * -------------------------------------------------------------------- - * - * Inquiries regarding the linux-wlan Open Source project can be - * made directly to: - * - * AbsoluteValue Systems Inc. - * info@linux-wlan.com - * http://www.linux-wlan.com - * - * -------------------------------------------------------------------- - * - * Portions of the development of this software were funded by - * Intersil Corporation as part of PRISM(R) chipset product development. - * - * -------------------------------------------------------------------- - * - * This file declares some of the constants and types used in various - * parts of the linux-wlan system. - * - * Notes: - * - Constant values are always in HOST byte order. - * - * All functions and statics declared here are implemented in p80211types.c - * -------------------------------------------------------------------- - */ - -#ifndef _P80211TYPES_H -#define _P80211TYPES_H - -/*----------------------------------------------------------------*/ -/* The following constants are indexes into the Mib Category List */ -/* and the Message Category List */ - -/* Mib Category List */ -#define P80211_MIB_CAT_DOT11SMT 1 -#define P80211_MIB_CAT_DOT11MAC 2 -#define P80211_MIB_CAT_DOT11PHY 3 - -#define P80211SEC_DOT11SMT P80211_MIB_CAT_DOT11SMT -#define P80211SEC_DOT11MAC P80211_MIB_CAT_DOT11MAC -#define P80211SEC_DOT11PHY P80211_MIB_CAT_DOT11PHY - -/* Message Category List */ -#define P80211_MSG_CAT_DOT11REQ 1 -#define P80211_MSG_CAT_DOT11IND 2 - -/*----------------------------------------------------------------*/ -/* p80211 enumeration constants. The value to text mappings for */ -/* these is in p80211types.c. These defines were generated */ -/* from the mappings. */ - -/* error codes for lookups */ - -#define P80211ENUM_truth_false 0 -#define P80211ENUM_truth_true 1 -#define P80211ENUM_ifstate_disable 0 -#define P80211ENUM_ifstate_fwload 1 -#define P80211ENUM_ifstate_enable 2 -#define P80211ENUM_bsstype_infrastructure 1 -#define P80211ENUM_bsstype_independent 2 -#define P80211ENUM_bsstype_any 3 -#define P80211ENUM_authalg_opensystem 1 -#define P80211ENUM_authalg_sharedkey 2 -#define P80211ENUM_scantype_active 1 -#define P80211ENUM_resultcode_success 1 -#define P80211ENUM_resultcode_invalid_parameters 2 -#define P80211ENUM_resultcode_not_supported 3 -#define P80211ENUM_resultcode_refused 6 -#define P80211ENUM_resultcode_cant_set_readonly_mib 10 -#define P80211ENUM_resultcode_implementation_failure 11 -#define P80211ENUM_resultcode_cant_get_writeonly_mib 12 -#define P80211ENUM_status_successful 0 -#define P80211ENUM_status_unspec_failure 1 -#define P80211ENUM_status_ap_full 17 -#define P80211ENUM_msgitem_status_data_ok 0 -#define P80211ENUM_msgitem_status_no_value 1 - -/*----------------------------------------------------------------*/ -/* p80211 max length constants for the different pascal strings. */ - -#define MAXLEN_PSTR6 (6) /* pascal array of 6 bytes */ -#define MAXLEN_PSTR14 (14) /* pascal array of 14 bytes */ -#define MAXLEN_PSTR32 (32) /* pascal array of 32 bytes */ -#define MAXLEN_PSTR255 (255) /* pascal array of 255 bytes */ -#define MAXLEN_MIBATTRIBUTE (392) /* maximum mibattribute */ - /* where the size of the DATA itself */ - /* is a DID-LEN-DATA triple */ - /* with a max size of 4+4+384 */ - -/*---------------------------------------------------------------- - * The following constants and macros are used to construct and - * deconstruct the Data ID codes. The coding is as follows: - * - * ...rwtnnnnnnnniiiiiiggggggssssss s - Section - * g - Group - * i - Item - * n - Index - * t - Table flag - * w - Write flag - * r - Read flag - * . - Unused - */ - -#define P80211DID_LSB_SECTION (0) -#define P80211DID_LSB_GROUP (6) -#define P80211DID_LSB_ITEM (12) -#define P80211DID_LSB_INDEX (18) -#define P80211DID_LSB_ISTABLE (26) -#define P80211DID_LSB_ACCESS (27) - -#define P80211DID_MASK_SECTION (0x0000003fUL) -#define P80211DID_MASK_GROUP (0x0000003fUL) -#define P80211DID_MASK_ITEM (0x0000003fUL) -#define P80211DID_MASK_INDEX (0x000000ffUL) -#define P80211DID_MASK_ISTABLE (0x00000001UL) -#define P80211DID_MASK_ACCESS (0x00000003UL) - -#define P80211DID_MK(a, m, l) ((((u32)(a)) & (m)) << (l)) - -#define P80211DID_MKSECTION(a) P80211DID_MK(a, \ - P80211DID_MASK_SECTION, \ - P80211DID_LSB_SECTION) -#define P80211DID_MKGROUP(a) P80211DID_MK(a, \ - P80211DID_MASK_GROUP, \ - P80211DID_LSB_GROUP) -#define P80211DID_MKITEM(a) P80211DID_MK(a, \ - P80211DID_MASK_ITEM, \ - P80211DID_LSB_ITEM) -#define P80211DID_MKINDEX(a) P80211DID_MK(a, \ - P80211DID_MASK_INDEX, \ - P80211DID_LSB_INDEX) -#define P80211DID_MKISTABLE(a) P80211DID_MK(a, \ - P80211DID_MASK_ISTABLE, \ - P80211DID_LSB_ISTABLE) - -#define P80211DID_MKID(s, g, i, n, t, a) (P80211DID_MKSECTION(s) | \ - P80211DID_MKGROUP(g) | \ - P80211DID_MKITEM(i) | \ - P80211DID_MKINDEX(n) | \ - P80211DID_MKISTABLE(t) | \ - (a)) - -#define P80211DID_GET(a, m, l) ((((u32)(a)) >> (l)) & (m)) - -#define P80211DID_SECTION(a) P80211DID_GET(a, \ - P80211DID_MASK_SECTION, \ - P80211DID_LSB_SECTION) -#define P80211DID_GROUP(a) P80211DID_GET(a, \ - P80211DID_MASK_GROUP, \ - P80211DID_LSB_GROUP) -#define P80211DID_ITEM(a) P80211DID_GET(a, \ - P80211DID_MASK_ITEM, \ - P80211DID_LSB_ITEM) -#define P80211DID_INDEX(a) P80211DID_GET(a, \ - P80211DID_MASK_INDEX, \ - P80211DID_LSB_INDEX) -#define P80211DID_ISTABLE(a) P80211DID_GET(a, \ - P80211DID_MASK_ISTABLE, \ - P80211DID_LSB_ISTABLE) -#define P80211DID_ACCESS(a) P80211DID_GET(a, \ - P80211DID_MASK_ACCESS, \ - P80211DID_LSB_ACCESS) - -/*----------------------------------------------------------------*/ -/* The following structure types are used to store data items in */ -/* messages. */ - -/* Template pascal string */ -struct p80211pstr { - u8 len; -} __packed; - -struct p80211pstrd { - u8 len; - u8 data[]; -} __packed; - -/* Maximum pascal string */ -struct p80211pstr255 { - u8 len; - u8 data[MAXLEN_PSTR255]; -} __packed; - -/* pascal string for macaddress and bssid */ -struct p80211pstr6 { - u8 len; - u8 data[MAXLEN_PSTR6]; -} __packed; - -/* pascal string for channel list */ -struct p80211pstr14 { - u8 len; - u8 data[MAXLEN_PSTR14]; -} __packed; - -/* pascal string for ssid */ -struct p80211pstr32 { - u8 len; - u8 data[MAXLEN_PSTR32]; -} __packed; - -/* prototype template */ -struct p80211item { - u32 did; - u16 status; - u16 len; -} __packed; - -/* prototype template w/ data item */ -struct p80211itemd { - u32 did; - u16 status; - u16 len; - u8 data[]; -} __packed; - -/* message data item for int, BOUNDEDINT, ENUMINT */ -struct p80211item_uint32 { - u32 did; - u16 status; - u16 len; - u32 data; -} __packed; - -/* message data item for OCTETSTR, DISPLAYSTR */ -struct p80211item_pstr6 { - u32 did; - u16 status; - u16 len; - struct p80211pstr6 data; -} __packed; - -/* message data item for OCTETSTR, DISPLAYSTR */ -struct p80211item_pstr14 { - u32 did; - u16 status; - u16 len; - struct p80211pstr14 data; -} __packed; - -/* message data item for OCTETSTR, DISPLAYSTR */ -struct p80211item_pstr32 { - u32 did; - u16 status; - u16 len; - struct p80211pstr32 data; -} __packed; - -/* message data item for OCTETSTR, DISPLAYSTR */ -struct p80211item_pstr255 { - u32 did; - u16 status; - u16 len; - struct p80211pstr255 data; -} __packed; - -/* message data item for UNK 392, namely mib items */ -struct p80211item_unk392 { - u32 did; - u16 status; - u16 len; - u8 data[MAXLEN_MIBATTRIBUTE]; -} __packed; - -/* message data item for UNK 1025, namely p2 pdas */ -struct p80211item_unk1024 { - u32 did; - u16 status; - u16 len; - u8 data[1024]; -} __packed; - -/* message data item for UNK 4096, namely p2 download chunks */ -struct p80211item_unk4096 { - u32 did; - u16 status; - u16 len; - u8 data[4096]; -} __packed; - -#endif /* _P80211TYPES_H */ diff --git a/drivers/staging/wlan-ng/p80211wep.c b/drivers/staging/wlan-ng/p80211wep.c deleted file mode 100644 index e7b26b057124..000000000000 --- a/drivers/staging/wlan-ng/p80211wep.c +++ /dev/null @@ -1,207 +0,0 @@ -// SPDX-License-Identifier: (GPL-2.0 OR MPL-1.1) -/* - * - * WEP encode/decode for P80211. - * - * Copyright (C) 2002 AbsoluteValue Systems, Inc. All Rights Reserved. - * -------------------------------------------------------------------- - * - * linux-wlan - * - * -------------------------------------------------------------------- - * - * Inquiries regarding the linux-wlan Open Source project can be - * made directly to: - * - * AbsoluteValue Systems Inc. - * info@linux-wlan.com - * http://www.linux-wlan.com - * - * -------------------------------------------------------------------- - * - * Portions of the development of this software were funded by - * Intersil Corporation as part of PRISM(R) chipset product development. - * - * -------------------------------------------------------------------- - */ - -/*================================================================*/ -/* System Includes */ - -#include -#include -#include -#include -#include -#include "p80211hdr.h" -#include "p80211types.h" -#include "p80211msg.h" -#include "p80211conv.h" -#include "p80211netdev.h" - -#define WEP_KEY(x) (((x) & 0xC0) >> 6) - -/* keylen in bytes! */ - -int wep_change_key(struct wlandevice *wlandev, int keynum, u8 *key, int keylen) -{ - if (keylen < 0) - return -1; - if (keylen >= MAX_KEYLEN) - return -1; - if (!key) - return -1; - if (keynum < 0) - return -1; - if (keynum >= NUM_WEPKEYS) - return -1; - - wlandev->wep_keylens[keynum] = keylen; - memcpy(wlandev->wep_keys[keynum], key, keylen); - - return 0; -} - -/* - * 4-byte IV at start of buffer, 4-byte ICV at end of buffer. - * if successful, buf start is payload begin, length -= 8; - */ -int wep_decrypt(struct wlandevice *wlandev, u8 *buf, u32 len, int key_override, - u8 *iv, u8 *icv) -{ - u32 i, j, k, crc, keylen; - u8 s[256], key[64], c_crc[4]; - u8 keyidx; - - /* Needs to be at least 8 bytes of payload */ - if (len <= 0) - return -1; - - /* initialize the first bytes of the key from the IV */ - key[0] = iv[0]; - key[1] = iv[1]; - key[2] = iv[2]; - keyidx = WEP_KEY(iv[3]); - - if (key_override >= 0) - keyidx = key_override; - - if (keyidx >= NUM_WEPKEYS) - return -2; - - keylen = wlandev->wep_keylens[keyidx]; - - if (keylen == 0) - return -3; - - /* copy the rest of the key over from the designated key */ - memcpy(key + 3, wlandev->wep_keys[keyidx], keylen); - - keylen += 3; /* add in IV bytes */ - - /* set up the RC4 state */ - for (i = 0; i < 256; i++) - s[i] = i; - j = 0; - for (i = 0; i < 256; i++) { - j = (j + s[i] + key[i % keylen]) & 0xff; - swap(i, j); - } - - /* Apply the RC4 to the data, update the CRC32 */ - i = 0; - j = 0; - for (k = 0; k < len; k++) { - i = (i + 1) & 0xff; - j = (j + s[i]) & 0xff; - swap(i, j); - buf[k] ^= s[(s[i] + s[j]) & 0xff]; - } - crc = ~crc32_le(~0, buf, len); - - /* now let's check the crc */ - c_crc[0] = crc; - c_crc[1] = crc >> 8; - c_crc[2] = crc >> 16; - c_crc[3] = crc >> 24; - - for (k = 0; k < 4; k++) { - i = (i + 1) & 0xff; - j = (j + s[i]) & 0xff; - swap(i, j); - if ((c_crc[k] ^ s[(s[i] + s[j]) & 0xff]) != icv[k]) - return -(4 | (k << 4)); /* ICV mismatch */ - } - - return 0; -} - -/* encrypts in-place. */ -int wep_encrypt(struct wlandevice *wlandev, u8 *buf, - u8 *dst, u32 len, int keynum, u8 *iv, u8 *icv) -{ - u32 i, j, k, crc, keylen; - u8 s[256], key[64]; - - /* no point in WEPping an empty frame */ - if (len <= 0) - return -1; - - /* we need to have a real key.. */ - if (keynum >= NUM_WEPKEYS) - return -2; - keylen = wlandev->wep_keylens[keynum]; - if (keylen <= 0) - return -3; - - /* use a random IV. And skip known weak ones. */ - get_random_bytes(iv, 3); - while ((iv[1] == 0xff) && (iv[0] >= 3) && (iv[0] < keylen)) - get_random_bytes(iv, 3); - - iv[3] = (keynum & 0x03) << 6; - - key[0] = iv[0]; - key[1] = iv[1]; - key[2] = iv[2]; - - /* copy the rest of the key over from the designated key */ - memcpy(key + 3, wlandev->wep_keys[keynum], keylen); - - keylen += 3; /* add in IV bytes */ - - /* set up the RC4 state */ - for (i = 0; i < 256; i++) - s[i] = i; - j = 0; - for (i = 0; i < 256; i++) { - j = (j + s[i] + key[i % keylen]) & 0xff; - swap(i, j); - } - - /* Update CRC32 then apply RC4 to the data */ - i = 0; - j = 0; - for (k = 0; k < len; k++) { - i = (i + 1) & 0xff; - j = (j + s[i]) & 0xff; - swap(i, j); - dst[k] = buf[k] ^ s[(s[i] + s[j]) & 0xff]; - } - crc = ~crc32_le(~0, buf, len); - - /* now let's encrypt the crc */ - icv[0] = crc; - icv[1] = crc >> 8; - icv[2] = crc >> 16; - icv[3] = crc >> 24; - - for (k = 0; k < 4; k++) { - i = (i + 1) & 0xff; - j = (j + s[i]) & 0xff; - swap(i, j); - icv[k] ^= s[(s[i] + s[j]) & 0xff]; - } - - return 0; -} diff --git a/drivers/staging/wlan-ng/prism2fw.c b/drivers/staging/wlan-ng/prism2fw.c deleted file mode 100644 index 3ccd11041646..000000000000 --- a/drivers/staging/wlan-ng/prism2fw.c +++ /dev/null @@ -1,1213 +0,0 @@ -// SPDX-License-Identifier: (GPL-2.0 OR MPL-1.1) -/* from src/prism2/download/prism2dl.c - * - * utility for downloading prism2 images moved into kernelspace - * - * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. - * -------------------------------------------------------------------- - * - * linux-wlan - * - * -------------------------------------------------------------------- - * - * Inquiries regarding the linux-wlan Open Source project can be - * made directly to: - * - * AbsoluteValue Systems Inc. - * info@linux-wlan.com - * http://www.linux-wlan.com - * - * -------------------------------------------------------------------- - * - * Portions of the development of this software were funded by - * Intersil Corporation as part of PRISM(R) chipset product development. - * - * -------------------------------------------------------------------- - */ - -/*================================================================*/ -/* System Includes */ -#include -#include - -/*================================================================*/ -/* Local Constants */ - -#define PRISM2_USB_FWFILE "prism2_ru.fw" -MODULE_FIRMWARE(PRISM2_USB_FWFILE); - -#define S3DATA_MAX 5000 -#define S3PLUG_MAX 200 -#define S3CRC_MAX 200 -#define S3INFO_MAX 50 - -#define S3ADDR_PLUG (0xff000000UL) -#define S3ADDR_CRC (0xff100000UL) -#define S3ADDR_INFO (0xff200000UL) -#define S3ADDR_START (0xff400000UL) - -#define CHUNKS_MAX 100 - -#define WRITESIZE_MAX 4096 - -/*================================================================*/ -/* Local Types */ - -struct s3datarec { - u32 len; - u32 addr; - u8 checksum; - u8 *data; -}; - -struct s3plugrec { - u32 itemcode; - u32 addr; - u32 len; -}; - -struct s3crcrec { - u32 addr; - u32 len; - unsigned int dowrite; -}; - -struct s3inforec { - u16 len; - u16 type; - union { - struct hfa384x_compident version; - struct hfa384x_caplevel compat; - u16 buildseq; - struct hfa384x_compident platform; - } info; -}; - -struct pda { - u8 buf[HFA384x_PDA_LEN_MAX]; - struct hfa384x_pdrec *rec[HFA384x_PDA_RECS_MAX]; - unsigned int nrec; -}; - -struct imgchunk { - u32 addr; /* start address */ - u32 len; /* in bytes */ - u16 crc; /* CRC value (if it falls at a chunk boundary) */ - u8 *data; -}; - -/*================================================================*/ -/* Local Static Definitions */ - -/*----------------------------------------------------------------*/ -/* s-record image processing */ - -/* Data records */ -static unsigned int ns3data; -static struct s3datarec *s3data; - -/* Plug records */ -static unsigned int ns3plug; -static struct s3plugrec s3plug[S3PLUG_MAX]; - -/* CRC records */ -static unsigned int ns3crc; -static struct s3crcrec s3crc[S3CRC_MAX]; - -/* Info records */ -static unsigned int ns3info; -static struct s3inforec s3info[S3INFO_MAX]; - -/* S7 record (there _better_ be only one) */ -static u32 startaddr; - -/* Load image chunks */ -static unsigned int nfchunks; -static struct imgchunk fchunk[CHUNKS_MAX]; - -/* Note that for the following pdrec_t arrays, the len and code */ -/* fields are stored in HOST byte order. The mkpdrlist() function */ -/* does the conversion. */ -/*----------------------------------------------------------------*/ -/* PDA, built from [card|newfile]+[addfile1+addfile2...] */ - -static struct pda pda; -static struct hfa384x_compident nicid; -static struct hfa384x_caplevel rfid; -static struct hfa384x_caplevel macid; -static struct hfa384x_caplevel priid; - -/*================================================================*/ -/* Local Function Declarations */ - -static int prism2_fwapply(const struct ihex_binrec *rfptr, - struct wlandevice *wlandev); - -static int read_fwfile(const struct ihex_binrec *rfptr); - -static int mkimage(struct imgchunk *clist, unsigned int *ccnt); - -static int read_cardpda(struct pda *pda, struct wlandevice *wlandev); - -static int mkpdrlist(struct pda *pda); - -static int plugimage(struct imgchunk *fchunk, unsigned int nfchunks, - struct s3plugrec *s3plug, unsigned int ns3plug, - struct pda *pda); - -static int crcimage(struct imgchunk *fchunk, unsigned int nfchunks, - struct s3crcrec *s3crc, unsigned int ns3crc); - -static int writeimage(struct wlandevice *wlandev, struct imgchunk *fchunk, - unsigned int nfchunks); - -static void free_chunks(struct imgchunk *fchunk, unsigned int *nfchunks); - -static void free_srecs(void); - -static int validate_identity(void); - -/*================================================================*/ -/* Function Definitions */ - -/*---------------------------------------------------------------- - * prism2_fwtry - * - * Try and get firmware into memory - * - * Arguments: - * udev usb device structure - * wlandev wlan device structure - * - * Returns: - * 0 - success - * ~0 - failure - *---------------------------------------------------------------- - */ -static int prism2_fwtry(struct usb_device *udev, struct wlandevice *wlandev) -{ - const struct firmware *fw_entry = NULL; - - netdev_info(wlandev->netdev, "prism2_usb: Checking for firmware %s\n", - PRISM2_USB_FWFILE); - if (request_ihex_firmware(&fw_entry, - PRISM2_USB_FWFILE, &udev->dev) != 0) { - netdev_info(wlandev->netdev, - "prism2_usb: Firmware not available, but not essential\n"); - netdev_info(wlandev->netdev, - "prism2_usb: can continue to use card anyway.\n"); - return 1; - } - - netdev_info(wlandev->netdev, - "prism2_usb: %s will be processed, size %zu\n", - PRISM2_USB_FWFILE, fw_entry->size); - prism2_fwapply((const struct ihex_binrec *)fw_entry->data, wlandev); - - release_firmware(fw_entry); - return 0; -} - -/*---------------------------------------------------------------- - * prism2_fwapply - * - * Apply the firmware loaded into memory - * - * Arguments: - * rfptr firmware image in kernel memory - * wlandev device - * - * Returns: - * 0 - success - * ~0 - failure - *---------------------------------------------------------------- - */ -static int prism2_fwapply(const struct ihex_binrec *rfptr, - struct wlandevice *wlandev) -{ - signed int result = 0; - struct p80211msg_dot11req_mibget getmsg; - struct p80211itemd *item; - u32 *data; - - /* Initialize the data structures */ - ns3data = 0; - s3data = kcalloc(S3DATA_MAX, sizeof(*s3data), GFP_KERNEL); - if (!s3data) { - result = -ENOMEM; - goto out; - } - - ns3plug = 0; - memset(s3plug, 0, sizeof(s3plug)); - ns3crc = 0; - memset(s3crc, 0, sizeof(s3crc)); - ns3info = 0; - memset(s3info, 0, sizeof(s3info)); - startaddr = 0; - - nfchunks = 0; - memset(fchunk, 0, sizeof(fchunk)); - memset(&nicid, 0, sizeof(nicid)); - memset(&rfid, 0, sizeof(rfid)); - memset(&macid, 0, sizeof(macid)); - memset(&priid, 0, sizeof(priid)); - - /* clear the pda and add an initial END record */ - memset(&pda, 0, sizeof(pda)); - pda.rec[0] = (struct hfa384x_pdrec *)pda.buf; - pda.rec[0]->len = cpu_to_le16(2); /* len in words */ - pda.rec[0]->code = cpu_to_le16(HFA384x_PDR_END_OF_PDA); - pda.nrec = 1; - - /*-----------------------------------------------------*/ - /* Put card into fwload state */ - prism2sta_ifstate(wlandev, P80211ENUM_ifstate_fwload); - - /* Build the PDA we're going to use. */ - if (read_cardpda(&pda, wlandev)) { - netdev_err(wlandev->netdev, "load_cardpda failed, exiting.\n"); - result = 1; - goto out; - } - - /* read the card's PRI-SUP */ - memset(&getmsg, 0, sizeof(getmsg)); - getmsg.msgcode = DIDMSG_DOT11REQ_MIBGET; - getmsg.msglen = sizeof(getmsg); - strscpy(getmsg.devname, wlandev->name, sizeof(getmsg.devname)); - - getmsg.mibattribute.did = DIDMSG_DOT11REQ_MIBGET_MIBATTRIBUTE; - getmsg.mibattribute.status = P80211ENUM_msgitem_status_data_ok; - getmsg.resultcode.did = DIDMSG_DOT11REQ_MIBGET_RESULTCODE; - getmsg.resultcode.status = P80211ENUM_msgitem_status_no_value; - - item = (struct p80211itemd *)getmsg.mibattribute.data; - item->did = DIDMIB_P2_NIC_PRISUPRANGE; - item->status = P80211ENUM_msgitem_status_no_value; - - data = (u32 *)item->data; - - /* DIDmsg_dot11req_mibget */ - prism2mgmt_mibset_mibget(wlandev, &getmsg); - if (getmsg.resultcode.data != P80211ENUM_resultcode_success) - netdev_err(wlandev->netdev, "Couldn't fetch PRI-SUP info\n"); - - /* Already in host order */ - priid.role = *data++; - priid.id = *data++; - priid.variant = *data++; - priid.bottom = *data++; - priid.top = *data++; - - /* Read the S3 file */ - result = read_fwfile(rfptr); - if (result) { - netdev_err(wlandev->netdev, - "Failed to read the data exiting.\n"); - goto out; - } - - result = validate_identity(); - if (result) { - netdev_err(wlandev->netdev, "Incompatible firmware image.\n"); - goto out; - } - - if (startaddr == 0x00000000) { - netdev_err(wlandev->netdev, - "Can't RAM download a Flash image!\n"); - result = 1; - goto out; - } - - /* Make the image chunks */ - result = mkimage(fchunk, &nfchunks); - if (result) { - netdev_err(wlandev->netdev, "Failed to make image chunk.\n"); - goto free_chunks; - } - - /* Do any plugging */ - result = plugimage(fchunk, nfchunks, s3plug, ns3plug, &pda); - if (result) { - netdev_err(wlandev->netdev, "Failed to plug data.\n"); - goto free_chunks; - } - - /* Insert any CRCs */ - result = crcimage(fchunk, nfchunks, s3crc, ns3crc); - if (result) { - netdev_err(wlandev->netdev, "Failed to insert all CRCs\n"); - goto free_chunks; - } - - /* Write the image */ - result = writeimage(wlandev, fchunk, nfchunks); - if (result) { - netdev_err(wlandev->netdev, "Failed to ramwrite image data.\n"); - goto free_chunks; - } - - netdev_info(wlandev->netdev, "prism2_usb: firmware loading finished.\n"); - -free_chunks: - /* clear any allocated memory */ - free_chunks(fchunk, &nfchunks); - free_srecs(); - -out: - return result; -} - -/*---------------------------------------------------------------- - * crcimage - * - * Adds a CRC16 in the two bytes prior to each block identified by - * an S3 CRC record. Currently, we don't actually do a CRC we just - * insert the value 0xC0DE in hfa384x order. - * - * Arguments: - * fchunk Array of image chunks - * nfchunks Number of image chunks - * s3crc Array of crc records - * ns3crc Number of crc records - * - * Returns: - * 0 success - * ~0 failure - *---------------------------------------------------------------- - */ -static int crcimage(struct imgchunk *fchunk, unsigned int nfchunks, - struct s3crcrec *s3crc, unsigned int ns3crc) -{ - int result = 0; - int i; - int c; - u32 crcstart; - u32 cstart = 0; - u32 cend; - u8 *dest; - u32 chunkoff; - - for (i = 0; i < ns3crc; i++) { - if (!s3crc[i].dowrite) - continue; - crcstart = s3crc[i].addr; - /* Find chunk */ - for (c = 0; c < nfchunks; c++) { - cstart = fchunk[c].addr; - cend = fchunk[c].addr + fchunk[c].len; - /* the line below does an address & len match search */ - /* unfortunately, I've found that the len fields of */ - /* some crc records don't match with the length of */ - /* the actual data, so we're not checking right now */ - /* if (crcstart-2 >= cstart && crcend <= cend) break; */ - - /* note the -2 below, it's to make sure the chunk has */ - /* space for the CRC value */ - if (crcstart - 2 >= cstart && crcstart < cend) - break; - } - if (c >= nfchunks) { - pr_err("Failed to find chunk for crcrec[%d], addr=0x%06x len=%d , aborting crc.\n", - i, s3crc[i].addr, s3crc[i].len); - return 1; - } - - /* Insert crc */ - pr_debug("Adding crc @ 0x%06x\n", s3crc[i].addr - 2); - chunkoff = crcstart - cstart - 2; - dest = fchunk[c].data + chunkoff; - *dest = 0xde; - *(dest + 1) = 0xc0; - } - return result; -} - -/*---------------------------------------------------------------- - * free_chunks - * - * Clears the chunklist data structures in preparation for a new file. - * - * Arguments: - * none - * - * Returns: - * nothing - *---------------------------------------------------------------- - */ -static void free_chunks(struct imgchunk *fchunk, unsigned int *nfchunks) -{ - int i; - - for (i = 0; i < *nfchunks; i++) - kfree(fchunk[i].data); - - *nfchunks = 0; - memset(fchunk, 0, sizeof(*fchunk)); -} - -/*---------------------------------------------------------------- - * free_srecs - * - * Clears the srec data structures in preparation for a new file. - * - * Arguments: - * none - * - * Returns: - * nothing - *---------------------------------------------------------------- - */ -static void free_srecs(void) -{ - ns3data = 0; - kfree(s3data); - ns3plug = 0; - memset(s3plug, 0, sizeof(s3plug)); - ns3crc = 0; - memset(s3crc, 0, sizeof(s3crc)); - ns3info = 0; - memset(s3info, 0, sizeof(s3info)); - startaddr = 0; -} - -/*---------------------------------------------------------------- - * mkimage - * - * Scans the currently loaded set of S records for data residing - * in contiguous memory regions. Each contiguous region is then - * made into a 'chunk'. This function assumes that we're building - * a new chunk list. Assumes the s3data items are in sorted order. - * - * Arguments: none - * - * Returns: - * 0 - success - * ~0 - failure (probably an errno) - *---------------------------------------------------------------- - */ -static int mkimage(struct imgchunk *clist, unsigned int *ccnt) -{ - int result = 0; - int i; - int j; - int currchunk = 0; - u32 nextaddr = 0; - u32 s3start; - u32 s3end; - u32 cstart = 0; - u32 cend; - u32 coffset; - - /* There may already be data in the chunklist */ - *ccnt = 0; - - /* Establish the location and size of each chunk */ - for (i = 0; i < ns3data; i++) { - if (s3data[i].addr == nextaddr) { - /* existing chunk, grow it */ - clist[currchunk].len += s3data[i].len; - nextaddr += s3data[i].len; - } else { - /* New chunk */ - (*ccnt)++; - currchunk = *ccnt - 1; - clist[currchunk].addr = s3data[i].addr; - clist[currchunk].len = s3data[i].len; - nextaddr = s3data[i].addr + s3data[i].len; - /* Expand the chunk if there is a CRC record at */ - /* their beginning bound */ - for (j = 0; j < ns3crc; j++) { - if (s3crc[j].dowrite && - s3crc[j].addr == clist[currchunk].addr) { - clist[currchunk].addr -= 2; - clist[currchunk].len += 2; - } - } - } - } - - /* We're currently assuming there aren't any overlapping chunks */ - /* if this proves false, we'll need to add code to coalesce. */ - - /* Allocate buffer space for chunks */ - for (i = 0; i < *ccnt; i++) { - clist[i].data = kzalloc(clist[i].len, GFP_KERNEL); - if (!clist[i].data) - return 1; - - pr_debug("chunk[%d]: addr=0x%06x len=%d\n", - i, clist[i].addr, clist[i].len); - } - - /* Copy srec data to chunks */ - for (i = 0; i < ns3data; i++) { - s3start = s3data[i].addr; - s3end = s3start + s3data[i].len - 1; - for (j = 0; j < *ccnt; j++) { - cstart = clist[j].addr; - cend = cstart + clist[j].len - 1; - if (s3start >= cstart && s3end <= cend) - break; - } - if (((unsigned int)j) >= (*ccnt)) { - pr_err("s3rec(a=0x%06x,l=%d), no chunk match, exiting.\n", - s3start, s3data[i].len); - return 1; - } - coffset = s3start - cstart; - memcpy(clist[j].data + coffset, s3data[i].data, s3data[i].len); - } - - return result; -} - -/*---------------------------------------------------------------- - * mkpdrlist - * - * Reads a raw PDA and builds an array of pdrec_t structures. - * - * Arguments: - * pda buffer containing raw PDA bytes - * pdrec ptr to an array of pdrec_t's. Will be filled on exit. - * nrec ptr to a variable that will contain the count of PDRs - * - * Returns: - * 0 - success - * ~0 - failure (probably an errno) - *---------------------------------------------------------------- - */ -static int mkpdrlist(struct pda *pda) -{ - __le16 *pda16 = (__le16 *)pda->buf; - int curroff; /* in 'words' */ - - pda->nrec = 0; - curroff = 0; - while (curroff < (HFA384x_PDA_LEN_MAX / 2 - 1) && - le16_to_cpu(pda16[curroff + 1]) != HFA384x_PDR_END_OF_PDA) { - pda->rec[pda->nrec] = (struct hfa384x_pdrec *)&pda16[curroff]; - - if (le16_to_cpu(pda->rec[pda->nrec]->code) == - HFA384x_PDR_NICID) { - memcpy(&nicid, &pda->rec[pda->nrec]->data.nicid, - sizeof(nicid)); - le16_to_cpus(&nicid.id); - le16_to_cpus(&nicid.variant); - le16_to_cpus(&nicid.major); - le16_to_cpus(&nicid.minor); - } - if (le16_to_cpu(pda->rec[pda->nrec]->code) == - HFA384x_PDR_MFISUPRANGE) { - memcpy(&rfid, &pda->rec[pda->nrec]->data.mfisuprange, - sizeof(rfid)); - le16_to_cpus(&rfid.id); - le16_to_cpus(&rfid.variant); - le16_to_cpus(&rfid.bottom); - le16_to_cpus(&rfid.top); - } - if (le16_to_cpu(pda->rec[pda->nrec]->code) == - HFA384x_PDR_CFISUPRANGE) { - memcpy(&macid, &pda->rec[pda->nrec]->data.cfisuprange, - sizeof(macid)); - le16_to_cpus(&macid.id); - le16_to_cpus(&macid.variant); - le16_to_cpus(&macid.bottom); - le16_to_cpus(&macid.top); - } - - (pda->nrec)++; - curroff += le16_to_cpu(pda16[curroff]) + 1; - } - if (curroff >= (HFA384x_PDA_LEN_MAX / 2 - 1)) { - pr_err("no end record found or invalid lengths in PDR data, exiting. %x %d\n", - curroff, pda->nrec); - return 1; - } - pda->rec[pda->nrec] = (struct hfa384x_pdrec *)&pda16[curroff]; - (pda->nrec)++; - return 0; -} - -/*---------------------------------------------------------------- - * plugimage - * - * Plugs the given image using the given plug records from the given - * PDA and filename. - * - * Arguments: - * fchunk Array of image chunks - * nfchunks Number of image chunks - * s3plug Array of plug records - * ns3plug Number of plug records - * pda Current pda data - * - * Returns: - * 0 success - * ~0 failure - *---------------------------------------------------------------- - */ -static int plugimage(struct imgchunk *fchunk, unsigned int nfchunks, - struct s3plugrec *s3plug, unsigned int ns3plug, - struct pda *pda) -{ - int result = 0; - int i; /* plug index */ - int j; /* index of PDR or -1 if fname plug */ - int c; /* chunk index */ - u32 pstart; - u32 pend; - u32 cstart = 0; - u32 cend; - u32 chunkoff; - u8 *dest; - - /* for each plug record */ - for (i = 0; i < ns3plug; i++) { - pstart = s3plug[i].addr; - pend = s3plug[i].addr + s3plug[i].len; - j = -1; - /* find the matching PDR (or filename) */ - if (s3plug[i].itemcode != 0xffffffffUL) { /* not filename */ - for (j = 0; j < pda->nrec; j++) { - if (s3plug[i].itemcode == - le16_to_cpu(pda->rec[j]->code)) - break; - } - } - if (j >= pda->nrec && j != -1) { /* if no matching PDR, fail */ - pr_warn("warning: Failed to find PDR for plugrec 0x%04x.\n", - s3plug[i].itemcode); - continue; /* and move on to the next PDR */ - - /* MSM: They swear that unless it's the MAC address, - * the serial number, or the TX calibration records, - * then there's reasonable defaults in the f/w - * image. Therefore, missing PDRs in the card - * should only be a warning, not fatal. - * TODO: add fatals for the PDRs mentioned above. - */ - } - - /* Validate plug len against PDR len */ - if (j != -1 && s3plug[i].len < le16_to_cpu(pda->rec[j]->len)) { - pr_err("error: Plug vs. PDR len mismatch for plugrec 0x%04x, abort plugging.\n", - s3plug[i].itemcode); - result = 1; - continue; - } - - /* - * Validate plug address against - * chunk data and identify chunk - */ - for (c = 0; c < nfchunks; c++) { - cstart = fchunk[c].addr; - cend = fchunk[c].addr + fchunk[c].len; - if (pstart >= cstart && pend <= cend) - break; - } - if (c >= nfchunks) { - pr_err("error: Failed to find image chunk for plugrec 0x%04x.\n", - s3plug[i].itemcode); - result = 1; - continue; - } - - /* Plug data */ - chunkoff = pstart - cstart; - dest = fchunk[c].data + chunkoff; - pr_debug("Plugging item 0x%04x @ 0x%06x, len=%d, cnum=%d coff=0x%06x\n", - s3plug[i].itemcode, pstart, s3plug[i].len, - c, chunkoff); - - if (j == -1) { /* plug the filename */ - memset(dest, 0, s3plug[i].len); - strscpy(dest, PRISM2_USB_FWFILE, s3plug[i].len); - } else { /* plug a PDR */ - memcpy(dest, &pda->rec[j]->data, s3plug[i].len); - } - } - return result; -} - -/*---------------------------------------------------------------- - * read_cardpda - * - * Sends the command for the driver to read the pda from the card - * named in the device variable. Upon success, the card pda is - * stored in the "cardpda" variables. Note that the pda structure - * is considered 'well formed' after this function. That means - * that the nrecs is valid, the rec array has been set up, and there's - * a valid PDAEND record in the raw PDA data. - * - * Arguments: - * pda pda structure - * wlandev device - * - * Returns: - * 0 - success - * ~0 - failure (probably an errno) - *---------------------------------------------------------------- - */ -static int read_cardpda(struct pda *pda, struct wlandevice *wlandev) -{ - int result = 0; - struct p80211msg_p2req_readpda *msg; - - msg = kzalloc(sizeof(*msg), GFP_KERNEL); - if (!msg) - return -ENOMEM; - - /* set up the msg */ - msg->msgcode = DIDMSG_P2REQ_READPDA; - msg->msglen = sizeof(msg); - strscpy(msg->devname, wlandev->name, sizeof(msg->devname)); - msg->pda.did = DIDMSG_P2REQ_READPDA_PDA; - msg->pda.len = HFA384x_PDA_LEN_MAX; - msg->pda.status = P80211ENUM_msgitem_status_no_value; - msg->resultcode.did = DIDMSG_P2REQ_READPDA_RESULTCODE; - msg->resultcode.len = sizeof(u32); - msg->resultcode.status = P80211ENUM_msgitem_status_no_value; - - if (prism2mgmt_readpda(wlandev, msg) != 0) { - /* prism2mgmt_readpda prints an errno if appropriate */ - result = -1; - } else if (msg->resultcode.data == P80211ENUM_resultcode_success) { - memcpy(pda->buf, msg->pda.data, HFA384x_PDA_LEN_MAX); - result = mkpdrlist(pda); - } else { - /* resultcode must've been something other than success */ - result = -1; - } - - kfree(msg); - return result; -} - -/*---------------------------------------------------------------- - * read_fwfile - * - * Reads the given fw file which should have been compiled from an srec - * file. Each record in the fw file will either be a plain data record, - * a start address record, or other records used for plugging. - * - * Note that data records are expected to be sorted into - * ascending address order in the fw file. - * - * Note also that the start address record, originally an S7 record in - * the srec file, is expected in the fw file to be like a data record but - * with a certain address to make it identifiable. - * - * Here's the SREC format that the fw should have come from: - * S[37]nnaaaaaaaaddd...dddcc - * - * nn - number of bytes starting with the address field - * aaaaaaaa - address in readable (or big endian) format - * dd....dd - 0-245 data bytes (two chars per byte) - * cc - checksum - * - * The S7 record's (there should be only one) address value gets - * converted to an S3 record with address of 0xff400000, with the - * start address being stored as a 4 byte data word. That address is - * the start execution address used for RAM downloads. - * - * The S3 records have a collection of subformats indicated by the - * value of aaaaaaaa: - * 0xff000000 - Plug record, data field format: - * xxxxxxxxaaaaaaaassssssss - * x - PDR code number (little endian) - * a - Address in load image to plug (little endian) - * s - Length of plug data area (little endian) - * - * 0xff100000 - CRC16 generation record, data field format: - * aaaaaaaassssssssbbbbbbbb - * a - Start address for CRC calculation (little endian) - * s - Length of data to calculate over (little endian) - * b - Boolean, true=write crc, false=don't write - * - * 0xff200000 - Info record, data field format: - * ssssttttdd..dd - * s - Size in words (little endian) - * t - Info type (little endian), see #defines and - * struct s3inforec for details about types. - * d - (s - 1) little endian words giving the contents of - * the given info type. - * - * 0xff400000 - Start address record, data field format: - * aaaaaaaa - * a - Address in load image to plug (little endian) - * - * Arguments: - * record firmware image (ihex record structure) in kernel memory - * - * Returns: - * 0 - success - * ~0 - failure (probably an errno) - *---------------------------------------------------------------- - */ -static int read_fwfile(const struct ihex_binrec *record) -{ - int i; - int rcnt = 0; - u16 *tmpinfo; - u16 *ptr16; - u32 *ptr32, len, addr; - - pr_debug("Reading fw file ...\n"); - - while (record) { - rcnt++; - - len = be16_to_cpu(record->len); - addr = be32_to_cpu(record->addr); - - /* Point into data for different word lengths */ - ptr32 = (u32 *)record->data; - ptr16 = (u16 *)record->data; - - /* parse what was an S3 srec and put it in the right array */ - switch (addr) { - case S3ADDR_START: - startaddr = *ptr32; - pr_debug(" S7 start addr, record=%d addr=0x%08x\n", - rcnt, - startaddr); - break; - case S3ADDR_PLUG: - s3plug[ns3plug].itemcode = *ptr32; - s3plug[ns3plug].addr = *(ptr32 + 1); - s3plug[ns3plug].len = *(ptr32 + 2); - - pr_debug(" S3 plugrec, record=%d itemcode=0x%08x addr=0x%08x len=%d\n", - rcnt, - s3plug[ns3plug].itemcode, - s3plug[ns3plug].addr, - s3plug[ns3plug].len); - - ns3plug++; - if (ns3plug == S3PLUG_MAX) { - pr_err("S3 plugrec limit reached - aborting\n"); - return 1; - } - break; - case S3ADDR_CRC: - s3crc[ns3crc].addr = *ptr32; - s3crc[ns3crc].len = *(ptr32 + 1); - s3crc[ns3crc].dowrite = *(ptr32 + 2); - - pr_debug(" S3 crcrec, record=%d addr=0x%08x len=%d write=0x%08x\n", - rcnt, - s3crc[ns3crc].addr, - s3crc[ns3crc].len, - s3crc[ns3crc].dowrite); - ns3crc++; - if (ns3crc == S3CRC_MAX) { - pr_err("S3 crcrec limit reached - aborting\n"); - return 1; - } - break; - case S3ADDR_INFO: - s3info[ns3info].len = *ptr16; - s3info[ns3info].type = *(ptr16 + 1); - - pr_debug(" S3 inforec, record=%d len=0x%04x type=0x%04x\n", - rcnt, - s3info[ns3info].len, - s3info[ns3info].type); - if (((s3info[ns3info].len - 1) * sizeof(u16)) > - sizeof(s3info[ns3info].info)) { - pr_err("S3 inforec length too long - aborting\n"); - return 1; - } - - tmpinfo = (u16 *)&s3info[ns3info].info.version; - pr_debug(" info="); - for (i = 0; i < s3info[ns3info].len - 1; i++) { - tmpinfo[i] = *(ptr16 + 2 + i); - pr_debug("%04x ", tmpinfo[i]); - } - pr_debug("\n"); - - ns3info++; - if (ns3info == S3INFO_MAX) { - pr_err("S3 inforec limit reached - aborting\n"); - return 1; - } - break; - default: /* Data record */ - s3data[ns3data].addr = addr; - s3data[ns3data].len = len; - s3data[ns3data].data = (uint8_t *)record->data; - ns3data++; - if (ns3data == S3DATA_MAX) { - pr_err("S3 datarec limit reached - aborting\n"); - return 1; - } - break; - } - record = ihex_next_binrec(record); - } - return 0; -} - -/*---------------------------------------------------------------- - * writeimage - * - * Takes the chunks, builds p80211 messages and sends them down - * to the driver for writing to the card. - * - * Arguments: - * wlandev device - * fchunk Array of image chunks - * nfchunks Number of image chunks - * - * Returns: - * 0 success - * ~0 failure - *---------------------------------------------------------------- - */ -static int writeimage(struct wlandevice *wlandev, struct imgchunk *fchunk, - unsigned int nfchunks) -{ - int result = 0; - struct p80211msg_p2req_ramdl_state *rstmsg; - struct p80211msg_p2req_ramdl_write *rwrmsg; - u32 resultcode; - int i; - int j; - unsigned int nwrites; - u32 curroff; - u32 currlen; - u32 currdaddr; - - rstmsg = kzalloc(sizeof(*rstmsg), GFP_KERNEL); - rwrmsg = kzalloc(sizeof(*rwrmsg), GFP_KERNEL); - if (!rstmsg || !rwrmsg) { - netdev_err(wlandev->netdev, - "%s: no memory for firmware download, aborting download\n", - __func__); - result = -ENOMEM; - goto free_result; - } - - /* Initialize the messages */ - strscpy(rstmsg->devname, wlandev->name, sizeof(rstmsg->devname)); - rstmsg->msgcode = DIDMSG_P2REQ_RAMDL_STATE; - rstmsg->msglen = sizeof(*rstmsg); - rstmsg->enable.did = DIDMSG_P2REQ_RAMDL_STATE_ENABLE; - rstmsg->exeaddr.did = DIDMSG_P2REQ_RAMDL_STATE_EXEADDR; - rstmsg->resultcode.did = DIDMSG_P2REQ_RAMDL_STATE_RESULTCODE; - rstmsg->enable.status = P80211ENUM_msgitem_status_data_ok; - rstmsg->exeaddr.status = P80211ENUM_msgitem_status_data_ok; - rstmsg->resultcode.status = P80211ENUM_msgitem_status_no_value; - rstmsg->enable.len = sizeof(u32); - rstmsg->exeaddr.len = sizeof(u32); - rstmsg->resultcode.len = sizeof(u32); - - strscpy(rwrmsg->devname, wlandev->name, sizeof(rwrmsg->devname)); - rwrmsg->msgcode = DIDMSG_P2REQ_RAMDL_WRITE; - rwrmsg->msglen = sizeof(*rwrmsg); - rwrmsg->addr.did = DIDMSG_P2REQ_RAMDL_WRITE_ADDR; - rwrmsg->len.did = DIDMSG_P2REQ_RAMDL_WRITE_LEN; - rwrmsg->data.did = DIDMSG_P2REQ_RAMDL_WRITE_DATA; - rwrmsg->resultcode.did = DIDMSG_P2REQ_RAMDL_WRITE_RESULTCODE; - rwrmsg->addr.status = P80211ENUM_msgitem_status_data_ok; - rwrmsg->len.status = P80211ENUM_msgitem_status_data_ok; - rwrmsg->data.status = P80211ENUM_msgitem_status_data_ok; - rwrmsg->resultcode.status = P80211ENUM_msgitem_status_no_value; - rwrmsg->addr.len = sizeof(u32); - rwrmsg->len.len = sizeof(u32); - rwrmsg->data.len = WRITESIZE_MAX; - rwrmsg->resultcode.len = sizeof(u32); - - /* Send xxx_state(enable) */ - pr_debug("Sending dl_state(enable) message.\n"); - rstmsg->enable.data = P80211ENUM_truth_true; - rstmsg->exeaddr.data = startaddr; - - result = prism2mgmt_ramdl_state(wlandev, rstmsg); - if (result) { - netdev_err(wlandev->netdev, - "%s state enable failed w/ result=%d, aborting download\n", - __func__, result); - goto free_result; - } - resultcode = rstmsg->resultcode.data; - if (resultcode != P80211ENUM_resultcode_success) { - netdev_err(wlandev->netdev, - "%s()->xxxdl_state msg indicates failure, w/ resultcode=%d, aborting download.\n", - __func__, resultcode); - result = 1; - goto free_result; - } - - /* Now, loop through the data chunks and send WRITESIZE_MAX data */ - for (i = 0; i < nfchunks; i++) { - nwrites = fchunk[i].len / WRITESIZE_MAX; - nwrites += (fchunk[i].len % WRITESIZE_MAX) ? 1 : 0; - curroff = 0; - for (j = 0; j < nwrites; j++) { - /* TODO Move this to a separate function */ - int lenleft = fchunk[i].len - (WRITESIZE_MAX * j); - - if (fchunk[i].len > WRITESIZE_MAX) - currlen = WRITESIZE_MAX; - else - currlen = lenleft; - curroff = j * WRITESIZE_MAX; - currdaddr = fchunk[i].addr + curroff; - /* Setup the message */ - rwrmsg->addr.data = currdaddr; - rwrmsg->len.data = currlen; - memcpy(rwrmsg->data.data, - fchunk[i].data + curroff, currlen); - - /* Send flashdl_write(pda) */ - pr_debug - ("Sending xxxdl_write message addr=%06x len=%d.\n", - currdaddr, currlen); - - result = prism2mgmt_ramdl_write(wlandev, rwrmsg); - - /* Check the results */ - if (result) { - netdev_err(wlandev->netdev, - "%s chunk write failed w/ result=%d, aborting download\n", - __func__, result); - goto free_result; - } - resultcode = rstmsg->resultcode.data; - if (resultcode != P80211ENUM_resultcode_success) { - pr_err("%s()->xxxdl_write msg indicates failure, w/ resultcode=%d, aborting download.\n", - __func__, resultcode); - result = 1; - goto free_result; - } - } - } - - /* Send xxx_state(disable) */ - pr_debug("Sending dl_state(disable) message.\n"); - rstmsg->enable.data = P80211ENUM_truth_false; - rstmsg->exeaddr.data = 0; - - result = prism2mgmt_ramdl_state(wlandev, rstmsg); - if (result) { - netdev_err(wlandev->netdev, - "%s state disable failed w/ result=%d, aborting download\n", - __func__, result); - goto free_result; - } - resultcode = rstmsg->resultcode.data; - if (resultcode != P80211ENUM_resultcode_success) { - netdev_err(wlandev->netdev, - "%s()->xxxdl_state msg indicates failure, w/ resultcode=%d, aborting download.\n", - __func__, resultcode); - result = 1; - goto free_result; - } - -free_result: - kfree(rstmsg); - kfree(rwrmsg); - return result; -} - -static int validate_identity(void) -{ - int i; - int result = 1; - int trump = 0; - - pr_debug("NIC ID: %#x v%d.%d.%d\n", - nicid.id, nicid.major, nicid.minor, nicid.variant); - pr_debug("MFI ID: %#x v%d %d->%d\n", - rfid.id, rfid.variant, rfid.bottom, rfid.top); - pr_debug("CFI ID: %#x v%d %d->%d\n", - macid.id, macid.variant, macid.bottom, macid.top); - pr_debug("PRI ID: %#x v%d %d->%d\n", - priid.id, priid.variant, priid.bottom, priid.top); - - for (i = 0; i < ns3info; i++) { - switch (s3info[i].type) { - case 1: - pr_debug("Version: ID %#x %d.%d.%d\n", - s3info[i].info.version.id, - s3info[i].info.version.major, - s3info[i].info.version.minor, - s3info[i].info.version.variant); - break; - case 2: - pr_debug("Compat: Role %#x Id %#x v%d %d->%d\n", - s3info[i].info.compat.role, - s3info[i].info.compat.id, - s3info[i].info.compat.variant, - s3info[i].info.compat.bottom, - s3info[i].info.compat.top); - - /* MAC compat range */ - if ((s3info[i].info.compat.role == 1) && - (s3info[i].info.compat.id == 2)) { - if (s3info[i].info.compat.variant != - macid.variant) { - result = 2; - } - } - - /* PRI compat range */ - if ((s3info[i].info.compat.role == 1) && - (s3info[i].info.compat.id == 3)) { - if ((s3info[i].info.compat.bottom > - priid.top) || - (s3info[i].info.compat.top < - priid.bottom)) { - result = 3; - } - } - /* SEC compat range */ - if ((s3info[i].info.compat.role == 1) && - (s3info[i].info.compat.id == 4)) { - /* FIXME: isn't something missing here? */ - } - - break; - case 3: - pr_debug("Seq: %#x\n", s3info[i].info.buildseq); - - break; - case 4: - pr_debug("Platform: ID %#x %d.%d.%d\n", - s3info[i].info.version.id, - s3info[i].info.version.major, - s3info[i].info.version.minor, - s3info[i].info.version.variant); - - if (nicid.id != s3info[i].info.version.id) - continue; - if (nicid.major != s3info[i].info.version.major) - continue; - if (nicid.minor != s3info[i].info.version.minor) - continue; - if ((nicid.variant != s3info[i].info.version.variant) && - (nicid.id != 0x8008)) - continue; - - trump = 1; - break; - case 0x8001: - pr_debug("name inforec len %d\n", s3info[i].len); - - break; - default: - pr_debug("Unknown inforec type %d\n", s3info[i].type); - } - } - /* walk through */ - - if (trump && (result != 2)) - result = 0; - return result; -} diff --git a/drivers/staging/wlan-ng/prism2mgmt.c b/drivers/staging/wlan-ng/prism2mgmt.c deleted file mode 100644 index d5737166564e..000000000000 --- a/drivers/staging/wlan-ng/prism2mgmt.c +++ /dev/null @@ -1,1315 +0,0 @@ -// SPDX-License-Identifier: (GPL-2.0 OR MPL-1.1) -/* - * - * Management request handler functions. - * - * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. - * -------------------------------------------------------------------- - * - * linux-wlan - * - * -------------------------------------------------------------------- - * - * Inquiries regarding the linux-wlan Open Source project can be - * made directly to: - * - * AbsoluteValue Systems Inc. - * info@linux-wlan.com - * http://www.linux-wlan.com - * - * -------------------------------------------------------------------- - * - * Portions of the development of this software were funded by - * Intersil Corporation as part of PRISM(R) chipset product development. - * - * -------------------------------------------------------------------- - * - * The functions in this file handle management requests sent from - * user mode. - * - * Most of these functions have two separate blocks of code that are - * conditional on whether this is a station or an AP. This is used - * to separate out the STA and AP responses to these management primitives. - * It's a choice (good, bad, indifferent?) to have the code in the same - * place so it's clear that the same primitive is implemented in both - * cases but has different behavior. - * - * -------------------------------------------------------------------- - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "p80211types.h" -#include "p80211hdr.h" -#include "p80211mgmt.h" -#include "p80211conv.h" -#include "p80211msg.h" -#include "p80211netdev.h" -#include "p80211metadef.h" -#include "p80211metastruct.h" -#include "hfa384x.h" -#include "prism2mgmt.h" - -/* Converts 802.11 format rate specifications to prism2 */ -static inline u16 p80211rate_to_p2bit(u32 rate) -{ - switch (rate & ~BIT(7)) { - case 2: - return BIT(0); - case 4: - return BIT(1); - case 11: - return BIT(2); - case 22: - return BIT(3); - default: - return 0; - } -} - -/*---------------------------------------------------------------- - * prism2mgmt_scan - * - * Initiate a scan for BSSs. - * - * This function corresponds to MLME-scan.request and part of - * MLME-scan.confirm. As far as I can tell in the standard, there - * are no restrictions on when a scan.request may be issued. We have - * to handle in whatever state the driver/MAC happen to be. - * - * Arguments: - * wlandev wlan device structure - * msgp ptr to msg buffer - * - * Returns: - * 0 success and done - * <0 success, but we're waiting for something to finish. - * >0 an error occurred while handling the message. - * Side effects: - * - * Call context: - * process thread (usually) - * interrupt - *---------------------------------------------------------------- - */ -int prism2mgmt_scan(struct wlandevice *wlandev, void *msgp) -{ - int result = 0; - struct hfa384x *hw = wlandev->priv; - struct p80211msg_dot11req_scan *msg = msgp; - u16 roamingmode, word; - int i, timeout; - int istmpenable = 0; - - struct hfa384x_host_scan_request_data scanreq; - - /* gatekeeper check */ - if (HFA384x_FIRMWARE_VERSION(hw->ident_sta_fw.major, - hw->ident_sta_fw.minor, - hw->ident_sta_fw.variant) < - HFA384x_FIRMWARE_VERSION(1, 3, 2)) { - netdev_err(wlandev->netdev, - "HostScan not supported with current firmware (<1.3.2).\n"); - result = 1; - msg->resultcode.data = P80211ENUM_resultcode_not_supported; - goto exit; - } - - memset(&scanreq, 0, sizeof(scanreq)); - - /* save current roaming mode */ - result = hfa384x_drvr_getconfig16(hw, - HFA384x_RID_CNFROAMINGMODE, - &roamingmode); - if (result) { - netdev_err(wlandev->netdev, - "getconfig(ROAMMODE) failed. result=%d\n", result); - msg->resultcode.data = - P80211ENUM_resultcode_implementation_failure; - goto exit; - } - - /* drop into mode 3 for the scan */ - result = hfa384x_drvr_setconfig16(hw, - HFA384x_RID_CNFROAMINGMODE, - HFA384x_ROAMMODE_HOSTSCAN_HOSTROAM); - if (result) { - netdev_err(wlandev->netdev, - "setconfig(ROAMINGMODE) failed. result=%d\n", - result); - msg->resultcode.data = - P80211ENUM_resultcode_implementation_failure; - goto exit; - } - - /* active or passive? */ - if (HFA384x_FIRMWARE_VERSION(hw->ident_sta_fw.major, - hw->ident_sta_fw.minor, - hw->ident_sta_fw.variant) > - HFA384x_FIRMWARE_VERSION(1, 5, 0)) { - if (msg->scantype.data != P80211ENUM_scantype_active) - word = msg->maxchanneltime.data; - else - word = 0; - - result = - hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFPASSIVESCANCTRL, - word); - if (result) { - netdev_warn(wlandev->netdev, - "Passive scan not supported with current firmware. (<1.5.1)\n"); - } - } - - /* set up the txrate to be 2MBPS. Should be fastest basicrate... */ - word = HFA384x_RATEBIT_2; - scanreq.tx_rate = cpu_to_le16(word); - - /* set up the channel list */ - word = 0; - for (i = 0; i < msg->channellist.data.len; i++) { - u8 channel = msg->channellist.data.data[i]; - - if (channel > 14) - continue; - /* channel 1 is BIT 0 ... channel 14 is BIT 13 */ - word |= (1 << (channel - 1)); - } - scanreq.channel_list = cpu_to_le16(word); - - /* set up the ssid, if present. */ - scanreq.ssid.len = cpu_to_le16(msg->ssid.data.len); - memcpy(scanreq.ssid.data, msg->ssid.data.data, msg->ssid.data.len); - - /* Enable the MAC port if it's not already enabled */ - result = hfa384x_drvr_getconfig16(hw, HFA384x_RID_PORTSTATUS, &word); - if (result) { - netdev_err(wlandev->netdev, - "getconfig(PORTSTATUS) failed. result=%d\n", result); - msg->resultcode.data = - P80211ENUM_resultcode_implementation_failure; - goto exit; - } - if (word == HFA384x_PORTSTATUS_DISABLED) { - __le16 wordbuf[17]; - - result = hfa384x_drvr_setconfig16(hw, - HFA384x_RID_CNFROAMINGMODE, - HFA384x_ROAMMODE_HOSTSCAN_HOSTROAM); - if (result) { - netdev_err(wlandev->netdev, - "setconfig(ROAMINGMODE) failed. result=%d\n", - result); - msg->resultcode.data = - P80211ENUM_resultcode_implementation_failure; - goto exit; - } - /* Construct a bogus SSID and assign it to OwnSSID and - * DesiredSSID - */ - wordbuf[0] = cpu_to_le16(WLAN_SSID_MAXLEN); - get_random_bytes(&wordbuf[1], WLAN_SSID_MAXLEN); - result = hfa384x_drvr_setconfig(hw, HFA384x_RID_CNFOWNSSID, - wordbuf, - HFA384x_RID_CNFOWNSSID_LEN); - if (result) { - netdev_err(wlandev->netdev, "Failed to set OwnSSID.\n"); - msg->resultcode.data = - P80211ENUM_resultcode_implementation_failure; - goto exit; - } - result = hfa384x_drvr_setconfig(hw, HFA384x_RID_CNFDESIREDSSID, - wordbuf, - HFA384x_RID_CNFDESIREDSSID_LEN); - if (result) { - netdev_err(wlandev->netdev, - "Failed to set DesiredSSID.\n"); - msg->resultcode.data = - P80211ENUM_resultcode_implementation_failure; - goto exit; - } - /* bsstype */ - result = hfa384x_drvr_setconfig16(hw, - HFA384x_RID_CNFPORTTYPE, - HFA384x_PORTTYPE_IBSS); - if (result) { - netdev_err(wlandev->netdev, - "Failed to set CNFPORTTYPE.\n"); - msg->resultcode.data = - P80211ENUM_resultcode_implementation_failure; - goto exit; - } - /* ibss options */ - result = hfa384x_drvr_setconfig16(hw, - HFA384x_RID_CREATEIBSS, - HFA384x_CREATEIBSS_JOINCREATEIBSS); - if (result) { - netdev_err(wlandev->netdev, - "Failed to set CREATEIBSS.\n"); - msg->resultcode.data = - P80211ENUM_resultcode_implementation_failure; - goto exit; - } - result = hfa384x_drvr_enable(hw, 0); - if (result) { - netdev_err(wlandev->netdev, - "drvr_enable(0) failed. result=%d\n", - result); - msg->resultcode.data = - P80211ENUM_resultcode_implementation_failure; - goto exit; - } - istmpenable = 1; - } - - /* Figure out our timeout first Kus, then HZ */ - timeout = msg->channellist.data.len * msg->maxchanneltime.data; - timeout = (timeout * HZ) / 1000; - - /* Issue the scan request */ - hw->scanflag = 0; - - result = hfa384x_drvr_setconfig(hw, - HFA384x_RID_HOSTSCAN, &scanreq, - sizeof(scanreq)); - if (result) { - netdev_err(wlandev->netdev, - "setconfig(SCANREQUEST) failed. result=%d\n", - result); - msg->resultcode.data = - P80211ENUM_resultcode_implementation_failure; - goto exit; - } - - /* sleep until info frame arrives */ - wait_event_interruptible_timeout(hw->cmdq, hw->scanflag, timeout); - - msg->numbss.status = P80211ENUM_msgitem_status_data_ok; - if (hw->scanflag == -1) - hw->scanflag = 0; - - msg->numbss.data = hw->scanflag; - - hw->scanflag = 0; - - /* Disable port if we temporarily enabled it. */ - if (istmpenable) { - result = hfa384x_drvr_disable(hw, 0); - if (result) { - netdev_err(wlandev->netdev, - "drvr_disable(0) failed. result=%d\n", - result); - msg->resultcode.data = - P80211ENUM_resultcode_implementation_failure; - goto exit; - } - } - - /* restore original roaming mode */ - result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFROAMINGMODE, - roamingmode); - if (result) { - netdev_err(wlandev->netdev, - "setconfig(ROAMMODE) failed. result=%d\n", result); - msg->resultcode.data = - P80211ENUM_resultcode_implementation_failure; - goto exit; - } - - result = 0; - msg->resultcode.data = P80211ENUM_resultcode_success; - -exit: - msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; - - return result; -} - -/*---------------------------------------------------------------- - * prism2mgmt_scan_results - * - * Retrieve the BSS description for one of the BSSs identified in - * a scan. - * - * Arguments: - * wlandev wlan device structure - * msgp ptr to msg buffer - * - * Returns: - * 0 success and done - * <0 success, but we're waiting for something to finish. - * >0 an error occurred while handling the message. - * Side effects: - * - * Call context: - * process thread (usually) - * interrupt - *---------------------------------------------------------------- - */ -int prism2mgmt_scan_results(struct wlandevice *wlandev, void *msgp) -{ - int result = 0; - struct p80211msg_dot11req_scan_results *req; - struct hfa384x *hw = wlandev->priv; - struct hfa384x_hscan_result_sub *item = NULL; - - int count; - - req = msgp; - - req->resultcode.status = P80211ENUM_msgitem_status_data_ok; - - if (!hw->scanresults) { - netdev_err(wlandev->netdev, - "dot11req_scan_results can only be used after a successful dot11req_scan.\n"); - result = 2; - req->resultcode.data = P80211ENUM_resultcode_invalid_parameters; - goto exit; - } - - count = (hw->scanresults->framelen - 3) / 32; - if (count > HFA384x_SCANRESULT_MAX) - count = HFA384x_SCANRESULT_MAX; - - if (req->bssindex.data >= count) { - netdev_dbg(wlandev->netdev, - "requested index (%d) out of range (%d)\n", - req->bssindex.data, count); - result = 2; - req->resultcode.data = P80211ENUM_resultcode_invalid_parameters; - goto exit; - } - - item = &hw->scanresults->info.hscanresult.result[req->bssindex.data]; - /* signal and noise */ - req->signal.status = P80211ENUM_msgitem_status_data_ok; - req->noise.status = P80211ENUM_msgitem_status_data_ok; - req->signal.data = le16_to_cpu(item->sl); - req->noise.data = le16_to_cpu(item->anl); - - /* BSSID */ - req->bssid.status = P80211ENUM_msgitem_status_data_ok; - req->bssid.data.len = WLAN_BSSID_LEN; - memcpy(req->bssid.data.data, item->bssid, WLAN_BSSID_LEN); - - /* SSID */ - req->ssid.status = P80211ENUM_msgitem_status_data_ok; - req->ssid.data.len = le16_to_cpu(item->ssid.len); - req->ssid.data.len = min_t(u16, req->ssid.data.len, WLAN_SSID_MAXLEN); - memcpy(req->ssid.data.data, item->ssid.data, req->ssid.data.len); - - /* supported rates */ - for (count = 0; count < 10; count++) - if (item->supprates[count] == 0) - break; - - for (int i = 0; i < 8; i++) { - if (count > i && - DOT11_RATE5_ISBASIC_GET(item->supprates[i])) { - req->basicrate[i].data = item->supprates[i]; - req->basicrate[i].status = - P80211ENUM_msgitem_status_data_ok; - } - } - - for (int i = 0; i < 8; i++) { - if (count > i) { - req->supprate[i].data = item->supprates[i]; - req->supprate[i].status = - P80211ENUM_msgitem_status_data_ok; - } - } - - /* beacon period */ - req->beaconperiod.status = P80211ENUM_msgitem_status_data_ok; - req->beaconperiod.data = le16_to_cpu(item->bcnint); - - /* timestamps */ - req->timestamp.status = P80211ENUM_msgitem_status_data_ok; - req->timestamp.data = jiffies; - req->localtime.status = P80211ENUM_msgitem_status_data_ok; - req->localtime.data = jiffies; - - /* atim window */ - req->ibssatimwindow.status = P80211ENUM_msgitem_status_data_ok; - req->ibssatimwindow.data = le16_to_cpu(item->atim); - - /* Channel */ - req->dschannel.status = P80211ENUM_msgitem_status_data_ok; - req->dschannel.data = le16_to_cpu(item->chid); - - /* capinfo bits */ - count = le16_to_cpu(item->capinfo); - req->capinfo.status = P80211ENUM_msgitem_status_data_ok; - req->capinfo.data = count; - - /* privacy flag */ - req->privacy.status = P80211ENUM_msgitem_status_data_ok; - req->privacy.data = WLAN_GET_MGMT_CAP_INFO_PRIVACY(count); - - /* cfpollable */ - req->cfpollable.status = P80211ENUM_msgitem_status_data_ok; - req->cfpollable.data = WLAN_GET_MGMT_CAP_INFO_CFPOLLABLE(count); - - /* cfpollreq */ - req->cfpollreq.status = P80211ENUM_msgitem_status_data_ok; - req->cfpollreq.data = WLAN_GET_MGMT_CAP_INFO_CFPOLLREQ(count); - - /* bsstype */ - req->bsstype.status = P80211ENUM_msgitem_status_data_ok; - req->bsstype.data = (WLAN_GET_MGMT_CAP_INFO_ESS(count)) ? - P80211ENUM_bsstype_infrastructure : P80211ENUM_bsstype_independent; - - result = 0; - req->resultcode.data = P80211ENUM_resultcode_success; - -exit: - return result; -} - -/*---------------------------------------------------------------- - * prism2mgmt_start - * - * Start a BSS. Any station can do this for IBSS, only AP for ESS. - * - * Arguments: - * wlandev wlan device structure - * msgp ptr to msg buffer - * - * Returns: - * 0 success and done - * <0 success, but we're waiting for something to finish. - * >0 an error occurred while handling the message. - * Side effects: - * - * Call context: - * process thread (usually) - * interrupt - *---------------------------------------------------------------- - */ -int prism2mgmt_start(struct wlandevice *wlandev, void *msgp) -{ - int result = 0; - struct hfa384x *hw = wlandev->priv; - struct p80211msg_dot11req_start *msg = msgp; - - struct p80211pstrd *pstr; - u8 bytebuf[80]; - struct hfa384x_bytestr *p2bytestr = (struct hfa384x_bytestr *)bytebuf; - u16 word; - - wlandev->macmode = WLAN_MACMODE_NONE; - - /* Set the SSID */ - memcpy(&wlandev->ssid, &msg->ssid.data, sizeof(msg->ssid.data)); - - /*** ADHOC IBSS ***/ - /* see if current f/w is less than 8c3 */ - if (HFA384x_FIRMWARE_VERSION(hw->ident_sta_fw.major, - hw->ident_sta_fw.minor, - hw->ident_sta_fw.variant) < - HFA384x_FIRMWARE_VERSION(0, 8, 3)) { - /* Ad-Hoc not quite supported on Prism2 */ - msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; - msg->resultcode.data = P80211ENUM_resultcode_not_supported; - goto done; - } - - msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; - - /*** STATION ***/ - /* Set the REQUIRED config items */ - /* SSID */ - pstr = (struct p80211pstrd *)&msg->ssid.data; - prism2mgmt_pstr2bytestr(p2bytestr, pstr); - result = hfa384x_drvr_setconfig(hw, HFA384x_RID_CNFOWNSSID, - bytebuf, HFA384x_RID_CNFOWNSSID_LEN); - if (result) { - netdev_err(wlandev->netdev, "Failed to set CnfOwnSSID\n"); - goto failed; - } - result = hfa384x_drvr_setconfig(hw, HFA384x_RID_CNFDESIREDSSID, - bytebuf, - HFA384x_RID_CNFDESIREDSSID_LEN); - if (result) { - netdev_err(wlandev->netdev, "Failed to set CnfDesiredSSID\n"); - goto failed; - } - - /* bsstype - we use the default in the ap firmware */ - /* IBSS port */ - hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFPORTTYPE, 0); - - /* beacon period */ - word = msg->beaconperiod.data; - result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFAPBCNINT, word); - if (result) { - netdev_err(wlandev->netdev, - "Failed to set beacon period=%d.\n", word); - goto failed; - } - - /* dschannel */ - word = msg->dschannel.data; - result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFOWNCHANNEL, word); - if (result) { - netdev_err(wlandev->netdev, - "Failed to set channel=%d.\n", word); - goto failed; - } - /* Basic rates */ - word = p80211rate_to_p2bit(msg->basicrate1.data); - if (msg->basicrate2.status == P80211ENUM_msgitem_status_data_ok) - word |= p80211rate_to_p2bit(msg->basicrate2.data); - - if (msg->basicrate3.status == P80211ENUM_msgitem_status_data_ok) - word |= p80211rate_to_p2bit(msg->basicrate3.data); - - if (msg->basicrate4.status == P80211ENUM_msgitem_status_data_ok) - word |= p80211rate_to_p2bit(msg->basicrate4.data); - - if (msg->basicrate5.status == P80211ENUM_msgitem_status_data_ok) - word |= p80211rate_to_p2bit(msg->basicrate5.data); - - if (msg->basicrate6.status == P80211ENUM_msgitem_status_data_ok) - word |= p80211rate_to_p2bit(msg->basicrate6.data); - - if (msg->basicrate7.status == P80211ENUM_msgitem_status_data_ok) - word |= p80211rate_to_p2bit(msg->basicrate7.data); - - if (msg->basicrate8.status == P80211ENUM_msgitem_status_data_ok) - word |= p80211rate_to_p2bit(msg->basicrate8.data); - - result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFBASICRATES, word); - if (result) { - netdev_err(wlandev->netdev, - "Failed to set basicrates=%d.\n", word); - goto failed; - } - - /* Operational rates (supprates and txratecontrol) */ - word = p80211rate_to_p2bit(msg->operationalrate1.data); - if (msg->operationalrate2.status == P80211ENUM_msgitem_status_data_ok) - word |= p80211rate_to_p2bit(msg->operationalrate2.data); - - if (msg->operationalrate3.status == P80211ENUM_msgitem_status_data_ok) - word |= p80211rate_to_p2bit(msg->operationalrate3.data); - - if (msg->operationalrate4.status == P80211ENUM_msgitem_status_data_ok) - word |= p80211rate_to_p2bit(msg->operationalrate4.data); - - if (msg->operationalrate5.status == P80211ENUM_msgitem_status_data_ok) - word |= p80211rate_to_p2bit(msg->operationalrate5.data); - - if (msg->operationalrate6.status == P80211ENUM_msgitem_status_data_ok) - word |= p80211rate_to_p2bit(msg->operationalrate6.data); - - if (msg->operationalrate7.status == P80211ENUM_msgitem_status_data_ok) - word |= p80211rate_to_p2bit(msg->operationalrate7.data); - - if (msg->operationalrate8.status == P80211ENUM_msgitem_status_data_ok) - word |= p80211rate_to_p2bit(msg->operationalrate8.data); - - result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFSUPPRATES, word); - if (result) { - netdev_err(wlandev->netdev, - "Failed to set supprates=%d.\n", word); - goto failed; - } - - result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_TXRATECNTL, word); - if (result) { - netdev_err(wlandev->netdev, "Failed to set txrates=%d.\n", - word); - goto failed; - } - - /* Set the macmode so the frame setup code knows what to do */ - if (msg->bsstype.data == P80211ENUM_bsstype_independent) { - wlandev->macmode = WLAN_MACMODE_IBSS_STA; - /* lets extend the data length a bit */ - hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFMAXDATALEN, 2304); - } - - /* Enable the Port */ - result = hfa384x_drvr_enable(hw, 0); - if (result) { - netdev_err(wlandev->netdev, - "Enable macport failed, result=%d.\n", result); - goto failed; - } - - msg->resultcode.data = P80211ENUM_resultcode_success; - - goto done; -failed: - netdev_dbg(wlandev->netdev, - "Failed to set a config option, result=%d\n", result); - msg->resultcode.data = P80211ENUM_resultcode_invalid_parameters; - -done: - return 0; -} - -/*---------------------------------------------------------------- - * prism2mgmt_readpda - * - * Collect the PDA data and put it in the message. - * - * Arguments: - * wlandev wlan device structure - * msgp ptr to msg buffer - * - * Returns: - * 0 success and done - * <0 success, but we're waiting for something to finish. - * >0 an error occurred while handling the message. - * Side effects: - * - * Call context: - * process thread (usually) - *---------------------------------------------------------------- - */ -int prism2mgmt_readpda(struct wlandevice *wlandev, void *msgp) -{ - struct hfa384x *hw = wlandev->priv; - struct p80211msg_p2req_readpda *msg = msgp; - int result; - - /* We only support collecting the PDA when in the FWLOAD - * state. - */ - if (wlandev->msdstate != WLAN_MSD_FWLOAD) { - netdev_err(wlandev->netdev, - "PDA may only be read in the fwload state.\n"); - msg->resultcode.data = - P80211ENUM_resultcode_implementation_failure; - msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; - } else { - /* Call drvr_readpda(), it handles the auxport enable - * and validating the returned PDA. - */ - result = hfa384x_drvr_readpda(hw, - msg->pda.data, - HFA384x_PDA_LEN_MAX); - if (result) { - netdev_err(wlandev->netdev, - "hfa384x_drvr_readpda() failed, result=%d\n", - result); - - msg->resultcode.data = - P80211ENUM_resultcode_implementation_failure; - msg->resultcode.status = - P80211ENUM_msgitem_status_data_ok; - return 0; - } - msg->pda.status = P80211ENUM_msgitem_status_data_ok; - msg->resultcode.data = P80211ENUM_resultcode_success; - msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; - } - - return 0; -} - -/*---------------------------------------------------------------- - * prism2mgmt_ramdl_state - * - * Establishes the beginning/end of a card RAM download session. - * - * It is expected that the ramdl_write() function will be called - * one or more times between the 'enable' and 'disable' calls to - * this function. - * - * Note: This function should not be called when a mac comm port - * is active. - * - * Arguments: - * wlandev wlan device structure - * msgp ptr to msg buffer - * - * Returns: - * 0 success and done - * <0 success, but we're waiting for something to finish. - * >0 an error occurred while handling the message. - * Side effects: - * - * Call context: - * process thread (usually) - *---------------------------------------------------------------- - */ -int prism2mgmt_ramdl_state(struct wlandevice *wlandev, void *msgp) -{ - struct hfa384x *hw = wlandev->priv; - struct p80211msg_p2req_ramdl_state *msg = msgp; - - if (wlandev->msdstate != WLAN_MSD_FWLOAD) { - netdev_err(wlandev->netdev, - "ramdl_state(): may only be called in the fwload state.\n"); - msg->resultcode.data = - P80211ENUM_resultcode_implementation_failure; - msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; - return 0; - } - - /* - ** Note: Interrupts are locked out if this is an AP and are NOT - ** locked out if this is a station. - */ - - msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; - if (msg->enable.data == P80211ENUM_truth_true) { - if (hfa384x_drvr_ramdl_enable(hw, msg->exeaddr.data)) { - msg->resultcode.data = - P80211ENUM_resultcode_implementation_failure; - } else { - msg->resultcode.data = P80211ENUM_resultcode_success; - } - } else { - hfa384x_drvr_ramdl_disable(hw); - msg->resultcode.data = P80211ENUM_resultcode_success; - } - - return 0; -} - -/*---------------------------------------------------------------- - * prism2mgmt_ramdl_write - * - * Writes a buffer to the card RAM using the download state. This - * is for writing code to card RAM. To just read or write raw data - * use the aux functions. - * - * Arguments: - * wlandev wlan device structure - * msgp ptr to msg buffer - * - * Returns: - * 0 success and done - * <0 success, but we're waiting for something to finish. - * >0 an error occurred while handling the message. - * Side effects: - * - * Call context: - * process thread (usually) - *---------------------------------------------------------------- - */ -int prism2mgmt_ramdl_write(struct wlandevice *wlandev, void *msgp) -{ - struct hfa384x *hw = wlandev->priv; - struct p80211msg_p2req_ramdl_write *msg = msgp; - u32 addr; - u32 len; - u8 *buf; - - if (wlandev->msdstate != WLAN_MSD_FWLOAD) { - netdev_err(wlandev->netdev, - "ramdl_write(): may only be called in the fwload state.\n"); - msg->resultcode.data = - P80211ENUM_resultcode_implementation_failure; - msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; - return 0; - } - - msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; - /* first validate the length */ - if (msg->len.data > sizeof(msg->data.data)) { - msg->resultcode.status = - P80211ENUM_resultcode_invalid_parameters; - return 0; - } - /* call the hfa384x function to do the write */ - addr = msg->addr.data; - len = msg->len.data; - buf = msg->data.data; - if (hfa384x_drvr_ramdl_write(hw, addr, buf, len)) - msg->resultcode.data = P80211ENUM_resultcode_refused; - - msg->resultcode.data = P80211ENUM_resultcode_success; - - return 0; -} - -/*---------------------------------------------------------------- - * prism2mgmt_flashdl_state - * - * Establishes the beginning/end of a card Flash download session. - * - * It is expected that the flashdl_write() function will be called - * one or more times between the 'enable' and 'disable' calls to - * this function. - * - * Note: This function should not be called when a mac comm port - * is active. - * - * Arguments: - * wlandev wlan device structure - * msgp ptr to msg buffer - * - * Returns: - * 0 success and done - * <0 success, but we're waiting for something to finish. - * >0 an error occurred while handling the message. - * Side effects: - * - * Call context: - * process thread (usually) - *---------------------------------------------------------------- - */ -int prism2mgmt_flashdl_state(struct wlandevice *wlandev, void *msgp) -{ - int result = 0; - struct hfa384x *hw = wlandev->priv; - struct p80211msg_p2req_flashdl_state *msg = msgp; - - if (wlandev->msdstate != WLAN_MSD_FWLOAD) { - netdev_err(wlandev->netdev, - "flashdl_state(): may only be called in the fwload state.\n"); - msg->resultcode.data = - P80211ENUM_resultcode_implementation_failure; - msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; - return 0; - } - - /* - ** Note: Interrupts are locked out if this is an AP and are NOT - ** locked out if this is a station. - */ - - msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; - if (msg->enable.data == P80211ENUM_truth_true) { - if (hfa384x_drvr_flashdl_enable(hw)) { - msg->resultcode.data = - P80211ENUM_resultcode_implementation_failure; - } else { - msg->resultcode.data = P80211ENUM_resultcode_success; - } - } else { - hfa384x_drvr_flashdl_disable(hw); - msg->resultcode.data = P80211ENUM_resultcode_success; - /* NOTE: At this point, the MAC is in the post-reset - * state and the driver is in the fwload state. - * We need to get the MAC back into the fwload - * state. To do this, we set the nsdstate to HWPRESENT - * and then call the ifstate function to redo everything - * that got us into the fwload state. - */ - wlandev->msdstate = WLAN_MSD_HWPRESENT; - result = prism2sta_ifstate(wlandev, P80211ENUM_ifstate_fwload); - if (result != P80211ENUM_resultcode_success) { - netdev_err(wlandev->netdev, - "prism2sta_ifstate(fwload) failed, P80211ENUM_resultcode=%d\n", - result); - msg->resultcode.data = - P80211ENUM_resultcode_implementation_failure; - result = -1; - } - } - - return result; -} - -/*---------------------------------------------------------------- - * prism2mgmt_flashdl_write - * - * - * - * Arguments: - * wlandev wlan device structure - * msgp ptr to msg buffer - * - * Returns: - * 0 success and done - * <0 success, but we're waiting for something to finish. - * >0 an error occurred while handling the message. - * Side effects: - * - * Call context: - * process thread (usually) - *---------------------------------------------------------------- - */ -int prism2mgmt_flashdl_write(struct wlandevice *wlandev, void *msgp) -{ - struct hfa384x *hw = wlandev->priv; - struct p80211msg_p2req_flashdl_write *msg = msgp; - u32 addr; - u32 len; - u8 *buf; - - if (wlandev->msdstate != WLAN_MSD_FWLOAD) { - netdev_err(wlandev->netdev, - "flashdl_write(): may only be called in the fwload state.\n"); - msg->resultcode.data = - P80211ENUM_resultcode_implementation_failure; - msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; - return 0; - } - - /* - ** Note: Interrupts are locked out if this is an AP and are NOT - ** locked out if this is a station. - */ - - msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; - /* first validate the length */ - if (msg->len.data > sizeof(msg->data.data)) { - msg->resultcode.status = - P80211ENUM_resultcode_invalid_parameters; - return 0; - } - /* call the hfa384x function to do the write */ - addr = msg->addr.data; - len = msg->len.data; - buf = msg->data.data; - if (hfa384x_drvr_flashdl_write(hw, addr, buf, len)) - msg->resultcode.data = P80211ENUM_resultcode_refused; - - msg->resultcode.data = P80211ENUM_resultcode_success; - - return 0; -} - -/*---------------------------------------------------------------- - * prism2mgmt_autojoin - * - * Associate with an ESS. - * - * Arguments: - * wlandev wlan device structure - * msgp ptr to msg buffer - * - * Returns: - * 0 success and done - * <0 success, but we're waiting for something to finish. - * >0 an error occurred while handling the message. - * Side effects: - * - * Call context: - * process thread (usually) - * interrupt - *---------------------------------------------------------------- - */ -int prism2mgmt_autojoin(struct wlandevice *wlandev, void *msgp) -{ - struct hfa384x *hw = wlandev->priv; - int result = 0; - u16 reg; - u16 port_type; - struct p80211msg_lnxreq_autojoin *msg = msgp; - struct p80211pstrd *pstr; - u8 bytebuf[256]; - struct hfa384x_bytestr *p2bytestr = (struct hfa384x_bytestr *)bytebuf; - - wlandev->macmode = WLAN_MACMODE_NONE; - - /* Set the SSID */ - memcpy(&wlandev->ssid, &msg->ssid.data, sizeof(msg->ssid.data)); - - /* Disable the Port */ - hfa384x_drvr_disable(hw, 0); - - /*** STATION ***/ - /* Set the TxRates */ - hfa384x_drvr_setconfig16(hw, HFA384x_RID_TXRATECNTL, 0x000f); - - /* Set the auth type */ - if (msg->authtype.data == P80211ENUM_authalg_sharedkey) - reg = HFA384x_CNFAUTHENTICATION_SHAREDKEY; - else - reg = HFA384x_CNFAUTHENTICATION_OPENSYSTEM; - - hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFAUTHENTICATION, reg); - - /* Set the ssid */ - memset(bytebuf, 0, 256); - pstr = (struct p80211pstrd *)&msg->ssid.data; - prism2mgmt_pstr2bytestr(p2bytestr, pstr); - result = hfa384x_drvr_setconfig(hw, HFA384x_RID_CNFDESIREDSSID, - bytebuf, - HFA384x_RID_CNFDESIREDSSID_LEN); - port_type = HFA384x_PORTTYPE_BSS; - /* Set the PortType */ - hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFPORTTYPE, port_type); - - /* Enable the Port */ - hfa384x_drvr_enable(hw, 0); - - /* Set the resultcode */ - msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; - msg->resultcode.data = P80211ENUM_resultcode_success; - - return result; -} - -/*---------------------------------------------------------------- - * prism2mgmt_wlansniff - * - * Start or stop sniffing. - * - * Arguments: - * wlandev wlan device structure - * msgp ptr to msg buffer - * - * Returns: - * 0 success and done - * <0 success, but we're waiting for something to finish. - * >0 an error occurred while handling the message. - * Side effects: - * - * Call context: - * process thread (usually) - * interrupt - *---------------------------------------------------------------- - */ -int prism2mgmt_wlansniff(struct wlandevice *wlandev, void *msgp) -{ - int result = 0; - struct p80211msg_lnxreq_wlansniff *msg = msgp; - - struct hfa384x *hw = wlandev->priv; - u16 word; - - msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; - switch (msg->enable.data) { - case P80211ENUM_truth_false: - /* Confirm that we're in monitor mode */ - if (wlandev->netdev->type == ARPHRD_ETHER) { - msg->resultcode.data = - P80211ENUM_resultcode_invalid_parameters; - return 0; - } - /* Disable monitor mode */ - result = hfa384x_cmd_monitor(hw, HFA384x_MONITOR_DISABLE); - if (result) { - netdev_dbg(wlandev->netdev, - "failed to disable monitor mode, result=%d\n", - result); - goto failed; - } - /* Disable port 0 */ - result = hfa384x_drvr_disable(hw, 0); - if (result) { - netdev_dbg - (wlandev->netdev, - "failed to disable port 0 after sniffing, result=%d\n", - result); - goto failed; - } - /* Clear the driver state */ - wlandev->netdev->type = ARPHRD_ETHER; - - /* Restore the wepflags */ - result = hfa384x_drvr_setconfig16(hw, - HFA384x_RID_CNFWEPFLAGS, - hw->presniff_wepflags); - if (result) { - netdev_dbg - (wlandev->netdev, - "failed to restore wepflags=0x%04x, result=%d\n", - hw->presniff_wepflags, result); - goto failed; - } - - /* Set the port to its prior type and enable (if necessary) */ - if (hw->presniff_port_type != 0) { - word = hw->presniff_port_type; - result = hfa384x_drvr_setconfig16(hw, - HFA384x_RID_CNFPORTTYPE, - word); - if (result) { - netdev_dbg - (wlandev->netdev, - "failed to restore porttype, result=%d\n", - result); - goto failed; - } - - /* Enable the port */ - result = hfa384x_drvr_enable(hw, 0); - if (result) { - netdev_dbg(wlandev->netdev, - "failed to enable port to presniff setting, result=%d\n", - result); - goto failed; - } - } else { - result = hfa384x_drvr_disable(hw, 0); - } - - netdev_info(wlandev->netdev, "monitor mode disabled\n"); - msg->resultcode.data = P80211ENUM_resultcode_success; - return 0; - case P80211ENUM_truth_true: - /* Disable the port (if enabled), only check Port 0 */ - if (hw->port_enabled[0]) { - if (wlandev->netdev->type == ARPHRD_ETHER) { - /* Save macport 0 state */ - result = hfa384x_drvr_getconfig16(hw, - HFA384x_RID_CNFPORTTYPE, - &hw->presniff_port_type); - if (result) { - netdev_dbg - (wlandev->netdev, - "failed to read porttype, result=%d\n", - result); - goto failed; - } - /* Save the wepflags state */ - result = hfa384x_drvr_getconfig16(hw, - HFA384x_RID_CNFWEPFLAGS, - &hw->presniff_wepflags); - if (result) { - netdev_dbg - (wlandev->netdev, - "failed to read wepflags, result=%d\n", - result); - goto failed; - } - hfa384x_drvr_stop(hw); - result = hfa384x_drvr_start(hw); - if (result) { - netdev_dbg(wlandev->netdev, - "failed to restart the card for sniffing, result=%d\n", - result); - goto failed; - } - } else { - /* Disable the port */ - result = hfa384x_drvr_disable(hw, 0); - if (result) { - netdev_dbg(wlandev->netdev, - "failed to enable port for sniffing, result=%d\n", - result); - goto failed; - } - } - } else { - hw->presniff_port_type = 0; - } - - /* Set the channel we wish to sniff */ - word = msg->channel.data; - result = hfa384x_drvr_setconfig16(hw, - HFA384x_RID_CNFOWNCHANNEL, - word); - hw->sniff_channel = word; - - if (result) { - netdev_dbg(wlandev->netdev, - "failed to set channel %d, result=%d\n", - word, result); - goto failed; - } - - /* Now if we're already sniffing, we can skip the rest */ - if (wlandev->netdev->type != ARPHRD_ETHER) { - /* Set the port type to pIbss */ - word = HFA384x_PORTTYPE_PSUEDOIBSS; - result = hfa384x_drvr_setconfig16(hw, - HFA384x_RID_CNFPORTTYPE, - word); - if (result) { - netdev_dbg - (wlandev->netdev, - "failed to set porttype %d, result=%d\n", - word, result); - goto failed; - } - if ((msg->keepwepflags.status == - P80211ENUM_msgitem_status_data_ok) && - (msg->keepwepflags.data != P80211ENUM_truth_true)) { - /* Set the wepflags for no decryption */ - word = HFA384x_WEPFLAGS_DISABLE_TXCRYPT | - HFA384x_WEPFLAGS_DISABLE_RXCRYPT; - result = - hfa384x_drvr_setconfig16(hw, - HFA384x_RID_CNFWEPFLAGS, - word); - } - - if (result) { - netdev_dbg - (wlandev->netdev, - "failed to set wepflags=0x%04x, result=%d\n", - word, result); - goto failed; - } - } - - /* Do we want to strip the FCS in monitor mode? */ - if ((msg->stripfcs.status == - P80211ENUM_msgitem_status_data_ok) && - (msg->stripfcs.data == P80211ENUM_truth_true)) { - hw->sniff_fcs = 0; - } else { - hw->sniff_fcs = 1; - } - - /* Do we want to truncate the packets? */ - if (msg->packet_trunc.status == - P80211ENUM_msgitem_status_data_ok) { - hw->sniff_truncate = msg->packet_trunc.data; - } else { - hw->sniff_truncate = 0; - } - - /* Enable the port */ - result = hfa384x_drvr_enable(hw, 0); - if (result) { - netdev_dbg - (wlandev->netdev, - "failed to enable port for sniffing, result=%d\n", - result); - goto failed; - } - /* Enable monitor mode */ - result = hfa384x_cmd_monitor(hw, HFA384x_MONITOR_ENABLE); - if (result) { - netdev_dbg(wlandev->netdev, - "failed to enable monitor mode, result=%d\n", - result); - goto failed; - } - - if (wlandev->netdev->type == ARPHRD_ETHER) - netdev_info(wlandev->netdev, "monitor mode enabled\n"); - - /* Set the driver state */ - /* Do we want the prism2 header? */ - if ((msg->prismheader.status == - P80211ENUM_msgitem_status_data_ok) && - (msg->prismheader.data == P80211ENUM_truth_true)) { - hw->sniffhdr = 0; - wlandev->netdev->type = ARPHRD_IEEE80211_PRISM; - } else if ((msg->wlanheader.status == - P80211ENUM_msgitem_status_data_ok) && - (msg->wlanheader.data == P80211ENUM_truth_true)) { - hw->sniffhdr = 1; - wlandev->netdev->type = ARPHRD_IEEE80211_PRISM; - } else { - wlandev->netdev->type = ARPHRD_IEEE80211; - } - - msg->resultcode.data = P80211ENUM_resultcode_success; - return 0; - default: - msg->resultcode.data = P80211ENUM_resultcode_invalid_parameters; - return 0; - } - -failed: - msg->resultcode.data = P80211ENUM_resultcode_refused; - return 0; -} diff --git a/drivers/staging/wlan-ng/prism2mgmt.h b/drivers/staging/wlan-ng/prism2mgmt.h deleted file mode 100644 index 17222516e85e..000000000000 --- a/drivers/staging/wlan-ng/prism2mgmt.h +++ /dev/null @@ -1,89 +0,0 @@ -/* SPDX-License-Identifier: (GPL-2.0 OR MPL-1.1) */ -/* - * - * Declares the mgmt command handler functions - * - * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. - * -------------------------------------------------------------------- - * - * linux-wlan - * - * -------------------------------------------------------------------- - * - * Inquiries regarding the linux-wlan Open Source project can be - * made directly to: - * - * AbsoluteValue Systems Inc. - * info@linux-wlan.com - * http://www.linux-wlan.com - * - * -------------------------------------------------------------------- - * - * Portions of the development of this software were funded by - * Intersil Corporation as part of PRISM(R) chipset product development. - * - * -------------------------------------------------------------------- - * - * This file contains the constants and data structures for interaction - * with the hfa384x Wireless LAN (WLAN) Media Access Controller (MAC). - * The hfa384x is a portion of the Harris PRISM(tm) WLAN chipset. - * - * [Implementation and usage notes] - * - * [References] - * CW10 Programmer's Manual v1.5 - * IEEE 802.11 D10.0 - * - * -------------------------------------------------------------------- - */ - -#ifndef _PRISM2MGMT_H -#define _PRISM2MGMT_H - -extern int prism2_reset_holdtime; -extern int prism2_reset_settletime; - -u32 prism2sta_ifstate(struct wlandevice *wlandev, u32 ifstate); - -void prism2sta_ev_info(struct wlandevice *wlandev, struct hfa384x_inf_frame *inf); -void prism2sta_ev_tx(struct wlandevice *wlandev, u16 status); -void prism2sta_ev_alloc(struct wlandevice *wlandev); - -int prism2mgmt_mibset_mibget(struct wlandevice *wlandev, void *msgp); -int prism2mgmt_scan(struct wlandevice *wlandev, void *msgp); -int prism2mgmt_scan_results(struct wlandevice *wlandev, void *msgp); -int prism2mgmt_start(struct wlandevice *wlandev, void *msgp); -int prism2mgmt_wlansniff(struct wlandevice *wlandev, void *msgp); -int prism2mgmt_readpda(struct wlandevice *wlandev, void *msgp); -int prism2mgmt_ramdl_state(struct wlandevice *wlandev, void *msgp); -int prism2mgmt_ramdl_write(struct wlandevice *wlandev, void *msgp); -int prism2mgmt_flashdl_state(struct wlandevice *wlandev, void *msgp); -int prism2mgmt_flashdl_write(struct wlandevice *wlandev, void *msgp); -int prism2mgmt_autojoin(struct wlandevice *wlandev, void *msgp); - -/*--------------------------------------------------------------- - * conversion functions going between wlan message data types and - * Prism2 data types - *--------------------------------------------------------------- - */ - -/* byte area conversion functions*/ -void prism2mgmt_bytearea2pstr(u8 *bytearea, struct p80211pstrd *pstr, int len); - -/* byte string conversion functions*/ -void prism2mgmt_pstr2bytestr(struct hfa384x_bytestr *bytestr, - struct p80211pstrd *pstr); -void prism2mgmt_bytestr2pstr(struct hfa384x_bytestr *bytestr, - struct p80211pstrd *pstr); - -void prism2sta_processing_defer(struct work_struct *data); - -void prism2sta_commsqual_defer(struct work_struct *data); -void prism2sta_commsqual_timer(struct timer_list *t); - -/* Interface callback functions, passing data back up to the cfg80211 layer */ -void prism2_connect_result(struct wlandevice *wlandev, u8 failed); -void prism2_disconnected(struct wlandevice *wlandev); -void prism2_roamed(struct wlandevice *wlandev); - -#endif diff --git a/drivers/staging/wlan-ng/prism2mib.c b/drivers/staging/wlan-ng/prism2mib.c deleted file mode 100644 index 4346b90c1a77..000000000000 --- a/drivers/staging/wlan-ng/prism2mib.c +++ /dev/null @@ -1,742 +0,0 @@ -// SPDX-License-Identifier: (GPL-2.0 OR MPL-1.1) -/* - * - * Management request for mibset/mibget - * - * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. - * -------------------------------------------------------------------- - * - * linux-wlan - * - * -------------------------------------------------------------------- - * - * Inquiries regarding the linux-wlan Open Source project can be - * made directly to: - * - * AbsoluteValue Systems Inc. - * info@linux-wlan.com - * http://www.linux-wlan.com - * - * -------------------------------------------------------------------- - * - * Portions of the development of this software were funded by - * Intersil Corporation as part of PRISM(R) chipset product development. - * - * -------------------------------------------------------------------- - * - * The functions in this file handle the mibset/mibget management - * functions. - * - * -------------------------------------------------------------------- - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "p80211types.h" -#include "p80211hdr.h" -#include "p80211mgmt.h" -#include "p80211conv.h" -#include "p80211msg.h" -#include "p80211netdev.h" -#include "p80211metadef.h" -#include "p80211metastruct.h" -#include "hfa384x.h" -#include "prism2mgmt.h" - -#define MIB_TMP_MAXLEN 200 /* Max length of RID record (in bytes). */ - -#define F_STA 0x1 /* MIB is supported on stations. */ -#define F_READ 0x2 /* MIB may be read. */ -#define F_WRITE 0x4 /* MIB may be written. */ - -struct mibrec { - u32 did; - u16 flag; - u16 parm1; - u16 parm2; - u16 parm3; - int (*func)(struct mibrec *mib, - int isget, - struct wlandevice *wlandev, - struct hfa384x *hw, - struct p80211msg_dot11req_mibset *msg, void *data); -}; - -static int prism2mib_bytearea2pstr(struct mibrec *mib, - int isget, - struct wlandevice *wlandev, - struct hfa384x *hw, - struct p80211msg_dot11req_mibset *msg, - void *data); - -static int prism2mib_uint32(struct mibrec *mib, - int isget, - struct wlandevice *wlandev, - struct hfa384x *hw, - struct p80211msg_dot11req_mibset *msg, void *data); - -static int prism2mib_flag(struct mibrec *mib, - int isget, - struct wlandevice *wlandev, - struct hfa384x *hw, - struct p80211msg_dot11req_mibset *msg, void *data); - -static int prism2mib_wepdefaultkey(struct mibrec *mib, - int isget, - struct wlandevice *wlandev, - struct hfa384x *hw, - struct p80211msg_dot11req_mibset *msg, - void *data); - -static int prism2mib_privacyinvoked(struct mibrec *mib, - int isget, - struct wlandevice *wlandev, - struct hfa384x *hw, - struct p80211msg_dot11req_mibset *msg, - void *data); - -static int -prism2mib_fragmentationthreshold(struct mibrec *mib, - int isget, - struct wlandevice *wlandev, - struct hfa384x *hw, - struct p80211msg_dot11req_mibset *msg, - void *data); - -static int prism2mib_priv(struct mibrec *mib, - int isget, - struct wlandevice *wlandev, - struct hfa384x *hw, - struct p80211msg_dot11req_mibset *msg, void *data); - -static struct mibrec mibtab[] = { - /* dot11smt MIB's */ - {didmib_dot11smt_wepdefaultkeystable_key(1), - F_STA | F_WRITE, - HFA384x_RID_CNFWEPDEFAULTKEY0, 0, 0, - prism2mib_wepdefaultkey}, - {didmib_dot11smt_wepdefaultkeystable_key(2), - F_STA | F_WRITE, - HFA384x_RID_CNFWEPDEFAULTKEY1, 0, 0, - prism2mib_wepdefaultkey}, - {didmib_dot11smt_wepdefaultkeystable_key(3), - F_STA | F_WRITE, - HFA384x_RID_CNFWEPDEFAULTKEY2, 0, 0, - prism2mib_wepdefaultkey}, - {didmib_dot11smt_wepdefaultkeystable_key(4), - F_STA | F_WRITE, - HFA384x_RID_CNFWEPDEFAULTKEY3, 0, 0, - prism2mib_wepdefaultkey}, - {DIDMIB_DOT11SMT_PRIVACYTABLE_PRIVACYINVOKED, - F_STA | F_READ | F_WRITE, - HFA384x_RID_CNFWEPFLAGS, HFA384x_WEPFLAGS_PRIVINVOKED, 0, - prism2mib_privacyinvoked}, - {DIDMIB_DOT11SMT_PRIVACYTABLE_WEPDEFAULTKEYID, - F_STA | F_READ | F_WRITE, - HFA384x_RID_CNFWEPDEFAULTKEYID, 0, 0, - prism2mib_uint32}, - {DIDMIB_DOT11SMT_PRIVACYTABLE_EXCLUDEUNENCRYPTED, - F_STA | F_READ | F_WRITE, - HFA384x_RID_CNFWEPFLAGS, HFA384x_WEPFLAGS_EXCLUDE, 0, - prism2mib_flag}, - - /* dot11mac MIB's */ - - {DIDMIB_DOT11MAC_OPERATIONTABLE_MACADDRESS, - F_STA | F_READ | F_WRITE, - HFA384x_RID_CNFOWNMACADDR, HFA384x_RID_CNFOWNMACADDR_LEN, 0, - prism2mib_bytearea2pstr}, - {DIDMIB_DOT11MAC_OPERATIONTABLE_RTSTHRESHOLD, - F_STA | F_READ | F_WRITE, - HFA384x_RID_RTSTHRESH, 0, 0, - prism2mib_uint32}, - {DIDMIB_DOT11MAC_OPERATIONTABLE_SHORTRETRYLIMIT, - F_STA | F_READ, - HFA384x_RID_SHORTRETRYLIMIT, 0, 0, - prism2mib_uint32}, - {DIDMIB_DOT11MAC_OPERATIONTABLE_LONGRETRYLIMIT, - F_STA | F_READ, - HFA384x_RID_LONGRETRYLIMIT, 0, 0, - prism2mib_uint32}, - {DIDMIB_DOT11MAC_OPERATIONTABLE_FRAGMENTATIONTHRESHOLD, - F_STA | F_READ | F_WRITE, - HFA384x_RID_FRAGTHRESH, 0, 0, - prism2mib_fragmentationthreshold}, - {DIDMIB_DOT11MAC_OPERATIONTABLE_MAXTRANSMITMSDULIFETIME, - F_STA | F_READ, - HFA384x_RID_MAXTXLIFETIME, 0, 0, - prism2mib_uint32}, - - /* dot11phy MIB's */ - - {DIDMIB_DOT11PHY_DSSSTABLE_CURRENTCHANNEL, - F_STA | F_READ, - HFA384x_RID_CURRENTCHANNEL, 0, 0, - prism2mib_uint32}, - {DIDMIB_DOT11PHY_TXPOWERTABLE_CURRENTTXPOWERLEVEL, - F_STA | F_READ | F_WRITE, - HFA384x_RID_TXPOWERMAX, 0, 0, - prism2mib_uint32}, - - /* p2Static MIB's */ - - {DIDMIB_P2_STATIC_CNFPORTTYPE, - F_STA | F_READ | F_WRITE, - HFA384x_RID_CNFPORTTYPE, 0, 0, - prism2mib_uint32}, - - /* p2MAC MIB's */ - - {DIDMIB_P2_MAC_CURRENTTXRATE, - F_STA | F_READ, - HFA384x_RID_CURRENTTXRATE, 0, 0, - prism2mib_uint32}, - - /* And finally, lnx mibs */ - {DIDMIB_LNX_CONFIGTABLE_RSNAIE, - F_STA | F_READ | F_WRITE, - HFA384x_RID_CNFWPADATA, 0, 0, - prism2mib_priv}, - {0, 0, 0, 0, 0, NULL} -}; - -/* - * prism2mgmt_mibset_mibget - * - * Set the value of a mib item. - * - * Arguments: - * wlandev wlan device structure - * msgp ptr to msg buffer - * - * Returns: - * 0 success and done - * <0 success, but we're waiting for something to finish. - * >0 an error occurred while handling the message. - * Side effects: - * - * Call context: - * process thread (usually) - * interrupt - */ - -int prism2mgmt_mibset_mibget(struct wlandevice *wlandev, void *msgp) -{ - struct hfa384x *hw = wlandev->priv; - int result, isget; - struct mibrec *mib; - - u16 which; - - struct p80211msg_dot11req_mibset *msg = msgp; - struct p80211itemd *mibitem; - - msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; - msg->resultcode.data = P80211ENUM_resultcode_success; - - /* - ** Determine if this is an Access Point or a station. - */ - - which = F_STA; - - /* - ** Find the MIB in the MIB table. Note that a MIB may be in the - ** table twice...once for an AP and once for a station. Make sure - ** to get the correct one. Note that DID=0 marks the end of the - ** MIB table. - */ - - mibitem = (struct p80211itemd *)msg->mibattribute.data; - - for (mib = mibtab; mib->did != 0; mib++) - if (mib->did == mibitem->did && (mib->flag & which)) - break; - - if (mib->did == 0) { - msg->resultcode.data = P80211ENUM_resultcode_not_supported; - goto done; - } - - /* - ** Determine if this is a "mibget" or a "mibset". If this is a - ** "mibget", then make sure that the MIB may be read. Otherwise, - ** this is a "mibset" so make sure that the MIB may be written. - */ - - isget = (msg->msgcode == DIDMSG_DOT11REQ_MIBGET); - - if (isget) { - if (!(mib->flag & F_READ)) { - msg->resultcode.data = - P80211ENUM_resultcode_cant_get_writeonly_mib; - goto done; - } - } else { - if (!(mib->flag & F_WRITE)) { - msg->resultcode.data = - P80211ENUM_resultcode_cant_set_readonly_mib; - goto done; - } - } - - /* - ** Execute the MIB function. If things worked okay, then make - ** sure that the MIB function also worked okay. If so, and this - ** is a "mibget", then the status value must be set for both the - ** "mibattribute" parameter and the mib item within the data - ** portion of the "mibattribute". - */ - - result = mib->func(mib, isget, wlandev, hw, msg, (void *)mibitem->data); - - if (msg->resultcode.data == P80211ENUM_resultcode_success) { - if (result != 0) { - pr_debug("get/set failure, result=%d\n", result); - msg->resultcode.data = - P80211ENUM_resultcode_implementation_failure; - } else { - if (isget) { - msg->mibattribute.status = - P80211ENUM_msgitem_status_data_ok; - mibitem->status = - P80211ENUM_msgitem_status_data_ok; - } - } - } - -done: - return 0; -} - -/* - * prism2mib_bytearea2pstr - * - * Get/set pstr data to/from a byte area. - * - * MIB record parameters: - * parm1 Prism2 RID value. - * parm2 Number of bytes of RID data. - * parm3 Not used. - * - * Arguments: - * mib MIB record. - * isget MIBGET/MIBSET flag. - * wlandev wlan device structure. - * priv "priv" structure. - * hw "hw" structure. - * msg Message structure. - * data Data buffer. - * - * Returns: - * 0 - Success. - * ~0 - Error. - * - */ - -static int prism2mib_bytearea2pstr(struct mibrec *mib, - int isget, - struct wlandevice *wlandev, - struct hfa384x *hw, - struct p80211msg_dot11req_mibset *msg, - void *data) -{ - int result; - struct p80211pstrd *pstr = data; - u8 bytebuf[MIB_TMP_MAXLEN]; - - if (isget) { - result = - hfa384x_drvr_getconfig(hw, mib->parm1, bytebuf, mib->parm2); - prism2mgmt_bytearea2pstr(bytebuf, pstr, mib->parm2); - } else { - memset(bytebuf, 0, mib->parm2); - memcpy(bytebuf, pstr->data, pstr->len); - result = - hfa384x_drvr_setconfig(hw, mib->parm1, bytebuf, mib->parm2); - } - - return result; -} - -/* - * prism2mib_uint32 - * - * Get/set uint32 data. - * - * MIB record parameters: - * parm1 Prism2 RID value. - * parm2 Not used. - * parm3 Not used. - * - * Arguments: - * mib MIB record. - * isget MIBGET/MIBSET flag. - * wlandev wlan device structure. - * priv "priv" structure. - * hw "hw" structure. - * msg Message structure. - * data Data buffer. - * - * Returns: - * 0 - Success. - * ~0 - Error. - * - */ - -static int prism2mib_uint32(struct mibrec *mib, - int isget, - struct wlandevice *wlandev, - struct hfa384x *hw, - struct p80211msg_dot11req_mibset *msg, void *data) -{ - int result; - u32 *uint32 = data; - u8 bytebuf[MIB_TMP_MAXLEN]; - u16 *wordbuf = (u16 *)bytebuf; - - if (isget) { - result = hfa384x_drvr_getconfig16(hw, mib->parm1, wordbuf); - *uint32 = *wordbuf; - } else { - *wordbuf = *uint32; - result = hfa384x_drvr_setconfig16(hw, mib->parm1, *wordbuf); - } - - return result; -} - -/* - * prism2mib_flag - * - * Get/set a flag. - * - * MIB record parameters: - * parm1 Prism2 RID value. - * parm2 Bit to get/set. - * parm3 Not used. - * - * Arguments: - * mib MIB record. - * isget MIBGET/MIBSET flag. - * wlandev wlan device structure. - * priv "priv" structure. - * hw "hw" structure. - * msg Message structure. - * data Data buffer. - * - * Returns: - * 0 - Success. - * ~0 - Error. - * - */ - -static int prism2mib_flag(struct mibrec *mib, - int isget, - struct wlandevice *wlandev, - struct hfa384x *hw, - struct p80211msg_dot11req_mibset *msg, void *data) -{ - int result; - u32 *uint32 = data; - u8 bytebuf[MIB_TMP_MAXLEN]; - u16 *wordbuf = (u16 *)bytebuf; - u32 flags; - - result = hfa384x_drvr_getconfig16(hw, mib->parm1, wordbuf); - if (result == 0) { - flags = *wordbuf; - if (isget) { - *uint32 = (flags & mib->parm2) ? - P80211ENUM_truth_true : P80211ENUM_truth_false; - } else { - if ((*uint32) == P80211ENUM_truth_true) - flags |= mib->parm2; - else - flags &= ~mib->parm2; - *wordbuf = flags; - result = - hfa384x_drvr_setconfig16(hw, mib->parm1, *wordbuf); - } - } - - return result; -} - -/* - * prism2mib_wepdefaultkey - * - * Get/set WEP default keys. - * - * MIB record parameters: - * parm1 Prism2 RID value. - * parm2 Number of bytes of RID data. - * parm3 Not used. - * - * Arguments: - * mib MIB record. - * isget MIBGET/MIBSET flag. - * wlandev wlan device structure. - * priv "priv" structure. - * hw "hw" structure. - * msg Message structure. - * data Data buffer. - * - * Returns: - * 0 - Success. - * ~0 - Error. - * - */ - -static int prism2mib_wepdefaultkey(struct mibrec *mib, - int isget, - struct wlandevice *wlandev, - struct hfa384x *hw, - struct p80211msg_dot11req_mibset *msg, - void *data) -{ - int result; - struct p80211pstrd *pstr = data; - u8 bytebuf[MIB_TMP_MAXLEN]; - u16 len; - - if (isget) { - result = 0; /* Should never happen. */ - } else { - len = (pstr->len > 5) ? HFA384x_RID_CNFWEP128DEFAULTKEY_LEN : - HFA384x_RID_CNFWEPDEFAULTKEY_LEN; - memset(bytebuf, 0, len); - memcpy(bytebuf, pstr->data, pstr->len); - result = hfa384x_drvr_setconfig(hw, mib->parm1, bytebuf, len); - } - - return result; -} - -/* - * prism2mib_privacyinvoked - * - * Get/set the dot11PrivacyInvoked value. - * - * MIB record parameters: - * parm1 Prism2 RID value. - * parm2 Bit value for PrivacyInvoked flag. - * parm3 Not used. - * - * Arguments: - * mib MIB record. - * isget MIBGET/MIBSET flag. - * wlandev wlan device structure. - * priv "priv" structure. - * hw "hw" structure. - * msg Message structure. - * data Data buffer. - * - * Returns: - * 0 - Success. - * ~0 - Error. - * - */ - -static int prism2mib_privacyinvoked(struct mibrec *mib, - int isget, - struct wlandevice *wlandev, - struct hfa384x *hw, - struct p80211msg_dot11req_mibset *msg, - void *data) -{ - if (wlandev->hostwep & HOSTWEP_DECRYPT) { - if (wlandev->hostwep & HOSTWEP_DECRYPT) - mib->parm2 |= HFA384x_WEPFLAGS_DISABLE_RXCRYPT; - if (wlandev->hostwep & HOSTWEP_ENCRYPT) - mib->parm2 |= HFA384x_WEPFLAGS_DISABLE_TXCRYPT; - } - - return prism2mib_flag(mib, isget, wlandev, hw, msg, data); -} - -/* - * prism2mib_fragmentationthreshold - * - * Get/set the fragmentation threshold. - * - * MIB record parameters: - * parm1 Prism2 RID value. - * parm2 Not used. - * parm3 Not used. - * - * Arguments: - * mib MIB record. - * isget MIBGET/MIBSET flag. - * wlandev wlan device structure. - * priv "priv" structure. - * hw "hw" structure. - * msg Message structure. - * data Data buffer. - * - * Returns: - * 0 - Success. - * ~0 - Error. - * - */ - -static int -prism2mib_fragmentationthreshold(struct mibrec *mib, - int isget, - struct wlandevice *wlandev, - struct hfa384x *hw, - struct p80211msg_dot11req_mibset *msg, - void *data) -{ - u32 *uint32 = data; - - if (!isget) - if ((*uint32) % 2) { - netdev_warn(wlandev->netdev, - "Attempt to set odd number FragmentationThreshold\n"); - msg->resultcode.data = - P80211ENUM_resultcode_not_supported; - return 0; - } - - return prism2mib_uint32(mib, isget, wlandev, hw, msg, data); -} - -/* - * prism2mib_priv - * - * Get/set values in the "priv" data structure. - * - * MIB record parameters: - * parm1 Not used. - * parm2 Not used. - * parm3 Not used. - * - * Arguments: - * mib MIB record. - * isget MIBGET/MIBSET flag. - * wlandev wlan device structure. - * priv "priv" structure. - * hw "hw" structure. - * msg Message structure. - * data Data buffer. - * - * Returns: - * 0 - Success. - * ~0 - Error. - * - */ - -static int prism2mib_priv(struct mibrec *mib, - int isget, - struct wlandevice *wlandev, - struct hfa384x *hw, - struct p80211msg_dot11req_mibset *msg, void *data) -{ - struct p80211pstrd *pstr = data; - - switch (mib->did) { - case DIDMIB_LNX_CONFIGTABLE_RSNAIE: { - /* - * This can never work: wpa is on the stack - * and has no bytes allocated in wpa.data. - */ - struct hfa384x_wpa_data wpa; - - if (isget) { - hfa384x_drvr_getconfig(hw, - HFA384x_RID_CNFWPADATA, - (u8 *)&wpa, - sizeof(wpa)); - pstr->len = 0; - } else { - wpa.datalen = 0; - - hfa384x_drvr_setconfig(hw, - HFA384x_RID_CNFWPADATA, - (u8 *)&wpa, - sizeof(wpa)); - } - break; - } - default: - netdev_err(wlandev->netdev, "Unhandled DID 0x%08x\n", mib->did); - } - - return 0; -} - -/* - * prism2mgmt_pstr2bytestr - * - * Convert the pstr data in the WLAN message structure into an hfa384x - * byte string format. - * - * Arguments: - * bytestr hfa384x byte string data type - * pstr wlan message data - * - * Returns: - * Nothing - * - */ - -void prism2mgmt_pstr2bytestr(struct hfa384x_bytestr *bytestr, - struct p80211pstrd *pstr) -{ - bytestr->len = cpu_to_le16((u16)(pstr->len)); - memcpy(bytestr->data, pstr->data, pstr->len); -} - -/* - * prism2mgmt_bytestr2pstr - * - * Convert the data in an hfa384x byte string format into a - * pstr in the WLAN message. - * - * Arguments: - * bytestr hfa384x byte string data type - * msg wlan message - * - * Returns: - * Nothing - * - */ - -void prism2mgmt_bytestr2pstr(struct hfa384x_bytestr *bytestr, - struct p80211pstrd *pstr) -{ - pstr->len = (u8)(le16_to_cpu(bytestr->len)); - memcpy(pstr->data, bytestr->data, pstr->len); -} - -/* - * prism2mgmt_bytearea2pstr - * - * Convert the data in an hfa384x byte area format into a pstr - * in the WLAN message. - * - * Arguments: - * bytearea hfa384x byte area data type - * msg wlan message - * - * Returns: - * Nothing - * - */ - -void prism2mgmt_bytearea2pstr(u8 *bytearea, struct p80211pstrd *pstr, int len) -{ - pstr->len = (u8)len; - memcpy(pstr->data, bytearea, len); -} diff --git a/drivers/staging/wlan-ng/prism2sta.c b/drivers/staging/wlan-ng/prism2sta.c deleted file mode 100644 index cb6c7a9fb8f3..000000000000 --- a/drivers/staging/wlan-ng/prism2sta.c +++ /dev/null @@ -1,1945 +0,0 @@ -// SPDX-License-Identifier: (GPL-2.0 OR MPL-1.1) -/* - * - * Implements the station functionality for prism2 - * - * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. - * -------------------------------------------------------------------- - * - * linux-wlan - * - * -------------------------------------------------------------------- - * - * Inquiries regarding the linux-wlan Open Source project can be - * made directly to: - * - * AbsoluteValue Systems Inc. - * info@linux-wlan.com - * http://www.linux-wlan.com - * - * -------------------------------------------------------------------- - * - * Portions of the development of this software were funded by - * Intersil Corporation as part of PRISM(R) chipset product development. - * - * -------------------------------------------------------------------- - * - * This file implements the module and linux pcmcia routines for the - * prism2 driver. - * - * -------------------------------------------------------------------- - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "p80211types.h" -#include "p80211hdr.h" -#include "p80211mgmt.h" -#include "p80211conv.h" -#include "p80211msg.h" -#include "p80211netdev.h" -#include "p80211req.h" -#include "p80211metadef.h" -#include "p80211metastruct.h" -#include "hfa384x.h" -#include "prism2mgmt.h" - -static char *dev_info = "prism2_usb"; -static struct wlandevice *create_wlan(void); - -int prism2_reset_holdtime = 30; /* Reset hold time in ms */ -int prism2_reset_settletime = 100; /* Reset settle time in ms */ - -static int prism2_doreset; /* Do a reset at init? */ - -module_param(prism2_doreset, int, 0644); -MODULE_PARM_DESC(prism2_doreset, "Issue a reset on initialization"); - -module_param(prism2_reset_holdtime, int, 0644); -MODULE_PARM_DESC(prism2_reset_holdtime, "reset hold time in ms"); -module_param(prism2_reset_settletime, int, 0644); -MODULE_PARM_DESC(prism2_reset_settletime, "reset settle time in ms"); - -MODULE_LICENSE("Dual MPL/GPL"); - -static int prism2sta_open(struct wlandevice *wlandev); -static int prism2sta_close(struct wlandevice *wlandev); -static void prism2sta_reset(struct wlandevice *wlandev); -static int prism2sta_txframe(struct wlandevice *wlandev, struct sk_buff *skb, - struct p80211_hdr *p80211_hdr, - struct p80211_metawep *p80211_wep); -static int prism2sta_mlmerequest(struct wlandevice *wlandev, - struct p80211msg *msg); -static int prism2sta_getcardinfo(struct wlandevice *wlandev); -static int prism2sta_globalsetup(struct wlandevice *wlandev); -static int prism2sta_setmulticast(struct wlandevice *wlandev, - struct net_device *dev); -static void prism2sta_inf_tallies(struct wlandevice *wlandev, - struct hfa384x_inf_frame *inf); -static void prism2sta_inf_hostscanresults(struct wlandevice *wlandev, - struct hfa384x_inf_frame *inf); -static void prism2sta_inf_scanresults(struct wlandevice *wlandev, - struct hfa384x_inf_frame *inf); -static void prism2sta_inf_chinforesults(struct wlandevice *wlandev, - struct hfa384x_inf_frame *inf); -static void prism2sta_inf_linkstatus(struct wlandevice *wlandev, - struct hfa384x_inf_frame *inf); -static void prism2sta_inf_assocstatus(struct wlandevice *wlandev, - struct hfa384x_inf_frame *inf); -static void prism2sta_inf_authreq(struct wlandevice *wlandev, - struct hfa384x_inf_frame *inf); -static void prism2sta_inf_authreq_defer(struct wlandevice *wlandev, - struct hfa384x_inf_frame *inf); -static void prism2sta_inf_psusercnt(struct wlandevice *wlandev, - struct hfa384x_inf_frame *inf); - -/* - * prism2sta_open - * - * WLAN device open method. Called from p80211netdev when kernel - * device open (start) method is called in response to the - * SIOCSIIFFLAGS ioctl changing the flags bit IFF_UP - * from clear to set. - * - * Arguments: - * wlandev wlan device structure - * - * Returns: - * 0 success - * >0 f/w reported error - * <0 driver reported error - * - * Side effects: - * - * Call context: - * process thread - */ -static int prism2sta_open(struct wlandevice *wlandev) -{ - /* We don't currently have to do anything else. - * The setup of the MAC should be subsequently completed via - * the mlme commands. - * Higher layers know we're ready from dev->start==1 and - * dev->tbusy==0. Our rx path knows to pass up received/ - * frames because of dev->flags&IFF_UP is true. - */ - - return 0; -} - -/* - * prism2sta_close - * - * WLAN device close method. Called from p80211netdev when kernel - * device close method is called in response to the - * SIOCSIIFFLAGS ioctl changing the flags bit IFF_UP - * from set to clear. - * - * Arguments: - * wlandev wlan device structure - * - * Returns: - * 0 success - * >0 f/w reported error - * <0 driver reported error - * - * Side effects: - * - * Call context: - * process thread - */ -static int prism2sta_close(struct wlandevice *wlandev) -{ - /* We don't currently have to do anything else. - * Higher layers know we're not ready from dev->start==0 and - * dev->tbusy==1. Our rx path knows to not pass up received - * frames because of dev->flags&IFF_UP is false. - */ - - return 0; -} - -/* - * prism2sta_reset - * - * Currently not implemented. - * - * Arguments: - * wlandev wlan device structure - * none - * - * Returns: - * nothing - * - * Side effects: - * - * Call context: - * process thread - */ -static void prism2sta_reset(struct wlandevice *wlandev) -{ -} - -/* - * prism2sta_txframe - * - * Takes a frame from p80211 and queues it for transmission. - * - * Arguments: - * wlandev wlan device structure - * pb packet buffer struct. Contains an 802.11 - * data frame. - * p80211_hdr points to the 802.11 header for the packet. - * Returns: - * 0 Success and more buffs available - * 1 Success but no more buffs - * 2 Allocation failure - * 4 Buffer full or queue busy - * - * Side effects: - * - * Call context: - * process thread - */ -static int prism2sta_txframe(struct wlandevice *wlandev, struct sk_buff *skb, - struct p80211_hdr *p80211_hdr, - struct p80211_metawep *p80211_wep) -{ - struct hfa384x *hw = wlandev->priv; - - /* If necessary, set the 802.11 WEP bit */ - if ((wlandev->hostwep & (HOSTWEP_PRIVACYINVOKED | HOSTWEP_ENCRYPT)) == - HOSTWEP_PRIVACYINVOKED) { - p80211_hdr->frame_control |= cpu_to_le16(WLAN_SET_FC_ISWEP(1)); - } - - return hfa384x_drvr_txframe(hw, skb, p80211_hdr, p80211_wep); -} - -/* - * prism2sta_mlmerequest - * - * wlan command message handler. All we do here is pass the message - * over to the prism2sta_mgmt_handler. - * - * Arguments: - * wlandev wlan device structure - * msg wlan command message - * Returns: - * 0 success - * <0 successful acceptance of message, but we're - * waiting for an async process to finish before - * we're done with the msg. When the asynch - * process is done, we'll call the p80211 - * function p80211req_confirm() . - * >0 An error occurred while we were handling - * the message. - * - * Side effects: - * - * Call context: - * process thread - */ -static int prism2sta_mlmerequest(struct wlandevice *wlandev, - struct p80211msg *msg) -{ - struct hfa384x *hw = wlandev->priv; - - int result = 0; - - switch (msg->msgcode) { - case DIDMSG_DOT11REQ_MIBGET: - netdev_dbg(wlandev->netdev, "Received mibget request\n"); - result = prism2mgmt_mibset_mibget(wlandev, msg); - break; - case DIDMSG_DOT11REQ_MIBSET: - netdev_dbg(wlandev->netdev, "Received mibset request\n"); - result = prism2mgmt_mibset_mibget(wlandev, msg); - break; - case DIDMSG_DOT11REQ_SCAN: - netdev_dbg(wlandev->netdev, "Received scan request\n"); - result = prism2mgmt_scan(wlandev, msg); - break; - case DIDMSG_DOT11REQ_SCAN_RESULTS: - netdev_dbg(wlandev->netdev, "Received scan_results request\n"); - result = prism2mgmt_scan_results(wlandev, msg); - break; - case DIDMSG_DOT11REQ_START: - netdev_dbg(wlandev->netdev, "Received mlme start request\n"); - result = prism2mgmt_start(wlandev, msg); - break; - /* - * Prism2 specific messages - */ - case DIDMSG_P2REQ_READPDA: - netdev_dbg(wlandev->netdev, "Received mlme readpda request\n"); - result = prism2mgmt_readpda(wlandev, msg); - break; - case DIDMSG_P2REQ_RAMDL_STATE: - netdev_dbg(wlandev->netdev, - "Received mlme ramdl_state request\n"); - result = prism2mgmt_ramdl_state(wlandev, msg); - break; - case DIDMSG_P2REQ_RAMDL_WRITE: - netdev_dbg(wlandev->netdev, - "Received mlme ramdl_write request\n"); - result = prism2mgmt_ramdl_write(wlandev, msg); - break; - case DIDMSG_P2REQ_FLASHDL_STATE: - netdev_dbg(wlandev->netdev, - "Received mlme flashdl_state request\n"); - result = prism2mgmt_flashdl_state(wlandev, msg); - break; - case DIDMSG_P2REQ_FLASHDL_WRITE: - netdev_dbg(wlandev->netdev, - "Received mlme flashdl_write request\n"); - result = prism2mgmt_flashdl_write(wlandev, msg); - break; - /* - * Linux specific messages - */ - case DIDMSG_LNXREQ_HOSTWEP: - break; /* ignore me. */ - case DIDMSG_LNXREQ_IFSTATE: { - struct p80211msg_lnxreq_ifstate *ifstatemsg; - - netdev_dbg(wlandev->netdev, "Received mlme ifstate request\n"); - ifstatemsg = (struct p80211msg_lnxreq_ifstate *)msg; - result = prism2sta_ifstate(wlandev, - ifstatemsg->ifstate.data); - ifstatemsg->resultcode.status = - P80211ENUM_msgitem_status_data_ok; - ifstatemsg->resultcode.data = result; - result = 0; - break; - } - case DIDMSG_LNXREQ_WLANSNIFF: - netdev_dbg(wlandev->netdev, - "Received mlme wlansniff request\n"); - result = prism2mgmt_wlansniff(wlandev, msg); - break; - case DIDMSG_LNXREQ_AUTOJOIN: - netdev_dbg(wlandev->netdev, "Received mlme autojoin request\n"); - result = prism2mgmt_autojoin(wlandev, msg); - break; - case DIDMSG_LNXREQ_COMMSQUALITY: { - struct p80211msg_lnxreq_commsquality *qualmsg; - - netdev_dbg(wlandev->netdev, "Received commsquality request\n"); - - qualmsg = (struct p80211msg_lnxreq_commsquality *)msg; - - qualmsg->link.status = P80211ENUM_msgitem_status_data_ok; - qualmsg->level.status = P80211ENUM_msgitem_status_data_ok; - qualmsg->noise.status = P80211ENUM_msgitem_status_data_ok; - - qualmsg->link.data = le16_to_cpu(hw->qual.cq_curr_bss); - qualmsg->level.data = le16_to_cpu(hw->qual.asl_curr_bss); - qualmsg->noise.data = le16_to_cpu(hw->qual.anl_curr_fc); - qualmsg->txrate.data = hw->txrate; - - break; - } - default: - netdev_warn(wlandev->netdev, - "Unknown mgmt request message 0x%08x", - msg->msgcode); - break; - } - - return result; -} - -/* - * prism2sta_ifstate - * - * Interface state. This is the primary WLAN interface enable/disable - * handler. Following the driver/load/deviceprobe sequence, this - * function must be called with a state of "enable" before any other - * commands will be accepted. - * - * Arguments: - * wlandev wlan device structure - * msgp ptr to msg buffer - * - * Returns: - * A p80211 message resultcode value. - * - * Side effects: - * - * Call context: - * process thread (usually) - * interrupt - */ -u32 prism2sta_ifstate(struct wlandevice *wlandev, u32 ifstate) -{ - struct hfa384x *hw = wlandev->priv; - u32 result; - - result = P80211ENUM_resultcode_implementation_failure; - - netdev_dbg(wlandev->netdev, "Current MSD state(%d), requesting(%d)\n", - wlandev->msdstate, ifstate); - switch (ifstate) { - case P80211ENUM_ifstate_fwload: - switch (wlandev->msdstate) { - case WLAN_MSD_HWPRESENT: - wlandev->msdstate = WLAN_MSD_FWLOAD_PENDING; - /* - * Initialize the device+driver sufficiently - * for firmware loading. - */ - result = hfa384x_drvr_start(hw); - if (result) { - netdev_err(wlandev->netdev, - "hfa384x_drvr_start() failed,result=%d\n", - (int)result); - result = - P80211ENUM_resultcode_implementation_failure; - wlandev->msdstate = WLAN_MSD_HWPRESENT; - break; - } - wlandev->msdstate = WLAN_MSD_FWLOAD; - result = P80211ENUM_resultcode_success; - break; - case WLAN_MSD_FWLOAD: - hfa384x_cmd_initialize(hw); - result = P80211ENUM_resultcode_success; - break; - case WLAN_MSD_RUNNING: - netdev_warn(wlandev->netdev, - "Cannot enter fwload state from enable state, you must disable first.\n"); - result = P80211ENUM_resultcode_invalid_parameters; - break; - case WLAN_MSD_HWFAIL: - default: - /* probe() had a problem or the msdstate contains - * an unrecognized value, there's nothing we can do. - */ - result = P80211ENUM_resultcode_implementation_failure; - break; - } - break; - case P80211ENUM_ifstate_enable: - switch (wlandev->msdstate) { - case WLAN_MSD_HWPRESENT: - case WLAN_MSD_FWLOAD: - wlandev->msdstate = WLAN_MSD_RUNNING_PENDING; - /* Initialize the device+driver for full - * operation. Note that this might me an FWLOAD - * to RUNNING transition so we must not do a chip - * or board level reset. Note that on failure, - * the MSD state is set to HWPRESENT because we - * can't make any assumptions about the state - * of the hardware or a previous firmware load. - */ - result = hfa384x_drvr_start(hw); - if (result) { - netdev_err(wlandev->netdev, - "hfa384x_drvr_start() failed,result=%d\n", - (int)result); - result = - P80211ENUM_resultcode_implementation_failure; - wlandev->msdstate = WLAN_MSD_HWPRESENT; - break; - } - - result = prism2sta_getcardinfo(wlandev); - if (result) { - netdev_err(wlandev->netdev, - "prism2sta_getcardinfo() failed,result=%d\n", - (int)result); - result = - P80211ENUM_resultcode_implementation_failure; - hfa384x_drvr_stop(hw); - wlandev->msdstate = WLAN_MSD_HWPRESENT; - break; - } - result = prism2sta_globalsetup(wlandev); - if (result) { - netdev_err(wlandev->netdev, - "prism2sta_globalsetup() failed,result=%d\n", - (int)result); - result = - P80211ENUM_resultcode_implementation_failure; - hfa384x_drvr_stop(hw); - wlandev->msdstate = WLAN_MSD_HWPRESENT; - break; - } - wlandev->msdstate = WLAN_MSD_RUNNING; - hw->join_ap = 0; - hw->join_retries = 60; - result = P80211ENUM_resultcode_success; - break; - case WLAN_MSD_RUNNING: - /* Do nothing, we're already in this state. */ - result = P80211ENUM_resultcode_success; - break; - case WLAN_MSD_HWFAIL: - default: - /* probe() had a problem or the msdstate contains - * an unrecognized value, there's nothing we can do. - */ - result = P80211ENUM_resultcode_implementation_failure; - break; - } - break; - case P80211ENUM_ifstate_disable: - switch (wlandev->msdstate) { - case WLAN_MSD_HWPRESENT: - /* Do nothing, we're already in this state. */ - result = P80211ENUM_resultcode_success; - break; - case WLAN_MSD_FWLOAD: - case WLAN_MSD_RUNNING: - wlandev->msdstate = WLAN_MSD_HWPRESENT_PENDING; - /* - * TODO: Shut down the MAC completely. Here a chip - * or board level reset is probably called for. - * After a "disable" _all_ results are lost, even - * those from a fwload. - */ - if (!wlandev->hwremoved) - netif_carrier_off(wlandev->netdev); - - hfa384x_drvr_stop(hw); - - wlandev->macmode = WLAN_MACMODE_NONE; - wlandev->msdstate = WLAN_MSD_HWPRESENT; - result = P80211ENUM_resultcode_success; - break; - case WLAN_MSD_HWFAIL: - default: - /* probe() had a problem or the msdstate contains - * an unrecognized value, there's nothing we can do. - */ - result = P80211ENUM_resultcode_implementation_failure; - break; - } - break; - default: - result = P80211ENUM_resultcode_invalid_parameters; - break; - } - - return result; -} - -/* - * prism2sta_getcardinfo - * - * Collect the NICID, firmware version and any other identifiers - * we'd like to have in host-side data structures. - * - * Arguments: - * wlandev wlan device structure - * - * Returns: - * 0 success - * >0 f/w reported error - * <0 driver reported error - * - * Side effects: - * - * Call context: - * Either. - */ -static int prism2sta_getcardinfo(struct wlandevice *wlandev) -{ - int result = 0; - struct hfa384x *hw = wlandev->priv; - u16 temp; - u8 snum[HFA384x_RID_NICSERIALNUMBER_LEN]; - u8 addr[ETH_ALEN]; - - /* Collect version and compatibility info */ - /* Some are critical, some are not */ - /* NIC identity */ - result = hfa384x_drvr_getconfig(hw, HFA384x_RID_NICIDENTITY, - &hw->ident_nic, - sizeof(struct hfa384x_compident)); - if (result) { - netdev_err(wlandev->netdev, "Failed to retrieve NICIDENTITY\n"); - goto failed; - } - - /* get all the nic id fields in host byte order */ - le16_to_cpus(&hw->ident_nic.id); - le16_to_cpus(&hw->ident_nic.variant); - le16_to_cpus(&hw->ident_nic.major); - le16_to_cpus(&hw->ident_nic.minor); - - netdev_info(wlandev->netdev, "ident: nic h/w: id=0x%02x %d.%d.%d\n", - hw->ident_nic.id, hw->ident_nic.major, - hw->ident_nic.minor, hw->ident_nic.variant); - - /* Primary f/w identity */ - result = hfa384x_drvr_getconfig(hw, HFA384x_RID_PRIIDENTITY, - &hw->ident_pri_fw, - sizeof(struct hfa384x_compident)); - if (result) { - netdev_err(wlandev->netdev, "Failed to retrieve PRIIDENTITY\n"); - goto failed; - } - - /* get all the private fw id fields in host byte order */ - le16_to_cpus(&hw->ident_pri_fw.id); - le16_to_cpus(&hw->ident_pri_fw.variant); - le16_to_cpus(&hw->ident_pri_fw.major); - le16_to_cpus(&hw->ident_pri_fw.minor); - - netdev_info(wlandev->netdev, "ident: pri f/w: id=0x%02x %d.%d.%d\n", - hw->ident_pri_fw.id, hw->ident_pri_fw.major, - hw->ident_pri_fw.minor, hw->ident_pri_fw.variant); - - /* Station (Secondary?) f/w identity */ - result = hfa384x_drvr_getconfig(hw, HFA384x_RID_STAIDENTITY, - &hw->ident_sta_fw, - sizeof(struct hfa384x_compident)); - if (result) { - netdev_err(wlandev->netdev, "Failed to retrieve STAIDENTITY\n"); - goto failed; - } - - if (hw->ident_nic.id < 0x8000) { - netdev_err(wlandev->netdev, - "FATAL: Card is not an Intersil Prism2/2.5/3\n"); - result = -1; - goto failed; - } - - /* get all the station fw id fields in host byte order */ - le16_to_cpus(&hw->ident_sta_fw.id); - le16_to_cpus(&hw->ident_sta_fw.variant); - le16_to_cpus(&hw->ident_sta_fw.major); - le16_to_cpus(&hw->ident_sta_fw.minor); - - /* strip out the 'special' variant bits */ - hw->mm_mods = hw->ident_sta_fw.variant & GENMASK(15, 14); - hw->ident_sta_fw.variant &= ~((u16)GENMASK(15, 14)); - - if (hw->ident_sta_fw.id == 0x1f) { - netdev_info(wlandev->netdev, - "ident: sta f/w: id=0x%02x %d.%d.%d\n", - hw->ident_sta_fw.id, hw->ident_sta_fw.major, - hw->ident_sta_fw.minor, hw->ident_sta_fw.variant); - } else { - netdev_info(wlandev->netdev, - "ident: ap f/w: id=0x%02x %d.%d.%d\n", - hw->ident_sta_fw.id, hw->ident_sta_fw.major, - hw->ident_sta_fw.minor, hw->ident_sta_fw.variant); - netdev_err(wlandev->netdev, "Unsupported Tertiary AP firmware loaded!\n"); - goto failed; - } - - /* Compatibility range, Modem supplier */ - result = hfa384x_drvr_getconfig(hw, HFA384x_RID_MFISUPRANGE, - &hw->cap_sup_mfi, - sizeof(struct hfa384x_caplevel)); - if (result) { - netdev_err(wlandev->netdev, "Failed to retrieve MFISUPRANGE\n"); - goto failed; - } - - /* get all the Compatibility range, modem interface supplier - * fields in byte order - */ - le16_to_cpus(&hw->cap_sup_mfi.role); - le16_to_cpus(&hw->cap_sup_mfi.id); - le16_to_cpus(&hw->cap_sup_mfi.variant); - le16_to_cpus(&hw->cap_sup_mfi.bottom); - le16_to_cpus(&hw->cap_sup_mfi.top); - - netdev_info(wlandev->netdev, - "MFI:SUP:role=0x%02x:id=0x%02x:var=0x%02x:b/t=%d/%d\n", - hw->cap_sup_mfi.role, hw->cap_sup_mfi.id, - hw->cap_sup_mfi.variant, hw->cap_sup_mfi.bottom, - hw->cap_sup_mfi.top); - - /* Compatibility range, Controller supplier */ - result = hfa384x_drvr_getconfig(hw, HFA384x_RID_CFISUPRANGE, - &hw->cap_sup_cfi, - sizeof(struct hfa384x_caplevel)); - if (result) { - netdev_err(wlandev->netdev, "Failed to retrieve CFISUPRANGE\n"); - goto failed; - } - - /* get all the Compatibility range, controller interface supplier - * fields in byte order - */ - le16_to_cpus(&hw->cap_sup_cfi.role); - le16_to_cpus(&hw->cap_sup_cfi.id); - le16_to_cpus(&hw->cap_sup_cfi.variant); - le16_to_cpus(&hw->cap_sup_cfi.bottom); - le16_to_cpus(&hw->cap_sup_cfi.top); - - netdev_info(wlandev->netdev, - "CFI:SUP:role=0x%02x:id=0x%02x:var=0x%02x:b/t=%d/%d\n", - hw->cap_sup_cfi.role, hw->cap_sup_cfi.id, - hw->cap_sup_cfi.variant, hw->cap_sup_cfi.bottom, - hw->cap_sup_cfi.top); - - /* Compatibility range, Primary f/w supplier */ - result = hfa384x_drvr_getconfig(hw, HFA384x_RID_PRISUPRANGE, - &hw->cap_sup_pri, - sizeof(struct hfa384x_caplevel)); - if (result) { - netdev_err(wlandev->netdev, "Failed to retrieve PRISUPRANGE\n"); - goto failed; - } - - /* get all the Compatibility range, primary firmware supplier - * fields in byte order - */ - le16_to_cpus(&hw->cap_sup_pri.role); - le16_to_cpus(&hw->cap_sup_pri.id); - le16_to_cpus(&hw->cap_sup_pri.variant); - le16_to_cpus(&hw->cap_sup_pri.bottom); - le16_to_cpus(&hw->cap_sup_pri.top); - - netdev_info(wlandev->netdev, - "PRI:SUP:role=0x%02x:id=0x%02x:var=0x%02x:b/t=%d/%d\n", - hw->cap_sup_pri.role, hw->cap_sup_pri.id, - hw->cap_sup_pri.variant, hw->cap_sup_pri.bottom, - hw->cap_sup_pri.top); - - /* Compatibility range, Station f/w supplier */ - result = hfa384x_drvr_getconfig(hw, HFA384x_RID_STASUPRANGE, - &hw->cap_sup_sta, - sizeof(struct hfa384x_caplevel)); - if (result) { - netdev_err(wlandev->netdev, "Failed to retrieve STASUPRANGE\n"); - goto failed; - } - - /* get all the Compatibility range, station firmware supplier - * fields in byte order - */ - le16_to_cpus(&hw->cap_sup_sta.role); - le16_to_cpus(&hw->cap_sup_sta.id); - le16_to_cpus(&hw->cap_sup_sta.variant); - le16_to_cpus(&hw->cap_sup_sta.bottom); - le16_to_cpus(&hw->cap_sup_sta.top); - - if (hw->cap_sup_sta.id == 0x04) { - netdev_info(wlandev->netdev, - "STA:SUP:role=0x%02x:id=0x%02x:var=0x%02x:b/t=%d/%d\n", - hw->cap_sup_sta.role, hw->cap_sup_sta.id, - hw->cap_sup_sta.variant, hw->cap_sup_sta.bottom, - hw->cap_sup_sta.top); - } else { - netdev_info(wlandev->netdev, - "AP:SUP:role=0x%02x:id=0x%02x:var=0x%02x:b/t=%d/%d\n", - hw->cap_sup_sta.role, hw->cap_sup_sta.id, - hw->cap_sup_sta.variant, hw->cap_sup_sta.bottom, - hw->cap_sup_sta.top); - } - - /* Compatibility range, primary f/w actor, CFI supplier */ - result = hfa384x_drvr_getconfig(hw, HFA384x_RID_PRI_CFIACTRANGES, - &hw->cap_act_pri_cfi, - sizeof(struct hfa384x_caplevel)); - if (result) { - netdev_err(wlandev->netdev, "Failed to retrieve PRI_CFIACTRANGES\n"); - goto failed; - } - - /* get all the Compatibility range, primary f/w actor, CFI supplier - * fields in byte order - */ - le16_to_cpus(&hw->cap_act_pri_cfi.role); - le16_to_cpus(&hw->cap_act_pri_cfi.id); - le16_to_cpus(&hw->cap_act_pri_cfi.variant); - le16_to_cpus(&hw->cap_act_pri_cfi.bottom); - le16_to_cpus(&hw->cap_act_pri_cfi.top); - - netdev_info(wlandev->netdev, - "PRI-CFI:ACT:role=0x%02x:id=0x%02x:var=0x%02x:b/t=%d/%d\n", - hw->cap_act_pri_cfi.role, hw->cap_act_pri_cfi.id, - hw->cap_act_pri_cfi.variant, hw->cap_act_pri_cfi.bottom, - hw->cap_act_pri_cfi.top); - - /* Compatibility range, sta f/w actor, CFI supplier */ - result = hfa384x_drvr_getconfig(hw, HFA384x_RID_STA_CFIACTRANGES, - &hw->cap_act_sta_cfi, - sizeof(struct hfa384x_caplevel)); - if (result) { - netdev_err(wlandev->netdev, "Failed to retrieve STA_CFIACTRANGES\n"); - goto failed; - } - - /* get all the Compatibility range, station f/w actor, CFI supplier - * fields in byte order - */ - le16_to_cpus(&hw->cap_act_sta_cfi.role); - le16_to_cpus(&hw->cap_act_sta_cfi.id); - le16_to_cpus(&hw->cap_act_sta_cfi.variant); - le16_to_cpus(&hw->cap_act_sta_cfi.bottom); - le16_to_cpus(&hw->cap_act_sta_cfi.top); - - netdev_info(wlandev->netdev, - "STA-CFI:ACT:role=0x%02x:id=0x%02x:var=0x%02x:b/t=%d/%d\n", - hw->cap_act_sta_cfi.role, hw->cap_act_sta_cfi.id, - hw->cap_act_sta_cfi.variant, hw->cap_act_sta_cfi.bottom, - hw->cap_act_sta_cfi.top); - - /* Compatibility range, sta f/w actor, MFI supplier */ - result = hfa384x_drvr_getconfig(hw, HFA384x_RID_STA_MFIACTRANGES, - &hw->cap_act_sta_mfi, - sizeof(struct hfa384x_caplevel)); - if (result) { - netdev_err(wlandev->netdev, "Failed to retrieve STA_MFIACTRANGES\n"); - goto failed; - } - - /* get all the Compatibility range, station f/w actor, MFI supplier - * fields in byte order - */ - le16_to_cpus(&hw->cap_act_sta_mfi.role); - le16_to_cpus(&hw->cap_act_sta_mfi.id); - le16_to_cpus(&hw->cap_act_sta_mfi.variant); - le16_to_cpus(&hw->cap_act_sta_mfi.bottom); - le16_to_cpus(&hw->cap_act_sta_mfi.top); - - netdev_info(wlandev->netdev, - "STA-MFI:ACT:role=0x%02x:id=0x%02x:var=0x%02x:b/t=%d/%d\n", - hw->cap_act_sta_mfi.role, hw->cap_act_sta_mfi.id, - hw->cap_act_sta_mfi.variant, hw->cap_act_sta_mfi.bottom, - hw->cap_act_sta_mfi.top); - - /* Serial Number */ - result = hfa384x_drvr_getconfig(hw, HFA384x_RID_NICSERIALNUMBER, - snum, HFA384x_RID_NICSERIALNUMBER_LEN); - if (!result) { - netdev_info(wlandev->netdev, "Prism2 card SN: %*pE\n", - HFA384x_RID_NICSERIALNUMBER_LEN, snum); - } else { - netdev_err(wlandev->netdev, "Failed to retrieve Prism2 Card SN\n"); - goto failed; - } - - /* Collect the MAC address */ - result = hfa384x_drvr_getconfig(hw, HFA384x_RID_CNFOWNMACADDR, - addr, ETH_ALEN); - if (result != 0) { - netdev_err(wlandev->netdev, "Failed to retrieve mac address\n"); - goto failed; - } - eth_hw_addr_set(wlandev->netdev, addr); - - /* short preamble is always implemented */ - wlandev->nsdcaps |= P80211_NSDCAP_SHORT_PREAMBLE; - - /* find out if hardware wep is implemented */ - hfa384x_drvr_getconfig16(hw, HFA384x_RID_PRIVACYOPTIMP, &temp); - if (temp) - wlandev->nsdcaps |= P80211_NSDCAP_HARDWAREWEP; - - /* get the dBm Scaling constant */ - hfa384x_drvr_getconfig16(hw, HFA384x_RID_CNFDBMADJUST, &temp); - hw->dbmadjust = temp; - - /* Only enable scan by default on newer firmware */ - if (HFA384x_FIRMWARE_VERSION(hw->ident_sta_fw.major, - hw->ident_sta_fw.minor, - hw->ident_sta_fw.variant) < - HFA384x_FIRMWARE_VERSION(1, 5, 5)) { - wlandev->nsdcaps |= P80211_NSDCAP_NOSCAN; - } - - /* TODO: Set any internally managed config items */ - - goto done; -failed: - netdev_err(wlandev->netdev, "Failed, result=%d\n", result); -done: - return result; -} - -/* - * prism2sta_globalsetup - * - * Set any global RIDs that we want to set at device activation. - * - * Arguments: - * wlandev wlan device structure - * - * Returns: - * 0 success - * >0 f/w reported error - * <0 driver reported error - * - * Side effects: - * - * Call context: - * process thread - */ -static int prism2sta_globalsetup(struct wlandevice *wlandev) -{ - struct hfa384x *hw = wlandev->priv; - - /* Set the maximum frame size */ - return hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFMAXDATALEN, - WLAN_DATA_MAXLEN); -} - -static int prism2sta_setmulticast(struct wlandevice *wlandev, - struct net_device *dev) -{ - int result = 0; - struct hfa384x *hw = wlandev->priv; - - u16 promisc; - - /* If we're not ready, what's the point? */ - if (hw->state != HFA384x_STATE_RUNNING) - goto exit; - - if ((dev->flags & (IFF_PROMISC | IFF_ALLMULTI)) != 0) - promisc = P80211ENUM_truth_true; - else - promisc = P80211ENUM_truth_false; - - result = - hfa384x_drvr_setconfig16_async(hw, HFA384x_RID_PROMISCMODE, - promisc); -exit: - return result; -} - -/* - * prism2sta_inf_tallies - * - * Handles the receipt of a CommTallies info frame. - * - * Arguments: - * wlandev wlan device structure - * inf ptr to info frame (contents in hfa384x order) - * - * Returns: - * nothing - * - * Side effects: - * - * Call context: - * interrupt - */ -static void prism2sta_inf_tallies(struct wlandevice *wlandev, - struct hfa384x_inf_frame *inf) -{ - struct hfa384x *hw = wlandev->priv; - __le16 *src16; - u32 *dst; - __le32 *src32; - int i; - int cnt; - - /* - * Determine if these are 16-bit or 32-bit tallies, based on the - * record length of the info record. - */ - - cnt = sizeof(struct hfa384x_comm_tallies_32) / sizeof(u32); - if (inf->framelen > 22) { - dst = (u32 *)&hw->tallies; - src32 = (__le32 *)&inf->info.commtallies32; - for (i = 0; i < cnt; i++, dst++, src32++) - *dst += le32_to_cpu(*src32); - } else { - dst = (u32 *)&hw->tallies; - src16 = (__le16 *)&inf->info.commtallies16; - for (i = 0; i < cnt; i++, dst++, src16++) - *dst += le16_to_cpu(*src16); - } -} - -/* - * prism2sta_inf_scanresults - * - * Handles the receipt of a Scan Results info frame. - * - * Arguments: - * wlandev wlan device structure - * inf ptr to info frame (contents in hfa384x order) - * - * Returns: - * nothing - * - * Side effects: - * - * Call context: - * interrupt - */ -static void prism2sta_inf_scanresults(struct wlandevice *wlandev, - struct hfa384x_inf_frame *inf) -{ - struct hfa384x *hw = wlandev->priv; - int nbss; - struct hfa384x_scan_result *sr = &inf->info.scanresult; - int i; - struct hfa384x_join_request_data joinreq; - int result; - - /* Get the number of results, first in bytes, then in results */ - nbss = (inf->framelen * sizeof(u16)) - - sizeof(inf->infotype) - sizeof(inf->info.scanresult.scanreason); - nbss /= sizeof(struct hfa384x_scan_result_sub); - - /* Print em */ - netdev_dbg(wlandev->netdev, "rx scanresults, reason=%d, nbss=%d:\n", - inf->info.scanresult.scanreason, nbss); - for (i = 0; i < nbss; i++) { - netdev_dbg(wlandev->netdev, "chid=%d anl=%d sl=%d bcnint=%d\n", - sr->result[i].chid, sr->result[i].anl, - sr->result[i].sl, sr->result[i].bcnint); - netdev_dbg(wlandev->netdev, - " capinfo=0x%04x proberesp_rate=%d\n", - sr->result[i].capinfo, sr->result[i].proberesp_rate); - } - /* issue a join request */ - joinreq.channel = sr->result[0].chid; - memcpy(joinreq.bssid, sr->result[0].bssid, WLAN_BSSID_LEN); - result = hfa384x_drvr_setconfig(hw, - HFA384x_RID_JOINREQUEST, - &joinreq, HFA384x_RID_JOINREQUEST_LEN); - if (result) { - netdev_err(wlandev->netdev, "setconfig(joinreq) failed, result=%d\n", - result); - } -} - -/* - * prism2sta_inf_hostscanresults - * - * Handles the receipt of a Scan Results info frame. - * - * Arguments: - * wlandev wlan device structure - * inf ptr to info frame (contents in hfa384x order) - * - * Returns: - * nothing - * - * Side effects: - * - * Call context: - * interrupt - */ -static void prism2sta_inf_hostscanresults(struct wlandevice *wlandev, - struct hfa384x_inf_frame *inf) -{ - struct hfa384x *hw = wlandev->priv; - int nbss; - - nbss = (inf->framelen - 3) / 32; - netdev_dbg(wlandev->netdev, "Received %d hostscan results\n", nbss); - - if (nbss > 32) - nbss = 32; - - kfree(hw->scanresults); - - hw->scanresults = kmemdup(inf, sizeof(*inf), GFP_ATOMIC); - - if (nbss == 0) - nbss = -1; - - /* Notify/wake the sleeping caller. */ - hw->scanflag = nbss; - wake_up_interruptible(&hw->cmdq); -}; - -/* - * prism2sta_inf_chinforesults - * - * Handles the receipt of a Channel Info Results info frame. - * - * Arguments: - * wlandev wlan device structure - * inf ptr to info frame (contents in hfa384x order) - * - * Returns: - * nothing - * - * Side effects: - * - * Call context: - * interrupt - */ -static void prism2sta_inf_chinforesults(struct wlandevice *wlandev, - struct hfa384x_inf_frame *inf) -{ - struct hfa384x *hw = wlandev->priv; - unsigned int i, n; - - hw->channel_info.results.scanchannels = - inf->info.chinforesult.scanchannels; - - for (i = 0, n = 0; i < HFA384x_CHINFORESULT_MAX; i++) { - struct hfa384x_ch_info_result_sub *result; - struct hfa384x_ch_info_result_sub *chinforesult; - int chan; - - if (!(hw->channel_info.results.scanchannels & (1 << i))) - continue; - - result = &inf->info.chinforesult.result[n]; - chan = result->chid - 1; - - if (chan < 0 || chan >= HFA384x_CHINFORESULT_MAX) - continue; - - chinforesult = &hw->channel_info.results.result[chan]; - chinforesult->chid = chan; - chinforesult->anl = result->anl; - chinforesult->pnl = result->pnl; - chinforesult->active = result->active; - - netdev_dbg(wlandev->netdev, - "chinfo: channel %d, %s level (avg/peak)=%d/%d dB, pcf %d\n", - chan + 1, - (chinforesult->active & HFA384x_CHINFORESULT_BSSACTIVE) ? - "signal" : "noise", - chinforesult->anl, - chinforesult->pnl, - (chinforesult->active & HFA384x_CHINFORESULT_PCFACTIVE) ? 1 : 0); - n++; - } - atomic_set(&hw->channel_info.done, 2); - - hw->channel_info.count = n; -} - -void prism2sta_processing_defer(struct work_struct *data) -{ - struct hfa384x *hw = container_of(data, struct hfa384x, link_bh); - struct wlandevice *wlandev = hw->wlandev; - struct hfa384x_bytestr32 ssid; - int result; - - /* First let's process the auth frames */ - { - struct sk_buff *skb; - struct hfa384x_inf_frame *inf; - - while ((skb = skb_dequeue(&hw->authq))) { - inf = (struct hfa384x_inf_frame *)skb->data; - prism2sta_inf_authreq_defer(wlandev, inf); - } - } - - /* Now let's handle the linkstatus stuff */ - if (hw->link_status == hw->link_status_new) - return; - - hw->link_status = hw->link_status_new; - - switch (hw->link_status) { - case HFA384x_LINK_NOTCONNECTED: - /* I'm currently assuming that this is the initial link - * state. It should only be possible immediately - * following an Enable command. - * Response: - * Block Transmits, Ignore receives of data frames - */ - netif_carrier_off(wlandev->netdev); - - netdev_info(wlandev->netdev, "linkstatus=NOTCONNECTED (unhandled)\n"); - break; - - case HFA384x_LINK_CONNECTED: - /* This one indicates a successful scan/join/auth/assoc. - * When we have the full MLME complement, this event will - * signify successful completion of both mlme_authenticate - * and mlme_associate. State management will get a little - * ugly here. - * Response: - * Indicate authentication and/or association - * Enable Transmits, Receives and pass up data frames - */ - - netif_carrier_on(wlandev->netdev); - - /* If we are joining a specific AP, set our - * state and reset retries - */ - if (hw->join_ap == 1) - hw->join_ap = 2; - hw->join_retries = 60; - - /* Don't call this in monitor mode */ - if (wlandev->netdev->type == ARPHRD_ETHER) { - u16 portstatus; - - netdev_info(wlandev->netdev, "linkstatus=CONNECTED\n"); - - /* For non-usb devices, we can use the sync versions */ - /* Collect the BSSID, and set state to allow tx */ - - result = hfa384x_drvr_getconfig(hw, - HFA384x_RID_CURRENTBSSID, - wlandev->bssid, - WLAN_BSSID_LEN); - if (result) { - netdev_dbg(wlandev->netdev, - "getconfig(0x%02x) failed, result = %d\n", - HFA384x_RID_CURRENTBSSID, result); - return; - } - - result = hfa384x_drvr_getconfig(hw, - HFA384x_RID_CURRENTSSID, - &ssid, sizeof(ssid)); - if (result) { - netdev_dbg(wlandev->netdev, - "getconfig(0x%02x) failed, result = %d\n", - HFA384x_RID_CURRENTSSID, result); - return; - } - prism2mgmt_bytestr2pstr((struct hfa384x_bytestr *)&ssid, - (struct p80211pstrd *)&wlandev->ssid); - - /* Collect the port status */ - result = hfa384x_drvr_getconfig16(hw, - HFA384x_RID_PORTSTATUS, - &portstatus); - if (result) { - netdev_dbg(wlandev->netdev, - "getconfig(0x%02x) failed, result = %d\n", - HFA384x_RID_PORTSTATUS, result); - return; - } - wlandev->macmode = - (portstatus == HFA384x_PSTATUS_CONN_IBSS) ? - WLAN_MACMODE_IBSS_STA : WLAN_MACMODE_ESS_STA; - - /* signal back up to cfg80211 layer */ - prism2_connect_result(wlandev, P80211ENUM_truth_false); - - /* Get the ball rolling on the comms quality stuff */ - prism2sta_commsqual_defer(&hw->commsqual_bh); - } - break; - - case HFA384x_LINK_DISCONNECTED: - /* This one indicates that our association is gone. We've - * lost connection with the AP and/or been disassociated. - * This indicates that the MAC has completely cleared it's - * associated state. We * should send a deauth indication - * (implying disassoc) up * to the MLME. - * Response: - * Indicate Deauthentication - * Block Transmits, Ignore receives of data frames - */ - if (wlandev->netdev->type == ARPHRD_ETHER) - netdev_info(wlandev->netdev, - "linkstatus=DISCONNECTED (unhandled)\n"); - wlandev->macmode = WLAN_MACMODE_NONE; - - netif_carrier_off(wlandev->netdev); - - /* signal back up to cfg80211 layer */ - prism2_disconnected(wlandev); - - break; - - case HFA384x_LINK_AP_CHANGE: - /* This one indicates that the MAC has decided to and - * successfully completed a change to another AP. We - * should probably implement a reassociation indication - * in response to this one. I'm thinking that the - * p80211 layer needs to be notified in case of - * buffering/queueing issues. User mode also needs to be - * notified so that any BSS dependent elements can be - * updated. - * associated state. We * should send a deauth indication - * (implying disassoc) up * to the MLME. - * Response: - * Indicate Reassociation - * Enable Transmits, Receives and pass up data frames - */ - netdev_info(wlandev->netdev, "linkstatus=AP_CHANGE\n"); - - result = hfa384x_drvr_getconfig(hw, - HFA384x_RID_CURRENTBSSID, - wlandev->bssid, WLAN_BSSID_LEN); - if (result) { - netdev_dbg(wlandev->netdev, - "getconfig(0x%02x) failed, result = %d\n", - HFA384x_RID_CURRENTBSSID, result); - return; - } - - result = hfa384x_drvr_getconfig(hw, - HFA384x_RID_CURRENTSSID, - &ssid, sizeof(ssid)); - if (result) { - netdev_dbg(wlandev->netdev, - "getconfig(0x%02x) failed, result = %d\n", - HFA384x_RID_CURRENTSSID, result); - return; - } - prism2mgmt_bytestr2pstr((struct hfa384x_bytestr *)&ssid, - (struct p80211pstrd *)&wlandev->ssid); - - hw->link_status = HFA384x_LINK_CONNECTED; - netif_carrier_on(wlandev->netdev); - - /* signal back up to cfg80211 layer */ - prism2_roamed(wlandev); - - break; - - case HFA384x_LINK_AP_OUTOFRANGE: - /* This one indicates that the MAC has decided that the - * AP is out of range, but hasn't found a better candidate - * so the MAC maintains its "associated" state in case - * we get back in range. We should block transmits and - * receives in this state. Do we need an indication here? - * Probably not since a polling user-mode element would - * get this status from p2PortStatus(FD40). What about - * p80211? - * Response: - * Block Transmits, Ignore receives of data frames - */ - netdev_info(wlandev->netdev, "linkstatus=AP_OUTOFRANGE (unhandled)\n"); - - netif_carrier_off(wlandev->netdev); - - break; - - case HFA384x_LINK_AP_INRANGE: - /* This one indicates that the MAC has decided that the - * AP is back in range. We continue working with our - * existing association. - * Response: - * Enable Transmits, Receives and pass up data frames - */ - netdev_info(wlandev->netdev, "linkstatus=AP_INRANGE\n"); - - hw->link_status = HFA384x_LINK_CONNECTED; - netif_carrier_on(wlandev->netdev); - - break; - - case HFA384x_LINK_ASSOCFAIL: - /* This one is actually a peer to CONNECTED. We've - * requested a join for a given SSID and optionally BSSID. - * We can use this one to indicate authentication and - * association failures. The trick is going to be - * 1) identifying the failure, and 2) state management. - * Response: - * Disable Transmits, Ignore receives of data frames - */ - if (hw->join_ap && --hw->join_retries > 0) { - struct hfa384x_join_request_data joinreq; - - joinreq = hw->joinreq; - /* Send the join request */ - hfa384x_drvr_setconfig(hw, - HFA384x_RID_JOINREQUEST, - &joinreq, - HFA384x_RID_JOINREQUEST_LEN); - netdev_info(wlandev->netdev, - "linkstatus=ASSOCFAIL (re-submitting join)\n"); - } else { - netdev_info(wlandev->netdev, "linkstatus=ASSOCFAIL (unhandled)\n"); - } - - netif_carrier_off(wlandev->netdev); - - /* signal back up to cfg80211 layer */ - prism2_connect_result(wlandev, P80211ENUM_truth_true); - - break; - - default: - /* This is bad, IO port problems? */ - netdev_warn(wlandev->netdev, - "unknown linkstatus=0x%02x\n", hw->link_status); - return; - } - - wlandev->linkstatus = (hw->link_status == HFA384x_LINK_CONNECTED); -} - -/* - * prism2sta_inf_linkstatus - * - * Handles the receipt of a Link Status info frame. - * - * Arguments: - * wlandev wlan device structure - * inf ptr to info frame (contents in hfa384x order) - * - * Returns: - * nothing - * - * Side effects: - * - * Call context: - * interrupt - */ -static void prism2sta_inf_linkstatus(struct wlandevice *wlandev, - struct hfa384x_inf_frame *inf) -{ - struct hfa384x *hw = wlandev->priv; - - hw->link_status_new = le16_to_cpu(inf->info.linkstatus.linkstatus); - - schedule_work(&hw->link_bh); -} - -/* - * prism2sta_inf_assocstatus - * - * Handles the receipt of an Association Status info frame. Should - * be present in APs only. - * - * Arguments: - * wlandev wlan device structure - * inf ptr to info frame (contents in hfa384x order) - * - * Returns: - * nothing - * - * Side effects: - * - * Call context: - * interrupt - */ -static void prism2sta_inf_assocstatus(struct wlandevice *wlandev, - struct hfa384x_inf_frame *inf) -{ - struct hfa384x *hw = wlandev->priv; - struct hfa384x_assoc_status rec; - int i; - - memcpy(&rec, &inf->info.assocstatus, sizeof(rec)); - le16_to_cpus(&rec.assocstatus); - le16_to_cpus(&rec.reason); - - /* - * Find the address in the list of authenticated stations. - * If it wasn't found, then this address has not been previously - * authenticated and something weird has happened if this is - * anything other than an "authentication failed" message. - * If the address was found, then set the "associated" flag for - * that station, based on whether the station is associating or - * losing its association. Something weird has also happened - * if we find the address in the list of authenticated stations - * but we are getting an "authentication failed" message. - */ - - for (i = 0; i < hw->authlist.cnt; i++) - if (ether_addr_equal(rec.sta_addr, hw->authlist.addr[i])) - break; - - if (i >= hw->authlist.cnt) { - if (rec.assocstatus != HFA384x_ASSOCSTATUS_AUTHFAIL) - netdev_warn(wlandev->netdev, - "assocstatus info frame received for non-authenticated station.\n"); - } else { - hw->authlist.assoc[i] = - (rec.assocstatus == HFA384x_ASSOCSTATUS_STAASSOC || - rec.assocstatus == HFA384x_ASSOCSTATUS_REASSOC); - - if (rec.assocstatus == HFA384x_ASSOCSTATUS_AUTHFAIL) - netdev_warn(wlandev->netdev, - "authfail assocstatus info frame received for authenticated station.\n"); - } -} - -/* - * prism2sta_inf_authreq - * - * Handles the receipt of an Authentication Request info frame. Should - * be present in APs only. - * - * Arguments: - * wlandev wlan device structure - * inf ptr to info frame (contents in hfa384x order) - * - * Returns: - * nothing - * - * Side effects: - * - * Call context: - * interrupt - * - */ -static void prism2sta_inf_authreq(struct wlandevice *wlandev, - struct hfa384x_inf_frame *inf) -{ - struct hfa384x *hw = wlandev->priv; - struct sk_buff *skb; - - skb = dev_alloc_skb(sizeof(*inf)); - if (skb) { - skb_put(skb, sizeof(*inf)); - memcpy(skb->data, inf, sizeof(*inf)); - skb_queue_tail(&hw->authq, skb); - schedule_work(&hw->link_bh); - } -} - -static void prism2sta_inf_authreq_defer(struct wlandevice *wlandev, - struct hfa384x_inf_frame *inf) -{ - struct hfa384x *hw = wlandev->priv; - struct hfa384x_authenticate_station_data rec; - - int i, added, result, cnt; - u8 *addr; - - /* - * Build the AuthenticateStation record. Initialize it for denying - * authentication. - */ - - ether_addr_copy(rec.address, inf->info.authreq.sta_addr); - rec.status = cpu_to_le16(P80211ENUM_status_unspec_failure); - - /* - * Authenticate based on the access mode. - */ - - switch (hw->accessmode) { - case WLAN_ACCESS_NONE: - - /* - * Deny all new authentications. However, if a station - * is ALREADY authenticated, then accept it. - */ - - for (i = 0; i < hw->authlist.cnt; i++) - if (ether_addr_equal(rec.address, - hw->authlist.addr[i])) { - rec.status = cpu_to_le16(P80211ENUM_status_successful); - break; - } - - break; - - case WLAN_ACCESS_ALL: - - /* - * Allow all authentications. - */ - - rec.status = cpu_to_le16(P80211ENUM_status_successful); - break; - - case WLAN_ACCESS_ALLOW: - - /* - * Only allow the authentication if the MAC address - * is in the list of allowed addresses. - * - * Since this is the interrupt handler, we may be here - * while the access list is in the middle of being - * updated. Choose the list which is currently okay. - * See "prism2mib_priv_accessallow()" for details. - */ - - if (hw->allow.modify == 0) { - cnt = hw->allow.cnt; - addr = hw->allow.addr[0]; - } else { - cnt = hw->allow.cnt1; - addr = hw->allow.addr1[0]; - } - - for (i = 0; i < cnt; i++, addr += ETH_ALEN) - if (ether_addr_equal(rec.address, addr)) { - rec.status = cpu_to_le16(P80211ENUM_status_successful); - break; - } - - break; - - case WLAN_ACCESS_DENY: - - /* - * Allow the authentication UNLESS the MAC address is - * in the list of denied addresses. - * - * Since this is the interrupt handler, we may be here - * while the access list is in the middle of being - * updated. Choose the list which is currently okay. - * See "prism2mib_priv_accessdeny()" for details. - */ - - if (hw->deny.modify == 0) { - cnt = hw->deny.cnt; - addr = hw->deny.addr[0]; - } else { - cnt = hw->deny.cnt1; - addr = hw->deny.addr1[0]; - } - - rec.status = cpu_to_le16(P80211ENUM_status_successful); - - for (i = 0; i < cnt; i++, addr += ETH_ALEN) - if (ether_addr_equal(rec.address, addr)) { - rec.status = cpu_to_le16(P80211ENUM_status_unspec_failure); - break; - } - - break; - } - - /* - * If the authentication is okay, then add the MAC address to the - * list of authenticated stations. Don't add the address if it - * is already in the list. (802.11b does not seem to disallow - * a station from issuing an authentication request when the - * station is already authenticated. Does this sort of thing - * ever happen? We might as well do the check just in case.) - */ - - added = 0; - - if (rec.status == cpu_to_le16(P80211ENUM_status_successful)) { - for (i = 0; i < hw->authlist.cnt; i++) - if (ether_addr_equal(rec.address, - hw->authlist.addr[i])) - break; - - if (i >= hw->authlist.cnt) { - if (hw->authlist.cnt >= WLAN_AUTH_MAX) { - rec.status = cpu_to_le16(P80211ENUM_status_ap_full); - } else { - ether_addr_copy(hw->authlist.addr[hw->authlist.cnt], - rec.address); - hw->authlist.cnt++; - added = 1; - } - } - } - - /* - * Send back the results of the authentication. If this doesn't work, - * then make sure to remove the address from the authenticated list if - * it was added. - */ - - rec.algorithm = inf->info.authreq.algorithm; - - result = hfa384x_drvr_setconfig(hw, HFA384x_RID_AUTHENTICATESTA, - &rec, sizeof(rec)); - if (result) { - if (added) - hw->authlist.cnt--; - netdev_err(wlandev->netdev, - "setconfig(authenticatestation) failed, result=%d\n", - result); - } -} - -/* - * prism2sta_inf_psusercnt - * - * Handles the receipt of a PowerSaveUserCount info frame. Should - * be present in APs only. - * - * Arguments: - * wlandev wlan device structure - * inf ptr to info frame (contents in hfa384x order) - * - * Returns: - * nothing - * - * Side effects: - * - * Call context: - * interrupt - */ -static void prism2sta_inf_psusercnt(struct wlandevice *wlandev, - struct hfa384x_inf_frame *inf) -{ - struct hfa384x *hw = wlandev->priv; - - hw->psusercount = le16_to_cpu(inf->info.psusercnt.usercnt); -} - -/* - * prism2sta_ev_info - * - * Handles the Info event. - * - * Arguments: - * wlandev wlan device structure - * inf ptr to a generic info frame - * - * Returns: - * nothing - * - * Side effects: - * - * Call context: - * interrupt - */ -void prism2sta_ev_info(struct wlandevice *wlandev, - struct hfa384x_inf_frame *inf) -{ - le16_to_cpus(&inf->infotype); - /* Dispatch */ - switch (inf->infotype) { - case HFA384x_IT_HANDOVERADDR: - netdev_dbg(wlandev->netdev, - "received infoframe:HANDOVER (unhandled)\n"); - break; - case HFA384x_IT_COMMTALLIES: - prism2sta_inf_tallies(wlandev, inf); - break; - case HFA384x_IT_HOSTSCANRESULTS: - prism2sta_inf_hostscanresults(wlandev, inf); - break; - case HFA384x_IT_SCANRESULTS: - prism2sta_inf_scanresults(wlandev, inf); - break; - case HFA384x_IT_CHINFORESULTS: - prism2sta_inf_chinforesults(wlandev, inf); - break; - case HFA384x_IT_LINKSTATUS: - prism2sta_inf_linkstatus(wlandev, inf); - break; - case HFA384x_IT_ASSOCSTATUS: - prism2sta_inf_assocstatus(wlandev, inf); - break; - case HFA384x_IT_AUTHREQ: - prism2sta_inf_authreq(wlandev, inf); - break; - case HFA384x_IT_PSUSERCNT: - prism2sta_inf_psusercnt(wlandev, inf); - break; - case HFA384x_IT_KEYIDCHANGED: - netdev_warn(wlandev->netdev, "Unhandled IT_KEYIDCHANGED\n"); - break; - case HFA384x_IT_ASSOCREQ: - netdev_warn(wlandev->netdev, "Unhandled IT_ASSOCREQ\n"); - break; - case HFA384x_IT_MICFAILURE: - netdev_warn(wlandev->netdev, "Unhandled IT_MICFAILURE\n"); - break; - default: - netdev_warn(wlandev->netdev, - "Unknown info type=0x%02x\n", inf->infotype); - break; - } -} - -/* - * prism2sta_ev_tx - * - * Handles the Tx event. - * - * Arguments: - * wlandev wlan device structure - * status tx frame status word - * Returns: - * nothing - * - * Side effects: - * - * Call context: - * interrupt - */ -void prism2sta_ev_tx(struct wlandevice *wlandev, u16 status) -{ - netdev_dbg(wlandev->netdev, "Tx Complete, status=0x%04x\n", status); - /* update linux network stats */ - wlandev->netdev->stats.tx_packets++; -} - -/* - * prism2sta_ev_alloc - * - * Handles the Alloc event. - * - * Arguments: - * wlandev wlan device structure - * - * Returns: - * nothing - * - * Side effects: - * - * Call context: - * interrupt - */ -void prism2sta_ev_alloc(struct wlandevice *wlandev) -{ - netif_wake_queue(wlandev->netdev); -} - -/* - * create_wlan - * - * Called at module init time. This creates the struct wlandevice structure - * and initializes it with relevant bits. - * - * Arguments: - * none - * - * Returns: - * the created struct wlandevice structure. - * - * Side effects: - * also allocates the priv/hw structures. - * - * Call context: - * process thread - * - */ -static struct wlandevice *create_wlan(void) -{ - struct wlandevice *wlandev = NULL; - struct hfa384x *hw = NULL; - - /* Alloc our structures */ - wlandev = kzalloc(sizeof(*wlandev), GFP_KERNEL); - hw = kzalloc(sizeof(*hw), GFP_KERNEL); - - if (!wlandev || !hw) { - kfree(wlandev); - kfree(hw); - return NULL; - } - - /* Initialize the network device object. */ - wlandev->nsdname = dev_info; - wlandev->msdstate = WLAN_MSD_HWPRESENT_PENDING; - wlandev->priv = hw; - wlandev->open = prism2sta_open; - wlandev->close = prism2sta_close; - wlandev->reset = prism2sta_reset; - wlandev->txframe = prism2sta_txframe; - wlandev->mlmerequest = prism2sta_mlmerequest; - wlandev->set_multicast_list = prism2sta_setmulticast; - wlandev->tx_timeout = hfa384x_tx_timeout; - - wlandev->nsdcaps = P80211_NSDCAP_HWFRAGMENT | P80211_NSDCAP_AUTOJOIN; - - /* Initialize the device private data structure. */ - hw->dot11_desired_bss_type = 1; - - return wlandev; -} - -void prism2sta_commsqual_defer(struct work_struct *data) -{ - struct hfa384x *hw = container_of(data, struct hfa384x, commsqual_bh); - struct wlandevice *wlandev = hw->wlandev; - struct hfa384x_bytestr32 ssid; - struct p80211msg_dot11req_mibget msg; - struct p80211item_uint32 *mibitem = (struct p80211item_uint32 *) - &msg.mibattribute.data; - int result = 0; - - if (hw->wlandev->hwremoved) - return; - - /* we don't care if we're in AP mode */ - if ((wlandev->macmode == WLAN_MACMODE_NONE) || - (wlandev->macmode == WLAN_MACMODE_ESS_AP)) { - return; - } - - /* It only makes sense to poll these in non-IBSS */ - if (wlandev->macmode != WLAN_MACMODE_IBSS_STA) { - result = hfa384x_drvr_getconfig(hw, HFA384x_RID_DBMCOMMSQUALITY, - &hw->qual, HFA384x_RID_DBMCOMMSQUALITY_LEN); - - if (result) { - netdev_err(wlandev->netdev, "error fetching commsqual\n"); - return; - } - - netdev_dbg(wlandev->netdev, "commsqual %d %d %d\n", - le16_to_cpu(hw->qual.cq_curr_bss), - le16_to_cpu(hw->qual.asl_curr_bss), - le16_to_cpu(hw->qual.anl_curr_fc)); - } - - /* Get the signal rate */ - msg.msgcode = DIDMSG_DOT11REQ_MIBGET; - mibitem->did = DIDMIB_P2_MAC_CURRENTTXRATE; - result = p80211req_dorequest(wlandev, (u8 *)&msg); - - if (result) { - netdev_dbg(wlandev->netdev, - "get signal rate failed, result = %d\n", result); - return; - } - - switch (mibitem->data) { - case HFA384x_RATEBIT_1: - hw->txrate = 10; - break; - case HFA384x_RATEBIT_2: - hw->txrate = 20; - break; - case HFA384x_RATEBIT_5dot5: - hw->txrate = 55; - break; - case HFA384x_RATEBIT_11: - hw->txrate = 110; - break; - default: - netdev_dbg(wlandev->netdev, "Bad ratebit (%d)\n", - mibitem->data); - } - - /* Lastly, we need to make sure the BSSID didn't change on us */ - result = hfa384x_drvr_getconfig(hw, - HFA384x_RID_CURRENTBSSID, - wlandev->bssid, WLAN_BSSID_LEN); - if (result) { - netdev_dbg(wlandev->netdev, - "getconfig(0x%02x) failed, result = %d\n", - HFA384x_RID_CURRENTBSSID, result); - return; - } - - result = hfa384x_drvr_getconfig(hw, - HFA384x_RID_CURRENTSSID, - &ssid, sizeof(ssid)); - if (result) { - netdev_dbg(wlandev->netdev, - "getconfig(0x%02x) failed, result = %d\n", - HFA384x_RID_CURRENTSSID, result); - return; - } - prism2mgmt_bytestr2pstr((struct hfa384x_bytestr *)&ssid, - (struct p80211pstrd *)&wlandev->ssid); - - /* Reschedule timer */ - mod_timer(&hw->commsqual_timer, jiffies + HZ); -} - -void prism2sta_commsqual_timer(struct timer_list *t) -{ - struct hfa384x *hw = from_timer(hw, t, commsqual_timer); - - schedule_work(&hw->commsqual_bh); -} diff --git a/drivers/staging/wlan-ng/prism2usb.c b/drivers/staging/wlan-ng/prism2usb.c deleted file mode 100644 index 416127e5d713..000000000000 --- a/drivers/staging/wlan-ng/prism2usb.c +++ /dev/null @@ -1,299 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include "hfa384x_usb.c" -#include "prism2mgmt.c" -#include "prism2mib.c" -#include "prism2sta.c" -#include "prism2fw.c" - -#define PRISM_DEV(vid, pid, name) \ - { USB_DEVICE(vid, pid), \ - .driver_info = (unsigned long)name } - -static const struct usb_device_id usb_prism_tbl[] = { - PRISM_DEV(0x04bb, 0x0922, "IOData AirPort WN-B11/USBS"), - PRISM_DEV(0x07aa, 0x0012, "Corega USB Wireless LAN Stick-11"), - PRISM_DEV(0x09aa, 0x3642, "Prism2.x 11Mbps USB WLAN Adapter"), - PRISM_DEV(0x1668, 0x0408, "Actiontec Prism2.5 11Mbps USB WLAN Adapter"), - PRISM_DEV(0x1668, 0x0421, "Actiontec Prism2.5 11Mbps USB WLAN Adapter"), - PRISM_DEV(0x1915, 0x2236, "Linksys WUSB11v3.0 11Mbps USB WLAN Adapter"), - PRISM_DEV(0x066b, 0x2212, "Linksys WUSB11v2.5 11Mbps USB WLAN Adapter"), - PRISM_DEV(0x066b, 0x2213, "Linksys WUSB12v1.1 11Mbps USB WLAN Adapter"), - PRISM_DEV(0x0411, 0x0016, "Melco WLI-USB-S11 11Mbps WLAN Adapter"), - PRISM_DEV(0x08de, 0x7a01, "PRISM25 USB IEEE 802.11 Mini Adapter"), - PRISM_DEV(0x8086, 0x1111, "Intel PRO/Wireless 2011B USB LAN Adapter"), - PRISM_DEV(0x0d8e, 0x7a01, "PRISM25 IEEE 802.11 Mini USB Adapter"), - PRISM_DEV(0x045e, 0x006e, "Microsoft MN510 USB Wireless Adapter"), - PRISM_DEV(0x0967, 0x0204, "Acer Warplink USB Adapter"), - PRISM_DEV(0x0cde, 0x0002, "Z-Com 725/726 Prism2.5 USB/USB Integrated"), - PRISM_DEV(0x0cde, 0x0005, "Z-Com Xl735 USB Wireless 802.11b Adapter"), - PRISM_DEV(0x413c, 0x8100, "Dell TrueMobile 1180 USB Wireless Adapter"), - PRISM_DEV(0x0b3b, 0x1601, "ALLNET 0193 11Mbps USB WLAN Adapter"), - PRISM_DEV(0x0b3b, 0x1602, "ZyXEL ZyAIR B200 USB Wireless Adapter"), - PRISM_DEV(0x0baf, 0x00eb, "USRobotics USR1120 USB Wireless Adapter"), - PRISM_DEV(0x0411, 0x0027, "Melco WLI-USB-KS11G 11Mbps WLAN Adapter"), - PRISM_DEV(0x04f1, 0x3009, "JVC MP-XP7250 Builtin USB WLAN Adapter"), - PRISM_DEV(0x0846, 0x4110, "NetGear MA111"), - PRISM_DEV(0x03f3, 0x0020, "Adaptec AWN-8020 USB WLAN Adapter"), - PRISM_DEV(0x2821, 0x3300, "ASUS-WL140 / Hawking HighDB USB Wireless Adapter"), - PRISM_DEV(0x2001, 0x3700, "DWL-122 USB Wireless Adapter"), - PRISM_DEV(0x2001, 0x3702, "DWL-120 Rev F USB Wireless Adapter"), - PRISM_DEV(0x50c2, 0x4013, "Averatec USB WLAN Adapter"), - PRISM_DEV(0x2c02, 0x14ea, "Planex GW-US11H USB WLAN Adapter"), - PRISM_DEV(0x124a, 0x168b, "Airvast PRISM3 USB WLAN Adapter"), - PRISM_DEV(0x083a, 0x3503, "T-Sinus 111 USB WLAN Adapter"), - PRISM_DEV(0x0411, 0x0044, "Melco WLI-USB-KB11 11Mbps WLAN Adapter"), - PRISM_DEV(0x1668, 0x6106, "ROPEX FreeLan USB 802.11b Adapter"), - PRISM_DEV(0x124a, 0x4017, "Pheenet WL-503IA USB 802.11b Adapter"), - PRISM_DEV(0x0bb2, 0x0302, "Ambit Microsystems Corp."), - PRISM_DEV(0x9016, 0x182d, "Sitecom WL-022 USB 802.11b Adapter"), - PRISM_DEV(0x0543, 0x0f01, - "ViewSonic Airsync USB Adapter 11Mbps (Prism2.5)"), - PRISM_DEV(0x067c, 0x1022, - "Siemens SpeedStream 1022 11Mbps USB WLAN Adapter"), - PRISM_DEV(0x049f, 0x0033, - "Compaq/Intel W100 PRO/Wireless 11Mbps multiport WLAN Adapter"), - { } /* terminator */ -}; -MODULE_DEVICE_TABLE(usb, usb_prism_tbl); - -static int prism2sta_probe_usb(struct usb_interface *interface, - const struct usb_device_id *id) -{ - struct usb_device *dev; - struct usb_endpoint_descriptor *bulk_in, *bulk_out; - struct usb_host_interface *iface_desc = interface->cur_altsetting; - struct wlandevice *wlandev = NULL; - struct hfa384x *hw = NULL; - int result = 0; - - result = usb_find_common_endpoints(iface_desc, &bulk_in, &bulk_out, NULL, NULL); - if (result) - goto failed; - - dev = interface_to_usbdev(interface); - wlandev = create_wlan(); - if (!wlandev) { - dev_err(&interface->dev, "Memory allocation failure.\n"); - result = -EIO; - goto failed; - } - hw = wlandev->priv; - - if (wlan_setup(wlandev, &interface->dev) != 0) { - dev_err(&interface->dev, "wlan_setup() failed.\n"); - result = -EIO; - goto failed; - } - - /* Initialize the hw data */ - hw->endp_in = usb_rcvbulkpipe(dev, bulk_in->bEndpointAddress); - hw->endp_out = usb_sndbulkpipe(dev, bulk_out->bEndpointAddress); - hfa384x_create(hw, dev); - hw->wlandev = wlandev; - - /* Register the wlandev, this gets us a name and registers the - * linux netdevice. - */ - SET_NETDEV_DEV(wlandev->netdev, &interface->dev); - - /* Do a chip-level reset on the MAC */ - if (prism2_doreset) { - result = hfa384x_corereset(hw, - prism2_reset_holdtime, - prism2_reset_settletime, 0); - if (result != 0) { - result = -EIO; - dev_err(&interface->dev, - "hfa384x_corereset() failed.\n"); - goto failed_reset; - } - } - - usb_get_dev(dev); - - wlandev->msdstate = WLAN_MSD_HWPRESENT; - - /* Try and load firmware, then enable card before we register */ - prism2_fwtry(dev, wlandev); - prism2sta_ifstate(wlandev, P80211ENUM_ifstate_enable); - - if (register_wlandev(wlandev) != 0) { - dev_err(&interface->dev, "register_wlandev() failed.\n"); - result = -EIO; - goto failed_register; - } - - goto done; - -failed_register: - usb_put_dev(dev); -failed_reset: - wlan_teardown(wlandev); -failed: - kfree(wlandev); - kfree(hw); - wlandev = NULL; - -done: - usb_set_intfdata(interface, wlandev); - return result; -} - -static void prism2sta_disconnect_usb(struct usb_interface *interface) -{ - struct wlandevice *wlandev; - - wlandev = usb_get_intfdata(interface); - if (wlandev) { - LIST_HEAD(cleanlist); - struct hfa384x_usbctlx *ctlx, *temp; - unsigned long flags; - - struct hfa384x *hw = wlandev->priv; - - if (!hw) - goto exit; - - spin_lock_irqsave(&hw->ctlxq.lock, flags); - - p80211netdev_hwremoved(wlandev); - list_splice_init(&hw->ctlxq.reapable, &cleanlist); - list_splice_init(&hw->ctlxq.completing, &cleanlist); - list_splice_init(&hw->ctlxq.pending, &cleanlist); - list_splice_init(&hw->ctlxq.active, &cleanlist); - - spin_unlock_irqrestore(&hw->ctlxq.lock, flags); - - /* There's no hardware to shutdown, but the driver - * might have some tasks that must be stopped before - * we can tear everything down. - */ - prism2sta_ifstate(wlandev, P80211ENUM_ifstate_disable); - - timer_shutdown_sync(&hw->throttle); - timer_shutdown_sync(&hw->reqtimer); - timer_shutdown_sync(&hw->resptimer); - - /* Unlink all the URBs. This "removes the wheels" - * from the entire CTLX handling mechanism. - */ - usb_kill_urb(&hw->rx_urb); - usb_kill_urb(&hw->tx_urb); - usb_kill_urb(&hw->ctlx_urb); - - cancel_work_sync(&hw->completion_bh); - cancel_work_sync(&hw->reaper_bh); - - cancel_work_sync(&hw->link_bh); - cancel_work_sync(&hw->commsqual_bh); - cancel_work_sync(&hw->usb_work); - - /* Now we complete any outstanding commands - * and tell everyone who is waiting for their - * responses that we have shut down. - */ - list_for_each_entry(ctlx, &cleanlist, list) - complete(&ctlx->done); - - /* Give any outstanding synchronous commands - * a chance to complete. All they need to do - * is "wake up", so that's easy. - * (I'd like a better way to do this, really.) - */ - msleep(100); - - /* Now delete the CTLXs, because no-one else can now. */ - list_for_each_entry_safe(ctlx, temp, &cleanlist, list) - kfree(ctlx); - - /* Unhook the wlandev */ - unregister_wlandev(wlandev); - wlan_teardown(wlandev); - - usb_put_dev(hw->usb); - - hfa384x_destroy(hw); - kfree(hw); - - kfree(wlandev); - } - -exit: - usb_set_intfdata(interface, NULL); -} - -#ifdef CONFIG_PM -static int prism2sta_suspend(struct usb_interface *interface, - pm_message_t message) -{ - struct hfa384x *hw = NULL; - struct wlandevice *wlandev; - - wlandev = usb_get_intfdata(interface); - if (!wlandev) - return -ENODEV; - - hw = wlandev->priv; - if (!hw) - return -ENODEV; - - prism2sta_ifstate(wlandev, P80211ENUM_ifstate_disable); - - usb_kill_urb(&hw->rx_urb); - usb_kill_urb(&hw->tx_urb); - usb_kill_urb(&hw->ctlx_urb); - - return 0; -} - -static int prism2sta_resume(struct usb_interface *interface) -{ - int result = 0; - struct hfa384x *hw = NULL; - struct wlandevice *wlandev; - - wlandev = usb_get_intfdata(interface); - if (!wlandev) - return -ENODEV; - - hw = wlandev->priv; - if (!hw) - return -ENODEV; - - /* Do a chip-level reset on the MAC */ - if (prism2_doreset) { - result = hfa384x_corereset(hw, - prism2_reset_holdtime, - prism2_reset_settletime, 0); - if (result != 0) { - unregister_wlandev(wlandev); - hfa384x_destroy(hw); - dev_err(&interface->dev, "hfa384x_corereset() failed.\n"); - kfree(wlandev); - kfree(hw); - wlandev = NULL; - return -ENODEV; - } - } - - prism2sta_ifstate(wlandev, P80211ENUM_ifstate_enable); - - return 0; -} -#else -#define prism2sta_suspend NULL -#define prism2sta_resume NULL -#endif /* CONFIG_PM */ - -static struct usb_driver prism2_usb_driver = { - .name = "prism2_usb", - .probe = prism2sta_probe_usb, - .disconnect = prism2sta_disconnect_usb, - .id_table = usb_prism_tbl, - .suspend = prism2sta_suspend, - .resume = prism2sta_resume, - .reset_resume = prism2sta_resume, - /* fops, minor? */ -}; - -module_usb_driver(prism2_usb_driver); -- cgit v1.2.3-59-g8ed1b From 1961511c8e662417f7fd3a111c9980d415413c28 Mon Sep 17 00:00:00 2001 From: "Ricardo B. Marliere" Date: Tue, 5 Mar 2024 16:40:23 -0300 Subject: remoteproc: Make rproc_class constant Since commit 43a7206b0963 ("driver core: class: make class_register() take a const *"), the driver core allows for struct class to be in read-only memory, so move the rproc_class structure to be declared at build time placing it into read-only memory, instead of having to be dynamically allocated at boot time. Cc: Greg Kroah-Hartman Suggested-by: Greg Kroah-Hartman Signed-off-by: Ricardo B. Marliere Link: https://lore.kernel.org/r/20240305-class_cleanup-remoteproc2-v1-1-1b139e9828c9@marliere.net Signed-off-by: Mathieu Poirier --- drivers/remoteproc/remoteproc_internal.h | 2 +- drivers/remoteproc/remoteproc_sysfs.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/remoteproc/remoteproc_internal.h b/drivers/remoteproc/remoteproc_internal.h index f62a82d71dfa..0cd09e67ac14 100644 --- a/drivers/remoteproc/remoteproc_internal.h +++ b/drivers/remoteproc/remoteproc_internal.h @@ -72,7 +72,7 @@ void rproc_init_debugfs(void); void rproc_exit_debugfs(void); /* from remoteproc_sysfs.c */ -extern struct class rproc_class; +extern const struct class rproc_class; int rproc_init_sysfs(void); void rproc_exit_sysfs(void); diff --git a/drivers/remoteproc/remoteproc_sysfs.c b/drivers/remoteproc/remoteproc_sysfs.c index 8c7ea8922638..138e752c5e4e 100644 --- a/drivers/remoteproc/remoteproc_sysfs.c +++ b/drivers/remoteproc/remoteproc_sysfs.c @@ -254,7 +254,7 @@ static const struct attribute_group *rproc_devgroups[] = { NULL }; -struct class rproc_class = { +const struct class rproc_class = { .name = "remoteproc", .dev_groups = rproc_devgroups, }; -- cgit v1.2.3-59-g8ed1b From 193d0c4e1e42517958b6510687fbd9a92165aa0d Mon Sep 17 00:00:00 2001 From: "Ricardo B. Marliere" Date: Tue, 5 Mar 2024 15:28:27 -0300 Subject: rpmsg: core: Make rpmsg_class constant Since commit 43a7206b0963 ("driver core: class: make class_register() take a const *"), the driver core allows for struct class to be in read-only memory, so move the rpmsg_class structure to be declared at build time placing it into read-only memory, instead of having to be dynamically allocated at boot time. Cc: Greg Kroah-Hartman Suggested-by: Greg Kroah-Hartman Signed-off-by: Ricardo B. Marliere Link: https://lore.kernel.org/r/20240305-class_cleanup-remoteproc-v1-1-19373374e003@marliere.net Signed-off-by: Mathieu Poirier --- drivers/rpmsg/rpmsg_char.c | 2 +- drivers/rpmsg/rpmsg_core.c | 16 +++++++++------- drivers/rpmsg/rpmsg_ctrl.c | 2 +- drivers/rpmsg/rpmsg_internal.h | 2 +- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c index 1cb8d7474428..d7a342510902 100644 --- a/drivers/rpmsg/rpmsg_char.c +++ b/drivers/rpmsg/rpmsg_char.c @@ -423,7 +423,7 @@ static struct rpmsg_eptdev *rpmsg_chrdev_eptdev_alloc(struct rpmsg_device *rpdev init_waitqueue_head(&eptdev->readq); device_initialize(dev); - dev->class = rpmsg_class; + dev->class = &rpmsg_class; dev->parent = parent; dev->groups = rpmsg_eptdev_groups; dev_set_drvdata(dev, eptdev); diff --git a/drivers/rpmsg/rpmsg_core.c b/drivers/rpmsg/rpmsg_core.c index 4295c01a2861..0fa08266404d 100644 --- a/drivers/rpmsg/rpmsg_core.c +++ b/drivers/rpmsg/rpmsg_core.c @@ -20,7 +20,9 @@ #include "rpmsg_internal.h" -struct class *rpmsg_class; +const struct class rpmsg_class = { + .name = "rpmsg", +}; EXPORT_SYMBOL(rpmsg_class); /** @@ -715,16 +717,16 @@ static int __init rpmsg_init(void) { int ret; - rpmsg_class = class_create("rpmsg"); - if (IS_ERR(rpmsg_class)) { - pr_err("failed to create rpmsg class\n"); - return PTR_ERR(rpmsg_class); + ret = class_register(&rpmsg_class); + if (ret) { + pr_err("failed to register rpmsg class\n"); + return ret; } ret = bus_register(&rpmsg_bus); if (ret) { pr_err("failed to register rpmsg bus: %d\n", ret); - class_destroy(rpmsg_class); + class_destroy(&rpmsg_class); } return ret; } @@ -733,7 +735,7 @@ postcore_initcall(rpmsg_init); static void __exit rpmsg_fini(void) { bus_unregister(&rpmsg_bus); - class_destroy(rpmsg_class); + class_destroy(&rpmsg_class); } module_exit(rpmsg_fini); diff --git a/drivers/rpmsg/rpmsg_ctrl.c b/drivers/rpmsg/rpmsg_ctrl.c index c312794ba4b3..28f57945ccd9 100644 --- a/drivers/rpmsg/rpmsg_ctrl.c +++ b/drivers/rpmsg/rpmsg_ctrl.c @@ -150,7 +150,7 @@ static int rpmsg_ctrldev_probe(struct rpmsg_device *rpdev) dev = &ctrldev->dev; device_initialize(dev); dev->parent = &rpdev->dev; - dev->class = rpmsg_class; + dev->class = &rpmsg_class; mutex_init(&ctrldev->ctrl_lock); cdev_init(&ctrldev->cdev, &rpmsg_ctrldev_fops); diff --git a/drivers/rpmsg/rpmsg_internal.h b/drivers/rpmsg/rpmsg_internal.h index b950d6f790a3..a3ba768138f1 100644 --- a/drivers/rpmsg/rpmsg_internal.h +++ b/drivers/rpmsg/rpmsg_internal.h @@ -18,7 +18,7 @@ #define to_rpmsg_device(d) container_of(d, struct rpmsg_device, dev) #define to_rpmsg_driver(d) container_of(d, struct rpmsg_driver, drv) -extern struct class *rpmsg_class; +extern const struct class rpmsg_class; /** * struct rpmsg_device_ops - indirection table for the rpmsg_device operations -- cgit v1.2.3-59-g8ed1b From 331f91d86f71d0bb89a44217cc0b2a22810bbd42 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Thu, 21 Mar 2024 09:46:13 +0100 Subject: remoteproc: mediatek: Make sure IPI buffer fits in L2TCM The IPI buffer location is read from the firmware that we load to the System Companion Processor, and it's not granted that both the SRAM (L2TCM) size that is defined in the devicetree node is large enough for that, and while this is especially true for multi-core SCP, it's still useful to check on single-core variants as well. Failing to perform this check may make this driver perform R/W operations out of the L2TCM boundary, resulting (at best) in a kernel panic. To fix that, check that the IPI buffer fits, otherwise return a failure and refuse to boot the relevant SCP core (or the SCP at all, if this is single core). Fixes: 3efa0ea743b7 ("remoteproc/mediatek: read IPI buffer offset from FW") Signed-off-by: AngeloGioacchino Del Regno Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20240321084614.45253-2-angelogioacchino.delregno@collabora.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/mtk_scp.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/remoteproc/mtk_scp.c b/drivers/remoteproc/mtk_scp.c index a35409eda0cf..67518291a8ad 100644 --- a/drivers/remoteproc/mtk_scp.c +++ b/drivers/remoteproc/mtk_scp.c @@ -132,7 +132,7 @@ static int scp_elf_read_ipi_buf_addr(struct mtk_scp *scp, static int scp_ipi_init(struct mtk_scp *scp, const struct firmware *fw) { int ret; - size_t offset; + size_t buf_sz, offset; /* read the ipi buf addr from FW itself first */ ret = scp_elf_read_ipi_buf_addr(scp, fw, &offset); @@ -144,6 +144,14 @@ static int scp_ipi_init(struct mtk_scp *scp, const struct firmware *fw) } dev_info(scp->dev, "IPI buf addr %#010zx\n", offset); + /* Make sure IPI buffer fits in the L2TCM range assigned to this core */ + buf_sz = sizeof(*scp->recv_buf) + sizeof(*scp->send_buf); + + if (scp->sram_size < buf_sz + offset) { + dev_err(scp->dev, "IPI buffer does not fit in SRAM.\n"); + return -EOVERFLOW; + } + scp->recv_buf = (struct mtk_share_obj __iomem *) (scp->sram_base + offset); scp->send_buf = (struct mtk_share_obj __iomem *) -- cgit v1.2.3-59-g8ed1b From 0f74c64f0a9f6e1e7cf17bea3d4350fa6581e0d7 Mon Sep 17 00:00:00 2001 From: Shengyu Qu Date: Thu, 7 Mar 2024 20:21:12 +0800 Subject: riscv: dts: starfive: Remove PMIC interrupt info for Visionfive 2 board Interrupt line number of the AXP15060 PMIC is not a necessary part of its device tree. Originally the binding required one, so the dts patch added an invalid interrupt that the driver ignored (0) as the interrupt line of the PMIC is not actually connected on this platform. This went unnoticed during review as it would have been a valid interrupt for a GPIO controller, but it is not for the PLIC. The PLIC, on this platform at least, silently ignores the enablement of interrupt 0. Bo Gan is running a modified version of OpenSBI that faults if writes are done to reserved fields, so their kernel runs into problems. Delete the invalid interrupt from the device tree. Cc: stable@vger.kernel.org Reported-by: Bo Gan Link: https://lore.kernel.org/all/c8b6e960-2459-130f-e4e4-7c9c2ebaa6d3@gmail.com/ Signed-off-by: Shengyu Qu Fixes: 2378341504de ("riscv: dts: starfive: Enable axp15060 pmic for cpufreq") [conor: rewrite the commit message to add more detail] Signed-off-by: Conor Dooley --- arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi index 45b58b6f3df8..7783d464d529 100644 --- a/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi +++ b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi @@ -238,7 +238,6 @@ axp15060: pmic@36 { compatible = "x-powers,axp15060"; reg = <0x36>; - interrupts = <0>; interrupt-controller; #interrupt-cells = <1>; -- cgit v1.2.3-59-g8ed1b From c92ed34281417fbdc91b7570e83df39066fc9e72 Mon Sep 17 00:00:00 2001 From: Inochi Amaoto Date: Tue, 26 Mar 2024 10:37:28 +0800 Subject: dt-bindings: usb: dwc2: Add support for Sophgo CV18XX/SG200X series SoC Add compatible string for the DWC2 IP which is used by Sophgo CV18XX/SG2000 series SoC. Signed-off-by: Inochi Amaoto Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/IA1PR20MB49530A43A81CF4B809DBC2F8BB352@IA1PR20MB4953.namprd20.prod.outlook.com Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/usb/dwc2.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/usb/dwc2.yaml b/Documentation/devicetree/bindings/usb/dwc2.yaml index 0a5c98ea711d..9a2106e7b4b6 100644 --- a/Documentation/devicetree/bindings/usb/dwc2.yaml +++ b/Documentation/devicetree/bindings/usb/dwc2.yaml @@ -59,6 +59,7 @@ properties: - const: amcc,dwc-otg - const: apm,apm82181-dwc-otg - const: snps,dwc2 + - const: sophgo,cv1800-usb - const: st,stm32f4x9-fsotg - const: st,stm32f4x9-hsotg - const: st,stm32f7-hsotg -- cgit v1.2.3-59-g8ed1b From 63aa7ab955e7d028d3be59ebc2960e105497c70d Mon Sep 17 00:00:00 2001 From: Inochi Amaoto Date: Tue, 26 Mar 2024 10:37:29 +0800 Subject: usb: dwc2: add support for Sophgo CV18XX/SG200X series SoC Add params for DWC2 IP in Sophgo CV18XX/SG200X series SoC. Signed-off-by: Inochi Amaoto Acked-by: Minas Harutyunyan Link: https://lore.kernel.org/r/IA1PR20MB4953EE73DD36D5FFC81D90EDBB352@IA1PR20MB4953.namprd20.prod.outlook.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc2/params.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/usb/dwc2/params.c b/drivers/usb/dwc2/params.c index c47524483f48..5a1500d0bdd9 100644 --- a/drivers/usb/dwc2/params.c +++ b/drivers/usb/dwc2/params.c @@ -201,6 +201,25 @@ static void dwc2_set_amcc_params(struct dwc2_hsotg *hsotg) p->ahbcfg = GAHBCFG_HBSTLEN_INCR16 << GAHBCFG_HBSTLEN_SHIFT; } +static void dwc2_set_cv1800_params(struct dwc2_hsotg *hsotg) +{ + struct dwc2_core_params *p = &hsotg->params; + + p->otg_caps.hnp_support = false; + p->otg_caps.srp_support = false; + p->host_dma = false; + p->g_dma = false; + p->speed = DWC2_SPEED_PARAM_HIGH; + p->phy_type = DWC2_PHY_TYPE_PARAM_UTMI; + p->phy_utmi_width = 16; + p->ahbcfg = GAHBCFG_HBSTLEN_INCR16 << GAHBCFG_HBSTLEN_SHIFT; + p->lpm = false; + p->lpm_clock_gating = false; + p->besl = false; + p->hird_threshold_en = false; + p->power_down = DWC2_POWER_DOWN_PARAM_NONE; +} + static void dwc2_set_stm32f4x9_fsotg_params(struct dwc2_hsotg *hsotg) { struct dwc2_core_params *p = &hsotg->params; @@ -295,6 +314,8 @@ const struct of_device_id dwc2_of_match_table[] = { .data = dwc2_set_amlogic_a1_params }, { .compatible = "amcc,dwc-otg", .data = dwc2_set_amcc_params }, { .compatible = "apm,apm82181-dwc-otg", .data = dwc2_set_amcc_params }, + { .compatible = "sophgo,cv1800-usb", + .data = dwc2_set_cv1800_params }, { .compatible = "st,stm32f4x9-fsotg", .data = dwc2_set_stm32f4x9_fsotg_params }, { .compatible = "st,stm32f4x9-hsotg" }, -- cgit v1.2.3-59-g8ed1b From c4f426460febadd10002248f579ee69374a4ef99 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Tue, 19 Mar 2024 10:53:51 +0000 Subject: dt-bindings: usb: renesas,usbhs: Document RZ/G2L family compatible The USBHS IP found on RZ/G2L SoCs only has 10 pipe buffers compared to 16 pipe buffers on RZ/A2M. Document renesas,rzg2l-usbhs family compatible to handle this difference for RZ/G2L family SoCs. Signed-off-by: Biju Das Acked-by: Krzysztof Kozlowski Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20240319105356.87287-2-biju.das.jz@bp.renesas.com Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/usb/renesas,usbhs.yaml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/usb/renesas,usbhs.yaml b/Documentation/devicetree/bindings/usb/renesas,usbhs.yaml index 40ada78f2328..c63db3ebd07b 100644 --- a/Documentation/devicetree/bindings/usb/renesas,usbhs.yaml +++ b/Documentation/devicetree/bindings/usb/renesas,usbhs.yaml @@ -19,10 +19,14 @@ properties: - items: - enum: - renesas,usbhs-r7s9210 # RZ/A2 + - const: renesas,rza2-usbhs + + - items: + - enum: - renesas,usbhs-r9a07g043 # RZ/G2UL and RZ/Five - renesas,usbhs-r9a07g044 # RZ/G2{L,LC} - renesas,usbhs-r9a07g054 # RZ/V2L - - const: renesas,rza2-usbhs + - const: renesas,rzg2l-usbhs - items: - enum: -- cgit v1.2.3-59-g8ed1b From a79c5b6f675634387de8e88b0c85a053b9952970 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Tue, 19 Mar 2024 10:53:52 +0000 Subject: usb: renesas_usbhs: Simplify obtaining device data Simplify probe() by removing redundant dev->of_node check. While at it, replace dev_err->dev_err_probe for error path. Signed-off-by: Biju Das Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20240319105356.87287-3-biju.das.jz@bp.renesas.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/renesas_usbhs/common.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c index dd1c17542439..0c62e4c6c88d 100644 --- a/drivers/usb/renesas_usbhs/common.c +++ b/drivers/usb/renesas_usbhs/common.c @@ -595,16 +595,11 @@ static int usbhs_probe(struct platform_device *pdev) u32 tmp; int irq; - /* check device node */ - if (dev_of_node(dev)) - info = of_device_get_match_data(dev); - else - info = renesas_usbhs_get_info(pdev); - - /* check platform information */ + info = of_device_get_match_data(dev); if (!info) { - dev_err(dev, "no platform information\n"); - return -EINVAL; + info = renesas_usbhs_get_info(pdev); + if (!info) + return dev_err_probe(dev, -EINVAL, "no platform info\n"); } /* platform data */ -- cgit v1.2.3-59-g8ed1b From 790effae39cf368a9ff029406b8033ab6618ff90 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Tue, 19 Mar 2024 10:53:53 +0000 Subject: usb: renesas_usbhs: Improve usbhsc_default_pipe[] for isochronous transfers As per the hardware manual, double buffer setting results in fewer interrupts for high-speed data transfers. Improve usbhsc_default_pipe[] for isochronous transfers by updating the table from single->double buffering and update the pipe number accordingly. Suggested-by: Geert Uytterhoeven Signed-off-by: Biju Das Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20240319105356.87287-4-biju.das.jz@bp.renesas.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/renesas_usbhs/common.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c index 0c62e4c6c88d..177fa3144a47 100644 --- a/drivers/usb/renesas_usbhs/common.c +++ b/drivers/usb/renesas_usbhs/common.c @@ -366,11 +366,11 @@ static void usbhsc_clk_disable_unprepare(struct usbhs_priv *priv) /* commonly used on old SH-Mobile SoCs */ static struct renesas_usbhs_driver_pipe_config usbhsc_default_pipe[] = { RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_CONTROL, 64, 0x00, false), - RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_ISOC, 1024, 0x08, false), - RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_ISOC, 1024, 0x18, false), - RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_BULK, 512, 0x28, true), - RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_BULK, 512, 0x38, true), + RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_ISOC, 1024, 0x08, true), + RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_ISOC, 1024, 0x28, true), RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_BULK, 512, 0x48, true), + RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_BULK, 512, 0x58, true), + RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_BULK, 512, 0x68, true), RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_INT, 64, 0x04, false), RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_INT, 64, 0x05, false), RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_INT, 64, 0x06, false), -- cgit v1.2.3-59-g8ed1b From caf8fa1120c2fd9206cc1dfd58b8b55e0817238e Mon Sep 17 00:00:00 2001 From: Biju Das Date: Tue, 19 Mar 2024 10:53:54 +0000 Subject: usb: renesas_usbhs: Update usbhs pipe configuration for RZ/G2L family The RZ/G2L family SoCs has 10 pipe buffers compared to 16 pipe buffers on RZ/A2M. Update the pipe configuration for RZ/G2L family SoCs and use family SoC specific compatible to handle this difference. The pipe configuration of RZ/G2L is same as usbhsc_rzg2l_default_pipe[], so select the default pipe configuration for RZ/G2L SoCs by setting .has_new_pipe_configs to zero. Add SoC specific compatible to OF table to avoid ABI breakage with old DTB. To optimize memory usage the SoC specific compatible will be removed later. Based on the patch in BSP by Huy Nguyen Signed-off-by: Biju Das Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20240319105356.87287-5-biju.das.jz@bp.renesas.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/renesas_usbhs/common.c | 18 +++++++++++++++++- drivers/usb/renesas_usbhs/rza.h | 1 + drivers/usb/renesas_usbhs/rza2.c | 13 +++++++++++++ 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c index 177fa3144a47..b436927c2711 100644 --- a/drivers/usb/renesas_usbhs/common.c +++ b/drivers/usb/renesas_usbhs/common.c @@ -363,7 +363,7 @@ static void usbhsc_clk_disable_unprepare(struct usbhs_priv *priv) * platform default param */ -/* commonly used on old SH-Mobile SoCs */ +/* commonly used on old SH-Mobile and RZ/G2L family SoCs */ static struct renesas_usbhs_driver_pipe_config usbhsc_default_pipe[] = { RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_CONTROL, 64, 0x00, false), RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_ISOC, 1024, 0x08, true), @@ -565,6 +565,18 @@ static const struct of_device_id usbhs_of_match[] = { .compatible = "renesas,usbhs-r8a77995", .data = &usbhs_rcar_gen3_with_pll_plat_info, }, + { + .compatible = "renesas,usbhs-r9a07g043", + .data = &usbhs_rzg2l_plat_info, + }, + { + .compatible = "renesas,usbhs-r9a07g044", + .data = &usbhs_rzg2l_plat_info, + }, + { + .compatible = "renesas,usbhs-r9a07g054", + .data = &usbhs_rzg2l_plat_info, + }, { .compatible = "renesas,rcar-gen2-usbhs", .data = &usbhs_rcar_gen2_plat_info, @@ -581,6 +593,10 @@ static const struct of_device_id usbhs_of_match[] = { .compatible = "renesas,rza2-usbhs", .data = &usbhs_rza2_plat_info, }, + { + .compatible = "renesas,rzg2l-usbhs", + .data = &usbhs_rzg2l_plat_info, + }, { }, }; MODULE_DEVICE_TABLE(of, usbhs_of_match); diff --git a/drivers/usb/renesas_usbhs/rza.h b/drivers/usb/renesas_usbhs/rza.h index a29b75fef057..8b879aa34a20 100644 --- a/drivers/usb/renesas_usbhs/rza.h +++ b/drivers/usb/renesas_usbhs/rza.h @@ -3,3 +3,4 @@ extern const struct renesas_usbhs_platform_info usbhs_rza1_plat_info; extern const struct renesas_usbhs_platform_info usbhs_rza2_plat_info; +extern const struct renesas_usbhs_platform_info usbhs_rzg2l_plat_info; diff --git a/drivers/usb/renesas_usbhs/rza2.c b/drivers/usb/renesas_usbhs/rza2.c index f079817250bb..b83699eab373 100644 --- a/drivers/usb/renesas_usbhs/rza2.c +++ b/drivers/usb/renesas_usbhs/rza2.c @@ -71,3 +71,16 @@ const struct renesas_usbhs_platform_info usbhs_rza2_plat_info = { .has_new_pipe_configs = 1, }, }; + +const struct renesas_usbhs_platform_info usbhs_rzg2l_plat_info = { + .platform_callback = { + .hardware_init = usbhs_rza2_hardware_init, + .hardware_exit = usbhs_rza2_hardware_exit, + .power_ctrl = usbhs_rza2_power_ctrl, + .get_id = usbhs_get_id_as_gadget, + }, + .driver_param = { + .has_cnen = 1, + .cfifo_byte_addr = 1, + }, +}; -- cgit v1.2.3-59-g8ed1b From de9700f44d41d5ebdcbc0c5b5e1ffe7861eaffb1 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Tue, 19 Mar 2024 10:53:55 +0000 Subject: usb: renesas_usbhs: Remove trailing comma in the terminator entry for OF table Remove the trailing comma in the terminator entry for the OF table making code robust against (theoretical) misrebases or other similar things where the new entry goes _after_ the termination without the compiler noticing. Signed-off-by: Biju Das Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20240319105356.87287-6-biju.das.jz@bp.renesas.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/renesas_usbhs/common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c index b436927c2711..b6bef9081bf2 100644 --- a/drivers/usb/renesas_usbhs/common.c +++ b/drivers/usb/renesas_usbhs/common.c @@ -597,7 +597,7 @@ static const struct of_device_id usbhs_of_match[] = { .compatible = "renesas,rzg2l-usbhs", .data = &usbhs_rzg2l_plat_info, }, - { }, + { } }; MODULE_DEVICE_TABLE(of, usbhs_of_match); -- cgit v1.2.3-59-g8ed1b From 3bfe384f6f4f7433103ffcc36e7a7106f7e70c4e Mon Sep 17 00:00:00 2001 From: Biju Das Date: Tue, 19 Mar 2024 10:53:56 +0000 Subject: arm64: dts: renesas: r9a07g0{43,44,54}: Update RZ/G2L family compatible The number of pipe buffers on RZ/G2L family SoCs is 10, whereas on RZ/A2M it is 16. Replace 'renesas,rza2m-usbhs->renesas,rzg2l-usbhs' as family SoC compatible to handle this difference and use the SoC specific compatible in driver to avoid the ABI breakage with older DTB. Signed-off-by: Biju Das Reviewed-by: Geert Uytterhoeven Acked-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20240319105356.87287-7-biju.das.jz@bp.renesas.com Signed-off-by: Greg Kroah-Hartman --- arch/arm64/boot/dts/renesas/r9a07g043.dtsi | 2 +- arch/arm64/boot/dts/renesas/r9a07g044.dtsi | 2 +- arch/arm64/boot/dts/renesas/r9a07g054.dtsi | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm64/boot/dts/renesas/r9a07g043.dtsi b/arch/arm64/boot/dts/renesas/r9a07g043.dtsi index 8721f4c9fa0f..766c54b91acc 100644 --- a/arch/arm64/boot/dts/renesas/r9a07g043.dtsi +++ b/arch/arm64/boot/dts/renesas/r9a07g043.dtsi @@ -812,7 +812,7 @@ hsusb: usb@11c60000 { compatible = "renesas,usbhs-r9a07g043", - "renesas,rza2-usbhs"; + "renesas,rzg2l-usbhs"; reg = <0 0x11c60000 0 0x10000>; interrupts = , , diff --git a/arch/arm64/boot/dts/renesas/r9a07g044.dtsi b/arch/arm64/boot/dts/renesas/r9a07g044.dtsi index 9f00b75d2bd0..88634ae43287 100644 --- a/arch/arm64/boot/dts/renesas/r9a07g044.dtsi +++ b/arch/arm64/boot/dts/renesas/r9a07g044.dtsi @@ -1217,7 +1217,7 @@ hsusb: usb@11c60000 { compatible = "renesas,usbhs-r9a07g044", - "renesas,rza2-usbhs"; + "renesas,rzg2l-usbhs"; reg = <0 0x11c60000 0 0x10000>; interrupts = , , diff --git a/arch/arm64/boot/dts/renesas/r9a07g054.dtsi b/arch/arm64/boot/dts/renesas/r9a07g054.dtsi index 53d8905f367a..e89bfe4085f5 100644 --- a/arch/arm64/boot/dts/renesas/r9a07g054.dtsi +++ b/arch/arm64/boot/dts/renesas/r9a07g054.dtsi @@ -1225,7 +1225,7 @@ hsusb: usb@11c60000 { compatible = "renesas,usbhs-r9a07g054", - "renesas,rza2-usbhs"; + "renesas,rzg2l-usbhs"; reg = <0 0x11c60000 0 0x10000>; interrupts = , , -- cgit v1.2.3-59-g8ed1b From 43590333ca086070b302fb390bacec5c12c8a9b1 Mon Sep 17 00:00:00 2001 From: Xu Yang Date: Thu, 21 Mar 2024 16:14:39 +0800 Subject: usb: chipidea: ci_hdrc_imx: align usb wakeup clock name with dt-bindings The dt-bindings is going to use "usb_wakeup" as wakup clock name. This will align the change with dt-bindings. Acked-by: Peter Chen Signed-off-by: Xu Yang Link: https://lore.kernel.org/r/20240321081439.541799-11-xu.yang_2@nxp.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/chipidea/ci_hdrc_imx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c index ae9a6a17ec6e..a17b6d619305 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.c +++ b/drivers/usb/chipidea/ci_hdrc_imx.c @@ -212,7 +212,7 @@ static int imx_get_clks(struct device *dev) /* Get wakeup clock. Not all of the platforms need to * handle this clock. So make it optional. */ - data->clk_wakeup = devm_clk_get_optional(dev, "usb_wakeup_clk"); + data->clk_wakeup = devm_clk_get_optional(dev, "usb_wakeup"); if (IS_ERR(data->clk_wakeup)) ret = dev_err_probe(dev, PTR_ERR(data->clk_wakeup), "Failed to get wakeup clk\n"); -- cgit v1.2.3-59-g8ed1b From af1969a1f6b54f8a6e0ca1986f0e8836d2dcc0a6 Mon Sep 17 00:00:00 2001 From: Xu Yang Date: Thu, 21 Mar 2024 16:14:32 +0800 Subject: dt-bindings: usb: chipidea,usb2-imx: move imx parts to dedicated schema As more and more NXP i.MX chips come out, it becomes harder to maintain ci-hdrc-usb2.yaml if more stuffs like property restrictions are added to this file. This will separate i.MX parts out of ci-hdrc-usb2.yaml and add a new schema for NXP ChipIdea USB2 Controller, also add a common schema. 1. Copy common ci-hdrc-usb2.yaml properties to a new shared chipidea,usb2-common.yaml schema. 2. Move fsl,* compatible devices and imx spefific properties to dedicated binding file chipidea,usb2-imx.yaml. Reviewed-by: Rob Herring Signed-off-by: Xu Yang Link: https://lore.kernel.org/r/20240321081439.541799-4-xu.yang_2@nxp.com Signed-off-by: Greg Kroah-Hartman --- .../bindings/usb/chipidea,usb2-common.yaml | 200 ++++++++++++ .../devicetree/bindings/usb/chipidea,usb2-imx.yaml | 193 +++++++++++ .../devicetree/bindings/usb/ci-hdrc-usb2.yaml | 360 +-------------------- 3 files changed, 396 insertions(+), 357 deletions(-) create mode 100644 Documentation/devicetree/bindings/usb/chipidea,usb2-common.yaml create mode 100644 Documentation/devicetree/bindings/usb/chipidea,usb2-imx.yaml diff --git a/Documentation/devicetree/bindings/usb/chipidea,usb2-common.yaml b/Documentation/devicetree/bindings/usb/chipidea,usb2-common.yaml new file mode 100644 index 000000000000..d2a7d2ecf48a --- /dev/null +++ b/Documentation/devicetree/bindings/usb/chipidea,usb2-common.yaml @@ -0,0 +1,200 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/usb/chipidea,usb2-common.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: USB2 ChipIdea USB controller Common Properties + +maintainers: + - Xu Yang + +properties: + reg: + minItems: 1 + maxItems: 2 + + interrupts: + minItems: 1 + maxItems: 2 + + clocks: + minItems: 1 + maxItems: 3 + + clock-names: + minItems: 1 + maxItems: 3 + + dr_mode: true + + power-domains: + maxItems: 1 + + resets: + maxItems: 1 + + reset-names: + maxItems: 1 + + "#reset-cells": + const: 1 + + phy_type: true + + itc-setting: + description: + interrupt threshold control register control, the setting should be + aligned with ITC bits at register USBCMD. + $ref: /schemas/types.yaml#/definitions/uint32 + + ahb-burst-config: + description: + it is vendor dependent, the required value should be aligned with + AHBBRST at SBUSCFG, the range is from 0x0 to 0x7. This property is + used to change AHB burst configuration, check the chipidea spec for + meaning of each value. If this property is not existed, it will use + the reset value. + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0x0 + maximum: 0x7 + + tx-burst-size-dword: + description: + it is vendor dependent, the tx burst size in dword (4 bytes), This + register represents the maximum length of a the burst in 32-bit + words while moving data from system memory to the USB bus, the value + of this property will only take effect if property "ahb-burst-config" + is set to 0, if this property is missing the reset default of the + hardware implementation will be used. + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0x0 + maximum: 0x20 + + rx-burst-size-dword: + description: + it is vendor dependent, the rx burst size in dword (4 bytes), This + register represents the maximum length of a the burst in 32-bit words + while moving data from the USB bus to system memory, the value of + this property will only take effect if property "ahb-burst-config" + is set to 0, if this property is missing the reset default of the + hardware implementation will be used. + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0x0 + maximum: 0x20 + + extcon: + description: + Phandles to external connector devices. First phandle should point + to external connector, which provide "USB" cable events, the second + should point to external connector device, which provide "USB-HOST" + cable events. If one of the external connector devices is not + required, empty <0> phandle should be specified. + $ref: /schemas/types.yaml#/definitions/phandle-array + minItems: 1 + items: + - description: vbus extcon + - description: id extcon + + phy-clkgate-delay-us: + description: + The delay time (us) between putting the PHY into low power mode and + gating the PHY clock. + + non-zero-ttctrl-ttha: + description: + After setting this property, the value of register ttctrl.ttha + will be 0x7f; if not, the value will be 0x0, this is the default + value. It needs to be very carefully for setting this property, it + is recommended that consult with your IC engineer before setting + this value. On the most of chipidea platforms, the "usage_tt" flag + at RTL is 0, so this property only affects siTD. + + If this property is not set, the max packet size is 1023 bytes, and + if the total of packet size for previous transactions are more than + 256 bytes, it can't accept any transactions within this frame. The + use case is single transaction, but higher frame rate. + + If this property is set, the max packet size is 188 bytes, it can + handle more transactions than above case, it can accept transactions + until it considers the left room size within frame is less than 188 + bytes, software needs to make sure it does not send more than 90% + maximum_periodic_data_per_frame. The use case is multiple + transactions, but less frame rate. + type: boolean + + mux-controls: + description: + The mux control for toggling host/device output of this controller. + It's expected that a mux state of 0 indicates device mode and a mux + state of 1 indicates host mode. + maxItems: 1 + + mux-control-names: + const: usb_switch + + pinctrl-names: + description: + Names for optional pin modes in "default", "host", "device". + In case of HSIC-mode, "idle" and "active" pin modes are mandatory. + In this case, the "idle" state needs to pull down the data and + strobe pin and the "active" state needs to pull up the strobe pin. + oneOf: + - items: + - const: idle + - const: active + - items: + - const: default + - const: host + - const: device + - items: + - const: default + - enum: + - host + - device + - items: + - const: default + + pinctrl-0: + maxItems: 1 + + pinctrl-1: + maxItems: 1 + + phys: + maxItems: 1 + + phy-names: + const: usb-phy + + vbus-supply: + description: reference to the VBUS regulator. + + usb-phy: + description: phandle for the PHY device. Use "phys" instead. + maxItems: 1 + deprecated: true + + port: + description: + Any connector to the data bus of this controller should be modelled + using the OF graph bindings specified, if the "usb-role-switch" + property is used. + $ref: /schemas/graph.yaml#/properties/port + + reset-gpios: + maxItems: 1 + +dependencies: + port: [ usb-role-switch ] + mux-controls: [ mux-control-names ] + +required: + - reg + - interrupts + +allOf: + - $ref: usb-hcd.yaml# + - $ref: usb-drd.yaml# + +additionalProperties: true diff --git a/Documentation/devicetree/bindings/usb/chipidea,usb2-imx.yaml b/Documentation/devicetree/bindings/usb/chipidea,usb2-imx.yaml new file mode 100644 index 000000000000..cdbb224e9f68 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/chipidea,usb2-imx.yaml @@ -0,0 +1,193 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/usb/chipidea,usb2-imx.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NXP USB2 ChipIdea USB controller + +maintainers: + - Xu Yang + +properties: + compatible: + oneOf: + - enum: + - fsl,imx27-usb + - items: + - enum: + - fsl,imx23-usb + - fsl,imx25-usb + - fsl,imx28-usb + - fsl,imx35-usb + - fsl,imx50-usb + - fsl,imx51-usb + - fsl,imx53-usb + - fsl,imx6q-usb + - fsl,imx6sl-usb + - fsl,imx6sx-usb + - fsl,imx6ul-usb + - fsl,imx7d-usb + - fsl,vf610-usb + - const: fsl,imx27-usb + - items: + - enum: + - fsl,imx8dxl-usb + - fsl,imx8ulp-usb + - const: fsl,imx7ulp-usb + - const: fsl,imx6ul-usb + - items: + - enum: + - fsl,imx8mm-usb + - fsl,imx8mn-usb + - const: fsl,imx7d-usb + - const: fsl,imx27-usb + - items: + - enum: + - fsl,imx6sll-usb + - fsl,imx7ulp-usb + - const: fsl,imx6ul-usb + - const: fsl,imx27-usb + + clocks: + minItems: 1 + maxItems: 3 + + clock-names: + minItems: 1 + maxItems: 3 + + fsl,usbmisc: + description: + Phandler of non-core register device, with one argument that + indicate usb controller index + $ref: /schemas/types.yaml#/definitions/phandle-array + items: + - items: + - description: phandle to usbmisc node + - description: index of usb controller + + disable-over-current: + type: boolean + description: disable over current detect + + over-current-active-low: + type: boolean + description: over current signal polarity is active low + + over-current-active-high: + type: boolean + description: + Over current signal polarity is active high. It's recommended to + specify the over current polarity. + + power-active-high: + type: boolean + description: power signal polarity is active high + + external-vbus-divider: + type: boolean + description: enables off-chip resistor divider for Vbus + + samsung,picophy-pre-emp-curr-control: + description: + HS Transmitter Pre-Emphasis Current Control. This signal controls + the amount of current sourced to the USB_OTG*_DP and USB_OTG*_DN + pins after a J-to-K or K-to-J transition. The range is from 0x0 to + 0x3, the default value is 0x1. Details can refer to TXPREEMPAMPTUNE0 + bits of USBNC_n_PHY_CFG1. + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0x0 + maximum: 0x3 + + samsung,picophy-dc-vol-level-adjust: + description: + HS DC Voltage Level Adjustment. Adjust the high-speed transmitter DC + level voltage. The range is from 0x0 to 0xf, the default value is + 0x3. Details can refer to TXVREFTUNE0 bits of USBNC_n_PHY_CFG1. + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0x0 + maximum: 0xf + + fsl,picophy-rise-fall-time-adjust: + description: + HS Transmitter Rise/Fall Time Adjustment. Adjust the rise/fall times + of the high-speed transmitter waveform. It has no unit. The rise/fall + time will be increased or decreased by a certain percentage relative + to design default time. (0:-10%; 1:design default; 2:+15%; 3:+20%) + Details can refer to TXRISETUNE0 bit of USBNC_n_PHY_CFG1. + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 3 + default: 1 + + fsl,usbphy: + description: phandle of usb phy that connects to the port. Use "phys" instead. + $ref: /schemas/types.yaml#/definitions/phandle + deprecated: true + +required: + - compatible + +allOf: + - $ref: chipidea,usb2-common.yaml# + - if: + properties: + phy_type: + const: hsic + required: + - phy_type + then: + properties: + pinctrl-names: + items: + - const: idle + - const: active + +unevaluatedProperties: false + +examples: + - | + #include + #include + + usb@30b10000 { + compatible = "fsl,imx7d-usb", "fsl,imx27-usb"; + reg = <0x30b10000 0x200>; + interrupts = ; + clocks = <&clks IMX7D_USB_CTRL_CLK>; + fsl,usbphy = <&usbphynop1>; + fsl,usbmisc = <&usbmisc1 0>; + phy-clkgate-delay-us = <400>; + }; + + # Example for HSIC: + - | + #include + #include + + usb@2184400 { + compatible = "fsl,imx6q-usb", "fsl,imx27-usb"; + reg = <0x02184400 0x200>; + interrupts = <0 41 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks IMX6QDL_CLK_USBOH3>; + fsl,usbphy = <&usbphynop1>; + fsl,usbmisc = <&usbmisc 2>; + phy_type = "hsic"; + dr_mode = "host"; + ahb-burst-config = <0x0>; + tx-burst-size-dword = <0x10>; + rx-burst-size-dword = <0x10>; + pinctrl-names = "idle", "active"; + pinctrl-0 = <&pinctrl_usbh2_idle>; + pinctrl-1 = <&pinctrl_usbh2_active>; + #address-cells = <1>; + #size-cells = <0>; + + ethernet@1 { + compatible = "usb424,9730"; + reg = <1>; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.yaml b/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.yaml index 3b56e0edb1c6..cc5787a8cfa3 100644 --- a/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.yaml +++ b/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.yaml @@ -15,7 +15,6 @@ properties: oneOf: - enum: - chipidea,usb2 - - fsl,imx27-usb - lsi,zevio-usb - nuvoton,npcm750-udc - nvidia,tegra20-ehci @@ -31,40 +30,6 @@ properties: - nvidia,tegra124-ehci - nvidia,tegra210-ehci - const: nvidia,tegra30-ehci - - items: - - enum: - - fsl,imx23-usb - - fsl,imx25-usb - - fsl,imx28-usb - - fsl,imx35-usb - - fsl,imx50-usb - - fsl,imx51-usb - - fsl,imx53-usb - - fsl,imx6q-usb - - fsl,imx6sl-usb - - fsl,imx6sx-usb - - fsl,imx6ul-usb - - fsl,imx7d-usb - - fsl,vf610-usb - - const: fsl,imx27-usb - - items: - - enum: - - fsl,imx8dxl-usb - - fsl,imx8ulp-usb - - const: fsl,imx7ulp-usb - - const: fsl,imx6ul-usb - - items: - - enum: - - fsl,imx8mm-usb - - fsl,imx8mn-usb - - const: fsl,imx7d-usb - - const: fsl,imx27-usb - - items: - - enum: - - fsl,imx6sll-usb - - fsl,imx7ulp-usb - - const: fsl,imx6ul-usb - - const: fsl,imx27-usb - items: - const: xlnx,zynq-usb-2.20a - const: chipidea,usb2 @@ -73,163 +38,18 @@ properties: - nuvoton,npcm845-udc - const: nuvoton,npcm750-udc - reg: - minItems: 1 - maxItems: 2 - - interrupts: - minItems: 1 - maxItems: 2 - clocks: minItems: 1 - maxItems: 3 + maxItems: 2 clock-names: minItems: 1 - maxItems: 3 - - dr_mode: true - - power-domains: - maxItems: 1 - - resets: - maxItems: 1 - - reset-names: - maxItems: 1 - - "#reset-cells": - const: 1 - - phy_type: true - - itc-setting: - description: - interrupt threshold control register control, the setting should be - aligned with ITC bits at register USBCMD. - $ref: /schemas/types.yaml#/definitions/uint32 - - ahb-burst-config: - description: - it is vendor dependent, the required value should be aligned with - AHBBRST at SBUSCFG, the range is from 0x0 to 0x7. This property is - used to change AHB burst configuration, check the chipidea spec for - meaning of each value. If this property is not existed, it will use - the reset value. - $ref: /schemas/types.yaml#/definitions/uint32 - minimum: 0x0 - maximum: 0x7 - - tx-burst-size-dword: - description: - it is vendor dependent, the tx burst size in dword (4 bytes), This - register represents the maximum length of a the burst in 32-bit - words while moving data from system memory to the USB bus, the value - of this property will only take effect if property "ahb-burst-config" - is set to 0, if this property is missing the reset default of the - hardware implementation will be used. - $ref: /schemas/types.yaml#/definitions/uint32 - minimum: 0x0 - maximum: 0x20 - - rx-burst-size-dword: - description: - it is vendor dependent, the rx burst size in dword (4 bytes), This - register represents the maximum length of a the burst in 32-bit words - while moving data from the USB bus to system memory, the value of - this property will only take effect if property "ahb-burst-config" - is set to 0, if this property is missing the reset default of the - hardware implementation will be used. - $ref: /schemas/types.yaml#/definitions/uint32 - minimum: 0x0 - maximum: 0x20 - - extcon: - description: - Phandles to external connector devices. First phandle should point - to external connector, which provide "USB" cable events, the second - should point to external connector device, which provide "USB-HOST" - cable events. If one of the external connector devices is not - required, empty <0> phandle should be specified. - $ref: /schemas/types.yaml#/definitions/phandle-array - minItems: 1 - items: - - description: vbus extcon - - description: id extcon - - phy-clkgate-delay-us: - description: - The delay time (us) between putting the PHY into low power mode and - gating the PHY clock. - - non-zero-ttctrl-ttha: - description: - After setting this property, the value of register ttctrl.ttha - will be 0x7f; if not, the value will be 0x0, this is the default - value. It needs to be very carefully for setting this property, it - is recommended that consult with your IC engineer before setting - this value. On the most of chipidea platforms, the "usage_tt" flag - at RTL is 0, so this property only affects siTD. - - If this property is not set, the max packet size is 1023 bytes, and - if the total of packet size for previous transactions are more than - 256 bytes, it can't accept any transactions within this frame. The - use case is single transaction, but higher frame rate. - - If this property is set, the max packet size is 188 bytes, it can - handle more transactions than above case, it can accept transactions - until it considers the left room size within frame is less than 188 - bytes, software needs to make sure it does not send more than 90% - maximum_periodic_data_per_frame. The use case is multiple - transactions, but less frame rate. - type: boolean - - mux-controls: - description: - The mux control for toggling host/device output of this controller. - It's expected that a mux state of 0 indicates device mode and a mux - state of 1 indicates host mode. - maxItems: 1 - - mux-control-names: - const: usb_switch + maxItems: 2 operating-points-v2: description: A phandle to the OPP table containing the performance states. $ref: /schemas/types.yaml#/definitions/phandle - pinctrl-names: - description: - Names for optional pin modes in "default", "host", "device". - In case of HSIC-mode, "idle" and "active" pin modes are mandatory. - In this case, the "idle" state needs to pull down the data and - strobe pin and the "active" state needs to pull up the strobe pin. - oneOf: - - items: - - const: idle - - const: active - - items: - - const: default - - enum: - - host - - device - - items: - - const: default - - pinctrl-0: - maxItems: 1 - - pinctrl-1: - maxItems: 1 - - phys: - maxItems: 1 - - phy-names: - const: usb-phy - phy-select: description: Phandler of TCSR node with two argument that indicate register @@ -240,87 +60,6 @@ properties: - description: register offset - description: phy index - vbus-supply: - description: reference to the VBUS regulator. - - fsl,usbmisc: - description: - Phandler of non-core register device, with one argument that - indicate usb controller index - $ref: /schemas/types.yaml#/definitions/phandle-array - items: - - items: - - description: phandle to usbmisc node - - description: index of usb controller - - fsl,anatop: - description: phandle for the anatop node. - $ref: /schemas/types.yaml#/definitions/phandle - - disable-over-current: - type: boolean - description: disable over current detect - - over-current-active-low: - type: boolean - description: over current signal polarity is active low - - over-current-active-high: - type: boolean - description: - Over current signal polarity is active high. It's recommended to - specify the over current polarity. - - power-active-high: - type: boolean - description: power signal polarity is active high - - external-vbus-divider: - type: boolean - description: enables off-chip resistor divider for Vbus - - samsung,picophy-pre-emp-curr-control: - description: - HS Transmitter Pre-Emphasis Current Control. This signal controls - the amount of current sourced to the USB_OTG*_DP and USB_OTG*_DN - pins after a J-to-K or K-to-J transition. The range is from 0x0 to - 0x3, the default value is 0x1. Details can refer to TXPREEMPAMPTUNE0 - bits of USBNC_n_PHY_CFG1. - $ref: /schemas/types.yaml#/definitions/uint32 - minimum: 0x0 - maximum: 0x3 - - samsung,picophy-dc-vol-level-adjust: - description: - HS DC Voltage Level Adjustment. Adjust the high-speed transmitter DC - level voltage. The range is from 0x0 to 0xf, the default value is - 0x3. Details can refer to TXVREFTUNE0 bits of USBNC_n_PHY_CFG1. - $ref: /schemas/types.yaml#/definitions/uint32 - minimum: 0x0 - maximum: 0xf - - fsl,picophy-rise-fall-time-adjust: - description: - HS Transmitter Rise/Fall Time Adjustment. Adjust the rise/fall times - of the high-speed transmitter waveform. It has no unit. The rise/fall - time will be increased or decreased by a certain percentage relative - to design default time. (0:-10%; 1:design default; 2:+15%; 3:+20%) - Details can refer to TXRISETUNE0 bit of USBNC_n_PHY_CFG1. - $ref: /schemas/types.yaml#/definitions/uint32 - minimum: 0 - maximum: 3 - default: 1 - - usb-phy: - description: phandle for the PHY device. Use "phys" instead. - maxItems: 1 - deprecated: true - - fsl,usbphy: - description: phandle of usb phy that connects to the port. Use "phys" instead. - $ref: /schemas/types.yaml#/definitions/phandle - deprecated: true - nvidia,phy: description: phandle of usb phy that connects to the port. Use "phys" instead. $ref: /schemas/types.yaml#/definitions/phandle @@ -331,16 +70,6 @@ properties: type: boolean deprecated: true - port: - description: - Any connector to the data bus of this controller should be modelled - using the OF graph bindings specified, if the "usb-role-switch" - property is used. - $ref: /schemas/graph.yaml#/properties/port - - reset-gpios: - maxItems: 1 - ulpi: type: object additionalProperties: false @@ -350,67 +79,13 @@ properties: type: object $ref: /schemas/phy/qcom,usb-hs-phy.yaml -dependencies: - port: [ usb-role-switch ] - mux-controls: [ mux-control-names ] - required: - compatible - - reg - - interrupts allOf: + - $ref: chipidea,usb2-common.yaml# - $ref: usb-hcd.yaml# - $ref: usb-drd.yaml# - - if: - properties: - phy_type: - const: hsic - required: - - phy_type - then: - properties: - pinctrl-names: - items: - - const: idle - - const: active - else: - properties: - pinctrl-names: - minItems: 1 - maxItems: 2 - oneOf: - - items: - - const: default - - enum: - - host - - device - - items: - - const: default - - if: - properties: - compatible: - contains: - enum: - - chipidea,usb2 - - lsi,zevio-usb - - nuvoton,npcm750-udc - - nvidia,tegra20-udc - - nvidia,tegra30-udc - - nvidia,tegra114-udc - - nvidia,tegra124-udc - - qcom,ci-hdrc - - xlnx,zynq-usb-2.20a - then: - properties: - fsl,usbmisc: false - disable-over-current: false - over-current-active-low: false - over-current-active-high: false - power-active-high: false - external-vbus-divider: false - samsung,picophy-pre-emp-curr-control: false - samsung,picophy-dc-vol-level-adjust: false unevaluatedProperties: false @@ -438,33 +113,4 @@ examples: mux-control-names = "usb_switch"; }; - # Example for HSIC: - - | - #include - #include - - usb@2184400 { - compatible = "fsl,imx6q-usb", "fsl,imx27-usb"; - reg = <0x02184400 0x200>; - interrupts = <0 41 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&clks IMX6QDL_CLK_USBOH3>; - fsl,usbphy = <&usbphynop1>; - fsl,usbmisc = <&usbmisc 2>; - phy_type = "hsic"; - dr_mode = "host"; - ahb-burst-config = <0x0>; - tx-burst-size-dword = <0x10>; - rx-burst-size-dword = <0x10>; - pinctrl-names = "idle", "active"; - pinctrl-0 = <&pinctrl_usbh2_idle>; - pinctrl-1 = <&pinctrl_usbh2_active>; - #address-cells = <1>; - #size-cells = <0>; - - ethernet@1 { - compatible = "usb424,9730"; - reg = <1>; - }; - }; - ... -- cgit v1.2.3-59-g8ed1b From 089fa715f599b30581ee7d0e3990cf0a37f9cbcb Mon Sep 17 00:00:00 2001 From: Xu Yang Date: Thu, 21 Mar 2024 16:14:33 +0800 Subject: dt-bindings: usb: ci-hdrc-usb2-imx: add restrictions for reg, interrupts, clock and clock-names properties Add restrictions for reg, interrupts, clock and clock-names properties for imx Socs. Reviewed-by: Rob Herring Signed-off-by: Xu Yang Link: https://lore.kernel.org/r/20240321081439.541799-5-xu.yang_2@nxp.com Signed-off-by: Greg Kroah-Hartman --- .../devicetree/bindings/usb/chipidea,usb2-imx.yaml | 76 ++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/Documentation/devicetree/bindings/usb/chipidea,usb2-imx.yaml b/Documentation/devicetree/bindings/usb/chipidea,usb2-imx.yaml index cdbb224e9f68..e2eb60eaf6fe 100644 --- a/Documentation/devicetree/bindings/usb/chipidea,usb2-imx.yaml +++ b/Documentation/devicetree/bindings/usb/chipidea,usb2-imx.yaml @@ -49,6 +49,12 @@ properties: - const: fsl,imx6ul-usb - const: fsl,imx27-usb + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + clocks: minItems: 1 maxItems: 3 @@ -144,6 +150,76 @@ allOf: - const: idle - const: active + # imx27 Soc needs three clocks + - if: + properties: + compatible: + const: fsl,imx27-usb + then: + properties: + clocks: + minItems: 3 + clock-names: + items: + - const: ipg + - const: ahb + - const: per + + # imx25 and imx35 Soc need three clocks + - if: + properties: + compatible: + contains: + enum: + - fsl,imx25-usb + - fsl,imx35-usb + then: + properties: + clocks: + minItems: 3 + clock-names: + items: + - const: ipg + - const: ahb + - const: per + + # imx7d Soc need one clock + - if: + properties: + compatible: + items: + - const: fsl,imx7d-usb + - const: fsl,imx27-usb + then: + properties: + clocks: + maxItems: 1 + clock-names: false + + # other Soc need one clock + - if: + properties: + compatible: + contains: + enum: + - fsl,imx23-usb + - fsl,imx28-usb + - fsl,imx50-usb + - fsl,imx51-usb + - fsl,imx53-usb + - fsl,imx6q-usb + - fsl,imx6sl-usb + - fsl,imx6sx-usb + - fsl,imx6ul-usb + - fsl,imx8mm-usb + - fsl,imx8mn-usb + - fsl,vf610-usb + then: + properties: + clocks: + maxItems: 1 + clock-names: false + unevaluatedProperties: false examples: -- cgit v1.2.3-59-g8ed1b From 47870badf33a59994e73b70b1f0464d7b0945f2e Mon Sep 17 00:00:00 2001 From: Xu Yang Date: Thu, 21 Mar 2024 16:14:34 +0800 Subject: dt-bindings: usb: ci-hdrc-usb2-imx: add compatible and clock-names restriction for imx93 The i.MX93 needs a wakup clock to work properly. This will add compatible and restriction for i.MX93 platform. Reviewed-by: Rob Herring Signed-off-by: Xu Yang Link: https://lore.kernel.org/r/20240321081439.541799-6-xu.yang_2@nxp.com Signed-off-by: Greg Kroah-Hartman --- .../devicetree/bindings/usb/chipidea,usb2-imx.yaml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Documentation/devicetree/bindings/usb/chipidea,usb2-imx.yaml b/Documentation/devicetree/bindings/usb/chipidea,usb2-imx.yaml index e2eb60eaf6fe..8f6136f5d72e 100644 --- a/Documentation/devicetree/bindings/usb/chipidea,usb2-imx.yaml +++ b/Documentation/devicetree/bindings/usb/chipidea,usb2-imx.yaml @@ -40,6 +40,7 @@ properties: - enum: - fsl,imx8mm-usb - fsl,imx8mn-usb + - fsl,imx93-usb - const: fsl,imx7d-usb - const: fsl,imx27-usb - items: @@ -183,6 +184,23 @@ allOf: - const: ahb - const: per + # imx93 Soc needs two clocks + - if: + properties: + compatible: + contains: + enum: + - fsl,imx93-usb + then: + properties: + clocks: + minItems: 2 + maxItems: 2 + clock-names: + items: + - const: usb_ctrl_root + - const: usb_wakeup + # imx7d Soc need one clock - if: properties: -- cgit v1.2.3-59-g8ed1b From ec1848cd5df426f57a7f6a8a6b95b69259c52cfc Mon Sep 17 00:00:00 2001 From: Javier Carrasco Date: Mon, 25 Mar 2024 10:15:11 +0100 Subject: usb: misc: onboard_hub: use device supply names The current implementation uses generic names for the power supplies, which conflicts with proper name definitions in the device bindings. Add a per-device property to include real supply names and keep generic names for existing devices to keep backward compatibility. Acked-by: Matthias Kaehlcke Signed-off-by: Javier Carrasco Link: https://lore.kernel.org/r/20240325-onboard_xvf3500-v8-1-29e3f9222922@wolfvision.net Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/onboard_usb_hub.c | 49 ++++++++++++++++++++------------------ drivers/usb/misc/onboard_usb_hub.h | 13 ++++++++++ 2 files changed, 39 insertions(+), 23 deletions(-) diff --git a/drivers/usb/misc/onboard_usb_hub.c b/drivers/usb/misc/onboard_usb_hub.c index c6101ed2d9d4..5308c54aaabe 100644 --- a/drivers/usb/misc/onboard_usb_hub.c +++ b/drivers/usb/misc/onboard_usb_hub.c @@ -29,17 +29,6 @@ #include "onboard_usb_hub.h" -/* - * Use generic names, as the actual names might differ between hubs. If a new - * hub requires more than the currently supported supplies, add a new one here. - */ -static const char * const supply_names[] = { - "vdd", - "vdd2", -}; - -#define MAX_SUPPLIES ARRAY_SIZE(supply_names) - static void onboard_hub_attach_usb_driver(struct work_struct *work); static struct usb_device_driver onboard_hub_usbdev_driver; @@ -65,6 +54,29 @@ struct onboard_hub { struct clk *clk; }; +static int onboard_hub_get_regulators(struct onboard_hub *hub) +{ + const char * const *supply_names = hub->pdata->supply_names; + unsigned int num_supplies = hub->pdata->num_supplies; + struct device *dev = hub->dev; + unsigned int i; + int err; + + if (num_supplies > MAX_SUPPLIES) + return dev_err_probe(dev, -EINVAL, "max %d supplies supported!\n", + MAX_SUPPLIES); + + for (i = 0; i < num_supplies; i++) + hub->supplies[i].supply = supply_names[i]; + + err = devm_regulator_bulk_get(dev, num_supplies, hub->supplies); + if (err) + dev_err(dev, "Failed to get regulator supplies: %pe\n", + ERR_PTR(err)); + + return err; +} + static int onboard_hub_power_on(struct onboard_hub *hub) { int err; @@ -253,7 +265,6 @@ static int onboard_hub_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct onboard_hub *hub; - unsigned int i; int err; hub = devm_kzalloc(dev, sizeof(*hub), GFP_KERNEL); @@ -264,18 +275,11 @@ static int onboard_hub_probe(struct platform_device *pdev) if (!hub->pdata) return -EINVAL; - if (hub->pdata->num_supplies > MAX_SUPPLIES) - return dev_err_probe(dev, -EINVAL, "max %zu supplies supported!\n", - MAX_SUPPLIES); - - for (i = 0; i < hub->pdata->num_supplies; i++) - hub->supplies[i].supply = supply_names[i]; + hub->dev = dev; - err = devm_regulator_bulk_get(dev, hub->pdata->num_supplies, hub->supplies); - if (err) { - dev_err(dev, "Failed to get regulator supplies: %pe\n", ERR_PTR(err)); + err = onboard_hub_get_regulators(hub); + if (err) return err; - } hub->clk = devm_clk_get_optional(dev, NULL); if (IS_ERR(hub->clk)) @@ -286,7 +290,6 @@ static int onboard_hub_probe(struct platform_device *pdev) if (IS_ERR(hub->reset_gpio)) return dev_err_probe(dev, PTR_ERR(hub->reset_gpio), "failed to get reset GPIO\n"); - hub->dev = dev; mutex_init(&hub->lock); INIT_LIST_HEAD(&hub->udev_list); diff --git a/drivers/usb/misc/onboard_usb_hub.h b/drivers/usb/misc/onboard_usb_hub.h index b4b15d45f84d..edbca8aa6ea0 100644 --- a/drivers/usb/misc/onboard_usb_hub.h +++ b/drivers/usb/misc/onboard_usb_hub.h @@ -6,59 +6,72 @@ #ifndef _USB_MISC_ONBOARD_USB_HUB_H #define _USB_MISC_ONBOARD_USB_HUB_H +#define MAX_SUPPLIES 2 + struct onboard_hub_pdata { unsigned long reset_us; /* reset pulse width in us */ unsigned int num_supplies; /* number of supplies */ + const char * const supply_names[MAX_SUPPLIES]; }; static const struct onboard_hub_pdata microchip_usb424_data = { .reset_us = 1, .num_supplies = 1, + .supply_names = { "vdd" }, }; static const struct onboard_hub_pdata microchip_usb5744_data = { .reset_us = 0, .num_supplies = 2, + .supply_names = { "vdd", "vdd2" }, }; static const struct onboard_hub_pdata realtek_rts5411_data = { .reset_us = 0, .num_supplies = 1, + .supply_names = { "vdd" }, }; static const struct onboard_hub_pdata ti_tusb8020b_data = { .reset_us = 3000, .num_supplies = 1, + .supply_names = { "vdd" }, }; static const struct onboard_hub_pdata ti_tusb8041_data = { .reset_us = 3000, .num_supplies = 1, + .supply_names = { "vdd" }, }; static const struct onboard_hub_pdata cypress_hx3_data = { .reset_us = 10000, .num_supplies = 2, + .supply_names = { "vdd", "vdd2" }, }; static const struct onboard_hub_pdata cypress_hx2vl_data = { .reset_us = 1, .num_supplies = 1, + .supply_names = { "vdd" }, }; static const struct onboard_hub_pdata genesys_gl850g_data = { .reset_us = 3, .num_supplies = 1, + .supply_names = { "vdd" }, }; static const struct onboard_hub_pdata genesys_gl852g_data = { .reset_us = 50, .num_supplies = 1, + .supply_names = { "vdd" }, }; static const struct onboard_hub_pdata vialab_vl817_data = { .reset_us = 10, .num_supplies = 1, + .supply_names = { "vdd" }, }; static const struct of_device_id onboard_hub_match[] = { -- cgit v1.2.3-59-g8ed1b From 31e7f6c015d9eb35e77ae9868801c53ab0ff19ac Mon Sep 17 00:00:00 2001 From: Javier Carrasco Date: Mon, 25 Mar 2024 10:15:12 +0100 Subject: usb: misc: onboard_hub: rename to onboard_dev This patch prepares onboad_hub to support non-hub devices by renaming the driver files and their content, the headers and their references. The comments and descriptions have been slightly modified to keep coherence and account for the specific cases that only affect onboard hubs (e.g. peer-hub). The "hub" variables in functions where "dev" (and similar names) variables already exist have been renamed to onboard_dev for clarity, which adds a few lines in cases where more than 80 characters are used. No new functionality has been added. Acked-by: Matthias Kaehlcke Signed-off-by: Javier Carrasco Link: https://lore.kernel.org/r/20240325-onboard_xvf3500-v8-2-29e3f9222922@wolfvision.net Signed-off-by: Greg Kroah-Hartman --- .../ABI/testing/sysfs-bus-platform-onboard-usb-dev | 9 + .../ABI/testing/sysfs-bus-platform-onboard-usb-hub | 8 - MAINTAINERS | 4 +- drivers/usb/core/Makefile | 4 +- drivers/usb/core/hub.c | 8 +- drivers/usb/core/hub.h | 2 +- drivers/usb/misc/Kconfig | 16 +- drivers/usb/misc/Makefile | 2 +- drivers/usb/misc/onboard_usb_dev.c | 521 +++++++++++++++++++++ drivers/usb/misc/onboard_usb_dev.h | 103 ++++ drivers/usb/misc/onboard_usb_dev_pdevs.c | 144 ++++++ drivers/usb/misc/onboard_usb_hub.c | 506 -------------------- drivers/usb/misc/onboard_usb_hub.h | 103 ---- drivers/usb/misc/onboard_usb_hub_pdevs.c | 143 ------ include/linux/usb/onboard_dev.h | 18 + include/linux/usb/onboard_hub.h | 18 - 16 files changed, 813 insertions(+), 796 deletions(-) create mode 100644 Documentation/ABI/testing/sysfs-bus-platform-onboard-usb-dev delete mode 100644 Documentation/ABI/testing/sysfs-bus-platform-onboard-usb-hub create mode 100644 drivers/usb/misc/onboard_usb_dev.c create mode 100644 drivers/usb/misc/onboard_usb_dev.h create mode 100644 drivers/usb/misc/onboard_usb_dev_pdevs.c delete mode 100644 drivers/usb/misc/onboard_usb_hub.c delete mode 100644 drivers/usb/misc/onboard_usb_hub.h delete mode 100644 drivers/usb/misc/onboard_usb_hub_pdevs.c create mode 100644 include/linux/usb/onboard_dev.h delete mode 100644 include/linux/usb/onboard_hub.h diff --git a/Documentation/ABI/testing/sysfs-bus-platform-onboard-usb-dev b/Documentation/ABI/testing/sysfs-bus-platform-onboard-usb-dev new file mode 100644 index 000000000000..b06a48c3c85a --- /dev/null +++ b/Documentation/ABI/testing/sysfs-bus-platform-onboard-usb-dev @@ -0,0 +1,9 @@ +What: /sys/bus/platform/devices//always_powered_in_suspend +Date: June 2022 +KernelVersion: 5.20 +Contact: Matthias Kaehlcke + linux-usb@vger.kernel.org +Description: + (RW) Controls whether the USB hub remains always powered + during system suspend or not. This attribute is not + available for non-hub devices. diff --git a/Documentation/ABI/testing/sysfs-bus-platform-onboard-usb-hub b/Documentation/ABI/testing/sysfs-bus-platform-onboard-usb-hub deleted file mode 100644 index 42deb0552065..000000000000 --- a/Documentation/ABI/testing/sysfs-bus-platform-onboard-usb-hub +++ /dev/null @@ -1,8 +0,0 @@ -What: /sys/bus/platform/devices//always_powered_in_suspend -Date: June 2022 -KernelVersion: 5.20 -Contact: Matthias Kaehlcke - linux-usb@vger.kernel.org -Description: - (RW) Controls whether the USB hub remains always powered - during system suspend or not. \ No newline at end of file diff --git a/MAINTAINERS b/MAINTAINERS index aa3b947fb080..48cbcab391c9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -16439,8 +16439,8 @@ ONBOARD USB HUB DRIVER M: Matthias Kaehlcke L: linux-usb@vger.kernel.org S: Maintained -F: Documentation/ABI/testing/sysfs-bus-platform-onboard-usb-hub -F: drivers/usb/misc/onboard_usb_hub.c +F: Documentation/ABI/testing/sysfs-bus-platform-onboard-usb-dev +F: drivers/usb/misc/onboard_usb_dev.c ONENAND FLASH DRIVER M: Kyungmin Park diff --git a/drivers/usb/core/Makefile b/drivers/usb/core/Makefile index 7d338e9c0657..ac006abd13b3 100644 --- a/drivers/usb/core/Makefile +++ b/drivers/usb/core/Makefile @@ -12,8 +12,8 @@ usbcore-$(CONFIG_OF) += of.o usbcore-$(CONFIG_USB_PCI) += hcd-pci.o usbcore-$(CONFIG_ACPI) += usb-acpi.o -ifdef CONFIG_USB_ONBOARD_HUB -usbcore-y += ../misc/onboard_usb_hub_pdevs.o +ifdef CONFIG_USB_ONBOARD_DEV +usbcore-y += ../misc/onboard_usb_dev_pdevs.o endif obj-$(CONFIG_USB) += usbcore.o diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 3ee8455585b6..1dcae5db85b2 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include #include @@ -1805,7 +1805,7 @@ static void hub_disconnect(struct usb_interface *intf) if (hub->quirk_disable_autosuspend) usb_autopm_put_interface(intf); - onboard_hub_destroy_pdevs(&hub->onboard_hub_devs); + onboard_dev_destroy_pdevs(&hub->onboard_devs); kref_put(&hub->kref, hub_release); } @@ -1924,7 +1924,7 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id) INIT_DELAYED_WORK(&hub->leds, led_work); INIT_DELAYED_WORK(&hub->init_work, NULL); INIT_WORK(&hub->events, hub_event); - INIT_LIST_HEAD(&hub->onboard_hub_devs); + INIT_LIST_HEAD(&hub->onboard_devs); spin_lock_init(&hub->irq_urb_lock); timer_setup(&hub->irq_urb_retry, hub_retry_irq_urb, 0); usb_get_intf(intf); @@ -1954,7 +1954,7 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id) } if (hub_configure(hub, &desc->endpoint[0].desc) >= 0) { - onboard_hub_create_pdevs(hdev, &hub->onboard_hub_devs); + onboard_dev_create_pdevs(hdev, &hub->onboard_devs); return 0; } diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h index 43ce21c96a51..3820703b11d8 100644 --- a/drivers/usb/core/hub.h +++ b/drivers/usb/core/hub.h @@ -74,7 +74,7 @@ struct usb_hub { spinlock_t irq_urb_lock; struct timer_list irq_urb_retry; struct usb_port **ports; - struct list_head onboard_hub_devs; + struct list_head onboard_devs; }; /** diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig index c510af7baa0d..50b86d531701 100644 --- a/drivers/usb/misc/Kconfig +++ b/drivers/usb/misc/Kconfig @@ -316,18 +316,18 @@ config BRCM_USB_PINMAP signals, which are typically on dedicated pins on the chip, to any gpio. -config USB_ONBOARD_HUB - tristate "Onboard USB hub support" +config USB_ONBOARD_DEV + tristate "Onboard USB device support" depends on OF help - Say Y here if you want to support discrete onboard USB hubs that - don't require an additional control bus for initialization, but - need some non-trivial form of initialization, such as enabling a - power regulator. An example for such a hub is the Realtek - RTS5411. + Say Y here if you want to support discrete onboard USB devices + that don't require an additional control bus for initialization, + but need some non-trivial form of initialization, such as + enabling a power regulator. An example for such device is the + Realtek RTS5411 hub. This driver can be used as a module but its state (module vs builtin) must match the state of the USB subsystem. Enabling this config will enable the driver and it will automatically match the state of the USB subsystem. If this driver is a - module it will be called onboard_usb_hub. + module it will be called onboard_usb_dev. diff --git a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile index 0bc732bcb162..0cd5bc8f52fe 100644 --- a/drivers/usb/misc/Makefile +++ b/drivers/usb/misc/Makefile @@ -33,4 +33,4 @@ obj-$(CONFIG_USB_CHAOSKEY) += chaoskey.o obj-$(CONFIG_USB_SISUSBVGA) += sisusbvga/ obj-$(CONFIG_USB_LINK_LAYER_TEST) += lvstest.o obj-$(CONFIG_BRCM_USB_PINMAP) += brcmstb-usb-pinmap.o -obj-$(CONFIG_USB_ONBOARD_HUB) += onboard_usb_hub.o +obj-$(CONFIG_USB_ONBOARD_DEV) += onboard_usb_dev.o diff --git a/drivers/usb/misc/onboard_usb_dev.c b/drivers/usb/misc/onboard_usb_dev.c new file mode 100644 index 000000000000..6aee43896216 --- /dev/null +++ b/drivers/usb/misc/onboard_usb_dev.c @@ -0,0 +1,521 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Driver for onboard USB devices + * + * Copyright (c) 2022, Google LLC + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "onboard_usb_dev.h" + +static void onboard_dev_attach_usb_driver(struct work_struct *work); + +static struct usb_device_driver onboard_dev_usbdev_driver; +static DECLARE_WORK(attach_usb_driver_work, onboard_dev_attach_usb_driver); + +/************************** Platform driver **************************/ + +struct usbdev_node { + struct usb_device *udev; + struct list_head list; +}; + +struct onboard_dev { + struct regulator_bulk_data supplies[MAX_SUPPLIES]; + struct device *dev; + const struct onboard_dev_pdata *pdata; + struct gpio_desc *reset_gpio; + bool always_powered_in_suspend; + bool is_powered_on; + bool going_away; + struct list_head udev_list; + struct mutex lock; + struct clk *clk; +}; + +static int onboard_dev_get_regulators(struct onboard_dev *onboard_dev) +{ + const char * const *supply_names = onboard_dev->pdata->supply_names; + unsigned int num_supplies = onboard_dev->pdata->num_supplies; + struct device *dev = onboard_dev->dev; + unsigned int i; + int err; + + if (num_supplies > MAX_SUPPLIES) + return dev_err_probe(dev, -EINVAL, "max %d supplies supported!\n", + MAX_SUPPLIES); + + for (i = 0; i < num_supplies; i++) + onboard_dev->supplies[i].supply = supply_names[i]; + + err = devm_regulator_bulk_get(dev, num_supplies, onboard_dev->supplies); + if (err) + dev_err(dev, "Failed to get regulator supplies: %pe\n", + ERR_PTR(err)); + + return err; +} + +static int onboard_dev_power_on(struct onboard_dev *onboard_dev) +{ + int err; + + err = clk_prepare_enable(onboard_dev->clk); + if (err) { + dev_err(onboard_dev->dev, "failed to enable clock: %pe\n", + ERR_PTR(err)); + return err; + } + + err = regulator_bulk_enable(onboard_dev->pdata->num_supplies, + onboard_dev->supplies); + if (err) { + dev_err(onboard_dev->dev, "failed to enable supplies: %pe\n", + ERR_PTR(err)); + return err; + } + + fsleep(onboard_dev->pdata->reset_us); + gpiod_set_value_cansleep(onboard_dev->reset_gpio, 0); + + onboard_dev->is_powered_on = true; + + return 0; +} + +static int onboard_dev_power_off(struct onboard_dev *onboard_dev) +{ + int err; + + gpiod_set_value_cansleep(onboard_dev->reset_gpio, 1); + + err = regulator_bulk_disable(onboard_dev->pdata->num_supplies, + onboard_dev->supplies); + if (err) { + dev_err(onboard_dev->dev, "failed to disable supplies: %pe\n", + ERR_PTR(err)); + return err; + } + + clk_disable_unprepare(onboard_dev->clk); + + onboard_dev->is_powered_on = false; + + return 0; +} + +static int __maybe_unused onboard_dev_suspend(struct device *dev) +{ + struct onboard_dev *onboard_dev = dev_get_drvdata(dev); + struct usbdev_node *node; + bool power_off = true; + + if (onboard_dev->always_powered_in_suspend) + return 0; + + mutex_lock(&onboard_dev->lock); + + list_for_each_entry(node, &onboard_dev->udev_list, list) { + if (!device_may_wakeup(node->udev->bus->controller)) + continue; + + if (usb_wakeup_enabled_descendants(node->udev)) { + power_off = false; + break; + } + } + + mutex_unlock(&onboard_dev->lock); + + if (!power_off) + return 0; + + return onboard_dev_power_off(onboard_dev); +} + +static int __maybe_unused onboard_dev_resume(struct device *dev) +{ + struct onboard_dev *onboard_dev = dev_get_drvdata(dev); + + if (onboard_dev->is_powered_on) + return 0; + + return onboard_dev_power_on(onboard_dev); +} + +static inline void get_udev_link_name(const struct usb_device *udev, char *buf, + size_t size) +{ + snprintf(buf, size, "usb_dev.%s", dev_name(&udev->dev)); +} + +static int onboard_dev_add_usbdev(struct onboard_dev *onboard_dev, + struct usb_device *udev) +{ + struct usbdev_node *node; + char link_name[64]; + int err; + + mutex_lock(&onboard_dev->lock); + + if (onboard_dev->going_away) { + err = -EINVAL; + goto error; + } + + node = kzalloc(sizeof(*node), GFP_KERNEL); + if (!node) { + err = -ENOMEM; + goto error; + } + + node->udev = udev; + + list_add(&node->list, &onboard_dev->udev_list); + + mutex_unlock(&onboard_dev->lock); + + get_udev_link_name(udev, link_name, sizeof(link_name)); + WARN_ON(sysfs_create_link(&onboard_dev->dev->kobj, &udev->dev.kobj, + link_name)); + + return 0; + +error: + mutex_unlock(&onboard_dev->lock); + + return err; +} + +static void onboard_dev_remove_usbdev(struct onboard_dev *onboard_dev, + const struct usb_device *udev) +{ + struct usbdev_node *node; + char link_name[64]; + + get_udev_link_name(udev, link_name, sizeof(link_name)); + sysfs_remove_link(&onboard_dev->dev->kobj, link_name); + + mutex_lock(&onboard_dev->lock); + + list_for_each_entry(node, &onboard_dev->udev_list, list) { + if (node->udev == udev) { + list_del(&node->list); + kfree(node); + break; + } + } + + mutex_unlock(&onboard_dev->lock); +} + +static ssize_t always_powered_in_suspend_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + const struct onboard_dev *onboard_dev = dev_get_drvdata(dev); + + return sysfs_emit(buf, "%d\n", onboard_dev->always_powered_in_suspend); +} + +static ssize_t always_powered_in_suspend_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct onboard_dev *onboard_dev = dev_get_drvdata(dev); + bool val; + int ret; + + ret = kstrtobool(buf, &val); + if (ret < 0) + return ret; + + onboard_dev->always_powered_in_suspend = val; + + return count; +} +static DEVICE_ATTR_RW(always_powered_in_suspend); + +static struct attribute *onboard_dev_attrs[] = { + &dev_attr_always_powered_in_suspend.attr, + NULL, +}; +ATTRIBUTE_GROUPS(onboard_dev); + +static void onboard_dev_attach_usb_driver(struct work_struct *work) +{ + int err; + + err = driver_attach(&onboard_dev_usbdev_driver.driver); + if (err) + pr_err("Failed to attach USB driver: %pe\n", ERR_PTR(err)); +} + +static int onboard_dev_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct onboard_dev *onboard_dev; + int err; + + onboard_dev = devm_kzalloc(dev, sizeof(*onboard_dev), GFP_KERNEL); + if (!onboard_dev) + return -ENOMEM; + + onboard_dev->pdata = device_get_match_data(dev); + if (!onboard_dev->pdata) + return -EINVAL; + + onboard_dev->dev = dev; + + err = onboard_dev_get_regulators(onboard_dev); + if (err) + return err; + + onboard_dev->clk = devm_clk_get_optional(dev, NULL); + if (IS_ERR(onboard_dev->clk)) + return dev_err_probe(dev, PTR_ERR(onboard_dev->clk), + "failed to get clock\n"); + + onboard_dev->reset_gpio = devm_gpiod_get_optional(dev, "reset", + GPIOD_OUT_HIGH); + if (IS_ERR(onboard_dev->reset_gpio)) + return dev_err_probe(dev, PTR_ERR(onboard_dev->reset_gpio), + "failed to get reset GPIO\n"); + + mutex_init(&onboard_dev->lock); + INIT_LIST_HEAD(&onboard_dev->udev_list); + + dev_set_drvdata(dev, onboard_dev); + + err = onboard_dev_power_on(onboard_dev); + if (err) + return err; + + /* + * The USB driver might have been detached from the USB devices by + * onboard_dev_remove() (e.g. through an 'unbind' by userspace), + * make sure to re-attach it if needed. + * + * This needs to be done deferred to avoid self-deadlocks on systems + * with nested onboard hubs. + */ + schedule_work(&attach_usb_driver_work); + + return 0; +} + +static void onboard_dev_remove(struct platform_device *pdev) +{ + struct onboard_dev *onboard_dev = dev_get_drvdata(&pdev->dev); + struct usbdev_node *node; + struct usb_device *udev; + + onboard_dev->going_away = true; + + mutex_lock(&onboard_dev->lock); + + /* unbind the USB devices to avoid dangling references to this device */ + while (!list_empty(&onboard_dev->udev_list)) { + node = list_first_entry(&onboard_dev->udev_list, + struct usbdev_node, list); + udev = node->udev; + + /* + * Unbinding the driver will call onboard_dev_remove_usbdev(), + * which acquires onboard_dev->lock. We must release the lock + * first. + */ + get_device(&udev->dev); + mutex_unlock(&onboard_dev->lock); + device_release_driver(&udev->dev); + put_device(&udev->dev); + mutex_lock(&onboard_dev->lock); + } + + mutex_unlock(&onboard_dev->lock); + + onboard_dev_power_off(onboard_dev); +} + +MODULE_DEVICE_TABLE(of, onboard_dev_match); + +static const struct dev_pm_ops __maybe_unused onboard_dev_pm_ops = { + SET_LATE_SYSTEM_SLEEP_PM_OPS(onboard_dev_suspend, onboard_dev_resume) +}; + +static struct platform_driver onboard_dev_driver = { + .probe = onboard_dev_probe, + .remove_new = onboard_dev_remove, + + .driver = { + .name = "onboard-usb-dev", + .of_match_table = onboard_dev_match, + .pm = pm_ptr(&onboard_dev_pm_ops), + .dev_groups = onboard_dev_groups, + }, +}; + +/************************** USB driver **************************/ + +#define VENDOR_ID_CYPRESS 0x04b4 +#define VENDOR_ID_GENESYS 0x05e3 +#define VENDOR_ID_MICROCHIP 0x0424 +#define VENDOR_ID_REALTEK 0x0bda +#define VENDOR_ID_TI 0x0451 +#define VENDOR_ID_VIA 0x2109 + +/* + * Returns the onboard_dev platform device that is associated with the USB + * device passed as parameter. + */ +static struct onboard_dev *_find_onboard_dev(struct device *dev) +{ + struct platform_device *pdev; + struct device_node *np; + struct onboard_dev *onboard_dev; + + pdev = of_find_device_by_node(dev->of_node); + if (!pdev) { + np = of_parse_phandle(dev->of_node, "peer-hub", 0); + if (!np) { + dev_err(dev, "failed to find device node for peer hub\n"); + return ERR_PTR(-EINVAL); + } + + pdev = of_find_device_by_node(np); + of_node_put(np); + + if (!pdev) + return ERR_PTR(-ENODEV); + } + + onboard_dev = dev_get_drvdata(&pdev->dev); + put_device(&pdev->dev); + + /* + * The presence of drvdata indicates that the platform driver finished + * probing. This handles the case where (conceivably) we could be + * running at the exact same time as the platform driver's probe. If + * we detect the race we request probe deferral and we'll come back and + * try again. + */ + if (!onboard_dev) + return ERR_PTR(-EPROBE_DEFER); + + return onboard_dev; +} + +static int onboard_dev_usbdev_probe(struct usb_device *udev) +{ + struct device *dev = &udev->dev; + struct onboard_dev *onboard_dev; + int err; + + /* ignore supported devices without device tree node */ + if (!dev->of_node) + return -ENODEV; + + onboard_dev = _find_onboard_dev(dev); + if (IS_ERR(onboard_dev)) + return PTR_ERR(onboard_dev); + + dev_set_drvdata(dev, onboard_dev); + + err = onboard_dev_add_usbdev(onboard_dev, udev); + if (err) + return err; + + return 0; +} + +static void onboard_dev_usbdev_disconnect(struct usb_device *udev) +{ + struct onboard_dev *onboard_dev = dev_get_drvdata(&udev->dev); + + onboard_dev_remove_usbdev(onboard_dev, udev); +} + +static const struct usb_device_id onboard_dev_id_table[] = { + { USB_DEVICE(VENDOR_ID_CYPRESS, 0x6504) }, /* CYUSB33{0,1,2}x/CYUSB230x 3.0 HUB */ + { USB_DEVICE(VENDOR_ID_CYPRESS, 0x6506) }, /* CYUSB33{0,1,2}x/CYUSB230x 2.0 HUB */ + { USB_DEVICE(VENDOR_ID_CYPRESS, 0x6570) }, /* CY7C6563x 2.0 HUB */ + { USB_DEVICE(VENDOR_ID_GENESYS, 0x0608) }, /* Genesys Logic GL850G USB 2.0 HUB */ + { USB_DEVICE(VENDOR_ID_GENESYS, 0x0610) }, /* Genesys Logic GL852G USB 2.0 HUB */ + { USB_DEVICE(VENDOR_ID_GENESYS, 0x0620) }, /* Genesys Logic GL3523 USB 3.1 HUB */ + { USB_DEVICE(VENDOR_ID_MICROCHIP, 0x2412) }, /* USB2412 USB 2.0 HUB */ + { USB_DEVICE(VENDOR_ID_MICROCHIP, 0x2514) }, /* USB2514B USB 2.0 HUB */ + { USB_DEVICE(VENDOR_ID_MICROCHIP, 0x2517) }, /* USB2517 USB 2.0 HUB */ + { USB_DEVICE(VENDOR_ID_MICROCHIP, 0x2744) }, /* USB5744 USB 2.0 HUB */ + { USB_DEVICE(VENDOR_ID_MICROCHIP, 0x5744) }, /* USB5744 USB 3.0 HUB */ + { USB_DEVICE(VENDOR_ID_REALTEK, 0x0411) }, /* RTS5411 USB 3.1 HUB */ + { USB_DEVICE(VENDOR_ID_REALTEK, 0x5411) }, /* RTS5411 USB 2.1 HUB */ + { USB_DEVICE(VENDOR_ID_REALTEK, 0x0414) }, /* RTS5414 USB 3.2 HUB */ + { USB_DEVICE(VENDOR_ID_REALTEK, 0x5414) }, /* RTS5414 USB 2.1 HUB */ + { USB_DEVICE(VENDOR_ID_TI, 0x8025) }, /* TI USB8020B 3.0 HUB */ + { USB_DEVICE(VENDOR_ID_TI, 0x8027) }, /* TI USB8020B 2.0 HUB */ + { USB_DEVICE(VENDOR_ID_TI, 0x8140) }, /* TI USB8041 3.0 HUB */ + { USB_DEVICE(VENDOR_ID_TI, 0x8142) }, /* TI USB8041 2.0 HUB */ + { USB_DEVICE(VENDOR_ID_VIA, 0x0817) }, /* VIA VL817 3.1 HUB */ + { USB_DEVICE(VENDOR_ID_VIA, 0x2817) }, /* VIA VL817 2.0 HUB */ + {} +}; +MODULE_DEVICE_TABLE(usb, onboard_dev_id_table); + +static struct usb_device_driver onboard_dev_usbdev_driver = { + .name = "onboard-usb-dev", + .probe = onboard_dev_usbdev_probe, + .disconnect = onboard_dev_usbdev_disconnect, + .generic_subclass = 1, + .supports_autosuspend = 1, + .id_table = onboard_dev_id_table, +}; + +static int __init onboard_dev_init(void) +{ + int ret; + + ret = usb_register_device_driver(&onboard_dev_usbdev_driver, THIS_MODULE); + if (ret) + return ret; + + ret = platform_driver_register(&onboard_dev_driver); + if (ret) + usb_deregister_device_driver(&onboard_dev_usbdev_driver); + + return ret; +} +module_init(onboard_dev_init); + +static void __exit onboard_dev_exit(void) +{ + usb_deregister_device_driver(&onboard_dev_usbdev_driver); + platform_driver_unregister(&onboard_dev_driver); + + cancel_work_sync(&attach_usb_driver_work); +} +module_exit(onboard_dev_exit); + +MODULE_AUTHOR("Matthias Kaehlcke "); +MODULE_DESCRIPTION("Driver for discrete onboard USB devices"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/usb/misc/onboard_usb_dev.h b/drivers/usb/misc/onboard_usb_dev.h new file mode 100644 index 000000000000..debab2895a53 --- /dev/null +++ b/drivers/usb/misc/onboard_usb_dev.h @@ -0,0 +1,103 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (c) 2022, Google LLC + */ + +#ifndef _USB_MISC_ONBOARD_USB_DEV_H +#define _USB_MISC_ONBOARD_USB_DEV_H + +#define MAX_SUPPLIES 2 + +struct onboard_dev_pdata { + unsigned long reset_us; /* reset pulse width in us */ + unsigned int num_supplies; /* number of supplies */ + const char * const supply_names[MAX_SUPPLIES]; +}; + +static const struct onboard_dev_pdata microchip_usb424_data = { + .reset_us = 1, + .num_supplies = 1, + .supply_names = { "vdd" }, +}; + +static const struct onboard_dev_pdata microchip_usb5744_data = { + .reset_us = 0, + .num_supplies = 2, + .supply_names = { "vdd", "vdd2" }, +}; + +static const struct onboard_dev_pdata realtek_rts5411_data = { + .reset_us = 0, + .num_supplies = 1, + .supply_names = { "vdd" }, +}; + +static const struct onboard_dev_pdata ti_tusb8020b_data = { + .reset_us = 3000, + .num_supplies = 1, + .supply_names = { "vdd" }, +}; + +static const struct onboard_dev_pdata ti_tusb8041_data = { + .reset_us = 3000, + .num_supplies = 1, + .supply_names = { "vdd" }, +}; + +static const struct onboard_dev_pdata cypress_hx3_data = { + .reset_us = 10000, + .num_supplies = 2, + .supply_names = { "vdd", "vdd2" }, +}; + +static const struct onboard_dev_pdata cypress_hx2vl_data = { + .reset_us = 1, + .num_supplies = 1, + .supply_names = { "vdd" }, +}; + +static const struct onboard_dev_pdata genesys_gl850g_data = { + .reset_us = 3, + .num_supplies = 1, + .supply_names = { "vdd" }, +}; + +static const struct onboard_dev_pdata genesys_gl852g_data = { + .reset_us = 50, + .num_supplies = 1, + .supply_names = { "vdd" }, +}; + +static const struct onboard_dev_pdata vialab_vl817_data = { + .reset_us = 10, + .num_supplies = 1, + .supply_names = { "vdd" }, +}; + +static const struct of_device_id onboard_dev_match[] = { + { .compatible = "usb424,2412", .data = µchip_usb424_data, }, + { .compatible = "usb424,2514", .data = µchip_usb424_data, }, + { .compatible = "usb424,2517", .data = µchip_usb424_data, }, + { .compatible = "usb424,2744", .data = µchip_usb5744_data, }, + { .compatible = "usb424,5744", .data = µchip_usb5744_data, }, + { .compatible = "usb451,8025", .data = &ti_tusb8020b_data, }, + { .compatible = "usb451,8027", .data = &ti_tusb8020b_data, }, + { .compatible = "usb451,8140", .data = &ti_tusb8041_data, }, + { .compatible = "usb451,8142", .data = &ti_tusb8041_data, }, + { .compatible = "usb4b4,6504", .data = &cypress_hx3_data, }, + { .compatible = "usb4b4,6506", .data = &cypress_hx3_data, }, + { .compatible = "usb4b4,6570", .data = &cypress_hx2vl_data, }, + { .compatible = "usb5e3,608", .data = &genesys_gl850g_data, }, + { .compatible = "usb5e3,610", .data = &genesys_gl852g_data, }, + { .compatible = "usb5e3,620", .data = &genesys_gl852g_data, }, + { .compatible = "usb5e3,626", .data = &genesys_gl852g_data, }, + { .compatible = "usbbda,411", .data = &realtek_rts5411_data, }, + { .compatible = "usbbda,5411", .data = &realtek_rts5411_data, }, + { .compatible = "usbbda,414", .data = &realtek_rts5411_data, }, + { .compatible = "usbbda,5414", .data = &realtek_rts5411_data, }, + { .compatible = "usb2109,817", .data = &vialab_vl817_data, }, + { .compatible = "usb2109,2817", .data = &vialab_vl817_data, }, + {} +}; + +#endif /* _USB_MISC_ONBOARD_USB_DEV_H */ diff --git a/drivers/usb/misc/onboard_usb_dev_pdevs.c b/drivers/usb/misc/onboard_usb_dev_pdevs.c new file mode 100644 index 000000000000..722504752ce3 --- /dev/null +++ b/drivers/usb/misc/onboard_usb_dev_pdevs.c @@ -0,0 +1,144 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * API for creating and destroying USB onboard platform devices + * + * Copyright (c) 2022, Google LLC + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "onboard_usb_dev.h" + +struct pdev_list_entry { + struct platform_device *pdev; + struct list_head node; +}; + +static bool of_is_onboard_usb_dev(struct device_node *np) +{ + return !!of_match_node(onboard_dev_match, np); +} + +/** + * onboard_dev_create_pdevs -- create platform devices for onboard USB devices + * @parent_hub : parent hub to scan for connected onboard devices + * @pdev_list : list of onboard platform devices owned by the parent hub + * + * Creates a platform device for each supported onboard device that is connected + * to the given parent hub. The platform device is in charge of initializing the + * device (enable regulators, take the device out of reset, ...). For onboard + * hubs, it can optionally control whether the device remains powered during + * system suspend or not. + * + * To keep track of the platform devices they are added to a list that is owned + * by the parent hub. + * + * Some background about the logic in this function, which can be a bit hard + * to follow: + * + * Root hubs don't have dedicated device tree nodes, but use the node of their + * HCD. The primary and secondary HCD are usually represented by a single DT + * node. That means the root hubs of the primary and secondary HCD share the + * same device tree node (the HCD node). As a result this function can be called + * twice with the same DT node for root hubs. We only want to create a single + * platform device for each physical onboard device, hence for root hubs the + * loop is only executed for the root hub of the primary HCD. Since the function + * scans through all child nodes it still creates pdevs for onboard devices + * connected to the root hub of the secondary HCD if needed. + * + * Further there must be only one platform device for onboard hubs with a peer + * hub (the hub is a single physical device). To achieve this two measures are + * taken: pdevs for onboard hubs with a peer are only created when the function + * is called on behalf of the parent hub that is connected to the primary HCD + * (directly or through other hubs). For onboard hubs connected to root hubs + * the function processes the nodes of both peers. A platform device is only + * created if the peer hub doesn't have one already. + */ +void onboard_dev_create_pdevs(struct usb_device *parent_hub, struct list_head *pdev_list) +{ + int i; + struct usb_hcd *hcd = bus_to_hcd(parent_hub->bus); + struct device_node *np, *npc; + struct platform_device *pdev; + struct pdev_list_entry *pdle; + + if (!parent_hub->dev.of_node) + return; + + if (!parent_hub->parent && !usb_hcd_is_primary_hcd(hcd)) + return; + + for (i = 1; i <= parent_hub->maxchild; i++) { + np = usb_of_get_device_node(parent_hub, i); + if (!np) + continue; + + if (!of_is_onboard_usb_dev(np)) + goto node_put; + + npc = of_parse_phandle(np, "peer-hub", 0); + if (npc) { + if (!usb_hcd_is_primary_hcd(hcd)) { + of_node_put(npc); + goto node_put; + } + + pdev = of_find_device_by_node(npc); + of_node_put(npc); + + if (pdev) { + put_device(&pdev->dev); + goto node_put; + } + } + + pdev = of_platform_device_create(np, NULL, &parent_hub->dev); + if (!pdev) { + dev_err(&parent_hub->dev, + "failed to create platform device for onboard dev '%pOF'\n", np); + goto node_put; + } + + pdle = kzalloc(sizeof(*pdle), GFP_KERNEL); + if (!pdle) { + of_platform_device_destroy(&pdev->dev, NULL); + goto node_put; + } + + pdle->pdev = pdev; + list_add(&pdle->node, pdev_list); + +node_put: + of_node_put(np); + } +} +EXPORT_SYMBOL_GPL(onboard_dev_create_pdevs); + +/** + * onboard_dev_destroy_pdevs -- free resources of onboard platform devices + * @pdev_list : list of onboard platform devices + * + * Destroys the platform devices in the given list and frees the memory associated + * with the list entry. + */ +void onboard_dev_destroy_pdevs(struct list_head *pdev_list) +{ + struct pdev_list_entry *pdle, *tmp; + + list_for_each_entry_safe(pdle, tmp, pdev_list, node) { + list_del(&pdle->node); + of_platform_device_destroy(&pdle->pdev->dev, NULL); + kfree(pdle); + } +} +EXPORT_SYMBOL_GPL(onboard_dev_destroy_pdevs); diff --git a/drivers/usb/misc/onboard_usb_hub.c b/drivers/usb/misc/onboard_usb_hub.c deleted file mode 100644 index 5308c54aaabe..000000000000 --- a/drivers/usb/misc/onboard_usb_hub.c +++ /dev/null @@ -1,506 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Driver for onboard USB hubs - * - * Copyright (c) 2022, Google LLC - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "onboard_usb_hub.h" - -static void onboard_hub_attach_usb_driver(struct work_struct *work); - -static struct usb_device_driver onboard_hub_usbdev_driver; -static DECLARE_WORK(attach_usb_driver_work, onboard_hub_attach_usb_driver); - -/************************** Platform driver **************************/ - -struct usbdev_node { - struct usb_device *udev; - struct list_head list; -}; - -struct onboard_hub { - struct regulator_bulk_data supplies[MAX_SUPPLIES]; - struct device *dev; - const struct onboard_hub_pdata *pdata; - struct gpio_desc *reset_gpio; - bool always_powered_in_suspend; - bool is_powered_on; - bool going_away; - struct list_head udev_list; - struct mutex lock; - struct clk *clk; -}; - -static int onboard_hub_get_regulators(struct onboard_hub *hub) -{ - const char * const *supply_names = hub->pdata->supply_names; - unsigned int num_supplies = hub->pdata->num_supplies; - struct device *dev = hub->dev; - unsigned int i; - int err; - - if (num_supplies > MAX_SUPPLIES) - return dev_err_probe(dev, -EINVAL, "max %d supplies supported!\n", - MAX_SUPPLIES); - - for (i = 0; i < num_supplies; i++) - hub->supplies[i].supply = supply_names[i]; - - err = devm_regulator_bulk_get(dev, num_supplies, hub->supplies); - if (err) - dev_err(dev, "Failed to get regulator supplies: %pe\n", - ERR_PTR(err)); - - return err; -} - -static int onboard_hub_power_on(struct onboard_hub *hub) -{ - int err; - - err = clk_prepare_enable(hub->clk); - if (err) { - dev_err(hub->dev, "failed to enable clock: %pe\n", ERR_PTR(err)); - return err; - } - - err = regulator_bulk_enable(hub->pdata->num_supplies, hub->supplies); - if (err) { - dev_err(hub->dev, "failed to enable supplies: %pe\n", ERR_PTR(err)); - return err; - } - - fsleep(hub->pdata->reset_us); - gpiod_set_value_cansleep(hub->reset_gpio, 0); - - hub->is_powered_on = true; - - return 0; -} - -static int onboard_hub_power_off(struct onboard_hub *hub) -{ - int err; - - gpiod_set_value_cansleep(hub->reset_gpio, 1); - - err = regulator_bulk_disable(hub->pdata->num_supplies, hub->supplies); - if (err) { - dev_err(hub->dev, "failed to disable supplies: %pe\n", ERR_PTR(err)); - return err; - } - - clk_disable_unprepare(hub->clk); - - hub->is_powered_on = false; - - return 0; -} - -static int __maybe_unused onboard_hub_suspend(struct device *dev) -{ - struct onboard_hub *hub = dev_get_drvdata(dev); - struct usbdev_node *node; - bool power_off = true; - - if (hub->always_powered_in_suspend) - return 0; - - mutex_lock(&hub->lock); - - list_for_each_entry(node, &hub->udev_list, list) { - if (!device_may_wakeup(node->udev->bus->controller)) - continue; - - if (usb_wakeup_enabled_descendants(node->udev)) { - power_off = false; - break; - } - } - - mutex_unlock(&hub->lock); - - if (!power_off) - return 0; - - return onboard_hub_power_off(hub); -} - -static int __maybe_unused onboard_hub_resume(struct device *dev) -{ - struct onboard_hub *hub = dev_get_drvdata(dev); - - if (hub->is_powered_on) - return 0; - - return onboard_hub_power_on(hub); -} - -static inline void get_udev_link_name(const struct usb_device *udev, char *buf, size_t size) -{ - snprintf(buf, size, "usb_dev.%s", dev_name(&udev->dev)); -} - -static int onboard_hub_add_usbdev(struct onboard_hub *hub, struct usb_device *udev) -{ - struct usbdev_node *node; - char link_name[64]; - int err; - - mutex_lock(&hub->lock); - - if (hub->going_away) { - err = -EINVAL; - goto error; - } - - node = kzalloc(sizeof(*node), GFP_KERNEL); - if (!node) { - err = -ENOMEM; - goto error; - } - - node->udev = udev; - - list_add(&node->list, &hub->udev_list); - - mutex_unlock(&hub->lock); - - get_udev_link_name(udev, link_name, sizeof(link_name)); - WARN_ON(sysfs_create_link(&hub->dev->kobj, &udev->dev.kobj, link_name)); - - return 0; - -error: - mutex_unlock(&hub->lock); - - return err; -} - -static void onboard_hub_remove_usbdev(struct onboard_hub *hub, const struct usb_device *udev) -{ - struct usbdev_node *node; - char link_name[64]; - - get_udev_link_name(udev, link_name, sizeof(link_name)); - sysfs_remove_link(&hub->dev->kobj, link_name); - - mutex_lock(&hub->lock); - - list_for_each_entry(node, &hub->udev_list, list) { - if (node->udev == udev) { - list_del(&node->list); - kfree(node); - break; - } - } - - mutex_unlock(&hub->lock); -} - -static ssize_t always_powered_in_suspend_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - const struct onboard_hub *hub = dev_get_drvdata(dev); - - return sysfs_emit(buf, "%d\n", hub->always_powered_in_suspend); -} - -static ssize_t always_powered_in_suspend_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct onboard_hub *hub = dev_get_drvdata(dev); - bool val; - int ret; - - ret = kstrtobool(buf, &val); - if (ret < 0) - return ret; - - hub->always_powered_in_suspend = val; - - return count; -} -static DEVICE_ATTR_RW(always_powered_in_suspend); - -static struct attribute *onboard_hub_attrs[] = { - &dev_attr_always_powered_in_suspend.attr, - NULL, -}; -ATTRIBUTE_GROUPS(onboard_hub); - -static void onboard_hub_attach_usb_driver(struct work_struct *work) -{ - int err; - - err = driver_attach(&onboard_hub_usbdev_driver.driver); - if (err) - pr_err("Failed to attach USB driver: %pe\n", ERR_PTR(err)); -} - -static int onboard_hub_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct onboard_hub *hub; - int err; - - hub = devm_kzalloc(dev, sizeof(*hub), GFP_KERNEL); - if (!hub) - return -ENOMEM; - - hub->pdata = device_get_match_data(dev); - if (!hub->pdata) - return -EINVAL; - - hub->dev = dev; - - err = onboard_hub_get_regulators(hub); - if (err) - return err; - - hub->clk = devm_clk_get_optional(dev, NULL); - if (IS_ERR(hub->clk)) - return dev_err_probe(dev, PTR_ERR(hub->clk), "failed to get clock\n"); - - hub->reset_gpio = devm_gpiod_get_optional(dev, "reset", - GPIOD_OUT_HIGH); - if (IS_ERR(hub->reset_gpio)) - return dev_err_probe(dev, PTR_ERR(hub->reset_gpio), "failed to get reset GPIO\n"); - - mutex_init(&hub->lock); - INIT_LIST_HEAD(&hub->udev_list); - - dev_set_drvdata(dev, hub); - - err = onboard_hub_power_on(hub); - if (err) - return err; - - /* - * The USB driver might have been detached from the USB devices by - * onboard_hub_remove() (e.g. through an 'unbind' by userspace), - * make sure to re-attach it if needed. - * - * This needs to be done deferred to avoid self-deadlocks on systems - * with nested onboard hubs. - */ - schedule_work(&attach_usb_driver_work); - - return 0; -} - -static void onboard_hub_remove(struct platform_device *pdev) -{ - struct onboard_hub *hub = dev_get_drvdata(&pdev->dev); - struct usbdev_node *node; - struct usb_device *udev; - - hub->going_away = true; - - mutex_lock(&hub->lock); - - /* unbind the USB devices to avoid dangling references to this device */ - while (!list_empty(&hub->udev_list)) { - node = list_first_entry(&hub->udev_list, struct usbdev_node, list); - udev = node->udev; - - /* - * Unbinding the driver will call onboard_hub_remove_usbdev(), - * which acquires hub->lock. We must release the lock first. - */ - get_device(&udev->dev); - mutex_unlock(&hub->lock); - device_release_driver(&udev->dev); - put_device(&udev->dev); - mutex_lock(&hub->lock); - } - - mutex_unlock(&hub->lock); - - onboard_hub_power_off(hub); -} - -MODULE_DEVICE_TABLE(of, onboard_hub_match); - -static const struct dev_pm_ops __maybe_unused onboard_hub_pm_ops = { - SET_LATE_SYSTEM_SLEEP_PM_OPS(onboard_hub_suspend, onboard_hub_resume) -}; - -static struct platform_driver onboard_hub_driver = { - .probe = onboard_hub_probe, - .remove_new = onboard_hub_remove, - - .driver = { - .name = "onboard-usb-hub", - .of_match_table = onboard_hub_match, - .pm = pm_ptr(&onboard_hub_pm_ops), - .dev_groups = onboard_hub_groups, - }, -}; - -/************************** USB driver **************************/ - -#define VENDOR_ID_CYPRESS 0x04b4 -#define VENDOR_ID_GENESYS 0x05e3 -#define VENDOR_ID_MICROCHIP 0x0424 -#define VENDOR_ID_REALTEK 0x0bda -#define VENDOR_ID_TI 0x0451 -#define VENDOR_ID_VIA 0x2109 - -/* - * Returns the onboard_hub platform device that is associated with the USB - * device passed as parameter. - */ -static struct onboard_hub *_find_onboard_hub(struct device *dev) -{ - struct platform_device *pdev; - struct device_node *np; - struct onboard_hub *hub; - - pdev = of_find_device_by_node(dev->of_node); - if (!pdev) { - np = of_parse_phandle(dev->of_node, "peer-hub", 0); - if (!np) { - dev_err(dev, "failed to find device node for peer hub\n"); - return ERR_PTR(-EINVAL); - } - - pdev = of_find_device_by_node(np); - of_node_put(np); - - if (!pdev) - return ERR_PTR(-ENODEV); - } - - hub = dev_get_drvdata(&pdev->dev); - put_device(&pdev->dev); - - /* - * The presence of drvdata ('hub') indicates that the platform driver - * finished probing. This handles the case where (conceivably) we could - * be running at the exact same time as the platform driver's probe. If - * we detect the race we request probe deferral and we'll come back and - * try again. - */ - if (!hub) - return ERR_PTR(-EPROBE_DEFER); - - return hub; -} - -static int onboard_hub_usbdev_probe(struct usb_device *udev) -{ - struct device *dev = &udev->dev; - struct onboard_hub *hub; - int err; - - /* ignore supported hubs without device tree node */ - if (!dev->of_node) - return -ENODEV; - - hub = _find_onboard_hub(dev); - if (IS_ERR(hub)) - return PTR_ERR(hub); - - dev_set_drvdata(dev, hub); - - err = onboard_hub_add_usbdev(hub, udev); - if (err) - return err; - - return 0; -} - -static void onboard_hub_usbdev_disconnect(struct usb_device *udev) -{ - struct onboard_hub *hub = dev_get_drvdata(&udev->dev); - - onboard_hub_remove_usbdev(hub, udev); -} - -static const struct usb_device_id onboard_hub_id_table[] = { - { USB_DEVICE(VENDOR_ID_CYPRESS, 0x6504) }, /* CYUSB33{0,1,2}x/CYUSB230x 3.0 */ - { USB_DEVICE(VENDOR_ID_CYPRESS, 0x6506) }, /* CYUSB33{0,1,2}x/CYUSB230x 2.0 */ - { USB_DEVICE(VENDOR_ID_CYPRESS, 0x6570) }, /* CY7C6563x 2.0 */ - { USB_DEVICE(VENDOR_ID_GENESYS, 0x0608) }, /* Genesys Logic GL850G USB 2.0 */ - { USB_DEVICE(VENDOR_ID_GENESYS, 0x0610) }, /* Genesys Logic GL852G USB 2.0 */ - { USB_DEVICE(VENDOR_ID_GENESYS, 0x0620) }, /* Genesys Logic GL3523 USB 3.1 */ - { USB_DEVICE(VENDOR_ID_MICROCHIP, 0x2412) }, /* USB2412 USB 2.0 */ - { USB_DEVICE(VENDOR_ID_MICROCHIP, 0x2514) }, /* USB2514B USB 2.0 */ - { USB_DEVICE(VENDOR_ID_MICROCHIP, 0x2517) }, /* USB2517 USB 2.0 */ - { USB_DEVICE(VENDOR_ID_MICROCHIP, 0x2744) }, /* USB5744 USB 2.0 */ - { USB_DEVICE(VENDOR_ID_MICROCHIP, 0x5744) }, /* USB5744 USB 3.0 */ - { USB_DEVICE(VENDOR_ID_REALTEK, 0x0411) }, /* RTS5411 USB 3.1 */ - { USB_DEVICE(VENDOR_ID_REALTEK, 0x5411) }, /* RTS5411 USB 2.1 */ - { USB_DEVICE(VENDOR_ID_REALTEK, 0x0414) }, /* RTS5414 USB 3.2 */ - { USB_DEVICE(VENDOR_ID_REALTEK, 0x5414) }, /* RTS5414 USB 2.1 */ - { USB_DEVICE(VENDOR_ID_TI, 0x8025) }, /* TI USB8020B 3.0 */ - { USB_DEVICE(VENDOR_ID_TI, 0x8027) }, /* TI USB8020B 2.0 */ - { USB_DEVICE(VENDOR_ID_TI, 0x8140) }, /* TI USB8041 3.0 */ - { USB_DEVICE(VENDOR_ID_TI, 0x8142) }, /* TI USB8041 2.0 */ - { USB_DEVICE(VENDOR_ID_VIA, 0x0817) }, /* VIA VL817 3.1 */ - { USB_DEVICE(VENDOR_ID_VIA, 0x2817) }, /* VIA VL817 2.0 */ - {} -}; -MODULE_DEVICE_TABLE(usb, onboard_hub_id_table); - -static struct usb_device_driver onboard_hub_usbdev_driver = { - .name = "onboard-usb-hub", - .probe = onboard_hub_usbdev_probe, - .disconnect = onboard_hub_usbdev_disconnect, - .generic_subclass = 1, - .supports_autosuspend = 1, - .id_table = onboard_hub_id_table, -}; - -static int __init onboard_hub_init(void) -{ - int ret; - - ret = usb_register_device_driver(&onboard_hub_usbdev_driver, THIS_MODULE); - if (ret) - return ret; - - ret = platform_driver_register(&onboard_hub_driver); - if (ret) - usb_deregister_device_driver(&onboard_hub_usbdev_driver); - - return ret; -} -module_init(onboard_hub_init); - -static void __exit onboard_hub_exit(void) -{ - usb_deregister_device_driver(&onboard_hub_usbdev_driver); - platform_driver_unregister(&onboard_hub_driver); - - cancel_work_sync(&attach_usb_driver_work); -} -module_exit(onboard_hub_exit); - -MODULE_AUTHOR("Matthias Kaehlcke "); -MODULE_DESCRIPTION("Driver for discrete onboard USB hubs"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/usb/misc/onboard_usb_hub.h b/drivers/usb/misc/onboard_usb_hub.h deleted file mode 100644 index edbca8aa6ea0..000000000000 --- a/drivers/usb/misc/onboard_usb_hub.h +++ /dev/null @@ -1,103 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (c) 2022, Google LLC - */ - -#ifndef _USB_MISC_ONBOARD_USB_HUB_H -#define _USB_MISC_ONBOARD_USB_HUB_H - -#define MAX_SUPPLIES 2 - -struct onboard_hub_pdata { - unsigned long reset_us; /* reset pulse width in us */ - unsigned int num_supplies; /* number of supplies */ - const char * const supply_names[MAX_SUPPLIES]; -}; - -static const struct onboard_hub_pdata microchip_usb424_data = { - .reset_us = 1, - .num_supplies = 1, - .supply_names = { "vdd" }, -}; - -static const struct onboard_hub_pdata microchip_usb5744_data = { - .reset_us = 0, - .num_supplies = 2, - .supply_names = { "vdd", "vdd2" }, -}; - -static const struct onboard_hub_pdata realtek_rts5411_data = { - .reset_us = 0, - .num_supplies = 1, - .supply_names = { "vdd" }, -}; - -static const struct onboard_hub_pdata ti_tusb8020b_data = { - .reset_us = 3000, - .num_supplies = 1, - .supply_names = { "vdd" }, -}; - -static const struct onboard_hub_pdata ti_tusb8041_data = { - .reset_us = 3000, - .num_supplies = 1, - .supply_names = { "vdd" }, -}; - -static const struct onboard_hub_pdata cypress_hx3_data = { - .reset_us = 10000, - .num_supplies = 2, - .supply_names = { "vdd", "vdd2" }, -}; - -static const struct onboard_hub_pdata cypress_hx2vl_data = { - .reset_us = 1, - .num_supplies = 1, - .supply_names = { "vdd" }, -}; - -static const struct onboard_hub_pdata genesys_gl850g_data = { - .reset_us = 3, - .num_supplies = 1, - .supply_names = { "vdd" }, -}; - -static const struct onboard_hub_pdata genesys_gl852g_data = { - .reset_us = 50, - .num_supplies = 1, - .supply_names = { "vdd" }, -}; - -static const struct onboard_hub_pdata vialab_vl817_data = { - .reset_us = 10, - .num_supplies = 1, - .supply_names = { "vdd" }, -}; - -static const struct of_device_id onboard_hub_match[] = { - { .compatible = "usb424,2412", .data = µchip_usb424_data, }, - { .compatible = "usb424,2514", .data = µchip_usb424_data, }, - { .compatible = "usb424,2517", .data = µchip_usb424_data, }, - { .compatible = "usb424,2744", .data = µchip_usb5744_data, }, - { .compatible = "usb424,5744", .data = µchip_usb5744_data, }, - { .compatible = "usb451,8025", .data = &ti_tusb8020b_data, }, - { .compatible = "usb451,8027", .data = &ti_tusb8020b_data, }, - { .compatible = "usb451,8140", .data = &ti_tusb8041_data, }, - { .compatible = "usb451,8142", .data = &ti_tusb8041_data, }, - { .compatible = "usb4b4,6504", .data = &cypress_hx3_data, }, - { .compatible = "usb4b4,6506", .data = &cypress_hx3_data, }, - { .compatible = "usb4b4,6570", .data = &cypress_hx2vl_data, }, - { .compatible = "usb5e3,608", .data = &genesys_gl850g_data, }, - { .compatible = "usb5e3,610", .data = &genesys_gl852g_data, }, - { .compatible = "usb5e3,620", .data = &genesys_gl852g_data, }, - { .compatible = "usb5e3,626", .data = &genesys_gl852g_data, }, - { .compatible = "usbbda,411", .data = &realtek_rts5411_data, }, - { .compatible = "usbbda,5411", .data = &realtek_rts5411_data, }, - { .compatible = "usbbda,414", .data = &realtek_rts5411_data, }, - { .compatible = "usbbda,5414", .data = &realtek_rts5411_data, }, - { .compatible = "usb2109,817", .data = &vialab_vl817_data, }, - { .compatible = "usb2109,2817", .data = &vialab_vl817_data, }, - {} -}; - -#endif /* _USB_MISC_ONBOARD_USB_HUB_H */ diff --git a/drivers/usb/misc/onboard_usb_hub_pdevs.c b/drivers/usb/misc/onboard_usb_hub_pdevs.c deleted file mode 100644 index ed22a18f4ab7..000000000000 --- a/drivers/usb/misc/onboard_usb_hub_pdevs.c +++ /dev/null @@ -1,143 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * API for creating and destroying USB onboard hub platform devices - * - * Copyright (c) 2022, Google LLC - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "onboard_usb_hub.h" - -struct pdev_list_entry { - struct platform_device *pdev; - struct list_head node; -}; - -static bool of_is_onboard_usb_hub(const struct device_node *np) -{ - return !!of_match_node(onboard_hub_match, np); -} - -/** - * onboard_hub_create_pdevs -- create platform devices for onboard USB hubs - * @parent_hub : parent hub to scan for connected onboard hubs - * @pdev_list : list of onboard hub platform devices owned by the parent hub - * - * Creates a platform device for each supported onboard hub that is connected to - * the given parent hub. The platform device is in charge of initializing the - * hub (enable regulators, take the hub out of reset, ...) and can optionally - * control whether the hub remains powered during system suspend or not. - * - * To keep track of the platform devices they are added to a list that is owned - * by the parent hub. - * - * Some background about the logic in this function, which can be a bit hard - * to follow: - * - * Root hubs don't have dedicated device tree nodes, but use the node of their - * HCD. The primary and secondary HCD are usually represented by a single DT - * node. That means the root hubs of the primary and secondary HCD share the - * same device tree node (the HCD node). As a result this function can be called - * twice with the same DT node for root hubs. We only want to create a single - * platform device for each physical onboard hub, hence for root hubs the loop - * is only executed for the root hub of the primary HCD. Since the function - * scans through all child nodes it still creates pdevs for onboard hubs - * connected to the root hub of the secondary HCD if needed. - * - * Further there must be only one platform device for onboard hubs with a peer - * hub (the hub is a single physical device). To achieve this two measures are - * taken: pdevs for onboard hubs with a peer are only created when the function - * is called on behalf of the parent hub that is connected to the primary HCD - * (directly or through other hubs). For onboard hubs connected to root hubs - * the function processes the nodes of both peers. A platform device is only - * created if the peer hub doesn't have one already. - */ -void onboard_hub_create_pdevs(struct usb_device *parent_hub, struct list_head *pdev_list) -{ - int i; - struct usb_hcd *hcd = bus_to_hcd(parent_hub->bus); - struct device_node *np, *npc; - struct platform_device *pdev; - struct pdev_list_entry *pdle; - - if (!parent_hub->dev.of_node) - return; - - if (!parent_hub->parent && !usb_hcd_is_primary_hcd(hcd)) - return; - - for (i = 1; i <= parent_hub->maxchild; i++) { - np = usb_of_get_device_node(parent_hub, i); - if (!np) - continue; - - if (!of_is_onboard_usb_hub(np)) - goto node_put; - - npc = of_parse_phandle(np, "peer-hub", 0); - if (npc) { - if (!usb_hcd_is_primary_hcd(hcd)) { - of_node_put(npc); - goto node_put; - } - - pdev = of_find_device_by_node(npc); - of_node_put(npc); - - if (pdev) { - put_device(&pdev->dev); - goto node_put; - } - } - - pdev = of_platform_device_create(np, NULL, &parent_hub->dev); - if (!pdev) { - dev_err(&parent_hub->dev, - "failed to create platform device for onboard hub '%pOF'\n", np); - goto node_put; - } - - pdle = kzalloc(sizeof(*pdle), GFP_KERNEL); - if (!pdle) { - of_platform_device_destroy(&pdev->dev, NULL); - goto node_put; - } - - pdle->pdev = pdev; - list_add(&pdle->node, pdev_list); - -node_put: - of_node_put(np); - } -} -EXPORT_SYMBOL_GPL(onboard_hub_create_pdevs); - -/** - * onboard_hub_destroy_pdevs -- free resources of onboard hub platform devices - * @pdev_list : list of onboard hub platform devices - * - * Destroys the platform devices in the given list and frees the memory associated - * with the list entry. - */ -void onboard_hub_destroy_pdevs(struct list_head *pdev_list) -{ - struct pdev_list_entry *pdle, *tmp; - - list_for_each_entry_safe(pdle, tmp, pdev_list, node) { - list_del(&pdle->node); - of_platform_device_destroy(&pdle->pdev->dev, NULL); - kfree(pdle); - } -} -EXPORT_SYMBOL_GPL(onboard_hub_destroy_pdevs); diff --git a/include/linux/usb/onboard_dev.h b/include/linux/usb/onboard_dev.h new file mode 100644 index 000000000000..b79db6d193c8 --- /dev/null +++ b/include/linux/usb/onboard_dev.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef __LINUX_USB_ONBOARD_DEV_H +#define __LINUX_USB_ONBOARD_DEV_H + +struct usb_device; +struct list_head; + +#if IS_ENABLED(CONFIG_USB_ONBOARD_DEV) +void onboard_dev_create_pdevs(struct usb_device *parent_dev, struct list_head *pdev_list); +void onboard_dev_destroy_pdevs(struct list_head *pdev_list); +#else +static inline void onboard_dev_create_pdevs(struct usb_device *parent_dev, + struct list_head *pdev_list) {} +static inline void onboard_dev_destroy_pdevs(struct list_head *pdev_list) {} +#endif + +#endif /* __LINUX_USB_ONBOARD_DEV_H */ diff --git a/include/linux/usb/onboard_hub.h b/include/linux/usb/onboard_hub.h deleted file mode 100644 index d9373230556e..000000000000 --- a/include/linux/usb/onboard_hub.h +++ /dev/null @@ -1,18 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ - -#ifndef __LINUX_USB_ONBOARD_HUB_H -#define __LINUX_USB_ONBOARD_HUB_H - -struct usb_device; -struct list_head; - -#if IS_ENABLED(CONFIG_USB_ONBOARD_HUB) -void onboard_hub_create_pdevs(struct usb_device *parent_hub, struct list_head *pdev_list); -void onboard_hub_destroy_pdevs(struct list_head *pdev_list); -#else -static inline void onboard_hub_create_pdevs(struct usb_device *parent_hub, - struct list_head *pdev_list) {} -static inline void onboard_hub_destroy_pdevs(struct list_head *pdev_list) {} -#endif - -#endif /* __LINUX_USB_ONBOARD_HUB_H */ -- cgit v1.2.3-59-g8ed1b From ff508c0e9707608f217bfc6b1a9166822150f3ea Mon Sep 17 00:00:00 2001 From: Javier Carrasco Date: Mon, 25 Mar 2024 10:15:13 +0100 Subject: drm: ci: arm64.config: update ONBOARD_USB_HUB to ONBOARD_USB_DEV The onboard_usb_hub driver has been updated to support non-hub devices, which has led to some renaming. Update to the new name (ONBOARD_USB_DEV) accordingly. Acked-by: Helen Koike Reviewed-by: Matthias Kaehlcke Signed-off-by: Javier Carrasco Link: https://lore.kernel.org/r/20240325-onboard_xvf3500-v8-3-29e3f9222922@wolfvision.net Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/ci/arm64.config | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/ci/arm64.config b/drivers/gpu/drm/ci/arm64.config index 8dbce9919a57..4140303d6260 100644 --- a/drivers/gpu/drm/ci/arm64.config +++ b/drivers/gpu/drm/ci/arm64.config @@ -87,7 +87,7 @@ CONFIG_DRM_PARADE_PS8640=y CONFIG_DRM_LONTIUM_LT9611UXC=y CONFIG_PHY_QCOM_USB_HS=y CONFIG_QCOM_GPI_DMA=y -CONFIG_USB_ONBOARD_HUB=y +CONFIG_USB_ONBOARD_DEV=y CONFIG_NVMEM_QCOM_QFPROM=y CONFIG_PHY_QCOM_USB_SNPS_FEMTO_V2=y @@ -97,7 +97,7 @@ CONFIG_USB_RTL8152=y # db820c ethernet CONFIG_ATL1C=y # Chromebooks ethernet -CONFIG_USB_ONBOARD_HUB=y +CONFIG_USB_ONBOARD_DEV=y # 888 HDK ethernet CONFIG_USB_LAN78XX=y -- cgit v1.2.3-59-g8ed1b From e00e3a14adcc3030c37f7b83f2bd060eef9a434d Mon Sep 17 00:00:00 2001 From: Javier Carrasco Date: Mon, 25 Mar 2024 10:15:14 +0100 Subject: arm64: defconfig: update ONBOARD_USB_HUB to ONBOARD_USB_DEV The onboard_usb_hub driver has been updated to support non-hub devices, which has led to some renaming. Update to the new name (ONBOARD_USB_DEV) accordingly. Reviewed-by: Matthias Kaehlcke Signed-off-by: Javier Carrasco Link: https://lore.kernel.org/r/20240325-onboard_xvf3500-v8-4-29e3f9222922@wolfvision.net Signed-off-by: Greg Kroah-Hartman --- arch/arm64/configs/defconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig index 2c30d617e180..fe1c55a41791 100644 --- a/arch/arm64/configs/defconfig +++ b/arch/arm64/configs/defconfig @@ -1060,7 +1060,7 @@ CONFIG_USB_SERIAL_FTDI_SIO=m CONFIG_USB_SERIAL_OPTION=m CONFIG_USB_QCOM_EUD=m CONFIG_USB_HSIC_USB3503=y -CONFIG_USB_ONBOARD_HUB=m +CONFIG_USB_ONBOARD_DEV=m CONFIG_NOP_USB_XCEIV=y CONFIG_USB_MXS_PHY=m CONFIG_USB_GADGET=y -- cgit v1.2.3-59-g8ed1b From 70ab96e92106ecd03b39a39ce58c6c237eb0be66 Mon Sep 17 00:00:00 2001 From: Javier Carrasco Date: Mon, 25 Mar 2024 10:15:15 +0100 Subject: ARM: multi_v7_defconfig: update ONBOARD_USB_HUB to ONBOAD_USB_DEV The onboard_usb_hub driver has been updated to support non-hub devices, which has led to some renaming. Update to the new name accordingly. Update to the new name (ONBOARD_USB_DEV) accordingly. Reviewed-by: Matthias Kaehlcke Signed-off-by: Javier Carrasco Link: https://lore.kernel.org/r/20240325-onboard_xvf3500-v8-5-29e3f9222922@wolfvision.net Signed-off-by: Greg Kroah-Hartman --- arch/arm/configs/multi_v7_defconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/configs/multi_v7_defconfig b/arch/arm/configs/multi_v7_defconfig index b2955dcb5a53..86bf057ac366 100644 --- a/arch/arm/configs/multi_v7_defconfig +++ b/arch/arm/configs/multi_v7_defconfig @@ -885,7 +885,7 @@ CONFIG_USB_CHIPIDEA_UDC=y CONFIG_USB_CHIPIDEA_HOST=y CONFIG_USB_ISP1760=y CONFIG_USB_HSIC_USB3503=y -CONFIG_USB_ONBOARD_HUB=m +CONFIG_USB_ONBOARD_DEV=m CONFIG_AB8500_USB=y CONFIG_KEYSTONE_USB_PHY=m CONFIG_NOP_USB_XCEIV=y -- cgit v1.2.3-59-g8ed1b From dd84ac9765410c4375f88457dcb86f126a5eb18d Mon Sep 17 00:00:00 2001 From: Javier Carrasco Date: Mon, 25 Mar 2024 10:15:16 +0100 Subject: usb: misc: onboard_dev: add support for non-hub devices Most of the functionality this driver provides can be used by non-hub devices as well. To account for the hub-specific code, add a flag to the device data structure and check its value for hub-specific code. The 'always_powered_in_supend' attribute is only available for hub devices, keeping the driver's default behavior for non-hub devices (keep on in suspend). Acked-by: Matthias Kaehlcke Signed-off-by: Javier Carrasco Link: https://lore.kernel.org/r/20240325-onboard_xvf3500-v8-6-29e3f9222922@wolfvision.net Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/onboard_usb_dev.c | 25 ++++++++++++++++++++++++- drivers/usb/misc/onboard_usb_dev.h | 11 +++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/drivers/usb/misc/onboard_usb_dev.c b/drivers/usb/misc/onboard_usb_dev.c index 6aee43896216..f72f47edd87e 100644 --- a/drivers/usb/misc/onboard_usb_dev.c +++ b/drivers/usb/misc/onboard_usb_dev.c @@ -261,7 +261,27 @@ static struct attribute *onboard_dev_attrs[] = { &dev_attr_always_powered_in_suspend.attr, NULL, }; -ATTRIBUTE_GROUPS(onboard_dev); + +static umode_t onboard_dev_attrs_are_visible(struct kobject *kobj, + struct attribute *attr, + int n) +{ + struct device *dev = kobj_to_dev(kobj); + struct onboard_dev *onboard_dev = dev_get_drvdata(dev); + + if (attr == &dev_attr_always_powered_in_suspend.attr && + !onboard_dev->pdata->is_hub) + return 0; + + return attr->mode; +} + +static const struct attribute_group onboard_dev_group = { + .is_visible = onboard_dev_attrs_are_visible, + .attrs = onboard_dev_attrs, +}; +__ATTRIBUTE_GROUPS(onboard_dev); + static void onboard_dev_attach_usb_driver(struct work_struct *work) { @@ -286,6 +306,9 @@ static int onboard_dev_probe(struct platform_device *pdev) if (!onboard_dev->pdata) return -EINVAL; + if (!onboard_dev->pdata->is_hub) + onboard_dev->always_powered_in_suspend = true; + onboard_dev->dev = dev; err = onboard_dev_get_regulators(onboard_dev); diff --git a/drivers/usb/misc/onboard_usb_dev.h b/drivers/usb/misc/onboard_usb_dev.h index debab2895a53..b6fd73f960bc 100644 --- a/drivers/usb/misc/onboard_usb_dev.h +++ b/drivers/usb/misc/onboard_usb_dev.h @@ -12,66 +12,77 @@ struct onboard_dev_pdata { unsigned long reset_us; /* reset pulse width in us */ unsigned int num_supplies; /* number of supplies */ const char * const supply_names[MAX_SUPPLIES]; + bool is_hub; }; static const struct onboard_dev_pdata microchip_usb424_data = { .reset_us = 1, .num_supplies = 1, .supply_names = { "vdd" }, + .is_hub = true, }; static const struct onboard_dev_pdata microchip_usb5744_data = { .reset_us = 0, .num_supplies = 2, .supply_names = { "vdd", "vdd2" }, + .is_hub = true, }; static const struct onboard_dev_pdata realtek_rts5411_data = { .reset_us = 0, .num_supplies = 1, .supply_names = { "vdd" }, + .is_hub = true, }; static const struct onboard_dev_pdata ti_tusb8020b_data = { .reset_us = 3000, .num_supplies = 1, .supply_names = { "vdd" }, + .is_hub = true, }; static const struct onboard_dev_pdata ti_tusb8041_data = { .reset_us = 3000, .num_supplies = 1, .supply_names = { "vdd" }, + .is_hub = true, }; static const struct onboard_dev_pdata cypress_hx3_data = { .reset_us = 10000, .num_supplies = 2, .supply_names = { "vdd", "vdd2" }, + .is_hub = true, }; static const struct onboard_dev_pdata cypress_hx2vl_data = { .reset_us = 1, .num_supplies = 1, .supply_names = { "vdd" }, + .is_hub = true, }; static const struct onboard_dev_pdata genesys_gl850g_data = { .reset_us = 3, .num_supplies = 1, .supply_names = { "vdd" }, + .is_hub = true, }; static const struct onboard_dev_pdata genesys_gl852g_data = { .reset_us = 50, .num_supplies = 1, .supply_names = { "vdd" }, + .is_hub = true, }; static const struct onboard_dev_pdata vialab_vl817_data = { .reset_us = 10, .num_supplies = 1, .supply_names = { "vdd" }, + .is_hub = true, }; static const struct of_device_id onboard_dev_match[] = { -- cgit v1.2.3-59-g8ed1b From 5b5858e467fa68c8aeeed1bd9256f2a284503ea2 Mon Sep 17 00:00:00 2001 From: Javier Carrasco Date: Mon, 25 Mar 2024 10:15:17 +0100 Subject: ASoC: dt-bindings: xmos,xvf3500: add XMOS XVF3500 voice processor The XMOS XVF3500 VocalFusion Voice Processor[1] is a low-latency, 32-bit multicore controller for voice processing. Add new bindings to define the device properties. [1] https://www.xmos.com/xvf3500/ Reviewed-by: Krzysztof Kozlowski Acked-by: Mark Brown Signed-off-by: Javier Carrasco Link: https://lore.kernel.org/r/20240325-onboard_xvf3500-v8-7-29e3f9222922@wolfvision.net Signed-off-by: Greg Kroah-Hartman --- .../devicetree/bindings/sound/xmos,xvf3500.yaml | 63 ++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/xmos,xvf3500.yaml diff --git a/Documentation/devicetree/bindings/sound/xmos,xvf3500.yaml b/Documentation/devicetree/bindings/sound/xmos,xvf3500.yaml new file mode 100644 index 000000000000..fb77a61f1350 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/xmos,xvf3500.yaml @@ -0,0 +1,63 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/xmos,xvf3500.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: XMOS XVF3500 VocalFusion Voice Processor + +maintainers: + - Javier Carrasco + +description: + The XMOS XVF3500 VocalFusion Voice Processor is a low-latency, 32-bit + multicore controller for voice processing. + https://www.xmos.com/xvf3500/ + +allOf: + - $ref: /schemas/usb/usb-device.yaml# + +properties: + compatible: + const: usb20b1,0013 + + reg: true + + reset-gpios: + maxItems: 1 + + vdd-supply: + description: + Regulator for the 1V0 supply. + + vddio-supply: + description: + Regulator for the 3V3 supply. + +required: + - compatible + - reg + - reset-gpios + - vdd-supply + - vddio-supply + +additionalProperties: false + +examples: + - | + #include + + usb { + #address-cells = <1>; + #size-cells = <0>; + + voice_processor: voice-processor@1 { + compatible = "usb20b1,0013"; + reg = <1>; + reset-gpios = <&gpio 5 GPIO_ACTIVE_LOW>; + vdd-supply = <&vcc1v0>; + vddio-supply = <&vcc3v3>; + }; + }; + +... -- cgit v1.2.3-59-g8ed1b From ef83531c8e4a5f2fc9c602be7e2a300de1575ee4 Mon Sep 17 00:00:00 2001 From: Javier Carrasco Date: Mon, 25 Mar 2024 10:15:18 +0100 Subject: usb: misc: onboard_dev: add support for XMOS XVF3500 The XMOS XVF3500 VocalFusion Voice Processor[1] is a low-latency, 32-bit multicore controller for voice processing. This device requires a specific power sequence, which consists of enabling the regulators that control the 3V3 and 1V0 device supplies, and a reset de-assertion after a delay of at least 100ns. Once in normal operation, the XVF3500 registers itself as a USB device, and it does not require any device-specific operations in the driver. [1] https://www.xmos.com/xvf3500/ Acked-by: Matthias Kaehlcke Signed-off-by: Javier Carrasco Link: https://lore.kernel.org/r/20240325-onboard_xvf3500-v8-8-29e3f9222922@wolfvision.net Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/onboard_usb_dev.c | 2 ++ drivers/usb/misc/onboard_usb_dev.h | 8 ++++++++ 2 files changed, 10 insertions(+) diff --git a/drivers/usb/misc/onboard_usb_dev.c b/drivers/usb/misc/onboard_usb_dev.c index f72f47edd87e..648ea933bdad 100644 --- a/drivers/usb/misc/onboard_usb_dev.c +++ b/drivers/usb/misc/onboard_usb_dev.c @@ -407,6 +407,7 @@ static struct platform_driver onboard_dev_driver = { #define VENDOR_ID_REALTEK 0x0bda #define VENDOR_ID_TI 0x0451 #define VENDOR_ID_VIA 0x2109 +#define VENDOR_ID_XMOS 0x20B1 /* * Returns the onboard_dev platform device that is associated with the USB @@ -501,6 +502,7 @@ static const struct usb_device_id onboard_dev_id_table[] = { { USB_DEVICE(VENDOR_ID_TI, 0x8142) }, /* TI USB8041 2.0 HUB */ { USB_DEVICE(VENDOR_ID_VIA, 0x0817) }, /* VIA VL817 3.1 HUB */ { USB_DEVICE(VENDOR_ID_VIA, 0x2817) }, /* VIA VL817 2.0 HUB */ + { USB_DEVICE(VENDOR_ID_XMOS, 0x0013) }, /* XMOS XVF3500 Voice Processor */ {} }; MODULE_DEVICE_TABLE(usb, onboard_dev_id_table); diff --git a/drivers/usb/misc/onboard_usb_dev.h b/drivers/usb/misc/onboard_usb_dev.h index b6fd73f960bc..fbba549c0f47 100644 --- a/drivers/usb/misc/onboard_usb_dev.h +++ b/drivers/usb/misc/onboard_usb_dev.h @@ -85,6 +85,13 @@ static const struct onboard_dev_pdata vialab_vl817_data = { .is_hub = true, }; +static const struct onboard_dev_pdata xmos_xvf3500_data = { + .reset_us = 1, + .num_supplies = 2, + .supply_names = { "vdd", "vddio" }, + .is_hub = false, +}; + static const struct of_device_id onboard_dev_match[] = { { .compatible = "usb424,2412", .data = µchip_usb424_data, }, { .compatible = "usb424,2514", .data = µchip_usb424_data, }, @@ -108,6 +115,7 @@ static const struct of_device_id onboard_dev_match[] = { { .compatible = "usbbda,5414", .data = &realtek_rts5411_data, }, { .compatible = "usb2109,817", .data = &vialab_vl817_data, }, { .compatible = "usb2109,2817", .data = &vialab_vl817_data, }, + { .compatible = "usb20b1,0013", .data = &xmos_xvf3500_data, }, {} }; -- cgit v1.2.3-59-g8ed1b From 0bb322be5d389c00740d884351d4ba08fca938aa Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Mon, 25 Mar 2024 17:14:09 -0500 Subject: driver core: Remove unused platform_notify, platform_notify_remove The "platform_notify" and "platform_notify_remove" hooks have been unused since 00ba9357d189 ("ARM: ixp4xx: Drop custom DMA coherency and bouncing"). Remove "platform_notify" and "platform_notify_remove". No functional change intended. Signed-off-by: Bjorn Helgaas Cc: Heikki Krogerus Cc: Linus Walleij Reviewed-by: Andy Shevchenko Acked-by: Rafael J. Wysocki Link: https://lore.kernel.org/r/20240325221409.1457036-1-helgaas@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/base/core.c | 8 -------- include/linux/device.h | 11 ----------- 2 files changed, 19 deletions(-) diff --git a/drivers/base/core.c b/drivers/base/core.c index b93f3c5716ae..78dfa74ee18b 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -2331,8 +2331,6 @@ static void fw_devlink_link_device(struct device *dev) /* Device links support end. */ -int (*platform_notify)(struct device *dev) = NULL; -int (*platform_notify_remove)(struct device *dev) = NULL; static struct kobject *dev_kobj; /* /sys/dev/char */ @@ -2380,16 +2378,10 @@ static void device_platform_notify(struct device *dev) acpi_device_notify(dev); software_node_notify(dev); - - if (platform_notify) - platform_notify(dev); } static void device_platform_notify_remove(struct device *dev) { - if (platform_notify_remove) - platform_notify_remove(dev); - software_node_notify_remove(dev); acpi_device_notify_remove(dev); diff --git a/include/linux/device.h b/include/linux/device.h index 97c4b046c09d..c515ba5756e4 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -1206,17 +1206,6 @@ int __must_check devm_device_add_groups(struct device *dev, int __must_check devm_device_add_group(struct device *dev, const struct attribute_group *grp); -/* - * Platform "fixup" functions - allow the platform to have their say - * about devices and actions that the general device layer doesn't - * know about. - */ -/* Notify platform of device discovery */ -extern int (*platform_notify)(struct device *dev); - -extern int (*platform_notify_remove)(struct device *dev); - - /* * get_device - atomically increment the reference count for the device. * -- cgit v1.2.3-59-g8ed1b From 3b938e231b660a278de2988ee77b832d665c5326 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sat, 23 Mar 2024 20:35:00 +0900 Subject: riscv: merge two if-blocks for KBUILD_IMAGE In arch/riscv/Makefile, KBUILD_IMAGE is assigned in two separate if-blocks. When CONFIG_XIP_KERNEL is disabled, the decision made by the first if-block is overwritten by the second one, which is redundant and unreadable. Merge the two if-blocks. Signed-off-by: Masahiro Yamada Reviewed-by: Alexandre Ghiti Link: https://lore.kernel.org/r/20240323113500.1249272-1-masahiroy@kernel.org Signed-off-by: Palmer Dabbelt --- arch/riscv/Makefile | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile index 252d63942f34..a74e70405d3f 100644 --- a/arch/riscv/Makefile +++ b/arch/riscv/Makefile @@ -133,7 +133,15 @@ boot := arch/riscv/boot ifeq ($(CONFIG_XIP_KERNEL),y) KBUILD_IMAGE := $(boot)/xipImage else +ifeq ($(CONFIG_RISCV_M_MODE)$(CONFIG_ARCH_CANAAN),yy) +KBUILD_IMAGE := $(boot)/loader.bin +else +ifeq ($(CONFIG_EFI_ZBOOT),) KBUILD_IMAGE := $(boot)/Image.gz +else +KBUILD_IMAGE := $(boot)/vmlinuz.efi +endif +endif endif libs-y += arch/riscv/lib/ @@ -153,17 +161,6 @@ endif vdso-install-y += arch/riscv/kernel/vdso/vdso.so.dbg vdso-install-$(CONFIG_COMPAT) += arch/riscv/kernel/compat_vdso/compat_vdso.so.dbg:../compat_vdso/compat_vdso.so -ifneq ($(CONFIG_XIP_KERNEL),y) -ifeq ($(CONFIG_RISCV_M_MODE)$(CONFIG_ARCH_CANAAN),yy) -KBUILD_IMAGE := $(boot)/loader.bin -else -ifeq ($(CONFIG_EFI_ZBOOT),) -KBUILD_IMAGE := $(boot)/Image.gz -else -KBUILD_IMAGE := $(boot)/vmlinuz.efi -endif -endif -endif BOOT_TARGETS := Image Image.gz loader loader.bin xipImage vmlinuz.efi all: $(notdir $(KBUILD_IMAGE)) -- cgit v1.2.3-59-g8ed1b From 36d37f11f555812b0ded5d15aa686a6b9da57f61 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sat, 23 Mar 2024 18:06:15 +0900 Subject: export.h: remove include/asm-generic/export.h Commit 3a6dd5f614a1 ("riscv: remove unneeded #include ") removed the last use of include/asm-generic/export.h. This deprecated header can go away. Signed-off-by: Masahiro Yamada Link: https://lore.kernel.org/r/20240323090615.1244904-1-masahiroy@kernel.org Signed-off-by: Palmer Dabbelt --- include/asm-generic/export.h | 11 ----------- 1 file changed, 11 deletions(-) delete mode 100644 include/asm-generic/export.h diff --git a/include/asm-generic/export.h b/include/asm-generic/export.h deleted file mode 100644 index 570cd4da7210..000000000000 --- a/include/asm-generic/export.h +++ /dev/null @@ -1,11 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -#ifndef __ASM_GENERIC_EXPORT_H -#define __ASM_GENERIC_EXPORT_H - -/* - * and are deprecated. - * Please include directly. - */ -#include - -#endif -- cgit v1.2.3-59-g8ed1b From 84c3a079ab98f729e9a968a201d9aa8d196195a1 Mon Sep 17 00:00:00 2001 From: "tanzirh@google.com" Date: Tue, 12 Dec 2023 00:20:14 +0000 Subject: riscv: remove unused header arch/riscv/kernel/sys_riscv.c builds without using anything from asm-generic/mman-common.h. There seems to be no reason to include this file. Signed-off-by: Tanzir Hasan Fixes: 9e2e6042a7ec ("riscv: Allow PROT_WRITE-only mmap()") Reviewed-by: Nick Desaulniers Tested-by: Nick Desaulniers Link: https://lore.kernel.org/r/20231212-removeasmgeneric-v2-1-a0e6d7df34a7@google.com Signed-off-by: Palmer Dabbelt --- arch/riscv/kernel/sys_riscv.c | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/riscv/kernel/sys_riscv.c b/arch/riscv/kernel/sys_riscv.c index f1c1416a9f1e..64155323cc92 100644 --- a/arch/riscv/kernel/sys_riscv.c +++ b/arch/riscv/kernel/sys_riscv.c @@ -7,7 +7,6 @@ #include #include -#include static long riscv_sys_mmap(unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags, -- cgit v1.2.3-59-g8ed1b From 542124fc0d5cccea273bccf2ee58545ac17aad3f Mon Sep 17 00:00:00 2001 From: Yangyu Chen Date: Wed, 10 Jan 2024 02:48:59 +0800 Subject: RISC-V: only flush icache when it has VM_EXEC set As I-Cache flush on current RISC-V needs to send IPIs to every CPU cores in the system is very costly, limiting flush_icache_mm to be called only when vma->vm_flags has VM_EXEC can help minimize the frequency of these operations. It improves performance and reduces disturbances when copy_from_user_page is needed such as profiling with perf. For I-D coherence concerns, it will not fail if such a page adds VM_EXEC flags in the future since we have checked it in the __set_pte_at function. Signed-off-by: Yangyu Chen Reviewed-by: Alexandre Ghiti Link: https://lore.kernel.org/r/tencent_6D851035F6F2FD0B5A69FB391AE39AC6300A@qq.com Signed-off-by: Palmer Dabbelt --- arch/riscv/include/asm/cacheflush.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/arch/riscv/include/asm/cacheflush.h b/arch/riscv/include/asm/cacheflush.h index a129dac4521d..dd8d07146116 100644 --- a/arch/riscv/include/asm/cacheflush.h +++ b/arch/riscv/include/asm/cacheflush.h @@ -33,8 +33,11 @@ static inline void flush_dcache_page(struct page *page) * so instead we just flush the whole thing. */ #define flush_icache_range(start, end) flush_icache_all() -#define flush_icache_user_page(vma, pg, addr, len) \ - flush_icache_mm(vma->vm_mm, 0) +#define flush_icache_user_page(vma, pg, addr, len) \ +do { \ + if (vma->vm_flags & VM_EXEC) \ + flush_icache_mm(vma->vm_mm, 0); \ +} while (0) #ifdef CONFIG_64BIT #define flush_cache_vmap(start, end) flush_tlb_kernel_range(start, end) -- cgit v1.2.3-59-g8ed1b From eeee3b5e6d0bf331befa57b4dcb079f827bcd829 Mon Sep 17 00:00:00 2001 From: Kai-Heng Feng Date: Wed, 27 Mar 2024 10:45:09 +0800 Subject: PCI: Mask Replay Timer Timeout errors for Genesys GL975x SD host controller Due to a hardware defect in GL975x, config accesses when ASPM is enabled frequently cause Replay Timer Timeouts in the Port leading to the device. These are Correctable Errors, so the Downstream Port logs it in its AER Correctable Error Status register and, when the error is not masked, sends an ERR_COR message upstream. The message terminates at a Root Port, which may generate an AER interrupt so the OS can log it. The Correctable Error logging is an annoyance but not a major issue itself. But when the AER interrupt happens during suspend, it can prevent the system from suspending. 015c9cbcf0ad ("mmc: sdhci-pci-gli: GL9750: Mask the replay timer timeout of AER") masked these errors in the GL975x itself. Mask these errors in the Port leading to GL975x as well. Note that Replay Timer Timeouts will still be logged in the AER Correctable Error Status register, but they will not cause AER interrupts. Link: https://lore.kernel.org/r/20240327024509.1071189-1-kai.heng.feng@canonical.com Signed-off-by: Kai-Heng Feng [bhelgaas: commit log, update dmesg note] Signed-off-by: Bjorn Helgaas Cc: Victor Shih Cc: Ben Chuang --- drivers/pci/quirks.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index bf4833221816..5cb0f7fae3b8 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -6261,3 +6261,23 @@ static void pci_fixup_d3cold_delay_1sec(struct pci_dev *pdev) pdev->d3cold_delay = 1000; } DECLARE_PCI_FIXUP_FINAL(0x5555, 0x0004, pci_fixup_d3cold_delay_1sec); + +#ifdef CONFIG_PCIEAER +static void pci_mask_replay_timer_timeout(struct pci_dev *pdev) +{ + struct pci_dev *parent = pci_upstream_bridge(pdev); + u32 val; + + if (!parent || !parent->aer_cap) + return; + + pci_info(parent, "mask Replay Timer Timeout Correctable Errors due to %s hardware defect", + pci_name(pdev)); + + pci_read_config_dword(parent, parent->aer_cap + PCI_ERR_COR_MASK, &val); + val |= PCI_ERR_COR_REP_TIMER; + pci_write_config_dword(parent, parent->aer_cap + PCI_ERR_COR_MASK, val); +} +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_GLI, 0x9750, pci_mask_replay_timer_timeout); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_GLI, 0x9755, pci_mask_replay_timer_timeout); +#endif -- cgit v1.2.3-59-g8ed1b From 8b7149803af174f3184d97c779faa1c7608da5af Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Tue, 26 Mar 2024 14:22:56 +0530 Subject: MAINTAINERS: Drop Gustavo Pimentel as EDMA Reviewer Gustavo Pimentel seems to have left Synopsys, so his email is bouncing. And there is no indication from him expressing willingness to continue contributing to the driver. So let's drop him from the MAINTAINERS entry. Signed-off-by: Manivannan Sadhasivam Reviewed-by: Serge Semin Link: https://lore.kernel.org/r/20240326085256.12639-1-manivannan.sadhasivam@linaro.org Signed-off-by: Vinod Koul --- MAINTAINERS | 1 - 1 file changed, 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index aa3b947fb080..9038abd8411e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6067,7 +6067,6 @@ F: drivers/mtd/nand/raw/denali* DESIGNWARE EDMA CORE IP DRIVER M: Manivannan Sadhasivam -R: Gustavo Pimentel R: Serge Semin L: dmaengine@vger.kernel.org S: Maintained -- cgit v1.2.3-59-g8ed1b From e6c6fea5c314d90dbfca4983f2ea46388aab3bb0 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Tue, 5 Mar 2024 17:22:34 +0100 Subject: backlight: Match backlight device against struct fb_info.bl_dev Framebuffer drivers for devices with dedicated backlight are supposed to set struct fb_info.bl_dev to the backlight's respective device. Use the value to match backlight and framebuffer in the backlight core code. The code first tests against struct backlight_ops.check_ops. If this test succeeds, it performs the test against fbdev. So backlight drivers can override the later test as before. Fbdev's backlight support depends on CONFIG_FB_BACKLIGHT. To avoid ifdef in the code, the new helper fb_bl_device() returns the backlight device, or NULL if the config option has been disabled. The test in the backlight code will then do nothing. v4: * declare empty fb_bl_device() as static inline * export fb_bl_device() v3: * hide ifdef in fb_bl_device() (Lee) * no if-else blocks (Andy) Signed-off-by: Thomas Zimmermann Reviewed-by: Daniel Thompson Reviewed-by: Javier Martinez Canillas Link: https://lore.kernel.org/r/20240305162425.23845-2-tzimmermann@suse.de Signed-off-by: Lee Jones --- drivers/video/backlight/backlight.c | 8 ++++++-- drivers/video/fbdev/core/fb_backlight.c | 6 ++++++ include/linux/fb.h | 9 +++++++++ 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c index 86e1cdc8e369..4f7973c6fcc7 100644 --- a/drivers/video/backlight/backlight.c +++ b/drivers/video/backlight/backlight.c @@ -98,7 +98,9 @@ static int fb_notifier_callback(struct notifier_block *self, { struct backlight_device *bd; struct fb_event *evdata = data; - int node = evdata->info->node; + struct fb_info *info = evdata->info; + struct backlight_device *fb_bd = fb_bl_device(info); + int node = info->node; int fb_blank = 0; /* If we aren't interested in this event, skip it immediately ... */ @@ -110,7 +112,9 @@ static int fb_notifier_callback(struct notifier_block *self, if (!bd->ops) goto out; - if (bd->ops->check_fb && !bd->ops->check_fb(bd, evdata->info)) + if (bd->ops->check_fb && !bd->ops->check_fb(bd, info)) + goto out; + if (fb_bd && fb_bd != bd) goto out; fb_blank = *(int *)evdata->data; diff --git a/drivers/video/fbdev/core/fb_backlight.c b/drivers/video/fbdev/core/fb_backlight.c index e2d3b3adc870..6fdaa9f81be9 100644 --- a/drivers/video/fbdev/core/fb_backlight.c +++ b/drivers/video/fbdev/core/fb_backlight.c @@ -30,4 +30,10 @@ void fb_bl_default_curve(struct fb_info *fb_info, u8 off, u8 min, u8 max) mutex_unlock(&fb_info->bl_curve_mutex); } EXPORT_SYMBOL_GPL(fb_bl_default_curve); + +struct backlight_device *fb_bl_device(struct fb_info *info) +{ + return info->bl_dev; +} +EXPORT_SYMBOL(fb_bl_device); #endif diff --git a/include/linux/fb.h b/include/linux/fb.h index 0dd27364d56f..75c5f800467c 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -738,6 +738,15 @@ extern struct fb_info *framebuffer_alloc(size_t size, struct device *dev); extern void framebuffer_release(struct fb_info *info); extern void fb_bl_default_curve(struct fb_info *fb_info, u8 off, u8 min, u8 max); +#if IS_ENABLED(CONFIG_FB_BACKLIGHT) +struct backlight_device *fb_bl_device(struct fb_info *info); +#else +static inline struct backlight_device *fb_bl_device(struct fb_info *info) +{ + return NULL; +} +#endif + /* fbmon.c */ #define FB_MAXTIMINGS 0 #define FB_VSYNCTIMINGS 1 -- cgit v1.2.3-59-g8ed1b From 330682161d8702880ec72e9f4ea982deba9935dc Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Tue, 5 Mar 2024 17:22:35 +0100 Subject: auxdisplay: ht16k33: Remove struct backlight_ops.check_fb The driver sets struct fb_info.bl_dev to the correct backlight device. Thus rely on the backlight core code to match backlight and framebuffer devices, and remove the extra check_fb() function from struct backlight_ops. v3: * use 'check_fb()' in commit message (Andy) Signed-off-by: Thomas Zimmermann Cc: Robin van der Gracht Acked-by: Robin van der Gracht Acked-by: Andy Shevchenko Reviewed-by: Javier Martinez Canillas Link: https://lore.kernel.org/r/20240305162425.23845-3-tzimmermann@suse.de Signed-off-by: Lee Jones --- drivers/auxdisplay/ht16k33.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/auxdisplay/ht16k33.c b/drivers/auxdisplay/ht16k33.c index 96acfb2b58cd..82e55d61893b 100644 --- a/drivers/auxdisplay/ht16k33.c +++ b/drivers/auxdisplay/ht16k33.c @@ -295,16 +295,8 @@ static int ht16k33_bl_update_status(struct backlight_device *bl) return ht16k33_brightness_set(priv, brightness); } -static int ht16k33_bl_check_fb(struct backlight_device *bl, struct fb_info *fi) -{ - struct ht16k33_priv *priv = bl_get_data(bl); - - return (fi == NULL) || (fi->par == priv); -} - static const struct backlight_ops ht16k33_bl_ops = { .update_status = ht16k33_bl_update_status, - .check_fb = ht16k33_bl_check_fb, }; /* -- cgit v1.2.3-59-g8ed1b From e755554568fbe638bb69f0faffb116436ec28af2 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Tue, 5 Mar 2024 17:22:36 +0100 Subject: hid: hid-picolcd: Fix initialization order MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For drivers that support backlight, LCD and fbdev devices, fbdev has to be initialized last. See documentation for struct fbinfo.bl_dev. Signed-off-by: Thomas Zimmermann Cc: Bruno Prémont Reviewed-by: Javier Martinez Canillas Link: https://lore.kernel.org/r/20240305162425.23845-4-tzimmermann@suse.de Signed-off-by: Lee Jones --- drivers/hid/hid-picolcd_core.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/hid/hid-picolcd_core.c b/drivers/hid/hid-picolcd_core.c index bbda231a7ce3..5ddebe25eb91 100644 --- a/drivers/hid/hid-picolcd_core.c +++ b/drivers/hid/hid-picolcd_core.c @@ -474,11 +474,6 @@ static int picolcd_probe_lcd(struct hid_device *hdev, struct picolcd_data *data) if (error) goto err; - /* Set up the framebuffer device */ - error = picolcd_init_framebuffer(data); - if (error) - goto err; - /* Setup lcd class device */ error = picolcd_init_lcd(data, picolcd_out_report(REPORT_CONTRAST, hdev)); if (error) @@ -489,6 +484,11 @@ static int picolcd_probe_lcd(struct hid_device *hdev, struct picolcd_data *data) if (error) goto err; + /* Set up the framebuffer device */ + error = picolcd_init_framebuffer(data); + if (error) + goto err; + /* Setup the LED class devices */ error = picolcd_init_leds(data, picolcd_out_report(REPORT_LED_STATE, hdev)); if (error) @@ -502,9 +502,9 @@ static int picolcd_probe_lcd(struct hid_device *hdev, struct picolcd_data *data) return 0; err: picolcd_exit_leds(data); + picolcd_exit_framebuffer(data); picolcd_exit_backlight(data); picolcd_exit_lcd(data); - picolcd_exit_framebuffer(data); picolcd_exit_cir(data); picolcd_exit_keys(data); return error; @@ -623,9 +623,9 @@ static void picolcd_remove(struct hid_device *hdev) /* Cleanup LED */ picolcd_exit_leds(data); /* Clean up the framebuffer */ + picolcd_exit_framebuffer(data); picolcd_exit_backlight(data); picolcd_exit_lcd(data); - picolcd_exit_framebuffer(data); /* Cleanup input */ picolcd_exit_cir(data); picolcd_exit_keys(data); -- cgit v1.2.3-59-g8ed1b From c34b107770ed6643ea999d7be3566f54ec065239 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Tue, 5 Mar 2024 17:22:37 +0100 Subject: hid: hid-picolcd: Remove struct backlight_ops.check_fb MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update the driver to initialize struct fb_info.bl_dev to its backlight device, if any. Thus rely on the backlight core code to match backlight and framebuffer devices, and remove the extra check_fb function from struct backlight_ops. v2: * protect against CONFIG_FB_BACKLIGHT (Javier, kernel test robot) * reword commit message (Daniel) Signed-off-by: Thomas Zimmermann Cc: Bruno Prémont Reviewed-by: Javier Martinez Canillas Link: https://lore.kernel.org/r/20240305162425.23845-5-tzimmermann@suse.de Signed-off-by: Lee Jones --- drivers/hid/hid-picolcd_backlight.c | 7 ------- drivers/hid/hid-picolcd_fb.c | 6 ++++++ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/hid/hid-picolcd_backlight.c b/drivers/hid/hid-picolcd_backlight.c index 5bd2a8c4bbd6..08d16917eb60 100644 --- a/drivers/hid/hid-picolcd_backlight.c +++ b/drivers/hid/hid-picolcd_backlight.c @@ -9,7 +9,6 @@ #include -#include #include #include "hid-picolcd.h" @@ -39,15 +38,9 @@ static int picolcd_set_brightness(struct backlight_device *bdev) return 0; } -static int picolcd_check_bl_fb(struct backlight_device *bdev, struct fb_info *fb) -{ - return fb && fb == picolcd_fbinfo((struct picolcd_data *)bl_get_data(bdev)); -} - static const struct backlight_ops picolcd_blops = { .update_status = picolcd_set_brightness, .get_brightness = picolcd_get_brightness, - .check_fb = picolcd_check_bl_fb, }; int picolcd_init_backlight(struct picolcd_data *data, struct hid_report *report) diff --git a/drivers/hid/hid-picolcd_fb.c b/drivers/hid/hid-picolcd_fb.c index d7dddd99d325..750206f5fc67 100644 --- a/drivers/hid/hid-picolcd_fb.c +++ b/drivers/hid/hid-picolcd_fb.c @@ -493,6 +493,12 @@ int picolcd_init_framebuffer(struct picolcd_data *data) info->fix = picolcdfb_fix; info->fix.smem_len = PICOLCDFB_SIZE*8; +#ifdef CONFIG_FB_BACKLIGHT +#ifdef CONFIG_HID_PICOLCD_BACKLIGHT + info->bl_dev = data->backlight; +#endif +#endif + fbdata = info->par; spin_lock_init(&fbdata->lock); fbdata->picolcd = data; -- cgit v1.2.3-59-g8ed1b From 0133952aaca26f91f8c667b1c2f0c2f68d9db242 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Tue, 5 Mar 2024 17:22:38 +0100 Subject: backlight: aat2870-backlight: Remove struct backlight.check_fb The driver's implementation of check_fb always returns true, which is the default if no implementation has been set. So remove the code from the driver. Signed-off-by: Thomas Zimmermann Reviewed-by: Daniel Thompson Reviewed-by: Javier Martinez Canillas Link: https://lore.kernel.org/r/20240305162425.23845-6-tzimmermann@suse.de Signed-off-by: Lee Jones --- drivers/video/backlight/aat2870_bl.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/video/backlight/aat2870_bl.c b/drivers/video/backlight/aat2870_bl.c index 81fde3abb92c..b4c3354a1a8a 100644 --- a/drivers/video/backlight/aat2870_bl.c +++ b/drivers/video/backlight/aat2870_bl.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include @@ -90,15 +89,9 @@ static int aat2870_bl_update_status(struct backlight_device *bd) return 0; } -static int aat2870_bl_check_fb(struct backlight_device *bd, struct fb_info *fi) -{ - return 1; -} - static const struct backlight_ops aat2870_bl_ops = { .options = BL_CORE_SUSPENDRESUME, .update_status = aat2870_bl_update_status, - .check_fb = aat2870_bl_check_fb, }; static int aat2870_bl_probe(struct platform_device *pdev) -- cgit v1.2.3-59-g8ed1b From 397b7493729288ac308c5f4ff3496eaeb1080293 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Tue, 5 Mar 2024 17:22:39 +0100 Subject: backlight: pwm-backlight: Remove struct backlight_ops.check_fb MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The internal check_fb callback from struct pwm_bl_data is never implemented. The driver's implementation of check_fb always returns true, which is the backlight core's default if no implementation has been set. So remove the code from the driver. v2: * reword commit message Signed-off-by: Thomas Zimmermann Cc: Uwe Kleine-König Acked-by: Uwe Kleine-König Reviewed-by: Daniel Thompson Reviewed-by: Javier Martinez Canillas Link: https://lore.kernel.org/r/20240305162425.23845-7-tzimmermann@suse.de Signed-off-by: Lee Jones --- drivers/video/backlight/pwm_bl.c | 12 ------------ include/linux/pwm_backlight.h | 1 - 2 files changed, 13 deletions(-) diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c index ffcebf6aa76a..61d30bc98eea 100644 --- a/drivers/video/backlight/pwm_bl.c +++ b/drivers/video/backlight/pwm_bl.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include @@ -34,7 +33,6 @@ struct pwm_bl_data { int brightness); void (*notify_after)(struct device *, int brightness); - int (*check_fb)(struct device *, struct fb_info *); void (*exit)(struct device *); }; @@ -129,17 +127,8 @@ static int pwm_backlight_update_status(struct backlight_device *bl) return 0; } -static int pwm_backlight_check_fb(struct backlight_device *bl, - struct fb_info *info) -{ - struct pwm_bl_data *pb = bl_get_data(bl); - - return !pb->check_fb || pb->check_fb(pb->dev, info); -} - static const struct backlight_ops pwm_backlight_ops = { .update_status = pwm_backlight_update_status, - .check_fb = pwm_backlight_check_fb, }; #ifdef CONFIG_OF @@ -482,7 +471,6 @@ static int pwm_backlight_probe(struct platform_device *pdev) pb->notify = data->notify; pb->notify_after = data->notify_after; - pb->check_fb = data->check_fb; pb->exit = data->exit; pb->dev = &pdev->dev; pb->enabled = false; diff --git a/include/linux/pwm_backlight.h b/include/linux/pwm_backlight.h index cdd2ac366bc7..0bf80e98d5b4 100644 --- a/include/linux/pwm_backlight.h +++ b/include/linux/pwm_backlight.h @@ -19,7 +19,6 @@ struct platform_pwm_backlight_data { int (*notify)(struct device *dev, int brightness); void (*notify_after)(struct device *dev, int brightness); void (*exit)(struct device *dev); - int (*check_fb)(struct device *dev, struct fb_info *info); }; #endif -- cgit v1.2.3-59-g8ed1b From 8a8e7f84c13c2700ae77540e2841922a87f71c9b Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Tue, 5 Mar 2024 17:22:40 +0100 Subject: fbdev: sh_mobile_lcdc_fb: Remove struct backlight_ops.check_fb The driver sets struct fb_info.bl_dev to the correct backlight device. Thus rely on the backlight core code to match backlight and framebuffer devices, and remove the extra check_fb function from struct backlight_ops. Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Link: https://lore.kernel.org/r/20240305162425.23845-8-tzimmermann@suse.de Signed-off-by: Lee Jones --- drivers/video/fbdev/sh_mobile_lcdcfb.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/video/fbdev/sh_mobile_lcdcfb.c b/drivers/video/fbdev/sh_mobile_lcdcfb.c index eb2297b37504..bf34c8ec1a26 100644 --- a/drivers/video/fbdev/sh_mobile_lcdcfb.c +++ b/drivers/video/fbdev/sh_mobile_lcdcfb.c @@ -2140,17 +2140,10 @@ static int sh_mobile_lcdc_get_brightness(struct backlight_device *bdev) return ch->bl_brightness; } -static int sh_mobile_lcdc_check_fb(struct backlight_device *bdev, - struct fb_info *info) -{ - return (info->bl_dev == bdev); -} - static const struct backlight_ops sh_mobile_lcdc_bl_ops = { .options = BL_CORE_SUSPENDRESUME, .update_status = sh_mobile_lcdc_update_bl, .get_brightness = sh_mobile_lcdc_get_brightness, - .check_fb = sh_mobile_lcdc_check_fb, }; static struct backlight_device *sh_mobile_lcdc_bl_probe(struct device *parent, -- cgit v1.2.3-59-g8ed1b From 56a6f83f764a983c12f059847d82fd7b64bacd2a Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Tue, 5 Mar 2024 17:22:41 +0100 Subject: fbdev: ssd1307fb: Init backlight before registering framebuffer For drivers that support backlight, LCD and fbdev devices, fbdev has to be initialized last. See documentation for struct fbinfo.bl_dev. The backlight name's index number comes from register_framebuffer(), which now happens after initializing the backlight device. So like in all other backlight drivers, we now give the backlight device a generic name without the fbdev index. Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Link: https://lore.kernel.org/r/20240305162425.23845-9-tzimmermann@suse.de Signed-off-by: Lee Jones --- drivers/video/fbdev/ssd1307fb.c | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/drivers/video/fbdev/ssd1307fb.c b/drivers/video/fbdev/ssd1307fb.c index 1a4f90ea7d5a..0d1590c61eb0 100644 --- a/drivers/video/fbdev/ssd1307fb.c +++ b/drivers/video/fbdev/ssd1307fb.c @@ -594,7 +594,6 @@ static int ssd1307fb_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct backlight_device *bl; - char bl_name[12]; struct fb_info *info; struct fb_deferred_io *ssd1307fb_defio; u32 vmem_size; @@ -733,31 +732,30 @@ static int ssd1307fb_probe(struct i2c_client *client) if (ret) goto regulator_enable_error; - ret = register_framebuffer(info); - if (ret) { - dev_err(dev, "Couldn't register the framebuffer\n"); - goto panel_init_error; - } - - snprintf(bl_name, sizeof(bl_name), "ssd1307fb%d", info->node); - bl = backlight_device_register(bl_name, dev, par, &ssd1307fb_bl_ops, + bl = backlight_device_register("ssd1307fb-bl", dev, par, &ssd1307fb_bl_ops, NULL); if (IS_ERR(bl)) { ret = PTR_ERR(bl); dev_err(dev, "unable to register backlight device: %d\n", ret); - goto bl_init_error; + goto panel_init_error; + } + info->bl_dev = bl; + + ret = register_framebuffer(info); + if (ret) { + dev_err(dev, "Couldn't register the framebuffer\n"); + goto fb_init_error; } bl->props.brightness = par->contrast; bl->props.max_brightness = MAX_CONTRAST; - info->bl_dev = bl; dev_info(dev, "fb%d: %s framebuffer device registered, using %d bytes of video memory\n", info->node, info->fix.id, vmem_size); return 0; -bl_init_error: - unregister_framebuffer(info); +fb_init_error: + backlight_device_unregister(bl); panel_init_error: pwm_disable(par->pwm); pwm_put(par->pwm); -- cgit v1.2.3-59-g8ed1b From 7929446702295f7e336c13b39302589070f11560 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Tue, 5 Mar 2024 17:22:42 +0100 Subject: fbdev: ssd1307fb: Remove struct backlight_ops.check_fb The driver sets struct fb_info.bl_dev to the correct backlight device. Thus rely on the backlight core code to match backlight and framebuffer devices, and remove the extra check_fb function from struct backlight_ops. Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Link: https://lore.kernel.org/r/20240305162425.23845-10-tzimmermann@suse.de Signed-off-by: Lee Jones --- drivers/video/fbdev/ssd1307fb.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/video/fbdev/ssd1307fb.c b/drivers/video/fbdev/ssd1307fb.c index 0d1590c61eb0..3f30af3c059e 100644 --- a/drivers/video/fbdev/ssd1307fb.c +++ b/drivers/video/fbdev/ssd1307fb.c @@ -530,17 +530,10 @@ static int ssd1307fb_get_brightness(struct backlight_device *bdev) return par->contrast; } -static int ssd1307fb_check_fb(struct backlight_device *bdev, - struct fb_info *info) -{ - return (info->bl_dev == bdev); -} - static const struct backlight_ops ssd1307fb_bl_ops = { .options = BL_CORE_SUSPENDRESUME, .update_status = ssd1307fb_update_bl, .get_brightness = ssd1307fb_get_brightness, - .check_fb = ssd1307fb_check_fb, }; static struct ssd1307fb_deviceinfo ssd1307fb_ssd1305_deviceinfo = { -- cgit v1.2.3-59-g8ed1b From 0a4be7263749945a3882f7a0e2e5b1c45c31064e Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Tue, 5 Mar 2024 17:22:43 +0100 Subject: backlight: Add controls_device callback to struct backlight_ops Replace check_fb with controls_device in struct backlight_ops. The new callback interface takes a Linux device instead of a framebuffer. Resolves one of the dependencies of backlight.h on fb.h. The few drivers that had custom implementations of check_fb can easily use the framebuffer's Linux device instead. Update them accordingly. Signed-off-by: Thomas Zimmermann Reviewed-by: Daniel Thompson Reviewed-by: Javier Martinez Canillas Link: https://lore.kernel.org/r/20240305162425.23845-11-tzimmermann@suse.de Signed-off-by: Lee Jones --- drivers/video/backlight/backlight.c | 2 +- drivers/video/backlight/bd6107.c | 12 ++++++------ drivers/video/backlight/gpio_backlight.c | 12 ++++++------ drivers/video/backlight/lv5207lp.c | 12 ++++++------ include/linux/backlight.h | 16 ++++++++-------- 5 files changed, 27 insertions(+), 27 deletions(-) diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c index 4f7973c6fcc7..2bd4299206ae 100644 --- a/drivers/video/backlight/backlight.c +++ b/drivers/video/backlight/backlight.c @@ -112,7 +112,7 @@ static int fb_notifier_callback(struct notifier_block *self, if (!bd->ops) goto out; - if (bd->ops->check_fb && !bd->ops->check_fb(bd, info)) + if (bd->ops->controls_device && !bd->ops->controls_device(bd, info->device)) goto out; if (fb_bd && fb_bd != bd) goto out; diff --git a/drivers/video/backlight/bd6107.c b/drivers/video/backlight/bd6107.c index b1e7126380ef..6be2c67ba85c 100644 --- a/drivers/video/backlight/bd6107.c +++ b/drivers/video/backlight/bd6107.c @@ -99,18 +99,18 @@ static int bd6107_backlight_update_status(struct backlight_device *backlight) return 0; } -static int bd6107_backlight_check_fb(struct backlight_device *backlight, - struct fb_info *info) +static bool bd6107_backlight_controls_device(struct backlight_device *backlight, + struct device *display_dev) { struct bd6107 *bd = bl_get_data(backlight); - return !bd->pdata->dev || bd->pdata->dev == info->device; + return !bd->pdata->dev || bd->pdata->dev == display_dev; } static const struct backlight_ops bd6107_backlight_ops = { - .options = BL_CORE_SUSPENDRESUME, - .update_status = bd6107_backlight_update_status, - .check_fb = bd6107_backlight_check_fb, + .options = BL_CORE_SUSPENDRESUME, + .update_status = bd6107_backlight_update_status, + .controls_device = bd6107_backlight_controls_device, }; static int bd6107_probe(struct i2c_client *client) diff --git a/drivers/video/backlight/gpio_backlight.c b/drivers/video/backlight/gpio_backlight.c index e0c8c2a3f5dc..4476c317ce29 100644 --- a/drivers/video/backlight/gpio_backlight.c +++ b/drivers/video/backlight/gpio_backlight.c @@ -30,18 +30,18 @@ static int gpio_backlight_update_status(struct backlight_device *bl) return 0; } -static int gpio_backlight_check_fb(struct backlight_device *bl, - struct fb_info *info) +static bool gpio_backlight_controls_device(struct backlight_device *bl, + struct device *display_dev) { struct gpio_backlight *gbl = bl_get_data(bl); - return !gbl->dev || gbl->dev == info->device; + return !gbl->dev || gbl->dev == display_dev; } static const struct backlight_ops gpio_backlight_ops = { - .options = BL_CORE_SUSPENDRESUME, - .update_status = gpio_backlight_update_status, - .check_fb = gpio_backlight_check_fb, + .options = BL_CORE_SUSPENDRESUME, + .update_status = gpio_backlight_update_status, + .controls_device = gpio_backlight_controls_device, }; static int gpio_backlight_probe(struct platform_device *pdev) diff --git a/drivers/video/backlight/lv5207lp.c b/drivers/video/backlight/lv5207lp.c index 1f1d06b4e119..0cf00fee0f60 100644 --- a/drivers/video/backlight/lv5207lp.c +++ b/drivers/video/backlight/lv5207lp.c @@ -62,18 +62,18 @@ static int lv5207lp_backlight_update_status(struct backlight_device *backlight) return 0; } -static int lv5207lp_backlight_check_fb(struct backlight_device *backlight, - struct fb_info *info) +static bool lv5207lp_backlight_controls_device(struct backlight_device *backlight, + struct device *display_dev) { struct lv5207lp *lv = bl_get_data(backlight); - return !lv->pdata->dev || lv->pdata->dev == info->device; + return !lv->pdata->dev || lv->pdata->dev == display_dev; } static const struct backlight_ops lv5207lp_backlight_ops = { - .options = BL_CORE_SUSPENDRESUME, - .update_status = lv5207lp_backlight_update_status, - .check_fb = lv5207lp_backlight_check_fb, + .options = BL_CORE_SUSPENDRESUME, + .update_status = lv5207lp_backlight_update_status, + .controls_device = lv5207lp_backlight_controls_device, }; static int lv5207lp_probe(struct i2c_client *client) diff --git a/include/linux/backlight.h b/include/linux/backlight.h index 614653e07e3a..2db4c70053c4 100644 --- a/include/linux/backlight.h +++ b/include/linux/backlight.h @@ -13,6 +13,7 @@ #include #include #include +#include /** * enum backlight_update_reason - what method was used to update backlight @@ -110,7 +111,6 @@ enum backlight_scale { }; struct backlight_device; -struct fb_info; /** * struct backlight_ops - backlight operations @@ -160,18 +160,18 @@ struct backlight_ops { int (*get_brightness)(struct backlight_device *); /** - * @check_fb: Check the framebuffer device. + * @controls_device: Check against the display device * - * Check if given framebuffer device is the one bound to this backlight. - * This operation is optional and if not implemented it is assumed that the - * fbdev is always the one bound to the backlight. + * Check if the backlight controls the given display device. This + * operation is optional and if not implemented it is assumed that + * the display is always the one controlled by the backlight. * * RETURNS: * - * If info is NULL or the info matches the fbdev bound to the backlight return true. - * If info does not match the fbdev bound to the backlight return false. + * If display_dev is NULL or display_dev matches the device controlled by + * the backlight, return true. Otherwise return false. */ - int (*check_fb)(struct backlight_device *bd, struct fb_info *info); + bool (*controls_device)(struct backlight_device *bd, struct device *display_dev); }; /** -- cgit v1.2.3-59-g8ed1b From 899dbfb28b7941c381431a05c4a9ada42daf9507 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Tue, 19 Mar 2024 10:37:20 +0100 Subject: auxdisplay: ht16k33: Replace use of fb_blank with backlight helper Replace the use of struct backlight_properties.fb_blank with a call to backlight_get_brightness(). The helper implements similar logic as the driver's function. It also accounts for BL_CORE_SUSPENDED for drivers that set BL_CORE_SUSPENDRESUME. Ht16k33 doesn't use this, so there's no change in behaviour here. Signed-off-by: Thomas Zimmermann Cc: Robin van der Gracht Cc: Miguel Ojeda Reviewed-by: Sam Ravnborg Reviewed-by: Geert Uytterhoeven Reviewed-by: Miguel Ojeda Reviewed-by: Robin van der Gracht Reviewed-by: Dan Carpenter Link: https://lore.kernel.org/r/20240319093915.31778-2-tzimmermann@suse.de Signed-off-by: Lee Jones --- drivers/auxdisplay/ht16k33.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/auxdisplay/ht16k33.c b/drivers/auxdisplay/ht16k33.c index 96acfb2b58cd..70a7b88709ff 100644 --- a/drivers/auxdisplay/ht16k33.c +++ b/drivers/auxdisplay/ht16k33.c @@ -284,14 +284,9 @@ static int ht16k33_initialize(struct ht16k33_priv *priv) static int ht16k33_bl_update_status(struct backlight_device *bl) { - int brightness = bl->props.brightness; + const int brightness = backlight_get_brightness(bl); struct ht16k33_priv *priv = bl_get_data(bl); - if (bl->props.power != FB_BLANK_UNBLANK || - bl->props.fb_blank != FB_BLANK_UNBLANK || - bl->props.state & BL_CORE_FBBLANK) - brightness = 0; - return ht16k33_brightness_set(priv, brightness); } -- cgit v1.2.3-59-g8ed1b From b7ad4c67ed945524ab38bd61676e684eff84fc2a Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Tue, 19 Mar 2024 10:37:21 +0100 Subject: backlight: omap1: Remove unused struct omap_backlight_config.set_power The callback set_power in struct omap_backlight_config is not implemented anywhere. Remove it from the structure and driver. Signed-off-by: Thomas Zimmermann Reviewed-by: Sam Ravnborg Reviewed-by: Daniel Thompson Reviewed-by: Dan Carpenter Link: https://lore.kernel.org/r/20240319093915.31778-3-tzimmermann@suse.de Signed-off-by: Lee Jones --- drivers/video/backlight/omap1_bl.c | 3 --- include/linux/platform_data/omap1_bl.h | 1 - 2 files changed, 4 deletions(-) diff --git a/drivers/video/backlight/omap1_bl.c b/drivers/video/backlight/omap1_bl.c index 69a49384b3de..84d148f38595 100644 --- a/drivers/video/backlight/omap1_bl.c +++ b/drivers/video/backlight/omap1_bl.c @@ -39,9 +39,6 @@ static inline void omapbl_send_enable(int enable) static void omapbl_blank(struct omap_backlight *bl, int mode) { - if (bl->pdata->set_power) - bl->pdata->set_power(bl->dev, mode); - switch (mode) { case FB_BLANK_NORMAL: case FB_BLANK_VSYNC_SUSPEND: diff --git a/include/linux/platform_data/omap1_bl.h b/include/linux/platform_data/omap1_bl.h index 5e8b17d77a5f..3d0bab31a0a9 100644 --- a/include/linux/platform_data/omap1_bl.h +++ b/include/linux/platform_data/omap1_bl.h @@ -6,7 +6,6 @@ struct omap_backlight_config { int default_intensity; - int (*set_power)(struct device *dev, int state); }; #endif -- cgit v1.2.3-59-g8ed1b From bf8c95504494ceb097f94e9aa03a5f5a0cfaed98 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Tue, 19 Mar 2024 10:37:22 +0100 Subject: backlight: omap1: Replace FB_BLANK_ states with simple on/off The backlight is on for fb_blank eq FB_BLANK_UNBLANK, or off for any other value in fb_blank. But the field fb_blank in struct backlight_properties is deprecated and should not be used any longer. Replace the test for fb_blank in omap's backlight code with a simple boolean parameter and push the test into the update_status helper. Instead of reading fb_blank directly, decode the backlight device's status with backlight_is_blank(). Signed-off-by: Thomas Zimmermann Reviewed-by: Dan Carpenter Reviewed-by: Daniel Thompson Link: https://lore.kernel.org/r/20240319093915.31778-4-tzimmermann@suse.de Signed-off-by: Lee Jones --- drivers/video/backlight/omap1_bl.c | 43 ++++++++++++++++---------------------- 1 file changed, 18 insertions(+), 25 deletions(-) diff --git a/drivers/video/backlight/omap1_bl.c b/drivers/video/backlight/omap1_bl.c index 84d148f38595..636b390f78f0 100644 --- a/drivers/video/backlight/omap1_bl.c +++ b/drivers/video/backlight/omap1_bl.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include @@ -20,7 +19,7 @@ #define OMAPBL_MAX_INTENSITY 0xff struct omap_backlight { - int powermode; + bool enabled; int current_intensity; struct device *dev; @@ -37,21 +36,14 @@ static inline void omapbl_send_enable(int enable) omap_writeb(enable, OMAP_PWL_CLK_ENABLE); } -static void omapbl_blank(struct omap_backlight *bl, int mode) +static void omapbl_enable(struct omap_backlight *bl, bool enable) { - switch (mode) { - case FB_BLANK_NORMAL: - case FB_BLANK_VSYNC_SUSPEND: - case FB_BLANK_HSYNC_SUSPEND: - case FB_BLANK_POWERDOWN: - omapbl_send_intensity(0); - omapbl_send_enable(0); - break; - - case FB_BLANK_UNBLANK: + if (enable) { omapbl_send_intensity(bl->current_intensity); omapbl_send_enable(1); - break; + } else { + omapbl_send_intensity(0); + omapbl_send_enable(0); } } @@ -61,7 +53,7 @@ static int omapbl_suspend(struct device *dev) struct backlight_device *bl_dev = dev_get_drvdata(dev); struct omap_backlight *bl = bl_get_data(bl_dev); - omapbl_blank(bl, FB_BLANK_POWERDOWN); + omapbl_enable(bl, false); return 0; } @@ -70,33 +62,34 @@ static int omapbl_resume(struct device *dev) struct backlight_device *bl_dev = dev_get_drvdata(dev); struct omap_backlight *bl = bl_get_data(bl_dev); - omapbl_blank(bl, bl->powermode); + omapbl_enable(bl, bl->enabled); return 0; } #endif -static int omapbl_set_power(struct backlight_device *dev, int state) +static void omapbl_set_enabled(struct backlight_device *dev, bool enable) { struct omap_backlight *bl = bl_get_data(dev); - omapbl_blank(bl, state); - bl->powermode = state; - - return 0; + omapbl_enable(bl, enable); + bl->enabled = enable; } static int omapbl_update_status(struct backlight_device *dev) { struct omap_backlight *bl = bl_get_data(dev); + bool enable; if (bl->current_intensity != dev->props.brightness) { - if (bl->powermode == FB_BLANK_UNBLANK) + if (bl->enabled) omapbl_send_intensity(dev->props.brightness); bl->current_intensity = dev->props.brightness; } - if (dev->props.fb_blank != bl->powermode) - omapbl_set_power(dev, dev->props.fb_blank); + enable = !backlight_is_blank(dev); + + if (enable != bl->enabled) + omapbl_set_enabled(dev, enable); return 0; } @@ -136,7 +129,7 @@ static int omapbl_probe(struct platform_device *pdev) if (IS_ERR(dev)) return PTR_ERR(dev); - bl->powermode = FB_BLANK_POWERDOWN; + bl->enabled = false; bl->current_intensity = 0; bl->pdata = pdata; -- cgit v1.2.3-59-g8ed1b From 6be0fb641ba655ca690295d29526f7b8e4a1dcfc Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Tue, 19 Mar 2024 10:37:23 +0100 Subject: fbdev: omap2/omapfb: Replace use of fb_blank with backlight helpers Replace the use of struct backlight_properties.fb_blank with backlight helpers. This effects testing if the backlight is blanked and reading the backlight's brightness level. Signed-off-by: Thomas Zimmermann Reviewed-by: Dan Carpenter Link: https://lore.kernel.org/r/20240319093915.31778-5-tzimmermann@suse.de Signed-off-by: Lee Jones --- drivers/video/fbdev/omap2/omapfb/displays/panel-dsi-cm.c | 6 +----- drivers/video/fbdev/omap2/omapfb/displays/panel-sony-acx565akm.c | 9 ++------- 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/drivers/video/fbdev/omap2/omapfb/displays/panel-dsi-cm.c b/drivers/video/fbdev/omap2/omapfb/displays/panel-dsi-cm.c index adb8881bac28..47683a6c0076 100644 --- a/drivers/video/fbdev/omap2/omapfb/displays/panel-dsi-cm.c +++ b/drivers/video/fbdev/omap2/omapfb/displays/panel-dsi-cm.c @@ -356,11 +356,7 @@ static int dsicm_bl_update_status(struct backlight_device *dev) static int dsicm_bl_get_intensity(struct backlight_device *dev) { - if (dev->props.fb_blank == FB_BLANK_UNBLANK && - dev->props.power == FB_BLANK_UNBLANK) - return dev->props.brightness; - - return 0; + return backlight_get_brightness(dev); } static const struct backlight_ops dsicm_bl_ops = { diff --git a/drivers/video/fbdev/omap2/omapfb/displays/panel-sony-acx565akm.c b/drivers/video/fbdev/omap2/omapfb/displays/panel-sony-acx565akm.c index 685c63aa4e03..9d3ce234a787 100644 --- a/drivers/video/fbdev/omap2/omapfb/displays/panel-sony-acx565akm.c +++ b/drivers/video/fbdev/omap2/omapfb/displays/panel-sony-acx565akm.c @@ -340,11 +340,7 @@ static int acx565akm_bl_update_status(struct backlight_device *dev) dev_dbg(&ddata->spi->dev, "%s\n", __func__); - if (dev->props.fb_blank == FB_BLANK_UNBLANK && - dev->props.power == FB_BLANK_UNBLANK) - level = dev->props.brightness; - else - level = 0; + level = backlight_get_brightness(dev); if (ddata->has_bc) acx565akm_set_brightness(ddata, level); @@ -363,8 +359,7 @@ static int acx565akm_bl_get_intensity(struct backlight_device *dev) if (!ddata->has_bc) return -ENODEV; - if (dev->props.fb_blank == FB_BLANK_UNBLANK && - dev->props.power == FB_BLANK_UNBLANK) { + if (!backlight_is_blank(dev)) { if (ddata->has_bc) return acx565akm_get_actual_brightness(ddata); else -- cgit v1.2.3-59-g8ed1b From 9a7bb61ffe467034571959ce90509158d4bd00bd Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Tue, 19 Mar 2024 10:37:24 +0100 Subject: staging: fbtft: Remove reference to fb_blank The field fb_blank in struct backlight_properties is deprecated and should not be used. Don't output its value in the driver's debug print. Signed-off-by: Thomas Zimmermann Reviewed-by: Dan Carpenter Link: https://lore.kernel.org/r/20240319093915.31778-6-tzimmermann@suse.de Signed-off-by: Lee Jones --- drivers/staging/fbtft/fb_ssd1351.c | 4 +--- drivers/staging/fbtft/fbtft-core.c | 5 ++--- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/staging/fbtft/fb_ssd1351.c b/drivers/staging/fbtft/fb_ssd1351.c index 72172e870007..ca2cba2185ae 100644 --- a/drivers/staging/fbtft/fb_ssd1351.c +++ b/drivers/staging/fbtft/fb_ssd1351.c @@ -194,9 +194,7 @@ static int update_onboard_backlight(struct backlight_device *bd) struct fbtft_par *par = bl_get_data(bd); bool on; - fbtft_par_dbg(DEBUG_BACKLIGHT, par, - "%s: power=%d, fb_blank=%d\n", - __func__, bd->props.power, bd->props.fb_blank); + fbtft_par_dbg(DEBUG_BACKLIGHT, par, "%s: power=%d\n", __func__, bd->props.power); on = !backlight_is_blank(bd); /* Onboard backlight connected to GPIO0 on SSD1351, GPIO1 unused */ diff --git a/drivers/staging/fbtft/fbtft-core.c b/drivers/staging/fbtft/fbtft-core.c index 38845f23023f..c8d52c63d79f 100644 --- a/drivers/staging/fbtft/fbtft-core.c +++ b/drivers/staging/fbtft/fbtft-core.c @@ -133,9 +133,8 @@ static int fbtft_backlight_update_status(struct backlight_device *bd) struct fbtft_par *par = bl_get_data(bd); bool polarity = par->polarity; - fbtft_par_dbg(DEBUG_BACKLIGHT, par, - "%s: polarity=%d, power=%d, fb_blank=%d\n", - __func__, polarity, bd->props.power, bd->props.fb_blank); + fbtft_par_dbg(DEBUG_BACKLIGHT, par, "%s: polarity=%d, power=%d\n", __func__, + polarity, bd->props.power); if (!backlight_is_blank(bd)) gpiod_set_value(par->gpio.led[0], polarity); -- cgit v1.2.3-59-g8ed1b From 4551978bb50a8d59b49629deebacd73478a8b1e1 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Tue, 19 Mar 2024 10:37:25 +0100 Subject: backlight: Remove fb_blank from struct backlight_properties Remove the field fb_blank from struct backlight_properties and remove all code that still sets or reads it. Backlight blank status is now tracked exclusively in struct backlight_properties.state. The core backlight code keeps the fb_blank and state fields in sync, but doesn't do anything else with fb_blank. Several drivers initialize fb_blank to FB_BLANK_UNBLANK to enable the backlight. This is already the default for the state field. So we can delete the fb_blank code from core and drivers and rely on the state field. Signed-off-by: Thomas Zimmermann Cc: Flavio Suligoi Cc: Nicolas Ferre Cc: Alexandre Belloni Cc: Claudiu Beznea Tested-by: Flavio Suligoi Reviewed-by: Daniel Thompson Reviewed-by: Dan Carpenter Link: https://lore.kernel.org/r/20240319093915.31778-7-tzimmermann@suse.de Signed-off-by: Lee Jones --- drivers/video/backlight/backlight.c | 2 -- drivers/video/backlight/mp3309c.c | 1 - drivers/video/backlight/omap1_bl.c | 1 - drivers/video/fbdev/atmel_lcdfb.c | 1 - .../fbdev/omap2/omapfb/displays/panel-dsi-cm.c | 1 - .../omap2/omapfb/displays/panel-sony-acx565akm.c | 1 - include/linux/backlight.h | 25 +--------------------- 7 files changed, 1 insertion(+), 31 deletions(-) diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c index 86e1cdc8e369..691f1f3030e9 100644 --- a/drivers/video/backlight/backlight.c +++ b/drivers/video/backlight/backlight.c @@ -118,14 +118,12 @@ static int fb_notifier_callback(struct notifier_block *self, bd->fb_bl_on[node] = true; if (!bd->use_count++) { bd->props.state &= ~BL_CORE_FBBLANK; - bd->props.fb_blank = FB_BLANK_UNBLANK; backlight_update_status(bd); } } else if (fb_blank != FB_BLANK_UNBLANK && bd->fb_bl_on[node]) { bd->fb_bl_on[node] = false; if (!(--bd->use_count)) { bd->props.state |= BL_CORE_FBBLANK; - bd->props.fb_blank = fb_blank; backlight_update_status(bd); } } diff --git a/drivers/video/backlight/mp3309c.c b/drivers/video/backlight/mp3309c.c index c80a1481e742..7d73e85b8c14 100644 --- a/drivers/video/backlight/mp3309c.c +++ b/drivers/video/backlight/mp3309c.c @@ -363,7 +363,6 @@ static int mp3309c_probe(struct i2c_client *client) props.scale = BACKLIGHT_SCALE_LINEAR; props.type = BACKLIGHT_RAW; props.power = FB_BLANK_UNBLANK; - props.fb_blank = FB_BLANK_UNBLANK; chip->bl = devm_backlight_device_register(dev, "mp3309c", dev, chip, &mp3309c_bl_ops, &props); if (IS_ERR(chip->bl)) diff --git a/drivers/video/backlight/omap1_bl.c b/drivers/video/backlight/omap1_bl.c index 636b390f78f0..e461e19231ae 100644 --- a/drivers/video/backlight/omap1_bl.c +++ b/drivers/video/backlight/omap1_bl.c @@ -139,7 +139,6 @@ static int omapbl_probe(struct platform_device *pdev) omap_cfg_reg(PWL); /* Conflicts with UART3 */ - dev->props.fb_blank = FB_BLANK_UNBLANK; dev->props.brightness = pdata->default_intensity; omapbl_update_status(dev); diff --git a/drivers/video/fbdev/atmel_lcdfb.c b/drivers/video/fbdev/atmel_lcdfb.c index 9e391e5eaf9d..5574fb0361ee 100644 --- a/drivers/video/fbdev/atmel_lcdfb.c +++ b/drivers/video/fbdev/atmel_lcdfb.c @@ -153,7 +153,6 @@ static void init_backlight(struct atmel_lcdfb_info *sinfo) sinfo->backlight = bl; bl->props.power = FB_BLANK_UNBLANK; - bl->props.fb_blank = FB_BLANK_UNBLANK; bl->props.brightness = atmel_bl_get_brightness(bl); } diff --git a/drivers/video/fbdev/omap2/omapfb/displays/panel-dsi-cm.c b/drivers/video/fbdev/omap2/omapfb/displays/panel-dsi-cm.c index 47683a6c0076..274bdf7b3b45 100644 --- a/drivers/video/fbdev/omap2/omapfb/displays/panel-dsi-cm.c +++ b/drivers/video/fbdev/omap2/omapfb/displays/panel-dsi-cm.c @@ -1215,7 +1215,6 @@ static int dsicm_probe(struct platform_device *pdev) ddata->bldev = bldev; - bldev->props.fb_blank = FB_BLANK_UNBLANK; bldev->props.power = FB_BLANK_UNBLANK; bldev->props.brightness = 255; diff --git a/drivers/video/fbdev/omap2/omapfb/displays/panel-sony-acx565akm.c b/drivers/video/fbdev/omap2/omapfb/displays/panel-sony-acx565akm.c index 9d3ce234a787..71d2e015960c 100644 --- a/drivers/video/fbdev/omap2/omapfb/displays/panel-sony-acx565akm.c +++ b/drivers/video/fbdev/omap2/omapfb/displays/panel-sony-acx565akm.c @@ -753,7 +753,6 @@ static int acx565akm_probe(struct spi_device *spi) } memset(&props, 0, sizeof(props)); - props.fb_blank = FB_BLANK_UNBLANK; props.power = FB_BLANK_UNBLANK; props.type = BACKLIGHT_RAW; diff --git a/include/linux/backlight.h b/include/linux/backlight.h index 614653e07e3a..31600b144d79 100644 --- a/include/linux/backlight.h +++ b/include/linux/backlight.h @@ -218,25 +218,6 @@ struct backlight_properties { */ int power; - /** - * @fb_blank: The power state from the FBIOBLANK ioctl. - * - * When the FBIOBLANK ioctl is called @fb_blank is set to the - * blank parameter and the update_status() operation is called. - * - * When the backlight device is enabled @fb_blank is set - * to FB_BLANK_UNBLANK. When the backlight device is disabled - * @fb_blank is set to FB_BLANK_POWERDOWN. - * - * Backlight drivers should avoid using this property. It has been - * replaced by state & BL_CORE_FBLANK (although most drivers should - * use backlight_is_blank() as the preferred means to get the blank - * state). - * - * fb_blank is deprecated and will be removed. - */ - int fb_blank; - /** * @type: The type of backlight supported. * @@ -366,7 +347,6 @@ static inline int backlight_enable(struct backlight_device *bd) return 0; bd->props.power = FB_BLANK_UNBLANK; - bd->props.fb_blank = FB_BLANK_UNBLANK; bd->props.state &= ~BL_CORE_FBBLANK; return backlight_update_status(bd); @@ -382,7 +362,6 @@ static inline int backlight_disable(struct backlight_device *bd) return 0; bd->props.power = FB_BLANK_POWERDOWN; - bd->props.fb_blank = FB_BLANK_POWERDOWN; bd->props.state |= BL_CORE_FBBLANK; return backlight_update_status(bd); @@ -395,15 +374,13 @@ static inline int backlight_disable(struct backlight_device *bd) * Display is expected to be blank if any of these is true:: * * 1) if power in not UNBLANK - * 2) if fb_blank is not UNBLANK - * 3) if state indicate BLANK or SUSPENDED + * 2) if state indicate BLANK or SUSPENDED * * Returns true if display is expected to be blank, false otherwise. */ static inline bool backlight_is_blank(const struct backlight_device *bd) { return bd->props.power != FB_BLANK_UNBLANK || - bd->props.fb_blank != FB_BLANK_UNBLANK || bd->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK); } -- cgit v1.2.3-59-g8ed1b From 822c91e72eac568ed8d83765634f00decb45666c Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Mon, 4 Mar 2024 21:57:30 +0100 Subject: leds: trigger: Store brightness set by led_trigger_event() If a simple trigger is assigned to a LED, then the LED may be off until the next led_trigger_event() call. This may be an issue for simple triggers with rare led_trigger_event() calls, e.g. power supply charging indicators (drivers/power/supply/power_supply_leds.c). Therefore persist the brightness value of the last led_trigger_event() call and use this value if the trigger is assigned to a LED. In addition add a getter for the trigger brightness value. Signed-off-by: Heiner Kallweit Reviewed-by: Takashi Iwai Link: https://lore.kernel.org/r/b1358b25-3f30-458d-8240-5705ae007a8a@gmail.com Signed-off-by: Lee Jones --- drivers/leds/led-triggers.c | 6 ++++-- include/linux/leds.h | 15 +++++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/drivers/leds/led-triggers.c b/drivers/leds/led-triggers.c index 0f5ac30053ad..b1b323b19301 100644 --- a/drivers/leds/led-triggers.c +++ b/drivers/leds/led-triggers.c @@ -194,11 +194,11 @@ int led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trig) spin_unlock(&trig->leddev_list_lock); led_cdev->trigger = trig; + ret = 0; if (trig->activate) ret = trig->activate(led_cdev); else - ret = 0; - + led_set_brightness(led_cdev, trig->brightness); if (ret) goto err_activate; @@ -387,6 +387,8 @@ void led_trigger_event(struct led_trigger *trig, if (!trig) return; + trig->brightness = brightness; + rcu_read_lock(); list_for_each_entry_rcu(led_cdev, &trig->led_cdevs, trig_list) led_set_brightness(led_cdev, brightness); diff --git a/include/linux/leds.h b/include/linux/leds.h index db6b114bb3d9..7964ee38b2a3 100644 --- a/include/linux/leds.h +++ b/include/linux/leds.h @@ -455,6 +455,9 @@ struct led_trigger { int (*activate)(struct led_classdev *led_cdev); void (*deactivate)(struct led_classdev *led_cdev); + /* Brightness set by led_trigger_event */ + enum led_brightness brightness; + /* LED-private triggers have this set */ struct led_hw_trigger_type *trigger_type; @@ -508,6 +511,12 @@ static inline void *led_get_trigger_data(struct led_classdev *led_cdev) return led_cdev->trigger_data; } +static inline enum led_brightness +led_trigger_get_brightness(const struct led_trigger *trigger) +{ + return trigger ? trigger->brightness : LED_OFF; +} + #define module_led_trigger(__led_trigger) \ module_driver(__led_trigger, led_trigger_register, \ led_trigger_unregister) @@ -544,6 +553,12 @@ static inline void *led_get_trigger_data(struct led_classdev *led_cdev) return NULL; } +static inline enum led_brightness +led_trigger_get_brightness(const struct led_trigger *trigger) +{ + return LED_OFF; +} + #endif /* CONFIG_LEDS_TRIGGERS */ /* Trigger specific enum */ -- cgit v1.2.3-59-g8ed1b From a24de38de8046c075777bd6b8a291ae1ee56f71c Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Mon, 4 Mar 2024 21:58:46 +0100 Subject: ALSA: control-led: Integrate mute led trigger This driver is the only one calling ledtrig_audio_set(), therefore the LED audio trigger isn't usable standalone. So it makes sense to fully integrate LED audio triger handling here. The module aliases ensure that the driver is auto-loaded (if built as module) if a LED device has one of the two audio triggers as default trigger. In addition disable building the old audio mute LED trigger. Signed-off-by: Heiner Kallweit Reviewed-by: Takashi Iwai Link: https://lore.kernel.org/r/107634e6-d9ad-4a9f-881d-1eb72ea1a5a7@gmail.com Signed-off-by: Lee Jones --- drivers/leds/trigger/Kconfig | 7 ------- drivers/leds/trigger/Makefile | 1 - sound/core/Kconfig | 1 - sound/core/control_led.c | 20 +++++++++++++++++--- 4 files changed, 17 insertions(+), 12 deletions(-) diff --git a/drivers/leds/trigger/Kconfig b/drivers/leds/trigger/Kconfig index d11d80176fc0..31576952e181 100644 --- a/drivers/leds/trigger/Kconfig +++ b/drivers/leds/trigger/Kconfig @@ -136,13 +136,6 @@ config LEDS_TRIGGER_PATTERN which is a series of tuples, of brightness and duration (ms). If unsure, say N -config LEDS_TRIGGER_AUDIO - tristate "Audio Mute LED Trigger" - help - This allows LEDs to be controlled by audio drivers for following - the audio mute and mic-mute changes. - If unsure, say N - config LEDS_TRIGGER_TTY tristate "LED Trigger for TTY devices" depends on TTY diff --git a/drivers/leds/trigger/Makefile b/drivers/leds/trigger/Makefile index 25c4db97cdd4..242f6c4e3453 100644 --- a/drivers/leds/trigger/Makefile +++ b/drivers/leds/trigger/Makefile @@ -14,5 +14,4 @@ obj-$(CONFIG_LEDS_TRIGGER_CAMERA) += ledtrig-camera.o obj-$(CONFIG_LEDS_TRIGGER_PANIC) += ledtrig-panic.o obj-$(CONFIG_LEDS_TRIGGER_NETDEV) += ledtrig-netdev.o obj-$(CONFIG_LEDS_TRIGGER_PATTERN) += ledtrig-pattern.o -obj-$(CONFIG_LEDS_TRIGGER_AUDIO) += ledtrig-audio.o obj-$(CONFIG_LEDS_TRIGGER_TTY) += ledtrig-tty.o diff --git a/sound/core/Kconfig b/sound/core/Kconfig index 8077f481d84f..b970a1734647 100644 --- a/sound/core/Kconfig +++ b/sound/core/Kconfig @@ -262,6 +262,5 @@ config SND_CTL_LED tristate select NEW_LEDS if SND_CTL_LED select LEDS_TRIGGERS if SND_CTL_LED - select LEDS_TRIGGER_AUDIO if SND_CTL_LED source "sound/core/seq/Kconfig" diff --git a/sound/core/control_led.c b/sound/core/control_led.c index 3d37e9fa7b9c..061a8ea23340 100644 --- a/sound/core/control_led.c +++ b/sound/core/control_led.c @@ -53,6 +53,7 @@ struct snd_ctl_led_ctl { static DEFINE_MUTEX(snd_ctl_led_mutex); static bool snd_ctl_led_card_valid[SNDRV_CARDS]; +static struct led_trigger *snd_ctl_ledtrig_audio[NUM_AUDIO_LEDS]; static struct snd_ctl_led snd_ctl_leds[MAX_LED] = { { .name = "speaker", @@ -174,8 +175,11 @@ static void snd_ctl_led_set_state(struct snd_card *card, unsigned int access, case MODE_FOLLOW_ROUTE: if (route >= 0) route ^= 1; break; case MODE_FOLLOW_MUTE: /* noop */ break; } - if (route >= 0) - ledtrig_audio_set(led->trigger_type, route ? LED_OFF : LED_ON); + if (route >= 0) { + struct led_trigger *trig = snd_ctl_ledtrig_audio[led->trigger_type]; + + led_trigger_event(trig, route ? LED_OFF : LED_ON); + } } static struct snd_ctl_led_ctl *snd_ctl_led_find(struct snd_kcontrol *kctl, unsigned int ioff) @@ -425,8 +429,9 @@ static ssize_t brightness_show(struct device *dev, struct device_attribute *attr, char *buf) { struct snd_ctl_led *led = container_of(dev, struct snd_ctl_led, dev); + struct led_trigger *trig = snd_ctl_ledtrig_audio[led->trigger_type]; - return sysfs_emit(buf, "%u\n", ledtrig_audio_get(led->trigger_type)); + return sysfs_emit(buf, "%u\n", led_trigger_get_brightness(trig)); } static DEVICE_ATTR_RW(mode); @@ -716,6 +721,9 @@ static int __init snd_ctl_led_init(void) struct snd_ctl_led *led; unsigned int group; + led_trigger_register_simple("audio-mute", &snd_ctl_ledtrig_audio[LED_AUDIO_MUTE]); + led_trigger_register_simple("audio-micmute", &snd_ctl_ledtrig_audio[LED_AUDIO_MICMUTE]); + device_initialize(&snd_ctl_led_dev); snd_ctl_led_dev.class = &sound_class; snd_ctl_led_dev.release = snd_ctl_led_dev_release; @@ -768,7 +776,13 @@ static void __exit snd_ctl_led_exit(void) } device_unregister(&snd_ctl_led_dev); snd_ctl_led_clean(NULL); + + led_trigger_unregister_simple(snd_ctl_ledtrig_audio[LED_AUDIO_MUTE]); + led_trigger_unregister_simple(snd_ctl_ledtrig_audio[LED_AUDIO_MICMUTE]); } module_init(snd_ctl_led_init) module_exit(snd_ctl_led_exit) + +MODULE_ALIAS("ledtrig:audio-mute"); +MODULE_ALIAS("ledtrig:audio-micmute"); -- cgit v1.2.3-59-g8ed1b From ab2ab9e69ef9734b875ce6d43fe3f9f90135daae Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Mon, 4 Mar 2024 21:59:47 +0100 Subject: leds: trigger: audio: Remove this trigger Now that the audio trigger is fully integrated in sound/core/control_led.c, we can remove it here. Signed-off-by: Heiner Kallweit Reviewed-by: Takashi Iwai Link: https://lore.kernel.org/r/1e339779-6d04-4392-8ea2-5592c0fd1aa2@gmail.com Signed-off-by: Lee Jones --- arch/mips/configs/ci20_defconfig | 1 - drivers/leds/trigger/ledtrig-audio.c | 67 ------------------------------------ include/linux/leds.h | 14 -------- 3 files changed, 82 deletions(-) delete mode 100644 drivers/leds/trigger/ledtrig-audio.c diff --git a/arch/mips/configs/ci20_defconfig b/arch/mips/configs/ci20_defconfig index cdf2a782dee1..7827b2b392f6 100644 --- a/arch/mips/configs/ci20_defconfig +++ b/arch/mips/configs/ci20_defconfig @@ -152,7 +152,6 @@ CONFIG_LEDS_TRIGGER_CAMERA=m CONFIG_LEDS_TRIGGER_PANIC=y CONFIG_LEDS_TRIGGER_NETDEV=y CONFIG_LEDS_TRIGGER_PATTERN=y -CONFIG_LEDS_TRIGGER_AUDIO=y CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_JZ4740=y CONFIG_DMADEVICES=y diff --git a/drivers/leds/trigger/ledtrig-audio.c b/drivers/leds/trigger/ledtrig-audio.c deleted file mode 100644 index 2ecd4b760fc3..000000000000 --- a/drivers/leds/trigger/ledtrig-audio.c +++ /dev/null @@ -1,67 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// -// Audio Mute LED trigger -// - -#include -#include -#include -#include "../leds.h" - -static enum led_brightness audio_state[NUM_AUDIO_LEDS]; - -static int ledtrig_audio_mute_activate(struct led_classdev *led_cdev) -{ - led_set_brightness_nosleep(led_cdev, audio_state[LED_AUDIO_MUTE]); - return 0; -} - -static int ledtrig_audio_micmute_activate(struct led_classdev *led_cdev) -{ - led_set_brightness_nosleep(led_cdev, audio_state[LED_AUDIO_MICMUTE]); - return 0; -} - -static struct led_trigger ledtrig_audio[NUM_AUDIO_LEDS] = { - [LED_AUDIO_MUTE] = { - .name = "audio-mute", - .activate = ledtrig_audio_mute_activate, - }, - [LED_AUDIO_MICMUTE] = { - .name = "audio-micmute", - .activate = ledtrig_audio_micmute_activate, - }, -}; - -enum led_brightness ledtrig_audio_get(enum led_audio type) -{ - return audio_state[type]; -} -EXPORT_SYMBOL_GPL(ledtrig_audio_get); - -void ledtrig_audio_set(enum led_audio type, enum led_brightness state) -{ - audio_state[type] = state; - led_trigger_event(&ledtrig_audio[type], state); -} -EXPORT_SYMBOL_GPL(ledtrig_audio_set); - -static int __init ledtrig_audio_init(void) -{ - led_trigger_register(&ledtrig_audio[LED_AUDIO_MUTE]); - led_trigger_register(&ledtrig_audio[LED_AUDIO_MICMUTE]); - return 0; -} -module_init(ledtrig_audio_init); - -static void __exit ledtrig_audio_exit(void) -{ - led_trigger_unregister(&ledtrig_audio[LED_AUDIO_MUTE]); - led_trigger_unregister(&ledtrig_audio[LED_AUDIO_MICMUTE]); -} -module_exit(ledtrig_audio_exit); - -MODULE_DESCRIPTION("LED trigger for audio mute control"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("ledtrig:audio-mute"); -MODULE_ALIAS("ledtrig:audio-micmute"); diff --git a/include/linux/leds.h b/include/linux/leds.h index 7964ee38b2a3..6300313c46b7 100644 --- a/include/linux/leds.h +++ b/include/linux/leds.h @@ -705,18 +705,4 @@ enum led_audio { NUM_AUDIO_LEDS }; -#if IS_ENABLED(CONFIG_LEDS_TRIGGER_AUDIO) -enum led_brightness ledtrig_audio_get(enum led_audio type); -void ledtrig_audio_set(enum led_audio type, enum led_brightness state); -#else -static inline enum led_brightness ledtrig_audio_get(enum led_audio type) -{ - return LED_OFF; -} -static inline void ledtrig_audio_set(enum led_audio type, - enum led_brightness state) -{ -} -#endif - #endif /* __LINUX_LEDS_H_INCLUDED */ -- cgit v1.2.3-59-g8ed1b From 74f7ffd684334dfae365d708633e9e73256bdd11 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Fri, 22 Mar 2024 16:52:13 -0500 Subject: MAINTAINERS: add Documentation/iio/ to IIO subsystem Patches touching the IIO subsystem documentation should also be sent to the IIO mailing list. Signed-off-by: David Lechner Link: https://lore.kernel.org/r/20240322-mainline-ad7944-doc-v2-1-0923d35d5596@baylibre.com Signed-off-by: Jonathan Cameron --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index eefd1a8906bf..c3ddf2754780 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -10554,6 +10554,7 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git F: Documentation/ABI/testing/configfs-iio* F: Documentation/ABI/testing/sysfs-bus-iio* F: Documentation/devicetree/bindings/iio/ +F: Documentation/iio/ F: drivers/iio/ F: drivers/staging/iio/ F: include/dt-bindings/iio/ -- cgit v1.2.3-59-g8ed1b From 18b51455e618d0de57975ab47cef85666fb92636 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Fri, 22 Mar 2024 16:52:14 -0500 Subject: docs: iio: new docs for ad7944 driver This adds a new page to document how to use the ad7944 ADC driver. Signed-off-by: David Lechner Link: https://lore.kernel.org/r/20240322-mainline-ad7944-doc-v2-2-0923d35d5596@baylibre.com Signed-off-by: Jonathan Cameron --- Documentation/iio/ad7944.rst | 130 +++++++++++++++++++++++++++++++++++++++++++ Documentation/iio/index.rst | 1 + MAINTAINERS | 1 + 3 files changed, 132 insertions(+) create mode 100644 Documentation/iio/ad7944.rst diff --git a/Documentation/iio/ad7944.rst b/Documentation/iio/ad7944.rst new file mode 100644 index 000000000000..f418ab1288ae --- /dev/null +++ b/Documentation/iio/ad7944.rst @@ -0,0 +1,130 @@ +.. SPDX-License-Identifier: GPL-2.0-only + +============= +AD7944 driver +============= + +ADC driver for Analog Devices Inc. AD7944 and similar devices. The module name +is ``ad7944``. + + +Supported devices +================= + +The following chips are supported by this driver: + +* `AD7944 `_ +* `AD7985 `_ +* `AD7986 `_ + + +Supported features +================== + +SPI wiring modes +---------------- + +The driver currently supports two of the many possible SPI wiring configurations. + +CS mode, 3-wire, without busy indicator +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: + + +-------------+ + +--------------------| CS | + v | | + VIO +--------------------+ | HOST | + | | CNV | | | + +--->| SDI AD7944 SDO |-------->| SDI | + | SCK | | | + +--------------------+ | | + ^ | | + +--------------------| SCLK | + +-------------+ + +To select this mode in the device tree, set the ``adi,spi-mode`` property to +``"single"`` and omit the ``cnv-gpios`` property. + +CS mode, 4-wire, without busy indicator +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: + + +-------------+ + +-----------------------------------| CS | + | | | + | +--------------------| GPIO | + | v | | + | +--------------------+ | HOST | + | | CNV | | | + +--->| SDI AD7944 SDO |-------->| SDI | + | SCK | | | + +--------------------+ | | + ^ | | + +--------------------| SCLK | + +-------------+ + +To select this mode in the device tree, omit the ``adi,spi-mode`` property and +provide the ``cnv-gpios`` property. + +Reference voltage +----------------- + +All 3 possible reference voltage sources are supported: + +- Internal reference +- External 1.2V reference and internal buffer +- External reference + +The source is determined by the device tree. If ``ref-supply`` is present, then +the external reference is used. If ``refin-supply`` is present, then the internal +buffer is used. If neither is present, then the internal reference is used. + +Unimplemented features +---------------------- + +- ``BUSY`` indication +- ``TURBO`` mode +- Daisy chain mode + + +Device attributes +================= + +There are two types of ADCs in this family, pseudo-differential and fully +differential. The channel name is different depending on the type of ADC. + +Pseudo-differential ADCs +------------------------ + +AD7944 and AD7985 are pseudo-differential ADCs and have the following attributes: + ++---------------------------------------+--------------------------------------------------------------+ +| Attribute | Description | ++=======================================+==============================================================+ +| ``in_voltage0_raw`` | Raw ADC voltage value (*IN+* referenced to ground sense). | ++---------------------------------------+--------------------------------------------------------------+ +| ``in_voltage0_scale`` | Scale factor to convert raw value to mV. | ++---------------------------------------+--------------------------------------------------------------+ + +Fully-differential ADCs +----------------------- + +AD7986 is a fully-differential ADC and has the following attributes: + ++---------------------------------------+--------------------------------------------------------------+ +| Attribute | Description | ++=======================================+==============================================================+ +| ``in_voltage0-voltage1_raw`` | Raw ADC voltage value (*IN+* - *IN-*). | ++---------------------------------------+--------------------------------------------------------------+ +| ``in_voltage0-voltage1_scale`` | Scale factor to convert raw value to mV. | ++---------------------------------------+--------------------------------------------------------------+ + + +Device buffers +============== + +This driver supports IIO triggered buffers. + +See :doc:`iio_devbuf` for more information. diff --git a/Documentation/iio/index.rst b/Documentation/iio/index.rst index 30b09eefe75e..fb6f9d743211 100644 --- a/Documentation/iio/index.rst +++ b/Documentation/iio/index.rst @@ -16,6 +16,7 @@ Industrial I/O Kernel Drivers .. toctree:: :maxdepth: 1 + ad7944 adis16475 bno055 ep93xx_adc diff --git a/MAINTAINERS b/MAINTAINERS index c3ddf2754780..a7287cf44869 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -448,6 +448,7 @@ R: David Lechner S: Supported W: https://ez.analog.com/linux-software-drivers F: Documentation/devicetree/bindings/iio/adc/adi,ad7944.yaml +F: Documentation/iio/ad7944.rst F: drivers/iio/adc/ad7944.c ADAFRUIT MINI I2C GAMEPAD -- cgit v1.2.3-59-g8ed1b From 905908546cb883079971b7e150537d260df64f00 Mon Sep 17 00:00:00 2001 From: Vasileios Amoiridis Date: Tue, 19 Mar 2024 01:29:20 +0100 Subject: iio: pressure: BMP280 core driver headers sorting Sort headers in alphabetical order. Signed-off-by: Vasileios Amoiridis Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240319002925.2121016-2-vassilisamir@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/pressure/bmp280-core.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c index fe8734468ed3..871b2214121b 100644 --- a/drivers/iio/pressure/bmp280-core.c +++ b/drivers/iio/pressure/bmp280-core.c @@ -27,20 +27,20 @@ #include #include -#include -#include -#include -#include +#include #include -#include -#include +#include #include -#include #include #include /* For irq_get_irq_data() */ -#include +#include +#include #include #include +#include +#include + +#include #include -- cgit v1.2.3-59-g8ed1b From 86156cadbeff81c194e18e78c23585a8aa673abc Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sun, 24 Mar 2024 13:36:16 +0100 Subject: iio: pressure: hsc030pa: Use spi_read() Use spi_read() instead of hand-writing it. It is less verbose. Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/8327ac591d244ac85aa83c01e559076159c7ba12.1711283728.git.christophe.jaillet@wanadoo.fr Signed-off-by: Jonathan Cameron --- drivers/iio/pressure/hsc030pa_spi.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/iio/pressure/hsc030pa_spi.c b/drivers/iio/pressure/hsc030pa_spi.c index 818fa6303454..337eecc577d2 100644 --- a/drivers/iio/pressure/hsc030pa_spi.c +++ b/drivers/iio/pressure/hsc030pa_spi.c @@ -23,14 +23,9 @@ static int hsc_spi_recv(struct hsc_data *data) { struct spi_device *spi = to_spi_device(data->dev); - struct spi_transfer xfer = { - .tx_buf = NULL, - .rx_buf = data->buffer, - .len = HSC_REG_MEASUREMENT_RD_SIZE, - }; msleep_interruptible(HSC_RESP_TIME_MS); - return spi_sync_transfer(spi, &xfer, 1); + return spi_read(spi, data->buffer, HSC_REG_MEASUREMENT_RD_SIZE); } static int hsc_spi_probe(struct spi_device *spi) -- cgit v1.2.3-59-g8ed1b From 0a2c44324f3be607345834234259c0a1eaf65c1e Mon Sep 17 00:00:00 2001 From: Javier Carrasco Date: Sun, 24 Mar 2024 20:20:28 +0100 Subject: dt-bindings: iio: health: maxim,max30102: add max30101 The Maxim max30101 is the replacement for the max30105, which is no longer recommended for future designs. The max30101 does not require new properties, and it can be described with the existing ones for the max30105, which will be used as a fallback compatible. Signed-off-by: Javier Carrasco Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240324-max30101-v2-1-611deb510c97@gmail.com Signed-off-by: Jonathan Cameron --- .../devicetree/bindings/iio/health/maxim,max30102.yaml | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/iio/health/maxim,max30102.yaml b/Documentation/devicetree/bindings/iio/health/maxim,max30102.yaml index c13c10c8d65d..a0fe0a818d86 100644 --- a/Documentation/devicetree/bindings/iio/health/maxim,max30102.yaml +++ b/Documentation/devicetree/bindings/iio/health/maxim,max30102.yaml @@ -4,16 +4,20 @@ $id: http://devicetree.org/schemas/iio/health/maxim,max30102.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: Maxim MAX30102 heart rate and pulse oximeter and MAX30105 particle-sensor +title: Maxim MAX30101/2 heart rate and pulse oximeter and MAX30105 particle-sensor maintainers: - Matt Ranostay properties: compatible: - enum: - - maxim,max30102 - - maxim,max30105 + oneOf: + - enum: + - maxim,max30102 + - maxim,max30105 + - items: + - const: maxim,max30101 + - const: maxim,max30105 reg: maxItems: 1 -- cgit v1.2.3-59-g8ed1b From c71af78d9bf2edd9777113e7a9cbacc518318976 Mon Sep 17 00:00:00 2001 From: Javier Carrasco Date: Sun, 24 Mar 2024 20:20:29 +0100 Subject: iio: health: max30102: add support for max30101 The Maxim max30101 is the replacement for the max30105, which is no longer recommended for future designs. Their internal structure is identical, as well as the register map, configuration options and sensitivity, which allows for code recycling. Signed-off-by: Javier Carrasco Link: https://lore.kernel.org/r/20240324-max30101-v2-2-611deb510c97@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/health/max30102.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/iio/health/max30102.c b/drivers/iio/health/max30102.c index 37e619827e8a..6616729af5b7 100644 --- a/drivers/iio/health/max30102.c +++ b/drivers/iio/health/max30102.c @@ -613,6 +613,7 @@ static void max30102_remove(struct i2c_client *client) } static const struct i2c_device_id max30102_id[] = { + { "max30101", max30105 }, { "max30102", max30102 }, { "max30105", max30105 }, {} @@ -620,6 +621,7 @@ static const struct i2c_device_id max30102_id[] = { MODULE_DEVICE_TABLE(i2c, max30102_id); static const struct of_device_id max30102_dt_ids[] = { + { .compatible = "maxim,max30101" }, { .compatible = "maxim,max30102" }, { .compatible = "maxim,max30105" }, { } -- cgit v1.2.3-59-g8ed1b From cba15a6237652c07ed01aaa73623deb68473a940 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 25 Mar 2024 22:32:41 +0200 Subject: dt-bindings: iio: dac: ti,dac5571: Add DAC081C081 support The DAC081C081 is a TI DAC whose software interface is compatible with the DAC5571. It is the 8-bit version of the DAC121C081, already supported by the DAC5571 bindings. Extends the bindings to support this chip. Signed-off-by: Laurent Pinchart Reviewed-by: Sean Nyekjaer Link: https://lore.kernel.org/r/20240325203245.31660-2-laurent.pinchart@ideasonboard.com Signed-off-by: Jonathan Cameron --- Documentation/devicetree/bindings/iio/dac/ti,dac5571.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/iio/dac/ti,dac5571.yaml b/Documentation/devicetree/bindings/iio/dac/ti,dac5571.yaml index 79da0323c327..e59db861e2eb 100644 --- a/Documentation/devicetree/bindings/iio/dac/ti,dac5571.yaml +++ b/Documentation/devicetree/bindings/iio/dac/ti,dac5571.yaml @@ -21,6 +21,7 @@ properties: - ti,dac5573 - ti,dac6573 - ti,dac7573 + - ti,dac081c081 - ti,dac121c081 reg: -- cgit v1.2.3-59-g8ed1b From 3d797af1d69a23571ec89dc4d95eb0e0e971d3d8 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 25 Mar 2024 22:32:42 +0200 Subject: iio: dac: ti-dac5571: Add DAC081C081 support The DAC081C081 is a TI DAC whose software interface is compatible with the DAC5571. It is the 8-bit version of the DAC121C081, already supported by the DAC5571 driver. Extends the driver to support this chip. Signed-off-by: Laurent Pinchart Reviewed-by: Sean Nyekjaer > Link: https://lore.kernel.org/r/20240325203245.31660-3-laurent.pinchart@ideasonboard.com Signed-off-by: Jonathan Cameron --- drivers/iio/dac/ti-dac5571.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/iio/dac/ti-dac5571.c b/drivers/iio/dac/ti-dac5571.c index efb1269a77c1..c5162b72951a 100644 --- a/drivers/iio/dac/ti-dac5571.c +++ b/drivers/iio/dac/ti-dac5571.c @@ -13,6 +13,7 @@ * https://www.ti.com/lit/ds/symlink/dac5573.pdf * https://www.ti.com/lit/ds/symlink/dac6573.pdf * https://www.ti.com/lit/ds/symlink/dac7573.pdf + * https://www.ti.com/lit/ds/symlink/dac081c081.pdf * https://www.ti.com/lit/ds/symlink/dac121c081.pdf */ @@ -386,6 +387,7 @@ static void dac5571_remove(struct i2c_client *i2c) } static const struct of_device_id dac5571_of_id[] = { + {.compatible = "ti,dac081c081", .data = &dac5571_spec[single_8bit] }, {.compatible = "ti,dac121c081", .data = &dac5571_spec[single_12bit] }, {.compatible = "ti,dac5571", .data = &dac5571_spec[single_8bit] }, {.compatible = "ti,dac6571", .data = &dac5571_spec[single_10bit] }, @@ -401,6 +403,7 @@ static const struct of_device_id dac5571_of_id[] = { MODULE_DEVICE_TABLE(of, dac5571_of_id); static const struct i2c_device_id dac5571_id[] = { + {"dac081c081", (kernel_ulong_t)&dac5571_spec[single_8bit] }, {"dac121c081", (kernel_ulong_t)&dac5571_spec[single_12bit] }, {"dac5571", (kernel_ulong_t)&dac5571_spec[single_8bit] }, {"dac6571", (kernel_ulong_t)&dac5571_spec[single_10bit] }, -- cgit v1.2.3-59-g8ed1b From 27eea4778db8268cd6dc80a5b853c599bd3099f1 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Mon, 25 Mar 2024 14:40:36 -0500 Subject: iio: adc: ad7944: simplify adi,spi-mode property parsing This simplifies the adi,spi-mode property parsing by using device_property_match_property_string() instead of two separate functions. Also, the error return value is now more informative in cases where there was a problem parsing the property. Suggested-by: Andy Shevchenko Signed-off-by: David Lechner Link: https://lore.kernel.org/r/20240325-ad7944-cleanups-v3-1-3a19120cdd06@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7944.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/drivers/iio/adc/ad7944.c b/drivers/iio/adc/ad7944.c index d5ec6b5a41c7..9aa3e98cd75c 100644 --- a/drivers/iio/adc/ad7944.c +++ b/drivers/iio/adc/ad7944.c @@ -366,7 +366,6 @@ static int ad7944_probe(struct spi_device *spi) struct ad7944_adc *adc; bool have_refin = false; struct regulator *ref; - const char *str_val; int ret; indio_dev = devm_iio_device_alloc(dev, sizeof(*adc)); @@ -382,17 +381,17 @@ static int ad7944_probe(struct spi_device *spi) adc->timing_spec = chip_info->timing_spec; - if (device_property_read_string(dev, "adi,spi-mode", &str_val) == 0) { - ret = sysfs_match_string(ad7944_spi_modes, str_val); - if (ret < 0) - return dev_err_probe(dev, -EINVAL, - "unsupported adi,spi-mode\n"); - - adc->spi_mode = ret; - } else { - /* absence of adi,spi-mode property means default mode */ + ret = device_property_match_property_string(dev, "adi,spi-mode", + ad7944_spi_modes, + ARRAY_SIZE(ad7944_spi_modes)); + /* absence of adi,spi-mode property means default mode */ + if (ret == -EINVAL) adc->spi_mode = AD7944_SPI_MODE_DEFAULT; - } + else if (ret < 0) + return dev_err_probe(dev, ret, + "getting adi,spi-mode property failed\n"); + else + adc->spi_mode = ret; if (adc->spi_mode == AD7944_SPI_MODE_CHAIN) return dev_err_probe(dev, -EINVAL, -- cgit v1.2.3-59-g8ed1b From c7df39b2a5643c4df566fb23951f619f8c639042 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 27 Mar 2024 18:46:55 +0100 Subject: Input: stmpe - drop driver owner assignment Core in platform_driver_register() already sets the .owner, so driver does not need to. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240327174655.519503-1-krzysztof.kozlowski@linaro.org Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/stmpe-keypad.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/input/keyboard/stmpe-keypad.c b/drivers/input/keyboard/stmpe-keypad.c index 2013c0afd0c3..ef2f44027894 100644 --- a/drivers/input/keyboard/stmpe-keypad.c +++ b/drivers/input/keyboard/stmpe-keypad.c @@ -413,7 +413,6 @@ static void stmpe_keypad_remove(struct platform_device *pdev) static struct platform_driver stmpe_keypad_driver = { .driver.name = "stmpe-keypad", - .driver.owner = THIS_MODULE, .probe = stmpe_keypad_probe, .remove_new = stmpe_keypad_remove, }; -- cgit v1.2.3-59-g8ed1b From b1b11bb07898b7e0313438734c310100219e676f Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 30 Jan 2024 10:46:28 -0800 Subject: soundwire: sysfs: move sdw_slave_dev_attr_group into the existing list of groups The sysfs logic already creates a list of groups for the device, so add the sdw_slave_dev_attr_group group to that list instead of having to do a two-step process of adding a group list and then an individual group. This is a step on the way to moving all of the sysfs attribute handling into the default driver core attribute group logic so that the soundwire core does not have to do any of it manually. Cc: Vinod Koul Cc: Bard Liao Cc: Pierre-Louis Bossart Cc: Sanyog Kale Cc: alsa-devel@alsa-project.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Greg Kroah-Hartman Reviewed-by: Dan Williams Tested-By: Vijendar Mukunda Link: https://lore.kernel.org/r/2024013029-afternoon-suitably-cb59@gregkh Signed-off-by: Vinod Koul --- drivers/soundwire/sysfs_slave.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/soundwire/sysfs_slave.c b/drivers/soundwire/sysfs_slave.c index 3210359cd944..83e3f6cc3250 100644 --- a/drivers/soundwire/sysfs_slave.c +++ b/drivers/soundwire/sysfs_slave.c @@ -105,7 +105,10 @@ static struct attribute *slave_attrs[] = { &dev_attr_modalias.attr, NULL, }; -ATTRIBUTE_GROUPS(slave); + +static const struct attribute_group slave_attr_group = { + .attrs = slave_attrs, +}; static struct attribute *slave_dev_attrs[] = { &dev_attr_mipi_revision.attr, @@ -190,6 +193,12 @@ static const struct attribute_group dp0_group = { .name = "dp0", }; +static const struct attribute_group *slave_groups[] = { + &slave_attr_group, + &sdw_slave_dev_attr_group, + NULL, +}; + int sdw_slave_sysfs_init(struct sdw_slave *slave) { int ret; @@ -198,10 +207,6 @@ int sdw_slave_sysfs_init(struct sdw_slave *slave) if (ret < 0) return ret; - ret = devm_device_add_group(&slave->dev, &sdw_slave_dev_attr_group); - if (ret < 0) - return ret; - if (slave->prop.dp0_prop) { ret = devm_device_add_group(&slave->dev, &dp0_group); if (ret < 0) -- cgit v1.2.3-59-g8ed1b From 3ee43f7cc9841cdf3f2bec2de4b1e729fd17e303 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 30 Jan 2024 10:46:29 -0800 Subject: soundwire: sysfs: cleanup the logic for creating the dp0 sysfs attributes There's no need to special-case the dp0 sysfs attributes, the is_visible() callback in the attribute group can handle that for us, so add that and add it to the attribute group list making the logic simpler overall. This is a step on the way to moving all of the sysfs attribute handling into the default driver core attribute group logic so that the soundwire core does not have to do any of it manually. Cc: Vinod Koul Cc: Bard Liao Cc: Pierre-Louis Bossart Cc: Sanyog Kale Cc: alsa-devel@alsa-project.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Greg Kroah-Hartman Reviewed-by: Dan Williams Tested-By: Vijendar Mukunda Link: https://lore.kernel.org/r/2024013029-budget-mulled-5b34@gregkh Signed-off-by: Vinod Koul --- drivers/soundwire/sysfs_slave.c | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/drivers/soundwire/sysfs_slave.c b/drivers/soundwire/sysfs_slave.c index 83e3f6cc3250..8876c7807048 100644 --- a/drivers/soundwire/sysfs_slave.c +++ b/drivers/soundwire/sysfs_slave.c @@ -184,18 +184,40 @@ static struct attribute *dp0_attrs[] = { NULL, }; +static umode_t dp0_attr_visible(struct kobject *kobj, struct attribute *attr, + int n) +{ + struct sdw_slave *slave = dev_to_sdw_dev(kobj_to_dev(kobj)); + + if (slave->prop.dp0_prop) + return attr->mode; + return 0; +} + +static bool dp0_group_visible(struct kobject *kobj) +{ + struct sdw_slave *slave = dev_to_sdw_dev(kobj_to_dev(kobj)); + + if (slave->prop.dp0_prop) + return true; + return false; +} +DEFINE_SYSFS_GROUP_VISIBLE(dp0); + /* * we don't use ATTRIBUTES_GROUP here since we want to add a subdirectory * for dp0-level properties */ static const struct attribute_group dp0_group = { .attrs = dp0_attrs, + .is_visible = SYSFS_GROUP_VISIBLE(dp0), .name = "dp0", }; static const struct attribute_group *slave_groups[] = { &slave_attr_group, &sdw_slave_dev_attr_group, + &dp0_group, NULL, }; @@ -207,12 +229,6 @@ int sdw_slave_sysfs_init(struct sdw_slave *slave) if (ret < 0) return ret; - if (slave->prop.dp0_prop) { - ret = devm_device_add_group(&slave->dev, &dp0_group); - if (ret < 0) - return ret; - } - if (slave->prop.source_ports || slave->prop.sink_ports) { ret = sdw_slave_sysfs_dpn_init(slave); if (ret < 0) -- cgit v1.2.3-59-g8ed1b From fc7e56017b51482f1b9da2e778eedb4bd1deb6b3 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 30 Jan 2024 10:46:30 -0800 Subject: soundwire: sysfs: have the driver core handle the creation of the device groups The driver core supports the ability to handle the creation and removal of device-specific sysfs files in a race-free manner. Take advantage of that by converting this driver to use this by moving the sysfs attributes into a group and assigning the dev_groups pointer to it. Cc: Vinod Koul Cc: Bard Liao Cc: Pierre-Louis Bossart Cc: Sanyog Kale Cc: alsa-devel@alsa-project.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Greg Kroah-Hartman Reviewed-by: Dan Williams Tested-By: Vijendar Mukunda Link: https://lore.kernel.org/r/2024013030-worsening-rocket-a3cb@gregkh Signed-off-by: Vinod Koul --- drivers/soundwire/bus_type.c | 1 + drivers/soundwire/sysfs_local.h | 3 +++ drivers/soundwire/sysfs_slave.c | 6 +----- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/soundwire/bus_type.c b/drivers/soundwire/bus_type.c index fd65b2360fc1..b913322a2070 100644 --- a/drivers/soundwire/bus_type.c +++ b/drivers/soundwire/bus_type.c @@ -221,6 +221,7 @@ int __sdw_register_driver(struct sdw_driver *drv, struct module *owner) drv->driver.probe = sdw_drv_probe; drv->driver.remove = sdw_drv_remove; drv->driver.shutdown = sdw_drv_shutdown; + drv->driver.dev_groups = sdw_attr_groups; return driver_register(&drv->driver); } diff --git a/drivers/soundwire/sysfs_local.h b/drivers/soundwire/sysfs_local.h index 7268bc24c538..3ab8658a7782 100644 --- a/drivers/soundwire/sysfs_local.h +++ b/drivers/soundwire/sysfs_local.h @@ -11,6 +11,9 @@ /* basic attributes to report status of Slave (attachment, dev_num) */ extern const struct attribute_group *sdw_slave_status_attr_groups[]; +/* attributes for all soundwire devices */ +extern const struct attribute_group *sdw_attr_groups[]; + /* additional device-managed properties reported after driver probe */ int sdw_slave_sysfs_init(struct sdw_slave *slave); int sdw_slave_sysfs_dpn_init(struct sdw_slave *slave); diff --git a/drivers/soundwire/sysfs_slave.c b/drivers/soundwire/sysfs_slave.c index 8876c7807048..3afc0dc06c98 100644 --- a/drivers/soundwire/sysfs_slave.c +++ b/drivers/soundwire/sysfs_slave.c @@ -214,7 +214,7 @@ static const struct attribute_group dp0_group = { .name = "dp0", }; -static const struct attribute_group *slave_groups[] = { +const struct attribute_group *sdw_attr_groups[] = { &slave_attr_group, &sdw_slave_dev_attr_group, &dp0_group, @@ -225,10 +225,6 @@ int sdw_slave_sysfs_init(struct sdw_slave *slave) { int ret; - ret = devm_device_add_groups(&slave->dev, slave_groups); - if (ret < 0) - return ret; - if (slave->prop.source_ports || slave->prop.sink_ports) { ret = sdw_slave_sysfs_dpn_init(slave); if (ret < 0) -- cgit v1.2.3-59-g8ed1b From f88c1afe338edbcbfd23743742c45581075fb86c Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 30 Jan 2024 10:46:31 -0800 Subject: soundwire: sysfs: remove sdw_slave_sysfs_init() Now that sdw_slave_sysfs_init() only calls sdw_slave_sysfs_dpn_init(), just do that instead and remove sdw_slave_sysfs_init() to get it out of the way to save a bit of logic and code size. Cc: Vinod Koul Cc: Bard Liao Cc: Pierre-Louis Bossart Cc: Sanyog Kale Cc: alsa-devel@alsa-project.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Greg Kroah-Hartman Reviewed-by: Dan Williams Tested-By: Vijendar Mukunda Link: https://lore.kernel.org/r/2024013030-denatured-swaddling-b047@gregkh Signed-off-by: Vinod Koul --- drivers/soundwire/bus_type.c | 4 ++-- drivers/soundwire/sysfs_local.h | 1 - drivers/soundwire/sysfs_slave.c | 13 ------------- drivers/soundwire/sysfs_slave_dpn.c | 3 +++ 4 files changed, 5 insertions(+), 16 deletions(-) diff --git a/drivers/soundwire/bus_type.c b/drivers/soundwire/bus_type.c index b913322a2070..c32faace618f 100644 --- a/drivers/soundwire/bus_type.c +++ b/drivers/soundwire/bus_type.c @@ -126,8 +126,8 @@ static int sdw_drv_probe(struct device *dev) if (slave->prop.use_domain_irq) sdw_irq_create_mapping(slave); - /* init the sysfs as we have properties now */ - ret = sdw_slave_sysfs_init(slave); + /* init the dynamic sysfs attributes we need */ + ret = sdw_slave_sysfs_dpn_init(slave); if (ret < 0) dev_warn(dev, "Slave sysfs init failed:%d\n", ret); diff --git a/drivers/soundwire/sysfs_local.h b/drivers/soundwire/sysfs_local.h index 3ab8658a7782..fa048e112629 100644 --- a/drivers/soundwire/sysfs_local.h +++ b/drivers/soundwire/sysfs_local.h @@ -15,7 +15,6 @@ extern const struct attribute_group *sdw_slave_status_attr_groups[]; extern const struct attribute_group *sdw_attr_groups[]; /* additional device-managed properties reported after driver probe */ -int sdw_slave_sysfs_init(struct sdw_slave *slave); int sdw_slave_sysfs_dpn_init(struct sdw_slave *slave); #endif /* __SDW_SYSFS_LOCAL_H */ diff --git a/drivers/soundwire/sysfs_slave.c b/drivers/soundwire/sysfs_slave.c index 3afc0dc06c98..0eefc205f697 100644 --- a/drivers/soundwire/sysfs_slave.c +++ b/drivers/soundwire/sysfs_slave.c @@ -221,19 +221,6 @@ const struct attribute_group *sdw_attr_groups[] = { NULL, }; -int sdw_slave_sysfs_init(struct sdw_slave *slave) -{ - int ret; - - if (slave->prop.source_ports || slave->prop.sink_ports) { - ret = sdw_slave_sysfs_dpn_init(slave); - if (ret < 0) - return ret; - } - - return 0; -} - /* * the status is shown in capital letters for UNATTACHED and RESERVED * on purpose, to highligh users to the fact that these status values diff --git a/drivers/soundwire/sysfs_slave_dpn.c b/drivers/soundwire/sysfs_slave_dpn.c index c4b6543c09fd..a3fb380ee519 100644 --- a/drivers/soundwire/sysfs_slave_dpn.c +++ b/drivers/soundwire/sysfs_slave_dpn.c @@ -283,6 +283,9 @@ int sdw_slave_sysfs_dpn_init(struct sdw_slave *slave) int ret; int i; + if (!slave->prop.source_ports && !slave->prop.sink_ports) + return 0; + mask = slave->prop.source_ports; for_each_set_bit(i, &mask, 32) { ret = add_all_attributes(&slave->dev, i, 1); -- cgit v1.2.3-59-g8ed1b From 91c4dd2e5c9066577960c7eef7dd8e699220c85e Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 30 Jan 2024 10:46:32 -0800 Subject: soundwire: sysfs: remove unneeded ATTRIBUTE_GROUPS() comments Now that we manually created our own attribute group list, the outdated ATTRIBUTE_GROUPS() comments can be removed as they are not needed at all. Cc: Vinod Koul Cc: Bard Liao Cc: Pierre-Louis Bossart Cc: Sanyog Kale Cc: alsa-devel@alsa-project.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Greg Kroah-Hartman Reviewed-by: Dan Williams Tested-By: Vijendar Mukunda Link: https://lore.kernel.org/r/2024013031-tranquil-matador-a554@gregkh Signed-off-by: Vinod Koul --- drivers/soundwire/sysfs_slave.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/soundwire/sysfs_slave.c b/drivers/soundwire/sysfs_slave.c index 0eefc205f697..f4259710dd0f 100644 --- a/drivers/soundwire/sysfs_slave.c +++ b/drivers/soundwire/sysfs_slave.c @@ -129,10 +129,6 @@ static struct attribute *slave_dev_attrs[] = { NULL, }; -/* - * we don't use ATTRIBUTES_GROUP here since we want to add a subdirectory - * for device-level properties - */ static const struct attribute_group sdw_slave_dev_attr_group = { .attrs = slave_dev_attrs, .name = "dev-properties", @@ -204,10 +200,6 @@ static bool dp0_group_visible(struct kobject *kobj) } DEFINE_SYSFS_GROUP_VISIBLE(dp0); -/* - * we don't use ATTRIBUTES_GROUP here since we want to add a subdirectory - * for dp0-level properties - */ static const struct attribute_group dp0_group = { .attrs = dp0_attrs, .is_visible = SYSFS_GROUP_VISIBLE(dp0), -- cgit v1.2.3-59-g8ed1b From e05af1a42bb804e0465f76baa79a1ae8e4b619fc Mon Sep 17 00:00:00 2001 From: Vijendar Mukunda Date: Wed, 27 Mar 2024 12:01:42 +0530 Subject: soundwire: amd: use inline function for register update Define common inline function for register update. Use this inline function for updating SoundWire Pad registers and enable/disable SoundWire interrupt control registers. Signed-off-by: Vijendar Mukunda Link: https://lore.kernel.org/r/20240327063143.2266464-1-Vijendar.Mukunda@amd.com Signed-off-by: Vinod Koul --- drivers/soundwire/amd_init.c | 36 ++++++++++++++++-------------------- drivers/soundwire/amd_init.h | 8 ++++++++ drivers/soundwire/amd_manager.c | 13 ++++++------- 3 files changed, 30 insertions(+), 27 deletions(-) diff --git a/drivers/soundwire/amd_init.c b/drivers/soundwire/amd_init.c index e45dc8261ab1..4cd26f3a21f5 100644 --- a/drivers/soundwire/amd_init.c +++ b/drivers/soundwire/amd_init.c @@ -17,42 +17,38 @@ #define ACP_PAD_PULLDOWN_CTRL 0x0001448 #define ACP_SW_PAD_KEEPER_EN 0x0001454 -#define AMD_SDW_PAD_PULLDOWN_CTRL_ENABLE_MASK 0x7f9a -#define AMD_SDW0_PAD_PULLDOWN_CTRL_ENABLE_MASK 0x7f9f -#define AMD_SDW1_PAD_PULLDOWN_CTRL_ENABLE_MASK 0x7ffa -#define AMD_SDW0_PAD_EN_MASK 1 -#define AMD_SDW1_PAD_EN_MASK 0x10 -#define AMD_SDW_PAD_EN_MASK (AMD_SDW0_PAD_EN_MASK | AMD_SDW1_PAD_EN_MASK) +#define AMD_SDW0_PAD_CTRL_MASK 0x60 +#define AMD_SDW1_PAD_CTRL_MASK 5 +#define AMD_SDW_PAD_CTRL_MASK (AMD_SDW0_PAD_CTRL_MASK | AMD_SDW1_PAD_CTRL_MASK) +#define AMD_SDW0_PAD_EN 1 +#define AMD_SDW1_PAD_EN 0x10 +#define AMD_SDW_PAD_EN (AMD_SDW0_PAD_EN | AMD_SDW1_PAD_EN) static int amd_enable_sdw_pads(void __iomem *mmio, u32 link_mask, struct device *dev) { - u32 val; - u32 pad_keeper_en_mask, pad_pulldown_ctrl_mask; + u32 pad_keeper_en, pad_pulldown_ctrl_mask; switch (link_mask) { case 1: - pad_keeper_en_mask = AMD_SDW0_PAD_EN_MASK; - pad_pulldown_ctrl_mask = AMD_SDW0_PAD_PULLDOWN_CTRL_ENABLE_MASK; + pad_keeper_en = AMD_SDW0_PAD_EN; + pad_pulldown_ctrl_mask = AMD_SDW0_PAD_CTRL_MASK; break; case 2: - pad_keeper_en_mask = AMD_SDW1_PAD_EN_MASK; - pad_pulldown_ctrl_mask = AMD_SDW1_PAD_PULLDOWN_CTRL_ENABLE_MASK; + pad_keeper_en = AMD_SDW1_PAD_EN; + pad_pulldown_ctrl_mask = AMD_SDW1_PAD_CTRL_MASK; break; case 3: - pad_keeper_en_mask = AMD_SDW_PAD_EN_MASK; - pad_pulldown_ctrl_mask = AMD_SDW_PAD_PULLDOWN_CTRL_ENABLE_MASK; + pad_keeper_en = AMD_SDW_PAD_EN; + pad_pulldown_ctrl_mask = AMD_SDW_PAD_CTRL_MASK; break; default: dev_err(dev, "No SDW Links are enabled\n"); return -ENODEV; } - val = readl(mmio + ACP_SW_PAD_KEEPER_EN); - val |= pad_keeper_en_mask; - writel(val, mmio + ACP_SW_PAD_KEEPER_EN); - val = readl(mmio + ACP_PAD_PULLDOWN_CTRL); - val &= pad_pulldown_ctrl_mask; - writel(val, mmio + ACP_PAD_PULLDOWN_CTRL); + amd_updatel(mmio, ACP_SW_PAD_KEEPER_EN, pad_keeper_en, pad_keeper_en); + amd_updatel(mmio, ACP_PAD_PULLDOWN_CTRL, pad_pulldown_ctrl_mask, 0); + return 0; } diff --git a/drivers/soundwire/amd_init.h b/drivers/soundwire/amd_init.h index 928b0c707162..5e7b43836a37 100644 --- a/drivers/soundwire/amd_init.h +++ b/drivers/soundwire/amd_init.h @@ -10,4 +10,12 @@ int amd_sdw_manager_start(struct amd_sdw_manager *amd_manager); +static inline void amd_updatel(void __iomem *mmio, int offset, u32 mask, u32 val) +{ + u32 tmp; + + tmp = readl(mmio + offset); + tmp = (tmp & ~mask) | val; + writel(tmp, mmio + offset); +} #endif diff --git a/drivers/soundwire/amd_manager.c b/drivers/soundwire/amd_manager.c index 7cd24bd8e224..1066d87aa011 100644 --- a/drivers/soundwire/amd_manager.c +++ b/drivers/soundwire/amd_manager.c @@ -89,9 +89,8 @@ static void amd_enable_sdw_interrupts(struct amd_sdw_manager *amd_manager) u32 val; mutex_lock(amd_manager->acp_sdw_lock); - val = readl(amd_manager->acp_mmio + ACP_EXTERNAL_INTR_CNTL(amd_manager->instance)); - val |= sdw_manager_reg_mask_array[amd_manager->instance]; - writel(val, amd_manager->acp_mmio + ACP_EXTERNAL_INTR_CNTL(amd_manager->instance)); + val = sdw_manager_reg_mask_array[amd_manager->instance]; + amd_updatel(amd_manager->acp_mmio, ACP_EXTERNAL_INTR_CNTL(amd_manager->instance), val, val); mutex_unlock(amd_manager->acp_sdw_lock); writel(AMD_SDW_IRQ_MASK_0TO7, amd_manager->mmio + @@ -103,12 +102,12 @@ static void amd_enable_sdw_interrupts(struct amd_sdw_manager *amd_manager) static void amd_disable_sdw_interrupts(struct amd_sdw_manager *amd_manager) { - u32 val; + u32 irq_mask; mutex_lock(amd_manager->acp_sdw_lock); - val = readl(amd_manager->acp_mmio + ACP_EXTERNAL_INTR_CNTL(amd_manager->instance)); - val &= ~sdw_manager_reg_mask_array[amd_manager->instance]; - writel(val, amd_manager->acp_mmio + ACP_EXTERNAL_INTR_CNTL(amd_manager->instance)); + irq_mask = sdw_manager_reg_mask_array[amd_manager->instance]; + amd_updatel(amd_manager->acp_mmio, ACP_EXTERNAL_INTR_CNTL(amd_manager->instance), + irq_mask, 0); mutex_unlock(amd_manager->acp_sdw_lock); writel(0x00, amd_manager->mmio + ACP_SW_STATE_CHANGE_STATUS_MASK_0TO7); -- cgit v1.2.3-59-g8ed1b From b3a6809e623c03371ba51845129cdec3ebb7896e Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 26 Mar 2024 06:00:21 +0000 Subject: soundwire: bus: don't clear SDCA_CASCADE bit The SDCA_CASCADE bit is a SoundWire 1.2 addition. It is technically in the DP0_INT register, but SDCA interrupts shall not be handled as part of the DP0 interrupt processing. The existing code has clear comments that we don't want to touch the SDCA_CASCADE bit, but it's actually cleared due to faulty logic dating from SoundWire 1.0 In theory clearing this bit should have no effect: a cascade bit remains set while all ORed status are set, but better safe than sorry. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Chao Song Signed-off-by: Bard Liao Link: https://lore.kernel.org/r/20240326060021.973501-1-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- drivers/soundwire/bus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c index f3fec15c3112..05b2db00d9cd 100644 --- a/drivers/soundwire/bus.c +++ b/drivers/soundwire/bus.c @@ -1474,7 +1474,7 @@ static int sdw_handle_dp0_interrupt(struct sdw_slave *slave, u8 *slave_status) } do { - clear = status & ~SDW_DP0_INTERRUPTS; + clear = status & ~(SDW_DP0_INTERRUPTS | SDW_DP0_SDCA_CASCADE); if (status & SDW_DP0_INT_TEST_FAIL) { dev_err(&slave->dev, "Test fail for port 0\n"); -- cgit v1.2.3-59-g8ed1b From fe12bec586332f3f84feea6dddad15d40889034a Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Thu, 7 Mar 2024 19:03:59 +0100 Subject: soundwire: qcom: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20240307180359.190008-2-u.kleine-koenig@pengutronix.de Signed-off-by: Vinod Koul --- drivers/soundwire/qcom.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c index 3c4d6debab1f..fb70afe64fcc 100644 --- a/drivers/soundwire/qcom.c +++ b/drivers/soundwire/qcom.c @@ -1636,14 +1636,12 @@ err_init: return ret; } -static int qcom_swrm_remove(struct platform_device *pdev) +static void qcom_swrm_remove(struct platform_device *pdev) { struct qcom_swrm_ctrl *ctrl = dev_get_drvdata(&pdev->dev); sdw_bus_master_delete(&ctrl->bus); clk_disable_unprepare(ctrl->hclk); - - return 0; } static int __maybe_unused swrm_runtime_resume(struct device *dev) @@ -1769,7 +1767,7 @@ MODULE_DEVICE_TABLE(of, qcom_swrm_of_match); static struct platform_driver qcom_swrm_driver = { .probe = &qcom_swrm_probe, - .remove = &qcom_swrm_remove, + .remove_new = qcom_swrm_remove, .driver = { .name = "qcom-soundwire", .of_match_table = qcom_swrm_of_match, -- cgit v1.2.3-59-g8ed1b From 2a9c6ff5ca5ac074a9f10216e009c042dbba0526 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Wed, 27 Mar 2024 05:52:15 +0000 Subject: soundwire: intel: add intel_free_stream() back MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the intel_free_stream() callback to deal with the change in IPC that requires additional steps to be done to clear the gateway node_id. Signed-off-by: Ranjani Sridharan Reviewed-by: Rander Wang Reviewed-by: Péter Ujfalusi Reviewed-by: Pierre-Louis Bossart Signed-off-by: Bard Liao Link: https://lore.kernel.org/r/20240327055215.1097559-1-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- drivers/soundwire/intel.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index 1287a325c435..839268175079 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -668,6 +668,24 @@ static int intel_params_stream(struct sdw_intel *sdw, * DAI routines */ +static int intel_free_stream(struct sdw_intel *sdw, + struct snd_pcm_substream *substream, + struct snd_soc_dai *dai, + int link_id) +{ + struct sdw_intel_link_res *res = sdw->link_res; + struct sdw_intel_stream_free_data free_data; + + free_data.substream = substream; + free_data.dai = dai; + free_data.link_id = link_id; + + if (res->ops && res->ops->free_stream && res->dev) + return res->ops->free_stream(res->dev, &free_data); + + return 0; +} + static int intel_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) @@ -799,6 +817,7 @@ static int intel_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai); + struct sdw_intel *sdw = cdns_to_intel(cdns); struct sdw_cdns_dai_runtime *dai_runtime; int ret; @@ -819,6 +838,12 @@ intel_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) return ret; } + ret = intel_free_stream(sdw, substream, dai, sdw->instance); + if (ret < 0) { + dev_err(dai->dev, "intel_free_stream: failed %d\n", ret); + return ret; + } + dai_runtime->pdi = NULL; return 0; -- cgit v1.2.3-59-g8ed1b From d0f4b70eb9a9ed05a37d963655698906cd4dac9a Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Tue, 27 Feb 2024 16:04:35 -0600 Subject: dt-bindings: phy: add binding for the i.MX8MP HDMI PHY Add a DT binding for the HDMI PHY found on the i.MX8MP SoC. Signed-off-by: Lucas Stach Signed-off-by: Adam Ford Reviewed-by: Krzysztof Kozlowski Reviewed-by: Luca Ceresoli Tested-by: Tommaso Merciai Link: https://lore.kernel.org/r/20240227220444.77566-2-aford173@gmail.com Signed-off-by: Vinod Koul --- .../bindings/phy/fsl,imx8mp-hdmi-phy.yaml | 62 ++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 Documentation/devicetree/bindings/phy/fsl,imx8mp-hdmi-phy.yaml diff --git a/Documentation/devicetree/bindings/phy/fsl,imx8mp-hdmi-phy.yaml b/Documentation/devicetree/bindings/phy/fsl,imx8mp-hdmi-phy.yaml new file mode 100644 index 000000000000..c43e86a8c2e0 --- /dev/null +++ b/Documentation/devicetree/bindings/phy/fsl,imx8mp-hdmi-phy.yaml @@ -0,0 +1,62 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/phy/fsl,imx8mp-hdmi-phy.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Freescale i.MX8MP HDMI PHY + +maintainers: + - Lucas Stach + +properties: + compatible: + enum: + - fsl,imx8mp-hdmi-phy + + reg: + maxItems: 1 + + "#clock-cells": + const: 0 + + clocks: + maxItems: 2 + + clock-names: + items: + - const: apb + - const: ref + + "#phy-cells": + const: 0 + + power-domains: + maxItems: 1 + +required: + - compatible + - reg + - "#clock-cells" + - clocks + - clock-names + - "#phy-cells" + - power-domains + +additionalProperties: false + +examples: + - | + #include + #include + + phy@32fdff00 { + compatible = "fsl,imx8mp-hdmi-phy"; + reg = <0x32fdff00 0x100>; + clocks = <&clk IMX8MP_CLK_HDMI_APB>, + <&clk IMX8MP_CLK_HDMI_24M>; + clock-names = "apb", "ref"; + power-domains = <&hdmi_blk_ctrl IMX8MP_HDMIBLK_PD_HDMI_TX_PHY>; + #clock-cells = <0>; + #phy-cells = <0>; + }; -- cgit v1.2.3-59-g8ed1b From 6ad082bee9025fa8e0ef8ee478c5a614b9db9e3d Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Tue, 27 Feb 2024 16:04:36 -0600 Subject: phy: freescale: add Samsung HDMI PHY This adds the driver for the Samsung HDMI PHY found on the i.MX8MP SoC. Based on downstream implementation from Sandor Yu . According to the TRM, the PHY receives parallel data from the link and serializes it. It also sets the PLL clock needed for the TX serializer. Tested-by: Luca Ceresoli Tested-by: Richard Leitner Co-developed-by: Marco Felsch Signed-off-by: Marco Felsch Signed-off-by: Lucas Stach Tested-by: Alexander Stein Tested-by: Frieder Schrempf # Kontron BL Signed-off-by: Adam Ford Tested-by: Marek Vasut Tested-by: Luca Ceresoli Tested-by: Tommaso Merciai Link: https://lore.kernel.org/r/20240227220444.77566-3-aford173@gmail.com Signed-off-by: Vinod Koul --- drivers/phy/freescale/Kconfig | 6 + drivers/phy/freescale/Makefile | 1 + drivers/phy/freescale/phy-fsl-samsung-hdmi.c | 720 +++++++++++++++++++++++++++ 3 files changed, 727 insertions(+) create mode 100644 drivers/phy/freescale/phy-fsl-samsung-hdmi.c diff --git a/drivers/phy/freescale/Kconfig b/drivers/phy/freescale/Kconfig index 853958fb2c06..45aaaea14fb4 100644 --- a/drivers/phy/freescale/Kconfig +++ b/drivers/phy/freescale/Kconfig @@ -35,6 +35,12 @@ config PHY_FSL_IMX8M_PCIE Enable this to add support for the PCIE PHY as found on i.MX8M family of SOCs. +config PHY_FSL_SAMSUNG_HDMI_PHY + tristate "Samsung HDMI PHY support" + depends on OF && HAS_IOMEM && COMMON_CLK + help + Enable this to add support for the Samsung HDMI PHY in i.MX8MP. + endif config PHY_FSL_LYNX_28G diff --git a/drivers/phy/freescale/Makefile b/drivers/phy/freescale/Makefile index cedb328bc4d2..c4386bfdb853 100644 --- a/drivers/phy/freescale/Makefile +++ b/drivers/phy/freescale/Makefile @@ -4,3 +4,4 @@ obj-$(CONFIG_PHY_MIXEL_LVDS_PHY) += phy-fsl-imx8qm-lvds-phy.o obj-$(CONFIG_PHY_MIXEL_MIPI_DPHY) += phy-fsl-imx8-mipi-dphy.o obj-$(CONFIG_PHY_FSL_IMX8M_PCIE) += phy-fsl-imx8m-pcie.o obj-$(CONFIG_PHY_FSL_LYNX_28G) += phy-fsl-lynx-28g.o +obj-$(CONFIG_PHY_FSL_SAMSUNG_HDMI_PHY) += phy-fsl-samsung-hdmi.o diff --git a/drivers/phy/freescale/phy-fsl-samsung-hdmi.c b/drivers/phy/freescale/phy-fsl-samsung-hdmi.c new file mode 100644 index 000000000000..89e2c01f2ccf --- /dev/null +++ b/drivers/phy/freescale/phy-fsl-samsung-hdmi.c @@ -0,0 +1,720 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2020 NXP + * Copyright 2022 Pengutronix, Lucas Stach + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PHY_REG_00 0x00 +#define PHY_REG_01 0x04 +#define PHY_REG_02 0x08 +#define PHY_REG_08 0x20 +#define PHY_REG_09 0x24 +#define PHY_REG_10 0x28 +#define PHY_REG_11 0x2c + +#define PHY_REG_12 0x30 +#define REG12_CK_DIV_MASK GENMASK(5, 4) + +#define PHY_REG_13 0x34 +#define REG13_TG_CODE_LOW_MASK GENMASK(7, 0) + +#define PHY_REG_14 0x38 +#define REG14_TOL_MASK GENMASK(7, 4) +#define REG14_RP_CODE_MASK GENMASK(3, 1) +#define REG14_TG_CODE_HIGH_MASK GENMASK(0, 0) + +#define PHY_REG_15 0x3c +#define PHY_REG_16 0x40 +#define PHY_REG_17 0x44 +#define PHY_REG_18 0x48 +#define PHY_REG_19 0x4c +#define PHY_REG_20 0x50 + +#define PHY_REG_21 0x54 +#define REG21_SEL_TX_CK_INV BIT(7) +#define REG21_PMS_S_MASK GENMASK(3, 0) + +#define PHY_REG_22 0x58 +#define PHY_REG_23 0x5c +#define PHY_REG_24 0x60 +#define PHY_REG_25 0x64 +#define PHY_REG_26 0x68 +#define PHY_REG_27 0x6c +#define PHY_REG_28 0x70 +#define PHY_REG_29 0x74 +#define PHY_REG_30 0x78 +#define PHY_REG_31 0x7c +#define PHY_REG_32 0x80 + +/* + * REG33 does not match the ref manual. According to Sandor Yu from NXP, + * "There is a doc issue on the i.MX8MP latest RM" + * REG33 is being used per guidance from Sandor + */ + +#define PHY_REG_33 0x84 +#define REG33_MODE_SET_DONE BIT(7) +#define REG33_FIX_DA BIT(1) + +#define PHY_REG_34 0x88 +#define REG34_PHY_READY BIT(7) +#define REG34_PLL_LOCK BIT(6) +#define REG34_PHY_CLK_READY BIT(5) + +#define PHY_REG_35 0x8c +#define PHY_REG_36 0x90 +#define PHY_REG_37 0x94 +#define PHY_REG_38 0x98 +#define PHY_REG_39 0x9c +#define PHY_REG_40 0xa0 +#define PHY_REG_41 0xa4 +#define PHY_REG_42 0xa8 +#define PHY_REG_43 0xac +#define PHY_REG_44 0xb0 +#define PHY_REG_45 0xb4 +#define PHY_REG_46 0xb8 +#define PHY_REG_47 0xbc + +#define PHY_PLL_DIV_REGS_NUM 6 + +struct phy_config { + u32 pixclk; + u8 pll_div_regs[PHY_PLL_DIV_REGS_NUM]; +}; + +static const struct phy_config phy_pll_cfg[] = { + { + .pixclk = 22250000, + .pll_div_regs = { 0x4b, 0xf1, 0x89, 0x88, 0x80, 0x40 }, + }, { + .pixclk = 23750000, + .pll_div_regs = { 0x50, 0xf1, 0x86, 0x85, 0x80, 0x40 }, + }, { + .pixclk = 24000000, + .pll_div_regs = { 0x50, 0xf0, 0x00, 0x00, 0x80, 0x00 }, + }, { + .pixclk = 24024000, + .pll_div_regs = { 0x50, 0xf1, 0x99, 0x02, 0x80, 0x40 }, + }, { + .pixclk = 25175000, + .pll_div_regs = { 0x54, 0xfc, 0xcc, 0x91, 0x80, 0x40 }, + }, { + .pixclk = 25200000, + .pll_div_regs = { 0x54, 0xf0, 0x00, 0x00, 0x80, 0x00 }, + }, { + .pixclk = 26750000, + .pll_div_regs = { 0x5a, 0xf2, 0x89, 0x88, 0x80, 0x40 }, + }, { + .pixclk = 27000000, + .pll_div_regs = { 0x5a, 0xf0, 0x00, 0x00, 0x80, 0x00 }, + }, { + .pixclk = 27027000, + .pll_div_regs = { 0x5a, 0xf2, 0xfd, 0x0c, 0x80, 0x40 }, + }, { + .pixclk = 29500000, + .pll_div_regs = { 0x62, 0xf4, 0x95, 0x08, 0x80, 0x40 }, + }, { + .pixclk = 30750000, + .pll_div_regs = { 0x66, 0xf4, 0x82, 0x01, 0x88, 0x45 }, + }, { + .pixclk = 30888000, + .pll_div_regs = { 0x66, 0xf4, 0x99, 0x18, 0x88, 0x45 }, + }, { + .pixclk = 33750000, + .pll_div_regs = { 0x70, 0xf4, 0x82, 0x01, 0x80, 0x40 }, + }, { + .pixclk = 35000000, + .pll_div_regs = { 0x58, 0xb8, 0x8b, 0x88, 0x80, 0x40 }, + }, { + .pixclk = 36000000, + .pll_div_regs = { 0x5a, 0xb0, 0x00, 0x00, 0x80, 0x00 }, + }, { + .pixclk = 36036000, + .pll_div_regs = { 0x5a, 0xb2, 0xfd, 0x0c, 0x80, 0x40 }, + }, { + .pixclk = 40000000, + .pll_div_regs = { 0x64, 0xb0, 0x00, 0x00, 0x80, 0x00 }, + }, { + .pixclk = 43200000, + .pll_div_regs = { 0x5a, 0x90, 0x00, 0x00, 0x80, 0x00 }, + }, { + .pixclk = 43243200, + .pll_div_regs = { 0x5a, 0x92, 0xfd, 0x0c, 0x80, 0x40 }, + }, { + .pixclk = 44500000, + .pll_div_regs = { 0x5c, 0x92, 0x98, 0x11, 0x84, 0x41 }, + }, { + .pixclk = 47000000, + .pll_div_regs = { 0x62, 0x94, 0x95, 0x82, 0x80, 0x40 }, + }, { + .pixclk = 47500000, + .pll_div_regs = { 0x63, 0x96, 0xa1, 0x82, 0x80, 0x40 }, + }, { + .pixclk = 50349650, + .pll_div_regs = { 0x54, 0x7c, 0xc3, 0x8f, 0x80, 0x40 }, + }, { + .pixclk = 50400000, + .pll_div_regs = { 0x54, 0x70, 0x00, 0x00, 0x80, 0x00 }, + }, { + .pixclk = 53250000, + .pll_div_regs = { 0x58, 0x72, 0x84, 0x03, 0x82, 0x41 }, + }, { + .pixclk = 53500000, + .pll_div_regs = { 0x5a, 0x72, 0x89, 0x88, 0x80, 0x40 }, + }, { + .pixclk = 54000000, + .pll_div_regs = { 0x5a, 0x70, 0x00, 0x00, 0x80, 0x00 }, + }, { + .pixclk = 54054000, + .pll_div_regs = { 0x5a, 0x72, 0xfd, 0x0c, 0x80, 0x40 }, + }, { + .pixclk = 59000000, + .pll_div_regs = { 0x62, 0x74, 0x95, 0x08, 0x80, 0x40 }, + }, { + .pixclk = 59340659, + .pll_div_regs = { 0x62, 0x74, 0xdb, 0x52, 0x88, 0x47 }, + }, { + .pixclk = 59400000, + .pll_div_regs = { 0x63, 0x70, 0x00, 0x00, 0x80, 0x00 }, + }, { + .pixclk = 61500000, + .pll_div_regs = { 0x66, 0x74, 0x82, 0x01, 0x88, 0x45 }, + }, { + .pixclk = 63500000, + .pll_div_regs = { 0x69, 0x74, 0x89, 0x08, 0x80, 0x40 }, + }, { + .pixclk = 67500000, + .pll_div_regs = { 0x54, 0x52, 0x87, 0x03, 0x80, 0x40 }, + }, { + .pixclk = 70000000, + .pll_div_regs = { 0x58, 0x58, 0x8b, 0x88, 0x80, 0x40 }, + }, { + .pixclk = 72000000, + .pll_div_regs = { 0x5a, 0x50, 0x00, 0x00, 0x80, 0x00 }, + }, { + .pixclk = 72072000, + .pll_div_regs = { 0x5a, 0x52, 0xfd, 0x0c, 0x80, 0x40 }, + }, { + .pixclk = 74176000, + .pll_div_regs = { 0x5d, 0x58, 0xdb, 0xA2, 0x88, 0x41 }, + }, { + .pixclk = 74250000, + .pll_div_regs = { 0x5c, 0x52, 0x90, 0x0d, 0x84, 0x41 }, + }, { + .pixclk = 78500000, + .pll_div_regs = { 0x62, 0x54, 0x87, 0x01, 0x80, 0x40 }, + }, { + .pixclk = 80000000, + .pll_div_regs = { 0x64, 0x50, 0x00, 0x00, 0x80, 0x00 }, + }, { + .pixclk = 82000000, + .pll_div_regs = { 0x66, 0x54, 0x82, 0x01, 0x88, 0x45 }, + }, { + .pixclk = 82500000, + .pll_div_regs = { 0x67, 0x54, 0x88, 0x01, 0x90, 0x49 }, + }, { + .pixclk = 89000000, + .pll_div_regs = { 0x70, 0x54, 0x84, 0x83, 0x80, 0x40 }, + }, { + .pixclk = 90000000, + .pll_div_regs = { 0x70, 0x54, 0x82, 0x01, 0x80, 0x40 }, + }, { + .pixclk = 94000000, + .pll_div_regs = { 0x4e, 0x32, 0xa7, 0x10, 0x80, 0x40 }, + }, { + .pixclk = 95000000, + .pll_div_regs = { 0x50, 0x31, 0x86, 0x85, 0x80, 0x40 }, + }, { + .pixclk = 98901099, + .pll_div_regs = { 0x52, 0x3a, 0xdb, 0x4c, 0x88, 0x47 }, + }, { + .pixclk = 99000000, + .pll_div_regs = { 0x52, 0x32, 0x82, 0x01, 0x88, 0x47 }, + }, { + .pixclk = 100699300, + .pll_div_regs = { 0x54, 0x3c, 0xc3, 0x8f, 0x80, 0x40 }, + }, { + .pixclk = 100800000, + .pll_div_regs = { 0x54, 0x30, 0x00, 0x00, 0x80, 0x00 }, + }, { + .pixclk = 102500000, + .pll_div_regs = { 0x55, 0x32, 0x8c, 0x05, 0x90, 0x4b }, + }, { + .pixclk = 104750000, + .pll_div_regs = { 0x57, 0x32, 0x98, 0x07, 0x90, 0x49 }, + }, { + .pixclk = 106500000, + .pll_div_regs = { 0x58, 0x32, 0x84, 0x03, 0x82, 0x41 }, + }, { + .pixclk = 107000000, + .pll_div_regs = { 0x5a, 0x32, 0x89, 0x88, 0x80, 0x40 }, + }, { + .pixclk = 108000000, + .pll_div_regs = { 0x5a, 0x30, 0x00, 0x00, 0x80, 0x00 }, + }, { + .pixclk = 108108000, + .pll_div_regs = { 0x5a, 0x32, 0xfd, 0x0c, 0x80, 0x40 }, + }, { + .pixclk = 118000000, + .pll_div_regs = { 0x62, 0x34, 0x95, 0x08, 0x80, 0x40 }, + }, { + .pixclk = 118800000, + .pll_div_regs = { 0x63, 0x30, 0x00, 0x00, 0x80, 0x00 }, + }, { + .pixclk = 123000000, + .pll_div_regs = { 0x66, 0x34, 0x82, 0x01, 0x88, 0x45 }, + }, { + .pixclk = 127000000, + .pll_div_regs = { 0x69, 0x34, 0x89, 0x08, 0x80, 0x40 }, + }, { + .pixclk = 135000000, + .pll_div_regs = { 0x70, 0x34, 0x82, 0x01, 0x80, 0x40 }, + }, { + .pixclk = 135580000, + .pll_div_regs = { 0x71, 0x39, 0xe9, 0x82, 0x9c, 0x5b }, + }, { + .pixclk = 137520000, + .pll_div_regs = { 0x72, 0x38, 0x99, 0x10, 0x85, 0x41 }, + }, { + .pixclk = 138750000, + .pll_div_regs = { 0x73, 0x35, 0x88, 0x05, 0x90, 0x4d }, + }, { + .pixclk = 140000000, + .pll_div_regs = { 0x75, 0x36, 0xa7, 0x90, 0x80, 0x40 }, + }, { + .pixclk = 144000000, + .pll_div_regs = { 0x78, 0x30, 0x00, 0x00, 0x80, 0x00 }, + }, { + .pixclk = 148352000, + .pll_div_regs = { 0x7b, 0x35, 0xdb, 0x39, 0x90, 0x45 }, + }, { + .pixclk = 148500000, + .pll_div_regs = { 0x7b, 0x35, 0x84, 0x03, 0x90, 0x45 }, + }, { + .pixclk = 154000000, + .pll_div_regs = { 0x40, 0x18, 0x83, 0x01, 0x00, 0x40 }, + }, { + .pixclk = 157000000, + .pll_div_regs = { 0x41, 0x11, 0xa7, 0x14, 0x80, 0x40 }, + }, { + .pixclk = 160000000, + .pll_div_regs = { 0x42, 0x12, 0xa1, 0x20, 0x80, 0x40 }, + }, { + .pixclk = 162000000, + .pll_div_regs = { 0x43, 0x18, 0x8b, 0x08, 0x96, 0x55 }, + }, { + .pixclk = 164000000, + .pll_div_regs = { 0x45, 0x11, 0x83, 0x82, 0x90, 0x4b }, + }, { + .pixclk = 165000000, + .pll_div_regs = { 0x45, 0x11, 0x84, 0x81, 0x90, 0x4b }, + }, { + .pixclk = 180000000, + .pll_div_regs = { 0x4b, 0x10, 0x00, 0x00, 0x80, 0x00 }, + }, { + .pixclk = 185625000, + .pll_div_regs = { 0x4e, 0x12, 0x9a, 0x95, 0x80, 0x40 }, + }, { + .pixclk = 188000000, + .pll_div_regs = { 0x4e, 0x12, 0xa7, 0x10, 0x80, 0x40 }, + }, { + .pixclk = 198000000, + .pll_div_regs = { 0x52, 0x12, 0x82, 0x01, 0x88, 0x47 }, + }, { + .pixclk = 205000000, + .pll_div_regs = { 0x55, 0x12, 0x8c, 0x05, 0x90, 0x4b }, + }, { + .pixclk = 209500000, + .pll_div_regs = { 0x57, 0x12, 0x98, 0x07, 0x90, 0x49 }, + }, { + .pixclk = 213000000, + .pll_div_regs = { 0x58, 0x12, 0x84, 0x03, 0x82, 0x41 }, + }, { + .pixclk = 216000000, + .pll_div_regs = { 0x5a, 0x10, 0x00, 0x00, 0x80, 0x00 }, + }, { + .pixclk = 216216000, + .pll_div_regs = { 0x5a, 0x12, 0xfd, 0x0c, 0x80, 0x40 }, + }, { + .pixclk = 237600000, + .pll_div_regs = { 0x63, 0x10, 0x00, 0x00, 0x80, 0x00 }, + }, { + .pixclk = 254000000, + .pll_div_regs = { 0x69, 0x14, 0x89, 0x08, 0x80, 0x40 }, + }, { + .pixclk = 277500000, + .pll_div_regs = { 0x73, 0x15, 0x88, 0x05, 0x90, 0x4d }, + }, { + .pixclk = 288000000, + .pll_div_regs = { 0x78, 0x10, 0x00, 0x00, 0x80, 0x00 }, + }, { + .pixclk = 297000000, + .pll_div_regs = { 0x7b, 0x15, 0x84, 0x03, 0x90, 0x45 }, + }, +}; + +struct reg_settings { + u8 reg; + u8 val; +}; + +static const struct reg_settings common_phy_cfg[] = { + { PHY_REG_00, 0x00 }, { PHY_REG_01, 0xd1 }, + { PHY_REG_08, 0x4f }, { PHY_REG_09, 0x30 }, + { PHY_REG_10, 0x33 }, { PHY_REG_11, 0x65 }, + /* REG12 pixclk specific */ + /* REG13 pixclk specific */ + /* REG14 pixclk specific */ + { PHY_REG_15, 0x80 }, { PHY_REG_16, 0x6c }, + { PHY_REG_17, 0xf2 }, { PHY_REG_18, 0x67 }, + { PHY_REG_19, 0x00 }, { PHY_REG_20, 0x10 }, + /* REG21 pixclk specific */ + { PHY_REG_22, 0x30 }, { PHY_REG_23, 0x32 }, + { PHY_REG_24, 0x60 }, { PHY_REG_25, 0x8f }, + { PHY_REG_26, 0x00 }, { PHY_REG_27, 0x00 }, + { PHY_REG_28, 0x08 }, { PHY_REG_29, 0x00 }, + { PHY_REG_30, 0x00 }, { PHY_REG_31, 0x00 }, + { PHY_REG_32, 0x00 }, { PHY_REG_33, 0x80 }, + { PHY_REG_34, 0x00 }, { PHY_REG_35, 0x00 }, + { PHY_REG_36, 0x00 }, { PHY_REG_37, 0x00 }, + { PHY_REG_38, 0x00 }, { PHY_REG_39, 0x00 }, + { PHY_REG_40, 0x00 }, { PHY_REG_41, 0xe0 }, + { PHY_REG_42, 0x83 }, { PHY_REG_43, 0x0f }, + { PHY_REG_44, 0x3E }, { PHY_REG_45, 0xf8 }, + { PHY_REG_46, 0x00 }, { PHY_REG_47, 0x00 } +}; + +struct fsl_samsung_hdmi_phy { + struct device *dev; + void __iomem *regs; + struct clk *apbclk; + struct clk *refclk; + + /* clk provider */ + struct clk_hw hw; + const struct phy_config *cur_cfg; +}; + +static inline struct fsl_samsung_hdmi_phy * +to_fsl_samsung_hdmi_phy(struct clk_hw *hw) +{ + return container_of(hw, struct fsl_samsung_hdmi_phy, hw); +} + +static void +fsl_samsung_hdmi_phy_configure_pixclk(struct fsl_samsung_hdmi_phy *phy, + const struct phy_config *cfg) +{ + u8 div = 0x1; + + switch (cfg->pixclk) { + case 22250000 ... 33750000: + div = 0xf; + break; + case 35000000 ... 40000000: + div = 0xb; + break; + case 43200000 ... 47500000: + div = 0x9; + break; + case 50349650 ... 63500000: + div = 0x7; + break; + case 67500000 ... 90000000: + div = 0x5; + break; + case 94000000 ... 148500000: + div = 0x3; + break; + case 154000000 ... 297000000: + div = 0x1; + break; + } + + writeb(REG21_SEL_TX_CK_INV | FIELD_PREP(REG21_PMS_S_MASK, div), + phy->regs + PHY_REG_21); +} + +static void +fsl_samsung_hdmi_phy_configure_pll_lock_det(struct fsl_samsung_hdmi_phy *phy, + const struct phy_config *cfg) +{ + u32 pclk = cfg->pixclk; + u32 fld_tg_code; + u32 pclk_khz; + u8 div = 1; + + switch (cfg->pixclk) { + case 22250000 ... 47500000: + div = 1; + break; + case 50349650 ... 99000000: + div = 2; + break; + case 100699300 ... 198000000: + div = 4; + break; + case 205000000 ... 297000000: + div = 8; + break; + } + + writeb(FIELD_PREP(REG12_CK_DIV_MASK, ilog2(div)), phy->regs + PHY_REG_12); + + /* + * Calculation for the frequency lock detector target code (fld_tg_code) + * is based on reference manual register description of PHY_REG13 + * (13.10.3.1.14.2): + * 1st) Calculate int_pllclk which is determinded by FLD_CK_DIV + * 2nd) Increase resolution to avoid rounding issues + * 3th) Do the div (256 / Freq. of int_pllclk) * 24 + * 4th) Reduce the resolution and always round up since the NXP + * settings rounding up always too. TODO: Check if that is + * correct. + */ + pclk /= div; + pclk_khz = pclk / 1000; + fld_tg_code = 256 * 1000 * 1000 / pclk_khz * 24; + fld_tg_code = DIV_ROUND_UP(fld_tg_code, 1000); + + /* FLD_TOL and FLD_RP_CODE taken from downstream driver */ + writeb(FIELD_PREP(REG13_TG_CODE_LOW_MASK, fld_tg_code), + phy->regs + PHY_REG_13); + writeb(FIELD_PREP(REG14_TOL_MASK, 2) | + FIELD_PREP(REG14_RP_CODE_MASK, 2) | + FIELD_PREP(REG14_TG_CODE_HIGH_MASK, fld_tg_code >> 8), + phy->regs + PHY_REG_14); +} + +static int fsl_samsung_hdmi_phy_configure(struct fsl_samsung_hdmi_phy *phy, + const struct phy_config *cfg) +{ + int i, ret; + u8 val; + + /* HDMI PHY init */ + writeb(REG33_FIX_DA, phy->regs + PHY_REG_33); + + /* common PHY registers */ + for (i = 0; i < ARRAY_SIZE(common_phy_cfg); i++) + writeb(common_phy_cfg[i].val, phy->regs + common_phy_cfg[i].reg); + + /* set individual PLL registers PHY_REG2 ... PHY_REG7 */ + for (i = 0; i < PHY_PLL_DIV_REGS_NUM; i++) + writeb(cfg->pll_div_regs[i], phy->regs + PHY_REG_02 + i * 4); + + fsl_samsung_hdmi_phy_configure_pixclk(phy, cfg); + fsl_samsung_hdmi_phy_configure_pll_lock_det(phy, cfg); + + writeb(REG33_FIX_DA | REG33_MODE_SET_DONE, phy->regs + PHY_REG_33); + + ret = readb_poll_timeout(phy->regs + PHY_REG_34, val, + val & REG34_PLL_LOCK, 50, 20000); + if (ret) + dev_err(phy->dev, "PLL failed to lock\n"); + + return ret; +} + +static unsigned long phy_clk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct fsl_samsung_hdmi_phy *phy = to_fsl_samsung_hdmi_phy(hw); + + if (!phy->cur_cfg) + return 74250000; + + return phy->cur_cfg->pixclk; +} + +static long phy_clk_round_rate(struct clk_hw *hw, + unsigned long rate, unsigned long *parent_rate) +{ + int i; + + for (i = ARRAY_SIZE(phy_pll_cfg) - 1; i >= 0; i--) + if (phy_pll_cfg[i].pixclk <= rate) + return phy_pll_cfg[i].pixclk; + + return -EINVAL; +} + +static int phy_clk_set_rate(struct clk_hw *hw, + unsigned long rate, unsigned long parent_rate) +{ + struct fsl_samsung_hdmi_phy *phy = to_fsl_samsung_hdmi_phy(hw); + int i; + + for (i = ARRAY_SIZE(phy_pll_cfg) - 1; i >= 0; i--) + if (phy_pll_cfg[i].pixclk <= rate) + break; + + if (i < 0) + return -EINVAL; + + phy->cur_cfg = &phy_pll_cfg[i]; + + return fsl_samsung_hdmi_phy_configure(phy, phy->cur_cfg); +} + +static const struct clk_ops phy_clk_ops = { + .recalc_rate = phy_clk_recalc_rate, + .round_rate = phy_clk_round_rate, + .set_rate = phy_clk_set_rate, +}; + +static int phy_clk_register(struct fsl_samsung_hdmi_phy *phy) +{ + struct device *dev = phy->dev; + struct device_node *np = dev->of_node; + struct clk_init_data init; + const char *parent_name; + struct clk *phyclk; + int ret; + + parent_name = __clk_get_name(phy->refclk); + + init.parent_names = &parent_name; + init.num_parents = 1; + init.flags = 0; + init.name = "hdmi_pclk"; + init.ops = &phy_clk_ops; + + phy->hw.init = &init; + + phyclk = devm_clk_register(dev, &phy->hw); + if (IS_ERR(phyclk)) + return dev_err_probe(dev, PTR_ERR(phyclk), + "failed to register clock\n"); + + ret = of_clk_add_hw_provider(np, of_clk_hw_simple_get, phyclk); + if (ret) + return dev_err_probe(dev, ret, + "failed to register clock provider\n"); + + return 0; +} + +static int fsl_samsung_hdmi_phy_probe(struct platform_device *pdev) +{ + struct fsl_samsung_hdmi_phy *phy; + int ret; + + phy = devm_kzalloc(&pdev->dev, sizeof(*phy), GFP_KERNEL); + if (!phy) + return -ENOMEM; + + platform_set_drvdata(pdev, phy); + phy->dev = &pdev->dev; + + phy->regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(phy->regs)) + return PTR_ERR(phy->regs); + + phy->apbclk = devm_clk_get(phy->dev, "apb"); + if (IS_ERR(phy->apbclk)) + return dev_err_probe(phy->dev, PTR_ERR(phy->apbclk), + "failed to get apb clk\n"); + + phy->refclk = devm_clk_get(phy->dev, "ref"); + if (IS_ERR(phy->refclk)) + return dev_err_probe(phy->dev, PTR_ERR(phy->refclk), + "failed to get ref clk\n"); + + ret = clk_prepare_enable(phy->apbclk); + if (ret) { + dev_err(phy->dev, "failed to enable apbclk\n"); + return ret; + } + + pm_runtime_get_noresume(phy->dev); + pm_runtime_set_active(phy->dev); + pm_runtime_enable(phy->dev); + + ret = phy_clk_register(phy); + if (ret) { + dev_err(&pdev->dev, "register clk failed\n"); + goto register_clk_failed; + } + + pm_runtime_put(phy->dev); + + return 0; + +register_clk_failed: + clk_disable_unprepare(phy->apbclk); + + return ret; +} + +static int fsl_samsung_hdmi_phy_remove(struct platform_device *pdev) +{ + of_clk_del_provider(pdev->dev.of_node); + + return 0; +} + +static int __maybe_unused fsl_samsung_hdmi_phy_suspend(struct device *dev) +{ + struct fsl_samsung_hdmi_phy *phy = dev_get_drvdata(dev); + + clk_disable_unprepare(phy->apbclk); + + return 0; +} + +static int __maybe_unused fsl_samsung_hdmi_phy_resume(struct device *dev) +{ + struct fsl_samsung_hdmi_phy *phy = dev_get_drvdata(dev); + int ret = 0; + + ret = clk_prepare_enable(phy->apbclk); + if (ret) { + dev_err(phy->dev, "failed to enable apbclk\n"); + return ret; + } + + if (phy->cur_cfg) + ret = fsl_samsung_hdmi_phy_configure(phy, phy->cur_cfg); + + return ret; + +} + +static DEFINE_RUNTIME_DEV_PM_OPS(fsl_samsung_hdmi_phy_pm_ops, + fsl_samsung_hdmi_phy_suspend, + fsl_samsung_hdmi_phy_resume, NULL); + +static const struct of_device_id fsl_samsung_hdmi_phy_of_match[] = { + { + .compatible = "fsl,imx8mp-hdmi-phy", + }, { + /* sentinel */ + } +}; +MODULE_DEVICE_TABLE(of, fsl_samsung_hdmi_phy_of_match); + +static struct platform_driver fsl_samsung_hdmi_phy_driver = { + .probe = fsl_samsung_hdmi_phy_probe, + .remove = fsl_samsung_hdmi_phy_remove, + .driver = { + .name = "fsl-samsung-hdmi-phy", + .of_match_table = fsl_samsung_hdmi_phy_of_match, + .pm = pm_ptr(&fsl_samsung_hdmi_phy_pm_ops), + }, +}; +module_platform_driver(fsl_samsung_hdmi_phy_driver); + +MODULE_AUTHOR("Sandor Yu "); +MODULE_DESCRIPTION("SAMSUNG HDMI 2.0 Transmitter PHY Driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3-59-g8ed1b From f8d27a7e0ae36c204bffe4992043b2bb42ca8580 Mon Sep 17 00:00:00 2001 From: Abel Vesa Date: Tue, 20 Feb 2024 21:41:59 +0200 Subject: dt-bindings: phy: qcom,snps-eusb2-repeater: Add compatible for SMB2360 Add a dt-bindings compatible string for the Qualcomm's SMB2360 PMIC. Acked-by: Krzysztof Kozlowski Signed-off-by: Abel Vesa Link: https://lore.kernel.org/r/20240220-phy-qualcomm-eusb2-repeater-smb2360-v2-1-213338ca1d5f@linaro.org Signed-off-by: Vinod Koul --- Documentation/devicetree/bindings/phy/qcom,snps-eusb2-repeater.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/phy/qcom,snps-eusb2-repeater.yaml b/Documentation/devicetree/bindings/phy/qcom,snps-eusb2-repeater.yaml index 24c733c10e0e..90d79491e281 100644 --- a/Documentation/devicetree/bindings/phy/qcom,snps-eusb2-repeater.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,snps-eusb2-repeater.yaml @@ -20,7 +20,9 @@ properties: - enum: - qcom,pm7550ba-eusb2-repeater - const: qcom,pm8550b-eusb2-repeater - - const: qcom,pm8550b-eusb2-repeater + - enum: + - qcom,pm8550b-eusb2-repeater + - qcom,smb2360-eusb2-repeater reg: maxItems: 1 -- cgit v1.2.3-59-g8ed1b From 67076749e093ffb3c82ba6225d41c88f8c816472 Mon Sep 17 00:00:00 2001 From: Abel Vesa Date: Tue, 20 Feb 2024 21:42:00 +0200 Subject: phy: qualcomm: phy-qcom-eusb2-repeater: Add support for SMB2360 The SMB2360 PMICs contain the same repeater as the PM8550B, but requiring different settings, so add dedicated compatible for SMB2360. Reviewed-by: Dmitry Baryshkov Signed-off-by: Abel Vesa Link: https://lore.kernel.org/r/20240220-phy-qualcomm-eusb2-repeater-smb2360-v2-2-213338ca1d5f@linaro.org Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c b/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c index a43e20abb10d..68cc8e24f383 100644 --- a/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c +++ b/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c @@ -88,6 +88,12 @@ static const u32 pm8550b_init_tbl[NUM_TUNE_FIELDS] = { [TUNE_USB2_PREEM] = 0x5, }; +static const u32 smb2360_init_tbl[NUM_TUNE_FIELDS] = { + [TUNE_IUSB2] = 0x5, + [TUNE_SQUELCH_U] = 0x3, + [TUNE_USB2_PREEM] = 0x2, +}; + static const struct eusb2_repeater_cfg pm8550b_eusb2_cfg = { .init_tbl = pm8550b_init_tbl, .init_tbl_num = ARRAY_SIZE(pm8550b_init_tbl), @@ -95,6 +101,13 @@ static const struct eusb2_repeater_cfg pm8550b_eusb2_cfg = { .num_vregs = ARRAY_SIZE(pm8550b_vreg_l), }; +static const struct eusb2_repeater_cfg smb2360_eusb2_cfg = { + .init_tbl = smb2360_init_tbl, + .init_tbl_num = ARRAY_SIZE(smb2360_init_tbl), + .vreg_list = pm8550b_vreg_l, + .num_vregs = ARRAY_SIZE(pm8550b_vreg_l), +}; + static int eusb2_repeater_init_vregs(struct eusb2_repeater *rptr) { int num = rptr->cfg->num_vregs; @@ -271,6 +284,10 @@ static const struct of_device_id eusb2_repeater_of_match_table[] = { .compatible = "qcom,pm8550b-eusb2-repeater", .data = &pm8550b_eusb2_cfg, }, + { + .compatible = "qcom,smb2360-eusb2-repeater", + .data = &smb2360_eusb2_cfg, + }, { }, }; MODULE_DEVICE_TABLE(of, eusb2_repeater_of_match_table); -- cgit v1.2.3-59-g8ed1b From 5d5607861350db4020b3d74c02837ffc008701d9 Mon Sep 17 00:00:00 2001 From: Abel Vesa Date: Wed, 21 Feb 2024 00:05:21 +0200 Subject: dt-bindings: phy: qcom-edp: Add X1E80100 PHY compatibles The Qualcomm X1E80100 platform has multiple PHYs that can work in both eDP or DP mode, so document their compatible. Signed-off-by: Abel Vesa Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240221-phy-qualcomm-edp-x1e80100-v4-1-4e5018877bee@linaro.org Signed-off-by: Vinod Koul --- Documentation/devicetree/bindings/phy/qcom,edp-phy.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/phy/qcom,edp-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,edp-phy.yaml index 6566353f1a02..4e15d90d08b0 100644 --- a/Documentation/devicetree/bindings/phy/qcom,edp-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,edp-phy.yaml @@ -21,6 +21,7 @@ properties: - qcom,sc8180x-edp-phy - qcom,sc8280xp-dp-phy - qcom,sc8280xp-edp-phy + - qcom,x1e80100-dp-phy reg: items: -- cgit v1.2.3-59-g8ed1b From 9eb8e3dd297f976aec24e07c5e3ca1e79629140b Mon Sep 17 00:00:00 2001 From: Abel Vesa Date: Wed, 21 Feb 2024 00:05:22 +0200 Subject: phy: qcom: edp: Move v4 specific settings to version ops In order to support different HW versions move everything specific to v4 into so-called version ops. Signed-off-by: Abel Vesa Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20240221-phy-qualcomm-edp-x1e80100-v4-2-4e5018877bee@linaro.org Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-edp.c | 183 +++++++++++++++++++++++------------- 1 file changed, 118 insertions(+), 65 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-edp.c b/drivers/phy/qualcomm/phy-qcom-edp.c index 621d0453bf76..9bbf977c7b4e 100644 --- a/drivers/phy/qualcomm/phy-qcom-edp.c +++ b/drivers/phy/qualcomm/phy-qcom-edp.c @@ -77,9 +77,20 @@ struct qcom_edp_swing_pre_emph_cfg { const u8 (*pre_emphasis_hbr3_hbr2)[4][4]; }; +struct qcom_edp; + +struct phy_ver_ops { + int (*com_power_on)(const struct qcom_edp *edp); + int (*com_resetsm_cntrl)(const struct qcom_edp *edp); + int (*com_bias_en_clkbuflr)(const struct qcom_edp *edp); + int (*com_configure_pll)(const struct qcom_edp *edp); + int (*com_configure_ssc)(const struct qcom_edp *edp); +}; + struct qcom_edp_phy_cfg { bool is_edp; const struct qcom_edp_swing_pre_emph_cfg *swing_pre_emph_cfg; + const struct phy_ver_ops *ver_ops; }; struct qcom_edp { @@ -174,18 +185,6 @@ static const struct qcom_edp_swing_pre_emph_cfg edp_phy_swing_pre_emph_cfg = { .pre_emphasis_hbr3_hbr2 = &edp_pre_emp_hbr2_hbr3, }; -static const struct qcom_edp_phy_cfg sc7280_dp_phy_cfg = { -}; - -static const struct qcom_edp_phy_cfg sc8280xp_dp_phy_cfg = { - .swing_pre_emph_cfg = &dp_phy_swing_pre_emph_cfg, -}; - -static const struct qcom_edp_phy_cfg sc8280xp_edp_phy_cfg = { - .is_edp = true, - .swing_pre_emph_cfg = &edp_phy_swing_pre_emph_cfg, -}; - static int qcom_edp_phy_init(struct phy *phy) { struct qcom_edp *edp = phy_get_drvdata(phy); @@ -204,8 +203,9 @@ static int qcom_edp_phy_init(struct phy *phy) DP_PHY_PD_CTL_PLL_PWRDN | DP_PHY_PD_CTL_DP_CLAMP_EN, edp->edp + DP_PHY_PD_CTL); - /* Turn on BIAS current for PHY/PLL */ - writel(0x17, edp->pll + QSERDES_V4_COM_BIAS_EN_CLKBUFLR_EN); + ret = edp->cfg->ver_ops->com_bias_en_clkbuflr(edp); + if (ret) + return ret; writel(DP_PHY_PD_CTL_PSR_PWRDN, edp->edp + DP_PHY_PD_CTL); msleep(20); @@ -312,6 +312,84 @@ static int qcom_edp_phy_configure(struct phy *phy, union phy_configure_opts *opt } static int qcom_edp_configure_ssc(const struct qcom_edp *edp) +{ + return edp->cfg->ver_ops->com_configure_ssc(edp); +} + +static int qcom_edp_configure_pll(const struct qcom_edp *edp) +{ + return edp->cfg->ver_ops->com_configure_pll(edp); +} + +static int qcom_edp_set_vco_div(const struct qcom_edp *edp, unsigned long *pixel_freq) +{ + const struct phy_configure_opts_dp *dp_opts = &edp->dp_opts; + u32 vco_div; + + switch (dp_opts->link_rate) { + case 1620: + vco_div = 0x1; + *pixel_freq = 1620000000UL / 2; + break; + + case 2700: + vco_div = 0x1; + *pixel_freq = 2700000000UL / 2; + break; + + case 5400: + vco_div = 0x2; + *pixel_freq = 5400000000UL / 4; + break; + + case 8100: + vco_div = 0x0; + *pixel_freq = 8100000000UL / 6; + break; + + default: + /* Other link rates aren't supported */ + return -EINVAL; + } + + writel(vco_div, edp->edp + DP_PHY_VCO_DIV); + + return 0; +} + +static int qcom_edp_phy_power_on_v4(const struct qcom_edp *edp) +{ + u32 val; + + writel(DP_PHY_PD_CTL_PWRDN | DP_PHY_PD_CTL_AUX_PWRDN | + DP_PHY_PD_CTL_LANE_0_1_PWRDN | DP_PHY_PD_CTL_LANE_2_3_PWRDN | + DP_PHY_PD_CTL_PLL_PWRDN | DP_PHY_PD_CTL_DP_CLAMP_EN, + edp->edp + DP_PHY_PD_CTL); + writel(0xfc, edp->edp + DP_PHY_MODE); + + return readl_poll_timeout(edp->pll + QSERDES_V4_COM_CMN_STATUS, + val, val & BIT(7), 5, 200); +} + +static int qcom_edp_phy_com_resetsm_cntrl_v4(const struct qcom_edp *edp) +{ + u32 val; + + writel(0x20, edp->pll + QSERDES_V4_COM_RESETSM_CNTRL); + + return readl_poll_timeout(edp->pll + QSERDES_V4_COM_C_READY_STATUS, + val, val & BIT(0), 500, 10000); +} + +static int qcom_edp_com_bias_en_clkbuflr_v4(const struct qcom_edp *edp) +{ + /* Turn on BIAS current for PHY/PLL */ + writel(0x17, edp->pll + QSERDES_V4_COM_BIAS_EN_CLKBUFLR_EN); + + return 0; +} + +static int qcom_edp_com_configure_ssc_v4(const struct qcom_edp *edp) { const struct phy_configure_opts_dp *dp_opts = &edp->dp_opts; u32 step1; @@ -345,7 +423,7 @@ static int qcom_edp_configure_ssc(const struct qcom_edp *edp) return 0; } -static int qcom_edp_configure_pll(const struct qcom_edp *edp) +static int qcom_edp_com_configure_pll_v4(const struct qcom_edp *edp) { const struct phy_configure_opts_dp *dp_opts = &edp->dp_opts; u32 div_frac_start2_mode0; @@ -431,41 +509,28 @@ static int qcom_edp_configure_pll(const struct qcom_edp *edp) return 0; } -static int qcom_edp_set_vco_div(const struct qcom_edp *edp, unsigned long *pixel_freq) -{ - const struct phy_configure_opts_dp *dp_opts = &edp->dp_opts; - u32 vco_div; - - switch (dp_opts->link_rate) { - case 1620: - vco_div = 0x1; - *pixel_freq = 1620000000UL / 2; - break; - - case 2700: - vco_div = 0x1; - *pixel_freq = 2700000000UL / 2; - break; - - case 5400: - vco_div = 0x2; - *pixel_freq = 5400000000UL / 4; - break; - - case 8100: - vco_div = 0x0; - *pixel_freq = 8100000000UL / 6; - break; +static const struct phy_ver_ops qcom_edp_phy_ops_v4 = { + .com_power_on = qcom_edp_phy_power_on_v4, + .com_resetsm_cntrl = qcom_edp_phy_com_resetsm_cntrl_v4, + .com_bias_en_clkbuflr = qcom_edp_com_bias_en_clkbuflr_v4, + .com_configure_pll = qcom_edp_com_configure_pll_v4, + .com_configure_ssc = qcom_edp_com_configure_ssc_v4, +}; - default: - /* Other link rates aren't supported */ - return -EINVAL; - } +static const struct qcom_edp_phy_cfg sc7280_dp_phy_cfg = { + .ver_ops = &qcom_edp_phy_ops_v4, +}; - writel(vco_div, edp->edp + DP_PHY_VCO_DIV); +static const struct qcom_edp_phy_cfg sc8280xp_dp_phy_cfg = { + .swing_pre_emph_cfg = &dp_phy_swing_pre_emph_cfg, + .ver_ops = &qcom_edp_phy_ops_v4, +}; - return 0; -} +static const struct qcom_edp_phy_cfg sc8280xp_edp_phy_cfg = { + .is_edp = true, + .swing_pre_emph_cfg = &edp_phy_swing_pre_emph_cfg, + .ver_ops = &qcom_edp_phy_ops_v4, +}; static int qcom_edp_phy_power_on(struct phy *phy) { @@ -473,22 +538,13 @@ static int qcom_edp_phy_power_on(struct phy *phy) u32 bias0_en, drvr0_en, bias1_en, drvr1_en; unsigned long pixel_freq; u8 ldo_config = 0x0; - int timeout; int ret; u32 val; u8 cfg1; - writel(DP_PHY_PD_CTL_PWRDN | DP_PHY_PD_CTL_AUX_PWRDN | - DP_PHY_PD_CTL_LANE_0_1_PWRDN | DP_PHY_PD_CTL_LANE_2_3_PWRDN | - DP_PHY_PD_CTL_PLL_PWRDN | DP_PHY_PD_CTL_DP_CLAMP_EN, - edp->edp + DP_PHY_PD_CTL); - writel(0xfc, edp->edp + DP_PHY_MODE); - - timeout = readl_poll_timeout(edp->pll + QSERDES_V4_COM_CMN_STATUS, - val, val & BIT(7), 5, 200); - if (timeout) - return timeout; - + ret = edp->cfg->ver_ops->com_power_on(edp); + if (ret) + return ret; if (edp->cfg->swing_pre_emph_cfg && !edp->is_edp) ldo_config = 0x1; @@ -535,12 +591,9 @@ static int qcom_edp_phy_power_on(struct phy *phy) writel(0x01, edp->edp + DP_PHY_CFG); writel(0x09, edp->edp + DP_PHY_CFG); - writel(0x20, edp->pll + QSERDES_V4_COM_RESETSM_CNTRL); - - timeout = readl_poll_timeout(edp->pll + QSERDES_V4_COM_C_READY_STATUS, - val, val & BIT(0), 500, 10000); - if (timeout) - return timeout; + ret = edp->cfg->ver_ops->com_resetsm_cntrl(edp); + if (ret) + return ret; writel(0x19, edp->edp + DP_PHY_CFG); writel(0x1f, edp->tx0 + TXn_HIGHZ_DRVR_EN); -- cgit v1.2.3-59-g8ed1b From db83c107dc295a6d26727917dc62baa91a1bf989 Mon Sep 17 00:00:00 2001 From: Abel Vesa Date: Wed, 21 Feb 2024 00:05:23 +0200 Subject: phy: qcom: edp: Add v6 specific ops and X1E80100 platform support Add v6 HW support by implementing the version ops. Add the X1E80100 compatible and match config as it is v6. Signed-off-by: Abel Vesa Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20240221-phy-qualcomm-edp-x1e80100-v4-3-4e5018877bee@linaro.org Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-edp.c | 180 ++++++++++++++++++++++++++++++++++++ 1 file changed, 180 insertions(+) diff --git a/drivers/phy/qualcomm/phy-qcom-edp.c b/drivers/phy/qualcomm/phy-qcom-edp.c index 9bbf977c7b4e..da2b32fb5b45 100644 --- a/drivers/phy/qualcomm/phy-qcom-edp.c +++ b/drivers/phy/qualcomm/phy-qcom-edp.c @@ -24,6 +24,7 @@ #include "phy-qcom-qmp-dp-phy.h" #include "phy-qcom-qmp-qserdes-com-v4.h" +#include "phy-qcom-qmp-qserdes-com-v6.h" /* EDP_PHY registers */ #define DP_PHY_CFG 0x0010 @@ -532,6 +533,184 @@ static const struct qcom_edp_phy_cfg sc8280xp_edp_phy_cfg = { .ver_ops = &qcom_edp_phy_ops_v4, }; +static int qcom_edp_phy_power_on_v6(const struct qcom_edp *edp) +{ + u32 val; + + writel(DP_PHY_PD_CTL_PWRDN | DP_PHY_PD_CTL_AUX_PWRDN | + DP_PHY_PD_CTL_LANE_0_1_PWRDN | DP_PHY_PD_CTL_LANE_2_3_PWRDN | + DP_PHY_PD_CTL_PLL_PWRDN | DP_PHY_PD_CTL_DP_CLAMP_EN, + edp->edp + DP_PHY_PD_CTL); + writel(0xfc, edp->edp + DP_PHY_MODE); + + return readl_poll_timeout(edp->pll + QSERDES_V6_COM_CMN_STATUS, + val, val & BIT(7), 5, 200); +} + +static int qcom_edp_phy_com_resetsm_cntrl_v6(const struct qcom_edp *edp) +{ + u32 val; + + writel(0x20, edp->pll + QSERDES_V6_COM_RESETSM_CNTRL); + + return readl_poll_timeout(edp->pll + QSERDES_V6_COM_C_READY_STATUS, + val, val & BIT(0), 500, 10000); +} + +static int qcom_edp_com_bias_en_clkbuflr_v6(const struct qcom_edp *edp) +{ + /* Turn on BIAS current for PHY/PLL */ + writel(0x1f, edp->pll + QSERDES_V6_COM_PLL_BIAS_EN_CLK_BUFLR_EN); + + return 0; +} + +static int qcom_edp_com_configure_ssc_v6(const struct qcom_edp *edp) +{ + const struct phy_configure_opts_dp *dp_opts = &edp->dp_opts; + u32 step1; + u32 step2; + + switch (dp_opts->link_rate) { + case 1620: + case 2700: + case 8100: + step1 = 0x92; + step2 = 0x01; + break; + + case 5400: + step1 = 0x18; + step2 = 0x02; + break; + + default: + /* Other link rates aren't supported */ + return -EINVAL; + } + + writel(0x01, edp->pll + QSERDES_V6_COM_SSC_EN_CENTER); + writel(0x00, edp->pll + QSERDES_V6_COM_SSC_ADJ_PER1); + writel(0x36, edp->pll + QSERDES_V6_COM_SSC_PER1); + writel(0x01, edp->pll + QSERDES_V6_COM_SSC_PER2); + writel(step1, edp->pll + QSERDES_V6_COM_SSC_STEP_SIZE1_MODE0); + writel(step2, edp->pll + QSERDES_V6_COM_SSC_STEP_SIZE2_MODE0); + + return 0; +} + +static int qcom_edp_com_configure_pll_v6(const struct qcom_edp *edp) +{ + const struct phy_configure_opts_dp *dp_opts = &edp->dp_opts; + u32 div_frac_start2_mode0; + u32 div_frac_start3_mode0; + u32 dec_start_mode0; + u32 lock_cmp1_mode0; + u32 lock_cmp2_mode0; + u32 code1_mode0; + u32 code2_mode0; + u32 hsclk_sel; + + switch (dp_opts->link_rate) { + case 1620: + hsclk_sel = 0x5; + dec_start_mode0 = 0x34; + div_frac_start2_mode0 = 0xc0; + div_frac_start3_mode0 = 0x0b; + lock_cmp1_mode0 = 0x37; + lock_cmp2_mode0 = 0x04; + code1_mode0 = 0x71; + code2_mode0 = 0x0c; + break; + + case 2700: + hsclk_sel = 0x3; + dec_start_mode0 = 0x34; + div_frac_start2_mode0 = 0xc0; + div_frac_start3_mode0 = 0x0b; + lock_cmp1_mode0 = 0x07; + lock_cmp2_mode0 = 0x07; + code1_mode0 = 0x71; + code2_mode0 = 0x0c; + break; + + case 5400: + hsclk_sel = 0x1; + dec_start_mode0 = 0x46; + div_frac_start2_mode0 = 0x00; + div_frac_start3_mode0 = 0x05; + lock_cmp1_mode0 = 0x0f; + lock_cmp2_mode0 = 0x0e; + code1_mode0 = 0x97; + code2_mode0 = 0x10; + break; + + case 8100: + hsclk_sel = 0x0; + dec_start_mode0 = 0x34; + div_frac_start2_mode0 = 0xc0; + div_frac_start3_mode0 = 0x0b; + lock_cmp1_mode0 = 0x17; + lock_cmp2_mode0 = 0x15; + code1_mode0 = 0x71; + code2_mode0 = 0x0c; + break; + + default: + /* Other link rates aren't supported */ + return -EINVAL; + } + + writel(0x01, edp->pll + QSERDES_V6_COM_SVS_MODE_CLK_SEL); + writel(0x0b, edp->pll + QSERDES_V6_COM_SYSCLK_EN_SEL); + writel(0x02, edp->pll + QSERDES_V6_COM_SYS_CLK_CTRL); + writel(0x0c, edp->pll + QSERDES_V6_COM_CLK_ENABLE1); + writel(0x06, edp->pll + QSERDES_V6_COM_SYSCLK_BUF_ENABLE); + writel(0x30, edp->pll + QSERDES_V6_COM_CLK_SELECT); + writel(hsclk_sel, edp->pll + QSERDES_V6_COM_HSCLK_SEL_1); + writel(0x07, edp->pll + QSERDES_V6_COM_PLL_IVCO); + writel(0x08, edp->pll + QSERDES_V6_COM_LOCK_CMP_EN); + writel(0x36, edp->pll + QSERDES_V6_COM_PLL_CCTRL_MODE0); + writel(0x16, edp->pll + QSERDES_V6_COM_PLL_RCTRL_MODE0); + writel(0x06, edp->pll + QSERDES_V6_COM_CP_CTRL_MODE0); + writel(dec_start_mode0, edp->pll + QSERDES_V6_COM_DEC_START_MODE0); + writel(0x00, edp->pll + QSERDES_V6_COM_DIV_FRAC_START1_MODE0); + writel(div_frac_start2_mode0, edp->pll + QSERDES_V6_COM_DIV_FRAC_START2_MODE0); + writel(div_frac_start3_mode0, edp->pll + QSERDES_V6_COM_DIV_FRAC_START3_MODE0); + writel(0x12, edp->pll + QSERDES_V6_COM_CMN_CONFIG_1); + writel(0x3f, edp->pll + QSERDES_V6_COM_INTEGLOOP_GAIN0_MODE0); + writel(0x00, edp->pll + QSERDES_V6_COM_INTEGLOOP_GAIN1_MODE0); + writel(0x00, edp->pll + QSERDES_V6_COM_VCO_TUNE_MAP); + writel(lock_cmp1_mode0, edp->pll + QSERDES_V6_COM_LOCK_CMP1_MODE0); + writel(lock_cmp2_mode0, edp->pll + QSERDES_V6_COM_LOCK_CMP2_MODE0); + + writel(0x0a, edp->pll + QSERDES_V6_COM_BG_TIMER); + writel(0x14, edp->pll + QSERDES_V6_COM_PLL_CORE_CLK_DIV_MODE0); + writel(0x00, edp->pll + QSERDES_V6_COM_VCO_TUNE_CTRL); + writel(0x1f, edp->pll + QSERDES_V6_COM_PLL_BIAS_EN_CLK_BUFLR_EN); + writel(0x0f, edp->pll + QSERDES_V6_COM_CORE_CLK_EN); + writel(0xa0, edp->pll + QSERDES_V6_COM_VCO_TUNE1_MODE0); + writel(0x03, edp->pll + QSERDES_V6_COM_VCO_TUNE2_MODE0); + + writel(code1_mode0, edp->pll + QSERDES_V6_COM_BIN_VCOCAL_CMP_CODE1_MODE0); + writel(code2_mode0, edp->pll + QSERDES_V6_COM_BIN_VCOCAL_CMP_CODE2_MODE0); + + return 0; +} + +static const struct phy_ver_ops qcom_edp_phy_ops_v6 = { + .com_power_on = qcom_edp_phy_power_on_v6, + .com_resetsm_cntrl = qcom_edp_phy_com_resetsm_cntrl_v6, + .com_bias_en_clkbuflr = qcom_edp_com_bias_en_clkbuflr_v6, + .com_configure_pll = qcom_edp_com_configure_pll_v6, + .com_configure_ssc = qcom_edp_com_configure_ssc_v6, +}; + +static struct qcom_edp_phy_cfg x1e80100_phy_cfg = { + .swing_pre_emph_cfg = &dp_phy_swing_pre_emph_cfg, + .ver_ops = &qcom_edp_phy_ops_v6, +}; + static int qcom_edp_phy_power_on(struct phy *phy) { const struct qcom_edp *edp = phy_get_drvdata(phy); @@ -933,6 +1112,7 @@ static const struct of_device_id qcom_edp_phy_match_table[] = { { .compatible = "qcom,sc8180x-edp-phy", .data = &sc7280_dp_phy_cfg, }, { .compatible = "qcom,sc8280xp-dp-phy", .data = &sc8280xp_dp_phy_cfg, }, { .compatible = "qcom,sc8280xp-edp-phy", .data = &sc8280xp_edp_phy_cfg, }, + { .compatible = "qcom,x1e80100-dp-phy", .data = &x1e80100_phy_cfg, }, { } }; MODULE_DEVICE_TABLE(of, qcom_edp_phy_match_table); -- cgit v1.2.3-59-g8ed1b From e298ae7caafcc429e0fc4b3779f1738c0acc5dac Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Wed, 28 Feb 2024 18:05:13 +0100 Subject: phy: qcom: qmp-combo: fix duplicate return in qmp_v4_configure_dp_phy Remove duplicate "return 0" in qmp_v4_configure_dp_phy() Fixes: 186ad90aa49f ("phy: qcom: qmp-combo: reuse register layouts for even more registers") Signed-off-by: Neil Armstrong Reviewed-by: Konrad Dybcio Reviewed-by: Abhinav Kumar Link: https://lore.kernel.org/r/20240228-topic-sm8x50-upstream-phy-combo-fix-duplicate-return-v1-1-60027a37cab1@linaro.org Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-qmp-combo.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c index 7d585a4bbbba..ea2d5369534d 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c @@ -2431,8 +2431,6 @@ static int qmp_v4_configure_dp_phy(struct qmp_combo *qmp) writel(0x20, qmp->dp_tx2 + cfg->regs[QPHY_TX_TX_EMP_POST1_LVL]); return 0; - - return 0; } /* -- cgit v1.2.3-59-g8ed1b From bf32bceedd0453c70d9d022e2e29f98e446d7161 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 28 Mar 2024 13:28:56 -0700 Subject: Input: ims-pcu - fix printf string overflow clang warns about a string overflow in this driver drivers/input/misc/ims-pcu.c:1802:2: error: 'snprintf' will always be truncated; specified size is 10, but format string expands to at least 12 [-Werror,-Wformat-truncation] drivers/input/misc/ims-pcu.c:1814:2: error: 'snprintf' will always be truncated; specified size is 10, but format string expands to at least 12 [-Werror,-Wformat-truncation] Make the buffer a little longer to ensure it always fits. Fixes: 628329d52474 ("Input: add IMS Passenger Control Unit driver") Signed-off-by: Arnd Bergmann Link: https://lore.kernel.org/r/20240326223825.4084412-7-arnd@kernel.org Signed-off-by: Dmitry Torokhov --- drivers/input/misc/ims-pcu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/input/misc/ims-pcu.c b/drivers/input/misc/ims-pcu.c index 6e8cc28debd9..80d16c92a08b 100644 --- a/drivers/input/misc/ims-pcu.c +++ b/drivers/input/misc/ims-pcu.c @@ -42,8 +42,8 @@ struct ims_pcu_backlight { #define IMS_PCU_PART_NUMBER_LEN 15 #define IMS_PCU_SERIAL_NUMBER_LEN 8 #define IMS_PCU_DOM_LEN 8 -#define IMS_PCU_FW_VERSION_LEN (9 + 1) -#define IMS_PCU_BL_VERSION_LEN (9 + 1) +#define IMS_PCU_FW_VERSION_LEN 16 +#define IMS_PCU_BL_VERSION_LEN 16 #define IMS_PCU_BL_RESET_REASON_LEN (2 + 1) #define IMS_PCU_PCU_B_DEVICE_ID 5 -- cgit v1.2.3-59-g8ed1b From d40e9edcf3eb925c259df9f9dd7319a4fcbc675b Mon Sep 17 00:00:00 2001 From: Karel Balej Date: Fri, 15 Mar 2024 12:46:14 -0700 Subject: Input: ioc3kbd - add device table Without the device table the driver will not auto-load when compiled as a module. Fixes: 273db8f03509 ("Input: add IOC3 serio driver") Signed-off-by: Karel Balej Link: https://lore.kernel.org/r/20240313115832.8052-1-balejk@matfyz.cz Signed-off-by: Dmitry Torokhov --- drivers/input/serio/ioc3kbd.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/input/serio/ioc3kbd.c b/drivers/input/serio/ioc3kbd.c index 50552dc7b4f5..676b0bda3d72 100644 --- a/drivers/input/serio/ioc3kbd.c +++ b/drivers/input/serio/ioc3kbd.c @@ -200,9 +200,16 @@ static void ioc3kbd_remove(struct platform_device *pdev) serio_unregister_port(d->aux); } +static const struct platform_device_id ioc3kbd_id_table[] = { + { "ioc3-kbd", }, + { } +}; +MODULE_DEVICE_TABLE(platform, ioc3kbd_id_table); + static struct platform_driver ioc3kbd_driver = { .probe = ioc3kbd_probe, .remove_new = ioc3kbd_remove, + .id_table = ioc3kbd_id_table, .driver = { .name = "ioc3-kbd", }, -- cgit v1.2.3-59-g8ed1b From 8984e0b569236c8581901efce2f1f4d03cd3dec1 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 10 Jan 2024 23:13:01 -0800 Subject: Input: adafruit-seesaw - only report buttons that changed state If a button has not changed its state when we poll the device the driver does not need to report it. While duplicate events will be filtered out by the input core anyway we can do it very cheaply directly in the driver. Link: https://lore.kernel.org/r/ZZ-U_bmZpIdoYA6c@google.com Signed-off-by: Dmitry Torokhov --- drivers/input/joystick/adafruit-seesaw.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/drivers/input/joystick/adafruit-seesaw.c b/drivers/input/joystick/adafruit-seesaw.c index 1b9279f024cc..5c775ca886a5 100644 --- a/drivers/input/joystick/adafruit-seesaw.c +++ b/drivers/input/joystick/adafruit-seesaw.c @@ -56,7 +56,7 @@ #define SEESAW_GAMEPAD_POLL_MIN 8 #define SEESAW_GAMEPAD_POLL_MAX 32 -static const unsigned long SEESAW_BUTTON_MASK = +static const u32 SEESAW_BUTTON_MASK = BIT(SEESAW_BUTTON_A) | BIT(SEESAW_BUTTON_B) | BIT(SEESAW_BUTTON_X) | BIT(SEESAW_BUTTON_Y) | BIT(SEESAW_BUTTON_START) | BIT(SEESAW_BUTTON_SELECT); @@ -64,6 +64,7 @@ static const unsigned long SEESAW_BUTTON_MASK = struct seesaw_gamepad { struct input_dev *input_dev; struct i2c_client *i2c_client; + u32 button_state; }; struct seesaw_data { @@ -178,10 +179,20 @@ static int seesaw_read_data(struct i2c_client *client, struct seesaw_data *data) return 0; } +static int seesaw_open(struct input_dev *input) +{ + struct seesaw_gamepad *private = input_get_drvdata(input); + + private->button_state = 0; + + return 0; +} + static void seesaw_poll(struct input_dev *input) { struct seesaw_gamepad *private = input_get_drvdata(input); struct seesaw_data data; + unsigned long changed; int err, i; err = seesaw_read_data(private->i2c_client, &data); @@ -194,8 +205,11 @@ static void seesaw_poll(struct input_dev *input) input_report_abs(input, ABS_X, data.x); input_report_abs(input, ABS_Y, data.y); - for_each_set_bit(i, &SEESAW_BUTTON_MASK, - BITS_PER_TYPE(SEESAW_BUTTON_MASK)) { + data.button_state &= SEESAW_BUTTON_MASK; + changed = private->button_state ^ data.button_state; + private->button_state = data.button_state; + + for_each_set_bit(i, &changed, fls(SEESAW_BUTTON_MASK)) { if (!sparse_keymap_report_event(input, i, data.button_state & BIT(i), false)) @@ -253,6 +267,7 @@ static int seesaw_probe(struct i2c_client *client) seesaw->input_dev->id.bustype = BUS_I2C; seesaw->input_dev->name = "Adafruit Seesaw Gamepad"; seesaw->input_dev->phys = "i2c/" SEESAW_DEVICE_NAME; + seesaw->input_dev->open = seesaw_open; input_set_drvdata(seesaw->input_dev, seesaw); input_set_abs_params(seesaw->input_dev, ABS_X, 0, SEESAW_JOYSTICK_MAX_AXIS, -- cgit v1.2.3-59-g8ed1b From 61c86d14745ddda7fe9778862fa705da9c711429 Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Fri, 29 Mar 2024 15:56:15 +0800 Subject: rtc: cros-ec: provide ID table for avoiding fallback match Instead of using fallback driver name match, provide ID table[1] for the primary match. [1]: https://elixir.bootlin.com/linux/v6.8/source/drivers/base/platform.c#L1353 Signed-off-by: Tzung-Bi Shih Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240329075630.2069474-4-tzungbi@kernel.org Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-cros-ec.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/rtc/rtc-cros-ec.c b/drivers/rtc/rtc-cros-ec.c index 0cd397c04ff0..f57462c7b2c6 100644 --- a/drivers/rtc/rtc-cros-ec.c +++ b/drivers/rtc/rtc-cros-ec.c @@ -5,6 +5,7 @@ // Author: Stephen Barber #include +#include #include #include #include @@ -392,6 +393,12 @@ static void cros_ec_rtc_remove(struct platform_device *pdev) dev_err(dev, "failed to unregister notifier\n"); } +static const struct platform_device_id cros_ec_rtc_id[] = { + { DRV_NAME, 0 }, + {} +}; +MODULE_DEVICE_TABLE(platform, cros_ec_rtc_id); + static struct platform_driver cros_ec_rtc_driver = { .probe = cros_ec_rtc_probe, .remove_new = cros_ec_rtc_remove, @@ -399,6 +406,7 @@ static struct platform_driver cros_ec_rtc_driver = { .name = DRV_NAME, .pm = &cros_ec_rtc_pm_ops, }, + .id_table = cros_ec_rtc_id, }; module_platform_driver(cros_ec_rtc_driver); @@ -406,4 +414,3 @@ module_platform_driver(cros_ec_rtc_driver); MODULE_DESCRIPTION("RTC driver for Chrome OS ECs"); MODULE_AUTHOR("Stephen Barber "); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:" DRV_NAME); -- cgit v1.2.3-59-g8ed1b From c3c50e7df39b396766ad0c2f184837a5a9ef2150 Mon Sep 17 00:00:00 2001 From: Javier Carrasco Date: Tue, 26 Mar 2024 14:03:23 +0100 Subject: dt-bindings: rtc: armada-380-rtc: convert to dtschema Convert existing binding to dtschema to support validation. This is a direct conversion with no additions. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Javier Carrasco Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20240326-rtc-yaml-v3-1-caa430ecace7@gmail.com Signed-off-by: Alexandre Belloni --- .../devicetree/bindings/rtc/armada-380-rtc.txt | 24 ---------- .../bindings/rtc/marvell,armada-380-rtc.yaml | 51 ++++++++++++++++++++++ 2 files changed, 51 insertions(+), 24 deletions(-) delete mode 100644 Documentation/devicetree/bindings/rtc/armada-380-rtc.txt create mode 100644 Documentation/devicetree/bindings/rtc/marvell,armada-380-rtc.yaml diff --git a/Documentation/devicetree/bindings/rtc/armada-380-rtc.txt b/Documentation/devicetree/bindings/rtc/armada-380-rtc.txt deleted file mode 100644 index c3c9a1226f9a..000000000000 --- a/Documentation/devicetree/bindings/rtc/armada-380-rtc.txt +++ /dev/null @@ -1,24 +0,0 @@ -* Real Time Clock of the Armada 38x/7K/8K SoCs - -RTC controller for the Armada 38x, 7K and 8K SoCs - -Required properties: -- compatible : Should be one of the following: - "marvell,armada-380-rtc" for Armada 38x SoC - "marvell,armada-8k-rtc" for Aramda 7K/8K SoCs -- reg: a list of base address and size pairs, one for each entry in - reg-names -- reg names: should contain: - * "rtc" for the RTC registers - * "rtc-soc" for the SoC related registers and among them the one - related to the interrupt. -- interrupts: IRQ line for the RTC. - -Example: - -rtc@a3800 { - compatible = "marvell,armada-380-rtc"; - reg = <0xa3800 0x20>, <0x184a0 0x0c>; - reg-names = "rtc", "rtc-soc"; - interrupts = ; -}; diff --git a/Documentation/devicetree/bindings/rtc/marvell,armada-380-rtc.yaml b/Documentation/devicetree/bindings/rtc/marvell,armada-380-rtc.yaml new file mode 100644 index 000000000000..adf3ba0cd09f --- /dev/null +++ b/Documentation/devicetree/bindings/rtc/marvell,armada-380-rtc.yaml @@ -0,0 +1,51 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/rtc/marvell,armada-380-rtc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: RTC controller for the Armada 38x, 7K and 8K SoCs + +maintainers: + - Javier Carrasco + +allOf: + - $ref: rtc.yaml# + +properties: + compatible: + enum: + - marvell,armada-380-rtc + - marvell,armada-8k-rtc + + reg: + items: + - description: RTC base address size + - description: Base address and size of SoC related registers + + reg-names: + items: + - const: rtc + - const: rtc-soc + + interrupts: + maxItems: 1 + +required: + - compatible + - reg + - reg-names + - interrupts + +unevaluatedProperties: false + +examples: + - | + #include + + rtc@a3800 { + compatible = "marvell,armada-380-rtc"; + reg = <0xa3800 0x20>, <0x184a0 0x0c>; + reg-names = "rtc", "rtc-soc"; + interrupts = ; + }; -- cgit v1.2.3-59-g8ed1b From 432008d2f766f85122c80fe5275efe97932b4e49 Mon Sep 17 00:00:00 2001 From: Javier Carrasco Date: Tue, 26 Mar 2024 14:03:24 +0100 Subject: dt-bindings: rtc: alphascale,asm9260-rtc: convert to dtschema Convert existing binding to dtschema to support validation. This is a direct conversion with no additions. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Javier Carrasco Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20240326-rtc-yaml-v3-2-caa430ecace7@gmail.com Signed-off-by: Alexandre Belloni --- .../bindings/rtc/alphascale,asm9260-rtc.txt | 19 -------- .../bindings/rtc/alphascale,asm9260-rtc.yaml | 50 ++++++++++++++++++++++ 2 files changed, 50 insertions(+), 19 deletions(-) delete mode 100644 Documentation/devicetree/bindings/rtc/alphascale,asm9260-rtc.txt create mode 100644 Documentation/devicetree/bindings/rtc/alphascale,asm9260-rtc.yaml diff --git a/Documentation/devicetree/bindings/rtc/alphascale,asm9260-rtc.txt b/Documentation/devicetree/bindings/rtc/alphascale,asm9260-rtc.txt deleted file mode 100644 index 76ebca568db9..000000000000 --- a/Documentation/devicetree/bindings/rtc/alphascale,asm9260-rtc.txt +++ /dev/null @@ -1,19 +0,0 @@ -* Alphascale asm9260 SoC Real Time Clock - -Required properties: -- compatible: Should be "alphascale,asm9260-rtc" -- reg: Physical base address of the controller and length - of memory mapped region. -- interrupts: IRQ line for the RTC. -- clocks: Reference to the clock entry. -- clock-names: should contain: - * "ahb" for the SoC RTC clock - -Example: -rtc0: rtc@800a0000 { - compatible = "alphascale,asm9260-rtc"; - reg = <0x800a0000 0x100>; - clocks = <&acc CLKID_AHB_RTC>; - clock-names = "ahb"; - interrupts = <2>; -}; diff --git a/Documentation/devicetree/bindings/rtc/alphascale,asm9260-rtc.yaml b/Documentation/devicetree/bindings/rtc/alphascale,asm9260-rtc.yaml new file mode 100644 index 000000000000..f955a7f638ad --- /dev/null +++ b/Documentation/devicetree/bindings/rtc/alphascale,asm9260-rtc.yaml @@ -0,0 +1,50 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/rtc/alphascale,asm9260-rtc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Alphascale asm9260 SoC Real Time Clock + +maintainers: + - Javier Carrasco + +allOf: + - $ref: rtc.yaml# + +properties: + compatible: + const: alphascale,asm9260-rtc + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + + clock-names: + const: ahb + + interrupts: + maxItems: 1 + +required: + - compatible + - reg + - clocks + - clock-names + - interrupts + +unevaluatedProperties: false + +examples: + - | + #include + + rtc@800a0000 { + compatible = "alphascale,asm9260-rtc"; + reg = <0x800a0000 0x100>; + clocks = <&acc CLKID_AHB_RTC>; + clock-names = "ahb"; + interrupts = <2>; + }; -- cgit v1.2.3-59-g8ed1b From 971e7303f472ca6d37c6639efcf08dea14a2e5f8 Mon Sep 17 00:00:00 2001 From: Javier Carrasco Date: Tue, 26 Mar 2024 14:03:25 +0100 Subject: dt-bindings: rtc: digicolor-rtc: move to trivial-rtc Convert existing binding to dtschema to support validation. This device meets the requirements to be moved to trivial-rtc (compatible, reg and a single interrupt). Reviewed-by: Krzysztof Kozlowski Signed-off-by: Javier Carrasco Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20240326-rtc-yaml-v3-3-caa430ecace7@gmail.com Signed-off-by: Alexandre Belloni --- Documentation/devicetree/bindings/rtc/digicolor-rtc.txt | 17 ----------------- Documentation/devicetree/bindings/rtc/trivial-rtc.yaml | 2 ++ 2 files changed, 2 insertions(+), 17 deletions(-) delete mode 100644 Documentation/devicetree/bindings/rtc/digicolor-rtc.txt diff --git a/Documentation/devicetree/bindings/rtc/digicolor-rtc.txt b/Documentation/devicetree/bindings/rtc/digicolor-rtc.txt deleted file mode 100644 index d464986012cd..000000000000 --- a/Documentation/devicetree/bindings/rtc/digicolor-rtc.txt +++ /dev/null @@ -1,17 +0,0 @@ -Conexant Digicolor Real Time Clock controller - -This binding currently supports the CX92755 SoC. - -Required properties: -- compatible: should be "cnxt,cx92755-rtc" -- reg: physical base address of the controller and length of memory mapped - region. -- interrupts: rtc alarm interrupt - -Example: - - rtc@f0000c30 { - compatible = "cnxt,cx92755-rtc"; - reg = <0xf0000c30 0x18>; - interrupts = <25>; - }; diff --git a/Documentation/devicetree/bindings/rtc/trivial-rtc.yaml b/Documentation/devicetree/bindings/rtc/trivial-rtc.yaml index c9e3c5262c21..a3db41c5207c 100644 --- a/Documentation/devicetree/bindings/rtc/trivial-rtc.yaml +++ b/Documentation/devicetree/bindings/rtc/trivial-rtc.yaml @@ -24,6 +24,8 @@ properties: - abracon,abb5zes3 # AB-RTCMC-32.768kHz-EOZ9: Real Time Clock/Calendar Module with I2C Interface - abracon,abeoz9 + # Conexant Digicolor Real Time Clock Controller + - cnxt,cx92755-rtc # I2C, 32-Bit Binary Counter Watchdog RTC with Trickle Charger and Reset Input/Output - dallas,ds1374 # Dallas DS1672 Real-time Clock -- cgit v1.2.3-59-g8ed1b From 7918a220d210df91d981bd6d19fb8c26827f22ea Mon Sep 17 00:00:00 2001 From: Javier Carrasco Date: Tue, 26 Mar 2024 14:03:26 +0100 Subject: dt-bindings: rtc: nxp,lpc1788-rtc: convert to dtschema Convert existing binding to dtschema to support validation. This is a direct conversion with no additions. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Javier Carrasco Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20240326-rtc-yaml-v3-4-caa430ecace7@gmail.com Signed-off-by: Alexandre Belloni --- .../devicetree/bindings/rtc/nxp,lpc1788-rtc.txt | 21 -------- .../devicetree/bindings/rtc/nxp,lpc1788-rtc.yaml | 58 ++++++++++++++++++++++ 2 files changed, 58 insertions(+), 21 deletions(-) delete mode 100644 Documentation/devicetree/bindings/rtc/nxp,lpc1788-rtc.txt create mode 100644 Documentation/devicetree/bindings/rtc/nxp,lpc1788-rtc.yaml diff --git a/Documentation/devicetree/bindings/rtc/nxp,lpc1788-rtc.txt b/Documentation/devicetree/bindings/rtc/nxp,lpc1788-rtc.txt deleted file mode 100644 index 3c97bd180592..000000000000 --- a/Documentation/devicetree/bindings/rtc/nxp,lpc1788-rtc.txt +++ /dev/null @@ -1,21 +0,0 @@ -NXP LPC1788 real-time clock - -The LPC1788 RTC provides calendar and clock functionality -together with periodic tick and alarm interrupt support. - -Required properties: -- compatible : must contain "nxp,lpc1788-rtc" -- reg : Specifies base physical address and size of the registers. -- interrupts : A single interrupt specifier. -- clocks : Must contain clock specifiers for rtc and register clock -- clock-names : Must contain "rtc" and "reg" - See ../clocks/clock-bindings.txt for details. - -Example: -rtc: rtc@40046000 { - compatible = "nxp,lpc1788-rtc"; - reg = <0x40046000 0x1000>; - interrupts = <47>; - clocks = <&creg_clk 0>, <&ccu1 CLK_CPU_BUS>; - clock-names = "rtc", "reg"; -}; diff --git a/Documentation/devicetree/bindings/rtc/nxp,lpc1788-rtc.yaml b/Documentation/devicetree/bindings/rtc/nxp,lpc1788-rtc.yaml new file mode 100644 index 000000000000..e88b847a1cc5 --- /dev/null +++ b/Documentation/devicetree/bindings/rtc/nxp,lpc1788-rtc.yaml @@ -0,0 +1,58 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/rtc/nxp,lpc1788-rtc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NXP LPC1788 real-time clock + +description: + The LPC1788 RTC provides calendar and clock functionality + together with periodic tick and alarm interrupt support. + +maintainers: + - Javier Carrasco + +allOf: + - $ref: rtc.yaml# + +properties: + compatible: + const: nxp,lpc1788-rtc + + reg: + maxItems: 1 + + clocks: + items: + - description: RTC clock + - description: Register clock + + clock-names: + items: + - const: rtc + - const: reg + + interrupts: + maxItems: 1 + +required: + - compatible + - reg + - clocks + - clock-names + - interrupts + +unevaluatedProperties: false + +examples: + - | + #include + + rtc@40046000 { + compatible = "nxp,lpc1788-rtc"; + reg = <0x40046000 0x1000>; + clocks = <&creg_clk 0>, <&ccu1 CLK_CPU_BUS>; + clock-names = "rtc", "reg"; + interrupts = <47>; + }; -- cgit v1.2.3-59-g8ed1b From 95c46336ab4785701a506e94fbd6256c7859be7b Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Wed, 13 Mar 2024 10:42:21 -0700 Subject: rtc: test: Split rtc unit test into slow and normal speed test On slow systems, the rtc unit test may result in soft lockups and/or generate messages such as # rtc_time64_to_tm_test_date_range: Test should be marked slow (runtime: 34.253230015s) # rtc_time64_to_tm_test_date_range: pass:1 fail:0 skip:0 total:1 The test covers a date range of 160,000 years, resulting in the long runtime. Unit tests running for more than 1 second are supposed to be marked as slow. Just marking the test as slow would prevent it from running when slow tests are disabled, which would not be desirable. At the same time, the current test range of 160,000 years seems to be of limited value. Split the test into two parts, one covering a range of 1,000 years and the other covering the current range of 160,000 years. Mark the 160,000 year test as slow to be able to separate it from the faster test. Signed-off-by: Guenter Roeck Link: https://lore.kernel.org/r/20240313174221.1999654-1-linux@roeck-us.net Signed-off-by: Alexandre Belloni --- drivers/rtc/lib_test.c | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/drivers/rtc/lib_test.c b/drivers/rtc/lib_test.c index 225c859d6da5..3893a202e9ea 100644 --- a/drivers/rtc/lib_test.c +++ b/drivers/rtc/lib_test.c @@ -27,17 +27,17 @@ static void advance_date(int *year, int *month, int *mday, int *yday) } /* - * Checks every day in a 160000 years interval starting on 1970-01-01 + * Check every day in specified number of years interval starting on 1970-01-01 * against the expected result. */ -static void rtc_time64_to_tm_test_date_range(struct kunit *test) +static void rtc_time64_to_tm_test_date_range(struct kunit *test, int years) { /* - * 160000 years = (160000 / 400) * 400 years - * = (160000 / 400) * 146097 days - * = (160000 / 400) * 146097 * 86400 seconds + * years = (years / 400) * 400 years + * = (years / 400) * 146097 days + * = (years / 400) * 146097 * 86400 seconds */ - time64_t total_secs = ((time64_t) 160000) / 400 * 146097 * 86400; + time64_t total_secs = ((time64_t)years) / 400 * 146097 * 86400; int year = 1970; int month = 1; @@ -66,8 +66,27 @@ static void rtc_time64_to_tm_test_date_range(struct kunit *test) } } +/* + * Checks every day in a 160000 years interval starting on 1970-01-01 + * against the expected result. + */ +static void rtc_time64_to_tm_test_date_range_160000(struct kunit *test) +{ + rtc_time64_to_tm_test_date_range(test, 160000); +} + +/* + * Checks every day in a 1000 years interval starting on 1970-01-01 + * against the expected result. + */ +static void rtc_time64_to_tm_test_date_range_1000(struct kunit *test) +{ + rtc_time64_to_tm_test_date_range(test, 1000); +} + static struct kunit_case rtc_lib_test_cases[] = { - KUNIT_CASE(rtc_time64_to_tm_test_date_range), + KUNIT_CASE(rtc_time64_to_tm_test_date_range_1000), + KUNIT_CASE_SLOW(rtc_time64_to_tm_test_date_range_160000), {} }; -- cgit v1.2.3-59-g8ed1b From 8b59a11fb8e60540ee00ea054afd8dbe9dd3ba00 Mon Sep 17 00:00:00 2001 From: Mia Lin Date: Mon, 11 Mar 2024 09:34:05 +0800 Subject: rtc: nuvoton: Modify part number value Base on datasheet, the part number is corresponding to bit 0 and 1 of the part info reg. Signed-off-by: Mia Lin Link: https://lore.kernel.org/r/20240311013405.3398823-2-mimi05633@gmail.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-nct3018y.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/rtc/rtc-nct3018y.c b/drivers/rtc/rtc-nct3018y.c index 076d8b99f913..7a8b4de893b8 100644 --- a/drivers/rtc/rtc-nct3018y.c +++ b/drivers/rtc/rtc-nct3018y.c @@ -517,12 +517,15 @@ static int nct3018y_probe(struct i2c_client *client) if (nct3018y->part_num < 0) { dev_dbg(&client->dev, "Failed to read NCT3018Y_REG_PART.\n"); return nct3018y->part_num; - } else if (nct3018y->part_num == NCT3018Y_REG_PART_NCT3018Y) { - flags = NCT3018Y_BIT_HF; - err = i2c_smbus_write_byte_data(client, NCT3018Y_REG_CTRL, flags); - if (err < 0) { - dev_dbg(&client->dev, "Unable to write NCT3018Y_REG_CTRL.\n"); - return err; + } else { + nct3018y->part_num &= 0x03; /* Part number is corresponding to bit 0 and 1 */ + if (nct3018y->part_num == NCT3018Y_REG_PART_NCT3018Y) { + flags = NCT3018Y_BIT_HF; + err = i2c_smbus_write_byte_data(client, NCT3018Y_REG_CTRL, flags); + if (err < 0) { + dev_dbg(&client->dev, "Unable to write NCT3018Y_REG_CTRL.\n"); + return err; + } } } -- cgit v1.2.3-59-g8ed1b From 5787731c7467faeb1bcbe5a64e1a86fb7987bbaa Mon Sep 17 00:00:00 2001 From: Danila Tikhonov Date: Wed, 27 Mar 2024 21:06:41 +0300 Subject: dt-bindings: phy: Add QMP UFS PHY comptible for SM8475 Document the QMP UFS PHY compatible for SM8475. Signed-off-by: Danila Tikhonov Acked-by: Krzysztof Kozlowski Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240327180642.20146-2-danila@jiaxyga.com Signed-off-by: Vinod Koul --- Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml index 91a6cc38ff7f..1e8c3abb09a4 100644 --- a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml @@ -32,6 +32,7 @@ properties: - qcom,sm8250-qmp-ufs-phy - qcom,sm8350-qmp-ufs-phy - qcom,sm8450-qmp-ufs-phy + - qcom,sm8475-qmp-ufs-phy - qcom,sm8550-qmp-ufs-phy - qcom,sm8650-qmp-ufs-phy @@ -98,6 +99,7 @@ allOf: - qcom,sm8250-qmp-ufs-phy - qcom,sm8350-qmp-ufs-phy - qcom,sm8450-qmp-ufs-phy + - qcom,sm8475-qmp-ufs-phy - qcom,sm8550-qmp-ufs-phy - qcom,sm8650-qmp-ufs-phy then: -- cgit v1.2.3-59-g8ed1b From ef2bd6c969830c7e42c23bcaf9d533db77420512 Mon Sep 17 00:00:00 2001 From: Danila Tikhonov Date: Wed, 27 Mar 2024 21:06:42 +0300 Subject: phy: qcom-qmp-ufs: Add SM8475 support Add the tables and constants for init sequences for UFS QMP phy found in SM8475 SoC. Signed-off-by: Danila Tikhonov Link: https://lore.kernel.org/r/20240327180642.20146-3-danila@jiaxyga.com Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-qmp-ufs.c | 71 +++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c index 590432d581f9..ddc0def0ae61 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c @@ -722,6 +722,38 @@ static const struct qmp_phy_init_tbl sm8350_ufsphy_g4_pcs[] = { QMP_PHY_INIT_CFG(QPHY_V5_PCS_UFS_BIST_FIXED_PAT_CTRL, 0x0a), }; +static const struct qmp_phy_init_tbl sm8475_ufsphy_serdes[] = { + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SYSCLK_EN_SEL, 0xd9), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CMN_CONFIG_1, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_HSCLK_SEL_1, 0x11), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_HSCLK_HS_SWITCH_SEL_1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP_EN, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_INITVAL2, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE0, 0x82), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_RCTRL_MODE0, 0x18), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_CCTRL_MODE0, 0x18), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP1_MODE0, 0xff), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP2_MODE0, 0x0c), +}; + +static const struct qmp_phy_init_tbl sm8475_ufsphy_g4_serdes[] = { + QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_MAP, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_IVCO, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE0, 0x14), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE1, 0x98), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE1, 0x14), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_RCTRL_MODE1, 0x18), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_CCTRL_MODE1, 0x18), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP1_MODE1, 0x32), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP2_MODE1, 0x0f), +}; + +static const struct qmp_phy_init_tbl sm8475_ufsphy_g4_pcs[] = { + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_PLL_CNTL, 0x0b), + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_HSGEAR_CAPABILITY, 0x04), + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_HSGEAR_CAPABILITY, 0x04), +}; + static const struct qmp_phy_init_tbl sm8550_ufsphy_serdes[] = { QMP_PHY_INIT_CFG(QSERDES_V6_COM_SYSCLK_EN_SEL, 0xd9), QMP_PHY_INIT_CFG(QSERDES_V6_COM_CMN_CONFIG_1, 0x16), @@ -1346,6 +1378,42 @@ static const struct qmp_phy_cfg sm8450_ufsphy_cfg = { .regs = ufsphy_v5_regs_layout, }; +static const struct qmp_phy_cfg sm8475_ufsphy_cfg = { + .lanes = 2, + + .offsets = &qmp_ufs_offsets_v6, + .max_supported_gear = UFS_HS_G4, + + .tbls = { + .serdes = sm8475_ufsphy_serdes, + .serdes_num = ARRAY_SIZE(sm8475_ufsphy_serdes), + .tx = sm8550_ufsphy_tx, + .tx_num = ARRAY_SIZE(sm8550_ufsphy_tx), + .rx = sm8550_ufsphy_rx, + .rx_num = ARRAY_SIZE(sm8550_ufsphy_rx), + .pcs = sm8550_ufsphy_pcs, + .pcs_num = ARRAY_SIZE(sm8550_ufsphy_pcs), + }, + .tbls_hs_b = { + .serdes = sm8550_ufsphy_hs_b_serdes, + .serdes_num = ARRAY_SIZE(sm8550_ufsphy_hs_b_serdes), + }, + .tbls_hs_overlay[0] = { + .serdes = sm8475_ufsphy_g4_serdes, + .serdes_num = ARRAY_SIZE(sm8475_ufsphy_g4_serdes), + .tx = sm8550_ufsphy_g4_tx, + .tx_num = ARRAY_SIZE(sm8550_ufsphy_g4_tx), + .rx = sm8550_ufsphy_g4_rx, + .rx_num = ARRAY_SIZE(sm8550_ufsphy_g4_rx), + .pcs = sm8475_ufsphy_g4_pcs, + .pcs_num = ARRAY_SIZE(sm8475_ufsphy_g4_pcs), + .max_gear = UFS_HS_G4, + }, + .vreg_list = qmp_phy_vreg_l, + .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + .regs = ufsphy_v6_regs_layout, +}; + static const struct qmp_phy_cfg sm8550_ufsphy_cfg = { .lanes = 2, @@ -1941,6 +2009,9 @@ static const struct of_device_id qmp_ufs_of_match_table[] = { }, { .compatible = "qcom,sm8450-qmp-ufs-phy", .data = &sm8450_ufsphy_cfg, + }, { + .compatible = "qcom,sm8475-qmp-ufs-phy", + .data = &sm8475_ufsphy_cfg, }, { .compatible = "qcom,sm8550-qmp-ufs-phy", .data = &sm8550_ufsphy_cfg, -- cgit v1.2.3-59-g8ed1b From 6020ca4de8e5404b20f15a6d9873cd6eb5f6d8d6 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 28 Mar 2024 16:16:59 -0500 Subject: iio: adc: ad7944: use spi_optimize_message() This modifies the ad7944 driver to use spi_optimize_message() to reduce CPU usage and increase the max sample rate by avoiding repeating validation of the spi message on each transfer. Signed-off-by: David Lechner Link: https://lore.kernel.org/r/20240328-ad7944-spi-optimize-message-v2-1-a142b2576379@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7944.c | 177 +++++++++++++++++++++++++++-------------------- 1 file changed, 103 insertions(+), 74 deletions(-) diff --git a/drivers/iio/adc/ad7944.c b/drivers/iio/adc/ad7944.c index 9aa3e98cd75c..9dc86ec23c36 100644 --- a/drivers/iio/adc/ad7944.c +++ b/drivers/iio/adc/ad7944.c @@ -51,6 +51,8 @@ static const char * const ad7944_spi_modes[] = { struct ad7944_adc { struct spi_device *spi; enum ad7944_spi_mode spi_mode; + struct spi_transfer xfers[3]; + struct spi_message msg; /* Chip-specific timing specifications. */ const struct ad7944_timing_spec *timing_spec; /* GPIO connected to CNV pin. */ @@ -130,6 +132,88 @@ AD7944_DEFINE_CHIP_INFO(ad7985, ad7944, 16, 0); /* fully differential */ AD7944_DEFINE_CHIP_INFO(ad7986, ad7986, 18, 1); +static void ad7944_unoptimize_msg(void *msg) +{ + spi_unoptimize_message(msg); +} + +static int ad7944_3wire_cs_mode_init_msg(struct device *dev, struct ad7944_adc *adc, + const struct iio_chan_spec *chan) +{ + unsigned int t_conv_ns = adc->always_turbo ? adc->timing_spec->turbo_conv_ns + : adc->timing_spec->conv_ns; + struct spi_transfer *xfers = adc->xfers; + int ret; + + /* + * NB: can get better performance from some SPI controllers if we use + * the same bits_per_word in every transfer. + */ + xfers[0].bits_per_word = chan->scan_type.realbits; + /* + * CS is tied to CNV and we need a low to high transition to start the + * conversion, so place CNV low for t_QUIET to prepare for this. + */ + xfers[0].delay.value = T_QUIET_NS; + xfers[0].delay.unit = SPI_DELAY_UNIT_NSECS; + + /* + * CS has to be high for full conversion time to avoid triggering the + * busy indication. + */ + xfers[1].cs_off = 1; + xfers[1].delay.value = t_conv_ns; + xfers[1].delay.unit = SPI_DELAY_UNIT_NSECS; + xfers[1].bits_per_word = chan->scan_type.realbits; + + /* Then we can read the data during the acquisition phase */ + xfers[2].rx_buf = &adc->sample.raw; + xfers[2].len = BITS_TO_BYTES(chan->scan_type.storagebits); + xfers[2].bits_per_word = chan->scan_type.realbits; + + spi_message_init_with_transfers(&adc->msg, xfers, 3); + + ret = spi_optimize_message(adc->spi, &adc->msg); + if (ret) + return ret; + + return devm_add_action_or_reset(dev, ad7944_unoptimize_msg, &adc->msg); +} + +static int ad7944_4wire_mode_init_msg(struct device *dev, struct ad7944_adc *adc, + const struct iio_chan_spec *chan) +{ + unsigned int t_conv_ns = adc->always_turbo ? adc->timing_spec->turbo_conv_ns + : adc->timing_spec->conv_ns; + struct spi_transfer *xfers = adc->xfers; + int ret; + + /* + * NB: can get better performance from some SPI controllers if we use + * the same bits_per_word in every transfer. + */ + xfers[0].bits_per_word = chan->scan_type.realbits; + /* + * CS has to be high for full conversion time to avoid triggering the + * busy indication. + */ + xfers[0].cs_off = 1; + xfers[0].delay.value = t_conv_ns; + xfers[0].delay.unit = SPI_DELAY_UNIT_NSECS; + + xfers[1].rx_buf = &adc->sample.raw; + xfers[1].len = BITS_TO_BYTES(chan->scan_type.storagebits); + xfers[1].bits_per_word = chan->scan_type.realbits; + + spi_message_init_with_transfers(&adc->msg, xfers, 2); + + ret = spi_optimize_message(adc->spi, &adc->msg); + if (ret) + return ret; + + return devm_add_action_or_reset(dev, ad7944_unoptimize_msg, &adc->msg); +} + /* * ad7944_3wire_cs_mode_conversion - Perform a 3-wire CS mode conversion and * acquisition @@ -145,48 +229,7 @@ AD7944_DEFINE_CHIP_INFO(ad7986, ad7986, 18, 1); static int ad7944_3wire_cs_mode_conversion(struct ad7944_adc *adc, const struct iio_chan_spec *chan) { - unsigned int t_conv_ns = adc->always_turbo ? adc->timing_spec->turbo_conv_ns - : adc->timing_spec->conv_ns; - struct spi_transfer xfers[] = { - { - /* - * NB: can get better performance from some SPI - * controllers if we use the same bits_per_word - * in every transfer. - */ - .bits_per_word = chan->scan_type.realbits, - /* - * CS is tied to CNV and we need a low to high - * transition to start the conversion, so place CNV - * low for t_QUIET to prepare for this. - */ - .delay = { - .value = T_QUIET_NS, - .unit = SPI_DELAY_UNIT_NSECS, - }, - - }, - { - .bits_per_word = chan->scan_type.realbits, - /* - * CS has to be high for full conversion time to avoid - * triggering the busy indication. - */ - .cs_off = 1, - .delay = { - .value = t_conv_ns, - .unit = SPI_DELAY_UNIT_NSECS, - }, - }, - { - /* Then we can read the data during the acquisition phase */ - .rx_buf = &adc->sample.raw, - .len = BITS_TO_BYTES(chan->scan_type.storagebits), - .bits_per_word = chan->scan_type.realbits, - }, - }; - - return spi_sync_transfer(adc->spi, xfers, ARRAY_SIZE(xfers)); + return spi_sync(adc->spi, &adc->msg); } /* @@ -200,33 +243,6 @@ static int ad7944_3wire_cs_mode_conversion(struct ad7944_adc *adc, static int ad7944_4wire_mode_conversion(struct ad7944_adc *adc, const struct iio_chan_spec *chan) { - unsigned int t_conv_ns = adc->always_turbo ? adc->timing_spec->turbo_conv_ns - : adc->timing_spec->conv_ns; - struct spi_transfer xfers[] = { - { - /* - * NB: can get better performance from some SPI - * controllers if we use the same bits_per_word - * in every transfer. - */ - .bits_per_word = chan->scan_type.realbits, - /* - * CS has to be high for full conversion time to avoid - * triggering the busy indication. - */ - .cs_off = 1, - .delay = { - .value = t_conv_ns, - .unit = SPI_DELAY_UNIT_NSECS, - }, - - }, - { - .rx_buf = &adc->sample.raw, - .len = BITS_TO_BYTES(chan->scan_type.storagebits), - .bits_per_word = chan->scan_type.realbits, - }, - }; int ret; /* @@ -234,7 +250,7 @@ static int ad7944_4wire_mode_conversion(struct ad7944_adc *adc, * and acquisition process. */ gpiod_set_value_cansleep(adc->cnv, 1); - ret = spi_sync_transfer(adc->spi, xfers, ARRAY_SIZE(xfers)); + ret = spi_sync(adc->spi, &adc->msg); gpiod_set_value_cansleep(adc->cnv, 0); return ret; @@ -393,10 +409,6 @@ static int ad7944_probe(struct spi_device *spi) else adc->spi_mode = ret; - if (adc->spi_mode == AD7944_SPI_MODE_CHAIN) - return dev_err_probe(dev, -EINVAL, - "chain mode is not implemented\n"); - /* * Some chips use unusual word sizes, so check now instead of waiting * for the first xfer. @@ -489,6 +501,23 @@ static int ad7944_probe(struct spi_device *spi) return dev_err_probe(dev, -EINVAL, "cannot have both chain mode and always turbo\n"); + switch (adc->spi_mode) { + case AD7944_SPI_MODE_DEFAULT: + ret = ad7944_4wire_mode_init_msg(dev, adc, &chip_info->channels[0]); + if (ret) + return ret; + + break; + case AD7944_SPI_MODE_SINGLE: + ret = ad7944_3wire_cs_mode_init_msg(dev, adc, &chip_info->channels[0]); + if (ret) + return ret; + + break; + case AD7944_SPI_MODE_CHAIN: + return dev_err_probe(dev, -EINVAL, "chain mode is not implemented\n"); + } + indio_dev->name = chip_info->name; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &ad7944_iio_info; -- cgit v1.2.3-59-g8ed1b From 4d4d2d4346857bf778fafaa97d6f76bb1663e3c9 Mon Sep 17 00:00:00 2001 From: Marco Pagani Date: Tue, 5 Mar 2024 20:29:26 +0100 Subject: fpga: manager: add owner module and take its refcount The current implementation of the fpga manager assumes that the low-level module registers a driver for the parent device and uses its owner pointer to take the module's refcount. This approach is problematic since it can lead to a null pointer dereference while attempting to get the manager if the parent device does not have a driver. To address this problem, add a module owner pointer to the fpga_manager struct and use it to take the module's refcount. Modify the functions for registering the manager to take an additional owner module parameter and rename them to avoid conflicts. Use the old function names for helper macros that automatically set the module that registers the manager as the owner. This ensures compatibility with existing low-level control modules and reduces the chances of registering a manager without setting the owner. Also, update the documentation to keep it consistent with the new interface for registering an fpga manager. Other changes: opportunistically move put_device() from __fpga_mgr_get() to fpga_mgr_get() and of_fpga_mgr_get() to improve code clarity since the manager device is taken in these functions. Fixes: 654ba4cc0f3e ("fpga manager: ensure lifetime with of_fpga_mgr_get") Suggested-by: Greg Kroah-Hartman Suggested-by: Xu Yilun Signed-off-by: Marco Pagani Acked-by: Xu Yilun Link: https://lore.kernel.org/r/20240305192926.84886-1-marpagan@redhat.com Signed-off-by: Xu Yilun --- Documentation/driver-api/fpga/fpga-mgr.rst | 34 ++++++++----- drivers/fpga/fpga-mgr.c | 82 ++++++++++++++++++------------ include/linux/fpga/fpga-mgr.h | 26 +++++++--- 3 files changed, 89 insertions(+), 53 deletions(-) diff --git a/Documentation/driver-api/fpga/fpga-mgr.rst b/Documentation/driver-api/fpga/fpga-mgr.rst index 49c0a9512653..8d2b79f696c1 100644 --- a/Documentation/driver-api/fpga/fpga-mgr.rst +++ b/Documentation/driver-api/fpga/fpga-mgr.rst @@ -24,7 +24,8 @@ How to support a new FPGA device -------------------------------- To add another FPGA manager, write a driver that implements a set of ops. The -probe function calls fpga_mgr_register() or fpga_mgr_register_full(), such as:: +probe function calls ``fpga_mgr_register()`` or ``fpga_mgr_register_full()``, +such as:: static const struct fpga_manager_ops socfpga_fpga_ops = { .write_init = socfpga_fpga_ops_configure_init, @@ -69,10 +70,11 @@ probe function calls fpga_mgr_register() or fpga_mgr_register_full(), such as:: } Alternatively, the probe function could call one of the resource managed -register functions, devm_fpga_mgr_register() or devm_fpga_mgr_register_full(). -When these functions are used, the parameter syntax is the same, but the call -to fpga_mgr_unregister() should be removed. In the above example, the -socfpga_fpga_remove() function would not be required. +register functions, ``devm_fpga_mgr_register()`` or +``devm_fpga_mgr_register_full()``. When these functions are used, the +parameter syntax is the same, but the call to ``fpga_mgr_unregister()`` should be +removed. In the above example, the ``socfpga_fpga_remove()`` function would not be +required. The ops will implement whatever device specific register writes are needed to do the programming sequence for this particular FPGA. These ops return 0 for @@ -125,15 +127,19 @@ API for implementing a new FPGA Manager driver * struct fpga_manager - the FPGA manager struct * struct fpga_manager_ops - Low level FPGA manager driver ops * struct fpga_manager_info - Parameter structure for fpga_mgr_register_full() -* fpga_mgr_register_full() - Create and register an FPGA manager using the +* __fpga_mgr_register_full() - Create and register an FPGA manager using the fpga_mgr_info structure to provide the full flexibility of options -* fpga_mgr_register() - Create and register an FPGA manager using standard +* __fpga_mgr_register() - Create and register an FPGA manager using standard arguments -* devm_fpga_mgr_register_full() - Resource managed version of - fpga_mgr_register_full() -* devm_fpga_mgr_register() - Resource managed version of fpga_mgr_register() +* __devm_fpga_mgr_register_full() - Resource managed version of + __fpga_mgr_register_full() +* __devm_fpga_mgr_register() - Resource managed version of __fpga_mgr_register() * fpga_mgr_unregister() - Unregister an FPGA manager +Helper macros ``fpga_mgr_register_full()``, ``fpga_mgr_register()``, +``devm_fpga_mgr_register_full()``, and ``devm_fpga_mgr_register()`` are available +to ease the registration. + .. kernel-doc:: include/linux/fpga/fpga-mgr.h :functions: fpga_mgr_states @@ -147,16 +153,16 @@ API for implementing a new FPGA Manager driver :functions: fpga_manager_info .. kernel-doc:: drivers/fpga/fpga-mgr.c - :functions: fpga_mgr_register_full + :functions: __fpga_mgr_register_full .. kernel-doc:: drivers/fpga/fpga-mgr.c - :functions: fpga_mgr_register + :functions: __fpga_mgr_register .. kernel-doc:: drivers/fpga/fpga-mgr.c - :functions: devm_fpga_mgr_register_full + :functions: __devm_fpga_mgr_register_full .. kernel-doc:: drivers/fpga/fpga-mgr.c - :functions: devm_fpga_mgr_register + :functions: __devm_fpga_mgr_register .. kernel-doc:: drivers/fpga/fpga-mgr.c :functions: fpga_mgr_unregister diff --git a/drivers/fpga/fpga-mgr.c b/drivers/fpga/fpga-mgr.c index 06651389c592..0f4035b089a2 100644 --- a/drivers/fpga/fpga-mgr.c +++ b/drivers/fpga/fpga-mgr.c @@ -664,20 +664,16 @@ static struct attribute *fpga_mgr_attrs[] = { }; ATTRIBUTE_GROUPS(fpga_mgr); -static struct fpga_manager *__fpga_mgr_get(struct device *dev) +static struct fpga_manager *__fpga_mgr_get(struct device *mgr_dev) { struct fpga_manager *mgr; - mgr = to_fpga_manager(dev); + mgr = to_fpga_manager(mgr_dev); - if (!try_module_get(dev->parent->driver->owner)) - goto err_dev; + if (!try_module_get(mgr->mops_owner)) + mgr = ERR_PTR(-ENODEV); return mgr; - -err_dev: - put_device(dev); - return ERR_PTR(-ENODEV); } static int fpga_mgr_dev_match(struct device *dev, const void *data) @@ -693,12 +689,18 @@ static int fpga_mgr_dev_match(struct device *dev, const void *data) */ struct fpga_manager *fpga_mgr_get(struct device *dev) { - struct device *mgr_dev = class_find_device(&fpga_mgr_class, NULL, dev, - fpga_mgr_dev_match); + struct fpga_manager *mgr; + struct device *mgr_dev; + + mgr_dev = class_find_device(&fpga_mgr_class, NULL, dev, fpga_mgr_dev_match); if (!mgr_dev) return ERR_PTR(-ENODEV); - return __fpga_mgr_get(mgr_dev); + mgr = __fpga_mgr_get(mgr_dev); + if (IS_ERR(mgr)) + put_device(mgr_dev); + + return mgr; } EXPORT_SYMBOL_GPL(fpga_mgr_get); @@ -711,13 +713,18 @@ EXPORT_SYMBOL_GPL(fpga_mgr_get); */ struct fpga_manager *of_fpga_mgr_get(struct device_node *node) { - struct device *dev; + struct fpga_manager *mgr; + struct device *mgr_dev; - dev = class_find_device_by_of_node(&fpga_mgr_class, node); - if (!dev) + mgr_dev = class_find_device_by_of_node(&fpga_mgr_class, node); + if (!mgr_dev) return ERR_PTR(-ENODEV); - return __fpga_mgr_get(dev); + mgr = __fpga_mgr_get(mgr_dev); + if (IS_ERR(mgr)) + put_device(mgr_dev); + + return mgr; } EXPORT_SYMBOL_GPL(of_fpga_mgr_get); @@ -727,7 +734,7 @@ EXPORT_SYMBOL_GPL(of_fpga_mgr_get); */ void fpga_mgr_put(struct fpga_manager *mgr) { - module_put(mgr->dev.parent->driver->owner); + module_put(mgr->mops_owner); put_device(&mgr->dev); } EXPORT_SYMBOL_GPL(fpga_mgr_put); @@ -766,9 +773,10 @@ void fpga_mgr_unlock(struct fpga_manager *mgr) EXPORT_SYMBOL_GPL(fpga_mgr_unlock); /** - * fpga_mgr_register_full - create and register an FPGA Manager device + * __fpga_mgr_register_full - create and register an FPGA Manager device * @parent: fpga manager device from pdev * @info: parameters for fpga manager + * @owner: owner module containing the ops * * The caller of this function is responsible for calling fpga_mgr_unregister(). * Using devm_fpga_mgr_register_full() instead is recommended. @@ -776,7 +784,8 @@ EXPORT_SYMBOL_GPL(fpga_mgr_unlock); * Return: pointer to struct fpga_manager pointer or ERR_PTR() */ struct fpga_manager * -fpga_mgr_register_full(struct device *parent, const struct fpga_manager_info *info) +__fpga_mgr_register_full(struct device *parent, const struct fpga_manager_info *info, + struct module *owner) { const struct fpga_manager_ops *mops = info->mops; struct fpga_manager *mgr; @@ -804,6 +813,8 @@ fpga_mgr_register_full(struct device *parent, const struct fpga_manager_info *in mutex_init(&mgr->ref_mutex); + mgr->mops_owner = owner; + mgr->name = info->name; mgr->mops = info->mops; mgr->priv = info->priv; @@ -841,14 +852,15 @@ error_kfree: return ERR_PTR(ret); } -EXPORT_SYMBOL_GPL(fpga_mgr_register_full); +EXPORT_SYMBOL_GPL(__fpga_mgr_register_full); /** - * fpga_mgr_register - create and register an FPGA Manager device + * __fpga_mgr_register - create and register an FPGA Manager device * @parent: fpga manager device from pdev * @name: fpga manager name * @mops: pointer to structure of fpga manager ops * @priv: fpga manager private data + * @owner: owner module containing the ops * * The caller of this function is responsible for calling fpga_mgr_unregister(). * Using devm_fpga_mgr_register() instead is recommended. This simple @@ -859,8 +871,8 @@ EXPORT_SYMBOL_GPL(fpga_mgr_register_full); * Return: pointer to struct fpga_manager pointer or ERR_PTR() */ struct fpga_manager * -fpga_mgr_register(struct device *parent, const char *name, - const struct fpga_manager_ops *mops, void *priv) +__fpga_mgr_register(struct device *parent, const char *name, + const struct fpga_manager_ops *mops, void *priv, struct module *owner) { struct fpga_manager_info info = { 0 }; @@ -868,9 +880,9 @@ fpga_mgr_register(struct device *parent, const char *name, info.mops = mops; info.priv = priv; - return fpga_mgr_register_full(parent, &info); + return __fpga_mgr_register_full(parent, &info, owner); } -EXPORT_SYMBOL_GPL(fpga_mgr_register); +EXPORT_SYMBOL_GPL(__fpga_mgr_register); /** * fpga_mgr_unregister - unregister an FPGA manager @@ -900,9 +912,10 @@ static void devm_fpga_mgr_unregister(struct device *dev, void *res) } /** - * devm_fpga_mgr_register_full - resource managed variant of fpga_mgr_register() + * __devm_fpga_mgr_register_full - resource managed variant of fpga_mgr_register() * @parent: fpga manager device from pdev * @info: parameters for fpga manager + * @owner: owner module containing the ops * * Return: fpga manager pointer on success, negative error code otherwise. * @@ -910,7 +923,8 @@ static void devm_fpga_mgr_unregister(struct device *dev, void *res) * function will be called automatically when the managing device is detached. */ struct fpga_manager * -devm_fpga_mgr_register_full(struct device *parent, const struct fpga_manager_info *info) +__devm_fpga_mgr_register_full(struct device *parent, const struct fpga_manager_info *info, + struct module *owner) { struct fpga_mgr_devres *dr; struct fpga_manager *mgr; @@ -919,7 +933,7 @@ devm_fpga_mgr_register_full(struct device *parent, const struct fpga_manager_inf if (!dr) return ERR_PTR(-ENOMEM); - mgr = fpga_mgr_register_full(parent, info); + mgr = __fpga_mgr_register_full(parent, info, owner); if (IS_ERR(mgr)) { devres_free(dr); return mgr; @@ -930,14 +944,15 @@ devm_fpga_mgr_register_full(struct device *parent, const struct fpga_manager_inf return mgr; } -EXPORT_SYMBOL_GPL(devm_fpga_mgr_register_full); +EXPORT_SYMBOL_GPL(__devm_fpga_mgr_register_full); /** - * devm_fpga_mgr_register - resource managed variant of fpga_mgr_register() + * __devm_fpga_mgr_register - resource managed variant of fpga_mgr_register() * @parent: fpga manager device from pdev * @name: fpga manager name * @mops: pointer to structure of fpga manager ops * @priv: fpga manager private data + * @owner: owner module containing the ops * * Return: fpga manager pointer on success, negative error code otherwise. * @@ -946,8 +961,9 @@ EXPORT_SYMBOL_GPL(devm_fpga_mgr_register_full); * device is detached. */ struct fpga_manager * -devm_fpga_mgr_register(struct device *parent, const char *name, - const struct fpga_manager_ops *mops, void *priv) +__devm_fpga_mgr_register(struct device *parent, const char *name, + const struct fpga_manager_ops *mops, void *priv, + struct module *owner) { struct fpga_manager_info info = { 0 }; @@ -955,9 +971,9 @@ devm_fpga_mgr_register(struct device *parent, const char *name, info.mops = mops; info.priv = priv; - return devm_fpga_mgr_register_full(parent, &info); + return __devm_fpga_mgr_register_full(parent, &info, owner); } -EXPORT_SYMBOL_GPL(devm_fpga_mgr_register); +EXPORT_SYMBOL_GPL(__devm_fpga_mgr_register); static void fpga_mgr_dev_release(struct device *dev) { diff --git a/include/linux/fpga/fpga-mgr.h b/include/linux/fpga/fpga-mgr.h index 54f63459efd6..0d4fe068f3d8 100644 --- a/include/linux/fpga/fpga-mgr.h +++ b/include/linux/fpga/fpga-mgr.h @@ -201,6 +201,7 @@ struct fpga_manager_ops { * @state: state of fpga manager * @compat_id: FPGA manager id for compatibility check. * @mops: pointer to struct of fpga manager ops + * @mops_owner: module containing the mops * @priv: low level driver private date */ struct fpga_manager { @@ -210,6 +211,7 @@ struct fpga_manager { enum fpga_mgr_states state; struct fpga_compat_id *compat_id; const struct fpga_manager_ops *mops; + struct module *mops_owner; void *priv; }; @@ -230,18 +232,30 @@ struct fpga_manager *fpga_mgr_get(struct device *dev); void fpga_mgr_put(struct fpga_manager *mgr); +#define fpga_mgr_register_full(parent, info) \ + __fpga_mgr_register_full(parent, info, THIS_MODULE) struct fpga_manager * -fpga_mgr_register_full(struct device *parent, const struct fpga_manager_info *info); +__fpga_mgr_register_full(struct device *parent, const struct fpga_manager_info *info, + struct module *owner); +#define fpga_mgr_register(parent, name, mops, priv) \ + __fpga_mgr_register(parent, name, mops, priv, THIS_MODULE) struct fpga_manager * -fpga_mgr_register(struct device *parent, const char *name, - const struct fpga_manager_ops *mops, void *priv); +__fpga_mgr_register(struct device *parent, const char *name, + const struct fpga_manager_ops *mops, void *priv, struct module *owner); + void fpga_mgr_unregister(struct fpga_manager *mgr); +#define devm_fpga_mgr_register_full(parent, info) \ + __devm_fpga_mgr_register_full(parent, info, THIS_MODULE) struct fpga_manager * -devm_fpga_mgr_register_full(struct device *parent, const struct fpga_manager_info *info); +__devm_fpga_mgr_register_full(struct device *parent, const struct fpga_manager_info *info, + struct module *owner); +#define devm_fpga_mgr_register(parent, name, mops, priv) \ + __devm_fpga_mgr_register(parent, name, mops, priv, THIS_MODULE) struct fpga_manager * -devm_fpga_mgr_register(struct device *parent, const char *name, - const struct fpga_manager_ops *mops, void *priv); +__devm_fpga_mgr_register(struct device *parent, const char *name, + const struct fpga_manager_ops *mops, void *priv, + struct module *owner); #endif /*_LINUX_FPGA_MGR_H */ -- cgit v1.2.3-59-g8ed1b From 1da11f822042eb6ef4b6064dc048f157a7852529 Mon Sep 17 00:00:00 2001 From: Marco Pagani Date: Fri, 22 Mar 2024 18:18:37 +0100 Subject: fpga: bridge: add owner module and take its refcount The current implementation of the fpga bridge assumes that the low-level module registers a driver for the parent device and uses its owner pointer to take the module's refcount. This approach is problematic since it can lead to a null pointer dereference while attempting to get the bridge if the parent device does not have a driver. To address this problem, add a module owner pointer to the fpga_bridge struct and use it to take the module's refcount. Modify the function for registering a bridge to take an additional owner module parameter and rename it to avoid conflicts. Use the old function name for a helper macro that automatically sets the module that registers the bridge as the owner. This ensures compatibility with existing low-level control modules and reduces the chances of registering a bridge without setting the owner. Also, update the documentation to keep it consistent with the new interface for registering an fpga bridge. Other changes: opportunistically move put_device() from __fpga_bridge_get() to fpga_bridge_get() and of_fpga_bridge_get() to improve code clarity since the bridge device is taken in these functions. Fixes: 21aeda950c5f ("fpga: add fpga bridge framework") Suggested-by: Greg Kroah-Hartman Suggested-by: Xu Yilun Reviewed-by: Russ Weight Signed-off-by: Marco Pagani Acked-by: Xu Yilun Link: https://lore.kernel.org/r/20240322171839.233864-1-marpagan@redhat.com Signed-off-by: Xu Yilun --- Documentation/driver-api/fpga/fpga-bridge.rst | 7 +++- drivers/fpga/fpga-bridge.c | 57 +++++++++++++++------------ include/linux/fpga/fpga-bridge.h | 10 +++-- 3 files changed, 43 insertions(+), 31 deletions(-) diff --git a/Documentation/driver-api/fpga/fpga-bridge.rst b/Documentation/driver-api/fpga/fpga-bridge.rst index 604208534095..833f68fb0700 100644 --- a/Documentation/driver-api/fpga/fpga-bridge.rst +++ b/Documentation/driver-api/fpga/fpga-bridge.rst @@ -6,9 +6,12 @@ API to implement a new FPGA bridge * struct fpga_bridge - The FPGA Bridge structure * struct fpga_bridge_ops - Low level Bridge driver ops -* fpga_bridge_register() - Create and register a bridge +* __fpga_bridge_register() - Create and register a bridge * fpga_bridge_unregister() - Unregister a bridge +The helper macro ``fpga_bridge_register()`` automatically sets +the module that registers the FPGA bridge as the owner. + .. kernel-doc:: include/linux/fpga/fpga-bridge.h :functions: fpga_bridge @@ -16,7 +19,7 @@ API to implement a new FPGA bridge :functions: fpga_bridge_ops .. kernel-doc:: drivers/fpga/fpga-bridge.c - :functions: fpga_bridge_register + :functions: __fpga_bridge_register .. kernel-doc:: drivers/fpga/fpga-bridge.c :functions: fpga_bridge_unregister diff --git a/drivers/fpga/fpga-bridge.c b/drivers/fpga/fpga-bridge.c index 79c473b3c7c3..8ef395b49bf8 100644 --- a/drivers/fpga/fpga-bridge.c +++ b/drivers/fpga/fpga-bridge.c @@ -55,33 +55,26 @@ int fpga_bridge_disable(struct fpga_bridge *bridge) } EXPORT_SYMBOL_GPL(fpga_bridge_disable); -static struct fpga_bridge *__fpga_bridge_get(struct device *dev, +static struct fpga_bridge *__fpga_bridge_get(struct device *bridge_dev, struct fpga_image_info *info) { struct fpga_bridge *bridge; - int ret = -ENODEV; - bridge = to_fpga_bridge(dev); + bridge = to_fpga_bridge(bridge_dev); bridge->info = info; - if (!mutex_trylock(&bridge->mutex)) { - ret = -EBUSY; - goto err_dev; - } + if (!mutex_trylock(&bridge->mutex)) + return ERR_PTR(-EBUSY); - if (!try_module_get(dev->parent->driver->owner)) - goto err_ll_mod; + if (!try_module_get(bridge->br_ops_owner)) { + mutex_unlock(&bridge->mutex); + return ERR_PTR(-ENODEV); + } dev_dbg(&bridge->dev, "get\n"); return bridge; - -err_ll_mod: - mutex_unlock(&bridge->mutex); -err_dev: - put_device(dev); - return ERR_PTR(ret); } /** @@ -98,13 +91,18 @@ err_dev: struct fpga_bridge *of_fpga_bridge_get(struct device_node *np, struct fpga_image_info *info) { - struct device *dev; + struct fpga_bridge *bridge; + struct device *bridge_dev; - dev = class_find_device_by_of_node(&fpga_bridge_class, np); - if (!dev) + bridge_dev = class_find_device_by_of_node(&fpga_bridge_class, np); + if (!bridge_dev) return ERR_PTR(-ENODEV); - return __fpga_bridge_get(dev, info); + bridge = __fpga_bridge_get(bridge_dev, info); + if (IS_ERR(bridge)) + put_device(bridge_dev); + + return bridge; } EXPORT_SYMBOL_GPL(of_fpga_bridge_get); @@ -125,6 +123,7 @@ static int fpga_bridge_dev_match(struct device *dev, const void *data) struct fpga_bridge *fpga_bridge_get(struct device *dev, struct fpga_image_info *info) { + struct fpga_bridge *bridge; struct device *bridge_dev; bridge_dev = class_find_device(&fpga_bridge_class, NULL, dev, @@ -132,7 +131,11 @@ struct fpga_bridge *fpga_bridge_get(struct device *dev, if (!bridge_dev) return ERR_PTR(-ENODEV); - return __fpga_bridge_get(bridge_dev, info); + bridge = __fpga_bridge_get(bridge_dev, info); + if (IS_ERR(bridge)) + put_device(bridge_dev); + + return bridge; } EXPORT_SYMBOL_GPL(fpga_bridge_get); @@ -146,7 +149,7 @@ void fpga_bridge_put(struct fpga_bridge *bridge) dev_dbg(&bridge->dev, "put\n"); bridge->info = NULL; - module_put(bridge->dev.parent->driver->owner); + module_put(bridge->br_ops_owner); mutex_unlock(&bridge->mutex); put_device(&bridge->dev); } @@ -316,18 +319,19 @@ static struct attribute *fpga_bridge_attrs[] = { ATTRIBUTE_GROUPS(fpga_bridge); /** - * fpga_bridge_register - create and register an FPGA Bridge device + * __fpga_bridge_register - create and register an FPGA Bridge device * @parent: FPGA bridge device from pdev * @name: FPGA bridge name * @br_ops: pointer to structure of fpga bridge ops * @priv: FPGA bridge private data + * @owner: owner module containing the br_ops * * Return: struct fpga_bridge pointer or ERR_PTR() */ struct fpga_bridge * -fpga_bridge_register(struct device *parent, const char *name, - const struct fpga_bridge_ops *br_ops, - void *priv) +__fpga_bridge_register(struct device *parent, const char *name, + const struct fpga_bridge_ops *br_ops, + void *priv, struct module *owner) { struct fpga_bridge *bridge; int id, ret; @@ -357,6 +361,7 @@ fpga_bridge_register(struct device *parent, const char *name, bridge->name = name; bridge->br_ops = br_ops; + bridge->br_ops_owner = owner; bridge->priv = priv; bridge->dev.groups = br_ops->groups; @@ -386,7 +391,7 @@ error_kfree: return ERR_PTR(ret); } -EXPORT_SYMBOL_GPL(fpga_bridge_register); +EXPORT_SYMBOL_GPL(__fpga_bridge_register); /** * fpga_bridge_unregister - unregister an FPGA bridge diff --git a/include/linux/fpga/fpga-bridge.h b/include/linux/fpga/fpga-bridge.h index 223da48a6d18..94c4edd047e5 100644 --- a/include/linux/fpga/fpga-bridge.h +++ b/include/linux/fpga/fpga-bridge.h @@ -45,6 +45,7 @@ struct fpga_bridge_info { * @dev: FPGA bridge device * @mutex: enforces exclusive reference to bridge * @br_ops: pointer to struct of FPGA bridge ops + * @br_ops_owner: module containing the br_ops * @info: fpga image specific information * @node: FPGA bridge list node * @priv: low level driver private date @@ -54,6 +55,7 @@ struct fpga_bridge { struct device dev; struct mutex mutex; /* for exclusive reference to bridge */ const struct fpga_bridge_ops *br_ops; + struct module *br_ops_owner; struct fpga_image_info *info; struct list_head node; void *priv; @@ -79,10 +81,12 @@ int of_fpga_bridge_get_to_list(struct device_node *np, struct fpga_image_info *info, struct list_head *bridge_list); +#define fpga_bridge_register(parent, name, br_ops, priv) \ + __fpga_bridge_register(parent, name, br_ops, priv, THIS_MODULE) struct fpga_bridge * -fpga_bridge_register(struct device *parent, const char *name, - const struct fpga_bridge_ops *br_ops, - void *priv); +__fpga_bridge_register(struct device *parent, const char *name, + const struct fpga_bridge_ops *br_ops, void *priv, + struct module *owner); void fpga_bridge_unregister(struct fpga_bridge *br); #endif /* _LINUX_FPGA_BRIDGE_H */ -- cgit v1.2.3-59-g8ed1b From a52e3a9dba347134ee53ebfe68b7b22548a387b0 Mon Sep 17 00:00:00 2001 From: Charles Perry Date: Thu, 21 Mar 2024 18:04:33 -0400 Subject: fpga: xilinx-spi: extract a common driver core Factor out the gpio handshaking (using PROGRAM_B, INIT_B and DONE) protocol in xilinx-core so that it can be reused for another driver. This commit does not change anything functionally to xilinx-spi. xilinx-core expects drivers to provide a write(const char* buf, size_t count) function that performs the actual write to the device, as well as a struct device* for resource management. Signed-off-by: Charles Perry Acked-by: Xu Yilun Link: https://lore.kernel.org/r/20240321220447.3260065-2-charles.perry@savoirfairelinux.com Signed-off-by: Xu Yilun --- drivers/fpga/Kconfig | 4 + drivers/fpga/Makefile | 1 + drivers/fpga/xilinx-core.c | 213 ++++++++++++++++++++++++++++++++++++++++++ drivers/fpga/xilinx-core.h | 27 ++++++ drivers/fpga/xilinx-spi.c | 224 +++------------------------------------------ 5 files changed, 260 insertions(+), 209 deletions(-) create mode 100644 drivers/fpga/xilinx-core.c create mode 100644 drivers/fpga/xilinx-core.h diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig index 2f689ac4ba3a..d27a1ebf4083 100644 --- a/drivers/fpga/Kconfig +++ b/drivers/fpga/Kconfig @@ -64,9 +64,13 @@ config FPGA_MGR_STRATIX10_SOC help FPGA manager driver support for the Intel Stratix10 SoC. +config FPGA_MGR_XILINX_CORE + tristate + config FPGA_MGR_XILINX_SPI tristate "Xilinx Configuration over Slave Serial (SPI)" depends on SPI + select FPGA_MGR_XILINX_CORE help FPGA manager driver support for Xilinx FPGA configuration over slave serial interface. diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile index 352a2612623e..7ec795b6a5a7 100644 --- a/drivers/fpga/Makefile +++ b/drivers/fpga/Makefile @@ -15,6 +15,7 @@ obj-$(CONFIG_FPGA_MGR_SOCFPGA) += socfpga.o obj-$(CONFIG_FPGA_MGR_SOCFPGA_A10) += socfpga-a10.o obj-$(CONFIG_FPGA_MGR_STRATIX10_SOC) += stratix10-soc.o obj-$(CONFIG_FPGA_MGR_TS73XX) += ts73xx-fpga.o +obj-$(CONFIG_FPGA_MGR_XILINX_CORE) += xilinx-core.o obj-$(CONFIG_FPGA_MGR_XILINX_SPI) += xilinx-spi.o obj-$(CONFIG_FPGA_MGR_ZYNQ_FPGA) += zynq-fpga.o obj-$(CONFIG_FPGA_MGR_ZYNQMP_FPGA) += zynqmp-fpga.o diff --git a/drivers/fpga/xilinx-core.c b/drivers/fpga/xilinx-core.c new file mode 100644 index 000000000000..a35c43382dd5 --- /dev/null +++ b/drivers/fpga/xilinx-core.c @@ -0,0 +1,213 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Common parts of the Xilinx Spartan6 and 7 Series FPGA manager drivers. + * + * Copyright (C) 2017 DENX Software Engineering + * + * Anatolij Gustschin + */ + +#include "xilinx-core.h" + +#include +#include +#include +#include + +static int get_done_gpio(struct fpga_manager *mgr) +{ + struct xilinx_fpga_core *core = mgr->priv; + int ret; + + ret = gpiod_get_value(core->done); + if (ret < 0) + dev_err(&mgr->dev, "Error reading DONE (%d)\n", ret); + + return ret; +} + +static enum fpga_mgr_states xilinx_core_state(struct fpga_manager *mgr) +{ + if (!get_done_gpio(mgr)) + return FPGA_MGR_STATE_RESET; + + return FPGA_MGR_STATE_UNKNOWN; +} + +/** + * wait_for_init_b - wait for the INIT_B pin to have a given state, or wait + * a given delay if the pin is unavailable + * + * @mgr: The FPGA manager object + * @value: Value INIT_B to wait for (1 = asserted = low) + * @alt_udelay: Delay to wait if the INIT_B GPIO is not available + * + * Returns 0 when the INIT_B GPIO reached the given state or -ETIMEDOUT if + * too much time passed waiting for that. If no INIT_B GPIO is available + * then always return 0. + */ +static int wait_for_init_b(struct fpga_manager *mgr, int value, + unsigned long alt_udelay) +{ + struct xilinx_fpga_core *core = mgr->priv; + unsigned long timeout = jiffies + msecs_to_jiffies(1000); + + if (core->init_b) { + while (time_before(jiffies, timeout)) { + int ret = gpiod_get_value(core->init_b); + + if (ret == value) + return 0; + + if (ret < 0) { + dev_err(&mgr->dev, + "Error reading INIT_B (%d)\n", ret); + return ret; + } + + usleep_range(100, 400); + } + + dev_err(&mgr->dev, "Timeout waiting for INIT_B to %s\n", + value ? "assert" : "deassert"); + return -ETIMEDOUT; + } + + udelay(alt_udelay); + + return 0; +} + +static int xilinx_core_write_init(struct fpga_manager *mgr, + struct fpga_image_info *info, const char *buf, + size_t count) +{ + struct xilinx_fpga_core *core = mgr->priv; + int err; + + if (info->flags & FPGA_MGR_PARTIAL_RECONFIG) { + dev_err(&mgr->dev, "Partial reconfiguration not supported\n"); + return -EINVAL; + } + + gpiod_set_value(core->prog_b, 1); + + err = wait_for_init_b(mgr, 1, 1); /* min is 500 ns */ + if (err) { + gpiod_set_value(core->prog_b, 0); + return err; + } + + gpiod_set_value(core->prog_b, 0); + + err = wait_for_init_b(mgr, 0, 0); + if (err) + return err; + + if (get_done_gpio(mgr)) { + dev_err(&mgr->dev, "Unexpected DONE pin state...\n"); + return -EIO; + } + + /* program latency */ + usleep_range(7500, 7600); + return 0; +} + +static int xilinx_core_write(struct fpga_manager *mgr, const char *buf, + size_t count) +{ + struct xilinx_fpga_core *core = mgr->priv; + + return core->write(core, buf, count); +} + +static int xilinx_core_write_complete(struct fpga_manager *mgr, + struct fpga_image_info *info) +{ + struct xilinx_fpga_core *core = mgr->priv; + unsigned long timeout = + jiffies + usecs_to_jiffies(info->config_complete_timeout_us); + bool expired = false; + int done; + int ret; + const char padding[1] = { 0xff }; + + /* + * This loop is carefully written such that if the driver is + * scheduled out for more than 'timeout', we still check for DONE + * before giving up and we apply 8 extra CCLK cycles in all cases. + */ + while (!expired) { + expired = time_after(jiffies, timeout); + + done = get_done_gpio(mgr); + if (done < 0) + return done; + + ret = core->write(core, padding, sizeof(padding)); + if (ret) + return ret; + + if (done) + return 0; + } + + if (core->init_b) { + ret = gpiod_get_value(core->init_b); + + if (ret < 0) { + dev_err(&mgr->dev, "Error reading INIT_B (%d)\n", ret); + return ret; + } + + dev_err(&mgr->dev, + ret ? "CRC error or invalid device\n" : + "Missing sync word or incomplete bitstream\n"); + } else { + dev_err(&mgr->dev, "Timeout after config data transfer\n"); + } + + return -ETIMEDOUT; +} + +static const struct fpga_manager_ops xilinx_core_ops = { + .state = xilinx_core_state, + .write_init = xilinx_core_write_init, + .write = xilinx_core_write, + .write_complete = xilinx_core_write_complete, +}; + +int xilinx_core_probe(struct xilinx_fpga_core *core) +{ + struct fpga_manager *mgr; + + if (!core || !core->dev || !core->write) + return -EINVAL; + + /* PROGRAM_B is active low */ + core->prog_b = devm_gpiod_get(core->dev, "prog_b", GPIOD_OUT_LOW); + if (IS_ERR(core->prog_b)) + return dev_err_probe(core->dev, PTR_ERR(core->prog_b), + "Failed to get PROGRAM_B gpio\n"); + + core->init_b = devm_gpiod_get_optional(core->dev, "init-b", GPIOD_IN); + if (IS_ERR(core->init_b)) + return dev_err_probe(core->dev, PTR_ERR(core->init_b), + "Failed to get INIT_B gpio\n"); + + core->done = devm_gpiod_get(core->dev, "done", GPIOD_IN); + if (IS_ERR(core->done)) + return dev_err_probe(core->dev, PTR_ERR(core->done), + "Failed to get DONE gpio\n"); + + mgr = devm_fpga_mgr_register(core->dev, + "Xilinx Slave Serial FPGA Manager", + &xilinx_core_ops, core); + return PTR_ERR_OR_ZERO(mgr); +} +EXPORT_SYMBOL_GPL(xilinx_core_probe); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Anatolij Gustschin "); +MODULE_DESCRIPTION("Xilinx 7 Series FPGA manager core"); diff --git a/drivers/fpga/xilinx-core.h b/drivers/fpga/xilinx-core.h new file mode 100644 index 000000000000..f02ac67fce7b --- /dev/null +++ b/drivers/fpga/xilinx-core.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef __XILINX_CORE_H +#define __XILINX_CORE_H + +#include + +/** + * struct xilinx_fpga_core - interface between the driver and the core manager + * of Xilinx 7 Series FPGA manager + * @dev: device node + * @write: write callback of the driver + */ +struct xilinx_fpga_core { +/* public: */ + struct device *dev; + int (*write)(struct xilinx_fpga_core *core, const char *buf, + size_t count); +/* private: handled by xilinx-core */ + struct gpio_desc *prog_b; + struct gpio_desc *init_b; + struct gpio_desc *done; +}; + +int xilinx_core_probe(struct xilinx_fpga_core *core); + +#endif /* __XILINX_CORE_H */ diff --git a/drivers/fpga/xilinx-spi.c b/drivers/fpga/xilinx-spi.c index e1a227e7ff2a..8756504340de 100644 --- a/drivers/fpga/xilinx-spi.c +++ b/drivers/fpga/xilinx-spi.c @@ -10,127 +10,17 @@ * the slave serial configuration interface. */ -#include -#include -#include -#include +#include "xilinx-core.h" + #include #include #include #include -#include - -struct xilinx_spi_conf { - struct spi_device *spi; - struct gpio_desc *prog_b; - struct gpio_desc *init_b; - struct gpio_desc *done; -}; - -static int get_done_gpio(struct fpga_manager *mgr) -{ - struct xilinx_spi_conf *conf = mgr->priv; - int ret; - - ret = gpiod_get_value(conf->done); - - if (ret < 0) - dev_err(&mgr->dev, "Error reading DONE (%d)\n", ret); - - return ret; -} - -static enum fpga_mgr_states xilinx_spi_state(struct fpga_manager *mgr) -{ - if (!get_done_gpio(mgr)) - return FPGA_MGR_STATE_RESET; - - return FPGA_MGR_STATE_UNKNOWN; -} - -/** - * wait_for_init_b - wait for the INIT_B pin to have a given state, or wait - * a given delay if the pin is unavailable - * - * @mgr: The FPGA manager object - * @value: Value INIT_B to wait for (1 = asserted = low) - * @alt_udelay: Delay to wait if the INIT_B GPIO is not available - * - * Returns 0 when the INIT_B GPIO reached the given state or -ETIMEDOUT if - * too much time passed waiting for that. If no INIT_B GPIO is available - * then always return 0. - */ -static int wait_for_init_b(struct fpga_manager *mgr, int value, - unsigned long alt_udelay) -{ - struct xilinx_spi_conf *conf = mgr->priv; - unsigned long timeout = jiffies + msecs_to_jiffies(1000); - - if (conf->init_b) { - while (time_before(jiffies, timeout)) { - int ret = gpiod_get_value(conf->init_b); - - if (ret == value) - return 0; - - if (ret < 0) { - dev_err(&mgr->dev, "Error reading INIT_B (%d)\n", ret); - return ret; - } - - usleep_range(100, 400); - } - - dev_err(&mgr->dev, "Timeout waiting for INIT_B to %s\n", - value ? "assert" : "deassert"); - return -ETIMEDOUT; - } - - udelay(alt_udelay); - - return 0; -} - -static int xilinx_spi_write_init(struct fpga_manager *mgr, - struct fpga_image_info *info, - const char *buf, size_t count) -{ - struct xilinx_spi_conf *conf = mgr->priv; - int err; - - if (info->flags & FPGA_MGR_PARTIAL_RECONFIG) { - dev_err(&mgr->dev, "Partial reconfiguration not supported\n"); - return -EINVAL; - } - - gpiod_set_value(conf->prog_b, 1); - - err = wait_for_init_b(mgr, 1, 1); /* min is 500 ns */ - if (err) { - gpiod_set_value(conf->prog_b, 0); - return err; - } - - gpiod_set_value(conf->prog_b, 0); - - err = wait_for_init_b(mgr, 0, 0); - if (err) - return err; - - if (get_done_gpio(mgr)) { - dev_err(&mgr->dev, "Unexpected DONE pin state...\n"); - return -EIO; - } - /* program latency */ - usleep_range(7500, 7600); - return 0; -} - -static int xilinx_spi_write(struct fpga_manager *mgr, const char *buf, +static int xilinx_spi_write(struct xilinx_fpga_core *core, const char *buf, size_t count) { - struct xilinx_spi_conf *conf = mgr->priv; + struct spi_device *spi = to_spi_device(core->dev); const char *fw_data = buf; const char *fw_data_end = fw_data + count; @@ -141,9 +31,9 @@ static int xilinx_spi_write(struct fpga_manager *mgr, const char *buf, remaining = fw_data_end - fw_data; stride = min_t(size_t, remaining, SZ_4K); - ret = spi_write(conf->spi, fw_data, stride); + ret = spi_write(spi, fw_data, stride); if (ret) { - dev_err(&mgr->dev, "SPI error in firmware write: %d\n", + dev_err(core->dev, "SPI error in firmware write: %d\n", ret); return ret; } @@ -153,109 +43,25 @@ static int xilinx_spi_write(struct fpga_manager *mgr, const char *buf, return 0; } -static int xilinx_spi_apply_cclk_cycles(struct xilinx_spi_conf *conf) -{ - struct spi_device *spi = conf->spi; - const u8 din_data[1] = { 0xff }; - int ret; - - ret = spi_write(conf->spi, din_data, sizeof(din_data)); - if (ret) - dev_err(&spi->dev, "applying CCLK cycles failed: %d\n", ret); - - return ret; -} - -static int xilinx_spi_write_complete(struct fpga_manager *mgr, - struct fpga_image_info *info) -{ - struct xilinx_spi_conf *conf = mgr->priv; - unsigned long timeout = jiffies + usecs_to_jiffies(info->config_complete_timeout_us); - bool expired = false; - int done; - int ret; - - /* - * This loop is carefully written such that if the driver is - * scheduled out for more than 'timeout', we still check for DONE - * before giving up and we apply 8 extra CCLK cycles in all cases. - */ - while (!expired) { - expired = time_after(jiffies, timeout); - - done = get_done_gpio(mgr); - if (done < 0) - return done; - - ret = xilinx_spi_apply_cclk_cycles(conf); - if (ret) - return ret; - - if (done) - return 0; - } - - if (conf->init_b) { - ret = gpiod_get_value(conf->init_b); - - if (ret < 0) { - dev_err(&mgr->dev, "Error reading INIT_B (%d)\n", ret); - return ret; - } - - dev_err(&mgr->dev, - ret ? "CRC error or invalid device\n" - : "Missing sync word or incomplete bitstream\n"); - } else { - dev_err(&mgr->dev, "Timeout after config data transfer\n"); - } - - return -ETIMEDOUT; -} - -static const struct fpga_manager_ops xilinx_spi_ops = { - .state = xilinx_spi_state, - .write_init = xilinx_spi_write_init, - .write = xilinx_spi_write, - .write_complete = xilinx_spi_write_complete, -}; - static int xilinx_spi_probe(struct spi_device *spi) { - struct xilinx_spi_conf *conf; - struct fpga_manager *mgr; + struct xilinx_fpga_core *core; - conf = devm_kzalloc(&spi->dev, sizeof(*conf), GFP_KERNEL); - if (!conf) + core = devm_kzalloc(&spi->dev, sizeof(*core), GFP_KERNEL); + if (!core) return -ENOMEM; - conf->spi = spi; + core->dev = &spi->dev; + core->write = xilinx_spi_write; - /* PROGRAM_B is active low */ - conf->prog_b = devm_gpiod_get(&spi->dev, "prog_b", GPIOD_OUT_LOW); - if (IS_ERR(conf->prog_b)) - return dev_err_probe(&spi->dev, PTR_ERR(conf->prog_b), - "Failed to get PROGRAM_B gpio\n"); - - conf->init_b = devm_gpiod_get_optional(&spi->dev, "init-b", GPIOD_IN); - if (IS_ERR(conf->init_b)) - return dev_err_probe(&spi->dev, PTR_ERR(conf->init_b), - "Failed to get INIT_B gpio\n"); - - conf->done = devm_gpiod_get(&spi->dev, "done", GPIOD_IN); - if (IS_ERR(conf->done)) - return dev_err_probe(&spi->dev, PTR_ERR(conf->done), - "Failed to get DONE gpio\n"); - - mgr = devm_fpga_mgr_register(&spi->dev, - "Xilinx Slave Serial FPGA Manager", - &xilinx_spi_ops, conf); - return PTR_ERR_OR_ZERO(mgr); + return xilinx_core_probe(core); } #ifdef CONFIG_OF static const struct of_device_id xlnx_spi_of_match[] = { - { .compatible = "xlnx,fpga-slave-serial", }, + { + .compatible = "xlnx,fpga-slave-serial", + }, {} }; MODULE_DEVICE_TABLE(of, xlnx_spi_of_match); -- cgit v1.2.3-59-g8ed1b From 8afcb190f3aac8d9ae4ca4f84a67bb281a4d9a3f Mon Sep 17 00:00:00 2001 From: Charles Perry Date: Thu, 21 Mar 2024 18:04:34 -0400 Subject: dt-bindings: fpga: xlnx,fpga-selectmap: add DT schema Document the SelectMAP interface of Xilinx 7 series FPGA. Signed-off-by: Charles Perry Reviewed-by: Krzysztof Kozlowski Acked-by: Xu Yilun Link: https://lore.kernel.org/r/20240321220447.3260065-3-charles.perry@savoirfairelinux.com Signed-off-by: Xu Yilun --- .../bindings/fpga/xlnx,fpga-selectmap.yaml | 86 ++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 Documentation/devicetree/bindings/fpga/xlnx,fpga-selectmap.yaml diff --git a/Documentation/devicetree/bindings/fpga/xlnx,fpga-selectmap.yaml b/Documentation/devicetree/bindings/fpga/xlnx,fpga-selectmap.yaml new file mode 100644 index 000000000000..05775746fd70 --- /dev/null +++ b/Documentation/devicetree/bindings/fpga/xlnx,fpga-selectmap.yaml @@ -0,0 +1,86 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/fpga/xlnx,fpga-selectmap.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Xilinx SelectMAP FPGA interface + +maintainers: + - Charles Perry + +description: | + Xilinx 7 Series FPGAs support a method of loading the bitstream over a + parallel port named the SelectMAP interface in the documentation. Only + the x8 mode is supported where data is loaded at one byte per rising edge of + the clock, with the MSB of each byte presented to the D0 pin. + + Datasheets: + https://www.xilinx.com/support/documentation/user_guides/ug470_7Series_Config.pdf + +allOf: + - $ref: /schemas/memory-controllers/mc-peripheral-props.yaml# + +properties: + compatible: + enum: + - xlnx,fpga-xc7s-selectmap + - xlnx,fpga-xc7a-selectmap + - xlnx,fpga-xc7k-selectmap + - xlnx,fpga-xc7v-selectmap + + reg: + description: + At least 1 byte of memory mapped IO + maxItems: 1 + + prog-gpios: + description: + config pin (referred to as PROGRAM_B in the manual) + maxItems: 1 + + done-gpios: + description: + config status pin (referred to as DONE in the manual) + maxItems: 1 + + init-gpios: + description: + initialization status and configuration error pin + (referred to as INIT_B in the manual) + maxItems: 1 + + csi-gpios: + description: + chip select pin (referred to as CSI_B in the manual) + Optional gpio for if the bus controller does not provide a chip select. + maxItems: 1 + + rdwr-gpios: + description: + read/write select pin (referred to as RDWR_B in the manual) + Optional gpio for if the bus controller does not provide this pin. + maxItems: 1 + +required: + - compatible + - reg + - prog-gpios + - done-gpios + - init-gpios + +unevaluatedProperties: false + +examples: + - | + #include + fpga-mgr@8000000 { + compatible = "xlnx,fpga-xc7s-selectmap"; + reg = <0x8000000 0x4>; + prog-gpios = <&gpio5 5 GPIO_ACTIVE_LOW>; + init-gpios = <&gpio5 8 GPIO_ACTIVE_LOW>; + done-gpios = <&gpio2 30 GPIO_ACTIVE_HIGH>; + csi-gpios = <&gpio3 19 GPIO_ACTIVE_LOW>; + rdwr-gpios = <&gpio3 10 GPIO_ACTIVE_LOW>; + }; +... -- cgit v1.2.3-59-g8ed1b From 104712a0866f7e3eb050271fc104c543aac642e8 Mon Sep 17 00:00:00 2001 From: Charles Perry Date: Thu, 21 Mar 2024 18:04:35 -0400 Subject: fpga: xilinx-selectmap: add new driver Xilinx 7 series FPGA can be programmed using a parallel port named the SelectMAP interface in the datasheet. This interface is compatible with the i.MX6 EIM bus controller but other types of external memory mapped parallel bus might work. xilinx-selectmap currently only supports the x8 mode where data is loaded at one byte per rising edge of the clock, with the MSb of each byte presented to the D0 pin. Signed-off-by: Charles Perry [yilun.xu@linux.intel.com: replace data type of i from u32 to size_t] Acked-by: Xu Yilun Link: https://lore.kernel.org/r/20240321220447.3260065-4-charles.perry@savoirfairelinux.com Signed-off-by: Xu Yilun --- drivers/fpga/Kconfig | 8 ++++ drivers/fpga/Makefile | 1 + drivers/fpga/xilinx-selectmap.c | 95 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 104 insertions(+) create mode 100644 drivers/fpga/xilinx-selectmap.c diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig index d27a1ebf4083..37b35f58f0df 100644 --- a/drivers/fpga/Kconfig +++ b/drivers/fpga/Kconfig @@ -67,6 +67,14 @@ config FPGA_MGR_STRATIX10_SOC config FPGA_MGR_XILINX_CORE tristate +config FPGA_MGR_XILINX_SELECTMAP + tristate "Xilinx Configuration over SelectMAP" + depends on HAS_IOMEM + select FPGA_MGR_XILINX_CORE + help + FPGA manager driver support for Xilinx FPGA configuration + over SelectMAP interface. + config FPGA_MGR_XILINX_SPI tristate "Xilinx Configuration over Slave Serial (SPI)" depends on SPI diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile index 7ec795b6a5a7..aeb89bb13517 100644 --- a/drivers/fpga/Makefile +++ b/drivers/fpga/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_FPGA_MGR_SOCFPGA_A10) += socfpga-a10.o obj-$(CONFIG_FPGA_MGR_STRATIX10_SOC) += stratix10-soc.o obj-$(CONFIG_FPGA_MGR_TS73XX) += ts73xx-fpga.o obj-$(CONFIG_FPGA_MGR_XILINX_CORE) += xilinx-core.o +obj-$(CONFIG_FPGA_MGR_XILINX_SELECTMAP) += xilinx-selectmap.o obj-$(CONFIG_FPGA_MGR_XILINX_SPI) += xilinx-spi.o obj-$(CONFIG_FPGA_MGR_ZYNQ_FPGA) += zynq-fpga.o obj-$(CONFIG_FPGA_MGR_ZYNQMP_FPGA) += zynqmp-fpga.o diff --git a/drivers/fpga/xilinx-selectmap.c b/drivers/fpga/xilinx-selectmap.c new file mode 100644 index 000000000000..2cd87e7e913f --- /dev/null +++ b/drivers/fpga/xilinx-selectmap.c @@ -0,0 +1,95 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Xilinx Spartan6 and 7 Series SelectMAP interface driver + * + * (C) 2024 Charles Perry + * + * Manage Xilinx FPGA firmware loaded over the SelectMAP configuration + * interface. + */ + +#include "xilinx-core.h" + +#include +#include +#include +#include +#include +#include + +struct xilinx_selectmap_conf { + struct xilinx_fpga_core core; + void __iomem *base; +}; + +#define to_xilinx_selectmap_conf(obj) \ + container_of(obj, struct xilinx_selectmap_conf, core) + +static int xilinx_selectmap_write(struct xilinx_fpga_core *core, + const char *buf, size_t count) +{ + struct xilinx_selectmap_conf *conf = to_xilinx_selectmap_conf(core); + size_t i; + + for (i = 0; i < count; ++i) + writeb(buf[i], conf->base); + + return 0; +} + +static int xilinx_selectmap_probe(struct platform_device *pdev) +{ + struct xilinx_selectmap_conf *conf; + struct gpio_desc *gpio; + void __iomem *base; + + conf = devm_kzalloc(&pdev->dev, sizeof(*conf), GFP_KERNEL); + if (!conf) + return -ENOMEM; + + conf->core.dev = &pdev->dev; + conf->core.write = xilinx_selectmap_write; + + base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); + if (IS_ERR(base)) + return dev_err_probe(&pdev->dev, PTR_ERR(base), + "ioremap error\n"); + conf->base = base; + + /* CSI_B is active low */ + gpio = devm_gpiod_get_optional(&pdev->dev, "csi", GPIOD_OUT_HIGH); + if (IS_ERR(gpio)) + return dev_err_probe(&pdev->dev, PTR_ERR(gpio), + "Failed to get CSI_B gpio\n"); + + /* RDWR_B is active low */ + gpio = devm_gpiod_get_optional(&pdev->dev, "rdwr", GPIOD_OUT_HIGH); + if (IS_ERR(gpio)) + return dev_err_probe(&pdev->dev, PTR_ERR(gpio), + "Failed to get RDWR_B gpio\n"); + + return xilinx_core_probe(&conf->core); +} + +static const struct of_device_id xlnx_selectmap_of_match[] = { + { .compatible = "xlnx,fpga-xc7s-selectmap", }, // Spartan-7 + { .compatible = "xlnx,fpga-xc7a-selectmap", }, // Artix-7 + { .compatible = "xlnx,fpga-xc7k-selectmap", }, // Kintex-7 + { .compatible = "xlnx,fpga-xc7v-selectmap", }, // Virtex-7 + {}, +}; +MODULE_DEVICE_TABLE(of, xlnx_selectmap_of_match); + +static struct platform_driver xilinx_selectmap_driver = { + .driver = { + .name = "xilinx-selectmap", + .of_match_table = xlnx_selectmap_of_match, + }, + .probe = xilinx_selectmap_probe, +}; + +module_platform_driver(xilinx_selectmap_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Charles Perry "); +MODULE_DESCRIPTION("Load Xilinx FPGA firmware over SelectMap"); -- cgit v1.2.3-59-g8ed1b From 4a1f12b5b50dd7d8ad681be701b2b00521c9d201 Mon Sep 17 00:00:00 2001 From: Charles Perry Date: Thu, 21 Mar 2024 18:04:36 -0400 Subject: fpga: xilinx-core: add new gpio names for prog and init Old names (prog_b and init-b) are used as a fallback for hardware compatible with the "xlnx,fpga-slave-serial" string. Signed-off-by: Charles Perry Acked-by: Xu Yilun Link: https://lore.kernel.org/r/20240321220447.3260065-5-charles.perry@savoirfairelinux.com Signed-off-by: Xu Yilun --- drivers/fpga/xilinx-core.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/drivers/fpga/xilinx-core.c b/drivers/fpga/xilinx-core.c index a35c43382dd5..39aeacf2e4f1 100644 --- a/drivers/fpga/xilinx-core.c +++ b/drivers/fpga/xilinx-core.c @@ -171,6 +171,20 @@ static int xilinx_core_write_complete(struct fpga_manager *mgr, return -ETIMEDOUT; } +static inline struct gpio_desc * +xilinx_core_devm_gpiod_get(struct device *dev, const char *con_id, + const char *legacy_con_id, enum gpiod_flags flags) +{ + struct gpio_desc *desc; + + desc = devm_gpiod_get(dev, con_id, flags); + if (IS_ERR(desc) && PTR_ERR(desc) == -ENOENT && + of_device_is_compatible(dev->of_node, "xlnx,fpga-slave-serial")) + desc = devm_gpiod_get(dev, legacy_con_id, flags); + + return desc; +} + static const struct fpga_manager_ops xilinx_core_ops = { .state = xilinx_core_state, .write_init = xilinx_core_write_init, @@ -186,12 +200,14 @@ int xilinx_core_probe(struct xilinx_fpga_core *core) return -EINVAL; /* PROGRAM_B is active low */ - core->prog_b = devm_gpiod_get(core->dev, "prog_b", GPIOD_OUT_LOW); + core->prog_b = xilinx_core_devm_gpiod_get(core->dev, "prog", "prog_b", + GPIOD_OUT_LOW); if (IS_ERR(core->prog_b)) return dev_err_probe(core->dev, PTR_ERR(core->prog_b), "Failed to get PROGRAM_B gpio\n"); - core->init_b = devm_gpiod_get_optional(core->dev, "init-b", GPIOD_IN); + core->init_b = xilinx_core_devm_gpiod_get(core->dev, "init", "init-b", + GPIOD_IN); if (IS_ERR(core->init_b)) return dev_err_probe(core->dev, PTR_ERR(core->init_b), "Failed to get INIT_B gpio\n"); -- cgit v1.2.3-59-g8ed1b From a97fc99a02c767f5970b75ce40fedd2a0843f323 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 27 Mar 2024 18:49:09 +0100 Subject: fpga: altera: drop driver owner assignment Core in spi_register_driver() already sets the .owner, so driver does not need to. Signed-off-by: Krzysztof Kozlowski Acked-by: Xu Yilun Link: https://lore.kernel.org/r/20240327174909.519796-1-krzysztof.kozlowski@linaro.org Signed-off-by: Xu Yilun --- drivers/fpga/altera-ps-spi.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/fpga/altera-ps-spi.c b/drivers/fpga/altera-ps-spi.c index 740980e7cef8..d0ec3539b31f 100644 --- a/drivers/fpga/altera-ps-spi.c +++ b/drivers/fpga/altera-ps-spi.c @@ -284,7 +284,6 @@ MODULE_DEVICE_TABLE(spi, altera_ps_spi_ids); static struct spi_driver altera_ps_driver = { .driver = { .name = "altera-ps-spi", - .owner = THIS_MODULE, .of_match_table = of_ef_match, }, .id_table = altera_ps_spi_ids, -- cgit v1.2.3-59-g8ed1b From f6c86fdf3716c9257612f8f001c6e95db84fb844 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Mon, 1 Apr 2024 15:08:21 +0200 Subject: fpga: altera-cvp: Remove an unused field in struct altera_cvp_conf In "struct altera_cvp_conf", the 'mgr' field is unused. Remove it. Found with cppcheck, unusedStructMember. Signed-off-by: Christophe JAILLET Acked-by: Xu Yilun Link: https://lore.kernel.org/r/7986690e79fa6f7880bc1db783cb0e46a1c2723e.1711976883.git.christophe.jaillet@wanadoo.fr Signed-off-by: Xu Yilun --- drivers/fpga/altera-cvp.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/fpga/altera-cvp.c b/drivers/fpga/altera-cvp.c index 4ffb9da537d8..6b0914432445 100644 --- a/drivers/fpga/altera-cvp.c +++ b/drivers/fpga/altera-cvp.c @@ -72,7 +72,6 @@ static bool altera_cvp_chkcfg; struct cvp_priv; struct altera_cvp_conf { - struct fpga_manager *mgr; struct pci_dev *pci_dev; void __iomem *map; void (*write_data)(struct altera_cvp_conf *conf, -- cgit v1.2.3-59-g8ed1b From 416bdb89605d960405178b9bf04df512d1ace1a3 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 22 Dec 2023 21:05:11 -0800 Subject: counter: linux/counter.h: fix Excess kernel-doc description warning Remove the @priv: line to prevent the kernel-doc warning: include/linux/counter.h:400: warning: Excess struct member 'priv' description in 'counter_device' Signed-off-by: Randy Dunlap Fixes: f2ee4759fb70 ("counter: remove old and now unused registration API") Link: https://lore.kernel.org/r/20231223050511.13849-1-rdunlap@infradead.org Signed-off-by: William Breathitt Gray --- include/linux/counter.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/linux/counter.h b/include/linux/counter.h index 702e9108bbb4..b767b5c821f5 100644 --- a/include/linux/counter.h +++ b/include/linux/counter.h @@ -359,7 +359,6 @@ struct counter_ops { * @num_counts: number of Counts specified in @counts * @ext: optional array of Counter device extensions * @num_ext: number of Counter device extensions specified in @ext - * @priv: optional private data supplied by driver * @dev: internal device structure * @chrdev: internal character device structure * @events_list: list of current watching Counter events -- cgit v1.2.3-59-g8ed1b From 6b0828ca8bd18315647511dfe731101b6a59de2b Mon Sep 17 00:00:00 2001 From: "Ricardo B. Marliere" Date: Sun, 4 Feb 2024 13:02:30 -0300 Subject: counter: make counter_bus_type const Now that the driver core can properly handle constant struct bus_type, move the counter_bus_type variable to be a constant structure as well, placing it into read-only memory which can not be modified at runtime. Suggested-by: Greg Kroah-Hartman Signed-off-by: "Ricardo B. Marliere" Reviewed-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20240204-bus_cleanup-counter-v1-1-cef9dd719bdc@marliere.net Signed-off-by: William Breathitt Gray --- drivers/counter/counter-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/counter/counter-core.c b/drivers/counter/counter-core.c index 3f24481fc04a..29df0985f2ba 100644 --- a/drivers/counter/counter-core.c +++ b/drivers/counter/counter-core.c @@ -54,7 +54,7 @@ static struct device_type counter_device_type = { .release = counter_device_release, }; -static struct bus_type counter_bus_type = { +static const struct bus_type counter_bus_type = { .name = "counter", .dev_name = "counter", }; -- cgit v1.2.3-59-g8ed1b From e0363c0706a187b037c06e1f30b2ac0fb44c31c3 Mon Sep 17 00:00:00 2001 From: "Ricardo B. Marliere" Date: Mon, 19 Feb 2024 16:52:52 -0300 Subject: counter: constify the struct device_type usage Since commit aed65af1cc2f ("drivers: make device_type const"), the driver core can properly handle constant struct device_type. Move the counter_device_type variable to be a constant structure as well, placing it into read-only memory which can not be modified at runtime. Cc: Greg Kroah-Hartman Signed-off-by: "Ricardo B. Marliere" Link: https://lore.kernel.org/r/20240219-device_cleanup-counter-v1-1-24d0316ae815@marliere.net Signed-off-by: William Breathitt Gray --- drivers/counter/counter-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/counter/counter-core.c b/drivers/counter/counter-core.c index 29df0985f2ba..893b4f0726d2 100644 --- a/drivers/counter/counter-core.c +++ b/drivers/counter/counter-core.c @@ -49,7 +49,7 @@ static void counter_device_release(struct device *dev) kfree(container_of(counter, struct counter_device_allochelper, counter)); } -static struct device_type counter_device_type = { +static const struct device_type counter_device_type = { .name = "counter_device", .release = counter_device_release, }; -- cgit v1.2.3-59-g8ed1b From 2f48aba356a004d854bc6d77fbc032b2fc666911 Mon Sep 17 00:00:00 2001 From: Fabrice Gasnier Date: Wed, 6 Mar 2024 16:36:31 +0100 Subject: counter: Introduce the COUNTER_COMP_FREQUENCY() macro Now that there are two users for the "frequency" extension, introduce a new COUNTER_COMP_FREQUENCY() macro. This extension is intended to be a read-only signal attribute. Suggested-by: William Breathitt Gray Signed-off-by: Fabrice Gasnier Link: https://lore.kernel.org/r/20240306153631.4051115-1-fabrice.gasnier@foss.st.com Signed-off-by: William Breathitt Gray --- include/linux/counter.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/linux/counter.h b/include/linux/counter.h index b767b5c821f5..cd35d8574ee2 100644 --- a/include/linux/counter.h +++ b/include/linux/counter.h @@ -601,6 +601,9 @@ struct counter_array { #define COUNTER_COMP_FLOOR(_read, _write) \ COUNTER_COMP_COUNT_U64("floor", _read, _write) +#define COUNTER_COMP_FREQUENCY(_read) \ + COUNTER_COMP_SIGNAL_U64("frequency", _read, NULL) + #define COUNTER_COMP_POLARITY(_read, _write, _available) \ { \ .type = COUNTER_COMP_SIGNAL_POLARITY, \ -- cgit v1.2.3-59-g8ed1b From f7131297d638ffc9a63005464f7108e0dfdda8b6 Mon Sep 17 00:00:00 2001 From: Fabrice Gasnier Date: Thu, 7 Mar 2024 14:32:57 +0100 Subject: counter: stm32-timer-cnt: rename quadrature signal Drop the Quadrature convention in the signal name. On stm32-timer: - Quadrature A signal corresponds to timer input ch1, hence "Channel 1" - Quadrature B signal corresponds to timer input ch2, hence "Channel 2". So name these signals after their channel. I suspect it referred to the (unique) quadrature counter support earlier, but the physical input really is CH1/CH2. This will be easier to support other counter modes. Reviewed-by: William Breathitt Gray Signed-off-by: Fabrice Gasnier Link: https://lore.kernel.org/r/20240307133306.383045-2-fabrice.gasnier@foss.st.com Signed-off-by: William Breathitt Gray --- drivers/counter/stm32-timer-cnt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/counter/stm32-timer-cnt.c b/drivers/counter/stm32-timer-cnt.c index 6206d2dc3d47..36d812ddf162 100644 --- a/drivers/counter/stm32-timer-cnt.c +++ b/drivers/counter/stm32-timer-cnt.c @@ -279,11 +279,11 @@ static const struct counter_ops stm32_timer_cnt_ops = { static struct counter_signal stm32_signals[] = { { .id = 0, - .name = "Channel 1 Quadrature A" + .name = "Channel 1" }, { .id = 1, - .name = "Channel 1 Quadrature B" + .name = "Channel 2" } }; -- cgit v1.2.3-59-g8ed1b From 752923ccfd988401c254c3d63632e87b33835da5 Mon Sep 17 00:00:00 2001 From: Fabrice Gasnier Date: Thu, 7 Mar 2024 14:32:58 +0100 Subject: counter: stm32-timer-cnt: rename counter The STM32 timer may count on various sources or channels. The counter isn't specifically counting on channe1 1. So rename it to avoid a confusion. Reviewed-by: William Breathitt Gray Signed-off-by: Fabrice Gasnier Link: https://lore.kernel.org/r/20240307133306.383045-3-fabrice.gasnier@foss.st.com Signed-off-by: William Breathitt Gray --- drivers/counter/stm32-timer-cnt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/counter/stm32-timer-cnt.c b/drivers/counter/stm32-timer-cnt.c index 36d812ddf162..668e9d1061d3 100644 --- a/drivers/counter/stm32-timer-cnt.c +++ b/drivers/counter/stm32-timer-cnt.c @@ -302,7 +302,7 @@ static struct counter_synapse stm32_count_synapses[] = { static struct counter_count stm32_counts = { .id = 0, - .name = "Channel 1 Count", + .name = "STM32 Timer Counter", .functions_list = stm32_count_functions, .num_functions = ARRAY_SIZE(stm32_count_functions), .synapses = stm32_count_synapses, -- cgit v1.2.3-59-g8ed1b From 5679d5f76ca781c46212db3e274e610aeea62af9 Mon Sep 17 00:00:00 2001 From: Fabrice Gasnier Date: Thu, 7 Mar 2024 14:32:59 +0100 Subject: counter: stm32-timer-cnt: adopt signal definitions Adopt signals definitions to ease later signals additions. There are no intended functional changes here. Reviewed-by: William Breathitt Gray Signed-off-by: Fabrice Gasnier Link: https://lore.kernel.org/r/20240307133306.383045-4-fabrice.gasnier@foss.st.com Signed-off-by: William Breathitt Gray --- drivers/counter/stm32-timer-cnt.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/counter/stm32-timer-cnt.c b/drivers/counter/stm32-timer-cnt.c index 668e9d1061d3..c34747d7857e 100644 --- a/drivers/counter/stm32-timer-cnt.c +++ b/drivers/counter/stm32-timer-cnt.c @@ -21,6 +21,9 @@ #define TIM_CCER_MASK (TIM_CCER_CC1P | TIM_CCER_CC1NP | \ TIM_CCER_CC2P | TIM_CCER_CC2NP) +#define STM32_CH1_SIG 0 +#define STM32_CH2_SIG 1 + struct stm32_timer_regs { u32 cr1; u32 cnt; @@ -247,14 +250,14 @@ static int stm32_action_read(struct counter_device *counter, return 0; case COUNTER_FUNCTION_QUADRATURE_X2_A: /* counts up/down on TI1FP1 edge depending on TI2FP2 level */ - if (synapse->signal->id == count->synapses[0].signal->id) + if (synapse->signal->id == STM32_CH1_SIG) *action = COUNTER_SYNAPSE_ACTION_BOTH_EDGES; else *action = COUNTER_SYNAPSE_ACTION_NONE; return 0; case COUNTER_FUNCTION_QUADRATURE_X2_B: /* counts up/down on TI2FP2 edge depending on TI1FP1 level */ - if (synapse->signal->id == count->synapses[1].signal->id) + if (synapse->signal->id == STM32_CH2_SIG) *action = COUNTER_SYNAPSE_ACTION_BOTH_EDGES; else *action = COUNTER_SYNAPSE_ACTION_NONE; @@ -278,11 +281,11 @@ static const struct counter_ops stm32_timer_cnt_ops = { static struct counter_signal stm32_signals[] = { { - .id = 0, + .id = STM32_CH1_SIG, .name = "Channel 1" }, { - .id = 1, + .id = STM32_CH2_SIG, .name = "Channel 2" } }; @@ -291,12 +294,12 @@ static struct counter_synapse stm32_count_synapses[] = { { .actions_list = stm32_synapse_actions, .num_actions = ARRAY_SIZE(stm32_synapse_actions), - .signal = &stm32_signals[0] + .signal = &stm32_signals[STM32_CH1_SIG] }, { .actions_list = stm32_synapse_actions, .num_actions = ARRAY_SIZE(stm32_synapse_actions), - .signal = &stm32_signals[1] + .signal = &stm32_signals[STM32_CH2_SIG] } }; -- cgit v1.2.3-59-g8ed1b From 7a6c69f2be82e60a57d75ef9ad29fac0aa3d619e Mon Sep 17 00:00:00 2001 From: Fabrice Gasnier Date: Thu, 7 Mar 2024 14:33:00 +0100 Subject: counter: stm32-timer-cnt: introduce clock signal Introduce the internal clock signal, used to count when in simple rising function. Also add the "frequency" extension to the clock signal. With this patch, signal action reports a consistent state when "increase" function is used, and the counting frequency: $ echo increase > function $ grep -H "" signal*_action signal0_action:none signal1_action:none signal2_action:rising edge $ echo 1 > enable $ cat count 25425 $ cat count 44439 $ cat ../signal2/frequency 208877930 Signed-off-by: Fabrice Gasnier Link: https://lore.kernel.org/r/20240307133306.383045-5-fabrice.gasnier@foss.st.com Signed-off-by: William Breathitt Gray --- drivers/counter/stm32-timer-cnt.c | 53 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 49 insertions(+), 4 deletions(-) diff --git a/drivers/counter/stm32-timer-cnt.c b/drivers/counter/stm32-timer-cnt.c index c34747d7857e..65b447b42e75 100644 --- a/drivers/counter/stm32-timer-cnt.c +++ b/drivers/counter/stm32-timer-cnt.c @@ -23,6 +23,7 @@ #define STM32_CH1_SIG 0 #define STM32_CH2_SIG 1 +#define STM32_CLOCK_SIG 2 struct stm32_timer_regs { u32 cr1; @@ -226,6 +227,10 @@ static struct counter_comp stm32_count_ext[] = { stm32_count_ceiling_write), }; +static const enum counter_synapse_action stm32_clock_synapse_actions[] = { + COUNTER_SYNAPSE_ACTION_RISING_EDGE, +}; + static const enum counter_synapse_action stm32_synapse_actions[] = { COUNTER_SYNAPSE_ACTION_NONE, COUNTER_SYNAPSE_ACTION_BOTH_EDGES @@ -246,7 +251,10 @@ static int stm32_action_read(struct counter_device *counter, switch (function) { case COUNTER_FUNCTION_INCREASE: /* counts on internal clock when CEN=1 */ - *action = COUNTER_SYNAPSE_ACTION_NONE; + if (synapse->signal->id == STM32_CLOCK_SIG) + *action = COUNTER_SYNAPSE_ACTION_RISING_EDGE; + else + *action = COUNTER_SYNAPSE_ACTION_NONE; return 0; case COUNTER_FUNCTION_QUADRATURE_X2_A: /* counts up/down on TI1FP1 edge depending on TI2FP2 level */ @@ -264,7 +272,10 @@ static int stm32_action_read(struct counter_device *counter, return 0; case COUNTER_FUNCTION_QUADRATURE_X4: /* counts up/down on both TI1FP1 and TI2FP2 edges */ - *action = COUNTER_SYNAPSE_ACTION_BOTH_EDGES; + if (synapse->signal->id == STM32_CH1_SIG || synapse->signal->id == STM32_CH2_SIG) + *action = COUNTER_SYNAPSE_ACTION_BOTH_EDGES; + else + *action = COUNTER_SYNAPSE_ACTION_NONE; return 0; default: return -EINVAL; @@ -279,7 +290,30 @@ static const struct counter_ops stm32_timer_cnt_ops = { .action_read = stm32_action_read, }; +static int stm32_count_clk_get_freq(struct counter_device *counter, + struct counter_signal *signal, u64 *freq) +{ + struct stm32_timer_cnt *const priv = counter_priv(counter); + + *freq = clk_get_rate(priv->clk); + + return 0; +} + +static struct counter_comp stm32_count_clock_ext[] = { + COUNTER_COMP_FREQUENCY(stm32_count_clk_get_freq), +}; + static struct counter_signal stm32_signals[] = { + /* + * Need to declare all the signals as a static array, and keep the signals order here, + * even if they're unused or unexisting on some timer instances. It's an abstraction, + * e.g. high level view of the counter features. + * + * Userspace programs may rely on signal0 to be "Channel 1", signal1 to be "Channel 2", + * and so on. When a signal is unexisting, the COUNTER_SYNAPSE_ACTION_NONE can be used, + * to indicate that a signal doesn't affect the counter. + */ { .id = STM32_CH1_SIG, .name = "Channel 1" @@ -287,7 +321,13 @@ static struct counter_signal stm32_signals[] = { { .id = STM32_CH2_SIG, .name = "Channel 2" - } + }, + { + .id = STM32_CLOCK_SIG, + .name = "Clock", + .ext = stm32_count_clock_ext, + .num_ext = ARRAY_SIZE(stm32_count_clock_ext), + }, }; static struct counter_synapse stm32_count_synapses[] = { @@ -300,7 +340,12 @@ static struct counter_synapse stm32_count_synapses[] = { .actions_list = stm32_synapse_actions, .num_actions = ARRAY_SIZE(stm32_synapse_actions), .signal = &stm32_signals[STM32_CH2_SIG] - } + }, + { + .actions_list = stm32_clock_synapse_actions, + .num_actions = ARRAY_SIZE(stm32_clock_synapse_actions), + .signal = &stm32_signals[STM32_CLOCK_SIG] + }, }; static struct counter_count stm32_counts = { -- cgit v1.2.3-59-g8ed1b From b73d03b3474212028f5b41675b0f30273c7ffa58 Mon Sep 17 00:00:00 2001 From: Fabrice Gasnier Date: Thu, 7 Mar 2024 14:33:01 +0100 Subject: counter: stm32-timer-cnt: add counter prescaler extension There's a prescaler in between the selected input signal used for counting (CK_PSC), and the counter input (CK_CNT). So add the "prescaler" extension to the counter. Reviewed-by: William Breathitt Gray Signed-off-by: Fabrice Gasnier Link: https://lore.kernel.org/r/20240307133306.383045-6-fabrice.gasnier@foss.st.com Signed-off-by: William Breathitt Gray --- drivers/counter/stm32-timer-cnt.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/drivers/counter/stm32-timer-cnt.c b/drivers/counter/stm32-timer-cnt.c index 65b447b42e75..b969d550e90a 100644 --- a/drivers/counter/stm32-timer-cnt.c +++ b/drivers/counter/stm32-timer-cnt.c @@ -220,11 +220,40 @@ static int stm32_count_enable_write(struct counter_device *counter, return 0; } +static int stm32_count_prescaler_read(struct counter_device *counter, + struct counter_count *count, u64 *prescaler) +{ + struct stm32_timer_cnt *const priv = counter_priv(counter); + u32 psc; + + regmap_read(priv->regmap, TIM_PSC, &psc); + + *prescaler = psc + 1; + + return 0; +} + +static int stm32_count_prescaler_write(struct counter_device *counter, + struct counter_count *count, u64 prescaler) +{ + struct stm32_timer_cnt *const priv = counter_priv(counter); + u32 psc; + + if (!prescaler || prescaler > MAX_TIM_PSC + 1) + return -ERANGE; + + psc = prescaler - 1; + + return regmap_write(priv->regmap, TIM_PSC, psc); +} + static struct counter_comp stm32_count_ext[] = { COUNTER_COMP_DIRECTION(stm32_count_direction_read), COUNTER_COMP_ENABLE(stm32_count_enable_read, stm32_count_enable_write), COUNTER_COMP_CEILING(stm32_count_ceiling_read, stm32_count_ceiling_write), + COUNTER_COMP_COUNT_U64("prescaler", stm32_count_prescaler_read, + stm32_count_prescaler_write), }; static const enum counter_synapse_action stm32_clock_synapse_actions[] = { -- cgit v1.2.3-59-g8ed1b From 29646ee33cc34b322578e923a121a3ba5eedc22b Mon Sep 17 00:00:00 2001 From: Fabrice Gasnier Date: Thu, 7 Mar 2024 14:33:02 +0100 Subject: counter: stm32-timer-cnt: add checks on quadrature encoder capability This is a precursor patch to support capture channels on all possible channels and stm32 timer types. Original driver was intended to be used only as quadrature encoder and simple counter on internal clock. So, add a check on encoder capability, so the driver may be probed for timer instances without encoder feature. This way, all timers may be used as simple counter on internal clock, starting from here. Encoder capability is retrieved by using the timer index (originally in stm32-timer-trigger driver and dt-bindings). The need to keep backward compatibility with existing device tree lead to parse aside trigger node. Reviewed-by: William Breathitt Gray Signed-off-by: Fabrice Gasnier Link: https://lore.kernel.org/r/20240307133306.383045-7-fabrice.gasnier@foss.st.com Signed-off-by: William Breathitt Gray --- drivers/counter/stm32-timer-cnt.c | 55 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/drivers/counter/stm32-timer-cnt.c b/drivers/counter/stm32-timer-cnt.c index b969d550e90a..17f87ace450d 100644 --- a/drivers/counter/stm32-timer-cnt.c +++ b/drivers/counter/stm32-timer-cnt.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -38,6 +39,7 @@ struct stm32_timer_cnt { u32 max_arr; bool enabled; struct stm32_timer_regs bak; + bool has_encoder; }; static const enum counter_function stm32_count_functions[] = { @@ -111,12 +113,18 @@ static int stm32_count_function_write(struct counter_device *counter, sms = TIM_SMCR_SMS_SLAVE_MODE_DISABLED; break; case COUNTER_FUNCTION_QUADRATURE_X2_A: + if (!priv->has_encoder) + return -EOPNOTSUPP; sms = TIM_SMCR_SMS_ENCODER_MODE_1; break; case COUNTER_FUNCTION_QUADRATURE_X2_B: + if (!priv->has_encoder) + return -EOPNOTSUPP; sms = TIM_SMCR_SMS_ENCODER_MODE_2; break; case COUNTER_FUNCTION_QUADRATURE_X4: + if (!priv->has_encoder) + return -EOPNOTSUPP; sms = TIM_SMCR_SMS_ENCODER_MODE_3; break; default: @@ -388,6 +396,49 @@ static struct counter_count stm32_counts = { .num_ext = ARRAY_SIZE(stm32_count_ext) }; +/* encoder supported on TIM1 TIM2 TIM3 TIM4 TIM5 TIM8 */ +#define STM32_TIM_ENCODER_SUPPORTED (BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(7)) + +static const char * const stm32_timer_trigger_compat[] = { + "st,stm32-timer-trigger", + "st,stm32h7-timer-trigger", +}; + +static int stm32_timer_cnt_probe_encoder(struct device *dev, + struct stm32_timer_cnt *priv) +{ + struct device *parent = dev->parent; + struct device_node *tnode = NULL, *pnode = parent->of_node; + int i, ret; + u32 idx; + + /* + * Need to retrieve the trigger node index from DT, to be able + * to determine if the counter supports encoder mode. It also + * enforce backward compatibility, and allow to support other + * counter modes in this driver (when the timer doesn't support + * encoder). + */ + for (i = 0; i < ARRAY_SIZE(stm32_timer_trigger_compat) && !tnode; i++) + tnode = of_get_compatible_child(pnode, stm32_timer_trigger_compat[i]); + if (!tnode) { + dev_err(dev, "Can't find trigger node\n"); + return -ENODATA; + } + + ret = of_property_read_u32(tnode, "reg", &idx); + if (ret) { + dev_err(dev, "Can't get index (%d)\n", ret); + return ret; + } + + priv->has_encoder = !!(STM32_TIM_ENCODER_SUPPORTED & BIT(idx)); + + dev_dbg(dev, "encoder support: %s\n", priv->has_encoder ? "yes" : "no"); + + return 0; +} + static int stm32_timer_cnt_probe(struct platform_device *pdev) { struct stm32_timers *ddata = dev_get_drvdata(pdev->dev.parent); @@ -409,6 +460,10 @@ static int stm32_timer_cnt_probe(struct platform_device *pdev) priv->clk = ddata->clk; priv->max_arr = ddata->max_arr; + ret = stm32_timer_cnt_probe_encoder(dev, priv); + if (ret) + return ret; + counter->name = dev_name(dev); counter->parent = dev; counter->ops = &stm32_timer_cnt_ops; -- cgit v1.2.3-59-g8ed1b From efec660d78f06cd1101b3300ebfef4918cc0f63f Mon Sep 17 00:00:00 2001 From: Fabrice Gasnier Date: Thu, 7 Mar 2024 14:33:03 +0100 Subject: counter: stm32-timer-cnt: introduce channels Simply add channels 3 and 4 that can be used for capture. Statically add them, despite some timers doesn't have them. Rather rely on stm32_action_read that will report "none" action for these currently. Reviewed-by: William Breathitt Gray Signed-off-by: Fabrice Gasnier Link: https://lore.kernel.org/r/20240307133306.383045-8-fabrice.gasnier@foss.st.com Signed-off-by: William Breathitt Gray --- drivers/counter/stm32-timer-cnt.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/drivers/counter/stm32-timer-cnt.c b/drivers/counter/stm32-timer-cnt.c index 17f87ace450d..f63d0c3e3f22 100644 --- a/drivers/counter/stm32-timer-cnt.c +++ b/drivers/counter/stm32-timer-cnt.c @@ -25,6 +25,8 @@ #define STM32_CH1_SIG 0 #define STM32_CH2_SIG 1 #define STM32_CLOCK_SIG 2 +#define STM32_CH3_SIG 3 +#define STM32_CH4_SIG 4 struct stm32_timer_regs { u32 cr1; @@ -365,6 +367,14 @@ static struct counter_signal stm32_signals[] = { .ext = stm32_count_clock_ext, .num_ext = ARRAY_SIZE(stm32_count_clock_ext), }, + { + .id = STM32_CH3_SIG, + .name = "Channel 3" + }, + { + .id = STM32_CH4_SIG, + .name = "Channel 4" + }, }; static struct counter_synapse stm32_count_synapses[] = { @@ -383,6 +393,16 @@ static struct counter_synapse stm32_count_synapses[] = { .num_actions = ARRAY_SIZE(stm32_clock_synapse_actions), .signal = &stm32_signals[STM32_CLOCK_SIG] }, + { + .actions_list = stm32_synapse_actions, + .num_actions = ARRAY_SIZE(stm32_synapse_actions), + .signal = &stm32_signals[STM32_CH3_SIG] + }, + { + .actions_list = stm32_synapse_actions, + .num_actions = ARRAY_SIZE(stm32_synapse_actions), + .signal = &stm32_signals[STM32_CH4_SIG] + }, }; static struct counter_count stm32_counts = { -- cgit v1.2.3-59-g8ed1b From f7630270b67836bedc518e96fb4c64b11fe3fb5e Mon Sep 17 00:00:00 2001 From: Fabrice Gasnier Date: Thu, 7 Mar 2024 14:33:04 +0100 Subject: counter: stm32-timer-cnt: probe number of channels from registers Probe the number of capture compare channels, by writing CCER register bits and read them back. Take care to restore the register original value. This is a precursor patch to support capture channels. Reviewed-by: William Breathitt Gray Signed-off-by: Fabrice Gasnier Link: https://lore.kernel.org/r/20240307133306.383045-9-fabrice.gasnier@foss.st.com Signed-off-by: William Breathitt Gray --- drivers/counter/stm32-timer-cnt.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/counter/stm32-timer-cnt.c b/drivers/counter/stm32-timer-cnt.c index f63d0c3e3f22..e1c0a502b74c 100644 --- a/drivers/counter/stm32-timer-cnt.c +++ b/drivers/counter/stm32-timer-cnt.c @@ -42,6 +42,7 @@ struct stm32_timer_cnt { bool enabled; struct stm32_timer_regs bak; bool has_encoder; + unsigned int nchannels; }; static const enum counter_function stm32_count_functions[] = { @@ -416,6 +417,20 @@ static struct counter_count stm32_counts = { .num_ext = ARRAY_SIZE(stm32_count_ext) }; +static void stm32_timer_cnt_detect_channels(struct device *dev, + struct stm32_timer_cnt *priv) +{ + u32 ccer, ccer_backup; + + regmap_read(priv->regmap, TIM_CCER, &ccer_backup); + regmap_set_bits(priv->regmap, TIM_CCER, TIM_CCER_CCXE); + regmap_read(priv->regmap, TIM_CCER, &ccer); + regmap_write(priv->regmap, TIM_CCER, ccer_backup); + priv->nchannels = hweight32(ccer & TIM_CCER_CCXE); + + dev_dbg(dev, "has %d cc channels\n", priv->nchannels); +} + /* encoder supported on TIM1 TIM2 TIM3 TIM4 TIM5 TIM8 */ #define STM32_TIM_ENCODER_SUPPORTED (BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(7)) @@ -484,6 +499,8 @@ static int stm32_timer_cnt_probe(struct platform_device *pdev) if (ret) return ret; + stm32_timer_cnt_detect_channels(dev, priv); + counter->name = dev_name(dev); counter->parent = dev; counter->ops = &stm32_timer_cnt_ops; -- cgit v1.2.3-59-g8ed1b From 2c70ccd45985f1e458f9785fc8cf9b8c48e3807f Mon Sep 17 00:00:00 2001 From: Fabrice Gasnier Date: Thu, 7 Mar 2024 14:33:05 +0100 Subject: counter: stm32-timer-cnt: add support for overflow events Add support overflow events. Also add the related validation and configuration routine. Register and enable interrupts to push events. STM32 Timers can have either 1 global interrupt, or 4 dedicated interrupt lines. Request only the necessary interrupt, e.g. either global interrupt that can report all event types, or update interrupt only for overflow event. Reviewed-by: William Breathitt Gray Signed-off-by: Fabrice Gasnier Link: https://lore.kernel.org/r/20240307133306.383045-10-fabrice.gasnier@foss.st.com Signed-off-by: William Breathitt Gray --- drivers/counter/stm32-timer-cnt.c | 138 +++++++++++++++++++++++++++++++++++++- 1 file changed, 137 insertions(+), 1 deletion(-) diff --git a/drivers/counter/stm32-timer-cnt.c b/drivers/counter/stm32-timer-cnt.c index e1c0a502b74c..9fcafec682b7 100644 --- a/drivers/counter/stm32-timer-cnt.c +++ b/drivers/counter/stm32-timer-cnt.c @@ -8,6 +8,7 @@ * */ #include +#include #include #include #include @@ -43,6 +44,9 @@ struct stm32_timer_cnt { struct stm32_timer_regs bak; bool has_encoder; unsigned int nchannels; + unsigned int nr_irqs; + spinlock_t lock; /* protects nb_ovf */ + u64 nb_ovf; }; static const enum counter_function stm32_count_functions[] = { @@ -258,6 +262,32 @@ static int stm32_count_prescaler_write(struct counter_device *counter, return regmap_write(priv->regmap, TIM_PSC, psc); } +static int stm32_count_nb_ovf_read(struct counter_device *counter, + struct counter_count *count, u64 *val) +{ + struct stm32_timer_cnt *const priv = counter_priv(counter); + unsigned long irqflags; + + spin_lock_irqsave(&priv->lock, irqflags); + *val = priv->nb_ovf; + spin_unlock_irqrestore(&priv->lock, irqflags); + + return 0; +} + +static int stm32_count_nb_ovf_write(struct counter_device *counter, + struct counter_count *count, u64 val) +{ + struct stm32_timer_cnt *const priv = counter_priv(counter); + unsigned long irqflags; + + spin_lock_irqsave(&priv->lock, irqflags); + priv->nb_ovf = val; + spin_unlock_irqrestore(&priv->lock, irqflags); + + return 0; +} + static struct counter_comp stm32_count_ext[] = { COUNTER_COMP_DIRECTION(stm32_count_direction_read), COUNTER_COMP_ENABLE(stm32_count_enable_read, stm32_count_enable_write), @@ -265,6 +295,7 @@ static struct counter_comp stm32_count_ext[] = { stm32_count_ceiling_write), COUNTER_COMP_COUNT_U64("prescaler", stm32_count_prescaler_read, stm32_count_prescaler_write), + COUNTER_COMP_COUNT_U64("num_overflows", stm32_count_nb_ovf_read, stm32_count_nb_ovf_write), }; static const enum counter_synapse_action stm32_clock_synapse_actions[] = { @@ -322,12 +353,57 @@ static int stm32_action_read(struct counter_device *counter, } } +static int stm32_count_events_configure(struct counter_device *counter) +{ + struct stm32_timer_cnt *const priv = counter_priv(counter); + struct counter_event_node *event_node; + u32 dier = 0; + + list_for_each_entry(event_node, &counter->events_list, l) { + switch (event_node->event) { + case COUNTER_EVENT_OVERFLOW_UNDERFLOW: + /* first clear possibly latched UIF before enabling */ + if (!regmap_test_bits(priv->regmap, TIM_DIER, TIM_DIER_UIE)) + regmap_write(priv->regmap, TIM_SR, (u32)~TIM_SR_UIF); + dier |= TIM_DIER_UIE; + break; + default: + /* should never reach this path */ + return -EINVAL; + } + } + + /* Enable / disable all events at once, from events_list, so write all DIER bits */ + regmap_write(priv->regmap, TIM_DIER, dier); + + return 0; +} + +static int stm32_count_watch_validate(struct counter_device *counter, + const struct counter_watch *watch) +{ + struct stm32_timer_cnt *const priv = counter_priv(counter); + + /* Interrupts are optional */ + if (!priv->nr_irqs) + return -EOPNOTSUPP; + + switch (watch->event) { + case COUNTER_EVENT_OVERFLOW_UNDERFLOW: + return 0; + default: + return -EINVAL; + } +} + static const struct counter_ops stm32_timer_cnt_ops = { .count_read = stm32_count_read, .count_write = stm32_count_write, .function_read = stm32_count_function_read, .function_write = stm32_count_function_write, .action_read = stm32_action_read, + .events_configure = stm32_count_events_configure, + .watch_validate = stm32_count_watch_validate, }; static int stm32_count_clk_get_freq(struct counter_device *counter, @@ -417,6 +493,37 @@ static struct counter_count stm32_counts = { .num_ext = ARRAY_SIZE(stm32_count_ext) }; +static irqreturn_t stm32_timer_cnt_isr(int irq, void *ptr) +{ + struct counter_device *counter = ptr; + struct stm32_timer_cnt *const priv = counter_priv(counter); + u32 clr = GENMASK(31, 0); /* SR flags can be cleared by writing 0 (wr 1 has no effect) */ + u32 sr, dier; + + regmap_read(priv->regmap, TIM_SR, &sr); + regmap_read(priv->regmap, TIM_DIER, &dier); + /* + * Some status bits in SR don't match with the enable bits in DIER. Only take care of + * the possibly enabled bits in DIER (that matches in between SR and DIER). + */ + dier &= TIM_DIER_UIE; + sr &= dier; + + if (sr & TIM_SR_UIF) { + spin_lock(&priv->lock); + priv->nb_ovf++; + spin_unlock(&priv->lock); + counter_push_event(counter, COUNTER_EVENT_OVERFLOW_UNDERFLOW, 0); + dev_dbg(counter->parent, "COUNTER_EVENT_OVERFLOW_UNDERFLOW\n"); + /* SR flags can be cleared by writing 0, only clear relevant flag */ + clr &= ~TIM_SR_UIF; + } + + regmap_write(priv->regmap, TIM_SR, clr); + + return IRQ_HANDLED; +}; + static void stm32_timer_cnt_detect_channels(struct device *dev, struct stm32_timer_cnt *priv) { @@ -480,7 +587,7 @@ static int stm32_timer_cnt_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct stm32_timer_cnt *priv; struct counter_device *counter; - int ret; + int i, ret; if (IS_ERR_OR_NULL(ddata)) return -EINVAL; @@ -494,6 +601,7 @@ static int stm32_timer_cnt_probe(struct platform_device *pdev) priv->regmap = ddata->regmap; priv->clk = ddata->clk; priv->max_arr = ddata->max_arr; + priv->nr_irqs = ddata->nr_irqs; ret = stm32_timer_cnt_probe_encoder(dev, priv); if (ret) @@ -509,8 +617,36 @@ static int stm32_timer_cnt_probe(struct platform_device *pdev) counter->signals = stm32_signals; counter->num_signals = ARRAY_SIZE(stm32_signals); + spin_lock_init(&priv->lock); + platform_set_drvdata(pdev, priv); + /* STM32 Timers can have either 1 global, or 4 dedicated interrupts (optional) */ + if (priv->nr_irqs == 1) { + /* All events reported through the global interrupt */ + ret = devm_request_irq(&pdev->dev, ddata->irq[0], stm32_timer_cnt_isr, + 0, dev_name(dev), counter); + if (ret) { + dev_err(dev, "Failed to request irq %d (err %d)\n", + ddata->irq[0], ret); + return ret; + } + } else { + for (i = 0; i < priv->nr_irqs; i++) { + /* Only take care of update IRQ for overflow events */ + if (i != STM32_TIMERS_IRQ_UP) + continue; + + ret = devm_request_irq(&pdev->dev, ddata->irq[i], stm32_timer_cnt_isr, + 0, dev_name(dev), counter); + if (ret) { + dev_err(dev, "Failed to request irq %d (err %d)\n", + ddata->irq[i], ret); + return ret; + } + } + } + /* Reset input selector to its default input */ regmap_write(priv->regmap, TIM_TISEL, 0x0); -- cgit v1.2.3-59-g8ed1b From 1aed15275b7ce17b5ebdfc112a76e0d7165ed46b Mon Sep 17 00:00:00 2001 From: Fabrice Gasnier Date: Thu, 7 Mar 2024 14:33:06 +0100 Subject: counter: stm32-timer-cnt: add support for capture events Add support for capture events. Captured counter value for each channel can be retrieved through CCRx register. STM32 timers can have up to 4 capture channels (on input channel 1 to channel 4), hence need to check the number of channels before reading the capture data. The capture configuration is hard-coded to capture signals on both edges (non-inverted). Interrupts are used to report events independently for each channel. Reviewed-by: William Breathitt Gray Acked-by: Lee Jones Signed-off-by: Fabrice Gasnier Link: https://lore.kernel.org/r/20240307133306.383045-11-fabrice.gasnier@foss.st.com Signed-off-by: William Breathitt Gray --- drivers/counter/stm32-timer-cnt.c | 134 +++++++++++++++++++++++++++++++++++++- include/linux/mfd/stm32-timers.h | 13 ++++ 2 files changed, 144 insertions(+), 3 deletions(-) diff --git a/drivers/counter/stm32-timer-cnt.c b/drivers/counter/stm32-timer-cnt.c index 9fcafec682b7..0664ef969f79 100644 --- a/drivers/counter/stm32-timer-cnt.c +++ b/drivers/counter/stm32-timer-cnt.c @@ -262,6 +262,40 @@ static int stm32_count_prescaler_write(struct counter_device *counter, return regmap_write(priv->regmap, TIM_PSC, psc); } +static int stm32_count_cap_read(struct counter_device *counter, + struct counter_count *count, + size_t ch, u64 *cap) +{ + struct stm32_timer_cnt *const priv = counter_priv(counter); + u32 ccrx; + + if (ch >= priv->nchannels) + return -EOPNOTSUPP; + + switch (ch) { + case 0: + regmap_read(priv->regmap, TIM_CCR1, &ccrx); + break; + case 1: + regmap_read(priv->regmap, TIM_CCR2, &ccrx); + break; + case 2: + regmap_read(priv->regmap, TIM_CCR3, &ccrx); + break; + case 3: + regmap_read(priv->regmap, TIM_CCR4, &ccrx); + break; + default: + return -EINVAL; + } + + dev_dbg(counter->parent, "CCR%zu: 0x%08x\n", ch + 1, ccrx); + + *cap = ccrx; + + return 0; +} + static int stm32_count_nb_ovf_read(struct counter_device *counter, struct counter_count *count, u64 *val) { @@ -288,6 +322,8 @@ static int stm32_count_nb_ovf_write(struct counter_device *counter, return 0; } +static DEFINE_COUNTER_ARRAY_CAPTURE(stm32_count_cap_array, 4); + static struct counter_comp stm32_count_ext[] = { COUNTER_COMP_DIRECTION(stm32_count_direction_read), COUNTER_COMP_ENABLE(stm32_count_enable_read, stm32_count_enable_write), @@ -295,6 +331,7 @@ static struct counter_comp stm32_count_ext[] = { stm32_count_ceiling_write), COUNTER_COMP_COUNT_U64("prescaler", stm32_count_prescaler_read, stm32_count_prescaler_write), + COUNTER_COMP_ARRAY_CAPTURE(stm32_count_cap_read, NULL, stm32_count_cap_array), COUNTER_COMP_COUNT_U64("num_overflows", stm32_count_nb_ovf_read, stm32_count_nb_ovf_write), }; @@ -353,11 +390,68 @@ static int stm32_action_read(struct counter_device *counter, } } +struct stm32_count_cc_regs { + u32 ccmr_reg; + u32 ccmr_mask; + u32 ccmr_bits; + u32 ccer_bits; +}; + +static const struct stm32_count_cc_regs stm32_cc[] = { + { TIM_CCMR1, TIM_CCMR_CC1S, TIM_CCMR_CC1S_TI1, + TIM_CCER_CC1E | TIM_CCER_CC1P | TIM_CCER_CC1NP }, + { TIM_CCMR1, TIM_CCMR_CC2S, TIM_CCMR_CC2S_TI2, + TIM_CCER_CC2E | TIM_CCER_CC2P | TIM_CCER_CC2NP }, + { TIM_CCMR2, TIM_CCMR_CC3S, TIM_CCMR_CC3S_TI3, + TIM_CCER_CC3E | TIM_CCER_CC3P | TIM_CCER_CC3NP }, + { TIM_CCMR2, TIM_CCMR_CC4S, TIM_CCMR_CC4S_TI4, + TIM_CCER_CC4E | TIM_CCER_CC4P | TIM_CCER_CC4NP }, +}; + +static int stm32_count_capture_configure(struct counter_device *counter, unsigned int ch, + bool enable) +{ + struct stm32_timer_cnt *const priv = counter_priv(counter); + const struct stm32_count_cc_regs *cc; + u32 ccmr, ccer; + + if (ch >= ARRAY_SIZE(stm32_cc) || ch >= priv->nchannels) { + dev_err(counter->parent, "invalid ch: %d\n", ch); + return -EINVAL; + } + + cc = &stm32_cc[ch]; + + /* + * configure channel in input capture mode, map channel 1 on TI1, channel2 on TI2... + * Select both edges / non-inverted to trigger a capture. + */ + if (enable) { + /* first clear possibly latched capture flag upon enabling */ + if (!regmap_test_bits(priv->regmap, TIM_CCER, cc->ccer_bits)) + regmap_write(priv->regmap, TIM_SR, ~TIM_SR_CC_IF(ch)); + regmap_update_bits(priv->regmap, cc->ccmr_reg, cc->ccmr_mask, + cc->ccmr_bits); + regmap_set_bits(priv->regmap, TIM_CCER, cc->ccer_bits); + } else { + regmap_clear_bits(priv->regmap, TIM_CCER, cc->ccer_bits); + regmap_clear_bits(priv->regmap, cc->ccmr_reg, cc->ccmr_mask); + } + + regmap_read(priv->regmap, cc->ccmr_reg, &ccmr); + regmap_read(priv->regmap, TIM_CCER, &ccer); + dev_dbg(counter->parent, "%s(%s) ch%d 0x%08x 0x%08x\n", __func__, enable ? "ena" : "dis", + ch, ccmr, ccer); + + return 0; +} + static int stm32_count_events_configure(struct counter_device *counter) { struct stm32_timer_cnt *const priv = counter_priv(counter); struct counter_event_node *event_node; u32 dier = 0; + int i, ret; list_for_each_entry(event_node, &counter->events_list, l) { switch (event_node->event) { @@ -367,6 +461,12 @@ static int stm32_count_events_configure(struct counter_device *counter) regmap_write(priv->regmap, TIM_SR, (u32)~TIM_SR_UIF); dier |= TIM_DIER_UIE; break; + case COUNTER_EVENT_CAPTURE: + ret = stm32_count_capture_configure(counter, event_node->channel, true); + if (ret) + return ret; + dier |= TIM_DIER_CC_IE(event_node->channel); + break; default: /* should never reach this path */ return -EINVAL; @@ -376,6 +476,15 @@ static int stm32_count_events_configure(struct counter_device *counter) /* Enable / disable all events at once, from events_list, so write all DIER bits */ regmap_write(priv->regmap, TIM_DIER, dier); + /* check for disabled capture events */ + for (i = 0 ; i < priv->nchannels; i++) { + if (!(dier & TIM_DIER_CC_IE(i))) { + ret = stm32_count_capture_configure(counter, i, false); + if (ret) + return ret; + } + } + return 0; } @@ -389,6 +498,12 @@ static int stm32_count_watch_validate(struct counter_device *counter, return -EOPNOTSUPP; switch (watch->event) { + case COUNTER_EVENT_CAPTURE: + if (watch->channel >= priv->nchannels) { + dev_err(counter->parent, "Invalid channel %d\n", watch->channel); + return -EINVAL; + } + return 0; case COUNTER_EVENT_OVERFLOW_UNDERFLOW: return 0; default: @@ -499,6 +614,7 @@ static irqreturn_t stm32_timer_cnt_isr(int irq, void *ptr) struct stm32_timer_cnt *const priv = counter_priv(counter); u32 clr = GENMASK(31, 0); /* SR flags can be cleared by writing 0 (wr 1 has no effect) */ u32 sr, dier; + int i; regmap_read(priv->regmap, TIM_SR, &sr); regmap_read(priv->regmap, TIM_DIER, &dier); @@ -506,7 +622,7 @@ static irqreturn_t stm32_timer_cnt_isr(int irq, void *ptr) * Some status bits in SR don't match with the enable bits in DIER. Only take care of * the possibly enabled bits in DIER (that matches in between SR and DIER). */ - dier &= TIM_DIER_UIE; + dier &= (TIM_DIER_UIE | TIM_DIER_CC1IE | TIM_DIER_CC2IE | TIM_DIER_CC3IE | TIM_DIER_CC4IE); sr &= dier; if (sr & TIM_SR_UIF) { @@ -519,6 +635,15 @@ static irqreturn_t stm32_timer_cnt_isr(int irq, void *ptr) clr &= ~TIM_SR_UIF; } + /* Check capture events */ + for (i = 0 ; i < priv->nchannels; i++) { + if (sr & TIM_SR_CC_IF(i)) { + counter_push_event(counter, COUNTER_EVENT_CAPTURE, i); + clr &= ~TIM_SR_CC_IF(i); + dev_dbg(counter->parent, "COUNTER_EVENT_CAPTURE, %d\n", i); + } + } + regmap_write(priv->regmap, TIM_SR, clr); return IRQ_HANDLED; @@ -633,8 +758,11 @@ static int stm32_timer_cnt_probe(struct platform_device *pdev) } } else { for (i = 0; i < priv->nr_irqs; i++) { - /* Only take care of update IRQ for overflow events */ - if (i != STM32_TIMERS_IRQ_UP) + /* + * Only take care of update IRQ for overflow events, and cc for + * capture events. + */ + if (i != STM32_TIMERS_IRQ_UP && i != STM32_TIMERS_IRQ_CC) continue; ret = devm_request_irq(&pdev->dev, ddata->irq[i], stm32_timer_cnt_isr, diff --git a/include/linux/mfd/stm32-timers.h b/include/linux/mfd/stm32-timers.h index ca35af30745f..9eb17481b07f 100644 --- a/include/linux/mfd/stm32-timers.h +++ b/include/linux/mfd/stm32-timers.h @@ -41,6 +41,11 @@ #define TIM_SMCR_SMS (BIT(0) | BIT(1) | BIT(2)) /* Slave mode selection */ #define TIM_SMCR_TS (BIT(4) | BIT(5) | BIT(6)) /* Trigger selection */ #define TIM_DIER_UIE BIT(0) /* Update interrupt */ +#define TIM_DIER_CC1IE BIT(1) /* CC1 Interrupt Enable */ +#define TIM_DIER_CC2IE BIT(2) /* CC2 Interrupt Enable */ +#define TIM_DIER_CC3IE BIT(3) /* CC3 Interrupt Enable */ +#define TIM_DIER_CC4IE BIT(4) /* CC4 Interrupt Enable */ +#define TIM_DIER_CC_IE(x) BIT((x) + 1) /* CC1, CC2, CC3, CC4 interrupt enable */ #define TIM_DIER_UDE BIT(8) /* Update DMA request Enable */ #define TIM_DIER_CC1DE BIT(9) /* CC1 DMA request Enable */ #define TIM_DIER_CC2DE BIT(10) /* CC2 DMA request Enable */ @@ -49,6 +54,7 @@ #define TIM_DIER_COMDE BIT(13) /* COM DMA request Enable */ #define TIM_DIER_TDE BIT(14) /* Trigger DMA request Enable */ #define TIM_SR_UIF BIT(0) /* Update interrupt flag */ +#define TIM_SR_CC_IF(x) BIT((x) + 1) /* CC1, CC2, CC3, CC4 interrupt flag */ #define TIM_EGR_UG BIT(0) /* Update Generation */ #define TIM_CCMR_PE BIT(3) /* Channel Preload Enable */ #define TIM_CCMR_M1 (BIT(6) | BIT(5)) /* Channel PWM Mode 1 */ @@ -60,16 +66,23 @@ #define TIM_CCMR_CC1S_TI2 BIT(1) /* IC1/IC3 selects TI2/TI4 */ #define TIM_CCMR_CC2S_TI2 BIT(8) /* IC2/IC4 selects TI2/TI4 */ #define TIM_CCMR_CC2S_TI1 BIT(9) /* IC2/IC4 selects TI1/TI3 */ +#define TIM_CCMR_CC3S (BIT(0) | BIT(1)) /* Capture/compare 3 sel */ +#define TIM_CCMR_CC4S (BIT(8) | BIT(9)) /* Capture/compare 4 sel */ +#define TIM_CCMR_CC3S_TI3 BIT(0) /* IC3 selects TI3 */ +#define TIM_CCMR_CC4S_TI4 BIT(8) /* IC4 selects TI4 */ #define TIM_CCER_CC1E BIT(0) /* Capt/Comp 1 out Ena */ #define TIM_CCER_CC1P BIT(1) /* Capt/Comp 1 Polarity */ #define TIM_CCER_CC1NE BIT(2) /* Capt/Comp 1N out Ena */ #define TIM_CCER_CC1NP BIT(3) /* Capt/Comp 1N Polarity */ #define TIM_CCER_CC2E BIT(4) /* Capt/Comp 2 out Ena */ #define TIM_CCER_CC2P BIT(5) /* Capt/Comp 2 Polarity */ +#define TIM_CCER_CC2NP BIT(7) /* Capt/Comp 2N Polarity */ #define TIM_CCER_CC3E BIT(8) /* Capt/Comp 3 out Ena */ #define TIM_CCER_CC3P BIT(9) /* Capt/Comp 3 Polarity */ +#define TIM_CCER_CC3NP BIT(11) /* Capt/Comp 3N Polarity */ #define TIM_CCER_CC4E BIT(12) /* Capt/Comp 4 out Ena */ #define TIM_CCER_CC4P BIT(13) /* Capt/Comp 4 Polarity */ +#define TIM_CCER_CC4NP BIT(15) /* Capt/Comp 4N Polarity */ #define TIM_CCER_CCXE (BIT(0) | BIT(4) | BIT(8) | BIT(12)) #define TIM_BDTR_BKE(x) BIT(12 + (x) * 12) /* Break input enable */ #define TIM_BDTR_BKP(x) BIT(13 + (x) * 12) /* Break input polarity */ -- cgit v1.2.3-59-g8ed1b From c90663596e7c97363d8855c635f39500ed2f0030 Mon Sep 17 00:00:00 2001 From: William Breathitt Gray Date: Sat, 9 Mar 2024 10:47:56 -0500 Subject: MAINTAINERS: Update email addresses for William Breathitt Gray Using a kernel.org address is more consistent for kernel work and should prevent the need to update again if the underlying email address changes. Signed-off-by: William Breathitt Gray --- MAINTAINERS | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 7c121493f43d..bb0e4c6091dc 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -210,44 +210,44 @@ S: Maintained F: drivers/hwmon/abituguru3.c ACCES 104-DIO-48E GPIO DRIVER -M: William Breathitt Gray +M: William Breathitt Gray L: linux-gpio@vger.kernel.org S: Maintained F: drivers/gpio/gpio-104-dio-48e.c ACCES 104-IDI-48 GPIO DRIVER -M: William Breathitt Gray +M: William Breathitt Gray L: linux-gpio@vger.kernel.org S: Maintained F: drivers/gpio/gpio-104-idi-48.c ACCES 104-IDIO-16 GPIO DRIVER -M: William Breathitt Gray +M: William Breathitt Gray L: linux-gpio@vger.kernel.org S: Maintained F: drivers/gpio/gpio-104-idio-16.c ACCES 104-QUAD-8 DRIVER -M: William Breathitt Gray +M: William Breathitt Gray L: linux-iio@vger.kernel.org S: Maintained F: drivers/counter/104-quad-8.c ACCES IDIO-16 GPIO LIBRARY -M: William Breathitt Gray +M: William Breathitt Gray L: linux-gpio@vger.kernel.org S: Maintained F: drivers/gpio/gpio-idio-16.c F: drivers/gpio/gpio-idio-16.h ACCES PCI-IDIO-16 GPIO DRIVER -M: William Breathitt Gray +M: William Breathitt Gray L: linux-gpio@vger.kernel.org S: Maintained F: drivers/gpio/gpio-pci-idio-16.c ACCES PCIe-IDIO-24 GPIO DRIVER -M: William Breathitt Gray +M: William Breathitt Gray L: linux-gpio@vger.kernel.org S: Maintained F: drivers/gpio/gpio-pcie-idio-24.c @@ -1453,7 +1453,7 @@ S: Maintained F: sound/aoa/ APEX EMBEDDED SYSTEMS STX104 IIO DRIVER -M: William Breathitt Gray +M: William Breathitt Gray L: linux-iio@vger.kernel.org S: Maintained F: drivers/iio/addac/stx104.c @@ -5459,7 +5459,7 @@ F: Documentation/hwmon/corsair-psu.rst F: drivers/hwmon/corsair-psu.c COUNTER SUBSYSTEM -M: William Breathitt Gray +M: William Breathitt Gray L: linux-iio@vger.kernel.org S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/wbg/counter.git @@ -6245,7 +6245,7 @@ F: include/sound/da[79]*.h F: sound/soc/codecs/da[79]*.[ch] DIAMOND SYSTEMS GPIO-MM GPIO DRIVER -M: William Breathitt Gray +M: William Breathitt Gray L: linux-gpio@vger.kernel.org S: Maintained F: drivers/gpio/gpio-gpio-mm.c @@ -10756,14 +10756,14 @@ S: Maintained F: drivers/video/fbdev/i810/ INTEL 8254 COUNTER DRIVER -M: William Breathitt Gray +M: William Breathitt Gray L: linux-iio@vger.kernel.org S: Maintained F: drivers/counter/i8254.c F: include/linux/i8254.h INTEL 8255 GPIO DRIVER -M: William Breathitt Gray +M: William Breathitt Gray L: linux-gpio@vger.kernel.org S: Maintained F: drivers/gpio/gpio-i8255.c @@ -11460,7 +11460,7 @@ F: Documentation/devicetree/bindings/interrupt-controller/ F: drivers/irqchip/ ISA -M: William Breathitt Gray +M: William Breathitt Gray S: Maintained F: Documentation/driver-api/isa.rst F: drivers/base/isa.c @@ -13472,7 +13472,7 @@ F: drivers/net/mdio/mdio-regmap.c F: include/linux/mdio/mdio-regmap.h MEASUREMENT COMPUTING CIO-DAC IIO DRIVER -M: William Breathitt Gray +M: William Breathitt Gray L: linux-iio@vger.kernel.org S: Maintained F: drivers/iio/dac/cio-dac.c @@ -23888,7 +23888,7 @@ S: Orphan F: drivers/watchdog/ebc-c384_wdt.c WINSYSTEMS WS16C48 GPIO DRIVER -M: William Breathitt Gray +M: William Breathitt Gray L: linux-gpio@vger.kernel.org S: Maintained F: drivers/gpio/gpio-ws16c48.c -- cgit v1.2.3-59-g8ed1b From e9b4895fd171dfa961c570d31ef61f443b210ab1 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Sun, 10 Mar 2024 09:06:06 +0100 Subject: counter: ti-ecap-capture: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/f70902b2aabecaa9295c28629cd7a8a0e6eb06d0.1710057753.git.u.kleine-koenig@pengutronix.de Signed-off-by: William Breathitt Gray --- drivers/counter/ti-ecap-capture.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/counter/ti-ecap-capture.c b/drivers/counter/ti-ecap-capture.c index fb1cb1774674..d33d35055b91 100644 --- a/drivers/counter/ti-ecap-capture.c +++ b/drivers/counter/ti-ecap-capture.c @@ -537,15 +537,13 @@ static int ecap_cnt_probe(struct platform_device *pdev) return 0; } -static int ecap_cnt_remove(struct platform_device *pdev) +static void ecap_cnt_remove(struct platform_device *pdev) { struct counter_device *counter_dev = platform_get_drvdata(pdev); struct ecap_cnt_dev *ecap_dev = counter_priv(counter_dev); if (ecap_dev->enabled) ecap_cnt_capture_disable(counter_dev); - - return 0; } static int ecap_cnt_suspend(struct device *dev) @@ -600,7 +598,7 @@ MODULE_DEVICE_TABLE(of, ecap_cnt_of_match); static struct platform_driver ecap_cnt_driver = { .probe = ecap_cnt_probe, - .remove = ecap_cnt_remove, + .remove_new = ecap_cnt_remove, .driver = { .name = "ecap-capture", .of_match_table = ecap_cnt_of_match, -- cgit v1.2.3-59-g8ed1b From 4b986b68e6993c512106548ed712aebe40d3605e Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Sun, 10 Mar 2024 09:06:07 +0100 Subject: counter: ti-eqep: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Acked-by: David Lechner Link: https://lore.kernel.org/r/bf78595f6a49be0b6bb403b466c13177d72c02b7.1710057753.git.u.kleine-koenig@pengutronix.de Signed-off-by: William Breathitt Gray --- drivers/counter/ti-eqep.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/counter/ti-eqep.c b/drivers/counter/ti-eqep.c index b0f24cf3e891..072b11fd6b32 100644 --- a/drivers/counter/ti-eqep.c +++ b/drivers/counter/ti-eqep.c @@ -425,7 +425,7 @@ static int ti_eqep_probe(struct platform_device *pdev) return 0; } -static int ti_eqep_remove(struct platform_device *pdev) +static void ti_eqep_remove(struct platform_device *pdev) { struct counter_device *counter = platform_get_drvdata(pdev); struct device *dev = &pdev->dev; @@ -433,8 +433,6 @@ static int ti_eqep_remove(struct platform_device *pdev) counter_unregister(counter); pm_runtime_put_sync(dev); pm_runtime_disable(dev); - - return 0; } static const struct of_device_id ti_eqep_of_match[] = { @@ -445,7 +443,7 @@ MODULE_DEVICE_TABLE(of, ti_eqep_of_match); static struct platform_driver ti_eqep_driver = { .probe = ti_eqep_probe, - .remove = ti_eqep_remove, + .remove_new = ti_eqep_remove, .driver = { .name = "ti-eqep-cnt", .of_match_table = ti_eqep_of_match, -- cgit v1.2.3-59-g8ed1b From 916baadd293a4d11e08a7ca1e2968314451ade6c Mon Sep 17 00:00:00 2001 From: William Breathitt Gray Date: Thu, 21 Mar 2024 12:32:16 -0400 Subject: counter: ti-ecap-capture: Utilize COUNTER_COMP_FREQUENCY macro Reduce boilerplate by leveraging the COUNTER_COMP_FREQUENCY() macro to define the "frequency" extension. Link: https://lore.kernel.org/r/ZfxhEKdSi1amfcJC@ishi Signed-off-by: William Breathitt Gray --- drivers/counter/ti-ecap-capture.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/counter/ti-ecap-capture.c b/drivers/counter/ti-ecap-capture.c index d33d35055b91..675447315caf 100644 --- a/drivers/counter/ti-ecap-capture.c +++ b/drivers/counter/ti-ecap-capture.c @@ -369,7 +369,7 @@ static const enum counter_synapse_action ecap_cnt_input_actions[] = { }; static struct counter_comp ecap_cnt_clock_ext[] = { - COUNTER_COMP_SIGNAL_U64("frequency", ecap_cnt_clk_get_freq, NULL), + COUNTER_COMP_FREQUENCY(ecap_cnt_clk_get_freq), }; static const enum counter_signal_polarity ecap_cnt_pol_avail[] = { -- cgit v1.2.3-59-g8ed1b From f7a0674ec418458b0fba2d8de5d576b04ff97981 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 22 Mar 2024 11:34:26 -0300 Subject: perf tools: Add Kan Liang to MAINTAINERS as a reviewer Kan has been reviewing patches regularly, add him as a perf tools reviewer so that people CC him on new patches. Acked-by: Adrian Hunter Acked-by: Ian Rogers Acked-by: "Liang, Kan" Acked-by: Namhyung Kim Cc: Alexander Shishkin Cc: Jiri Olsa Cc: Mark Rutland Cc: Peter Zijlstra Signed-off-by: Arnaldo Carvalho de Melo --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 43b39956694a..91a867845d0c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -17264,6 +17264,7 @@ R: Alexander Shishkin R: Jiri Olsa R: Ian Rogers R: Adrian Hunter +R: "Liang, Kan" L: linux-perf-users@vger.kernel.org L: linux-kernel@vger.kernel.org S: Supported -- cgit v1.2.3-59-g8ed1b From 374af9f1f06b5e991c810d2e4983d6f58df32136 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Fri, 22 Mar 2024 15:43:12 -0700 Subject: perf annotate: Get rid of duplicate --group option item The options array in cmd_annotate() has duplicate --group options. It only needs one and let's get rid of the other. $ perf annotate -h 2>&1 | grep group --group Show event group information together --group Show event group information together Fixes: 7ebaf4890f63eb90 ("perf annotate: Support '--group' option") Reviewed-by: Kan Liang Signed-off-by: Namhyung Kim Cc: Adrian Hunter Cc: Ian Rogers Cc: Ingo Molnar Cc: Jin Yao Cc: Jiri Olsa Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20240322224313.423181-1-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-annotate.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index f677671409b1..3e9f7e0596e8 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -810,8 +810,6 @@ int cmd_annotate(int argc, const char **argv) "Enable symbol demangling"), OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel, "Enable kernel symbol demangling"), - OPT_BOOLEAN(0, "group", &symbol_conf.event_group, - "Show event group information together"), OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period, "Show a column with the sum of periods"), OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples, -- cgit v1.2.3-59-g8ed1b From bdeaf6ffec8b3590740973712c6be673c28a54a4 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Fri, 22 Mar 2024 15:43:13 -0700 Subject: perf annotate: Honor output options with --data-type For data type profiling output, it should be in sync with normal output so make it display percentage for each field. Also use coloring scheme for users to identify fields with big overhead easily. Users can use --show-total-period or --show-nr-samples to change the output style like in the normal perf annotate output. Before: $ perf annotate --data-type Annotate type: 'struct task_struct' in [kernel.kallsyms] (34 samples): ============================================================================ samples offset size field 34 0 9792 struct task_struct { 2 0 24 struct thread_info thread_info { 0 0 8 long unsigned int flags; 1 8 8 long unsigned int syscall_work; 0 16 4 u32 status; 1 20 4 u32 cpu; }; After: $ perf annotate --data-type Annotate type: 'struct task_struct' in [kernel.kallsyms] (34 samples): ============================================================================ Percent offset size field 100.00 0 9792 struct task_struct { 3.55 0 24 struct thread_info thread_info { 0.00 0 8 long unsigned int flags; 1.63 8 8 long unsigned int syscall_work; 0.00 16 4 u32 status; 1.91 20 4 u32 cpu; }; Committer testing: First collect a suitable perf.data file for use with 'perf annotate --data-type': root@number:~# perf mem record -a sleep 1s [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 11.047 MB perf.data (3466 samples) ] root@number:~# Then, before: root@number:~# perf annotate --data-type Annotate type: 'union ' in /usr/lib64/libc.so.6 (6 samples): ============================================================================ samples offset size field 6 0 40 union { 6 0 40 struct __pthread_mutex_s __data { 2 0 4 int __lock; 0 4 4 unsigned int __count; 0 8 4 int __owner; 1 12 4 unsigned int __nusers; 2 16 4 int __kind; 1 20 2 short int __spins; 0 22 2 short int __elision; 0 24 16 __pthread_list_t __list { 0 24 8 struct __pthread_internal_list* __prev; 0 32 8 struct __pthread_internal_list* __next; }; }; 0 0 0 char* __size; 2 0 8 long int __align; }; And after: Annotate type: 'union ' in /usr/lib64/libc.so.6 (6 samples): ============================================================================ Percent offset size field 100.00 0 40 union { 100.00 0 40 struct __pthread_mutex_s __data { 31.27 0 4 int __lock; 0.00 4 4 unsigned int __count; 0.00 8 4 int __owner; 7.67 12 4 unsigned int __nusers; 53.10 16 4 int __kind; 7.96 20 2 short int __spins; 0.00 22 2 short int __elision; 0.00 24 16 __pthread_list_t __list { 0.00 24 8 struct __pthread_internal_list* __prev; 0.00 32 8 struct __pthread_internal_list* __next; }; }; 0.00 0 0 char* __size; 31.27 0 8 long int __align; }; The lines with percentages >= 7.67 have its percentages red colored. Reviewed-by: Kan Liang Signed-off-by: Namhyung Kim Tested-by: Arnaldo Carvalho de Melo Cc: Adrian Hunter Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20240322224313.423181-2-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-annotate.c | 44 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 38 insertions(+), 6 deletions(-) diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 3e9f7e0596e8..16e1581207c9 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -42,6 +42,7 @@ #include #include #include +#include struct perf_annotate { struct perf_tool tool; @@ -332,6 +333,8 @@ static void print_annotated_data_header(struct hist_entry *he, struct evsel *evs struct dso *dso = map__dso(he->ms.map); int nr_members = 1; int nr_samples = he->stat.nr_events; + int width = 7; + const char *val_hdr = "Percent"; if (evsel__is_group_event(evsel)) { struct hist_entry *pair; @@ -353,8 +356,30 @@ static void print_annotated_data_header(struct hist_entry *he, struct evsel *evs nr_members = evsel->core.nr_members; } + if (symbol_conf.show_total_period) { + width = 11; + val_hdr = "Period"; + } else if (symbol_conf.show_nr_samples) { + width = 7; + val_hdr = "Samples"; + } + printf("============================================================================\n"); - printf("%*s %10s %10s %s\n", 11 * nr_members, "samples", "offset", "size", "field"); + printf("%*s %10s %10s %s\n", (width + 1) * nr_members, val_hdr, + "offset", "size", "field"); +} + +static void print_annotated_data_value(struct type_hist *h, u64 period, int nr_samples) +{ + double percent = h->period ? (100.0 * period / h->period) : 0; + const char *color = get_percent_color(percent); + + if (symbol_conf.show_total_period) + color_fprintf(stdout, color, " %11" PRIu64, period); + else if (symbol_conf.show_nr_samples) + color_fprintf(stdout, color, " %7d", nr_samples); + else + color_fprintf(stdout, color, " %7.2f", percent); } static void print_annotated_data_type(struct annotated_data_type *mem_type, @@ -364,10 +389,14 @@ static void print_annotated_data_type(struct annotated_data_type *mem_type, struct annotated_member *child; struct type_hist *h = mem_type->histograms[evsel->core.idx]; int i, nr_events = 1, samples = 0; + u64 period = 0; + int width = symbol_conf.show_total_period ? 11 : 7; - for (i = 0; i < member->size; i++) + for (i = 0; i < member->size; i++) { samples += h->addr[member->offset + i].nr_samples; - printf(" %10d", samples); + period += h->addr[member->offset + i].period; + } + print_annotated_data_value(h, period, samples); if (evsel__is_group_event(evsel)) { struct evsel *pos; @@ -376,9 +405,12 @@ static void print_annotated_data_type(struct annotated_data_type *mem_type, h = mem_type->histograms[pos->core.idx]; samples = 0; - for (i = 0; i < member->size; i++) + period = 0; + for (i = 0; i < member->size; i++) { samples += h->addr[member->offset + i].nr_samples; - printf(" %10d", samples); + period += h->addr[member->offset + i].period; + } + print_annotated_data_value(h, period, samples); } nr_events = evsel->core.nr_members; } @@ -394,7 +426,7 @@ static void print_annotated_data_type(struct annotated_data_type *mem_type, print_annotated_data_type(mem_type, child, evsel, indent + 4); if (!list_empty(&member->children)) - printf("%*s}", 11 * nr_events + 24 + indent, ""); + printf("%*s}", (width + 1) * nr_events + 24 + indent, ""); printf(";\n"); } -- cgit v1.2.3-59-g8ed1b From 6e4b398770d5023eb6383da9360a23bd537c155b Mon Sep 17 00:00:00 2001 From: Yang Jihong Date: Mon, 1 Apr 2024 14:27:23 +0800 Subject: perf sched timehist: Fix -g/--call-graph option failure When 'perf sched' enables the call-graph recording, sample_type of dummy event does not have PERF_SAMPLE_CALLCHAIN, timehist_check_attr() checks that the evsel does not have a callchain, and set show_callchain to 0. Currently 'perf sched timehist' only saves callchain when processing the 'sched:sched_switch event', timehist_check_attr() only needs to determine whether the event has PERF_SAMPLE_CALLCHAIN. Before: # perf sched record -g true [ perf record: Woken up 0 times to write data ] [ perf record: Captured and wrote 4.153 MB perf.data (7536 samples) ] # perf sched timehist Samples do not have callchains. time cpu task name wait time sch delay run time [tid/pid] (msec) (msec) (msec) --------------- ------ ------------------------------ --------- --------- --------- 147851.826019 [0000] perf[285035] 0.000 0.000 0.000 147851.826029 [0000] migration/0[15] 0.000 0.003 0.009 147851.826063 [0001] perf[285035] 0.000 0.000 0.000 147851.826069 [0001] migration/1[21] 0.000 0.003 0.006 After: # perf sched record -g true [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 2.572 MB perf.data (822 samples) ] # perf sched timehist time cpu task name waittime sch delay runtime [tid/pid] (msec) (msec) (msec) ----------- --- --------------- -------- -------- ----- 4193.035164 [0] perf[277062] 0.000 0.000 0.000 __traceiter_sched_switch <- __traceiter_sched_switch <- __sched_text_start <- preempt_schedule_common <- __cond_resched <- __wait_for_common <- wait_for_completion 4193.035174 [0] migration/0[15] 0.000 0.003 0.009 __traceiter_sched_switch <- __traceiter_sched_switch <- __sched_text_start <- smpboot_thread_fn <- kthread <- ret_from_fork 4193.035207 [1] perf[277062] 0.000 0.000 0.000 __traceiter_sched_switch <- __traceiter_sched_switch <- __sched_text_start <- preempt_schedule_common <- __cond_resched <- __wait_for_common <- wait_for_completion 4193.035214 [1] migration/1[21] 0.000 0.003 0.007 __traceiter_sched_switch <- __traceiter_sched_switch <- __sched_text_start <- smpboot_thread_fn <- kthread <- ret_from_fork Fixes: 9c95e4ef06572349 ("perf evlist: Add evlist__findnew_tracking_event() helper") Reviewed-by: Ian Rogers Signed-off-by: Yang Jihong Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Kan Liang Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Yang Jihong Link: https://lore.kernel.org/r/20240401062724.1006010-2-yangjihong@bytedance.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-sched.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index b248c433529a..1bfb22347371 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c @@ -2963,8 +2963,11 @@ static int timehist_check_attr(struct perf_sched *sched, return -1; } - if (sched->show_callchain && !evsel__has_callchain(evsel)) { - pr_info("Samples do not have callchains.\n"); + /* only need to save callchain related to sched_switch event */ + if (sched->show_callchain && + evsel__name_is(evsel, "sched:sched_switch") && + !evsel__has_callchain(evsel)) { + pr_info("Samples of sched_switch event do not have callchains.\n"); sched->show_callchain = 0; symbol_conf.use_callchain = 0; } -- cgit v1.2.3-59-g8ed1b From 09d2056efe0c02b7a589915c004c6e925735d081 Mon Sep 17 00:00:00 2001 From: Yang Jihong Date: Mon, 1 Apr 2024 14:27:24 +0800 Subject: perf evsel: Use evsel__name_is() helper Code cleanup, replace strcmp(evsel__name(evsel, {NAME})) with evsel__name_is() helper. No functional change. Committer notes: Fix this build error: trace.syscalls.events.bpf_output = evlist__last(trace.evlist); - assert(evsel__name_is(trace.syscalls.events.bpf_output), "__augmented_syscalls__"); + assert(evsel__name_is(trace.syscalls.events.bpf_output, "__augmented_syscalls__")); Reviewed-by: Ian Rogers Signed-off-by: Yang Jihong Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Kan Liang Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20240401062724.1006010-3-yangjihong@bytedance.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-kmem.c | 2 +- tools/perf/builtin-sched.c | 4 ++-- tools/perf/builtin-script.c | 2 +- tools/perf/builtin-trace.c | 4 ++-- tools/perf/tests/evsel-roundtrip-name.c | 4 ++-- tools/perf/tests/parse-events.c | 39 ++++++++++++--------------------- 6 files changed, 22 insertions(+), 33 deletions(-) diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index 9714327fd0ea..6fd95be5032b 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c @@ -1408,7 +1408,7 @@ static int __cmd_kmem(struct perf_session *session) } evlist__for_each_entry(session->evlist, evsel) { - if (!strcmp(evsel__name(evsel), "kmem:mm_page_alloc") && + if (evsel__name_is(evsel, "kmem:mm_page_alloc") && evsel__field(evsel, "pfn")) { use_pfn = true; break; diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index 1bfb22347371..0fce7d8986c0 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c @@ -2148,7 +2148,7 @@ static bool is_idle_sample(struct perf_sample *sample, struct evsel *evsel) { /* pid 0 == swapper == idle task */ - if (strcmp(evsel__name(evsel), "sched:sched_switch") == 0) + if (evsel__name_is(evsel, "sched:sched_switch")) return evsel__intval(evsel, sample, "prev_pid") == 0; return sample->pid == 0; @@ -2375,7 +2375,7 @@ static bool timehist_skip_sample(struct perf_sched *sched, } if (sched->idle_hist) { - if (strcmp(evsel__name(evsel), "sched:sched_switch")) + if (!evsel__name_is(evsel, "sched:sched_switch")) rc = true; else if (evsel__intval(evsel, sample, "prev_pid") != 0 && evsel__intval(evsel, sample, "next_pid") != 0) diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 2e7148d667bd..6a274e27b108 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -3471,7 +3471,7 @@ static int check_ev_match(char *dir_name, char *scriptname, match = 0; evlist__for_each_entry(session->evlist, pos) { - if (!strcmp(evsel__name(pos), evname)) { + if (evsel__name_is(pos, evname)) { match = 1; break; } diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index d3ec244e692a..e5fef39c34bf 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -4916,7 +4916,7 @@ int cmd_trace(int argc, const char **argv) goto out; } trace.syscalls.events.bpf_output = evlist__last(trace.evlist); - assert(!strcmp(evsel__name(trace.syscalls.events.bpf_output), "__augmented_syscalls__")); + assert(evsel__name_is(trace.syscalls.events.bpf_output, "__augmented_syscalls__")); skip_augmentation: #endif err = -1; @@ -4973,7 +4973,7 @@ skip_augmentation: */ if (trace.syscalls.events.bpf_output) { evlist__for_each_entry(trace.evlist, evsel) { - bool raw_syscalls_sys_exit = strcmp(evsel__name(evsel), "raw_syscalls:sys_exit") == 0; + bool raw_syscalls_sys_exit = evsel__name_is(evsel, "raw_syscalls:sys_exit"); if (raw_syscalls_sys_exit) { trace.raw_augmented_syscalls = true; diff --git a/tools/perf/tests/evsel-roundtrip-name.c b/tools/perf/tests/evsel-roundtrip-name.c index 15ff86f9da0b..1922cac13a24 100644 --- a/tools/perf/tests/evsel-roundtrip-name.c +++ b/tools/perf/tests/evsel-roundtrip-name.c @@ -37,7 +37,7 @@ static int perf_evsel__roundtrip_cache_name_test(void) continue; } evlist__for_each_entry(evlist, evsel) { - if (strcmp(evsel__name(evsel), name)) { + if (!evsel__name_is(evsel, name)) { pr_debug("%s != %s\n", evsel__name(evsel), name); ret = TEST_FAIL; } @@ -71,7 +71,7 @@ static int perf_evsel__name_array_test(const char *const names[], int nr_names) continue; } evlist__for_each_entry(evlist, evsel) { - if (strcmp(evsel__name(evsel), names[i])) { + if (!evsel__name_is(evsel, names[i])) { pr_debug("%s != %s\n", evsel__name(evsel), names[i]); ret = TEST_FAIL; } diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c index feb5727584d1..0b70451451b3 100644 --- a/tools/perf/tests/parse-events.c +++ b/tools/perf/tests/parse-events.c @@ -470,8 +470,7 @@ static int test__checkevent_breakpoint_modifier(struct evlist *evlist) TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); - TEST_ASSERT_VAL("wrong name", - !strcmp(evsel__name(evsel), "mem:0:u")); + TEST_ASSERT_VAL("wrong name", evsel__name_is(evsel, "mem:0:u")); return test__checkevent_breakpoint(evlist); } @@ -484,8 +483,7 @@ static int test__checkevent_breakpoint_x_modifier(struct evlist *evlist) TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); - TEST_ASSERT_VAL("wrong name", - !strcmp(evsel__name(evsel), "mem:0:x:k")); + TEST_ASSERT_VAL("wrong name", evsel__name_is(evsel, "mem:0:x:k")); return test__checkevent_breakpoint_x(evlist); } @@ -498,8 +496,7 @@ static int test__checkevent_breakpoint_r_modifier(struct evlist *evlist) TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv); TEST_ASSERT_VAL("wrong precise_ip", evsel->core.attr.precise_ip); - TEST_ASSERT_VAL("wrong name", - !strcmp(evsel__name(evsel), "mem:0:r:hp")); + TEST_ASSERT_VAL("wrong name", evsel__name_is(evsel, "mem:0:r:hp")); return test__checkevent_breakpoint_r(evlist); } @@ -512,8 +509,7 @@ static int test__checkevent_breakpoint_w_modifier(struct evlist *evlist) TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); TEST_ASSERT_VAL("wrong precise_ip", evsel->core.attr.precise_ip); - TEST_ASSERT_VAL("wrong name", - !strcmp(evsel__name(evsel), "mem:0:w:up")); + TEST_ASSERT_VAL("wrong name", evsel__name_is(evsel, "mem:0:w:up")); return test__checkevent_breakpoint_w(evlist); } @@ -526,8 +522,7 @@ static int test__checkevent_breakpoint_rw_modifier(struct evlist *evlist) TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); TEST_ASSERT_VAL("wrong precise_ip", evsel->core.attr.precise_ip); - TEST_ASSERT_VAL("wrong name", - !strcmp(evsel__name(evsel), "mem:0:rw:kp")); + TEST_ASSERT_VAL("wrong name", evsel__name_is(evsel, "mem:0:rw:kp")); return test__checkevent_breakpoint_rw(evlist); } @@ -540,8 +535,7 @@ static int test__checkevent_breakpoint_modifier_name(struct evlist *evlist) TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); - TEST_ASSERT_VAL("wrong name", - !strcmp(evsel__name(evsel), "breakpoint")); + TEST_ASSERT_VAL("wrong name", evsel__name_is(evsel, "breakpoint")); return test__checkevent_breakpoint(evlist); } @@ -554,8 +548,7 @@ static int test__checkevent_breakpoint_x_modifier_name(struct evlist *evlist) TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); - TEST_ASSERT_VAL("wrong name", - !strcmp(evsel__name(evsel), "breakpoint")); + TEST_ASSERT_VAL("wrong name", evsel__name_is(evsel, "breakpoint")); return test__checkevent_breakpoint_x(evlist); } @@ -568,8 +561,7 @@ static int test__checkevent_breakpoint_r_modifier_name(struct evlist *evlist) TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv); TEST_ASSERT_VAL("wrong precise_ip", evsel->core.attr.precise_ip); - TEST_ASSERT_VAL("wrong name", - !strcmp(evsel__name(evsel), "breakpoint")); + TEST_ASSERT_VAL("wrong name", evsel__name_is(evsel, "breakpoint")); return test__checkevent_breakpoint_r(evlist); } @@ -582,8 +574,7 @@ static int test__checkevent_breakpoint_w_modifier_name(struct evlist *evlist) TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); TEST_ASSERT_VAL("wrong precise_ip", evsel->core.attr.precise_ip); - TEST_ASSERT_VAL("wrong name", - !strcmp(evsel__name(evsel), "breakpoint")); + TEST_ASSERT_VAL("wrong name", evsel__name_is(evsel, "breakpoint")); return test__checkevent_breakpoint_w(evlist); } @@ -596,8 +587,7 @@ static int test__checkevent_breakpoint_rw_modifier_name(struct evlist *evlist) TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); TEST_ASSERT_VAL("wrong precise_ip", evsel->core.attr.precise_ip); - TEST_ASSERT_VAL("wrong name", - !strcmp(evsel__name(evsel), "breakpoint")); + TEST_ASSERT_VAL("wrong name", evsel__name_is(evsel, "breakpoint")); return test__checkevent_breakpoint_rw(evlist); } @@ -609,12 +599,12 @@ static int test__checkevent_breakpoint_2_events(struct evlist *evlist) TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); TEST_ASSERT_VAL("wrong type", PERF_TYPE_BREAKPOINT == evsel->core.attr.type); - TEST_ASSERT_VAL("wrong name", !strcmp(evsel__name(evsel), "breakpoint1")); + TEST_ASSERT_VAL("wrong name", evsel__name_is(evsel, "breakpoint1")); evsel = evsel__next(evsel); TEST_ASSERT_VAL("wrong type", PERF_TYPE_BREAKPOINT == evsel->core.attr.type); - TEST_ASSERT_VAL("wrong name", !strcmp(evsel__name(evsel), "breakpoint2")); + TEST_ASSERT_VAL("wrong name", evsel__name_is(evsel, "breakpoint2")); return TEST_OK; } @@ -691,15 +681,14 @@ static int test__checkevent_pmu_name(struct evlist *evlist) TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->core.attr.type); TEST_ASSERT_VAL("wrong config", test_config(evsel, 1)); - TEST_ASSERT_VAL("wrong name", !strcmp(evsel__name(evsel), "krava")); + TEST_ASSERT_VAL("wrong name", evsel__name_is(evsel, "krava")); /* cpu/config=2/u" */ evsel = evsel__next(evsel); TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->core.attr.type); TEST_ASSERT_VAL("wrong config", test_config(evsel, 2)); - TEST_ASSERT_VAL("wrong name", - !strcmp(evsel__name(evsel), "cpu/config=2/u")); + TEST_ASSERT_VAL("wrong name", evsel__name_is(evsel, "cpu/config=2/u")); return TEST_OK; } -- cgit v1.2.3-59-g8ed1b From ad399baa06931a62d1166d215eaad6f3b0dcd3d5 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Fri, 29 Mar 2024 14:58:08 -0700 Subject: perf annotate: Use ins__is_xxx() if possible This is to prepare separation of disasm related code. Use the public ins API instead of checking the internal data structure. Signed-off-by: Namhyung Kim Tested-by: Ian Rogers Cc: Adrian Hunter Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20240329215812.537846-2-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 64e54ff1aa1d..986c499150ef 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -3665,7 +3665,7 @@ int annotate_get_insn_location(struct arch *arch, struct disasm_line *dl, struct annotated_op_loc *op_loc; int i; - if (!strcmp(dl->ins.name, "lock")) + if (ins__is_lock(&dl->ins)) ops = dl->ops.locked.ops; else ops = &dl->ops; @@ -3763,7 +3763,7 @@ static struct disasm_line *find_disasm_line(struct symbol *sym, u64 ip, * llvm-objdump places "lock" in a separate line and * in that case, we want to get the next line. */ - if (!strcmp(dl->ins.name, "lock") && + if (ins__is_lock(&dl->ins) && *dl->ops.raw == '\0' && allow_update) { ip++; continue; @@ -4093,10 +4093,10 @@ static bool process_basic_block(struct basic_block_data *bb_data, if (dl == last_dl) break; /* 'return' instruction finishes the block */ - if (dl->ins.ops == &ret_ops) + if (ins__is_ret(&dl->ins)) break; /* normal instructions are part of the basic block */ - if (dl->ins.ops != &jump_ops) + if (!ins__is_jump(&dl->ins)) continue; /* jump to a different function, tail call or return */ if (dl->ops.target.outside) -- cgit v1.2.3-59-g8ed1b From 10adbf777622e22323abbf9f7861c26deb373199 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Fri, 29 Mar 2024 14:58:09 -0700 Subject: perf annotate: Add and use ins__is_nop() Likewise, add ins__is_nop() to check if the current instruction is NOP. Signed-off-by: Namhyung Kim Tested-by: Ian Rogers Cc: Adrian Hunter Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20240329215812.537846-3-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 7 ++++++- tools/perf/util/annotate.h | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 986c499150ef..5d0ca004dcfb 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -757,6 +757,11 @@ static struct ins_ops ret_ops = { .scnprintf = ins__raw_scnprintf, }; +bool ins__is_nop(const struct ins *ins) +{ + return ins->ops == &nop_ops; +} + bool ins__is_ret(const struct ins *ins) { return ins->ops == &ret_ops; @@ -1785,7 +1790,7 @@ static void delete_last_nop(struct symbol *sym) dl = list_entry(list->prev, struct disasm_line, al.node); if (dl->ins.ops) { - if (dl->ins.ops != &nop_ops) + if (!ins__is_nop(&dl->ins)) return; } else { if (!strstr(dl->al.line, " nop ") && diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 14980b65f812..98f556af637c 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -74,6 +74,7 @@ struct ins_ops { bool ins__is_jump(const struct ins *ins); bool ins__is_call(const struct ins *ins); +bool ins__is_nop(const struct ins *ins); bool ins__is_ret(const struct ins *ins); bool ins__is_lock(const struct ins *ins); int ins__scnprintf(struct ins *ins, char *bf, size_t size, struct ins_operands *ops, int max_ins_name); -- cgit v1.2.3-59-g8ed1b From 98f69a573c668a18cfda41b3976118e04521a196 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Fri, 29 Mar 2024 14:58:10 -0700 Subject: perf annotate: Split out util/disasm.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The util/annotate.c code has both disassembly and sample annotation related codes. Factor out the disasm part so that it can be handled more easily. No functional changes intended. Committer notes: Add missing include env.h, util.h, bpf-event.h and bpf-util.h to disasm.c, to fix things like: util/disasm.c: In function ‘symbol__disassemble_bpf’: util/disasm.c:1203:9: error: implicit declaration of function ‘perf_exe’ [-Werror=implicit-function-declaration] 1203 | perf_exe(tpath, sizeof(tpath)); | ^~~~~~~~ Signed-off-by: Namhyung Kim Tested-by: Ian Rogers Cc: Adrian Hunter Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20240329215812.537846-4-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/Build | 1 + tools/perf/util/annotate.c | 1708 ++------------------------------------------ tools/perf/util/annotate.h | 60 +- tools/perf/util/disasm.c | 1591 +++++++++++++++++++++++++++++++++++++++++ tools/perf/util/disasm.h | 112 +++ 5 files changed, 1762 insertions(+), 1710 deletions(-) create mode 100644 tools/perf/util/disasm.c create mode 100644 tools/perf/util/disasm.h diff --git a/tools/perf/util/Build b/tools/perf/util/Build index e0a723e24503..aec5a590e349 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -12,6 +12,7 @@ perf-y += config.o perf-y += copyfile.o perf-y += ctype.o perf-y += db-export.o +perf-y += disasm.o perf-y += env.o perf-y += event.o perf-y += evlist.o diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 5d0ca004dcfb..b795f27f2602 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -16,6 +16,7 @@ #include "build-id.h" #include "color.h" #include "config.h" +#include "disasm.h" #include "dso.h" #include "env.h" #include "map.h" @@ -64,48 +65,6 @@ /* global annotation options */ struct annotation_options annotate_opts; -static regex_t file_lineno; - -static struct ins_ops *ins__find(struct arch *arch, const char *name); -static void ins__sort(struct arch *arch); -static int disasm_line__parse(char *line, const char **namep, char **rawp); -static int call__scnprintf(struct ins *ins, char *bf, size_t size, - struct ins_operands *ops, int max_ins_name); -static int jump__scnprintf(struct ins *ins, char *bf, size_t size, - struct ins_operands *ops, int max_ins_name); - -struct arch { - const char *name; - struct ins *instructions; - size_t nr_instructions; - size_t nr_instructions_allocated; - struct ins_ops *(*associate_instruction_ops)(struct arch *arch, const char *name); - bool sorted_instructions; - bool initialized; - const char *insn_suffix; - void *priv; - unsigned int model; - unsigned int family; - int (*init)(struct arch *arch, char *cpuid); - bool (*ins_is_fused)(struct arch *arch, const char *ins1, - const char *ins2); - struct { - char comment_char; - char skip_functions_char; - char register_char; - char memory_ref_char; - char imm_char; - } objdump; -}; - -static struct ins_ops call_ops; -static struct ins_ops dec_ops; -static struct ins_ops jump_ops; -static struct ins_ops mov_ops; -static struct ins_ops nop_ops; -static struct ins_ops lock_ops; -static struct ins_ops ret_ops; - /* Data type collection debug statistics */ struct annotated_data_stat ann_data_stat; LIST_HEAD(ann_insn_stat); @@ -125,759 +84,6 @@ struct annotated_data_type canary_type = { }, }; -static int arch__grow_instructions(struct arch *arch) -{ - struct ins *new_instructions; - size_t new_nr_allocated; - - if (arch->nr_instructions_allocated == 0 && arch->instructions) - goto grow_from_non_allocated_table; - - new_nr_allocated = arch->nr_instructions_allocated + 128; - new_instructions = realloc(arch->instructions, new_nr_allocated * sizeof(struct ins)); - if (new_instructions == NULL) - return -1; - -out_update_instructions: - arch->instructions = new_instructions; - arch->nr_instructions_allocated = new_nr_allocated; - return 0; - -grow_from_non_allocated_table: - new_nr_allocated = arch->nr_instructions + 128; - new_instructions = calloc(new_nr_allocated, sizeof(struct ins)); - if (new_instructions == NULL) - return -1; - - memcpy(new_instructions, arch->instructions, arch->nr_instructions); - goto out_update_instructions; -} - -static int arch__associate_ins_ops(struct arch* arch, const char *name, struct ins_ops *ops) -{ - struct ins *ins; - - if (arch->nr_instructions == arch->nr_instructions_allocated && - arch__grow_instructions(arch)) - return -1; - - ins = &arch->instructions[arch->nr_instructions]; - ins->name = strdup(name); - if (!ins->name) - return -1; - - ins->ops = ops; - arch->nr_instructions++; - - ins__sort(arch); - return 0; -} - -#include "arch/arc/annotate/instructions.c" -#include "arch/arm/annotate/instructions.c" -#include "arch/arm64/annotate/instructions.c" -#include "arch/csky/annotate/instructions.c" -#include "arch/loongarch/annotate/instructions.c" -#include "arch/mips/annotate/instructions.c" -#include "arch/x86/annotate/instructions.c" -#include "arch/powerpc/annotate/instructions.c" -#include "arch/riscv64/annotate/instructions.c" -#include "arch/s390/annotate/instructions.c" -#include "arch/sparc/annotate/instructions.c" - -static struct arch architectures[] = { - { - .name = "arc", - .init = arc__annotate_init, - }, - { - .name = "arm", - .init = arm__annotate_init, - }, - { - .name = "arm64", - .init = arm64__annotate_init, - }, - { - .name = "csky", - .init = csky__annotate_init, - }, - { - .name = "mips", - .init = mips__annotate_init, - .objdump = { - .comment_char = '#', - }, - }, - { - .name = "x86", - .init = x86__annotate_init, - .instructions = x86__instructions, - .nr_instructions = ARRAY_SIZE(x86__instructions), - .insn_suffix = "bwlq", - .objdump = { - .comment_char = '#', - .register_char = '%', - .memory_ref_char = '(', - .imm_char = '$', - }, - }, - { - .name = "powerpc", - .init = powerpc__annotate_init, - }, - { - .name = "riscv64", - .init = riscv64__annotate_init, - }, - { - .name = "s390", - .init = s390__annotate_init, - .objdump = { - .comment_char = '#', - }, - }, - { - .name = "sparc", - .init = sparc__annotate_init, - .objdump = { - .comment_char = '#', - }, - }, - { - .name = "loongarch", - .init = loongarch__annotate_init, - .objdump = { - .comment_char = '#', - }, - }, -}; - -static void ins__delete(struct ins_operands *ops) -{ - if (ops == NULL) - return; - zfree(&ops->source.raw); - zfree(&ops->source.name); - zfree(&ops->target.raw); - zfree(&ops->target.name); -} - -static int ins__raw_scnprintf(struct ins *ins, char *bf, size_t size, - struct ins_operands *ops, int max_ins_name) -{ - return scnprintf(bf, size, "%-*s %s", max_ins_name, ins->name, ops->raw); -} - -int ins__scnprintf(struct ins *ins, char *bf, size_t size, - struct ins_operands *ops, int max_ins_name) -{ - if (ins->ops->scnprintf) - return ins->ops->scnprintf(ins, bf, size, ops, max_ins_name); - - return ins__raw_scnprintf(ins, bf, size, ops, max_ins_name); -} - -bool ins__is_fused(struct arch *arch, const char *ins1, const char *ins2) -{ - if (!arch || !arch->ins_is_fused) - return false; - - return arch->ins_is_fused(arch, ins1, ins2); -} - -static int call__parse(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms) -{ - char *endptr, *tok, *name; - struct map *map = ms->map; - struct addr_map_symbol target = { - .ms = { .map = map, }, - }; - - ops->target.addr = strtoull(ops->raw, &endptr, 16); - - name = strchr(endptr, '<'); - if (name == NULL) - goto indirect_call; - - name++; - - if (arch->objdump.skip_functions_char && - strchr(name, arch->objdump.skip_functions_char)) - return -1; - - tok = strchr(name, '>'); - if (tok == NULL) - return -1; - - *tok = '\0'; - ops->target.name = strdup(name); - *tok = '>'; - - if (ops->target.name == NULL) - return -1; -find_target: - target.addr = map__objdump_2mem(map, ops->target.addr); - - if (maps__find_ams(ms->maps, &target) == 0 && - map__rip_2objdump(target.ms.map, map__map_ip(target.ms.map, target.addr)) == ops->target.addr) - ops->target.sym = target.ms.sym; - - return 0; - -indirect_call: - tok = strchr(endptr, '*'); - if (tok != NULL) { - endptr++; - - /* Indirect call can use a non-rip register and offset: callq *0x8(%rbx). - * Do not parse such instruction. */ - if (strstr(endptr, "(%r") == NULL) - ops->target.addr = strtoull(endptr, NULL, 16); - } - goto find_target; -} - -static int call__scnprintf(struct ins *ins, char *bf, size_t size, - struct ins_operands *ops, int max_ins_name) -{ - if (ops->target.sym) - return scnprintf(bf, size, "%-*s %s", max_ins_name, ins->name, ops->target.sym->name); - - if (ops->target.addr == 0) - return ins__raw_scnprintf(ins, bf, size, ops, max_ins_name); - - if (ops->target.name) - return scnprintf(bf, size, "%-*s %s", max_ins_name, ins->name, ops->target.name); - - return scnprintf(bf, size, "%-*s *%" PRIx64, max_ins_name, ins->name, ops->target.addr); -} - -static struct ins_ops call_ops = { - .parse = call__parse, - .scnprintf = call__scnprintf, -}; - -bool ins__is_call(const struct ins *ins) -{ - return ins->ops == &call_ops || ins->ops == &s390_call_ops || ins->ops == &loongarch_call_ops; -} - -/* - * Prevents from matching commas in the comment section, e.g.: - * ffff200008446e70: b.cs ffff2000084470f4 // b.hs, b.nlast - * - * and skip comma as part of function arguments, e.g.: - * 1d8b4ac - */ -static inline const char *validate_comma(const char *c, struct ins_operands *ops) -{ - if (ops->jump.raw_comment && c > ops->jump.raw_comment) - return NULL; - - if (ops->jump.raw_func_start && c > ops->jump.raw_func_start) - return NULL; - - return c; -} - -static int jump__parse(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms) -{ - struct map *map = ms->map; - struct symbol *sym = ms->sym; - struct addr_map_symbol target = { - .ms = { .map = map, }, - }; - const char *c = strchr(ops->raw, ','); - u64 start, end; - - ops->jump.raw_comment = strchr(ops->raw, arch->objdump.comment_char); - ops->jump.raw_func_start = strchr(ops->raw, '<'); - - c = validate_comma(c, ops); - - /* - * Examples of lines to parse for the _cpp_lex_token@@Base - * function: - * - * 1159e6c: jne 115aa32 <_cpp_lex_token@@Base+0xf92> - * 1159e8b: jne c469be - * - * The first is a jump to an offset inside the same function, - * the second is to another function, i.e. that 0xa72 is an - * offset in the cpp_named_operator2name@@base function. - */ - /* - * skip over possible up to 2 operands to get to address, e.g.: - * tbnz w0, #26, ffff0000083cd190 - */ - if (c++ != NULL) { - ops->target.addr = strtoull(c, NULL, 16); - if (!ops->target.addr) { - c = strchr(c, ','); - c = validate_comma(c, ops); - if (c++ != NULL) - ops->target.addr = strtoull(c, NULL, 16); - } - } else { - ops->target.addr = strtoull(ops->raw, NULL, 16); - } - - target.addr = map__objdump_2mem(map, ops->target.addr); - start = map__unmap_ip(map, sym->start); - end = map__unmap_ip(map, sym->end); - - ops->target.outside = target.addr < start || target.addr > end; - - /* - * FIXME: things like this in _cpp_lex_token (gcc's cc1 program): - - cpp_named_operator2name@@Base+0xa72 - - * Point to a place that is after the cpp_named_operator2name - * boundaries, i.e. in the ELF symbol table for cc1 - * cpp_named_operator2name is marked as being 32-bytes long, but it in - * fact is much larger than that, so we seem to need a symbols__find() - * routine that looks for >= current->start and < next_symbol->start, - * possibly just for C++ objects? - * - * For now lets just make some progress by marking jumps to outside the - * current function as call like. - * - * Actual navigation will come next, with further understanding of how - * the symbol searching and disassembly should be done. - */ - if (maps__find_ams(ms->maps, &target) == 0 && - map__rip_2objdump(target.ms.map, map__map_ip(target.ms.map, target.addr)) == ops->target.addr) - ops->target.sym = target.ms.sym; - - if (!ops->target.outside) { - ops->target.offset = target.addr - start; - ops->target.offset_avail = true; - } else { - ops->target.offset_avail = false; - } - - return 0; -} - -static int jump__scnprintf(struct ins *ins, char *bf, size_t size, - struct ins_operands *ops, int max_ins_name) -{ - const char *c; - - if (!ops->target.addr || ops->target.offset < 0) - return ins__raw_scnprintf(ins, bf, size, ops, max_ins_name); - - if (ops->target.outside && ops->target.sym != NULL) - return scnprintf(bf, size, "%-*s %s", max_ins_name, ins->name, ops->target.sym->name); - - c = strchr(ops->raw, ','); - c = validate_comma(c, ops); - - if (c != NULL) { - const char *c2 = strchr(c + 1, ','); - - c2 = validate_comma(c2, ops); - /* check for 3-op insn */ - if (c2 != NULL) - c = c2; - c++; - - /* mirror arch objdump's space-after-comma style */ - if (*c == ' ') - c++; - } - - return scnprintf(bf, size, "%-*s %.*s%" PRIx64, max_ins_name, - ins->name, c ? c - ops->raw : 0, ops->raw, - ops->target.offset); -} - -static void jump__delete(struct ins_operands *ops __maybe_unused) -{ - /* - * The ops->jump.raw_comment and ops->jump.raw_func_start belong to the - * raw string, don't free them. - */ -} - -static struct ins_ops jump_ops = { - .free = jump__delete, - .parse = jump__parse, - .scnprintf = jump__scnprintf, -}; - -bool ins__is_jump(const struct ins *ins) -{ - return ins->ops == &jump_ops || ins->ops == &loongarch_jump_ops; -} - -static int comment__symbol(char *raw, char *comment, u64 *addrp, char **namep) -{ - char *endptr, *name, *t; - - if (strstr(raw, "(%rip)") == NULL) - return 0; - - *addrp = strtoull(comment, &endptr, 16); - if (endptr == comment) - return 0; - name = strchr(endptr, '<'); - if (name == NULL) - return -1; - - name++; - - t = strchr(name, '>'); - if (t == NULL) - return 0; - - *t = '\0'; - *namep = strdup(name); - *t = '>'; - - return 0; -} - -static int lock__parse(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms) -{ - ops->locked.ops = zalloc(sizeof(*ops->locked.ops)); - if (ops->locked.ops == NULL) - return 0; - - if (disasm_line__parse(ops->raw, &ops->locked.ins.name, &ops->locked.ops->raw) < 0) - goto out_free_ops; - - ops->locked.ins.ops = ins__find(arch, ops->locked.ins.name); - - if (ops->locked.ins.ops == NULL) - goto out_free_ops; - - if (ops->locked.ins.ops->parse && - ops->locked.ins.ops->parse(arch, ops->locked.ops, ms) < 0) - goto out_free_ops; - - return 0; - -out_free_ops: - zfree(&ops->locked.ops); - return 0; -} - -static int lock__scnprintf(struct ins *ins, char *bf, size_t size, - struct ins_operands *ops, int max_ins_name) -{ - int printed; - - if (ops->locked.ins.ops == NULL) - return ins__raw_scnprintf(ins, bf, size, ops, max_ins_name); - - printed = scnprintf(bf, size, "%-*s ", max_ins_name, ins->name); - return printed + ins__scnprintf(&ops->locked.ins, bf + printed, - size - printed, ops->locked.ops, max_ins_name); -} - -static void lock__delete(struct ins_operands *ops) -{ - struct ins *ins = &ops->locked.ins; - - if (ins->ops && ins->ops->free) - ins->ops->free(ops->locked.ops); - else - ins__delete(ops->locked.ops); - - zfree(&ops->locked.ops); - zfree(&ops->target.raw); - zfree(&ops->target.name); -} - -static struct ins_ops lock_ops = { - .free = lock__delete, - .parse = lock__parse, - .scnprintf = lock__scnprintf, -}; - -/* - * Check if the operand has more than one registers like x86 SIB addressing: - * 0x1234(%rax, %rbx, 8) - * - * But it doesn't care segment selectors like %gs:0x5678(%rcx), so just check - * the input string after 'memory_ref_char' if exists. - */ -static bool check_multi_regs(struct arch *arch, const char *op) -{ - int count = 0; - - if (arch->objdump.register_char == 0) - return false; - - if (arch->objdump.memory_ref_char) { - op = strchr(op, arch->objdump.memory_ref_char); - if (op == NULL) - return false; - } - - while ((op = strchr(op, arch->objdump.register_char)) != NULL) { - count++; - op++; - } - - return count > 1; -} - -static int mov__parse(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms __maybe_unused) -{ - char *s = strchr(ops->raw, ','), *target, *comment, prev; - - if (s == NULL) - return -1; - - *s = '\0'; - - /* - * x86 SIB addressing has something like 0x8(%rax, %rcx, 1) - * then it needs to have the closing parenthesis. - */ - if (strchr(ops->raw, '(')) { - *s = ','; - s = strchr(ops->raw, ')'); - if (s == NULL || s[1] != ',') - return -1; - *++s = '\0'; - } - - ops->source.raw = strdup(ops->raw); - *s = ','; - - if (ops->source.raw == NULL) - return -1; - - ops->source.multi_regs = check_multi_regs(arch, ops->source.raw); - - target = skip_spaces(++s); - comment = strchr(s, arch->objdump.comment_char); - - if (comment != NULL) - s = comment - 1; - else - s = strchr(s, '\0') - 1; - - while (s > target && isspace(s[0])) - --s; - s++; - prev = *s; - *s = '\0'; - - ops->target.raw = strdup(target); - *s = prev; - - if (ops->target.raw == NULL) - goto out_free_source; - - ops->target.multi_regs = check_multi_regs(arch, ops->target.raw); - - if (comment == NULL) - return 0; - - comment = skip_spaces(comment); - comment__symbol(ops->source.raw, comment + 1, &ops->source.addr, &ops->source.name); - comment__symbol(ops->target.raw, comment + 1, &ops->target.addr, &ops->target.name); - - return 0; - -out_free_source: - zfree(&ops->source.raw); - return -1; -} - -static int mov__scnprintf(struct ins *ins, char *bf, size_t size, - struct ins_operands *ops, int max_ins_name) -{ - return scnprintf(bf, size, "%-*s %s,%s", max_ins_name, ins->name, - ops->source.name ?: ops->source.raw, - ops->target.name ?: ops->target.raw); -} - -static struct ins_ops mov_ops = { - .parse = mov__parse, - .scnprintf = mov__scnprintf, -}; - -static int dec__parse(struct arch *arch __maybe_unused, struct ins_operands *ops, struct map_symbol *ms __maybe_unused) -{ - char *target, *comment, *s, prev; - - target = s = ops->raw; - - while (s[0] != '\0' && !isspace(s[0])) - ++s; - prev = *s; - *s = '\0'; - - ops->target.raw = strdup(target); - *s = prev; - - if (ops->target.raw == NULL) - return -1; - - comment = strchr(s, arch->objdump.comment_char); - if (comment == NULL) - return 0; - - comment = skip_spaces(comment); - comment__symbol(ops->target.raw, comment + 1, &ops->target.addr, &ops->target.name); - - return 0; -} - -static int dec__scnprintf(struct ins *ins, char *bf, size_t size, - struct ins_operands *ops, int max_ins_name) -{ - return scnprintf(bf, size, "%-*s %s", max_ins_name, ins->name, - ops->target.name ?: ops->target.raw); -} - -static struct ins_ops dec_ops = { - .parse = dec__parse, - .scnprintf = dec__scnprintf, -}; - -static int nop__scnprintf(struct ins *ins __maybe_unused, char *bf, size_t size, - struct ins_operands *ops __maybe_unused, int max_ins_name) -{ - return scnprintf(bf, size, "%-*s", max_ins_name, "nop"); -} - -static struct ins_ops nop_ops = { - .scnprintf = nop__scnprintf, -}; - -static struct ins_ops ret_ops = { - .scnprintf = ins__raw_scnprintf, -}; - -bool ins__is_nop(const struct ins *ins) -{ - return ins->ops == &nop_ops; -} - -bool ins__is_ret(const struct ins *ins) -{ - return ins->ops == &ret_ops; -} - -bool ins__is_lock(const struct ins *ins) -{ - return ins->ops == &lock_ops; -} - -static int ins__key_cmp(const void *name, const void *insp) -{ - const struct ins *ins = insp; - - return strcmp(name, ins->name); -} - -static int ins__cmp(const void *a, const void *b) -{ - const struct ins *ia = a; - const struct ins *ib = b; - - return strcmp(ia->name, ib->name); -} - -static void ins__sort(struct arch *arch) -{ - const int nmemb = arch->nr_instructions; - - qsort(arch->instructions, nmemb, sizeof(struct ins), ins__cmp); -} - -static struct ins_ops *__ins__find(struct arch *arch, const char *name) -{ - struct ins *ins; - const int nmemb = arch->nr_instructions; - - if (!arch->sorted_instructions) { - ins__sort(arch); - arch->sorted_instructions = true; - } - - ins = bsearch(name, arch->instructions, nmemb, sizeof(struct ins), ins__key_cmp); - if (ins) - return ins->ops; - - if (arch->insn_suffix) { - char tmp[32]; - char suffix; - size_t len = strlen(name); - - if (len == 0 || len >= sizeof(tmp)) - return NULL; - - suffix = name[len - 1]; - if (strchr(arch->insn_suffix, suffix) == NULL) - return NULL; - - strcpy(tmp, name); - tmp[len - 1] = '\0'; /* remove the suffix and check again */ - - ins = bsearch(tmp, arch->instructions, nmemb, sizeof(struct ins), ins__key_cmp); - } - return ins ? ins->ops : NULL; -} - -static struct ins_ops *ins__find(struct arch *arch, const char *name) -{ - struct ins_ops *ops = __ins__find(arch, name); - - if (!ops && arch->associate_instruction_ops) - ops = arch->associate_instruction_ops(arch, name); - - return ops; -} - -static int arch__key_cmp(const void *name, const void *archp) -{ - const struct arch *arch = archp; - - return strcmp(name, arch->name); -} - -static int arch__cmp(const void *a, const void *b) -{ - const struct arch *aa = a; - const struct arch *ab = b; - - return strcmp(aa->name, ab->name); -} - -static void arch__sort(void) -{ - const int nmemb = ARRAY_SIZE(architectures); - - qsort(architectures, nmemb, sizeof(struct arch), arch__cmp); -} - -static struct arch *arch__find(const char *name) -{ - const int nmemb = ARRAY_SIZE(architectures); - static bool sorted; - - if (!sorted) { - arch__sort(); - sorted = true; - } - - return bsearch(name, architectures, nmemb, sizeof(struct arch), arch__key_cmp); -} - -bool arch__is(struct arch *arch, const char *name) -{ - return !strcmp(arch->name, name); -} - /* symbol histogram: key = offset << 16 | evsel->core.idx */ static size_t sym_hist_hash(long key, void *ctx __maybe_unused) { @@ -1214,212 +420,76 @@ static void annotation__count_and_fill(struct annotation *notes, u64 start, u64 branch->cover_insn += cover_insn; } } -} - -static int annotation__compute_ipc(struct annotation *notes, size_t size) -{ - int err = 0; - s64 offset; - - if (!notes->branch || !notes->branch->cycles_hist) - return 0; - - notes->branch->total_insn = annotation__count_insn(notes, 0, size - 1); - notes->branch->hit_cycles = 0; - notes->branch->hit_insn = 0; - notes->branch->cover_insn = 0; - - annotation__lock(notes); - for (offset = size - 1; offset >= 0; --offset) { - struct cyc_hist *ch; - - ch = ¬es->branch->cycles_hist[offset]; - if (ch && ch->cycles) { - struct annotation_line *al; - - al = notes->src->offsets[offset]; - if (al && al->cycles == NULL) { - al->cycles = zalloc(sizeof(*al->cycles)); - if (al->cycles == NULL) { - err = ENOMEM; - break; - } - } - if (ch->have_start) - annotation__count_and_fill(notes, ch->start, offset, ch); - if (al && ch->num_aggr) { - al->cycles->avg = ch->cycles_aggr / ch->num_aggr; - al->cycles->max = ch->cycles_max; - al->cycles->min = ch->cycles_min; - } - } - } - - if (err) { - while (++offset < (s64)size) { - struct cyc_hist *ch = ¬es->branch->cycles_hist[offset]; - - if (ch && ch->cycles) { - struct annotation_line *al = notes->src->offsets[offset]; - if (al) - zfree(&al->cycles); - } - } - } - - annotation__unlock(notes); - return 0; -} - -int addr_map_symbol__inc_samples(struct addr_map_symbol *ams, struct perf_sample *sample, - struct evsel *evsel) -{ - return symbol__inc_addr_samples(&ams->ms, evsel, ams->al_addr, sample); -} - -int hist_entry__inc_addr_samples(struct hist_entry *he, struct perf_sample *sample, - struct evsel *evsel, u64 ip) -{ - return symbol__inc_addr_samples(&he->ms, evsel, ip, sample); -} - -static void disasm_line__init_ins(struct disasm_line *dl, struct arch *arch, struct map_symbol *ms) -{ - dl->ins.ops = ins__find(arch, dl->ins.name); - - if (!dl->ins.ops) - return; - - if (dl->ins.ops->parse && dl->ins.ops->parse(arch, &dl->ops, ms) < 0) - dl->ins.ops = NULL; -} - -static int disasm_line__parse(char *line, const char **namep, char **rawp) -{ - char tmp, *name = skip_spaces(line); - - if (name[0] == '\0') - return -1; - - *rawp = name + 1; - - while ((*rawp)[0] != '\0' && !isspace((*rawp)[0])) - ++*rawp; - - tmp = (*rawp)[0]; - (*rawp)[0] = '\0'; - *namep = strdup(name); - - if (*namep == NULL) - goto out; - - (*rawp)[0] = tmp; - *rawp = strim(*rawp); - - return 0; - -out: - return -1; -} - -struct annotate_args { - struct arch *arch; - struct map_symbol ms; - struct evsel *evsel; - struct annotation_options *options; - s64 offset; - char *line; - int line_nr; - char *fileloc; -}; - -static void annotation_line__init(struct annotation_line *al, - struct annotate_args *args, - int nr) -{ - al->offset = args->offset; - al->line = strdup(args->line); - al->line_nr = args->line_nr; - al->fileloc = args->fileloc; - al->data_nr = nr; -} - -static void annotation_line__exit(struct annotation_line *al) -{ - zfree_srcline(&al->path); - zfree(&al->line); - zfree(&al->cycles); -} - -static size_t disasm_line_size(int nr) -{ - struct annotation_line *al; - - return (sizeof(struct disasm_line) + (sizeof(al->data[0]) * nr)); -} - -/* - * Allocating the disasm annotation line data with - * following structure: - * - * ------------------------------------------- - * struct disasm_line | struct annotation_line - * ------------------------------------------- - * - * We have 'struct annotation_line' member as last member - * of 'struct disasm_line' to have an easy access. - */ -static struct disasm_line *disasm_line__new(struct annotate_args *args) +} + +static int annotation__compute_ipc(struct annotation *notes, size_t size) { - struct disasm_line *dl = NULL; - int nr = 1; + int err = 0; + s64 offset; - if (evsel__is_group_event(args->evsel)) - nr = args->evsel->core.nr_members; + if (!notes->branch || !notes->branch->cycles_hist) + return 0; - dl = zalloc(disasm_line_size(nr)); - if (!dl) - return NULL; + notes->branch->total_insn = annotation__count_insn(notes, 0, size - 1); + notes->branch->hit_cycles = 0; + notes->branch->hit_insn = 0; + notes->branch->cover_insn = 0; - annotation_line__init(&dl->al, args, nr); - if (dl->al.line == NULL) - goto out_delete; + annotation__lock(notes); + for (offset = size - 1; offset >= 0; --offset) { + struct cyc_hist *ch; - if (args->offset != -1) { - if (disasm_line__parse(dl->al.line, &dl->ins.name, &dl->ops.raw) < 0) - goto out_free_line; + ch = ¬es->branch->cycles_hist[offset]; + if (ch && ch->cycles) { + struct annotation_line *al; - disasm_line__init_ins(dl, args->arch, &args->ms); + al = notes->src->offsets[offset]; + if (al && al->cycles == NULL) { + al->cycles = zalloc(sizeof(*al->cycles)); + if (al->cycles == NULL) { + err = ENOMEM; + break; + } + } + if (ch->have_start) + annotation__count_and_fill(notes, ch->start, offset, ch); + if (al && ch->num_aggr) { + al->cycles->avg = ch->cycles_aggr / ch->num_aggr; + al->cycles->max = ch->cycles_max; + al->cycles->min = ch->cycles_min; + } + } } - return dl; + if (err) { + while (++offset < (s64)size) { + struct cyc_hist *ch = ¬es->branch->cycles_hist[offset]; -out_free_line: - zfree(&dl->al.line); -out_delete: - free(dl); - return NULL; + if (ch && ch->cycles) { + struct annotation_line *al = notes->src->offsets[offset]; + if (al) + zfree(&al->cycles); + } + } + } + + annotation__unlock(notes); + return 0; } -void disasm_line__free(struct disasm_line *dl) +int addr_map_symbol__inc_samples(struct addr_map_symbol *ams, struct perf_sample *sample, + struct evsel *evsel) { - if (dl->ins.ops && dl->ins.ops->free) - dl->ins.ops->free(&dl->ops); - else - ins__delete(&dl->ops); - zfree(&dl->ins.name); - annotation_line__exit(&dl->al); - free(dl); + return symbol__inc_addr_samples(&ams->ms, evsel, ams->al_addr, sample); } -int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw, int max_ins_name) +int hist_entry__inc_addr_samples(struct hist_entry *he, struct perf_sample *sample, + struct evsel *evsel, u64 ip) { - if (raw || !dl->ins.ops) - return scnprintf(bf, size, "%-*s %s", max_ins_name, dl->ins.name, dl->ops.raw); - - return ins__scnprintf(&dl->ins, bf, size, &dl->ops, max_ins_name); + return symbol__inc_addr_samples(&he->ms, evsel, ip, sample); } + void annotation__exit(struct annotation *notes) { annotated_source__delete(notes->src); @@ -1478,8 +548,7 @@ bool annotation__trylock(struct annotation *notes) return mutex_trylock(mutex); } - -static void annotation_line__add(struct annotation_line *al, struct list_head *head) +void annotation_line__add(struct annotation_line *al, struct list_head *head) { list_add_tail(&al->node, head); } @@ -1689,673 +758,6 @@ annotation_line__print(struct annotation_line *al, struct symbol *sym, u64 start return 0; } -/* - * symbol__parse_objdump_line() parses objdump output (with -d --no-show-raw) - * which looks like following - * - * 0000000000415500 <_init>: - * 415500: sub $0x8,%rsp - * 415504: mov 0x2f5ad5(%rip),%rax # 70afe0 <_DYNAMIC+0x2f8> - * 41550b: test %rax,%rax - * 41550e: je 415515 <_init+0x15> - * 415510: callq 416e70 <__gmon_start__@plt> - * 415515: add $0x8,%rsp - * 415519: retq - * - * it will be parsed and saved into struct disasm_line as - * - * - * The offset will be a relative offset from the start of the symbol and -1 - * means that it's not a disassembly line so should be treated differently. - * The ops.raw part will be parsed further according to type of the instruction. - */ -static int symbol__parse_objdump_line(struct symbol *sym, - struct annotate_args *args, - char *parsed_line, int *line_nr, char **fileloc) -{ - struct map *map = args->ms.map; - struct annotation *notes = symbol__annotation(sym); - struct disasm_line *dl; - char *tmp; - s64 line_ip, offset = -1; - regmatch_t match[2]; - - /* /filename:linenr ? Save line number and ignore. */ - if (regexec(&file_lineno, parsed_line, 2, match, 0) == 0) { - *line_nr = atoi(parsed_line + match[1].rm_so); - free(*fileloc); - *fileloc = strdup(parsed_line); - return 0; - } - - /* Process hex address followed by ':'. */ - line_ip = strtoull(parsed_line, &tmp, 16); - if (parsed_line != tmp && tmp[0] == ':' && tmp[1] != '\0') { - u64 start = map__rip_2objdump(map, sym->start), - end = map__rip_2objdump(map, sym->end); - - offset = line_ip - start; - if ((u64)line_ip < start || (u64)line_ip >= end) - offset = -1; - else - parsed_line = tmp + 1; - } - - args->offset = offset; - args->line = parsed_line; - args->line_nr = *line_nr; - args->fileloc = *fileloc; - args->ms.sym = sym; - - dl = disasm_line__new(args); - (*line_nr)++; - - if (dl == NULL) - return -1; - - if (!disasm_line__has_local_offset(dl)) { - dl->ops.target.offset = dl->ops.target.addr - - map__rip_2objdump(map, sym->start); - dl->ops.target.offset_avail = true; - } - - /* kcore has no symbols, so add the call target symbol */ - if (dl->ins.ops && ins__is_call(&dl->ins) && !dl->ops.target.sym) { - struct addr_map_symbol target = { - .addr = dl->ops.target.addr, - .ms = { .map = map, }, - }; - - if (!maps__find_ams(args->ms.maps, &target) && - target.ms.sym->start == target.al_addr) - dl->ops.target.sym = target.ms.sym; - } - - annotation_line__add(&dl->al, ¬es->src->source); - return 0; -} - -static __attribute__((constructor)) void symbol__init_regexpr(void) -{ - regcomp(&file_lineno, "^/[^:]+:([0-9]+)", REG_EXTENDED); -} - -static void delete_last_nop(struct symbol *sym) -{ - struct annotation *notes = symbol__annotation(sym); - struct list_head *list = ¬es->src->source; - struct disasm_line *dl; - - while (!list_empty(list)) { - dl = list_entry(list->prev, struct disasm_line, al.node); - - if (dl->ins.ops) { - if (!ins__is_nop(&dl->ins)) - return; - } else { - if (!strstr(dl->al.line, " nop ") && - !strstr(dl->al.line, " nopl ") && - !strstr(dl->al.line, " nopw ")) - return; - } - - list_del_init(&dl->al.node); - disasm_line__free(dl); - } -} - -int symbol__strerror_disassemble(struct map_symbol *ms, int errnum, char *buf, size_t buflen) -{ - struct dso *dso = map__dso(ms->map); - - BUG_ON(buflen == 0); - - if (errnum >= 0) { - str_error_r(errnum, buf, buflen); - return 0; - } - - switch (errnum) { - case SYMBOL_ANNOTATE_ERRNO__NO_VMLINUX: { - char bf[SBUILD_ID_SIZE + 15] = " with build id "; - char *build_id_msg = NULL; - - if (dso->has_build_id) { - build_id__sprintf(&dso->bid, bf + 15); - build_id_msg = bf; - } - scnprintf(buf, buflen, - "No vmlinux file%s\nwas found in the path.\n\n" - "Note that annotation using /proc/kcore requires CAP_SYS_RAWIO capability.\n\n" - "Please use:\n\n" - " perf buildid-cache -vu vmlinux\n\n" - "or:\n\n" - " --vmlinux vmlinux\n", build_id_msg ?: ""); - } - break; - case SYMBOL_ANNOTATE_ERRNO__NO_LIBOPCODES_FOR_BPF: - scnprintf(buf, buflen, "Please link with binutils's libopcode to enable BPF annotation"); - break; - case SYMBOL_ANNOTATE_ERRNO__ARCH_INIT_REGEXP: - scnprintf(buf, buflen, "Problems with arch specific instruction name regular expressions."); - break; - case SYMBOL_ANNOTATE_ERRNO__ARCH_INIT_CPUID_PARSING: - scnprintf(buf, buflen, "Problems while parsing the CPUID in the arch specific initialization."); - break; - case SYMBOL_ANNOTATE_ERRNO__BPF_INVALID_FILE: - scnprintf(buf, buflen, "Invalid BPF file: %s.", dso->long_name); - break; - case SYMBOL_ANNOTATE_ERRNO__BPF_MISSING_BTF: - scnprintf(buf, buflen, "The %s BPF file has no BTF section, compile with -g or use pahole -J.", - dso->long_name); - break; - default: - scnprintf(buf, buflen, "Internal error: Invalid %d error code\n", errnum); - break; - } - - return 0; -} - -static int dso__disassemble_filename(struct dso *dso, char *filename, size_t filename_size) -{ - char linkname[PATH_MAX]; - char *build_id_filename; - char *build_id_path = NULL; - char *pos; - int len; - - if (dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS && - !dso__is_kcore(dso)) - return SYMBOL_ANNOTATE_ERRNO__NO_VMLINUX; - - build_id_filename = dso__build_id_filename(dso, NULL, 0, false); - if (build_id_filename) { - __symbol__join_symfs(filename, filename_size, build_id_filename); - free(build_id_filename); - } else { - if (dso->has_build_id) - return ENOMEM; - goto fallback; - } - - build_id_path = strdup(filename); - if (!build_id_path) - return ENOMEM; - - /* - * old style build-id cache has name of XX/XXXXXXX.. while - * new style has XX/XXXXXXX../{elf,kallsyms,vdso}. - * extract the build-id part of dirname in the new style only. - */ - pos = strrchr(build_id_path, '/'); - if (pos && strlen(pos) < SBUILD_ID_SIZE - 2) - dirname(build_id_path); - - if (dso__is_kcore(dso)) - goto fallback; - - len = readlink(build_id_path, linkname, sizeof(linkname) - 1); - if (len < 0) - goto fallback; - - linkname[len] = '\0'; - if (strstr(linkname, DSO__NAME_KALLSYMS) || - access(filename, R_OK)) { -fallback: - /* - * If we don't have build-ids or the build-id file isn't in the - * cache, or is just a kallsyms file, well, lets hope that this - * DSO is the same as when 'perf record' ran. - */ - if (dso->kernel && dso->long_name[0] == '/') - snprintf(filename, filename_size, "%s", dso->long_name); - else - __symbol__join_symfs(filename, filename_size, dso->long_name); - - mutex_lock(&dso->lock); - if (access(filename, R_OK) && errno == ENOENT && dso->nsinfo) { - char *new_name = dso__filename_with_chroot(dso, filename); - if (new_name) { - strlcpy(filename, new_name, filename_size); - free(new_name); - } - } - mutex_unlock(&dso->lock); - } - - free(build_id_path); - return 0; -} - -#if defined(HAVE_LIBBFD_SUPPORT) && defined(HAVE_LIBBPF_SUPPORT) -#define PACKAGE "perf" -#include -#include -#include -#include -#include -#include -#include - -static int symbol__disassemble_bpf(struct symbol *sym, - struct annotate_args *args) -{ - struct annotation *notes = symbol__annotation(sym); - struct bpf_prog_linfo *prog_linfo = NULL; - struct bpf_prog_info_node *info_node; - int len = sym->end - sym->start; - disassembler_ftype disassemble; - struct map *map = args->ms.map; - struct perf_bpil *info_linear; - struct disassemble_info info; - struct dso *dso = map__dso(map); - int pc = 0, count, sub_id; - struct btf *btf = NULL; - char tpath[PATH_MAX]; - size_t buf_size; - int nr_skip = 0; - char *buf; - bfd *bfdf; - int ret; - FILE *s; - - if (dso->binary_type != DSO_BINARY_TYPE__BPF_PROG_INFO) - return SYMBOL_ANNOTATE_ERRNO__BPF_INVALID_FILE; - - pr_debug("%s: handling sym %s addr %" PRIx64 " len %" PRIx64 "\n", __func__, - sym->name, sym->start, sym->end - sym->start); - - memset(tpath, 0, sizeof(tpath)); - perf_exe(tpath, sizeof(tpath)); - - bfdf = bfd_openr(tpath, NULL); - if (bfdf == NULL) - abort(); - - if (!bfd_check_format(bfdf, bfd_object)) - abort(); - - s = open_memstream(&buf, &buf_size); - if (!s) { - ret = errno; - goto out; - } - init_disassemble_info_compat(&info, s, - (fprintf_ftype) fprintf, - fprintf_styled); - info.arch = bfd_get_arch(bfdf); - info.mach = bfd_get_mach(bfdf); - - info_node = perf_env__find_bpf_prog_info(dso->bpf_prog.env, - dso->bpf_prog.id); - if (!info_node) { - ret = SYMBOL_ANNOTATE_ERRNO__BPF_MISSING_BTF; - goto out; - } - info_linear = info_node->info_linear; - sub_id = dso->bpf_prog.sub_id; - - info.buffer = (void *)(uintptr_t)(info_linear->info.jited_prog_insns); - info.buffer_length = info_linear->info.jited_prog_len; - - if (info_linear->info.nr_line_info) - prog_linfo = bpf_prog_linfo__new(&info_linear->info); - - if (info_linear->info.btf_id) { - struct btf_node *node; - - node = perf_env__find_btf(dso->bpf_prog.env, - info_linear->info.btf_id); - if (node) - btf = btf__new((__u8 *)(node->data), - node->data_size); - } - - disassemble_init_for_target(&info); - -#ifdef DISASM_FOUR_ARGS_SIGNATURE - disassemble = disassembler(info.arch, - bfd_big_endian(bfdf), - info.mach, - bfdf); -#else - disassemble = disassembler(bfdf); -#endif - if (disassemble == NULL) - abort(); - - fflush(s); - do { - const struct bpf_line_info *linfo = NULL; - struct disasm_line *dl; - size_t prev_buf_size; - const char *srcline; - u64 addr; - - addr = pc + ((u64 *)(uintptr_t)(info_linear->info.jited_ksyms))[sub_id]; - count = disassemble(pc, &info); - - if (prog_linfo) - linfo = bpf_prog_linfo__lfind_addr_func(prog_linfo, - addr, sub_id, - nr_skip); - - if (linfo && btf) { - srcline = btf__name_by_offset(btf, linfo->line_off); - nr_skip++; - } else - srcline = NULL; - - fprintf(s, "\n"); - prev_buf_size = buf_size; - fflush(s); - - if (!annotate_opts.hide_src_code && srcline) { - args->offset = -1; - args->line = strdup(srcline); - args->line_nr = 0; - args->fileloc = NULL; - args->ms.sym = sym; - dl = disasm_line__new(args); - if (dl) { - annotation_line__add(&dl->al, - ¬es->src->source); - } - } - - args->offset = pc; - args->line = buf + prev_buf_size; - args->line_nr = 0; - args->fileloc = NULL; - args->ms.sym = sym; - dl = disasm_line__new(args); - if (dl) - annotation_line__add(&dl->al, ¬es->src->source); - - pc += count; - } while (count > 0 && pc < len); - - ret = 0; -out: - free(prog_linfo); - btf__free(btf); - fclose(s); - bfd_close(bfdf); - return ret; -} -#else // defined(HAVE_LIBBFD_SUPPORT) && defined(HAVE_LIBBPF_SUPPORT) -static int symbol__disassemble_bpf(struct symbol *sym __maybe_unused, - struct annotate_args *args __maybe_unused) -{ - return SYMBOL_ANNOTATE_ERRNO__NO_LIBOPCODES_FOR_BPF; -} -#endif // defined(HAVE_LIBBFD_SUPPORT) && defined(HAVE_LIBBPF_SUPPORT) - -static int -symbol__disassemble_bpf_image(struct symbol *sym, - struct annotate_args *args) -{ - struct annotation *notes = symbol__annotation(sym); - struct disasm_line *dl; - - args->offset = -1; - args->line = strdup("to be implemented"); - args->line_nr = 0; - args->fileloc = NULL; - dl = disasm_line__new(args); - if (dl) - annotation_line__add(&dl->al, ¬es->src->source); - - zfree(&args->line); - return 0; -} - -/* - * Possibly create a new version of line with tabs expanded. Returns the - * existing or new line, storage is updated if a new line is allocated. If - * allocation fails then NULL is returned. - */ -static char *expand_tabs(char *line, char **storage, size_t *storage_len) -{ - size_t i, src, dst, len, new_storage_len, num_tabs; - char *new_line; - size_t line_len = strlen(line); - - for (num_tabs = 0, i = 0; i < line_len; i++) - if (line[i] == '\t') - num_tabs++; - - if (num_tabs == 0) - return line; - - /* - * Space for the line and '\0', less the leading and trailing - * spaces. Each tab may introduce 7 additional spaces. - */ - new_storage_len = line_len + 1 + (num_tabs * 7); - - new_line = malloc(new_storage_len); - if (new_line == NULL) { - pr_err("Failure allocating memory for tab expansion\n"); - return NULL; - } - - /* - * Copy regions starting at src and expand tabs. If there are two - * adjacent tabs then 'src == i', the memcpy is of size 0 and the spaces - * are inserted. - */ - for (i = 0, src = 0, dst = 0; i < line_len && num_tabs; i++) { - if (line[i] == '\t') { - len = i - src; - memcpy(&new_line[dst], &line[src], len); - dst += len; - new_line[dst++] = ' '; - while (dst % 8 != 0) - new_line[dst++] = ' '; - src = i + 1; - num_tabs--; - } - } - - /* Expand the last region. */ - len = line_len - src; - memcpy(&new_line[dst], &line[src], len); - dst += len; - new_line[dst] = '\0'; - - free(*storage); - *storage = new_line; - *storage_len = new_storage_len; - return new_line; - -} - -static int symbol__disassemble(struct symbol *sym, struct annotate_args *args) -{ - struct annotation_options *opts = &annotate_opts; - struct map *map = args->ms.map; - struct dso *dso = map__dso(map); - char *command; - FILE *file; - char symfs_filename[PATH_MAX]; - struct kcore_extract kce; - bool delete_extract = false; - bool decomp = false; - int lineno = 0; - char *fileloc = NULL; - int nline; - char *line; - size_t line_len; - const char *objdump_argv[] = { - "/bin/sh", - "-c", - NULL, /* Will be the objdump command to run. */ - "--", - NULL, /* Will be the symfs path. */ - NULL, - }; - struct child_process objdump_process; - int err = dso__disassemble_filename(dso, symfs_filename, sizeof(symfs_filename)); - - if (err) - return err; - - pr_debug("%s: filename=%s, sym=%s, start=%#" PRIx64 ", end=%#" PRIx64 "\n", __func__, - symfs_filename, sym->name, map__unmap_ip(map, sym->start), - map__unmap_ip(map, sym->end)); - - pr_debug("annotating [%p] %30s : [%p] %30s\n", - dso, dso->long_name, sym, sym->name); - - if (dso->binary_type == DSO_BINARY_TYPE__BPF_PROG_INFO) { - return symbol__disassemble_bpf(sym, args); - } else if (dso->binary_type == DSO_BINARY_TYPE__BPF_IMAGE) { - return symbol__disassemble_bpf_image(sym, args); - } else if (dso__is_kcore(dso)) { - kce.kcore_filename = symfs_filename; - kce.addr = map__rip_2objdump(map, sym->start); - kce.offs = sym->start; - kce.len = sym->end - sym->start; - if (!kcore_extract__create(&kce)) { - delete_extract = true; - strlcpy(symfs_filename, kce.extract_filename, - sizeof(symfs_filename)); - } - } else if (dso__needs_decompress(dso)) { - char tmp[KMOD_DECOMP_LEN]; - - if (dso__decompress_kmodule_path(dso, symfs_filename, - tmp, sizeof(tmp)) < 0) - return -1; - - decomp = true; - strcpy(symfs_filename, tmp); - } - - err = asprintf(&command, - "%s %s%s --start-address=0x%016" PRIx64 - " --stop-address=0x%016" PRIx64 - " %s -d %s %s %s %c%s%c %s%s -C \"$1\"", - opts->objdump_path ?: "objdump", - opts->disassembler_style ? "-M " : "", - opts->disassembler_style ?: "", - map__rip_2objdump(map, sym->start), - map__rip_2objdump(map, sym->end), - opts->show_linenr ? "-l" : "", - opts->show_asm_raw ? "" : "--no-show-raw-insn", - opts->annotate_src ? "-S" : "", - opts->prefix ? "--prefix " : "", - opts->prefix ? '"' : ' ', - opts->prefix ?: "", - opts->prefix ? '"' : ' ', - opts->prefix_strip ? "--prefix-strip=" : "", - opts->prefix_strip ?: ""); - - if (err < 0) { - pr_err("Failure allocating memory for the command to run\n"); - goto out_remove_tmp; - } - - pr_debug("Executing: %s\n", command); - - objdump_argv[2] = command; - objdump_argv[4] = symfs_filename; - - /* Create a pipe to read from for stdout */ - memset(&objdump_process, 0, sizeof(objdump_process)); - objdump_process.argv = objdump_argv; - objdump_process.out = -1; - objdump_process.err = -1; - objdump_process.no_stderr = 1; - if (start_command(&objdump_process)) { - pr_err("Failure starting to run %s\n", command); - err = -1; - goto out_free_command; - } - - file = fdopen(objdump_process.out, "r"); - if (!file) { - pr_err("Failure creating FILE stream for %s\n", command); - /* - * If we were using debug info should retry with - * original binary. - */ - err = -1; - goto out_close_stdout; - } - - /* Storage for getline. */ - line = NULL; - line_len = 0; - - nline = 0; - while (!feof(file)) { - const char *match; - char *expanded_line; - - if (getline(&line, &line_len, file) < 0 || !line) - break; - - /* Skip lines containing "filename:" */ - match = strstr(line, symfs_filename); - if (match && match[strlen(symfs_filename)] == ':') - continue; - - expanded_line = strim(line); - expanded_line = expand_tabs(expanded_line, &line, &line_len); - if (!expanded_line) - break; - - /* - * The source code line number (lineno) needs to be kept in - * across calls to symbol__parse_objdump_line(), so that it - * can associate it with the instructions till the next one. - * See disasm_line__new() and struct disasm_line::line_nr. - */ - if (symbol__parse_objdump_line(sym, args, expanded_line, - &lineno, &fileloc) < 0) - break; - nline++; - } - free(line); - free(fileloc); - - err = finish_command(&objdump_process); - if (err) - pr_err("Error running %s\n", command); - - if (nline == 0) { - err = -1; - pr_err("No output from %s\n", command); - } - - /* - * kallsyms does not have symbol sizes so there may a nop at the end. - * Remove it. - */ - if (dso__is_kcore(dso)) - delete_last_nop(sym); - - fclose(file); - -out_close_stdout: - close(objdump_process.out); - -out_free_command: - free(command); - -out_remove_tmp: - if (decomp) - unlink(symfs_filename); - - if (delete_extract) - kcore_extract__delete(&kce); - - return err; -} - static void calc_percent(struct annotation *notes, struct evsel *evsel, struct annotation_data *data, diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 98f556af637c..b3007c9966fd 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -13,10 +13,10 @@ #include "mutex.h" #include "spark.h" #include "hashmap.h" +#include "disasm.h" struct hist_browser_timer; struct hist_entry; -struct ins_ops; struct map; struct map_symbol; struct addr_map_symbol; @@ -26,60 +26,6 @@ struct evsel; struct symbol; struct annotated_data_type; -struct ins { - const char *name; - struct ins_ops *ops; -}; - -struct ins_operands { - char *raw; - struct { - char *raw; - char *name; - struct symbol *sym; - u64 addr; - s64 offset; - bool offset_avail; - bool outside; - bool multi_regs; - } target; - union { - struct { - char *raw; - char *name; - u64 addr; - bool multi_regs; - } source; - struct { - struct ins ins; - struct ins_operands *ops; - } locked; - struct { - char *raw_comment; - char *raw_func_start; - } jump; - }; -}; - -struct arch; - -bool arch__is(struct arch *arch, const char *name); - -struct ins_ops { - void (*free)(struct ins_operands *ops); - int (*parse)(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms); - int (*scnprintf)(struct ins *ins, char *bf, size_t size, - struct ins_operands *ops, int max_ins_name); -}; - -bool ins__is_jump(const struct ins *ins); -bool ins__is_call(const struct ins *ins); -bool ins__is_nop(const struct ins *ins); -bool ins__is_ret(const struct ins *ins); -bool ins__is_lock(const struct ins *ins); -int ins__scnprintf(struct ins *ins, char *bf, size_t size, struct ins_operands *ops, int max_ins_name); -bool ins__is_fused(struct arch *arch, const char *ins1, const char *ins2); - #define ANNOTATION__IPC_WIDTH 6 #define ANNOTATION__CYCLES_WIDTH 6 #define ANNOTATION__MINMAX_CYCLES_WIDTH 19 @@ -172,6 +118,8 @@ struct disasm_line { struct annotation_line al; }; +void annotation_line__add(struct annotation_line *al, struct list_head *head); + static inline double annotation_data__percent(struct annotation_data *data, unsigned int which) { @@ -213,7 +161,6 @@ static inline bool disasm_line__has_local_offset(const struct disasm_line *dl) */ bool disasm_line__is_valid_local_jump(struct disasm_line *dl, struct symbol *sym); -void disasm_line__free(struct disasm_line *dl); struct annotation_line * annotation_line__next(struct annotation_line *pos, struct list_head *head); @@ -236,7 +183,6 @@ int __annotation__scnprintf_samples_period(struct annotation *notes, struct evsel *evsel, bool show_freq); -int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw, int max_ins_name); size_t disasm__fprintf(struct list_head *head, FILE *fp); void symbol__calc_percent(struct symbol *sym, struct evsel *evsel); diff --git a/tools/perf/util/disasm.c b/tools/perf/util/disasm.c new file mode 100644 index 000000000000..21a43b07e8b5 --- /dev/null +++ b/tools/perf/util/disasm.c @@ -0,0 +1,1591 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "annotate.h" +#include "build-id.h" +#include "debug.h" +#include "disasm.h" +#include "dso.h" +#include "env.h" +#include "evsel.h" +#include "map.h" +#include "maps.h" +#include "srcline.h" +#include "symbol.h" +#include "util.h" + +static regex_t file_lineno; + +/* These can be referred from the arch-dependent code */ +static struct ins_ops call_ops; +static struct ins_ops dec_ops; +static struct ins_ops jump_ops; +static struct ins_ops mov_ops; +static struct ins_ops nop_ops; +static struct ins_ops lock_ops; +static struct ins_ops ret_ops; + +static int jump__scnprintf(struct ins *ins, char *bf, size_t size, + struct ins_operands *ops, int max_ins_name); +static int call__scnprintf(struct ins *ins, char *bf, size_t size, + struct ins_operands *ops, int max_ins_name); + +static void ins__sort(struct arch *arch); +static int disasm_line__parse(char *line, const char **namep, char **rawp); + +static __attribute__((constructor)) void symbol__init_regexpr(void) +{ + regcomp(&file_lineno, "^/[^:]+:([0-9]+)", REG_EXTENDED); +} + +static int arch__grow_instructions(struct arch *arch) +{ + struct ins *new_instructions; + size_t new_nr_allocated; + + if (arch->nr_instructions_allocated == 0 && arch->instructions) + goto grow_from_non_allocated_table; + + new_nr_allocated = arch->nr_instructions_allocated + 128; + new_instructions = realloc(arch->instructions, new_nr_allocated * sizeof(struct ins)); + if (new_instructions == NULL) + return -1; + +out_update_instructions: + arch->instructions = new_instructions; + arch->nr_instructions_allocated = new_nr_allocated; + return 0; + +grow_from_non_allocated_table: + new_nr_allocated = arch->nr_instructions + 128; + new_instructions = calloc(new_nr_allocated, sizeof(struct ins)); + if (new_instructions == NULL) + return -1; + + memcpy(new_instructions, arch->instructions, arch->nr_instructions); + goto out_update_instructions; +} + +static int arch__associate_ins_ops(struct arch* arch, const char *name, struct ins_ops *ops) +{ + struct ins *ins; + + if (arch->nr_instructions == arch->nr_instructions_allocated && + arch__grow_instructions(arch)) + return -1; + + ins = &arch->instructions[arch->nr_instructions]; + ins->name = strdup(name); + if (!ins->name) + return -1; + + ins->ops = ops; + arch->nr_instructions++; + + ins__sort(arch); + return 0; +} + +#include "arch/arc/annotate/instructions.c" +#include "arch/arm/annotate/instructions.c" +#include "arch/arm64/annotate/instructions.c" +#include "arch/csky/annotate/instructions.c" +#include "arch/loongarch/annotate/instructions.c" +#include "arch/mips/annotate/instructions.c" +#include "arch/x86/annotate/instructions.c" +#include "arch/powerpc/annotate/instructions.c" +#include "arch/riscv64/annotate/instructions.c" +#include "arch/s390/annotate/instructions.c" +#include "arch/sparc/annotate/instructions.c" + +static struct arch architectures[] = { + { + .name = "arc", + .init = arc__annotate_init, + }, + { + .name = "arm", + .init = arm__annotate_init, + }, + { + .name = "arm64", + .init = arm64__annotate_init, + }, + { + .name = "csky", + .init = csky__annotate_init, + }, + { + .name = "mips", + .init = mips__annotate_init, + .objdump = { + .comment_char = '#', + }, + }, + { + .name = "x86", + .init = x86__annotate_init, + .instructions = x86__instructions, + .nr_instructions = ARRAY_SIZE(x86__instructions), + .insn_suffix = "bwlq", + .objdump = { + .comment_char = '#', + .register_char = '%', + .memory_ref_char = '(', + .imm_char = '$', + }, + }, + { + .name = "powerpc", + .init = powerpc__annotate_init, + }, + { + .name = "riscv64", + .init = riscv64__annotate_init, + }, + { + .name = "s390", + .init = s390__annotate_init, + .objdump = { + .comment_char = '#', + }, + }, + { + .name = "sparc", + .init = sparc__annotate_init, + .objdump = { + .comment_char = '#', + }, + }, + { + .name = "loongarch", + .init = loongarch__annotate_init, + .objdump = { + .comment_char = '#', + }, + }, +}; + +static int arch__key_cmp(const void *name, const void *archp) +{ + const struct arch *arch = archp; + + return strcmp(name, arch->name); +} + +static int arch__cmp(const void *a, const void *b) +{ + const struct arch *aa = a; + const struct arch *ab = b; + + return strcmp(aa->name, ab->name); +} + +static void arch__sort(void) +{ + const int nmemb = ARRAY_SIZE(architectures); + + qsort(architectures, nmemb, sizeof(struct arch), arch__cmp); +} + +struct arch *arch__find(const char *name) +{ + const int nmemb = ARRAY_SIZE(architectures); + static bool sorted; + + if (!sorted) { + arch__sort(); + sorted = true; + } + + return bsearch(name, architectures, nmemb, sizeof(struct arch), arch__key_cmp); +} + +bool arch__is(struct arch *arch, const char *name) +{ + return !strcmp(arch->name, name); +} + +static void ins_ops__delete(struct ins_operands *ops) +{ + if (ops == NULL) + return; + zfree(&ops->source.raw); + zfree(&ops->source.name); + zfree(&ops->target.raw); + zfree(&ops->target.name); +} + +static int ins__raw_scnprintf(struct ins *ins, char *bf, size_t size, + struct ins_operands *ops, int max_ins_name) +{ + return scnprintf(bf, size, "%-*s %s", max_ins_name, ins->name, ops->raw); +} + +int ins__scnprintf(struct ins *ins, char *bf, size_t size, + struct ins_operands *ops, int max_ins_name) +{ + if (ins->ops->scnprintf) + return ins->ops->scnprintf(ins, bf, size, ops, max_ins_name); + + return ins__raw_scnprintf(ins, bf, size, ops, max_ins_name); +} + +bool ins__is_fused(struct arch *arch, const char *ins1, const char *ins2) +{ + if (!arch || !arch->ins_is_fused) + return false; + + return arch->ins_is_fused(arch, ins1, ins2); +} + +static int call__parse(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms) +{ + char *endptr, *tok, *name; + struct map *map = ms->map; + struct addr_map_symbol target = { + .ms = { .map = map, }, + }; + + ops->target.addr = strtoull(ops->raw, &endptr, 16); + + name = strchr(endptr, '<'); + if (name == NULL) + goto indirect_call; + + name++; + + if (arch->objdump.skip_functions_char && + strchr(name, arch->objdump.skip_functions_char)) + return -1; + + tok = strchr(name, '>'); + if (tok == NULL) + return -1; + + *tok = '\0'; + ops->target.name = strdup(name); + *tok = '>'; + + if (ops->target.name == NULL) + return -1; +find_target: + target.addr = map__objdump_2mem(map, ops->target.addr); + + if (maps__find_ams(ms->maps, &target) == 0 && + map__rip_2objdump(target.ms.map, map__map_ip(target.ms.map, target.addr)) == ops->target.addr) + ops->target.sym = target.ms.sym; + + return 0; + +indirect_call: + tok = strchr(endptr, '*'); + if (tok != NULL) { + endptr++; + + /* Indirect call can use a non-rip register and offset: callq *0x8(%rbx). + * Do not parse such instruction. */ + if (strstr(endptr, "(%r") == NULL) + ops->target.addr = strtoull(endptr, NULL, 16); + } + goto find_target; +} + +static int call__scnprintf(struct ins *ins, char *bf, size_t size, + struct ins_operands *ops, int max_ins_name) +{ + if (ops->target.sym) + return scnprintf(bf, size, "%-*s %s", max_ins_name, ins->name, ops->target.sym->name); + + if (ops->target.addr == 0) + return ins__raw_scnprintf(ins, bf, size, ops, max_ins_name); + + if (ops->target.name) + return scnprintf(bf, size, "%-*s %s", max_ins_name, ins->name, ops->target.name); + + return scnprintf(bf, size, "%-*s *%" PRIx64, max_ins_name, ins->name, ops->target.addr); +} + +static struct ins_ops call_ops = { + .parse = call__parse, + .scnprintf = call__scnprintf, +}; + +bool ins__is_call(const struct ins *ins) +{ + return ins->ops == &call_ops || ins->ops == &s390_call_ops || ins->ops == &loongarch_call_ops; +} + +/* + * Prevents from matching commas in the comment section, e.g.: + * ffff200008446e70: b.cs ffff2000084470f4 // b.hs, b.nlast + * + * and skip comma as part of function arguments, e.g.: + * 1d8b4ac + */ +static inline const char *validate_comma(const char *c, struct ins_operands *ops) +{ + if (ops->jump.raw_comment && c > ops->jump.raw_comment) + return NULL; + + if (ops->jump.raw_func_start && c > ops->jump.raw_func_start) + return NULL; + + return c; +} + +static int jump__parse(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms) +{ + struct map *map = ms->map; + struct symbol *sym = ms->sym; + struct addr_map_symbol target = { + .ms = { .map = map, }, + }; + const char *c = strchr(ops->raw, ','); + u64 start, end; + + ops->jump.raw_comment = strchr(ops->raw, arch->objdump.comment_char); + ops->jump.raw_func_start = strchr(ops->raw, '<'); + + c = validate_comma(c, ops); + + /* + * Examples of lines to parse for the _cpp_lex_token@@Base + * function: + * + * 1159e6c: jne 115aa32 <_cpp_lex_token@@Base+0xf92> + * 1159e8b: jne c469be + * + * The first is a jump to an offset inside the same function, + * the second is to another function, i.e. that 0xa72 is an + * offset in the cpp_named_operator2name@@base function. + */ + /* + * skip over possible up to 2 operands to get to address, e.g.: + * tbnz w0, #26, ffff0000083cd190 + */ + if (c++ != NULL) { + ops->target.addr = strtoull(c, NULL, 16); + if (!ops->target.addr) { + c = strchr(c, ','); + c = validate_comma(c, ops); + if (c++ != NULL) + ops->target.addr = strtoull(c, NULL, 16); + } + } else { + ops->target.addr = strtoull(ops->raw, NULL, 16); + } + + target.addr = map__objdump_2mem(map, ops->target.addr); + start = map__unmap_ip(map, sym->start); + end = map__unmap_ip(map, sym->end); + + ops->target.outside = target.addr < start || target.addr > end; + + /* + * FIXME: things like this in _cpp_lex_token (gcc's cc1 program): + + cpp_named_operator2name@@Base+0xa72 + + * Point to a place that is after the cpp_named_operator2name + * boundaries, i.e. in the ELF symbol table for cc1 + * cpp_named_operator2name is marked as being 32-bytes long, but it in + * fact is much larger than that, so we seem to need a symbols__find() + * routine that looks for >= current->start and < next_symbol->start, + * possibly just for C++ objects? + * + * For now lets just make some progress by marking jumps to outside the + * current function as call like. + * + * Actual navigation will come next, with further understanding of how + * the symbol searching and disassembly should be done. + */ + if (maps__find_ams(ms->maps, &target) == 0 && + map__rip_2objdump(target.ms.map, map__map_ip(target.ms.map, target.addr)) == ops->target.addr) + ops->target.sym = target.ms.sym; + + if (!ops->target.outside) { + ops->target.offset = target.addr - start; + ops->target.offset_avail = true; + } else { + ops->target.offset_avail = false; + } + + return 0; +} + +static int jump__scnprintf(struct ins *ins, char *bf, size_t size, + struct ins_operands *ops, int max_ins_name) +{ + const char *c; + + if (!ops->target.addr || ops->target.offset < 0) + return ins__raw_scnprintf(ins, bf, size, ops, max_ins_name); + + if (ops->target.outside && ops->target.sym != NULL) + return scnprintf(bf, size, "%-*s %s", max_ins_name, ins->name, ops->target.sym->name); + + c = strchr(ops->raw, ','); + c = validate_comma(c, ops); + + if (c != NULL) { + const char *c2 = strchr(c + 1, ','); + + c2 = validate_comma(c2, ops); + /* check for 3-op insn */ + if (c2 != NULL) + c = c2; + c++; + + /* mirror arch objdump's space-after-comma style */ + if (*c == ' ') + c++; + } + + return scnprintf(bf, size, "%-*s %.*s%" PRIx64, max_ins_name, + ins->name, c ? c - ops->raw : 0, ops->raw, + ops->target.offset); +} + +static void jump__delete(struct ins_operands *ops __maybe_unused) +{ + /* + * The ops->jump.raw_comment and ops->jump.raw_func_start belong to the + * raw string, don't free them. + */ +} + +static struct ins_ops jump_ops = { + .free = jump__delete, + .parse = jump__parse, + .scnprintf = jump__scnprintf, +}; + +bool ins__is_jump(const struct ins *ins) +{ + return ins->ops == &jump_ops || ins->ops == &loongarch_jump_ops; +} + +static int comment__symbol(char *raw, char *comment, u64 *addrp, char **namep) +{ + char *endptr, *name, *t; + + if (strstr(raw, "(%rip)") == NULL) + return 0; + + *addrp = strtoull(comment, &endptr, 16); + if (endptr == comment) + return 0; + name = strchr(endptr, '<'); + if (name == NULL) + return -1; + + name++; + + t = strchr(name, '>'); + if (t == NULL) + return 0; + + *t = '\0'; + *namep = strdup(name); + *t = '>'; + + return 0; +} + +static int lock__parse(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms) +{ + ops->locked.ops = zalloc(sizeof(*ops->locked.ops)); + if (ops->locked.ops == NULL) + return 0; + + if (disasm_line__parse(ops->raw, &ops->locked.ins.name, &ops->locked.ops->raw) < 0) + goto out_free_ops; + + ops->locked.ins.ops = ins__find(arch, ops->locked.ins.name); + + if (ops->locked.ins.ops == NULL) + goto out_free_ops; + + if (ops->locked.ins.ops->parse && + ops->locked.ins.ops->parse(arch, ops->locked.ops, ms) < 0) + goto out_free_ops; + + return 0; + +out_free_ops: + zfree(&ops->locked.ops); + return 0; +} + +static int lock__scnprintf(struct ins *ins, char *bf, size_t size, + struct ins_operands *ops, int max_ins_name) +{ + int printed; + + if (ops->locked.ins.ops == NULL) + return ins__raw_scnprintf(ins, bf, size, ops, max_ins_name); + + printed = scnprintf(bf, size, "%-*s ", max_ins_name, ins->name); + return printed + ins__scnprintf(&ops->locked.ins, bf + printed, + size - printed, ops->locked.ops, max_ins_name); +} + +static void lock__delete(struct ins_operands *ops) +{ + struct ins *ins = &ops->locked.ins; + + if (ins->ops && ins->ops->free) + ins->ops->free(ops->locked.ops); + else + ins_ops__delete(ops->locked.ops); + + zfree(&ops->locked.ops); + zfree(&ops->target.raw); + zfree(&ops->target.name); +} + +static struct ins_ops lock_ops = { + .free = lock__delete, + .parse = lock__parse, + .scnprintf = lock__scnprintf, +}; + +/* + * Check if the operand has more than one registers like x86 SIB addressing: + * 0x1234(%rax, %rbx, 8) + * + * But it doesn't care segment selectors like %gs:0x5678(%rcx), so just check + * the input string after 'memory_ref_char' if exists. + */ +static bool check_multi_regs(struct arch *arch, const char *op) +{ + int count = 0; + + if (arch->objdump.register_char == 0) + return false; + + if (arch->objdump.memory_ref_char) { + op = strchr(op, arch->objdump.memory_ref_char); + if (op == NULL) + return false; + } + + while ((op = strchr(op, arch->objdump.register_char)) != NULL) { + count++; + op++; + } + + return count > 1; +} + +static int mov__parse(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms __maybe_unused) +{ + char *s = strchr(ops->raw, ','), *target, *comment, prev; + + if (s == NULL) + return -1; + + *s = '\0'; + + /* + * x86 SIB addressing has something like 0x8(%rax, %rcx, 1) + * then it needs to have the closing parenthesis. + */ + if (strchr(ops->raw, '(')) { + *s = ','; + s = strchr(ops->raw, ')'); + if (s == NULL || s[1] != ',') + return -1; + *++s = '\0'; + } + + ops->source.raw = strdup(ops->raw); + *s = ','; + + if (ops->source.raw == NULL) + return -1; + + ops->source.multi_regs = check_multi_regs(arch, ops->source.raw); + + target = skip_spaces(++s); + comment = strchr(s, arch->objdump.comment_char); + + if (comment != NULL) + s = comment - 1; + else + s = strchr(s, '\0') - 1; + + while (s > target && isspace(s[0])) + --s; + s++; + prev = *s; + *s = '\0'; + + ops->target.raw = strdup(target); + *s = prev; + + if (ops->target.raw == NULL) + goto out_free_source; + + ops->target.multi_regs = check_multi_regs(arch, ops->target.raw); + + if (comment == NULL) + return 0; + + comment = skip_spaces(comment); + comment__symbol(ops->source.raw, comment + 1, &ops->source.addr, &ops->source.name); + comment__symbol(ops->target.raw, comment + 1, &ops->target.addr, &ops->target.name); + + return 0; + +out_free_source: + zfree(&ops->source.raw); + return -1; +} + +static int mov__scnprintf(struct ins *ins, char *bf, size_t size, + struct ins_operands *ops, int max_ins_name) +{ + return scnprintf(bf, size, "%-*s %s,%s", max_ins_name, ins->name, + ops->source.name ?: ops->source.raw, + ops->target.name ?: ops->target.raw); +} + +static struct ins_ops mov_ops = { + .parse = mov__parse, + .scnprintf = mov__scnprintf, +}; + +static int dec__parse(struct arch *arch __maybe_unused, struct ins_operands *ops, struct map_symbol *ms __maybe_unused) +{ + char *target, *comment, *s, prev; + + target = s = ops->raw; + + while (s[0] != '\0' && !isspace(s[0])) + ++s; + prev = *s; + *s = '\0'; + + ops->target.raw = strdup(target); + *s = prev; + + if (ops->target.raw == NULL) + return -1; + + comment = strchr(s, arch->objdump.comment_char); + if (comment == NULL) + return 0; + + comment = skip_spaces(comment); + comment__symbol(ops->target.raw, comment + 1, &ops->target.addr, &ops->target.name); + + return 0; +} + +static int dec__scnprintf(struct ins *ins, char *bf, size_t size, + struct ins_operands *ops, int max_ins_name) +{ + return scnprintf(bf, size, "%-*s %s", max_ins_name, ins->name, + ops->target.name ?: ops->target.raw); +} + +static struct ins_ops dec_ops = { + .parse = dec__parse, + .scnprintf = dec__scnprintf, +}; + +static int nop__scnprintf(struct ins *ins __maybe_unused, char *bf, size_t size, + struct ins_operands *ops __maybe_unused, int max_ins_name) +{ + return scnprintf(bf, size, "%-*s", max_ins_name, "nop"); +} + +static struct ins_ops nop_ops = { + .scnprintf = nop__scnprintf, +}; + +static struct ins_ops ret_ops = { + .scnprintf = ins__raw_scnprintf, +}; + +bool ins__is_nop(const struct ins *ins) +{ + return ins->ops == &nop_ops; +} + +bool ins__is_ret(const struct ins *ins) +{ + return ins->ops == &ret_ops; +} + +bool ins__is_lock(const struct ins *ins) +{ + return ins->ops == &lock_ops; +} + +static int ins__key_cmp(const void *name, const void *insp) +{ + const struct ins *ins = insp; + + return strcmp(name, ins->name); +} + +static int ins__cmp(const void *a, const void *b) +{ + const struct ins *ia = a; + const struct ins *ib = b; + + return strcmp(ia->name, ib->name); +} + +static void ins__sort(struct arch *arch) +{ + const int nmemb = arch->nr_instructions; + + qsort(arch->instructions, nmemb, sizeof(struct ins), ins__cmp); +} + +static struct ins_ops *__ins__find(struct arch *arch, const char *name) +{ + struct ins *ins; + const int nmemb = arch->nr_instructions; + + if (!arch->sorted_instructions) { + ins__sort(arch); + arch->sorted_instructions = true; + } + + ins = bsearch(name, arch->instructions, nmemb, sizeof(struct ins), ins__key_cmp); + if (ins) + return ins->ops; + + if (arch->insn_suffix) { + char tmp[32]; + char suffix; + size_t len = strlen(name); + + if (len == 0 || len >= sizeof(tmp)) + return NULL; + + suffix = name[len - 1]; + if (strchr(arch->insn_suffix, suffix) == NULL) + return NULL; + + strcpy(tmp, name); + tmp[len - 1] = '\0'; /* remove the suffix and check again */ + + ins = bsearch(tmp, arch->instructions, nmemb, sizeof(struct ins), ins__key_cmp); + } + return ins ? ins->ops : NULL; +} + +struct ins_ops *ins__find(struct arch *arch, const char *name) +{ + struct ins_ops *ops = __ins__find(arch, name); + + if (!ops && arch->associate_instruction_ops) + ops = arch->associate_instruction_ops(arch, name); + + return ops; +} + +static void disasm_line__init_ins(struct disasm_line *dl, struct arch *arch, struct map_symbol *ms) +{ + dl->ins.ops = ins__find(arch, dl->ins.name); + + if (!dl->ins.ops) + return; + + if (dl->ins.ops->parse && dl->ins.ops->parse(arch, &dl->ops, ms) < 0) + dl->ins.ops = NULL; +} + +static int disasm_line__parse(char *line, const char **namep, char **rawp) +{ + char tmp, *name = skip_spaces(line); + + if (name[0] == '\0') + return -1; + + *rawp = name + 1; + + while ((*rawp)[0] != '\0' && !isspace((*rawp)[0])) + ++*rawp; + + tmp = (*rawp)[0]; + (*rawp)[0] = '\0'; + *namep = strdup(name); + + if (*namep == NULL) + goto out; + + (*rawp)[0] = tmp; + *rawp = strim(*rawp); + + return 0; + +out: + return -1; +} + +static void annotation_line__init(struct annotation_line *al, + struct annotate_args *args, + int nr) +{ + al->offset = args->offset; + al->line = strdup(args->line); + al->line_nr = args->line_nr; + al->fileloc = args->fileloc; + al->data_nr = nr; +} + +static void annotation_line__exit(struct annotation_line *al) +{ + zfree_srcline(&al->path); + zfree(&al->line); + zfree(&al->cycles); +} + +static size_t disasm_line_size(int nr) +{ + struct annotation_line *al; + + return (sizeof(struct disasm_line) + (sizeof(al->data[0]) * nr)); +} + +/* + * Allocating the disasm annotation line data with + * following structure: + * + * ------------------------------------------- + * struct disasm_line | struct annotation_line + * ------------------------------------------- + * + * We have 'struct annotation_line' member as last member + * of 'struct disasm_line' to have an easy access. + */ +struct disasm_line *disasm_line__new(struct annotate_args *args) +{ + struct disasm_line *dl = NULL; + int nr = 1; + + if (evsel__is_group_event(args->evsel)) + nr = args->evsel->core.nr_members; + + dl = zalloc(disasm_line_size(nr)); + if (!dl) + return NULL; + + annotation_line__init(&dl->al, args, nr); + if (dl->al.line == NULL) + goto out_delete; + + if (args->offset != -1) { + if (disasm_line__parse(dl->al.line, &dl->ins.name, &dl->ops.raw) < 0) + goto out_free_line; + + disasm_line__init_ins(dl, args->arch, &args->ms); + } + + return dl; + +out_free_line: + zfree(&dl->al.line); +out_delete: + free(dl); + return NULL; +} + +void disasm_line__free(struct disasm_line *dl) +{ + if (dl->ins.ops && dl->ins.ops->free) + dl->ins.ops->free(&dl->ops); + else + ins_ops__delete(&dl->ops); + zfree(&dl->ins.name); + annotation_line__exit(&dl->al); + free(dl); +} + +int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw, int max_ins_name) +{ + if (raw || !dl->ins.ops) + return scnprintf(bf, size, "%-*s %s", max_ins_name, dl->ins.name, dl->ops.raw); + + return ins__scnprintf(&dl->ins, bf, size, &dl->ops, max_ins_name); +} + +/* + * symbol__parse_objdump_line() parses objdump output (with -d --no-show-raw) + * which looks like following + * + * 0000000000415500 <_init>: + * 415500: sub $0x8,%rsp + * 415504: mov 0x2f5ad5(%rip),%rax # 70afe0 <_DYNAMIC+0x2f8> + * 41550b: test %rax,%rax + * 41550e: je 415515 <_init+0x15> + * 415510: callq 416e70 <__gmon_start__@plt> + * 415515: add $0x8,%rsp + * 415519: retq + * + * it will be parsed and saved into struct disasm_line as + * + * + * The offset will be a relative offset from the start of the symbol and -1 + * means that it's not a disassembly line so should be treated differently. + * The ops.raw part will be parsed further according to type of the instruction. + */ +static int symbol__parse_objdump_line(struct symbol *sym, + struct annotate_args *args, + char *parsed_line, int *line_nr, char **fileloc) +{ + struct map *map = args->ms.map; + struct annotation *notes = symbol__annotation(sym); + struct disasm_line *dl; + char *tmp; + s64 line_ip, offset = -1; + regmatch_t match[2]; + + /* /filename:linenr ? Save line number and ignore. */ + if (regexec(&file_lineno, parsed_line, 2, match, 0) == 0) { + *line_nr = atoi(parsed_line + match[1].rm_so); + free(*fileloc); + *fileloc = strdup(parsed_line); + return 0; + } + + /* Process hex address followed by ':'. */ + line_ip = strtoull(parsed_line, &tmp, 16); + if (parsed_line != tmp && tmp[0] == ':' && tmp[1] != '\0') { + u64 start = map__rip_2objdump(map, sym->start), + end = map__rip_2objdump(map, sym->end); + + offset = line_ip - start; + if ((u64)line_ip < start || (u64)line_ip >= end) + offset = -1; + else + parsed_line = tmp + 1; + } + + args->offset = offset; + args->line = parsed_line; + args->line_nr = *line_nr; + args->fileloc = *fileloc; + args->ms.sym = sym; + + dl = disasm_line__new(args); + (*line_nr)++; + + if (dl == NULL) + return -1; + + if (!disasm_line__has_local_offset(dl)) { + dl->ops.target.offset = dl->ops.target.addr - + map__rip_2objdump(map, sym->start); + dl->ops.target.offset_avail = true; + } + + /* kcore has no symbols, so add the call target symbol */ + if (dl->ins.ops && ins__is_call(&dl->ins) && !dl->ops.target.sym) { + struct addr_map_symbol target = { + .addr = dl->ops.target.addr, + .ms = { .map = map, }, + }; + + if (!maps__find_ams(args->ms.maps, &target) && + target.ms.sym->start == target.al_addr) + dl->ops.target.sym = target.ms.sym; + } + + annotation_line__add(&dl->al, ¬es->src->source); + return 0; +} + +static void delete_last_nop(struct symbol *sym) +{ + struct annotation *notes = symbol__annotation(sym); + struct list_head *list = ¬es->src->source; + struct disasm_line *dl; + + while (!list_empty(list)) { + dl = list_entry(list->prev, struct disasm_line, al.node); + + if (dl->ins.ops) { + if (!ins__is_nop(&dl->ins)) + return; + } else { + if (!strstr(dl->al.line, " nop ") && + !strstr(dl->al.line, " nopl ") && + !strstr(dl->al.line, " nopw ")) + return; + } + + list_del_init(&dl->al.node); + disasm_line__free(dl); + } +} + +int symbol__strerror_disassemble(struct map_symbol *ms, int errnum, char *buf, size_t buflen) +{ + struct dso *dso = map__dso(ms->map); + + BUG_ON(buflen == 0); + + if (errnum >= 0) { + str_error_r(errnum, buf, buflen); + return 0; + } + + switch (errnum) { + case SYMBOL_ANNOTATE_ERRNO__NO_VMLINUX: { + char bf[SBUILD_ID_SIZE + 15] = " with build id "; + char *build_id_msg = NULL; + + if (dso->has_build_id) { + build_id__sprintf(&dso->bid, bf + 15); + build_id_msg = bf; + } + scnprintf(buf, buflen, + "No vmlinux file%s\nwas found in the path.\n\n" + "Note that annotation using /proc/kcore requires CAP_SYS_RAWIO capability.\n\n" + "Please use:\n\n" + " perf buildid-cache -vu vmlinux\n\n" + "or:\n\n" + " --vmlinux vmlinux\n", build_id_msg ?: ""); + } + break; + case SYMBOL_ANNOTATE_ERRNO__NO_LIBOPCODES_FOR_BPF: + scnprintf(buf, buflen, "Please link with binutils's libopcode to enable BPF annotation"); + break; + case SYMBOL_ANNOTATE_ERRNO__ARCH_INIT_REGEXP: + scnprintf(buf, buflen, "Problems with arch specific instruction name regular expressions."); + break; + case SYMBOL_ANNOTATE_ERRNO__ARCH_INIT_CPUID_PARSING: + scnprintf(buf, buflen, "Problems while parsing the CPUID in the arch specific initialization."); + break; + case SYMBOL_ANNOTATE_ERRNO__BPF_INVALID_FILE: + scnprintf(buf, buflen, "Invalid BPF file: %s.", dso->long_name); + break; + case SYMBOL_ANNOTATE_ERRNO__BPF_MISSING_BTF: + scnprintf(buf, buflen, "The %s BPF file has no BTF section, compile with -g or use pahole -J.", + dso->long_name); + break; + default: + scnprintf(buf, buflen, "Internal error: Invalid %d error code\n", errnum); + break; + } + + return 0; +} + +static int dso__disassemble_filename(struct dso *dso, char *filename, size_t filename_size) +{ + char linkname[PATH_MAX]; + char *build_id_filename; + char *build_id_path = NULL; + char *pos; + int len; + + if (dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS && + !dso__is_kcore(dso)) + return SYMBOL_ANNOTATE_ERRNO__NO_VMLINUX; + + build_id_filename = dso__build_id_filename(dso, NULL, 0, false); + if (build_id_filename) { + __symbol__join_symfs(filename, filename_size, build_id_filename); + free(build_id_filename); + } else { + if (dso->has_build_id) + return ENOMEM; + goto fallback; + } + + build_id_path = strdup(filename); + if (!build_id_path) + return ENOMEM; + + /* + * old style build-id cache has name of XX/XXXXXXX.. while + * new style has XX/XXXXXXX../{elf,kallsyms,vdso}. + * extract the build-id part of dirname in the new style only. + */ + pos = strrchr(build_id_path, '/'); + if (pos && strlen(pos) < SBUILD_ID_SIZE - 2) + dirname(build_id_path); + + if (dso__is_kcore(dso)) + goto fallback; + + len = readlink(build_id_path, linkname, sizeof(linkname) - 1); + if (len < 0) + goto fallback; + + linkname[len] = '\0'; + if (strstr(linkname, DSO__NAME_KALLSYMS) || + access(filename, R_OK)) { +fallback: + /* + * If we don't have build-ids or the build-id file isn't in the + * cache, or is just a kallsyms file, well, lets hope that this + * DSO is the same as when 'perf record' ran. + */ + if (dso->kernel && dso->long_name[0] == '/') + snprintf(filename, filename_size, "%s", dso->long_name); + else + __symbol__join_symfs(filename, filename_size, dso->long_name); + + mutex_lock(&dso->lock); + if (access(filename, R_OK) && errno == ENOENT && dso->nsinfo) { + char *new_name = dso__filename_with_chroot(dso, filename); + if (new_name) { + strlcpy(filename, new_name, filename_size); + free(new_name); + } + } + mutex_unlock(&dso->lock); + } + + free(build_id_path); + return 0; +} + +#if defined(HAVE_LIBBFD_SUPPORT) && defined(HAVE_LIBBPF_SUPPORT) +#define PACKAGE "perf" +#include +#include +#include +#include +#include +#include +#include + +#include "bpf-event.h" +#include "bpf-utils.h" + +static int symbol__disassemble_bpf(struct symbol *sym, + struct annotate_args *args) +{ + struct annotation *notes = symbol__annotation(sym); + struct bpf_prog_linfo *prog_linfo = NULL; + struct bpf_prog_info_node *info_node; + int len = sym->end - sym->start; + disassembler_ftype disassemble; + struct map *map = args->ms.map; + struct perf_bpil *info_linear; + struct disassemble_info info; + struct dso *dso = map__dso(map); + int pc = 0, count, sub_id; + struct btf *btf = NULL; + char tpath[PATH_MAX]; + size_t buf_size; + int nr_skip = 0; + char *buf; + bfd *bfdf; + int ret; + FILE *s; + + if (dso->binary_type != DSO_BINARY_TYPE__BPF_PROG_INFO) + return SYMBOL_ANNOTATE_ERRNO__BPF_INVALID_FILE; + + pr_debug("%s: handling sym %s addr %" PRIx64 " len %" PRIx64 "\n", __func__, + sym->name, sym->start, sym->end - sym->start); + + memset(tpath, 0, sizeof(tpath)); + perf_exe(tpath, sizeof(tpath)); + + bfdf = bfd_openr(tpath, NULL); + if (bfdf == NULL) + abort(); + + if (!bfd_check_format(bfdf, bfd_object)) + abort(); + + s = open_memstream(&buf, &buf_size); + if (!s) { + ret = errno; + goto out; + } + init_disassemble_info_compat(&info, s, + (fprintf_ftype) fprintf, + fprintf_styled); + info.arch = bfd_get_arch(bfdf); + info.mach = bfd_get_mach(bfdf); + + info_node = perf_env__find_bpf_prog_info(dso->bpf_prog.env, + dso->bpf_prog.id); + if (!info_node) { + ret = SYMBOL_ANNOTATE_ERRNO__BPF_MISSING_BTF; + goto out; + } + info_linear = info_node->info_linear; + sub_id = dso->bpf_prog.sub_id; + + info.buffer = (void *)(uintptr_t)(info_linear->info.jited_prog_insns); + info.buffer_length = info_linear->info.jited_prog_len; + + if (info_linear->info.nr_line_info) + prog_linfo = bpf_prog_linfo__new(&info_linear->info); + + if (info_linear->info.btf_id) { + struct btf_node *node; + + node = perf_env__find_btf(dso->bpf_prog.env, + info_linear->info.btf_id); + if (node) + btf = btf__new((__u8 *)(node->data), + node->data_size); + } + + disassemble_init_for_target(&info); + +#ifdef DISASM_FOUR_ARGS_SIGNATURE + disassemble = disassembler(info.arch, + bfd_big_endian(bfdf), + info.mach, + bfdf); +#else + disassemble = disassembler(bfdf); +#endif + if (disassemble == NULL) + abort(); + + fflush(s); + do { + const struct bpf_line_info *linfo = NULL; + struct disasm_line *dl; + size_t prev_buf_size; + const char *srcline; + u64 addr; + + addr = pc + ((u64 *)(uintptr_t)(info_linear->info.jited_ksyms))[sub_id]; + count = disassemble(pc, &info); + + if (prog_linfo) + linfo = bpf_prog_linfo__lfind_addr_func(prog_linfo, + addr, sub_id, + nr_skip); + + if (linfo && btf) { + srcline = btf__name_by_offset(btf, linfo->line_off); + nr_skip++; + } else + srcline = NULL; + + fprintf(s, "\n"); + prev_buf_size = buf_size; + fflush(s); + + if (!annotate_opts.hide_src_code && srcline) { + args->offset = -1; + args->line = strdup(srcline); + args->line_nr = 0; + args->fileloc = NULL; + args->ms.sym = sym; + dl = disasm_line__new(args); + if (dl) { + annotation_line__add(&dl->al, + ¬es->src->source); + } + } + + args->offset = pc; + args->line = buf + prev_buf_size; + args->line_nr = 0; + args->fileloc = NULL; + args->ms.sym = sym; + dl = disasm_line__new(args); + if (dl) + annotation_line__add(&dl->al, ¬es->src->source); + + pc += count; + } while (count > 0 && pc < len); + + ret = 0; +out: + free(prog_linfo); + btf__free(btf); + fclose(s); + bfd_close(bfdf); + return ret; +} +#else // defined(HAVE_LIBBFD_SUPPORT) && defined(HAVE_LIBBPF_SUPPORT) +static int symbol__disassemble_bpf(struct symbol *sym __maybe_unused, + struct annotate_args *args __maybe_unused) +{ + return SYMBOL_ANNOTATE_ERRNO__NO_LIBOPCODES_FOR_BPF; +} +#endif // defined(HAVE_LIBBFD_SUPPORT) && defined(HAVE_LIBBPF_SUPPORT) + +static int +symbol__disassemble_bpf_image(struct symbol *sym, + struct annotate_args *args) +{ + struct annotation *notes = symbol__annotation(sym); + struct disasm_line *dl; + + args->offset = -1; + args->line = strdup("to be implemented"); + args->line_nr = 0; + args->fileloc = NULL; + dl = disasm_line__new(args); + if (dl) + annotation_line__add(&dl->al, ¬es->src->source); + + zfree(&args->line); + return 0; +} + +/* + * Possibly create a new version of line with tabs expanded. Returns the + * existing or new line, storage is updated if a new line is allocated. If + * allocation fails then NULL is returned. + */ +static char *expand_tabs(char *line, char **storage, size_t *storage_len) +{ + size_t i, src, dst, len, new_storage_len, num_tabs; + char *new_line; + size_t line_len = strlen(line); + + for (num_tabs = 0, i = 0; i < line_len; i++) + if (line[i] == '\t') + num_tabs++; + + if (num_tabs == 0) + return line; + + /* + * Space for the line and '\0', less the leading and trailing + * spaces. Each tab may introduce 7 additional spaces. + */ + new_storage_len = line_len + 1 + (num_tabs * 7); + + new_line = malloc(new_storage_len); + if (new_line == NULL) { + pr_err("Failure allocating memory for tab expansion\n"); + return NULL; + } + + /* + * Copy regions starting at src and expand tabs. If there are two + * adjacent tabs then 'src == i', the memcpy is of size 0 and the spaces + * are inserted. + */ + for (i = 0, src = 0, dst = 0; i < line_len && num_tabs; i++) { + if (line[i] == '\t') { + len = i - src; + memcpy(&new_line[dst], &line[src], len); + dst += len; + new_line[dst++] = ' '; + while (dst % 8 != 0) + new_line[dst++] = ' '; + src = i + 1; + num_tabs--; + } + } + + /* Expand the last region. */ + len = line_len - src; + memcpy(&new_line[dst], &line[src], len); + dst += len; + new_line[dst] = '\0'; + + free(*storage); + *storage = new_line; + *storage_len = new_storage_len; + return new_line; +} + +int symbol__disassemble(struct symbol *sym, struct annotate_args *args) +{ + struct annotation_options *opts = &annotate_opts; + struct map *map = args->ms.map; + struct dso *dso = map__dso(map); + char *command; + FILE *file; + char symfs_filename[PATH_MAX]; + struct kcore_extract kce; + bool delete_extract = false; + bool decomp = false; + int lineno = 0; + char *fileloc = NULL; + int nline; + char *line; + size_t line_len; + const char *objdump_argv[] = { + "/bin/sh", + "-c", + NULL, /* Will be the objdump command to run. */ + "--", + NULL, /* Will be the symfs path. */ + NULL, + }; + struct child_process objdump_process; + int err = dso__disassemble_filename(dso, symfs_filename, sizeof(symfs_filename)); + + if (err) + return err; + + pr_debug("%s: filename=%s, sym=%s, start=%#" PRIx64 ", end=%#" PRIx64 "\n", __func__, + symfs_filename, sym->name, map__unmap_ip(map, sym->start), + map__unmap_ip(map, sym->end)); + + pr_debug("annotating [%p] %30s : [%p] %30s\n", + dso, dso->long_name, sym, sym->name); + + if (dso->binary_type == DSO_BINARY_TYPE__BPF_PROG_INFO) { + return symbol__disassemble_bpf(sym, args); + } else if (dso->binary_type == DSO_BINARY_TYPE__BPF_IMAGE) { + return symbol__disassemble_bpf_image(sym, args); + } else if (dso__is_kcore(dso)) { + kce.kcore_filename = symfs_filename; + kce.addr = map__rip_2objdump(map, sym->start); + kce.offs = sym->start; + kce.len = sym->end - sym->start; + if (!kcore_extract__create(&kce)) { + delete_extract = true; + strlcpy(symfs_filename, kce.extract_filename, + sizeof(symfs_filename)); + } + } else if (dso__needs_decompress(dso)) { + char tmp[KMOD_DECOMP_LEN]; + + if (dso__decompress_kmodule_path(dso, symfs_filename, + tmp, sizeof(tmp)) < 0) + return -1; + + decomp = true; + strcpy(symfs_filename, tmp); + } + + err = asprintf(&command, + "%s %s%s --start-address=0x%016" PRIx64 + " --stop-address=0x%016" PRIx64 + " %s -d %s %s %s %c%s%c %s%s -C \"$1\"", + opts->objdump_path ?: "objdump", + opts->disassembler_style ? "-M " : "", + opts->disassembler_style ?: "", + map__rip_2objdump(map, sym->start), + map__rip_2objdump(map, sym->end), + opts->show_linenr ? "-l" : "", + opts->show_asm_raw ? "" : "--no-show-raw-insn", + opts->annotate_src ? "-S" : "", + opts->prefix ? "--prefix " : "", + opts->prefix ? '"' : ' ', + opts->prefix ?: "", + opts->prefix ? '"' : ' ', + opts->prefix_strip ? "--prefix-strip=" : "", + opts->prefix_strip ?: ""); + + if (err < 0) { + pr_err("Failure allocating memory for the command to run\n"); + goto out_remove_tmp; + } + + pr_debug("Executing: %s\n", command); + + objdump_argv[2] = command; + objdump_argv[4] = symfs_filename; + + /* Create a pipe to read from for stdout */ + memset(&objdump_process, 0, sizeof(objdump_process)); + objdump_process.argv = objdump_argv; + objdump_process.out = -1; + objdump_process.err = -1; + objdump_process.no_stderr = 1; + if (start_command(&objdump_process)) { + pr_err("Failure starting to run %s\n", command); + err = -1; + goto out_free_command; + } + + file = fdopen(objdump_process.out, "r"); + if (!file) { + pr_err("Failure creating FILE stream for %s\n", command); + /* + * If we were using debug info should retry with + * original binary. + */ + err = -1; + goto out_close_stdout; + } + + /* Storage for getline. */ + line = NULL; + line_len = 0; + + nline = 0; + while (!feof(file)) { + const char *match; + char *expanded_line; + + if (getline(&line, &line_len, file) < 0 || !line) + break; + + /* Skip lines containing "filename:" */ + match = strstr(line, symfs_filename); + if (match && match[strlen(symfs_filename)] == ':') + continue; + + expanded_line = strim(line); + expanded_line = expand_tabs(expanded_line, &line, &line_len); + if (!expanded_line) + break; + + /* + * The source code line number (lineno) needs to be kept in + * across calls to symbol__parse_objdump_line(), so that it + * can associate it with the instructions till the next one. + * See disasm_line__new() and struct disasm_line::line_nr. + */ + if (symbol__parse_objdump_line(sym, args, expanded_line, + &lineno, &fileloc) < 0) + break; + nline++; + } + free(line); + free(fileloc); + + err = finish_command(&objdump_process); + if (err) + pr_err("Error running %s\n", command); + + if (nline == 0) { + err = -1; + pr_err("No output from %s\n", command); + } + + /* + * kallsyms does not have symbol sizes so there may a nop at the end. + * Remove it. + */ + if (dso__is_kcore(dso)) + delete_last_nop(sym); + + fclose(file); + +out_close_stdout: + close(objdump_process.out); + +out_free_command: + free(command); + +out_remove_tmp: + if (decomp) + unlink(symfs_filename); + + if (delete_extract) + kcore_extract__delete(&kce); + + return err; +} diff --git a/tools/perf/util/disasm.h b/tools/perf/util/disasm.h new file mode 100644 index 000000000000..3d381a043520 --- /dev/null +++ b/tools/perf/util/disasm.h @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: GPL-2.0 +#ifndef __PERF_UTIL_DISASM_H +#define __PERF_UTIL_DISASM_H + +#include "map_symbol.h" + +struct annotation_options; +struct disasm_line; +struct ins; +struct evsel; +struct symbol; + +struct arch { + const char *name; + struct ins *instructions; + size_t nr_instructions; + size_t nr_instructions_allocated; + struct ins_ops *(*associate_instruction_ops)(struct arch *arch, const char *name); + bool sorted_instructions; + bool initialized; + const char *insn_suffix; + void *priv; + unsigned int model; + unsigned int family; + int (*init)(struct arch *arch, char *cpuid); + bool (*ins_is_fused)(struct arch *arch, const char *ins1, + const char *ins2); + struct { + char comment_char; + char skip_functions_char; + char register_char; + char memory_ref_char; + char imm_char; + } objdump; +}; + +struct ins { + const char *name; + struct ins_ops *ops; +}; + +struct ins_operands { + char *raw; + struct { + char *raw; + char *name; + struct symbol *sym; + u64 addr; + s64 offset; + bool offset_avail; + bool outside; + bool multi_regs; + } target; + union { + struct { + char *raw; + char *name; + u64 addr; + bool multi_regs; + } source; + struct { + struct ins ins; + struct ins_operands *ops; + } locked; + struct { + char *raw_comment; + char *raw_func_start; + } jump; + }; +}; + +struct ins_ops { + void (*free)(struct ins_operands *ops); + int (*parse)(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms); + int (*scnprintf)(struct ins *ins, char *bf, size_t size, + struct ins_operands *ops, int max_ins_name); +}; + +struct annotate_args { + struct arch *arch; + struct map_symbol ms; + struct evsel *evsel; + struct annotation_options *options; + s64 offset; + char *line; + int line_nr; + char *fileloc; +}; + +struct arch *arch__find(const char *name); +bool arch__is(struct arch *arch, const char *name); + +struct ins_ops *ins__find(struct arch *arch, const char *name); +int ins__scnprintf(struct ins *ins, char *bf, size_t size, + struct ins_operands *ops, int max_ins_name); + +bool ins__is_call(const struct ins *ins); +bool ins__is_jump(const struct ins *ins); +bool ins__is_fused(struct arch *arch, const char *ins1, const char *ins2); +bool ins__is_nop(const struct ins *ins); +bool ins__is_ret(const struct ins *ins); +bool ins__is_lock(const struct ins *ins); + +struct disasm_line *disasm_line__new(struct annotate_args *args); +void disasm_line__free(struct disasm_line *dl); + +int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, + bool raw, int max_ins_name); + +int symbol__disassemble(struct symbol *sym, struct annotate_args *args); + +#endif /* __PERF_UTIL_DISASM_H */ -- cgit v1.2.3-59-g8ed1b From 6d17edc113de1e21fc66afa76be475a4f7c91826 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Fri, 29 Mar 2024 14:58:11 -0700 Subject: perf annotate: Use libcapstone to disassemble Now it can use the capstone library to disassemble the instructions. Let's use that (if available) for perf annotate to speed up. Currently it only supports x86 architecture. With this change I can see ~3x speed up in data type profiling. But note that capstone cannot give the source file and line number info. For now, users should use the external objdump for that by specifying the --objdump option explicitly. Signed-off-by: Namhyung Kim Tested-by: Ian Rogers Cc: Adrian Hunter Cc: Changbin Du Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20240329215812.537846-5-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/disasm.c | 160 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 160 insertions(+) diff --git a/tools/perf/util/disasm.c b/tools/perf/util/disasm.c index 21a43b07e8b5..6552b45e37ec 100644 --- a/tools/perf/util/disasm.c +++ b/tools/perf/util/disasm.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only #include #include +#include #include #include #include @@ -19,6 +20,7 @@ #include "evsel.h" #include "map.h" #include "maps.h" +#include "namespaces.h" #include "srcline.h" #include "symbol.h" #include "util.h" @@ -1346,6 +1348,158 @@ symbol__disassemble_bpf_image(struct symbol *sym, return 0; } +#ifdef HAVE_LIBCAPSTONE_SUPPORT +#include + +static int open_capstone_handle(struct annotate_args *args, bool is_64bit, + csh *handle) +{ + struct annotation_options *opt = args->options; + cs_mode mode = is_64bit ? CS_MODE_64 : CS_MODE_32; + + /* TODO: support more architectures */ + if (!arch__is(args->arch, "x86")) + return -1; + + if (cs_open(CS_ARCH_X86, mode, handle) != CS_ERR_OK) + return -1; + + if (!opt->disassembler_style || + !strcmp(opt->disassembler_style, "att")) + cs_option(*handle, CS_OPT_SYNTAX, CS_OPT_SYNTAX_ATT); + + return 0; +} + +struct find_file_offset_data { + u64 ip; + u64 offset; +}; + +/* This will be called for each PHDR in an ELF binary */ +static int find_file_offset(u64 start, u64 len, u64 pgoff, void *arg) +{ + struct find_file_offset_data *data = arg; + + if (start <= data->ip && data->ip < start + len) { + data->offset = pgoff + data->ip - start; + return 1; + } + return 0; +} + +static int symbol__disassemble_capstone(char *filename, struct symbol *sym, + struct annotate_args *args) +{ + struct annotation *notes = symbol__annotation(sym); + struct map *map = args->ms.map; + struct dso *dso = map__dso(map); + struct nscookie nsc; + u64 start = map__rip_2objdump(map, sym->start); + u64 end = map__rip_2objdump(map, sym->end); + u64 len = end - start; + u64 offset; + int i, fd, count; + bool is_64bit = false; + bool needs_cs_close = false; + u8 *buf = NULL; + struct find_file_offset_data data = { + .ip = start, + }; + csh handle; + cs_insn *insn; + char disasm_buf[512]; + struct disasm_line *dl; + + if (args->options->objdump_path) + return -1; + + nsinfo__mountns_enter(dso->nsinfo, &nsc); + fd = open(filename, O_RDONLY); + nsinfo__mountns_exit(&nsc); + if (fd < 0) + return -1; + + if (file__read_maps(fd, /*exe=*/true, find_file_offset, &data, + &is_64bit) == 0) + goto err; + + if (open_capstone_handle(args, is_64bit, &handle) < 0) + goto err; + + needs_cs_close = true; + + buf = malloc(len); + if (buf == NULL) + goto err; + + count = pread(fd, buf, len, data.offset); + close(fd); + fd = -1; + + if ((u64)count != len) + goto err; + + /* add the function address and name */ + scnprintf(disasm_buf, sizeof(disasm_buf), "%#"PRIx64" <%s>:", + start, sym->name); + + args->offset = -1; + args->line = disasm_buf; + args->line_nr = 0; + args->fileloc = NULL; + args->ms.sym = sym; + + dl = disasm_line__new(args); + if (dl == NULL) + goto err; + + annotation_line__add(&dl->al, ¬es->src->source); + + count = cs_disasm(handle, buf, len, start, len, &insn); + for (i = 0, offset = 0; i < count; i++) { + scnprintf(disasm_buf, sizeof(disasm_buf), + " %-7s %s", + insn[i].mnemonic, insn[i].op_str); + + args->offset = offset; + args->line = disasm_buf; + + dl = disasm_line__new(args); + if (dl == NULL) + goto err; + + annotation_line__add(&dl->al, ¬es->src->source); + + offset += insn[i].size; + } + +out: + if (needs_cs_close) + cs_close(&handle); + free(buf); + return count < 0 ? count : 0; + +err: + if (fd >= 0) + close(fd); + if (needs_cs_close) { + struct disasm_line *tmp; + + /* + * It probably failed in the middle of the above loop. + * Release any resources it might add. + */ + list_for_each_entry_safe(dl, tmp, ¬es->src->source, al.node) { + list_del(&dl->al.node); + free(dl); + } + } + count = -1; + goto out; +} +#endif + /* * Possibly create a new version of line with tabs expanded. Returns the * existing or new line, storage is updated if a new line is allocated. If @@ -1468,6 +1622,12 @@ int symbol__disassemble(struct symbol *sym, struct annotate_args *args) strcpy(symfs_filename, tmp); } +#ifdef HAVE_LIBCAPSTONE_SUPPORT + err = symbol__disassemble_capstone(symfs_filename, sym, args); + if (err == 0) + goto out_remove_tmp; +#endif + err = asprintf(&command, "%s %s%s --start-address=0x%016" PRIx64 " --stop-address=0x%016" PRIx64 -- cgit v1.2.3-59-g8ed1b From 92dfc59463d55b9abb47429591fd8a21b27930cf Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Fri, 29 Mar 2024 14:58:12 -0700 Subject: perf annotate: Add symbol name when using capstone This is to keep the existing behavior with objdump. It needs to show symbol information of global variables like below: Percent | Source code & Disassembly of elf for cycles:P (1 samples, percent: local period) ------------------------------------------------------------------------------------------------ : 0 0xffffffff81338f70 : 0.00 : ffffffff81338f70: endbr64 0.00 : ffffffff81338f74: callq 0xffffffff81083a40 0.00 : ffffffff81338f79: movq %rdi, %r8 0.00 : ffffffff81338f7c: movq %rdx, %rdi 0.00 : ffffffff81338f7f: callq *0x17021c3(%rip) # ffffffff82a3b148 0.00 : ffffffff81338f85: movq 0xffbf3c(%rip), %rdx # ffffffff82334ec8 0.00 : ffffffff81338f8c: testq %rax, %rax ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 0.00 : ffffffff81338f8f: je 0xffffffff81338fd0 here 0.00 : ffffffff81338f91: movq %rax, %rcx 0.00 : ffffffff81338f94: andl $1, %ecx Signed-off-by: Namhyung Kim Cc: Adrian Hunter Cc: Changbin Du Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20240329215812.537846-6-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/disasm.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 71 insertions(+), 3 deletions(-) diff --git a/tools/perf/util/disasm.c b/tools/perf/util/disasm.c index 6552b45e37ec..a1219eb930aa 100644 --- a/tools/perf/util/disasm.c +++ b/tools/perf/util/disasm.c @@ -1368,6 +1368,12 @@ static int open_capstone_handle(struct annotate_args *args, bool is_64bit, !strcmp(opt->disassembler_style, "att")) cs_option(*handle, CS_OPT_SYNTAX, CS_OPT_SYNTAX_ATT); + /* + * Resolving address operands to symbols is implemented + * on x86 by investigating instruction details. + */ + cs_option(*handle, CS_OPT_DETAIL, CS_OPT_ON); + return 0; } @@ -1388,6 +1394,63 @@ static int find_file_offset(u64 start, u64 len, u64 pgoff, void *arg) return 0; } +static void print_capstone_detail(cs_insn *insn, char *buf, size_t len, + struct annotate_args *args, u64 addr) +{ + int i; + struct map *map = args->ms.map; + struct symbol *sym; + + /* TODO: support more architectures */ + if (!arch__is(args->arch, "x86")) + return; + + if (insn->detail == NULL) + return; + + for (i = 0; i < insn->detail->x86.op_count; i++) { + cs_x86_op *op = &insn->detail->x86.operands[i]; + u64 orig_addr; + + if (op->type != X86_OP_MEM) + continue; + + /* only print RIP-based global symbols for now */ + if (op->mem.base != X86_REG_RIP) + continue; + + /* get the target address */ + orig_addr = addr + insn->size + op->mem.disp; + addr = map__objdump_2mem(map, orig_addr); + + if (map__dso(map)->kernel) { + /* + * The kernel maps can be splitted into sections, + * let's find the map first and the search the symbol. + */ + map = maps__find(map__kmaps(map), addr); + if (map == NULL) + continue; + } + + /* convert it to map-relative address for search */ + addr = map__map_ip(map, addr); + + sym = map__find_symbol(map, addr); + if (sym == NULL) + continue; + + if (addr == sym->start) { + scnprintf(buf, len, "\t# %"PRIx64" <%s>", + orig_addr, sym->name); + } else { + scnprintf(buf, len, "\t# %"PRIx64" <%s+%#"PRIx64">", + orig_addr, sym->name, addr - sym->start); + } + break; + } +} + static int symbol__disassemble_capstone(char *filename, struct symbol *sym, struct annotate_args *args) { @@ -1458,9 +1521,14 @@ static int symbol__disassemble_capstone(char *filename, struct symbol *sym, count = cs_disasm(handle, buf, len, start, len, &insn); for (i = 0, offset = 0; i < count; i++) { - scnprintf(disasm_buf, sizeof(disasm_buf), - " %-7s %s", - insn[i].mnemonic, insn[i].op_str); + int printed; + + printed = scnprintf(disasm_buf, sizeof(disasm_buf), + " %-7s %s", + insn[i].mnemonic, insn[i].op_str); + print_capstone_detail(&insn[i], disasm_buf + printed, + sizeof(disasm_buf) - printed, args, + start + offset); args->offset = offset; args->line = disasm_buf; -- cgit v1.2.3-59-g8ed1b From 089ef2f4c8b9fa609b99c96592a60c8c025dca3f Mon Sep 17 00:00:00 2001 From: Yang Jihong Date: Wed, 3 Apr 2024 20:25:58 +0800 Subject: perf beauty: Fix AT_EACCESS undeclared build error for system with kernel versions lower than v5.8 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the environment of ubuntu 20.04 (the version of kernel headers is 5.4), there is an error in building perf: CC trace/beauty/fs_at_flags.o trace/beauty/fs_at_flags.c: In function ‘faccessat2__scnprintf_flags’: trace/beauty/fs_at_flags.c:35:14: error: ‘AT_EACCESS’ undeclared (first use in this function); did you mean ‘DN_ACCESS’? 35 | if (flags & AT_EACCESS) { | ^~~~~~~~~~ | DN_ACCESS trace/beauty/fs_at_flags.c:35:14: note: each undeclared identifier is reported only once for each function it appears in commit 8a1ad4413519b10f ("tools headers: Remove now unused copies of uapi/{fcntl,openat2}.h and asm/fcntl.h") removes fcntl.h from tools headers directory, and fs_at_flags.c uses the 'AT_EACCESS' macro. This macro was introduced in the kernel version v5.8. For system with a kernel version older than this version, it will cause compilation to fail. Fixes: 8a1ad4413519b10f ("tools headers: Remove now unused copies of uapi/{fcntl,openat2}.h and asm/fcntl.h") Signed-off-by: Yang Jihong Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ian Rogers Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Kan Liang Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20240403122558.1438841-1-yangjihong@bytedance.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/trace/beauty/fs_at_flags.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tools/perf/trace/beauty/fs_at_flags.c b/tools/perf/trace/beauty/fs_at_flags.c index c1365e8f0b96..c200669cb944 100644 --- a/tools/perf/trace/beauty/fs_at_flags.c +++ b/tools/perf/trace/beauty/fs_at_flags.c @@ -10,6 +10,14 @@ #include #include +/* + * uapi/linux/fcntl.h does not keep a copy in tools headers directory, + * for system with kernel versions before v5.8, need to sync AT_EACCESS macro. + */ +#ifndef AT_EACCESS +#define AT_EACCESS 0x200 +#endif + #include "trace/beauty/generated/fs_at_flags_array.c" static DEFINE_STRARRAY(fs_at_flags, "AT_"); -- cgit v1.2.3-59-g8ed1b From baa2ca59ec1e31ccbe3f24ff0368152b36f68720 Mon Sep 17 00:00:00 2001 From: Yang Jihong Date: Thu, 14 Mar 2024 14:30:00 +0800 Subject: perf build: Add LIBTRACEEVENT_DIR build option Currently, when libtraceevent is not linked, perf does not support tracepoint: # ./perf record -e sched:sched_switch -a sleep 10 event syntax error: 'sched:sched_switch' \___ unsupported tracepoint libtraceevent is necessary for tracepoint support Run 'perf list' for a list of valid events Usage: perf record [] [] or: perf record [] -- [] -e, --event event selector. use 'perf list' to list available events For cross-compilation scenario, library may not be installed in the default system path. Based on the above requirements, add LIBTRACEEVENT_DIR build option to support specifying path of libtraceevent. Example: 1. Cross compile libtraceevent # cd /opt/libtraceevent # CROSS_COMPILE=aarch64-linux-gnu- make 2. Cross compile perf # cd tool/perf # make VF=1 ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- NO_LIBELF=1 LDFLAGS=--static LIBTRACEEVENT_DIR=/opt/libtraceevent Auto-detecting system features: ... LIBTRACEEVENT_DIR: /opt/libtraceevent Reviewed-by: Ian Rogers Signed-off-by: Yang Jihong Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ingo Molnar Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20240314063000.2139877-1-yangjihong@bytedance.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Makefile.config | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config index 1fe8df97fe88..7783479de691 100644 --- a/tools/perf/Makefile.config +++ b/tools/perf/Makefile.config @@ -182,6 +182,16 @@ endif FEATURE_CHECK_CFLAGS-libzstd := $(LIBZSTD_CFLAGS) FEATURE_CHECK_LDFLAGS-libzstd := $(LIBZSTD_LDFLAGS) +# for linking with debug library, run like: +# make DEBUG=1 LIBTRACEEVENT_DIR=/opt/libtraceevent/ +TRACEEVENTLIBS := -ltraceevent +ifdef LIBTRACEEVENT_DIR + LIBTRACEEVENT_CFLAGS := -I$(LIBTRACEEVENT_DIR)/include + LIBTRACEEVENT_LDFLAGS := -L$(LIBTRACEEVENT_DIR)/lib +endif +FEATURE_CHECK_CFLAGS-libtraceevent := $(LIBTRACEEVENT_CFLAGS) +FEATURE_CHECK_LDFLAGS-libtraceevent := $(LIBTRACEEVENT_LDFLAGS) $(TRACEEVENTLIBS) + FEATURE_CHECK_CFLAGS-bpf = -I. -I$(srctree)/tools/include -I$(srctree)/tools/arch/$(SRCARCH)/include/uapi -I$(srctree)/tools/include/uapi # include ARCH specific config -include $(src-perf)/arch/$(SRCARCH)/Makefile @@ -1165,9 +1175,10 @@ endif ifneq ($(NO_LIBTRACEEVENT),1) $(call feature_check,libtraceevent) ifeq ($(feature-libtraceevent), 1) - CFLAGS += -DHAVE_LIBTRACEEVENT - EXTLIBS += -ltraceevent - LIBTRACEEVENT_VERSION := $(shell $(PKG_CONFIG) --modversion libtraceevent) + CFLAGS += -DHAVE_LIBTRACEEVENT $(LIBTRACEEVENT_CFLAGS) + LDFLAGS += $(LIBTRACEEVENT_LDFLAGS) + EXTLIBS += ${TRACEEVENTLIBS} + LIBTRACEEVENT_VERSION := $(shell PKG_CONFIG_PATH=$(LIBTRACEEVENT_DIR) $(PKG_CONFIG) --modversion libtraceevent) LIBTRACEEVENT_VERSION_1 := $(word 1, $(subst ., ,$(LIBTRACEEVENT_VERSION))) LIBTRACEEVENT_VERSION_2 := $(word 2, $(subst ., ,$(LIBTRACEEVENT_VERSION))) LIBTRACEEVENT_VERSION_3 := $(word 3, $(subst ., ,$(LIBTRACEEVENT_VERSION))) @@ -1175,7 +1186,7 @@ ifneq ($(NO_LIBTRACEEVENT),1) CFLAGS += -DLIBTRACEEVENT_VERSION=$(LIBTRACEEVENT_VERSION_CPP) $(call detected,CONFIG_LIBTRACEEVENT) else - $(error ERROR: libtraceevent is missing. Please install libtraceevent-dev/libtraceevent-devel or build with NO_LIBTRACEEVENT=1) + $(error ERROR: libtraceevent is missing. Please install libtraceevent-dev/libtraceevent-devel and/or set LIBTRACEEVENT_DIR or build with NO_LIBTRACEEVENT=1) endif $(call feature_check,libtracefs) @@ -1301,6 +1312,7 @@ ifeq ($(VF),1) $(call print_var,LIBUNWIND_DIR) $(call print_var,LIBDW_DIR) $(call print_var,JDIR) + $(call print_var,LIBTRACEEVENT_DIR) ifeq ($(dwarf-post-unwind),1) $(call feature_print_text,"DWARF post unwind library", $(dwarf-post-unwind-text)) $(info $(MSG)) -- cgit v1.2.3-59-g8ed1b From b6347cb5e04e9c1d17342ab46e2ace2d448de727 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 3 Apr 2024 11:44:19 -0300 Subject: perf annotate: Initialize 'arch' variable not to trip some -Werror=maybe-uninitialized In some older distros the build is failing due to -Werror=maybe-uninitialized, in this case we know that this isn't the case because 'arch' gets initialized by evsel__get_arch(), so make sure it is initialized to NULL before returning from evsel__get_arch(), as suggested by Ian Rogers. E.g.: 32 17.12 opensuse:15.5 : FAIL gcc version 7.5.0 (SUSE Linux) util/annotate.c: In function 'hist_entry__get_data_type': util/annotate.c:2269:15: error: 'arch' may be used uninitialized in this function [-Werror=maybe-uninitialized] struct arch *arch; ^~~~ cc1: all warnings being treated as errors 43 7.30 ubuntu:18.04-x-powerpc64el : FAIL gcc version 7.5.0 (Ubuntu 7.5.0-3ubuntu1~18.04) util/annotate.c: In function 'hist_entry__get_data_type': util/annotate.c:2351:36: error: 'arch' may be used uninitialized in this function [-Werror=maybe-uninitialized] if (map__dso(ms->map)->kernel && arch__is(arch, "x86") && ^~~~~~~~~~~~~~~~~~~~~ cc1: all warnings being treated as errors Suggested-by: Ian Rogers Reviewed-by: Ian Rogers Cc: Adrian Hunter Cc: Jiri Olsa Cc: Namhyung Kim Link: https://lore.kernel.org/lkml/CAP-5=fUqtjxAsmdGrnkjhUTLHs-JvV10TtxyocpYDJK_+LYTiQ@mail.gmail.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index b795f27f2602..35235147b111 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -838,8 +838,10 @@ static int evsel__get_arch(struct evsel *evsel, struct arch **parch) struct arch *arch; int err; - if (!arch_name) + if (!arch_name) { + *parch = NULL; return errno; + } *parch = arch = arch__find(arch_name); if (arch == NULL) { -- cgit v1.2.3-59-g8ed1b From 650cede0415bad26f487c25e8eb3b39bfe04e740 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Thu, 28 Mar 2024 09:03:20 -0700 Subject: usb: typec: ptn36502: Only select DRM_AUX_BRIDGE with OF CONFIG_DRM_AUX_BRIDGE depends on CONFIG_OF but that dependency is not included when CONFIG_TYPEC_MUX_PTN36502 selects it, resulting in a Kconfig warning when CONFIG_OF is disabled: WARNING: unmet direct dependencies detected for DRM_AUX_BRIDGE Depends on [n]: HAS_IOMEM [=y] && DRM_BRIDGE [=y] && OF [=n] Selected by [m]: - TYPEC_MUX_PTN36502 [=m] && USB_SUPPORT [=y] && TYPEC [=m] && I2C [=y] && (DRM [=y] || DRM [=y]=n) && DRM_BRIDGE [=y] Only select CONFIG_DRM_AUX_BRIDGE when CONFIG_DRM_BRIDGE and CONFIG_OF are enabled to clear up the warning. This results in no functional change because prior to the refactoring that introduces this warning, ptn36502_register_bridge() returned 0 when CONFIG_OF was disabled, which continues to occur with drm_aux_bridge_register() when CONFIG_DRM_AUX_BRIDGE is not enabled. Fixes: 9dc28ea21eb4 ("usb: typec: ptn36502: switch to DRM_AUX_BRIDGE") Signed-off-by: Nathan Chancellor Reviewed-by: Luca Weiss Reviewed-by: Heikki Krogerus Signed-off-by: Arnd Bergmann Link: https://lore.kernel.org/r/20240328-fix-ptn36502-drm_aux_bridge-select-v1-1-85552117e26e@kernel.org Link: https://lore.kernel.org/r/20240404123534.2708591-1-arnd@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/mux/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/typec/mux/Kconfig b/drivers/usb/typec/mux/Kconfig index 4827e86fed6d..ce7db6ad3057 100644 --- a/drivers/usb/typec/mux/Kconfig +++ b/drivers/usb/typec/mux/Kconfig @@ -60,7 +60,7 @@ config TYPEC_MUX_PTN36502 tristate "NXP PTN36502 Type-C redriver driver" depends on I2C depends on DRM || DRM=n - select DRM_AUX_BRIDGE if DRM_BRIDGE + select DRM_AUX_BRIDGE if DRM_BRIDGE && OF select REGMAP_I2C help Say Y or M if your system has a NXP PTN36502 Type-C redriver chip -- cgit v1.2.3-59-g8ed1b From a2723e29c7f405e142e415efa6002479b79b57fa Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 3 Apr 2024 10:06:43 +0200 Subject: usb: gadget: omap_udc: remove unused variable The driver_desc variable is only used in some configurations: drivers/usb/gadget/udc/omap_udc.c:113:19: error: unused variable 'driver_desc' [-Werror,-Wunused-const-variable] Since there is only ever one user of it, just open-code the string in place and remove the global variable and the macro behind it. This also helps grep for the MODULE_DESCRIPTION string. Signed-off-by: Arnd Bergmann Link: https://lore.kernel.org/r/20240403080702.3509288-26-arnd@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/udc/omap_udc.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/usb/gadget/udc/omap_udc.c b/drivers/usb/gadget/udc/omap_udc.c index f90eeecf27de..e13b8ec8ef8a 100644 --- a/drivers/usb/gadget/udc/omap_udc.c +++ b/drivers/usb/gadget/udc/omap_udc.c @@ -56,7 +56,6 @@ /* ISO too */ #define USE_ISO -#define DRIVER_DESC "OMAP UDC driver" #define DRIVER_VERSION "4 October 2004" #define OMAP_DMA_USB_W2FC_TX0 29 @@ -110,7 +109,6 @@ MODULE_PARM_DESC(use_dma, "enable/disable DMA"); static const char driver_name[] = "omap_udc"; -static const char driver_desc[] = DRIVER_DESC; /*-------------------------------------------------------------------------*/ @@ -2299,13 +2297,11 @@ static int proc_udc_show(struct seq_file *s, void *_) spin_lock_irqsave(&udc->lock, flags); - seq_printf(s, "%s, version: " DRIVER_VERSION + seq_printf(s, "OMAP UDC driver, version: " DRIVER_VERSION #ifdef USE_ISO " (iso)" #endif - "%s\n", - driver_desc, - use_dma ? " (dma)" : ""); + "%s\n", use_dma ? " (dma)" : ""); tmp = omap_readw(UDC_REV) & 0xff; seq_printf(s, @@ -2994,6 +2990,6 @@ static struct platform_driver udc_driver = { module_platform_driver(udc_driver); -MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_DESCRIPTION("OMAP UDC driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:omap_udc"); -- cgit v1.2.3-59-g8ed1b From 27ffe4ff0b33b3dcc97fd448fd1e38d31ade575b Mon Sep 17 00:00:00 2001 From: Diogo Ivo Date: Wed, 27 Mar 2024 12:11:42 +0000 Subject: usb: typec: ucsi: Only enable supported notifications The UCSI specification defines some notifications to be optional for the PPM to support. From these only enable the ones the PPM informs us are actually supported. Signed-off-by: Diogo Ivo Reviewed-by: Heikki Krogerus Link: https://lore.kernel.org/r/yhz7nq622mbg3rqsyvqz632pc756niagpfbnzayfswhzo7esho@vrdtx5c3hjgx Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/ucsi/ucsi.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c index 31d8a46ae5e7..f7157215eed6 100644 --- a/drivers/usb/typec/ucsi/ucsi.c +++ b/drivers/usb/typec/ucsi/ucsi.c @@ -1672,6 +1672,27 @@ out_unlock: return ret; } +static u64 ucsi_get_supported_notifications(struct ucsi *ucsi) +{ + u8 features = ucsi->cap.features; + u64 ntfy = UCSI_ENABLE_NTFY_ALL; + + if (!(features & UCSI_CAP_ALT_MODE_DETAILS)) + ntfy &= ~UCSI_ENABLE_NTFY_CAM_CHANGE; + + if (!(features & UCSI_CAP_PDO_DETAILS)) + ntfy &= ~(UCSI_ENABLE_NTFY_PWR_LEVEL_CHANGE | + UCSI_ENABLE_NTFY_CAP_CHANGE); + + if (!(features & UCSI_CAP_EXT_SUPPLY_NOTIFICATIONS)) + ntfy &= ~UCSI_ENABLE_NTFY_EXT_PWR_SRC_CHANGE; + + if (!(features & UCSI_CAP_PD_RESET)) + ntfy &= ~UCSI_ENABLE_NTFY_PD_RESET_COMPLETE; + + return ntfy; +} + /** * ucsi_init - Initialize UCSI interface * @ucsi: UCSI to be initialized @@ -1726,8 +1747,8 @@ static int ucsi_init(struct ucsi *ucsi) goto err_unregister; } - /* Enable all notifications */ - ntfy = UCSI_ENABLE_NTFY_ALL; + /* Enable all supported notifications */ + ntfy = ucsi_get_supported_notifications(ucsi); command = UCSI_SET_NOTIFICATION_ENABLE | ntfy; ret = ucsi_send_command(ucsi, command, NULL, 0); if (ret < 0) -- cgit v1.2.3-59-g8ed1b From 6f729457a8ee097f96ee2b026d502b5249515cb3 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 31 Mar 2024 11:17:35 +0200 Subject: usb: phy: fsl-usb: drop driver owner assignment Core in platform_driver_register() already sets the .owner, so driver does not need to. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Heikki Krogerus Link: https://lore.kernel.org/r/20240331091737.19836-1-krzk@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/phy/phy-fsl-usb.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/usb/phy/phy-fsl-usb.c b/drivers/usb/phy/phy-fsl-usb.c index 79617bb0a70e..1ebbf189a535 100644 --- a/drivers/usb/phy/phy-fsl-usb.c +++ b/drivers/usb/phy/phy-fsl-usb.c @@ -1005,7 +1005,6 @@ struct platform_driver fsl_otg_driver = { .remove_new = fsl_otg_remove, .driver = { .name = driver_name, - .owner = THIS_MODULE, }, }; -- cgit v1.2.3-59-g8ed1b From 7b5a0fa49e8f0d3ce75c874371c29ad9115f8eff Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 31 Mar 2024 11:17:36 +0200 Subject: usb: typec: nvidia: drop driver owner assignment Core in typec_altmode_register_driver() already sets the .owner, so driver does not need to. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Heikki Krogerus Link: https://lore.kernel.org/r/20240331091737.19836-2-krzk@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/altmodes/nvidia.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/usb/typec/altmodes/nvidia.c b/drivers/usb/typec/altmodes/nvidia.c index c36769736405..fe70b36f078f 100644 --- a/drivers/usb/typec/altmodes/nvidia.c +++ b/drivers/usb/typec/altmodes/nvidia.c @@ -35,7 +35,6 @@ static struct typec_altmode_driver nvidia_altmode_driver = { .remove = nvidia_altmode_remove, .driver = { .name = "typec_nvidia", - .owner = THIS_MODULE, }, }; module_typec_altmode_driver(nvidia_altmode_driver); -- cgit v1.2.3-59-g8ed1b From db2ed6ec11a887dabffef0d5354e32902b704047 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 31 Mar 2024 11:17:37 +0200 Subject: usb: typec: displayport: drop driver owner assignment Core in typec_altmode_register_driver() already sets the .owner, so driver does not need to. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Heikki Krogerus Link: https://lore.kernel.org/r/20240331091737.19836-3-krzk@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/altmodes/displayport.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/usb/typec/altmodes/displayport.c b/drivers/usb/typec/altmodes/displayport.c index 038dc51f429d..596cd4806018 100644 --- a/drivers/usb/typec/altmodes/displayport.c +++ b/drivers/usb/typec/altmodes/displayport.c @@ -802,7 +802,6 @@ static struct typec_altmode_driver dp_altmode_driver = { .remove = dp_altmode_remove, .driver = { .name = "typec_displayport", - .owner = THIS_MODULE, .dev_groups = displayport_groups, }, }; -- cgit v1.2.3-59-g8ed1b From 897d68d4ce7d50ca45a31e10c0e61597257b32d3 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Fri, 29 Mar 2024 08:15:33 +0200 Subject: usb: typec: ucsi: allow non-partner GET_PDOS for Qualcomm devices The name and description of the USB_NO_PARTNER_PDOS quirk specifies that only retrieving PDOS of the attached device is crashing. Retrieving PDOS of the UCSI device works. Fix the condition to limit the workaround only to is_partner cases. Fixes: 1d103d6af241 ("usb: typec: ucsi: fix UCSI on buggy Qualcomm devices") Reviewed-by: Heikki Krogerus Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20240329-qcom-ucsi-fixes-v2-1-0f5d37ed04db@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/ucsi/ucsi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c index f7157215eed6..29a7d71c9a40 100644 --- a/drivers/usb/typec/ucsi/ucsi.c +++ b/drivers/usb/typec/ucsi/ucsi.c @@ -619,7 +619,8 @@ static int ucsi_read_pdos(struct ucsi_connector *con, u64 command; int ret; - if (ucsi->quirks & UCSI_NO_PARTNER_PDOS) + if (is_partner && + ucsi->quirks & UCSI_NO_PARTNER_PDOS) return 0; command = UCSI_COMMAND(UCSI_GET_PDOS) | UCSI_CONNECTOR_NUMBER(con->num); -- cgit v1.2.3-59-g8ed1b From 2a2eec558ec1a21c6263e291287ffa91c082e46a Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Fri, 29 Mar 2024 08:15:34 +0200 Subject: usb: typec: ucsi: limit the UCSI_NO_PARTNER_PDOS even further Reading Partner Source PDOs for the consumer Connectors appears to be working. Permit getting PDOs in this case in order to populate capabilities of the connected power supply in the sysfs. Reviewed-by: Heikki Krogerus Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20240329-qcom-ucsi-fixes-v2-2-0f5d37ed04db@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/ucsi/ucsi.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c index 29a7d71c9a40..cd0ed3938c21 100644 --- a/drivers/usb/typec/ucsi/ucsi.c +++ b/drivers/usb/typec/ucsi/ucsi.c @@ -620,7 +620,9 @@ static int ucsi_read_pdos(struct ucsi_connector *con, int ret; if (is_partner && - ucsi->quirks & UCSI_NO_PARTNER_PDOS) + ucsi->quirks & UCSI_NO_PARTNER_PDOS && + ((con->status.flags & UCSI_CONSTAT_PWR_DIR) || + !is_source(role))) return 0; command = UCSI_COMMAND(UCSI_GET_PDOS) | UCSI_CONNECTOR_NUMBER(con->num); -- cgit v1.2.3-59-g8ed1b From 9625607f15aa0c378c36c465dee1cfdf76941d08 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Fri, 29 Mar 2024 08:15:35 +0200 Subject: usb: typec: ucsi: properly register partner's PD device Use typec_partner_usb_power_delivery_register() to register PD device for Type-C partner so that the PD device is nested under the partner's device in sysfs. Reviewed-by: Heikki Krogerus Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20240329-qcom-ucsi-fixes-v2-3-0f5d37ed04db@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/ucsi/ucsi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c index cd0ed3938c21..dcaffea654f2 100644 --- a/drivers/usb/typec/ucsi/ucsi.c +++ b/drivers/usb/typec/ucsi/ucsi.c @@ -811,7 +811,7 @@ static int ucsi_register_partner_pdos(struct ucsi_connector *con) if (con->partner_pd) return 0; - con->partner_pd = usb_power_delivery_register(NULL, &desc); + con->partner_pd = typec_partner_usb_power_delivery_register(con->partner, &desc); if (IS_ERR(con->partner_pd)) return PTR_ERR(con->partner_pd); -- cgit v1.2.3-59-g8ed1b From c0f66d78f42353d38b9608c05f211cf0773d93ac Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Fri, 29 Mar 2024 08:15:36 +0200 Subject: usb: typec: ucsi: always register a link to USB PD device UCSI driver will attempt to set a USB PD device only if it was able to read PDOs from the firmware. This results in suboptimal behaviour, since the PD device will be created anyway. Move calls to typec_port_set_usb_power_delivery() out of conditional code and call it after reading capabilities. Fixes: b04e1747fbcc ("usb: typec: ucsi: Register USB Power Delivery Capabilities") Signed-off-by: Dmitry Baryshkov Reviewed-by: Heikki Krogerus Link: https://lore.kernel.org/r/20240329-qcom-ucsi-fixes-v2-4-0f5d37ed04db@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/ucsi/ucsi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c index dcaffea654f2..69611f20b3da 100644 --- a/drivers/usb/typec/ucsi/ucsi.c +++ b/drivers/usb/typec/ucsi/ucsi.c @@ -1575,7 +1575,6 @@ static int ucsi_register_port(struct ucsi *ucsi, struct ucsi_connector *con) } con->port_source_caps = pd_cap; - typec_port_set_usb_power_delivery(con->port, con->pd); } memset(&pd_caps, 0, sizeof(pd_caps)); @@ -1592,9 +1591,10 @@ static int ucsi_register_port(struct ucsi *ucsi, struct ucsi_connector *con) } con->port_sink_caps = pd_cap; - typec_port_set_usb_power_delivery(con->port, con->pd); } + typec_port_set_usb_power_delivery(con->port, con->pd); + /* Alternate modes */ ret = ucsi_register_altmodes(con, UCSI_RECIPIENT_CON); if (ret) { -- cgit v1.2.3-59-g8ed1b From 41e1cd1401fcd1f1ae9e47574af2d9fc44a870b3 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Fri, 29 Mar 2024 08:15:37 +0200 Subject: usb: typec: ucsi: simplify partner's PD caps registration In a way similar to the previous commit, move typec_partner_set_usb_power_delivery() to be called after reading the PD caps. This also removes calls to usb_power_delivery_unregister_capabilities() from the error path. Keep all capabilities registered until they are cleared by ucsi_unregister_partner_pdos(). Fixes: b04e1747fbcc ("usb: typec: ucsi: Register USB Power Delivery Capabilities") Signed-off-by: Dmitry Baryshkov Reviewed-by: Heikki Krogerus Link: https://lore.kernel.org/r/20240329-qcom-ucsi-fixes-v2-5-0f5d37ed04db@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/ucsi/ucsi.c | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c index 69611f20b3da..0da30b90e3f7 100644 --- a/drivers/usb/typec/ucsi/ucsi.c +++ b/drivers/usb/typec/ucsi/ucsi.c @@ -826,12 +826,6 @@ static int ucsi_register_partner_pdos(struct ucsi_connector *con) return PTR_ERR(cap); con->partner_source_caps = cap; - - ret = typec_partner_set_usb_power_delivery(con->partner, con->partner_pd); - if (ret) { - usb_power_delivery_unregister_capabilities(con->partner_source_caps); - return ret; - } } ret = ucsi_get_pdos(con, TYPEC_SINK, 1, caps.pdo); @@ -846,15 +840,9 @@ static int ucsi_register_partner_pdos(struct ucsi_connector *con) return PTR_ERR(cap); con->partner_sink_caps = cap; - - ret = typec_partner_set_usb_power_delivery(con->partner, con->partner_pd); - if (ret) { - usb_power_delivery_unregister_capabilities(con->partner_sink_caps); - return ret; - } } - return 0; + return typec_partner_set_usb_power_delivery(con->partner, con->partner_pd); } static void ucsi_unregister_partner_pdos(struct ucsi_connector *con) -- cgit v1.2.3-59-g8ed1b From ad4bc68bef3e5b54a70ea60b60bc20032d508992 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Fri, 29 Mar 2024 08:15:38 +0200 Subject: usb: typec: ucsi: extract code to read PD caps Extract function to read PDOs from the port and set PD capabilities accordingly. Signed-off-by: Dmitry Baryshkov Reviewed-by: Heikki Krogerus Link: https://lore.kernel.org/r/20240329-qcom-ucsi-fixes-v2-6-0f5d37ed04db@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/ucsi/ucsi.c | 85 ++++++++++++++++--------------------------- 1 file changed, 32 insertions(+), 53 deletions(-) diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c index 0da30b90e3f7..649bb69caed4 100644 --- a/drivers/usb/typec/ucsi/ucsi.c +++ b/drivers/usb/typec/ucsi/ucsi.c @@ -677,6 +677,26 @@ static int ucsi_get_src_pdos(struct ucsi_connector *con) return ret; } +static struct usb_power_delivery_capabilities *ucsi_get_pd_caps(struct ucsi_connector *con, + enum typec_role role, + bool is_partner) +{ + struct usb_power_delivery_capabilities_desc pd_caps; + int ret; + + ret = ucsi_get_pdos(con, role, is_partner, pd_caps.pdo); + if (ret <= 0) + return ERR_PTR(ret); + + if (ret < PDO_MAX_OBJECTS) + pd_caps.pdo[ret] = 0; + + pd_caps.role = role; + + return usb_power_delivery_register_capabilities(is_partner ? con->partner_pd : con->pd, + &pd_caps); +} + static int ucsi_read_identity(struct ucsi_connector *con, u8 recipient, u8 offset, u8 bytes, void *resp) { @@ -804,9 +824,7 @@ static int ucsi_check_altmodes(struct ucsi_connector *con) static int ucsi_register_partner_pdos(struct ucsi_connector *con) { struct usb_power_delivery_desc desc = { con->ucsi->cap.pd_version }; - struct usb_power_delivery_capabilities_desc caps; struct usb_power_delivery_capabilities *cap; - int ret; if (con->partner_pd) return 0; @@ -815,32 +833,17 @@ static int ucsi_register_partner_pdos(struct ucsi_connector *con) if (IS_ERR(con->partner_pd)) return PTR_ERR(con->partner_pd); - ret = ucsi_get_pdos(con, TYPEC_SOURCE, 1, caps.pdo); - if (ret > 0) { - if (ret < PDO_MAX_OBJECTS) - caps.pdo[ret] = 0; - - caps.role = TYPEC_SOURCE; - cap = usb_power_delivery_register_capabilities(con->partner_pd, &caps); - if (IS_ERR(cap)) - return PTR_ERR(cap); - - con->partner_source_caps = cap; - } - - ret = ucsi_get_pdos(con, TYPEC_SINK, 1, caps.pdo); - if (ret > 0) { - if (ret < PDO_MAX_OBJECTS) - caps.pdo[ret] = 0; + cap = ucsi_get_pd_caps(con, TYPEC_SOURCE, true); + if (IS_ERR(cap)) + return PTR_ERR(cap); - caps.role = TYPEC_SINK; + con->partner_source_caps = cap; - cap = usb_power_delivery_register_capabilities(con->partner_pd, &caps); - if (IS_ERR(cap)) - return PTR_ERR(cap); + cap = ucsi_get_pd_caps(con, TYPEC_SINK, true); + if (IS_ERR(cap)) + return PTR_ERR(cap); - con->partner_sink_caps = cap; - } + con->partner_sink_caps = cap; return typec_partner_set_usb_power_delivery(con->partner, con->partner_pd); } @@ -1469,7 +1472,6 @@ static struct fwnode_handle *ucsi_find_fwnode(struct ucsi_connector *con) static int ucsi_register_port(struct ucsi *ucsi, struct ucsi_connector *con) { struct usb_power_delivery_desc desc = { ucsi->cap.pd_version}; - struct usb_power_delivery_capabilities_desc pd_caps; struct usb_power_delivery_capabilities *pd_cap; struct typec_capability *cap = &con->typec_cap; enum typec_accessory *accessory = cap->accessory; @@ -1550,36 +1552,13 @@ static int ucsi_register_port(struct ucsi *ucsi, struct ucsi_connector *con) con->pd = usb_power_delivery_register(ucsi->dev, &desc); - ret = ucsi_get_pdos(con, TYPEC_SOURCE, 0, pd_caps.pdo); - if (ret > 0) { - if (ret < PDO_MAX_OBJECTS) - pd_caps.pdo[ret] = 0; - - pd_caps.role = TYPEC_SOURCE; - pd_cap = usb_power_delivery_register_capabilities(con->pd, &pd_caps); - if (IS_ERR(pd_cap)) { - ret = PTR_ERR(pd_cap); - goto out; - } - + pd_cap = ucsi_get_pd_caps(con, TYPEC_SOURCE, false); + if (!IS_ERR(pd_cap)) con->port_source_caps = pd_cap; - } - - memset(&pd_caps, 0, sizeof(pd_caps)); - ret = ucsi_get_pdos(con, TYPEC_SINK, 0, pd_caps.pdo); - if (ret > 0) { - if (ret < PDO_MAX_OBJECTS) - pd_caps.pdo[ret] = 0; - - pd_caps.role = TYPEC_SINK; - pd_cap = usb_power_delivery_register_capabilities(con->pd, &pd_caps); - if (IS_ERR(pd_cap)) { - ret = PTR_ERR(pd_cap); - goto out; - } + pd_cap = ucsi_get_pd_caps(con, TYPEC_SINK, false); + if (!IS_ERR(pd_cap)) con->port_sink_caps = pd_cap; - } typec_port_set_usb_power_delivery(con->port, con->pd); -- cgit v1.2.3-59-g8ed1b From 16cad519984140340375af6e0da7ef66d8a87193 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Fri, 29 Mar 2024 08:15:39 +0200 Subject: usb: typec: ucsi: support delaying GET_PDOS for device Qualcomm firmware doesn't return sane information for device's PDOs unless the partner is also using a PD mode. On SC8280XP this even results in the Error bit being set in the UCSI response (with 0 error status). Add a quirk to delay reading USB PD capabilities for a device until we detect a partner in PD mode. Signed-off-by: Dmitry Baryshkov Reviewed-by: Heikki Krogerus Link: https://lore.kernel.org/r/20240329-qcom-ucsi-fixes-v2-7-0f5d37ed04db@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/ucsi/ucsi.c | 41 ++++++++++++++++++++++++++++------------- drivers/usb/typec/ucsi/ucsi.h | 1 + 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c index 649bb69caed4..60f44b7a3907 100644 --- a/drivers/usb/typec/ucsi/ucsi.c +++ b/drivers/usb/typec/ucsi/ucsi.c @@ -821,6 +821,28 @@ static int ucsi_check_altmodes(struct ucsi_connector *con) return ret; } +static void ucsi_register_device_pdos(struct ucsi_connector *con) +{ + struct ucsi *ucsi = con->ucsi; + struct usb_power_delivery_desc desc = { ucsi->cap.pd_version }; + struct usb_power_delivery_capabilities *pd_cap; + + if (con->pd) + return; + + con->pd = usb_power_delivery_register(ucsi->dev, &desc); + + pd_cap = ucsi_get_pd_caps(con, TYPEC_SOURCE, false); + if (!IS_ERR(pd_cap)) + con->port_source_caps = pd_cap; + + pd_cap = ucsi_get_pd_caps(con, TYPEC_SINK, false); + if (!IS_ERR(pd_cap)) + con->port_sink_caps = pd_cap; + + typec_port_set_usb_power_delivery(con->port, con->pd); +} + static int ucsi_register_partner_pdos(struct ucsi_connector *con) { struct usb_power_delivery_desc desc = { con->ucsi->cap.pd_version }; @@ -981,6 +1003,9 @@ static int ucsi_register_partner(struct ucsi_connector *con) break; } + if (pwr_opmode == UCSI_CONSTAT_PWR_OPMODE_PD) + ucsi_register_device_pdos(con); + desc.identity = &con->partner_identity; desc.usb_pd = pwr_opmode == UCSI_CONSTAT_PWR_OPMODE_PD; desc.pd_revision = UCSI_CONCAP_FLAG_PARTNER_PD_MAJOR_REV_AS_BCD(con->cap.flags); @@ -1471,8 +1496,6 @@ static struct fwnode_handle *ucsi_find_fwnode(struct ucsi_connector *con) static int ucsi_register_port(struct ucsi *ucsi, struct ucsi_connector *con) { - struct usb_power_delivery_desc desc = { ucsi->cap.pd_version}; - struct usb_power_delivery_capabilities *pd_cap; struct typec_capability *cap = &con->typec_cap; enum typec_accessory *accessory = cap->accessory; enum usb_role u_role = USB_ROLE_NONE; @@ -1550,17 +1573,8 @@ static int ucsi_register_port(struct ucsi *ucsi, struct ucsi_connector *con) goto out; } - con->pd = usb_power_delivery_register(ucsi->dev, &desc); - - pd_cap = ucsi_get_pd_caps(con, TYPEC_SOURCE, false); - if (!IS_ERR(pd_cap)) - con->port_source_caps = pd_cap; - - pd_cap = ucsi_get_pd_caps(con, TYPEC_SINK, false); - if (!IS_ERR(pd_cap)) - con->port_sink_caps = pd_cap; - - typec_port_set_usb_power_delivery(con->port, con->pd); + if (!(ucsi->quirks & UCSI_DELAY_DEVICE_PDOS)) + ucsi_register_device_pdos(con); /* Alternate modes */ ret = ucsi_register_altmodes(con, UCSI_RECIPIENT_CON); @@ -1623,6 +1637,7 @@ static int ucsi_register_port(struct ucsi *ucsi, struct ucsi_connector *con) if (con->partner && UCSI_CONSTAT_PWR_OPMODE(con->status.flags) == UCSI_CONSTAT_PWR_OPMODE_PD) { + ucsi_register_device_pdos(con); ucsi_get_src_pdos(con); ucsi_check_altmodes(con); } diff --git a/drivers/usb/typec/ucsi/ucsi.h b/drivers/usb/typec/ucsi/ucsi.h index 0e7c92eb1b22..f478218cbb54 100644 --- a/drivers/usb/typec/ucsi/ucsi.h +++ b/drivers/usb/typec/ucsi/ucsi.h @@ -408,6 +408,7 @@ struct ucsi { unsigned long quirks; #define UCSI_NO_PARTNER_PDOS BIT(0) /* Don't read partner's PDOs */ +#define UCSI_DELAY_DEVICE_PDOS BIT(1) /* Reading PDOs fails until the parter is in PD mode */ }; #define UCSI_MAX_SVID 5 -- cgit v1.2.3-59-g8ed1b From 3f81cf54c1889eeecbb8d9188f5f2f597622170e Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Fri, 29 Mar 2024 08:15:40 +0200 Subject: usb: typec: ucsi_glink: rework quirks implementation In preparation to adding more quirks, extract quirks to the static variables and reference them through match->data. Otherwise adding more quirks will add the table really cumbersome. Signed-off-by: Dmitry Baryshkov Reviewed-by: Heikki Krogerus Link: https://lore.kernel.org/r/20240329-qcom-ucsi-fixes-v2-8-0f5d37ed04db@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/ucsi/ucsi_glink.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/usb/typec/ucsi/ucsi_glink.c b/drivers/usb/typec/ucsi/ucsi_glink.c index ce08eb33e5be..0e6f837f6c31 100644 --- a/drivers/usb/typec/ucsi/ucsi_glink.c +++ b/drivers/usb/typec/ucsi/ucsi_glink.c @@ -311,12 +311,14 @@ static void pmic_glink_ucsi_destroy(void *data) mutex_unlock(&ucsi->lock); } +static unsigned long quirk_sc8180x = UCSI_NO_PARTNER_PDOS; + static const struct of_device_id pmic_glink_ucsi_of_quirks[] = { - { .compatible = "qcom,qcm6490-pmic-glink", .data = (void *)UCSI_NO_PARTNER_PDOS, }, - { .compatible = "qcom,sc8180x-pmic-glink", .data = (void *)UCSI_NO_PARTNER_PDOS, }, - { .compatible = "qcom,sc8280xp-pmic-glink", .data = (void *)UCSI_NO_PARTNER_PDOS, }, - { .compatible = "qcom,sm8350-pmic-glink", .data = (void *)UCSI_NO_PARTNER_PDOS, }, - { .compatible = "qcom,sm8550-pmic-glink", .data = (void *)UCSI_NO_PARTNER_PDOS, }, + { .compatible = "qcom,qcm6490-pmic-glink", .data = &quirk_sc8180x, }, + { .compatible = "qcom,sc8180x-pmic-glink", .data = &quirk_sc8180x, }, + { .compatible = "qcom,sc8280xp-pmic-glink", .data = &quirk_sc8180x, }, + { .compatible = "qcom,sm8350-pmic-glink", .data = &quirk_sc8180x, }, + { .compatible = "qcom,sm8550-pmic-glink", .data = &quirk_sc8180x, }, {} }; @@ -354,7 +356,7 @@ static int pmic_glink_ucsi_probe(struct auxiliary_device *adev, match = of_match_device(pmic_glink_ucsi_of_quirks, dev->parent); if (match) - ucsi->ucsi->quirks = (unsigned long)match->data; + ucsi->ucsi->quirks = *(unsigned long *)match->data; ucsi_set_drvdata(ucsi->ucsi, ucsi); -- cgit v1.2.3-59-g8ed1b From 5da727f75823f3d6fea81a523584a4d931e353fa Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Fri, 29 Mar 2024 08:15:41 +0200 Subject: usb: typec: ucsi_glink: enable the UCSI_DELAY_DEVICE_PDOS quirk Enable the UCSI_DELAY_DEVICE_PDOS quirk on anything past sc8180x / sm8350. Signed-off-by: Dmitry Baryshkov Reviewed-by: Heikki Krogerus Link: https://lore.kernel.org/r/20240329-qcom-ucsi-fixes-v2-9-0f5d37ed04db@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/ucsi/ucsi_glink.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/usb/typec/ucsi/ucsi_glink.c b/drivers/usb/typec/ucsi/ucsi_glink.c index 0e6f837f6c31..ef00a6563c88 100644 --- a/drivers/usb/typec/ucsi/ucsi_glink.c +++ b/drivers/usb/typec/ucsi/ucsi_glink.c @@ -312,13 +312,16 @@ static void pmic_glink_ucsi_destroy(void *data) } static unsigned long quirk_sc8180x = UCSI_NO_PARTNER_PDOS; +static unsigned long quirk_sc8280xp = UCSI_NO_PARTNER_PDOS | UCSI_DELAY_DEVICE_PDOS; +static unsigned long quirk_sm8450 = UCSI_DELAY_DEVICE_PDOS; static const struct of_device_id pmic_glink_ucsi_of_quirks[] = { { .compatible = "qcom,qcm6490-pmic-glink", .data = &quirk_sc8180x, }, { .compatible = "qcom,sc8180x-pmic-glink", .data = &quirk_sc8180x, }, - { .compatible = "qcom,sc8280xp-pmic-glink", .data = &quirk_sc8180x, }, + { .compatible = "qcom,sc8280xp-pmic-glink", .data = &quirk_sc8280xp, }, { .compatible = "qcom,sm8350-pmic-glink", .data = &quirk_sc8180x, }, - { .compatible = "qcom,sm8550-pmic-glink", .data = &quirk_sc8180x, }, + { .compatible = "qcom,sm8450-pmic-glink", .data = &quirk_sm8450, }, + { .compatible = "qcom,sm8550-pmic-glink", .data = &quirk_sc8280xp, }, {} }; -- cgit v1.2.3-59-g8ed1b From 3f91a0bf4a0b36d5a6338ec90aedb0753112965f Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Fri, 29 Mar 2024 08:15:42 +0200 Subject: soc: qcom: pmic_glink: reenable UCSI on sc8280xp Now as all UCSI issues have been fixed, reenable UCSI subdevice on the Qualcomm SC8280XP platform. Reviewed-by: Heikki Krogerus Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20240329-qcom-ucsi-fixes-v2-10-0f5d37ed04db@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/soc/qcom/pmic_glink.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/soc/qcom/pmic_glink.c b/drivers/soc/qcom/pmic_glink.c index f913e9bd57ed..e5a591733a0f 100644 --- a/drivers/soc/qcom/pmic_glink.c +++ b/drivers/soc/qcom/pmic_glink.c @@ -343,7 +343,6 @@ static const unsigned long pmic_glink_sm8450_client_mask = BIT(PMIC_GLINK_CLIENT static const struct of_device_id pmic_glink_of_match[] = { { .compatible = "qcom,sc8180x-pmic-glink", .data = &pmic_glink_sc8180x_client_mask }, - { .compatible = "qcom,sc8280xp-pmic-glink", .data = &pmic_glink_sc8180x_client_mask }, { .compatible = "qcom,pmic-glink", .data = &pmic_glink_sm8450_client_mask }, {} }; -- cgit v1.2.3-59-g8ed1b From 6151c02160c28838141fafeb1e391c2ba3ee2a7d Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Fri, 29 Mar 2024 08:15:43 +0200 Subject: soc: qcom: pmic_glink: enable UCSI on sc8180x Now as all UCSI issues have been fixed, enable UCSI subdevice on the Qualcomm SC8180X platform. Signed-off-by: Dmitry Baryshkov Reviewed-by: Heikki Krogerus Link: https://lore.kernel.org/r/20240329-qcom-ucsi-fixes-v2-11-0f5d37ed04db@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/soc/qcom/pmic_glink.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/soc/qcom/pmic_glink.c b/drivers/soc/qcom/pmic_glink.c index e5a591733a0f..c2f71d393bbb 100644 --- a/drivers/soc/qcom/pmic_glink.c +++ b/drivers/soc/qcom/pmic_glink.c @@ -334,15 +334,11 @@ static void pmic_glink_remove(struct platform_device *pdev) mutex_unlock(&__pmic_glink_lock); } -static const unsigned long pmic_glink_sc8180x_client_mask = BIT(PMIC_GLINK_CLIENT_BATT) | - BIT(PMIC_GLINK_CLIENT_ALTMODE); - static const unsigned long pmic_glink_sm8450_client_mask = BIT(PMIC_GLINK_CLIENT_BATT) | BIT(PMIC_GLINK_CLIENT_ALTMODE) | BIT(PMIC_GLINK_CLIENT_UCSI); static const struct of_device_id pmic_glink_of_match[] = { - { .compatible = "qcom,sc8180x-pmic-glink", .data = &pmic_glink_sc8180x_client_mask }, { .compatible = "qcom,pmic-glink", .data = &pmic_glink_sm8450_client_mask }, {} }; -- cgit v1.2.3-59-g8ed1b From f3031f9b39c1e96f71bb032b73496c973ae7a60b Mon Sep 17 00:00:00 2001 From: "Christian A. Ehrhardt" Date: Wed, 27 Mar 2024 23:45:52 +0100 Subject: usb: typec: ucsi: Stop abuse of bit definitions from ucsi.h In ucsi.h there are flag definitions for the ->flags field in struct ucsi. Some implementations abuse these bits for their private ->flags fields e.g. in struct ucsi_acpi. Move the definitions into the backend implementations that still need them. While there fix one instance where the flag name was not converted in a previous change. No semantic change intended. Signed-off-by: Christian A. Ehrhardt Reviewed-by: Heikki Krogerus Tested-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20240327224554.1772525-2-lk@c--e.de Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/ucsi/ucsi.h | 2 -- drivers/usb/typec/ucsi/ucsi_acpi.c | 3 ++- drivers/usb/typec/ucsi/ucsi_stm32g0.c | 1 + 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/usb/typec/ucsi/ucsi.h b/drivers/usb/typec/ucsi/ucsi.h index f478218cbb54..2caf2969668c 100644 --- a/drivers/usb/typec/ucsi/ucsi.h +++ b/drivers/usb/typec/ucsi/ucsi.h @@ -403,8 +403,6 @@ struct ucsi { /* PPM communication flags */ unsigned long flags; #define EVENT_PENDING 0 -#define COMMAND_PENDING 1 -#define ACK_PENDING 2 unsigned long quirks; #define UCSI_NO_PARTNER_PDOS BIT(0) /* Don't read partner's PDOs */ diff --git a/drivers/usb/typec/ucsi/ucsi_acpi.c b/drivers/usb/typec/ucsi/ucsi_acpi.c index 7b3ac133ef86..cc03a49c589c 100644 --- a/drivers/usb/typec/ucsi/ucsi_acpi.c +++ b/drivers/usb/typec/ucsi/ucsi_acpi.c @@ -203,7 +203,8 @@ static void ucsi_acpi_notify(acpi_handle handle, u32 event, void *data) !test_bit(UCSI_ACPI_SUPPRESS_EVENT, &ua->flags)) ucsi_connector_change(ua->ucsi, UCSI_CCI_CONNECTOR(cci)); - if (cci & UCSI_CCI_ACK_COMPLETE && test_bit(ACK_PENDING, &ua->flags)) + if (cci & UCSI_CCI_ACK_COMPLETE && + test_bit(UCSI_ACPI_ACK_PENDING, &ua->flags)) complete(&ua->complete); if (cci & UCSI_CCI_COMMAND_COMPLETE && test_bit(UCSI_ACPI_COMMAND_PENDING, &ua->flags)) diff --git a/drivers/usb/typec/ucsi/ucsi_stm32g0.c b/drivers/usb/typec/ucsi/ucsi_stm32g0.c index 93d7806681cf..ac48b7763114 100644 --- a/drivers/usb/typec/ucsi/ucsi_stm32g0.c +++ b/drivers/usb/typec/ucsi/ucsi_stm32g0.c @@ -64,6 +64,7 @@ struct ucsi_stm32g0 { struct completion complete; struct device *dev; unsigned long flags; +#define COMMAND_PENDING 1 const char *fw_name; struct ucsi *ucsi; bool suspended; -- cgit v1.2.3-59-g8ed1b From de52aca4d9d56c3b2f00b638d457075914b1a227 Mon Sep 17 00:00:00 2001 From: "Christian A. Ehrhardt" Date: Wed, 27 Mar 2024 23:45:53 +0100 Subject: usb: typec: ucsi: Never send a lone connector change ack Some PPM implementation do not like UCSI_ACK_CONNECTOR_CHANGE without UCSI_ACK_COMMAND_COMPLETE. Moreover, doing this is racy as it requires sending two UCSI_ACK_CC_CI commands in a row and the second one will be started with UCSI_CCI_ACK_COMPLETE already set in CCI. Bundle the UCSI_ACK_CONNECTOR_CHANGE with the UCSI_ACK_COMMAND_COMPLETE for the UCSI_GET_CONNECTOR_STATUS command that is sent while handling a connector change event. Signed-off-by: Christian A. Ehrhardt Reviewed-by: Heikki Krogerus Tested-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20240327224554.1772525-3-lk@c--e.de Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/ucsi/ucsi.c | 48 +++++++++++++++++++------------------------ 1 file changed, 21 insertions(+), 27 deletions(-) diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c index 60f44b7a3907..0e37404d309a 100644 --- a/drivers/usb/typec/ucsi/ucsi.c +++ b/drivers/usb/typec/ucsi/ucsi.c @@ -49,22 +49,16 @@ static int ucsi_read_message_in(struct ucsi *ucsi, void *buf, return ucsi->ops->read(ucsi, UCSI_MESSAGE_IN, buf, buf_size); } -static int ucsi_acknowledge_command(struct ucsi *ucsi) +static int ucsi_acknowledge(struct ucsi *ucsi, bool conn_ack) { u64 ctrl; ctrl = UCSI_ACK_CC_CI; ctrl |= UCSI_ACK_COMMAND_COMPLETE; - - return ucsi->ops->sync_write(ucsi, UCSI_CONTROL, &ctrl, sizeof(ctrl)); -} - -static int ucsi_acknowledge_connector_change(struct ucsi *ucsi) -{ - u64 ctrl; - - ctrl = UCSI_ACK_CC_CI; - ctrl |= UCSI_ACK_CONNECTOR_CHANGE; + if (conn_ack) { + clear_bit(EVENT_PENDING, &ucsi->flags); + ctrl |= UCSI_ACK_CONNECTOR_CHANGE; + } return ucsi->ops->sync_write(ucsi, UCSI_CONTROL, &ctrl, sizeof(ctrl)); } @@ -77,7 +71,7 @@ static int ucsi_read_error(struct ucsi *ucsi) int ret; /* Acknowledge the command that failed */ - ret = ucsi_acknowledge_command(ucsi); + ret = ucsi_acknowledge(ucsi, false); if (ret) return ret; @@ -89,7 +83,7 @@ static int ucsi_read_error(struct ucsi *ucsi) if (ret) return ret; - ret = ucsi_acknowledge_command(ucsi); + ret = ucsi_acknowledge(ucsi, false); if (ret) return ret; @@ -152,7 +146,7 @@ static int ucsi_exec_command(struct ucsi *ucsi, u64 cmd) return -EIO; if (cci & UCSI_CCI_NOT_SUPPORTED) { - if (ucsi_acknowledge_command(ucsi) < 0) + if (ucsi_acknowledge(ucsi, false) < 0) dev_err(ucsi->dev, "ACK of unsupported command failed\n"); return -EOPNOTSUPP; @@ -165,15 +159,15 @@ static int ucsi_exec_command(struct ucsi *ucsi, u64 cmd) } if (cmd == UCSI_CANCEL && cci & UCSI_CCI_CANCEL_COMPLETE) { - ret = ucsi_acknowledge_command(ucsi); + ret = ucsi_acknowledge(ucsi, false); return ret ? ret : -EBUSY; } return UCSI_CCI_LENGTH(cci); } -int ucsi_send_command(struct ucsi *ucsi, u64 command, - void *data, size_t size) +static int ucsi_send_command_common(struct ucsi *ucsi, u64 command, + void *data, size_t size, bool conn_ack) { u8 length; int ret; @@ -192,7 +186,7 @@ int ucsi_send_command(struct ucsi *ucsi, u64 command, goto out; } - ret = ucsi_acknowledge_command(ucsi); + ret = ucsi_acknowledge(ucsi, conn_ack); if (ret) goto out; @@ -201,6 +195,12 @@ out: mutex_unlock(&ucsi->ppm_lock); return ret; } + +int ucsi_send_command(struct ucsi *ucsi, u64 command, + void *data, size_t size) +{ + return ucsi_send_command_common(ucsi, command, data, size, false); +} EXPORT_SYMBOL_GPL(ucsi_send_command); /* -------------------------------------------------------------------------- */ @@ -1187,7 +1187,9 @@ static void ucsi_handle_connector_change(struct work_struct *work) mutex_lock(&con->lock); command = UCSI_GET_CONNECTOR_STATUS | UCSI_CONNECTOR_NUMBER(con->num); - ret = ucsi_send_command(ucsi, command, &con->status, sizeof(con->status)); + + ret = ucsi_send_command_common(ucsi, command, &con->status, + sizeof(con->status), true); if (ret < 0) { dev_err(ucsi->dev, "%s: GET_CONNECTOR_STATUS failed (%d)\n", __func__, ret); @@ -1244,14 +1246,6 @@ static void ucsi_handle_connector_change(struct work_struct *work) if (con->status.change & UCSI_CONSTAT_CAM_CHANGE) ucsi_partner_task(con, ucsi_check_altmodes, 1, 0); - mutex_lock(&ucsi->ppm_lock); - clear_bit(EVENT_PENDING, &con->ucsi->flags); - ret = ucsi_acknowledge_connector_change(ucsi); - mutex_unlock(&ucsi->ppm_lock); - - if (ret) - dev_err(ucsi->dev, "%s: ACK failed (%d)", __func__, ret); - out_unlock: mutex_unlock(&con->lock); } -- cgit v1.2.3-59-g8ed1b From 4ed37ef8678daf3f8adc839c6e8fe80afd0105c1 Mon Sep 17 00:00:00 2001 From: "Christian A. Ehrhardt" Date: Wed, 27 Mar 2024 23:45:54 +0100 Subject: usb: typec: ucsi_acpi: Remove Dell quirk The Dell quirk from ucsi_acpi.c. The quirk is no longer necessary as we no longer send lone connector change acks. Signed-off-by: Christian A. Ehrhardt Reviewed-by: Heikki Krogerus Tested-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20240327224554.1772525-4-lk@c--e.de Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/ucsi/ucsi_acpi.c | 53 +------------------------------------- 1 file changed, 1 insertion(+), 52 deletions(-) diff --git a/drivers/usb/typec/ucsi/ucsi_acpi.c b/drivers/usb/typec/ucsi/ucsi_acpi.c index cc03a49c589c..8d112c3edae5 100644 --- a/drivers/usb/typec/ucsi/ucsi_acpi.c +++ b/drivers/usb/typec/ucsi/ucsi_acpi.c @@ -23,7 +23,6 @@ struct ucsi_acpi { void *base; struct completion complete; unsigned long flags; -#define UCSI_ACPI_SUPPRESS_EVENT 0 #define UCSI_ACPI_COMMAND_PENDING 1 #define UCSI_ACPI_ACK_PENDING 2 guid_t guid; @@ -129,49 +128,6 @@ static const struct ucsi_operations ucsi_zenbook_ops = { .async_write = ucsi_acpi_async_write }; -/* - * Some Dell laptops don't like ACK commands with the - * UCSI_ACK_CONNECTOR_CHANGE but not the UCSI_ACK_COMMAND_COMPLETE - * bit set. To work around this send a dummy command and bundle the - * UCSI_ACK_CONNECTOR_CHANGE with the UCSI_ACK_COMMAND_COMPLETE - * for the dummy command. - */ -static int -ucsi_dell_sync_write(struct ucsi *ucsi, unsigned int offset, - const void *val, size_t val_len) -{ - struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi); - u64 cmd = *(u64 *)val; - u64 dummycmd = UCSI_GET_CAPABILITY; - int ret; - - if (cmd == (UCSI_ACK_CC_CI | UCSI_ACK_CONNECTOR_CHANGE)) { - cmd |= UCSI_ACK_COMMAND_COMPLETE; - - /* - * The UCSI core thinks it is sending a connector change ack - * and will accept new connector change events. We don't want - * this to happen for the dummy command as its response will - * still report the very event that the core is trying to clear. - */ - set_bit(UCSI_ACPI_SUPPRESS_EVENT, &ua->flags); - ret = ucsi_acpi_sync_write(ucsi, UCSI_CONTROL, &dummycmd, - sizeof(dummycmd)); - clear_bit(UCSI_ACPI_SUPPRESS_EVENT, &ua->flags); - - if (ret < 0) - return ret; - } - - return ucsi_acpi_sync_write(ucsi, UCSI_CONTROL, &cmd, sizeof(cmd)); -} - -static const struct ucsi_operations ucsi_dell_ops = { - .read = ucsi_acpi_read, - .sync_write = ucsi_dell_sync_write, - .async_write = ucsi_acpi_async_write -}; - static const struct dmi_system_id ucsi_acpi_quirks[] = { { .matches = { @@ -180,12 +136,6 @@ static const struct dmi_system_id ucsi_acpi_quirks[] = { }, .driver_data = (void *)&ucsi_zenbook_ops, }, - { - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), - }, - .driver_data = (void *)&ucsi_dell_ops, - }, { } }; @@ -199,8 +149,7 @@ static void ucsi_acpi_notify(acpi_handle handle, u32 event, void *data) if (ret) return; - if (UCSI_CCI_CONNECTOR(cci) && - !test_bit(UCSI_ACPI_SUPPRESS_EVENT, &ua->flags)) + if (UCSI_CCI_CONNECTOR(cci)) ucsi_connector_change(ua->ucsi, UCSI_CCI_CONNECTOR(cci)); if (cci & UCSI_CCI_ACK_COMPLETE && -- cgit v1.2.3-59-g8ed1b From 51fcd7ec9df6c8e771339a03211dabd3e565f73d Mon Sep 17 00:00:00 2001 From: Alex Henrie Date: Tue, 26 Mar 2024 09:07:08 -0600 Subject: usb: misc: uss720: point pp->dev to usbdev->dev This avoids a "fix this legacy no-device port driver" warning from parport_announce_port in drivers/parport/share.c. The parport driver now requires a pointer to the device struct. Signed-off-by: Alex Henrie Acked-by: Sudip Mukherjee Link: https://lore.kernel.org/r/20240326150723.99939-2-alexhenrie24@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/uss720.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/misc/uss720.c b/drivers/usb/misc/uss720.c index b00d92db5dfd..1c940608deb5 100644 --- a/drivers/usb/misc/uss720.c +++ b/drivers/usb/misc/uss720.c @@ -720,6 +720,7 @@ static int uss720_probe(struct usb_interface *intf, priv->pp = pp; pp->private_data = priv; pp->modes = PARPORT_MODE_PCSPP | PARPORT_MODE_TRISTATE | PARPORT_MODE_EPP | PARPORT_MODE_ECP | PARPORT_MODE_COMPAT; + pp->dev = &usbdev->dev; /* set the USS720 control register to manual mode, no ECP compression, enable all ints */ set_1284_register(pp, 7, 0x00, GFP_KERNEL); -- cgit v1.2.3-59-g8ed1b From fabce53c240fa43c0deacd020f9563b36792c757 Mon Sep 17 00:00:00 2001 From: Alex Henrie Date: Tue, 26 Mar 2024 09:07:09 -0600 Subject: usb: misc: uss720: document the names of the compatible devices Information about 04b8:0002 and 05ab:0002 is from commit e3cb7bde9a6a ("USB: misc: uss720: more vendor/product ID's", 2018-03-20). The rest are from . Signed-off-by: Alex Henrie Link: https://lore.kernel.org/r/20240326150723.99939-3-alexhenrie24@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/uss720.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/usb/misc/uss720.c b/drivers/usb/misc/uss720.c index 1c940608deb5..32caf3ca300f 100644 --- a/drivers/usb/misc/uss720.c +++ b/drivers/usb/misc/uss720.c @@ -767,14 +767,14 @@ static void uss720_disconnect(struct usb_interface *intf) /* table of cables that work through this driver */ static const struct usb_device_id uss720_table[] = { - { USB_DEVICE(0x047e, 0x1001) }, - { USB_DEVICE(0x04b8, 0x0002) }, - { USB_DEVICE(0x04b8, 0x0003) }, + { USB_DEVICE(0x047e, 0x1001) }, /* Infowave 901-0030 */ + { USB_DEVICE(0x04b8, 0x0002) }, /* Epson CAEUL0002 ISD-103 */ + { USB_DEVICE(0x04b8, 0x0003) }, /* Epson ISD-101 */ { USB_DEVICE(0x050d, 0x0002) }, - { USB_DEVICE(0x050d, 0x1202) }, + { USB_DEVICE(0x050d, 0x1202) }, /* Belkin F5U120-PC */ { USB_DEVICE(0x0557, 0x2001) }, - { USB_DEVICE(0x05ab, 0x0002) }, - { USB_DEVICE(0x06c6, 0x0100) }, + { USB_DEVICE(0x05ab, 0x0002) }, /* Belkin F5U002 ISD-101 */ + { USB_DEVICE(0x06c6, 0x0100) }, /* Infowave ISD-103 */ { USB_DEVICE(0x0729, 0x1284) }, { USB_DEVICE(0x1293, 0x0002) }, { } /* Terminating entry */ -- cgit v1.2.3-59-g8ed1b From d24f05964f2dc5677c8b1f09a6ad42137467d1f0 Mon Sep 17 00:00:00 2001 From: Alex Henrie Date: Tue, 26 Mar 2024 09:07:10 -0600 Subject: usb: misc: uss720: add support for another variant of the Belkin F5U002 This device is a gray USB parallel port adapter with "F5U002" imprinted on the plastic and a sticker that says both "F5U002" and "P80453-A". It's identified in lsusb as "05ab:1001 In-System Design BAYI Printer Class Support". It's subtly different from the other gray cable I have that has "F5U002 Rev 2" and "P80453-B" on its sticker and device ID 050d:0002. The uss720 driver appears to work flawlessly with this device, although the device evidently does not support ECP. Signed-off-by: Alex Henrie Link: https://lore.kernel.org/r/20240326150723.99939-4-alexhenrie24@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/uss720.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/usb/misc/uss720.c b/drivers/usb/misc/uss720.c index 32caf3ca300f..5423da08a467 100644 --- a/drivers/usb/misc/uss720.c +++ b/drivers/usb/misc/uss720.c @@ -693,7 +693,7 @@ static int uss720_probe(struct usb_interface *intf, interface = intf->cur_altsetting; - if (interface->desc.bNumEndpoints < 3) { + if (interface->desc.bNumEndpoints < 2) { usb_put_dev(usbdev); return -ENODEV; } @@ -719,7 +719,9 @@ static int uss720_probe(struct usb_interface *intf, priv->pp = pp; pp->private_data = priv; - pp->modes = PARPORT_MODE_PCSPP | PARPORT_MODE_TRISTATE | PARPORT_MODE_EPP | PARPORT_MODE_ECP | PARPORT_MODE_COMPAT; + pp->modes = PARPORT_MODE_PCSPP | PARPORT_MODE_TRISTATE | PARPORT_MODE_EPP | PARPORT_MODE_COMPAT; + if (interface->desc.bNumEndpoints >= 3) + pp->modes |= PARPORT_MODE_ECP; pp->dev = &usbdev->dev; /* set the USS720 control register to manual mode, no ECP compression, enable all ints */ @@ -774,6 +776,7 @@ static const struct usb_device_id uss720_table[] = { { USB_DEVICE(0x050d, 0x1202) }, /* Belkin F5U120-PC */ { USB_DEVICE(0x0557, 0x2001) }, { USB_DEVICE(0x05ab, 0x0002) }, /* Belkin F5U002 ISD-101 */ + { USB_DEVICE(0x05ab, 0x1001) }, /* Belkin F5U002 P80453-A */ { USB_DEVICE(0x06c6, 0x0100) }, /* Infowave ISD-103 */ { USB_DEVICE(0x0729, 0x1284) }, { USB_DEVICE(0x1293, 0x0002) }, -- cgit v1.2.3-59-g8ed1b From 3295f1b866bfbcabd625511968e8a5c541f9ab32 Mon Sep 17 00:00:00 2001 From: Alex Henrie Date: Tue, 26 Mar 2024 09:07:11 -0600 Subject: usb: misc: uss720: check for incompatible versions of the Belkin F5U002 The incompatible device in my possession has a sticker that says "F5U002 Rev 2" and "P80453-B", and lsusb identifies it as "050d:0002 Belkin Components IEEE-1284 Controller". There is a bug report from 2007 from Michael Trausch who was seeing the exact same errors that I saw in 2024 trying to use this cable. Link: https://lore.kernel.org/all/46DE5830.9060401@trausch.us/ Signed-off-by: Alex Henrie Link: https://lore.kernel.org/r/20240326150723.99939-5-alexhenrie24@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/uss720.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/drivers/usb/misc/uss720.c b/drivers/usb/misc/uss720.c index 5423da08a467..b26c1d382d59 100644 --- a/drivers/usb/misc/uss720.c +++ b/drivers/usb/misc/uss720.c @@ -677,7 +677,7 @@ static int uss720_probe(struct usb_interface *intf, struct parport_uss720_private *priv; struct parport *pp; unsigned char reg; - int i; + int ret; dev_dbg(&intf->dev, "probe: vendor id 0x%x, device id 0x%x\n", le16_to_cpu(usbdev->descriptor.idVendor), @@ -688,8 +688,8 @@ static int uss720_probe(struct usb_interface *intf, usb_put_dev(usbdev); return -ENODEV; } - i = usb_set_interface(usbdev, intf->altsetting->desc.bInterfaceNumber, 2); - dev_dbg(&intf->dev, "set interface result %d\n", i); + ret = usb_set_interface(usbdev, intf->altsetting->desc.bInterfaceNumber, 2); + dev_dbg(&intf->dev, "set interface result %d\n", ret); interface = intf->cur_altsetting; @@ -728,12 +728,18 @@ static int uss720_probe(struct usb_interface *intf, set_1284_register(pp, 7, 0x00, GFP_KERNEL); set_1284_register(pp, 6, 0x30, GFP_KERNEL); /* PS/2 mode */ set_1284_register(pp, 2, 0x0c, GFP_KERNEL); - /* debugging */ - get_1284_register(pp, 0, ®, GFP_KERNEL); + + /* The Belkin F5U002 Rev 2 P80453-B USB parallel port adapter shares the + * device ID 050d:0002 with some other device that works with this + * driver, but it itself does not. Detect and handle the bad cable + * here. */ + ret = get_1284_register(pp, 0, ®, GFP_KERNEL); dev_dbg(&intf->dev, "reg: %7ph\n", priv->reg); + if (ret < 0) + return ret; - i = usb_find_last_int_in_endpoint(interface, &epd); - if (!i) { + ret = usb_find_last_int_in_endpoint(interface, &epd); + if (!ret) { dev_dbg(&intf->dev, "epaddr %d interval %d\n", epd->bEndpointAddress, epd->bInterval); } -- cgit v1.2.3-59-g8ed1b From b74bc5a633a7d72f89141d481d835e73bda3c3ae Mon Sep 17 00:00:00 2001 From: Thomas Richter Date: Thu, 4 Apr 2024 08:48:05 +0200 Subject: perf report: Fix PAI counter names for s390 virtual machines s390 introduced the Processor Activity Instrumentation (PAI) counter facility on LPAR and virtual machines z/VM for models 3931 and 3932. These counters are stored as raw data in the perf.data file and are displayed with: # perf report -i /tmp//perfout-635468 -D | grep Counter Counter:007 Value:0x00000000000186a0 Counter:032 Value:0x0000000000000001 Counter:032 Value:0x0000000000000001 Counter:032 Value:0x0000000000000001 # However on z/VM virtual machines, the counter names are not retrieved from the PMU and are shown as ''. This is caused by the CPU string saved in the mapfile.csv for this machine: ^IBM.393[12].*3\.7.[[:xdigit:]]+$,3,cf_z16,core This string contains the CPU Measurement facility first and second version number and authorization level (3\.7.[[:xdigit:]]+). These numbers do not apply to the PAI counter facility. In fact they can be omitted. Shorten the CPU identification string for this machine to manufacturer and model. This is sufficient for all PMU devices. Output after: # perf report -i /tmp//perfout-635468 -D | grep Counter Counter:007 km_aes_128 Value:0x00000000000186a0 Counter:032 kma_gcm_aes_256 Value:0x0000000000000001 Counter:032 kma_gcm_aes_256 Value:0x0000000000000001 Counter:032 kma_gcm_aes_256 Value:0x0000000000000001 # Fixes: b539deafbadb2fc6 ("perf report: Add s390 raw data interpretation for PAI counters") Reviewed-by: Ian Rogers Signed-off-by: Thomas Richter Acked-by: Sumanth Korikkar Cc: Heiko Carstens Cc: Namhyung Kim Cc: Sven Schnelle Cc: Thomas Richter Cc: Vasily Gorbik Link: https://lore.kernel.org/r/20240404064806.1362876-1-tmricht@linux.ibm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/pmu-events/arch/s390/mapfile.csv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/pmu-events/arch/s390/mapfile.csv b/tools/perf/pmu-events/arch/s390/mapfile.csv index a918e1af77a5..b22648d12751 100644 --- a/tools/perf/pmu-events/arch/s390/mapfile.csv +++ b/tools/perf/pmu-events/arch/s390/mapfile.csv @@ -5,4 +5,4 @@ Family-model,Version,Filename,EventType ^IBM.296[45].*[13]\.[1-5].[[:xdigit:]]+$,1,cf_z13,core ^IBM.390[67].*[13]\.[1-5].[[:xdigit:]]+$,3,cf_z14,core ^IBM.856[12].*3\.6.[[:xdigit:]]+$,3,cf_z15,core -^IBM.393[12].*3\.7.[[:xdigit:]]+$,3,cf_z16,core +^IBM.393[12].*$,3,cf_z16,core -- cgit v1.2.3-59-g8ed1b From c2f3d7dfc7373d53286f2a5c882d3397a5070adc Mon Sep 17 00:00:00 2001 From: Thomas Richter Date: Thu, 4 Apr 2024 08:48:06 +0200 Subject: perf stat: Do not fail on metrics on s390 z/VM systems On s390 z/VM virtual machines command 'perf list' also displays metrics: # perf list | grep -A 20 'Metric Groups:' Metric Groups: No_group: cpi [Cycles per Instruction] est_cpi [Estimated Instruction Complexity CPI infinite Level 1] finite_cpi [Cycles per Instructions from Finite cache/memory] l1mp [Level One Miss per 100 Instructions] l2p [Percentage sourced from Level 2 cache] l3p [Percentage sourced from Level 3 on same chip cache] l4lp [Percentage sourced from Level 4 Local cache on same book] l4rp [Percentage sourced from Level 4 Remote cache on different book] memp [Percentage sourced from memory] .... # The command # perf stat -M cpi -- true event syntax error: '{CPU_CYCLES/metric-id=CPU_CYCLES/.....' \___ Bad event or PMU Unable to find PMU or event on a PMU of 'CPU_CYCLES' event syntax error: '{CPU_CYCLES/metric-id=CPU_CYCLES/...' \___ Cannot find PMU `CPU_CYCLES'. Missing kernel support? # fails. 'perf stat' should not fail on metrics when the referenced CPU Counter Measurement PMU is not available. Output after: # perf stat -M est_cpi -- sleep 1 Performance counter stats for 'sleep 1': 1,000,887,494 ns duration_time # 0.00 est_cpi 1.000887494 seconds time elapsed 0.000143000 seconds user 0.000662000 seconds sys # Fixes: 7f76b31130680fb3 ("perf list: Add IBM z16 event description for s390") Suggested-by: Ian Rogers Reviewed-by: Ian Rogers Signed-off-by: Thomas Richter Cc: Heiko Carstens Cc: Namhyung Kim Cc: Sumanth Korikkar Cc: Sven Schnelle Cc: Vasily Gorbik Link: https://lore.kernel.org/r/20240404064806.1362876-2-tmricht@linux.ibm.com Signed-off-by: Arnaldo Carvalho de Melo --- .../pmu-events/arch/s390/cf_z16/transaction.json | 28 +++++++++++----------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/tools/perf/pmu-events/arch/s390/cf_z16/transaction.json b/tools/perf/pmu-events/arch/s390/cf_z16/transaction.json index ec2ff78e2b5f..3ab1d3a6638c 100644 --- a/tools/perf/pmu-events/arch/s390/cf_z16/transaction.json +++ b/tools/perf/pmu-events/arch/s390/cf_z16/transaction.json @@ -2,71 +2,71 @@ { "BriefDescription": "Transaction count", "MetricName": "transaction", - "MetricExpr": "TX_C_TEND + TX_NC_TEND + TX_NC_TABORT + TX_C_TABORT_SPECIAL + TX_C_TABORT_NO_SPECIAL" + "MetricExpr": "TX_C_TEND + TX_NC_TEND + TX_NC_TABORT + TX_C_TABORT_SPECIAL + TX_C_TABORT_NO_SPECIAL if has_event(TX_C_TEND) else 0" }, { "BriefDescription": "Cycles per Instruction", "MetricName": "cpi", - "MetricExpr": "CPU_CYCLES / INSTRUCTIONS" + "MetricExpr": "CPU_CYCLES / INSTRUCTIONS if has_event(INSTRUCTIONS) else 0" }, { "BriefDescription": "Problem State Instruction Ratio", "MetricName": "prbstate", - "MetricExpr": "(PROBLEM_STATE_INSTRUCTIONS / INSTRUCTIONS) * 100" + "MetricExpr": "(PROBLEM_STATE_INSTRUCTIONS / INSTRUCTIONS) * 100 if has_event(INSTRUCTIONS) else 0" }, { "BriefDescription": "Level One Miss per 100 Instructions", "MetricName": "l1mp", - "MetricExpr": "((L1I_DIR_WRITES + L1D_DIR_WRITES) / INSTRUCTIONS) * 100" + "MetricExpr": "((L1I_DIR_WRITES + L1D_DIR_WRITES) / INSTRUCTIONS) * 100 if has_event(INSTRUCTIONS) else 0" }, { "BriefDescription": "Percentage sourced from Level 2 cache", "MetricName": "l2p", - "MetricExpr": "((DCW_REQ + DCW_REQ_IV + ICW_REQ + ICW_REQ_IV) / (L1I_DIR_WRITES + L1D_DIR_WRITES)) * 100" + "MetricExpr": "((DCW_REQ + DCW_REQ_IV + ICW_REQ + ICW_REQ_IV) / (L1I_DIR_WRITES + L1D_DIR_WRITES)) * 100 if has_event(DCW_REQ) else 0" }, { "BriefDescription": "Percentage sourced from Level 3 on same chip cache", "MetricName": "l3p", - "MetricExpr": "((DCW_REQ_CHIP_HIT + DCW_ON_CHIP + DCW_ON_CHIP_IV + DCW_ON_CHIP_CHIP_HIT + ICW_REQ_CHIP_HIT + ICW_ON_CHIP + ICW_ON_CHIP_IV + ICW_ON_CHIP_CHIP_HIT) / (L1I_DIR_WRITES + L1D_DIR_WRITES)) * 100" + "MetricExpr": "((DCW_REQ_CHIP_HIT + DCW_ON_CHIP + DCW_ON_CHIP_IV + DCW_ON_CHIP_CHIP_HIT + ICW_REQ_CHIP_HIT + ICW_ON_CHIP + ICW_ON_CHIP_IV + ICW_ON_CHIP_CHIP_HIT) / (L1I_DIR_WRITES + L1D_DIR_WRITES)) * 100 if has_event(DCW_REQ_CHIP_HIT) else 0" }, { "BriefDescription": "Percentage sourced from Level 4 Local cache on same book", "MetricName": "l4lp", - "MetricExpr": "((DCW_REQ_DRAWER_HIT + DCW_ON_CHIP_DRAWER_HIT + DCW_ON_MODULE + DCW_ON_DRAWER + IDCW_ON_MODULE_IV + IDCW_ON_MODULE_CHIP_HIT + IDCW_ON_MODULE_DRAWER_HIT + IDCW_ON_DRAWER_IV + IDCW_ON_DRAWER_CHIP_HIT + IDCW_ON_DRAWER_DRAWER_HIT + ICW_REQ_DRAWER_HIT + ICW_ON_CHIP_DRAWER_HIT + ICW_ON_MODULE + ICW_ON_DRAWER) / (L1I_DIR_WRITES + L1D_DIR_WRITES)) * 100" + "MetricExpr": "((DCW_REQ_DRAWER_HIT + DCW_ON_CHIP_DRAWER_HIT + DCW_ON_MODULE + DCW_ON_DRAWER + IDCW_ON_MODULE_IV + IDCW_ON_MODULE_CHIP_HIT + IDCW_ON_MODULE_DRAWER_HIT + IDCW_ON_DRAWER_IV + IDCW_ON_DRAWER_CHIP_HIT + IDCW_ON_DRAWER_DRAWER_HIT + ICW_REQ_DRAWER_HIT + ICW_ON_CHIP_DRAWER_HIT + ICW_ON_MODULE + ICW_ON_DRAWER) / (L1I_DIR_WRITES + L1D_DIR_WRITES)) * 100 if has_event(DCW_REQ_DRAWER_HIT) else 0" }, { "BriefDescription": "Percentage sourced from Level 4 Remote cache on different book", "MetricName": "l4rp", - "MetricExpr": "((DCW_OFF_DRAWER + IDCW_OFF_DRAWER_IV + IDCW_OFF_DRAWER_CHIP_HIT + IDCW_OFF_DRAWER_DRAWER_HIT + ICW_OFF_DRAWER) / (L1I_DIR_WRITES + L1D_DIR_WRITES)) * 100" + "MetricExpr": "((DCW_OFF_DRAWER + IDCW_OFF_DRAWER_IV + IDCW_OFF_DRAWER_CHIP_HIT + IDCW_OFF_DRAWER_DRAWER_HIT + ICW_OFF_DRAWER) / (L1I_DIR_WRITES + L1D_DIR_WRITES)) * 100 if has_event(DCW_OFF_DRAWER) else 0" }, { "BriefDescription": "Percentage sourced from memory", "MetricName": "memp", - "MetricExpr": "((DCW_ON_CHIP_MEMORY + DCW_ON_MODULE_MEMORY + DCW_ON_DRAWER_MEMORY + DCW_OFF_DRAWER_MEMORY + ICW_ON_CHIP_MEMORY + ICW_ON_MODULE_MEMORY + ICW_ON_DRAWER_MEMORY + ICW_OFF_DRAWER_MEMORY) / (L1I_DIR_WRITES + L1D_DIR_WRITES)) * 100" + "MetricExpr": "((DCW_ON_CHIP_MEMORY + DCW_ON_MODULE_MEMORY + DCW_ON_DRAWER_MEMORY + DCW_OFF_DRAWER_MEMORY + ICW_ON_CHIP_MEMORY + ICW_ON_MODULE_MEMORY + ICW_ON_DRAWER_MEMORY + ICW_OFF_DRAWER_MEMORY) / (L1I_DIR_WRITES + L1D_DIR_WRITES)) * 100 if has_event(DCW_ON_CHIP_MEMORY) else 0" }, { "BriefDescription": "Cycles per Instructions from Finite cache/memory", "MetricName": "finite_cpi", - "MetricExpr": "L1C_TLB2_MISSES / INSTRUCTIONS" + "MetricExpr": "L1C_TLB2_MISSES / INSTRUCTIONS if has_event(L1C_TLB2_MISSES) else 0" }, { "BriefDescription": "Estimated Instruction Complexity CPI infinite Level 1", "MetricName": "est_cpi", - "MetricExpr": "(CPU_CYCLES / INSTRUCTIONS) - (L1C_TLB2_MISSES / INSTRUCTIONS)" + "MetricExpr": "(CPU_CYCLES / INSTRUCTIONS) - (L1C_TLB2_MISSES / INSTRUCTIONS) if has_event(INSTRUCTIONS) else 0" }, { "BriefDescription": "Estimated Sourcing Cycles per Level 1 Miss", "MetricName": "scpl1m", - "MetricExpr": "L1C_TLB2_MISSES / (L1I_DIR_WRITES + L1D_DIR_WRITES)" + "MetricExpr": "L1C_TLB2_MISSES / (L1I_DIR_WRITES + L1D_DIR_WRITES) if has_event(L1C_TLB2_MISSES) else 0" }, { "BriefDescription": "Estimated TLB CPU percentage of Total CPU", "MetricName": "tlb_percent", - "MetricExpr": "((DTLB2_MISSES + ITLB2_MISSES) / CPU_CYCLES) * (L1C_TLB2_MISSES / (L1I_PENALTY_CYCLES + L1D_PENALTY_CYCLES)) * 100" + "MetricExpr": "((DTLB2_MISSES + ITLB2_MISSES) / CPU_CYCLES) * (L1C_TLB2_MISSES / (L1I_PENALTY_CYCLES + L1D_PENALTY_CYCLES)) * 100 if has_event(CPU_CYCLES) else 0" }, { "BriefDescription": "Estimated Cycles per TLB Miss", "MetricName": "tlb_miss", - "MetricExpr": "((DTLB2_MISSES + ITLB2_MISSES) / (DTLB2_WRITES + ITLB2_WRITES)) * (L1C_TLB2_MISSES / (L1I_PENALTY_CYCLES + L1D_PENALTY_CYCLES))" + "MetricExpr": "((DTLB2_MISSES + ITLB2_MISSES) / (DTLB2_WRITES + ITLB2_WRITES)) * (L1C_TLB2_MISSES / (L1I_PENALTY_CYCLES + L1D_PENALTY_CYCLES)) if has_event(DTLB2_MISSES) else 0" } ] -- cgit v1.2.3-59-g8ed1b From 8ee1b439b1540ae543149b15a2a61b9dff937d91 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 26 Mar 2024 09:01:16 +0000 Subject: soundwire: cadence: fix invalid PDI offset For some reason, we add an offset to the PDI, presumably to skip the PDI0 and PDI1 which are reserved for BPT. This code is however completely wrong and leads to an out-of-bounds access. We were just lucky so far since we used only a couple of PDIs and remained within the PDI array bounds. A Fixes: tag is not provided since there are no known platforms where the out-of-bounds would be accessed, and the initial code had problems as well. A follow-up patch completely removes this useless offset. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Signed-off-by: Bard Liao Link: https://lore.kernel.org/r/20240326090122.1051806-2-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- drivers/soundwire/cadence_master.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c index 0efc1c3bee5f..3e7cf04aaf2a 100644 --- a/drivers/soundwire/cadence_master.c +++ b/drivers/soundwire/cadence_master.c @@ -1880,7 +1880,7 @@ struct sdw_cdns_pdi *sdw_cdns_alloc_pdi(struct sdw_cdns *cdns, /* check if we found a PDI, else find in bi-directional */ if (!pdi) - pdi = cdns_find_pdi(cdns, 2, stream->num_bd, stream->bd, + pdi = cdns_find_pdi(cdns, 0, stream->num_bd, stream->bd, dai_id); if (pdi) { -- cgit v1.2.3-59-g8ed1b From 1845165fbd6e746c60e8f2e4fc88febd6a195143 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 26 Mar 2024 09:01:17 +0000 Subject: soundwire: cadence: remove PDI offset completely This offset is set to exactly zero and serves no purpose. Remove. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Signed-off-by: Bard Liao Link: https://lore.kernel.org/r/20240326090122.1051806-3-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- drivers/soundwire/cadence_master.c | 30 +++++++++--------------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c index 3e7cf04aaf2a..c2c1463a5c53 100644 --- a/drivers/soundwire/cadence_master.c +++ b/drivers/soundwire/cadence_master.c @@ -1236,7 +1236,7 @@ EXPORT_SYMBOL(sdw_cdns_enable_interrupt); static int cdns_allocate_pdi(struct sdw_cdns *cdns, struct sdw_cdns_pdi **stream, - u32 num, u32 pdi_offset) + u32 num) { struct sdw_cdns_pdi *pdi; int i; @@ -1249,7 +1249,7 @@ static int cdns_allocate_pdi(struct sdw_cdns *cdns, return -ENOMEM; for (i = 0; i < num; i++) { - pdi[i].num = i + pdi_offset; + pdi[i].num = i; } *stream = pdi; @@ -1266,7 +1266,6 @@ int sdw_cdns_pdi_init(struct sdw_cdns *cdns, struct sdw_cdns_stream_config config) { struct sdw_cdns_streams *stream; - int offset; int ret; cdns->pcm.num_bd = config.pcm_bd; @@ -1277,24 +1276,15 @@ int sdw_cdns_pdi_init(struct sdw_cdns *cdns, stream = &cdns->pcm; /* we allocate PDI0 and PDI1 which are used for Bulk */ - offset = 0; - - ret = cdns_allocate_pdi(cdns, &stream->bd, - stream->num_bd, offset); + ret = cdns_allocate_pdi(cdns, &stream->bd, stream->num_bd); if (ret) return ret; - offset += stream->num_bd; - - ret = cdns_allocate_pdi(cdns, &stream->in, - stream->num_in, offset); + ret = cdns_allocate_pdi(cdns, &stream->in, stream->num_in); if (ret) return ret; - offset += stream->num_in; - - ret = cdns_allocate_pdi(cdns, &stream->out, - stream->num_out, offset); + ret = cdns_allocate_pdi(cdns, &stream->out, stream->num_out); if (ret) return ret; @@ -1802,7 +1792,6 @@ EXPORT_SYMBOL(cdns_set_sdw_stream); * cdns_find_pdi() - Find a free PDI * * @cdns: Cadence instance - * @offset: Starting offset * @num: Number of PDIs * @pdi: PDI instances * @dai_id: DAI id @@ -1811,14 +1800,13 @@ EXPORT_SYMBOL(cdns_set_sdw_stream); * expected to match, return NULL otherwise. */ static struct sdw_cdns_pdi *cdns_find_pdi(struct sdw_cdns *cdns, - unsigned int offset, unsigned int num, struct sdw_cdns_pdi *pdi, int dai_id) { int i; - for (i = offset; i < offset + num; i++) + for (i = 0; i < num; i++) if (pdi[i].num == dai_id) return &pdi[i]; @@ -1872,15 +1860,15 @@ struct sdw_cdns_pdi *sdw_cdns_alloc_pdi(struct sdw_cdns *cdns, struct sdw_cdns_pdi *pdi = NULL; if (dir == SDW_DATA_DIR_RX) - pdi = cdns_find_pdi(cdns, 0, stream->num_in, stream->in, + pdi = cdns_find_pdi(cdns, stream->num_in, stream->in, dai_id); else - pdi = cdns_find_pdi(cdns, 0, stream->num_out, stream->out, + pdi = cdns_find_pdi(cdns, stream->num_out, stream->out, dai_id); /* check if we found a PDI, else find in bi-directional */ if (!pdi) - pdi = cdns_find_pdi(cdns, 0, stream->num_bd, stream->bd, + pdi = cdns_find_pdi(cdns, stream->num_bd, stream->bd, dai_id); if (pdi) { -- cgit v1.2.3-59-g8ed1b From 59401c3c08e1a306e29a8d6c826685e2c5c6c794 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 26 Mar 2024 09:01:18 +0000 Subject: soundwire: remove unused sdw_bus_conf structure This is redundant with sdw_bus_params, and was never used. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Signed-off-by: Bard Liao Link: https://lore.kernel.org/r/20240326090122.1051806-4-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- include/linux/soundwire/sdw.h | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h index 66f814b63a43..e5d0aa58e7f6 100644 --- a/include/linux/soundwire/sdw.h +++ b/include/linux/soundwire/sdw.h @@ -542,21 +542,6 @@ enum sdw_reg_bank { SDW_BANK1, }; -/** - * struct sdw_bus_conf: Bus configuration - * - * @clk_freq: Clock frequency, in Hz - * @num_rows: Number of rows in frame - * @num_cols: Number of columns in frame - * @bank: Next register bank - */ -struct sdw_bus_conf { - unsigned int clk_freq; - unsigned int num_rows; - unsigned int num_cols; - unsigned int bank; -}; - /** * struct sdw_prepare_ch: Prepare/De-prepare Data Port channel * -- cgit v1.2.3-59-g8ed1b From bc13cf3f6e63dd708ccd160a28e6bb696af7e9f6 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 26 Mar 2024 09:01:20 +0000 Subject: soundwire: clarify maximum allowed address The existing code sets the maximum address at 0x80000000, which is not completely accurate. The last 2 Gbytes are indeed reserved, but so are the 896 Mbytes just before. The maximum address which can be used with paging or BRA is 0x47FFFFFF per Table 131 of the SoundWire 1.2.1 specification. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Signed-off-by: Bard Liao Link: https://lore.kernel.org/r/20240326090122.1051806-6-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- include/linux/soundwire/sdw_registers.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/soundwire/sdw_registers.h b/include/linux/soundwire/sdw_registers.h index 138bec908c40..658b10fa5b20 100644 --- a/include/linux/soundwire/sdw_registers.h +++ b/include/linux/soundwire/sdw_registers.h @@ -13,7 +13,7 @@ #define SDW_REG_NO_PAGE 0x00008000 #define SDW_REG_OPTIONAL_PAGE 0x00010000 -#define SDW_REG_MAX 0x80000000 +#define SDW_REG_MAX 0x48000000 #define SDW_DPN_SIZE 0x100 #define SDW_BANK1_OFFSET 0x10 -- cgit v1.2.3-59-g8ed1b From 8292c815bbb71ea9f86331c3d07d2b9530b93565 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 26 Mar 2024 09:20:24 +0000 Subject: soundwire: cadence: show the bus frequency and frame shape This log is useful when trying different configurations, specifically to make sure ACPI initrd overrides have been taken into account. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Signed-off-by: Bard Liao Link: https://lore.kernel.org/r/20240326092030.1062802-2-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- drivers/soundwire/cadence_master.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c index c2c1463a5c53..74da99034dab 100644 --- a/drivers/soundwire/cadence_master.c +++ b/drivers/soundwire/cadence_master.c @@ -1319,6 +1319,12 @@ static void cdns_init_clock_ctrl(struct sdw_cdns *cdns) u32 ssp_interval; int divider; + dev_dbg(cdns->dev, "mclk %d max %d row %d col %d\n", + prop->mclk_freq, + prop->max_clk_freq, + prop->default_row, + prop->default_col); + /* Set clock divider */ divider = (prop->mclk_freq / prop->max_clk_freq) - 1; -- cgit v1.2.3-59-g8ed1b From 7eca9c722eed80f76cd272a52d9fa98f89322e7e Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 26 Mar 2024 09:20:25 +0000 Subject: soundwire: bus: extend base clock checks to 96 MHz Starting with MeteorLake, the input frequency to the SoundWire IP can be 96MHz. The existing code is limited to 24MHz, change accordingly and move branch after the 32MHz case to avoid issues. While we're at it, reorder the frequencies by increasing order. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Signed-off-by: Bard Liao Link: https://lore.kernel.org/r/20240326092030.1062802-3-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- drivers/soundwire/bus.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c index 05b2db00d9cd..191e6cc6f962 100644 --- a/drivers/soundwire/bus.c +++ b/drivers/soundwire/bus.c @@ -1312,18 +1312,18 @@ static int sdw_slave_set_frequency(struct sdw_slave *slave) if (!(19200000 % mclk_freq)) { mclk_freq = 19200000; base = SDW_SCP_BASE_CLOCK_19200000_HZ; - } else if (!(24000000 % mclk_freq)) { - mclk_freq = 24000000; - base = SDW_SCP_BASE_CLOCK_24000000_HZ; - } else if (!(24576000 % mclk_freq)) { - mclk_freq = 24576000; - base = SDW_SCP_BASE_CLOCK_24576000_HZ; } else if (!(22579200 % mclk_freq)) { mclk_freq = 22579200; base = SDW_SCP_BASE_CLOCK_22579200_HZ; + } else if (!(24576000 % mclk_freq)) { + mclk_freq = 24576000; + base = SDW_SCP_BASE_CLOCK_24576000_HZ; } else if (!(32000000 % mclk_freq)) { mclk_freq = 32000000; base = SDW_SCP_BASE_CLOCK_32000000_HZ; + } else if (!(96000000 % mclk_freq)) { + mclk_freq = 24000000; + base = SDW_SCP_BASE_CLOCK_24000000_HZ; } else { dev_err(&slave->dev, "Unsupported clock base, mclk %d\n", -- cgit v1.2.3-59-g8ed1b From d0a69cd0369a390cc1c100e52e78a273695a170c Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 26 Mar 2024 09:20:26 +0000 Subject: soundwire: intel: add more values for SYNCPRD Starting with MeteorLake, the input to the SoundWire IP can be 24.576 MHz (aka Audio Cardinal Clock) or 96 MHz (Audio PLL). Signed-off-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Signed-off-by: Bard Liao Link: https://lore.kernel.org/r/20240326092030.1062802-4-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- include/linux/soundwire/sdw_intel.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/include/linux/soundwire/sdw_intel.h b/include/linux/soundwire/sdw_intel.h index 00bb22d96ae5..fa40b85d5019 100644 --- a/include/linux/soundwire/sdw_intel.h +++ b/include/linux/soundwire/sdw_intel.h @@ -34,8 +34,10 @@ /* SYNC */ #define SDW_SHIM_SYNC 0xC -#define SDW_SHIM_SYNC_SYNCPRD_VAL_24 (24000 / SDW_CADENCE_GSYNC_KHZ - 1) -#define SDW_SHIM_SYNC_SYNCPRD_VAL_38_4 (38400 / SDW_CADENCE_GSYNC_KHZ - 1) +#define SDW_SHIM_SYNC_SYNCPRD_VAL_24 (24000 / SDW_CADENCE_GSYNC_KHZ - 1) +#define SDW_SHIM_SYNC_SYNCPRD_VAL_24_576 (24576 / SDW_CADENCE_GSYNC_KHZ - 1) +#define SDW_SHIM_SYNC_SYNCPRD_VAL_38_4 (38400 / SDW_CADENCE_GSYNC_KHZ - 1) +#define SDW_SHIM_SYNC_SYNCPRD_VAL_96 (96000 / SDW_CADENCE_GSYNC_KHZ - 1) #define SDW_SHIM_SYNC_SYNCPRD GENMASK(14, 0) #define SDW_SHIM_SYNC_SYNCCPU BIT(15) #define SDW_SHIM_SYNC_CMDSYNC_MASK GENMASK(19, 16) -- cgit v1.2.3-59-g8ed1b From 09ee49e3de6bcecc57028682c673d180ec2d436b Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 26 Mar 2024 09:20:27 +0000 Subject: soundwire: intel: add support for MeteorLake additional clocks In the MeteorLake hardware, the SoundWire link clock can be selected from the Xtal, audio cardinal clock (24.576 MHz) or the 96 MHz audio PLL. This patches add the clock selection in a backwards-compatible manner, using the ACPI firmware as the source of information and checking its compatibility with hardware capabilities. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Signed-off-by: Bard Liao Link: https://lore.kernel.org/r/20240326092030.1062802-5-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- drivers/soundwire/intel.c | 43 +++++++++++++++++++++++++++++++------ include/linux/soundwire/sdw_intel.h | 5 +++++ 2 files changed, 42 insertions(+), 6 deletions(-) diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index 839268175079..01e1a0f3ec39 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -345,8 +345,10 @@ static int intel_link_power_up(struct sdw_intel *sdw) u32 spa_mask, cpa_mask; u32 link_control; int ret = 0; + u32 clock_source; u32 syncprd; u32 sync_reg; + bool lcap_mlcs; mutex_lock(sdw->link_res->shim_lock); @@ -358,12 +360,35 @@ static int intel_link_power_up(struct sdw_intel *sdw) * is only dependent on the oscillator clock provided to * the IP, so adjust based on _DSD properties reported in DSDT * tables. The values reported are based on either 24MHz - * (CNL/CML) or 38.4 MHz (ICL/TGL+). + * (CNL/CML) or 38.4 MHz (ICL/TGL+). On MeteorLake additional + * frequencies are available with the MLCS clock source selection. */ - if (prop->mclk_freq % 6000000) - syncprd = SDW_SHIM_SYNC_SYNCPRD_VAL_38_4; - else - syncprd = SDW_SHIM_SYNC_SYNCPRD_VAL_24; + lcap_mlcs = intel_readl(shim, SDW_SHIM_LCAP) & SDW_SHIM_LCAP_MLCS_MASK; + + if (prop->mclk_freq % 6000000) { + if (prop->mclk_freq % 2400000) { + if (lcap_mlcs) { + syncprd = SDW_SHIM_SYNC_SYNCPRD_VAL_24_576; + clock_source = SDW_SHIM_MLCS_CARDINAL_CLK; + } else { + dev_err(sdw->cdns.dev, "%s: invalid clock configuration, mclk %d lcap_mlcs %d\n", + __func__, prop->mclk_freq, lcap_mlcs); + ret = -EINVAL; + goto out; + } + } else { + syncprd = SDW_SHIM_SYNC_SYNCPRD_VAL_38_4; + clock_source = SDW_SHIM_MLCS_XTAL_CLK; + } + } else { + if (lcap_mlcs) { + syncprd = SDW_SHIM_SYNC_SYNCPRD_VAL_96; + clock_source = SDW_SHIM_MLCS_AUDIO_PLL_CLK; + } else { + syncprd = SDW_SHIM_SYNC_SYNCPRD_VAL_24; + clock_source = SDW_SHIM_MLCS_XTAL_CLK; + } + } if (!*shim_mask) { dev_dbg(sdw->cdns.dev, "powering up all links\n"); @@ -403,6 +428,13 @@ static int intel_link_power_up(struct sdw_intel *sdw) "Failed to set SHIM_SYNC: %d\n", ret); goto out; } + + /* update link clock if needed */ + if (lcap_mlcs) { + link_control = intel_readl(shim, SDW_SHIM_LCTL); + u32p_replace_bits(&link_control, clock_source, SDW_SHIM_LCTL_MLCS_MASK); + intel_writel(shim, SDW_SHIM_LCTL, link_control); + } } *shim_mask |= BIT(link_id); @@ -1087,4 +1119,3 @@ const struct sdw_intel_hw_ops sdw_intel_cnl_hw_ops = { .sync_check_cmdsync_unlocked = intel_check_cmdsync_unlocked, }; EXPORT_SYMBOL_NS(sdw_intel_cnl_hw_ops, SOUNDWIRE_INTEL); - diff --git a/include/linux/soundwire/sdw_intel.h b/include/linux/soundwire/sdw_intel.h index fa40b85d5019..8e78417156e3 100644 --- a/include/linux/soundwire/sdw_intel.h +++ b/include/linux/soundwire/sdw_intel.h @@ -22,6 +22,7 @@ /* LCAP */ #define SDW_SHIM_LCAP 0x0 #define SDW_SHIM_LCAP_LCOUNT_MASK GENMASK(2, 0) +#define SDW_SHIM_LCAP_MLCS_MASK BIT(8) /* LCTL */ #define SDW_SHIM_LCTL 0x4 @@ -30,6 +31,10 @@ #define SDW_SHIM_LCTL_SPA_MASK GENMASK(3, 0) #define SDW_SHIM_LCTL_CPA BIT(8) #define SDW_SHIM_LCTL_CPA_MASK GENMASK(11, 8) +#define SDW_SHIM_LCTL_MLCS_MASK GENMASK(29, 27) +#define SDW_SHIM_MLCS_XTAL_CLK 0x0 +#define SDW_SHIM_MLCS_CARDINAL_CLK 0x1 +#define SDW_SHIM_MLCS_AUDIO_PLL_CLK 0x2 /* SYNC */ #define SDW_SHIM_SYNC 0xC -- cgit v1.2.3-59-g8ed1b From 769d69812b42f0fc710bdf16b9f3979c959910b7 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 26 Mar 2024 09:20:28 +0000 Subject: soundwire: intel_ace2x: move and extend clock selection The input clock to the SoundWire IP can be 38.4 MHz (xtal clock source) 24.576 MHz (audio cardinal clock) 96 MHz (internal Audio PLL) This patch moves the clock selection outside the mutex and add the new choices for 24.576 and 96 MHz, but doesn't add any functionality. Follow-up patches will add support for clock selection. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Signed-off-by: Bard Liao Link: https://lore.kernel.org/r/20240326092030.1062802-6-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- drivers/soundwire/intel_ace2x.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/drivers/soundwire/intel_ace2x.c b/drivers/soundwire/intel_ace2x.c index 8280baa3254b..abdd651a185c 100644 --- a/drivers/soundwire/intel_ace2x.c +++ b/drivers/soundwire/intel_ace2x.c @@ -74,20 +74,29 @@ static int intel_link_power_up(struct sdw_intel *sdw) struct sdw_master_prop *prop = &bus->prop; u32 *shim_mask = sdw->link_res->shim_mask; unsigned int link_id = sdw->instance; + u32 clock_source; u32 syncprd; int ret; + if (prop->mclk_freq % 6000000) { + if (prop->mclk_freq % 2400000) { + syncprd = SDW_SHIM_SYNC_SYNCPRD_VAL_24_576; + clock_source = SDW_SHIM2_MLCS_CARDINAL_CLK; + } else { + syncprd = SDW_SHIM_SYNC_SYNCPRD_VAL_38_4; + clock_source = SDW_SHIM2_MLCS_XTAL_CLK; + } + } else { + syncprd = SDW_SHIM_SYNC_SYNCPRD_VAL_96; + clock_source = SDW_SHIM2_MLCS_AUDIO_PLL_CLK; + } + mutex_lock(sdw->link_res->shim_lock); if (!*shim_mask) { /* we first need to program the SyncPRD/CPU registers */ dev_dbg(sdw->cdns.dev, "first link up, programming SYNCPRD\n"); - if (prop->mclk_freq % 6000000) - syncprd = SDW_SHIM_SYNC_SYNCPRD_VAL_38_4; - else - syncprd = SDW_SHIM_SYNC_SYNCPRD_VAL_24; - ret = hdac_bus_eml_sdw_set_syncprd_unlocked(sdw->link_res->hbus, syncprd); if (ret < 0) { dev_err(sdw->cdns.dev, "%s: hdac_bus_eml_sdw_set_syncprd failed: %d\n", -- cgit v1.2.3-59-g8ed1b From a206d2e3409f58733c9097523e5f62ebb920fbbf Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 26 Mar 2024 09:20:29 +0000 Subject: soundwire: intel_ace2.x: power-up first before setting SYNCPRD The existing sequence is fine if we want to only use the xtal clock. However if we want to select the clock, we first need to power-up, then select the clock and last set the SYNCPRD. This patch first modifies the order, we will add the clock selection as a follow-up. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Signed-off-by: Bard Liao Link: https://lore.kernel.org/r/20240326092030.1062802-7-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- drivers/soundwire/intel_ace2x.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/drivers/soundwire/intel_ace2x.c b/drivers/soundwire/intel_ace2x.c index abdd651a185c..d8ae05cf3d57 100644 --- a/drivers/soundwire/intel_ace2x.c +++ b/drivers/soundwire/intel_ace2x.c @@ -93,6 +93,13 @@ static int intel_link_power_up(struct sdw_intel *sdw) mutex_lock(sdw->link_res->shim_lock); + ret = hdac_bus_eml_sdw_power_up_unlocked(sdw->link_res->hbus, link_id); + if (ret < 0) { + dev_err(sdw->cdns.dev, "%s: hdac_bus_eml_sdw_power_up failed: %d\n", + __func__, ret); + goto out; + } + if (!*shim_mask) { /* we first need to program the SyncPRD/CPU registers */ dev_dbg(sdw->cdns.dev, "first link up, programming SYNCPRD\n"); @@ -103,16 +110,7 @@ static int intel_link_power_up(struct sdw_intel *sdw) __func__, ret); goto out; } - } - ret = hdac_bus_eml_sdw_power_up_unlocked(sdw->link_res->hbus, link_id); - if (ret < 0) { - dev_err(sdw->cdns.dev, "%s: hdac_bus_eml_sdw_power_up failed: %d\n", - __func__, ret); - goto out; - } - - if (!*shim_mask) { /* SYNCPU will change once link is active */ ret = hdac_bus_eml_sdw_wait_syncpu_unlocked(sdw->link_res->hbus); if (ret < 0) { -- cgit v1.2.3-59-g8ed1b From 5b3f661b244973374626f7cc798cea91345786e8 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 26 Mar 2024 09:20:30 +0000 Subject: soundwire: intel_ace2x: set the clock source Insert clock setup after power-up and before setting up the SYNCPRD, per hardware recommendations. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Signed-off-by: Bard Liao Link: https://lore.kernel.org/r/20240326092030.1062802-8-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- drivers/soundwire/intel_ace2x.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/soundwire/intel_ace2x.c b/drivers/soundwire/intel_ace2x.c index d8ae05cf3d57..43a348db83bf 100644 --- a/drivers/soundwire/intel_ace2x.c +++ b/drivers/soundwire/intel_ace2x.c @@ -33,6 +33,20 @@ static void intel_shim_vs_init(struct sdw_intel *sdw) usleep_range(10, 15); } +static void intel_shim_vs_set_clock_source(struct sdw_intel *sdw, u32 source) +{ + void __iomem *shim_vs = sdw->link_res->shim_vs; + u32 val; + + val = intel_readl(shim_vs, SDW_SHIM2_INTEL_VS_LVSCTL); + + u32p_replace_bits(&val, source, SDW_SHIM2_INTEL_VS_LVSCTL_MLCS); + + intel_writel(shim_vs, SDW_SHIM2_INTEL_VS_LVSCTL, val); + + dev_dbg(sdw->cdns.dev, "clock source %d LVSCTL %#x\n", source, val); +} + static int intel_shim_check_wake(struct sdw_intel *sdw) { void __iomem *shim_vs; @@ -100,6 +114,8 @@ static int intel_link_power_up(struct sdw_intel *sdw) goto out; } + intel_shim_vs_set_clock_source(sdw, clock_source); + if (!*shim_mask) { /* we first need to program the SyncPRD/CPU registers */ dev_dbg(sdw->cdns.dev, "first link up, programming SYNCPRD\n"); -- cgit v1.2.3-59-g8ed1b From 38ab60132b0d477e19d841daed701b491c20b465 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Mon, 1 Apr 2024 14:08:03 -0700 Subject: perf script: Support 32bit code under 64bit OS with capstone Use the DSO to resolve whether an IP is 32bit or 64bit and use that to configure capstone to the correct mode. This allows to correctly disassemble 32bit code under a 64bit OS. % cat > loop.c volatile int var; int main(void) { int i; for (i = 0; i < 100000; i++) var++; } % gcc -m32 -o loop loop.c % perf record -e cycles:u ./loop % perf script -F +disasm loop 82665 1833176.618023: 1 cycles:u: f7eed500 _start+0x0 (/usr/lib/ld-linux.so.2) movl %esp, %eax loop 82665 1833176.618029: 1 cycles:u: f7eed500 _start+0x0 (/usr/lib/ld-linux.so.2) movl %esp, %eax loop 82665 1833176.618031: 7 cycles:u: f7eed500 _start+0x0 (/usr/lib/ld-linux.so.2) movl %esp, %eax loop 82665 1833176.618034: 91 cycles:u: f7eed500 _start+0x0 (/usr/lib/ld-linux.so.2) movl %esp, %eax loop 82665 1833176.618036: 1242 cycles:u: f7eed500 _start+0x0 (/usr/lib/ld-linux.so.2) movl %esp, %eax Reviewed-by: Adrian Hunter Acked-by: Thomas Richter Signed-off-by: Andi Kleen Link: https://lore.kernel.org/r/20240401210925.209671-2-ak@linux.intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-script.c | 9 +++++---- tools/perf/util/print_insn.c | 27 ++++++++++++++++++++++----- tools/perf/util/print_insn.h | 2 +- 3 files changed, 28 insertions(+), 10 deletions(-) diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 6a274e27b108..a711bedace47 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -1517,7 +1517,8 @@ void script_fetch_insn(struct perf_sample *sample, struct thread *thread, static int perf_sample__fprintf_insn(struct perf_sample *sample, struct perf_event_attr *attr, struct thread *thread, - struct machine *machine, FILE *fp) + struct machine *machine, FILE *fp, + struct addr_location *al) { int printed = 0; @@ -1531,7 +1532,7 @@ static int perf_sample__fprintf_insn(struct perf_sample *sample, } if (PRINT_FIELD(DISASM) && sample->insn_len) { printed += fprintf(fp, "\t\t"); - printed += sample__fprintf_insn_asm(sample, thread, machine, fp); + printed += sample__fprintf_insn_asm(sample, thread, machine, fp, al); } if (PRINT_FIELD(BRSTACKINSN) || PRINT_FIELD(BRSTACKINSNLEN)) printed += perf_sample__fprintf_brstackinsn(sample, thread, attr, machine, fp); @@ -1606,7 +1607,7 @@ static int perf_sample__fprintf_bts(struct perf_sample *sample, if (print_srcline_last) printed += map__fprintf_srcline(al->map, al->addr, "\n ", fp); - printed += perf_sample__fprintf_insn(sample, attr, thread, machine, fp); + printed += perf_sample__fprintf_insn(sample, attr, thread, machine, fp, al); printed += fprintf(fp, "\n"); if (PRINT_FIELD(SRCCODE)) { int ret = map__fprintf_srccode(al->map, al->addr, stdout, @@ -2259,7 +2260,7 @@ static void process_event(struct perf_script *script, if (evsel__is_bpf_output(evsel) && PRINT_FIELD(BPF_OUTPUT)) perf_sample__fprintf_bpf_output(sample, fp); - perf_sample__fprintf_insn(sample, attr, thread, machine, fp); + perf_sample__fprintf_insn(sample, attr, thread, machine, fp, al); if (PRINT_FIELD(PHYS_ADDR)) fprintf(fp, "%16" PRIx64, sample->phys_addr); diff --git a/tools/perf/util/print_insn.c b/tools/perf/util/print_insn.c index 459e0e93d7b1..32dc9dad9cf2 100644 --- a/tools/perf/util/print_insn.c +++ b/tools/perf/util/print_insn.c @@ -12,6 +12,8 @@ #include "machine.h" #include "thread.h" #include "print_insn.h" +#include "map.h" +#include "dso.h" size_t sample__fprintf_insn_raw(struct perf_sample *sample, FILE *fp) { @@ -28,12 +30,12 @@ size_t sample__fprintf_insn_raw(struct perf_sample *sample, FILE *fp) #ifdef HAVE_LIBCAPSTONE_SUPPORT #include -static int capstone_init(struct machine *machine, csh *cs_handle) +static int capstone_init(struct machine *machine, csh *cs_handle, bool is64) { cs_arch arch; cs_mode mode; - if (machine__is(machine, "x86_64")) { + if (machine__is(machine, "x86_64") && is64) { arch = CS_ARCH_X86; mode = CS_MODE_64; } else if (machine__normalized_is(machine, "x86")) { @@ -93,17 +95,31 @@ static size_t print_insn_x86(struct perf_sample *sample, struct thread *thread, return printed; } +static bool is64bitip(struct machine *machine, struct addr_location *al) +{ + const struct dso *dso = al->map ? map__dso(al->map) : NULL; + + if (dso) + return dso->is_64_bit; + + return machine__is(machine, "x86_64") || + machine__normalized_is(machine, "arm64") || + machine__normalized_is(machine, "s390"); +} + size_t sample__fprintf_insn_asm(struct perf_sample *sample, struct thread *thread, - struct machine *machine, FILE *fp) + struct machine *machine, FILE *fp, + struct addr_location *al) { csh cs_handle; cs_insn *insn; size_t count; size_t printed = 0; int ret; + bool is64bit = is64bitip(machine, al); /* TODO: Try to initiate capstone only once but need a proper place. */ - ret = capstone_init(machine, &cs_handle); + ret = capstone_init(machine, &cs_handle, is64bit); if (ret < 0) { /* fallback */ return sample__fprintf_insn_raw(sample, fp); @@ -128,7 +144,8 @@ size_t sample__fprintf_insn_asm(struct perf_sample *sample, struct thread *threa size_t sample__fprintf_insn_asm(struct perf_sample *sample __maybe_unused, struct thread *thread __maybe_unused, struct machine *machine __maybe_unused, - FILE *fp __maybe_unused) + FILE *fp __maybe_unused, + struct addr_location *al __maybe_unused) { return 0; } diff --git a/tools/perf/util/print_insn.h b/tools/perf/util/print_insn.h index 465bdcfcc2fd..6447dd41b543 100644 --- a/tools/perf/util/print_insn.h +++ b/tools/perf/util/print_insn.h @@ -10,7 +10,7 @@ struct thread; struct machine; size_t sample__fprintf_insn_asm(struct perf_sample *sample, struct thread *thread, - struct machine *machine, FILE *fp); + struct machine *machine, FILE *fp, struct addr_location *al); size_t sample__fprintf_insn_raw(struct perf_sample *sample, FILE *fp); #endif /* PERF_PRINT_INSN_H */ -- cgit v1.2.3-59-g8ed1b From d812044688dfe73e1b309689d58d06f50a15e618 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Mon, 1 Apr 2024 14:08:04 -0700 Subject: perf script: Add capstone support for '-F +brstackdisasm' Support capstone output for the '-F +brstackinsn' branch dump. The new output is enabled with the new field 'brstackdisasm'. This was possible before with --xed, but now also allow it for users that don't have xed using the builtin capstone support. Before: perf record -b emacs -Q --batch '()' perf script -F +brstackinsn ... emacs 55778 1814366.755945: 151564 cycles:P: 7f0ab2d17192 intel_check_word.constprop.0+0x162 (/usr/lib64/ld-linux-x86-64.s> intel_check_word.constprop.0+237: 00007f0ab2d1711d insn: 75 e6 # PRED 3 cycles [3] 00007f0ab2d17105 insn: 73 51 00007f0ab2d17107 insn: 48 89 c1 00007f0ab2d1710a insn: 48 39 ca 00007f0ab2d1710d insn: 73 96 00007f0ab2d1710f insn: 48 8d 04 11 00007f0ab2d17113 insn: 48 d1 e8 00007f0ab2d17116 insn: 49 8d 34 c1 00007f0ab2d1711a insn: 44 3a 06 00007f0ab2d1711d insn: 75 e6 # PRED 3 cycles [6] 3.00 IPC 00007f0ab2d17105 insn: 73 51 # PRED 1 cycles [7] 1.00 IPC 00007f0ab2d17158 insn: 48 8d 50 01 00007f0ab2d1715c insn: eb 92 # PRED 1 cycles [8] 2.00 IPC 00007f0ab2d170f0 insn: 48 39 ca 00007f0ab2d170f3 insn: 73 b0 # PRED 1 cycles [9] 2.00 IPC After (perf must be compiled with capstone): perf script -F +brstackdisasm ... emacs 55778 1814366.755945: 151564 cycles:P: 7f0ab2d17192 intel_check_word.constprop.0+0x162 (/usr/lib64/ld-linux-x86-64.s> intel_check_word.constprop.0+237: 00007f0ab2d1711d jne intel_check_word.constprop.0+0xd5 # PRED 3 cycles [3] 00007f0ab2d17105 jae intel_check_word.constprop.0+0x128 00007f0ab2d17107 movq %rax, %rcx 00007f0ab2d1710a cmpq %rcx, %rdx 00007f0ab2d1710d jae intel_check_word.constprop.0+0x75 00007f0ab2d1710f leaq (%rcx, %rdx), %rax 00007f0ab2d17113 shrq $1, %rax 00007f0ab2d17116 leaq (%r9, %rax, 8), %rsi 00007f0ab2d1711a cmpb (%rsi), %r8b 00007f0ab2d1711d jne intel_check_word.constprop.0+0xd5 # PRED 3 cycles [6] 3.00 IPC 00007f0ab2d17105 jae intel_check_word.constprop.0+0x128 # PRED 1 cycles [7] 1.00 IPC 00007f0ab2d17158 leaq 1(%rax), %rdx 00007f0ab2d1715c jmp intel_check_word.constprop.0+0xc0 # PRED 1 cycles [8] 2.00 IPC 00007f0ab2d170f0 cmpq %rcx, %rdx 00007f0ab2d170f3 jae intel_check_word.constprop.0+0x75 # PRED 1 cycles [9] 2.00 IPC Reviewed-by: Adrian Hunter Signed-off-by: Andi Kleen Link: https://lore.kernel.org/r/20240401210925.209671-3-ak@linux.intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-script.txt | 7 +++-- tools/perf/builtin-script.c | 32 +++++++++++++++----- tools/perf/util/dump-insn.h | 1 + tools/perf/util/print_insn.c | 52 ++++++++++++++++++++++++++++++++ tools/perf/util/print_insn.h | 3 ++ 5 files changed, 86 insertions(+), 9 deletions(-) diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt index 005e51df855e..ff086ef05a0c 100644 --- a/tools/perf/Documentation/perf-script.txt +++ b/tools/perf/Documentation/perf-script.txt @@ -132,9 +132,9 @@ OPTIONS Comma separated list of fields to print. Options are: comm, tid, pid, time, cpu, event, trace, ip, sym, dso, dsoff, addr, symoff, srcline, period, iregs, uregs, brstack, brstacksym, flags, bpf-output, - brstackinsn, brstackinsnlen, brstackoff, callindent, insn, disasm, + brstackinsn, brstackinsnlen, brstackdisasm, brstackoff, callindent, insn, disasm, insnlen, synth, phys_addr, metric, misc, srccode, ipc, data_page_size, - code_page_size, ins_lat, machine_pid, vcpu, cgroup, retire_lat. + code_page_size, ins_lat, machine_pid, vcpu, cgroup, retire_lat, Field list can be prepended with the type, trace, sw or hw, to indicate to which event type the field list applies. @@ -257,6 +257,9 @@ OPTIONS can’t know the next sequential instruction after an unconditional branch unless you calculate that based on its length. + brstackdisasm acts like brstackinsn, but will print disassembled instructions if + perf is built with the capstone library. + The brstackoff field will print an offset into a specific dso/binary. With the metric option perf script can compute metrics for diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index a711bedace47..dd10f158ed0c 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -136,6 +136,7 @@ enum perf_output_field { PERF_OUTPUT_RETIRE_LAT = 1ULL << 40, PERF_OUTPUT_DSOFF = 1ULL << 41, PERF_OUTPUT_DISASM = 1ULL << 42, + PERF_OUTPUT_BRSTACKDISASM = 1ULL << 43, }; struct perf_script { @@ -210,6 +211,7 @@ struct output_option { {.str = "vcpu", .field = PERF_OUTPUT_VCPU}, {.str = "cgroup", .field = PERF_OUTPUT_CGROUP}, {.str = "retire_lat", .field = PERF_OUTPUT_RETIRE_LAT}, + {.str = "brstackdisasm", .field = PERF_OUTPUT_BRSTACKDISASM}, }; enum { @@ -510,7 +512,8 @@ static int evsel__check_attr(struct evsel *evsel, struct perf_session *session) "selected. Hence, no address to lookup the source line number.\n"); return -EINVAL; } - if ((PRINT_FIELD(BRSTACKINSN) || PRINT_FIELD(BRSTACKINSNLEN)) && !allow_user_set && + if ((PRINT_FIELD(BRSTACKINSN) || PRINT_FIELD(BRSTACKINSNLEN) || PRINT_FIELD(BRSTACKDISASM)) + && !allow_user_set && !(evlist__combined_branch_type(session->evlist) & PERF_SAMPLE_BRANCH_ANY)) { pr_err("Display of branch stack assembler requested, but non all-branch filter set\n" "Hint: run 'perf record -b ...'\n"); @@ -1162,6 +1165,20 @@ out: return ret; } +static const char *any_dump_insn(struct perf_event_attr *attr __maybe_unused, + struct perf_insn *x, uint64_t ip, + u8 *inbuf, int inlen, int *lenp) +{ +#ifdef HAVE_LIBCAPSTONE_SUPPORT + if (PRINT_FIELD(BRSTACKDISASM)) { + const char *p = cs_dump_insn(x, ip, inbuf, inlen, lenp); + if (p) + return p; + } +#endif + return dump_insn(x, ip, inbuf, inlen, lenp); +} + static int ip__fprintf_jump(uint64_t ip, struct branch_entry *en, struct perf_insn *x, u8 *inbuf, int len, int insn, FILE *fp, int *total_cycles, @@ -1170,7 +1187,7 @@ static int ip__fprintf_jump(uint64_t ip, struct branch_entry *en, { int ilen = 0; int printed = fprintf(fp, "\t%016" PRIx64 "\t%-30s\t", ip, - dump_insn(x, ip, inbuf, len, &ilen)); + any_dump_insn(attr, x, ip, inbuf, len, &ilen)); if (PRINT_FIELD(BRSTACKINSNLEN)) printed += fprintf(fp, "ilen: %d\t", ilen); @@ -1262,6 +1279,7 @@ static int perf_sample__fprintf_brstackinsn(struct perf_sample *sample, nr = max_blocks + 1; x.thread = thread; + x.machine = machine; x.cpu = sample->cpu; printed += fprintf(fp, "%c", '\n'); @@ -1313,7 +1331,7 @@ static int perf_sample__fprintf_brstackinsn(struct perf_sample *sample, } else { ilen = 0; printed += fprintf(fp, "\t%016" PRIx64 "\t%s", ip, - dump_insn(&x, ip, buffer + off, len - off, &ilen)); + any_dump_insn(attr, &x, ip, buffer + off, len - off, &ilen)); if (PRINT_FIELD(BRSTACKINSNLEN)) printed += fprintf(fp, "\tilen: %d", ilen); printed += fprintf(fp, "\n"); @@ -1361,7 +1379,7 @@ static int perf_sample__fprintf_brstackinsn(struct perf_sample *sample, goto out; ilen = 0; printed += fprintf(fp, "\t%016" PRIx64 "\t%s", sample->ip, - dump_insn(&x, sample->ip, buffer, len, &ilen)); + any_dump_insn(attr, &x, sample->ip, buffer, len, &ilen)); if (PRINT_FIELD(BRSTACKINSNLEN)) printed += fprintf(fp, "\tilen: %d", ilen); printed += fprintf(fp, "\n"); @@ -1372,7 +1390,7 @@ static int perf_sample__fprintf_brstackinsn(struct perf_sample *sample, for (off = 0; off <= end - start; off += ilen) { ilen = 0; printed += fprintf(fp, "\t%016" PRIx64 "\t%s", start + off, - dump_insn(&x, start + off, buffer + off, len - off, &ilen)); + any_dump_insn(attr, &x, start + off, buffer + off, len - off, &ilen)); if (PRINT_FIELD(BRSTACKINSNLEN)) printed += fprintf(fp, "\tilen: %d", ilen); printed += fprintf(fp, "\n"); @@ -1534,7 +1552,7 @@ static int perf_sample__fprintf_insn(struct perf_sample *sample, printed += fprintf(fp, "\t\t"); printed += sample__fprintf_insn_asm(sample, thread, machine, fp, al); } - if (PRINT_FIELD(BRSTACKINSN) || PRINT_FIELD(BRSTACKINSNLEN)) + if (PRINT_FIELD(BRSTACKINSN) || PRINT_FIELD(BRSTACKINSNLEN) || PRINT_FIELD(BRSTACKDISASM)) printed += perf_sample__fprintf_brstackinsn(sample, thread, attr, machine, fp); return printed; @@ -3940,7 +3958,7 @@ int cmd_script(int argc, const char **argv) "Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso,dsoff," "addr,symoff,srcline,period,iregs,uregs,brstack," "brstacksym,flags,data_src,weight,bpf-output,brstackinsn," - "brstackinsnlen,brstackoff,callindent,insn,disasm,insnlen,synth," + "brstackinsnlen,brstackdisasm,brstackoff,callindent,insn,disasm,insnlen,synth," "phys_addr,metric,misc,srccode,ipc,tod,data_page_size," "code_page_size,ins_lat,machine_pid,vcpu,cgroup,retire_lat", parse_output_fields), diff --git a/tools/perf/util/dump-insn.h b/tools/perf/util/dump-insn.h index 650125061530..4a7797dd6d09 100644 --- a/tools/perf/util/dump-insn.h +++ b/tools/perf/util/dump-insn.h @@ -11,6 +11,7 @@ struct thread; struct perf_insn { /* Initialized by callers: */ struct thread *thread; + struct machine *machine; u8 cpumode; bool is64bit; int cpu; diff --git a/tools/perf/util/print_insn.c b/tools/perf/util/print_insn.c index 32dc9dad9cf2..8825330d435f 100644 --- a/tools/perf/util/print_insn.c +++ b/tools/perf/util/print_insn.c @@ -12,6 +12,7 @@ #include "machine.h" #include "thread.h" #include "print_insn.h" +#include "dump-insn.h" #include "map.h" #include "dso.h" @@ -71,6 +72,57 @@ static int capstone_init(struct machine *machine, csh *cs_handle, bool is64) return 0; } +static void dump_insn_x86(struct thread *thread, cs_insn *insn, struct perf_insn *x) +{ + struct addr_location al; + bool printed = false; + + if (insn->detail && insn->detail->x86.op_count == 1) { + cs_x86_op *op = &insn->detail->x86.operands[0]; + + addr_location__init(&al); + if (op->type == X86_OP_IMM && + thread__find_symbol(thread, x->cpumode, op->imm, &al) && + al.sym && + al.addr < al.sym->end) { + snprintf(x->out, sizeof(x->out), "%s %s+%#" PRIx64 " [%#" PRIx64 "]", insn[0].mnemonic, + al.sym->name, al.addr - al.sym->start, op->imm); + printed = true; + } + addr_location__exit(&al); + } + + if (!printed) + snprintf(x->out, sizeof(x->out), "%s %s", insn[0].mnemonic, insn[0].op_str); +} + +const char *cs_dump_insn(struct perf_insn *x, uint64_t ip, + u8 *inbuf, int inlen, int *lenp) +{ + int ret; + int count; + cs_insn *insn; + csh cs_handle; + + ret = capstone_init(x->machine, &cs_handle, x->is64bit); + if (ret < 0) + return NULL; + + count = cs_disasm(cs_handle, (uint8_t *)inbuf, inlen, ip, 1, &insn); + if (count > 0) { + if (machine__normalized_is(x->machine, "x86")) + dump_insn_x86(x->thread, &insn[0], x); + else + snprintf(x->out, sizeof(x->out), "%s %s", + insn[0].mnemonic, insn[0].op_str); + *lenp = insn->size; + cs_free(insn, count); + } else { + return NULL; + } + return x->out; +} + static size_t print_insn_x86(struct perf_sample *sample, struct thread *thread, cs_insn *insn, FILE *fp) { diff --git a/tools/perf/util/print_insn.h b/tools/perf/util/print_insn.h index 6447dd41b543..c2a6391a45ce 100644 --- a/tools/perf/util/print_insn.h +++ b/tools/perf/util/print_insn.h @@ -8,9 +8,12 @@ struct perf_sample; struct thread; struct machine; +struct perf_insn; size_t sample__fprintf_insn_asm(struct perf_sample *sample, struct thread *thread, struct machine *machine, FILE *fp, struct addr_location *al); size_t sample__fprintf_insn_raw(struct perf_sample *sample, FILE *fp); +const char *cs_dump_insn(struct perf_insn *x, uint64_t ip, + u8 *inbuf, int inlen, int *lenp); #endif /* PERF_PRINT_INSN_H */ -- cgit v1.2.3-59-g8ed1b From f320268fcebcbab02631d2070fa19ad4856a5a5e Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Mon, 26 Feb 2024 16:22:36 +0100 Subject: phy: qcom: qmp-combo: fix sm8650 voltage swing table The QMP USB3/DP PHY found in the SM8650 SoC requires a slightly different Voltage Swing table for HBR/RBR link speeds. Add a new hbr/rbr voltage switch table named "v6" used in a new sm8650 qmp_phy_cfg struct replacing the sm8550 fallback used for the sm8650 compatible. Fixes: 80c1afe8c5fe ("phy: qcom: qmp-combo: add QMP USB3/DP PHY tables for SM8650") Signed-off-by: Neil Armstrong Link: https://lore.kernel.org/r/20240226-topic-sm8650-upstream-combo-phy-swing-update-v1-1-08707ebca92a@linaro.org Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-qmp-combo.c | 54 ++++++++++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c index ea2d5369534d..9fd921d71457 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c @@ -1377,6 +1377,13 @@ static const u8 qmp_dp_v5_voltage_swing_hbr_rbr[4][4] = { { 0x3f, 0xff, 0xff, 0xff } }; +static const u8 qmp_dp_v6_voltage_swing_hbr_rbr[4][4] = { + { 0x27, 0x2f, 0x36, 0x3f }, + { 0x31, 0x3e, 0x3f, 0xff }, + { 0x36, 0x3f, 0xff, 0xff }, + { 0x3f, 0xff, 0xff, 0xff } +}; + static const u8 qmp_dp_v6_pre_emphasis_hbr_rbr[4][4] = { { 0x20, 0x2d, 0x34, 0x3a }, { 0x20, 0x2e, 0x35, 0xff }, @@ -1996,6 +2003,51 @@ static const struct qmp_phy_cfg sm8550_usb3dpphy_cfg = { .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), }; +static const struct qmp_phy_cfg sm8650_usb3dpphy_cfg = { + .offsets = &qmp_combo_offsets_v3, + + .serdes_tbl = sm8550_usb3_serdes_tbl, + .serdes_tbl_num = ARRAY_SIZE(sm8550_usb3_serdes_tbl), + .tx_tbl = sm8550_usb3_tx_tbl, + .tx_tbl_num = ARRAY_SIZE(sm8550_usb3_tx_tbl), + .rx_tbl = sm8550_usb3_rx_tbl, + .rx_tbl_num = ARRAY_SIZE(sm8550_usb3_rx_tbl), + .pcs_tbl = sm8550_usb3_pcs_tbl, + .pcs_tbl_num = ARRAY_SIZE(sm8550_usb3_pcs_tbl), + .pcs_usb_tbl = sm8550_usb3_pcs_usb_tbl, + .pcs_usb_tbl_num = ARRAY_SIZE(sm8550_usb3_pcs_usb_tbl), + + .dp_serdes_tbl = qmp_v6_dp_serdes_tbl, + .dp_serdes_tbl_num = ARRAY_SIZE(qmp_v6_dp_serdes_tbl), + .dp_tx_tbl = qmp_v6_dp_tx_tbl, + .dp_tx_tbl_num = ARRAY_SIZE(qmp_v6_dp_tx_tbl), + + .serdes_tbl_rbr = qmp_v6_dp_serdes_tbl_rbr, + .serdes_tbl_rbr_num = ARRAY_SIZE(qmp_v6_dp_serdes_tbl_rbr), + .serdes_tbl_hbr = qmp_v6_dp_serdes_tbl_hbr, + .serdes_tbl_hbr_num = ARRAY_SIZE(qmp_v6_dp_serdes_tbl_hbr), + .serdes_tbl_hbr2 = qmp_v6_dp_serdes_tbl_hbr2, + .serdes_tbl_hbr2_num = ARRAY_SIZE(qmp_v6_dp_serdes_tbl_hbr2), + .serdes_tbl_hbr3 = qmp_v6_dp_serdes_tbl_hbr3, + .serdes_tbl_hbr3_num = ARRAY_SIZE(qmp_v6_dp_serdes_tbl_hbr3), + + .swing_hbr_rbr = &qmp_dp_v6_voltage_swing_hbr_rbr, + .pre_emphasis_hbr_rbr = &qmp_dp_v6_pre_emphasis_hbr_rbr, + .swing_hbr3_hbr2 = &qmp_dp_v5_voltage_swing_hbr3_hbr2, + .pre_emphasis_hbr3_hbr2 = &qmp_dp_v5_pre_emphasis_hbr3_hbr2, + + .dp_aux_init = qmp_v4_dp_aux_init, + .configure_dp_tx = qmp_v4_configure_dp_tx, + .configure_dp_phy = qmp_v4_configure_dp_phy, + .calibrate_dp_phy = qmp_v4_calibrate_dp_phy, + + .regs = qmp_v6_usb3phy_regs_layout, + .reset_list = msm8996_usb3phy_reset_l, + .num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l), + .vreg_list = qmp_phy_vreg_l, + .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), +}; + static int qmp_combo_dp_serdes_init(struct qmp_combo *qmp) { const struct qmp_phy_cfg *cfg = qmp->cfg; @@ -3623,7 +3675,7 @@ static const struct of_device_id qmp_combo_of_match_table[] = { }, { .compatible = "qcom,sm8650-qmp-usb3-dp-phy", - .data = &sm8550_usb3dpphy_cfg, + .data = &sm8650_usb3dpphy_cfg, }, { .compatible = "qcom,x1e80100-qmp-usb3-dp-phy", -- cgit v1.2.3-59-g8ed1b From 9b6bfad9070a95d19973be17177e5d9220cbbf1f Mon Sep 17 00:00:00 2001 From: Rick Wertenbroek Date: Thu, 7 Mar 2024 10:53:18 +0100 Subject: phy: rockchip: Fix typo in function names Several functions had "rochchip" instead of "rockchip" in their name. Replace "rochchip" by "rockchip". Signed-off-By: Rick Wertenbroek Reviewed-by: Heiko Stuebner Link: https://lore.kernel.org/r/20240307095318.3651498-1-rick.wertenbroek@gmail.com Signed-off-by: Vinod Koul --- drivers/phy/rockchip/phy-rockchip-naneng-combphy.c | 4 ++-- drivers/phy/rockchip/phy-rockchip-snps-pcie3.c | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c b/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c index 76b9cf417591..35d5c18661a3 100644 --- a/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c +++ b/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c @@ -245,7 +245,7 @@ static int rockchip_combphy_exit(struct phy *phy) return 0; } -static const struct phy_ops rochchip_combphy_ops = { +static const struct phy_ops rockchip_combphy_ops = { .init = rockchip_combphy_init, .exit = rockchip_combphy_exit, .owner = THIS_MODULE, @@ -352,7 +352,7 @@ static int rockchip_combphy_probe(struct platform_device *pdev) return ret; } - priv->phy = devm_phy_create(dev, NULL, &rochchip_combphy_ops); + priv->phy = devm_phy_create(dev, NULL, &rockchip_combphy_ops); if (IS_ERR(priv->phy)) { dev_err(dev, "failed to create combphy\n"); return PTR_ERR(priv->phy); diff --git a/drivers/phy/rockchip/phy-rockchip-snps-pcie3.c b/drivers/phy/rockchip/phy-rockchip-snps-pcie3.c index 121e5961ce11..3cdc7625b308 100644 --- a/drivers/phy/rockchip/phy-rockchip-snps-pcie3.c +++ b/drivers/phy/rockchip/phy-rockchip-snps-pcie3.c @@ -187,7 +187,7 @@ static const struct rockchip_p3phy_ops rk3588_ops = { .phy_init = rockchip_p3phy_rk3588_init, }; -static int rochchip_p3phy_init(struct phy *phy) +static int rockchip_p3phy_init(struct phy *phy) { struct rockchip_p3phy_priv *priv = phy_get_drvdata(phy); int ret; @@ -210,7 +210,7 @@ static int rochchip_p3phy_init(struct phy *phy) return ret; } -static int rochchip_p3phy_exit(struct phy *phy) +static int rockchip_p3phy_exit(struct phy *phy) { struct rockchip_p3phy_priv *priv = phy_get_drvdata(phy); @@ -219,9 +219,9 @@ static int rochchip_p3phy_exit(struct phy *phy) return 0; } -static const struct phy_ops rochchip_p3phy_ops = { - .init = rochchip_p3phy_init, - .exit = rochchip_p3phy_exit, +static const struct phy_ops rockchip_p3phy_ops = { + .init = rockchip_p3phy_init, + .exit = rockchip_p3phy_exit, .set_mode = rockchip_p3phy_set_mode, .owner = THIS_MODULE, }; @@ -280,7 +280,7 @@ static int rockchip_p3phy_probe(struct platform_device *pdev) return priv->num_lanes; } - priv->phy = devm_phy_create(dev, NULL, &rochchip_p3phy_ops); + priv->phy = devm_phy_create(dev, NULL, &rockchip_p3phy_ops); if (IS_ERR(priv->phy)) { dev_err(dev, "failed to create combphy\n"); return PTR_ERR(priv->phy); -- cgit v1.2.3-59-g8ed1b From 7dcb8668aedc5603cba1f2625c6051beff03797d Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Fri, 8 Mar 2024 09:51:13 +0100 Subject: phy: xilinx: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Acked-by: Michal Simek Link: https://lore.kernel.org/r/57a3338a1cec683ac84d48e00dbf197e15ee5481.1709886922.git.u.kleine-koenig@pengutronix.de Signed-off-by: Vinod Koul --- drivers/phy/xilinx/phy-zynqmp.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/phy/xilinx/phy-zynqmp.c b/drivers/phy/xilinx/phy-zynqmp.c index f72c5257d712..dc8319bda43d 100644 --- a/drivers/phy/xilinx/phy-zynqmp.c +++ b/drivers/phy/xilinx/phy-zynqmp.c @@ -995,15 +995,13 @@ static int xpsgtr_probe(struct platform_device *pdev) return 0; } -static int xpsgtr_remove(struct platform_device *pdev) +static void xpsgtr_remove(struct platform_device *pdev) { struct xpsgtr_dev *gtr_dev = platform_get_drvdata(pdev); pm_runtime_disable(gtr_dev->dev); pm_runtime_put_noidle(gtr_dev->dev); pm_runtime_set_suspended(gtr_dev->dev); - - return 0; } static const struct of_device_id xpsgtr_of_match[] = { @@ -1015,7 +1013,7 @@ MODULE_DEVICE_TABLE(of, xpsgtr_of_match); static struct platform_driver xpsgtr_driver = { .probe = xpsgtr_probe, - .remove = xpsgtr_remove, + .remove_new = xpsgtr_remove, .driver = { .name = "xilinx-psgtr", .of_match_table = xpsgtr_of_match, -- cgit v1.2.3-59-g8ed1b From 72bea132f3680ee51e7ed2cee62892b6f5121909 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Fri, 22 Mar 2024 10:42:38 +0100 Subject: dt-bindings: phy: qcom,sc8280xp-qmp-pcie-phy: document PHY AUX clock on SM8[456]50 SoCs The PCIe Gen4x2 PHY found in the SM8[456]50 SoCs have a second clock named "PHY_AUX_CLK" which is an input of the Global Clock Controller (GCC) which is muxed & gated then returned to the PHY as an input. Document the clock IDs to select the PIPE clock or the AUX clock, also enforce a second clock-output-names and a #clock-cells value of 1 for the PCIe Gen4x2 PHY found in the SM8[456]50 SoCs. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Neil Armstrong Link: https://lore.kernel.org/r/20240322-topic-sm8x50-upstream-pcie-1-phy-aux-clk-v2-1-3ec0a966d52f@linaro.org Signed-off-by: Vinod Koul --- .../bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml | 27 +++++++++++++++++++--- include/dt-bindings/phy/phy-qcom-qmp.h | 4 ++++ 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml index ba966a78a128..14ac341b1577 100644 --- a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml @@ -88,11 +88,11 @@ properties: - description: offset of PCIe 4-lane configuration register - description: offset of configuration bit for this PHY - "#clock-cells": - const: 0 + "#clock-cells": true clock-output-names: - maxItems: 1 + minItems: 1 + maxItems: 2 "#phy-cells": const: 0 @@ -213,6 +213,27 @@ allOf: reset-names: maxItems: 1 + - if: + properties: + compatible: + contains: + enum: + - qcom,sm8450-qmp-gen4x2-pcie-phy + - qcom,sm8550-qmp-gen4x2-pcie-phy + - qcom,sm8650-qmp-gen4x2-pcie-phy + then: + properties: + clock-output-names: + minItems: 2 + "#clock-cells": + const: 1 + else: + properties: + clock-output-names: + maxItems: 1 + "#clock-cells": + const: 0 + examples: - | #include diff --git a/include/dt-bindings/phy/phy-qcom-qmp.h b/include/dt-bindings/phy/phy-qcom-qmp.h index 4edec4c5b224..6b43ea9e0051 100644 --- a/include/dt-bindings/phy/phy-qcom-qmp.h +++ b/include/dt-bindings/phy/phy-qcom-qmp.h @@ -17,4 +17,8 @@ #define QMP_USB43DP_USB3_PHY 0 #define QMP_USB43DP_DP_PHY 1 +/* QMP PCIE PHYs */ +#define QMP_PCIE_PIPE_CLK 0 +#define QMP_PCIE_PHY_AUX_CLK 1 + #endif /* _DT_BINDINGS_PHY_QMP */ -- cgit v1.2.3-59-g8ed1b From 677b45114b4430a43d2602296617efc4d3f2ab7a Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Fri, 22 Mar 2024 10:42:39 +0100 Subject: phy: qcom: qmp-pcie: refactor clock register code The PCIe Gen4x2 PHY found in the SM8[456]50 SoCs have a second clock, in order to expose it, split the current clock registering in two parts: - CCF clock registering - DT clock registering Keep the of_clk_add_hw_provider/devm_add_action_or_reset to keep compatibility with the legacy subnode bindings. Signed-off-by: Neil Armstrong Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20240322-topic-sm8x50-upstream-pcie-1-phy-aux-clk-v2-2-3ec0a966d52f@linaro.org Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-qmp-pcie.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c index 8836bb1ff0cc..e8da2e9146dc 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c @@ -3664,7 +3664,7 @@ static int phy_pipe_clk_register(struct qmp_pcie *qmp, struct device_node *np) struct clk_init_data init = { }; int ret; - ret = of_property_read_string(np, "clock-output-names", &init.name); + ret = of_property_read_string_index(np, "clock-output-names", 0, &init.name); if (ret) { dev_err(qmp->dev, "%pOFn: No clock-output-names\n", np); return ret; @@ -3683,11 +3683,18 @@ static int phy_pipe_clk_register(struct qmp_pcie *qmp, struct device_node *np) fixed->hw.init = &init; - ret = devm_clk_hw_register(qmp->dev, &fixed->hw); + return devm_clk_hw_register(qmp->dev, &fixed->hw); +} + +static int qmp_pcie_register_clocks(struct qmp_pcie *qmp, struct device_node *np) +{ + int ret; + + ret = phy_pipe_clk_register(qmp, np); if (ret) return ret; - ret = of_clk_add_hw_provider(np, of_clk_hw_simple_get, &fixed->hw); + ret = of_clk_add_hw_provider(np, of_clk_hw_simple_get, &qmp->pipe_clk_fixed.hw); if (ret) return ret; @@ -3899,7 +3906,7 @@ static int qmp_pcie_probe(struct platform_device *pdev) if (ret) goto err_node_put; - ret = phy_pipe_clk_register(qmp, np); + ret = qmp_pcie_register_clocks(qmp, np); if (ret) goto err_node_put; -- cgit v1.2.3-59-g8ed1b From 583ca9ccfa806605ae1391aafa3f78a8a2cc0b48 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Fri, 22 Mar 2024 10:42:40 +0100 Subject: phy: qcom: qmp-pcie: register second optional PHY AUX clock The PCIe Gen4x2 PHY found in the SM8[456]50 SoCs have a second clock, add the code to register it for PHYs configs that sets a aux_clock_rate. In order to get the right clock, add qmp_pcie_clk_hw_get() which uses the newly introduced QMP_PCIE_PIPE_CLK & QMP_PCIE_PHY_AUX_CLK clock IDs and also supports the legacy bindings by returning the PIPE clock when #clock-cells=0. Signed-off-by: Neil Armstrong Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20240322-topic-sm8x50-upstream-pcie-1-phy-aux-clk-v2-3-3ec0a966d52f@linaro.org Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-qmp-pcie.c | 78 ++++++++++++++++++++++++++++++-- 1 file changed, 75 insertions(+), 3 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c index e8da2e9146dc..6c9a95e62429 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c @@ -22,6 +22,8 @@ #include #include +#include + #include "phy-qcom-qmp-common.h" #include "phy-qcom-qmp.h" @@ -2389,6 +2391,9 @@ struct qmp_phy_cfg { /* QMP PHY pipe clock interface rate */ unsigned long pipe_clock_rate; + + /* QMP PHY AUX clock interface rate */ + unsigned long aux_clock_rate; }; struct qmp_pcie { @@ -2420,6 +2425,7 @@ struct qmp_pcie { int mode; struct clk_fixed_rate pipe_clk_fixed; + struct clk_fixed_rate aux_clk_fixed; }; static inline void qphy_setbits(void __iomem *base, u32 offset, u32 val) @@ -3686,6 +3692,62 @@ static int phy_pipe_clk_register(struct qmp_pcie *qmp, struct device_node *np) return devm_clk_hw_register(qmp->dev, &fixed->hw); } +/* + * Register a fixed rate PHY aux clock. + * + * The _phy_aux_clksrc generated by PHY goes to the GCC that gate + * controls it. The _phy_aux_clk coming out of the GCC is requested + * by the PHY driver for its operations. + * We register the _phy_aux_clksrc here. The gcc driver takes care + * of assigning this _phy_aux_clksrc as parent to _phy_aux_clk. + * Below picture shows this relationship. + * + * +---------------+ + * | PHY block |<<---------------------------------------------+ + * | | | + * | +-------+ | +-----+ | + * I/P---^-->| PLL |---^--->phy_aux_clksrc--->| GCC |--->phy_aux_clk---+ + * clk | +-------+ | +-----+ + * +---------------+ + */ +static int phy_aux_clk_register(struct qmp_pcie *qmp, struct device_node *np) +{ + struct clk_fixed_rate *fixed = &qmp->aux_clk_fixed; + struct clk_init_data init = { }; + int ret; + + ret = of_property_read_string_index(np, "clock-output-names", 1, &init.name); + if (ret) { + dev_err(qmp->dev, "%pOFn: No clock-output-names index 1\n", np); + return ret; + } + + init.ops = &clk_fixed_rate_ops; + + fixed->fixed_rate = qmp->cfg->aux_clock_rate; + fixed->hw.init = &init; + + return devm_clk_hw_register(qmp->dev, &fixed->hw); +} + +static struct clk_hw *qmp_pcie_clk_hw_get(struct of_phandle_args *clkspec, void *data) +{ + struct qmp_pcie *qmp = data; + + /* Support legacy bindings */ + if (!clkspec->args_count) + return &qmp->pipe_clk_fixed.hw; + + switch (clkspec->args[0]) { + case QMP_PCIE_PIPE_CLK: + return &qmp->pipe_clk_fixed.hw; + case QMP_PCIE_PHY_AUX_CLK: + return &qmp->aux_clk_fixed.hw; + } + + return ERR_PTR(-EINVAL); +} + static int qmp_pcie_register_clocks(struct qmp_pcie *qmp, struct device_node *np) { int ret; @@ -3694,9 +3756,19 @@ static int qmp_pcie_register_clocks(struct qmp_pcie *qmp, struct device_node *np if (ret) return ret; - ret = of_clk_add_hw_provider(np, of_clk_hw_simple_get, &qmp->pipe_clk_fixed.hw); - if (ret) - return ret; + if (qmp->cfg->aux_clock_rate) { + ret = phy_aux_clk_register(qmp, np); + if (ret) + return ret; + + ret = of_clk_add_hw_provider(np, qmp_pcie_clk_hw_get, qmp); + if (ret) + return ret; + } else { + ret = of_clk_add_hw_provider(np, of_clk_hw_simple_get, &qmp->pipe_clk_fixed.hw); + if (ret) + return ret; + } /* * Roll a devm action because the clock provider is the child node, but -- cgit v1.2.3-59-g8ed1b From 5cee04a8369049b92d52995e320abff18dfeda44 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Fri, 22 Mar 2024 10:42:41 +0100 Subject: phy: qcom: qmp-pcie: register PHY AUX clock for SM8[456]50 4x2 PCIe PHY The PCIe Gen4x2 PHY found in the SM8[456]50 SoCs have a second clock, enable this second clock by setting the proper 20MHz hardware rate in the Gen4x2 SM8[456]50 aux_clock_rate config fields. Reviewed-by: Dmitry Baryshkov Signed-off-by: Neil Armstrong Link: https://lore.kernel.org/r/20240322-topic-sm8x50-upstream-pcie-1-phy-aux-clk-v2-4-3ec0a966d52f@linaro.org Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-qmp-pcie.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c index 6c9a95e62429..e3103bcc24c4 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c @@ -3141,6 +3141,9 @@ static const struct qmp_phy_cfg sm8450_qmp_gen4x2_pciephy_cfg = { .pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL, .phy_status = PHYSTATUS_4_20, + + /* 20MHz PHY AUX Clock */ + .aux_clock_rate = 20000000, }; static const struct qmp_phy_cfg sm8550_qmp_gen3x2_pciephy_cfg = { @@ -3198,6 +3201,9 @@ static const struct qmp_phy_cfg sm8550_qmp_gen4x2_pciephy_cfg = { .pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL, .phy_status = PHYSTATUS_4_20, .has_nocsr_reset = true, + + /* 20MHz PHY AUX Clock */ + .aux_clock_rate = 20000000, }; static const struct qmp_phy_cfg sm8650_qmp_gen4x2_pciephy_cfg = { @@ -3228,6 +3234,9 @@ static const struct qmp_phy_cfg sm8650_qmp_gen4x2_pciephy_cfg = { .pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL, .phy_status = PHYSTATUS_4_20, .has_nocsr_reset = true, + + /* 20MHz PHY AUX Clock */ + .aux_clock_rate = 20000000, }; static const struct qmp_phy_cfg sa8775p_qmp_gen4x2_pciephy_cfg = { -- cgit v1.2.3-59-g8ed1b From db704bf6dccc8fef77ee4a8326bf2013b828205b Mon Sep 17 00:00:00 2001 From: "Ricardo B. Marliere" Date: Tue, 5 Mar 2024 15:18:51 -0300 Subject: phy: core: make phy_class constant Since commit 43a7206b0963 ("driver core: class: make class_register() take a const *"), the driver core allows for struct class to be in read-only memory, so move the phy_class structure to be declared at build time placing it into read-only memory, instead of having to be dynamically allocated at boot time. Cc: Greg Kroah-Hartman Suggested-by: Greg Kroah-Hartman Signed-off-by: "Ricardo B. Marliere" Link: https://lore.kernel.org/r/20240305-class_cleanup-phy-v1-1-106013a644dc@marliere.net Signed-off-by: Vinod Koul --- drivers/phy/phy-core.c | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c index c5c8d70bc853..bf6a07590321 100644 --- a/drivers/phy/phy-core.c +++ b/drivers/phy/phy-core.c @@ -20,7 +20,12 @@ #include #include -static struct class *phy_class; +static void phy_release(struct device *dev); +static const struct class phy_class = { + .name = "phy", + .dev_release = phy_release, +}; + static struct dentry *phy_debugfs_root; static DEFINE_MUTEX(phy_provider_mutex); static LIST_HEAD(phy_provider_list); @@ -753,7 +758,7 @@ struct phy *of_phy_simple_xlate(struct device *dev, struct phy *phy; struct class_dev_iter iter; - class_dev_iter_init(&iter, phy_class, NULL, NULL); + class_dev_iter_init(&iter, &phy_class, NULL, NULL); while ((dev = class_dev_iter_next(&iter))) { phy = to_phy(dev); if (args->np != phy->dev.of_node) @@ -1016,7 +1021,7 @@ struct phy *phy_create(struct device *dev, struct device_node *node, device_initialize(&phy->dev); mutex_init(&phy->mutex); - phy->dev.class = phy_class; + phy->dev.class = &phy_class; phy->dev.parent = dev; phy->dev.of_node = node ?: dev->of_node; phy->id = id; @@ -1285,14 +1290,13 @@ static void phy_release(struct device *dev) static int __init phy_core_init(void) { - phy_class = class_create("phy"); - if (IS_ERR(phy_class)) { - pr_err("failed to create phy class --> %ld\n", - PTR_ERR(phy_class)); - return PTR_ERR(phy_class); - } + int err; - phy_class->dev_release = phy_release; + err = class_register(&phy_class); + if (err) { + pr_err("failed to register phy class"); + return err; + } phy_debugfs_root = debugfs_create_dir("phy", NULL); @@ -1303,6 +1307,6 @@ device_initcall(phy_core_init); static void __exit phy_core_exit(void) { debugfs_remove_recursive(phy_debugfs_root); - class_destroy(phy_class); + class_unregister(&phy_class); } module_exit(phy_core_exit); -- cgit v1.2.3-59-g8ed1b From 7c1f42967b75bdcd0640c52d37d58d8dd122989b Mon Sep 17 00:00:00 2001 From: Danila Tikhonov Date: Mon, 1 Apr 2024 21:22:39 +0300 Subject: dt-bindings: phy: qmp-ufs: Fix PHY clocks for SC7180 QMP UFS PHY used in SC7180 requires 3 clocks: * ref - 19.2MHz reference clock from RPMh * ref_aux - Auxiliary reference clock from GCC * qref - QREF clock from GCC This change obviously breaks the ABI, but it is inevitable since the clock topology needs to be accurately described in the binding. Signed-off-by: Danila Tikhonov Acked-by: Rob Herring Reviewed-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/20240401182240.55282-2-danila@jiaxyga.com Signed-off-by: Vinod Koul --- Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml index 1e8c3abb09a4..9dac6852f8cb 100644 --- a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml @@ -87,6 +87,7 @@ allOf: enum: - qcom,msm8998-qmp-ufs-phy - qcom,sa8775p-qmp-ufs-phy + - qcom,sc7180-qmp-ufs-phy - qcom,sc7280-qmp-ufs-phy - qcom,sc8180x-qmp-ufs-phy - qcom,sc8280xp-qmp-ufs-phy -- cgit v1.2.3-59-g8ed1b From 724e4fc053fe217d0ed477517ae68db11feab1f5 Mon Sep 17 00:00:00 2001 From: Peter Griffin Date: Thu, 4 Apr 2024 13:25:46 +0100 Subject: dt-bindings: phy: samsung,ufs-phy: Add dedicated gs101-ufs-phy compatible Update dt schema to include the gs101 ufs phy compatible. Signed-off-by: Peter Griffin Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240404122559.898930-5-peter.griffin@linaro.org Signed-off-by: Vinod Koul --- Documentation/devicetree/bindings/phy/samsung,ufs-phy.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/phy/samsung,ufs-phy.yaml b/Documentation/devicetree/bindings/phy/samsung,ufs-phy.yaml index 782f975b43ae..f402e31bf58d 100644 --- a/Documentation/devicetree/bindings/phy/samsung,ufs-phy.yaml +++ b/Documentation/devicetree/bindings/phy/samsung,ufs-phy.yaml @@ -15,6 +15,7 @@ properties: compatible: enum: + - google,gs101-ufs-phy - samsung,exynos7-ufs-phy - samsung,exynosautov9-ufs-phy - tesla,fsd-ufs-phy -- cgit v1.2.3-59-g8ed1b From f2c6d0fa197a1558f4ef50162bb87e6644af232d Mon Sep 17 00:00:00 2001 From: Peter Griffin Date: Thu, 4 Apr 2024 13:25:51 +0100 Subject: phy: samsung-ufs: use exynos_get_pmu_regmap_by_phandle() to obtain PMU regmap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows us to obtain a PMU regmap that is created by the exynos-pmu driver. Platforms such as gs101 require exynos-pmu created regmap to issue SMC calls for PMU register accesses. Existing platforms still get a MMIO regmap as before. Signed-off-by: Peter Griffin Reviewed-by: André Draszik Link: https://lore.kernel.org/r/20240404122559.898930-10-peter.griffin@linaro.org Signed-off-by: Vinod Koul --- drivers/phy/samsung/phy-samsung-ufs.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/phy/samsung/phy-samsung-ufs.c b/drivers/phy/samsung/phy-samsung-ufs.c index 183c88e3d1ec..c567efafc30f 100644 --- a/drivers/phy/samsung/phy-samsung-ufs.c +++ b/drivers/phy/samsung/phy-samsung-ufs.c @@ -18,6 +18,7 @@ #include #include #include +#include #include "phy-samsung-ufs.h" @@ -255,8 +256,8 @@ static int samsung_ufs_phy_probe(struct platform_device *pdev) goto out; } - phy->reg_pmu = syscon_regmap_lookup_by_phandle( - dev->of_node, "samsung,pmu-syscon"); + phy->reg_pmu = exynos_get_pmu_regmap_by_phandle(dev->of_node, + "samsung,pmu-syscon"); if (IS_ERR(phy->reg_pmu)) { err = PTR_ERR(phy->reg_pmu); dev_err(dev, "failed syscon remap for pmu\n"); -- cgit v1.2.3-59-g8ed1b From a4de58a9096b471f9dc1c2bc6bfaa8aa48110c31 Mon Sep 17 00:00:00 2001 From: Peter Griffin Date: Thu, 4 Apr 2024 13:25:52 +0100 Subject: phy: samsung-ufs: ufs: Add SoC callbacks for calibration and clk data recovery Some SoCs like gs101 don't fit in well with the existing pll lock and clock data recovery (CDR) callback used by existing exynos platforms. Allow SoCs to specifify and implement their own calibration and CDR functions that can be called by the generic samsung phy code. Signed-off-by: Peter Griffin Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240404122559.898930-11-peter.griffin@linaro.org Signed-off-by: Vinod Koul --- drivers/phy/samsung/phy-exynos7-ufs.c | 1 + drivers/phy/samsung/phy-exynosautov9-ufs.c | 1 + drivers/phy/samsung/phy-fsd-ufs.c | 1 + drivers/phy/samsung/phy-samsung-ufs.c | 13 ++++++++++--- drivers/phy/samsung/phy-samsung-ufs.h | 5 +++++ 5 files changed, 18 insertions(+), 3 deletions(-) diff --git a/drivers/phy/samsung/phy-exynos7-ufs.c b/drivers/phy/samsung/phy-exynos7-ufs.c index a982e7c128c5..15eec1d9e0e0 100644 --- a/drivers/phy/samsung/phy-exynos7-ufs.c +++ b/drivers/phy/samsung/phy-exynos7-ufs.c @@ -82,4 +82,5 @@ const struct samsung_ufs_phy_drvdata exynos7_ufs_phy = { .clk_list = exynos7_ufs_phy_clks, .num_clks = ARRAY_SIZE(exynos7_ufs_phy_clks), .cdr_lock_status_offset = EXYNOS7_EMBEDDED_COMBO_PHY_CDR_LOCK_STATUS, + .wait_for_cdr = samsung_ufs_phy_wait_for_lock_acq, }; diff --git a/drivers/phy/samsung/phy-exynosautov9-ufs.c b/drivers/phy/samsung/phy-exynosautov9-ufs.c index 49e2bcbef0b4..9c3e030f07ba 100644 --- a/drivers/phy/samsung/phy-exynosautov9-ufs.c +++ b/drivers/phy/samsung/phy-exynosautov9-ufs.c @@ -71,4 +71,5 @@ const struct samsung_ufs_phy_drvdata exynosautov9_ufs_phy = { .clk_list = exynosautov9_ufs_phy_clks, .num_clks = ARRAY_SIZE(exynosautov9_ufs_phy_clks), .cdr_lock_status_offset = EXYNOSAUTOV9_EMBEDDED_COMBO_PHY_CDR_LOCK_STATUS, + .wait_for_cdr = samsung_ufs_phy_wait_for_lock_acq, }; diff --git a/drivers/phy/samsung/phy-fsd-ufs.c b/drivers/phy/samsung/phy-fsd-ufs.c index d36cabd53434..f2361746db0e 100644 --- a/drivers/phy/samsung/phy-fsd-ufs.c +++ b/drivers/phy/samsung/phy-fsd-ufs.c @@ -60,4 +60,5 @@ const struct samsung_ufs_phy_drvdata fsd_ufs_phy = { .clk_list = fsd_ufs_phy_clks, .num_clks = ARRAY_SIZE(fsd_ufs_phy_clks), .cdr_lock_status_offset = FSD_EMBEDDED_COMBO_PHY_CDR_LOCK_STATUS, + .wait_for_cdr = samsung_ufs_phy_wait_for_lock_acq, }; diff --git a/drivers/phy/samsung/phy-samsung-ufs.c b/drivers/phy/samsung/phy-samsung-ufs.c index c567efafc30f..f57a2f2a415d 100644 --- a/drivers/phy/samsung/phy-samsung-ufs.c +++ b/drivers/phy/samsung/phy-samsung-ufs.c @@ -46,7 +46,7 @@ static void samsung_ufs_phy_config(struct samsung_ufs_phy *phy, } } -static int samsung_ufs_phy_wait_for_lock_acq(struct phy *phy) +int samsung_ufs_phy_wait_for_lock_acq(struct phy *phy, u8 lane) { struct samsung_ufs_phy *ufs_phy = get_samsung_ufs_phy(phy); const unsigned int timeout_us = 100000; @@ -98,8 +98,15 @@ static int samsung_ufs_phy_calibrate(struct phy *phy) } } - if (ufs_phy->ufs_phy_state == CFG_POST_PWR_HS) - err = samsung_ufs_phy_wait_for_lock_acq(phy); + for_each_phy_lane(ufs_phy, i) { + if (ufs_phy->ufs_phy_state == CFG_PRE_INIT && + ufs_phy->drvdata->wait_for_cal) + err = ufs_phy->drvdata->wait_for_cal(phy, i); + + if (ufs_phy->ufs_phy_state == CFG_POST_PWR_HS && + ufs_phy->drvdata->wait_for_cdr) + err = ufs_phy->drvdata->wait_for_cdr(phy, i); + } /** * In Samsung ufshci, PHY need to be calibrated at different diff --git a/drivers/phy/samsung/phy-samsung-ufs.h b/drivers/phy/samsung/phy-samsung-ufs.h index e122960cfee8..7de6b574b94d 100644 --- a/drivers/phy/samsung/phy-samsung-ufs.h +++ b/drivers/phy/samsung/phy-samsung-ufs.h @@ -112,6 +112,9 @@ struct samsung_ufs_phy_drvdata { const char * const *clk_list; int num_clks; u32 cdr_lock_status_offset; + /* SoC's specific operations */ + int (*wait_for_cal)(struct phy *phy, u8 lane); + int (*wait_for_cdr)(struct phy *phy, u8 lane); }; struct samsung_ufs_phy { @@ -139,6 +142,8 @@ static inline void samsung_ufs_phy_ctrl_isol( phy->isol.mask, isol ? 0 : phy->isol.en); } +int samsung_ufs_phy_wait_for_lock_acq(struct phy *phy, u8 lane); + extern const struct samsung_ufs_phy_drvdata exynos7_ufs_phy; extern const struct samsung_ufs_phy_drvdata exynosautov9_ufs_phy; extern const struct samsung_ufs_phy_drvdata fsd_ufs_phy; -- cgit v1.2.3-59-g8ed1b From c1cf725db1065153459f0deb69bd4d497a5fd183 Mon Sep 17 00:00:00 2001 From: Peter Griffin Date: Thu, 4 Apr 2024 13:25:53 +0100 Subject: phy: samsung-ufs: ufs: Add support for gs101 UFS phy tuning Add the m-phy tuning values for gs101 UFS phy and SoC callbacks gs101_phy_wait_for_calibration() and gs101_phy_wait_for_cdr_lock(). Signed-off-by: Peter Griffin Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240404122559.898930-12-peter.griffin@linaro.org Signed-off-by: Vinod Koul --- drivers/phy/samsung/Makefile | 1 + drivers/phy/samsung/phy-gs101-ufs.c | 182 ++++++++++++++++++++++++++++++++++ drivers/phy/samsung/phy-samsung-ufs.c | 3 + drivers/phy/samsung/phy-samsung-ufs.h | 1 + 4 files changed, 187 insertions(+) create mode 100644 drivers/phy/samsung/phy-gs101-ufs.c diff --git a/drivers/phy/samsung/Makefile b/drivers/phy/samsung/Makefile index afb34a153e34..fea1f96d0e43 100644 --- a/drivers/phy/samsung/Makefile +++ b/drivers/phy/samsung/Makefile @@ -3,6 +3,7 @@ obj-$(CONFIG_PHY_EXYNOS_DP_VIDEO) += phy-exynos-dp-video.o obj-$(CONFIG_PHY_EXYNOS_MIPI_VIDEO) += phy-exynos-mipi-video.o obj-$(CONFIG_PHY_EXYNOS_PCIE) += phy-exynos-pcie.o obj-$(CONFIG_PHY_SAMSUNG_UFS) += phy-exynos-ufs.o +phy-exynos-ufs-y += phy-gs101-ufs.o phy-exynos-ufs-y += phy-samsung-ufs.o phy-exynos-ufs-y += phy-exynos7-ufs.o phy-exynos-ufs-y += phy-exynosautov9-ufs.o diff --git a/drivers/phy/samsung/phy-gs101-ufs.c b/drivers/phy/samsung/phy-gs101-ufs.c new file mode 100644 index 000000000000..17b798da5b57 --- /dev/null +++ b/drivers/phy/samsung/phy-gs101-ufs.c @@ -0,0 +1,182 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * UFS PHY driver data for Google Tensor gs101 SoC + * + * Copyright (C) 2024 Linaro Ltd + * Author: Peter Griffin + */ + +#include "phy-samsung-ufs.h" + +#define TENSOR_GS101_PHY_CTRL 0x3ec8 +#define TENSOR_GS101_PHY_CTRL_MASK 0x1 +#define TENSOR_GS101_PHY_CTRL_EN BIT(0) +#define PHY_GS101_LANE_OFFSET 0x200 +#define TRSV_REG338 0x338 +#define LN0_MON_RX_CAL_DONE BIT(3) +#define TRSV_REG339 0x339 +#define LN0_MON_RX_CDR_FLD_CK_MODE_DONE BIT(3) +#define TRSV_REG222 0x222 +#define LN0_OVRD_RX_CDR_EN BIT(4) +#define LN0_RX_CDR_EN BIT(3) + +#define PHY_PMA_TRSV_ADDR(reg, lane) (PHY_APB_ADDR((reg) + \ + ((lane) * PHY_GS101_LANE_OFFSET))) + +#define PHY_TRSV_REG_CFG_GS101(o, v, d) \ + PHY_TRSV_REG_CFG_OFFSET(o, v, d, PHY_GS101_LANE_OFFSET) + +/* Calibration for phy initialization */ +static const struct samsung_ufs_phy_cfg tensor_gs101_pre_init_cfg[] = { + PHY_COMN_REG_CFG(0x43, 0x10, PWR_MODE_ANY), + PHY_COMN_REG_CFG(0x3C, 0x14, PWR_MODE_ANY), + PHY_COMN_REG_CFG(0x46, 0x48, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x200, 0x00, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x201, 0x06, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x202, 0x06, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x203, 0x0a, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x204, 0x00, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x205, 0x11, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x207, 0x0c, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x2E1, 0xc0, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x22D, 0xb8, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x234, 0x60, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x238, 0x13, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x239, 0x48, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x23A, 0x01, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x23B, 0x25, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x23C, 0x2a, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x23D, 0x01, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x23E, 0x13, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x23F, 0x13, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x240, 0x4a, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x243, 0x40, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x244, 0x02, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x25D, 0x00, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x25E, 0x3f, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x25F, 0xff, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x273, 0x33, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x274, 0x50, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x284, 0x02, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x285, 0x02, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x2A2, 0x04, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x25D, 0x01, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x2FA, 0x01, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x286, 0x03, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x287, 0x03, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x288, 0x03, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x289, 0x03, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x2B3, 0x04, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x2B6, 0x0b, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x2B7, 0x0b, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x2B8, 0x0b, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x2B9, 0x0b, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x2BA, 0x0b, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x2BB, 0x06, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x2BC, 0x06, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x2BD, 0x06, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x29E, 0x06, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x2E4, 0x1a, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x2ED, 0x25, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x269, 0x1a, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x2F4, 0x2f, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x34B, 0x01, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x34C, 0x23, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x34D, 0x23, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x34E, 0x45, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x34F, 0x00, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x350, 0x31, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x351, 0x00, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x352, 0x02, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x353, 0x00, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x354, 0x01, PWR_MODE_ANY), + PHY_COMN_REG_CFG(0x43, 0x18, PWR_MODE_ANY), + PHY_COMN_REG_CFG(0x43, 0x00, PWR_MODE_ANY), + END_UFS_PHY_CFG, +}; + +static const struct samsung_ufs_phy_cfg tensor_gs101_pre_pwr_hs_config[] = { + PHY_TRSV_REG_CFG_GS101(0x369, 0x11, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x246, 0x03, PWR_MODE_ANY), +}; + +/* Calibration for HS mode series A/B */ +static const struct samsung_ufs_phy_cfg tensor_gs101_post_pwr_hs_config[] = { + PHY_COMN_REG_CFG(0x8, 0x60, PWR_MODE_PWM_ANY), + PHY_TRSV_REG_CFG_GS101(0x222, 0x08, PWR_MODE_PWM_ANY), + PHY_TRSV_REG_CFG_GS101(0x246, 0x01, PWR_MODE_ANY), + END_UFS_PHY_CFG, +}; + +static const struct samsung_ufs_phy_cfg *tensor_gs101_ufs_phy_cfgs[CFG_TAG_MAX] = { + [CFG_PRE_INIT] = tensor_gs101_pre_init_cfg, + [CFG_PRE_PWR_HS] = tensor_gs101_pre_pwr_hs_config, + [CFG_POST_PWR_HS] = tensor_gs101_post_pwr_hs_config, +}; + +static const char * const tensor_gs101_ufs_phy_clks[] = { + "ref_clk", +}; + +static int gs101_phy_wait_for_calibration(struct phy *phy, u8 lane) +{ + struct samsung_ufs_phy *ufs_phy = get_samsung_ufs_phy(phy); + const unsigned int timeout_us = 40000; + const unsigned int sleep_us = 40; + u32 val; + u32 off; + int err; + + off = PHY_PMA_TRSV_ADDR(TRSV_REG338, lane); + + err = readl_poll_timeout(ufs_phy->reg_pma + off, + val, (val & LN0_MON_RX_CAL_DONE), + sleep_us, timeout_us); + + if (err) { + dev_err(ufs_phy->dev, + "failed to get phy cal done %d\n", err); + } + + return err; +} + +#define DELAY_IN_US 40 +#define RETRY_CNT 100 +static int gs101_phy_wait_for_cdr_lock(struct phy *phy, u8 lane) +{ + struct samsung_ufs_phy *ufs_phy = get_samsung_ufs_phy(phy); + u32 val; + int i; + + for (i = 0; i < RETRY_CNT; i++) { + udelay(DELAY_IN_US); + val = readl(ufs_phy->reg_pma + + PHY_PMA_TRSV_ADDR(TRSV_REG339, lane)); + + if (val & LN0_MON_RX_CDR_FLD_CK_MODE_DONE) + return 0; + + udelay(DELAY_IN_US); + /* Override and enable clock data recovery */ + writel(LN0_OVRD_RX_CDR_EN, ufs_phy->reg_pma + + PHY_PMA_TRSV_ADDR(TRSV_REG222, lane)); + writel(LN0_OVRD_RX_CDR_EN | LN0_RX_CDR_EN, + ufs_phy->reg_pma + PHY_PMA_TRSV_ADDR(TRSV_REG222, lane)); + } + dev_err(ufs_phy->dev, "failed to get cdr lock\n"); + return -ETIMEDOUT; +} + +const struct samsung_ufs_phy_drvdata tensor_gs101_ufs_phy = { + .cfgs = tensor_gs101_ufs_phy_cfgs, + .isol = { + .offset = TENSOR_GS101_PHY_CTRL, + .mask = TENSOR_GS101_PHY_CTRL_MASK, + .en = TENSOR_GS101_PHY_CTRL_EN, + }, + .clk_list = tensor_gs101_ufs_phy_clks, + .num_clks = ARRAY_SIZE(tensor_gs101_ufs_phy_clks), + .wait_for_cal = gs101_phy_wait_for_calibration, + .wait_for_cdr = gs101_phy_wait_for_cdr_lock, +}; diff --git a/drivers/phy/samsung/phy-samsung-ufs.c b/drivers/phy/samsung/phy-samsung-ufs.c index f57a2f2a415d..813bce47121d 100644 --- a/drivers/phy/samsung/phy-samsung-ufs.c +++ b/drivers/phy/samsung/phy-samsung-ufs.c @@ -310,6 +310,9 @@ out: static const struct of_device_id samsung_ufs_phy_match[] = { { + .compatible = "google,gs101-ufs-phy", + .data = &tensor_gs101_ufs_phy, + }, { .compatible = "samsung,exynos7-ufs-phy", .data = &exynos7_ufs_phy, }, { diff --git a/drivers/phy/samsung/phy-samsung-ufs.h b/drivers/phy/samsung/phy-samsung-ufs.h index 7de6b574b94d..9b7deef6e10f 100644 --- a/drivers/phy/samsung/phy-samsung-ufs.h +++ b/drivers/phy/samsung/phy-samsung-ufs.h @@ -147,5 +147,6 @@ int samsung_ufs_phy_wait_for_lock_acq(struct phy *phy, u8 lane); extern const struct samsung_ufs_phy_drvdata exynos7_ufs_phy; extern const struct samsung_ufs_phy_drvdata exynosautov9_ufs_phy; extern const struct samsung_ufs_phy_drvdata fsd_ufs_phy; +extern const struct samsung_ufs_phy_drvdata tensor_gs101_ufs_phy; #endif /* _PHY_SAMSUNG_UFS_ */ -- cgit v1.2.3-59-g8ed1b From 0338e1d2f933a4ec7ae96ed1f40c39b899e357d7 Mon Sep 17 00:00:00 2001 From: Peter Griffin Date: Thu, 4 Apr 2024 13:25:59 +0100 Subject: MAINTAINERS: Add phy-gs101-ufs file to Tensor GS101. Add the newly created ufs phy for GS101 to MAINTAINERS. Signed-off-by: Peter Griffin Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240404122559.898930-18-peter.griffin@linaro.org Signed-off-by: Vinod Koul --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index aa3b947fb080..7debfc40df50 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9180,6 +9180,7 @@ S: Maintained F: Documentation/devicetree/bindings/clock/google,gs101-clock.yaml F: arch/arm64/boot/dts/exynos/google/ F: drivers/clk/samsung/clk-gs101.c +F: drivers/phy/samsung/phy-gs101-ufs.c F: include/dt-bindings/clock/google,gs101.h K: [gG]oogle.?[tT]ensor -- cgit v1.2.3-59-g8ed1b From 2d766e79ba2bd15e59ceda4b0596e369c9564948 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 30 Mar 2024 18:53:04 +0000 Subject: iio: dac: ad3552r: Use device_for_each_child_node_scoped() Switching to the _scoped() version removes the need for manual calling of fwnode_handle_put() in the paths where the code exits the loop early. In this case that's all in error paths. Removing the goto err; statements also allows more extensive use of dev_err_probe() further simplifying the code. Cc: Mihail Chindris Reviewed-by: Nuno Sa Link: https://lore.kernel.org/r/20240330185305.1319844-8-jic23@kernel.org Signed-off-by: Jonathan Cameron --- drivers/iio/dac/ad3552r.c | 51 ++++++++++++++++++----------------------------- 1 file changed, 19 insertions(+), 32 deletions(-) diff --git a/drivers/iio/dac/ad3552r.c b/drivers/iio/dac/ad3552r.c index a492e8f2fc0f..e14a065b29ca 100644 --- a/drivers/iio/dac/ad3552r.c +++ b/drivers/iio/dac/ad3552r.c @@ -880,7 +880,6 @@ static void ad3552r_reg_disable(void *reg) static int ad3552r_configure_device(struct ad3552r_desc *dac) { struct device *dev = &dac->spi->dev; - struct fwnode_handle *child; struct regulator *vref; int err, cnt = 0, voltage, delta = 100000; u32 vals[2], val, ch; @@ -949,53 +948,45 @@ static int ad3552r_configure_device(struct ad3552r_desc *dac) return -ENODEV; } - device_for_each_child_node(dev, child) { + device_for_each_child_node_scoped(dev, child) { err = fwnode_property_read_u32(child, "reg", &ch); - if (err) { - dev_err(dev, "mandatory reg property missing\n"); - goto put_child; - } - if (ch >= AD3552R_NUM_CH) { - dev_err(dev, "reg must be less than %d\n", - AD3552R_NUM_CH); - err = -EINVAL; - goto put_child; - } + if (err) + return dev_err_probe(dev, err, + "mandatory reg property missing\n"); + if (ch >= AD3552R_NUM_CH) + return dev_err_probe(dev, -EINVAL, + "reg must be less than %d\n", + AD3552R_NUM_CH); if (fwnode_property_present(child, "adi,output-range-microvolt")) { err = fwnode_property_read_u32_array(child, "adi,output-range-microvolt", vals, 2); - if (err) { - dev_err(dev, + if (err) + return dev_err_probe(dev, err, "adi,output-range-microvolt property could not be parsed\n"); - goto put_child; - } err = ad3552r_find_range(dac->chip_id, vals); - if (err < 0) { - dev_err(dev, - "Invalid adi,output-range-microvolt value\n"); - goto put_child; - } + if (err < 0) + return dev_err_probe(dev, err, + "Invalid adi,output-range-microvolt value\n"); + val = err; err = ad3552r_set_ch_value(dac, AD3552R_CH_OUTPUT_RANGE_SEL, ch, val); if (err) - goto put_child; + return err; dac->ch_data[ch].range = val; } else if (dac->chip_id == AD3542R_ID) { - dev_err(dev, - "adi,output-range-microvolt is required for ad3542r\n"); - err = -EINVAL; - goto put_child; + return dev_err_probe(dev, -EINVAL, + "adi,output-range-microvolt is required for ad3542r\n"); } else { err = ad3552r_configure_custom_gain(dac, child, ch); if (err) - goto put_child; + return err; } ad3552r_calc_gain_and_offset(dac, ch); @@ -1003,7 +994,7 @@ static int ad3552r_configure_device(struct ad3552r_desc *dac) err = ad3552r_set_ch_value(dac, AD3552R_CH_SELECT, ch, 1); if (err < 0) - goto put_child; + return err; dac->channels[cnt] = AD3552R_CH_DAC(ch); ++cnt; @@ -1021,10 +1012,6 @@ static int ad3552r_configure_device(struct ad3552r_desc *dac) dac->num_ch = cnt; return 0; -put_child: - fwnode_handle_put(child); - - return err; } static int ad3552r_init(struct ad3552r_desc *dac) -- cgit v1.2.3-59-g8ed1b From eff19f6b9e00f70cd20a3c62779b68b6e820500c Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 30 Mar 2024 18:53:05 +0000 Subject: iio: dac: ad5770r: Use device_for_each_child_node_scoped() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Switching to the _scoped() version removes the need for manual calling of fwnode_handle_put() in the paths where the code exits the loop early. In this case that's all in error paths. Cc: Nuno Sá Reviewed-by: Nuno Sa Link: https://lore.kernel.org/r/20240330185305.1319844-9-jic23@kernel.org Signed-off-by: Jonathan Cameron --- drivers/iio/dac/ad5770r.c | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/drivers/iio/dac/ad5770r.c b/drivers/iio/dac/ad5770r.c index f66d67402e43..c360ebf5297a 100644 --- a/drivers/iio/dac/ad5770r.c +++ b/drivers/iio/dac/ad5770r.c @@ -515,39 +515,32 @@ static int ad5770r_channel_config(struct ad5770r_state *st) { int ret, tmp[2], min, max; unsigned int num; - struct fwnode_handle *child; num = device_get_child_node_count(&st->spi->dev); if (num != AD5770R_MAX_CHANNELS) return -EINVAL; - device_for_each_child_node(&st->spi->dev, child) { + device_for_each_child_node_scoped(&st->spi->dev, child) { ret = fwnode_property_read_u32(child, "reg", &num); if (ret) - goto err_child_out; - if (num >= AD5770R_MAX_CHANNELS) { - ret = -EINVAL; - goto err_child_out; - } + return ret; + if (num >= AD5770R_MAX_CHANNELS) + return -EINVAL; ret = fwnode_property_read_u32_array(child, "adi,range-microamp", tmp, 2); if (ret) - goto err_child_out; + return ret; min = tmp[0] / 1000; max = tmp[1] / 1000; ret = ad5770r_store_output_range(st, min, max, num); if (ret) - goto err_child_out; + return ret; } return 0; - -err_child_out: - fwnode_handle_put(child); - return ret; } static int ad5770r_init(struct ad5770r_state *st) -- cgit v1.2.3-59-g8ed1b From 18abc64bfe0478716adcf0fd6b95ea4dbfe9f9e7 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 30 Mar 2024 19:08:43 +0000 Subject: iio: adc: ab8500-gpadc: Fix kernel-doc parameter names. Seems these got renamed at somepoint but the documentation wasn't updated to match. Cc: Linus Walleij Reviewed-by: Linus Walleij Reviewed-by: Nuno Sa Link: https://lore.kernel.org/r/20240330190849.1321065-3-jic23@kernel.org Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ab8500-gpadc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/iio/adc/ab8500-gpadc.c b/drivers/iio/adc/ab8500-gpadc.c index 80645fee79a4..0bc1550c7f11 100644 --- a/drivers/iio/adc/ab8500-gpadc.c +++ b/drivers/iio/adc/ab8500-gpadc.c @@ -1021,8 +1021,8 @@ static int ab8500_gpadc_parse_channel(struct device *dev, /** * ab8500_gpadc_parse_channels() - Parse the GPADC channels from DT * @gpadc: the GPADC to configure the channels for - * @chans: the IIO channels we parsed - * @nchans: the number of IIO channels we parsed + * @chans_parsed: the IIO channels we parsed + * @nchans_parsed: the number of IIO channels we parsed */ static int ab8500_gpadc_parse_channels(struct ab8500_gpadc *gpadc, struct iio_chan_spec **chans_parsed, -- cgit v1.2.3-59-g8ed1b From f875790e6ae8b53e99530e6c7f7d9394c1f6b9ee Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 30 Mar 2024 19:08:44 +0000 Subject: iio: adc: ab8500-gpadc: Use device_for_each_child_node_scoped() to simplify erorr paths. This new loop definition automatically releases the handle on early exit reducing the chance of bugs that cause resource leaks. Cc: Linus Walleij Reviewed-by: Linus Walleij Reviewed-by: Nuno Sa Link: https://lore.kernel.org/r/20240330190849.1321065-4-jic23@kernel.org Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ab8500-gpadc.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/iio/adc/ab8500-gpadc.c b/drivers/iio/adc/ab8500-gpadc.c index 0bc1550c7f11..59f66e9cb0e8 100644 --- a/drivers/iio/adc/ab8500-gpadc.c +++ b/drivers/iio/adc/ab8500-gpadc.c @@ -1028,7 +1028,6 @@ static int ab8500_gpadc_parse_channels(struct ab8500_gpadc *gpadc, struct iio_chan_spec **chans_parsed, unsigned int *nchans_parsed) { - struct fwnode_handle *child; struct ab8500_gpadc_chan_info *ch; struct iio_chan_spec *iio_chans; unsigned int nchans; @@ -1052,7 +1051,7 @@ static int ab8500_gpadc_parse_channels(struct ab8500_gpadc *gpadc, return -ENOMEM; i = 0; - device_for_each_child_node(gpadc->dev, child) { + device_for_each_child_node_scoped(gpadc->dev, child) { struct iio_chan_spec *iio_chan; int ret; @@ -1062,7 +1061,6 @@ static int ab8500_gpadc_parse_channels(struct ab8500_gpadc *gpadc, ret = ab8500_gpadc_parse_channel(gpadc->dev, child, ch, iio_chan); if (ret) { - fwnode_handle_put(child); return ret; } i++; -- cgit v1.2.3-59-g8ed1b From 8c40277ec673635a24fccf016510583065d30069 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 30 Mar 2024 19:08:45 +0000 Subject: iio: adc: ad4130: Use device_for_each_child_node_scoped() to simplify error paths. This loop definition removes the need for manual releasing of the fwnode_handle in early exit paths (here an error path) allow simplfication of the code and reducing the chance of future modificiations not releasing fwnode_handle correctly. Cc: Cosmin Tanislav Cc: Nuno Sa Reviewed-by: Nuno Sa Link: https://lore.kernel.org/r/20240330190849.1321065-5-jic23@kernel.org Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad4130.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/iio/adc/ad4130.c b/drivers/iio/adc/ad4130.c index febb64e67955..aaf1fb0ac447 100644 --- a/drivers/iio/adc/ad4130.c +++ b/drivers/iio/adc/ad4130.c @@ -1600,17 +1600,14 @@ static int ad4130_parse_fw_children(struct iio_dev *indio_dev) { struct ad4130_state *st = iio_priv(indio_dev); struct device *dev = &st->spi->dev; - struct fwnode_handle *child; int ret; indio_dev->channels = st->chans; - device_for_each_child_node(dev, child) { + device_for_each_child_node_scoped(dev, child) { ret = ad4130_parse_fw_channel(indio_dev, child); - if (ret) { - fwnode_handle_put(child); + if (ret) return ret; - } } return 0; -- cgit v1.2.3-59-g8ed1b From cf84f1e0a8fd236a965c4b79a1de1509e05e0343 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 30 Mar 2024 19:08:46 +0000 Subject: iio: adc: ad7173: Use device_for_each_child_node_scoped() to simplify error paths. This loop definition automatically releases the fwnode_handle on early exit such as the error cases seen here. This reducing boilerplate and the chance of a resource leak being introduced in future. Cc: Dumitru Ceclan Reviewed-by: Nuno Sa Link: https://lore.kernel.org/r/20240330190849.1321065-6-jic23@kernel.org Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7173.c | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/drivers/iio/adc/ad7173.c b/drivers/iio/adc/ad7173.c index 4ff6ce46b02c..f6d29abe1d04 100644 --- a/drivers/iio/adc/ad7173.c +++ b/drivers/iio/adc/ad7173.c @@ -910,7 +910,6 @@ static int ad7173_fw_parse_channel_config(struct iio_dev *indio_dev) struct device *dev = indio_dev->dev.parent; struct iio_chan_spec *chan_arr, *chan; unsigned int ain[2], chan_index = 0; - struct fwnode_handle *child; int ref_sel, ret; chan_arr = devm_kcalloc(dev, sizeof(*indio_dev->channels), @@ -940,23 +939,19 @@ static int ad7173_fw_parse_channel_config(struct iio_dev *indio_dev) chan_index++; } - device_for_each_child_node(dev, child) { + device_for_each_child_node_scoped(dev, child) { chan = &chan_arr[chan_index]; chan_st_priv = &chans_st_arr[chan_index]; ret = fwnode_property_read_u32_array(child, "diff-channels", ain, ARRAY_SIZE(ain)); - if (ret) { - fwnode_handle_put(child); + if (ret) return ret; - } if (ain[0] >= st->info->num_inputs || - ain[1] >= st->info->num_inputs) { - fwnode_handle_put(child); + ain[1] >= st->info->num_inputs) return dev_err_probe(dev, -EINVAL, "Input pin number out of range for pair (%d %d).\n", ain[0], ain[1]); - } ret = fwnode_property_match_property_string(child, "adi,reference-select", @@ -968,24 +963,19 @@ static int ad7173_fw_parse_channel_config(struct iio_dev *indio_dev) ref_sel = ret; if (ref_sel == AD7173_SETUP_REF_SEL_INT_REF && - !st->info->has_int_ref) { - fwnode_handle_put(child); + !st->info->has_int_ref) return dev_err_probe(dev, -EINVAL, "Internal reference is not available on current model.\n"); - } - if (ref_sel == AD7173_SETUP_REF_SEL_EXT_REF2 && !st->info->has_ref2) { - fwnode_handle_put(child); + if (ref_sel == AD7173_SETUP_REF_SEL_EXT_REF2 && !st->info->has_ref2) return dev_err_probe(dev, -EINVAL, "External reference 2 is not available on current model.\n"); - } ret = ad7173_get_ref_voltage_milli(st, ref_sel); - if (ret < 0) { - fwnode_handle_put(child); + if (ret < 0) return dev_err_probe(dev, ret, "Cannot use reference %u\n", ref_sel); - } + if (ref_sel == AD7173_SETUP_REF_SEL_INT_REF) st->adc_mode |= AD7173_ADC_MODE_REF_EN; chan_st_priv->cfg.ref_sel = ref_sel; -- cgit v1.2.3-59-g8ed1b From de4eefe8f16fb2854e8375978c0c517dcddc4d71 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 30 Mar 2024 19:08:47 +0000 Subject: iio: frequency: admfm2000: Use device_for_each_child_node_scoped() to simplify error paths. This loop definition automatically release the fwnode_handle on early exit simplifying error handling paths. Cc: Kim Seer Paller Reviewed-by: Nuno Sa Link: https://lore.kernel.org/r/20240330190849.1321065-7-jic23@kernel.org Signed-off-by: Jonathan Cameron --- drivers/iio/frequency/admfm2000.c | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/drivers/iio/frequency/admfm2000.c b/drivers/iio/frequency/admfm2000.c index c34d79e55a7c..b2263b9afeda 100644 --- a/drivers/iio/frequency/admfm2000.c +++ b/drivers/iio/frequency/admfm2000.c @@ -160,26 +160,21 @@ static int admfm2000_channel_config(struct admfm2000_state *st, { struct platform_device *pdev = to_platform_device(indio_dev->dev.parent); struct device *dev = &pdev->dev; - struct fwnode_handle *child; struct gpio_desc **dsa; struct gpio_desc **sw; int ret, i; bool mode; u32 reg; - device_for_each_child_node(dev, child) { + device_for_each_child_node_scoped(dev, child) { ret = fwnode_property_read_u32(child, "reg", ®); - if (ret) { - fwnode_handle_put(child); + if (ret) return dev_err_probe(dev, ret, "Failed to get reg property\n"); - } - if (reg >= indio_dev->num_channels) { - fwnode_handle_put(child); + if (reg >= indio_dev->num_channels) return dev_err_probe(dev, -EINVAL, "reg bigger than: %d\n", indio_dev->num_channels); - } if (fwnode_property_present(child, "adi,mixer-mode")) mode = ADMFM2000_MIXER_MODE; @@ -196,36 +191,29 @@ static int admfm2000_channel_config(struct admfm2000_state *st, dsa = st->dsa2_gpios; break; default: - fwnode_handle_put(child); return -EINVAL; } for (i = 0; i < ADMFM2000_MODE_GPIOS; i++) { sw[i] = devm_fwnode_gpiod_get_index(dev, child, "switch", i, GPIOD_OUT_LOW, NULL); - if (IS_ERR(sw[i])) { - fwnode_handle_put(child); + if (IS_ERR(sw[i])) return dev_err_probe(dev, PTR_ERR(sw[i]), "Failed to get gpios\n"); - } } for (i = 0; i < ADMFM2000_DSA_GPIOS; i++) { dsa[i] = devm_fwnode_gpiod_get_index(dev, child, "attenuation", i, GPIOD_OUT_LOW, NULL); - if (IS_ERR(dsa[i])) { - fwnode_handle_put(child); + if (IS_ERR(dsa[i])) return dev_err_probe(dev, PTR_ERR(dsa[i]), "Failed to get gpios\n"); - } } ret = admfm2000_mode(indio_dev, reg, mode); - if (ret) { - fwnode_handle_put(child); + if (ret) return ret; - } } return 0; -- cgit v1.2.3-59-g8ed1b From bcf571a854d4a91617d688015277525edfbc30fb Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 30 Mar 2024 19:08:48 +0000 Subject: iio: dac: ad3552: Use __free(fwnode_handle) to simplify error handling. By using this scoped based cleanup direct returns on errors are enabled simplifying the code. Cc: Mihail Chindris Cc: Marcelo Schmitt Reviewed-by: Nuno Sa Link: https://lore.kernel.org/r/20240330190849.1321065-8-jic23@kernel.org Signed-off-by: Jonathan Cameron --- drivers/iio/dac/ad3552r.c | 59 ++++++++++++++++++----------------------------- 1 file changed, 23 insertions(+), 36 deletions(-) diff --git a/drivers/iio/dac/ad3552r.c b/drivers/iio/dac/ad3552r.c index e14a065b29ca..8aa942896b5b 100644 --- a/drivers/iio/dac/ad3552r.c +++ b/drivers/iio/dac/ad3552r.c @@ -801,51 +801,45 @@ static int ad3552r_configure_custom_gain(struct ad3552r_desc *dac, u32 ch) { struct device *dev = &dac->spi->dev; - struct fwnode_handle *gain_child; u32 val; int err; u8 addr; u16 reg = 0, offset; - gain_child = fwnode_get_named_child_node(child, - "custom-output-range-config"); - if (!gain_child) { - dev_err(dev, - "mandatory custom-output-range-config property missing\n"); - return -EINVAL; - } + struct fwnode_handle *gain_child __free(fwnode_handle) + = fwnode_get_named_child_node(child, + "custom-output-range-config"); + if (!gain_child) + return dev_err_probe(dev, -EINVAL, + "mandatory custom-output-range-config property missing\n"); dac->ch_data[ch].range_override = 1; reg |= ad3552r_field_prep(1, AD3552R_MASK_CH_RANGE_OVERRIDE); err = fwnode_property_read_u32(gain_child, "adi,gain-scaling-p", &val); - if (err) { - dev_err(dev, "mandatory adi,gain-scaling-p property missing\n"); - goto put_child; - } + if (err) + return dev_err_probe(dev, err, + "mandatory adi,gain-scaling-p property missing\n"); reg |= ad3552r_field_prep(val, AD3552R_MASK_CH_GAIN_SCALING_P); dac->ch_data[ch].p = val; err = fwnode_property_read_u32(gain_child, "adi,gain-scaling-n", &val); - if (err) { - dev_err(dev, "mandatory adi,gain-scaling-n property missing\n"); - goto put_child; - } + if (err) + return dev_err_probe(dev, err, + "mandatory adi,gain-scaling-n property missing\n"); reg |= ad3552r_field_prep(val, AD3552R_MASK_CH_GAIN_SCALING_N); dac->ch_data[ch].n = val; err = fwnode_property_read_u32(gain_child, "adi,rfb-ohms", &val); - if (err) { - dev_err(dev, "mandatory adi,rfb-ohms property missing\n"); - goto put_child; - } + if (err) + return dev_err_probe(dev, err, + "mandatory adi,rfb-ohms property missing\n"); dac->ch_data[ch].rfb = val; err = fwnode_property_read_u32(gain_child, "adi,gain-offset", &val); - if (err) { - dev_err(dev, "mandatory adi,gain-offset property missing\n"); - goto put_child; - } + if (err) + return dev_err_probe(dev, err, + "mandatory adi,gain-offset property missing\n"); dac->ch_data[ch].gain_offset = val; offset = abs((s32)val); @@ -855,21 +849,14 @@ static int ad3552r_configure_custom_gain(struct ad3552r_desc *dac, addr = AD3552R_REG_ADDR_CH_GAIN(ch); err = ad3552r_write_reg(dac, addr, offset & AD3552R_MASK_CH_OFFSET_BITS_0_7); - if (err) { - dev_err(dev, "Error writing register\n"); - goto put_child; - } + if (err) + return dev_err_probe(dev, err, "Error writing register\n"); err = ad3552r_write_reg(dac, addr, reg); - if (err) { - dev_err(dev, "Error writing register\n"); - goto put_child; - } - -put_child: - fwnode_handle_put(gain_child); + if (err) + return dev_err_probe(dev, err, "Error writing register\n"); - return err; + return 0; } static void ad3552r_reg_disable(void *reg) -- cgit v1.2.3-59-g8ed1b From 2eef045c5231658b3d7514c6640951e0de3e9d05 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 30 Mar 2024 19:08:49 +0000 Subject: iio: adc: pac1934: Use device_for_each_available_child_node_scoped() to simplify error handling. Also change both firmware parsing functions to return meaningful errors. Whilst for the ACPI case this isn't that useful, for the generic fwnode case we can return the errors coming from the property parsing instead of just whether we succeeded or not. Cc: Marius Cristea Reviewed-by: Nuno Sa Link: https://lore.kernel.org/r/20240330190849.1321065-9-jic23@kernel.org Signed-off-by: Jonathan Cameron --- drivers/iio/adc/pac1934.c | 77 +++++++++++++++++++---------------------------- 1 file changed, 31 insertions(+), 46 deletions(-) diff --git a/drivers/iio/adc/pac1934.c b/drivers/iio/adc/pac1934.c index e0c2742da523..f751260605e4 100644 --- a/drivers/iio/adc/pac1934.c +++ b/drivers/iio/adc/pac1934.c @@ -1079,8 +1079,8 @@ static int pac1934_chip_identify(struct pac1934_chip_info *info) * documentation related to the ACPI device definition * https://ww1.microchip.com/downloads/aemDocuments/documents/OTH/ApplicationNotes/ApplicationNotes/PAC1934-Integration-Notes-for-Microsoft-Windows-10-and-Windows-11-Driver-Support-DS00002534.pdf */ -static bool pac1934_acpi_parse_channel_config(struct i2c_client *client, - struct pac1934_chip_info *info) +static int pac1934_acpi_parse_channel_config(struct i2c_client *client, + struct pac1934_chip_info *info) { acpi_handle handle; union acpi_object *rez; @@ -1095,7 +1095,7 @@ static bool pac1934_acpi_parse_channel_config(struct i2c_client *client, rez = acpi_evaluate_dsm(handle, &guid, 0, PAC1934_ACPI_GET_NAMES_AND_MOHMS_VALS, NULL); if (!rez) - return false; + return -EINVAL; for (i = 0; i < rez->package.count; i += 2) { idx = i / 2; @@ -1118,7 +1118,7 @@ static bool pac1934_acpi_parse_channel_config(struct i2c_client *client, * and assign the default sampling rate */ info->sample_rate_value = PAC1934_DEFAULT_CHIP_SAMP_SPEED_HZ; - return true; + return 0; } for (i = 0; i < rez->package.count; i++) { @@ -1131,7 +1131,7 @@ static bool pac1934_acpi_parse_channel_config(struct i2c_client *client, rez = acpi_evaluate_dsm(handle, &guid, 1, PAC1934_ACPI_GET_BIPOLAR_SETTINGS, NULL); if (!rez) - return false; + return -EINVAL; bi_dir_mask = rez->package.elements[0].integer.value; info->bi_dir[0] = ((bi_dir_mask & (1 << 3)) | (bi_dir_mask & (1 << 7))) != 0; @@ -1143,19 +1143,18 @@ static bool pac1934_acpi_parse_channel_config(struct i2c_client *client, rez = acpi_evaluate_dsm(handle, &guid, 1, PAC1934_ACPI_GET_SAMP, NULL); if (!rez) - return false; + return -EINVAL; info->sample_rate_value = rez->package.elements[0].integer.value; ACPI_FREE(rez); - return true; + return 0; } -static bool pac1934_of_parse_channel_config(struct i2c_client *client, - struct pac1934_chip_info *info) +static int pac1934_fw_parse_channel_config(struct i2c_client *client, + struct pac1934_chip_info *info) { - struct fwnode_handle *node, *fwnode; struct device *dev = &client->dev; unsigned int current_channel; int idx, ret; @@ -1163,46 +1162,38 @@ static bool pac1934_of_parse_channel_config(struct i2c_client *client, info->sample_rate_value = 1024; current_channel = 1; - fwnode = dev_fwnode(dev); - fwnode_for_each_available_child_node(fwnode, node) { + device_for_each_child_node_scoped(dev, node) { ret = fwnode_property_read_u32(node, "reg", &idx); - if (ret) { - dev_err_probe(dev, ret, - "reading invalid channel index\n"); - goto err_fwnode; - } + if (ret) + return dev_err_probe(dev, ret, + "reading invalid channel index\n"); + /* adjust idx to match channel index (1 to 4) from the datasheet */ idx--; if (current_channel >= (info->phys_channels + 1) || - idx >= info->phys_channels || idx < 0) { - dev_err_probe(dev, -EINVAL, - "%s: invalid channel_index %d value\n", - fwnode_get_name(node), idx); - goto err_fwnode; - } + idx >= info->phys_channels || idx < 0) + return dev_err_probe(dev, -EINVAL, + "%s: invalid channel_index %d value\n", + fwnode_get_name(node), idx); /* enable channel */ info->active_channels[idx] = true; ret = fwnode_property_read_u32(node, "shunt-resistor-micro-ohms", &info->shunts[idx]); - if (ret) { - dev_err_probe(dev, ret, - "%s: invalid shunt-resistor value: %d\n", - fwnode_get_name(node), info->shunts[idx]); - goto err_fwnode; - } + if (ret) + return dev_err_probe(dev, ret, + "%s: invalid shunt-resistor value: %d\n", + fwnode_get_name(node), info->shunts[idx]); if (fwnode_property_present(node, "label")) { ret = fwnode_property_read_string(node, "label", (const char **)&info->labels[idx]); - if (ret) { - dev_err_probe(dev, ret, - "%s: invalid rail-name value\n", - fwnode_get_name(node)); - goto err_fwnode; - } + if (ret) + return dev_err_probe(dev, ret, + "%s: invalid rail-name value\n", + fwnode_get_name(node)); } info->bi_dir[idx] = fwnode_property_read_bool(node, "bipolar"); @@ -1210,12 +1201,7 @@ static bool pac1934_of_parse_channel_config(struct i2c_client *client, current_channel++; } - return true; - -err_fwnode: - fwnode_handle_put(node); - - return false; + return 0; } static void pac1934_cancel_delayed_work(void *dwork) @@ -1485,7 +1471,6 @@ static int pac1934_probe(struct i2c_client *client) const struct pac1934_features *chip; struct iio_dev *indio_dev; int cnt, ret; - bool match = false; struct device *dev = &client->dev; indio_dev = devm_iio_device_alloc(dev, sizeof(*info)); @@ -1519,16 +1504,16 @@ static int pac1934_probe(struct i2c_client *client) } if (acpi_match_device(dev->driver->acpi_match_table, dev)) - match = pac1934_acpi_parse_channel_config(client, info); + ret = pac1934_acpi_parse_channel_config(client, info); else /* * This makes it possible to use also ACPI PRP0001 for * registering the device using device tree properties. */ - match = pac1934_of_parse_channel_config(client, info); + ret = pac1934_fw_parse_channel_config(client, info); - if (!match) - return dev_err_probe(dev, -EINVAL, + if (ret) + return dev_err_probe(dev, ret, "parameter parsing returned an error\n"); mutex_init(&info->lock); -- cgit v1.2.3-59-g8ed1b From f68ebfe1501bf1110eebf5e968c4d9186cba8706 Mon Sep 17 00:00:00 2001 From: Lothar Rubusch Date: Mon, 1 Apr 2024 19:48:59 +0000 Subject: iio: accel: adxl345: Make data_range obsolete Replace write() data_format by regmap_update_bits() to keep bus specific pre-configuration which might have happened before on the same register. The bus specific bits in data_format register then need to be masked out, Remove the data_range field from the struct adxl345_data, because it is not used anymore. Signed-off-by: Lothar Rubusch Link: https://lore.kernel.org/r/20240401194906.56810-2-l.rubusch@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/accel/adxl345_core.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/drivers/iio/accel/adxl345_core.c b/drivers/iio/accel/adxl345_core.c index 8bd30a23ed3b..ff89215e90fd 100644 --- a/drivers/iio/accel/adxl345_core.c +++ b/drivers/iio/accel/adxl345_core.c @@ -37,7 +37,11 @@ #define ADXL345_POWER_CTL_MEASURE BIT(3) #define ADXL345_POWER_CTL_STANDBY 0x00 -#define ADXL345_DATA_FORMAT_FULL_RES BIT(3) /* Up to 13-bits resolution */ +#define ADXL345_DATA_FORMAT_RANGE GENMASK(1, 0) /* Set the g range */ +#define ADXL345_DATA_FORMAT_JUSTIFY BIT(2) /* Left-justified (MSB) mode */ +#define ADXL345_DATA_FORMAT_FULL_RES BIT(3) /* Up to 13-bits resolution */ +#define ADXL345_DATA_FORMAT_SELF_TEST BIT(7) /* Enable a self test */ + #define ADXL345_DATA_FORMAT_2G 0 #define ADXL345_DATA_FORMAT_4G 1 #define ADXL345_DATA_FORMAT_8G 2 @@ -48,7 +52,6 @@ struct adxl345_data { const struct adxl345_chip_info *info; struct regmap *regmap; - u8 data_range; }; #define ADXL345_CHANNEL(index, axis) { \ @@ -202,6 +205,10 @@ int adxl345_core_probe(struct device *dev, struct regmap *regmap) struct adxl345_data *data; struct iio_dev *indio_dev; u32 regval; + unsigned int data_format_mask = (ADXL345_DATA_FORMAT_RANGE | + ADXL345_DATA_FORMAT_JUSTIFY | + ADXL345_DATA_FORMAT_FULL_RES | + ADXL345_DATA_FORMAT_SELF_TEST); int ret; ret = regmap_read(regmap, ADXL345_REG_DEVID, ®val); @@ -218,15 +225,14 @@ int adxl345_core_probe(struct device *dev, struct regmap *regmap) data = iio_priv(indio_dev); data->regmap = regmap; - /* Enable full-resolution mode */ - data->data_range = ADXL345_DATA_FORMAT_FULL_RES; data->info = device_get_match_data(dev); if (!data->info) return -ENODEV; - ret = regmap_write(data->regmap, ADXL345_REG_DATA_FORMAT, - data->data_range); - if (ret < 0) + /* Enable full-resolution mode */ + ret = regmap_update_bits(regmap, ADXL345_REG_DATA_FORMAT, + data_format_mask, ADXL345_DATA_FORMAT_FULL_RES); + if (ret) return dev_err_probe(dev, ret, "Failed to set data range\n"); indio_dev->name = data->info->name; -- cgit v1.2.3-59-g8ed1b From ab158628d46c0cf15f77bc839e96d800dbdcbf8a Mon Sep 17 00:00:00 2001 From: Lothar Rubusch Date: Mon, 1 Apr 2024 19:49:00 +0000 Subject: iio: accel: adxl345: Group bus configuration Group the indio_dev initialization and bus configuration for improved readability. Signed-off-by: Lothar Rubusch Link: https://lore.kernel.org/r/20240401194906.56810-3-l.rubusch@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/accel/adxl345_core.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/iio/accel/adxl345_core.c b/drivers/iio/accel/adxl345_core.c index ff89215e90fd..e4afc6d2a681 100644 --- a/drivers/iio/accel/adxl345_core.c +++ b/drivers/iio/accel/adxl345_core.c @@ -229,18 +229,18 @@ int adxl345_core_probe(struct device *dev, struct regmap *regmap) if (!data->info) return -ENODEV; - /* Enable full-resolution mode */ - ret = regmap_update_bits(regmap, ADXL345_REG_DATA_FORMAT, - data_format_mask, ADXL345_DATA_FORMAT_FULL_RES); - if (ret) - return dev_err_probe(dev, ret, "Failed to set data range\n"); - indio_dev->name = data->info->name; indio_dev->info = &adxl345_info; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->channels = adxl345_channels; indio_dev->num_channels = ARRAY_SIZE(adxl345_channels); + /* Enable full-resolution mode */ + ret = regmap_update_bits(regmap, ADXL345_REG_DATA_FORMAT, + data_format_mask, ADXL345_DATA_FORMAT_FULL_RES); + if (ret) + return dev_err_probe(dev, ret, "Failed to set data range\n"); + /* Enable measurement mode */ ret = adxl345_powerup(data->regmap); if (ret < 0) -- cgit v1.2.3-59-g8ed1b From 25b83220873a19cab7e424da656da0106573431c Mon Sep 17 00:00:00 2001 From: Lothar Rubusch Date: Mon, 1 Apr 2024 19:49:01 +0000 Subject: iio: accel: adxl345: Move defines to header Move defines from core to the header file. Keep the defines block together in one location. Signed-off-by: Lothar Rubusch Link: https://lore.kernel.org/r/20240401194906.56810-4-l.rubusch@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/accel/adxl345.h | 32 ++++++++++++++++++++++++++++++++ drivers/iio/accel/adxl345_core.c | 32 -------------------------------- 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/drivers/iio/accel/adxl345.h b/drivers/iio/accel/adxl345.h index 284bd387ce69..732820d34db3 100644 --- a/drivers/iio/accel/adxl345.h +++ b/drivers/iio/accel/adxl345.h @@ -8,6 +8,38 @@ #ifndef _ADXL345_H_ #define _ADXL345_H_ +#define ADXL345_REG_DEVID 0x00 +#define ADXL345_REG_OFSX 0x1E +#define ADXL345_REG_OFSY 0x1F +#define ADXL345_REG_OFSZ 0x20 +#define ADXL345_REG_OFS_AXIS(index) (ADXL345_REG_OFSX + (index)) +#define ADXL345_REG_BW_RATE 0x2C +#define ADXL345_REG_POWER_CTL 0x2D +#define ADXL345_REG_DATA_FORMAT 0x31 +#define ADXL345_REG_DATAX0 0x32 +#define ADXL345_REG_DATAY0 0x34 +#define ADXL345_REG_DATAZ0 0x36 +#define ADXL345_REG_DATA_AXIS(index) \ + (ADXL345_REG_DATAX0 + (index) * sizeof(__le16)) + +#define ADXL345_BW_RATE GENMASK(3, 0) +#define ADXL345_BASE_RATE_NANO_HZ 97656250LL + +#define ADXL345_POWER_CTL_MEASURE BIT(3) +#define ADXL345_POWER_CTL_STANDBY 0x00 + +#define ADXL345_DATA_FORMAT_RANGE GENMASK(1, 0) /* Set the g range */ +#define ADXL345_DATA_FORMAT_JUSTIFY BIT(2) /* Left-justified (MSB) mode */ +#define ADXL345_DATA_FORMAT_FULL_RES BIT(3) /* Up to 13-bits resolution */ +#define ADXL345_DATA_FORMAT_SELF_TEST BIT(7) /* Enable a self test */ + +#define ADXL345_DATA_FORMAT_2G 0 +#define ADXL345_DATA_FORMAT_4G 1 +#define ADXL345_DATA_FORMAT_8G 2 +#define ADXL345_DATA_FORMAT_16G 3 + +#define ADXL345_DEVID 0xE5 + /* * In full-resolution mode, scale factor is maintained at ~4 mg/LSB * in all g ranges. diff --git a/drivers/iio/accel/adxl345_core.c b/drivers/iio/accel/adxl345_core.c index e4afc6d2a681..f875a6275fb8 100644 --- a/drivers/iio/accel/adxl345_core.c +++ b/drivers/iio/accel/adxl345_core.c @@ -17,38 +17,6 @@ #include "adxl345.h" -#define ADXL345_REG_DEVID 0x00 -#define ADXL345_REG_OFSX 0x1e -#define ADXL345_REG_OFSY 0x1f -#define ADXL345_REG_OFSZ 0x20 -#define ADXL345_REG_OFS_AXIS(index) (ADXL345_REG_OFSX + (index)) -#define ADXL345_REG_BW_RATE 0x2C -#define ADXL345_REG_POWER_CTL 0x2D -#define ADXL345_REG_DATA_FORMAT 0x31 -#define ADXL345_REG_DATAX0 0x32 -#define ADXL345_REG_DATAY0 0x34 -#define ADXL345_REG_DATAZ0 0x36 -#define ADXL345_REG_DATA_AXIS(index) \ - (ADXL345_REG_DATAX0 + (index) * sizeof(__le16)) - -#define ADXL345_BW_RATE GENMASK(3, 0) -#define ADXL345_BASE_RATE_NANO_HZ 97656250LL - -#define ADXL345_POWER_CTL_MEASURE BIT(3) -#define ADXL345_POWER_CTL_STANDBY 0x00 - -#define ADXL345_DATA_FORMAT_RANGE GENMASK(1, 0) /* Set the g range */ -#define ADXL345_DATA_FORMAT_JUSTIFY BIT(2) /* Left-justified (MSB) mode */ -#define ADXL345_DATA_FORMAT_FULL_RES BIT(3) /* Up to 13-bits resolution */ -#define ADXL345_DATA_FORMAT_SELF_TEST BIT(7) /* Enable a self test */ - -#define ADXL345_DATA_FORMAT_2G 0 -#define ADXL345_DATA_FORMAT_4G 1 -#define ADXL345_DATA_FORMAT_8G 2 -#define ADXL345_DATA_FORMAT_16G 3 - -#define ADXL345_DEVID 0xE5 - struct adxl345_data { const struct adxl345_chip_info *info; struct regmap *regmap; -- cgit v1.2.3-59-g8ed1b From 59307e8f74fb339f5c665fc521466bbf18752bce Mon Sep 17 00:00:00 2001 From: Lothar Rubusch Date: Mon, 1 Apr 2024 19:49:02 +0000 Subject: dt-bindings: iio: accel: adxl345: Add spi-3wire Add spi-3wire because the device allows to be configured for spi 3-wire communication. Signed-off-by: Lothar Rubusch Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240401194906.56810-5-l.rubusch@gmail.com Signed-off-by: Jonathan Cameron --- Documentation/devicetree/bindings/iio/accel/adi,adxl345.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/iio/accel/adi,adxl345.yaml b/Documentation/devicetree/bindings/iio/accel/adi,adxl345.yaml index 07cacc3f6a97..280ed479ef5a 100644 --- a/Documentation/devicetree/bindings/iio/accel/adi,adxl345.yaml +++ b/Documentation/devicetree/bindings/iio/accel/adi,adxl345.yaml @@ -32,6 +32,8 @@ properties: spi-cpol: true + spi-3wire: true + interrupts: maxItems: 1 -- cgit v1.2.3-59-g8ed1b From 41561abc417eb92b38631cb05427fecbfeec19cb Mon Sep 17 00:00:00 2001 From: Lothar Rubusch Date: Mon, 1 Apr 2024 19:49:03 +0000 Subject: iio: accel: adxl345: Pass function pointer to core Provide a way for bus specific pre-configuration by adding a function pointer argument to the driver core's probe() function, and keep the driver core implementation bus independent. In case NULL was passed, a regmap_write() shall initialize all bits of the data_format register, else regmap_update() is used. In this way spi and i2c are covered. Signed-off-by: Lothar Rubusch Link: https://lore.kernel.org/r/20240401194906.56810-6-l.rubusch@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/accel/adxl345.h | 3 ++- drivers/iio/accel/adxl345_core.c | 32 +++++++++++++++++++++++++------- drivers/iio/accel/adxl345_i2c.c | 2 +- drivers/iio/accel/adxl345_spi.c | 2 +- 4 files changed, 29 insertions(+), 10 deletions(-) diff --git a/drivers/iio/accel/adxl345.h b/drivers/iio/accel/adxl345.h index 732820d34db3..e859c01d4bff 100644 --- a/drivers/iio/accel/adxl345.h +++ b/drivers/iio/accel/adxl345.h @@ -60,6 +60,7 @@ struct adxl345_chip_info { int uscale; }; -int adxl345_core_probe(struct device *dev, struct regmap *regmap); +int adxl345_core_probe(struct device *dev, struct regmap *regmap, + int (*setup)(struct device*, struct regmap*)); #endif /* _ADXL345_H_ */ diff --git a/drivers/iio/accel/adxl345_core.c b/drivers/iio/accel/adxl345_core.c index f875a6275fb8..8d4a66d8c528 100644 --- a/drivers/iio/accel/adxl345_core.c +++ b/drivers/iio/accel/adxl345_core.c @@ -168,7 +168,8 @@ static void adxl345_powerdown(void *regmap) regmap_write(regmap, ADXL345_REG_POWER_CTL, ADXL345_POWER_CTL_STANDBY); } -int adxl345_core_probe(struct device *dev, struct regmap *regmap) +int adxl345_core_probe(struct device *dev, struct regmap *regmap, + int (*setup)(struct device*, struct regmap*)) { struct adxl345_data *data; struct iio_dev *indio_dev; @@ -179,6 +180,29 @@ int adxl345_core_probe(struct device *dev, struct regmap *regmap) ADXL345_DATA_FORMAT_SELF_TEST); int ret; + if (setup) { + /* Perform optional initial bus specific configuration */ + ret = setup(dev, regmap); + if (ret) + return ret; + + /* Enable full-resolution mode */ + ret = regmap_update_bits(regmap, ADXL345_REG_DATA_FORMAT, + data_format_mask, + ADXL345_DATA_FORMAT_FULL_RES); + if (ret) + return dev_err_probe(dev, ret, + "Failed to set data range\n"); + + } else { + /* Enable full-resolution mode (init all data_format bits) */ + ret = regmap_write(regmap, ADXL345_REG_DATA_FORMAT, + ADXL345_DATA_FORMAT_FULL_RES); + if (ret) + return dev_err_probe(dev, ret, + "Failed to set data range\n"); + } + ret = regmap_read(regmap, ADXL345_REG_DEVID, ®val); if (ret < 0) return dev_err_probe(dev, ret, "Error reading device ID\n"); @@ -203,12 +227,6 @@ int adxl345_core_probe(struct device *dev, struct regmap *regmap) indio_dev->channels = adxl345_channels; indio_dev->num_channels = ARRAY_SIZE(adxl345_channels); - /* Enable full-resolution mode */ - ret = regmap_update_bits(regmap, ADXL345_REG_DATA_FORMAT, - data_format_mask, ADXL345_DATA_FORMAT_FULL_RES); - if (ret) - return dev_err_probe(dev, ret, "Failed to set data range\n"); - /* Enable measurement mode */ ret = adxl345_powerup(data->regmap); if (ret < 0) diff --git a/drivers/iio/accel/adxl345_i2c.c b/drivers/iio/accel/adxl345_i2c.c index a3084b0a8f78..4065b8f7c8a8 100644 --- a/drivers/iio/accel/adxl345_i2c.c +++ b/drivers/iio/accel/adxl345_i2c.c @@ -27,7 +27,7 @@ static int adxl345_i2c_probe(struct i2c_client *client) if (IS_ERR(regmap)) return dev_err_probe(&client->dev, PTR_ERR(regmap), "Error initializing regmap\n"); - return adxl345_core_probe(&client->dev, regmap); + return adxl345_core_probe(&client->dev, regmap, NULL); } static const struct adxl345_chip_info adxl345_i2c_info = { diff --git a/drivers/iio/accel/adxl345_spi.c b/drivers/iio/accel/adxl345_spi.c index 93ca349f1780..1c0513bd3b9b 100644 --- a/drivers/iio/accel/adxl345_spi.c +++ b/drivers/iio/accel/adxl345_spi.c @@ -33,7 +33,7 @@ static int adxl345_spi_probe(struct spi_device *spi) if (IS_ERR(regmap)) return dev_err_probe(&spi->dev, PTR_ERR(regmap), "Error initializing regmap\n"); - return adxl345_core_probe(&spi->dev, regmap); + return adxl345_core_probe(&spi->dev, regmap, NULL); } static const struct adxl345_chip_info adxl345_spi_info = { -- cgit v1.2.3-59-g8ed1b From 196fb733e5e6c4f05e208ad31c4155cd525750e9 Mon Sep 17 00:00:00 2001 From: Lothar Rubusch Date: Mon, 1 Apr 2024 19:49:04 +0000 Subject: iio: accel: adxl345: Reorder probe initialization Bring indio_dev, setup() and data initialization to begin of the probe() function to increase readability. Access members through data pointer to assure implicitely the driver's data instance is correctly initialized and functional. Signed-off-by: Lothar Rubusch Link: https://lore.kernel.org/r/20240401194906.56810-7-l.rubusch@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/accel/adxl345_core.c | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/drivers/iio/accel/adxl345_core.c b/drivers/iio/accel/adxl345_core.c index 8d4a66d8c528..5d0f3243ec6c 100644 --- a/drivers/iio/accel/adxl345_core.c +++ b/drivers/iio/accel/adxl345_core.c @@ -180,14 +180,30 @@ int adxl345_core_probe(struct device *dev, struct regmap *regmap, ADXL345_DATA_FORMAT_SELF_TEST); int ret; + indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + data = iio_priv(indio_dev); + data->regmap = regmap; + data->info = device_get_match_data(dev); + if (!data->info) + return -ENODEV; + + indio_dev->name = data->info->name; + indio_dev->info = &adxl345_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = adxl345_channels; + indio_dev->num_channels = ARRAY_SIZE(adxl345_channels); + if (setup) { /* Perform optional initial bus specific configuration */ - ret = setup(dev, regmap); + ret = setup(dev, data->regmap); if (ret) return ret; /* Enable full-resolution mode */ - ret = regmap_update_bits(regmap, ADXL345_REG_DATA_FORMAT, + ret = regmap_update_bits(data->regmap, ADXL345_REG_DATA_FORMAT, data_format_mask, ADXL345_DATA_FORMAT_FULL_RES); if (ret) @@ -196,14 +212,14 @@ int adxl345_core_probe(struct device *dev, struct regmap *regmap, } else { /* Enable full-resolution mode (init all data_format bits) */ - ret = regmap_write(regmap, ADXL345_REG_DATA_FORMAT, + ret = regmap_write(data->regmap, ADXL345_REG_DATA_FORMAT, ADXL345_DATA_FORMAT_FULL_RES); if (ret) return dev_err_probe(dev, ret, "Failed to set data range\n"); } - ret = regmap_read(regmap, ADXL345_REG_DEVID, ®val); + ret = regmap_read(data->regmap, ADXL345_REG_DEVID, ®val); if (ret < 0) return dev_err_probe(dev, ret, "Error reading device ID\n"); @@ -211,22 +227,6 @@ int adxl345_core_probe(struct device *dev, struct regmap *regmap, return dev_err_probe(dev, -ENODEV, "Invalid device ID: %x, expected %x\n", regval, ADXL345_DEVID); - indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); - if (!indio_dev) - return -ENOMEM; - - data = iio_priv(indio_dev); - data->regmap = regmap; - data->info = device_get_match_data(dev); - if (!data->info) - return -ENODEV; - - indio_dev->name = data->info->name; - indio_dev->info = &adxl345_info; - indio_dev->modes = INDIO_DIRECT_MODE; - indio_dev->channels = adxl345_channels; - indio_dev->num_channels = ARRAY_SIZE(adxl345_channels); - /* Enable measurement mode */ ret = adxl345_powerup(data->regmap); if (ret < 0) -- cgit v1.2.3-59-g8ed1b From 34ca62caa0dd7c62b57e5b48a69af677c7a63824 Mon Sep 17 00:00:00 2001 From: Lothar Rubusch Date: Mon, 1 Apr 2024 19:49:05 +0000 Subject: iio: accel: adxl345: Add comment to probe Add a comment to the probe() function to describe the passed function pointer argument in particular. Signed-off-by: Lothar Rubusch Link: https://lore.kernel.org/r/20240401194906.56810-8-l.rubusch@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/accel/adxl345_core.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/iio/accel/adxl345_core.c b/drivers/iio/accel/adxl345_core.c index 5d0f3243ec6c..006ce66c0aa3 100644 --- a/drivers/iio/accel/adxl345_core.c +++ b/drivers/iio/accel/adxl345_core.c @@ -168,6 +168,16 @@ static void adxl345_powerdown(void *regmap) regmap_write(regmap, ADXL345_REG_POWER_CTL, ADXL345_POWER_CTL_STANDBY); } +/** + * adxl345_core_probe() - probe and setup for the adxl345 accelerometer, + * also covers the adlx375 accelerometer + * @dev: Driver model representation of the device + * @regmap: Regmap instance for the device + * @setup: Setup routine to be executed right before the standard device + * setup + * + * Return: 0 on success, negative errno on error + */ int adxl345_core_probe(struct device *dev, struct regmap *regmap, int (*setup)(struct device*, struct regmap*)) { -- cgit v1.2.3-59-g8ed1b From 2f896dd97cedbf6a8a7a14f4c6090d2b088cb694 Mon Sep 17 00:00:00 2001 From: Lothar Rubusch Date: Mon, 1 Apr 2024 19:49:06 +0000 Subject: iio: accel: adxl345: Add spi-3wire option Add a setup function implementation to the spi module to enable spi-3wire when specified in the device-tree. If spi-3wire is not specified in the device-tree, NULL is returned as bus pre-initialization. This behavior is identical to the i2c initialization, hence the default initialization. Signed-off-by: Lothar Rubusch Link: https://lore.kernel.org/r/20240401194906.56810-9-l.rubusch@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/accel/adxl345.h | 1 + drivers/iio/accel/adxl345_spi.c | 10 +++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/iio/accel/adxl345.h b/drivers/iio/accel/adxl345.h index e859c01d4bff..3d5c8719db3d 100644 --- a/drivers/iio/accel/adxl345.h +++ b/drivers/iio/accel/adxl345.h @@ -31,6 +31,7 @@ #define ADXL345_DATA_FORMAT_RANGE GENMASK(1, 0) /* Set the g range */ #define ADXL345_DATA_FORMAT_JUSTIFY BIT(2) /* Left-justified (MSB) mode */ #define ADXL345_DATA_FORMAT_FULL_RES BIT(3) /* Up to 13-bits resolution */ +#define ADXL345_DATA_FORMAT_SPI_3WIRE BIT(6) /* 3-wire SPI mode */ #define ADXL345_DATA_FORMAT_SELF_TEST BIT(7) /* Enable a self test */ #define ADXL345_DATA_FORMAT_2G 0 diff --git a/drivers/iio/accel/adxl345_spi.c b/drivers/iio/accel/adxl345_spi.c index 1c0513bd3b9b..57e16b441702 100644 --- a/drivers/iio/accel/adxl345_spi.c +++ b/drivers/iio/accel/adxl345_spi.c @@ -20,6 +20,11 @@ static const struct regmap_config adxl345_spi_regmap_config = { .read_flag_mask = BIT(7) | BIT(6), }; +static int adxl345_spi_setup(struct device *dev, struct regmap *regmap) +{ + return regmap_write(regmap, ADXL345_REG_DATA_FORMAT, ADXL345_DATA_FORMAT_SPI_3WIRE); +} + static int adxl345_spi_probe(struct spi_device *spi) { struct regmap *regmap; @@ -33,7 +38,10 @@ static int adxl345_spi_probe(struct spi_device *spi) if (IS_ERR(regmap)) return dev_err_probe(&spi->dev, PTR_ERR(regmap), "Error initializing regmap\n"); - return adxl345_core_probe(&spi->dev, regmap, NULL); + if (spi->mode & SPI_3WIRE) + return adxl345_core_probe(&spi->dev, regmap, adxl345_spi_setup); + else + return adxl345_core_probe(&spi->dev, regmap, NULL); } static const struct adxl345_chip_info adxl345_spi_info = { -- cgit v1.2.3-59-g8ed1b From c8e2d4873902c58ee14d3eb5138f516ba963e7d9 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 4 Apr 2024 10:31:25 +0300 Subject: iio: light: apds9306: Fix off by one in apds9306_sampling_freq_get() The > comparison needs to be >= to prevent an out of bounds access. Fixes: 620d1e6c7a3f ("iio: light: Add support for APDS9306 Light Sensor") Signed-off-by: Dan Carpenter Reviewed-by: Subhajit Ghosh Link: https://lore.kernel.org/r/69c5cb83-0209-40ff-a276-a0ae5e81c528@moroto.mountain Signed-off-by: Jonathan Cameron --- drivers/iio/light/apds9306.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/light/apds9306.c b/drivers/iio/light/apds9306.c index 4d8490602cd7..49fa6b7d5170 100644 --- a/drivers/iio/light/apds9306.c +++ b/drivers/iio/light/apds9306.c @@ -635,7 +635,7 @@ static int apds9306_sampling_freq_get(struct apds9306_data *data, int *val, if (ret) return ret; - if (repeat_rate_idx > ARRAY_SIZE(apds9306_repeat_rate_freq)) + if (repeat_rate_idx >= ARRAY_SIZE(apds9306_repeat_rate_freq)) return -EINVAL; *val = apds9306_repeat_rate_freq[repeat_rate_idx][0]; -- cgit v1.2.3-59-g8ed1b From 107585b06926aac6b36e466d4c6f05c520bb0f41 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 4 Apr 2024 10:31:32 +0300 Subject: iio: adc: ad7173: Fix ! vs ~ typo in ad7173_sel_clk() This was obviously supposed to be a bitwise negate instead of logical. Fixes: 76a1e6a42802 ("iio: adc: ad7173: add AD7173 driver") Signed-off-by: Dan Carpenter Reviewed-by: Nuno Sa Link: https://lore.kernel.org/r/5401c681-c4aa-4fab-8c8c-8f0a379e2687@moroto.mountain Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7173.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/adc/ad7173.c b/drivers/iio/adc/ad7173.c index f6d29abe1d04..a7826bba0852 100644 --- a/drivers/iio/adc/ad7173.c +++ b/drivers/iio/adc/ad7173.c @@ -835,7 +835,7 @@ static unsigned long ad7173_sel_clk(struct ad7173_state *st, { int ret; - st->adc_mode &= !AD7173_ADC_MODE_CLOCKSEL_MASK; + st->adc_mode &= ~AD7173_ADC_MODE_CLOCKSEL_MASK; st->adc_mode |= FIELD_PREP(AD7173_ADC_MODE_CLOCKSEL_MASK, clk_sel); ret = ad_sd_write_reg(&st->sd, AD7173_REG_ADC_MODE, 0x2, st->adc_mode); -- cgit v1.2.3-59-g8ed1b From f979e52d3bc136b4ef1351479464c54a7c81c934 Mon Sep 17 00:00:00 2001 From: Nuno Sa Date: Thu, 4 Apr 2024 10:58:17 +0200 Subject: dt-bindings: iio: temperature: ltc2983: document power supply Add a property for the VDD power supply regulator. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Nuno Sa Link: https://lore.kernel.org/r/20240404-ltc2983-misc-improv-v5-1-c1f58057fcea@analog.com Signed-off-by: Jonathan Cameron --- Documentation/devicetree/bindings/iio/temperature/adi,ltc2983.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/devicetree/bindings/iio/temperature/adi,ltc2983.yaml b/Documentation/devicetree/bindings/iio/temperature/adi,ltc2983.yaml index dbb85135fd66..312febeeb3bb 100644 --- a/Documentation/devicetree/bindings/iio/temperature/adi,ltc2983.yaml +++ b/Documentation/devicetree/bindings/iio/temperature/adi,ltc2983.yaml @@ -57,6 +57,8 @@ properties: interrupts: maxItems: 1 + vdd-supply: true + adi,mux-delay-config-us: description: | Extra delay prior to each conversion, in addition to the internal 1ms @@ -460,6 +462,7 @@ required: - compatible - reg - interrupts + - vdd-supply additionalProperties: false @@ -489,6 +492,7 @@ examples: #address-cells = <1>; #size-cells = <0>; + vdd-supply = <&supply>; interrupts = <20 IRQ_TYPE_EDGE_RISING>; interrupt-parent = <&gpio>; -- cgit v1.2.3-59-g8ed1b From 47ef0501a9cc25c88dcac2b57ed3bab4da53f3d5 Mon Sep 17 00:00:00 2001 From: Nuno Sa Date: Thu, 4 Apr 2024 10:58:18 +0200 Subject: iio: temperature: ltc2983: support vdd regulator Add support for the power supply regulator. Signed-off-by: Nuno Sa Link: https://lore.kernel.org/r/20240404-ltc2983-misc-improv-v5-2-c1f58057fcea@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/temperature/ltc2983.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/iio/temperature/ltc2983.c b/drivers/iio/temperature/ltc2983.c index 3c4524d57b8e..24d19f3c7292 100644 --- a/drivers/iio/temperature/ltc2983.c +++ b/drivers/iio/temperature/ltc2983.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -1597,6 +1598,10 @@ static int ltc2983_probe(struct spi_device *spi) if (ret) return ret; + ret = devm_regulator_get_enable(&spi->dev, "vdd"); + if (ret) + return ret; + gpio = devm_gpiod_get_optional(&st->spi->dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(gpio)) return PTR_ERR(gpio); -- cgit v1.2.3-59-g8ed1b From 85795d3eddeb5f0e3e11caad24cc78f6c43d7fd1 Mon Sep 17 00:00:00 2001 From: Subhajit Ghosh Date: Fri, 5 Apr 2024 21:16:41 +1030 Subject: iio: light: apds9306: Improve apds9306_write_event_config() Simplify event configuration flow. Suggested-by: Jonathan Cameron Link: https://lore.kernel.org/all/20240310124237.52fa8a56@jic23-huawei/ Signed-off-by: Subhajit Ghosh Link: https://lore.kernel.org/r/20240405104641.29478-1-subhajit.ghosh@tweaklogic.com Signed-off-by: Jonathan Cameron --- drivers/iio/light/apds9306.c | 48 +++++++++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 21 deletions(-) diff --git a/drivers/iio/light/apds9306.c b/drivers/iio/light/apds9306.c index 49fa6b7d5170..46c647ccd44c 100644 --- a/drivers/iio/light/apds9306.c +++ b/drivers/iio/light/apds9306.c @@ -1075,14 +1075,16 @@ static int apds9306_write_event_config(struct iio_dev *indio_dev, { struct apds9306_data *data = iio_priv(indio_dev); struct apds9306_regfields *rf = &data->rf; - int ret, val; - - state = !!state; + int ret, enabled; switch (type) { case IIO_EV_TYPE_THRESH: { guard(mutex)(&data->mutex); + ret = regmap_field_read(rf->int_en, &enabled); + if (ret) + return ret; + /* * If interrupt is enabled, the channel is set before enabling * the interrupt. In case of disable, no need to switch @@ -1091,38 +1093,42 @@ static int apds9306_write_event_config(struct iio_dev *indio_dev, */ if (state) { if (chan->type == IIO_LIGHT) - val = 1; + ret = regmap_field_write(rf->int_src, 1); else if (chan->type == IIO_INTENSITY) - val = 0; + ret = regmap_field_write(rf->int_src, 0); else return -EINVAL; - ret = regmap_field_write(rf->int_src, val); if (ret) return ret; - } - ret = regmap_field_read(rf->int_en, &val); - if (ret) - return ret; - - if (val == state) - return 0; + if (enabled) + return 0; - ret = regmap_field_write(rf->int_en, state); - if (ret) - return ret; + ret = regmap_field_write(rf->int_en, 1); + if (ret) + return ret; - if (state) return pm_runtime_resume_and_get(data->dev); + } else { + if (!enabled) + return 0; - pm_runtime_mark_last_busy(data->dev); - pm_runtime_put_autosuspend(data->dev); + ret = regmap_field_write(rf->int_en, 0); + if (ret) + return ret; - return 0; + pm_runtime_mark_last_busy(data->dev); + pm_runtime_put_autosuspend(data->dev); + + return 0; + } } case IIO_EV_TYPE_THRESH_ADAPTIVE: - return regmap_field_write(rf->int_thresh_var_en, state); + if (state) + return regmap_field_write(rf->int_thresh_var_en, 1); + else + return regmap_field_write(rf->int_thresh_var_en, 0); default: return -EINVAL; } -- cgit v1.2.3-59-g8ed1b From aabc0aa90c927a03d509d0b592720d9897894ce4 Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Sat, 6 Apr 2024 17:31:04 +0200 Subject: Documentation: ABI: document in_temp_input file For example the BMP280 barometric pressure sensor on Qualcomm MSM8974-based Nexus 5 smartphone exposes such file in sysfs. Document it. Whilst here, fix up incorrect repeated use of X as a wildcard for in_tempY_input. Signed-off-by: Luca Weiss Link: https://lore.kernel.org/r/20240406-in_temp_input-v1-1-a1744a4a49e3@z3ntu.xyz Signed-off-by: Jonathan Cameron --- Documentation/ABI/testing/sysfs-bus-iio | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index 2e6d5ebfd3c7..7cee78ad4108 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -243,7 +243,8 @@ Description: less measurements. Units after application of scale and offset are milli degrees Celsius. -What: /sys/bus/iio/devices/iio:deviceX/in_tempX_input +What: /sys/bus/iio/devices/iio:deviceX/in_tempY_input +What: /sys/bus/iio/devices/iio:deviceX/in_temp_input KernelVersion: 2.6.38 Contact: linux-iio@vger.kernel.org Description: -- cgit v1.2.3-59-g8ed1b From 469ad583c1293f5d9f45183050b3beeb4a8c3475 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 7 Apr 2024 03:04:50 -0400 Subject: erofs: switch erofs_bread() to passing offset instead of block number Callers are happier that way, especially since we no longer need to play with splitting offset into block number and offset within block, passing the former to erofs_bread(), then adding the latter... erofs_bread() always reads entire pages, anyway. Signed-off-by: Al Viro --- fs/erofs/data.c | 5 ++--- fs/erofs/dir.c | 2 +- fs/erofs/internal.h | 2 +- fs/erofs/namei.c | 2 +- fs/erofs/super.c | 8 ++++---- fs/erofs/xattr.c | 35 +++++++++++++---------------------- fs/erofs/zdata.c | 4 ++-- 7 files changed, 24 insertions(+), 34 deletions(-) diff --git a/fs/erofs/data.c b/fs/erofs/data.c index 52524bd9698b..d3c446dda2ff 100644 --- a/fs/erofs/data.c +++ b/fs/erofs/data.c @@ -29,11 +29,10 @@ void erofs_put_metabuf(struct erofs_buf *buf) * Derive the block size from inode->i_blkbits to make compatible with * anonymous inode in fscache mode. */ -void *erofs_bread(struct erofs_buf *buf, erofs_blk_t blkaddr, +void *erofs_bread(struct erofs_buf *buf, erofs_off_t offset, enum erofs_kmap_type type) { struct inode *inode = buf->inode; - erofs_off_t offset = (erofs_off_t)blkaddr << inode->i_blkbits; pgoff_t index = offset >> PAGE_SHIFT; struct page *page = buf->page; struct folio *folio; @@ -77,7 +76,7 @@ void *erofs_read_metabuf(struct erofs_buf *buf, struct super_block *sb, erofs_blk_t blkaddr, enum erofs_kmap_type type) { erofs_init_metabuf(buf, sb); - return erofs_bread(buf, blkaddr, type); + return erofs_bread(buf, erofs_pos(sb, blkaddr), type); } static int erofs_map_blocks_flatmode(struct inode *inode, diff --git a/fs/erofs/dir.c b/fs/erofs/dir.c index b80abec0531a..9d38f39bb4f7 100644 --- a/fs/erofs/dir.c +++ b/fs/erofs/dir.c @@ -63,7 +63,7 @@ static int erofs_readdir(struct file *f, struct dir_context *ctx) struct erofs_dirent *de; unsigned int nameoff, maxsize; - de = erofs_bread(&buf, i, EROFS_KMAP); + de = erofs_bread(&buf, erofs_pos(sb, i), EROFS_KMAP); if (IS_ERR(de)) { erofs_err(sb, "fail to readdir of logical block %u of nid %llu", i, EROFS_I(dir)->nid); diff --git a/fs/erofs/internal.h b/fs/erofs/internal.h index 39c67119f43b..9e30c67c135c 100644 --- a/fs/erofs/internal.h +++ b/fs/erofs/internal.h @@ -409,7 +409,7 @@ void *erofs_read_metadata(struct super_block *sb, struct erofs_buf *buf, erofs_off_t *offset, int *lengthp); void erofs_unmap_metabuf(struct erofs_buf *buf); void erofs_put_metabuf(struct erofs_buf *buf); -void *erofs_bread(struct erofs_buf *buf, erofs_blk_t blkaddr, +void *erofs_bread(struct erofs_buf *buf, erofs_off_t offset, enum erofs_kmap_type type); void erofs_init_metabuf(struct erofs_buf *buf, struct super_block *sb); void *erofs_read_metabuf(struct erofs_buf *buf, struct super_block *sb, diff --git a/fs/erofs/namei.c b/fs/erofs/namei.c index f0110a78acb2..11afa48996a3 100644 --- a/fs/erofs/namei.c +++ b/fs/erofs/namei.c @@ -100,7 +100,7 @@ static void *erofs_find_target_block(struct erofs_buf *target, struct erofs_dirent *de; buf.inode = dir; - de = erofs_bread(&buf, mid, EROFS_KMAP); + de = erofs_bread(&buf, erofs_pos(dir->i_sb, mid), EROFS_KMAP); if (!IS_ERR(de)) { const int nameoff = nameoff_from_disk(de->nameoff, bsz); const int ndirents = nameoff / sizeof(*de); diff --git a/fs/erofs/super.c b/fs/erofs/super.c index c0eb139adb07..fdefc3772620 100644 --- a/fs/erofs/super.c +++ b/fs/erofs/super.c @@ -132,11 +132,11 @@ void *erofs_read_metadata(struct super_block *sb, struct erofs_buf *buf, int len, i, cnt; *offset = round_up(*offset, 4); - ptr = erofs_bread(buf, erofs_blknr(sb, *offset), EROFS_KMAP); + ptr = erofs_bread(buf, *offset, EROFS_KMAP); if (IS_ERR(ptr)) return ptr; - len = le16_to_cpu(*(__le16 *)&ptr[erofs_blkoff(sb, *offset)]); + len = le16_to_cpu(*(__le16 *)ptr); if (!len) len = U16_MAX + 1; buffer = kmalloc(len, GFP_KERNEL); @@ -148,12 +148,12 @@ void *erofs_read_metadata(struct super_block *sb, struct erofs_buf *buf, for (i = 0; i < len; i += cnt) { cnt = min_t(int, sb->s_blocksize - erofs_blkoff(sb, *offset), len - i); - ptr = erofs_bread(buf, erofs_blknr(sb, *offset), EROFS_KMAP); + ptr = erofs_bread(buf, *offset, EROFS_KMAP); if (IS_ERR(ptr)) { kfree(buffer); return ptr; } - memcpy(buffer + i, ptr + erofs_blkoff(sb, *offset), cnt); + memcpy(buffer + i, ptr, cnt); *offset += cnt; } return buffer; diff --git a/fs/erofs/xattr.c b/fs/erofs/xattr.c index b58316b49a43..ec233917830a 100644 --- a/fs/erofs/xattr.c +++ b/fs/erofs/xattr.c @@ -81,13 +81,13 @@ static int erofs_init_inode_xattrs(struct inode *inode) it.pos = erofs_iloc(inode) + vi->inode_isize; /* read in shared xattr array (non-atomic, see kmalloc below) */ - it.kaddr = erofs_bread(&it.buf, erofs_blknr(sb, it.pos), EROFS_KMAP); + it.kaddr = erofs_bread(&it.buf, it.pos, EROFS_KMAP); if (IS_ERR(it.kaddr)) { ret = PTR_ERR(it.kaddr); goto out_unlock; } - ih = it.kaddr + erofs_blkoff(sb, it.pos); + ih = it.kaddr; vi->xattr_name_filter = le32_to_cpu(ih->h_name_filter); vi->xattr_shared_count = ih->h_shared_count; vi->xattr_shared_xattrs = kmalloc_array(vi->xattr_shared_count, @@ -102,16 +102,14 @@ static int erofs_init_inode_xattrs(struct inode *inode) it.pos += sizeof(struct erofs_xattr_ibody_header); for (i = 0; i < vi->xattr_shared_count; ++i) { - it.kaddr = erofs_bread(&it.buf, erofs_blknr(sb, it.pos), - EROFS_KMAP); + it.kaddr = erofs_bread(&it.buf, it.pos, EROFS_KMAP); if (IS_ERR(it.kaddr)) { kfree(vi->xattr_shared_xattrs); vi->xattr_shared_xattrs = NULL; ret = PTR_ERR(it.kaddr); goto out_unlock; } - vi->xattr_shared_xattrs[i] = le32_to_cpu(*(__le32 *) - (it.kaddr + erofs_blkoff(sb, it.pos))); + vi->xattr_shared_xattrs[i] = le32_to_cpu(*(__le32 *)it.kaddr); it.pos += sizeof(__le32); } erofs_put_metabuf(&it.buf); @@ -185,12 +183,11 @@ static int erofs_xattr_copy_to_buffer(struct erofs_xattr_iter *it, void *src; for (processed = 0; processed < len; processed += slice) { - it->kaddr = erofs_bread(&it->buf, erofs_blknr(sb, it->pos), - EROFS_KMAP); + it->kaddr = erofs_bread(&it->buf, it->pos, EROFS_KMAP); if (IS_ERR(it->kaddr)) return PTR_ERR(it->kaddr); - src = it->kaddr + erofs_blkoff(sb, it->pos); + src = it->kaddr; slice = min_t(unsigned int, sb->s_blocksize - erofs_blkoff(sb, it->pos), len - processed); memcpy(it->buffer + it->buffer_ofs, src, slice); @@ -208,8 +205,7 @@ static int erofs_listxattr_foreach(struct erofs_xattr_iter *it) int err; /* 1. handle xattr entry */ - entry = *(struct erofs_xattr_entry *) - (it->kaddr + erofs_blkoff(it->sb, it->pos)); + entry = *(struct erofs_xattr_entry *)it->kaddr; it->pos += sizeof(struct erofs_xattr_entry); base_index = entry.e_name_index; @@ -259,8 +255,7 @@ static int erofs_getxattr_foreach(struct erofs_xattr_iter *it) unsigned int slice, processed, value_sz; /* 1. handle xattr entry */ - entry = *(struct erofs_xattr_entry *) - (it->kaddr + erofs_blkoff(sb, it->pos)); + entry = *(struct erofs_xattr_entry *)it->kaddr; it->pos += sizeof(struct erofs_xattr_entry); value_sz = le16_to_cpu(entry.e_value_size); @@ -291,8 +286,7 @@ static int erofs_getxattr_foreach(struct erofs_xattr_iter *it) /* 2. handle xattr name */ for (processed = 0; processed < entry.e_name_len; processed += slice) { - it->kaddr = erofs_bread(&it->buf, erofs_blknr(sb, it->pos), - EROFS_KMAP); + it->kaddr = erofs_bread(&it->buf, it->pos, EROFS_KMAP); if (IS_ERR(it->kaddr)) return PTR_ERR(it->kaddr); @@ -300,7 +294,7 @@ static int erofs_getxattr_foreach(struct erofs_xattr_iter *it) sb->s_blocksize - erofs_blkoff(sb, it->pos), entry.e_name_len - processed); if (memcmp(it->name.name + it->infix_len + processed, - it->kaddr + erofs_blkoff(sb, it->pos), slice)) + it->kaddr, slice)) return -ENOATTR; it->pos += slice; } @@ -336,13 +330,11 @@ static int erofs_xattr_iter_inline(struct erofs_xattr_iter *it, it->pos = erofs_iloc(inode) + vi->inode_isize + xattr_header_sz; while (remaining) { - it->kaddr = erofs_bread(&it->buf, erofs_blknr(it->sb, it->pos), - EROFS_KMAP); + it->kaddr = erofs_bread(&it->buf, it->pos, EROFS_KMAP); if (IS_ERR(it->kaddr)) return PTR_ERR(it->kaddr); - entry_sz = erofs_xattr_entry_size(it->kaddr + - erofs_blkoff(it->sb, it->pos)); + entry_sz = erofs_xattr_entry_size(it->kaddr); /* xattr on-disk corruption: xattr entry beyond xattr_isize */ if (remaining < entry_sz) { DBG_BUGON(1); @@ -375,8 +367,7 @@ static int erofs_xattr_iter_shared(struct erofs_xattr_iter *it, for (i = 0; i < vi->xattr_shared_count; ++i) { it->pos = erofs_pos(sb, sbi->xattr_blkaddr) + vi->xattr_shared_xattrs[i] * sizeof(__le32); - it->kaddr = erofs_bread(&it->buf, erofs_blknr(sb, it->pos), - EROFS_KMAP); + it->kaddr = erofs_bread(&it->buf, it->pos, EROFS_KMAP); if (IS_ERR(it->kaddr)) return PTR_ERR(it->kaddr); diff --git a/fs/erofs/zdata.c b/fs/erofs/zdata.c index 3216b920d369..9ffdae7fcd5b 100644 --- a/fs/erofs/zdata.c +++ b/fs/erofs/zdata.c @@ -940,12 +940,12 @@ static int z_erofs_read_fragment(struct super_block *sb, struct page *page, for (; cur < end; cur += cnt, pos += cnt) { cnt = min_t(unsigned int, end - cur, sb->s_blocksize - erofs_blkoff(sb, pos)); - src = erofs_bread(&buf, erofs_blknr(sb, pos), EROFS_KMAP); + src = erofs_bread(&buf, pos, EROFS_KMAP); if (IS_ERR(src)) { erofs_put_metabuf(&buf); return PTR_ERR(src); } - memcpy_to_page(page, cur, src + erofs_blkoff(sb, pos), cnt); + memcpy_to_page(page, cur, src, cnt); } erofs_put_metabuf(&buf); return 0; -- cgit v1.2.3-59-g8ed1b From c863062cf8250d8330859fc1d730b2aed3313bcd Mon Sep 17 00:00:00 2001 From: Jerry Snitselaar Date: Fri, 5 Apr 2024 14:39:41 -0700 Subject: dmaengine: idxd: Check for driver name match before sva user feature Currently if the user driver is probed on a workqueue configured for another driver with SVA not enabled on the system, it will print out a number of probe failing messages like the following: [ 264.831140] user: probe of wq13.0 failed with error -95 On some systems, such as GNR, the number of messages can reach over 100. Move the SVA feature check to be after the driver name match check. Cc: Vinod Koul Cc: dmaengine@vger.kernel.org Cc: linux-kernel@vger.kernel.org Reviewed-by: Fenghua Yu Reviewed-by: Dave Jiang Signed-off-by: Jerry Snitselaar Link: https://lore.kernel.org/r/20240405213941.3629709-1-jsnitsel@redhat.com Signed-off-by: Vinod Koul --- drivers/dma/idxd/cdev.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/dma/idxd/cdev.c b/drivers/dma/idxd/cdev.c index 8078ab9acfbc..a4b771781afc 100644 --- a/drivers/dma/idxd/cdev.c +++ b/drivers/dma/idxd/cdev.c @@ -517,6 +517,14 @@ static int idxd_user_drv_probe(struct idxd_dev *idxd_dev) if (idxd->state != IDXD_DEV_ENABLED) return -ENXIO; + mutex_lock(&wq->wq_lock); + + if (!idxd_wq_driver_name_match(wq, dev)) { + idxd->cmd_status = IDXD_SCMD_WQ_NO_DRV_NAME; + rc = -ENODEV; + goto wq_err; + } + /* * User type WQ is enabled only when SVA is enabled for two reasons: * - If no IOMMU or IOMMU Passthrough without SVA, userspace @@ -532,14 +540,7 @@ static int idxd_user_drv_probe(struct idxd_dev *idxd_dev) dev_dbg(&idxd->pdev->dev, "User type WQ cannot be enabled without SVA.\n"); - return -EOPNOTSUPP; - } - - mutex_lock(&wq->wq_lock); - - if (!idxd_wq_driver_name_match(wq, dev)) { - idxd->cmd_status = IDXD_SCMD_WQ_NO_DRV_NAME; - rc = -ENODEV; + rc = -EOPNOTSUPP; goto wq_err; } -- cgit v1.2.3-59-g8ed1b From 2b1c1cf08a0addb6df42f16b37133dc7a351de29 Mon Sep 17 00:00:00 2001 From: Chen Ni Date: Wed, 3 Apr 2024 02:49:32 +0000 Subject: dmaengine: idma64: Add check for dma_set_max_seg_size As the possible failure of the dma_set_max_seg_size(), it should be better to check the return value of the dma_set_max_seg_size(). Fixes: e3fdb1894cfa ("dmaengine: idma64: set maximum allowed segment size for DMA") Signed-off-by: Chen Ni Acked-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240403024932.3342606-1-nichen@iscas.ac.cn Signed-off-by: Vinod Koul --- drivers/dma/idma64.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/dma/idma64.c b/drivers/dma/idma64.c index 78a938969d7d..58ac374efa3b 100644 --- a/drivers/dma/idma64.c +++ b/drivers/dma/idma64.c @@ -594,7 +594,9 @@ static int idma64_probe(struct idma64_chip *chip) idma64->dma.dev = chip->sysdev; - dma_set_max_seg_size(idma64->dma.dev, IDMA64C_CTLH_BLOCK_TS_MASK); + ret = dma_set_max_seg_size(idma64->dma.dev, IDMA64C_CTLH_BLOCK_TS_MASK); + if (ret) + return ret; ret = dma_async_device_register(&idma64->dma); if (ret) -- cgit v1.2.3-59-g8ed1b From 7eccb5a5b224be42431c8087c9c9e016636ff3b5 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 1 Apr 2024 15:43:53 -0500 Subject: dt-bindings: dma: snps,dma-spear1340: Fix data{-,_}width schema 'data-width' and 'data_width' properties are defined as arrays, but the schema is defined as a matrix. That works currently since everything gets decoded in to matrices, but that is internal to dtschema and could change. Acked-by: Viresh Kumar Reviewed-by: Serge Semin Signed-off-by: Rob Herring Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20240401204354.1691845-1-robh@kernel.org Signed-off-by: Vinod Koul --- .../bindings/dma/snps,dma-spear1340.yaml | 42 +++++++++++----------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/Documentation/devicetree/bindings/dma/snps,dma-spear1340.yaml b/Documentation/devicetree/bindings/dma/snps,dma-spear1340.yaml index 5da8291a7de0..c21a4f073f6c 100644 --- a/Documentation/devicetree/bindings/dma/snps,dma-spear1340.yaml +++ b/Documentation/devicetree/bindings/dma/snps,dma-spear1340.yaml @@ -93,10 +93,10 @@ properties: data-width: $ref: /schemas/types.yaml#/definitions/uint32-array description: Data bus width per each DMA master in bytes. + minItems: 1 + maxItems: 4 items: - maxItems: 4 - items: - enum: [4, 8, 16, 32] + enum: [4, 8, 16, 32] data_width: $ref: /schemas/types.yaml#/definitions/uint32-array @@ -106,28 +106,28 @@ properties: deprecated. It' usage is discouraged in favor of data-width one. Moreover the property incorrectly permits to define data-bus width of 8 and 16 bits, which is impossible in accordance with DW DMAC IP-core data book. + minItems: 1 + maxItems: 4 items: - maxItems: 4 - items: - enum: - - 0 # 8 bits - - 1 # 16 bits - - 2 # 32 bits - - 3 # 64 bits - - 4 # 128 bits - - 5 # 256 bits - default: 0 + enum: + - 0 # 8 bits + - 1 # 16 bits + - 2 # 32 bits + - 3 # 64 bits + - 4 # 128 bits + - 5 # 256 bits + default: 0 multi-block: $ref: /schemas/types.yaml#/definitions/uint32-array description: | LLP-based multi-block transfer supported by hardware per each DMA channel. + minItems: 1 + maxItems: 8 items: - maxItems: 8 - items: - enum: [0, 1] - default: 1 + enum: [0, 1] + default: 1 snps,max-burst-len: $ref: /schemas/types.yaml#/definitions/uint32-array @@ -138,11 +138,11 @@ properties: will be from 1 to max-burst-len words. It's an array property with one cell per channel in the units determined by the value set in the CTLx.SRC_TR_WIDTH/CTLx.DST_TR_WIDTH fields (data width). + minItems: 1 + maxItems: 8 items: - maxItems: 8 - items: - enum: [4, 8, 16, 32, 64, 128, 256] - default: 256 + enum: [4, 8, 16, 32, 64, 128, 256] + default: 256 snps,dma-protection-control: $ref: /schemas/types.yaml#/definitions/uint32 -- cgit v1.2.3-59-g8ed1b From 802ef223101fec83d92e045f89000b228904a580 Mon Sep 17 00:00:00 2001 From: Nicolin Chen Date: Fri, 29 Mar 2024 10:34:41 -0400 Subject: dmaengine: imx-sdma: Support allocate memory from internal SRAM (iram) Allocate memory from SoC internal SRAM to reduce DDR access and keep DDR in lower power state (such as self-referesh) longer. Check iram_pool before sdma_init() so that ccb/context could be allocated from iram because DDR maybe in self-referesh in lower power audio case while sdma still running. Reviewed-by: Shengjiu Wang Signed-off-by: Nicolin Chen Signed-off-by: Joy Zou Reviewed-by: Daniel Baluta Signed-off-by: Frank Li Link: https://lore.kernel.org/r/20240329-sdma_upstream-v4-1-daeb3067dea7@nxp.com Signed-off-by: Vinod Koul --- drivers/dma/imx-sdma.c | 46 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 36 insertions(+), 10 deletions(-) diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index 9b42f5e96b1e..4f1a9d1b152d 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -531,6 +532,7 @@ struct sdma_engine { /* clock ratio for AHB:SDMA core. 1:1 is 1, 2:1 is 0*/ bool clk_ratio; bool fw_loaded; + struct gen_pool *iram_pool; }; static int sdma_config_write(struct dma_chan *chan, @@ -1358,8 +1360,14 @@ static int sdma_request_channel0(struct sdma_engine *sdma) { int ret = -EBUSY; - sdma->bd0 = dma_alloc_coherent(sdma->dev, PAGE_SIZE, &sdma->bd0_phys, - GFP_NOWAIT); + if (sdma->iram_pool) + sdma->bd0 = gen_pool_dma_alloc(sdma->iram_pool, + sizeof(struct sdma_buffer_descriptor), + &sdma->bd0_phys); + else + sdma->bd0 = dma_alloc_coherent(sdma->dev, + sizeof(struct sdma_buffer_descriptor), + &sdma->bd0_phys, GFP_NOWAIT); if (!sdma->bd0) { ret = -ENOMEM; goto out; @@ -1379,10 +1387,14 @@ out: static int sdma_alloc_bd(struct sdma_desc *desc) { u32 bd_size = desc->num_bd * sizeof(struct sdma_buffer_descriptor); + struct sdma_engine *sdma = desc->sdmac->sdma; int ret = 0; - desc->bd = dma_alloc_coherent(desc->sdmac->sdma->dev, bd_size, - &desc->bd_phys, GFP_NOWAIT); + if (sdma->iram_pool) + desc->bd = gen_pool_dma_alloc(sdma->iram_pool, bd_size, &desc->bd_phys); + else + desc->bd = dma_alloc_coherent(sdma->dev, bd_size, &desc->bd_phys, GFP_NOWAIT); + if (!desc->bd) { ret = -ENOMEM; goto out; @@ -1394,9 +1406,12 @@ out: static void sdma_free_bd(struct sdma_desc *desc) { u32 bd_size = desc->num_bd * sizeof(struct sdma_buffer_descriptor); + struct sdma_engine *sdma = desc->sdmac->sdma; - dma_free_coherent(desc->sdmac->sdma->dev, bd_size, desc->bd, - desc->bd_phys); + if (sdma->iram_pool) + gen_pool_free(sdma->iram_pool, (unsigned long)desc->bd, bd_size); + else + dma_free_coherent(desc->sdmac->sdma->dev, bd_size, desc->bd, desc->bd_phys); } static void sdma_desc_free(struct virt_dma_desc *vd) @@ -2068,6 +2083,7 @@ static int sdma_init(struct sdma_engine *sdma) { int i, ret; dma_addr_t ccb_phys; + int ccbsize; ret = clk_enable(sdma->clk_ipg); if (ret) @@ -2083,10 +2099,14 @@ static int sdma_init(struct sdma_engine *sdma) /* Be sure SDMA has not started yet */ writel_relaxed(0, sdma->regs + SDMA_H_C0PTR); - sdma->channel_control = dma_alloc_coherent(sdma->dev, - MAX_DMA_CHANNELS * sizeof(struct sdma_channel_control) + - sizeof(struct sdma_context_data), - &ccb_phys, GFP_KERNEL); + ccbsize = MAX_DMA_CHANNELS * (sizeof(struct sdma_channel_control) + + sizeof(struct sdma_context_data)); + + if (sdma->iram_pool) + sdma->channel_control = gen_pool_dma_alloc(sdma->iram_pool, ccbsize, &ccb_phys); + else + sdma->channel_control = dma_alloc_coherent(sdma->dev, ccbsize, &ccb_phys, + GFP_KERNEL); if (!sdma->channel_control) { ret = -ENOMEM; @@ -2272,6 +2292,12 @@ static int sdma_probe(struct platform_device *pdev) vchan_init(&sdmac->vc, &sdma->dma_device); } + if (np) { + sdma->iram_pool = of_gen_pool_get(np, "iram", 0); + if (sdma->iram_pool) + dev_info(&pdev->dev, "alloc bd from iram.\n"); + } + ret = sdma_init(sdma); if (ret) goto err_init; -- cgit v1.2.3-59-g8ed1b From 288109387becd8abadca5c063c70a07ae0dd7716 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Fri, 29 Mar 2024 10:34:42 -0400 Subject: dmaengine: imx-sdma: Support 24bit/3bytes for sg mode Update 3bytes buswidth that is supported by sdma. Signed-off-by: Shengjiu Wang Signed-off-by: Vipul Kumar Signed-off-by: Srikanth Krishnakar Acked-by: Robin Gong Reviewed-by: Joy Zou Reviewed-by: Daniel Baluta Signed-off-by: Frank Li Link: https://lore.kernel.org/r/20240329-sdma_upstream-v4-2-daeb3067dea7@nxp.com Signed-off-by: Vinod Koul --- drivers/dma/imx-sdma.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index 4f1a9d1b152d..6be4c1e44126 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c @@ -176,6 +176,7 @@ #define SDMA_DMA_BUSWIDTHS (BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | \ BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | \ + BIT(DMA_SLAVE_BUSWIDTH_3_BYTES) | \ BIT(DMA_SLAVE_BUSWIDTH_4_BYTES)) #define SDMA_DMA_DIRECTIONS (BIT(DMA_DEV_TO_MEM) | \ @@ -1658,6 +1659,9 @@ static struct dma_async_tx_descriptor *sdma_prep_slave_sg( if (count & 3 || sg->dma_address & 3) goto err_bd_out; break; + case DMA_SLAVE_BUSWIDTH_3_BYTES: + bd->mode.command = 3; + break; case DMA_SLAVE_BUSWIDTH_2_BYTES: bd->mode.command = 2; if (count & 1 || sg->dma_address & 1) -- cgit v1.2.3-59-g8ed1b From a20f10d6accb9f5096fa7a7296e5ae34f4562440 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Fri, 29 Mar 2024 10:34:43 -0400 Subject: dmaengine: imx-sdma: support dual fifo for DEV_TO_DEV SSI and SPDIF are dual fifo interface, when support ASRC P2P with SSI and SPDIF, the src fifo or dst fifo number can be two. The p2p watermark level bit 13 and 14 are designed for these use case. This patch is to complete this function in driver. Signed-off-by: Shengjiu Wang Signed-off-by: Joy Zou Acked-by: Iuliana Prodan Signed-off-by: Frank Li Link: https://lore.kernel.org/r/20240329-sdma_upstream-v4-3-daeb3067dea7@nxp.com Signed-off-by: Vinod Koul --- drivers/dma/imx-sdma.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index 6be4c1e44126..f68ab34a3c88 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c @@ -138,7 +138,11 @@ * 0: Source on AIPS * 12 Destination Bit(DP) 1: Destination on SPBA * 0: Destination on AIPS - * 13-15 --------- MUST BE 0 + * 13 Source FIFO 1: Source is dual FIFO + * 0: Source is single FIFO + * 14 Destination FIFO 1: Destination is dual FIFO + * 0: Destination is single FIFO + * 15 --------- MUST BE 0 * 16-23 Higher WML HWML * 24-27 N Total number of samples after * which Pad adding/Swallowing @@ -169,6 +173,8 @@ #define SDMA_WATERMARK_LEVEL_SPDIF BIT(10) #define SDMA_WATERMARK_LEVEL_SP BIT(11) #define SDMA_WATERMARK_LEVEL_DP BIT(12) +#define SDMA_WATERMARK_LEVEL_SD BIT(13) +#define SDMA_WATERMARK_LEVEL_DD BIT(14) #define SDMA_WATERMARK_LEVEL_HWML (0xFF << 16) #define SDMA_WATERMARK_LEVEL_LWE BIT(28) #define SDMA_WATERMARK_LEVEL_HWE BIT(29) @@ -1258,6 +1264,16 @@ static void sdma_set_watermarklevel_for_p2p(struct sdma_channel *sdmac) sdmac->watermark_level |= SDMA_WATERMARK_LEVEL_DP; sdmac->watermark_level |= SDMA_WATERMARK_LEVEL_CONT; + + /* + * Limitation: The p2p script support dual fifos in maximum, + * So when fifo number is larger than 1, force enable dual + * fifos. + */ + if (sdmac->n_fifos_src > 1) + sdmac->watermark_level |= SDMA_WATERMARK_LEVEL_SD; + if (sdmac->n_fifos_dst > 1) + sdmac->watermark_level |= SDMA_WATERMARK_LEVEL_DD; } static void sdma_set_watermarklevel_for_sais(struct sdma_channel *sdmac) -- cgit v1.2.3-59-g8ed1b From 28ccf02caa199e02a6fbf605496bfb9ee73f872c Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Fri, 8 Mar 2024 16:00:33 -0500 Subject: dma: xilinx_dpdma: Remove unnecessary use of irqsave/restore xilinx_dpdma_chan_done_irq and xilinx_dpdma_chan_vsync_irq are always called with IRQs disabled from xilinx_dpdma_irq_handler. Therefore we don't need to save/restore the IRQ flags. Signed-off-by: Sean Anderson Reviewed-by: Tomi Valkeinen Link: https://lore.kernel.org/r/20240308210034.3634938-3-sean.anderson@linux.dev Signed-off-by: Vinod Koul --- drivers/dma/xilinx/xilinx_dpdma.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/dma/xilinx/xilinx_dpdma.c b/drivers/dma/xilinx/xilinx_dpdma.c index b82815e64d24..bc27a0ca86af 100644 --- a/drivers/dma/xilinx/xilinx_dpdma.c +++ b/drivers/dma/xilinx/xilinx_dpdma.c @@ -1042,9 +1042,8 @@ static int xilinx_dpdma_chan_stop(struct xilinx_dpdma_chan *chan) static void xilinx_dpdma_chan_done_irq(struct xilinx_dpdma_chan *chan) { struct xilinx_dpdma_tx_desc *active; - unsigned long flags; - spin_lock_irqsave(&chan->lock, flags); + spin_lock(&chan->lock); xilinx_dpdma_debugfs_desc_done_irq(chan); @@ -1056,7 +1055,7 @@ static void xilinx_dpdma_chan_done_irq(struct xilinx_dpdma_chan *chan) "chan%u: DONE IRQ with no active descriptor!\n", chan->id); - spin_unlock_irqrestore(&chan->lock, flags); + spin_unlock(&chan->lock); } /** @@ -1071,10 +1070,9 @@ static void xilinx_dpdma_chan_vsync_irq(struct xilinx_dpdma_chan *chan) { struct xilinx_dpdma_tx_desc *pending; struct xilinx_dpdma_sw_desc *sw_desc; - unsigned long flags; u32 desc_id; - spin_lock_irqsave(&chan->lock, flags); + spin_lock(&chan->lock); pending = chan->desc.pending; if (!chan->running || !pending) @@ -1105,7 +1103,7 @@ static void xilinx_dpdma_chan_vsync_irq(struct xilinx_dpdma_chan *chan) xilinx_dpdma_chan_queue_transfer(chan); out: - spin_unlock_irqrestore(&chan->lock, flags); + spin_unlock(&chan->lock); } /** -- cgit v1.2.3-59-g8ed1b From ec177e46451597ac9d2e371e216afca9535ee547 Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Fri, 8 Mar 2024 16:00:34 -0500 Subject: dma: Add lockdep asserts to virt-dma Add lockdep asserts to all functions with "vc.lock must be held by caller" in their documentation. This will help catch cases where these assumptions do not hold. Signed-off-by: Sean Anderson Reviewed-by: Tomi Valkeinen Link: https://lore.kernel.org/r/20240308210034.3634938-4-sean.anderson@linux.dev Signed-off-by: Vinod Koul --- drivers/dma/virt-dma.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/dma/virt-dma.h b/drivers/dma/virt-dma.h index e9f5250fbe4d..59d9eabc8b67 100644 --- a/drivers/dma/virt-dma.h +++ b/drivers/dma/virt-dma.h @@ -81,6 +81,8 @@ static inline struct dma_async_tx_descriptor *vchan_tx_prep(struct virt_dma_chan */ static inline bool vchan_issue_pending(struct virt_dma_chan *vc) { + lockdep_assert_held(&vc->lock); + list_splice_tail_init(&vc->desc_submitted, &vc->desc_issued); return !list_empty(&vc->desc_issued); } @@ -96,6 +98,8 @@ static inline void vchan_cookie_complete(struct virt_dma_desc *vd) struct virt_dma_chan *vc = to_virt_chan(vd->tx.chan); dma_cookie_t cookie; + lockdep_assert_held(&vc->lock); + cookie = vd->tx.cookie; dma_cookie_complete(&vd->tx); dev_vdbg(vc->chan.device->dev, "txd %p[%x]: marked complete\n", @@ -146,6 +150,8 @@ static inline void vchan_terminate_vdesc(struct virt_dma_desc *vd) { struct virt_dma_chan *vc = to_virt_chan(vd->tx.chan); + lockdep_assert_held(&vc->lock); + list_add_tail(&vd->node, &vc->desc_terminated); if (vc->cyclic == vd) @@ -160,6 +166,8 @@ static inline void vchan_terminate_vdesc(struct virt_dma_desc *vd) */ static inline struct virt_dma_desc *vchan_next_desc(struct virt_dma_chan *vc) { + lockdep_assert_held(&vc->lock); + return list_first_entry_or_null(&vc->desc_issued, struct virt_dma_desc, node); } @@ -177,6 +185,8 @@ static inline struct virt_dma_desc *vchan_next_desc(struct virt_dma_chan *vc) static inline void vchan_get_all_descriptors(struct virt_dma_chan *vc, struct list_head *head) { + lockdep_assert_held(&vc->lock); + list_splice_tail_init(&vc->desc_allocated, head); list_splice_tail_init(&vc->desc_submitted, head); list_splice_tail_init(&vc->desc_issued, head); -- cgit v1.2.3-59-g8ed1b From 1bc31444209c8efae98cb78818131950d9a6f4d6 Mon Sep 17 00:00:00 2001 From: Nuno Sa Date: Thu, 28 Mar 2024 14:58:50 +0100 Subject: dmaengine: axi-dmac: fix possible race in remove() We need to first free the IRQ before calling of_dma_controller_free(). Otherwise we could get an interrupt and schedule a tasklet while removing the DMA controller. Fixes: 0e3b67b348b8 ("dmaengine: Add support for the Analog Devices AXI-DMAC DMA controller") Cc: stable@kernel.org Signed-off-by: Nuno Sa Link: https://lore.kernel.org/r/20240328-axi-dmac-devm-probe-v3-1-523c0176df70@analog.com Signed-off-by: Vinod Koul --- drivers/dma/dma-axi-dmac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/dma/dma-axi-dmac.c b/drivers/dma/dma-axi-dmac.c index 4e339c04fc1e..d5a33e4a91b1 100644 --- a/drivers/dma/dma-axi-dmac.c +++ b/drivers/dma/dma-axi-dmac.c @@ -1134,8 +1134,8 @@ static void axi_dmac_remove(struct platform_device *pdev) { struct axi_dmac *dmac = platform_get_drvdata(pdev); - of_dma_controller_free(pdev->dev.of_node); free_irq(dmac->irq, dmac); + of_dma_controller_free(pdev->dev.of_node); tasklet_kill(&dmac->chan.vchan.task); dma_async_device_unregister(&dmac->dma_dev); clk_disable_unprepare(dmac->clk); -- cgit v1.2.3-59-g8ed1b From 779a44831a4f64616a2fb18256fc9c299e1c033a Mon Sep 17 00:00:00 2001 From: Nuno Sa Date: Thu, 28 Mar 2024 14:58:51 +0100 Subject: dmaengine: axi-dmac: move to device managed probe In axi_dmac_probe(), there's a mix in using device managed APIs and explicitly cleaning things in the driver .remove() hook. Move to use device managed APIs and thus drop the .remove() hook. Signed-off-by: Nuno Sa Link: https://lore.kernel.org/r/20240328-axi-dmac-devm-probe-v3-2-523c0176df70@analog.com Signed-off-by: Vinod Koul --- drivers/dma/dma-axi-dmac.c | 78 ++++++++++++++++++++-------------------------- 1 file changed, 34 insertions(+), 44 deletions(-) diff --git a/drivers/dma/dma-axi-dmac.c b/drivers/dma/dma-axi-dmac.c index d5a33e4a91b1..bdb752f11869 100644 --- a/drivers/dma/dma-axi-dmac.c +++ b/drivers/dma/dma-axi-dmac.c @@ -1002,6 +1002,16 @@ static int axi_dmac_detect_caps(struct axi_dmac *dmac, unsigned int version) return 0; } +static void axi_dmac_tasklet_kill(void *task) +{ + tasklet_kill(task); +} + +static void axi_dmac_free_dma_controller(void *of_node) +{ + of_dma_controller_free(of_node); +} + static int axi_dmac_probe(struct platform_device *pdev) { struct dma_device *dma_dev; @@ -1025,14 +1035,10 @@ static int axi_dmac_probe(struct platform_device *pdev) if (IS_ERR(dmac->base)) return PTR_ERR(dmac->base); - dmac->clk = devm_clk_get(&pdev->dev, NULL); + dmac->clk = devm_clk_get_enabled(&pdev->dev, NULL); if (IS_ERR(dmac->clk)) return PTR_ERR(dmac->clk); - ret = clk_prepare_enable(dmac->clk); - if (ret < 0) - return ret; - version = axi_dmac_read(dmac, ADI_AXI_REG_VERSION); if (version >= ADI_AXI_PCORE_VER(4, 3, 'a')) @@ -1041,7 +1047,7 @@ static int axi_dmac_probe(struct platform_device *pdev) ret = axi_dmac_parse_dt(&pdev->dev, dmac); if (ret < 0) - goto err_clk_disable; + return ret; INIT_LIST_HEAD(&dmac->chan.active_descs); @@ -1072,7 +1078,7 @@ static int axi_dmac_probe(struct platform_device *pdev) ret = axi_dmac_detect_caps(dmac, version); if (ret) - goto err_clk_disable; + return ret; dma_dev->copy_align = (dmac->chan.address_align_mask + 1); @@ -1088,57 +1094,42 @@ static int axi_dmac_probe(struct platform_device *pdev) !AXI_DMAC_DST_COHERENT_GET(ret)) { dev_err(dmac->dma_dev.dev, "Coherent DMA not supported in hardware"); - ret = -EINVAL; - goto err_clk_disable; + return -EINVAL; } } - ret = dma_async_device_register(dma_dev); + ret = dmaenginem_async_device_register(dma_dev); + if (ret) + return ret; + + /* + * Put the action in here so it get's done before unregistering the DMA + * device. + */ + ret = devm_add_action_or_reset(&pdev->dev, axi_dmac_tasklet_kill, + &dmac->chan.vchan.task); if (ret) - goto err_clk_disable; + return ret; ret = of_dma_controller_register(pdev->dev.of_node, of_dma_xlate_by_chan_id, dma_dev); if (ret) - goto err_unregister_device; + return ret; - ret = request_irq(dmac->irq, axi_dmac_interrupt_handler, IRQF_SHARED, - dev_name(&pdev->dev), dmac); + ret = devm_add_action_or_reset(&pdev->dev, axi_dmac_free_dma_controller, + pdev->dev.of_node); if (ret) - goto err_unregister_of; + return ret; - platform_set_drvdata(pdev, dmac); + ret = devm_request_irq(&pdev->dev, dmac->irq, axi_dmac_interrupt_handler, + IRQF_SHARED, dev_name(&pdev->dev), dmac); + if (ret) + return ret; regmap = devm_regmap_init_mmio(&pdev->dev, dmac->base, &axi_dmac_regmap_config); - if (IS_ERR(regmap)) { - ret = PTR_ERR(regmap); - goto err_free_irq; - } - - return 0; - -err_free_irq: - free_irq(dmac->irq, dmac); -err_unregister_of: - of_dma_controller_free(pdev->dev.of_node); -err_unregister_device: - dma_async_device_unregister(&dmac->dma_dev); -err_clk_disable: - clk_disable_unprepare(dmac->clk); - - return ret; -} - -static void axi_dmac_remove(struct platform_device *pdev) -{ - struct axi_dmac *dmac = platform_get_drvdata(pdev); - free_irq(dmac->irq, dmac); - of_dma_controller_free(pdev->dev.of_node); - tasklet_kill(&dmac->chan.vchan.task); - dma_async_device_unregister(&dmac->dma_dev); - clk_disable_unprepare(dmac->clk); + return PTR_ERR_OR_ZERO(regmap); } static const struct of_device_id axi_dmac_of_match_table[] = { @@ -1153,7 +1144,6 @@ static struct platform_driver axi_dmac_driver = { .of_match_table = axi_dmac_of_match_table, }, .probe = axi_dmac_probe, - .remove_new = axi_dmac_remove, }; module_platform_driver(axi_dmac_driver); -- cgit v1.2.3-59-g8ed1b From 9bcf929ba1879887e0464d06cbf9b33839572af7 Mon Sep 17 00:00:00 2001 From: Tan Chun Hau Date: Tue, 26 Mar 2024 19:51:25 -0700 Subject: dt-bindings: dma: snps,dw-axi-dmac: Add JH8100 support Add support for StarFive JH8100 SoC in Sysnopsys Designware AXI DMA controller. Both JH8100 and JH7110 require reset operation in device probe. However, JH8100 doesn't need to apply different configuration on CH_CFG registers. Signed-off-by: Tan Chun Hau Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20240327025126.229475-2-chunhau.tan@starfivetech.com Signed-off-by: Vinod Koul --- Documentation/devicetree/bindings/dma/snps,dw-axi-dmac.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/dma/snps,dw-axi-dmac.yaml b/Documentation/devicetree/bindings/dma/snps,dw-axi-dmac.yaml index 363cf8bd150d..525f5f3932f5 100644 --- a/Documentation/devicetree/bindings/dma/snps,dw-axi-dmac.yaml +++ b/Documentation/devicetree/bindings/dma/snps,dw-axi-dmac.yaml @@ -21,6 +21,7 @@ properties: - snps,axi-dma-1.01a - intel,kmb-axi-dma - starfive,jh7110-axi-dma + - starfive,jh8100-axi-dma reg: minItems: 1 -- cgit v1.2.3-59-g8ed1b From 559a6690187ee0ab7875f7c560d3d19e35423fb3 Mon Sep 17 00:00:00 2001 From: Tan Chun Hau Date: Tue, 26 Mar 2024 19:51:26 -0700 Subject: dmaengine: dw-axi-dmac: Add support for StarFive JH8100 DMA JH8100 requires reset operation only in device probe. Signed-off-by: Tan Chun Hau Link: https://lore.kernel.org/r/20240327025126.229475-3-chunhau.tan@starfivetech.com Signed-off-by: Vinod Koul --- drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c index a86a81ff0caa..abb3523ba8ab 100644 --- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c +++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c @@ -1653,6 +1653,9 @@ static const struct of_device_id dw_dma_of_id_table[] = { }, { .compatible = "starfive,jh7110-axi-dma", .data = (void *)(AXI_DMA_FLAG_HAS_RESETS | AXI_DMA_FLAG_USE_CFG2), + }, { + .compatible = "starfive,jh8100-axi-dma", + .data = (void *)AXI_DMA_FLAG_HAS_RESETS, }, {} }; -- cgit v1.2.3-59-g8ed1b From 333e11bf47fa8d477db90e2900b1ed3c9ae9b697 Mon Sep 17 00:00:00 2001 From: Joao Pinto Date: Wed, 27 Mar 2024 10:49:24 +0000 Subject: Avoid hw_desc array overrun in dw-axi-dmac I have a use case where nr_buffers = 3 and in which each descriptor is composed by 3 segments, resulting in the DMA channel descs_allocated to be 9. Since axi_desc_put() handles the hw_desc considering the descs_allocated, this scenario would result in a kernel panic (hw_desc array will be overrun). To fix this, the proposal is to add a new member to the axi_dma_desc structure, where we keep the number of allocated hw_descs (axi_desc_alloc()) and use it in axi_desc_put() to handle the hw_desc array correctly. Additionally I propose to remove the axi_chan_start_first_queued() call after completing the transfer, since it was identified that unbalance can occur (started descriptors can be interrupted and transfer ignored due to DMA channel not being enabled). Signed-off-by: Joao Pinto Link: https://lore.kernel.org/r/1711536564-12919-1-git-send-email-jpinto@synopsys.com Signed-off-by: Vinod Koul --- drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c | 6 ++---- drivers/dma/dw-axi-dmac/dw-axi-dmac.h | 1 + 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c index abb3523ba8ab..8e4cfac64137 100644 --- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c +++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c @@ -302,6 +302,7 @@ static struct axi_dma_desc *axi_desc_alloc(u32 num) kfree(desc); return NULL; } + desc->nr_hw_descs = num; return desc; } @@ -328,7 +329,7 @@ static struct axi_dma_lli *axi_desc_get(struct axi_dma_chan *chan, static void axi_desc_put(struct axi_dma_desc *desc) { struct axi_dma_chan *chan = desc->chan; - int count = atomic_read(&chan->descs_allocated); + int count = desc->nr_hw_descs; struct axi_dma_hw_desc *hw_desc; int descs_put; @@ -1139,9 +1140,6 @@ static void axi_chan_block_xfer_complete(struct axi_dma_chan *chan) /* Remove the completed descriptor from issued list before completing */ list_del(&vd->node); vchan_cookie_complete(vd); - - /* Submit queued descriptors after processing the completed ones */ - axi_chan_start_first_queued(chan); } out: diff --git a/drivers/dma/dw-axi-dmac/dw-axi-dmac.h b/drivers/dma/dw-axi-dmac/dw-axi-dmac.h index 454904d99654..ac571b413b21 100644 --- a/drivers/dma/dw-axi-dmac/dw-axi-dmac.h +++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac.h @@ -104,6 +104,7 @@ struct axi_dma_desc { u32 completed_blocks; u32 length; u32 period_len; + u32 nr_hw_descs; }; struct axi_dma_chan_config { -- cgit v1.2.3-59-g8ed1b From e32634f466a9cc22e6d10252bee98d881e6357b8 Mon Sep 17 00:00:00 2001 From: Baruch Siach Date: Tue, 26 Mar 2024 13:43:07 +0200 Subject: dma: dw-axi-dmac: support per channel interrupt Hardware might not support a single combined interrupt that covers all channels. In that case we have to deal with interrupt per channel. Add support for that configuration. Signed-off-by: Baruch Siach Link: https://lore.kernel.org/r/ebab52e886ef1adc3c40e636aeb1ba3adfe2e578.1711453387.git.baruchs-c@neureality.ai Signed-off-by: Vinod Koul --- drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c | 29 +++++++++++++++++++------- drivers/dma/dw-axi-dmac/dw-axi-dmac.h | 2 +- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c index 8e4cfac64137..fffafa86d964 100644 --- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c +++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c @@ -1443,6 +1443,24 @@ static int parse_device_properties(struct axi_dma_chip *chip) return 0; } +static int axi_req_irqs(struct platform_device *pdev, struct axi_dma_chip *chip) +{ + int irq_count = platform_irq_count(pdev); + int ret; + + for (int i = 0; i < irq_count; i++) { + chip->irq[i] = platform_get_irq(pdev, i); + if (chip->irq[i] < 0) + return chip->irq[i]; + ret = devm_request_irq(chip->dev, chip->irq[i], dw_axi_dma_interrupt, + IRQF_SHARED, KBUILD_MODNAME, chip); + if (ret < 0) + return ret; + } + + return 0; +} + static int dw_probe(struct platform_device *pdev) { struct axi_dma_chip *chip; @@ -1469,10 +1487,6 @@ static int dw_probe(struct platform_device *pdev) chip->dev = &pdev->dev; chip->dw->hdata = hdata; - chip->irq = platform_get_irq(pdev, 0); - if (chip->irq < 0) - return chip->irq; - chip->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(chip->regs)) return PTR_ERR(chip->regs); @@ -1513,8 +1527,7 @@ static int dw_probe(struct platform_device *pdev) if (!dw->chan) return -ENOMEM; - ret = devm_request_irq(chip->dev, chip->irq, dw_axi_dma_interrupt, - IRQF_SHARED, KBUILD_MODNAME, chip); + ret = axi_req_irqs(pdev, chip); if (ret) return ret; @@ -1627,7 +1640,9 @@ static void dw_remove(struct platform_device *pdev) pm_runtime_disable(chip->dev); axi_dma_suspend(chip); - devm_free_irq(chip->dev, chip->irq, chip); + for (i = 0; i < DMAC_MAX_CHANNELS; i++) + if (chip->irq[i] > 0) + devm_free_irq(chip->dev, chip->irq[i], chip); of_dma_controller_free(chip->dev->of_node); diff --git a/drivers/dma/dw-axi-dmac/dw-axi-dmac.h b/drivers/dma/dw-axi-dmac/dw-axi-dmac.h index ac571b413b21..b842e6a8d90d 100644 --- a/drivers/dma/dw-axi-dmac/dw-axi-dmac.h +++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac.h @@ -65,7 +65,7 @@ struct dw_axi_dma { struct axi_dma_chip { struct device *dev; - int irq; + int irq[DMAC_MAX_CHANNELS]; void __iomem *regs; void __iomem *apb_regs; struct clk *core_clk; -- cgit v1.2.3-59-g8ed1b From cee8cbfc7be8ff9f3ccf258134f9ab2c273abb75 Mon Sep 17 00:00:00 2001 From: Frank Li Date: Sat, 23 Mar 2024 11:34:50 -0400 Subject: dmaengine: fsl-edma: remove 'slave_id' from fsl_edma_chan The 'slave_id' field is redundant as it duplicates the functionality of 'srcid'. Remove 'slave_id' from fsl_edma_chan to eliminate redundancy. Signed-off-by: Frank Li Link: https://lore.kernel.org/r/20240323-8ulp_edma-v3-1-c0e981027c05@nxp.com Signed-off-by: Vinod Koul --- drivers/dma/fsl-edma-common.h | 1 - drivers/dma/fsl-edma-main.c | 10 +++++----- drivers/dma/mcf-edma-main.c | 4 ++-- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/dma/fsl-edma-common.h b/drivers/dma/fsl-edma-common.h index 7bf0aba471a8..4cf1de9f0e51 100644 --- a/drivers/dma/fsl-edma-common.h +++ b/drivers/dma/fsl-edma-common.h @@ -151,7 +151,6 @@ struct fsl_edma_chan { enum dma_status status; enum fsl_edma_pm_state pm_state; bool idle; - u32 slave_id; struct fsl_edma_engine *edma; struct fsl_edma_desc *edesc; struct dma_slave_config cfg; diff --git a/drivers/dma/fsl-edma-main.c b/drivers/dma/fsl-edma-main.c index 402f0058a180..0a6e0c404027 100644 --- a/drivers/dma/fsl-edma-main.c +++ b/drivers/dma/fsl-edma-main.c @@ -114,8 +114,8 @@ static struct dma_chan *fsl_edma_xlate(struct of_phandle_args *dma_spec, if (chan) { chan->device->privatecnt++; fsl_chan = to_fsl_edma_chan(chan); - fsl_chan->slave_id = dma_spec->args[1]; - fsl_edma_chan_mux(fsl_chan, fsl_chan->slave_id, + fsl_chan->srcid = dma_spec->args[1]; + fsl_edma_chan_mux(fsl_chan, fsl_chan->srcid, true); mutex_unlock(&fsl_edma->fsl_edma_mutex); return chan; @@ -540,7 +540,7 @@ static int fsl_edma_probe(struct platform_device *pdev) fsl_chan->edma = fsl_edma; fsl_chan->pm_state = RUNNING; - fsl_chan->slave_id = 0; + fsl_chan->srcid = 0; fsl_chan->idle = true; fsl_chan->dma_dir = DMA_NONE; fsl_chan->vchan.desc_free = fsl_edma_free_desc; @@ -682,8 +682,8 @@ static int fsl_edma_resume_early(struct device *dev) continue; fsl_chan->pm_state = RUNNING; edma_write_tcdreg(fsl_chan, 0, csr); - if (fsl_chan->slave_id != 0) - fsl_edma_chan_mux(fsl_chan, fsl_chan->slave_id, true); + if (fsl_chan->srcid != 0) + fsl_edma_chan_mux(fsl_chan, fsl_chan->srcid, true); } if (!(fsl_edma->drvdata->flags & FSL_EDMA_DRV_SPLIT_REG)) diff --git a/drivers/dma/mcf-edma-main.c b/drivers/dma/mcf-edma-main.c index dba631783876..78c606f6d002 100644 --- a/drivers/dma/mcf-edma-main.c +++ b/drivers/dma/mcf-edma-main.c @@ -195,7 +195,7 @@ static int mcf_edma_probe(struct platform_device *pdev) struct fsl_edma_chan *mcf_chan = &mcf_edma->chans[i]; mcf_chan->edma = mcf_edma; - mcf_chan->slave_id = i; + mcf_chan->srcid = i; mcf_chan->idle = true; mcf_chan->dma_dir = DMA_NONE; mcf_chan->vchan.desc_free = fsl_edma_free_desc; @@ -277,7 +277,7 @@ bool mcf_edma_filter_fn(struct dma_chan *chan, void *param) if (chan->device->dev->driver == &mcf_edma_driver.driver) { struct fsl_edma_chan *mcf_chan = to_fsl_edma_chan(chan); - return (mcf_chan->slave_id == (uintptr_t)param); + return (mcf_chan->srcid == (uintptr_t)param); } return false; -- cgit v1.2.3-59-g8ed1b From 6aa60f79e6794bbbc571ea4e0501b9fcc26026e2 Mon Sep 17 00:00:00 2001 From: Frank Li Date: Sat, 23 Mar 2024 11:34:51 -0400 Subject: dmaengine: fsl-edma: add safety check for 'srcid' Ensure that 'srcid' is a non-zero value to avoid dtb passing invalid 'srcid' to the driver. Signed-off-by: Frank Li Link: https://lore.kernel.org/r/20240323-8ulp_edma-v3-2-c0e981027c05@nxp.com Signed-off-by: Vinod Koul --- drivers/dma/fsl-edma-main.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/dma/fsl-edma-main.c b/drivers/dma/fsl-edma-main.c index 0a6e0c404027..2148a7f1ae84 100644 --- a/drivers/dma/fsl-edma-main.c +++ b/drivers/dma/fsl-edma-main.c @@ -115,6 +115,13 @@ static struct dma_chan *fsl_edma_xlate(struct of_phandle_args *dma_spec, chan->device->privatecnt++; fsl_chan = to_fsl_edma_chan(chan); fsl_chan->srcid = dma_spec->args[1]; + + if (!fsl_chan->srcid) { + dev_err(&fsl_chan->pdev->dev, "Invalidate srcid %d\n", + fsl_chan->srcid); + return NULL; + } + fsl_edma_chan_mux(fsl_chan, fsl_chan->srcid, true); mutex_unlock(&fsl_edma->fsl_edma_mutex); -- cgit v1.2.3-59-g8ed1b From 9a5000cf70bcfcb5dd4e5b4bae0a01fb9bdf9fa1 Mon Sep 17 00:00:00 2001 From: Frank Li Date: Sat, 23 Mar 2024 11:34:52 -0400 Subject: dmaengine: fsl-edma: clean up chclk and FSL_EDMA_DRV_HAS_CHCLK No device currently utilizes chclk and FSL_EDMA_DRV_HAS_CHCLK features. Removes these unused features. Signed-off-by: Frank Li Link: https://lore.kernel.org/r/20240323-8ulp_edma-v3-3-c0e981027c05@nxp.com Signed-off-by: Vinod Koul --- drivers/dma/fsl-edma-common.h | 2 -- drivers/dma/fsl-edma-main.c | 8 -------- 2 files changed, 10 deletions(-) diff --git a/drivers/dma/fsl-edma-common.h b/drivers/dma/fsl-edma-common.h index 4cf1de9f0e51..532f647e540e 100644 --- a/drivers/dma/fsl-edma-common.h +++ b/drivers/dma/fsl-edma-common.h @@ -192,7 +192,6 @@ struct fsl_edma_desc { #define FSL_EDMA_DRV_WRAP_IO BIT(3) #define FSL_EDMA_DRV_EDMA64 BIT(4) #define FSL_EDMA_DRV_HAS_PD BIT(5) -#define FSL_EDMA_DRV_HAS_CHCLK BIT(6) #define FSL_EDMA_DRV_HAS_CHMUX BIT(7) /* imx8 QM audio edma remote local swapped */ #define FSL_EDMA_DRV_QUIRK_SWAPPED BIT(8) @@ -237,7 +236,6 @@ struct fsl_edma_engine { void __iomem *muxbase[DMAMUX_NR]; struct clk *muxclk[DMAMUX_NR]; struct clk *dmaclk; - struct clk *chclk; struct mutex fsl_edma_mutex; const struct fsl_edma_drvdata *drvdata; u32 n_chans; diff --git a/drivers/dma/fsl-edma-main.c b/drivers/dma/fsl-edma-main.c index 2148a7f1ae84..41c71c360ff1 100644 --- a/drivers/dma/fsl-edma-main.c +++ b/drivers/dma/fsl-edma-main.c @@ -483,14 +483,6 @@ static int fsl_edma_probe(struct platform_device *pdev) } } - if (drvdata->flags & FSL_EDMA_DRV_HAS_CHCLK) { - fsl_edma->chclk = devm_clk_get_enabled(&pdev->dev, "mp"); - if (IS_ERR(fsl_edma->chclk)) { - dev_err(&pdev->dev, "Missing MP block clock.\n"); - return PTR_ERR(fsl_edma->chclk); - } - } - ret = of_property_read_variable_u32_array(np, "dma-channel-mask", chan_mask, 1, 2); if (ret > 0) { -- cgit v1.2.3-59-g8ed1b From b14f56beb289ff67fe484d720bf09092163f90c8 Mon Sep 17 00:00:00 2001 From: Joy Zou Date: Sat, 23 Mar 2024 11:34:53 -0400 Subject: dt-bindings: dma: fsl-edma: add fsl,imx8ulp-edma compatible string Introduce the compatible string 'fsl,imx8ulp-edma' to enable support for the i.MX8ULP's eDMA, alongside adjusting the clock numbering. The i.MX8ULP eDMA architecture features one clock for each DMA channel and an additional clock for the core controller. Given a maximum of 32 DMA channels, the maximum clock number consequently increases to 33. Signed-off-by: Joy Zou Signed-off-by: Frank Li Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20240323-8ulp_edma-v3-4-c0e981027c05@nxp.com Signed-off-by: Vinod Koul --- .../devicetree/bindings/dma/fsl,edma.yaml | 40 ++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/dma/fsl,edma.yaml b/Documentation/devicetree/bindings/dma/fsl,edma.yaml index aa51d278cb67..825f4715499e 100644 --- a/Documentation/devicetree/bindings/dma/fsl,edma.yaml +++ b/Documentation/devicetree/bindings/dma/fsl,edma.yaml @@ -23,6 +23,7 @@ properties: - fsl,imx7ulp-edma - fsl,imx8qm-adma - fsl,imx8qm-edma + - fsl,imx8ulp-edma - fsl,imx93-edma3 - fsl,imx93-edma4 - fsl,imx95-edma5 @@ -43,6 +44,17 @@ properties: maxItems: 64 "#dma-cells": + description: | + Specifies the number of cells needed to encode an DMA channel. + + Encode for cells number 2: + cell 0: index of dma channel mux instance. + cell 1: peripheral dma request id. + + Encode for cells number 3: + cell 0: peripheral dma request id. + cell 1: dma channel priority. + cell 2: bitmask, defined at include/dt-bindings/dma/fsl-edma.h enum: - 2 - 3 @@ -53,11 +65,11 @@ properties: clocks: minItems: 1 - maxItems: 2 + maxItems: 33 clock-names: minItems: 1 - maxItems: 2 + maxItems: 33 big-endian: description: | @@ -108,6 +120,7 @@ allOf: properties: clocks: minItems: 2 + maxItems: 2 clock-names: items: - const: dmamux0 @@ -136,6 +149,7 @@ allOf: properties: clock: minItems: 2 + maxItems: 2 clock-names: items: - const: dma @@ -151,6 +165,28 @@ allOf: dma-channels: const: 32 + - if: + properties: + compatible: + contains: + const: fsl,imx8ulp-edma + then: + properties: + clocks: + minItems: 33 + clock-names: + minItems: 33 + items: + oneOf: + - const: dma + - pattern: "^ch(0[0-9]|[1-2][0-9]|3[01])$" + + interrupt-names: false + interrupts: + minItems: 32 + "#dma-cells": + const: 3 + unevaluatedProperties: false examples: -- cgit v1.2.3-59-g8ed1b From d8d4355861d874cbd1395ec0edcbe4e0f6940738 Mon Sep 17 00:00:00 2001 From: Joy Zou Date: Sat, 23 Mar 2024 11:34:54 -0400 Subject: dmaengine: fsl-edma: add i.MX8ULP edma support Add support for the i.MX8ULP platform to the eDMA driver. Introduce the use of the correct FSL_EDMA_DRV_HAS_CHCLK flag to handle per-channel clock configurations. Signed-off-by: Joy Zou Reviewed-by: Frank Li Link: https://lore.kernel.org/r/20240323-8ulp_edma-v3-5-c0e981027c05@nxp.com Signed-off-by: Vinod Koul --- drivers/dma/fsl-edma-common.c | 6 ++++++ drivers/dma/fsl-edma-common.h | 1 + drivers/dma/fsl-edma-main.c | 22 ++++++++++++++++++++++ 3 files changed, 29 insertions(+) diff --git a/drivers/dma/fsl-edma-common.c b/drivers/dma/fsl-edma-common.c index b18faa7cfedb..f9144b015439 100644 --- a/drivers/dma/fsl-edma-common.c +++ b/drivers/dma/fsl-edma-common.c @@ -3,6 +3,7 @@ // Copyright (c) 2013-2014 Freescale Semiconductor, Inc // Copyright (c) 2017 Sysam, Angelo Dureghello +#include #include #include #include @@ -810,6 +811,9 @@ int fsl_edma_alloc_chan_resources(struct dma_chan *chan) { struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan); + if (fsl_edma_drvflags(fsl_chan) & FSL_EDMA_DRV_HAS_CHCLK) + clk_prepare_enable(fsl_chan->clk); + fsl_chan->tcd_pool = dma_pool_create("tcd_pool", chan->device->dev, fsl_edma_drvflags(fsl_chan) & FSL_EDMA_DRV_TCD64 ? sizeof(struct fsl_edma_hw_tcd64) : sizeof(struct fsl_edma_hw_tcd), @@ -838,6 +842,8 @@ void fsl_edma_free_chan_resources(struct dma_chan *chan) fsl_chan->tcd_pool = NULL; fsl_chan->is_sw = false; fsl_chan->srcid = 0; + if (fsl_edma_drvflags(fsl_chan) & FSL_EDMA_DRV_HAS_CHCLK) + clk_disable_unprepare(fsl_chan->clk); } void fsl_edma_cleanup_vchan(struct dma_device *dmadev) diff --git a/drivers/dma/fsl-edma-common.h b/drivers/dma/fsl-edma-common.h index 532f647e540e..01157912bfd5 100644 --- a/drivers/dma/fsl-edma-common.h +++ b/drivers/dma/fsl-edma-common.h @@ -192,6 +192,7 @@ struct fsl_edma_desc { #define FSL_EDMA_DRV_WRAP_IO BIT(3) #define FSL_EDMA_DRV_EDMA64 BIT(4) #define FSL_EDMA_DRV_HAS_PD BIT(5) +#define FSL_EDMA_DRV_HAS_CHCLK BIT(6) #define FSL_EDMA_DRV_HAS_CHMUX BIT(7) /* imx8 QM audio edma remote local swapped */ #define FSL_EDMA_DRV_QUIRK_SWAPPED BIT(8) diff --git a/drivers/dma/fsl-edma-main.c b/drivers/dma/fsl-edma-main.c index 41c71c360ff1..755a3dc3b0a7 100644 --- a/drivers/dma/fsl-edma-main.c +++ b/drivers/dma/fsl-edma-main.c @@ -356,6 +356,16 @@ static struct fsl_edma_drvdata imx8qm_audio_data = { .setup_irq = fsl_edma3_irq_init, }; +static struct fsl_edma_drvdata imx8ulp_data = { + .flags = FSL_EDMA_DRV_HAS_CHMUX | FSL_EDMA_DRV_HAS_CHCLK | FSL_EDMA_DRV_HAS_DMACLK | + FSL_EDMA_DRV_EDMA3, + .chreg_space_sz = 0x10000, + .chreg_off = 0x10000, + .mux_off = 0x10000 + offsetof(struct fsl_edma3_ch_reg, ch_mux), + .mux_skip = 0x10000, + .setup_irq = fsl_edma3_irq_init, +}; + static struct fsl_edma_drvdata imx93_data3 = { .flags = FSL_EDMA_DRV_HAS_DMACLK | FSL_EDMA_DRV_EDMA3, .chreg_space_sz = 0x10000, @@ -388,6 +398,7 @@ static const struct of_device_id fsl_edma_dt_ids[] = { { .compatible = "fsl,imx7ulp-edma", .data = &imx7ulp_data}, { .compatible = "fsl,imx8qm-edma", .data = &imx8qm_data}, { .compatible = "fsl,imx8qm-adma", .data = &imx8qm_audio_data}, + { .compatible = "fsl,imx8ulp-edma", .data = &imx8ulp_data}, { .compatible = "fsl,imx93-edma3", .data = &imx93_data3}, { .compatible = "fsl,imx93-edma4", .data = &imx93_data4}, { .compatible = "fsl,imx95-edma5", .data = &imx95_data5}, @@ -441,6 +452,7 @@ static int fsl_edma_probe(struct platform_device *pdev) struct fsl_edma_engine *fsl_edma; const struct fsl_edma_drvdata *drvdata = NULL; u32 chan_mask[2] = {0, 0}; + char clk_name[36]; struct edma_regs *regs; int chans; int ret, i; @@ -550,11 +562,21 @@ static int fsl_edma_probe(struct platform_device *pdev) + i * drvdata->chreg_space_sz + drvdata->chreg_off + len; fsl_chan->mux_addr = fsl_edma->membase + drvdata->mux_off + i * drvdata->mux_skip; + if (drvdata->flags & FSL_EDMA_DRV_HAS_CHCLK) { + snprintf(clk_name, sizeof(clk_name), "ch%02d", i); + fsl_chan->clk = devm_clk_get_enabled(&pdev->dev, + (const char *)clk_name); + + if (IS_ERR(fsl_chan->clk)) + return PTR_ERR(fsl_chan->clk); + } fsl_chan->pdev = pdev; vchan_init(&fsl_chan->vchan, &fsl_edma->dma_dev); edma_write_tcdreg(fsl_chan, cpu_to_le32(0), csr); fsl_edma_chan_mux(fsl_chan, 0, false); + if (fsl_chan->edma->drvdata->flags & FSL_EDMA_DRV_HAS_CHCLK) + clk_disable_unprepare(fsl_chan->clk); } ret = fsl_edma->drvdata->setup_irq(pdev, fsl_edma); -- cgit v1.2.3-59-g8ed1b From 06db9ee8b42ef833e3941ef3c7795c1bea37212c Mon Sep 17 00:00:00 2001 From: Frank Li Date: Wed, 20 Mar 2024 15:39:19 -0400 Subject: dmaengine: fsl-dpaa2-qdma: clean up unused macro Remove unused macro definition. Signed-off-by: Frank Li Link: https://lore.kernel.org/r/20240320-dpaa2-v1-1-eb56e47c94ec@nxp.com Signed-off-by: Vinod Koul --- drivers/dma/fsl-dpaa2-qdma/dpdmai.h | 9 --------- 1 file changed, 9 deletions(-) diff --git a/drivers/dma/fsl-dpaa2-qdma/dpdmai.h b/drivers/dma/fsl-dpaa2-qdma/dpdmai.h index b13b9bf0c003..2749608575f0 100644 --- a/drivers/dma/fsl-dpaa2-qdma/dpdmai.h +++ b/drivers/dma/fsl-dpaa2-qdma/dpdmai.h @@ -26,15 +26,6 @@ #define DPDMAI_CMDID_RESET DPDMAI_CMDID_FORMAT(0x005) #define DPDMAI_CMDID_IS_ENABLED DPDMAI_CMDID_FORMAT(0x006) -#define DPDMAI_CMDID_SET_IRQ DPDMAI_CMDID_FORMAT(0x010) -#define DPDMAI_CMDID_GET_IRQ DPDMAI_CMDID_FORMAT(0x011) -#define DPDMAI_CMDID_SET_IRQ_ENABLE DPDMAI_CMDID_FORMAT(0x012) -#define DPDMAI_CMDID_GET_IRQ_ENABLE DPDMAI_CMDID_FORMAT(0x013) -#define DPDMAI_CMDID_SET_IRQ_MASK DPDMAI_CMDID_FORMAT(0x014) -#define DPDMAI_CMDID_GET_IRQ_MASK DPDMAI_CMDID_FORMAT(0x015) -#define DPDMAI_CMDID_GET_IRQ_STATUS DPDMAI_CMDID_FORMAT(0x016) -#define DPDMAI_CMDID_CLEAR_IRQ_STATUS DPDMAI_CMDID_FORMAT(0x017) - #define DPDMAI_CMDID_SET_RX_QUEUE DPDMAI_CMDID_FORMAT(0x1A0) #define DPDMAI_CMDID_GET_RX_QUEUE DPDMAI_CMDID_FORMAT(0x1A1) #define DPDMAI_CMDID_GET_TX_QUEUE DPDMAI_CMDID_FORMAT(0x1A2) -- cgit v1.2.3-59-g8ed1b From 26a4d2aedac28640c1fbb3761d940d99eff44488 Mon Sep 17 00:00:00 2001 From: Frank Li Date: Wed, 20 Mar 2024 15:39:20 -0400 Subject: dmaengine: fsl-dpaa2-qdma: Remove unused function dpdmai_create() Remove unused function dpdmai_create(); Signed-off-by: Frank Li Link: https://lore.kernel.org/r/20240320-dpaa2-v1-2-eb56e47c94ec@nxp.com Signed-off-by: Vinod Koul --- drivers/dma/fsl-dpaa2-qdma/dpdmai.c | 54 ------------------------------------- drivers/dma/fsl-dpaa2-qdma/dpdmai.h | 2 -- 2 files changed, 56 deletions(-) diff --git a/drivers/dma/fsl-dpaa2-qdma/dpdmai.c b/drivers/dma/fsl-dpaa2-qdma/dpdmai.c index 878662aaa1c2..66a3953f0e3b 100644 --- a/drivers/dma/fsl-dpaa2-qdma/dpdmai.c +++ b/drivers/dma/fsl-dpaa2-qdma/dpdmai.c @@ -33,16 +33,6 @@ struct dpdmai_rsp_get_tx_queue { __le32 fqid; }; -#define MC_CMD_OP(_cmd, _param, _offset, _width, _type, _arg) \ - ((_cmd).params[_param] |= mc_enc((_offset), (_width), _arg)) - -/* cmd, param, offset, width, type, arg_name */ -#define DPDMAI_CMD_CREATE(cmd, cfg) \ -do { \ - MC_CMD_OP(cmd, 0, 8, 8, u8, (cfg)->priorities[0]);\ - MC_CMD_OP(cmd, 0, 16, 8, u8, (cfg)->priorities[1]);\ -} while (0) - static inline u64 mc_enc(int lsoffset, int width, u64 val) { return (val & MAKE_UMASK64(width)) << lsoffset; @@ -115,50 +105,6 @@ int dpdmai_close(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token) } EXPORT_SYMBOL_GPL(dpdmai_close); -/** - * dpdmai_create() - Create the DPDMAI object - * @mc_io: Pointer to MC portal's I/O object - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' - * @cfg: Configuration structure - * @token: Returned token; use in subsequent API calls - * - * Create the DPDMAI object, allocate required resources and - * perform required initialization. - * - * The object can be created either by declaring it in the - * DPL file, or by calling this function. - * - * This function returns a unique authentication token, - * associated with the specific object ID and the specific MC - * portal; this token must be used in all subsequent calls to - * this specific object. For objects that are created using the - * DPL file, call dpdmai_open() function to get an authentication - * token first. - * - * Return: '0' on Success; Error code otherwise. - */ -int dpdmai_create(struct fsl_mc_io *mc_io, u32 cmd_flags, - const struct dpdmai_cfg *cfg, u16 *token) -{ - struct fsl_mc_command cmd = { 0 }; - int err; - - /* prepare command */ - cmd.header = mc_encode_cmd_header(DPDMAI_CMDID_CREATE, - cmd_flags, 0); - DPDMAI_CMD_CREATE(cmd, cfg); - - /* send command to mc*/ - err = mc_send_command(mc_io, &cmd); - if (err) - return err; - - /* retrieve response parameters */ - *token = mc_cmd_hdr_read_token(&cmd); - - return 0; -} - /** * dpdmai_destroy() - Destroy the DPDMAI object and release all its resources. * @mc_io: Pointer to MC portal's I/O object diff --git a/drivers/dma/fsl-dpaa2-qdma/dpdmai.h b/drivers/dma/fsl-dpaa2-qdma/dpdmai.h index 2749608575f0..3f2db582509a 100644 --- a/drivers/dma/fsl-dpaa2-qdma/dpdmai.h +++ b/drivers/dma/fsl-dpaa2-qdma/dpdmai.h @@ -153,8 +153,6 @@ int dpdmai_open(struct fsl_mc_io *mc_io, u32 cmd_flags, int dpdmai_id, u16 *token); int dpdmai_close(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token); int dpdmai_destroy(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token); -int dpdmai_create(struct fsl_mc_io *mc_io, u32 cmd_flags, - const struct dpdmai_cfg *cfg, u16 *token); int dpdmai_enable(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token); int dpdmai_disable(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token); int dpdmai_reset(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token); -- cgit v1.2.3-59-g8ed1b From ebf850697a9daa9f59b902ea1e547079d426618b Mon Sep 17 00:00:00 2001 From: Frank Li Date: Wed, 20 Mar 2024 15:39:21 -0400 Subject: dmaengine: fsl-dpaa2-qdma: Add dpdmai_cmd_open Introduce the structures dpdmai_cmd_open to maintain consistency within the API calls of the driver. Signed-off-by: Frank Li Link: https://lore.kernel.org/r/20240320-dpaa2-v1-3-eb56e47c94ec@nxp.com Signed-off-by: Vinod Koul --- drivers/dma/fsl-dpaa2-qdma/dpdmai.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/dma/fsl-dpaa2-qdma/dpdmai.c b/drivers/dma/fsl-dpaa2-qdma/dpdmai.c index 66a3953f0e3b..610f6231835a 100644 --- a/drivers/dma/fsl-dpaa2-qdma/dpdmai.c +++ b/drivers/dma/fsl-dpaa2-qdma/dpdmai.c @@ -33,6 +33,10 @@ struct dpdmai_rsp_get_tx_queue { __le32 fqid; }; +struct dpdmai_cmd_open { + __le32 dpdmai_id; +} __packed; + static inline u64 mc_enc(int lsoffset, int width, u64 val) { return (val & MAKE_UMASK64(width)) << lsoffset; @@ -58,16 +62,16 @@ static inline u64 mc_enc(int lsoffset, int width, u64 val) int dpdmai_open(struct fsl_mc_io *mc_io, u32 cmd_flags, int dpdmai_id, u16 *token) { + struct dpdmai_cmd_open *cmd_params; struct fsl_mc_command cmd = { 0 }; - __le64 *cmd_dpdmai_id; int err; /* prepare command */ cmd.header = mc_encode_cmd_header(DPDMAI_CMDID_OPEN, cmd_flags, 0); - cmd_dpdmai_id = cmd.params; - *cmd_dpdmai_id = cpu_to_le32(dpdmai_id); + cmd_params = (struct dpdmai_cmd_open *)&cmd.params; + cmd_params->dpdmai_id = cpu_to_le32(dpdmai_id); /* send command to mc*/ err = mc_send_command(mc_io, &cmd); -- cgit v1.2.3-59-g8ed1b From 4665be0e952f68306cc6fba2cce68b940a7ec78c Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 8 Mar 2024 13:47:50 +0000 Subject: dmaengine: pch_dma: remove unused function chan2parent The helper function chan2parent is not used and has never been used since the first commit to the code back in 2010. The function is redundant and can be removed. Cleans up clang scan build warning: drivers/dma/pch_dma.c:158:30: warning: unused function 'chan2parent' [-Wunused-function] Signed-off-by: Colin Ian King Link: https://lore.kernel.org/r/20240308134750.2058556-1-colin.i.king@gmail.com Signed-off-by: Vinod Koul --- drivers/dma/pch_dma.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/dma/pch_dma.c b/drivers/dma/pch_dma.c index c359decc07a3..6b2793b07694 100644 --- a/drivers/dma/pch_dma.c +++ b/drivers/dma/pch_dma.c @@ -155,11 +155,6 @@ static inline struct device *chan2dev(struct dma_chan *chan) return &chan->dev->device; } -static inline struct device *chan2parent(struct dma_chan *chan) -{ - return chan->dev->device.parent; -} - static inline struct pch_dma_desc *pdc_first_active(struct pch_dma_chan *pd_chan) { -- cgit v1.2.3-59-g8ed1b From 9a966517a83090ee3e26e9a93a92523e2358c5b3 Mon Sep 17 00:00:00 2001 From: Alex James Date: Thu, 4 Apr 2024 23:11:52 -0500 Subject: thunderbolt: Enable NVM upgrade support on Intel Maple Ridge Intel Maple Ridge supports NVM firmware upgrade with the same flows used on previous discrete Thunderbolt contollers from Intel (such as Titan Ridge). Advertise NVM upgrade support for Maple Ridge in icm_probe() to expose the corresponding files in /sys/bus/thunderbolt. The NVM firmware process was successfully tested on a system with a JHL8540 controller (ASUS ProArt Z790-CREATOR). Signed-off-by: Alex James Signed-off-by: Mika Westerberg --- drivers/thunderbolt/icm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/thunderbolt/icm.c b/drivers/thunderbolt/icm.c index baf10d099c77..7859bccc592d 100644 --- a/drivers/thunderbolt/icm.c +++ b/drivers/thunderbolt/icm.c @@ -2532,6 +2532,7 @@ struct tb *icm_probe(struct tb_nhi *nhi) case PCI_DEVICE_ID_INTEL_MAPLE_RIDGE_2C_NHI: case PCI_DEVICE_ID_INTEL_MAPLE_RIDGE_4C_NHI: + icm->can_upgrade_nvm = true; icm->is_supported = icm_tgl_is_supported; icm->get_mode = icm_ar_get_mode; icm->driver_ready = icm_tr_driver_ready; -- cgit v1.2.3-59-g8ed1b From fec2601f2003b9e9820ab5057607df7fff61cfaf Mon Sep 17 00:00:00 2001 From: Leonard Crestez Date: Sat, 16 Mar 2024 20:16:42 +0200 Subject: remoteproc: zynqmp: Add coredump support Supporting remoteproc coredump requires the platform-specific driver to register coredump segments to be dumped. Do this by calling rproc_coredump_add_segment for every carveout. Also call rproc_coredump_set_elf_info when then rproc is created. If the ELFCLASS parameter is not provided then coredump fails with an error. Other drivers seem to pass EM_NONE for the machine argument but for me this shows a warning in gdb. Pass EM_ARM because this is an ARM R5. Signed-off-by: Leonard Crestez Link: https://lore.kernel.org/r/d4556268-8274-4089-949f-3b97d67793c7@gmail.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/xlnx_r5_remoteproc.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/remoteproc/xlnx_r5_remoteproc.c b/drivers/remoteproc/xlnx_r5_remoteproc.c index 4395edea9a64..cfbd97b89c26 100644 --- a/drivers/remoteproc/xlnx_r5_remoteproc.c +++ b/drivers/remoteproc/xlnx_r5_remoteproc.c @@ -486,6 +486,7 @@ static int add_mem_regions_carveout(struct rproc *rproc) } rproc_add_carveout(rproc, rproc_mem); + rproc_coredump_add_segment(rproc, rmem->base, rmem->size); dev_dbg(&rproc->dev, "reserved mem carveout %s addr=%llx, size=0x%llx", it.node->name, rmem->base, rmem->size); @@ -597,6 +598,7 @@ static int add_tcm_carveout_split_mode(struct rproc *rproc) } rproc_add_carveout(rproc, rproc_mem); + rproc_coredump_add_segment(rproc, da, bank_size); } return 0; @@ -676,6 +678,7 @@ static int add_tcm_carveout_lockstep_mode(struct rproc *rproc) /* If registration is success, add carveouts */ rproc_add_carveout(rproc, rproc_mem); + rproc_coredump_add_segment(rproc, da, bank_size); dev_dbg(dev, "TCM carveout lockstep mode %s addr=0x%llx, da=0x%x, size=0x%lx", bank_name, bank_addr, da, bank_size); @@ -853,6 +856,8 @@ static struct zynqmp_r5_core *zynqmp_r5_add_rproc_core(struct device *cdev) return ERR_PTR(-ENOMEM); } + rproc_coredump_set_elf_info(r5_rproc, ELFCLASS32, EM_ARM); + r5_rproc->auto_boot = false; r5_core = r5_rproc->priv; r5_core->dev = cdev; -- cgit v1.2.3-59-g8ed1b From 4bfa185fe3f0b20ebb6e7224dae771fcb657f260 Mon Sep 17 00:00:00 2001 From: Leonardo Bras Date: Wed, 3 Jan 2024 13:31:59 -0300 Subject: riscv/cmpxchg: Deduplicate xchg() asm functions In this header every xchg define (_relaxed, _acquire, _release, vanilla) contain it's own asm file, both for 4-byte variables an 8-byte variables, on a total of 8 versions of mostly the same asm. This is usually bad, as it means any change may be done in up to 8 different places. Unify those versions by creating a new define with enough parameters to generate any version of the previous 8. Then unify the result under a more general define, and simplify arch_xchg* generation. (This did not cause any change in generated asm) Signed-off-by: Leonardo Bras Reviewed-by: Guo Ren Reviewed-by: Andrea Parri Tested-by: Guo Ren Link: https://lore.kernel.org/r/20240103163203.72768-3-leobras@redhat.com Signed-off-by: Palmer Dabbelt --- arch/riscv/include/asm/cmpxchg.h | 138 +++++++-------------------------------- 1 file changed, 23 insertions(+), 115 deletions(-) diff --git a/arch/riscv/include/asm/cmpxchg.h b/arch/riscv/include/asm/cmpxchg.h index 2f4726d3cfcc..48478a8eecee 100644 --- a/arch/riscv/include/asm/cmpxchg.h +++ b/arch/riscv/include/asm/cmpxchg.h @@ -11,140 +11,48 @@ #include #include -#define __xchg_relaxed(ptr, new, size) \ +#define __arch_xchg(sfx, prepend, append, r, p, n) \ ({ \ - __typeof__(ptr) __ptr = (ptr); \ - __typeof__(new) __new = (new); \ - __typeof__(*(ptr)) __ret; \ - switch (size) { \ - case 4: \ - __asm__ __volatile__ ( \ - " amoswap.w %0, %2, %1\n" \ - : "=r" (__ret), "+A" (*__ptr) \ - : "r" (__new) \ - : "memory"); \ - break; \ - case 8: \ - __asm__ __volatile__ ( \ - " amoswap.d %0, %2, %1\n" \ - : "=r" (__ret), "+A" (*__ptr) \ - : "r" (__new) \ - : "memory"); \ - break; \ - default: \ - BUILD_BUG(); \ - } \ - __ret; \ -}) - -#define arch_xchg_relaxed(ptr, x) \ -({ \ - __typeof__(*(ptr)) _x_ = (x); \ - (__typeof__(*(ptr))) __xchg_relaxed((ptr), \ - _x_, sizeof(*(ptr))); \ + __asm__ __volatile__ ( \ + prepend \ + " amoswap" sfx " %0, %2, %1\n" \ + append \ + : "=r" (r), "+A" (*(p)) \ + : "r" (n) \ + : "memory"); \ }) -#define __xchg_acquire(ptr, new, size) \ +#define _arch_xchg(ptr, new, sfx, prepend, append) \ ({ \ __typeof__(ptr) __ptr = (ptr); \ - __typeof__(new) __new = (new); \ - __typeof__(*(ptr)) __ret; \ - switch (size) { \ + __typeof__(*(__ptr)) __new = (new); \ + __typeof__(*(__ptr)) __ret; \ + switch (sizeof(*__ptr)) { \ case 4: \ - __asm__ __volatile__ ( \ - " amoswap.w %0, %2, %1\n" \ - RISCV_ACQUIRE_BARRIER \ - : "=r" (__ret), "+A" (*__ptr) \ - : "r" (__new) \ - : "memory"); \ + __arch_xchg(".w" sfx, prepend, append, \ + __ret, __ptr, __new); \ break; \ case 8: \ - __asm__ __volatile__ ( \ - " amoswap.d %0, %2, %1\n" \ - RISCV_ACQUIRE_BARRIER \ - : "=r" (__ret), "+A" (*__ptr) \ - : "r" (__new) \ - : "memory"); \ + __arch_xchg(".d" sfx, prepend, append, \ + __ret, __ptr, __new); \ break; \ default: \ BUILD_BUG(); \ } \ - __ret; \ + (__typeof__(*(__ptr)))__ret; \ }) -#define arch_xchg_acquire(ptr, x) \ -({ \ - __typeof__(*(ptr)) _x_ = (x); \ - (__typeof__(*(ptr))) __xchg_acquire((ptr), \ - _x_, sizeof(*(ptr))); \ -}) +#define arch_xchg_relaxed(ptr, x) \ + _arch_xchg(ptr, x, "", "", "") -#define __xchg_release(ptr, new, size) \ -({ \ - __typeof__(ptr) __ptr = (ptr); \ - __typeof__(new) __new = (new); \ - __typeof__(*(ptr)) __ret; \ - switch (size) { \ - case 4: \ - __asm__ __volatile__ ( \ - RISCV_RELEASE_BARRIER \ - " amoswap.w %0, %2, %1\n" \ - : "=r" (__ret), "+A" (*__ptr) \ - : "r" (__new) \ - : "memory"); \ - break; \ - case 8: \ - __asm__ __volatile__ ( \ - RISCV_RELEASE_BARRIER \ - " amoswap.d %0, %2, %1\n" \ - : "=r" (__ret), "+A" (*__ptr) \ - : "r" (__new) \ - : "memory"); \ - break; \ - default: \ - BUILD_BUG(); \ - } \ - __ret; \ -}) +#define arch_xchg_acquire(ptr, x) \ + _arch_xchg(ptr, x, "", "", RISCV_ACQUIRE_BARRIER) #define arch_xchg_release(ptr, x) \ -({ \ - __typeof__(*(ptr)) _x_ = (x); \ - (__typeof__(*(ptr))) __xchg_release((ptr), \ - _x_, sizeof(*(ptr))); \ -}) - -#define __arch_xchg(ptr, new, size) \ -({ \ - __typeof__(ptr) __ptr = (ptr); \ - __typeof__(new) __new = (new); \ - __typeof__(*(ptr)) __ret; \ - switch (size) { \ - case 4: \ - __asm__ __volatile__ ( \ - " amoswap.w.aqrl %0, %2, %1\n" \ - : "=r" (__ret), "+A" (*__ptr) \ - : "r" (__new) \ - : "memory"); \ - break; \ - case 8: \ - __asm__ __volatile__ ( \ - " amoswap.d.aqrl %0, %2, %1\n" \ - : "=r" (__ret), "+A" (*__ptr) \ - : "r" (__new) \ - : "memory"); \ - break; \ - default: \ - BUILD_BUG(); \ - } \ - __ret; \ -}) + _arch_xchg(ptr, x, "", RISCV_RELEASE_BARRIER, "") #define arch_xchg(ptr, x) \ -({ \ - __typeof__(*(ptr)) _x_ = (x); \ - (__typeof__(*(ptr))) __arch_xchg((ptr), _x_, sizeof(*(ptr))); \ -}) + _arch_xchg(ptr, x, ".aqrl", "", "") #define xchg32(ptr, x) \ ({ \ -- cgit v1.2.3-59-g8ed1b From 07a0a41cb77d582e4db05bd9e79daa145d5d6ea4 Mon Sep 17 00:00:00 2001 From: Leonardo Bras Date: Wed, 3 Jan 2024 13:32:00 -0300 Subject: riscv/cmpxchg: Deduplicate cmpxchg() asm and macros In this header every cmpxchg define (_relaxed, _acquire, _release, vanilla) contain it's own asm file, both for 4-byte variables an 8-byte variables, on a total of 8 versions of mostly the same asm. This is usually bad, as it means any change may be done in up to 8 different places. Unify those versions by creating a new define with enough parameters to generate any version of the previous 8. Then unify the result under a more general define, and simplify arch_cmpxchg* generation (This did not cause any change in generated asm) Signed-off-by: Leonardo Bras Reviewed-by: Guo Ren Reviewed-by: Andrea Parri Tested-by: Guo Ren Link: https://lore.kernel.org/r/20240103163203.72768-4-leobras@redhat.com Signed-off-by: Palmer Dabbelt --- arch/riscv/include/asm/cmpxchg.h | 195 +++++++-------------------------------- 1 file changed, 33 insertions(+), 162 deletions(-) diff --git a/arch/riscv/include/asm/cmpxchg.h b/arch/riscv/include/asm/cmpxchg.h index 48478a8eecee..e3e0ac7ba061 100644 --- a/arch/riscv/include/asm/cmpxchg.h +++ b/arch/riscv/include/asm/cmpxchg.h @@ -71,190 +71,61 @@ * store NEW in MEM. Return the initial value in MEM. Success is * indicated by comparing RETURN with OLD. */ -#define __cmpxchg_relaxed(ptr, old, new, size) \ -({ \ - __typeof__(ptr) __ptr = (ptr); \ - __typeof__(*(ptr)) __old = (old); \ - __typeof__(*(ptr)) __new = (new); \ - __typeof__(*(ptr)) __ret; \ - register unsigned int __rc; \ - switch (size) { \ - case 4: \ - __asm__ __volatile__ ( \ - "0: lr.w %0, %2\n" \ - " bne %0, %z3, 1f\n" \ - " sc.w %1, %z4, %2\n" \ - " bnez %1, 0b\n" \ - "1:\n" \ - : "=&r" (__ret), "=&r" (__rc), "+A" (*__ptr) \ - : "rJ" ((long)__old), "rJ" (__new) \ - : "memory"); \ - break; \ - case 8: \ - __asm__ __volatile__ ( \ - "0: lr.d %0, %2\n" \ - " bne %0, %z3, 1f\n" \ - " sc.d %1, %z4, %2\n" \ - " bnez %1, 0b\n" \ - "1:\n" \ - : "=&r" (__ret), "=&r" (__rc), "+A" (*__ptr) \ - : "rJ" (__old), "rJ" (__new) \ - : "memory"); \ - break; \ - default: \ - BUILD_BUG(); \ - } \ - __ret; \ -}) -#define arch_cmpxchg_relaxed(ptr, o, n) \ -({ \ - __typeof__(*(ptr)) _o_ = (o); \ - __typeof__(*(ptr)) _n_ = (n); \ - (__typeof__(*(ptr))) __cmpxchg_relaxed((ptr), \ - _o_, _n_, sizeof(*(ptr))); \ -}) -#define __cmpxchg_acquire(ptr, old, new, size) \ +#define __arch_cmpxchg(lr_sfx, sc_sfx, prepend, append, r, p, co, o, n) \ ({ \ - __typeof__(ptr) __ptr = (ptr); \ - __typeof__(*(ptr)) __old = (old); \ - __typeof__(*(ptr)) __new = (new); \ - __typeof__(*(ptr)) __ret; \ register unsigned int __rc; \ - switch (size) { \ - case 4: \ - __asm__ __volatile__ ( \ - "0: lr.w %0, %2\n" \ - " bne %0, %z3, 1f\n" \ - " sc.w %1, %z4, %2\n" \ - " bnez %1, 0b\n" \ - RISCV_ACQUIRE_BARRIER \ - "1:\n" \ - : "=&r" (__ret), "=&r" (__rc), "+A" (*__ptr) \ - : "rJ" ((long)__old), "rJ" (__new) \ - : "memory"); \ - break; \ - case 8: \ - __asm__ __volatile__ ( \ - "0: lr.d %0, %2\n" \ - " bne %0, %z3, 1f\n" \ - " sc.d %1, %z4, %2\n" \ - " bnez %1, 0b\n" \ - RISCV_ACQUIRE_BARRIER \ - "1:\n" \ - : "=&r" (__ret), "=&r" (__rc), "+A" (*__ptr) \ - : "rJ" (__old), "rJ" (__new) \ - : "memory"); \ - break; \ - default: \ - BUILD_BUG(); \ - } \ - __ret; \ -}) - -#define arch_cmpxchg_acquire(ptr, o, n) \ -({ \ - __typeof__(*(ptr)) _o_ = (o); \ - __typeof__(*(ptr)) _n_ = (n); \ - (__typeof__(*(ptr))) __cmpxchg_acquire((ptr), \ - _o_, _n_, sizeof(*(ptr))); \ + \ + __asm__ __volatile__ ( \ + prepend \ + "0: lr" lr_sfx " %0, %2\n" \ + " bne %0, %z3, 1f\n" \ + " sc" sc_sfx " %1, %z4, %2\n" \ + " bnez %1, 0b\n" \ + append \ + "1:\n" \ + : "=&r" (r), "=&r" (__rc), "+A" (*(p)) \ + : "rJ" (co o), "rJ" (n) \ + : "memory"); \ }) -#define __cmpxchg_release(ptr, old, new, size) \ +#define _arch_cmpxchg(ptr, old, new, sc_sfx, prepend, append) \ ({ \ __typeof__(ptr) __ptr = (ptr); \ - __typeof__(*(ptr)) __old = (old); \ - __typeof__(*(ptr)) __new = (new); \ - __typeof__(*(ptr)) __ret; \ - register unsigned int __rc; \ - switch (size) { \ + __typeof__(*(__ptr)) __old = (old); \ + __typeof__(*(__ptr)) __new = (new); \ + __typeof__(*(__ptr)) __ret; \ + \ + switch (sizeof(*__ptr)) { \ case 4: \ - __asm__ __volatile__ ( \ - RISCV_RELEASE_BARRIER \ - "0: lr.w %0, %2\n" \ - " bne %0, %z3, 1f\n" \ - " sc.w %1, %z4, %2\n" \ - " bnez %1, 0b\n" \ - "1:\n" \ - : "=&r" (__ret), "=&r" (__rc), "+A" (*__ptr) \ - : "rJ" ((long)__old), "rJ" (__new) \ - : "memory"); \ + __arch_cmpxchg(".w", ".w" sc_sfx, prepend, append, \ + __ret, __ptr, (long), __old, __new); \ break; \ case 8: \ - __asm__ __volatile__ ( \ - RISCV_RELEASE_BARRIER \ - "0: lr.d %0, %2\n" \ - " bne %0, %z3, 1f\n" \ - " sc.d %1, %z4, %2\n" \ - " bnez %1, 0b\n" \ - "1:\n" \ - : "=&r" (__ret), "=&r" (__rc), "+A" (*__ptr) \ - : "rJ" (__old), "rJ" (__new) \ - : "memory"); \ + __arch_cmpxchg(".d", ".d" sc_sfx, prepend, append, \ + __ret, __ptr, /**/, __old, __new); \ break; \ default: \ BUILD_BUG(); \ } \ - __ret; \ + (__typeof__(*(__ptr)))__ret; \ }) -#define arch_cmpxchg_release(ptr, o, n) \ -({ \ - __typeof__(*(ptr)) _o_ = (o); \ - __typeof__(*(ptr)) _n_ = (n); \ - (__typeof__(*(ptr))) __cmpxchg_release((ptr), \ - _o_, _n_, sizeof(*(ptr))); \ -}) +#define arch_cmpxchg_relaxed(ptr, o, n) \ + _arch_cmpxchg((ptr), (o), (n), "", "", "") -#define __cmpxchg(ptr, old, new, size) \ -({ \ - __typeof__(ptr) __ptr = (ptr); \ - __typeof__(*(ptr)) __old = (old); \ - __typeof__(*(ptr)) __new = (new); \ - __typeof__(*(ptr)) __ret; \ - register unsigned int __rc; \ - switch (size) { \ - case 4: \ - __asm__ __volatile__ ( \ - "0: lr.w %0, %2\n" \ - " bne %0, %z3, 1f\n" \ - " sc.w.rl %1, %z4, %2\n" \ - " bnez %1, 0b\n" \ - " fence rw, rw\n" \ - "1:\n" \ - : "=&r" (__ret), "=&r" (__rc), "+A" (*__ptr) \ - : "rJ" ((long)__old), "rJ" (__new) \ - : "memory"); \ - break; \ - case 8: \ - __asm__ __volatile__ ( \ - "0: lr.d %0, %2\n" \ - " bne %0, %z3, 1f\n" \ - " sc.d.rl %1, %z4, %2\n" \ - " bnez %1, 0b\n" \ - " fence rw, rw\n" \ - "1:\n" \ - : "=&r" (__ret), "=&r" (__rc), "+A" (*__ptr) \ - : "rJ" (__old), "rJ" (__new) \ - : "memory"); \ - break; \ - default: \ - BUILD_BUG(); \ - } \ - __ret; \ -}) +#define arch_cmpxchg_acquire(ptr, o, n) \ + _arch_cmpxchg((ptr), (o), (n), "", "", RISCV_ACQUIRE_BARRIER) + +#define arch_cmpxchg_release(ptr, o, n) \ + _arch_cmpxchg((ptr), (o), (n), "", RISCV_RELEASE_BARRIER, "") #define arch_cmpxchg(ptr, o, n) \ -({ \ - __typeof__(*(ptr)) _o_ = (o); \ - __typeof__(*(ptr)) _n_ = (n); \ - (__typeof__(*(ptr))) __cmpxchg((ptr), \ - _o_, _n_, sizeof(*(ptr))); \ -}) + _arch_cmpxchg((ptr), (o), (n), ".rl", "", " fence rw, rw\n") #define arch_cmpxchg_local(ptr, o, n) \ - (__cmpxchg_relaxed((ptr), (o), (n), sizeof(*(ptr)))) + arch_cmpxchg_relaxed((ptr), (o), (n)) #define arch_cmpxchg64(ptr, o, n) \ ({ \ -- cgit v1.2.3-59-g8ed1b From 9061237392721f0e9b399161876fa36ddb6c4226 Mon Sep 17 00:00:00 2001 From: Leonardo Bras Date: Wed, 3 Jan 2024 13:32:01 -0300 Subject: riscv/atomic.h : Deduplicate arch_atomic.* Some functions use mostly the same asm for 32-bit and 64-bit versions. Make a macro that is generic enough and avoid code duplication. (This did not cause any change in generated asm) Signed-off-by: Leonardo Bras Reviewed-by: Guo Ren Reviewed-by: Andrea Parri Tested-by: Guo Ren Link: https://lore.kernel.org/r/20240103163203.72768-5-leobras@redhat.com Signed-off-by: Palmer Dabbelt --- arch/riscv/include/asm/atomic.h | 164 +++++++++++++++++++--------------------- 1 file changed, 76 insertions(+), 88 deletions(-) diff --git a/arch/riscv/include/asm/atomic.h b/arch/riscv/include/asm/atomic.h index f5dfef6c2153..80cca7ac16fd 100644 --- a/arch/riscv/include/asm/atomic.h +++ b/arch/riscv/include/asm/atomic.h @@ -196,22 +196,28 @@ ATOMIC_OPS(xor, xor, i) #undef ATOMIC_FETCH_OP #undef ATOMIC_OP_RETURN +#define _arch_atomic_fetch_add_unless(_prev, _rc, counter, _a, _u, sfx) \ +({ \ + __asm__ __volatile__ ( \ + "0: lr." sfx " %[p], %[c]\n" \ + " beq %[p], %[u], 1f\n" \ + " add %[rc], %[p], %[a]\n" \ + " sc." sfx ".rl %[rc], %[rc], %[c]\n" \ + " bnez %[rc], 0b\n" \ + " fence rw, rw\n" \ + "1:\n" \ + : [p]"=&r" (_prev), [rc]"=&r" (_rc), [c]"+A" (counter) \ + : [a]"r" (_a), [u]"r" (_u) \ + : "memory"); \ +}) + /* This is required to provide a full barrier on success. */ static __always_inline int arch_atomic_fetch_add_unless(atomic_t *v, int a, int u) { int prev, rc; - __asm__ __volatile__ ( - "0: lr.w %[p], %[c]\n" - " beq %[p], %[u], 1f\n" - " add %[rc], %[p], %[a]\n" - " sc.w.rl %[rc], %[rc], %[c]\n" - " bnez %[rc], 0b\n" - " fence rw, rw\n" - "1:\n" - : [p]"=&r" (prev), [rc]"=&r" (rc), [c]"+A" (v->counter) - : [a]"r" (a), [u]"r" (u) - : "memory"); + _arch_atomic_fetch_add_unless(prev, rc, v->counter, a, u, "w"); + return prev; } #define arch_atomic_fetch_add_unless arch_atomic_fetch_add_unless @@ -222,77 +228,86 @@ static __always_inline s64 arch_atomic64_fetch_add_unless(atomic64_t *v, s64 a, s64 prev; long rc; - __asm__ __volatile__ ( - "0: lr.d %[p], %[c]\n" - " beq %[p], %[u], 1f\n" - " add %[rc], %[p], %[a]\n" - " sc.d.rl %[rc], %[rc], %[c]\n" - " bnez %[rc], 0b\n" - " fence rw, rw\n" - "1:\n" - : [p]"=&r" (prev), [rc]"=&r" (rc), [c]"+A" (v->counter) - : [a]"r" (a), [u]"r" (u) - : "memory"); + _arch_atomic_fetch_add_unless(prev, rc, v->counter, a, u, "d"); + return prev; } #define arch_atomic64_fetch_add_unless arch_atomic64_fetch_add_unless #endif +#define _arch_atomic_inc_unless_negative(_prev, _rc, counter, sfx) \ +({ \ + __asm__ __volatile__ ( \ + "0: lr." sfx " %[p], %[c]\n" \ + " bltz %[p], 1f\n" \ + " addi %[rc], %[p], 1\n" \ + " sc." sfx ".rl %[rc], %[rc], %[c]\n" \ + " bnez %[rc], 0b\n" \ + " fence rw, rw\n" \ + "1:\n" \ + : [p]"=&r" (_prev), [rc]"=&r" (_rc), [c]"+A" (counter) \ + : \ + : "memory"); \ +}) + static __always_inline bool arch_atomic_inc_unless_negative(atomic_t *v) { int prev, rc; - __asm__ __volatile__ ( - "0: lr.w %[p], %[c]\n" - " bltz %[p], 1f\n" - " addi %[rc], %[p], 1\n" - " sc.w.rl %[rc], %[rc], %[c]\n" - " bnez %[rc], 0b\n" - " fence rw, rw\n" - "1:\n" - : [p]"=&r" (prev), [rc]"=&r" (rc), [c]"+A" (v->counter) - : - : "memory"); + _arch_atomic_inc_unless_negative(prev, rc, v->counter, "w"); + return !(prev < 0); } #define arch_atomic_inc_unless_negative arch_atomic_inc_unless_negative +#define _arch_atomic_dec_unless_positive(_prev, _rc, counter, sfx) \ +({ \ + __asm__ __volatile__ ( \ + "0: lr." sfx " %[p], %[c]\n" \ + " bgtz %[p], 1f\n" \ + " addi %[rc], %[p], -1\n" \ + " sc." sfx ".rl %[rc], %[rc], %[c]\n" \ + " bnez %[rc], 0b\n" \ + " fence rw, rw\n" \ + "1:\n" \ + : [p]"=&r" (_prev), [rc]"=&r" (_rc), [c]"+A" (counter) \ + : \ + : "memory"); \ +}) + static __always_inline bool arch_atomic_dec_unless_positive(atomic_t *v) { int prev, rc; - __asm__ __volatile__ ( - "0: lr.w %[p], %[c]\n" - " bgtz %[p], 1f\n" - " addi %[rc], %[p], -1\n" - " sc.w.rl %[rc], %[rc], %[c]\n" - " bnez %[rc], 0b\n" - " fence rw, rw\n" - "1:\n" - : [p]"=&r" (prev), [rc]"=&r" (rc), [c]"+A" (v->counter) - : - : "memory"); + _arch_atomic_dec_unless_positive(prev, rc, v->counter, "w"); + return !(prev > 0); } #define arch_atomic_dec_unless_positive arch_atomic_dec_unless_positive +#define _arch_atomic_dec_if_positive(_prev, _rc, counter, sfx) \ +({ \ + __asm__ __volatile__ ( \ + "0: lr." sfx " %[p], %[c]\n" \ + " addi %[rc], %[p], -1\n" \ + " bltz %[rc], 1f\n" \ + " sc." sfx ".rl %[rc], %[rc], %[c]\n" \ + " bnez %[rc], 0b\n" \ + " fence rw, rw\n" \ + "1:\n" \ + : [p]"=&r" (_prev), [rc]"=&r" (_rc), [c]"+A" (counter) \ + : \ + : "memory"); \ +}) + static __always_inline int arch_atomic_dec_if_positive(atomic_t *v) { int prev, rc; - __asm__ __volatile__ ( - "0: lr.w %[p], %[c]\n" - " addi %[rc], %[p], -1\n" - " bltz %[rc], 1f\n" - " sc.w.rl %[rc], %[rc], %[c]\n" - " bnez %[rc], 0b\n" - " fence rw, rw\n" - "1:\n" - : [p]"=&r" (prev), [rc]"=&r" (rc), [c]"+A" (v->counter) - : - : "memory"); + _arch_atomic_dec_if_positive(prev, rc, v->counter, "w"); + return prev - 1; } @@ -304,17 +319,8 @@ static __always_inline bool arch_atomic64_inc_unless_negative(atomic64_t *v) s64 prev; long rc; - __asm__ __volatile__ ( - "0: lr.d %[p], %[c]\n" - " bltz %[p], 1f\n" - " addi %[rc], %[p], 1\n" - " sc.d.rl %[rc], %[rc], %[c]\n" - " bnez %[rc], 0b\n" - " fence rw, rw\n" - "1:\n" - : [p]"=&r" (prev), [rc]"=&r" (rc), [c]"+A" (v->counter) - : - : "memory"); + _arch_atomic_inc_unless_negative(prev, rc, v->counter, "d"); + return !(prev < 0); } @@ -325,17 +331,8 @@ static __always_inline bool arch_atomic64_dec_unless_positive(atomic64_t *v) s64 prev; long rc; - __asm__ __volatile__ ( - "0: lr.d %[p], %[c]\n" - " bgtz %[p], 1f\n" - " addi %[rc], %[p], -1\n" - " sc.d.rl %[rc], %[rc], %[c]\n" - " bnez %[rc], 0b\n" - " fence rw, rw\n" - "1:\n" - : [p]"=&r" (prev), [rc]"=&r" (rc), [c]"+A" (v->counter) - : - : "memory"); + _arch_atomic_dec_unless_positive(prev, rc, v->counter, "d"); + return !(prev > 0); } @@ -346,17 +343,8 @@ static __always_inline s64 arch_atomic64_dec_if_positive(atomic64_t *v) s64 prev; long rc; - __asm__ __volatile__ ( - "0: lr.d %[p], %[c]\n" - " addi %[rc], %[p], -1\n" - " bltz %[rc], 1f\n" - " sc.d.rl %[rc], %[rc], %[c]\n" - " bnez %[rc], 0b\n" - " fence rw, rw\n" - "1:\n" - : [p]"=&r" (prev), [rc]"=&r" (rc), [c]"+A" (v->counter) - : - : "memory"); + _arch_atomic_dec_if_positive(prev, rc, v->counter, "d"); + return prev - 1; } -- cgit v1.2.3-59-g8ed1b From 54280ca64626f73ce39ba8f7befa9139a6786ffd Mon Sep 17 00:00:00 2001 From: Leonardo Bras Date: Wed, 3 Jan 2024 13:32:02 -0300 Subject: riscv/cmpxchg: Implement cmpxchg for variables of size 1 and 2 cmpxchg for variables of size 1-byte and 2-bytes is not yet available for riscv, even though its present in other architectures such as arm64 and x86. This could lead to not being able to implement some locking mechanisms or requiring some rework to make it work properly. Implement 1-byte and 2-bytes cmpxchg in order to achieve parity with other architectures. Signed-off-by: Leonardo Bras Tested-by: Guo Ren Link: https://lore.kernel.org/r/20240103163203.72768-6-leobras@redhat.com Signed-off-by: Palmer Dabbelt --- arch/riscv/include/asm/cmpxchg.h | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/arch/riscv/include/asm/cmpxchg.h b/arch/riscv/include/asm/cmpxchg.h index e3e0ac7ba061..ac9d0eeb74e6 100644 --- a/arch/riscv/include/asm/cmpxchg.h +++ b/arch/riscv/include/asm/cmpxchg.h @@ -72,6 +72,35 @@ * indicated by comparing RETURN with OLD. */ +#define __arch_cmpxchg_masked(sc_sfx, prepend, append, r, p, o, n) \ +({ \ + u32 *__ptr32b = (u32 *)((ulong)(p) & ~0x3); \ + ulong __s = ((ulong)(p) & (0x4 - sizeof(*p))) * BITS_PER_BYTE; \ + ulong __mask = GENMASK(((sizeof(*p)) * BITS_PER_BYTE) - 1, 0) \ + << __s; \ + ulong __newx = (ulong)(n) << __s; \ + ulong __oldx = (ulong)(o) << __s; \ + ulong __retx; \ + ulong __rc; \ + \ + __asm__ __volatile__ ( \ + prepend \ + "0: lr.w %0, %2\n" \ + " and %1, %0, %z5\n" \ + " bne %1, %z3, 1f\n" \ + " and %1, %0, %z6\n" \ + " or %1, %1, %z4\n" \ + " sc.w" sc_sfx " %1, %1, %2\n" \ + " bnez %1, 0b\n" \ + append \ + "1:\n" \ + : "=&r" (__retx), "=&r" (__rc), "+A" (*(__ptr32b)) \ + : "rJ" ((long)__oldx), "rJ" (__newx), \ + "rJ" (__mask), "rJ" (~__mask) \ + : "memory"); \ + \ + r = (__typeof__(*(p)))((__retx & __mask) >> __s); \ +}) #define __arch_cmpxchg(lr_sfx, sc_sfx, prepend, append, r, p, co, o, n) \ ({ \ @@ -98,6 +127,11 @@ __typeof__(*(__ptr)) __ret; \ \ switch (sizeof(*__ptr)) { \ + case 1: \ + case 2: \ + __arch_cmpxchg_masked(sc_sfx, prepend, append, \ + __ret, __ptr, __old, __new); \ + break; \ case 4: \ __arch_cmpxchg(".w", ".w" sc_sfx, prepend, append, \ __ret, __ptr, (long), __old, __new); \ -- cgit v1.2.3-59-g8ed1b From a8ed2b7a2c13cb8a613cc9a8862688a1385b942d Mon Sep 17 00:00:00 2001 From: Leonardo Bras Date: Wed, 3 Jan 2024 13:32:03 -0300 Subject: riscv/cmpxchg: Implement xchg for variables of size 1 and 2 xchg for variables of size 1-byte and 2-bytes is not yet available for riscv, even though its present in other architectures such as arm64 and x86. This could lead to not being able to implement some locking mechanisms or requiring some rework to make it work properly. Implement 1-byte and 2-bytes xchg in order to achieve parity with other architectures. Signed-off-by: Leonardo Bras Tested-by: Guo Ren Link: https://lore.kernel.org/r/20240103163203.72768-7-leobras@redhat.com Signed-off-by: Palmer Dabbelt --- arch/riscv/include/asm/cmpxchg.h | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/arch/riscv/include/asm/cmpxchg.h b/arch/riscv/include/asm/cmpxchg.h index ac9d0eeb74e6..26cea2395aae 100644 --- a/arch/riscv/include/asm/cmpxchg.h +++ b/arch/riscv/include/asm/cmpxchg.h @@ -11,6 +11,31 @@ #include #include +#define __arch_xchg_masked(prepend, append, r, p, n) \ +({ \ + u32 *__ptr32b = (u32 *)((ulong)(p) & ~0x3); \ + ulong __s = ((ulong)(p) & (0x4 - sizeof(*p))) * BITS_PER_BYTE; \ + ulong __mask = GENMASK(((sizeof(*p)) * BITS_PER_BYTE) - 1, 0) \ + << __s; \ + ulong __newx = (ulong)(n) << __s; \ + ulong __retx; \ + ulong __rc; \ + \ + __asm__ __volatile__ ( \ + prepend \ + "0: lr.w %0, %2\n" \ + " and %1, %0, %z4\n" \ + " or %1, %1, %z3\n" \ + " sc.w %1, %1, %2\n" \ + " bnez %1, 0b\n" \ + append \ + : "=&r" (__retx), "=&r" (__rc), "+A" (*(__ptr32b)) \ + : "rJ" (__newx), "rJ" (~__mask) \ + : "memory"); \ + \ + r = (__typeof__(*(p)))((__retx & __mask) >> __s); \ +}) + #define __arch_xchg(sfx, prepend, append, r, p, n) \ ({ \ __asm__ __volatile__ ( \ @@ -27,7 +52,13 @@ __typeof__(ptr) __ptr = (ptr); \ __typeof__(*(__ptr)) __new = (new); \ __typeof__(*(__ptr)) __ret; \ + \ switch (sizeof(*__ptr)) { \ + case 1: \ + case 2: \ + __arch_xchg_masked(prepend, append, \ + __ret, __ptr, __new); \ + break; \ case 4: \ __arch_xchg(".w" sfx, prepend, append, \ __ret, __ptr, __new); \ -- cgit v1.2.3-59-g8ed1b From 218c200f677d8af46a8540319e4d26c52b3277a5 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Mon, 1 Apr 2024 14:08:05 -0700 Subject: perf script: Consolidate capstone print functions Consolidate capstone print functions, to reduce duplication. Amend call sites to use a file pointer for output, which is consistent with most perf tools print functions. Add print_opts with an option to print also the hex value of a resolved symbol+offset. Signed-off-by: Adrian Hunter Link: https://lore.kernel.org/r/20240401210925.209671-4-ak@linux.intel.com Signed-off-by: Andi Kleen [ Added missing inttypes.h include to use PRIx64 in util/print_insn.c ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-script.c | 43 +++++++++++------- tools/perf/util/print_insn.c | 104 +++++++++++++++---------------------------- tools/perf/util/print_insn.h | 7 ++- 3 files changed, 68 insertions(+), 86 deletions(-) diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index dd10f158ed0c..647cb31a47c8 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -1165,18 +1165,29 @@ out: return ret; } -static const char *any_dump_insn(struct perf_event_attr *attr __maybe_unused, - struct perf_insn *x, uint64_t ip, - u8 *inbuf, int inlen, int *lenp) +static int any_dump_insn(struct perf_event_attr *attr __maybe_unused, + struct perf_insn *x, uint64_t ip, + u8 *inbuf, int inlen, int *lenp, + FILE *fp) { #ifdef HAVE_LIBCAPSTONE_SUPPORT if (PRINT_FIELD(BRSTACKDISASM)) { - const char *p = cs_dump_insn(x, ip, inbuf, inlen, lenp); - if (p) - return p; + int printed = fprintf_insn_asm(x->machine, x->thread, x->cpumode, x->is64bit, + (uint8_t *)inbuf, inlen, ip, lenp, + PRINT_INSN_IMM_HEX, fp); + + if (printed > 0) + return printed; } #endif - return dump_insn(x, ip, inbuf, inlen, lenp); + return fprintf(fp, "%s", dump_insn(x, ip, inbuf, inlen, lenp)); +} + +static int add_padding(FILE *fp, int printed, int padding) +{ + if (printed >= 0 && printed < padding) + printed += fprintf(fp, "%*s", padding - printed, ""); + return printed; } static int ip__fprintf_jump(uint64_t ip, struct branch_entry *en, @@ -1186,8 +1197,10 @@ static int ip__fprintf_jump(uint64_t ip, struct branch_entry *en, struct thread *thread) { int ilen = 0; - int printed = fprintf(fp, "\t%016" PRIx64 "\t%-30s\t", ip, - any_dump_insn(attr, x, ip, inbuf, len, &ilen)); + int printed = fprintf(fp, "\t%016" PRIx64 "\t", ip); + + printed += add_padding(fp, any_dump_insn(attr, x, ip, inbuf, len, &ilen, fp), 30); + printed += fprintf(fp, "\t"); if (PRINT_FIELD(BRSTACKINSNLEN)) printed += fprintf(fp, "ilen: %d\t", ilen); @@ -1330,8 +1343,8 @@ static int perf_sample__fprintf_brstackinsn(struct perf_sample *sample, break; } else { ilen = 0; - printed += fprintf(fp, "\t%016" PRIx64 "\t%s", ip, - any_dump_insn(attr, &x, ip, buffer + off, len - off, &ilen)); + printed += fprintf(fp, "\t%016" PRIx64 "\t", ip); + printed += any_dump_insn(attr, &x, ip, buffer + off, len - off, &ilen, fp); if (PRINT_FIELD(BRSTACKINSNLEN)) printed += fprintf(fp, "\tilen: %d", ilen); printed += fprintf(fp, "\n"); @@ -1378,8 +1391,8 @@ static int perf_sample__fprintf_brstackinsn(struct perf_sample *sample, if (len <= 0) goto out; ilen = 0; - printed += fprintf(fp, "\t%016" PRIx64 "\t%s", sample->ip, - any_dump_insn(attr, &x, sample->ip, buffer, len, &ilen)); + printed += fprintf(fp, "\t%016" PRIx64 "\t", sample->ip); + printed += any_dump_insn(attr, &x, sample->ip, buffer, len, &ilen, fp); if (PRINT_FIELD(BRSTACKINSNLEN)) printed += fprintf(fp, "\tilen: %d", ilen); printed += fprintf(fp, "\n"); @@ -1389,8 +1402,8 @@ static int perf_sample__fprintf_brstackinsn(struct perf_sample *sample, } for (off = 0; off <= end - start; off += ilen) { ilen = 0; - printed += fprintf(fp, "\t%016" PRIx64 "\t%s", start + off, - any_dump_insn(attr, &x, start + off, buffer + off, len - off, &ilen)); + printed += fprintf(fp, "\t%016" PRIx64 "\t", start + off); + printed += any_dump_insn(attr, &x, start + off, buffer + off, len - off, &ilen, fp); if (PRINT_FIELD(BRSTACKINSNLEN)) printed += fprintf(fp, "\tilen: %d", ilen); printed += fprintf(fp, "\n"); diff --git a/tools/perf/util/print_insn.c b/tools/perf/util/print_insn.c index 8825330d435f..aab11d8e1b1d 100644 --- a/tools/perf/util/print_insn.c +++ b/tools/perf/util/print_insn.c @@ -4,6 +4,7 @@ * * Author(s): Changbin Du */ +#include #include #include #include "debug.h" @@ -72,59 +73,8 @@ static int capstone_init(struct machine *machine, csh *cs_handle, bool is64) return 0; } -static void dump_insn_x86(struct thread *thread, cs_insn *insn, struct perf_insn *x) -{ - struct addr_location al; - bool printed = false; - - if (insn->detail && insn->detail->x86.op_count == 1) { - cs_x86_op *op = &insn->detail->x86.operands[0]; - - addr_location__init(&al); - if (op->type == X86_OP_IMM && - thread__find_symbol(thread, x->cpumode, op->imm, &al) && - al.sym && - al.addr < al.sym->end) { - snprintf(x->out, sizeof(x->out), "%s %s+%#" PRIx64 " [%#" PRIx64 "]", insn[0].mnemonic, - al.sym->name, al.addr - al.sym->start, op->imm); - printed = true; - } - addr_location__exit(&al); - } - - if (!printed) - snprintf(x->out, sizeof(x->out), "%s %s", insn[0].mnemonic, insn[0].op_str); -} - -const char *cs_dump_insn(struct perf_insn *x, uint64_t ip, - u8 *inbuf, int inlen, int *lenp) -{ - int ret; - int count; - cs_insn *insn; - csh cs_handle; - - ret = capstone_init(x->machine, &cs_handle, x->is64bit); - if (ret < 0) - return NULL; - - count = cs_disasm(cs_handle, (uint8_t *)inbuf, inlen, ip, 1, &insn); - if (count > 0) { - if (machine__normalized_is(x->machine, "x86")) - dump_insn_x86(x->thread, &insn[0], x); - else - snprintf(x->out, sizeof(x->out), "%s %s", - insn[0].mnemonic, insn[0].op_str); - *lenp = insn->size; - cs_free(insn, count); - } else { - return NULL; - } - return x->out; -} - -static size_t print_insn_x86(struct perf_sample *sample, struct thread *thread, - cs_insn *insn, FILE *fp) +static size_t print_insn_x86(struct thread *thread, u8 cpumode, cs_insn *insn, + int print_opts, FILE *fp) { struct addr_location al; size_t printed = 0; @@ -134,9 +84,11 @@ static size_t print_insn_x86(struct perf_sample *sample, struct thread *thread, addr_location__init(&al); if (op->type == X86_OP_IMM && - thread__find_symbol(thread, sample->cpumode, op->imm, &al)) { + thread__find_symbol(thread, cpumode, op->imm, &al)) { printed += fprintf(fp, "%s ", insn[0].mnemonic); printed += symbol__fprintf_symname_offs(al.sym, &al, fp); + if (print_opts & PRINT_INSN_IMM_HEX) + printed += fprintf(fp, " [%#" PRIx64 "]", op->imm); addr_location__exit(&al); return printed; } @@ -159,39 +111,53 @@ static bool is64bitip(struct machine *machine, struct addr_location *al) machine__normalized_is(machine, "s390"); } -size_t sample__fprintf_insn_asm(struct perf_sample *sample, struct thread *thread, - struct machine *machine, FILE *fp, - struct addr_location *al) +ssize_t fprintf_insn_asm(struct machine *machine, struct thread *thread, u8 cpumode, + bool is64bit, const uint8_t *code, size_t code_size, + uint64_t ip, int *lenp, int print_opts, FILE *fp) { - csh cs_handle; + size_t printed; cs_insn *insn; + csh cs_handle; size_t count; - size_t printed = 0; int ret; - bool is64bit = is64bitip(machine, al); /* TODO: Try to initiate capstone only once but need a proper place. */ ret = capstone_init(machine, &cs_handle, is64bit); - if (ret < 0) { - /* fallback */ - return sample__fprintf_insn_raw(sample, fp); - } + if (ret < 0) + return ret; - count = cs_disasm(cs_handle, (uint8_t *)sample->insn, sample->insn_len, - sample->ip, 1, &insn); + count = cs_disasm(cs_handle, code, code_size, ip, 1, &insn); if (count > 0) { if (machine__normalized_is(machine, "x86")) - printed += print_insn_x86(sample, thread, &insn[0], fp); + printed = print_insn_x86(thread, cpumode, &insn[0], print_opts, fp); else - printed += fprintf(fp, "%s %s", insn[0].mnemonic, insn[0].op_str); + printed = fprintf(fp, "%s %s", insn[0].mnemonic, insn[0].op_str); + if (lenp) + *lenp = insn->size; cs_free(insn, count); } else { - printed += fprintf(fp, "illegal instruction"); + printed = -1; } cs_close(&cs_handle); return printed; } + +size_t sample__fprintf_insn_asm(struct perf_sample *sample, struct thread *thread, + struct machine *machine, FILE *fp, + struct addr_location *al) +{ + bool is64bit = is64bitip(machine, al); + ssize_t printed; + + printed = fprintf_insn_asm(machine, thread, sample->cpumode, is64bit, + (uint8_t *)sample->insn, sample->insn_len, + sample->ip, NULL, 0, fp); + if (printed < 0) + return sample__fprintf_insn_raw(sample, fp); + + return printed; +} #else size_t sample__fprintf_insn_asm(struct perf_sample *sample __maybe_unused, struct thread *thread __maybe_unused, diff --git a/tools/perf/util/print_insn.h b/tools/perf/util/print_insn.h index c2a6391a45ce..07d11af3fc1c 100644 --- a/tools/perf/util/print_insn.h +++ b/tools/perf/util/print_insn.h @@ -10,10 +10,13 @@ struct thread; struct machine; struct perf_insn; +#define PRINT_INSN_IMM_HEX (1<<0) + size_t sample__fprintf_insn_asm(struct perf_sample *sample, struct thread *thread, struct machine *machine, FILE *fp, struct addr_location *al); size_t sample__fprintf_insn_raw(struct perf_sample *sample, FILE *fp); -const char *cs_dump_insn(struct perf_insn *x, uint64_t ip, - u8 *inbuf, int inlen, int *lenp); +ssize_t fprintf_insn_asm(struct machine *machine, struct thread *thread, u8 cpumode, + bool is64bit, const uint8_t *code, size_t code_size, + uint64_t ip, int *lenp, int print_opts, FILE *fp); #endif /* PERF_PRINT_INSN_H */ -- cgit v1.2.3-59-g8ed1b From aaf494cf483a1a835c44e942861429b30a00cab0 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Thu, 4 Apr 2024 10:57:08 -0700 Subject: perf annotate: Fix annotation_calc_lines() to pass correct address to get_srcline() It should pass a proper address (i.e. suitable for objdump or addr2line) to get_srcline() in order to work correctly. It used to pass an address with map__rip_2objdump() as the second argument but later it's changed to use notes->start. It's ok in normal cases but it can be changed when annotate_opts.full_addr is set. So let's convert the address directly instead of using the notes->start. Also the last argument is an IP to print symbol offset if requested. So it should pass symbol-relative address. Fixes: 7d18a824b5e57ddd ("perf annotate: Toggle full address <-> offset display") Signed-off-by: Namhyung Kim Cc: Adrian Hunter Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Namhyung Kim Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20240404175716.1225482-2-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 35235147b111..a330e92c2552 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -1440,7 +1440,7 @@ void annotation__toggle_full_addr(struct annotation *notes, struct map_symbol *m annotation__update_column_widths(notes); } -static void annotation__calc_lines(struct annotation *notes, struct map *map, +static void annotation__calc_lines(struct annotation *notes, struct map_symbol *ms, struct rb_root *root) { struct annotation_line *al; @@ -1448,6 +1448,7 @@ static void annotation__calc_lines(struct annotation *notes, struct map *map, list_for_each_entry(al, ¬es->src->source, node) { double percent_max = 0.0; + u64 addr; int i; for (i = 0; i < al->data_nr; i++) { @@ -1463,8 +1464,9 @@ static void annotation__calc_lines(struct annotation *notes, struct map *map, if (percent_max <= 0.5) continue; - al->path = get_srcline(map__dso(map), notes->start + al->offset, NULL, - false, true, notes->start + al->offset); + addr = map__rip_2objdump(ms->map, ms->sym->start); + al->path = get_srcline(map__dso(ms->map), addr + al->offset, NULL, + false, true, ms->sym->start + al->offset); insert_source_line(&tmp_root, al); } @@ -1475,7 +1477,7 @@ static void symbol__calc_lines(struct map_symbol *ms, struct rb_root *root) { struct annotation *notes = symbol__annotation(ms->sym); - annotation__calc_lines(notes, ms->map, root); + annotation__calc_lines(notes, ms, root); } int symbol__tty_annotate2(struct map_symbol *ms, struct evsel *evsel) -- cgit v1.2.3-59-g8ed1b From bfd98ceb6267712ae298f10144ba0576cc03c70f Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Thu, 4 Apr 2024 10:57:09 -0700 Subject: perf annotate: Staticize some local functions I found annotation__mark_jump_targets(), annotation__set_offsets() and annotation__init_column_widths() are only used in the same file. Let's make them static. Signed-off-by: Namhyung Kim Cc: Adrian Hunter Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20240404175716.1225482-3-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 8 +++++--- tools/perf/util/annotate.h | 3 --- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index a330e92c2552..bbf4894b1309 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -1316,7 +1316,8 @@ bool disasm_line__is_valid_local_jump(struct disasm_line *dl, struct symbol *sym return true; } -void annotation__mark_jump_targets(struct annotation *notes, struct symbol *sym) +static void +annotation__mark_jump_targets(struct annotation *notes, struct symbol *sym) { u64 offset, size = symbol__size(sym); @@ -1347,7 +1348,7 @@ void annotation__mark_jump_targets(struct annotation *notes, struct symbol *sym) } } -void annotation__set_offsets(struct annotation *notes, s64 size) +static void annotation__set_offsets(struct annotation *notes, s64 size) { struct annotation_line *al; struct annotated_source *src = notes->src; @@ -1404,7 +1405,8 @@ static int annotation__max_ins_name(struct annotation *notes) return max_name; } -void annotation__init_column_widths(struct annotation *notes, struct symbol *sym) +static void +annotation__init_column_widths(struct annotation *notes, struct symbol *sym) { notes->widths.addr = notes->widths.target = notes->widths.min_addr = hex_width(symbol__size(sym)); diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index b3007c9966fd..3f383f38f65f 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -340,10 +340,7 @@ static inline bool annotation_line__filter(struct annotation_line *al) return annotate_opts.hide_src_code && al->offset == -1; } -void annotation__set_offsets(struct annotation *notes, s64 size); -void annotation__mark_jump_targets(struct annotation *notes, struct symbol *sym); void annotation__update_column_widths(struct annotation *notes); -void annotation__init_column_widths(struct annotation *notes, struct symbol *sym); void annotation__toggle_full_addr(struct annotation *notes, struct map_symbol *ms); static inline struct sym_hist *annotated_source__histogram(struct annotated_source *src, int idx) -- cgit v1.2.3-59-g8ed1b From 6f157d9af1e42aafa469deb7c16203e39a2f9545 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Thu, 4 Apr 2024 10:57:10 -0700 Subject: perf annotate: Introduce annotated_source__get_line() It's a helper function to get annotation_line at the given offset without using the offsets array. The goal is to get rid of the offsets array altogether. It just does the linear search but I think it's better to save memory as it won't be called in a hot path. Signed-off-by: Namhyung Kim Cc: Adrian Hunter Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20240404175716.1225482-4-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 2 +- tools/perf/util/annotate.c | 26 +++++++++++++++++++++----- tools/perf/util/annotate.h | 3 +++ 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index ec5e21932876..e72583f37972 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -186,7 +186,7 @@ static void annotate_browser__draw_current_jump(struct ui_browser *browser) * name right after the '<' token and probably treating this like a * 'call' instruction. */ - target = notes->src->offsets[cursor->ops.target.offset]; + target = annotated_source__get_line(notes->src, cursor->ops.target.offset); if (target == NULL) { ui_helpline__printf("WARN: jump target inconsistency, press 'o', notes->offsets[%#x] = NULL\n", cursor->ops.target.offset); diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index bbf4894b1309..2409d7424c71 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -369,13 +369,25 @@ int addr_map_symbol__account_cycles(struct addr_map_symbol *ams, return err; } +struct annotation_line *annotated_source__get_line(struct annotated_source *src, + s64 offset) +{ + struct annotation_line *al; + + list_for_each_entry(al, &src->source, node) { + if (al->offset == offset) + return al; + } + return NULL; +} + static unsigned annotation__count_insn(struct annotation *notes, u64 start, u64 end) { unsigned n_insn = 0; u64 offset; for (offset = start; offset <= end; offset++) { - if (notes->src->offsets[offset]) + if (annotated_source__get_line(notes->src, offset)) n_insn++; } return n_insn; @@ -405,8 +417,9 @@ static void annotation__count_and_fill(struct annotation *notes, u64 start, u64 return; for (offset = start; offset <= end; offset++) { - struct annotation_line *al = notes->src->offsets[offset]; + struct annotation_line *al; + al = annotated_source__get_line(notes->src, offset); if (al && al->cycles && al->cycles->ipc == 0.0) { al->cycles->ipc = ipc; cover_insn++; @@ -443,7 +456,7 @@ static int annotation__compute_ipc(struct annotation *notes, size_t size) if (ch && ch->cycles) { struct annotation_line *al; - al = notes->src->offsets[offset]; + al = annotated_source__get_line(notes->src, offset); if (al && al->cycles == NULL) { al->cycles = zalloc(sizeof(*al->cycles)); if (al->cycles == NULL) { @@ -466,7 +479,9 @@ static int annotation__compute_ipc(struct annotation *notes, size_t size) struct cyc_hist *ch = ¬es->branch->cycles_hist[offset]; if (ch && ch->cycles) { - struct annotation_line *al = notes->src->offsets[offset]; + struct annotation_line *al; + + al = annotated_source__get_line(notes->src, offset); if (al) zfree(&al->cycles); } @@ -1326,9 +1341,10 @@ annotation__mark_jump_targets(struct annotation *notes, struct symbol *sym) return; for (offset = 0; offset < size; ++offset) { - struct annotation_line *al = notes->src->offsets[offset]; + struct annotation_line *al; struct disasm_line *dl; + al = annotated_source__get_line(notes->src, offset); dl = disasm_line(al); if (!disasm_line__is_valid_local_jump(dl, sym)) diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 3f383f38f65f..aa3298c20300 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -270,6 +270,9 @@ struct annotated_source { u16 max_line_len; }; +struct annotation_line *annotated_source__get_line(struct annotated_source *src, + s64 offset); + /** * struct annotated_branch - basic block and IPC information for a symbol. * -- cgit v1.2.3-59-g8ed1b From 0c053ed27303660140ee5e9a82c06f923d4f9c73 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Thu, 4 Apr 2024 10:57:11 -0700 Subject: perf annotate: Check annotation lines more efficiently In some places, it checks annotated (disasm) lines for each byte. But as it already has a list of disasm lines, it'd be better to traverse the list entries instead of checking every offset with linear search (by annotated_source__get_line() helper). Signed-off-by: Namhyung Kim Cc: Adrian Hunter Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20240404175716.1225482-5-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 56 +++++++++++++++++++++++++++++----------------- 1 file changed, 35 insertions(+), 21 deletions(-) diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 2409d7424c71..d98fc248ba5b 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -383,12 +383,19 @@ struct annotation_line *annotated_source__get_line(struct annotated_source *src, static unsigned annotation__count_insn(struct annotation *notes, u64 start, u64 end) { + struct annotation_line *al; unsigned n_insn = 0; - u64 offset; - for (offset = start; offset <= end; offset++) { - if (annotated_source__get_line(notes->src, offset)) - n_insn++; + al = annotated_source__get_line(notes->src, start); + if (al == NULL) + return 0; + + list_for_each_entry_from(al, ¬es->src->source, node) { + if (al->offset == -1) + continue; + if ((u64)al->offset > end) + break; + n_insn++; } return n_insn; } @@ -405,10 +412,10 @@ static void annotation__count_and_fill(struct annotation *notes, u64 start, u64 { unsigned n_insn; unsigned int cover_insn = 0; - u64 offset; n_insn = annotation__count_insn(notes, start, end); if (n_insn && ch->num && ch->cycles) { + struct annotation_line *al; struct annotated_branch *branch; float ipc = n_insn / ((double)ch->cycles / (double)ch->num); @@ -416,11 +423,16 @@ static void annotation__count_and_fill(struct annotation *notes, u64 start, u64 if (ch->reset >= 0x7fff) return; - for (offset = start; offset <= end; offset++) { - struct annotation_line *al; + al = annotated_source__get_line(notes->src, start); + if (al == NULL) + return; - al = annotated_source__get_line(notes->src, offset); - if (al && al->cycles && al->cycles->ipc == 0.0) { + list_for_each_entry_from(al, ¬es->src->source, node) { + if (al->offset == -1) + continue; + if ((u64)al->offset > end) + break; + if (al->cycles && al->cycles->ipc == 0.0) { al->cycles->ipc = ipc; cover_insn++; } @@ -1268,13 +1280,16 @@ void symbol__annotate_decay_histogram(struct symbol *sym, int evidx) { struct annotation *notes = symbol__annotation(sym); struct sym_hist *h = annotation__histogram(notes, evidx); - int len = symbol__size(sym), offset; + struct annotation_line *al; h->nr_samples = 0; - for (offset = 0; offset < len; ++offset) { + list_for_each_entry(al, ¬es->src->source, node) { struct sym_hist_entry *entry; - entry = annotated_source__hist_entry(notes->src, evidx, offset); + if (al->offset == -1) + continue; + + entry = annotated_source__hist_entry(notes->src, evidx, al->offset); if (entry == NULL) continue; @@ -1334,33 +1349,32 @@ bool disasm_line__is_valid_local_jump(struct disasm_line *dl, struct symbol *sym static void annotation__mark_jump_targets(struct annotation *notes, struct symbol *sym) { - u64 offset, size = symbol__size(sym); + struct annotation_line *al; /* PLT symbols contain external offsets */ if (strstr(sym->name, "@plt")) return; - for (offset = 0; offset < size; ++offset) { - struct annotation_line *al; + list_for_each_entry(al, ¬es->src->source, node) { struct disasm_line *dl; + struct annotation_line *target; - al = annotated_source__get_line(notes->src, offset); dl = disasm_line(al); if (!disasm_line__is_valid_local_jump(dl, sym)) continue; - al = notes->src->offsets[dl->ops.target.offset]; - + target = annotated_source__get_line(notes->src, + dl->ops.target.offset); /* * FIXME: Oops, no jump target? Buggy disassembler? Or do we * have to adjust to the previous offset? */ - if (al == NULL) + if (target == NULL) continue; - if (++al->jump_sources > notes->max_jump_sources) - notes->max_jump_sources = al->jump_sources; + if (++target->jump_sources > notes->max_jump_sources) + notes->max_jump_sources = target->jump_sources; } } -- cgit v1.2.3-59-g8ed1b From cee9b86043d3690bc9154dabe13e7d53ca44ef9b Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Thu, 4 Apr 2024 10:57:12 -0700 Subject: perf annotate: Get rid of offsets array The struct annotated_source.offsets[] is to save pointers to annotation_line at each offset. We can use annotated_source__get_line() helper instead so let's get rid of the array. Signed-off-by: Namhyung Kim Cc: Adrian Hunter Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20240404175716.1225482-6-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 5 +---- tools/perf/util/annotate.c | 29 ++++++----------------------- tools/perf/util/annotate.h | 2 -- 3 files changed, 7 insertions(+), 29 deletions(-) diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index e72583f37972..c93da2ce727f 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -977,7 +977,7 @@ int symbol__tui_annotate(struct map_symbol *ms, struct evsel *evsel, dso->annotate_warned = true; symbol__strerror_disassemble(ms, err, msg, sizeof(msg)); ui__error("Couldn't annotate %s:\n%s", sym->name, msg); - goto out_free_offsets; + return -1; } } @@ -996,8 +996,5 @@ int symbol__tui_annotate(struct map_symbol *ms, struct evsel *evsel, if(not_annotated) annotated_source__purge(notes->src); -out_free_offsets: - if(not_annotated) - zfree(¬es->src->offsets); return ret; } diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index d98fc248ba5b..0e8319835986 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -1378,7 +1378,7 @@ annotation__mark_jump_targets(struct annotation *notes, struct symbol *sym) } } -static void annotation__set_offsets(struct annotation *notes, s64 size) +static void annotation__set_index(struct annotation *notes) { struct annotation_line *al; struct annotated_source *src = notes->src; @@ -1393,18 +1393,9 @@ static void annotation__set_offsets(struct annotation *notes, s64 size) if (src->max_line_len < line_len) src->max_line_len = line_len; al->idx = src->nr_entries++; - if (al->offset != -1) { + if (al->offset != -1) al->idx_asm = src->nr_asm_entries++; - /* - * FIXME: short term bandaid to cope with assembly - * routines that comes with labels in the same column - * as the address in objdump, sigh. - * - * E.g. copy_user_generic_unrolled - */ - if (al->offset < size) - notes->src->offsets[al->offset] = al; - } else + else al->idx_asm = -1; } } @@ -1835,25 +1826,21 @@ int symbol__annotate2(struct map_symbol *ms, struct evsel *evsel, size_t size = symbol__size(sym); int nr_pcnt = 1, err; - notes->src->offsets = zalloc(size * sizeof(struct annotation_line *)); - if (notes->src->offsets == NULL) - return ENOMEM; - if (evsel__is_group_event(evsel)) nr_pcnt = evsel->core.nr_members; err = symbol__annotate(ms, evsel, parch); if (err) - goto out_free_offsets; + return err; symbol__calc_percent(sym, evsel); - annotation__set_offsets(notes, size); + annotation__set_index(notes); annotation__mark_jump_targets(notes, sym); err = annotation__compute_ipc(notes, size); if (err) - goto out_free_offsets; + return err; annotation__init_column_widths(notes, sym); notes->nr_events = nr_pcnt; @@ -1862,10 +1849,6 @@ int symbol__annotate2(struct map_symbol *ms, struct evsel *evsel, sym->annotate2 = 1; return 0; - -out_free_offsets: - zfree(¬es->src->offsets); - return err; } static int annotation__config(const char *var, const char *value, void *data) diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index aa3298c20300..d61184499bda 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -246,7 +246,6 @@ struct cyc_hist { * we have more than a group in a evlist, where we will want * to see each group separately, that is why symbol__annotate2() * sets src->nr_histograms to evsel->nr_members. - * @offsets: Array of annotation_line to be accessed by offset. * @samples: Hash map of sym_hist_entry. Keyed by event index and offset in symbol. * @nr_entries: Number of annotated_line in the source list. * @nr_asm_entries: Number of annotated_line with actual asm instruction in the @@ -262,7 +261,6 @@ struct cyc_hist { struct annotated_source { struct list_head source; struct sym_hist *histograms; - struct annotation_line **offsets; struct hashmap *samples; int nr_histograms; int nr_entries; -- cgit v1.2.3-59-g8ed1b From a46acc45673bc5537b0d9fc77b7a4edb5d068de6 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Thu, 4 Apr 2024 10:57:13 -0700 Subject: perf annotate: Move 'widths' struct to 'struct annotated_source' It's only used in 'perf annotate' output which means functions with actual samples. No need to consume memory for every symbol ('struct annotation'). Also move the 'max_line_len' field into it as it's related. Signed-off-by: Namhyung Kim Cc: Adrian Hunter Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20240404175716.1225482-7-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 6 +++--- tools/perf/util/annotate.c | 41 +++++++++++++++++++++------------------ tools/perf/util/annotate.h | 20 +++++++++---------- 3 files changed, 35 insertions(+), 32 deletions(-) diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index c93da2ce727f..032642a0b4b6 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -205,13 +205,13 @@ static void annotate_browser__draw_current_jump(struct ui_browser *browser) ui_browser__set_color(browser, HE_COLORSET_JUMP_ARROWS); __ui_browser__line_arrow(browser, - pcnt_width + 2 + notes->widths.addr + width, + pcnt_width + 2 + notes->src->widths.addr + width, from, to); diff = is_fused(ab, cursor); if (diff > 0) { ui_browser__mark_fused(browser, - pcnt_width + 3 + notes->widths.addr + width, + pcnt_width + 3 + notes->src->widths.addr + width, from - diff, diff, to > from); } } @@ -983,7 +983,7 @@ int symbol__tui_annotate(struct map_symbol *ms, struct evsel *evsel, ui_helpline__push("Press ESC to exit"); - browser.b.width = notes->src->max_line_len; + browser.b.width = notes->src->widths.max_line_len; browser.b.nr_entries = notes->src->nr_entries; browser.b.entries = ¬es->src->source, browser.b.width += 18; /* Percentage */ diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 0e8319835986..0be744bb529c 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -1383,15 +1383,15 @@ static void annotation__set_index(struct annotation *notes) struct annotation_line *al; struct annotated_source *src = notes->src; - src->max_line_len = 0; + src->widths.max_line_len = 0; src->nr_entries = 0; src->nr_asm_entries = 0; list_for_each_entry(al, &src->source, node) { size_t line_len = strlen(al->line); - if (src->max_line_len < line_len) - src->max_line_len = line_len; + if (src->widths.max_line_len < line_len) + src->widths.max_line_len = line_len; al->idx = src->nr_entries++; if (al->offset != -1) al->idx_asm = src->nr_asm_entries++; @@ -1429,26 +1429,26 @@ static int annotation__max_ins_name(struct annotation *notes) static void annotation__init_column_widths(struct annotation *notes, struct symbol *sym) { - notes->widths.addr = notes->widths.target = - notes->widths.min_addr = hex_width(symbol__size(sym)); - notes->widths.max_addr = hex_width(sym->end); - notes->widths.jumps = width_jumps(notes->max_jump_sources); - notes->widths.max_ins_name = annotation__max_ins_name(notes); + notes->src->widths.addr = notes->src->widths.target = + notes->src->widths.min_addr = hex_width(symbol__size(sym)); + notes->src->widths.max_addr = hex_width(sym->end); + notes->src->widths.jumps = width_jumps(notes->max_jump_sources); + notes->src->widths.max_ins_name = annotation__max_ins_name(notes); } void annotation__update_column_widths(struct annotation *notes) { if (annotate_opts.use_offset) - notes->widths.target = notes->widths.min_addr; + notes->src->widths.target = notes->src->widths.min_addr; else if (annotate_opts.full_addr) - notes->widths.target = BITS_PER_LONG / 4; + notes->src->widths.target = BITS_PER_LONG / 4; else - notes->widths.target = notes->widths.max_addr; + notes->src->widths.target = notes->src->widths.max_addr; - notes->widths.addr = notes->widths.target; + notes->src->widths.addr = notes->src->widths.target; if (annotate_opts.show_nr_jumps) - notes->widths.addr += notes->widths.jumps + 1; + notes->src->widths.addr += notes->src->widths.jumps + 1; } void annotation__toggle_full_addr(struct annotation *notes, struct map_symbol *ms) @@ -1625,7 +1625,8 @@ call_like: obj__printf(obj, " "); } - disasm_line__scnprintf(dl, bf, size, !annotate_opts.use_offset, notes->widths.max_ins_name); + disasm_line__scnprintf(dl, bf, size, !annotate_opts.use_offset, + notes->src->widths.max_ins_name); } static void ipc_coverage_string(char *bf, int size, struct annotation *notes) @@ -1753,9 +1754,11 @@ static void __annotation_line__write(struct annotation_line *al, struct annotati obj__printf(obj, "%-*s", width - pcnt_width - cycles_width, " "); else if (al->offset == -1) { if (al->line_nr && annotate_opts.show_linenr) - printed = scnprintf(bf, sizeof(bf), "%-*d ", notes->widths.addr + 1, al->line_nr); + printed = scnprintf(bf, sizeof(bf), "%-*d ", + notes->src->widths.addr + 1, al->line_nr); else - printed = scnprintf(bf, sizeof(bf), "%-*s ", notes->widths.addr, " "); + printed = scnprintf(bf, sizeof(bf), "%-*s ", + notes->src->widths.addr, " "); obj__printf(obj, bf); obj__printf(obj, "%-*s", width - printed - pcnt_width - cycles_width + 1, al->line); } else { @@ -1773,7 +1776,7 @@ static void __annotation_line__write(struct annotation_line *al, struct annotati if (annotate_opts.show_nr_jumps) { int prev; printed = scnprintf(bf, sizeof(bf), "%*d ", - notes->widths.jumps, + notes->src->widths.jumps, al->jump_sources); prev = obj__set_jumps_percent_color(obj, al->jump_sources, current_entry); @@ -1782,7 +1785,7 @@ static void __annotation_line__write(struct annotation_line *al, struct annotati } print_addr: printed = scnprintf(bf, sizeof(bf), "%*" PRIx64 ": ", - notes->widths.target, addr); + notes->src->widths.target, addr); } else if (ins__is_call(&disasm_line(al)->ins) && annotate_opts.offset_level >= ANNOTATION__OFFSET_CALL) { goto print_addr; @@ -1790,7 +1793,7 @@ print_addr: goto print_addr; } else { printed = scnprintf(bf, sizeof(bf), "%-*s ", - notes->widths.addr, " "); + notes->src->widths.addr, " "); } } diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index d61184499bda..402ae774426b 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -250,7 +250,7 @@ struct cyc_hist { * @nr_entries: Number of annotated_line in the source list. * @nr_asm_entries: Number of annotated_line with actual asm instruction in the * source list. - * @max_line_len: Maximum length of objdump output in an annotated_line. + * @widths: Precalculated width of each column in the TUI output. * * disasm_lines are allocated, percentages calculated and all sorted by percentage * when the annotation is about to be presented, so the percentages are for @@ -265,7 +265,15 @@ struct annotated_source { int nr_histograms; int nr_entries; int nr_asm_entries; - u16 max_line_len; + struct { + u8 addr; + u8 jumps; + u8 target; + u8 min_addr; + u8 max_addr; + u8 max_ins_name; + u16 max_line_len; + } widths; }; struct annotation_line *annotated_source__get_line(struct annotated_source *src, @@ -302,14 +310,6 @@ struct LOCKABLE annotation { u64 start; int nr_events; int max_jump_sources; - struct { - u8 addr; - u8 jumps; - u8 target; - u8 min_addr; - u8 max_addr; - u8 max_ins_name; - } widths; struct annotated_source *src; struct annotated_branch *branch; }; -- cgit v1.2.3-59-g8ed1b From f6b18ababa5ea8d7f798aa452eae83058fd09c59 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Thu, 4 Apr 2024 10:57:14 -0700 Subject: perf annotate: Move 'max_jump_sources' struct to 'struct annotated_source' It's only used in 'perf annotate' output which means functions with actual samples. No need to consume memory for every symbol ('struct annotation'). Signed-off-by: Namhyung Kim Cc: Adrian Hunter Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20240404175716.1225482-8-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 2 +- tools/perf/util/annotate.c | 6 +++--- tools/perf/util/annotate.h | 4 +++- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 032642a0b4b6..0e16c268e329 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -49,7 +49,7 @@ static int ui_browser__jumps_percent_color(struct ui_browser *browser, int nr, b if (current && (!browser->use_navkeypressed || browser->navkeypressed)) return HE_COLORSET_SELECTED; - if (nr == notes->max_jump_sources) + if (nr == notes->src->max_jump_sources) return HE_COLORSET_TOP; if (nr > 1) return HE_COLORSET_MEDIUM; diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 0be744bb529c..1fd51856d78f 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -1373,8 +1373,8 @@ annotation__mark_jump_targets(struct annotation *notes, struct symbol *sym) if (target == NULL) continue; - if (++target->jump_sources > notes->max_jump_sources) - notes->max_jump_sources = target->jump_sources; + if (++target->jump_sources > notes->src->max_jump_sources) + notes->src->max_jump_sources = target->jump_sources; } } @@ -1432,7 +1432,7 @@ annotation__init_column_widths(struct annotation *notes, struct symbol *sym) notes->src->widths.addr = notes->src->widths.target = notes->src->widths.min_addr = hex_width(symbol__size(sym)); notes->src->widths.max_addr = hex_width(sym->end); - notes->src->widths.jumps = width_jumps(notes->max_jump_sources); + notes->src->widths.jumps = width_jumps(notes->src->max_jump_sources); notes->src->widths.max_ins_name = annotation__max_ins_name(notes); } diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 402ae774426b..382705311d28 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -250,6 +250,8 @@ struct cyc_hist { * @nr_entries: Number of annotated_line in the source list. * @nr_asm_entries: Number of annotated_line with actual asm instruction in the * source list. + * @max_jump_sources: Maximum number of jump instructions targeting to the same + * instruction. * @widths: Precalculated width of each column in the TUI output. * * disasm_lines are allocated, percentages calculated and all sorted by percentage @@ -265,6 +267,7 @@ struct annotated_source { int nr_histograms; int nr_entries; int nr_asm_entries; + int max_jump_sources; struct { u8 addr; u8 jumps; @@ -309,7 +312,6 @@ struct annotated_branch { struct LOCKABLE annotation { u64 start; int nr_events; - int max_jump_sources; struct annotated_source *src; struct annotated_branch *branch; }; -- cgit v1.2.3-59-g8ed1b From 6f94a72d45295741b8be64da40a86780c7681a3b Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Thu, 4 Apr 2024 10:57:15 -0700 Subject: perf annotate: Move nr_events struct to 'struct annotated_source' It's only used in 'perf annotate' output which means functions with actual samples. No need to consume memory for every symbol ('struct annotation'). Signed-off-by: Namhyung Kim Cc: Adrian Hunter Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20240404175716.1225482-9-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 6 +++--- tools/perf/util/annotate.h | 5 +++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 1fd51856d78f..5f79ae0bccfd 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -1584,7 +1584,7 @@ static double annotation_line__max_percent(struct annotation_line *al, double percent_max = 0.0; int i; - for (i = 0; i < notes->nr_events; i++) { + for (i = 0; i < notes->src->nr_events; i++) { double percent; percent = annotation_data__percent(&al->data[i], @@ -1674,7 +1674,7 @@ static void __annotation_line__write(struct annotation_line *al, struct annotati if (al->offset != -1 && percent_max != 0.0) { int i; - for (i = 0; i < notes->nr_events; i++) { + for (i = 0; i < notes->src->nr_events; i++) { double percent; percent = annotation_data__percent(&al->data[i], percent_type); @@ -1846,7 +1846,7 @@ int symbol__annotate2(struct map_symbol *ms, struct evsel *evsel, return err; annotation__init_column_widths(notes, sym); - notes->nr_events = nr_pcnt; + notes->src->nr_events = nr_pcnt; annotation__update_column_widths(notes); sym->annotate2 = 1; diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 382705311d28..d22b9e9a2fad 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -247,6 +247,7 @@ struct cyc_hist { * to see each group separately, that is why symbol__annotate2() * sets src->nr_histograms to evsel->nr_members. * @samples: Hash map of sym_hist_entry. Keyed by event index and offset in symbol. + * @nr_events: Number of events in the current output. * @nr_entries: Number of annotated_line in the source list. * @nr_asm_entries: Number of annotated_line with actual asm instruction in the * source list. @@ -265,6 +266,7 @@ struct annotated_source { struct sym_hist *histograms; struct hashmap *samples; int nr_histograms; + int nr_events; int nr_entries; int nr_asm_entries; int max_jump_sources; @@ -311,7 +313,6 @@ struct annotated_branch { struct LOCKABLE annotation { u64 start; - int nr_events; struct annotated_source *src; struct annotated_branch *branch; }; @@ -335,7 +336,7 @@ static inline int annotation__cycles_width(struct annotation *notes) static inline int annotation__pcnt_width(struct annotation *notes) { - return (symbol_conf.show_total_period ? 12 : 7) * notes->nr_events; + return (symbol_conf.show_total_period ? 12 : 7) * notes->src->nr_events; } static inline bool annotation_line__filter(struct annotation_line *al) -- cgit v1.2.3-59-g8ed1b From 8c004c7a608a278548e4a7f25df6bae0b0a04370 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Thu, 4 Apr 2024 10:57:16 -0700 Subject: perf annotate: Move 'start' field struct to 'struct annotated_source' It's only used in 'perf annotate' output which means functions with actual samples. No need to consume memory for every symbol ('struct annotation'). Signed-off-by: Namhyung Kim Link: https://lore.kernel.org/r/20240404175716.1225482-10-namhyung@kernel.org Cc: Ian Rogers Cc: Peter Zijlstra Cc: Adrian Hunter Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Ingo Molnar Cc: Kan Liang Cc: LKML Cc: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 10 +++++----- tools/perf/util/annotate.h | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 5f79ae0bccfd..4db49611c386 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -909,9 +909,9 @@ int symbol__annotate(struct map_symbol *ms, struct evsel *evsel, args.arch = arch; args.ms = *ms; if (annotate_opts.full_addr) - notes->start = map__objdump_2mem(ms->map, ms->sym->start); + notes->src->start = map__objdump_2mem(ms->map, ms->sym->start); else - notes->start = map__rip_2objdump(ms->map, ms->sym->start); + notes->src->start = map__rip_2objdump(ms->map, ms->sym->start); return symbol__disassemble(sym, &args); } @@ -1456,9 +1456,9 @@ void annotation__toggle_full_addr(struct annotation *notes, struct map_symbol *m annotate_opts.full_addr = !annotate_opts.full_addr; if (annotate_opts.full_addr) - notes->start = map__objdump_2mem(ms->map, ms->sym->start); + notes->src->start = map__objdump_2mem(ms->map, ms->sym->start); else - notes->start = map__rip_2objdump(ms->map, ms->sym->start); + notes->src->start = map__rip_2objdump(ms->map, ms->sym->start); annotation__update_column_widths(notes); } @@ -1766,7 +1766,7 @@ static void __annotation_line__write(struct annotation_line *al, struct annotati int color = -1; if (!annotate_opts.use_offset) - addr += notes->start; + addr += notes->src->start; if (!annotate_opts.use_offset) { printed = scnprintf(bf, sizeof(bf), "%" PRIx64 ": ", addr); diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index d22b9e9a2fad..d5c821c22f79 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -270,6 +270,7 @@ struct annotated_source { int nr_entries; int nr_asm_entries; int max_jump_sources; + u64 start; struct { u8 addr; u8 jumps; @@ -312,7 +313,6 @@ struct annotated_branch { }; struct LOCKABLE annotation { - u64 start; struct annotated_source *src; struct annotated_branch *branch; }; -- cgit v1.2.3-59-g8ed1b From 705c09bb3cdffb141986598ad4ff9c9b0a66c3bd Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Fri, 5 Apr 2024 00:09:30 -0700 Subject: tools subcmd: Add check_if_command_finished() Add non-blocking function to check if a 'struct child_process' has completed. If the process has completed the exit code is stored in the 'struct child_process' so that finish_command() returns it. Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Kan Liang Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20240405070931.1231245-1-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/lib/subcmd/run-command.c | 70 +++++++++++++++++++++++++++--------------- tools/lib/subcmd/run-command.h | 3 ++ 2 files changed, 49 insertions(+), 24 deletions(-) diff --git a/tools/lib/subcmd/run-command.c b/tools/lib/subcmd/run-command.c index d435eb42354b..4e3a557a2f37 100644 --- a/tools/lib/subcmd/run-command.c +++ b/tools/lib/subcmd/run-command.c @@ -165,43 +165,65 @@ int start_command(struct child_process *cmd) return 0; } -static int wait_or_whine(pid_t pid) +static int wait_or_whine(struct child_process *cmd, bool block) { - char sbuf[STRERR_BUFSIZE]; + bool finished = cmd->finished; + int result = cmd->finish_result; - for (;;) { + while (!finished) { int status, code; - pid_t waiting = waitpid(pid, &status, 0); + pid_t waiting = waitpid(cmd->pid, &status, block ? 0 : WNOHANG); + + if (!block && waiting == 0) + break; + + if (waiting < 0 && errno == EINTR) + continue; + finished = true; if (waiting < 0) { - if (errno == EINTR) - continue; + char sbuf[STRERR_BUFSIZE]; + fprintf(stderr, " Error: waitpid failed (%s)", str_error_r(errno, sbuf, sizeof(sbuf))); - return -ERR_RUN_COMMAND_WAITPID; - } - if (waiting != pid) - return -ERR_RUN_COMMAND_WAITPID_WRONG_PID; - if (WIFSIGNALED(status)) - return -ERR_RUN_COMMAND_WAITPID_SIGNAL; - - if (!WIFEXITED(status)) - return -ERR_RUN_COMMAND_WAITPID_NOEXIT; - code = WEXITSTATUS(status); - switch (code) { - case 127: - return -ERR_RUN_COMMAND_EXEC; - case 0: - return 0; - default: - return -code; + result = -ERR_RUN_COMMAND_WAITPID; + } else if (waiting != cmd->pid) { + result = -ERR_RUN_COMMAND_WAITPID_WRONG_PID; + } else if (WIFSIGNALED(status)) { + result = -ERR_RUN_COMMAND_WAITPID_SIGNAL; + } else if (!WIFEXITED(status)) { + result = -ERR_RUN_COMMAND_WAITPID_NOEXIT; + } else { + code = WEXITSTATUS(status); + switch (code) { + case 127: + result = -ERR_RUN_COMMAND_EXEC; + break; + case 0: + result = 0; + break; + default: + result = -code; + break; + } } } + if (finished) { + cmd->finished = 1; + cmd->finish_result = result; + } + return result; +} + +int check_if_command_finished(struct child_process *cmd) +{ + wait_or_whine(cmd, /*block=*/false); + return cmd->finished; } int finish_command(struct child_process *cmd) { - return wait_or_whine(cmd->pid); + return wait_or_whine(cmd, /*block=*/true); } int run_command(struct child_process *cmd) diff --git a/tools/lib/subcmd/run-command.h b/tools/lib/subcmd/run-command.h index d794138a797f..b2d39de6e690 100644 --- a/tools/lib/subcmd/run-command.h +++ b/tools/lib/subcmd/run-command.h @@ -41,17 +41,20 @@ struct child_process { int err; const char *dir; const char *const *env; + int finish_result; unsigned no_stdin:1; unsigned no_stdout:1; unsigned no_stderr:1; unsigned exec_cmd:1; /* if this is to be external sub-command */ unsigned stdout_to_stderr:1; + unsigned finished:1; void (*preexec_cb)(void); /* If set, call function in child rather than doing an exec. */ int (*no_exec_cmd)(struct child_process *process); }; int start_command(struct child_process *); +int check_if_command_finished(struct child_process *); int finish_command(struct child_process *); int run_command(struct child_process *); -- cgit v1.2.3-59-g8ed1b From 4d2bc3f7dea4d17243924c6758e0447cc1aa0eea Mon Sep 17 00:00:00 2001 From: Marco Pagani Date: Fri, 29 Mar 2024 18:48:47 +0100 Subject: fpga: tests: use KUnit devices instead of platform devices KUnit now provides helper functions to create fake devices, so use them instead of relying on platform devices. Other changes: remove an unnecessary white space in the fpga region suite. Reviewed-by: Russ Weight Signed-off-by: Marco Pagani Acked-by: Xu Yilun Link: https://lore.kernel.org/r/20240329174849.248243-1-marpagan@redhat.com Signed-off-by: Xu Yilun --- drivers/fpga/tests/fpga-bridge-test.c | 33 ++++++++++++++-------------- drivers/fpga/tests/fpga-mgr-test.c | 16 +++++++------- drivers/fpga/tests/fpga-region-test.c | 41 ++++++++++++++++------------------- 3 files changed, 44 insertions(+), 46 deletions(-) diff --git a/drivers/fpga/tests/fpga-bridge-test.c b/drivers/fpga/tests/fpga-bridge-test.c index 1d258002cdd7..2f7a24f23808 100644 --- a/drivers/fpga/tests/fpga-bridge-test.c +++ b/drivers/fpga/tests/fpga-bridge-test.c @@ -7,8 +7,8 @@ * Author: Marco Pagani */ +#include #include -#include #include #include #include @@ -19,7 +19,7 @@ struct bridge_stats { struct bridge_ctx { struct fpga_bridge *bridge; - struct platform_device *pdev; + struct device *dev; struct bridge_stats stats; }; @@ -43,30 +43,31 @@ static const struct fpga_bridge_ops fake_bridge_ops = { /** * register_test_bridge() - Register a fake FPGA bridge for testing. * @test: KUnit test context object. + * @dev_name: name of the kunit device to be registered * * Return: Context of the newly registered FPGA bridge. */ -static struct bridge_ctx *register_test_bridge(struct kunit *test) +static struct bridge_ctx *register_test_bridge(struct kunit *test, const char *dev_name) { struct bridge_ctx *ctx; ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx); - ctx->pdev = platform_device_register_simple("bridge_pdev", PLATFORM_DEVID_AUTO, NULL, 0); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx->pdev); + ctx->dev = kunit_device_register(test, dev_name); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx->dev); - ctx->bridge = fpga_bridge_register(&ctx->pdev->dev, "Fake FPGA bridge", &fake_bridge_ops, + ctx->bridge = fpga_bridge_register(ctx->dev, "Fake FPGA bridge", &fake_bridge_ops, &ctx->stats); KUNIT_ASSERT_FALSE(test, IS_ERR_OR_NULL(ctx->bridge)); return ctx; } -static void unregister_test_bridge(struct bridge_ctx *ctx) +static void unregister_test_bridge(struct kunit *test, struct bridge_ctx *ctx) { fpga_bridge_unregister(ctx->bridge); - platform_device_unregister(ctx->pdev); + kunit_device_unregister(test, ctx->dev); } static void fpga_bridge_test_get(struct kunit *test) @@ -74,10 +75,10 @@ static void fpga_bridge_test_get(struct kunit *test) struct bridge_ctx *ctx = test->priv; struct fpga_bridge *bridge; - bridge = fpga_bridge_get(&ctx->pdev->dev, NULL); + bridge = fpga_bridge_get(ctx->dev, NULL); KUNIT_EXPECT_PTR_EQ(test, bridge, ctx->bridge); - bridge = fpga_bridge_get(&ctx->pdev->dev, NULL); + bridge = fpga_bridge_get(ctx->dev, NULL); KUNIT_EXPECT_EQ(test, PTR_ERR(bridge), -EBUSY); fpga_bridge_put(ctx->bridge); @@ -105,19 +106,19 @@ static void fpga_bridge_test_get_put_list(struct kunit *test) int ret; ctx_0 = test->priv; - ctx_1 = register_test_bridge(test); + ctx_1 = register_test_bridge(test, "fpga-bridge-test-dev-1"); INIT_LIST_HEAD(&bridge_list); /* Get bridge 0 and add it to the list */ - ret = fpga_bridge_get_to_list(&ctx_0->pdev->dev, NULL, &bridge_list); + ret = fpga_bridge_get_to_list(ctx_0->dev, NULL, &bridge_list); KUNIT_EXPECT_EQ(test, ret, 0); KUNIT_EXPECT_PTR_EQ(test, ctx_0->bridge, list_first_entry_or_null(&bridge_list, struct fpga_bridge, node)); /* Get bridge 1 and add it to the list */ - ret = fpga_bridge_get_to_list(&ctx_1->pdev->dev, NULL, &bridge_list); + ret = fpga_bridge_get_to_list(ctx_1->dev, NULL, &bridge_list); KUNIT_EXPECT_EQ(test, ret, 0); KUNIT_EXPECT_PTR_EQ(test, ctx_1->bridge, @@ -141,19 +142,19 @@ static void fpga_bridge_test_get_put_list(struct kunit *test) KUNIT_EXPECT_TRUE(test, list_empty(&bridge_list)); - unregister_test_bridge(ctx_1); + unregister_test_bridge(test, ctx_1); } static int fpga_bridge_test_init(struct kunit *test) { - test->priv = register_test_bridge(test); + test->priv = register_test_bridge(test, "fpga-bridge-test-dev-0"); return 0; } static void fpga_bridge_test_exit(struct kunit *test) { - unregister_test_bridge(test->priv); + unregister_test_bridge(test, test->priv); } static struct kunit_case fpga_bridge_test_cases[] = { diff --git a/drivers/fpga/tests/fpga-mgr-test.c b/drivers/fpga/tests/fpga-mgr-test.c index 6acec55b60ce..125b3a4d43c6 100644 --- a/drivers/fpga/tests/fpga-mgr-test.c +++ b/drivers/fpga/tests/fpga-mgr-test.c @@ -7,8 +7,8 @@ * Author: Marco Pagani */ +#include #include -#include #include #include #include @@ -40,7 +40,7 @@ struct mgr_stats { struct mgr_ctx { struct fpga_image_info *img_info; struct fpga_manager *mgr; - struct platform_device *pdev; + struct device *dev; struct mgr_stats stats; }; @@ -194,7 +194,7 @@ static void fpga_mgr_test_get(struct kunit *test) struct mgr_ctx *ctx = test->priv; struct fpga_manager *mgr; - mgr = fpga_mgr_get(&ctx->pdev->dev); + mgr = fpga_mgr_get(ctx->dev); KUNIT_EXPECT_PTR_EQ(test, mgr, ctx->mgr); fpga_mgr_put(ctx->mgr); @@ -284,14 +284,14 @@ static int fpga_mgr_test_init(struct kunit *test) ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx); - ctx->pdev = platform_device_register_simple("mgr_pdev", PLATFORM_DEVID_AUTO, NULL, 0); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx->pdev); + ctx->dev = kunit_device_register(test, "fpga-manager-test-dev"); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx->dev); - ctx->mgr = devm_fpga_mgr_register(&ctx->pdev->dev, "Fake FPGA Manager", &fake_mgr_ops, + ctx->mgr = devm_fpga_mgr_register(ctx->dev, "Fake FPGA Manager", &fake_mgr_ops, &ctx->stats); KUNIT_ASSERT_FALSE(test, IS_ERR_OR_NULL(ctx->mgr)); - ctx->img_info = fpga_image_info_alloc(&ctx->pdev->dev); + ctx->img_info = fpga_image_info_alloc(ctx->dev); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx->img_info); test->priv = ctx; @@ -304,7 +304,7 @@ static void fpga_mgr_test_exit(struct kunit *test) struct mgr_ctx *ctx = test->priv; fpga_image_info_free(ctx->img_info); - platform_device_unregister(ctx->pdev); + kunit_device_unregister(test, ctx->dev); } static struct kunit_case fpga_mgr_test_cases[] = { diff --git a/drivers/fpga/tests/fpga-region-test.c b/drivers/fpga/tests/fpga-region-test.c index baab07e3fc59..bcf0651df261 100644 --- a/drivers/fpga/tests/fpga-region-test.c +++ b/drivers/fpga/tests/fpga-region-test.c @@ -7,12 +7,12 @@ * Author: Marco Pagani */ +#include #include #include #include #include #include -#include #include struct mgr_stats { @@ -26,11 +26,11 @@ struct bridge_stats { struct test_ctx { struct fpga_manager *mgr; - struct platform_device *mgr_pdev; + struct device *mgr_dev; struct fpga_bridge *bridge; - struct platform_device *bridge_pdev; + struct device *bridge_dev; struct fpga_region *region; - struct platform_device *region_pdev; + struct device *region_dev; struct bridge_stats bridge_stats; struct mgr_stats mgr_stats; }; @@ -91,7 +91,7 @@ static void fpga_region_test_class_find(struct kunit *test) struct test_ctx *ctx = test->priv; struct fpga_region *region; - region = fpga_region_class_find(NULL, &ctx->region_pdev->dev, fake_region_match); + region = fpga_region_class_find(NULL, ctx->region_dev, fake_region_match); KUNIT_EXPECT_PTR_EQ(test, region, ctx->region); put_device(®ion->dev); @@ -108,7 +108,7 @@ static void fpga_region_test_program_fpga(struct kunit *test) char img_buf[4]; int ret; - img_info = fpga_image_info_alloc(&ctx->mgr_pdev->dev); + img_info = fpga_image_info_alloc(ctx->mgr_dev); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, img_info); img_info->buf = img_buf; @@ -148,32 +148,30 @@ static int fpga_region_test_init(struct kunit *test) ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx); - ctx->mgr_pdev = platform_device_register_simple("mgr_pdev", PLATFORM_DEVID_AUTO, NULL, 0); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx->mgr_pdev); + ctx->mgr_dev = kunit_device_register(test, "fpga-manager-test-dev"); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx->mgr_dev); - ctx->mgr = devm_fpga_mgr_register(&ctx->mgr_pdev->dev, "Fake FPGA Manager", &fake_mgr_ops, - &ctx->mgr_stats); + ctx->mgr = devm_fpga_mgr_register(ctx->mgr_dev, "Fake FPGA Manager", + &fake_mgr_ops, &ctx->mgr_stats); KUNIT_ASSERT_FALSE(test, IS_ERR_OR_NULL(ctx->mgr)); - ctx->bridge_pdev = platform_device_register_simple("bridge_pdev", PLATFORM_DEVID_AUTO, - NULL, 0); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx->bridge_pdev); + ctx->bridge_dev = kunit_device_register(test, "fpga-bridge-test-dev"); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx->bridge_dev); - ctx->bridge = fpga_bridge_register(&ctx->bridge_pdev->dev, "Fake FPGA Bridge", + ctx->bridge = fpga_bridge_register(ctx->bridge_dev, "Fake FPGA Bridge", &fake_bridge_ops, &ctx->bridge_stats); KUNIT_ASSERT_FALSE(test, IS_ERR_OR_NULL(ctx->bridge)); ctx->bridge_stats.enable = true; - ctx->region_pdev = platform_device_register_simple("region_pdev", PLATFORM_DEVID_AUTO, - NULL, 0); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx->region_pdev); + ctx->region_dev = kunit_device_register(test, "fpga-region-test-dev"); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx->region_dev); region_info.mgr = ctx->mgr; region_info.priv = ctx->bridge; region_info.get_bridges = fake_region_get_bridges; - ctx->region = fpga_region_register_full(&ctx->region_pdev->dev, ®ion_info); + ctx->region = fpga_region_register_full(ctx->region_dev, ®ion_info); KUNIT_ASSERT_FALSE(test, IS_ERR_OR_NULL(ctx->region)); test->priv = ctx; @@ -186,18 +184,17 @@ static void fpga_region_test_exit(struct kunit *test) struct test_ctx *ctx = test->priv; fpga_region_unregister(ctx->region); - platform_device_unregister(ctx->region_pdev); + kunit_device_unregister(test, ctx->region_dev); fpga_bridge_unregister(ctx->bridge); - platform_device_unregister(ctx->bridge_pdev); + kunit_device_unregister(test, ctx->bridge_dev); - platform_device_unregister(ctx->mgr_pdev); + kunit_device_unregister(test, ctx->mgr_dev); } static struct kunit_case fpga_region_test_cases[] = { KUNIT_CASE(fpga_region_test_class_find), KUNIT_CASE(fpga_region_test_program_fpga), - {} }; -- cgit v1.2.3-59-g8ed1b From 779087fe2fecf8b8aa7bdd69982f9c0c8266927b Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Fri, 5 Apr 2024 08:08:12 +0200 Subject: kfifo: drop __kfifo_dma_out_finish_r() It is the same as __kfifo_skip_r(), so: * drop __kfifo_dma_out_finish_r() completely, and * replace its (only) use by __kfifo_skip_r(). Signed-off-by: Jiri Slaby (SUSE) Cc: Stefani Seibold Cc: Andrew Morton Link: https://lore.kernel.org/r/20240405060826.2521-2-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- include/linux/kfifo.h | 4 +--- lib/kfifo.c | 8 -------- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/include/linux/kfifo.h b/include/linux/kfifo.h index 0b35a41440ff..bc7a1f5bb0ce 100644 --- a/include/linux/kfifo.h +++ b/include/linux/kfifo.h @@ -797,7 +797,7 @@ __kfifo_int_must_check_helper( \ const size_t __recsize = sizeof(*__tmp->rectype); \ struct __kfifo *__kfifo = &__tmp->kfifo; \ if (__recsize) \ - __kfifo_dma_out_finish_r(__kfifo, __recsize); \ + __kfifo_skip_r(__kfifo, __recsize); \ else \ __kfifo->out += __len / sizeof(*__tmp->type); \ }) @@ -879,8 +879,6 @@ extern void __kfifo_dma_in_finish_r(struct __kfifo *fifo, extern unsigned int __kfifo_dma_out_prepare_r(struct __kfifo *fifo, struct scatterlist *sgl, int nents, unsigned int len, size_t recsize); -extern void __kfifo_dma_out_finish_r(struct __kfifo *fifo, size_t recsize); - extern unsigned int __kfifo_len_r(struct __kfifo *fifo, size_t recsize); extern void __kfifo_skip_r(struct __kfifo *fifo, size_t recsize); diff --git a/lib/kfifo.c b/lib/kfifo.c index 12f5a347aa13..958099cc4914 100644 --- a/lib/kfifo.c +++ b/lib/kfifo.c @@ -582,11 +582,3 @@ unsigned int __kfifo_dma_out_prepare_r(struct __kfifo *fifo, } EXPORT_SYMBOL(__kfifo_dma_out_prepare_r); -void __kfifo_dma_out_finish_r(struct __kfifo *fifo, size_t recsize) -{ - unsigned int len; - - len = __kfifo_peek_n(fifo, recsize); - fifo->out += len + recsize; -} -EXPORT_SYMBOL(__kfifo_dma_out_finish_r); -- cgit v1.2.3-59-g8ed1b From 76738194be605c9fb279f87d8a6b0b95904bfb60 Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Fri, 5 Apr 2024 08:08:13 +0200 Subject: kfifo: introduce and use kfifo_skip_count() kfifo_skip_count() is an extended version of kfifo_skip(), accepting also count. This will be useful in the serial code later. Now, it can be used to implement both kfifo_skip() and kfifo_dma_out_finish(). In the latter, 'len' only needs to be divided by 'type' size (as it was until now). And stop using statement expressions when the return value is cast to 'void'. Use classic 'do {} while (0)' instead. Note: perhaps we should skip 'count' records for the 'recsize' case, but the original (kfifo_dma_out_finish()) used to skip only one record. So this is kept unchanged and 'count' is still ignored in the recsize case. Signed-off-by: Jiri Slaby (SUSE) Cc: Stefani Seibold Cc: Andrew Morton Link: https://lore.kernel.org/r/20240405060826.2521-3-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- include/linux/kfifo.h | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/include/linux/kfifo.h b/include/linux/kfifo.h index bc7a1f5bb0ce..8f3369ec528b 100644 --- a/include/linux/kfifo.h +++ b/include/linux/kfifo.h @@ -304,19 +304,25 @@ __kfifo_uint_must_check_helper( \ ) /** - * kfifo_skip - skip output data + * kfifo_skip_count - skip output data * @fifo: address of the fifo to be used + * @count: count of data to skip */ -#define kfifo_skip(fifo) \ -(void)({ \ +#define kfifo_skip_count(fifo, count) do { \ typeof((fifo) + 1) __tmp = (fifo); \ const size_t __recsize = sizeof(*__tmp->rectype); \ struct __kfifo *__kfifo = &__tmp->kfifo; \ if (__recsize) \ __kfifo_skip_r(__kfifo, __recsize); \ else \ - __kfifo->out++; \ -}) + __kfifo->out += (count); \ +} while(0) + +/** + * kfifo_skip - skip output data + * @fifo: address of the fifo to be used + */ +#define kfifo_skip(fifo) kfifo_skip_count(fifo, 1) /** * kfifo_peek_len - gets the size of the next fifo record @@ -790,17 +796,10 @@ __kfifo_int_must_check_helper( \ * Note that with only one concurrent reader and one concurrent * writer, you don't need extra locking to use these macros. */ -#define kfifo_dma_out_finish(fifo, len) \ -(void)({ \ - typeof((fifo) + 1) __tmp = (fifo); \ - unsigned int __len = (len); \ - const size_t __recsize = sizeof(*__tmp->rectype); \ - struct __kfifo *__kfifo = &__tmp->kfifo; \ - if (__recsize) \ - __kfifo_skip_r(__kfifo, __recsize); \ - else \ - __kfifo->out += __len / sizeof(*__tmp->type); \ -}) +#define kfifo_dma_out_finish(fifo, len) do { \ + typeof((fifo) + 1) ___tmp = (fifo); \ + kfifo_skip_count(___tmp, (len) / sizeof(*___tmp->type)); \ +} while (0) /** * kfifo_out_peek - gets some data from the fifo -- cgit v1.2.3-59-g8ed1b From 4edd7e96a1f159f43bd1cb82616f81eaddd54262 Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Fri, 5 Apr 2024 08:08:14 +0200 Subject: kfifo: add kfifo_out_linear{,_ptr}() These are helpers which are going to be used in the serial layer. We need a wrapper around kfifo which provides us with a tail (sometimes "tail" offset, sometimes a pointer) to the kfifo data. And which returns count of available data -- but not larger than to the end of the buffer (hence _linear in the names). I.e. something like CIRC_CNT_TO_END() in the legacy circ_buf. This patch adds such two helpers. Signed-off-by: Jiri Slaby (SUSE) Cc: Stefani Seibold Cc: Andrew Morton Link: https://lore.kernel.org/r/20240405060826.2521-4-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- include/linux/kfifo.h | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++ lib/kfifo.c | 26 +++++++++++++++++++++ 2 files changed, 89 insertions(+) diff --git a/include/linux/kfifo.h b/include/linux/kfifo.h index 8f3369ec528b..3def70e1a3e3 100644 --- a/include/linux/kfifo.h +++ b/include/linux/kfifo.h @@ -827,6 +827,63 @@ __kfifo_uint_must_check_helper( \ }) \ ) +/** + * kfifo_out_linear - gets a tail of/offset to available data + * @fifo: address of the fifo to be used + * @tail: pointer to an unsigned int to store the value of tail + * @n: max. number of elements to point at + * + * This macro obtains the offset (tail) to the available data in the fifo + * buffer and returns the + * numbers of elements available. It returns the available count till the end + * of data or till the end of the buffer. So that it can be used for linear + * data processing (like memcpy() of (@fifo->data + @tail) with count + * returned). + * + * Note that with only one concurrent reader and one concurrent + * writer, you don't need extra locking to use these macro. + */ +#define kfifo_out_linear(fifo, tail, n) \ +__kfifo_uint_must_check_helper( \ +({ \ + typeof((fifo) + 1) __tmp = (fifo); \ + unsigned int *__tail = (tail); \ + unsigned long __n = (n); \ + const size_t __recsize = sizeof(*__tmp->rectype); \ + struct __kfifo *__kfifo = &__tmp->kfifo; \ + (__recsize) ? \ + __kfifo_out_linear_r(__kfifo, __tail, __n, __recsize) : \ + __kfifo_out_linear(__kfifo, __tail, __n); \ +}) \ +) + +/** + * kfifo_out_linear_ptr - gets a pointer to the available data + * @fifo: address of the fifo to be used + * @ptr: pointer to data to store the pointer to tail + * @n: max. number of elements to point at + * + * Similarly to kfifo_out_linear(), this macro obtains the pointer to the + * available data in the fifo buffer and returns the numbers of elements + * available. It returns the available count till the end of available data or + * till the end of the buffer. So that it can be used for linear data + * processing (like memcpy() of @ptr with count returned). + * + * Note that with only one concurrent reader and one concurrent + * writer, you don't need extra locking to use these macro. + */ +#define kfifo_out_linear_ptr(fifo, ptr, n) \ +__kfifo_uint_must_check_helper( \ +({ \ + typeof((fifo) + 1) ___tmp = (fifo); \ + unsigned int ___tail; \ + unsigned int ___n = kfifo_out_linear(___tmp, &___tail, (n)); \ + *(ptr) = ___tmp->kfifo.data + ___tail * kfifo_esize(___tmp); \ + ___n; \ +}) \ +) + + extern int __kfifo_alloc(struct __kfifo *fifo, unsigned int size, size_t esize, gfp_t gfp_mask); @@ -856,6 +913,9 @@ extern unsigned int __kfifo_dma_out_prepare(struct __kfifo *fifo, extern unsigned int __kfifo_out_peek(struct __kfifo *fifo, void *buf, unsigned int len); +extern unsigned int __kfifo_out_linear(struct __kfifo *fifo, + unsigned int *tail, unsigned int n); + extern unsigned int __kfifo_in_r(struct __kfifo *fifo, const void *buf, unsigned int len, size_t recsize); @@ -885,6 +945,9 @@ extern void __kfifo_skip_r(struct __kfifo *fifo, size_t recsize); extern unsigned int __kfifo_out_peek_r(struct __kfifo *fifo, void *buf, unsigned int len, size_t recsize); +extern unsigned int __kfifo_out_linear_r(struct __kfifo *fifo, + unsigned int *tail, unsigned int n, size_t recsize); + extern unsigned int __kfifo_max_r(unsigned int len, size_t recsize); #endif diff --git a/lib/kfifo.c b/lib/kfifo.c index 958099cc4914..a36bfdbdb17d 100644 --- a/lib/kfifo.c +++ b/lib/kfifo.c @@ -163,6 +163,19 @@ unsigned int __kfifo_out_peek(struct __kfifo *fifo, } EXPORT_SYMBOL(__kfifo_out_peek); +unsigned int __kfifo_out_linear(struct __kfifo *fifo, + unsigned int *tail, unsigned int n) +{ + unsigned int size = fifo->mask + 1; + unsigned int off = fifo->out & fifo->mask; + + if (tail) + *tail = off; + + return min3(n, fifo->in - fifo->out, size - off); +} +EXPORT_SYMBOL(__kfifo_out_linear); + unsigned int __kfifo_out(struct __kfifo *fifo, void *buf, unsigned int len) { @@ -473,6 +486,19 @@ unsigned int __kfifo_out_peek_r(struct __kfifo *fifo, void *buf, } EXPORT_SYMBOL(__kfifo_out_peek_r); +unsigned int __kfifo_out_linear_r(struct __kfifo *fifo, + unsigned int *tail, unsigned int n, size_t recsize) +{ + if (fifo->in == fifo->out) + return 0; + + if (tail) + *tail = fifo->out + recsize; + + return min(n, __kfifo_peek_n(fifo, recsize)); +} +EXPORT_SYMBOL(__kfifo_out_linear_r); + unsigned int __kfifo_out_r(struct __kfifo *fifo, void *buf, unsigned int len, size_t recsize) { -- cgit v1.2.3-59-g8ed1b From e9d9576de08ac65d2c973ef7ce542338d2da94f9 Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Fri, 5 Apr 2024 08:08:15 +0200 Subject: kfifo: remove support for physically non-contiguous memory First, there is no such user. The only user of this interface is caam_rng_fill_async() and that uses kfifo_alloc() -> kmalloc(). Second, the implementation does not allow anything else than direct mapping and kmalloc() (due to virt_to_phys()), anyway. Therefore, there is no point in having this dead (and complex) code in the kernel. Note the setup_sgl_buf() function now boils down to simple sg_set_buf(). That is called twice from setup_sgl() to take care of kfifo buffer wrap-around. setup_sgl_buf() will be extended shortly, so keeping it in place. Signed-off-by: Jiri Slaby (SUSE) Cc: Andrew Morton Cc: Stefani Seibold Link: https://lore.kernel.org/r/20240405060826.2521-5-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- lib/kfifo.c | 38 +++++--------------------------------- 1 file changed, 5 insertions(+), 33 deletions(-) diff --git a/lib/kfifo.c b/lib/kfifo.c index a36bfdbdb17d..d5830960ab87 100644 --- a/lib/kfifo.c +++ b/lib/kfifo.c @@ -305,43 +305,15 @@ int __kfifo_to_user(struct __kfifo *fifo, void __user *to, } EXPORT_SYMBOL(__kfifo_to_user); -static int setup_sgl_buf(struct scatterlist *sgl, void *buf, - int nents, unsigned int len) +static unsigned int setup_sgl_buf(struct scatterlist *sgl, void *buf, + int nents, unsigned int len) { - int n; - unsigned int l; - unsigned int off; - struct page *page; - - if (!nents) + if (!nents || !len) return 0; - if (!len) - return 0; + sg_set_buf(sgl, buf, len); - n = 0; - page = virt_to_page(buf); - off = offset_in_page(buf); - l = 0; - - while (len >= l + PAGE_SIZE - off) { - struct page *npage; - - l += PAGE_SIZE; - buf += PAGE_SIZE; - npage = virt_to_page(buf); - if (page_to_phys(page) != page_to_phys(npage) - l) { - sg_set_page(sgl, page, l - off, off); - sgl = sg_next(sgl); - if (++n == nents || sgl == NULL) - return n; - page = npage; - len -= l - off; - l = off = 0; - } - } - sg_set_page(sgl, page, len, off); - return n + 1; + return 1; } static unsigned int setup_sgl(struct __kfifo *fifo, struct scatterlist *sgl, -- cgit v1.2.3-59-g8ed1b From ed6d22f5d8672f38d6020c719d5d658a4e3e6be5 Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Fri, 5 Apr 2024 08:08:16 +0200 Subject: kfifo: rename l to len_to_end in setup_sgl() So that one can make any sense of the name. Signed-off-by: Jiri Slaby (SUSE) Cc: Stefani Seibold Cc: Andrew Morton Link: https://lore.kernel.org/r/20240405060826.2521-6-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- lib/kfifo.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/kfifo.c b/lib/kfifo.c index d5830960ab87..61e35550aea5 100644 --- a/lib/kfifo.c +++ b/lib/kfifo.c @@ -321,7 +321,7 @@ static unsigned int setup_sgl(struct __kfifo *fifo, struct scatterlist *sgl, { unsigned int size = fifo->mask + 1; unsigned int esize = fifo->esize; - unsigned int l; + unsigned int len_to_end; unsigned int n; off &= fifo->mask; @@ -330,10 +330,10 @@ static unsigned int setup_sgl(struct __kfifo *fifo, struct scatterlist *sgl, size *= esize; len *= esize; } - l = min(len, size - off); + len_to_end = min(len, size - off); - n = setup_sgl_buf(sgl, fifo->data + off, nents, l); - n += setup_sgl_buf(sgl + n, fifo->data, nents - n, len - l); + n = setup_sgl_buf(sgl, fifo->data + off, nents, len_to_end); + n += setup_sgl_buf(sgl + n, fifo->data, nents - n, len - len_to_end); return n; } -- cgit v1.2.3-59-g8ed1b From fea0dde081621e25bcf7efd40cce6c8272e3aa13 Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Fri, 5 Apr 2024 08:08:17 +0200 Subject: kfifo: pass offset to setup_sgl_buf() instead of a pointer As a preparatory for dma addresses filling, we need the data offset instead of virtual pointer in setup_sgl_buf(). So pass the former instead the latter. And pointer to fifo is needed in setup_sgl_buf() now too. Signed-off-by: Jiri Slaby (SUSE) Cc: Stefani Seibold Cc: Andrew Morton Link: https://lore.kernel.org/r/20240405060826.2521-7-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- lib/kfifo.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/kfifo.c b/lib/kfifo.c index 61e35550aea5..3a249ce4f281 100644 --- a/lib/kfifo.c +++ b/lib/kfifo.c @@ -305,9 +305,12 @@ int __kfifo_to_user(struct __kfifo *fifo, void __user *to, } EXPORT_SYMBOL(__kfifo_to_user); -static unsigned int setup_sgl_buf(struct scatterlist *sgl, void *buf, - int nents, unsigned int len) +static unsigned int setup_sgl_buf(struct __kfifo *fifo, struct scatterlist *sgl, + unsigned int data_offset, int nents, + unsigned int len) { + const void *buf = fifo->data + data_offset; + if (!nents || !len) return 0; @@ -332,8 +335,8 @@ static unsigned int setup_sgl(struct __kfifo *fifo, struct scatterlist *sgl, } len_to_end = min(len, size - off); - n = setup_sgl_buf(sgl, fifo->data + off, nents, len_to_end); - n += setup_sgl_buf(sgl + n, fifo->data, nents - n, len - len_to_end); + n = setup_sgl_buf(fifo, sgl, off, nents, len_to_end); + n += setup_sgl_buf(fifo, sgl + n, 0, nents - n, len - len_to_end); return n; } -- cgit v1.2.3-59-g8ed1b From d52b761e4b1acc897e65bcc8eff42b0537ac0134 Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Fri, 5 Apr 2024 08:08:18 +0200 Subject: kfifo: add kfifo_dma_out_prepare_mapped() When the kfifo buffer is already dma-mapped, one cannot use the kfifo API to fill in an SG list. Add kfifo_dma_in_prepare_mapped() which allows exactly this. A mapped dma_addr_t is passed and it is filled into provided sgl too. Including the dma_len. Signed-off-by: Jiri Slaby (SUSE) Cc: Stefani Seibold Cc: Andrew Morton Link: https://lore.kernel.org/r/20240405060826.2521-8-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- include/linux/kfifo.h | 37 +++++++++++++++++++++++++------------ lib/kfifo.c | 34 ++++++++++++++++++++++------------ 2 files changed, 47 insertions(+), 24 deletions(-) diff --git a/include/linux/kfifo.h b/include/linux/kfifo.h index 3def70e1a3e3..c7cc25b2808b 100644 --- a/include/linux/kfifo.h +++ b/include/linux/kfifo.h @@ -36,6 +36,7 @@ * to lock the reader. */ +#include #include #include #include @@ -709,11 +710,12 @@ __kfifo_int_must_check_helper( \ ) /** - * kfifo_dma_in_prepare - setup a scatterlist for DMA input + * kfifo_dma_in_prepare_mapped - setup a scatterlist for DMA input * @fifo: address of the fifo to be used * @sgl: pointer to the scatterlist array * @nents: number of entries in the scatterlist array * @len: number of elements to transfer + * @dma: mapped dma address to fill into @sgl * * This macro fills a scatterlist for DMA input. * It returns the number entries in the scatterlist array. @@ -721,7 +723,7 @@ __kfifo_int_must_check_helper( \ * Note that with only one concurrent reader and one concurrent * writer, you don't need extra locking to use these macros. */ -#define kfifo_dma_in_prepare(fifo, sgl, nents, len) \ +#define kfifo_dma_in_prepare_mapped(fifo, sgl, nents, len, dma) \ ({ \ typeof((fifo) + 1) __tmp = (fifo); \ struct scatterlist *__sgl = (sgl); \ @@ -730,10 +732,14 @@ __kfifo_int_must_check_helper( \ const size_t __recsize = sizeof(*__tmp->rectype); \ struct __kfifo *__kfifo = &__tmp->kfifo; \ (__recsize) ? \ - __kfifo_dma_in_prepare_r(__kfifo, __sgl, __nents, __len, __recsize) : \ - __kfifo_dma_in_prepare(__kfifo, __sgl, __nents, __len); \ + __kfifo_dma_in_prepare_r(__kfifo, __sgl, __nents, __len, __recsize, \ + dma) : \ + __kfifo_dma_in_prepare(__kfifo, __sgl, __nents, __len, dma); \ }) +#define kfifo_dma_in_prepare(fifo, sgl, nents, len) \ + kfifo_dma_in_prepare_mapped(fifo, sgl, nents, len, DMA_MAPPING_ERROR) + /** * kfifo_dma_in_finish - finish a DMA IN operation * @fifo: address of the fifo to be used @@ -758,11 +764,12 @@ __kfifo_int_must_check_helper( \ }) /** - * kfifo_dma_out_prepare - setup a scatterlist for DMA output + * kfifo_dma_out_prepare_mapped - setup a scatterlist for DMA output * @fifo: address of the fifo to be used * @sgl: pointer to the scatterlist array * @nents: number of entries in the scatterlist array * @len: number of elements to transfer + * @dma: mapped dma address to fill into @sgl * * This macro fills a scatterlist for DMA output which at most @len bytes * to transfer. @@ -772,7 +779,7 @@ __kfifo_int_must_check_helper( \ * Note that with only one concurrent reader and one concurrent * writer, you don't need extra locking to use these macros. */ -#define kfifo_dma_out_prepare(fifo, sgl, nents, len) \ +#define kfifo_dma_out_prepare_mapped(fifo, sgl, nents, len, dma) \ ({ \ typeof((fifo) + 1) __tmp = (fifo); \ struct scatterlist *__sgl = (sgl); \ @@ -781,10 +788,14 @@ __kfifo_int_must_check_helper( \ const size_t __recsize = sizeof(*__tmp->rectype); \ struct __kfifo *__kfifo = &__tmp->kfifo; \ (__recsize) ? \ - __kfifo_dma_out_prepare_r(__kfifo, __sgl, __nents, __len, __recsize) : \ - __kfifo_dma_out_prepare(__kfifo, __sgl, __nents, __len); \ + __kfifo_dma_out_prepare_r(__kfifo, __sgl, __nents, __len, __recsize, \ + dma) : \ + __kfifo_dma_out_prepare(__kfifo, __sgl, __nents, __len, dma); \ }) +#define kfifo_dma_out_prepare(fifo, sgl, nents, len) \ + kfifo_dma_out_prepare_mapped(fifo, sgl, nents, len, DMA_MAPPING_ERROR) + /** * kfifo_dma_out_finish - finish a DMA OUT operation * @fifo: address of the fifo to be used @@ -905,10 +916,10 @@ extern int __kfifo_to_user(struct __kfifo *fifo, void __user *to, unsigned long len, unsigned int *copied); extern unsigned int __kfifo_dma_in_prepare(struct __kfifo *fifo, - struct scatterlist *sgl, int nents, unsigned int len); + struct scatterlist *sgl, int nents, unsigned int len, dma_addr_t dma); extern unsigned int __kfifo_dma_out_prepare(struct __kfifo *fifo, - struct scatterlist *sgl, int nents, unsigned int len); + struct scatterlist *sgl, int nents, unsigned int len, dma_addr_t dma); extern unsigned int __kfifo_out_peek(struct __kfifo *fifo, void *buf, unsigned int len); @@ -930,13 +941,15 @@ extern int __kfifo_to_user_r(struct __kfifo *fifo, void __user *to, unsigned long len, unsigned int *copied, size_t recsize); extern unsigned int __kfifo_dma_in_prepare_r(struct __kfifo *fifo, - struct scatterlist *sgl, int nents, unsigned int len, size_t recsize); + struct scatterlist *sgl, int nents, unsigned int len, size_t recsize, + dma_addr_t dma); extern void __kfifo_dma_in_finish_r(struct __kfifo *fifo, unsigned int len, size_t recsize); extern unsigned int __kfifo_dma_out_prepare_r(struct __kfifo *fifo, - struct scatterlist *sgl, int nents, unsigned int len, size_t recsize); + struct scatterlist *sgl, int nents, unsigned int len, size_t recsize, + dma_addr_t dma); extern unsigned int __kfifo_len_r(struct __kfifo *fifo, size_t recsize); diff --git a/lib/kfifo.c b/lib/kfifo.c index 3a249ce4f281..75ce9225548a 100644 --- a/lib/kfifo.c +++ b/lib/kfifo.c @@ -6,6 +6,7 @@ */ #include +#include #include #include #include @@ -307,7 +308,7 @@ EXPORT_SYMBOL(__kfifo_to_user); static unsigned int setup_sgl_buf(struct __kfifo *fifo, struct scatterlist *sgl, unsigned int data_offset, int nents, - unsigned int len) + unsigned int len, dma_addr_t dma) { const void *buf = fifo->data + data_offset; @@ -316,11 +317,16 @@ static unsigned int setup_sgl_buf(struct __kfifo *fifo, struct scatterlist *sgl, sg_set_buf(sgl, buf, len); + if (dma != DMA_MAPPING_ERROR) { + sg_dma_address(sgl) = dma + data_offset; + sg_dma_len(sgl) = len; + } + return 1; } static unsigned int setup_sgl(struct __kfifo *fifo, struct scatterlist *sgl, - int nents, unsigned int len, unsigned int off) + int nents, unsigned int len, unsigned int off, dma_addr_t dma) { unsigned int size = fifo->mask + 1; unsigned int esize = fifo->esize; @@ -335,14 +341,15 @@ static unsigned int setup_sgl(struct __kfifo *fifo, struct scatterlist *sgl, } len_to_end = min(len, size - off); - n = setup_sgl_buf(fifo, sgl, off, nents, len_to_end); - n += setup_sgl_buf(fifo, sgl + n, 0, nents - n, len - len_to_end); + n = setup_sgl_buf(fifo, sgl, off, nents, len_to_end, dma); + n += setup_sgl_buf(fifo, sgl + n, 0, nents - n, len - len_to_end, dma); return n; } unsigned int __kfifo_dma_in_prepare(struct __kfifo *fifo, - struct scatterlist *sgl, int nents, unsigned int len) + struct scatterlist *sgl, int nents, unsigned int len, + dma_addr_t dma) { unsigned int l; @@ -350,12 +357,13 @@ unsigned int __kfifo_dma_in_prepare(struct __kfifo *fifo, if (len > l) len = l; - return setup_sgl(fifo, sgl, nents, len, fifo->in); + return setup_sgl(fifo, sgl, nents, len, fifo->in, dma); } EXPORT_SYMBOL(__kfifo_dma_in_prepare); unsigned int __kfifo_dma_out_prepare(struct __kfifo *fifo, - struct scatterlist *sgl, int nents, unsigned int len) + struct scatterlist *sgl, int nents, unsigned int len, + dma_addr_t dma) { unsigned int l; @@ -363,7 +371,7 @@ unsigned int __kfifo_dma_out_prepare(struct __kfifo *fifo, if (len > l) len = l; - return setup_sgl(fifo, sgl, nents, len, fifo->out); + return setup_sgl(fifo, sgl, nents, len, fifo->out, dma); } EXPORT_SYMBOL(__kfifo_dma_out_prepare); @@ -547,7 +555,8 @@ int __kfifo_to_user_r(struct __kfifo *fifo, void __user *to, EXPORT_SYMBOL(__kfifo_to_user_r); unsigned int __kfifo_dma_in_prepare_r(struct __kfifo *fifo, - struct scatterlist *sgl, int nents, unsigned int len, size_t recsize) + struct scatterlist *sgl, int nents, unsigned int len, size_t recsize, + dma_addr_t dma) { BUG_ON(!nents); @@ -556,7 +565,7 @@ unsigned int __kfifo_dma_in_prepare_r(struct __kfifo *fifo, if (len + recsize > kfifo_unused(fifo)) return 0; - return setup_sgl(fifo, sgl, nents, len, fifo->in + recsize); + return setup_sgl(fifo, sgl, nents, len, fifo->in + recsize, dma); } EXPORT_SYMBOL(__kfifo_dma_in_prepare_r); @@ -570,7 +579,8 @@ void __kfifo_dma_in_finish_r(struct __kfifo *fifo, EXPORT_SYMBOL(__kfifo_dma_in_finish_r); unsigned int __kfifo_dma_out_prepare_r(struct __kfifo *fifo, - struct scatterlist *sgl, int nents, unsigned int len, size_t recsize) + struct scatterlist *sgl, int nents, unsigned int len, size_t recsize, + dma_addr_t dma) { BUG_ON(!nents); @@ -579,7 +589,7 @@ unsigned int __kfifo_dma_out_prepare_r(struct __kfifo *fifo, if (len + recsize > fifo->in - fifo->out) return 0; - return setup_sgl(fifo, sgl, nents, len, fifo->out + recsize); + return setup_sgl(fifo, sgl, nents, len, fifo->out + recsize, dma); } EXPORT_SYMBOL(__kfifo_dma_out_prepare_r); -- cgit v1.2.3-59-g8ed1b From 2ab682d221551d5eb9606dad1efa01e184de7b00 Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Fri, 5 Apr 2024 08:08:19 +0200 Subject: kfifo: fix typos in kernel-doc Obviously: "This macro finish" -> "This macro finishes" and similar. Signed-off-by: Jiri Slaby (SUSE) Cc: Stefani Seibold Cc: Andrew Morton Link: https://lore.kernel.org/r/20240405060826.2521-9-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- include/linux/kfifo.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/include/linux/kfifo.h b/include/linux/kfifo.h index c7cc25b2808b..d613748de7ff 100644 --- a/include/linux/kfifo.h +++ b/include/linux/kfifo.h @@ -585,7 +585,7 @@ __kfifo_uint_must_check_helper( \ * @buf: pointer to the storage buffer * @n: max. number of elements to get * - * This macro get some data from the fifo and return the numbers of elements + * This macro gets some data from the fifo and returns the numbers of elements * copied. * * Note that with only one concurrent reader and one concurrent @@ -612,7 +612,7 @@ __kfifo_uint_must_check_helper( \ * @n: max. number of elements to get * @lock: pointer to the spinlock to use for locking * - * This macro get the data from the fifo and return the numbers of elements + * This macro gets the data from the fifo and returns the numbers of elements * copied. */ #define kfifo_out_spinlocked(fifo, buf, n, lock) \ @@ -745,7 +745,7 @@ __kfifo_int_must_check_helper( \ * @fifo: address of the fifo to be used * @len: number of bytes to received * - * This macro finish a DMA IN operation. The in counter will be updated by + * This macro finishes a DMA IN operation. The in counter will be updated by * the len parameter. No error checking will be done. * * Note that with only one concurrent reader and one concurrent @@ -801,7 +801,7 @@ __kfifo_int_must_check_helper( \ * @fifo: address of the fifo to be used * @len: number of bytes transferred * - * This macro finish a DMA OUT operation. The out counter will be updated by + * This macro finishes a DMA OUT operation. The out counter will be updated by * the len parameter. No error checking will be done. * * Note that with only one concurrent reader and one concurrent @@ -818,7 +818,7 @@ __kfifo_int_must_check_helper( \ * @buf: pointer to the storage buffer * @n: max. number of elements to get * - * This macro get the data from the fifo and return the numbers of elements + * This macro gets the data from the fifo and returns the numbers of elements * copied. The data is not removed from the fifo. * * Note that with only one concurrent reader and one concurrent -- cgit v1.2.3-59-g8ed1b From 8192fabb0db269a4130d8cbdd8557a47bfa1ffec Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Fri, 5 Apr 2024 08:08:20 +0200 Subject: tty: 8250_dma: use dmaengine_prep_slave_sg() This is a preparatory for the serial-to-kfifo switch. kfifo understands only scatter-gatter approach, so switch to that. No functional change intended, it's just dmaengine_prep_slave_single() inline expanded. Signed-off-by: Jiri Slaby (SUSE) Link: https://lore.kernel.org/r/20240405060826.2521-10-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_dma.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/tty/serial/8250/8250_dma.c b/drivers/tty/serial/8250/8250_dma.c index 8b30ca8fdd3f..8b2c3f478b17 100644 --- a/drivers/tty/serial/8250/8250_dma.c +++ b/drivers/tty/serial/8250/8250_dma.c @@ -89,6 +89,7 @@ int serial8250_tx_dma(struct uart_8250_port *p) struct circ_buf *xmit = &p->port.state->xmit; struct dma_async_tx_descriptor *desc; struct uart_port *up = &p->port; + struct scatterlist sg; int ret; if (dma->tx_running) { @@ -111,10 +112,13 @@ int serial8250_tx_dma(struct uart_8250_port *p) serial8250_do_prepare_tx_dma(p); - desc = dmaengine_prep_slave_single(dma->txchan, - dma->tx_addr + xmit->tail, - dma->tx_size, DMA_MEM_TO_DEV, - DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + sg_init_table(&sg, 1); + sg_dma_address(&sg) = dma->tx_addr + xmit->tail; + sg_dma_len(&sg) = dma->tx_size; + + desc = dmaengine_prep_slave_sg(dma->txchan, &sg, 1, + DMA_MEM_TO_DEV, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!desc) { ret = -EBUSY; goto err; -- cgit v1.2.3-59-g8ed1b From 9054605ab8468936a514298211d9e9bb68bf24bd Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Fri, 5 Apr 2024 08:08:21 +0200 Subject: tty: 8250_omap: use dmaengine_prep_slave_sg() This is a preparatory for the serial-to-kfifo switch. kfifo understands only scatter-gatter approach, so switch to that. No functional change intended, it's just dmaengine_prep_slave_single() inline expanded. Signed-off-by: Jiri Slaby (SUSE) Link: https://lore.kernel.org/r/20240405060826.2521-11-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_omap.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index 66901d93089a..879e77b30701 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -1140,6 +1140,7 @@ static int omap_8250_tx_dma(struct uart_8250_port *p) struct omap8250_priv *priv = p->port.private_data; struct circ_buf *xmit = &p->port.state->xmit; struct dma_async_tx_descriptor *desc; + struct scatterlist sg; unsigned int skip_byte = 0; int ret; @@ -1191,9 +1192,11 @@ static int omap_8250_tx_dma(struct uart_8250_port *p) skip_byte = 1; } - desc = dmaengine_prep_slave_single(dma->txchan, - dma->tx_addr + xmit->tail + skip_byte, - dma->tx_size - skip_byte, DMA_MEM_TO_DEV, + sg_init_table(&sg, 1); + sg_dma_address(&sg) = dma->tx_addr + xmit->tail + skip_byte; + sg_dma_len(&sg) = dma->tx_size - skip_byte; + + desc = dmaengine_prep_slave_sg(dma->txchan, &sg, 1, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!desc) { ret = -EBUSY; -- cgit v1.2.3-59-g8ed1b From f8fef2fa419febbfed2d04f0518111565df2673d Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Fri, 5 Apr 2024 08:08:22 +0200 Subject: tty: msm_serial: use dmaengine_prep_slave_sg() This is a preparatory for the serial-to-kfifo switch. kfifo understands only scatter-gatter approach, so switch to that. No functional change intended, it's just dmaengine_prep_slave_single() inline expanded. And in this case, switch from dma_map_single() to dma_map_sg() too. This needs struct msm_dma changes. I split the rx and tx parts into an union. TX is now struct scatterlist, RX remains the old good phys-virt-count triple. Signed-off-by: Jiri Slaby (SUSE) Cc: Bjorn Andersson Cc: Konrad Dybcio Cc: linux-arm-msm@vger.kernel.org Link: https://lore.kernel.org/r/20240405060826.2521-12-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/msm_serial.c | 86 +++++++++++++++++++++++------------------ 1 file changed, 49 insertions(+), 37 deletions(-) diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c index d27c4c8c84e1..7bf30e632313 100644 --- a/drivers/tty/serial/msm_serial.c +++ b/drivers/tty/serial/msm_serial.c @@ -161,11 +161,16 @@ enum { struct msm_dma { struct dma_chan *chan; enum dma_data_direction dir; - dma_addr_t phys; - unsigned char *virt; + union { + struct { + dma_addr_t phys; + unsigned char *virt; + unsigned int count; + } rx; + struct scatterlist tx_sg; + }; dma_cookie_t cookie; u32 enable_bit; - unsigned int count; struct dma_async_tx_descriptor *desc; }; @@ -249,8 +254,12 @@ static void msm_stop_dma(struct uart_port *port, struct msm_dma *dma) unsigned int mapped; u32 val; - mapped = dma->count; - dma->count = 0; + if (dma->dir == DMA_TO_DEVICE) { + mapped = sg_dma_len(&dma->tx_sg); + } else { + mapped = dma->rx.count; + dma->rx.count = 0; + } dmaengine_terminate_all(dma->chan); @@ -265,8 +274,13 @@ static void msm_stop_dma(struct uart_port *port, struct msm_dma *dma) val &= ~dma->enable_bit; msm_write(port, val, UARTDM_DMEN); - if (mapped) - dma_unmap_single(dev, dma->phys, mapped, dma->dir); + if (mapped) { + if (dma->dir == DMA_TO_DEVICE) { + dma_unmap_sg(dev, &dma->tx_sg, 1, dma->dir); + sg_init_table(&dma->tx_sg, 1); + } else + dma_unmap_single(dev, dma->rx.phys, mapped, dma->dir); + } } static void msm_release_dma(struct msm_port *msm_port) @@ -285,7 +299,7 @@ static void msm_release_dma(struct msm_port *msm_port) if (dma->chan) { msm_stop_dma(&msm_port->uart, dma); dma_release_channel(dma->chan); - kfree(dma->virt); + kfree(dma->rx.virt); } memset(dma, 0, sizeof(*dma)); @@ -357,8 +371,8 @@ static void msm_request_rx_dma(struct msm_port *msm_port, resource_size_t base) of_property_read_u32(dev->of_node, "qcom,rx-crci", &crci); - dma->virt = kzalloc(UARTDM_RX_SIZE, GFP_KERNEL); - if (!dma->virt) + dma->rx.virt = kzalloc(UARTDM_RX_SIZE, GFP_KERNEL); + if (!dma->rx.virt) goto rel_rx; memset(&conf, 0, sizeof(conf)); @@ -385,7 +399,7 @@ static void msm_request_rx_dma(struct msm_port *msm_port, resource_size_t base) return; err: - kfree(dma->virt); + kfree(dma->rx.virt); rel_rx: dma_release_channel(dma->chan); no_rx: @@ -420,7 +434,7 @@ static void msm_start_tx(struct uart_port *port) struct msm_dma *dma = &msm_port->tx_dma; /* Already started in DMA mode */ - if (dma->count) + if (sg_dma_len(&dma->tx_sg)) return; msm_port->imr |= MSM_UART_IMR_TXLEV; @@ -448,12 +462,12 @@ static void msm_complete_tx_dma(void *args) uart_port_lock_irqsave(port, &flags); /* Already stopped */ - if (!dma->count) + if (!sg_dma_len(&dma->tx_sg)) goto done; dmaengine_tx_status(dma->chan, dma->cookie, &state); - dma_unmap_single(port->dev, dma->phys, dma->count, dma->dir); + dma_unmap_sg(port->dev, &dma->tx_sg, 1, dma->dir); val = msm_read(port, UARTDM_DMEN); val &= ~dma->enable_bit; @@ -464,9 +478,9 @@ static void msm_complete_tx_dma(void *args) msm_write(port, MSM_UART_CR_TX_ENABLE, MSM_UART_CR); } - count = dma->count - state.residue; + count = sg_dma_len(&dma->tx_sg) - state.residue; uart_xmit_advance(port, count); - dma->count = 0; + sg_init_table(&dma->tx_sg, 1); /* Restore "Tx FIFO below watermark" interrupt */ msm_port->imr |= MSM_UART_IMR_TXLEV; @@ -485,19 +499,18 @@ static int msm_handle_tx_dma(struct msm_port *msm_port, unsigned int count) struct circ_buf *xmit = &msm_port->uart.state->xmit; struct uart_port *port = &msm_port->uart; struct msm_dma *dma = &msm_port->tx_dma; - void *cpu_addr; int ret; u32 val; - cpu_addr = &xmit->buf[xmit->tail]; + sg_init_table(&dma->tx_sg, 1); + sg_set_buf(&dma->tx_sg, &xmit->buf[xmit->tail], count); - dma->phys = dma_map_single(port->dev, cpu_addr, count, dma->dir); - ret = dma_mapping_error(port->dev, dma->phys); + ret = dma_map_sg(port->dev, &dma->tx_sg, 1, dma->dir); if (ret) return ret; - dma->desc = dmaengine_prep_slave_single(dma->chan, dma->phys, - count, DMA_MEM_TO_DEV, + dma->desc = dmaengine_prep_slave_sg(dma->chan, &dma->tx_sg, 1, + DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_PREP_FENCE); if (!dma->desc) { @@ -520,8 +533,6 @@ static int msm_handle_tx_dma(struct msm_port *msm_port, unsigned int count) msm_port->imr &= ~MSM_UART_IMR_TXLEV; msm_write(port, msm_port->imr, MSM_UART_IMR); - dma->count = count; - val = msm_read(port, UARTDM_DMEN); val |= dma->enable_bit; @@ -536,7 +547,8 @@ static int msm_handle_tx_dma(struct msm_port *msm_port, unsigned int count) dma_async_issue_pending(dma->chan); return 0; unmap: - dma_unmap_single(port->dev, dma->phys, count, dma->dir); + dma_unmap_sg(port->dev, &dma->tx_sg, 1, dma->dir); + sg_init_table(&dma->tx_sg, 1); return ret; } @@ -553,7 +565,7 @@ static void msm_complete_rx_dma(void *args) uart_port_lock_irqsave(port, &flags); /* Already stopped */ - if (!dma->count) + if (!dma->rx.count) goto done; val = msm_read(port, UARTDM_DMEN); @@ -570,14 +582,14 @@ static void msm_complete_rx_dma(void *args) port->icount.rx += count; - dma->count = 0; + dma->rx.count = 0; - dma_unmap_single(port->dev, dma->phys, UARTDM_RX_SIZE, dma->dir); + dma_unmap_single(port->dev, dma->rx.phys, UARTDM_RX_SIZE, dma->dir); for (i = 0; i < count; i++) { char flag = TTY_NORMAL; - if (msm_port->break_detected && dma->virt[i] == 0) { + if (msm_port->break_detected && dma->rx.virt[i] == 0) { port->icount.brk++; flag = TTY_BREAK; msm_port->break_detected = false; @@ -588,9 +600,9 @@ static void msm_complete_rx_dma(void *args) if (!(port->read_status_mask & MSM_UART_SR_RX_BREAK)) flag = TTY_NORMAL; - sysrq = uart_prepare_sysrq_char(port, dma->virt[i]); + sysrq = uart_prepare_sysrq_char(port, dma->rx.virt[i]); if (!sysrq) - tty_insert_flip_char(tport, dma->virt[i], flag); + tty_insert_flip_char(tport, dma->rx.virt[i], flag); } msm_start_rx_dma(msm_port); @@ -614,13 +626,13 @@ static void msm_start_rx_dma(struct msm_port *msm_port) if (!dma->chan) return; - dma->phys = dma_map_single(uart->dev, dma->virt, + dma->rx.phys = dma_map_single(uart->dev, dma->rx.virt, UARTDM_RX_SIZE, dma->dir); - ret = dma_mapping_error(uart->dev, dma->phys); + ret = dma_mapping_error(uart->dev, dma->rx.phys); if (ret) goto sw_mode; - dma->desc = dmaengine_prep_slave_single(dma->chan, dma->phys, + dma->desc = dmaengine_prep_slave_single(dma->chan, dma->rx.phys, UARTDM_RX_SIZE, DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT); if (!dma->desc) @@ -648,7 +660,7 @@ static void msm_start_rx_dma(struct msm_port *msm_port) msm_write(uart, msm_port->imr, MSM_UART_IMR); - dma->count = UARTDM_RX_SIZE; + dma->rx.count = UARTDM_RX_SIZE; dma_async_issue_pending(dma->chan); @@ -668,7 +680,7 @@ static void msm_start_rx_dma(struct msm_port *msm_port) return; unmap: - dma_unmap_single(uart->dev, dma->phys, UARTDM_RX_SIZE, dma->dir); + dma_unmap_single(uart->dev, dma->rx.phys, UARTDM_RX_SIZE, dma->dir); sw_mode: /* @@ -955,7 +967,7 @@ static irqreturn_t msm_uart_irq(int irq, void *dev_id) } if (misr & (MSM_UART_IMR_RXLEV | MSM_UART_IMR_RXSTALE)) { - if (dma->count) { + if (dma->rx.count) { val = MSM_UART_CR_CMD_STALE_EVENT_DISABLE; msm_write(port, val, MSM_UART_CR); val = MSM_UART_CR_CMD_RESET_STALE_INT; -- cgit v1.2.3-59-g8ed1b From 1788cf6a91d9fa9aa61fc2917afe192c23d67f6a Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Fri, 5 Apr 2024 08:08:23 +0200 Subject: tty: serial: switch from circ_buf to kfifo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Switch from struct circ_buf to proper kfifo. kfifo provides much better API, esp. when wrap-around of the buffer needs to be taken into account. Look at pl011_dma_tx_refill() or cpm_uart_tx_pump() changes for example. Kfifo API can also fill in scatter-gather DMA structures, so it easier for that use case too. Look at lpuart_dma_tx() for example. Note that not all drivers can be converted to that (like atmel_serial), they handle DMA specially. Note that usb-serial uses kfifo for TX for ages. omap needed a bit more care as it needs to put a char into FIFO to start the DMA transfer when OMAP_DMA_TX_KICK is set. In that case, we have to do kfifo_dma_out_prepare twice: once to find out the tx_size (to find out if it is worths to do DMA at all -- size >= 4), the second time for the actual transfer. All traces of circ_buf are removed from serial_core.h (and its struct uart_state). Signed-off-by: Jiri Slaby (SUSE) Cc: Al Cooper Cc: Matthias Brugger Cc: AngeloGioacchino Del Regno Cc: Kumaravel Thiagarajan Cc: Tharun Kumar P Cc: Russell King Cc: Vineet Gupta Cc: Richard Genoud Cc: Nicolas Ferre Cc: Alexandre Belloni Cc: Claudiu Beznea Cc: Alexander Shiyan Cc: Baruch Siach Cc: Maciej W. Rozycki Cc: Shawn Guo Cc: Sascha Hauer Cc: Fabio Estevam Cc: Neil Armstrong Cc: Kevin Hilman Cc: Jerome Brunet Cc: Martin Blumenstingl Cc: Taichi Sugaya Cc: Takao Orito Cc: Bjorn Andersson Cc: Konrad Dybcio Cc: Pali Rohár Cc: Michael Ellerman Cc: Nicholas Piggin Cc: Christophe Leroy Cc: Aneesh Kumar K.V Cc: Naveen N. Rao Cc: Manivannan Sadhasivam Cc: Krzysztof Kozlowski Cc: Alim Akhtar Cc: Laxman Dewangan Cc: Thierry Reding Cc: Jonathan Hunter Cc: Orson Zhai Cc: Baolin Wang Cc: Chunyan Zhang Cc: Patrice Chotard Cc: Maxime Coquelin Cc: Alexandre Torgue Cc: David S. Miller Cc: Hammer Hsieh Cc: Peter Korsgaard Cc: Timur Tabi Cc: Michal Simek Cc: Sumit Semwal Cc: Christian König Link: https://lore.kernel.org/r/20240405060826.2521-13-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_bcm7271.c | 14 ++++---- drivers/tty/serial/8250/8250_core.c | 3 +- drivers/tty/serial/8250/8250_dma.c | 23 +++++++------ drivers/tty/serial/8250/8250_exar.c | 5 +-- drivers/tty/serial/8250/8250_mtk.c | 2 +- drivers/tty/serial/8250/8250_omap.c | 47 ++++++++++++++++++--------- drivers/tty/serial/8250/8250_pci1xxxx.c | 50 +++++++++++++---------------- drivers/tty/serial/8250/8250_port.c | 22 +++++++------ drivers/tty/serial/amba-pl011.c | 46 +++++++++++--------------- drivers/tty/serial/ar933x_uart.c | 15 ++++----- drivers/tty/serial/arc_uart.c | 8 ++--- drivers/tty/serial/atmel_serial.c | 57 +++++++++++++++++---------------- drivers/tty/serial/clps711x.c | 12 +++---- drivers/tty/serial/cpm_uart.c | 20 ++++-------- drivers/tty/serial/digicolor-usart.c | 12 +++---- drivers/tty/serial/dz.c | 13 ++++---- drivers/tty/serial/fsl_linflexuart.c | 17 +++++----- drivers/tty/serial/fsl_lpuart.c | 39 ++++++++++------------ drivers/tty/serial/icom.c | 25 ++++----------- drivers/tty/serial/imx.c | 54 +++++++++++++------------------ drivers/tty/serial/ip22zilog.c | 26 +++++++-------- drivers/tty/serial/jsm/jsm_cls.c | 29 +++++------------ drivers/tty/serial/jsm/jsm_neo.c | 38 ++++++++-------------- drivers/tty/serial/max3100.c | 14 ++++---- drivers/tty/serial/max310x.c | 35 +++++++++----------- drivers/tty/serial/men_z135_uart.c | 26 ++++++--------- drivers/tty/serial/meson_uart.c | 11 +++---- drivers/tty/serial/milbeaut_usio.c | 15 +++++---- drivers/tty/serial/msm_serial.c | 30 ++++++++--------- drivers/tty/serial/mvebu-uart.c | 8 ++--- drivers/tty/serial/mxs-auart.c | 23 ++++--------- drivers/tty/serial/pch_uart.c | 21 ++++++------ drivers/tty/serial/pic32_uart.c | 15 ++++----- drivers/tty/serial/pmac_zilog.c | 24 +++++++------- drivers/tty/serial/qcom_geni_serial.c | 36 ++++++++++----------- drivers/tty/serial/rda-uart.c | 17 ++++------ drivers/tty/serial/samsung_tty.c | 54 ++++++++++++++++--------------- drivers/tty/serial/sb1250-duart.c | 13 ++++---- drivers/tty/serial/sc16is7xx.c | 40 +++++++++-------------- drivers/tty/serial/sccnxp.c | 16 +++++---- drivers/tty/serial/serial-tegra.c | 43 ++++++++++++++----------- drivers/tty/serial/serial_core.c | 56 ++++++++++++-------------------- drivers/tty/serial/serial_port.c | 2 +- drivers/tty/serial/sh-sci.c | 51 +++++++++++++++-------------- drivers/tty/serial/sprd_serial.c | 20 ++++++------ drivers/tty/serial/st-asc.c | 4 +-- drivers/tty/serial/stm32-usart.c | 52 ++++++++++++------------------ drivers/tty/serial/sunhv.c | 35 +++++++++++--------- drivers/tty/serial/sunplus-uart.c | 16 +++++---- drivers/tty/serial/sunsab.c | 30 +++++++++-------- drivers/tty/serial/sunsu.c | 15 +++++---- drivers/tty/serial/sunzilog.c | 27 ++++++++-------- drivers/tty/serial/tegra-tcu.c | 10 +++--- drivers/tty/serial/timbuart.c | 17 ++++------ drivers/tty/serial/uartlite.c | 13 +++++--- drivers/tty/serial/ucc_uart.c | 20 ++++-------- drivers/tty/serial/xilinx_uartps.c | 20 ++++++------ drivers/tty/serial/zs.c | 13 ++++---- include/linux/serial_core.h | 49 +++++++++++++++++----------- 59 files changed, 688 insertions(+), 780 deletions(-) diff --git a/drivers/tty/serial/8250/8250_bcm7271.c b/drivers/tty/serial/8250/8250_bcm7271.c index 5daa38d9c64e..de270863eb5e 100644 --- a/drivers/tty/serial/8250/8250_bcm7271.c +++ b/drivers/tty/serial/8250/8250_bcm7271.c @@ -413,20 +413,18 @@ static int stop_tx_dma(struct uart_8250_port *p) static int brcmuart_tx_dma(struct uart_8250_port *p) { struct brcmuart_priv *priv = p->port.private_data; - struct circ_buf *xmit = &p->port.state->xmit; + struct tty_port *tport = &p->port.state->port; u32 tx_size; if (uart_tx_stopped(&p->port) || priv->tx_running || - uart_circ_empty(xmit)) { + kfifo_is_empty(&tport->xmit_fifo)) { return 0; } - tx_size = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); priv->dma.tx_err = 0; - memcpy(priv->tx_buf, &xmit->buf[xmit->tail], tx_size); - uart_xmit_advance(&p->port, tx_size); + tx_size = uart_fifo_out(&p->port, priv->tx_buf, UART_XMIT_SIZE); - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(&p->port); udma_writel(priv, REGS_DMA_TX, UDMA_TX_TRANSFER_LEN, tx_size); @@ -540,7 +538,7 @@ static void brcmuart_tx_isr(struct uart_port *up, u32 isr) struct brcmuart_priv *priv = up->private_data; struct device *dev = up->dev; struct uart_8250_port *port_8250 = up_to_u8250p(up); - struct circ_buf *xmit = &port_8250->port.state->xmit; + struct tty_port *tport = &port_8250->port.state->port; if (isr & UDMA_INTR_TX_ABORT) { if (priv->tx_running) @@ -548,7 +546,7 @@ static void brcmuart_tx_isr(struct uart_port *up, u32 isr) return; } priv->tx_running = false; - if (!uart_circ_empty(xmit) && !uart_tx_stopped(up)) + if (!kfifo_is_empty(&tport->xmit_fifo) && !uart_tx_stopped(up)) brcmuart_tx_dma(port_8250); } diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index b62ad9006780..3a1936b7f05f 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -280,7 +280,8 @@ static void serial8250_backup_timeout(struct timer_list *t) */ lsr = serial_lsr_in(up); if ((iir & UART_IIR_NO_INT) && (up->ier & UART_IER_THRI) && - (!uart_circ_empty(&up->port.state->xmit) || up->port.x_char) && + (!kfifo_is_empty(&up->port.state->port.xmit_fifo) || + up->port.x_char) && (lsr & UART_LSR_THRE)) { iir &= ~(UART_IIR_ID | UART_IIR_NO_INT); iir |= UART_IIR_THRI; diff --git a/drivers/tty/serial/8250/8250_dma.c b/drivers/tty/serial/8250/8250_dma.c index 8b2c3f478b17..8a353e3cc3dd 100644 --- a/drivers/tty/serial/8250/8250_dma.c +++ b/drivers/tty/serial/8250/8250_dma.c @@ -15,7 +15,7 @@ static void __dma_tx_complete(void *param) { struct uart_8250_port *p = param; struct uart_8250_dma *dma = p->dma; - struct circ_buf *xmit = &p->port.state->xmit; + struct tty_port *tport = &p->port.state->port; unsigned long flags; int ret; @@ -28,7 +28,7 @@ static void __dma_tx_complete(void *param) uart_xmit_advance(&p->port, dma->tx_size); - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(&p->port); ret = serial8250_tx_dma(p); @@ -86,7 +86,7 @@ static void dma_rx_complete(void *param) int serial8250_tx_dma(struct uart_8250_port *p) { struct uart_8250_dma *dma = p->dma; - struct circ_buf *xmit = &p->port.state->xmit; + struct tty_port *tport = &p->port.state->port; struct dma_async_tx_descriptor *desc; struct uart_port *up = &p->port; struct scatterlist sg; @@ -103,18 +103,23 @@ int serial8250_tx_dma(struct uart_8250_port *p) uart_xchar_out(up, UART_TX); } - if (uart_tx_stopped(&p->port) || uart_circ_empty(xmit)) { + if (uart_tx_stopped(&p->port) || kfifo_is_empty(&tport->xmit_fifo)) { /* We have been called from __dma_tx_complete() */ return 0; } - dma->tx_size = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); - serial8250_do_prepare_tx_dma(p); sg_init_table(&sg, 1); - sg_dma_address(&sg) = dma->tx_addr + xmit->tail; - sg_dma_len(&sg) = dma->tx_size; + /* kfifo can do more than one sg, we don't (quite yet) */ + ret = kfifo_dma_out_prepare_mapped(&tport->xmit_fifo, &sg, 1, + UART_XMIT_SIZE, dma->tx_addr); + + /* we already checked empty fifo above, so there should be something */ + if (WARN_ON_ONCE(ret != 1)) + return 0; + + dma->tx_size = sg_dma_len(&sg); desc = dmaengine_prep_slave_sg(dma->txchan, &sg, 1, DMA_MEM_TO_DEV, @@ -257,7 +262,7 @@ int serial8250_request_dma(struct uart_8250_port *p) /* TX buffer */ dma->tx_addr = dma_map_single(dma->txchan->device->dev, - p->port.state->xmit.buf, + p->port.state->port.xmit_buf, UART_XMIT_SIZE, DMA_TO_DEVICE); if (dma_mapping_error(dma->txchan->device->dev, dma->tx_addr)) { diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c index 0440df7de1ed..f89dabfc0f97 100644 --- a/drivers/tty/serial/8250/8250_exar.c +++ b/drivers/tty/serial/8250/8250_exar.c @@ -214,7 +214,7 @@ static void exar_shutdown(struct uart_port *port) { bool tx_complete = false; struct uart_8250_port *up = up_to_u8250p(port); - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; int i = 0; u16 lsr; @@ -225,7 +225,8 @@ static void exar_shutdown(struct uart_port *port) else tx_complete = false; usleep_range(1000, 1100); - } while (!uart_circ_empty(xmit) && !tx_complete && i++ < 1000); + } while (!kfifo_is_empty(&tport->xmit_fifo) && + !tx_complete && i++ < 1000); serial8250_do_shutdown(port); } diff --git a/drivers/tty/serial/8250/8250_mtk.c b/drivers/tty/serial/8250/8250_mtk.c index 9ff6bbe9c086..c365a349421a 100644 --- a/drivers/tty/serial/8250/8250_mtk.c +++ b/drivers/tty/serial/8250/8250_mtk.c @@ -199,7 +199,7 @@ static int mtk8250_startup(struct uart_port *port) if (up->dma) { data->rx_status = DMA_RX_START; - uart_circ_clear(&port->state->xmit); + kfifo_reset(&port->state->port.xmit_fifo); } #endif memset(&port->icount, 0, sizeof(port->icount)); diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index 879e77b30701..c07d924d5add 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -1094,7 +1094,7 @@ static void omap_8250_dma_tx_complete(void *param) { struct uart_8250_port *p = param; struct uart_8250_dma *dma = p->dma; - struct circ_buf *xmit = &p->port.state->xmit; + struct tty_port *tport = &p->port.state->port; unsigned long flags; bool en_thri = false; struct omap8250_priv *priv = p->port.private_data; @@ -1113,10 +1113,10 @@ static void omap_8250_dma_tx_complete(void *param) omap8250_restore_regs(p); } - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(&p->port); - if (!uart_circ_empty(xmit) && !uart_tx_stopped(&p->port)) { + if (!kfifo_is_empty(&tport->xmit_fifo) && !uart_tx_stopped(&p->port)) { int ret; ret = omap_8250_tx_dma(p); @@ -1138,15 +1138,15 @@ static int omap_8250_tx_dma(struct uart_8250_port *p) { struct uart_8250_dma *dma = p->dma; struct omap8250_priv *priv = p->port.private_data; - struct circ_buf *xmit = &p->port.state->xmit; + struct tty_port *tport = &p->port.state->port; struct dma_async_tx_descriptor *desc; struct scatterlist sg; - unsigned int skip_byte = 0; + int skip_byte = -1; int ret; if (dma->tx_running) return 0; - if (uart_tx_stopped(&p->port) || uart_circ_empty(xmit)) { + if (uart_tx_stopped(&p->port) || kfifo_is_empty(&tport->xmit_fifo)) { /* * Even if no data, we need to return an error for the two cases @@ -1161,8 +1161,18 @@ static int omap_8250_tx_dma(struct uart_8250_port *p) return 0; } - dma->tx_size = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); + sg_init_table(&sg, 1); + ret = kfifo_dma_out_prepare_mapped(&tport->xmit_fifo, &sg, 1, + UART_XMIT_SIZE, dma->tx_addr); + if (ret != 1) { + serial8250_clear_THRI(p); + return 0; + } + + dma->tx_size = sg_dma_len(&sg); + if (priv->habit & OMAP_DMA_TX_KICK) { + unsigned char c; u8 tx_lvl; /* @@ -1189,13 +1199,16 @@ static int omap_8250_tx_dma(struct uart_8250_port *p) ret = -EINVAL; goto err; } - skip_byte = 1; + if (!kfifo_get(&tport->xmit_fifo, &c)) { + ret = -EINVAL; + goto err; + } + skip_byte = c; + /* now we need to recompute due to kfifo_get */ + kfifo_dma_out_prepare_mapped(&tport->xmit_fifo, &sg, 1, + UART_XMIT_SIZE, dma->tx_addr); } - sg_init_table(&sg, 1); - sg_dma_address(&sg) = dma->tx_addr + xmit->tail + skip_byte; - sg_dma_len(&sg) = dma->tx_size - skip_byte; - desc = dmaengine_prep_slave_sg(dma->txchan, &sg, 1, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!desc) { @@ -1218,11 +1231,13 @@ static int omap_8250_tx_dma(struct uart_8250_port *p) dma->tx_err = 0; serial8250_clear_THRI(p); - if (skip_byte) - serial_out(p, UART_TX, xmit->buf[xmit->tail]); - return 0; + ret = 0; + goto out_skip; err: dma->tx_err = 1; +out_skip: + if (skip_byte >= 0) + serial_out(p, UART_TX, skip_byte); return ret; } @@ -1311,7 +1326,7 @@ static int omap_8250_dma_handle_irq(struct uart_port *port) serial8250_modem_status(up); if (status & UART_LSR_THRE && up->dma->tx_err) { if (uart_tx_stopped(&up->port) || - uart_circ_empty(&up->port.state->xmit)) { + kfifo_is_empty(&up->port.state->port.xmit_fifo)) { up->dma->tx_err = 0; serial8250_tx_chars(up); } else { diff --git a/drivers/tty/serial/8250/8250_pci1xxxx.c b/drivers/tty/serial/8250/8250_pci1xxxx.c index 2fbb5851f788..d3930bf32fe4 100644 --- a/drivers/tty/serial/8250/8250_pci1xxxx.c +++ b/drivers/tty/serial/8250/8250_pci1xxxx.c @@ -382,10 +382,10 @@ static void pci1xxxx_rx_burst(struct uart_port *port, u32 uart_status) } static void pci1xxxx_process_write_data(struct uart_port *port, - struct circ_buf *xmit, int *data_empty_count, u32 *valid_byte_count) { + struct tty_port *tport = &port->state->port; u32 valid_burst_count = *valid_byte_count / UART_BURST_SIZE; /* @@ -395,41 +395,36 @@ static void pci1xxxx_process_write_data(struct uart_port *port, * one byte at a time. */ while (valid_burst_count) { + u32 c; + if (*data_empty_count - UART_BURST_SIZE < 0) break; - if (xmit->tail > (UART_XMIT_SIZE - UART_BURST_SIZE)) + if (kfifo_len(&tport->xmit_fifo) < UART_BURST_SIZE) + break; + if (WARN_ON(kfifo_out(&tport->xmit_fifo, (u8 *)&c, sizeof(c)) != + sizeof(c))) break; - writel(*(unsigned int *)&xmit->buf[xmit->tail], - port->membase + UART_TX_BURST_FIFO); + writel(c, port->membase + UART_TX_BURST_FIFO); *valid_byte_count -= UART_BURST_SIZE; *data_empty_count -= UART_BURST_SIZE; valid_burst_count -= UART_BYTE_SIZE; - - xmit->tail = (xmit->tail + UART_BURST_SIZE) & - (UART_XMIT_SIZE - 1); } while (*valid_byte_count) { - if (*data_empty_count - UART_BYTE_SIZE < 0) + u8 c; + + if (!kfifo_get(&tport->xmit_fifo, &c)) break; - writeb(xmit->buf[xmit->tail], port->membase + - UART_TX_BYTE_FIFO); + writeb(c, port->membase + UART_TX_BYTE_FIFO); *data_empty_count -= UART_BYTE_SIZE; *valid_byte_count -= UART_BYTE_SIZE; - /* - * When the tail of the circular buffer is reached, the next - * byte is transferred to the beginning of the buffer. - */ - xmit->tail = (xmit->tail + UART_BYTE_SIZE) & - (UART_XMIT_SIZE - 1); - /* * If there are any pending burst count, data is handled by * transmitting DWORDs at a time. */ - if (valid_burst_count && (xmit->tail < - (UART_XMIT_SIZE - UART_BURST_SIZE))) + if (valid_burst_count && + kfifo_len(&tport->xmit_fifo) >= UART_BURST_SIZE) break; } } @@ -437,11 +432,9 @@ static void pci1xxxx_process_write_data(struct uart_port *port, static void pci1xxxx_tx_burst(struct uart_port *port, u32 uart_status) { struct uart_8250_port *up = up_to_u8250p(port); + struct tty_port *tport = &port->state->port; u32 valid_byte_count; int data_empty_count; - struct circ_buf *xmit; - - xmit = &port->state->xmit; if (port->x_char) { writeb(port->x_char, port->membase + UART_TX); @@ -450,25 +443,25 @@ static void pci1xxxx_tx_burst(struct uart_port *port, u32 uart_status) return; } - if ((uart_tx_stopped(port)) || (uart_circ_empty(xmit))) { + if ((uart_tx_stopped(port)) || kfifo_is_empty(&tport->xmit_fifo)) { port->ops->stop_tx(port); } else { data_empty_count = (pci1xxxx_read_burst_status(port) & UART_BST_STAT_TX_COUNT_MASK) >> 8; do { - valid_byte_count = uart_circ_chars_pending(xmit); + valid_byte_count = kfifo_len(&tport->xmit_fifo); - pci1xxxx_process_write_data(port, xmit, + pci1xxxx_process_write_data(port, &data_empty_count, &valid_byte_count); port->icount.tx++; - if (uart_circ_empty(xmit)) + if (kfifo_is_empty(&tport->xmit_fifo)) break; } while (data_empty_count && valid_byte_count); } - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(port); /* @@ -476,7 +469,8 @@ static void pci1xxxx_tx_burst(struct uart_port *port, u32 uart_status) * the HW can go idle. So we get here once again with empty FIFO and * disable the interrupt and RPM in __stop_tx() */ - if (uart_circ_empty(xmit) && !(up->capabilities & UART_CAP_RPM)) + if (kfifo_is_empty(&tport->xmit_fifo) && + !(up->capabilities & UART_CAP_RPM)) port->ops->stop_tx(port); } diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index fc9dd5d45295..0c19451d0332 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -1630,7 +1630,7 @@ static void serial8250_start_tx(struct uart_port *port) /* Port locked to synchronize UART_IER access against the console. */ lockdep_assert_held_once(&port->lock); - if (!port->x_char && uart_circ_empty(&port->state->xmit)) + if (!port->x_char && kfifo_is_empty(&port->state->port.xmit_fifo)) return; serial8250_rpm_get_tx(up); @@ -1778,7 +1778,7 @@ EXPORT_SYMBOL_GPL(serial8250_rx_chars); void serial8250_tx_chars(struct uart_8250_port *up) { struct uart_port *port = &up->port; - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; int count; if (port->x_char) { @@ -1789,14 +1789,19 @@ void serial8250_tx_chars(struct uart_8250_port *up) serial8250_stop_tx(port); return; } - if (uart_circ_empty(xmit)) { + if (kfifo_is_empty(&tport->xmit_fifo)) { __stop_tx(up); return; } count = up->tx_loadsz; do { - serial_out(up, UART_TX, xmit->buf[xmit->tail]); + unsigned char c; + + if (!uart_fifo_get(port, &c)) + break; + + serial_out(up, UART_TX, c); if (up->bugs & UART_BUG_TXRACE) { /* * The Aspeed BMC virtual UARTs have a bug where data @@ -1809,9 +1814,7 @@ void serial8250_tx_chars(struct uart_8250_port *up) */ serial_in(up, UART_SCR); } - uart_xmit_advance(port, 1); - if (uart_circ_empty(xmit)) - break; + if ((up->capabilities & UART_CAP_HFIFO) && !uart_lsr_tx_empty(serial_in(up, UART_LSR))) break; @@ -1821,7 +1824,7 @@ void serial8250_tx_chars(struct uart_8250_port *up) break; } while (--count > 0); - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(port); /* @@ -1829,7 +1832,8 @@ void serial8250_tx_chars(struct uart_8250_port *up) * HW can go idle. So we get here once again with empty FIFO and disable * the interrupt and RPM in __stop_tx() */ - if (uart_circ_empty(xmit) && !(up->capabilities & UART_CAP_RPM)) + if (kfifo_is_empty(&tport->xmit_fifo) && + !(up->capabilities & UART_CAP_RPM)) __stop_tx(up); } EXPORT_SYMBOL_GPL(serial8250_tx_chars); diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 2fa3fb30dc6c..51b202eb8296 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -535,6 +535,7 @@ static void pl011_start_tx_pio(struct uart_amba_port *uap); static void pl011_dma_tx_callback(void *data) { struct uart_amba_port *uap = data; + struct tty_port *tport = &uap->port.state->port; struct pl011_dmatx_data *dmatx = &uap->dmatx; unsigned long flags; u16 dmacr; @@ -558,7 +559,7 @@ static void pl011_dma_tx_callback(void *data) * get further refills (hence we check dmacr). */ if (!(dmacr & UART011_TXDMAE) || uart_tx_stopped(&uap->port) || - uart_circ_empty(&uap->port.state->xmit)) { + kfifo_is_empty(&tport->xmit_fifo)) { uap->dmatx.queued = false; uart_port_unlock_irqrestore(&uap->port, flags); return; @@ -588,7 +589,7 @@ static int pl011_dma_tx_refill(struct uart_amba_port *uap) struct dma_chan *chan = dmatx->chan; struct dma_device *dma_dev = chan->device; struct dma_async_tx_descriptor *desc; - struct circ_buf *xmit = &uap->port.state->xmit; + struct tty_port *tport = &uap->port.state->port; unsigned int count; /* @@ -597,7 +598,7 @@ static int pl011_dma_tx_refill(struct uart_amba_port *uap) * the standard interrupt handling. This ensures that we * issue a uart_write_wakeup() at the appropriate time. */ - count = uart_circ_chars_pending(xmit); + count = kfifo_len(&tport->xmit_fifo); if (count < (uap->fifosize >> 1)) { uap->dmatx.queued = false; return 0; @@ -613,21 +614,7 @@ static int pl011_dma_tx_refill(struct uart_amba_port *uap) if (count > PL011_DMA_BUFFER_SIZE) count = PL011_DMA_BUFFER_SIZE; - if (xmit->tail < xmit->head) { - memcpy(&dmatx->buf[0], &xmit->buf[xmit->tail], count); - } else { - size_t first = UART_XMIT_SIZE - xmit->tail; - size_t second; - - if (first > count) - first = count; - second = count - first; - - memcpy(&dmatx->buf[0], &xmit->buf[xmit->tail], first); - if (second) - memcpy(&dmatx->buf[first], &xmit->buf[0], second); - } - + count = kfifo_out_peek(&tport->xmit_fifo, dmatx->buf, count); dmatx->len = count; dmatx->dma = dma_map_single(dma_dev->dev, dmatx->buf, count, DMA_TO_DEVICE); @@ -670,7 +657,7 @@ static int pl011_dma_tx_refill(struct uart_amba_port *uap) */ uart_xmit_advance(&uap->port, count); - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(&uap->port); return 1; @@ -1454,7 +1441,7 @@ static bool pl011_tx_char(struct uart_amba_port *uap, unsigned char c, /* Returns true if tx interrupts have to be (kept) enabled */ static bool pl011_tx_chars(struct uart_amba_port *uap, bool from_irq) { - struct circ_buf *xmit = &uap->port.state->xmit; + struct tty_port *tport = &uap->port.state->port; int count = uap->fifosize >> 1; if (uap->port.x_char) { @@ -1463,7 +1450,7 @@ static bool pl011_tx_chars(struct uart_amba_port *uap, bool from_irq) uap->port.x_char = 0; --count; } - if (uart_circ_empty(xmit) || uart_tx_stopped(&uap->port)) { + if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(&uap->port)) { pl011_stop_tx(&uap->port); return false; } @@ -1472,20 +1459,25 @@ static bool pl011_tx_chars(struct uart_amba_port *uap, bool from_irq) if (pl011_dma_tx_irq(uap)) return true; - do { + while (1) { + unsigned char c; + if (likely(from_irq) && count-- == 0) break; - if (!pl011_tx_char(uap, xmit->buf[xmit->tail], from_irq)) + if (!kfifo_peek(&tport->xmit_fifo, &c)) + break; + + if (!pl011_tx_char(uap, c, from_irq)) break; - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - } while (!uart_circ_empty(xmit)); + kfifo_skip(&tport->xmit_fifo); + } - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(&uap->port); - if (uart_circ_empty(xmit)) { + if (kfifo_is_empty(&tport->xmit_fifo)) { pl011_stop_tx(&uap->port); return false; } diff --git a/drivers/tty/serial/ar933x_uart.c b/drivers/tty/serial/ar933x_uart.c index 7790cbc57391..f2836ecc5c19 100644 --- a/drivers/tty/serial/ar933x_uart.c +++ b/drivers/tty/serial/ar933x_uart.c @@ -390,7 +390,7 @@ static void ar933x_uart_rx_chars(struct ar933x_uart_port *up) static void ar933x_uart_tx_chars(struct ar933x_uart_port *up) { - struct circ_buf *xmit = &up->port.state->xmit; + struct tty_port *tport = &up->port.state->port; struct serial_rs485 *rs485conf = &up->port.rs485; int count; bool half_duplex_send = false; @@ -399,7 +399,7 @@ static void ar933x_uart_tx_chars(struct ar933x_uart_port *up) return; if ((rs485conf->flags & SER_RS485_ENABLED) && - (up->port.x_char || !uart_circ_empty(xmit))) { + (up->port.x_char || !kfifo_is_empty(&tport->xmit_fifo))) { ar933x_uart_stop_rx_interrupt(up); gpiod_set_value(up->rts_gpiod, !!(rs485conf->flags & SER_RS485_RTS_ON_SEND)); half_duplex_send = true; @@ -408,6 +408,7 @@ static void ar933x_uart_tx_chars(struct ar933x_uart_port *up) count = up->port.fifosize; do { unsigned int rdata; + unsigned char c; rdata = ar933x_uart_read(up, AR933X_UART_DATA_REG); if ((rdata & AR933X_UART_DATA_TX_CSR) == 0) @@ -420,18 +421,16 @@ static void ar933x_uart_tx_chars(struct ar933x_uart_port *up) continue; } - if (uart_circ_empty(xmit)) + if (!uart_fifo_get(&up->port, &c)) break; - ar933x_uart_putc(up, xmit->buf[xmit->tail]); - - uart_xmit_advance(&up->port, 1); + ar933x_uart_putc(up, c); } while (--count > 0); - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(&up->port); - if (!uart_circ_empty(xmit)) { + if (!kfifo_is_empty(&tport->xmit_fifo)) { ar933x_uart_start_tx_interrupt(up); } else if (half_duplex_send) { ar933x_uart_wait_tx_complete(up); diff --git a/drivers/tty/serial/arc_uart.c b/drivers/tty/serial/arc_uart.c index 1aa5b2b49c26..5c4895d154c0 100644 --- a/drivers/tty/serial/arc_uart.c +++ b/drivers/tty/serial/arc_uart.c @@ -155,7 +155,7 @@ static unsigned int arc_serial_tx_empty(struct uart_port *port) */ static void arc_serial_tx_chars(struct uart_port *port) { - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; int sent = 0; unsigned char ch; @@ -164,9 +164,7 @@ static void arc_serial_tx_chars(struct uart_port *port) port->icount.tx++; port->x_char = 0; sent = 1; - } else if (!uart_circ_empty(xmit)) { - ch = xmit->buf[xmit->tail]; - uart_xmit_advance(port, 1); + } else if (uart_fifo_get(port, &ch)) { while (!(UART_GET_STATUS(port) & TXEMPTY)) cpu_relax(); UART_SET_DATA(port, ch); @@ -177,7 +175,7 @@ static void arc_serial_tx_chars(struct uart_port *port) * If num chars in xmit buffer are too few, ask tty layer for more. * By Hard ISR to schedule processing in software interrupt part */ - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(port); if (sent) diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index 85667f709515..5bb5e4303754 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -857,7 +857,7 @@ static void atmel_complete_tx_dma(void *arg) { struct atmel_uart_port *atmel_port = arg; struct uart_port *port = &atmel_port->uart; - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; struct dma_chan *chan = atmel_port->chan_tx; unsigned long flags; @@ -873,15 +873,15 @@ static void atmel_complete_tx_dma(void *arg) atmel_port->desc_tx = NULL; spin_unlock(&atmel_port->lock_tx); - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(port); /* - * xmit is a circular buffer so, if we have just send data from - * xmit->tail to the end of xmit->buf, now we have to transmit the - * remaining data from the beginning of xmit->buf to xmit->head. + * xmit is a circular buffer so, if we have just send data from the + * tail to the end, now we have to transmit the remaining data from the + * beginning to the head. */ - if (!uart_circ_empty(xmit)) + if (!kfifo_is_empty(&tport->xmit_fifo)) atmel_tasklet_schedule(atmel_port, &atmel_port->tasklet_tx); else if (atmel_uart_is_half_duplex(port)) { /* @@ -919,18 +919,18 @@ static void atmel_release_tx_dma(struct uart_port *port) static void atmel_tx_dma(struct uart_port *port) { struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; struct dma_chan *chan = atmel_port->chan_tx; struct dma_async_tx_descriptor *desc; struct scatterlist sgl[2], *sg, *sg_tx = &atmel_port->sg_tx; - unsigned int tx_len, part1_len, part2_len, sg_len; + unsigned int tx_len, tail, part1_len, part2_len, sg_len; dma_addr_t phys_addr; /* Make sure we have an idle channel */ if (atmel_port->desc_tx != NULL) return; - if (!uart_circ_empty(xmit) && !uart_tx_stopped(port)) { + if (!kfifo_is_empty(&tport->xmit_fifo) && !uart_tx_stopped(port)) { /* * DMA is idle now. * Port xmit buffer is already mapped, @@ -940,9 +940,8 @@ static void atmel_tx_dma(struct uart_port *port) * Take the port lock to get a * consistent xmit buffer state. */ - tx_len = CIRC_CNT_TO_END(xmit->head, - xmit->tail, - UART_XMIT_SIZE); + tx_len = kfifo_out_linear(&tport->xmit_fifo, &tail, + UART_XMIT_SIZE); if (atmel_port->fifo_size) { /* multi data mode */ @@ -956,7 +955,7 @@ static void atmel_tx_dma(struct uart_port *port) sg_init_table(sgl, 2); sg_len = 0; - phys_addr = sg_dma_address(sg_tx) + xmit->tail; + phys_addr = sg_dma_address(sg_tx) + tail; if (part1_len) { sg = &sgl[sg_len++]; sg_dma_address(sg) = phys_addr; @@ -973,7 +972,7 @@ static void atmel_tx_dma(struct uart_port *port) /* * save tx_len so atmel_complete_tx_dma() will increase - * xmit->tail correctly + * tail correctly */ atmel_port->tx_len = tx_len; @@ -1003,13 +1002,14 @@ static void atmel_tx_dma(struct uart_port *port) dma_async_issue_pending(chan); } - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(port); } static int atmel_prepare_tx_dma(struct uart_port *port) { struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + struct tty_port *tport = &port->state->port; struct device *mfd_dev = port->dev->parent; dma_cap_mask_t mask; struct dma_slave_config config; @@ -1031,11 +1031,11 @@ static int atmel_prepare_tx_dma(struct uart_port *port) spin_lock_init(&atmel_port->lock_tx); sg_init_table(&atmel_port->sg_tx, 1); /* UART circular tx buffer is an aligned page. */ - BUG_ON(!PAGE_ALIGNED(port->state->xmit.buf)); + BUG_ON(!PAGE_ALIGNED(tport->xmit_buf)); sg_set_page(&atmel_port->sg_tx, - virt_to_page(port->state->xmit.buf), + virt_to_page(tport->xmit_buf), UART_XMIT_SIZE, - offset_in_page(port->state->xmit.buf)); + offset_in_page(tport->xmit_buf)); nent = dma_map_sg(port->dev, &atmel_port->sg_tx, 1, @@ -1047,7 +1047,7 @@ static int atmel_prepare_tx_dma(struct uart_port *port) } else { dev_dbg(port->dev, "%s: mapped %d@%p to %pad\n", __func__, sg_dma_len(&atmel_port->sg_tx), - port->state->xmit.buf, + tport->xmit_buf, &sg_dma_address(&atmel_port->sg_tx)); } @@ -1459,9 +1459,8 @@ static void atmel_release_tx_pdc(struct uart_port *port) static void atmel_tx_pdc(struct uart_port *port) { struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx; - int count; /* nothing left to transmit? */ if (atmel_uart_readl(port, ATMEL_PDC_TCR)) @@ -1474,17 +1473,19 @@ static void atmel_tx_pdc(struct uart_port *port) /* disable PDC transmit */ atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_TXTDIS); - if (!uart_circ_empty(xmit) && !uart_tx_stopped(port)) { + if (!kfifo_is_empty(&tport->xmit_fifo) && !uart_tx_stopped(port)) { + unsigned int count, tail; + dma_sync_single_for_device(port->dev, pdc->dma_addr, pdc->dma_size, DMA_TO_DEVICE); - count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); + count = kfifo_out_linear(&tport->xmit_fifo, &tail, + UART_XMIT_SIZE); pdc->ofs = count; - atmel_uart_writel(port, ATMEL_PDC_TPR, - pdc->dma_addr + xmit->tail); + atmel_uart_writel(port, ATMEL_PDC_TPR, pdc->dma_addr + tail); atmel_uart_writel(port, ATMEL_PDC_TCR, count); /* re-enable PDC transmit */ atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_TXTEN); @@ -1498,7 +1499,7 @@ static void atmel_tx_pdc(struct uart_port *port) } } - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(port); } @@ -1506,9 +1507,9 @@ static int atmel_prepare_tx_pdc(struct uart_port *port) { struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx; - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; - pdc->buf = xmit->buf; + pdc->buf = tport->xmit_buf; pdc->dma_addr = dma_map_single(port->dev, pdc->buf, UART_XMIT_SIZE, diff --git a/drivers/tty/serial/clps711x.c b/drivers/tty/serial/clps711x.c index 7927725b8957..30425a3d19fb 100644 --- a/drivers/tty/serial/clps711x.c +++ b/drivers/tty/serial/clps711x.c @@ -146,7 +146,8 @@ static irqreturn_t uart_clps711x_int_tx(int irq, void *dev_id) { struct uart_port *port = dev_id; struct clps711x_port *s = dev_get_drvdata(port->dev); - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; + unsigned char c; if (port->x_char) { writew(port->x_char, port->membase + UARTDR_OFFSET); @@ -155,7 +156,7 @@ static irqreturn_t uart_clps711x_int_tx(int irq, void *dev_id) return IRQ_HANDLED; } - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { + if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)) { if (s->tx_enabled) { disable_irq_nosync(port->irq); s->tx_enabled = 0; @@ -163,18 +164,17 @@ static irqreturn_t uart_clps711x_int_tx(int irq, void *dev_id) return IRQ_HANDLED; } - while (!uart_circ_empty(xmit)) { + while (uart_fifo_get(port, &c)) { u32 sysflg = 0; - writew(xmit->buf[xmit->tail], port->membase + UARTDR_OFFSET); - uart_xmit_advance(port, 1); + writew(c, port->membase + UARTDR_OFFSET); regmap_read(s->syscon, SYSFLG_OFFSET, &sysflg); if (sysflg & SYSFLG_UTXFF) break; } - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(port); return IRQ_HANDLED; diff --git a/drivers/tty/serial/cpm_uart.c b/drivers/tty/serial/cpm_uart.c index df56c6c5afd0..a927478f581d 100644 --- a/drivers/tty/serial/cpm_uart.c +++ b/drivers/tty/serial/cpm_uart.c @@ -648,7 +648,7 @@ static int cpm_uart_tx_pump(struct uart_port *port) int count; struct uart_cpm_port *pinfo = container_of(port, struct uart_cpm_port, port); - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; /* Handle xon/xoff */ if (port->x_char) { @@ -673,7 +673,7 @@ static int cpm_uart_tx_pump(struct uart_port *port) return 1; } - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { + if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)) { cpm_uart_stop_tx(port); return 0; } @@ -681,16 +681,10 @@ static int cpm_uart_tx_pump(struct uart_port *port) /* Pick next descriptor and fill from buffer */ bdp = pinfo->tx_cur; - while (!(in_be16(&bdp->cbd_sc) & BD_SC_READY) && !uart_circ_empty(xmit)) { - count = 0; + while (!(in_be16(&bdp->cbd_sc) & BD_SC_READY) && + !kfifo_is_empty(&tport->xmit_fifo)) { p = cpm2cpu_addr(in_be32(&bdp->cbd_bufaddr), pinfo); - while (count < pinfo->tx_fifosize) { - *p++ = xmit->buf[xmit->tail]; - uart_xmit_advance(port, 1); - count++; - if (uart_circ_empty(xmit)) - break; - } + count = uart_fifo_out(port, p, pinfo->tx_fifosize); out_be16(&bdp->cbd_datlen, count); setbits16(&bdp->cbd_sc, BD_SC_READY); /* Get next BD. */ @@ -701,10 +695,10 @@ static int cpm_uart_tx_pump(struct uart_port *port) } pinfo->tx_cur = bdp; - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(port); - if (uart_circ_empty(xmit)) { + if (kfifo_is_empty(&tport->xmit_fifo)) { cpm_uart_stop_tx(port); return 0; } diff --git a/drivers/tty/serial/digicolor-usart.c b/drivers/tty/serial/digicolor-usart.c index e419c4bde8b7..2ccd13cc0a89 100644 --- a/drivers/tty/serial/digicolor-usart.c +++ b/drivers/tty/serial/digicolor-usart.c @@ -179,8 +179,9 @@ static void digicolor_uart_rx(struct uart_port *port) static void digicolor_uart_tx(struct uart_port *port) { - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; unsigned long flags; + unsigned char c; if (digicolor_uart_tx_full(port)) return; @@ -194,20 +195,19 @@ static void digicolor_uart_tx(struct uart_port *port) goto out; } - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { + if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)) { digicolor_uart_stop_tx(port); goto out; } - while (!uart_circ_empty(xmit)) { - writeb(xmit->buf[xmit->tail], port->membase + UA_EMI_REC); - uart_xmit_advance(port, 1); + while (uart_fifo_get(port, &c)) { + writeb(c, port->membase + UA_EMI_REC); if (digicolor_uart_tx_full(port)) break; } - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(port); out: diff --git a/drivers/tty/serial/dz.c b/drivers/tty/serial/dz.c index 6df7af9edc1c..eba91daedef8 100644 --- a/drivers/tty/serial/dz.c +++ b/drivers/tty/serial/dz.c @@ -252,13 +252,13 @@ static inline void dz_receive_chars(struct dz_mux *mux) static inline void dz_transmit_chars(struct dz_mux *mux) { struct dz_port *dport = &mux->dport[0]; - struct circ_buf *xmit; + struct tty_port *tport; unsigned char tmp; u16 status; status = dz_in(dport, DZ_CSR); dport = &mux->dport[LINE(status)]; - xmit = &dport->port.state->xmit; + tport = &dport->port.state->port; if (dport->port.x_char) { /* XON/XOFF chars */ dz_out(dport, DZ_TDR, dport->port.x_char); @@ -267,7 +267,8 @@ static inline void dz_transmit_chars(struct dz_mux *mux) return; } /* If nothing to do or stopped or hardware stopped. */ - if (uart_circ_empty(xmit) || uart_tx_stopped(&dport->port)) { + if (uart_tx_stopped(&dport->port) || + !uart_fifo_get(&dport->port, &tmp)) { uart_port_lock(&dport->port); dz_stop_tx(&dport->port); uart_port_unlock(&dport->port); @@ -278,15 +279,13 @@ static inline void dz_transmit_chars(struct dz_mux *mux) * If something to do... (remember the dz has no output fifo, * so we go one char at a time) :-< */ - tmp = xmit->buf[xmit->tail]; dz_out(dport, DZ_TDR, tmp); - uart_xmit_advance(&dport->port, 1); - if (uart_circ_chars_pending(xmit) < DZ_WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < DZ_WAKEUP_CHARS) uart_write_wakeup(&dport->port); /* Are we are done. */ - if (uart_circ_empty(xmit)) { + if (kfifo_is_empty(&tport->xmit_fifo)) { uart_port_lock(&dport->port); dz_stop_tx(&dport->port); uart_port_unlock(&dport->port); diff --git a/drivers/tty/serial/fsl_linflexuart.c b/drivers/tty/serial/fsl_linflexuart.c index 5426322b5f0c..e972df4b188d 100644 --- a/drivers/tty/serial/fsl_linflexuart.c +++ b/drivers/tty/serial/fsl_linflexuart.c @@ -174,17 +174,18 @@ static void linflex_put_char(struct uart_port *sport, unsigned char c) static inline void linflex_transmit_buffer(struct uart_port *sport) { - struct circ_buf *xmit = &sport->state->xmit; + struct tty_port *tport = &sport->state->port; + unsigned char c; - while (!uart_circ_empty(xmit)) { - linflex_put_char(sport, xmit->buf[xmit->tail]); - uart_xmit_advance(sport, 1); + while (uart_fifo_get(sport, &c)) { + linflex_put_char(sport, c); + sport->icount.tx++; } - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(sport); - if (uart_circ_empty(xmit)) + if (kfifo_is_empty(&tport->xmit_fifo)) linflex_stop_tx(sport); } @@ -200,7 +201,7 @@ static void linflex_start_tx(struct uart_port *port) static irqreturn_t linflex_txint(int irq, void *dev_id) { struct uart_port *sport = dev_id; - struct circ_buf *xmit = &sport->state->xmit; + struct tty_port *tport = &sport->state->port; unsigned long flags; uart_port_lock_irqsave(sport, &flags); @@ -210,7 +211,7 @@ static irqreturn_t linflex_txint(int irq, void *dev_id) goto out; } - if (uart_circ_empty(xmit) || uart_tx_stopped(sport)) { + if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(sport)) { linflex_stop_tx(sport); goto out; } diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index bbcbc91482af..ae5e1ecc48fc 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -473,7 +474,7 @@ static void lpuart32_stop_rx(struct uart_port *port) static void lpuart_dma_tx(struct lpuart_port *sport) { - struct circ_buf *xmit = &sport->port.state->xmit; + struct tty_port *tport = &sport->port.state->port; struct scatterlist *sgl = sport->tx_sgl; struct device *dev = sport->port.dev; struct dma_chan *chan = sport->dma_tx_chan; @@ -482,18 +483,10 @@ static void lpuart_dma_tx(struct lpuart_port *sport) if (sport->dma_tx_in_progress) return; - sport->dma_tx_bytes = uart_circ_chars_pending(xmit); - - if (xmit->tail < xmit->head || xmit->head == 0) { - sport->dma_tx_nents = 1; - sg_init_one(sgl, xmit->buf + xmit->tail, sport->dma_tx_bytes); - } else { - sport->dma_tx_nents = 2; - sg_init_table(sgl, 2); - sg_set_buf(sgl, xmit->buf + xmit->tail, - UART_XMIT_SIZE - xmit->tail); - sg_set_buf(sgl + 1, xmit->buf, xmit->head); - } + sg_init_table(sgl, ARRAY_SIZE(sport->tx_sgl)); + sport->dma_tx_bytes = kfifo_len(&tport->xmit_fifo); + sport->dma_tx_nents = kfifo_dma_out_prepare(&tport->xmit_fifo, sgl, + ARRAY_SIZE(sport->tx_sgl), sport->dma_tx_bytes); ret = dma_map_sg(chan->device->dev, sgl, sport->dma_tx_nents, DMA_TO_DEVICE); @@ -521,14 +514,15 @@ static void lpuart_dma_tx(struct lpuart_port *sport) static bool lpuart_stopped_or_empty(struct uart_port *port) { - return uart_circ_empty(&port->state->xmit) || uart_tx_stopped(port); + return kfifo_is_empty(&port->state->port.xmit_fifo) || + uart_tx_stopped(port); } static void lpuart_dma_tx_complete(void *arg) { struct lpuart_port *sport = arg; struct scatterlist *sgl = &sport->tx_sgl[0]; - struct circ_buf *xmit = &sport->port.state->xmit; + struct tty_port *tport = &sport->port.state->port; struct dma_chan *chan = sport->dma_tx_chan; unsigned long flags; @@ -545,7 +539,7 @@ static void lpuart_dma_tx_complete(void *arg) sport->dma_tx_in_progress = false; uart_port_unlock_irqrestore(&sport->port, flags); - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(&sport->port); if (waitqueue_active(&sport->dma_wait)) { @@ -756,8 +750,9 @@ static inline void lpuart_transmit_buffer(struct lpuart_port *sport) static inline void lpuart32_transmit_buffer(struct lpuart_port *sport) { - struct circ_buf *xmit = &sport->port.state->xmit; + struct tty_port *tport = &sport->port.state->port; unsigned long txcnt; + unsigned char c; if (sport->port.x_char) { lpuart32_write(&sport->port, sport->port.x_char, UARTDATA); @@ -774,18 +769,18 @@ static inline void lpuart32_transmit_buffer(struct lpuart_port *sport) txcnt = lpuart32_read(&sport->port, UARTWATER); txcnt = txcnt >> UARTWATER_TXCNT_OFF; txcnt &= UARTWATER_COUNT_MASK; - while (!uart_circ_empty(xmit) && (txcnt < sport->txfifo_size)) { - lpuart32_write(&sport->port, xmit->buf[xmit->tail], UARTDATA); - uart_xmit_advance(&sport->port, 1); + while (txcnt < sport->txfifo_size && + uart_fifo_get(&sport->port, &c)) { + lpuart32_write(&sport->port, c, UARTDATA); txcnt = lpuart32_read(&sport->port, UARTWATER); txcnt = txcnt >> UARTWATER_TXCNT_OFF; txcnt &= UARTWATER_COUNT_MASK; } - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(&sport->port); - if (uart_circ_empty(xmit)) + if (kfifo_is_empty(&tport->xmit_fifo)) lpuart32_stop_tx(&sport->port); } diff --git a/drivers/tty/serial/icom.c b/drivers/tty/serial/icom.c index a75eafbcbea3..29e42831df39 100644 --- a/drivers/tty/serial/icom.c +++ b/drivers/tty/serial/icom.c @@ -877,10 +877,10 @@ unlock: static int icom_write(struct uart_port *port) { struct icom_port *icom_port = to_icom_port(port); + struct tty_port *tport = &port->state->port; unsigned long data_count; unsigned char cmdReg; unsigned long offset; - int temp_tail = port->state->xmit.tail; trace(icom_port, "WRITE", 0); @@ -890,16 +890,8 @@ static int icom_write(struct uart_port *port) return 0; } - data_count = 0; - while ((port->state->xmit.head != temp_tail) && - (data_count <= XMIT_BUFF_SZ)) { - - icom_port->xmit_buf[data_count++] = - port->state->xmit.buf[temp_tail]; - - temp_tail++; - temp_tail &= (UART_XMIT_SIZE - 1); - } + data_count = kfifo_out_peek(&tport->xmit_fifo, icom_port->xmit_buf, + XMIT_BUFF_SZ); if (data_count) { icom_port->statStg->xmit[0].flags = @@ -956,7 +948,8 @@ static inline void check_modem_status(struct icom_port *icom_port) static void xmit_interrupt(u16 port_int_reg, struct icom_port *icom_port) { - u16 count, i; + struct tty_port *tport = &icom_port->uart_port.state->port; + u16 count; if (port_int_reg & (INT_XMIT_COMPLETED)) { trace(icom_port, "XMIT_COMPLETE", 0); @@ -968,13 +961,7 @@ static void xmit_interrupt(u16 port_int_reg, struct icom_port *icom_port) count = le16_to_cpu(icom_port->statStg->xmit[0].leLength); icom_port->uart_port.icount.tx += count; - for (i=0; iuart_port.state->xmit); i++) { - - icom_port->uart_port.state->xmit.tail++; - icom_port->uart_port.state->xmit.tail &= - (UART_XMIT_SIZE - 1); - } + kfifo_skip_count(&tport->xmit_fifo, count); if (!icom_write(&icom_port->uart_port)) /* activate write queue */ diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index e14813250616..56b76a221082 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -8,6 +8,7 @@ * Copyright (C) 2004 Pengutronix */ +#include #include #include #include @@ -521,7 +522,8 @@ static void imx_uart_dma_tx(struct imx_port *sport); /* called with port.lock taken and irqs off */ static inline void imx_uart_transmit_buffer(struct imx_port *sport) { - struct circ_buf *xmit = &sport->port.state->xmit; + struct tty_port *tport = &sport->port.state->port; + unsigned char c; if (sport->port.x_char) { /* Send next char */ @@ -531,7 +533,8 @@ static inline void imx_uart_transmit_buffer(struct imx_port *sport) return; } - if (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)) { + if (kfifo_is_empty(&tport->xmit_fifo) || + uart_tx_stopped(&sport->port)) { imx_uart_stop_tx(&sport->port); return; } @@ -555,26 +558,22 @@ static inline void imx_uart_transmit_buffer(struct imx_port *sport) return; } - while (!uart_circ_empty(xmit) && - !(imx_uart_readl(sport, imx_uart_uts_reg(sport)) & UTS_TXFULL)) { - /* send xmit->buf[xmit->tail] - * out the port here */ - imx_uart_writel(sport, xmit->buf[xmit->tail], URTX0); - uart_xmit_advance(&sport->port, 1); - } + while (!(imx_uart_readl(sport, imx_uart_uts_reg(sport)) & UTS_TXFULL) && + uart_fifo_get(&sport->port, &c)) + imx_uart_writel(sport, c, URTX0); - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(&sport->port); - if (uart_circ_empty(xmit)) + if (kfifo_is_empty(&tport->xmit_fifo)) imx_uart_stop_tx(&sport->port); } static void imx_uart_dma_tx_callback(void *data) { struct imx_port *sport = data; + struct tty_port *tport = &sport->port.state->port; struct scatterlist *sgl = &sport->tx_sgl[0]; - struct circ_buf *xmit = &sport->port.state->xmit; unsigned long flags; u32 ucr1; @@ -592,10 +591,11 @@ static void imx_uart_dma_tx_callback(void *data) sport->dma_is_txing = 0; - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(&sport->port); - if (!uart_circ_empty(xmit) && !uart_tx_stopped(&sport->port)) + if (!kfifo_is_empty(&tport->xmit_fifo) && + !uart_tx_stopped(&sport->port)) imx_uart_dma_tx(sport); else if (sport->port.rs485.flags & SER_RS485_ENABLED) { u32 ucr4 = imx_uart_readl(sport, UCR4); @@ -609,7 +609,7 @@ static void imx_uart_dma_tx_callback(void *data) /* called with port.lock taken and irqs off */ static void imx_uart_dma_tx(struct imx_port *sport) { - struct circ_buf *xmit = &sport->port.state->xmit; + struct tty_port *tport = &sport->port.state->port; struct scatterlist *sgl = sport->tx_sgl; struct dma_async_tx_descriptor *desc; struct dma_chan *chan = sport->dma_chan_tx; @@ -624,18 +624,10 @@ static void imx_uart_dma_tx(struct imx_port *sport) ucr4 &= ~UCR4_TCEN; imx_uart_writel(sport, ucr4, UCR4); - sport->tx_bytes = uart_circ_chars_pending(xmit); - - if (xmit->tail < xmit->head || xmit->head == 0) { - sport->dma_tx_nents = 1; - sg_init_one(sgl, xmit->buf + xmit->tail, sport->tx_bytes); - } else { - sport->dma_tx_nents = 2; - sg_init_table(sgl, 2); - sg_set_buf(sgl, xmit->buf + xmit->tail, - UART_XMIT_SIZE - xmit->tail); - sg_set_buf(sgl + 1, xmit->buf, xmit->head); - } + sg_init_table(sgl, ARRAY_SIZE(sport->tx_sgl)); + sport->tx_bytes = kfifo_len(&tport->xmit_fifo); + sport->dma_tx_nents = kfifo_dma_out_prepare(&tport->xmit_fifo, sgl, + ARRAY_SIZE(sport->tx_sgl), sport->tx_bytes); ret = dma_map_sg(dev, sgl, sport->dma_tx_nents, DMA_TO_DEVICE); if (ret == 0) { @@ -653,8 +645,7 @@ static void imx_uart_dma_tx(struct imx_port *sport) desc->callback = imx_uart_dma_tx_callback; desc->callback_param = sport; - dev_dbg(dev, "TX: prepare to send %lu bytes by DMA.\n", - uart_circ_chars_pending(xmit)); + dev_dbg(dev, "TX: prepare to send %u bytes by DMA.\n", sport->tx_bytes); ucr1 = imx_uart_readl(sport, UCR1); ucr1 |= UCR1_TXDMAEN; @@ -671,9 +662,10 @@ static void imx_uart_dma_tx(struct imx_port *sport) static void imx_uart_start_tx(struct uart_port *port) { struct imx_port *sport = (struct imx_port *)port; + struct tty_port *tport = &sport->port.state->port; u32 ucr1; - if (!sport->port.x_char && uart_circ_empty(&port->state->xmit)) + if (!sport->port.x_char && kfifo_is_empty(&tport->xmit_fifo)) return; /* @@ -749,7 +741,7 @@ static void imx_uart_start_tx(struct uart_port *port) return; } - if (!uart_circ_empty(&port->state->xmit) && + if (!kfifo_is_empty(&tport->xmit_fifo) && !uart_tx_stopped(port)) imx_uart_dma_tx(sport); return; diff --git a/drivers/tty/serial/ip22zilog.c b/drivers/tty/serial/ip22zilog.c index 320b29cd4683..c2cae50f06f3 100644 --- a/drivers/tty/serial/ip22zilog.c +++ b/drivers/tty/serial/ip22zilog.c @@ -355,7 +355,8 @@ static void ip22zilog_status_handle(struct uart_ip22zilog_port *up, static void ip22zilog_transmit_chars(struct uart_ip22zilog_port *up, struct zilog_channel *channel) { - struct circ_buf *xmit; + struct tty_port *tport; + unsigned char c; if (ZS_IS_CONS(up)) { unsigned char status = readb(&channel->control); @@ -398,20 +399,18 @@ static void ip22zilog_transmit_chars(struct uart_ip22zilog_port *up, if (up->port.state == NULL) goto ack_tx_int; - xmit = &up->port.state->xmit; - if (uart_circ_empty(xmit)) - goto ack_tx_int; + tport = &up->port.state->port; if (uart_tx_stopped(&up->port)) goto ack_tx_int; + if (!uart_fifo_get(&up->port, &c)) + goto ack_tx_int; up->flags |= IP22ZILOG_FLAG_TX_ACTIVE; - writeb(xmit->buf[xmit->tail], &channel->data); + writeb(c, &channel->data); ZSDELAY(); ZS_WSYNC(channel); - uart_xmit_advance(&up->port, 1); - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(&up->port); return; @@ -600,17 +599,16 @@ static void ip22zilog_start_tx(struct uart_port *port) port->icount.tx++; port->x_char = 0; } else { - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; + unsigned char c; - if (uart_circ_empty(xmit)) + if (!uart_fifo_get(port, &c)) return; - writeb(xmit->buf[xmit->tail], &channel->data); + writeb(c, &channel->data); ZSDELAY(); ZS_WSYNC(channel); - uart_xmit_advance(port, 1); - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(&up->port); } } diff --git a/drivers/tty/serial/jsm/jsm_cls.c b/drivers/tty/serial/jsm/jsm_cls.c index ddbd42c09637..6e40792f92cf 100644 --- a/drivers/tty/serial/jsm/jsm_cls.c +++ b/drivers/tty/serial/jsm/jsm_cls.c @@ -443,20 +443,14 @@ static void cls_copy_data_from_uart_to_queue(struct jsm_channel *ch) static void cls_copy_data_from_queue_to_uart(struct jsm_channel *ch) { - u16 tail; + struct tty_port *tport; int n; - int qlen; u32 len_written = 0; - struct circ_buf *circ; if (!ch) return; - circ = &ch->uart_port.state->xmit; - - /* No data to write to the UART */ - if (uart_circ_empty(circ)) - return; + tport = &ch->uart_port.state->port; /* If port is "stopped", don't send any data to the UART */ if ((ch->ch_flags & CH_STOP) || (ch->ch_flags & CH_BREAK_SENDING)) @@ -467,29 +461,22 @@ static void cls_copy_data_from_queue_to_uart(struct jsm_channel *ch) return; n = 32; + while (n > 0) { + unsigned char c; - /* cache tail of queue */ - tail = circ->tail & (UART_XMIT_SIZE - 1); - qlen = uart_circ_chars_pending(circ); - - /* Find minimum of the FIFO space, versus queue length */ - n = min(n, qlen); + if (!kfifo_get(&tport->xmit_fifo, &c)) + break; - while (n > 0) { - writeb(circ->buf[tail], &ch->ch_cls_uart->txrx); - tail = (tail + 1) & (UART_XMIT_SIZE - 1); + writeb(c, &ch->ch_cls_uart->txrx); n--; ch->ch_txcount++; len_written++; } - /* Update the final tail */ - circ->tail = tail & (UART_XMIT_SIZE - 1); - if (len_written > ch->ch_t_tlevel) ch->ch_flags &= ~(CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM); - if (uart_circ_empty(circ)) + if (kfifo_is_empty(&tport->xmit_fifo)) uart_write_wakeup(&ch->uart_port); } diff --git a/drivers/tty/serial/jsm/jsm_neo.c b/drivers/tty/serial/jsm/jsm_neo.c index 1fa10f19368f..e8e13bf056e2 100644 --- a/drivers/tty/serial/jsm/jsm_neo.c +++ b/drivers/tty/serial/jsm/jsm_neo.c @@ -474,21 +474,21 @@ static void neo_copy_data_from_uart_to_queue(struct jsm_channel *ch) static void neo_copy_data_from_queue_to_uart(struct jsm_channel *ch) { - u16 head; - u16 tail; + struct tty_port *tport; + unsigned char *tail; + unsigned char c; int n; int s; int qlen; u32 len_written = 0; - struct circ_buf *circ; if (!ch) return; - circ = &ch->uart_port.state->xmit; + tport = &ch->uart_port.state->port; /* No data to write to the UART */ - if (uart_circ_empty(circ)) + if (kfifo_is_empty(&tport->xmit_fifo)) return; /* If port is "stopped", don't send any data to the UART */ @@ -504,10 +504,9 @@ static void neo_copy_data_from_queue_to_uart(struct jsm_channel *ch) if (ch->ch_cached_lsr & UART_LSR_THRE) { ch->ch_cached_lsr &= ~(UART_LSR_THRE); - writeb(circ->buf[circ->tail], &ch->ch_neo_uart->txrx); - jsm_dbg(WRITE, &ch->ch_bd->pci_dev, - "Tx data: %x\n", circ->buf[circ->tail]); - circ->tail = (circ->tail + 1) & (UART_XMIT_SIZE - 1); + WARN_ON_ONCE(!kfifo_get(&tport->xmit_fifo, &c)); + writeb(c, &ch->ch_neo_uart->txrx); + jsm_dbg(WRITE, &ch->ch_bd->pci_dev, "Tx data: %x\n", c); ch->ch_txcount++; } return; @@ -520,38 +519,27 @@ static void neo_copy_data_from_queue_to_uart(struct jsm_channel *ch) return; n = UART_17158_TX_FIFOSIZE - ch->ch_t_tlevel; - - /* cache head and tail of queue */ - head = circ->head & (UART_XMIT_SIZE - 1); - tail = circ->tail & (UART_XMIT_SIZE - 1); - qlen = uart_circ_chars_pending(circ); + qlen = kfifo_len(&tport->xmit_fifo); /* Find minimum of the FIFO space, versus queue length */ n = min(n, qlen); while (n > 0) { - - s = ((head >= tail) ? head : UART_XMIT_SIZE) - tail; - s = min(s, n); - + s = kfifo_out_linear_ptr(&tport->xmit_fifo, &tail, n); if (s <= 0) break; - memcpy_toio(&ch->ch_neo_uart->txrxburst, circ->buf + tail, s); - /* Add and flip queue if needed */ - tail = (tail + s) & (UART_XMIT_SIZE - 1); + memcpy_toio(&ch->ch_neo_uart->txrxburst, tail, s); + kfifo_skip_count(&tport->xmit_fifo, s); n -= s; ch->ch_txcount += s; len_written += s; } - /* Update the final tail */ - circ->tail = tail & (UART_XMIT_SIZE - 1); - if (len_written >= ch->ch_t_tlevel) ch->ch_flags &= ~(CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM); - if (uart_circ_empty(circ)) + if (kfifo_is_empty(&tport->xmit_fifo)) uart_write_wakeup(&ch->uart_port); } diff --git a/drivers/tty/serial/max3100.c b/drivers/tty/serial/max3100.c index 5efb2b593be3..b83eee37c17d 100644 --- a/drivers/tty/serial/max3100.c +++ b/drivers/tty/serial/max3100.c @@ -257,10 +257,11 @@ static int max3100_handlerx(struct max3100_port *s, u16 rx) static void max3100_work(struct work_struct *w) { struct max3100_port *s = container_of(w, struct max3100_port, work); + struct tty_port *tport = &s->port.state->port; + unsigned char ch; int rxchars; u16 tx, rx; int conf, cconf, crts; - struct circ_buf *xmit = &s->port.state->xmit; dev_dbg(&s->spi->dev, "%s\n", __func__); @@ -290,10 +291,9 @@ static void max3100_work(struct work_struct *w) tx = s->port.x_char; s->port.icount.tx++; s->port.x_char = 0; - } else if (!uart_circ_empty(xmit) && - !uart_tx_stopped(&s->port)) { - tx = xmit->buf[xmit->tail]; - uart_xmit_advance(&s->port, 1); + } else if (!uart_tx_stopped(&s->port) && + uart_fifo_get(&s->port, &ch)) { + tx = ch; } if (tx != 0xffff) { max3100_calc_parity(s, &tx); @@ -307,13 +307,13 @@ static void max3100_work(struct work_struct *w) tty_flip_buffer_push(&s->port.state->port); rxchars = 0; } - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(&s->port); } while (!s->force_end_work && !freezing(current) && ((rx & MAX3100_R) || - (!uart_circ_empty(xmit) && + (!kfifo_is_empty(&tport->xmit_fifo) && !uart_tx_stopped(&s->port)))); if (rxchars > 0) diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 14dd9cfaa9f7..f0eb96429dae 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -747,8 +747,9 @@ static void max310x_handle_rx(struct uart_port *port, unsigned int rxlen) static void max310x_handle_tx(struct uart_port *port) { - struct circ_buf *xmit = &port->state->xmit; - unsigned int txlen, to_send, until_end; + struct tty_port *tport = &port->state->port; + unsigned int txlen, to_send; + unsigned char *tail; if (unlikely(port->x_char)) { max310x_port_write(port, MAX310X_THR_REG, port->x_char); @@ -757,32 +758,26 @@ static void max310x_handle_tx(struct uart_port *port) return; } - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) + if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)) return; - /* Get length of data pending in circular buffer */ - to_send = uart_circ_chars_pending(xmit); - until_end = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); - if (likely(to_send)) { + /* + * It's a circ buffer -- wrap around. + * We could do that in one SPI transaction, but meh. + */ + while (!kfifo_is_empty(&tport->xmit_fifo)) { /* Limit to space available in TX FIFO */ txlen = max310x_port_read(port, MAX310X_TXFIFOLVL_REG); txlen = port->fifosize - txlen; - to_send = (to_send > txlen) ? txlen : to_send; - - if (until_end < to_send) { - /* - * It's a circ buffer -- wrap around. - * We could do that in one SPI transaction, but meh. - */ - max310x_batch_write(port, xmit->buf + xmit->tail, until_end); - max310x_batch_write(port, xmit->buf, to_send - until_end); - } else { - max310x_batch_write(port, xmit->buf + xmit->tail, to_send); - } + if (!txlen) + break; + + to_send = kfifo_out_linear_ptr(&tport->xmit_fifo, &tail, txlen); + max310x_batch_write(port, tail, to_send); uart_xmit_advance(port, to_send); } - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(port); } diff --git a/drivers/tty/serial/men_z135_uart.c b/drivers/tty/serial/men_z135_uart.c index 8048fa542fc4..4bff422bb1bc 100644 --- a/drivers/tty/serial/men_z135_uart.c +++ b/drivers/tty/serial/men_z135_uart.c @@ -293,17 +293,14 @@ static void men_z135_handle_rx(struct men_z135_port *uart) static void men_z135_handle_tx(struct men_z135_port *uart) { struct uart_port *port = &uart->port; - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; + unsigned char *tail; + unsigned int n, txfree; u32 txc; u32 wptr; int qlen; - int n; - int txfree; - int head; - int tail; - int s; - if (uart_circ_empty(xmit)) + if (kfifo_is_empty(&tport->xmit_fifo)) goto out; if (uart_tx_stopped(port)) @@ -313,7 +310,7 @@ static void men_z135_handle_tx(struct men_z135_port *uart) goto out; /* calculate bytes to copy */ - qlen = uart_circ_chars_pending(xmit); + qlen = kfifo_len(&tport->xmit_fifo); if (qlen <= 0) goto out; @@ -345,21 +342,18 @@ static void men_z135_handle_tx(struct men_z135_port *uart) if (n <= 0) goto irq_en; - head = xmit->head & (UART_XMIT_SIZE - 1); - tail = xmit->tail & (UART_XMIT_SIZE - 1); - - s = ((head >= tail) ? head : UART_XMIT_SIZE) - tail; - n = min(n, s); + n = kfifo_out_linear_ptr(&tport->xmit_fifo, &tail, + min_t(unsigned int, UART_XMIT_SIZE, n)); + memcpy_toio(port->membase + MEN_Z135_TX_RAM, tail, n); - memcpy_toio(port->membase + MEN_Z135_TX_RAM, &xmit->buf[xmit->tail], n); iowrite32(n & 0x3ff, port->membase + MEN_Z135_TX_CTRL); uart_xmit_advance(port, n); - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(port); irq_en: - if (!uart_circ_empty(xmit)) + if (!kfifo_is_empty(&tport->xmit_fifo)) men_z135_reg_set(uart, MEN_Z135_CONF_REG, MEN_Z135_IER_TXCIEN); else men_z135_reg_clr(uart, MEN_Z135_CONF_REG, MEN_Z135_IER_TXCIEN); diff --git a/drivers/tty/serial/meson_uart.c b/drivers/tty/serial/meson_uart.c index 6feac459c0cf..4587ed4d4d5d 100644 --- a/drivers/tty/serial/meson_uart.c +++ b/drivers/tty/serial/meson_uart.c @@ -141,8 +141,8 @@ static void meson_uart_shutdown(struct uart_port *port) static void meson_uart_start_tx(struct uart_port *port) { - struct circ_buf *xmit = &port->state->xmit; - unsigned int ch; + struct tty_port *tport = &port->state->port; + unsigned char ch; u32 val; if (uart_tx_stopped(port)) { @@ -158,21 +158,20 @@ static void meson_uart_start_tx(struct uart_port *port) continue; } - if (uart_circ_empty(xmit)) + if (!uart_fifo_get(port, &ch)) break; - ch = xmit->buf[xmit->tail]; writel(ch, port->membase + AML_UART_WFIFO); uart_xmit_advance(port, 1); } - if (!uart_circ_empty(xmit)) { + if (!kfifo_is_empty(&tport->xmit_fifo)) { val = readl(port->membase + AML_UART_CONTROL); val |= AML_UART_TX_INT_EN; writel(val, port->membase + AML_UART_CONTROL); } - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(port); } diff --git a/drivers/tty/serial/milbeaut_usio.c b/drivers/tty/serial/milbeaut_usio.c index da4c6f7e2a30..fb082ee73d5b 100644 --- a/drivers/tty/serial/milbeaut_usio.c +++ b/drivers/tty/serial/milbeaut_usio.c @@ -72,7 +72,7 @@ static void mlb_usio_stop_tx(struct uart_port *port) static void mlb_usio_tx_chars(struct uart_port *port) { - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; int count; writew(readw(port->membase + MLB_USIO_REG_FCR) & ~MLB_USIO_FCR_FTIE, @@ -87,7 +87,7 @@ static void mlb_usio_tx_chars(struct uart_port *port) port->x_char = 0; return; } - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { + if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)) { mlb_usio_stop_tx(port); return; } @@ -96,12 +96,13 @@ static void mlb_usio_tx_chars(struct uart_port *port) (readw(port->membase + MLB_USIO_REG_FBYTE) & 0xff); do { - writew(xmit->buf[xmit->tail], port->membase + MLB_USIO_REG_DR); + unsigned char ch; - uart_xmit_advance(port, 1); - if (uart_circ_empty(xmit)) + if (!uart_fifo_get(port, &ch)) break; + writew(ch, port->membase + MLB_USIO_REG_DR); + port->icount.tx++; } while (--count > 0); writew(readw(port->membase + MLB_USIO_REG_FCR) & ~MLB_USIO_FCR_FDRQ, @@ -110,10 +111,10 @@ static void mlb_usio_tx_chars(struct uart_port *port) writeb(readb(port->membase + MLB_USIO_REG_SCR) | MLB_USIO_SCR_TBIE, port->membase + MLB_USIO_REG_SCR); - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(port); - if (uart_circ_empty(xmit)) + if (kfifo_is_empty(&tport->xmit_fifo)) mlb_usio_stop_tx(port); } diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c index 7bf30e632313..ae7a8e3cf467 100644 --- a/drivers/tty/serial/msm_serial.c +++ b/drivers/tty/serial/msm_serial.c @@ -452,7 +452,7 @@ static void msm_complete_tx_dma(void *args) { struct msm_port *msm_port = args; struct uart_port *port = &msm_port->uart; - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; struct msm_dma *dma = &msm_port->tx_dma; struct dma_tx_state state; unsigned long flags; @@ -486,7 +486,7 @@ static void msm_complete_tx_dma(void *args) msm_port->imr |= MSM_UART_IMR_TXLEV; msm_write(port, msm_port->imr, MSM_UART_IMR); - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(port); msm_handle_tx(port); @@ -496,14 +496,14 @@ done: static int msm_handle_tx_dma(struct msm_port *msm_port, unsigned int count) { - struct circ_buf *xmit = &msm_port->uart.state->xmit; struct uart_port *port = &msm_port->uart; + struct tty_port *tport = &port->state->port; struct msm_dma *dma = &msm_port->tx_dma; int ret; u32 val; sg_init_table(&dma->tx_sg, 1); - sg_set_buf(&dma->tx_sg, &xmit->buf[xmit->tail], count); + kfifo_dma_out_prepare(&tport->xmit_fifo, &dma->tx_sg, 1, count); ret = dma_map_sg(port->dev, &dma->tx_sg, 1, dma->dir); if (ret) @@ -843,8 +843,8 @@ static void msm_handle_rx(struct uart_port *port) static void msm_handle_tx_pio(struct uart_port *port, unsigned int tx_count) { - struct circ_buf *xmit = &port->state->xmit; struct msm_port *msm_port = to_msm_port(port); + struct tty_port *tport = &port->state->port; unsigned int num_chars; unsigned int tf_pointer = 0; void __iomem *tf; @@ -858,8 +858,7 @@ static void msm_handle_tx_pio(struct uart_port *port, unsigned int tx_count) msm_reset_dm_count(port, tx_count); while (tf_pointer < tx_count) { - int i; - char buf[4] = { 0 }; + unsigned char buf[4] = { 0 }; if (!(msm_read(port, MSM_UART_SR) & MSM_UART_SR_TX_READY)) break; @@ -870,26 +869,23 @@ static void msm_handle_tx_pio(struct uart_port *port, unsigned int tx_count) else num_chars = 1; - for (i = 0; i < num_chars; i++) - buf[i] = xmit->buf[xmit->tail + i]; - + num_chars = uart_fifo_out(port, buf, num_chars); iowrite32_rep(tf, buf, 1); - uart_xmit_advance(port, num_chars); tf_pointer += num_chars; } /* disable tx interrupts if nothing more to send */ - if (uart_circ_empty(xmit)) + if (kfifo_is_empty(&tport->xmit_fifo)) msm_stop_tx(port); - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(port); } static void msm_handle_tx(struct uart_port *port) { struct msm_port *msm_port = to_msm_port(port); - struct circ_buf *xmit = &msm_port->uart.state->xmit; + struct tty_port *tport = &port->state->port; struct msm_dma *dma = &msm_port->tx_dma; unsigned int pio_count, dma_count, dma_min; char buf[4] = { 0 }; @@ -913,13 +909,13 @@ static void msm_handle_tx(struct uart_port *port) return; } - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { + if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)) { msm_stop_tx(port); return; } - pio_count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); - dma_count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); + dma_count = pio_count = kfifo_out_linear(&tport->xmit_fifo, NULL, + UART_XMIT_SIZE); dma_min = 1; /* Always DMA */ if (msm_port->is_uartdm > UARTDM_1P3) { diff --git a/drivers/tty/serial/mvebu-uart.c b/drivers/tty/serial/mvebu-uart.c index 0255646bc175..5de57b77abdb 100644 --- a/drivers/tty/serial/mvebu-uart.c +++ b/drivers/tty/serial/mvebu-uart.c @@ -219,12 +219,10 @@ static void mvebu_uart_stop_tx(struct uart_port *port) static void mvebu_uart_start_tx(struct uart_port *port) { unsigned int ctl; - struct circ_buf *xmit = &port->state->xmit; + unsigned char c; - if (IS_EXTENDED(port) && !uart_circ_empty(xmit)) { - writel(xmit->buf[xmit->tail], port->membase + UART_TSH(port)); - uart_xmit_advance(port, 1); - } + if (IS_EXTENDED(port) && uart_fifo_get(port, &c)) + writel(c, port->membase + UART_TSH(port)); ctl = readl(port->membase + UART_INTR(port)); ctl |= CTRL_TX_RDY_INT(port); diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c index 4749331fe618..144b35d31497 100644 --- a/drivers/tty/serial/mxs-auart.c +++ b/drivers/tty/serial/mxs-auart.c @@ -517,7 +517,7 @@ static void mxs_auart_tx_chars(struct mxs_auart_port *s); static void dma_tx_callback(void *param) { struct mxs_auart_port *s = param; - struct circ_buf *xmit = &s->port.state->xmit; + struct tty_port *tport = &s->port.state->port; dma_unmap_sg(s->dev, &s->tx_sgl, 1, DMA_TO_DEVICE); @@ -526,7 +526,7 @@ static void dma_tx_callback(void *param) smp_mb__after_atomic(); /* wake up the possible processes. */ - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(&s->port); mxs_auart_tx_chars(s); @@ -568,33 +568,22 @@ static int mxs_auart_dma_tx(struct mxs_auart_port *s, int size) static void mxs_auart_tx_chars(struct mxs_auart_port *s) { - struct circ_buf *xmit = &s->port.state->xmit; + struct tty_port *tport = &s->port.state->port; bool pending; u8 ch; if (auart_dma_enabled(s)) { u32 i = 0; - int size; void *buffer = s->tx_dma_buf; if (test_and_set_bit(MXS_AUART_DMA_TX_SYNC, &s->flags)) return; - while (!uart_circ_empty(xmit) && !uart_tx_stopped(&s->port)) { - size = min_t(u32, UART_XMIT_SIZE - i, - CIRC_CNT_TO_END(xmit->head, - xmit->tail, - UART_XMIT_SIZE)); - memcpy(buffer + i, xmit->buf + xmit->tail, size); - xmit->tail = (xmit->tail + size) & (UART_XMIT_SIZE - 1); - - i += size; - if (i >= UART_XMIT_SIZE) - break; - } - if (uart_tx_stopped(&s->port)) mxs_auart_stop_tx(&s->port); + else + i = kfifo_out(&tport->xmit_fifo, buffer, + UART_XMIT_SIZE); if (i) { mxs_auart_dma_tx(s, i); diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index 89257cddf540..c7cee5fee603 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -808,7 +808,7 @@ static int dma_handle_rx(struct eg20t_port *priv) static unsigned int handle_tx(struct eg20t_port *priv) { struct uart_port *port = &priv->port; - struct circ_buf *xmit = &port->state->xmit; + unsigned char ch; int fifo_size; int tx_empty; @@ -830,9 +830,9 @@ static unsigned int handle_tx(struct eg20t_port *priv) fifo_size--; } - while (!uart_tx_stopped(port) && !uart_circ_empty(xmit) && fifo_size) { - iowrite8(xmit->buf[xmit->tail], priv->membase + PCH_UART_THR); - uart_xmit_advance(port, 1); + while (!uart_tx_stopped(port) && fifo_size && + uart_fifo_get(port, &ch)) { + iowrite8(ch, priv->membase + PCH_UART_THR); fifo_size--; tx_empty = 0; } @@ -850,14 +850,14 @@ static unsigned int handle_tx(struct eg20t_port *priv) static unsigned int dma_handle_tx(struct eg20t_port *priv) { struct uart_port *port = &priv->port; - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; struct scatterlist *sg; int nent; int fifo_size; struct dma_async_tx_descriptor *desc; + unsigned int bytes, tail; int num; int i; - int bytes; int size; int rem; @@ -886,7 +886,7 @@ static unsigned int dma_handle_tx(struct eg20t_port *priv) fifo_size--; } - bytes = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); + bytes = kfifo_out_linear(&tport->xmit_fifo, &tail, UART_XMIT_SIZE); if (!bytes) { dev_dbg(priv->port.dev, "%s 0 bytes return\n", __func__); pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_TX_INT); @@ -920,10 +920,10 @@ static unsigned int dma_handle_tx(struct eg20t_port *priv) for (i = 0; i < num; i++, sg++) { if (i == (num - 1)) - sg_set_page(sg, virt_to_page(xmit->buf), + sg_set_page(sg, virt_to_page(tport->xmit_buf), rem, fifo_size * i); else - sg_set_page(sg, virt_to_page(xmit->buf), + sg_set_page(sg, virt_to_page(tport->xmit_buf), size, fifo_size * i); } @@ -937,8 +937,7 @@ static unsigned int dma_handle_tx(struct eg20t_port *priv) priv->nent = nent; for (i = 0; i < nent; i++, sg++) { - sg->offset = (xmit->tail & (UART_XMIT_SIZE - 1)) + - fifo_size * i; + sg->offset = tail + fifo_size * i; sg_dma_address(sg) = (sg_dma_address(sg) & ~(UART_XMIT_SIZE - 1)) + sg->offset; if (i == (nent - 1)) diff --git a/drivers/tty/serial/pic32_uart.c b/drivers/tty/serial/pic32_uart.c index bbb46e6e98a2..f5af336a869b 100644 --- a/drivers/tty/serial/pic32_uart.c +++ b/drivers/tty/serial/pic32_uart.c @@ -342,7 +342,7 @@ static void pic32_uart_do_rx(struct uart_port *port) static void pic32_uart_do_tx(struct uart_port *port) { struct pic32_sport *sport = to_pic32_sport(port); - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; unsigned int max_count = PIC32_UART_TX_FIFO_DEPTH; if (port->x_char) { @@ -357,7 +357,7 @@ static void pic32_uart_do_tx(struct uart_port *port) return; } - if (uart_circ_empty(xmit)) + if (kfifo_is_empty(&tport->xmit_fifo)) goto txq_empty; /* keep stuffing chars into uart tx buffer @@ -371,21 +371,20 @@ static void pic32_uart_do_tx(struct uart_port *port) */ while (!(PIC32_UART_STA_UTXBF & pic32_uart_readl(sport, PIC32_UART_STA))) { - unsigned int c = xmit->buf[xmit->tail]; + unsigned char c; + if (!uart_fifo_get(port, &c)) + break; pic32_uart_writel(sport, PIC32_UART_TX, c); - uart_xmit_advance(port, 1); - if (uart_circ_empty(xmit)) - break; if (--max_count == 0) break; } - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(port); - if (uart_circ_empty(xmit)) + if (kfifo_is_empty(&tport->xmit_fifo)) goto txq_empty; return; diff --git a/drivers/tty/serial/pmac_zilog.c b/drivers/tty/serial/pmac_zilog.c index 05d97e89511e..63bc726273fd 100644 --- a/drivers/tty/serial/pmac_zilog.c +++ b/drivers/tty/serial/pmac_zilog.c @@ -347,7 +347,8 @@ static void pmz_status_handle(struct uart_pmac_port *uap) static void pmz_transmit_chars(struct uart_pmac_port *uap) { - struct circ_buf *xmit; + struct tty_port *tport; + unsigned char ch; if (ZS_IS_CONS(uap)) { unsigned char status = read_zsreg(uap, R0); @@ -398,8 +399,8 @@ static void pmz_transmit_chars(struct uart_pmac_port *uap) if (uap->port.state == NULL) goto ack_tx_int; - xmit = &uap->port.state->xmit; - if (uart_circ_empty(xmit)) { + tport = &uap->port.state->port; + if (kfifo_is_empty(&tport->xmit_fifo)) { uart_write_wakeup(&uap->port); goto ack_tx_int; } @@ -407,12 +408,11 @@ static void pmz_transmit_chars(struct uart_pmac_port *uap) goto ack_tx_int; uap->flags |= PMACZILOG_FLAG_TX_ACTIVE; - write_zsdata(uap, xmit->buf[xmit->tail]); + WARN_ON(!uart_fifo_get(&uap->port, &ch)); + write_zsdata(uap, ch); zssync(uap); - uart_xmit_advance(&uap->port, 1); - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(&uap->port); return; @@ -620,15 +620,15 @@ static void pmz_start_tx(struct uart_port *port) port->icount.tx++; port->x_char = 0; } else { - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; + unsigned char ch; - if (uart_circ_empty(xmit)) + if (!uart_fifo_get(&uap->port, &ch)) return; - write_zsdata(uap, xmit->buf[xmit->tail]); + write_zsdata(uap, ch); zssync(uap); - uart_xmit_advance(port, 1); - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(&uap->port); } } diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c index f9f7ac1a10df..7814982f1921 100644 --- a/drivers/tty/serial/qcom_geni_serial.c +++ b/drivers/tty/serial/qcom_geni_serial.c @@ -505,7 +505,7 @@ static void qcom_geni_serial_console_write(struct console *co, const char *s, */ qcom_geni_serial_poll_tx_done(uport); - if (!uart_circ_empty(&uport->state->xmit)) { + if (!kfifo_is_empty(&uport->state->port.xmit_fifo)) { irq_en = readl(uport->membase + SE_GENI_M_IRQ_EN); writel(irq_en | M_TX_FIFO_WATERMARK_EN, uport->membase + SE_GENI_M_IRQ_EN); @@ -620,22 +620,24 @@ static void qcom_geni_serial_stop_tx_dma(struct uart_port *uport) static void qcom_geni_serial_start_tx_dma(struct uart_port *uport) { struct qcom_geni_serial_port *port = to_dev_port(uport); - struct circ_buf *xmit = &uport->state->xmit; + struct tty_port *tport = &uport->state->port; unsigned int xmit_size; + u8 *tail; int ret; if (port->tx_dma_addr) return; - if (uart_circ_empty(xmit)) + if (kfifo_is_empty(&tport->xmit_fifo)) return; - xmit_size = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); + xmit_size = kfifo_out_linear_ptr(&tport->xmit_fifo, &tail, + UART_XMIT_SIZE); qcom_geni_serial_setup_tx(uport, xmit_size); - ret = geni_se_tx_dma_prep(&port->se, &xmit->buf[xmit->tail], - xmit_size, &port->tx_dma_addr); + ret = geni_se_tx_dma_prep(&port->se, tail, xmit_size, + &port->tx_dma_addr); if (ret) { dev_err(uport->dev, "unable to start TX SE DMA: %d\n", ret); qcom_geni_serial_stop_tx_dma(uport); @@ -853,18 +855,16 @@ static void qcom_geni_serial_send_chunk_fifo(struct uart_port *uport, unsigned int chunk) { struct qcom_geni_serial_port *port = to_dev_port(uport); - struct circ_buf *xmit = &uport->state->xmit; - unsigned int tx_bytes, c, remaining = chunk; + struct tty_port *tport = &uport->state->port; + unsigned int tx_bytes, remaining = chunk; u8 buf[BYTES_PER_FIFO_WORD]; while (remaining) { memset(buf, 0, sizeof(buf)); tx_bytes = min(remaining, BYTES_PER_FIFO_WORD); - for (c = 0; c < tx_bytes ; c++) { - buf[c] = xmit->buf[xmit->tail]; - uart_xmit_advance(uport, 1); - } + tx_bytes = kfifo_out(&tport->xmit_fifo, buf, tx_bytes); + uart_xmit_advance(uport, tx_bytes); iowrite32_rep(uport->membase + SE_GENI_TX_FIFOn, buf, 1); @@ -877,7 +877,7 @@ static void qcom_geni_serial_handle_tx_fifo(struct uart_port *uport, bool done, bool active) { struct qcom_geni_serial_port *port = to_dev_port(uport); - struct circ_buf *xmit = &uport->state->xmit; + struct tty_port *tport = &uport->state->port; size_t avail; size_t pending; u32 status; @@ -890,7 +890,7 @@ static void qcom_geni_serial_handle_tx_fifo(struct uart_port *uport, if (active) pending = port->tx_remaining; else - pending = uart_circ_chars_pending(xmit); + pending = kfifo_len(&tport->xmit_fifo); /* All data has been transmitted and acknowledged as received */ if (!pending && !status && done) { @@ -933,24 +933,24 @@ out_write_wakeup: uport->membase + SE_GENI_M_IRQ_EN); } - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(uport); } static void qcom_geni_serial_handle_tx_dma(struct uart_port *uport) { struct qcom_geni_serial_port *port = to_dev_port(uport); - struct circ_buf *xmit = &uport->state->xmit; + struct tty_port *tport = &uport->state->port; uart_xmit_advance(uport, port->tx_remaining); geni_se_tx_dma_unprep(&port->se, port->tx_dma_addr, port->tx_remaining); port->tx_dma_addr = 0; port->tx_remaining = 0; - if (!uart_circ_empty(xmit)) + if (!kfifo_is_empty(&tport->xmit_fifo)) qcom_geni_serial_start_tx_dma(uport); - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(uport); } diff --git a/drivers/tty/serial/rda-uart.c b/drivers/tty/serial/rda-uart.c index 82def9b8632a..663e35e424bd 100644 --- a/drivers/tty/serial/rda-uart.c +++ b/drivers/tty/serial/rda-uart.c @@ -330,8 +330,8 @@ static void rda_uart_set_termios(struct uart_port *port, static void rda_uart_send_chars(struct uart_port *port) { - struct circ_buf *xmit = &port->state->xmit; - unsigned int ch; + struct tty_port *tport = &port->state->port; + unsigned char ch; u32 val; if (uart_tx_stopped(port)) @@ -347,19 +347,14 @@ static void rda_uart_send_chars(struct uart_port *port) port->x_char = 0; } - while (rda_uart_read(port, RDA_UART_STATUS) & RDA_UART_TX_FIFO_MASK) { - if (uart_circ_empty(xmit)) - break; - - ch = xmit->buf[xmit->tail]; + while ((rda_uart_read(port, RDA_UART_STATUS) & RDA_UART_TX_FIFO_MASK) && + uart_fifo_get(port, &ch)) rda_uart_write(port, ch, RDA_UART_RXTX_BUFFER); - uart_xmit_advance(port, 1); - } - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(port); - if (!uart_circ_empty(xmit)) { + if (!kfifo_is_empty(&tport->xmit_fifo)) { /* Re-enable Tx FIFO interrupt */ val = rda_uart_read(port, RDA_UART_IRQ_MASK); val |= RDA_UART_TX_DATA_NEEDED; diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c index a2d07e05c502..dc35eb77d2ef 100644 --- a/drivers/tty/serial/samsung_tty.c +++ b/drivers/tty/serial/samsung_tty.c @@ -329,7 +329,7 @@ static void s3c24xx_serial_tx_dma_complete(void *args) { struct s3c24xx_uart_port *ourport = args; struct uart_port *port = &ourport->port; - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; struct s3c24xx_uart_dma *dma = ourport->dma; struct dma_tx_state state; unsigned long flags; @@ -348,7 +348,7 @@ static void s3c24xx_serial_tx_dma_complete(void *args) uart_xmit_advance(port, count); ourport->tx_in_progress = 0; - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(port); s3c24xx_serial_start_next_tx(ourport); @@ -431,17 +431,15 @@ static void s3c24xx_serial_start_tx_pio(struct s3c24xx_uart_port *ourport) } static int s3c24xx_serial_start_tx_dma(struct s3c24xx_uart_port *ourport, - unsigned int count) + unsigned int count, unsigned int tail) { - struct uart_port *port = &ourport->port; - struct circ_buf *xmit = &port->state->xmit; struct s3c24xx_uart_dma *dma = ourport->dma; if (ourport->tx_mode != S3C24XX_TX_DMA) enable_tx_dma(ourport); dma->tx_size = count & ~(dma_get_cache_alignment() - 1); - dma->tx_transfer_addr = dma->tx_addr + xmit->tail; + dma->tx_transfer_addr = dma->tx_addr + tail; dma_sync_single_for_device(dma->tx_chan->device->dev, dma->tx_transfer_addr, dma->tx_size, @@ -468,11 +466,11 @@ static int s3c24xx_serial_start_tx_dma(struct s3c24xx_uart_port *ourport, static void s3c24xx_serial_start_next_tx(struct s3c24xx_uart_port *ourport) { struct uart_port *port = &ourport->port; - struct circ_buf *xmit = &port->state->xmit; - unsigned long count; + struct tty_port *tport = &port->state->port; + unsigned int count, tail; /* Get data size up to the end of buffer */ - count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); + count = kfifo_out_linear(&tport->xmit_fifo, &tail, UART_XMIT_SIZE); if (!count) { s3c24xx_serial_stop_tx(port); @@ -481,16 +479,16 @@ static void s3c24xx_serial_start_next_tx(struct s3c24xx_uart_port *ourport) if (!ourport->dma || !ourport->dma->tx_chan || count < ourport->min_dma_size || - xmit->tail & (dma_get_cache_alignment() - 1)) + tail & (dma_get_cache_alignment() - 1)) s3c24xx_serial_start_tx_pio(ourport); else - s3c24xx_serial_start_tx_dma(ourport, count); + s3c24xx_serial_start_tx_dma(ourport, count, tail); } static void s3c24xx_serial_start_tx(struct uart_port *port) { struct s3c24xx_uart_port *ourport = to_ourport(port); - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; if (!ourport->tx_enabled) { if (port->flags & UPF_CONS_FLOW) @@ -502,7 +500,8 @@ static void s3c24xx_serial_start_tx(struct uart_port *port) } if (ourport->dma && ourport->dma->tx_chan) { - if (!uart_circ_empty(xmit) && !ourport->tx_in_progress) + if (!kfifo_is_empty(&tport->xmit_fifo) && + !ourport->tx_in_progress) s3c24xx_serial_start_next_tx(ourport); } } @@ -868,18 +867,19 @@ static irqreturn_t s3c24xx_serial_rx_irq(int irq, void *dev_id) static void s3c24xx_serial_tx_chars(struct s3c24xx_uart_port *ourport) { struct uart_port *port = &ourport->port; - struct circ_buf *xmit = &port->state->xmit; - int count, dma_count = 0; + struct tty_port *tport = &port->state->port; + unsigned int count, dma_count = 0, tail; - count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); + count = kfifo_out_linear(&tport->xmit_fifo, &tail, UART_XMIT_SIZE); if (ourport->dma && ourport->dma->tx_chan && count >= ourport->min_dma_size) { int align = dma_get_cache_alignment() - - (xmit->tail & (dma_get_cache_alignment() - 1)); + (tail & (dma_get_cache_alignment() - 1)); if (count - align >= ourport->min_dma_size) { dma_count = count - align; count = align; + tail += align; } } @@ -894,7 +894,7 @@ static void s3c24xx_serial_tx_chars(struct s3c24xx_uart_port *ourport) * stopped, disable the uart and exit */ - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { + if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)) { s3c24xx_serial_stop_tx(port); return; } @@ -906,24 +906,25 @@ static void s3c24xx_serial_tx_chars(struct s3c24xx_uart_port *ourport) dma_count = 0; } - while (!uart_circ_empty(xmit) && count > 0) { - if (rd_regl(port, S3C2410_UFSTAT) & ourport->info->tx_fifofull) + while (!(rd_regl(port, S3C2410_UFSTAT) & ourport->info->tx_fifofull)) { + unsigned char ch; + + if (!uart_fifo_get(port, &ch)) break; - wr_reg(port, S3C2410_UTXH, xmit->buf[xmit->tail]); - uart_xmit_advance(port, 1); + wr_reg(port, S3C2410_UTXH, ch); count--; } if (!count && dma_count) { - s3c24xx_serial_start_tx_dma(ourport, dma_count); + s3c24xx_serial_start_tx_dma(ourport, dma_count, tail); return; } - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(port); - if (uart_circ_empty(xmit)) + if (kfifo_is_empty(&tport->xmit_fifo)) s3c24xx_serial_stop_tx(port); } @@ -1118,7 +1119,8 @@ static int s3c24xx_serial_request_dma(struct s3c24xx_uart_port *p) /* TX buffer */ dma->tx_addr = dma_map_single(dma->tx_chan->device->dev, - p->port.state->xmit.buf, UART_XMIT_SIZE, + p->port.state->port.xmit_buf, + UART_XMIT_SIZE, DMA_TO_DEVICE); if (dma_mapping_error(dma->tx_chan->device->dev, dma->tx_addr)) { reason = "DMA mapping error for TX buffer"; diff --git a/drivers/tty/serial/sb1250-duart.c b/drivers/tty/serial/sb1250-duart.c index dbec29d9a6c3..b4e1b90e5960 100644 --- a/drivers/tty/serial/sb1250-duart.c +++ b/drivers/tty/serial/sb1250-duart.c @@ -382,7 +382,8 @@ static void sbd_receive_chars(struct sbd_port *sport) static void sbd_transmit_chars(struct sbd_port *sport) { struct uart_port *uport = &sport->port; - struct circ_buf *xmit = &sport->port.state->xmit; + struct tty_port *tport = &sport->port.state->port; + unsigned char ch; unsigned int mask; int stop_tx; @@ -395,19 +396,19 @@ static void sbd_transmit_chars(struct sbd_port *sport) } /* If nothing to do or stopped or hardware stopped. */ - stop_tx = (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)); + stop_tx = uart_tx_stopped(&sport->port) || + !uart_fifo_get(&sport->port, &ch); /* Send char. */ if (!stop_tx) { - write_sbdchn(sport, R_DUART_TX_HOLD, xmit->buf[xmit->tail]); - uart_xmit_advance(&sport->port, 1); + write_sbdchn(sport, R_DUART_TX_HOLD, ch); - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(&sport->port); } /* Are we are done? */ - if (stop_tx || uart_circ_empty(xmit)) { + if (stop_tx || kfifo_is_empty(&tport->xmit_fifo)) { /* Disable tx interrupts. */ mask = read_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2)); mask &= ~M_DUART_IMR_TX; diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c index 929206a9a6e1..c6983b7bd78c 100644 --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c @@ -676,9 +676,9 @@ static void sc16is7xx_handle_rx(struct uart_port *port, unsigned int rxlen, static void sc16is7xx_handle_tx(struct uart_port *port) { struct sc16is7xx_port *s = dev_get_drvdata(port->dev); - struct circ_buf *xmit = &port->state->xmit; - unsigned int txlen, to_send, i; + struct tty_port *tport = &port->state->port; unsigned long flags; + unsigned int txlen; if (unlikely(port->x_char)) { sc16is7xx_port_write(port, SC16IS7XX_THR_REG, port->x_char); @@ -687,40 +687,30 @@ static void sc16is7xx_handle_tx(struct uart_port *port) return; } - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { + if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)) { uart_port_lock_irqsave(port, &flags); sc16is7xx_stop_tx(port); uart_port_unlock_irqrestore(port, flags); return; } - /* Get length of data pending in circular buffer */ - to_send = uart_circ_chars_pending(xmit); - if (likely(to_send)) { - /* Limit to space available in TX FIFO */ - txlen = sc16is7xx_port_read(port, SC16IS7XX_TXLVL_REG); - if (txlen > SC16IS7XX_FIFO_SIZE) { - dev_err_ratelimited(port->dev, - "chip reports %d free bytes in TX fifo, but it only has %d", - txlen, SC16IS7XX_FIFO_SIZE); - txlen = 0; - } - to_send = (to_send > txlen) ? txlen : to_send; - - /* Convert to linear buffer */ - for (i = 0; i < to_send; ++i) { - s->buf[i] = xmit->buf[xmit->tail]; - uart_xmit_advance(port, 1); - } - - sc16is7xx_fifo_write(port, s->buf, to_send); + /* Limit to space available in TX FIFO */ + txlen = sc16is7xx_port_read(port, SC16IS7XX_TXLVL_REG); + if (txlen > SC16IS7XX_FIFO_SIZE) { + dev_err_ratelimited(port->dev, + "chip reports %d free bytes in TX fifo, but it only has %d", + txlen, SC16IS7XX_FIFO_SIZE); + txlen = 0; } + txlen = uart_fifo_out(port, s->buf, txlen); + sc16is7xx_fifo_write(port, s->buf, txlen); + uart_port_lock_irqsave(port, &flags); - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(port); - if (uart_circ_empty(xmit)) + if (kfifo_is_empty(&tport->xmit_fifo)) sc16is7xx_stop_tx(port); else sc16is7xx_ier_set(port, SC16IS7XX_IER_THRI_BIT); diff --git a/drivers/tty/serial/sccnxp.c b/drivers/tty/serial/sccnxp.c index f24217a560d7..6d1d142fd216 100644 --- a/drivers/tty/serial/sccnxp.c +++ b/drivers/tty/serial/sccnxp.c @@ -439,7 +439,7 @@ static void sccnxp_handle_rx(struct uart_port *port) static void sccnxp_handle_tx(struct uart_port *port) { u8 sr; - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; struct sccnxp_port *s = dev_get_drvdata(port->dev); if (unlikely(port->x_char)) { @@ -449,7 +449,7 @@ static void sccnxp_handle_tx(struct uart_port *port) return; } - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { + if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)) { /* Disable TX if FIFO is empty */ if (sccnxp_port_read(port, SCCNXP_SR_REG) & SR_TXEMT) { sccnxp_disable_irq(port, IMR_TXRDY); @@ -461,16 +461,20 @@ static void sccnxp_handle_tx(struct uart_port *port) return; } - while (!uart_circ_empty(xmit)) { + while (1) { + unsigned char ch; + sr = sccnxp_port_read(port, SCCNXP_SR_REG); if (!(sr & SR_TXRDY)) break; - sccnxp_port_write(port, SCCNXP_THR_REG, xmit->buf[xmit->tail]); - uart_xmit_advance(port, 1); + if (!uart_fifo_get(port, &ch)) + break; + + sccnxp_port_write(port, SCCNXP_THR_REG, ch); } - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(port); } diff --git a/drivers/tty/serial/serial-tegra.c b/drivers/tty/serial/serial-tegra.c index 525f3a2f7bd4..1183ca54ab92 100644 --- a/drivers/tty/serial/serial-tegra.c +++ b/drivers/tty/serial/serial-tegra.c @@ -484,18 +484,18 @@ static void tegra_uart_release_port(struct uart_port *u) static void tegra_uart_fill_tx_fifo(struct tegra_uart_port *tup, int max_bytes) { - struct circ_buf *xmit = &tup->uport.state->xmit; + unsigned char ch; int i; for (i = 0; i < max_bytes; i++) { - BUG_ON(uart_circ_empty(xmit)); if (tup->cdata->tx_fifo_full_status) { unsigned long lsr = tegra_uart_read(tup, UART_LSR); if ((lsr & TEGRA_UART_LSR_TXFIFO_FULL)) break; } - tegra_uart_write(tup, xmit->buf[xmit->tail], UART_TX); - uart_xmit_advance(&tup->uport, 1); + if (WARN_ON_ONCE(!uart_fifo_get(&tup->uport, &ch))) + break; + tegra_uart_write(tup, ch, UART_TX); } } @@ -514,7 +514,7 @@ static void tegra_uart_start_pio_tx(struct tegra_uart_port *tup, static void tegra_uart_tx_dma_complete(void *args) { struct tegra_uart_port *tup = args; - struct circ_buf *xmit = &tup->uport.state->xmit; + struct tty_port *tport = &tup->uport.state->port; struct dma_tx_state state; unsigned long flags; unsigned int count; @@ -525,7 +525,7 @@ static void tegra_uart_tx_dma_complete(void *args) uart_port_lock_irqsave(&tup->uport, &flags); uart_xmit_advance(&tup->uport, count); tup->tx_in_progress = 0; - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(&tup->uport); tegra_uart_start_next_tx(tup); uart_port_unlock_irqrestore(&tup->uport, flags); @@ -534,11 +534,14 @@ static void tegra_uart_tx_dma_complete(void *args) static int tegra_uart_start_tx_dma(struct tegra_uart_port *tup, unsigned long count) { - struct circ_buf *xmit = &tup->uport.state->xmit; + struct tty_port *tport = &tup->uport.state->port; dma_addr_t tx_phys_addr; + unsigned int tail; tup->tx_bytes = count & ~(0xF); - tx_phys_addr = tup->tx_dma_buf_phys + xmit->tail; + WARN_ON_ONCE(kfifo_out_linear(&tport->xmit_fifo, &tail, + UART_XMIT_SIZE) < count); + tx_phys_addr = tup->tx_dma_buf_phys + tail; dma_sync_single_for_device(tup->uport.dev, tx_phys_addr, tup->tx_bytes, DMA_TO_DEVICE); @@ -562,18 +565,21 @@ static int tegra_uart_start_tx_dma(struct tegra_uart_port *tup, static void tegra_uart_start_next_tx(struct tegra_uart_port *tup) { + struct tty_port *tport = &tup->uport.state->port; + unsigned char *tail_ptr; unsigned long tail; - unsigned long count; - struct circ_buf *xmit = &tup->uport.state->xmit; + unsigned int count; if (!tup->current_baud) return; - tail = (unsigned long)&xmit->buf[xmit->tail]; - count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); + count = kfifo_out_linear_ptr(&tport->xmit_fifo, &tail_ptr, + UART_XMIT_SIZE); if (!count) return; + tail = (unsigned long)tail_ptr; + if (tup->use_tx_pio || count < TEGRA_UART_MIN_DMA) tegra_uart_start_pio_tx(tup, count); else if (BYTES_TO_ALIGN(tail) > 0) @@ -586,9 +592,9 @@ static void tegra_uart_start_next_tx(struct tegra_uart_port *tup) static void tegra_uart_start_tx(struct uart_port *u) { struct tegra_uart_port *tup = to_tegra_uport(u); - struct circ_buf *xmit = &u->state->xmit; + struct tty_port *tport = &u->state->port; - if (!uart_circ_empty(xmit) && !tup->tx_in_progress) + if (!kfifo_is_empty(&tport->xmit_fifo) && !tup->tx_in_progress) tegra_uart_start_next_tx(tup); } @@ -628,11 +634,11 @@ static void tegra_uart_stop_tx(struct uart_port *u) static void tegra_uart_handle_tx_pio(struct tegra_uart_port *tup) { - struct circ_buf *xmit = &tup->uport.state->xmit; + struct tty_port *tport = &tup->uport.state->port; tegra_uart_fill_tx_fifo(tup, tup->tx_bytes); tup->tx_in_progress = 0; - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(&tup->uport); tegra_uart_start_next_tx(tup); } @@ -1169,15 +1175,14 @@ static int tegra_uart_dma_channel_allocate(struct tegra_uart_port *tup, tup->rx_dma_buf_virt = dma_buf; tup->rx_dma_buf_phys = dma_phys; } else { + dma_buf = tup->uport.state->port.xmit_buf; dma_phys = dma_map_single(tup->uport.dev, - tup->uport.state->xmit.buf, UART_XMIT_SIZE, - DMA_TO_DEVICE); + dma_buf, UART_XMIT_SIZE, DMA_TO_DEVICE); if (dma_mapping_error(tup->uport.dev, dma_phys)) { dev_err(tup->uport.dev, "dma_map_single tx failed\n"); dma_release_channel(dma_chan); return -ENOMEM; } - dma_buf = tup->uport.state->xmit.buf; dma_sconfig.dst_addr = tup->uport.mapbase; dma_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; dma_sconfig.dst_maxburst = 16; diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index ff85ebd3a007..3c0931fba1c6 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -272,9 +272,10 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state, return -ENOMEM; uart_port_lock(state, flags); - if (!state->xmit.buf) { - state->xmit.buf = (unsigned char *) page; - uart_circ_clear(&state->xmit); + if (!state->port.xmit_buf) { + state->port.xmit_buf = (unsigned char *)page; + kfifo_init(&state->port.xmit_fifo, state->port.xmit_buf, + PAGE_SIZE); uart_port_unlock(uport, flags); } else { uart_port_unlock(uport, flags); @@ -387,8 +388,9 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state) * can endup in printk() recursion. */ uart_port_lock(state, flags); - xmit_buf = state->xmit.buf; - state->xmit.buf = NULL; + xmit_buf = port->xmit_buf; + port->xmit_buf = NULL; + INIT_KFIFO(port->xmit_fifo); uart_port_unlock(uport, flags); free_page((unsigned long)xmit_buf); @@ -552,22 +554,17 @@ static int uart_put_char(struct tty_struct *tty, u8 c) { struct uart_state *state = tty->driver_data; struct uart_port *port; - struct circ_buf *circ; unsigned long flags; int ret = 0; - circ = &state->xmit; port = uart_port_lock(state, flags); - if (!circ->buf) { + if (WARN_ON_ONCE(!state->port.xmit_buf)) { uart_port_unlock(port, flags); return 0; } - if (port && uart_circ_chars_free(circ) != 0) { - circ->buf[circ->head] = c; - circ->head = (circ->head + 1) & (UART_XMIT_SIZE - 1); - ret = 1; - } + if (port) + ret = kfifo_put(&state->port.xmit_fifo, c); uart_port_unlock(port, flags); return ret; } @@ -581,9 +578,8 @@ static ssize_t uart_write(struct tty_struct *tty, const u8 *buf, size_t count) { struct uart_state *state = tty->driver_data; struct uart_port *port; - struct circ_buf *circ; unsigned long flags; - int c, ret = 0; + int ret = 0; /* * This means you called this function _after_ the port was @@ -593,24 +589,13 @@ static ssize_t uart_write(struct tty_struct *tty, const u8 *buf, size_t count) return -EL3HLT; port = uart_port_lock(state, flags); - circ = &state->xmit; - if (!circ->buf) { + if (WARN_ON_ONCE(!state->port.xmit_buf)) { uart_port_unlock(port, flags); return 0; } - while (port) { - c = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE); - if (count < c) - c = count; - if (c <= 0) - break; - memcpy(circ->buf + circ->head, buf, c); - circ->head = (circ->head + c) & (UART_XMIT_SIZE - 1); - buf += c; - count -= c; - ret += c; - } + if (port) + ret = kfifo_in(&state->port.xmit_fifo, buf, count); __uart_start(state); uart_port_unlock(port, flags); @@ -625,7 +610,7 @@ static unsigned int uart_write_room(struct tty_struct *tty) unsigned int ret; port = uart_port_lock(state, flags); - ret = uart_circ_chars_free(&state->xmit); + ret = kfifo_avail(&state->port.xmit_fifo); uart_port_unlock(port, flags); return ret; } @@ -638,7 +623,7 @@ static unsigned int uart_chars_in_buffer(struct tty_struct *tty) unsigned int ret; port = uart_port_lock(state, flags); - ret = uart_circ_chars_pending(&state->xmit); + ret = kfifo_len(&state->port.xmit_fifo); uart_port_unlock(port, flags); return ret; } @@ -661,7 +646,7 @@ static void uart_flush_buffer(struct tty_struct *tty) port = uart_port_lock(state, flags); if (!port) return; - uart_circ_clear(&state->xmit); + kfifo_reset(&state->port.xmit_fifo); if (port->ops->flush_buffer) port->ops->flush_buffer(port); uart_port_unlock(port, flags); @@ -1064,7 +1049,7 @@ static int uart_get_lsr_info(struct tty_struct *tty, * interrupt happens). */ if (uport->x_char || - ((uart_circ_chars_pending(&state->xmit) > 0) && + (!kfifo_is_empty(&state->port.xmit_fifo) && !uart_tx_stopped(uport))) result &= ~TIOCSER_TEMT; @@ -1788,8 +1773,9 @@ static void uart_tty_port_shutdown(struct tty_port *port) * Free the transmit buffer. */ uart_port_lock_irq(uport); - buf = state->xmit.buf; - state->xmit.buf = NULL; + buf = port->xmit_buf; + port->xmit_buf = NULL; + INIT_KFIFO(port->xmit_fifo); uart_port_unlock_irq(uport); free_page((unsigned long)buf); diff --git a/drivers/tty/serial/serial_port.c b/drivers/tty/serial/serial_port.c index 22b9eeb23e68..3408c8827561 100644 --- a/drivers/tty/serial/serial_port.c +++ b/drivers/tty/serial/serial_port.c @@ -23,7 +23,7 @@ static int __serial_port_busy(struct uart_port *port) { return !uart_tx_stopped(port) && - uart_circ_chars_pending(&port->state->xmit); + !kfifo_is_empty(&port->state->port.xmit_fifo); } static int serial_port_runtime_resume(struct device *dev) diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index e512eaa57ed5..97031db26ae4 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -585,7 +585,7 @@ static void sci_start_tx(struct uart_port *port) sci_serial_out(port, SCSCR, new); } - if (s->chan_tx && !uart_circ_empty(&s->port.state->xmit) && + if (s->chan_tx && !kfifo_is_empty(&port->state->port.xmit_fifo) && dma_submit_error(s->cookie_tx)) { if (s->cfg->regtype == SCIx_RZ_SCIFA_REGTYPE) /* Switch irq from SCIF to DMA */ @@ -817,7 +817,7 @@ static int sci_rxfill(struct uart_port *port) static void sci_transmit_chars(struct uart_port *port) { - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; unsigned int stopped = uart_tx_stopped(port); unsigned short status; unsigned short ctrl; @@ -826,7 +826,7 @@ static void sci_transmit_chars(struct uart_port *port) status = sci_serial_in(port, SCxSR); if (!(status & SCxSR_TDxE(port))) { ctrl = sci_serial_in(port, SCSCR); - if (uart_circ_empty(xmit)) + if (kfifo_is_empty(&tport->xmit_fifo)) ctrl &= ~SCSCR_TIE; else ctrl |= SCSCR_TIE; @@ -842,15 +842,14 @@ static void sci_transmit_chars(struct uart_port *port) if (port->x_char) { c = port->x_char; port->x_char = 0; - } else if (!uart_circ_empty(xmit) && !stopped) { - c = xmit->buf[xmit->tail]; - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - } else if (port->type == PORT_SCI && uart_circ_empty(xmit)) { - ctrl = sci_serial_in(port, SCSCR); - ctrl &= ~SCSCR_TE; - sci_serial_out(port, SCSCR, ctrl); - return; - } else { + } else if (stopped || !kfifo_get(&tport->xmit_fifo, &c)) { + if (port->type == PORT_SCI && + kfifo_is_empty(&tport->xmit_fifo)) { + ctrl = sci_serial_in(port, SCSCR); + ctrl &= ~SCSCR_TE; + sci_serial_out(port, SCSCR, ctrl); + return; + } break; } @@ -861,9 +860,9 @@ static void sci_transmit_chars(struct uart_port *port) sci_clear_SCxSR(port, SCxSR_TDxE_CLEAR(port)); - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(port); - if (uart_circ_empty(xmit)) { + if (kfifo_is_empty(&tport->xmit_fifo)) { if (port->type == PORT_SCI) { ctrl = sci_serial_in(port, SCSCR); ctrl &= ~SCSCR_TIE; @@ -1199,7 +1198,7 @@ static void sci_dma_tx_complete(void *arg) { struct sci_port *s = arg; struct uart_port *port = &s->port; - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; unsigned long flags; dev_dbg(port->dev, "%s(%d)\n", __func__, port->line); @@ -1208,10 +1207,10 @@ static void sci_dma_tx_complete(void *arg) uart_xmit_advance(port, s->tx_dma_len); - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(port); - if (!uart_circ_empty(xmit)) { + if (!kfifo_is_empty(&tport->xmit_fifo)) { s->cookie_tx = 0; schedule_work(&s->work_tx); } else { @@ -1424,10 +1423,10 @@ static void sci_dma_tx_work_fn(struct work_struct *work) struct dma_async_tx_descriptor *desc; struct dma_chan *chan = s->chan_tx; struct uart_port *port = &s->port; - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; unsigned long flags; + unsigned int tail; dma_addr_t buf; - int head, tail; /* * DMA is idle now. @@ -1437,10 +1436,9 @@ static void sci_dma_tx_work_fn(struct work_struct *work) * consistent xmit buffer state. */ uart_port_lock_irq(port); - head = xmit->head; - tail = xmit->tail; + s->tx_dma_len = kfifo_out_linear(&tport->xmit_fifo, &tail, + UART_XMIT_SIZE); buf = s->tx_dma_addr + tail; - s->tx_dma_len = CIRC_CNT_TO_END(head, tail, UART_XMIT_SIZE); if (!s->tx_dma_len) { /* Transmit buffer has been flushed */ uart_port_unlock_irq(port); @@ -1469,8 +1467,8 @@ static void sci_dma_tx_work_fn(struct work_struct *work) } uart_port_unlock_irq(port); - dev_dbg(port->dev, "%s: %p: %d...%d, cookie %d\n", - __func__, xmit->buf, tail, head, s->cookie_tx); + dev_dbg(port->dev, "%s: %p: %u, cookie %d\n", + __func__, tport->xmit_buf, tail, s->cookie_tx); dma_async_issue_pending(chan); return; @@ -1585,6 +1583,7 @@ static struct dma_chan *sci_request_dma_chan(struct uart_port *port, static void sci_request_dma(struct uart_port *port) { struct sci_port *s = to_sci_port(port); + struct tty_port *tport = &port->state->port; struct dma_chan *chan; dev_dbg(port->dev, "%s: port %d\n", __func__, port->line); @@ -1613,7 +1612,7 @@ static void sci_request_dma(struct uart_port *port) if (chan) { /* UART circular tx buffer is an aligned page. */ s->tx_dma_addr = dma_map_single(chan->device->dev, - port->state->xmit.buf, + tport->xmit_buf, UART_XMIT_SIZE, DMA_TO_DEVICE); if (dma_mapping_error(chan->device->dev, s->tx_dma_addr)) { @@ -1622,7 +1621,7 @@ static void sci_request_dma(struct uart_port *port) } else { dev_dbg(port->dev, "%s: mapped %lu@%p to %pad\n", __func__, UART_XMIT_SIZE, - port->state->xmit.buf, &s->tx_dma_addr); + tport->xmit_buf, &s->tx_dma_addr); INIT_WORK(&s->work_tx, sci_dma_tx_work_fn); s->chan_tx_saved = s->chan_tx = chan; diff --git a/drivers/tty/serial/sprd_serial.c b/drivers/tty/serial/sprd_serial.c index 15f14fa593da..3fc54cc02a1f 100644 --- a/drivers/tty/serial/sprd_serial.c +++ b/drivers/tty/serial/sprd_serial.c @@ -227,13 +227,13 @@ static int sprd_tx_buf_remap(struct uart_port *port) { struct sprd_uart_port *sp = container_of(port, struct sprd_uart_port, port); - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; + unsigned char *tail; - sp->tx_dma.trans_len = - CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); + sp->tx_dma.trans_len = kfifo_out_linear_ptr(&tport->xmit_fifo, &tail, + UART_XMIT_SIZE); - sp->tx_dma.phys_addr = dma_map_single(port->dev, - (void *)&(xmit->buf[xmit->tail]), + sp->tx_dma.phys_addr = dma_map_single(port->dev, tail, sp->tx_dma.trans_len, DMA_TO_DEVICE); return dma_mapping_error(port->dev, sp->tx_dma.phys_addr); @@ -244,7 +244,7 @@ static void sprd_complete_tx_dma(void *data) struct uart_port *port = (struct uart_port *)data; struct sprd_uart_port *sp = container_of(port, struct sprd_uart_port, port); - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; unsigned long flags; uart_port_lock_irqsave(port, &flags); @@ -253,10 +253,10 @@ static void sprd_complete_tx_dma(void *data) uart_xmit_advance(port, sp->tx_dma.trans_len); - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(port); - if (uart_circ_empty(xmit) || sprd_tx_buf_remap(port) || + if (kfifo_is_empty(&tport->xmit_fifo) || sprd_tx_buf_remap(port) || sprd_tx_dma_config(port)) sp->tx_dma.trans_len = 0; @@ -319,7 +319,7 @@ static void sprd_start_tx_dma(struct uart_port *port) { struct sprd_uart_port *sp = container_of(port, struct sprd_uart_port, port); - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; if (port->x_char) { serial_out(port, SPRD_TXD, port->x_char); @@ -328,7 +328,7 @@ static void sprd_start_tx_dma(struct uart_port *port) return; } - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { + if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)) { sprd_stop_tx_dma(port); return; } diff --git a/drivers/tty/serial/st-asc.c b/drivers/tty/serial/st-asc.c index a23e59551848..f91753a40a69 100644 --- a/drivers/tty/serial/st-asc.c +++ b/drivers/tty/serial/st-asc.c @@ -387,9 +387,9 @@ static unsigned int asc_get_mctrl(struct uart_port *port) /* There are probably characters waiting to be transmitted. */ static void asc_start_tx(struct uart_port *port) { - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; - if (!uart_circ_empty(xmit)) + if (!kfifo_is_empty(&tport->xmit_fifo)) asc_enable_tx_interrupts(port); } diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c index 58d169e5c1db..8c66abcfe6ca 100644 --- a/drivers/tty/serial/stm32-usart.c +++ b/drivers/tty/serial/stm32-usart.c @@ -696,18 +696,23 @@ static void stm32_usart_transmit_chars_pio(struct uart_port *port) { struct stm32_port *stm32_port = to_stm32_port(port); const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; + + while (1) { + unsigned char ch; - while (!uart_circ_empty(xmit)) { /* Check that TDR is empty before filling FIFO */ if (!(readl_relaxed(port->membase + ofs->isr) & USART_SR_TXE)) break; - writel_relaxed(xmit->buf[xmit->tail], port->membase + ofs->tdr); - uart_xmit_advance(port, 1); + + if (!uart_fifo_get(port, &ch)) + break; + + writel_relaxed(ch, port->membase + ofs->tdr); } /* rely on TXE irq (mask or unmask) for sending remaining data */ - if (uart_circ_empty(xmit)) + if (kfifo_is_empty(&tport->xmit_fifo)) stm32_usart_tx_interrupt_disable(port); else stm32_usart_tx_interrupt_enable(port); @@ -716,7 +721,7 @@ static void stm32_usart_transmit_chars_pio(struct uart_port *port) static void stm32_usart_transmit_chars_dma(struct uart_port *port) { struct stm32_port *stm32port = to_stm32_port(port); - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; struct dma_async_tx_descriptor *desc = NULL; unsigned int count; int ret; @@ -728,25 +733,8 @@ static void stm32_usart_transmit_chars_dma(struct uart_port *port) return; } - count = uart_circ_chars_pending(xmit); - - if (count > TX_BUF_L) - count = TX_BUF_L; - - if (xmit->tail < xmit->head) { - memcpy(&stm32port->tx_buf[0], &xmit->buf[xmit->tail], count); - } else { - size_t one = UART_XMIT_SIZE - xmit->tail; - size_t two; - - if (one > count) - one = count; - two = count - one; - - memcpy(&stm32port->tx_buf[0], &xmit->buf[xmit->tail], one); - if (two) - memcpy(&stm32port->tx_buf[one], &xmit->buf[0], two); - } + count = kfifo_out_peek(&tport->xmit_fifo, &stm32port->tx_buf[0], + TX_BUF_L); desc = dmaengine_prep_slave_single(stm32port->tx_ch, stm32port->tx_dma_buf, @@ -792,14 +780,14 @@ static void stm32_usart_transmit_chars(struct uart_port *port) { struct stm32_port *stm32_port = to_stm32_port(port); const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; u32 isr; int ret; if (!stm32_port->hw_flow_control && port->rs485.flags & SER_RS485_ENABLED && (port->x_char || - !(uart_circ_empty(xmit) || uart_tx_stopped(port)))) { + !(kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)))) { stm32_usart_tc_interrupt_disable(port); stm32_usart_rs485_rts_enable(port); } @@ -826,7 +814,7 @@ static void stm32_usart_transmit_chars(struct uart_port *port) return; } - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { + if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)) { stm32_usart_tx_interrupt_disable(port); return; } @@ -841,10 +829,10 @@ static void stm32_usart_transmit_chars(struct uart_port *port) else stm32_usart_transmit_chars_pio(port); - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(port); - if (uart_circ_empty(xmit)) { + if (kfifo_is_empty(&tport->xmit_fifo)) { stm32_usart_tx_interrupt_disable(port); if (!stm32_port->hw_flow_control && port->rs485.flags & SER_RS485_ENABLED) { @@ -967,9 +955,9 @@ static void stm32_usart_stop_tx(struct uart_port *port) /* There are probably characters waiting to be transmitted. */ static void stm32_usart_start_tx(struct uart_port *port) { - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; - if (uart_circ_empty(xmit) && !port->x_char) { + if (kfifo_is_empty(&tport->xmit_fifo) && !port->x_char) { stm32_usart_rs485_rts_disable(port); return; } diff --git a/drivers/tty/serial/sunhv.c b/drivers/tty/serial/sunhv.c index 8d612ab80680..7f60679fdde1 100644 --- a/drivers/tty/serial/sunhv.c +++ b/drivers/tty/serial/sunhv.c @@ -39,10 +39,13 @@ static char *con_read_page; static int hung_up = 0; -static void transmit_chars_putchar(struct uart_port *port, struct circ_buf *xmit) +static void transmit_chars_putchar(struct uart_port *port, + struct tty_port *tport) { - while (!uart_circ_empty(xmit)) { - long status = sun4v_con_putchar(xmit->buf[xmit->tail]); + unsigned char ch; + + while (kfifo_peek(&tport->xmit_fifo, &ch)) { + long status = sun4v_con_putchar(ch); if (status != HV_EOK) break; @@ -51,14 +54,16 @@ static void transmit_chars_putchar(struct uart_port *port, struct circ_buf *xmit } } -static void transmit_chars_write(struct uart_port *port, struct circ_buf *xmit) +static void transmit_chars_write(struct uart_port *port, struct tty_port *tport) { - while (!uart_circ_empty(xmit)) { - unsigned long ra = __pa(xmit->buf + xmit->tail); - unsigned long len, status, sent; + while (!kfifo_is_empty(&tport->xmit_fifo)) { + unsigned long len, ra, status, sent; + unsigned char *tail; + + len = kfifo_out_linear_ptr(&tport->xmit_fifo, &tail, + UART_XMIT_SIZE); + ra = __pa(tail); - len = CIRC_CNT_TO_END(xmit->head, xmit->tail, - UART_XMIT_SIZE); status = sun4v_con_write(ra, len, &sent); if (status != HV_EOK) break; @@ -165,7 +170,7 @@ static int receive_chars_read(struct uart_port *port) } struct sunhv_ops { - void (*transmit_chars)(struct uart_port *port, struct circ_buf *xmit); + void (*transmit_chars)(struct uart_port *port, struct tty_port *tport); int (*receive_chars)(struct uart_port *port); }; @@ -196,18 +201,18 @@ static struct tty_port *receive_chars(struct uart_port *port) static void transmit_chars(struct uart_port *port) { - struct circ_buf *xmit; + struct tty_port *tport; if (!port->state) return; - xmit = &port->state->xmit; - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) + tport = &port->state->port; + if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)) return; - sunhv_ops->transmit_chars(port, xmit); + sunhv_ops->transmit_chars(port, tport); - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(port); } diff --git a/drivers/tty/serial/sunplus-uart.c b/drivers/tty/serial/sunplus-uart.c index f5e29eb4a4ce..abf7c449308d 100644 --- a/drivers/tty/serial/sunplus-uart.c +++ b/drivers/tty/serial/sunplus-uart.c @@ -200,7 +200,7 @@ static void sunplus_break_ctl(struct uart_port *port, int ctl) static void transmit_chars(struct uart_port *port) { - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; if (port->x_char) { sp_uart_put_char(port, port->x_char); @@ -209,22 +209,24 @@ static void transmit_chars(struct uart_port *port) return; } - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { + if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)) { sunplus_stop_tx(port); return; } do { - sp_uart_put_char(port, xmit->buf[xmit->tail]); - uart_xmit_advance(port, 1); - if (uart_circ_empty(xmit)) + unsigned char ch; + + if (!uart_fifo_get(port, &ch)) break; + + sp_uart_put_char(port, ch); } while (sunplus_tx_buf_not_full(port)); - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(port); - if (uart_circ_empty(xmit)) + if (kfifo_is_empty(&tport->xmit_fifo)) sunplus_stop_tx(port); } diff --git a/drivers/tty/serial/sunsab.c b/drivers/tty/serial/sunsab.c index 1ea2f33a07a7..1acbe2fba746 100644 --- a/drivers/tty/serial/sunsab.c +++ b/drivers/tty/serial/sunsab.c @@ -232,7 +232,7 @@ static void sunsab_tx_idle(struct uart_sunsab_port *); static void transmit_chars(struct uart_sunsab_port *up, union sab82532_irq_status *stat) { - struct circ_buf *xmit = &up->port.state->xmit; + struct tty_port *tport = &up->port.state->port; int i; if (stat->sreg.isr1 & SAB82532_ISR1_ALLS) { @@ -252,7 +252,7 @@ static void transmit_chars(struct uart_sunsab_port *up, set_bit(SAB82532_XPR, &up->irqflags); sunsab_tx_idle(up); - if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) { + if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(&up->port)) { up->interrupt_mask1 |= SAB82532_IMR1_XPR; writeb(up->interrupt_mask1, &up->regs->w.imr1); return; @@ -265,21 +265,22 @@ static void transmit_chars(struct uart_sunsab_port *up, /* Stuff 32 bytes into Transmit FIFO. */ clear_bit(SAB82532_XPR, &up->irqflags); for (i = 0; i < up->port.fifosize; i++) { - writeb(xmit->buf[xmit->tail], - &up->regs->w.xfifo[i]); - uart_xmit_advance(&up->port, 1); - if (uart_circ_empty(xmit)) + unsigned char ch; + + if (!uart_fifo_get(&up->port, &ch)) break; + + writeb(ch, &up->regs->w.xfifo[i]); } /* Issue a Transmit Frame command. */ sunsab_cec_wait(up); writeb(SAB82532_CMDR_XF, &up->regs->w.cmdr); - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(&up->port); - if (uart_circ_empty(xmit)) + if (kfifo_is_empty(&tport->xmit_fifo)) sunsab_stop_tx(&up->port); } @@ -435,10 +436,10 @@ static void sunsab_start_tx(struct uart_port *port) { struct uart_sunsab_port *up = container_of(port, struct uart_sunsab_port, port); - struct circ_buf *xmit = &up->port.state->xmit; + struct tty_port *tport = &up->port.state->port; int i; - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) + if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)) return; up->interrupt_mask1 &= ~(SAB82532_IMR1_ALLS|SAB82532_IMR1_XPR); @@ -451,11 +452,12 @@ static void sunsab_start_tx(struct uart_port *port) clear_bit(SAB82532_XPR, &up->irqflags); for (i = 0; i < up->port.fifosize; i++) { - writeb(xmit->buf[xmit->tail], - &up->regs->w.xfifo[i]); - uart_xmit_advance(&up->port, 1); - if (uart_circ_empty(xmit)) + unsigned char ch; + + if (!uart_fifo_get(&up->port, &ch)) break; + + writeb(ch, &up->regs->w.xfifo[i]); } /* Issue a Transmit Frame command. */ diff --git a/drivers/tty/serial/sunsu.c b/drivers/tty/serial/sunsu.c index c8b65f4b2710..67a5fc70bb4b 100644 --- a/drivers/tty/serial/sunsu.c +++ b/drivers/tty/serial/sunsu.c @@ -396,7 +396,8 @@ receive_chars(struct uart_sunsu_port *up, unsigned char *status) static void transmit_chars(struct uart_sunsu_port *up) { - struct circ_buf *xmit = &up->port.state->xmit; + struct tty_port *tport = &up->port.state->port; + unsigned char ch; int count; if (up->port.x_char) { @@ -409,23 +410,23 @@ static void transmit_chars(struct uart_sunsu_port *up) sunsu_stop_tx(&up->port); return; } - if (uart_circ_empty(xmit)) { + if (kfifo_is_empty(&tport->xmit_fifo)) { __stop_tx(up); return; } count = up->port.fifosize; do { - serial_out(up, UART_TX, xmit->buf[xmit->tail]); - uart_xmit_advance(&up->port, 1); - if (uart_circ_empty(xmit)) + if (!uart_fifo_get(&up->port, &ch)) break; + + serial_out(up, UART_TX, ch); } while (--count > 0); - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(&up->port); - if (uart_circ_empty(xmit)) + if (kfifo_is_empty(&tport->xmit_fifo)) __stop_tx(up); } diff --git a/drivers/tty/serial/sunzilog.c b/drivers/tty/serial/sunzilog.c index c99289c6c8f8..71758ad4241c 100644 --- a/drivers/tty/serial/sunzilog.c +++ b/drivers/tty/serial/sunzilog.c @@ -453,7 +453,8 @@ static void sunzilog_status_handle(struct uart_sunzilog_port *up, static void sunzilog_transmit_chars(struct uart_sunzilog_port *up, struct zilog_channel __iomem *channel) { - struct circ_buf *xmit; + struct tty_port *tport; + unsigned char ch; if (ZS_IS_CONS(up)) { unsigned char status = readb(&channel->control); @@ -496,21 +497,20 @@ static void sunzilog_transmit_chars(struct uart_sunzilog_port *up, if (up->port.state == NULL) goto ack_tx_int; - xmit = &up->port.state->xmit; - if (uart_circ_empty(xmit)) - goto ack_tx_int; + tport = &up->port.state->port; if (uart_tx_stopped(&up->port)) goto ack_tx_int; + if (!uart_fifo_get(&up->port, &ch)) + goto ack_tx_int; + up->flags |= SUNZILOG_FLAG_TX_ACTIVE; - writeb(xmit->buf[xmit->tail], &channel->data); + writeb(ch, &channel->data); ZSDELAY(); ZS_WSYNC(channel); - uart_xmit_advance(&up->port, 1); - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(&up->port); return; @@ -700,17 +700,16 @@ static void sunzilog_start_tx(struct uart_port *port) port->icount.tx++; port->x_char = 0; } else { - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; + unsigned char ch; - if (uart_circ_empty(xmit)) + if (!uart_fifo_get(&up->port, &ch)) return; - writeb(xmit->buf[xmit->tail], &channel->data); + writeb(ch, &channel->data); ZSDELAY(); ZS_WSYNC(channel); - uart_xmit_advance(port, 1); - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(&up->port); } } diff --git a/drivers/tty/serial/tegra-tcu.c b/drivers/tty/serial/tegra-tcu.c index d9c78320eb02..21ca5fcadf49 100644 --- a/drivers/tty/serial/tegra-tcu.c +++ b/drivers/tty/serial/tegra-tcu.c @@ -91,15 +91,17 @@ static void tegra_tcu_write(struct tegra_tcu *tcu, const char *s, static void tegra_tcu_uart_start_tx(struct uart_port *port) { struct tegra_tcu *tcu = port->private_data; - struct circ_buf *xmit = &port->state->xmit; - unsigned long count; + struct tty_port *tport = &port->state->port; + unsigned char *tail; + unsigned int count; for (;;) { - count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); + count = kfifo_out_linear_ptr(&tport->xmit_fifo, &tail, + UART_XMIT_SIZE); if (!count) break; - tegra_tcu_write(tcu, &xmit->buf[xmit->tail], count); + tegra_tcu_write(tcu, tail, count); uart_xmit_advance(port, count); } diff --git a/drivers/tty/serial/timbuart.c b/drivers/tty/serial/timbuart.c index 4bc89a9b380a..43fa0938b5e3 100644 --- a/drivers/tty/serial/timbuart.c +++ b/drivers/tty/serial/timbuart.c @@ -95,14 +95,11 @@ static void timbuart_rx_chars(struct uart_port *port) static void timbuart_tx_chars(struct uart_port *port) { - struct circ_buf *xmit = &port->state->xmit; + unsigned char ch; while (!(ioread32(port->membase + TIMBUART_ISR) & TXBF) && - !uart_circ_empty(xmit)) { - iowrite8(xmit->buf[xmit->tail], - port->membase + TIMBUART_TXFIFO); - uart_xmit_advance(port, 1); - } + uart_fifo_get(port, &ch)) + iowrite8(ch, port->membase + TIMBUART_TXFIFO); dev_dbg(port->dev, "%s - total written %d bytes, CTL: %x, RTS: %x, baud: %x\n", @@ -117,9 +114,9 @@ static void timbuart_handle_tx_port(struct uart_port *port, u32 isr, u32 *ier) { struct timbuart_port *uart = container_of(port, struct timbuart_port, port); - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) + if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)) return; if (port->x_char) @@ -130,7 +127,7 @@ static void timbuart_handle_tx_port(struct uart_port *port, u32 isr, u32 *ier) /* clear all TX interrupts */ iowrite32(TXFLAGS, port->membase + TIMBUART_ISR); - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(port); } else /* Re-enable any tx interrupt */ @@ -141,7 +138,7 @@ static void timbuart_handle_tx_port(struct uart_port *port, u32 isr, u32 *ier) * we wake up the upper layer later when we got the interrupt * to give it some time to go out... */ - if (!uart_circ_empty(xmit)) + if (!kfifo_is_empty(&tport->xmit_fifo)) *ier |= TXBAE; dev_dbg(port->dev, "%s - leaving\n", __func__); diff --git a/drivers/tty/serial/uartlite.c b/drivers/tty/serial/uartlite.c index 10ba41b7be99..68357ac8ffe3 100644 --- a/drivers/tty/serial/uartlite.c +++ b/drivers/tty/serial/uartlite.c @@ -189,7 +189,8 @@ static int ulite_receive(struct uart_port *port, int stat) static int ulite_transmit(struct uart_port *port, int stat) { - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; + unsigned char ch; if (stat & ULITE_STATUS_TXFULL) return 0; @@ -201,14 +202,16 @@ static int ulite_transmit(struct uart_port *port, int stat) return 1; } - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) + if (uart_tx_stopped(port)) + return 0; + + if (!uart_fifo_get(port, &ch)) return 0; - uart_out32(xmit->buf[xmit->tail], ULITE_TX, port); - uart_xmit_advance(port, 1); + uart_out32(ch, ULITE_TX, port); /* wake up */ - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(port); return 1; diff --git a/drivers/tty/serial/ucc_uart.c b/drivers/tty/serial/ucc_uart.c index 397b95dff7ed..53bb8c5ef499 100644 --- a/drivers/tty/serial/ucc_uart.c +++ b/drivers/tty/serial/ucc_uart.c @@ -334,7 +334,7 @@ static int qe_uart_tx_pump(struct uart_qe_port *qe_port) unsigned char *p; unsigned int count; struct uart_port *port = &qe_port->port; - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; /* Handle xon/xoff */ if (port->x_char) { @@ -358,7 +358,7 @@ static int qe_uart_tx_pump(struct uart_qe_port *qe_port) return 1; } - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { + if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)) { qe_uart_stop_tx(port); return 0; } @@ -366,16 +366,10 @@ static int qe_uart_tx_pump(struct uart_qe_port *qe_port) /* Pick next descriptor and fill from buffer */ bdp = qe_port->tx_cur; - while (!(ioread16be(&bdp->status) & BD_SC_READY) && !uart_circ_empty(xmit)) { - count = 0; + while (!(ioread16be(&bdp->status) & BD_SC_READY) && + !kfifo_is_empty(&tport->xmit_fifo)) { p = qe2cpu_addr(ioread32be(&bdp->buf), qe_port); - while (count < qe_port->tx_fifosize) { - *p++ = xmit->buf[xmit->tail]; - uart_xmit_advance(port, 1); - count++; - if (uart_circ_empty(xmit)) - break; - } + count = uart_fifo_out(port, p, qe_port->tx_fifosize); iowrite16be(count, &bdp->length); qe_setbits_be16(&bdp->status, BD_SC_READY); @@ -388,10 +382,10 @@ static int qe_uart_tx_pump(struct uart_qe_port *qe_port) } qe_port->tx_cur = bdp; - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(port); - if (uart_circ_empty(xmit)) { + if (kfifo_is_empty(&tport->xmit_fifo)) { /* The kernel buffer is empty, so turn off TX interrupts. We don't need to be told when the QE is finished transmitting the data. */ diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c index 5f48ec37cb25..de3487206bcb 100644 --- a/drivers/tty/serial/xilinx_uartps.c +++ b/drivers/tty/serial/xilinx_uartps.c @@ -425,32 +425,32 @@ static void cdns_uart_handle_tx(void *dev_id) { struct uart_port *port = (struct uart_port *)dev_id; struct cdns_uart *cdns_uart = port->private_data; - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; unsigned int numbytes; + unsigned char ch; - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { + if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)) { /* Disable the TX Empty interrupt */ writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_IDR); return; } numbytes = port->fifosize; - while (numbytes && !uart_circ_empty(xmit) && - !(readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_TXFULL)) { - - writel(xmit->buf[xmit->tail], port->membase + CDNS_UART_FIFO); - uart_xmit_advance(port, 1); + while (numbytes && + !(readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_TXFULL) && + uart_fifo_get(port, &ch)) { + writel(ch, port->membase + CDNS_UART_FIFO); numbytes--; } - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(port); /* Enable the TX Empty interrupt */ writel(CDNS_UART_IXR_TXEMPTY, cdns_uart->port->membase + CDNS_UART_IER); if (cdns_uart->port->rs485.flags & SER_RS485_ENABLED && - (uart_circ_empty(xmit) || uart_tx_stopped(port))) { + (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port))) { cdns_uart->tx_timer.function = &cdns_rs485_rx_callback; hrtimer_start(&cdns_uart->tx_timer, ns_to_ktime(cdns_calc_after_tx_delay(cdns_uart)), HRTIMER_MODE_REL); @@ -723,7 +723,7 @@ static void cdns_uart_start_tx(struct uart_port *port) status |= CDNS_UART_CR_TX_EN; writel(status, port->membase + CDNS_UART_CR); - if (uart_circ_empty(&port->state->xmit)) + if (kfifo_is_empty(&port->state->port.xmit_fifo)) return; /* Clear the TX Empty interrupt */ diff --git a/drivers/tty/serial/zs.c b/drivers/tty/serial/zs.c index 65ca4da6e368..79ea7108a0f3 100644 --- a/drivers/tty/serial/zs.c +++ b/drivers/tty/serial/zs.c @@ -606,7 +606,8 @@ static void zs_receive_chars(struct zs_port *zport) static void zs_raw_transmit_chars(struct zs_port *zport) { - struct circ_buf *xmit = &zport->port.state->xmit; + struct tty_port *tport = &zport->port.state->port; + unsigned char ch; /* XON/XOFF chars. */ if (zport->port.x_char) { @@ -617,20 +618,20 @@ static void zs_raw_transmit_chars(struct zs_port *zport) } /* If nothing to do or stopped or hardware stopped. */ - if (uart_circ_empty(xmit) || uart_tx_stopped(&zport->port)) { + if (uart_tx_stopped(&zport->port) || + !uart_fifo_get(&zport->port, &ch)) { zs_raw_stop_tx(zport); return; } /* Send char. */ - write_zsdata(zport, xmit->buf[xmit->tail]); - uart_xmit_advance(&zport->port, 1); + write_zsdata(zport, ch); - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(&zport->port); /* Are we are done? */ - if (uart_circ_empty(xmit)) + if (kfifo_is_empty(&tport->xmit_fifo)) zs_raw_stop_tx(zport); } diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index 0a0f6e21d40e..8cb65f50e830 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include @@ -699,7 +698,6 @@ struct uart_state { struct tty_port port; enum uart_pm_state pm_state; - struct circ_buf xmit; atomic_t refcount; wait_queue_head_t remove_wait; @@ -723,12 +721,35 @@ struct uart_state { */ static inline void uart_xmit_advance(struct uart_port *up, unsigned int chars) { - struct circ_buf *xmit = &up->state->xmit; + struct tty_port *tport = &up->state->port; - xmit->tail = (xmit->tail + chars) & (UART_XMIT_SIZE - 1); + kfifo_skip_count(&tport->xmit_fifo, chars); up->icount.tx += chars; } +static inline unsigned int uart_fifo_out(struct uart_port *up, + unsigned char *buf, unsigned int chars) +{ + struct tty_port *tport = &up->state->port; + + chars = kfifo_out(&tport->xmit_fifo, buf, chars); + up->icount.tx += chars; + + return chars; +} + +static inline unsigned int uart_fifo_get(struct uart_port *up, + unsigned char *ch) +{ + struct tty_port *tport = &up->state->port; + unsigned int chars; + + chars = kfifo_get(&tport->xmit_fifo, ch); + up->icount.tx += chars; + + return chars; +} + struct module; struct tty_driver; @@ -764,7 +785,7 @@ enum UART_TX_FLAGS { for_test, for_post) \ ({ \ struct uart_port *__port = (uport); \ - struct circ_buf *xmit = &__port->state->xmit; \ + struct tty_port *__tport = &__port->state->port; \ unsigned int pending; \ \ for (; (for_test) && (tx_ready); (for_post), __port->icount.tx++) { \ @@ -775,17 +796,18 @@ enum UART_TX_FLAGS { continue; \ } \ \ - if (uart_circ_empty(xmit) || uart_tx_stopped(__port)) \ + if (uart_tx_stopped(__port)) \ + break; \ + \ + if (!kfifo_get(&__tport->xmit_fifo, &(ch))) \ break; \ \ - (ch) = xmit->buf[xmit->tail]; \ (put_char); \ - xmit->tail = (xmit->tail + 1) % UART_XMIT_SIZE; \ } \ \ (tx_done); \ \ - pending = uart_circ_chars_pending(xmit); \ + pending = kfifo_len(&__tport->xmit_fifo); \ if (pending < WAKEUP_CHARS) { \ uart_write_wakeup(__port); \ \ @@ -974,15 +996,6 @@ bool uart_match_port(const struct uart_port *port1, int uart_suspend_port(struct uart_driver *reg, struct uart_port *port); int uart_resume_port(struct uart_driver *reg, struct uart_port *port); -#define uart_circ_empty(circ) ((circ)->head == (circ)->tail) -#define uart_circ_clear(circ) ((circ)->head = (circ)->tail = 0) - -#define uart_circ_chars_pending(circ) \ - (CIRC_CNT((circ)->head, (circ)->tail, UART_XMIT_SIZE)) - -#define uart_circ_chars_free(circ) \ - (CIRC_SPACE((circ)->head, (circ)->tail, UART_XMIT_SIZE)) - static inline int uart_tx_stopped(struct uart_port *port) { struct tty_struct *tty = port->state->port.tty; -- cgit v1.2.3-59-g8ed1b From b9cea51b65abecb4dc327a19ab58e6fb116e7e85 Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Fri, 5 Apr 2024 08:08:24 +0200 Subject: tty: atmel_serial: use single DMA mapping for TX dma_map_single() provides much easier interface for simple mappings as used for TX in atmel_serial. So switch to that, removing all the s-g unnecessary handling. Note that it is not easy (maybe impossible) to use kfifo_dma_* API for atmel's serial purposes. It handles DMA very specially. Signed-off-by: Jiri Slaby (SUSE) Cc: Richard Genoud Cc: Nicolas Ferre Cc: Alexandre Belloni Cc: Claudiu Beznea Cc: linux-arm-kernel@lists.infradead.org Link: https://lore.kernel.org/r/20240405060826.2521-14-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/atmel_serial.c | 35 ++++++++++++++--------------------- 1 file changed, 14 insertions(+), 21 deletions(-) diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index 5bb5e4303754..69ec80ffc97b 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -132,7 +132,7 @@ struct atmel_uart_port { struct dma_async_tx_descriptor *desc_rx; dma_cookie_t cookie_tx; dma_cookie_t cookie_rx; - struct scatterlist sg_tx; + dma_addr_t tx_phys; struct scatterlist sg_rx; struct tasklet_struct tasklet_rx; struct tasklet_struct tasklet_tx; @@ -904,8 +904,8 @@ static void atmel_release_tx_dma(struct uart_port *port) if (chan) { dmaengine_terminate_all(chan); dma_release_channel(chan); - dma_unmap_sg(port->dev, &atmel_port->sg_tx, 1, - DMA_TO_DEVICE); + dma_unmap_single(port->dev, atmel_port->tx_phys, + UART_XMIT_SIZE, DMA_TO_DEVICE); } atmel_port->desc_tx = NULL; @@ -922,7 +922,7 @@ static void atmel_tx_dma(struct uart_port *port) struct tty_port *tport = &port->state->port; struct dma_chan *chan = atmel_port->chan_tx; struct dma_async_tx_descriptor *desc; - struct scatterlist sgl[2], *sg, *sg_tx = &atmel_port->sg_tx; + struct scatterlist sgl[2], *sg; unsigned int tx_len, tail, part1_len, part2_len, sg_len; dma_addr_t phys_addr; @@ -955,7 +955,7 @@ static void atmel_tx_dma(struct uart_port *port) sg_init_table(sgl, 2); sg_len = 0; - phys_addr = sg_dma_address(sg_tx) + tail; + phys_addr = atmel_port->tx_phys + tail; if (part1_len) { sg = &sgl[sg_len++]; sg_dma_address(sg) = phys_addr; @@ -987,7 +987,8 @@ static void atmel_tx_dma(struct uart_port *port) return; } - dma_sync_sg_for_device(port->dev, sg_tx, 1, DMA_TO_DEVICE); + dma_sync_single_for_device(port->dev, atmel_port->tx_phys, + UART_XMIT_SIZE, DMA_TO_DEVICE); atmel_port->desc_tx = desc; desc->callback = atmel_complete_tx_dma; @@ -1014,7 +1015,7 @@ static int atmel_prepare_tx_dma(struct uart_port *port) dma_cap_mask_t mask; struct dma_slave_config config; struct dma_chan *chan; - int ret, nent; + int ret; dma_cap_zero(mask); dma_cap_set(DMA_SLAVE, mask); @@ -1029,26 +1030,18 @@ static int atmel_prepare_tx_dma(struct uart_port *port) dma_chan_name(atmel_port->chan_tx)); spin_lock_init(&atmel_port->lock_tx); - sg_init_table(&atmel_port->sg_tx, 1); /* UART circular tx buffer is an aligned page. */ BUG_ON(!PAGE_ALIGNED(tport->xmit_buf)); - sg_set_page(&atmel_port->sg_tx, - virt_to_page(tport->xmit_buf), - UART_XMIT_SIZE, - offset_in_page(tport->xmit_buf)); - nent = dma_map_sg(port->dev, - &atmel_port->sg_tx, - 1, - DMA_TO_DEVICE); + atmel_port->tx_phys = dma_map_single(port->dev, tport->xmit_buf, + UART_XMIT_SIZE, DMA_TO_DEVICE); - if (!nent) { + if (dma_mapping_error(port->dev, atmel_port->tx_phys)) { dev_dbg(port->dev, "need to release resource of dma\n"); goto chan_err; } else { - dev_dbg(port->dev, "%s: mapped %d@%p to %pad\n", __func__, - sg_dma_len(&atmel_port->sg_tx), - tport->xmit_buf, - &sg_dma_address(&atmel_port->sg_tx)); + dev_dbg(port->dev, "%s: mapped %lu@%p to %pad\n", __func__, + UART_XMIT_SIZE, tport->xmit_buf, + &atmel_port->tx_phys); } /* Configure the slave DMA */ -- cgit v1.2.3-59-g8ed1b From 12bedddb67520d38274ae9163338a125c24732bb Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Fri, 5 Apr 2024 08:08:25 +0200 Subject: tty: atmel_serial: define macro for RX size It is repeated in the code and there is also a big warning by ATMEL_SERIAL_RINGSIZE. So define ATMEL_SERIAL_RX_SIZE and use it appropriatelly. The macro uses array_size() and kmalloc_array() is switched to kmalloc(). Signed-off-by: Jiri Slaby (SUSE) Cc: Richard Genoud Cc: Nicolas Ferre Cc: Alexandre Belloni Cc: Claudiu Beznea Cc: linux-arm-kernel@lists.infradead.org Link: https://lore.kernel.org/r/20240405060826.2521-15-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/atmel_serial.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index 69ec80ffc97b..5cde5077c429 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -96,7 +96,9 @@ struct atmel_uart_char { * can contain up to 1024 characters in PIO mode and up to 4096 characters in * DMA mode. */ -#define ATMEL_SERIAL_RINGSIZE 1024 +#define ATMEL_SERIAL_RINGSIZE 1024 +#define ATMEL_SERIAL_RX_SIZE array_size(sizeof(struct atmel_uart_char), \ + ATMEL_SERIAL_RINGSIZE) /* * at91: 6 USARTs and one DBGU port (SAM9260) @@ -1208,7 +1210,7 @@ static int atmel_prepare_rx_dma(struct uart_port *port) BUG_ON(!PAGE_ALIGNED(ring->buf)); sg_set_page(&atmel_port->sg_rx, virt_to_page(ring->buf), - sizeof(struct atmel_uart_char) * ATMEL_SERIAL_RINGSIZE, + ATMEL_SERIAL_RX_SIZE, offset_in_page(ring->buf)); nent = dma_map_sg(port->dev, &atmel_port->sg_rx, @@ -2947,9 +2949,7 @@ static int atmel_serial_probe(struct platform_device *pdev) if (!atmel_use_pdc_rx(&atmel_port->uart)) { ret = -ENOMEM; - data = kmalloc_array(ATMEL_SERIAL_RINGSIZE, - sizeof(struct atmel_uart_char), - GFP_KERNEL); + data = kmalloc(ATMEL_SERIAL_RX_SIZE, GFP_KERNEL); if (!data) goto err_clk_disable_unprepare; atmel_port->rx_ring.buf = data; -- cgit v1.2.3-59-g8ed1b From e51c3e1d236f8b0ea9e839f8f1f83aa31e0ce1e8 Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Fri, 5 Apr 2024 08:08:26 +0200 Subject: tty: atmel_serial: use single DMA mapping for RX dma_map_single() provides much easier interface for simple mappings as used for RX in atmel_serial. So switch to that, removing all the s-g unnecessary handling. Signed-off-by: Jiri Slaby (SUSE) Cc: Richard Genoud Cc: Nicolas Ferre Cc: Alexandre Belloni Cc: Claudiu Beznea Cc: linux-arm-kernel@lists.infradead.org Link: https://lore.kernel.org/r/20240405060826.2521-16-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/atmel_serial.c | 56 +++++++++++++++------------------------ 1 file changed, 22 insertions(+), 34 deletions(-) diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index 5cde5077c429..0a90964d6d10 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -135,7 +135,7 @@ struct atmel_uart_port { dma_cookie_t cookie_tx; dma_cookie_t cookie_rx; dma_addr_t tx_phys; - struct scatterlist sg_rx; + dma_addr_t rx_phys; struct tasklet_struct tasklet_rx; struct tasklet_struct tasklet_tx; atomic_t tasklet_shutdown; @@ -1088,8 +1088,8 @@ static void atmel_release_rx_dma(struct uart_port *port) if (chan) { dmaengine_terminate_all(chan); dma_release_channel(chan); - dma_unmap_sg(port->dev, &atmel_port->sg_rx, 1, - DMA_FROM_DEVICE); + dma_unmap_single(port->dev, atmel_port->rx_phys, + ATMEL_SERIAL_RX_SIZE, DMA_FROM_DEVICE); } atmel_port->desc_rx = NULL; @@ -1122,10 +1122,8 @@ static void atmel_rx_from_dma(struct uart_port *port) } /* CPU claims ownership of RX DMA buffer */ - dma_sync_sg_for_cpu(port->dev, - &atmel_port->sg_rx, - 1, - DMA_FROM_DEVICE); + dma_sync_single_for_cpu(port->dev, atmel_port->rx_phys, + ATMEL_SERIAL_RX_SIZE, DMA_FROM_DEVICE); /* * ring->head points to the end of data already written by the DMA. @@ -1134,8 +1132,8 @@ static void atmel_rx_from_dma(struct uart_port *port) * The current transfer size should not be larger than the dma buffer * length. */ - ring->head = sg_dma_len(&atmel_port->sg_rx) - state.residue; - BUG_ON(ring->head > sg_dma_len(&atmel_port->sg_rx)); + ring->head = ATMEL_SERIAL_RX_SIZE - state.residue; + BUG_ON(ring->head > ATMEL_SERIAL_RX_SIZE); /* * At this point ring->head may point to the first byte right after the * last byte of the dma buffer: @@ -1149,7 +1147,7 @@ static void atmel_rx_from_dma(struct uart_port *port) * tail to the end of the buffer then reset tail. */ if (ring->head < ring->tail) { - count = sg_dma_len(&atmel_port->sg_rx) - ring->tail; + count = ATMEL_SERIAL_RX_SIZE - ring->tail; tty_insert_flip_string(tport, ring->buf + ring->tail, count); ring->tail = 0; @@ -1162,17 +1160,15 @@ static void atmel_rx_from_dma(struct uart_port *port) tty_insert_flip_string(tport, ring->buf + ring->tail, count); /* Wrap ring->head if needed */ - if (ring->head >= sg_dma_len(&atmel_port->sg_rx)) + if (ring->head >= ATMEL_SERIAL_RX_SIZE) ring->head = 0; ring->tail = ring->head; port->icount.rx += count; } /* USART retreives ownership of RX DMA buffer */ - dma_sync_sg_for_device(port->dev, - &atmel_port->sg_rx, - 1, - DMA_FROM_DEVICE); + dma_sync_single_for_device(port->dev, atmel_port->rx_phys, + ATMEL_SERIAL_RX_SIZE, DMA_FROM_DEVICE); tty_flip_buffer_push(tport); @@ -1188,7 +1184,7 @@ static int atmel_prepare_rx_dma(struct uart_port *port) struct dma_slave_config config; struct circ_buf *ring; struct dma_chan *chan; - int ret, nent; + int ret; ring = &atmel_port->rx_ring; @@ -1205,26 +1201,18 @@ static int atmel_prepare_rx_dma(struct uart_port *port) dma_chan_name(atmel_port->chan_rx)); spin_lock_init(&atmel_port->lock_rx); - sg_init_table(&atmel_port->sg_rx, 1); /* UART circular rx buffer is an aligned page. */ BUG_ON(!PAGE_ALIGNED(ring->buf)); - sg_set_page(&atmel_port->sg_rx, - virt_to_page(ring->buf), - ATMEL_SERIAL_RX_SIZE, - offset_in_page(ring->buf)); - nent = dma_map_sg(port->dev, - &atmel_port->sg_rx, - 1, - DMA_FROM_DEVICE); - - if (!nent) { + atmel_port->rx_phys = dma_map_single(port->dev, ring->buf, + ATMEL_SERIAL_RX_SIZE, + DMA_FROM_DEVICE); + + if (dma_mapping_error(port->dev, atmel_port->rx_phys)) { dev_dbg(port->dev, "need to release resource of dma\n"); goto chan_err; } else { - dev_dbg(port->dev, "%s: mapped %d@%p to %pad\n", __func__, - sg_dma_len(&atmel_port->sg_rx), - ring->buf, - &sg_dma_address(&atmel_port->sg_rx)); + dev_dbg(port->dev, "%s: mapped %zu@%p to %pad\n", __func__, + ATMEL_SERIAL_RX_SIZE, ring->buf, &atmel_port->rx_phys); } /* Configure the slave DMA */ @@ -1245,9 +1233,9 @@ static int atmel_prepare_rx_dma(struct uart_port *port) * each one is half ring buffer size */ desc = dmaengine_prep_dma_cyclic(atmel_port->chan_rx, - sg_dma_address(&atmel_port->sg_rx), - sg_dma_len(&atmel_port->sg_rx), - sg_dma_len(&atmel_port->sg_rx)/2, + atmel_port->rx_phys, + ATMEL_SERIAL_RX_SIZE, + ATMEL_SERIAL_RX_SIZE / 2, DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT); if (!desc) { -- cgit v1.2.3-59-g8ed1b From f03e8c1060f86c23eb49bafee99d9fcbd1c1bd77 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Wed, 27 Mar 2024 12:59:35 +0200 Subject: printk: Save console options for add_preferred_console_match() Driver subsystems may need to translate the preferred console name to the character device name used. We already do some of this in console_setup() with a few hardcoded names, but that does not scale well. The console options are parsed early in console_setup(), and the consoles are added with __add_preferred_console(). At this point we don't know much about the character device names and device drivers getting probed. To allow driver subsystems to set up a preferred console, let's save the kernel command line console options. To add a preferred console from a driver subsystem with optional character device name translation, let's add a new function add_preferred_console_match(). This allows the serial core layer to support console=DEVNAME:0.0 style hardware based addressing in addition to the current console=ttyS0 style naming. And we can start moving console_setup() character device parsing to the driver subsystem specific code. We use a separate array from the console_cmdline array as the character device name and index may be unknown at the console_setup() time. And eventually there's no need to call __add_preferred_console() until the subsystem is ready to handle the console. Adding the console name in addition to the character device name, and a flag for an added console, could be added to the struct console_cmdline. And the console_cmdline array handling could be modified accordingly. But that complicates things compared saving the console options, and then adding the consoles when the subsystems handling the consoles are ready. Co-developed-by: Andy Shevchenko Signed-off-by: Tony Lindgren Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240327110021.59793-2-tony@atomide.com Signed-off-by: Greg Kroah-Hartman --- include/linux/printk.h | 3 + kernel/printk/Makefile | 2 +- kernel/printk/conopt.c | 146 ++++++++++++++++++++++++++++++++++++++++ kernel/printk/console_cmdline.h | 6 ++ kernel/printk/printk.c | 14 +++- 5 files changed, 167 insertions(+), 4 deletions(-) create mode 100644 kernel/printk/conopt.c diff --git a/include/linux/printk.h b/include/linux/printk.h index 955e31860095..5e038e782256 100644 --- a/include/linux/printk.h +++ b/include/linux/printk.h @@ -60,6 +60,9 @@ static inline const char *printk_skip_headers(const char *buffer) #define CONSOLE_LOGLEVEL_DEFAULT CONFIG_CONSOLE_LOGLEVEL_DEFAULT #define CONSOLE_LOGLEVEL_QUIET CONFIG_CONSOLE_LOGLEVEL_QUIET +int add_preferred_console_match(const char *match, const char *name, + const short idx); + extern int console_printk[]; #define console_loglevel (console_printk[0]) diff --git a/kernel/printk/Makefile b/kernel/printk/Makefile index 39a2b61c7232..040fe7d1eda2 100644 --- a/kernel/printk/Makefile +++ b/kernel/printk/Makefile @@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0-only -obj-y = printk.o +obj-y = printk.o conopt.o obj-$(CONFIG_PRINTK) += printk_safe.o nbcon.o obj-$(CONFIG_A11Y_BRAILLE_CONSOLE) += braille.o obj-$(CONFIG_PRINTK_INDEX) += index.o diff --git a/kernel/printk/conopt.c b/kernel/printk/conopt.c new file mode 100644 index 000000000000..9d507bac3657 --- /dev/null +++ b/kernel/printk/conopt.c @@ -0,0 +1,146 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Kernel command line console options for hardware based addressing + * + * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/ + * Author: Tony Lindgren + */ + +#include +#include +#include +#include + +#include + +#include "console_cmdline.h" + +/* + * Allow longer DEVNAME:0.0 style console naming such as abcd0000.serial:0.0 + * in addition to the legacy ttyS0 style naming. + */ +#define CONSOLE_NAME_MAX 32 + +#define CONSOLE_OPT_MAX 16 +#define CONSOLE_BRL_OPT_MAX 16 + +struct console_option { + char name[CONSOLE_NAME_MAX]; + char opt[CONSOLE_OPT_MAX]; + char brl_opt[CONSOLE_BRL_OPT_MAX]; + u8 has_brl_opt:1; +}; + +/* Updated only at console_setup() time, no locking needed */ +static struct console_option conopt[MAX_CMDLINECONSOLES]; + +/** + * console_opt_save - Saves kernel command line console option for driver use + * @str: Kernel command line console name and option + * @brl_opt: Braille console options + * + * Saves a kernel command line console option for driver subsystems to use for + * adding a preferred console during init. Called from console_setup() only. + * + * Return: 0 on success, negative error code on failure. + */ +int __init console_opt_save(const char *str, const char *brl_opt) +{ + struct console_option *con; + size_t namelen, optlen; + const char *opt; + int i; + + namelen = strcspn(str, ","); + if (namelen == 0 || namelen >= CONSOLE_NAME_MAX) + return -EINVAL; + + opt = str + namelen; + if (*opt == ',') + opt++; + + optlen = strlen(opt); + if (optlen >= CONSOLE_OPT_MAX) + return -EINVAL; + + for (i = 0; i < MAX_CMDLINECONSOLES; i++) { + con = &conopt[i]; + + if (con->name[0]) { + if (!strncmp(str, con->name, namelen)) + return 0; + continue; + } + + /* + * The name isn't terminated, only opt is. Empty opt is fine, + * but brl_opt can be either empty or NULL. For more info, see + * _braille_console_setup(). + */ + strscpy(con->name, str, namelen + 1); + strscpy(con->opt, opt, CONSOLE_OPT_MAX); + if (brl_opt) { + strscpy(con->brl_opt, brl_opt, CONSOLE_BRL_OPT_MAX); + con->has_brl_opt = 1; + } + + return 0; + } + + return -ENOMEM; +} + +static struct console_option *console_opt_find(const char *name) +{ + struct console_option *con; + int i; + + for (i = 0; i < MAX_CMDLINECONSOLES; i++) { + con = &conopt[i]; + if (!strcmp(name, con->name)) + return con; + } + + return NULL; +} + +/** + * add_preferred_console_match - Adds a preferred console if a match is found + * @match: Expected console on kernel command line, such as console=DEVNAME:0.0 + * @name: Name of the console character device to add such as ttyS + * @idx: Index for the console + * + * Allows driver subsystems to add a console after translating the command + * line name to the character device name used for the console. Options are + * added automatically based on the kernel command line. Duplicate preferred + * consoles are ignored by __add_preferred_console(). + * + * Return: 0 on success, negative error code on failure. + */ +int add_preferred_console_match(const char *match, const char *name, + const short idx) +{ + struct console_option *con; + char *brl_opt = NULL; + + if (!match || !strlen(match) || !name || !strlen(name) || + idx < 0) + return -EINVAL; + + con = console_opt_find(match); + if (!con) + return -ENOENT; + + /* + * See __add_preferred_console(). It checks for NULL brl_options to set + * the preferred_console flag. Empty brl_opt instead of NULL leads into + * the preferred_console flag not set, and CON_CONSDEV not being set, + * and the boot console won't get disabled at the end of console_setup(). + */ + if (con->has_brl_opt) + brl_opt = con->brl_opt; + + console_opt_add_preferred_console(name, idx, con->opt, brl_opt); + + return 0; +} diff --git a/kernel/printk/console_cmdline.h b/kernel/printk/console_cmdline.h index 3ca74ad391d6..a125e0235589 100644 --- a/kernel/printk/console_cmdline.h +++ b/kernel/printk/console_cmdline.h @@ -2,6 +2,12 @@ #ifndef _CONSOLE_CMDLINE_H #define _CONSOLE_CMDLINE_H +#define MAX_CMDLINECONSOLES 8 + +int console_opt_save(const char *str, const char *brl_opt); +int console_opt_add_preferred_console(const char *name, const short idx, + char *options, char *brl_options); + struct console_cmdline { char name[16]; /* Name of the driver */ diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index adf99c05adca..05919491c5a2 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -383,9 +383,6 @@ static int console_locked; /* * Array of consoles built from command line options (console=) */ - -#define MAX_CMDLINECONSOLES 8 - static struct console_cmdline console_cmdline[MAX_CMDLINECONSOLES]; static int preferred_console = -1; @@ -2503,6 +2500,10 @@ static int __init console_setup(char *str) if (_braille_console_setup(&str, &brl_options)) return 1; + /* Save the console for driver subsystem use */ + if (console_opt_save(str, brl_options)) + return 1; + /* * Decode str into name, index, options. */ @@ -2533,6 +2534,13 @@ static int __init console_setup(char *str) } __setup("console=", console_setup); +/* Only called from add_preferred_console_match() */ +int console_opt_add_preferred_console(const char *name, const short idx, + char *options, char *brl_options) +{ + return __add_preferred_console(name, idx, options, brl_options, true); +} + /** * add_preferred_console - add a device to the list of preferred consoles. * @name: device name -- cgit v1.2.3-59-g8ed1b From 8a831c584e6e80cf68f79893dc395c16cdf47dc8 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Wed, 27 Mar 2024 12:59:36 +0200 Subject: printk: Don't try to parse DEVNAME:0.0 console options Currently console_setup() tries to make a console index out of any digits passed in the kernel command line for console. In the DEVNAME:0.0 case, the name can contain a device IO address, so bail out on console names with a ':'. Signed-off-by: Tony Lindgren Link: https://lore.kernel.org/r/20240327110021.59793-3-tony@atomide.com Signed-off-by: Greg Kroah-Hartman --- kernel/printk/printk.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index 05919491c5a2..67937e5c6010 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -2504,6 +2504,10 @@ static int __init console_setup(char *str) if (console_opt_save(str, brl_options)) return 1; + /* Don't attempt to parse a DEVNAME:0.0 style console */ + if (strchr(str, ':')) + return 1; + /* * Decode str into name, index, options. */ -- cgit v1.2.3-59-g8ed1b From b73c9cbe4f1fc02645228aa575998dd54067f8ef Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Wed, 27 Mar 2024 12:59:37 +0200 Subject: printk: Flag register_console() if console is set on command line If add_preferred_console() is not called early in setup_console(), we can end up having register_console() call try_enable_default_console() before a console device has called add_preferred_console(). Let's set console_set_on_cmdline flag in console_setup() to prevent this from happening. Signed-off-by: Tony Lindgren Link: https://lore.kernel.org/r/20240327110021.59793-4-tony@atomide.com Signed-off-by: Greg Kroah-Hartman --- kernel/printk/printk.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index 67937e5c6010..1e3b21682547 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -2504,6 +2504,9 @@ static int __init console_setup(char *str) if (console_opt_save(str, brl_options)) return 1; + /* Flag register_console() to not call try_enable_default_console() */ + console_set_on_cmdline = 1; + /* Don't attempt to parse a DEVNAME:0.0 style console */ if (strchr(str, ':')) return 1; @@ -3507,7 +3510,7 @@ void register_console(struct console *newcon) * Note that a console with tty binding will have CON_CONSDEV * flag set and will be first in the list. */ - if (preferred_console < 0) { + if (preferred_console < 0 && !console_set_on_cmdline) { if (hlist_empty(&console_list) || !console_first()->device || console_first()->flags & CON_BOOT) { try_enable_default_console(newcon); -- cgit v1.2.3-59-g8ed1b From 787a1cabac01c99846070fcf702e53befaf89f79 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Wed, 27 Mar 2024 12:59:38 +0200 Subject: serial: core: Add support for DEVNAME:0.0 style naming for kernel console We can now add hardware based addressing for serial ports. Starting with commit 84a9582fd203 ("serial: core: Start managing serial controllers to enable runtime PM"), and all the related fixes to this commit, the serial core now knows to which serial port controller the ports are connected. The serial ports can be addressed with DEVNAME:0.0 style naming. The names are something like 00:04:0.0 for a serial port on qemu, and something like 2800000.serial:0.0 on platform device using systems like ARM64 for example. The DEVNAME is the unique serial port hardware controller device name, AKA the name for port->dev. The 0.0 are the serial core controller id and port id. Typically 0.0 are used for each controller and port instance unless the serial port hardware controller has multiple controllers or ports. Using DEVNAME:0.0 style naming actually solves two long term issues for addressing the serial ports: 1. According to Andy Shevchenko, using DEVNAME:0.0 style naming fixes an issue where depending on the BIOS settings, the kernel serial port ttyS instance number may change if HSUART is enabled 2. Device tree using architectures no longer necessarily need to specify aliases to find a specific serial port, and we can just allocate the ttyS instance numbers dynamically in whatever probe order To do this, let's match the hardware addressing style console name to the character device name used, and add a preferred console using the character device name. Note that when using console=DEVNAME:0.0 style kernel command line, the 8250 serial console gets enabled later compared to using console=ttyS naming for ISA ports. This is because the serial port DEVNAME to character device mapping is not known until the serial driver probe time. If used together with earlycon, this issue is avoided. Signed-off-by: Tony Lindgren Reviewed-by: Dhruva Gole Link: https://lore.kernel.org/r/20240327110021.59793-5-tony@atomide.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_base.h | 16 +++++++++ drivers/tty/serial/serial_base_bus.c | 66 ++++++++++++++++++++++++++++++++++++ drivers/tty/serial/serial_core.c | 4 +++ 3 files changed, 86 insertions(+) diff --git a/drivers/tty/serial/serial_base.h b/drivers/tty/serial/serial_base.h index c74c548f0db6..327a18b1813b 100644 --- a/drivers/tty/serial/serial_base.h +++ b/drivers/tty/serial/serial_base.h @@ -45,3 +45,19 @@ void serial_ctrl_unregister_port(struct uart_driver *drv, struct uart_port *port int serial_core_register_port(struct uart_driver *drv, struct uart_port *port); void serial_core_unregister_port(struct uart_driver *drv, struct uart_port *port); + +#ifdef CONFIG_SERIAL_CORE_CONSOLE + +int serial_base_add_preferred_console(struct uart_driver *drv, + struct uart_port *port); + +#else + +static inline +int serial_base_add_preferred_console(struct uart_driver *drv, + struct uart_port *port) +{ + return 0; +} + +#endif diff --git a/drivers/tty/serial/serial_base_bus.c b/drivers/tty/serial/serial_base_bus.c index 4df2a4b10445..4ef26a1b09b1 100644 --- a/drivers/tty/serial/serial_base_bus.c +++ b/drivers/tty/serial/serial_base_bus.c @@ -8,6 +8,7 @@ * The serial core bus manages the serial core controller instances. */ +#include #include #include #include @@ -204,6 +205,71 @@ void serial_base_port_device_remove(struct serial_port_device *port_dev) put_device(&port_dev->dev); } +#ifdef CONFIG_SERIAL_CORE_CONSOLE + +static int serial_base_add_one_prefcon(const char *match, const char *dev_name, + int port_id) +{ + int ret; + + ret = add_preferred_console_match(match, dev_name, port_id); + if (ret == -ENOENT) + return 0; + + return ret; +} + +static int serial_base_add_prefcon(const char *name, int idx) +{ + const char *char_match __free(kfree) = NULL; + + /* Handle the traditional character device name style console=ttyS0 */ + char_match = kasprintf(GFP_KERNEL, "%s%i", name, idx); + if (!char_match) + return -ENOMEM; + + return serial_base_add_one_prefcon(char_match, name, idx); +} + +/** + * serial_base_add_preferred_console - Adds a preferred console + * @drv: Serial port device driver + * @port: Serial port instance + * + * Tries to add a preferred console for a serial port if specified in the + * kernel command line. Supports both the traditional character device such + * as console=ttyS0, and a hardware addressing based console=DEVNAME:0.0 + * style name. + * + * Translates the kernel command line option using a hardware based addressing + * console=DEVNAME:0.0 to the serial port character device such as ttyS0. + * Cannot be called early for ISA ports, depends on struct device. + * + * Note that duplicates are ignored by add_preferred_console(). + * + * Return: 0 on success, negative error code on failure. + */ +int serial_base_add_preferred_console(struct uart_driver *drv, + struct uart_port *port) +{ + const char *port_match __free(kfree) = NULL; + int ret; + + ret = serial_base_add_prefcon(drv->dev_name, port->line); + if (ret) + return ret; + + port_match = kasprintf(GFP_KERNEL, "%s:%i.%i", dev_name(port->dev), + port->ctrl_id, port->port_id); + if (!port_match) + return -ENOMEM; + + /* Translate a hardware addressing style console=DEVNAME:0.0 */ + return serial_base_add_one_prefcon(port_match, drv->dev_name, port->line); +} + +#endif + static int serial_base_init(void) { int ret; diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 3c0931fba1c6..a78ded8c60b5 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -3393,6 +3393,10 @@ int serial_core_register_port(struct uart_driver *drv, struct uart_port *port) if (ret) goto err_unregister_ctrl_dev; + ret = serial_base_add_preferred_console(drv, port); + if (ret) + goto err_unregister_port_dev; + ret = serial_core_add_one_port(drv, port); if (ret) goto err_unregister_port_dev; -- cgit v1.2.3-59-g8ed1b From a0f32e2dd99867b164bfebcf36729c2a0d41b30b Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Wed, 27 Mar 2024 12:59:39 +0200 Subject: serial: core: Handle serial console options In order to start moving the serial console quirks out of console_setup(), let's add parsing for the quirks to the serial core layer. We can use serial_base_add_one_prefcon() to handle the quirks. Note that eventually we may want to set up driver specific console quirk handling for the serial port device drivers to use. But we need to figure out which driver(s) need to call the quirk. So for now, we just handle the sparc quirk directly. Signed-off-by: Tony Lindgren Link: https://lore.kernel.org/r/20240327110021.59793-6-tony@atomide.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_base_bus.c | 49 ++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/drivers/tty/serial/serial_base_bus.c b/drivers/tty/serial/serial_base_bus.c index 4ef26a1b09b1..1375be3315e6 100644 --- a/drivers/tty/serial/serial_base_bus.c +++ b/drivers/tty/serial/serial_base_bus.c @@ -219,9 +219,58 @@ static int serial_base_add_one_prefcon(const char *match, const char *dev_name, return ret; } +#ifdef __sparc__ + +/* Handle Sparc ttya and ttyb options as done in console_setup() */ +static int serial_base_add_sparc_console(const char *dev_name, int idx) +{ + const char *name; + + switch (idx) { + case 0: + name = "ttya"; + break; + case 1: + name = "ttyb"; + break; + default: + return 0; + } + + return serial_base_add_one_prefcon(name, dev_name, idx); +} + +#else + +static inline int serial_base_add_sparc_console(const char *dev_name, int idx) +{ + return 0; +} + +#endif + static int serial_base_add_prefcon(const char *name, int idx) { const char *char_match __free(kfree) = NULL; + const char *nmbr_match __free(kfree) = NULL; + int ret; + + /* Handle ttyS specific options */ + if (strstarts(name, "ttyS")) { + /* No name, just a number */ + nmbr_match = kasprintf(GFP_KERNEL, "%i", idx); + if (!nmbr_match) + return -ENODEV; + + ret = serial_base_add_one_prefcon(nmbr_match, name, idx); + if (ret) + return ret; + + /* Sparc ttya and ttyb */ + ret = serial_base_add_sparc_console(name, idx); + if (ret) + return ret; + } /* Handle the traditional character device name style console=ttyS0 */ char_match = kasprintf(GFP_KERNEL, "%s%i", name, idx); -- cgit v1.2.3-59-g8ed1b From a8b04cfe7dad84e65df5996e14b435fd356fe62c Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Wed, 27 Mar 2024 12:59:40 +0200 Subject: serial: 8250: Add preferred console in serial8250_isa_init_ports() Prepare 8250 ISA ports to drop kernel command line serial console handling from console_setup(). We need to set the preferred console in serial8250_isa_init_ports() to drop a dependency to setup_console() handling the ttyS related quirks. Otherwise when console_setup() handles the ttyS related options, console gets enabled only at driver probe time. Note that this mostly affects x86 as this happens based on define SERIAL_PORT_DFNS. Signed-off-by: Tony Lindgren Link: https://lore.kernel.org/r/20240327110021.59793-7-tony@atomide.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_core.c | 5 +++++ drivers/tty/serial/serial_base.h | 8 ++++++++ drivers/tty/serial/serial_base_bus.c | 21 +++++++++++++++++++++ 3 files changed, 34 insertions(+) diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index 3a1936b7f05f..43824a174a51 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -15,6 +15,7 @@ */ #include +#include #include #include #include @@ -41,6 +42,8 @@ #include +#include "../serial_base.h" /* For serial_base_add_isa_preferred_console() */ + #include "8250.h" /* @@ -564,6 +567,8 @@ static void __init serial8250_isa_init_ports(void) port->irqflags |= irqflag; if (serial8250_isa_config != NULL) serial8250_isa_config(i, &up->port, &up->capabilities); + + serial_base_add_isa_preferred_console(serial8250_reg.dev_name, i); } } diff --git a/drivers/tty/serial/serial_base.h b/drivers/tty/serial/serial_base.h index 327a18b1813b..39dab6bd4b76 100644 --- a/drivers/tty/serial/serial_base.h +++ b/drivers/tty/serial/serial_base.h @@ -51,6 +51,8 @@ void serial_core_unregister_port(struct uart_driver *drv, struct uart_port *port int serial_base_add_preferred_console(struct uart_driver *drv, struct uart_port *port); +int serial_base_add_isa_preferred_console(const char *name, int idx); + #else static inline @@ -60,4 +62,10 @@ int serial_base_add_preferred_console(struct uart_driver *drv, return 0; } +static inline +int serial_base_add_isa_preferred_console(const char *name, int idx) +{ + return 0; +} + #endif diff --git a/drivers/tty/serial/serial_base_bus.c b/drivers/tty/serial/serial_base_bus.c index 1375be3315e6..ae18871c0f36 100644 --- a/drivers/tty/serial/serial_base_bus.c +++ b/drivers/tty/serial/serial_base_bus.c @@ -317,6 +317,27 @@ int serial_base_add_preferred_console(struct uart_driver *drv, return serial_base_add_one_prefcon(port_match, drv->dev_name, port->line); } +#ifdef CONFIG_SERIAL_8250_CONSOLE + +/* + * Early ISA ports initialize the console before there is no struct device. + * This should be only called from serial8250_isa_init_preferred_console(), + * other callers are likely wrong and should rely on earlycon instead. + */ +int serial_base_add_isa_preferred_console(const char *name, int idx) +{ + return serial_base_add_prefcon(name, idx); +} + +#else + +int serial_base_add_isa_preferred_console(const char *name, int idx) +{ + return 0; +} + +#endif + #endif static int serial_base_init(void) -- cgit v1.2.3-59-g8ed1b From 5c3a766e9f057ee7a54b5d7addff7fab02676fea Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Wed, 27 Mar 2024 12:59:41 +0200 Subject: Documentation: kernel-parameters: Add DEVNAME:0.0 format for serial ports Document the console option for DEVNAME:0.0 style addressing for serial ports. Suggested-by: Sebastian Reichel Signed-off-by: Tony Lindgren Reviewed-by: Dhruva Gole Link: https://lore.kernel.org/r/20240327110021.59793-8-tony@atomide.com Signed-off-by: Greg Kroah-Hartman --- Documentation/admin-guide/kernel-parameters.txt | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 623fce7d5fcd..ecf94382981f 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -785,6 +785,25 @@ Documentation/networking/netconsole.rst for an alternative. + :.[,options] + Use the specified serial port on the serial core bus. + The addressing uses DEVNAME of the physical serial port + device, followed by the serial core controller instance, + and the serial port instance. The options are the same + as documented for the ttyS addressing above. + + The mapping of the serial ports to the tty instances + can be viewed with: + + $ ls -d /sys/bus/serial-base/devices/*:*.*/tty/* + /sys/bus/serial-base/devices/00:04:0.0/tty/ttyS0 + + In the above example, the console can be addressed with + console=00:04:0.0. Note that a console addressed this + way will only get added when the related device driver + is ready. The use of an earlycon parameter in addition to + the console may be desired for console output early on. + uart[8250],io,[,options] uart[8250],mmio,[,options] uart[8250],mmio16,[,options] -- cgit v1.2.3-59-g8ed1b From a80451572968279cbc1e2d921fd5c9a3136d3217 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 7 Mar 2024 13:40:48 +0200 Subject: serial: 8250_omap: Remove unused of_gpio.h of_gpio.h is deprecated and subject to remove. The driver doesn't use it, simply remove the unused header. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240307114048.3642642-1-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_omap.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index c07d924d5add..170639d12b2a 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include -- cgit v1.2.3-59-g8ed1b From 56de74b4d783f41c2e2b745555c662c4031b5d87 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 7 Mar 2024 13:42:43 +0200 Subject: serial: pic32_uart: Replace of_gpio.h by proper one of_gpio.h is deprecated and subject to remove. The driver doesn't use it directly, replace it with what is really being used. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240307114243.3642832-1-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/pic32_uart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/pic32_uart.c b/drivers/tty/serial/pic32_uart.c index f5af336a869b..261c8115a700 100644 --- a/drivers/tty/serial/pic32_uart.c +++ b/drivers/tty/serial/pic32_uart.c @@ -8,11 +8,11 @@ * Sorin-Andrei Pistirica */ +#include #include #include #include #include -#include #include #include #include -- cgit v1.2.3-59-g8ed1b From 4210022789f345642d56b8165757df6316560db7 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Thu, 7 Mar 2024 10:09:50 +0100 Subject: serial: sifive: Remove 0 from fu540-c000-uart0 binding. The driver is using "sifive,fu540-c000-uart0" as a binding. The device tree and documentation states "sifive,fu540-c000-uart" instead. This means the binding is not matched and not used. This did not cause any problems because the alternative binding, used in the device tree, "sifive,uart0" is not handling the hardware any different. Align the binding in the driver with the documentation. Signed-off-by: Sebastian Andrzej Siewior Reviewed-by: Conor Dooley Link: https://lore.kernel.org/r/20240307090950.eLELkuyK@linutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sifive.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/tty/serial/sifive.c b/drivers/tty/serial/sifive.c index 0670fd9f8496..cbfce65c9d22 100644 --- a/drivers/tty/serial/sifive.c +++ b/drivers/tty/serial/sifive.c @@ -761,7 +761,7 @@ static int __init early_sifive_serial_setup(struct earlycon_device *dev, } OF_EARLYCON_DECLARE(sifive, "sifive,uart0", early_sifive_serial_setup); -OF_EARLYCON_DECLARE(sifive, "sifive,fu540-c000-uart0", +OF_EARLYCON_DECLARE(sifive, "sifive,fu540-c000-uart", early_sifive_serial_setup); #endif /* CONFIG_SERIAL_EARLYCON */ @@ -1032,7 +1032,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(sifive_uart_pm_ops, sifive_serial_suspend, sifive_serial_resume); static const struct of_device_id sifive_serial_of_match[] = { - { .compatible = "sifive,fu540-c000-uart0" }, + { .compatible = "sifive,fu540-c000-uart" }, { .compatible = "sifive,uart0" }, {}, }; -- cgit v1.2.3-59-g8ed1b From b464199eaae81f51de8c7b07605643195645c663 Mon Sep 17 00:00:00 2001 From: Nghia Nguyen Date: Tue, 12 Mar 2024 10:00:55 +0100 Subject: dt-bindings: serial: renesas,scif: Document r8a779h0 bindings R-Car V4M (R8A779H0) SoC has the R-Car Gen4 compatible SCIF ports, so document the SoC specific bindings. Signed-off-by: Nghia Nguyen Signed-off-by: Geert Uytterhoeven Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/49b854603c2c3ed6b2edd441f1d55160e0453b70.1709741175.git.geert+renesas@glider.be Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/serial/renesas,scif.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/serial/renesas,scif.yaml b/Documentation/devicetree/bindings/serial/renesas,scif.yaml index 4610a5bd580c..f3a3eb2831e9 100644 --- a/Documentation/devicetree/bindings/serial/renesas,scif.yaml +++ b/Documentation/devicetree/bindings/serial/renesas,scif.yaml @@ -68,6 +68,7 @@ properties: - renesas,scif-r8a779a0 # R-Car V3U - renesas,scif-r8a779f0 # R-Car S4-8 - renesas,scif-r8a779g0 # R-Car V4H + - renesas,scif-r8a779h0 # R-Car V4M - const: renesas,rcar-gen4-scif # R-Car Gen4 - const: renesas,scif # generic SCIF compatible UART -- cgit v1.2.3-59-g8ed1b From d78cc0df9d2b49ed7f87b46c7041aab1bce2995f Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 15 Mar 2024 09:17:34 +0000 Subject: tty: hvc: Remove second semicolon There is a statement with two semicolons. Remove the second one, it is redundant. Signed-off-by: Colin Ian King Link: https://lore.kernel.org/r/20240315091734.2430416-1-colin.i.king@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/hvc/hvc_xen.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/hvc/hvc_xen.c b/drivers/tty/hvc/hvc_xen.c index 0e497501f8e3..388a71afd6ef 100644 --- a/drivers/tty/hvc/hvc_xen.c +++ b/drivers/tty/hvc/hvc_xen.c @@ -558,7 +558,7 @@ static void xencons_backend_changed(struct xenbus_device *dev, break; fallthrough; /* Missed the backend's CLOSING state */ case XenbusStateClosing: { - struct xencons_info *info = dev_get_drvdata(&dev->dev);; + struct xencons_info *info = dev_get_drvdata(&dev->dev); /* * Don't tear down the evtchn and grant ref before the other -- cgit v1.2.3-59-g8ed1b From da4e0ba419bb953fb8ae0aa4f85aef3febfbdf3e Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Mon, 18 Mar 2024 23:02:12 +0000 Subject: tty: n_gsm: replace deprecated strncpy with strscpy strncpy() is deprecated for use on NUL-terminated destination strings [1] and as such we should prefer more robust and less ambiguous string interfaces. We expect nc->if_name to be NUL-terminated based on existing manual NUL-byte assignments and checks: | nc.if_name[IFNAMSIZ-1] = '\0'; ... | if (nc->if_name[0] != '\0') Let's use the new 2-argument strscpy() since it guarantees NUL-termination on the destination buffer while correctly using the destination buffers size to bound the operation. Link: https://www.kernel.org/doc/html/latest/process/deprecated.html#strncpy-on-nul-terminated-strings [1] Link: https://manpages.debian.org/testing/linux-manual-4.8/strscpy.9.en.html [2] Link: https://github.com/KSPP/linux/issues/90 Cc: linux-hardening@vger.kernel.org Signed-off-by: Justin Stitt Reviewed-by: Kees Cook Link: https://lore.kernel.org/r/20240318-strncpy-drivers-tty-n_gsm-c-v1-1-da37a07c642e@google.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_gsm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 4036566febcb..f5b0d91d32a7 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -4010,7 +4010,7 @@ static int gsm_create_network(struct gsm_dlci *dlci, struct gsm_netconfig *nc) mux_net = netdev_priv(net); mux_net->dlci = dlci; kref_init(&mux_net->ref); - strncpy(nc->if_name, net->name, IFNAMSIZ); /* return net name */ + strscpy(nc->if_name, net->name); /* return net name */ /* reconfigure dlci for network */ dlci->prev_adaption = dlci->adaption; -- cgit v1.2.3-59-g8ed1b From 3bd85c6c97b2d232638594bf828de62083fe3389 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Mon, 11 Mar 2024 12:30:18 +0100 Subject: tty: vt: conmakehash: Don't mention the full path of the input in output MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This change strips $abs_srctree of the input file containing the character mapping table in the generated output. The motivation for this change is Yocto emitting a build warning WARNING: linux-lxatac-6.7-r0 do_package_qa: QA Issue: File /usr/src/debug/linux-lxatac/6.7-r0/drivers/tty/vt/consolemap_deftbl.c in package linux-lxatac-src contains reference to TMPDIR So this change brings us one step closer to make the build result reproducible independent of the build path. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20240311113017.483101-2-u.kleine-koenig@pengutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/conmakehash.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/tty/vt/conmakehash.c b/drivers/tty/vt/conmakehash.c index cddd789fe46e..dc2177fec715 100644 --- a/drivers/tty/vt/conmakehash.c +++ b/drivers/tty/vt/conmakehash.c @@ -76,7 +76,8 @@ static void addpair(int fp, int un) int main(int argc, char *argv[]) { FILE *ctbl; - char *tblname; + const char *tblname, *rel_tblname; + const char *abs_srctree; char buffer[65536]; int fontlen; int i, nuni, nent; @@ -101,6 +102,16 @@ int main(int argc, char *argv[]) } } + abs_srctree = getenv("abs_srctree"); + if (abs_srctree && !strncmp(abs_srctree, tblname, strlen(abs_srctree))) + { + rel_tblname = tblname + strlen(abs_srctree); + while (*rel_tblname == '/') + ++rel_tblname; + } + else + rel_tblname = tblname; + /* For now we assume the default font is always 256 characters. */ fontlen = 256; @@ -253,7 +264,7 @@ int main(int argc, char *argv[]) #include \n\ \n\ u8 dfont_unicount[%d] = \n\ -{\n\t", argv[1], fontlen); +{\n\t", rel_tblname, fontlen); for ( i = 0 ; i < fontlen ; i++ ) { -- cgit v1.2.3-59-g8ed1b From 9013517527b628019a9acecc7da4a13b0a62d851 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Fri, 29 Mar 2024 22:54:40 +0100 Subject: serial: ami: Mark driver struct with __refdata to prevent section mismatch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As described in the added code comment, a reference to .exit.text is ok for drivers registered via module_platform_driver_probe(). Make this explicit to prevent the following section mismatch warning WARNING: modpost: drivers/tty/amiserial: section mismatch in reference: amiga_serial_driver+0x8 (section: .data) -> amiga_serial_remove (section: .exit.text) that triggers on an allmodconfig W=1 build. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/043afcbc94ad90079301f3c7738136a7993a1748.1711748999.git.u.kleine-koenig@pengutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/tty/amiserial.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c index e27360652d9b..8c964da75f2d 100644 --- a/drivers/tty/amiserial.c +++ b/drivers/tty/amiserial.c @@ -1578,7 +1578,13 @@ static void __exit amiga_serial_remove(struct platform_device *pdev) free_irq(IRQ_AMIGA_RBF, state); } -static struct platform_driver amiga_serial_driver = { +/* + * amiga_serial_remove() lives in .exit.text. For drivers registered via + * module_platform_driver_probe() this is ok because they cannot get unbound at + * runtime. So mark the driver struct with __refdata to prevent modpost + * triggering a section mismatch warning. + */ +static struct platform_driver amiga_serial_driver __refdata = { .remove_new = __exit_p(amiga_serial_remove), .driver = { .name = "amiga-serial", -- cgit v1.2.3-59-g8ed1b From 7fb96133a76a14a970219bd2016c8fcc647010c4 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Fri, 29 Mar 2024 22:54:43 +0100 Subject: serial: pmac_zilog: Drop usage of platform_driver_probe() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are considerations to drop platform_driver_probe() as a concept that isn't relevant any more today. It comes with an added complexity that makes many users hold it wrong. (E.g. this driver should have marked the driver struct with __refdata to prevent the below mentioned false positive section mismatch warning.) This fixes a W=1 build warning: WARNING: modpost: drivers/tty/serial/pmac_zilog: section mismatch in reference: pmz_driver+0x8 (section: .data) -> pmz_detach (section: .exit.text) Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/5ea3174616abc9fa256f115b4fb175d289ac1754.1711748999.git.u.kleine-koenig@pengutronix.de Tested-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/pmac_zilog.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/tty/serial/pmac_zilog.c b/drivers/tty/serial/pmac_zilog.c index 63bc726273fd..b6909dcb137d 100644 --- a/drivers/tty/serial/pmac_zilog.c +++ b/drivers/tty/serial/pmac_zilog.c @@ -1695,7 +1695,7 @@ static void pmz_dispose_port(struct uart_pmac_port *uap) memset(uap, 0, sizeof(struct uart_pmac_port)); } -static int __init pmz_attach(struct platform_device *pdev) +static int pmz_attach(struct platform_device *pdev) { struct uart_pmac_port *uap; int i; @@ -1714,7 +1714,7 @@ static int __init pmz_attach(struct platform_device *pdev) return uart_add_one_port(&pmz_uart_reg, &uap->port); } -static void __exit pmz_detach(struct platform_device *pdev) +static void pmz_detach(struct platform_device *pdev) { struct uart_pmac_port *uap = platform_get_drvdata(pdev); @@ -1789,7 +1789,8 @@ static struct macio_driver pmz_driver = { #else static struct platform_driver pmz_driver = { - .remove_new = __exit_p(pmz_detach), + .probe = pmz_attach, + .remove_new = pmz_detach, .driver = { .name = "scc", }, @@ -1837,7 +1838,7 @@ static int __init init_pmz(void) #ifdef CONFIG_PPC_PMAC return macio_register_driver(&pmz_driver); #else - return platform_driver_probe(&pmz_driver, pmz_attach); + return platform_driver_register(&pmz_driver); #endif } -- cgit v1.2.3-59-g8ed1b From 8c278ade67bdcd9882d32547015a091fb16132b1 Mon Sep 17 00:00:00 2001 From: Kanak Shilledar Date: Fri, 5 Apr 2024 13:32:32 +0530 Subject: dt-bindings: serial: actions,owl-uart: convert to dtschema Convert the Actions Semi Owl UART to newer DT schema. Created DT schema based on the .txt file which had `compatible`, `reg` and `interrupts` as the required properties. This binding is used by Actions S500, S700 and S900 SoC. S700 and S900 use the same UART compatible string. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Kanak Shilledar Link: https://lore.kernel.org/r/20240405080235.11563-1-kanakshilledar@gmail.com Signed-off-by: Greg Kroah-Hartman --- .../bindings/serial/actions,owl-uart.txt | 16 -------- .../bindings/serial/actions,owl-uart.yaml | 48 ++++++++++++++++++++++ 2 files changed, 48 insertions(+), 16 deletions(-) delete mode 100644 Documentation/devicetree/bindings/serial/actions,owl-uart.txt create mode 100644 Documentation/devicetree/bindings/serial/actions,owl-uart.yaml diff --git a/Documentation/devicetree/bindings/serial/actions,owl-uart.txt b/Documentation/devicetree/bindings/serial/actions,owl-uart.txt deleted file mode 100644 index aa873eada02d..000000000000 --- a/Documentation/devicetree/bindings/serial/actions,owl-uart.txt +++ /dev/null @@ -1,16 +0,0 @@ -Actions Semi Owl UART - -Required properties: -- compatible : "actions,s500-uart", "actions,owl-uart" for S500 - "actions,s900-uart", "actions,owl-uart" for S900 -- reg : Offset and length of the register set for the device. -- interrupts : Should contain UART interrupt. - - -Example: - - uart3: serial@b0126000 { - compatible = "actions,s500-uart", "actions,owl-uart"; - reg = <0xb0126000 0x1000>; - interrupts = ; - }; diff --git a/Documentation/devicetree/bindings/serial/actions,owl-uart.yaml b/Documentation/devicetree/bindings/serial/actions,owl-uart.yaml new file mode 100644 index 000000000000..ab1c4514ae93 --- /dev/null +++ b/Documentation/devicetree/bindings/serial/actions,owl-uart.yaml @@ -0,0 +1,48 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/serial/actions,owl-uart.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Actions Semi Owl UART + +maintainers: + - Kanak Shilledar + +allOf: + - $ref: serial.yaml + +properties: + compatible: + items: + - enum: + - actions,s500-uart + - actions,s900-uart + - const: actions,owl-uart + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + maxItems: 1 + +required: + - compatible + - reg + - interrupts + +unevaluatedProperties: false + +examples: + - | + #include + #include + uart0: serial@b0126000 { + compatible = "actions,s500-uart", "actions,owl-uart"; + reg = <0xb0126000 0x1000>; + clocks = <&cmu CLK_UART0>; + interrupts = ; + }; -- cgit v1.2.3-59-g8ed1b From 32f6ec282fb0ddb45da1a19145ef9eeef088968d Mon Sep 17 00:00:00 2001 From: Bastien Curutchet Date: Fri, 5 Apr 2024 14:05:52 +0200 Subject: serial: 8250_of: Add clock_notifier The UART's input clock rate can change at runtime but this is not handled by the driver. Add a clock_notifier callback that updates the divisors when the input clock is updated. The serial8250_update_uartclk() is used to do so. PRE_RATE_CHANGE and ABORT_RATE_CHANGE notifications are ignored, only the POST_RATE_CHANGE is used. Not using PRE_RATE_CHANGE notification can result in a few corrupted bytes during frequency transitions but, IMHO, it can be acceptable in many use cases. It has been tested on a DAVINCI/OMAP-L138 processor. Signed-off-by: Bastien Curutchet Reviewed-by: Herve Codina Link: https://lore.kernel.org/r/20240405120552.35991-1-bastien.curutchet@bootlin.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_of.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/drivers/tty/serial/8250/8250_of.c b/drivers/tty/serial/8250/8250_of.c index 5d1dd992d8fb..e14f47ef1172 100644 --- a/drivers/tty/serial/8250/8250_of.c +++ b/drivers/tty/serial/8250/8250_of.c @@ -18,6 +18,7 @@ #include #include #include +#include #include "8250.h" @@ -26,6 +27,7 @@ struct of_serial_info { struct reset_control *rst; int type; int line; + struct notifier_block clk_notifier; }; /* Nuvoton NPCM timeout register */ @@ -58,6 +60,26 @@ static int npcm_setup(struct uart_port *port) return 0; } +static inline struct of_serial_info *clk_nb_to_info(struct notifier_block *nb) +{ + return container_of(nb, struct of_serial_info, clk_notifier); +} + +static int of_platform_serial_clk_notifier_cb(struct notifier_block *nb, unsigned long event, + void *data) +{ + struct of_serial_info *info = clk_nb_to_info(nb); + struct uart_8250_port *port8250 = serial8250_get_port(info->line); + struct clk_notifier_data *ndata = data; + + if (event == POST_RATE_CHANGE) { + serial8250_update_uartclk(&port8250->port, ndata->new_rate); + return NOTIFY_OK; + } + + return NOTIFY_DONE; +} + /* * Fill a struct uart_port for a given device node */ @@ -218,7 +240,19 @@ static int of_platform_serial_probe(struct platform_device *ofdev) info->type = port_type; info->line = ret; platform_set_drvdata(ofdev, info); + + if (info->clk) { + info->clk_notifier.notifier_call = of_platform_serial_clk_notifier_cb; + ret = clk_notifier_register(info->clk, &info->clk_notifier); + if (ret) { + dev_err_probe(port8250.port.dev, ret, "Failed to set the clock notifier\n"); + goto err_unregister; + } + } + return 0; +err_unregister: + serial8250_unregister_port(info->line); err_dispose: pm_runtime_put_sync(&ofdev->dev); pm_runtime_disable(&ofdev->dev); @@ -234,6 +268,9 @@ static void of_platform_serial_remove(struct platform_device *ofdev) { struct of_serial_info *info = platform_get_drvdata(ofdev); + if (info->clk) + clk_notifier_unregister(info->clk, &info->clk_notifier); + serial8250_unregister_port(info->line); reset_control_assert(info->rst); -- cgit v1.2.3-59-g8ed1b From 77ab53371a2066fdf9b895246505f5ef5a4b5d47 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 2 Apr 2024 22:50:28 +0300 Subject: serial: max3100: Lock port->lock when calling uart_handle_cts_change() uart_handle_cts_change() has to be called with port lock taken, Since we run it in a separate work, the lock may not be taken at the time of running. Make sure that it's taken by explicitly doing that. Without it we got a splat: WARNING: CPU: 0 PID: 10 at drivers/tty/serial/serial_core.c:3491 uart_handle_cts_change+0xa6/0xb0 ... Workqueue: max3100-0 max3100_work [max3100] RIP: 0010:uart_handle_cts_change+0xa6/0xb0 ... max3100_handlerx+0xc5/0x110 [max3100] max3100_work+0x12a/0x340 [max3100] Fixes: 7831d56b0a35 ("tty: MAX3100") Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240402195306.269276-2-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/max3100.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/tty/serial/max3100.c b/drivers/tty/serial/max3100.c index b83eee37c17d..53dde3391abf 100644 --- a/drivers/tty/serial/max3100.c +++ b/drivers/tty/serial/max3100.c @@ -213,7 +213,7 @@ static int max3100_sr(struct max3100_port *s, u16 tx, u16 *rx) return 0; } -static int max3100_handlerx(struct max3100_port *s, u16 rx) +static int max3100_handlerx_unlocked(struct max3100_port *s, u16 rx) { unsigned int status = 0; int ret = 0, cts; @@ -254,6 +254,17 @@ static int max3100_handlerx(struct max3100_port *s, u16 rx) return ret; } +static int max3100_handlerx(struct max3100_port *s, u16 rx) +{ + unsigned long flags; + int ret; + + uart_port_lock_irqsave(&s->port, &flags); + ret = max3100_handlerx_unlocked(s, rx); + uart_port_unlock_irqrestore(&s->port, flags); + return ret; +} + static void max3100_work(struct work_struct *w) { struct max3100_port *s = container_of(w, struct max3100_port, work); -- cgit v1.2.3-59-g8ed1b From 712a1fcb38dc7cac6da63ee79a88708fbf9c45ec Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 2 Apr 2024 22:50:29 +0300 Subject: serial: max3100: Update uart_driver_registered on driver removal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The removal of the last MAX3100 device triggers the removal of the driver. However, code doesn't update the respective global variable and after insmod — rmmod — insmod cycle the kernel oopses: max3100 spi-PRP0001:01: max3100_probe: adding port 0 BUG: kernel NULL pointer dereference, address: 0000000000000408 ... RIP: 0010:serial_core_register_port+0xa0/0x840 ... max3100_probe+0x1b6/0x280 [max3100] spi_probe+0x8d/0xb0 Update the actual state so next time UART driver will be registered again. Hugo also noticed, that the error path in the probe also affected by having the variable set, and not cleared. Instead of clearing it move the assignment after the successfull uart_register_driver() call. Fixes: 7831d56b0a35 ("tty: MAX3100") Signed-off-by: Andy Shevchenko Reviewed-by: Hugo Villeneuve Link: https://lore.kernel.org/r/20240402195306.269276-3-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/max3100.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/tty/serial/max3100.c b/drivers/tty/serial/max3100.c index 53dde3391abf..14873576e52d 100644 --- a/drivers/tty/serial/max3100.c +++ b/drivers/tty/serial/max3100.c @@ -749,13 +749,14 @@ static int max3100_probe(struct spi_device *spi) mutex_lock(&max3100s_lock); if (!uart_driver_registered) { - uart_driver_registered = 1; retval = uart_register_driver(&max3100_uart_driver); if (retval) { printk(KERN_ERR "Couldn't register max3100 uart driver\n"); mutex_unlock(&max3100s_lock); return retval; } + + uart_driver_registered = 1; } for (i = 0; i < MAX_MAX3100; i++) @@ -841,6 +842,7 @@ static void max3100_remove(struct spi_device *spi) } pr_debug("removing max3100 driver\n"); uart_unregister_driver(&max3100_uart_driver); + uart_driver_registered = 0; mutex_unlock(&max3100s_lock); } -- cgit v1.2.3-59-g8ed1b From e60955dbecb97f080848a57524827e2db29c70fd Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 2 Apr 2024 22:50:30 +0300 Subject: serial: max3100: Fix bitwise types Sparse is not happy about misuse of bitwise types: .../max3100.c:194:13: warning: incorrect type in assignment (different base types) .../max3100.c:194:13: expected unsigned short [addressable] [usertype] etx .../max3100.c:194:13: got restricted __be16 [usertype] .../max3100.c:202:15: warning: cast to restricted __be16 Fix this by choosing proper types for the respective variables. Fixes: 7831d56b0a35 ("tty: MAX3100") Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240402195306.269276-4-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/max3100.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/tty/serial/max3100.c b/drivers/tty/serial/max3100.c index 14873576e52d..8c6eaf908bce 100644 --- a/drivers/tty/serial/max3100.c +++ b/drivers/tty/serial/max3100.c @@ -45,6 +45,9 @@ #include #include #include +#include + +#include #include @@ -191,7 +194,7 @@ static void max3100_timeout(struct timer_list *t) static int max3100_sr(struct max3100_port *s, u16 tx, u16 *rx) { struct spi_message message; - u16 etx, erx; + __be16 etx, erx; int status; struct spi_transfer tran = { .tx_buf = &etx, -- cgit v1.2.3-59-g8ed1b From 0487724912abc14eb0e95c352a29e6691a733631 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 2 Apr 2024 22:50:31 +0300 Subject: serial: max3100: Make struct plat_max3100 local There is no user of the struct plat_max3100 outside the driver. Inline its contents into the driver. While at it, drop outdated example in the comment. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240402195306.269276-5-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/max3100.c | 38 ++++++++++++++++----------------- include/linux/serial_max3100.h | 48 ------------------------------------------ 2 files changed, 18 insertions(+), 68 deletions(-) delete mode 100644 include/linux/serial_max3100.h diff --git a/drivers/tty/serial/max3100.c b/drivers/tty/serial/max3100.c index 8c6eaf908bce..0e30201e9689 100644 --- a/drivers/tty/serial/max3100.c +++ b/drivers/tty/serial/max3100.c @@ -1,6 +1,5 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * * Copyright (C) 2008 Christian Pellegrin * * Notes: the MAX3100 doesn't provide an interrupt on CTS so we have @@ -8,24 +7,6 @@ * writing conf clears FIFO buffer and we cannot have this interrupt * always asking us for attention. * - * Example platform data: - - static struct plat_max3100 max3100_plat_data = { - .loopback = 0, - .crystal = 0, - .poll_time = 100, - }; - - static struct spi_board_info spi_board_info[] = { - { - .modalias = "max3100", - .platform_data = &max3100_plat_data, - .irq = IRQ_EINT12, - .max_speed_hz = 5*1000*1000, - .chip_select = 0, - }, - }; - * The initial minor number is 209 in the low-density serial port: * mknod /dev/ttyMAX0 c 204 209 */ @@ -49,7 +30,24 @@ #include -#include +/** + * struct plat_max3100 - MAX3100 SPI UART platform data + * @loopback: force MAX3100 in loopback + * @crystal: 1 for 3.6864 Mhz, 0 for 1.8432 + * @max3100_hw_suspend: MAX3100 has a shutdown pin. This is a hook + * called on suspend and resume to activate it. + * @poll_time: poll time for CTS signal in ms, 0 disables (so no hw + * flow ctrl is possible but you have less CPU usage) + * + * You should use this structure in your machine description to specify + * how the MAX3100 is connected. + */ +struct plat_max3100 { + int loopback; + int crystal; + void (*max3100_hw_suspend) (int suspend); + int poll_time; +}; #define MAX3100_C (1<<14) #define MAX3100_D (0<<14) diff --git a/include/linux/serial_max3100.h b/include/linux/serial_max3100.h deleted file mode 100644 index befd55c08a7c..000000000000 --- a/include/linux/serial_max3100.h +++ /dev/null @@ -1,48 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * - * Copyright (C) 2007 Christian Pellegrin - */ - - -#ifndef _LINUX_SERIAL_MAX3100_H -#define _LINUX_SERIAL_MAX3100_H 1 - - -/** - * struct plat_max3100 - MAX3100 SPI UART platform data - * @loopback: force MAX3100 in loopback - * @crystal: 1 for 3.6864 Mhz, 0 for 1.8432 - * @max3100_hw_suspend: MAX3100 has a shutdown pin. This is a hook - * called on suspend and resume to activate it. - * @poll_time: poll time for CTS signal in ms, 0 disables (so no hw - * flow ctrl is possible but you have less CPU usage) - * - * You should use this structure in your machine description to specify - * how the MAX3100 is connected. Example: - * - * static struct plat_max3100 max3100_plat_data = { - * .loopback = 0, - * .crystal = 0, - * .poll_time = 100, - * }; - * - * static struct spi_board_info spi_board_info[] = { - * { - * .modalias = "max3100", - * .platform_data = &max3100_plat_data, - * .irq = IRQ_EINT12, - * .max_speed_hz = 5*1000*1000, - * .chip_select = 0, - * }, - * }; - * - **/ -struct plat_max3100 { - int loopback; - int crystal; - void (*max3100_hw_suspend) (int suspend); - int poll_time; -}; - -#endif -- cgit v1.2.3-59-g8ed1b From 3c37ac45718ebb25203314c908dc4b5c5b9b2119 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 2 Apr 2024 22:50:32 +0300 Subject: serial: max3100: Remove custom HW shutdown support While there is no user of this callback in the kernel, it also breaks the relationship in the driver model. The correct implementation should be done via GPIO or regulator framework. Remove custom HW shutdown support for good and, if needed, we will implement it correctly later on. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240402195306.269276-6-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/max3100.c | 42 +++++++----------------------------------- 1 file changed, 7 insertions(+), 35 deletions(-) diff --git a/drivers/tty/serial/max3100.c b/drivers/tty/serial/max3100.c index 0e30201e9689..ad6b692c7360 100644 --- a/drivers/tty/serial/max3100.c +++ b/drivers/tty/serial/max3100.c @@ -34,8 +34,6 @@ * struct plat_max3100 - MAX3100 SPI UART platform data * @loopback: force MAX3100 in loopback * @crystal: 1 for 3.6864 Mhz, 0 for 1.8432 - * @max3100_hw_suspend: MAX3100 has a shutdown pin. This is a hook - * called on suspend and resume to activate it. * @poll_time: poll time for CTS signal in ms, 0 disables (so no hw * flow ctrl is possible but you have less CPU usage) * @@ -45,7 +43,6 @@ struct plat_max3100 { int loopback; int crystal; - void (*max3100_hw_suspend) (int suspend); int poll_time; }; @@ -125,9 +122,6 @@ struct max3100_port { /* need to know we are suspending to avoid deadlock on workqueue */ int suspending; - /* hook for suspending MAX3100 via dedicated pin */ - void (*max3100_hw_suspend) (int suspend); - /* poll time (in ms) for ctrl lines */ int poll_time; /* and its timer */ @@ -553,6 +547,7 @@ static void max3100_shutdown(struct uart_port *port) struct max3100_port *s = container_of(port, struct max3100_port, port); + u16 rx; dev_dbg(&s->spi->dev, "%s\n", __func__); @@ -572,14 +567,7 @@ static void max3100_shutdown(struct uart_port *port) free_irq(s->irq, s); /* set shutdown mode to save power */ - if (s->max3100_hw_suspend) - s->max3100_hw_suspend(1); - else { - u16 tx, rx; - - tx = MAX3100_WC | MAX3100_SHDN; - max3100_sr(s, tx, &rx); - } + max3100_sr(s, MAX3100_WC | MAX3100_SHDN, &rx); } static int max3100_startup(struct uart_port *port) @@ -625,8 +613,6 @@ static int max3100_startup(struct uart_port *port) max3100_sr(s, tx, &rx); } - if (s->max3100_hw_suspend) - s->max3100_hw_suspend(0); s->conf_commit = 1; max3100_dowork(s); /* wait for clock to settle */ @@ -745,7 +731,7 @@ static int max3100_probe(struct spi_device *spi) { int i, retval; struct plat_max3100 *pdata; - u16 tx, rx; + u16 rx; mutex_lock(&max3100s_lock); @@ -786,7 +772,6 @@ static int max3100_probe(struct spi_device *spi) max3100s[i]->poll_time = msecs_to_jiffies(pdata->poll_time); if (pdata->poll_time > 0 && max3100s[i]->poll_time == 0) max3100s[i]->poll_time = 1; - max3100s[i]->max3100_hw_suspend = pdata->max3100_hw_suspend; max3100s[i]->minor = i; timer_setup(&max3100s[i]->timer, max3100_timeout, 0); @@ -806,12 +791,7 @@ static int max3100_probe(struct spi_device *spi) i, retval); /* set shutdown mode to save power. Will be woken-up on open */ - if (max3100s[i]->max3100_hw_suspend) - max3100s[i]->max3100_hw_suspend(1); - else { - tx = MAX3100_WC | MAX3100_SHDN; - max3100_sr(max3100s[i], tx, &rx); - } + max3100_sr(max3100s[i], MAX3100_WC | MAX3100_SHDN, &rx); mutex_unlock(&max3100s_lock); return 0; } @@ -853,6 +833,7 @@ static void max3100_remove(struct spi_device *spi) static int max3100_suspend(struct device *dev) { struct max3100_port *s = dev_get_drvdata(dev); + u16 rx; dev_dbg(&s->spi->dev, "%s\n", __func__); @@ -861,15 +842,8 @@ static int max3100_suspend(struct device *dev) s->suspending = 1; uart_suspend_port(&max3100_uart_driver, &s->port); - if (s->max3100_hw_suspend) - s->max3100_hw_suspend(1); - else { - /* no HW suspend, so do SW one */ - u16 tx, rx; - - tx = MAX3100_WC | MAX3100_SHDN; - max3100_sr(s, tx, &rx); - } + /* no HW suspend, so do SW one */ + max3100_sr(s, MAX3100_WC | MAX3100_SHDN, &rx); return 0; } @@ -879,8 +853,6 @@ static int max3100_resume(struct device *dev) dev_dbg(&s->spi->dev, "%s\n", __func__); - if (s->max3100_hw_suspend) - s->max3100_hw_suspend(0); uart_resume_port(&max3100_uart_driver, &s->port); s->suspending = 0; -- cgit v1.2.3-59-g8ed1b From e1cb4fa90fb8edbb7f47aca2328fc6425bcc582f Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 2 Apr 2024 22:50:33 +0300 Subject: serial: max3100: Replace custom polling timeout with standard one Serial core provides a standard timeout for polling modem state. Use it instead of a custom approach. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240402195306.269276-7-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/max3100.c | 25 +++++-------------------- 1 file changed, 5 insertions(+), 20 deletions(-) diff --git a/drivers/tty/serial/max3100.c b/drivers/tty/serial/max3100.c index ad6b692c7360..285675c3a848 100644 --- a/drivers/tty/serial/max3100.c +++ b/drivers/tty/serial/max3100.c @@ -34,8 +34,6 @@ * struct plat_max3100 - MAX3100 SPI UART platform data * @loopback: force MAX3100 in loopback * @crystal: 1 for 3.6864 Mhz, 0 for 1.8432 - * @poll_time: poll time for CTS signal in ms, 0 disables (so no hw - * flow ctrl is possible but you have less CPU usage) * * You should use this structure in your machine description to specify * how the MAX3100 is connected. @@ -43,7 +41,6 @@ struct plat_max3100 { int loopback; int crystal; - int poll_time; }; #define MAX3100_C (1<<14) @@ -122,9 +119,6 @@ struct max3100_port { /* need to know we are suspending to avoid deadlock on workqueue */ int suspending; - /* poll time (in ms) for ctrl lines */ - int poll_time; - /* and its timer */ struct timer_list timer; }; @@ -177,10 +171,8 @@ static void max3100_timeout(struct timer_list *t) { struct max3100_port *s = from_timer(s, t, timer); - if (s->port.state) { - max3100_dowork(s); - mod_timer(&s->timer, jiffies + s->poll_time); - } + max3100_dowork(s); + mod_timer(&s->timer, jiffies + uart_poll_timeout(&s->port)); } static int max3100_sr(struct max3100_port *s, u16 tx, u16 *rx) @@ -342,8 +334,7 @@ static void max3100_enable_ms(struct uart_port *port) struct max3100_port, port); - if (s->poll_time > 0) - mod_timer(&s->timer, jiffies); + mod_timer(&s->timer, jiffies); dev_dbg(&s->spi->dev, "%s\n", __func__); } @@ -526,9 +517,7 @@ max3100_set_termios(struct uart_port *port, struct ktermios *termios, MAX3100_STATUS_PE | MAX3100_STATUS_FE | MAX3100_STATUS_OE; - if (s->poll_time > 0) - del_timer_sync(&s->timer); - + del_timer_sync(&s->timer); uart_update_timeout(port, termios->c_cflag, baud); spin_lock(&s->conf_lock); @@ -556,8 +545,7 @@ static void max3100_shutdown(struct uart_port *port) s->force_end_work = 1; - if (s->poll_time > 0) - del_timer_sync(&s->timer); + del_timer_sync(&s->timer); if (s->workqueue) { destroy_workqueue(s->workqueue); @@ -769,9 +757,6 @@ static int max3100_probe(struct spi_device *spi) pdata = dev_get_platdata(&spi->dev); max3100s[i]->crystal = pdata->crystal; max3100s[i]->loopback = pdata->loopback; - max3100s[i]->poll_time = msecs_to_jiffies(pdata->poll_time); - if (pdata->poll_time > 0 && max3100s[i]->poll_time == 0) - max3100s[i]->poll_time = 1; max3100s[i]->minor = i; timer_setup(&max3100s[i]->timer, max3100_timeout, 0); -- cgit v1.2.3-59-g8ed1b From 80949ca0f3a89bc046b6a84ec2fcc2b3a4241a93 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 2 Apr 2024 22:50:41 +0300 Subject: serial: max3100: Remove unneeded forward declaration There is no code using max3100_work() before the definition of it. Remove unneeded forward declaration. While at it, move max3100_dowork() and max3100_timeout() down in the code to be after actual max3100_work() implementation. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240402195306.269276-15-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/max3100.c | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/drivers/tty/serial/max3100.c b/drivers/tty/serial/max3100.c index 285675c3a848..75e96ff74571 100644 --- a/drivers/tty/serial/max3100.c +++ b/drivers/tty/serial/max3100.c @@ -159,22 +159,6 @@ static void max3100_calc_parity(struct max3100_port *s, u16 *c) *c |= max3100_do_parity(s, *c) << 8; } -static void max3100_work(struct work_struct *w); - -static void max3100_dowork(struct max3100_port *s) -{ - if (!s->force_end_work && !freezing(current) && !s->suspending) - queue_work(s->workqueue, &s->work); -} - -static void max3100_timeout(struct timer_list *t) -{ - struct max3100_port *s = from_timer(s, t, timer); - - max3100_dowork(s); - mod_timer(&s->timer, jiffies + uart_poll_timeout(&s->port)); -} - static int max3100_sr(struct max3100_port *s, u16 tx, u16 *rx) { struct spi_message message; @@ -318,6 +302,20 @@ static void max3100_work(struct work_struct *w) tty_flip_buffer_push(&s->port.state->port); } +static void max3100_dowork(struct max3100_port *s) +{ + if (!s->force_end_work && !freezing(current) && !s->suspending) + queue_work(s->workqueue, &s->work); +} + +static void max3100_timeout(struct timer_list *t) +{ + struct max3100_port *s = from_timer(s, t, timer); + + max3100_dowork(s); + mod_timer(&s->timer, jiffies + uart_poll_timeout(&s->port)); +} + static irqreturn_t max3100_irq(int irqno, void *dev_id) { struct max3100_port *s = dev_id; -- cgit v1.2.3-59-g8ed1b From 0867a9805549632969fbb996c50ba8adb1bc38bf Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 2 Apr 2024 22:50:43 +0300 Subject: serial: max3100: Update Kconfig entry The driver actually supports more than one chip. Update Kconfig entry to list the supported chips. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240402195306.269276-17-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/Kconfig | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index ffcf4882b25f..5c80505cdf41 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -307,11 +307,14 @@ config SERIAL_TEGRA_TCU_CONSOLE If unsure, say Y. config SERIAL_MAX3100 - tristate "MAX3100 support" + tristate "MAX3100/3110/3111/3222 support" depends on SPI select SERIAL_CORE help - MAX3100 chip support + This selects support for an advanced UART from Maxim. + Supported ICs are MAX3100, MAX3110, MAX3111, MAX3222. + + Say Y here if you want to support these ICs. config SERIAL_MAX310X tristate "MAX310X support" -- cgit v1.2.3-59-g8ed1b From eebab7e3eb4bb906a8ebc3b70d28059ff1d9271c Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Thu, 7 Mar 2024 13:20:06 +1100 Subject: PCI/DOE: Support discovery version 2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PCIe r6.1, sec 6.30.1.1 defines a "DOE Discovery Version" field in the DOE Discovery Request Data Object Contents (3rd DW) as: 15:8 DOE Discovery Version – must be 02h if the Capability Version in the Data Object Exchange Extended Capability is 02h or greater. Add support for the version on devices with the DOE v2 capability. Link: https://lore.kernel.org/r/20240307022006.3657433-1-aik@amd.com Signed-off-by: Alexey Kardashevskiy Signed-off-by: Bjorn Helgaas Reviewed-by: Kuppuswamy Sathyanarayanan --- drivers/pci/doe.c | 12 +++++++++--- include/uapi/linux/pci_regs.h | 1 + 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/pci/doe.c b/drivers/pci/doe.c index e3aab5edaf70..652d63df9d22 100644 --- a/drivers/pci/doe.c +++ b/drivers/pci/doe.c @@ -383,11 +383,13 @@ static void pci_doe_task_complete(struct pci_doe_task *task) complete(task->private); } -static int pci_doe_discovery(struct pci_doe_mb *doe_mb, u8 *index, u16 *vid, +static int pci_doe_discovery(struct pci_doe_mb *doe_mb, u8 capver, u8 *index, u16 *vid, u8 *protocol) { u32 request_pl = FIELD_PREP(PCI_DOE_DATA_OBJECT_DISC_REQ_3_INDEX, - *index); + *index) | + FIELD_PREP(PCI_DOE_DATA_OBJECT_DISC_REQ_3_VER, + (capver >= 2) ? 2 : 0); __le32 request_pl_le = cpu_to_le32(request_pl); __le32 response_pl_le; u32 response_pl; @@ -421,13 +423,17 @@ static int pci_doe_cache_protocols(struct pci_doe_mb *doe_mb) { u8 index = 0; u8 xa_idx = 0; + u32 hdr = 0; + + pci_read_config_dword(doe_mb->pdev, doe_mb->cap_offset, &hdr); do { int rc; u16 vid; u8 prot; - rc = pci_doe_discovery(doe_mb, &index, &vid, &prot); + rc = pci_doe_discovery(doe_mb, PCI_EXT_CAP_VER(hdr), &index, + &vid, &prot); if (rc) return rc; diff --git a/include/uapi/linux/pci_regs.h b/include/uapi/linux/pci_regs.h index a39193213ff2..fbca743b2b86 100644 --- a/include/uapi/linux/pci_regs.h +++ b/include/uapi/linux/pci_regs.h @@ -1144,6 +1144,7 @@ #define PCI_DOE_DATA_OBJECT_HEADER_2_LENGTH 0x0003ffff #define PCI_DOE_DATA_OBJECT_DISC_REQ_3_INDEX 0x000000ff +#define PCI_DOE_DATA_OBJECT_DISC_REQ_3_VER 0x0000ff00 #define PCI_DOE_DATA_OBJECT_DISC_RSP_3_VID 0x0000ffff #define PCI_DOE_DATA_OBJECT_DISC_RSP_3_PROTOCOL 0x00ff0000 #define PCI_DOE_DATA_OBJECT_DISC_RSP_3_NEXT_INDEX 0xff000000 -- cgit v1.2.3-59-g8ed1b From c9615d34ce26199054e188f634eac2e45c9cc906 Mon Sep 17 00:00:00 2001 From: wangkaiyuan Date: Mon, 18 Mar 2024 14:40:36 +0800 Subject: tty: serial: max310x: convert to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. Signed-off-by: wangkaiyuan Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240318064036.1656-1-wangkaiyuan@inspur.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/max310x.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index f0eb96429dae..35369a2f77b2 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -1473,7 +1473,7 @@ static struct regmap_config regcfg = { .reg_bits = 8, .val_bits = 8, .write_flag_mask = MAX310X_WRITE_BIT, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .max_register = MAX310X_REG_1F, .writeable_reg = max310x_reg_writeable, .volatile_reg = max310x_reg_volatile, @@ -1577,7 +1577,7 @@ static int max310x_i2c_extended_reg_enable(struct device *dev, bool enable) static struct regmap_config regcfg_i2c = { .reg_bits = 8, .val_bits = 8, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .writeable_reg = max310x_reg_writeable, .volatile_reg = max310x_reg_volatile, .precious_reg = max310x_reg_precious, -- cgit v1.2.3-59-g8ed1b From 925b2c3f6b6f81a5405a647b381d12a93f06a730 Mon Sep 17 00:00:00 2001 From: wangkaiyuan Date: Mon, 18 Mar 2024 14:42:16 +0800 Subject: tty: serial: sc16is7xx: convert to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. Signed-off-by: wangkaiyuan Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240318064216.1765-1-wangkaiyuan@inspur.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sc16is7xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c index c6983b7bd78c..07aca9fc6d97 100644 --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c @@ -1686,7 +1686,7 @@ static struct regmap_config regcfg = { .reg_bits = 5, .pad_bits = 3, .val_bits = 8, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .volatile_reg = sc16is7xx_regmap_volatile, .precious_reg = sc16is7xx_regmap_precious, .writeable_noinc_reg = sc16is7xx_regmap_noinc, -- cgit v1.2.3-59-g8ed1b From 771d22bce79eec425c011fdf95a431a4a0b47c16 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 9 Apr 2024 17:45:48 +0300 Subject: serial: max3100: Enable TIOCM_LOOP Enable or disable loopback at run-time. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240409144721.638326-2-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/max3100.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/drivers/tty/serial/max3100.c b/drivers/tty/serial/max3100.c index 75e96ff74571..4a4343e7b1fa 100644 --- a/drivers/tty/serial/max3100.c +++ b/drivers/tty/serial/max3100.c @@ -32,14 +32,12 @@ /** * struct plat_max3100 - MAX3100 SPI UART platform data - * @loopback: force MAX3100 in loopback * @crystal: 1 for 3.6864 Mhz, 0 for 1.8432 * * You should use this structure in your machine description to specify * how the MAX3100 is connected. */ struct plat_max3100 { - int loopback; int crystal; }; @@ -109,6 +107,7 @@ struct max3100_port { int minor; /* minor number */ int crystal; /* 1 if 3.6864Mhz crystal 0 for 1.8432 */ + int loopback_commit; /* need to change loopback */ int loopback; /* 1 if we are in loopback mode */ /* for handling irqs: need workqueue since we do spi_sync */ @@ -241,9 +240,9 @@ static void max3100_work(struct work_struct *w) struct max3100_port *s = container_of(w, struct max3100_port, work); struct tty_port *tport = &s->port.state->port; unsigned char ch; + int conf, cconf, cloopback, crts; int rxchars; u16 tx, rx; - int conf, cconf, crts; dev_dbg(&s->spi->dev, "%s\n", __func__); @@ -253,11 +252,15 @@ static void max3100_work(struct work_struct *w) conf = s->conf; cconf = s->conf_commit; s->conf_commit = 0; + cloopback = s->loopback_commit; + s->loopback_commit = 0; crts = s->rts_commit; s->rts_commit = 0; spin_unlock(&s->conf_lock); if (cconf) max3100_sr(s, MAX3100_WC | conf, &rx); + if (cloopback) + max3100_sr(s, 0x4001, &rx); if (crts) { max3100_sr(s, MAX3100_WD | MAX3100_TE | (s->rts ? MAX3100_RTS : 0), &rx); @@ -395,18 +398,24 @@ static void max3100_set_mctrl(struct uart_port *port, unsigned int mctrl) struct max3100_port *s = container_of(port, struct max3100_port, port); - int rts; + int loopback, rts; dev_dbg(&s->spi->dev, "%s\n", __func__); + loopback = (mctrl & TIOCM_LOOP) > 0; rts = (mctrl & TIOCM_RTS) > 0; spin_lock(&s->conf_lock); + if (s->loopback != loopback) { + s->loopback = loopback; + s->loopback_commit = 1; + } if (s->rts != rts) { s->rts = rts; s->rts_commit = 1; - max3100_dowork(s); } + if (s->loopback_commit || s->rts_commit) + max3100_dowork(s); spin_unlock(&s->conf_lock); } @@ -593,12 +602,6 @@ static int max3100_startup(struct uart_port *port) return -EBUSY; } - if (s->loopback) { - u16 tx, rx; - tx = 0x4001; - max3100_sr(s, tx, &rx); - } - s->conf_commit = 1; max3100_dowork(s); /* wait for clock to settle */ @@ -754,7 +757,6 @@ static int max3100_probe(struct spi_device *spi) spi_set_drvdata(spi, max3100s[i]); pdata = dev_get_platdata(&spi->dev); max3100s[i]->crystal = pdata->crystal; - max3100s[i]->loopback = pdata->loopback; max3100s[i]->minor = i; timer_setup(&max3100s[i]->timer, max3100_timeout, 0); -- cgit v1.2.3-59-g8ed1b From 61f538f23a7a83fabfb1fb5ce7ab6f2c75e911f2 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 9 Apr 2024 17:45:49 +0300 Subject: serial: max3100: Get crystal frequency via device property Get crystal frequency via device property instead of using a platform data. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240409144721.638326-3-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/max3100.c | 49 ++++++++++++++++++-------------------------- 1 file changed, 20 insertions(+), 29 deletions(-) diff --git a/drivers/tty/serial/max3100.c b/drivers/tty/serial/max3100.c index 4a4343e7b1fa..446bc78061e3 100644 --- a/drivers/tty/serial/max3100.c +++ b/drivers/tty/serial/max3100.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -30,17 +31,6 @@ #include -/** - * struct plat_max3100 - MAX3100 SPI UART platform data - * @crystal: 1 for 3.6864 Mhz, 0 for 1.8432 - * - * You should use this structure in your machine description to specify - * how the MAX3100 is connected. - */ -struct plat_max3100 { - int crystal; -}; - #define MAX3100_C (1<<14) #define MAX3100_D (0<<14) #define MAX3100_W (1<<15) @@ -106,7 +96,6 @@ struct max3100_port { int irq; /* irq assigned to the max3100 */ int minor; /* minor number */ - int crystal; /* 1 if 3.6864Mhz crystal 0 for 1.8432 */ int loopback_commit; /* need to change loopback */ int loopback; /* 1 if we are in loopback mode */ @@ -426,7 +415,8 @@ max3100_set_termios(struct uart_port *port, struct ktermios *termios, struct max3100_port *s = container_of(port, struct max3100_port, port); - int baud = 0; + unsigned int baud = port->uartclk / 16; + unsigned int baud230400 = (baud == 230400) ? 1 : 0; unsigned cflag; u32 param_new, param_mask, parity = 0; @@ -439,40 +429,40 @@ max3100_set_termios(struct uart_port *port, struct ktermios *termios, param_new = s->conf & MAX3100_BAUD; switch (baud) { case 300: - if (s->crystal) + if (baud230400) baud = s->baud; else param_new = 15; break; case 600: - param_new = 14 + s->crystal; + param_new = 14 + baud230400; break; case 1200: - param_new = 13 + s->crystal; + param_new = 13 + baud230400; break; case 2400: - param_new = 12 + s->crystal; + param_new = 12 + baud230400; break; case 4800: - param_new = 11 + s->crystal; + param_new = 11 + baud230400; break; case 9600: - param_new = 10 + s->crystal; + param_new = 10 + baud230400; break; case 19200: - param_new = 9 + s->crystal; + param_new = 9 + baud230400; break; case 38400: - param_new = 8 + s->crystal; + param_new = 8 + baud230400; break; case 57600: - param_new = 1 + s->crystal; + param_new = 1 + baud230400; break; case 115200: - param_new = 0 + s->crystal; + param_new = 0 + baud230400; break; case 230400: - if (s->crystal) + if (baud230400) param_new = 0; else baud = s->baud; @@ -575,7 +565,7 @@ static int max3100_startup(struct uart_port *port) dev_dbg(&s->spi->dev, "%s\n", __func__); s->conf = MAX3100_RM; - s->baud = s->crystal ? 230400 : 115200; + s->baud = port->uartclk / 16; s->rx_enabled = 1; if (s->suspending) @@ -718,8 +708,8 @@ static int uart_driver_registered; static int max3100_probe(struct spi_device *spi) { + struct device *dev = &spi->dev; int i, retval; - struct plat_max3100 *pdata; u16 rx; mutex_lock(&max3100s_lock); @@ -755,20 +745,21 @@ static int max3100_probe(struct spi_device *spi) max3100s[i]->irq = spi->irq; spin_lock_init(&max3100s[i]->conf_lock); spi_set_drvdata(spi, max3100s[i]); - pdata = dev_get_platdata(&spi->dev); - max3100s[i]->crystal = pdata->crystal; max3100s[i]->minor = i; timer_setup(&max3100s[i]->timer, max3100_timeout, 0); dev_dbg(&spi->dev, "%s: adding port %d\n", __func__, i); max3100s[i]->port.irq = max3100s[i]->irq; - max3100s[i]->port.uartclk = max3100s[i]->crystal ? 3686400 : 1843200; max3100s[i]->port.fifosize = 16; max3100s[i]->port.ops = &max3100_ops; max3100s[i]->port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF; max3100s[i]->port.line = i; max3100s[i]->port.type = PORT_MAX3100; max3100s[i]->port.dev = &spi->dev; + + /* Read clock frequency from a property, uart_add_one_port() will fail if it's not set */ + device_property_read_u32(dev, "clock-frequency", &max3100s[i]->port.uartclk); + retval = uart_add_one_port(&max3100_uart_driver, &max3100s[i]->port); if (retval < 0) dev_warn(&spi->dev, -- cgit v1.2.3-59-g8ed1b From 8c15f723caba9db359bdabcd54e7dda4c0b19c0b Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 9 Apr 2024 17:45:50 +0300 Subject: serial: max3100: Remove duplicating irq field The struct uart_port has a copy of the IRQ that is also stored in the private data structure. Remove the duplication in the latter one. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240409144721.638326-4-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/max3100.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/drivers/tty/serial/max3100.c b/drivers/tty/serial/max3100.c index 446bc78061e3..e3104ea7a3ca 100644 --- a/drivers/tty/serial/max3100.c +++ b/drivers/tty/serial/max3100.c @@ -93,8 +93,6 @@ struct max3100_port { #define MAX3100_7BIT 4 int rx_enabled; /* if we should rx chars */ - int irq; /* irq assigned to the max3100 */ - int minor; /* minor number */ int loopback_commit; /* need to change loopback */ int loopback; /* 1 if we are in loopback mode */ @@ -548,8 +546,8 @@ static void max3100_shutdown(struct uart_port *port) destroy_workqueue(s->workqueue); s->workqueue = NULL; } - if (s->irq) - free_irq(s->irq, s); + if (port->irq) + free_irq(port->irq, s); /* set shutdown mode to save power */ max3100_sr(s, MAX3100_WC | MAX3100_SHDN, &rx); @@ -561,6 +559,7 @@ static int max3100_startup(struct uart_port *port) struct max3100_port, port); char b[12]; + int ret; dev_dbg(&s->spi->dev, "%s\n", __func__); @@ -583,10 +582,10 @@ static int max3100_startup(struct uart_port *port) } INIT_WORK(&s->work, max3100_work); - if (request_irq(s->irq, max3100_irq, - IRQF_TRIGGER_FALLING, "max3100", s) < 0) { - dev_warn(&s->spi->dev, "cannot allocate irq %d\n", s->irq); - s->irq = 0; + ret = request_irq(port->irq, max3100_irq, IRQF_TRIGGER_FALLING, "max3100", s); + if (ret < 0) { + dev_warn(&s->spi->dev, "cannot allocate irq %d\n", port->irq); + port->irq = 0; destroy_workqueue(s->workqueue); s->workqueue = NULL; return -EBUSY; @@ -742,14 +741,13 @@ static int max3100_probe(struct spi_device *spi) return -ENOMEM; } max3100s[i]->spi = spi; - max3100s[i]->irq = spi->irq; spin_lock_init(&max3100s[i]->conf_lock); spi_set_drvdata(spi, max3100s[i]); max3100s[i]->minor = i; timer_setup(&max3100s[i]->timer, max3100_timeout, 0); dev_dbg(&spi->dev, "%s: adding port %d\n", __func__, i); - max3100s[i]->port.irq = max3100s[i]->irq; + max3100s[i]->port.irq = spi->irq; max3100s[i]->port.fifosize = 16; max3100s[i]->port.ops = &max3100_ops; max3100s[i]->port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF; @@ -813,7 +811,7 @@ static int max3100_suspend(struct device *dev) dev_dbg(&s->spi->dev, "%s\n", __func__); - disable_irq(s->irq); + disable_irq(s->port.irq); s->suspending = 1; uart_suspend_port(&max3100_uart_driver, &s->port); @@ -832,7 +830,7 @@ static int max3100_resume(struct device *dev) uart_resume_port(&max3100_uart_driver, &s->port); s->suspending = 0; - enable_irq(s->irq); + enable_irq(s->port.irq); s->conf_commit = 1; if (s->workqueue) -- cgit v1.2.3-59-g8ed1b From bbcbf739215eb8bfae346b9738bf5d209b434604 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 9 Apr 2024 17:45:51 +0300 Subject: serial: max3100: Switch to use dev_err_probe() Switch to use dev_err_probe() to simplify the error path and unify a message template. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240409144721.638326-5-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/max3100.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/drivers/tty/serial/max3100.c b/drivers/tty/serial/max3100.c index e3104ea7a3ca..09ec2ca06989 100644 --- a/drivers/tty/serial/max3100.c +++ b/drivers/tty/serial/max3100.c @@ -716,9 +716,8 @@ static int max3100_probe(struct spi_device *spi) if (!uart_driver_registered) { retval = uart_register_driver(&max3100_uart_driver); if (retval) { - printk(KERN_ERR "Couldn't register max3100 uart driver\n"); mutex_unlock(&max3100s_lock); - return retval; + return dev_err_probe(dev, retval, "Couldn't register max3100 uart driver\n"); } uart_driver_registered = 1; @@ -728,15 +727,12 @@ static int max3100_probe(struct spi_device *spi) if (!max3100s[i]) break; if (i == MAX_MAX3100) { - dev_warn(&spi->dev, "too many MAX3100 chips\n"); mutex_unlock(&max3100s_lock); - return -ENOMEM; + return dev_err_probe(dev, -ENOMEM, "too many MAX3100 chips\n"); } max3100s[i] = kzalloc(sizeof(struct max3100_port), GFP_KERNEL); if (!max3100s[i]) { - dev_warn(&spi->dev, - "kmalloc for max3100 structure %d failed!\n", i); mutex_unlock(&max3100s_lock); return -ENOMEM; } @@ -760,9 +756,7 @@ static int max3100_probe(struct spi_device *spi) retval = uart_add_one_port(&max3100_uart_driver, &max3100s[i]->port); if (retval < 0) - dev_warn(&spi->dev, - "uart_add_one_port failed for line %d with error %d\n", - i, retval); + dev_err_probe(dev, retval, "uart_add_one_port failed for line %d\n", i); /* set shutdown mode to save power. Will be woken-up on open */ max3100_sr(max3100s[i], MAX3100_WC | MAX3100_SHDN, &rx); -- cgit v1.2.3-59-g8ed1b From 8250b1c1fdf617e953511289b46c8a77d4d4457c Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 9 Apr 2024 17:45:52 +0300 Subject: serial: max3100: Replace MODULE_ALIAS() with respective ID tables MODULE_ALIAS() in most cases is a pure hack to avoid placing ID tables. Replace it with the respective ID tables. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240409144721.638326-6-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/max3100.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/drivers/tty/serial/max3100.c b/drivers/tty/serial/max3100.c index 09ec2ca06989..3004a95e573f 100644 --- a/drivers/tty/serial/max3100.c +++ b/drivers/tty/serial/max3100.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -840,13 +841,27 @@ static SIMPLE_DEV_PM_OPS(max3100_pm_ops, max3100_suspend, max3100_resume); #define MAX3100_PM_OPS NULL #endif +static const struct spi_device_id max3100_spi_id[] = { + { "max3100" }, + { } +}; +MODULE_DEVICE_TABLE(spi, max3100_spi_id); + +static const struct of_device_id max3100_of_match[] = { + { .compatible = "maxim,max3100" }, + { } +}; +MODULE_DEVICE_TABLE(of, max3100_of_match); + static struct spi_driver max3100_driver = { .driver = { .name = "max3100", + .of_match_table = max3100_of_match, .pm = MAX3100_PM_OPS, }, .probe = max3100_probe, .remove = max3100_remove, + .id_table = max3100_spi_id, }; module_spi_driver(max3100_driver); @@ -854,4 +869,3 @@ module_spi_driver(max3100_driver); MODULE_DESCRIPTION("MAX3100 driver"); MODULE_AUTHOR("Christian Pellegrin "); MODULE_LICENSE("GPL"); -MODULE_ALIAS("spi:max3100"); -- cgit v1.2.3-59-g8ed1b From 1d01740efb6856cf02905a84bf04b70d223993c2 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 9 Apr 2024 17:45:53 +0300 Subject: serial: max3100: Switch to DEFINE_SIMPLE_DEV_PM_OPS() The SIMPLE_DEV_PM_OPS() is deprecated, replace it with the DEFINE_SIMPLE_DEV_PM_OPS() and use pm_sleep_ptr() for setting the driver's PM routines. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240409144721.638326-7-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/max3100.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/drivers/tty/serial/max3100.c b/drivers/tty/serial/max3100.c index 3004a95e573f..db543eaa39c8 100644 --- a/drivers/tty/serial/max3100.c +++ b/drivers/tty/serial/max3100.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -797,8 +798,6 @@ static void max3100_remove(struct spi_device *spi) mutex_unlock(&max3100s_lock); } -#ifdef CONFIG_PM_SLEEP - static int max3100_suspend(struct device *dev) { struct max3100_port *s = dev_get_drvdata(dev); @@ -834,12 +833,7 @@ static int max3100_resume(struct device *dev) return 0; } -static SIMPLE_DEV_PM_OPS(max3100_pm_ops, max3100_suspend, max3100_resume); -#define MAX3100_PM_OPS (&max3100_pm_ops) - -#else -#define MAX3100_PM_OPS NULL -#endif +static DEFINE_SIMPLE_DEV_PM_OPS(max3100_pm_ops, max3100_suspend, max3100_resume); static const struct spi_device_id max3100_spi_id[] = { { "max3100" }, @@ -857,7 +851,7 @@ static struct spi_driver max3100_driver = { .driver = { .name = "max3100", .of_match_table = max3100_of_match, - .pm = MAX3100_PM_OPS, + .pm = pm_sleep_ptr(&max3100_pm_ops), }, .probe = max3100_probe, .remove = max3100_remove, -- cgit v1.2.3-59-g8ed1b From 69b2cc30315ac48e3a6308a7f736f67c3e3db0b1 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 9 Apr 2024 17:45:54 +0300 Subject: serial: max3100: Extract to_max3100_port() helper macro Instead of using container_of() explicitly, introduce a helper macro. This saves a lot of lines of code. Signed-off-by: Andy Shevchenko Reviewed-by: Hugo Villeneuve Link: https://lore.kernel.org/r/20240409144721.638326-8-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/max3100.c | 67 +++++++++++++------------------------------- 1 file changed, 19 insertions(+), 48 deletions(-) diff --git a/drivers/tty/serial/max3100.c b/drivers/tty/serial/max3100.c index db543eaa39c8..4e7cd037cfc2 100644 --- a/drivers/tty/serial/max3100.c +++ b/drivers/tty/serial/max3100.c @@ -16,6 +16,7 @@ /* 4 MAX3100s should be enough for everyone */ #define MAX_MAX3100 4 +#include #include #include #include @@ -110,6 +111,8 @@ struct max3100_port { struct timer_list timer; }; +#define to_max3100_port(port) container_of(port, struct max3100_port, port) + static struct max3100_port *max3100s[MAX_MAX3100]; /* the chips */ static DEFINE_MUTEX(max3100s_lock); /* race on probe */ @@ -320,9 +323,7 @@ static irqreturn_t max3100_irq(int irqno, void *dev_id) static void max3100_enable_ms(struct uart_port *port) { - struct max3100_port *s = container_of(port, - struct max3100_port, - port); + struct max3100_port *s = to_max3100_port(port); mod_timer(&s->timer, jiffies); dev_dbg(&s->spi->dev, "%s\n", __func__); @@ -330,9 +331,7 @@ static void max3100_enable_ms(struct uart_port *port) static void max3100_start_tx(struct uart_port *port) { - struct max3100_port *s = container_of(port, - struct max3100_port, - port); + struct max3100_port *s = to_max3100_port(port); dev_dbg(&s->spi->dev, "%s\n", __func__); @@ -341,9 +340,7 @@ static void max3100_start_tx(struct uart_port *port) static void max3100_stop_rx(struct uart_port *port) { - struct max3100_port *s = container_of(port, - struct max3100_port, - port); + struct max3100_port *s = to_max3100_port(port); dev_dbg(&s->spi->dev, "%s\n", __func__); @@ -357,9 +354,7 @@ static void max3100_stop_rx(struct uart_port *port) static unsigned int max3100_tx_empty(struct uart_port *port) { - struct max3100_port *s = container_of(port, - struct max3100_port, - port); + struct max3100_port *s = to_max3100_port(port); dev_dbg(&s->spi->dev, "%s\n", __func__); @@ -370,9 +365,7 @@ static unsigned int max3100_tx_empty(struct uart_port *port) static unsigned int max3100_get_mctrl(struct uart_port *port) { - struct max3100_port *s = container_of(port, - struct max3100_port, - port); + struct max3100_port *s = to_max3100_port(port); dev_dbg(&s->spi->dev, "%s\n", __func__); @@ -384,9 +377,7 @@ static unsigned int max3100_get_mctrl(struct uart_port *port) static void max3100_set_mctrl(struct uart_port *port, unsigned int mctrl) { - struct max3100_port *s = container_of(port, - struct max3100_port, - port); + struct max3100_port *s = to_max3100_port(port); int loopback, rts; dev_dbg(&s->spi->dev, "%s\n", __func__); @@ -412,9 +403,7 @@ static void max3100_set_termios(struct uart_port *port, struct ktermios *termios, const struct ktermios *old) { - struct max3100_port *s = container_of(port, - struct max3100_port, - port); + struct max3100_port *s = to_max3100_port(port); unsigned int baud = port->uartclk / 16; unsigned int baud230400 = (baud == 230400) ? 1 : 0; unsigned cflag; @@ -530,9 +519,7 @@ max3100_set_termios(struct uart_port *port, struct ktermios *termios, static void max3100_shutdown(struct uart_port *port) { - struct max3100_port *s = container_of(port, - struct max3100_port, - port); + struct max3100_port *s = to_max3100_port(port); u16 rx; dev_dbg(&s->spi->dev, "%s\n", __func__); @@ -557,9 +544,7 @@ static void max3100_shutdown(struct uart_port *port) static int max3100_startup(struct uart_port *port) { - struct max3100_port *s = container_of(port, - struct max3100_port, - port); + struct max3100_port *s = to_max3100_port(port); char b[12]; int ret; @@ -605,9 +590,7 @@ static int max3100_startup(struct uart_port *port) static const char *max3100_type(struct uart_port *port) { - struct max3100_port *s = container_of(port, - struct max3100_port, - port); + struct max3100_port *s = to_max3100_port(port); dev_dbg(&s->spi->dev, "%s\n", __func__); @@ -616,18 +599,14 @@ static const char *max3100_type(struct uart_port *port) static void max3100_release_port(struct uart_port *port) { - struct max3100_port *s = container_of(port, - struct max3100_port, - port); + struct max3100_port *s = to_max3100_port(port); dev_dbg(&s->spi->dev, "%s\n", __func__); } static void max3100_config_port(struct uart_port *port, int flags) { - struct max3100_port *s = container_of(port, - struct max3100_port, - port); + struct max3100_port *s = to_max3100_port(port); dev_dbg(&s->spi->dev, "%s\n", __func__); @@ -638,9 +617,7 @@ static void max3100_config_port(struct uart_port *port, int flags) static int max3100_verify_port(struct uart_port *port, struct serial_struct *ser) { - struct max3100_port *s = container_of(port, - struct max3100_port, - port); + struct max3100_port *s = to_max3100_port(port); int ret = -EINVAL; dev_dbg(&s->spi->dev, "%s\n", __func__); @@ -652,18 +629,14 @@ static int max3100_verify_port(struct uart_port *port, static void max3100_stop_tx(struct uart_port *port) { - struct max3100_port *s = container_of(port, - struct max3100_port, - port); + struct max3100_port *s = to_max3100_port(port); dev_dbg(&s->spi->dev, "%s\n", __func__); } static int max3100_request_port(struct uart_port *port) { - struct max3100_port *s = container_of(port, - struct max3100_port, - port); + struct max3100_port *s = to_max3100_port(port); dev_dbg(&s->spi->dev, "%s\n", __func__); return 0; @@ -671,9 +644,7 @@ static int max3100_request_port(struct uart_port *port) static void max3100_break_ctl(struct uart_port *port, int break_state) { - struct max3100_port *s = container_of(port, - struct max3100_port, - port); + struct max3100_port *s = to_max3100_port(port); dev_dbg(&s->spi->dev, "%s\n", __func__); } -- cgit v1.2.3-59-g8ed1b From 4fe952c141b285ca0b379c93c9c6c69d7240a495 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 9 Apr 2024 17:45:55 +0300 Subject: serial: max3100: Sort headers Sort the headers in alphabetic order in order to ease the maintenance for this part. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240409144721.638326-9-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/max3100.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/tty/serial/max3100.c b/drivers/tty/serial/max3100.c index 4e7cd037cfc2..ce24588150bf 100644 --- a/drivers/tty/serial/max3100.c +++ b/drivers/tty/serial/max3100.c @@ -18,18 +18,18 @@ #include #include -#include #include +#include #include #include #include #include #include #include +#include #include -#include -#include #include +#include #include #include -- cgit v1.2.3-59-g8ed1b From 838022def8ef2b676d6f3c19cad9185ce8046008 Mon Sep 17 00:00:00 2001 From: Lino Sanfilippo Date: Sun, 7 Apr 2024 02:27:06 +0200 Subject: serial: amba-pl011: get rid of useless wrapper pl011_get_rs485_mode() Due to earlier code changes function pl011_get_rs485_mode() is now merely a wrapper for uart_get_rs485_mode() which does not add any further functionality. So remove it and instead call uart_get_rs485_mode() directly. Reviewed-by: Lukas Wunner Signed-off-by: Lino Sanfilippo Link: https://lore.kernel.org/r/20240407002709.16224-2-l.sanfilippo@kunbus.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/amba-pl011.c | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 51b202eb8296..76d2078ec086 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -2692,18 +2692,6 @@ static int pl011_find_free_port(void) return -EBUSY; } -static int pl011_get_rs485_mode(struct uart_amba_port *uap) -{ - struct uart_port *port = &uap->port; - int ret; - - ret = uart_get_rs485_mode(port); - if (ret) - return ret; - - return 0; -} - static int pl011_setup_port(struct device *dev, struct uart_amba_port *uap, struct resource *mmiobase, int index) { @@ -2724,7 +2712,7 @@ static int pl011_setup_port(struct device *dev, struct uart_amba_port *uap, uap->port.flags = UPF_BOOT_AUTOCONF; uap->port.line = index; - ret = pl011_get_rs485_mode(uap); + ret = uart_get_rs485_mode(&uap->port); if (ret) return ret; -- cgit v1.2.3-59-g8ed1b From 255abd49f18533300bc5f20d7dce77a0a4479f58 Mon Sep 17 00:00:00 2001 From: Lino Sanfilippo Date: Sun, 7 Apr 2024 02:27:07 +0200 Subject: serial: amba-pl011: move variable into CONFIG_DMA_ENGINE conditional Variable dmacr is only used if DMA is enabled, so move it into the CONFIG_DMA_ENGINE conditional. Signed-off-by: Lino Sanfilippo Link: https://lore.kernel.org/r/20240407002709.16224-3-l.sanfilippo@kunbus.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/amba-pl011.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 76d2078ec086..8b1644f5411e 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -256,7 +256,6 @@ struct uart_amba_port { const u16 *reg_offset; struct clk *clk; const struct vendor_data *vendor; - unsigned int dmacr; /* dma control reg */ unsigned int im; /* interrupt mask */ unsigned int old_status; unsigned int fifosize; /* vendor-specific */ @@ -266,6 +265,7 @@ struct uart_amba_port { unsigned int rs485_tx_drain_interval; /* usecs */ #ifdef CONFIG_DMA_ENGINE /* DMA stuff */ + unsigned int dmacr; /* dma control reg */ bool using_tx_dma; bool using_rx_dma; struct pl011_dmarx_data dmarx; -- cgit v1.2.3-59-g8ed1b From 384fa8647dc55ab47515bbb76ebda37b2350e5b3 Mon Sep 17 00:00:00 2001 From: Lino Sanfilippo Date: Sun, 7 Apr 2024 02:27:08 +0200 Subject: serial: 8250: Remove superfluous sanity check The serial core already checks the RS485 RTS settings for sanity, so remove the superfluous check in serial8250_em485_config(). Signed-off-by: Lino Sanfilippo Link: https://lore.kernel.org/r/20240407002709.16224-4-l.sanfilippo@kunbus.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_port.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 0c19451d0332..893bc493f662 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -612,13 +612,6 @@ int serial8250_em485_config(struct uart_port *port, struct ktermios *termios, { struct uart_8250_port *up = up_to_u8250p(port); - /* pick sane settings if the user hasn't */ - if (!!(rs485->flags & SER_RS485_RTS_ON_SEND) == - !!(rs485->flags & SER_RS485_RTS_AFTER_SEND)) { - rs485->flags |= SER_RS485_RTS_ON_SEND; - rs485->flags &= ~SER_RS485_RTS_AFTER_SEND; - } - /* * Both serial8250_em485_init() and serial8250_em485_destroy() * are idempotent. -- cgit v1.2.3-59-g8ed1b From fff4a5d5609db86ccdf1cf5791b7651b7f6a9b19 Mon Sep 17 00:00:00 2001 From: Lino Sanfilippo Date: Sun, 7 Apr 2024 02:27:09 +0200 Subject: serial: ar933x: Remove unneeded static structure In case that no RTS GPIO is available do not use a dedicated nullified serial_rs485 struct to disable RS485 support, but simply delete the SER_RS485_ENABLED flag in the ports rs485_supported struct. This make the structure superfluous and it can be removed. Signed-off-by: Lino Sanfilippo Link: https://lore.kernel.org/r/20240407002709.16224-5-l.sanfilippo@kunbus.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/ar933x_uart.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/tty/serial/ar933x_uart.c b/drivers/tty/serial/ar933x_uart.c index f2836ecc5c19..47889a557119 100644 --- a/drivers/tty/serial/ar933x_uart.c +++ b/drivers/tty/serial/ar933x_uart.c @@ -692,7 +692,6 @@ static struct uart_driver ar933x_uart_driver = { .cons = NULL, /* filled in runtime */ }; -static const struct serial_rs485 ar933x_no_rs485 = {}; static const struct serial_rs485 ar933x_rs485_supported = { .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND, }; @@ -788,7 +787,7 @@ static int ar933x_uart_probe(struct platform_device *pdev) up->rts_gpiod = mctrl_gpio_to_gpiod(up->gpios, UART_GPIO_RTS); if (!up->rts_gpiod) { - port->rs485_supported = ar933x_no_rs485; + port->rs485_supported.flags &= ~SER_RS485_ENABLED; if (port->rs485.flags & SER_RS485_ENABLED) { dev_err(&pdev->dev, "lacking rts-gpio, disabling RS485\n"); port->rs485.flags &= ~SER_RS485_ENABLED; -- cgit v1.2.3-59-g8ed1b From ccdd4aac5f4b1e735c4372d2f12884a3ff0eb524 Mon Sep 17 00:00:00 2001 From: Michael Grzeschik Date: Tue, 2 Apr 2024 08:17:17 +0200 Subject: usb: phy-generic: add short delay after pulling the reset pin After pulling the reset pin some phys are not immediately ready. We add a short delay of at least 10 ms to ensure that the phy can be properly used. Signed-off-by: Michael Grzeschik Link: https://lore.kernel.org/r/20240402-phy-misc-v1-1-de5c17f93f17@pengutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/usb/phy/phy-generic.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/phy/phy-generic.c b/drivers/usb/phy/phy-generic.c index fdcffebf415c..e7d50e0a1612 100644 --- a/drivers/usb/phy/phy-generic.c +++ b/drivers/usb/phy/phy-generic.c @@ -71,6 +71,7 @@ static void nop_reset(struct usb_phy_generic *nop) gpiod_set_value_cansleep(nop->gpiod_reset, 1); usleep_range(10000, 20000); gpiod_set_value_cansleep(nop->gpiod_reset, 0); + usleep_range(10000, 30000); } /* interface to regulator framework */ -- cgit v1.2.3-59-g8ed1b From bfbf2e4b77e27741736c8dc2d2c5c560d7d0ff51 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Fri, 5 Apr 2024 09:01:47 -0300 Subject: dt-bindings: usb: Document the Microchip USB2514 hub Document the Microchip USB2412, USB2417, and USB2514 USB hubs. The existing usb251xb.yaml describes Microchip USB251x hubs that are connected under I2C bus. Here, the hub is under the USB bus and use the on-board-hub interface instead. Signed-off-by: Fabio Estevam Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240405120147.880933-1-festevam@gmail.com Signed-off-by: Greg Kroah-Hartman --- .../devicetree/bindings/usb/microchip,usb2514.yaml | 63 ++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 Documentation/devicetree/bindings/usb/microchip,usb2514.yaml diff --git a/Documentation/devicetree/bindings/usb/microchip,usb2514.yaml b/Documentation/devicetree/bindings/usb/microchip,usb2514.yaml new file mode 100644 index 000000000000..783c27591e56 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/microchip,usb2514.yaml @@ -0,0 +1,63 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/usb/microchip,usb2514.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Microchip USB2514 Hub Controller + +maintainers: + - Fabio Estevam + +allOf: + - $ref: usb-hcd.yaml# + +properties: + compatible: + enum: + - usb424,2412 + - usb424,2417 + - usb424,2514 + + reg: true + + reset-gpios: + description: GPIO connected to the RESET_N pin. + + vdd-supply: + description: 3.3V power supply. + + clocks: + description: External 24MHz clock connected to the CLKIN pin. + maxItems: 1 + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + #include + #include + + usb { + #address-cells = <1>; + #size-cells = <0>; + + usb-hub@1 { + compatible = "usb424,2514"; + reg = <1>; + clocks = <&clks IMX6QDL_CLK_CKO>; + reset-gpios = <&gpio7 12 GPIO_ACTIVE_LOW>; + vdd-supply = <®_3v3_hub>; + #address-cells = <1>; + #size-cells = <0>; + + ethernet@1 { + compatible = "usbb95,772b"; + reg = <1>; + }; + }; + }; -- cgit v1.2.3-59-g8ed1b From 00bca46580611a22d430bb709df96decb03e0756 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Fri, 5 Apr 2024 16:50:51 -0300 Subject: dt-bindings: usb: hx3: Remove unneeded dr_mode It is expected that the USB controller works in host mode to have the USB hub operational. Remove such unneeded property from the devicetree example. Signed-off-by: Fabio Estevam Link: https://lore.kernel.org/r/20240405195051.945474-1-festevam@gmail.com Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/usb/cypress,hx3.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/Documentation/devicetree/bindings/usb/cypress,hx3.yaml b/Documentation/devicetree/bindings/usb/cypress,hx3.yaml index 28096619a882..e44e88d993d0 100644 --- a/Documentation/devicetree/bindings/usb/cypress,hx3.yaml +++ b/Documentation/devicetree/bindings/usb/cypress,hx3.yaml @@ -51,7 +51,6 @@ examples: #include usb { - dr_mode = "host"; #address-cells = <1>; #size-cells = <0>; -- cgit v1.2.3-59-g8ed1b From 22ffd399e6e7aa18ae0314278ed0b7f05f8ab679 Mon Sep 17 00:00:00 2001 From: Michael Grzeschik Date: Tue, 2 Apr 2024 08:23:43 +0200 Subject: usb: chipidea: move ci_ulpi_init after the phy initialization The function ci_usb_phy_init is already handling the hw_phymode_configure path which is also only possible after we have a valid phy. So we move the ci_ulpi_init after the phy initialization to be really sure to be able to communicate with the ulpi phy. Signed-off-by: Michael Grzeschik Acked-by: Peter Chen Link: https://lore.kernel.org/r/20240328-chipidea-phy-misc-v1-1-907d9de5d4df@pengutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/usb/chipidea/core.c | 8 ++++---- drivers/usb/chipidea/ulpi.c | 5 ----- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 835bf2428dc6..bada13f704b6 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -1084,10 +1084,6 @@ static int ci_hdrc_probe(struct platform_device *pdev) return -ENODEV; } - ret = ci_ulpi_init(ci); - if (ret) - return ret; - if (ci->platdata->phy) { ci->phy = ci->platdata->phy; } else if (ci->platdata->usb_phy) { @@ -1142,6 +1138,10 @@ static int ci_hdrc_probe(struct platform_device *pdev) goto ulpi_exit; } + ret = ci_ulpi_init(ci); + if (ret) + return ret; + ci->hw_bank.phys = res->start; ci->irq = platform_get_irq(pdev, 0); diff --git a/drivers/usb/chipidea/ulpi.c b/drivers/usb/chipidea/ulpi.c index dfec07e8ae1d..89fb51e2c3de 100644 --- a/drivers/usb/chipidea/ulpi.c +++ b/drivers/usb/chipidea/ulpi.c @@ -68,11 +68,6 @@ int ci_ulpi_init(struct ci_hdrc *ci) if (ci->platdata->phy_mode != USBPHY_INTERFACE_MODE_ULPI) return 0; - /* - * Set PORTSC correctly so we can read/write ULPI registers for - * identification purposes - */ - hw_phymode_configure(ci); ci->ulpi_ops.read = ci_ulpi_read; ci->ulpi_ops.write = ci_ulpi_write; -- cgit v1.2.3-59-g8ed1b From 0fb782b5d5c462b2518b3b4fe7d652114c28d613 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 6 Apr 2024 16:01:27 +0200 Subject: usb: dwc3: pci: Don't set "linux,phy_charger_detect" property on Lenovo Yoga Tab2 1380 The Lenovo Yoga Tablet 2 Pro 1380 model is the exception to the rule that devices which use the Crystal Cove PMIC without using ACPI for battery and AC power_supply class support use the USB-phy for charger detection. Unlike the Lenovo Yoga Tablet 2 830 / 1050 models this model has an extra LC824206XA Micro USB switch which does the charger detection. Add a DMI quirk to not set the "linux,phy_charger_detect" property on the 1380 model. This quirk matches on the BIOS version to differentiate the 1380 model from the 830 and 1050 models which otherwise have the same DMI strings. Signed-off-by: Hans de Goede Acked-by: Thinh Nguyen Link: https://lore.kernel.org/r/20240406140127.17885-1-hdegoede@redhat.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/dwc3-pci.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c index 497deed38c0c..9ef821ca2fc7 100644 --- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -8,6 +8,7 @@ * Sebastian Andrzej Siewior */ +#include #include #include #include @@ -220,6 +221,7 @@ static int dwc3_pci_quirks(struct dwc3_pci *dwc, if (pdev->device == PCI_DEVICE_ID_INTEL_BYT) { struct gpio_desc *gpio; + const char *bios_ver; int ret; /* On BYT the FW does not always enable the refclock */ @@ -277,8 +279,12 @@ static int dwc3_pci_quirks(struct dwc3_pci *dwc, * detection. These can be identified by them _not_ * using the standard ACPI battery and ac drivers. */ + bios_ver = dmi_get_system_info(DMI_BIOS_VERSION); if (acpi_dev_present("INT33FD", "1", 2) && - acpi_quirk_skip_acpi_ac_and_battery()) { + acpi_quirk_skip_acpi_ac_and_battery() && + /* Lenovo Yoga Tablet 2 Pro 1380 uses LC824206XA instead */ + !(bios_ver && + strstarts(bios_ver, "BLADE_21.X64.0005.R00.1504101516"))) { dev_info(&pdev->dev, "Using TUSB1211 phy for charger detection\n"); swnode = &dwc3_pci_intel_phy_charger_detect_swnode; } -- cgit v1.2.3-59-g8ed1b From c4ede56172dc5a9b60d7b7f11a5cf2073b14c14e Mon Sep 17 00:00:00 2001 From: Pavan Holla Date: Tue, 9 Apr 2024 01:58:57 +0000 Subject: usb: typec: ucsi: Wait 20ms before reading CCI after a reset The PPM might take time to process a reset. Allow 20ms for the reset to be processed before reading the CCI. This should not slow down existing implementations because they would not set any bits in the CCI after a reset, and would take a 20ms delay to read the CCI anyway. This change makes the delay explicit, and reduces a CCI read. Based on the spec, the PPM has 10ms to set busy, so, 20ms seems like a reasonable delay before we read the CCI. Signed-off-by: Pavan Holla Reviewed-by: Prashant Malani Reviewed-by: Heikki Krogerus Link: https://lore.kernel.org/r/20240409-ucsi-reset-delay-v3-1-8440710b012b@chromium.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/ucsi/ucsi.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c index 0e37404d309a..36e1b191f87d 100644 --- a/drivers/usb/typec/ucsi/ucsi.c +++ b/drivers/usb/typec/ucsi/ucsi.c @@ -1337,6 +1337,9 @@ static int ucsi_reset_ppm(struct ucsi *ucsi) goto out; } + /* Give the PPM time to process a reset before reading CCI */ + msleep(20); + ret = ucsi->ops->read(ucsi, UCSI_CCI, &cci, sizeof(cci)); if (ret) goto out; @@ -1350,7 +1353,6 @@ static int ucsi_reset_ppm(struct ucsi *ucsi) goto out; } - msleep(20); } while (!(cci & UCSI_CCI_RESET_COMPLETE)); out: -- cgit v1.2.3-59-g8ed1b From 0c5794f7b0ef74f54314183f560a0a938be21b45 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Mon, 8 Apr 2024 04:04:15 +0300 Subject: usb: typec: ucsi_glink: enable the UCSI_DELAY_DEVICE_PDOS quirk on qcm6490 Enable the UCSI_DELAY_DEVICE_PDOS quirk on Qualcomm QCM6490. This platform also doesn't correctly handle reading PD capabilities until PD partner is connected. Fixes: 5da727f75823 ("usb: typec: ucsi_glink: enable the UCSI_DELAY_DEVICE_PDOS quirk") Signed-off-by: Dmitry Baryshkov Reviewed-by: Heikki Krogerus Link: https://lore.kernel.org/r/20240408-qcom-ucsi-fixes-bis-v1-1-716c145ca4b1@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/ucsi/ucsi_glink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/typec/ucsi/ucsi_glink.c b/drivers/usb/typec/ucsi/ucsi_glink.c index ef00a6563c88..9bd80a2218e4 100644 --- a/drivers/usb/typec/ucsi/ucsi_glink.c +++ b/drivers/usb/typec/ucsi/ucsi_glink.c @@ -316,7 +316,7 @@ static unsigned long quirk_sc8280xp = UCSI_NO_PARTNER_PDOS | UCSI_DELAY_DEVICE_P static unsigned long quirk_sm8450 = UCSI_DELAY_DEVICE_PDOS; static const struct of_device_id pmic_glink_ucsi_of_quirks[] = { - { .compatible = "qcom,qcm6490-pmic-glink", .data = &quirk_sc8180x, }, + { .compatible = "qcom,qcm6490-pmic-glink", .data = &quirk_sc8280xp, }, { .compatible = "qcom,sc8180x-pmic-glink", .data = &quirk_sc8180x, }, { .compatible = "qcom,sc8280xp-pmic-glink", .data = &quirk_sc8280xp, }, { .compatible = "qcom,sm8350-pmic-glink", .data = &quirk_sc8180x, }, -- cgit v1.2.3-59-g8ed1b From c82d6cbb03ccb7ca0162f144ffa320479588b792 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Mon, 8 Apr 2024 04:04:16 +0300 Subject: usb: typec: ucsi_glink: drop NO_PARTNER_PDOS quirk for sm8550 / sm8650 The Qualcomm SM8550 (and via a fallback compat SM8650) firmware properly handles the GET_PDOS command, it sends the CCI_BUSY notification, and then follows with the CCI_COMMAND_COMPLETE event. Stop using the quirk for those two platforms. Signed-off-by: Dmitry Baryshkov Reviewed-by: Heikki Krogerus Link: https://lore.kernel.org/r/20240408-qcom-ucsi-fixes-bis-v1-2-716c145ca4b1@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/ucsi/ucsi_glink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/typec/ucsi/ucsi_glink.c b/drivers/usb/typec/ucsi/ucsi_glink.c index 9bd80a2218e4..9ffea20020e7 100644 --- a/drivers/usb/typec/ucsi/ucsi_glink.c +++ b/drivers/usb/typec/ucsi/ucsi_glink.c @@ -321,7 +321,7 @@ static const struct of_device_id pmic_glink_ucsi_of_quirks[] = { { .compatible = "qcom,sc8280xp-pmic-glink", .data = &quirk_sc8280xp, }, { .compatible = "qcom,sm8350-pmic-glink", .data = &quirk_sc8180x, }, { .compatible = "qcom,sm8450-pmic-glink", .data = &quirk_sm8450, }, - { .compatible = "qcom,sm8550-pmic-glink", .data = &quirk_sc8280xp, }, + { .compatible = "qcom,sm8550-pmic-glink", .data = &quirk_sm8450, }, {} }; -- cgit v1.2.3-59-g8ed1b From 1a395af9d53c6240bf7799abc43b4dc292ca9dd0 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Mon, 8 Apr 2024 04:04:17 +0300 Subject: usb: typec: ucsi_glink: drop special handling for CCI_BUSY Newer Qualcomm platforms (sm8450+) successfully handle busy state and send the Command Completion after sending the Busy state. Older devices have firmware bug and can not continue after sending the CCI_BUSY state, but the command that leads to CCI_BUSY is already forbidden by the NO_PARTNER_PDOS quirk. Follow other UCSI glue drivers and drop special handling for CCI_BUSY event. Let the UCSI core properly handle this state. Signed-off-by: Dmitry Baryshkov Reviewed-by: Heikki Krogerus Link: https://lore.kernel.org/r/20240408-qcom-ucsi-fixes-bis-v1-3-716c145ca4b1@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/ucsi/ucsi_glink.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/usb/typec/ucsi/ucsi_glink.c b/drivers/usb/typec/ucsi/ucsi_glink.c index 9ffea20020e7..b91d2d15d7d9 100644 --- a/drivers/usb/typec/ucsi/ucsi_glink.c +++ b/drivers/usb/typec/ucsi/ucsi_glink.c @@ -176,7 +176,8 @@ static int pmic_glink_ucsi_sync_write(struct ucsi *__ucsi, unsigned int offset, left = wait_for_completion_timeout(&ucsi->sync_ack, 5 * HZ); if (!left) { dev_err(ucsi->dev, "timeout waiting for UCSI sync write response\n"); - ret = -ETIMEDOUT; + /* return 0 here and let core UCSI code handle the CCI_BUSY */ + ret = 0; } else if (ucsi->sync_val) { dev_err(ucsi->dev, "sync write returned: %d\n", ucsi->sync_val); } @@ -243,10 +244,7 @@ static void pmic_glink_ucsi_notify(struct work_struct *work) ucsi_connector_change(ucsi->ucsi, con_num); } - if (ucsi->sync_pending && cci & UCSI_CCI_BUSY) { - ucsi->sync_val = -EBUSY; - complete(&ucsi->sync_ack); - } else if (ucsi->sync_pending && + if (ucsi->sync_pending && (cci & (UCSI_CCI_ACK_COMPLETE | UCSI_CCI_COMMAND_COMPLETE))) { complete(&ucsi->sync_ack); } -- cgit v1.2.3-59-g8ed1b From 9643ce5e28a7649e0359aaefd08fb84390c8db23 Mon Sep 17 00:00:00 2001 From: Uri Arev Date: Tue, 5 Mar 2024 23:14:01 +0200 Subject: staging: axis-fifo: Fix indentation Warning reported by checkpatch.pl script: CHECK: Alignment should match open parenthesis Signed-off-by: Uri Arev Reviewed-by: Bagas Sanjaya Link: https://lore.kernel.org/r/20240305211416.755911-1-me@wantyapps.xyz Signed-off-by: Greg Kroah-Hartman --- drivers/staging/axis-fifo/axis-fifo.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/staging/axis-fifo/axis-fifo.c b/drivers/staging/axis-fifo/axis-fifo.c index c51818c56dd2..1bbb9a6db597 100644 --- a/drivers/staging/axis-fifo/axis-fifo.c +++ b/drivers/staging/axis-fifo/axis-fifo.c @@ -376,8 +376,8 @@ static ssize_t axis_fifo_read(struct file *f, char __user *buf, */ mutex_lock(&fifo->read_lock); ret = wait_event_interruptible_timeout(fifo->read_queue, - ioread32(fifo->base_addr + XLLF_RDFO_OFFSET), - read_timeout); + ioread32(fifo->base_addr + XLLF_RDFO_OFFSET), + read_timeout); if (ret <= 0) { if (ret == 0) { @@ -517,9 +517,9 @@ static ssize_t axis_fifo_write(struct file *f, const char __user *buf, */ mutex_lock(&fifo->write_lock); ret = wait_event_interruptible_timeout(fifo->write_queue, - ioread32(fifo->base_addr + XLLF_TDFV_OFFSET) - >= words_to_write, - write_timeout); + ioread32(fifo->base_addr + XLLF_TDFV_OFFSET) + >= words_to_write, + write_timeout); if (ret <= 0) { if (ret == 0) { -- cgit v1.2.3-59-g8ed1b From 9d343b597fb0b95659e62bf233da12c3c4d95ab1 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 27 Mar 2024 18:47:24 +0100 Subject: staging: pi433: drop driver owner assignment Core in spi_register_driver() already sets the .owner, so driver does not need to. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240327174724.519607-1-krzysztof.kozlowski@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/staging/pi433/pi433_if.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/staging/pi433/pi433_if.c b/drivers/staging/pi433/pi433_if.c index 81de98c0245a..e08cb18b9129 100644 --- a/drivers/staging/pi433/pi433_if.c +++ b/drivers/staging/pi433/pi433_if.c @@ -1366,7 +1366,6 @@ MODULE_DEVICE_TABLE(of, pi433_dt_ids); static struct spi_driver pi433_spi_driver = { .driver = { .name = "pi433", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(pi433_dt_ids), }, .probe = pi433_probe, -- cgit v1.2.3-59-g8ed1b From 30b6e72b15091134a1e33d95470d27f447260b47 Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Fri, 29 Mar 2024 12:14:58 +0100 Subject: staging: rtl8192e: remove unnecessary wrapper _rtl92e_dm_ctrl_initgain_byrssi() is just a wrapper around _rtl92e_dm_ctrl_initgain_byrssi_driver(). Using a wrapper here adds no value, remove it. Keep the name _rtl92e_dm_ctrl_initgain_byrssi(). Signed-off-by: Michael Straube Tested-by: Philipp Hortmann Link: https://lore.kernel.org/r/20240329111458.14961-1-straube.linux@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/rtl_dm.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c index 4c67bfe0e8ec..aebe67f1a46d 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c @@ -163,7 +163,6 @@ static void _rtl92e_dm_check_tx_power_tracking(struct net_device *dev); static void _rtl92e_dm_dig_init(struct net_device *dev); static void _rtl92e_dm_ctrl_initgain_byrssi(struct net_device *dev); -static void _rtl92e_dm_ctrl_initgain_byrssi_driver(struct net_device *dev); static void _rtl92e_dm_initial_gain(struct net_device *dev); static void _rtl92e_dm_pd_th(struct net_device *dev); static void _rtl92e_dm_cs_ratio(struct net_device *dev); @@ -929,11 +928,6 @@ static void _rtl92e_dm_dig_init(struct net_device *dev) dm_digtable.rx_gain_range_min = DM_DIG_MIN; } -static void _rtl92e_dm_ctrl_initgain_byrssi(struct net_device *dev) -{ - _rtl92e_dm_ctrl_initgain_byrssi_driver(dev); -} - /*----------------------------------------------------------------------------- * Function: dm_CtrlInitGainBeforeConnectByRssiAndFalseAlarm() * @@ -952,7 +946,7 @@ static void _rtl92e_dm_ctrl_initgain_byrssi(struct net_device *dev) * ******************************************************************************/ -static void _rtl92e_dm_ctrl_initgain_byrssi_driver(struct net_device *dev) +static void _rtl92e_dm_ctrl_initgain_byrssi(struct net_device *dev) { struct r8192_priv *priv = rtllib_priv(dev); u8 i; -- cgit v1.2.3-59-g8ed1b From 883295e9489aafb8b85916bd1ac947f4b19644dd Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 29 Mar 2024 18:10:57 +0100 Subject: staging: ks7010: replace open-coded module_sdio_driver() Use module_sdio_driver() instead of open-coding it. No functional difference. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240329171057.63941-1-krzysztof.kozlowski@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/staging/ks7010/ks7010_sdio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/ks7010/ks7010_sdio.c b/drivers/staging/ks7010/ks7010_sdio.c index f1d44e4955fc..8df0e77b57f6 100644 --- a/drivers/staging/ks7010/ks7010_sdio.c +++ b/drivers/staging/ks7010/ks7010_sdio.c @@ -1136,7 +1136,7 @@ static struct sdio_driver ks7010_sdio_driver = { .remove = ks7010_sdio_remove, }; -module_driver(ks7010_sdio_driver, sdio_register_driver, sdio_unregister_driver); +module_sdio_driver(ks7010_sdio_driver); MODULE_AUTHOR("Sang Engineering, Qi-Hardware, KeyStream"); MODULE_DESCRIPTION("Driver for KeyStream KS7010 based SDIO cards"); MODULE_LICENSE("GPL v2"); -- cgit v1.2.3-59-g8ed1b From ebee9ca2f59e35a60a6704a79df6477b3c84ac96 Mon Sep 17 00:00:00 2001 From: Umang Jain Date: Wed, 3 Apr 2024 10:51:00 +0530 Subject: Revert "staging: vc04_services: vchiq_core: Stop kthreads on shutdown" This reverts commit d9c60badccc183eb971e0941bb86f9475d4b9551. It has been reported that stopping kthreads corrupts the VC04 firmware and creates issues at boot time [1]. A fix-up version of this patch bac670144384 ("staging: vc04_services: Stop kthreads on .remove") [2] was also attempted but it also doesn't properly fix the TODO (i.e. clean module unload) and similar errors were observed when stopping these khthreads on RaspberryPi 3. Hence, revert the entire patch for now since it is not very clear why stopping the kthreads breaks the firmware. [1]: https://lore.kernel.org/linux-staging/CAPY8ntBaz_RGr2sboQqbuUv+xZNfRct6-sckDLYPTig_HWyXEw@mail.gmail.com/t/#me90b9a9bc91599f18cd65ceb7eedd40e5fee0cdd [2]: https://lore.kernel.org/linux-staging/171161507013.3072637.12125782507523919379@ping.linuxembedded.co.uk/T/#m1d3de7d2fa73b2447274858353bbd4a0c3a8ba14 Signed-off-by: Umang Jain Reviewed-by: Stefan Wahren Link: https://lore.kernel.org/r/20240403052100.2794-1-umang.jain@ideasonboard.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vc04_services/interface/TODO | 7 +++++++ drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c | 8 ++------ drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c | 10 +++------- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/drivers/staging/vc04_services/interface/TODO b/drivers/staging/vc04_services/interface/TODO index 57a2d6761f9b..05eb5140d096 100644 --- a/drivers/staging/vc04_services/interface/TODO +++ b/drivers/staging/vc04_services/interface/TODO @@ -16,6 +16,13 @@ some of the ones we want: to manage these buffers as dmabufs so that we can zero-copy import camera images into vc4 for rendering/display. +* Fix kernel module support + +Even the VPU firmware doesn't support a VCHI re-connect, the driver +should properly handle a module unload. This also includes that all +resources must be freed (kthreads, debugfs entries, ...) and global +variables avoided. + * Documentation A short top-down description of this driver's architecture (function of diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c index 1d21f9cfbfe5..ad506016fc93 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c @@ -726,9 +726,8 @@ void free_bulk_waiter(struct vchiq_instance *instance) int vchiq_shutdown(struct vchiq_instance *instance) { - struct vchiq_state *state = instance->state; - struct vchiq_arm_state *arm_state; int status = 0; + struct vchiq_state *state = instance->state; if (mutex_lock_killable(&state->mutex)) return -EAGAIN; @@ -740,9 +739,6 @@ int vchiq_shutdown(struct vchiq_instance *instance) dev_dbg(state->dev, "core: (%p): returning %d\n", instance, status); - arm_state = vchiq_platform_get_arm_state(state); - kthread_stop(arm_state->ka_thread); - free_bulk_waiter(instance); kfree(instance); @@ -1314,7 +1310,7 @@ vchiq_keepalive_thread_func(void *v) goto shutdown; } - while (!kthread_should_stop()) { + while (1) { long rc = 0, uc = 0; if (wait_for_completion_interruptible(&arm_state->ka_evt)) { diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c index 953ccd87f425..76c27778154a 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c @@ -1936,7 +1936,7 @@ slot_handler_func(void *v) DEBUG_INITIALISE(local); - while (!kthread_should_stop()) { + while (1) { DEBUG_COUNT(SLOT_HANDLER_COUNT); DEBUG_TRACE(SLOT_HANDLER_LINE); remote_event_wait(&state->trigger_event, &local->trigger); @@ -1978,7 +1978,7 @@ recycle_func(void *v) if (!found) return -ENOMEM; - while (!kthread_should_stop()) { + while (1) { remote_event_wait(&state->recycle_event, &local->recycle); process_free_queue(state, found, length); @@ -1997,7 +1997,7 @@ sync_func(void *v) state->remote->slot_sync); int svc_fourcc; - while (!kthread_should_stop()) { + while (1) { struct vchiq_service *service; int msgid, size; int type; @@ -2844,10 +2844,6 @@ vchiq_shutdown_internal(struct vchiq_state *state, struct vchiq_instance *instan (void)vchiq_remove_service(instance, service->handle); vchiq_service_put(service); } - - kthread_stop(state->sync_thread); - kthread_stop(state->recycle_thread); - kthread_stop(state->slot_handler_thread); } int -- cgit v1.2.3-59-g8ed1b From fdb43d131fba3e314f5cb353745a8caeefdff48b Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 28 Mar 2024 11:15:57 +0000 Subject: staging: vt6655: remove redundant assignment to variable byData Variable byData is being assigned a value that is never read, it is being re-assigned later on. The assignment is redundant and can be removed. Cleans up clang scan build warning: drivers/staging/vt6655/srom.c:67:2: warning: Value stored to 'byData' is never read [deadcode.DeadStores] Signed-off-by: Colin Ian King Tested-by: Philipp Hortmann Link: https://lore.kernel.org/r/20240328111557.761380-1-colin.i.king@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6655/srom.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/staging/vt6655/srom.c b/drivers/staging/vt6655/srom.c index 1b89d401a7eb..e80556509c58 100644 --- a/drivers/staging/vt6655/srom.c +++ b/drivers/staging/vt6655/srom.c @@ -64,7 +64,6 @@ unsigned char SROMbyReadEmbedded(void __iomem *iobase, unsigned char byData; unsigned char byOrg; - byData = 0xFF; byOrg = ioread8(iobase + MAC_REG_I2MCFG); /* turn off hardware retry for getting NACK */ iowrite8(byOrg & (~I2MCFG_NORETRY), iobase + MAC_REG_I2MCFG); -- cgit v1.2.3-59-g8ed1b From 33a470713ad589e99a989189f58d4ee1bc8df1a8 Mon Sep 17 00:00:00 2001 From: Dorine Tipo Date: Sun, 31 Mar 2024 17:05:48 +0000 Subject: staging: nvec: Fix documentation typo in nvec.c This commit corrects the spelling of "initialisation" which was misspelled as "intialisation" in the irqreturn_t nvec_interrupt() documentation. The issue was found using checkpatch. Signed-off-by: Dorine Tipo Link: https://lore.kernel.org/r/20240331170548.81409-1-dorine.a.tipo@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/nvec/nvec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/nvec/nvec.c b/drivers/staging/nvec/nvec.c index 282a664c9176..b4485b10beb8 100644 --- a/drivers/staging/nvec/nvec.c +++ b/drivers/staging/nvec/nvec.c @@ -712,7 +712,7 @@ static irqreturn_t nvec_interrupt(int irq, void *dev) * TODO: replace the udelay with a read back after each writel above * in order to work around a hardware issue, see i2c-tegra.c * - * Unfortunately, this change causes an intialisation issue with the + * Unfortunately, this change causes an initialisation issue with the * touchpad, which needs to be fixed first. */ udelay(100); -- cgit v1.2.3-59-g8ed1b From 6a0b8c0da8d8d418cde6894a104cf74e6098ddfa Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 3 Apr 2024 10:06:35 +0200 Subject: greybus: arche-ctrl: move device table to its right location The arche-ctrl has two platform drivers and three of_device_id tables, but one table is only used for the the module loader, while the other two seem to be associated with their drivers. This leads to a W=1 warning when the driver is built-in: drivers/staging/greybus/arche-platform.c:623:34: error: 'arche_combined_id' defined but not used [-Werror=unused-const-variable=] 623 | static const struct of_device_id arche_combined_id[] = { Drop the extra table and register both tables that are actually used as the ones for the module loader instead. Fixes: 7b62b61c752a ("greybus: arche-ctrl: Don't expose driver internals to arche-platform driver") Signed-off-by: Arnd Bergmann Link: https://lore.kernel.org/r/20240403080702.3509288-18-arnd@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/staging/greybus/arche-apb-ctrl.c | 1 + drivers/staging/greybus/arche-platform.c | 9 +-------- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/staging/greybus/arche-apb-ctrl.c b/drivers/staging/greybus/arche-apb-ctrl.c index 8541995008da..aa6f266b62a1 100644 --- a/drivers/staging/greybus/arche-apb-ctrl.c +++ b/drivers/staging/greybus/arche-apb-ctrl.c @@ -466,6 +466,7 @@ static const struct of_device_id arche_apb_ctrl_of_match[] = { { .compatible = "usbffff,2", }, { }, }; +MODULE_DEVICE_TABLE(of, arche_apb_ctrl_of_match); static struct platform_driver arche_apb_ctrl_device_driver = { .probe = arche_apb_ctrl_probe, diff --git a/drivers/staging/greybus/arche-platform.c b/drivers/staging/greybus/arche-platform.c index 891b75327d7f..b33977ccd527 100644 --- a/drivers/staging/greybus/arche-platform.c +++ b/drivers/staging/greybus/arche-platform.c @@ -619,14 +619,7 @@ static const struct of_device_id arche_platform_of_match[] = { { .compatible = "google,arche-platform", }, { }, }; - -static const struct of_device_id arche_combined_id[] = { - /* Use PID/VID of SVC device */ - { .compatible = "google,arche-platform", }, - { .compatible = "usbffff,2", }, - { }, -}; -MODULE_DEVICE_TABLE(of, arche_combined_id); +MODULE_DEVICE_TABLE(of, arche_platform_of_match); static struct platform_driver arche_platform_device_driver = { .probe = arche_platform_probe, -- cgit v1.2.3-59-g8ed1b From 98b6073d7ab3fd3790995118b386f7362d991dcd Mon Sep 17 00:00:00 2001 From: Prasad Pandit Date: Sat, 30 Mar 2024 09:34:11 +0530 Subject: staging: bcm2835-audio: add terminating new line to Kconfig Add terminating new line to the Kconfig file. It helps while displaying file with cat(1) command. Signed-off-by: Prasad Pandit Reviewed-by: Florian Fainelli Acked-by: Dan Carpenter Reviewed-by: Dan Carpenter Link: https://lore.kernel.org/r/20240330040411.3273337-1-ppandit@redhat.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vc04_services/bcm2835-audio/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/vc04_services/bcm2835-audio/Kconfig b/drivers/staging/vc04_services/bcm2835-audio/Kconfig index 7f22f6c85067..7fbb29d3c34d 100644 --- a/drivers/staging/vc04_services/bcm2835-audio/Kconfig +++ b/drivers/staging/vc04_services/bcm2835-audio/Kconfig @@ -8,4 +8,4 @@ config SND_BCM2835 Say Y or M if you want to support BCM2835 built in audio. This driver handles both 3.5mm and HDMI audio, by leveraging the VCHIQ messaging interface between the kernel and the firmware - running on VideoCore. \ No newline at end of file + running on VideoCore. -- cgit v1.2.3-59-g8ed1b From ed394dbf5371b03a5335a7ba1973ba124c0ced3d Mon Sep 17 00:00:00 2001 From: Philipp Hortmann Date: Thu, 4 Apr 2024 22:24:50 +0200 Subject: MAINTAINERS: vt665?: Replace Forest with Philipp as maintainer Remove Forest Bond as maintainer as this email address is not reachable anymore. Add me as I want to take care of the driver and I do have vt6655 and vt6656 hardware to test. Link: https://lore.kernel.org/linux-staging/d599cd7b-a5d6-4f2d-8744-10254b75f7e5@moroto.mountain/ Signed-off-by: Philipp Hortmann Acked-by: Dan Carpenter Link: https://lore.kernel.org/r/20240404202450.GA23408@matrix-ESPRIMO-P710 Signed-off-by: Greg Kroah-Hartman --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 7c121493f43d..15492869ac8d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -20954,7 +20954,7 @@ S: Maintained F: drivers/staging/sm750fb/ STAGING - VIA VT665X DRIVERS -M: Forest Bond +M: Philipp Hortmann S: Odd Fixes F: drivers/staging/vt665?/ -- cgit v1.2.3-59-g8ed1b From 80f91c8237398049b08c0d8f34180ef0efc00ad7 Mon Sep 17 00:00:00 2001 From: Shahar Avidar Date: Fri, 5 Apr 2024 10:39:54 +0300 Subject: staging: pi433: Rename struct pi433_device buffer field to tx_buffer. Driver holds buffers in different structs, as does the HW. Using explicit names for buffers increases readability. Signed-off-by: Shahar Avidar Reviewed-by: Dan Carpenter Link: https://lore.kernel.org/r/20240405074000.3481217-2-ikobh7@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/pi433/pi433_if.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/staging/pi433/pi433_if.c b/drivers/staging/pi433/pi433_if.c index e08cb18b9129..f64884b3a65a 100644 --- a/drivers/staging/pi433/pi433_if.c +++ b/drivers/staging/pi433/pi433_if.c @@ -89,7 +89,7 @@ struct pi433_device { struct task_struct *tx_task_struct; wait_queue_head_t tx_wait_queue; u8 free_in_fifo; - char buffer[MAX_MSG_SIZE]; + char tx_buffer[MAX_MSG_SIZE]; /* rx related values */ struct pi433_rx_cfg rx_cfg; @@ -612,8 +612,8 @@ static int pi433_tx_thread(void *data) if (tx_cfg.enable_address_byte == OPTION_ON) size++; - /* prime buffer */ - memset(device->buffer, 0, size); + /* prime tx_buffer */ + memset(device->tx_buffer, 0, size); position = 0; /* add length byte, if requested */ @@ -622,15 +622,15 @@ static int pi433_tx_thread(void *data) * according to spec, length byte itself must be * excluded from the length calculation */ - device->buffer[position++] = size - 1; + device->tx_buffer[position++] = size - 1; /* add adr byte, if requested */ if (tx_cfg.enable_address_byte == OPTION_ON) - device->buffer[position++] = tx_cfg.address_byte; + device->tx_buffer[position++] = tx_cfg.address_byte; /* finally get message data from fifo */ - retval = kfifo_out(&device->tx_fifo, &device->buffer[position], - sizeof(device->buffer) - position); + retval = kfifo_out(&device->tx_fifo, &device->tx_buffer[position], + sizeof(device->tx_buffer) - position); dev_dbg(device->dev, "read %d message byte(s) from fifo queue.\n", retval); @@ -714,7 +714,7 @@ static int pi433_tx_thread(void *data) device->free_in_fifo = 0; rf69_write_fifo(spi, - &device->buffer[position], + &device->tx_buffer[position], write_size); position += write_size; } else { @@ -722,7 +722,7 @@ static int pi433_tx_thread(void *data) device->free_in_fifo -= size; repetitions--; rf69_write_fifo(spi, - &device->buffer[position], + &device->tx_buffer[position], (size - position)); position = 0; /* reset for next repetition */ } -- cgit v1.2.3-59-g8ed1b From 6f85a70352174856992efeaaff2ac9fcf6b824a8 Mon Sep 17 00:00:00 2001 From: Shahar Avidar Date: Fri, 5 Apr 2024 10:39:55 +0300 Subject: staging: pi433: Rename struct pi433_device instances to pi433. Just as other devices use specific names for instantiation, struct_pi433 should also have a distinct name. Moreover, some other structs use the "dev" or "device" in their naming conventions for members, which can be confusing. Signed-off-by: Shahar Avidar Reviewed-by: Dan Carpenter Link: https://lore.kernel.org/r/20240405074000.3481217-3-ikobh7@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/pi433/pi433_if.c | 654 +++++++++++++++++++-------------------- 1 file changed, 327 insertions(+), 327 deletions(-) diff --git a/drivers/staging/pi433/pi433_if.c b/drivers/staging/pi433/pi433_if.c index f64884b3a65a..88889b5d5309 100644 --- a/drivers/staging/pi433/pi433_if.c +++ b/drivers/staging/pi433/pi433_if.c @@ -112,7 +112,7 @@ struct pi433_device { }; struct pi433_instance { - struct pi433_device *device; + struct pi433_device *pi433; struct pi433_tx_cfg tx_cfg; /* control flags */ @@ -124,19 +124,19 @@ struct pi433_instance { /* GPIO interrupt handlers */ static irqreturn_t DIO0_irq_handler(int irq, void *dev_id) { - struct pi433_device *device = dev_id; - - if (device->irq_state[DIO0] == DIO_PACKET_SENT) { - device->free_in_fifo = FIFO_SIZE; - dev_dbg(device->dev, "DIO0 irq: Packet sent\n"); - wake_up_interruptible(&device->fifo_wait_queue); - } else if (device->irq_state[DIO0] == DIO_RSSI_DIO0) { - dev_dbg(device->dev, "DIO0 irq: RSSI level over threshold\n"); - wake_up_interruptible(&device->rx_wait_queue); - } else if (device->irq_state[DIO0] == DIO_PAYLOAD_READY) { - dev_dbg(device->dev, "DIO0 irq: Payload ready\n"); - device->free_in_fifo = 0; - wake_up_interruptible(&device->fifo_wait_queue); + struct pi433_device *pi433 = dev_id; + + if (pi433->irq_state[DIO0] == DIO_PACKET_SENT) { + pi433->free_in_fifo = FIFO_SIZE; + dev_dbg(pi433->dev, "DIO0 irq: Packet sent\n"); + wake_up_interruptible(&pi433->fifo_wait_queue); + } else if (pi433->irq_state[DIO0] == DIO_RSSI_DIO0) { + dev_dbg(pi433->dev, "DIO0 irq: RSSI level over threshold\n"); + wake_up_interruptible(&pi433->rx_wait_queue); + } else if (pi433->irq_state[DIO0] == DIO_PAYLOAD_READY) { + dev_dbg(pi433->dev, "DIO0 irq: Payload ready\n"); + pi433->free_in_fifo = 0; + wake_up_interruptible(&pi433->fifo_wait_queue); } return IRQ_HANDLED; @@ -144,19 +144,19 @@ static irqreturn_t DIO0_irq_handler(int irq, void *dev_id) static irqreturn_t DIO1_irq_handler(int irq, void *dev_id) { - struct pi433_device *device = dev_id; + struct pi433_device *pi433 = dev_id; - if (device->irq_state[DIO1] == DIO_FIFO_NOT_EMPTY_DIO1) { - device->free_in_fifo = FIFO_SIZE; - } else if (device->irq_state[DIO1] == DIO_FIFO_LEVEL) { - if (device->rx_active) - device->free_in_fifo = FIFO_THRESHOLD - 1; + if (pi433->irq_state[DIO1] == DIO_FIFO_NOT_EMPTY_DIO1) { + pi433->free_in_fifo = FIFO_SIZE; + } else if (pi433->irq_state[DIO1] == DIO_FIFO_LEVEL) { + if (pi433->rx_active) + pi433->free_in_fifo = FIFO_THRESHOLD - 1; else - device->free_in_fifo = FIFO_SIZE - FIFO_THRESHOLD - 1; + pi433->free_in_fifo = FIFO_SIZE - FIFO_THRESHOLD - 1; } - dev_dbg(device->dev, - "DIO1 irq: %d bytes free in fifo\n", device->free_in_fifo); - wake_up_interruptible(&device->fifo_wait_queue); + dev_dbg(pi433->dev, + "DIO1 irq: %d bytes free in fifo\n", pi433->free_in_fifo); + wake_up_interruptible(&pi433->fifo_wait_queue); return IRQ_HANDLED; } @@ -164,94 +164,94 @@ static irqreturn_t DIO1_irq_handler(int irq, void *dev_id) /*-------------------------------------------------------------------------*/ static int -rf69_set_rx_cfg(struct pi433_device *dev, struct pi433_rx_cfg *rx_cfg) +rf69_set_rx_cfg(struct pi433_device *pi433, struct pi433_rx_cfg *rx_cfg) { int ret; int payload_length; /* receiver config */ - ret = rf69_set_frequency(dev->spi, rx_cfg->frequency); + ret = rf69_set_frequency(pi433->spi, rx_cfg->frequency); if (ret < 0) return ret; - ret = rf69_set_modulation(dev->spi, rx_cfg->modulation); + ret = rf69_set_modulation(pi433->spi, rx_cfg->modulation); if (ret < 0) return ret; - ret = rf69_set_bit_rate(dev->spi, rx_cfg->bit_rate); + ret = rf69_set_bit_rate(pi433->spi, rx_cfg->bit_rate); if (ret < 0) return ret; - ret = rf69_set_antenna_impedance(dev->spi, rx_cfg->antenna_impedance); + ret = rf69_set_antenna_impedance(pi433->spi, rx_cfg->antenna_impedance); if (ret < 0) return ret; - ret = rf69_set_rssi_threshold(dev->spi, rx_cfg->rssi_threshold); + ret = rf69_set_rssi_threshold(pi433->spi, rx_cfg->rssi_threshold); if (ret < 0) return ret; - ret = rf69_set_ook_threshold_dec(dev->spi, rx_cfg->threshold_decrement); + ret = rf69_set_ook_threshold_dec(pi433->spi, rx_cfg->threshold_decrement); if (ret < 0) return ret; - ret = rf69_set_bandwidth(dev->spi, rx_cfg->bw_mantisse, + ret = rf69_set_bandwidth(pi433->spi, rx_cfg->bw_mantisse, rx_cfg->bw_exponent); if (ret < 0) return ret; - ret = rf69_set_bandwidth_during_afc(dev->spi, rx_cfg->bw_mantisse, + ret = rf69_set_bandwidth_during_afc(pi433->spi, rx_cfg->bw_mantisse, rx_cfg->bw_exponent); if (ret < 0) return ret; - ret = rf69_set_dagc(dev->spi, rx_cfg->dagc); + ret = rf69_set_dagc(pi433->spi, rx_cfg->dagc); if (ret < 0) return ret; - dev->rx_bytes_to_drop = rx_cfg->bytes_to_drop; + pi433->rx_bytes_to_drop = rx_cfg->bytes_to_drop; /* packet config */ /* enable */ if (rx_cfg->enable_sync == OPTION_ON) { - ret = rf69_enable_sync(dev->spi); + ret = rf69_enable_sync(pi433->spi); if (ret < 0) return ret; - ret = rf69_set_fifo_fill_condition(dev->spi, + ret = rf69_set_fifo_fill_condition(pi433->spi, after_sync_interrupt); if (ret < 0) return ret; } else { - ret = rf69_disable_sync(dev->spi); + ret = rf69_disable_sync(pi433->spi); if (ret < 0) return ret; - ret = rf69_set_fifo_fill_condition(dev->spi, always); + ret = rf69_set_fifo_fill_condition(pi433->spi, always); if (ret < 0) return ret; } if (rx_cfg->enable_length_byte == OPTION_ON) { - ret = rf69_set_packet_format(dev->spi, packet_length_var); + ret = rf69_set_packet_format(pi433->spi, packet_length_var); if (ret < 0) return ret; } else { - ret = rf69_set_packet_format(dev->spi, packet_length_fix); + ret = rf69_set_packet_format(pi433->spi, packet_length_fix); if (ret < 0) return ret; } - ret = rf69_set_address_filtering(dev->spi, + ret = rf69_set_address_filtering(pi433->spi, rx_cfg->enable_address_filtering); if (ret < 0) return ret; if (rx_cfg->enable_crc == OPTION_ON) { - ret = rf69_enable_crc(dev->spi); + ret = rf69_enable_crc(pi433->spi); if (ret < 0) return ret; } else { - ret = rf69_disable_crc(dev->spi); + ret = rf69_disable_crc(pi433->spi); if (ret < 0) return ret; } /* lengths */ - ret = rf69_set_sync_size(dev->spi, rx_cfg->sync_length); + ret = rf69_set_sync_size(pi433->spi, rx_cfg->sync_length); if (ret < 0) return ret; if (rx_cfg->enable_length_byte == OPTION_ON) { - ret = rf69_set_payload_length(dev->spi, 0xff); + ret = rf69_set_payload_length(pi433->spi, 0xff); if (ret < 0) return ret; } else if (rx_cfg->fixed_message_length != 0) { @@ -260,26 +260,26 @@ rf69_set_rx_cfg(struct pi433_device *dev, struct pi433_rx_cfg *rx_cfg) payload_length++; if (rx_cfg->enable_address_filtering != filtering_off) payload_length++; - ret = rf69_set_payload_length(dev->spi, payload_length); + ret = rf69_set_payload_length(pi433->spi, payload_length); if (ret < 0) return ret; } else { - ret = rf69_set_payload_length(dev->spi, 0); + ret = rf69_set_payload_length(pi433->spi, 0); if (ret < 0) return ret; } /* values */ if (rx_cfg->enable_sync == OPTION_ON) { - ret = rf69_set_sync_values(dev->spi, rx_cfg->sync_pattern); + ret = rf69_set_sync_values(pi433->spi, rx_cfg->sync_pattern); if (ret < 0) return ret; } if (rx_cfg->enable_address_filtering != filtering_off) { - ret = rf69_set_node_address(dev->spi, rx_cfg->node_address); + ret = rf69_set_node_address(pi433->spi, rx_cfg->node_address); if (ret < 0) return ret; - ret = rf69_set_broadcast_address(dev->spi, + ret = rf69_set_broadcast_address(pi433->spi, rx_cfg->broadcast_address); if (ret < 0) return ret; @@ -289,76 +289,76 @@ rf69_set_rx_cfg(struct pi433_device *dev, struct pi433_rx_cfg *rx_cfg) } static int -rf69_set_tx_cfg(struct pi433_device *dev, struct pi433_tx_cfg *tx_cfg) +rf69_set_tx_cfg(struct pi433_device *pi433, struct pi433_tx_cfg *tx_cfg) { int ret; - ret = rf69_set_frequency(dev->spi, tx_cfg->frequency); + ret = rf69_set_frequency(pi433->spi, tx_cfg->frequency); if (ret < 0) return ret; - ret = rf69_set_modulation(dev->spi, tx_cfg->modulation); + ret = rf69_set_modulation(pi433->spi, tx_cfg->modulation); if (ret < 0) return ret; - ret = rf69_set_bit_rate(dev->spi, tx_cfg->bit_rate); + ret = rf69_set_bit_rate(pi433->spi, tx_cfg->bit_rate); if (ret < 0) return ret; - ret = rf69_set_deviation(dev->spi, tx_cfg->dev_frequency); + ret = rf69_set_deviation(pi433->spi, tx_cfg->dev_frequency); if (ret < 0) return ret; - ret = rf69_set_pa_ramp(dev->spi, tx_cfg->pa_ramp); + ret = rf69_set_pa_ramp(pi433->spi, tx_cfg->pa_ramp); if (ret < 0) return ret; - ret = rf69_set_modulation_shaping(dev->spi, tx_cfg->mod_shaping); + ret = rf69_set_modulation_shaping(pi433->spi, tx_cfg->mod_shaping); if (ret < 0) return ret; - ret = rf69_set_tx_start_condition(dev->spi, tx_cfg->tx_start_condition); + ret = rf69_set_tx_start_condition(pi433->spi, tx_cfg->tx_start_condition); if (ret < 0) return ret; /* packet format enable */ if (tx_cfg->enable_preamble == OPTION_ON) { - ret = rf69_set_preamble_length(dev->spi, + ret = rf69_set_preamble_length(pi433->spi, tx_cfg->preamble_length); if (ret < 0) return ret; } else { - ret = rf69_set_preamble_length(dev->spi, 0); + ret = rf69_set_preamble_length(pi433->spi, 0); if (ret < 0) return ret; } if (tx_cfg->enable_sync == OPTION_ON) { - ret = rf69_set_sync_size(dev->spi, tx_cfg->sync_length); + ret = rf69_set_sync_size(pi433->spi, tx_cfg->sync_length); if (ret < 0) return ret; - ret = rf69_set_sync_values(dev->spi, tx_cfg->sync_pattern); + ret = rf69_set_sync_values(pi433->spi, tx_cfg->sync_pattern); if (ret < 0) return ret; - ret = rf69_enable_sync(dev->spi); + ret = rf69_enable_sync(pi433->spi); if (ret < 0) return ret; } else { - ret = rf69_disable_sync(dev->spi); + ret = rf69_disable_sync(pi433->spi); if (ret < 0) return ret; } if (tx_cfg->enable_length_byte == OPTION_ON) { - ret = rf69_set_packet_format(dev->spi, packet_length_var); + ret = rf69_set_packet_format(pi433->spi, packet_length_var); if (ret < 0) return ret; } else { - ret = rf69_set_packet_format(dev->spi, packet_length_fix); + ret = rf69_set_packet_format(pi433->spi, packet_length_fix); if (ret < 0) return ret; } if (tx_cfg->enable_crc == OPTION_ON) { - ret = rf69_enable_crc(dev->spi); + ret = rf69_enable_crc(pi433->spi); if (ret < 0) return ret; } else { - ret = rf69_disable_crc(dev->spi); + ret = rf69_disable_crc(pi433->spi); if (ret < 0) return ret; } @@ -368,38 +368,38 @@ rf69_set_tx_cfg(struct pi433_device *dev, struct pi433_tx_cfg *tx_cfg) /*-------------------------------------------------------------------------*/ -static int pi433_start_rx(struct pi433_device *dev) +static int pi433_start_rx(struct pi433_device *pi433) { int retval; /* return without action, if no pending read request */ - if (!dev->rx_active) + if (!pi433->rx_active) return 0; /* setup for receiving */ - retval = rf69_set_rx_cfg(dev, &dev->rx_cfg); + retval = rf69_set_rx_cfg(pi433, &pi433->rx_cfg); if (retval) return retval; /* setup rssi irq */ - retval = rf69_set_dio_mapping(dev->spi, DIO0, DIO_RSSI_DIO0); + retval = rf69_set_dio_mapping(pi433->spi, DIO0, DIO_RSSI_DIO0); if (retval < 0) return retval; - dev->irq_state[DIO0] = DIO_RSSI_DIO0; - irq_set_irq_type(dev->irq_num[DIO0], IRQ_TYPE_EDGE_RISING); + pi433->irq_state[DIO0] = DIO_RSSI_DIO0; + irq_set_irq_type(pi433->irq_num[DIO0], IRQ_TYPE_EDGE_RISING); /* setup fifo level interrupt */ - retval = rf69_set_fifo_threshold(dev->spi, FIFO_SIZE - FIFO_THRESHOLD); + retval = rf69_set_fifo_threshold(pi433->spi, FIFO_SIZE - FIFO_THRESHOLD); if (retval < 0) return retval; - retval = rf69_set_dio_mapping(dev->spi, DIO1, DIO_FIFO_LEVEL); + retval = rf69_set_dio_mapping(pi433->spi, DIO1, DIO_FIFO_LEVEL); if (retval < 0) return retval; - dev->irq_state[DIO1] = DIO_FIFO_LEVEL; - irq_set_irq_type(dev->irq_num[DIO1], IRQ_TYPE_EDGE_RISING); + pi433->irq_state[DIO1] = DIO_FIFO_LEVEL; + irq_set_irq_type(pi433->irq_num[DIO1], IRQ_TYPE_EDGE_RISING); /* set module to receiving mode */ - retval = rf69_set_mode(dev->spi, receive); + retval = rf69_set_mode(pi433->spi, receive); if (retval < 0) return retval; @@ -410,50 +410,50 @@ static int pi433_start_rx(struct pi433_device *dev) static int pi433_receive(void *data) { - struct pi433_device *dev = data; - struct spi_device *spi = dev->spi; + struct pi433_device *pi433 = data; + struct spi_device *spi = pi433->spi; int bytes_to_read, bytes_total; int retval; - dev->interrupt_rx_allowed = false; + pi433->interrupt_rx_allowed = false; /* wait for any tx to finish */ - dev_dbg(dev->dev, "rx: going to wait for any tx to finish\n"); - retval = wait_event_interruptible(dev->rx_wait_queue, !dev->tx_active); + dev_dbg(pi433->dev, "rx: going to wait for any tx to finish\n"); + retval = wait_event_interruptible(pi433->rx_wait_queue, !pi433->tx_active); if (retval) { /* wait was interrupted */ - dev->interrupt_rx_allowed = true; - wake_up_interruptible(&dev->tx_wait_queue); + pi433->interrupt_rx_allowed = true; + wake_up_interruptible(&pi433->tx_wait_queue); return retval; } /* prepare status vars */ - dev->free_in_fifo = FIFO_SIZE; - dev->rx_position = 0; - dev->rx_bytes_dropped = 0; + pi433->free_in_fifo = FIFO_SIZE; + pi433->rx_position = 0; + pi433->rx_bytes_dropped = 0; /* setup radio module to listen for something "in the air" */ - retval = pi433_start_rx(dev); + retval = pi433_start_rx(pi433); if (retval) return retval; /* now check RSSI, if low wait for getting high (RSSI interrupt) */ while (!(rf69_read_reg(spi, REG_IRQFLAGS1) & MASK_IRQFLAGS1_RSSI)) { /* allow tx to interrupt us while waiting for high RSSI */ - dev->interrupt_rx_allowed = true; - wake_up_interruptible(&dev->tx_wait_queue); + pi433->interrupt_rx_allowed = true; + wake_up_interruptible(&pi433->tx_wait_queue); /* wait for RSSI level to become high */ - dev_dbg(dev->dev, "rx: going to wait for high RSSI level\n"); - retval = wait_event_interruptible(dev->rx_wait_queue, + dev_dbg(pi433->dev, "rx: going to wait for high RSSI level\n"); + retval = wait_event_interruptible(pi433->rx_wait_queue, rf69_read_reg(spi, REG_IRQFLAGS1) & MASK_IRQFLAGS1_RSSI); if (retval) /* wait was interrupted */ goto abort; - dev->interrupt_rx_allowed = false; + pi433->interrupt_rx_allowed = false; /* cross check for ongoing tx */ - if (!dev->tx_active) + if (!pi433->tx_active) break; } @@ -461,97 +461,97 @@ static int pi433_receive(void *data) retval = rf69_set_dio_mapping(spi, DIO0, DIO_PAYLOAD_READY); if (retval < 0) goto abort; - dev->irq_state[DIO0] = DIO_PAYLOAD_READY; - irq_set_irq_type(dev->irq_num[DIO0], IRQ_TYPE_EDGE_RISING); + pi433->irq_state[DIO0] = DIO_PAYLOAD_READY; + irq_set_irq_type(pi433->irq_num[DIO0], IRQ_TYPE_EDGE_RISING); /* fixed or unlimited length? */ - if (dev->rx_cfg.fixed_message_length != 0) { - if (dev->rx_cfg.fixed_message_length > dev->rx_buffer_size) { + if (pi433->rx_cfg.fixed_message_length != 0) { + if (pi433->rx_cfg.fixed_message_length > pi433->rx_buffer_size) { retval = -1; goto abort; } - bytes_total = dev->rx_cfg.fixed_message_length; - dev_dbg(dev->dev, "rx: msg len set to %d by fixed length\n", + bytes_total = pi433->rx_cfg.fixed_message_length; + dev_dbg(pi433->dev, "rx: msg len set to %d by fixed length\n", bytes_total); } else { - bytes_total = dev->rx_buffer_size; - dev_dbg(dev->dev, "rx: msg len set to %d as requested by read\n", + bytes_total = pi433->rx_buffer_size; + dev_dbg(pi433->dev, "rx: msg len set to %d as requested by read\n", bytes_total); } /* length byte enabled? */ - if (dev->rx_cfg.enable_length_byte == OPTION_ON) { - retval = wait_event_interruptible(dev->fifo_wait_queue, - dev->free_in_fifo < FIFO_SIZE); + if (pi433->rx_cfg.enable_length_byte == OPTION_ON) { + retval = wait_event_interruptible(pi433->fifo_wait_queue, + pi433->free_in_fifo < FIFO_SIZE); if (retval) /* wait was interrupted */ goto abort; rf69_read_fifo(spi, (u8 *)&bytes_total, 1); - if (bytes_total > dev->rx_buffer_size) { + if (bytes_total > pi433->rx_buffer_size) { retval = -1; goto abort; } - dev->free_in_fifo++; - dev_dbg(dev->dev, "rx: msg len reset to %d due to length byte\n", + pi433->free_in_fifo++; + dev_dbg(pi433->dev, "rx: msg len reset to %d due to length byte\n", bytes_total); } /* address byte enabled? */ - if (dev->rx_cfg.enable_address_filtering != filtering_off) { + if (pi433->rx_cfg.enable_address_filtering != filtering_off) { u8 dummy; bytes_total--; - retval = wait_event_interruptible(dev->fifo_wait_queue, - dev->free_in_fifo < FIFO_SIZE); + retval = wait_event_interruptible(pi433->fifo_wait_queue, + pi433->free_in_fifo < FIFO_SIZE); if (retval) /* wait was interrupted */ goto abort; rf69_read_fifo(spi, &dummy, 1); - dev->free_in_fifo++; - dev_dbg(dev->dev, "rx: address byte stripped off\n"); + pi433->free_in_fifo++; + dev_dbg(pi433->dev, "rx: address byte stripped off\n"); } /* get payload */ - while (dev->rx_position < bytes_total) { + while (pi433->rx_position < bytes_total) { if (!(rf69_read_reg(spi, REG_IRQFLAGS2) & MASK_IRQFLAGS2_PAYLOAD_READY)) { - retval = wait_event_interruptible(dev->fifo_wait_queue, - dev->free_in_fifo < FIFO_SIZE); + retval = wait_event_interruptible(pi433->fifo_wait_queue, + pi433->free_in_fifo < FIFO_SIZE); if (retval) /* wait was interrupted */ goto abort; } /* need to drop bytes or acquire? */ - if (dev->rx_bytes_to_drop > dev->rx_bytes_dropped) - bytes_to_read = dev->rx_bytes_to_drop - - dev->rx_bytes_dropped; + if (pi433->rx_bytes_to_drop > pi433->rx_bytes_dropped) + bytes_to_read = pi433->rx_bytes_to_drop - + pi433->rx_bytes_dropped; else - bytes_to_read = bytes_total - dev->rx_position; + bytes_to_read = bytes_total - pi433->rx_position; /* access the fifo */ - if (bytes_to_read > FIFO_SIZE - dev->free_in_fifo) - bytes_to_read = FIFO_SIZE - dev->free_in_fifo; + if (bytes_to_read > FIFO_SIZE - pi433->free_in_fifo) + bytes_to_read = FIFO_SIZE - pi433->free_in_fifo; retval = rf69_read_fifo(spi, - &dev->rx_buffer[dev->rx_position], + &pi433->rx_buffer[pi433->rx_position], bytes_to_read); if (retval) /* read failed */ goto abort; - dev->free_in_fifo += bytes_to_read; + pi433->free_in_fifo += bytes_to_read; /* adjust status vars */ - if (dev->rx_bytes_to_drop > dev->rx_bytes_dropped) - dev->rx_bytes_dropped += bytes_to_read; + if (pi433->rx_bytes_to_drop > pi433->rx_bytes_dropped) + pi433->rx_bytes_dropped += bytes_to_read; else - dev->rx_position += bytes_to_read; + pi433->rx_position += bytes_to_read; } /* rx done, wait was interrupted or error occurred */ abort: - dev->interrupt_rx_allowed = true; - if (rf69_set_mode(dev->spi, standby)) + pi433->interrupt_rx_allowed = true; + if (rf69_set_mode(pi433->spi, standby)) pr_err("rf69_set_mode(): radio module failed to go standby\n"); - wake_up_interruptible(&dev->tx_wait_queue); + wake_up_interruptible(&pi433->tx_wait_queue); if (retval) return retval; @@ -561,8 +561,8 @@ abort: static int pi433_tx_thread(void *data) { - struct pi433_device *device = data; - struct spi_device *spi = device->spi; + struct pi433_device *pi433 = data; + struct spi_device *spi = pi433->spi; struct pi433_tx_cfg tx_cfg; size_t size; bool rx_interrupted = false; @@ -571,9 +571,9 @@ static int pi433_tx_thread(void *data) while (1) { /* wait for fifo to be populated or for request to terminate*/ - dev_dbg(device->dev, "thread: going to wait for new messages\n"); - wait_event_interruptible(device->tx_wait_queue, - (!kfifo_is_empty(&device->tx_fifo) || + dev_dbg(pi433->dev, "thread: going to wait for new messages\n"); + wait_event_interruptible(pi433->tx_wait_queue, + (!kfifo_is_empty(&pi433->tx_fifo) || kthread_should_stop())); if (kthread_should_stop()) return 0; @@ -584,17 +584,17 @@ static int pi433_tx_thread(void *data) * - size of message * - message */ - retval = kfifo_out(&device->tx_fifo, &tx_cfg, sizeof(tx_cfg)); + retval = kfifo_out(&pi433->tx_fifo, &tx_cfg, sizeof(tx_cfg)); if (retval != sizeof(tx_cfg)) { - dev_dbg(device->dev, + dev_dbg(pi433->dev, "reading tx_cfg from fifo failed: got %d byte(s), expected %d\n", retval, (unsigned int)sizeof(tx_cfg)); continue; } - retval = kfifo_out(&device->tx_fifo, &size, sizeof(size_t)); + retval = kfifo_out(&pi433->tx_fifo, &size, sizeof(size_t)); if (retval != sizeof(size_t)) { - dev_dbg(device->dev, + dev_dbg(pi433->dev, "reading msg size from fifo failed: got %d, expected %d\n", retval, (unsigned int)sizeof(size_t)); continue; @@ -613,7 +613,7 @@ static int pi433_tx_thread(void *data) size++; /* prime tx_buffer */ - memset(device->tx_buffer, 0, size); + memset(pi433->tx_buffer, 0, size); position = 0; /* add length byte, if requested */ @@ -622,16 +622,16 @@ static int pi433_tx_thread(void *data) * according to spec, length byte itself must be * excluded from the length calculation */ - device->tx_buffer[position++] = size - 1; + pi433->tx_buffer[position++] = size - 1; /* add adr byte, if requested */ if (tx_cfg.enable_address_byte == OPTION_ON) - device->tx_buffer[position++] = tx_cfg.address_byte; + pi433->tx_buffer[position++] = tx_cfg.address_byte; /* finally get message data from fifo */ - retval = kfifo_out(&device->tx_fifo, &device->tx_buffer[position], - sizeof(device->tx_buffer) - position); - dev_dbg(device->dev, + retval = kfifo_out(&pi433->tx_fifo, &pi433->tx_buffer[position], + sizeof(pi433->tx_buffer) - position); + dev_dbg(pi433->dev, "read %d message byte(s) from fifo queue.\n", retval); /* @@ -641,23 +641,23 @@ static int pi433_tx_thread(void *data) * place otherwise we need to wait for the incoming telegram * to finish */ - wait_event_interruptible(device->tx_wait_queue, - !device->rx_active || - device->interrupt_rx_allowed); + wait_event_interruptible(pi433->tx_wait_queue, + !pi433->rx_active || + pi433->interrupt_rx_allowed); /* * prevent race conditions * irq will be re-enabled after tx config is set */ - disable_irq(device->irq_num[DIO0]); - device->tx_active = true; + disable_irq(pi433->irq_num[DIO0]); + pi433->tx_active = true; /* clear fifo, set fifo threshold, set payload length */ retval = rf69_set_mode(spi, standby); /* this clears the fifo */ if (retval < 0) goto abort; - if (device->rx_active && !rx_interrupted) { + if (pi433->rx_active && !rx_interrupted) { /* * rx is currently waiting for a telegram; * we need to set the radio module to standby @@ -679,7 +679,7 @@ static int pi433_tx_thread(void *data) } /* configure the rf chip */ - retval = rf69_set_tx_cfg(device, &tx_cfg); + retval = rf69_set_tx_cfg(pi433, &tx_cfg); if (retval < 0) goto abort; @@ -687,16 +687,16 @@ static int pi433_tx_thread(void *data) retval = rf69_set_dio_mapping(spi, DIO1, DIO_FIFO_LEVEL); if (retval < 0) goto abort; - device->irq_state[DIO1] = DIO_FIFO_LEVEL; - irq_set_irq_type(device->irq_num[DIO1], IRQ_TYPE_EDGE_FALLING); + pi433->irq_state[DIO1] = DIO_FIFO_LEVEL; + irq_set_irq_type(pi433->irq_num[DIO1], IRQ_TYPE_EDGE_FALLING); /* enable packet sent interrupt */ retval = rf69_set_dio_mapping(spi, DIO0, DIO_PACKET_SENT); if (retval < 0) goto abort; - device->irq_state[DIO0] = DIO_PACKET_SENT; - irq_set_irq_type(device->irq_num[DIO0], IRQ_TYPE_EDGE_RISING); - enable_irq(device->irq_num[DIO0]); /* was disabled by rx active check */ + pi433->irq_state[DIO0] = DIO_PACKET_SENT; + irq_set_irq_type(pi433->irq_num[DIO0], IRQ_TYPE_EDGE_RISING); + enable_irq(pi433->irq_num[DIO0]); /* was disabled by rx active check */ /* enable transmission */ retval = rf69_set_mode(spi, transmit); @@ -704,61 +704,61 @@ static int pi433_tx_thread(void *data) goto abort; /* transfer this msg (and repetitions) to chip fifo */ - device->free_in_fifo = FIFO_SIZE; + pi433->free_in_fifo = FIFO_SIZE; position = 0; repetitions = tx_cfg.repetitions; while ((repetitions > 0) && (size > position)) { - if ((size - position) > device->free_in_fifo) { + if ((size - position) > pi433->free_in_fifo) { /* msg to big for fifo - take a part */ - int write_size = device->free_in_fifo; + int write_size = pi433->free_in_fifo; - device->free_in_fifo = 0; + pi433->free_in_fifo = 0; rf69_write_fifo(spi, - &device->tx_buffer[position], + &pi433->tx_buffer[position], write_size); position += write_size; } else { /* msg fits into fifo - take all */ - device->free_in_fifo -= size; + pi433->free_in_fifo -= size; repetitions--; rf69_write_fifo(spi, - &device->tx_buffer[position], + &pi433->tx_buffer[position], (size - position)); position = 0; /* reset for next repetition */ } - retval = wait_event_interruptible(device->fifo_wait_queue, - device->free_in_fifo > 0); + retval = wait_event_interruptible(pi433->fifo_wait_queue, + pi433->free_in_fifo > 0); if (retval) { - dev_dbg(device->dev, "ABORT\n"); + dev_dbg(pi433->dev, "ABORT\n"); goto abort; } } /* we are done. Wait for packet to get sent */ - dev_dbg(device->dev, + dev_dbg(pi433->dev, "thread: wait for packet to get sent/fifo to be empty\n"); - wait_event_interruptible(device->fifo_wait_queue, - device->free_in_fifo == FIFO_SIZE || + wait_event_interruptible(pi433->fifo_wait_queue, + pi433->free_in_fifo == FIFO_SIZE || kthread_should_stop()); if (kthread_should_stop()) return 0; /* STOP_TRANSMISSION */ - dev_dbg(device->dev, "thread: Packet sent. Set mode to stby.\n"); + dev_dbg(pi433->dev, "thread: Packet sent. Set mode to stby.\n"); retval = rf69_set_mode(spi, standby); if (retval < 0) goto abort; /* everything sent? */ - if (kfifo_is_empty(&device->tx_fifo)) { + if (kfifo_is_empty(&pi433->tx_fifo)) { abort: if (rx_interrupted) { rx_interrupted = false; - pi433_start_rx(device); + pi433_start_rx(pi433); } - device->tx_active = false; - wake_up_interruptible(&device->rx_wait_queue); + pi433->tx_active = false; + wake_up_interruptible(&pi433->rx_wait_queue); } } } @@ -769,7 +769,7 @@ static ssize_t pi433_read(struct file *filp, char __user *buf, size_t size, loff_t *f_pos) { struct pi433_instance *instance; - struct pi433_device *device; + struct pi433_device *pi433; int bytes_received; ssize_t retval; @@ -778,31 +778,31 @@ pi433_read(struct file *filp, char __user *buf, size_t size, loff_t *f_pos) return -EMSGSIZE; instance = filp->private_data; - device = instance->device; + pi433 = instance->pi433; /* just one read request at a time */ - mutex_lock(&device->rx_lock); - if (device->rx_active) { - mutex_unlock(&device->rx_lock); + mutex_lock(&pi433->rx_lock); + if (pi433->rx_active) { + mutex_unlock(&pi433->rx_lock); return -EAGAIN; } - device->rx_active = true; - mutex_unlock(&device->rx_lock); + pi433->rx_active = true; + mutex_unlock(&pi433->rx_lock); /* start receiving */ /* will block until something was received*/ - device->rx_buffer_size = size; - bytes_received = pi433_receive(device); + pi433->rx_buffer_size = size; + bytes_received = pi433_receive(pi433); /* release rx */ - mutex_lock(&device->rx_lock); - device->rx_active = false; - mutex_unlock(&device->rx_lock); + mutex_lock(&pi433->rx_lock); + pi433->rx_active = false; + mutex_unlock(&pi433->rx_lock); /* if read was successful copy to user space*/ if (bytes_received > 0) { - retval = copy_to_user(buf, device->rx_buffer, bytes_received); + retval = copy_to_user(buf, pi433->rx_buffer, bytes_received); if (retval) return -EFAULT; } @@ -815,12 +815,12 @@ pi433_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) { struct pi433_instance *instance; - struct pi433_device *device; + struct pi433_device *pi433; int retval; unsigned int required, available, copied; instance = filp->private_data; - device = instance->device; + pi433 = instance->pi433; /* * check, whether internal buffer (tx thread) is big enough @@ -834,7 +834,7 @@ pi433_write(struct file *filp, const char __user *buf, * config the RF trasmitter correctly due to invalid settings */ if (!instance->tx_cfg_initialized) { - dev_notice_once(device->dev, + dev_notice_once(pi433->dev, "write: failed due to unconfigured tx_cfg (see PI433_IOC_WR_TX_CFG)\n"); return -EINVAL; } @@ -845,49 +845,49 @@ pi433_write(struct file *filp, const char __user *buf, * - size of message * - message */ - mutex_lock(&device->tx_fifo_lock); + mutex_lock(&pi433->tx_fifo_lock); required = sizeof(instance->tx_cfg) + sizeof(size_t) + count; - available = kfifo_avail(&device->tx_fifo); + available = kfifo_avail(&pi433->tx_fifo); if (required > available) { - dev_dbg(device->dev, "write to fifo failed: %d bytes required but %d available\n", + dev_dbg(pi433->dev, "write to fifo failed: %d bytes required but %d available\n", required, available); - mutex_unlock(&device->tx_fifo_lock); + mutex_unlock(&pi433->tx_fifo_lock); return -EAGAIN; } - retval = kfifo_in(&device->tx_fifo, &instance->tx_cfg, + retval = kfifo_in(&pi433->tx_fifo, &instance->tx_cfg, sizeof(instance->tx_cfg)); if (retval != sizeof(instance->tx_cfg)) goto abort; - retval = kfifo_in(&device->tx_fifo, &count, sizeof(size_t)); + retval = kfifo_in(&pi433->tx_fifo, &count, sizeof(size_t)); if (retval != sizeof(size_t)) goto abort; - retval = kfifo_from_user(&device->tx_fifo, buf, count, &copied); + retval = kfifo_from_user(&pi433->tx_fifo, buf, count, &copied); if (retval || copied != count) goto abort; - mutex_unlock(&device->tx_fifo_lock); + mutex_unlock(&pi433->tx_fifo_lock); /* start transfer */ - wake_up_interruptible(&device->tx_wait_queue); - dev_dbg(device->dev, "write: generated new msg with %d bytes.\n", copied); + wake_up_interruptible(&pi433->tx_wait_queue); + dev_dbg(pi433->dev, "write: generated new msg with %d bytes.\n", copied); return copied; abort: - dev_warn(device->dev, + dev_warn(pi433->dev, "write to fifo failed, non recoverable: 0x%x\n", retval); - mutex_unlock(&device->tx_fifo_lock); + mutex_unlock(&pi433->tx_fifo_lock); return -EAGAIN; } static long pi433_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { struct pi433_instance *instance; - struct pi433_device *device; + struct pi433_device *pi433; struct pi433_tx_cfg tx_cfg; void __user *argp = (void __user *)arg; @@ -896,9 +896,9 @@ static long pi433_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) return -ENOTTY; instance = filp->private_data; - device = instance->device; + pi433 = instance->pi433; - if (!device) + if (!pi433) return -ESHUTDOWN; switch (cmd) { @@ -910,32 +910,32 @@ static long pi433_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) case PI433_IOC_WR_TX_CFG: if (copy_from_user(&tx_cfg, argp, sizeof(struct pi433_tx_cfg))) return -EFAULT; - mutex_lock(&device->tx_fifo_lock); + mutex_lock(&pi433->tx_fifo_lock); memcpy(&instance->tx_cfg, &tx_cfg, sizeof(struct pi433_tx_cfg)); instance->tx_cfg_initialized = true; - mutex_unlock(&device->tx_fifo_lock); + mutex_unlock(&pi433->tx_fifo_lock); break; case PI433_IOC_RD_RX_CFG: - if (copy_to_user(argp, &device->rx_cfg, + if (copy_to_user(argp, &pi433->rx_cfg, sizeof(struct pi433_rx_cfg))) return -EFAULT; break; case PI433_IOC_WR_RX_CFG: - mutex_lock(&device->rx_lock); + mutex_lock(&pi433->rx_lock); /* during pending read request, change of config not allowed */ - if (device->rx_active) { - mutex_unlock(&device->rx_lock); + if (pi433->rx_active) { + mutex_unlock(&pi433->rx_lock); return -EAGAIN; } - if (copy_from_user(&device->rx_cfg, argp, + if (copy_from_user(&pi433->rx_cfg, argp, sizeof(struct pi433_rx_cfg))) { - mutex_unlock(&device->rx_lock); + mutex_unlock(&pi433->rx_lock); return -EFAULT; } - mutex_unlock(&device->rx_lock); + mutex_unlock(&pi433->rx_lock); break; default: return -EINVAL; @@ -948,13 +948,13 @@ static long pi433_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) static int pi433_open(struct inode *inode, struct file *filp) { - struct pi433_device *device; + struct pi433_device *pi433; struct pi433_instance *instance; mutex_lock(&minor_lock); - device = idr_find(&pi433_idr, iminor(inode)); + pi433 = idr_find(&pi433_idr, iminor(inode)); mutex_unlock(&minor_lock); - if (!device) { + if (!pi433) { pr_debug("device: minor %d unknown.\n", iminor(inode)); return -ENODEV; } @@ -964,7 +964,7 @@ static int pi433_open(struct inode *inode, struct file *filp) return -ENOMEM; /* setup instance data*/ - instance->device = device; + instance->pi433 = pi433; /* instance data as context */ filp->private_data = instance; @@ -986,7 +986,7 @@ static int pi433_release(struct inode *inode, struct file *filp) /*-------------------------------------------------------------------------*/ -static int setup_gpio(struct pi433_device *device) +static int setup_gpio(struct pi433_device *pi433) { char name[5]; int retval; @@ -999,89 +999,89 @@ static int setup_gpio(struct pi433_device *device) for (i = 0; i < NUM_DIO; i++) { /* "construct" name and get the gpio descriptor */ snprintf(name, sizeof(name), "DIO%d", i); - device->gpiod[i] = gpiod_get(&device->spi->dev, name, - 0 /*GPIOD_IN*/); + pi433->gpiod[i] = gpiod_get(&pi433->spi->dev, name, + 0 /*GPIOD_IN*/); - if (device->gpiod[i] == ERR_PTR(-ENOENT)) { - dev_dbg(&device->spi->dev, + if (pi433->gpiod[i] == ERR_PTR(-ENOENT)) { + dev_dbg(&pi433->spi->dev, "Could not find entry for %s. Ignoring.\n", name); continue; } - if (device->gpiod[i] == ERR_PTR(-EBUSY)) - dev_dbg(&device->spi->dev, "%s is busy.\n", name); + if (pi433->gpiod[i] == ERR_PTR(-EBUSY)) + dev_dbg(&pi433->spi->dev, "%s is busy.\n", name); - if (IS_ERR(device->gpiod[i])) { - retval = PTR_ERR(device->gpiod[i]); + if (IS_ERR(pi433->gpiod[i])) { + retval = PTR_ERR(pi433->gpiod[i]); /* release already allocated gpios */ for (i--; i >= 0; i--) { - free_irq(device->irq_num[i], device); - gpiod_put(device->gpiod[i]); + free_irq(pi433->irq_num[i], pi433); + gpiod_put(pi433->gpiod[i]); } return retval; } /* configure the pin */ - retval = gpiod_direction_input(device->gpiod[i]); + retval = gpiod_direction_input(pi433->gpiod[i]); if (retval) return retval; /* configure irq */ - device->irq_num[i] = gpiod_to_irq(device->gpiod[i]); - if (device->irq_num[i] < 0) { - device->gpiod[i] = ERR_PTR(-EINVAL); - return device->irq_num[i]; + pi433->irq_num[i] = gpiod_to_irq(pi433->gpiod[i]); + if (pi433->irq_num[i] < 0) { + pi433->gpiod[i] = ERR_PTR(-EINVAL); + return pi433->irq_num[i]; } - retval = request_irq(device->irq_num[i], + retval = request_irq(pi433->irq_num[i], DIO_irq_handler[i], 0, /* flags */ name, - device); + pi433); if (retval) return retval; - dev_dbg(&device->spi->dev, "%s successfully configured\n", name); + dev_dbg(&pi433->spi->dev, "%s successfully configured\n", name); } return 0; } -static void free_gpio(struct pi433_device *device) +static void free_gpio(struct pi433_device *pi433) { int i; for (i = 0; i < NUM_DIO; i++) { /* check if gpiod is valid */ - if (IS_ERR(device->gpiod[i])) + if (IS_ERR(pi433->gpiod[i])) continue; - free_irq(device->irq_num[i], device); - gpiod_put(device->gpiod[i]); + free_irq(pi433->irq_num[i], pi433); + gpiod_put(pi433->gpiod[i]); } } -static int pi433_get_minor(struct pi433_device *device) +static int pi433_get_minor(struct pi433_device *pi433) { int retval = -ENOMEM; mutex_lock(&minor_lock); - retval = idr_alloc(&pi433_idr, device, 0, N_PI433_MINORS, GFP_KERNEL); + retval = idr_alloc(&pi433_idr, pi433, 0, N_PI433_MINORS, GFP_KERNEL); if (retval >= 0) { - device->minor = retval; + pi433->minor = retval; retval = 0; } else if (retval == -ENOSPC) { - dev_err(&device->spi->dev, "too many pi433 devices\n"); + dev_err(&pi433->spi->dev, "too many pi433 devices\n"); retval = -EINVAL; } mutex_unlock(&minor_lock); return retval; } -static void pi433_free_minor(struct pi433_device *dev) +static void pi433_free_minor(struct pi433_device *pi433) { mutex_lock(&minor_lock); - idr_remove(&pi433_idr, dev->minor); + idr_remove(&pi433_idr, pi433->minor); mutex_unlock(&minor_lock); } @@ -1105,35 +1105,35 @@ static const struct file_operations pi433_fops = { static int pi433_debugfs_regs_show(struct seq_file *m, void *p) { - struct pi433_device *dev; + struct pi433_device *pi433; u8 reg_data[114]; int i; char *fmt = "0x%02x, 0x%02x\n"; int ret; - dev = m->private; + pi433 = m->private; - mutex_lock(&dev->tx_fifo_lock); - mutex_lock(&dev->rx_lock); + mutex_lock(&pi433->tx_fifo_lock); + mutex_lock(&pi433->rx_lock); // wait for on-going operations to finish - ret = wait_event_interruptible(dev->rx_wait_queue, !dev->tx_active); + ret = wait_event_interruptible(pi433->rx_wait_queue, !pi433->tx_active); if (ret) goto out_unlock; - ret = wait_event_interruptible(dev->tx_wait_queue, !dev->rx_active); + ret = wait_event_interruptible(pi433->tx_wait_queue, !pi433->rx_active); if (ret) goto out_unlock; // skip FIFO register (0x0) otherwise this can affect some of uC ops for (i = 1; i < 0x50; i++) - reg_data[i] = rf69_read_reg(dev->spi, i); + reg_data[i] = rf69_read_reg(pi433->spi, i); - reg_data[REG_TESTLNA] = rf69_read_reg(dev->spi, REG_TESTLNA); - reg_data[REG_TESTPA1] = rf69_read_reg(dev->spi, REG_TESTPA1); - reg_data[REG_TESTPA2] = rf69_read_reg(dev->spi, REG_TESTPA2); - reg_data[REG_TESTDAGC] = rf69_read_reg(dev->spi, REG_TESTDAGC); - reg_data[REG_TESTAFC] = rf69_read_reg(dev->spi, REG_TESTAFC); + reg_data[REG_TESTLNA] = rf69_read_reg(pi433->spi, REG_TESTLNA); + reg_data[REG_TESTPA1] = rf69_read_reg(pi433->spi, REG_TESTPA1); + reg_data[REG_TESTPA2] = rf69_read_reg(pi433->spi, REG_TESTPA2); + reg_data[REG_TESTDAGC] = rf69_read_reg(pi433->spi, REG_TESTDAGC); + reg_data[REG_TESTAFC] = rf69_read_reg(pi433->spi, REG_TESTAFC); seq_puts(m, "# reg, val\n"); @@ -1147,8 +1147,8 @@ static int pi433_debugfs_regs_show(struct seq_file *m, void *p) seq_printf(m, fmt, REG_TESTAFC, reg_data[REG_TESTAFC]); out_unlock: - mutex_unlock(&dev->rx_lock); - mutex_unlock(&dev->tx_fifo_lock); + mutex_unlock(&pi433->rx_lock); + mutex_unlock(&pi433->tx_fifo_lock); return ret; } @@ -1158,7 +1158,7 @@ DEFINE_SHOW_ATTRIBUTE(pi433_debugfs_regs); static int pi433_probe(struct spi_device *spi) { - struct pi433_device *device; + struct pi433_device *pi433; int retval; struct dentry *entry; @@ -1195,37 +1195,37 @@ static int pi433_probe(struct spi_device *spi) } /* Allocate driver data */ - device = kzalloc(sizeof(*device), GFP_KERNEL); - if (!device) + pi433 = kzalloc(sizeof(*pi433), GFP_KERNEL); + if (!pi433) return -ENOMEM; /* Initialize the driver data */ - device->spi = spi; - device->rx_active = false; - device->tx_active = false; - device->interrupt_rx_allowed = false; + pi433->spi = spi; + pi433->rx_active = false; + pi433->tx_active = false; + pi433->interrupt_rx_allowed = false; /* init rx buffer */ - device->rx_buffer = kmalloc(MAX_MSG_SIZE, GFP_KERNEL); - if (!device->rx_buffer) { + pi433->rx_buffer = kmalloc(MAX_MSG_SIZE, GFP_KERNEL); + if (!pi433->rx_buffer) { retval = -ENOMEM; goto RX_failed; } /* init wait queues */ - init_waitqueue_head(&device->tx_wait_queue); - init_waitqueue_head(&device->rx_wait_queue); - init_waitqueue_head(&device->fifo_wait_queue); + init_waitqueue_head(&pi433->tx_wait_queue); + init_waitqueue_head(&pi433->rx_wait_queue); + init_waitqueue_head(&pi433->fifo_wait_queue); /* init fifo */ - INIT_KFIFO(device->tx_fifo); + INIT_KFIFO(pi433->tx_fifo); /* init mutexes and locks */ - mutex_init(&device->tx_fifo_lock); - mutex_init(&device->rx_lock); + mutex_init(&pi433->tx_fifo_lock); + mutex_init(&pi433->rx_lock); /* setup GPIO (including irq_handler) for the different DIOs */ - retval = setup_gpio(device); + retval = setup_gpio(pi433); if (retval) { dev_dbg(&spi->dev, "setup of GPIOs failed\n"); goto GPIO_failed; @@ -1255,105 +1255,105 @@ static int pi433_probe(struct spi_device *spi) goto minor_failed; /* determ minor number */ - retval = pi433_get_minor(device); + retval = pi433_get_minor(pi433); if (retval) { dev_dbg(&spi->dev, "get of minor number failed\n"); goto minor_failed; } /* create device */ - device->devt = MKDEV(MAJOR(pi433_dev), device->minor); - device->dev = device_create(&pi433_class, - &spi->dev, - device->devt, - device, - "pi433.%d", - device->minor); - if (IS_ERR(device->dev)) { + pi433->devt = MKDEV(MAJOR(pi433_dev), pi433->minor); + pi433->dev = device_create(&pi433_class, + &spi->dev, + pi433->devt, + pi433, + "pi433.%d", + pi433->minor); + if (IS_ERR(pi433->dev)) { pr_err("pi433: device register failed\n"); - retval = PTR_ERR(device->dev); + retval = PTR_ERR(pi433->dev); goto device_create_failed; } else { - dev_dbg(device->dev, + dev_dbg(pi433->dev, "created device for major %d, minor %d\n", MAJOR(pi433_dev), - device->minor); + pi433->minor); } /* start tx thread */ - device->tx_task_struct = kthread_run(pi433_tx_thread, - device, - "pi433.%d_tx_task", - device->minor); - if (IS_ERR(device->tx_task_struct)) { - dev_dbg(device->dev, "start of send thread failed\n"); - retval = PTR_ERR(device->tx_task_struct); + pi433->tx_task_struct = kthread_run(pi433_tx_thread, + pi433, + "pi433.%d_tx_task", + pi433->minor); + if (IS_ERR(pi433->tx_task_struct)) { + dev_dbg(pi433->dev, "start of send thread failed\n"); + retval = PTR_ERR(pi433->tx_task_struct); goto send_thread_failed; } /* create cdev */ - device->cdev = cdev_alloc(); - if (!device->cdev) { - dev_dbg(device->dev, "allocation of cdev failed\n"); + pi433->cdev = cdev_alloc(); + if (!pi433->cdev) { + dev_dbg(pi433->dev, "allocation of cdev failed\n"); retval = -ENOMEM; goto cdev_failed; } - device->cdev->owner = THIS_MODULE; - cdev_init(device->cdev, &pi433_fops); - retval = cdev_add(device->cdev, device->devt, 1); + pi433->cdev->owner = THIS_MODULE; + cdev_init(pi433->cdev, &pi433_fops); + retval = cdev_add(pi433->cdev, pi433->devt, 1); if (retval) { - dev_dbg(device->dev, "register of cdev failed\n"); + dev_dbg(pi433->dev, "register of cdev failed\n"); goto del_cdev; } /* spi setup */ - spi_set_drvdata(spi, device); + spi_set_drvdata(spi, pi433); - entry = debugfs_create_dir(dev_name(device->dev), root_dir); - debugfs_create_file("regs", 0400, entry, device, &pi433_debugfs_regs_fops); + entry = debugfs_create_dir(dev_name(pi433->dev), root_dir); + debugfs_create_file("regs", 0400, entry, pi433, &pi433_debugfs_regs_fops); return 0; del_cdev: - cdev_del(device->cdev); + cdev_del(pi433->cdev); cdev_failed: - kthread_stop(device->tx_task_struct); + kthread_stop(pi433->tx_task_struct); send_thread_failed: - device_destroy(&pi433_class, device->devt); + device_destroy(&pi433_class, pi433->devt); device_create_failed: - pi433_free_minor(device); + pi433_free_minor(pi433); minor_failed: - free_gpio(device); + free_gpio(pi433); GPIO_failed: - kfree(device->rx_buffer); + kfree(pi433->rx_buffer); RX_failed: - kfree(device); + kfree(pi433); return retval; } static void pi433_remove(struct spi_device *spi) { - struct pi433_device *device = spi_get_drvdata(spi); + struct pi433_device *pi433 = spi_get_drvdata(spi); - debugfs_lookup_and_remove(dev_name(device->dev), root_dir); + debugfs_lookup_and_remove(dev_name(pi433->dev), root_dir); /* free GPIOs */ - free_gpio(device); + free_gpio(pi433); /* make sure ops on existing fds can abort cleanly */ - device->spi = NULL; + pi433->spi = NULL; - kthread_stop(device->tx_task_struct); + kthread_stop(pi433->tx_task_struct); - device_destroy(&pi433_class, device->devt); + device_destroy(&pi433_class, pi433->devt); - cdev_del(device->cdev); + cdev_del(pi433->cdev); - pi433_free_minor(device); + pi433_free_minor(pi433); - kfree(device->rx_buffer); - kfree(device); + kfree(pi433->rx_buffer); + kfree(pi433); } static const struct of_device_id pi433_dt_ids[] = { -- cgit v1.2.3-59-g8ed1b From cdcf3051f0c05dab75ba46d751adede00f77c54b Mon Sep 17 00:00:00 2001 From: Shahar Avidar Date: Fri, 5 Apr 2024 10:39:56 +0300 Subject: staging: pi433: Replace pi433_receive param void type to struct pi433_device. pi433_receive is only called once. It immediately assigns the data param to a struct pi433_device. Rename param name to pi433. Signed-off-by: Shahar Avidar Reviewed-by: Dan Carpenter Link: https://lore.kernel.org/r/20240405074000.3481217-4-ikobh7@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/pi433/pi433_if.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/staging/pi433/pi433_if.c b/drivers/staging/pi433/pi433_if.c index 88889b5d5309..1e467693d546 100644 --- a/drivers/staging/pi433/pi433_if.c +++ b/drivers/staging/pi433/pi433_if.c @@ -408,9 +408,8 @@ static int pi433_start_rx(struct pi433_device *pi433) /*-------------------------------------------------------------------------*/ -static int pi433_receive(void *data) +static int pi433_receive(struct pi433_device *pi433) { - struct pi433_device *pi433 = data; struct spi_device *spi = pi433->spi; int bytes_to_read, bytes_total; int retval; -- cgit v1.2.3-59-g8ed1b From 494566f7a544ae6813bc7b41ec4e03bd62740b7c Mon Sep 17 00:00:00 2001 From: Shahar Avidar Date: Fri, 5 Apr 2024 10:39:57 +0300 Subject: staging: pi433: Rename "pi433_dev" of type "dev_t" to "pi433_devt" Distinguish struct device type instances from dev_t instances to enhance readability. Signed-off-by: Shahar Avidar Reviewed-by: Dan Carpenter Link: https://lore.kernel.org/r/20240405074000.3481217-5-ikobh7@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/pi433/pi433_if.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/staging/pi433/pi433_if.c b/drivers/staging/pi433/pi433_if.c index 1e467693d546..ac4cbeb961e9 100644 --- a/drivers/staging/pi433/pi433_if.c +++ b/drivers/staging/pi433/pi433_if.c @@ -52,7 +52,7 @@ #define FIFO_THRESHOLD 15 /* bytes */ #define NUM_DIO 2 -static dev_t pi433_dev; +static dev_t pi433_devt; static DEFINE_IDR(pi433_idr); static DEFINE_MUTEX(minor_lock); /* Protect idr accesses */ static struct dentry *root_dir; /* debugfs root directory for the driver */ @@ -1261,7 +1261,7 @@ static int pi433_probe(struct spi_device *spi) } /* create device */ - pi433->devt = MKDEV(MAJOR(pi433_dev), pi433->minor); + pi433->devt = MKDEV(MAJOR(pi433_devt), pi433->minor); pi433->dev = device_create(&pi433_class, &spi->dev, pi433->devt, @@ -1275,7 +1275,7 @@ static int pi433_probe(struct spi_device *spi) } else { dev_dbg(pi433->dev, "created device for major %d, minor %d\n", - MAJOR(pi433_dev), + MAJOR(pi433_devt), pi433->minor); } @@ -1396,13 +1396,13 @@ static int __init pi433_init(void) * that will key udev/mdev to add/remove /dev nodes. * Last, register the driver which manages those device numbers. */ - status = alloc_chrdev_region(&pi433_dev, 0, N_PI433_MINORS, "pi433"); + status = alloc_chrdev_region(&pi433_devt, 0, N_PI433_MINORS, "pi433"); if (status < 0) return status; status = class_register(&pi433_class); if (status) { - unregister_chrdev(MAJOR(pi433_dev), + unregister_chrdev(MAJOR(pi433_devt), pi433_spi_driver.driver.name); return status; } @@ -1412,7 +1412,7 @@ static int __init pi433_init(void) status = spi_register_driver(&pi433_spi_driver); if (status < 0) { class_unregister(&pi433_class); - unregister_chrdev(MAJOR(pi433_dev), + unregister_chrdev(MAJOR(pi433_devt), pi433_spi_driver.driver.name); } @@ -1425,7 +1425,7 @@ static void __exit pi433_exit(void) { spi_unregister_driver(&pi433_spi_driver); class_unregister(&pi433_class); - unregister_chrdev(MAJOR(pi433_dev), pi433_spi_driver.driver.name); + unregister_chrdev(MAJOR(pi433_devt), pi433_spi_driver.driver.name); debugfs_remove(root_dir); } module_exit(pi433_exit); -- cgit v1.2.3-59-g8ed1b From bd9ea55b228b689e79ebe09ab267a1181b384155 Mon Sep 17 00:00:00 2001 From: Shahar Avidar Date: Fri, 5 Apr 2024 10:39:58 +0300 Subject: staging: pi433: Remove duplicated code using the "goto" error recovery scheme. pi433_init had "unregister_chrdev" called twice. Remove it using goto statements. Signed-off-by: Shahar Avidar Reviewed-by: Dan Carpenter Link: https://lore.kernel.org/r/20240405074000.3481217-6-ikobh7@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/pi433/pi433_if.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/staging/pi433/pi433_if.c b/drivers/staging/pi433/pi433_if.c index ac4cbeb961e9..8aa6659936e8 100644 --- a/drivers/staging/pi433/pi433_if.c +++ b/drivers/staging/pi433/pi433_if.c @@ -1401,21 +1401,21 @@ static int __init pi433_init(void) return status; status = class_register(&pi433_class); - if (status) { - unregister_chrdev(MAJOR(pi433_devt), - pi433_spi_driver.driver.name); - return status; - } + if (status) + goto unreg_chrdev; root_dir = debugfs_create_dir(KBUILD_MODNAME, NULL); status = spi_register_driver(&pi433_spi_driver); - if (status < 0) { - class_unregister(&pi433_class); - unregister_chrdev(MAJOR(pi433_devt), - pi433_spi_driver.driver.name); - } + if (status < 0) + goto unreg_class_and_remove_dbfs; + return 0; + +unreg_class_and_remove_dbfs: + class_unregister(&pi433_class); +unreg_chrdev: + unregister_chrdev(MAJOR(pi433_devt), pi433_spi_driver.driver.name); return status; } -- cgit v1.2.3-59-g8ed1b From 78d17ecffcf41e3117a6c0408d186b99c555de76 Mon Sep 17 00:00:00 2001 From: Shahar Avidar Date: Fri, 5 Apr 2024 10:39:59 +0300 Subject: staging: pi433: Add debugfs_remove in case of driver register fails. debugfs resources were never cleaned in case of failure to register driver. Reported-by Dan Carpenter Fixes: 4ef027d5a367 ("staging: pi433: add debugfs interface") Signed-off-by: Shahar Avidar Reviewed-by: Dan Carpenter Link: https://lore.kernel.org/r/20240405074000.3481217-7-ikobh7@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/pi433/pi433_if.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/staging/pi433/pi433_if.c b/drivers/staging/pi433/pi433_if.c index 8aa6659936e8..633daf50a401 100644 --- a/drivers/staging/pi433/pi433_if.c +++ b/drivers/staging/pi433/pi433_if.c @@ -1413,6 +1413,7 @@ static int __init pi433_init(void) return 0; unreg_class_and_remove_dbfs: + debugfs_remove(root_dir); class_unregister(&pi433_class); unreg_chrdev: unregister_chrdev(MAJOR(pi433_devt), pi433_spi_driver.driver.name); -- cgit v1.2.3-59-g8ed1b From e68e319fc948aac7a67c88a2854d28c03f7891dc Mon Sep 17 00:00:00 2001 From: Shahar Avidar Date: Fri, 5 Apr 2024 10:40:00 +0300 Subject: staging: pi433: Reorder pi433_exit cleanup calls. debugfs_remove was called out of order. Ensure pi433 init & exit have reverse function calls order. Signed-off-by: Shahar Avidar Reviewed-by: Dan Carpenter Link: https://lore.kernel.org/r/20240405074000.3481217-8-ikobh7@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/pi433/pi433_if.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/pi433/pi433_if.c b/drivers/staging/pi433/pi433_if.c index 633daf50a401..befddf6bcea9 100644 --- a/drivers/staging/pi433/pi433_if.c +++ b/drivers/staging/pi433/pi433_if.c @@ -1425,9 +1425,9 @@ module_init(pi433_init); static void __exit pi433_exit(void) { spi_unregister_driver(&pi433_spi_driver); + debugfs_remove(root_dir); class_unregister(&pi433_class); unregister_chrdev(MAJOR(pi433_devt), pi433_spi_driver.driver.name); - debugfs_remove(root_dir); } module_exit(pi433_exit); -- cgit v1.2.3-59-g8ed1b From e945c43df60b50bda05800ef83d380ec34e391e2 Mon Sep 17 00:00:00 2001 From: Meir Elisha Date: Sun, 7 Apr 2024 15:38:36 +0300 Subject: Staging: rtl8723bs: Delete dead code from update_current_network() Remove dead code from rtw_mlme.c in order to improve code readability. Signed-off-by: Meir Elisha Link: https://lore.kernel.org/r/20240407123836.115055-1-meir6264@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723bs/core/rtw_mlme.c | 92 ++----------------------------- 1 file changed, 5 insertions(+), 87 deletions(-) diff --git a/drivers/staging/rtl8723bs/core/rtw_mlme.c b/drivers/staging/rtl8723bs/core/rtw_mlme.c index bfb27f902753..8c487b7b7a40 100644 --- a/drivers/staging/rtl8723bs/core/rtw_mlme.c +++ b/drivers/staging/rtl8723bs/core/rtw_mlme.c @@ -22,7 +22,6 @@ int rtw_init_mlme_priv(struct adapter *padapter) pmlmepriv->pscanned = NULL; pmlmepriv->fw_state = WIFI_STATION_STATE; /* Must sync with rtw_wdev_alloc() */ - /* wdev->iftype = NL80211_IFTYPE_STATION */ pmlmepriv->cur_network.network.infrastructure_mode = Ndis802_11AutoUnknown; pmlmepriv->scan_mode = SCAN_ACTIVE;/* 1: active, 0: passive. Maybe someday we should rename this varable to "active_mode" (Jeff) */ @@ -109,32 +108,6 @@ void _rtw_free_mlme_priv(struct mlme_priv *pmlmepriv) } } -/* -struct wlan_network *_rtw_dequeue_network(struct __queue *queue) -{ - _irqL irqL; - - struct wlan_network *pnetwork; - - spin_lock_bh(&queue->lock); - - if (list_empty(&queue->queue)) - - pnetwork = NULL; - - else - { - pnetwork = container_of(get_next(&queue->queue), struct wlan_network, list); - - list_del_init(&(pnetwork->list)); - } - - spin_unlock_bh(&queue->lock); - - return pnetwork; -} -*/ - struct wlan_network *rtw_alloc_network(struct mlme_priv *pmlmepriv) { struct wlan_network *pnetwork; @@ -207,13 +180,9 @@ void _rtw_free_network_nolock(struct mlme_priv *pmlmepriv, struct wlan_network * if (pnetwork->fixed) return; - /* spin_lock_irqsave(&free_queue->lock, irqL); */ - list_del_init(&(pnetwork->list)); list_add_tail(&(pnetwork->list), get_list_head(free_queue)); - - /* spin_unlock_irqrestore(&free_queue->lock, irqL); */ } /* @@ -231,8 +200,6 @@ struct wlan_network *_rtw_find_network(struct __queue *scanned_queue, u8 *addr) goto exit; } - /* spin_lock_bh(&scanned_queue->lock); */ - phead = get_list_head(scanned_queue); list_for_each(plist, phead) { pnetwork = list_entry(plist, struct wlan_network, list); @@ -244,8 +211,6 @@ struct wlan_network *_rtw_find_network(struct __queue *scanned_queue, u8 *addr) if (plist == phead) pnetwork = NULL; - /* spin_unlock_bh(&scanned_queue->lock); */ - exit: return pnetwork; } @@ -320,16 +285,6 @@ void rtw_free_mlme_priv(struct mlme_priv *pmlmepriv) _rtw_free_mlme_priv(pmlmepriv); } -/* -static struct wlan_network *rtw_dequeue_network(struct __queue *queue) -{ - struct wlan_network *pnetwork; - - pnetwork = _rtw_dequeue_network(queue); - return pnetwork; -} -*/ - void rtw_free_network_nolock(struct adapter *padapter, struct wlan_network *pnetwork); void rtw_free_network_nolock(struct adapter *padapter, struct wlan_network *pnetwork) { @@ -494,12 +449,9 @@ static void update_current_network(struct adapter *adapter, struct wlan_bssid_ex &(pmlmepriv->cur_network.network)); if ((check_fwstate(pmlmepriv, _FW_LINKED) == true) && (is_same_network(&(pmlmepriv->cur_network.network), pnetwork, 0))) { - /* if (pmlmepriv->cur_network.network.ie_length<= pnetwork->ie_length) */ - { - update_network(&(pmlmepriv->cur_network.network), pnetwork, adapter, true); - rtw_update_protection(adapter, (pmlmepriv->cur_network.network.ies) + sizeof(struct ndis_802_11_fix_ie), - pmlmepriv->cur_network.network.ie_length); - } + update_network(&(pmlmepriv->cur_network.network), pnetwork, adapter, true); + rtw_update_protection(adapter, (pmlmepriv->cur_network.network.ies) + sizeof(struct ndis_802_11_fix_ie), + pmlmepriv->cur_network.network.ie_length); } } @@ -540,7 +492,6 @@ void rtw_update_scanned_network(struct adapter *adapter, struct wlan_bssid_ex *t /* If we didn't find a match, then get a new network slot to initialize * with this beacon's information */ - /* if (phead == plist) { */ if (!target_find) { if (list_empty(&pmlmepriv->free_bss_pool.queue)) { /* If there are no more slots, expire the oldest */ @@ -613,15 +564,8 @@ exit: void rtw_add_network(struct adapter *adapter, struct wlan_bssid_ex *pnetwork); void rtw_add_network(struct adapter *adapter, struct wlan_bssid_ex *pnetwork) { - /* struct __queue *queue = &(pmlmepriv->scanned_queue); */ - - /* spin_lock_bh(&queue->lock); */ - update_current_network(adapter, pnetwork); - rtw_update_scanned_network(adapter, pnetwork); - - /* spin_unlock_bh(&queue->lock); */ } /* select the desired network based on the capability of the (i)bss. */ @@ -637,10 +581,7 @@ int rtw_is_desired_network(struct adapter *adapter, struct wlan_network *pnetwor struct mlme_priv *pmlmepriv = &adapter->mlmepriv; u32 desired_encmode; u32 privacy; - - /* u8 wps_ie[512]; */ uint wps_ielen; - int bselected = true; desired_encmode = psecuritypriv->ndisencryptstatus; @@ -1052,9 +993,8 @@ static struct sta_info *rtw_joinbss_update_stainfo(struct adapter *padapter, str memset((u8 *)&psta->dot11rxpn, 0, sizeof(union pn48)); } - /* Commented by Albert 2012/07/21 */ - /* When doing the WPS, the wps_ie_len won't equal to 0 */ - /* And the Wi-Fi driver shouldn't allow the data packet to be transmitted. */ + /* When doing the WPS, the wps_ie_len won't equal to 0 */ + /* And the Wi-Fi driver shouldn't allow the data packet to be transmitted. */ if (padapter->securitypriv.wps_ie_len != 0) { psta->ieee8021x_blocked = true; padapter->securitypriv.wps_ie_len = 0; @@ -1064,7 +1004,6 @@ static struct sta_info *rtw_joinbss_update_stainfo(struct adapter *padapter, str /* if A-MPDU Rx is enabled, resetting rx_ordering_ctrl wstart_b(indicate_seq) to default value = 0xffff */ /* todo: check if AP can send A-MPDU packets */ for (i = 0; i < 16 ; i++) { - /* preorder_ctrl = &precvpriv->recvreorder_ctrl[i]; */ preorder_ctrl = &psta->recvreorder_ctrl[i]; preorder_ctrl->enable = false; preorder_ctrl->indicate_seq = 0xffff; @@ -1075,7 +1014,6 @@ static struct sta_info *rtw_joinbss_update_stainfo(struct adapter *padapter, str bmc_sta = rtw_get_bcmc_stainfo(padapter); if (bmc_sta) { for (i = 0; i < 16 ; i++) { - /* preorder_ctrl = &precvpriv->recvreorder_ctrl[i]; */ preorder_ctrl = &bmc_sta->recvreorder_ctrl[i]; preorder_ctrl->enable = false; preorder_ctrl->indicate_seq = 0xffff; @@ -1239,8 +1177,6 @@ void rtw_joinbss_event_prehandle(struct adapter *adapter, u8 *pbuf) rtw_reset_securitypriv(adapter); _set_timer(&pmlmepriv->assoc_timer, 1); - /* rtw_free_assoc_resources(adapter, 1); */ - if ((check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) == true) _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); @@ -1262,7 +1198,6 @@ void rtw_joinbss_event_prehandle(struct adapter *adapter, u8 *pbuf) #endif _set_timer(&pmlmepriv->assoc_timer, 1); - /* rtw_free_assoc_resources(adapter, 1); */ _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); #ifdef REJOIN @@ -1357,7 +1292,6 @@ void rtw_stassoc_event_callback(struct adapter *adapter, u8 *pbuf) /* to do : init sta_info variable */ psta->qos_option = 0; psta->mac_id = (uint)pstassoc->cam_id; - /* psta->aid = (uint)pstassoc->cam_id; */ /* for ad-hoc mode */ rtw_hal_set_odm_var(adapter, HAL_ODM_STA_INFO, psta, true); @@ -1472,10 +1406,8 @@ void rtw_stadel_event_callback(struct adapter *adapter, u8 *pbuf) if (adapter->stapriv.asoc_sta_count == 1) {/* a sta + bc/mc_stainfo (not Ibss_stainfo) */ u8 ret = _SUCCESS; - /* rtw_indicate_disconnect(adapter);removed@20091105 */ spin_lock_bh(&(pmlmepriv->scanned_queue.lock)); /* free old ibss network */ - /* pwlan = rtw_find_network(&pmlmepriv->scanned_queue, pstadel->macaddr); */ pwlan = rtw_find_network(&pmlmepriv->scanned_queue, tgt_network->network.mac_address); if (pwlan) { pwlan->fixed = false; @@ -2088,14 +2020,6 @@ signed int rtw_restruct_sec_ie(struct adapter *adapter, u8 *in_ie, u8 *out_ie, u } else if ((authmode == WLAN_EID_VENDOR_SPECIFIC) || (authmode == WLAN_EID_RSN)) { /* copy RSN or SSN */ memcpy(&out_ie[ielength], &psecuritypriv->supplicant_ie[0], psecuritypriv->supplicant_ie[1]+2); - /* debug for CONFIG_IEEE80211W - { - int jj; - printk("supplicant_ie_length =%d &&&&&&&&&&&&&&&&&&&\n", psecuritypriv->supplicant_ie[1]+2); - for (jj = 0; jj < psecuritypriv->supplicant_ie[1]+2; jj++) - printk(" %02x ", psecuritypriv->supplicant_ie[jj]); - printk("\n"); - }*/ ielength += psecuritypriv->supplicant_ie[1]+2; rtw_report_sec_ie(adapter, authmode, psecuritypriv->supplicant_ie); } @@ -2132,7 +2056,6 @@ void rtw_update_registrypriv_dev_network(struct adapter *adapter) struct wlan_bssid_ex *pdev_network = &pregistrypriv->dev_network; struct security_priv *psecuritypriv = &adapter->securitypriv; struct wlan_network *cur_network = &adapter->mlmepriv.cur_network; - /* struct xmit_priv *pxmitpriv = &adapter->xmitpriv; */ pdev_network->privacy = (psecuritypriv->dot11PrivacyAlgrthm > 0 ? 1 : 0) ; /* adhoc no 802.1x */ @@ -2381,7 +2304,6 @@ unsigned int rtw_restructure_ht_ie(struct adapter *padapter, u8 *in_ie, u8 *out_ rtw_hal_get_def_var(padapter, HW_VAR_MAX_RX_AMPDU_FACTOR, &max_rx_ampdu_factor); - /* rtw_hal_get_def_var(padapter, HW_VAR_MAX_RX_AMPDU_FACTOR, &max_rx_ampdu_factor); */ ht_capie.ampdu_params_info = (max_rx_ampdu_factor&0x03); if (padapter->securitypriv.dot11PrivacyAlgrthm == _AES_) @@ -2411,14 +2333,10 @@ void rtw_update_ht_cap(struct adapter *padapter, u8 *pie, uint ie_len, u8 channe { u8 *p, max_ampdu_sz; int len; - /* struct sta_info *bmc_sta, *psta; */ struct ieee80211_ht_cap *pht_capie; - /* struct recv_reorder_ctrl *preorder_ctrl; */ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; struct ht_priv *phtpriv = &pmlmepriv->htpriv; - /* struct recv_priv *precvpriv = &padapter->recvpriv; */ struct registry_priv *pregistrypriv = &padapter->registrypriv; - /* struct wlan_network *pcur_network = &(pmlmepriv->cur_network);; */ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); u8 cbw40_enable = 0; -- cgit v1.2.3-59-g8ed1b From bef4c8939d51af198defa284b782e90676d6c463 Mon Sep 17 00:00:00 2001 From: Jackson Chui Date: Mon, 8 Apr 2024 15:44:40 -0700 Subject: staging: greybus: Replace gcam macros with direct dev log calls Reported by checkpatch: CHECK: Macro argument 'gcam' may be better as '(gcam)' to avoid precedence issues Inline standard calls to 'dev_*' kernel logging functions, in favor of 'gcam_*' macros, to clear up gcam-related logging. Signed-off-by: Jackson Chui Reviewed-by: Dan Carpenter Link: https://lore.kernel.org/r/ZhRzWNiak1qOdJLL@jc-ubuntu-dev-korn-1 Signed-off-by: Greg Kroah-Hartman --- drivers/staging/greybus/camera.c | 58 +++++++++++++++++++--------------------- 1 file changed, 27 insertions(+), 31 deletions(-) diff --git a/drivers/staging/greybus/camera.c b/drivers/staging/greybus/camera.c index a8173aa3a995..b8b2bdfa59e5 100644 --- a/drivers/staging/greybus/camera.c +++ b/drivers/staging/greybus/camera.c @@ -180,10 +180,6 @@ static const struct gb_camera_fmt_info *gb_camera_get_format_info(u16 gb_fmt) #define GB_CAMERA_MAX_SETTINGS_SIZE 8192 -#define gcam_dbg(gcam, format...) dev_dbg(&gcam->bundle->dev, format) -#define gcam_info(gcam, format...) dev_info(&gcam->bundle->dev, format) -#define gcam_err(gcam, format...) dev_err(&gcam->bundle->dev, format) - static int gb_camera_operation_sync_flags(struct gb_connection *connection, int type, unsigned int flags, void *request, size_t request_size, @@ -232,8 +228,8 @@ static int gb_camera_get_max_pkt_size(struct gb_camera *gcam, fmt_info = gb_camera_get_format_info(cfg->format); if (!fmt_info) { - gcam_err(gcam, "unsupported greybus image format: %d\n", - cfg->format); + dev_err(&gcam->bundle->dev, "unsupported greybus image format: %d\n", + cfg->format); return -EIO; } @@ -241,18 +237,18 @@ static int gb_camera_get_max_pkt_size(struct gb_camera *gcam, pkt_size = le32_to_cpu(cfg->max_pkt_size); if (pkt_size == 0) { - gcam_err(gcam, - "Stream %u: invalid zero maximum packet size\n", - i); + dev_err(&gcam->bundle->dev, + "Stream %u: invalid zero maximum packet size\n", + i); return -EIO; } } else { pkt_size = le16_to_cpu(cfg->width) * fmt_info->bpp / 8; if (pkt_size != le32_to_cpu(cfg->max_pkt_size)) { - gcam_err(gcam, - "Stream %u: maximum packet size mismatch (%u/%u)\n", - i, pkt_size, cfg->max_pkt_size); + dev_err(&gcam->bundle->dev, + "Stream %u: maximum packet size mismatch (%u/%u)\n", + i, pkt_size, cfg->max_pkt_size); return -EIO; } } @@ -275,13 +271,13 @@ static const int gb_camera_configure_streams_validate_response(struct gb_camera /* Validate the returned response structure */ if (resp->padding[0] || resp->padding[1]) { - gcam_err(gcam, "response padding != 0\n"); + dev_err(&gcam->bundle->dev, "response padding != 0\n"); return -EIO; } if (resp->num_streams > nstreams) { - gcam_err(gcam, "got #streams %u > request %u\n", - resp->num_streams, nstreams); + dev_err(&gcam->bundle->dev, "got #streams %u > request %u\n", + resp->num_streams, nstreams); return -EIO; } @@ -289,7 +285,7 @@ static const int gb_camera_configure_streams_validate_response(struct gb_camera struct gb_camera_stream_config_response *cfg = &resp->config[i]; if (cfg->padding) { - gcam_err(gcam, "stream #%u padding != 0\n", i); + dev_err(&gcam->bundle->dev, "stream #%u padding != 0\n", i); return -EIO; } } @@ -340,16 +336,16 @@ static int gb_camera_set_power_mode(struct gb_camera *gcam, bool hs) ret = gb_camera_set_intf_power_mode(gcam, intf->interface_id, hs); if (ret < 0) { - gcam_err(gcam, "failed to set module interface to %s (%d)\n", - hs ? "HS" : "PWM", ret); + dev_err(&gcam->bundle->dev, "failed to set module interface to %s (%d)\n", + hs ? "HS" : "PWM", ret); return ret; } ret = gb_camera_set_intf_power_mode(gcam, svc->ap_intf_id, hs); if (ret < 0) { gb_camera_set_intf_power_mode(gcam, intf->interface_id, !hs); - gcam_err(gcam, "failed to set AP interface to %s (%d)\n", - hs ? "HS" : "PWM", ret); + dev_err(&gcam->bundle->dev, "failed to set AP interface to %s (%d)\n", + hs ? "HS" : "PWM", ret); return ret; } @@ -435,7 +431,7 @@ static int gb_camera_setup_data_connection(struct gb_camera *gcam, sizeof(csi_cfg), GB_APB_REQUEST_CSI_TX_CONTROL, false); if (ret < 0) { - gcam_err(gcam, "failed to start the CSI transmitter\n"); + dev_err(&gcam->bundle->dev, "failed to start the CSI transmitter\n"); goto error_power; } @@ -470,7 +466,7 @@ static void gb_camera_teardown_data_connection(struct gb_camera *gcam) GB_APB_REQUEST_CSI_TX_CONTROL, false); if (ret < 0) - gcam_err(gcam, "failed to stop the CSI transmitter\n"); + dev_err(&gcam->bundle->dev, "failed to stop the CSI transmitter\n"); /* Set the UniPro link to low speed mode. */ gb_camera_set_power_mode(gcam, false); @@ -507,7 +503,7 @@ static int gb_camera_capabilities(struct gb_camera *gcam, NULL, 0, (void *)capabilities, size); if (ret) - gcam_err(gcam, "failed to retrieve capabilities: %d\n", ret); + dev_err(&gcam->bundle->dev, "failed to retrieve capabilities: %d\n", ret); done: mutex_unlock(&gcam->mutex); @@ -723,22 +719,22 @@ static int gb_camera_request_handler(struct gb_operation *op) struct gb_message *request; if (op->type != GB_CAMERA_TYPE_METADATA) { - gcam_err(gcam, "Unsupported unsolicited event: %u\n", op->type); + dev_err(&gcam->bundle->dev, "Unsupported unsolicited event: %u\n", op->type); return -EINVAL; } request = op->request; if (request->payload_size < sizeof(*payload)) { - gcam_err(gcam, "Wrong event size received (%zu < %zu)\n", - request->payload_size, sizeof(*payload)); + dev_err(&gcam->bundle->dev, "Wrong event size received (%zu < %zu)\n", + request->payload_size, sizeof(*payload)); return -EINVAL; } payload = request->payload; - gcam_dbg(gcam, "received metadata for request %u, frame %u, stream %u\n", - payload->request_id, payload->frame_number, payload->stream); + dev_dbg(&gcam->bundle->dev, "received metadata for request %u, frame %u, stream %u\n", + payload->request_id, payload->frame_number, payload->stream); return 0; } @@ -1347,15 +1343,15 @@ static int gb_camera_resume(struct device *dev) ret = gb_connection_enable(gcam->connection); if (ret) { - gcam_err(gcam, "failed to enable connection: %d\n", ret); + dev_err(&gcam->bundle->dev, "failed to enable connection: %d\n", ret); return ret; } if (gcam->data_connection) { ret = gb_connection_enable(gcam->data_connection); if (ret) { - gcam_err(gcam, - "failed to enable data connection: %d\n", ret); + dev_err(&gcam->bundle->dev, + "failed to enable data connection: %d\n", ret); return ret; } } -- cgit v1.2.3-59-g8ed1b From 1b61680cfe3e4dce1e4dcf41d47d92b85c3fcceb Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 8 Apr 2024 21:48:09 +0200 Subject: staging: rts5208: replace weird strncpy() with memcpy() When -Wstringop-truncation is enabled, gcc finds a function that always does a short copy: In function 'inquiry', inlined from 'rtsx_scsi_handler' at drivers/staging/rts5208/rtsx_scsi.c:3210:12: drivers/staging/rts5208/rtsx_scsi.c:526:17: error: 'strncpy' output truncated copying between 1 and 28 bytes from a string of length 28 [-Werror=stringop-truncation] 526 | strncpy(buf + 8, inquiry_string, sendbytes - 8); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The code originally had a memcpy() that would overread the source string, and commit 88a5b39b69ab ("staging/rts5208: Fix read overflow in memcpy") fixed this but introduced the warning about truncation in the process. As Dan points out, the final space in the inquiry_string always gets cut off, so remove it here for clarity, leaving exactly the 28 non-NUL characters that can get copied into the output. In the 'pro_formatter_flag' this is followed by another 20 bytes from the 'formatter_inquiry_str' array, but there the output never contains a NUL-termination, and the length is known, so memcpy() is the more logical choice. Cc: Dan Carpenter Link: https://lore.kernel.org/lkml/695be581-548f-4e5e-a211-5f3b95568e77@moroto.mountain/ Signed-off-by: Arnd Bergmann Reviewed-by: Dan Carpenter Reviewed-by: Justin Stitt Link: https://lore.kernel.org/r/20240408194821.3183462-1-arnd@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rts5208/rtsx_scsi.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/staging/rts5208/rtsx_scsi.c b/drivers/staging/rts5208/rtsx_scsi.c index 08bd768ad34d..c27cffb9ad8f 100644 --- a/drivers/staging/rts5208/rtsx_scsi.c +++ b/drivers/staging/rts5208/rtsx_scsi.c @@ -463,10 +463,10 @@ static unsigned char formatter_inquiry_str[20] = { static int inquiry(struct scsi_cmnd *srb, struct rtsx_chip *chip) { unsigned int lun = SCSI_LUN(srb); - char *inquiry_default = (char *)"Generic-xD/SD/M.S. 1.00 "; - char *inquiry_sdms = (char *)"Generic-SD/MemoryStick 1.00 "; - char *inquiry_sd = (char *)"Generic-SD/MMC 1.00 "; - char *inquiry_ms = (char *)"Generic-MemoryStick 1.00 "; + char *inquiry_default = (char *)"Generic-xD/SD/M.S. 1.00"; + char *inquiry_sdms = (char *)"Generic-SD/MemoryStick 1.00"; + char *inquiry_sd = (char *)"Generic-SD/MMC 1.00"; + char *inquiry_ms = (char *)"Generic-MemoryStick 1.00"; char *inquiry_string; unsigned char sendbytes; unsigned char *buf; @@ -523,7 +523,7 @@ static int inquiry(struct scsi_cmnd *srb, struct rtsx_chip *chip) if (sendbytes > 8) { memcpy(buf, inquiry_buf, 8); - strncpy(buf + 8, inquiry_string, sendbytes - 8); + memcpy(buf + 8, inquiry_string, min(sendbytes, 36) - 8); if (pro_formatter_flag) { /* Additional Length */ buf[4] = 0x33; -- cgit v1.2.3-59-g8ed1b From c3a8f7dfc7c3d5fa71f9038971e2081f0e3ee279 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 8 Apr 2024 21:48:10 +0200 Subject: staging: rtl8723bs: convert strncpy to strscpy gcc-9 complains about a possibly unterminated string in the strncpy() destination: In function 'rtw_cfg80211_add_monitor_if', inlined from 'cfg80211_rtw_add_virtual_intf' at drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c:2209:9: drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c:2146:2: error: 'strncpy' specified bound 16 equals destination size [-Werror=stringop-truncation] 2146 | strncpy(mon_ndev->name, name, IFNAMSIZ); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This one is a false-positive because of the explicit termination in the following line, and recent versions of clang and gcc no longer warn about this. Interestingly, the other strncpy() in this file is missing a termination but does not produce a warning, possibly because of the type confusion and the cast between u8 and char. Change both strncpy() instances to strscpy(), which avoids the warning as well as the possibly missing termination. No additional padding is needed here. Signed-off-by: Arnd Bergmann Link: https://github.com/KSPP/linux/issues/90 Reviewed-by: Justin Stitt Reviewed-by: Dan Carpenter Link: https://lore.kernel.org/r/20240408194821.3183462-2-arnd@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c | 5 ++--- drivers/staging/rtl8723bs/os_dep/os_intfs.c | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c b/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c index 65a450fcdce7..3fe27ee75b47 100644 --- a/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c +++ b/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c @@ -884,7 +884,7 @@ static int cfg80211_rtw_add_key(struct wiphy *wiphy, struct net_device *ndev, goto addkey_end; } - strncpy((char *)param->u.crypt.alg, alg_name, IEEE_CRYPT_ALG_NAME_LEN); + strscpy(param->u.crypt.alg, alg_name); if (!mac_addr || is_broadcast_ether_addr(mac_addr)) param->u.crypt.set_tx = 0; /* for wpa/wpa2 group key */ @@ -2143,8 +2143,7 @@ static int rtw_cfg80211_add_monitor_if(struct adapter *padapter, char *name, str } mon_ndev->type = ARPHRD_IEEE80211_RADIOTAP; - strncpy(mon_ndev->name, name, IFNAMSIZ); - mon_ndev->name[IFNAMSIZ - 1] = 0; + strscpy(mon_ndev->name, name); mon_ndev->needs_free_netdev = true; mon_ndev->priv_destructor = rtw_ndev_destructor; diff --git a/drivers/staging/rtl8723bs/os_dep/os_intfs.c b/drivers/staging/rtl8723bs/os_dep/os_intfs.c index 68bba3c0e757..55d0140cd543 100644 --- a/drivers/staging/rtl8723bs/os_dep/os_intfs.c +++ b/drivers/staging/rtl8723bs/os_dep/os_intfs.c @@ -415,7 +415,7 @@ static int rtw_ndev_init(struct net_device *dev) struct adapter *adapter = rtw_netdev_priv(dev); netdev_dbg(dev, FUNC_ADPT_FMT "\n", FUNC_ADPT_ARG(adapter)); - strncpy(adapter->old_ifname, dev->name, IFNAMSIZ); + strscpy(adapter->old_ifname, dev->name); return 0; } -- cgit v1.2.3-59-g8ed1b From 18f44de63f88a47ea7669a8b81708b9fa54e5d65 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 8 Apr 2024 21:48:11 +0200 Subject: staging: greybus: change strncpy() to strscpy_pad() gcc-10 warns about a strncpy() that does not enforce zero-termination: In file included from include/linux/string.h:369, from drivers/staging/greybus/fw-management.c:9: In function 'strncpy', inlined from 'fw_mgmt_backend_fw_update_operation' at drivers/staging/greybus/fw-management.c:306:2: include/linux/fortify-string.h:108:30: error: '__builtin_strncpy' specified bound 10 equals destination size [-Werror=stringop-truncation] 108 | #define __underlying_strncpy __builtin_strncpy | ^ include/linux/fortify-string.h:187:9: note: in expansion of macro '__underlying_strncpy' 187 | return __underlying_strncpy(p, q, size); | ^~~~~~~~~~~~~~~~~~~~ For some reason, I cannot reproduce this with gcc-9 or gcc-11, and I only get a warning for one of the four related strncpy()s, so I'm not sure what's going on. Change all four to strscpy_pad(), which is the safest replacement here, as it avoids ending up with uninitialized stack data in the tag name. Signed-off-by: Arnd Bergmann Reviewed-by: Dan Carpenter Reviewed-by: Justin Stitt Link: https://github.com/KSPP/linux/issues/90 [1] Link: https://lore.kernel.org/r/20240408194821.3183462-3-arnd@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/staging/greybus/fw-management.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/staging/greybus/fw-management.c b/drivers/staging/greybus/fw-management.c index 3054f084d777..a47385175582 100644 --- a/drivers/staging/greybus/fw-management.c +++ b/drivers/staging/greybus/fw-management.c @@ -123,8 +123,7 @@ static int fw_mgmt_interface_fw_version_operation(struct fw_mgmt *fw_mgmt, fw_info->major = le16_to_cpu(response.major); fw_info->minor = le16_to_cpu(response.minor); - strncpy(fw_info->firmware_tag, response.firmware_tag, - GB_FIRMWARE_TAG_MAX_SIZE); + strscpy_pad(fw_info->firmware_tag, response.firmware_tag); /* * The firmware-tag should be NULL terminated, otherwise throw error but @@ -153,7 +152,7 @@ static int fw_mgmt_load_and_validate_operation(struct fw_mgmt *fw_mgmt, } request.load_method = load_method; - strncpy(request.firmware_tag, tag, GB_FIRMWARE_TAG_MAX_SIZE); + strscpy_pad(request.firmware_tag, tag); /* * The firmware-tag should be NULL terminated, otherwise throw error and @@ -249,8 +248,7 @@ static int fw_mgmt_backend_fw_version_operation(struct fw_mgmt *fw_mgmt, struct gb_fw_mgmt_backend_fw_version_response response; int ret; - strncpy(request.firmware_tag, fw_info->firmware_tag, - GB_FIRMWARE_TAG_MAX_SIZE); + strscpy_pad(request.firmware_tag, fw_info->firmware_tag); /* * The firmware-tag should be NULL terminated, otherwise throw error and @@ -303,13 +301,13 @@ static int fw_mgmt_backend_fw_update_operation(struct fw_mgmt *fw_mgmt, struct gb_fw_mgmt_backend_fw_update_request request; int ret; - strncpy(request.firmware_tag, tag, GB_FIRMWARE_TAG_MAX_SIZE); + ret = strscpy_pad(request.firmware_tag, tag); /* * The firmware-tag should be NULL terminated, otherwise throw error and * fail. */ - if (request.firmware_tag[GB_FIRMWARE_TAG_MAX_SIZE - 1] != '\0') { + if (ret == -E2BIG) { dev_err(fw_mgmt->parent, "backend-update: firmware-tag is not NULL terminated\n"); return -EINVAL; } -- cgit v1.2.3-59-g8ed1b From 9c4319d697448e738b1e20d187d9391164c84a89 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Mon, 26 Feb 2024 16:34:48 -0800 Subject: riscv: Remove MMU dependency from Zbb and Zicboz The Zbb and Zicboz ISA extensions have no dependency on an MMU and are equally useful on NOMMU kernels. Signed-off-by: Samuel Holland Reviewed-by: Conor Dooley Link: https://lore.kernel.org/r/20240227003630.3634533-4-samuel.holland@sifive.com Signed-off-by: Palmer Dabbelt --- arch/riscv/Kconfig | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index bffbd869a068..ef53c00470d6 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -581,7 +581,6 @@ config TOOLCHAIN_HAS_ZBB config RISCV_ISA_ZBB bool "Zbb extension support for bit manipulation instructions" depends on TOOLCHAIN_HAS_ZBB - depends on MMU depends on RISCV_ALTERNATIVE default y help @@ -613,7 +612,6 @@ config RISCV_ISA_ZICBOM config RISCV_ISA_ZICBOZ bool "Zicboz extension support for faster zeroing of memory" - depends on MMU depends on RISCV_ALTERNATIVE default y help -- cgit v1.2.3-59-g8ed1b From f862bbf4cdca696ef3073c5cf3d340b778a3e42a Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Mon, 26 Feb 2024 16:34:49 -0800 Subject: riscv: Allow NOMMU kernels to run in S-mode For ease of testing, it is convenient to run NOMMU kernels in supervisor mode. The only required change is to offset the kernel load address, since the beginning of RAM is usually reserved for M-mode firmware. Signed-off-by: Samuel Holland Reviewed-by: Conor Dooley Link: https://lore.kernel.org/r/20240227003630.3634533-5-samuel.holland@sifive.com Signed-off-by: Palmer Dabbelt --- arch/riscv/Kconfig | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index ef53c00470d6..0dc09b2ac2f6 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -64,7 +64,7 @@ config RISCV select ARCH_WANTS_THP_SWAP if HAVE_ARCH_TRANSPARENT_HUGEPAGE select BINFMT_FLAT_NO_DATA_START_OFFSET if !MMU select BUILDTIME_TABLE_SORT if MMU - select CLINT_TIMER if !MMU + select CLINT_TIMER if RISCV_M_MODE select CLONE_BACKWARDS select COMMON_CLK select CPU_PM if CPU_IDLE || HIBERNATION || SUSPEND @@ -220,8 +220,12 @@ config ARCH_MMAP_RND_COMPAT_BITS_MAX # set if we run in machine mode, cleared if we run in supervisor mode config RISCV_M_MODE - bool - default !MMU + bool "Build a kernel that runs in machine mode" + depends on !MMU + default y + help + Select this option if you want to run the kernel in M-mode, + without the assistance of any other firmware. # set if we are running in S-mode and can use SBI calls config RISCV_SBI @@ -238,8 +242,9 @@ config MMU config PAGE_OFFSET hex - default 0xC0000000 if 32BIT && MMU - default 0x80000000 if !MMU + default 0x80000000 if !MMU && RISCV_M_MODE + default 0x80200000 if !MMU + default 0xc0000000 if 32BIT default 0xff60000000000000 if 64BIT config KASAN_SHADOW_OFFSET -- cgit v1.2.3-59-g8ed1b From ef5a84d716042871599ff7c8ff571a6390b99718 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Wed, 3 Apr 2024 09:46:32 +0200 Subject: dt-bindings: arm: amlogic: Document the MNT Reform 2 CM4 adapter with a BPI-CM4 Module The MNT Reform 2 CM4 adapter can be populated with any Raspberry Pi CM4 compatible module such as a BPI-CM4 Module, document that. Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20240403-amlogic-v6-4-upstream-dsi-ccf-vim3-v12-1-99ecdfdc87fc@linaro.org Signed-off-by: Neil Armstrong --- Documentation/devicetree/bindings/arm/amlogic.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/arm/amlogic.yaml b/Documentation/devicetree/bindings/arm/amlogic.yaml index 949537cea6be..b66b93b8bfd3 100644 --- a/Documentation/devicetree/bindings/arm/amlogic.yaml +++ b/Documentation/devicetree/bindings/arm/amlogic.yaml @@ -157,6 +157,7 @@ properties: items: - enum: - bananapi,bpi-cm4io + - mntre,reform2-cm4 - const: bananapi,bpi-cm4 - const: amlogic,a311d - const: amlogic,g12b -- cgit v1.2.3-59-g8ed1b From 6f1c2a12ed1138c3e680935718672d361afee372 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Wed, 3 Apr 2024 09:46:36 +0200 Subject: arm64: meson: g12-common: add the MIPI DSI nodes Add the MIPI DSI Analog & Digital PHY nodes and the DSI control nodes with proper port endpoint to the VPU. Link: https://lore.kernel.org/r/20240403-amlogic-v6-4-upstream-dsi-ccf-vim3-v12-5-99ecdfdc87fc@linaro.org Signed-off-by: Neil Armstrong --- arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi | 70 +++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi index 9d5eab6595d0..b058ed78faf0 100644 --- a/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi +++ b/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi @@ -1663,9 +1663,28 @@ <250000000>, <0>; /* Do Nothing */ }; + + mipi_analog_dphy: phy { + compatible = "amlogic,g12a-mipi-dphy-analog"; + #phy-cells = <0>; + status = "disabled"; + }; }; }; + mipi_dphy: phy@44000 { + compatible = "amlogic,axg-mipi-dphy"; + reg = <0x0 0x44000 0x0 0x2000>; + clocks = <&clkc CLKID_MIPI_DSI_PHY>; + clock-names = "pclk"; + resets = <&reset RESET_MIPI_DSI_PHY>; + reset-names = "phy"; + phys = <&mipi_analog_dphy>; + phy-names = "analog"; + #phy-cells = <0>; + status = "disabled"; + }; + usb3_pcie_phy: phy@46000 { compatible = "amlogic,g12a-usb3-pcie-phy"; reg = <0x0 0x46000 0x0 0x2000>; @@ -2152,6 +2171,15 @@ remote-endpoint = <&hdmi_tx_in>; }; }; + + /* DPI output port */ + dpi_port: port@2 { + reg = <2>; + + dpi_out: endpoint { + remote-endpoint = <&mipi_dsi_in>; + }; + }; }; gic: interrupt-controller@ffc01000 { @@ -2189,6 +2217,48 @@ amlogic,channel-interrupts = <64 65 66 67 68 69 70 71>; }; + mipi_dsi: dsi@7000 { + compatible = "amlogic,meson-g12a-dw-mipi-dsi"; + reg = <0x0 0x7000 0x0 0x1000>; + resets = <&reset RESET_MIPI_DSI_HOST>; + reset-names = "top"; + clocks = <&clkc CLKID_MIPI_DSI_HOST>, + <&clkc CLKID_MIPI_DSI_PXCLK>, + <&clkc CLKID_CTS_ENCL>; + clock-names = "pclk", "bit", "px"; + phys = <&mipi_dphy>; + phy-names = "dphy"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + + assigned-clocks = <&clkc CLKID_MIPI_DSI_PXCLK_SEL>, + <&clkc CLKID_CTS_ENCL_SEL>, + <&clkc CLKID_VCLK2_SEL>; + assigned-clock-parents = <&clkc CLKID_GP0_PLL>, + <&clkc CLKID_VCLK2_DIV1>, + <&clkc CLKID_GP0_PLL>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + /* VPU VENC Input */ + mipi_dsi_venc_port: port@0 { + reg = <0>; + + mipi_dsi_in: endpoint { + remote-endpoint = <&dpi_out>; + }; + }; + + /* DSI Output */ + mipi_dsi_panel_port: port@1 { + reg = <1>; + }; + }; + }; + watchdog: watchdog@f0d0 { compatible = "amlogic,meson-gxbb-wdt"; reg = <0x0 0xf0d0 0x0 0x10>; -- cgit v1.2.3-59-g8ed1b From 2a885bad5ba4d553758d3f1689000cee8e6dae87 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Wed, 3 Apr 2024 09:46:37 +0200 Subject: arm64: meson: khadas-vim3l: add TS050 DSI panel overlay This add dtbo overlay to support the Khadas TS050 panel on the Khadas VIM3 & VIM3L boards. Link: https://lore.kernel.org/r/20240403-amlogic-v6-4-upstream-dsi-ccf-vim3-v12-6-99ecdfdc87fc@linaro.org Signed-off-by: Neil Armstrong --- arch/arm64/boot/dts/amlogic/Makefile | 4 + .../boot/dts/amlogic/meson-khadas-vim3-ts050.dtso | 108 +++++++++++++++++++++ 2 files changed, 112 insertions(+) create mode 100644 arch/arm64/boot/dts/amlogic/meson-khadas-vim3-ts050.dtso diff --git a/arch/arm64/boot/dts/amlogic/Makefile b/arch/arm64/boot/dts/amlogic/Makefile index 1ab160bf928a..0b7961de3db7 100644 --- a/arch/arm64/boot/dts/amlogic/Makefile +++ b/arch/arm64/boot/dts/amlogic/Makefile @@ -16,6 +16,7 @@ dtb-$(CONFIG_ARCH_MESON) += meson-g12a-u200.dtb dtb-$(CONFIG_ARCH_MESON) += meson-g12a-x96-max.dtb dtb-$(CONFIG_ARCH_MESON) += meson-g12b-a311d-bananapi-m2s.dtb dtb-$(CONFIG_ARCH_MESON) += meson-g12b-a311d-khadas-vim3.dtb +dtb-$(CONFIG_ARCH_MESON) += meson-g12b-a311d-khadas-vim3-ts050.dtb dtb-$(CONFIG_ARCH_MESON) += meson-g12b-bananapi-cm4-cm4io.dtb dtb-$(CONFIG_ARCH_MESON) += meson-g12b-gsking-x.dtb dtb-$(CONFIG_ARCH_MESON) += meson-g12b-gtking-pro.dtb @@ -76,6 +77,7 @@ dtb-$(CONFIG_ARCH_MESON) += meson-sm1-bananapi-m2-pro.dtb dtb-$(CONFIG_ARCH_MESON) += meson-sm1-bananapi-m5.dtb dtb-$(CONFIG_ARCH_MESON) += meson-sm1-h96-max.dtb dtb-$(CONFIG_ARCH_MESON) += meson-sm1-khadas-vim3l.dtb +dtb-$(CONFIG_ARCH_MESON) += meson-sm1-khadas-vim3l-ts050.dtb dtb-$(CONFIG_ARCH_MESON) += meson-sm1-s905d3-libretech-cc.dtb dtb-$(CONFIG_ARCH_MESON) += meson-sm1-odroid-c4.dtb dtb-$(CONFIG_ARCH_MESON) += meson-sm1-odroid-hc4.dtb @@ -86,3 +88,5 @@ dtb-$(CONFIG_ARCH_MESON) += meson-sm1-x96-air.dtb # Overlays meson-g12a-fbx8am-brcm-dtbs := meson-g12a-fbx8am.dtb meson-g12a-fbx8am-brcm.dtbo meson-g12a-fbx8am-realtek-dtbs := meson-g12a-fbx8am.dtb meson-g12a-fbx8am-realtek.dtbo +meson-g12b-a311d-khadas-vim3-ts050-dtbs := meson-g12b-a311d-khadas-vim3.dtb meson-khadas-vim3-ts050.dtbo +meson-sm1-khadas-vim3l-ts050-dtbs := meson-sm1-khadas-vim3l.dtb meson-khadas-vim3-ts050.dtbo diff --git a/arch/arm64/boot/dts/amlogic/meson-khadas-vim3-ts050.dtso b/arch/arm64/boot/dts/amlogic/meson-khadas-vim3-ts050.dtso new file mode 100644 index 000000000000..a41b4e619580 --- /dev/null +++ b/arch/arm64/boot/dts/amlogic/meson-khadas-vim3-ts050.dtso @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2019 BayLibre, SAS + * Author: Neil Armstrong + */ + +#include +#include +#include +#include +#include + +/dts-v1/; +/plugin/; + +/* + * Enable Khadas TS050 DSI Panel + Touch Controller + * on Khadas VIM3 (A311D) and VIM3L (S905D3) + */ + +&{/} { + panel_backlight: backlight { + compatible = "pwm-backlight"; + pwms = <&pwm_AO_cd 0 25000 0>; + brightness-levels = <0 255>; + num-interpolated-steps = <255>; + default-brightness-level = <200>; + }; +}; + +&i2c3 { + #address-cells = <1>; + #size-cells = <0>; + pinctrl-0 = <&i2c3_sda_a_pins>, <&i2c3_sck_a_pins>; + pinctrl-names = "default"; + status = "okay"; + + touch-controller@38 { + compatible = "edt,edt-ft5206"; + reg = <0x38>; + interrupt-parent = <&gpio_intc>; + interrupts = ; + reset-gpios = <&gpio_expander 6 GPIO_ACTIVE_LOW>; + touchscreen-size-x = <1080>; + touchscreen-size-y = <1920>; + status = "okay"; + }; +}; + +&mipi_dsi { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + assigned-clocks = <&clkc CLKID_GP0_PLL>, + <&clkc CLKID_MIPI_DSI_PXCLK_SEL>, + <&clkc CLKID_MIPI_DSI_PXCLK>, + <&clkc CLKID_CTS_ENCL_SEL>, + <&clkc CLKID_VCLK2_SEL>; + assigned-clock-parents = <0>, + <&clkc CLKID_GP0_PLL>, + <0>, + <&clkc CLKID_VCLK2_DIV1>, + <&clkc CLKID_GP0_PLL>; + assigned-clock-rates = <960000000>, + <0>, + <960000000>, + <0>, + <0>; + + panel@0 { + compatible = "khadas,ts050"; + reset-gpios = <&gpio_expander 0 GPIO_ACTIVE_LOW>; + enable-gpios = <&gpio_expander 1 GPIO_ACTIVE_HIGH>; + power-supply = <&vcc_3v3>; + backlight = <&panel_backlight>; + reg = <0>; + + port { + mipi_in_panel: endpoint { + remote-endpoint = <&mipi_out_panel>; + }; + }; + }; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@1 { + mipi_out_panel: endpoint { + remote-endpoint = <&mipi_in_panel>; + }; + }; + }; +}; + +&mipi_analog_dphy { + status = "okay"; +}; + +&mipi_dphy { + status = "okay"; +}; + +&pwm_AO_cd { + pinctrl-0 = <&pwm_ao_c_6_pins>, <&pwm_ao_d_e_pins>; +}; -- cgit v1.2.3-59-g8ed1b From fde2d69c1626bebb3a8851909c912e582db1ca95 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Wed, 3 Apr 2024 09:46:38 +0200 Subject: arm64: dts: amlogic: meson-g12b-bananapi-cm4: add support for MNT Reform2 with CM4 adaper This adds a basic devicetree for the MNT Reform2 DIY laptop when using a CM4 adapter and a BPI-CM4 module. Co-developed-by: Lukas F. Hartmann Link: https://lore.kernel.org/r/20240403-amlogic-v6-4-upstream-dsi-ccf-vim3-v12-7-99ecdfdc87fc@linaro.org Signed-off-by: Neil Armstrong --- arch/arm64/boot/dts/amlogic/Makefile | 1 + .../meson-g12b-bananapi-cm4-mnt-reform2.dts | 384 +++++++++++++++++++++ 2 files changed, 385 insertions(+) create mode 100644 arch/arm64/boot/dts/amlogic/meson-g12b-bananapi-cm4-mnt-reform2.dts diff --git a/arch/arm64/boot/dts/amlogic/Makefile b/arch/arm64/boot/dts/amlogic/Makefile index 0b7961de3db7..d525e5123fbc 100644 --- a/arch/arm64/boot/dts/amlogic/Makefile +++ b/arch/arm64/boot/dts/amlogic/Makefile @@ -18,6 +18,7 @@ dtb-$(CONFIG_ARCH_MESON) += meson-g12b-a311d-bananapi-m2s.dtb dtb-$(CONFIG_ARCH_MESON) += meson-g12b-a311d-khadas-vim3.dtb dtb-$(CONFIG_ARCH_MESON) += meson-g12b-a311d-khadas-vim3-ts050.dtb dtb-$(CONFIG_ARCH_MESON) += meson-g12b-bananapi-cm4-cm4io.dtb +dtb-$(CONFIG_ARCH_MESON) += meson-g12b-bananapi-cm4-mnt-reform2.dtb dtb-$(CONFIG_ARCH_MESON) += meson-g12b-gsking-x.dtb dtb-$(CONFIG_ARCH_MESON) += meson-g12b-gtking-pro.dtb dtb-$(CONFIG_ARCH_MESON) += meson-g12b-gtking.dtb diff --git a/arch/arm64/boot/dts/amlogic/meson-g12b-bananapi-cm4-mnt-reform2.dts b/arch/arm64/boot/dts/amlogic/meson-g12b-bananapi-cm4-mnt-reform2.dts new file mode 100644 index 000000000000..003efed529ba --- /dev/null +++ b/arch/arm64/boot/dts/amlogic/meson-g12b-bananapi-cm4-mnt-reform2.dts @@ -0,0 +1,384 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2023 Neil Armstrong + * Copyright 2023 MNT Research GmbH + */ + +/dts-v1/; + +#include "meson-g12b-bananapi-cm4.dtsi" +#include +#include +#include + +/ { + model = "MNT Reform 2 with BPI-CM4 Module"; + compatible = "mntre,reform2-cm4", "bananapi,bpi-cm4", "amlogic,a311d", "amlogic,g12b"; + chassis-type = "laptop"; + + aliases { + ethernet0 = ðmac; + i2c0 = &i2c1; + i2c1 = &i2c3; + }; + + hdmi_connector: hdmi-connector { + compatible = "hdmi-connector"; + type = "a"; + + port { + hdmi_connector_in: endpoint { + remote-endpoint = <&hdmi_tx_tmds_out>; + }; + }; + }; + + leds { + compatible = "gpio-leds"; + + led-blue { + color = ; + function = LED_FUNCTION_STATUS; + gpios = <&gpio_ao GPIOAO_7 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "heartbeat"; + }; + + led-green { + color = ; + function = LED_FUNCTION_STATUS; + gpios = <&gpio_ao GPIOAO_2 GPIO_ACTIVE_HIGH>; + }; + }; + + sound { + compatible = "amlogic,axg-sound-card"; + model = "MNT-REFORM2-BPI-CM4"; + audio-widgets = "Headphone", "Headphone Jack", + "Speaker", "External Speaker", + "Microphone", "Mic Jack"; + audio-aux-devs = <&tdmout_a>, <&tdmout_b>, <&tdmin_b>; + audio-routing = "TDMOUT_A IN 0", "FRDDR_A OUT 0", + "TDMOUT_A IN 1", "FRDDR_B OUT 0", + "TDMOUT_A IN 2", "FRDDR_C OUT 0", + "TDM_A Playback", "TDMOUT_A OUT", + "TDMOUT_B IN 0", "FRDDR_A OUT 1", + "TDMOUT_B IN 1", "FRDDR_B OUT 1", + "TDMOUT_B IN 2", "FRDDR_C OUT 1", + "TDM_B Playback", "TDMOUT_B OUT", + "TDMIN_B IN 1", "TDM_B Capture", + "TDMIN_B IN 4", "TDM_B Loopback", + "TODDR_A IN 1", "TDMIN_B OUT", + "TODDR_B IN 1", "TDMIN_B OUT", + "TODDR_C IN 1", "TDMIN_B OUT", + "Headphone Jack", "HP_L", + "Headphone Jack", "HP_R", + "External Speaker", "SPK_LP", + "External Speaker", "SPK_LN", + "External Speaker", "SPK_RP", + "External Speaker", "SPK_RN", + "LINPUT1", "Mic Jack", + "Mic Jack", "MICB"; + + assigned-clocks = <&clkc CLKID_MPLL2>, + <&clkc CLKID_MPLL0>, + <&clkc CLKID_MPLL1>; + assigned-clock-parents = <0>, <0>, <0>; + assigned-clock-rates = <294912000>, + <270950400>, + <393216000>; + + dai-link-0 { + sound-dai = <&frddr_a>; + }; + + dai-link-1 { + sound-dai = <&frddr_b>; + }; + + dai-link-2 { + sound-dai = <&frddr_c>; + }; + + dai-link-3 { + sound-dai = <&toddr_a>; + }; + + dai-link-4 { + sound-dai = <&toddr_b>; + }; + + dai-link-5 { + sound-dai = <&toddr_c>; + }; + + /* 8ch hdmi interface */ + dai-link-6 { + sound-dai = <&tdmif_a>; + dai-format = "i2s"; + dai-tdm-slot-tx-mask-0 = <1 1>; + dai-tdm-slot-tx-mask-1 = <1 1>; + dai-tdm-slot-tx-mask-2 = <1 1>; + dai-tdm-slot-tx-mask-3 = <1 1>; + mclk-fs = <256>; + + codec { + sound-dai = <&tohdmitx TOHDMITX_I2S_IN_A>; + }; + }; + + /* Analog Audio */ + dai-link-7 { + sound-dai = <&tdmif_b>; + dai-format = "i2s"; + dai-tdm-slot-tx-mask-0 = <1 1>; + mclk-fs = <256>; + + codec { + sound-dai = <&wm8960>; + }; + }; + + /* hdmi glue */ + dai-link-8 { + sound-dai = <&tohdmitx TOHDMITX_I2S_OUT>; + + codec { + sound-dai = <&hdmi_tx>; + }; + }; + }; + + reg_main_1v8: regulator-main-1v8 { + compatible = "regulator-fixed"; + regulator-name = "1V8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + vin-supply = <®_main_3v3>; + }; + + reg_main_1v2: regulator-main-1v2 { + compatible = "regulator-fixed"; + regulator-name = "1V2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + vin-supply = <®_main_5v>; + }; + + reg_main_3v3: regulator-main-3v3 { + compatible = "regulator-fixed"; + regulator-name = "3V3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + + reg_main_5v: regulator-main-5v { + compatible = "regulator-fixed"; + regulator-name = "5V"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + }; + + reg_main_usb: regulator-main-usb { + compatible = "regulator-fixed"; + regulator-name = "USB_PWR"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <®_main_5v>; + }; + + backlight: backlight { + compatible = "pwm-backlight"; + pwms = <&pwm_AO_ab 0 10000 0>; + power-supply = <®_main_usb>; + enable-gpios = <&gpio 58 GPIO_ACTIVE_HIGH>; + brightness-levels = <0 32 64 128 160 200 255>; + default-brightness-level = <6>; + }; + + panel { + compatible = "innolux,n125hce-gn1"; + power-supply = <®_main_3v3>; + backlight = <&backlight>; + no-hpd; + + port { + panel_in: endpoint { + remote-endpoint = <&edp_bridge_out>; + }; + }; + }; + + clock_12288: clock_12288 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <12288000>; + }; +}; + +&mipi_analog_dphy { + status = "okay"; +}; + +&mipi_dphy { + status = "okay"; +}; + +&mipi_dsi { + status = "okay"; + + assigned-clocks = <&clkc CLKID_GP0_PLL>, + <&clkc CLKID_MIPI_DSI_PXCLK_SEL>, + <&clkc CLKID_MIPI_DSI_PXCLK>, + <&clkc CLKID_CTS_ENCL_SEL>, + <&clkc CLKID_VCLK2_SEL>; + assigned-clock-parents = <0>, + <&clkc CLKID_GP0_PLL>, + <0>, + <&clkc CLKID_VCLK2_DIV1>, + <&clkc CLKID_GP0_PLL>; + assigned-clock-rates = <936000000>, + <0>, + <936000000>, + <0>, + <0>; +}; + +&mipi_dsi_panel_port { + mipi_dsi_out: endpoint { + remote-endpoint = <&edp_bridge_in>; + }; +}; + +&cecb_AO { + status = "okay"; +}; + +ðmac { + status = "okay"; +}; + +&hdmi_tx { + status = "okay"; +}; + +&hdmi_tx_tmds_port { + hdmi_tx_tmds_out: endpoint { + remote-endpoint = <&hdmi_connector_in>; + }; +}; + +&pwm_AO_ab { + pinctrl-names = "default"; + pinctrl-0 = <&pwm_ao_a_pins>; + status = "okay"; +}; + +&i2c0 { + status = "okay"; +}; + +&i2c3 { + status = "okay"; + + edp_bridge: bridge@2c { + compatible = "ti,sn65dsi86"; + reg = <0x2c>; + enable-gpios = <&gpio GPIOX_10 GPIO_ACTIVE_HIGH>; // PIN_24 / GPIO8 + vccio-supply = <®_main_1v8>; + vpll-supply = <®_main_1v8>; + vcca-supply = <®_main_1v2>; + vcc-supply = <®_main_1v2>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + edp_bridge_in: endpoint { + remote-endpoint = <&mipi_dsi_out>; + }; + }; + + port@1 { + reg = <1>; + + edp_bridge_out: endpoint { + remote-endpoint = <&panel_in>; + }; + }; + }; + }; +}; + +&i2c2 { + status = "okay"; + + wm8960: codec@1a { + compatible = "wlf,wm8960"; + reg = <0x1a>; + clocks = <&clock_12288>; + clock-names = "mclk"; + #sound-dai-cells = <0>; + wlf,shared-lrclk; + }; + + rtc@68 { + compatible = "nxp,pcf8523"; + reg = <0x68>; + }; +}; + +&pcie { + status = "okay"; +}; + +&sd_emmc_b { + status = "okay"; +}; + +&tdmif_a { + status = "okay"; +}; + +&tdmout_a { + status = "okay"; +}; + +&tdmif_b { + pinctrl-0 = <&tdm_b_dout0_pins>, <&tdm_b_fs_pins>, <&tdm_b_sclk_pins>, <&tdm_b_din1_pins>; + pinctrl-names = "default"; + + assigned-clocks = <&clkc_audio AUD_CLKID_TDM_SCLK_PAD1>, + <&clkc_audio AUD_CLKID_TDM_LRCLK_PAD1>; + assigned-clock-parents = <&clkc_audio AUD_CLKID_MST_B_SCLK>, + <&clkc_audio AUD_CLKID_MST_B_LRCLK>; + assigned-clock-rates = <0>, <0>; +}; + +&tdmin_b { + status = "okay"; +}; + +&toddr_a { + status = "okay"; +}; + +&toddr_b { + status = "okay"; +}; + +&toddr_c { + status = "okay"; +}; + +&tohdmitx { + status = "okay"; +}; + +&usb { + dr_mode = "host"; + + status = "okay"; +}; -- cgit v1.2.3-59-g8ed1b From 256df20c590bf0e4d63ac69330cf23faddac3e08 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Thu, 7 Mar 2024 10:37:09 -0600 Subject: PCI/PM: Avoid D3cold for HP Pavilion 17 PC/1972 PCIe Ports Hewlett-Packard HP Pavilion 17 Notebook PC/1972 is an Intel Ivy Bridge system with a muxless AMD Radeon dGPU. Attempting to use the dGPU fails with the following sequence: ACPI Error: Aborting method \AMD3._ON due to previous error (AE_AML_LOOP_TIMEOUT) (20230628/psparse-529) radeon 0000:01:00.0: not ready 1023ms after resume; waiting radeon 0000:01:00.0: not ready 2047ms after resume; waiting radeon 0000:01:00.0: not ready 4095ms after resume; waiting radeon 0000:01:00.0: not ready 8191ms after resume; waiting radeon 0000:01:00.0: not ready 16383ms after resume; waiting radeon 0000:01:00.0: not ready 32767ms after resume; waiting radeon 0000:01:00.0: not ready 65535ms after resume; giving up radeon 0000:01:00.0: Unable to change power state from D3cold to D0, device inaccessible The issue is that the Root Port the dGPU is connected to can't handle the transition from D3cold to D0 so the dGPU can't properly exit runtime PM. The existing logic in pci_bridge_d3_possible() checks for systems that are newer than 2015 to decide that D3 is safe. This would nominally work for an Ivy Bridge system (which was discontinued in 2015), but this system appears to have continued to receive BIOS updates until 2017 and so this existing logic doesn't appropriately capture it. Add the system to bridge_d3_blacklist to prevent D3cold from being used. Link: https://lore.kernel.org/r/20240307163709.323-1-mario.limonciello@amd.com Reported-by: Eric Heintzmann Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/3229 Signed-off-by: Mario Limonciello Signed-off-by: Bjorn Helgaas Tested-by: Eric Heintzmann --- drivers/pci/pci.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index e5f243dd4288..4028717ec2ce 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -2962,6 +2962,18 @@ static const struct dmi_system_id bridge_d3_blacklist[] = { DMI_MATCH(DMI_BOARD_VERSION, "Continental Z2"), }, }, + { + /* + * Changing power state of root port dGPU is connected fails + * https://gitlab.freedesktop.org/drm/amd/-/issues/3229 + */ + .ident = "Hewlett-Packard HP Pavilion 17 Notebook PC/1972", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_BOARD_NAME, "1972"), + DMI_MATCH(DMI_BOARD_VERSION, "95.33"), + }, + }, #endif { } }; -- cgit v1.2.3-59-g8ed1b From 07db0fa80cf311be17da55e01f99d455f83a7c7b Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Wed, 20 Mar 2024 12:31:53 +0100 Subject: PCI: cadence: Set a 64-bit BAR if requested MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ever since commit f25b5fae29d4 ("PCI: endpoint: Setting a BAR size > 4 GB is invalid if 64-bit flag is not set") it has been impossible to get the .set_bar() callback with a BAR size > 2 GB (yes, 2GB!), if the BAR was also not requested to be configured as a 64-bit BAR. Thus, forcing setting the 64-bit flag for BARs larger than 2 GB in the lower level driver is dead code and can be removed. It is however possible that an EPF driver configures a BAR as 64-bit, even if the requested size is < 4 GB. Respect the requested BAR configuration, just like how it is already respected with regards to the prefetchable bit. Link: https://lore.kernel.org/linux-pci/20240320113157.322695-7-cassel@kernel.org Signed-off-by: Niklas Cassel Signed-off-by: Krzysztof Wilczyński Reviewed-by: Manivannan Sadhasivam --- drivers/pci/controller/cadence/pcie-cadence-ep.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/pci/controller/cadence/pcie-cadence-ep.c b/drivers/pci/controller/cadence/pcie-cadence-ep.c index 81c50dc64da9..068082a311c4 100644 --- a/drivers/pci/controller/cadence/pcie-cadence-ep.c +++ b/drivers/pci/controller/cadence/pcie-cadence-ep.c @@ -99,14 +99,11 @@ static int cdns_pcie_ep_set_bar(struct pci_epc *epc, u8 fn, u8 vfn, ctrl = CDNS_PCIE_LM_BAR_CFG_CTRL_IO_32BITS; } else { bool is_prefetch = !!(flags & PCI_BASE_ADDRESS_MEM_PREFETCH); - bool is_64bits = sz > SZ_2G; + bool is_64bits = !!(flags & PCI_BASE_ADDRESS_MEM_TYPE_64); if (is_64bits && (bar & 1)) return -EINVAL; - if (is_64bits && !(flags & PCI_BASE_ADDRESS_MEM_TYPE_64)) - epf_bar->flags |= PCI_BASE_ADDRESS_MEM_TYPE_64; - if (is_64bits && is_prefetch) ctrl = CDNS_PCIE_LM_BAR_CFG_CTRL_PREFETCH_MEM_64BITS; else if (is_prefetch) -- cgit v1.2.3-59-g8ed1b From de66b37a174f979cb1c7e9ba15e87f181cb5ad32 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Wed, 20 Mar 2024 12:31:54 +0100 Subject: PCI: rockchip-ep: Set a 64-bit BAR if requested MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ever since commit f25b5fae29d4 ("PCI: endpoint: Setting a BAR size > 4 GB is invalid if 64-bit flag is not set") it has been impossible to get the .set_bar() callback with a BAR size > 2 GB (yes, 2GB!), if the BAR was also not requested to be configured as a 64-bit BAR. It is however possible that an EPF driver configures a BAR as 64-bit, even if the requested size is < 4 GB. Respect the requested BAR configuration, just like how it is already respected with regards to the prefetchable bit. Link: https://lore.kernel.org/linux-pci/20240320113157.322695-8-cassel@kernel.org Signed-off-by: Niklas Cassel Signed-off-by: Krzysztof Wilczyński Reviewed-by: Manivannan Sadhasivam --- drivers/pci/controller/pcie-rockchip-ep.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/controller/pcie-rockchip-ep.c b/drivers/pci/controller/pcie-rockchip-ep.c index c9046e97a1d2..57472cf48997 100644 --- a/drivers/pci/controller/pcie-rockchip-ep.c +++ b/drivers/pci/controller/pcie-rockchip-ep.c @@ -153,7 +153,7 @@ static int rockchip_pcie_ep_set_bar(struct pci_epc *epc, u8 fn, u8 vfn, ctrl = ROCKCHIP_PCIE_CORE_BAR_CFG_CTRL_IO_32BITS; } else { bool is_prefetch = !!(flags & PCI_BASE_ADDRESS_MEM_PREFETCH); - bool is_64bits = sz > SZ_2G; + bool is_64bits = !!(flags & PCI_BASE_ADDRESS_MEM_TYPE_64); if (is_64bits && (bar & 1)) return -EINVAL; -- cgit v1.2.3-59-g8ed1b From 869bc52534065990cb57013b2bb354c0c1e66c5c Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Wed, 27 Mar 2024 14:43:30 +0530 Subject: PCI: dwc: ep: Fix DBI access failure for drivers requiring refclk from host MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The DWC glue drivers requiring an active reference clock from the PCIe host for initializing their PCIe EP core, set a flag called 'core_init_notifier' to let DWC driver know that these drivers need a special attention during initialization. In these drivers, access to the hw registers (like DBI) before receiving the active refclk from host will result in access failure and also could cause a whole system hang. But the current DWC EP driver doesn't honor the requirements of the drivers setting 'core_init_notifier' flag and tries to access the DBI registers during dw_pcie_ep_init(). This causes the system hang for glue drivers such as Tegra194 and Qcom EP as they depend on refclk from host and have set the above mentioned flag. To workaround this issue, users of the affected platforms have to maintain the dependency with the PCIe host by booting the PCIe EP after host boot. But this won't provide a good user experience, since PCIe EP is _one_ of the features of those platforms and it doesn't make sense to delay the whole platform booting due to PCIe requiring active refclk. So to fix this issue, let's move all the DBI access from dw_pcie_ep_init() in the DWC EP driver to the dw_pcie_ep_init_complete() API. This API will only be called by the drivers setting 'core_init_notifier' flag once refclk is received from host. For the rest of the drivers that gets the refclk locally, this API will be called within dw_pcie_ep_init(). Link: https://lore.kernel.org/linux-pci/20240327-pci-dbi-rework-v12-1-082625472414@linaro.org Fixes: e966f7390da9 ("PCI: dwc: Refactor core initialization code for EP mode") Co-developed-by: Vidya Sagar Signed-off-by: Vidya Sagar Signed-off-by: Manivannan Sadhasivam Signed-off-by: Krzysztof Wilczyński Reviewed-by: Frank Li Reviewed-by: Niklas Cassel --- drivers/pci/controller/dwc/pcie-designware-ep.c | 120 ++++++++++++++---------- 1 file changed, 71 insertions(+), 49 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index 746a11dcb67f..c43a1479de2c 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -604,11 +604,16 @@ static unsigned int dw_pcie_ep_find_ext_capability(struct dw_pcie *pci, int cap) int dw_pcie_ep_init_complete(struct dw_pcie_ep *ep) { struct dw_pcie *pci = to_dw_pcie_from_ep(ep); + struct dw_pcie_ep_func *ep_func; + struct device *dev = pci->dev; + struct pci_epc *epc = ep->epc; unsigned int offset, ptm_cap_base; unsigned int nbars; u8 hdr_type; + u8 func_no; + int i, ret; + void *addr; u32 reg; - int i; hdr_type = dw_pcie_readb_dbi(pci, PCI_HEADER_TYPE) & PCI_HEADER_TYPE_MASK; @@ -619,6 +624,58 @@ int dw_pcie_ep_init_complete(struct dw_pcie_ep *ep) return -EIO; } + dw_pcie_version_detect(pci); + + dw_pcie_iatu_detect(pci); + + ret = dw_pcie_edma_detect(pci); + if (ret) + return ret; + + if (!ep->ib_window_map) { + ep->ib_window_map = devm_bitmap_zalloc(dev, pci->num_ib_windows, + GFP_KERNEL); + if (!ep->ib_window_map) + goto err_remove_edma; + } + + if (!ep->ob_window_map) { + ep->ob_window_map = devm_bitmap_zalloc(dev, pci->num_ob_windows, + GFP_KERNEL); + if (!ep->ob_window_map) + goto err_remove_edma; + } + + if (!ep->outbound_addr) { + addr = devm_kcalloc(dev, pci->num_ob_windows, sizeof(phys_addr_t), + GFP_KERNEL); + if (!addr) + goto err_remove_edma; + ep->outbound_addr = addr; + } + + for (func_no = 0; func_no < epc->max_functions; func_no++) { + + ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no); + if (ep_func) + continue; + + ep_func = devm_kzalloc(dev, sizeof(*ep_func), GFP_KERNEL); + if (!ep_func) + goto err_remove_edma; + + ep_func->func_no = func_no; + ep_func->msi_cap = dw_pcie_ep_find_capability(ep, func_no, + PCI_CAP_ID_MSI); + ep_func->msix_cap = dw_pcie_ep_find_capability(ep, func_no, + PCI_CAP_ID_MSIX); + + list_add_tail(&ep_func->list, &ep->func_list); + } + + if (ep->ops->init) + ep->ops->init(ep); + offset = dw_pcie_ep_find_ext_capability(pci, PCI_EXT_CAP_ID_REBAR); ptm_cap_base = dw_pcie_ep_find_ext_capability(pci, PCI_EXT_CAP_ID_PTM); @@ -658,14 +715,17 @@ int dw_pcie_ep_init_complete(struct dw_pcie_ep *ep) dw_pcie_dbi_ro_wr_dis(pci); return 0; + +err_remove_edma: + dw_pcie_edma_remove(pci); + + return ret; } EXPORT_SYMBOL_GPL(dw_pcie_ep_init_complete); int dw_pcie_ep_init(struct dw_pcie_ep *ep) { int ret; - void *addr; - u8 func_no; struct resource *res; struct pci_epc *epc; struct dw_pcie *pci = to_dw_pcie_from_ep(ep); @@ -673,7 +733,6 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep) struct platform_device *pdev = to_platform_device(dev); struct device_node *np = dev->of_node; const struct pci_epc_features *epc_features; - struct dw_pcie_ep_func *ep_func; INIT_LIST_HEAD(&ep->func_list); @@ -691,26 +750,6 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep) if (ep->ops->pre_init) ep->ops->pre_init(ep); - dw_pcie_version_detect(pci); - - dw_pcie_iatu_detect(pci); - - ep->ib_window_map = devm_bitmap_zalloc(dev, pci->num_ib_windows, - GFP_KERNEL); - if (!ep->ib_window_map) - return -ENOMEM; - - ep->ob_window_map = devm_bitmap_zalloc(dev, pci->num_ob_windows, - GFP_KERNEL); - if (!ep->ob_window_map) - return -ENOMEM; - - addr = devm_kcalloc(dev, pci->num_ob_windows, sizeof(phys_addr_t), - GFP_KERNEL); - if (!addr) - return -ENOMEM; - ep->outbound_addr = addr; - epc = devm_pci_epc_create(dev, &epc_ops); if (IS_ERR(epc)) { dev_err(dev, "Failed to create epc device\n"); @@ -724,23 +763,6 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep) if (ret < 0) epc->max_functions = 1; - for (func_no = 0; func_no < epc->max_functions; func_no++) { - ep_func = devm_kzalloc(dev, sizeof(*ep_func), GFP_KERNEL); - if (!ep_func) - return -ENOMEM; - - ep_func->func_no = func_no; - ep_func->msi_cap = dw_pcie_ep_find_capability(ep, func_no, - PCI_CAP_ID_MSI); - ep_func->msix_cap = dw_pcie_ep_find_capability(ep, func_no, - PCI_CAP_ID_MSIX); - - list_add_tail(&ep_func->list, &ep->func_list); - } - - if (ep->ops->init) - ep->ops->init(ep); - ret = pci_epc_mem_init(epc, ep->phys_base, ep->addr_size, ep->page_size); if (ret < 0) { @@ -756,25 +778,25 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep) goto err_exit_epc_mem; } - ret = dw_pcie_edma_detect(pci); - if (ret) - goto err_free_epc_mem; - if (ep->ops->get_features) { epc_features = ep->ops->get_features(ep); if (epc_features->core_init_notifier) return 0; } + /* + * NOTE:- Avoid accessing the hardware (Ex:- DBI space) before this + * step as platforms that implement 'core_init_notifier' feature may + * not have the hardware ready (i.e. core initialized) for access + * (Ex: tegra194). Any hardware access on such platforms result + * in system hang. + */ ret = dw_pcie_ep_init_complete(ep); if (ret) - goto err_remove_edma; + goto err_free_epc_mem; return 0; -err_remove_edma: - dw_pcie_edma_remove(pci); - err_free_epc_mem: pci_epc_mem_free_addr(epc, ep->msi_mem_phys, ep->msi_mem, epc->mem->window.page_size); -- cgit v1.2.3-59-g8ed1b From 7cbebc86c72aa215802ad159d60ecaf9a20d5530 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Wed, 27 Mar 2024 14:43:31 +0530 Subject: PCI: dwc: ep: Add Kernel-doc comments for APIs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All of the APIs are missing the Kernel-doc comments. Hence, add them. Link: https://lore.kernel.org/linux-pci/20240327-pci-dbi-rework-v12-2-082625472414@linaro.org Signed-off-by: Manivannan Sadhasivam Signed-off-by: Krzysztof Wilczyński Reviewed-by: Frank Li Reviewed-by: Niklas Cassel --- drivers/pci/controller/dwc/pcie-designware-ep.c | 77 +++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index c43a1479de2c..dc63478f6910 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -15,6 +15,10 @@ #include #include +/** + * dw_pcie_ep_linkup - Notify EPF drivers about Link Up event + * @ep: DWC EP device + */ void dw_pcie_ep_linkup(struct dw_pcie_ep *ep) { struct pci_epc *epc = ep->epc; @@ -23,6 +27,10 @@ void dw_pcie_ep_linkup(struct dw_pcie_ep *ep) } EXPORT_SYMBOL_GPL(dw_pcie_ep_linkup); +/** + * dw_pcie_ep_init_notify - Notify EPF drivers about EPC initialization complete + * @ep: DWC EP device + */ void dw_pcie_ep_init_notify(struct dw_pcie_ep *ep) { struct pci_epc *epc = ep->epc; @@ -31,6 +39,14 @@ void dw_pcie_ep_init_notify(struct dw_pcie_ep *ep) } EXPORT_SYMBOL_GPL(dw_pcie_ep_init_notify); +/** + * dw_pcie_ep_get_func_from_ep - Get the struct dw_pcie_ep_func corresponding to + * the endpoint function + * @ep: DWC EP device + * @func_no: Function number of the endpoint device + * + * Return: struct dw_pcie_ep_func if success, NULL otherwise. + */ struct dw_pcie_ep_func * dw_pcie_ep_get_func_from_ep(struct dw_pcie_ep *ep, u8 func_no) { @@ -61,6 +77,11 @@ static void __dw_pcie_ep_reset_bar(struct dw_pcie *pci, u8 func_no, dw_pcie_dbi_ro_wr_dis(pci); } +/** + * dw_pcie_ep_reset_bar - Reset endpoint BAR + * @pci: DWC PCI device + * @bar: BAR number of the endpoint + */ void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar) { u8 func_no, funcs; @@ -440,6 +461,13 @@ static const struct pci_epc_ops epc_ops = { .get_features = dw_pcie_ep_get_features, }; +/** + * dw_pcie_ep_raise_intx_irq - Raise INTx IRQ to the host + * @ep: DWC EP device + * @func_no: Function number of the endpoint + * + * Return: 0 if success, errono otherwise. + */ int dw_pcie_ep_raise_intx_irq(struct dw_pcie_ep *ep, u8 func_no) { struct dw_pcie *pci = to_dw_pcie_from_ep(ep); @@ -451,6 +479,14 @@ int dw_pcie_ep_raise_intx_irq(struct dw_pcie_ep *ep, u8 func_no) } EXPORT_SYMBOL_GPL(dw_pcie_ep_raise_intx_irq); +/** + * dw_pcie_ep_raise_msi_irq - Raise MSI IRQ to the host + * @ep: DWC EP device + * @func_no: Function number of the endpoint + * @interrupt_num: Interrupt number to be raised + * + * Return: 0 if success, errono otherwise. + */ int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no, u8 interrupt_num) { @@ -500,6 +536,15 @@ int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no, } EXPORT_SYMBOL_GPL(dw_pcie_ep_raise_msi_irq); +/** + * dw_pcie_ep_raise_msix_irq_doorbell - Raise MSI-X to the host using Doorbell + * method + * @ep: DWC EP device + * @func_no: Function number of the endpoint device + * @interrupt_num: Interrupt number to be raised + * + * Return: 0 if success, errno otherwise. + */ int dw_pcie_ep_raise_msix_irq_doorbell(struct dw_pcie_ep *ep, u8 func_no, u16 interrupt_num) { @@ -519,6 +564,14 @@ int dw_pcie_ep_raise_msix_irq_doorbell(struct dw_pcie_ep *ep, u8 func_no, return 0; } +/** + * dw_pcie_ep_raise_msix_irq - Raise MSI-X to the host + * @ep: DWC EP device + * @func_no: Function number of the endpoint device + * @interrupt_num: Interrupt number to be raised + * + * Return: 0 if success, errno otherwise. + */ int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no, u16 interrupt_num) { @@ -566,6 +619,13 @@ int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no, return 0; } +/** + * dw_pcie_ep_exit - Deinitialize the endpoint device + * @ep: DWC EP device + * + * Deinitialize the endpoint device. EPC device is not destroyed since that will + * be taken care by Devres. + */ void dw_pcie_ep_exit(struct dw_pcie_ep *ep) { struct dw_pcie *pci = to_dw_pcie_from_ep(ep); @@ -601,6 +661,14 @@ static unsigned int dw_pcie_ep_find_ext_capability(struct dw_pcie *pci, int cap) return 0; } +/** + * dw_pcie_ep_init_complete - Complete DWC EP initialization + * @ep: DWC EP device + * + * Complete the initialization of the registers (CSRs) specific to DWC EP. This + * API should be called only when the endpoint receives an active refclk (either + * from host or generated locally). + */ int dw_pcie_ep_init_complete(struct dw_pcie_ep *ep) { struct dw_pcie *pci = to_dw_pcie_from_ep(ep); @@ -723,6 +791,15 @@ err_remove_edma: } EXPORT_SYMBOL_GPL(dw_pcie_ep_init_complete); +/** + * dw_pcie_ep_init - Initialize the endpoint device + * @ep: DWC EP device + * + * Initialize the endpoint device. Allocate resources and create the EPC + * device with the endpoint framework. + * + * Return: 0 if success, errno otherwise. + */ int dw_pcie_ep_init(struct dw_pcie_ep *ep) { int ret; -- cgit v1.2.3-59-g8ed1b From b7dec6b85089fcadf2478e22429d4e1863f95294 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Wed, 27 Mar 2024 14:43:32 +0530 Subject: PCI: dwc: ep: Remove deinit() callback from struct dw_pcie_ep_ops MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit deinit() callback was solely introduced for the pcie-rcar-gen4 driver where it is used to do platform specific resource deallocation. And this callback is called right at the end of the dw_pcie_ep_exit() API. So it doesn't matter whether it is called within or outside of dw_pcie_ep_exit() API. So let's remove this callback and directly call rcar_gen4_pcie_ep_deinit() in pcie-rcar-gen4 driver to do resource deallocation after the completion of dw_pcie_ep_exit() API in rcar_gen4_remove_dw_pcie_ep(). This simplifies the DWC layer. Link: https://lore.kernel.org/linux-pci/20240327-pci-dbi-rework-v12-3-082625472414@linaro.org Signed-off-by: Manivannan Sadhasivam Signed-off-by: Krzysztof Wilczyński Reviewed-by: Frank Li Reviewed-by: Niklas Cassel Reviewed-by: Yoshihiro Shimoda --- drivers/pci/controller/dwc/pcie-designware-ep.c | 9 +-------- drivers/pci/controller/dwc/pcie-designware.h | 1 - drivers/pci/controller/dwc/pcie-rcar-gen4.c | 14 ++++++++------ 3 files changed, 9 insertions(+), 15 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index dc63478f6910..f06598715412 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -637,9 +637,6 @@ void dw_pcie_ep_exit(struct dw_pcie_ep *ep) epc->mem->window.page_size); pci_epc_mem_exit(epc); - - if (ep->ops->deinit) - ep->ops->deinit(ep); } EXPORT_SYMBOL_GPL(dw_pcie_ep_exit); @@ -844,7 +841,7 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep) ep->page_size); if (ret < 0) { dev_err(dev, "Failed to initialize address space\n"); - goto err_ep_deinit; + return ret; } ep->msi_mem = pci_epc_mem_alloc_addr(epc, &ep->msi_mem_phys, @@ -881,10 +878,6 @@ err_free_epc_mem: err_exit_epc_mem: pci_epc_mem_exit(epc); -err_ep_deinit: - if (ep->ops->deinit) - ep->ops->deinit(ep); - return ret; } EXPORT_SYMBOL_GPL(dw_pcie_ep_init); diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index 26dae4837462..ab7431a37209 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -333,7 +333,6 @@ struct dw_pcie_rp { struct dw_pcie_ep_ops { void (*pre_init)(struct dw_pcie_ep *ep); void (*init)(struct dw_pcie_ep *ep); - void (*deinit)(struct dw_pcie_ep *ep); int (*raise_irq)(struct dw_pcie_ep *ep, u8 func_no, unsigned int type, u16 interrupt_num); const struct pci_epc_features* (*get_features)(struct dw_pcie_ep *ep); diff --git a/drivers/pci/controller/dwc/pcie-rcar-gen4.c b/drivers/pci/controller/dwc/pcie-rcar-gen4.c index 0be760ed420b..5d29c4cfe0a0 100644 --- a/drivers/pci/controller/dwc/pcie-rcar-gen4.c +++ b/drivers/pci/controller/dwc/pcie-rcar-gen4.c @@ -352,11 +352,8 @@ static void rcar_gen4_pcie_ep_init(struct dw_pcie_ep *ep) dw_pcie_ep_reset_bar(pci, bar); } -static void rcar_gen4_pcie_ep_deinit(struct dw_pcie_ep *ep) +static void rcar_gen4_pcie_ep_deinit(struct rcar_gen4_pcie *rcar) { - struct dw_pcie *dw = to_dw_pcie_from_ep(ep); - struct rcar_gen4_pcie *rcar = to_rcar_gen4_pcie(dw); - writel(0, rcar->base + PCIEDMAINTSTSEN); rcar_gen4_pcie_common_deinit(rcar); } @@ -410,7 +407,6 @@ static unsigned int rcar_gen4_pcie_ep_get_dbi2_offset(struct dw_pcie_ep *ep, static const struct dw_pcie_ep_ops pcie_ep_ops = { .pre_init = rcar_gen4_pcie_ep_pre_init, .init = rcar_gen4_pcie_ep_init, - .deinit = rcar_gen4_pcie_ep_deinit, .raise_irq = rcar_gen4_pcie_ep_raise_irq, .get_features = rcar_gen4_pcie_ep_get_features, .get_dbi_offset = rcar_gen4_pcie_ep_get_dbi_offset, @@ -420,18 +416,24 @@ static const struct dw_pcie_ep_ops pcie_ep_ops = { static int rcar_gen4_add_dw_pcie_ep(struct rcar_gen4_pcie *rcar) { struct dw_pcie_ep *ep = &rcar->dw.ep; + int ret; if (!IS_ENABLED(CONFIG_PCIE_RCAR_GEN4_EP)) return -ENODEV; ep->ops = &pcie_ep_ops; - return dw_pcie_ep_init(ep); + ret = dw_pcie_ep_init(ep); + if (ret) + rcar_gen4_pcie_ep_deinit(rcar); + + return ret; } static void rcar_gen4_remove_dw_pcie_ep(struct rcar_gen4_pcie *rcar) { dw_pcie_ep_exit(&rcar->dw.ep); + rcar_gen4_pcie_ep_deinit(rcar); } /* Common */ -- cgit v1.2.3-59-g8ed1b From c8682a3314c1e247b253a5ffa22e8cc4cd7156cc Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Wed, 27 Mar 2024 14:43:33 +0530 Subject: PCI: dwc: ep: Rename dw_pcie_ep_exit() to dw_pcie_ep_deinit() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit dw_pcie_ep_exit() API is undoing what the dw_pcie_ep_init() API has done already (at least partly). But the API name dw_pcie_ep_exit() is not quite reflecting that. So let's rename it to dw_pcie_ep_deinit() to make the purpose of this API clear. This also aligns with the DWC host driver. Link: https://patchwork.kernel.org/project/linux-pci/patch/20240327-pci-dbi-rework-v12-4-082625472414@linaro.org Signed-off-by: Manivannan Sadhasivam Signed-off-by: Krzysztof Wilczyński Reviewed-by: Frank Li Reviewed-by: Niklas Cassel Reviewed-by: Yoshihiro Shimoda --- drivers/pci/controller/dwc/pcie-designware-ep.c | 6 +++--- drivers/pci/controller/dwc/pcie-designware.h | 4 ++-- drivers/pci/controller/dwc/pcie-rcar-gen4.c | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index f06598715412..d87f7642d7f6 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -620,13 +620,13 @@ int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no, } /** - * dw_pcie_ep_exit - Deinitialize the endpoint device + * dw_pcie_ep_deinit - Deinitialize the endpoint device * @ep: DWC EP device * * Deinitialize the endpoint device. EPC device is not destroyed since that will * be taken care by Devres. */ -void dw_pcie_ep_exit(struct dw_pcie_ep *ep) +void dw_pcie_ep_deinit(struct dw_pcie_ep *ep) { struct dw_pcie *pci = to_dw_pcie_from_ep(ep); struct pci_epc *epc = ep->epc; @@ -638,7 +638,7 @@ void dw_pcie_ep_exit(struct dw_pcie_ep *ep) pci_epc_mem_exit(epc); } -EXPORT_SYMBOL_GPL(dw_pcie_ep_exit); +EXPORT_SYMBOL_GPL(dw_pcie_ep_deinit); static unsigned int dw_pcie_ep_find_ext_capability(struct dw_pcie *pci, int cap) { diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index ab7431a37209..61465203bb60 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -671,7 +671,7 @@ void dw_pcie_ep_linkup(struct dw_pcie_ep *ep); int dw_pcie_ep_init(struct dw_pcie_ep *ep); int dw_pcie_ep_init_complete(struct dw_pcie_ep *ep); void dw_pcie_ep_init_notify(struct dw_pcie_ep *ep); -void dw_pcie_ep_exit(struct dw_pcie_ep *ep); +void dw_pcie_ep_deinit(struct dw_pcie_ep *ep); int dw_pcie_ep_raise_intx_irq(struct dw_pcie_ep *ep, u8 func_no); int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no, u8 interrupt_num); @@ -701,7 +701,7 @@ static inline void dw_pcie_ep_init_notify(struct dw_pcie_ep *ep) { } -static inline void dw_pcie_ep_exit(struct dw_pcie_ep *ep) +static inline void dw_pcie_ep_deinit(struct dw_pcie_ep *ep) { } diff --git a/drivers/pci/controller/dwc/pcie-rcar-gen4.c b/drivers/pci/controller/dwc/pcie-rcar-gen4.c index 5d29c4cfe0a0..de4bdfaecab3 100644 --- a/drivers/pci/controller/dwc/pcie-rcar-gen4.c +++ b/drivers/pci/controller/dwc/pcie-rcar-gen4.c @@ -432,7 +432,7 @@ static int rcar_gen4_add_dw_pcie_ep(struct rcar_gen4_pcie *rcar) static void rcar_gen4_remove_dw_pcie_ep(struct rcar_gen4_pcie *rcar) { - dw_pcie_ep_exit(&rcar->dw.ep); + dw_pcie_ep_deinit(&rcar->dw.ep); rcar_gen4_pcie_ep_deinit(rcar); } -- cgit v1.2.3-59-g8ed1b From 570d7715eed8a29ac5bd96c7694f060a991e5a31 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Wed, 27 Mar 2024 14:43:34 +0530 Subject: PCI: dwc: ep: Introduce dw_pcie_ep_cleanup() API for drivers supporting PERST# MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For DWC glue drivers supporting PERST# (currently Qcom and Tegra194), some of the DWC resources like eDMA should be cleaned up during the PERST# assert time. So let's introduce a dw_pcie_ep_cleanup() API that could be called by these drivers to cleanup the DWC specific resources. Currently, it just removes eDMA. Closes: https://lore.kernel.org/linux-pci/ZWYmX8Y%2F7Q9WMxES@x1-carbon Link: https://lore.kernel.org/linux-pci/20240327-pci-dbi-rework-v12-5-082625472414@linaro.org Reported-by: Niklas Cassel Signed-off-by: Manivannan Sadhasivam Signed-off-by: Krzysztof Wilczyński Reviewed-by: Frank Li Reviewed-by: Niklas Cassel --- drivers/pci/controller/dwc/pcie-designware-ep.c | 19 +++++++++++++++++-- drivers/pci/controller/dwc/pcie-designware.h | 5 +++++ drivers/pci/controller/dwc/pcie-qcom-ep.c | 1 + drivers/pci/controller/dwc/pcie-tegra194.c | 2 ++ 4 files changed, 25 insertions(+), 2 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index d87f7642d7f6..eeff7f1ff8f1 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -619,6 +619,22 @@ int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no, return 0; } +/** + * dw_pcie_ep_cleanup - Cleanup DWC EP resources after fundamental reset + * @ep: DWC EP device + * + * Cleans up the DWC EP specific resources like eDMA etc... after fundamental + * reset like PERST#. Note that this API is only applicable for drivers + * supporting PERST# or any other methods of fundamental reset. + */ +void dw_pcie_ep_cleanup(struct dw_pcie_ep *ep) +{ + struct dw_pcie *pci = to_dw_pcie_from_ep(ep); + + dw_pcie_edma_remove(pci); +} +EXPORT_SYMBOL_GPL(dw_pcie_ep_cleanup); + /** * dw_pcie_ep_deinit - Deinitialize the endpoint device * @ep: DWC EP device @@ -628,10 +644,9 @@ int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no, */ void dw_pcie_ep_deinit(struct dw_pcie_ep *ep) { - struct dw_pcie *pci = to_dw_pcie_from_ep(ep); struct pci_epc *epc = ep->epc; - dw_pcie_edma_remove(pci); + dw_pcie_ep_cleanup(ep); pci_epc_mem_free_addr(epc, ep->msi_mem_phys, ep->msi_mem, epc->mem->window.page_size); diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index 61465203bb60..351d2fe3ea4d 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -672,6 +672,7 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep); int dw_pcie_ep_init_complete(struct dw_pcie_ep *ep); void dw_pcie_ep_init_notify(struct dw_pcie_ep *ep); void dw_pcie_ep_deinit(struct dw_pcie_ep *ep); +void dw_pcie_ep_cleanup(struct dw_pcie_ep *ep); int dw_pcie_ep_raise_intx_irq(struct dw_pcie_ep *ep, u8 func_no); int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no, u8 interrupt_num); @@ -705,6 +706,10 @@ static inline void dw_pcie_ep_deinit(struct dw_pcie_ep *ep) { } +static inline void dw_pcie_ep_cleanup(struct dw_pcie_ep *ep) +{ +} + static inline int dw_pcie_ep_raise_intx_irq(struct dw_pcie_ep *ep, u8 func_no) { return 0; diff --git a/drivers/pci/controller/dwc/pcie-qcom-ep.c b/drivers/pci/controller/dwc/pcie-qcom-ep.c index 36e5e80cd22f..59b1c0110288 100644 --- a/drivers/pci/controller/dwc/pcie-qcom-ep.c +++ b/drivers/pci/controller/dwc/pcie-qcom-ep.c @@ -507,6 +507,7 @@ static void qcom_pcie_perst_assert(struct dw_pcie *pci) return; } + dw_pcie_ep_cleanup(&pci->ep); qcom_pcie_disable_resources(pcie_ep); pcie_ep->link_status = QCOM_PCIE_EP_LINK_DISABLED; } diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c index 1f7b662cb8e1..26ea2f8313eb 100644 --- a/drivers/pci/controller/dwc/pcie-tegra194.c +++ b/drivers/pci/controller/dwc/pcie-tegra194.c @@ -1715,6 +1715,8 @@ static void pex_ep_event_pex_rst_assert(struct tegra_pcie_dw *pcie) if (ret) dev_err(pcie->dev, "Failed to go Detect state: %d\n", ret); + dw_pcie_ep_cleanup(&pcie->pci.ep); + reset_control_assert(pcie->core_rst); tegra_pcie_disable_phy(pcie); -- cgit v1.2.3-59-g8ed1b From 7d6e64c443ea03090b01ae2fe401a78a68427ddc Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Wed, 27 Mar 2024 14:43:35 +0530 Subject: PCI: dwc: ep: Rename dw_pcie_ep_init_complete() to dw_pcie_ep_init_registers() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The goal of the dw_pcie_ep_init_complete() API is to initialize the DWC specific registers post registering the controller with the EP framework. But the naming doesn't reflect its functionality and causes confusion. So, let's rename it to dw_pcie_ep_init_registers() to make it clear that it initializes the DWC specific registers. Link: https://lore.kernel.org/linux-pci/20240327-pci-dbi-rework-v12-6-082625472414@linaro.org Signed-off-by: Manivannan Sadhasivam Signed-off-by: Krzysztof Wilczyński Reviewed-by: Frank Li Reviewed-by: Niklas Cassel --- drivers/pci/controller/dwc/pcie-designware-ep.c | 14 +++++++------- drivers/pci/controller/dwc/pcie-designware.h | 4 ++-- drivers/pci/controller/dwc/pcie-qcom-ep.c | 2 +- drivers/pci/controller/dwc/pcie-tegra194.c | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index eeff7f1ff8f1..761d3012a073 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -674,14 +674,14 @@ static unsigned int dw_pcie_ep_find_ext_capability(struct dw_pcie *pci, int cap) } /** - * dw_pcie_ep_init_complete - Complete DWC EP initialization + * dw_pcie_ep_init_registers - Initialize DWC EP specific registers * @ep: DWC EP device * - * Complete the initialization of the registers (CSRs) specific to DWC EP. This - * API should be called only when the endpoint receives an active refclk (either - * from host or generated locally). + * Initialize the registers (CSRs) specific to DWC EP. This API should be called + * only when the endpoint receives an active refclk (either from host or + * generated locally). */ -int dw_pcie_ep_init_complete(struct dw_pcie_ep *ep) +int dw_pcie_ep_init_registers(struct dw_pcie_ep *ep) { struct dw_pcie *pci = to_dw_pcie_from_ep(ep); struct dw_pcie_ep_func *ep_func; @@ -801,7 +801,7 @@ err_remove_edma: return ret; } -EXPORT_SYMBOL_GPL(dw_pcie_ep_init_complete); +EXPORT_SYMBOL_GPL(dw_pcie_ep_init_registers); /** * dw_pcie_ep_init - Initialize the endpoint device @@ -880,7 +880,7 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep) * (Ex: tegra194). Any hardware access on such platforms result * in system hang. */ - ret = dw_pcie_ep_init_complete(ep); + ret = dw_pcie_ep_init_registers(ep); if (ret) goto err_free_epc_mem; diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index 351d2fe3ea4d..f8e5431a207b 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -669,7 +669,7 @@ static inline void __iomem *dw_pcie_own_conf_map_bus(struct pci_bus *bus, #ifdef CONFIG_PCIE_DW_EP void dw_pcie_ep_linkup(struct dw_pcie_ep *ep); int dw_pcie_ep_init(struct dw_pcie_ep *ep); -int dw_pcie_ep_init_complete(struct dw_pcie_ep *ep); +int dw_pcie_ep_init_registers(struct dw_pcie_ep *ep); void dw_pcie_ep_init_notify(struct dw_pcie_ep *ep); void dw_pcie_ep_deinit(struct dw_pcie_ep *ep); void dw_pcie_ep_cleanup(struct dw_pcie_ep *ep); @@ -693,7 +693,7 @@ static inline int dw_pcie_ep_init(struct dw_pcie_ep *ep) return 0; } -static inline int dw_pcie_ep_init_complete(struct dw_pcie_ep *ep) +static inline int dw_pcie_ep_init_registers(struct dw_pcie_ep *ep) { return 0; } diff --git a/drivers/pci/controller/dwc/pcie-qcom-ep.c b/drivers/pci/controller/dwc/pcie-qcom-ep.c index 59b1c0110288..3697b4a944cc 100644 --- a/drivers/pci/controller/dwc/pcie-qcom-ep.c +++ b/drivers/pci/controller/dwc/pcie-qcom-ep.c @@ -463,7 +463,7 @@ static int qcom_pcie_perst_deassert(struct dw_pcie *pci) PARF_INT_ALL_LINK_UP | PARF_INT_ALL_EDMA; writel_relaxed(val, pcie_ep->parf + PARF_INT_ALL_MASK); - ret = dw_pcie_ep_init_complete(&pcie_ep->pci.ep); + ret = dw_pcie_ep_init_registers(&pcie_ep->pci.ep); if (ret) { dev_err(dev, "Failed to complete initialization: %d\n", ret); goto err_disable_resources; diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c index 26ea2f8313eb..db043f579fbe 100644 --- a/drivers/pci/controller/dwc/pcie-tegra194.c +++ b/drivers/pci/controller/dwc/pcie-tegra194.c @@ -1897,7 +1897,7 @@ static void pex_ep_event_pex_rst_deassert(struct tegra_pcie_dw *pcie) val = (upper_32_bits(ep->msi_mem_phys) & MSIX_ADDR_MATCH_HIGH_OFF_MASK); dw_pcie_writel_dbi(pci, MSIX_ADDR_MATCH_HIGH_OFF, val); - ret = dw_pcie_ep_init_complete(ep); + ret = dw_pcie_ep_init_registers(ep); if (ret) { dev_err(dev, "Failed to complete initialization: %d\n", ret); goto fail_init_complete; -- cgit v1.2.3-59-g8ed1b From df69e17ccc2f87bd6ce7a862dcdce16ae55a7fd7 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Wed, 27 Mar 2024 14:43:36 +0530 Subject: PCI: dwc: ep: Call dw_pcie_ep_init_registers() API directly from all glue drivers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, dw_pcie_ep_init_registers() API is directly called by the glue drivers requiring active refclk from host. But for the other drivers, it is getting called implicitly by dw_pcie_ep_init(). This is due to the fact that this API initializes DWC EP specific registers and that requires an active refclk (either from host or generated locally by endpoint itsef). But, this causes a discrepancy among the glue drivers. So to avoid this confusion, let's call this API directly from all glue drivers irrespective of refclk dependency. Only difference here is that the drivers requiring refclk from host will call this API only after the refclk is received and other drivers without refclk dependency will call this API right after dw_pcie_ep_init(). With this change, the check for 'core_init_notifier' flag can now be dropped from dw_pcie_ep_init() API. This will also allow us to remove the 'core_init_notifier' flag completely in the later commits. Link: https://lore.kernel.org/linux-pci/20240327-pci-dbi-rework-v12-7-082625472414@linaro.org Signed-off-by: Manivannan Sadhasivam Signed-off-by: Krzysztof Wilczyński Reviewed-by: Frank Li Reviewed-by: Niklas Cassel Reviewed-by: Yoshihiro Shimoda --- drivers/pci/controller/dwc/pci-dra7xx.c | 7 +++++++ drivers/pci/controller/dwc/pci-imx6.c | 8 ++++++++ drivers/pci/controller/dwc/pci-keystone.c | 9 +++++++++ drivers/pci/controller/dwc/pci-layerscape-ep.c | 7 +++++++ drivers/pci/controller/dwc/pcie-artpec6.c | 13 ++++++++++++- drivers/pci/controller/dwc/pcie-designware-ep.c | 22 ---------------------- drivers/pci/controller/dwc/pcie-designware-plat.c | 9 +++++++++ drivers/pci/controller/dwc/pcie-keembay.c | 16 +++++++++++++++- drivers/pci/controller/dwc/pcie-rcar-gen4.c | 12 +++++++++++- drivers/pci/controller/dwc/pcie-uniphier-ep.c | 13 ++++++++++++- 10 files changed, 90 insertions(+), 26 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-dra7xx.c b/drivers/pci/controller/dwc/pci-dra7xx.c index 0e406677060d..395042b29ffc 100644 --- a/drivers/pci/controller/dwc/pci-dra7xx.c +++ b/drivers/pci/controller/dwc/pci-dra7xx.c @@ -467,6 +467,13 @@ static int dra7xx_add_pcie_ep(struct dra7xx_pcie *dra7xx, return ret; } + ret = dw_pcie_ep_init_registers(ep); + if (ret) { + dev_err(dev, "Failed to initialize DWC endpoint registers\n"); + dw_pcie_ep_deinit(ep); + return ret; + } + return 0; } diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 99a60270b26c..8d28ecc381bc 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -1123,6 +1123,14 @@ static int imx6_add_pcie_ep(struct imx6_pcie *imx6_pcie, dev_err(dev, "failed to initialize endpoint\n"); return ret; } + + ret = dw_pcie_ep_init_registers(ep); + if (ret) { + dev_err(dev, "Failed to initialize DWC endpoint registers\n"); + dw_pcie_ep_deinit(ep); + return ret; + } + /* Start LTSSM. */ imx6_pcie_ltssm_enable(dev); diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index 844de4418724..81ebac520650 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -1286,6 +1286,13 @@ static int ks_pcie_probe(struct platform_device *pdev) ret = dw_pcie_ep_init(&pci->ep); if (ret < 0) goto err_get_sync; + + ret = dw_pcie_ep_init_registers(&pci->ep); + if (ret) { + dev_err(dev, "Failed to initialize DWC endpoint registers\n"); + goto err_ep_init; + } + break; default: dev_err(dev, "INVALID device type %d\n", mode); @@ -1295,6 +1302,8 @@ static int ks_pcie_probe(struct platform_device *pdev) return 0; +err_ep_init: + dw_pcie_ep_deinit(&pci->ep); err_get_sync: pm_runtime_put(dev); pm_runtime_disable(dev); diff --git a/drivers/pci/controller/dwc/pci-layerscape-ep.c b/drivers/pci/controller/dwc/pci-layerscape-ep.c index 1f6ee1460ec2..9eb2233e3d7f 100644 --- a/drivers/pci/controller/dwc/pci-layerscape-ep.c +++ b/drivers/pci/controller/dwc/pci-layerscape-ep.c @@ -279,6 +279,13 @@ static int __init ls_pcie_ep_probe(struct platform_device *pdev) if (ret) return ret; + ret = dw_pcie_ep_init_registers(&pci->ep); + if (ret) { + dev_err(dev, "Failed to initialize DWC endpoint registers\n"); + dw_pcie_ep_deinit(&pci->ep); + return ret; + } + return ls_pcie_ep_interrupt_init(pcie, pdev); } diff --git a/drivers/pci/controller/dwc/pcie-artpec6.c b/drivers/pci/controller/dwc/pcie-artpec6.c index 9ed0a9ba7619..a6095561db4a 100644 --- a/drivers/pci/controller/dwc/pcie-artpec6.c +++ b/drivers/pci/controller/dwc/pcie-artpec6.c @@ -441,7 +441,18 @@ static int artpec6_pcie_probe(struct platform_device *pdev) pci->ep.ops = &pcie_ep_ops; - return dw_pcie_ep_init(&pci->ep); + ret = dw_pcie_ep_init(&pci->ep); + if (ret) + return ret; + + ret = dw_pcie_ep_init_registers(&pci->ep); + if (ret) { + dev_err(dev, "Failed to initialize DWC endpoint registers\n"); + dw_pcie_ep_deinit(&pci->ep); + return ret; + } + + break; default: dev_err(dev, "INVALID device type %d\n", artpec6_pcie->mode); } diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index 761d3012a073..2063cf2049e5 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -821,7 +821,6 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep) struct device *dev = pci->dev; struct platform_device *pdev = to_platform_device(dev); struct device_node *np = dev->of_node; - const struct pci_epc_features *epc_features; INIT_LIST_HEAD(&ep->func_list); @@ -867,29 +866,8 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep) goto err_exit_epc_mem; } - if (ep->ops->get_features) { - epc_features = ep->ops->get_features(ep); - if (epc_features->core_init_notifier) - return 0; - } - - /* - * NOTE:- Avoid accessing the hardware (Ex:- DBI space) before this - * step as platforms that implement 'core_init_notifier' feature may - * not have the hardware ready (i.e. core initialized) for access - * (Ex: tegra194). Any hardware access on such platforms result - * in system hang. - */ - ret = dw_pcie_ep_init_registers(ep); - if (ret) - goto err_free_epc_mem; - return 0; -err_free_epc_mem: - pci_epc_mem_free_addr(epc, ep->msi_mem_phys, ep->msi_mem, - epc->mem->window.page_size); - err_exit_epc_mem: pci_epc_mem_exit(epc); diff --git a/drivers/pci/controller/dwc/pcie-designware-plat.c b/drivers/pci/controller/dwc/pcie-designware-plat.c index 778588b4be70..ca9b22e654cd 100644 --- a/drivers/pci/controller/dwc/pcie-designware-plat.c +++ b/drivers/pci/controller/dwc/pcie-designware-plat.c @@ -145,6 +145,15 @@ static int dw_plat_pcie_probe(struct platform_device *pdev) pci->ep.ops = &pcie_ep_ops; ret = dw_pcie_ep_init(&pci->ep); + if (ret) + return ret; + + ret = dw_pcie_ep_init_registers(&pci->ep); + if (ret) { + dev_err(dev, "Failed to initialize DWC endpoint registers\n"); + dw_pcie_ep_deinit(&pci->ep); + } + break; default: dev_err(dev, "INVALID device type %d\n", dw_plat_pcie->mode); diff --git a/drivers/pci/controller/dwc/pcie-keembay.c b/drivers/pci/controller/dwc/pcie-keembay.c index 5e8e54f597dd..b2556dbcffb5 100644 --- a/drivers/pci/controller/dwc/pcie-keembay.c +++ b/drivers/pci/controller/dwc/pcie-keembay.c @@ -396,6 +396,7 @@ static int keembay_pcie_probe(struct platform_device *pdev) struct keembay_pcie *pcie; struct dw_pcie *pci; enum dw_pcie_device_mode mode; + int ret; data = device_get_match_data(dev); if (!data) @@ -430,11 +431,24 @@ static int keembay_pcie_probe(struct platform_device *pdev) return -ENODEV; pci->ep.ops = &keembay_pcie_ep_ops; - return dw_pcie_ep_init(&pci->ep); + ret = dw_pcie_ep_init(&pci->ep); + if (ret) + return ret; + + ret = dw_pcie_ep_init_registers(&pci->ep); + if (ret) { + dev_err(dev, "Failed to initialize DWC endpoint registers\n"); + dw_pcie_ep_deinit(&pci->ep); + return ret; + } + + break; default: dev_err(dev, "Invalid device type %d\n", pcie->mode); return -ENODEV; } + + return 0; } static const struct keembay_pcie_of_data keembay_pcie_rc_of_data = { diff --git a/drivers/pci/controller/dwc/pcie-rcar-gen4.c b/drivers/pci/controller/dwc/pcie-rcar-gen4.c index de4bdfaecab3..e155a905fb4f 100644 --- a/drivers/pci/controller/dwc/pcie-rcar-gen4.c +++ b/drivers/pci/controller/dwc/pcie-rcar-gen4.c @@ -416,6 +416,7 @@ static const struct dw_pcie_ep_ops pcie_ep_ops = { static int rcar_gen4_add_dw_pcie_ep(struct rcar_gen4_pcie *rcar) { struct dw_pcie_ep *ep = &rcar->dw.ep; + struct device *dev = rcar->dw.dev; int ret; if (!IS_ENABLED(CONFIG_PCIE_RCAR_GEN4_EP)) @@ -424,8 +425,17 @@ static int rcar_gen4_add_dw_pcie_ep(struct rcar_gen4_pcie *rcar) ep->ops = &pcie_ep_ops; ret = dw_pcie_ep_init(ep); - if (ret) + if (ret) { rcar_gen4_pcie_ep_deinit(rcar); + return ret; + } + + ret = dw_pcie_ep_init_registers(ep); + if (ret) { + dev_err(dev, "Failed to initialize DWC endpoint registers\n"); + dw_pcie_ep_deinit(ep); + rcar_gen4_pcie_ep_deinit(rcar); + } return ret; } diff --git a/drivers/pci/controller/dwc/pcie-uniphier-ep.c b/drivers/pci/controller/dwc/pcie-uniphier-ep.c index 639bc2e12476..0e5e7344de48 100644 --- a/drivers/pci/controller/dwc/pcie-uniphier-ep.c +++ b/drivers/pci/controller/dwc/pcie-uniphier-ep.c @@ -399,7 +399,18 @@ static int uniphier_pcie_ep_probe(struct platform_device *pdev) return ret; priv->pci.ep.ops = &uniphier_pcie_ep_ops; - return dw_pcie_ep_init(&priv->pci.ep); + ret = dw_pcie_ep_init(&priv->pci.ep); + if (ret) + return ret; + + ret = dw_pcie_ep_init_registers(&priv->pci.ep); + if (ret) { + dev_err(dev, "Failed to initialize DWC endpoint registers\n"); + dw_pcie_ep_deinit(&priv->pci.ep); + return ret; + } + + return 0; } static const struct uniphier_pcie_ep_soc_data uniphier_pro5_data = { -- cgit v1.2.3-59-g8ed1b From a01e7214bef904723d26d293eb17586078610379 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Wed, 27 Mar 2024 14:43:37 +0530 Subject: PCI: endpoint: Remove "core_init_notifier" flag MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit "core_init_notifier" flag is set by the glue drivers requiring refclk from the host to complete the DWC core initialization. Also, those drivers will send a notification to the EPF drivers once the initialization is fully completed using the pci_epc_init_notify() API. Only then, the EPF drivers will start functioning. For the rest of the drivers generating refclk locally, EPF drivers will start functioning post binding with them. EPF drivers rely on the 'core_init_notifier' flag to differentiate between the drivers. Unfortunately, this creates two different flows for the EPF drivers. So to avoid that, let's get rid of the "core_init_notifier" flag and follow a single initialization flow for the EPF drivers. This is done by calling the dw_pcie_ep_init_notify() from all glue drivers after the completion of dw_pcie_ep_init_registers() API. This will allow all the glue drivers to send the notification to the EPF drivers once the initialization is fully completed. Only difference here is that, the drivers requiring refclk from host will send the notification once refclk is received, while others will send it during probe time itself. But this also requires the EPC core driver to deliver the notification after EPF driver bind. Because, the glue driver can send the notification before the EPF drivers bind() and in those cases the EPF drivers will miss the event. To accommodate this, EPC core is now caching the state of the EPC initialization in 'init_complete' flag and pci-ep-cfs driver sends the notification to EPF drivers based on that after each EPF driver bind. Link: https://lore.kernel.org/linux-pci/20240327-pci-dbi-rework-v12-8-082625472414@linaro.org Tested-by: Niklas Cassel Signed-off-by: Manivannan Sadhasivam Signed-off-by: Krzysztof Wilczyński Reviewed-by: Frank Li Reviewed-by: Niklas Cassel --- drivers/pci/controller/cadence/pcie-cadence-ep.c | 2 ++ drivers/pci/controller/dwc/pci-dra7xx.c | 2 ++ drivers/pci/controller/dwc/pci-imx6.c | 2 ++ drivers/pci/controller/dwc/pci-keystone.c | 2 ++ drivers/pci/controller/dwc/pci-layerscape-ep.c | 2 ++ drivers/pci/controller/dwc/pcie-artpec6.c | 2 ++ drivers/pci/controller/dwc/pcie-designware-ep.c | 1 + drivers/pci/controller/dwc/pcie-designware-plat.c | 2 ++ drivers/pci/controller/dwc/pcie-keembay.c | 2 ++ drivers/pci/controller/dwc/pcie-qcom-ep.c | 1 - drivers/pci/controller/dwc/pcie-rcar-gen4.c | 2 ++ drivers/pci/controller/dwc/pcie-tegra194.c | 1 - drivers/pci/controller/dwc/pcie-uniphier-ep.c | 2 ++ drivers/pci/controller/pcie-rcar-ep.c | 2 ++ drivers/pci/controller/pcie-rockchip-ep.c | 2 ++ drivers/pci/endpoint/functions/pci-epf-test.c | 18 +++++------------- drivers/pci/endpoint/pci-ep-cfs.c | 9 +++++++++ drivers/pci/endpoint/pci-epc-core.c | 22 ++++++++++++++++++++++ include/linux/pci-epc.h | 7 ++++--- 19 files changed, 65 insertions(+), 18 deletions(-) diff --git a/drivers/pci/controller/cadence/pcie-cadence-ep.c b/drivers/pci/controller/cadence/pcie-cadence-ep.c index 81c50dc64da9..55c42ca2b777 100644 --- a/drivers/pci/controller/cadence/pcie-cadence-ep.c +++ b/drivers/pci/controller/cadence/pcie-cadence-ep.c @@ -746,6 +746,8 @@ int cdns_pcie_ep_setup(struct cdns_pcie_ep *ep) spin_lock_init(&ep->lock); + pci_epc_init_notify(epc); + return 0; free_epc_mem: diff --git a/drivers/pci/controller/dwc/pci-dra7xx.c b/drivers/pci/controller/dwc/pci-dra7xx.c index 395042b29ffc..d2d17d37d3e0 100644 --- a/drivers/pci/controller/dwc/pci-dra7xx.c +++ b/drivers/pci/controller/dwc/pci-dra7xx.c @@ -474,6 +474,8 @@ static int dra7xx_add_pcie_ep(struct dra7xx_pcie *dra7xx, return ret; } + dw_pcie_ep_init_notify(ep); + return 0; } diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 8d28ecc381bc..917c69edee1d 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -1131,6 +1131,8 @@ static int imx6_add_pcie_ep(struct imx6_pcie *imx6_pcie, return ret; } + dw_pcie_ep_init_notify(ep); + /* Start LTSSM. */ imx6_pcie_ltssm_enable(dev); diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index 81ebac520650..d3a7d14ee685 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -1293,6 +1293,8 @@ static int ks_pcie_probe(struct platform_device *pdev) goto err_ep_init; } + dw_pcie_ep_init_notify(&pci->ep); + break; default: dev_err(dev, "INVALID device type %d\n", mode); diff --git a/drivers/pci/controller/dwc/pci-layerscape-ep.c b/drivers/pci/controller/dwc/pci-layerscape-ep.c index 9eb2233e3d7f..7dde6d5fa4d8 100644 --- a/drivers/pci/controller/dwc/pci-layerscape-ep.c +++ b/drivers/pci/controller/dwc/pci-layerscape-ep.c @@ -286,6 +286,8 @@ static int __init ls_pcie_ep_probe(struct platform_device *pdev) return ret; } + dw_pcie_ep_init_notify(&pci->ep); + return ls_pcie_ep_interrupt_init(pcie, pdev); } diff --git a/drivers/pci/controller/dwc/pcie-artpec6.c b/drivers/pci/controller/dwc/pcie-artpec6.c index a6095561db4a..a4630b92489b 100644 --- a/drivers/pci/controller/dwc/pcie-artpec6.c +++ b/drivers/pci/controller/dwc/pcie-artpec6.c @@ -452,6 +452,8 @@ static int artpec6_pcie_probe(struct platform_device *pdev) return ret; } + dw_pcie_ep_init_notify(&pci->ep); + break; default: dev_err(dev, "INVALID device type %d\n", artpec6_pcie->mode); diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index 2063cf2049e5..47391d7d3a73 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -632,6 +632,7 @@ void dw_pcie_ep_cleanup(struct dw_pcie_ep *ep) struct dw_pcie *pci = to_dw_pcie_from_ep(ep); dw_pcie_edma_remove(pci); + ep->epc->init_complete = false; } EXPORT_SYMBOL_GPL(dw_pcie_ep_cleanup); diff --git a/drivers/pci/controller/dwc/pcie-designware-plat.c b/drivers/pci/controller/dwc/pcie-designware-plat.c index ca9b22e654cd..8490c5d6ff9f 100644 --- a/drivers/pci/controller/dwc/pcie-designware-plat.c +++ b/drivers/pci/controller/dwc/pcie-designware-plat.c @@ -154,6 +154,8 @@ static int dw_plat_pcie_probe(struct platform_device *pdev) dw_pcie_ep_deinit(&pci->ep); } + dw_pcie_ep_init_notify(&pci->ep); + break; default: dev_err(dev, "INVALID device type %d\n", dw_plat_pcie->mode); diff --git a/drivers/pci/controller/dwc/pcie-keembay.c b/drivers/pci/controller/dwc/pcie-keembay.c index b2556dbcffb5..98bbc83182b4 100644 --- a/drivers/pci/controller/dwc/pcie-keembay.c +++ b/drivers/pci/controller/dwc/pcie-keembay.c @@ -442,6 +442,8 @@ static int keembay_pcie_probe(struct platform_device *pdev) return ret; } + dw_pcie_ep_init_notify(&pci->ep); + break; default: dev_err(dev, "Invalid device type %d\n", pcie->mode); diff --git a/drivers/pci/controller/dwc/pcie-qcom-ep.c b/drivers/pci/controller/dwc/pcie-qcom-ep.c index 3697b4a944cc..2fb8c15e7a91 100644 --- a/drivers/pci/controller/dwc/pcie-qcom-ep.c +++ b/drivers/pci/controller/dwc/pcie-qcom-ep.c @@ -775,7 +775,6 @@ static void qcom_pcie_ep_init_debugfs(struct qcom_pcie_ep *pcie_ep) static const struct pci_epc_features qcom_pcie_epc_features = { .linkup_notifier = true, - .core_init_notifier = true, .msi_capable = true, .msix_capable = false, .align = SZ_4K, diff --git a/drivers/pci/controller/dwc/pcie-rcar-gen4.c b/drivers/pci/controller/dwc/pcie-rcar-gen4.c index e155a905fb4f..cfeccc2f9ee1 100644 --- a/drivers/pci/controller/dwc/pcie-rcar-gen4.c +++ b/drivers/pci/controller/dwc/pcie-rcar-gen4.c @@ -437,6 +437,8 @@ static int rcar_gen4_add_dw_pcie_ep(struct rcar_gen4_pcie *rcar) rcar_gen4_pcie_ep_deinit(rcar); } + dw_pcie_ep_init_notify(ep); + return ret; } diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c index db043f579fbe..ddc23602eca7 100644 --- a/drivers/pci/controller/dwc/pcie-tegra194.c +++ b/drivers/pci/controller/dwc/pcie-tegra194.c @@ -2006,7 +2006,6 @@ static int tegra_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no, static const struct pci_epc_features tegra_pcie_epc_features = { .linkup_notifier = true, - .core_init_notifier = true, .msi_capable = false, .msix_capable = false, .bar[BAR_0] = { .type = BAR_FIXED, .fixed_size = SZ_1M, diff --git a/drivers/pci/controller/dwc/pcie-uniphier-ep.c b/drivers/pci/controller/dwc/pcie-uniphier-ep.c index 0e5e7344de48..a2b844268e28 100644 --- a/drivers/pci/controller/dwc/pcie-uniphier-ep.c +++ b/drivers/pci/controller/dwc/pcie-uniphier-ep.c @@ -410,6 +410,8 @@ static int uniphier_pcie_ep_probe(struct platform_device *pdev) return ret; } + dw_pcie_ep_init_notify(&priv->pci.ep); + return 0; } diff --git a/drivers/pci/controller/pcie-rcar-ep.c b/drivers/pci/controller/pcie-rcar-ep.c index 05967c6c0b42..047e2cef5afc 100644 --- a/drivers/pci/controller/pcie-rcar-ep.c +++ b/drivers/pci/controller/pcie-rcar-ep.c @@ -542,6 +542,8 @@ static int rcar_pcie_ep_probe(struct platform_device *pdev) goto err_pm_put; } + pci_epc_init_notify(epc); + return 0; err_pm_put: diff --git a/drivers/pci/controller/pcie-rockchip-ep.c b/drivers/pci/controller/pcie-rockchip-ep.c index c9046e97a1d2..8613df8184df 100644 --- a/drivers/pci/controller/pcie-rockchip-ep.c +++ b/drivers/pci/controller/pcie-rockchip-ep.c @@ -609,6 +609,8 @@ static int rockchip_pcie_ep_probe(struct platform_device *pdev) rockchip_pcie_write(rockchip, PCIE_CLIENT_CONF_ENABLE, PCIE_CLIENT_CONFIG); + pci_epc_init_notify(epc); + return 0; err_epc_mem_exit: pci_epc_mem_exit(epc); diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c index cd4ffb39dcdc..212fc303fb63 100644 --- a/drivers/pci/endpoint/functions/pci-epf-test.c +++ b/drivers/pci/endpoint/functions/pci-epf-test.c @@ -753,6 +753,7 @@ static int pci_epf_test_core_init(struct pci_epf *epf) const struct pci_epc_features *epc_features; struct pci_epc *epc = epf->epc; struct device *dev = &epf->dev; + bool linkup_notifier = false; bool msix_capable = false; bool msi_capable = true; int ret; @@ -795,6 +796,10 @@ static int pci_epf_test_core_init(struct pci_epf *epf) } } + linkup_notifier = epc_features->linkup_notifier; + if (!linkup_notifier) + queue_work(kpcitest_workqueue, &epf_test->cmd_handler.work); + return 0; } @@ -890,8 +895,6 @@ static int pci_epf_test_bind(struct pci_epf *epf) const struct pci_epc_features *epc_features; enum pci_barno test_reg_bar = BAR_0; struct pci_epc *epc = epf->epc; - bool linkup_notifier = false; - bool core_init_notifier = false; if (WARN_ON_ONCE(!epc)) return -EINVAL; @@ -902,8 +905,6 @@ static int pci_epf_test_bind(struct pci_epf *epf) return -EOPNOTSUPP; } - linkup_notifier = epc_features->linkup_notifier; - core_init_notifier = epc_features->core_init_notifier; test_reg_bar = pci_epc_get_first_free_bar(epc_features); if (test_reg_bar < 0) return -EINVAL; @@ -916,21 +917,12 @@ static int pci_epf_test_bind(struct pci_epf *epf) if (ret) return ret; - if (!core_init_notifier) { - ret = pci_epf_test_core_init(epf); - if (ret) - return ret; - } - epf_test->dma_supported = true; ret = pci_epf_test_init_dma_chan(epf_test); if (ret) epf_test->dma_supported = false; - if (!linkup_notifier && !core_init_notifier) - queue_work(kpcitest_workqueue, &epf_test->cmd_handler.work); - return 0; } diff --git a/drivers/pci/endpoint/pci-ep-cfs.c b/drivers/pci/endpoint/pci-ep-cfs.c index 0ea64e24ed61..3b21e28f9b59 100644 --- a/drivers/pci/endpoint/pci-ep-cfs.c +++ b/drivers/pci/endpoint/pci-ep-cfs.c @@ -64,6 +64,9 @@ static int pci_secondary_epc_epf_link(struct config_item *epf_item, return ret; } + /* Send any pending EPC initialization complete to the EPF driver */ + pci_epc_notify_pending_init(epc, epf); + return 0; } @@ -125,6 +128,9 @@ static int pci_primary_epc_epf_link(struct config_item *epf_item, return ret; } + /* Send any pending EPC initialization complete to the EPF driver */ + pci_epc_notify_pending_init(epc, epf); + return 0; } @@ -230,6 +236,9 @@ static int pci_epc_epf_link(struct config_item *epc_item, return ret; } + /* Send any pending EPC initialization complete to the EPF driver */ + pci_epc_notify_pending_init(epc, epf); + return 0; } diff --git a/drivers/pci/endpoint/pci-epc-core.c b/drivers/pci/endpoint/pci-epc-core.c index da3fc0795b0b..47d27ec7439d 100644 --- a/drivers/pci/endpoint/pci-epc-core.c +++ b/drivers/pci/endpoint/pci-epc-core.c @@ -748,10 +748,32 @@ void pci_epc_init_notify(struct pci_epc *epc) epf->event_ops->core_init(epf); mutex_unlock(&epf->lock); } + epc->init_complete = true; mutex_unlock(&epc->list_lock); } EXPORT_SYMBOL_GPL(pci_epc_init_notify); +/** + * pci_epc_notify_pending_init() - Notify the pending EPC device initialization + * complete to the EPF device + * @epc: the EPC device whose core initialization is pending to be notified + * @epf: the EPF device to be notified + * + * Invoke to notify the pending EPC device initialization complete to the EPF + * device. This is used to deliver the notification if the EPC initialization + * got completed before the EPF driver bind. + */ +void pci_epc_notify_pending_init(struct pci_epc *epc, struct pci_epf *epf) +{ + if (epc->init_complete) { + mutex_lock(&epf->lock); + if (epf->event_ops && epf->event_ops->core_init) + epf->event_ops->core_init(epf); + mutex_unlock(&epf->lock); + } +} +EXPORT_SYMBOL_GPL(pci_epc_notify_pending_init); + /** * pci_epc_bme_notify() - Notify the EPF device that the EPC device has received * the BME event from the Root complex diff --git a/include/linux/pci-epc.h b/include/linux/pci-epc.h index cc2f70d061c8..acc5f96161fe 100644 --- a/include/linux/pci-epc.h +++ b/include/linux/pci-epc.h @@ -128,6 +128,8 @@ struct pci_epc_mem { * @group: configfs group representing the PCI EPC device * @lock: mutex to protect pci_epc ops * @function_num_map: bitmap to manage physical function number + * @init_complete: flag to indicate whether the EPC initialization is complete + * or not */ struct pci_epc { struct device dev; @@ -143,6 +145,7 @@ struct pci_epc { /* mutex to protect against concurrent access of EP controller */ struct mutex lock; unsigned long function_num_map; + bool init_complete; }; /** @@ -179,8 +182,6 @@ struct pci_epc_bar_desc { /** * struct pci_epc_features - features supported by a EPC device per function * @linkup_notifier: indicate if the EPC device can notify EPF driver on link up - * @core_init_notifier: indicate cores that can notify about their availability - * for initialization * @msi_capable: indicate if the endpoint function has MSI capability * @msix_capable: indicate if the endpoint function has MSI-X capability * @bar: array specifying the hardware description for each BAR @@ -188,7 +189,6 @@ struct pci_epc_bar_desc { */ struct pci_epc_features { unsigned int linkup_notifier : 1; - unsigned int core_init_notifier : 1; unsigned int msi_capable : 1; unsigned int msix_capable : 1; struct pci_epc_bar_desc bar[PCI_STD_NUM_BARS]; @@ -225,6 +225,7 @@ int pci_epc_add_epf(struct pci_epc *epc, struct pci_epf *epf, void pci_epc_linkup(struct pci_epc *epc); void pci_epc_linkdown(struct pci_epc *epc); void pci_epc_init_notify(struct pci_epc *epc); +void pci_epc_notify_pending_init(struct pci_epc *epc, struct pci_epf *epf); void pci_epc_bme_notify(struct pci_epc *epc); void pci_epc_remove_epf(struct pci_epc *epc, struct pci_epf *epf, enum pci_epc_interface_type type); -- cgit v1.2.3-59-g8ed1b From 417660525d6fb8c34e81f5fa2397370a685e48bc Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Wed, 20 Mar 2024 12:31:48 +0100 Subject: PCI: endpoint: pci-epf-test: Simplify pci_epf_test_alloc_space() loop MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make pci-epf-test use pci_epc_get_next_free_bar() just like pci-epf-ntb.c and pci-epf-vntb.c. Using pci_epc_get_next_free_bar() also makes it more obvious that pci-epf-test does no special configuration at all. (The only configuration pci-epf-test does is setting PCI_BASE_ADDRESS_MEM_TYPE_64 if epc_features has marked the specific BAR as only_64bit. pci_epc_get_next_free_bar() already takes only_64bit into account when looping.) This way, the code is more consistent between EPF drivers, and pci-epf-test does not need to explicitly check if the BAR is reserved, or if the index belongs to a BAR succeeding a 64-bit only BAR. Link: https://lore.kernel.org/linux-pci/20240320113157.322695-2-cassel@kernel.org Signed-off-by: Niklas Cassel Signed-off-by: Krzysztof Wilczyński Reviewed-by: Manivannan Sadhasivam --- drivers/pci/endpoint/functions/pci-epf-test.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c index cd4ffb39dcdc..16dfd61cd9fb 100644 --- a/drivers/pci/endpoint/functions/pci-epf-test.c +++ b/drivers/pci/endpoint/functions/pci-epf-test.c @@ -817,14 +817,13 @@ static int pci_epf_test_alloc_space(struct pci_epf *epf) { struct pci_epf_test *epf_test = epf_get_drvdata(epf); struct device *dev = &epf->dev; - struct pci_epf_bar *epf_bar; size_t msix_table_size = 0; size_t test_reg_bar_size; size_t pba_size = 0; bool msix_capable; void *base; - int bar, add; enum pci_barno test_reg_bar = epf_test->test_reg_bar; + enum pci_barno bar; const struct pci_epc_features *epc_features; size_t test_reg_size; @@ -849,16 +848,14 @@ static int pci_epf_test_alloc_space(struct pci_epf *epf) } epf_test->reg[test_reg_bar] = base; - for (bar = 0; bar < PCI_STD_NUM_BARS; bar += add) { - epf_bar = &epf->bar[bar]; - add = (epf_bar->flags & PCI_BASE_ADDRESS_MEM_TYPE_64) ? 2 : 1; + for (bar = BAR_0; bar < PCI_STD_NUM_BARS; bar++) { + bar = pci_epc_get_next_free_bar(epc_features, bar); + if (bar == NO_BAR) + break; if (bar == test_reg_bar) continue; - if (epc_features->bar[bar].type == BAR_RESERVED) - continue; - base = pci_epf_alloc_space(epf, bar_size[bar], bar, epc_features, PRIMARY_INTERFACE); if (!base) -- cgit v1.2.3-59-g8ed1b From 29a025b6fbf36a218d1210061ff889b13e04bc33 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Wed, 20 Mar 2024 12:31:49 +0100 Subject: PCI: endpoint: Allocate a 64-bit BAR if that is the only option MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pci_epf_alloc_space() already sets the 64-bit flag if the BAR size is larger than 2GB, even if the caller did not explicitly request a 64-bit BAR. Thus, let pci_epf_alloc_space() also set the 64-bit flag if the hardware description says that the specific BAR can only be 64-bit. Link: https://lore.kernel.org/linux-pci/20240320113157.322695-3-cassel@kernel.org Signed-off-by: Niklas Cassel Signed-off-by: Krzysztof Wilczyński Reviewed-by: Manivannan Sadhasivam --- drivers/pci/endpoint/pci-epf-core.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/pci/endpoint/pci-epf-core.c b/drivers/pci/endpoint/pci-epf-core.c index 0a28a0b0911b..323f2a60ab16 100644 --- a/drivers/pci/endpoint/pci-epf-core.c +++ b/drivers/pci/endpoint/pci-epf-core.c @@ -255,6 +255,8 @@ EXPORT_SYMBOL_GPL(pci_epf_free_space); * @type: Identifies if the allocation is for primary EPC or secondary EPC * * Invoke to allocate memory for the PCI EPF register space. + * Flag PCI_BASE_ADDRESS_MEM_TYPE_64 will automatically get set if the BAR + * can only be a 64-bit BAR, or if the requested size is larger than 2 GB. */ void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar, const struct pci_epc_features *epc_features, @@ -304,9 +306,10 @@ void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar, epf_bar[bar].addr = space; epf_bar[bar].size = size; epf_bar[bar].barno = bar; - epf_bar[bar].flags |= upper_32_bits(size) ? - PCI_BASE_ADDRESS_MEM_TYPE_64 : - PCI_BASE_ADDRESS_MEM_TYPE_32; + if (upper_32_bits(size) || epc_features->bar[bar].only_64bit) + epf_bar[bar].flags |= PCI_BASE_ADDRESS_MEM_TYPE_64; + else + epf_bar[bar].flags |= PCI_BASE_ADDRESS_MEM_TYPE_32; return space; } -- cgit v1.2.3-59-g8ed1b From 828e870431aab36910306c71b2024ab586fefc01 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Wed, 20 Mar 2024 12:31:50 +0100 Subject: PCI: endpoint: pci-epf-test: Remove superfluous code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The only reason why we call pci_epf_configure_bar() is to set PCI_BASE_ADDRESS_MEM_TYPE_64 in case the hardware requires it. However, this flag is now automatically set when allocating a BAR that can only be a 64-bit BAR, so we can drop pci_epf_configure_bar() completely. Link: https://lore.kernel.org/linux-pci/20240320113157.322695-4-cassel@kernel.org Signed-off-by: Niklas Cassel Signed-off-by: Krzysztof Wilczyński Reviewed-by: Manivannan Sadhasivam --- drivers/pci/endpoint/functions/pci-epf-test.c | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c index 16dfd61cd9fb..0a83a1901bb7 100644 --- a/drivers/pci/endpoint/functions/pci-epf-test.c +++ b/drivers/pci/endpoint/functions/pci-epf-test.c @@ -867,19 +867,6 @@ static int pci_epf_test_alloc_space(struct pci_epf *epf) return 0; } -static void pci_epf_configure_bar(struct pci_epf *epf, - const struct pci_epc_features *epc_features) -{ - struct pci_epf_bar *epf_bar; - int i; - - for (i = 0; i < PCI_STD_NUM_BARS; i++) { - epf_bar = &epf->bar[i]; - if (epc_features->bar[i].only_64bit) - epf_bar->flags |= PCI_BASE_ADDRESS_MEM_TYPE_64; - } -} - static int pci_epf_test_bind(struct pci_epf *epf) { int ret; @@ -904,7 +891,6 @@ static int pci_epf_test_bind(struct pci_epf *epf) test_reg_bar = pci_epc_get_first_free_bar(epc_features); if (test_reg_bar < 0) return -EINVAL; - pci_epf_configure_bar(epf, epc_features); epf_test->test_reg_bar = test_reg_bar; epf_test->epc_features = epc_features; -- cgit v1.2.3-59-g8ed1b From e49eab944cfb3c0281100ab61e1c5d229e0f7b18 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Wed, 20 Mar 2024 12:31:51 +0100 Subject: PCI: endpoint: pci-epf-test: Simplify pci_epf_test_set_bar() loop MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Simplify the loop in pci_epf_test_set_bar(). If we allocated memory for the BAR, we need to call set_bar() for that BAR, if we did not allocated memory for that BAR, we need to skip. It is as simple as that. This also matches the logic in pci_epf_test_unbind(). A 64-bit BAR will still only be one allocation, with the BAR succeeding the 64-bit BAR being null. While at it, remove the misleading comment. A EPC .set_bar() callback should never change the epf_bar->flags. (E.g. to set a 64-bit BAR if we requested a 32-bit BAR.) A .set_bar() callback should do what we request it to do. If it can't satisfy the request, it should return an error. If platform has a specific requirement, e.g. that a certain BAR has to be a 64-bit BAR, then it should specify that by setting the .only_64bit flag for that specific BAR in epc_features->bar[], such that pci_epf_alloc_space() will return a epf_bar with the 64-bit flag set. (Such that .set_bar() will receive a request to set a 64-bit BAR.) Link: https://lore.kernel.org/linux-pci/20240320113157.322695-5-cassel@kernel.org Signed-off-by: Niklas Cassel Signed-off-by: Krzysztof Wilczyński Reviewed-by: Manivannan Sadhasivam --- drivers/pci/endpoint/functions/pci-epf-test.c | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c index 0a83a1901bb7..faf347216b6b 100644 --- a/drivers/pci/endpoint/functions/pci-epf-test.c +++ b/drivers/pci/endpoint/functions/pci-epf-test.c @@ -709,31 +709,18 @@ static void pci_epf_test_unbind(struct pci_epf *epf) static int pci_epf_test_set_bar(struct pci_epf *epf) { - int bar, add; - int ret; - struct pci_epf_bar *epf_bar; + int bar, ret; struct pci_epc *epc = epf->epc; struct device *dev = &epf->dev; struct pci_epf_test *epf_test = epf_get_drvdata(epf); enum pci_barno test_reg_bar = epf_test->test_reg_bar; - const struct pci_epc_features *epc_features; - epc_features = epf_test->epc_features; - - for (bar = 0; bar < PCI_STD_NUM_BARS; bar += add) { - epf_bar = &epf->bar[bar]; - /* - * pci_epc_set_bar() sets PCI_BASE_ADDRESS_MEM_TYPE_64 - * if the specific implementation required a 64-bit BAR, - * even if we only requested a 32-bit BAR. - */ - add = (epf_bar->flags & PCI_BASE_ADDRESS_MEM_TYPE_64) ? 2 : 1; - - if (epc_features->bar[bar].type == BAR_RESERVED) + for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) { + if (!epf_test->reg[bar]) continue; ret = pci_epc_set_bar(epc, epf->func_no, epf->vfunc_no, - epf_bar); + &epf->bar[bar]); if (ret) { pci_epf_free_space(epf, epf_test->reg[bar], bar, PRIMARY_INTERFACE); -- cgit v1.2.3-59-g8ed1b From 597ac0fa37b86833203c6c73ecbaa72ccc3781bd Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Wed, 20 Mar 2024 12:31:52 +0100 Subject: PCI: endpoint: pci-epf-test: Clean up pci_epf_test_unbind() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Clean up pci_epf_test_unbind() by using a continue if we did not allocate memory for the BAR index. This reduces the indentation level by one. This makes pci_epf_test_unbind() more similar to pci_epf_test_set_bar(). Link: https://lore.kernel.org/linux-pci/20240320113157.322695-6-cassel@kernel.org Signed-off-by: Niklas Cassel Signed-off-by: Krzysztof Wilczyński Reviewed-by: Manivannan Sadhasivam --- drivers/pci/endpoint/functions/pci-epf-test.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c index faf347216b6b..d244a5083d04 100644 --- a/drivers/pci/endpoint/functions/pci-epf-test.c +++ b/drivers/pci/endpoint/functions/pci-epf-test.c @@ -690,20 +690,18 @@ static void pci_epf_test_unbind(struct pci_epf *epf) { struct pci_epf_test *epf_test = epf_get_drvdata(epf); struct pci_epc *epc = epf->epc; - struct pci_epf_bar *epf_bar; int bar; cancel_delayed_work(&epf_test->cmd_handler); pci_epf_test_clean_dma_chan(epf_test); for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) { - epf_bar = &epf->bar[bar]; + if (!epf_test->reg[bar]) + continue; - if (epf_test->reg[bar]) { - pci_epc_clear_bar(epc, epf->func_no, epf->vfunc_no, - epf_bar); - pci_epf_free_space(epf, epf_test->reg[bar], bar, - PRIMARY_INTERFACE); - } + pci_epc_clear_bar(epc, epf->func_no, epf->vfunc_no, + &epf->bar[bar]); + pci_epf_free_space(epf, epf_test->reg[bar], bar, + PRIMARY_INTERFACE); } } -- cgit v1.2.3-59-g8ed1b From 19326006a21da26532d982254677c892dae8f29b Mon Sep 17 00:00:00 2001 From: Vidya Sagar Date: Mon, 8 Apr 2024 15:00:53 +0530 Subject: PCI: tegra194: Fix probe path for Endpoint mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tegra194 PCIe probe path is taking failure path in success case for Endpoint mode. Return success from the switch case instead of going into the failure path. Fixes: c57247f940e8 ("PCI: tegra: Add support for PCIe endpoint mode in Tegra194") Link: https://lore.kernel.org/linux-pci/20240408093053.3948634-1-vidyas@nvidia.com Signed-off-by: Vidya Sagar Signed-off-by: Krzysztof Wilczyński Reviewed-by: Jon Hunter --- drivers/pci/controller/dwc/pcie-tegra194.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c index 1f7b662cb8e1..e440c09d1dc1 100644 --- a/drivers/pci/controller/dwc/pcie-tegra194.c +++ b/drivers/pci/controller/dwc/pcie-tegra194.c @@ -2273,11 +2273,14 @@ static int tegra_pcie_dw_probe(struct platform_device *pdev) ret = tegra_pcie_config_ep(pcie, pdev); if (ret < 0) goto fail; + else + return 0; break; default: dev_err(dev, "Invalid PCIe device type %d\n", pcie->of_data->mode); + ret = -EINVAL; } fail: -- cgit v1.2.3-59-g8ed1b From 8dfd00f7069c54db78463f2a8a8cb677844fdf1f Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 8 Apr 2024 06:38:22 +0000 Subject: soundwire: reconcile dp0_prop and dpn_prop The definitions for DP0 are missing a set of fields that are required to reuse the same configuration code as DPn. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Signed-off-by: Bard Liao Link: https://lore.kernel.org/r/20240408063822.421963-1-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- include/linux/soundwire/sdw.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h index e5d0aa58e7f6..7bb9119f3069 100644 --- a/include/linux/soundwire/sdw.h +++ b/include/linux/soundwire/sdw.h @@ -235,6 +235,7 @@ enum sdw_clk_stop_mode { * @BRA_flow_controlled: Slave implementation results in an OK_NotReady * response * @simple_ch_prep_sm: If channel prepare sequence is required + * @ch_prep_timeout: Port-specific timeout value, in milliseconds * @imp_def_interrupts: If set, each bit corresponds to support for * implementation-defined interrupts * @@ -249,6 +250,7 @@ struct sdw_dp0_prop { u32 *words; bool BRA_flow_controlled; bool simple_ch_prep_sm; + u32 ch_prep_timeout; bool imp_def_interrupts; }; -- cgit v1.2.3-59-g8ed1b From b18c25afabf80972b32a3918f6d7f16fbd54b18f Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 8 Apr 2024 06:22:06 +0000 Subject: soundwire: intel_ace2x: use legacy formula for intel_alh_id Starting with Lunar Lake, the notion of ALH is mostly irrelevant, since the HDaudio DMAs are used. However the firmware still relies on an 'ALH gateway' with a 'node_id' based on the same formula. This patch in isolation has no functional impact, it's only when the ASoC parts use it that we will see a changed behavior. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Signed-off-by: Bard Liao Link: https://lore.kernel.org/r/20240408062206.421326-1-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- drivers/soundwire/intel_ace2x.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/soundwire/intel_ace2x.c b/drivers/soundwire/intel_ace2x.c index 43a348db83bf..22afaf055227 100644 --- a/drivers/soundwire/intel_ace2x.c +++ b/drivers/soundwire/intel_ace2x.c @@ -291,6 +291,11 @@ static int intel_hw_params(struct snd_pcm_substream *substream, goto error; } + /* use same definitions for alh_id as previous generations */ + pdi->intel_alh_id = (sdw->instance * 16) + pdi->num + 3; + if (pdi->num >= 2) + pdi->intel_alh_id += 2; + /* the SHIM will be configured in the callback functions */ sdw_cdns_config_stream(cdns, ch, dir, pdi); -- cgit v1.2.3-59-g8ed1b From fd6eb49a84a85150d5e9ffbd85d3b102303f9470 Mon Sep 17 00:00:00 2001 From: Sergio Paracuellos Date: Thu, 11 Jan 2024 09:27:04 +0100 Subject: PCI: mt7621: Fix string truncation in mt7621_pcie_parse_port() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The following warning appears when driver is compiled with W=1. CC drivers/pci/controller/pcie-mt7621.o drivers/pci/controller/pcie-mt7621.c: In function ‘mt7621_pcie_probe’: drivers/pci/controller/pcie-mt7621.c:228:49: error: ‘snprintf’ output may be truncated before the last format character [-Werror=format-truncation=] 228 | snprintf(name, sizeof(name), "pcie-phy%d", slot); | ^ drivers/pci/controller/pcie-mt7621.c:228:9: note: ‘snprintf’ output between 10 and 11 bytes into a destination of size 10 228 | snprintf(name, sizeof(name), "pcie-phy%d", slot); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Clean this up increasing destination buffer one byte. [kwilczynski: commit log] Closes: https://lore.kernel.org/linux-pci/20240110212302.GA2123146@bhelgaas/T/#t Link: https://lore.kernel.org/linux-pci/20240111082704.2259450-1-sergio.paracuellos@gmail.com Reported-by: Bjorn Helgaas Signed-off-by: Sergio Paracuellos Signed-off-by: Krzysztof Wilczyński --- drivers/pci/controller/pcie-mt7621.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/controller/pcie-mt7621.c b/drivers/pci/controller/pcie-mt7621.c index 79e225edb42a..d97b956e6e57 100644 --- a/drivers/pci/controller/pcie-mt7621.c +++ b/drivers/pci/controller/pcie-mt7621.c @@ -202,7 +202,7 @@ static int mt7621_pcie_parse_port(struct mt7621_pcie *pcie, struct mt7621_pcie_port *port; struct device *dev = pcie->dev; struct platform_device *pdev = to_platform_device(dev); - char name[10]; + char name[11]; int err; port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL); -- cgit v1.2.3-59-g8ed1b From 244b6e92bd1a0b6ff1f6253b10a96dc208a315f2 Mon Sep 17 00:00:00 2001 From: Marc Dietrich Date: Sat, 6 Apr 2024 14:31:19 +0200 Subject: staging: nvec: add ability to ignore EC responses in sync writes In case we just want to submit a message to the EC but are not interested in its response, we can free the response buffer early. Signed-off-by: Marc Dietrich Link: https://lore.kernel.org/r/20240406123123.37148-2-marvin24@gmx.de Signed-off-by: Greg Kroah-Hartman --- drivers/staging/nvec/nvec.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/staging/nvec/nvec.c b/drivers/staging/nvec/nvec.c index b4485b10beb8..e5ca78e57384 100644 --- a/drivers/staging/nvec/nvec.c +++ b/drivers/staging/nvec/nvec.c @@ -300,7 +300,9 @@ int nvec_write_sync(struct nvec_chip *nvec, { mutex_lock(&nvec->sync_write_mutex); - *msg = NULL; + if (msg != NULL) + *msg = NULL; + nvec->sync_write_pending = (data[1] << 8) + data[0]; if (nvec_write_async(nvec, data, size) < 0) { @@ -320,7 +322,10 @@ int nvec_write_sync(struct nvec_chip *nvec, dev_dbg(nvec->dev, "nvec_sync_write: pong!\n"); - *msg = nvec->last_sync_msg; + if (msg != NULL) + *msg = nvec->last_sync_msg; + else + nvec_msg_free(nvec, nvec->last_sync_msg); mutex_unlock(&nvec->sync_write_mutex); -- cgit v1.2.3-59-g8ed1b From 41288dfaf1b8231bc21fd6966e7296b087e75969 Mon Sep 17 00:00:00 2001 From: Marc Dietrich Date: Sat, 6 Apr 2024 14:31:20 +0200 Subject: staging: nvec: make keyboard init synchronous Currently, we are constantly sending commands to the EC without waiting for them to be executed. This can lead to confusion, especially if we initialize several different devices one after the other. To avoid this, we are switching from asynchronous to synchronous command transmission. Signed-off-by: Marc Dietrich Link: https://lore.kernel.org/r/20240406123123.37148-3-marvin24@gmx.de Signed-off-by: Greg Kroah-Hartman --- drivers/staging/nvec/nvec_kbd.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/staging/nvec/nvec_kbd.c b/drivers/staging/nvec/nvec_kbd.c index f9a1da952c0a..d0259c80f810 100644 --- a/drivers/staging/nvec/nvec_kbd.c +++ b/drivers/staging/nvec/nvec_kbd.c @@ -148,15 +148,16 @@ static int nvec_kbd_probe(struct platform_device *pdev) nvec_register_notifier(nvec, &keys_dev.notifier, 0); /* Enable keyboard */ - nvec_write_async(nvec, enable_kbd, 2); + nvec_write_sync(nvec, enable_kbd, 2, NULL); /* configures wake on special keys */ - nvec_write_async(nvec, cnfg_wake, 4); + nvec_write_sync(nvec, cnfg_wake, 4, NULL); + /* enable wake key reporting */ - nvec_write_async(nvec, cnfg_wake_key_reporting, 3); + nvec_write_sync(nvec, cnfg_wake_key_reporting, 3, NULL); /* Disable caps lock LED */ - nvec_write_async(nvec, clear_leds, sizeof(clear_leds)); + nvec_write_sync(nvec, clear_leds, sizeof(clear_leds), NULL); return 0; } -- cgit v1.2.3-59-g8ed1b From 395e9164bf721aff9bbbf8d6ac4f6c988d25980c Mon Sep 17 00:00:00 2001 From: Marc Dietrich Date: Sat, 6 Apr 2024 14:31:21 +0200 Subject: staging: nvec: make touchpad init synchronous MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, we are constantly sending commands to the EC without waiting for them to be executed. For the touchpad initialization this only worked because we were waiting 200 µs between each submitted command byte, so the EC had enough time to execute. In the furture we like to avoid this delay, so we need to wait for each command to be executed first. Do this by switching from asynchronous to synchronous command transmission. Signed-off-by: Marc Dietrich Link: https://lore.kernel.org/r/20240406123123.37148-4-marvin24@gmx.de Signed-off-by: Greg Kroah-Hartman --- drivers/staging/nvec/nvec_ps2.c | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/drivers/staging/nvec/nvec_ps2.c b/drivers/staging/nvec/nvec_ps2.c index cb6d71b8dc83..f34016c4a26b 100644 --- a/drivers/staging/nvec/nvec_ps2.c +++ b/drivers/staging/nvec/nvec_ps2.c @@ -60,16 +60,6 @@ static void ps2_stopstreaming(struct serio *ser_dev) nvec_write_async(ps2_dev.nvec, buf, sizeof(buf)); } -static int ps2_sendcommand(struct serio *ser_dev, unsigned char cmd) -{ - unsigned char buf[] = { NVEC_PS2, SEND_COMMAND, ENABLE_MOUSE, 1 }; - - buf[2] = cmd & 0xff; - - dev_dbg(&ser_dev->dev, "Sending ps2 cmd %02x\n", cmd); - return nvec_write_async(ps2_dev.nvec, buf, sizeof(buf)); -} - static int nvec_ps2_notifier(struct notifier_block *nb, unsigned long event_type, void *data) { @@ -98,6 +88,27 @@ static int nvec_ps2_notifier(struct notifier_block *nb, return NOTIFY_DONE; } +static int ps2_sendcommand(struct serio *ser_dev, unsigned char cmd) +{ + unsigned char buf[] = { NVEC_PS2, SEND_COMMAND, ENABLE_MOUSE, 1 }; + struct nvec_msg *msg; + int ret; + + buf[2] = cmd & 0xff; + + dev_dbg(&ser_dev->dev, "Sending ps2 cmd %02x\n", cmd); + + ret = nvec_write_sync(ps2_dev.nvec, buf, sizeof(buf), &msg); + if (ret < 0) + return ret; + + nvec_ps2_notifier(NULL, NVEC_PS2, msg->data); + + nvec_msg_free(ps2_dev.nvec, msg); + + return 0; +} + static int nvec_mouse_probe(struct platform_device *pdev) { struct nvec_chip *nvec = dev_get_drvdata(pdev->dev.parent); -- cgit v1.2.3-59-g8ed1b From e4d5e3a9ae68250f7cc7e930ffeecba2c9f32832 Mon Sep 17 00:00:00 2001 From: Marc Dietrich Date: Sat, 6 Apr 2024 14:31:23 +0200 Subject: staging: nvec: update TODO Remove isr delay from the bill. Signed-off-by: Marc Dietrich Link: https://lore.kernel.org/r/20240406123123.37148-6-marvin24@gmx.de Signed-off-by: Greg Kroah-Hartman --- drivers/staging/nvec/TODO | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/staging/nvec/TODO b/drivers/staging/nvec/TODO index 8afde3ccc960..33f9ebe6d59b 100644 --- a/drivers/staging/nvec/TODO +++ b/drivers/staging/nvec/TODO @@ -1,5 +1,4 @@ ToDo list (incomplete, unordered) - move the driver to the new i2c slave framework - finish suspend/resume support - - fix udelay in the isr - add atomic ops in order to fix shutoff/reboot problems -- cgit v1.2.3-59-g8ed1b From 2a8e4ab0c93fad30769479f86849e22d63cd0e12 Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Tue, 9 Apr 2024 11:42:49 -0400 Subject: serial: sc16is7xx: add proper sched.h include for sched_set_fifo() Replace incorrect include with the proper one for sched_set_fifo() declaration. Fixes: 28d2f209cd16 ("sched,serial: Convert to sched_set_fifo()") Signed-off-by: Hugo Villeneuve Link: https://lore.kernel.org/r/20240409154253.3043822-2-hugo@hugovil.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sc16is7xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c index 07aca9fc6d97..afcfb4f38945 100644 --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -25,7 +26,6 @@ #include #include #include -#include #define SC16IS7XX_NAME "sc16is7xx" #define SC16IS7XX_MAX_DEVS 8 -- cgit v1.2.3-59-g8ed1b From 7f335744817092112be68efc06404466c135ae52 Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Tue, 9 Apr 2024 11:42:50 -0400 Subject: serial: sc16is7xx: unconditionally clear line bit in sc16is7xx_remove() There is no need to check for previous port registration in sc16is7xx_remove() because if sc16is7xx_probe() succeeded, we are guaranteed to have successfully registered both ports. We can thus unconditionally clear the line allocation bit in sc16is7xx_lines. Signed-off-by: Hugo Villeneuve Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240409154253.3043822-3-hugo@hugovil.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sc16is7xx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c index afcfb4f38945..a134cd2a931d 100644 --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c @@ -1660,8 +1660,8 @@ static void sc16is7xx_remove(struct device *dev) for (i = 0; i < s->devtype->nr_uart; i++) { kthread_cancel_delayed_work_sync(&s->p[i].ms_work); - if (test_and_clear_bit(s->p[i].port.line, sc16is7xx_lines)) - uart_remove_one_port(&sc16is7xx_uart, &s->p[i].port); + clear_bit(s->p[i].port.line, sc16is7xx_lines); + uart_remove_one_port(&sc16is7xx_uart, &s->p[i].port); sc16is7xx_power(&s->p[i].port, 0); } -- cgit v1.2.3-59-g8ed1b From d49216438139bca0454e69b6c4ab8a01af2b72ed Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Tue, 9 Apr 2024 11:42:51 -0400 Subject: serial: sc16is7xx: split into core and I2C/SPI parts (core) Split the common code from sc16is7xx driver and move the I2C and SPI bus parts into interface-specific source files. sc16is7xx becomes the core functions which can support multiple bus interfaces like I2C and SPI. No functional changes intended. Also simplify and improve Kconfig entries. - Capitalize SPI keyword for consistency - Display list of supported ICs each on a separate line (and aligned) to facilitate locating a specific IC model - Add Manufacturer name at start of description string - Add UART keyword to description string Suggested-by: Andy Shevchenko Signed-off-by: Hugo Villeneuve Link: https://lore.kernel.org/r/20240409154253.3043822-4-hugo@hugovil.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/Kconfig | 47 +++----- drivers/tty/serial/Makefile | 2 + drivers/tty/serial/sc16is7xx.c | 225 ++++++------------------------------- drivers/tty/serial/sc16is7xx.h | 41 +++++++ drivers/tty/serial/sc16is7xx_i2c.c | 64 +++++++++++ drivers/tty/serial/sc16is7xx_spi.c | 87 ++++++++++++++ 6 files changed, 248 insertions(+), 218 deletions(-) create mode 100644 drivers/tty/serial/sc16is7xx.h create mode 100644 drivers/tty/serial/sc16is7xx_i2c.c create mode 100644 drivers/tty/serial/sc16is7xx_spi.c diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 5c80505cdf41..4fdd7857ef4d 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -1024,41 +1024,30 @@ config SERIAL_SCCNXP_CONSOLE Support for console on SCCNXP serial ports. config SERIAL_SC16IS7XX_CORE - tristate - -config SERIAL_SC16IS7XX - tristate "SC16IS7xx serial support" + tristate "NXP SC16IS7xx UART support" select SERIAL_CORE - depends on (SPI_MASTER && !I2C) || I2C + select SERIAL_SC16IS7XX_SPI if SPI_MASTER + select SERIAL_SC16IS7XX_I2C if I2C help - This selects support for SC16IS7xx serial ports. - Supported ICs are SC16IS740, SC16IS741, SC16IS750, SC16IS752, - SC16IS760 and SC16IS762. Select supported buses using options below. + Core driver for NXP SC16IS7xx UARTs. + Supported ICs are: + + SC16IS740 + SC16IS741 + SC16IS750 + SC16IS752 + SC16IS760 + SC16IS762 + + The driver supports both I2C and SPI interfaces. config SERIAL_SC16IS7XX_I2C - bool "SC16IS7xx for I2C interface" - depends on SERIAL_SC16IS7XX - depends on I2C - select SERIAL_SC16IS7XX_CORE if SERIAL_SC16IS7XX - select REGMAP_I2C if I2C - default y - help - Enable SC16IS7xx driver on I2C bus, - If required say y, and say n to i2c if not required, - Enabled by default to support oldconfig. - You must select at least one bus for the driver to be built. + tristate + select REGMAP_I2C config SERIAL_SC16IS7XX_SPI - bool "SC16IS7xx for spi interface" - depends on SERIAL_SC16IS7XX - depends on SPI_MASTER - select SERIAL_SC16IS7XX_CORE if SERIAL_SC16IS7XX - select REGMAP_SPI if SPI_MASTER - help - Enable SC16IS7xx driver on SPI bus, - If required say y, and say n to spi if not required, - This is additional support to existing driver. - You must select at least one bus for the driver to be built. + tristate + select REGMAP_SPI config SERIAL_TIMBERDALE tristate "Support for timberdale UART" diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile index b25e9b54a660..faa45f2b8bb0 100644 --- a/drivers/tty/serial/Makefile +++ b/drivers/tty/serial/Makefile @@ -76,6 +76,8 @@ obj-$(CONFIG_SERIAL_SAMSUNG) += samsung_tty.o obj-$(CONFIG_SERIAL_SB1250_DUART) += sb1250-duart.o obj-$(CONFIG_SERIAL_SCCNXP) += sccnxp.o obj-$(CONFIG_SERIAL_SC16IS7XX_CORE) += sc16is7xx.o +obj-$(CONFIG_SERIAL_SC16IS7XX_SPI) += sc16is7xx_spi.o +obj-$(CONFIG_SERIAL_SC16IS7XX_I2C) += sc16is7xx_i2c.o obj-$(CONFIG_SERIAL_SH_SCI) += sh-sci.o obj-$(CONFIG_SERIAL_SIFIVE) += sifive.o obj-$(CONFIG_SERIAL_SPRD) += sprd_serial.o diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c index a134cd2a931d..366eb3f53789 100644 --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c @@ -1,19 +1,22 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * SC16IS7xx tty serial driver - Copyright (C) 2014 GridPoint - * Author: Jon Ringle + * SC16IS7xx tty serial driver - common code * - * Based on max310x.c, by Alexander Shiyan + * Copyright (C) 2014 GridPoint + * Author: Jon Ringle + * Based on max310x.c, by Alexander Shiyan */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#undef DEFAULT_SYMBOL_NAMESPACE +#define DEFAULT_SYMBOL_NAMESPACE SERIAL_NXP_SC16IS7XX #include #include #include #include +#include #include -#include +#include #include #include #include @@ -21,15 +24,15 @@ #include #include #include +#include #include #include -#include #include #include -#define SC16IS7XX_NAME "sc16is7xx" +#include "sc16is7xx.h" + #define SC16IS7XX_MAX_DEVS 8 -#define SC16IS7XX_MAX_PORTS 2 /* Maximum number of UART ports per IC. */ /* SC16IS7XX register definitions */ #define SC16IS7XX_RHR_REG (0x00) /* RX FIFO */ @@ -302,16 +305,9 @@ /* Misc definitions */ -#define SC16IS7XX_SPI_READ_BIT BIT(7) #define SC16IS7XX_FIFO_SIZE (64) #define SC16IS7XX_GPIOS_PER_BANK 4 -struct sc16is7xx_devtype { - char name[10]; - int nr_gpio; - int nr_uart; -}; - #define SC16IS7XX_RECONF_MD (1 << 0) #define SC16IS7XX_RECONF_IER (1 << 1) #define SC16IS7XX_RECONF_RS485 (1 << 2) @@ -492,35 +488,40 @@ static void sc16is7xx_stop_rx(struct uart_port *port) sc16is7xx_ier_clear(port, SC16IS7XX_IER_RDI_BIT); } -static const struct sc16is7xx_devtype sc16is74x_devtype = { +const struct sc16is7xx_devtype sc16is74x_devtype = { .name = "SC16IS74X", .nr_gpio = 0, .nr_uart = 1, }; +EXPORT_SYMBOL_GPL(sc16is74x_devtype); -static const struct sc16is7xx_devtype sc16is750_devtype = { +const struct sc16is7xx_devtype sc16is750_devtype = { .name = "SC16IS750", .nr_gpio = 8, .nr_uart = 1, }; +EXPORT_SYMBOL_GPL(sc16is750_devtype); -static const struct sc16is7xx_devtype sc16is752_devtype = { +const struct sc16is7xx_devtype sc16is752_devtype = { .name = "SC16IS752", .nr_gpio = 8, .nr_uart = 2, }; +EXPORT_SYMBOL_GPL(sc16is752_devtype); -static const struct sc16is7xx_devtype sc16is760_devtype = { +const struct sc16is7xx_devtype sc16is760_devtype = { .name = "SC16IS760", .nr_gpio = 8, .nr_uart = 1, }; +EXPORT_SYMBOL_GPL(sc16is760_devtype); -static const struct sc16is7xx_devtype sc16is762_devtype = { +const struct sc16is7xx_devtype sc16is762_devtype = { .name = "SC16IS762", .nr_gpio = 8, .nr_uart = 2, }; +EXPORT_SYMBOL_GPL(sc16is762_devtype); static bool sc16is7xx_regmap_volatile(struct device *dev, unsigned int reg) { @@ -1453,9 +1454,8 @@ static const struct serial_rs485 sc16is7xx_rs485_supported = { .delay_rts_after_send = 1, /* Not supported but keep returning -EINVAL */ }; -static int sc16is7xx_probe(struct device *dev, - const struct sc16is7xx_devtype *devtype, - struct regmap *regmaps[], int irq) +int sc16is7xx_probe(struct device *dev, const struct sc16is7xx_devtype *devtype, + struct regmap *regmaps[], int irq) { unsigned long freq = 0, *pfreq = dev_get_platdata(dev); unsigned int val; @@ -1647,8 +1647,9 @@ out_clk: return ret; } +EXPORT_SYMBOL_GPL(sc16is7xx_probe); -static void sc16is7xx_remove(struct device *dev) +void sc16is7xx_remove(struct device *dev) { struct sc16is7xx_port *s = dev_get_drvdata(dev); int i; @@ -1670,8 +1671,9 @@ static void sc16is7xx_remove(struct device *dev) clk_disable_unprepare(s->clk); } +EXPORT_SYMBOL_GPL(sc16is7xx_remove); -static const struct of_device_id __maybe_unused sc16is7xx_dt_ids[] = { +const struct of_device_id __maybe_unused sc16is7xx_dt_ids[] = { { .compatible = "nxp,sc16is740", .data = &sc16is74x_devtype, }, { .compatible = "nxp,sc16is741", .data = &sc16is74x_devtype, }, { .compatible = "nxp,sc16is750", .data = &sc16is750_devtype, }, @@ -1680,9 +1682,10 @@ static const struct of_device_id __maybe_unused sc16is7xx_dt_ids[] = { { .compatible = "nxp,sc16is762", .data = &sc16is762_devtype, }, { } }; +EXPORT_SYMBOL_GPL(sc16is7xx_dt_ids); MODULE_DEVICE_TABLE(of, sc16is7xx_dt_ids); -static struct regmap_config regcfg = { +struct regmap_config sc16is7xx_regcfg = { .reg_bits = 5, .pad_bits = 3, .val_bits = 8, @@ -1695,8 +1698,9 @@ static struct regmap_config regcfg = { .max_raw_write = SC16IS7XX_FIFO_SIZE, .max_register = SC16IS7XX_EFCR_REG, }; +EXPORT_SYMBOL_GPL(sc16is7xx_regcfg); -static const char *sc16is7xx_regmap_name(u8 port_id) +const char *sc16is7xx_regmap_name(u8 port_id) { switch (port_id) { case 0: return "port0"; @@ -1706,184 +1710,27 @@ static const char *sc16is7xx_regmap_name(u8 port_id) return NULL; } } +EXPORT_SYMBOL_GPL(sc16is7xx_regmap_name); -static unsigned int sc16is7xx_regmap_port_mask(unsigned int port_id) +unsigned int sc16is7xx_regmap_port_mask(unsigned int port_id) { /* CH1,CH0 are at bits 2:1. */ return port_id << 1; } - -#ifdef CONFIG_SERIAL_SC16IS7XX_SPI -static int sc16is7xx_spi_probe(struct spi_device *spi) -{ - const struct sc16is7xx_devtype *devtype; - struct regmap *regmaps[SC16IS7XX_MAX_PORTS]; - unsigned int i; - int ret; - - /* Setup SPI bus */ - spi->bits_per_word = 8; - /* For all variants, only mode 0 is supported */ - if ((spi->mode & SPI_MODE_X_MASK) != SPI_MODE_0) - return dev_err_probe(&spi->dev, -EINVAL, "Unsupported SPI mode\n"); - - spi->mode = spi->mode ? : SPI_MODE_0; - spi->max_speed_hz = spi->max_speed_hz ? : 4 * HZ_PER_MHZ; - ret = spi_setup(spi); - if (ret) - return ret; - - devtype = spi_get_device_match_data(spi); - if (!devtype) - return dev_err_probe(&spi->dev, -ENODEV, "Failed to match device\n"); - - for (i = 0; i < devtype->nr_uart; i++) { - regcfg.name = sc16is7xx_regmap_name(i); - /* - * If read_flag_mask is 0, the regmap code sets it to a default - * of 0x80. Since we specify our own mask, we must add the READ - * bit ourselves: - */ - regcfg.read_flag_mask = sc16is7xx_regmap_port_mask(i) | - SC16IS7XX_SPI_READ_BIT; - regcfg.write_flag_mask = sc16is7xx_regmap_port_mask(i); - regmaps[i] = devm_regmap_init_spi(spi, ®cfg); - } - - return sc16is7xx_probe(&spi->dev, devtype, regmaps, spi->irq); -} - -static void sc16is7xx_spi_remove(struct spi_device *spi) -{ - sc16is7xx_remove(&spi->dev); -} - -static const struct spi_device_id sc16is7xx_spi_id_table[] = { - { "sc16is74x", (kernel_ulong_t)&sc16is74x_devtype, }, - { "sc16is740", (kernel_ulong_t)&sc16is74x_devtype, }, - { "sc16is741", (kernel_ulong_t)&sc16is74x_devtype, }, - { "sc16is750", (kernel_ulong_t)&sc16is750_devtype, }, - { "sc16is752", (kernel_ulong_t)&sc16is752_devtype, }, - { "sc16is760", (kernel_ulong_t)&sc16is760_devtype, }, - { "sc16is762", (kernel_ulong_t)&sc16is762_devtype, }, - { } -}; - -MODULE_DEVICE_TABLE(spi, sc16is7xx_spi_id_table); - -static struct spi_driver sc16is7xx_spi_uart_driver = { - .driver = { - .name = SC16IS7XX_NAME, - .of_match_table = sc16is7xx_dt_ids, - }, - .probe = sc16is7xx_spi_probe, - .remove = sc16is7xx_spi_remove, - .id_table = sc16is7xx_spi_id_table, -}; -#endif - -#ifdef CONFIG_SERIAL_SC16IS7XX_I2C -static int sc16is7xx_i2c_probe(struct i2c_client *i2c) -{ - const struct sc16is7xx_devtype *devtype; - struct regmap *regmaps[SC16IS7XX_MAX_PORTS]; - unsigned int i; - - devtype = i2c_get_match_data(i2c); - if (!devtype) - return dev_err_probe(&i2c->dev, -ENODEV, "Failed to match device\n"); - - for (i = 0; i < devtype->nr_uart; i++) { - regcfg.name = sc16is7xx_regmap_name(i); - regcfg.read_flag_mask = sc16is7xx_regmap_port_mask(i); - regcfg.write_flag_mask = sc16is7xx_regmap_port_mask(i); - regmaps[i] = devm_regmap_init_i2c(i2c, ®cfg); - } - - return sc16is7xx_probe(&i2c->dev, devtype, regmaps, i2c->irq); -} - -static void sc16is7xx_i2c_remove(struct i2c_client *client) -{ - sc16is7xx_remove(&client->dev); -} - -static const struct i2c_device_id sc16is7xx_i2c_id_table[] = { - { "sc16is74x", (kernel_ulong_t)&sc16is74x_devtype, }, - { "sc16is740", (kernel_ulong_t)&sc16is74x_devtype, }, - { "sc16is741", (kernel_ulong_t)&sc16is74x_devtype, }, - { "sc16is750", (kernel_ulong_t)&sc16is750_devtype, }, - { "sc16is752", (kernel_ulong_t)&sc16is752_devtype, }, - { "sc16is760", (kernel_ulong_t)&sc16is760_devtype, }, - { "sc16is762", (kernel_ulong_t)&sc16is762_devtype, }, - { } -}; -MODULE_DEVICE_TABLE(i2c, sc16is7xx_i2c_id_table); - -static struct i2c_driver sc16is7xx_i2c_uart_driver = { - .driver = { - .name = SC16IS7XX_NAME, - .of_match_table = sc16is7xx_dt_ids, - }, - .probe = sc16is7xx_i2c_probe, - .remove = sc16is7xx_i2c_remove, - .id_table = sc16is7xx_i2c_id_table, -}; - -#endif +EXPORT_SYMBOL_GPL(sc16is7xx_regmap_port_mask); static int __init sc16is7xx_init(void) { - int ret; - - ret = uart_register_driver(&sc16is7xx_uart); - if (ret) { - pr_err("Registering UART driver failed\n"); - return ret; - } - -#ifdef CONFIG_SERIAL_SC16IS7XX_I2C - ret = i2c_add_driver(&sc16is7xx_i2c_uart_driver); - if (ret < 0) { - pr_err("failed to init sc16is7xx i2c --> %d\n", ret); - goto err_i2c; - } -#endif - -#ifdef CONFIG_SERIAL_SC16IS7XX_SPI - ret = spi_register_driver(&sc16is7xx_spi_uart_driver); - if (ret < 0) { - pr_err("failed to init sc16is7xx spi --> %d\n", ret); - goto err_spi; - } -#endif - return ret; - -#ifdef CONFIG_SERIAL_SC16IS7XX_SPI -err_spi: -#endif -#ifdef CONFIG_SERIAL_SC16IS7XX_I2C - i2c_del_driver(&sc16is7xx_i2c_uart_driver); -err_i2c: -#endif - uart_unregister_driver(&sc16is7xx_uart); - return ret; + return uart_register_driver(&sc16is7xx_uart); } module_init(sc16is7xx_init); static void __exit sc16is7xx_exit(void) { -#ifdef CONFIG_SERIAL_SC16IS7XX_I2C - i2c_del_driver(&sc16is7xx_i2c_uart_driver); -#endif - -#ifdef CONFIG_SERIAL_SC16IS7XX_SPI - spi_unregister_driver(&sc16is7xx_spi_uart_driver); -#endif uart_unregister_driver(&sc16is7xx_uart); } module_exit(sc16is7xx_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Jon Ringle "); -MODULE_DESCRIPTION("SC16IS7XX serial driver"); +MODULE_DESCRIPTION("SC16IS7xx tty serial core driver"); diff --git a/drivers/tty/serial/sc16is7xx.h b/drivers/tty/serial/sc16is7xx.h new file mode 100644 index 000000000000..2ee3ce83d95a --- /dev/null +++ b/drivers/tty/serial/sc16is7xx.h @@ -0,0 +1,41 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* SC16IS7xx SPI/I2C tty serial driver */ + +#ifndef _SC16IS7XX_H_ +#define _SC16IS7XX_H_ + +#include +#include +#include + +#define SC16IS7XX_NAME "sc16is7xx" +#define SC16IS7XX_MAX_PORTS 2 /* Maximum number of UART ports per IC. */ + +struct device; + +struct sc16is7xx_devtype { + char name[10]; + int nr_gpio; + int nr_uart; +}; + +extern struct regmap_config sc16is7xx_regcfg; + +extern const struct of_device_id sc16is7xx_dt_ids[]; + +extern const struct sc16is7xx_devtype sc16is74x_devtype; +extern const struct sc16is7xx_devtype sc16is750_devtype; +extern const struct sc16is7xx_devtype sc16is752_devtype; +extern const struct sc16is7xx_devtype sc16is760_devtype; +extern const struct sc16is7xx_devtype sc16is762_devtype; + +const char *sc16is7xx_regmap_name(u8 port_id); + +unsigned int sc16is7xx_regmap_port_mask(unsigned int port_id); + +int sc16is7xx_probe(struct device *dev, const struct sc16is7xx_devtype *devtype, + struct regmap *regmaps[], int irq); + +void sc16is7xx_remove(struct device *dev); + +#endif /* _SC16IS7XX_H_ */ diff --git a/drivers/tty/serial/sc16is7xx_i2c.c b/drivers/tty/serial/sc16is7xx_i2c.c new file mode 100644 index 000000000000..de51d1675abf --- /dev/null +++ b/drivers/tty/serial/sc16is7xx_i2c.c @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* SC16IS7xx I2C interface driver */ + +#include +#include +#include +#include +#include +#include + +#include "sc16is7xx.h" + +static int sc16is7xx_i2c_probe(struct i2c_client *i2c) +{ + const struct sc16is7xx_devtype *devtype; + struct regmap *regmaps[SC16IS7XX_MAX_PORTS]; + unsigned int i; + + devtype = i2c_get_match_data(i2c); + if (!devtype) + return dev_err_probe(&i2c->dev, -ENODEV, "Failed to match device\n"); + + for (i = 0; i < devtype->nr_uart; i++) { + sc16is7xx_regcfg.name = sc16is7xx_regmap_name(i); + sc16is7xx_regcfg.read_flag_mask = sc16is7xx_regmap_port_mask(i); + sc16is7xx_regcfg.write_flag_mask = sc16is7xx_regmap_port_mask(i); + regmaps[i] = devm_regmap_init_i2c(i2c, &sc16is7xx_regcfg); + } + + return sc16is7xx_probe(&i2c->dev, devtype, regmaps, i2c->irq); +} + +static void sc16is7xx_i2c_remove(struct i2c_client *client) +{ + sc16is7xx_remove(&client->dev); +} + +static const struct i2c_device_id sc16is7xx_i2c_id_table[] = { + { "sc16is74x", (kernel_ulong_t)&sc16is74x_devtype, }, + { "sc16is740", (kernel_ulong_t)&sc16is74x_devtype, }, + { "sc16is741", (kernel_ulong_t)&sc16is74x_devtype, }, + { "sc16is750", (kernel_ulong_t)&sc16is750_devtype, }, + { "sc16is752", (kernel_ulong_t)&sc16is752_devtype, }, + { "sc16is760", (kernel_ulong_t)&sc16is760_devtype, }, + { "sc16is762", (kernel_ulong_t)&sc16is762_devtype, }, + { } +}; +MODULE_DEVICE_TABLE(i2c, sc16is7xx_i2c_id_table); + +static struct i2c_driver sc16is7xx_i2c_driver = { + .driver = { + .name = SC16IS7XX_NAME, + .of_match_table = sc16is7xx_dt_ids, + }, + .probe = sc16is7xx_i2c_probe, + .remove = sc16is7xx_i2c_remove, + .id_table = sc16is7xx_i2c_id_table, +}; + +module_i2c_driver(sc16is7xx_i2c_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("SC16IS7xx I2C interface driver"); +MODULE_IMPORT_NS(SERIAL_NXP_SC16IS7XX); diff --git a/drivers/tty/serial/sc16is7xx_spi.c b/drivers/tty/serial/sc16is7xx_spi.c new file mode 100644 index 000000000000..f110c4e6dce6 --- /dev/null +++ b/drivers/tty/serial/sc16is7xx_spi.c @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* SC16IS7xx SPI interface driver */ + +#include +#include +#include +#include +#include +#include +#include + +#include "sc16is7xx.h" + +/* SPI definitions */ +#define SC16IS7XX_SPI_READ_BIT BIT(7) + +static int sc16is7xx_spi_probe(struct spi_device *spi) +{ + const struct sc16is7xx_devtype *devtype; + struct regmap *regmaps[SC16IS7XX_MAX_PORTS]; + unsigned int i; + int ret; + + /* Setup SPI bus */ + spi->bits_per_word = 8; + /* For all variants, only mode 0 is supported */ + if ((spi->mode & SPI_MODE_X_MASK) != SPI_MODE_0) + return dev_err_probe(&spi->dev, -EINVAL, "Unsupported SPI mode\n"); + + spi->mode = spi->mode ? : SPI_MODE_0; + spi->max_speed_hz = spi->max_speed_hz ? : 4 * HZ_PER_MHZ; + ret = spi_setup(spi); + if (ret) + return ret; + + devtype = spi_get_device_match_data(spi); + if (!devtype) + return dev_err_probe(&spi->dev, -ENODEV, "Failed to match device\n"); + + for (i = 0; i < devtype->nr_uart; i++) { + sc16is7xx_regcfg.name = sc16is7xx_regmap_name(i); + /* + * If read_flag_mask is 0, the regmap code sets it to a default + * of 0x80. Since we specify our own mask, we must add the READ + * bit ourselves: + */ + sc16is7xx_regcfg.read_flag_mask = sc16is7xx_regmap_port_mask(i) | + SC16IS7XX_SPI_READ_BIT; + sc16is7xx_regcfg.write_flag_mask = sc16is7xx_regmap_port_mask(i); + regmaps[i] = devm_regmap_init_spi(spi, &sc16is7xx_regcfg); + } + + return sc16is7xx_probe(&spi->dev, devtype, regmaps, spi->irq); +} + +static void sc16is7xx_spi_remove(struct spi_device *spi) +{ + sc16is7xx_remove(&spi->dev); +} + +static const struct spi_device_id sc16is7xx_spi_id_table[] = { + { "sc16is74x", (kernel_ulong_t)&sc16is74x_devtype, }, + { "sc16is740", (kernel_ulong_t)&sc16is74x_devtype, }, + { "sc16is741", (kernel_ulong_t)&sc16is74x_devtype, }, + { "sc16is750", (kernel_ulong_t)&sc16is750_devtype, }, + { "sc16is752", (kernel_ulong_t)&sc16is752_devtype, }, + { "sc16is760", (kernel_ulong_t)&sc16is760_devtype, }, + { "sc16is762", (kernel_ulong_t)&sc16is762_devtype, }, + { } +}; +MODULE_DEVICE_TABLE(spi, sc16is7xx_spi_id_table); + +static struct spi_driver sc16is7xx_spi_driver = { + .driver = { + .name = SC16IS7XX_NAME, + .of_match_table = sc16is7xx_dt_ids, + }, + .probe = sc16is7xx_spi_probe, + .remove = sc16is7xx_spi_remove, + .id_table = sc16is7xx_spi_id_table, +}; + +module_spi_driver(sc16is7xx_spi_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("SC16IS7xx SPI interface driver"); +MODULE_IMPORT_NS(SERIAL_NXP_SC16IS7XX); -- cgit v1.2.3-59-g8ed1b From cf9c37530fdabc0c25a896ff56f4c9208dcb9c86 Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Tue, 9 Apr 2024 11:42:52 -0400 Subject: serial: sc16is7xx: split into core and I2C/SPI parts (sc16is7xx_lines) Before, sc16is7xx_lines was checked for a free (zero) bit first, and then later it was set only if UART port registration succeeded. Now that sc16is7xx_lines is shared for the I2C and SPI drivers, there is a possibility that the two drivers can simultaneously try to reserve the same line bit at the same time. To prevent this, make sure line allocation is reserved atomically, and use a new variable to hold the status of UART port registration. Now that we no longer need to search if a bit is set, it is now possible to simplify sc16is7xx_lines allocation by using the IDA framework. Link: https://lore.kernel.org/all/20231212150302.a9ec5d085a4ba65e89ca41af@hugovil.com/ Link: https://lore.kernel.org/all/CAHp75VebCZckUrNraYQj9k=Mrn2kbYs1Lx26f5-8rKJ3RXeh-w@mail.gmail.com/ Suggested-by: Andy Shevchenko Signed-off-by: Hugo Villeneuve Link: https://lore.kernel.org/r/20240409154253.3043822-5-hugo@hugovil.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sc16is7xx.c | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c index 366eb3f53789..9c9673243c4c 100644 --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c @@ -10,12 +10,12 @@ #undef DEFAULT_SYMBOL_NAMESPACE #define DEFAULT_SYMBOL_NAMESPACE SERIAL_NXP_SC16IS7XX -#include #include #include #include #include #include +#include #include #include #include @@ -345,7 +345,7 @@ struct sc16is7xx_port { struct sc16is7xx_one p[]; }; -static DECLARE_BITMAP(sc16is7xx_lines, SC16IS7XX_MAX_DEVS); +static DEFINE_IDA(sc16is7xx_lines); static struct uart_driver sc16is7xx_uart = { .owner = THIS_MODULE, @@ -1462,6 +1462,7 @@ int sc16is7xx_probe(struct device *dev, const struct sc16is7xx_devtype *devtype, u32 uartclk = 0; int i, ret; struct sc16is7xx_port *s; + bool port_registered[SC16IS7XX_MAX_PORTS]; for (i = 0; i < devtype->nr_uart; i++) if (IS_ERR(regmaps[i])) @@ -1526,13 +1527,19 @@ int sc16is7xx_probe(struct device *dev, const struct sc16is7xx_devtype *devtype, regmap_write(regmaps[0], SC16IS7XX_IOCONTROL_REG, SC16IS7XX_IOCONTROL_SRESET_BIT); + /* Mark each port line and status as uninitialised. */ for (i = 0; i < devtype->nr_uart; ++i) { - s->p[i].port.line = find_first_zero_bit(sc16is7xx_lines, - SC16IS7XX_MAX_DEVS); - if (s->p[i].port.line >= SC16IS7XX_MAX_DEVS) { - ret = -ERANGE; + s->p[i].port.line = SC16IS7XX_MAX_DEVS; + port_registered[i] = false; + } + + for (i = 0; i < devtype->nr_uart; ++i) { + ret = ida_alloc_max(&sc16is7xx_lines, + SC16IS7XX_MAX_DEVS - 1, GFP_KERNEL); + if (ret < 0) goto out_ports; - } + + s->p[i].port.line = ret; /* Initialize port data */ s->p[i].port.dev = dev; @@ -1578,7 +1585,7 @@ int sc16is7xx_probe(struct device *dev, const struct sc16is7xx_devtype *devtype, if (ret) goto out_ports; - set_bit(s->p[i].port.line, sc16is7xx_lines); + port_registered[i] = true; /* Enable EFR */ sc16is7xx_port_write(&s->p[i].port, SC16IS7XX_LCR_REG, @@ -1636,9 +1643,12 @@ int sc16is7xx_probe(struct device *dev, const struct sc16is7xx_devtype *devtype, #endif out_ports: - for (i = 0; i < devtype->nr_uart; i++) - if (test_and_clear_bit(s->p[i].port.line, sc16is7xx_lines)) + for (i = 0; i < devtype->nr_uart; i++) { + if (s->p[i].port.line < SC16IS7XX_MAX_DEVS) + ida_free(&sc16is7xx_lines, s->p[i].port.line); + if (port_registered[i]) uart_remove_one_port(&sc16is7xx_uart, &s->p[i].port); + } kthread_stop(s->kworker_task); @@ -1661,7 +1671,7 @@ void sc16is7xx_remove(struct device *dev) for (i = 0; i < s->devtype->nr_uart; i++) { kthread_cancel_delayed_work_sync(&s->p[i].ms_work); - clear_bit(s->p[i].port.line, sc16is7xx_lines); + ida_free(&sc16is7xx_lines, s->p[i].port.line); uart_remove_one_port(&sc16is7xx_uart, &s->p[i].port); sc16is7xx_power(&s->p[i].port, 0); } -- cgit v1.2.3-59-g8ed1b From 48d4a801be0ff64740832fcc71ac4632c12fd73b Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Tue, 9 Apr 2024 11:42:53 -0400 Subject: serial: sc16is7xx: split into core and I2C/SPI parts (sc16is7xx_regcfg) Since each I2C/SPI probe function can modify sc16is7xx_regcfg at the same time, change structure to be constant and do the required modifications on a local copy. Signed-off-by: Hugo Villeneuve Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240409154253.3043822-6-hugo@hugovil.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sc16is7xx.c | 2 +- drivers/tty/serial/sc16is7xx.h | 2 +- drivers/tty/serial/sc16is7xx_i2c.c | 11 +++++++---- drivers/tty/serial/sc16is7xx_spi.c | 11 +++++++---- 4 files changed, 16 insertions(+), 10 deletions(-) diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c index 9c9673243c4c..03cf30e20b75 100644 --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c @@ -1695,7 +1695,7 @@ const struct of_device_id __maybe_unused sc16is7xx_dt_ids[] = { EXPORT_SYMBOL_GPL(sc16is7xx_dt_ids); MODULE_DEVICE_TABLE(of, sc16is7xx_dt_ids); -struct regmap_config sc16is7xx_regcfg = { +const struct regmap_config sc16is7xx_regcfg = { .reg_bits = 5, .pad_bits = 3, .val_bits = 8, diff --git a/drivers/tty/serial/sc16is7xx.h b/drivers/tty/serial/sc16is7xx.h index 2ee3ce83d95a..afb784eaee45 100644 --- a/drivers/tty/serial/sc16is7xx.h +++ b/drivers/tty/serial/sc16is7xx.h @@ -19,7 +19,7 @@ struct sc16is7xx_devtype { int nr_uart; }; -extern struct regmap_config sc16is7xx_regcfg; +extern const struct regmap_config sc16is7xx_regcfg; extern const struct of_device_id sc16is7xx_dt_ids[]; diff --git a/drivers/tty/serial/sc16is7xx_i2c.c b/drivers/tty/serial/sc16is7xx_i2c.c index de51d1675abf..3ed47c306d85 100644 --- a/drivers/tty/serial/sc16is7xx_i2c.c +++ b/drivers/tty/serial/sc16is7xx_i2c.c @@ -14,17 +14,20 @@ static int sc16is7xx_i2c_probe(struct i2c_client *i2c) { const struct sc16is7xx_devtype *devtype; struct regmap *regmaps[SC16IS7XX_MAX_PORTS]; + struct regmap_config regcfg; unsigned int i; devtype = i2c_get_match_data(i2c); if (!devtype) return dev_err_probe(&i2c->dev, -ENODEV, "Failed to match device\n"); + memcpy(®cfg, &sc16is7xx_regcfg, sizeof(struct regmap_config)); + for (i = 0; i < devtype->nr_uart; i++) { - sc16is7xx_regcfg.name = sc16is7xx_regmap_name(i); - sc16is7xx_regcfg.read_flag_mask = sc16is7xx_regmap_port_mask(i); - sc16is7xx_regcfg.write_flag_mask = sc16is7xx_regmap_port_mask(i); - regmaps[i] = devm_regmap_init_i2c(i2c, &sc16is7xx_regcfg); + regcfg.name = sc16is7xx_regmap_name(i); + regcfg.read_flag_mask = sc16is7xx_regmap_port_mask(i); + regcfg.write_flag_mask = sc16is7xx_regmap_port_mask(i); + regmaps[i] = devm_regmap_init_i2c(i2c, ®cfg); } return sc16is7xx_probe(&i2c->dev, devtype, regmaps, i2c->irq); diff --git a/drivers/tty/serial/sc16is7xx_spi.c b/drivers/tty/serial/sc16is7xx_spi.c index f110c4e6dce6..73df36f8a7fd 100644 --- a/drivers/tty/serial/sc16is7xx_spi.c +++ b/drivers/tty/serial/sc16is7xx_spi.c @@ -18,6 +18,7 @@ static int sc16is7xx_spi_probe(struct spi_device *spi) { const struct sc16is7xx_devtype *devtype; struct regmap *regmaps[SC16IS7XX_MAX_PORTS]; + struct regmap_config regcfg; unsigned int i; int ret; @@ -37,17 +38,19 @@ static int sc16is7xx_spi_probe(struct spi_device *spi) if (!devtype) return dev_err_probe(&spi->dev, -ENODEV, "Failed to match device\n"); + memcpy(®cfg, &sc16is7xx_regcfg, sizeof(struct regmap_config)); + for (i = 0; i < devtype->nr_uart; i++) { - sc16is7xx_regcfg.name = sc16is7xx_regmap_name(i); + regcfg.name = sc16is7xx_regmap_name(i); /* * If read_flag_mask is 0, the regmap code sets it to a default * of 0x80. Since we specify our own mask, we must add the READ * bit ourselves: */ - sc16is7xx_regcfg.read_flag_mask = sc16is7xx_regmap_port_mask(i) | + regcfg.read_flag_mask = sc16is7xx_regmap_port_mask(i) | SC16IS7XX_SPI_READ_BIT; - sc16is7xx_regcfg.write_flag_mask = sc16is7xx_regmap_port_mask(i); - regmaps[i] = devm_regmap_init_spi(spi, &sc16is7xx_regcfg); + regcfg.write_flag_mask = sc16is7xx_regmap_port_mask(i); + regmaps[i] = devm_regmap_init_spi(spi, ®cfg); } return sc16is7xx_probe(&spi->dev, devtype, regmaps, spi->irq); -- cgit v1.2.3-59-g8ed1b From 4547cd76f08a6f301f6ad563f5d0e4566924ec6b Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Thu, 11 Apr 2024 11:06:20 +0300 Subject: serial: 8250: Fix add preferred console for serial8250_isa_init_ports() We need to inline serial_base_add_isa_preferred_console() based on CONFIG_SERIAL_8250_CONSOLE and not based on CONFIG_SERIAL_CORE_CONSOLE. Otherwise we can get the follwoing error as noted by Stephen: ERROR: modpost: "serial_base_add_isa_preferred_console" [drivers/tty/serial/8250/8250.ko] undefined! We also have a duplicate inlined serial_base_add_isa_preferred_console(), in serial_base_bus.c added by the same commit by accident, let's drop it. Fixes: a8b04cfe7dad ("serial: 8250: Add preferred console in serial8250_isa_init_ports()") Reported-by: Stephen Rothwell Signed-off-by: Tony Lindgren Link: https://lore.kernel.org/r/20240411080622.11929-1-tony@atomide.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_base.h | 10 ++++++++-- drivers/tty/serial/serial_base_bus.c | 11 ++--------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/drivers/tty/serial/serial_base.h b/drivers/tty/serial/serial_base.h index 39dab6bd4b76..ab6f1876726c 100644 --- a/drivers/tty/serial/serial_base.h +++ b/drivers/tty/serial/serial_base.h @@ -51,8 +51,6 @@ void serial_core_unregister_port(struct uart_driver *drv, struct uart_port *port int serial_base_add_preferred_console(struct uart_driver *drv, struct uart_port *port); -int serial_base_add_isa_preferred_console(const char *name, int idx); - #else static inline @@ -62,6 +60,14 @@ int serial_base_add_preferred_console(struct uart_driver *drv, return 0; } +#endif + +#ifdef CONFIG_SERIAL_8250_CONSOLE + +int serial_base_add_isa_preferred_console(const char *name, int idx); + +#else + static inline int serial_base_add_isa_preferred_console(const char *name, int idx) { diff --git a/drivers/tty/serial/serial_base_bus.c b/drivers/tty/serial/serial_base_bus.c index ae18871c0f36..281a2d5a7332 100644 --- a/drivers/tty/serial/serial_base_bus.c +++ b/drivers/tty/serial/serial_base_bus.c @@ -219,6 +219,8 @@ static int serial_base_add_one_prefcon(const char *match, const char *dev_name, return ret; } +#endif + #ifdef __sparc__ /* Handle Sparc ttya and ttyb options as done in console_setup() */ @@ -329,15 +331,6 @@ int serial_base_add_isa_preferred_console(const char *name, int idx) return serial_base_add_prefcon(name, idx); } -#else - -int serial_base_add_isa_preferred_console(const char *name, int idx) -{ - return 0; -} - -#endif - #endif static int serial_base_init(void) -- cgit v1.2.3-59-g8ed1b From 46f2bba8314fdd818cc7408126919cb6421b4e19 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 11 Apr 2024 09:55:37 +0100 Subject: serial: omap: remove redundant assignment to variable tmout Variable tmout is being assigned a value that is never read, it is being re-assinged in the following for-loop statement. The assignment is redundant and can be removed. Cleans up clang scan warning: drivers/tty/serial/omap-serial.c:1096:3: warning: Value stored to 'tmout' is never read [deadcode.DeadStores] Signed-off-by: Colin Ian King Link: https://lore.kernel.org/r/20240411085537.306020-1-colin.i.king@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/omap-serial.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index 9be1c871cf11..d7e172eeaab1 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -1093,7 +1093,6 @@ static void __maybe_unused wait_for_xmitr(struct uart_omap_port *up) /* Wait up to 1s for flow control if necessary */ if (up->port.flags & UPF_CONS_FLOW) { - tmout = 1000000; for (tmout = 1000000; tmout; tmout--) { unsigned int msr = serial_in(up, UART_MSR); -- cgit v1.2.3-59-g8ed1b From 25ca2d573ebae939d19f5df5fef2c58ef83ed97a Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 10 Apr 2024 17:11:35 +0300 Subject: serial: max3100: Convert to_max3100_port() to be static inline MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As Jiri rightfully pointed out the current to_max3100_port() macro implementation is fragile in a sense that it expects the variable name to be port, otherwise it blow up the build. Change this to be static inline to prevent bad compilation. Suggested-by: Jiri Slaby Signed-off-by: Andy Shevchenko Reviewed-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20240410141135.1378948-1-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/max3100.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/tty/serial/max3100.c b/drivers/tty/serial/max3100.c index ce24588150bf..fda63918d1eb 100644 --- a/drivers/tty/serial/max3100.c +++ b/drivers/tty/serial/max3100.c @@ -111,7 +111,10 @@ struct max3100_port { struct timer_list timer; }; -#define to_max3100_port(port) container_of(port, struct max3100_port, port) +static inline struct max3100_port *to_max3100_port(struct uart_port *port) +{ + return container_of(port, struct max3100_port, port); +} static struct max3100_port *max3100s[MAX_MAX3100]; /* the chips */ static DEFINE_MUTEX(max3100s_lock); /* race on probe */ -- cgit v1.2.3-59-g8ed1b From 693f75b91a9171e99f84fc193e39f48e21ba4a4f Mon Sep 17 00:00:00 2001 From: Sreenath Vijayan Date: Wed, 13 Mar 2024 15:50:52 +0530 Subject: printk: Add function to replay kernel log on consoles Add a generic function console_replay_all() for replaying the kernel log on consoles, in any context. It would allow viewing the logs on an unresponsive terminal via sysrq. Reuse the existing code from console_flush_on_panic() for resetting the sequence numbers, by introducing a new helper function __console_rewind_all(). It is safe to be called under console_lock(). Try to acquire lock on the console subsystem without waiting. If successful, reset the sequence number to oldest available record on all consoles and call console_unlock() which will automatically flush the messages to the consoles. Suggested-by: John Ogness Suggested-by: Petr Mladek Signed-off-by: Shimoyashiki Taichi Reviewed-by: John Ogness Signed-off-by: Sreenath Vijayan Link: https://lore.kernel.org/r/90ee131c643a5033d117b556c0792de65129d4c3.1710220326.git.sreenath.vijayan@sony.com Signed-off-by: Greg Kroah-Hartman --- include/linux/printk.h | 4 +++ kernel/printk/printk.c | 77 ++++++++++++++++++++++++++++++++++---------------- 2 files changed, 57 insertions(+), 24 deletions(-) diff --git a/include/linux/printk.h b/include/linux/printk.h index 5e038e782256..1c5936ab991f 100644 --- a/include/linux/printk.h +++ b/include/linux/printk.h @@ -195,6 +195,7 @@ void show_regs_print_info(const char *log_lvl); extern asmlinkage void dump_stack_lvl(const char *log_lvl) __cold; extern asmlinkage void dump_stack(void) __cold; void printk_trigger_flush(void); +void console_replay_all(void); #else static inline __printf(1, 0) int vprintk(const char *s, va_list args) @@ -274,6 +275,9 @@ static inline void dump_stack(void) static inline void printk_trigger_flush(void) { } +static inline void console_replay_all(void) +{ +} #endif bool this_cpu_in_panic(void); diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index 1e3b21682547..6206804d275b 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -3161,6 +3161,40 @@ void console_unblank(void) pr_flush(1000, true); } +/* + * Rewind all consoles to the oldest available record. + * + * IMPORTANT: The function is safe only when called under + * console_lock(). It is not enforced because + * it is used as a best effort in panic(). + */ +static void __console_rewind_all(void) +{ + struct console *c; + short flags; + int cookie; + u64 seq; + + seq = prb_first_valid_seq(prb); + + cookie = console_srcu_read_lock(); + for_each_console_srcu(c) { + flags = console_srcu_read_flags(c); + + if (flags & CON_NBCON) { + nbcon_seq_force(c, seq); + } else { + /* + * This assignment is safe only when called under + * console_lock(). On panic, legacy consoles are + * only best effort. + */ + c->seq = seq; + } + } + console_srcu_read_unlock(cookie); +} + /** * console_flush_on_panic - flush console content on panic * @mode: flush all messages in buffer or just the pending ones @@ -3189,30 +3223,8 @@ void console_flush_on_panic(enum con_flush_mode mode) */ console_may_schedule = 0; - if (mode == CONSOLE_REPLAY_ALL) { - struct console *c; - short flags; - int cookie; - u64 seq; - - seq = prb_first_valid_seq(prb); - - cookie = console_srcu_read_lock(); - for_each_console_srcu(c) { - flags = console_srcu_read_flags(c); - - if (flags & CON_NBCON) { - nbcon_seq_force(c, seq); - } else { - /* - * This is an unsynchronized assignment. On - * panic legacy consoles are only best effort. - */ - c->seq = seq; - } - } - console_srcu_read_unlock(cookie); - } + if (mode == CONSOLE_REPLAY_ALL) + __console_rewind_all(); console_flush_all(false, &next_seq, &handover); } @@ -4301,6 +4313,23 @@ void kmsg_dump_rewind(struct kmsg_dump_iter *iter) } EXPORT_SYMBOL_GPL(kmsg_dump_rewind); +/** + * console_replay_all - replay kernel log on consoles + * + * Try to obtain lock on console subsystem and replay all + * available records in printk buffer on the consoles. + * Does nothing if lock is not obtained. + * + * Context: Any context. + */ +void console_replay_all(void) +{ + if (console_trylock()) { + __console_rewind_all(); + /* Consoles are flushed as part of console_unlock(). */ + console_unlock(); + } +} #endif #ifdef CONFIG_SMP -- cgit v1.2.3-59-g8ed1b From 1b743485e27f3d874695434cc8103f557dfdf4b9 Mon Sep 17 00:00:00 2001 From: Sreenath Vijayan Date: Wed, 13 Mar 2024 15:52:52 +0530 Subject: tty/sysrq: Replay kernel log messages on consoles via sysrq When terminal is unresponsive, one cannot use dmesg to view the printk ring buffer messages. Also, syslog services may be disabled, especially on embedded systems, to check the messages after a reboot. In this scenario, replay the messages in printk ring buffer on consoles via sysrq by pressing sysrq+R. The console loglevel will determine which all kernel log messages are displayed. The messages will be displayed only when console_trylock() succeeds. Users could repeat the sysrq key when it fails. If the owner of console subsystem lock is stuck, repeating the key won't work. Suggested-by: Petr Mladek Signed-off-by: Shimoyashiki Taichi Reviewed-by: John Ogness Signed-off-by: Sreenath Vijayan Link: https://lore.kernel.org/r/cc3b9b1aae60a236c6aed1dc7b0ffa2c7cd1f183.1710220326.git.sreenath.vijayan@sony.com Signed-off-by: Greg Kroah-Hartman --- Documentation/admin-guide/sysrq.rst | 9 +++++++++ drivers/tty/sysrq.c | 13 ++++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/Documentation/admin-guide/sysrq.rst b/Documentation/admin-guide/sysrq.rst index 2f2e5bd440f9..a85b3384d1e7 100644 --- a/Documentation/admin-guide/sysrq.rst +++ b/Documentation/admin-guide/sysrq.rst @@ -161,6 +161,8 @@ Command Function will be printed to your console. (``0``, for example would make it so that only emergency messages like PANICs or OOPSes would make it to your console.) + +``R`` Replay the kernel log messages on consoles. =========== =================================================================== Okay, so what can I use them for? @@ -211,6 +213,13 @@ processes. "just thaw ``it(j)``" is useful if your system becomes unresponsive due to a frozen (probably root) filesystem via the FIFREEZE ioctl. +``Replay logs(R)`` is useful to view the kernel log messages when system is hung +or you are not able to use dmesg command to view the messages in printk buffer. +User may have to press the key combination multiple times if console system is +busy. If it is completely locked up, then messages won't be printed. Output +messages depend on current console loglevel, which can be modified using +sysrq[0-9] (see above). + Sometimes SysRq seems to get 'stuck' after using it, what can I do? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c index 02217e3c916b..e5974b8239c9 100644 --- a/drivers/tty/sysrq.c +++ b/drivers/tty/sysrq.c @@ -450,6 +450,17 @@ static const struct sysrq_key_op sysrq_unrt_op = { .enable_mask = SYSRQ_ENABLE_RTNICE, }; +static void sysrq_handle_replay_logs(u8 key) +{ + console_replay_all(); +} +static struct sysrq_key_op sysrq_replay_logs_op = { + .handler = sysrq_handle_replay_logs, + .help_msg = "replay-kernel-logs(R)", + .action_msg = "Replay kernel logs on consoles", + .enable_mask = SYSRQ_ENABLE_DUMP, +}; + /* Key Operations table and lock */ static DEFINE_SPINLOCK(sysrq_key_table_lock); @@ -519,7 +530,7 @@ static const struct sysrq_key_op *sysrq_key_table[62] = { NULL, /* O */ NULL, /* P */ NULL, /* Q */ - NULL, /* R */ + &sysrq_replay_logs_op, /* R */ NULL, /* S */ NULL, /* T */ NULL, /* U */ -- cgit v1.2.3-59-g8ed1b From 3d122e6d27e417a9fa91181922743df26b2cd679 Mon Sep 17 00:00:00 2001 From: Francesco Dolcini Date: Tue, 9 Apr 2024 21:09:10 +0200 Subject: usb: typec: mux: gpio-sbu: Allow GPIO operations to sleep Use gpiod_set_value_cansleep() to support gpiochips which can sleep like, e.g. I2C GPIO expanders. Signed-off-by: Francesco Dolcini Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20240409190910.4707-1-francesco@dolcini.it Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/mux/gpio-sbu-mux.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/usb/typec/mux/gpio-sbu-mux.c b/drivers/usb/typec/mux/gpio-sbu-mux.c index ad60fd4e8431..374168482d36 100644 --- a/drivers/usb/typec/mux/gpio-sbu-mux.c +++ b/drivers/usb/typec/mux/gpio-sbu-mux.c @@ -48,10 +48,10 @@ static int gpio_sbu_switch_set(struct typec_switch_dev *sw, } if (enabled != sbu_mux->enabled) - gpiod_set_value(sbu_mux->enable_gpio, enabled); + gpiod_set_value_cansleep(sbu_mux->enable_gpio, enabled); if (swapped != sbu_mux->swapped) - gpiod_set_value(sbu_mux->select_gpio, swapped); + gpiod_set_value_cansleep(sbu_mux->select_gpio, swapped); sbu_mux->enabled = enabled; sbu_mux->swapped = swapped; @@ -82,7 +82,7 @@ static int gpio_sbu_mux_set(struct typec_mux_dev *mux, break; } - gpiod_set_value(sbu_mux->enable_gpio, sbu_mux->enabled); + gpiod_set_value_cansleep(sbu_mux->enable_gpio, sbu_mux->enabled); mutex_unlock(&sbu_mux->lock); @@ -141,7 +141,7 @@ static void gpio_sbu_mux_remove(struct platform_device *pdev) { struct gpio_sbu_mux *sbu_mux = platform_get_drvdata(pdev); - gpiod_set_value(sbu_mux->enable_gpio, 0); + gpiod_set_value_cansleep(sbu_mux->enable_gpio, 0); typec_mux_unregister(sbu_mux->mux); typec_switch_unregister(sbu_mux->sw); -- cgit v1.2.3-59-g8ed1b From 4bc4634eda10b5a9e703d4b52c0941ea7fbf0fa9 Mon Sep 17 00:00:00 2001 From: Samuel Thibault Date: Wed, 27 Mar 2024 12:50:51 +0100 Subject: speakup: Turn i18n files utf-8 i18n currently assume latin1 encoding, which is not enough for most languages. This separates out the utf-8 processing of /dev/synthu, and uses it for a new synth_writeu, which we make synth_printf now use. This has the effect of making all the i18 messages processed in utf-8. Signed-off-by: Samuel Thibault Link: https://lore.kernel.org/r/20240327115051.ng7xqnhozyii4ik2@begin Signed-off-by: Greg Kroah-Hartman --- drivers/accessibility/speakup/devsynth.c | 59 +++++--------------- drivers/accessibility/speakup/speakup.h | 2 + drivers/accessibility/speakup/synth.c | 92 ++++++++++++++++++++++++++++++-- 3 files changed, 102 insertions(+), 51 deletions(-) diff --git a/drivers/accessibility/speakup/devsynth.c b/drivers/accessibility/speakup/devsynth.c index cb7e1114e8eb..e3d909bd0480 100644 --- a/drivers/accessibility/speakup/devsynth.c +++ b/drivers/accessibility/speakup/devsynth.c @@ -39,13 +39,13 @@ static ssize_t speakup_file_write(struct file *fp, const char __user *buffer, static ssize_t speakup_file_writeu(struct file *fp, const char __user *buffer, size_t nbytes, loff_t *ppos) { - size_t count = nbytes, want; + size_t count = nbytes, consumed, want; const char __user *ptr = buffer; size_t bytes; unsigned long flags; unsigned char buf[256]; u16 ubuf[256]; - size_t in, in2, out; + size_t in, out; if (!synth) return -ENODEV; @@ -58,57 +58,24 @@ static ssize_t speakup_file_writeu(struct file *fp, const char __user *buffer, return -EFAULT; /* Convert to u16 */ - for (in = 0, out = 0; in < bytes; in++) { - unsigned char c = buf[in]; - int nbytes = 8 - fls(c ^ 0xff); - u32 value; - - switch (nbytes) { - case 8: /* 0xff */ - case 7: /* 0xfe */ - case 1: /* 0x80 */ - /* Invalid, drop */ - goto drop; - - case 0: - /* ASCII, copy */ - ubuf[out++] = c; - continue; + for (in = 0, out = 0; in < bytes; in += consumed) { + s32 value; - default: - /* 2..6-byte UTF-8 */ + value = synth_utf8_get(buf + in, bytes - in, &consumed, &want); + if (value == -1) { + /* Invalid or incomplete */ - if (bytes - in < nbytes) { + if (want > bytes - in) /* We don't have it all yet, stop here * and wait for the rest */ bytes = in; - want = nbytes; - continue; - } - - /* First byte */ - value = c & ((1u << (7 - nbytes)) - 1); - - /* Other bytes */ - for (in2 = 2; in2 <= nbytes; in2++) { - c = buf[in + 1]; - if ((c & 0xc0) != 0x80) { - /* Invalid, drop the head */ - want = 1; - goto drop; - } - value = (value << 6) | (c & 0x3f); - in++; - } - - if (value < 0x10000) - ubuf[out++] = value; - want = 1; - break; + + continue; } -drop: - /* empty statement */; + + if (value < 0x10000) + ubuf[out++] = value; } count -= bytes; diff --git a/drivers/accessibility/speakup/speakup.h b/drivers/accessibility/speakup/speakup.h index 364fde99749e..54f1226ea061 100644 --- a/drivers/accessibility/speakup/speakup.h +++ b/drivers/accessibility/speakup/speakup.h @@ -76,7 +76,9 @@ int speakup_paste_selection(struct tty_struct *tty); void speakup_cancel_paste(void); void speakup_register_devsynth(void); void speakup_unregister_devsynth(void); +s32 synth_utf8_get(const char *buf, size_t count, size_t *consumed, size_t *want); void synth_write(const char *buf, size_t count); +void synth_writeu(const char *buf, size_t count); int synth_supports_indexing(void); extern struct vc_data *spk_sel_cons; diff --git a/drivers/accessibility/speakup/synth.c b/drivers/accessibility/speakup/synth.c index 45f906103133..85062e605d79 100644 --- a/drivers/accessibility/speakup/synth.c +++ b/drivers/accessibility/speakup/synth.c @@ -217,10 +217,95 @@ void synth_write(const char *_buf, size_t count) synth_start(); } +/* Consume one utf-8 character from buf (that contains up to count bytes), + * returns the unicode codepoint if valid, -1 otherwise. + * In all cases, returns the number of consumed bytes in *consumed, + * and the minimum number of bytes that would be needed for the next character + * in *want. + */ +s32 synth_utf8_get(const char *buf, size_t count, size_t *consumed, size_t *want) +{ + unsigned char c = buf[0]; + int nbytes = 8 - fls(c ^ 0xff); + u32 value; + size_t i; + + switch (nbytes) { + case 8: /* 0xff */ + case 7: /* 0xfe */ + case 1: /* 0x80 */ + /* Invalid, drop */ + *consumed = 1; + *want = 1; + return -1; + + case 0: + /* ASCII, take as such */ + *consumed = 1; + *want = 1; + return c; + + default: + /* 2..6-byte UTF-8 */ + + if (count < nbytes) { + /* We don't have it all */ + *consumed = 0; + *want = nbytes; + return -1; + } + + /* First byte */ + value = c & ((1u << (7 - nbytes)) - 1); + + /* Other bytes */ + for (i = 1; i < nbytes; i++) { + c = buf[i]; + if ((c & 0xc0) != 0x80) { + /* Invalid, drop the head */ + *consumed = i; + *want = 1; + return -1; + } + value = (value << 6) | (c & 0x3f); + } + + *consumed = nbytes; + *want = 1; + return value; + } +} + +void synth_writeu(const char *buf, size_t count) +{ + size_t i, consumed, want; + + /* Convert to u16 */ + for (i = 0; i < count; i++) { + s32 value; + + value = synth_utf8_get(buf + i, count - i, &consumed, &want); + if (value == -1) { + /* Invalid or incomplete */ + + if (want > count - i) + /* We don't have it all, stop */ + count = i; + + continue; + } + + if (value < 0x10000) + synth_buffer_add(value); + } + + synth_start(); +} + void synth_printf(const char *fmt, ...) { va_list args; - unsigned char buf[160], *p; + unsigned char buf[160]; int r; va_start(args, fmt); @@ -229,10 +314,7 @@ void synth_printf(const char *fmt, ...) if (r > sizeof(buf) - 1) r = sizeof(buf) - 1; - p = buf; - while (r--) - synth_buffer_add(*p++); - synth_start(); + synth_writeu(buf, r); } EXPORT_SYMBOL_GPL(synth_printf); -- cgit v1.2.3-59-g8ed1b From b2c6a73fb4130f3c5e2a8ba4b1c98c5a9db03b65 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Fri, 8 Mar 2024 22:31:01 +0100 Subject: uio: fsl_elbc_gpcm: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/ca99d4e71054e8452f3cee6c016bf4f89bfc7eaa.1709933231.git.u.kleine-koenig@pengutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/uio/uio_fsl_elbc_gpcm.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/uio/uio_fsl_elbc_gpcm.c b/drivers/uio/uio_fsl_elbc_gpcm.c index 82dda799f327..496caff66e7e 100644 --- a/drivers/uio/uio_fsl_elbc_gpcm.c +++ b/drivers/uio/uio_fsl_elbc_gpcm.c @@ -427,7 +427,7 @@ out_err2: return ret; } -static int uio_fsl_elbc_gpcm_remove(struct platform_device *pdev) +static void uio_fsl_elbc_gpcm_remove(struct platform_device *pdev) { struct uio_info *info = platform_get_drvdata(pdev); struct fsl_elbc_gpcm *priv = info->priv; @@ -438,8 +438,6 @@ static int uio_fsl_elbc_gpcm_remove(struct platform_device *pdev) priv->shutdown(info, false); iounmap(info->mem[0].internal_addr); - return 0; - } static const struct of_device_id uio_fsl_elbc_gpcm_match[] = { @@ -455,7 +453,7 @@ static struct platform_driver uio_fsl_elbc_gpcm_driver = { .dev_groups = uio_fsl_elbc_gpcm_groups, }, .probe = uio_fsl_elbc_gpcm_probe, - .remove = uio_fsl_elbc_gpcm_remove, + .remove_new = uio_fsl_elbc_gpcm_remove, }; module_platform_driver(uio_fsl_elbc_gpcm_driver); -- cgit v1.2.3-59-g8ed1b From 1019fa4839c97c4efff9c26af4d74a184921d8da Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Wed, 10 Apr 2024 09:48:03 -0500 Subject: uio: pruss: Remove this driver This UIO driver was used to control the PRU processors found on various TI SoCs. It was created before the Remoteproc framework, but now with that we have a standard way to program and manage the PRU processors. The proper PRU Remoteproc driver should be used instead of this driver. This driver only supported the original class of PRUSS (OMAP-L1xx / AM17xx / AM18xx / TMS320C674x / DA8xx) but when these platforms were switched to use Device Tree the support for DT was not added to this driver and so it is now unused/unusable. Support for these platforms can be added to the proper PRU Remoteproc driver if ever needed. Remove this driver. Signed-off-by: Andrew Davis Link: https://lore.kernel.org/r/20240410144803.126831-1-afd@ti.com Signed-off-by: Greg Kroah-Hartman --- drivers/uio/Kconfig | 18 --- drivers/uio/Makefile | 1 - drivers/uio/uio_pruss.c | 255 -------------------------------- include/linux/platform_data/uio_pruss.h | 18 --- 4 files changed, 292 deletions(-) delete mode 100644 drivers/uio/uio_pruss.c delete mode 100644 include/linux/platform_data/uio_pruss.h diff --git a/drivers/uio/Kconfig b/drivers/uio/Kconfig index 2e16c5338e5b..b060dcd7c635 100644 --- a/drivers/uio/Kconfig +++ b/drivers/uio/Kconfig @@ -125,24 +125,6 @@ config UIO_FSL_ELBC_GPCM_NETX5152 Information about this hardware can be found at: http://www.hilscher.com/netx -config UIO_PRUSS - tristate "Texas Instruments PRUSS driver" - select GENERIC_ALLOCATOR - depends on HAS_IOMEM && HAS_DMA - help - PRUSS driver for OMAPL138/DA850/AM18XX devices - PRUSS driver requires user space components, examples and user space - driver is available from below SVN repo - you may use anonymous login - - https://gforge.ti.com/gf/project/pru_sw/ - - More info on API is available at below wiki - - http://processors.wiki.ti.com/index.php/PRU_Linux_Application_Loader - - To compile this driver as a module, choose M here: the module - will be called uio_pruss. - config UIO_MF624 tristate "Humusoft MF624 DAQ PCI card driver" depends on PCI diff --git a/drivers/uio/Makefile b/drivers/uio/Makefile index f2f416a14228..1c5f3b5a95cf 100644 --- a/drivers/uio/Makefile +++ b/drivers/uio/Makefile @@ -7,7 +7,6 @@ obj-$(CONFIG_UIO_AEC) += uio_aec.o obj-$(CONFIG_UIO_SERCOS3) += uio_sercos3.o obj-$(CONFIG_UIO_PCI_GENERIC) += uio_pci_generic.o obj-$(CONFIG_UIO_NETX) += uio_netx.o -obj-$(CONFIG_UIO_PRUSS) += uio_pruss.o obj-$(CONFIG_UIO_MF624) += uio_mf624.o obj-$(CONFIG_UIO_FSL_ELBC_GPCM) += uio_fsl_elbc_gpcm.o obj-$(CONFIG_UIO_HV_GENERIC) += uio_hv_generic.o diff --git a/drivers/uio/uio_pruss.c b/drivers/uio/uio_pruss.c deleted file mode 100644 index f67881cba645..000000000000 --- a/drivers/uio/uio_pruss.c +++ /dev/null @@ -1,255 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Programmable Real-Time Unit Sub System (PRUSS) UIO driver (uio_pruss) - * - * This driver exports PRUSS host event out interrupts and PRUSS, L3 RAM, - * and DDR RAM to user space for applications interacting with PRUSS firmware - * - * Copyright (C) 2010-11 Texas Instruments Incorporated - http://www.ti.com/ - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define DRV_NAME "pruss_uio" -#define DRV_VERSION "1.0" - -static int sram_pool_sz = SZ_16K; -module_param(sram_pool_sz, int, 0); -MODULE_PARM_DESC(sram_pool_sz, "sram pool size to allocate "); - -static int extram_pool_sz = SZ_256K; -module_param(extram_pool_sz, int, 0); -MODULE_PARM_DESC(extram_pool_sz, "external ram pool size to allocate"); - -/* - * Host event IRQ numbers from PRUSS - PRUSS can generate up to 8 interrupt - * events to AINTC of ARM host processor - which can be used for IPC b/w PRUSS - * firmware and user space application, async notification from PRU firmware - * to user space application - * 3 PRU_EVTOUT0 - * 4 PRU_EVTOUT1 - * 5 PRU_EVTOUT2 - * 6 PRU_EVTOUT3 - * 7 PRU_EVTOUT4 - * 8 PRU_EVTOUT5 - * 9 PRU_EVTOUT6 - * 10 PRU_EVTOUT7 -*/ -#define MAX_PRUSS_EVT 8 - -#define PINTC_HIDISR 0x0038 -#define PINTC_HIPIR 0x0900 -#define HIPIR_NOPEND 0x80000000 -#define PINTC_HIER 0x1500 - -struct uio_pruss_dev { - struct uio_info *info; - struct clk *pruss_clk; - dma_addr_t sram_paddr; - dma_addr_t ddr_paddr; - void __iomem *prussio_vaddr; - unsigned long sram_vaddr; - void *ddr_vaddr; - unsigned int hostirq_start; - unsigned int pintc_base; - struct gen_pool *sram_pool; -}; - -static irqreturn_t pruss_handler(int irq, struct uio_info *info) -{ - struct uio_pruss_dev *gdev = info->priv; - int intr_bit = (irq - gdev->hostirq_start + 2); - int val, intr_mask = (1 << intr_bit); - void __iomem *base = gdev->prussio_vaddr + gdev->pintc_base; - void __iomem *intren_reg = base + PINTC_HIER; - void __iomem *intrdis_reg = base + PINTC_HIDISR; - void __iomem *intrstat_reg = base + PINTC_HIPIR + (intr_bit << 2); - - val = ioread32(intren_reg); - /* Is interrupt enabled and active ? */ - if (!(val & intr_mask) && (ioread32(intrstat_reg) & HIPIR_NOPEND)) - return IRQ_NONE; - /* Disable interrupt */ - iowrite32(intr_bit, intrdis_reg); - return IRQ_HANDLED; -} - -static void pruss_cleanup(struct device *dev, struct uio_pruss_dev *gdev) -{ - int cnt; - struct uio_info *p = gdev->info; - - for (cnt = 0; cnt < MAX_PRUSS_EVT; cnt++, p++) { - uio_unregister_device(p); - } - iounmap(gdev->prussio_vaddr); - if (gdev->ddr_vaddr) { - dma_free_coherent(dev, extram_pool_sz, gdev->ddr_vaddr, - gdev->ddr_paddr); - } - if (gdev->sram_vaddr) - gen_pool_free(gdev->sram_pool, - gdev->sram_vaddr, - sram_pool_sz); - clk_disable(gdev->pruss_clk); -} - -static int pruss_probe(struct platform_device *pdev) -{ - struct uio_info *p; - struct uio_pruss_dev *gdev; - struct resource *regs_prussio; - struct device *dev = &pdev->dev; - int ret, cnt, i, len; - struct uio_pruss_pdata *pdata = dev_get_platdata(dev); - - gdev = devm_kzalloc(dev, sizeof(struct uio_pruss_dev), GFP_KERNEL); - if (!gdev) - return -ENOMEM; - - gdev->info = devm_kcalloc(dev, MAX_PRUSS_EVT, sizeof(*p), GFP_KERNEL); - if (!gdev->info) - return -ENOMEM; - - /* Power on PRU in case its not done as part of boot-loader */ - gdev->pruss_clk = devm_clk_get(dev, "pruss"); - if (IS_ERR(gdev->pruss_clk)) { - dev_err(dev, "Failed to get clock\n"); - return PTR_ERR(gdev->pruss_clk); - } - - ret = clk_enable(gdev->pruss_clk); - if (ret) { - dev_err(dev, "Failed to enable clock\n"); - return ret; - } - - regs_prussio = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!regs_prussio) { - dev_err(dev, "No PRUSS I/O resource specified\n"); - ret = -EIO; - goto err_clk_disable; - } - - if (!regs_prussio->start) { - dev_err(dev, "Invalid memory resource\n"); - ret = -EIO; - goto err_clk_disable; - } - - if (pdata->sram_pool) { - gdev->sram_pool = pdata->sram_pool; - gdev->sram_vaddr = - (unsigned long)gen_pool_dma_alloc(gdev->sram_pool, - sram_pool_sz, &gdev->sram_paddr); - if (!gdev->sram_vaddr) { - dev_err(dev, "Could not allocate SRAM pool\n"); - ret = -ENOMEM; - goto err_clk_disable; - } - } - - gdev->ddr_vaddr = dma_alloc_coherent(dev, extram_pool_sz, - &(gdev->ddr_paddr), GFP_KERNEL | GFP_DMA); - if (!gdev->ddr_vaddr) { - dev_err(dev, "Could not allocate external memory\n"); - ret = -ENOMEM; - goto err_free_sram; - } - - len = resource_size(regs_prussio); - gdev->prussio_vaddr = ioremap(regs_prussio->start, len); - if (!gdev->prussio_vaddr) { - dev_err(dev, "Can't remap PRUSS I/O address range\n"); - ret = -ENOMEM; - goto err_free_ddr_vaddr; - } - - ret = platform_get_irq(pdev, 0); - if (ret < 0) - goto err_unmap; - - gdev->hostirq_start = ret; - gdev->pintc_base = pdata->pintc_base; - - for (cnt = 0, p = gdev->info; cnt < MAX_PRUSS_EVT; cnt++, p++) { - p->mem[0].addr = regs_prussio->start; - p->mem[0].size = resource_size(regs_prussio); - p->mem[0].memtype = UIO_MEM_PHYS; - - p->mem[1].addr = gdev->sram_paddr; - p->mem[1].size = sram_pool_sz; - p->mem[1].memtype = UIO_MEM_PHYS; - - p->mem[2].addr = (uintptr_t) gdev->ddr_vaddr; - p->mem[2].dma_addr = gdev->ddr_paddr; - p->mem[2].size = extram_pool_sz; - p->mem[2].memtype = UIO_MEM_DMA_COHERENT; - p->mem[2].dma_device = dev; - - p->name = devm_kasprintf(dev, GFP_KERNEL, "pruss_evt%d", cnt); - p->version = DRV_VERSION; - - /* Register PRUSS IRQ lines */ - p->irq = gdev->hostirq_start + cnt; - p->handler = pruss_handler; - p->priv = gdev; - - ret = uio_register_device(dev, p); - if (ret < 0) - goto err_unloop; - } - - platform_set_drvdata(pdev, gdev); - return 0; - -err_unloop: - for (i = 0, p = gdev->info; i < cnt; i++, p++) { - uio_unregister_device(p); - } -err_unmap: - iounmap(gdev->prussio_vaddr); -err_free_ddr_vaddr: - dma_free_coherent(dev, extram_pool_sz, gdev->ddr_vaddr, - gdev->ddr_paddr); -err_free_sram: - if (pdata->sram_pool) - gen_pool_free(gdev->sram_pool, gdev->sram_vaddr, sram_pool_sz); -err_clk_disable: - clk_disable(gdev->pruss_clk); - - return ret; -} - -static int pruss_remove(struct platform_device *dev) -{ - struct uio_pruss_dev *gdev = platform_get_drvdata(dev); - - pruss_cleanup(&dev->dev, gdev); - return 0; -} - -static struct platform_driver pruss_driver = { - .probe = pruss_probe, - .remove = pruss_remove, - .driver = { - .name = DRV_NAME, - }, -}; - -module_platform_driver(pruss_driver); - -MODULE_LICENSE("GPL v2"); -MODULE_VERSION(DRV_VERSION); -MODULE_AUTHOR("Amit Chatterjee "); -MODULE_AUTHOR("Pratheesh Gangadhar "); diff --git a/include/linux/platform_data/uio_pruss.h b/include/linux/platform_data/uio_pruss.h deleted file mode 100644 index f76fa393b802..000000000000 --- a/include/linux/platform_data/uio_pruss.h +++ /dev/null @@ -1,18 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * include/linux/platform_data/uio_pruss.h - * - * Platform data for uio_pruss driver - * - * Copyright (C) 2010-11 Texas Instruments Incorporated - https://www.ti.com/ - */ - -#ifndef _UIO_PRUSS_H_ -#define _UIO_PRUSS_H_ - -/* To configure the PRUSS INTC base offset for UIO driver */ -struct uio_pruss_pdata { - u32 pintc_base; - struct gen_pool *sram_pool; -}; -#endif /* _UIO_PRUSS_H_ */ -- cgit v1.2.3-59-g8ed1b From 90fa0280553a87d0db51dd04f1aea1c2dde53c74 Mon Sep 17 00:00:00 2001 From: Chris Packham Date: Tue, 9 Apr 2024 11:40:48 +1200 Subject: uio_pdrv_genirq: convert to use device_property APIs Convert the uio_pdrv_genirq driver to use the device_property_* APIs instead of the of_property_* ones. This allows UIO interrupts to be defined via an ACPI overlay using the Device Tree namespace linkage. Signed-off-by: Chris Packham Link: https://lore.kernel.org/r/20240408234050.2056374-2-chris.packham@alliedtelesis.co.nz Signed-off-by: Greg Kroah-Hartman --- drivers/uio/uio_pdrv_genirq.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/uio/uio_pdrv_genirq.c b/drivers/uio/uio_pdrv_genirq.c index 63258b6accc4..796f5be0a086 100644 --- a/drivers/uio/uio_pdrv_genirq.c +++ b/drivers/uio/uio_pdrv_genirq.c @@ -23,8 +23,8 @@ #include #include -#include -#include +#include +#include #define DRIVER_NAME "uio_pdrv_genirq" @@ -110,7 +110,7 @@ static void uio_pdrv_genirq_cleanup(void *data) static int uio_pdrv_genirq_probe(struct platform_device *pdev) { struct uio_info *uioinfo = dev_get_platdata(&pdev->dev); - struct device_node *node = pdev->dev.of_node; + struct fwnode_handle *node = dev_fwnode(&pdev->dev); struct uio_pdrv_genirq_platdata *priv; struct uio_mem *uiomem; int ret = -EINVAL; @@ -127,11 +127,11 @@ static int uio_pdrv_genirq_probe(struct platform_device *pdev) return -ENOMEM; } - if (!of_property_read_string(node, "linux,uio-name", &name)) + if (!device_property_read_string(&pdev->dev, "linux,uio-name", &name)) uioinfo->name = devm_kstrdup(&pdev->dev, name, GFP_KERNEL); else uioinfo->name = devm_kasprintf(&pdev->dev, GFP_KERNEL, - "%pOFn", node); + "%pfwP", node); uioinfo->version = "devicetree"; /* Multiple IRQs are not supported */ -- cgit v1.2.3-59-g8ed1b From f8a27dfa4b82d442af1c0645a5acc70cc97c67f6 Mon Sep 17 00:00:00 2001 From: Chris Packham Date: Tue, 9 Apr 2024 11:40:49 +1200 Subject: uio: use threaded interrupts Split the existing uio_interrupt into a hardirq handler and a thread function. The hardirq handler deals with the interrupt source in hardware, the thread function notifies userspace that there is an event to be handled. Signed-off-by: Chris Packham Link: https://lore.kernel.org/r/20240408234050.2056374-3-chris.packham@alliedtelesis.co.nz Signed-off-by: Greg Kroah-Hartman --- drivers/uio/uio.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c index 009158fef2a8..e815856eb46c 100644 --- a/drivers/uio/uio.c +++ b/drivers/uio/uio.c @@ -442,18 +442,27 @@ EXPORT_SYMBOL_GPL(uio_event_notify); * @irq: IRQ number, can be UIO_IRQ_CYCLIC for cyclic timer * @dev_id: Pointer to the devices uio_device structure */ -static irqreturn_t uio_interrupt(int irq, void *dev_id) +static irqreturn_t uio_interrupt_handler(int irq, void *dev_id) { struct uio_device *idev = (struct uio_device *)dev_id; irqreturn_t ret; ret = idev->info->handler(irq, idev->info); if (ret == IRQ_HANDLED) - uio_event_notify(idev->info); + ret = IRQ_WAKE_THREAD; return ret; } +static irqreturn_t uio_interrupt_thread(int irq, void *dev_id) +{ + struct uio_device *idev = (struct uio_device *)dev_id; + + uio_event_notify(idev->info); + + return IRQ_HANDLED; +} + struct uio_listener { struct uio_device *dev; s32 event_count; @@ -1024,8 +1033,8 @@ int __uio_register_device(struct module *owner, * FDs at the time of unregister and therefore may not be * freed until they are released. */ - ret = request_irq(info->irq, uio_interrupt, - info->irq_flags, info->name, idev); + ret = request_threaded_irq(info->irq, uio_interrupt_handler, uio_interrupt_thread, + info->irq_flags, info->name, idev); if (ret) { info->uio_dev = NULL; goto err_request_irq; -- cgit v1.2.3-59-g8ed1b From 85d2b0aa170351380be39fe4ff7973df1427fe76 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 8 Apr 2024 10:05:58 +0200 Subject: module: don't ignore sysfs_create_link() failures The sysfs_create_link() return code is marked as __must_check, but the module_add_driver() function tries hard to not care, by assigning the return code to a variable. When building with 'make W=1', gcc still warns because this variable is only assigned but not used: drivers/base/module.c: In function 'module_add_driver': drivers/base/module.c:36:6: warning: variable 'no_warn' set but not used [-Wunused-but-set-variable] Rework the code to properly unwind and return the error code to the caller. My reading of the original code was that it tries to not fail when the links already exist, so keep ignoring -EEXIST errors. Fixes: e17e0f51aeea ("Driver core: show drivers in /sys/module/") See-also: 4a7fb6363f2d ("add __must_check to device management code") Signed-off-by: Arnd Bergmann Reviewed-by: Luis Chamberlain Link: https://lore.kernel.org/r/20240408080616.3911573-1-arnd@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/base/base.h | 9 ++++++--- drivers/base/bus.c | 9 ++++++++- drivers/base/module.c | 42 +++++++++++++++++++++++++++++++----------- 3 files changed, 45 insertions(+), 15 deletions(-) diff --git a/drivers/base/base.h b/drivers/base/base.h index 0738ccad08b2..db4f910e8e36 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h @@ -192,11 +192,14 @@ extern struct kset *devices_kset; void devices_kset_move_last(struct device *dev); #if defined(CONFIG_MODULES) && defined(CONFIG_SYSFS) -void module_add_driver(struct module *mod, struct device_driver *drv); +int module_add_driver(struct module *mod, struct device_driver *drv); void module_remove_driver(struct device_driver *drv); #else -static inline void module_add_driver(struct module *mod, - struct device_driver *drv) { } +static inline int module_add_driver(struct module *mod, + struct device_driver *drv) +{ + return 0; +} static inline void module_remove_driver(struct device_driver *drv) { } #endif diff --git a/drivers/base/bus.c b/drivers/base/bus.c index daee55c9b2d9..ffea0728b8b2 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -674,7 +674,12 @@ int bus_add_driver(struct device_driver *drv) if (error) goto out_del_list; } - module_add_driver(drv->owner, drv); + error = module_add_driver(drv->owner, drv); + if (error) { + printk(KERN_ERR "%s: failed to create module links for %s\n", + __func__, drv->name); + goto out_detach; + } error = driver_create_file(drv, &driver_attr_uevent); if (error) { @@ -699,6 +704,8 @@ int bus_add_driver(struct device_driver *drv) return 0; +out_detach: + driver_detach(drv); out_del_list: klist_del(&priv->knode_bus); out_unregister: diff --git a/drivers/base/module.c b/drivers/base/module.c index 46ad4d636731..a1b55da07127 100644 --- a/drivers/base/module.c +++ b/drivers/base/module.c @@ -30,14 +30,14 @@ static void module_create_drivers_dir(struct module_kobject *mk) mutex_unlock(&drivers_dir_mutex); } -void module_add_driver(struct module *mod, struct device_driver *drv) +int module_add_driver(struct module *mod, struct device_driver *drv) { char *driver_name; - int no_warn; struct module_kobject *mk = NULL; + int ret; if (!drv) - return; + return 0; if (mod) mk = &mod->mkobj; @@ -56,17 +56,37 @@ void module_add_driver(struct module *mod, struct device_driver *drv) } if (!mk) - return; + return 0; + + ret = sysfs_create_link(&drv->p->kobj, &mk->kobj, "module"); + if (ret) + return ret; - /* Don't check return codes; these calls are idempotent */ - no_warn = sysfs_create_link(&drv->p->kobj, &mk->kobj, "module"); driver_name = make_driver_name(drv); - if (driver_name) { - module_create_drivers_dir(mk); - no_warn = sysfs_create_link(mk->drivers_dir, &drv->p->kobj, - driver_name); - kfree(driver_name); + if (!driver_name) { + ret = -ENOMEM; + goto out; + } + + module_create_drivers_dir(mk); + if (!mk->drivers_dir) { + ret = -EINVAL; + goto out; } + + ret = sysfs_create_link(mk->drivers_dir, &drv->p->kobj, driver_name); + if (ret) + goto out; + + kfree(driver_name); + + return 0; +out: + sysfs_remove_link(&drv->p->kobj, "module"); + sysfs_remove_link(mk->drivers_dir, driver_name); + kfree(driver_name); + + return ret; } void module_remove_driver(struct device_driver *drv) -- cgit v1.2.3-59-g8ed1b From a36b69775fcaab42262f6dbf288ccb6d470158ae Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Fri, 8 Mar 2024 09:51:22 +0100 Subject: ndtest: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Reviewed-by: Dave Jiang Reviewed-by: Dan Williams Link: https://lore.kernel.org/r/c04bfc941a9f5d249b049572c1ae122fe551ee5d.1709886922.git.u.kleine-koenig@pengutronix.de Signed-off-by: Greg Kroah-Hartman --- tools/testing/nvdimm/test/ndtest.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tools/testing/nvdimm/test/ndtest.c b/tools/testing/nvdimm/test/ndtest.c index b8419f460368..2c6285aae852 100644 --- a/tools/testing/nvdimm/test/ndtest.c +++ b/tools/testing/nvdimm/test/ndtest.c @@ -830,12 +830,11 @@ static int ndtest_bus_register(struct ndtest_priv *p) return 0; } -static int ndtest_remove(struct platform_device *pdev) +static void ndtest_remove(struct platform_device *pdev) { struct ndtest_priv *p = to_ndtest_priv(&pdev->dev); nvdimm_bus_unregister(p->bus); - return 0; } static int ndtest_probe(struct platform_device *pdev) @@ -882,7 +881,7 @@ static const struct platform_device_id ndtest_id[] = { static struct platform_driver ndtest_driver = { .probe = ndtest_probe, - .remove = ndtest_remove, + .remove_new = ndtest_remove, .driver = { .name = KBUILD_MODNAME, }, -- cgit v1.2.3-59-g8ed1b From e8c4bd6c6e6b7e7b416c42806981c2a81370001e Mon Sep 17 00:00:00 2001 From: Saurabh Sengar Date: Sat, 30 Mar 2024 01:51:57 -0700 Subject: Drivers: hv: vmbus: Add utility function for querying ring size Add a function to query for the preferred ring buffer size of VMBus device. This will allow the drivers (eg. UIO) to allocate the most optimized ring buffer size for devices. Signed-off-by: Saurabh Sengar Reviewed-by: Long Li Link: https://lore.kernel.org/r/1711788723-8593-2-git-send-email-ssengar@linux.microsoft.com Signed-off-by: Greg Kroah-Hartman --- drivers/hv/channel_mgmt.c | 15 ++++++++++++--- drivers/hv/hyperv_vmbus.h | 5 +++++ include/linux/hyperv.h | 2 ++ 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c index 2f4d09ce027a..3c6011a48dab 100644 --- a/drivers/hv/channel_mgmt.c +++ b/drivers/hv/channel_mgmt.c @@ -120,7 +120,9 @@ const struct vmbus_device vmbus_devs[] = { }, /* File copy */ - { .dev_type = HV_FCOPY, + /* fcopy always uses 16KB ring buffer size and is working well for last many years */ + { .pref_ring_size = 0x4000, + .dev_type = HV_FCOPY, HV_FCOPY_GUID, .perf_device = false, .allowed_in_isolated = false, @@ -140,12 +142,19 @@ const struct vmbus_device vmbus_devs[] = { .allowed_in_isolated = false, }, - /* Unknown GUID */ - { .dev_type = HV_UNKNOWN, + /* + * Unknown GUID + * 64 KB ring buffer + 4 KB header should be sufficient size for any Hyper-V device apart + * from HV_NIC and HV_SCSI. This case avoid the fallback for unknown devices to allocate + * much bigger (2 MB) of ring size. + */ + { .pref_ring_size = 0x11000, + .dev_type = HV_UNKNOWN, .perf_device = false, .allowed_in_isolated = false, }, }; +EXPORT_SYMBOL_GPL(vmbus_devs); static const struct { guid_t guid; diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h index f6b1e710f805..76ac5185a01a 100644 --- a/drivers/hv/hyperv_vmbus.h +++ b/drivers/hv/hyperv_vmbus.h @@ -417,6 +417,11 @@ static inline bool hv_is_perf_channel(struct vmbus_channel *channel) return vmbus_devs[channel->device_id].perf_device; } +static inline size_t hv_dev_ring_size(struct vmbus_channel *channel) +{ + return vmbus_devs[channel->device_id].pref_ring_size; +} + static inline bool hv_is_allocated_cpu(unsigned int cpu) { struct vmbus_channel *channel, *sc; diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h index 6ef0557b4bff..7de9f90d3f95 100644 --- a/include/linux/hyperv.h +++ b/include/linux/hyperv.h @@ -820,6 +820,8 @@ struct vmbus_requestor { #define VMBUS_RQST_RESET (U64_MAX - 3) struct vmbus_device { + /* preferred ring buffer size in KB, 0 means no preferred size for this device */ + size_t pref_ring_size; u16 dev_type; guid_t guid; bool perf_device; -- cgit v1.2.3-59-g8ed1b From e566ed5b64177a0c07b677568f623ed31d23406d Mon Sep 17 00:00:00 2001 From: Saurabh Sengar Date: Sat, 30 Mar 2024 01:51:58 -0700 Subject: uio_hv_generic: Query the ringbuffer size for device Query the ring buffer size from pre defined table per device and use that value for allocating the ring buffer for that device. Keep the size as current default which is 2 MB if the device doesn't have any preferred ring size. Signed-off-by: Saurabh Sengar Reviewed-by: Long Li Link: https://lore.kernel.org/r/1711788723-8593-3-git-send-email-ssengar@linux.microsoft.com Signed-off-by: Greg Kroah-Hartman --- drivers/uio/uio_hv_generic.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/uio/uio_hv_generic.c b/drivers/uio/uio_hv_generic.c index 20d9762331bd..4bda6b52e49e 100644 --- a/drivers/uio/uio_hv_generic.c +++ b/drivers/uio/uio_hv_generic.c @@ -238,6 +238,7 @@ hv_uio_probe(struct hv_device *dev, struct hv_uio_private_data *pdata; void *ring_buffer; int ret; + size_t ring_size = hv_dev_ring_size(channel); /* Communicating with host has to be via shared memory not hypercall */ if (!channel->offermsg.monitor_allocated) { @@ -245,12 +246,14 @@ hv_uio_probe(struct hv_device *dev, return -ENOTSUPP; } + if (!ring_size) + ring_size = HV_RING_SIZE * PAGE_SIZE; + pdata = devm_kzalloc(&dev->device, sizeof(*pdata), GFP_KERNEL); if (!pdata) return -ENOMEM; - ret = vmbus_alloc_ring(channel, HV_RING_SIZE * PAGE_SIZE, - HV_RING_SIZE * PAGE_SIZE); + ret = vmbus_alloc_ring(channel, ring_size, ring_size); if (ret) return ret; -- cgit v1.2.3-59-g8ed1b From 547fa4ffd799ad48bf96e60efd24985adeec35de Mon Sep 17 00:00:00 2001 From: Saurabh Sengar Date: Sat, 30 Mar 2024 01:51:59 -0700 Subject: uio_hv_generic: Enable interrupt for low speed VMBus devices Hyper-V is adding some "specialty" synthetic devices. Instead of writing new kernel-level VMBus drivers for these devices, the devices will be presented to user space via this existing Hyper-V generic UIO driver, so that a user space driver can handle the device. Since these new synthetic devices are low speed devices, they don't support monitor bits and we must use vmbus_setevent() to enable interrupts from the host. Signed-off-by: Saurabh Sengar Reviewed-by: Long Li Link: https://lore.kernel.org/r/1711788723-8593-4-git-send-email-ssengar@linux.microsoft.com Signed-off-by: Greg Kroah-Hartman --- drivers/uio/uio_hv_generic.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/uio/uio_hv_generic.c b/drivers/uio/uio_hv_generic.c index 4bda6b52e49e..289611c7dfd7 100644 --- a/drivers/uio/uio_hv_generic.c +++ b/drivers/uio/uio_hv_generic.c @@ -84,6 +84,9 @@ hv_uio_irqcontrol(struct uio_info *info, s32 irq_state) dev->channel->inbound.ring_buffer->interrupt_mask = !irq_state; virt_mb(); + if (!dev->channel->offermsg.monitor_allocated && irq_state) + vmbus_setevent(dev->channel); + return 0; } @@ -240,12 +243,6 @@ hv_uio_probe(struct hv_device *dev, int ret; size_t ring_size = hv_dev_ring_size(channel); - /* Communicating with host has to be via shared memory not hypercall */ - if (!channel->offermsg.monitor_allocated) { - dev_err(&dev->device, "vmbus channel requires hypercall\n"); - return -ENOTSUPP; - } - if (!ring_size) ring_size = HV_RING_SIZE * PAGE_SIZE; -- cgit v1.2.3-59-g8ed1b From 45bab4d746510ac2bdd9102bf152db617ef96a6b Mon Sep 17 00:00:00 2001 From: Saurabh Sengar Date: Sat, 30 Mar 2024 01:52:00 -0700 Subject: tools: hv: Add vmbus_bufring Common userspace interface for read/write from VMBus ringbuffer. This implementation is open for use by any userspace driver or application seeking direct control over VMBus ring buffers. A significant part of this code is borrowed from DPDK. Link: https://github.com/DPDK/dpdk/ Currently this library is not supported for ARM64. Signed-off-by: Mary Hardy Signed-off-by: Saurabh Sengar Reviewed-by: Long Li Link: https://lore.kernel.org/r/1711788723-8593-5-git-send-email-ssengar@linux.microsoft.com Signed-off-by: Greg Kroah-Hartman --- tools/hv/vmbus_bufring.c | 318 +++++++++++++++++++++++++++++++++++++++++++++++ tools/hv/vmbus_bufring.h | 158 +++++++++++++++++++++++ 2 files changed, 476 insertions(+) create mode 100644 tools/hv/vmbus_bufring.c create mode 100644 tools/hv/vmbus_bufring.h diff --git a/tools/hv/vmbus_bufring.c b/tools/hv/vmbus_bufring.c new file mode 100644 index 000000000000..bac32c1109df --- /dev/null +++ b/tools/hv/vmbus_bufring.c @@ -0,0 +1,318 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2009-2012,2016,2023 Microsoft Corp. + * Copyright (c) 2012 NetApp Inc. + * Copyright (c) 2012 Citrix Inc. + * All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "vmbus_bufring.h" + +/** + * Compiler barrier. + * + * Guarantees that operation reordering does not occur at compile time + * for operations directly before and after the barrier. + */ +#define rte_compiler_barrier() ({ asm volatile ("" : : : "memory"); }) + +#define VMBUS_RQST_ERROR 0xFFFFFFFFFFFFFFFF +#define ALIGN(val, align) ((typeof(val))((val) & (~((typeof(val))((align) - 1))))) + +void *vmbus_uio_map(int *fd, int size) +{ + void *map; + + map = mmap(NULL, 2 * size, PROT_READ | PROT_WRITE, MAP_SHARED, *fd, 0); + if (map == MAP_FAILED) + return NULL; + + return map; +} + +/* Increase bufring index by inc with wraparound */ +static inline uint32_t vmbus_br_idxinc(uint32_t idx, uint32_t inc, uint32_t sz) +{ + idx += inc; + if (idx >= sz) + idx -= sz; + + return idx; +} + +void vmbus_br_setup(struct vmbus_br *br, void *buf, unsigned int blen) +{ + br->vbr = buf; + br->windex = br->vbr->windex; + br->dsize = blen - sizeof(struct vmbus_bufring); +} + +static inline __always_inline void +rte_smp_mb(void) +{ + asm volatile("lock addl $0, -128(%%rsp); " ::: "memory"); +} + +static inline int +rte_atomic32_cmpset(volatile uint32_t *dst, uint32_t exp, uint32_t src) +{ + uint8_t res; + + asm volatile("lock ; " + "cmpxchgl %[src], %[dst];" + "sete %[res];" + : [res] "=a" (res), /* output */ + [dst] "=m" (*dst) + : [src] "r" (src), /* input */ + "a" (exp), + "m" (*dst) + : "memory"); /* no-clobber list */ + return res; +} + +static inline uint32_t +vmbus_txbr_copyto(const struct vmbus_br *tbr, uint32_t windex, + const void *src0, uint32_t cplen) +{ + uint8_t *br_data = tbr->vbr->data; + uint32_t br_dsize = tbr->dsize; + const uint8_t *src = src0; + + /* XXX use double mapping like Linux kernel? */ + if (cplen > br_dsize - windex) { + uint32_t fraglen = br_dsize - windex; + + /* Wrap-around detected */ + memcpy(br_data + windex, src, fraglen); + memcpy(br_data, src + fraglen, cplen - fraglen); + } else { + memcpy(br_data + windex, src, cplen); + } + + return vmbus_br_idxinc(windex, cplen, br_dsize); +} + +/* + * Write scattered channel packet to TX bufring. + * + * The offset of this channel packet is written as a 64bits value + * immediately after this channel packet. + * + * The write goes through three stages: + * 1. Reserve space in ring buffer for the new data. + * Writer atomically moves priv_write_index. + * 2. Copy the new data into the ring. + * 3. Update the tail of the ring (visible to host) that indicates + * next read location. Writer updates write_index + */ +static int +vmbus_txbr_write(struct vmbus_br *tbr, const struct iovec iov[], int iovlen) +{ + struct vmbus_bufring *vbr = tbr->vbr; + uint32_t ring_size = tbr->dsize; + uint32_t old_windex, next_windex, windex, total; + uint64_t save_windex; + int i; + + total = 0; + for (i = 0; i < iovlen; i++) + total += iov[i].iov_len; + total += sizeof(save_windex); + + /* Reserve space in ring */ + do { + uint32_t avail; + + /* Get current free location */ + old_windex = tbr->windex; + + /* Prevent compiler reordering this with calculation */ + rte_compiler_barrier(); + + avail = vmbus_br_availwrite(tbr, old_windex); + + /* If not enough space in ring, then tell caller. */ + if (avail <= total) + return -EAGAIN; + + next_windex = vmbus_br_idxinc(old_windex, total, ring_size); + + /* Atomic update of next write_index for other threads */ + } while (!rte_atomic32_cmpset(&tbr->windex, old_windex, next_windex)); + + /* Space from old..new is now reserved */ + windex = old_windex; + for (i = 0; i < iovlen; i++) + windex = vmbus_txbr_copyto(tbr, windex, iov[i].iov_base, iov[i].iov_len); + + /* Set the offset of the current channel packet. */ + save_windex = ((uint64_t)old_windex) << 32; + windex = vmbus_txbr_copyto(tbr, windex, &save_windex, + sizeof(save_windex)); + + /* The region reserved should match region used */ + if (windex != next_windex) + return -EINVAL; + + /* Ensure that data is available before updating host index */ + rte_compiler_barrier(); + + /* Checkin for our reservation. wait for our turn to update host */ + while (!rte_atomic32_cmpset(&vbr->windex, old_windex, next_windex)) + _mm_pause(); + + return 0; +} + +int rte_vmbus_chan_send(struct vmbus_br *txbr, uint16_t type, void *data, + uint32_t dlen, uint32_t flags) +{ + struct vmbus_chanpkt pkt; + unsigned int pktlen, pad_pktlen; + const uint32_t hlen = sizeof(pkt); + uint64_t pad = 0; + struct iovec iov[3]; + int error; + + pktlen = hlen + dlen; + pad_pktlen = ALIGN(pktlen, sizeof(uint64_t)); + + pkt.hdr.type = type; + pkt.hdr.flags = flags; + pkt.hdr.hlen = hlen >> VMBUS_CHANPKT_SIZE_SHIFT; + pkt.hdr.tlen = pad_pktlen >> VMBUS_CHANPKT_SIZE_SHIFT; + pkt.hdr.xactid = VMBUS_RQST_ERROR; + + iov[0].iov_base = &pkt; + iov[0].iov_len = hlen; + iov[1].iov_base = data; + iov[1].iov_len = dlen; + iov[2].iov_base = &pad; + iov[2].iov_len = pad_pktlen - pktlen; + + error = vmbus_txbr_write(txbr, iov, 3); + + return error; +} + +static inline uint32_t +vmbus_rxbr_copyfrom(const struct vmbus_br *rbr, uint32_t rindex, + void *dst0, size_t cplen) +{ + const uint8_t *br_data = rbr->vbr->data; + uint32_t br_dsize = rbr->dsize; + uint8_t *dst = dst0; + + if (cplen > br_dsize - rindex) { + uint32_t fraglen = br_dsize - rindex; + + /* Wrap-around detected. */ + memcpy(dst, br_data + rindex, fraglen); + memcpy(dst + fraglen, br_data, cplen - fraglen); + } else { + memcpy(dst, br_data + rindex, cplen); + } + + return vmbus_br_idxinc(rindex, cplen, br_dsize); +} + +/* Copy data from receive ring but don't change index */ +static int +vmbus_rxbr_peek(const struct vmbus_br *rbr, void *data, size_t dlen) +{ + uint32_t avail; + + /* + * The requested data and the 64bits channel packet + * offset should be there at least. + */ + avail = vmbus_br_availread(rbr); + if (avail < dlen + sizeof(uint64_t)) + return -EAGAIN; + + vmbus_rxbr_copyfrom(rbr, rbr->vbr->rindex, data, dlen); + return 0; +} + +/* + * Copy data from receive ring and change index + * NOTE: + * We assume (dlen + skip) == sizeof(channel packet). + */ +static int +vmbus_rxbr_read(struct vmbus_br *rbr, void *data, size_t dlen, size_t skip) +{ + struct vmbus_bufring *vbr = rbr->vbr; + uint32_t br_dsize = rbr->dsize; + uint32_t rindex; + + if (vmbus_br_availread(rbr) < dlen + skip + sizeof(uint64_t)) + return -EAGAIN; + + /* Record where host was when we started read (for debug) */ + rbr->windex = rbr->vbr->windex; + + /* + * Copy channel packet from RX bufring. + */ + rindex = vmbus_br_idxinc(rbr->vbr->rindex, skip, br_dsize); + rindex = vmbus_rxbr_copyfrom(rbr, rindex, data, dlen); + + /* + * Discard this channel packet's 64bits offset, which is useless to us. + */ + rindex = vmbus_br_idxinc(rindex, sizeof(uint64_t), br_dsize); + + /* Update the read index _after_ the channel packet is fetched. */ + rte_compiler_barrier(); + + vbr->rindex = rindex; + + return 0; +} + +int rte_vmbus_chan_recv_raw(struct vmbus_br *rxbr, + void *data, uint32_t *len) +{ + struct vmbus_chanpkt_hdr pkt; + uint32_t dlen, bufferlen = *len; + int error; + + error = vmbus_rxbr_peek(rxbr, &pkt, sizeof(pkt)); + if (error) + return error; + + if (unlikely(pkt.hlen < VMBUS_CHANPKT_HLEN_MIN)) + /* XXX this channel is dead actually. */ + return -EIO; + + if (unlikely(pkt.hlen > pkt.tlen)) + return -EIO; + + /* Length are in quad words */ + dlen = pkt.tlen << VMBUS_CHANPKT_SIZE_SHIFT; + *len = dlen; + + /* If caller buffer is not large enough */ + if (unlikely(dlen > bufferlen)) + return -ENOBUFS; + + /* Read data and skip packet header */ + error = vmbus_rxbr_read(rxbr, data, dlen, 0); + if (error) + return error; + + /* Return the number of bytes read */ + return dlen + sizeof(uint64_t); +} diff --git a/tools/hv/vmbus_bufring.h b/tools/hv/vmbus_bufring.h new file mode 100644 index 000000000000..6e7caacfff57 --- /dev/null +++ b/tools/hv/vmbus_bufring.h @@ -0,0 +1,158 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +#ifndef _VMBUS_BUF_H_ +#define _VMBUS_BUF_H_ + +#include +#include + +#define __packed __attribute__((__packed__)) +#define unlikely(x) __builtin_expect(!!(x), 0) + +#define ICMSGHDRFLAG_TRANSACTION 1 +#define ICMSGHDRFLAG_REQUEST 2 +#define ICMSGHDRFLAG_RESPONSE 4 + +#define IC_VERSION_NEGOTIATION_MAX_VER_COUNT 100 +#define ICMSG_HDR (sizeof(struct vmbuspipe_hdr) + sizeof(struct icmsg_hdr)) +#define ICMSG_NEGOTIATE_PKT_SIZE(icframe_vercnt, icmsg_vercnt) \ + (ICMSG_HDR + sizeof(struct icmsg_negotiate) + \ + (((icframe_vercnt) + (icmsg_vercnt)) * sizeof(struct ic_version))) + +/* + * Channel packets + */ + +/* Channel packet flags */ +#define VMBUS_CHANPKT_TYPE_INBAND 0x0006 +#define VMBUS_CHANPKT_TYPE_RXBUF 0x0007 +#define VMBUS_CHANPKT_TYPE_GPA 0x0009 +#define VMBUS_CHANPKT_TYPE_COMP 0x000b + +#define VMBUS_CHANPKT_FLAG_NONE 0 +#define VMBUS_CHANPKT_FLAG_RC 0x0001 /* report completion */ + +#define VMBUS_CHANPKT_SIZE_SHIFT 3 +#define VMBUS_CHANPKT_SIZE_ALIGN BIT(VMBUS_CHANPKT_SIZE_SHIFT) +#define VMBUS_CHANPKT_HLEN_MIN \ + (sizeof(struct vmbus_chanpkt_hdr) >> VMBUS_CHANPKT_SIZE_SHIFT) + +/* + * Buffer ring + */ +struct vmbus_bufring { + volatile uint32_t windex; + volatile uint32_t rindex; + + /* + * Interrupt mask {0,1} + * + * For TX bufring, host set this to 1, when it is processing + * the TX bufring, so that we can safely skip the TX event + * notification to host. + * + * For RX bufring, once this is set to 1 by us, host will not + * further dispatch interrupts to us, even if there are data + * pending on the RX bufring. This effectively disables the + * interrupt of the channel to which this RX bufring is attached. + */ + volatile uint32_t imask; + + /* + * Win8 uses some of the reserved bits to implement + * interrupt driven flow management. On the send side + * we can request that the receiver interrupt the sender + * when the ring transitions from being full to being able + * to handle a message of size "pending_send_sz". + * + * Add necessary state for this enhancement. + */ + volatile uint32_t pending_send; + uint32_t reserved1[12]; + + union { + struct { + uint32_t feat_pending_send_sz:1; + }; + uint32_t value; + } feature_bits; + + /* Pad it to rte_mem_page_size() so that data starts on page boundary */ + uint8_t reserved2[4028]; + + /* + * Ring data starts here + RingDataStartOffset + * !!! DO NOT place any fields below this !!! + */ + uint8_t data[]; +} __packed; + +struct vmbus_br { + struct vmbus_bufring *vbr; + uint32_t dsize; + uint32_t windex; /* next available location */ +}; + +struct vmbus_chanpkt_hdr { + uint16_t type; /* VMBUS_CHANPKT_TYPE_ */ + uint16_t hlen; /* header len, in 8 bytes */ + uint16_t tlen; /* total len, in 8 bytes */ + uint16_t flags; /* VMBUS_CHANPKT_FLAG_ */ + uint64_t xactid; +} __packed; + +struct vmbus_chanpkt { + struct vmbus_chanpkt_hdr hdr; +} __packed; + +struct vmbuspipe_hdr { + unsigned int flags; + unsigned int msgsize; +} __packed; + +struct ic_version { + unsigned short major; + unsigned short minor; +} __packed; + +struct icmsg_negotiate { + unsigned short icframe_vercnt; + unsigned short icmsg_vercnt; + unsigned int reserved; + struct ic_version icversion_data[]; /* any size array */ +} __packed; + +struct icmsg_hdr { + struct ic_version icverframe; + unsigned short icmsgtype; + struct ic_version icvermsg; + unsigned short icmsgsize; + unsigned int status; + unsigned char ictransaction_id; + unsigned char icflags; + unsigned char reserved[2]; +} __packed; + +int rte_vmbus_chan_recv_raw(struct vmbus_br *rxbr, void *data, uint32_t *len); +int rte_vmbus_chan_send(struct vmbus_br *txbr, uint16_t type, void *data, + uint32_t dlen, uint32_t flags); +void vmbus_br_setup(struct vmbus_br *br, void *buf, unsigned int blen); +void *vmbus_uio_map(int *fd, int size); + +/* Amount of space available for write */ +static inline uint32_t vmbus_br_availwrite(const struct vmbus_br *br, uint32_t windex) +{ + uint32_t rindex = br->vbr->rindex; + + if (windex >= rindex) + return br->dsize - (windex - rindex); + else + return rindex - windex; +} + +static inline uint32_t vmbus_br_availread(const struct vmbus_br *br) +{ + return br->dsize - vmbus_br_availwrite(br, br->vbr->windex); +} + +#endif /* !_VMBUS_BUF_H_ */ -- cgit v1.2.3-59-g8ed1b From 82b0945ce2c2d636d5e893ad50210875c929f257 Mon Sep 17 00:00:00 2001 From: Saurabh Sengar Date: Sat, 30 Mar 2024 01:52:01 -0700 Subject: tools: hv: Add new fcopy application based on uio driver New fcopy application using uio_hv_generic driver. This application copies file from Hyper-V host to guest VM. A big part of this code is copied from tools/hv/hv_fcopy_daemon.c which this new application is replacing. Signed-off-by: Saurabh Sengar Reviewed-by: Long Li Link: https://lore.kernel.org/r/1711788723-8593-6-git-send-email-ssengar@linux.microsoft.com Signed-off-by: Greg Kroah-Hartman --- tools/hv/Build | 3 +- tools/hv/Makefile | 14 +- tools/hv/hv_fcopy_uio_daemon.c | 490 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 501 insertions(+), 6 deletions(-) create mode 100644 tools/hv/hv_fcopy_uio_daemon.c diff --git a/tools/hv/Build b/tools/hv/Build index 6cf51fa4b306..7d1f1698069b 100644 --- a/tools/hv/Build +++ b/tools/hv/Build @@ -1,3 +1,4 @@ hv_kvp_daemon-y += hv_kvp_daemon.o hv_vss_daemon-y += hv_vss_daemon.o -hv_fcopy_daemon-y += hv_fcopy_daemon.o +hv_fcopy_uio_daemon-y += hv_fcopy_uio_daemon.o +hv_fcopy_uio_daemon-y += vmbus_bufring.o diff --git a/tools/hv/Makefile b/tools/hv/Makefile index fe770e679ae8..bb52871da341 100644 --- a/tools/hv/Makefile +++ b/tools/hv/Makefile @@ -2,6 +2,7 @@ # Makefile for Hyper-V tools include ../scripts/Makefile.include +ARCH := $(shell uname -m 2>/dev/null) sbindir ?= /usr/sbin libexecdir ?= /usr/libexec sharedstatedir ?= /var/lib @@ -17,7 +18,10 @@ MAKEFLAGS += -r override CFLAGS += -O2 -Wall -g -D_GNU_SOURCE -I$(OUTPUT)include -ALL_TARGETS := hv_kvp_daemon hv_vss_daemon hv_fcopy_daemon +ALL_TARGETS := hv_kvp_daemon hv_vss_daemon +ifneq ($(ARCH), aarch64) +ALL_TARGETS += hv_fcopy_uio_daemon +endif ALL_PROGRAMS := $(patsubst %,$(OUTPUT)%,$(ALL_TARGETS)) ALL_SCRIPTS := hv_get_dhcp_info.sh hv_get_dns_info.sh hv_set_ifconfig.sh @@ -39,10 +43,10 @@ $(HV_VSS_DAEMON_IN): FORCE $(OUTPUT)hv_vss_daemon: $(HV_VSS_DAEMON_IN) $(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ -HV_FCOPY_DAEMON_IN := $(OUTPUT)hv_fcopy_daemon-in.o -$(HV_FCOPY_DAEMON_IN): FORCE - $(Q)$(MAKE) $(build)=hv_fcopy_daemon -$(OUTPUT)hv_fcopy_daemon: $(HV_FCOPY_DAEMON_IN) +HV_FCOPY_UIO_DAEMON_IN := $(OUTPUT)hv_fcopy_uio_daemon-in.o +$(HV_FCOPY_UIO_DAEMON_IN): FORCE + $(Q)$(MAKE) $(build)=hv_fcopy_uio_daemon +$(OUTPUT)hv_fcopy_uio_daemon: $(HV_FCOPY_UIO_DAEMON_IN) $(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ clean: diff --git a/tools/hv/hv_fcopy_uio_daemon.c b/tools/hv/hv_fcopy_uio_daemon.c new file mode 100644 index 000000000000..3ce316cc9f97 --- /dev/null +++ b/tools/hv/hv_fcopy_uio_daemon.c @@ -0,0 +1,490 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * An implementation of host to guest copy functionality for Linux. + * + * Copyright (C) 2023, Microsoft, Inc. + * + * Author : K. Y. Srinivasan + * Author : Saurabh Sengar + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "vmbus_bufring.h" + +#define ICMSGTYPE_NEGOTIATE 0 +#define ICMSGTYPE_FCOPY 7 + +#define WIN8_SRV_MAJOR 1 +#define WIN8_SRV_MINOR 1 +#define WIN8_SRV_VERSION (WIN8_SRV_MAJOR << 16 | WIN8_SRV_MINOR) + +#define MAX_FOLDER_NAME 15 +#define MAX_PATH_LEN 15 +#define FCOPY_UIO "/sys/bus/vmbus/devices/eb765408-105f-49b6-b4aa-c123b64d17d4/uio" + +#define FCOPY_VER_COUNT 1 +static const int fcopy_versions[] = { + WIN8_SRV_VERSION +}; + +#define FW_VER_COUNT 1 +static const int fw_versions[] = { + UTIL_FW_VERSION +}; + +#define HV_RING_SIZE 0x4000 /* 16KB ring buffer size */ + +unsigned char desc[HV_RING_SIZE]; + +static int target_fd; +static char target_fname[PATH_MAX]; +static unsigned long long filesize; + +static int hv_fcopy_create_file(char *file_name, char *path_name, __u32 flags) +{ + int error = HV_E_FAIL; + char *q, *p; + + filesize = 0; + p = path_name; + snprintf(target_fname, sizeof(target_fname), "%s/%s", + path_name, file_name); + + /* + * Check to see if the path is already in place; if not, + * create if required. + */ + while ((q = strchr(p, '/')) != NULL) { + if (q == p) { + p++; + continue; + } + *q = '\0'; + if (access(path_name, F_OK)) { + if (flags & CREATE_PATH) { + if (mkdir(path_name, 0755)) { + syslog(LOG_ERR, "Failed to create %s", + path_name); + goto done; + } + } else { + syslog(LOG_ERR, "Invalid path: %s", path_name); + goto done; + } + } + p = q + 1; + *q = '/'; + } + + if (!access(target_fname, F_OK)) { + syslog(LOG_INFO, "File: %s exists", target_fname); + if (!(flags & OVER_WRITE)) { + error = HV_ERROR_ALREADY_EXISTS; + goto done; + } + } + + target_fd = open(target_fname, + O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC, 0744); + if (target_fd == -1) { + syslog(LOG_INFO, "Open Failed: %s", strerror(errno)); + goto done; + } + + error = 0; +done: + if (error) + target_fname[0] = '\0'; + return error; +} + +/* copy the data into the file */ +static int hv_copy_data(struct hv_do_fcopy *cpmsg) +{ + ssize_t len; + int ret = 0; + + len = pwrite(target_fd, cpmsg->data, cpmsg->size, cpmsg->offset); + + filesize += cpmsg->size; + if (len != cpmsg->size) { + switch (errno) { + case ENOSPC: + ret = HV_ERROR_DISK_FULL; + break; + default: + ret = HV_E_FAIL; + break; + } + syslog(LOG_ERR, "pwrite failed to write %llu bytes: %ld (%s)", + filesize, (long)len, strerror(errno)); + } + + return ret; +} + +static int hv_copy_finished(void) +{ + close(target_fd); + target_fname[0] = '\0'; + + return 0; +} + +static void print_usage(char *argv[]) +{ + fprintf(stderr, "Usage: %s [options]\n" + "Options are:\n" + " -n, --no-daemon stay in foreground, don't daemonize\n" + " -h, --help print this help\n", argv[0]); +} + +static bool vmbus_prep_negotiate_resp(struct icmsg_hdr *icmsghdrp, unsigned char *buf, + unsigned int buflen, const int *fw_version, int fw_vercnt, + const int *srv_version, int srv_vercnt, + int *nego_fw_version, int *nego_srv_version) +{ + int icframe_major, icframe_minor; + int icmsg_major, icmsg_minor; + int fw_major, fw_minor; + int srv_major, srv_minor; + int i, j; + bool found_match = false; + struct icmsg_negotiate *negop; + + /* Check that there's enough space for icframe_vercnt, icmsg_vercnt */ + if (buflen < ICMSG_HDR + offsetof(struct icmsg_negotiate, reserved)) { + syslog(LOG_ERR, "Invalid icmsg negotiate"); + return false; + } + + icmsghdrp->icmsgsize = 0x10; + negop = (struct icmsg_negotiate *)&buf[ICMSG_HDR]; + + icframe_major = negop->icframe_vercnt; + icframe_minor = 0; + + icmsg_major = negop->icmsg_vercnt; + icmsg_minor = 0; + + /* Validate negop packet */ + if (icframe_major > IC_VERSION_NEGOTIATION_MAX_VER_COUNT || + icmsg_major > IC_VERSION_NEGOTIATION_MAX_VER_COUNT || + ICMSG_NEGOTIATE_PKT_SIZE(icframe_major, icmsg_major) > buflen) { + syslog(LOG_ERR, "Invalid icmsg negotiate - icframe_major: %u, icmsg_major: %u\n", + icframe_major, icmsg_major); + goto fw_error; + } + + /* + * Select the framework version number we will + * support. + */ + + for (i = 0; i < fw_vercnt; i++) { + fw_major = (fw_version[i] >> 16); + fw_minor = (fw_version[i] & 0xFFFF); + + for (j = 0; j < negop->icframe_vercnt; j++) { + if (negop->icversion_data[j].major == fw_major && + negop->icversion_data[j].minor == fw_minor) { + icframe_major = negop->icversion_data[j].major; + icframe_minor = negop->icversion_data[j].minor; + found_match = true; + break; + } + } + + if (found_match) + break; + } + + if (!found_match) + goto fw_error; + + found_match = false; + + for (i = 0; i < srv_vercnt; i++) { + srv_major = (srv_version[i] >> 16); + srv_minor = (srv_version[i] & 0xFFFF); + + for (j = negop->icframe_vercnt; + (j < negop->icframe_vercnt + negop->icmsg_vercnt); + j++) { + if (negop->icversion_data[j].major == srv_major && + negop->icversion_data[j].minor == srv_minor) { + icmsg_major = negop->icversion_data[j].major; + icmsg_minor = negop->icversion_data[j].minor; + found_match = true; + break; + } + } + + if (found_match) + break; + } + + /* + * Respond with the framework and service + * version numbers we can support. + */ +fw_error: + if (!found_match) { + negop->icframe_vercnt = 0; + negop->icmsg_vercnt = 0; + } else { + negop->icframe_vercnt = 1; + negop->icmsg_vercnt = 1; + } + + if (nego_fw_version) + *nego_fw_version = (icframe_major << 16) | icframe_minor; + + if (nego_srv_version) + *nego_srv_version = (icmsg_major << 16) | icmsg_minor; + + negop->icversion_data[0].major = icframe_major; + negop->icversion_data[0].minor = icframe_minor; + negop->icversion_data[1].major = icmsg_major; + negop->icversion_data[1].minor = icmsg_minor; + + return found_match; +} + +static void wcstoutf8(char *dest, const __u16 *src, size_t dest_size) +{ + size_t len = 0; + + while (len < dest_size) { + if (src[len] < 0x80) + dest[len++] = (char)(*src++); + else + dest[len++] = 'X'; + } + + dest[len] = '\0'; +} + +static int hv_fcopy_start(struct hv_start_fcopy *smsg_in) +{ + setlocale(LC_ALL, "en_US.utf8"); + size_t file_size, path_size; + char *file_name, *path_name; + char *in_file_name = (char *)smsg_in->file_name; + char *in_path_name = (char *)smsg_in->path_name; + + file_size = wcstombs(NULL, (const wchar_t *restrict)in_file_name, 0) + 1; + path_size = wcstombs(NULL, (const wchar_t *restrict)in_path_name, 0) + 1; + + file_name = (char *)malloc(file_size * sizeof(char)); + path_name = (char *)malloc(path_size * sizeof(char)); + + wcstoutf8(file_name, (__u16 *)in_file_name, file_size); + wcstoutf8(path_name, (__u16 *)in_path_name, path_size); + + return hv_fcopy_create_file(file_name, path_name, smsg_in->copy_flags); +} + +static int hv_fcopy_send_data(struct hv_fcopy_hdr *fcopy_msg, int recvlen) +{ + int operation = fcopy_msg->operation; + + /* + * The strings sent from the host are encoded in + * utf16; convert it to utf8 strings. + * The host assures us that the utf16 strings will not exceed + * the max lengths specified. We will however, reserve room + * for the string terminating character - in the utf16s_utf8s() + * function we limit the size of the buffer where the converted + * string is placed to W_MAX_PATH -1 to guarantee + * that the strings can be properly terminated! + */ + + switch (operation) { + case START_FILE_COPY: + return hv_fcopy_start((struct hv_start_fcopy *)fcopy_msg); + case WRITE_TO_FILE: + return hv_copy_data((struct hv_do_fcopy *)fcopy_msg); + case COMPLETE_FCOPY: + return hv_copy_finished(); + } + + return HV_E_FAIL; +} + +/* process the packet recv from host */ +static int fcopy_pkt_process(struct vmbus_br *txbr) +{ + int ret, offset, pktlen; + int fcopy_srv_version; + const struct vmbus_chanpkt_hdr *pkt; + struct hv_fcopy_hdr *fcopy_msg; + struct icmsg_hdr *icmsghdr; + + pkt = (const struct vmbus_chanpkt_hdr *)desc; + offset = pkt->hlen << 3; + pktlen = (pkt->tlen << 3) - offset; + icmsghdr = (struct icmsg_hdr *)&desc[offset + sizeof(struct vmbuspipe_hdr)]; + icmsghdr->status = HV_E_FAIL; + + if (icmsghdr->icmsgtype == ICMSGTYPE_NEGOTIATE) { + if (vmbus_prep_negotiate_resp(icmsghdr, desc + offset, pktlen, fw_versions, + FW_VER_COUNT, fcopy_versions, FCOPY_VER_COUNT, + NULL, &fcopy_srv_version)) { + syslog(LOG_INFO, "FCopy IC version %d.%d", + fcopy_srv_version >> 16, fcopy_srv_version & 0xFFFF); + icmsghdr->status = 0; + } + } else if (icmsghdr->icmsgtype == ICMSGTYPE_FCOPY) { + /* Ensure recvlen is big enough to contain hv_fcopy_hdr */ + if (pktlen < ICMSG_HDR + sizeof(struct hv_fcopy_hdr)) { + syslog(LOG_ERR, "Invalid Fcopy hdr. Packet length too small: %u", + pktlen); + return -ENOBUFS; + } + + fcopy_msg = (struct hv_fcopy_hdr *)&desc[offset + ICMSG_HDR]; + icmsghdr->status = hv_fcopy_send_data(fcopy_msg, pktlen); + } + + icmsghdr->icflags = ICMSGHDRFLAG_TRANSACTION | ICMSGHDRFLAG_RESPONSE; + ret = rte_vmbus_chan_send(txbr, 0x6, desc + offset, pktlen, 0); + if (ret) { + syslog(LOG_ERR, "Write to ringbuffer failed err: %d", ret); + return ret; + } + + return 0; +} + +static void fcopy_get_first_folder(char *path, char *chan_no) +{ + DIR *dir = opendir(path); + struct dirent *entry; + + if (!dir) { + syslog(LOG_ERR, "Failed to open directory (errno=%s).\n", strerror(errno)); + return; + } + + while ((entry = readdir(dir)) != NULL) { + if (entry->d_type == DT_DIR && strcmp(entry->d_name, ".") != 0 && + strcmp(entry->d_name, "..") != 0) { + strcpy(chan_no, entry->d_name); + break; + } + } + + closedir(dir); +} + +int main(int argc, char *argv[]) +{ + int fcopy_fd = -1, tmp = 1; + int daemonize = 1, long_index = 0, opt, ret = -EINVAL; + struct vmbus_br txbr, rxbr; + void *ring; + uint32_t len = HV_RING_SIZE; + char uio_name[MAX_FOLDER_NAME] = {0}; + char uio_dev_path[MAX_PATH_LEN] = {0}; + + static struct option long_options[] = { + {"help", no_argument, 0, 'h' }, + {"no-daemon", no_argument, 0, 'n' }, + {0, 0, 0, 0 } + }; + + while ((opt = getopt_long(argc, argv, "hn", long_options, + &long_index)) != -1) { + switch (opt) { + case 'n': + daemonize = 0; + break; + case 'h': + default: + print_usage(argv); + goto exit; + } + } + + if (daemonize && daemon(1, 0)) { + syslog(LOG_ERR, "daemon() failed; error: %s", strerror(errno)); + goto exit; + } + + openlog("HV_UIO_FCOPY", 0, LOG_USER); + syslog(LOG_INFO, "starting; pid is:%d", getpid()); + + fcopy_get_first_folder(FCOPY_UIO, uio_name); + snprintf(uio_dev_path, sizeof(uio_dev_path), "/dev/%s", uio_name); + fcopy_fd = open(uio_dev_path, O_RDWR); + + if (fcopy_fd < 0) { + syslog(LOG_ERR, "open %s failed; error: %d %s", + uio_dev_path, errno, strerror(errno)); + ret = fcopy_fd; + goto exit; + } + + ring = vmbus_uio_map(&fcopy_fd, HV_RING_SIZE); + if (!ring) { + ret = errno; + syslog(LOG_ERR, "mmap ringbuffer failed; error: %d %s", ret, strerror(ret)); + goto close; + } + vmbus_br_setup(&txbr, ring, HV_RING_SIZE); + vmbus_br_setup(&rxbr, (char *)ring + HV_RING_SIZE, HV_RING_SIZE); + + rxbr.vbr->imask = 0; + + while (1) { + /* + * In this loop we process fcopy messages after the + * handshake is complete. + */ + ret = pread(fcopy_fd, &tmp, sizeof(int), 0); + if (ret < 0) { + syslog(LOG_ERR, "pread failed: %s", strerror(errno)); + continue; + } + + len = HV_RING_SIZE; + ret = rte_vmbus_chan_recv_raw(&rxbr, desc, &len); + if (unlikely(ret <= 0)) { + /* This indicates a failure to communicate (or worse) */ + syslog(LOG_ERR, "VMBus channel recv error: %d", ret); + } else { + ret = fcopy_pkt_process(&txbr); + if (ret < 0) + goto close; + + /* Signal host */ + if ((write(fcopy_fd, &tmp, sizeof(int))) != sizeof(int)) { + ret = errno; + syslog(LOG_ERR, "Signal to host failed: %s\n", strerror(ret)); + goto close; + } + } + } +close: + close(fcopy_fd); +exit: + return ret; +} -- cgit v1.2.3-59-g8ed1b From ec314f61e4fc2d3dd6ea78aa18a5ac276eb1a8e3 Mon Sep 17 00:00:00 2001 From: Saurabh Sengar Date: Sat, 30 Mar 2024 01:52:02 -0700 Subject: Drivers: hv: Remove fcopy driver As the new fcopy driver using uio is introduced, remove obsolete driver and application. Signed-off-by: Saurabh Sengar Reviewed-by: Long Li Link: https://lore.kernel.org/r/1711788723-8593-7-git-send-email-ssengar@linux.microsoft.com Signed-off-by: Greg Kroah-Hartman --- drivers/hv/Makefile | 2 +- drivers/hv/hv_fcopy.c | 427 --------------------------------------------- drivers/hv/hv_util.c | 12 -- tools/hv/hv_fcopy_daemon.c | 266 ---------------------------- 4 files changed, 1 insertion(+), 706 deletions(-) delete mode 100644 drivers/hv/hv_fcopy.c delete mode 100644 tools/hv/hv_fcopy_daemon.c diff --git a/drivers/hv/Makefile b/drivers/hv/Makefile index d76df5c8c2a9..b992c0ed182b 100644 --- a/drivers/hv/Makefile +++ b/drivers/hv/Makefile @@ -10,7 +10,7 @@ hv_vmbus-y := vmbus_drv.o \ hv.o connection.o channel.o \ channel_mgmt.o ring_buffer.o hv_trace.o hv_vmbus-$(CONFIG_HYPERV_TESTING) += hv_debugfs.o -hv_utils-y := hv_util.o hv_kvp.o hv_snapshot.o hv_fcopy.o hv_utils_transport.o +hv_utils-y := hv_util.o hv_kvp.o hv_snapshot.o hv_utils_transport.o # Code that must be built-in obj-$(subst m,y,$(CONFIG_HYPERV)) += hv_common.o diff --git a/drivers/hv/hv_fcopy.c b/drivers/hv/hv_fcopy.c deleted file mode 100644 index 922d83eb7ddf..000000000000 --- a/drivers/hv/hv_fcopy.c +++ /dev/null @@ -1,427 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * An implementation of file copy service. - * - * Copyright (C) 2014, Microsoft, Inc. - * - * Author : K. Y. Srinivasan - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include - -#include "hyperv_vmbus.h" -#include "hv_utils_transport.h" - -#define WIN8_SRV_MAJOR 1 -#define WIN8_SRV_MINOR 1 -#define WIN8_SRV_VERSION (WIN8_SRV_MAJOR << 16 | WIN8_SRV_MINOR) - -#define FCOPY_VER_COUNT 1 -static const int fcopy_versions[] = { - WIN8_SRV_VERSION -}; - -#define FW_VER_COUNT 1 -static const int fw_versions[] = { - UTIL_FW_VERSION -}; - -/* - * Global state maintained for transaction that is being processed. - * For a class of integration services, including the "file copy service", - * the specified protocol is a "request/response" protocol which means that - * there can only be single outstanding transaction from the host at any - * given point in time. We use this to simplify memory management in this - * driver - we cache and process only one message at a time. - * - * While the request/response protocol is guaranteed by the host, we further - * ensure this by serializing packet processing in this driver - we do not - * read additional packets from the VMBUs until the current packet is fully - * handled. - */ - -static struct { - int state; /* hvutil_device_state */ - int recv_len; /* number of bytes received. */ - struct hv_fcopy_hdr *fcopy_msg; /* current message */ - struct vmbus_channel *recv_channel; /* chn we got the request */ - u64 recv_req_id; /* request ID. */ -} fcopy_transaction; - -static void fcopy_respond_to_host(int error); -static void fcopy_send_data(struct work_struct *dummy); -static void fcopy_timeout_func(struct work_struct *dummy); -static DECLARE_DELAYED_WORK(fcopy_timeout_work, fcopy_timeout_func); -static DECLARE_WORK(fcopy_send_work, fcopy_send_data); -static const char fcopy_devname[] = "vmbus/hv_fcopy"; -static u8 *recv_buffer; -static struct hvutil_transport *hvt; -/* - * This state maintains the version number registered by the daemon. - */ -static int dm_reg_value; - -static void fcopy_poll_wrapper(void *channel) -{ - /* Transaction is finished, reset the state here to avoid races. */ - fcopy_transaction.state = HVUTIL_READY; - tasklet_schedule(&((struct vmbus_channel *)channel)->callback_event); -} - -static void fcopy_timeout_func(struct work_struct *dummy) -{ - /* - * If the timer fires, the user-mode component has not responded; - * process the pending transaction. - */ - fcopy_respond_to_host(HV_E_FAIL); - hv_poll_channel(fcopy_transaction.recv_channel, fcopy_poll_wrapper); -} - -static void fcopy_register_done(void) -{ - pr_debug("FCP: userspace daemon registered\n"); - hv_poll_channel(fcopy_transaction.recv_channel, fcopy_poll_wrapper); -} - -static int fcopy_handle_handshake(u32 version) -{ - u32 our_ver = FCOPY_CURRENT_VERSION; - - switch (version) { - case FCOPY_VERSION_0: - /* Daemon doesn't expect us to reply */ - dm_reg_value = version; - break; - case FCOPY_VERSION_1: - /* Daemon expects us to reply with our own version */ - if (hvutil_transport_send(hvt, &our_ver, sizeof(our_ver), - fcopy_register_done)) - return -EFAULT; - dm_reg_value = version; - break; - default: - /* - * For now we will fail the registration. - * If and when we have multiple versions to - * deal with, we will be backward compatible. - * We will add this code when needed. - */ - return -EINVAL; - } - pr_debug("FCP: userspace daemon ver. %d connected\n", version); - return 0; -} - -static void fcopy_send_data(struct work_struct *dummy) -{ - struct hv_start_fcopy *smsg_out = NULL; - int operation = fcopy_transaction.fcopy_msg->operation; - struct hv_start_fcopy *smsg_in; - void *out_src; - int rc, out_len; - - /* - * The strings sent from the host are encoded in - * utf16; convert it to utf8 strings. - * The host assures us that the utf16 strings will not exceed - * the max lengths specified. We will however, reserve room - * for the string terminating character - in the utf16s_utf8s() - * function we limit the size of the buffer where the converted - * string is placed to W_MAX_PATH -1 to guarantee - * that the strings can be properly terminated! - */ - - switch (operation) { - case START_FILE_COPY: - out_len = sizeof(struct hv_start_fcopy); - smsg_out = kzalloc(sizeof(*smsg_out), GFP_KERNEL); - if (!smsg_out) - return; - - smsg_out->hdr.operation = operation; - smsg_in = (struct hv_start_fcopy *)fcopy_transaction.fcopy_msg; - - utf16s_to_utf8s((wchar_t *)smsg_in->file_name, W_MAX_PATH, - UTF16_LITTLE_ENDIAN, - (__u8 *)&smsg_out->file_name, W_MAX_PATH - 1); - - utf16s_to_utf8s((wchar_t *)smsg_in->path_name, W_MAX_PATH, - UTF16_LITTLE_ENDIAN, - (__u8 *)&smsg_out->path_name, W_MAX_PATH - 1); - - smsg_out->copy_flags = smsg_in->copy_flags; - smsg_out->file_size = smsg_in->file_size; - out_src = smsg_out; - break; - - case WRITE_TO_FILE: - out_src = fcopy_transaction.fcopy_msg; - out_len = sizeof(struct hv_do_fcopy); - break; - default: - out_src = fcopy_transaction.fcopy_msg; - out_len = fcopy_transaction.recv_len; - break; - } - - fcopy_transaction.state = HVUTIL_USERSPACE_REQ; - rc = hvutil_transport_send(hvt, out_src, out_len, NULL); - if (rc) { - pr_debug("FCP: failed to communicate to the daemon: %d\n", rc); - if (cancel_delayed_work_sync(&fcopy_timeout_work)) { - fcopy_respond_to_host(HV_E_FAIL); - fcopy_transaction.state = HVUTIL_READY; - } - } - kfree(smsg_out); -} - -/* - * Send a response back to the host. - */ - -static void -fcopy_respond_to_host(int error) -{ - struct icmsg_hdr *icmsghdr; - u32 buf_len; - struct vmbus_channel *channel; - u64 req_id; - - /* - * Copy the global state for completing the transaction. Note that - * only one transaction can be active at a time. This is guaranteed - * by the file copy protocol implemented by the host. Furthermore, - * the "transaction active" state we maintain ensures that there can - * only be one active transaction at a time. - */ - - buf_len = fcopy_transaction.recv_len; - channel = fcopy_transaction.recv_channel; - req_id = fcopy_transaction.recv_req_id; - - icmsghdr = (struct icmsg_hdr *) - &recv_buffer[sizeof(struct vmbuspipe_hdr)]; - - if (channel->onchannel_callback == NULL) - /* - * We have raced with util driver being unloaded; - * silently return. - */ - return; - - icmsghdr->status = error; - icmsghdr->icflags = ICMSGHDRFLAG_TRANSACTION | ICMSGHDRFLAG_RESPONSE; - vmbus_sendpacket(channel, recv_buffer, buf_len, req_id, - VM_PKT_DATA_INBAND, 0); -} - -void hv_fcopy_onchannelcallback(void *context) -{ - struct vmbus_channel *channel = context; - u32 recvlen; - u64 requestid; - struct hv_fcopy_hdr *fcopy_msg; - struct icmsg_hdr *icmsghdr; - int fcopy_srv_version; - - if (fcopy_transaction.state > HVUTIL_READY) - return; - - if (vmbus_recvpacket(channel, recv_buffer, HV_HYP_PAGE_SIZE * 2, &recvlen, &requestid)) { - pr_err_ratelimited("Fcopy request received. Could not read into recv buf\n"); - return; - } - - if (!recvlen) - return; - - /* Ensure recvlen is big enough to read header data */ - if (recvlen < ICMSG_HDR) { - pr_err_ratelimited("Fcopy request received. Packet length too small: %d\n", - recvlen); - return; - } - - icmsghdr = (struct icmsg_hdr *)&recv_buffer[ - sizeof(struct vmbuspipe_hdr)]; - - if (icmsghdr->icmsgtype == ICMSGTYPE_NEGOTIATE) { - if (vmbus_prep_negotiate_resp(icmsghdr, - recv_buffer, recvlen, - fw_versions, FW_VER_COUNT, - fcopy_versions, FCOPY_VER_COUNT, - NULL, &fcopy_srv_version)) { - - pr_info("FCopy IC version %d.%d\n", - fcopy_srv_version >> 16, - fcopy_srv_version & 0xFFFF); - } - } else if (icmsghdr->icmsgtype == ICMSGTYPE_FCOPY) { - /* Ensure recvlen is big enough to contain hv_fcopy_hdr */ - if (recvlen < ICMSG_HDR + sizeof(struct hv_fcopy_hdr)) { - pr_err_ratelimited("Invalid Fcopy hdr. Packet length too small: %u\n", - recvlen); - return; - } - fcopy_msg = (struct hv_fcopy_hdr *)&recv_buffer[ICMSG_HDR]; - - /* - * Stash away this global state for completing the - * transaction; note transactions are serialized. - */ - - fcopy_transaction.recv_len = recvlen; - fcopy_transaction.recv_req_id = requestid; - fcopy_transaction.fcopy_msg = fcopy_msg; - - if (fcopy_transaction.state < HVUTIL_READY) { - /* Userspace is not registered yet */ - fcopy_respond_to_host(HV_E_FAIL); - return; - } - fcopy_transaction.state = HVUTIL_HOSTMSG_RECEIVED; - - /* - * Send the information to the user-level daemon. - */ - schedule_work(&fcopy_send_work); - schedule_delayed_work(&fcopy_timeout_work, - HV_UTIL_TIMEOUT * HZ); - return; - } else { - pr_err_ratelimited("Fcopy request received. Invalid msg type: %d\n", - icmsghdr->icmsgtype); - return; - } - icmsghdr->icflags = ICMSGHDRFLAG_TRANSACTION | ICMSGHDRFLAG_RESPONSE; - vmbus_sendpacket(channel, recv_buffer, recvlen, requestid, - VM_PKT_DATA_INBAND, 0); -} - -/* Callback when data is received from userspace */ -static int fcopy_on_msg(void *msg, int len) -{ - int *val = (int *)msg; - - if (len != sizeof(int)) - return -EINVAL; - - if (fcopy_transaction.state == HVUTIL_DEVICE_INIT) - return fcopy_handle_handshake(*val); - - if (fcopy_transaction.state != HVUTIL_USERSPACE_REQ) - return -EINVAL; - - /* - * Complete the transaction by forwarding the result - * to the host. But first, cancel the timeout. - */ - if (cancel_delayed_work_sync(&fcopy_timeout_work)) { - fcopy_transaction.state = HVUTIL_USERSPACE_RECV; - fcopy_respond_to_host(*val); - hv_poll_channel(fcopy_transaction.recv_channel, - fcopy_poll_wrapper); - } - - return 0; -} - -static void fcopy_on_reset(void) -{ - /* - * The daemon has exited; reset the state. - */ - fcopy_transaction.state = HVUTIL_DEVICE_INIT; - - if (cancel_delayed_work_sync(&fcopy_timeout_work)) - fcopy_respond_to_host(HV_E_FAIL); -} - -int hv_fcopy_init(struct hv_util_service *srv) -{ - recv_buffer = srv->recv_buffer; - fcopy_transaction.recv_channel = srv->channel; - fcopy_transaction.recv_channel->max_pkt_size = HV_HYP_PAGE_SIZE * 2; - - /* - * When this driver loads, the user level daemon that - * processes the host requests may not yet be running. - * Defer processing channel callbacks until the daemon - * has registered. - */ - fcopy_transaction.state = HVUTIL_DEVICE_INIT; - - hvt = hvutil_transport_init(fcopy_devname, 0, 0, - fcopy_on_msg, fcopy_on_reset); - if (!hvt) - return -EFAULT; - - return 0; -} - -static void hv_fcopy_cancel_work(void) -{ - cancel_delayed_work_sync(&fcopy_timeout_work); - cancel_work_sync(&fcopy_send_work); -} - -int hv_fcopy_pre_suspend(void) -{ - struct vmbus_channel *channel = fcopy_transaction.recv_channel; - struct hv_fcopy_hdr *fcopy_msg; - - /* - * Fake a CANCEL_FCOPY message for the user space daemon in case the - * daemon is in the middle of copying some file. It doesn't matter if - * there is already a message pending to be delivered to the user - * space since we force fcopy_transaction.state to be HVUTIL_READY, so - * the user space daemon's write() will fail with EINVAL (see - * fcopy_on_msg()), and the daemon will reset the device by closing - * and re-opening it. - */ - fcopy_msg = kzalloc(sizeof(*fcopy_msg), GFP_KERNEL); - if (!fcopy_msg) - return -ENOMEM; - - tasklet_disable(&channel->callback_event); - - fcopy_msg->operation = CANCEL_FCOPY; - - hv_fcopy_cancel_work(); - - /* We don't care about the return value. */ - hvutil_transport_send(hvt, fcopy_msg, sizeof(*fcopy_msg), NULL); - - kfree(fcopy_msg); - - fcopy_transaction.state = HVUTIL_READY; - - /* tasklet_enable() will be called in hv_fcopy_pre_resume(). */ - return 0; -} - -int hv_fcopy_pre_resume(void) -{ - struct vmbus_channel *channel = fcopy_transaction.recv_channel; - - tasklet_enable(&channel->callback_event); - - return 0; -} - -void hv_fcopy_deinit(void) -{ - fcopy_transaction.state = HVUTIL_DEVICE_DYING; - - hv_fcopy_cancel_work(); - - hvutil_transport_destroy(hvt); -} diff --git a/drivers/hv/hv_util.c b/drivers/hv/hv_util.c index 9c97c4065fe7..c4f525325790 100644 --- a/drivers/hv/hv_util.c +++ b/drivers/hv/hv_util.c @@ -154,14 +154,6 @@ static struct hv_util_service util_vss = { .util_deinit = hv_vss_deinit, }; -static struct hv_util_service util_fcopy = { - .util_cb = hv_fcopy_onchannelcallback, - .util_init = hv_fcopy_init, - .util_pre_suspend = hv_fcopy_pre_suspend, - .util_pre_resume = hv_fcopy_pre_resume, - .util_deinit = hv_fcopy_deinit, -}; - static void perform_shutdown(struct work_struct *dummy) { orderly_poweroff(true); @@ -700,10 +692,6 @@ static const struct hv_vmbus_device_id id_table[] = { { HV_VSS_GUID, .driver_data = (unsigned long)&util_vss }, - /* File copy GUID */ - { HV_FCOPY_GUID, - .driver_data = (unsigned long)&util_fcopy - }, { }, }; diff --git a/tools/hv/hv_fcopy_daemon.c b/tools/hv/hv_fcopy_daemon.c deleted file mode 100644 index 16d629b22c25..000000000000 --- a/tools/hv/hv_fcopy_daemon.c +++ /dev/null @@ -1,266 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * An implementation of host to guest copy functionality for Linux. - * - * Copyright (C) 2014, Microsoft, Inc. - * - * Author : K. Y. Srinivasan - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static int target_fd; -static char target_fname[PATH_MAX]; -static unsigned long long filesize; - -static int hv_start_fcopy(struct hv_start_fcopy *smsg) -{ - int error = HV_E_FAIL; - char *q, *p; - - filesize = 0; - p = (char *)smsg->path_name; - snprintf(target_fname, sizeof(target_fname), "%s/%s", - (char *)smsg->path_name, (char *)smsg->file_name); - - syslog(LOG_INFO, "Target file name: %s", target_fname); - /* - * Check to see if the path is already in place; if not, - * create if required. - */ - while ((q = strchr(p, '/')) != NULL) { - if (q == p) { - p++; - continue; - } - *q = '\0'; - if (access((char *)smsg->path_name, F_OK)) { - if (smsg->copy_flags & CREATE_PATH) { - if (mkdir((char *)smsg->path_name, 0755)) { - syslog(LOG_ERR, "Failed to create %s", - (char *)smsg->path_name); - goto done; - } - } else { - syslog(LOG_ERR, "Invalid path: %s", - (char *)smsg->path_name); - goto done; - } - } - p = q + 1; - *q = '/'; - } - - if (!access(target_fname, F_OK)) { - syslog(LOG_INFO, "File: %s exists", target_fname); - if (!(smsg->copy_flags & OVER_WRITE)) { - error = HV_ERROR_ALREADY_EXISTS; - goto done; - } - } - - target_fd = open(target_fname, - O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC, 0744); - if (target_fd == -1) { - syslog(LOG_INFO, "Open Failed: %s", strerror(errno)); - goto done; - } - - error = 0; -done: - if (error) - target_fname[0] = '\0'; - return error; -} - -static int hv_copy_data(struct hv_do_fcopy *cpmsg) -{ - ssize_t bytes_written; - int ret = 0; - - bytes_written = pwrite(target_fd, cpmsg->data, cpmsg->size, - cpmsg->offset); - - filesize += cpmsg->size; - if (bytes_written != cpmsg->size) { - switch (errno) { - case ENOSPC: - ret = HV_ERROR_DISK_FULL; - break; - default: - ret = HV_E_FAIL; - break; - } - syslog(LOG_ERR, "pwrite failed to write %llu bytes: %ld (%s)", - filesize, (long)bytes_written, strerror(errno)); - } - - return ret; -} - -/* - * Reset target_fname to "" in the two below functions for hibernation: if - * the fcopy operation is aborted by hibernation, the daemon should remove the - * partially-copied file; to achieve this, the hv_utils driver always fakes a - * CANCEL_FCOPY message upon suspend, and later when the VM resumes back, - * the daemon calls hv_copy_cancel() to remove the file; if a file is copied - * successfully before suspend, hv_copy_finished() must reset target_fname to - * avoid that the file can be incorrectly removed upon resume, since the faked - * CANCEL_FCOPY message is spurious in this case. - */ -static int hv_copy_finished(void) -{ - close(target_fd); - target_fname[0] = '\0'; - return 0; -} -static int hv_copy_cancel(void) -{ - close(target_fd); - if (strlen(target_fname) > 0) { - unlink(target_fname); - target_fname[0] = '\0'; - } - return 0; - -} - -void print_usage(char *argv[]) -{ - fprintf(stderr, "Usage: %s [options]\n" - "Options are:\n" - " -n, --no-daemon stay in foreground, don't daemonize\n" - " -h, --help print this help\n", argv[0]); -} - -int main(int argc, char *argv[]) -{ - int fcopy_fd = -1; - int error; - int daemonize = 1, long_index = 0, opt; - int version = FCOPY_CURRENT_VERSION; - union { - struct hv_fcopy_hdr hdr; - struct hv_start_fcopy start; - struct hv_do_fcopy copy; - __u32 kernel_modver; - } buffer = { }; - int in_handshake; - - static struct option long_options[] = { - {"help", no_argument, 0, 'h' }, - {"no-daemon", no_argument, 0, 'n' }, - {0, 0, 0, 0 } - }; - - while ((opt = getopt_long(argc, argv, "hn", long_options, - &long_index)) != -1) { - switch (opt) { - case 'n': - daemonize = 0; - break; - case 'h': - default: - print_usage(argv); - exit(EXIT_FAILURE); - } - } - - if (daemonize && daemon(1, 0)) { - syslog(LOG_ERR, "daemon() failed; error: %s", strerror(errno)); - exit(EXIT_FAILURE); - } - - openlog("HV_FCOPY", 0, LOG_USER); - syslog(LOG_INFO, "starting; pid is:%d", getpid()); - -reopen_fcopy_fd: - if (fcopy_fd != -1) - close(fcopy_fd); - /* Remove any possible partially-copied file on error */ - hv_copy_cancel(); - in_handshake = 1; - fcopy_fd = open("/dev/vmbus/hv_fcopy", O_RDWR); - - if (fcopy_fd < 0) { - syslog(LOG_ERR, "open /dev/vmbus/hv_fcopy failed; error: %d %s", - errno, strerror(errno)); - exit(EXIT_FAILURE); - } - - /* - * Register with the kernel. - */ - if ((write(fcopy_fd, &version, sizeof(int))) != sizeof(int)) { - syslog(LOG_ERR, "Registration failed: %s", strerror(errno)); - exit(EXIT_FAILURE); - } - - while (1) { - /* - * In this loop we process fcopy messages after the - * handshake is complete. - */ - ssize_t len; - - len = pread(fcopy_fd, &buffer, sizeof(buffer), 0); - if (len < 0) { - syslog(LOG_ERR, "pread failed: %s", strerror(errno)); - goto reopen_fcopy_fd; - } - - if (in_handshake) { - if (len != sizeof(buffer.kernel_modver)) { - syslog(LOG_ERR, "invalid version negotiation"); - exit(EXIT_FAILURE); - } - in_handshake = 0; - syslog(LOG_INFO, "kernel module version: %u", - buffer.kernel_modver); - continue; - } - - switch (buffer.hdr.operation) { - case START_FILE_COPY: - error = hv_start_fcopy(&buffer.start); - break; - case WRITE_TO_FILE: - error = hv_copy_data(&buffer.copy); - break; - case COMPLETE_FCOPY: - error = hv_copy_finished(); - break; - case CANCEL_FCOPY: - error = hv_copy_cancel(); - break; - - default: - error = HV_E_FAIL; - syslog(LOG_ERR, "Unknown operation: %d", - buffer.hdr.operation); - - } - - /* - * pwrite() may return an error due to the faked CANCEL_FCOPY - * message upon hibernation. Ignore the error by resetting the - * dev file, i.e. closing and re-opening it. - */ - if (pwrite(fcopy_fd, &error, sizeof(int), 0) != sizeof(int)) { - syslog(LOG_ERR, "pwrite failed: %s", strerror(errno)); - goto reopen_fcopy_fd; - } - } -} -- cgit v1.2.3-59-g8ed1b From 76457f9a11dd1521efeb553526d350100e1ef422 Mon Sep 17 00:00:00 2001 From: Saurabh Sengar Date: Sat, 30 Mar 2024 01:52:03 -0700 Subject: uio_hv_generic: Remove use of PAGE_SIZE Remove use of PAGE_SIZE for device ring buffer size calculation, as there is no dependency on device ring buffer size for linux kernel's PAGE_SIZE. Use the absolute value of 2 MB instead. Signed-off-by: Saurabh Sengar Reviewed-by: Long Li Link: https://lore.kernel.org/r/1711788723-8593-8-git-send-email-ssengar@linux.microsoft.com Signed-off-by: Greg Kroah-Hartman --- drivers/uio/uio_hv_generic.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/uio/uio_hv_generic.c b/drivers/uio/uio_hv_generic.c index 289611c7dfd7..015ddbddd6e1 100644 --- a/drivers/uio/uio_hv_generic.c +++ b/drivers/uio/uio_hv_generic.c @@ -36,7 +36,6 @@ #define DRIVER_AUTHOR "Stephen Hemminger " #define DRIVER_DESC "Generic UIO driver for VMBus devices" -#define HV_RING_SIZE 512 /* pages */ #define SEND_BUFFER_SIZE (16 * 1024 * 1024) #define RECV_BUFFER_SIZE (31 * 1024 * 1024) @@ -146,7 +145,7 @@ static const struct bin_attribute ring_buffer_bin_attr = { .name = "ring", .mode = 0600, }, - .size = 2 * HV_RING_SIZE * PAGE_SIZE, + .size = 2 * SZ_2M, .mmap = hv_uio_ring_mmap, }; @@ -156,7 +155,7 @@ hv_uio_new_channel(struct vmbus_channel *new_sc) { struct hv_device *hv_dev = new_sc->primary_channel->device_obj; struct device *device = &hv_dev->device; - const size_t ring_bytes = HV_RING_SIZE * PAGE_SIZE; + const size_t ring_bytes = SZ_2M; int ret; /* Create host communication ring */ @@ -244,7 +243,7 @@ hv_uio_probe(struct hv_device *dev, size_t ring_size = hv_dev_ring_size(channel); if (!ring_size) - ring_size = HV_RING_SIZE * PAGE_SIZE; + ring_size = SZ_2M; pdata = devm_kzalloc(&dev->device, sizeof(*pdata), GFP_KERNEL); if (!pdata) -- cgit v1.2.3-59-g8ed1b From d3eb521378a685150396687c3c7a10a877ed065a Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 8 Mar 2024 13:18:48 +0000 Subject: comedi: remove unused helper function dma_chain_flag_bits The helper function dma_chain_flag_bits is not being called from anywhere, it is redundant and can be removed. Cleans up clang scan build warning: drivers/comedi/drivers/cb_pcidas64.c:377:28: warning: unused function 'dma_chain_flag_bits' [-Wunused-function] Signed-off-by: Colin Ian King Reviewed-by: Ian Abbott Link: https://lore.kernel.org/r/20240308131848.2057693-1-colin.i.king@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/comedi/drivers/cb_pcidas64.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/comedi/drivers/cb_pcidas64.c b/drivers/comedi/drivers/cb_pcidas64.c index ff19fc3859e4..d398c6df9482 100644 --- a/drivers/comedi/drivers/cb_pcidas64.c +++ b/drivers/comedi/drivers/cb_pcidas64.c @@ -374,11 +374,6 @@ static inline u16 pipe_full_bits(u16 hw_status_bits) return (hw_status_bits >> 10) & 0x3; }; -static inline unsigned int dma_chain_flag_bits(u16 prepost_bits) -{ - return (prepost_bits >> 6) & 0x3; -} - static inline unsigned int adc_upper_read_ptr_code(u16 prepost_bits) { return (prepost_bits >> 12) & 0x3; -- cgit v1.2.3-59-g8ed1b From 043327875298030095f9c5d04bd41def28275175 Mon Sep 17 00:00:00 2001 From: Thomas Weißschuh Date: Wed, 13 Mar 2024 19:19:30 +0100 Subject: misc/pvpanic: use bit macros MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The macros are easier to read. Suggested-by: Greg Kroah-Hartman Link: https://lore.kernel.org/lkml/2023110407-unselect-uptight-b96d@gregkh/ Signed-off-by: Thomas Weißschuh Link: https://lore.kernel.org/r/20240313-pvpanic-shutdown-header-v1-1-7f1970d66366@weissschuh.net Signed-off-by: Greg Kroah-Hartman --- include/uapi/misc/pvpanic.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/include/uapi/misc/pvpanic.h b/include/uapi/misc/pvpanic.h index 54b7485390d3..9ea6a965ca7a 100644 --- a/include/uapi/misc/pvpanic.h +++ b/include/uapi/misc/pvpanic.h @@ -3,7 +3,9 @@ #ifndef __PVPANIC_H__ #define __PVPANIC_H__ -#define PVPANIC_PANICKED (1 << 0) -#define PVPANIC_CRASH_LOADED (1 << 1) +#include + +#define PVPANIC_PANICKED _BITUL(0) +#define PVPANIC_CRASH_LOADED _BITUL(1) #endif /* __PVPANIC_H__ */ -- cgit v1.2.3-59-g8ed1b From ad76f3e8f57cef368fa98f2d4d8902ad66481a3e Mon Sep 17 00:00:00 2001 From: Thomas Weißschuh Date: Wed, 13 Mar 2024 19:19:31 +0100 Subject: misc/pvpanic: add shutdown event definition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Shutdown requests are normally hardware dependent. By extending pvpanic to also handle shutdown requests, guests can submit such requests with an easily implementable and cross-platform mechanism. The event was added to the specification in qemu commit 73279cecca03 ("docs/specs/pvpanic: document shutdown event"). Signed-off-by: Thomas Weißschuh Acked-by: Arnd Bergmann Link: https://lore.kernel.org/r/20240313-pvpanic-shutdown-header-v1-2-7f1970d66366@weissschuh.net Signed-off-by: Greg Kroah-Hartman --- include/uapi/misc/pvpanic.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/uapi/misc/pvpanic.h b/include/uapi/misc/pvpanic.h index 9ea6a965ca7a..3f1745cd1b52 100644 --- a/include/uapi/misc/pvpanic.h +++ b/include/uapi/misc/pvpanic.h @@ -7,5 +7,6 @@ #define PVPANIC_PANICKED _BITUL(0) #define PVPANIC_CRASH_LOADED _BITUL(1) +#define PVPANIC_SHUTDOWN _BITUL(2) #endif /* __PVPANIC_H__ */ -- cgit v1.2.3-59-g8ed1b From 115ee55351c1d3fee16515f01133144205ddb29b Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Fri, 15 Mar 2024 17:35:40 -0400 Subject: misc: ds1682: Add NVMEM support Add NVMEM support for the internal EEPROM. Signed-off-by: Sean Anderson Link: https://lore.kernel.org/r/20240315213540.1682964-1-sean.anderson@linux.dev Signed-off-by: Greg Kroah-Hartman --- drivers/misc/ds1682.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/drivers/misc/ds1682.c b/drivers/misc/ds1682.c index 21fc5bc85c5c..5f8dcd0e3848 100644 --- a/drivers/misc/ds1682.c +++ b/drivers/misc/ds1682.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -197,11 +198,43 @@ static const struct bin_attribute ds1682_eeprom_attr = { .write = ds1682_eeprom_write, }; +static int ds1682_nvmem_read(void *priv, unsigned int offset, void *val, + size_t bytes) +{ + struct i2c_client *client = priv; + int ret; + + ret = i2c_smbus_read_i2c_block_data(client, DS1682_REG_EEPROM + offset, + bytes, val); + return ret < 0 ? ret : 0; +} + +static int ds1682_nvmem_write(void *priv, unsigned int offset, void *val, + size_t bytes) +{ + struct i2c_client *client = priv; + int ret; + + ret = i2c_smbus_write_i2c_block_data(client, DS1682_REG_EEPROM + offset, + bytes, val); + return ret < 0 ? ret : 0; +} + /* * Called when a ds1682 device is matched with this driver */ static int ds1682_probe(struct i2c_client *client) { + struct nvmem_config config = { + .dev = &client->dev, + .owner = THIS_MODULE, + .type = NVMEM_TYPE_EEPROM, + .reg_read = ds1682_nvmem_read, + .reg_write = ds1682_nvmem_write, + .size = DS1682_EEPROM_SIZE, + .priv = client, + }; + struct nvmem_device *nvmem; int rc; if (!i2c_check_functionality(client->adapter, @@ -211,6 +244,10 @@ static int ds1682_probe(struct i2c_client *client) goto exit; } + nvmem = devm_nvmem_register(&client->dev, &config); + if (IS_ENABLED(CONFIG_NVMEM) && IS_ERR(nvmem)) + return PTR_ERR(nvmem); + rc = sysfs_create_group(&client->dev.kobj, &ds1682_group); if (rc) goto exit; -- cgit v1.2.3-59-g8ed1b From 355f6a292fa2443f0c4d2017b5cb0f67fcb01ddb Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Mon, 25 Mar 2024 14:01:23 -0600 Subject: mei: Avoid a bunch of -Wflex-array-member-not-at-end warnings -Wflex-array-member-not-at-end is coming in GCC-14, and we are getting ready to enable it globally. After commit 40292383640a ("mei: revamp mei extension header structure layout.") it seems that flexible-array member `data` in `struct mei_ext_hdr` is no longer needed. So, remove it and, with that, fix 45 of the following -Wflex-array-member-not-at-end warnings[1] in drivers/misc/mei/: drivers/misc/mei/hw.h:280:28: warning: structure containing a flexible array member is not at the end of another structure [-Wflex-array-member-not-at-end] Link: https://gist.github.com/GustavoARSilva/62dcc235555a6b29b506269edb83da0b [1] Link: https://github.com/KSPP/linux/issues/202 Signed-off-by: Gustavo A. R. Silva Link: https://lore.kernel.org/r/ZgHYE2s5kBGlv1cw@neat Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/hw.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/misc/mei/hw.h b/drivers/misc/mei/hw.h index eb800a07a84b..2e9cf6f4efb6 100644 --- a/drivers/misc/mei/hw.h +++ b/drivers/misc/mei/hw.h @@ -247,12 +247,10 @@ enum mei_ext_hdr_type { * struct mei_ext_hdr - extend header descriptor (TLV) * @type: enum mei_ext_hdr_type * @length: length excluding descriptor - * @data: the extended header payload */ struct mei_ext_hdr { u8 type; u8 length; - u8 data[]; } __packed; /** -- cgit v1.2.3-59-g8ed1b From 5f8fcfc3e509d8a1d458a09baeacc53595607d4d Mon Sep 17 00:00:00 2001 From: Atin Bainada Date: Wed, 27 Mar 2024 11:19:45 +0000 Subject: misc: ti-st: st_kim: remove unnecessary (void*) conversions No need to type cast (void*) pointer variables. Signed-off-by: Atin Bainada Link: https://lore.kernel.org/r/20240327111914.38104-1-atin4@proton.me Signed-off-by: Greg Kroah-Hartman --- drivers/misc/ti-st/st_kim.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/misc/ti-st/st_kim.c b/drivers/misc/ti-st/st_kim.c index 47ebe80bf849..c4f963cf96f2 100644 --- a/drivers/misc/ti-st/st_kim.c +++ b/drivers/misc/ti-st/st_kim.c @@ -563,7 +563,7 @@ long st_kim_stop(void *kim_data) static int version_show(struct seq_file *s, void *unused) { - struct kim_data_s *kim_gdata = (struct kim_data_s *)s->private; + struct kim_data_s *kim_gdata = s->private; seq_printf(s, "%04X %d.%d.%d\n", kim_gdata->version.full, kim_gdata->version.chip, kim_gdata->version.maj_ver, kim_gdata->version.min_ver); @@ -572,7 +572,7 @@ static int version_show(struct seq_file *s, void *unused) static int list_show(struct seq_file *s, void *unused) { - struct kim_data_s *kim_gdata = (struct kim_data_s *)s->private; + struct kim_data_s *kim_gdata = s->private; kim_st_list_protocols(kim_gdata->core_data, s); return 0; } -- cgit v1.2.3-59-g8ed1b From 1d6b84d29779f84f3108acc90681c372a2f70a24 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 5 Apr 2024 16:42:57 +0200 Subject: parport: mfc3: avoid empty-body warning on m68k builds, the mfc3 driver causes a warning about an empty if() block: drivers/parport/parport_mfc3.c: In function 'control_pc_to_mfc3': drivers/parport/parport_mfc3.c:106:37: warning: suggest braces around empty body in an 'if' statement [-Wempty-body] Remove it in favor of a simpler comment. Acked-by: Sudip Mukherjee Link: https://lore.kernel.org/lkml/20230727122448.2479942-1-arnd@kernel.org/ Signed-off-by: Arnd Bergmann Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20240405144304.1223160-1-arnd@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/parport/parport_mfc3.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/parport/parport_mfc3.c b/drivers/parport/parport_mfc3.c index f4d0da741e85..bb1817218d7b 100644 --- a/drivers/parport/parport_mfc3.c +++ b/drivers/parport/parport_mfc3.c @@ -102,8 +102,7 @@ static unsigned char control_pc_to_mfc3(unsigned char control) ret |= 128; if (control & PARPORT_CONTROL_AUTOFD) /* AUTOLF */ ret &= ~64; - if (control & PARPORT_CONTROL_STROBE) /* Strobe */ - /* Handled directly by hardware */; + /* PARPORT_CONTROL_STROBE handled directly by hardware */ return ret; } -- cgit v1.2.3-59-g8ed1b From f0a816fb12dadd21326a7c0e54e3253f69d895d5 Mon Sep 17 00:00:00 2001 From: Niklas Schnelle Date: Thu, 4 Apr 2024 13:49:17 +0200 Subject: /dev/port: don't compile file operations without CONFIG_DEVPORT In the future inb() and friends will not be available when compiling with CONFIG_HAS_IOPORT=n so we must only try to access them here if CONFIG_DEVPORT is set which depends on HAS_IOPORT. Co-developed-by: Arnd Bergmann Signed-off-by: Arnd Bergmann Signed-off-by: Niklas Schnelle Link: https://lore.kernel.org/r/20240404114917.3627747-2-schnelle@linux.ibm.com Signed-off-by: Greg Kroah-Hartman --- drivers/char/mem.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 3c6670cf905f..7904e2bb6427 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -383,6 +383,7 @@ static int mmap_mem(struct file *file, struct vm_area_struct *vma) return 0; } +#ifdef CONFIG_DEVPORT static ssize_t read_port(struct file *file, char __user *buf, size_t count, loff_t *ppos) { @@ -424,6 +425,7 @@ static ssize_t write_port(struct file *file, const char __user *buf, *ppos = i; return tmp-buf; } +#endif static ssize_t read_null(struct file *file, char __user *buf, size_t count, loff_t *ppos) @@ -653,12 +655,14 @@ static const struct file_operations null_fops = { .uring_cmd = uring_cmd_null, }; -static const struct file_operations __maybe_unused port_fops = { +#ifdef CONFIG_DEVPORT +static const struct file_operations port_fops = { .llseek = memory_lseek, .read = read_port, .write = write_port, .open = open_port, }; +#endif static const struct file_operations zero_fops = { .llseek = zero_lseek, -- cgit v1.2.3-59-g8ed1b From 2193014f79472658b8b1efa12a9adaae07f8b0e0 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Wed, 10 Apr 2024 14:47:07 +0200 Subject: powerpc/powernv: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20240410124707.194228-2-u.kleine-koenig@pengutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/char/powernv-op-panel.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/char/powernv-op-panel.c b/drivers/char/powernv-op-panel.c index 3c99696b145e..f2cff1a6fed5 100644 --- a/drivers/char/powernv-op-panel.c +++ b/drivers/char/powernv-op-panel.c @@ -195,12 +195,11 @@ free_oppanel_data: return rc; } -static int oppanel_remove(struct platform_device *pdev) +static void oppanel_remove(struct platform_device *pdev) { misc_deregister(&oppanel_dev); kfree(oppanel_lines); kfree(oppanel_data); - return 0; } static const struct of_device_id oppanel_match[] = { @@ -214,7 +213,7 @@ static struct platform_driver oppanel_driver = { .of_match_table = oppanel_match, }, .probe = oppanel_probe, - .remove = oppanel_remove, + .remove_new = oppanel_remove, }; module_platform_driver(oppanel_driver); -- cgit v1.2.3-59-g8ed1b From 26f0d3b11aff6bf7ffd39809171865871aadb992 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Wed, 10 Apr 2024 14:48:27 +0200 Subject: sonypi: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20240410124827.194351-2-u.kleine-koenig@pengutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/char/sonypi.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c index 22d249333f53..bb5115b1736a 100644 --- a/drivers/char/sonypi.c +++ b/drivers/char/sonypi.c @@ -1408,7 +1408,7 @@ static int sonypi_probe(struct platform_device *dev) return error; } -static int sonypi_remove(struct platform_device *dev) +static void sonypi_remove(struct platform_device *dev) { sonypi_disable(); @@ -1432,8 +1432,6 @@ static int sonypi_remove(struct platform_device *dev) } kfifo_free(&sonypi_device.fifo); - - return 0; } #ifdef CONFIG_PM_SLEEP @@ -1470,7 +1468,7 @@ static struct platform_driver sonypi_driver = { .pm = SONYPI_PM, }, .probe = sonypi_probe, - .remove = sonypi_remove, + .remove_new = sonypi_remove, .shutdown = sonypi_shutdown, }; -- cgit v1.2.3-59-g8ed1b From 25b9cadb1ee3434b92de9096d4a2ae91820146bf Mon Sep 17 00:00:00 2001 From: Elizabeth Figura Date: Thu, 28 Mar 2024 19:05:52 -0500 Subject: ntsync: Introduce the ntsync driver and character device. ntsync uses a misc device as the simplest and least intrusive uAPI interface. Each file description on the device represents an isolated NT instance, intended to correspond to a single NT virtual machine. Signed-off-by: Elizabeth Figura Link: https://lore.kernel.org/r/20240329000621.148791-2-zfigura@codeweavers.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/Kconfig | 11 +++++++++++ drivers/misc/Makefile | 1 + drivers/misc/ntsync.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 64 insertions(+) create mode 100644 drivers/misc/ntsync.c diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 4fb291f0bf7c..801ed229ed7d 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -506,6 +506,17 @@ config OPEN_DICE If unsure, say N. +config NTSYNC + tristate "NT synchronization primitive emulation" + help + This module provides kernel support for emulation of Windows NT + synchronization primitives. It is not a hardware driver. + + To compile this driver as a module, choose M here: the + module will be called ntsync. + + If unsure, say N. + config VCPU_STALL_DETECTOR tristate "Guest vCPU stall detector" depends on OF && HAS_IOMEM diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index ea6ea5bbbc9c..153a3f4837e8 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -59,6 +59,7 @@ obj-$(CONFIG_PVPANIC) += pvpanic/ obj-$(CONFIG_UACCE) += uacce/ obj-$(CONFIG_XILINX_SDFEC) += xilinx_sdfec.o obj-$(CONFIG_HISI_HIKEY_USB) += hisi_hikey_usb.o +obj-$(CONFIG_NTSYNC) += ntsync.o obj-$(CONFIG_HI6421V600_IRQ) += hi6421v600-irq.o obj-$(CONFIG_OPEN_DICE) += open-dice.o obj-$(CONFIG_GP_PCI1XXXX) += mchp_pci1xxxx/ diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c new file mode 100644 index 000000000000..bd76e653d83e --- /dev/null +++ b/drivers/misc/ntsync.c @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * ntsync.c - Kernel driver for NT synchronization primitives + * + * Copyright (C) 2024 Elizabeth Figura + */ + +#include +#include +#include + +#define NTSYNC_NAME "ntsync" + +static int ntsync_char_open(struct inode *inode, struct file *file) +{ + return nonseekable_open(inode, file); +} + +static int ntsync_char_release(struct inode *inode, struct file *file) +{ + return 0; +} + +static long ntsync_char_ioctl(struct file *file, unsigned int cmd, + unsigned long parm) +{ + switch (cmd) { + default: + return -ENOIOCTLCMD; + } +} + +static const struct file_operations ntsync_fops = { + .owner = THIS_MODULE, + .open = ntsync_char_open, + .release = ntsync_char_release, + .unlocked_ioctl = ntsync_char_ioctl, + .compat_ioctl = compat_ptr_ioctl, + .llseek = no_llseek, +}; + +static struct miscdevice ntsync_misc = { + .minor = MISC_DYNAMIC_MINOR, + .name = NTSYNC_NAME, + .fops = &ntsync_fops, +}; + +module_misc_device(ntsync_misc); + +MODULE_AUTHOR("Elizabeth Figura "); +MODULE_DESCRIPTION("Kernel driver for NT synchronization primitives"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3-59-g8ed1b From b46271ec40a05580d55f917c9ac52cb93553160a Mon Sep 17 00:00:00 2001 From: Elizabeth Figura Date: Thu, 28 Mar 2024 19:05:53 -0500 Subject: ntsync: Introduce NTSYNC_IOC_CREATE_SEM. This corresponds to the NT syscall NtCreateSemaphore(). Semaphores are one of three types of object to be implemented in this driver, the others being mutexes and events. An NT semaphore contains a 32-bit counter, and is signaled and can be acquired when the counter is nonzero. The counter has a maximum value which is specified at creation time. The initial value of the semaphore is also specified at creation time. There are no restrictions on the maximum and initial value. Each object is exposed as an file, to which any number of fds may be opened. When all fds are closed, the object is deleted. Objects hold a pointer to the ntsync_device that created them. The device's reference count is driven by struct file. Signed-off-by: Elizabeth Figura Link: https://lore.kernel.org/r/20240329000621.148791-3-zfigura@codeweavers.com Signed-off-by: Greg Kroah-Hartman --- Documentation/userspace-api/ioctl/ioctl-number.rst | 2 + drivers/misc/ntsync.c | 131 +++++++++++++++++++++ include/uapi/linux/ntsync.h | 21 ++++ 3 files changed, 154 insertions(+) create mode 100644 include/uapi/linux/ntsync.h diff --git a/Documentation/userspace-api/ioctl/ioctl-number.rst b/Documentation/userspace-api/ioctl/ioctl-number.rst index c472423412bf..a141e8e65c5d 100644 --- a/Documentation/userspace-api/ioctl/ioctl-number.rst +++ b/Documentation/userspace-api/ioctl/ioctl-number.rst @@ -174,6 +174,8 @@ Code Seq# Include File Comments 'M' 00-0F drivers/video/fsl-diu-fb.h conflict! 'N' 00-1F drivers/usb/scanner.h 'N' 40-7F drivers/block/nvme.c +'N' 80-8F uapi/linux/ntsync.h NT synchronization primitives + 'O' 00-06 mtd/ubi-user.h UBI 'P' all linux/soundcard.h conflict! 'P' 60-6F sound/sscape_ioctl.h conflict! diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c index bd76e653d83e..20158ec148bc 100644 --- a/drivers/misc/ntsync.c +++ b/drivers/misc/ntsync.c @@ -5,26 +5,157 @@ * Copyright (C) 2024 Elizabeth Figura */ +#include +#include #include #include #include +#include +#include #define NTSYNC_NAME "ntsync" +enum ntsync_type { + NTSYNC_TYPE_SEM, +}; + +/* + * Individual synchronization primitives are represented by + * struct ntsync_obj, and each primitive is backed by a file. + * + * The whole namespace is represented by a struct ntsync_device also + * backed by a file. + * + * Both rely on struct file for reference counting. Individual + * ntsync_obj objects take a reference to the device when created. + */ + +struct ntsync_obj { + enum ntsync_type type; + + union { + struct { + __u32 count; + __u32 max; + } sem; + } u; + + struct file *file; + struct ntsync_device *dev; +}; + +struct ntsync_device { + struct file *file; +}; + +static int ntsync_obj_release(struct inode *inode, struct file *file) +{ + struct ntsync_obj *obj = file->private_data; + + fput(obj->dev->file); + kfree(obj); + + return 0; +} + +static const struct file_operations ntsync_obj_fops = { + .owner = THIS_MODULE, + .release = ntsync_obj_release, + .llseek = no_llseek, +}; + +static struct ntsync_obj *ntsync_alloc_obj(struct ntsync_device *dev, + enum ntsync_type type) +{ + struct ntsync_obj *obj; + + obj = kzalloc(sizeof(*obj), GFP_KERNEL); + if (!obj) + return NULL; + obj->type = type; + obj->dev = dev; + get_file(dev->file); + + return obj; +} + +static int ntsync_obj_get_fd(struct ntsync_obj *obj) +{ + struct file *file; + int fd; + + fd = get_unused_fd_flags(O_CLOEXEC); + if (fd < 0) + return fd; + file = anon_inode_getfile("ntsync", &ntsync_obj_fops, obj, O_RDWR); + if (IS_ERR(file)) { + put_unused_fd(fd); + return PTR_ERR(file); + } + obj->file = file; + fd_install(fd, file); + + return fd; +} + +static int ntsync_create_sem(struct ntsync_device *dev, void __user *argp) +{ + struct ntsync_sem_args __user *user_args = argp; + struct ntsync_sem_args args; + struct ntsync_obj *sem; + int fd; + + if (copy_from_user(&args, argp, sizeof(args))) + return -EFAULT; + + if (args.count > args.max) + return -EINVAL; + + sem = ntsync_alloc_obj(dev, NTSYNC_TYPE_SEM); + if (!sem) + return -ENOMEM; + sem->u.sem.count = args.count; + sem->u.sem.max = args.max; + fd = ntsync_obj_get_fd(sem); + if (fd < 0) { + kfree(sem); + return fd; + } + + return put_user(fd, &user_args->sem); +} + static int ntsync_char_open(struct inode *inode, struct file *file) { + struct ntsync_device *dev; + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; + + file->private_data = dev; + dev->file = file; return nonseekable_open(inode, file); } static int ntsync_char_release(struct inode *inode, struct file *file) { + struct ntsync_device *dev = file->private_data; + + kfree(dev); + return 0; } static long ntsync_char_ioctl(struct file *file, unsigned int cmd, unsigned long parm) { + struct ntsync_device *dev = file->private_data; + void __user *argp = (void __user *)parm; + switch (cmd) { + case NTSYNC_IOC_CREATE_SEM: + return ntsync_create_sem(dev, argp); default: return -ENOIOCTLCMD; } diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h new file mode 100644 index 000000000000..6a4867a6c97b --- /dev/null +++ b/include/uapi/linux/ntsync.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* + * Kernel support for NT synchronization primitive emulation + * + * Copyright (C) 2021-2022 Elizabeth Figura + */ + +#ifndef __LINUX_NTSYNC_H +#define __LINUX_NTSYNC_H + +#include + +struct ntsync_sem_args { + __u32 sem; + __u32 count; + __u32 max; +}; + +#define NTSYNC_IOC_CREATE_SEM _IOWR('N', 0x80, struct ntsync_sem_args) + +#endif -- cgit v1.2.3-59-g8ed1b From dc806bd48abc1b8a4ae72709a37e65db42a32048 Mon Sep 17 00:00:00 2001 From: Elizabeth Figura Date: Thu, 28 Mar 2024 19:05:54 -0500 Subject: ntsync: Introduce NTSYNC_IOC_SEM_POST. This corresponds to the NT syscall NtReleaseSemaphore(). This increases the semaphore's internal counter by the given value, and returns the previous value. If the counter would overflow the defined maximum, the function instead fails and returns -EOVERFLOW. Signed-off-by: Elizabeth Figura Link: https://lore.kernel.org/r/20240329000621.148791-4-zfigura@codeweavers.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/ntsync.c | 72 +++++++++++++++++++++++++++++++++++++++++++-- include/uapi/linux/ntsync.h | 2 ++ 2 files changed, 71 insertions(+), 3 deletions(-) diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c index 20158ec148bc..3c2f743c58b0 100644 --- a/drivers/misc/ntsync.c +++ b/drivers/misc/ntsync.c @@ -10,7 +10,9 @@ #include #include #include +#include #include +#include #include #define NTSYNC_NAME "ntsync" @@ -31,23 +33,70 @@ enum ntsync_type { */ struct ntsync_obj { + spinlock_t lock; + enum ntsync_type type; + struct file *file; + struct ntsync_device *dev; + + /* The following fields are protected by the object lock. */ union { struct { __u32 count; __u32 max; } sem; } u; - - struct file *file; - struct ntsync_device *dev; }; struct ntsync_device { struct file *file; }; +/* + * Actually change the semaphore state, returning -EOVERFLOW if it is made + * invalid. + */ +static int post_sem_state(struct ntsync_obj *sem, __u32 count) +{ + __u32 sum; + + lockdep_assert_held(&sem->lock); + + if (check_add_overflow(sem->u.sem.count, count, &sum) || + sum > sem->u.sem.max) + return -EOVERFLOW; + + sem->u.sem.count = sum; + return 0; +} + +static int ntsync_sem_post(struct ntsync_obj *sem, void __user *argp) +{ + __u32 __user *user_args = argp; + __u32 prev_count; + __u32 args; + int ret; + + if (copy_from_user(&args, argp, sizeof(args))) + return -EFAULT; + + if (sem->type != NTSYNC_TYPE_SEM) + return -EINVAL; + + spin_lock(&sem->lock); + + prev_count = sem->u.sem.count; + ret = post_sem_state(sem, args); + + spin_unlock(&sem->lock); + + if (!ret && put_user(prev_count, user_args)) + ret = -EFAULT; + + return ret; +} + static int ntsync_obj_release(struct inode *inode, struct file *file) { struct ntsync_obj *obj = file->private_data; @@ -58,9 +107,25 @@ static int ntsync_obj_release(struct inode *inode, struct file *file) return 0; } +static long ntsync_obj_ioctl(struct file *file, unsigned int cmd, + unsigned long parm) +{ + struct ntsync_obj *obj = file->private_data; + void __user *argp = (void __user *)parm; + + switch (cmd) { + case NTSYNC_IOC_SEM_POST: + return ntsync_sem_post(obj, argp); + default: + return -ENOIOCTLCMD; + } +} + static const struct file_operations ntsync_obj_fops = { .owner = THIS_MODULE, .release = ntsync_obj_release, + .unlocked_ioctl = ntsync_obj_ioctl, + .compat_ioctl = compat_ptr_ioctl, .llseek = no_llseek, }; @@ -75,6 +140,7 @@ static struct ntsync_obj *ntsync_alloc_obj(struct ntsync_device *dev, obj->type = type; obj->dev = dev; get_file(dev->file); + spin_lock_init(&obj->lock); return obj; } diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h index 6a4867a6c97b..dcfa38fdc93c 100644 --- a/include/uapi/linux/ntsync.h +++ b/include/uapi/linux/ntsync.h @@ -18,4 +18,6 @@ struct ntsync_sem_args { #define NTSYNC_IOC_CREATE_SEM _IOWR('N', 0x80, struct ntsync_sem_args) +#define NTSYNC_IOC_SEM_POST _IOWR('N', 0x81, __u32) + #endif -- cgit v1.2.3-59-g8ed1b From ce5e811e069168898ae2ff02a90de68637ed7dc4 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 5 Apr 2024 16:41:41 +0200 Subject: soundwire: qcom: allow multi-link on newer devices Newer Qualcomm SoCs like X1E80100 might come with four speakers spread over two Soundwire controllers, thus they need a multi-link Soundwire stream runtime. Cc: Mark Brown Cc: alsa-devel@alsa-project.org Reviewed-by: Pierre-Louis Bossart Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240405144141.47217-1-krzysztof.kozlowski@linaro.org Signed-off-by: Vinod Koul --- drivers/soundwire/qcom.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c index fb70afe64fcc..ce5cf3ecceb5 100644 --- a/drivers/soundwire/qcom.c +++ b/drivers/soundwire/qcom.c @@ -905,6 +905,18 @@ static int qcom_swrm_init(struct qcom_swrm_ctrl *ctrl) return 0; } +static int qcom_swrm_read_prop(struct sdw_bus *bus) +{ + struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus); + + if (ctrl->version >= SWRM_VERSION_2_0_0) { + bus->multi_link = true; + bus->hw_sync_min_links = 3; + } + + return 0; +} + static enum sdw_command_response qcom_swrm_xfer_msg(struct sdw_bus *bus, struct sdw_msg *msg) { @@ -1056,6 +1068,7 @@ static const struct sdw_master_port_ops qcom_swrm_port_ops = { }; static const struct sdw_master_ops qcom_swrm_ops = { + .read_prop = qcom_swrm_read_prop, .xfer_msg = qcom_swrm_xfer_msg, .pre_bank_switch = qcom_swrm_pre_bank_switch, }; @@ -1173,6 +1186,15 @@ static int qcom_swrm_stream_alloc_ports(struct qcom_swrm_ctrl *ctrl, mutex_lock(&ctrl->port_lock); list_for_each_entry(m_rt, &stream->master_list, stream_node) { + /* + * For streams with multiple masters: + * Allocate ports only for devices connected to this master. + * Such devices will have ports allocated by their own master + * and its qcom_swrm_stream_alloc_ports() call. + */ + if (ctrl->bus.id != m_rt->bus->id) + continue; + if (m_rt->direction == SDW_DATA_DIR_RX) { maxport = ctrl->num_dout_ports; port_mask = &ctrl->dout_port_mask; -- cgit v1.2.3-59-g8ed1b From d48c03198a92edf41e89477dab4f602df15165ee Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Sat, 6 Apr 2024 15:52:01 +0200 Subject: sysfs: Add sysfs_bin_attr_simple_read() helper When drivers expose a bin_attribute in sysfs which is backed by a buffer in memory, a common pattern is to set the @private and @size members in struct bin_attribute to the buffer's location and size. The ->read() callback then merely consists of a single memcpy() call. It's not even necessary to perform bounds checks as these are already handled by sysfs_kf_bin_read(). However each driver is so far providing its own ->read() implementation. The pattern is sufficiently frequent to merit a public helper, so add sysfs_bin_attr_simple_read() as well as BIN_ATTR_SIMPLE_RO() and BIN_ATTR_SIMPLE_ADMIN_RO() macros to ease declaration of such bin_attributes and reduce LoC and .text section size. Signed-off-by: Lukas Wunner Reviewed-by: Greg Kroah-Hartman Acked-by: Rafael J. Wysocki Acked-by: Ard Biesheuvel Link: https://lore.kernel.org/r/5ed62b197a442ec6db53d8746d9d806dd0576e2d.1712410202.git.lukas@wunner.de Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/file.c | 27 +++++++++++++++++++++++++++ include/linux/sysfs.h | 15 +++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index 6b7652fb8050..289b57d32c89 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -783,3 +783,30 @@ int sysfs_emit_at(char *buf, int at, const char *fmt, ...) return len; } EXPORT_SYMBOL_GPL(sysfs_emit_at); + +/** + * sysfs_bin_attr_simple_read - read callback to simply copy from memory. + * @file: attribute file which is being read. + * @kobj: object to which the attribute belongs. + * @attr: attribute descriptor. + * @buf: destination buffer. + * @off: offset in bytes from which to read. + * @count: maximum number of bytes to read. + * + * Simple ->read() callback for bin_attributes backed by a buffer in memory. + * The @private and @size members in struct bin_attribute must be set to the + * buffer's location and size before the bin_attribute is created in sysfs. + * + * Bounds check for @off and @count is done in sysfs_kf_bin_read(). + * Negative value check for @off is done in vfs_setpos() and default_llseek(). + * + * Returns number of bytes written to @buf. + */ +ssize_t sysfs_bin_attr_simple_read(struct file *file, struct kobject *kobj, + struct bin_attribute *attr, char *buf, + loff_t off, size_t count) +{ + memcpy(buf, attr->private + off, count); + return count; +} +EXPORT_SYMBOL_GPL(sysfs_bin_attr_simple_read); diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h index 326341c62385..a7d725fbf739 100644 --- a/include/linux/sysfs.h +++ b/include/linux/sysfs.h @@ -371,6 +371,17 @@ struct bin_attribute bin_attr_##_name = __BIN_ATTR_ADMIN_RO(_name, _size) #define BIN_ATTR_ADMIN_RW(_name, _size) \ struct bin_attribute bin_attr_##_name = __BIN_ATTR_ADMIN_RW(_name, _size) +#define __BIN_ATTR_SIMPLE_RO(_name, _mode) { \ + .attr = { .name = __stringify(_name), .mode = _mode }, \ + .read = sysfs_bin_attr_simple_read, \ +} + +#define BIN_ATTR_SIMPLE_RO(_name) \ +struct bin_attribute bin_attr_##_name = __BIN_ATTR_SIMPLE_RO(_name, 0444) + +#define BIN_ATTR_SIMPLE_ADMIN_RO(_name) \ +struct bin_attribute bin_attr_##_name = __BIN_ATTR_SIMPLE_RO(_name, 0400) + struct sysfs_ops { ssize_t (*show)(struct kobject *, struct attribute *, char *); ssize_t (*store)(struct kobject *, struct attribute *, const char *, size_t); @@ -478,6 +489,10 @@ int sysfs_emit(char *buf, const char *fmt, ...); __printf(3, 4) int sysfs_emit_at(char *buf, int at, const char *fmt, ...); +ssize_t sysfs_bin_attr_simple_read(struct file *file, struct kobject *kobj, + struct bin_attribute *attr, char *buf, + loff_t off, size_t count); + #else /* CONFIG_SYSFS */ static inline int sysfs_create_dir_ns(struct kobject *kobj, const void *ns) -- cgit v1.2.3-59-g8ed1b From 66bc1a173328dec3e37c203a999f2a2914c96b56 Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Sat, 6 Apr 2024 15:52:02 +0200 Subject: treewide: Use sysfs_bin_attr_simple_read() helper Deduplicate ->read() callbacks of bin_attributes which are backed by a simple buffer in memory: Use the newly introduced sysfs_bin_attr_simple_read() helper instead, either by referencing it directly or by declaring such bin_attributes with BIN_ATTR_SIMPLE_RO() or BIN_ATTR_SIMPLE_ADMIN_RO(). Aside from a reduction of LoC, this shaves off a few bytes from vmlinux (304 bytes on an x86_64 allyesconfig). No functional change intended. Signed-off-by: Lukas Wunner Acked-by: Zhi Wang Acked-by: Michael Ellerman Acked-by: Rafael J. Wysocki Acked-by: Ard Biesheuvel Link: https://lore.kernel.org/r/92ee0a0e83a5a3f3474845db6c8575297698933a.1712410202.git.lukas@wunner.de Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/platforms/powernv/opal.c | 10 +-------- drivers/acpi/bgrt.c | 9 +------- drivers/firmware/dmi_scan.c | 12 ++-------- drivers/firmware/efi/rci2-table.c | 10 +-------- drivers/gpu/drm/i915/gvt/firmware.c | 26 +++++----------------- .../intel/int340x_thermal/int3400_thermal.c | 9 +------- init/initramfs.c | 10 +-------- kernel/module/sysfs.c | 13 +---------- 8 files changed, 14 insertions(+), 85 deletions(-) diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c index 45dd77e3ccf6..5d0f35bb917e 100644 --- a/arch/powerpc/platforms/powernv/opal.c +++ b/arch/powerpc/platforms/powernv/opal.c @@ -792,14 +792,6 @@ static int __init opal_sysfs_init(void) return 0; } -static ssize_t export_attr_read(struct file *fp, struct kobject *kobj, - struct bin_attribute *bin_attr, char *buf, - loff_t off, size_t count) -{ - return memory_read_from_buffer(buf, count, &off, bin_attr->private, - bin_attr->size); -} - static int opal_add_one_export(struct kobject *parent, const char *export_name, struct device_node *np, const char *prop_name) { @@ -826,7 +818,7 @@ static int opal_add_one_export(struct kobject *parent, const char *export_name, sysfs_bin_attr_init(attr); attr->attr.name = name; attr->attr.mode = 0400; - attr->read = export_attr_read; + attr->read = sysfs_bin_attr_simple_read; attr->private = __va(vals[0]); attr->size = vals[1]; diff --git a/drivers/acpi/bgrt.c b/drivers/acpi/bgrt.c index e4fb9e225ddf..d1d9c9289087 100644 --- a/drivers/acpi/bgrt.c +++ b/drivers/acpi/bgrt.c @@ -29,14 +29,7 @@ BGRT_SHOW(type, image_type); BGRT_SHOW(xoffset, image_offset_x); BGRT_SHOW(yoffset, image_offset_y); -static ssize_t image_read(struct file *file, struct kobject *kobj, - struct bin_attribute *attr, char *buf, loff_t off, size_t count) -{ - memcpy(buf, attr->private + off, count); - return count; -} - -static BIN_ATTR_RO(image, 0); /* size gets filled in later */ +static BIN_ATTR_SIMPLE_RO(image); static struct attribute *bgrt_attributes[] = { &bgrt_attr_version.attr, diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c index 015c95a825d3..3d0f773ab876 100644 --- a/drivers/firmware/dmi_scan.c +++ b/drivers/firmware/dmi_scan.c @@ -746,16 +746,8 @@ static void __init dmi_scan_machine(void) pr_info("DMI not present or invalid.\n"); } -static ssize_t raw_table_read(struct file *file, struct kobject *kobj, - struct bin_attribute *attr, char *buf, - loff_t pos, size_t count) -{ - memcpy(buf, attr->private + pos, count); - return count; -} - -static BIN_ATTR(smbios_entry_point, S_IRUSR, raw_table_read, NULL, 0); -static BIN_ATTR(DMI, S_IRUSR, raw_table_read, NULL, 0); +static BIN_ATTR_SIMPLE_ADMIN_RO(smbios_entry_point); +static BIN_ATTR_SIMPLE_ADMIN_RO(DMI); static int __init dmi_init(void) { diff --git a/drivers/firmware/efi/rci2-table.c b/drivers/firmware/efi/rci2-table.c index de1a9a1f9f14..4fd45d6f69a4 100644 --- a/drivers/firmware/efi/rci2-table.c +++ b/drivers/firmware/efi/rci2-table.c @@ -40,15 +40,7 @@ static u8 *rci2_base; static u32 rci2_table_len; unsigned long rci2_table_phys __ro_after_init = EFI_INVALID_TABLE_ADDR; -static ssize_t raw_table_read(struct file *file, struct kobject *kobj, - struct bin_attribute *attr, char *buf, - loff_t pos, size_t count) -{ - memcpy(buf, attr->private + pos, count); - return count; -} - -static BIN_ATTR(rci2, S_IRUSR, raw_table_read, NULL, 0); +static BIN_ATTR_SIMPLE_ADMIN_RO(rci2); static u16 checksum(void) { diff --git a/drivers/gpu/drm/i915/gvt/firmware.c b/drivers/gpu/drm/i915/gvt/firmware.c index 4dd52ac2043e..5e66a260df12 100644 --- a/drivers/gpu/drm/i915/gvt/firmware.c +++ b/drivers/gpu/drm/i915/gvt/firmware.c @@ -50,21 +50,7 @@ struct gvt_firmware_header { #define dev_to_drm_minor(d) dev_get_drvdata((d)) -static ssize_t -gvt_firmware_read(struct file *filp, struct kobject *kobj, - struct bin_attribute *attr, char *buf, - loff_t offset, size_t count) -{ - memcpy(buf, attr->private + offset, count); - return count; -} - -static struct bin_attribute firmware_attr = { - .attr = {.name = "gvt_firmware", .mode = (S_IRUSR)}, - .read = gvt_firmware_read, - .write = NULL, - .mmap = NULL, -}; +static BIN_ATTR_SIMPLE_ADMIN_RO(gvt_firmware); static int expose_firmware_sysfs(struct intel_gvt *gvt) { @@ -107,10 +93,10 @@ static int expose_firmware_sysfs(struct intel_gvt *gvt) crc32_start = offsetof(struct gvt_firmware_header, version); h->crc32 = crc32_le(0, firmware + crc32_start, size - crc32_start); - firmware_attr.size = size; - firmware_attr.private = firmware; + bin_attr_gvt_firmware.size = size; + bin_attr_gvt_firmware.private = firmware; - ret = device_create_bin_file(&pdev->dev, &firmware_attr); + ret = device_create_bin_file(&pdev->dev, &bin_attr_gvt_firmware); if (ret) { vfree(firmware); return ret; @@ -122,8 +108,8 @@ static void clean_firmware_sysfs(struct intel_gvt *gvt) { struct pci_dev *pdev = to_pci_dev(gvt->gt->i915->drm.dev); - device_remove_bin_file(&pdev->dev, &firmware_attr); - vfree(firmware_attr.private); + device_remove_bin_file(&pdev->dev, &bin_attr_gvt_firmware); + vfree(bin_attr_gvt_firmware.private); } /** diff --git a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c index 427d370648d5..6d4b51a122bc 100644 --- a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c +++ b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c @@ -73,14 +73,7 @@ struct odvp_attr { struct device_attribute attr; }; -static ssize_t data_vault_read(struct file *file, struct kobject *kobj, - struct bin_attribute *attr, char *buf, loff_t off, size_t count) -{ - memcpy(buf, attr->private + off, count); - return count; -} - -static BIN_ATTR_RO(data_vault, 0); +static BIN_ATTR_SIMPLE_RO(data_vault); static struct bin_attribute *data_attributes[] = { &bin_attr_data_vault, diff --git a/init/initramfs.c b/init/initramfs.c index da79760b8be3..5193fae330c3 100644 --- a/init/initramfs.c +++ b/init/initramfs.c @@ -575,15 +575,7 @@ extern unsigned long __initramfs_size; #include #include -static ssize_t raw_read(struct file *file, struct kobject *kobj, - struct bin_attribute *attr, char *buf, - loff_t pos, size_t count) -{ - memcpy(buf, attr->private + pos, count); - return count; -} - -static BIN_ATTR(initrd, 0440, raw_read, NULL, 0); +static BIN_ATTR(initrd, 0440, sysfs_bin_attr_simple_read, NULL, 0); void __init reserve_initrd_mem(void) { diff --git a/kernel/module/sysfs.c b/kernel/module/sysfs.c index d964167c6658..26efe1305c12 100644 --- a/kernel/module/sysfs.c +++ b/kernel/module/sysfs.c @@ -146,17 +146,6 @@ struct module_notes_attrs { struct bin_attribute attrs[] __counted_by(notes); }; -static ssize_t module_notes_read(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, - char *buf, loff_t pos, size_t count) -{ - /* - * The caller checked the pos and count against our size. - */ - memcpy(buf, bin_attr->private + pos, count); - return count; -} - static void free_notes_attrs(struct module_notes_attrs *notes_attrs, unsigned int i) { @@ -205,7 +194,7 @@ static void add_notes_attrs(struct module *mod, const struct load_info *info) nattr->attr.mode = 0444; nattr->size = info->sechdrs[i].sh_size; nattr->private = (void *)info->sechdrs[i].sh_addr; - nattr->read = module_notes_read; + nattr->read = sysfs_bin_attr_simple_read; ++nattr; } ++loaded; -- cgit v1.2.3-59-g8ed1b From 4cd47222e435dec8e3787614924174f53fcfb5ae Mon Sep 17 00:00:00 2001 From: George Stark Date: Thu, 11 Apr 2024 19:10:25 +0300 Subject: locking/mutex: Introduce devm_mutex_init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Using of devm API leads to a certain order of releasing resources. So all dependent resources which are not devm-wrapped should be deleted with respect to devm-release order. Mutex is one of such objects that often is bound to other resources and has no own devm wrapping. Since mutex_destroy() actually does nothing in non-debug builds frequently calling mutex_destroy() is just ignored which is safe for now but wrong formally and can lead to a problem if mutex_destroy() will be extended so introduce devm_mutex_init(). Suggested-by: Christophe Leroy Signed-off-by: George Stark Reviewed-by: Christophe Leroy Reviewed-by: Andy Shevchenko Reviewed-by: Marek Behún Acked-by: Waiman Long Link: https://lore.kernel.org/r/20240411161032.609544-2-gnstark@salutedevices.com Signed-off-by: Lee Jones --- include/linux/mutex.h | 27 +++++++++++++++++++++++++++ kernel/locking/mutex-debug.c | 12 ++++++++++++ 2 files changed, 39 insertions(+) diff --git a/include/linux/mutex.h b/include/linux/mutex.h index 67edc4ca2bee..a561c629d89f 100644 --- a/include/linux/mutex.h +++ b/include/linux/mutex.h @@ -22,6 +22,8 @@ #include #include +struct device; + #ifdef CONFIG_DEBUG_LOCK_ALLOC # define __DEP_MAP_MUTEX_INITIALIZER(lockname) \ , .dep_map = { \ @@ -117,6 +119,31 @@ do { \ } while (0) #endif /* CONFIG_PREEMPT_RT */ +#ifdef CONFIG_DEBUG_MUTEXES + +int __devm_mutex_init(struct device *dev, struct mutex *lock); + +#else + +static inline int __devm_mutex_init(struct device *dev, struct mutex *lock) +{ + /* + * When CONFIG_DEBUG_MUTEXES is off mutex_destroy() is just a nop so + * no really need to register it in the devm subsystem. + */ + return 0; +} + +#endif + +#define devm_mutex_init(dev, mutex) \ +({ \ + typeof(mutex) mutex_ = (mutex); \ + \ + mutex_init(mutex_); \ + __devm_mutex_init(dev, mutex_); \ +}) + /* * See kernel/locking/mutex.c for detailed documentation of these APIs. * Also see Documentation/locking/mutex-design.rst. diff --git a/kernel/locking/mutex-debug.c b/kernel/locking/mutex-debug.c index bc8abb8549d2..6e6f6071cfa2 100644 --- a/kernel/locking/mutex-debug.c +++ b/kernel/locking/mutex-debug.c @@ -12,6 +12,7 @@ */ #include #include +#include #include #include #include @@ -89,6 +90,17 @@ void debug_mutex_init(struct mutex *lock, const char *name, lock->magic = lock; } +static void devm_mutex_release(void *res) +{ + mutex_destroy(res); +} + +int __devm_mutex_init(struct device *dev, struct mutex *lock) +{ + return devm_add_action_or_reset(dev, devm_mutex_release, lock); +} +EXPORT_SYMBOL_GPL(__devm_mutex_init); + /*** * mutex_destroy - mark a mutex unusable * @lock: the mutex to be destroyed -- cgit v1.2.3-59-g8ed1b From fb74e4fa524d57ca4bb86595cca8cf457ce93e0c Mon Sep 17 00:00:00 2001 From: George Stark Date: Thu, 11 Apr 2024 19:10:26 +0300 Subject: leds: aw2013: Use devm API to cleanup module's resources In this driver LEDs are registered using devm_led_classdev_register() so they are automatically unregistered after module's remove() is done. led_classdev_unregister() calls module's led_set_brightness() to turn off the LEDs and that callback uses resources which were destroyed already in module's remove() so use devm API instead of remove(). Signed-off-by: George Stark Reviewed-by: Andy Shevchenko Tested-by: Nikita Travkin Link: https://lore.kernel.org/r/20240411161032.609544-3-gnstark@salutedevices.com Signed-off-by: Lee Jones --- drivers/leds/leds-aw2013.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/drivers/leds/leds-aw2013.c b/drivers/leds/leds-aw2013.c index 17235a5e576a..6475eadcb0df 100644 --- a/drivers/leds/leds-aw2013.c +++ b/drivers/leds/leds-aw2013.c @@ -320,6 +320,11 @@ static int aw2013_probe_dt(struct aw2013 *chip) return 0; } +static void aw2013_chip_disable_action(void *data) +{ + aw2013_chip_disable(data); +} + static const struct regmap_config aw2013_regmap_config = { .reg_bits = 8, .val_bits = 8, @@ -336,7 +341,10 @@ static int aw2013_probe(struct i2c_client *client) if (!chip) return -ENOMEM; - mutex_init(&chip->mutex); + ret = devm_mutex_init(&client->dev, &chip->mutex); + if (ret) + return ret; + mutex_lock(&chip->mutex); chip->client = client; @@ -384,6 +392,10 @@ static int aw2013_probe(struct i2c_client *client) goto error_reg; } + ret = devm_add_action(&client->dev, aw2013_chip_disable_action, chip); + if (ret) + goto error_reg; + ret = aw2013_probe_dt(chip); if (ret < 0) goto error_reg; @@ -406,19 +418,9 @@ error_reg: error: mutex_unlock(&chip->mutex); - mutex_destroy(&chip->mutex); return ret; } -static void aw2013_remove(struct i2c_client *client) -{ - struct aw2013 *chip = i2c_get_clientdata(client); - - aw2013_chip_disable(chip); - - mutex_destroy(&chip->mutex); -} - static const struct of_device_id aw2013_match_table[] = { { .compatible = "awinic,aw2013", }, { /* sentinel */ }, @@ -432,7 +434,6 @@ static struct i2c_driver aw2013_driver = { .of_match_table = aw2013_match_table, }, .probe = aw2013_probe, - .remove = aw2013_remove, }; module_i2c_driver(aw2013_driver); -- cgit v1.2.3-59-g8ed1b From a59d8824d7303297718c496a24ac4209eb3c0195 Mon Sep 17 00:00:00 2001 From: George Stark Date: Thu, 11 Apr 2024 19:10:27 +0300 Subject: leds: aw200xx: Use devm API to cleanup module's resources In this driver LEDs are registered using devm_led_classdev_register() so they are automatically unregistered after module's remove() is done. led_classdev_unregister() calls module's led_set_brightness() to turn off the LEDs and that callback uses resources which were destroyed already in module's remove() so use devm API instead of remove(). Signed-off-by: George Stark Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240411161032.609544-4-gnstark@salutedevices.com Signed-off-by: Lee Jones --- drivers/leds/leds-aw200xx.c | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/drivers/leds/leds-aw200xx.c b/drivers/leds/leds-aw200xx.c index 6c8c9f2c19e3..f9d9844e0273 100644 --- a/drivers/leds/leds-aw200xx.c +++ b/drivers/leds/leds-aw200xx.c @@ -530,6 +530,16 @@ static const struct regmap_config aw200xx_regmap_config = { .disable_locking = true, }; +static void aw200xx_chip_reset_action(void *data) +{ + aw200xx_chip_reset(data); +} + +static void aw200xx_disable_action(void *data) +{ + aw200xx_disable(data); +} + static int aw200xx_probe(struct i2c_client *client) { const struct aw200xx_chipdef *cdef; @@ -568,11 +578,17 @@ static int aw200xx_probe(struct i2c_client *client) aw200xx_enable(chip); + ret = devm_add_action(&client->dev, aw200xx_disable_action, chip); + if (ret) + return ret; + ret = aw200xx_chip_check(chip); if (ret) return ret; - mutex_init(&chip->mutex); + ret = devm_mutex_init(&client->dev, &chip->mutex); + if (ret) + return ret; /* Need a lock now since after call aw200xx_probe_fw, sysfs nodes created */ mutex_lock(&chip->mutex); @@ -581,6 +597,10 @@ static int aw200xx_probe(struct i2c_client *client) if (ret) goto out_unlock; + ret = devm_add_action(&client->dev, aw200xx_chip_reset_action, chip); + if (ret) + goto out_unlock; + ret = aw200xx_probe_fw(&client->dev, chip); if (ret) goto out_unlock; @@ -595,15 +615,6 @@ out_unlock: return ret; } -static void aw200xx_remove(struct i2c_client *client) -{ - struct aw200xx *chip = i2c_get_clientdata(client); - - aw200xx_chip_reset(chip); - aw200xx_disable(chip); - mutex_destroy(&chip->mutex); -} - static const struct aw200xx_chipdef aw20036_cdef = { .channels = 36, .display_size_rows_max = 3, @@ -652,7 +663,6 @@ static struct i2c_driver aw200xx_driver = { .of_match_table = aw200xx_match_table, }, .probe = aw200xx_probe, - .remove = aw200xx_remove, .id_table = aw200xx_id, }; module_i2c_driver(aw200xx_driver); -- cgit v1.2.3-59-g8ed1b From b5a0b81605c70b86aa5e8e502613f32b408340ad Mon Sep 17 00:00:00 2001 From: George Stark Date: Thu, 11 Apr 2024 19:10:28 +0300 Subject: leds: lp3952: Use devm API to cleanup module's resources In this driver LEDs are registered using devm_led_classdev_register() so they are automatically unregistered after module's remove() is done. led_classdev_unregister() calls module's led_set_brightness() to turn off the LEDs and that callback uses resources which were destroyed already in module's remove() so use devm API instead of remove(). Also drop explicit turning LEDs off from remove() due to they will be off anyway by led_classdev_unregister(). Signed-off-by: George Stark Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240411161032.609544-5-gnstark@salutedevices.com Signed-off-by: Lee Jones --- drivers/leds/leds-lp3952.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/drivers/leds/leds-lp3952.c b/drivers/leds/leds-lp3952.c index 5d18bbfd1f23..ff7bae2447dd 100644 --- a/drivers/leds/leds-lp3952.c +++ b/drivers/leds/leds-lp3952.c @@ -207,6 +207,13 @@ static const struct regmap_config lp3952_regmap = { .cache_type = REGCACHE_MAPLE, }; +static void gpio_set_low_action(void *data) +{ + struct lp3952_led_array *priv = data; + + gpiod_set_value(priv->enable_gpio, 0); +} + static int lp3952_probe(struct i2c_client *client) { int status; @@ -226,6 +233,10 @@ static int lp3952_probe(struct i2c_client *client) return status; } + status = devm_add_action(&client->dev, gpio_set_low_action, priv); + if (status) + return status; + priv->regmap = devm_regmap_init_i2c(client, &lp3952_regmap); if (IS_ERR(priv->regmap)) { int err = PTR_ERR(priv->regmap); @@ -254,15 +265,6 @@ static int lp3952_probe(struct i2c_client *client) return 0; } -static void lp3952_remove(struct i2c_client *client) -{ - struct lp3952_led_array *priv; - - priv = i2c_get_clientdata(client); - lp3952_on_off(priv, LP3952_LED_ALL, false); - gpiod_set_value(priv->enable_gpio, 0); -} - static const struct i2c_device_id lp3952_id[] = { {LP3952_NAME, 0}, {} @@ -274,7 +276,6 @@ static struct i2c_driver lp3952_i2c_driver = { .name = LP3952_NAME, }, .probe = lp3952_probe, - .remove = lp3952_remove, .id_table = lp3952_id, }; -- cgit v1.2.3-59-g8ed1b From c230c03ba8cdfec1acf935a676bcd45707db5a42 Mon Sep 17 00:00:00 2001 From: George Stark Date: Thu, 11 Apr 2024 19:10:29 +0300 Subject: leds: lm3532: Use devm API to cleanup module's resources In this driver LEDs are registered using devm_led_classdev_register() so they are automatically unregistered after module's remove() is done. led_classdev_unregister() calls module's led_set_brightness() to turn off the LEDs and that callback uses resources which were destroyed already in module's remove() so use devm API instead of remove(). Signed-off-by: George Stark Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240411161032.609544-6-gnstark@salutedevices.com Signed-off-by: Lee Jones --- drivers/leds/leds-lm3532.c | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/drivers/leds/leds-lm3532.c b/drivers/leds/leds-lm3532.c index 13662a4aa1f2..8c90701dc50d 100644 --- a/drivers/leds/leds-lm3532.c +++ b/drivers/leds/leds-lm3532.c @@ -542,6 +542,13 @@ static int lm3532_parse_als(struct lm3532_data *priv) return ret; } +static void gpio_set_low_action(void *data) +{ + struct lm3532_data *priv = data; + + gpiod_direction_output(priv->enable_gpio, 0); +} + static int lm3532_parse_node(struct lm3532_data *priv) { struct fwnode_handle *child = NULL; @@ -556,6 +563,12 @@ static int lm3532_parse_node(struct lm3532_data *priv) if (IS_ERR(priv->enable_gpio)) priv->enable_gpio = NULL; + if (priv->enable_gpio) { + ret = devm_add_action(&priv->client->dev, gpio_set_low_action, priv); + if (ret) + return ret; + } + priv->regulator = devm_regulator_get(&priv->client->dev, "vin"); if (IS_ERR(priv->regulator)) priv->regulator = NULL; @@ -691,7 +704,10 @@ static int lm3532_probe(struct i2c_client *client) return ret; } - mutex_init(&drvdata->lock); + ret = devm_mutex_init(&client->dev, &drvdata->lock); + if (ret) + return ret; + i2c_set_clientdata(client, drvdata); ret = lm3532_parse_node(drvdata); @@ -703,16 +719,6 @@ static int lm3532_probe(struct i2c_client *client) return ret; } -static void lm3532_remove(struct i2c_client *client) -{ - struct lm3532_data *drvdata = i2c_get_clientdata(client); - - mutex_destroy(&drvdata->lock); - - if (drvdata->enable_gpio) - gpiod_direction_output(drvdata->enable_gpio, 0); -} - static const struct of_device_id of_lm3532_leds_match[] = { { .compatible = "ti,lm3532", }, {}, @@ -727,7 +733,6 @@ MODULE_DEVICE_TABLE(i2c, lm3532_id); static struct i2c_driver lm3532_i2c_driver = { .probe = lm3532_probe, - .remove = lm3532_remove, .id_table = lm3532_id, .driver = { .name = LM3532_NAME, -- cgit v1.2.3-59-g8ed1b From 310d26520e6a09b8a472aab8b8ef210e654be01a Mon Sep 17 00:00:00 2001 From: George Stark Date: Thu, 11 Apr 2024 19:10:30 +0300 Subject: leds: nic78bx: Use devm API to cleanup module's resources In this driver LEDs are registered using devm_led_classdev_register() so they are automatically unregistered after module's remove() is done. led_classdev_unregister() calls module's led_set_brightness() to turn off the LEDs and that callback uses resources which were destroyed already in module's remove() so use devm API instead of remove(). Signed-off-by: George Stark Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240411161032.609544-7-gnstark@salutedevices.com Signed-off-by: Lee Jones --- drivers/leds/leds-nic78bx.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/drivers/leds/leds-nic78bx.c b/drivers/leds/leds-nic78bx.c index a86b43dd995e..282d9e4cf116 100644 --- a/drivers/leds/leds-nic78bx.c +++ b/drivers/leds/leds-nic78bx.c @@ -118,6 +118,15 @@ static struct nic78bx_led nic78bx_leds[] = { } }; +static void lock_led_reg_action(void *data) +{ + struct nic78bx_led_data *led_data = data; + + /* Lock LED register */ + outb(NIC78BX_LOCK_VALUE, + led_data->io_base + NIC78BX_LOCK_REG_OFFSET); +} + static int nic78bx_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -152,6 +161,10 @@ static int nic78bx_probe(struct platform_device *pdev) led_data->io_base = io_rc->start; spin_lock_init(&led_data->lock); + ret = devm_add_action(dev, lock_led_reg_action, led_data); + if (ret) + return ret; + for (i = 0; i < ARRAY_SIZE(nic78bx_leds); i++) { nic78bx_leds[i].data = led_data; @@ -167,15 +180,6 @@ static int nic78bx_probe(struct platform_device *pdev) return ret; } -static void nic78bx_remove(struct platform_device *pdev) -{ - struct nic78bx_led_data *led_data = platform_get_drvdata(pdev); - - /* Lock LED register */ - outb(NIC78BX_LOCK_VALUE, - led_data->io_base + NIC78BX_LOCK_REG_OFFSET); -} - static const struct acpi_device_id led_device_ids[] = { {"NIC78B3", 0}, {"", 0}, @@ -184,7 +188,6 @@ MODULE_DEVICE_TABLE(acpi, led_device_ids); static struct platform_driver led_driver = { .probe = nic78bx_probe, - .remove_new = nic78bx_remove, .driver = { .name = KBUILD_MODNAME, .acpi_match_table = ACPI_PTR(led_device_ids), -- cgit v1.2.3-59-g8ed1b From efc347b9efee1c2b081f5281d33be4559fa50a16 Mon Sep 17 00:00:00 2001 From: George Stark Date: Thu, 11 Apr 2024 19:10:31 +0300 Subject: leds: mlxreg: Use devm_mutex_init() for mutex initialization In this driver LEDs are registered using devm_led_classdev_register() so they are automatically unregistered after module's remove() is done. led_classdev_unregister() calls module's led_set_brightness() to turn off the LEDs and that callback uses mutex which was destroyed already in module's remove() so use devm API instead. Signed-off-by: George Stark Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240411161032.609544-8-gnstark@salutedevices.com Signed-off-by: Lee Jones --- drivers/leds/leds-mlxreg.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/drivers/leds/leds-mlxreg.c b/drivers/leds/leds-mlxreg.c index 5595788d98d2..1b70de72376c 100644 --- a/drivers/leds/leds-mlxreg.c +++ b/drivers/leds/leds-mlxreg.c @@ -256,6 +256,7 @@ static int mlxreg_led_probe(struct platform_device *pdev) { struct mlxreg_core_platform_data *led_pdata; struct mlxreg_led_priv_data *priv; + int err; led_pdata = dev_get_platdata(&pdev->dev); if (!led_pdata) { @@ -267,26 +268,21 @@ static int mlxreg_led_probe(struct platform_device *pdev) if (!priv) return -ENOMEM; - mutex_init(&priv->access_lock); + err = devm_mutex_init(&pdev->dev, &priv->access_lock); + if (err) + return err; + priv->pdev = pdev; priv->pdata = led_pdata; return mlxreg_led_config(priv); } -static void mlxreg_led_remove(struct platform_device *pdev) -{ - struct mlxreg_led_priv_data *priv = dev_get_drvdata(&pdev->dev); - - mutex_destroy(&priv->access_lock); -} - static struct platform_driver mlxreg_led_driver = { .driver = { .name = "leds-mlxreg", }, .probe = mlxreg_led_probe, - .remove_new = mlxreg_led_remove, }; module_platform_driver(mlxreg_led_driver); -- cgit v1.2.3-59-g8ed1b From c382e2e3eccb6b7ca8c7aff5092c1668428e7de6 Mon Sep 17 00:00:00 2001 From: George Stark Date: Thu, 11 Apr 2024 19:10:32 +0300 Subject: leds: an30259a: Use devm_mutex_init() for mutex initialization In this driver LEDs are registered using devm_led_classdev_register() so they are automatically unregistered after module's remove() is done. led_classdev_unregister() calls module's led_set_brightness() to turn off the LEDs and that callback uses mutex which was destroyed already in module's remove() so use devm API instead. Signed-off-by: George Stark Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240411161032.609544-9-gnstark@salutedevices.com Signed-off-by: Lee Jones --- drivers/leds/leds-an30259a.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/drivers/leds/leds-an30259a.c b/drivers/leds/leds-an30259a.c index 0216afed3b6e..decfca447d8a 100644 --- a/drivers/leds/leds-an30259a.c +++ b/drivers/leds/leds-an30259a.c @@ -283,7 +283,10 @@ static int an30259a_probe(struct i2c_client *client) if (err < 0) return err; - mutex_init(&chip->mutex); + err = devm_mutex_init(&client->dev, &chip->mutex); + if (err) + return err; + chip->client = client; i2c_set_clientdata(client, chip); @@ -317,17 +320,9 @@ static int an30259a_probe(struct i2c_client *client) return 0; exit: - mutex_destroy(&chip->mutex); return err; } -static void an30259a_remove(struct i2c_client *client) -{ - struct an30259a *chip = i2c_get_clientdata(client); - - mutex_destroy(&chip->mutex); -} - static const struct of_device_id an30259a_match_table[] = { { .compatible = "panasonic,an30259a", }, { /* sentinel */ }, @@ -347,7 +342,6 @@ static struct i2c_driver an30259a_driver = { .of_match_table = an30259a_match_table, }, .probe = an30259a_probe, - .remove = an30259a_remove, .id_table = an30259a_id, }; -- cgit v1.2.3-59-g8ed1b From 62707b56b2b47dfdc94d4b079c9f9bfe5a923e33 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 10 Apr 2024 02:34:35 +0000 Subject: ASoC: SOF: Intel: hda: disable SoundWire interrupt later The SoundWire interrupts can be masked at two levels a) in the Cadence IP b) at the HDaudio controller level We have an existing mechanism with cancel_work_sync() and status flags to make sure all existing interrupts are handled in the Cadence IP, and likewise no new interrupts can be generated before turning off the links. However on remove we first use the higher-level mask at the controller level, which is a sledgehammer preventing interrupts from all links. This is very racy and not necessary. We can disable the SoundWire interrupts after all the cleanups are done without any loss of functionality. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Bard Liao Acked-by: Mark Brown Link: https://lore.kernel.org/r/20240410023438.487017-2-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- sound/soc/sof/intel/hda.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 7fe72b065451..ecfdb8f882d2 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -384,12 +384,12 @@ static int hda_sdw_exit(struct snd_sof_dev *sdev) hdev = sdev->pdata->hw_pdata; - hda_sdw_int_enable(sdev, false); - if (hdev->sdw) sdw_intel_exit(hdev->sdw); hdev->sdw = NULL; + hda_sdw_int_enable(sdev, false); + return 0; } -- cgit v1.2.3-59-g8ed1b From 6f4867fa57604fc898a63ee73fe890786b9f4a72 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Wed, 10 Apr 2024 02:34:36 +0000 Subject: soundwire: intel_auxdevice: use pm_runtime_resume() instead of pm_request_resume() We need to wait for each child to fully resume. pm_request_resume() is asynchronous, what we need is to wait synchronously to avoid race conditions. Signed-off-by: Bard Liao Link: https://lore.kernel.org/r/20240410023438.487017-3-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- drivers/soundwire/intel_auxdevice.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/soundwire/intel_auxdevice.c b/drivers/soundwire/intel_auxdevice.c index 95125cc2fc59..012232cfbf7f 100644 --- a/drivers/soundwire/intel_auxdevice.c +++ b/drivers/soundwire/intel_auxdevice.c @@ -454,9 +454,9 @@ static int intel_resume_child_device(struct device *dev, void *data) return 0; } - ret = pm_request_resume(dev); + ret = pm_runtime_resume(dev); if (ret < 0) { - dev_err(dev, "%s: pm_request_resume failed: %d\n", __func__, ret); + dev_err(dev, "%s: pm_runtime_resume failed: %d\n", __func__, ret); return ret; } @@ -499,9 +499,9 @@ static int __maybe_unused intel_pm_prepare(struct device *dev) * first resume the device for this link. This will also by construction * resume the PCI parent device. */ - ret = pm_request_resume(dev); + ret = pm_runtime_resume(dev); if (ret < 0) { - dev_err(dev, "%s: pm_request_resume failed: %d\n", __func__, ret); + dev_err(dev, "%s: pm_runtime_resume failed: %d\n", __func__, ret); return 0; } -- cgit v1.2.3-59-g8ed1b From f2fa6865566483582aed4511ef603b44239b227b Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Wed, 10 Apr 2024 02:34:37 +0000 Subject: soundwire: intel: export intel_resume_child_device We will resume each child in the next patch, and intel_resume_child_device() will be used. Signed-off-by: Bard Liao Link: https://lore.kernel.org/r/20240410023438.487017-4-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- drivers/soundwire/intel_auxdevice.c | 2 +- drivers/soundwire/intel_auxdevice.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/soundwire/intel_auxdevice.c b/drivers/soundwire/intel_auxdevice.c index 012232cfbf7f..296a470ce1e0 100644 --- a/drivers/soundwire/intel_auxdevice.c +++ b/drivers/soundwire/intel_auxdevice.c @@ -440,7 +440,7 @@ int intel_link_process_wakeen_event(struct auxiliary_device *auxdev) * PM calls */ -static int intel_resume_child_device(struct device *dev, void *data) +int intel_resume_child_device(struct device *dev, void *data) { int ret; struct sdw_slave *slave = dev_to_sdw_dev(dev); diff --git a/drivers/soundwire/intel_auxdevice.h b/drivers/soundwire/intel_auxdevice.h index a00ecde95563..acaae0bd6592 100644 --- a/drivers/soundwire/intel_auxdevice.h +++ b/drivers/soundwire/intel_auxdevice.h @@ -6,6 +6,7 @@ int intel_link_startup(struct auxiliary_device *auxdev); int intel_link_process_wakeen_event(struct auxiliary_device *auxdev); +int intel_resume_child_device(struct device *dev, void *data); struct sdw_intel_link_dev { struct auxiliary_device auxdev; -- cgit v1.2.3-59-g8ed1b From 4cd5ea6de156850d555e1af8244a530812ae6ff6 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Wed, 10 Apr 2024 02:34:38 +0000 Subject: soundwire: intel_init: resume all devices on exit. When the manager becomes pm_runtime active in the remove procedure, peripherals will become attached, and do the initialization process. We have to wait until all the devices are fully resumed before the cleanup, otherwise there is a possible race condition where asynchronous workqueues initiate transfers on the bus that cannot complete. This will ensure there are no SoundWire registers accessed after the bus is powered-down. Signed-off-by: Bard Liao Link: https://lore.kernel.org/r/20240410023438.487017-5-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- drivers/soundwire/intel_init.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/soundwire/intel_init.c b/drivers/soundwire/intel_init.c index 534c8795e7e8..a09134b97cd6 100644 --- a/drivers/soundwire/intel_init.c +++ b/drivers/soundwire/intel_init.c @@ -16,6 +16,7 @@ #include #include #include "cadence_master.h" +#include "bus.h" #include "intel.h" #include "intel_auxdevice.h" @@ -356,6 +357,19 @@ EXPORT_SYMBOL_NS(sdw_intel_startup, SOUNDWIRE_INTEL_INIT); */ void sdw_intel_exit(struct sdw_intel_ctx *ctx) { + struct sdw_intel_link_res *link; + + /* we first resume links and devices and wait synchronously before the cleanup */ + list_for_each_entry(link, &ctx->link_list, list) { + struct sdw_bus *bus = &link->cdns->bus; + int ret; + + ret = device_for_each_child(bus->dev, NULL, intel_resume_child_device); + if (ret < 0) + dev_err(bus->dev, "%s: intel_resume_child_device failed: %d\n", + __func__, ret); + } + sdw_intel_cleanup(ctx); kfree(ctx->ids); kfree(ctx->ldev); -- cgit v1.2.3-59-g8ed1b From 2adc731188b6123fc44ac01480ac381b41f8d6c6 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Tue, 26 Mar 2024 20:42:32 +0100 Subject: interconnect: qcom: sm6115: Unspaghettify SNoC QoS port numbering When I was creating this driver, my bright mind overlooked the existence of desc->qos_offset and decided to make up for the difference it made by adding 21 (0x15) to the port index on SNoC and its downstream buses. Undo this mistake to make the indices actually mean something. Signed-off-by: Konrad Dybcio Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20240326-topic-rpm_icc_qos_cleanup-v1-1-357e736792be@linaro.org Signed-off-by: Georgi Djakov --- drivers/interconnect/qcom/sm6115.c | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/drivers/interconnect/qcom/sm6115.c b/drivers/interconnect/qcom/sm6115.c index 7e15ddf0a80a..271b07c74862 100644 --- a/drivers/interconnect/qcom/sm6115.c +++ b/drivers/interconnect/qcom/sm6115.c @@ -242,7 +242,7 @@ static struct qcom_icc_node crypto_c0 = { .id = SM6115_MASTER_CRYPTO_CORE0, .channels = 1, .buswidth = 8, - .qos.qos_port = 43, + .qos.qos_port = 22, .qos.qos_mode = NOC_QOS_MODE_FIXED, .qos.areq_prio = 2, .mas_rpm_id = 23, @@ -332,7 +332,7 @@ static struct qcom_icc_node qnm_camera_nrt = { .id = SM6115_MASTER_CAMNOC_SF, .channels = 1, .buswidth = 32, - .qos.qos_port = 25, + .qos.qos_port = 4, .qos.qos_mode = NOC_QOS_MODE_FIXED, .qos.areq_prio = 3, .mas_rpm_id = -1, @@ -346,7 +346,7 @@ static struct qcom_icc_node qxm_venus0 = { .id = SM6115_MASTER_VIDEO_P0, .channels = 1, .buswidth = 16, - .qos.qos_port = 30, + .qos.qos_port = 9, .qos.qos_mode = NOC_QOS_MODE_FIXED, .qos.areq_prio = 3, .qos.urg_fwd_en = true, @@ -361,7 +361,7 @@ static struct qcom_icc_node qxm_venus_cpu = { .id = SM6115_MASTER_VIDEO_PROC, .channels = 1, .buswidth = 8, - .qos.qos_port = 34, + .qos.qos_port = 13, .qos.qos_mode = NOC_QOS_MODE_FIXED, .qos.areq_prio = 4, .mas_rpm_id = -1, @@ -379,7 +379,7 @@ static struct qcom_icc_node qnm_camera_rt = { .id = SM6115_MASTER_CAMNOC_HF, .channels = 1, .buswidth = 32, - .qos.qos_port = 31, + .qos.qos_port = 10, .qos.qos_mode = NOC_QOS_MODE_FIXED, .qos.areq_prio = 3, .qos.urg_fwd_en = true, @@ -394,7 +394,7 @@ static struct qcom_icc_node qxm_mdp0 = { .id = SM6115_MASTER_MDP_PORT0, .channels = 1, .buswidth = 16, - .qos.qos_port = 26, + .qos.qos_port = 5, .qos.qos_mode = NOC_QOS_MODE_FIXED, .qos.areq_prio = 3, .qos.urg_fwd_en = true, @@ -434,7 +434,7 @@ static struct qcom_icc_node qhm_tic = { .id = SM6115_MASTER_TIC, .channels = 1, .buswidth = 4, - .qos.qos_port = 29, + .qos.qos_port = 8, .qos.qos_mode = NOC_QOS_MODE_FIXED, .qos.areq_prio = 2, .mas_rpm_id = -1, @@ -484,7 +484,7 @@ static struct qcom_icc_node qxm_pimem = { .id = SM6115_MASTER_PIMEM, .channels = 1, .buswidth = 8, - .qos.qos_port = 41, + .qos.qos_port = 20, .qos.qos_mode = NOC_QOS_MODE_FIXED, .qos.areq_prio = 2, .mas_rpm_id = -1, @@ -498,7 +498,7 @@ static struct qcom_icc_node qhm_qdss_bam = { .id = SM6115_MASTER_QDSS_BAM, .channels = 1, .buswidth = 4, - .qos.qos_port = 23, + .qos.qos_port = 2, .qos.qos_mode = NOC_QOS_MODE_FIXED, .qos.areq_prio = 2, .mas_rpm_id = -1, @@ -523,7 +523,7 @@ static struct qcom_icc_node qhm_qup0 = { .id = SM6115_MASTER_QUP_0, .channels = 1, .buswidth = 4, - .qos.qos_port = 21, + .qos.qos_port = 0, .qos.qos_mode = NOC_QOS_MODE_FIXED, .qos.areq_prio = 2, .mas_rpm_id = 166, @@ -537,7 +537,7 @@ static struct qcom_icc_node qxm_ipa = { .id = SM6115_MASTER_IPA, .channels = 1, .buswidth = 8, - .qos.qos_port = 24, + .qos.qos_port = 3, .qos.qos_mode = NOC_QOS_MODE_FIXED, .qos.areq_prio = 2, .mas_rpm_id = 59, @@ -551,7 +551,7 @@ static struct qcom_icc_node xm_qdss_etr = { .id = SM6115_MASTER_QDSS_ETR, .channels = 1, .buswidth = 8, - .qos.qos_port = 33, + .qos.qos_port = 12, .qos.qos_mode = NOC_QOS_MODE_FIXED, .qos.areq_prio = 2, .mas_rpm_id = -1, @@ -565,7 +565,7 @@ static struct qcom_icc_node xm_sdc1 = { .id = SM6115_MASTER_SDCC_1, .channels = 1, .buswidth = 8, - .qos.qos_port = 38, + .qos.qos_port = 17, .qos.qos_mode = NOC_QOS_MODE_FIXED, .qos.areq_prio = 2, .mas_rpm_id = 33, @@ -579,7 +579,7 @@ static struct qcom_icc_node xm_sdc2 = { .id = SM6115_MASTER_SDCC_2, .channels = 1, .buswidth = 8, - .qos.qos_port = 44, + .qos.qos_port = 23, .qos.qos_mode = NOC_QOS_MODE_FIXED, .qos.areq_prio = 2, .mas_rpm_id = 35, @@ -593,7 +593,7 @@ static struct qcom_icc_node xm_usb3_0 = { .id = SM6115_MASTER_USB3, .channels = 1, .buswidth = 8, - .qos.qos_port = 45, + .qos.qos_port = 24, .qos.qos_mode = NOC_QOS_MODE_FIXED, .qos.areq_prio = 2, .mas_rpm_id = -1, @@ -1336,6 +1336,7 @@ static const struct qcom_icc_desc sm6115_sys_noc = { .intf_clocks = snoc_intf_clocks, .num_intf_clocks = ARRAY_SIZE(snoc_intf_clocks), .bus_clk_desc = &bus_2_clk, + .qos_offset = 0x15000, .keep_alive = true, }; @@ -1367,6 +1368,7 @@ static const struct qcom_icc_desc sm6115_mmnrt_virt = { .regmap_cfg = &sys_noc_regmap_config, .bus_clk_desc = &mmaxi_0_clk, .keep_alive = true, + .qos_offset = 0x15000, .ab_coeff = 142, }; @@ -1383,6 +1385,7 @@ static const struct qcom_icc_desc sm6115_mmrt_virt = { .regmap_cfg = &sys_noc_regmap_config, .bus_clk_desc = &mmaxi_1_clk, .keep_alive = true, + .qos_offset = 0x15000, .ab_coeff = 139, }; -- cgit v1.2.3-59-g8ed1b From 230d05b1179f6ce6f8dc8a2b99eba92799ac22d7 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Tue, 26 Mar 2024 20:42:33 +0100 Subject: interconnect: qcom: qcm2290: Fix mas_snoc_bimc QoS port assignment The value was wrong, resulting in misprogramming of the hardware. Fix it. Fixes: 1a14b1ac3935 ("interconnect: qcom: Add QCM2290 driver support") Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20240326-topic-rpm_icc_qos_cleanup-v1-2-357e736792be@linaro.org Signed-off-by: Georgi Djakov --- drivers/interconnect/qcom/qcm2290.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/interconnect/qcom/qcm2290.c b/drivers/interconnect/qcom/qcm2290.c index 96735800b13c..ba4cc08684d6 100644 --- a/drivers/interconnect/qcom/qcm2290.c +++ b/drivers/interconnect/qcom/qcm2290.c @@ -164,7 +164,7 @@ static struct qcom_icc_node mas_snoc_bimc = { .name = "mas_snoc_bimc", .buswidth = 16, .qos.ap_owned = true, - .qos.qos_port = 2, + .qos.qos_port = 6, .qos.qos_mode = NOC_QOS_MODE_BYPASS, .mas_rpm_id = 164, .slv_rpm_id = -1, -- cgit v1.2.3-59-g8ed1b From 6016137a964b67a6ac8afb9071ef6e83777afca6 Mon Sep 17 00:00:00 2001 From: Gil Fine Date: Mon, 12 Feb 2024 00:33:25 +0200 Subject: thunderbolt: Fix calculation of consumed USB3 bandwidth on a path Currently, when setup a new USB3 tunnel that is starting from downstream USB3 adapter of first depth router (or deeper), to upstream USB3 adapter of a second depth router (or deeper), we calculate consumed bandwidth. For this calculation we take into account first USB3 tunnel consumed bandwidth while we shouldn't, because we just recalculating the first USB3 tunnel allocated bandwidth. Fix that, so that more bandwidth is available for the new USB3 tunnel being setup. While there, fix the kernel-doc to decribe more accurately the purpose of the function. Signed-off-by: Gil Fine Signed-off-by: Mika Westerberg --- drivers/thunderbolt/tb.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/thunderbolt/tb.c b/drivers/thunderbolt/tb.c index c5ce7a694b27..ec8c4ef5e3ba 100644 --- a/drivers/thunderbolt/tb.c +++ b/drivers/thunderbolt/tb.c @@ -498,8 +498,9 @@ static struct tb_tunnel *tb_find_first_usb3_tunnel(struct tb *tb, * @consumed_down: Consumed downstream bandwidth (Mb/s) * * Calculates consumed USB3 and PCIe bandwidth at @port between path - * from @src_port to @dst_port. Does not take tunnel starting from - * @src_port and ending from @src_port into account. + * from @src_port to @dst_port. Does not take USB3 tunnel starting from + * @src_port and ending on @src_port into account because that bandwidth is + * already included in as part of the "first hop" USB3 tunnel. */ static int tb_consumed_usb3_pcie_bandwidth(struct tb *tb, struct tb_port *src_port, @@ -514,8 +515,8 @@ static int tb_consumed_usb3_pcie_bandwidth(struct tb *tb, *consumed_up = *consumed_down = 0; tunnel = tb_find_first_usb3_tunnel(tb, src_port, dst_port); - if (tunnel && tunnel->src_port != src_port && - tunnel->dst_port != dst_port) { + if (tunnel && !tb_port_is_usb3_down(src_port) && + !tb_port_is_usb3_up(dst_port)) { int ret; ret = tb_tunnel_consumed_bandwidth(tunnel, consumed_up, -- cgit v1.2.3-59-g8ed1b From 25d905d2b81973426b73ad943342dfda4e9a6fb5 Mon Sep 17 00:00:00 2001 From: Gil Fine Date: Mon, 12 Feb 2024 00:33:24 +0200 Subject: thunderbolt: Allow USB3 bandwidth to be lower than maximum supported Currently USB3 tunnel setup fails if USB4 link available bandwidth is too low to allow USB3 Maximum Supported Link Rate. In reality, this limitation is not needed, and may cause failure of USB3 tunnel establishment, if USB4 link available bandwidth is lower than USB3 Maximum Supported Link Rate. E.g. if we connect to USB4 v1 host router, a USB4 v1 device router, via 10 Gb/s cable. Hence, here we discard this limitation, and now we only limit USB3 bandwidth allocation to be not higher than 90% of USB3 Max Supported Link Rate (for first USB3 tunnel only). Signed-off-by: Gil Fine Signed-off-by: Mika Westerberg --- drivers/thunderbolt/tunnel.c | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/drivers/thunderbolt/tunnel.c b/drivers/thunderbolt/tunnel.c index cb6609a56a03..fdc5e8e12ca8 100644 --- a/drivers/thunderbolt/tunnel.c +++ b/drivers/thunderbolt/tunnel.c @@ -2064,26 +2064,21 @@ struct tb_tunnel *tb_tunnel_alloc_usb3(struct tb *tb, struct tb_port *up, { struct tb_tunnel *tunnel; struct tb_path *path; - int max_rate = 0; + int max_rate; - /* - * Check that we have enough bandwidth available for the new - * USB3 tunnel. - */ - if (max_up > 0 || max_down > 0) { + if (!tb_route(down->sw) && (max_up > 0 || max_down > 0)) { + /* + * For USB3 isochronous transfers, we allow bandwidth which is + * not higher than 90% of maximum supported bandwidth by USB3 + * adapters. + */ max_rate = tb_usb3_max_link_rate(down, up); if (max_rate < 0) return NULL; - /* Only 90% can be allocated for USB3 isochronous transfers */ max_rate = max_rate * 90 / 100; - tb_port_dbg(up, "required bandwidth for USB3 tunnel %d Mb/s\n", + tb_port_dbg(up, "maximum required bandwidth for USB3 tunnel %d Mb/s\n", max_rate); - - if (max_rate > max_up || max_rate > max_down) { - tb_port_warn(up, "not enough bandwidth for USB3 tunnel\n"); - return NULL; - } } tunnel = tb_tunnel_alloc(tb, 2, TB_TUNNEL_USB3); @@ -2115,8 +2110,8 @@ struct tb_tunnel *tb_tunnel_alloc_usb3(struct tb *tb, struct tb_port *up, tunnel->paths[TB_USB3_PATH_UP] = path; if (!tb_route(down->sw)) { - tunnel->allocated_up = max_rate; - tunnel->allocated_down = max_rate; + tunnel->allocated_up = min(max_rate, max_up); + tunnel->allocated_down = min(max_rate, max_down); tunnel->init = tb_usb3_init; tunnel->consumed_bandwidth = tb_usb3_consumed_bandwidth; -- cgit v1.2.3-59-g8ed1b From a004f2427079024aec5bdeebfe6f9b9a495ab2b1 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 5 Mar 2024 02:45:01 +0200 Subject: dt-bindings: leds: pca963x: Convert text bindings to YAML Convert the pca963x DT bindings to YAML schema. The existing properties are kept without modification, but the example is adapted to the latest common bindings for LEDs. Signed-off-by: Laurent Pinchart Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20240305004501.849-1-laurent.pinchart@ideasonboard.com Signed-off-by: Lee Jones --- .../devicetree/bindings/leds/nxp,pca963x.yaml | 140 +++++++++++++++++++++ Documentation/devicetree/bindings/leds/pca963x.txt | 52 -------- 2 files changed, 140 insertions(+), 52 deletions(-) create mode 100644 Documentation/devicetree/bindings/leds/nxp,pca963x.yaml delete mode 100644 Documentation/devicetree/bindings/leds/pca963x.txt diff --git a/Documentation/devicetree/bindings/leds/nxp,pca963x.yaml b/Documentation/devicetree/bindings/leds/nxp,pca963x.yaml new file mode 100644 index 000000000000..938d0e48fe51 --- /dev/null +++ b/Documentation/devicetree/bindings/leds/nxp,pca963x.yaml @@ -0,0 +1,140 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/leds/nxp,pca963x.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NXP PCA963x LED controllers + +maintainers: + - Laurent Pinchart + +description: | + The NXP PCA963x are I2C-controlled LED drivers optimized for + Red/Green/Blue/Amber (RGBA) color mixing applications. Each LED is + individually controllable and has its own PWM controller. + + Datasheets are available at + + - https://www.nxp.com/docs/en/data-sheet/PCA9632.pdf + - https://www.nxp.com/docs/en/data-sheet/PCA9633.pdf + - https://www.nxp.com/docs/en/data-sheet/PCA9634.pdf + - https://www.nxp.com/docs/en/data-sheet/PCA9635.pdf + +properties: + compatible: + enum: + - nxp,pca9632 + - nxp,pca9633 + - nxp,pca9634 + - nxp,pca9635 + + reg: + maxItems: 1 + + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + + nxp,hw-blink: + type: boolean + description: + Use hardware blinking instead of software blinking + + nxp,inverted-out: + type: boolean + description: + Invert the polarity of the generated PWM. + + nxp,period-scale: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + In some configurations, the chip blinks faster than expected. This + parameter provides a scaling ratio (fixed point, decimal divided by 1000) + to compensate, e.g. 1300=1.3x and 750=0.75x. + + nxp,totem-pole: + type: boolean + description: + Use totem pole (push-pull) instead of open-drain (pca9632 defaults to + open-drain, newer chips to totem pole). + +patternProperties: + "^led@[0-9a-f]+$": + type: object + $ref: common.yaml# + unevaluatedProperties: false + + properties: + reg: + minimum: 0 + + required: + - reg + +allOf: + - if: + properties: + compatible: + contains: + enum: + - nxp,pca9632 + - nxp,pca9633 + then: + patternProperties: + "^led@[0-9a-f]+$": + properties: + reg: + maximum: 3 + else: + patternProperties: + "^led@[0-9a-f]+$": + properties: + reg: + maximum: 7 + +additionalProperties: false + +examples: + - | + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + led-controller@62 { + compatible = "nxp,pca9632"; + reg = <0x62>; + #address-cells = <1>; + #size-cells = <0>; + + led@0 { + reg = <0>; + color = ; + function = LED_FUNCTION_STATUS; + }; + + led@1 { + reg = <1>; + color = ; + function = LED_FUNCTION_STATUS; + }; + + led@2 { + reg = <2>; + color = ; + function = LED_FUNCTION_STATUS; + }; + + led@3 { + reg = <3>; + color = ; + function = LED_FUNCTION_STATUS; + }; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/leds/pca963x.txt b/Documentation/devicetree/bindings/leds/pca963x.txt deleted file mode 100644 index 4eee41482041..000000000000 --- a/Documentation/devicetree/bindings/leds/pca963x.txt +++ /dev/null @@ -1,52 +0,0 @@ -LEDs connected to pca9632, pca9633 or pca9634 - -Required properties: -- compatible : should be : "nxp,pca9632", "nxp,pca9633", "nxp,pca9634" or "nxp,pca9635" - -Optional properties: -- nxp,totem-pole : use totem pole (push-pull) instead of open-drain (pca9632 defaults - to open-drain, newer chips to totem pole) -- nxp,hw-blink : use hardware blinking instead of software blinking -- nxp,period-scale : In some configurations, the chip blinks faster than expected. - This parameter provides a scaling ratio (fixed point, decimal divided - by 1000) to compensate, e.g. 1300=1.3x and 750=0.75x. -- nxp,inverted-out: invert the polarity of the generated PWM - -Each led is represented as a sub-node of the nxp,pca963x device. - -LED sub-node properties: -- label : (optional) see Documentation/devicetree/bindings/leds/common.txt -- reg : number of LED line (could be from 0 to 3 in pca9632 or pca9633, - 0 to 7 in pca9634, or 0 to 15 in pca9635) -- linux,default-trigger : (optional) - see Documentation/devicetree/bindings/leds/common.txt - -Examples: - -pca9632: pca9632 { - compatible = "nxp,pca9632"; - #address-cells = <1>; - #size-cells = <0>; - reg = <0x62>; - - red@0 { - label = "red"; - reg = <0>; - linux,default-trigger = "none"; - }; - green@1 { - label = "green"; - reg = <1>; - linux,default-trigger = "none"; - }; - blue@2 { - label = "blue"; - reg = <2>; - linux,default-trigger = "none"; - }; - unused@3 { - label = "unused"; - reg = <3>; - linux,default-trigger = "none"; - }; -}; -- cgit v1.2.3-59-g8ed1b From 016cfc41fc6d6598d72826ba61546900542a3acb Mon Sep 17 00:00:00 2001 From: Danila Tikhonov Date: Wed, 6 Mar 2024 20:27:09 +0300 Subject: dt-bindings: leds: qcom-lpg: Document PM6150L compatible The PM6150L LPG modules are compatible with the PM8150L LPG modules, document the PM6150L LPG compatible as fallback for the PM8150L LPG. Signed-off-by: Danila Tikhonov Acked-by: Rob Herring Link: https://lore.kernel.org/r/20240306172710.59780-2-danila@jiaxyga.com Signed-off-by: Lee Jones --- Documentation/devicetree/bindings/leds/leds-qcom-lpg.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/devicetree/bindings/leds/leds-qcom-lpg.yaml b/Documentation/devicetree/bindings/leds/leds-qcom-lpg.yaml index 54a428d3d46f..7b9e0ad1ecaa 100644 --- a/Documentation/devicetree/bindings/leds/leds-qcom-lpg.yaml +++ b/Documentation/devicetree/bindings/leds/leds-qcom-lpg.yaml @@ -30,6 +30,10 @@ properties: - qcom,pmi8994-lpg - qcom,pmi8998-lpg - qcom,pmk8550-pwm + - items: + - enum: + - qcom,pm6150l-lpg + - const: qcom,pm8150l-lpg - items: - enum: - qcom,pm8550-pwm -- cgit v1.2.3-59-g8ed1b From 6b0d685d75a70ef9c9558efb0374ec4a9aaf95d2 Mon Sep 17 00:00:00 2001 From: Xing Tong Wu Date: Thu, 14 Mar 2024 15:05:06 +0800 Subject: leds: simatic-ipc-leds-gpio: Add support for module BX-59A This is used for the Siemens Simatic IPC BX-59A, which has its LEDs connected to GPIOs provided by the Nuvoton NCT6126D. Reviewed-by: Andy Shevchenko Signed-off-by: Xing Tong Wu Link: https://lore.kernel.org/r/20240314070506.2384-1-xingtong_wu@163.com Signed-off-by: Lee Jones --- drivers/leds/simple/simatic-ipc-leds-gpio-core.c | 1 + drivers/leds/simple/simatic-ipc-leds-gpio-f7188x.c | 52 +++++++++++++++++++--- 2 files changed, 47 insertions(+), 6 deletions(-) diff --git a/drivers/leds/simple/simatic-ipc-leds-gpio-core.c b/drivers/leds/simple/simatic-ipc-leds-gpio-core.c index 667ba1bc3a30..85003fd7f1aa 100644 --- a/drivers/leds/simple/simatic-ipc-leds-gpio-core.c +++ b/drivers/leds/simple/simatic-ipc-leds-gpio-core.c @@ -56,6 +56,7 @@ int simatic_ipc_leds_gpio_probe(struct platform_device *pdev, case SIMATIC_IPC_DEVICE_127E: case SIMATIC_IPC_DEVICE_227G: case SIMATIC_IPC_DEVICE_BX_21A: + case SIMATIC_IPC_DEVICE_BX_59A: break; default: return -ENODEV; diff --git a/drivers/leds/simple/simatic-ipc-leds-gpio-f7188x.c b/drivers/leds/simple/simatic-ipc-leds-gpio-f7188x.c index c7c3a1f986e6..7a5018639aaf 100644 --- a/drivers/leds/simple/simatic-ipc-leds-gpio-f7188x.c +++ b/drivers/leds/simple/simatic-ipc-leds-gpio-f7188x.c @@ -17,7 +17,12 @@ #include "simatic-ipc-leds-gpio.h" -static struct gpiod_lookup_table simatic_ipc_led_gpio_table = { +struct simatic_ipc_led_tables { + struct gpiod_lookup_table *led_lookup_table; + struct gpiod_lookup_table *led_lookup_table_extra; +}; + +static struct gpiod_lookup_table simatic_ipc_led_gpio_table_227g = { .dev_id = "leds-gpio", .table = { GPIO_LOOKUP_IDX("gpio-f7188x-2", 0, NULL, 0, GPIO_ACTIVE_LOW), @@ -30,7 +35,7 @@ static struct gpiod_lookup_table simatic_ipc_led_gpio_table = { }, }; -static struct gpiod_lookup_table simatic_ipc_led_gpio_table_extra = { +static struct gpiod_lookup_table simatic_ipc_led_gpio_table_extra_227g = { .dev_id = NULL, /* Filled during initialization */ .table = { GPIO_LOOKUP_IDX("gpio-f7188x-3", 6, NULL, 6, GPIO_ACTIVE_HIGH), @@ -39,16 +44,51 @@ static struct gpiod_lookup_table simatic_ipc_led_gpio_table_extra = { }, }; +static struct gpiod_lookup_table simatic_ipc_led_gpio_table_bx_59a = { + .dev_id = "leds-gpio", + .table = { + GPIO_LOOKUP_IDX("gpio-f7188x-2", 0, NULL, 0, GPIO_ACTIVE_LOW), + GPIO_LOOKUP_IDX("gpio-f7188x-2", 3, NULL, 1, GPIO_ACTIVE_LOW), + GPIO_LOOKUP_IDX("gpio-f7188x-5", 3, NULL, 2, GPIO_ACTIVE_LOW), + GPIO_LOOKUP_IDX("gpio-f7188x-5", 2, NULL, 3, GPIO_ACTIVE_LOW), + GPIO_LOOKUP_IDX("gpio-f7188x-7", 7, NULL, 4, GPIO_ACTIVE_LOW), + GPIO_LOOKUP_IDX("gpio-f7188x-7", 4, NULL, 5, GPIO_ACTIVE_LOW), + {} /* Terminating entry */ + } +}; + static int simatic_ipc_leds_gpio_f7188x_probe(struct platform_device *pdev) { - return simatic_ipc_leds_gpio_probe(pdev, &simatic_ipc_led_gpio_table, - &simatic_ipc_led_gpio_table_extra); + const struct simatic_ipc_platform *plat = dev_get_platdata(&pdev->dev); + struct simatic_ipc_led_tables *led_tables; + + led_tables = devm_kzalloc(&pdev->dev, sizeof(*led_tables), GFP_KERNEL); + if (!led_tables) + return -ENOMEM; + + switch (plat->devmode) { + case SIMATIC_IPC_DEVICE_227G: + led_tables->led_lookup_table = &simatic_ipc_led_gpio_table_227g; + led_tables->led_lookup_table_extra = &simatic_ipc_led_gpio_table_extra_227g; + break; + case SIMATIC_IPC_DEVICE_BX_59A: + led_tables->led_lookup_table = &simatic_ipc_led_gpio_table_bx_59a; + break; + default: + return -ENODEV; + } + + platform_set_drvdata(pdev, led_tables); + return simatic_ipc_leds_gpio_probe(pdev, led_tables->led_lookup_table, + led_tables->led_lookup_table_extra); } static void simatic_ipc_leds_gpio_f7188x_remove(struct platform_device *pdev) { - simatic_ipc_leds_gpio_remove(pdev, &simatic_ipc_led_gpio_table, - &simatic_ipc_led_gpio_table_extra); + struct simatic_ipc_led_tables *led_tables = platform_get_drvdata(pdev); + + simatic_ipc_leds_gpio_remove(pdev, led_tables->led_lookup_table, + led_tables->led_lookup_table_extra); } static struct platform_driver simatic_ipc_led_gpio_driver = { -- cgit v1.2.3-59-g8ed1b From 7d36c3573391dcf0da089298a4b5a25c39f7289d Mon Sep 17 00:00:00 2001 From: INAGAKI Hiroshi Date: Sat, 23 Mar 2024 16:36:09 +0900 Subject: dt-bindings: leds: Add LED_FUNCTION_MOBILE for mobile network Add LED_FUNCTION_MOBILE for LEDs that indicate status of mobile network connection. This is useful to distinguish those LEDs from LEDs that indicates status of wired "wan" connection. example (on stock fw): IIJ SA-W2 has "Mobile" LEDs that indicate status (no signal, too low, low, good) of mobile network connection via dongle connected to USB port. - no signal: (none, turned off) - too low: green:mobile & red:mobile (amber, blink) - low: green:mobile & red:mobile (amber, turned on) - good: green:mobile (turned on) Suggested-by: Hauke Mehrtens Signed-off-by: INAGAKI Hiroshi Reviewed-by: Rob Herring Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240323074326.1428-2-musashino.open@gmail.com Signed-off-by: Lee Jones --- include/dt-bindings/leds/common.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/dt-bindings/leds/common.h b/include/dt-bindings/leds/common.h index ecea167930d9..6216ecdb06c7 100644 --- a/include/dt-bindings/leds/common.h +++ b/include/dt-bindings/leds/common.h @@ -90,6 +90,7 @@ #define LED_FUNCTION_INDICATOR "indicator" #define LED_FUNCTION_LAN "lan" #define LED_FUNCTION_MAIL "mail" +#define LED_FUNCTION_MOBILE "mobile" #define LED_FUNCTION_MTD "mtd" #define LED_FUNCTION_PANIC "panic" #define LED_FUNCTION_PROGRAMMING "programming" -- cgit v1.2.3-59-g8ed1b From 77b9f2d6fd9bf34ec810de6bdad42d7d0a47d31b Mon Sep 17 00:00:00 2001 From: INAGAKI Hiroshi Date: Sat, 23 Mar 2024 16:36:10 +0900 Subject: dt-bindings: leds: Add LED_FUNCTION_SPEED_* for link speed on LAN/WAN Add LED_FUNCTION_SPEED_LAN and LED_FUNCTION_SPEED_WAN for LEDs that indicate link speed of ethernet ports on LAN/WAN. This is useful to distinguish those LEDs from LEDs that indicate link status (up/down). example: Fortinet FortiGate 30E/50E have LEDs that indicate link speed on each of the ethernet ports in addition to LEDs that indicate link status (up/down). - 1000 Mbps: green:speed-(lan|wan)-N - 100 Mbps: amber:speed-(lan|wan)-N - 10 Mbps: (none, turned off) Signed-off-by: INAGAKI Hiroshi Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20240323074326.1428-3-musashino.open@gmail.com Signed-off-by: Lee Jones --- include/dt-bindings/leds/common.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/dt-bindings/leds/common.h b/include/dt-bindings/leds/common.h index 6216ecdb06c7..82a5769725ce 100644 --- a/include/dt-bindings/leds/common.h +++ b/include/dt-bindings/leds/common.h @@ -96,6 +96,8 @@ #define LED_FUNCTION_PROGRAMMING "programming" #define LED_FUNCTION_RX "rx" #define LED_FUNCTION_SD "sd" +#define LED_FUNCTION_SPEED_LAN "speed-lan" +#define LED_FUNCTION_SPEED_WAN "speed-wan" #define LED_FUNCTION_STANDBY "standby" #define LED_FUNCTION_TORCH "torch" #define LED_FUNCTION_TX "tx" -- cgit v1.2.3-59-g8ed1b From 1fe4f1bf60fdd2110480e8be8b084fcb2b1df656 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Fri, 5 Apr 2024 22:53:08 +0200 Subject: leds: trigger: netdev: Remove not needed call to led_set_brightness in deactivate led_trigger_set() is the only caller of the deactivate() callback, and it calls led_set_brightness(LED_OFF) anyway after deactivate(). So we can remove the call here. Signed-off-by: Heiner Kallweit Link: https://lore.kernel.org/r/8dc929e7-8e14-4c85-aa28-9c5fe2620f52@gmail.com Signed-off-by: Lee Jones --- drivers/leds/trigger/ledtrig-netdev.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/leds/trigger/ledtrig-netdev.c b/drivers/leds/trigger/ledtrig-netdev.c index ea00f6c70882..22bba8e97642 100644 --- a/drivers/leds/trigger/ledtrig-netdev.c +++ b/drivers/leds/trigger/ledtrig-netdev.c @@ -724,8 +724,6 @@ static void netdev_trig_deactivate(struct led_classdev *led_cdev) cancel_delayed_work_sync(&trigger_data->work); - led_set_brightness(led_cdev, LED_OFF); - dev_put(trigger_data->net_dev); kfree(trigger_data); -- cgit v1.2.3-59-g8ed1b From 4bea1ca9e366e1159047279b87334d5cf1bd3adf Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 3 Apr 2024 10:06:33 +0200 Subject: leds: apu: Remove duplicate DMI lookup data Building with W=1 shows a warning about an unused dmi_system_id table: drivers/leds/leds-apu.c:85:35: error: 'apu_led_dmi_table' defined but not used [-Werror=unused-const-variable=] 85 | static const struct dmi_system_id apu_led_dmi_table[] __initconst = { Since the current version doesn't even do anything about the different implementations but only checks the type of system, just drop the custom lookup logic and call dmi_check_system() using the table itself. Signed-off-by: Arnd Bergmann Link: https://lore.kernel.org/r/20240403080702.3509288-16-arnd@kernel.org Signed-off-by: Lee Jones --- drivers/leds/leds-apu.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/leds/leds-apu.c b/drivers/leds/leds-apu.c index c409b80c236d..1c116aaa9b6e 100644 --- a/drivers/leds/leds-apu.c +++ b/drivers/leds/leds-apu.c @@ -181,8 +181,7 @@ static int __init apu_led_init(void) struct platform_device *pdev; int err; - if (!(dmi_match(DMI_SYS_VENDOR, "PC Engines") && - (dmi_match(DMI_PRODUCT_NAME, "APU") || dmi_match(DMI_PRODUCT_NAME, "apu1")))) { + if (!dmi_check_system(apu_led_dmi_table)) { pr_err("No PC Engines APUv1 board detected. For APUv2,3 support, enable CONFIG_PCENGINES_APU2\n"); return -ENODEV; } -- cgit v1.2.3-59-g8ed1b From 2573c25e2c482b53b6e1142ff3cd28f6de13e659 Mon Sep 17 00:00:00 2001 From: Gianluca Boiano Date: Tue, 2 Apr 2024 14:35:42 +0200 Subject: leds: qcom-lpg: Add support for PMI8950 PWM The PMI8950 PMIC contains 1 PWM channel Signed-off-by: Gianluca Boiano Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20240402-pmi8950-pwm-support-v1-1-1a66899eeeb3@gmail.com Signed-off-by: Lee Jones --- drivers/leds/rgb/leds-qcom-lpg.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/leds/rgb/leds-qcom-lpg.c b/drivers/leds/rgb/leds-qcom-lpg.c index 6bdc5b923f98..9467c796bd04 100644 --- a/drivers/leds/rgb/leds-qcom-lpg.c +++ b/drivers/leds/rgb/leds-qcom-lpg.c @@ -1693,6 +1693,13 @@ static const struct lpg_data pm8941_lpg_data = { }, }; +static const struct lpg_data pmi8950_pwm_data = { + .num_channels = 1, + .channels = (const struct lpg_channel_data[]) { + { .base = 0xb000 }, + }, +}; + static const struct lpg_data pm8994_lpg_data = { .lut_base = 0xb000, .lut_size = 64, @@ -1819,6 +1826,7 @@ static const struct of_device_id lpg_of_table[] = { { .compatible = "qcom,pm8941-lpg", .data = &pm8941_lpg_data }, { .compatible = "qcom,pm8994-lpg", .data = &pm8994_lpg_data }, { .compatible = "qcom,pmi632-lpg", .data = &pmi632_lpg_data }, + { .compatible = "qcom,pmi8950-pwm", .data = &pmi8950_pwm_data }, { .compatible = "qcom,pmi8994-lpg", .data = &pmi8994_lpg_data }, { .compatible = "qcom,pmi8998-lpg", .data = &pmi8998_lpg_data }, { .compatible = "qcom,pmc8180c-lpg", .data = &pm8150l_lpg_data }, -- cgit v1.2.3-59-g8ed1b From fc3b23faa14371182ca8a3806854f0db827cb91f Mon Sep 17 00:00:00 2001 From: Gianluca Boiano Date: Tue, 2 Apr 2024 14:35:44 +0200 Subject: dt-bindings: leds: leds-qcom-lpg: Add support for PMI8950 PWM Update leds-qcom-lpg binding to support PMI8950 PWM. Signed-off-by: Gianluca Boiano Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20240402-pmi8950-pwm-support-v1-3-1a66899eeeb3@gmail.com Signed-off-by: Lee Jones --- Documentation/devicetree/bindings/leds/leds-qcom-lpg.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/leds/leds-qcom-lpg.yaml b/Documentation/devicetree/bindings/leds/leds-qcom-lpg.yaml index 7b9e0ad1ecaa..8b82c45d1a48 100644 --- a/Documentation/devicetree/bindings/leds/leds-qcom-lpg.yaml +++ b/Documentation/devicetree/bindings/leds/leds-qcom-lpg.yaml @@ -27,6 +27,7 @@ properties: - qcom,pm8994-lpg - qcom,pmc8180c-lpg - qcom,pmi632-lpg + - qcom,pmi8950-pwm - qcom,pmi8994-lpg - qcom,pmi8998-lpg - qcom,pmk8550-pwm @@ -146,6 +147,7 @@ allOf: - qcom,pm8941-lpg - qcom,pm8994-lpg - qcom,pmc8180c-lpg + - qcom,pmi8950-pwm - qcom,pmi8994-lpg - qcom,pmi8998-lpg - qcom,pmk8550-pwm @@ -294,5 +296,3 @@ examples: label = "blue"; }; }; - -... -- cgit v1.2.3-59-g8ed1b From fd05e3698649f253db5476929675a8cd954cb2b8 Mon Sep 17 00:00:00 2001 From: ChiaEn Wu Date: Tue, 9 Apr 2024 18:21:54 +0800 Subject: leds: mt6360: Fix the second LED can not enable torch mode by V4L2 V4L2 will disable strobe mode of the LED device when enable torch mode, but this logic will conflict with the "priv->fled_torch_used" in "mt6360_strobe_set()". So after enabling torch mode of the first LED, the second LED will not be able to enable torch mode correctly. Therefore, at the beginning of "mt6360_strobe_set()", check whether the state of the upcoming change and the current LED device state are the same, so as to avoid the above problem. Signed-off-by: ChiaEn Wu Link: https://lore.kernel.org/r/28FE6F1712799128000.chiaen_wu@richtek.com Signed-off-by: Lee Jones --- drivers/leds/flash/leds-mt6360.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/leds/flash/leds-mt6360.c b/drivers/leds/flash/leds-mt6360.c index a90de82f4568..1b75b4d36834 100644 --- a/drivers/leds/flash/leds-mt6360.c +++ b/drivers/leds/flash/leds-mt6360.c @@ -241,10 +241,20 @@ static int mt6360_strobe_set(struct led_classdev_flash *fl_cdev, bool state) u32 enable_mask = MT6360_STROBEN_MASK | MT6360_FLCSEN_MASK(led->led_no); u32 val = state ? MT6360_FLCSEN_MASK(led->led_no) : 0; u32 prev = priv->fled_strobe_used, curr; - int ret; + int ret = 0; mutex_lock(&priv->lock); + /* + * If the state of the upcoming change is the same as the current LED + * device state, then skip the subsequent code to avoid conflict + * with the flow of turning on LED torch mode in V4L2. + */ + if (state == !!(BIT(led->led_no) & prev)) { + dev_info(lcdev->dev, "No change in strobe state [0x%x]\n", prev); + goto unlock; + } + /* * Only one set of flash control logic, use the flag to avoid torch is * currently used -- cgit v1.2.3-59-g8ed1b From b9251e64a96f87441694d41dbe98ee9349950fe7 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Wed, 10 Apr 2024 17:39:40 +0200 Subject: phy: qcom: qmp-ufs: update SM8650 tables for Gear 4 & 5 Update the SM8650 UFS PHY init tables to support Gear 4 and Gear 5 using the overlays setup (only supported Gear 5 before), and sync back with the latest Qualcomm recommended values. The new recommended values allow a solid 50% bump in sequential read/write benchmarks on the SM8650 QRD & HDK reference boards. Signed-off-by: Neil Armstrong Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20240410-topic-sm8650-upstream-ufs-g5-v1-1-5527c44b37e6@linaro.org Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-qmp-pcs-ufs-v6.h | 4 ++ .../qualcomm/phy-qcom-qmp-qserdes-txrx-ufs-v6.h | 6 ++ drivers/phy/qualcomm/phy-qcom-qmp-ufs.c | 73 +++++++++++++++++----- 3 files changed, 68 insertions(+), 15 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-ufs-v6.h b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-ufs-v6.h index 970cc0667809..f19f9892ed7b 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-ufs-v6.h +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-ufs-v6.h @@ -30,5 +30,9 @@ #define QPHY_V6_PCS_UFS_TX_MID_TERM_CTRL1 0x1f4 #define QPHY_V6_PCS_UFS_MULTI_LANE_CTRL1 0x1fc #define QPHY_V6_PCS_UFS_RX_HSG5_SYNC_WAIT_TIME 0x220 +#define QPHY_V6_PCS_UFS_TX_POST_EMP_LVL_S4 0x240 +#define QPHY_V6_PCS_UFS_TX_POST_EMP_LVL_S5 0x244 +#define QPHY_V6_PCS_UFS_TX_POST_EMP_LVL_S6 0x248 +#define QPHY_V6_PCS_UFS_TX_POST_EMP_LVL_S7 0x24c #endif diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-ufs-v6.h b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-ufs-v6.h index d9a87bd95590..d17a52357965 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-ufs-v6.h +++ b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-ufs-v6.h @@ -25,12 +25,15 @@ #define QSERDES_UFS_V6_RX_UCDR_SO_GAIN_RATE4 0xf0 #define QSERDES_UFS_V6_RX_UCDR_PI_CONTROLS 0xf4 #define QSERDES_UFS_V6_RX_VGA_CAL_MAN_VAL 0x178 +#define QSERDES_UFS_V6_RX_RX_EQU_ADAPTOR_CNTRL4 0x1ac #define QSERDES_UFS_V6_RX_EQ_OFFSET_ADAPTOR_CNTRL1 0x1bc #define QSERDES_UFS_V6_RX_INTERFACE_MODE 0x1e0 #define QSERDES_UFS_V6_RX_OFFSET_ADAPTOR_CNTRL3 0x1c4 #define QSERDES_UFS_V6_RX_MODE_RATE_0_1_B0 0x208 #define QSERDES_UFS_V6_RX_MODE_RATE_0_1_B1 0x20c +#define QSERDES_UFS_V6_RX_MODE_RATE_0_1_B2 0x210 #define QSERDES_UFS_V6_RX_MODE_RATE_0_1_B3 0x214 +#define QSERDES_UFS_V6_RX_MODE_RATE_0_1_B4 0x218 #define QSERDES_UFS_V6_RX_MODE_RATE_0_1_B6 0x220 #define QSERDES_UFS_V6_RX_MODE_RATE2_B3 0x238 #define QSERDES_UFS_V6_RX_MODE_RATE2_B6 0x244 @@ -38,6 +41,9 @@ #define QSERDES_UFS_V6_RX_MODE_RATE3_B4 0x260 #define QSERDES_UFS_V6_RX_MODE_RATE3_B5 0x264 #define QSERDES_UFS_V6_RX_MODE_RATE3_B8 0x270 +#define QSERDES_UFS_V6_RX_MODE_RATE4_B0 0x274 +#define QSERDES_UFS_V6_RX_MODE_RATE4_B1 0x278 +#define QSERDES_UFS_V6_RX_MODE_RATE4_B2 0x27c #define QSERDES_UFS_V6_RX_MODE_RATE4_B3 0x280 #define QSERDES_UFS_V6_RX_MODE_RATE4_B4 0x284 #define QSERDES_UFS_V6_RX_MODE_RATE4_B6 0x28c diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c index ddc0def0ae61..a57e8a4657f4 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c @@ -862,17 +862,20 @@ static const struct qmp_phy_init_tbl sm8650_ufsphy_serdes[] = { QMP_PHY_INIT_CFG(QSERDES_V6_COM_HSCLK_SEL_1, 0x11), QMP_PHY_INIT_CFG(QSERDES_V6_COM_HSCLK_HS_SWITCH_SEL_1, 0x00), QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP_EN, 0x01), - QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_IVCO, 0x0f), - QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_MAP, 0x44), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_IVCO, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_IVCO_MODE1, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CMN_IETRIM, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CMN_IPTRIM, 0x17), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_MAP, 0x04), QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_INITVAL2, 0x00), QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE0, 0x41), - QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE0, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE0, 0x06), QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_RCTRL_MODE0, 0x18), QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_CCTRL_MODE0, 0x14), QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP1_MODE0, 0x7f), QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP2_MODE0, 0x06), QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE1, 0x4c), - QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE1, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE1, 0x06), QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_RCTRL_MODE1, 0x18), QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_CCTRL_MODE1, 0x14), QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP1_MODE1, 0x99), @@ -880,17 +883,28 @@ static const struct qmp_phy_init_tbl sm8650_ufsphy_serdes[] = { }; static const struct qmp_phy_init_tbl sm8650_ufsphy_tx[] = { - QMP_PHY_INIT_CFG(QSERDES_UFS_V6_TX_LANE_MODE_1, 0x05), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_TX_LANE_MODE_1, 0x01), QMP_PHY_INIT_CFG(QSERDES_UFS_V6_TX_RES_CODE_LANE_OFFSET_TX, 0x07), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_TX_RES_CODE_LANE_OFFSET_RX, 0x0e), }; static const struct qmp_phy_init_tbl sm8650_ufsphy_rx[] = { QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_FO_GAIN_RATE2, 0x0c), - QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_FO_GAIN_RATE4, 0x0f), - QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_VGA_CAL_MAN_VAL, 0x0e), - QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE_0_1_B0, 0xc2), - QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE_0_1_B1, 0xc2), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_FO_GAIN_RATE4, 0x0c), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_SO_GAIN_RATE4, 0x04), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x14), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_PI_CONTROLS, 0x07), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_OFFSET_ADAPTOR_CNTRL3, 0x0e), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_FASTLOCK_COUNT_HIGH_RATE4, 0x02), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_FASTLOCK_FO_GAIN_RATE4, 0x1c), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_FASTLOCK_SO_GAIN_RATE4, 0x06), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_VGA_CAL_MAN_VAL, 0x3e), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_RX_EQU_ADAPTOR_CNTRL4, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE_0_1_B0, 0xce), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE_0_1_B1, 0xce), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE_0_1_B2, 0x18), QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE_0_1_B3, 0x1a), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE_0_1_B4, 0x0f), QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE_0_1_B6, 0x60), QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE2_B3, 0x9e), QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE2_B6, 0x60), @@ -898,23 +912,41 @@ static const struct qmp_phy_init_tbl sm8650_ufsphy_rx[] = { QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE3_B4, 0x0e), QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE3_B5, 0x36), QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE3_B8, 0x02), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE4_B0, 0x24), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE4_B1, 0x24), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE4_B2, 0x20), QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE4_B3, 0xb9), - QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE4_B6, 0xff), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE4_B4, 0x4f), QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_SO_SATURATION, 0x1f), QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_PI_CTRL1, 0x94), QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_RX_TERM_BW_CTRL0, 0xfa), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_DLL0_FTUNE_CTRL, 0x30), }; static const struct qmp_phy_init_tbl sm8650_ufsphy_pcs[] = { - QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_MULTI_LANE_CTRL1, 0x00), + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_MULTI_LANE_CTRL1, 0x02), QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_MID_TERM_CTRL1, 0x43), QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_PCS_CTRL1, 0xc1), - QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_PLL_CNTL, 0x33), + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_LARGE_AMP_DRV_LVL, 0x0f), + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_SIGDET_CTRL2, 0x68), + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_POST_EMP_LVL_S4, 0x0e), + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_POST_EMP_LVL_S5, 0x12), + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_POST_EMP_LVL_S6, 0x15), + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_POST_EMP_LVL_S7, 0x19), +}; + +static const struct qmp_phy_init_tbl sm8650_ufsphy_g4_pcs[] = { + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_PLL_CNTL, 0x13), QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_HSGEAR_CAPABILITY, 0x04), QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_HSGEAR_CAPABILITY, 0x04), - QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_LARGE_AMP_DRV_LVL, 0x0f), - QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_SIGDET_CTRL2, 0x69), - QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_MULTI_LANE_CTRL1, 0x02), +}; + +static const struct qmp_phy_init_tbl sm8650_ufsphy_g5_pcs[] = { + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_PLL_CNTL, 0x33), + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_HSGEAR_CAPABILITY, 0x05), + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_HSGEAR_CAPABILITY, 0x05), + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_HS_G5_SYNC_LENGTH_CAPABILITY, 0x4d), + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_HSG5_SYNC_WAIT_TIME, 0x9e), }; struct qmp_ufs_offsets { @@ -1475,6 +1507,17 @@ static const struct qmp_phy_cfg sm8650_ufsphy_cfg = { .pcs = sm8650_ufsphy_pcs, .pcs_num = ARRAY_SIZE(sm8650_ufsphy_pcs), }, + .tbls_hs_overlay[0] = { + .pcs = sm8650_ufsphy_g4_pcs, + .pcs_num = ARRAY_SIZE(sm8650_ufsphy_g4_pcs), + .max_gear = UFS_HS_G4, + }, + .tbls_hs_overlay[1] = { + .pcs = sm8650_ufsphy_g5_pcs, + .pcs_num = ARRAY_SIZE(sm8650_ufsphy_g5_pcs), + .max_gear = UFS_HS_G5, + }, + .vreg_list = qmp_phy_vreg_l, .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), .regs = ufsphy_v6_regs_layout, -- cgit v1.2.3-59-g8ed1b From c49de54c6224103ab9c4b98464b03ab82721839a Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Tue, 9 Apr 2024 18:15:06 +0200 Subject: phy: freescale: fsl-samsung-hdmi: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20240409161505.66619-2-u.kleine-koenig@pengutronix.de Signed-off-by: Vinod Koul --- drivers/phy/freescale/phy-fsl-samsung-hdmi.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/phy/freescale/phy-fsl-samsung-hdmi.c b/drivers/phy/freescale/phy-fsl-samsung-hdmi.c index 89e2c01f2ccf..9048cdc760c2 100644 --- a/drivers/phy/freescale/phy-fsl-samsung-hdmi.c +++ b/drivers/phy/freescale/phy-fsl-samsung-hdmi.c @@ -657,11 +657,9 @@ register_clk_failed: return ret; } -static int fsl_samsung_hdmi_phy_remove(struct platform_device *pdev) +static void fsl_samsung_hdmi_phy_remove(struct platform_device *pdev) { of_clk_del_provider(pdev->dev.of_node); - - return 0; } static int __maybe_unused fsl_samsung_hdmi_phy_suspend(struct device *dev) @@ -706,7 +704,7 @@ MODULE_DEVICE_TABLE(of, fsl_samsung_hdmi_phy_of_match); static struct platform_driver fsl_samsung_hdmi_phy_driver = { .probe = fsl_samsung_hdmi_phy_probe, - .remove = fsl_samsung_hdmi_phy_remove, + .remove_new = fsl_samsung_hdmi_phy_remove, .driver = { .name = "fsl-samsung-hdmi-phy", .of_match_table = fsl_samsung_hdmi_phy_of_match, -- cgit v1.2.3-59-g8ed1b From f482f76c9d0933b91f32f170fbc421a4d0ebaf56 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Tue, 9 Apr 2024 03:23:54 +0100 Subject: dt-bindings: phy: mediatek,mt7988-xfi-tphy: add new bindings Add bindings for the MediaTek XFI Ethernet SerDes T-PHY found in the MediaTek MT7988 SoC which can operate at various interfaces modes: via USXGMII PCS: * USXGMII * 10GBase-R * 5GBase-R via LynxI SGMII PCS: * 2500Base-X * 1000Base-X * Cisco SGMII (MAC side) Signed-off-by: Daniel Golle Reviewed-by: AngeloGioacchino Del Regno Reviewed-by: Krzysztof Kozlowski Reviewed-by: Jacob Keller Link: https://lore.kernel.org/r/da5498096f71a40ca1eac4124b7bb601c82396fb.1712625857.git.daniel@makrotopia.org Signed-off-by: Vinod Koul --- .../bindings/phy/mediatek,mt7988-xfi-tphy.yaml | 80 ++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 Documentation/devicetree/bindings/phy/mediatek,mt7988-xfi-tphy.yaml diff --git a/Documentation/devicetree/bindings/phy/mediatek,mt7988-xfi-tphy.yaml b/Documentation/devicetree/bindings/phy/mediatek,mt7988-xfi-tphy.yaml new file mode 100644 index 000000000000..cfb3ca97f87c --- /dev/null +++ b/Documentation/devicetree/bindings/phy/mediatek,mt7988-xfi-tphy.yaml @@ -0,0 +1,80 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/phy/mediatek,mt7988-xfi-tphy.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MediaTek MT7988 XFI T-PHY + +maintainers: + - Daniel Golle + +description: + The MediaTek XFI SerDes T-PHY provides the physical SerDes lanes + used by the (10G/5G) USXGMII PCS and (1G/2.5G) LynxI PCS found in + MediaTek's 10G-capabale MT7988 SoC. + In MediaTek's SDK sources, this unit is referred to as "pextp". + +properties: + compatible: + const: mediatek,mt7988-xfi-tphy + + reg: + maxItems: 1 + + clocks: + items: + - description: XFI PHY clock + - description: XFI register clock + + clock-names: + items: + - const: xfipll + - const: topxtal + + resets: + items: + - description: Reset controller corresponding to the phy instance. + + mediatek,usxgmii-performance-errata: + $ref: /schemas/types.yaml#/definitions/flag + description: + One instance of the T-PHY on MT7988 suffers from a performance + problem in 10GBase-R mode which needs a work-around in the driver. + This flag enables a work-around ajusting an analog phy setting and + is required for XFI Port0 of the MT7988 SoC to be in compliance with + the SFP specification. + + "#phy-cells": + const: 0 + +required: + - compatible + - reg + - clocks + - clock-names + - resets + - "#phy-cells" + +additionalProperties: false + +examples: + - | + #include + soc { + #address-cells = <2>; + #size-cells = <2>; + + phy@11f20000 { + compatible = "mediatek,mt7988-xfi-tphy"; + reg = <0 0x11f20000 0 0x10000>; + clocks = <&xfi_pll CLK_XFIPLL_PLL_EN>, + <&topckgen CLK_TOP_XFI_PHY_0_XTAL_SEL>; + clock-names = "xfipll", "topxtal"; + resets = <&watchdog 14>; + mediatek,usxgmii-performance-errata; + #phy-cells = <0>; + }; + }; + +... -- cgit v1.2.3-59-g8ed1b From ac4aa9dbc702329c447d968325b055af84ae1b59 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Tue, 9 Apr 2024 03:24:12 +0100 Subject: phy: add driver for MediaTek XFI T-PHY Add driver for MediaTek's XFI T-PHY which can be found in the MT7988 SoC. The XFI T-PHY is a 10 Gigabit/s Ethernet SerDes PHY with muxes on the internal side to be used with either USXGMII PCS or LynxI PCS, depending on the selected PHY interface mode. The PHY can operates only in PHY_MODE_ETHERNET, the submode is one of PHY_INTERFACE_MODE_* corresponding to the supported modes: * USXGMII \ * 10GBase-R }- USXGMII PCS - XGDM \ * 5GBase-R / \ }- Ethernet MAC * 2500Base-X \ / * 1000Base-X }- LynxI PCS - GDM / * Cisco SGMII (MAC side) / I chose the name XFI T-PHY because names of functions dealing with the phy in the vendor driver are prefixed "xfi_pextp_". The register space used by the phy is called "pextp" in the vendor sources, which could be read as "_P_CI _ex_press _T_-_P_hy", and that is quite misleading as this phy isn't used for anything related to PCIe, so I wanted to find a better name. XFI is still somehow related (as in: you would find the relevant places using grep in the vendor driver when looking for that) and the term seemed to at least somehow be aligned with the function of that phy: Dealing with (up to) 10 Gbit/s Ethernet serialized differential signals. In order to work-around a performance issue present on the first of two XFI T-PHYs found in MT7988, special tuning is applied which can be selected by adding the 'mediatek,usxgmii-performance-errata' property to the device tree node, similar to how the vendor driver is doing that too. There is no documentation for most registers used for the analog/tuning part, however, most of the registers have been partially reverse-engineered from MediaTek's SDK implementation (see links, an opaque sequence of 32-bit register writes) and descriptions for all relevant digital registers and bits such as resets and muxes have been supplied by MediaTek. Link: https://git01.mediatek.com/plugins/gitiles/openwrt/feeds/mtk-openwrt-feeds/+/b72d6cba92bf9e29fb035c03052fa1e86664a25b/21.02/files/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_sgmii.c Link: https://git01.mediatek.com/plugins/gitiles/openwrt/feeds/mtk-openwrt-feeds/+/dec96a1d9b82cdcda4a56453fd0b453d4cab4b85/21.02/files/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.c Signed-off-by: Daniel Golle Reviewed-by: AngeloGioacchino Del Regno Reviewed-by: Jacob Keller Link: https://lore.kernel.org/r/8719c82634df7e8e984f1a608be3ba2f2d494fb4.1712625857.git.daniel@makrotopia.org Signed-off-by: Vinod Koul --- MAINTAINERS | 1 + drivers/phy/mediatek/Kconfig | 11 + drivers/phy/mediatek/Makefile | 1 + drivers/phy/mediatek/phy-mtk-xfi-tphy.c | 451 ++++++++++++++++++++++++++++++++ 4 files changed, 464 insertions(+) create mode 100644 drivers/phy/mediatek/phy-mtk-xfi-tphy.c diff --git a/MAINTAINERS b/MAINTAINERS index 7debfc40df50..9b6d7487e8e0 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -13781,6 +13781,7 @@ L: netdev@vger.kernel.org S: Maintained F: drivers/net/phy/mediatek-ge-soc.c F: drivers/net/phy/mediatek-ge.c +F: drivers/phy/mediatek/phy-mtk-xfi-tphy.c MEDIATEK I2C CONTROLLER DRIVER M: Qii Wang diff --git a/drivers/phy/mediatek/Kconfig b/drivers/phy/mediatek/Kconfig index 3849b7c87d28..60e00057e8bc 100644 --- a/drivers/phy/mediatek/Kconfig +++ b/drivers/phy/mediatek/Kconfig @@ -13,6 +13,17 @@ config PHY_MTK_PCIE callback for PCIe GEN3 port, it supports software efuse initialization. +config PHY_MTK_XFI_TPHY + tristate "MediaTek 10GE SerDes XFI T-PHY driver" + depends on ARCH_MEDIATEK || COMPILE_TEST + depends on OF + select GENERIC_PHY + help + Say 'Y' here to add support for MediaTek XFI T-PHY driver. + The driver provides access to the Ethernet SerDes T-PHY supporting + 1GE and 2.5GE modes via the LynxI PCS, and 5GE and 10GE modes + via the USXGMII PCS found in MediaTek SoCs with 10G Ethernet. + config PHY_MTK_TPHY tristate "MediaTek T-PHY Driver" depends on ARCH_MEDIATEK || COMPILE_TEST diff --git a/drivers/phy/mediatek/Makefile b/drivers/phy/mediatek/Makefile index f6e24a47e081..1b8088df71e8 100644 --- a/drivers/phy/mediatek/Makefile +++ b/drivers/phy/mediatek/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_PHY_MTK_PCIE) += phy-mtk-pcie.o obj-$(CONFIG_PHY_MTK_TPHY) += phy-mtk-tphy.o obj-$(CONFIG_PHY_MTK_UFS) += phy-mtk-ufs.o obj-$(CONFIG_PHY_MTK_XSPHY) += phy-mtk-xsphy.o +obj-$(CONFIG_PHY_MTK_XFI_TPHY) += phy-mtk-xfi-tphy.o phy-mtk-hdmi-drv-y := phy-mtk-hdmi.o phy-mtk-hdmi-drv-y += phy-mtk-hdmi-mt2701.o diff --git a/drivers/phy/mediatek/phy-mtk-xfi-tphy.c b/drivers/phy/mediatek/phy-mtk-xfi-tphy.c new file mode 100644 index 000000000000..1a0b7484f525 --- /dev/null +++ b/drivers/phy/mediatek/phy-mtk-xfi-tphy.c @@ -0,0 +1,451 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * MediaTek 10GE SerDes XFI T-PHY driver + * + * Copyright (c) 2024 Daniel Golle + * Bc-bocun Chen + * based on mtk_usxgmii.c and mtk_sgmii.c found in MediaTek's SDK (GPL-2.0) + * Copyright (c) 2022 MediaTek Inc. + * Author: Henry Yen + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "phy-mtk-io.h" + +#define MTK_XFI_TPHY_NUM_CLOCKS 2 + +#define REG_DIG_GLB_70 0x0070 +#define XTP_PCS_RX_EQ_IN_PROGRESS(x) FIELD_PREP(GENMASK(25, 24), (x)) +#define XTP_PCS_MODE_MASK GENMASK(17, 16) +#define XTP_PCS_MODE(x) FIELD_PREP(GENMASK(17, 16), (x)) +#define XTP_PCS_RST_B BIT(15) +#define XTP_FRC_PCS_RST_B BIT(14) +#define XTP_PCS_PWD_SYNC_MASK GENMASK(13, 12) +#define XTP_PCS_PWD_SYNC(x) FIELD_PREP(XTP_PCS_PWD_SYNC_MASK, (x)) +#define XTP_PCS_PWD_ASYNC_MASK GENMASK(11, 10) +#define XTP_PCS_PWD_ASYNC(x) FIELD_PREP(XTP_PCS_PWD_ASYNC_MASK, (x)) +#define XTP_FRC_PCS_PWD_ASYNC BIT(8) +#define XTP_PCS_UPDT BIT(4) +#define XTP_PCS_IN_FR_RG BIT(0) + +#define REG_DIG_GLB_F4 0x00f4 +#define XFI_DPHY_PCS_SEL BIT(0) +#define XFI_DPHY_PCS_SEL_SGMII FIELD_PREP(XFI_DPHY_PCS_SEL, 1) +#define XFI_DPHY_PCS_SEL_USXGMII FIELD_PREP(XFI_DPHY_PCS_SEL, 0) +#define XFI_DPHY_AD_SGDT_FRC_EN BIT(5) + +#define REG_DIG_LN_TRX_40 0x3040 +#define XTP_LN_FRC_TX_DATA_EN BIT(29) +#define XTP_LN_TX_DATA_EN BIT(28) + +#define REG_DIG_LN_TRX_B0 0x30b0 +#define XTP_LN_FRC_TX_MACCK_EN BIT(5) +#define XTP_LN_TX_MACCK_EN BIT(4) + +#define REG_ANA_GLB_D0 0x90d0 +#define XTP_GLB_USXGMII_SEL_MASK GENMASK(3, 1) +#define XTP_GLB_USXGMII_SEL(x) FIELD_PREP(GENMASK(3, 1), (x)) +#define XTP_GLB_USXGMII_EN BIT(0) + +/** + * struct mtk_xfi_tphy - run-time data of the XFI phy instance + * @base: IO memory area to access phy registers. + * @dev: Kernel device used to output prefixed debug info. + * @reset: Reset control corresponding to the phy instance. + * @clocks: All clocks required for the phy to operate. + * @da_war: Enables work-around for 10GBase-R mode. + */ +struct mtk_xfi_tphy { + void __iomem *base; + struct device *dev; + struct reset_control *reset; + struct clk_bulk_data clocks[MTK_XFI_TPHY_NUM_CLOCKS]; + bool da_war; +}; + +/** + * mtk_xfi_tphy_setup() - Setup phy for specified interface mode. + * @xfi_tphy: XFI phy instance. + * @interface: Ethernet interface mode + * + * The setup function is the condensed result of combining the 5 functions which + * setup the phy in MediaTek's GPL licensed public SDK sources. They can be found + * in mtk_sgmii.c[1] as well as mtk_usxgmii.c[2]. + * + * Many magic values have been replaced by register and bit definitions, however, + * that has not been possible in all cases. While the vendor driver uses a + * sequence of 32-bit writes, here we try to only modify the actually required + * bits. + * + * [1]: https://git01.mediatek.com/plugins/gitiles/openwrt/feeds/mtk-openwrt-feeds/+/b72d6cba92bf9e29fb035c03052fa1e86664a25b/21.02/files/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_sgmii.c + * + * [2]: https://git01.mediatek.com/plugins/gitiles/openwrt/feeds/mtk-openwrt-feeds/+/dec96a1d9b82cdcda4a56453fd0b453d4cab4b85/21.02/files/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.c + */ +static void mtk_xfi_tphy_setup(struct mtk_xfi_tphy *xfi_tphy, + phy_interface_t interface) +{ + bool is_1g, is_2p5g, is_5g, is_10g, da_war, use_lynxi_pcs; + + /* shorthands for specific clock speeds depending on interface mode */ + is_1g = interface == PHY_INTERFACE_MODE_1000BASEX || + interface == PHY_INTERFACE_MODE_SGMII; + is_2p5g = interface == PHY_INTERFACE_MODE_2500BASEX; + is_5g = interface == PHY_INTERFACE_MODE_5GBASER; + is_10g = interface == PHY_INTERFACE_MODE_10GBASER || + interface == PHY_INTERFACE_MODE_USXGMII; + + /* Is overriding 10GBase-R tuning value required? */ + da_war = xfi_tphy->da_war && (interface == PHY_INTERFACE_MODE_10GBASER); + + /* configure input mux to either + * - USXGMII PCS (64b/66b coding) for 5G/10G + * - LynxI PCS (8b/10b coding) for 1G/2.5G + */ + use_lynxi_pcs = is_1g || is_2p5g; + + dev_dbg(xfi_tphy->dev, "setting up for mode %s\n", phy_modes(interface)); + + /* Setup PLL setting */ + mtk_phy_update_bits(xfi_tphy->base + 0x9024, 0x100000, is_10g ? 0x0 : 0x100000); + mtk_phy_update_bits(xfi_tphy->base + 0x2020, 0x202000, is_5g ? 0x202000 : 0x0); + mtk_phy_update_bits(xfi_tphy->base + 0x2030, 0x500, is_1g ? 0x0 : 0x500); + mtk_phy_update_bits(xfi_tphy->base + 0x2034, 0xa00, is_1g ? 0x0 : 0xa00); + mtk_phy_update_bits(xfi_tphy->base + 0x2040, 0x340000, is_1g ? 0x200000 : 0x140000); + + /* Setup RXFE BW setting */ + mtk_phy_update_bits(xfi_tphy->base + 0x50f0, 0xc10, is_1g ? 0x410 : is_5g ? 0x800 : 0x400); + mtk_phy_update_bits(xfi_tphy->base + 0x50e0, 0x4000, is_5g ? 0x0 : 0x4000); + + /* Setup RX CDR setting */ + mtk_phy_update_bits(xfi_tphy->base + 0x506c, 0x30000, is_5g ? 0x0 : 0x30000); + mtk_phy_update_bits(xfi_tphy->base + 0x5070, 0x670000, is_5g ? 0x620000 : 0x50000); + mtk_phy_update_bits(xfi_tphy->base + 0x5074, 0x180000, is_5g ? 0x180000 : 0x0); + mtk_phy_update_bits(xfi_tphy->base + 0x5078, 0xf000400, is_5g ? 0x8000000 : + 0x7000400); + mtk_phy_update_bits(xfi_tphy->base + 0x507c, 0x5000500, is_5g ? 0x4000400 : + 0x1000100); + mtk_phy_update_bits(xfi_tphy->base + 0x5080, 0x1410, is_1g ? 0x400 : is_5g ? 0x1010 : 0x0); + mtk_phy_update_bits(xfi_tphy->base + 0x5084, 0x30300, is_1g ? 0x30300 : + is_5g ? 0x30100 : + 0x100); + mtk_phy_update_bits(xfi_tphy->base + 0x5088, 0x60200, is_1g ? 0x20200 : + is_5g ? 0x40000 : + 0x20000); + + /* Setting RXFE adaptation range setting */ + mtk_phy_update_bits(xfi_tphy->base + 0x50e4, 0xc0000, is_5g ? 0x0 : 0xc0000); + mtk_phy_update_bits(xfi_tphy->base + 0x50e8, 0x40000, is_5g ? 0x0 : 0x40000); + mtk_phy_update_bits(xfi_tphy->base + 0x50ec, 0xa00, is_1g ? 0x200 : 0x800); + mtk_phy_update_bits(xfi_tphy->base + 0x50a8, 0xee0000, is_5g ? 0x800000 : + 0x6e0000); + mtk_phy_update_bits(xfi_tphy->base + 0x6004, 0x190000, is_5g ? 0x0 : 0x190000); + + if (is_10g) + writel(0x01423342, xfi_tphy->base + 0x00f8); + else if (is_5g) + writel(0x00a132a1, xfi_tphy->base + 0x00f8); + else if (is_2p5g) + writel(0x009c329c, xfi_tphy->base + 0x00f8); + else + writel(0x00fa32fa, xfi_tphy->base + 0x00f8); + + /* Force SGDT_OUT off and select PCS */ + mtk_phy_update_bits(xfi_tphy->base + REG_DIG_GLB_F4, + XFI_DPHY_AD_SGDT_FRC_EN | XFI_DPHY_PCS_SEL, + XFI_DPHY_AD_SGDT_FRC_EN | + (use_lynxi_pcs ? XFI_DPHY_PCS_SEL_SGMII : + XFI_DPHY_PCS_SEL_USXGMII)); + + /* Force GLB_CKDET_OUT */ + mtk_phy_set_bits(xfi_tphy->base + 0x0030, 0xc00); + + /* Force AEQ on */ + writel(XTP_PCS_RX_EQ_IN_PROGRESS(2) | XTP_PCS_PWD_SYNC(2) | XTP_PCS_PWD_ASYNC(2), + xfi_tphy->base + REG_DIG_GLB_70); + + usleep_range(1, 5); + writel(XTP_LN_FRC_TX_DATA_EN, xfi_tphy->base + REG_DIG_LN_TRX_40); + + /* Setup TX DA default value */ + mtk_phy_update_bits(xfi_tphy->base + 0x30b0, 0x30, 0x20); + writel(0x00008a01, xfi_tphy->base + 0x3028); + writel(0x0000a884, xfi_tphy->base + 0x302c); + writel(0x00083002, xfi_tphy->base + 0x3024); + + /* Setup RG default value */ + if (use_lynxi_pcs) { + writel(0x00011110, xfi_tphy->base + 0x3010); + writel(0x40704000, xfi_tphy->base + 0x3048); + } else { + writel(0x00022220, xfi_tphy->base + 0x3010); + writel(0x0f020a01, xfi_tphy->base + 0x5064); + writel(0x06100600, xfi_tphy->base + 0x50b4); + if (interface == PHY_INTERFACE_MODE_USXGMII) + writel(0x40704000, xfi_tphy->base + 0x3048); + else + writel(0x47684100, xfi_tphy->base + 0x3048); + } + + if (is_1g) + writel(0x0000c000, xfi_tphy->base + 0x3064); + + /* Setup RX EQ initial value */ + mtk_phy_update_bits(xfi_tphy->base + 0x3050, 0xa8000000, + (interface != PHY_INTERFACE_MODE_10GBASER) ? 0xa8000000 : 0x0); + mtk_phy_update_bits(xfi_tphy->base + 0x3054, 0xaa, + (interface != PHY_INTERFACE_MODE_10GBASER) ? 0xaa : 0x0); + + if (!use_lynxi_pcs) + writel(0x00000f00, xfi_tphy->base + 0x306c); + else if (is_2p5g) + writel(0x22000f00, xfi_tphy->base + 0x306c); + else + writel(0x20200f00, xfi_tphy->base + 0x306c); + + mtk_phy_update_bits(xfi_tphy->base + 0xa008, 0x10000, da_war ? 0x10000 : 0x0); + + mtk_phy_update_bits(xfi_tphy->base + 0xa060, 0x50000, use_lynxi_pcs ? 0x50000 : 0x40000); + + /* Setup PHYA speed */ + mtk_phy_update_bits(xfi_tphy->base + REG_ANA_GLB_D0, + XTP_GLB_USXGMII_SEL_MASK | XTP_GLB_USXGMII_EN, + is_10g ? XTP_GLB_USXGMII_SEL(0) : + is_5g ? XTP_GLB_USXGMII_SEL(1) : + is_2p5g ? XTP_GLB_USXGMII_SEL(2) : + XTP_GLB_USXGMII_SEL(3)); + mtk_phy_set_bits(xfi_tphy->base + REG_ANA_GLB_D0, XTP_GLB_USXGMII_EN); + + /* Release reset */ + mtk_phy_set_bits(xfi_tphy->base + REG_DIG_GLB_70, + XTP_PCS_RST_B | XTP_FRC_PCS_RST_B); + usleep_range(150, 500); + + /* Switch to P0 */ + mtk_phy_update_bits(xfi_tphy->base + REG_DIG_GLB_70, + XTP_PCS_IN_FR_RG | + XTP_FRC_PCS_PWD_ASYNC | + XTP_PCS_PWD_ASYNC_MASK | + XTP_PCS_PWD_SYNC_MASK | + XTP_PCS_UPDT, + XTP_PCS_IN_FR_RG | + XTP_FRC_PCS_PWD_ASYNC | + XTP_PCS_UPDT); + usleep_range(1, 5); + + mtk_phy_clear_bits(xfi_tphy->base + REG_DIG_GLB_70, XTP_PCS_UPDT); + usleep_range(15, 50); + + if (use_lynxi_pcs) { + /* Switch to Gen2 */ + mtk_phy_update_bits(xfi_tphy->base + REG_DIG_GLB_70, + XTP_PCS_MODE_MASK | XTP_PCS_UPDT, + XTP_PCS_MODE(1) | XTP_PCS_UPDT); + } else { + /* Switch to Gen3 */ + mtk_phy_update_bits(xfi_tphy->base + REG_DIG_GLB_70, + XTP_PCS_MODE_MASK | XTP_PCS_UPDT, + XTP_PCS_MODE(2) | XTP_PCS_UPDT); + } + usleep_range(1, 5); + + mtk_phy_clear_bits(xfi_tphy->base + REG_DIG_GLB_70, XTP_PCS_UPDT); + + usleep_range(100, 500); + + /* Enable MAC CK */ + mtk_phy_set_bits(xfi_tphy->base + REG_DIG_LN_TRX_B0, XTP_LN_TX_MACCK_EN); + mtk_phy_clear_bits(xfi_tphy->base + REG_DIG_GLB_F4, XFI_DPHY_AD_SGDT_FRC_EN); + + /* Enable TX data */ + mtk_phy_set_bits(xfi_tphy->base + REG_DIG_LN_TRX_40, + XTP_LN_FRC_TX_DATA_EN | XTP_LN_TX_DATA_EN); + usleep_range(400, 1000); +} + +/** + * mtk_xfi_tphy_set_mode() - Setup phy for specified interface mode. + * + * @phy: Phy instance. + * @mode: Only PHY_MODE_ETHERNET is supported. + * @submode: An Ethernet interface mode. + * + * Validate selected mode and call function mtk_xfi_tphy_setup(). + * + * Return: + * * %0 - OK + * * %-EINVAL - invalid mode + */ +static int mtk_xfi_tphy_set_mode(struct phy *phy, enum phy_mode mode, int + submode) +{ + struct mtk_xfi_tphy *xfi_tphy = phy_get_drvdata(phy); + + if (mode != PHY_MODE_ETHERNET) + return -EINVAL; + + switch (submode) { + case PHY_INTERFACE_MODE_1000BASEX: + case PHY_INTERFACE_MODE_2500BASEX: + case PHY_INTERFACE_MODE_SGMII: + case PHY_INTERFACE_MODE_5GBASER: + case PHY_INTERFACE_MODE_10GBASER: + case PHY_INTERFACE_MODE_USXGMII: + mtk_xfi_tphy_setup(xfi_tphy, submode); + return 0; + default: + return -EINVAL; + } +} + +/** + * mtk_xfi_tphy_reset() - Reset the phy. + * + * @phy: Phy instance. + * + * Reset the phy using the external reset controller. + * + * Return: + * %0 - OK + */ +static int mtk_xfi_tphy_reset(struct phy *phy) +{ + struct mtk_xfi_tphy *xfi_tphy = phy_get_drvdata(phy); + + reset_control_assert(xfi_tphy->reset); + usleep_range(100, 500); + reset_control_deassert(xfi_tphy->reset); + usleep_range(1, 10); + + return 0; +} + +/** + * mtk_xfi_tphy_power_on() - Power-on the phy. + * + * @phy: Phy instance. + * + * Prepare and enable all clocks required for the phy to operate. + * + * Return: + * See clk_bulk_prepare_enable(). + */ +static int mtk_xfi_tphy_power_on(struct phy *phy) +{ + struct mtk_xfi_tphy *xfi_tphy = phy_get_drvdata(phy); + + return clk_bulk_prepare_enable(MTK_XFI_TPHY_NUM_CLOCKS, xfi_tphy->clocks); +} + +/** + * mtk_xfi_tphy_power_off() - Power-off the phy. + * + * @phy: Phy instance. + * + * Disable and unprepare all clocks previously enabled. + * + * Return: + * See clk_bulk_prepare_disable(). + */ +static int mtk_xfi_tphy_power_off(struct phy *phy) +{ + struct mtk_xfi_tphy *xfi_tphy = phy_get_drvdata(phy); + + clk_bulk_disable_unprepare(MTK_XFI_TPHY_NUM_CLOCKS, xfi_tphy->clocks); + + return 0; +} + +static const struct phy_ops mtk_xfi_tphy_ops = { + .power_on = mtk_xfi_tphy_power_on, + .power_off = mtk_xfi_tphy_power_off, + .set_mode = mtk_xfi_tphy_set_mode, + .reset = mtk_xfi_tphy_reset, + .owner = THIS_MODULE, +}; + +/** + * mtk_xfi_tphy_probe() - Probe phy instance from Device Tree. + * @pdev: Matching platform device. + * + * The probe function gets IO resource, clocks, reset controller and + * whether the DA work-around for 10GBase-R is required from Device Tree and + * allocates memory for holding that information in a struct mtk_xfi_tphy. + * + * Return: + * * %0 - OK + * * %-ENODEV - Missing associated Device Tree node (should never happen). + * * %-ENOMEM - Out of memory. + * * Any error value which devm_platform_ioremap_resource(), + * devm_clk_bulk_get(), devm_reset_control_get_exclusive(), + * devm_phy_create() or devm_of_phy_provider_register() may return. + */ +static int mtk_xfi_tphy_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct phy_provider *phy_provider; + struct mtk_xfi_tphy *xfi_tphy; + struct phy *phy; + int ret; + + if (!np) + return -ENODEV; + + xfi_tphy = devm_kzalloc(&pdev->dev, sizeof(*xfi_tphy), GFP_KERNEL); + if (!xfi_tphy) + return -ENOMEM; + + xfi_tphy->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(xfi_tphy->base)) + return PTR_ERR(xfi_tphy->base); + + xfi_tphy->dev = &pdev->dev; + xfi_tphy->clocks[0].id = "topxtal"; + xfi_tphy->clocks[1].id = "xfipll"; + ret = devm_clk_bulk_get(&pdev->dev, MTK_XFI_TPHY_NUM_CLOCKS, xfi_tphy->clocks); + if (ret) + return ret; + + xfi_tphy->reset = devm_reset_control_get_exclusive(&pdev->dev, NULL); + if (IS_ERR(xfi_tphy->reset)) + return PTR_ERR(xfi_tphy->reset); + + xfi_tphy->da_war = of_property_read_bool(np, "mediatek,usxgmii-performance-errata"); + + phy = devm_phy_create(&pdev->dev, NULL, &mtk_xfi_tphy_ops); + if (IS_ERR(phy)) + return PTR_ERR(phy); + + phy_set_drvdata(phy, xfi_tphy); + phy_provider = devm_of_phy_provider_register(&pdev->dev, of_phy_simple_xlate); + + return PTR_ERR_OR_ZERO(phy_provider); +} + +static const struct of_device_id mtk_xfi_tphy_match[] = { + { .compatible = "mediatek,mt7988-xfi-tphy", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, mtk_xfi_tphy_match); + +static struct platform_driver mtk_xfi_tphy_driver = { + .probe = mtk_xfi_tphy_probe, + .driver = { + .name = "mtk-xfi-tphy", + .of_match_table = mtk_xfi_tphy_match, + }, +}; +module_platform_driver(mtk_xfi_tphy_driver); + +MODULE_DESCRIPTION("MediaTek 10GE SerDes XFI T-PHY driver"); +MODULE_AUTHOR("Daniel Golle "); +MODULE_AUTHOR("Bc-bocun Chen "); +MODULE_LICENSE("GPL"); -- cgit v1.2.3-59-g8ed1b From a75d8056e9fefa82ca2bd75a32febc44411cc5c0 Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Tue, 9 Apr 2024 00:50:28 +0200 Subject: dt-bindings: phy: add rockchip usbdp combo phy document Add device tree binding document for Rockchip USBDP Combo PHY with Samsung IP block. Co-developed-by: Frank Wang Signed-off-by: Frank Wang Reviewed-by: Conor Dooley Reviewed-by: Heiko Stuebner Signed-off-by: Sebastian Reichel Link: https://lore.kernel.org/r/20240408225109.128953-2-sebastian.reichel@collabora.com Signed-off-by: Vinod Koul --- .../bindings/phy/phy-rockchip-usbdp.yaml | 148 +++++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 Documentation/devicetree/bindings/phy/phy-rockchip-usbdp.yaml diff --git a/Documentation/devicetree/bindings/phy/phy-rockchip-usbdp.yaml b/Documentation/devicetree/bindings/phy/phy-rockchip-usbdp.yaml new file mode 100644 index 000000000000..1f1f8863b80d --- /dev/null +++ b/Documentation/devicetree/bindings/phy/phy-rockchip-usbdp.yaml @@ -0,0 +1,148 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/phy/phy-rockchip-usbdp.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Rockchip USBDP Combo PHY with Samsung IP block + +maintainers: + - Frank Wang + - Zhang Yubing + +properties: + compatible: + enum: + - rockchip,rk3588-usbdp-phy + + reg: + maxItems: 1 + + "#phy-cells": + description: | + Cell allows setting the type of the PHY. Possible values are: + - PHY_TYPE_USB3 + - PHY_TYPE_DP + const: 1 + + clocks: + maxItems: 4 + + clock-names: + items: + - const: refclk + - const: immortal + - const: pclk + - const: utmi + + resets: + maxItems: 5 + + reset-names: + items: + - const: init + - const: cmn + - const: lane + - const: pcs_apb + - const: pma_apb + + rockchip,dp-lane-mux: + $ref: /schemas/types.yaml#/definitions/uint32-array + minItems: 2 + maxItems: 4 + items: + maximum: 3 + description: + An array of physical Type-C lanes indexes. Position of an entry + determines the DisplayPort (DP) lane index, while the value of an entry + indicates physical Type-C lane. The supported DP lanes number are 2 or 4. + e.g. for 2 lanes DP lanes map, we could have "rockchip,dp-lane-mux = <2, + 3>;", assuming DP lane0 on Type-C phy lane2, DP lane1 on Type-C phy + lane3. For 4 lanes DP lanes map, we could have "rockchip,dp-lane-mux = + <0, 1, 2, 3>;", assuming DP lane0 on Type-C phy lane0, DP lane1 on Type-C + phy lane1, DP lane2 on Type-C phy lane2, DP lane3 on Type-C phy lane3. If + DP lanes are mapped by DisplayPort Alt mode, this property is not needed. + + rockchip,u2phy-grf: + $ref: /schemas/types.yaml#/definitions/phandle + description: + Phandle to the syscon managing the 'usb2 phy general register files'. + + rockchip,usb-grf: + $ref: /schemas/types.yaml#/definitions/phandle + description: + Phandle to the syscon managing the 'usb general register files'. + + rockchip,usbdpphy-grf: + $ref: /schemas/types.yaml#/definitions/phandle + description: + Phandle to the syscon managing the 'usbdp phy general register files'. + + rockchip,vo-grf: + $ref: /schemas/types.yaml#/definitions/phandle + description: + Phandle to the syscon managing the 'video output general register files'. + When select the DP lane mapping will request its phandle. + + sbu1-dc-gpios: + description: + GPIO connected to the SBU1 line of the USB-C connector via a big resistor + (~100K) to apply a DC offset for signalling the connector orientation. + maxItems: 1 + + sbu2-dc-gpios: + description: + GPIO connected to the SBU2 line of the USB-C connector via a big resistor + (~100K) to apply a DC offset for signalling the connector orientation. + maxItems: 1 + + orientation-switch: + description: Flag the port as possible handler of orientation switching + type: boolean + + mode-switch: + description: Flag the port as possible handler of altmode switching + type: boolean + + port: + $ref: /schemas/graph.yaml#/properties/port + description: + A port node to link the PHY to a TypeC controller for the purpose of + handling orientation switching. + +required: + - compatible + - reg + - clocks + - clock-names + - resets + - reset-names + - "#phy-cells" + +additionalProperties: false + +examples: + - | + #include + #include + + usbdp_phy0: phy@fed80000 { + compatible = "rockchip,rk3588-usbdp-phy"; + reg = <0xfed80000 0x10000>; + #phy-cells = <1>; + clocks = <&cru CLK_USBDPPHY_MIPIDCPPHY_REF>, + <&cru CLK_USBDP_PHY0_IMMORTAL>, + <&cru PCLK_USBDPPHY0>, + <&u2phy0>; + clock-names = "refclk", "immortal", "pclk", "utmi"; + resets = <&cru SRST_USBDP_COMBO_PHY0_INIT>, + <&cru SRST_USBDP_COMBO_PHY0_CMN>, + <&cru SRST_USBDP_COMBO_PHY0_LANE>, + <&cru SRST_USBDP_COMBO_PHY0_PCS>, + <&cru SRST_P_USBDPPHY0>; + reset-names = "init", "cmn", "lane", "pcs_apb", "pma_apb"; + rockchip,u2phy-grf = <&usb2phy0_grf>; + rockchip,usb-grf = <&usb_grf>; + rockchip,usbdpphy-grf = <&usbdpphy0_grf>; + rockchip,vo-grf = <&vo0_grf>; + }; -- cgit v1.2.3-59-g8ed1b From 2f70bbddeb457580cef3ceb574506083b9272188 Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Tue, 9 Apr 2024 00:50:29 +0200 Subject: phy: rockchip: add usbdp combo phy driver This adds a new USBDP combo PHY with Samsung IP block driver. The driver get lane mux and mapping info in 2 ways, supporting DisplayPort alternate mode or parsing from DT. When parsing from DT, the property "rockchip,dp-lane-mux" provide the DP mux and mapping info. This is needed when the PHY is not used with TypeC Alt-Mode. For example if the USB3 interface of the PHY is connected to a USB Type A connector and the DP interface is connected to a DisplayPort connector. When do DP link training, need to set lane number, link rate, swing, and pre-emphasis via PHY configure interface. Co-developed-by: Heiko Stuebner Signed-off-by: Heiko Stuebner Co-developed-by: Zhang Yubing Signed-off-by: Zhang Yubing Co-developed-by: Frank Wang Signed-off-by: Frank Wang Signed-off-by: Sebastian Reichel Link: https://lore.kernel.org/r/20240408225109.128953-3-sebastian.reichel@collabora.com Signed-off-by: Vinod Koul --- drivers/phy/rockchip/Kconfig | 12 + drivers/phy/rockchip/Makefile | 1 + drivers/phy/rockchip/phy-rockchip-usbdp.c | 1608 +++++++++++++++++++++++++++++ 3 files changed, 1621 insertions(+) create mode 100644 drivers/phy/rockchip/phy-rockchip-usbdp.c diff --git a/drivers/phy/rockchip/Kconfig b/drivers/phy/rockchip/Kconfig index a34f67bb7e61..c3d62243b474 100644 --- a/drivers/phy/rockchip/Kconfig +++ b/drivers/phy/rockchip/Kconfig @@ -115,3 +115,15 @@ config PHY_ROCKCHIP_USB select GENERIC_PHY help Enable this to support the Rockchip USB 2.0 PHY. + +config PHY_ROCKCHIP_USBDP + tristate "Rockchip USBDP COMBO PHY Driver" + depends on ARCH_ROCKCHIP && OF + select GENERIC_PHY + select TYPEC + help + Enable this to support the Rockchip USB3.0/DP combo PHY with + Samsung IP block. This is required for USB3 support on RK3588. + + To compile this driver as a module, choose M here: the module + will be called phy-rockchip-usbdp diff --git a/drivers/phy/rockchip/Makefile b/drivers/phy/rockchip/Makefile index 3d911304e654..010a824e32ce 100644 --- a/drivers/phy/rockchip/Makefile +++ b/drivers/phy/rockchip/Makefile @@ -12,3 +12,4 @@ obj-$(CONFIG_PHY_ROCKCHIP_SAMSUNG_HDPTX) += phy-rockchip-samsung-hdptx.o obj-$(CONFIG_PHY_ROCKCHIP_SNPS_PCIE3) += phy-rockchip-snps-pcie3.o obj-$(CONFIG_PHY_ROCKCHIP_TYPEC) += phy-rockchip-typec.o obj-$(CONFIG_PHY_ROCKCHIP_USB) += phy-rockchip-usb.o +obj-$(CONFIG_PHY_ROCKCHIP_USBDP) += phy-rockchip-usbdp.o diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c new file mode 100644 index 000000000000..32f306459182 --- /dev/null +++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c @@ -0,0 +1,1608 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Rockchip USBDP Combo PHY with Samsung IP block driver + * + * Copyright (C) 2021-2024 Rockchip Electronics Co., Ltd + * Copyright (C) 2024 Collabora Ltd + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* USBDP PHY Register Definitions */ +#define UDPHY_PCS 0x4000 +#define UDPHY_PMA 0x8000 + +/* VO0 GRF Registers */ +#define DP_SINK_HPD_CFG BIT(11) +#define DP_SINK_HPD_SEL BIT(10) +#define DP_AUX_DIN_SEL BIT(9) +#define DP_AUX_DOUT_SEL BIT(8) +#define DP_LANE_SEL_N(n) GENMASK(2 * (n) + 1, 2 * (n)) +#define DP_LANE_SEL_ALL GENMASK(7, 0) + +/* PMA CMN Registers */ +#define CMN_LANE_MUX_AND_EN_OFFSET 0x0288 /* cmn_reg00A2 */ +#define CMN_DP_LANE_MUX_N(n) BIT((n) + 4) +#define CMN_DP_LANE_EN_N(n) BIT(n) +#define CMN_DP_LANE_MUX_ALL GENMASK(7, 4) +#define CMN_DP_LANE_EN_ALL GENMASK(3, 0) + +#define CMN_DP_LINK_OFFSET 0x28c /* cmn_reg00A3 */ +#define CMN_DP_TX_LINK_BW GENMASK(6, 5) +#define CMN_DP_TX_LANE_SWAP_EN BIT(2) + +#define CMN_SSC_EN_OFFSET 0x2d0 /* cmn_reg00B4 */ +#define CMN_ROPLL_SSC_EN BIT(1) +#define CMN_LCPLL_SSC_EN BIT(0) + +#define CMN_ANA_LCPLL_DONE_OFFSET 0x0350 /* cmn_reg00D4 */ +#define CMN_ANA_LCPLL_LOCK_DONE BIT(7) +#define CMN_ANA_LCPLL_AFC_DONE BIT(6) + +#define CMN_ANA_ROPLL_DONE_OFFSET 0x0354 /* cmn_reg00D5 */ +#define CMN_ANA_ROPLL_LOCK_DONE BIT(1) +#define CMN_ANA_ROPLL_AFC_DONE BIT(0) + +#define CMN_DP_RSTN_OFFSET 0x038c /* cmn_reg00E3 */ +#define CMN_DP_INIT_RSTN BIT(3) +#define CMN_DP_CMN_RSTN BIT(2) +#define CMN_CDR_WTCHDG_EN BIT(1) +#define CMN_CDR_WTCHDG_MSK_CDR_EN BIT(0) + +#define TRSV_ANA_TX_CLK_OFFSET_N(n) (0x854 + (n) * 0x800) /* trsv_reg0215 */ +#define LN_ANA_TX_SER_TXCLK_INV BIT(1) + +#define TRSV_LN0_MON_RX_CDR_DONE_OFFSET 0x0b84 /* trsv_reg02E1 */ +#define TRSV_LN0_MON_RX_CDR_LOCK_DONE BIT(0) + +#define TRSV_LN2_MON_RX_CDR_DONE_OFFSET 0x1b84 /* trsv_reg06E1 */ +#define TRSV_LN2_MON_RX_CDR_LOCK_DONE BIT(0) + +#define BIT_WRITEABLE_SHIFT 16 +#define PHY_AUX_DP_DATA_POL_NORMAL 0 +#define PHY_AUX_DP_DATA_POL_INVERT 1 +#define PHY_LANE_MUX_USB 0 +#define PHY_LANE_MUX_DP 1 + +enum { + DP_BW_RBR, + DP_BW_HBR, + DP_BW_HBR2, + DP_BW_HBR3, +}; + +enum { + UDPHY_MODE_NONE = 0, + UDPHY_MODE_USB = BIT(0), + UDPHY_MODE_DP = BIT(1), + UDPHY_MODE_DP_USB = BIT(1) | BIT(0), +}; + +struct rk_udphy_grf_reg { + unsigned int offset; + unsigned int disable; + unsigned int enable; +}; + +#define _RK_UDPHY_GEN_GRF_REG(offset, mask, disable, enable) \ +{\ + offset, \ + FIELD_PREP_CONST(mask, disable) | (mask << BIT_WRITEABLE_SHIFT), \ + FIELD_PREP_CONST(mask, enable) | (mask << BIT_WRITEABLE_SHIFT), \ +} + +#define RK_UDPHY_GEN_GRF_REG(offset, bitend, bitstart, disable, enable) \ + _RK_UDPHY_GEN_GRF_REG(offset, GENMASK(bitend, bitstart), disable, enable) + +struct rk_udphy_grf_cfg { + /* u2phy-grf */ + struct rk_udphy_grf_reg bvalid_phy_con; + struct rk_udphy_grf_reg bvalid_grf_con; + + /* usb-grf */ + struct rk_udphy_grf_reg usb3otg0_cfg; + struct rk_udphy_grf_reg usb3otg1_cfg; + + /* usbdpphy-grf */ + struct rk_udphy_grf_reg low_pwrn; + struct rk_udphy_grf_reg rx_lfps; +}; + +struct rk_udphy_vogrf_cfg { + /* vo-grf */ + struct rk_udphy_grf_reg hpd_trigger; + u32 dp_lane_reg; +}; + +struct rk_udphy_dp_tx_drv_ctrl { + u32 trsv_reg0204; + u32 trsv_reg0205; + u32 trsv_reg0206; + u32 trsv_reg0207; +}; + +struct rk_udphy_cfg { + unsigned int num_phys; + unsigned int phy_ids[2]; + /* resets to be requested */ + const char * const *rst_list; + int num_rsts; + + struct rk_udphy_grf_cfg grfcfg; + struct rk_udphy_vogrf_cfg vogrfcfg[2]; + const struct rk_udphy_dp_tx_drv_ctrl (*dp_tx_ctrl_cfg[4])[4]; + const struct rk_udphy_dp_tx_drv_ctrl (*dp_tx_ctrl_cfg_typec[4])[4]; +}; + +struct rk_udphy { + struct device *dev; + struct regmap *pma_regmap; + struct regmap *u2phygrf; + struct regmap *udphygrf; + struct regmap *usbgrf; + struct regmap *vogrf; + struct typec_switch_dev *sw; + struct typec_mux_dev *mux; + struct mutex mutex; /* mutex to protect access to individual PHYs */ + + /* clocks and rests */ + int num_clks; + struct clk_bulk_data *clks; + struct clk *refclk; + int num_rsts; + struct reset_control_bulk_data *rsts; + + /* PHY status management */ + bool flip; + bool mode_change; + u8 mode; + u8 status; + + /* utilized for USB */ + bool hs; /* flag for high-speed */ + + /* utilized for DP */ + struct gpio_desc *sbu1_dc_gpio; + struct gpio_desc *sbu2_dc_gpio; + u32 lane_mux_sel[4]; + u32 dp_lane_sel[4]; + u32 dp_aux_dout_sel; + u32 dp_aux_din_sel; + bool dp_sink_hpd_sel; + bool dp_sink_hpd_cfg; + u8 bw; + int id; + + bool dp_in_use; + + /* PHY const config */ + const struct rk_udphy_cfg *cfgs; + + /* PHY devices */ + struct phy *phy_dp; + struct phy *phy_u3; +}; + +static const struct rk_udphy_dp_tx_drv_ctrl rk3588_dp_tx_drv_ctrl_rbr_hbr[4][4] = { + /* voltage swing 0, pre-emphasis 0->3 */ + { + { 0x20, 0x10, 0x42, 0xe5 }, + { 0x26, 0x14, 0x42, 0xe5 }, + { 0x29, 0x18, 0x42, 0xe5 }, + { 0x2b, 0x1c, 0x43, 0xe7 }, + }, + + /* voltage swing 1, pre-emphasis 0->2 */ + { + { 0x23, 0x10, 0x42, 0xe7 }, + { 0x2a, 0x17, 0x43, 0xe7 }, + { 0x2b, 0x1a, 0x43, 0xe7 }, + }, + + /* voltage swing 2, pre-emphasis 0->1 */ + { + { 0x27, 0x10, 0x42, 0xe7 }, + { 0x2b, 0x17, 0x43, 0xe7 }, + }, + + /* voltage swing 3, pre-emphasis 0 */ + { + { 0x29, 0x10, 0x43, 0xe7 }, + }, +}; + +static const struct rk_udphy_dp_tx_drv_ctrl rk3588_dp_tx_drv_ctrl_rbr_hbr_typec[4][4] = { + /* voltage swing 0, pre-emphasis 0->3 */ + { + { 0x20, 0x10, 0x42, 0xe5 }, + { 0x26, 0x14, 0x42, 0xe5 }, + { 0x29, 0x18, 0x42, 0xe5 }, + { 0x2b, 0x1c, 0x43, 0xe7 }, + }, + + /* voltage swing 1, pre-emphasis 0->2 */ + { + { 0x23, 0x10, 0x42, 0xe7 }, + { 0x2a, 0x17, 0x43, 0xe7 }, + { 0x2b, 0x1a, 0x43, 0xe7 }, + }, + + /* voltage swing 2, pre-emphasis 0->1 */ + { + { 0x27, 0x10, 0x43, 0x67 }, + { 0x2b, 0x17, 0x43, 0xe7 }, + }, + + /* voltage swing 3, pre-emphasis 0 */ + { + { 0x29, 0x10, 0x43, 0xe7 }, + }, +}; + +static const struct rk_udphy_dp_tx_drv_ctrl rk3588_dp_tx_drv_ctrl_hbr2[4][4] = { + /* voltage swing 0, pre-emphasis 0->3 */ + { + { 0x21, 0x10, 0x42, 0xe5 }, + { 0x26, 0x14, 0x42, 0xe5 }, + { 0x26, 0x16, 0x43, 0xe5 }, + { 0x2a, 0x19, 0x43, 0xe7 }, + }, + + /* voltage swing 1, pre-emphasis 0->2 */ + { + { 0x24, 0x10, 0x42, 0xe7 }, + { 0x2a, 0x17, 0x43, 0xe7 }, + { 0x2b, 0x1a, 0x43, 0xe7 }, + }, + + /* voltage swing 2, pre-emphasis 0->1 */ + { + { 0x28, 0x10, 0x42, 0xe7 }, + { 0x2b, 0x17, 0x43, 0xe7 }, + }, + + /* voltage swing 3, pre-emphasis 0 */ + { + { 0x28, 0x10, 0x43, 0xe7 }, + }, +}; + +static const struct rk_udphy_dp_tx_drv_ctrl rk3588_dp_tx_drv_ctrl_hbr3[4][4] = { + /* voltage swing 0, pre-emphasis 0->3 */ + { + { 0x21, 0x10, 0x42, 0xe5 }, + { 0x26, 0x14, 0x42, 0xe5 }, + { 0x26, 0x16, 0x43, 0xe5 }, + { 0x29, 0x18, 0x43, 0xe7 }, + }, + + /* voltage swing 1, pre-emphasis 0->2 */ + { + { 0x24, 0x10, 0x42, 0xe7 }, + { 0x2a, 0x18, 0x43, 0xe7 }, + { 0x2b, 0x1b, 0x43, 0xe7 } + }, + + /* voltage swing 2, pre-emphasis 0->1 */ + { + { 0x27, 0x10, 0x42, 0xe7 }, + { 0x2b, 0x18, 0x43, 0xe7 } + }, + + /* voltage swing 3, pre-emphasis 0 */ + { + { 0x28, 0x10, 0x43, 0xe7 }, + }, +}; + +static const struct reg_sequence rk_udphy_24m_refclk_cfg[] = { + {0x0090, 0x68}, {0x0094, 0x68}, + {0x0128, 0x24}, {0x012c, 0x44}, + {0x0130, 0x3f}, {0x0134, 0x44}, + {0x015c, 0xa9}, {0x0160, 0x71}, + {0x0164, 0x71}, {0x0168, 0xa9}, + {0x0174, 0xa9}, {0x0178, 0x71}, + {0x017c, 0x71}, {0x0180, 0xa9}, + {0x018c, 0x41}, {0x0190, 0x00}, + {0x0194, 0x05}, {0x01ac, 0x2a}, + {0x01b0, 0x17}, {0x01b4, 0x17}, + {0x01b8, 0x2a}, {0x01c8, 0x04}, + {0x01cc, 0x08}, {0x01d0, 0x08}, + {0x01d4, 0x04}, {0x01d8, 0x20}, + {0x01dc, 0x01}, {0x01e0, 0x09}, + {0x01e4, 0x03}, {0x01f0, 0x29}, + {0x01f4, 0x02}, {0x01f8, 0x02}, + {0x01fc, 0x29}, {0x0208, 0x2a}, + {0x020c, 0x17}, {0x0210, 0x17}, + {0x0214, 0x2a}, {0x0224, 0x20}, + {0x03f0, 0x0a}, {0x03f4, 0x07}, + {0x03f8, 0x07}, {0x03fc, 0x0c}, + {0x0404, 0x12}, {0x0408, 0x1a}, + {0x040c, 0x1a}, {0x0410, 0x3f}, + {0x0ce0, 0x68}, {0x0ce8, 0xd0}, + {0x0cf0, 0x87}, {0x0cf8, 0x70}, + {0x0d00, 0x70}, {0x0d08, 0xa9}, + {0x1ce0, 0x68}, {0x1ce8, 0xd0}, + {0x1cf0, 0x87}, {0x1cf8, 0x70}, + {0x1d00, 0x70}, {0x1d08, 0xa9}, + {0x0a3c, 0xd0}, {0x0a44, 0xd0}, + {0x0a48, 0x01}, {0x0a4c, 0x0d}, + {0x0a54, 0xe0}, {0x0a5c, 0xe0}, + {0x0a64, 0xa8}, {0x1a3c, 0xd0}, + {0x1a44, 0xd0}, {0x1a48, 0x01}, + {0x1a4c, 0x0d}, {0x1a54, 0xe0}, + {0x1a5c, 0xe0}, {0x1a64, 0xa8} +}; + +static const struct reg_sequence rk_udphy_26m_refclk_cfg[] = { + {0x0830, 0x07}, {0x085c, 0x80}, + {0x1030, 0x07}, {0x105c, 0x80}, + {0x1830, 0x07}, {0x185c, 0x80}, + {0x2030, 0x07}, {0x205c, 0x80}, + {0x0228, 0x38}, {0x0104, 0x44}, + {0x0248, 0x44}, {0x038c, 0x02}, + {0x0878, 0x04}, {0x1878, 0x04}, + {0x0898, 0x77}, {0x1898, 0x77}, + {0x0054, 0x01}, {0x00e0, 0x38}, + {0x0060, 0x24}, {0x0064, 0x77}, + {0x0070, 0x76}, {0x0234, 0xe8}, + {0x0af4, 0x15}, {0x1af4, 0x15}, + {0x081c, 0xe5}, {0x181c, 0xe5}, + {0x099c, 0x48}, {0x199c, 0x48}, + {0x09a4, 0x07}, {0x09a8, 0x22}, + {0x19a4, 0x07}, {0x19a8, 0x22}, + {0x09b8, 0x3e}, {0x19b8, 0x3e}, + {0x09e4, 0x02}, {0x19e4, 0x02}, + {0x0a34, 0x1e}, {0x1a34, 0x1e}, + {0x0a98, 0x2f}, {0x1a98, 0x2f}, + {0x0c30, 0x0e}, {0x0c48, 0x06}, + {0x1c30, 0x0e}, {0x1c48, 0x06}, + {0x028c, 0x18}, {0x0af0, 0x00}, + {0x1af0, 0x00} +}; + +static const struct reg_sequence rk_udphy_init_sequence[] = { + {0x0104, 0x44}, {0x0234, 0xe8}, + {0x0248, 0x44}, {0x028c, 0x18}, + {0x081c, 0xe5}, {0x0878, 0x00}, + {0x0994, 0x1c}, {0x0af0, 0x00}, + {0x181c, 0xe5}, {0x1878, 0x00}, + {0x1994, 0x1c}, {0x1af0, 0x00}, + {0x0428, 0x60}, {0x0d58, 0x33}, + {0x1d58, 0x33}, {0x0990, 0x74}, + {0x0d64, 0x17}, {0x08c8, 0x13}, + {0x1990, 0x74}, {0x1d64, 0x17}, + {0x18c8, 0x13}, {0x0d90, 0x40}, + {0x0da8, 0x40}, {0x0dc0, 0x40}, + {0x0dd8, 0x40}, {0x1d90, 0x40}, + {0x1da8, 0x40}, {0x1dc0, 0x40}, + {0x1dd8, 0x40}, {0x03c0, 0x30}, + {0x03c4, 0x06}, {0x0e10, 0x00}, + {0x1e10, 0x00}, {0x043c, 0x0f}, + {0x0d2c, 0xff}, {0x1d2c, 0xff}, + {0x0d34, 0x0f}, {0x1d34, 0x0f}, + {0x08fc, 0x2a}, {0x0914, 0x28}, + {0x0a30, 0x03}, {0x0e38, 0x03}, + {0x0ecc, 0x27}, {0x0ed0, 0x22}, + {0x0ed4, 0x26}, {0x18fc, 0x2a}, + {0x1914, 0x28}, {0x1a30, 0x03}, + {0x1e38, 0x03}, {0x1ecc, 0x27}, + {0x1ed0, 0x22}, {0x1ed4, 0x26}, + {0x0048, 0x0f}, {0x0060, 0x3c}, + {0x0064, 0xf7}, {0x006c, 0x20}, + {0x0070, 0x7d}, {0x0074, 0x68}, + {0x0af4, 0x1a}, {0x1af4, 0x1a}, + {0x0440, 0x3f}, {0x10d4, 0x08}, + {0x20d4, 0x08}, {0x00d4, 0x30}, + {0x0024, 0x6e}, +}; + +static inline int rk_udphy_grfreg_write(struct regmap *base, + const struct rk_udphy_grf_reg *reg, bool en) +{ + return regmap_write(base, reg->offset, en ? reg->enable : reg->disable); +} + +static int rk_udphy_clk_init(struct rk_udphy *udphy, struct device *dev) +{ + int i; + + udphy->num_clks = devm_clk_bulk_get_all(dev, &udphy->clks); + if (udphy->num_clks < 1) + return -ENODEV; + + /* used for configure phy reference clock frequency */ + for (i = 0; i < udphy->num_clks; i++) { + if (!strncmp(udphy->clks[i].id, "refclk", 6)) { + udphy->refclk = udphy->clks[i].clk; + break; + } + } + + if (!udphy->refclk) + return dev_err_probe(udphy->dev, -EINVAL, "no refclk found\n"); + + return 0; +} + +static int rk_udphy_reset_assert_all(struct rk_udphy *udphy) +{ + return reset_control_bulk_assert(udphy->num_rsts, udphy->rsts); +} + +static int rk_udphy_reset_deassert_all(struct rk_udphy *udphy) +{ + return reset_control_bulk_deassert(udphy->num_rsts, udphy->rsts); +} + +static int rk_udphy_reset_deassert(struct rk_udphy *udphy, char *name) +{ + struct reset_control_bulk_data *list = udphy->rsts; + int idx; + + for (idx = 0; idx < udphy->num_rsts; idx++) { + if (!strcmp(list[idx].id, name)) + return reset_control_deassert(list[idx].rstc); + } + + return -EINVAL; +} + +static int rk_udphy_reset_init(struct rk_udphy *udphy, struct device *dev) +{ + const struct rk_udphy_cfg *cfg = udphy->cfgs; + int idx; + + udphy->num_rsts = cfg->num_rsts; + udphy->rsts = devm_kcalloc(dev, udphy->num_rsts, + sizeof(*udphy->rsts), GFP_KERNEL); + if (!udphy->rsts) + return -ENOMEM; + + for (idx = 0; idx < cfg->num_rsts; idx++) + udphy->rsts[idx].id = cfg->rst_list[idx]; + + return devm_reset_control_bulk_get_exclusive(dev, cfg->num_rsts, + udphy->rsts); +} + +static void rk_udphy_u3_port_disable(struct rk_udphy *udphy, u8 disable) +{ + const struct rk_udphy_cfg *cfg = udphy->cfgs; + const struct rk_udphy_grf_reg *preg; + + preg = udphy->id ? &cfg->grfcfg.usb3otg1_cfg : &cfg->grfcfg.usb3otg0_cfg; + rk_udphy_grfreg_write(udphy->usbgrf, preg, disable); +} + +static void rk_udphy_usb_bvalid_enable(struct rk_udphy *udphy, u8 enable) +{ + const struct rk_udphy_cfg *cfg = udphy->cfgs; + + rk_udphy_grfreg_write(udphy->u2phygrf, &cfg->grfcfg.bvalid_phy_con, enable); + rk_udphy_grfreg_write(udphy->u2phygrf, &cfg->grfcfg.bvalid_grf_con, enable); +} + +/* + * In usb/dp combo phy driver, here are 2 ways to mapping lanes. + * + * 1 Type-C Mapping table (DP_Alt_Mode V1.0b remove ABF pin mapping) + * --------------------------------------------------------------------------- + * Type-C Pin B11-B10 A2-A3 A11-A10 B2-B3 + * PHY Pad ln0(tx/rx) ln1(tx) ln2(tx/rx) ln3(tx) + * C/E(Normal) dpln3 dpln2 dpln0 dpln1 + * C/E(Flip ) dpln0 dpln1 dpln3 dpln2 + * D/F(Normal) usbrx usbtx dpln0 dpln1 + * D/F(Flip ) dpln0 dpln1 usbrx usbtx + * A(Normal ) dpln3 dpln1 dpln2 dpln0 + * A(Flip ) dpln2 dpln0 dpln3 dpln1 + * B(Normal ) usbrx usbtx dpln1 dpln0 + * B(Flip ) dpln1 dpln0 usbrx usbtx + * --------------------------------------------------------------------------- + * + * 2 Mapping the lanes in dtsi + * if all 4 lane assignment for dp function, define rockchip,dp-lane-mux = ; + * sample as follow: + * --------------------------------------------------------------------------- + * B11-B10 A2-A3 A11-A10 B2-B3 + * rockchip,dp-lane-mux ln0(tx/rx) ln1(tx) ln2(tx/rx) ln3(tx) + * <0 1 2 3> dpln0 dpln1 dpln2 dpln3 + * <2 3 0 1> dpln2 dpln3 dpln0 dpln1 + * --------------------------------------------------------------------------- + * if 2 lane for dp function, 2 lane for usb function, define rockchip,dp-lane-mux = ; + * sample as follow: + * --------------------------------------------------------------------------- + * B11-B10 A2-A3 A11-A10 B2-B3 + * rockchip,dp-lane-mux ln0(tx/rx) ln1(tx) ln2(tx/rx) ln3(tx) + * <0 1> dpln0 dpln1 usbrx usbtx + * <2 3> usbrx usbtx dpln0 dpln1 + * --------------------------------------------------------------------------- + */ + +static void rk_udphy_dplane_select(struct rk_udphy *udphy) +{ + const struct rk_udphy_cfg *cfg = udphy->cfgs; + u32 value = 0; + + switch (udphy->mode) { + case UDPHY_MODE_DP: + value |= 2 << udphy->dp_lane_sel[2] * 2; + value |= 3 << udphy->dp_lane_sel[3] * 2; + fallthrough; + + case UDPHY_MODE_DP_USB: + value |= 0 << udphy->dp_lane_sel[0] * 2; + value |= 1 << udphy->dp_lane_sel[1] * 2; + break; + + case UDPHY_MODE_USB: + break; + + default: + break; + } + + regmap_write(udphy->vogrf, cfg->vogrfcfg[udphy->id].dp_lane_reg, + ((DP_AUX_DIN_SEL | DP_AUX_DOUT_SEL | DP_LANE_SEL_ALL) << 16) | + FIELD_PREP(DP_AUX_DIN_SEL, udphy->dp_aux_din_sel) | + FIELD_PREP(DP_AUX_DOUT_SEL, udphy->dp_aux_dout_sel) | value); +} + +static int rk_udphy_dplane_get(struct rk_udphy *udphy) +{ + int dp_lanes; + + switch (udphy->mode) { + case UDPHY_MODE_DP: + dp_lanes = 4; + break; + + case UDPHY_MODE_DP_USB: + dp_lanes = 2; + break; + + case UDPHY_MODE_USB: + default: + dp_lanes = 0; + break; + } + + return dp_lanes; +} + +static void rk_udphy_dplane_enable(struct rk_udphy *udphy, int dp_lanes) +{ + u32 val = 0; + int i; + + for (i = 0; i < dp_lanes; i++) + val |= BIT(udphy->dp_lane_sel[i]); + + regmap_update_bits(udphy->pma_regmap, CMN_LANE_MUX_AND_EN_OFFSET, CMN_DP_LANE_EN_ALL, + FIELD_PREP(CMN_DP_LANE_EN_ALL, val)); + + if (!dp_lanes) + regmap_update_bits(udphy->pma_regmap, CMN_DP_RSTN_OFFSET, + CMN_DP_CMN_RSTN, FIELD_PREP(CMN_DP_CMN_RSTN, 0x0)); +} + +static void rk_udphy_dp_hpd_event_trigger(struct rk_udphy *udphy, bool hpd) +{ + const struct rk_udphy_cfg *cfg = udphy->cfgs; + + udphy->dp_sink_hpd_sel = true; + udphy->dp_sink_hpd_cfg = hpd; + + if (!udphy->dp_in_use) + return; + + rk_udphy_grfreg_write(udphy->vogrf, &cfg->vogrfcfg[udphy->id].hpd_trigger, hpd); +} + +static void rk_udphy_set_typec_default_mapping(struct rk_udphy *udphy) +{ + if (udphy->flip) { + udphy->dp_lane_sel[0] = 0; + udphy->dp_lane_sel[1] = 1; + udphy->dp_lane_sel[2] = 3; + udphy->dp_lane_sel[3] = 2; + udphy->lane_mux_sel[0] = PHY_LANE_MUX_DP; + udphy->lane_mux_sel[1] = PHY_LANE_MUX_DP; + udphy->lane_mux_sel[2] = PHY_LANE_MUX_USB; + udphy->lane_mux_sel[3] = PHY_LANE_MUX_USB; + udphy->dp_aux_dout_sel = PHY_AUX_DP_DATA_POL_INVERT; + udphy->dp_aux_din_sel = PHY_AUX_DP_DATA_POL_INVERT; + gpiod_set_value_cansleep(udphy->sbu1_dc_gpio, 1); + gpiod_set_value_cansleep(udphy->sbu2_dc_gpio, 0); + } else { + udphy->dp_lane_sel[0] = 2; + udphy->dp_lane_sel[1] = 3; + udphy->dp_lane_sel[2] = 1; + udphy->dp_lane_sel[3] = 0; + udphy->lane_mux_sel[0] = PHY_LANE_MUX_USB; + udphy->lane_mux_sel[1] = PHY_LANE_MUX_USB; + udphy->lane_mux_sel[2] = PHY_LANE_MUX_DP; + udphy->lane_mux_sel[3] = PHY_LANE_MUX_DP; + udphy->dp_aux_dout_sel = PHY_AUX_DP_DATA_POL_NORMAL; + udphy->dp_aux_din_sel = PHY_AUX_DP_DATA_POL_NORMAL; + gpiod_set_value_cansleep(udphy->sbu1_dc_gpio, 0); + gpiod_set_value_cansleep(udphy->sbu2_dc_gpio, 1); + } + + udphy->mode = UDPHY_MODE_DP_USB; +} + +static int rk_udphy_orien_sw_set(struct typec_switch_dev *sw, + enum typec_orientation orien) +{ + struct rk_udphy *udphy = typec_switch_get_drvdata(sw); + + mutex_lock(&udphy->mutex); + + if (orien == TYPEC_ORIENTATION_NONE) { + gpiod_set_value_cansleep(udphy->sbu1_dc_gpio, 0); + gpiod_set_value_cansleep(udphy->sbu2_dc_gpio, 0); + /* unattached */ + rk_udphy_usb_bvalid_enable(udphy, false); + goto unlock_ret; + } + + udphy->flip = (orien == TYPEC_ORIENTATION_REVERSE) ? true : false; + rk_udphy_set_typec_default_mapping(udphy); + rk_udphy_usb_bvalid_enable(udphy, true); + +unlock_ret: + mutex_unlock(&udphy->mutex); + return 0; +} + +static void rk_udphy_orien_switch_unregister(void *data) +{ + struct rk_udphy *udphy = data; + + typec_switch_unregister(udphy->sw); +} + +static int rk_udphy_setup_orien_switch(struct rk_udphy *udphy) +{ + struct typec_switch_desc sw_desc = { }; + + sw_desc.drvdata = udphy; + sw_desc.fwnode = dev_fwnode(udphy->dev); + sw_desc.set = rk_udphy_orien_sw_set; + + udphy->sw = typec_switch_register(udphy->dev, &sw_desc); + if (IS_ERR(udphy->sw)) { + dev_err(udphy->dev, "Error register typec orientation switch: %ld\n", + PTR_ERR(udphy->sw)); + return PTR_ERR(udphy->sw); + } + + return devm_add_action_or_reset(udphy->dev, + rk_udphy_orien_switch_unregister, udphy); +} + +static int rk_udphy_refclk_set(struct rk_udphy *udphy) +{ + unsigned long rate; + int ret; + + /* configure phy reference clock */ + rate = clk_get_rate(udphy->refclk); + dev_dbg(udphy->dev, "refclk freq %ld\n", rate); + + switch (rate) { + case 24000000: + ret = regmap_multi_reg_write(udphy->pma_regmap, rk_udphy_24m_refclk_cfg, + ARRAY_SIZE(rk_udphy_24m_refclk_cfg)); + if (ret) + return ret; + break; + + case 26000000: + /* register default is 26MHz */ + ret = regmap_multi_reg_write(udphy->pma_regmap, rk_udphy_26m_refclk_cfg, + ARRAY_SIZE(rk_udphy_26m_refclk_cfg)); + if (ret) + return ret; + break; + + default: + dev_err(udphy->dev, "unsupported refclk freq %ld\n", rate); + return -EINVAL; + } + + return 0; +} + +static int rk_udphy_status_check(struct rk_udphy *udphy) +{ + unsigned int val; + int ret; + + /* LCPLL check */ + if (udphy->mode & UDPHY_MODE_USB) { + ret = regmap_read_poll_timeout(udphy->pma_regmap, CMN_ANA_LCPLL_DONE_OFFSET, + val, (val & CMN_ANA_LCPLL_AFC_DONE) && + (val & CMN_ANA_LCPLL_LOCK_DONE), 200, 100000); + if (ret) { + dev_err(udphy->dev, "cmn ana lcpll lock timeout\n"); + /* + * If earlier software (U-Boot) enabled USB once already + * the PLL may have problems locking on the first try. + * It will be successful on the second try, so for the + * time being a -EPROBE_DEFER will solve the issue. + * + * This requires further investigation to understand the + * root cause, especially considering that the driver is + * asserting all reset lines at probe time. + */ + return -EPROBE_DEFER; + } + + if (!udphy->flip) { + ret = regmap_read_poll_timeout(udphy->pma_regmap, + TRSV_LN0_MON_RX_CDR_DONE_OFFSET, val, + val & TRSV_LN0_MON_RX_CDR_LOCK_DONE, + 200, 100000); + if (ret) + dev_err(udphy->dev, "trsv ln0 mon rx cdr lock timeout\n"); + } else { + ret = regmap_read_poll_timeout(udphy->pma_regmap, + TRSV_LN2_MON_RX_CDR_DONE_OFFSET, val, + val & TRSV_LN2_MON_RX_CDR_LOCK_DONE, + 200, 100000); + if (ret) + dev_err(udphy->dev, "trsv ln2 mon rx cdr lock timeout\n"); + } + } + + return 0; +} + +static int rk_udphy_init(struct rk_udphy *udphy) +{ + const struct rk_udphy_cfg *cfg = udphy->cfgs; + int ret; + + rk_udphy_reset_assert_all(udphy); + usleep_range(10000, 11000); + + /* enable rx lfps for usb */ + if (udphy->mode & UDPHY_MODE_USB) + rk_udphy_grfreg_write(udphy->udphygrf, &cfg->grfcfg.rx_lfps, true); + + /* Step 1: power on pma and deassert apb rstn */ + rk_udphy_grfreg_write(udphy->udphygrf, &cfg->grfcfg.low_pwrn, true); + + rk_udphy_reset_deassert(udphy, "pma_apb"); + rk_udphy_reset_deassert(udphy, "pcs_apb"); + + /* Step 2: set init sequence and phy refclk */ + ret = regmap_multi_reg_write(udphy->pma_regmap, rk_udphy_init_sequence, + ARRAY_SIZE(rk_udphy_init_sequence)); + if (ret) { + dev_err(udphy->dev, "init sequence set error %d\n", ret); + goto assert_resets; + } + + ret = rk_udphy_refclk_set(udphy); + if (ret) { + dev_err(udphy->dev, "refclk set error %d\n", ret); + goto assert_resets; + } + + /* Step 3: configure lane mux */ + regmap_update_bits(udphy->pma_regmap, CMN_LANE_MUX_AND_EN_OFFSET, + CMN_DP_LANE_MUX_ALL | CMN_DP_LANE_EN_ALL, + FIELD_PREP(CMN_DP_LANE_MUX_N(3), udphy->lane_mux_sel[3]) | + FIELD_PREP(CMN_DP_LANE_MUX_N(2), udphy->lane_mux_sel[2]) | + FIELD_PREP(CMN_DP_LANE_MUX_N(1), udphy->lane_mux_sel[1]) | + FIELD_PREP(CMN_DP_LANE_MUX_N(0), udphy->lane_mux_sel[0]) | + FIELD_PREP(CMN_DP_LANE_EN_ALL, 0)); + + /* Step 4: deassert init rstn and wait for 200ns from datasheet */ + if (udphy->mode & UDPHY_MODE_USB) + rk_udphy_reset_deassert(udphy, "init"); + + if (udphy->mode & UDPHY_MODE_DP) { + regmap_update_bits(udphy->pma_regmap, CMN_DP_RSTN_OFFSET, + CMN_DP_INIT_RSTN, + FIELD_PREP(CMN_DP_INIT_RSTN, 0x1)); + } + + udelay(1); + + /* Step 5: deassert cmn/lane rstn */ + if (udphy->mode & UDPHY_MODE_USB) { + rk_udphy_reset_deassert(udphy, "cmn"); + rk_udphy_reset_deassert(udphy, "lane"); + } + + /* Step 6: wait for lock done of pll */ + ret = rk_udphy_status_check(udphy); + if (ret) + goto assert_resets; + + return 0; + +assert_resets: + rk_udphy_reset_assert_all(udphy); + return ret; +} + +static int rk_udphy_setup(struct rk_udphy *udphy) +{ + int ret; + + ret = clk_bulk_prepare_enable(udphy->num_clks, udphy->clks); + if (ret) { + dev_err(udphy->dev, "failed to enable clk\n"); + return ret; + } + + ret = rk_udphy_init(udphy); + if (ret) { + dev_err(udphy->dev, "failed to init combophy\n"); + clk_bulk_disable_unprepare(udphy->num_clks, udphy->clks); + return ret; + } + + return 0; +} + +static void rk_udphy_disable(struct rk_udphy *udphy) +{ + clk_bulk_disable_unprepare(udphy->num_clks, udphy->clks); + rk_udphy_reset_assert_all(udphy); +} + +static int rk_udphy_parse_lane_mux_data(struct rk_udphy *udphy) +{ + int ret, i, num_lanes; + + num_lanes = device_property_count_u32(udphy->dev, "rockchip,dp-lane-mux"); + if (num_lanes < 0) { + dev_dbg(udphy->dev, "no dp-lane-mux, following dp alt mode\n"); + udphy->mode = UDPHY_MODE_USB; + return 0; + } + + if (num_lanes != 2 && num_lanes != 4) + return dev_err_probe(udphy->dev, -EINVAL, + "invalid number of lane mux\n"); + + ret = device_property_read_u32_array(udphy->dev, "rockchip,dp-lane-mux", + udphy->dp_lane_sel, num_lanes); + if (ret) + return dev_err_probe(udphy->dev, ret, "get dp lane mux failed\n"); + + for (i = 0; i < num_lanes; i++) { + int j; + + if (udphy->dp_lane_sel[i] > 3) + return dev_err_probe(udphy->dev, -EINVAL, + "lane mux between 0 and 3, exceeding the range\n"); + + udphy->lane_mux_sel[udphy->dp_lane_sel[i]] = PHY_LANE_MUX_DP; + + for (j = i + 1; j < num_lanes; j++) { + if (udphy->dp_lane_sel[i] == udphy->dp_lane_sel[j]) + return dev_err_probe(udphy->dev, -EINVAL, + "set repeat lane mux value\n"); + } + } + + udphy->mode = UDPHY_MODE_DP; + if (num_lanes == 2) { + udphy->mode |= UDPHY_MODE_USB; + udphy->flip = (udphy->lane_mux_sel[0] == PHY_LANE_MUX_DP); + } + + return 0; +} + +static int rk_udphy_get_initial_status(struct rk_udphy *udphy) +{ + int ret; + u32 value; + + ret = clk_bulk_prepare_enable(udphy->num_clks, udphy->clks); + if (ret) { + dev_err(udphy->dev, "failed to enable clk\n"); + return ret; + } + + rk_udphy_reset_deassert_all(udphy); + + regmap_read(udphy->pma_regmap, CMN_LANE_MUX_AND_EN_OFFSET, &value); + if (FIELD_GET(CMN_DP_LANE_MUX_ALL, value) && FIELD_GET(CMN_DP_LANE_EN_ALL, value)) + udphy->status = UDPHY_MODE_DP; + else + rk_udphy_disable(udphy); + + return 0; +} + +static int rk_udphy_parse_dt(struct rk_udphy *udphy) +{ + struct device *dev = udphy->dev; + struct device_node *np = dev_of_node(dev); + enum usb_device_speed maximum_speed; + int ret; + + udphy->u2phygrf = syscon_regmap_lookup_by_phandle(np, "rockchip,u2phy-grf"); + if (IS_ERR(udphy->u2phygrf)) + return dev_err_probe(dev, PTR_ERR(udphy->u2phygrf), "failed to get u2phy-grf\n"); + + udphy->udphygrf = syscon_regmap_lookup_by_phandle(np, "rockchip,usbdpphy-grf"); + if (IS_ERR(udphy->udphygrf)) + return dev_err_probe(dev, PTR_ERR(udphy->udphygrf), "failed to get usbdpphy-grf\n"); + + udphy->usbgrf = syscon_regmap_lookup_by_phandle(np, "rockchip,usb-grf"); + if (IS_ERR(udphy->usbgrf)) + return dev_err_probe(dev, PTR_ERR(udphy->usbgrf), "failed to get usb-grf\n"); + + udphy->vogrf = syscon_regmap_lookup_by_phandle(np, "rockchip,vo-grf"); + if (IS_ERR(udphy->vogrf)) + return dev_err_probe(dev, PTR_ERR(udphy->vogrf), "failed to get vo-grf\n"); + + ret = rk_udphy_parse_lane_mux_data(udphy); + if (ret) + return ret; + + udphy->sbu1_dc_gpio = devm_gpiod_get_optional(dev, "sbu1-dc", GPIOD_OUT_LOW); + if (IS_ERR(udphy->sbu1_dc_gpio)) + return PTR_ERR(udphy->sbu1_dc_gpio); + + udphy->sbu2_dc_gpio = devm_gpiod_get_optional(dev, "sbu2-dc", GPIOD_OUT_LOW); + if (IS_ERR(udphy->sbu2_dc_gpio)) + return PTR_ERR(udphy->sbu2_dc_gpio); + + if (device_property_present(dev, "maximum-speed")) { + maximum_speed = usb_get_maximum_speed(dev); + udphy->hs = maximum_speed <= USB_SPEED_HIGH ? true : false; + } + + ret = rk_udphy_clk_init(udphy, dev); + if (ret) + return ret; + + return rk_udphy_reset_init(udphy, dev); +} + +static int rk_udphy_power_on(struct rk_udphy *udphy, u8 mode) +{ + int ret; + + if (!(udphy->mode & mode)) { + dev_info(udphy->dev, "mode 0x%02x is not support\n", mode); + return 0; + } + + if (udphy->status == UDPHY_MODE_NONE) { + udphy->mode_change = false; + ret = rk_udphy_setup(udphy); + if (ret) + return ret; + + if (udphy->mode & UDPHY_MODE_USB) + rk_udphy_u3_port_disable(udphy, false); + } else if (udphy->mode_change) { + udphy->mode_change = false; + udphy->status = UDPHY_MODE_NONE; + if (udphy->mode == UDPHY_MODE_DP) + rk_udphy_u3_port_disable(udphy, true); + + rk_udphy_disable(udphy); + ret = rk_udphy_setup(udphy); + if (ret) + return ret; + } + + udphy->status |= mode; + + return 0; +} + +static void rk_udphy_power_off(struct rk_udphy *udphy, u8 mode) +{ + if (!(udphy->mode & mode)) { + dev_info(udphy->dev, "mode 0x%02x is not support\n", mode); + return; + } + + if (!udphy->status) + return; + + udphy->status &= ~mode; + + if (udphy->status == UDPHY_MODE_NONE) + rk_udphy_disable(udphy); +} + +static int rk_udphy_dp_phy_init(struct phy *phy) +{ + struct rk_udphy *udphy = phy_get_drvdata(phy); + + mutex_lock(&udphy->mutex); + + udphy->dp_in_use = true; + rk_udphy_dp_hpd_event_trigger(udphy, udphy->dp_sink_hpd_cfg); + + mutex_unlock(&udphy->mutex); + + return 0; +} + +static int rk_udphy_dp_phy_exit(struct phy *phy) +{ + struct rk_udphy *udphy = phy_get_drvdata(phy); + + mutex_lock(&udphy->mutex); + udphy->dp_in_use = false; + mutex_unlock(&udphy->mutex); + return 0; +} + +static int rk_udphy_dp_phy_power_on(struct phy *phy) +{ + struct rk_udphy *udphy = phy_get_drvdata(phy); + int ret, dp_lanes; + + mutex_lock(&udphy->mutex); + + dp_lanes = rk_udphy_dplane_get(udphy); + phy_set_bus_width(phy, dp_lanes); + + ret = rk_udphy_power_on(udphy, UDPHY_MODE_DP); + if (ret) + goto unlock; + + rk_udphy_dplane_enable(udphy, dp_lanes); + + rk_udphy_dplane_select(udphy); + +unlock: + mutex_unlock(&udphy->mutex); + /* + * If data send by aux channel too fast after phy power on, + * the aux may be not ready which will cause aux error. Adding + * delay to avoid this issue. + */ + usleep_range(10000, 11000); + return ret; +} + +static int rk_udphy_dp_phy_power_off(struct phy *phy) +{ + struct rk_udphy *udphy = phy_get_drvdata(phy); + + mutex_lock(&udphy->mutex); + rk_udphy_dplane_enable(udphy, 0); + rk_udphy_power_off(udphy, UDPHY_MODE_DP); + mutex_unlock(&udphy->mutex); + + return 0; +} + +static int rk_udphy_dp_phy_verify_link_rate(unsigned int link_rate) +{ + switch (link_rate) { + case 1620: + case 2700: + case 5400: + case 8100: + break; + + default: + return -EINVAL; + } + + return 0; +} + +static int rk_udphy_dp_phy_verify_config(struct rk_udphy *udphy, + struct phy_configure_opts_dp *dp) +{ + int i, ret; + + /* If changing link rate was required, verify it's supported. */ + ret = rk_udphy_dp_phy_verify_link_rate(dp->link_rate); + if (ret) + return ret; + + /* Verify lane count. */ + switch (dp->lanes) { + case 1: + case 2: + case 4: + /* valid lane count. */ + break; + + default: + return -EINVAL; + } + + /* + * If changing voltages is required, check swing and pre-emphasis + * levels, per-lane. + */ + if (dp->set_voltages) { + /* Lane count verified previously. */ + for (i = 0; i < dp->lanes; i++) { + if (dp->voltage[i] > 3 || dp->pre[i] > 3) + return -EINVAL; + + /* + * Sum of voltage swing and pre-emphasis levels cannot + * exceed 3. + */ + if (dp->voltage[i] + dp->pre[i] > 3) + return -EINVAL; + } + } + + return 0; +} + +static void rk_udphy_dp_set_voltage(struct rk_udphy *udphy, u8 bw, + u32 voltage, u32 pre, u32 lane) +{ + const struct rk_udphy_cfg *cfg = udphy->cfgs; + const struct rk_udphy_dp_tx_drv_ctrl (*dp_ctrl)[4]; + u32 offset = 0x800 * lane; + u32 val; + + if (udphy->mux) + dp_ctrl = cfg->dp_tx_ctrl_cfg_typec[bw]; + else + dp_ctrl = cfg->dp_tx_ctrl_cfg[bw]; + + val = dp_ctrl[voltage][pre].trsv_reg0204; + regmap_write(udphy->pma_regmap, 0x0810 + offset, val); + + val = dp_ctrl[voltage][pre].trsv_reg0205; + regmap_write(udphy->pma_regmap, 0x0814 + offset, val); + + val = dp_ctrl[voltage][pre].trsv_reg0206; + regmap_write(udphy->pma_regmap, 0x0818 + offset, val); + + val = dp_ctrl[voltage][pre].trsv_reg0207; + regmap_write(udphy->pma_regmap, 0x081c + offset, val); +} + +static int rk_udphy_dp_phy_configure(struct phy *phy, + union phy_configure_opts *opts) +{ + struct rk_udphy *udphy = phy_get_drvdata(phy); + struct phy_configure_opts_dp *dp = &opts->dp; + u32 i, val, lane; + int ret; + + ret = rk_udphy_dp_phy_verify_config(udphy, dp); + if (ret) + return ret; + + if (dp->set_rate) { + regmap_update_bits(udphy->pma_regmap, CMN_DP_RSTN_OFFSET, + CMN_DP_CMN_RSTN, FIELD_PREP(CMN_DP_CMN_RSTN, 0x0)); + + switch (dp->link_rate) { + case 1620: + udphy->bw = DP_BW_RBR; + break; + + case 2700: + udphy->bw = DP_BW_HBR; + break; + + case 5400: + udphy->bw = DP_BW_HBR2; + break; + + case 8100: + udphy->bw = DP_BW_HBR3; + break; + + default: + return -EINVAL; + } + + regmap_update_bits(udphy->pma_regmap, CMN_DP_LINK_OFFSET, CMN_DP_TX_LINK_BW, + FIELD_PREP(CMN_DP_TX_LINK_BW, udphy->bw)); + regmap_update_bits(udphy->pma_regmap, CMN_SSC_EN_OFFSET, CMN_ROPLL_SSC_EN, + FIELD_PREP(CMN_ROPLL_SSC_EN, dp->ssc)); + regmap_update_bits(udphy->pma_regmap, CMN_DP_RSTN_OFFSET, CMN_DP_CMN_RSTN, + FIELD_PREP(CMN_DP_CMN_RSTN, 0x1)); + + ret = regmap_read_poll_timeout(udphy->pma_regmap, CMN_ANA_ROPLL_DONE_OFFSET, val, + FIELD_GET(CMN_ANA_ROPLL_LOCK_DONE, val) && + FIELD_GET(CMN_ANA_ROPLL_AFC_DONE, val), + 0, 1000); + if (ret) { + dev_err(udphy->dev, "ROPLL is not lock, set_rate failed\n"); + return ret; + } + } + + if (dp->set_voltages) { + for (i = 0; i < dp->lanes; i++) { + lane = udphy->dp_lane_sel[i]; + switch (dp->link_rate) { + case 1620: + case 2700: + regmap_update_bits(udphy->pma_regmap, + TRSV_ANA_TX_CLK_OFFSET_N(lane), + LN_ANA_TX_SER_TXCLK_INV, + FIELD_PREP(LN_ANA_TX_SER_TXCLK_INV, + udphy->lane_mux_sel[lane])); + break; + + case 5400: + case 8100: + regmap_update_bits(udphy->pma_regmap, + TRSV_ANA_TX_CLK_OFFSET_N(lane), + LN_ANA_TX_SER_TXCLK_INV, + FIELD_PREP(LN_ANA_TX_SER_TXCLK_INV, 0x0)); + break; + } + + rk_udphy_dp_set_voltage(udphy, udphy->bw, dp->voltage[i], + dp->pre[i], lane); + } + } + + return 0; +} + +static const struct phy_ops rk_udphy_dp_phy_ops = { + .init = rk_udphy_dp_phy_init, + .exit = rk_udphy_dp_phy_exit, + .power_on = rk_udphy_dp_phy_power_on, + .power_off = rk_udphy_dp_phy_power_off, + .configure = rk_udphy_dp_phy_configure, + .owner = THIS_MODULE, +}; + +static int rk_udphy_usb3_phy_init(struct phy *phy) +{ + struct rk_udphy *udphy = phy_get_drvdata(phy); + int ret; + + mutex_lock(&udphy->mutex); + /* DP only or high-speed, disable U3 port */ + if (!(udphy->mode & UDPHY_MODE_USB) || udphy->hs) { + rk_udphy_u3_port_disable(udphy, true); + goto unlock; + } + + ret = rk_udphy_power_on(udphy, UDPHY_MODE_USB); + +unlock: + mutex_unlock(&udphy->mutex); + return ret; +} + +static int rk_udphy_usb3_phy_exit(struct phy *phy) +{ + struct rk_udphy *udphy = phy_get_drvdata(phy); + + mutex_lock(&udphy->mutex); + /* DP only or high-speed */ + if (!(udphy->mode & UDPHY_MODE_USB) || udphy->hs) + goto unlock; + + rk_udphy_power_off(udphy, UDPHY_MODE_USB); + +unlock: + mutex_unlock(&udphy->mutex); + return 0; +} + +static const struct phy_ops rk_udphy_usb3_phy_ops = { + .init = rk_udphy_usb3_phy_init, + .exit = rk_udphy_usb3_phy_exit, + .owner = THIS_MODULE, +}; + +static int rk_udphy_typec_mux_set(struct typec_mux_dev *mux, + struct typec_mux_state *state) +{ + struct rk_udphy *udphy = typec_mux_get_drvdata(mux); + u8 mode; + + mutex_lock(&udphy->mutex); + + switch (state->mode) { + case TYPEC_DP_STATE_C: + case TYPEC_DP_STATE_E: + udphy->lane_mux_sel[0] = PHY_LANE_MUX_DP; + udphy->lane_mux_sel[1] = PHY_LANE_MUX_DP; + udphy->lane_mux_sel[2] = PHY_LANE_MUX_DP; + udphy->lane_mux_sel[3] = PHY_LANE_MUX_DP; + mode = UDPHY_MODE_DP; + break; + + case TYPEC_DP_STATE_D: + default: + if (udphy->flip) { + udphy->lane_mux_sel[0] = PHY_LANE_MUX_DP; + udphy->lane_mux_sel[1] = PHY_LANE_MUX_DP; + udphy->lane_mux_sel[2] = PHY_LANE_MUX_USB; + udphy->lane_mux_sel[3] = PHY_LANE_MUX_USB; + } else { + udphy->lane_mux_sel[0] = PHY_LANE_MUX_USB; + udphy->lane_mux_sel[1] = PHY_LANE_MUX_USB; + udphy->lane_mux_sel[2] = PHY_LANE_MUX_DP; + udphy->lane_mux_sel[3] = PHY_LANE_MUX_DP; + } + mode = UDPHY_MODE_DP_USB; + break; + } + + if (state->alt && state->alt->svid == USB_TYPEC_DP_SID) { + struct typec_displayport_data *data = state->data; + + if (!data) { + rk_udphy_dp_hpd_event_trigger(udphy, false); + } else if (data->status & DP_STATUS_IRQ_HPD) { + rk_udphy_dp_hpd_event_trigger(udphy, false); + usleep_range(750, 800); + rk_udphy_dp_hpd_event_trigger(udphy, true); + } else if (data->status & DP_STATUS_HPD_STATE) { + if (udphy->mode != mode) { + udphy->mode = mode; + udphy->mode_change = true; + } + rk_udphy_dp_hpd_event_trigger(udphy, true); + } else { + rk_udphy_dp_hpd_event_trigger(udphy, false); + } + } + + mutex_unlock(&udphy->mutex); + return 0; +} + +static void rk_udphy_typec_mux_unregister(void *data) +{ + struct rk_udphy *udphy = data; + + typec_mux_unregister(udphy->mux); +} + +static int rk_udphy_setup_typec_mux(struct rk_udphy *udphy) +{ + struct typec_mux_desc mux_desc = {}; + + mux_desc.drvdata = udphy; + mux_desc.fwnode = dev_fwnode(udphy->dev); + mux_desc.set = rk_udphy_typec_mux_set; + + udphy->mux = typec_mux_register(udphy->dev, &mux_desc); + if (IS_ERR(udphy->mux)) { + dev_err(udphy->dev, "Error register typec mux: %ld\n", + PTR_ERR(udphy->mux)); + return PTR_ERR(udphy->mux); + } + + return devm_add_action_or_reset(udphy->dev, rk_udphy_typec_mux_unregister, + udphy); +} + +static const struct regmap_config rk_udphy_pma_regmap_cfg = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .fast_io = true, + .max_register = 0x20dc, +}; + +static struct phy *rk_udphy_phy_xlate(struct device *dev, const struct of_phandle_args *args) +{ + struct rk_udphy *udphy = dev_get_drvdata(dev); + + if (args->args_count == 0) + return ERR_PTR(-EINVAL); + + switch (args->args[0]) { + case PHY_TYPE_USB3: + return udphy->phy_u3; + case PHY_TYPE_DP: + return udphy->phy_dp; + } + + return ERR_PTR(-EINVAL); +} + +static int rk_udphy_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct phy_provider *phy_provider; + struct resource *res; + struct rk_udphy *udphy; + void __iomem *base; + int id, ret; + + udphy = devm_kzalloc(dev, sizeof(*udphy), GFP_KERNEL); + if (!udphy) + return -ENOMEM; + + udphy->cfgs = device_get_match_data(dev); + if (!udphy->cfgs) + return dev_err_probe(dev, -EINVAL, "missing match data\n"); + + base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); + if (IS_ERR(base)) + return PTR_ERR(base); + + /* find the phy-id from the io address */ + udphy->id = -ENODEV; + for (id = 0; id < udphy->cfgs->num_phys; id++) { + if (res->start == udphy->cfgs->phy_ids[id]) { + udphy->id = id; + break; + } + } + + if (udphy->id < 0) + return dev_err_probe(dev, -ENODEV, "no matching device found\n"); + + udphy->pma_regmap = devm_regmap_init_mmio(dev, base + UDPHY_PMA, + &rk_udphy_pma_regmap_cfg); + if (IS_ERR(udphy->pma_regmap)) + return PTR_ERR(udphy->pma_regmap); + + udphy->dev = dev; + ret = rk_udphy_parse_dt(udphy); + if (ret) + return ret; + + ret = rk_udphy_get_initial_status(udphy); + if (ret) + return ret; + + mutex_init(&udphy->mutex); + platform_set_drvdata(pdev, udphy); + + if (device_property_present(dev, "orientation-switch")) { + ret = rk_udphy_setup_orien_switch(udphy); + if (ret) + return ret; + } + + if (device_property_present(dev, "mode-switch")) { + ret = rk_udphy_setup_typec_mux(udphy); + if (ret) + return ret; + } + + udphy->phy_u3 = devm_phy_create(dev, dev->of_node, &rk_udphy_usb3_phy_ops); + if (IS_ERR(udphy->phy_u3)) { + ret = PTR_ERR(udphy->phy_u3); + return dev_err_probe(dev, ret, "failed to create USB3 phy\n"); + } + phy_set_drvdata(udphy->phy_u3, udphy); + + udphy->phy_dp = devm_phy_create(dev, dev->of_node, &rk_udphy_dp_phy_ops); + if (IS_ERR(udphy->phy_dp)) { + ret = PTR_ERR(udphy->phy_dp); + return dev_err_probe(dev, ret, "failed to create DP phy\n"); + } + phy_set_bus_width(udphy->phy_dp, rk_udphy_dplane_get(udphy)); + udphy->phy_dp->attrs.max_link_rate = 8100; + phy_set_drvdata(udphy->phy_dp, udphy); + + phy_provider = devm_of_phy_provider_register(dev, rk_udphy_phy_xlate); + if (IS_ERR(phy_provider)) { + ret = PTR_ERR(phy_provider); + return dev_err_probe(dev, ret, "failed to register phy provider\n"); + } + + return 0; +} + +static int __maybe_unused rk_udphy_resume(struct device *dev) +{ + struct rk_udphy *udphy = dev_get_drvdata(dev); + + if (udphy->dp_sink_hpd_sel) + rk_udphy_dp_hpd_event_trigger(udphy, udphy->dp_sink_hpd_cfg); + + return 0; +} + +static const struct dev_pm_ops rk_udphy_pm_ops = { + SET_LATE_SYSTEM_SLEEP_PM_OPS(NULL, rk_udphy_resume) +}; + +static const char * const rk_udphy_rst_list[] = { + "init", "cmn", "lane", "pcs_apb", "pma_apb" +}; + +static const struct rk_udphy_cfg rk3588_udphy_cfgs = { + .num_phys = 2, + .phy_ids = { + 0xfed80000, + 0xfed90000, + }, + .num_rsts = ARRAY_SIZE(rk_udphy_rst_list), + .rst_list = rk_udphy_rst_list, + .grfcfg = { + /* u2phy-grf */ + .bvalid_phy_con = RK_UDPHY_GEN_GRF_REG(0x0008, 1, 0, 0x2, 0x3), + .bvalid_grf_con = RK_UDPHY_GEN_GRF_REG(0x0010, 3, 2, 0x2, 0x3), + + /* usb-grf */ + .usb3otg0_cfg = RK_UDPHY_GEN_GRF_REG(0x001c, 15, 0, 0x1100, 0x0188), + .usb3otg1_cfg = RK_UDPHY_GEN_GRF_REG(0x0034, 15, 0, 0x1100, 0x0188), + + /* usbdpphy-grf */ + .low_pwrn = RK_UDPHY_GEN_GRF_REG(0x0004, 13, 13, 0, 1), + .rx_lfps = RK_UDPHY_GEN_GRF_REG(0x0004, 14, 14, 0, 1), + }, + .vogrfcfg = { + { + .hpd_trigger = RK_UDPHY_GEN_GRF_REG(0x0000, 11, 10, 1, 3), + .dp_lane_reg = 0x0000, + }, + { + .hpd_trigger = RK_UDPHY_GEN_GRF_REG(0x0008, 11, 10, 1, 3), + .dp_lane_reg = 0x0008, + }, + }, + .dp_tx_ctrl_cfg = { + rk3588_dp_tx_drv_ctrl_rbr_hbr, + rk3588_dp_tx_drv_ctrl_rbr_hbr, + rk3588_dp_tx_drv_ctrl_hbr2, + rk3588_dp_tx_drv_ctrl_hbr3, + }, + .dp_tx_ctrl_cfg_typec = { + rk3588_dp_tx_drv_ctrl_rbr_hbr_typec, + rk3588_dp_tx_drv_ctrl_rbr_hbr_typec, + rk3588_dp_tx_drv_ctrl_hbr2, + rk3588_dp_tx_drv_ctrl_hbr3, + }, +}; + +static const struct of_device_id rk_udphy_dt_match[] = { + { + .compatible = "rockchip,rk3588-usbdp-phy", + .data = &rk3588_udphy_cfgs + }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, rk_udphy_dt_match); + +static struct platform_driver rk_udphy_driver = { + .probe = rk_udphy_probe, + .driver = { + .name = "rockchip-usbdp-phy", + .of_match_table = rk_udphy_dt_match, + .pm = &rk_udphy_pm_ops, + }, +}; +module_platform_driver(rk_udphy_driver); + +MODULE_AUTHOR("Frank Wang "); +MODULE_AUTHOR("Zhang Yubing "); +MODULE_DESCRIPTION("Rockchip USBDP Combo PHY driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3-59-g8ed1b From 72907de9051dc2aa7b55c2a020e2872184ac17cd Mon Sep 17 00:00:00 2001 From: Xianwei Zhao Date: Fri, 12 Apr 2024 16:42:30 +0800 Subject: arm64: dts: meson: fix S4 power-controller node The power-controller module works well by adding its parent node secure-monitor. Fixes: 085f7a298a14 ("arm64: dts: add support for S4 power domain controller") Signed-off-by: Xianwei Zhao Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20240412-fix-secpwr-s4-v2-1-3802fd936d77@amlogic.com Signed-off-by: Neil Armstrong --- arch/arm64/boot/dts/amlogic/meson-s4.dtsi | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/arch/arm64/boot/dts/amlogic/meson-s4.dtsi b/arch/arm64/boot/dts/amlogic/meson-s4.dtsi index ce90b35686a2..10896f9df682 100644 --- a/arch/arm64/boot/dts/amlogic/meson-s4.dtsi +++ b/arch/arm64/boot/dts/amlogic/meson-s4.dtsi @@ -65,10 +65,15 @@ #clock-cells = <0>; }; - pwrc: power-controller { - compatible = "amlogic,meson-s4-pwrc"; - #power-domain-cells = <1>; - status = "okay"; + firmware { + sm: secure-monitor { + compatible = "amlogic,meson-gxbb-sm"; + + pwrc: power-controller { + compatible = "amlogic,meson-s4-pwrc"; + #power-domain-cells = <1>; + }; + }; }; soc { -- cgit v1.2.3-59-g8ed1b From 8b8e6e24eca07efb4860c97aa773dd36fa3a1164 Mon Sep 17 00:00:00 2001 From: Xianwei Zhao Date: Mon, 1 Apr 2024 18:10:49 +0800 Subject: dt-bindings: arm: amlogic: add A4 support Document the new A4 SoC/board device tree bindings. Amlogic A4 is an application processor designed for smart audio and IoT applications. Acked-by: Krzysztof Kozlowski Signed-off-by: Xianwei Zhao Link: https://lore.kernel.org/r/20240401-basic_dt-v3-1-cb29ae1c16da@amlogic.com Signed-off-by: Neil Armstrong --- Documentation/devicetree/bindings/arm/amlogic.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Documentation/devicetree/bindings/arm/amlogic.yaml b/Documentation/devicetree/bindings/arm/amlogic.yaml index b66b93b8bfd3..c0c3f18a1f4b 100644 --- a/Documentation/devicetree/bindings/arm/amlogic.yaml +++ b/Documentation/devicetree/bindings/arm/amlogic.yaml @@ -202,6 +202,12 @@ properties: - amlogic,ad402 - const: amlogic,a1 + - description: Boards with the Amlogic A4 A113L2 SoC + items: + - enum: + - amlogic,ba400 + - const: amlogic,a4 + - description: Boards with the Amlogic C3 C302X/C308L SoC items: - enum: -- cgit v1.2.3-59-g8ed1b From 7e05175cb7be232450e70fe75ba2a852947eecc8 Mon Sep 17 00:00:00 2001 From: Xianwei Zhao Date: Mon, 1 Apr 2024 18:10:50 +0800 Subject: dt-bindings: arm: amlogic: add A5 support Document the new A5 SoC/board device tree bindings. Amlogic A5 is an application processor designed for smart audio and IoT applications. Acked-by: Krzysztof Kozlowski Signed-off-by: Xianwei Zhao Link: https://lore.kernel.org/r/20240401-basic_dt-v3-2-cb29ae1c16da@amlogic.com Signed-off-by: Neil Armstrong --- Documentation/devicetree/bindings/arm/amlogic.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Documentation/devicetree/bindings/arm/amlogic.yaml b/Documentation/devicetree/bindings/arm/amlogic.yaml index c0c3f18a1f4b..a374b98080fe 100644 --- a/Documentation/devicetree/bindings/arm/amlogic.yaml +++ b/Documentation/devicetree/bindings/arm/amlogic.yaml @@ -208,6 +208,12 @@ properties: - amlogic,ba400 - const: amlogic,a4 + - description: Boards with the Amlogic A5 A113X2 SoC + items: + - enum: + - amlogic,av400 + - const: amlogic,a5 + - description: Boards with the Amlogic C3 C302X/C308L SoC items: - enum: -- cgit v1.2.3-59-g8ed1b From a652d67a84575e09b52614a2f81399772d52876b Mon Sep 17 00:00:00 2001 From: Xianwei Zhao Date: Mon, 1 Apr 2024 18:10:51 +0800 Subject: dt-bindings: serial: amlogic,meson-uart: Add compatible string for A4 Amlogic A4 SoCs uses the same UART controller as S4 SoCs and G12A. There is no need for an extra compatible line in the driver, but add A4 compatible line for documentation. Signed-off-by: Xianwei Zhao Acked-by: Conor Dooley Reviewed-by: Martin Blumenstingl Link: https://lore.kernel.org/r/20240401-basic_dt-v3-3-cb29ae1c16da@amlogic.com Signed-off-by: Neil Armstrong --- Documentation/devicetree/bindings/serial/amlogic,meson-uart.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/serial/amlogic,meson-uart.yaml b/Documentation/devicetree/bindings/serial/amlogic,meson-uart.yaml index 2e189e548327..0565fb7649c5 100644 --- a/Documentation/devicetree/bindings/serial/amlogic,meson-uart.yaml +++ b/Documentation/devicetree/bindings/serial/amlogic,meson-uart.yaml @@ -54,7 +54,9 @@ properties: - const: amlogic,meson-gx-uart - description: UART controller on S4 compatible SoCs items: - - const: amlogic,t7-uart + - enum: + - amlogic,a4-uart + - amlogic,t7-uart - const: amlogic,meson-s4-uart reg: -- cgit v1.2.3-59-g8ed1b From 6ef63301fa37087414342269bc02a2a930e81779 Mon Sep 17 00:00:00 2001 From: Xianwei Zhao Date: Mon, 1 Apr 2024 18:10:52 +0800 Subject: arm64: dts: add support for A4 based Amlogic BA400 Amlogic A4 is an application processor designed for smart audio and IoT applications. Add basic support for the A4 based Amlogic BA400 board, which describes the following components: CPU, GIC, IRQ, Timer and UART. These are capable of booting up into the serial console. Signed-off-by: Xianwei Zhao Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20240401-basic_dt-v3-4-cb29ae1c16da@amlogic.com Signed-off-by: Neil Armstrong --- arch/arm64/boot/dts/amlogic/Makefile | 1 + .../boot/dts/amlogic/amlogic-a4-a113l2-ba400.dts | 42 ++++++++++++++ arch/arm64/boot/dts/amlogic/amlogic-a4-common.dtsi | 66 ++++++++++++++++++++++ arch/arm64/boot/dts/amlogic/amlogic-a4.dtsi | 40 +++++++++++++ 4 files changed, 149 insertions(+) create mode 100644 arch/arm64/boot/dts/amlogic/amlogic-a4-a113l2-ba400.dts create mode 100644 arch/arm64/boot/dts/amlogic/amlogic-a4-common.dtsi create mode 100644 arch/arm64/boot/dts/amlogic/amlogic-a4.dtsi diff --git a/arch/arm64/boot/dts/amlogic/Makefile b/arch/arm64/boot/dts/amlogic/Makefile index d525e5123fbc..2c1f3bb38f78 100644 --- a/arch/arm64/boot/dts/amlogic/Makefile +++ b/arch/arm64/boot/dts/amlogic/Makefile @@ -1,4 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 +dtb-$(CONFIG_ARCH_MESON) += amlogic-a4-a113l2-ba400.dtb dtb-$(CONFIG_ARCH_MESON) += amlogic-c3-c302x-aw409.dtb dtb-$(CONFIG_ARCH_MESON) += amlogic-t7-a311d2-an400.dtb dtb-$(CONFIG_ARCH_MESON) += amlogic-t7-a311d2-khadas-vim4.dtb diff --git a/arch/arm64/boot/dts/amlogic/amlogic-a4-a113l2-ba400.dts b/arch/arm64/boot/dts/amlogic/amlogic-a4-a113l2-ba400.dts new file mode 100644 index 000000000000..ad3127e695d9 --- /dev/null +++ b/arch/arm64/boot/dts/amlogic/amlogic-a4-a113l2-ba400.dts @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2024 Amlogic, Inc. All rights reserved. + */ + +/dts-v1/; + +#include "amlogic-a4.dtsi" + +/ { + model = "Amlogic A113L2 ba400 Development Board"; + compatible = "amlogic,ba400", "amlogic,a4"; + interrupt-parent = <&gic>; + #address-cells = <2>; + #size-cells = <2>; + + aliases { + serial0 = &uart_b; + }; + + memory@0 { + device_type = "memory"; + reg = <0x0 0x0 0x0 0x40000000>; + }; + + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + /* 10 MiB reserved for ARM Trusted Firmware */ + secmon_reserved: secmon@5000000 { + compatible = "shared-dma-pool"; + reg = <0x0 0x05000000 0x0 0xa00000>; + no-map; + }; + }; +}; + +&uart_b { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/amlogic/amlogic-a4-common.dtsi b/arch/arm64/boot/dts/amlogic/amlogic-a4-common.dtsi new file mode 100644 index 000000000000..b6106ad4a072 --- /dev/null +++ b/arch/arm64/boot/dts/amlogic/amlogic-a4-common.dtsi @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2024 Amlogic, Inc. All rights reserved. + */ + +#include +#include +#include +/ { + timer { + compatible = "arm,armv8-timer"; + interrupts = , + , + , + ; + }; + + psci { + compatible = "arm,psci-1.0"; + method = "smc"; + }; + + xtal: xtal-clk { + compatible = "fixed-clock"; + clock-frequency = <24000000>; + clock-output-names = "xtal"; + #clock-cells = <0>; + }; + + soc { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + ranges; + + gic: interrupt-controller@fff01000 { + compatible = "arm,gic-400"; + reg = <0x0 0xfff01000 0 0x1000>, + <0x0 0xfff02000 0 0x2000>, + <0x0 0xfff04000 0 0x2000>, + <0x0 0xfff06000 0 0x2000>; + #interrupt-cells = <3>; + #address-cells = <0>; + interrupt-controller; + interrupts = ; + }; + + apb: bus@fe000000 { + compatible = "simple-bus"; + reg = <0x0 0xfe000000 0x0 0x480000>; + #address-cells = <2>; + #size-cells = <2>; + ranges = <0x0 0x0 0x0 0xfe000000 0x0 0x480000>; + + uart_b: serial@7a000 { + compatible = "amlogic,a4-uart", + "amlogic,meson-s4-uart"; + reg = <0x0 0x7a000 0x0 0x18>; + interrupts = ; + clocks = <&xtal>, <&xtal>, <&xtal>; + clock-names = "xtal", "pclk", "baud"; + status = "disabled"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/amlogic/amlogic-a4.dtsi b/arch/arm64/boot/dts/amlogic/amlogic-a4.dtsi new file mode 100644 index 000000000000..73ca1d7eed81 --- /dev/null +++ b/arch/arm64/boot/dts/amlogic/amlogic-a4.dtsi @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2024 Amlogic, Inc. All rights reserved. + */ + +#include "amlogic-a4-common.dtsi" +/ { + cpus { + #address-cells = <2>; + #size-cells = <0>; + + cpu0: cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a53"; + reg = <0x0 0x0>; + enable-method = "psci"; + }; + + cpu1: cpu@1 { + device_type = "cpu"; + compatible = "arm,cortex-a53"; + reg = <0x0 0x1>; + enable-method = "psci"; + }; + + cpu2: cpu@2 { + device_type = "cpu"; + compatible = "arm,cortex-a53"; + reg = <0x0 0x2>; + enable-method = "psci"; + }; + + cpu3: cpu@3 { + device_type = "cpu"; + compatible = "arm,cortex-a53"; + reg = <0x0 0x3>; + enable-method = "psci"; + }; + }; +}; -- cgit v1.2.3-59-g8ed1b From a654af36fe8b54e360fcf155b785df3aa0eab73e Mon Sep 17 00:00:00 2001 From: Xianwei Zhao Date: Mon, 1 Apr 2024 18:10:53 +0800 Subject: arm64: dts: add support for A5 based Amlogic AV400 Amlogic A5 is an application processor designed for smart audio and IoT applications. Add basic support for the A5 based Amlogic AV400 board, which describes the following components: CPU, GIC, IRQ, Timer and UART. These are capable of booting up into the serial console. Signed-off-by: Xianwei Zhao Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20240401-basic_dt-v3-5-cb29ae1c16da@amlogic.com Signed-off-by: Neil Armstrong --- arch/arm64/boot/dts/amlogic/Makefile | 1 + .../boot/dts/amlogic/amlogic-a5-a113x2-av400.dts | 42 ++++++++++++++++++++++ arch/arm64/boot/dts/amlogic/amlogic-a5.dtsi | 40 +++++++++++++++++++++ 3 files changed, 83 insertions(+) create mode 100644 arch/arm64/boot/dts/amlogic/amlogic-a5-a113x2-av400.dts create mode 100644 arch/arm64/boot/dts/amlogic/amlogic-a5.dtsi diff --git a/arch/arm64/boot/dts/amlogic/Makefile b/arch/arm64/boot/dts/amlogic/Makefile index 2c1f3bb38f78..0f29517da5ec 100644 --- a/arch/arm64/boot/dts/amlogic/Makefile +++ b/arch/arm64/boot/dts/amlogic/Makefile @@ -1,5 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 dtb-$(CONFIG_ARCH_MESON) += amlogic-a4-a113l2-ba400.dtb +dtb-$(CONFIG_ARCH_MESON) += amlogic-a5-a113x2-av400.dtb dtb-$(CONFIG_ARCH_MESON) += amlogic-c3-c302x-aw409.dtb dtb-$(CONFIG_ARCH_MESON) += amlogic-t7-a311d2-an400.dtb dtb-$(CONFIG_ARCH_MESON) += amlogic-t7-a311d2-khadas-vim4.dtb diff --git a/arch/arm64/boot/dts/amlogic/amlogic-a5-a113x2-av400.dts b/arch/arm64/boot/dts/amlogic/amlogic-a5-a113x2-av400.dts new file mode 100644 index 000000000000..11d8b88c1ce5 --- /dev/null +++ b/arch/arm64/boot/dts/amlogic/amlogic-a5-a113x2-av400.dts @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2024 Amlogic, Inc. All rights reserved. + */ + +/dts-v1/; + +#include "amlogic-a5.dtsi" + +/ { + model = "Amlogic A113X2 av400 Development Board"; + compatible = "amlogic,av400", "amlogic,a5"; + interrupt-parent = <&gic>; + #address-cells = <2>; + #size-cells = <2>; + + aliases { + serial0 = &uart_b; + }; + + memory@0 { + device_type = "memory"; + reg = <0x0 0x0 0x0 0x40000000>; + }; + + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + /* 10 MiB reserved for ARM Trusted Firmware */ + secmon_reserved: secmon@5000000 { + compatible = "shared-dma-pool"; + reg = <0x0 0x05000000 0x0 0xa00000>; + no-map; + }; + }; +}; + +&uart_b { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/amlogic/amlogic-a5.dtsi b/arch/arm64/boot/dts/amlogic/amlogic-a5.dtsi new file mode 100644 index 000000000000..43f68a7da2f7 --- /dev/null +++ b/arch/arm64/boot/dts/amlogic/amlogic-a5.dtsi @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2024 Amlogic, Inc. All rights reserved. + */ + +#include "amlogic-a4-common.dtsi" +/ { + cpus { + #address-cells = <2>; + #size-cells = <0>; + + cpu0: cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a55"; + reg = <0x0 0x0>; + enable-method = "psci"; + }; + + cpu1: cpu@100 { + device_type = "cpu"; + compatible = "arm,cortex-a55"; + reg = <0x0 0x100>; + enable-method = "psci"; + }; + + cpu2: cpu@200 { + device_type = "cpu"; + compatible = "arm,cortex-a55"; + reg = <0x0 0x200>; + enable-method = "psci"; + }; + + cpu3: cpu@300 { + device_type = "cpu"; + compatible = "arm,cortex-a55"; + reg = <0x0 0x300>; + enable-method = "psci"; + }; + }; +}; -- cgit v1.2.3-59-g8ed1b From 657852135d39b75b1b5139839b7388c1d47f3ecc Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Fri, 5 Apr 2024 14:17:58 -0700 Subject: perf annotate-data: Fix global variable lookup The recent change in the global variable handling added a bug to miss setting the return value even if it found a data type. Also add the type name in the debug message. Fixes: 1ebb5e17ef21b492 ("perf annotate-data: Add get_global_var_type()") Reviewed-by: Ian Rogers Signed-off-by: Namhyung Kim Cc: Adrian Hunter Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Namhyung Kim Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20240405211800.1412920-3-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate-data.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c index 043d80791bd0..1047ea9d578c 100644 --- a/tools/perf/util/annotate-data.c +++ b/tools/perf/util/annotate-data.c @@ -1468,8 +1468,10 @@ static int find_data_type_die(struct data_loc_info *dloc, Dwarf_Die *type_die) &offset, type_die)) { dloc->type_offset = offset; - pr_debug_dtp("found PC-rel by addr=%#"PRIx64" offset=%#x\n", + pr_debug_dtp("found PC-rel by addr=%#"PRIx64" offset=%#x", dloc->var_addr, offset); + pr_debug_type_name(type_die, TSR_KIND_TYPE); + ret = 0; goto out; } } -- cgit v1.2.3-59-g8ed1b From 879ebf3c830dba437781d034c536af53b0bff0c0 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Fri, 5 Apr 2024 14:17:59 -0700 Subject: perf annotate-data: Do not delete non-asm lines For data type profiling, it removed non-instruction lines from the list of annotation lines. It was to simplify the implementation dealing with instructions like to calculate the PC-relative address and to search the shortest path to the target instruction or basic block. But it means that it removes all the comments and debug information in the annotate output like source file name and line numbers. To support both code annotation and data type annotation, it'd be better to keep the non-instruction lines as well. So this change is to skip those lines during the data type profiling and to display them in the normal perf annotate output. No function changes intended (other than having more lines). Reviewed-by: Ian Rogers Signed-off-by: Namhyung Kim Cc: Adrian Hunter Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20240405211800.1412920-4-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate-data.c | 6 +++ tools/perf/util/annotate.c | 93 ++++++++++++++++++++++++++++++----------- 2 files changed, 74 insertions(+), 25 deletions(-) diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c index 1047ea9d578c..b69a1cd1577a 100644 --- a/tools/perf/util/annotate-data.c +++ b/tools/perf/util/annotate-data.c @@ -1314,6 +1314,8 @@ static int find_data_type_insn(struct data_loc_info *dloc, int reg, list_for_each_entry(bb, basic_blocks, list) { struct disasm_line *dl = bb->begin; + BUG_ON(bb->begin->al.offset == -1 || bb->end->al.offset == -1); + pr_debug_dtp("bb: [%"PRIx64" - %"PRIx64"]\n", bb->begin->al.offset, bb->end->al.offset); @@ -1321,6 +1323,10 @@ static int find_data_type_insn(struct data_loc_info *dloc, int reg, u64 this_ip = sym->start + dl->al.offset; u64 addr = map__rip_2objdump(dloc->ms->map, this_ip); + /* Skip comment or debug info lines */ + if (dl->al.offset == -1) + continue; + /* Update variable type at this address */ update_var_state(&state, dloc, addr, dl->al.offset, var_types); diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 4db49611c386..5d9b79559c73 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -2159,23 +2159,10 @@ int annotate_get_insn_location(struct arch *arch, struct disasm_line *dl, static void symbol__ensure_annotate(struct map_symbol *ms, struct evsel *evsel) { - struct disasm_line *dl, *tmp_dl; - struct annotation *notes; - - notes = symbol__annotation(ms->sym); - if (!list_empty(¬es->src->source)) - return; - - if (symbol__annotate(ms, evsel, NULL) < 0) - return; + struct annotation *notes = symbol__annotation(ms->sym); - /* remove non-insn disasm lines for simplicity */ - list_for_each_entry_safe(dl, tmp_dl, ¬es->src->source, al.node) { - if (dl->al.offset == -1) { - list_del(&dl->al.node); - free(dl); - } - } + if (list_empty(¬es->src->source)) + symbol__annotate(ms, evsel, NULL); } static struct disasm_line *find_disasm_line(struct symbol *sym, u64 ip, @@ -2187,6 +2174,9 @@ static struct disasm_line *find_disasm_line(struct symbol *sym, u64 ip, notes = symbol__annotation(sym); list_for_each_entry(dl, ¬es->src->source, al.node) { + if (dl->al.offset == -1) + continue; + if (sym->start + dl->al.offset == ip) { /* * llvm-objdump places "lock" in a separate line and @@ -2251,6 +2241,46 @@ static bool is_stack_canary(struct arch *arch, struct annotated_op_loc *loc) return false; } +static struct disasm_line * +annotation__prev_asm_line(struct annotation *notes, struct disasm_line *curr) +{ + struct list_head *sources = ¬es->src->source; + struct disasm_line *prev; + + if (curr == list_first_entry(sources, struct disasm_line, al.node)) + return NULL; + + prev = list_prev_entry(curr, al.node); + while (prev->al.offset == -1 && + prev != list_first_entry(sources, struct disasm_line, al.node)) + prev = list_prev_entry(prev, al.node); + + if (prev->al.offset == -1) + return NULL; + + return prev; +} + +static struct disasm_line * +annotation__next_asm_line(struct annotation *notes, struct disasm_line *curr) +{ + struct list_head *sources = ¬es->src->source; + struct disasm_line *next; + + if (curr == list_last_entry(sources, struct disasm_line, al.node)) + return NULL; + + next = list_next_entry(curr, al.node); + while (next->al.offset == -1 && + next != list_last_entry(sources, struct disasm_line, al.node)) + next = list_next_entry(next, al.node); + + if (next->al.offset == -1) + return NULL; + + return next; +} + u64 annotate_calc_pcrel(struct map_symbol *ms, u64 ip, int offset, struct disasm_line *dl) { @@ -2266,12 +2296,12 @@ u64 annotate_calc_pcrel(struct map_symbol *ms, u64 ip, int offset, * disasm_line. If it's the last one, we can use symbol's end * address directly. */ - if (&dl->al.node == notes->src->source.prev) + next = annotation__next_asm_line(notes, dl); + if (next == NULL) addr = ms->sym->end + offset; - else { - next = list_next_entry(dl, al.node); + else addr = ip + (next->al.offset - dl->al.offset) + offset; - } + return map__rip_2objdump(ms->map, addr); } @@ -2403,10 +2433,13 @@ retry: * from the previous instruction. */ if (dl->al.offset > 0) { + struct annotation *notes; struct disasm_line *prev_dl; - prev_dl = list_prev_entry(dl, al.node); - if (ins__is_fused(arch, prev_dl->ins.name, dl->ins.name)) { + notes = symbol__annotation(ms->sym); + prev_dl = annotation__prev_asm_line(notes, dl); + + if (prev_dl && ins__is_fused(arch, prev_dl->ins.name, dl->ins.name)) { dl = prev_dl; goto retry; } @@ -2511,8 +2544,16 @@ static bool process_basic_block(struct basic_block_data *bb_data, last_dl = list_last_entry(¬es->src->source, struct disasm_line, al.node); + if (last_dl->al.offset == -1) + last_dl = annotation__prev_asm_line(notes, last_dl); + + if (last_dl == NULL) + return false; list_for_each_entry_from(dl, ¬es->src->source, al.node) { + /* Skip comment or debug info line */ + if (dl->al.offset == -1) + continue; /* Found the target instruction */ if (sym->start + dl->al.offset == target) { found = true; @@ -2533,7 +2574,8 @@ static bool process_basic_block(struct basic_block_data *bb_data, /* jump instruction creates new basic block(s) */ next_dl = find_disasm_line(sym, sym->start + dl->ops.target.offset, /*allow_update=*/false); - add_basic_block(bb_data, link, next_dl); + if (next_dl) + add_basic_block(bb_data, link, next_dl); /* * FIXME: determine conditional jumps properly. @@ -2541,8 +2583,9 @@ static bool process_basic_block(struct basic_block_data *bb_data, * next disasm line. */ if (!strstr(dl->ins.name, "jmp")) { - next_dl = list_next_entry(dl, al.node); - add_basic_block(bb_data, link, next_dl); + next_dl = annotation__next_asm_line(notes, dl); + if (next_dl) + add_basic_block(bb_data, link, next_dl); } break; -- cgit v1.2.3-59-g8ed1b From 0235abd89feaf29fe67d3abbe2c18b7119503537 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Fri, 5 Apr 2024 14:18:00 -0700 Subject: perf annotate: Get rid of symbol__ensure_annotate() Now symbol__annotate() is reentrant and it doesn't need to remove non-instruction lines. Let's get rid of symbol__ensure_annotate() and call symbol__annotate() directly. Also we can use it to get the arch pointer instead of calling evsel__get_arch() directly. Reviewed-by: Ian Rogers Signed-off-by: Namhyung Kim Cc: Adrian Hunter Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20240405211800.1412920-5-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 5d9b79559c73..11da27801d88 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -2157,14 +2157,6 @@ int annotate_get_insn_location(struct arch *arch, struct disasm_line *dl, return 0; } -static void symbol__ensure_annotate(struct map_symbol *ms, struct evsel *evsel) -{ - struct annotation *notes = symbol__annotation(ms->sym); - - if (list_empty(¬es->src->source)) - symbol__annotate(ms, evsel, NULL); -} - static struct disasm_line *find_disasm_line(struct symbol *sym, u64 ip, bool allow_update) { @@ -2339,14 +2331,12 @@ struct annotated_data_type *hist_entry__get_data_type(struct hist_entry *he) return NULL; } - if (evsel__get_arch(evsel, &arch) < 0) { + /* Make sure it has the disasm of the function */ + if (symbol__annotate(ms, evsel, &arch) < 0) { ann_data_stat.no_insn++; return NULL; } - /* Make sure it runs objdump to get disasm of the function */ - symbol__ensure_annotate(ms, evsel); - /* * Get a disasm to extract the location from the insn. * This is too slow... -- cgit v1.2.3-59-g8ed1b From 4b5ee6db2d3cd6249919ae554552856de0e29791 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Wed, 3 Apr 2024 09:46:36 -0700 Subject: perf metrics: Remove the "No_group" metric group Rather than place metrics without a metric group in "No_group" place them in a a metric group that is their name. Still allow such metrics to be selected if "No_group" is passed, this change just impacts perf list. Reviewed-by: Kan Liang Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andi Kleen Cc: Ingo Molnar Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20240403164636.3429091-1-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/metricgroup.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c index 79ef6095ab28..6ec083af14a1 100644 --- a/tools/perf/util/metricgroup.c +++ b/tools/perf/util/metricgroup.c @@ -455,7 +455,7 @@ static int metricgroup__add_to_mep_groups(const struct pmu_metric *pm, const char *g; char *omg, *mg; - mg = strdup(pm->metric_group ?: "No_group"); + mg = strdup(pm->metric_group ?: pm->metric_name); if (!mg) return -ENOMEM; omg = mg; @@ -466,7 +466,7 @@ static int metricgroup__add_to_mep_groups(const struct pmu_metric *pm, if (strlen(g)) me = mep_lookup(groups, g, pm->metric_name); else - me = mep_lookup(groups, "No_group", pm->metric_name); + me = mep_lookup(groups, pm->metric_name, pm->metric_name); if (me) { me->metric_desc = pm->desc; -- cgit v1.2.3-59-g8ed1b From 256ef072b3842273ce703db18b603b051aca95fe Mon Sep 17 00:00:00 2001 From: James Clark Date: Wed, 10 Apr 2024 11:34:52 +0100 Subject: perf tests: Make "test data symbol" more robust on Neoverse N1 To prevent anyone from seeing a test failure appear as a regression and thinking that it was caused by their code change, insert some noise into the loop which makes it immune to sampling bias issues (errata 1694299). The "test data symbol" test can fail with any unrelated change that shifts the loop into an unfortunate position in the Perf binary which is almost impossible to debug as the root cause of the test failure. Ultimately it's caused by the referenced errata. Fixes: 60abedb8aa902b06 ("perf test: Introduce script for data symbol testing") Reviewed-by: Ian Rogers Signed-off-by: James Clark Acked-by: Namhyung Kim Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Athira Rajeev Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Leo Yan Cc: Mark Rutland Cc: Peter Zijlstra Cc: Spoorthy S Link: https://lore.kernel.org/r/20240410103458.813656-2-james.clark@arm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/workloads/datasym.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tools/perf/tests/workloads/datasym.c b/tools/perf/tests/workloads/datasym.c index ddd40bc63448..8e08fc75a973 100644 --- a/tools/perf/tests/workloads/datasym.c +++ b/tools/perf/tests/workloads/datasym.c @@ -16,6 +16,22 @@ static int datasym(int argc __maybe_unused, const char **argv __maybe_unused) { for (;;) { buf1.data1++; + if (buf1.data1 == 123) { + /* + * Add some 'noise' in the loop to work around errata + * 1694299 on Arm N1. + * + * Bias exists in SPE sampling which can cause the load + * and store instructions to be skipped entirely. This + * comes and goes randomly depending on the offset the + * linker places the datasym loop at in the Perf binary. + * With an extra branch in the middle of the loop that + * isn't always taken, the instruction stream is no + * longer a continuous repeating pattern that interacts + * badly with the bias. + */ + buf1.data1++; + } buf1.data2 += buf1.data1; } return 0; -- cgit v1.2.3-59-g8ed1b From 2dade41a533f337447b945239b87ff31a8857890 Mon Sep 17 00:00:00 2001 From: James Clark Date: Wed, 10 Apr 2024 11:34:53 +0100 Subject: perf tests: Apply attributes to all events in object code reading test PERF_PMU_CAP_EXTENDED_HW_TYPE results in multiple events being opened on heterogeneous systems. Currently this test only sets its required attributes on the first event. Not disabling enable_on_exec on the other events causes the test to fail because the forked objdump processes are sampled. No tracking event is opened so Perf only knows about its own mappings causing the objdump samples to give the following error: $ perf test -vvv "object code reading" Reading object code for memory address: 0xffff9aaa55ec thread__find_map failed ---- end(-1) ---- 24: Object code reading : FAILED! Fixes: 251aa040244a3b17 ("perf parse-events: Wildcard most "numeric" events") Reviewed-by: Ian Rogers Signed-off-by: James Clark Acked-by: Namhyung Kim Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Athira Rajeev Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Leo Yan Cc: Mark Rutland Cc: Peter Zijlstra Cc: Spoorthy S Link: https://lore.kernel.org/r/20240410103458.813656-3-james.clark@arm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/code-reading.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tools/perf/tests/code-reading.c b/tools/perf/tests/code-reading.c index 7a3a7bbbec71..29d2f3ee4e10 100644 --- a/tools/perf/tests/code-reading.c +++ b/tools/perf/tests/code-reading.c @@ -637,11 +637,11 @@ static int do_test_code_reading(bool try_kcore) evlist__config(evlist, &opts, NULL); - evsel = evlist__first(evlist); - - evsel->core.attr.comm = 1; - evsel->core.attr.disabled = 1; - evsel->core.attr.enable_on_exec = 0; + evlist__for_each_entry(evlist, evsel) { + evsel->core.attr.comm = 1; + evsel->core.attr.disabled = 1; + evsel->core.attr.enable_on_exec = 0; + } ret = evlist__open(evlist); if (ret < 0) { -- cgit v1.2.3-59-g8ed1b From df12e21d4e15e48a5e7d12e58f1a00742c4177d0 Mon Sep 17 00:00:00 2001 From: James Clark Date: Wed, 10 Apr 2024 11:34:54 +0100 Subject: perf map: Remove kernel map before updating start and end addresses In a debug build there is validation that mmap lists are sorted when taking a lock. In machine__update_kernel_mmap() the start and end addresses are updated resulting in an unsorted list before the map is removed from the list. When the map is removed, the lock is taken which triggers the validation and the failure: $ perf test "object code reading" --- start --- perf: util/maps.c:88: check_invariants: Assertion `map__start(prev) <= map__start(map)' failed. Aborted Fix it by updating the addresses after removal, but before insertion. The bug depends on the ordering and type of debug info on the system and doesn't reproduce everywhere. Fixes: 659ad3492b913c90 ("perf maps: Switch from rbtree to lazily sorted array for addresses") Reviewed-by: Ian Rogers Signed-off-by: James Clark Acked-by: Namhyung Kim Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Athira Rajeev Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Leo Yan Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Spoorthy S Link: https://lore.kernel.org/r/20240410103458.813656-4-james.clark@arm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/machine.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index 5eb9044bc223..a26c8bea58d0 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -1549,8 +1549,8 @@ static int machine__update_kernel_mmap(struct machine *machine, updated = map__get(orig); machine->vmlinux_map = updated; - machine__set_kernel_mmap(machine, start, end); maps__remove(machine__kernel_maps(machine), orig); + machine__set_kernel_mmap(machine, start, end); err = maps__insert(machine__kernel_maps(machine), updated); map__put(orig); -- cgit v1.2.3-59-g8ed1b From 7aa87499797c8e805c93fb0fd457c6babfb44bdb Mon Sep 17 00:00:00 2001 From: James Clark Date: Wed, 10 Apr 2024 11:34:55 +0100 Subject: perf tests: Remove dependency on lscpu This check can be done with uname which is more portable. At the same time re-arrange it into a standard if statement so that it's more readable. Reviewed-by: Ian Rogers Signed-off-by: James Clark Acked-by: Namhyung Kim Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Athira Rajeev Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Leo Yan Cc: Mark Rutland Cc: Peter Zijlstra Cc: Spoorthy S Link: https://lore.kernel.org/r/20240410103458.813656-5-james.clark@arm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/shell/test_arm_callgraph_fp.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/perf/tests/shell/test_arm_callgraph_fp.sh b/tools/perf/tests/shell/test_arm_callgraph_fp.sh index 83b53591b1ea..61898e256616 100755 --- a/tools/perf/tests/shell/test_arm_callgraph_fp.sh +++ b/tools/perf/tests/shell/test_arm_callgraph_fp.sh @@ -6,7 +6,9 @@ shelldir=$(dirname "$0") # shellcheck source=lib/perf_has_symbol.sh . "${shelldir}"/lib/perf_has_symbol.sh -lscpu | grep -q "aarch64" || exit 2 +if [ "$(uname -m)" != "aarch64" ]; then + exit 2 +fi if perf version --build-options | grep HAVE_DWARF_UNWIND_SUPPORT | grep -q OFF then -- cgit v1.2.3-59-g8ed1b From eb833488631b171e693a6917eb17b41fdedda659 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 10 Apr 2024 20:32:50 -0700 Subject: perf annotate-data: Skip sample histogram for stack canary It's a pseudo data type and has no field. Fixes: b3c95109c131fcc9 ("perf annotate-data: Add stack canary type") Closes: https://lore.kernel.org/lkml/Zhb6jJneP36Z-or0@x1 Reported-by: Arnaldo Carvalho de Melo Signed-off-by: Namhyung Kim Tested-by: Arnaldo Carvalho de Melo Cc: Adrian Hunter Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Namhyung Kim Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20240411033256.2099646-2-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 11da27801d88..ec79c120a7d2 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -2399,8 +2399,9 @@ retry: mem_type = find_data_type(&dloc); if (mem_type == NULL && is_stack_canary(arch, op_loc)) { - mem_type = &canary_type; - dloc.type_offset = 0; + istat->good++; + he->mem_type_off = 0; + return &canary_type; } if (mem_type) -- cgit v1.2.3-59-g8ed1b From d9aedc12d3477ab72ec48bb7abb0f038c902c937 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 10 Apr 2024 20:32:51 -0700 Subject: perf annotate: Show progress of sample processing Like 'perf report', it can take a while to process samples. Show a progress window to inform users how that it is not stuck. Reviewed-by: Ian Rogers Signed-off-by: Namhyung Kim Tested-by: Arnaldo Carvalho de Melo Cc: Adrian Hunter Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20240411033256.2099646-3-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-annotate.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 16e1581207c9..332e1ddcacbd 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -37,6 +37,7 @@ #include "util/map_symbol.h" #include "util/branch.h" #include "util/util.h" +#include "ui/progress.h" #include #include @@ -665,13 +666,23 @@ static int __cmd_annotate(struct perf_annotate *ann) evlist__for_each_entry(session->evlist, pos) { struct hists *hists = evsel__hists(pos); u32 nr_samples = hists->stats.nr_samples; + struct ui_progress prog; if (nr_samples > 0) { total_nr_samples += nr_samples; - hists__collapse_resort(hists, NULL); + + ui_progress__init(&prog, nr_samples, + "Merging related events..."); + hists__collapse_resort(hists, &prog); + ui_progress__finish(); + /* Don't sort callchain */ evsel__reset_sample_bit(pos, CALLCHAIN); - evsel__output_resort(pos, NULL); + + ui_progress__init(&prog, nr_samples, + "Sorting events for output..."); + evsel__output_resort(pos, &prog); + ui_progress__finish(); /* * An event group needs to display other events too. -- cgit v1.2.3-59-g8ed1b From 9b561be15febda6f9b314c9eab51e157f8f34dea Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 10 Apr 2024 20:32:52 -0700 Subject: perf annotate-data: Add hist_entry__annotate_data_tty() And move the related code into util/annotate-data.c file. Reviewed-by: Ian Rogers Signed-off-by: Namhyung Kim Cc: Adrian Hunter Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20240411033256.2099646-4-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-annotate.c | 106 +------------------------------------ tools/perf/util/annotate-data.c | 112 ++++++++++++++++++++++++++++++++++++++++ tools/perf/util/annotate-data.h | 9 ++++ 3 files changed, 122 insertions(+), 105 deletions(-) diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 332e1ddcacbd..0812664faa54 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -329,108 +329,6 @@ static int hist_entry__tty_annotate(struct hist_entry *he, return symbol__tty_annotate2(&he->ms, evsel); } -static void print_annotated_data_header(struct hist_entry *he, struct evsel *evsel) -{ - struct dso *dso = map__dso(he->ms.map); - int nr_members = 1; - int nr_samples = he->stat.nr_events; - int width = 7; - const char *val_hdr = "Percent"; - - if (evsel__is_group_event(evsel)) { - struct hist_entry *pair; - - list_for_each_entry(pair, &he->pairs.head, pairs.node) - nr_samples += pair->stat.nr_events; - } - - printf("Annotate type: '%s' in %s (%d samples):\n", - he->mem_type->self.type_name, dso->name, nr_samples); - - if (evsel__is_group_event(evsel)) { - struct evsel *pos; - int i = 0; - - for_each_group_evsel(pos, evsel) - printf(" event[%d] = %s\n", i++, pos->name); - - nr_members = evsel->core.nr_members; - } - - if (symbol_conf.show_total_period) { - width = 11; - val_hdr = "Period"; - } else if (symbol_conf.show_nr_samples) { - width = 7; - val_hdr = "Samples"; - } - - printf("============================================================================\n"); - printf("%*s %10s %10s %s\n", (width + 1) * nr_members, val_hdr, - "offset", "size", "field"); -} - -static void print_annotated_data_value(struct type_hist *h, u64 period, int nr_samples) -{ - double percent = h->period ? (100.0 * period / h->period) : 0; - const char *color = get_percent_color(percent); - - if (symbol_conf.show_total_period) - color_fprintf(stdout, color, " %11" PRIu64, period); - else if (symbol_conf.show_nr_samples) - color_fprintf(stdout, color, " %7d", nr_samples); - else - color_fprintf(stdout, color, " %7.2f", percent); -} - -static void print_annotated_data_type(struct annotated_data_type *mem_type, - struct annotated_member *member, - struct evsel *evsel, int indent) -{ - struct annotated_member *child; - struct type_hist *h = mem_type->histograms[evsel->core.idx]; - int i, nr_events = 1, samples = 0; - u64 period = 0; - int width = symbol_conf.show_total_period ? 11 : 7; - - for (i = 0; i < member->size; i++) { - samples += h->addr[member->offset + i].nr_samples; - period += h->addr[member->offset + i].period; - } - print_annotated_data_value(h, period, samples); - - if (evsel__is_group_event(evsel)) { - struct evsel *pos; - - for_each_group_member(pos, evsel) { - h = mem_type->histograms[pos->core.idx]; - - samples = 0; - period = 0; - for (i = 0; i < member->size; i++) { - samples += h->addr[member->offset + i].nr_samples; - period += h->addr[member->offset + i].period; - } - print_annotated_data_value(h, period, samples); - } - nr_events = evsel->core.nr_members; - } - - printf(" %10d %10d %*s%s\t%s", - member->offset, member->size, indent, "", member->type_name, - member->var_name ?: ""); - - if (!list_empty(&member->children)) - printf(" {\n"); - - list_for_each_entry(child, &member->children, node) - print_annotated_data_type(mem_type, child, evsel, indent + 4); - - if (!list_empty(&member->children)) - printf("%*s}", (width + 1) * nr_events + 24 + indent, ""); - printf(";\n"); -} - static void print_annotate_data_stat(struct annotated_data_stat *s) { #define PRINT_STAT(fld) if (s->fld) printf("%10d : %s\n", s->fld, #fld) @@ -571,9 +469,7 @@ find_next: goto find_next; } - print_annotated_data_header(he, evsel); - print_annotated_data_type(he->mem_type, &he->mem_type->self, evsel, 0); - printf("\n"); + hist_entry__annotate_data_tty(he, evsel); goto find_next; } diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c index b69a1cd1577a..b150137a92dc 100644 --- a/tools/perf/util/annotate-data.c +++ b/tools/perf/util/annotate-data.c @@ -19,6 +19,7 @@ #include "evlist.h" #include "map.h" #include "map_symbol.h" +#include "sort.h" #include "strbuf.h" #include "symbol.h" #include "symbol_conf.h" @@ -1710,3 +1711,114 @@ int annotated_data_type__update_samples(struct annotated_data_type *adt, h->addr[offset].period += period; return 0; } + +static void print_annotated_data_header(struct hist_entry *he, struct evsel *evsel) +{ + struct dso *dso = map__dso(he->ms.map); + int nr_members = 1; + int nr_samples = he->stat.nr_events; + int width = 7; + const char *val_hdr = "Percent"; + + if (evsel__is_group_event(evsel)) { + struct hist_entry *pair; + + list_for_each_entry(pair, &he->pairs.head, pairs.node) + nr_samples += pair->stat.nr_events; + } + + printf("Annotate type: '%s' in %s (%d samples):\n", + he->mem_type->self.type_name, dso->name, nr_samples); + + if (evsel__is_group_event(evsel)) { + struct evsel *pos; + int i = 0; + + for_each_group_evsel(pos, evsel) + printf(" event[%d] = %s\n", i++, pos->name); + + nr_members = evsel->core.nr_members; + } + + if (symbol_conf.show_total_period) { + width = 11; + val_hdr = "Period"; + } else if (symbol_conf.show_nr_samples) { + width = 7; + val_hdr = "Samples"; + } + + printf("============================================================================\n"); + printf("%*s %10s %10s %s\n", (width + 1) * nr_members, val_hdr, + "offset", "size", "field"); +} + +static void print_annotated_data_value(struct type_hist *h, u64 period, int nr_samples) +{ + double percent = h->period ? (100.0 * period / h->period) : 0; + const char *color = get_percent_color(percent); + + if (symbol_conf.show_total_period) + color_fprintf(stdout, color, " %11" PRIu64, period); + else if (symbol_conf.show_nr_samples) + color_fprintf(stdout, color, " %7d", nr_samples); + else + color_fprintf(stdout, color, " %7.2f", percent); +} + +static void print_annotated_data_type(struct annotated_data_type *mem_type, + struct annotated_member *member, + struct evsel *evsel, int indent) +{ + struct annotated_member *child; + struct type_hist *h = mem_type->histograms[evsel->core.idx]; + int i, nr_events = 1, samples = 0; + u64 period = 0; + int width = symbol_conf.show_total_period ? 11 : 7; + + for (i = 0; i < member->size; i++) { + samples += h->addr[member->offset + i].nr_samples; + period += h->addr[member->offset + i].period; + } + print_annotated_data_value(h, period, samples); + + if (evsel__is_group_event(evsel)) { + struct evsel *pos; + + for_each_group_member(pos, evsel) { + h = mem_type->histograms[pos->core.idx]; + + samples = 0; + period = 0; + for (i = 0; i < member->size; i++) { + samples += h->addr[member->offset + i].nr_samples; + period += h->addr[member->offset + i].period; + } + print_annotated_data_value(h, period, samples); + } + nr_events = evsel->core.nr_members; + } + + printf(" %10d %10d %*s%s\t%s", + member->offset, member->size, indent, "", member->type_name, + member->var_name ?: ""); + + if (!list_empty(&member->children)) + printf(" {\n"); + + list_for_each_entry(child, &member->children, node) + print_annotated_data_type(mem_type, child, evsel, indent + 4); + + if (!list_empty(&member->children)) + printf("%*s}", (width + 1) * nr_events + 24 + indent, ""); + printf(";\n"); +} + +int hist_entry__annotate_data_tty(struct hist_entry *he, struct evsel *evsel) +{ + print_annotated_data_header(he, evsel); + print_annotated_data_type(he->mem_type, &he->mem_type->self, evsel, 0); + printf("\n"); + + return 0; +} diff --git a/tools/perf/util/annotate-data.h b/tools/perf/util/annotate-data.h index fe1e53d6e8c7..01489db267d4 100644 --- a/tools/perf/util/annotate-data.h +++ b/tools/perf/util/annotate-data.h @@ -10,6 +10,7 @@ struct annotated_op_loc; struct debuginfo; struct evsel; +struct hist_entry; struct map_symbol; struct thread; @@ -156,6 +157,8 @@ void annotated_data_type__tree_delete(struct rb_root *root); /* Release all global variable information in the tree */ void global_var_type__tree_delete(struct rb_root *root); +int hist_entry__annotate_data_tty(struct hist_entry *he, struct evsel *evsel); + #else /* HAVE_DWARF_SUPPORT */ static inline struct annotated_data_type * @@ -182,6 +185,12 @@ static inline void global_var_type__tree_delete(struct rb_root *root __maybe_unu { } +static inline int hist_entry__annotate_data_tty(struct hist_entry *he __maybe_unused, + struct evsel *evsel __maybe_unused) +{ + return -1; +} + #endif /* HAVE_DWARF_SUPPORT */ #endif /* _PERF_ANNOTATE_DATA_H */ -- cgit v1.2.3-59-g8ed1b From d001c7a7f473674353311a79cf140d054b26afcd Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 10 Apr 2024 20:32:53 -0700 Subject: perf annotate-data: Add hist_entry__annotate_data_tui() Support data type profiling output on TUI. Testing from Arnaldo: First make sure that the debug information for your workload binaries in embedded in them by building it with '-g' or install the debuginfo packages, since our workload is 'find': root@number:~# type find find is hashed (/usr/bin/find) root@number:~# rpm -qf /usr/bin/find findutils-4.9.0-5.fc39.x86_64 root@number:~# dnf debuginfo-install findutils root@number:~# Then collect some data: root@number:~# echo 1 > /proc/sys/vm/drop_caches root@number:~# perf mem record find / > /dev/null [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.331 MB perf.data (3982 samples) ] root@number:~# Finally do data-type annotation with the following command, that will default, as 'perf report' to the --tui mode, with lines colored to highlight the hotspots, etc. root@number:~# perf annotate --data-type Annotate type: 'struct predicate' (58 samples) Percent Offset Size Field 100.00 0 312 struct predicate { 0.00 0 8 PRED_FUNC pred_func; 0.00 8 8 char* p_name; 0.00 16 4 enum predicate_type p_type; 0.00 20 4 enum predicate_precedence p_prec; 0.00 24 1 _Bool side_effects; 0.00 25 1 _Bool no_default_print; 0.00 26 1 _Bool need_stat; 0.00 27 1 _Bool need_type; 0.00 28 1 _Bool need_inum; 0.00 32 4 enum EvaluationCost p_cost; 0.00 36 4 float est_success_rate; 0.00 40 1 _Bool literal_control_chars; 0.00 41 1 _Bool artificial; 0.00 48 8 char* arg_text; Reviewed-by: Ian Rogers Signed-off-by: Namhyung Kim Tested-by: Arnaldo Carvalho de Melo Cc: Adrian Hunter Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20240411033256.2099646-5-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-annotate.c | 30 +++- tools/perf/ui/browsers/Build | 1 + tools/perf/ui/browsers/annotate-data.c | 282 +++++++++++++++++++++++++++++++++ tools/perf/util/annotate-data.c | 3 +- tools/perf/util/annotate-data.h | 13 ++ 5 files changed, 324 insertions(+), 5 deletions(-) create mode 100644 tools/perf/ui/browsers/annotate-data.c diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 0812664faa54..6f7104f06c42 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -469,8 +469,32 @@ find_next: goto find_next; } - hist_entry__annotate_data_tty(he, evsel); - goto find_next; + if (use_browser == 1) + key = hist_entry__annotate_data_tui(he, evsel, NULL); + else + key = hist_entry__annotate_data_tty(he, evsel); + + switch (key) { + case -1: + if (!ann->skip_missing) + return; + /* fall through */ + case K_RIGHT: + case '>': + next = rb_next(nd); + break; + case K_LEFT: + case '<': + next = rb_prev(nd); + break; + default: + return; + } + + if (next != NULL) + nd = next; + + continue; } if (use_browser == 2) { @@ -873,9 +897,7 @@ int cmd_annotate(int argc, const char **argv) use_browser = 2; #endif - /* FIXME: only support stdio for now */ if (annotate.data_type) { - use_browser = 0; annotate_opts.annotate_src = false; symbol_conf.annotate_data_member = true; symbol_conf.annotate_data_sample = true; diff --git a/tools/perf/ui/browsers/Build b/tools/perf/ui/browsers/Build index 7a1d5ddaf688..2608b5da3167 100644 --- a/tools/perf/ui/browsers/Build +++ b/tools/perf/ui/browsers/Build @@ -1,4 +1,5 @@ perf-y += annotate.o +perf-y += annotate-data.o perf-y += hists.o perf-y += map.o perf-y += scripts.o diff --git a/tools/perf/ui/browsers/annotate-data.c b/tools/perf/ui/browsers/annotate-data.c new file mode 100644 index 000000000000..fefacaaf16db --- /dev/null +++ b/tools/perf/ui/browsers/annotate-data.c @@ -0,0 +1,282 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include + +#include "ui/browser.h" +#include "ui/helpline.h" +#include "ui/keysyms.h" +#include "ui/ui.h" +#include "util/annotate.h" +#include "util/annotate-data.h" +#include "util/evsel.h" +#include "util/sort.h" + +struct annotated_data_browser { + struct ui_browser b; + struct list_head entries; +}; + +struct browser_entry { + struct list_head node; + struct annotated_member *data; + struct type_hist_entry hists; + int indent; +}; + +static void update_hist_entry(struct type_hist_entry *dst, + struct type_hist_entry *src) +{ + dst->nr_samples += src->nr_samples; + dst->period += src->period; +} + +static int get_member_overhead(struct annotated_data_type *adt, + struct browser_entry *entry, + struct evsel *evsel) +{ + struct annotated_member *member = entry->data; + int i; + + for (i = 0; i < member->size; i++) { + struct type_hist *h; + int offset = member->offset + i; + + h = adt->histograms[evsel->core.idx]; + update_hist_entry(&entry->hists, &h->addr[offset]); + } + return 0; +} + +static int add_child_entries(struct annotated_data_browser *browser, + struct annotated_data_type *adt, + struct annotated_member *member, + struct evsel *evsel, int indent) +{ + struct annotated_member *pos; + struct browser_entry *entry; + int nr_entries = 0; + + entry = zalloc(sizeof(*entry)); + if (entry == NULL) + return -1; + + entry->data = member; + entry->indent = indent; + if (get_member_overhead(adt, entry, evsel) < 0) { + free(entry); + return -1; + } + + list_add_tail(&entry->node, &browser->entries); + nr_entries++; + + list_for_each_entry(pos, &member->children, node) { + int nr = add_child_entries(browser, adt, pos, evsel, indent + 1); + + if (nr < 0) + return nr; + + nr_entries += nr; + } + + /* add an entry for the closing bracket ("}") */ + if (!list_empty(&member->children)) { + entry = zalloc(sizeof(*entry)); + if (entry == NULL) + return -1; + + entry->indent = indent; + list_add_tail(&entry->node, &browser->entries); + nr_entries++; + } + + return nr_entries; +} + +static int annotated_data_browser__collect_entries(struct annotated_data_browser *browser) +{ + struct hist_entry *he = browser->b.priv; + struct annotated_data_type *adt = he->mem_type; + struct evsel *evsel = hists_to_evsel(he->hists); + + INIT_LIST_HEAD(&browser->entries); + browser->b.entries = &browser->entries; + browser->b.nr_entries = add_child_entries(browser, adt, &adt->self, + evsel, /*indent=*/0); + return 0; +} + +static void annotated_data_browser__delete_entries(struct annotated_data_browser *browser) +{ + struct browser_entry *pos, *tmp; + + list_for_each_entry_safe(pos, tmp, &browser->entries, node) { + list_del_init(&pos->node); + free(pos); + } +} + +static unsigned int browser__refresh(struct ui_browser *uib) +{ + return ui_browser__list_head_refresh(uib); +} + +static int browser__show(struct ui_browser *uib) +{ + struct hist_entry *he = uib->priv; + struct annotated_data_type *adt = he->mem_type; + const char *help = "Press 'h' for help on key bindings"; + char title[256]; + + snprintf(title, sizeof(title), "Annotate type: '%s' (%d samples)", + adt->self.type_name, he->stat.nr_events); + + if (ui_browser__show(uib, title, help) < 0) + return -1; + + /* second line header */ + ui_browser__gotorc_title(uib, 0, 0); + ui_browser__set_color(uib, HE_COLORSET_ROOT); + + if (symbol_conf.show_total_period) + strcpy(title, "Period"); + else if (symbol_conf.show_nr_samples) + strcpy(title, "Samples"); + else + strcpy(title, "Percent"); + + ui_browser__printf(uib, " %10s %10s %10s %s", + title, "Offset", "Size", "Field"); + ui_browser__write_nstring(uib, "", uib->width); + return 0; +} + +static void browser__write_overhead(struct ui_browser *uib, + struct type_hist *total, + struct type_hist_entry *hist, int row) +{ + u64 period = hist->period; + double percent = total->period ? (100.0 * period / total->period) : 0; + bool current = ui_browser__is_current_entry(uib, row); + int nr_samples = 0; + + ui_browser__set_percent_color(uib, percent, current); + + if (symbol_conf.show_total_period) + ui_browser__printf(uib, " %10" PRIu64, period); + else if (symbol_conf.show_nr_samples) + ui_browser__printf(uib, " %10d", nr_samples); + else + ui_browser__printf(uib, " %10.2f", percent); + + ui_browser__set_percent_color(uib, 0, current); +} + +static void browser__write(struct ui_browser *uib, void *entry, int row) +{ + struct browser_entry *be = entry; + struct annotated_member *member = be->data; + struct hist_entry *he = uib->priv; + struct annotated_data_type *adt = he->mem_type; + struct evsel *evsel = hists_to_evsel(he->hists); + + if (member == NULL) { + bool current = ui_browser__is_current_entry(uib, row); + + /* print the closing bracket */ + ui_browser__set_percent_color(uib, 0, current); + ui_browser__write_nstring(uib, "", 11); + ui_browser__printf(uib, " %10s %10s %*s};", + "", "", be->indent * 4, ""); + ui_browser__write_nstring(uib, "", uib->width); + return; + } + + /* print the number */ + browser__write_overhead(uib, adt->histograms[evsel->core.idx], + &be->hists, row); + + /* print type info */ + if (be->indent == 0 && !member->var_name) { + ui_browser__printf(uib, " %10d %10d %s%s", + member->offset, member->size, + member->type_name, + list_empty(&member->children) ? ";" : " {"); + } else { + ui_browser__printf(uib, " %10d %10d %*s%s\t%s%s", + member->offset, member->size, + be->indent * 4, "", member->type_name, + member->var_name ?: "", + list_empty(&member->children) ? ";" : " {"); + } + /* fill the rest */ + ui_browser__write_nstring(uib, "", uib->width); +} + +static int annotated_data_browser__run(struct annotated_data_browser *browser, + struct evsel *evsel __maybe_unused, + struct hist_browser_timer *hbt) +{ + int delay_secs = hbt ? hbt->refresh : 0; + int key; + + if (browser__show(&browser->b) < 0) + return -1; + + while (1) { + key = ui_browser__run(&browser->b, delay_secs); + + switch (key) { + case K_TIMER: + if (hbt) + hbt->timer(hbt->arg); + continue; + case K_F1: + case 'h': + ui_browser__help_window(&browser->b, + "UP/DOWN/PGUP\n" + "PGDN/SPACE Navigate\n" + " Move to prev/next symbol\n" + "q/ESC/CTRL+C Exit\n\n"); + continue; + case K_LEFT: + case '<': + case '>': + case K_ESC: + case 'q': + case CTRL('c'): + goto out; + default: + continue; + } + } +out: + ui_browser__hide(&browser->b); + return key; +} + +int hist_entry__annotate_data_tui(struct hist_entry *he, struct evsel *evsel, + struct hist_browser_timer *hbt) +{ + struct annotated_data_browser browser = { + .b = { + .refresh = browser__refresh, + .seek = ui_browser__list_head_seek, + .write = browser__write, + .priv = he, + .extra_title_lines = 1, + }, + }; + int ret; + + ui_helpline__push("Press ESC to exit"); + + ret = annotated_data_browser__collect_entries(&browser); + if (ret == 0) + ret = annotated_data_browser__run(&browser, evsel, hbt); + + annotated_data_browser__delete_entries(&browser); + + return ret; +} diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c index b150137a92dc..1cd857400038 100644 --- a/tools/perf/util/annotate-data.c +++ b/tools/perf/util/annotate-data.c @@ -1820,5 +1820,6 @@ int hist_entry__annotate_data_tty(struct hist_entry *he, struct evsel *evsel) print_annotated_data_type(he->mem_type, &he->mem_type->self, evsel, 0); printf("\n"); - return 0; + /* move to the next entry */ + return '>'; } diff --git a/tools/perf/util/annotate-data.h b/tools/perf/util/annotate-data.h index 01489db267d4..0a57d9f5ee78 100644 --- a/tools/perf/util/annotate-data.h +++ b/tools/perf/util/annotate-data.h @@ -10,6 +10,7 @@ struct annotated_op_loc; struct debuginfo; struct evsel; +struct hist_browser_timer; struct hist_entry; struct map_symbol; struct thread; @@ -193,4 +194,16 @@ static inline int hist_entry__annotate_data_tty(struct hist_entry *he __maybe_un #endif /* HAVE_DWARF_SUPPORT */ +#ifdef HAVE_SLANG_SUPPORT +int hist_entry__annotate_data_tui(struct hist_entry *he, struct evsel *evsel, + struct hist_browser_timer *hbt); +#else +static inline int hist_entry__annotate_data_tui(struct hist_entry *he __maybe_unused, + struct evsel *evsel __maybe_unused, + struct hist_browser_timer *hbt __maybe_unused) +{ + return -1; +} +#endif /* HAVE_SLANG_SUPPORT */ + #endif /* _PERF_ANNOTATE_DATA_H */ -- cgit v1.2.3-59-g8ed1b From 2b08f219d592d5b3d17db9a3850a9d793e6c9d83 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 10 Apr 2024 20:32:54 -0700 Subject: perf annotate-data: Support event group display in TUI Like in stdio, it should print all events in a group together. Committer notes: Collect it: root@number:~# perf record -a -e '{cpu_core/mem-loads,ldlat=30/P,cpu_core/mem-stores/P}' ^C[ perf record: Woken up 8 times to write data ] [ perf record: Captured and wrote 4.980 MB perf.data (55825 samples) ] root@number:~# Then do it in stdio: root@number:~# perf annotate --stdio --data-type Annotate type: 'union ' in /usr/lib64/libc.so.6 (1131 samples): event[0] = cpu_core/mem-loads,ldlat=30/P event[1] = cpu_core/mem-stores/P ============================================================================ Percent offset size field 100.00 100.00 0 40 union { 100.00 100.00 0 40 struct __pthread_mutex_s __data { 48.61 23.46 0 4 int __lock; 0.00 0.48 4 4 unsigned int __count; 6.38 41.32 8 4 int __owner; 8.74 34.02 12 4 unsigned int __nusers; 35.66 0.26 16 4 int __kind; 0.61 0.45 20 2 short int __spins; 0.00 0.00 22 2 short int __elision; 0.00 0.00 24 16 __pthread_list_t __list { 0.00 0.00 24 8 struct __pthread_internal_list* __prev; 0.00 0.00 32 8 struct __pthread_internal_list* __next; }; }; 0.00 0.00 0 0 char* __size; 48.61 23.94 0 8 long int __align; }; Now with TUI before this patch: root@number:~# perf annotate --tui --data-type Annotate type: 'union ' (790 samples) Percent Offset Size Field 100.00 0 40 union { 100.00 0 40 struct __pthread_mutex_s __data { 48.61 0 4 int __lock; 0.00 4 4 unsigned int __count; 6.38 8 4 int __owner; 8.74 12 4 unsigned int __nusers; 35.66 16 4 int __kind; 0.61 20 2 short int __spins; 0.00 22 2 short int __elision; 0.00 24 16 __pthread_list_t __list { 0.00 24 8 struct __pthread_internal_list* __prev; 0.00 32 8 struct __pthread_internal_list* __next; 0.00 0 0 char* __size; 48.61 0 8 long int __align; }; And now after this patch: Annotate type: 'union ' (790 samples) Percent Offset Size Field 100.00 100.00 0 40 union { 100.00 100.00 0 40 struct __pthread_mutex_s __data { 48.61 23.46 0 4 int __lock; 0.00 0.48 4 4 unsigned int __count; 6.38 41.32 8 4 int __owner; 8.74 34.02 12 4 unsigned int __nusers; 35.66 0.26 16 4 int __kind; 0.61 0.45 20 2 short int __spins; 0.00 0.00 22 2 short int __elision; 0.00 0.00 24 16 __pthread_list_t __list { 0.00 0.00 24 8 struct __pthread_internal_list* __prev; 0.00 0.00 32 8 struct __pthread_internal_list* __next; }; }; 0.00 0.00 0 0 char* __size; 48.61 23.94 0 8 long int __align; }; On a followup patch the --tui output should have this that is present in --stdio: And the --stdio has all the missing info in TUI: Annotate type: 'union ' in /usr/lib64/libc.so.6 (1131 samples): event[0] = cpu_core/mem-loads,ldlat=30/P event[1] = cpu_core/mem-stores/P Reviewed-by: Ian Rogers Signed-off-by: Namhyung Kim Tested-by: Arnaldo Carvalho de Melo Cc: Adrian Hunter Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20240411033256.2099646-6-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate-data.c | 50 +++++++++++++++++++++++++++------- 1 file changed, 40 insertions(+), 10 deletions(-) diff --git a/tools/perf/ui/browsers/annotate-data.c b/tools/perf/ui/browsers/annotate-data.c index fefacaaf16db..a4a0f042f201 100644 --- a/tools/perf/ui/browsers/annotate-data.c +++ b/tools/perf/ui/browsers/annotate-data.c @@ -10,20 +10,27 @@ #include "util/annotate.h" #include "util/annotate-data.h" #include "util/evsel.h" +#include "util/evlist.h" #include "util/sort.h" struct annotated_data_browser { struct ui_browser b; struct list_head entries; + int nr_events; }; struct browser_entry { struct list_head node; struct annotated_member *data; - struct type_hist_entry hists; + struct type_hist_entry *hists; int indent; }; +static struct annotated_data_browser *get_browser(struct ui_browser *uib) +{ + return container_of(uib, struct annotated_data_browser, b); +} + static void update_hist_entry(struct type_hist_entry *dst, struct type_hist_entry *src) { @@ -33,17 +40,21 @@ static void update_hist_entry(struct type_hist_entry *dst, static int get_member_overhead(struct annotated_data_type *adt, struct browser_entry *entry, - struct evsel *evsel) + struct evsel *leader) { struct annotated_member *member = entry->data; - int i; + int i, k; for (i = 0; i < member->size; i++) { struct type_hist *h; + struct evsel *evsel; int offset = member->offset + i; - h = adt->histograms[evsel->core.idx]; - update_hist_entry(&entry->hists, &h->addr[offset]); + for_each_group_evsel(evsel, leader) { + h = adt->histograms[evsel->core.idx]; + k = evsel__group_idx(evsel); + update_hist_entry(&entry->hists[k], &h->addr[offset]); + } } return 0; } @@ -61,6 +72,12 @@ static int add_child_entries(struct annotated_data_browser *browser, if (entry == NULL) return -1; + entry->hists = calloc(browser->nr_events, sizeof(*entry->hists)); + if (entry->hists == NULL) { + free(entry); + return -1; + } + entry->data = member; entry->indent = indent; if (get_member_overhead(adt, entry, evsel) < 0) { @@ -113,6 +130,7 @@ static void annotated_data_browser__delete_entries(struct annotated_data_browser list_for_each_entry_safe(pos, tmp, &browser->entries, node) { list_del_init(&pos->node); + free(pos->hists); free(pos); } } @@ -126,6 +144,7 @@ static int browser__show(struct ui_browser *uib) { struct hist_entry *he = uib->priv; struct annotated_data_type *adt = he->mem_type; + struct annotated_data_browser *browser = get_browser(uib); const char *help = "Press 'h' for help on key bindings"; char title[256]; @@ -146,7 +165,8 @@ static int browser__show(struct ui_browser *uib) else strcpy(title, "Percent"); - ui_browser__printf(uib, " %10s %10s %10s %s", + ui_browser__printf(uib, "%*s %10s %10s %10s %s", + 11 * (browser->nr_events - 1), "", title, "Offset", "Size", "Field"); ui_browser__write_nstring(uib, "", uib->width); return 0; @@ -175,18 +195,20 @@ static void browser__write_overhead(struct ui_browser *uib, static void browser__write(struct ui_browser *uib, void *entry, int row) { + struct annotated_data_browser *browser = get_browser(uib); struct browser_entry *be = entry; struct annotated_member *member = be->data; struct hist_entry *he = uib->priv; struct annotated_data_type *adt = he->mem_type; - struct evsel *evsel = hists_to_evsel(he->hists); + struct evsel *leader = hists_to_evsel(he->hists); + struct evsel *evsel; if (member == NULL) { bool current = ui_browser__is_current_entry(uib, row); /* print the closing bracket */ ui_browser__set_percent_color(uib, 0, current); - ui_browser__write_nstring(uib, "", 11); + ui_browser__write_nstring(uib, "", 11 * browser->nr_events); ui_browser__printf(uib, " %10s %10s %*s};", "", "", be->indent * 4, ""); ui_browser__write_nstring(uib, "", uib->width); @@ -194,8 +216,12 @@ static void browser__write(struct ui_browser *uib, void *entry, int row) } /* print the number */ - browser__write_overhead(uib, adt->histograms[evsel->core.idx], - &be->hists, row); + for_each_group_evsel(evsel, leader) { + struct type_hist *h = adt->histograms[evsel->core.idx]; + int idx = evsel__group_idx(evsel); + + browser__write_overhead(uib, h, &be->hists[idx], row); + } /* print type info */ if (be->indent == 0 && !member->var_name) { @@ -267,11 +293,15 @@ int hist_entry__annotate_data_tui(struct hist_entry *he, struct evsel *evsel, .priv = he, .extra_title_lines = 1, }, + .nr_events = 1, }; int ret; ui_helpline__push("Press ESC to exit"); + if (evsel__is_group_event(evsel)) + browser.nr_events = evsel->core.nr_members; + ret = annotated_data_browser__collect_entries(&browser); if (ret == 0) ret = annotated_data_browser__run(&browser, evsel, hbt); -- cgit v1.2.3-59-g8ed1b From 0bfbe661a21f7c77a22eb978e0de3b672041e502 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 10 Apr 2024 20:32:55 -0700 Subject: perf report: Add a menu item to annotate data type in TUI When the hist entry has the type info, it should be able to display the annotation browser for the type like in `perf annotate --data-type`. Reviewed-by: Ian Rogers Signed-off-by: Namhyung Kim Cc: Adrian Hunter Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20240411033256.2099646-7-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-report.c | 5 +++++ tools/perf/ui/browsers/hists.c | 31 +++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index dcd93ee5fc24..aaa6427a1224 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -1694,6 +1694,11 @@ repeat: else use_browser = 0; + if (report.data_type && use_browser == 1) { + symbol_conf.annotate_data_member = true; + symbol_conf.annotate_data_sample = true; + } + if (sort_order && strstr(sort_order, "ipc")) { parse_options_usage(report_usage, options, "s", 1); goto error; diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index 0c02b3a8e121..71b32591d61a 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -38,6 +38,7 @@ #include "../ui.h" #include "map.h" #include "annotate.h" +#include "annotate-data.h" #include "srcline.h" #include "string2.h" #include "units.h" @@ -2505,6 +2506,32 @@ add_annotate_opt(struct hist_browser *browser __maybe_unused, return 1; } +static int +do_annotate_type(struct hist_browser *browser, struct popup_action *act) +{ + struct hist_entry *he = browser->he_selection; + + hist_entry__annotate_data_tui(he, act->evsel, browser->hbt); + ui_browser__handle_resize(&browser->b); + return 0; +} + +static int +add_annotate_type_opt(struct hist_browser *browser, + struct popup_action *act, char **optstr, + struct hist_entry *he) +{ + if (he == NULL || he->mem_type == NULL || he->mem_type->histograms == NULL) + return 0; + + if (asprintf(optstr, "Annotate type %s", he->mem_type->self.type_name) < 0) + return 0; + + act->evsel = hists_to_evsel(browser->hists); + act->fn = do_annotate_type; + return 1; +} + static int do_zoom_thread(struct hist_browser *browser, struct popup_action *act) { @@ -3307,6 +3334,10 @@ do_hotkey: // key came straight from options ui__popup_menu() browser->he_selection->ip); } skip_annotation: + nr_options += add_annotate_type_opt(browser, + &actions[nr_options], + &options[nr_options], + browser->he_selection); nr_options += add_thread_opt(browser, &actions[nr_options], &options[nr_options], thread); nr_options += add_dso_opt(browser, &actions[nr_options], -- cgit v1.2.3-59-g8ed1b From 6cdd977ec24e1538b35a08bde823a74b69e829f2 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 10 Apr 2024 20:32:56 -0700 Subject: perf report: Do not collect sample histogram unnecessarily The data type profiling alone doesn't need the sample histogram for functions. It only needs the histogram for the types. Let's remove the condition in the report_callback to check if data type profiling is selected and make sure the annotation has the 'struct annotated_source' instantiated before calling symbol__disassemble(). Reviewed-by: Ian Rogers Signed-off-by: Namhyung Kim Cc: Adrian Hunter Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20240411033256.2099646-8-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-report.c | 2 +- tools/perf/util/annotate.c | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index aaa6427a1224..dafba6e030ef 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -172,7 +172,7 @@ static int hist_iter__report_callback(struct hist_entry_iter *iter, struct mem_info *mi; struct branch_info *bi; - if (!ui__has_annotation() && !rep->symbol_ipc && !rep->data_type) + if (!ui__has_annotation() && !rep->symbol_ipc) return 0; if (sort__mode == SORT_MODE__BRANCH) { diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index ec79c120a7d2..7595c8fbc2c5 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -908,6 +908,13 @@ int symbol__annotate(struct map_symbol *ms, struct evsel *evsel, args.arch = arch; args.ms = *ms; + + if (notes->src == NULL) { + notes->src = annotated_source__new(); + if (notes->src == NULL) + return -1; + } + if (annotate_opts.full_addr) notes->src->start = map__objdump_2mem(ms->map, ms->sym->start); else -- cgit v1.2.3-59-g8ed1b From 873a83731f1cc85c8427fdc7a9e24fb270faca44 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 10 Apr 2024 11:51:17 -0700 Subject: perf annotate: Skip DSOs not found In some data file, I see the following messages repeated. It seems it doesn't have DSOs in the system and the dso->binary_type is set to DSO_BINARY_TYPE__NOT_FOUND. Let's skip them to avoid the followings. No output from objdump --start-address=0x0000000000000000 --stop-address=0x00000000000000d4 -d --no-show-raw-insn -C "$1" Error running objdump --start-address=0x0000000000000000 --stop-address=0x0000000000000631 -d --no-show-raw-insn -C "$1" ... Closes: https://lore.kernel.org/linux-perf-users/15e1a2847b8cebab4de57fc68e033086aa6980ce.camel@yandex.ru/ Reported-by: Konstantin Kharlamov Reviewed-by: Ian Rogers Signed-off-by: Namhyung Kim Tested-by: Konstantin Kharlamov Cc: Adrian Hunter Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20240410185117.1987239-1-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/disasm.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/perf/util/disasm.c b/tools/perf/util/disasm.c index a1219eb930aa..92937809be85 100644 --- a/tools/perf/util/disasm.c +++ b/tools/perf/util/disasm.c @@ -1669,6 +1669,8 @@ int symbol__disassemble(struct symbol *sym, struct annotate_args *args) return symbol__disassemble_bpf(sym, args); } else if (dso->binary_type == DSO_BINARY_TYPE__BPF_IMAGE) { return symbol__disassemble_bpf_image(sym, args); + } else if (dso->binary_type == DSO_BINARY_TYPE__NOT_FOUND) { + return -1; } else if (dso__is_kcore(dso)) { kce.kcore_filename = symfs_filename; kce.addr = map__rip_2objdump(map, sym->start); -- cgit v1.2.3-59-g8ed1b From 792bc998baf9ae17297b1f93b1edc3ca34a0b7e2 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Thu, 11 Apr 2024 10:54:47 +0300 Subject: perf record: Fix debug message placement for test consumption evlist__config() might mess up the debug output consumed by test "Test per-thread recording" in "Miscellaneous Intel PT testing". Move it out from between the debug prints: "perf record opening and mmapping events" and "perf record done opening and mmapping events" Fixes: da4062021e0e6da5 ("perf tools: Add debug messages and comments for testing") Closes: https://lore.kernel.org/linux-perf-users/ZhVfc5jYLarnGzKa@x1/ Reported-by: Arnaldo Carvalho de Melo Signed-off-by: Adrian Hunter Tested-by: Arnaldo Carvalho de Melo Cc: Ian Rogers Cc: Jiri Olsa Cc: Namhyung Kim Link: https://lore.kernel.org/r/20240411075447.17306-1-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-record.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 40d2c1c48666..6aeae398ec28 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -1355,8 +1355,6 @@ static int record__open(struct record *rec) struct record_opts *opts = &rec->opts; int rc = 0; - evlist__config(evlist, opts, &callchain_param); - evlist__for_each_entry(evlist, pos) { try_again: if (evsel__open(pos, pos->core.cpus, pos->core.threads) < 0) { @@ -2483,6 +2481,8 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) evlist__uniquify_name(rec->evlist); + evlist__config(rec->evlist, opts, &callchain_param); + /* Debug message used by test scripts */ pr_debug3("perf record opening and mmapping events\n"); if (record__open(rec) != 0) { -- cgit v1.2.3-59-g8ed1b From 83acca9f90c700bafd81229f2c2d5debcf6b27bc Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Tue, 9 Apr 2024 23:42:03 -0700 Subject: perf dsos: Attempt to better abstract DSOs internals Move functions from machine and build-id to dsos. Pass 'struct dsos' rather than internal state. Rename some functions to better represent which data structure they operate on. Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andi Kleen Cc: Anne Macedo Cc: Athira Rajeev Cc: Ben Gainey Cc: Changbin Du Cc: Chengen Du Cc: Colin Ian King Cc: Ilkka Koskinen Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: K Prateek Nayak Cc: Kan Liang Cc: Leo Yan Cc: Li Dong Cc: Mark Rutland Cc: Markus Elfring Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Paran Lee Cc: Peter Zijlstra Cc: Ravi Bangoria Cc: Song Liu Cc: Sun Haiyong Cc: Thomas Richter Cc: Yang Jihong Cc: Yanteng Si Cc: Yicong Yang Cc: zhaimingbing Link: https://lore.kernel.org/r/20240410064214.2755936-2-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-inject.c | 2 +- tools/perf/builtin-record.c | 2 +- tools/perf/util/build-id.c | 38 +---------------------------------- tools/perf/util/build-id.h | 2 -- tools/perf/util/dso.h | 6 ------ tools/perf/util/dsos.c | 49 ++++++++++++++++++++++++++++++++++++++++++--- tools/perf/util/dsos.h | 19 ++++++++++++++---- tools/perf/util/machine.c | 40 ++++++++---------------------------- tools/perf/util/machine.h | 2 ++ tools/perf/util/session.c | 21 +++++++++++++++++++ tools/perf/util/session.h | 2 ++ 11 files changed, 97 insertions(+), 86 deletions(-) diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c index eb3ef5c24b66..ef73317e6ae7 100644 --- a/tools/perf/builtin-inject.c +++ b/tools/perf/builtin-inject.c @@ -2122,7 +2122,7 @@ static int __cmd_inject(struct perf_inject *inject) */ if (perf_header__has_feat(&session->header, HEADER_BUILD_ID) && inject->have_auxtrace && !inject->itrace_synth_opts.set) - dsos__hit_all(session); + perf_session__dsos_hit_all(session); /* * The AUX areas have been removed and replaced with * synthesized hardware events, so clear the feature flag. diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 6aeae398ec28..2ff718d3e202 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -1788,7 +1788,7 @@ record__finish_output(struct record *rec) process_buildids(rec); if (rec->buildid_all) - dsos__hit_all(rec->session); + perf_session__dsos_hit_all(rec->session); } perf_session__write_header(rec->session, rec->evlist, fd, true); diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c index 03c64b85383b..a617b1917e6b 100644 --- a/tools/perf/util/build-id.c +++ b/tools/perf/util/build-id.c @@ -390,42 +390,6 @@ int perf_session__write_buildid_table(struct perf_session *session, return err; } -static int __dsos__hit_all(struct list_head *head) -{ - struct dso *pos; - - list_for_each_entry(pos, head, node) - pos->hit = true; - - return 0; -} - -static int machine__hit_all_dsos(struct machine *machine) -{ - return __dsos__hit_all(&machine->dsos.head); -} - -int dsos__hit_all(struct perf_session *session) -{ - struct rb_node *nd; - int err; - - err = machine__hit_all_dsos(&session->machines.host); - if (err) - return err; - - for (nd = rb_first_cached(&session->machines.guests); nd; - nd = rb_next(nd)) { - struct machine *pos = rb_entry(nd, struct machine, rb_node); - - err = machine__hit_all_dsos(pos); - if (err) - return err; - } - - return 0; -} - void disable_buildid_cache(void) { no_buildid_cache = true; @@ -992,7 +956,7 @@ int perf_session__cache_build_ids(struct perf_session *session) static bool machine__read_build_ids(struct machine *machine, bool with_hits) { - return __dsos__read_build_ids(&machine->dsos.head, with_hits); + return __dsos__read_build_ids(&machine->dsos, with_hits); } bool perf_session__read_build_ids(struct perf_session *session, bool with_hits) diff --git a/tools/perf/util/build-id.h b/tools/perf/util/build-id.h index 4e3a1169379b..3fa8bffb07ca 100644 --- a/tools/perf/util/build-id.h +++ b/tools/perf/util/build-id.h @@ -39,8 +39,6 @@ int build_id__mark_dso_hit(struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, struct evsel *evsel, struct machine *machine); -int dsos__hit_all(struct perf_session *session); - int perf_event__inject_buildid(struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, struct evsel *evsel, struct machine *machine); diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h index 17dab230a2ca..3d4faad8d5dc 100644 --- a/tools/perf/util/dso.h +++ b/tools/perf/util/dso.h @@ -233,12 +233,6 @@ struct dso { #define dso__for_each_symbol(dso, pos, n) \ symbols__for_each_entry(&(dso)->symbols, pos, n) -#define dsos__for_each_with_build_id(pos, head) \ - list_for_each_entry(pos, head, node) \ - if (!pos->has_build_id) \ - continue; \ - else - static inline void dso__set_loaded(struct dso *dso) { dso->loaded = true; diff --git a/tools/perf/util/dsos.c b/tools/perf/util/dsos.c index cf80aa42dd07..e65ef6762bed 100644 --- a/tools/perf/util/dsos.c +++ b/tools/perf/util/dsos.c @@ -12,6 +12,35 @@ #include // filename__read_build_id #include +void dsos__init(struct dsos *dsos) +{ + INIT_LIST_HEAD(&dsos->head); + dsos->root = RB_ROOT; + init_rwsem(&dsos->lock); +} + +static void dsos__purge(struct dsos *dsos) +{ + struct dso *pos, *n; + + down_write(&dsos->lock); + + list_for_each_entry_safe(pos, n, &dsos->head, node) { + RB_CLEAR_NODE(&pos->rb_node); + pos->root = NULL; + list_del_init(&pos->node); + dso__put(pos); + } + + up_write(&dsos->lock); +} + +void dsos__exit(struct dsos *dsos) +{ + dsos__purge(dsos); + exit_rwsem(&dsos->lock); +} + static int __dso_id__cmp(struct dso_id *a, struct dso_id *b) { if (a->maj > b->maj) return -1; @@ -73,8 +102,9 @@ int dso__cmp_id(struct dso *a, struct dso *b) return __dso_id__cmp(&a->id, &b->id); } -bool __dsos__read_build_ids(struct list_head *head, bool with_hits) +bool __dsos__read_build_ids(struct dsos *dsos, bool with_hits) { + struct list_head *head = &dsos->head; bool have_build_id = false; struct dso *pos; struct nscookie nsc; @@ -303,9 +333,10 @@ struct dso *dsos__findnew_id(struct dsos *dsos, const char *name, struct dso_id return dso; } -size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp, +size_t __dsos__fprintf_buildid(struct dsos *dsos, FILE *fp, bool (skip)(struct dso *dso, int parm), int parm) { + struct list_head *head = &dsos->head; struct dso *pos; size_t ret = 0; @@ -320,8 +351,9 @@ size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp, return ret; } -size_t __dsos__fprintf(struct list_head *head, FILE *fp) +size_t __dsos__fprintf(struct dsos *dsos, FILE *fp) { + struct list_head *head = &dsos->head; struct dso *pos; size_t ret = 0; @@ -331,3 +363,14 @@ size_t __dsos__fprintf(struct list_head *head, FILE *fp) return ret; } + +int __dsos__hit_all(struct dsos *dsos) +{ + struct list_head *head = &dsos->head; + struct dso *pos; + + list_for_each_entry(pos, head, node) + pos->hit = true; + + return 0; +} diff --git a/tools/perf/util/dsos.h b/tools/perf/util/dsos.h index 5dbec2bc6966..1c81ddf07f8f 100644 --- a/tools/perf/util/dsos.h +++ b/tools/perf/util/dsos.h @@ -21,6 +21,15 @@ struct dsos { struct rw_semaphore lock; }; +#define dsos__for_each_with_build_id(pos, head) \ + list_for_each_entry(pos, head, node) \ + if (!pos->has_build_id) \ + continue; \ + else + +void dsos__init(struct dsos *dsos); +void dsos__exit(struct dsos *dsos); + void __dsos__add(struct dsos *dsos, struct dso *dso); void dsos__add(struct dsos *dsos, struct dso *dso); struct dso *__dsos__addnew(struct dsos *dsos, const char *name); @@ -28,13 +37,15 @@ struct dso *__dsos__find(struct dsos *dsos, const char *name, bool cmp_short); struct dso *dsos__findnew_id(struct dsos *dsos, const char *name, struct dso_id *id); +bool __dsos__read_build_ids(struct dsos *dsos, bool with_hits); + struct dso *__dsos__findnew_link_by_longname_id(struct rb_root *root, struct dso *dso, const char *name, struct dso_id *id); -bool __dsos__read_build_ids(struct list_head *head, bool with_hits); - -size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp, +size_t __dsos__fprintf_buildid(struct dsos *dsos, FILE *fp, bool (skip)(struct dso *dso, int parm), int parm); -size_t __dsos__fprintf(struct list_head *head, FILE *fp); +size_t __dsos__fprintf(struct dsos *dsos, FILE *fp); + +int __dsos__hit_all(struct dsos *dsos); #endif /* __PERF_DSOS */ diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index a26c8bea58d0..848a94b8602b 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -48,13 +48,6 @@ static struct dso *machine__kernel_dso(struct machine *machine) return map__dso(machine->vmlinux_map); } -static void dsos__init(struct dsos *dsos) -{ - INIT_LIST_HEAD(&dsos->head); - dsos->root = RB_ROOT; - init_rwsem(&dsos->lock); -} - static int machine__set_mmap_name(struct machine *machine) { if (machine__is_host(machine)) @@ -165,28 +158,6 @@ struct machine *machine__new_kallsyms(void) return machine; } -static void dsos__purge(struct dsos *dsos) -{ - struct dso *pos, *n; - - down_write(&dsos->lock); - - list_for_each_entry_safe(pos, n, &dsos->head, node) { - RB_CLEAR_NODE(&pos->rb_node); - pos->root = NULL; - list_del_init(&pos->node); - dso__put(pos); - } - - up_write(&dsos->lock); -} - -static void dsos__exit(struct dsos *dsos) -{ - dsos__purge(dsos); - exit_rwsem(&dsos->lock); -} - void machine__delete_threads(struct machine *machine) { threads__remove_all_threads(&machine->threads); @@ -907,11 +878,11 @@ out: size_t machines__fprintf_dsos(struct machines *machines, FILE *fp) { struct rb_node *nd; - size_t ret = __dsos__fprintf(&machines->host.dsos.head, fp); + size_t ret = __dsos__fprintf(&machines->host.dsos, fp); for (nd = rb_first_cached(&machines->guests); nd; nd = rb_next(nd)) { struct machine *pos = rb_entry(nd, struct machine, rb_node); - ret += __dsos__fprintf(&pos->dsos.head, fp); + ret += __dsos__fprintf(&pos->dsos, fp); } return ret; @@ -920,7 +891,7 @@ size_t machines__fprintf_dsos(struct machines *machines, FILE *fp) size_t machine__fprintf_dsos_buildid(struct machine *m, FILE *fp, bool (skip)(struct dso *dso, int parm), int parm) { - return __dsos__fprintf_buildid(&m->dsos.head, fp, skip, parm); + return __dsos__fprintf_buildid(&m->dsos, fp, skip, parm); } size_t machines__fprintf_dsos_buildid(struct machines *machines, FILE *fp, @@ -3306,3 +3277,8 @@ bool machine__is_lock_function(struct machine *machine, u64 addr) return false; } + +int machine__hit_all_dsos(struct machine *machine) +{ + return __dsos__hit_all(&machine->dsos); +} diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h index 4312f6db6de0..82a47bac8023 100644 --- a/tools/perf/util/machine.h +++ b/tools/perf/util/machine.h @@ -306,4 +306,6 @@ int machine__map_x86_64_entry_trampolines(struct machine *machine, int machine__resolve(struct machine *machine, struct addr_location *al, struct perf_sample *sample); +int machine__hit_all_dsos(struct machine *machine); + #endif /* __PERF_MACHINE_H */ diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 02a932a83c51..a10343b9dcd4 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -2916,3 +2916,24 @@ int perf_event__process_id_index(struct perf_session *session, } return 0; } + +int perf_session__dsos_hit_all(struct perf_session *session) +{ + struct rb_node *nd; + int err; + + err = machine__hit_all_dsos(&session->machines.host); + if (err) + return err; + + for (nd = rb_first_cached(&session->machines.guests); nd; + nd = rb_next(nd)) { + struct machine *pos = rb_entry(nd, struct machine, rb_node); + + err = machine__hit_all_dsos(pos); + if (err) + return err; + } + + return 0; +} diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 5064c6ec11e7..3b0256e977a6 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h @@ -156,6 +156,8 @@ int perf_session__deliver_synth_event(struct perf_session *session, union perf_event *event, struct perf_sample *sample); +int perf_session__dsos_hit_all(struct perf_session *session); + int perf_event__process_id_index(struct perf_session *session, union perf_event *event); -- cgit v1.2.3-59-g8ed1b From f649ed80f3cabbf16b228894bb7ecd718da86e47 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Tue, 9 Apr 2024 23:42:04 -0700 Subject: perf dsos: Tidy reference counting and locking Move more functionality into dsos.c generally from machine.c, renaming functions to match their new usage. The find function is made to always "get" before returning a dso. Reduce the scope of locks in vdso to match the locking paradigm. Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andi Kleen Cc: Anne Macedo Cc: Athira Rajeev Cc: Ben Gainey Cc: Changbin Du Cc: Chengen Du Cc: Colin Ian King Cc: Ilkka Koskinen Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: K Prateek Nayak Cc: Kan Liang Cc: Leo Yan Cc: Li Dong Cc: Mark Rutland Cc: Markus Elfring Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Paran Lee Cc: Peter Zijlstra Cc: Ravi Bangoria Cc: Song Liu Cc: Sun Haiyong Cc: Thomas Richter Cc: Yang Jihong Cc: Yanteng Si Cc: Yicong Yang Cc: zhaimingbing Link: https://lore.kernel.org/r/20240410064214.2755936-3-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/dsos.c | 73 ++++++++++++++++++++++++++++++++++++++++++----- tools/perf/util/dsos.h | 9 +++++- tools/perf/util/machine.c | 62 ++-------------------------------------- tools/perf/util/map.c | 4 +-- tools/perf/util/vdso.c | 48 +++++++++++++------------------ 5 files changed, 97 insertions(+), 99 deletions(-) diff --git a/tools/perf/util/dsos.c b/tools/perf/util/dsos.c index e65ef6762bed..d269e09005a7 100644 --- a/tools/perf/util/dsos.c +++ b/tools/perf/util/dsos.c @@ -181,7 +181,7 @@ struct dso *__dsos__findnew_link_by_longname_id(struct rb_root *root, struct dso * at the end of the list of duplicates. */ if (!dso || (dso == this)) - return this; /* Find matching dso */ + return dso__get(this); /* Find matching dso */ /* * The core kernel DSOs may have duplicated long name. * In this case, the short name should be different. @@ -253,15 +253,20 @@ static struct dso *__dsos__find_id(struct dsos *dsos, const char *name, struct d if (cmp_short) { list_for_each_entry(pos, &dsos->head, node) if (__dso__cmp_short_name(name, id, pos) == 0) - return pos; + return dso__get(pos); return NULL; } return __dsos__findnew_by_longname_id(&dsos->root, name, id); } -struct dso *__dsos__find(struct dsos *dsos, const char *name, bool cmp_short) +struct dso *dsos__find(struct dsos *dsos, const char *name, bool cmp_short) { - return __dsos__find_id(dsos, name, NULL, cmp_short); + struct dso *res; + + down_read(&dsos->lock); + res = __dsos__find_id(dsos, name, NULL, cmp_short); + up_read(&dsos->lock); + return res; } static void dso__set_basename(struct dso *dso) @@ -303,8 +308,6 @@ static struct dso *__dsos__addnew_id(struct dsos *dsos, const char *name, struct if (dso != NULL) { __dsos__add(dsos, dso); dso__set_basename(dso); - /* Put dso here because __dsos_add already got it */ - dso__put(dso); } return dso; } @@ -328,7 +331,7 @@ struct dso *dsos__findnew_id(struct dsos *dsos, const char *name, struct dso_id { struct dso *dso; down_write(&dsos->lock); - dso = dso__get(__dsos__findnew_id(dsos, name, id)); + dso = __dsos__findnew_id(dsos, name, id); up_write(&dsos->lock); return dso; } @@ -374,3 +377,59 @@ int __dsos__hit_all(struct dsos *dsos) return 0; } + +struct dso *dsos__findnew_module_dso(struct dsos *dsos, + struct machine *machine, + struct kmod_path *m, + const char *filename) +{ + struct dso *dso; + + down_write(&dsos->lock); + + dso = __dsos__find_id(dsos, m->name, NULL, /*cmp_short=*/true); + if (!dso) { + dso = __dsos__addnew(dsos, m->name); + if (dso == NULL) + goto out_unlock; + + dso__set_module_info(dso, m, machine); + dso__set_long_name(dso, strdup(filename), true); + dso->kernel = DSO_SPACE__KERNEL; + } + +out_unlock: + up_write(&dsos->lock); + return dso; +} + +struct dso *dsos__find_kernel_dso(struct dsos *dsos) +{ + struct dso *dso, *res = NULL; + + down_read(&dsos->lock); + list_for_each_entry(dso, &dsos->head, node) { + /* + * The cpumode passed to is_kernel_module is not the cpumode of + * *this* event. If we insist on passing correct cpumode to + * is_kernel_module, we should record the cpumode when we adding + * this dso to the linked list. + * + * However we don't really need passing correct cpumode. We + * know the correct cpumode must be kernel mode (if not, we + * should not link it onto kernel_dsos list). + * + * Therefore, we pass PERF_RECORD_MISC_CPUMODE_UNKNOWN. + * is_kernel_module() treats it as a kernel cpumode. + */ + if (!dso->kernel || + is_kernel_module(dso->long_name, + PERF_RECORD_MISC_CPUMODE_UNKNOWN)) + continue; + + res = dso__get(dso); + break; + } + up_read(&dsos->lock); + return res; +} diff --git a/tools/perf/util/dsos.h b/tools/perf/util/dsos.h index 1c81ddf07f8f..a7c7f723c5ff 100644 --- a/tools/perf/util/dsos.h +++ b/tools/perf/util/dsos.h @@ -10,6 +10,8 @@ struct dso; struct dso_id; +struct kmod_path; +struct machine; /* * DSOs are put into both a list for fast iteration and rbtree for fast @@ -33,7 +35,7 @@ void dsos__exit(struct dsos *dsos); void __dsos__add(struct dsos *dsos, struct dso *dso); void dsos__add(struct dsos *dsos, struct dso *dso); struct dso *__dsos__addnew(struct dsos *dsos, const char *name); -struct dso *__dsos__find(struct dsos *dsos, const char *name, bool cmp_short); +struct dso *dsos__find(struct dsos *dsos, const char *name, bool cmp_short); struct dso *dsos__findnew_id(struct dsos *dsos, const char *name, struct dso_id *id); @@ -48,4 +50,9 @@ size_t __dsos__fprintf(struct dsos *dsos, FILE *fp); int __dsos__hit_all(struct dsos *dsos); +struct dso *dsos__findnew_module_dso(struct dsos *dsos, struct machine *machine, + struct kmod_path *m, const char *filename); + +struct dso *dsos__find_kernel_dso(struct dsos *dsos); + #endif /* __PERF_DSOS */ diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index 848a94b8602b..e2c800a1449b 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -646,31 +646,6 @@ int machine__process_lost_samples_event(struct machine *machine __maybe_unused, return 0; } -static struct dso *machine__findnew_module_dso(struct machine *machine, - struct kmod_path *m, - const char *filename) -{ - struct dso *dso; - - down_write(&machine->dsos.lock); - - dso = __dsos__find(&machine->dsos, m->name, true); - if (!dso) { - dso = __dsos__addnew(&machine->dsos, m->name); - if (dso == NULL) - goto out_unlock; - - dso__set_module_info(dso, m, machine); - dso__set_long_name(dso, strdup(filename), true); - dso->kernel = DSO_SPACE__KERNEL; - } - - dso__get(dso); -out_unlock: - up_write(&machine->dsos.lock); - return dso; -} - int machine__process_aux_event(struct machine *machine __maybe_unused, union perf_event *event) { @@ -854,7 +829,7 @@ static struct map *machine__addnew_module_map(struct machine *machine, u64 start if (kmod_path__parse_name(&m, filename)) return NULL; - dso = machine__findnew_module_dso(machine, &m, filename); + dso = dsos__findnew_module_dso(&machine->dsos, machine, &m, filename); if (dso == NULL) goto out; @@ -1663,40 +1638,7 @@ static int machine__process_kernel_mmap_event(struct machine *machine, * Should be there already, from the build-id table in * the header. */ - struct dso *kernel = NULL; - struct dso *dso; - - down_read(&machine->dsos.lock); - - list_for_each_entry(dso, &machine->dsos.head, node) { - - /* - * The cpumode passed to is_kernel_module is not the - * cpumode of *this* event. If we insist on passing - * correct cpumode to is_kernel_module, we should - * record the cpumode when we adding this dso to the - * linked list. - * - * However we don't really need passing correct - * cpumode. We know the correct cpumode must be kernel - * mode (if not, we should not link it onto kernel_dsos - * list). - * - * Therefore, we pass PERF_RECORD_MISC_CPUMODE_UNKNOWN. - * is_kernel_module() treats it as a kernel cpumode. - */ - - if (!dso->kernel || - is_kernel_module(dso->long_name, - PERF_RECORD_MISC_CPUMODE_UNKNOWN)) - continue; - - - kernel = dso__get(dso); - break; - } - - up_read(&machine->dsos.lock); + struct dso *kernel = dsos__find_kernel_dso(&machine->dsos); if (kernel == NULL) kernel = machine__findnew_dso(machine, machine->mmap_name); diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index a5d57c201a30..cca871959f87 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c @@ -196,9 +196,7 @@ struct map *map__new(struct machine *machine, u64 start, u64 len, * reading the header will have the build ID set and all future mmaps will * have it missing. */ - down_read(&machine->dsos.lock); - header_bid_dso = __dsos__find(&machine->dsos, filename, false); - up_read(&machine->dsos.lock); + header_bid_dso = dsos__find(&machine->dsos, filename, false); if (header_bid_dso && header_bid_dso->header_build_id) { dso__set_build_id(dso, &header_bid_dso->bid); dso->header_build_id = 1; diff --git a/tools/perf/util/vdso.c b/tools/perf/util/vdso.c index df8963796187..35532dcbff74 100644 --- a/tools/perf/util/vdso.c +++ b/tools/perf/util/vdso.c @@ -133,8 +133,6 @@ static struct dso *__machine__addnew_vdso(struct machine *machine, const char *s if (dso != NULL) { __dsos__add(&machine->dsos, dso); dso__set_long_name(dso, long_name, false); - /* Put dso here because __dsos_add already got it */ - dso__put(dso); } return dso; @@ -252,17 +250,15 @@ static struct dso *__machine__findnew_compat(struct machine *machine, const char *file_name; struct dso *dso; - dso = __dsos__find(&machine->dsos, vdso_file->dso_name, true); + dso = dsos__find(&machine->dsos, vdso_file->dso_name, true); if (dso) - goto out; + return dso; file_name = vdso__get_compat_file(vdso_file); if (!file_name) - goto out; + return NULL; - dso = __machine__addnew_vdso(machine, vdso_file->dso_name, file_name); -out: - return dso; + return __machine__addnew_vdso(machine, vdso_file->dso_name, file_name); } static int __machine__findnew_vdso_compat(struct machine *machine, @@ -308,21 +304,21 @@ static struct dso *machine__find_vdso(struct machine *machine, dso_type = machine__thread_dso_type(machine, thread); switch (dso_type) { case DSO__TYPE_32BIT: - dso = __dsos__find(&machine->dsos, DSO__NAME_VDSO32, true); + dso = dsos__find(&machine->dsos, DSO__NAME_VDSO32, true); if (!dso) { - dso = __dsos__find(&machine->dsos, DSO__NAME_VDSO, - true); + dso = dsos__find(&machine->dsos, DSO__NAME_VDSO, + true); if (dso && dso_type != dso__type(dso, machine)) dso = NULL; } break; case DSO__TYPE_X32BIT: - dso = __dsos__find(&machine->dsos, DSO__NAME_VDSOX32, true); + dso = dsos__find(&machine->dsos, DSO__NAME_VDSOX32, true); break; case DSO__TYPE_64BIT: case DSO__TYPE_UNKNOWN: default: - dso = __dsos__find(&machine->dsos, DSO__NAME_VDSO, true); + dso = dsos__find(&machine->dsos, DSO__NAME_VDSO, true); break; } @@ -334,37 +330,33 @@ struct dso *machine__findnew_vdso(struct machine *machine, { struct vdso_info *vdso_info; struct dso *dso = NULL; + char *file; - down_write(&machine->dsos.lock); if (!machine->vdso_info) machine->vdso_info = vdso_info__new(); vdso_info = machine->vdso_info; if (!vdso_info) - goto out_unlock; + return NULL; dso = machine__find_vdso(machine, thread); if (dso) - goto out_unlock; + return dso; #if BITS_PER_LONG == 64 if (__machine__findnew_vdso_compat(machine, thread, vdso_info, &dso)) - goto out_unlock; + return dso; #endif - dso = __dsos__find(&machine->dsos, DSO__NAME_VDSO, true); - if (!dso) { - char *file; + dso = dsos__find(&machine->dsos, DSO__NAME_VDSO, true); + if (dso) + return dso; - file = get_file(&vdso_info->vdso); - if (file) - dso = __machine__addnew_vdso(machine, DSO__NAME_VDSO, file); - } + file = get_file(&vdso_info->vdso); + if (!file) + return NULL; -out_unlock: - dso__get(dso); - up_write(&machine->dsos.lock); - return dso; + return __machine__addnew_vdso(machine, DSO__NAME_VDSO, file); } bool dso__is_vdso(struct dso *dso) -- cgit v1.2.3-59-g8ed1b From 73f3fea2e11dbd92f49807ee1c33429674f71f13 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Tue, 9 Apr 2024 23:42:05 -0700 Subject: perf dsos: Introduce dsos__for_each_dso() To better abstract the dsos internals, introduce dsos__for_each_dso that does a callback on each dso. This also means the read lock can be correctly held. Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andi Kleen Cc: Anne Macedo Cc: Athira Rajeev Cc: Ben Gainey Cc: Changbin Du Cc: Chengen Du Cc: Colin Ian King Cc: Ilkka Koskinen Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: K Prateek Nayak Cc: Kan Liang Cc: Leo Yan Cc: Li Dong Cc: Mark Rutland Cc: Markus Elfring Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Paran Lee Cc: Peter Zijlstra Cc: Ravi Bangoria Cc: Song Liu Cc: Sun Haiyong Cc: Thomas Richter Cc: Yang Jihong Cc: Yanteng Si Cc: Yicong Yang Cc: zhaimingbing Link: https://lore.kernel.org/r/20240410064214.2755936-4-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-inject.c | 25 +++++++++------ tools/perf/util/build-id.c | 76 +++++++++++++++++++++++++-------------------- tools/perf/util/dsos.c | 16 ++++++++++ tools/perf/util/dsos.h | 8 ++--- tools/perf/util/machine.c | 40 +++++++++++++++--------- 5 files changed, 100 insertions(+), 65 deletions(-) diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c index ef73317e6ae7..ce5e28eaad90 100644 --- a/tools/perf/builtin-inject.c +++ b/tools/perf/builtin-inject.c @@ -1187,23 +1187,28 @@ static int synthesize_build_id(struct perf_inject *inject, struct dso *dso, pid_ process_build_id, machine); } +static int guest_session__add_build_ids_cb(struct dso *dso, void *data) +{ + struct guest_session *gs = data; + struct perf_inject *inject = container_of(gs, struct perf_inject, guest_session); + + if (!dso->has_build_id) + return 0; + + return synthesize_build_id(inject, dso, gs->machine_pid); + +} + static int guest_session__add_build_ids(struct guest_session *gs) { struct perf_inject *inject = container_of(gs, struct perf_inject, guest_session); - struct machine *machine = &gs->session->machines.host; - struct dso *dso; - int ret; /* Build IDs will be put in the Build ID feature section */ perf_header__set_feat(&inject->session->header, HEADER_BUILD_ID); - dsos__for_each_with_build_id(dso, &machine->dsos.head) { - ret = synthesize_build_id(inject, dso, gs->machine_pid); - if (ret) - return ret; - } - - return 0; + return dsos__for_each_dso(&gs->session->machines.host.dsos, + guest_session__add_build_ids_cb, + gs); } static int guest_session__ksymbol_event(struct perf_tool *tool, diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c index a617b1917e6b..a6d3c253f19f 100644 --- a/tools/perf/util/build-id.c +++ b/tools/perf/util/build-id.c @@ -327,48 +327,56 @@ static int write_buildid(const char *name, size_t name_len, struct build_id *bid return write_padded(fd, name, name_len + 1, len); } -static int machine__write_buildid_table(struct machine *machine, - struct feat_fd *fd) +struct machine__write_buildid_table_cb_args { + struct machine *machine; + struct feat_fd *fd; + u16 kmisc, umisc; +}; + +static int machine__write_buildid_table_cb(struct dso *dso, void *data) { - int err = 0; - struct dso *pos; - u16 kmisc = PERF_RECORD_MISC_KERNEL, - umisc = PERF_RECORD_MISC_USER; + struct machine__write_buildid_table_cb_args *args = data; + const char *name; + size_t name_len; + bool in_kernel = false; - if (!machine__is_host(machine)) { - kmisc = PERF_RECORD_MISC_GUEST_KERNEL; - umisc = PERF_RECORD_MISC_GUEST_USER; - } + if (!dso->has_build_id) + return 0; - dsos__for_each_with_build_id(pos, &machine->dsos.head) { - const char *name; - size_t name_len; - bool in_kernel = false; + if (!dso->hit && !dso__is_vdso(dso)) + return 0; - if (!pos->hit && !dso__is_vdso(pos)) - continue; + if (dso__is_vdso(dso)) { + name = dso->short_name; + name_len = dso->short_name_len; + } else if (dso__is_kcore(dso)) { + name = args->machine->mmap_name; + name_len = strlen(name); + } else { + name = dso->long_name; + name_len = dso->long_name_len; + } - if (dso__is_vdso(pos)) { - name = pos->short_name; - name_len = pos->short_name_len; - } else if (dso__is_kcore(pos)) { - name = machine->mmap_name; - name_len = strlen(name); - } else { - name = pos->long_name; - name_len = pos->long_name_len; - } + in_kernel = dso->kernel || is_kernel_module(name, PERF_RECORD_MISC_CPUMODE_UNKNOWN); + return write_buildid(name, name_len, &dso->bid, args->machine->pid, + in_kernel ? args->kmisc : args->umisc, args->fd); +} - in_kernel = pos->kernel || - is_kernel_module(name, - PERF_RECORD_MISC_CPUMODE_UNKNOWN); - err = write_buildid(name, name_len, &pos->bid, machine->pid, - in_kernel ? kmisc : umisc, fd); - if (err) - break; +static int machine__write_buildid_table(struct machine *machine, struct feat_fd *fd) +{ + struct machine__write_buildid_table_cb_args args = { + .machine = machine, + .fd = fd, + .kmisc = PERF_RECORD_MISC_KERNEL, + .umisc = PERF_RECORD_MISC_USER, + }; + + if (!machine__is_host(machine)) { + args.kmisc = PERF_RECORD_MISC_GUEST_KERNEL; + args.umisc = PERF_RECORD_MISC_GUEST_USER; } - return err; + return dsos__for_each_dso(&machine->dsos, machine__write_buildid_table_cb, &args); } int perf_session__write_buildid_table(struct perf_session *session, diff --git a/tools/perf/util/dsos.c b/tools/perf/util/dsos.c index d269e09005a7..d43f64939b12 100644 --- a/tools/perf/util/dsos.c +++ b/tools/perf/util/dsos.c @@ -433,3 +433,19 @@ struct dso *dsos__find_kernel_dso(struct dsos *dsos) up_read(&dsos->lock); return res; } + +int dsos__for_each_dso(struct dsos *dsos, int (*cb)(struct dso *dso, void *data), void *data) +{ + struct dso *dso; + + down_read(&dsos->lock); + list_for_each_entry(dso, &dsos->head, node) { + int err; + + err = cb(dso, data); + if (err) + return err; + } + up_read(&dsos->lock); + return 0; +} diff --git a/tools/perf/util/dsos.h b/tools/perf/util/dsos.h index a7c7f723c5ff..317a263f0e37 100644 --- a/tools/perf/util/dsos.h +++ b/tools/perf/util/dsos.h @@ -23,12 +23,6 @@ struct dsos { struct rw_semaphore lock; }; -#define dsos__for_each_with_build_id(pos, head) \ - list_for_each_entry(pos, head, node) \ - if (!pos->has_build_id) \ - continue; \ - else - void dsos__init(struct dsos *dsos); void dsos__exit(struct dsos *dsos); @@ -55,4 +49,6 @@ struct dso *dsos__findnew_module_dso(struct dsos *dsos, struct machine *machine, struct dso *dsos__find_kernel_dso(struct dsos *dsos); +int dsos__for_each_dso(struct dsos *dsos, int (*cb)(struct dso *dso, void *data), void *data); + #endif /* __PERF_DSOS */ diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index e2c800a1449b..e3deef38405c 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -1562,16 +1562,14 @@ out_put: return ret; } -static bool machine__uses_kcore(struct machine *machine) +static int machine__uses_kcore_cb(struct dso *dso, void *data __maybe_unused) { - struct dso *dso; - - list_for_each_entry(dso, &machine->dsos.head, node) { - if (dso__is_kcore(dso)) - return true; - } + return dso__is_kcore(dso) ? 1 : 0; +} - return false; +static bool machine__uses_kcore(struct machine *machine) +{ + return dsos__for_each_dso(&machine->dsos, machine__uses_kcore_cb, NULL) != 0 ? true : false; } static bool perf_event__is_extra_kernel_mmap(struct machine *machine, @@ -3137,16 +3135,28 @@ char *machine__resolve_kernel_addr(void *vmachine, unsigned long long *addrp, ch return sym->name; } +struct machine__for_each_dso_cb_args { + struct machine *machine; + machine__dso_t fn; + void *priv; +}; + +static int machine__for_each_dso_cb(struct dso *dso, void *data) +{ + struct machine__for_each_dso_cb_args *args = data; + + return args->fn(dso, args->machine, args->priv); +} + int machine__for_each_dso(struct machine *machine, machine__dso_t fn, void *priv) { - struct dso *pos; - int err = 0; + struct machine__for_each_dso_cb_args args = { + .machine = machine, + .fn = fn, + .priv = priv, + }; - list_for_each_entry(pos, &machine->dsos.head, node) { - if (fn(pos, machine, priv)) - err = -1; - } - return err; + return dsos__for_each_dso(&machine->dsos, machine__for_each_dso_cb, &args); } int machine__for_each_kernel_map(struct machine *machine, machine__map_t fn, void *priv) -- cgit v1.2.3-59-g8ed1b From 1d6eff930595eef83cfb8486c122249afb66145d Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Tue, 9 Apr 2024 23:42:06 -0700 Subject: perf dso: Move dso functions out of dsos.c Move dso and dso_id functions to dso.c to match the struct declarations. Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andi Kleen Cc: Anne Macedo Cc: Athira Rajeev Cc: Ben Gainey Cc: Changbin Du Cc: Chengen Du Cc: Colin Ian King Cc: Ilkka Koskinen Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: K Prateek Nayak Cc: Kan Liang Cc: Leo Yan Cc: Li Dong Cc: Mark Rutland Cc: Markus Elfring Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Paran Lee Cc: Peter Zijlstra Cc: Ravi Bangoria Cc: Song Liu Cc: Sun Haiyong Cc: Thomas Richter Cc: Yang Jihong Cc: Yanteng Si Cc: Yicong Yang Cc: zhaimingbing Link: https://lore.kernel.org/r/20240410064214.2755936-5-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/dso.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/dso.h | 4 ++++ tools/perf/util/dsos.c | 61 -------------------------------------------------- 3 files changed, 65 insertions(+), 61 deletions(-) diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c index 6e2a7198b382..ad562743d769 100644 --- a/tools/perf/util/dso.c +++ b/tools/perf/util/dso.c @@ -1269,6 +1269,67 @@ static void dso__set_long_name_id(struct dso *dso, const char *name, struct dso_ __dsos__findnew_link_by_longname_id(root, dso, NULL, id); } +static int __dso_id__cmp(struct dso_id *a, struct dso_id *b) +{ + if (a->maj > b->maj) return -1; + if (a->maj < b->maj) return 1; + + if (a->min > b->min) return -1; + if (a->min < b->min) return 1; + + if (a->ino > b->ino) return -1; + if (a->ino < b->ino) return 1; + + /* + * Synthesized MMAP events have zero ino_generation, avoid comparing + * them with MMAP events with actual ino_generation. + * + * I found it harmful because the mismatch resulted in a new + * dso that did not have a build ID whereas the original dso did have a + * build ID. The build ID was essential because the object was not found + * otherwise. - Adrian + */ + if (a->ino_generation && b->ino_generation) { + if (a->ino_generation > b->ino_generation) return -1; + if (a->ino_generation < b->ino_generation) return 1; + } + + return 0; +} + +bool dso_id__empty(struct dso_id *id) +{ + if (!id) + return true; + + return !id->maj && !id->min && !id->ino && !id->ino_generation; +} + +void dso__inject_id(struct dso *dso, struct dso_id *id) +{ + dso->id.maj = id->maj; + dso->id.min = id->min; + dso->id.ino = id->ino; + dso->id.ino_generation = id->ino_generation; +} + +int dso_id__cmp(struct dso_id *a, struct dso_id *b) +{ + /* + * The second is always dso->id, so zeroes if not set, assume passing + * NULL for a means a zeroed id + */ + if (dso_id__empty(a) || dso_id__empty(b)) + return 0; + + return __dso_id__cmp(a, b); +} + +int dso__cmp_id(struct dso *a, struct dso *b) +{ + return __dso_id__cmp(&a->id, &b->id); +} + void dso__set_long_name(struct dso *dso, const char *name, bool name_allocated) { dso__set_long_name_id(dso, name, NULL, name_allocated); diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h index 3d4faad8d5dc..2c295438226d 100644 --- a/tools/perf/util/dso.h +++ b/tools/perf/util/dso.h @@ -238,6 +238,9 @@ static inline void dso__set_loaded(struct dso *dso) dso->loaded = true; } +int dso_id__cmp(struct dso_id *a, struct dso_id *b); +bool dso_id__empty(struct dso_id *id); + struct dso *dso__new_id(const char *name, struct dso_id *id); struct dso *dso__new(const char *name); void dso__delete(struct dso *dso); @@ -245,6 +248,7 @@ void dso__delete(struct dso *dso); int dso__cmp_id(struct dso *a, struct dso *b); void dso__set_short_name(struct dso *dso, const char *name, bool name_allocated); void dso__set_long_name(struct dso *dso, const char *name, bool name_allocated); +void dso__inject_id(struct dso *dso, struct dso_id *id); int dso__name_len(const struct dso *dso); diff --git a/tools/perf/util/dsos.c b/tools/perf/util/dsos.c index d43f64939b12..f816927a21ff 100644 --- a/tools/perf/util/dsos.c +++ b/tools/perf/util/dsos.c @@ -41,67 +41,6 @@ void dsos__exit(struct dsos *dsos) exit_rwsem(&dsos->lock); } -static int __dso_id__cmp(struct dso_id *a, struct dso_id *b) -{ - if (a->maj > b->maj) return -1; - if (a->maj < b->maj) return 1; - - if (a->min > b->min) return -1; - if (a->min < b->min) return 1; - - if (a->ino > b->ino) return -1; - if (a->ino < b->ino) return 1; - - /* - * Synthesized MMAP events have zero ino_generation, avoid comparing - * them with MMAP events with actual ino_generation. - * - * I found it harmful because the mismatch resulted in a new - * dso that did not have a build ID whereas the original dso did have a - * build ID. The build ID was essential because the object was not found - * otherwise. - Adrian - */ - if (a->ino_generation && b->ino_generation) { - if (a->ino_generation > b->ino_generation) return -1; - if (a->ino_generation < b->ino_generation) return 1; - } - - return 0; -} - -static bool dso_id__empty(struct dso_id *id) -{ - if (!id) - return true; - - return !id->maj && !id->min && !id->ino && !id->ino_generation; -} - -static void dso__inject_id(struct dso *dso, struct dso_id *id) -{ - dso->id.maj = id->maj; - dso->id.min = id->min; - dso->id.ino = id->ino; - dso->id.ino_generation = id->ino_generation; -} - -static int dso_id__cmp(struct dso_id *a, struct dso_id *b) -{ - /* - * The second is always dso->id, so zeroes if not set, assume passing - * NULL for a means a zeroed id - */ - if (dso_id__empty(a) || dso_id__empty(b)) - return 0; - - return __dso_id__cmp(a, b); -} - -int dso__cmp_id(struct dso *a, struct dso *b) -{ - return __dso_id__cmp(&a->id, &b->id); -} - bool __dsos__read_build_ids(struct dsos *dsos, bool with_hits) { struct list_head *head = &dsos->head; -- cgit v1.2.3-59-g8ed1b From 0ffc8fca5c15a70f32c8aff12c566bbd3991bd0a Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Tue, 9 Apr 2024 23:42:07 -0700 Subject: perf dsos: Switch more loops to dsos__for_each_dso() Switch loops within dsos.c, add a version that isn't locked. Switch some unlocked loops to hold the read lock. Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andi Kleen Cc: Anne Macedo Cc: Athira Rajeev Cc: Ben Gainey Cc: Changbin Du Cc: Chengen Du Cc: Colin Ian King Cc: Ilkka Koskinen Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: K Prateek Nayak Cc: Kan Liang Cc: Leo Yan Cc: Li Dong Cc: Mark Rutland Cc: Markus Elfring Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Paran Lee Cc: Peter Zijlstra Cc: Ravi Bangoria Cc: Song Liu Cc: Sun Haiyong Cc: Thomas Richter Cc: Yang Jihong Cc: Yanteng Si Cc: Yicong Yang Cc: zhaimingbing Link: https://lore.kernel.org/r/20240410064214.2755936-6-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/build-id.c | 2 +- tools/perf/util/dsos.c | 258 +++++++++++++++++++++++++++++---------------- tools/perf/util/dsos.h | 8 +- tools/perf/util/machine.c | 8 +- 4 files changed, 174 insertions(+), 102 deletions(-) diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c index a6d3c253f19f..864bc26b6b46 100644 --- a/tools/perf/util/build-id.c +++ b/tools/perf/util/build-id.c @@ -964,7 +964,7 @@ int perf_session__cache_build_ids(struct perf_session *session) static bool machine__read_build_ids(struct machine *machine, bool with_hits) { - return __dsos__read_build_ids(&machine->dsos, with_hits); + return dsos__read_build_ids(&machine->dsos, with_hits); } bool perf_session__read_build_ids(struct perf_session *session, bool with_hits) diff --git a/tools/perf/util/dsos.c b/tools/perf/util/dsos.c index f816927a21ff..b7fbfb877ae3 100644 --- a/tools/perf/util/dsos.c +++ b/tools/perf/util/dsos.c @@ -41,38 +41,65 @@ void dsos__exit(struct dsos *dsos) exit_rwsem(&dsos->lock); } -bool __dsos__read_build_ids(struct dsos *dsos, bool with_hits) + +static int __dsos__for_each_dso(struct dsos *dsos, + int (*cb)(struct dso *dso, void *data), + void *data) +{ + struct dso *dso; + + list_for_each_entry(dso, &dsos->head, node) { + int err; + + err = cb(dso, data); + if (err) + return err; + } + return 0; +} + +struct dsos__read_build_ids_cb_args { + bool with_hits; + bool have_build_id; +}; + +static int dsos__read_build_ids_cb(struct dso *dso, void *data) { - struct list_head *head = &dsos->head; - bool have_build_id = false; - struct dso *pos; + struct dsos__read_build_ids_cb_args *args = data; struct nscookie nsc; - list_for_each_entry(pos, head, node) { - if (with_hits && !pos->hit && !dso__is_vdso(pos)) - continue; - if (pos->has_build_id) { - have_build_id = true; - continue; - } - nsinfo__mountns_enter(pos->nsinfo, &nsc); - if (filename__read_build_id(pos->long_name, &pos->bid) > 0) { - have_build_id = true; - pos->has_build_id = true; - } else if (errno == ENOENT && pos->nsinfo) { - char *new_name = dso__filename_with_chroot(pos, pos->long_name); - - if (new_name && filename__read_build_id(new_name, - &pos->bid) > 0) { - have_build_id = true; - pos->has_build_id = true; - } - free(new_name); + if (args->with_hits && !dso->hit && !dso__is_vdso(dso)) + return 0; + if (dso->has_build_id) { + args->have_build_id = true; + return 0; + } + nsinfo__mountns_enter(dso->nsinfo, &nsc); + if (filename__read_build_id(dso->long_name, &dso->bid) > 0) { + args->have_build_id = true; + dso->has_build_id = true; + } else if (errno == ENOENT && dso->nsinfo) { + char *new_name = dso__filename_with_chroot(dso, dso->long_name); + + if (new_name && filename__read_build_id(new_name, &dso->bid) > 0) { + args->have_build_id = true; + dso->has_build_id = true; } - nsinfo__mountns_exit(&nsc); + free(new_name); } + nsinfo__mountns_exit(&nsc); + return 0; +} - return have_build_id; +bool dsos__read_build_ids(struct dsos *dsos, bool with_hits) +{ + struct dsos__read_build_ids_cb_args args = { + .with_hits = with_hits, + .have_build_id = false, + }; + + dsos__for_each_dso(dsos, dsos__read_build_ids_cb, &args); + return args.have_build_id; } static int __dso__cmp_long_name(const char *long_name, struct dso_id *id, struct dso *b) @@ -105,6 +132,7 @@ struct dso *__dsos__findnew_link_by_longname_id(struct rb_root *root, struct dso if (!name) name = dso->long_name; + /* * Find node with the matching name */ @@ -185,17 +213,40 @@ static struct dso *__dsos__findnew_by_longname_id(struct rb_root *root, const ch return __dsos__findnew_link_by_longname_id(root, NULL, name, id); } +struct dsos__find_id_cb_args { + const char *name; + struct dso_id *id; + struct dso *res; +}; + +static int dsos__find_id_cb(struct dso *dso, void *data) +{ + struct dsos__find_id_cb_args *args = data; + + if (__dso__cmp_short_name(args->name, args->id, dso) == 0) { + args->res = dso__get(dso); + return 1; + } + return 0; + +} + static struct dso *__dsos__find_id(struct dsos *dsos, const char *name, struct dso_id *id, bool cmp_short) { - struct dso *pos; + struct dso *res; if (cmp_short) { - list_for_each_entry(pos, &dsos->head, node) - if (__dso__cmp_short_name(name, id, pos) == 0) - return dso__get(pos); - return NULL; + struct dsos__find_id_cb_args args = { + .name = name, + .id = id, + .res = NULL, + }; + + __dsos__for_each_dso(dsos, dsos__find_id_cb, &args); + return args.res; } - return __dsos__findnew_by_longname_id(&dsos->root, name, id); + res = __dsos__findnew_by_longname_id(&dsos->root, name, id); + return res; } struct dso *dsos__find(struct dsos *dsos, const char *name, bool cmp_short) @@ -275,48 +326,74 @@ struct dso *dsos__findnew_id(struct dsos *dsos, const char *name, struct dso_id return dso; } -size_t __dsos__fprintf_buildid(struct dsos *dsos, FILE *fp, - bool (skip)(struct dso *dso, int parm), int parm) -{ - struct list_head *head = &dsos->head; - struct dso *pos; - size_t ret = 0; +struct dsos__fprintf_buildid_cb_args { + FILE *fp; + bool (*skip)(struct dso *dso, int parm); + int parm; + size_t ret; +}; - list_for_each_entry(pos, head, node) { - char sbuild_id[SBUILD_ID_SIZE]; +static int dsos__fprintf_buildid_cb(struct dso *dso, void *data) +{ + struct dsos__fprintf_buildid_cb_args *args = data; + char sbuild_id[SBUILD_ID_SIZE]; - if (skip && skip(pos, parm)) - continue; - build_id__sprintf(&pos->bid, sbuild_id); - ret += fprintf(fp, "%-40s %s\n", sbuild_id, pos->long_name); - } - return ret; + if (args->skip && args->skip(dso, args->parm)) + return 0; + build_id__sprintf(&dso->bid, sbuild_id); + args->ret += fprintf(args->fp, "%-40s %s\n", sbuild_id, dso->long_name); + return 0; } -size_t __dsos__fprintf(struct dsos *dsos, FILE *fp) +size_t dsos__fprintf_buildid(struct dsos *dsos, FILE *fp, + bool (*skip)(struct dso *dso, int parm), int parm) { - struct list_head *head = &dsos->head; - struct dso *pos; - size_t ret = 0; + struct dsos__fprintf_buildid_cb_args args = { + .fp = fp, + .skip = skip, + .parm = parm, + .ret = 0, + }; + + dsos__for_each_dso(dsos, dsos__fprintf_buildid_cb, &args); + return args.ret; +} - list_for_each_entry(pos, head, node) { - ret += dso__fprintf(pos, fp); - } +struct dsos__fprintf_cb_args { + FILE *fp; + size_t ret; +}; - return ret; +static int dsos__fprintf_cb(struct dso *dso, void *data) +{ + struct dsos__fprintf_cb_args *args = data; + + args->ret += dso__fprintf(dso, args->fp); + return 0; } -int __dsos__hit_all(struct dsos *dsos) +size_t dsos__fprintf(struct dsos *dsos, FILE *fp) { - struct list_head *head = &dsos->head; - struct dso *pos; + struct dsos__fprintf_cb_args args = { + .fp = fp, + .ret = 0, + }; - list_for_each_entry(pos, head, node) - pos->hit = true; + dsos__for_each_dso(dsos, dsos__fprintf_cb, &args); + return args.ret; +} +static int dsos__hit_all_cb(struct dso *dso, void *data __maybe_unused) +{ + dso->hit = true; return 0; } +int dsos__hit_all(struct dsos *dsos) +{ + return dsos__for_each_dso(dsos, dsos__hit_all_cb, NULL); +} + struct dso *dsos__findnew_module_dso(struct dsos *dsos, struct machine *machine, struct kmod_path *m, @@ -342,49 +419,44 @@ out_unlock: return dso; } -struct dso *dsos__find_kernel_dso(struct dsos *dsos) +static int dsos__find_kernel_dso_cb(struct dso *dso, void *data) { - struct dso *dso, *res = NULL; + struct dso **res = data; + /* + * The cpumode passed to is_kernel_module is not the cpumode of *this* + * event. If we insist on passing correct cpumode to is_kernel_module, + * we should record the cpumode when we adding this dso to the linked + * list. + * + * However we don't really need passing correct cpumode. We know the + * correct cpumode must be kernel mode (if not, we should not link it + * onto kernel_dsos list). + * + * Therefore, we pass PERF_RECORD_MISC_CPUMODE_UNKNOWN. + * is_kernel_module() treats it as a kernel cpumode. + */ + if (!dso->kernel || + is_kernel_module(dso->long_name, PERF_RECORD_MISC_CPUMODE_UNKNOWN)) + return 0; - down_read(&dsos->lock); - list_for_each_entry(dso, &dsos->head, node) { - /* - * The cpumode passed to is_kernel_module is not the cpumode of - * *this* event. If we insist on passing correct cpumode to - * is_kernel_module, we should record the cpumode when we adding - * this dso to the linked list. - * - * However we don't really need passing correct cpumode. We - * know the correct cpumode must be kernel mode (if not, we - * should not link it onto kernel_dsos list). - * - * Therefore, we pass PERF_RECORD_MISC_CPUMODE_UNKNOWN. - * is_kernel_module() treats it as a kernel cpumode. - */ - if (!dso->kernel || - is_kernel_module(dso->long_name, - PERF_RECORD_MISC_CPUMODE_UNKNOWN)) - continue; + *res = dso__get(dso); + return 1; +} - res = dso__get(dso); - break; - } - up_read(&dsos->lock); +struct dso *dsos__find_kernel_dso(struct dsos *dsos) +{ + struct dso *res = NULL; + + dsos__for_each_dso(dsos, dsos__find_kernel_dso_cb, &res); return res; } int dsos__for_each_dso(struct dsos *dsos, int (*cb)(struct dso *dso, void *data), void *data) { - struct dso *dso; + int err; down_read(&dsos->lock); - list_for_each_entry(dso, &dsos->head, node) { - int err; - - err = cb(dso, data); - if (err) - return err; - } + err = __dsos__for_each_dso(dsos, cb, data); up_read(&dsos->lock); - return 0; + return err; } diff --git a/tools/perf/util/dsos.h b/tools/perf/util/dsos.h index 317a263f0e37..50bd51523475 100644 --- a/tools/perf/util/dsos.h +++ b/tools/perf/util/dsos.h @@ -33,16 +33,16 @@ struct dso *dsos__find(struct dsos *dsos, const char *name, bool cmp_short); struct dso *dsos__findnew_id(struct dsos *dsos, const char *name, struct dso_id *id); -bool __dsos__read_build_ids(struct dsos *dsos, bool with_hits); +bool dsos__read_build_ids(struct dsos *dsos, bool with_hits); struct dso *__dsos__findnew_link_by_longname_id(struct rb_root *root, struct dso *dso, const char *name, struct dso_id *id); -size_t __dsos__fprintf_buildid(struct dsos *dsos, FILE *fp, +size_t dsos__fprintf_buildid(struct dsos *dsos, FILE *fp, bool (skip)(struct dso *dso, int parm), int parm); -size_t __dsos__fprintf(struct dsos *dsos, FILE *fp); +size_t dsos__fprintf(struct dsos *dsos, FILE *fp); -int __dsos__hit_all(struct dsos *dsos); +int dsos__hit_all(struct dsos *dsos); struct dso *dsos__findnew_module_dso(struct dsos *dsos, struct machine *machine, struct kmod_path *m, const char *filename); diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index e3deef38405c..c5c895131bca 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -853,11 +853,11 @@ out: size_t machines__fprintf_dsos(struct machines *machines, FILE *fp) { struct rb_node *nd; - size_t ret = __dsos__fprintf(&machines->host.dsos, fp); + size_t ret = dsos__fprintf(&machines->host.dsos, fp); for (nd = rb_first_cached(&machines->guests); nd; nd = rb_next(nd)) { struct machine *pos = rb_entry(nd, struct machine, rb_node); - ret += __dsos__fprintf(&pos->dsos, fp); + ret += dsos__fprintf(&pos->dsos, fp); } return ret; @@ -866,7 +866,7 @@ size_t machines__fprintf_dsos(struct machines *machines, FILE *fp) size_t machine__fprintf_dsos_buildid(struct machine *m, FILE *fp, bool (skip)(struct dso *dso, int parm), int parm) { - return __dsos__fprintf_buildid(&m->dsos, fp, skip, parm); + return dsos__fprintf_buildid(&m->dsos, fp, skip, parm); } size_t machines__fprintf_dsos_buildid(struct machines *machines, FILE *fp, @@ -3232,5 +3232,5 @@ bool machine__is_lock_function(struct machine *machine, u64 addr) int machine__hit_all_dsos(struct machine *machine) { - return __dsos__hit_all(&machine->dsos); + return dsos__hit_all(&machine->dsos); } -- cgit v1.2.3-59-g8ed1b From b7a791b26409a5853ddd72e85c89214c818ba268 Mon Sep 17 00:00:00 2001 From: Siddharth Vadapalli Date: Mon, 1 Apr 2024 16:39:51 +0530 Subject: dt-bindings: PCI: ti,j721e-pci-host: Add device-id for TI's J784S4 SoC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the device-id of 0xb012 for the PCIe controller on the J784S4 SoC as described in the CTRL_MMR_PCI_DEVICE_ID register's PCI_DEVICE_ID_DEVICE_ID field. The Register descriptions and the Technical Reference Manual for J784S4 SoC can be found at: https://www.ti.com/lit/zip/spruj52 Link: https://lore.kernel.org/linux-pci/20240401110951.3816291-1-s-vadapalli@ti.com Signed-off-by: Siddharth Vadapalli Signed-off-by: Krzysztof Wilczyński Acked-by: Rob Herring --- Documentation/devicetree/bindings/pci/ti,j721e-pci-host.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/pci/ti,j721e-pci-host.yaml b/Documentation/devicetree/bindings/pci/ti,j721e-pci-host.yaml index b7a534cef24d..0b1f21570ed0 100644 --- a/Documentation/devicetree/bindings/pci/ti,j721e-pci-host.yaml +++ b/Documentation/devicetree/bindings/pci/ti,j721e-pci-host.yaml @@ -68,6 +68,7 @@ properties: - 0xb00d - 0xb00f - 0xb010 + - 0xb012 - 0xb013 msi-map: true -- cgit v1.2.3-59-g8ed1b From 78d212851f0e56b7d7083c4d5014aa7fa8b77e20 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 1 Feb 2024 16:52:01 +0100 Subject: dt-bindings: PCI: rcar-pci-host: Add missing IOMMU properties MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit make dtbs_check: arch/arm64/boot/dts/renesas/r8a77951-salvator-xs.dtb: pcie@fe000000: Unevaluated properties are not allowed ('iommu-map', 'iommu-map-mask' were unexpected) from schema $id: http://devicetree.org/schemas/pci/rcar-pci-host.yaml# Fix this by adding the missing IOMMU-related properties. [kwilczynski: added missing Fixes: tag] Fixes: 0d69ce3c2c63 ("dt-bindings: PCI: rcar-pci-host: Convert bindings to json-schema") Link: https://lore.kernel.org/linux-pci/babc878a93cb6461a5d39331f8ecfa654dfda921.1706802597.git.geert+renesas@glider.be Signed-off-by: Geert Uytterhoeven Signed-off-by: Krzysztof Wilczyński Acked-by: Conor Dooley --- Documentation/devicetree/bindings/pci/rcar-pci-host.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/pci/rcar-pci-host.yaml b/Documentation/devicetree/bindings/pci/rcar-pci-host.yaml index b6a7cb32f61e..835b6db00c27 100644 --- a/Documentation/devicetree/bindings/pci/rcar-pci-host.yaml +++ b/Documentation/devicetree/bindings/pci/rcar-pci-host.yaml @@ -77,6 +77,9 @@ properties: vpcie12v-supply: description: The 12v regulator to use for PCIe. + iommu-map: true + iommu-map-mask: true + required: - compatible - reg -- cgit v1.2.3-59-g8ed1b From 01fec70206d48891b76ee8a3a4bfbd331543c18a Mon Sep 17 00:00:00 2001 From: Siddharth Vadapalli Date: Wed, 24 Jan 2024 17:59:36 +0530 Subject: dt-bindings: PCI: ti,j721e-pci-host: Add support for J722S SoC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TI's J722S SoC has one instance of a Gen3 Single-Lane PCIe controller. The controller on J722S SoC is similar to the one present on TI's AM64 SoC, with the difference being that the controller on AM64 SoC supports up to Gen2 link speed while the one on J722S SoC supports Gen3 link speed. Update the bindings with a new compatible for J722S SoC. Technical Reference Manual of J722S SoC: https://www.ti.com/lit/zip/sprujb3 Link: https://lore.kernel.org/linux-pci/20240124122936.816142-1-s-vadapalli@ti.com Signed-off-by: Siddharth Vadapalli Signed-off-by: Krzysztof Wilczyński Acked-by: Conor Dooley --- Documentation/devicetree/bindings/pci/ti,j721e-pci-host.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/devicetree/bindings/pci/ti,j721e-pci-host.yaml b/Documentation/devicetree/bindings/pci/ti,j721e-pci-host.yaml index 0b1f21570ed0..15a2658ceeef 100644 --- a/Documentation/devicetree/bindings/pci/ti,j721e-pci-host.yaml +++ b/Documentation/devicetree/bindings/pci/ti,j721e-pci-host.yaml @@ -23,6 +23,10 @@ properties: items: - const: ti,j7200-pcie-host - const: ti,j721e-pcie-host + - description: PCIe controller in J722S + items: + - const: ti,j722s-pcie-host + - const: ti,j721e-pcie-host reg: maxItems: 4 -- cgit v1.2.3-59-g8ed1b From 20b0027ca1a7ee3b6811f4d67c6015483c6bb456 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Wed, 10 Apr 2024 15:23:53 -0700 Subject: perf list: Escape '\r' in JSON output Events like for sapphirerapids have '\r' in the uncore descriptions. The non-escaped versions of this fail JSON validation the the 'perf list' test. Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ingo Molnar Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20240410222353.1722840-1-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-list.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/perf/builtin-list.c b/tools/perf/builtin-list.c index e0fe3d178d63..5cab31231551 100644 --- a/tools/perf/builtin-list.c +++ b/tools/perf/builtin-list.c @@ -326,6 +326,9 @@ static void fix_escape_fprintf(FILE *fp, struct strbuf *buf, const char *fmt, .. case '\n': strbuf_addstr(buf, "\\n"); break; + case '\r': + strbuf_addstr(buf, "\\r"); + break; case '\\': fallthrough; case '\"': -- cgit v1.2.3-59-g8ed1b From 646e22eb877cdf618a13e7865ff58939b81304ac Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 8 Apr 2024 19:32:13 -0700 Subject: perf build: Add shellcheck to tools/perf scripts Address shell check errors/warnings in perf-archive.sh and perf-completion.sh. Reviewed-by: James Clark Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Athira Rajeev Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kajol Jain Cc: Kan Liang Cc: Mark Rutland Cc: Namhyung Kim Cc: Oliver Upton Cc: Peter Zijlstra Cc: Ravi Bangoria Link: https://lore.kernel.org/r/20240409023216.2342032-2-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Build | 14 ++++++++++++++ tools/perf/perf-archive.sh | 2 +- tools/perf/perf-completion.sh | 23 ++++++++++++++++------- 3 files changed, 31 insertions(+), 8 deletions(-) diff --git a/tools/perf/Build b/tools/perf/Build index aa7623622834..b0cb7ad8e6ac 100644 --- a/tools/perf/Build +++ b/tools/perf/Build @@ -59,3 +59,17 @@ perf-y += ui/ perf-y += scripts/ gtk-y += ui/gtk/ + +ifdef SHELLCHECK + SHELL_TESTS := $(wildcard *.sh) + TEST_LOGS := $(SHELL_TESTS:%=%.shellcheck_log) +else + SHELL_TESTS := + TEST_LOGS := +endif + +$(OUTPUT)%.shellcheck_log: % + $(call rule_mkdir) + $(Q)$(call echo-cmd,test)shellcheck -s bash -a -S warning "$<" > $@ || (cat $@ && rm $@ && false) + +perf-y += $(TEST_LOGS) diff --git a/tools/perf/perf-archive.sh b/tools/perf/perf-archive.sh index f94795794b36..6ed7e52ab881 100755 --- a/tools/perf/perf-archive.sh +++ b/tools/perf/perf-archive.sh @@ -34,7 +34,7 @@ if [ $UNPACK -eq 1 ]; then TARGET=`find . -regex "\./perf.*\.tar\.bz2"` TARGET_NUM=`echo -n "$TARGET" | grep -c '^'` - if [ -z "$TARGET" -o $TARGET_NUM -gt 1 ]; then + if [ -z "$TARGET" ] || [ $TARGET_NUM -gt 1 ]; then echo -e "Error: $TARGET_NUM files found for unpacking:\n$TARGET" echo "Provide the requested file as an argument" exit 1 diff --git a/tools/perf/perf-completion.sh b/tools/perf/perf-completion.sh index f224d79b89e6..69cba3c170d5 100644 --- a/tools/perf/perf-completion.sh +++ b/tools/perf/perf-completion.sh @@ -108,6 +108,8 @@ __perf__ltrim_colon_completions() __perfcomp () { + # Expansion of spaces to array is deliberate. + # shellcheck disable=SC2207 COMPREPLY=( $( compgen -W "$1" -- "$2" ) ) } @@ -127,13 +129,13 @@ __perf_prev_skip_opts () let i=cword-1 cmds_=$($cmd $1 --list-cmds) - prev_skip_opts=() + prev_skip_opts="" while [ $i -ge 0 ]; do - if [[ ${words[i]} == $1 ]]; then + if [[ ${words[i]} == "$1" ]]; then return fi for cmd_ in $cmds_; do - if [[ ${words[i]} == $cmd_ ]]; then + if [[ ${words[i]} == "$cmd_" ]]; then prev_skip_opts=${words[i]} return fi @@ -164,9 +166,10 @@ __perf_main () $prev_skip_opts == @(record|stat|top) ]]; then local cur1=${COMP_WORDS[COMP_CWORD]} - local raw_evts=$($cmd list --raw-dump hw sw cache tracepoint pmu sdt) + local raw_evts local arr s tmp result cpu_evts + raw_evts=$($cmd list --raw-dump hw sw cache tracepoint pmu sdt) # aarch64 doesn't have /sys/bus/event_source/devices/cpu/events if [[ `uname -m` != aarch64 ]]; then cpu_evts=$(ls /sys/bus/event_source/devices/cpu/events) @@ -175,10 +178,12 @@ __perf_main () if [[ "$cur1" == */* && ${cur1#*/} =~ ^[A-Z] ]]; then OLD_IFS="$IFS" IFS=" " + # Expansion of spaces to array is deliberate. + # shellcheck disable=SC2206 arr=($raw_evts) IFS="$OLD_IFS" - for s in ${arr[@]} + for s in "${arr[@]}" do if [[ "$s" == *cpu/* ]]; then tmp=${s#*cpu/} @@ -200,11 +205,13 @@ __perf_main () fi elif [[ $prev == @("--pfm-events") && $prev_skip_opts == @(record|stat|top) ]]; then - local evts=$($cmd list --raw-dump pfm) + local evts + evts=$($cmd list --raw-dump pfm) __perfcomp "$evts" "$cur" elif [[ $prev == @("-M"|"--metrics") && $prev_skip_opts == @(stat) ]]; then - local metrics=$($cmd list --raw-dump metric metricgroup) + local metrics + metrics=$($cmd list --raw-dump metric metricgroup) __perfcomp "$metrics" "$cur" else # List subcommands for perf commands @@ -278,6 +285,8 @@ if [[ -n ${ZSH_VERSION-} ]]; then let cword=CURRENT-1 emulate ksh -c __perf_main let _ret && _default && _ret=0 + # _ret is only assigned 0 or 1, disable inaccurate analysis. + # shellcheck disable=SC2152 return _ret } -- cgit v1.2.3-59-g8ed1b From ec440763bbfc84738d2b38e0d47cb5185d2408b8 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 8 Apr 2024 19:32:14 -0700 Subject: perf arch x86: Add shellcheck to build Add shellcheck for: tools/perf/arch/x86/tests/gen-insn-x86-dat.sh tools/perf/arch/x86/entry/syscalls/syscalltbl.sh Address a minor quoting issue. Reviewed-by: James Clark Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Athira Rajeev Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kajol Jain Cc: Kan Liang Cc: Mark Rutland Cc: Namhyung Kim Cc: Oliver Upton Cc: Peter Zijlstra Cc: Ravi Bangoria Link: https://lore.kernel.org/r/20240409023216.2342032-3-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/arch/x86/Build | 14 ++++++++++++++ tools/perf/arch/x86/tests/Build | 14 ++++++++++++++ tools/perf/arch/x86/tests/gen-insn-x86-dat.sh | 2 +- 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/tools/perf/arch/x86/Build b/tools/perf/arch/x86/Build index a7dd46a5b678..ed37013b4289 100644 --- a/tools/perf/arch/x86/Build +++ b/tools/perf/arch/x86/Build @@ -1,2 +1,16 @@ perf-y += util/ perf-y += tests/ + +ifdef SHELLCHECK + SHELL_TESTS := entry/syscalls/syscalltbl.sh + TEST_LOGS := $(SHELL_TESTS:%=%.shellcheck_log) +else + SHELL_TESTS := + TEST_LOGS := +endif + +$(OUTPUT)%.shellcheck_log: % + $(call rule_mkdir) + $(Q)$(call echo-cmd,test)shellcheck -a -S warning "$<" > $@ || (cat $@ && rm $@ && false) + +perf-y += $(TEST_LOGS) diff --git a/tools/perf/arch/x86/tests/Build b/tools/perf/arch/x86/tests/Build index b87f46e5feea..c1e3b7d39554 100644 --- a/tools/perf/arch/x86/tests/Build +++ b/tools/perf/arch/x86/tests/Build @@ -10,3 +10,17 @@ perf-$(CONFIG_AUXTRACE) += insn-x86.o endif perf-$(CONFIG_X86_64) += bp-modify.o perf-y += amd-ibs-via-core-pmu.o + +ifdef SHELLCHECK + SHELL_TESTS := gen-insn-x86-dat.sh + TEST_LOGS := $(SHELL_TESTS:%=%.shellcheck_log) +else + SHELL_TESTS := + TEST_LOGS := +endif + +$(OUTPUT)%.shellcheck_log: % + $(call rule_mkdir) + $(Q)$(call echo-cmd,test)shellcheck -a -S warning "$<" > $@ || (cat $@ && rm $@ && false) + +perf-y += $(TEST_LOGS) diff --git a/tools/perf/arch/x86/tests/gen-insn-x86-dat.sh b/tools/perf/arch/x86/tests/gen-insn-x86-dat.sh index 0d0a003a9c5e..89c46532cd5c 100755 --- a/tools/perf/arch/x86/tests/gen-insn-x86-dat.sh +++ b/tools/perf/arch/x86/tests/gen-insn-x86-dat.sh @@ -11,7 +11,7 @@ if [ "$(uname -m)" != "x86_64" ]; then exit 1 fi -cd $(dirname $0) +cd "$(dirname $0)" trap 'echo "Might need a more recent version of binutils"' EXIT -- cgit v1.2.3-59-g8ed1b From 61ff60aab7d6846a5983804d96a316b22aacefa1 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 8 Apr 2024 19:32:15 -0700 Subject: perf util: Add shellcheck to generate-cmdlist.sh Add shellcheck to generate-cmdlist.sh to avoid basic shell script mistakes. Reviewed-by: James Clark Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Athira Rajeev Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kajol Jain Cc: Kan Liang Cc: Mark Rutland Cc: Namhyung Kim Cc: Oliver Upton Cc: Peter Zijlstra Cc: Ravi Bangoria Link: https://lore.kernel.org/r/20240409023216.2342032-4-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/Build | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tools/perf/util/Build b/tools/perf/util/Build index aec5a590e349..292170a99ab6 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -389,3 +389,17 @@ $(OUTPUT)util/vsprintf.o: ../lib/vsprintf.c FORCE $(OUTPUT)util/list_sort.o: ../lib/list_sort.c FORCE $(call rule_mkdir) $(call if_changed_dep,cc_o_c) + +ifdef SHELLCHECK + SHELL_TESTS := generate-cmdlist.sh + TEST_LOGS := $(SHELL_TESTS:%=%.shellcheck_log) +else + SHELL_TESTS := + TEST_LOGS := +endif + +$(OUTPUT)%.shellcheck_log: % + $(call rule_mkdir) + $(Q)$(call echo-cmd,test)shellcheck -a -S warning "$<" > $@ || (cat $@ && rm $@ && false) + +perf-y += $(TEST_LOGS) -- cgit v1.2.3-59-g8ed1b From 2b8c43e7688fa61b842ea2b21d4159c67d6f2fd1 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 8 Apr 2024 19:32:16 -0700 Subject: perf trace beauty: Add shellcheck to scripts Add shell check to scripts generating perf trace lookup tables. Fix quoting issue in arch_errno_names.sh. Reviewed-by: James Clark Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Athira Rajeev Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kajol Jain Cc: Kan Liang Cc: Mark Rutland Cc: Namhyung Kim Cc: Oliver Upton Cc: Peter Zijlstra Cc: Ravi Bangoria Link: https://lore.kernel.org/r/20240409023216.2342032-5-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/trace/beauty/Build | 14 ++++++++++++++ tools/perf/trace/beauty/arch_errno_names.sh | 8 +++++--- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/tools/perf/trace/beauty/Build b/tools/perf/trace/beauty/Build index d8ce1b698983..cb3c1399ff40 100644 --- a/tools/perf/trace/beauty/Build +++ b/tools/perf/trace/beauty/Build @@ -20,3 +20,17 @@ perf-y += statx.o perf-y += sync_file_range.o perf-y += timespec.o perf-y += tracepoints/ + +ifdef SHELLCHECK + SHELL_TESTS := $(wildcard trace/beauty/*.sh) + TEST_LOGS := $(SHELL_TESTS:trace/beauty/%=%.shellcheck_log) +else + SHELL_TESTS := + TEST_LOGS := +endif + +$(OUTPUT)%.shellcheck_log: % + $(call rule_mkdir) + $(Q)$(call echo-cmd,test)shellcheck -s bash -a -S warning "$<" > $@ || (cat $@ && rm $@ && false) + +perf-y += $(TEST_LOGS) diff --git a/tools/perf/trace/beauty/arch_errno_names.sh b/tools/perf/trace/beauty/arch_errno_names.sh index 7df4bf5b55a3..30d3889b2957 100755 --- a/tools/perf/trace/beauty/arch_errno_names.sh +++ b/tools/perf/trace/beauty/arch_errno_names.sh @@ -60,10 +60,12 @@ create_arch_errno_table_func() printf 'arch_syscalls__strerrno_t *arch_syscalls__strerrno_function(const char *arch)\n' printf '{\n' for arch in $archlist; do - printf '\tif (!strcmp(arch, "%s"))\n' $(arch_string "$arch") - printf '\t\treturn errno_to_name__%s;\n' $(arch_string "$arch") + arch_str=$(arch_string "$arch") + printf '\tif (!strcmp(arch, "%s"))\n' "$arch_str" + printf '\t\treturn errno_to_name__%s;\n' "$arch_str" done - printf '\treturn errno_to_name__%s;\n' $(arch_string "$default") + arch_str=$(arch_string "$default") + printf '\treturn errno_to_name__%s;\n' "$arch_str" printf '}\n' } -- cgit v1.2.3-59-g8ed1b From 459fee7b508231cd4622b3bd94aaa85e8e16b888 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Fri, 5 Apr 2024 21:09:10 -0700 Subject: perf bench uprobe: Remove lib64 from libc.so.6 binary path bpf_program__attach_uprobe_opts will search LD_LIBRARY_PATH and so specifying `/lib64` is unnecessary and causes failures for libc.so.6 paths like `/lib/x86_64-linux-gnu/libc.so.6`. Fixes: 7b47623b8cae8149 ("perf bench uprobe trace_printk: Add entry attaching an BPF program that does a trace_printk") Signed-off-by: Ian Rogers Acked-by: Jiri Olsa Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andrei Vagin Cc: Ingo Molnar Cc: Kan Liang Cc: Kees Kook Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20240406040911.1603801-1-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/bench/uprobe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/bench/uprobe.c b/tools/perf/bench/uprobe.c index 5c71fdc419dd..b722ff88fe7d 100644 --- a/tools/perf/bench/uprobe.c +++ b/tools/perf/bench/uprobe.c @@ -47,7 +47,7 @@ static const char * const bench_uprobe_usage[] = { #define bench_uprobe__attach_uprobe(prog) \ skel->links.prog = bpf_program__attach_uprobe_opts(/*prog=*/skel->progs.prog, \ /*pid=*/-1, \ - /*binary_path=*/"/lib64/libc.so.6", \ + /*binary_path=*/"libc.so.6", \ /*func_offset=*/0, \ /*opts=*/&uprobe_opts); \ if (!skel->links.prog) { \ -- cgit v1.2.3-59-g8ed1b From 988052f4bfcc4ee893ea19e9d9ce888cc8578e5a Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Fri, 5 Apr 2024 21:09:11 -0700 Subject: perf bench uprobe: Add uretprobe variant of uprobe benchmarks Name benchmarks with _ret at the end to avoid creating a new set of benchmarks. Signed-off-by: Ian Rogers Acked-by: Jiri Olsa Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andrei Vagin Cc: Ingo Molnar Cc: Kan Liang Cc: Kees Kook Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20240406040911.1603801-2-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/bench/bench.h | 2 ++ tools/perf/bench/uprobe.c | 20 +++++++++++++++++--- tools/perf/builtin-bench.c | 2 ++ tools/perf/util/bpf_skel/bench_uprobe.bpf.c | 16 ++++++++++++++++ 4 files changed, 37 insertions(+), 3 deletions(-) diff --git a/tools/perf/bench/bench.h b/tools/perf/bench/bench.h index faa18e6d2467..9f736423af53 100644 --- a/tools/perf/bench/bench.h +++ b/tools/perf/bench/bench.h @@ -46,6 +46,8 @@ int bench_breakpoint_enable(int argc, const char **argv); int bench_uprobe_baseline(int argc, const char **argv); int bench_uprobe_empty(int argc, const char **argv); int bench_uprobe_trace_printk(int argc, const char **argv); +int bench_uprobe_empty_ret(int argc, const char **argv); +int bench_uprobe_trace_printk_ret(int argc, const char **argv); int bench_pmu_scan(int argc, const char **argv); #define BENCH_FORMAT_DEFAULT_STR "default" diff --git a/tools/perf/bench/uprobe.c b/tools/perf/bench/uprobe.c index b722ff88fe7d..0b90275862e1 100644 --- a/tools/perf/bench/uprobe.c +++ b/tools/perf/bench/uprobe.c @@ -26,9 +26,11 @@ static int loops = LOOPS_DEFAULT; enum bench_uprobe { - BENCH_UPROBE__BASELINE, - BENCH_UPROBE__EMPTY, - BENCH_UPROBE__TRACE_PRINTK, + BENCH_UPROBE__BASELINE, + BENCH_UPROBE__EMPTY, + BENCH_UPROBE__TRACE_PRINTK, + BENCH_UPROBE__EMPTY_RET, + BENCH_UPROBE__TRACE_PRINTK_RET, }; static const struct option options[] = { @@ -81,6 +83,8 @@ static int bench_uprobe__setup_bpf_skel(enum bench_uprobe bench) case BENCH_UPROBE__BASELINE: break; case BENCH_UPROBE__EMPTY: bench_uprobe__attach_uprobe(empty); break; case BENCH_UPROBE__TRACE_PRINTK: bench_uprobe__attach_uprobe(trace_printk); break; + case BENCH_UPROBE__EMPTY_RET: bench_uprobe__attach_uprobe(empty_ret); break; + case BENCH_UPROBE__TRACE_PRINTK_RET: bench_uprobe__attach_uprobe(trace_printk_ret); break; default: fprintf(stderr, "Invalid bench: %d\n", bench); goto cleanup; @@ -197,3 +201,13 @@ int bench_uprobe_trace_printk(int argc, const char **argv) { return bench_uprobe(argc, argv, BENCH_UPROBE__TRACE_PRINTK); } + +int bench_uprobe_empty_ret(int argc, const char **argv) +{ + return bench_uprobe(argc, argv, BENCH_UPROBE__EMPTY_RET); +} + +int bench_uprobe_trace_printk_ret(int argc, const char **argv) +{ + return bench_uprobe(argc, argv, BENCH_UPROBE__TRACE_PRINTK_RET); +} diff --git a/tools/perf/builtin-bench.c b/tools/perf/builtin-bench.c index 1a8898d5b560..2c1a9f3d847a 100644 --- a/tools/perf/builtin-bench.c +++ b/tools/perf/builtin-bench.c @@ -109,6 +109,8 @@ static struct bench uprobe_benchmarks[] = { { "baseline", "Baseline libc usleep(1000) call", bench_uprobe_baseline, }, { "empty", "Attach empty BPF prog to uprobe on usleep, system wide", bench_uprobe_empty, }, { "trace_printk", "Attach trace_printk BPF prog to uprobe on usleep syswide", bench_uprobe_trace_printk, }, + { "empty_ret", "Attach empty BPF prog to uretprobe on usleep, system wide", bench_uprobe_empty_ret, }, + { "trace_printk_ret", "Attach trace_printk BPF prog to uretprobe on usleep syswide", bench_uprobe_trace_printk_ret,}, { NULL, NULL, NULL }, }; diff --git a/tools/perf/util/bpf_skel/bench_uprobe.bpf.c b/tools/perf/util/bpf_skel/bench_uprobe.bpf.c index 2c55896bb33c..a01c7f791fcd 100644 --- a/tools/perf/util/bpf_skel/bench_uprobe.bpf.c +++ b/tools/perf/util/bpf_skel/bench_uprobe.bpf.c @@ -4,6 +4,7 @@ #include unsigned int nr_uprobes; +unsigned int nr_uretprobes; SEC("uprobe") int BPF_UPROBE(empty) @@ -20,4 +21,19 @@ int BPF_UPROBE(trace_printk) return 0; } +SEC("uretprobe") +int BPF_URETPROBE(empty_ret) +{ + return 0; +} + +SEC("uretprobe") +int BPF_URETPROBE(trace_printk_ret) +{ + char fmt[] = "perf bench uretprobe %u"; + + bpf_trace_printk(fmt, sizeof(fmt), ++nr_uretprobes); + return 0; +} + char LICENSE[] SEC("license") = "Dual BSD/GPL"; -- cgit v1.2.3-59-g8ed1b From 46492d10067660785a09db4ce9244545126a17b8 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Fri, 12 Apr 2024 14:58:15 +0200 Subject: dt-bindings: phy: rockchip,pcie3-phy: add rockchip,rx-common-refclk-mode >From the RK3588 Technical Reference Manual, Part1, section 6.19 PCIe3PHY_GRF Register Description: "rxX_cmn_refclk_mode" RX common reference clock mode for lane X. This mode should be enabled only when the far-end and near-end devices are running with a common reference clock. The hardware reset value for this field is 0x1 (enabled). Note that this register field is only available on RK3588, not on RK3568. The link training either fails or is highly unstable (link state will jump continuously between L0 and recovery) when this mode is enabled while using an endpoint running in Separate Reference Clock with No SSC (SRNS) mode or Separate Reference Clock with SSC (SRIS) mode. (Which is usually the case when using a real SoC as endpoint, e.g. the RK3588 PCIe controller can run in both Root Complex and Endpoint mode.) Add a rockchip specific property to enable/disable the rxX_cmn_refclk_mode per lane. (Since this PHY supports bifurcation.) Signed-off-by: Niklas Cassel Acked-by: Krzysztof Kozlowski Reviewed-by: Sebastian Reichel Link: https://lore.kernel.org/r/20240412125818.17052-2-cassel@kernel.org Signed-off-by: Vinod Koul --- Documentation/devicetree/bindings/phy/rockchip,pcie3-phy.yaml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Documentation/devicetree/bindings/phy/rockchip,pcie3-phy.yaml b/Documentation/devicetree/bindings/phy/rockchip,pcie3-phy.yaml index c4fbffcde6e4..ba67dca5a446 100644 --- a/Documentation/devicetree/bindings/phy/rockchip,pcie3-phy.yaml +++ b/Documentation/devicetree/bindings/phy/rockchip,pcie3-phy.yaml @@ -54,6 +54,16 @@ properties: $ref: /schemas/types.yaml#/definitions/phandle description: phandle to the syscon managing the pipe "general register files" + rockchip,rx-common-refclk-mode: + description: which lanes (by position) should be configured to run in + RX common reference clock mode. 0 means disabled, 1 means enabled. + $ref: /schemas/types.yaml#/definitions/uint32-array + minItems: 1 + maxItems: 16 + items: + minimum: 0 + maximum: 1 + required: - compatible - reg -- cgit v1.2.3-59-g8ed1b From a1fe1eca0d8be69ccc1f3d615e5a529df1c82e66 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Fri, 12 Apr 2024 14:58:16 +0200 Subject: phy: rockchip-snps-pcie3: add support for rockchip,rx-common-refclk-mode >From the RK3588 Technical Reference Manual, Part1, section 6.19 PCIe3PHY_GRF Register Description: "rxX_cmn_refclk_mode" RX common reference clock mode for lane X. This mode should be enabled only when the far-end and near-end devices are running with a common reference clock. The hardware reset value for this field is 0x1 (enabled). Note that this register field is only available on RK3588, not on RK3568. The link training either fails or is highly unstable (link state will jump continuously between L0 and recovery) when this mode is enabled while using an endpoint running in Separate Reference Clock with No SSC (SRNS) mode or Separate Reference Clock with SSC (SRIS) mode. (Which is usually the case when using a real SoC as endpoint, e.g. the RK3588 PCIe controller can run in both Root Complex and Endpoint mode.) Add support for the device tree property rockchip,rx-common-refclk-mode, such that the PCIe PHY can be used in configurations where the Root Complex and Endpoint are not using a common reference clock. Signed-off-by: Niklas Cassel Link: https://lore.kernel.org/r/20240412125818.17052-3-cassel@kernel.org Signed-off-by: Vinod Koul --- drivers/phy/rockchip/phy-rockchip-snps-pcie3.c | 37 ++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/drivers/phy/rockchip/phy-rockchip-snps-pcie3.c b/drivers/phy/rockchip/phy-rockchip-snps-pcie3.c index dcccee3c211c..4e8ffd173096 100644 --- a/drivers/phy/rockchip/phy-rockchip-snps-pcie3.c +++ b/drivers/phy/rockchip/phy-rockchip-snps-pcie3.c @@ -35,11 +35,17 @@ #define RK3588_PCIE3PHY_GRF_CMN_CON0 0x0 #define RK3588_PCIE3PHY_GRF_PHY0_STATUS1 0x904 #define RK3588_PCIE3PHY_GRF_PHY1_STATUS1 0xa04 +#define RK3588_PCIE3PHY_GRF_PHY0_LN0_CON1 0x1004 +#define RK3588_PCIE3PHY_GRF_PHY0_LN1_CON1 0x1104 +#define RK3588_PCIE3PHY_GRF_PHY1_LN0_CON1 0x2004 +#define RK3588_PCIE3PHY_GRF_PHY1_LN1_CON1 0x2104 #define RK3588_SRAM_INIT_DONE(reg) (reg & BIT(0)) #define RK3588_BIFURCATION_LANE_0_1 BIT(0) #define RK3588_BIFURCATION_LANE_2_3 BIT(1) #define RK3588_LANE_AGGREGATION BIT(2) +#define RK3588_RX_CMN_REFCLK_MODE_EN ((BIT(7) << 16) | BIT(7)) +#define RK3588_RX_CMN_REFCLK_MODE_DIS (BIT(7) << 16) #define RK3588_PCIE1LN_SEL_EN (GENMASK(1, 0) << 16) #define RK3588_PCIE30_PHY_MODE_EN (GENMASK(2, 0) << 16) @@ -60,6 +66,7 @@ struct rockchip_p3phy_priv { int num_clks; int num_lanes; u32 lanes[4]; + u32 rx_cmn_refclk_mode[4]; }; struct rockchip_p3phy_ops { @@ -137,6 +144,19 @@ static int rockchip_p3phy_rk3588_init(struct rockchip_p3phy_priv *priv) u8 mode = RK3588_LANE_AGGREGATION; /* default */ int ret; + regmap_write(priv->phy_grf, RK3588_PCIE3PHY_GRF_PHY0_LN0_CON1, + priv->rx_cmn_refclk_mode[0] ? RK3588_RX_CMN_REFCLK_MODE_EN : + RK3588_RX_CMN_REFCLK_MODE_DIS); + regmap_write(priv->phy_grf, RK3588_PCIE3PHY_GRF_PHY0_LN1_CON1, + priv->rx_cmn_refclk_mode[1] ? RK3588_RX_CMN_REFCLK_MODE_EN : + RK3588_RX_CMN_REFCLK_MODE_DIS); + regmap_write(priv->phy_grf, RK3588_PCIE3PHY_GRF_PHY1_LN0_CON1, + priv->rx_cmn_refclk_mode[2] ? RK3588_RX_CMN_REFCLK_MODE_EN : + RK3588_RX_CMN_REFCLK_MODE_DIS); + regmap_write(priv->phy_grf, RK3588_PCIE3PHY_GRF_PHY1_LN1_CON1, + priv->rx_cmn_refclk_mode[3] ? RK3588_RX_CMN_REFCLK_MODE_EN : + RK3588_RX_CMN_REFCLK_MODE_DIS); + /* Deassert PCIe PMA output clamp mode */ regmap_write(priv->phy_grf, RK3588_PCIE3PHY_GRF_CMN_CON0, BIT(8) | BIT(24)); @@ -275,6 +295,23 @@ static int rockchip_p3phy_probe(struct platform_device *pdev) return priv->num_lanes; } + ret = of_property_read_variable_u32_array(dev->of_node, + "rockchip,rx-common-refclk-mode", + priv->rx_cmn_refclk_mode, 1, + ARRAY_SIZE(priv->rx_cmn_refclk_mode)); + /* + * if no rockchip,rx-common-refclk-mode, assume enabled for all lanes in + * order to be DT backwards compatible. (Since HW reset val is enabled.) + */ + if (ret == -EINVAL) { + for (int i = 0; i < ARRAY_SIZE(priv->rx_cmn_refclk_mode); i++) + priv->rx_cmn_refclk_mode[i] = 1; + } else if (ret < 0) { + dev_err(dev, "failed to read rockchip,rx-common-refclk-mode property %d\n", + ret); + return ret; + } + priv->phy = devm_phy_create(dev, NULL, &rockchip_p3phy_ops); if (IS_ERR(priv->phy)) { dev_err(dev, "failed to create combphy\n"); -- cgit v1.2.3-59-g8ed1b From 3735ca0b072656c3aa2cedc617a5e639b583a472 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 30 Mar 2024 18:53:00 +0000 Subject: iio: adc: stm32: Fixing err code to not indicate success This path would result in returning 0 / success on an error path. Cc: Olivier Moysan Fixes: 95bc818404b2 ("iio: adc: stm32-adc: add support of generic channels binding") Reviewed-by: Fabrice Gasnier Link: https://lore.kernel.org/r/20240330185305.1319844-4-jic23@kernel.org Signed-off-by: Jonathan Cameron --- drivers/iio/adc/stm32-adc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c index b5d3c9cea5c4..283c20757106 100644 --- a/drivers/iio/adc/stm32-adc.c +++ b/drivers/iio/adc/stm32-adc.c @@ -2234,6 +2234,7 @@ static int stm32_adc_generic_chan_init(struct iio_dev *indio_dev, if (vin[0] != val || vin[1] >= adc_info->max_channels) { dev_err(&indio_dev->dev, "Invalid channel in%d-in%d\n", vin[0], vin[1]); + ret = -EINVAL; goto err; } } else if (ret != -EINVAL) { -- cgit v1.2.3-59-g8ed1b From 24622259e3a8f7df1972aafd801b888443e44363 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 30 Mar 2024 18:53:01 +0000 Subject: iio: adc: stm32: Use device_for_each_child_node_scoped() Switching to the _scoped() version removes the need for manual calling of fwnode_handle_put() in the paths where the code exits the loop early. In this case that's all in error paths. Note this would have made the bug fixed in the previous path much less likely as it allows for direct returns. Took advantage of dev_err_probe() to futher simplify things given no longer a need for the goto err. Cc: Olivier Moysan Tested-by: Fabrice Gasnier Acked-by: Fabrice Gasnier Link: https://lore.kernel.org/r/20240330185305.1319844-5-jic23@kernel.org Signed-off-by: Jonathan Cameron --- drivers/iio/adc/stm32-adc.c | 62 ++++++++++++++++++--------------------------- 1 file changed, 24 insertions(+), 38 deletions(-) diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c index 283c20757106..36add95212c3 100644 --- a/drivers/iio/adc/stm32-adc.c +++ b/drivers/iio/adc/stm32-adc.c @@ -2187,59 +2187,52 @@ static int stm32_adc_generic_chan_init(struct iio_dev *indio_dev, struct iio_chan_spec *channels) { const struct stm32_adc_info *adc_info = adc->cfg->adc_info; - struct fwnode_handle *child; + struct device *dev = &indio_dev->dev; const char *name; int val, scan_index = 0, ret; bool differential; u32 vin[2]; - device_for_each_child_node(&indio_dev->dev, child) { + device_for_each_child_node_scoped(dev, child) { ret = fwnode_property_read_u32(child, "reg", &val); - if (ret) { - dev_err(&indio_dev->dev, "Missing channel index %d\n", ret); - goto err; - } + if (ret) + return dev_err_probe(dev, ret, + "Missing channel index\n"); ret = fwnode_property_read_string(child, "label", &name); /* label is optional */ if (!ret) { - if (strlen(name) >= STM32_ADC_CH_SZ) { - dev_err(&indio_dev->dev, "Label %s exceeds %d characters\n", - name, STM32_ADC_CH_SZ); - ret = -EINVAL; - goto err; - } + if (strlen(name) >= STM32_ADC_CH_SZ) + return dev_err_probe(dev, -EINVAL, + "Label %s exceeds %d characters\n", + name, STM32_ADC_CH_SZ); + strscpy(adc->chan_name[val], name, STM32_ADC_CH_SZ); ret = stm32_adc_populate_int_ch(indio_dev, name, val); if (ret == -ENOENT) continue; else if (ret) - goto err; + return ret; } else if (ret != -EINVAL) { - dev_err(&indio_dev->dev, "Invalid label %d\n", ret); - goto err; + return dev_err_probe(dev, ret, "Invalid label\n"); } - if (val >= adc_info->max_channels) { - dev_err(&indio_dev->dev, "Invalid channel %d\n", val); - ret = -EINVAL; - goto err; - } + if (val >= adc_info->max_channels) + return dev_err_probe(dev, -EINVAL, + "Invalid channel %d\n", val); differential = false; ret = fwnode_property_read_u32_array(child, "diff-channels", vin, 2); /* diff-channels is optional */ if (!ret) { differential = true; - if (vin[0] != val || vin[1] >= adc_info->max_channels) { - dev_err(&indio_dev->dev, "Invalid channel in%d-in%d\n", - vin[0], vin[1]); - ret = -EINVAL; - goto err; - } + if (vin[0] != val || vin[1] >= adc_info->max_channels) + return dev_err_probe(dev, -EINVAL, + "Invalid channel in%d-in%d\n", + vin[0], vin[1]); } else if (ret != -EINVAL) { - dev_err(&indio_dev->dev, "Invalid diff-channels property %d\n", ret); - goto err; + return dev_err_probe(dev, ret, + "Invalid diff-channels property\n"); } stm32_adc_chan_init_one(indio_dev, &channels[scan_index], val, @@ -2248,11 +2241,9 @@ static int stm32_adc_generic_chan_init(struct iio_dev *indio_dev, val = 0; ret = fwnode_property_read_u32(child, "st,min-sample-time-ns", &val); /* st,min-sample-time-ns is optional */ - if (ret && ret != -EINVAL) { - dev_err(&indio_dev->dev, "Invalid st,min-sample-time-ns property %d\n", - ret); - goto err; - } + if (ret && ret != -EINVAL) + return dev_err_probe(dev, ret, + "Invalid st,min-sample-time-ns property\n"); stm32_adc_smpr_init(adc, channels[scan_index].channel, val); if (differential) @@ -2262,11 +2253,6 @@ static int stm32_adc_generic_chan_init(struct iio_dev *indio_dev, } return scan_index; - -err: - fwnode_handle_put(child); - - return ret; } static int stm32_adc_chan_fw_init(struct iio_dev *indio_dev, bool timestamping) -- cgit v1.2.3-59-g8ed1b From 77dc3b173d7258329e22ad8d8407bd5f8fe97fd1 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 30 Mar 2024 18:52:59 +0000 Subject: iio: adc: qcom-spmi-adc5: Use device_for_each_child_node_scoped() Switching to the _scoped() version removes the need for manual calling of fwnode_handle_put() in the paths where the code exits the loop early. In this case that's all in error paths. A slightly less convincing usecase than many as all the failure paths are wrapped up in a call to a per fwnode_handle utility function. The complexity in that function is sufficient that it makes sense to factor it out even if it this new auto cleanup would enable simpler returns if the code was inline at the call site. Hence I've left it alone. Cc: Marijn Suijten Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20240330185305.1319844-3-jic23@kernel.org Signed-off-by: Jonathan Cameron --- drivers/iio/adc/qcom-spmi-adc5.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/iio/adc/qcom-spmi-adc5.c b/drivers/iio/adc/qcom-spmi-adc5.c index b6b612d733ff..9b69f40beed8 100644 --- a/drivers/iio/adc/qcom-spmi-adc5.c +++ b/drivers/iio/adc/qcom-spmi-adc5.c @@ -825,7 +825,6 @@ static int adc5_get_fw_data(struct adc5_chip *adc) const struct adc5_channels *adc_chan; struct iio_chan_spec *iio_chan; struct adc5_channel_prop prop, *chan_props; - struct fwnode_handle *child; unsigned int index = 0; int ret; @@ -849,12 +848,10 @@ static int adc5_get_fw_data(struct adc5_chip *adc) if (!adc->data) adc->data = &adc5_data_pmic; - device_for_each_child_node(adc->dev, child) { + device_for_each_child_node_scoped(adc->dev, child) { ret = adc5_get_fw_channel_data(adc, &prop, child, adc->data); - if (ret) { - fwnode_handle_put(child); + if (ret) return ret; - } prop.scale_fn_type = adc->data->adc_chans[prop.channel].scale_fn_type; -- cgit v1.2.3-59-g8ed1b From 4b9f86214c054ea2da2917f6c107b34f7076c181 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Fri, 8 Mar 2024 09:51:05 +0100 Subject: cdx: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Acked-by: Nipun Gupta Link: https://lore.kernel.org/r/5d40f57e978bcce003133306712ec96439e93595.1709886922.git.u.kleine-koenig@pengutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/cdx/controller/cdx_controller.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/cdx/controller/cdx_controller.c b/drivers/cdx/controller/cdx_controller.c index 112a1541de6d..201f9a6fbde7 100644 --- a/drivers/cdx/controller/cdx_controller.c +++ b/drivers/cdx/controller/cdx_controller.c @@ -222,7 +222,7 @@ mcdi_init_fail: return ret; } -static int xlnx_cdx_remove(struct platform_device *pdev) +static void xlnx_cdx_remove(struct platform_device *pdev) { struct cdx_controller *cdx = platform_get_drvdata(pdev); struct cdx_mcdi *cdx_mcdi = cdx->priv; @@ -234,8 +234,6 @@ static int xlnx_cdx_remove(struct platform_device *pdev) cdx_mcdi_finish(cdx_mcdi); kfree(cdx_mcdi); - - return 0; } static const struct of_device_id cdx_match_table[] = { @@ -252,7 +250,7 @@ static struct platform_driver cdx_pdriver = { .of_match_table = cdx_match_table, }, .probe = xlnx_cdx_probe, - .remove = xlnx_cdx_remove, + .remove_new = xlnx_cdx_remove, }; static int __init cdx_controller_init(void) -- cgit v1.2.3-59-g8ed1b From b20172ca6bf489534892b801a5db41bbf5ceec75 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Sat, 13 Apr 2024 13:33:41 +0300 Subject: serial: core: Fix ifdef for serial base console functions If CONFIG_SERIAL_CORE_CONSOLE is not set, we get build errors. Let's fix the issue by moving the endif after the serial base console functions. Fixes: 4547cd76f08a ("serial: 8250: Fix add preferred console for serial8250_isa_init_ports()") Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202404131416.VJljwvkS-lkp@intel.com/ Signed-off-by: Tony Lindgren Link: https://lore.kernel.org/r/20240413103343.24231-1-tony@atomide.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_base_bus.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/tty/serial/serial_base_bus.c b/drivers/tty/serial/serial_base_bus.c index 281a2d5a7332..73c6ee540c83 100644 --- a/drivers/tty/serial/serial_base_bus.c +++ b/drivers/tty/serial/serial_base_bus.c @@ -219,8 +219,6 @@ static int serial_base_add_one_prefcon(const char *match, const char *dev_name, return ret; } -#endif - #ifdef __sparc__ /* Handle Sparc ttya and ttyb options as done in console_setup() */ @@ -319,6 +317,8 @@ int serial_base_add_preferred_console(struct uart_driver *drv, return serial_base_add_one_prefcon(port_match, drv->dev_name, port->line); } +#endif + #ifdef CONFIG_SERIAL_8250_CONSOLE /* -- cgit v1.2.3-59-g8ed1b From d9dd38cb59fb828a428084128569e684dd51cbe9 Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Mon, 8 Apr 2024 18:34:33 +0200 Subject: dt-bindings: iio: imu: mpu6050: Improve i2c-gate disallow list Before all supported sensors except for MPU{9150,9250,9255} were not allowed to use i2c-gate in the bindings which excluded quite a few supported sensors where this functionality is supported. Switch the list of sensors to ones where the Linux driver explicitly disallows support for the auxiliary bus ("inv_mpu_i2c_aux_bus"). Since the driver is also based on "default: return true" this should scale better into the future. Signed-off-by: Luca Weiss Acked-by: Jean-Baptiste Maneyrol Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240408-mpu6050-i2c-gate-v1-1-621f051ce7de@z3ntu.xyz Signed-off-by: Jonathan Cameron --- .../devicetree/bindings/iio/imu/invensense,mpu6050.yaml | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/Documentation/devicetree/bindings/iio/imu/invensense,mpu6050.yaml b/Documentation/devicetree/bindings/iio/imu/invensense,mpu6050.yaml index 297b8a1a7ffb..587ff2bced2d 100644 --- a/Documentation/devicetree/bindings/iio/imu/invensense,mpu6050.yaml +++ b/Documentation/devicetree/bindings/iio/imu/invensense,mpu6050.yaml @@ -62,14 +62,15 @@ properties: allOf: - $ref: /schemas/spi/spi-peripheral-props.yaml# - if: - not: - properties: - compatible: - contains: - enum: - - invensense,mpu9150 - - invensense,mpu9250 - - invensense,mpu9255 + properties: + compatible: + contains: + enum: + - invensense,iam20680 + - invensense,icm20602 + - invensense,icm20608 + - invensense,icm20609 + - invensense,icm20689 then: properties: i2c-gate: false -- cgit v1.2.3-59-g8ed1b From 61c8031af674bb80a7e346368ea0a41632e1f5fc Mon Sep 17 00:00:00 2001 From: David Lechner Date: Fri, 12 Apr 2024 18:25:02 -0500 Subject: iio: adc: ad7944: Consolidate spi_sync() wrapper Since commit 6020ca4de8e5 ("iio: adc: ad7944: use spi_optimize_message()"), The helper functions wrapping spi_sync() for 3-wire and 4-wire modes are virtually identical. Since gpiod_set_value_cansleep() does a NULL check internally, we can consolidate the two functions into one and avoid switch statements at the call sites. The default cases of the removed switch statement were just to make the compiler happy and are not reachable since the mode is validated in the probe function. So removing those should be safe. Signed-off-by: David Lechner Link: https://lore.kernel.org/r/20240412-ad7944-consolidate-msg-v1-1-7fdeff89172f@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7944.c | 67 ++++++++++-------------------------------------- 1 file changed, 13 insertions(+), 54 deletions(-) diff --git a/drivers/iio/adc/ad7944.c b/drivers/iio/adc/ad7944.c index 9dc86ec23c36..4af574ffa864 100644 --- a/drivers/iio/adc/ad7944.c +++ b/drivers/iio/adc/ad7944.c @@ -214,40 +214,26 @@ static int ad7944_4wire_mode_init_msg(struct device *dev, struct ad7944_adc *adc return devm_add_action_or_reset(dev, ad7944_unoptimize_msg, &adc->msg); } -/* - * ad7944_3wire_cs_mode_conversion - Perform a 3-wire CS mode conversion and - * acquisition +/** + * ad7944_convert_and_acquire - Perform a single conversion and acquisition * @adc: The ADC device structure * @chan: The channel specification * Return: 0 on success, a negative error code on failure * - * This performs a conversion and reads data when the chip is wired in 3-wire - * mode with the CNV line on the ADC tied to the CS line on the SPI controller. - * - * Upon successful return adc->sample.raw will contain the conversion result. - */ -static int ad7944_3wire_cs_mode_conversion(struct ad7944_adc *adc, - const struct iio_chan_spec *chan) -{ - return spi_sync(adc->spi, &adc->msg); -} - -/* - * ad7944_4wire_mode_conversion - Perform a 4-wire mode conversion and acquisition - * @adc: The ADC device structure - * @chan: The channel specification - * Return: 0 on success, a negative error code on failure + * Perform a conversion and acquisition of a single sample using the + * pre-optimized adc->msg. * * Upon successful return adc->sample.raw will contain the conversion result. */ -static int ad7944_4wire_mode_conversion(struct ad7944_adc *adc, - const struct iio_chan_spec *chan) +static int ad7944_convert_and_acquire(struct ad7944_adc *adc, + const struct iio_chan_spec *chan) { int ret; /* * In 4-wire mode, the CNV line is held high for the entire conversion - * and acquisition process. + * and acquisition process. In other modes adc->cnv is NULL and is + * ignored (CS is wired to CNV in those cases). */ gpiod_set_value_cansleep(adc->cnv, 1); ret = spi_sync(adc->spi, &adc->msg); @@ -262,22 +248,9 @@ static int ad7944_single_conversion(struct ad7944_adc *adc, { int ret; - switch (adc->spi_mode) { - case AD7944_SPI_MODE_DEFAULT: - ret = ad7944_4wire_mode_conversion(adc, chan); - if (ret) - return ret; - - break; - case AD7944_SPI_MODE_SINGLE: - ret = ad7944_3wire_cs_mode_conversion(adc, chan); - if (ret) - return ret; - - break; - default: - return -EOPNOTSUPP; - } + ret = ad7944_convert_and_acquire(adc, chan); + if (ret) + return ret; if (chan->scan_type.storagebits > 16) *val = adc->sample.raw.u32; @@ -338,23 +311,9 @@ static irqreturn_t ad7944_trigger_handler(int irq, void *p) struct ad7944_adc *adc = iio_priv(indio_dev); int ret; - switch (adc->spi_mode) { - case AD7944_SPI_MODE_DEFAULT: - ret = ad7944_4wire_mode_conversion(adc, &indio_dev->channels[0]); - if (ret) - goto out; - - break; - case AD7944_SPI_MODE_SINGLE: - ret = ad7944_3wire_cs_mode_conversion(adc, &indio_dev->channels[0]); - if (ret) - goto out; - - break; - default: - /* not supported */ + ret = ad7944_convert_and_acquire(adc, &indio_dev->channels[0]); + if (ret) goto out; - } iio_push_to_buffers_with_timestamp(indio_dev, &adc->sample.raw, pf->timestamp); -- cgit v1.2.3-59-g8ed1b From 6a9e5518287ba3807968ba2213b5636e572567ad Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Maneyrol Date: Mon, 8 Apr 2024 09:07:19 +0000 Subject: dt-bindings: iio: imu: add icm42688 inside inv_icm42600 Add bindings for ICM-42688-P chip. Signed-off-by: Jean-Baptiste Maneyrol Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240408090720.847107-2-inv.git-commit@tdk.com Signed-off-by: Jonathan Cameron --- Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml b/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml index 7cd05bcbee31..5e0bed2c45de 100644 --- a/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml +++ b/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml @@ -32,6 +32,7 @@ properties: - invensense,icm42605 - invensense,icm42622 - invensense,icm42631 + - invensense,icm42688 reg: maxItems: 1 -- cgit v1.2.3-59-g8ed1b From 88b49449f25ddab6d10e4ba4fad225cb81d0a6d8 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Maneyrol Date: Mon, 8 Apr 2024 09:07:20 +0000 Subject: iio: imu: inv_icm42600: add support of ICM-42688-P Add ICM-42688-P support inside driver. Signed-off-by: Jean-Baptiste Maneyrol Link: https://lore.kernel.org/r/20240408090720.847107-3-inv.git-commit@tdk.com Signed-off-by: Jonathan Cameron --- drivers/iio/imu/inv_icm42600/inv_icm42600.h | 2 ++ drivers/iio/imu/inv_icm42600/inv_icm42600_core.c | 5 +++++ drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c | 3 +++ drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c | 3 +++ 4 files changed, 13 insertions(+) diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600.h b/drivers/iio/imu/inv_icm42600/inv_icm42600.h index 0e290c807b0f..0566340b2660 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600.h +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600.h @@ -22,6 +22,7 @@ enum inv_icm42600_chip { INV_CHIP_ICM42602, INV_CHIP_ICM42605, INV_CHIP_ICM42622, + INV_CHIP_ICM42688, INV_CHIP_ICM42631, INV_CHIP_NB, }; @@ -304,6 +305,7 @@ struct inv_icm42600_state { #define INV_ICM42600_WHOAMI_ICM42602 0x41 #define INV_ICM42600_WHOAMI_ICM42605 0x42 #define INV_ICM42600_WHOAMI_ICM42622 0x46 +#define INV_ICM42600_WHOAMI_ICM42688 0x47 #define INV_ICM42600_WHOAMI_ICM42631 0x5C /* User bank 1 (MSB 0x10) */ diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c index a5e81906e37e..82e0a2e2ad70 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c @@ -87,6 +87,11 @@ static const struct inv_icm42600_hw inv_icm42600_hw[INV_CHIP_NB] = { .name = "icm42622", .conf = &inv_icm42600_default_conf, }, + [INV_CHIP_ICM42688] = { + .whoami = INV_ICM42600_WHOAMI_ICM42688, + .name = "icm42688", + .conf = &inv_icm42600_default_conf, + }, [INV_CHIP_ICM42631] = { .whoami = INV_ICM42600_WHOAMI_ICM42631, .name = "icm42631", diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c index 1af559403ba6..ebb28f84ba98 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c @@ -84,6 +84,9 @@ static const struct of_device_id inv_icm42600_of_matches[] = { }, { .compatible = "invensense,icm42622", .data = (void *)INV_CHIP_ICM42622, + }, { + .compatible = "invensense,icm42688", + .data = (void *)INV_CHIP_ICM42688, }, { .compatible = "invensense,icm42631", .data = (void *)INV_CHIP_ICM42631, diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c index 6be4ac794937..50217a10e0bb 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c @@ -80,6 +80,9 @@ static const struct of_device_id inv_icm42600_of_matches[] = { }, { .compatible = "invensense,icm42622", .data = (void *)INV_CHIP_ICM42622, + }, { + .compatible = "invensense,icm42688", + .data = (void *)INV_CHIP_ICM42688, }, { .compatible = "invensense,icm42631", .data = (void *)INV_CHIP_ICM42631, -- cgit v1.2.3-59-g8ed1b From 62d3fb9dcc091ccdf25eb3b716e90e07e3ed861f Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sat, 13 Apr 2024 17:45:11 +0200 Subject: iio: dac: ad5755: make use of of_device_id table Store pointers to chip info (struct ad5755_chip_info) in driver match data, instead of enum, so every value will be != 0, populate the of_device_id table and use it in driver. Even though it is one change, it gives multiple benefits: 1. Allows to use spi_get_device_match_data() dropping local 'type' variable. 2. Makes both ID tables usable, so kernel can match via any of these methods. 3. Code is more obvious as both tables are properly filled. 4. Fixes W=1 warning: ad5755.c:866:34: error: unused variable 'ad5755_of_match' [-Werror,-Wunused-const-variable] Cc: Arnd Bergmann Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240413154511.52576-1-krzysztof.kozlowski@linaro.org Signed-off-by: Jonathan Cameron --- drivers/iio/dac/ad5755.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/iio/dac/ad5755.c b/drivers/iio/dac/ad5755.c index 404865e35460..0b24cb19ac9d 100644 --- a/drivers/iio/dac/ad5755.c +++ b/drivers/iio/dac/ad5755.c @@ -809,7 +809,6 @@ static struct ad5755_platform_data *ad5755_parse_fw(struct device *dev) static int ad5755_probe(struct spi_device *spi) { - enum ad5755_type type = spi_get_device_id(spi)->driver_data; const struct ad5755_platform_data *pdata; struct iio_dev *indio_dev; struct ad5755_state *st; @@ -824,7 +823,7 @@ static int ad5755_probe(struct spi_device *spi) st = iio_priv(indio_dev); spi_set_drvdata(spi, indio_dev); - st->chip_info = &ad5755_chip_info_tbl[type]; + st->chip_info = spi_get_device_match_data(spi); st->spi = spi; st->pwr_down = 0xf; @@ -854,21 +853,21 @@ static int ad5755_probe(struct spi_device *spi) } static const struct spi_device_id ad5755_id[] = { - { "ad5755", ID_AD5755 }, - { "ad5755-1", ID_AD5755 }, - { "ad5757", ID_AD5757 }, - { "ad5735", ID_AD5735 }, - { "ad5737", ID_AD5737 }, + { "ad5755", (kernel_ulong_t)&ad5755_chip_info_tbl[ID_AD5755] }, + { "ad5755-1", (kernel_ulong_t)&ad5755_chip_info_tbl[ID_AD5755] }, + { "ad5757", (kernel_ulong_t)&ad5755_chip_info_tbl[ID_AD5757] }, + { "ad5735", (kernel_ulong_t)&ad5755_chip_info_tbl[ID_AD5735] }, + { "ad5737", (kernel_ulong_t)&ad5755_chip_info_tbl[ID_AD5737] }, {} }; MODULE_DEVICE_TABLE(spi, ad5755_id); static const struct of_device_id ad5755_of_match[] = { - { .compatible = "adi,ad5755" }, - { .compatible = "adi,ad5755-1" }, - { .compatible = "adi,ad5757" }, - { .compatible = "adi,ad5735" }, - { .compatible = "adi,ad5737" }, + { .compatible = "adi,ad5755", &ad5755_chip_info_tbl[ID_AD5755] }, + { .compatible = "adi,ad5755-1", &ad5755_chip_info_tbl[ID_AD5755] }, + { .compatible = "adi,ad5757", &ad5755_chip_info_tbl[ID_AD5757] }, + { .compatible = "adi,ad5735", &ad5755_chip_info_tbl[ID_AD5735] }, + { .compatible = "adi,ad5737", &ad5755_chip_info_tbl[ID_AD5737] }, { } }; MODULE_DEVICE_TABLE(of, ad5755_of_match); @@ -876,6 +875,7 @@ MODULE_DEVICE_TABLE(of, ad5755_of_match); static struct spi_driver ad5755_driver = { .driver = { .name = "ad5755", + .of_match_table = ad5755_of_match, }, .probe = ad5755_probe, .id_table = ad5755_id, -- cgit v1.2.3-59-g8ed1b From ebbc1a4789c666846b9854ef845a37a64879e5f9 Mon Sep 17 00:00:00 2001 From: Chris Packham Date: Mon, 15 Apr 2024 09:52:20 +1200 Subject: uio: update kerneldoc comments for interrupt functions Update the kerneldoc comment for uio_interrupt_handler and add one for uio_interrupt_thread. Reported-by: kernel test robot Reported-by: Stephen Rothwell Closes: https://lore.kernel.org/oe-kbuild-all/202404112227.mIATKoTb-lkp@intel.com/ Fixes: f8a27dfa4b82 ("uio: use threaded interrupts") Signed-off-by: Chris Packham Link: https://lore.kernel.org/r/20240414215220.2424597-1-chris.packham@alliedtelesis.co.nz Signed-off-by: Greg Kroah-Hartman --- drivers/uio/uio.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c index e815856eb46c..5ce429286ab0 100644 --- a/drivers/uio/uio.c +++ b/drivers/uio/uio.c @@ -438,7 +438,7 @@ void uio_event_notify(struct uio_info *info) EXPORT_SYMBOL_GPL(uio_event_notify); /** - * uio_interrupt - hardware interrupt handler + * uio_interrupt_handler - hardware interrupt handler * @irq: IRQ number, can be UIO_IRQ_CYCLIC for cyclic timer * @dev_id: Pointer to the devices uio_device structure */ @@ -454,6 +454,11 @@ static irqreturn_t uio_interrupt_handler(int irq, void *dev_id) return ret; } +/** + * uio_interrupt_thread - irq thread handler + * @irq: IRQ number + * @dev_id: Pointer to the devices uio_device structure + */ static irqreturn_t uio_interrupt_thread(int irq, void *dev_id) { struct uio_device *idev = (struct uio_device *)dev_id; -- cgit v1.2.3-59-g8ed1b From dcde4e97b122ac318aaa71e8bcd2857dc28a0d12 Mon Sep 17 00:00:00 2001 From: Hannah Peuckmann Date: Mon, 15 Apr 2024 14:50:32 +0200 Subject: riscv: dts: starfive: visionfive 2: Remove non-existing TDM hardware This partially reverts commit e7c304c0346d ("riscv: dts: starfive: jh7110: add the node and pins configuration for tdm") This added device tree nodes for TDM hardware that is not actually on the VisionFive 2 board, but connected on the 40pin header. Many different extension boards could be added on those pins, so this should be handled by overlays instead. This also conflicts with the I2S node which also attempts to grab GPIO 44: starfive-jh7110-sys-pinctrl 13040000.pinctrl: pin GPIO44 already requested by 10090000.tdm; cannot claim for 120c0000.i2s Fixes: e7c304c0346d ("riscv: dts: starfive: jh7110: add the node and pins configuration for tdm") Signed-off-by: Hannah Peuckmann Reviewed-by: Emil Renner Berthing Tested-by: Emil Renner Berthing Signed-off-by: Conor Dooley --- .../dts/starfive/jh7110-starfive-visionfive-2.dtsi | 40 ---------------------- 1 file changed, 40 deletions(-) diff --git a/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi index 7783d464d529..58f892f984a4 100644 --- a/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi +++ b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi @@ -621,40 +621,6 @@ }; }; - tdm_pins: tdm-0 { - tx-pins { - pinmux = ; - bias-pull-up; - drive-strength = <2>; - input-disable; - input-schmitt-disable; - slew-rate = <0>; - }; - - rx-pins { - pinmux = ; - input-enable; - }; - - sync-pins { - pinmux = ; - input-enable; - }; - - pcmclk-pins { - pinmux = ; - input-enable; - }; - }; - uart0_pins: uart0-0 { tx-pins { pinmux = ; - status = "okay"; -}; - &uart0 { pinctrl-names = "default"; pinctrl-0 = <&uart0_pins>; -- cgit v1.2.3-59-g8ed1b From e0503d47e93dead8c0475ea1eb624e03fada21d3 Mon Sep 17 00:00:00 2001 From: Hannah Peuckmann Date: Mon, 15 Apr 2024 14:50:33 +0200 Subject: riscv: dts: starfive: visionfive 2: Remove non-existing I2S hardware This partially reverts commit 92cfc35838b2 ("riscv: dts: starfive: Add the nodes and pins of I2Srx/I2Stx0/I2Stx1") This added device tree nodes for I2S hardware that is not actually on the VisionFive 2 board, but connected on the 40pin header. Many different extension boards could be added on those pins, so this should be handled by overlays instead. This also conflicts with the TDM node which also attempts to grab GPIO 44: starfive-jh7110-sys-pinctrl 13040000.pinctrl: pin GPIO44 already requested by 10090000.tdm; cannot claim for 120c0000.i2s Fixes: 92cfc35838b2 ("riscv: dts: starfive: Add the nodes and pins of I2Srx/I2Stx0/I2Stx1") Signed-off-by: Hannah Peuckmann Reviewed-by: Emil Renner Berthing Tested-by: Emil Renner Berthing Signed-off-by: Conor Dooley --- .../dts/starfive/jh7110-starfive-visionfive-2.dtsi | 58 ---------------------- 1 file changed, 58 deletions(-) diff --git a/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi index 58f892f984a4..ccd0ce55aa53 100644 --- a/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi +++ b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi @@ -278,24 +278,6 @@ status = "okay"; }; -&i2srx { - pinctrl-names = "default"; - pinctrl-0 = <&i2srx_pins>; - status = "okay"; -}; - -&i2stx0 { - pinctrl-names = "default"; - pinctrl-0 = <&mclk_ext_pins>; - status = "okay"; -}; - -&i2stx1 { - pinctrl-names = "default"; - pinctrl-0 = <&i2stx1_pins>; - status = "okay"; -}; - &mmc0 { max-frequency = <100000000>; assigned-clocks = <&syscrg JH7110_SYSCLK_SDIO0_SDCARD>; @@ -446,46 +428,6 @@ }; }; - i2srx_pins: i2srx-0 { - clk-sd-pins { - pinmux = , - , - , - , - ; - input-enable; - }; - }; - - i2stx1_pins: i2stx1-0 { - sd-pins { - pinmux = ; - bias-disable; - input-disable; - }; - }; - - mclk_ext_pins: mclk-ext-0 { - mclk-ext-pins { - pinmux = ; - input-enable; - }; - }; - mmc0_pins: mmc0-0 { rst-pins { pinmux = Date: Thu, 4 Jan 2024 21:35:38 -0500 Subject: close_on_exec(): pass files_struct instead of fdtable both callers are happier that way... Reviewed-by: Christian Brauner Signed-off-by: Al Viro --- fs/file.c | 5 +---- fs/proc/fd.c | 4 +--- include/linux/fdtable.h | 10 +++++----- 3 files changed, 7 insertions(+), 12 deletions(-) diff --git a/fs/file.c b/fs/file.c index 3b683b9101d8..eff5ce79f66a 100644 --- a/fs/file.c +++ b/fs/file.c @@ -1219,12 +1219,9 @@ void set_close_on_exec(unsigned int fd, int flag) bool get_close_on_exec(unsigned int fd) { - struct files_struct *files = current->files; - struct fdtable *fdt; bool res; rcu_read_lock(); - fdt = files_fdtable(files); - res = close_on_exec(fd, fdt); + res = close_on_exec(fd, current->files); rcu_read_unlock(); return res; } diff --git a/fs/proc/fd.c b/fs/proc/fd.c index 6e72e5ad42bc..0139aae19651 100644 --- a/fs/proc/fd.c +++ b/fs/proc/fd.c @@ -39,10 +39,8 @@ static int seq_show(struct seq_file *m, void *v) spin_lock(&files->file_lock); file = files_lookup_fd_locked(files, fd); if (file) { - struct fdtable *fdt = files_fdtable(files); - f_flags = file->f_flags; - if (close_on_exec(fd, fdt)) + if (close_on_exec(fd, files)) f_flags |= O_CLOEXEC; get_file(file); diff --git a/include/linux/fdtable.h b/include/linux/fdtable.h index 78c8326d74ae..cc060b20502b 100644 --- a/include/linux/fdtable.h +++ b/include/linux/fdtable.h @@ -33,11 +33,6 @@ struct fdtable { struct rcu_head rcu; }; -static inline bool close_on_exec(unsigned int fd, const struct fdtable *fdt) -{ - return test_bit(fd, fdt->close_on_exec); -} - static inline bool fd_is_open(unsigned int fd, const struct fdtable *fdt) { return test_bit(fd, fdt->open_fds); @@ -107,6 +102,11 @@ struct file *lookup_fdget_rcu(unsigned int fd); struct file *task_lookup_fdget_rcu(struct task_struct *task, unsigned int fd); struct file *task_lookup_next_fdget_rcu(struct task_struct *task, unsigned int *fd); +static inline bool close_on_exec(unsigned int fd, const struct files_struct *files) +{ + return test_bit(fd, files_fdtable(files)->close_on_exec); +} + struct task_struct; void put_files_struct(struct files_struct *fs); -- cgit v1.2.3-59-g8ed1b From c4aab26253cd1f302279b8d6b5b66ccf1b120520 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 4 Jan 2024 21:45:47 -0500 Subject: fd_is_open(): move to fs/file.c no users outside that... Reviewed-by: Christian Brauner Signed-off-by: Al Viro --- fs/file.c | 5 +++++ include/linux/fdtable.h | 5 ----- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/fs/file.c b/fs/file.c index eff5ce79f66a..ab38b005633c 100644 --- a/fs/file.c +++ b/fs/file.c @@ -271,6 +271,11 @@ static inline void __clear_open_fd(unsigned int fd, struct fdtable *fdt) __clear_bit(fd / BITS_PER_LONG, fdt->full_fds_bits); } +static inline bool fd_is_open(unsigned int fd, const struct fdtable *fdt) +{ + return test_bit(fd, fdt->open_fds); +} + static unsigned int count_open_files(struct fdtable *fdt) { unsigned int size = fdt->max_fds; diff --git a/include/linux/fdtable.h b/include/linux/fdtable.h index cc060b20502b..2944d4aa413b 100644 --- a/include/linux/fdtable.h +++ b/include/linux/fdtable.h @@ -33,11 +33,6 @@ struct fdtable { struct rcu_head rcu; }; -static inline bool fd_is_open(unsigned int fd, const struct fdtable *fdt) -{ - return test_bit(fd, fdt->open_fds); -} - /* * Open file table structure */ -- cgit v1.2.3-59-g8ed1b From 613aee94dddf07de9fde8dd4fcb6e4579cde8a65 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 20 Jan 2024 06:20:36 -0500 Subject: get_file_rcu(): no need to check for NULL separately IS_ERR(NULL) is false and IS_ERR() already comes with unlikely()... Reviewed-by: Christian Brauner Signed-off-by: Al Viro --- fs/file.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/fs/file.c b/fs/file.c index ab38b005633c..8076aef9c210 100644 --- a/fs/file.c +++ b/fs/file.c @@ -920,13 +920,8 @@ struct file *get_file_rcu(struct file __rcu **f) struct file __rcu *file; file = __get_file_rcu(f); - if (unlikely(!file)) - return NULL; - - if (unlikely(IS_ERR(file))) - continue; - - return file; + if (!IS_ERR(file)) + return file; } } EXPORT_SYMBOL_GPL(get_file_rcu); -- cgit v1.2.3-59-g8ed1b From af58dc1f50c1946018773beca23ebaad587b9cc9 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 20 Jan 2024 06:24:55 -0500 Subject: kernel_file_open(): get rid of inode argument always equal to ->dentry->d_inode of the path argument these days. Reviewed-by: Christian Brauner Signed-off-by: Al Viro --- fs/cachefiles/namei.c | 3 +-- fs/open.c | 5 ++--- fs/overlayfs/util.c | 2 +- include/linux/fs.h | 2 +- 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/fs/cachefiles/namei.c b/fs/cachefiles/namei.c index 7ade836beb58..f53977169db4 100644 --- a/fs/cachefiles/namei.c +++ b/fs/cachefiles/namei.c @@ -563,8 +563,7 @@ static bool cachefiles_open_file(struct cachefiles_object *object, */ path.mnt = cache->mnt; path.dentry = dentry; - file = kernel_file_open(&path, O_RDWR | O_LARGEFILE | O_DIRECT, - d_backing_inode(dentry), cache->cache_cred); + file = kernel_file_open(&path, O_RDWR | O_LARGEFILE | O_DIRECT, cache->cache_cred); if (IS_ERR(file)) { trace_cachefiles_vfs_error(object, d_backing_inode(dentry), PTR_ERR(file), diff --git a/fs/open.c b/fs/open.c index ee8460c83c77..ec287ac67e7f 100644 --- a/fs/open.c +++ b/fs/open.c @@ -1155,7 +1155,6 @@ EXPORT_SYMBOL(dentry_create); * kernel_file_open - open a file for kernel internal use * @path: path of the file to open * @flags: open flags - * @inode: the inode * @cred: credentials for open * * Open a file for use by in-kernel consumers. The file is not accounted @@ -1165,7 +1164,7 @@ EXPORT_SYMBOL(dentry_create); * Return: Opened file on success, an error pointer on failure. */ struct file *kernel_file_open(const struct path *path, int flags, - struct inode *inode, const struct cred *cred) + const struct cred *cred) { struct file *f; int error; @@ -1175,7 +1174,7 @@ struct file *kernel_file_open(const struct path *path, int flags, return f; f->f_path = *path; - error = do_dentry_open(f, inode, NULL); + error = do_dentry_open(f, d_inode(path->dentry), NULL); if (error) { fput(f); f = ERR_PTR(error); diff --git a/fs/overlayfs/util.c b/fs/overlayfs/util.c index d285d1d7baad..edc9216f6e27 100644 --- a/fs/overlayfs/util.c +++ b/fs/overlayfs/util.c @@ -1376,7 +1376,7 @@ int ovl_ensure_verity_loaded(struct path *datapath) * If this inode was not yet opened, the verity info hasn't been * loaded yet, so we need to do that here to force it into memory. */ - filp = kernel_file_open(datapath, O_RDONLY, inode, current_cred()); + filp = kernel_file_open(datapath, O_RDONLY, current_cred()); if (IS_ERR(filp)) return PTR_ERR(filp); fput(filp); diff --git a/include/linux/fs.h b/include/linux/fs.h index 00fc429b0af0..143e967a3af2 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1906,7 +1906,7 @@ struct file *kernel_tmpfile_open(struct mnt_idmap *idmap, umode_t mode, int open_flag, const struct cred *cred); struct file *kernel_file_open(const struct path *path, int flags, - struct inode *inode, const struct cred *cred); + const struct cred *cred); int vfs_mkobj(struct dentry *, umode_t, int (*f)(struct dentry *, umode_t, void *), -- cgit v1.2.3-59-g8ed1b From 0f4a2cebe256dab4e9b8836b87ce4c909cd585eb Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 20 Jan 2024 06:28:52 -0500 Subject: do_dentry_open(): kill inode argument should've been done as soon as overlayfs stopped messing with fake paths... Reviewed-by: Christian Brauner Signed-off-by: Al Viro --- fs/open.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fs/open.c b/fs/open.c index ec287ac67e7f..89cafb572061 100644 --- a/fs/open.c +++ b/fs/open.c @@ -902,10 +902,10 @@ cleanup_inode: } static int do_dentry_open(struct file *f, - struct inode *inode, int (*open)(struct inode *, struct file *)) { static const struct file_operations empty_fops = {}; + struct inode *inode = f->f_path.dentry->d_inode; int error; path_get(&f->f_path); @@ -1047,7 +1047,7 @@ int finish_open(struct file *file, struct dentry *dentry, BUG_ON(file->f_mode & FMODE_OPENED); /* once it's opened, it's opened */ file->f_path.dentry = dentry; - return do_dentry_open(file, d_backing_inode(dentry), open); + return do_dentry_open(file, open); } EXPORT_SYMBOL(finish_open); @@ -1086,7 +1086,7 @@ EXPORT_SYMBOL(file_path); int vfs_open(const struct path *path, struct file *file) { file->f_path = *path; - return do_dentry_open(file, d_backing_inode(path->dentry), NULL); + return do_dentry_open(file, NULL); } struct file *dentry_open(const struct path *path, int flags, @@ -1174,7 +1174,7 @@ struct file *kernel_file_open(const struct path *path, int flags, return f; f->f_path = *path; - error = do_dentry_open(f, d_inode(path->dentry), NULL); + error = do_dentry_open(f, NULL); if (error) { fput(f); f = ERR_PTR(error); -- cgit v1.2.3-59-g8ed1b From 7c98f7cb8fda964fbc60b9307ad35e94735fa35f Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Mon, 28 Aug 2023 17:13:18 +0200 Subject: remove call_{read,write}_iter() functions These have no clear purpose. This is effectively a revert of commit bb7462b6fd64 ("vfs: use helpers for calling f_op->{read,write}_iter()"). The patch was created with the help of a coccinelle script. Fixes: bb7462b6fd64 ("vfs: use helpers for calling f_op->{read,write}_iter()") Reviewed-by: Christian Brauner Signed-off-by: Miklos Szeredi Signed-off-by: Al Viro --- drivers/block/loop.c | 4 ++-- drivers/target/target_core_file.c | 4 ++-- fs/aio.c | 4 ++-- fs/read_write.c | 12 ++++++------ fs/splice.c | 4 ++-- include/linux/fs.h | 12 ------------ io_uring/rw.c | 4 ++-- 7 files changed, 16 insertions(+), 28 deletions(-) diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 28a95fd366fe..93780f41646b 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -445,9 +445,9 @@ static int lo_rw_aio(struct loop_device *lo, struct loop_cmd *cmd, cmd->iocb.ki_ioprio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_NONE, 0); if (rw == ITER_SOURCE) - ret = call_write_iter(file, &cmd->iocb, &iter); + ret = file->f_op->write_iter(&cmd->iocb, &iter); else - ret = call_read_iter(file, &cmd->iocb, &iter); + ret = file->f_op->read_iter(&cmd->iocb, &iter); lo_rw_aio_do_completion(cmd); diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c index 4d447520bab8..94e6cd4e7e43 100644 --- a/drivers/target/target_core_file.c +++ b/drivers/target/target_core_file.c @@ -299,9 +299,9 @@ fd_execute_rw_aio(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, aio_cmd->iocb.ki_flags |= IOCB_DSYNC; if (is_write) - ret = call_write_iter(file, &aio_cmd->iocb, &iter); + ret = file->f_op->write_iter(&aio_cmd->iocb, &iter); else - ret = call_read_iter(file, &aio_cmd->iocb, &iter); + ret = file->f_op->read_iter(&aio_cmd->iocb, &iter); if (ret != -EIOCBQUEUED) cmd_rw_aio_complete(&aio_cmd->iocb, ret); diff --git a/fs/aio.c b/fs/aio.c index 9cdaa2faa536..13ca81c7c744 100644 --- a/fs/aio.c +++ b/fs/aio.c @@ -1605,7 +1605,7 @@ static int aio_read(struct kiocb *req, const struct iocb *iocb, return ret; ret = rw_verify_area(READ, file, &req->ki_pos, iov_iter_count(&iter)); if (!ret) - aio_rw_done(req, call_read_iter(file, req, &iter)); + aio_rw_done(req, file->f_op->read_iter(req, &iter)); kfree(iovec); return ret; } @@ -1636,7 +1636,7 @@ static int aio_write(struct kiocb *req, const struct iocb *iocb, if (S_ISREG(file_inode(file)->i_mode)) kiocb_start_write(req); req->ki_flags |= IOCB_WRITE; - aio_rw_done(req, call_write_iter(file, req, &iter)); + aio_rw_done(req, file->f_op->write_iter(req, &iter)); } kfree(iovec); return ret; diff --git a/fs/read_write.c b/fs/read_write.c index d4c036e82b6c..2de7f6adb33d 100644 --- a/fs/read_write.c +++ b/fs/read_write.c @@ -392,7 +392,7 @@ static ssize_t new_sync_read(struct file *filp, char __user *buf, size_t len, lo kiocb.ki_pos = (ppos ? *ppos : 0); iov_iter_ubuf(&iter, ITER_DEST, buf, len); - ret = call_read_iter(filp, &kiocb, &iter); + ret = filp->f_op->read_iter(&kiocb, &iter); BUG_ON(ret == -EIOCBQUEUED); if (ppos) *ppos = kiocb.ki_pos; @@ -494,7 +494,7 @@ static ssize_t new_sync_write(struct file *filp, const char __user *buf, size_t kiocb.ki_pos = (ppos ? *ppos : 0); iov_iter_ubuf(&iter, ITER_SOURCE, (void __user *)buf, len); - ret = call_write_iter(filp, &kiocb, &iter); + ret = filp->f_op->write_iter(&kiocb, &iter); BUG_ON(ret == -EIOCBQUEUED); if (ret > 0 && ppos) *ppos = kiocb.ki_pos; @@ -736,9 +736,9 @@ static ssize_t do_iter_readv_writev(struct file *filp, struct iov_iter *iter, kiocb.ki_pos = (ppos ? *ppos : 0); if (type == READ) - ret = call_read_iter(filp, &kiocb, iter); + ret = filp->f_op->read_iter(&kiocb, iter); else - ret = call_write_iter(filp, &kiocb, iter); + ret = filp->f_op->write_iter(&kiocb, iter); BUG_ON(ret == -EIOCBQUEUED); if (ppos) *ppos = kiocb.ki_pos; @@ -799,7 +799,7 @@ ssize_t vfs_iocb_iter_read(struct file *file, struct kiocb *iocb, if (ret < 0) return ret; - ret = call_read_iter(file, iocb, iter); + ret = file->f_op->read_iter(iocb, iter); out: if (ret >= 0) fsnotify_access(file); @@ -860,7 +860,7 @@ ssize_t vfs_iocb_iter_write(struct file *file, struct kiocb *iocb, return ret; kiocb_start_write(iocb); - ret = call_write_iter(file, iocb, iter); + ret = file->f_op->write_iter(iocb, iter); if (ret != -EIOCBQUEUED) kiocb_end_write(iocb); if (ret > 0) diff --git a/fs/splice.c b/fs/splice.c index 218e24b1ac40..60aed8de21f8 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -362,7 +362,7 @@ ssize_t copy_splice_read(struct file *in, loff_t *ppos, iov_iter_bvec(&to, ITER_DEST, bv, npages, len); init_sync_kiocb(&kiocb, in); kiocb.ki_pos = *ppos; - ret = call_read_iter(in, &kiocb, &to); + ret = in->f_op->read_iter(&kiocb, &to); if (ret > 0) { keep = DIV_ROUND_UP(ret, PAGE_SIZE); @@ -740,7 +740,7 @@ iter_file_splice_write(struct pipe_inode_info *pipe, struct file *out, iov_iter_bvec(&from, ITER_SOURCE, array, n, sd.total_len - left); init_sync_kiocb(&kiocb, out); kiocb.ki_pos = sd.pos; - ret = call_write_iter(out, &kiocb, &from); + ret = out->f_op->write_iter(&kiocb, &from); sd.pos = kiocb.ki_pos; if (ret <= 0) break; diff --git a/include/linux/fs.h b/include/linux/fs.h index 143e967a3af2..a94343f567cb 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2096,18 +2096,6 @@ struct inode_operations { struct offset_ctx *(*get_offset_ctx)(struct inode *inode); } ____cacheline_aligned; -static inline ssize_t call_read_iter(struct file *file, struct kiocb *kio, - struct iov_iter *iter) -{ - return file->f_op->read_iter(kio, iter); -} - -static inline ssize_t call_write_iter(struct file *file, struct kiocb *kio, - struct iov_iter *iter) -{ - return file->f_op->write_iter(kio, iter); -} - static inline int call_mmap(struct file *file, struct vm_area_struct *vma) { return file->f_op->mmap(file, vma); diff --git a/io_uring/rw.c b/io_uring/rw.c index 0585ebcc9773..7d335b7e00ed 100644 --- a/io_uring/rw.c +++ b/io_uring/rw.c @@ -701,7 +701,7 @@ static inline int io_iter_do_read(struct io_rw *rw, struct iov_iter *iter) struct file *file = rw->kiocb.ki_filp; if (likely(file->f_op->read_iter)) - return call_read_iter(file, &rw->kiocb, iter); + return file->f_op->read_iter(&rw->kiocb, iter); else if (file->f_op->read) return loop_rw_iter(READ, rw, iter); else @@ -1047,7 +1047,7 @@ int io_write(struct io_kiocb *req, unsigned int issue_flags) kiocb->ki_flags |= IOCB_WRITE; if (likely(req->file->f_op->write_iter)) - ret2 = call_write_iter(req->file, kiocb, &s->iter); + ret2 = req->file->f_op->write_iter(kiocb, &s->iter); else if (req->file->f_op->write) ret2 = loop_rw_iter(WRITE, rw, &s->iter); else -- cgit v1.2.3-59-g8ed1b From ed8c2dad25eb2fbaa61f2e32385ecc1aa34c2355 Mon Sep 17 00:00:00 2001 From: "Ricardo B. Marliere" Date: Sat, 10 Feb 2024 12:10:14 -0300 Subject: peci: Make peci_bus_type const Now that the driver core can properly handle constant struct bus_type, move the peci_bus_type variable to be a constant structure as well, placing it into read-only memory which can not be modified at runtime. Cc: Greg Kroah-Hartman Suggested-by: Greg Kroah-Hartman Signed-off-by: "Ricardo B. Marliere" Link: https://lore.kernel.org/r/20240210-bus_cleanup-peci-v1-1-1e64bef6efc0@marliere.net Signed-off-by: Iwona Winiarska --- drivers/peci/core.c | 2 +- drivers/peci/internal.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/peci/core.c b/drivers/peci/core.c index 0f83a9c6093b..b2f8db967e9b 100644 --- a/drivers/peci/core.c +++ b/drivers/peci/core.c @@ -201,7 +201,7 @@ static void peci_bus_device_remove(struct device *dev) driver->remove(device); } -struct bus_type peci_bus_type = { +const struct bus_type peci_bus_type = { .name = "peci", .match = peci_bus_device_match, .probe = peci_bus_device_probe, diff --git a/drivers/peci/internal.h b/drivers/peci/internal.h index 9d75ea54504c..8a896c256c5f 100644 --- a/drivers/peci/internal.h +++ b/drivers/peci/internal.h @@ -81,7 +81,7 @@ extern const struct attribute_group *peci_device_groups[]; int peci_device_create(struct peci_controller *controller, u8 addr); void peci_device_destroy(struct peci_device *device); -extern struct bus_type peci_bus_type; +extern const struct bus_type peci_bus_type; extern const struct attribute_group *peci_bus_groups[]; /** -- cgit v1.2.3-59-g8ed1b From e6faf2b750ebf3837a63ebe465e7b7933502bdc4 Mon Sep 17 00:00:00 2001 From: "Ricardo B. Marliere" Date: Mon, 19 Feb 2024 09:36:35 -0300 Subject: peci: constify the struct device_type usage Since commit aed65af1cc2f ("drivers: make device_type const"), the driver core can properly handle constant struct device_type. Move the peci_controller_type and peci_device_type variables to be constant structures as well, placing it into read-only memory which can not be modified at runtime. Cc: Greg Kroah-Hartman Signed-off-by: "Ricardo B. Marliere" Reviewed-by: Iwona Winiarska Link: https://lore.kernel.org/r/20240219-device_cleanup-peci-v1-1-0727662616f7@marliere.net Signed-off-by: Iwona Winiarska --- drivers/peci/core.c | 2 +- drivers/peci/device.c | 2 +- drivers/peci/internal.h | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/peci/core.c b/drivers/peci/core.c index b2f8db967e9b..8f8bda2f2a62 100644 --- a/drivers/peci/core.c +++ b/drivers/peci/core.c @@ -25,7 +25,7 @@ static void peci_controller_dev_release(struct device *dev) kfree(controller); } -struct device_type peci_controller_type = { +const struct device_type peci_controller_type = { .release = peci_controller_dev_release, }; diff --git a/drivers/peci/device.c b/drivers/peci/device.c index e6b0bffb14f4..ee01f03c29b7 100644 --- a/drivers/peci/device.c +++ b/drivers/peci/device.c @@ -246,7 +246,7 @@ static void peci_device_release(struct device *dev) kfree(device); } -struct device_type peci_device_type = { +const struct device_type peci_device_type = { .groups = peci_device_groups, .release = peci_device_release, }; diff --git a/drivers/peci/internal.h b/drivers/peci/internal.h index 8a896c256c5f..506bafcccbbf 100644 --- a/drivers/peci/internal.h +++ b/drivers/peci/internal.h @@ -75,7 +75,7 @@ struct peci_device_id { u8 model; }; -extern struct device_type peci_device_type; +extern const struct device_type peci_device_type; extern const struct attribute_group *peci_device_groups[]; int peci_device_create(struct peci_controller *controller, u8 addr); @@ -129,7 +129,7 @@ void peci_driver_unregister(struct peci_driver *driver); #define module_peci_driver(__peci_driver) \ module_driver(__peci_driver, peci_driver_register, peci_driver_unregister) -extern struct device_type peci_controller_type; +extern const struct device_type peci_controller_type; int peci_controller_scan_devices(struct peci_controller *controller); -- cgit v1.2.3-59-g8ed1b From ba2ec9c4f0c8ab59befc7f62e1606a840347f020 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Date: Mon, 15 Apr 2024 14:53:03 -0700 Subject: Input: sur40 - convert le16 to cpu before use Smatch found this issue: drivers/input/touchscreen/sur40.c:424:55: warning: incorrect type in argument 2 (different base types) drivers/input/touchscreen/sur40.c:424:55: expected int key drivers/input/touchscreen/sur40.c:424:55: got restricted __le16 [usertype] blob_id Signed-off-by: Ricardo Ribalda Link: https://lore.kernel.org/r/20240410-smatch-v1-6-785d009a852b@chromium.org Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/sur40.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/touchscreen/sur40.c b/drivers/input/touchscreen/sur40.c index 8ddb3f7d307a..cba6f5015106 100644 --- a/drivers/input/touchscreen/sur40.c +++ b/drivers/input/touchscreen/sur40.c @@ -421,7 +421,7 @@ static void sur40_report_blob(struct sur40_blob *blob, struct input_dev *input) if (blob->type != SUR40_TOUCH) return; - slotnum = input_mt_get_slot_by_key(input, blob->blob_id); + slotnum = input_mt_get_slot_by_key(input, le16_to_cpu(blob->blob_id)); if (slotnum < 0 || slotnum >= MAX_CONTACTS) return; -- cgit v1.2.3-59-g8ed1b From 48c0687a322d54ac7e7a685c0b6db78d78f593af Mon Sep 17 00:00:00 2001 From: Fenglin Wu Date: Mon, 15 Apr 2024 16:03:40 -0700 Subject: Input: pm8xxx-vibrator - correct VIB_MAX_LEVELS calculation The output voltage is inclusive hence the max level calculation is off-by-one-step. Correct it. iWhile we are at it also add a define for the step size instead of using the magic value. Fixes: 11205bb63e5c ("Input: add support for pm8xxx based vibrator driver") Signed-off-by: Fenglin Wu Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20240412-pm8xxx-vibrator-new-design-v10-1-0ec0ad133866@quicinc.com Signed-off-by: Dmitry Torokhov --- drivers/input/misc/pm8xxx-vibrator.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/input/misc/pm8xxx-vibrator.c b/drivers/input/misc/pm8xxx-vibrator.c index 5c288fe7accf..79f478d3a9b3 100644 --- a/drivers/input/misc/pm8xxx-vibrator.c +++ b/drivers/input/misc/pm8xxx-vibrator.c @@ -13,7 +13,8 @@ #define VIB_MAX_LEVEL_mV (3100) #define VIB_MIN_LEVEL_mV (1200) -#define VIB_MAX_LEVELS (VIB_MAX_LEVEL_mV - VIB_MIN_LEVEL_mV) +#define VIB_PER_STEP_mV (100) +#define VIB_MAX_LEVELS (VIB_MAX_LEVEL_mV - VIB_MIN_LEVEL_mV + VIB_PER_STEP_mV) #define MAX_FF_SPEED 0xff @@ -117,10 +118,10 @@ static void pm8xxx_work_handler(struct work_struct *work) vib->active = true; vib->level = ((VIB_MAX_LEVELS * vib->speed) / MAX_FF_SPEED) + VIB_MIN_LEVEL_mV; - vib->level /= 100; + vib->level /= VIB_PER_STEP_mV; } else { vib->active = false; - vib->level = VIB_MIN_LEVEL_mV / 100; + vib->level = VIB_MIN_LEVEL_mV / VIB_PER_STEP_mV; } pm8xxx_vib_set(vib, vib->active); -- cgit v1.2.3-59-g8ed1b From 35fad98ed25ab9e08c4363f0f74efd612c8eb185 Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Tue, 16 Apr 2024 07:48:25 +0200 Subject: serial: meson+qcom: don't advance the kfifo twice Marek reports, that the -next commit 1788cf6a91d9 (tty: serial: switch from circ_buf to kfifo) broke meson_uart and qcom_geni_serial. The commit mistakenly advanced the kfifo twice: once by uart_fifo_get()/kfifo_out() and second time by uart_xmit_advance(). To advance the fifo only once, drop the superfluous uart_xmit_advance() from both. To count the TX statistics properly, use uart_fifo_out() in qcom_geni_serial (meson_uart_start_tx() already uses that). I checked all other uses of uart_xmit_advance() and they appear correct: either they are finishing DMA transfers or are after peek/linear_ptr (i.e. they do not advance fifo). Signed-off-by: Jiri Slaby (SUSE) Reported-by: Marek Szyprowski Fixes: 1788cf6a91d9 ("tty: serial: switch from circ_buf to kfifo") Cc: Neil Armstrong Cc: Kevin Hilman Cc: Jerome Brunet Cc: Martin Blumenstingl Link: https://lore.kernel.org/r/20240416054825.6211-1-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/meson_uart.c | 1 - drivers/tty/serial/qcom_geni_serial.c | 4 +--- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/tty/serial/meson_uart.c b/drivers/tty/serial/meson_uart.c index 4587ed4d4d5d..8eb586ac3b0d 100644 --- a/drivers/tty/serial/meson_uart.c +++ b/drivers/tty/serial/meson_uart.c @@ -162,7 +162,6 @@ static void meson_uart_start_tx(struct uart_port *port) break; writel(ch, port->membase + AML_UART_WFIFO); - uart_xmit_advance(port, 1); } if (!kfifo_is_empty(&tport->xmit_fifo)) { diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c index 7814982f1921..2bd25afe0d92 100644 --- a/drivers/tty/serial/qcom_geni_serial.c +++ b/drivers/tty/serial/qcom_geni_serial.c @@ -855,7 +855,6 @@ static void qcom_geni_serial_send_chunk_fifo(struct uart_port *uport, unsigned int chunk) { struct qcom_geni_serial_port *port = to_dev_port(uport); - struct tty_port *tport = &uport->state->port; unsigned int tx_bytes, remaining = chunk; u8 buf[BYTES_PER_FIFO_WORD]; @@ -863,8 +862,7 @@ static void qcom_geni_serial_send_chunk_fifo(struct uart_port *uport, memset(buf, 0, sizeof(buf)); tx_bytes = min(remaining, BYTES_PER_FIFO_WORD); - tx_bytes = kfifo_out(&tport->xmit_fifo, buf, tx_bytes); - uart_xmit_advance(uport, tx_bytes); + tx_bytes = uart_fifo_out(uport, buf, tx_bytes); iowrite32_rep(uport->membase + SE_GENI_TX_FIFOn, buf, 1); -- cgit v1.2.3-59-g8ed1b From bf901e49a9a894021d4366a311223ea5e891c5e4 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 25 Mar 2024 11:40:06 +0100 Subject: dt-bindings: arm: qcom,coresight-tpda: drop redundant type from ports "in-ports" and "out-ports" are defined by graph schema, so defining its type is redundant. Acked-by: Rob Herring Signed-off-by: Krzysztof Kozlowski Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20240325104007.30723-1-krzysztof.kozlowski@linaro.org --- Documentation/devicetree/bindings/arm/qcom,coresight-tpda.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/Documentation/devicetree/bindings/arm/qcom,coresight-tpda.yaml b/Documentation/devicetree/bindings/arm/qcom,coresight-tpda.yaml index ea3c5db6b52d..7fbd855a66a0 100644 --- a/Documentation/devicetree/bindings/arm/qcom,coresight-tpda.yaml +++ b/Documentation/devicetree/bindings/arm/qcom,coresight-tpda.yaml @@ -66,13 +66,11 @@ properties: - const: apb_pclk in-ports: - type: object description: | Input connections from TPDM to TPDA $ref: /schemas/graph.yaml#/properties/ports out-ports: - type: object description: | Output connections from the TPDA to legacy CoreSight trace bus. $ref: /schemas/graph.yaml#/properties/ports -- cgit v1.2.3-59-g8ed1b From e0b97ddaf4b5babdc30be8a665052af8bcb4610e Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 25 Mar 2024 11:40:07 +0100 Subject: dt-bindings: arm: qcom,coresight-tpda: fix indentation in the example Fix triple-space indentation to double-space in the example DTS. Acked-by: Rob Herring Signed-off-by: Krzysztof Kozlowski Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20240325104007.30723-2-krzysztof.kozlowski@linaro.org --- .../bindings/arm/qcom,coresight-tpda.yaml | 32 ++++++++++------------ 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/Documentation/devicetree/bindings/arm/qcom,coresight-tpda.yaml b/Documentation/devicetree/bindings/arm/qcom,coresight-tpda.yaml index 7fbd855a66a0..76163abed655 100644 --- a/Documentation/devicetree/bindings/arm/qcom,coresight-tpda.yaml +++ b/Documentation/devicetree/bindings/arm/qcom,coresight-tpda.yaml @@ -95,33 +95,31 @@ examples: # minimum tpda definition. - | tpda@6004000 { - compatible = "qcom,coresight-tpda", "arm,primecell"; - reg = <0x6004000 0x1000>; + compatible = "qcom,coresight-tpda", "arm,primecell"; + reg = <0x6004000 0x1000>; - clocks = <&aoss_qmp>; - clock-names = "apb_pclk"; + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; - in-ports { - #address-cells = <1>; - #size-cells = <0>; + in-ports { + #address-cells = <1>; + #size-cells = <0>; port@0 { reg = <0>; tpda_qdss_0_in_tpdm_dcc: endpoint { - remote-endpoint = - <&tpdm_dcc_out_tpda_qdss_0>; - }; + remote-endpoint = <&tpdm_dcc_out_tpda_qdss_0>; + }; }; }; - out-ports { - port { - tpda_qdss_out_funnel_in0: endpoint { - remote-endpoint = - <&funnel_in0_in_tpda_qdss>; - }; + out-ports { + port { + tpda_qdss_out_funnel_in0: endpoint { + remote-endpoint = <&funnel_in0_in_tpda_qdss>; }; - }; + }; + }; }; ... -- cgit v1.2.3-59-g8ed1b From caa41c47dab7e1054f587e592ab21296e3a6781c Mon Sep 17 00:00:00 2001 From: Anshuman Khandual Date: Thu, 14 Mar 2024 11:28:33 +0530 Subject: coresight: etm4x: Fix unbalanced pm_runtime_enable() There is an unbalanced pm_runtime_enable() in etm4_probe_platform_dev() when etm4_probe() fails. This problem can be observed via the coresight etm4 module's (load -> unload -> load) sequence when etm4_probe() fails in etm4_probe_platform_dev(). [ 63.379943] coresight-etm4x 7040000.etm: Unbalanced pm_runtime_enable! [ 63.393630] coresight-etm4x 7140000.etm: Unbalanced pm_runtime_enable! [ 63.407455] coresight-etm4x 7240000.etm: Unbalanced pm_runtime_enable! [ 63.420983] coresight-etm4x 7340000.etm: Unbalanced pm_runtime_enable! [ 63.420999] coresight-etm4x 7440000.etm: Unbalanced pm_runtime_enable! [ 63.441209] coresight-etm4x 7540000.etm: Unbalanced pm_runtime_enable! [ 63.454689] coresight-etm4x 7640000.etm: Unbalanced pm_runtime_enable! [ 63.474982] coresight-etm4x 7740000.etm: Unbalanced pm_runtime_enable! This fixes the above problem - with an explicit pm_runtime_disable() call when etm4_probe() fails during etm4_probe_platform_dev(). Cc: Lorenzo Pieralisi Cc: Hanjun Guo Cc: Sudeep Holla Cc: "Rafael J. Wysocki" Cc: Len Brown Cc: Suzuki K Poulose Cc: Mike Leach Cc: James Clark Cc: Leo Yan Cc: linux-acpi@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org Cc: linux-kernel@vger.kernel.org Cc: coresight@lists.linaro.org Fixes: 5214b563588e ("coresight: etm4x: Add support for sysreg only devices") Reviewed-by: James Clark Signed-off-by: Anshuman Khandual Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20240314055843.2625883-2-anshuman.khandual@arm.com --- drivers/hwtracing/coresight/coresight-etm4x-core.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c index c2ca4a02dfce..06a9b94b8c13 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c @@ -2213,6 +2213,9 @@ static int etm4_probe_platform_dev(struct platform_device *pdev) ret = etm4_probe(&pdev->dev); pm_runtime_put(&pdev->dev); + if (ret) + pm_runtime_disable(&pdev->dev); + return ret; } -- cgit v1.2.3-59-g8ed1b From 852e9a32058a73702c016a8be10c60375276e46e Mon Sep 17 00:00:00 2001 From: Anshuman Khandual Date: Thu, 14 Mar 2024 11:28:34 +0530 Subject: coresight: stm: Extract device name from AMBA pid based table lookup Instead of using AMBA private data field, extract the device name from AMBA pid based table lookup using new coresight_get_uci_data_from_amba() helper. Cc: Suzuki K Poulose Cc: Mike Leach Cc: James Clark Cc: coresight@lists.linaro.org Cc: linux-arm-kernel@lists.infradead.org Cc: linux-kernel@vger.kernel.org Cc: linux-stm32@st-md-mailman.stormreply.com Reviewed-by: James Clark Signed-off-by: Anshuman Khandual Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20240314055843.2625883-3-anshuman.khandual@arm.com --- drivers/hwtracing/coresight/coresight-priv.h | 10 ++++++++++ drivers/hwtracing/coresight/coresight-stm.c | 12 +++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h index eb365236f9a9..fc3617642b01 100644 --- a/drivers/hwtracing/coresight/coresight-priv.h +++ b/drivers/hwtracing/coresight/coresight-priv.h @@ -222,6 +222,16 @@ static inline void *coresight_get_uci_data(const struct amba_id *id) return uci_id->data; } +static inline void *coresight_get_uci_data_from_amba(const struct amba_id *table, u32 pid) +{ + while (table->mask) { + if ((pid & table->mask) == table->id) + return coresight_get_uci_data(table); + table++; + }; + return NULL; +} + void coresight_release_platform_data(struct coresight_device *csdev, struct device *dev, struct coresight_platform_data *pdata); diff --git a/drivers/hwtracing/coresight/coresight-stm.c b/drivers/hwtracing/coresight/coresight-stm.c index 974d37e5f94c..5ae24c33c846 100644 --- a/drivers/hwtracing/coresight/coresight-stm.c +++ b/drivers/hwtracing/coresight/coresight-stm.c @@ -800,6 +800,16 @@ static void stm_init_generic_data(struct stm_drvdata *drvdata, drvdata->stm.set_options = stm_generic_set_options; } +static const struct amba_id stm_ids[]; + +static char *stm_csdev_name(struct coresight_device *csdev) +{ + u32 stm_pid = coresight_get_pid(&csdev->access); + void *uci_data = coresight_get_uci_data_from_amba(stm_ids, stm_pid); + + return uci_data ? (char *)uci_data : "STM"; +} + static int stm_probe(struct amba_device *adev, const struct amba_id *id) { int ret, trace_id; @@ -896,7 +906,7 @@ static int stm_probe(struct amba_device *adev, const struct amba_id *id) pm_runtime_put(&adev->dev); dev_info(&drvdata->csdev->dev, "%s initialized\n", - (char *)coresight_get_uci_data(id)); + stm_csdev_name(drvdata->csdev)); return 0; cs_unregister: -- cgit v1.2.3-59-g8ed1b From 3ab210297c31b8fef1cfb2aa3d85b227b9ace09b Mon Sep 17 00:00:00 2001 From: Anshuman Khandual Date: Thu, 14 Mar 2024 11:28:35 +0530 Subject: coresight: tmc: Extract device properties from AMBA pid based table lookup This extracts device properties from AMBA pid based table lookup. But first this modifies tmc_etr_setup_caps() to accept csdev access. Cc: Suzuki K Poulose Cc: Mike Leach Cc: James Clark Cc: coresight@lists.linaro.org Cc: linux-arm-kernel@lists.infradead.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Anshuman Khandual Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20240314055843.2625883-4-anshuman.khandual@arm.com --- drivers/hwtracing/coresight/coresight-tmc-core.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-tmc-core.c b/drivers/hwtracing/coresight/coresight-tmc-core.c index 72005b0c633e..1a5ca65d8677 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-core.c +++ b/drivers/hwtracing/coresight/coresight-tmc-core.c @@ -370,16 +370,23 @@ static inline bool tmc_etr_has_non_secure_access(struct tmc_drvdata *drvdata) return (auth & TMC_AUTH_NSID_MASK) == 0x3; } +static const struct amba_id tmc_ids[]; + /* Detect and initialise the capabilities of a TMC ETR */ -static int tmc_etr_setup_caps(struct device *parent, u32 devid, void *dev_caps) +static int tmc_etr_setup_caps(struct device *parent, u32 devid, + struct csdev_access *access) { int rc; - u32 dma_mask = 0; + u32 tmc_pid, dma_mask = 0; struct tmc_drvdata *drvdata = dev_get_drvdata(parent); + void *dev_caps; if (!tmc_etr_has_non_secure_access(drvdata)) return -EACCES; + tmc_pid = coresight_get_pid(access); + dev_caps = coresight_get_uci_data_from_amba(tmc_ids, tmc_pid); + /* Set the unadvertised capabilities */ tmc_etr_init_caps(drvdata, (u32)(unsigned long)dev_caps); @@ -497,8 +504,7 @@ static int tmc_probe(struct amba_device *adev, const struct amba_id *id) desc.type = CORESIGHT_DEV_TYPE_SINK; desc.subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_SYSMEM; desc.ops = &tmc_etr_cs_ops; - ret = tmc_etr_setup_caps(dev, devid, - coresight_get_uci_data(id)); + ret = tmc_etr_setup_caps(dev, devid, &desc.access); if (ret) goto out; idr_init(&drvdata->idr); -- cgit v1.2.3-59-g8ed1b From 075b7cd7ad7dec8651a6a6654fa5ebae436ac00f Mon Sep 17 00:00:00 2001 From: Anshuman Khandual Date: Thu, 14 Mar 2024 11:28:36 +0530 Subject: coresight: Add helpers registering/removing both AMBA and platform drivers This adds two different helpers i.e coresight_init_driver()/remove_driver() enabling coresight devices to register or remove AMBA and platform drivers. This changes replicator and funnel devices to use above new helpers. Cc: Suzuki K Poulose Cc: Mike Leach Cc: James Clark Cc: Leo Yan Cc: Alexander Shishkin Cc: linux-arm-kernel@lists.infradead.org Cc: linux-kernel@vger.kernel.org Cc: coresight@lists.linaro.org Reviewed-by: James Clark Signed-off-by: Anshuman Khandual Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20240314055843.2625883-5-anshuman.khandual@arm.com --- drivers/hwtracing/coresight/coresight-core.c | 29 ++++++++++++++++++++++ drivers/hwtracing/coresight/coresight-funnel.c | 19 ++------------ drivers/hwtracing/coresight/coresight-replicator.c | 20 +++------------ include/linux/coresight.h | 7 ++++++ 4 files changed, 41 insertions(+), 34 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c index b83613e34289..9fc6f6b863e0 100644 --- a/drivers/hwtracing/coresight/coresight-core.c +++ b/drivers/hwtracing/coresight/coresight-core.c @@ -1398,6 +1398,35 @@ static void __exit coresight_exit(void) module_init(coresight_init); module_exit(coresight_exit); +int coresight_init_driver(const char *drv, struct amba_driver *amba_drv, + struct platform_driver *pdev_drv) +{ + int ret; + + ret = amba_driver_register(amba_drv); + if (ret) { + pr_err("%s: error registering AMBA driver\n", drv); + return ret; + } + + ret = platform_driver_register(pdev_drv); + if (!ret) + return 0; + + pr_err("%s: error registering platform driver\n", drv); + amba_driver_unregister(amba_drv); + return ret; +} +EXPORT_SYMBOL_GPL(coresight_init_driver); + +void coresight_remove_driver(struct amba_driver *amba_drv, + struct platform_driver *pdev_drv) +{ + amba_driver_unregister(amba_drv); + platform_driver_unregister(pdev_drv); +} +EXPORT_SYMBOL_GPL(coresight_remove_driver); + MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Pratik Patel "); MODULE_AUTHOR("Mathieu Poirier "); diff --git a/drivers/hwtracing/coresight/coresight-funnel.c b/drivers/hwtracing/coresight/coresight-funnel.c index ef1a0abfee4e..ff3ea0670a5b 100644 --- a/drivers/hwtracing/coresight/coresight-funnel.c +++ b/drivers/hwtracing/coresight/coresight-funnel.c @@ -410,27 +410,12 @@ static struct amba_driver dynamic_funnel_driver = { static int __init funnel_init(void) { - int ret; - - ret = platform_driver_register(&static_funnel_driver); - if (ret) { - pr_info("Error registering platform driver\n"); - return ret; - } - - ret = amba_driver_register(&dynamic_funnel_driver); - if (ret) { - pr_info("Error registering amba driver\n"); - platform_driver_unregister(&static_funnel_driver); - } - - return ret; + return coresight_init_driver("funnel", &dynamic_funnel_driver, &static_funnel_driver); } static void __exit funnel_exit(void) { - platform_driver_unregister(&static_funnel_driver); - amba_driver_unregister(&dynamic_funnel_driver); + coresight_remove_driver(&dynamic_funnel_driver, &static_funnel_driver); } module_init(funnel_init); diff --git a/drivers/hwtracing/coresight/coresight-replicator.c b/drivers/hwtracing/coresight/coresight-replicator.c index 73452d9dc13b..ddb530a8436f 100644 --- a/drivers/hwtracing/coresight/coresight-replicator.c +++ b/drivers/hwtracing/coresight/coresight-replicator.c @@ -416,27 +416,13 @@ static struct amba_driver dynamic_replicator_driver = { static int __init replicator_init(void) { - int ret; - - ret = platform_driver_register(&static_replicator_driver); - if (ret) { - pr_info("Error registering platform driver\n"); - return ret; - } - - ret = amba_driver_register(&dynamic_replicator_driver); - if (ret) { - pr_info("Error registering amba driver\n"); - platform_driver_unregister(&static_replicator_driver); - } - - return ret; + return coresight_init_driver("replicator", &dynamic_replicator_driver, + &static_replicator_driver); } static void __exit replicator_exit(void) { - platform_driver_unregister(&static_replicator_driver); - amba_driver_unregister(&dynamic_replicator_driver); + coresight_remove_driver(&dynamic_replicator_driver, &static_replicator_driver); } module_init(replicator_init); diff --git a/include/linux/coresight.h b/include/linux/coresight.h index 5f288d475490..653f1712eb77 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -12,6 +12,8 @@ #include #include #include +#include +#include /* Peripheral id registers (0xFD0-0xFEC) */ #define CORESIGHT_PERIPHIDR4 0xfd0 @@ -658,4 +660,9 @@ coresight_find_output_type(struct coresight_platform_data *pdata, enum coresight_dev_type type, union coresight_dev_subtype subtype); +int coresight_init_driver(const char *drv, struct amba_driver *amba_drv, + struct platform_driver *pdev_drv); + +void coresight_remove_driver(struct amba_driver *amba_drv, + struct platform_driver *pdev_drv); #endif /* _LINUX_COREISGHT_H */ -- cgit v1.2.3-59-g8ed1b From b448c4c72ca3327232dfb20d0065b693b3fcc2e2 Mon Sep 17 00:00:00 2001 From: Anshuman Khandual Date: Thu, 14 Mar 2024 11:28:37 +0530 Subject: coresight: replicator: Move ACPI support from AMBA driver to platform driver Add support for the dynamic replicator device in the platform driver, which can then be used on ACPI based platforms. This change would now allow runtime power management for replicator devices on ACPI based systems. The driver would try to enable the APB clock if available. Also, rename the code to reflect the fact that it now handles both static and dynamic replicators. But first this refactors replicator_probe() making sure it can be used both for platform and AMBA drivers, by moving the pm_runtime_put() to the callers. Cc: Lorenzo Pieralisi Cc: Sudeep Holla Cc: Suzuki K Poulose Cc: Mike Leach Cc: James Clark Cc: linux-acpi@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org Cc: linux-kernel@vger.kernel.org Cc: coresight@lists.linaro.org Tested-by: Sudeep Holla # Boot and driver probe only Acked-by: Sudeep Holla # For ACPI related changes Reviewed-by: James Clark Signed-off-by: Anshuman Khandual Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20240314055843.2625883-6-anshuman.khandual@arm.com --- drivers/acpi/arm64/amba.c | 1 - drivers/hwtracing/coresight/coresight-replicator.c | 68 ++++++++++++++-------- 2 files changed, 45 insertions(+), 24 deletions(-) diff --git a/drivers/acpi/arm64/amba.c b/drivers/acpi/arm64/amba.c index 171b5c2c7edd..270f4e3819a2 100644 --- a/drivers/acpi/arm64/amba.c +++ b/drivers/acpi/arm64/amba.c @@ -27,7 +27,6 @@ static const struct acpi_device_id amba_id_list[] = { {"ARMHC503", 0}, /* ARM CoreSight Debug */ {"ARMHC979", 0}, /* ARM CoreSight TPIU */ {"ARMHC97C", 0}, /* ARM CoreSight SoC-400 TMC, SoC-600 ETF/ETB */ - {"ARMHC98D", 0}, /* ARM CoreSight Dynamic Replicator */ {"ARMHC9CA", 0}, /* ARM CoreSight CATU */ {"ARMHC9FF", 0}, /* ARM CoreSight Dynamic Funnel */ {"", 0}, diff --git a/drivers/hwtracing/coresight/coresight-replicator.c b/drivers/hwtracing/coresight/coresight-replicator.c index ddb530a8436f..87e590cf1678 100644 --- a/drivers/hwtracing/coresight/coresight-replicator.c +++ b/drivers/hwtracing/coresight/coresight-replicator.c @@ -31,6 +31,7 @@ DEFINE_CORESIGHT_DEVLIST(replicator_devs, "replicator"); * @base: memory mapped base address for this component. Also indicates * whether this one is programmable or not. * @atclk: optional clock for the core parts of the replicator. + * @pclk: APB clock if present, otherwise NULL * @csdev: component vitals needed by the framework * @spinlock: serialize enable/disable operations. * @check_idfilter_val: check if the context is lost upon clock removal. @@ -38,6 +39,7 @@ DEFINE_CORESIGHT_DEVLIST(replicator_devs, "replicator"); struct replicator_drvdata { void __iomem *base; struct clk *atclk; + struct clk *pclk; struct coresight_device *csdev; spinlock_t spinlock; bool check_idfilter_val; @@ -243,6 +245,10 @@ static int replicator_probe(struct device *dev, struct resource *res) return ret; } + drvdata->pclk = coresight_get_enable_apb_pclk(dev); + if (IS_ERR(drvdata->pclk)) + return -ENODEV; + /* * Map the device base for dynamic-replicator, which has been * validated by AMBA core @@ -285,11 +291,12 @@ static int replicator_probe(struct device *dev, struct resource *res) } replicator_reset(drvdata); - pm_runtime_put(dev); out_disable_clk: if (ret && !IS_ERR_OR_NULL(drvdata->atclk)) clk_disable_unprepare(drvdata->atclk); + if (ret && !IS_ERR_OR_NULL(drvdata->pclk)) + clk_disable_unprepare(drvdata->pclk); return ret; } @@ -301,29 +308,34 @@ static int replicator_remove(struct device *dev) return 0; } -static int static_replicator_probe(struct platform_device *pdev) +static int replicator_platform_probe(struct platform_device *pdev) { + struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); int ret; pm_runtime_get_noresume(&pdev->dev); pm_runtime_set_active(&pdev->dev); pm_runtime_enable(&pdev->dev); - /* Static replicators do not have programming base */ - ret = replicator_probe(&pdev->dev, NULL); - - if (ret) { - pm_runtime_put_noidle(&pdev->dev); + ret = replicator_probe(&pdev->dev, res); + pm_runtime_put(&pdev->dev); + if (ret) pm_runtime_disable(&pdev->dev); - } return ret; } -static void static_replicator_remove(struct platform_device *pdev) +static void replicator_platform_remove(struct platform_device *pdev) { + struct replicator_drvdata *drvdata = dev_get_drvdata(&pdev->dev); + + if (WARN_ON(!drvdata)) + return; + replicator_remove(&pdev->dev); pm_runtime_disable(&pdev->dev); + if (!IS_ERR_OR_NULL(drvdata->pclk)) + clk_put(drvdata->pclk); } #ifdef CONFIG_PM @@ -334,6 +346,8 @@ static int replicator_runtime_suspend(struct device *dev) if (drvdata && !IS_ERR(drvdata->atclk)) clk_disable_unprepare(drvdata->atclk); + if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk)) + clk_disable_unprepare(drvdata->pclk); return 0; } @@ -344,6 +358,8 @@ static int replicator_runtime_resume(struct device *dev) if (drvdata && !IS_ERR(drvdata->atclk)) clk_prepare_enable(drvdata->atclk); + if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk)) + clk_prepare_enable(drvdata->pclk); return 0; } #endif @@ -353,31 +369,32 @@ static const struct dev_pm_ops replicator_dev_pm_ops = { replicator_runtime_resume, NULL) }; -static const struct of_device_id static_replicator_match[] = { +static const struct of_device_id replicator_match[] = { {.compatible = "arm,coresight-replicator"}, {.compatible = "arm,coresight-static-replicator"}, {} }; -MODULE_DEVICE_TABLE(of, static_replicator_match); +MODULE_DEVICE_TABLE(of, replicator_match); #ifdef CONFIG_ACPI -static const struct acpi_device_id static_replicator_acpi_ids[] = { +static const struct acpi_device_id replicator_acpi_ids[] = { {"ARMHC985", 0, 0, 0}, /* ARM CoreSight Static Replicator */ + {"ARMHC98D", 0, 0, 0}, /* ARM CoreSight Dynamic Replicator */ {} }; -MODULE_DEVICE_TABLE(acpi, static_replicator_acpi_ids); +MODULE_DEVICE_TABLE(acpi, replicator_acpi_ids); #endif -static struct platform_driver static_replicator_driver = { - .probe = static_replicator_probe, - .remove_new = static_replicator_remove, +static struct platform_driver replicator_driver = { + .probe = replicator_platform_probe, + .remove_new = replicator_platform_remove, .driver = { - .name = "coresight-static-replicator", + .name = "coresight-replicator", /* THIS_MODULE is taken care of by platform_driver_register() */ - .of_match_table = of_match_ptr(static_replicator_match), - .acpi_match_table = ACPI_PTR(static_replicator_acpi_ids), + .of_match_table = of_match_ptr(replicator_match), + .acpi_match_table = ACPI_PTR(replicator_acpi_ids), .pm = &replicator_dev_pm_ops, .suppress_bind_attrs = true, }, @@ -386,7 +403,13 @@ static struct platform_driver static_replicator_driver = { static int dynamic_replicator_probe(struct amba_device *adev, const struct amba_id *id) { - return replicator_probe(&adev->dev, &adev->res); + int ret; + + ret = replicator_probe(&adev->dev, &adev->res); + if (!ret) + pm_runtime_put(&adev->dev); + + return ret; } static void dynamic_replicator_remove(struct amba_device *adev) @@ -416,13 +439,12 @@ static struct amba_driver dynamic_replicator_driver = { static int __init replicator_init(void) { - return coresight_init_driver("replicator", &dynamic_replicator_driver, - &static_replicator_driver); + return coresight_init_driver("replicator", &dynamic_replicator_driver, &replicator_driver); } static void __exit replicator_exit(void) { - coresight_remove_driver(&dynamic_replicator_driver, &static_replicator_driver); + coresight_remove_driver(&dynamic_replicator_driver, &replicator_driver); } module_init(replicator_init); -- cgit v1.2.3-59-g8ed1b From 8e3227ddfbd7216f14186ec534f43e9dbcde717c Mon Sep 17 00:00:00 2001 From: Anshuman Khandual Date: Thu, 14 Mar 2024 11:28:38 +0530 Subject: coresight: funnel: Move ACPI support from AMBA driver to platform driver Add support for the dynamic funnel device in the platform driver, which can then be used on ACPI based platforms. This change would allow runtime power management for ACPI based systems. The driver would try to enable the APB clock if available. Also, rename the code to reflect the fact that it now handles both static and dynamic funnels. But first this refactors funnel_probe() making sure it can be used both for platform and AMBA drivers, by moving the pm_runtime_put() to the callers. Cc: Lorenzo Pieralisi Cc: Sudeep Holla Cc: Suzuki K Poulose Cc: Mike Leach Cc: James Clark Cc: linux-acpi@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org Cc: linux-kernel@vger.kernel.org Cc: coresight@lists.linaro.org Tested-by: Sudeep Holla # Boot and driver probe only Acked-by: Sudeep Holla # For ACPI related changes Reviewed-by: James Clark Signed-off-by: Anshuman Khandual Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20240314055843.2625883-7-anshuman.khandual@arm.com --- drivers/acpi/arm64/amba.c | 1 - drivers/hwtracing/coresight/coresight-funnel.c | 72 +++++++++++++++++--------- 2 files changed, 48 insertions(+), 25 deletions(-) diff --git a/drivers/acpi/arm64/amba.c b/drivers/acpi/arm64/amba.c index 270f4e3819a2..afb6afb66967 100644 --- a/drivers/acpi/arm64/amba.c +++ b/drivers/acpi/arm64/amba.c @@ -28,7 +28,6 @@ static const struct acpi_device_id amba_id_list[] = { {"ARMHC979", 0}, /* ARM CoreSight TPIU */ {"ARMHC97C", 0}, /* ARM CoreSight SoC-400 TMC, SoC-600 ETF/ETB */ {"ARMHC9CA", 0}, /* ARM CoreSight CATU */ - {"ARMHC9FF", 0}, /* ARM CoreSight Dynamic Funnel */ {"", 0}, }; diff --git a/drivers/hwtracing/coresight/coresight-funnel.c b/drivers/hwtracing/coresight/coresight-funnel.c index ff3ea0670a5b..616735dc80a6 100644 --- a/drivers/hwtracing/coresight/coresight-funnel.c +++ b/drivers/hwtracing/coresight/coresight-funnel.c @@ -36,6 +36,7 @@ DEFINE_CORESIGHT_DEVLIST(funnel_devs, "funnel"); * struct funnel_drvdata - specifics associated to a funnel component * @base: memory mapped base address for this component. * @atclk: optional clock for the core parts of the funnel. + * @pclk: APB clock if present, otherwise NULL * @csdev: component vitals needed by the framework. * @priority: port selection order. * @spinlock: serialize enable/disable operations. @@ -43,6 +44,7 @@ DEFINE_CORESIGHT_DEVLIST(funnel_devs, "funnel"); struct funnel_drvdata { void __iomem *base; struct clk *atclk; + struct clk *pclk; struct coresight_device *csdev; unsigned long priority; spinlock_t spinlock; @@ -236,6 +238,10 @@ static int funnel_probe(struct device *dev, struct resource *res) return ret; } + drvdata->pclk = coresight_get_enable_apb_pclk(dev); + if (IS_ERR(drvdata->pclk)) + return -ENODEV; + /* * Map the device base for dynamic-funnel, which has been * validated by AMBA core. @@ -272,12 +278,13 @@ static int funnel_probe(struct device *dev, struct resource *res) goto out_disable_clk; } - pm_runtime_put(dev); ret = 0; out_disable_clk: if (ret && !IS_ERR_OR_NULL(drvdata->atclk)) clk_disable_unprepare(drvdata->atclk); + if (ret && !IS_ERR_OR_NULL(drvdata->pclk)) + clk_disable_unprepare(drvdata->pclk); return ret; } @@ -298,6 +305,9 @@ static int funnel_runtime_suspend(struct device *dev) if (drvdata && !IS_ERR(drvdata->atclk)) clk_disable_unprepare(drvdata->atclk); + if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk)) + clk_disable_unprepare(drvdata->pclk); + return 0; } @@ -308,6 +318,8 @@ static int funnel_runtime_resume(struct device *dev) if (drvdata && !IS_ERR(drvdata->atclk)) clk_prepare_enable(drvdata->atclk); + if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk)) + clk_prepare_enable(drvdata->pclk); return 0; } #endif @@ -316,55 +328,61 @@ static const struct dev_pm_ops funnel_dev_pm_ops = { SET_RUNTIME_PM_OPS(funnel_runtime_suspend, funnel_runtime_resume, NULL) }; -static int static_funnel_probe(struct platform_device *pdev) +static int funnel_platform_probe(struct platform_device *pdev) { + struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); int ret; pm_runtime_get_noresume(&pdev->dev); pm_runtime_set_active(&pdev->dev); pm_runtime_enable(&pdev->dev); - /* Static funnel do not have programming base */ - ret = funnel_probe(&pdev->dev, NULL); - - if (ret) { - pm_runtime_put_noidle(&pdev->dev); + ret = funnel_probe(&pdev->dev, res); + pm_runtime_put(&pdev->dev); + if (ret) pm_runtime_disable(&pdev->dev); - } return ret; } -static void static_funnel_remove(struct platform_device *pdev) +static void funnel_platform_remove(struct platform_device *pdev) { + struct funnel_drvdata *drvdata = dev_get_drvdata(&pdev->dev); + + if (WARN_ON(!drvdata)) + return; + funnel_remove(&pdev->dev); pm_runtime_disable(&pdev->dev); + if (!IS_ERR_OR_NULL(drvdata->pclk)) + clk_put(drvdata->pclk); } -static const struct of_device_id static_funnel_match[] = { +static const struct of_device_id funnel_match[] = { {.compatible = "arm,coresight-static-funnel"}, {} }; -MODULE_DEVICE_TABLE(of, static_funnel_match); +MODULE_DEVICE_TABLE(of, funnel_match); #ifdef CONFIG_ACPI -static const struct acpi_device_id static_funnel_ids[] = { - {"ARMHC9FE", 0, 0, 0}, +static const struct acpi_device_id funnel_acpi_ids[] = { + {"ARMHC9FE", 0, 0, 0}, /* ARM Coresight Static Funnel */ + {"ARMHC9FF", 0, 0, 0}, /* ARM CoreSight Dynamic Funnel */ {}, }; -MODULE_DEVICE_TABLE(acpi, static_funnel_ids); +MODULE_DEVICE_TABLE(acpi, funnel_acpi_ids); #endif -static struct platform_driver static_funnel_driver = { - .probe = static_funnel_probe, - .remove_new = static_funnel_remove, - .driver = { - .name = "coresight-static-funnel", +static struct platform_driver funnel_driver = { + .probe = funnel_platform_probe, + .remove_new = funnel_platform_remove, + .driver = { + .name = "coresight-funnel", /* THIS_MODULE is taken care of by platform_driver_register() */ - .of_match_table = static_funnel_match, - .acpi_match_table = ACPI_PTR(static_funnel_ids), + .of_match_table = funnel_match, + .acpi_match_table = ACPI_PTR(funnel_acpi_ids), .pm = &funnel_dev_pm_ops, .suppress_bind_attrs = true, }, @@ -373,7 +391,13 @@ static struct platform_driver static_funnel_driver = { static int dynamic_funnel_probe(struct amba_device *adev, const struct amba_id *id) { - return funnel_probe(&adev->dev, &adev->res); + int ret; + + ret = funnel_probe(&adev->dev, &adev->res); + if (!ret) + pm_runtime_put(&adev->dev); + + return ret; } static void dynamic_funnel_remove(struct amba_device *adev) @@ -410,12 +434,12 @@ static struct amba_driver dynamic_funnel_driver = { static int __init funnel_init(void) { - return coresight_init_driver("funnel", &dynamic_funnel_driver, &static_funnel_driver); + return coresight_init_driver("funnel", &dynamic_funnel_driver, &funnel_driver); } static void __exit funnel_exit(void) { - coresight_remove_driver(&dynamic_funnel_driver, &static_funnel_driver); + coresight_remove_driver(&dynamic_funnel_driver, &funnel_driver); } module_init(funnel_init); -- cgit v1.2.3-59-g8ed1b From 23567323857d2073197953bb158413be1aceca8b Mon Sep 17 00:00:00 2001 From: Anshuman Khandual Date: Thu, 14 Mar 2024 11:28:39 +0530 Subject: coresight: catu: Move ACPI support from AMBA driver to platform driver Add support for the catu devices in a new platform driver, which can then be used on ACPI based platforms. This change would now allow runtime power management for ACPI based systems. The driver would try to enable the APB clock if available. But first this renames and then refactors catu_probe() and catu_remove(), making sure it can be used both for platform and AMBA drivers. This also moves pm_runtime_put() from catu_probe() to the callers. Cc: Lorenzo Pieralisi Cc: Sudeep Holla Cc: Suzuki K Poulose Cc: Mike Leach Cc: James Clark Cc: linux-acpi@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org Cc: linux-kernel@vger.kernel.org Cc: coresight@lists.linaro.org Acked-by: Sudeep Holla # For ACPI related changes Reviewed-by: James Clark Signed-off-by: Anshuman Khandual Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20240314055843.2625883-8-anshuman.khandual@arm.com --- drivers/acpi/arm64/amba.c | 1 - drivers/hwtracing/coresight/coresight-catu.c | 138 +++++++++++++++++++++++---- drivers/hwtracing/coresight/coresight-catu.h | 1 + 3 files changed, 120 insertions(+), 20 deletions(-) diff --git a/drivers/acpi/arm64/amba.c b/drivers/acpi/arm64/amba.c index afb6afb66967..587061b0fd2f 100644 --- a/drivers/acpi/arm64/amba.c +++ b/drivers/acpi/arm64/amba.c @@ -27,7 +27,6 @@ static const struct acpi_device_id amba_id_list[] = { {"ARMHC503", 0}, /* ARM CoreSight Debug */ {"ARMHC979", 0}, /* ARM CoreSight TPIU */ {"ARMHC97C", 0}, /* ARM CoreSight SoC-400 TMC, SoC-600 ETF/ETB */ - {"ARMHC9CA", 0}, /* ARM CoreSight CATU */ {"", 0}, }; diff --git a/drivers/hwtracing/coresight/coresight-catu.c b/drivers/hwtracing/coresight/coresight-catu.c index 3949ded0d4fa..9712be6acd26 100644 --- a/drivers/hwtracing/coresight/coresight-catu.c +++ b/drivers/hwtracing/coresight/coresight-catu.c @@ -7,11 +7,13 @@ * Author: Suzuki K Poulose */ +#include #include #include #include #include #include +#include #include #include "coresight-catu.h" @@ -502,28 +504,20 @@ static const struct coresight_ops catu_ops = { .helper_ops = &catu_helper_ops, }; -static int catu_probe(struct amba_device *adev, const struct amba_id *id) +static int __catu_probe(struct device *dev, struct resource *res) { int ret = 0; u32 dma_mask; - struct catu_drvdata *drvdata; + struct catu_drvdata *drvdata = dev_get_drvdata(dev); struct coresight_desc catu_desc; struct coresight_platform_data *pdata = NULL; - struct device *dev = &adev->dev; void __iomem *base; catu_desc.name = coresight_alloc_device_name(&catu_devs, dev); if (!catu_desc.name) return -ENOMEM; - drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); - if (!drvdata) { - ret = -ENOMEM; - goto out; - } - - dev_set_drvdata(dev, drvdata); - base = devm_ioremap_resource(dev, &adev->res); + base = devm_ioremap_resource(dev, res); if (IS_ERR(base)) { ret = PTR_ERR(base); goto out; @@ -567,19 +561,39 @@ static int catu_probe(struct amba_device *adev, const struct amba_id *id) drvdata->csdev = coresight_register(&catu_desc); if (IS_ERR(drvdata->csdev)) ret = PTR_ERR(drvdata->csdev); - else - pm_runtime_put(&adev->dev); out: return ret; } -static void catu_remove(struct amba_device *adev) +static int catu_probe(struct amba_device *adev, const struct amba_id *id) { - struct catu_drvdata *drvdata = dev_get_drvdata(&adev->dev); + struct catu_drvdata *drvdata; + int ret; + + drvdata = devm_kzalloc(&adev->dev, sizeof(*drvdata), GFP_KERNEL); + if (!drvdata) + return -ENOMEM; + + amba_set_drvdata(adev, drvdata); + ret = __catu_probe(&adev->dev, &adev->res); + if (!ret) + pm_runtime_put(&adev->dev); + + return ret; +} + +static void __catu_remove(struct device *dev) +{ + struct catu_drvdata *drvdata = dev_get_drvdata(dev); coresight_unregister(drvdata->csdev); } +static void catu_remove(struct amba_device *adev) +{ + __catu_remove(&adev->dev); +} + static struct amba_id catu_ids[] = { CS_AMBA_ID(0x000bb9ee), {}, @@ -598,13 +612,99 @@ static struct amba_driver catu_driver = { .id_table = catu_ids, }; +static int catu_platform_probe(struct platform_device *pdev) +{ + struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + struct catu_drvdata *drvdata; + int ret = 0; + + drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL); + if (!drvdata) + return -ENOMEM; + + drvdata->pclk = coresight_get_enable_apb_pclk(&pdev->dev); + if (IS_ERR(drvdata->pclk)) + return -ENODEV; + + pm_runtime_get_noresume(&pdev->dev); + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + + dev_set_drvdata(&pdev->dev, drvdata); + ret = __catu_probe(&pdev->dev, res); + pm_runtime_put(&pdev->dev); + if (ret) { + pm_runtime_disable(&pdev->dev); + if (!IS_ERR_OR_NULL(drvdata->pclk)) + clk_put(drvdata->pclk); + } + + return ret; +} + +static int catu_platform_remove(struct platform_device *pdev) +{ + struct catu_drvdata *drvdata = dev_get_drvdata(&pdev->dev); + + if (WARN_ON(!drvdata)) + return -ENODEV; + + __catu_remove(&pdev->dev); + pm_runtime_disable(&pdev->dev); + if (!IS_ERR_OR_NULL(drvdata->pclk)) + clk_put(drvdata->pclk); + return 0; +} + +#ifdef CONFIG_PM +static int catu_runtime_suspend(struct device *dev) +{ + struct catu_drvdata *drvdata = dev_get_drvdata(dev); + + if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk)) + clk_disable_unprepare(drvdata->pclk); + return 0; +} + +static int catu_runtime_resume(struct device *dev) +{ + struct catu_drvdata *drvdata = dev_get_drvdata(dev); + + if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk)) + clk_prepare_enable(drvdata->pclk); + return 0; +} +#endif + +static const struct dev_pm_ops catu_dev_pm_ops = { + SET_RUNTIME_PM_OPS(catu_runtime_suspend, catu_runtime_resume, NULL) +}; + +#ifdef CONFIG_ACPI +static const struct acpi_device_id catu_acpi_ids[] = { + {"ARMHC9CA", 0, 0, 0}, /* ARM CoreSight CATU */ + {}, +}; + +MODULE_DEVICE_TABLE(acpi, catu_acpi_ids); +#endif + +static struct platform_driver catu_platform_driver = { + .probe = catu_platform_probe, + .remove = catu_platform_remove, + .driver = { + .name = "coresight-catu-platform", + .acpi_match_table = ACPI_PTR(catu_acpi_ids), + .suppress_bind_attrs = true, + .pm = &catu_dev_pm_ops, + }, +}; + static int __init catu_init(void) { int ret; - ret = amba_driver_register(&catu_driver); - if (ret) - pr_info("Error registering catu driver\n"); + ret = coresight_init_driver("catu", &catu_driver, &catu_platform_driver); tmc_etr_set_catu_ops(&etr_catu_buf_ops); return ret; } @@ -612,7 +712,7 @@ static int __init catu_init(void) static void __exit catu_exit(void) { tmc_etr_remove_catu_ops(); - amba_driver_unregister(&catu_driver); + coresight_remove_driver(&catu_driver, &catu_platform_driver); } module_init(catu_init); diff --git a/drivers/hwtracing/coresight/coresight-catu.h b/drivers/hwtracing/coresight/coresight-catu.h index 442e034bbfba..141feac1c14b 100644 --- a/drivers/hwtracing/coresight/coresight-catu.h +++ b/drivers/hwtracing/coresight/coresight-catu.h @@ -61,6 +61,7 @@ #define CATU_IRQEN_OFF 0x0 struct catu_drvdata { + struct clk *pclk; void __iomem *base; struct coresight_device *csdev; int irq; -- cgit v1.2.3-59-g8ed1b From 3d83d4d4904a47626854b6bba44127d21a7dc713 Mon Sep 17 00:00:00 2001 From: Anshuman Khandual Date: Thu, 14 Mar 2024 11:28:40 +0530 Subject: coresight: tpiu: Move ACPI support from AMBA driver to platform driver Add support for the tpiu device in the platform driver, which can then be used on ACPI based platforms. This change would now allow runtime power management for ACPI based systems. The driver would try to enable the APB clock if available. But first this renames and then refactors tpiu_probe() and tpiu_remove(), making sure it can be used both for platform and AMBA drivers. This also moves pm_runtime_put() from tpiu_probe() to the callers. While here, this also sorts the included headers in alphabetic order. Cc: Lorenzo Pieralisi Cc: Sudeep Holla Cc: Suzuki K Poulose Cc: Mike Leach Cc: James Clark Cc: linux-acpi@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org Cc: linux-kernel@vger.kernel.org Cc: coresight@lists.linaro.org Tested-by: Sudeep Holla # Boot and driver probe only Acked-by: Sudeep Holla # For ACPI related changes Reviewed-by: James Clark Signed-off-by: Anshuman Khandual Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20240314055843.2625883-9-anshuman.khandual@arm.com --- drivers/acpi/arm64/amba.c | 1 - drivers/hwtracing/coresight/coresight-tpiu.c | 117 +++++++++++++++++++++++---- 2 files changed, 100 insertions(+), 18 deletions(-) diff --git a/drivers/acpi/arm64/amba.c b/drivers/acpi/arm64/amba.c index 587061b0fd2f..6d24a8f7914b 100644 --- a/drivers/acpi/arm64/amba.c +++ b/drivers/acpi/arm64/amba.c @@ -25,7 +25,6 @@ static const struct acpi_device_id amba_id_list[] = { {"ARMHC501", 0}, /* ARM CoreSight ETR */ {"ARMHC502", 0}, /* ARM CoreSight STM */ {"ARMHC503", 0}, /* ARM CoreSight Debug */ - {"ARMHC979", 0}, /* ARM CoreSight TPIU */ {"ARMHC97C", 0}, /* ARM CoreSight SoC-400 TMC, SoC-600 ETF/ETB */ {"", 0}, }; diff --git a/drivers/hwtracing/coresight/coresight-tpiu.c b/drivers/hwtracing/coresight/coresight-tpiu.c index 29024f880fda..6bf3039839c1 100644 --- a/drivers/hwtracing/coresight/coresight-tpiu.c +++ b/drivers/hwtracing/coresight/coresight-tpiu.c @@ -5,17 +5,19 @@ * Description: CoreSight Trace Port Interface Unit driver */ +#include +#include #include -#include -#include +#include +#include #include -#include #include -#include +#include +#include +#include +#include #include -#include -#include -#include +#include #include "coresight-priv.h" @@ -52,11 +54,13 @@ DEFINE_CORESIGHT_DEVLIST(tpiu_devs, "tpiu"); /* * @base: memory mapped base address for this component. * @atclk: optional clock for the core parts of the TPIU. + * @pclk: APB clock if present, otherwise NULL * @csdev: component vitals needed by the framework. */ struct tpiu_drvdata { void __iomem *base; struct clk *atclk; + struct clk *pclk; struct coresight_device *csdev; spinlock_t spinlock; }; @@ -122,14 +126,12 @@ static const struct coresight_ops tpiu_cs_ops = { .sink_ops = &tpiu_sink_ops, }; -static int tpiu_probe(struct amba_device *adev, const struct amba_id *id) +static int __tpiu_probe(struct device *dev, struct resource *res) { int ret; void __iomem *base; - struct device *dev = &adev->dev; struct coresight_platform_data *pdata = NULL; struct tpiu_drvdata *drvdata; - struct resource *res = &adev->res; struct coresight_desc desc = { 0 }; desc.name = coresight_alloc_device_name(&tpiu_devs, dev); @@ -142,12 +144,16 @@ static int tpiu_probe(struct amba_device *adev, const struct amba_id *id) spin_lock_init(&drvdata->spinlock); - drvdata->atclk = devm_clk_get(&adev->dev, "atclk"); /* optional */ + drvdata->atclk = devm_clk_get(dev, "atclk"); /* optional */ if (!IS_ERR(drvdata->atclk)) { ret = clk_prepare_enable(drvdata->atclk); if (ret) return ret; } + + drvdata->pclk = coresight_get_enable_apb_pclk(dev); + if (IS_ERR(drvdata->pclk)) + return -ENODEV; dev_set_drvdata(dev, drvdata); /* Validity for the resource is already checked by the AMBA core */ @@ -173,21 +179,34 @@ static int tpiu_probe(struct amba_device *adev, const struct amba_id *id) desc.dev = dev; drvdata->csdev = coresight_register(&desc); - if (!IS_ERR(drvdata->csdev)) { - pm_runtime_put(&adev->dev); + if (!IS_ERR(drvdata->csdev)) return 0; - } return PTR_ERR(drvdata->csdev); } -static void tpiu_remove(struct amba_device *adev) +static int tpiu_probe(struct amba_device *adev, const struct amba_id *id) +{ + int ret; + + ret = __tpiu_probe(&adev->dev, &adev->res); + if (!ret) + pm_runtime_put(&adev->dev); + return ret; +} + +static void __tpiu_remove(struct device *dev) { - struct tpiu_drvdata *drvdata = dev_get_drvdata(&adev->dev); + struct tpiu_drvdata *drvdata = dev_get_drvdata(dev); coresight_unregister(drvdata->csdev); } +static void tpiu_remove(struct amba_device *adev) +{ + __tpiu_remove(&adev->dev); +} + #ifdef CONFIG_PM static int tpiu_runtime_suspend(struct device *dev) { @@ -196,6 +215,8 @@ static int tpiu_runtime_suspend(struct device *dev) if (drvdata && !IS_ERR(drvdata->atclk)) clk_disable_unprepare(drvdata->atclk); + if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk)) + clk_disable_unprepare(drvdata->pclk); return 0; } @@ -206,6 +227,8 @@ static int tpiu_runtime_resume(struct device *dev) if (drvdata && !IS_ERR(drvdata->atclk)) clk_prepare_enable(drvdata->atclk); + if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk)) + clk_prepare_enable(drvdata->pclk); return 0; } #endif @@ -245,7 +268,67 @@ static struct amba_driver tpiu_driver = { .id_table = tpiu_ids, }; -module_amba_driver(tpiu_driver); +static int tpiu_platform_probe(struct platform_device *pdev) +{ + struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + int ret; + + pm_runtime_get_noresume(&pdev->dev); + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + + ret = __tpiu_probe(&pdev->dev, res); + pm_runtime_put(&pdev->dev); + if (ret) + pm_runtime_disable(&pdev->dev); + + return ret; +} + +static int tpiu_platform_remove(struct platform_device *pdev) +{ + struct tpiu_drvdata *drvdata = dev_get_drvdata(&pdev->dev); + + if (WARN_ON(!drvdata)) + return -ENODEV; + + __tpiu_remove(&pdev->dev); + pm_runtime_disable(&pdev->dev); + if (!IS_ERR_OR_NULL(drvdata->pclk)) + clk_put(drvdata->pclk); + return 0; +} + +#ifdef CONFIG_ACPI +static const struct acpi_device_id tpiu_acpi_ids[] = { + {"ARMHC979", 0, 0, 0}, /* ARM CoreSight TPIU */ + {} +}; +MODULE_DEVICE_TABLE(acpi, tpiu_acpi_ids); +#endif + +static struct platform_driver tpiu_platform_driver = { + .probe = tpiu_platform_probe, + .remove = tpiu_platform_remove, + .driver = { + .name = "coresight-tpiu-platform", + .acpi_match_table = ACPI_PTR(tpiu_acpi_ids), + .suppress_bind_attrs = true, + .pm = &tpiu_dev_pm_ops, + }, +}; + +static int __init tpiu_init(void) +{ + return coresight_init_driver("tpiu", &tpiu_driver, &tpiu_platform_driver); +} + +static void __exit tpiu_exit(void) +{ + coresight_remove_driver(&tpiu_driver, &tpiu_platform_driver); +} +module_init(tpiu_init); +module_exit(tpiu_exit); MODULE_AUTHOR("Pratik Patel "); MODULE_AUTHOR("Mathieu Poirier "); -- cgit v1.2.3-59-g8ed1b From 70750e257aab4cd4d755294ae8b9834214a624bb Mon Sep 17 00:00:00 2001 From: Anshuman Khandual Date: Thu, 14 Mar 2024 11:28:41 +0530 Subject: coresight: tmc: Move ACPI support from AMBA driver to platform driver Add support for the tmc devices in the platform driver, which can then be used on ACPI based platforms. This change would now allow runtime power management for ACPI based systems. The driver would try to enable the APB clock if available. But first this renames and then refactors tmc_probe() and tmc_remove(), making sure it can be used both for platform and AMBA drivers. This also moves pm_runtime_put() from tmc_probe() to the callers. Cc: Lorenzo Pieralisi Cc: Sudeep Holla Cc: Suzuki K Poulose Cc: Mike Leach Cc: James Clark Cc: linux-acpi@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org Cc: linux-kernel@vger.kernel.org Cc: coresight@lists.linaro.org Tested-by: Sudeep Holla # Boot and driver probe only Acked-by: Sudeep Holla # For ACPI related changes Reviewed-by: James Clark Signed-off-by: Anshuman Khandual Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20240314055843.2625883-10-anshuman.khandual@arm.com --- drivers/acpi/arm64/amba.c | 2 - drivers/hwtracing/coresight/coresight-tmc-core.c | 140 ++++++++++++++++++++--- drivers/hwtracing/coresight/coresight-tmc.h | 2 + 3 files changed, 127 insertions(+), 17 deletions(-) diff --git a/drivers/acpi/arm64/amba.c b/drivers/acpi/arm64/amba.c index 6d24a8f7914b..d3c1defa7bc8 100644 --- a/drivers/acpi/arm64/amba.c +++ b/drivers/acpi/arm64/amba.c @@ -22,10 +22,8 @@ static const struct acpi_device_id amba_id_list[] = { {"ARMH0061", 0}, /* PL061 GPIO Device */ {"ARMH0330", 0}, /* ARM DMA Controller DMA-330 */ - {"ARMHC501", 0}, /* ARM CoreSight ETR */ {"ARMHC502", 0}, /* ARM CoreSight STM */ {"ARMHC503", 0}, /* ARM CoreSight Debug */ - {"ARMHC97C", 0}, /* ARM CoreSight SoC-400 TMC, SoC-600 ETF/ETB */ {"", 0}, }; diff --git a/drivers/hwtracing/coresight/coresight-tmc-core.c b/drivers/hwtracing/coresight/coresight-tmc-core.c index 1a5ca65d8677..c9aaf3567565 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-core.c +++ b/drivers/hwtracing/coresight/coresight-tmc-core.c @@ -24,6 +24,8 @@ #include #include #include +#include +#include #include "coresight-priv.h" #include "coresight-tmc.h" @@ -444,24 +446,17 @@ static u32 tmc_etr_get_max_burst_size(struct device *dev) return burst_size; } -static int tmc_probe(struct amba_device *adev, const struct amba_id *id) +static int __tmc_probe(struct device *dev, struct resource *res) { int ret = 0; u32 devid; void __iomem *base; - struct device *dev = &adev->dev; struct coresight_platform_data *pdata = NULL; - struct tmc_drvdata *drvdata; - struct resource *res = &adev->res; + struct tmc_drvdata *drvdata = dev_get_drvdata(dev); struct coresight_desc desc = { 0 }; struct coresight_dev_list *dev_list = NULL; ret = -ENOMEM; - drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); - if (!drvdata) - goto out; - - dev_set_drvdata(dev, drvdata); /* Validity for the resource is already checked by the AMBA core */ base = devm_ioremap_resource(dev, res); @@ -536,7 +531,7 @@ static int tmc_probe(struct amba_device *adev, const struct amba_id *id) ret = PTR_ERR(pdata); goto out; } - adev->dev.platform_data = pdata; + dev->platform_data = pdata; desc.pdata = pdata; drvdata->csdev = coresight_register(&desc); @@ -551,12 +546,27 @@ static int tmc_probe(struct amba_device *adev, const struct amba_id *id) ret = misc_register(&drvdata->miscdev); if (ret) coresight_unregister(drvdata->csdev); - else - pm_runtime_put(&adev->dev); out: return ret; } +static int tmc_probe(struct amba_device *adev, const struct amba_id *id) +{ + struct tmc_drvdata *drvdata; + int ret; + + drvdata = devm_kzalloc(&adev->dev, sizeof(*drvdata), GFP_KERNEL); + if (!drvdata) + return -ENOMEM; + + amba_set_drvdata(adev, drvdata); + ret = __tmc_probe(&adev->dev, &adev->res); + if (!ret) + pm_runtime_put(&adev->dev); + + return ret; +} + static void tmc_shutdown(struct amba_device *adev) { unsigned long flags; @@ -579,9 +589,9 @@ out: spin_unlock_irqrestore(&drvdata->spinlock, flags); } -static void tmc_remove(struct amba_device *adev) +static void __tmc_remove(struct device *dev) { - struct tmc_drvdata *drvdata = dev_get_drvdata(&adev->dev); + struct tmc_drvdata *drvdata = dev_get_drvdata(dev); /* * Since misc_open() holds a refcount on the f_ops, which is @@ -592,6 +602,11 @@ static void tmc_remove(struct amba_device *adev) coresight_unregister(drvdata->csdev); } +static void tmc_remove(struct amba_device *adev) +{ + __tmc_remove(&adev->dev); +} + static const struct amba_id tmc_ids[] = { CS_AMBA_ID(0x000bb961), /* Coresight SoC 600 TMC-ETR/ETS */ @@ -617,7 +632,102 @@ static struct amba_driver tmc_driver = { .id_table = tmc_ids, }; -module_amba_driver(tmc_driver); +static int tmc_platform_probe(struct platform_device *pdev) +{ + struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + struct tmc_drvdata *drvdata; + int ret = 0; + + drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL); + if (!drvdata) + return -ENOMEM; + + drvdata->pclk = coresight_get_enable_apb_pclk(&pdev->dev); + if (IS_ERR(drvdata->pclk)) + return -ENODEV; + + dev_set_drvdata(&pdev->dev, drvdata); + pm_runtime_get_noresume(&pdev->dev); + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + + ret = __tmc_probe(&pdev->dev, res); + pm_runtime_put(&pdev->dev); + if (ret) + pm_runtime_disable(&pdev->dev); + + return ret; +} + +static int tmc_platform_remove(struct platform_device *pdev) +{ + struct tmc_drvdata *drvdata = dev_get_drvdata(&pdev->dev); + + if (WARN_ON(!drvdata)) + return -ENODEV; + + __tmc_remove(&pdev->dev); + pm_runtime_disable(&pdev->dev); + if (!IS_ERR_OR_NULL(drvdata->pclk)) + clk_put(drvdata->pclk); + return 0; +} + +#ifdef CONFIG_PM +static int tmc_runtime_suspend(struct device *dev) +{ + struct tmc_drvdata *drvdata = dev_get_drvdata(dev); + + if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk)) + clk_disable_unprepare(drvdata->pclk); + return 0; +} + +static int tmc_runtime_resume(struct device *dev) +{ + struct tmc_drvdata *drvdata = dev_get_drvdata(dev); + + if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk)) + clk_prepare_enable(drvdata->pclk); + return 0; +} +#endif + +static const struct dev_pm_ops tmc_dev_pm_ops = { + SET_RUNTIME_PM_OPS(tmc_runtime_suspend, tmc_runtime_resume, NULL) +}; + +#ifdef CONFIG_ACPI +static const struct acpi_device_id tmc_acpi_ids[] = { + {"ARMHC501", 0, 0, 0}, /* ARM CoreSight ETR */ + {"ARMHC97C", 0, 0, 0}, /* ARM CoreSight SoC-400 TMC, SoC-600 ETF/ETB */ + {}, +}; +MODULE_DEVICE_TABLE(acpi, tmc_acpi_ids); +#endif + +static struct platform_driver tmc_platform_driver = { + .probe = tmc_platform_probe, + .remove = tmc_platform_remove, + .driver = { + .name = "coresight-tmc-platform", + .acpi_match_table = ACPI_PTR(tmc_acpi_ids), + .suppress_bind_attrs = true, + .pm = &tmc_dev_pm_ops, + }, +}; + +static int __init tmc_init(void) +{ + return coresight_init_driver("tmc", &tmc_driver, &tmc_platform_driver); +} + +static void __exit tmc_exit(void) +{ + coresight_remove_driver(&tmc_driver, &tmc_platform_driver); +} +module_init(tmc_init); +module_exit(tmc_exit); MODULE_AUTHOR("Pratik Patel "); MODULE_DESCRIPTION("Arm CoreSight Trace Memory Controller driver"); diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h index cef979c897e6..c77763b49de0 100644 --- a/drivers/hwtracing/coresight/coresight-tmc.h +++ b/drivers/hwtracing/coresight/coresight-tmc.h @@ -166,6 +166,7 @@ struct etr_buf { /** * struct tmc_drvdata - specifics associated to an TMC component + * @pclk: APB clock if present, otherwise NULL * @base: memory mapped base address for this component. * @csdev: component vitals needed by the framework. * @miscdev: specifics to handle "/dev/xyz.tmc" entry. @@ -189,6 +190,7 @@ struct etr_buf { * @perf_buf: PERF buffer for ETR. */ struct tmc_drvdata { + struct clk *pclk; void __iomem *base; struct coresight_device *csdev; struct miscdevice miscdev; -- cgit v1.2.3-59-g8ed1b From 057256aaacc862356417a75ceeb1cfa41408dbf0 Mon Sep 17 00:00:00 2001 From: Anshuman Khandual Date: Thu, 14 Mar 2024 11:28:42 +0530 Subject: coresight: stm: Move ACPI support from AMBA driver to platform driver Add support for the stm devices in the platform driver, which can then be used on ACPI based platforms. This change would now allow runtime power management for ACPI based systems. The driver would try to enable the APB clock if available. But first this renames and then refactors stm_probe() and stm_remove(), making sure it can be used both for platform and AMBA drivers. Also this moves pm_runtime_put() from stm_probe() to the callers. Cc: Lorenzo Pieralisi Cc: Sudeep Holla Cc: Suzuki K Poulose Cc: Mike Leach Cc: James Clark Cc: Maxime Coquelin Cc: Alexandre Torgue Cc: linux-acpi@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org Cc: linux-kernel@vger.kernel.org Cc: coresight@lists.linaro.org Cc: linux-stm32@st-md-mailman.stormreply.com Tested-by: Sudeep Holla # Boot and driver probe only Acked-by: Sudeep Holla # For ACPI related changes Reviewed-by: James Clark Signed-off-by: Anshuman Khandual Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20240314055843.2625883-11-anshuman.khandual@arm.com --- drivers/acpi/arm64/amba.c | 1 - drivers/hwtracing/coresight/coresight-stm.c | 104 +++++++++++++++++++++++++--- 2 files changed, 94 insertions(+), 11 deletions(-) diff --git a/drivers/acpi/arm64/amba.c b/drivers/acpi/arm64/amba.c index d3c1defa7bc8..bec0976541da 100644 --- a/drivers/acpi/arm64/amba.c +++ b/drivers/acpi/arm64/amba.c @@ -22,7 +22,6 @@ static const struct acpi_device_id amba_id_list[] = { {"ARMH0061", 0}, /* PL061 GPIO Device */ {"ARMH0330", 0}, /* ARM DMA Controller DMA-330 */ - {"ARMHC502", 0}, /* ARM CoreSight STM */ {"ARMHC503", 0}, /* ARM CoreSight Debug */ {"", 0}, }; diff --git a/drivers/hwtracing/coresight/coresight-stm.c b/drivers/hwtracing/coresight/coresight-stm.c index 5ae24c33c846..cbf7f17556f8 100644 --- a/drivers/hwtracing/coresight/coresight-stm.c +++ b/drivers/hwtracing/coresight/coresight-stm.c @@ -29,6 +29,8 @@ #include #include #include +#include +#include #include "coresight-priv.h" #include "coresight-trace-id.h" @@ -115,6 +117,7 @@ DEFINE_CORESIGHT_DEVLIST(stm_devs, "stm"); * struct stm_drvdata - specifics associated to an STM component * @base: memory mapped base address for this component. * @atclk: optional clock for the core parts of the STM. + * @pclk: APB clock if present, otherwise NULL * @csdev: component vitals needed by the framework. * @spinlock: only one at a time pls. * @chs: the channels accociated to this STM. @@ -131,6 +134,7 @@ DEFINE_CORESIGHT_DEVLIST(stm_devs, "stm"); struct stm_drvdata { void __iomem *base; struct clk *atclk; + struct clk *pclk; struct coresight_device *csdev; spinlock_t spinlock; struct channel_space chs; @@ -810,14 +814,12 @@ static char *stm_csdev_name(struct coresight_device *csdev) return uci_data ? (char *)uci_data : "STM"; } -static int stm_probe(struct amba_device *adev, const struct amba_id *id) +static int __stm_probe(struct device *dev, struct resource *res) { int ret, trace_id; void __iomem *base; - struct device *dev = &adev->dev; struct coresight_platform_data *pdata = NULL; struct stm_drvdata *drvdata; - struct resource *res = &adev->res; struct resource ch_res; struct coresight_desc desc = { 0 }; @@ -829,12 +831,16 @@ static int stm_probe(struct amba_device *adev, const struct amba_id *id) if (!drvdata) return -ENOMEM; - drvdata->atclk = devm_clk_get(&adev->dev, "atclk"); /* optional */ + drvdata->atclk = devm_clk_get(dev, "atclk"); /* optional */ if (!IS_ERR(drvdata->atclk)) { ret = clk_prepare_enable(drvdata->atclk); if (ret) return ret; } + + drvdata->pclk = coresight_get_enable_apb_pclk(dev); + if (IS_ERR(drvdata->pclk)) + return -ENODEV; dev_set_drvdata(dev, drvdata); base = devm_ioremap_resource(dev, res); @@ -882,7 +888,7 @@ static int stm_probe(struct amba_device *adev, const struct amba_id *id) ret = PTR_ERR(pdata); goto stm_unregister; } - adev->dev.platform_data = pdata; + dev->platform_data = pdata; desc.type = CORESIGHT_DEV_TYPE_SOURCE; desc.subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE; @@ -903,8 +909,6 @@ static int stm_probe(struct amba_device *adev, const struct amba_id *id) } drvdata->traceid = (u8)trace_id; - pm_runtime_put(&adev->dev); - dev_info(&drvdata->csdev->dev, "%s initialized\n", stm_csdev_name(drvdata->csdev)); return 0; @@ -917,9 +921,20 @@ stm_unregister: return ret; } -static void stm_remove(struct amba_device *adev) +static int stm_probe(struct amba_device *adev, const struct amba_id *id) +{ + int ret; + + ret = __stm_probe(&adev->dev, &adev->res); + if (!ret) + pm_runtime_put(&adev->dev); + + return ret; +} + +static void __stm_remove(struct device *dev) { - struct stm_drvdata *drvdata = dev_get_drvdata(&adev->dev); + struct stm_drvdata *drvdata = dev_get_drvdata(dev); coresight_trace_id_put_system_id(drvdata->traceid); coresight_unregister(drvdata->csdev); @@ -927,6 +942,11 @@ static void stm_remove(struct amba_device *adev) stm_unregister_device(&drvdata->stm); } +static void stm_remove(struct amba_device *adev) +{ + __stm_remove(&adev->dev); +} + #ifdef CONFIG_PM static int stm_runtime_suspend(struct device *dev) { @@ -935,6 +955,8 @@ static int stm_runtime_suspend(struct device *dev) if (drvdata && !IS_ERR(drvdata->atclk)) clk_disable_unprepare(drvdata->atclk); + if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk)) + clk_disable_unprepare(drvdata->pclk); return 0; } @@ -945,6 +967,8 @@ static int stm_runtime_resume(struct device *dev) if (drvdata && !IS_ERR(drvdata->atclk)) clk_prepare_enable(drvdata->atclk); + if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk)) + clk_prepare_enable(drvdata->pclk); return 0; } #endif @@ -973,7 +997,67 @@ static struct amba_driver stm_driver = { .id_table = stm_ids, }; -module_amba_driver(stm_driver); +static int stm_platform_probe(struct platform_device *pdev) +{ + struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + int ret = 0; + + pm_runtime_get_noresume(&pdev->dev); + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + + ret = __stm_probe(&pdev->dev, res); + pm_runtime_put(&pdev->dev); + if (ret) + pm_runtime_disable(&pdev->dev); + + return ret; +} + +static int stm_platform_remove(struct platform_device *pdev) +{ + struct stm_drvdata *drvdata = dev_get_drvdata(&pdev->dev); + + if (WARN_ON(!drvdata)) + return -ENODEV; + + __stm_remove(&pdev->dev); + pm_runtime_disable(&pdev->dev); + if (!IS_ERR_OR_NULL(drvdata->pclk)) + clk_put(drvdata->pclk); + return 0; +} + +#ifdef CONFIG_ACPI +static const struct acpi_device_id stm_acpi_ids[] = { + {"ARMHC502", 0, 0, 0}, /* ARM CoreSight STM */ + {}, +}; +MODULE_DEVICE_TABLE(acpi, stm_acpi_ids); +#endif + +static struct platform_driver stm_platform_driver = { + .probe = stm_platform_probe, + .remove = stm_platform_remove, + .driver = { + .name = "coresight-stm-platform", + .acpi_match_table = ACPI_PTR(stm_acpi_ids), + .suppress_bind_attrs = true, + .pm = &stm_dev_pm_ops, + }, +}; + +static int __init stm_init(void) +{ + return coresight_init_driver("stm", &stm_driver, &stm_platform_driver); +} + +static void __exit stm_exit(void) +{ + coresight_remove_driver(&stm_driver, &stm_platform_driver); +} +module_init(stm_init); +module_exit(stm_exit); MODULE_AUTHOR("Pratik Patel "); MODULE_DESCRIPTION("Arm CoreSight System Trace Macrocell driver"); -- cgit v1.2.3-59-g8ed1b From 965edae4e6a2bca1f6e56d2c56d992417a53bba4 Mon Sep 17 00:00:00 2001 From: Anshuman Khandual Date: Thu, 14 Mar 2024 11:28:43 +0530 Subject: coresight: debug: Move ACPI support from AMBA driver to platform driver Add support for the cpu debug devices in a new platform driver, which can then be used on ACPI based platforms. This change would now allow runtime power management for ACPI based systems. The driver would try to enable the APB clock if available. But first this renames and then refactors debug_probe() and debug_remove(), making sure they can be used both for platform and AMBA drivers. Cc: Lorenzo Pieralisi Cc: Sudeep Holla Cc: Suzuki K Poulose Cc: Mike Leach Cc: James Clark Cc: linux-acpi@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org Cc: linux-kernel@vger.kernel.org Cc: coresight@lists.linaro.org Acked-by: Sudeep Holla # For ACPI related changes Reviewed-by: James Clark Signed-off-by: Anshuman Khandual Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20240314055843.2625883-12-anshuman.khandual@arm.com --- drivers/acpi/arm64/amba.c | 1 - drivers/hwtracing/coresight/coresight-cpu-debug.c | 138 +++++++++++++++++++--- 2 files changed, 122 insertions(+), 17 deletions(-) diff --git a/drivers/acpi/arm64/amba.c b/drivers/acpi/arm64/amba.c index bec0976541da..e1f0bbb8f393 100644 --- a/drivers/acpi/arm64/amba.c +++ b/drivers/acpi/arm64/amba.c @@ -22,7 +22,6 @@ static const struct acpi_device_id amba_id_list[] = { {"ARMH0061", 0}, /* PL061 GPIO Device */ {"ARMH0330", 0}, /* ARM DMA Controller DMA-330 */ - {"ARMHC503", 0}, /* ARM CoreSight Debug */ {"", 0}, }; diff --git a/drivers/hwtracing/coresight/coresight-cpu-debug.c b/drivers/hwtracing/coresight/coresight-cpu-debug.c index 1874df7c6a73..3263fc86cb66 100644 --- a/drivers/hwtracing/coresight/coresight-cpu-debug.c +++ b/drivers/hwtracing/coresight/coresight-cpu-debug.c @@ -4,6 +4,7 @@ * * Author: Leo Yan */ +#include #include #include #include @@ -18,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -84,6 +86,7 @@ #define DEBUG_WAIT_TIMEOUT 32000 struct debug_drvdata { + struct clk *pclk; void __iomem *base; struct device *dev; int cpu; @@ -557,18 +560,12 @@ static void debug_func_exit(void) debugfs_remove_recursive(debug_debugfs_dir); } -static int debug_probe(struct amba_device *adev, const struct amba_id *id) +static int __debug_probe(struct device *dev, struct resource *res) { + struct debug_drvdata *drvdata = dev_get_drvdata(dev); void __iomem *base; - struct device *dev = &adev->dev; - struct debug_drvdata *drvdata; - struct resource *res = &adev->res; int ret; - drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); - if (!drvdata) - return -ENOMEM; - drvdata->cpu = coresight_get_cpu(dev); if (drvdata->cpu < 0) return drvdata->cpu; @@ -579,10 +576,7 @@ static int debug_probe(struct amba_device *adev, const struct amba_id *id) return -EBUSY; } - drvdata->dev = &adev->dev; - amba_set_drvdata(adev, drvdata); - - /* Validity for the resource is already checked by the AMBA core */ + drvdata->dev = dev; base = devm_ioremap_resource(dev, res); if (IS_ERR(base)) return PTR_ERR(base); @@ -629,10 +623,21 @@ err: return ret; } -static void debug_remove(struct amba_device *adev) +static int debug_probe(struct amba_device *adev, const struct amba_id *id) { - struct device *dev = &adev->dev; - struct debug_drvdata *drvdata = amba_get_drvdata(adev); + struct debug_drvdata *drvdata; + + drvdata = devm_kzalloc(&adev->dev, sizeof(*drvdata), GFP_KERNEL); + if (!drvdata) + return -ENOMEM; + + amba_set_drvdata(adev, drvdata); + return __debug_probe(&adev->dev, &adev->res); +} + +static void __debug_remove(struct device *dev) +{ + struct debug_drvdata *drvdata = dev_get_drvdata(dev); per_cpu(debug_drvdata, drvdata->cpu) = NULL; @@ -646,6 +651,11 @@ static void debug_remove(struct amba_device *adev) debug_func_exit(); } +static void debug_remove(struct amba_device *adev) +{ + __debug_remove(&adev->dev); +} + static const struct amba_cs_uci_id uci_id_debug[] = { { /* CPU Debug UCI data */ @@ -677,7 +687,103 @@ static struct amba_driver debug_driver = { .id_table = debug_ids, }; -module_amba_driver(debug_driver); +static int debug_platform_probe(struct platform_device *pdev) +{ + struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + struct debug_drvdata *drvdata; + int ret = 0; + + drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL); + if (!drvdata) + return -ENOMEM; + + drvdata->pclk = coresight_get_enable_apb_pclk(&pdev->dev); + if (IS_ERR(drvdata->pclk)) + return -ENODEV; + + dev_set_drvdata(&pdev->dev, drvdata); + pm_runtime_get_noresume(&pdev->dev); + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + + ret = __debug_probe(&pdev->dev, res); + if (ret) { + pm_runtime_put_noidle(&pdev->dev); + pm_runtime_disable(&pdev->dev); + if (!IS_ERR_OR_NULL(drvdata->pclk)) + clk_put(drvdata->pclk); + } + return ret; +} + +static int debug_platform_remove(struct platform_device *pdev) +{ + struct debug_drvdata *drvdata = dev_get_drvdata(&pdev->dev); + + if (WARN_ON(!drvdata)) + return -ENODEV; + + __debug_remove(&pdev->dev); + pm_runtime_disable(&pdev->dev); + if (!IS_ERR_OR_NULL(drvdata->pclk)) + clk_put(drvdata->pclk); + return 0; +} + +#ifdef CONFIG_ACPI +static const struct acpi_device_id debug_platform_ids[] = { + {"ARMHC503", 0, 0, 0}, /* ARM CoreSight Debug */ + {}, +}; +MODULE_DEVICE_TABLE(acpi, debug_platform_ids); +#endif + +#ifdef CONFIG_PM +static int debug_runtime_suspend(struct device *dev) +{ + struct debug_drvdata *drvdata = dev_get_drvdata(dev); + + if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk)) + clk_disable_unprepare(drvdata->pclk); + return 0; +} + +static int debug_runtime_resume(struct device *dev) +{ + struct debug_drvdata *drvdata = dev_get_drvdata(dev); + + if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk)) + clk_prepare_enable(drvdata->pclk); + return 0; +} +#endif + +static const struct dev_pm_ops debug_dev_pm_ops = { + SET_RUNTIME_PM_OPS(debug_runtime_suspend, debug_runtime_resume, NULL) +}; + +static struct platform_driver debug_platform_driver = { + .probe = debug_platform_probe, + .remove = debug_platform_remove, + .driver = { + .name = "coresight-debug-platform", + .acpi_match_table = ACPI_PTR(debug_platform_ids), + .suppress_bind_attrs = true, + .pm = &debug_dev_pm_ops, + }, +}; + +static int __init debug_init(void) +{ + return coresight_init_driver("debug", &debug_driver, &debug_platform_driver); +} + +static void __exit debug_exit(void) +{ + coresight_remove_driver(&debug_driver, &debug_platform_driver); +} +module_init(debug_init); +module_exit(debug_exit); MODULE_AUTHOR("Leo Yan "); MODULE_DESCRIPTION("ARM Coresight CPU Debug Driver"); -- cgit v1.2.3-59-g8ed1b From 2bc3cf575a162a2ca9c98262a63e95cc2b619de7 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Fri, 12 Apr 2024 11:33:07 -0700 Subject: perf annotate-data: Improve debug message with location info To verify it found the correct variable, let's add the location expression to the debug message. $ perf --debug type-profile annotate --data-type ... ----------------------------------------------------------- find data type for 0xaf0(reg15) at schedule+0xeb CU for kernel/sched/core.c (die:0x1180523) frame base: cfa=0 fbreg=6 found "rq" in scope=3/4 (die: 0x11b6a00) type_offset=0xaf0 variable location: reg15 type='struct rq' size=0xfc0 (die:0x11892e2) ----------------------------------------------------------- find data type for 0x7bc(reg3) at tcp_get_info+0x62 CU for net/ipv4/tcp.c (die:0x7b5f516) frame base: cfa=0 fbreg=6 offset: 1980 is bigger than size: 760 check variable "sk" failed (die: 0x7b92b2c) variable location: reg3 type='struct sock' size=0x2f8 (die:0x7b63c3a) ----------------------------------------------------------- ... The first case is fine. It looked up a data type in r15 with offset of 0xaf0 at schedule+0xeb. It found the CU die and the frame base info and the variable "rq" was found in the scope 3/4. Its location is the r15 register and the type size is 0xfc0 which includes 0xaf0. But the second case is not good. It looked up a data type in rbx (reg3) with offset 0x7bc. It found a CU and the frame base which is good so far. And it also found a variable "sk" but the access offset is bigger than the type size (1980 vs. 760 or 0x7bc vs. 0x2f8). The variable has the right location (reg3) but I need to figure out why it accesses beyond what it's supposed to. Signed-off-by: Namhyung Kim Cc: Adrian Hunter Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20240412183310.2518474-2-namhyung@kernel.org [ Fix the build on 32-bit by casting Dwarf_Word to (long) in pr_debug_location() ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate-data.c | 99 ++++++++++++++++++++++++++++++++++------- 1 file changed, 82 insertions(+), 17 deletions(-) diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c index 1cd857400038..e53d66c46c54 100644 --- a/tools/perf/util/annotate-data.c +++ b/tools/perf/util/annotate-data.c @@ -46,6 +46,7 @@ static void pr_debug_type_name(Dwarf_Die *die, enum type_state_kind kind) { struct strbuf sb; char *str; + Dwarf_Word size = 0; if (!debug_type_profile && verbose < 3) return; @@ -72,13 +73,67 @@ static void pr_debug_type_name(Dwarf_Die *die, enum type_state_kind kind) break; } + dwarf_aggregate_size(die, &size); + strbuf_init(&sb, 32); die_get_typename_from_type(die, &sb); str = strbuf_detach(&sb, NULL); - pr_info(" type=%s (die:%lx)\n", str, (long)dwarf_dieoffset(die)); + pr_info(" type='%s' size=%#lx (die:%#lx)\n", + str, (long)size, (long)dwarf_dieoffset(die)); free(str); } +static void pr_debug_location(Dwarf_Die *die, u64 pc, int reg) +{ + ptrdiff_t off = 0; + Dwarf_Attribute attr; + Dwarf_Addr base, start, end; + Dwarf_Op *ops; + size_t nops; + + if (!debug_type_profile && verbose < 3) + return; + + if (dwarf_attr(die, DW_AT_location, &attr) == NULL) + return; + + while ((off = dwarf_getlocations(&attr, off, &base, &start, &end, &ops, &nops)) > 0) { + if (reg != DWARF_REG_PC && end < pc) + continue; + if (reg != DWARF_REG_PC && start > pc) + break; + + pr_info(" variable location: "); + switch (ops->atom) { + case DW_OP_reg0 ...DW_OP_reg31: + pr_info("reg%d\n", ops->atom - DW_OP_reg0); + break; + case DW_OP_breg0 ...DW_OP_breg31: + pr_info("base=reg%d, offset=%#lx\n", + ops->atom - DW_OP_breg0, (long)ops->number); + break; + case DW_OP_regx: + pr_info("reg%ld\n", (long)ops->number); + break; + case DW_OP_bregx: + pr_info("base=reg%ld, offset=%#lx\n", + (long)ops->number, (long)ops->number2); + break; + case DW_OP_fbreg: + pr_info("use frame base, offset=%#lx\n", (long)ops->number); + break; + case DW_OP_addr: + pr_info("address=%#lx\n", (long)ops->number); + break; + default: + pr_info("unknown: code=%#x, number=%#lx\n", + ops->atom, (long)ops->number); + break; + } + break; + } +} + /* * Type information in a register, valid when @ok is true. * The @caller_saved registers are invalidated after a function call. @@ -1404,7 +1459,7 @@ again: found = find_data_type_insn(dloc, reg, &basic_blocks, var_types, cu_die, type_die); if (found > 0) { - pr_debug_dtp("found by insn track: %#x(reg%d) type-offset=%#x", + pr_debug_dtp("found by insn track: %#x(reg%d) type-offset=%#x\n", dloc->op->offset, reg, dloc->type_offset); pr_debug_type_name(type_die, TSR_KIND_TYPE); ret = 0; @@ -1440,16 +1495,16 @@ static int find_data_type_die(struct data_loc_info *dloc, Dwarf_Die *type_die) char buf[64]; if (dloc->op->multi_regs) - snprintf(buf, sizeof(buf), " or reg%d", dloc->op->reg2); + snprintf(buf, sizeof(buf), "reg%d, reg%d", dloc->op->reg1, dloc->op->reg2); else if (dloc->op->reg1 == DWARF_REG_PC) - snprintf(buf, sizeof(buf), " (PC)"); + snprintf(buf, sizeof(buf), "PC"); else - buf[0] = '\0'; + snprintf(buf, sizeof(buf), "reg%d", dloc->op->reg1); pr_debug_dtp("-----------------------------------------------------------\n"); - pr_debug_dtp("%s [%"PRIx64"] for reg%d%s offset=%#x in %s\n", - __func__, dloc->ip - dloc->ms->sym->start, - dloc->op->reg1, buf, dloc->op->offset, dloc->ms->sym->name); + pr_debug_dtp("find data type for %#x(%s) at %s+%#"PRIx64"\n", + dloc->op->offset, buf, dloc->ms->sym->name, + dloc->ip - dloc->ms->sym->start); /* * IP is a relative instruction address from the start of the map, as @@ -1468,14 +1523,15 @@ static int find_data_type_die(struct data_loc_info *dloc, Dwarf_Die *type_die) reg = loc->reg1; offset = loc->offset; - pr_debug_dtp("CU die offset: %#lx\n", (long)dwarf_dieoffset(&cu_die)); + pr_debug_dtp("CU for %s (die:%#lx)\n", + dwarf_diename(&cu_die), (long)dwarf_dieoffset(&cu_die)); if (reg == DWARF_REG_PC) { if (get_global_var_type(&cu_die, dloc, dloc->ip, dloc->var_addr, &offset, type_die)) { dloc->type_offset = offset; - pr_debug_dtp("found PC-rel by addr=%#"PRIx64" offset=%#x", + pr_debug_dtp("found by addr=%#"PRIx64" type_offset=%#x\n", dloc->var_addr, offset); pr_debug_type_name(type_die, TSR_KIND_TYPE); ret = 0; @@ -1537,13 +1593,22 @@ retry: pr_debug_dtp("found \"%s\" in scope=%d/%d (die: %#lx) ", dwarf_diename(&var_die), i+1, nr_scopes, (long)dwarf_dieoffset(&scopes[i])); - if (reg == DWARF_REG_PC) - pr_debug_dtp("%#x(PC) offset=%#x", loc->offset, offset); - else if (reg == DWARF_REG_FB || is_fbreg) - pr_debug_dtp("%#x(reg%d) stack fb_offset=%#x offset=%#x", - loc->offset, reg, fb_offset, offset); - else - pr_debug_dtp("%#x(reg%d)", loc->offset, reg); + if (reg == DWARF_REG_PC) { + pr_debug_dtp("addr=%#"PRIx64" type_offset=%#x\n", + dloc->var_addr, offset); + } else if (reg == DWARF_REG_FB || is_fbreg) { + pr_debug_dtp("stack_offset=%#x type_offset=%#x\n", + fb_offset, offset); + } else { + pr_debug_dtp("type_offset=%#x\n", offset); + } + pr_debug_location(&var_die, pc, reg); + pr_debug_type_name(type_die, TSR_KIND_TYPE); + } else { + pr_debug_dtp("check variable \"%s\" failed (die: %#lx)\n", + dwarf_diename(&var_die), + (long)dwarf_dieoffset(&var_die)); + pr_debug_location(&var_die, pc, reg); pr_debug_type_name(type_die, TSR_KIND_TYPE); } dloc->type_offset = offset; -- cgit v1.2.3-59-g8ed1b From 645af3fb62bf12911ce1fc79efa676dae9a8289b Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Fri, 12 Apr 2024 11:33:08 -0700 Subject: perf dwarf-aux: Check pointer offset when checking variables In match_var_offset(), it checks the offset range with the target type only for non-pointer types. But it also needs to check the pointer types with the target type. This is because there can be more than one pointer variable located in the same register. Let's look at the following example. It's looking up a variable for reg3 at tcp_get_info+0x62. It found "sk" variable but it wasn't the right one since it accesses beyond the target type (struct 'sock' in this case) size. ----------------------------------------------------------- find data type for 0x7bc(reg3) at tcp_get_info+0x62 CU for net/ipv4/tcp.c (die:0x7b5f516) frame base: cfa=0 fbreg=6 offset: 1980 is bigger than size: 760 check variable "sk" failed (die: 0x7b92b2c) variable location: reg3 type='struct sock' size=0x2f8 (die:0x7b63c3a) Actually there was another variable "tp" in the function and it's located at the same (reg3) because it's just type-casted like below. void tcp_get_info(struct sock *sk, struct tcp_info *info) { const struct tcp_sock *tp = tcp_sk(sk); ... The 'struct tcp_sock' contains the 'struct sock' at offset 0 so it can just use the same address as a pointer to tcp_sock. That means it should match variables correctly by checking the offset and size. Actually it cannot distinguish if the offset was smaller than the size of the original struct sock. But I think it's fine as they are the same at that part. So let's check the target type size and retry if it doesn't match. Now it succeeded to find the correct variable. ----------------------------------------------------------- find data type for 0x7bc(reg3) at tcp_get_info+0x62 CU for net/ipv4/tcp.c (die:0x7b5f516) frame base: cfa=0 fbreg=6 found "tp" in scope=1/1 (die: 0x7b92b16) type_offset=0x7bc variable location: reg3 type='struct tcp_sock' size=0xa68 (die:0x7b81380) Fixes: bc10db8eb8955fbc ("perf annotate-data: Support stack variables") Signed-off-by: Namhyung Kim Cc: Adrian Hunter Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20240412183310.2518474-3-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/dwarf-aux.c | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c index 7dad99ee3ff3..b361fd7ebd56 100644 --- a/tools/perf/util/dwarf-aux.c +++ b/tools/perf/util/dwarf-aux.c @@ -1361,7 +1361,7 @@ struct find_var_data { #define DWARF_OP_DIRECT_REGS 32 static bool match_var_offset(Dwarf_Die *die_mem, struct find_var_data *data, - u64 addr_offset, u64 addr_type) + u64 addr_offset, u64 addr_type, bool is_pointer) { Dwarf_Die type_die; Dwarf_Word size; @@ -1375,6 +1375,12 @@ static bool match_var_offset(Dwarf_Die *die_mem, struct find_var_data *data, if (die_get_real_type(die_mem, &type_die) == NULL) return false; + if (is_pointer && dwarf_tag(&type_die) == DW_TAG_pointer_type) { + /* Get the target type of the pointer */ + if (die_get_real_type(&type_die, &type_die) == NULL) + return false; + } + if (dwarf_aggregate_size(&type_die, &size) < 0) return false; @@ -1442,31 +1448,38 @@ static int __die_find_var_reg_cb(Dwarf_Die *die_mem, void *arg) if (data->is_fbreg && ops->atom == DW_OP_fbreg && data->offset >= (int)ops->number && check_allowed_ops(ops, nops) && - match_var_offset(die_mem, data, data->offset, ops->number)) + match_var_offset(die_mem, data, data->offset, ops->number, + /*is_pointer=*/false)) return DIE_FIND_CB_END; /* Only match with a simple case */ if (data->reg < DWARF_OP_DIRECT_REGS) { /* pointer variables saved in a register 0 to 31 */ if (ops->atom == (DW_OP_reg0 + data->reg) && - check_allowed_ops(ops, nops)) + check_allowed_ops(ops, nops) && + match_var_offset(die_mem, data, data->offset, 0, + /*is_pointer=*/true)) return DIE_FIND_CB_END; /* Local variables accessed by a register + offset */ if (ops->atom == (DW_OP_breg0 + data->reg) && check_allowed_ops(ops, nops) && - match_var_offset(die_mem, data, data->offset, ops->number)) + match_var_offset(die_mem, data, data->offset, ops->number, + /*is_pointer=*/false)) return DIE_FIND_CB_END; } else { /* pointer variables saved in a register 32 or above */ if (ops->atom == DW_OP_regx && ops->number == data->reg && - check_allowed_ops(ops, nops)) + check_allowed_ops(ops, nops) && + match_var_offset(die_mem, data, data->offset, 0, + /*is_pointer=*/true)) return DIE_FIND_CB_END; /* Local variables accessed by a register + offset */ if (ops->atom == DW_OP_bregx && data->reg == ops->number && check_allowed_ops(ops, nops) && - match_var_offset(die_mem, data, data->offset, ops->number2)) + match_var_offset(die_mem, data, data->offset, ops->number2, + /*is_poitner=*/false)) return DIE_FIND_CB_END; } } @@ -1528,7 +1541,8 @@ static int __die_find_var_addr_cb(Dwarf_Die *die_mem, void *arg) continue; if (check_allowed_ops(ops, nops) && - match_var_offset(die_mem, data, data->addr, ops->number)) + match_var_offset(die_mem, data, data->addr, ops->number, + /*is_pointer=*/false)) return DIE_FIND_CB_END; } return DIE_FIND_CB_SIBLING; -- cgit v1.2.3-59-g8ed1b From 0519fadbbe3b1ed396d944911c1ff3a276701474 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Fri, 12 Apr 2024 11:33:09 -0700 Subject: perf dwarf-aux: Check variable address range properly In match_var_offset(), it just checked the end address of the variable with the given offset because it assumed the register holds a pointer to the data type and the offset starts from the base. But I found some cases that the stack pointer (rsp = reg7) register is used to pointer a stack variable while the frame base is maintained by a different register (rbp = reg6). In that case, it cannot simply use the stack pointer as it cannot guarantee that it points to the frame base. So it needs to check both boundaries of the variable location. Before: ----------------------------------------------------------- find data type for 0x7c(reg7) at tcp_getsockopt+0xb62 CU for net/ipv4/tcp.c (die:0x7b5f516) frame base: cfa=0 fbreg=6 no pointer or no type check variable "tss" failed (die: 0x7b95801) variable location: base reg7, offset=0x110 type='struct scm_timestamping_internal' size=0x30 (die:0x7b8c126) So the current code just checks register number for the non-PC and non-FB registers and assuming it has offset 0. But this variable has offset 0x110 so it should not match to this. After: ----------------------------------------------------------- find data type for 0x7c(reg7) at tcp_getsockopt+0xb62 CU for net/ipv4/tcp.c (die:0x7b5f516) frame base: cfa=0 fbreg=6 no pointer or no type check variable "zc" failed (die: 0x7b9580a) variable location: base=reg7, offset=0x40 type='struct tcp_zerocopy_receive' size=0x40 (die:7b947f4) Now it find the correct variable "zc". It was located at reg7 + 0x40 and the size if 0x40 which means it should cover [0x40, 0x80). And the access was for reg7 + 0x7c so it found the right one. But it still failed to use the variable and it would be handled in the next patch. Signed-off-by: Namhyung Kim Cc: Adrian Hunter Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Masami Hiramatsu Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20240412183310.2518474-4-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/dwarf-aux.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c index b361fd7ebd56..40cfbdfe2d75 100644 --- a/tools/perf/util/dwarf-aux.c +++ b/tools/perf/util/dwarf-aux.c @@ -1372,6 +1372,9 @@ static bool match_var_offset(Dwarf_Die *die_mem, struct find_var_data *data, return true; } + if (addr_offset < addr_type) + return false; + if (die_get_real_type(die_mem, &type_die) == NULL) return false; @@ -1446,7 +1449,6 @@ static int __die_find_var_reg_cb(Dwarf_Die *die_mem, void *arg) /* Local variables accessed using frame base register */ if (data->is_fbreg && ops->atom == DW_OP_fbreg && - data->offset >= (int)ops->number && check_allowed_ops(ops, nops) && match_var_offset(die_mem, data, data->offset, ops->number, /*is_pointer=*/false)) @@ -1537,9 +1539,6 @@ static int __die_find_var_addr_cb(Dwarf_Die *die_mem, void *arg) if (ops->atom != DW_OP_addr) continue; - if (data->addr < ops->number) - continue; - if (check_allowed_ops(ops, nops) && match_var_offset(die_mem, data, data->addr, ops->number, /*is_pointer=*/false)) -- cgit v1.2.3-59-g8ed1b From a5a00497b9dfefbf6872f387bc7692919e1785d3 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Fri, 12 Apr 2024 11:33:10 -0700 Subject: perf annotate-data: Handle RSP if it's not the FB register In some cases, the stack pointer on x86 (rsp = reg7) is used to point variables on stack but it's not the frame base register. Then it should handle the register like normal registers (IOW not to access the other stack variables using offset calculation) but it should not assume it would have a pointer. Before: ----------------------------------------------------------- find data type for 0x7c(reg7) at tcp_getsockopt+0xb62 CU for net/ipv4/tcp.c (die:0x7b5f516) frame base: cfa=0 fbreg=6 no pointer or no type check variable "zc" failed (die: 0x7b9580a) variable location: base=reg7, offset=0x40 type='struct tcp_zerocopy_receive' size=0x40 (die:0x7b947f4) After: ----------------------------------------------------------- find data type for 0x7c(reg7) at tcp_getsockopt+0xb62 CU for net/ipv4/tcp.c (die:0x7b5f516) frame base: cfa=0 fbreg=6 found "zc" in scope=3/3 (die: 0x7b957fc) type_offset=0x3c variable location: base=reg7, offset=0x40 type='struct tcp_zerocopy_receive' size=0x40 (die:0x7b947f4) Note that the type-offset was properly calculated to 0x3c as the variable starts at 0x40. Signed-off-by: Namhyung Kim Cc: Adrian Hunter Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20240412183310.2518474-5-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate-data.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c index e53d66c46c54..12d5faff3b7a 100644 --- a/tools/perf/util/annotate-data.c +++ b/tools/perf/util/annotate-data.c @@ -25,6 +25,9 @@ #include "symbol_conf.h" #include "thread.h" +/* register number of the stack pointer */ +#define X86_REG_SP 7 + enum type_state_kind { TSR_KIND_INVALID = 0, TSR_KIND_TYPE, @@ -197,7 +200,7 @@ static void init_type_state(struct type_state *state, struct arch *arch) state->regs[10].caller_saved = true; state->regs[11].caller_saved = true; state->ret_reg = 0; - state->stack_reg = 7; + state->stack_reg = X86_REG_SP; } } @@ -382,10 +385,18 @@ static bool find_cu_die(struct debuginfo *di, u64 pc, Dwarf_Die *cu_die) } /* The type info will be saved in @type_die */ -static int check_variable(Dwarf_Die *var_die, Dwarf_Die *type_die, int offset, - bool is_pointer) +static int check_variable(struct data_loc_info *dloc, Dwarf_Die *var_die, + Dwarf_Die *type_die, int reg, int offset, bool is_fbreg) { Dwarf_Word size; + bool is_pointer = true; + + if (reg == DWARF_REG_PC) + is_pointer = false; + else if (reg == dloc->fbreg || is_fbreg) + is_pointer = false; + else if (arch__is(dloc->arch, "x86") && reg == X86_REG_SP) + is_pointer = false; /* Get the type of the variable */ if (die_get_real_type(var_die, type_die) == NULL) { @@ -607,7 +618,6 @@ static bool get_global_var_type(Dwarf_Die *cu_die, struct data_loc_info *dloc, { u64 pc; int offset; - bool is_pointer = false; const char *var_name = NULL; struct global_var_entry *gvar; Dwarf_Die var_die; @@ -623,7 +633,8 @@ static bool get_global_var_type(Dwarf_Die *cu_die, struct data_loc_info *dloc, /* Try to get the variable by address first */ if (die_find_variable_by_addr(cu_die, var_addr, &var_die, &offset) && - check_variable(&var_die, type_die, offset, is_pointer) == 0) { + check_variable(dloc, &var_die, type_die, DWARF_REG_PC, offset, + /*is_fbreg=*/false) == 0) { var_name = dwarf_diename(&var_die); *var_offset = offset; goto ok; @@ -636,7 +647,8 @@ static bool get_global_var_type(Dwarf_Die *cu_die, struct data_loc_info *dloc, /* Try to get the name of global variable */ if (die_find_variable_at(cu_die, var_name, pc, &var_die) && - check_variable(&var_die, type_die, *var_offset, is_pointer) == 0) + check_variable(dloc, &var_die, type_die, DWARF_REG_PC, *var_offset, + /*is_fbreg=*/false) == 0) goto ok; return false; @@ -1587,8 +1599,7 @@ retry: } /* Found a variable, see if it's correct */ - ret = check_variable(&var_die, type_die, offset, - reg != DWARF_REG_PC && !is_fbreg); + ret = check_variable(dloc, &var_die, type_die, reg, offset, is_fbreg); if (ret == 0) { pr_debug_dtp("found \"%s\" in scope=%d/%d (die: %#lx) ", dwarf_diename(&var_die), i+1, nr_scopes, -- cgit v1.2.3-59-g8ed1b From b31bcda55fcb3f282ffcb3047fcf760748b26a37 Mon Sep 17 00:00:00 2001 From: Tanmay Shah Date: Fri, 12 Apr 2024 11:37:05 -0700 Subject: remoteproc: zynqmp: fix lockstep mode memory region In lockstep mode, r5 core0 uses TCM of R5 core1. Following is lockstep mode memory region as per hardware reference manual. | *TCM* | *R5 View* | *Linux view* | | R5_0 ATCM (128 KB) | 0x0000_0000 | 0xFFE0_0000 | | R5_0 BTCM (128 KB) | 0x0002_0000 | 0xFFE2_0000 | However, driver shouldn't model it as above because R5 core0 TCM and core1 TCM has different power-domains mapped to it. Hence, TCM address space in lockstep mode should be modeled as 64KB regions only where each region has its own power-domain as following: | *TCM* | *R5 View* | *Linux view* | | R5_0 ATCM0 (64 KB) | 0x0000_0000 | 0xFFE0_0000 | | R5_0 BTCM0 (64 KB) | 0x0002_0000 | 0xFFE2_0000 | | R5_0 ATCM1 (64 KB) | 0x0001_0000 | 0xFFE1_0000 | | R5_0 BTCM1 (64 KB) | 0x0003_0000 | 0xFFE3_0000 | This makes driver maintanance easy and makes design robust for future platorms as well. Signed-off-by: Tanmay Shah Link: https://lore.kernel.org/r/20240412183708.4036007-2-tanmay.shah@amd.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/xlnx_r5_remoteproc.c | 146 +++----------------------------- 1 file changed, 12 insertions(+), 134 deletions(-) diff --git a/drivers/remoteproc/xlnx_r5_remoteproc.c b/drivers/remoteproc/xlnx_r5_remoteproc.c index cfbd97b89c26..0f942440b4e2 100644 --- a/drivers/remoteproc/xlnx_r5_remoteproc.c +++ b/drivers/remoteproc/xlnx_r5_remoteproc.c @@ -84,12 +84,12 @@ static const struct mem_bank_data zynqmp_tcm_banks_split[] = { {0xffeb0000UL, 0x20000, 0x10000UL, PD_R5_1_BTCM, "btcm1"}, }; -/* In lockstep mode cluster combines each 64KB TCM and makes 128KB TCM */ +/* In lockstep mode cluster uses each 64KB TCM from second core as well */ static const struct mem_bank_data zynqmp_tcm_banks_lockstep[] = { - {0xffe00000UL, 0x0, 0x20000UL, PD_R5_0_ATCM, "atcm0"}, /* TCM 128KB each */ - {0xffe20000UL, 0x20000, 0x20000UL, PD_R5_0_BTCM, "btcm0"}, - {0, 0, 0, PD_R5_1_ATCM, ""}, - {0, 0, 0, PD_R5_1_BTCM, ""}, + {0xffe00000UL, 0x0, 0x10000UL, PD_R5_0_ATCM, "atcm0"}, /* TCM 64KB each */ + {0xffe20000UL, 0x20000, 0x10000UL, PD_R5_0_BTCM, "btcm0"}, + {0xffe10000UL, 0x10000, 0x10000UL, PD_R5_1_ATCM, "atcm1"}, + {0xffe30000UL, 0x30000, 0x10000UL, PD_R5_1_BTCM, "btcm1"}, }; /** @@ -541,14 +541,14 @@ static int tcm_mem_map(struct rproc *rproc, } /* - * add_tcm_carveout_split_mode() + * add_tcm_banks() * @rproc: single R5 core's corresponding rproc instance * - * allocate and add remoteproc carveout for TCM memory in split mode + * allocate and add remoteproc carveout for TCM memory * * return 0 on success, otherwise non-zero value on failure */ -static int add_tcm_carveout_split_mode(struct rproc *rproc) +static int add_tcm_banks(struct rproc *rproc) { struct rproc_mem_entry *rproc_mem; struct zynqmp_r5_core *r5_core; @@ -581,10 +581,10 @@ static int add_tcm_carveout_split_mode(struct rproc *rproc) ZYNQMP_PM_REQUEST_ACK_BLOCKING); if (ret < 0) { dev_err(dev, "failed to turn on TCM 0x%x", pm_domain_id); - goto release_tcm_split; + goto release_tcm; } - dev_dbg(dev, "TCM carveout split mode %s addr=%llx, da=0x%x, size=0x%lx", + dev_dbg(dev, "TCM carveout %s addr=%llx, da=0x%x, size=0x%lx", bank_name, bank_addr, da, bank_size); rproc_mem = rproc_mem_entry_init(dev, NULL, bank_addr, @@ -594,99 +594,16 @@ static int add_tcm_carveout_split_mode(struct rproc *rproc) if (!rproc_mem) { ret = -ENOMEM; zynqmp_pm_release_node(pm_domain_id); - goto release_tcm_split; - } - - rproc_add_carveout(rproc, rproc_mem); - rproc_coredump_add_segment(rproc, da, bank_size); - } - - return 0; - -release_tcm_split: - /* If failed, Turn off all TCM banks turned on before */ - for (i--; i >= 0; i--) { - pm_domain_id = r5_core->tcm_banks[i]->pm_domain_id; - zynqmp_pm_release_node(pm_domain_id); - } - return ret; -} - -/* - * add_tcm_carveout_lockstep_mode() - * @rproc: single R5 core's corresponding rproc instance - * - * allocate and add remoteproc carveout for TCM memory in lockstep mode - * - * return 0 on success, otherwise non-zero value on failure - */ -static int add_tcm_carveout_lockstep_mode(struct rproc *rproc) -{ - struct rproc_mem_entry *rproc_mem; - struct zynqmp_r5_core *r5_core; - int i, num_banks, ret; - phys_addr_t bank_addr; - size_t bank_size = 0; - struct device *dev; - u32 pm_domain_id; - char *bank_name; - u32 da; - - r5_core = rproc->priv; - dev = r5_core->dev; - - /* Go through zynqmp banks for r5 node */ - num_banks = r5_core->tcm_bank_count; - - /* - * In lockstep mode, TCM is contiguous memory block - * However, each TCM block still needs to be enabled individually. - * So, Enable each TCM block individually. - * Although ATCM and BTCM is contiguous memory block, add two separate - * carveouts for both. - */ - for (i = 0; i < num_banks; i++) { - pm_domain_id = r5_core->tcm_banks[i]->pm_domain_id; - - /* Turn on each TCM bank individually */ - ret = zynqmp_pm_request_node(pm_domain_id, - ZYNQMP_PM_CAPABILITY_ACCESS, 0, - ZYNQMP_PM_REQUEST_ACK_BLOCKING); - if (ret < 0) { - dev_err(dev, "failed to turn on TCM 0x%x", pm_domain_id); - goto release_tcm_lockstep; - } - - bank_size = r5_core->tcm_banks[i]->size; - if (bank_size == 0) - continue; - - bank_addr = r5_core->tcm_banks[i]->addr; - da = r5_core->tcm_banks[i]->da; - bank_name = r5_core->tcm_banks[i]->bank_name; - - /* Register TCM address range, TCM map and unmap functions */ - rproc_mem = rproc_mem_entry_init(dev, NULL, bank_addr, - bank_size, da, - tcm_mem_map, tcm_mem_unmap, - bank_name); - if (!rproc_mem) { - ret = -ENOMEM; - zynqmp_pm_release_node(pm_domain_id); - goto release_tcm_lockstep; + goto release_tcm; } - /* If registration is success, add carveouts */ rproc_add_carveout(rproc, rproc_mem); rproc_coredump_add_segment(rproc, da, bank_size); - - dev_dbg(dev, "TCM carveout lockstep mode %s addr=0x%llx, da=0x%x, size=0x%lx", - bank_name, bank_addr, da, bank_size); } return 0; -release_tcm_lockstep: +release_tcm: /* If failed, Turn off all TCM banks turned on before */ for (i--; i >= 0; i--) { pm_domain_id = r5_core->tcm_banks[i]->pm_domain_id; @@ -695,45 +612,6 @@ release_tcm_lockstep: return ret; } -/* - * add_tcm_banks() - * @rproc: single R5 core's corresponding rproc instance - * - * allocate and add remoteproc carveouts for TCM memory based on cluster mode - * - * return 0 on success, otherwise non-zero value on failure - */ -static int add_tcm_banks(struct rproc *rproc) -{ - struct zynqmp_r5_cluster *cluster; - struct zynqmp_r5_core *r5_core; - struct device *dev; - - r5_core = rproc->priv; - if (!r5_core) - return -EINVAL; - - dev = r5_core->dev; - - cluster = dev_get_drvdata(dev->parent); - if (!cluster) { - dev_err(dev->parent, "Invalid driver data\n"); - return -EINVAL; - } - - /* - * In lockstep mode TCM banks are one contiguous memory region of 256Kb - * In split mode, each TCM bank is 64Kb and not contiguous. - * We add memory carveouts accordingly. - */ - if (cluster->mode == SPLIT_MODE) - return add_tcm_carveout_split_mode(rproc); - else if (cluster->mode == LOCKSTEP_MODE) - return add_tcm_carveout_lockstep_mode(rproc); - - return -EINVAL; -} - /* * zynqmp_r5_parse_fw() * @rproc: single R5 core's corresponding rproc instance -- cgit v1.2.3-59-g8ed1b From 9e1b2a0757d081e327630d566901c084b056d5fe Mon Sep 17 00:00:00 2001 From: Radhey Shyam Pandey Date: Fri, 12 Apr 2024 11:37:06 -0700 Subject: dt-bindings: remoteproc: Add Tightly Coupled Memory (TCM) bindings Introduce bindings for TCM memory address space on AMD-xilinx Zynq UltraScale+ platform. It will help in defining TCM in device-tree and make it's access platform agnostic and data-driven. Tightly-coupled memories(TCMs) are low-latency memory that provides predictable instruction execution and predictable data load/store timing. Each Cortex-R5F processor contains two 64-bit wide 64 KB memory banks on the ATCM and BTCM ports, for a total of 128 KB of memory. The TCM resources(reg, reg-names and power-domain) are documented for each TCM in the R5 node. The reg and reg-names are made as required properties as we don't want to hardcode TCM addresses for future platforms and for zu+ legacy implementation will ensure that the old dts without reg/reg-names works and stable ABI is maintained. It also extends the examples for TCM split and lockstep modes. Signed-off-by: Radhey Shyam Pandey Reviewed-by: Krzysztof Kozlowski Signed-off-by: Tanmay Shah Link: https://lore.kernel.org/r/20240412183708.4036007-3-tanmay.shah@amd.com Signed-off-by: Mathieu Poirier --- .../bindings/remoteproc/xlnx,zynqmp-r5fss.yaml | 279 +++++++++++++++++++-- 1 file changed, 257 insertions(+), 22 deletions(-) diff --git a/Documentation/devicetree/bindings/remoteproc/xlnx,zynqmp-r5fss.yaml b/Documentation/devicetree/bindings/remoteproc/xlnx,zynqmp-r5fss.yaml index 78aac69f1060..6f13da11f593 100644 --- a/Documentation/devicetree/bindings/remoteproc/xlnx,zynqmp-r5fss.yaml +++ b/Documentation/devicetree/bindings/remoteproc/xlnx,zynqmp-r5fss.yaml @@ -18,11 +18,26 @@ description: | properties: compatible: - const: xlnx,zynqmp-r5fss + enum: + - xlnx,zynqmp-r5fss + - xlnx,versal-r5fss + - xlnx,versal-net-r52fss + + "#address-cells": + const: 2 + + "#size-cells": + const: 2 + + ranges: + description: | + Standard ranges definition providing address translations for + local R5F TCM address spaces to bus addresses. xlnx,cluster-mode: $ref: /schemas/types.yaml#/definitions/uint32 enum: [0, 1, 2] + default: 1 description: | The RPU MPCore can operate in split mode (Dual-processor performance), Safety lock-step mode(Both RPU cores execute the same code in lock-step, @@ -36,8 +51,16 @@ properties: 1: lockstep mode (default) 2: single cpu mode + xlnx,tcm-mode: + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [0, 1] + description: | + Configure RPU TCM + 0: split mode + 1: lockstep mode + patternProperties: - "^r5f-[a-f0-9]+$": + "^r(.*)@[0-9a-f]+$": type: object description: | The RPU is located in the Low Power Domain of the Processor Subsystem. @@ -52,10 +75,22 @@ patternProperties: properties: compatible: - const: xlnx,zynqmp-r5f + enum: + - xlnx,zynqmp-r5f + - xlnx,versal-r5f + - xlnx,versal-net-r52f + + reg: + minItems: 1 + maxItems: 4 + + reg-names: + minItems: 1 + maxItems: 4 power-domains: - maxItems: 1 + minItems: 2 + maxItems: 5 mboxes: minItems: 1 @@ -101,35 +136,235 @@ patternProperties: required: - compatible + - reg + - reg-names - power-domains - unevaluatedProperties: false - required: - compatible + - "#address-cells" + - "#size-cells" + - ranges + +allOf: + - if: + properties: + compatible: + contains: + enum: + - xlnx,versal-net-r52fss + then: + properties: + xlnx,tcm-mode: false + + patternProperties: + "^r52f@[0-9a-f]+$": + type: object + + properties: + reg: + minItems: 1 + items: + - description: ATCM internal memory + - description: BTCM internal memory + - description: CTCM internal memory + + reg-names: + minItems: 1 + items: + - const: atcm0 + - const: btcm0 + - const: ctcm0 + + power-domains: + minItems: 2 + items: + - description: RPU core power domain + - description: ATCM power domain + - description: BTCM power domain + - description: CTCM power domain + + - if: + properties: + compatible: + contains: + enum: + - xlnx,zynqmp-r5fss + - xlnx,versal-r5fss + then: + if: + properties: + xlnx,cluster-mode: + enum: [1, 2] + then: + properties: + xlnx,tcm-mode: + enum: [1] + + patternProperties: + "^r5f@[0-9a-f]+$": + type: object + + properties: + reg: + minItems: 1 + items: + - description: ATCM internal memory + - description: BTCM internal memory + - description: extra ATCM memory in lockstep mode + - description: extra BTCM memory in lockstep mode + + reg-names: + minItems: 1 + items: + - const: atcm0 + - const: btcm0 + - const: atcm1 + - const: btcm1 + + power-domains: + minItems: 2 + items: + - description: RPU core power domain + - description: ATCM power domain + - description: BTCM power domain + - description: second ATCM power domain + - description: second BTCM power domain + + required: + - xlnx,tcm-mode + + else: + properties: + xlnx,tcm-mode: + enum: [0] + + patternProperties: + "^r5f@[0-9a-f]+$": + type: object + + properties: + reg: + minItems: 1 + items: + - description: ATCM internal memory + - description: BTCM internal memory + + reg-names: + minItems: 1 + items: + - const: atcm0 + - const: btcm0 + + power-domains: + minItems: 2 + items: + - description: RPU core power domain + - description: ATCM power domain + - description: BTCM power domain + + required: + - xlnx,tcm-mode additionalProperties: false examples: - | - remoteproc { - compatible = "xlnx,zynqmp-r5fss"; - xlnx,cluster-mode = <1>; - - r5f-0 { - compatible = "xlnx,zynqmp-r5f"; - power-domains = <&zynqmp_firmware 0x7>; - memory-region = <&rproc_0_fw_image>, <&rpu0vdev0buffer>, <&rpu0vdev0vring0>, <&rpu0vdev0vring1>; - mboxes = <&ipi_mailbox_rpu0 0>, <&ipi_mailbox_rpu0 1>; - mbox-names = "tx", "rx"; + #include + + // Split mode configuration + soc { + #address-cells = <2>; + #size-cells = <2>; + + remoteproc@ffe00000 { + compatible = "xlnx,zynqmp-r5fss"; + xlnx,cluster-mode = <0>; + xlnx,tcm-mode = <0>; + + #address-cells = <2>; + #size-cells = <2>; + ranges = <0x0 0x0 0x0 0xffe00000 0x0 0x10000>, + <0x0 0x20000 0x0 0xffe20000 0x0 0x10000>, + <0x1 0x0 0x0 0xffe90000 0x0 0x10000>, + <0x1 0x20000 0x0 0xffeb0000 0x0 0x10000>; + + r5f@0 { + compatible = "xlnx,zynqmp-r5f"; + reg = <0x0 0x0 0x0 0x10000>, <0x0 0x20000 0x0 0x10000>; + reg-names = "atcm0", "btcm0"; + power-domains = <&zynqmp_firmware PD_RPU_0>, + <&zynqmp_firmware PD_R5_0_ATCM>, + <&zynqmp_firmware PD_R5_0_BTCM>; + memory-region = <&rproc_0_fw_image>, <&rpu0vdev0buffer>, + <&rpu0vdev0vring0>, <&rpu0vdev0vring1>; + mboxes = <&ipi_mailbox_rpu0 0>, <&ipi_mailbox_rpu0 1>; + mbox-names = "tx", "rx"; + }; + + r5f@1 { + compatible = "xlnx,zynqmp-r5f"; + reg = <0x1 0x0 0x0 0x10000>, <0x1 0x20000 0x0 0x10000>; + reg-names = "atcm0", "btcm0"; + power-domains = <&zynqmp_firmware PD_RPU_1>, + <&zynqmp_firmware PD_R5_1_ATCM>, + <&zynqmp_firmware PD_R5_1_BTCM>; + memory-region = <&rproc_1_fw_image>, <&rpu1vdev0buffer>, + <&rpu1vdev0vring0>, <&rpu1vdev0vring1>; + mboxes = <&ipi_mailbox_rpu1 0>, <&ipi_mailbox_rpu1 1>; + mbox-names = "tx", "rx"; + }; }; + }; + + - | + //Lockstep configuration + soc { + #address-cells = <2>; + #size-cells = <2>; + + remoteproc@ffe00000 { + compatible = "xlnx,zynqmp-r5fss"; + xlnx,cluster-mode = <1>; + xlnx,tcm-mode = <1>; + + #address-cells = <2>; + #size-cells = <2>; + ranges = <0x0 0x0 0x0 0xffe00000 0x0 0x10000>, + <0x0 0x20000 0x0 0xffe20000 0x0 0x10000>, + <0x0 0x10000 0x0 0xffe10000 0x0 0x10000>, + <0x0 0x30000 0x0 0xffe30000 0x0 0x10000>; + + r5f@0 { + compatible = "xlnx,zynqmp-r5f"; + reg = <0x0 0x0 0x0 0x10000>, + <0x0 0x20000 0x0 0x10000>, + <0x0 0x10000 0x0 0x10000>, + <0x0 0x30000 0x0 0x10000>; + reg-names = "atcm0", "btcm0", "atcm1", "btcm1"; + power-domains = <&zynqmp_firmware PD_RPU_0>, + <&zynqmp_firmware PD_R5_0_ATCM>, + <&zynqmp_firmware PD_R5_0_BTCM>, + <&zynqmp_firmware PD_R5_1_ATCM>, + <&zynqmp_firmware PD_R5_1_BTCM>; + memory-region = <&rproc_0_fw_image>, <&rpu0vdev0buffer>, + <&rpu0vdev0vring0>, <&rpu0vdev0vring1>; + mboxes = <&ipi_mailbox_rpu0 0>, <&ipi_mailbox_rpu0 1>; + mbox-names = "tx", "rx"; + }; - r5f-1 { - compatible = "xlnx,zynqmp-r5f"; - power-domains = <&zynqmp_firmware 0x8>; - memory-region = <&rproc_1_fw_image>, <&rpu1vdev0buffer>, <&rpu1vdev0vring0>, <&rpu1vdev0vring1>; - mboxes = <&ipi_mailbox_rpu1 0>, <&ipi_mailbox_rpu1 1>; - mbox-names = "tx", "rx"; + r5f@1 { + compatible = "xlnx,zynqmp-r5f"; + reg = <0x1 0x0 0x0 0x10000>, <0x1 0x20000 0x0 0x10000>; + reg-names = "atcm0", "btcm0"; + power-domains = <&zynqmp_firmware PD_RPU_1>, + <&zynqmp_firmware PD_R5_1_ATCM>, + <&zynqmp_firmware PD_R5_1_BTCM>; + memory-region = <&rproc_1_fw_image>, <&rpu1vdev0buffer>, + <&rpu1vdev0vring0>, <&rpu1vdev0vring1>; + mboxes = <&ipi_mailbox_rpu1 0>, <&ipi_mailbox_rpu1 1>; + mbox-names = "tx", "rx"; + }; }; }; ... -- cgit v1.2.3-59-g8ed1b From 72c350c9a6cdb8d666927ffd7a6507e77a5f5047 Mon Sep 17 00:00:00 2001 From: Tanmay Shah Date: Fri, 12 Apr 2024 11:37:08 -0700 Subject: remoteproc: zynqmp: parse TCM from device tree ZynqMP TCM information was fixed in driver. Now ZynqMP TCM information is available in device-tree. Parse TCM information in driver as per new bindings. Signed-off-by: Tanmay Shah Link: https://lore.kernel.org/r/20240412183708.4036007-5-tanmay.shah@amd.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/xlnx_r5_remoteproc.c | 127 ++++++++++++++++++++++++++++++-- 1 file changed, 120 insertions(+), 7 deletions(-) diff --git a/drivers/remoteproc/xlnx_r5_remoteproc.c b/drivers/remoteproc/xlnx_r5_remoteproc.c index 0f942440b4e2..7b1c12108bff 100644 --- a/drivers/remoteproc/xlnx_r5_remoteproc.c +++ b/drivers/remoteproc/xlnx_r5_remoteproc.c @@ -74,8 +74,8 @@ struct mbox_info { }; /* - * Hardcoded TCM bank values. This will be removed once TCM bindings are - * accepted for system-dt specifications and upstreamed in linux kernel + * Hardcoded TCM bank values. This will stay in driver to maintain backward + * compatibility with device-tree that does not have TCM information. */ static const struct mem_bank_data zynqmp_tcm_banks_split[] = { {0xffe00000UL, 0x0, 0x10000UL, PD_R5_0_ATCM, "atcm0"}, /* TCM 64KB each */ @@ -761,6 +761,103 @@ free_rproc: return ERR_PTR(ret); } +static int zynqmp_r5_get_tcm_node_from_dt(struct zynqmp_r5_cluster *cluster) +{ + int i, j, tcm_bank_count, ret, tcm_pd_idx, pd_count; + struct of_phandle_args out_args; + struct zynqmp_r5_core *r5_core; + struct platform_device *cpdev; + struct mem_bank_data *tcm; + struct device_node *np; + struct resource *res; + u64 abs_addr, size; + struct device *dev; + + for (i = 0; i < cluster->core_count; i++) { + r5_core = cluster->r5_cores[i]; + dev = r5_core->dev; + np = r5_core->np; + + pd_count = of_count_phandle_with_args(np, "power-domains", + "#power-domain-cells"); + + if (pd_count <= 0) { + dev_err(dev, "invalid power-domains property, %d\n", pd_count); + return -EINVAL; + } + + /* First entry in power-domains list is for r5 core, rest for TCM. */ + tcm_bank_count = pd_count - 1; + + if (tcm_bank_count <= 0) { + dev_err(dev, "invalid TCM count %d\n", tcm_bank_count); + return -EINVAL; + } + + r5_core->tcm_banks = devm_kcalloc(dev, tcm_bank_count, + sizeof(struct mem_bank_data *), + GFP_KERNEL); + if (!r5_core->tcm_banks) + return -ENOMEM; + + r5_core->tcm_bank_count = tcm_bank_count; + for (j = 0, tcm_pd_idx = 1; j < tcm_bank_count; j++, tcm_pd_idx++) { + tcm = devm_kzalloc(dev, sizeof(struct mem_bank_data), + GFP_KERNEL); + if (!tcm) + return -ENOMEM; + + r5_core->tcm_banks[j] = tcm; + + /* Get power-domains id of TCM. */ + ret = of_parse_phandle_with_args(np, "power-domains", + "#power-domain-cells", + tcm_pd_idx, &out_args); + if (ret) { + dev_err(r5_core->dev, + "failed to get tcm %d pm domain, ret %d\n", + tcm_pd_idx, ret); + return ret; + } + tcm->pm_domain_id = out_args.args[0]; + of_node_put(out_args.np); + + /* Get TCM address without translation. */ + ret = of_property_read_reg(np, j, &abs_addr, &size); + if (ret) { + dev_err(dev, "failed to get reg property\n"); + return ret; + } + + /* + * Remote processor can address only 32 bits + * so convert 64-bits into 32-bits. This will discard + * any unwanted upper 32-bits. + */ + tcm->da = (u32)abs_addr; + tcm->size = (u32)size; + + cpdev = to_platform_device(dev); + res = platform_get_resource(cpdev, IORESOURCE_MEM, j); + if (!res) { + dev_err(dev, "failed to get tcm resource\n"); + return -EINVAL; + } + + tcm->addr = (u32)res->start; + tcm->bank_name = (char *)res->name; + res = devm_request_mem_region(dev, tcm->addr, tcm->size, + tcm->bank_name); + if (!res) { + dev_err(dev, "failed to request tcm resource\n"); + return -EINVAL; + } + } + } + + return 0; +} + /** * zynqmp_r5_get_tcm_node() * Ideally this function should parse tcm node and store information @@ -839,9 +936,16 @@ static int zynqmp_r5_core_init(struct zynqmp_r5_cluster *cluster, struct zynqmp_r5_core *r5_core; int ret, i; - ret = zynqmp_r5_get_tcm_node(cluster); - if (ret < 0) { - dev_err(dev, "can't get tcm node, err %d\n", ret); + r5_core = cluster->r5_cores[0]; + + /* Maintain backward compatibility for zynqmp by using hardcode TCM address. */ + if (of_find_property(r5_core->np, "reg", NULL)) + ret = zynqmp_r5_get_tcm_node_from_dt(cluster); + else + ret = zynqmp_r5_get_tcm_node(cluster); + + if (ret) { + dev_err(dev, "can't get tcm, err %d\n", ret); return ret; } @@ -906,16 +1010,25 @@ static int zynqmp_r5_cluster_init(struct zynqmp_r5_cluster *cluster) * fail driver probe if either of that is not set in dts. */ if (cluster_mode == LOCKSTEP_MODE) { - tcm_mode = PM_RPU_TCM_COMB; fw_reg_val = PM_RPU_MODE_LOCKSTEP; } else if (cluster_mode == SPLIT_MODE) { - tcm_mode = PM_RPU_TCM_SPLIT; fw_reg_val = PM_RPU_MODE_SPLIT; } else { dev_err(dev, "driver does not support cluster mode %d\n", cluster_mode); return -EINVAL; } + if (of_find_property(dev_node, "xlnx,tcm-mode", NULL)) { + ret = of_property_read_u32(dev_node, "xlnx,tcm-mode", (u32 *)&tcm_mode); + if (ret) + return ret; + } else { + if (cluster_mode == LOCKSTEP_MODE) + tcm_mode = PM_RPU_TCM_COMB; + else + tcm_mode = PM_RPU_TCM_SPLIT; + } + /* * Number of cores is decided by number of child nodes of * r5f subsystem node in dts. If Split mode is used in dts -- cgit v1.2.3-59-g8ed1b From 393e3d290f61492d2ff0b47319b753c4a03c0e5b Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 14 Apr 2024 17:49:10 +0200 Subject: rtc: mcp795: drop unneeded MODULE_ALIAS The ID table already has respective entry and MODULE_DEVICE_TABLE and creates proper alias for SPI driver. Having another MODULE_ALIAS causes the alias to be duplicated. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240414154910.126991-1-krzk@kernel.org Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-mcp795.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/rtc/rtc-mcp795.c b/drivers/rtc/rtc-mcp795.c index 0d515b3df571..e12f0f806ec4 100644 --- a/drivers/rtc/rtc-mcp795.c +++ b/drivers/rtc/rtc-mcp795.c @@ -450,4 +450,3 @@ module_spi_driver(mcp795_driver); MODULE_DESCRIPTION("MCP795 RTC SPI Driver"); MODULE_AUTHOR("Josef Gajdusek "); MODULE_LICENSE("GPL"); -MODULE_ALIAS("spi:mcp795"); -- cgit v1.2.3-59-g8ed1b From c6a2fb6d14bfe321fa516fb5558e19d176e2ae52 Mon Sep 17 00:00:00 2001 From: Waqar Hameed Date: Mon, 20 Nov 2023 15:49:25 +0100 Subject: dt-bindings: rtc: Add Epson RX8111 Epson RX8111 is an RTC with timestamp functionality. Add devicetree bindings requiring the compatible string and I2C slave address (reg) through `trivial-rtc.yaml`. Acked-by: Krzysztof Kozlowski Signed-off-by: Waqar Hameed Link: https://lore.kernel.org/r/4823f303ec8308762430f4f3aaa462be20baef54.1700491765.git.waqar.hameed@axis.com Signed-off-by: Alexandre Belloni --- Documentation/devicetree/bindings/rtc/trivial-rtc.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/rtc/trivial-rtc.yaml b/Documentation/devicetree/bindings/rtc/trivial-rtc.yaml index a3db41c5207c..bad7e3114096 100644 --- a/Documentation/devicetree/bindings/rtc/trivial-rtc.yaml +++ b/Documentation/devicetree/bindings/rtc/trivial-rtc.yaml @@ -40,6 +40,7 @@ properties: - epson,rx8025 - epson,rx8035 # I2C-BUS INTERFACE REAL TIME CLOCK MODULE with Battery Backed RAM + - epson,rx8111 - epson,rx8571 # I2C-BUS INTERFACE REAL TIME CLOCK MODULE - epson,rx8581 -- cgit v1.2.3-59-g8ed1b From f8c81d15f4bb585f229a1f5f609a8544b89933ff Mon Sep 17 00:00:00 2001 From: Waqar Hameed Date: Mon, 20 Nov 2023 15:49:25 +0100 Subject: rtc: Add driver for Epson RX8111 Epson RX8111 is an RTC with alarm, timer and timestamp functionality. Add a basic driver with support for only reading/writing time (for now). Signed-off-by: Waqar Hameed Link: https://lore.kernel.org/r/0c3e1b03f276da47b26ac50f5d0ddf5c67aabe5c.1700491765.git.waqar.hameed@axis.com Signed-off-by: Alexandre Belloni --- drivers/rtc/Kconfig | 10 ++ drivers/rtc/Makefile | 1 + drivers/rtc/rtc-rx8111.c | 356 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 367 insertions(+) create mode 100644 drivers/rtc/rtc-rx8111.c diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index c63e32d012f2..2a95b05982ad 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -664,6 +664,16 @@ config RTC_DRV_RX8010 This driver can also be built as a module. If so, the module will be called rtc-rx8010. +config RTC_DRV_RX8111 + tristate "Epson RX8111" + select REGMAP_I2C + depends on I2C + help + If you say yes here you will get support for the Epson RX8111 RTC. + + This driver can also be built as a module. If so, the module will be + called rtc-rx8111. + config RTC_DRV_RX8581 tristate "Epson RX-8571/RX-8581" select REGMAP_I2C diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 6efff381c484..3004e372f25f 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -154,6 +154,7 @@ obj-$(CONFIG_RTC_DRV_RX4581) += rtc-rx4581.o obj-$(CONFIG_RTC_DRV_RX6110) += rtc-rx6110.o obj-$(CONFIG_RTC_DRV_RX8010) += rtc-rx8010.o obj-$(CONFIG_RTC_DRV_RX8025) += rtc-rx8025.o +obj-$(CONFIG_RTC_DRV_RX8111) += rtc-rx8111.o obj-$(CONFIG_RTC_DRV_RX8581) += rtc-rx8581.o obj-$(CONFIG_RTC_DRV_RZN1) += rtc-rzn1.o obj-$(CONFIG_RTC_DRV_S35390A) += rtc-s35390a.o diff --git a/drivers/rtc/rtc-rx8111.c b/drivers/rtc/rtc-rx8111.c new file mode 100644 index 000000000000..62d2352de102 --- /dev/null +++ b/drivers/rtc/rtc-rx8111.c @@ -0,0 +1,356 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Driver for Epson RX8111 RTC. + * + * Copyright (C) 2023 Axis Communications AB + */ + +#include +#include +#include +#include +#include + +#include + +#define RX8111_REG_SEC 0x10 /* Second counter. */ +#define RX8111_REG_MIN 0x11 /* Minute counter */ +#define RX8111_REG_HOUR 0x12 /* Hour counter. */ +#define RX8111_REG_WEEK 0x13 /* Week day counter. */ +#define RX8111_REG_DAY 0x14 /* Month day counter. */ +#define RX8111_REG_MONTH 0x15 /* Month counter. */ +#define RX8111_REG_YEAR 0x16 /* Year counter. */ + +#define RX8111_REG_ALARM_MIN 0x17 /* Alarm minute. */ +#define RX8111_REG_ALARM_HOUR 0x18 /* Alarm hour. */ +#define RX8111_REG_ALARM_WEEK_DAY 0x19 /* Alarm week or month day. */ + +#define RX8111_REG_TIMER_COUNTER0 0x1a /* Timer counter LSB. */ +#define RX8111_REG_TIMER_COUNTER1 0x1b /* Timer counter. */ +#define RX8111_REG_TIMER_COUNTER2 0x1c /* Timer counter MSB. */ + +#define RX8111_REG_EXT 0x1d /* Extension register. */ +#define RX8111_REG_FLAG 0x1e /* Flag register. */ +#define RX8111_REG_CTRL 0x1f /* Control register. */ + +#define RX8111_REG_TS_1_1000_SEC 0x20 /* Timestamp 256 or 512 Hz . */ +#define RX8111_REG_TS_1_100_SEC 0x21 /* Timestamp 1 - 128 Hz. */ +#define RX8111_REG_TS_SEC 0x22 /* Timestamp second. */ +#define RX8111_REG_TS_MIN 0x23 /* Timestamp minute. */ +#define RX8111_REG_TS_HOUR 0x24 /* Timestamp hour. */ +#define RX8111_REG_TS_WEEK 0x25 /* Timestamp week day. */ +#define RX8111_REG_TS_DAY 0x26 /* Timestamp month day. */ +#define RX8111_REG_TS_MONTH 0x27 /* Timestamp month. */ +#define RX8111_REG_TS_YEAR 0x28 /* Timestamp year. */ +#define RX8111_REG_TS_STATUS 0x29 /* Timestamp status. */ + +#define RX8111_REG_EVIN_SETTING 0x2b /* Timestamp trigger setting. */ +#define RX8111_REG_ALARM_SEC 0x2c /* Alarm second. */ +#define RX8111_REG_TIMER_CTRL 0x2d /* Timer control. */ +#define RX8111_REG_TS_CTRL0 0x2e /* Timestamp control 0. */ +#define RX8111_REG_CMD_TRIGGER 0x2f /* Timestamp trigger. */ +#define RX8111_REG_PWR_SWITCH_CTRL 0x32 /* Power switch control. */ +#define RX8111_REG_STATUS_MON 0x33 /* Status monitor. */ +#define RX8111_REG_TS_CTRL1 0x34 /* Timestamp control 1. */ +#define RX8111_REG_TS_CTRL2 0x35 /* Timestamp control 2. */ +#define RX8111_REG_TS_CTRL3 0x36 /* Timestamp control 3. */ + +#define RX8111_FLAG_XST_BIT BIT(0) +#define RX8111_FLAG_VLF_BIT BIT(1) + +#define RX8111_TIME_BUF_SZ (RX8111_REG_YEAR - RX8111_REG_SEC + 1) + +enum rx8111_regfield { + /* RX8111_REG_EXT. */ + RX8111_REGF_TSEL0, + RX8111_REGF_TSEL1, + RX8111_REGF_ETS, + RX8111_REGF_WADA, + RX8111_REGF_TE, + RX8111_REGF_USEL, + RX8111_REGF_FSEL0, + RX8111_REGF_FSEL1, + + /* RX8111_REG_FLAG. */ + RX8111_REGF_XST, + RX8111_REGF_VLF, + RX8111_REGF_EVF, + RX8111_REGF_AF, + RX8111_REGF_TF, + RX8111_REGF_UF, + RX8111_REGF_POR, + + /* RX8111_REG_CTRL. */ + RX8111_REGF_STOP, + RX8111_REGF_EIE, + RX8111_REGF_AIE, + RX8111_REGF_TIE, + RX8111_REGF_UIE, + + /* RX8111_REG_PWR_SWITCH_CTRL. */ + RX8111_REGF_SMPT0, + RX8111_REGF_SMPT1, + RX8111_REGF_SWSEL0, + RX8111_REGF_SWSEL1, + RX8111_REGF_INIEN, + RX8111_REGF_CHGEN, + + /* Sentinel value. */ + RX8111_REGF_MAX +}; + +static const struct reg_field rx8111_regfields[] = { + [RX8111_REGF_TSEL0] = REG_FIELD(RX8111_REG_EXT, 0, 0), + [RX8111_REGF_TSEL1] = REG_FIELD(RX8111_REG_EXT, 1, 1), + [RX8111_REGF_ETS] = REG_FIELD(RX8111_REG_EXT, 2, 2), + [RX8111_REGF_WADA] = REG_FIELD(RX8111_REG_EXT, 3, 3), + [RX8111_REGF_TE] = REG_FIELD(RX8111_REG_EXT, 4, 4), + [RX8111_REGF_USEL] = REG_FIELD(RX8111_REG_EXT, 5, 5), + [RX8111_REGF_FSEL0] = REG_FIELD(RX8111_REG_EXT, 6, 6), + [RX8111_REGF_FSEL1] = REG_FIELD(RX8111_REG_EXT, 7, 7), + + [RX8111_REGF_XST] = REG_FIELD(RX8111_REG_FLAG, 0, 0), + [RX8111_REGF_VLF] = REG_FIELD(RX8111_REG_FLAG, 1, 1), + [RX8111_REGF_EVF] = REG_FIELD(RX8111_REG_FLAG, 2, 2), + [RX8111_REGF_AF] = REG_FIELD(RX8111_REG_FLAG, 3, 3), + [RX8111_REGF_TF] = REG_FIELD(RX8111_REG_FLAG, 4, 4), + [RX8111_REGF_UF] = REG_FIELD(RX8111_REG_FLAG, 5, 5), + [RX8111_REGF_POR] = REG_FIELD(RX8111_REG_FLAG, 7, 7), + + [RX8111_REGF_STOP] = REG_FIELD(RX8111_REG_CTRL, 0, 0), + [RX8111_REGF_EIE] = REG_FIELD(RX8111_REG_CTRL, 2, 2), + [RX8111_REGF_AIE] = REG_FIELD(RX8111_REG_CTRL, 3, 3), + [RX8111_REGF_TIE] = REG_FIELD(RX8111_REG_CTRL, 4, 4), + [RX8111_REGF_UIE] = REG_FIELD(RX8111_REG_CTRL, 5, 5), + + [RX8111_REGF_SMPT0] = REG_FIELD(RX8111_REG_PWR_SWITCH_CTRL, 0, 0), + [RX8111_REGF_SMPT1] = REG_FIELD(RX8111_REG_PWR_SWITCH_CTRL, 1, 1), + [RX8111_REGF_SWSEL0] = REG_FIELD(RX8111_REG_PWR_SWITCH_CTRL, 2, 2), + [RX8111_REGF_SWSEL1] = REG_FIELD(RX8111_REG_PWR_SWITCH_CTRL, 3, 3), + [RX8111_REGF_INIEN] = REG_FIELD(RX8111_REG_PWR_SWITCH_CTRL, 6, 6), + [RX8111_REGF_CHGEN] = REG_FIELD(RX8111_REG_PWR_SWITCH_CTRL, 7, 7), +}; + +static const struct regmap_config rx8111_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = RX8111_REG_TS_CTRL3, +}; + +struct rx8111_data { + struct regmap *regmap; + struct regmap_field *regfields[RX8111_REGF_MAX]; + struct device *dev; + struct rtc_device *rtc; +}; + +static int rx8111_read_vl_flag(struct rx8111_data *data, unsigned int *vlval) +{ + int ret; + + ret = regmap_field_read(data->regfields[RX8111_REGF_VLF], vlval); + if (ret) + dev_dbg(data->dev, "Could not read VL flag (%d)", ret); + + return ret; +} + +static int rx8111_read_time(struct device *dev, struct rtc_time *tm) +{ + struct rx8111_data *data = dev_get_drvdata(dev); + u8 buf[RX8111_TIME_BUF_SZ]; + unsigned int regval; + int ret; + + /* Check status. */ + ret = regmap_read(data->regmap, RX8111_REG_FLAG, ®val); + if (ret) { + dev_dbg(data->dev, "Could not read flag register (%d)\n", ret); + return ret; + } + + if (FIELD_GET(RX8111_FLAG_XST_BIT, regval)) { + dev_warn(data->dev, + "Crystal oscillation stopped, time is not reliable\n"); + return -EINVAL; + } + + if (FIELD_GET(RX8111_FLAG_VLF_BIT, regval)) { + dev_warn(data->dev, + "Low voltage detected, time is not reliable\n"); + return -EINVAL; + } + + ret = regmap_field_read(data->regfields[RX8111_REGF_STOP], ®val); + if (ret) { + dev_dbg(data->dev, "Could not read clock status (%d)\n", ret); + return ret; + } + + if (regval) { + dev_warn(data->dev, "Clock stopped, time is not reliable\n"); + return -EINVAL; + } + + /* Read time. */ + ret = regmap_bulk_read(data->regmap, RX8111_REG_SEC, buf, + ARRAY_SIZE(buf)); + if (ret) { + dev_dbg(data->dev, "Could not bulk read time (%d)\n", ret); + return ret; + } + + tm->tm_sec = bcd2bin(buf[0]); + tm->tm_min = bcd2bin(buf[1]); + tm->tm_hour = bcd2bin(buf[2]); + tm->tm_wday = ffs(buf[3]) - 1; + tm->tm_mday = bcd2bin(buf[4]); + tm->tm_mon = bcd2bin(buf[5]) - 1; + tm->tm_year = bcd2bin(buf[6]) + 100; + + return 0; +} + +static int rx8111_set_time(struct device *dev, struct rtc_time *tm) +{ + struct rx8111_data *data = dev_get_drvdata(dev); + u8 buf[RX8111_TIME_BUF_SZ]; + int ret; + + buf[0] = bin2bcd(tm->tm_sec); + buf[1] = bin2bcd(tm->tm_min); + buf[2] = bin2bcd(tm->tm_hour); + buf[3] = BIT(tm->tm_wday); + buf[4] = bin2bcd(tm->tm_mday); + buf[5] = bin2bcd(tm->tm_mon + 1); + buf[6] = bin2bcd(tm->tm_year - 100); + + ret = regmap_clear_bits(data->regmap, RX8111_REG_FLAG, + RX8111_FLAG_XST_BIT | RX8111_FLAG_VLF_BIT); + if (ret) + return ret; + + /* Stop the clock. */ + ret = regmap_field_write(data->regfields[RX8111_REGF_STOP], 1); + if (ret) { + dev_dbg(data->dev, "Could not stop the clock (%d)\n", ret); + return ret; + } + + /* Set the time. */ + ret = regmap_bulk_write(data->regmap, RX8111_REG_SEC, buf, + ARRAY_SIZE(buf)); + if (ret) { + dev_dbg(data->dev, "Could not bulk write time (%d)\n", ret); + + /* + * We don't bother with trying to start the clock again. We + * check for this in rx8111_read_time() (and thus force user to + * call rx8111_set_time() to try again). + */ + return ret; + } + + /* Start the clock. */ + ret = regmap_field_write(data->regfields[RX8111_REGF_STOP], 0); + if (ret) { + dev_dbg(data->dev, "Could not start the clock (%d)\n", ret); + return ret; + } + + return 0; +} + +static int rx8111_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) +{ + struct rx8111_data *data = dev_get_drvdata(dev); + unsigned int regval; + unsigned int vlval; + int ret; + + switch (cmd) { + case RTC_VL_READ: + ret = rx8111_read_vl_flag(data, ®val); + if (ret) + return ret; + + vlval = regval ? RTC_VL_DATA_INVALID : 0; + + return put_user(vlval, (typeof(vlval) __user *)arg); + default: + return -ENOIOCTLCMD; + } +} + +static const struct rtc_class_ops rx8111_rtc_ops = { + .read_time = rx8111_read_time, + .set_time = rx8111_set_time, + .ioctl = rx8111_ioctl, +}; + +static int rx8111_probe(struct i2c_client *client) +{ + struct rx8111_data *data; + struct rtc_device *rtc; + size_t i; + + data = devm_kmalloc(&client->dev, sizeof(*data), GFP_KERNEL); + if (!data) { + dev_dbg(&client->dev, "Could not allocate device data\n"); + return -ENOMEM; + } + + data->dev = &client->dev; + dev_set_drvdata(data->dev, data); + + data->regmap = devm_regmap_init_i2c(client, &rx8111_regmap_config); + if (IS_ERR(data->regmap)) { + dev_dbg(data->dev, "Could not initialize regmap\n"); + return PTR_ERR(data->regmap); + } + + for (i = 0; i < RX8111_REGF_MAX; ++i) { + data->regfields[i] = devm_regmap_field_alloc( + data->dev, data->regmap, rx8111_regfields[i]); + if (IS_ERR(data->regfields[i])) { + dev_dbg(data->dev, + "Could not allocate register field %zu\n", i); + return PTR_ERR(data->regfields[i]); + } + } + + rtc = devm_rtc_allocate_device(data->dev); + if (IS_ERR(rtc)) { + dev_dbg(data->dev, "Could not allocate rtc device\n"); + return PTR_ERR(rtc); + } + + rtc->ops = &rx8111_rtc_ops; + rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; + rtc->range_max = RTC_TIMESTAMP_END_2099; + + clear_bit(RTC_FEATURE_ALARM, rtc->features); + + return devm_rtc_register_device(rtc); +} + +static const struct of_device_id rx8111_of_match[] = { + { + .compatible = "epson,rx8111", + }, + {} +}; +MODULE_DEVICE_TABLE(of, rx8111_of_match); + +static struct i2c_driver rx8111_driver = { + .driver = { + .name = "rtc-rx8111", + .of_match_table = rx8111_of_match, + }, + .probe = rx8111_probe, +}; +module_i2c_driver(rx8111_driver); + +MODULE_AUTHOR("Waqar Hameed "); +MODULE_DESCRIPTION("Epson RX8111 RTC driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3-59-g8ed1b From 29cee75fb66e6f2845360e0598974253bf79181a Mon Sep 17 00:00:00 2001 From: Alexandre Ghiti Date: Thu, 29 Feb 2024 13:10:55 +0100 Subject: riscv: Remove superfluous smp_mb() This memory barrier is not needed and not documented so simply remove it. Suggested-by: Andrea Parri Signed-off-by: Alexandre Ghiti Reviewed-by: Andrea Parri Link: https://lore.kernel.org/r/20240229121056.203419-2-alexghiti@rivosinc.com Signed-off-by: Palmer Dabbelt --- arch/riscv/kernel/patch.c | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/riscv/kernel/patch.c b/arch/riscv/kernel/patch.c index 37e87fdcf6a0..0b5c16dfe3f4 100644 --- a/arch/riscv/kernel/patch.c +++ b/arch/riscv/kernel/patch.c @@ -239,7 +239,6 @@ static int patch_text_cb(void *data) } else { while (atomic_read(&patch->cpu_count) <= num_online_cpus()) cpu_relax(); - smp_mb(); } return ret; -- cgit v1.2.3-59-g8ed1b From c97bf629963e52b205ed5fbaf151e5bd342f9c63 Mon Sep 17 00:00:00 2001 From: Alexandre Ghiti Date: Thu, 29 Feb 2024 13:10:56 +0100 Subject: riscv: Fix text patching when IPI are used MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For now, we use stop_machine() to patch the text and when we use IPIs for remote icache flushes (which is emitted in patch_text_nosync()), the system hangs. So instead, make sure every CPU executes the stop_machine() patching function and emit a local icache flush there. Co-developed-by: Björn Töpel Signed-off-by: Björn Töpel Signed-off-by: Alexandre Ghiti Reviewed-by: Andrea Parri Link: https://lore.kernel.org/r/20240229121056.203419-3-alexghiti@rivosinc.com Signed-off-by: Palmer Dabbelt --- arch/riscv/include/asm/patch.h | 1 + arch/riscv/kernel/ftrace.c | 44 ++++++++++++++++++++++++++++++++++++++---- arch/riscv/kernel/patch.c | 16 +++++++++++---- 3 files changed, 53 insertions(+), 8 deletions(-) diff --git a/arch/riscv/include/asm/patch.h b/arch/riscv/include/asm/patch.h index e88b52d39eac..9f5d6e14c405 100644 --- a/arch/riscv/include/asm/patch.h +++ b/arch/riscv/include/asm/patch.h @@ -6,6 +6,7 @@ #ifndef _ASM_RISCV_PATCH_H #define _ASM_RISCV_PATCH_H +int patch_insn_write(void *addr, const void *insn, size_t len); int patch_text_nosync(void *addr, const void *insns, size_t len); int patch_text_set_nosync(void *addr, u8 c, size_t len); int patch_text(void *addr, u32 *insns, int ninsns); diff --git a/arch/riscv/kernel/ftrace.c b/arch/riscv/kernel/ftrace.c index f5aa24d9e1c1..4f4987a6d83d 100644 --- a/arch/riscv/kernel/ftrace.c +++ b/arch/riscv/kernel/ftrace.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -75,8 +76,7 @@ static int __ftrace_modify_call(unsigned long hook_pos, unsigned long target, make_call_t0(hook_pos, target, call); /* Replace the auipc-jalr pair at once. Return -EPERM on write error. */ - if (patch_text_nosync - ((void *)hook_pos, enable ? call : nops, MCOUNT_INSN_SIZE)) + if (patch_insn_write((void *)hook_pos, enable ? call : nops, MCOUNT_INSN_SIZE)) return -EPERM; return 0; @@ -88,7 +88,7 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) make_call_t0(rec->ip, addr, call); - if (patch_text_nosync((void *)rec->ip, call, MCOUNT_INSN_SIZE)) + if (patch_insn_write((void *)rec->ip, call, MCOUNT_INSN_SIZE)) return -EPERM; return 0; @@ -99,7 +99,7 @@ int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec, { unsigned int nops[2] = {NOP4, NOP4}; - if (patch_text_nosync((void *)rec->ip, nops, MCOUNT_INSN_SIZE)) + if (patch_insn_write((void *)rec->ip, nops, MCOUNT_INSN_SIZE)) return -EPERM; return 0; @@ -134,6 +134,42 @@ int ftrace_update_ftrace_func(ftrace_func_t func) return ret; } + +struct ftrace_modify_param { + int command; + atomic_t cpu_count; +}; + +static int __ftrace_modify_code(void *data) +{ + struct ftrace_modify_param *param = data; + + if (atomic_inc_return(¶m->cpu_count) == num_online_cpus()) { + ftrace_modify_all_code(param->command); + /* + * Make sure the patching store is effective *before* we + * increment the counter which releases all waiting CPUs + * by using the release variant of atomic increment. The + * release pairs with the call to local_flush_icache_all() + * on the waiting CPU. + */ + atomic_inc_return_release(¶m->cpu_count); + } else { + while (atomic_read(¶m->cpu_count) <= num_online_cpus()) + cpu_relax(); + } + + local_flush_icache_all(); + + return 0; +} + +void arch_ftrace_update_code(int command) +{ + struct ftrace_modify_param param = { command, ATOMIC_INIT(0) }; + + stop_machine(__ftrace_modify_code, ¶m, cpu_online_mask); +} #endif #ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS diff --git a/arch/riscv/kernel/patch.c b/arch/riscv/kernel/patch.c index 0b5c16dfe3f4..9a1bce1adf5a 100644 --- a/arch/riscv/kernel/patch.c +++ b/arch/riscv/kernel/patch.c @@ -188,7 +188,7 @@ int patch_text_set_nosync(void *addr, u8 c, size_t len) } NOKPROBE_SYMBOL(patch_text_set_nosync); -static int patch_insn_write(void *addr, const void *insn, size_t len) +int patch_insn_write(void *addr, const void *insn, size_t len) { size_t patched = 0; size_t size; @@ -232,15 +232,23 @@ static int patch_text_cb(void *data) if (atomic_inc_return(&patch->cpu_count) == num_online_cpus()) { for (i = 0; ret == 0 && i < patch->ninsns; i++) { len = GET_INSN_LENGTH(patch->insns[i]); - ret = patch_text_nosync(patch->addr + i * len, - &patch->insns[i], len); + ret = patch_insn_write(patch->addr + i * len, &patch->insns[i], len); } - atomic_inc(&patch->cpu_count); + /* + * Make sure the patching store is effective *before* we + * increment the counter which releases all waiting CPUs + * by using the release variant of atomic increment. The + * release pairs with the call to local_flush_icache_all() + * on the waiting CPU. + */ + atomic_inc_return_release(&patch->cpu_count); } else { while (atomic_read(&patch->cpu_count) <= num_online_cpus()) cpu_relax(); } + local_flush_icache_all(); + return ret; } NOKPROBE_SYMBOL(patch_text_cb); -- cgit v1.2.3-59-g8ed1b From bebc345413f5fb4c8fafb59ff0bd8509197627e6 Mon Sep 17 00:00:00 2001 From: Charlie Jenkins Date: Tue, 12 Mar 2024 16:53:40 -0700 Subject: riscv: Remove unnecessary irqflags processor.h include This include is not used and can lead to circular dependencies. Signed-off-by: Charlie Jenkins Reviewed-by: Samuel Holland Link: https://lore.kernel.org/r/20240312-fencei-v13-1-4b6bdc2bbf32@rivosinc.com Signed-off-by: Palmer Dabbelt --- arch/riscv/include/asm/irqflags.h | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/riscv/include/asm/irqflags.h b/arch/riscv/include/asm/irqflags.h index 08d4d6a5b7e9..6fd8cbfcfcc7 100644 --- a/arch/riscv/include/asm/irqflags.h +++ b/arch/riscv/include/asm/irqflags.h @@ -7,7 +7,6 @@ #ifndef _ASM_RISCV_IRQFLAGS_H #define _ASM_RISCV_IRQFLAGS_H -#include #include /* read interrupt enabled status */ -- cgit v1.2.3-59-g8ed1b From 5f1149d2f4bff6269f04cceaf1038d6e80d27a62 Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Tue, 16 Apr 2024 09:19:04 +0200 Subject: serial: drop debugging WARN_ON_ONCE() from uart_put_char() Pengfei Xu reports, that the -next commit 1788cf6a91d9 (tty: serial: switch from circ_buf to kfifo) tries to emit a WARNING and that leads to lockdep errors. Obviously we cannot print anything from uart_put_char()! This WARN_ON_ONCE() was/is a debug aid to check if the condition in uart_put_char() can happen at all. Pengfei Xu confirmed it can. Unlike me and kbuild bot in my queue. Second, I completely forgot about it, so I did not remove it in the final version, nor mentioned it in the commit log. Drop it now as we are all good. And we even have stack traces (and a reproducer)! Signed-off-by: Jiri Slaby (SUSE) Reported-by: Pengfei Xu Link: https://lore.kernel.org/r/20240416071904.21440-1-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index a78ded8c60b5..5f88c45fbed3 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -558,7 +558,7 @@ static int uart_put_char(struct tty_struct *tty, u8 c) int ret = 0; port = uart_port_lock(state, flags); - if (WARN_ON_ONCE(!state->port.xmit_buf)) { + if (!state->port.xmit_buf) { uart_port_unlock(port, flags); return 0; } -- cgit v1.2.3-59-g8ed1b From abcd8632f26bbc24c4364b9cdf4feb8c9828c0c6 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 9 Apr 2024 20:40:57 +0300 Subject: serial: core: Extract uart_alloc_xmit_buf() and uart_free_xmit_buf() After conversion to the kfifo, it becomes possible to extract two helper functions for better maintenance and code deduplication. Do it here. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240409174057.1104262-1-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_core.c | 98 ++++++++++++++++++++++------------------ 1 file changed, 54 insertions(+), 44 deletions(-) diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 5f88c45fbed3..b9d631037ff6 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -243,25 +243,12 @@ static void uart_change_line_settings(struct tty_struct *tty, struct uart_state uart_port_unlock_irq(uport); } -/* - * Startup the port. This will be called once per open. All calls - * will be serialised by the per-port mutex. - */ -static int uart_port_startup(struct tty_struct *tty, struct uart_state *state, - bool init_hw) +static int uart_alloc_xmit_buf(struct tty_port *port) { - struct uart_port *uport = uart_port_check(state); + struct uart_state *state = container_of(port, struct uart_state, port); + struct uart_port *uport; unsigned long flags; unsigned long page; - int retval = 0; - - if (uport->type == PORT_UNKNOWN) - return 1; - - /* - * Make sure the device is in D0 state. - */ - uart_change_pm(state, UART_PM_STATE_ON); /* * Initialise and allocate the transmit and temporary @@ -271,7 +258,7 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state, if (!page) return -ENOMEM; - uart_port_lock(state, flags); + uport = uart_port_lock(state, flags); if (!state->port.xmit_buf) { state->port.xmit_buf = (unsigned char *)page; kfifo_init(&state->port.xmit_fifo, state->port.xmit_buf, @@ -281,11 +268,58 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state, uart_port_unlock(uport, flags); /* * Do not free() the page under the port lock, see - * uart_shutdown(). + * uart_free_xmit_buf(). */ free_page(page); } + return 0; +} + +static void uart_free_xmit_buf(struct tty_port *port) +{ + struct uart_state *state = container_of(port, struct uart_state, port); + struct uart_port *uport; + unsigned long flags; + char *xmit_buf; + + /* + * Do not free() the transmit buffer page under the port lock since + * this can create various circular locking scenarios. For instance, + * console driver may need to allocate/free a debug object, which + * can end up in printk() recursion. + */ + uport = uart_port_lock(state, flags); + xmit_buf = port->xmit_buf; + port->xmit_buf = NULL; + INIT_KFIFO(port->xmit_fifo); + uart_port_unlock(uport, flags); + + free_page((unsigned long)xmit_buf); +} + +/* + * Startup the port. This will be called once per open. All calls + * will be serialised by the per-port mutex. + */ +static int uart_port_startup(struct tty_struct *tty, struct uart_state *state, + bool init_hw) +{ + struct uart_port *uport = uart_port_check(state); + int retval; + + if (uport->type == PORT_UNKNOWN) + return 1; + + /* + * Make sure the device is in D0 state. + */ + uart_change_pm(state, UART_PM_STATE_ON); + + retval = uart_alloc_xmit_buf(&state->port); + if (retval) + return retval; + retval = uport->ops->startup(uport); if (retval == 0) { if (uart_console(uport) && uport->cons->cflag) { @@ -347,8 +381,6 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state) { struct uart_port *uport = uart_port_check(state); struct tty_port *port = &state->port; - unsigned long flags; - char *xmit_buf = NULL; /* * Set the TTY IO error marker @@ -381,19 +413,7 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state) */ tty_port_set_suspended(port, false); - /* - * Do not free() the transmit buffer page under the port lock since - * this can create various circular locking scenarios. For instance, - * console driver may need to allocate/free a debug object, which - * can endup in printk() recursion. - */ - uart_port_lock(state, flags); - xmit_buf = port->xmit_buf; - port->xmit_buf = NULL; - INIT_KFIFO(port->xmit_fifo); - uart_port_unlock(uport, flags); - - free_page((unsigned long)xmit_buf); + uart_free_xmit_buf(port); } /** @@ -1747,7 +1767,6 @@ static void uart_tty_port_shutdown(struct tty_port *port) { struct uart_state *state = container_of(port, struct uart_state, port); struct uart_port *uport = uart_port_check(state); - char *buf; /* * At this point, we stop accepting input. To do this, we @@ -1769,16 +1788,7 @@ static void uart_tty_port_shutdown(struct tty_port *port) */ tty_port_set_suspended(port, false); - /* - * Free the transmit buffer. - */ - uart_port_lock_irq(uport); - buf = port->xmit_buf; - port->xmit_buf = NULL; - INIT_KFIFO(port->xmit_fifo); - uart_port_unlock_irq(uport); - - free_page((unsigned long)buf); + uart_free_xmit_buf(port); uart_change_pm(state, UART_PM_STATE_OFF); } -- cgit v1.2.3-59-g8ed1b From e533e4c62e9993e62e947ae9bbec34e4c7ae81c2 Mon Sep 17 00:00:00 2001 From: Esben Haabendal Date: Thu, 11 Apr 2024 14:19:23 +0200 Subject: serial: imx: Introduce timeout when waiting on transmitter empty By waiting at most 1 second for USR2_TXDC to be set, we avoid a potential deadlock. In case of the timeout, there is not much we can do, so we simply ignore the transmitter state and optimistically try to continue. Signed-off-by: Esben Haabendal Acked-by: Marc Kleine-Budde Link: https://lore.kernel.org/r/919647898c337a46604edcabaf13d42d80c0915d.1712837613.git.esben@geanix.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/imx.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 56b76a221082..79f1503cd75b 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -2002,7 +2003,7 @@ imx_uart_console_write(struct console *co, const char *s, unsigned int count) struct imx_port *sport = imx_uart_ports[co->index]; struct imx_port_ucrs old_ucr; unsigned long flags; - unsigned int ucr1; + unsigned int ucr1, usr2; int locked = 1; if (sport->port.sysrq) @@ -2033,8 +2034,8 @@ imx_uart_console_write(struct console *co, const char *s, unsigned int count) * Finally, wait for transmitter to become empty * and restore UCR1/2/3 */ - while (!(imx_uart_readl(sport, USR2) & USR2_TXDC)); - + read_poll_timeout_atomic(imx_uart_readl, usr2, usr2 & USR2_TXDC, + 0, USEC_PER_SEC, false, sport, USR2); imx_uart_ucrs_restore(sport, &old_ucr); if (locked) -- cgit v1.2.3-59-g8ed1b From 5cb90c636d950c23ee63eea31fd03edbae99921f Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Thu, 11 Apr 2024 15:04:48 +0200 Subject: tty: serial: fsl_lpuart: use dev_err_probe for clocks Clocks might not be available yet when probing lpuart. Silence -517 errors by using dev_err_probe. Signed-off-by: Alexander Stein Link: https://lore.kernel.org/r/20240411130449.1096090-1-alexander.stein@ew.tq-group.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/fsl_lpuart.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index ae5e1ecc48fc..615291ea9b5e 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -2879,8 +2879,7 @@ static int lpuart_probe(struct platform_device *pdev) sport->ipg_clk = devm_clk_get(&pdev->dev, "ipg"); if (IS_ERR(sport->ipg_clk)) { ret = PTR_ERR(sport->ipg_clk); - dev_err(&pdev->dev, "failed to get uart ipg clk: %d\n", ret); - return ret; + return dev_err_probe(&pdev->dev, ret, "failed to get uart ipg clk\n"); } sport->baud_clk = NULL; @@ -2888,8 +2887,7 @@ static int lpuart_probe(struct platform_device *pdev) sport->baud_clk = devm_clk_get(&pdev->dev, "baud"); if (IS_ERR(sport->baud_clk)) { ret = PTR_ERR(sport->baud_clk); - dev_err(&pdev->dev, "failed to get uart baud clk: %d\n", ret); - return ret; + return dev_err_probe(&pdev->dev, ret, "failed to get uart baud clk\n"); } } -- cgit v1.2.3-59-g8ed1b From 6a533ed7350af50322a7e478a6557f1368222ea3 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 12 Apr 2024 20:39:31 +0300 Subject: serial: 8250_dw: Deduplicate LCR checks All callers of dw8250_check_lcr() perform the same check. Deduplicate it by moving them into respective call. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240412173931.187411-1-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_dw.c | 41 ++++++++++++++------------------------- 1 file changed, 15 insertions(+), 26 deletions(-) diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index a3acbf0f5da1..994604c77058 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -100,14 +100,18 @@ static void dw8250_force_idle(struct uart_port *p) (void)p->serial_in(p, UART_RX); } -static void dw8250_check_lcr(struct uart_port *p, int value) +static void dw8250_check_lcr(struct uart_port *p, int offset, int value) { - void __iomem *offset = p->membase + (UART_LCR << p->regshift); + struct dw8250_data *d = to_dw8250_data(p->private_data); + void __iomem *addr = p->membase + (offset << p->regshift); int tries = 1000; + if (offset != UART_LCR || d->uart_16550_compatible) + return; + /* Make sure LCR write wasn't ignored */ while (tries--) { - unsigned int lcr = p->serial_in(p, UART_LCR); + unsigned int lcr = p->serial_in(p, offset); if ((value & ~UART_LCR_SPAR) == (lcr & ~UART_LCR_SPAR)) return; @@ -116,15 +120,15 @@ static void dw8250_check_lcr(struct uart_port *p, int value) #ifdef CONFIG_64BIT if (p->type == PORT_OCTEON) - __raw_writeq(value & 0xff, offset); + __raw_writeq(value & 0xff, addr); else #endif if (p->iotype == UPIO_MEM32) - writel(value, offset); + writel(value, addr); else if (p->iotype == UPIO_MEM32BE) - iowrite32be(value, offset); + iowrite32be(value, addr); else - writeb(value, offset); + writeb(value, addr); } /* * FIXME: this deadlocks if port->lock is already held @@ -158,12 +162,8 @@ static void dw8250_tx_wait_empty(struct uart_port *p) static void dw8250_serial_out(struct uart_port *p, int offset, int value) { - struct dw8250_data *d = to_dw8250_data(p->private_data); - writeb(value, p->membase + (offset << p->regshift)); - - if (offset == UART_LCR && !d->uart_16550_compatible) - dw8250_check_lcr(p, value); + dw8250_check_lcr(p, offset, value); } static void dw8250_serial_out38x(struct uart_port *p, int offset, int value) @@ -194,26 +194,19 @@ static unsigned int dw8250_serial_inq(struct uart_port *p, int offset) static void dw8250_serial_outq(struct uart_port *p, int offset, int value) { - struct dw8250_data *d = to_dw8250_data(p->private_data); - value &= 0xff; __raw_writeq(value, p->membase + (offset << p->regshift)); /* Read back to ensure register write ordering. */ __raw_readq(p->membase + (UART_LCR << p->regshift)); - if (offset == UART_LCR && !d->uart_16550_compatible) - dw8250_check_lcr(p, value); + dw8250_check_lcr(p, offset, value); } #endif /* CONFIG_64BIT */ static void dw8250_serial_out32(struct uart_port *p, int offset, int value) { - struct dw8250_data *d = to_dw8250_data(p->private_data); - writel(value, p->membase + (offset << p->regshift)); - - if (offset == UART_LCR && !d->uart_16550_compatible) - dw8250_check_lcr(p, value); + dw8250_check_lcr(p, offset, value); } static unsigned int dw8250_serial_in32(struct uart_port *p, int offset) @@ -225,12 +218,8 @@ static unsigned int dw8250_serial_in32(struct uart_port *p, int offset) static void dw8250_serial_out32be(struct uart_port *p, int offset, int value) { - struct dw8250_data *d = to_dw8250_data(p->private_data); - iowrite32be(value, p->membase + (offset << p->regshift)); - - if (offset == UART_LCR && !d->uart_16550_compatible) - dw8250_check_lcr(p, value); + dw8250_check_lcr(p, offset, value); } static unsigned int dw8250_serial_in32be(struct uart_port *p, int offset) -- cgit v1.2.3-59-g8ed1b From c205edcd86dac01c205e4eadf6d0d95965e7a566 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 12 Apr 2024 20:39:37 +0300 Subject: serial: 8250_dw: Hide a cast in dw8250_serial_inq() dw8250_serial_inq() uses unsigned int variable to store 8-bit value. Due to that it needs a cast which can be avoided by switching to use u8 instead of unsigned int. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240412173937.187442-1-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_dw.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index 994604c77058..db0e67186a8b 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -185,9 +185,7 @@ static unsigned int dw8250_serial_in(struct uart_port *p, int offset) #ifdef CONFIG_64BIT static unsigned int dw8250_serial_inq(struct uart_port *p, int offset) { - unsigned int value; - - value = (u8)__raw_readq(p->membase + (offset << p->regshift)); + u8 value = __raw_readq(p->membase + (offset << p->regshift)); return dw8250_modify_msr(p, offset, value); } -- cgit v1.2.3-59-g8ed1b From 2a49b45cd0e7e8c9a0cd5e2f3993b558469ed744 Mon Sep 17 00:00:00 2001 From: Guanbing Huang Date: Tue, 16 Apr 2024 11:16:18 +0800 Subject: PNP: Add dev_is_pnp() macro Add dev_is_pnp() macro to determine whether the device is a PNP device. Signed-off-by: Guanbing Huang Suggested-by: Andy Shevchenko Reviewed-by: Bing Fan Tested-by: Linheng Du Reviewed-by: Andy Shevchenko Acked-by: Rafael J. Wysocki Link: https://lore.kernel.org/r/4e68f5557ad53b671ca8103e572163eca52a8f29.1713234515.git.albanhuang@tencent.com Signed-off-by: Greg Kroah-Hartman --- include/linux/pnp.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/linux/pnp.h b/include/linux/pnp.h index ddbe7c3ca4ce..82561242cda4 100644 --- a/include/linux/pnp.h +++ b/include/linux/pnp.h @@ -469,6 +469,8 @@ int compare_pnp_id(struct pnp_id *pos, const char *id); int pnp_register_driver(struct pnp_driver *drv); void pnp_unregister_driver(struct pnp_driver *drv); +#define dev_is_pnp(d) ((d)->bus == &pnp_bus_type) + #else /* device management */ @@ -500,6 +502,8 @@ static inline int compare_pnp_id(struct pnp_id *pos, const char *id) { return -E static inline int pnp_register_driver(struct pnp_driver *drv) { return -ENODEV; } static inline void pnp_unregister_driver(struct pnp_driver *drv) { } +#define dev_is_pnp(d) false + #endif /* CONFIG_PNP */ /** -- cgit v1.2.3-59-g8ed1b From 18ba7f2d99f698251294fe9521da3f00d03f96aa Mon Sep 17 00:00:00 2001 From: Guanbing Huang Date: Tue, 16 Apr 2024 11:16:37 +0800 Subject: serial: port: Add support of PNP IRQ to __uart_read_properties() The function __uart_read_properties doesn't cover PNP devices, so add IRQ processing for PNP devices in the branch. Signed-off-by: Guanbing Huang Suggested-by: Andy Shevchenko Reviewed-by: Andy Shevchenko Reviewed-by: Bing Fan Tested-by: Linheng Du Link: https://lore.kernel.org/r/7f4ca31ef1cab4c6ecad22fafd82117686b696be.1713234515.git.albanhuang@tencent.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_port.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/tty/serial/serial_port.c b/drivers/tty/serial/serial_port.c index 3408c8827561..47dd8c3fd06d 100644 --- a/drivers/tty/serial/serial_port.c +++ b/drivers/tty/serial/serial_port.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -221,7 +222,11 @@ static int __uart_read_properties(struct uart_port *port, bool use_defaults) if (dev_is_platform(dev)) ret = platform_get_irq(to_platform_device(dev), 0); - else + else if (dev_is_pnp(dev)) { + ret = pnp_irq(to_pnp_dev(dev), 0); + if (ret < 0) + ret = -ENXIO; + } else ret = fwnode_irq_get(dev_fwnode(dev), 0); if (ret == -EPROBE_DEFER) return ret; -- cgit v1.2.3-59-g8ed1b From 64c79dfbc45863821e172a606f453b39c8a8be6b Mon Sep 17 00:00:00 2001 From: Guanbing Huang Date: Tue, 16 Apr 2024 11:16:59 +0800 Subject: serial: 8250_pnp: Support configurable reg shift property The 16550a serial port based on the ACPI table requires obtaining the reg-shift attribute. In the ACPI scenario, If the reg-shift property is not configured like in DTS, the 16550a serial driver cannot read or write controller registers properly during initialization. Signed-off-by: Guanbing Huang Suggested-by: Andy Shevchenko Reviewed-by: Andy Shevchenko Reviewed-by: Bing Fan Tested-by: Linheng Du Link: https://lore.kernel.org/r/4726ecea8f7bfbfe42501b4f6ad9fe5b38994574.1713234515.git.albanhuang@tencent.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_pnp.c | 40 ++++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/drivers/tty/serial/8250/8250_pnp.c b/drivers/tty/serial/8250/8250_pnp.c index 1974bbadc975..8f72a7de1d1d 100644 --- a/drivers/tty/serial/8250/8250_pnp.c +++ b/drivers/tty/serial/8250/8250_pnp.c @@ -435,6 +435,7 @@ serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id) { struct uart_8250_port uart, *port; int ret, line, flags = dev_id->driver_data; + unsigned char iotype; if (flags & UNKNOWN_DEV) { ret = serial_pnp_guess_board(dev); @@ -443,37 +444,46 @@ serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id) } memset(&uart, 0, sizeof(uart)); - if (pnp_irq_valid(dev, 0)) - uart.port.irq = pnp_irq(dev, 0); if ((flags & CIR_PORT) && pnp_port_valid(dev, 2)) { uart.port.iobase = pnp_port_start(dev, 2); - uart.port.iotype = UPIO_PORT; + iotype = UPIO_PORT; } else if (pnp_port_valid(dev, 0)) { uart.port.iobase = pnp_port_start(dev, 0); - uart.port.iotype = UPIO_PORT; + iotype = UPIO_PORT; } else if (pnp_mem_valid(dev, 0)) { uart.port.mapbase = pnp_mem_start(dev, 0); - uart.port.iotype = UPIO_MEM; + uart.port.mapsize = pnp_mem_len(dev, 0); + iotype = UPIO_MEM; uart.port.flags = UPF_IOREMAP; } else return -ENODEV; - dev_dbg(&dev->dev, - "Setup PNP port: port %#lx, mem %#llx, irq %u, type %u\n", - uart.port.iobase, (unsigned long long)uart.port.mapbase, - uart.port.irq, uart.port.iotype); + uart.port.uartclk = 1843200; + uart.port.dev = &dev->dev; + uart.port.flags |= UPF_SKIP_TEST | UPF_BOOT_AUTOCONF; + + ret = uart_read_port_properties(&uart.port); + /* no interrupt -> fall back to polling */ + if (ret == -ENXIO) + ret = 0; + if (ret) + return ret; + + /* + * The previous call may not set iotype correctly when reg-io-width + * property is absent and it doesn't support IO port resource. + */ + uart.port.iotype = iotype; if (flags & CIR_PORT) { uart.port.flags |= UPF_FIXED_PORT | UPF_FIXED_TYPE; uart.port.type = PORT_8250_CIR; } - uart.port.flags |= UPF_SKIP_TEST | UPF_BOOT_AUTOCONF; - if (pnp_irq_flags(dev, 0) & IORESOURCE_IRQ_SHAREABLE) - uart.port.flags |= UPF_SHARE_IRQ; - uart.port.uartclk = 1843200; - device_property_read_u32(&dev->dev, "clock-frequency", &uart.port.uartclk); - uart.port.dev = &dev->dev; + dev_dbg(&dev->dev, + "Setup PNP port: port %#lx, mem %#llx, size %#llx, irq %u, type %u\n", + uart.port.iobase, (unsigned long long)uart.port.mapbase, + (unsigned long long)uart.port.mapsize, uart.port.irq, uart.port.iotype); line = serial8250_register_8250_port(&uart); if (line < 0 || (flags & CIR_PORT)) -- cgit v1.2.3-59-g8ed1b From b86ae40ffcf5a16b9569b1016da4a08c4f352ca2 Mon Sep 17 00:00:00 2001 From: Parker Newman Date: Tue, 16 Apr 2024 08:55:28 -0400 Subject: serial: exar: adding missing CTI and Exar PCI ids - Added Connect Tech and Exar IDs not already in pci_ids.h Signed-off-by: Parker Newman Link: https://lore.kernel.org/r/7c3d8e795a864dd9b0a00353b722060dc27c4e09.1713270624.git.pnewman@connecttech.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_exar.c | 42 +++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c index f89dabfc0f97..604e5a292d4e 100644 --- a/drivers/tty/serial/8250/8250_exar.c +++ b/drivers/tty/serial/8250/8250_exar.c @@ -46,8 +46,50 @@ #define PCI_DEVICE_ID_COMMTECH_4228PCIE 0x0021 #define PCI_DEVICE_ID_COMMTECH_4222PCIE 0x0022 +#define PCI_VENDOR_ID_CONNECT_TECH 0x12c4 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_SP_OPTO 0x0340 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_SP_OPTO_A 0x0341 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_SP_OPTO_B 0x0342 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_XPRS 0x0350 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_XPRS_A 0x0351 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_XPRS_B 0x0352 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_XPRS 0x0353 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_16_XPRS_A 0x0354 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_16_XPRS_B 0x0355 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_XPRS_OPTO 0x0360 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_XPRS_OPTO_A 0x0361 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_XPRS_OPTO_B 0x0362 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_SP 0x0370 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_SP_232 0x0371 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_SP_485 0x0372 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_4_SP 0x0373 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_6_2_SP 0x0374 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_6_SP 0x0375 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_SP_232_NS 0x0376 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_XP_OPTO_LEFT 0x0380 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_XP_OPTO_RIGHT 0x0381 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_XP_OPTO 0x0382 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_4_XPRS_OPTO 0x0392 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_XPRS_LP 0x03A0 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_XPRS_LP_232 0x03A1 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_XPRS_LP_485 0x03A2 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_XPRS_LP_232_NS 0x03A3 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCIE_XEG001 0x0602 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCIE_XR35X_BASE 0x1000 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCIE_XR35X_2 0x1002 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCIE_XR35X_4 0x1004 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCIE_XR35X_8 0x1008 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCIE_XR35X_12 0x100C +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCIE_XR35X_16 0x1010 +#define PCI_DEVICE_ID_CONNECT_TECH_PCI_XR79X_12_XIG00X 0x110c +#define PCI_DEVICE_ID_CONNECT_TECH_PCI_XR79X_12_XIG01X 0x110d +#define PCI_DEVICE_ID_CONNECT_TECH_PCI_XR79X_16 0x1110 + #define PCI_DEVICE_ID_EXAR_XR17V4358 0x4358 #define PCI_DEVICE_ID_EXAR_XR17V8358 0x8358 +#define PCI_DEVICE_ID_EXAR_XR17V252 0x0252 +#define PCI_DEVICE_ID_EXAR_XR17V254 0x0254 +#define PCI_DEVICE_ID_EXAR_XR17V258 0x0258 #define PCI_SUBDEVICE_ID_USR_2980 0x0128 #define PCI_SUBDEVICE_ID_USR_2981 0x0129 -- cgit v1.2.3-59-g8ed1b From cef359074cad6456aa060f4d701bd519a5c7baff Mon Sep 17 00:00:00 2001 From: Lenko Donchev Date: Sat, 10 Feb 2024 19:53:14 -0600 Subject: fs/ntfs3: use kcalloc() instead of kzalloc() We are trying to get rid of all multiplications from allocation functions to prevent integer overflows[1]. Here the multiplication is obviously safe, but using kcalloc() is more appropriate and improves readability. This patch has no effect on runtime behavior. Link: https://github.com/KSPP/linux/issues/162 [1] Link: https://www.kernel.org/doc/html/next/process/deprecated.html#open-coded-arithmetic-in-allocator-arguments [2] Signed-off-by: Lenko Donchev Signed-off-by: Konstantin Komarov --- fs/ntfs3/frecord.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ntfs3/frecord.c b/fs/ntfs3/frecord.c index 7f27382e0ce2..0008670939a4 100644 --- a/fs/ntfs3/frecord.c +++ b/fs/ntfs3/frecord.c @@ -2636,7 +2636,7 @@ int ni_read_frame(struct ntfs_inode *ni, u64 frame_vbo, struct page **pages, goto out1; } - pages_disk = kzalloc(npages_disk * sizeof(struct page *), GFP_NOFS); + pages_disk = kcalloc(npages_disk, sizeof(*pages_disk), GFP_NOFS); if (!pages_disk) { err = -ENOMEM; goto out2; -- cgit v1.2.3-59-g8ed1b From 93b4d70f6a4129fcfad18deae248bf89c129d1b5 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Mon, 18 Mar 2024 14:28:50 -0400 Subject: fs/ntfs3: remove atomic_open atomic_open is an optional VFS operation, and is primarily for network filesystems. NFS (for instance) can just send an open call for the last path component rather than doing a lookup and then having to follow that up with an open when it doesn't have a dentry in cache. ntfs3 is a local filesystem however, and its atomic_open just does a typical lookup + open, but in a convoluted way. atomic_open will also make directory leases more difficult to implement on the filesystem. Remove ntfs_atomic_open. Signed-off-by: Jeff Layton Signed-off-by: Konstantin Komarov --- fs/ntfs3/namei.c | 90 -------------------------------------------------------- 1 file changed, 90 deletions(-) diff --git a/fs/ntfs3/namei.c b/fs/ntfs3/namei.c index 084d19d78397..edb6a7141246 100644 --- a/fs/ntfs3/namei.c +++ b/fs/ntfs3/namei.c @@ -358,95 +358,6 @@ out: return err; } -/* - * ntfs_atomic_open - * - * inode_operations::atomic_open - */ -static int ntfs_atomic_open(struct inode *dir, struct dentry *dentry, - struct file *file, u32 flags, umode_t mode) -{ - int err; - struct inode *inode; - struct ntfs_fnd *fnd = NULL; - struct ntfs_inode *ni = ntfs_i(dir); - struct dentry *d = NULL; - struct cpu_str *uni = __getname(); - bool locked = false; - - if (!uni) - return -ENOMEM; - - err = ntfs_nls_to_utf16(ni->mi.sbi, dentry->d_name.name, - dentry->d_name.len, uni, NTFS_NAME_LEN, - UTF16_HOST_ENDIAN); - if (err < 0) - goto out; - -#ifdef CONFIG_NTFS3_FS_POSIX_ACL - if (IS_POSIXACL(dir)) { - /* - * Load in cache current acl to avoid ni_lock(dir): - * ntfs_create_inode -> ntfs_init_acl -> posix_acl_create -> - * ntfs_get_acl -> ntfs_get_acl_ex -> ni_lock - */ - struct posix_acl *p = get_inode_acl(dir, ACL_TYPE_DEFAULT); - - if (IS_ERR(p)) { - err = PTR_ERR(p); - goto out; - } - posix_acl_release(p); - } -#endif - - if (d_in_lookup(dentry)) { - ni_lock_dir(ni); - locked = true; - fnd = fnd_get(); - if (!fnd) { - err = -ENOMEM; - goto out1; - } - - d = d_splice_alias(dir_search_u(dir, uni, fnd), dentry); - if (IS_ERR(d)) { - err = PTR_ERR(d); - d = NULL; - goto out2; - } - - if (d) - dentry = d; - } - - if (!(flags & O_CREAT) || d_really_is_positive(dentry)) { - err = finish_no_open(file, d); - goto out2; - } - - file->f_mode |= FMODE_CREATED; - - /* - * fnd contains tree's path to insert to. - * If fnd is not NULL then dir is locked. - */ - inode = ntfs_create_inode(file_mnt_idmap(file), dir, dentry, uni, - mode, 0, NULL, 0, fnd); - err = IS_ERR(inode) ? PTR_ERR(inode) : - finish_open(file, dentry, ntfs_file_open); - dput(d); - -out2: - fnd_put(fnd); -out1: - if (locked) - ni_unlock(ni); -out: - __putname(uni); - return err; -} - struct dentry *ntfs3_get_parent(struct dentry *child) { struct inode *inode = d_inode(child); @@ -612,7 +523,6 @@ const struct inode_operations ntfs_dir_inode_operations = { .setattr = ntfs3_setattr, .getattr = ntfs_getattr, .listxattr = ntfs_listxattr, - .atomic_open = ntfs_atomic_open, .fiemap = ntfs_fiemap, }; -- cgit v1.2.3-59-g8ed1b From c9342d1a351ee1249fa98d936f756299a83d5684 Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Tue, 16 Apr 2024 16:51:23 +0200 Subject: phy: rockchip: usbdp: fix uninitialized variable The ret variable may not be initialized in rk_udphy_usb3_phy_init(), if the PHY is not using USB3 mode. Since the DisplayPort part is handled separately and the PHY does not support USB2 (which is routed to another PHY on Rockchip RK3588), the right exit code for this case is 0. Thus let's initialize the variable accordingly. Fixes: 2f70bbddeb457 ("phy: rockchip: add usbdp combo phy driver") Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202404141048.qFAYDctQ-lkp@intel.com/ Signed-off-by: Sebastian Reichel Reviewed-by: Muhammad Usama Anjum Link: https://lore.kernel.org/r/20240416145233.94687-1-sebastian.reichel@collabora.com Signed-off-by: Vinod Koul --- drivers/phy/rockchip/phy-rockchip-usbdp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c index 32f306459182..2c51e5c62d3e 100644 --- a/drivers/phy/rockchip/phy-rockchip-usbdp.c +++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c @@ -1285,7 +1285,7 @@ static const struct phy_ops rk_udphy_dp_phy_ops = { static int rk_udphy_usb3_phy_init(struct phy *phy) { struct rk_udphy *udphy = phy_get_drvdata(phy); - int ret; + int ret = 0; mutex_lock(&udphy->mutex); /* DP only or high-speed, disable U3 port */ -- cgit v1.2.3-59-g8ed1b From 9c79b779643e56d4253bd3ba6998c58c819943af Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 15 Apr 2024 19:42:25 +0200 Subject: phy: rockchip: fix CONFIG_TYPEC dependency The newly added driver causes a warning about missing dependencies by selecting CONFIG_TYPEC unconditionally: WARNING: unmet direct dependencies detected for TYPEC Depends on [n]: USB_SUPPORT [=n] Selected by [y]: - PHY_ROCKCHIP_USBDP [=y] && ARCH_ROCKCHIP [=y] && OF [=y] WARNING: unmet direct dependencies detected for USB_COMMON Depends on [n]: USB_SUPPORT [=n] Selected by [y]: - EXTCON_RTK_TYPE_C [=y] && EXTCON [=y] && (ARCH_REALTEK [=y] || COMPILE_TEST [=y]) && TYPEC [=y] Since that is a user-visible option, it should not really be selected in the first place. Replace the 'select' with a 'depends on' as we have for similar drivers. Fixes: 2f70bbddeb45 ("phy: rockchip: add usbdp combo phy driver") Signed-off-by: Arnd Bergmann Reviewed-by: Heiko Stuebner Link: https://lore.kernel.org/r/20240415174241.77982-1-arnd@kernel.org Signed-off-by: Vinod Koul --- drivers/phy/rockchip/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/phy/rockchip/Kconfig b/drivers/phy/rockchip/Kconfig index c3d62243b474..89ed32b3b12e 100644 --- a/drivers/phy/rockchip/Kconfig +++ b/drivers/phy/rockchip/Kconfig @@ -119,8 +119,8 @@ config PHY_ROCKCHIP_USB config PHY_ROCKCHIP_USBDP tristate "Rockchip USBDP COMBO PHY Driver" depends on ARCH_ROCKCHIP && OF + depends on TYPEC select GENERIC_PHY - select TYPEC help Enable this to support the Rockchip USB3.0/DP combo PHY with Samsung IP block. This is required for USB3 support on RK3588. -- cgit v1.2.3-59-g8ed1b From 0993d724674a9d905ebdc9b9cd0b64e30523c5d6 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Thu, 11 Apr 2024 11:17:16 -0700 Subject: perf hist: Move histogram related code to hist.h It's strange that sort.h has the definition of struct hist_entry. As sort.h already includes hist.h, let's move the data structure to hist.h. Signed-off-by: Namhyung Kim Cc: Adrian Hunter Cc: Andi Kleen Cc: Athira Rajeev Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Peter Zijlstra Cc: Stephane Eranian Link: https://lore.kernel.org/r/20240411181718.2367948-1-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/hist.h | 191 +++++++++++++++++++++++++++++++++++++++++++++-- tools/perf/util/sort.h | 188 ---------------------------------------------- tools/perf/util/values.h | 1 + 3 files changed, 184 insertions(+), 196 deletions(-) diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 4a0aea0c9e00..8f072f3749eb 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -4,21 +4,22 @@ #include #include -#include "evsel.h" +#include "callchain.h" #include "color.h" #include "events_stats.h" +#include "evsel.h" +#include "map_symbol.h" #include "mutex.h" +#include "sample.h" +#include "spark.h" +#include "stat.h" -struct hist_entry; -struct hist_entry_ops; struct addr_location; -struct map_symbol; struct mem_info; struct kvm_info; struct branch_info; struct branch_stack; struct block_info; -struct symbol; struct ui_progress; enum hist_filter { @@ -150,6 +151,159 @@ extern const struct hist_iter_ops hist_iter_branch; extern const struct hist_iter_ops hist_iter_mem; extern const struct hist_iter_ops hist_iter_cumulative; +struct res_sample { + u64 time; + int cpu; + int tid; +}; + +struct he_stat { + u64 period; + u64 period_sys; + u64 period_us; + u64 period_guest_sys; + u64 period_guest_us; + u32 nr_events; +}; + +struct namespace_id { + u64 dev; + u64 ino; +}; + +struct hist_entry_diff { + bool computed; + union { + /* PERF_HPP__DELTA */ + double period_ratio_delta; + + /* PERF_HPP__RATIO */ + double period_ratio; + + /* HISTC_WEIGHTED_DIFF */ + s64 wdiff; + + /* PERF_HPP_DIFF__CYCLES */ + s64 cycles; + }; + struct stats stats; + unsigned long svals[NUM_SPARKS]; +}; + +struct hist_entry_ops { + void *(*new)(size_t size); + void (*free)(void *ptr); +}; + +/** + * struct hist_entry - histogram entry + * + * @row_offset - offset from the first callchain expanded to appear on screen + * @nr_rows - rows expanded in callchain, recalculated on folding/unfolding + */ +struct hist_entry { + struct rb_node rb_node_in; + struct rb_node rb_node; + union { + struct list_head node; + struct list_head head; + } pairs; + struct he_stat stat; + struct he_stat *stat_acc; + struct map_symbol ms; + struct thread *thread; + struct comm *comm; + struct namespace_id cgroup_id; + u64 cgroup; + u64 ip; + u64 transaction; + s32 socket; + s32 cpu; + u64 code_page_size; + u64 weight; + u64 ins_lat; + u64 p_stage_cyc; + u8 cpumode; + u8 depth; + int mem_type_off; + struct simd_flags simd_flags; + + /* We are added by hists__add_dummy_entry. */ + bool dummy; + bool leaf; + + char level; + u8 filtered; + + u16 callchain_size; + union { + /* + * Since perf diff only supports the stdio output, TUI + * fields are only accessed from perf report (or perf + * top). So make it a union to reduce memory usage. + */ + struct hist_entry_diff diff; + struct /* for TUI */ { + u16 row_offset; + u16 nr_rows; + bool init_have_children; + bool unfolded; + bool has_children; + bool has_no_entry; + }; + }; + char *srcline; + char *srcfile; + struct symbol *parent; + struct branch_info *branch_info; + long time; + struct hists *hists; + struct mem_info *mem_info; + struct block_info *block_info; + struct kvm_info *kvm_info; + void *raw_data; + u32 raw_size; + int num_res; + struct res_sample *res_samples; + void *trace_output; + struct perf_hpp_list *hpp_list; + struct hist_entry *parent_he; + struct hist_entry_ops *ops; + struct annotated_data_type *mem_type; + union { + /* this is for hierarchical entry structure */ + struct { + struct rb_root_cached hroot_in; + struct rb_root_cached hroot_out; + }; /* non-leaf entries */ + struct rb_root sorted_chain; /* leaf entry has callchains */ + }; + struct callchain_root callchain[0]; /* must be last member */ +}; + +static __pure inline bool hist_entry__has_callchains(struct hist_entry *he) +{ + return he->callchain_size != 0; +} + +static inline bool hist_entry__has_pairs(struct hist_entry *he) +{ + return !list_empty(&he->pairs.node); +} + +static inline struct hist_entry *hist_entry__next_pair(struct hist_entry *he) +{ + if (hist_entry__has_pairs(he)) + return list_entry(he->pairs.node.next, struct hist_entry, pairs.node); + return NULL; +} + +static inline void hist_entry__add_pair(struct hist_entry *pair, + struct hist_entry *he) +{ + list_add_tail(&pair->pairs.node, &he->pairs.head); +} + struct hist_entry *hists__add_entry(struct hists *hists, struct addr_location *al, struct symbol *parent, @@ -186,6 +340,8 @@ int hist_entry__sort_snprintf(struct hist_entry *he, char *bf, size_t size, struct hists *hists); int hist_entry__snprintf_alignment(struct hist_entry *he, struct perf_hpp *hpp, struct perf_hpp_fmt *fmt, int printed); +int hist_entry__sym_snprintf(struct hist_entry *he, char *bf, size_t size, + unsigned int width); void hist_entry__delete(struct hist_entry *he); typedef int (*hists__resort_cb_t)(struct hist_entry *he, void *arg); @@ -238,6 +394,20 @@ void hists__match(struct hists *leader, struct hists *other); int hists__link(struct hists *leader, struct hists *other); int hists__unlink(struct hists *hists); +static inline float hist_entry__get_percent_limit(struct hist_entry *he) +{ + u64 period = he->stat.period; + u64 total_period = hists__total_period(he->hists); + + if (unlikely(total_period == 0)) + return 0; + + if (symbol_conf.cumulate_callchain) + period = he->stat_acc->period; + + return period * 100.0 / total_period; +} + struct hists_evsel { struct evsel evsel; struct hists hists; @@ -460,15 +630,20 @@ struct hist_browser_timer { int refresh; }; -struct res_sample; - enum rstype { A_NORMAL, A_ASM, A_SOURCE }; -struct block_hist; +struct block_hist { + struct hists block_hists; + struct perf_hpp_list block_list; + struct perf_hpp_fmt block_fmt; + int block_idx; + bool valid; + struct hist_entry he; +}; #ifdef HAVE_SLANG_SUPPORT #include "../ui/keysyms.h" diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index 6f6b4189a389..690892a92cf3 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h @@ -3,19 +3,9 @@ #define __PERF_SORT_H #include #include -#include -#include -#include "map_symbol.h" -#include "symbol_conf.h" -#include "callchain.h" -#include "values.h" #include "hist.h" -#include "stat.h" -#include "spark.h" struct option; -struct thread; -struct annotated_data_type; extern regex_t parent_regex; extern const char *sort_order; @@ -39,175 +29,6 @@ extern struct sort_entry sort_type; extern const char default_mem_sort_order[]; extern bool chk_double_cl; -struct res_sample { - u64 time; - int cpu; - int tid; -}; - -struct he_stat { - u64 period; - u64 period_sys; - u64 period_us; - u64 period_guest_sys; - u64 period_guest_us; - u32 nr_events; -}; - -struct namespace_id { - u64 dev; - u64 ino; -}; - -struct hist_entry_diff { - bool computed; - union { - /* PERF_HPP__DELTA */ - double period_ratio_delta; - - /* PERF_HPP__RATIO */ - double period_ratio; - - /* HISTC_WEIGHTED_DIFF */ - s64 wdiff; - - /* PERF_HPP_DIFF__CYCLES */ - s64 cycles; - }; - struct stats stats; - unsigned long svals[NUM_SPARKS]; -}; - -struct hist_entry_ops { - void *(*new)(size_t size); - void (*free)(void *ptr); -}; - -/** - * struct hist_entry - histogram entry - * - * @row_offset - offset from the first callchain expanded to appear on screen - * @nr_rows - rows expanded in callchain, recalculated on folding/unfolding - */ -struct hist_entry { - struct rb_node rb_node_in; - struct rb_node rb_node; - union { - struct list_head node; - struct list_head head; - } pairs; - struct he_stat stat; - struct he_stat *stat_acc; - struct map_symbol ms; - struct thread *thread; - struct comm *comm; - struct namespace_id cgroup_id; - u64 cgroup; - u64 ip; - u64 transaction; - s32 socket; - s32 cpu; - u64 code_page_size; - u64 weight; - u64 ins_lat; - u64 p_stage_cyc; - u8 cpumode; - u8 depth; - int mem_type_off; - struct simd_flags simd_flags; - - /* We are added by hists__add_dummy_entry. */ - bool dummy; - bool leaf; - - char level; - u8 filtered; - - u16 callchain_size; - union { - /* - * Since perf diff only supports the stdio output, TUI - * fields are only accessed from perf report (or perf - * top). So make it a union to reduce memory usage. - */ - struct hist_entry_diff diff; - struct /* for TUI */ { - u16 row_offset; - u16 nr_rows; - bool init_have_children; - bool unfolded; - bool has_children; - bool has_no_entry; - }; - }; - char *srcline; - char *srcfile; - struct symbol *parent; - struct branch_info *branch_info; - long time; - struct hists *hists; - struct mem_info *mem_info; - struct block_info *block_info; - struct kvm_info *kvm_info; - void *raw_data; - u32 raw_size; - int num_res; - struct res_sample *res_samples; - void *trace_output; - struct perf_hpp_list *hpp_list; - struct hist_entry *parent_he; - struct hist_entry_ops *ops; - struct annotated_data_type *mem_type; - union { - /* this is for hierarchical entry structure */ - struct { - struct rb_root_cached hroot_in; - struct rb_root_cached hroot_out; - }; /* non-leaf entries */ - struct rb_root sorted_chain; /* leaf entry has callchains */ - }; - struct callchain_root callchain[0]; /* must be last member */ -}; - -static __pure inline bool hist_entry__has_callchains(struct hist_entry *he) -{ - return he->callchain_size != 0; -} - -int hist_entry__sym_snprintf(struct hist_entry *he, char *bf, size_t size, unsigned int width); - -static inline bool hist_entry__has_pairs(struct hist_entry *he) -{ - return !list_empty(&he->pairs.node); -} - -static inline struct hist_entry *hist_entry__next_pair(struct hist_entry *he) -{ - if (hist_entry__has_pairs(he)) - return list_entry(he->pairs.node.next, struct hist_entry, pairs.node); - return NULL; -} - -static inline void hist_entry__add_pair(struct hist_entry *pair, - struct hist_entry *he) -{ - list_add_tail(&pair->pairs.node, &he->pairs.head); -} - -static inline float hist_entry__get_percent_limit(struct hist_entry *he) -{ - u64 period = he->stat.period; - u64 total_period = hists__total_period(he->hists); - - if (unlikely(total_period == 0)) - return 0; - - if (symbol_conf.cumulate_callchain) - period = he->stat_acc->period; - - return period * 100.0 / total_period; -} - enum sort_mode { SORT_MODE__NORMAL, SORT_MODE__BRANCH, @@ -299,15 +120,6 @@ struct sort_entry { u8 se_width_idx; }; -struct block_hist { - struct hists block_hists; - struct perf_hpp_list block_list; - struct perf_hpp_fmt block_fmt; - int block_idx; - bool valid; - struct hist_entry he; -}; - extern struct sort_entry sort_thread; struct evlist; diff --git a/tools/perf/util/values.h b/tools/perf/util/values.h index 8c41f22f42cf..791c1ad606c2 100644 --- a/tools/perf/util/values.h +++ b/tools/perf/util/values.h @@ -2,6 +2,7 @@ #ifndef __PERF_VALUES_H #define __PERF_VALUES_H +#include #include struct perf_read_values { -- cgit v1.2.3-59-g8ed1b From 6fcf1e65253c52a7584817cbd3393c63d5660467 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Thu, 11 Apr 2024 11:17:17 -0700 Subject: perf hist: Add weight fields to hist entry stats Like period and sample numbers, it'd be better to track weight values and display them in the output rather than having them as sort keys. This patch just adds a few more fields to save the weights in a hist entry. It'll be displayed as new output fields in the later patch. Signed-off-by: Namhyung Kim Cc: Adrian Hunter Cc: Andi Kleen Cc: Athira Rajeev Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Peter Zijlstra Cc: Stephane Eranian Link: https://lore.kernel.org/r/20240411181718.2367948-2-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/hist.c | 12 ++++++++++-- tools/perf/util/hist.h | 3 +++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index fa359180ebf8..9d43f8ae412d 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -308,6 +308,9 @@ static void he_stat__add_stat(struct he_stat *dest, struct he_stat *src) dest->period_us += src->period_us; dest->period_guest_sys += src->period_guest_sys; dest->period_guest_us += src->period_guest_us; + dest->weight1 += src->weight1; + dest->weight2 += src->weight2; + dest->weight3 += src->weight3; dest->nr_events += src->nr_events; } @@ -315,7 +318,9 @@ static void he_stat__decay(struct he_stat *he_stat) { he_stat->period = (he_stat->period * 7) / 8; he_stat->nr_events = (he_stat->nr_events * 7) / 8; - /* XXX need decay for weight too? */ + he_stat->weight1 = (he_stat->weight1 * 7) / 8; + he_stat->weight2 = (he_stat->weight2 * 7) / 8; + he_stat->weight3 = (he_stat->weight3 * 7) / 8; } static void hists__delete_entry(struct hists *hists, struct hist_entry *he); @@ -614,7 +619,7 @@ static struct hist_entry *hists__findnew_entry(struct hists *hists, cmp = hist_entry__cmp(he, entry); if (!cmp) { if (sample_self) { - he_stat__add_period(&he->stat, period); + he_stat__add_stat(&he->stat, &entry->stat); hist_entry__add_callchain_period(he, period); } if (symbol_conf.cumulate_callchain) @@ -731,6 +736,9 @@ __hists__add_entry(struct hists *hists, .stat = { .nr_events = 1, .period = sample->period, + .weight1 = sample->weight, + .weight2 = sample->ins_lat, + .weight3 = sample->p_stage_cyc, }, .parent = sym_parent, .filtered = symbol__parent_filter(sym_parent) | al->filtered, diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 8f072f3749eb..f34f101c36c2 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -163,6 +163,9 @@ struct he_stat { u64 period_us; u64 period_guest_sys; u64 period_guest_us; + u64 weight1; + u64 weight2; + u64 weight3; u32 nr_events; }; -- cgit v1.2.3-59-g8ed1b From 7043dc5286a8c082d449e2257f9f87d7f764e7d4 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Thu, 11 Apr 2024 11:17:18 -0700 Subject: perf report: Add weight[123] output fields Add weight1, weight2 and weight3 fields to -F/--fields and their aliases like 'ins_lat', 'p_stage_cyc' and 'retire_lat'. Note that they are in the sort keys too but the difference is that output fields will sum up the weight values and display the average. In the sort key, users can see the distribution of weight value and I think it's confusing we have local vs. global weight for the same weight. For example, I experiment with mem-loads events to get the weights. On my laptop, it seems only weight1 field is supported. $ perf mem record -- perf test -w noploop Let's look at the noploop function only. It has 7 samples. $ perf script -F event,ip,sym,weight | grep noploop # event weight ip sym cpu/mem-loads,ldlat=30/P: 43 55b3c122bffc noploop cpu/mem-loads,ldlat=30/P: 48 55b3c122bffc noploop cpu/mem-loads,ldlat=30/P: 38 55b3c122bffc noploop <--- same weight cpu/mem-loads,ldlat=30/P: 38 55b3c122bffc noploop <--- same weight cpu/mem-loads,ldlat=30/P: 59 55b3c122bffc noploop cpu/mem-loads,ldlat=30/P: 33 55b3c122bffc noploop cpu/mem-loads,ldlat=30/P: 38 55b3c122bffc noploop <--- same weight When you use the 'weight' sort key, it'd show entries with a separate weight value separately. Also note that the first entry has 3 samples with weight value 38, so they are displayed together and the weight value is the sum of 3 samples (114 = 38 * 3). $ perf report -n -s +weight | grep -e Weight -e noploop # Overhead Samples Command Shared Object Symbol Weight 0.53% 3 perf perf [.] noploop 114 0.18% 1 perf perf [.] noploop 59 0.18% 1 perf perf [.] noploop 48 0.18% 1 perf perf [.] noploop 43 0.18% 1 perf perf [.] noploop 33 If you use 'local_weight' sort key, you can see the actual weight. $ perf report -n -s +local_weight | grep -e Weight -e noploop # Overhead Samples Command Shared Object Symbol Local Weight 0.53% 3 perf perf [.] noploop 38 0.18% 1 perf perf [.] noploop 59 0.18% 1 perf perf [.] noploop 48 0.18% 1 perf perf [.] noploop 43 0.18% 1 perf perf [.] noploop 33 But when you use the -F/--field option instead, you can see the average weight for the while noploop function (as it won't group samples by weight value and use the default 'comm,dso,sym' sort keys). $ perf report -n -F +weight | grep -e Weight -e noploop Warning: --fields weight shows the average value unlike in the --sort key. # Overhead Samples Weight1 Command Shared Object Symbol 1.23% 7 42.4 perf perf [.] noploop The weight1 field shows the average value: (38 * 3 + 59 + 48 + 43 + 33) / 7 = 42.4 Also it'd show the warning that 'weight' field has the average value. Using 'weight1' can remove the warning. Signed-off-by: Namhyung Kim Cc: Adrian Hunter Cc: Andi Kleen Cc: Athira Rajeev Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Peter Zijlstra Cc: Stephane Eranian Link: https://lore.kernel.org/r/20240411181718.2367948-3-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-report.txt | 9 +++- tools/perf/ui/hist.c | 92 +++++++++++++++++++++++++------- tools/perf/util/hist.h | 15 +++++- tools/perf/util/sort.c | 28 ++++++---- tools/perf/util/sort.h | 2 +- 5 files changed, 115 insertions(+), 31 deletions(-) diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt index d8b863e01fe0..d2b1593ef700 100644 --- a/tools/perf/Documentation/perf-report.txt +++ b/tools/perf/Documentation/perf-report.txt @@ -121,6 +121,9 @@ OPTIONS - type: Data type of sample memory access. - typeoff: Offset in the data type of sample memory access. - symoff: Offset in the symbol. + - weight1: Average value of event specific weight (1st field of weight_struct). + - weight2: Average value of event specific weight (2nd field of weight_struct). + - weight3: Average value of event specific weight (3rd field of weight_struct). By default, comm, dso and symbol keys are used. (i.e. --sort comm,dso,symbol) @@ -198,7 +201,11 @@ OPTIONS --fields=:: Specify output field - multiple keys can be specified in CSV format. Following fields are available: - overhead, overhead_sys, overhead_us, overhead_children, sample and period. + overhead, overhead_sys, overhead_us, overhead_children, sample, period, + weight1, weight2, weight3, ins_lat, p_stage_cyc and retire_lat. The + last 3 names are alias for the corresponding weights. When the weight + fields are used, they will show the average value of the weight. + Also it can contain any sort key(s). By default, every sort keys not specified in -F will be appended diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c index 2bf959d08354..685ba2a54fd8 100644 --- a/tools/perf/ui/hist.c +++ b/tools/perf/ui/hist.c @@ -25,7 +25,7 @@ static int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he, hpp_field_fn get_field, const char *fmt, int len, - hpp_snprint_fn print_fn, bool fmt_percent) + hpp_snprint_fn print_fn, enum perf_hpp_fmt_type fmtype) { int ret; struct hists *hists = he->hists; @@ -33,7 +33,7 @@ static int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he, char *buf = hpp->buf; size_t size = hpp->size; - if (fmt_percent) { + if (fmtype == PERF_HPP_FMT_TYPE__PERCENT) { double percent = 0.0; u64 total = hists__total_period(hists); @@ -41,8 +41,16 @@ static int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he, percent = 100.0 * get_field(he) / total; ret = hpp__call_print_fn(hpp, print_fn, fmt, len, percent); - } else + } else if (fmtype == PERF_HPP_FMT_TYPE__AVERAGE) { + double average = 0; + + if (he->stat.nr_events) + average = 1.0 * get_field(he) / he->stat.nr_events; + + ret = hpp__call_print_fn(hpp, print_fn, fmt, len, average); + } else { ret = hpp__call_print_fn(hpp, print_fn, fmt, len, get_field(he)); + } if (evsel__is_group_event(evsel)) { int prev_idx, idx_delta; @@ -54,6 +62,7 @@ static int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he, list_for_each_entry(pair, &he->pairs.head, pairs.node) { u64 period = get_field(pair); u64 total = hists__total_period(pair->hists); + int nr_samples = pair->stat.nr_events; if (!total) continue; @@ -66,7 +75,7 @@ static int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he, * zero-fill group members in the middle which * have no sample */ - if (fmt_percent) { + if (fmtype != PERF_HPP_FMT_TYPE__RAW) { ret += hpp__call_print_fn(hpp, print_fn, fmt, len, 0.0); } else { @@ -75,9 +84,14 @@ static int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he, } } - if (fmt_percent) { + if (fmtype == PERF_HPP_FMT_TYPE__PERCENT) { ret += hpp__call_print_fn(hpp, print_fn, fmt, len, 100.0 * period / total); + } else if (fmtype == PERF_HPP_FMT_TYPE__AVERAGE) { + double avg = nr_samples ? (period / nr_samples) : 0; + + ret += hpp__call_print_fn(hpp, print_fn, fmt, + len, avg); } else { ret += hpp__call_print_fn(hpp, print_fn, fmt, len, period); @@ -92,7 +106,7 @@ static int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he, /* * zero-fill group members at last which have no sample */ - if (fmt_percent) { + if (fmtype != PERF_HPP_FMT_TYPE__RAW) { ret += hpp__call_print_fn(hpp, print_fn, fmt, len, 0.0); } else { @@ -114,33 +128,35 @@ static int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he, int hpp__fmt(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, struct hist_entry *he, hpp_field_fn get_field, - const char *fmtstr, hpp_snprint_fn print_fn, bool fmt_percent) + const char *fmtstr, hpp_snprint_fn print_fn, + enum perf_hpp_fmt_type fmtype) { int len = fmt->user_len ?: fmt->len; if (symbol_conf.field_sep) { return __hpp__fmt(hpp, he, get_field, fmtstr, 1, - print_fn, fmt_percent); + print_fn, fmtype); } - if (fmt_percent) + if (fmtype == PERF_HPP_FMT_TYPE__PERCENT) len -= 2; /* 2 for a space and a % sign */ else len -= 1; - return __hpp__fmt(hpp, he, get_field, fmtstr, len, print_fn, fmt_percent); + return __hpp__fmt(hpp, he, get_field, fmtstr, len, print_fn, fmtype); } int hpp__fmt_acc(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, struct hist_entry *he, hpp_field_fn get_field, - const char *fmtstr, hpp_snprint_fn print_fn, bool fmt_percent) + const char *fmtstr, hpp_snprint_fn print_fn, + enum perf_hpp_fmt_type fmtype) { if (!symbol_conf.cumulate_callchain) { int len = fmt->user_len ?: fmt->len; return snprintf(hpp->buf, hpp->size, " %*s", len - 1, "N/A"); } - return hpp__fmt(fmt, hpp, he, get_field, fmtstr, print_fn, fmt_percent); + return hpp__fmt(fmt, hpp, he, get_field, fmtstr, print_fn, fmtype); } static int field_cmp(u64 field_a, u64 field_b) @@ -350,7 +366,7 @@ static int hpp__color_##_type(struct perf_hpp_fmt *fmt, \ struct perf_hpp *hpp, struct hist_entry *he) \ { \ return hpp__fmt(fmt, hpp, he, he_get_##_field, " %*.2f%%", \ - hpp_color_scnprintf, true); \ + hpp_color_scnprintf, PERF_HPP_FMT_TYPE__PERCENT); \ } #define __HPP_ENTRY_PERCENT_FN(_type, _field) \ @@ -358,7 +374,7 @@ static int hpp__entry_##_type(struct perf_hpp_fmt *fmt, \ struct perf_hpp *hpp, struct hist_entry *he) \ { \ return hpp__fmt(fmt, hpp, he, he_get_##_field, " %*.2f%%", \ - hpp_entry_scnprintf, true); \ + hpp_entry_scnprintf, PERF_HPP_FMT_TYPE__PERCENT); \ } #define __HPP_SORT_FN(_type, _field) \ @@ -378,7 +394,7 @@ static int hpp__color_##_type(struct perf_hpp_fmt *fmt, \ struct perf_hpp *hpp, struct hist_entry *he) \ { \ return hpp__fmt_acc(fmt, hpp, he, he_get_acc_##_field, " %*.2f%%", \ - hpp_color_scnprintf, true); \ + hpp_color_scnprintf, PERF_HPP_FMT_TYPE__PERCENT); \ } #define __HPP_ENTRY_ACC_PERCENT_FN(_type, _field) \ @@ -386,7 +402,7 @@ static int hpp__entry_##_type(struct perf_hpp_fmt *fmt, \ struct perf_hpp *hpp, struct hist_entry *he) \ { \ return hpp__fmt_acc(fmt, hpp, he, he_get_acc_##_field, " %*.2f%%", \ - hpp_entry_scnprintf, true); \ + hpp_entry_scnprintf, PERF_HPP_FMT_TYPE__PERCENT); \ } #define __HPP_SORT_ACC_FN(_type, _field) \ @@ -406,7 +422,7 @@ static int hpp__entry_##_type(struct perf_hpp_fmt *fmt, \ struct perf_hpp *hpp, struct hist_entry *he) \ { \ return hpp__fmt(fmt, hpp, he, he_get_raw_##_field, " %*"PRIu64, \ - hpp_entry_scnprintf, false); \ + hpp_entry_scnprintf, PERF_HPP_FMT_TYPE__RAW); \ } #define __HPP_SORT_RAW_FN(_type, _field) \ @@ -416,6 +432,26 @@ static int64_t hpp__sort_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \ return __hpp__sort(a, b, he_get_raw_##_field); \ } +#define __HPP_ENTRY_AVERAGE_FN(_type, _field) \ +static u64 he_get_##_field(struct hist_entry *he) \ +{ \ + return he->stat._field; \ +} \ + \ +static int hpp__entry_##_type(struct perf_hpp_fmt *fmt, \ + struct perf_hpp *hpp, struct hist_entry *he) \ +{ \ + return hpp__fmt(fmt, hpp, he, he_get_##_field, " %*.1f", \ + hpp_entry_scnprintf, PERF_HPP_FMT_TYPE__AVERAGE); \ +} + +#define __HPP_SORT_AVERAGE_FN(_type, _field) \ +static int64_t hpp__sort_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \ + struct hist_entry *a, struct hist_entry *b) \ +{ \ + return __hpp__sort(a, b, he_get_##_field); \ +} + #define HPP_PERCENT_FNS(_type, _field) \ __HPP_COLOR_PERCENT_FN(_type, _field) \ @@ -431,6 +467,10 @@ __HPP_SORT_ACC_FN(_type, _field) __HPP_ENTRY_RAW_FN(_type, _field) \ __HPP_SORT_RAW_FN(_type, _field) +#define HPP_AVERAGE_FNS(_type, _field) \ +__HPP_ENTRY_AVERAGE_FN(_type, _field) \ +__HPP_SORT_AVERAGE_FN(_type, _field) + HPP_PERCENT_FNS(overhead, period) HPP_PERCENT_FNS(overhead_sys, period_sys) HPP_PERCENT_FNS(overhead_us, period_us) @@ -441,6 +481,10 @@ HPP_PERCENT_ACC_FNS(overhead_acc, period) HPP_RAW_FNS(samples, nr_events) HPP_RAW_FNS(period, period) +HPP_AVERAGE_FNS(weight1, weight1) +HPP_AVERAGE_FNS(weight2, weight2) +HPP_AVERAGE_FNS(weight3, weight3) + static int64_t hpp__nop_cmp(struct perf_hpp_fmt *fmt __maybe_unused, struct hist_entry *a __maybe_unused, struct hist_entry *b __maybe_unused) @@ -510,7 +554,10 @@ struct perf_hpp_fmt perf_hpp__format[] = { HPP__COLOR_PRINT_FNS("guest usr", overhead_guest_us, OVERHEAD_GUEST_US), HPP__COLOR_ACC_PRINT_FNS("Children", overhead_acc, OVERHEAD_ACC), HPP__PRINT_FNS("Samples", samples, SAMPLES), - HPP__PRINT_FNS("Period", period, PERIOD) + HPP__PRINT_FNS("Period", period, PERIOD), + HPP__PRINT_FNS("Weight1", weight1, WEIGHT1), + HPP__PRINT_FNS("Weight2", weight2, WEIGHT2), + HPP__PRINT_FNS("Weight3", weight3, WEIGHT3), }; struct perf_hpp_list perf_hpp_list = { @@ -526,6 +573,7 @@ struct perf_hpp_list perf_hpp_list = { #undef HPP_PERCENT_FNS #undef HPP_PERCENT_ACC_FNS #undef HPP_RAW_FNS +#undef HPP_AVERAGE_FNS #undef __HPP_HEADER_FN #undef __HPP_WIDTH_FN @@ -534,9 +582,11 @@ struct perf_hpp_list perf_hpp_list = { #undef __HPP_COLOR_ACC_PERCENT_FN #undef __HPP_ENTRY_ACC_PERCENT_FN #undef __HPP_ENTRY_RAW_FN +#undef __HPP_ENTRY_AVERAGE_FN #undef __HPP_SORT_FN #undef __HPP_SORT_ACC_FN #undef __HPP_SORT_RAW_FN +#undef __HPP_SORT_AVERAGE_FN static void fmt_free(struct perf_hpp_fmt *fmt) { @@ -785,6 +835,12 @@ void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists) fmt->len = 12; break; + case PERF_HPP__WEIGHT1: + case PERF_HPP__WEIGHT2: + case PERF_HPP__WEIGHT3: + fmt->len = 8; + break; + default: break; } diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index f34f101c36c2..5260822b9773 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -550,6 +550,9 @@ enum { PERF_HPP__OVERHEAD_ACC, PERF_HPP__SAMPLES, PERF_HPP__PERIOD, + PERF_HPP__WEIGHT1, + PERF_HPP__WEIGHT2, + PERF_HPP__WEIGHT3, PERF_HPP__MAX_INDEX }; @@ -596,16 +599,24 @@ void perf_hpp__reset_sort_width(struct perf_hpp_fmt *fmt, struct hists *hists); void perf_hpp__set_user_width(const char *width_list_str); void hists__reset_column_width(struct hists *hists); +enum perf_hpp_fmt_type { + PERF_HPP_FMT_TYPE__RAW, + PERF_HPP_FMT_TYPE__PERCENT, + PERF_HPP_FMT_TYPE__AVERAGE, +}; + typedef u64 (*hpp_field_fn)(struct hist_entry *he); typedef int (*hpp_callback_fn)(struct perf_hpp *hpp, bool front); typedef int (*hpp_snprint_fn)(struct perf_hpp *hpp, const char *fmt, ...); int hpp__fmt(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, struct hist_entry *he, hpp_field_fn get_field, - const char *fmtstr, hpp_snprint_fn print_fn, bool fmt_percent); + const char *fmtstr, hpp_snprint_fn print_fn, + enum perf_hpp_fmt_type fmtype); int hpp__fmt_acc(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, struct hist_entry *he, hpp_field_fn get_field, - const char *fmtstr, hpp_snprint_fn print_fn, bool fmt_percent); + const char *fmtstr, hpp_snprint_fn print_fn, + enum perf_hpp_fmt_type fmtype); static inline void advance_hpp(struct perf_hpp *hpp, int inc) { diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index 92a1bd695e8a..add8601c57fd 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c @@ -2441,6 +2441,13 @@ static struct hpp_dimension hpp_sort_dimensions[] = { DIM(PERF_HPP__OVERHEAD_ACC, "overhead_children"), DIM(PERF_HPP__SAMPLES, "sample"), DIM(PERF_HPP__PERIOD, "period"), + DIM(PERF_HPP__WEIGHT1, "weight1"), + DIM(PERF_HPP__WEIGHT2, "weight2"), + DIM(PERF_HPP__WEIGHT3, "weight3"), + /* aliases for weight_struct */ + DIM(PERF_HPP__WEIGHT2, "ins_lat"), + DIM(PERF_HPP__WEIGHT3, "retire_lat"), + DIM(PERF_HPP__WEIGHT3, "p_stage_cyc"), }; #undef DIM @@ -3743,26 +3750,29 @@ void sort__setup_elide(FILE *output) } } -int output_field_add(struct perf_hpp_list *list, char *tok) +int output_field_add(struct perf_hpp_list *list, const char *tok) { unsigned int i; - for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) { - struct sort_dimension *sd = &common_sort_dimensions[i]; + for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) { + struct hpp_dimension *hd = &hpp_sort_dimensions[i]; - if (!sd->name || strncasecmp(tok, sd->name, strlen(tok))) + if (strncasecmp(tok, hd->name, strlen(tok))) continue; - return __sort_dimension__add_output(list, sd); + if (!strcasecmp(tok, "weight")) + ui__warning("--fields weight shows the average value unlike in the --sort key.\n"); + + return __hpp_dimension__add_output(list, hd); } - for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) { - struct hpp_dimension *hd = &hpp_sort_dimensions[i]; + for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) { + struct sort_dimension *sd = &common_sort_dimensions[i]; - if (strncasecmp(tok, hd->name, strlen(tok))) + if (!sd->name || strncasecmp(tok, sd->name, strlen(tok))) continue; - return __hpp_dimension__add_output(list, hd); + return __sort_dimension__add_output(list, sd); } for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) { diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index 690892a92cf3..0bd0ee3ae76b 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h @@ -141,7 +141,7 @@ void reset_dimensions(void); int sort_dimension__add(struct perf_hpp_list *list, const char *tok, struct evlist *evlist, int level); -int output_field_add(struct perf_hpp_list *list, char *tok); +int output_field_add(struct perf_hpp_list *list, const char *tok); int64_t sort__iaddr_cmp(struct hist_entry *left, struct hist_entry *right); int64_t -- cgit v1.2.3-59-g8ed1b From 6b718ac6874c2233b8dec369a8a377d6c5b638e6 Mon Sep 17 00:00:00 2001 From: Chaitanya S Prakash Date: Mon, 8 Apr 2024 11:52:28 +0530 Subject: perf tools: Enable configs required for test_uprobe_from_different_cu.sh Test "perf probe of function from different CU" fails due to certain configs not being enabled. Building the kernel with CONFIG_KPROBE_EVENTS=y and CONFIG_UPROBE_EVENTS=y fixes the issue. As CONFIG_KPROBE_EVENTS is dependent on CONFIG_KPROBES, enable it as well. Some platforms enable these configs as a part of their defconfig, so this change is only required for the ones that don't do so. Reviewed-by: Masami Hiramatsu Signed-off-by: Chaitanya S Prakash Cc: Anshuman Khandual Cc: James Clark Link: https://lore.kernel.org/r/20240408062230.1949882-1-ChaitanyaS.Prakash@arm.com Link: https://lore.kernel.org/r/20240408062230.1949882-7-ChaitanyaS.Prakash@arm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/config-fragments/config | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/perf/tests/config-fragments/config b/tools/perf/tests/config-fragments/config index c340b3195fca..4fca12851016 100644 --- a/tools/perf/tests/config-fragments/config +++ b/tools/perf/tests/config-fragments/config @@ -9,3 +9,6 @@ CONFIG_GENERIC_TRACER=y CONFIG_FTRACE=y CONFIG_FTRACE_SYSCALLS=y CONFIG_BRANCH_PROFILE_NONE=y +CONFIG_KPROBES=y +CONFIG_KPROBE_EVENTS=y +CONFIG_UPROBE_EVENTS=y -- cgit v1.2.3-59-g8ed1b From a29e5290e3566ae4db4e6fe5f31caf23118c82b6 Mon Sep 17 00:00:00 2001 From: Kuppuswamy Sathyanarayanan Date: Tue, 16 Apr 2024 05:50:35 +0000 Subject: PCI/AER: Update aer-inject tool source URL The aer-inject tool is no longer maintained in the original repository and is missing a fix related to the musl library. So, with the author's (Huang Ying) consent, it has been moved to a new repository [1]. Update all references to the repository link. Link: https://github.com/intel/aer-inject.git [1] Link: https://lore.kernel.org/r/20240416055035.200085-1-sathyanarayanan.kuppuswamy@linux.intel.com Signed-off-by: Kuppuswamy Sathyanarayanan Signed-off-by: Bjorn Helgaas Cc: Huang Ying --- Documentation/PCI/pcieaer-howto.rst | 2 +- drivers/pci/pcie/Kconfig | 2 +- drivers/pci/pcie/aer_inject.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/PCI/pcieaer-howto.rst b/Documentation/PCI/pcieaer-howto.rst index e00d63971695..f013f3b27c82 100644 --- a/Documentation/PCI/pcieaer-howto.rst +++ b/Documentation/PCI/pcieaer-howto.rst @@ -241,7 +241,7 @@ After reboot with new kernel or insert the module, a device file named Then, you need a user space tool named aer-inject, which can be gotten from: - https://git.kernel.org/cgit/linux/kernel/git/gong.chen/aer-inject.git/ + https://github.com/intel/aer-inject.git More information about aer-inject can be found in the document in its source code. diff --git a/drivers/pci/pcie/Kconfig b/drivers/pci/pcie/Kconfig index 8999fcebde6a..17919b99fa66 100644 --- a/drivers/pci/pcie/Kconfig +++ b/drivers/pci/pcie/Kconfig @@ -47,7 +47,7 @@ config PCIEAER_INJECT error injection can fake almost all kinds of errors with the help of a user space helper tool aer-inject, which can be gotten from: - https://git.kernel.org/cgit/linux/kernel/git/gong.chen/aer-inject.git/ + https://github.com/intel/aer-inject.git config PCIEAER_CXL bool "PCI Express CXL RAS support" diff --git a/drivers/pci/pcie/aer_inject.c b/drivers/pci/pcie/aer_inject.c index 2dab275d252f..f81b2303bf6a 100644 --- a/drivers/pci/pcie/aer_inject.c +++ b/drivers/pci/pcie/aer_inject.c @@ -6,7 +6,7 @@ * trigger various real hardware errors. Software based error * injection can fake almost all kinds of errors with the help of a * user space helper tool aer-inject, which can be gotten from: - * https://git.kernel.org/cgit/linux/kernel/git/gong.chen/aer-inject.git/ + * https://github.com/intel/aer-inject.git * * Copyright 2009 Intel Corporation. * Huang Ying -- cgit v1.2.3-59-g8ed1b From e30556bf682d36a88cc5aef98d1123ca71adb245 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Sat, 13 Apr 2024 23:01:17 +0200 Subject: PCI: Constify pcibus_class Constify pcibus_class. All users take a const struct class * argument. Link: https://lore.kernel.org/r/5e01f46f-266f-4fb3-be8a-8cb9e566cd75@gmail.com Signed-off-by: Heiner Kallweit Signed-off-by: Bjorn Helgaas --- drivers/pci/probe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 1325fbae2f28..4ec903291f36 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -95,7 +95,7 @@ static void release_pcibus_dev(struct device *dev) kfree(pci_bus); } -static struct class pcibus_class = { +static const struct class pcibus_class = { .name = "pci_bus", .dev_release = &release_pcibus_dev, .dev_groups = pcibus_groups, -- cgit v1.2.3-59-g8ed1b From b52e28eca7da47fa389605a8eda1952a9fa3c69f Mon Sep 17 00:00:00 2001 From: Frank Li Date: Thu, 11 Apr 2024 16:39:35 -0400 Subject: dmaengine: fsl-edma: fix miss mutex unlock at an error return path Use cleanup to manage mutex. Let compiler to do scope guard automatically. Fixes: 6aa60f79e679 ("dmaengine: fsl-edma: add safety check for 'srcid'") Reported-by: kernel test robot Closes: https://lore.kernel.org/r/202404110915.riwV3ZAC-lkp@intel.com/ Signed-off-by: Frank Li Link: https://lore.kernel.org/r/20240411203935.3137158-1-Frank.Li@nxp.com Signed-off-by: Vinod Koul --- drivers/dma/fsl-edma-common.c | 1 + drivers/dma/fsl-edma-main.c | 5 ++--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/dma/fsl-edma-common.c b/drivers/dma/fsl-edma-common.c index f9144b015439..73628eac8aad 100644 --- a/drivers/dma/fsl-edma-common.c +++ b/drivers/dma/fsl-edma-common.c @@ -3,6 +3,7 @@ // Copyright (c) 2013-2014 Freescale Semiconductor, Inc // Copyright (c) 2017 Sysam, Angelo Dureghello +#include #include #include #include diff --git a/drivers/dma/fsl-edma-main.c b/drivers/dma/fsl-edma-main.c index 755a3dc3b0a7..de03148aed0b 100644 --- a/drivers/dma/fsl-edma-main.c +++ b/drivers/dma/fsl-edma-main.c @@ -105,7 +105,8 @@ static struct dma_chan *fsl_edma_xlate(struct of_phandle_args *dma_spec, if (dma_spec->args_count != 2) return NULL; - mutex_lock(&fsl_edma->fsl_edma_mutex); + guard(mutex)(&fsl_edma->fsl_edma_mutex); + list_for_each_entry_safe(chan, _chan, &fsl_edma->dma_dev.channels, device_node) { if (chan->client_count) continue; @@ -124,12 +125,10 @@ static struct dma_chan *fsl_edma_xlate(struct of_phandle_args *dma_spec, fsl_edma_chan_mux(fsl_chan, fsl_chan->srcid, true); - mutex_unlock(&fsl_edma->fsl_edma_mutex); return chan; } } } - mutex_unlock(&fsl_edma->fsl_edma_mutex); return NULL; } -- cgit v1.2.3-59-g8ed1b From bd2f66bc0ba08a68c7edcd3992886d1773c18cf2 Mon Sep 17 00:00:00 2001 From: Frank Li Date: Tue, 9 Apr 2024 12:36:30 -0400 Subject: dmaengine: fsl-dpaa2-qdma: Update DPDMAI interfaces to version 3 Update the DPDMAI interfaces to support MC firmware up to 10.1x.x, which major change is to add dpaa domain id support. User space MC controller tool can create difference dpaa domain for difference virtual environment. DMA queues can map to difference service priorities. The MC command was basic compatible original one. The new command use previous reserved field. - Add queue number for dpdmai_get_tx(rx)_queue(). - Unified rx(tx)_queue_attr. - Update pad/reserved field of struct dpdmai_rsp_get_attributes and struct dpdmai_cmd_queue for new API. - Update command DPDMAI_SET(GET)_RX_QUEUE and DPDMAI_CMDID_GET_TX_QUEUE Signed-off-by: Frank Li Link: https://lore.kernel.org/r/20240409163630.1996052-1-Frank.Li@nxp.com Signed-off-by: Vinod Koul --- drivers/dma/fsl-dpaa2-qdma/dpaa2-qdma.c | 14 +++++----- drivers/dma/fsl-dpaa2-qdma/dpaa2-qdma.h | 5 ++-- drivers/dma/fsl-dpaa2-qdma/dpdmai.c | 48 +++++++++++++++++++++++---------- drivers/dma/fsl-dpaa2-qdma/dpdmai.h | 35 +++++++++++++++--------- 4 files changed, 67 insertions(+), 35 deletions(-) diff --git a/drivers/dma/fsl-dpaa2-qdma/dpaa2-qdma.c b/drivers/dma/fsl-dpaa2-qdma/dpaa2-qdma.c index 5a8061a307cd..36384d019263 100644 --- a/drivers/dma/fsl-dpaa2-qdma/dpaa2-qdma.c +++ b/drivers/dma/fsl-dpaa2-qdma/dpaa2-qdma.c @@ -362,7 +362,7 @@ static int __cold dpaa2_qdma_setup(struct fsl_mc_device *ls_dev) for (i = 0; i < priv->num_pairs; i++) { err = dpdmai_get_rx_queue(priv->mc_io, 0, ls_dev->mc_handle, - i, &priv->rx_queue_attr[i]); + i, 0, &priv->rx_queue_attr[i]); if (err) { dev_err(dev, "dpdmai_get_rx_queue() failed\n"); goto exit; @@ -370,13 +370,13 @@ static int __cold dpaa2_qdma_setup(struct fsl_mc_device *ls_dev) ppriv->rsp_fqid = priv->rx_queue_attr[i].fqid; err = dpdmai_get_tx_queue(priv->mc_io, 0, ls_dev->mc_handle, - i, &priv->tx_fqid[i]); + i, 0, &priv->tx_queue_attr[i]); if (err) { dev_err(dev, "dpdmai_get_tx_queue() failed\n"); goto exit; } - ppriv->req_fqid = priv->tx_fqid[i]; - ppriv->prio = i; + ppriv->req_fqid = priv->tx_queue_attr[i].fqid; + ppriv->prio = DPAA2_QDMA_DEFAULT_PRIORITY; ppriv->priv = priv; ppriv++; } @@ -542,7 +542,7 @@ static int __cold dpaa2_dpdmai_bind(struct dpaa2_qdma_priv *priv) rx_queue_cfg.dest_cfg.dest_id = ppriv->nctx.dpio_id; rx_queue_cfg.dest_cfg.priority = ppriv->prio; err = dpdmai_set_rx_queue(priv->mc_io, 0, ls_dev->mc_handle, - rx_queue_cfg.dest_cfg.priority, + rx_queue_cfg.dest_cfg.priority, 0, &rx_queue_cfg); if (err) { dev_err(dev, "dpdmai_set_rx_queue() failed\n"); @@ -642,7 +642,7 @@ static int dpaa2_dpdmai_init_channels(struct dpaa2_qdma_engine *dpaa2_qdma) for (i = 0; i < dpaa2_qdma->n_chans; i++) { dpaa2_chan = &dpaa2_qdma->chans[i]; dpaa2_chan->qdma = dpaa2_qdma; - dpaa2_chan->fqid = priv->tx_fqid[i % num]; + dpaa2_chan->fqid = priv->tx_queue_attr[i % num].fqid; dpaa2_chan->vchan.desc_free = dpaa2_qdma_free_desc; vchan_init(&dpaa2_chan->vchan, &dpaa2_qdma->dma_dev); spin_lock_init(&dpaa2_chan->queue_lock); @@ -802,7 +802,7 @@ static void dpaa2_qdma_shutdown(struct fsl_mc_device *ls_dev) dpdmai_disable(priv->mc_io, 0, ls_dev->mc_handle); dpaa2_dpdmai_dpio_unbind(priv); dpdmai_close(priv->mc_io, 0, ls_dev->mc_handle); - dpdmai_destroy(priv->mc_io, 0, ls_dev->mc_handle); + dpdmai_destroy(priv->mc_io, 0, priv->dpqdma_id, ls_dev->mc_handle); } static const struct fsl_mc_device_id dpaa2_qdma_id_table[] = { diff --git a/drivers/dma/fsl-dpaa2-qdma/dpaa2-qdma.h b/drivers/dma/fsl-dpaa2-qdma/dpaa2-qdma.h index 03e2f4e0baca..2c80077cb7c0 100644 --- a/drivers/dma/fsl-dpaa2-qdma/dpaa2-qdma.h +++ b/drivers/dma/fsl-dpaa2-qdma/dpaa2-qdma.h @@ -6,6 +6,7 @@ #define DPAA2_QDMA_STORE_SIZE 16 #define NUM_CH 8 +#define DPAA2_QDMA_DEFAULT_PRIORITY 0 struct dpaa2_qdma_sd_d { u32 rsv:32; @@ -122,8 +123,8 @@ struct dpaa2_qdma_priv { struct dpaa2_qdma_engine *dpaa2_qdma; struct dpaa2_qdma_priv_per_prio *ppriv; - struct dpdmai_rx_queue_attr rx_queue_attr[DPDMAI_PRIO_NUM]; - u32 tx_fqid[DPDMAI_PRIO_NUM]; + struct dpdmai_rx_queue_attr rx_queue_attr[DPDMAI_MAX_QUEUE_NUM]; + struct dpdmai_tx_queue_attr tx_queue_attr[DPDMAI_MAX_QUEUE_NUM]; }; struct dpaa2_qdma_priv_per_prio { diff --git a/drivers/dma/fsl-dpaa2-qdma/dpdmai.c b/drivers/dma/fsl-dpaa2-qdma/dpdmai.c index 610f6231835a..a824450fe19c 100644 --- a/drivers/dma/fsl-dpaa2-qdma/dpdmai.c +++ b/drivers/dma/fsl-dpaa2-qdma/dpdmai.c @@ -1,32 +1,39 @@ // SPDX-License-Identifier: GPL-2.0 // Copyright 2019 NXP +#include #include #include #include #include #include "dpdmai.h" +#define DEST_TYPE_MASK 0xF + struct dpdmai_rsp_get_attributes { __le32 id; u8 num_of_priorities; - u8 pad0[3]; + u8 num_of_queues; + u8 pad0[2]; __le16 major; __le16 minor; }; struct dpdmai_cmd_queue { __le32 dest_id; - u8 priority; - u8 queue; + u8 dest_priority; + union { + u8 queue; + u8 pri; + }; u8 dest_type; - u8 pad; + u8 queue_idx; __le64 user_ctx; union { __le32 options; __le32 fqid; }; -}; +} __packed; struct dpdmai_rsp_get_tx_queue { __le64 pad; @@ -37,6 +44,10 @@ struct dpdmai_cmd_open { __le32 dpdmai_id; } __packed; +struct dpdmai_cmd_destroy { + __le32 dpdmai_id; +} __packed; + static inline u64 mc_enc(int lsoffset, int width, u64 val) { return (val & MAKE_UMASK64(width)) << lsoffset; @@ -113,18 +124,23 @@ EXPORT_SYMBOL_GPL(dpdmai_close); * dpdmai_destroy() - Destroy the DPDMAI object and release all its resources. * @mc_io: Pointer to MC portal's I/O object * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @dpdmai_id: The object id; it must be a valid id within the container that created this object; * @token: Token of DPDMAI object * * Return: '0' on Success; error code otherwise. */ -int dpdmai_destroy(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token) +int dpdmai_destroy(struct fsl_mc_io *mc_io, u32 cmd_flags, u32 dpdmai_id, u16 token) { + struct dpdmai_cmd_destroy *cmd_params; struct fsl_mc_command cmd = { 0 }; /* prepare command */ cmd.header = mc_encode_cmd_header(DPDMAI_CMDID_DESTROY, cmd_flags, token); + cmd_params = (struct dpdmai_cmd_destroy *)&cmd.params; + cmd_params->dpdmai_id = cpu_to_le32(dpdmai_id); + /* send command to mc*/ return mc_send_command(mc_io, &cmd); } @@ -224,6 +240,7 @@ int dpdmai_get_attributes(struct fsl_mc_io *mc_io, u32 cmd_flags, attr->version.major = le16_to_cpu(rsp_params->major); attr->version.minor = le16_to_cpu(rsp_params->minor); attr->num_of_priorities = rsp_params->num_of_priorities; + attr->num_of_queues = rsp_params->num_of_queues; return 0; } @@ -240,7 +257,7 @@ EXPORT_SYMBOL_GPL(dpdmai_get_attributes); * * Return: '0' on Success; Error code otherwise. */ -int dpdmai_set_rx_queue(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, +int dpdmai_set_rx_queue(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, u8 queue_idx, u8 priority, const struct dpdmai_rx_queue_cfg *cfg) { struct dpdmai_cmd_queue *cmd_params; @@ -252,11 +269,12 @@ int dpdmai_set_rx_queue(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, cmd_params = (struct dpdmai_cmd_queue *)cmd.params; cmd_params->dest_id = cpu_to_le32(cfg->dest_cfg.dest_id); - cmd_params->priority = cfg->dest_cfg.priority; - cmd_params->queue = priority; + cmd_params->dest_priority = cfg->dest_cfg.priority; + cmd_params->pri = priority; cmd_params->dest_type = cfg->dest_cfg.dest_type; cmd_params->user_ctx = cpu_to_le64(cfg->user_ctx); cmd_params->options = cpu_to_le32(cfg->options); + cmd_params->queue_idx = queue_idx; /* send command to mc*/ return mc_send_command(mc_io, &cmd); @@ -274,7 +292,7 @@ EXPORT_SYMBOL_GPL(dpdmai_set_rx_queue); * * Return: '0' on Success; Error code otherwise. */ -int dpdmai_get_rx_queue(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, +int dpdmai_get_rx_queue(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, u8 queue_idx, u8 priority, struct dpdmai_rx_queue_attr *attr) { struct dpdmai_cmd_queue *cmd_params; @@ -287,6 +305,7 @@ int dpdmai_get_rx_queue(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, cmd_params = (struct dpdmai_cmd_queue *)cmd.params; cmd_params->queue = priority; + cmd_params->queue_idx = queue_idx; /* send command to mc*/ err = mc_send_command(mc_io, &cmd); @@ -295,8 +314,8 @@ int dpdmai_get_rx_queue(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, /* retrieve response parameters */ attr->dest_cfg.dest_id = le32_to_cpu(cmd_params->dest_id); - attr->dest_cfg.priority = cmd_params->priority; - attr->dest_cfg.dest_type = cmd_params->dest_type; + attr->dest_cfg.priority = cmd_params->dest_priority; + attr->dest_cfg.dest_type = FIELD_GET(DEST_TYPE_MASK, cmd_params->dest_type); attr->user_ctx = le64_to_cpu(cmd_params->user_ctx); attr->fqid = le32_to_cpu(cmd_params->fqid); @@ -316,7 +335,7 @@ EXPORT_SYMBOL_GPL(dpdmai_get_rx_queue); * Return: '0' on Success; Error code otherwise. */ int dpdmai_get_tx_queue(struct fsl_mc_io *mc_io, u32 cmd_flags, - u16 token, u8 priority, u32 *fqid) + u16 token, u8 queue_idx, u8 priority, struct dpdmai_tx_queue_attr *attr) { struct dpdmai_rsp_get_tx_queue *rsp_params; struct dpdmai_cmd_queue *cmd_params; @@ -329,6 +348,7 @@ int dpdmai_get_tx_queue(struct fsl_mc_io *mc_io, u32 cmd_flags, cmd_params = (struct dpdmai_cmd_queue *)cmd.params; cmd_params->queue = priority; + cmd_params->queue_idx = queue_idx; /* send command to mc*/ err = mc_send_command(mc_io, &cmd); @@ -338,7 +358,7 @@ int dpdmai_get_tx_queue(struct fsl_mc_io *mc_io, u32 cmd_flags, /* retrieve response parameters */ rsp_params = (struct dpdmai_rsp_get_tx_queue *)cmd.params; - *fqid = le32_to_cpu(rsp_params->fqid); + attr->fqid = le32_to_cpu(rsp_params->fqid); return 0; } diff --git a/drivers/dma/fsl-dpaa2-qdma/dpdmai.h b/drivers/dma/fsl-dpaa2-qdma/dpdmai.h index 3f2db582509a..1efca2a30533 100644 --- a/drivers/dma/fsl-dpaa2-qdma/dpdmai.h +++ b/drivers/dma/fsl-dpaa2-qdma/dpdmai.h @@ -5,14 +5,19 @@ #define __FSL_DPDMAI_H /* DPDMAI Version */ -#define DPDMAI_VER_MAJOR 2 -#define DPDMAI_VER_MINOR 2 +#define DPDMAI_VER_MAJOR 3 +#define DPDMAI_VER_MINOR 3 -#define DPDMAI_CMD_BASE_VERSION 0 +#define DPDMAI_CMD_BASE_VERSION 1 #define DPDMAI_CMD_ID_OFFSET 4 -#define DPDMAI_CMDID_FORMAT(x) (((x) << DPDMAI_CMD_ID_OFFSET) | \ - DPDMAI_CMD_BASE_VERSION) +/* + * Maximum number of Tx/Rx queues per DPDMAI object + */ +#define DPDMAI_MAX_QUEUE_NUM 8 + +#define DPDMAI_CMDID_FORMAT_V(x, v) (((x) << DPDMAI_CMD_ID_OFFSET) | (v)) +#define DPDMAI_CMDID_FORMAT(x) DPDMAI_CMDID_FORMAT_V(x, DPDMAI_CMD_BASE_VERSION) /* Command IDs */ #define DPDMAI_CMDID_CLOSE DPDMAI_CMDID_FORMAT(0x800) @@ -26,9 +31,9 @@ #define DPDMAI_CMDID_RESET DPDMAI_CMDID_FORMAT(0x005) #define DPDMAI_CMDID_IS_ENABLED DPDMAI_CMDID_FORMAT(0x006) -#define DPDMAI_CMDID_SET_RX_QUEUE DPDMAI_CMDID_FORMAT(0x1A0) -#define DPDMAI_CMDID_GET_RX_QUEUE DPDMAI_CMDID_FORMAT(0x1A1) -#define DPDMAI_CMDID_GET_TX_QUEUE DPDMAI_CMDID_FORMAT(0x1A2) +#define DPDMAI_CMDID_SET_RX_QUEUE DPDMAI_CMDID_FORMAT_V(0x1A0, 2) +#define DPDMAI_CMDID_GET_RX_QUEUE DPDMAI_CMDID_FORMAT_V(0x1A1, 2) +#define DPDMAI_CMDID_GET_TX_QUEUE DPDMAI_CMDID_FORMAT_V(0x1A2, 2) #define MC_CMD_HDR_TOKEN_O 32 /* Token field offset */ #define MC_CMD_HDR_TOKEN_S 16 /* Token field size */ @@ -64,6 +69,7 @@ * should be configured with 0 */ struct dpdmai_cfg { + u8 num_queues; u8 priorities[DPDMAI_PRIO_NUM]; }; @@ -85,6 +91,7 @@ struct dpdmai_attr { u16 minor; } version; u8 num_of_priorities; + u8 num_of_queues; }; /** @@ -149,20 +156,24 @@ struct dpdmai_rx_queue_attr { u32 fqid; }; +struct dpdmai_tx_queue_attr { + u32 fqid; +}; + int dpdmai_open(struct fsl_mc_io *mc_io, u32 cmd_flags, int dpdmai_id, u16 *token); int dpdmai_close(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token); -int dpdmai_destroy(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token); +int dpdmai_destroy(struct fsl_mc_io *mc_io, u32 cmd_flags, u32 dpdmai_id, u16 token); int dpdmai_enable(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token); int dpdmai_disable(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token); int dpdmai_reset(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token); int dpdmai_get_attributes(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, struct dpdmai_attr *attr); int dpdmai_set_rx_queue(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, - u8 priority, const struct dpdmai_rx_queue_cfg *cfg); + u8 queue_idx, u8 priority, const struct dpdmai_rx_queue_cfg *cfg); int dpdmai_get_rx_queue(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, - u8 priority, struct dpdmai_rx_queue_attr *attr); + u8 queue_idx, u8 priority, struct dpdmai_rx_queue_attr *attr); int dpdmai_get_tx_queue(struct fsl_mc_io *mc_io, u32 cmd_flags, - u16 token, u8 priority, u32 *fqid); + u16 token, u8 queue_idx, u8 priority, struct dpdmai_tx_queue_attr *attr); #endif /* __FSL_DPDMAI_H */ -- cgit v1.2.3-59-g8ed1b From 98f2233a5c20ca567b2db1147278fd110681b9ed Mon Sep 17 00:00:00 2001 From: Erick Archer Date: Sat, 30 Mar 2024 16:23:23 +0100 Subject: dmaengine: pl08x: Use kcalloc() instead of kzalloc() This is an effort to get rid of all multiplications from allocation functions in order to prevent integer overflows [1]. Here the multiplication is obviously safe because the "channels" member can only be 8 or 2. This value is set when the "vendor_data" structs are initialized. static struct vendor_data vendor_pl080 = { [...] .channels = 8, [...] }; static struct vendor_data vendor_nomadik = { [...] .channels = 8, [...] }; static struct vendor_data vendor_pl080s = { [...] .channels = 8, [...] }; static struct vendor_data vendor_pl081 = { [...] .channels = 2, [...] }; However, using kcalloc() is more appropriate [1] and improves readability. This patch has no effect on runtime behavior. Link: https://github.com/KSPP/linux/issues/162 [1] Link: https://www.kernel.org/doc/html/next/process/deprecated.html#open-coded-arithmetic-in-allocator-arguments [1] Reviewed-by: Gustavo A. R. Silva Signed-off-by: Erick Archer Link: https://lore.kernel.org/r/AS8PR02MB72373D9261B3B166048A8E218B392@AS8PR02MB7237.eurprd02.prod.outlook.com Signed-off-by: Vinod Koul --- drivers/dma/amba-pl08x.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index fbf048f432bf..73a5cfb4da8a 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -2855,8 +2855,8 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id) } /* Initialize physical channels */ - pl08x->phy_chans = kzalloc((vd->channels * sizeof(*pl08x->phy_chans)), - GFP_KERNEL); + pl08x->phy_chans = kcalloc(vd->channels, sizeof(*pl08x->phy_chans), + GFP_KERNEL); if (!pl08x->phy_chans) { ret = -ENOMEM; goto out_no_phychans; -- cgit v1.2.3-59-g8ed1b From bbd3e43662d761be1bb7e737d85c87976d39bc5c Mon Sep 17 00:00:00 2001 From: Javier Carrasco Date: Sat, 13 Apr 2024 22:22:18 +0200 Subject: dt-bindings: rtc: pxa-rtc: convert to dtschema Convert existing binding to dtschema to support validation. The missing 'reg' and 'interrupts' properties have been added, taking the 2 supported interrupts into account to fix the example. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Javier Carrasco Link: https://lore.kernel.org/r/20240413-rtc_dtschema-v3-3-eff368bcc471@gmail.com Signed-off-by: Alexandre Belloni --- .../devicetree/bindings/rtc/marvell,pxa-rtc.yaml | 40 ++++++++++++++++++++++ Documentation/devicetree/bindings/rtc/pxa-rtc.txt | 14 -------- 2 files changed, 40 insertions(+), 14 deletions(-) create mode 100644 Documentation/devicetree/bindings/rtc/marvell,pxa-rtc.yaml delete mode 100644 Documentation/devicetree/bindings/rtc/pxa-rtc.txt diff --git a/Documentation/devicetree/bindings/rtc/marvell,pxa-rtc.yaml b/Documentation/devicetree/bindings/rtc/marvell,pxa-rtc.yaml new file mode 100644 index 000000000000..43d68681a1bf --- /dev/null +++ b/Documentation/devicetree/bindings/rtc/marvell,pxa-rtc.yaml @@ -0,0 +1,40 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/rtc/marvell,pxa-rtc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: PXA Real Time Clock + +maintainers: + - Javier Carrasco + +allOf: + - $ref: rtc.yaml# + +properties: + compatible: + const: marvell,pxa-rtc + + reg: + maxItems: 1 + + interrupts: + items: + - description: 1 Hz + - description: Alarm + +required: + - compatible + - reg + - interrupts + +unevaluatedProperties: false + +examples: + - | + rtc@40900000 { + compatible = "marvell,pxa-rtc"; + reg = <0x40900000 0x3c>; + interrupts = <30>, <31>; + }; diff --git a/Documentation/devicetree/bindings/rtc/pxa-rtc.txt b/Documentation/devicetree/bindings/rtc/pxa-rtc.txt deleted file mode 100644 index 8c6672a1b7d7..000000000000 --- a/Documentation/devicetree/bindings/rtc/pxa-rtc.txt +++ /dev/null @@ -1,14 +0,0 @@ -* PXA RTC - -PXA specific RTC driver. - -Required properties: -- compatible : Should be "marvell,pxa-rtc" - -Examples: - -rtc@40900000 { - compatible = "marvell,pxa-rtc"; - reg = <0x40900000 0x3c>; - interrupts = <30 31>; -}; -- cgit v1.2.3-59-g8ed1b From c3a0ee85f6e39988bfd300cbb10f073947eef0ed Mon Sep 17 00:00:00 2001 From: Javier Carrasco Date: Sat, 13 Apr 2024 22:22:19 +0200 Subject: dt-bindings: rtc: stmp3xxx-rtc: convert to dtschema Convert existing binding to dtschema to support validation and add the undocumented compatible 'fsl,imx23-rtc'. Signed-off-by: Javier Carrasco Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240413-rtc_dtschema-v3-4-eff368bcc471@gmail.com Signed-off-by: Alexandre Belloni --- .../devicetree/bindings/rtc/fsl,stmp3xxx-rtc.yaml | 51 ++++++++++++++++++++++ .../devicetree/bindings/rtc/stmp3xxx-rtc.txt | 21 --------- 2 files changed, 51 insertions(+), 21 deletions(-) create mode 100644 Documentation/devicetree/bindings/rtc/fsl,stmp3xxx-rtc.yaml delete mode 100644 Documentation/devicetree/bindings/rtc/stmp3xxx-rtc.txt diff --git a/Documentation/devicetree/bindings/rtc/fsl,stmp3xxx-rtc.yaml b/Documentation/devicetree/bindings/rtc/fsl,stmp3xxx-rtc.yaml new file mode 100644 index 000000000000..534de4196a4f --- /dev/null +++ b/Documentation/devicetree/bindings/rtc/fsl,stmp3xxx-rtc.yaml @@ -0,0 +1,51 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/rtc/fsl,stmp3xxx-rtc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: STMP3xxx/i.MX28 Time Clock Controller + +maintainers: + - Javier Carrasco + +allOf: + - $ref: rtc.yaml# + +properties: + compatible: + oneOf: + - items: + - enum: + - fsl,imx28-rtc + - fsl,imx23-rtc + - const: fsl,stmp3xxx-rtc + - const: fsl,stmp3xxx-rtc + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + stmp,crystal-freq: + description: + Override crystal frequency as determined from fuse bits. + Use <0> for "no crystal". + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [0, 32000, 32768] + +required: + - compatible + - reg + - interrupts + +unevaluatedProperties: false + +examples: + - | + rtc@80056000 { + compatible = "fsl,imx28-rtc", "fsl,stmp3xxx-rtc"; + reg = <0x80056000 2000>; + interrupts = <29>; + }; diff --git a/Documentation/devicetree/bindings/rtc/stmp3xxx-rtc.txt b/Documentation/devicetree/bindings/rtc/stmp3xxx-rtc.txt deleted file mode 100644 index fa6a94226669..000000000000 --- a/Documentation/devicetree/bindings/rtc/stmp3xxx-rtc.txt +++ /dev/null @@ -1,21 +0,0 @@ -* STMP3xxx/i.MX28 Time Clock controller - -Required properties: -- compatible: should be one of the following. - * "fsl,stmp3xxx-rtc" -- reg: physical base address of the controller and length of memory mapped - region. -- interrupts: rtc alarm interrupt - -Optional properties: -- stmp,crystal-freq: override crystal frequency as determined from fuse bits. - Only <32000> and <32768> are possible for the hardware. Use <0> for - "no crystal". - -Example: - -rtc@80056000 { - compatible = "fsl,imx28-rtc", "fsl,stmp3xxx-rtc"; - reg = <0x80056000 2000>; - interrupts = <29>; -}; -- cgit v1.2.3-59-g8ed1b From 1c431b92e21bcbfc374f97d801840c1df47e3d6b Mon Sep 17 00:00:00 2001 From: Javier Carrasco Date: Sat, 13 Apr 2024 22:22:17 +0200 Subject: dt-bindings: rtc: convert trivial devices into dtschema These RTCs meet the requirements for a direct conversion into trivial-rtc: - google,goldfish-rtc - maxim,ds1742 - lpc32xx-rtc - orion-rtc - rtc-aspeed - spear-rtc - via,vt8500-rtc Reviewed-by: Krzysztof Kozlowski Reviewed-by: Andrew Jeffery Signed-off-by: Javier Carrasco Link: https://lore.kernel.org/r/20240413-rtc_dtschema-v3-2-eff368bcc471@gmail.com Signed-off-by: Alexandre Belloni --- .../bindings/rtc/google,goldfish-rtc.txt | 17 ----------------- .../devicetree/bindings/rtc/lpc32xx-rtc.txt | 15 --------------- .../devicetree/bindings/rtc/maxim,ds1742.txt | 12 ------------ .../devicetree/bindings/rtc/orion-rtc.txt | 18 ------------------ .../devicetree/bindings/rtc/rtc-aspeed.txt | 22 ---------------------- .../devicetree/bindings/rtc/spear-rtc.txt | 15 --------------- .../devicetree/bindings/rtc/trivial-rtc.yaml | 18 ++++++++++++++++++ .../devicetree/bindings/rtc/via,vt8500-rtc.txt | 15 --------------- MAINTAINERS | 1 - 9 files changed, 18 insertions(+), 115 deletions(-) delete mode 100644 Documentation/devicetree/bindings/rtc/google,goldfish-rtc.txt delete mode 100644 Documentation/devicetree/bindings/rtc/lpc32xx-rtc.txt delete mode 100644 Documentation/devicetree/bindings/rtc/maxim,ds1742.txt delete mode 100644 Documentation/devicetree/bindings/rtc/orion-rtc.txt delete mode 100644 Documentation/devicetree/bindings/rtc/rtc-aspeed.txt delete mode 100644 Documentation/devicetree/bindings/rtc/spear-rtc.txt delete mode 100644 Documentation/devicetree/bindings/rtc/via,vt8500-rtc.txt diff --git a/Documentation/devicetree/bindings/rtc/google,goldfish-rtc.txt b/Documentation/devicetree/bindings/rtc/google,goldfish-rtc.txt deleted file mode 100644 index 634312dd95ca..000000000000 --- a/Documentation/devicetree/bindings/rtc/google,goldfish-rtc.txt +++ /dev/null @@ -1,17 +0,0 @@ -Android Goldfish RTC - -Android Goldfish RTC device used by Android emulator. - -Required properties: - -- compatible : should contain "google,goldfish-rtc" -- reg : -- interrupts : - -Example: - - goldfish_timer@9020000 { - compatible = "google,goldfish-rtc"; - reg = <0x9020000 0x1000>; - interrupts = <0x3>; - }; diff --git a/Documentation/devicetree/bindings/rtc/lpc32xx-rtc.txt b/Documentation/devicetree/bindings/rtc/lpc32xx-rtc.txt deleted file mode 100644 index a87a1e9bc060..000000000000 --- a/Documentation/devicetree/bindings/rtc/lpc32xx-rtc.txt +++ /dev/null @@ -1,15 +0,0 @@ -* NXP LPC32xx SoC Real Time Clock controller - -Required properties: -- compatible: must be "nxp,lpc3220-rtc" -- reg: physical base address of the controller and length of memory mapped - region. -- interrupts: The RTC interrupt - -Example: - - rtc@40024000 { - compatible = "nxp,lpc3220-rtc"; - reg = <0x40024000 0x1000>; - interrupts = <52 0>; - }; diff --git a/Documentation/devicetree/bindings/rtc/maxim,ds1742.txt b/Documentation/devicetree/bindings/rtc/maxim,ds1742.txt deleted file mode 100644 index d0f937c355b5..000000000000 --- a/Documentation/devicetree/bindings/rtc/maxim,ds1742.txt +++ /dev/null @@ -1,12 +0,0 @@ -* Maxim (Dallas) DS1742/DS1743 Real Time Clock - -Required properties: -- compatible: Should contain "maxim,ds1742". -- reg: Physical base address of the RTC and length of memory - mapped region. - -Example: - rtc: rtc@10000000 { - compatible = "maxim,ds1742"; - reg = <0x10000000 0x800>; - }; diff --git a/Documentation/devicetree/bindings/rtc/orion-rtc.txt b/Documentation/devicetree/bindings/rtc/orion-rtc.txt deleted file mode 100644 index 3bf63ffa5160..000000000000 --- a/Documentation/devicetree/bindings/rtc/orion-rtc.txt +++ /dev/null @@ -1,18 +0,0 @@ -* Mvebu Real Time Clock - -RTC controller for the Kirkwood, the Dove, the Armada 370 and the -Armada XP SoCs - -Required properties: -- compatible : Should be "marvell,orion-rtc" -- reg: physical base address of the controller and length of memory mapped - region. -- interrupts: IRQ line for the RTC. - -Example: - -rtc@10300 { - compatible = "marvell,orion-rtc"; - reg = <0xd0010300 0x20>; - interrupts = <50>; -}; diff --git a/Documentation/devicetree/bindings/rtc/rtc-aspeed.txt b/Documentation/devicetree/bindings/rtc/rtc-aspeed.txt deleted file mode 100644 index 2e956b3dc276..000000000000 --- a/Documentation/devicetree/bindings/rtc/rtc-aspeed.txt +++ /dev/null @@ -1,22 +0,0 @@ -ASPEED BMC RTC -============== - -Required properties: - - compatible: should be one of the following - * aspeed,ast2400-rtc for the ast2400 - * aspeed,ast2500-rtc for the ast2500 - * aspeed,ast2600-rtc for the ast2600 - - - reg: physical base address of the controller and length of memory mapped - region - - - interrupts: The interrupt number - -Example: - - rtc@1e781000 { - compatible = "aspeed,ast2400-rtc"; - reg = <0x1e781000 0x18>; - interrupts = <22>; - status = "disabled"; - }; diff --git a/Documentation/devicetree/bindings/rtc/spear-rtc.txt b/Documentation/devicetree/bindings/rtc/spear-rtc.txt deleted file mode 100644 index fecf8e4ad4b4..000000000000 --- a/Documentation/devicetree/bindings/rtc/spear-rtc.txt +++ /dev/null @@ -1,15 +0,0 @@ -* SPEAr RTC - -Required properties: -- compatible : "st,spear600-rtc" -- reg : Address range of the rtc registers -- interrupt: Should contain the rtc interrupt number - -Example: - - rtc@fc000000 { - compatible = "st,spear600-rtc"; - reg = <0xfc000000 0x1000>; - interrupt-parent = <&vic1>; - interrupts = <12>; - }; diff --git a/Documentation/devicetree/bindings/rtc/trivial-rtc.yaml b/Documentation/devicetree/bindings/rtc/trivial-rtc.yaml index bad7e3114096..fffd759c603f 100644 --- a/Documentation/devicetree/bindings/rtc/trivial-rtc.yaml +++ b/Documentation/devicetree/bindings/rtc/trivial-rtc.yaml @@ -24,6 +24,12 @@ properties: - abracon,abb5zes3 # AB-RTCMC-32.768kHz-EOZ9: Real Time Clock/Calendar Module with I2C Interface - abracon,abeoz9 + # ASPEED BMC ast2400 Real-time Clock + - aspeed,ast2400-rtc + # ASPEED BMC ast2500 Real-time Clock + - aspeed,ast2500-rtc + # ASPEED BMC ast2600 Real-time Clock + - aspeed,ast2600-rtc # Conexant Digicolor Real Time Clock Controller - cnxt,cx92755-rtc # I2C, 32-Bit Binary Counter Watchdog RTC with Trickle Charger and Reset Input/Output @@ -44,16 +50,24 @@ properties: - epson,rx8571 # I2C-BUS INTERFACE REAL TIME CLOCK MODULE - epson,rx8581 + # Android Goldfish Real-time Clock + - google,goldfish-rtc # Intersil ISL1208 Low Power RTC with Battery Backed SRAM - isil,isl1208 # Intersil ISL1218 Low Power RTC with Battery Backed SRAM - isil,isl1218 + # Mvebu Real-time Clock + - marvell,orion-rtc + # Maxim DS1742/DS1743 Real-time Clock + - maxim,ds1742 # SPI-BUS INTERFACE REAL TIME CLOCK MODULE - maxim,mcp795 # Real Time Clock Module with I2C-Bus - microcrystal,rv3029 # Real Time Clock - microcrystal,rv8523 + # NXP LPC32xx SoC Real-time Clock + - nxp,lpc3220-rtc # Real-time Clock Module - pericom,pt7c4338 # I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC @@ -70,6 +84,10 @@ properties: - ricoh,rv5c387a # 2-wire CMOS real-time clock - sii,s35390a + # ST SPEAr Real-time Clock + - st,spear600-rtc + # VIA/Wondermedia VT8500 Real-time Clock + - via,vt8500-rtc # I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC - whwave,sd3078 # Xircom X1205 I2C RTC diff --git a/Documentation/devicetree/bindings/rtc/via,vt8500-rtc.txt b/Documentation/devicetree/bindings/rtc/via,vt8500-rtc.txt deleted file mode 100644 index 3c0484c49582..000000000000 --- a/Documentation/devicetree/bindings/rtc/via,vt8500-rtc.txt +++ /dev/null @@ -1,15 +0,0 @@ -VIA/Wondermedia VT8500 Realtime Clock Controller ------------------------------------------------------ - -Required properties: -- compatible : "via,vt8500-rtc" -- reg : Should contain 1 register ranges(address and length) -- interrupts : alarm interrupt - -Example: - - rtc@d8100000 { - compatible = "via,vt8500-rtc"; - reg = <0xd8100000 0x10000>; - interrupts = <48>; - }; diff --git a/MAINTAINERS b/MAINTAINERS index aa3b947fb080..ea6034a641bf 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1442,7 +1442,6 @@ F: drivers/irqchip/irq-goldfish-pic.c ANDROID GOLDFISH RTC DRIVER M: Jiaxun Yang S: Supported -F: Documentation/devicetree/bindings/rtc/google,goldfish-rtc.txt F: drivers/rtc/rtc-goldfish.c AOA (Apple Onboard Audio) ALSA DRIVER -- cgit v1.2.3-59-g8ed1b From a9b5bb5c2222b90f30c37c6036664b96404ab369 Mon Sep 17 00:00:00 2001 From: Allen Pais Date: Wed, 27 Mar 2024 16:03:11 +0000 Subject: ipmi: Convert from tasklet to BH workqueue The only generic interface to execute asynchronously in the BH context is tasklet; however, it's marked deprecated and has some design flaws. To replace tasklets, BH workqueue support was recently added. A BH workqueue behaves similarly to regular workqueues except that the queued work items are executed in the BH context. This patch converts drivers/char/ipmi/* from tasklet to BH workqueue. Based on the work done by Tejun Heo Branch: https://git.kernel.org/pub/scm/linux/kernel/git/tj/wq.git for-6.10 Signed-off-by: Allen Pais Message-Id: <20240327160314.9982-7-apais@linux.microsoft.com> [Removed a duplicate include of workqueue.h] Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_msghandler.c | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index b0eedc4595b3..e12b531f5c2f 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -41,7 +41,7 @@ static struct ipmi_recv_msg *ipmi_alloc_recv_msg(void); static int ipmi_init_msghandler(void); -static void smi_recv_tasklet(struct tasklet_struct *t); +static void smi_recv_work(struct work_struct *t); static void handle_new_recv_msgs(struct ipmi_smi *intf); static void need_waiter(struct ipmi_smi *intf); static int handle_one_recv_msg(struct ipmi_smi *intf, @@ -498,13 +498,13 @@ struct ipmi_smi { /* * Messages queued for delivery. If delivery fails (out of memory * for instance), They will stay in here to be processed later in a - * periodic timer interrupt. The tasklet is for handling received + * periodic timer interrupt. The workqueue is for handling received * messages directly from the handler. */ spinlock_t waiting_rcv_msgs_lock; struct list_head waiting_rcv_msgs; atomic_t watchdog_pretimeouts_to_deliver; - struct tasklet_struct recv_tasklet; + struct work_struct recv_work; spinlock_t xmit_msgs_lock; struct list_head xmit_msgs; @@ -704,7 +704,7 @@ static void clean_up_interface_data(struct ipmi_smi *intf) struct cmd_rcvr *rcvr, *rcvr2; struct list_head list; - tasklet_kill(&intf->recv_tasklet); + cancel_work_sync(&intf->recv_work); free_smi_msg_list(&intf->waiting_rcv_msgs); free_recv_msg_list(&intf->waiting_events); @@ -1319,7 +1319,7 @@ static void free_user(struct kref *ref) { struct ipmi_user *user = container_of(ref, struct ipmi_user, refcount); - /* SRCU cleanup must happen in task context. */ + /* SRCU cleanup must happen in workqueue context. */ queue_work(remove_work_wq, &user->remove_work); } @@ -3605,8 +3605,7 @@ int ipmi_add_smi(struct module *owner, intf->curr_seq = 0; spin_lock_init(&intf->waiting_rcv_msgs_lock); INIT_LIST_HEAD(&intf->waiting_rcv_msgs); - tasklet_setup(&intf->recv_tasklet, - smi_recv_tasklet); + INIT_WORK(&intf->recv_work, smi_recv_work); atomic_set(&intf->watchdog_pretimeouts_to_deliver, 0); spin_lock_init(&intf->xmit_msgs_lock); INIT_LIST_HEAD(&intf->xmit_msgs); @@ -4779,7 +4778,7 @@ static void handle_new_recv_msgs(struct ipmi_smi *intf) * To preserve message order, quit if we * can't handle a message. Add the message * back at the head, this is safe because this - * tasklet is the only thing that pulls the + * workqueue is the only thing that pulls the * messages. */ list_add(&smi_msg->link, &intf->waiting_rcv_msgs); @@ -4812,10 +4811,10 @@ static void handle_new_recv_msgs(struct ipmi_smi *intf) } } -static void smi_recv_tasklet(struct tasklet_struct *t) +static void smi_recv_work(struct work_struct *t) { unsigned long flags = 0; /* keep us warning-free. */ - struct ipmi_smi *intf = from_tasklet(intf, t, recv_tasklet); + struct ipmi_smi *intf = from_work(intf, t, recv_work); int run_to_completion = intf->run_to_completion; struct ipmi_smi_msg *newmsg = NULL; @@ -4866,7 +4865,7 @@ void ipmi_smi_msg_received(struct ipmi_smi *intf, /* * To preserve message order, we keep a queue and deliver from - * a tasklet. + * a workqueue. */ if (!run_to_completion) spin_lock_irqsave(&intf->waiting_rcv_msgs_lock, flags); @@ -4887,9 +4886,9 @@ void ipmi_smi_msg_received(struct ipmi_smi *intf, spin_unlock_irqrestore(&intf->xmit_msgs_lock, flags); if (run_to_completion) - smi_recv_tasklet(&intf->recv_tasklet); + smi_recv_work(&intf->recv_work); else - tasklet_schedule(&intf->recv_tasklet); + queue_work(system_bh_wq, &intf->recv_work); } EXPORT_SYMBOL(ipmi_smi_msg_received); @@ -4899,7 +4898,7 @@ void ipmi_smi_watchdog_pretimeout(struct ipmi_smi *intf) return; atomic_set(&intf->watchdog_pretimeouts_to_deliver, 1); - tasklet_schedule(&intf->recv_tasklet); + queue_work(system_bh_wq, &intf->recv_work); } EXPORT_SYMBOL(ipmi_smi_watchdog_pretimeout); @@ -5068,7 +5067,7 @@ static bool ipmi_timeout_handler(struct ipmi_smi *intf, flags); } - tasklet_schedule(&intf->recv_tasklet); + queue_work(system_bh_wq, &intf->recv_work); return need_timer; } -- cgit v1.2.3-59-g8ed1b From c5c76d800a646e08890cb775efd6037008136b9e Mon Sep 17 00:00:00 2001 From: Niklas Schnelle Date: Thu, 4 Apr 2024 12:45:06 +0200 Subject: char: ipmi: handle HAS_IOPORT dependencies In a future patch HAS_IOPORT=n will disable inb()/outb() and friends at compile time. We thus need to add this dependency and ifdef sections of code using inb()/outb() as alternative access methods. Acked-by: Corey Minyard Co-developed-by: Arnd Bergmann Signed-off-by: Arnd Bergmann Signed-off-by: Niklas Schnelle Message-Id: <20240404104506.3352637-2-schnelle@linux.ibm.com> Signed-off-by: Corey Minyard --- drivers/char/ipmi/Makefile | 11 ++++------- drivers/char/ipmi/ipmi_si_intf.c | 3 ++- drivers/char/ipmi/ipmi_si_pci.c | 3 +++ 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/char/ipmi/Makefile b/drivers/char/ipmi/Makefile index cb6138b8ded9..e0944547c9d0 100644 --- a/drivers/char/ipmi/Makefile +++ b/drivers/char/ipmi/Makefile @@ -5,13 +5,10 @@ ipmi_si-y := ipmi_si_intf.o ipmi_kcs_sm.o ipmi_smic_sm.o ipmi_bt_sm.o \ ipmi_si_hotmod.o ipmi_si_hardcode.o ipmi_si_platform.o \ - ipmi_si_port_io.o ipmi_si_mem_io.o -ifdef CONFIG_PCI -ipmi_si-y += ipmi_si_pci.o -endif -ifdef CONFIG_PARISC -ipmi_si-y += ipmi_si_parisc.o -endif + ipmi_si_mem_io.o +ipmi_si-$(CONFIG_HAS_IOPORT) += ipmi_si_port_io.o +ipmi_si-$(CONFIG_PCI) += ipmi_si_pci.o +ipmi_si-$(CONFIG_PARISC) += ipmi_si_parisc.o obj-$(CONFIG_IPMI_HANDLER) += ipmi_msghandler.o obj-$(CONFIG_IPMI_DEVICE_INTERFACE) += ipmi_devintf.o diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 5cd031f3fc97..eea23a3b966e 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -1882,7 +1882,8 @@ int ipmi_si_add_smi(struct si_sm_io *io) } if (!io->io_setup) { - if (io->addr_space == IPMI_IO_ADDR_SPACE) { + if (IS_ENABLED(CONFIG_HAS_IOPORT) && + io->addr_space == IPMI_IO_ADDR_SPACE) { io->io_setup = ipmi_si_port_setup; } else if (io->addr_space == IPMI_MEM_ADDR_SPACE) { io->io_setup = ipmi_si_mem_setup; diff --git a/drivers/char/ipmi/ipmi_si_pci.c b/drivers/char/ipmi/ipmi_si_pci.c index 74fa2055868b..b83d55685b22 100644 --- a/drivers/char/ipmi/ipmi_si_pci.c +++ b/drivers/char/ipmi/ipmi_si_pci.c @@ -97,6 +97,9 @@ static int ipmi_pci_probe(struct pci_dev *pdev, } if (pci_resource_flags(pdev, 0) & IORESOURCE_IO) { + if (!IS_ENABLED(CONFIG_HAS_IOPORT)) + return -ENXIO; + io.addr_space = IPMI_IO_ADDR_SPACE; io.io_setup = ipmi_si_port_setup; } else { -- cgit v1.2.3-59-g8ed1b From 2348918407a73c3d5e35b09bd39a52ed5d0d6ab2 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Tue, 5 Mar 2024 17:26:58 +0100 Subject: ipmi: bt-bmc: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Message-Id: Signed-off-by: Corey Minyard --- drivers/char/ipmi/bt-bmc.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/char/ipmi/bt-bmc.c b/drivers/char/ipmi/bt-bmc.c index 7450904e330a..b8b9c07d3b5d 100644 --- a/drivers/char/ipmi/bt-bmc.c +++ b/drivers/char/ipmi/bt-bmc.c @@ -459,14 +459,13 @@ static int bt_bmc_probe(struct platform_device *pdev) return 0; } -static int bt_bmc_remove(struct platform_device *pdev) +static void bt_bmc_remove(struct platform_device *pdev) { struct bt_bmc *bt_bmc = dev_get_drvdata(&pdev->dev); misc_deregister(&bt_bmc->miscdev); if (bt_bmc->irq < 0) del_timer_sync(&bt_bmc->poll_timer); - return 0; } static const struct of_device_id bt_bmc_match[] = { @@ -482,7 +481,7 @@ static struct platform_driver bt_bmc_driver = { .of_match_table = bt_bmc_match, }, .probe = bt_bmc_probe, - .remove = bt_bmc_remove, + .remove_new = bt_bmc_remove, }; module_platform_driver(bt_bmc_driver); -- cgit v1.2.3-59-g8ed1b From 26edd74f5d778d9556fa80763522ca0b566f68e0 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Tue, 5 Mar 2024 17:26:59 +0100 Subject: ipmi: ipmi_powernv: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Message-Id: <22375be2dd616d8ccc2959586a08e49a5ad9e47b.1709655755.git.u.kleine-koenig@pengutronix.de> Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_powernv.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/char/ipmi/ipmi_powernv.c b/drivers/char/ipmi/ipmi_powernv.c index da22a8cbe68e..c59a86eb58c7 100644 --- a/drivers/char/ipmi/ipmi_powernv.c +++ b/drivers/char/ipmi/ipmi_powernv.c @@ -281,15 +281,13 @@ err_free: return rc; } -static int ipmi_powernv_remove(struct platform_device *pdev) +static void ipmi_powernv_remove(struct platform_device *pdev) { struct ipmi_smi_powernv *smi = dev_get_drvdata(&pdev->dev); ipmi_unregister_smi(smi->intf); free_irq(smi->irq, smi); irq_dispose_mapping(smi->irq); - - return 0; } static const struct of_device_id ipmi_powernv_match[] = { @@ -304,7 +302,7 @@ static struct platform_driver powernv_ipmi_driver = { .of_match_table = ipmi_powernv_match, }, .probe = ipmi_powernv_probe, - .remove = ipmi_powernv_remove, + .remove_new = ipmi_powernv_remove, }; -- cgit v1.2.3-59-g8ed1b From f99a996574275d33d64ee1fdee6b49369bc07a9f Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Tue, 5 Mar 2024 17:27:00 +0100 Subject: ipmi: ipmi_si_platform: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Message-Id: <789cd7876780241430dd5604bc4322453fe4e581.1709655755.git.u.kleine-koenig@pengutronix.de> Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_si_platform.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/char/ipmi/ipmi_si_platform.c b/drivers/char/ipmi/ipmi_si_platform.c index cd2edd8f8a03..96ba85648120 100644 --- a/drivers/char/ipmi/ipmi_si_platform.c +++ b/drivers/char/ipmi/ipmi_si_platform.c @@ -405,11 +405,9 @@ static int ipmi_probe(struct platform_device *pdev) return platform_ipmi_probe(pdev); } -static int ipmi_remove(struct platform_device *pdev) +static void ipmi_remove(struct platform_device *pdev) { ipmi_si_remove_by_dev(&pdev->dev); - - return 0; } static int pdev_match_name(struct device *dev, const void *data) @@ -447,7 +445,7 @@ struct platform_driver ipmi_platform_driver = { .acpi_match_table = ACPI_PTR(acpi_ipmi_match), }, .probe = ipmi_probe, - .remove = ipmi_remove, + .remove_new = ipmi_remove, .id_table = si_plat_ids }; -- cgit v1.2.3-59-g8ed1b From a69da5029931409912bb0f9f4767c4d6daa2e59e Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Tue, 5 Mar 2024 17:27:01 +0100 Subject: ipmi: ipmi_ssif: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Message-Id: Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_ssif.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c index 1f7600c361e6..3f509a22217b 100644 --- a/drivers/char/ipmi/ipmi_ssif.c +++ b/drivers/char/ipmi/ipmi_ssif.c @@ -2071,7 +2071,7 @@ static int ssif_platform_probe(struct platform_device *dev) return dmi_ipmi_probe(dev); } -static int ssif_platform_remove(struct platform_device *dev) +static void ssif_platform_remove(struct platform_device *dev) { struct ssif_addr_info *addr_info = dev_get_drvdata(&dev->dev); @@ -2079,7 +2079,6 @@ static int ssif_platform_remove(struct platform_device *dev) list_del(&addr_info->link); kfree(addr_info); mutex_unlock(&ssif_infos_mutex); - return 0; } static const struct platform_device_id ssif_plat_ids[] = { @@ -2092,7 +2091,7 @@ static struct platform_driver ipmi_driver = { .name = DEVICE_NAME, }, .probe = ssif_platform_probe, - .remove = ssif_platform_remove, + .remove_new = ssif_platform_remove, .id_table = ssif_plat_ids }; -- cgit v1.2.3-59-g8ed1b From c61090f4ef06f8cd75683ef18de4b3256697094c Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Tue, 5 Mar 2024 17:27:02 +0100 Subject: ipmi: kcs_bmc_aspeed: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Message-Id: Reviewed-by: Andrew Jeffery Signed-off-by: Corey Minyard --- drivers/char/ipmi/kcs_bmc_aspeed.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/char/ipmi/kcs_bmc_aspeed.c b/drivers/char/ipmi/kcs_bmc_aspeed.c index 72640da55380..227bf06c7ca4 100644 --- a/drivers/char/ipmi/kcs_bmc_aspeed.c +++ b/drivers/char/ipmi/kcs_bmc_aspeed.c @@ -641,7 +641,7 @@ static int aspeed_kcs_probe(struct platform_device *pdev) return 0; } -static int aspeed_kcs_remove(struct platform_device *pdev) +static void aspeed_kcs_remove(struct platform_device *pdev) { struct aspeed_kcs_bmc *priv = platform_get_drvdata(pdev); struct kcs_bmc_device *kcs_bmc = &priv->kcs_bmc; @@ -656,8 +656,6 @@ static int aspeed_kcs_remove(struct platform_device *pdev) priv->obe.remove = true; spin_unlock_irq(&priv->obe.lock); del_timer_sync(&priv->obe.timer); - - return 0; } static const struct of_device_id ast_kcs_bmc_match[] = { @@ -674,7 +672,7 @@ static struct platform_driver ast_kcs_bmc_driver = { .of_match_table = ast_kcs_bmc_match, }, .probe = aspeed_kcs_probe, - .remove = aspeed_kcs_remove, + .remove_new = aspeed_kcs_remove, }; module_platform_driver(ast_kcs_bmc_driver); -- cgit v1.2.3-59-g8ed1b From 999dff3c13930ad77a7070a5fb4473b1fafdcecc Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Tue, 5 Mar 2024 17:27:03 +0100 Subject: ipmi: kcs_bmc_npcm7xx: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Message-Id: <16144ffaa6f40a1a126d5cf19ef4337218a04fbb.1709655755.git.u.kleine-koenig@pengutronix.de> Signed-off-by: Corey Minyard --- drivers/char/ipmi/kcs_bmc_npcm7xx.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/char/ipmi/kcs_bmc_npcm7xx.c b/drivers/char/ipmi/kcs_bmc_npcm7xx.c index 7961fec56476..07710198233a 100644 --- a/drivers/char/ipmi/kcs_bmc_npcm7xx.c +++ b/drivers/char/ipmi/kcs_bmc_npcm7xx.c @@ -218,7 +218,7 @@ static int npcm7xx_kcs_probe(struct platform_device *pdev) return 0; } -static int npcm7xx_kcs_remove(struct platform_device *pdev) +static void npcm7xx_kcs_remove(struct platform_device *pdev) { struct npcm7xx_kcs_bmc *priv = platform_get_drvdata(pdev); struct kcs_bmc_device *kcs_bmc = &priv->kcs_bmc; @@ -227,8 +227,6 @@ static int npcm7xx_kcs_remove(struct platform_device *pdev) npcm7xx_kcs_enable_channel(kcs_bmc, false); npcm7xx_kcs_irq_mask_update(kcs_bmc, (KCS_BMC_EVENT_TYPE_IBF | KCS_BMC_EVENT_TYPE_OBE), 0); - - return 0; } static const struct of_device_id npcm_kcs_bmc_match[] = { @@ -243,7 +241,7 @@ static struct platform_driver npcm_kcs_bmc_driver = { .of_match_table = npcm_kcs_bmc_match, }, .probe = npcm7xx_kcs_probe, - .remove = npcm7xx_kcs_remove, + .remove_new = npcm7xx_kcs_remove, }; module_platform_driver(npcm_kcs_bmc_driver); -- cgit v1.2.3-59-g8ed1b From 6d84ec254a2283c7a97a89b0dbdc4a6854bf395f Mon Sep 17 00:00:00 2001 From: Fenglin Wu Date: Tue, 16 Apr 2024 10:44:32 +0800 Subject: input: pm8xxx-vibrator: refactor to support new SPMI vibrator Currently, vibrator control register addresses are hard coded, including the base address and offsets, it's not flexible to support new SPMI vibrator module which is usually included in different PMICs with different base address. Refactor it by using the base address defined in devicetree. Signed-off-by: Fenglin Wu Reviewed-by: Konrad Dybcio Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20240416-pm8xxx-vibrator-new-design-v11-1-7b1c951e1515@quicinc.com Signed-off-by: Dmitry Torokhov --- drivers/input/misc/pm8xxx-vibrator.c | 41 ++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/drivers/input/misc/pm8xxx-vibrator.c b/drivers/input/misc/pm8xxx-vibrator.c index 79f478d3a9b3..2bcfa7ed3d6b 100644 --- a/drivers/input/misc/pm8xxx-vibrator.c +++ b/drivers/input/misc/pm8xxx-vibrator.c @@ -19,27 +19,27 @@ #define MAX_FF_SPEED 0xff struct pm8xxx_regs { - unsigned int enable_addr; + unsigned int enable_offset; unsigned int enable_mask; - unsigned int drv_addr; + unsigned int drv_offset; unsigned int drv_mask; unsigned int drv_shift; unsigned int drv_en_manual_mask; }; static const struct pm8xxx_regs pm8058_regs = { - .drv_addr = 0x4A, - .drv_mask = 0xf8, + .drv_offset = 0, + .drv_mask = GENMASK(7, 3), .drv_shift = 3, .drv_en_manual_mask = 0xfc, }; static struct pm8xxx_regs pm8916_regs = { - .enable_addr = 0xc046, + .enable_offset = 0x46, .enable_mask = BIT(7), - .drv_addr = 0xc041, - .drv_mask = 0x1F, + .drv_offset = 0x41, + .drv_mask = GENMASK(4, 0), .drv_shift = 0, .drv_en_manual_mask = 0, }; @@ -50,6 +50,8 @@ static struct pm8xxx_regs pm8916_regs = { * @work: work structure to set the vibration parameters * @regmap: regmap for register read/write * @regs: registers' info + * @enable_addr: vibrator enable register + * @drv_addr: vibrator drive strength register * @speed: speed of vibration set from userland * @active: state of vibrator * @level: level of vibration to set in the chip @@ -60,6 +62,8 @@ struct pm8xxx_vib { struct work_struct work; struct regmap *regmap; const struct pm8xxx_regs *regs; + unsigned int enable_addr; + unsigned int drv_addr; int speed; int level; bool active; @@ -82,15 +86,15 @@ static int pm8xxx_vib_set(struct pm8xxx_vib *vib, bool on) else val &= ~regs->drv_mask; - rc = regmap_write(vib->regmap, regs->drv_addr, val); + rc = regmap_write(vib->regmap, vib->drv_addr, val); if (rc < 0) return rc; vib->reg_vib_drv = val; if (regs->enable_mask) - rc = regmap_update_bits(vib->regmap, regs->enable_addr, - regs->enable_mask, on ? ~0 : 0); + rc = regmap_update_bits(vib->regmap, vib->enable_addr, + regs->enable_mask, on ? regs->enable_mask : 0); return rc; } @@ -102,11 +106,10 @@ static int pm8xxx_vib_set(struct pm8xxx_vib *vib, bool on) static void pm8xxx_work_handler(struct work_struct *work) { struct pm8xxx_vib *vib = container_of(work, struct pm8xxx_vib, work); - const struct pm8xxx_regs *regs = vib->regs; - int rc; unsigned int val; + int rc; - rc = regmap_read(vib->regmap, regs->drv_addr, &val); + rc = regmap_read(vib->regmap, vib->drv_addr, &val); if (rc < 0) return; @@ -169,7 +172,7 @@ static int pm8xxx_vib_probe(struct platform_device *pdev) struct pm8xxx_vib *vib; struct input_dev *input_dev; int error; - unsigned int val; + unsigned int val, reg_base = 0; const struct pm8xxx_regs *regs; vib = devm_kzalloc(&pdev->dev, sizeof(*vib), GFP_KERNEL); @@ -187,15 +190,21 @@ static int pm8xxx_vib_probe(struct platform_device *pdev) INIT_WORK(&vib->work, pm8xxx_work_handler); vib->vib_input_dev = input_dev; + error = fwnode_property_read_u32(pdev->dev.fwnode, "reg", ®_base); + if (error < 0) + return dev_err_probe(&pdev->dev, error, "Failed to read reg address\n"); + regs = of_device_get_match_data(&pdev->dev); + vib->enable_addr = reg_base + regs->enable_offset; + vib->drv_addr = reg_base + regs->drv_offset; /* operate in manual mode */ - error = regmap_read(vib->regmap, regs->drv_addr, &val); + error = regmap_read(vib->regmap, vib->drv_addr, &val); if (error < 0) return error; val &= regs->drv_en_manual_mask; - error = regmap_write(vib->regmap, regs->drv_addr, val); + error = regmap_write(vib->regmap, vib->drv_addr, val); if (error < 0) return error; -- cgit v1.2.3-59-g8ed1b From ca7755adf0f20865705dd621534d50beb4f1057c Mon Sep 17 00:00:00 2001 From: Fenglin Wu Date: Tue, 16 Apr 2024 10:44:33 +0800 Subject: dt-bindings: input: qcom,pm8xxx-vib: add new SPMI vibrator module Add compatible strings to support vibrator module inside PMI632, PMI7250B, PM7325B, PM7550BA. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Fenglin Wu Link: https://lore.kernel.org/r/20240416-pm8xxx-vibrator-new-design-v11-2-7b1c951e1515@quicinc.com Signed-off-by: Dmitry Torokhov --- .../devicetree/bindings/input/qcom,pm8xxx-vib.yaml | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/input/qcom,pm8xxx-vib.yaml b/Documentation/devicetree/bindings/input/qcom,pm8xxx-vib.yaml index c8832cd0d7da..2025d6a5423e 100644 --- a/Documentation/devicetree/bindings/input/qcom,pm8xxx-vib.yaml +++ b/Documentation/devicetree/bindings/input/qcom,pm8xxx-vib.yaml @@ -11,10 +11,18 @@ maintainers: properties: compatible: - enum: - - qcom,pm8058-vib - - qcom,pm8916-vib - - qcom,pm8921-vib + oneOf: + - enum: + - qcom,pm8058-vib + - qcom,pm8916-vib + - qcom,pm8921-vib + - qcom,pmi632-vib + - items: + - enum: + - qcom,pm7250b-vib + - qcom,pm7325b-vib + - qcom,pm7550ba-vib + - const: qcom,pmi632-vib reg: maxItems: 1 -- cgit v1.2.3-59-g8ed1b From 9e0631695eac16e0102b9961c3b750c987d24f7f Mon Sep 17 00:00:00 2001 From: Fenglin Wu Date: Tue, 16 Apr 2024 10:44:34 +0800 Subject: input: pm8xxx-vibrator: add new SPMI vibrator support Add support for a new SPMI vibrator module which is very similar to the vibrator module inside PM8916 but has a finer drive voltage step and different output voltage range, its drive level control is expanded across 2 registers. The vibrator module can be found in following Qualcomm PMICs: PMI632, PM7250B, PM7325B, PM7550BA. Signed-off-by: Fenglin Wu Reviewed-by: Dmitry Baryshkov Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20240416-pm8xxx-vibrator-new-design-v11-3-7b1c951e1515@quicinc.com Signed-off-by: Dmitry Torokhov --- drivers/input/misc/pm8xxx-vibrator.c | 52 +++++++++++++++++++++++++++++------- 1 file changed, 43 insertions(+), 9 deletions(-) diff --git a/drivers/input/misc/pm8xxx-vibrator.c b/drivers/input/misc/pm8xxx-vibrator.c index 2bcfa7ed3d6b..381b06473279 100644 --- a/drivers/input/misc/pm8xxx-vibrator.c +++ b/drivers/input/misc/pm8xxx-vibrator.c @@ -11,10 +11,11 @@ #include #include -#define VIB_MAX_LEVEL_mV (3100) -#define VIB_MIN_LEVEL_mV (1200) -#define VIB_PER_STEP_mV (100) -#define VIB_MAX_LEVELS (VIB_MAX_LEVEL_mV - VIB_MIN_LEVEL_mV + VIB_PER_STEP_mV) +#define VIB_MAX_LEVEL_mV(vib) (vib->drv2_addr ? 3544 : 3100) +#define VIB_MIN_LEVEL_mV(vib) (vib->drv2_addr ? 1504 : 1200) +#define VIB_PER_STEP_mV(vib) (vib->drv2_addr ? 8 : 100) +#define VIB_MAX_LEVELS(vib) \ + (VIB_MAX_LEVEL_mV(vib) - VIB_MIN_LEVEL_mV(vib) + VIB_PER_STEP_mV(vib)) #define MAX_FF_SPEED 0xff @@ -25,7 +26,11 @@ struct pm8xxx_regs { unsigned int drv_offset; unsigned int drv_mask; unsigned int drv_shift; + unsigned int drv2_offset; + unsigned int drv2_mask; + unsigned int drv2_shift; unsigned int drv_en_manual_mask; + bool drv_in_step; }; static const struct pm8xxx_regs pm8058_regs = { @@ -33,6 +38,7 @@ static const struct pm8xxx_regs pm8058_regs = { .drv_mask = GENMASK(7, 3), .drv_shift = 3, .drv_en_manual_mask = 0xfc, + .drv_in_step = true, }; static struct pm8xxx_regs pm8916_regs = { @@ -42,6 +48,20 @@ static struct pm8xxx_regs pm8916_regs = { .drv_mask = GENMASK(4, 0), .drv_shift = 0, .drv_en_manual_mask = 0, + .drv_in_step = true, +}; + +static struct pm8xxx_regs pmi632_regs = { + .enable_offset = 0x46, + .enable_mask = BIT(7), + .drv_offset = 0x40, + .drv_mask = GENMASK(7, 0), + .drv_shift = 0, + .drv2_offset = 0x41, + .drv2_mask = GENMASK(3, 0), + .drv2_shift = 8, + .drv_en_manual_mask = 0, + .drv_in_step = false, }; /** @@ -52,6 +72,7 @@ static struct pm8xxx_regs pm8916_regs = { * @regs: registers' info * @enable_addr: vibrator enable register * @drv_addr: vibrator drive strength register + * @drv2_addr: vibrator drive strength upper byte register * @speed: speed of vibration set from userland * @active: state of vibrator * @level: level of vibration to set in the chip @@ -64,6 +85,7 @@ struct pm8xxx_vib { const struct pm8xxx_regs *regs; unsigned int enable_addr; unsigned int drv_addr; + unsigned int drv2_addr; int speed; int level; bool active; @@ -81,6 +103,9 @@ static int pm8xxx_vib_set(struct pm8xxx_vib *vib, bool on) unsigned int val = vib->reg_vib_drv; const struct pm8xxx_regs *regs = vib->regs; + if (regs->drv_in_step) + vib->level /= VIB_PER_STEP_mV(vib); + if (on) val |= (vib->level << regs->drv_shift) & regs->drv_mask; else @@ -92,6 +117,14 @@ static int pm8xxx_vib_set(struct pm8xxx_vib *vib, bool on) vib->reg_vib_drv = val; + if (regs->drv2_mask) { + val = vib->level << regs->drv2_shift; + rc = regmap_write_bits(vib->regmap, vib->drv2_addr, + regs->drv2_mask, on ? val : 0); + if (rc < 0) + return rc; + } + if (regs->enable_mask) rc = regmap_update_bits(vib->regmap, vib->enable_addr, regs->enable_mask, on ? regs->enable_mask : 0); @@ -114,17 +147,16 @@ static void pm8xxx_work_handler(struct work_struct *work) return; /* - * pmic vibrator supports voltage ranges from 1.2 to 3.1V, so + * pmic vibrator supports voltage ranges from MIN_LEVEL to MAX_LEVEL, so * scale the level to fit into these ranges. */ if (vib->speed) { vib->active = true; - vib->level = ((VIB_MAX_LEVELS * vib->speed) / MAX_FF_SPEED) + - VIB_MIN_LEVEL_mV; - vib->level /= VIB_PER_STEP_mV; + vib->level = VIB_MIN_LEVEL_mV(vib); + vib->level += mult_frac(VIB_MAX_LEVELS(vib), vib->speed, MAX_FF_SPEED); } else { vib->active = false; - vib->level = VIB_MIN_LEVEL_mV / VIB_PER_STEP_mV; + vib->level = VIB_MIN_LEVEL_mV(vib); } pm8xxx_vib_set(vib, vib->active); @@ -197,6 +229,7 @@ static int pm8xxx_vib_probe(struct platform_device *pdev) regs = of_device_get_match_data(&pdev->dev); vib->enable_addr = reg_base + regs->enable_offset; vib->drv_addr = reg_base + regs->drv_offset; + vib->drv2_addr = reg_base + regs->drv2_offset; /* operate in manual mode */ error = regmap_read(vib->regmap, vib->drv_addr, &val); @@ -251,6 +284,7 @@ static const struct of_device_id pm8xxx_vib_id_table[] = { { .compatible = "qcom,pm8058-vib", .data = &pm8058_regs }, { .compatible = "qcom,pm8921-vib", .data = &pm8058_regs }, { .compatible = "qcom,pm8916-vib", .data = &pm8916_regs }, + { .compatible = "qcom,pmi632-vib", .data = &pmi632_regs }, { } }; MODULE_DEVICE_TABLE(of, pm8xxx_vib_id_table); -- cgit v1.2.3-59-g8ed1b From 8c467f3300591a206fa8dcc6988d768910799872 Mon Sep 17 00:00:00 2001 From: Alexey Gladkov Date: Wed, 17 Apr 2024 19:37:35 +0200 Subject: VT: Use macros to define ioctls All other headers use _IOC() macros to describe ioctls for a long time now. This header is stuck in the last century. Simply use the _IO() macro. No other changes. Signed-off-by: Alexey Gladkov Link: https://lore.kernel.org/r/e4229fe2933a003341e338b558ab1ea8b63a51f6.1713375378.git.legion@kernel.org Signed-off-by: Greg Kroah-Hartman --- include/uapi/linux/kd.h | 96 +++++++++++++++++++++++++------------------------ 1 file changed, 49 insertions(+), 47 deletions(-) diff --git a/include/uapi/linux/kd.h b/include/uapi/linux/kd.h index 6b384065c013..8ddb2219a84b 100644 --- a/include/uapi/linux/kd.h +++ b/include/uapi/linux/kd.h @@ -5,60 +5,61 @@ #include /* 0x4B is 'K', to avoid collision with termios and vt */ +#define KD_IOCTL_BASE 'K' -#define GIO_FONT 0x4B60 /* gets font in expanded form */ -#define PIO_FONT 0x4B61 /* use font in expanded form */ +#define GIO_FONT _IO(KD_IOCTL_BASE, 0x60) /* gets font in expanded form */ +#define PIO_FONT _IO(KD_IOCTL_BASE, 0x61) /* use font in expanded form */ -#define GIO_FONTX 0x4B6B /* get font using struct consolefontdesc */ -#define PIO_FONTX 0x4B6C /* set font using struct consolefontdesc */ +#define GIO_FONTX _IO(KD_IOCTL_BASE, 0x6B) /* get font using struct consolefontdesc */ +#define PIO_FONTX _IO(KD_IOCTL_BASE, 0x6C) /* set font using struct consolefontdesc */ struct consolefontdesc { unsigned short charcount; /* characters in font (256 or 512) */ unsigned short charheight; /* scan lines per character (1-32) */ char __user *chardata; /* font data in expanded form */ }; -#define PIO_FONTRESET 0x4B6D /* reset to default font */ +#define PIO_FONTRESET _IO(KD_IOCTL_BASE, 0x6D) /* reset to default font */ -#define GIO_CMAP 0x4B70 /* gets colour palette on VGA+ */ -#define PIO_CMAP 0x4B71 /* sets colour palette on VGA+ */ +#define GIO_CMAP _IO(KD_IOCTL_BASE, 0x70) /* gets colour palette on VGA+ */ +#define PIO_CMAP _IO(KD_IOCTL_BASE, 0x71) /* sets colour palette on VGA+ */ -#define KIOCSOUND 0x4B2F /* start sound generation (0 for off) */ -#define KDMKTONE 0x4B30 /* generate tone */ +#define KIOCSOUND _IO(KD_IOCTL_BASE, 0x2F) /* start sound generation (0 for off) */ +#define KDMKTONE _IO(KD_IOCTL_BASE, 0x30) /* generate tone */ -#define KDGETLED 0x4B31 /* return current led state */ -#define KDSETLED 0x4B32 /* set led state [lights, not flags] */ +#define KDGETLED _IO(KD_IOCTL_BASE, 0x31) /* return current led state */ +#define KDSETLED _IO(KD_IOCTL_BASE, 0x32) /* set led state [lights, not flags] */ #define LED_SCR 0x01 /* scroll lock led */ #define LED_NUM 0x02 /* num lock led */ #define LED_CAP 0x04 /* caps lock led */ -#define KDGKBTYPE 0x4B33 /* get keyboard type */ +#define KDGKBTYPE _IO(KD_IOCTL_BASE, 0x33) /* get keyboard type */ #define KB_84 0x01 #define KB_101 0x02 /* this is what we always answer */ #define KB_OTHER 0x03 -#define KDADDIO 0x4B34 /* add i/o port as valid */ -#define KDDELIO 0x4B35 /* del i/o port as valid */ -#define KDENABIO 0x4B36 /* enable i/o to video board */ -#define KDDISABIO 0x4B37 /* disable i/o to video board */ +#define KDADDIO _IO(KD_IOCTL_BASE, 0x34) /* add i/o port as valid */ +#define KDDELIO _IO(KD_IOCTL_BASE, 0x35) /* del i/o port as valid */ +#define KDENABIO _IO(KD_IOCTL_BASE, 0x36) /* enable i/o to video board */ +#define KDDISABIO _IO(KD_IOCTL_BASE, 0x37) /* disable i/o to video board */ -#define KDSETMODE 0x4B3A /* set text/graphics mode */ +#define KDSETMODE _IO(KD_IOCTL_BASE, 0x3A) /* set text/graphics mode */ #define KD_TEXT 0x00 #define KD_GRAPHICS 0x01 #define KD_TEXT0 0x02 /* obsolete */ #define KD_TEXT1 0x03 /* obsolete */ -#define KDGETMODE 0x4B3B /* get current mode */ +#define KDGETMODE _IO(KD_IOCTL_BASE, 0x3B) /* get current mode */ -#define KDMAPDISP 0x4B3C /* map display into address space */ -#define KDUNMAPDISP 0x4B3D /* unmap display from address space */ +#define KDMAPDISP _IO(KD_IOCTL_BASE, 0x3C) /* map display into address space */ +#define KDUNMAPDISP _IO(KD_IOCTL_BASE, 0x3D) /* unmap display from address space */ typedef char scrnmap_t; #define E_TABSZ 256 -#define GIO_SCRNMAP 0x4B40 /* get screen mapping from kernel */ -#define PIO_SCRNMAP 0x4B41 /* put screen mapping table in kernel */ -#define GIO_UNISCRNMAP 0x4B69 /* get full Unicode screen mapping */ -#define PIO_UNISCRNMAP 0x4B6A /* set full Unicode screen mapping */ +#define GIO_SCRNMAP _IO(KD_IOCTL_BASE, 0x40) /* get screen mapping from kernel */ +#define PIO_SCRNMAP _IO(KD_IOCTL_BASE, 0x41) /* put screen mapping table in kernel */ +#define GIO_UNISCRNMAP _IO(KD_IOCTL_BASE, 0x69) /* get full Unicode screen mapping */ +#define PIO_UNISCRNMAP _IO(KD_IOCTL_BASE, 0x6A) /* set full Unicode screen mapping */ -#define GIO_UNIMAP 0x4B66 /* get unicode-to-font mapping from kernel */ +#define GIO_UNIMAP _IO(KD_IOCTL_BASE, 0x66) /* get unicode-to-font mapping from kernel */ struct unipair { unsigned short unicode; unsigned short fontpos; @@ -67,8 +68,8 @@ struct unimapdesc { unsigned short entry_ct; struct unipair __user *entries; }; -#define PIO_UNIMAP 0x4B67 /* put unicode-to-font mapping in kernel */ -#define PIO_UNIMAPCLR 0x4B68 /* clear table, possibly advise hash algorithm */ +#define PIO_UNIMAP _IO(KD_IOCTL_BASE, 0x67) /* put unicode-to-font mapping in kernel */ +#define PIO_UNIMAPCLR _IO(KD_IOCTL_BASE, 0x68) /* clear table, possibly advise hash algorithm */ struct unimapinit { unsigned short advised_hashsize; /* 0 if no opinion */ unsigned short advised_hashstep; /* 0 if no opinion */ @@ -83,19 +84,19 @@ struct unimapinit { #define K_MEDIUMRAW 0x02 #define K_UNICODE 0x03 #define K_OFF 0x04 -#define KDGKBMODE 0x4B44 /* gets current keyboard mode */ -#define KDSKBMODE 0x4B45 /* sets current keyboard mode */ +#define KDGKBMODE _IO(KD_IOCTL_BASE, 0x44) /* gets current keyboard mode */ +#define KDSKBMODE _IO(KD_IOCTL_BASE, 0x45) /* sets current keyboard mode */ #define K_METABIT 0x03 #define K_ESCPREFIX 0x04 -#define KDGKBMETA 0x4B62 /* gets meta key handling mode */ -#define KDSKBMETA 0x4B63 /* sets meta key handling mode */ +#define KDGKBMETA _IO(KD_IOCTL_BASE, 0x62) /* gets meta key handling mode */ +#define KDSKBMETA _IO(KD_IOCTL_BASE, 0x63) /* sets meta key handling mode */ #define K_SCROLLLOCK 0x01 #define K_NUMLOCK 0x02 #define K_CAPSLOCK 0x04 -#define KDGKBLED 0x4B64 /* get led flags (not lights) */ -#define KDSKBLED 0x4B65 /* set led flags (not lights) */ +#define KDGKBLED _IO(KD_IOCTL_BASE, 0x64) /* get led flags (not lights) */ +#define KDSKBLED _IO(KD_IOCTL_BASE, 0x65) /* set led flags (not lights) */ struct kbentry { unsigned char kb_table; @@ -107,15 +108,15 @@ struct kbentry { #define K_ALTTAB 0x02 #define K_ALTSHIFTTAB 0x03 -#define KDGKBENT 0x4B46 /* gets one entry in translation table */ -#define KDSKBENT 0x4B47 /* sets one entry in translation table */ +#define KDGKBENT _IO(KD_IOCTL_BASE, 0x46) /* gets one entry in translation table */ +#define KDSKBENT _IO(KD_IOCTL_BASE, 0x47) /* sets one entry in translation table */ struct kbsentry { unsigned char kb_func; unsigned char kb_string[512]; }; -#define KDGKBSENT 0x4B48 /* gets one function key string entry */ -#define KDSKBSENT 0x4B49 /* sets one function key string entry */ +#define KDGKBSENT _IO(KD_IOCTL_BASE, 0x48) /* gets one function key string entry */ +#define KDSKBSENT _IO(KD_IOCTL_BASE, 0x49) /* sets one function key string entry */ struct kbdiacr { unsigned char diacr, base, result; @@ -124,8 +125,8 @@ struct kbdiacrs { unsigned int kb_cnt; /* number of entries in following array */ struct kbdiacr kbdiacr[256]; /* MAX_DIACR from keyboard.h */ }; -#define KDGKBDIACR 0x4B4A /* read kernel accent table */ -#define KDSKBDIACR 0x4B4B /* write kernel accent table */ +#define KDGKBDIACR _IO(KD_IOCTL_BASE, 0x4A) /* read kernel accent table */ +#define KDSKBDIACR _IO(KD_IOCTL_BASE, 0x4B) /* write kernel accent table */ struct kbdiacruc { unsigned int diacr, base, result; @@ -134,16 +135,16 @@ struct kbdiacrsuc { unsigned int kb_cnt; /* number of entries in following array */ struct kbdiacruc kbdiacruc[256]; /* MAX_DIACR from keyboard.h */ }; -#define KDGKBDIACRUC 0x4BFA /* read kernel accent table - UCS */ -#define KDSKBDIACRUC 0x4BFB /* write kernel accent table - UCS */ +#define KDGKBDIACRUC _IO(KD_IOCTL_BASE, 0xFA) /* read kernel accent table - UCS */ +#define KDSKBDIACRUC _IO(KD_IOCTL_BASE, 0xFB) /* write kernel accent table - UCS */ struct kbkeycode { unsigned int scancode, keycode; }; -#define KDGETKEYCODE 0x4B4C /* read kernel keycode table entry */ -#define KDSETKEYCODE 0x4B4D /* write kernel keycode table entry */ +#define KDGETKEYCODE _IO(KD_IOCTL_BASE, 0x4C) /* read kernel keycode table entry */ +#define KDSETKEYCODE _IO(KD_IOCTL_BASE, 0x4D) /* write kernel keycode table entry */ -#define KDSIGACCEPT 0x4B4E /* accept kbd generated signals */ +#define KDSIGACCEPT _IO(KD_IOCTL_BASE, 0x4E) /* accept kbd generated signals */ struct kbd_repeat { int delay; /* in msec; <= 0: don't change */ @@ -151,10 +152,11 @@ struct kbd_repeat { /* earlier this field was misnamed "rate" */ }; -#define KDKBDREP 0x4B52 /* set keyboard delay/repeat rate; - * actually used values are returned */ +#define KDKBDREP _IO(KD_IOCTL_BASE, 0x52) /* set keyboard delay/repeat rate; + * actually used values are returned + */ -#define KDFONTOP 0x4B72 /* font operations */ +#define KDFONTOP _IO(KD_IOCTL_BASE, 0x72) /* font operations */ struct console_font_op { unsigned int op; /* operation code KD_FONT_OP_* */ -- cgit v1.2.3-59-g8ed1b From c69fddf12ffcf375d24ccc32c94546d56b1ba2e8 Mon Sep 17 00:00:00 2001 From: Parker Newman Date: Wed, 17 Apr 2024 16:31:23 -0400 Subject: serial: exar: remove old Connect Tech setup Preparatory patch removing existing Connect Tech setup code and CONNECT_DEVICE macro. Subsequent patches in this series will add in new UART family specific setup code and new device definition macros to allow for supporting CTI serial cards with Exar PCI IDs and CTI PCI IDs. Signed-off-by: Parker Newman Link: https://lore.kernel.org/r/06a04b6c683ca20c50646cc0836be869c2dacd87.1713382717.git.pnewman@connecttech.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_exar.c | 37 ------------------------------------- 1 file changed, 37 deletions(-) diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c index 604e5a292d4e..04ce5e8ddb24 100644 --- a/drivers/tty/serial/8250/8250_exar.c +++ b/drivers/tty/serial/8250/8250_exar.c @@ -358,17 +358,6 @@ pci_fastcom335_setup(struct exar8250 *priv, struct pci_dev *pcidev, return 0; } -static int -pci_connect_tech_setup(struct exar8250 *priv, struct pci_dev *pcidev, - struct uart_8250_port *port, int idx) -{ - unsigned int offset = idx * 0x200; - unsigned int baud = 1843200; - - port->port.uartclk = baud * 16; - return default_setup(priv, pcidev, idx, offset, port); -} - static int pci_xr17c154_setup(struct exar8250 *priv, struct pci_dev *pcidev, struct uart_8250_port *port, int idx) @@ -849,10 +838,6 @@ static const struct exar8250_board pbn_fastcom335_8 = { .setup = pci_fastcom335_setup, }; -static const struct exar8250_board pbn_connect = { - .setup = pci_connect_tech_setup, -}; - static const struct exar8250_board pbn_exar_ibm_saturn = { .num_ports = 1, .setup = pci_xr17c154_setup, @@ -897,15 +882,6 @@ static const struct exar8250_board pbn_exar_XR17V8358 = { .exit = pci_xr17v35x_exit, }; -#define CONNECT_DEVICE(devid, sdevid, bd) { \ - PCI_DEVICE_SUB( \ - PCI_VENDOR_ID_EXAR, \ - PCI_DEVICE_ID_EXAR_##devid, \ - PCI_SUBVENDOR_ID_CONNECT_TECH, \ - PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_##sdevid), 0, 0, \ - (kernel_ulong_t)&bd \ - } - #define EXAR_DEVICE(vend, devid, bd) { PCI_DEVICE_DATA(vend, devid, &bd) } #define IBM_DEVICE(devid, sdevid, bd) { \ @@ -935,19 +911,6 @@ static const struct pci_device_id exar_pci_tbl[] = { EXAR_DEVICE(ACCESSIO, COM_4SM, pbn_exar_XR17C15x), EXAR_DEVICE(ACCESSIO, COM_8SM, pbn_exar_XR17C15x), - CONNECT_DEVICE(XR17C152, UART_2_232, pbn_connect), - CONNECT_DEVICE(XR17C154, UART_4_232, pbn_connect), - CONNECT_DEVICE(XR17C158, UART_8_232, pbn_connect), - CONNECT_DEVICE(XR17C152, UART_1_1, pbn_connect), - CONNECT_DEVICE(XR17C154, UART_2_2, pbn_connect), - CONNECT_DEVICE(XR17C158, UART_4_4, pbn_connect), - CONNECT_DEVICE(XR17C152, UART_2, pbn_connect), - CONNECT_DEVICE(XR17C154, UART_4, pbn_connect), - CONNECT_DEVICE(XR17C158, UART_8, pbn_connect), - CONNECT_DEVICE(XR17C152, UART_2_485, pbn_connect), - CONNECT_DEVICE(XR17C154, UART_4_485, pbn_connect), - CONNECT_DEVICE(XR17C158, UART_8_485, pbn_connect), - IBM_DEVICE(XR17C152, SATURN_SERIAL_ONE_PORT, pbn_exar_ibm_saturn), /* USRobotics USR298x-OEM PCI Modems */ -- cgit v1.2.3-59-g8ed1b From 477f6ee694fbd07047fecd37a9992bbe22a36323 Mon Sep 17 00:00:00 2001 From: Parker Newman Date: Wed, 17 Apr 2024 16:31:24 -0400 Subject: serial: exar: added a exar_get_nr_ports function Moved code for getting number of ports from exar_pci_probe() to a separate exar_get_nr_ports() function. CTI specific code will be added in another patch in this series. Signed-off-by: Parker Newman Link: https://lore.kernel.org/r/33f2bf66bc334573c10cf670a299ecef0b7264bc.1713382717.git.pnewman@connecttech.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_exar.c | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c index 04ce5e8ddb24..72385c7d2eda 100644 --- a/drivers/tty/serial/8250/8250_exar.c +++ b/drivers/tty/serial/8250/8250_exar.c @@ -704,6 +704,21 @@ static irqreturn_t exar_misc_handler(int irq, void *data) return IRQ_HANDLED; } +static unsigned int exar_get_nr_ports(struct exar8250_board *board, + struct pci_dev *pcidev) +{ + unsigned int nr_ports = 0; + + if (pcidev->vendor == PCI_VENDOR_ID_ACCESSIO) + nr_ports = BIT(((pcidev->device & 0x38) >> 3) - 1); + else if (board->num_ports) + nr_ports = board->num_ports; + else + nr_ports = pcidev->device & 0x0f; + + return nr_ports; +} + static int exar_pci_probe(struct pci_dev *pcidev, const struct pci_device_id *ent) { @@ -723,12 +738,12 @@ exar_pci_probe(struct pci_dev *pcidev, const struct pci_device_id *ent) maxnr = pci_resource_len(pcidev, bar) >> (board->reg_shift + 3); - if (pcidev->vendor == PCI_VENDOR_ID_ACCESSIO) - nr_ports = BIT(((pcidev->device & 0x38) >> 3) - 1); - else if (board->num_ports) - nr_ports = board->num_ports; - else - nr_ports = pcidev->device & 0x0f; + nr_ports = exar_get_nr_ports(board, pcidev); + if (nr_ports == 0) { + dev_err_probe(&pcidev->dev, -ENODEV, + "failed to get number of ports\n"); + return -ENODEV; + } priv = devm_kzalloc(&pcidev->dev, struct_size(priv, line, nr_ports), GFP_KERNEL); if (!priv) -- cgit v1.2.3-59-g8ed1b From 393b520a99b21d9ec6d4bb32e7c05bbb4f6dc777 Mon Sep 17 00:00:00 2001 From: Parker Newman Date: Wed, 17 Apr 2024 16:31:25 -0400 Subject: serial: exar: add optional board_init function Add an optional "board_init()" function pointer to struct exar8250_board which is called once during probe prior to setting up the ports. It will be used in subsequent patches of this series. Signed-off-by: Parker Newman Link: https://lore.kernel.org/r/0e72a3154114c733283ff273bc1e31456ee101f4.1713382717.git.pnewman@connecttech.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_exar.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c index 72385c7d2eda..f14f73d250bb 100644 --- a/drivers/tty/serial/8250/8250_exar.c +++ b/drivers/tty/serial/8250/8250_exar.c @@ -177,12 +177,14 @@ struct exar8250_platform { * struct exar8250_board - board information * @num_ports: number of serial ports * @reg_shift: describes UART register mapping in PCI memory - * @setup: quirk run at ->probe() stage + * @board_init: quirk run once at ->probe() stage before setting up ports + * @setup: quirk run at ->probe() stage for each port * @exit: quirk run at ->remove() stage */ struct exar8250_board { unsigned int num_ports; unsigned int reg_shift; + int (*board_init)(struct exar8250 *priv, struct pci_dev *pcidev); int (*setup)(struct exar8250 *, struct pci_dev *, struct uart_8250_port *, int); void (*exit)(struct pci_dev *pcidev); @@ -773,6 +775,15 @@ exar_pci_probe(struct pci_dev *pcidev, const struct pci_device_id *ent) if (rc) return rc; + if (board->board_init) { + rc = board->board_init(priv, pcidev); + if (rc) { + dev_err_probe(&pcidev->dev, rc, + "failed to init serial board\n"); + return rc; + } + } + for (i = 0; i < nr_ports && i < maxnr; i++) { rc = board->setup(priv, pcidev, &uart, i); if (rc) { -- cgit v1.2.3-59-g8ed1b From 209a20d4bd91761f801116bb155758e45e9340a8 Mon Sep 17 00:00:00 2001 From: Parker Newman Date: Wed, 17 Apr 2024 16:31:26 -0400 Subject: serial: exar: moved generic_rs485 further up in 8250_exar.c Preparatory patch moving generic_rs485_config and generic_rs485_supported higher in the file to allow for CTI setup functions to use them. Signed-off-by: Parker Newman Link: https://lore.kernel.org/r/a7bf2a42de759908c058246ec15f60bde9a5dc65.1713382717.git.pnewman@connecttech.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_exar.c | 50 ++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c index f14f73d250bb..e68029a59122 100644 --- a/drivers/tty/serial/8250/8250_exar.c +++ b/drivers/tty/serial/8250/8250_exar.c @@ -197,6 +197,31 @@ struct exar8250 { int line[]; }; +static int generic_rs485_config(struct uart_port *port, struct ktermios *termios, + struct serial_rs485 *rs485) +{ + bool is_rs485 = !!(rs485->flags & SER_RS485_ENABLED); + u8 __iomem *p = port->membase; + u8 value; + + value = readb(p + UART_EXAR_FCTR); + if (is_rs485) + value |= UART_FCTR_EXAR_485; + else + value &= ~UART_FCTR_EXAR_485; + + writeb(value, p + UART_EXAR_FCTR); + + if (is_rs485) + writeb(UART_EXAR_RS485_DLY(4), p + UART_MSR); + + return 0; +} + +static const struct serial_rs485 generic_rs485_supported = { + .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND, +}; + static void exar_pm(struct uart_port *port, unsigned int state, unsigned int old) { /* @@ -459,27 +484,6 @@ static void xr17v35x_unregister_gpio(struct uart_8250_port *port) port->port.private_data = NULL; } -static int generic_rs485_config(struct uart_port *port, struct ktermios *termios, - struct serial_rs485 *rs485) -{ - bool is_rs485 = !!(rs485->flags & SER_RS485_ENABLED); - u8 __iomem *p = port->membase; - u8 value; - - value = readb(p + UART_EXAR_FCTR); - if (is_rs485) - value |= UART_FCTR_EXAR_485; - else - value &= ~UART_FCTR_EXAR_485; - - writeb(value, p + UART_EXAR_FCTR); - - if (is_rs485) - writeb(UART_EXAR_RS485_DLY(4), p + UART_MSR); - - return 0; -} - static int sealevel_rs485_config(struct uart_port *port, struct ktermios *termios, struct serial_rs485 *rs485) { @@ -518,10 +522,6 @@ static int sealevel_rs485_config(struct uart_port *port, struct ktermios *termio return 0; } -static const struct serial_rs485 generic_rs485_supported = { - .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND, -}; - static const struct exar8250_platform exar8250_default_platform = { .register_gpio = xr17v35x_register_gpio, .unregister_gpio = xr17v35x_unregister_gpio, -- cgit v1.2.3-59-g8ed1b From 5aa84fd8d0592ee72387bd807a052a52abaad360 Mon Sep 17 00:00:00 2001 From: Parker Newman Date: Wed, 17 Apr 2024 16:31:27 -0400 Subject: serial: exar: add CTI cards to exar_get_nr_ports Add code for getting number of ports of CTI cards to exar_get_nr_ports(). Signed-off-by: Parker Newman Link: https://lore.kernel.org/r/0c64bdf852f39aec966b38696695d951e485d7e6.1713382717.git.pnewman@connecttech.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_exar.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c index e68029a59122..197f45e306ff 100644 --- a/drivers/tty/serial/8250/8250_exar.c +++ b/drivers/tty/serial/8250/8250_exar.c @@ -711,12 +711,28 @@ static unsigned int exar_get_nr_ports(struct exar8250_board *board, { unsigned int nr_ports = 0; - if (pcidev->vendor == PCI_VENDOR_ID_ACCESSIO) + if (pcidev->vendor == PCI_VENDOR_ID_ACCESSIO) { nr_ports = BIT(((pcidev->device & 0x38) >> 3) - 1); - else if (board->num_ports) + } else if (board->num_ports > 0) { + // Check if board struct overrides number of ports nr_ports = board->num_ports; - else + } else if (pcidev->vendor == PCI_VENDOR_ID_EXAR) { + // Exar encodes # ports in last nibble of PCI Device ID ex. 0358 nr_ports = pcidev->device & 0x0f; + } else if (pcidev->vendor == PCI_VENDOR_ID_CONNECT_TECH) { + // Handle CTI FPGA cards + switch (pcidev->device) { + case PCI_DEVICE_ID_CONNECT_TECH_PCI_XR79X_12_XIG00X: + case PCI_DEVICE_ID_CONNECT_TECH_PCI_XR79X_12_XIG01X: + nr_ports = 12; + break; + case PCI_DEVICE_ID_CONNECT_TECH_PCI_XR79X_16: + nr_ports = 16; + break; + default: + break; + } + } return nr_ports; } -- cgit v1.2.3-59-g8ed1b From f7ce07062988a26b83ca1448df8d1e4a9232d962 Mon Sep 17 00:00:00 2001 From: Parker Newman Date: Wed, 17 Apr 2024 16:31:28 -0400 Subject: serial: exar: add CTI specific setup code This is a large patch but is only additions. All changes and removals are made in previous patches in this series. - Add CTI board_init and port setup functions for each UART type - Add CTI_EXAR_DEVICE() and CTI_PCI_DEVICE() macros - Add support for reading a word from the Exar EEPROM. - Add support for configuring and setting a single MPIO - Add various helper functions for CTI boards. - Add osc_freq to struct exar8250 Signed-off-by: Parker Newman Link: https://lore.kernel.org/r/ae4a66e7342b686cb8d4b15317585dfb37222cf4.1713382717.git.pnewman@connecttech.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_exar.c | 846 ++++++++++++++++++++++++++++++++++++ 1 file changed, 846 insertions(+) diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c index 197f45e306ff..6985aabe13cc 100644 --- a/drivers/tty/serial/8250/8250_exar.c +++ b/drivers/tty/serial/8250/8250_exar.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -128,6 +129,19 @@ #define UART_EXAR_DLD 0x02 /* Divisor Fractional */ #define UART_EXAR_DLD_485_POLARITY 0x80 /* RS-485 Enable Signal Polarity */ +/* EEPROM registers */ +#define UART_EXAR_REGB 0x8e +#define UART_EXAR_REGB_EECK BIT(4) +#define UART_EXAR_REGB_EECS BIT(5) +#define UART_EXAR_REGB_EEDI BIT(6) +#define UART_EXAR_REGB_EEDO BIT(7) +#define UART_EXAR_REGB_EE_ADDR_SIZE 6 +#define UART_EXAR_REGB_EE_DATA_SIZE 16 + +#define UART_EXAR_XR17C15X_PORT_OFFSET 0x200 +#define UART_EXAR_XR17V25X_PORT_OFFSET 0x200 +#define UART_EXAR_XR17V35X_PORT_OFFSET 0x400 + /* * IOT2040 MPIO wiring semantics: * @@ -163,6 +177,52 @@ #define IOT2040_UARTS_ENABLE 0x03 #define IOT2040_UARTS_GPIO_HI_MODE 0xF8 /* enable & LED as outputs */ +/* CTI EEPROM offsets */ +#define CTI_EE_OFF_XR17C15X_OSC_FREQ 0x04 /* 2 words */ +#define CTI_EE_OFF_XR17V25X_OSC_FREQ 0x08 /* 2 words */ +#define CTI_EE_OFF_XR17C15X_PART_NUM 0x0A /* 4 words */ +#define CTI_EE_OFF_XR17V25X_PART_NUM 0x0E /* 4 words */ +#define CTI_EE_OFF_XR17C15X_SERIAL_NUM 0x0E /* 1 word */ +#define CTI_EE_OFF_XR17V25X_SERIAL_NUM 0x12 /* 1 word */ +#define CTI_EE_OFF_XR17V35X_SERIAL_NUM 0x11 /* 2 word */ +#define CTI_EE_OFF_XR17V35X_BRD_FLAGS 0x13 /* 1 word */ +#define CTI_EE_OFF_XR17V35X_PORT_FLAGS 0x14 /* 1 word */ + +#define CTI_EE_MASK_PORT_FLAGS_TYPE GENMASK(7, 0) +#define CTI_EE_MASK_OSC_FREQ_LOWER GENMASK(15, 0) +#define CTI_EE_MASK_OSC_FREQ_UPPER GENMASK(31, 16) + +#define CTI_FPGA_RS485_IO_REG 0x2008 +#define CTI_FPGA_CFG_INT_EN_REG 0x48 +#define CTI_FPGA_CFG_INT_EN_EXT_BIT BIT(15) /* External int enable bit */ + +#define CTI_DEFAULT_PCI_OSC_FREQ 29491200 +#define CTI_DEFAULT_PCIE_OSC_FREQ 125000000 +#define CTI_DEFAULT_FPGA_OSC_FREQ 33333333 + +/* + * CTI Serial port line types. These match the values stored in the first + * nibble of the CTI EEPROM port_flags word. + */ +enum cti_port_type { + CTI_PORT_TYPE_NONE = 0, + CTI_PORT_TYPE_RS232, // RS232 ONLY + CTI_PORT_TYPE_RS422_485, // RS422/RS485 ONLY + CTI_PORT_TYPE_RS232_422_485_HW, // RS232/422/485 HW ONLY Switchable + CTI_PORT_TYPE_RS232_422_485_SW, // RS232/422/485 SW ONLY Switchable + CTI_PORT_TYPE_RS232_422_485_4B, // RS232/422/485 HW/SW (4bit ex. BCG004) + CTI_PORT_TYPE_RS232_422_485_2B, // RS232/422/485 HW/SW (2bit ex. BBG008) + CTI_PORT_TYPE_MAX, +}; + +#define CTI_PORT_TYPE_VALID(_port_type) \ + (((_port_type) > CTI_PORT_TYPE_NONE) && \ + ((_port_type) < CTI_PORT_TYPE_MAX)) + +#define CTI_PORT_TYPE_RS485(_port_type) \ + (((_port_type) > CTI_PORT_TYPE_RS232) && \ + ((_port_type) < CTI_PORT_TYPE_MAX)) + struct exar8250; struct exar8250_platform { @@ -192,11 +252,201 @@ struct exar8250_board { struct exar8250 { unsigned int nr; + unsigned int osc_freq; struct exar8250_board *board; void __iomem *virt; int line[]; }; +static inline void exar_write_reg(struct exar8250 *priv, + unsigned int reg, u8 value) +{ + writeb(value, priv->virt + reg); +} + +static inline u8 exar_read_reg(struct exar8250 *priv, unsigned int reg) +{ + return readb(priv->virt + reg); +} + +static inline void exar_ee_select(struct exar8250 *priv) +{ + // Set chip select pin high to enable EEPROM reads/writes + exar_write_reg(priv, UART_EXAR_REGB, UART_EXAR_REGB_EECS); + // Min ~500ns delay needed between CS assert and EEPROM access + udelay(1); +} + +static inline void exar_ee_deselect(struct exar8250 *priv) +{ + exar_write_reg(priv, UART_EXAR_REGB, 0x00); +} + +static inline void exar_ee_write_bit(struct exar8250 *priv, int bit) +{ + u8 value = UART_EXAR_REGB_EECS; + + if (bit) + value |= UART_EXAR_REGB_EEDI; + + // Clock out the bit on the EEPROM interface + exar_write_reg(priv, UART_EXAR_REGB, value); + // 2us delay = ~500khz clock speed + udelay(2); + + value |= UART_EXAR_REGB_EECK; + + exar_write_reg(priv, UART_EXAR_REGB, value); + udelay(2); +} + +static inline u8 exar_ee_read_bit(struct exar8250 *priv) +{ + u8 regb; + u8 value = UART_EXAR_REGB_EECS; + + // Clock in the bit on the EEPROM interface + exar_write_reg(priv, UART_EXAR_REGB, value); + // 2us delay = ~500khz clock speed + udelay(2); + + value |= UART_EXAR_REGB_EECK; + + exar_write_reg(priv, UART_EXAR_REGB, value); + udelay(2); + + regb = exar_read_reg(priv, UART_EXAR_REGB); + + return (regb & UART_EXAR_REGB_EEDO ? 1 : 0); +} + +/** + * exar_ee_read() - Read a word from the EEPROM + * @priv: Device's private structure + * @ee_addr: Offset of EEPROM to read word from + * + * Read a single 16bit word from an Exar UART's EEPROM. + * + * Return: EEPROM word + */ +static u16 exar_ee_read(struct exar8250 *priv, u8 ee_addr) +{ + int i; + u16 data = 0; + + exar_ee_select(priv); + + // Send read command (opcode 110) + exar_ee_write_bit(priv, 1); + exar_ee_write_bit(priv, 1); + exar_ee_write_bit(priv, 0); + + // Send address to read from + for (i = 1 << (UART_EXAR_REGB_EE_ADDR_SIZE - 1); i; i >>= 1) + exar_ee_write_bit(priv, (ee_addr & i)); + + // Read data 1 bit at a time + for (i = 0; i <= UART_EXAR_REGB_EE_DATA_SIZE; i++) { + data <<= 1; + data |= exar_ee_read_bit(priv); + } + + exar_ee_deselect(priv); + + return data; +} + +/** + * exar_mpio_config_output() - Configure an Exar MPIO as an output + * @priv: Device's private structure + * @mpio_num: MPIO number/offset to configure + * + * Configure a single MPIO as an output and disable tristate. It is reccomended + * to set the level with exar_mpio_set_high()/exar_mpio_set_low() prior to + * calling this function to ensure default MPIO pin state. + * + * Return: 0 on success, negative error code on failure + */ +static int exar_mpio_config_output(struct exar8250 *priv, + unsigned int mpio_num) +{ + unsigned int mpio_offset; + u8 sel_reg; // MPIO Select register (input/output) + u8 tri_reg; // MPIO Tristate register + u8 value; + + if (mpio_num < 8) { + sel_reg = UART_EXAR_MPIOSEL_7_0; + tri_reg = UART_EXAR_MPIO3T_7_0; + mpio_offset = mpio_num; + } else if (mpio_num >= 8 && mpio_num < 16) { + sel_reg = UART_EXAR_MPIOSEL_15_8; + tri_reg = UART_EXAR_MPIO3T_15_8; + mpio_offset = mpio_num - 8; + } else { + return -EINVAL; + } + + // Disable MPIO pin tri-state + value = exar_read_reg(priv, tri_reg); + value &= ~BIT(mpio_offset); + exar_write_reg(priv, tri_reg, value); + + value = exar_read_reg(priv, sel_reg); + value &= ~BIT(mpio_offset); + exar_write_reg(priv, sel_reg, value); + + return 0; +} + +/** + * _exar_mpio_set() - Set an Exar MPIO output high or low + * @priv: Device's private structure + * @mpio_num: MPIO number/offset to set + * @high: Set MPIO high if true, low if false + * + * Set a single MPIO high or low. exar_mpio_config_output() must also be called + * to configure the pin as an output. + * + * Return: 0 on success, negative error code on failure + */ +static int _exar_mpio_set(struct exar8250 *priv, + unsigned int mpio_num, bool high) +{ + unsigned int mpio_offset; + u8 lvl_reg; + u8 value; + + if (mpio_num < 8) { + lvl_reg = UART_EXAR_MPIOLVL_7_0; + mpio_offset = mpio_num; + } else if (mpio_num >= 8 && mpio_num < 16) { + lvl_reg = UART_EXAR_MPIOLVL_15_8; + mpio_offset = mpio_num - 8; + } else { + return -EINVAL; + } + + value = exar_read_reg(priv, lvl_reg); + if (high) + value |= BIT(mpio_offset); + else + value &= ~BIT(mpio_offset); + exar_write_reg(priv, lvl_reg, value); + + return 0; +} + +static int exar_mpio_set_low(struct exar8250 *priv, unsigned int mpio_num) +{ + return _exar_mpio_set(priv, mpio_num, false); +} + +static int exar_mpio_set_high(struct exar8250 *priv, unsigned int mpio_num) +{ + return _exar_mpio_set(priv, mpio_num, true); +} + static int generic_rs485_config(struct uart_port *port, struct ktermios *termios, struct serial_rs485 *rs485) { @@ -385,6 +635,546 @@ pci_fastcom335_setup(struct exar8250 *priv, struct pci_dev *pcidev, return 0; } +/** + * cti_tristate_disable() - Disable RS485 transciever tristate + * @priv: Device's private structure + * @port_num: Port number to set tristate off + * + * Most RS485 capable cards have a power on tristate jumper/switch that ensures + * the RS422/RS485 transciever does not drive a multi-drop RS485 bus when it is + * not the master. When this jumper is installed the user must set the RS485 + * mode to Full or Half duplex to disable tristate prior to using the port. + * + * Some Exar UARTs have an auto-tristate feature while others require setting + * an MPIO to disable the tristate. + * + * Return: 0 on success, negative error code on failure + */ +static int cti_tristate_disable(struct exar8250 *priv, unsigned int port_num) +{ + int ret; + + ret = exar_mpio_set_high(priv, port_num); + if (ret) + return ret; + + return exar_mpio_config_output(priv, port_num); +} + +/** + * cti_plx_int_enable() - Enable UART interrupts to PLX bridge + * @priv: Device's private structure + * + * Some older CTI cards require MPIO_0 to be set low to enable the + * interupts from the UART to the PLX PCI->PCIe bridge. + * + * Return: 0 on success, negative error code on failure + */ +static int cti_plx_int_enable(struct exar8250 *priv) +{ + int ret; + + ret = exar_mpio_set_low(priv, 0); + if (ret) + return ret; + + return exar_mpio_config_output(priv, 0); +} + +/** + * cti_read_osc_freq() - Read the UART oscillator frequency from EEPROM + * @priv: Device's private structure + * @eeprom_offset: Offset where the oscillator frequency is stored + * + * CTI XR17x15X and XR17V25X cards have the serial boards oscillator frequency + * stored in the EEPROM. FPGA and XR17V35X based cards use the PCI/PCIe clock. + * + * Return: frequency on success, negative error code on failure + */ +static int cti_read_osc_freq(struct exar8250 *priv, u8 eeprom_offset) +{ + u16 lower_word; + u16 upper_word; + int osc_freq; + + lower_word = exar_ee_read(priv, eeprom_offset); + // Check if EEPROM word was blank + if (lower_word == 0xFFFF) + return -EIO; + + upper_word = exar_ee_read(priv, (eeprom_offset + 1)); + if (upper_word == 0xFFFF) + return -EIO; + + osc_freq = FIELD_PREP(CTI_EE_MASK_OSC_FREQ_LOWER, lower_word) | + FIELD_PREP(CTI_EE_MASK_OSC_FREQ_UPPER, upper_word); + + return osc_freq; +} + +/** + * cti_get_port_type_xr17c15x_xr17v25x() - Get port type of xr17c15x/xr17v25x + * @priv: Device's private structure + * @port_num: Port to get type of + * + * CTI xr17c15x and xr17v25x based cards port types are based on PCI IDs. + * + * Return: port type on success, CTI_PORT_TYPE_NONE on failure + */ +static enum cti_port_type cti_get_port_type_xr17c15x_xr17v25x(struct exar8250 *priv, + struct pci_dev *pcidev, + unsigned int port_num) +{ + enum cti_port_type port_type; + + switch (pcidev->subsystem_device) { + // RS232 only cards + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_232: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_232: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_232: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_SP_232: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_SP_232_NS: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_XPRS_LP_232: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_XPRS_LP_232_NS: + port_type = CTI_PORT_TYPE_RS232; + break; + // 1x RS232, 1x RS422/RS485 + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_1_1: + port_type = (port_num == 0) ? + CTI_PORT_TYPE_RS232 : CTI_PORT_TYPE_RS422_485; + break; + // 2x RS232, 2x RS422/RS485 + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_2: + port_type = (port_num < 2) ? + CTI_PORT_TYPE_RS232 : CTI_PORT_TYPE_RS422_485; + break; + // 4x RS232, 4x RS422/RS485 + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_4: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_4_SP: + port_type = (port_num < 4) ? + CTI_PORT_TYPE_RS232 : CTI_PORT_TYPE_RS422_485; + break; + // RS232/RS422/RS485 HW (jumper) selectable + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_SP_OPTO: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_SP_OPTO_A: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_SP_OPTO_B: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_XPRS: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_XPRS_A: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_XPRS_B: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_XPRS: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_16_XPRS_A: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_16_XPRS_B: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_XPRS_OPTO: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_XPRS_OPTO_A: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_XPRS_OPTO_B: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_SP: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_XP_OPTO_LEFT: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_XP_OPTO_RIGHT: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_XP_OPTO: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_4_XPRS_OPTO: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_XPRS_LP: + port_type = CTI_PORT_TYPE_RS232_422_485_HW; + break; + // RS422/RS485 HW (jumper) selectable + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_485: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_485: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_485: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_SP_485: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_XPRS_LP_485: + port_type = CTI_PORT_TYPE_RS422_485; + break; + // 6x RS232, 2x RS422/RS485 + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_6_2_SP: + port_type = (port_num < 6) ? + CTI_PORT_TYPE_RS232 : CTI_PORT_TYPE_RS422_485; + break; + // 2x RS232, 6x RS422/RS485 + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_6_SP: + port_type = (port_num < 2) ? + CTI_PORT_TYPE_RS232 : CTI_PORT_TYPE_RS422_485; + break; + default: + dev_err(&pcidev->dev, "unknown/unsupported device\n"); + port_type = CTI_PORT_TYPE_NONE; + } + + return port_type; +} + +/** + * cti_get_port_type_fpga() - Get the port type of a CTI FPGA card + * @priv: Device's private structure + * @port_num: Port to get type of + * + * FPGA based cards port types are based on PCI IDs. + * + * Return: port type on success, CTI_PORT_TYPE_NONE on failure + */ +static enum cti_port_type cti_get_port_type_fpga(struct exar8250 *priv, + struct pci_dev *pcidev, + unsigned int port_num) +{ + enum cti_port_type port_type; + + switch (pcidev->device) { + case PCI_DEVICE_ID_CONNECT_TECH_PCI_XR79X_12_XIG00X: + case PCI_DEVICE_ID_CONNECT_TECH_PCI_XR79X_12_XIG01X: + case PCI_DEVICE_ID_CONNECT_TECH_PCI_XR79X_16: + port_type = CTI_PORT_TYPE_RS232_422_485_HW; + break; + default: + dev_err(&pcidev->dev, "unknown/unsupported device\n"); + return CTI_PORT_TYPE_NONE; + } + + return port_type; +} + +/** + * cti_get_port_type_xr17v35x() - Read port type from the EEPROM + * @priv: Device's private structure + * @port_num: port offset + * + * CTI XR17V35X based cards have the port types stored in the EEPROM. + * This function reads the port type for a single port. + * + * Return: port type on success, CTI_PORT_TYPE_NONE on failure + */ +static enum cti_port_type cti_get_port_type_xr17v35x(struct exar8250 *priv, + struct pci_dev *pcidev, + unsigned int port_num) +{ + enum cti_port_type port_type; + u16 port_flags; + u8 offset; + + offset = CTI_EE_OFF_XR17V35X_PORT_FLAGS + port_num; + port_flags = exar_ee_read(priv, offset); + + port_type = FIELD_GET(CTI_EE_MASK_PORT_FLAGS_TYPE, port_flags); + if (!CTI_PORT_TYPE_VALID(port_type)) { + /* + * If the port type is missing the card assume it is a + * RS232/RS422/RS485 card to be safe. + * + * There is one known board (BEG013) that only has + * 3 of 4 port types written to the EEPROM so this + * acts as a work around. + */ + dev_warn(&pcidev->dev, + "failed to get port %d type from EEPROM\n", port_num); + port_type = CTI_PORT_TYPE_RS232_422_485_HW; + } + + return port_type; +} + +static int cti_rs485_config_mpio_tristate(struct uart_port *port, + struct ktermios *termios, + struct serial_rs485 *rs485) +{ + struct exar8250 *priv = (struct exar8250 *)port->private_data; + int ret; + + ret = generic_rs485_config(port, termios, rs485); + if (ret) + return ret; + + // Disable power-on RS485 tri-state via MPIO + return cti_tristate_disable(priv, port->port_id); +} + +static int cti_port_setup_common(struct exar8250 *priv, + struct pci_dev *pcidev, + int idx, unsigned int offset, + struct uart_8250_port *port) +{ + int ret; + + if (priv->osc_freq == 0) + return -EINVAL; + + port->port.port_id = idx; + port->port.uartclk = priv->osc_freq; + + ret = serial8250_pci_setup_port(pcidev, port, 0, offset, 0); + if (ret) { + dev_err(&pcidev->dev, + "failed to setup pci for port %d err: %d\n", idx, ret); + return ret; + } + + port->port.private_data = (void *)priv; + port->port.pm = exar_pm; + port->port.shutdown = exar_shutdown; + + return 0; +} + +static int cti_port_setup_fpga(struct exar8250 *priv, + struct pci_dev *pcidev, + struct uart_8250_port *port, + int idx) +{ + enum cti_port_type port_type; + unsigned int offset; + + port_type = cti_get_port_type_fpga(priv, pcidev, idx); + + // FPGA shares port offests with XR17C15X + offset = idx * UART_EXAR_XR17C15X_PORT_OFFSET; + port->port.type = PORT_XR17D15X; + + port->port.get_divisor = xr17v35x_get_divisor; + port->port.set_divisor = xr17v35x_set_divisor; + port->port.startup = xr17v35x_startup; + + if (CTI_PORT_TYPE_RS485(port_type)) { + port->port.rs485_config = generic_rs485_config; + port->port.rs485_supported = generic_rs485_supported; + } + + return cti_port_setup_common(priv, pcidev, idx, offset, port); +} + +static int cti_port_setup_xr17v35x(struct exar8250 *priv, + struct pci_dev *pcidev, + struct uart_8250_port *port, + int idx) +{ + enum cti_port_type port_type; + unsigned int offset; + int ret; + + port_type = cti_get_port_type_xr17v35x(priv, pcidev, idx); + + offset = idx * UART_EXAR_XR17V35X_PORT_OFFSET; + port->port.type = PORT_XR17V35X; + + port->port.get_divisor = xr17v35x_get_divisor; + port->port.set_divisor = xr17v35x_set_divisor; + port->port.startup = xr17v35x_startup; + + switch (port_type) { + case CTI_PORT_TYPE_RS422_485: + case CTI_PORT_TYPE_RS232_422_485_HW: + port->port.rs485_config = cti_rs485_config_mpio_tristate; + port->port.rs485_supported = generic_rs485_supported; + break; + case CTI_PORT_TYPE_RS232_422_485_SW: + case CTI_PORT_TYPE_RS232_422_485_4B: + case CTI_PORT_TYPE_RS232_422_485_2B: + port->port.rs485_config = generic_rs485_config; + port->port.rs485_supported = generic_rs485_supported; + break; + default: + break; + } + + ret = cti_port_setup_common(priv, pcidev, idx, offset, port); + if (ret) + return ret; + + exar_write_reg(priv, (offset + UART_EXAR_8XMODE), 0x00); + exar_write_reg(priv, (offset + UART_EXAR_FCTR), UART_FCTR_EXAR_TRGD); + exar_write_reg(priv, (offset + UART_EXAR_TXTRG), 128); + exar_write_reg(priv, (offset + UART_EXAR_RXTRG), 128); + + return 0; +} + +static int cti_port_setup_xr17v25x(struct exar8250 *priv, + struct pci_dev *pcidev, + struct uart_8250_port *port, + int idx) +{ + enum cti_port_type port_type; + unsigned int offset; + int ret; + + port_type = cti_get_port_type_xr17c15x_xr17v25x(priv, pcidev, idx); + + offset = idx * UART_EXAR_XR17V25X_PORT_OFFSET; + port->port.type = PORT_XR17D15X; + + // XR17V25X supports fractional baudrates + port->port.get_divisor = xr17v35x_get_divisor; + port->port.set_divisor = xr17v35x_set_divisor; + port->port.startup = xr17v35x_startup; + + if (CTI_PORT_TYPE_RS485(port_type)) { + switch (pcidev->subsystem_device) { + // These cards support power on 485 tri-state via MPIO + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_SP: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_SP_485: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_4_SP: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_6_2_SP: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_6_SP: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_XP_OPTO_LEFT: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_XP_OPTO_RIGHT: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_XP_OPTO: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_4_XPRS_OPTO: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_XPRS_LP: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_XPRS_LP_485: + port->port.rs485_config = cti_rs485_config_mpio_tristate; + break; + // Otherwise auto or no power on 485 tri-state support + default: + port->port.rs485_config = generic_rs485_config; + break; + } + + port->port.rs485_supported = generic_rs485_supported; + } + + ret = cti_port_setup_common(priv, pcidev, idx, offset, port); + if (ret) + return ret; + + exar_write_reg(priv, (offset + UART_EXAR_8XMODE), 0x00); + exar_write_reg(priv, (offset + UART_EXAR_FCTR), UART_FCTR_EXAR_TRGD); + exar_write_reg(priv, (offset + UART_EXAR_TXTRG), 32); + exar_write_reg(priv, (offset + UART_EXAR_RXTRG), 32); + + return 0; +} + +static int cti_port_setup_xr17c15x(struct exar8250 *priv, + struct pci_dev *pcidev, + struct uart_8250_port *port, + int idx) +{ + enum cti_port_type port_type; + unsigned int offset; + + port_type = cti_get_port_type_xr17c15x_xr17v25x(priv, pcidev, idx); + + offset = idx * UART_EXAR_XR17C15X_PORT_OFFSET; + port->port.type = PORT_XR17D15X; + + if (CTI_PORT_TYPE_RS485(port_type)) { + switch (pcidev->subsystem_device) { + // These cards support power on 485 tri-state via MPIO + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_SP: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_SP_485: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_4_SP: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_6_2_SP: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_6_SP: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_XP_OPTO_LEFT: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_XP_OPTO_RIGHT: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_XP_OPTO: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_4_XPRS_OPTO: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_XPRS_LP: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_XPRS_LP_485: + port->port.rs485_config = cti_rs485_config_mpio_tristate; + break; + // Otherwise auto or no power on 485 tri-state support + default: + port->port.rs485_config = generic_rs485_config; + break; + } + + port->port.rs485_supported = generic_rs485_supported; + } + + return cti_port_setup_common(priv, pcidev, idx, offset, port); +} + +static int cti_board_init_xr17v35x(struct exar8250 *priv, + struct pci_dev *pcidev) +{ + // XR17V35X uses the PCIe clock rather than an oscillator + priv->osc_freq = CTI_DEFAULT_PCIE_OSC_FREQ; + + return 0; +} + +static int cti_board_init_xr17v25x(struct exar8250 *priv, + struct pci_dev *pcidev) +{ + int osc_freq; + + osc_freq = cti_read_osc_freq(priv, CTI_EE_OFF_XR17V25X_OSC_FREQ); + if (osc_freq < 0) { + dev_warn(&pcidev->dev, + "failed to read osc freq from EEPROM, using default\n"); + osc_freq = CTI_DEFAULT_PCI_OSC_FREQ; + } + + priv->osc_freq = osc_freq; + + /* enable interupts on cards that need the "PLX fix" */ + switch (pcidev->subsystem_device) { + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_XPRS: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_16_XPRS_A: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_16_XPRS_B: + cti_plx_int_enable(priv); + break; + default: + break; + } + + return 0; +} + +static int cti_board_init_xr17c15x(struct exar8250 *priv, + struct pci_dev *pcidev) +{ + int osc_freq; + + osc_freq = cti_read_osc_freq(priv, CTI_EE_OFF_XR17C15X_OSC_FREQ); + if (osc_freq <= 0) { + dev_warn(&pcidev->dev, + "failed to read osc freq from EEPROM, using default\n"); + osc_freq = CTI_DEFAULT_PCI_OSC_FREQ; + } + + priv->osc_freq = osc_freq; + + /* enable interrupts on cards that need the "PLX fix" */ + switch (pcidev->subsystem_device) { + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_XPRS: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_XPRS_A: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_XPRS_B: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_XPRS_OPTO: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_XPRS_OPTO_A: + case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_XPRS_OPTO_B: + cti_plx_int_enable(priv); + break; + default: + break; + } + + return 0; +} + +static int cti_board_init_fpga(struct exar8250 *priv, struct pci_dev *pcidev) +{ + int ret; + u16 cfg_val; + + // FPGA OSC is fixed to the 33MHz PCI clock + priv->osc_freq = CTI_DEFAULT_FPGA_OSC_FREQ; + + // Enable external interrupts in special cfg space register + ret = pci_read_config_word(pcidev, CTI_FPGA_CFG_INT_EN_REG, &cfg_val); + if (ret) + return ret; + + cfg_val |= CTI_FPGA_CFG_INT_EN_EXT_BIT; + ret = pci_write_config_word(pcidev, CTI_FPGA_CFG_INT_EN_REG, cfg_val); + if (ret) + return ret; + + // RS485 gate needs to be enabled; otherwise RTS/CTS will not work + exar_write_reg(priv, CTI_FPGA_RS485_IO_REG, 0x01); + + return 0; +} + static int pci_xr17c154_setup(struct exar8250 *priv, struct pci_dev *pcidev, struct uart_8250_port *port, int idx) @@ -880,6 +1670,26 @@ static const struct exar8250_board pbn_fastcom335_8 = { .setup = pci_fastcom335_setup, }; +static const struct exar8250_board pbn_cti_xr17c15x = { + .board_init = cti_board_init_xr17c15x, + .setup = cti_port_setup_xr17c15x, +}; + +static const struct exar8250_board pbn_cti_xr17v25x = { + .board_init = cti_board_init_xr17v25x, + .setup = cti_port_setup_xr17v25x, +}; + +static const struct exar8250_board pbn_cti_xr17v35x = { + .board_init = cti_board_init_xr17v35x, + .setup = cti_port_setup_xr17v35x, +}; + +static const struct exar8250_board pbn_cti_fpga = { + .board_init = cti_board_init_fpga, + .setup = cti_port_setup_fpga, +}; + static const struct exar8250_board pbn_exar_ibm_saturn = { .num_ports = 1, .setup = pci_xr17c154_setup, @@ -924,6 +1734,26 @@ static const struct exar8250_board pbn_exar_XR17V8358 = { .exit = pci_xr17v35x_exit, }; +// For Connect Tech cards with Exar vendor/device PCI IDs +#define CTI_EXAR_DEVICE(devid, bd) { \ + PCI_DEVICE_SUB( \ + PCI_VENDOR_ID_EXAR, \ + PCI_DEVICE_ID_EXAR_##devid, \ + PCI_SUBVENDOR_ID_CONNECT_TECH, \ + PCI_ANY_ID), 0, 0, \ + (kernel_ulong_t)&bd \ + } + +// For Connect Tech cards with Connect Tech vendor/device PCI IDs (FPGA based) +#define CTI_PCI_DEVICE(devid, bd) { \ + PCI_DEVICE_SUB( \ + PCI_VENDOR_ID_CONNECT_TECH, \ + PCI_DEVICE_ID_CONNECT_TECH_PCI_##devid, \ + PCI_ANY_ID, \ + PCI_ANY_ID), 0, 0, \ + (kernel_ulong_t)&bd \ + } + #define EXAR_DEVICE(vend, devid, bd) { PCI_DEVICE_DATA(vend, devid, &bd) } #define IBM_DEVICE(devid, sdevid, bd) { \ @@ -953,6 +1783,22 @@ static const struct pci_device_id exar_pci_tbl[] = { EXAR_DEVICE(ACCESSIO, COM_4SM, pbn_exar_XR17C15x), EXAR_DEVICE(ACCESSIO, COM_8SM, pbn_exar_XR17C15x), + CTI_EXAR_DEVICE(XR17C152, pbn_cti_xr17c15x), + CTI_EXAR_DEVICE(XR17C154, pbn_cti_xr17c15x), + CTI_EXAR_DEVICE(XR17C158, pbn_cti_xr17c15x), + + CTI_EXAR_DEVICE(XR17V252, pbn_cti_xr17v25x), + CTI_EXAR_DEVICE(XR17V254, pbn_cti_xr17v25x), + CTI_EXAR_DEVICE(XR17V258, pbn_cti_xr17v25x), + + CTI_EXAR_DEVICE(XR17V352, pbn_cti_xr17v35x), + CTI_EXAR_DEVICE(XR17V354, pbn_cti_xr17v35x), + CTI_EXAR_DEVICE(XR17V358, pbn_cti_xr17v35x), + + CTI_PCI_DEVICE(XR79X_12_XIG00X, pbn_cti_fpga), + CTI_PCI_DEVICE(XR79X_12_XIG01X, pbn_cti_fpga), + CTI_PCI_DEVICE(XR79X_16, pbn_cti_fpga), + IBM_DEVICE(XR17C152, SATURN_SERIAL_ONE_PORT, pbn_exar_ibm_saturn), /* USRobotics USR298x-OEM PCI Modems */ -- cgit v1.2.3-59-g8ed1b From c6795fbffc4547b40933ec368200bd4926a41b44 Mon Sep 17 00:00:00 2001 From: Parker Newman Date: Wed, 17 Apr 2024 16:31:29 -0400 Subject: serial: exar: fix checkpach warnings -Fix several "missing identifier name" warnings from checkpatch in struct exar8250_platform and struct exar8250_board. Example: WARNING: function definition argument should also have an identifier name - Fix space before tab warning from checkpatch: WARNING: please, no space before tabs + * 0^I^I2 ^IMode bit 0$ Signed-off-by: Parker Newman Link: https://lore.kernel.org/r/f7fa6c16cb5f2c8c1c7cb7d29f80bc7be53f91ab.1713382717.git.pnewman@connecttech.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_exar.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c index 6985aabe13cc..5e42558cbb01 100644 --- a/drivers/tty/serial/8250/8250_exar.c +++ b/drivers/tty/serial/8250/8250_exar.c @@ -147,7 +147,7 @@ * * MPIO Port Function * ---- ---- -------- - * 0 2 Mode bit 0 + * 0 2 Mode bit 0 * 1 2 Mode bit 1 * 2 2 Terminate bus * 3 - @@ -229,8 +229,8 @@ struct exar8250_platform { int (*rs485_config)(struct uart_port *port, struct ktermios *termios, struct serial_rs485 *rs485); const struct serial_rs485 *rs485_supported; - int (*register_gpio)(struct pci_dev *, struct uart_8250_port *); - void (*unregister_gpio)(struct uart_8250_port *); + int (*register_gpio)(struct pci_dev *pcidev, struct uart_8250_port *port); + void (*unregister_gpio)(struct uart_8250_port *port); }; /** @@ -245,8 +245,8 @@ struct exar8250_board { unsigned int num_ports; unsigned int reg_shift; int (*board_init)(struct exar8250 *priv, struct pci_dev *pcidev); - int (*setup)(struct exar8250 *, struct pci_dev *, - struct uart_8250_port *, int); + int (*setup)(struct exar8250 *priv, struct pci_dev *pcidev, + struct uart_8250_port *port, int idx); void (*exit)(struct pci_dev *pcidev); }; -- cgit v1.2.3-59-g8ed1b From 920e7522e3bab5ebc2fb0cc1a034f4470c87fa97 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sun, 14 Apr 2024 17:10:32 +0200 Subject: usb: gadget: function: Remove usage of the deprecated ida_simple_xx() API ida_alloc() and ida_free() should be preferred to the deprecated ida_simple_get() and ida_simple_remove(). Note that the upper limit of ida_simple_get() is exclusive, but the one of ida_alloc_max() is inclusive. So a -1 has been added when needed. Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/7cd361e2b377a5373968fa7deee4169229992a1e.1713107386.git.christophe.jaillet@wanadoo.fr Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/function/f_hid.c | 6 +++--- drivers/usb/gadget/function/f_printer.c | 6 +++--- drivers/usb/gadget/function/rndis.c | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c index 3c8a9dd585c0..2db01e03bfbf 100644 --- a/drivers/usb/gadget/function/f_hid.c +++ b/drivers/usb/gadget/function/f_hid.c @@ -1029,9 +1029,9 @@ static inline int hidg_get_minor(void) { int ret; - ret = ida_simple_get(&hidg_ida, 0, 0, GFP_KERNEL); + ret = ida_alloc(&hidg_ida, GFP_KERNEL); if (ret >= HIDG_MINORS) { - ida_simple_remove(&hidg_ida, ret); + ida_free(&hidg_ida, ret); ret = -ENODEV; } @@ -1176,7 +1176,7 @@ static const struct config_item_type hid_func_type = { static inline void hidg_put_minor(int minor) { - ida_simple_remove(&hidg_ida, minor); + ida_free(&hidg_ida, minor); } static void hidg_free_inst(struct usb_function_instance *f) diff --git a/drivers/usb/gadget/function/f_printer.c b/drivers/usb/gadget/function/f_printer.c index 076dd4c1be96..ba7d180cc9e6 100644 --- a/drivers/usb/gadget/function/f_printer.c +++ b/drivers/usb/gadget/function/f_printer.c @@ -1312,9 +1312,9 @@ static inline int gprinter_get_minor(void) { int ret; - ret = ida_simple_get(&printer_ida, 0, 0, GFP_KERNEL); + ret = ida_alloc(&printer_ida, GFP_KERNEL); if (ret >= PRINTER_MINORS) { - ida_simple_remove(&printer_ida, ret); + ida_free(&printer_ida, ret); ret = -ENODEV; } @@ -1323,7 +1323,7 @@ static inline int gprinter_get_minor(void) static inline void gprinter_put_minor(int minor) { - ida_simple_remove(&printer_ida, minor); + ida_free(&printer_ida, minor); } static int gprinter_setup(int); diff --git a/drivers/usb/gadget/function/rndis.c b/drivers/usb/gadget/function/rndis.c index 29bf8664bf58..12c5d9cf450c 100644 --- a/drivers/usb/gadget/function/rndis.c +++ b/drivers/usb/gadget/function/rndis.c @@ -869,12 +869,12 @@ EXPORT_SYMBOL_GPL(rndis_msg_parser); static inline int rndis_get_nr(void) { - return ida_simple_get(&rndis_ida, 0, 1000, GFP_KERNEL); + return ida_alloc_max(&rndis_ida, 999, GFP_KERNEL); } static inline void rndis_put_nr(int nr) { - ida_simple_remove(&rndis_ida, nr); + ida_free(&rndis_ida, nr); } struct rndis_params *rndis_register(void (*resp_avail)(void *v), void *v) -- cgit v1.2.3-59-g8ed1b From a7f3813e589fd8e2834720829a47b5eb914a9afe Mon Sep 17 00:00:00 2001 From: Marcello Sylvester Bauer Date: Thu, 11 Apr 2024 16:51:28 +0200 Subject: usb: gadget: dummy_hcd: Switch to hrtimer transfer scheduler The dummy_hcd transfer scheduler assumes that the internal kernel timer frequency is set to 1000Hz to give a polling interval of 1ms. Reducing the timer frequency will result in an anti-proportional reduction in transfer performance. Switch to a hrtimer to decouple this association. Signed-off-by: Marcello Sylvester Bauer Signed-off-by: Marcello Sylvester Bauer Reviewed-by: Alan Stern Link: https://lore.kernel.org/r/57a1c2180ff74661600e010c234d1dbaba1d0d46.1712843963.git.sylv@sylv.io Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/udc/dummy_hcd.c | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c index 0953e1b5c030..dab559d8ee8c 100644 --- a/drivers/usb/gadget/udc/dummy_hcd.c +++ b/drivers/usb/gadget/udc/dummy_hcd.c @@ -30,7 +30,7 @@ #include #include #include -#include +#include #include #include #include @@ -240,7 +240,7 @@ enum dummy_rh_state { struct dummy_hcd { struct dummy *dum; enum dummy_rh_state rh_state; - struct timer_list timer; + struct hrtimer timer; u32 port_status; u32 old_status; unsigned long re_timeout; @@ -1301,8 +1301,8 @@ static int dummy_urb_enqueue( urb->error_count = 1; /* mark as a new urb */ /* kick the scheduler, it'll do the rest */ - if (!timer_pending(&dum_hcd->timer)) - mod_timer(&dum_hcd->timer, jiffies + 1); + if (!hrtimer_active(&dum_hcd->timer)) + hrtimer_start(&dum_hcd->timer, ms_to_ktime(1), HRTIMER_MODE_REL); done: spin_unlock_irqrestore(&dum_hcd->dum->lock, flags); @@ -1323,7 +1323,7 @@ static int dummy_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) rc = usb_hcd_check_unlink_urb(hcd, urb, status); if (!rc && dum_hcd->rh_state != DUMMY_RH_RUNNING && !list_empty(&dum_hcd->urbp_list)) - mod_timer(&dum_hcd->timer, jiffies); + hrtimer_start(&dum_hcd->timer, ns_to_ktime(0), HRTIMER_MODE_REL); spin_unlock_irqrestore(&dum_hcd->dum->lock, flags); return rc; @@ -1777,7 +1777,7 @@ static int handle_control_request(struct dummy_hcd *dum_hcd, struct urb *urb, * drivers except that the callbacks are invoked from soft interrupt * context. */ -static void dummy_timer(struct timer_list *t) +static enum hrtimer_restart dummy_timer(struct hrtimer *t) { struct dummy_hcd *dum_hcd = from_timer(dum_hcd, t, timer); struct dummy *dum = dum_hcd->dum; @@ -1808,8 +1808,6 @@ static void dummy_timer(struct timer_list *t) break; } - /* FIXME if HZ != 1000 this will probably misbehave ... */ - /* look at each urb queued by the host side driver */ spin_lock_irqsave(&dum->lock, flags); @@ -1817,7 +1815,7 @@ static void dummy_timer(struct timer_list *t) dev_err(dummy_dev(dum_hcd), "timer fired with no URBs pending?\n"); spin_unlock_irqrestore(&dum->lock, flags); - return; + return HRTIMER_NORESTART; } dum_hcd->next_frame_urbp = NULL; @@ -1995,10 +1993,12 @@ return_urb: dum_hcd->udev = NULL; } else if (dum_hcd->rh_state == DUMMY_RH_RUNNING) { /* want a 1 msec delay here */ - mod_timer(&dum_hcd->timer, jiffies + msecs_to_jiffies(1)); + hrtimer_start(&dum_hcd->timer, ms_to_ktime(1), HRTIMER_MODE_REL); } spin_unlock_irqrestore(&dum->lock, flags); + + return HRTIMER_NORESTART; } /*-------------------------------------------------------------------------*/ @@ -2387,7 +2387,7 @@ static int dummy_bus_resume(struct usb_hcd *hcd) dum_hcd->rh_state = DUMMY_RH_RUNNING; set_link_state(dum_hcd); if (!list_empty(&dum_hcd->urbp_list)) - mod_timer(&dum_hcd->timer, jiffies); + hrtimer_start(&dum_hcd->timer, ns_to_ktime(0), HRTIMER_MODE_REL); hcd->state = HC_STATE_RUNNING; } spin_unlock_irq(&dum_hcd->dum->lock); @@ -2465,7 +2465,8 @@ static DEVICE_ATTR_RO(urbs); static int dummy_start_ss(struct dummy_hcd *dum_hcd) { - timer_setup(&dum_hcd->timer, dummy_timer, 0); + hrtimer_init(&dum_hcd->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + dum_hcd->timer.function = dummy_timer; dum_hcd->rh_state = DUMMY_RH_RUNNING; dum_hcd->stream_en_ep = 0; INIT_LIST_HEAD(&dum_hcd->urbp_list); @@ -2494,7 +2495,8 @@ static int dummy_start(struct usb_hcd *hcd) return dummy_start_ss(dum_hcd); spin_lock_init(&dum_hcd->dum->lock); - timer_setup(&dum_hcd->timer, dummy_timer, 0); + hrtimer_init(&dum_hcd->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + dum_hcd->timer.function = dummy_timer; dum_hcd->rh_state = DUMMY_RH_RUNNING; INIT_LIST_HEAD(&dum_hcd->urbp_list); @@ -2513,8 +2515,11 @@ static int dummy_start(struct usb_hcd *hcd) static void dummy_stop(struct usb_hcd *hcd) { - device_remove_file(dummy_dev(hcd_to_dummy_hcd(hcd)), &dev_attr_urbs); - dev_info(dummy_dev(hcd_to_dummy_hcd(hcd)), "stopped\n"); + struct dummy_hcd *dum_hcd = hcd_to_dummy_hcd(hcd); + + hrtimer_cancel(&dum_hcd->timer); + device_remove_file(dummy_dev(dum_hcd), &dev_attr_urbs); + dev_info(dummy_dev(dum_hcd), "stopped\n"); } /*-------------------------------------------------------------------------*/ -- cgit v1.2.3-59-g8ed1b From 0a723ed3baa941ca4f51d87bab00661f41142835 Mon Sep 17 00:00:00 2001 From: Marcello Sylvester Bauer Date: Thu, 11 Apr 2024 17:22:11 +0200 Subject: usb: gadget: dummy_hcd: Set transfer interval to 1 microframe Currently, the transfer polling interval is set to 1ms, which is the frame rate of full-speed and low-speed USB. The USB 2.0 specification introduces microframes (125 microseconds) to improve the timing precision of data transfers. Reducing the transfer interval to 1 microframe increases data throughput for high-speed and super-speed USB communication Signed-off-by: Marcello Sylvester Bauer Signed-off-by: Marcello Sylvester Bauer Link: https://lore.kernel.org/r/6295dbb84ca76884551df9eb157cce569377a22c.1712843963.git.sylv@sylv.io Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/udc/dummy_hcd.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c index dab559d8ee8c..f37b0d8386c1 100644 --- a/drivers/usb/gadget/udc/dummy_hcd.c +++ b/drivers/usb/gadget/udc/dummy_hcd.c @@ -50,6 +50,8 @@ #define POWER_BUDGET 500 /* in mA; use 8 for low-power port testing */ #define POWER_BUDGET_3 900 /* in mA */ +#define DUMMY_TIMER_INT_NSECS 125000 /* 1 microframe */ + static const char driver_name[] = "dummy_hcd"; static const char driver_desc[] = "USB Host+Gadget Emulator"; @@ -1302,7 +1304,7 @@ static int dummy_urb_enqueue( /* kick the scheduler, it'll do the rest */ if (!hrtimer_active(&dum_hcd->timer)) - hrtimer_start(&dum_hcd->timer, ms_to_ktime(1), HRTIMER_MODE_REL); + hrtimer_start(&dum_hcd->timer, ns_to_ktime(DUMMY_TIMER_INT_NSECS), HRTIMER_MODE_REL); done: spin_unlock_irqrestore(&dum_hcd->dum->lock, flags); @@ -1993,7 +1995,7 @@ return_urb: dum_hcd->udev = NULL; } else if (dum_hcd->rh_state == DUMMY_RH_RUNNING) { /* want a 1 msec delay here */ - hrtimer_start(&dum_hcd->timer, ms_to_ktime(1), HRTIMER_MODE_REL); + hrtimer_start(&dum_hcd->timer, ns_to_ktime(DUMMY_TIMER_INT_NSECS), HRTIMER_MODE_REL); } spin_unlock_irqrestore(&dum->lock, flags); -- cgit v1.2.3-59-g8ed1b From 24bce22d09ec8e67022aab9a888acb56fb7a996a Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Thu, 11 Apr 2024 07:49:53 +0300 Subject: usb: typec: ucsi: add callback for connector status updates Allow UCSI glue driver to perform addtional work to update connector status. For example, it might check the cable orientation. This call is performed after reading new connector statatus, so the platform driver can peek at new connection status bits. The callback is called both when registering the port and when the connector change event is being handled. Signed-off-by: Dmitry Baryshkov Reviewed-by: Heikki Krogerus Link: https://lore.kernel.org/r/20240411-ucsi-orient-aware-v2-1-d4b1cb22a33f@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/ucsi/ucsi.c | 6 ++++++ drivers/usb/typec/ucsi/ucsi.h | 3 +++ 2 files changed, 9 insertions(+) diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c index 36e1b191f87d..4d8910992a57 100644 --- a/drivers/usb/typec/ucsi/ucsi.c +++ b/drivers/usb/typec/ucsi/ucsi.c @@ -1199,6 +1199,9 @@ static void ucsi_handle_connector_change(struct work_struct *work) trace_ucsi_connector_change(con->num, &con->status); + if (ucsi->ops->connector_status) + ucsi->ops->connector_status(con); + role = !!(con->status.flags & UCSI_CONSTAT_PWR_DIR); if (con->status.change & UCSI_CONSTAT_POWER_DIR_CHANGE) { @@ -1590,6 +1593,9 @@ static int ucsi_register_port(struct ucsi *ucsi, struct ucsi_connector *con) } ret = 0; /* ucsi_send_command() returns length on success */ + if (ucsi->ops->connector_status) + ucsi->ops->connector_status(con); + switch (UCSI_CONSTAT_PARTNER_TYPE(con->status.flags)) { case UCSI_CONSTAT_PARTNER_TYPE_UFP: case UCSI_CONSTAT_PARTNER_TYPE_CABLE_AND_UFP: diff --git a/drivers/usb/typec/ucsi/ucsi.h b/drivers/usb/typec/ucsi/ucsi.h index 2caf2969668c..3e1241e38f3c 100644 --- a/drivers/usb/typec/ucsi/ucsi.h +++ b/drivers/usb/typec/ucsi/ucsi.h @@ -16,6 +16,7 @@ struct ucsi; struct ucsi_altmode; +struct ucsi_connector; struct dentry; /* UCSI offsets (Bytes) */ @@ -59,6 +60,7 @@ struct dentry; * @sync_write: Blocking write operation * @async_write: Non-blocking write operation * @update_altmodes: Squashes duplicate DP altmodes + * @connector_status: Updates connector status, called holding connector lock * * Read and write routines for UCSI interface. @sync_write must wait for the * Command Completion Event from the PPM before returning, and @async_write must @@ -73,6 +75,7 @@ struct ucsi_operations { const void *val, size_t val_len); bool (*update_altmodes)(struct ucsi *ucsi, struct ucsi_altmode *orig, struct ucsi_altmode *updated); + void (*connector_status)(struct ucsi_connector *con); }; struct ucsi *ucsi_create(struct device *dev, const struct ucsi_operations *ops); -- cgit v1.2.3-59-g8ed1b From 76716fd5bf09725c2c6825264147f16c21e56853 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Thu, 11 Apr 2024 07:49:54 +0300 Subject: usb: typec: ucsi: glink: move GPIO reading into connector_status callback To simplify the platform code move Type-C orientation handling into the connector_status callback. As it is called both during connector registration and on connector change events, duplicated code from pmic_glink_ucsi_register() can be dropped. Also this moves operations that can sleep into a worker thread, removing the only sleeping operation from pmic_glink_ucsi_notify(). Tested-by: Krishna Kurapati Signed-off-by: Dmitry Baryshkov Reviewed-by: Heikki Krogerus Link: https://lore.kernel.org/r/20240411-ucsi-orient-aware-v2-2-d4b1cb22a33f@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/ucsi/ucsi_glink.c | 48 ++++++++++++++++--------------------- 1 file changed, 20 insertions(+), 28 deletions(-) diff --git a/drivers/usb/typec/ucsi/ucsi_glink.c b/drivers/usb/typec/ucsi/ucsi_glink.c index b91d2d15d7d9..d21f8cd2fe35 100644 --- a/drivers/usb/typec/ucsi/ucsi_glink.c +++ b/drivers/usb/typec/ucsi/ucsi_glink.c @@ -187,10 +187,28 @@ static int pmic_glink_ucsi_sync_write(struct ucsi *__ucsi, unsigned int offset, return ret; } +static void pmic_glink_ucsi_connector_status(struct ucsi_connector *con) +{ + struct pmic_glink_ucsi *ucsi = ucsi_get_drvdata(con->ucsi); + int orientation; + + if (con->num >= PMIC_GLINK_MAX_PORTS || + !ucsi->port_orientation[con->num - 1]) + return; + + orientation = gpiod_get_value(ucsi->port_orientation[con->num - 1]); + if (orientation >= 0) { + typec_switch_set(ucsi->port_switch[con->num - 1], + orientation ? TYPEC_ORIENTATION_REVERSE + : TYPEC_ORIENTATION_NORMAL); + } +} + static const struct ucsi_operations pmic_glink_ucsi_ops = { .read = pmic_glink_ucsi_read, .sync_write = pmic_glink_ucsi_sync_write, - .async_write = pmic_glink_ucsi_async_write + .async_write = pmic_glink_ucsi_async_write, + .connector_status = pmic_glink_ucsi_connector_status, }; static void pmic_glink_ucsi_read_ack(struct pmic_glink_ucsi *ucsi, const void *data, int len) @@ -229,20 +247,8 @@ static void pmic_glink_ucsi_notify(struct work_struct *work) } con_num = UCSI_CCI_CONNECTOR(cci); - if (con_num) { - if (con_num <= PMIC_GLINK_MAX_PORTS && - ucsi->port_orientation[con_num - 1]) { - int orientation = gpiod_get_value(ucsi->port_orientation[con_num - 1]); - - if (orientation >= 0) { - typec_switch_set(ucsi->port_switch[con_num - 1], - orientation ? TYPEC_ORIENTATION_REVERSE - : TYPEC_ORIENTATION_NORMAL); - } - } - + if (con_num) ucsi_connector_change(ucsi->ucsi, con_num); - } if (ucsi->sync_pending && (cci & (UCSI_CCI_ACK_COMPLETE | UCSI_CCI_COMMAND_COMPLETE))) { @@ -253,20 +259,6 @@ static void pmic_glink_ucsi_notify(struct work_struct *work) static void pmic_glink_ucsi_register(struct work_struct *work) { struct pmic_glink_ucsi *ucsi = container_of(work, struct pmic_glink_ucsi, register_work); - int orientation; - int i; - - for (i = 0; i < PMIC_GLINK_MAX_PORTS; i++) { - if (!ucsi->port_orientation[i]) - continue; - orientation = gpiod_get_value(ucsi->port_orientation[i]); - - if (orientation >= 0) { - typec_switch_set(ucsi->port_switch[i], - orientation ? TYPEC_ORIENTATION_REVERSE - : TYPEC_ORIENTATION_NORMAL); - } - } ucsi_register(ucsi->ucsi); } -- cgit v1.2.3-59-g8ed1b From 2fb5ea6b67818300823c2ccf3fbe846d86d30724 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Thu, 11 Apr 2024 07:49:55 +0300 Subject: usb: typec: ucsi: glink: use typec_set_orientation Use typec_set_orientation() instead of calling typec_switch_set() manually. This way the rest of the typec framework and the userspace are notified about the orientation change. Signed-off-by: Dmitry Baryshkov Reviewed-by: Heikki Krogerus Link: https://lore.kernel.org/r/20240411-ucsi-orient-aware-v2-3-d4b1cb22a33f@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/ucsi/ucsi_glink.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/drivers/usb/typec/ucsi/ucsi_glink.c b/drivers/usb/typec/ucsi/ucsi_glink.c index d21f8cd2fe35..d279e2cf9bba 100644 --- a/drivers/usb/typec/ucsi/ucsi_glink.c +++ b/drivers/usb/typec/ucsi/ucsi_glink.c @@ -58,7 +58,6 @@ struct pmic_glink_ucsi { struct device *dev; struct gpio_desc *port_orientation[PMIC_GLINK_MAX_PORTS]; - struct typec_switch *port_switch[PMIC_GLINK_MAX_PORTS]; struct pmic_glink_client *client; @@ -198,9 +197,10 @@ static void pmic_glink_ucsi_connector_status(struct ucsi_connector *con) orientation = gpiod_get_value(ucsi->port_orientation[con->num - 1]); if (orientation >= 0) { - typec_switch_set(ucsi->port_switch[con->num - 1], - orientation ? TYPEC_ORIENTATION_REVERSE - : TYPEC_ORIENTATION_NORMAL); + typec_set_orientation(con->port, + orientation ? + TYPEC_ORIENTATION_REVERSE : + TYPEC_ORIENTATION_NORMAL); } } @@ -378,11 +378,6 @@ static int pmic_glink_ucsi_probe(struct auxiliary_device *adev, return dev_err_probe(dev, PTR_ERR(desc), "unable to acquire orientation gpio\n"); ucsi->port_orientation[port] = desc; - - ucsi->port_switch[port] = fwnode_typec_switch_get(fwnode); - if (IS_ERR(ucsi->port_switch[port])) - return dev_err_probe(dev, PTR_ERR(ucsi->port_switch[port]), - "failed to acquire orientation-switch\n"); } ucsi->client = devm_pmic_glink_register_client(dev, -- cgit v1.2.3-59-g8ed1b From 62866465196228917f233aea68de73be6cdb9fae Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Thu, 11 Apr 2024 07:49:56 +0300 Subject: usb: typec: ucsi: add update_connector callback Add a callback to allow glue drivers to update the connector before registering corresponding power supply and Type-C port. In particular this is useful if glue drivers want to touch the connector's Type-C capabilities structure. Signed-off-by: Dmitry Baryshkov Reviewed-by: Heikki Krogerus Link: https://lore.kernel.org/r/20240411-ucsi-orient-aware-v2-4-d4b1cb22a33f@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/ucsi/ucsi.c | 3 +++ drivers/usb/typec/ucsi/ucsi.h | 2 ++ 2 files changed, 5 insertions(+) diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c index 4d8910992a57..b8d56a443531 100644 --- a/drivers/usb/typec/ucsi/ucsi.c +++ b/drivers/usb/typec/ucsi/ucsi.c @@ -1561,6 +1561,9 @@ static int ucsi_register_port(struct ucsi *ucsi, struct ucsi_connector *con) cap->driver_data = con; cap->ops = &ucsi_ops; + if (ucsi->ops->update_connector) + ucsi->ops->update_connector(con); + ret = ucsi_register_port_psy(con); if (ret) goto out; diff --git a/drivers/usb/typec/ucsi/ucsi.h b/drivers/usb/typec/ucsi/ucsi.h index 3e1241e38f3c..c4d103db9d0f 100644 --- a/drivers/usb/typec/ucsi/ucsi.h +++ b/drivers/usb/typec/ucsi/ucsi.h @@ -60,6 +60,7 @@ struct dentry; * @sync_write: Blocking write operation * @async_write: Non-blocking write operation * @update_altmodes: Squashes duplicate DP altmodes + * @update_connector: Update connector capabilities before registering * @connector_status: Updates connector status, called holding connector lock * * Read and write routines for UCSI interface. @sync_write must wait for the @@ -75,6 +76,7 @@ struct ucsi_operations { const void *val, size_t val_len); bool (*update_altmodes)(struct ucsi *ucsi, struct ucsi_altmode *orig, struct ucsi_altmode *updated); + void (*update_connector)(struct ucsi_connector *con); void (*connector_status)(struct ucsi_connector *con); }; -- cgit v1.2.3-59-g8ed1b From 3d1b6c9d47707d6a0f80bb5db6473b1f107b5baf Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Thu, 11 Apr 2024 07:49:57 +0300 Subject: usb: typec: ucsi: glink: set orientation aware if supported If the PMIC-GLINK device has orientation GPIOs declared, then it will report connection orientation. In this case set the flag to mark registered ports as orientation-aware. Signed-off-by: Dmitry Baryshkov Reviewed-by: Heikki Krogerus Link: https://lore.kernel.org/r/20240411-ucsi-orient-aware-v2-5-d4b1cb22a33f@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/ucsi/ucsi_glink.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/usb/typec/ucsi/ucsi_glink.c b/drivers/usb/typec/ucsi/ucsi_glink.c index d279e2cf9bba..f7546bb488c3 100644 --- a/drivers/usb/typec/ucsi/ucsi_glink.c +++ b/drivers/usb/typec/ucsi/ucsi_glink.c @@ -186,6 +186,17 @@ static int pmic_glink_ucsi_sync_write(struct ucsi *__ucsi, unsigned int offset, return ret; } +static void pmic_glink_ucsi_update_connector(struct ucsi_connector *con) +{ + struct pmic_glink_ucsi *ucsi = ucsi_get_drvdata(con->ucsi); + int i; + + for (i = 0; i < PMIC_GLINK_MAX_PORTS; i++) { + if (ucsi->port_orientation[i]) + con->typec_cap.orientation_aware = true; + } +} + static void pmic_glink_ucsi_connector_status(struct ucsi_connector *con) { struct pmic_glink_ucsi *ucsi = ucsi_get_drvdata(con->ucsi); @@ -208,6 +219,7 @@ static const struct ucsi_operations pmic_glink_ucsi_ops = { .read = pmic_glink_ucsi_read, .sync_write = pmic_glink_ucsi_sync_write, .async_write = pmic_glink_ucsi_async_write, + .update_connector = pmic_glink_ucsi_update_connector, .connector_status = pmic_glink_ucsi_connector_status, }; -- cgit v1.2.3-59-g8ed1b From 606c096adc7995fcfc707210e4e051717eb0b3c1 Mon Sep 17 00:00:00 2001 From: Thinh Nguyen Date: Tue, 16 Apr 2024 23:11:20 +0000 Subject: usb: dwc3: Select 2.0 or 3.0 clk base on maximum_speed The dwc->maximum_speed is determined through the device capability and designer's constraint through device tree binding. If none of them applies, don't let the default coreConsultant setting in GUCTL1 to limit the device operating speed. Normally the default setting will not contradict the device capability or device tree binding. This scenario was found through our internal tests, not an actual bug in the wild. Signed-off-by: Thinh Nguyen Link: https://lore.kernel.org/r/65003b0cc37c08a0d22996009f548247ad18c00c.1713308949.git.Thinh.Nguyen@synopsys.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/core.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 31684cdaaae3..637194af506f 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -1320,10 +1320,13 @@ static int dwc3_core_init(struct dwc3 *dwc) if (dwc->parkmode_disable_hs_quirk) reg |= DWC3_GUCTL1_PARKMODE_DISABLE_HS; - if (DWC3_VER_IS_WITHIN(DWC3, 290A, ANY) && - (dwc->maximum_speed == USB_SPEED_HIGH || - dwc->maximum_speed == USB_SPEED_FULL)) - reg |= DWC3_GUCTL1_DEV_FORCE_20_CLK_FOR_30_CLK; + if (DWC3_VER_IS_WITHIN(DWC3, 290A, ANY)) { + if (dwc->maximum_speed == USB_SPEED_FULL || + dwc->maximum_speed == USB_SPEED_HIGH) + reg |= DWC3_GUCTL1_DEV_FORCE_20_CLK_FOR_30_CLK; + else + reg &= ~DWC3_GUCTL1_DEV_FORCE_20_CLK_FOR_30_CLK; + } dwc3_writel(dwc->regs, DWC3_GUCTL1, reg); } -- cgit v1.2.3-59-g8ed1b From bd2cd796d2859c1a7cee326d7a9c0f77c6b95c71 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 16 Apr 2024 17:53:45 +0200 Subject: usb: renesas_usbhs: Remove renesas_usbhs_get_info() wrapper The renesas_usbhs_get_info() wrapper was useful for legacy board code. Since commit 1fa59bda21c7fa36 ("ARM: shmobile: Remove legacy board code for Armadillo-800 EVA") in v4.3, it is no longer used outside the USBHS driver, and provides no added value over dev_get_platdata(), while obfuscating the real operation. Drop it, and replace it by dev_get_platdata() in its sole user. Signed-off-by: Geert Uytterhoeven Reviewed-by: Biju Das Reviewed-by: Yoshihiro Shimoda Link: https://lore.kernel.org/r/fa296af4452dfe394a58b75fd44c3bb9591936eb.1713282736.git.geert+renesas@glider.be Signed-off-by: Greg Kroah-Hartman --- drivers/usb/renesas_usbhs/common.c | 2 +- include/linux/usb/renesas_usbhs.h | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c index b6bef9081bf2..edc43f169d49 100644 --- a/drivers/usb/renesas_usbhs/common.c +++ b/drivers/usb/renesas_usbhs/common.c @@ -613,7 +613,7 @@ static int usbhs_probe(struct platform_device *pdev) info = of_device_get_match_data(dev); if (!info) { - info = renesas_usbhs_get_info(pdev); + info = dev_get_platdata(dev); if (!info) return dev_err_probe(dev, -EINVAL, "no platform info\n"); } diff --git a/include/linux/usb/renesas_usbhs.h b/include/linux/usb/renesas_usbhs.h index 372898d9eeb0..67bfcda6c7d2 100644 --- a/include/linux/usb/renesas_usbhs.h +++ b/include/linux/usb/renesas_usbhs.h @@ -194,9 +194,4 @@ struct renesas_usbhs_platform_info { struct renesas_usbhs_driver_param driver_param; }; -/* - * macro for platform - */ -#define renesas_usbhs_get_info(pdev)\ - ((struct renesas_usbhs_platform_info *)(pdev)->dev.platform_data) #endif /* RENESAS_USB_H */ -- cgit v1.2.3-59-g8ed1b From 1ac579a4bfed5209f39eb75e98566925e4efcec1 Mon Sep 17 00:00:00 2001 From: Anand Moon Date: Fri, 12 Apr 2024 19:52:50 +0530 Subject: usb: ehci-exynos: Use devm_clk_get_enabled() helpers The devm_clk_get_enabled() helpers: - call devm_clk_get() - call clk_prepare_enable() and register what is needed in order to call clk_disable_unprepare() when needed, as a managed resource. This simplifies the code and avoids the calls to clk_disable_unprepare(). Signed-off-by: Anand Moon Reviewed-by: Alan Stern Link: https://lore.kernel.org/r/20240412142317.5191-2-linux.amoon@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-exynos.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/drivers/usb/host/ehci-exynos.c b/drivers/usb/host/ehci-exynos.c index f644b131cc0b..e2303757bc0f 100644 --- a/drivers/usb/host/ehci-exynos.c +++ b/drivers/usb/host/ehci-exynos.c @@ -159,20 +159,16 @@ static int exynos_ehci_probe(struct platform_device *pdev) err = exynos_ehci_get_phy(&pdev->dev, exynos_ehci); if (err) - goto fail_clk; + goto fail_io; - exynos_ehci->clk = devm_clk_get(&pdev->dev, "usbhost"); + exynos_ehci->clk = devm_clk_get_enabled(&pdev->dev, "usbhost"); if (IS_ERR(exynos_ehci->clk)) { dev_err(&pdev->dev, "Failed to get usbhost clock\n"); err = PTR_ERR(exynos_ehci->clk); - goto fail_clk; + goto fail_io; } - err = clk_prepare_enable(exynos_ehci->clk); - if (err) - goto fail_clk; - hcd->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(hcd->regs)) { err = PTR_ERR(hcd->regs); @@ -223,8 +219,6 @@ fail_add_hcd: exynos_ehci_phy_disable(&pdev->dev); pdev->dev.of_node = exynos_ehci->of_node; fail_io: - clk_disable_unprepare(exynos_ehci->clk); -fail_clk: usb_put_hcd(hcd); return err; } @@ -240,8 +234,6 @@ static void exynos_ehci_remove(struct platform_device *pdev) exynos_ehci_phy_disable(&pdev->dev); - clk_disable_unprepare(exynos_ehci->clk); - usb_put_hcd(hcd); } -- cgit v1.2.3-59-g8ed1b From 3f26e2b07affab62d76deef1e62acd06ec25e528 Mon Sep 17 00:00:00 2001 From: Anand Moon Date: Fri, 12 Apr 2024 19:52:51 +0530 Subject: usb: ehci-exynos: Use DEFINE_SIMPLE_DEV_PM_OPS for PM functions This macro has the advantage over SIMPLE_DEV_PM_OPS that we don't have to care about when the functions are actually used. Also make use of pm_ptr() to discard all PM related stuff if CONFIG_PM isn't enabled. Signed-off-by: Anand Moon Link: https://lore.kernel.org/r/20240412142317.5191-3-linux.amoon@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-exynos.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/drivers/usb/host/ehci-exynos.c b/drivers/usb/host/ehci-exynos.c index e2303757bc0f..f40bc2a7a124 100644 --- a/drivers/usb/host/ehci-exynos.c +++ b/drivers/usb/host/ehci-exynos.c @@ -237,7 +237,6 @@ static void exynos_ehci_remove(struct platform_device *pdev) usb_put_hcd(hcd); } -#ifdef CONFIG_PM static int exynos_ehci_suspend(struct device *dev) { struct usb_hcd *hcd = dev_get_drvdata(dev); @@ -280,15 +279,9 @@ static int exynos_ehci_resume(struct device *dev) ehci_resume(hcd, false); return 0; } -#else -#define exynos_ehci_suspend NULL -#define exynos_ehci_resume NULL -#endif -static const struct dev_pm_ops exynos_ehci_pm_ops = { - .suspend = exynos_ehci_suspend, - .resume = exynos_ehci_resume, -}; +static DEFINE_SIMPLE_DEV_PM_OPS(exynos_ehci_pm_ops, + exynos_ehci_suspend, exynos_ehci_resume); #ifdef CONFIG_OF static const struct of_device_id exynos_ehci_match[] = { @@ -304,7 +297,7 @@ static struct platform_driver exynos_ehci_driver = { .shutdown = usb_hcd_platform_shutdown, .driver = { .name = "exynos-ehci", - .pm = &exynos_ehci_pm_ops, + .pm = pm_ptr(&exynos_ehci_pm_ops), .of_match_table = of_match_ptr(exynos_ehci_match), } }; -- cgit v1.2.3-59-g8ed1b From 3d284c95eeb8f3d0c84d0dcaa168ee545026a396 Mon Sep 17 00:00:00 2001 From: Anand Moon Date: Fri, 12 Apr 2024 19:52:52 +0530 Subject: usb: ohci-exynos: Use devm_clk_get_enabled() helpers The devm_clk_get_enabled() helpers: - call devm_clk_get() - call clk_prepare_enable() and register what is needed in order to call clk_disable_unprepare() when needed, as a managed resource. This simplifies the code and avoids the calls to clk_disable_unprepare(). Signed-off-by: Anand Moon Link: https://lore.kernel.org/r/20240412142317.5191-4-linux.amoon@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-exynos.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/drivers/usb/host/ohci-exynos.c b/drivers/usb/host/ohci-exynos.c index 20e26a474591..89e6587c089b 100644 --- a/drivers/usb/host/ohci-exynos.c +++ b/drivers/usb/host/ohci-exynos.c @@ -135,20 +135,16 @@ static int exynos_ohci_probe(struct platform_device *pdev) err = exynos_ohci_get_phy(&pdev->dev, exynos_ohci); if (err) - goto fail_clk; + goto fail_io; - exynos_ohci->clk = devm_clk_get(&pdev->dev, "usbhost"); + exynos_ohci->clk = devm_clk_get_enabled(&pdev->dev, "usbhost"); if (IS_ERR(exynos_ohci->clk)) { dev_err(&pdev->dev, "Failed to get usbhost clock\n"); err = PTR_ERR(exynos_ohci->clk); - goto fail_clk; + goto fail_io; } - err = clk_prepare_enable(exynos_ohci->clk); - if (err) - goto fail_clk; - hcd->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(hcd->regs)) { err = PTR_ERR(hcd->regs); @@ -191,8 +187,6 @@ fail_add_hcd: exynos_ohci_phy_disable(&pdev->dev); pdev->dev.of_node = exynos_ohci->of_node; fail_io: - clk_disable_unprepare(exynos_ohci->clk); -fail_clk: usb_put_hcd(hcd); return err; } @@ -208,8 +202,6 @@ static void exynos_ohci_remove(struct platform_device *pdev) exynos_ohci_phy_disable(&pdev->dev); - clk_disable_unprepare(exynos_ohci->clk); - usb_put_hcd(hcd); } -- cgit v1.2.3-59-g8ed1b From a6a243b6ed3c53dbe2a4eadae098c3c532b98b6b Mon Sep 17 00:00:00 2001 From: Anand Moon Date: Fri, 12 Apr 2024 19:52:53 +0530 Subject: usb: ohci-exynos: Use DEFINE_SIMPLE_DEV_PM_OPS for PM functions This macro has the advantage over SIMPLE_DEV_PM_OPS that we don't have to care about when the functions are actually used. Also make use of pm_ptr() to discard all PM related stuff if CONFIG_PM isn't enabled. Signed-off-by: Anand Moon Link: https://lore.kernel.org/r/20240412142317.5191-5-linux.amoon@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-exynos.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/drivers/usb/host/ohci-exynos.c b/drivers/usb/host/ohci-exynos.c index 89e6587c089b..3c4d68fd5c33 100644 --- a/drivers/usb/host/ohci-exynos.c +++ b/drivers/usb/host/ohci-exynos.c @@ -213,7 +213,6 @@ static void exynos_ohci_shutdown(struct platform_device *pdev) hcd->driver->shutdown(hcd); } -#ifdef CONFIG_PM static int exynos_ohci_suspend(struct device *dev) { struct usb_hcd *hcd = dev_get_drvdata(dev); @@ -250,19 +249,13 @@ static int exynos_ohci_resume(struct device *dev) return 0; } -#else -#define exynos_ohci_suspend NULL -#define exynos_ohci_resume NULL -#endif static const struct ohci_driver_overrides exynos_overrides __initconst = { .extra_priv_size = sizeof(struct exynos_ohci_hcd), }; -static const struct dev_pm_ops exynos_ohci_pm_ops = { - .suspend = exynos_ohci_suspend, - .resume = exynos_ohci_resume, -}; +static DEFINE_SIMPLE_DEV_PM_OPS(exynos_ohci_pm_ops, + exynos_ohci_suspend, exynos_ohci_resume); #ifdef CONFIG_OF static const struct of_device_id exynos_ohci_match[] = { @@ -278,7 +271,7 @@ static struct platform_driver exynos_ohci_driver = { .shutdown = exynos_ohci_shutdown, .driver = { .name = "exynos-ohci", - .pm = &exynos_ohci_pm_ops, + .pm = pm_ptr(&exynos_ohci_pm_ops), .of_match_table = of_match_ptr(exynos_ohci_match), } }; -- cgit v1.2.3-59-g8ed1b From 684e9f5f97eb4b7831298ffad140d5c1d426ff27 Mon Sep 17 00:00:00 2001 From: Anand Moon Date: Fri, 12 Apr 2024 19:52:54 +0530 Subject: usb: dwc3: exynos: Use DEFINE_SIMPLE_DEV_PM_OPS for PM functions This macro has the advantage over SIMPLE_DEV_PM_OPS that we don't have to care about when the functions are actually used. Also make use of pm_sleep_ptr() to discard all PM_SLEEP related stuff if CONFIG_PM_SLEEP isn't enabled. Signed-off-by: Anand Moon Acked-by: Thinh Nguyen Link: https://lore.kernel.org/r/20240412142317.5191-6-linux.amoon@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/dwc3-exynos.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/drivers/usb/dwc3/dwc3-exynos.c b/drivers/usb/dwc3/dwc3-exynos.c index 5d365ca51771..3427522a7c6a 100644 --- a/drivers/usb/dwc3/dwc3-exynos.c +++ b/drivers/usb/dwc3/dwc3-exynos.c @@ -187,7 +187,6 @@ static const struct of_device_id exynos_dwc3_match[] = { }; MODULE_DEVICE_TABLE(of, exynos_dwc3_match); -#ifdef CONFIG_PM_SLEEP static int dwc3_exynos_suspend(struct device *dev) { struct dwc3_exynos *exynos = dev_get_drvdata(dev); @@ -230,14 +229,8 @@ static int dwc3_exynos_resume(struct device *dev) return 0; } -static const struct dev_pm_ops dwc3_exynos_dev_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(dwc3_exynos_suspend, dwc3_exynos_resume) -}; - -#define DEV_PM_OPS (&dwc3_exynos_dev_pm_ops) -#else -#define DEV_PM_OPS NULL -#endif /* CONFIG_PM_SLEEP */ +static DEFINE_SIMPLE_DEV_PM_OPS(dwc3_exynos_dev_pm_ops, + dwc3_exynos_suspend, dwc3_exynos_resume); static struct platform_driver dwc3_exynos_driver = { .probe = dwc3_exynos_probe, @@ -245,7 +238,7 @@ static struct platform_driver dwc3_exynos_driver = { .driver = { .name = "exynos-dwc3", .of_match_table = exynos_dwc3_match, - .pm = DEV_PM_OPS, + .pm = pm_sleep_ptr(&dwc3_exynos_dev_pm_ops), }, }; -- cgit v1.2.3-59-g8ed1b From acf2192167cf42e7ab37376959d9eb34eec3589f Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Sun, 14 Apr 2024 21:22:57 +0200 Subject: staging: vchiq: Reformat Kconfig help texts The lines in the VCHIQ Kconfig help texts are too long, which makes it hard to read the menuconfig. So reformat them to restore the readability. Signed-off-by: Stefan Wahren Reviewed-by: Laurent Pinchart Link: https://lore.kernel.org/r/20240414192257.6011-1-wahrenst@gmx.net Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vc04_services/Kconfig | 36 ++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/drivers/staging/vc04_services/Kconfig b/drivers/staging/vc04_services/Kconfig index 31e58c9d1a11..ccc8e1588648 100644 --- a/drivers/staging/vc04_services/Kconfig +++ b/drivers/staging/vc04_services/Kconfig @@ -16,27 +16,33 @@ config BCM2835_VCHIQ depends on HAS_DMA imply VCHIQ_CDEV help - Broadcom BCM2835 and similar SoCs have a VPU called VideoCore. This config - enables the VCHIQ driver, which implements a messaging interface between - the kernel and the firmware running on VideoCore. Other drivers use this - interface to communicate to the VPU. More specifically, the VCHIQ driver is - used by audio/video and camera drivers as well as for implementing MMAL - API, which is in turn used by several multimedia services on the BCM2835 - family of SoCs. - Defaults to Y when the Broadcom Videocore services are included in - the build, N otherwise. + Broadcom BCM2835 and similar SoCs have a VPU called VideoCore. + This config enables the VCHIQ driver, which implements a + messaging interface between the kernel and the firmware running + on VideoCore. Other drivers use this interface to communicate to + the VPU. More specifically, the VCHIQ driver is used by + audio/video and camera drivers as well as for implementing MMAL + API, which is in turn used by several multimedia services on the + BCM2835 family of SoCs. + + Defaults to Y when the Broadcom Videocore services are included + in the build, N otherwise. if BCM2835_VCHIQ config VCHIQ_CDEV bool "VCHIQ Character Driver" help - Enable the creation of VCHIQ character driver. The cdev exposes ioctls used - by userspace libraries and testing tools to interact with VideoCore, via - the VCHIQ core driver (Check BCM2835_VCHIQ for more info). - This can be set to 'N' if the VideoCore communication is not needed by - userspace but only by other kernel modules (like bcm2835-audio). If not - sure, set this to 'Y'. + Enable the creation of VCHIQ character driver. The cdev exposes + ioctls used by userspace libraries and testing tools to interact + with VideoCore, via the VCHIQ core driver (Check BCM2835_VCHIQ + for more info). + + This can be set to 'N' if the VideoCore communication is not + needed by userspace but only by other kernel modules + (like bcm2835-audio). + + If not sure, set this to 'Y'. endif -- cgit v1.2.3-59-g8ed1b From e0279bb86bb2e1b197f381025b4bdab575fef40c Mon Sep 17 00:00:00 2001 From: Sumadhura Kalyan Date: Mon, 15 Apr 2024 22:41:38 +0530 Subject: staging: vc04_services: Re-align function parameters Checkpatch complains that: CHECK: Lines should not end with a '(' +typedef void (*vchiq_mmal_buffer_cb)( Re-align the function parameters to make checkpatch happy. Signed-off-by: Sumadhura Kalyan Reviewed-by: Dan Carpenter Link: https://lore.kernel.org/r/20240415171138.5849-1-opensourcecond@gmail.com Signed-off-by: Greg Kroah-Hartman --- .../staging/vc04_services/vchiq-mmal/mmal-vchiq.h | 29 ++++++++-------------- 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h index 09f030919d4e..98909fde978e 100644 --- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h +++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h @@ -42,8 +42,7 @@ struct vchiq_mmal_port_buffer { struct vchiq_mmal_port; -typedef void (*vchiq_mmal_buffer_cb)( - struct vchiq_mmal_instance *instance, +typedef void (*vchiq_mmal_buffer_cb)(struct vchiq_mmal_instance *instance, struct vchiq_mmal_port *port, int status, struct mmal_buffer *buffer); @@ -101,31 +100,25 @@ int vchiq_mmal_finalise(struct vchiq_mmal_instance *instance); /* Initialise a mmal component and its ports * */ -int vchiq_mmal_component_init( - struct vchiq_mmal_instance *instance, - const char *name, - struct vchiq_mmal_component **component_out); +int vchiq_mmal_component_init(struct vchiq_mmal_instance *instance, + const char *name, struct vchiq_mmal_component **component_out); -int vchiq_mmal_component_finalise( - struct vchiq_mmal_instance *instance, - struct vchiq_mmal_component *component); +int vchiq_mmal_component_finalise(struct vchiq_mmal_instance *instance, + struct vchiq_mmal_component *component); -int vchiq_mmal_component_enable( - struct vchiq_mmal_instance *instance, - struct vchiq_mmal_component *component); +int vchiq_mmal_component_enable(struct vchiq_mmal_instance *instance, + struct vchiq_mmal_component *component); -int vchiq_mmal_component_disable( - struct vchiq_mmal_instance *instance, - struct vchiq_mmal_component *component); +int vchiq_mmal_component_disable(struct vchiq_mmal_instance *instance, + struct vchiq_mmal_component *component); /* enable a mmal port * * enables a port and if a buffer callback provided enque buffer * headers as appropriate for the port. */ -int vchiq_mmal_port_enable( - struct vchiq_mmal_instance *instance, - struct vchiq_mmal_port *port, +int vchiq_mmal_port_enable(struct vchiq_mmal_instance *instance, + struct vchiq_mmal_port *port, vchiq_mmal_buffer_cb buffer_cb); /* disable a port -- cgit v1.2.3-59-g8ed1b From e82b22539a89d48140cddca896a53e174b7e05a9 Mon Sep 17 00:00:00 2001 From: Umang Jain Date: Fri, 12 Apr 2024 13:27:33 +0530 Subject: staging: vc04_services: Drop g_once_init global variable g_once_init is not used in a meaningful way anywhere. Drop it along with connected_init() which sets it. Suggested-by: Dan Carpenter Reviewed-by: Laurent Pinchart Reviewed-by: Dan Carpenter Reviewed-by: Kieran Bingham Signed-off-by: Umang Jain Reviewed-by: Stefan Wahren Link: https://lore.kernel.org/r/20240412075743.60712-2-umang.jain@ideasonboard.com Signed-off-by: Greg Kroah-Hartman --- .../vc04_services/interface/vchiq_arm/vchiq_connected.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_connected.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_connected.c index 3cad13f09e37..4604a2f4d2de 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_connected.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_connected.c @@ -11,16 +11,8 @@ static int g_connected; static int g_num_deferred_callbacks; static void (*g_deferred_callback[MAX_CALLBACKS])(void); -static int g_once_init; static DEFINE_MUTEX(g_connected_mutex); -/* Function to initialize our lock */ -static void connected_init(void) -{ - if (!g_once_init) - g_once_init = 1; -} - /* * This function is used to defer initialization until the vchiq stack is * initialized. If the stack is already initialized, then the callback will @@ -29,8 +21,6 @@ static void connected_init(void) */ void vchiq_add_connected_callback(struct vchiq_device *device, void (*callback)(void)) { - connected_init(); - if (mutex_lock_killable(&g_connected_mutex)) return; @@ -60,8 +50,6 @@ void vchiq_call_connected_callbacks(void) { int i; - connected_init(); - if (mutex_lock_killable(&g_connected_mutex)) return; -- cgit v1.2.3-59-g8ed1b From 1c9e16b73166bcc89b3d64674b60943ec6142c3e Mon Sep 17 00:00:00 2001 From: Umang Jain Date: Fri, 12 Apr 2024 13:27:34 +0530 Subject: staging: vc04_services: vchiq_arm: Split driver static and runtime data vchiq_drvdata combines two types of book-keeping data. There is platform-specific static data (for e.g. cache lines size) and then data needed for book-keeping at runtime. Split the data into two structures: struct vchiq_platform_info and struct vchiq_drv_mgmt. The vchiq_drv_mgmt is allocated at runtime during probe and will be extended in subsequent patches to remove all global variables allocated. No functional changes intended in this patch. Reviewed-by: Laurent Pinchart Signed-off-by: Umang Jain Reviewed-by: Stefan Wahren Link: https://lore.kernel.org/r/20240412075743.60712-3-umang.jain@ideasonboard.com Signed-off-by: Greg Kroah-Hartman --- .../vc04_services/interface/vchiq_arm/vchiq_arm.c | 43 ++++++++++++---------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c index ad506016fc93..7cf38f8581fa 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c @@ -71,16 +71,11 @@ struct vchiq_state g_state; static struct vchiq_device *bcm2835_audio; static struct vchiq_device *bcm2835_camera; -struct vchiq_drvdata { - const unsigned int cache_line_size; - struct rpi_firmware *fw; -}; - -static struct vchiq_drvdata bcm2835_drvdata = { +static const struct vchiq_platform_info bcm2835_info = { .cache_line_size = 32, }; -static struct vchiq_drvdata bcm2836_drvdata = { +static const struct vchiq_platform_info bcm2836_info = { .cache_line_size = 64, }; @@ -466,8 +461,8 @@ free_pagelist(struct vchiq_instance *instance, struct vchiq_pagelist_info *pagel static int vchiq_platform_init(struct platform_device *pdev, struct vchiq_state *state) { struct device *dev = &pdev->dev; - struct vchiq_drvdata *drvdata = platform_get_drvdata(pdev); - struct rpi_firmware *fw = drvdata->fw; + struct vchiq_drv_mgmt *drv_mgmt = platform_get_drvdata(pdev); + struct rpi_firmware *fw = drv_mgmt->fw; struct vchiq_slot_zero *vchiq_slot_zero; void *slot_mem; dma_addr_t slot_phys; @@ -484,7 +479,7 @@ static int vchiq_platform_init(struct platform_device *pdev, struct vchiq_state if (err < 0) return err; - g_cache_line_size = drvdata->cache_line_size; + g_cache_line_size = drv_mgmt->info->cache_line_size; g_fragments_size = 2 * g_cache_line_size; /* Allocate space for the channels in coherent memory */ @@ -1703,8 +1698,8 @@ void vchiq_platform_conn_state_changed(struct vchiq_state *state, } static const struct of_device_id vchiq_of_match[] = { - { .compatible = "brcm,bcm2835-vchiq", .data = &bcm2835_drvdata }, - { .compatible = "brcm,bcm2836-vchiq", .data = &bcm2836_drvdata }, + { .compatible = "brcm,bcm2835-vchiq", .data = &bcm2835_info }, + { .compatible = "brcm,bcm2836-vchiq", .data = &bcm2836_info }, {}, }; MODULE_DEVICE_TABLE(of, vchiq_of_match); @@ -1712,13 +1707,12 @@ MODULE_DEVICE_TABLE(of, vchiq_of_match); static int vchiq_probe(struct platform_device *pdev) { struct device_node *fw_node; - const struct of_device_id *of_id; - struct vchiq_drvdata *drvdata; + const struct vchiq_platform_info *info; + struct vchiq_drv_mgmt *mgmt; int err; - of_id = of_match_node(vchiq_of_match, pdev->dev.of_node); - drvdata = (struct vchiq_drvdata *)of_id->data; - if (!drvdata) + info = of_device_get_match_data(&pdev->dev); + if (!info) return -EINVAL; fw_node = of_find_compatible_node(NULL, NULL, @@ -1728,12 +1722,17 @@ static int vchiq_probe(struct platform_device *pdev) return -ENOENT; } - drvdata->fw = devm_rpi_firmware_get(&pdev->dev, fw_node); + mgmt = kzalloc(sizeof(*mgmt), GFP_KERNEL); + if (!mgmt) + return -ENOMEM; + + mgmt->fw = devm_rpi_firmware_get(&pdev->dev, fw_node); of_node_put(fw_node); - if (!drvdata->fw) + if (!mgmt->fw) return -EPROBE_DEFER; - platform_set_drvdata(pdev, drvdata); + mgmt->info = info; + platform_set_drvdata(pdev, mgmt); err = vchiq_platform_init(pdev, &g_state); if (err) @@ -1767,10 +1766,14 @@ error_exit: static void vchiq_remove(struct platform_device *pdev) { + struct vchiq_drv_mgmt *mgmt = dev_get_drvdata(&pdev->dev); + vchiq_device_unregister(bcm2835_audio); vchiq_device_unregister(bcm2835_camera); vchiq_debugfs_deinit(); vchiq_deregister_chrdev(); + + kfree(mgmt); } static struct platform_driver vchiq_driver = { -- cgit v1.2.3-59-g8ed1b From 8c9753f6390586d3bf4f72c4ec316e2ee212abf2 Mon Sep 17 00:00:00 2001 From: Umang Jain Date: Fri, 12 Apr 2024 13:27:35 +0530 Subject: staging: vc04_services: vchiq_arm: Drop g_cache_line_size The cache-line-size is cached in struct vchiq_platform_info. There is no need to cache this again via g_cache_line_size and use it. Instead use the value from vchiq_platform_info directly. While at it, move the comment about L2 cache line size in the kerneldoc block of struct vchiq_platform_info. Reviewed-by: Laurent Pinchart Signed-off-by: Umang Jain Reviewed-by: Stefan Wahren Link: https://lore.kernel.org/r/20240412075743.60712-4-umang.jain@ideasonboard.com Signed-off-by: Greg Kroah-Hartman --- .../vc04_services/interface/vchiq_arm/vchiq_arm.c | 34 +++++++++------------- .../vc04_services/interface/vchiq_arm/vchiq_arm.h | 11 +++++++ 2 files changed, 25 insertions(+), 20 deletions(-) diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c index 7cf38f8581fa..af74d7268717 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c @@ -131,17 +131,6 @@ struct vchiq_pagelist_info { }; static void __iomem *g_regs; -/* This value is the size of the L2 cache lines as understood by the - * VPU firmware, which determines the required alignment of the - * offsets/sizes in pagelists. - * - * Modern VPU firmware looks for a DT "cache-line-size" property in - * the VCHIQ node and will overwrite it with the actual L2 cache size, - * which the kernel must then respect. That property was rejected - * upstream, so we have to use the VPU firmware's compatibility value - * of 32. - */ -static unsigned int g_cache_line_size = 32; static unsigned int g_fragments_size; static char *g_fragments_base; static char *g_free_fragments; @@ -212,6 +201,7 @@ static struct vchiq_pagelist_info * create_pagelist(struct vchiq_instance *instance, char *buf, char __user *ubuf, size_t count, unsigned short type) { + struct vchiq_drv_mgmt *drv_mgmt; struct pagelist *pagelist; struct vchiq_pagelist_info *pagelistinfo; struct page **pages; @@ -226,6 +216,8 @@ create_pagelist(struct vchiq_instance *instance, char *buf, char __user *ubuf, if (count >= INT_MAX - PAGE_SIZE) return NULL; + drv_mgmt = dev_get_drvdata(instance->state->dev->parent); + if (buf) offset = (uintptr_t)buf & (PAGE_SIZE - 1); else @@ -368,9 +360,9 @@ create_pagelist(struct vchiq_instance *instance, char *buf, char __user *ubuf, /* Partial cache lines (fragments) require special measures */ if ((type == PAGELIST_READ) && - ((pagelist->offset & (g_cache_line_size - 1)) || + ((pagelist->offset & (drv_mgmt->info->cache_line_size - 1)) || ((pagelist->offset + pagelist->length) & - (g_cache_line_size - 1)))) { + (drv_mgmt->info->cache_line_size - 1)))) { char *fragments; if (down_interruptible(&g_free_fragments_sema)) { @@ -396,12 +388,15 @@ static void free_pagelist(struct vchiq_instance *instance, struct vchiq_pagelist_info *pagelistinfo, int actual) { + struct vchiq_drv_mgmt *drv_mgmt; struct pagelist *pagelist = pagelistinfo->pagelist; struct page **pages = pagelistinfo->pages; unsigned int num_pages = pagelistinfo->num_pages; dev_dbg(instance->state->dev, "arm: %pK, %d\n", pagelistinfo->pagelist, actual); + drv_mgmt = dev_get_drvdata(instance->state->dev->parent); + /* * NOTE: dma_unmap_sg must be called before the * cpu can touch any of the data/pages. @@ -417,10 +412,10 @@ free_pagelist(struct vchiq_instance *instance, struct vchiq_pagelist_info *pagel g_fragments_size; int head_bytes, tail_bytes; - head_bytes = (g_cache_line_size - pagelist->offset) & - (g_cache_line_size - 1); + head_bytes = (drv_mgmt->info->cache_line_size - pagelist->offset) & + (drv_mgmt->info->cache_line_size - 1); tail_bytes = (pagelist->offset + actual) & - (g_cache_line_size - 1); + (drv_mgmt->info->cache_line_size - 1); if ((actual >= 0) && (head_bytes != 0)) { if (head_bytes > actual) @@ -435,8 +430,8 @@ free_pagelist(struct vchiq_instance *instance, struct vchiq_pagelist_info *pagel (tail_bytes != 0)) memcpy_to_page(pages[num_pages - 1], (pagelist->offset + actual) & - (PAGE_SIZE - 1) & ~(g_cache_line_size - 1), - fragments + g_cache_line_size, + (PAGE_SIZE - 1) & ~(drv_mgmt->info->cache_line_size - 1), + fragments + drv_mgmt->info->cache_line_size, tail_bytes); down(&g_free_fragments_mutex); @@ -479,8 +474,7 @@ static int vchiq_platform_init(struct platform_device *pdev, struct vchiq_state if (err < 0) return err; - g_cache_line_size = drv_mgmt->info->cache_line_size; - g_fragments_size = 2 * g_cache_line_size; + g_fragments_size = 2 * drv_mgmt->info->cache_line_size; /* Allocate space for the channels in coherent memory */ slot_mem_size = PAGE_ALIGN(TOTAL_SLOTS * VCHIQ_SLOT_SIZE); diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h index 7844ef765a00..04683d98cd00 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h @@ -20,11 +20,22 @@ #define MAX_ELEMENTS 8 #define MSG_QUEUE_SIZE 128 +struct rpi_firmware; + enum USE_TYPE_E { USE_TYPE_SERVICE, USE_TYPE_VCHIQ }; +struct vchiq_platform_info { + unsigned int cache_line_size; +}; + +struct vchiq_drv_mgmt { + struct rpi_firmware *fw; + const struct vchiq_platform_info *info; +}; + struct user_service { struct vchiq_service *service; void __user *userdata; -- cgit v1.2.3-59-g8ed1b From e1c0af4f3ce0918d0849582fd3b1b630bc5917cb Mon Sep 17 00:00:00 2001 From: Umang Jain Date: Fri, 12 Apr 2024 13:27:36 +0530 Subject: staging: vc04_services: Move variables for tracking connections Connections to the vchiq driver are tracked using global variables. Drop those and introduce them as members of struct vchiq_drv_mgmt. Hence, struct vchiq_drv_mgmt will be used to track the connections. Also, store a vchiq_drv_mgmt pointer to struct vchiq_device to have easy access to struct vchiq_drv_mgmt across vchiq devices. Reviewed-by: Laurent Pinchart Signed-off-by: Umang Jain Link: https://lore.kernel.org/r/20240412075743.60712-5-umang.jain@ideasonboard.com Signed-off-by: Greg Kroah-Hartman --- .../vc04_services/interface/vchiq_arm/vchiq_arm.c | 3 +- .../vc04_services/interface/vchiq_arm/vchiq_arm.h | 9 ++++++ .../vc04_services/interface/vchiq_arm/vchiq_bus.c | 3 ++ .../vc04_services/interface/vchiq_arm/vchiq_bus.h | 3 ++ .../interface/vchiq_arm/vchiq_connected.c | 36 ++++++++++------------ .../interface/vchiq_arm/vchiq_connected.h | 4 ++- 6 files changed, 37 insertions(+), 21 deletions(-) diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c index af74d7268717..ac12ed0784a4 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c @@ -545,7 +545,8 @@ static int vchiq_platform_init(struct platform_device *pdev, struct vchiq_state dev_dbg(&pdev->dev, "arm: vchiq_init - done (slots %pK, phys %pad)\n", vchiq_slot_zero, &slot_phys); - vchiq_call_connected_callbacks(); + mutex_init(&drv_mgmt->connected_mutex); + vchiq_call_connected_callbacks(drv_mgmt); return 0; } diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h index 04683d98cd00..b4ed50e4072d 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h @@ -20,6 +20,8 @@ #define MAX_ELEMENTS 8 #define MSG_QUEUE_SIZE 128 +#define VCHIQ_DRV_MAX_CALLBACKS 10 + struct rpi_firmware; enum USE_TYPE_E { @@ -34,6 +36,13 @@ struct vchiq_platform_info { struct vchiq_drv_mgmt { struct rpi_firmware *fw; const struct vchiq_platform_info *info; + + bool connected; + int num_deferred_callbacks; + /* Protects connected and num_deferred_callbacks */ + struct mutex connected_mutex; + + void (*deferred_callback[VCHIQ_DRV_MAX_CALLBACKS])(void); }; struct user_service { diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_bus.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_bus.c index 93609716df84..3f87b93c6537 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_bus.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_bus.c @@ -11,6 +11,7 @@ #include #include +#include "vchiq_arm.h" #include "vchiq_bus.h" static int vchiq_bus_type_match(struct device *dev, struct device_driver *drv) @@ -77,6 +78,8 @@ vchiq_device_register(struct device *parent, const char *name) device->dev.dma_mask = &device->dev.coherent_dma_mask; device->dev.release = vchiq_device_release; + device->drv_mgmt = dev_get_drvdata(parent); + of_dma_configure(&device->dev, parent->of_node, true); ret = device_register(&device->dev); diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_bus.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_bus.h index 4db86e76edbd..9de179b39f85 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_bus.h +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_bus.h @@ -9,8 +9,11 @@ #include #include +struct vchiq_drv_mgmt; + struct vchiq_device { struct device dev; + struct vchiq_drv_mgmt *drv_mgmt; }; struct vchiq_driver { diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_connected.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_connected.c index 4604a2f4d2de..049b3f2d1bd4 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_connected.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_connected.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* Copyright (c) 2010-2012 Broadcom. All rights reserved. */ +#include "vchiq_arm.h" #include "vchiq_connected.h" #include "vchiq_core.h" #include @@ -8,11 +9,6 @@ #define MAX_CALLBACKS 10 -static int g_connected; -static int g_num_deferred_callbacks; -static void (*g_deferred_callback[MAX_CALLBACKS])(void); -static DEFINE_MUTEX(g_connected_mutex); - /* * This function is used to defer initialization until the vchiq stack is * initialized. If the stack is already initialized, then the callback will @@ -21,24 +17,26 @@ static DEFINE_MUTEX(g_connected_mutex); */ void vchiq_add_connected_callback(struct vchiq_device *device, void (*callback)(void)) { - if (mutex_lock_killable(&g_connected_mutex)) + struct vchiq_drv_mgmt *drv_mgmt = device->drv_mgmt; + + if (mutex_lock_killable(&drv_mgmt->connected_mutex)) return; - if (g_connected) { + if (drv_mgmt->connected) { /* We're already connected. Call the callback immediately. */ callback(); } else { - if (g_num_deferred_callbacks >= MAX_CALLBACKS) { + if (drv_mgmt->num_deferred_callbacks >= MAX_CALLBACKS) { dev_err(&device->dev, "core: There already %d callback registered - please increase MAX_CALLBACKS\n", - g_num_deferred_callbacks); + drv_mgmt->num_deferred_callbacks); } else { - g_deferred_callback[g_num_deferred_callbacks] = + drv_mgmt->deferred_callback[drv_mgmt->num_deferred_callbacks] = callback; - g_num_deferred_callbacks++; + drv_mgmt->num_deferred_callbacks++; } } - mutex_unlock(&g_connected_mutex); + mutex_unlock(&drv_mgmt->connected_mutex); } EXPORT_SYMBOL(vchiq_add_connected_callback); @@ -46,17 +44,17 @@ EXPORT_SYMBOL(vchiq_add_connected_callback); * This function is called by the vchiq stack once it has been connected to * the videocore and clients can start to use the stack. */ -void vchiq_call_connected_callbacks(void) +void vchiq_call_connected_callbacks(struct vchiq_drv_mgmt *drv_mgmt) { int i; - if (mutex_lock_killable(&g_connected_mutex)) + if (mutex_lock_killable(&drv_mgmt->connected_mutex)) return; - for (i = 0; i < g_num_deferred_callbacks; i++) - g_deferred_callback[i](); + for (i = 0; i < drv_mgmt->num_deferred_callbacks; i++) + drv_mgmt->deferred_callback[i](); - g_num_deferred_callbacks = 0; - g_connected = 1; - mutex_unlock(&g_connected_mutex); + drv_mgmt->num_deferred_callbacks = 0; + drv_mgmt->connected = true; + mutex_unlock(&drv_mgmt->connected_mutex); } diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_connected.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_connected.h index e4ed56446f8a..f57a878652b1 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_connected.h +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_connected.h @@ -6,7 +6,9 @@ #ifndef VCHIQ_CONNECTED_H #define VCHIQ_CONNECTED_H +struct vchiq_drv_mgmt; + void vchiq_add_connected_callback(struct vchiq_device *device, void (*callback)(void)); -void vchiq_call_connected_callbacks(void); +void vchiq_call_connected_callbacks(struct vchiq_drv_mgmt *mgmt); #endif /* VCHIQ_CONNECTED_H */ -- cgit v1.2.3-59-g8ed1b From f875976ecf450e0c5d0cd07a474313ea44922b5f Mon Sep 17 00:00:00 2001 From: Umang Jain Date: Fri, 12 Apr 2024 13:27:37 +0530 Subject: staging: vc04_services: Drop vchiq_connected.[ch] files The vchiq_connected.[ch] just implements two function: - vchiq_add_connected_callback() - vchiq_call_connected_callbacks() for the deferred vchiq callbacks. Those can easily live in vchiq_arm.[ch], hence move them. This allows making the vchiq_call_connected_callbacks() function static. The move doesn't copy over MAX_CALLBACKS because it is the same as VCHIQ_DRV_MAX_CALLBACKS. Hence, it now being used in vchiq_add_connected_callback(). No functional changes intended in this patch. Suggested-by: Laurent Pinchart Reviewed-by: Laurent Pinchart Signed-off-by: Umang Jain Link: https://lore.kernel.org/r/20240412075743.60712-6-umang.jain@ideasonboard.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vc04_services/Makefile | 1 - .../vc04_services/interface/vchiq_arm/vchiq_arm.c | 51 +++++++++++++++++- .../vc04_services/interface/vchiq_arm/vchiq_arm.h | 5 ++ .../interface/vchiq_arm/vchiq_connected.c | 60 ---------------------- .../interface/vchiq_arm/vchiq_connected.h | 14 ----- 5 files changed, 55 insertions(+), 76 deletions(-) delete mode 100644 drivers/staging/vc04_services/interface/vchiq_arm/vchiq_connected.c delete mode 100644 drivers/staging/vc04_services/interface/vchiq_arm/vchiq_connected.h diff --git a/drivers/staging/vc04_services/Makefile b/drivers/staging/vc04_services/Makefile index e8b897a7b9a6..dad3789522b8 100644 --- a/drivers/staging/vc04_services/Makefile +++ b/drivers/staging/vc04_services/Makefile @@ -6,7 +6,6 @@ vchiq-objs := \ interface/vchiq_arm/vchiq_arm.o \ interface/vchiq_arm/vchiq_bus.o \ interface/vchiq_arm/vchiq_debugfs.o \ - interface/vchiq_arm/vchiq_connected.o \ ifdef CONFIG_VCHIQ_CDEV vchiq-objs += interface/vchiq_arm/vchiq_dev.o diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c index ac12ed0784a4..396c686b1978 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c @@ -36,7 +36,6 @@ #include "vchiq_arm.h" #include "vchiq_bus.h" #include "vchiq_debugfs.h" -#include "vchiq_connected.h" #include "vchiq_pagelist.h" #define DEVICE_NAME "vchiq" @@ -189,6 +188,56 @@ is_adjacent_block(u32 *addrs, u32 addr, unsigned int k) return tmp == (addr & PAGE_MASK); } +/* + * This function is called by the vchiq stack once it has been connected to + * the videocore and clients can start to use the stack. + */ +static void vchiq_call_connected_callbacks(struct vchiq_drv_mgmt *drv_mgmt) +{ + int i; + + if (mutex_lock_killable(&drv_mgmt->connected_mutex)) + return; + + for (i = 0; i < drv_mgmt->num_deferred_callbacks; i++) + drv_mgmt->deferred_callback[i](); + + drv_mgmt->num_deferred_callbacks = 0; + drv_mgmt->connected = true; + mutex_unlock(&drv_mgmt->connected_mutex); +} + +/* + * This function is used to defer initialization until the vchiq stack is + * initialized. If the stack is already initialized, then the callback will + * be made immediately, otherwise it will be deferred until + * vchiq_call_connected_callbacks is called. + */ +void vchiq_add_connected_callback(struct vchiq_device *device, void (*callback)(void)) +{ + struct vchiq_drv_mgmt *drv_mgmt = device->drv_mgmt; + + if (mutex_lock_killable(&drv_mgmt->connected_mutex)) + return; + + if (drv_mgmt->connected) { + /* We're already connected. Call the callback immediately. */ + callback(); + } else { + if (drv_mgmt->num_deferred_callbacks >= VCHIQ_DRV_MAX_CALLBACKS) { + dev_err(&device->dev, + "core: deferred callbacks(%d) exceeded the maximum limit(%d)\n", + drv_mgmt->num_deferred_callbacks, VCHIQ_DRV_MAX_CALLBACKS); + } else { + drv_mgmt->deferred_callback[drv_mgmt->num_deferred_callbacks] = + callback; + drv_mgmt->num_deferred_callbacks++; + } + } + mutex_unlock(&drv_mgmt->connected_mutex); +} +EXPORT_SYMBOL(vchiq_add_connected_callback); + /* There is a potential problem with partial cache lines (pages?) * at the ends of the block when reading. If the CPU accessed anything in * the same line (page?) then it may have pulled old data into the cache, diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h index b4ed50e4072d..48f6abee591f 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h @@ -23,6 +23,7 @@ #define VCHIQ_DRV_MAX_CALLBACKS 10 struct rpi_firmware; +struct vchiq_device; enum USE_TYPE_E { USE_TYPE_SERVICE, @@ -132,6 +133,10 @@ vchiq_instance_get_trace(struct vchiq_instance *instance); extern void vchiq_instance_set_trace(struct vchiq_instance *instance, int trace); +extern void +vchiq_add_connected_callback(struct vchiq_device *device, + void (*callback)(void)); + #if IS_ENABLED(CONFIG_VCHIQ_CDEV) extern void diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_connected.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_connected.c deleted file mode 100644 index 049b3f2d1bd4..000000000000 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_connected.c +++ /dev/null @@ -1,60 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause -/* Copyright (c) 2010-2012 Broadcom. All rights reserved. */ - -#include "vchiq_arm.h" -#include "vchiq_connected.h" -#include "vchiq_core.h" -#include -#include - -#define MAX_CALLBACKS 10 - -/* - * This function is used to defer initialization until the vchiq stack is - * initialized. If the stack is already initialized, then the callback will - * be made immediately, otherwise it will be deferred until - * vchiq_call_connected_callbacks is called. - */ -void vchiq_add_connected_callback(struct vchiq_device *device, void (*callback)(void)) -{ - struct vchiq_drv_mgmt *drv_mgmt = device->drv_mgmt; - - if (mutex_lock_killable(&drv_mgmt->connected_mutex)) - return; - - if (drv_mgmt->connected) { - /* We're already connected. Call the callback immediately. */ - callback(); - } else { - if (drv_mgmt->num_deferred_callbacks >= MAX_CALLBACKS) { - dev_err(&device->dev, - "core: There already %d callback registered - please increase MAX_CALLBACKS\n", - drv_mgmt->num_deferred_callbacks); - } else { - drv_mgmt->deferred_callback[drv_mgmt->num_deferred_callbacks] = - callback; - drv_mgmt->num_deferred_callbacks++; - } - } - mutex_unlock(&drv_mgmt->connected_mutex); -} -EXPORT_SYMBOL(vchiq_add_connected_callback); - -/* - * This function is called by the vchiq stack once it has been connected to - * the videocore and clients can start to use the stack. - */ -void vchiq_call_connected_callbacks(struct vchiq_drv_mgmt *drv_mgmt) -{ - int i; - - if (mutex_lock_killable(&drv_mgmt->connected_mutex)) - return; - - for (i = 0; i < drv_mgmt->num_deferred_callbacks; i++) - drv_mgmt->deferred_callback[i](); - - drv_mgmt->num_deferred_callbacks = 0; - drv_mgmt->connected = true; - mutex_unlock(&drv_mgmt->connected_mutex); -} diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_connected.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_connected.h deleted file mode 100644 index f57a878652b1..000000000000 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_connected.h +++ /dev/null @@ -1,14 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ -/* Copyright (c) 2010-2012 Broadcom. All rights reserved. */ - -#include "vchiq_bus.h" - -#ifndef VCHIQ_CONNECTED_H -#define VCHIQ_CONNECTED_H - -struct vchiq_drv_mgmt; - -void vchiq_add_connected_callback(struct vchiq_device *device, void (*callback)(void)); -void vchiq_call_connected_callbacks(struct vchiq_drv_mgmt *mgmt); - -#endif /* VCHIQ_CONNECTED_H */ -- cgit v1.2.3-59-g8ed1b From 39fbff9dfc2ee0c8f5f8cc7379ebcc776184d3da Mon Sep 17 00:00:00 2001 From: Umang Jain Date: Fri, 12 Apr 2024 13:27:38 +0530 Subject: staging: vc04_services: Move global variables tracking allocated pages The variables tracking allocated pages fragments in vchiq_arm.c can be easily moved to struct vchiq_drv_mgmt instead of being global. This helps us to drop the non-essential global variables in the vchiq interface. No functional changes intended in this patch. Reviewed-by: Laurent Pinchart Signed-off-by: Umang Jain Reviewed-by: Stefan Wahren Link: https://lore.kernel.org/r/20240412075743.60712-7-umang.jain@ideasonboard.com Signed-off-by: Greg Kroah-Hartman --- .../vc04_services/interface/vchiq_arm/vchiq_arm.c | 53 ++++++++++------------ .../vc04_services/interface/vchiq_arm/vchiq_arm.h | 6 +++ 2 files changed, 30 insertions(+), 29 deletions(-) diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c index 396c686b1978..29f9affe5304 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c @@ -130,12 +130,6 @@ struct vchiq_pagelist_info { }; static void __iomem *g_regs; -static unsigned int g_fragments_size; -static char *g_fragments_base; -static char *g_free_fragments; -static struct semaphore g_free_fragments_sema; - -static DEFINE_SEMAPHORE(g_free_fragments_mutex, 1); static int vchiq_blocking_bulk_transfer(struct vchiq_instance *instance, unsigned int handle, void *data, @@ -414,20 +408,20 @@ create_pagelist(struct vchiq_instance *instance, char *buf, char __user *ubuf, (drv_mgmt->info->cache_line_size - 1)))) { char *fragments; - if (down_interruptible(&g_free_fragments_sema)) { + if (down_interruptible(&drv_mgmt->free_fragments_sema)) { cleanup_pagelistinfo(instance, pagelistinfo); return NULL; } - WARN_ON(!g_free_fragments); + WARN_ON(!drv_mgmt->free_fragments); - down(&g_free_fragments_mutex); - fragments = g_free_fragments; + down(&drv_mgmt->free_fragments_mutex); + fragments = drv_mgmt->free_fragments; WARN_ON(!fragments); - g_free_fragments = *(char **)g_free_fragments; - up(&g_free_fragments_mutex); + drv_mgmt->free_fragments = *(char **)drv_mgmt->free_fragments; + up(&drv_mgmt->free_fragments_mutex); pagelist->type = PAGELIST_READ_WITH_FRAGMENTS + - (fragments - g_fragments_base) / g_fragments_size; + (fragments - drv_mgmt->fragments_base) / drv_mgmt->fragments_size; } return pagelistinfo; @@ -455,10 +449,10 @@ free_pagelist(struct vchiq_instance *instance, struct vchiq_pagelist_info *pagel pagelistinfo->scatterlist_mapped = 0; /* Deal with any partial cache lines (fragments) */ - if (pagelist->type >= PAGELIST_READ_WITH_FRAGMENTS && g_fragments_base) { - char *fragments = g_fragments_base + + if (pagelist->type >= PAGELIST_READ_WITH_FRAGMENTS && drv_mgmt->fragments_base) { + char *fragments = drv_mgmt->fragments_base + (pagelist->type - PAGELIST_READ_WITH_FRAGMENTS) * - g_fragments_size; + drv_mgmt->fragments_size; int head_bytes, tail_bytes; head_bytes = (drv_mgmt->info->cache_line_size - pagelist->offset) & @@ -483,11 +477,11 @@ free_pagelist(struct vchiq_instance *instance, struct vchiq_pagelist_info *pagel fragments + drv_mgmt->info->cache_line_size, tail_bytes); - down(&g_free_fragments_mutex); - *(char **)fragments = g_free_fragments; - g_free_fragments = fragments; - up(&g_free_fragments_mutex); - up(&g_free_fragments_sema); + down(&drv_mgmt->free_fragments_mutex); + *(char **)fragments = drv_mgmt->free_fragments; + drv_mgmt->free_fragments = fragments; + up(&drv_mgmt->free_fragments_mutex); + up(&drv_mgmt->free_fragments_sema); } /* Need to mark all the pages dirty. */ @@ -523,11 +517,11 @@ static int vchiq_platform_init(struct platform_device *pdev, struct vchiq_state if (err < 0) return err; - g_fragments_size = 2 * drv_mgmt->info->cache_line_size; + drv_mgmt->fragments_size = 2 * drv_mgmt->info->cache_line_size; /* Allocate space for the channels in coherent memory */ slot_mem_size = PAGE_ALIGN(TOTAL_SLOTS * VCHIQ_SLOT_SIZE); - frag_mem_size = PAGE_ALIGN(g_fragments_size * MAX_FRAGMENTS); + frag_mem_size = PAGE_ALIGN(drv_mgmt->fragments_size * MAX_FRAGMENTS); slot_mem = dmam_alloc_coherent(dev, slot_mem_size + frag_mem_size, &slot_phys, GFP_KERNEL); @@ -547,15 +541,16 @@ static int vchiq_platform_init(struct platform_device *pdev, struct vchiq_state vchiq_slot_zero->platform_data[VCHIQ_PLATFORM_FRAGMENTS_COUNT_IDX] = MAX_FRAGMENTS; - g_fragments_base = (char *)slot_mem + slot_mem_size; + drv_mgmt->fragments_base = (char *)slot_mem + slot_mem_size; - g_free_fragments = g_fragments_base; + drv_mgmt->free_fragments = drv_mgmt->fragments_base; for (i = 0; i < (MAX_FRAGMENTS - 1); i++) { - *(char **)&g_fragments_base[i * g_fragments_size] = - &g_fragments_base[(i + 1) * g_fragments_size]; + *(char **)&drv_mgmt->fragments_base[i * drv_mgmt->fragments_size] = + &drv_mgmt->fragments_base[(i + 1) * drv_mgmt->fragments_size]; } - *(char **)&g_fragments_base[i * g_fragments_size] = NULL; - sema_init(&g_free_fragments_sema, MAX_FRAGMENTS); + *(char **)&drv_mgmt->fragments_base[i * drv_mgmt->fragments_size] = NULL; + sema_init(&drv_mgmt->free_fragments_sema, MAX_FRAGMENTS); + sema_init(&drv_mgmt->free_fragments_mutex, 1); err = vchiq_init_state(state, vchiq_slot_zero, dev); if (err) diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h index 48f6abee591f..52013bbc5171 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h @@ -44,6 +44,12 @@ struct vchiq_drv_mgmt { struct mutex connected_mutex; void (*deferred_callback[VCHIQ_DRV_MAX_CALLBACKS])(void); + + struct semaphore free_fragments_sema; + struct semaphore free_fragments_mutex; + char *fragments_base; + char *free_fragments; + unsigned int fragments_size; }; struct user_service { -- cgit v1.2.3-59-g8ed1b From 6d0ef3214ddb5cc66328d23ca225fff5308fd078 Mon Sep 17 00:00:00 2001 From: Umang Jain Date: Fri, 12 Apr 2024 13:27:39 +0530 Subject: staging: vc04_services: Move global memory mapped pointer g_regs stores the remapped memory pointer for the vchiq platform. It can be moved to struct vchiq_drv_mgmt instead of being global. Adjust the affected functions accordingly. Pass vchiq_state pointer wherever necessary to access struct vchiq_drv_mgmt. Reviewed-by: Laurent Pinchart Signed-off-by: Umang Jain Link: https://lore.kernel.org/r/20240412075743.60712-8-umang.jain@ideasonboard.com Signed-off-by: Greg Kroah-Hartman --- .../vc04_services/interface/vchiq_arm/vchiq_arm.c | 19 +++++++++++-------- .../vc04_services/interface/vchiq_arm/vchiq_arm.h | 2 ++ .../vc04_services/interface/vchiq_arm/vchiq_core.c | 10 +++++----- .../vc04_services/interface/vchiq_arm/vchiq_core.h | 2 +- 4 files changed, 19 insertions(+), 14 deletions(-) diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c index 29f9affe5304..9fc98411a2b8 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c @@ -129,8 +129,6 @@ struct vchiq_pagelist_info { unsigned int scatterlist_mapped; }; -static void __iomem *g_regs; - static int vchiq_blocking_bulk_transfer(struct vchiq_instance *instance, unsigned int handle, void *data, unsigned int size, enum vchiq_bulk_dir dir); @@ -139,11 +137,14 @@ static irqreturn_t vchiq_doorbell_irq(int irq, void *dev_id) { struct vchiq_state *state = dev_id; + struct vchiq_drv_mgmt *mgmt; irqreturn_t ret = IRQ_NONE; unsigned int status; + mgmt = dev_get_drvdata(state->dev); + /* Read (and clear) the doorbell */ - status = readl(g_regs + BELL0); + status = readl(mgmt->regs + BELL0); if (status & ARM_DS_ACTIVE) { /* Was the doorbell rung? */ remote_event_pollall(state); @@ -556,9 +557,9 @@ static int vchiq_platform_init(struct platform_device *pdev, struct vchiq_state if (err) return err; - g_regs = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(g_regs)) - return PTR_ERR(g_regs); + drv_mgmt->regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(drv_mgmt->regs)) + return PTR_ERR(drv_mgmt->regs); irq = platform_get_irq(pdev, 0); if (irq <= 0) @@ -641,8 +642,10 @@ static struct vchiq_arm_state *vchiq_platform_get_arm_state(struct vchiq_state * } void -remote_event_signal(struct remote_event *event) +remote_event_signal(struct vchiq_state *state, struct remote_event *event) { + struct vchiq_drv_mgmt *mgmt = dev_get_drvdata(state->dev); + /* * Ensure that all writes to shared data structures have completed * before signalling the peer. @@ -654,7 +657,7 @@ remote_event_signal(struct remote_event *event) dsb(sy); /* data barrier operation */ if (event->armed) - writel(0, g_regs + BELL2); /* trigger vc interrupt */ + writel(0, mgmt->regs + BELL2); /* trigger vc interrupt */ } int diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h index 52013bbc5171..10c1bdc50faf 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h @@ -50,6 +50,8 @@ struct vchiq_drv_mgmt { char *fragments_base; char *free_fragments; unsigned int fragments_size; + + void __iomem *regs; }; struct user_service { diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c index 76c27778154a..8c339aebbc99 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c @@ -691,7 +691,7 @@ reserve_space(struct vchiq_state *state, size_t space, int is_blocking) /* But first, flush through the last slot. */ state->local_tx_pos = tx_pos; local->tx_pos = tx_pos; - remote_event_signal(&state->remote->trigger); + remote_event_signal(state, &state->remote->trigger); if (!is_blocking || (wait_for_completion_interruptible(&state->slot_available_event))) @@ -1124,7 +1124,7 @@ queue_message(struct vchiq_state *state, struct vchiq_service *service, if (!(flags & QMFLAGS_NO_MUTEX_UNLOCK)) mutex_unlock(&state->slot_mutex); - remote_event_signal(&state->remote->trigger); + remote_event_signal(state, &state->remote->trigger); return 0; } @@ -1202,7 +1202,7 @@ queue_message_sync(struct vchiq_state *state, struct vchiq_service *service, &svc_fourcc, VCHIQ_MSG_SRCPORT(msgid), VCHIQ_MSG_DSTPORT(msgid), size); - remote_event_signal(&state->remote->sync_trigger); + remote_event_signal(state, &state->remote->sync_trigger); if (VCHIQ_MSG_TYPE(msgid) != VCHIQ_MSG_PAUSE) mutex_unlock(&state->sync_mutex); @@ -1260,7 +1260,7 @@ release_slot(struct vchiq_state *state, struct vchiq_slot_info *slot_info, * A write barrier is necessary, but remote_event_signal * contains one. */ - remote_event_signal(&state->remote->recycle); + remote_event_signal(state, &state->remote->recycle); } mutex_unlock(&state->recycle_mutex); @@ -3240,7 +3240,7 @@ static void release_message_sync(struct vchiq_state *state, struct vchiq_header *header) { header->msgid = VCHIQ_MSGID_PADDING; - remote_event_signal(&state->remote->sync_release); + remote_event_signal(state, &state->remote->sync_release); } int diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h index 5fbf173d9c56..8ca74b12427b 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h @@ -516,7 +516,7 @@ int vchiq_prepare_bulk_data(struct vchiq_instance *instance, struct vchiq_bulk * void vchiq_complete_bulk(struct vchiq_instance *instance, struct vchiq_bulk *bulk); -void remote_event_signal(struct remote_event *event); +void remote_event_signal(struct vchiq_state *state, struct remote_event *event); void vchiq_dump_platform_state(struct seq_file *f); -- cgit v1.2.3-59-g8ed1b From 12cc5f92c159e9dcc8eef90a1ea2779b41b86b71 Mon Sep 17 00:00:00 2001 From: Umang Jain Date: Fri, 12 Apr 2024 13:27:40 +0530 Subject: staging: vc04_services: Move spinlocks to vchiq_state The msg_queue_spinlock, quota_spinlock and bulk_waiter_spinlock are allocated globally. Instead move them to struct vchiq_state and initialise them in vchiq_init_state(). Signed-off-by: Umang Jain Reviewed-by: Stefan Wahren Link: https://lore.kernel.org/r/20240412075743.60712-9-umang.jain@ideasonboard.com Signed-off-by: Greg Kroah-Hartman --- .../vc04_services/interface/vchiq_arm/vchiq_arm.c | 17 +++++----- .../vc04_services/interface/vchiq_arm/vchiq_arm.h | 1 - .../vc04_services/interface/vchiq_arm/vchiq_core.c | 39 +++++++++++----------- .../vc04_services/interface/vchiq_arm/vchiq_core.h | 7 ++++ .../vc04_services/interface/vchiq_arm/vchiq_dev.c | 24 ++++++------- 5 files changed, 47 insertions(+), 41 deletions(-) diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c index 9fc98411a2b8..4bdd383a060c 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c @@ -59,7 +59,6 @@ #define KEEPALIVE_VER 1 #define KEEPALIVE_VER_MIN KEEPALIVE_VER -DEFINE_SPINLOCK(msg_queue_spinlock); struct vchiq_state g_state; /* @@ -985,9 +984,9 @@ vchiq_blocking_bulk_transfer(struct vchiq_instance *instance, unsigned int handl * This is not a retry of the previous one. * Cancel the signal when the transfer completes. */ - spin_lock(&bulk_waiter_spinlock); + spin_lock(&service->state->bulk_waiter_spinlock); bulk->userdata = NULL; - spin_unlock(&bulk_waiter_spinlock); + spin_unlock(&service->state->bulk_waiter_spinlock); } } } else { @@ -1004,9 +1003,9 @@ vchiq_blocking_bulk_transfer(struct vchiq_instance *instance, unsigned int handl if (bulk) { /* Cancel the signal when the transfer completes. */ - spin_lock(&bulk_waiter_spinlock); + spin_lock(&service->state->bulk_waiter_spinlock); bulk->userdata = NULL; - spin_unlock(&bulk_waiter_spinlock); + spin_unlock(&service->state->bulk_waiter_spinlock); } kfree(waiter); } else { @@ -1127,10 +1126,10 @@ service_callback(struct vchiq_instance *instance, enum vchiq_reason reason, reason, header, instance, bulk_userdata); if (header && user_service->is_vchi) { - spin_lock(&msg_queue_spinlock); + spin_lock(&service->state->msg_queue_spinlock); while (user_service->msg_insert == (user_service->msg_remove + MSG_QUEUE_SIZE)) { - spin_unlock(&msg_queue_spinlock); + spin_unlock(&service->state->msg_queue_spinlock); DEBUG_TRACE(SERVICE_CALLBACK_LINE); DEBUG_COUNT(MSG_QUEUE_FULL_COUNT); dev_dbg(service->state->dev, "arm: msg queue full\n"); @@ -1167,7 +1166,7 @@ service_callback(struct vchiq_instance *instance, enum vchiq_reason reason, return -EINVAL; } DEBUG_TRACE(SERVICE_CALLBACK_LINE); - spin_lock(&msg_queue_spinlock); + spin_lock(&service->state->msg_queue_spinlock); } user_service->msg_queue[user_service->msg_insert & @@ -1186,7 +1185,7 @@ service_callback(struct vchiq_instance *instance, enum vchiq_reason reason, skip_completion = true; } - spin_unlock(&msg_queue_spinlock); + spin_unlock(&service->state->msg_queue_spinlock); complete(&user_service->insert_event); header = NULL; diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h index 10c1bdc50faf..127e2d6b1d51 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h @@ -98,7 +98,6 @@ struct vchiq_instance { struct vchiq_debugfs_node debugfs_node; }; -extern spinlock_t msg_queue_spinlock; extern struct vchiq_state g_state; extern struct vchiq_state * diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c index 8c339aebbc99..52a11c743bd6 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c @@ -149,9 +149,6 @@ static inline void check_sizes(void) BUILD_BUG_ON_NOT_POWER_OF_2(VCHIQ_MAX_SERVICES); } -DEFINE_SPINLOCK(bulk_waiter_spinlock); -static DEFINE_SPINLOCK(quota_spinlock); - static unsigned int handle_seq; static const char *const srvstate_names[] = { @@ -724,11 +721,11 @@ process_free_data_message(struct vchiq_state *state, u32 *service_found, struct vchiq_service_quota *quota = &state->service_quotas[port]; int count; - spin_lock("a_spinlock); + spin_lock(&state->quota_spinlock); count = quota->message_use_count; if (count > 0) quota->message_use_count = count - 1; - spin_unlock("a_spinlock); + spin_unlock(&state->quota_spinlock); if (count == quota->message_quota) { /* @@ -747,11 +744,11 @@ process_free_data_message(struct vchiq_state *state, u32 *service_found, /* Set the found bit for this service */ BITSET_SET(service_found, port); - spin_lock("a_spinlock); + spin_lock(&state->quota_spinlock); count = quota->slot_use_count; if (count > 0) quota->slot_use_count = count - 1; - spin_unlock("a_spinlock); + spin_unlock(&state->quota_spinlock); if (count > 0) { /* @@ -837,11 +834,11 @@ process_free_queue(struct vchiq_state *state, u32 *service_found, if (data_found) { int count; - spin_lock("a_spinlock); + spin_lock(&state->quota_spinlock); count = state->data_use_count; if (count > 0) state->data_use_count = count - 1; - spin_unlock("a_spinlock); + spin_unlock(&state->quota_spinlock); if (count == state->data_quota) complete(&state->data_quota_event); } @@ -940,7 +937,7 @@ queue_message(struct vchiq_state *state, struct vchiq_service *service, quota = &state->service_quotas[service->localport]; - spin_lock("a_spinlock); + spin_lock(&state->quota_spinlock); /* * Ensure this service doesn't use more than its quota of @@ -955,14 +952,14 @@ queue_message(struct vchiq_state *state, struct vchiq_service *service, while ((tx_end_index != state->previous_data_index) && (state->data_use_count == state->data_quota)) { VCHIQ_STATS_INC(state, data_stalls); - spin_unlock("a_spinlock); + spin_unlock(&state->quota_spinlock); mutex_unlock(&state->slot_mutex); if (wait_for_completion_interruptible(&state->data_quota_event)) return -EAGAIN; mutex_lock(&state->slot_mutex); - spin_lock("a_spinlock); + spin_lock(&state->quota_spinlock); tx_end_index = SLOT_QUEUE_INDEX_FROM_POS(state->local_tx_pos + stride - 1); if ((tx_end_index == state->previous_data_index) || (state->data_use_count < state->data_quota)) { @@ -975,7 +972,7 @@ queue_message(struct vchiq_state *state, struct vchiq_service *service, while ((quota->message_use_count == quota->message_quota) || ((tx_end_index != quota->previous_tx_index) && (quota->slot_use_count == quota->slot_quota))) { - spin_unlock("a_spinlock); + spin_unlock(&state->quota_spinlock); dev_dbg(state->dev, "core: %d: qm:%d %s,%zx - quota stall (msg %d, slot %d)\n", state->id, service->localport, msg_type_str(type), size, @@ -993,11 +990,11 @@ queue_message(struct vchiq_state *state, struct vchiq_service *service, mutex_unlock(&state->slot_mutex); return -EHOSTDOWN; } - spin_lock("a_spinlock); + spin_lock(&state->quota_spinlock); tx_end_index = SLOT_QUEUE_INDEX_FROM_POS(state->local_tx_pos + stride - 1); } - spin_unlock("a_spinlock); + spin_unlock(&state->quota_spinlock); } header = reserve_space(state, stride, flags & QMFLAGS_IS_BLOCKING); @@ -1040,7 +1037,7 @@ queue_message(struct vchiq_state *state, struct vchiq_service *service, header->data, min_t(size_t, 16, callback_result)); - spin_lock("a_spinlock); + spin_lock(&state->quota_spinlock); quota->message_use_count++; tx_end_index = @@ -1066,7 +1063,7 @@ queue_message(struct vchiq_state *state, struct vchiq_service *service, slot_use_count = 0; } - spin_unlock("a_spinlock); + spin_unlock(&state->quota_spinlock); if (slot_use_count) dev_dbg(state->dev, "core: %d: qm:%d %s,%zx - slot_use->%d (hdr %p)\n", @@ -1322,13 +1319,13 @@ notify_bulks(struct vchiq_service *service, struct vchiq_bulk_queue *queue, if (bulk->mode == VCHIQ_BULK_MODE_BLOCKING) { struct bulk_waiter *waiter; - spin_lock(&bulk_waiter_spinlock); + spin_lock(&service->state->bulk_waiter_spinlock); waiter = bulk->userdata; if (waiter) { waiter->actual = bulk->actual; complete(&waiter->event); } - spin_unlock(&bulk_waiter_spinlock); + spin_unlock(&service->state->bulk_waiter_spinlock); } else if (bulk->mode == VCHIQ_BULK_MODE_CALLBACK) { enum vchiq_reason reason = get_bulk_reason(bulk); @@ -2169,6 +2166,10 @@ vchiq_init_state(struct vchiq_state *state, struct vchiq_slot_zero *slot_zero, s mutex_init(&state->sync_mutex); mutex_init(&state->bulk_transfer_mutex); + spin_lock_init(&state->msg_queue_spinlock); + spin_lock_init(&state->bulk_waiter_spinlock); + spin_lock_init(&state->quota_spinlock); + init_completion(&state->slot_available_event); init_completion(&state->slot_remove_event); init_completion(&state->data_quota_event); diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h index 8ca74b12427b..96299e2a2984 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h @@ -11,6 +11,7 @@ #include #include #include +#include #include #include "../../include/linux/raspberrypi/vchiq.h" @@ -348,6 +349,12 @@ struct vchiq_state { struct mutex bulk_transfer_mutex; + spinlock_t msg_queue_spinlock; + + spinlock_t bulk_waiter_spinlock; + + spinlock_t quota_spinlock; + /* * Indicates the byte position within the stream from where the next * message will be read. The least significant bits are an index into diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_dev.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_dev.c index 4d9deeeb637a..739ce529a71b 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_dev.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_dev.c @@ -220,10 +220,10 @@ static int vchiq_ioc_dequeue_message(struct vchiq_instance *instance, goto out; } - spin_lock(&msg_queue_spinlock); + spin_lock(&service->state->msg_queue_spinlock); if (user_service->msg_remove == user_service->msg_insert) { if (!args->blocking) { - spin_unlock(&msg_queue_spinlock); + spin_unlock(&service->state->msg_queue_spinlock); DEBUG_TRACE(DEQUEUE_MESSAGE_LINE); ret = -EWOULDBLOCK; goto out; @@ -231,14 +231,14 @@ static int vchiq_ioc_dequeue_message(struct vchiq_instance *instance, user_service->dequeue_pending = 1; ret = 0; do { - spin_unlock(&msg_queue_spinlock); + spin_unlock(&service->state->msg_queue_spinlock); DEBUG_TRACE(DEQUEUE_MESSAGE_LINE); if (wait_for_completion_interruptible(&user_service->insert_event)) { dev_dbg(service->state->dev, "arm: DEQUEUE_MESSAGE interrupted\n"); ret = -EINTR; break; } - spin_lock(&msg_queue_spinlock); + spin_lock(&service->state->msg_queue_spinlock); } while (user_service->msg_remove == user_service->msg_insert); if (ret) @@ -247,7 +247,7 @@ static int vchiq_ioc_dequeue_message(struct vchiq_instance *instance, if (WARN_ON_ONCE((int)(user_service->msg_insert - user_service->msg_remove) < 0)) { - spin_unlock(&msg_queue_spinlock); + spin_unlock(&service->state->msg_queue_spinlock); ret = -EINVAL; goto out; } @@ -255,7 +255,7 @@ static int vchiq_ioc_dequeue_message(struct vchiq_instance *instance, header = user_service->msg_queue[user_service->msg_remove & (MSG_QUEUE_SIZE - 1)]; user_service->msg_remove++; - spin_unlock(&msg_queue_spinlock); + spin_unlock(&service->state->msg_queue_spinlock); complete(&user_service->remove_event); if (!header) { @@ -340,9 +340,9 @@ static int vchiq_irq_queue_bulk_tx_rx(struct vchiq_instance *instance, !waiter->bulk_waiter.bulk) { if (waiter->bulk_waiter.bulk) { /* Cancel the signal when the transfer completes. */ - spin_lock(&bulk_waiter_spinlock); + spin_lock(&service->state->bulk_waiter_spinlock); waiter->bulk_waiter.bulk->userdata = NULL; - spin_unlock(&bulk_waiter_spinlock); + spin_unlock(&service->state->bulk_waiter_spinlock); } kfree(waiter); ret = 0; @@ -1246,7 +1246,7 @@ static int vchiq_release(struct inode *inode, struct file *file) break; } - spin_lock(&msg_queue_spinlock); + spin_lock(&service->state->msg_queue_spinlock); while (user_service->msg_remove != user_service->msg_insert) { struct vchiq_header *header; @@ -1254,14 +1254,14 @@ static int vchiq_release(struct inode *inode, struct file *file) header = user_service->msg_queue[m]; user_service->msg_remove++; - spin_unlock(&msg_queue_spinlock); + spin_unlock(&service->state->msg_queue_spinlock); if (header) vchiq_release_message(instance, service->handle, header); - spin_lock(&msg_queue_spinlock); + spin_lock(&service->state->msg_queue_spinlock); } - spin_unlock(&msg_queue_spinlock); + spin_unlock(&service->state->msg_queue_spinlock); vchiq_service_put(service); } -- cgit v1.2.3-59-g8ed1b From 7f56c601cae8e5f9a972dbcb45de227fe2235e83 Mon Sep 17 00:00:00 2001 From: Umang Jain Date: Fri, 12 Apr 2024 13:27:41 +0530 Subject: staging: vc04_services: vchiq_mmal: Rename service_callback() Rename the service_callback static function to mmal_service_callback() since the function signature conflicts with: extern int service_callback(struct vchiq_instance *vchiq_instance, enum vchiq_reason reason, struct vchiq_header *header, unsigned int handle, void *bulk_userdata); in vc04_services/interface/vchiq_arm/vchiq_arm.h In a subsequent patch, we will include vchiq_arm.h header to mmal-vchiq.c, which will then complain of this conflict. Hence, this patch is meant to handle the conflict beforehand. Reviewed-by: Laurent Pinchart Signed-off-by: Umang Jain Reviewed-by: Stefan Wahren Link: https://lore.kernel.org/r/20240412075743.60712-10-umang.jain@ideasonboard.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c index 4c3684dd902e..680961a7c61b 100644 --- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c +++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c @@ -548,9 +548,9 @@ static void bulk_abort_cb(struct vchiq_mmal_instance *instance, } /* incoming event service callback */ -static int service_callback(struct vchiq_instance *vchiq_instance, - enum vchiq_reason reason, struct vchiq_header *header, - unsigned int handle, void *bulk_ctx) +static int mmal_service_callback(struct vchiq_instance *vchiq_instance, + enum vchiq_reason reason, struct vchiq_header *header, + unsigned int handle, void *bulk_ctx) { struct vchiq_mmal_instance *instance = vchiq_get_service_userdata(vchiq_instance, handle); u32 msg_len; @@ -1862,7 +1862,7 @@ int vchiq_mmal_init(struct vchiq_mmal_instance **out_instance) .version = VC_MMAL_VER, .version_min = VC_MMAL_MIN_VER, .fourcc = VCHIQ_MAKE_FOURCC('m', 'm', 'a', 'l'), - .callback = service_callback, + .callback = mmal_service_callback, .userdata = NULL, }; -- cgit v1.2.3-59-g8ed1b From 42a2f6664e18874302623f31edef545ef41e1d14 Mon Sep 17 00:00:00 2001 From: Umang Jain Date: Fri, 12 Apr 2024 13:27:42 +0530 Subject: staging: vc04_services: Move global g_state to vchiq_state The patch intended to drop the g_state pointer. g_state is supposed to be a central place to track the state via vchiq_state. This is now moved to be contained in the struct vchiq_drv_mgmt. As a result vchiq_get_state() is also removed. In order to have access to vchiq_drv_mgmt, vchiq_initialise() and vchiq_mmal_init() are modified to receive a struct device pointer as one of their function parameter The vchiq_state pointer is now passed directly to vchiq_dump_platform_instances() to get access to the state instead getting it via vchiq_get_state(). For the char device, struct miscdevice is retrieved by struct file's private data in vchiq_open and struct vchiq_drv_mgmt is retrieved thereafter. Removal of global variable members is now addressed hence, drop the corresponding item from the TODO list. Signed-off-by: Umang Jain Link: https://lore.kernel.org/r/20240412075743.60712-11-umang.jain@ideasonboard.com Signed-off-by: Greg Kroah-Hartman --- .../vc04_services/bcm2835-audio/bcm2835-vchiq.c | 5 ++- .../vc04_services/bcm2835-camera/bcm2835-camera.c | 4 +-- .../include/linux/raspberrypi/vchiq.h | 4 ++- drivers/staging/vc04_services/interface/TODO | 8 ----- .../vc04_services/interface/vchiq_arm/vchiq_arm.c | 36 +++++----------------- .../vc04_services/interface/vchiq_arm/vchiq_arm.h | 7 ++--- .../vc04_services/interface/vchiq_arm/vchiq_core.c | 2 +- .../vc04_services/interface/vchiq_arm/vchiq_core.h | 2 +- .../interface/vchiq_arm/vchiq_debugfs.c | 5 ++- .../vc04_services/interface/vchiq_arm/vchiq_dev.c | 10 +++--- .../staging/vc04_services/vchiq-mmal/mmal-vchiq.c | 6 ++-- .../staging/vc04_services/vchiq-mmal/mmal-vchiq.h | 3 +- 12 files changed, 37 insertions(+), 55 deletions(-) diff --git a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c index d74110ca17ab..133ed15f3dbc 100644 --- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c +++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c @@ -7,6 +7,8 @@ #include "bcm2835.h" #include "vc_vchi_audioserv_defs.h" +#include "../interface/vchiq_arm/vchiq_arm.h" + struct bcm2835_audio_instance { struct device *dev; unsigned int service_handle; @@ -175,10 +177,11 @@ static void vc_vchi_audio_deinit(struct bcm2835_audio_instance *instance) int bcm2835_new_vchi_ctx(struct device *dev, struct bcm2835_vchi_ctx *vchi_ctx) { + struct vchiq_drv_mgmt *mgmt = dev_get_drvdata(dev->parent); int ret; /* Initialize and create a VCHI connection */ - ret = vchiq_initialise(&vchi_ctx->instance); + ret = vchiq_initialise(&mgmt->state, &vchi_ctx->instance); if (ret) { dev_err(dev, "failed to initialise VCHI instance (ret=%d)\n", ret); diff --git a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c index c3ba490e53cb..b3599ec6293a 100644 --- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c +++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c @@ -1555,7 +1555,7 @@ static int mmal_init(struct bcm2835_mmal_dev *dev) u32 param_size; struct vchiq_mmal_component *camera; - ret = vchiq_mmal_init(&dev->instance); + ret = vchiq_mmal_init(dev->v4l2_dev.dev, &dev->instance); if (ret < 0) { v4l2_err(&dev->v4l2_dev, "%s: vchiq mmal init failed %d\n", __func__, ret); @@ -1854,7 +1854,7 @@ static int bcm2835_mmal_probe(struct vchiq_device *device) return ret; } - ret = vchiq_mmal_init(&instance); + ret = vchiq_mmal_init(&device->dev, &instance); if (ret < 0) return ret; diff --git a/drivers/staging/vc04_services/include/linux/raspberrypi/vchiq.h b/drivers/staging/vc04_services/include/linux/raspberrypi/vchiq.h index 52e106f117da..6c40d8c1dde6 100644 --- a/drivers/staging/vc04_services/include/linux/raspberrypi/vchiq.h +++ b/drivers/staging/vc04_services/include/linux/raspberrypi/vchiq.h @@ -48,6 +48,7 @@ struct vchiq_element { }; struct vchiq_instance; +struct vchiq_state; struct vchiq_service_base { int fourcc; @@ -78,7 +79,8 @@ struct vchiq_service_params_kernel { short version_min; /* Update for incompatible changes */ }; -extern int vchiq_initialise(struct vchiq_instance **pinstance); +extern int vchiq_initialise(struct vchiq_state *state, + struct vchiq_instance **pinstance); extern int vchiq_shutdown(struct vchiq_instance *instance); extern int vchiq_connect(struct vchiq_instance *instance); extern int vchiq_open_service(struct vchiq_instance *instance, diff --git a/drivers/staging/vc04_services/interface/TODO b/drivers/staging/vc04_services/interface/TODO index 05eb5140d096..15f12b8f213e 100644 --- a/drivers/staging/vc04_services/interface/TODO +++ b/drivers/staging/vc04_services/interface/TODO @@ -41,14 +41,6 @@ The code follows the 80 characters limitation yet tends to go 3 or 4 levels of indentation deep making it very unpleasant to read. This is specially relevant in the character driver ioctl code and in the core thread functions. -* Get rid of all non essential global structures and create a proper per -device structure - -The first thing one generally sees in a probe function is a memory allocation -for all the device specific data. This structure is then passed all over the -driver. This is good practice since it makes the driver work regardless of the -number of devices probed. - * Clean up Sparse warnings from __user annotations. See vchiq_irq_queue_bulk_tx_rx(). Ensure that the address of "&waiter->bulk_waiter" is never disclosed to userspace. diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c index 4bdd383a060c..502ddc0f6e46 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c @@ -59,8 +59,6 @@ #define KEEPALIVE_VER 1 #define KEEPALIVE_VER_MIN KEEPALIVE_VER -struct vchiq_state g_state; - /* * The devices implemented in the VCHIQ firmware are not discoverable, * so we need to maintain a list of them in order to register them with @@ -698,9 +696,8 @@ void vchiq_dump_platform_state(struct seq_file *f) } #define VCHIQ_INIT_RETRIES 10 -int vchiq_initialise(struct vchiq_instance **instance_out) +int vchiq_initialise(struct vchiq_state *state, struct vchiq_instance **instance_out) { - struct vchiq_state *state; struct vchiq_instance *instance = NULL; int i, ret; @@ -710,7 +707,6 @@ int vchiq_initialise(struct vchiq_instance **instance_out) * block forever. */ for (i = 0; i < VCHIQ_INIT_RETRIES; i++) { - state = vchiq_get_state(); if (state) break; usleep_range(500, 600); @@ -1026,9 +1022,10 @@ add_completion(struct vchiq_instance *instance, enum vchiq_reason reason, void *bulk_userdata) { struct vchiq_completion_data_kernel *completion; + struct vchiq_drv_mgmt *mgmt = dev_get_drvdata(instance->state->dev); int insert; - DEBUG_INITIALISE(g_state.local); + DEBUG_INITIALISE(mgmt->state.local); insert = instance->completion_insert; while ((insert - instance->completion_remove) >= MAX_COMPLETIONS) { @@ -1091,11 +1088,12 @@ service_callback(struct vchiq_instance *instance, enum vchiq_reason reason, * containing the original callback and the user state structure, which * contains a circular buffer for completion records. */ + struct vchiq_drv_mgmt *mgmt = dev_get_drvdata(instance->state->dev); struct user_service *user_service; struct vchiq_service *service; bool skip_completion = false; - DEBUG_INITIALISE(g_state.local); + DEBUG_INITIALISE(mgmt->state.local); DEBUG_TRACE(SERVICE_CALLBACK_LINE); @@ -1200,9 +1198,8 @@ service_callback(struct vchiq_instance *instance, enum vchiq_reason reason, bulk_userdata); } -void vchiq_dump_platform_instances(struct seq_file *f) +void vchiq_dump_platform_instances(struct vchiq_state *state, struct seq_file *f) { - struct vchiq_state *state = vchiq_get_state(); int i; if (!state) @@ -1277,23 +1274,6 @@ void vchiq_dump_platform_service_state(struct seq_file *f, seq_puts(f, "\n"); } -struct vchiq_state * -vchiq_get_state(void) -{ - if (!g_state.remote) { - pr_err("%s: g_state.remote == NULL\n", __func__); - return NULL; - } - - if (g_state.remote->initialised != 1) { - pr_notice("%s: g_state.remote->initialised != 1 (%d)\n", - __func__, g_state.remote->initialised); - return NULL; - } - - return &g_state; -} - /* * Autosuspend related functionality */ @@ -1327,7 +1307,7 @@ vchiq_keepalive_thread_func(void *v) .version_min = KEEPALIVE_VER_MIN }; - ret = vchiq_initialise(&instance); + ret = vchiq_initialise(state, &instance); if (ret) { dev_err(state->dev, "suspend: %s: vchiq_initialise failed %d\n", __func__, ret); goto exit; @@ -1775,7 +1755,7 @@ static int vchiq_probe(struct platform_device *pdev) mgmt->info = info; platform_set_drvdata(pdev, mgmt); - err = vchiq_platform_init(pdev, &g_state); + err = vchiq_platform_init(pdev, &mgmt->state); if (err) goto failed_platform_init; diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h index 127e2d6b1d51..fd1b9d3555ce 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h @@ -52,6 +52,8 @@ struct vchiq_drv_mgmt { unsigned int fragments_size; void __iomem *regs; + + struct vchiq_state state; }; struct user_service { @@ -98,11 +100,6 @@ struct vchiq_instance { struct vchiq_debugfs_node debugfs_node; }; -extern struct vchiq_state g_state; - -extern struct vchiq_state * -vchiq_get_state(void); - int vchiq_use_service(struct vchiq_instance *instance, unsigned int handle); diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c index 52a11c743bd6..3397365e551e 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c @@ -3505,7 +3505,7 @@ void vchiq_dump_state(struct seq_file *f, struct vchiq_state *state) vchiq_dump_shared_state(f, state, state->remote, "Remote"); - vchiq_dump_platform_instances(f); + vchiq_dump_platform_instances(state, f); for (i = 0; i < state->unused_service; i++) { struct vchiq_service *service = find_service_by_port(state, i); diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h index 96299e2a2984..8af209e34fb2 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h @@ -527,7 +527,7 @@ void remote_event_signal(struct vchiq_state *state, struct remote_event *event); void vchiq_dump_platform_state(struct seq_file *f); -void vchiq_dump_platform_instances(struct seq_file *f); +void vchiq_dump_platform_instances(struct vchiq_state *state, struct seq_file *f); void vchiq_dump_platform_service_state(struct seq_file *f, struct vchiq_service *service); diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.c index d833e4e2973a..54e7bf029d9a 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.c @@ -42,7 +42,10 @@ static int debugfs_trace_show(struct seq_file *f, void *offset) static int vchiq_dump_show(struct seq_file *f, void *offset) { - vchiq_dump_state(f, &g_state); + struct vchiq_instance *instance = f->private; + + vchiq_dump_state(f, instance->state); + return 0; } DEFINE_SHOW_ATTRIBUTE(vchiq_dump); diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_dev.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_dev.c index 739ce529a71b..9fe35864936c 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_dev.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_dev.c @@ -208,7 +208,7 @@ static int vchiq_ioc_dequeue_message(struct vchiq_instance *instance, struct vchiq_header *header; int ret; - DEBUG_INITIALISE(g_state.local); + DEBUG_INITIALISE(instance->state->local); DEBUG_TRACE(DEQUEUE_MESSAGE_LINE); service = find_service_for_instance(instance, args->handle); if (!service) @@ -435,7 +435,7 @@ static int vchiq_ioc_await_completion(struct vchiq_instance *instance, int remove; int ret; - DEBUG_INITIALISE(g_state.local); + DEBUG_INITIALISE(instance->state->local); DEBUG_TRACE(AWAIT_COMPLETION_LINE); if (!instance->connected) @@ -1163,7 +1163,9 @@ vchiq_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) static int vchiq_open(struct inode *inode, struct file *file) { - struct vchiq_state *state = vchiq_get_state(); + struct miscdevice *vchiq_miscdev = file->private_data; + struct vchiq_drv_mgmt *mgmt = dev_get_drvdata(vchiq_miscdev->parent); + struct vchiq_state *state = &mgmt->state; struct vchiq_instance *instance; dev_dbg(state->dev, "arm: vchiq open\n"); @@ -1196,7 +1198,7 @@ static int vchiq_open(struct inode *inode, struct file *file) static int vchiq_release(struct inode *inode, struct file *file) { struct vchiq_instance *instance = file->private_data; - struct vchiq_state *state = vchiq_get_state(); + struct vchiq_state *state = instance->state; struct vchiq_service *service; int ret = 0; int i; diff --git a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c index 680961a7c61b..fca920d41e4f 100644 --- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c +++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c @@ -26,6 +26,7 @@ #include #include "../include/linux/raspberrypi/vchiq.h" +#include "../interface/vchiq_arm/vchiq_arm.h" #include "mmal-common.h" #include "mmal-vchiq.h" #include "mmal-msg.h" @@ -1852,7 +1853,7 @@ int vchiq_mmal_finalise(struct vchiq_mmal_instance *instance) } EXPORT_SYMBOL_GPL(vchiq_mmal_finalise); -int vchiq_mmal_init(struct vchiq_mmal_instance **out_instance) +int vchiq_mmal_init(struct device *dev, struct vchiq_mmal_instance **out_instance) { int status; int err = -ENODEV; @@ -1865,6 +1866,7 @@ int vchiq_mmal_init(struct vchiq_mmal_instance **out_instance) .callback = mmal_service_callback, .userdata = NULL, }; + struct vchiq_drv_mgmt *mgmt = dev_get_drvdata(dev->parent); /* compile time checks to ensure structure size as they are * directly (de)serialised from memory. @@ -1880,7 +1882,7 @@ int vchiq_mmal_init(struct vchiq_mmal_instance **out_instance) BUILD_BUG_ON(sizeof(struct mmal_port) != 64); /* create a vchi instance */ - status = vchiq_initialise(&vchiq_instance); + status = vchiq_initialise(&mgmt->state, &vchiq_instance); if (status) { pr_err("Failed to initialise VCHI instance (status=%d)\n", status); diff --git a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h index 98909fde978e..97abe4bdcfc5 100644 --- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h +++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h @@ -25,6 +25,7 @@ #define MMAL_FORMAT_EXTRADATA_MAX_SIZE 128 struct vchiq_mmal_instance; +struct device; enum vchiq_mmal_es_type { MMAL_ES_TYPE_UNKNOWN, /**< Unknown elementary stream type */ @@ -94,7 +95,7 @@ struct vchiq_mmal_component { u32 client_component; /* Used to ref back to client struct */ }; -int vchiq_mmal_init(struct vchiq_mmal_instance **out_instance); +int vchiq_mmal_init(struct device *dev, struct vchiq_mmal_instance **out_instance); int vchiq_mmal_finalise(struct vchiq_mmal_instance *instance); /* Initialise a mmal component and its ports -- cgit v1.2.3-59-g8ed1b From 75ff53c44f5e151d21d949416633b56e56160124 Mon Sep 17 00:00:00 2001 From: Umang Jain Date: Fri, 12 Apr 2024 13:27:43 +0530 Subject: staging: vc04_services: Drop completed TODO item The memory barrier comments are added in commit f6c99d86246a ("staging: vchiq_arm: Add missing memory barrier comments") Drop the respective item from the TODO list. Reviewed-by: Dan Carpenter Signed-off-by: Umang Jain Link: https://lore.kernel.org/r/20240412075743.60712-12-umang.jain@ideasonboard.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vc04_services/interface/TODO | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/staging/vc04_services/interface/TODO b/drivers/staging/vc04_services/interface/TODO index 15f12b8f213e..05f129c0c254 100644 --- a/drivers/staging/vc04_services/interface/TODO +++ b/drivers/staging/vc04_services/interface/TODO @@ -28,13 +28,6 @@ variables avoided. A short top-down description of this driver's architecture (function of kthreads, userspace, limitations) could be very helpful for reviewers. -* Review and comment memory barriers - -There is a heavy use of memory barriers in this driver, it would be very -beneficial to go over all of them and, if correct, comment on their merits. -Extra points to whomever confidently reviews the remote_event_*() family of -functions. - * Reformat core code with more sane indentations The code follows the 80 characters limitation yet tends to go 3 or 4 levels of -- cgit v1.2.3-59-g8ed1b From 6b9391b581fddd8579239dad4de4f0393149e10a Mon Sep 17 00:00:00 2001 From: Charlie Jenkins Date: Tue, 12 Mar 2024 16:53:41 -0700 Subject: riscv: Include riscv_set_icache_flush_ctx prctl Support new prctl with key PR_RISCV_SET_ICACHE_FLUSH_CTX to enable optimization of cross modifying code. This prctl enables userspace code to use icache flushing instructions such as fence.i with the guarantee that the icache will continue to be clean after thread migration. Signed-off-by: Charlie Jenkins Reviewed-by: Atish Patra Reviewed-by: Alexandre Ghiti Reviewed-by: Samuel Holland Link: https://lore.kernel.org/r/20240312-fencei-v13-2-4b6bdc2bbf32@rivosinc.com Signed-off-by: Palmer Dabbelt --- arch/riscv/include/asm/mmu.h | 2 + arch/riscv/include/asm/processor.h | 10 ++++ arch/riscv/include/asm/switch_to.h | 23 ++++++++ arch/riscv/mm/cacheflush.c | 113 +++++++++++++++++++++++++++++++++++++ arch/riscv/mm/context.c | 19 ++++--- include/uapi/linux/prctl.h | 6 ++ kernel/sys.c | 6 ++ 7 files changed, 171 insertions(+), 8 deletions(-) diff --git a/arch/riscv/include/asm/mmu.h b/arch/riscv/include/asm/mmu.h index 355504b37f8e..60be458e94da 100644 --- a/arch/riscv/include/asm/mmu.h +++ b/arch/riscv/include/asm/mmu.h @@ -19,6 +19,8 @@ typedef struct { #ifdef CONFIG_SMP /* A local icache flush is needed before user execution can resume. */ cpumask_t icache_stale_mask; + /* Force local icache flush on all migrations. */ + bool force_icache_flush; #endif #ifdef CONFIG_BINFMT_ELF_FDPIC unsigned long exec_fdpic_loadmap; diff --git a/arch/riscv/include/asm/processor.h b/arch/riscv/include/asm/processor.h index a8509cc31ab2..cca62013c3c0 100644 --- a/arch/riscv/include/asm/processor.h +++ b/arch/riscv/include/asm/processor.h @@ -69,6 +69,7 @@ #endif #ifndef __ASSEMBLY__ +#include struct task_struct; struct pt_regs; @@ -123,6 +124,12 @@ struct thread_struct { struct __riscv_v_ext_state vstate; unsigned long align_ctl; struct __riscv_v_ext_state kernel_vstate; +#ifdef CONFIG_SMP + /* Flush the icache on migration */ + bool force_icache_flush; + /* A forced icache flush is not needed if migrating to the previous cpu. */ + unsigned int prev_cpu; +#endif }; /* Whitelist the fstate from the task_struct for hardened usercopy */ @@ -184,6 +191,9 @@ extern int set_unalign_ctl(struct task_struct *tsk, unsigned int val); #define GET_UNALIGN_CTL(tsk, addr) get_unalign_ctl((tsk), (addr)) #define SET_UNALIGN_CTL(tsk, val) set_unalign_ctl((tsk), (val)) +#define RISCV_SET_ICACHE_FLUSH_CTX(arg1, arg2) riscv_set_icache_flush_ctx(arg1, arg2) +extern int riscv_set_icache_flush_ctx(unsigned long ctx, unsigned long per_thread); + #endif /* __ASSEMBLY__ */ #endif /* _ASM_RISCV_PROCESSOR_H */ diff --git a/arch/riscv/include/asm/switch_to.h b/arch/riscv/include/asm/switch_to.h index 7efdb0584d47..7594df37cc9f 100644 --- a/arch/riscv/include/asm/switch_to.h +++ b/arch/riscv/include/asm/switch_to.h @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -72,14 +73,36 @@ static __always_inline bool has_fpu(void) { return false; } extern struct task_struct *__switch_to(struct task_struct *, struct task_struct *); +static inline bool switch_to_should_flush_icache(struct task_struct *task) +{ +#ifdef CONFIG_SMP + bool stale_mm = task->mm && task->mm->context.force_icache_flush; + bool stale_thread = task->thread.force_icache_flush; + bool thread_migrated = smp_processor_id() != task->thread.prev_cpu; + + return thread_migrated && (stale_mm || stale_thread); +#else + return false; +#endif +} + +#ifdef CONFIG_SMP +#define __set_prev_cpu(thread) ((thread).prev_cpu = smp_processor_id()) +#else +#define __set_prev_cpu(thread) +#endif + #define switch_to(prev, next, last) \ do { \ struct task_struct *__prev = (prev); \ struct task_struct *__next = (next); \ + __set_prev_cpu(__prev->thread); \ if (has_fpu()) \ __switch_to_fpu(__prev, __next); \ if (has_vector()) \ __switch_to_vector(__prev, __next); \ + if (switch_to_should_flush_icache(__next)) \ + local_flush_icache_all(); \ ((last) = __switch_to(__prev, __next)); \ } while (0) diff --git a/arch/riscv/mm/cacheflush.c b/arch/riscv/mm/cacheflush.c index 55a34f2020a8..15a95578e670 100644 --- a/arch/riscv/mm/cacheflush.c +++ b/arch/riscv/mm/cacheflush.c @@ -5,6 +5,7 @@ #include #include +#include #include #include @@ -152,3 +153,115 @@ void __init riscv_init_cbo_blocksizes(void) if (cboz_block_size) riscv_cboz_block_size = cboz_block_size; } + +#ifdef CONFIG_SMP +static void set_icache_stale_mask(void) +{ + cpumask_t *mask; + bool stale_cpu; + + /* + * Mark every other hart's icache as needing a flush for + * this MM. Maintain the previous value of the current + * cpu to handle the case when this function is called + * concurrently on different harts. + */ + mask = ¤t->mm->context.icache_stale_mask; + stale_cpu = cpumask_test_cpu(smp_processor_id(), mask); + + cpumask_setall(mask); + assign_bit(cpumask_check(smp_processor_id()), cpumask_bits(mask), stale_cpu); +} +#endif + +/** + * riscv_set_icache_flush_ctx() - Enable/disable icache flushing instructions in + * userspace. + * @ctx: Set the type of icache flushing instructions permitted/prohibited in + * userspace. Supported values described below. + * + * Supported values for ctx: + * + * * %PR_RISCV_CTX_SW_FENCEI_ON: Allow fence.i in user space. + * + * * %PR_RISCV_CTX_SW_FENCEI_OFF: Disallow fence.i in user space. All threads in + * a process will be affected when ``scope == PR_RISCV_SCOPE_PER_PROCESS``. + * Therefore, caution must be taken; use this flag only when you can guarantee + * that no thread in the process will emit fence.i from this point onward. + * + * @scope: Set scope of where icache flushing instructions are allowed to be + * emitted. Supported values described below. + * + * Supported values for scope: + * + * * %PR_RISCV_SCOPE_PER_PROCESS: Ensure the icache of any thread in this process + * is coherent with instruction storage upon + * migration. + * + * * %PR_RISCV_SCOPE_PER_THREAD: Ensure the icache of the current thread is + * coherent with instruction storage upon + * migration. + * + * When ``scope == PR_RISCV_SCOPE_PER_PROCESS``, all threads in the process are + * permitted to emit icache flushing instructions. Whenever any thread in the + * process is migrated, the corresponding hart's icache will be guaranteed to be + * consistent with instruction storage. This does not enforce any guarantees + * outside of migration. If a thread modifies an instruction that another thread + * may attempt to execute, the other thread must still emit an icache flushing + * instruction before attempting to execute the potentially modified + * instruction. This must be performed by the user-space program. + * + * In per-thread context (eg. ``scope == PR_RISCV_SCOPE_PER_THREAD``) only the + * thread calling this function is permitted to emit icache flushing + * instructions. When the thread is migrated, the corresponding hart's icache + * will be guaranteed to be consistent with instruction storage. + * + * On kernels configured without SMP, this function is a nop as migrations + * across harts will not occur. + */ +int riscv_set_icache_flush_ctx(unsigned long ctx, unsigned long scope) +{ +#ifdef CONFIG_SMP + switch (ctx) { + case PR_RISCV_CTX_SW_FENCEI_ON: + switch (scope) { + case PR_RISCV_SCOPE_PER_PROCESS: + current->mm->context.force_icache_flush = true; + break; + case PR_RISCV_SCOPE_PER_THREAD: + current->thread.force_icache_flush = true; + break; + default: + return -EINVAL; + } + break; + case PR_RISCV_CTX_SW_FENCEI_OFF: + switch (scope) { + case PR_RISCV_SCOPE_PER_PROCESS: + current->mm->context.force_icache_flush = false; + + set_icache_stale_mask(); + break; + case PR_RISCV_SCOPE_PER_THREAD: + current->thread.force_icache_flush = false; + + set_icache_stale_mask(); + break; + default: + return -EINVAL; + } + break; + default: + return -EINVAL; + } + return 0; +#else + switch (ctx) { + case PR_RISCV_CTX_SW_FENCEI_ON: + case PR_RISCV_CTX_SW_FENCEI_OFF: + return 0; + default: + return -EINVAL; + } +#endif +} diff --git a/arch/riscv/mm/context.c b/arch/riscv/mm/context.c index 217fd4de6134..beef30f42d5c 100644 --- a/arch/riscv/mm/context.c +++ b/arch/riscv/mm/context.c @@ -15,6 +15,7 @@ #include #include #include +#include #ifdef CONFIG_MMU @@ -297,21 +298,23 @@ static inline void set_mm(struct mm_struct *prev, * * The "cpu" argument must be the current local CPU number. */ -static inline void flush_icache_deferred(struct mm_struct *mm, unsigned int cpu) +static inline void flush_icache_deferred(struct mm_struct *mm, unsigned int cpu, + struct task_struct *task) { #ifdef CONFIG_SMP - cpumask_t *mask = &mm->context.icache_stale_mask; - - if (cpumask_test_cpu(cpu, mask)) { - cpumask_clear_cpu(cpu, mask); + if (cpumask_test_and_clear_cpu(cpu, &mm->context.icache_stale_mask)) { /* * Ensure the remote hart's writes are visible to this hart. * This pairs with a barrier in flush_icache_mm. */ smp_mb(); - local_flush_icache_all(); - } + /* + * If cache will be flushed in switch_to, no need to flush here. + */ + if (!(task && switch_to_should_flush_icache(task))) + local_flush_icache_all(); + } #endif } @@ -332,5 +335,5 @@ void switch_mm(struct mm_struct *prev, struct mm_struct *next, set_mm(prev, next, cpu); - flush_icache_deferred(next, cpu); + flush_icache_deferred(next, cpu, task); } diff --git a/include/uapi/linux/prctl.h b/include/uapi/linux/prctl.h index 370ed14b1ae0..524d546d697b 100644 --- a/include/uapi/linux/prctl.h +++ b/include/uapi/linux/prctl.h @@ -306,4 +306,10 @@ struct prctl_mm_map { # define PR_RISCV_V_VSTATE_CTRL_NEXT_MASK 0xc # define PR_RISCV_V_VSTATE_CTRL_MASK 0x1f +#define PR_RISCV_SET_ICACHE_FLUSH_CTX 71 +# define PR_RISCV_CTX_SW_FENCEI_ON 0 +# define PR_RISCV_CTX_SW_FENCEI_OFF 1 +# define PR_RISCV_SCOPE_PER_PROCESS 0 +# define PR_RISCV_SCOPE_PER_THREAD 1 + #endif /* _LINUX_PRCTL_H */ diff --git a/kernel/sys.c b/kernel/sys.c index e219fcfa112d..69afdd8b430f 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -146,6 +146,9 @@ #ifndef RISCV_V_GET_CONTROL # define RISCV_V_GET_CONTROL() (-EINVAL) #endif +#ifndef RISCV_SET_ICACHE_FLUSH_CTX +# define RISCV_SET_ICACHE_FLUSH_CTX(a, b) (-EINVAL) +#endif /* * this is where the system-wide overflow UID and GID are defined, for @@ -2743,6 +2746,9 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3, case PR_RISCV_V_GET_CONTROL: error = RISCV_V_GET_CONTROL(); break; + case PR_RISCV_SET_ICACHE_FLUSH_CTX: + error = RISCV_SET_ICACHE_FLUSH_CTX(arg2, arg3); + break; default: error = -EINVAL; break; -- cgit v1.2.3-59-g8ed1b From 6a08e4709c58cb324a6324f07acec54e7764c32f Mon Sep 17 00:00:00 2001 From: Charlie Jenkins Date: Tue, 12 Mar 2024 16:53:42 -0700 Subject: documentation: Document PR_RISCV_SET_ICACHE_FLUSH_CTX prctl Provide documentation that explains how to properly do CMODX in riscv. Signed-off-by: Charlie Jenkins Reviewed-by: Atish Patra Reviewed-by: Alexandre Ghiti Link: https://lore.kernel.org/r/20240312-fencei-v13-3-4b6bdc2bbf32@rivosinc.com Signed-off-by: Palmer Dabbelt --- Documentation/arch/riscv/cmodx.rst | 98 ++++++++++++++++++++++++++++++++++++++ Documentation/arch/riscv/index.rst | 1 + 2 files changed, 99 insertions(+) create mode 100644 Documentation/arch/riscv/cmodx.rst diff --git a/Documentation/arch/riscv/cmodx.rst b/Documentation/arch/riscv/cmodx.rst new file mode 100644 index 000000000000..1c0ca06b6c97 --- /dev/null +++ b/Documentation/arch/riscv/cmodx.rst @@ -0,0 +1,98 @@ +.. SPDX-License-Identifier: GPL-2.0 + +============================================================================== +Concurrent Modification and Execution of Instructions (CMODX) for RISC-V Linux +============================================================================== + +CMODX is a programming technique where a program executes instructions that were +modified by the program itself. Instruction storage and the instruction cache +(icache) are not guaranteed to be synchronized on RISC-V hardware. Therefore, the +program must enforce its own synchronization with the unprivileged fence.i +instruction. + +However, the default Linux ABI prohibits the use of fence.i in userspace +applications. At any point the scheduler may migrate a task onto a new hart. If +migration occurs after the userspace synchronized the icache and instruction +storage with fence.i, the icache on the new hart will no longer be clean. This +is due to the behavior of fence.i only affecting the hart that it is called on. +Thus, the hart that the task has been migrated to may not have synchronized +instruction storage and icache. + +There are two ways to solve this problem: use the riscv_flush_icache() syscall, +or use the ``PR_RISCV_SET_ICACHE_FLUSH_CTX`` prctl() and emit fence.i in +userspace. The syscall performs a one-off icache flushing operation. The prctl +changes the Linux ABI to allow userspace to emit icache flushing operations. + +As an aside, "deferred" icache flushes can sometimes be triggered in the kernel. +At the time of writing, this only occurs during the riscv_flush_icache() syscall +and when the kernel uses copy_to_user_page(). These deferred flushes happen only +when the memory map being used by a hart changes. If the prctl() context caused +an icache flush, this deferred icache flush will be skipped as it is redundant. +Therefore, there will be no additional flush when using the riscv_flush_icache() +syscall inside of the prctl() context. + +prctl() Interface +--------------------- + +Call prctl() with ``PR_RISCV_SET_ICACHE_FLUSH_CTX`` as the first argument. The +remaining arguments will be delegated to the riscv_set_icache_flush_ctx +function detailed below. + +.. kernel-doc:: arch/riscv/mm/cacheflush.c + :identifiers: riscv_set_icache_flush_ctx + +Example usage: + +The following files are meant to be compiled and linked with each other. The +modify_instruction() function replaces an add with 0 with an add with one, +causing the instruction sequence in get_value() to change from returning a zero +to returning a one. + +cmodx.c:: + + #include + #include + + extern int get_value(); + extern void modify_instruction(); + + int main() + { + int value = get_value(); + printf("Value before cmodx: %d\n", value); + + // Call prctl before first fence.i is called inside modify_instruction + prctl(PR_RISCV_SET_ICACHE_FLUSH_CTX_ON, PR_RISCV_CTX_SW_FENCEI, PR_RISCV_SCOPE_PER_PROCESS); + modify_instruction(); + // Call prctl after final fence.i is called in process + prctl(PR_RISCV_SET_ICACHE_FLUSH_CTX_OFF, PR_RISCV_CTX_SW_FENCEI, PR_RISCV_SCOPE_PER_PROCESS); + + value = get_value(); + printf("Value after cmodx: %d\n", value); + return 0; + } + +cmodx.S:: + + .option norvc + + .text + .global modify_instruction + modify_instruction: + lw a0, new_insn + lui a5,%hi(old_insn) + sw a0,%lo(old_insn)(a5) + fence.i + ret + + .section modifiable, "awx" + .global get_value + get_value: + li a0, 0 + old_insn: + addi a0, a0, 0 + ret + + .data + new_insn: + addi a0, a0, 1 diff --git a/Documentation/arch/riscv/index.rst b/Documentation/arch/riscv/index.rst index 4dab0cb4b900..eecf347ce849 100644 --- a/Documentation/arch/riscv/index.rst +++ b/Documentation/arch/riscv/index.rst @@ -13,6 +13,7 @@ RISC-V architecture patch-acceptance uabi vector + cmodx features -- cgit v1.2.3-59-g8ed1b From decde1fa209323c77a7498e803350c5f3e992d62 Mon Sep 17 00:00:00 2001 From: Charlie Jenkins Date: Tue, 12 Mar 2024 16:53:43 -0700 Subject: cpumask: Add assign cpu Standardize an assign_cpu function for cpumasks. Signed-off-by: Charlie Jenkins Link: https://lore.kernel.org/r/20240312-fencei-v13-4-4b6bdc2bbf32@rivosinc.com Signed-off-by: Palmer Dabbelt --- arch/riscv/mm/cacheflush.c | 2 +- include/linux/cpumask.h | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/arch/riscv/mm/cacheflush.c b/arch/riscv/mm/cacheflush.c index 15a95578e670..9dad35f0ce8b 100644 --- a/arch/riscv/mm/cacheflush.c +++ b/arch/riscv/mm/cacheflush.c @@ -170,7 +170,7 @@ static void set_icache_stale_mask(void) stale_cpu = cpumask_test_cpu(smp_processor_id(), mask); cpumask_setall(mask); - assign_bit(cpumask_check(smp_processor_id()), cpumask_bits(mask), stale_cpu); + cpumask_assign_cpu(smp_processor_id(), mask, stale_cpu); } #endif diff --git a/include/linux/cpumask.h b/include/linux/cpumask.h index cfb545841a2c..1b85e09c4ba5 100644 --- a/include/linux/cpumask.h +++ b/include/linux/cpumask.h @@ -492,6 +492,22 @@ static __always_inline void __cpumask_clear_cpu(int cpu, struct cpumask *dstp) __clear_bit(cpumask_check(cpu), cpumask_bits(dstp)); } +/** + * cpumask_assign_cpu - assign a cpu in a cpumask + * @cpu: cpu number (< nr_cpu_ids) + * @dstp: the cpumask pointer + * @bool: the value to assign + */ +static __always_inline void cpumask_assign_cpu(int cpu, struct cpumask *dstp, bool value) +{ + assign_bit(cpumask_check(cpu), cpumask_bits(dstp), value); +} + +static __always_inline void __cpumask_assign_cpu(int cpu, struct cpumask *dstp, bool value) +{ + __assign_bit(cpumask_check(cpu), cpumask_bits(dstp), value); +} + /** * cpumask_test_cpu - test for a cpu in a cpumask * @cpu: cpu number (< nr_cpu_ids) -- cgit v1.2.3-59-g8ed1b From c7ae396ec597b2f3644f90f5c7278674b0527aa9 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Thu, 18 Apr 2024 20:29:21 +0200 Subject: PCI: Annotate pci_cache_line_size variables as __ro_after_init Annotate both variables as __ro_after_init, enforcing that they can't be changed after the init phase. Link: https://lore.kernel.org/r/52fd058d-6d72-48db-8e61-5fcddcd0aa51@gmail.com Signed-off-by: Heiner Kallweit Signed-off-by: Bjorn Helgaas --- drivers/pci/pci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index e5f243dd4288..9ee0d4e8808e 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -142,8 +142,8 @@ enum pcie_bus_config_types pcie_bus_config = PCIE_BUS_DEFAULT; * the dfl or actual value as it sees fit. Don't forget this is * measured in 32-bit words, not bytes. */ -u8 pci_dfl_cache_line_size = L1_CACHE_BYTES >> 2; -u8 pci_cache_line_size; +u8 pci_dfl_cache_line_size __ro_after_init = L1_CACHE_BYTES >> 2; +u8 pci_cache_line_size __ro_after_init ; /* * If we set up a device for bus mastering, we need to check the latency -- cgit v1.2.3-59-g8ed1b From eb4d27cf9aef3e6c9bcaf8fa1a1cadc2433d847b Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Tue, 16 Apr 2024 10:00:13 -0700 Subject: perf docs: Document bpf event modifier Document that 'b' is used as a modifier to make an event use a BPF counter. Fixes: 01bd8efcec444468 ("perf stat: Introduce ':b' modifier") Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Athira Rajeev Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Ravi Bangoria Cc: Song Liu Cc: Thomas Richter Link: https://lore.kernel.org/r/20240416170014.985191-1-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-list.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/perf/Documentation/perf-list.txt b/tools/perf/Documentation/perf-list.txt index 3b12595193c9..6bf2468f59d3 100644 --- a/tools/perf/Documentation/perf-list.txt +++ b/tools/perf/Documentation/perf-list.txt @@ -71,6 +71,7 @@ counted. The following modifiers exist: D - pin the event to the PMU W - group is weak and will fallback to non-group if not schedulable, e - group or event are exclusive and do not share the PMU + b - use BPF aggregration (see perf stat --bpf-counters) The 'p' modifier can be used for specifying how precise the instruction address should be. The 'p' modifier can be specified multiple times: -- cgit v1.2.3-59-g8ed1b From d9bd1d4264baddf7ab8baae86e91674d369f22de Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Tue, 16 Apr 2024 10:00:14 -0700 Subject: perf test bpf-counters: Add test for BPF event modifier Refactor test to better enable sharing of logic, to give an idea of progress and introduce test functions. Add test of measuring both cycles and cycles:b simultaneously. Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Athira Rajeev Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Ravi Bangoria Cc: Song Liu Cc: Thomas Richter Link: https://lore.kernel.org/r/20240416170014.985191-2-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/shell/stat_bpf_counters.sh | 75 ++++++++++++++++++++--------- 1 file changed, 52 insertions(+), 23 deletions(-) diff --git a/tools/perf/tests/shell/stat_bpf_counters.sh b/tools/perf/tests/shell/stat_bpf_counters.sh index 2d9209874774..61f8149d854e 100755 --- a/tools/perf/tests/shell/stat_bpf_counters.sh +++ b/tools/perf/tests/shell/stat_bpf_counters.sh @@ -4,21 +4,59 @@ set -e +workload="perf bench sched messaging -g 1 -l 100 -t" + # check whether $2 is within +/- 20% of $1 compare_number() { - first_num=$1 - second_num=$2 - - # upper bound is first_num * 120% - upper=$(expr $first_num + $first_num / 5 ) - # lower bound is first_num * 80% - lower=$(expr $first_num - $first_num / 5 ) - - if [ $second_num -gt $upper ] || [ $second_num -lt $lower ]; then - echo "The difference between $first_num and $second_num are greater than 20%." - exit 1 - fi + first_num=$1 + second_num=$2 + + # upper bound is first_num * 120% + upper=$(expr $first_num + $first_num / 5 ) + # lower bound is first_num * 80% + lower=$(expr $first_num - $first_num / 5 ) + + if [ $second_num -gt $upper ] || [ $second_num -lt $lower ]; then + echo "The difference between $first_num and $second_num are greater than 20%." + exit 1 + fi +} + +check_counts() +{ + base_cycles=$1 + bpf_cycles=$2 + + if [ "$base_cycles" = "&1 | awk '/cycles/ {print $1}') + bpf_cycles=$(perf stat --no-big-num --bpf-counters -e cycles -- $workload 2>&1 | awk '/cycles/ {print $1}') + check_counts $base_cycles $bpf_cycles + compare_number $base_cycles $bpf_cycles + echo "[Success]" +} + +test_bpf_modifier() +{ + printf "Testing bpf event modifier " + stat_output=$(perf stat --no-big-num -e cycles/name=base_cycles/,cycles/name=bpf_cycles/b -- $workload 2>&1) + base_cycles=$(echo "$stat_output"| awk '/base_cycles/ {print $1}') + bpf_cycles=$(echo "$stat_output"| awk '/bpf_cycles/ {print $1}') + check_counts $base_cycles $bpf_cycles + compare_number $base_cycles $bpf_cycles + echo "[Success]" } # skip if --bpf-counters is not supported @@ -30,16 +68,7 @@ if ! perf stat -e cycles --bpf-counters true > /dev/null 2>&1; then exit 2 fi -base_cycles=$(perf stat --no-big-num -e cycles -- perf bench sched messaging -g 1 -l 100 -t 2>&1 | awk '/cycles/ {print $1}') -if [ "$base_cycles" = "&1 | awk '/cycles/ {print $1}') -if [ "$bpf_cycles" = " Date: Mon, 8 Apr 2024 14:40:22 -0700 Subject: perf vendor events arm64: AmpereOne/AmpereOneX: Mark L1D_CACHE_INVAL impacted by errata L1D_CACHE_INVAL overcounts in certain situations. See AC03_CPU_41 and AC04_CPU_1 for more details. Mark the event impacted by the errata. Reviewed-by: James Clark Signed-off-by: Ilkka Koskinen Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: John Garry Cc: Leo Yan Cc: Mark Rutland Cc: Mike Leach Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Will Deacon Link: https://lore.kernel.org/r/20240408214022.541839-1-ilkka@os.amperecomputing.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/pmu-events/arch/arm64/ampere/ampereone/cache.json | 4 +++- tools/perf/pmu-events/arch/arm64/ampere/ampereonex/cache.json | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/tools/perf/pmu-events/arch/arm64/ampere/ampereone/cache.json b/tools/perf/pmu-events/arch/arm64/ampere/ampereone/cache.json index 7a2b7b200f14..ac75f12e27bf 100644 --- a/tools/perf/pmu-events/arch/arm64/ampere/ampereone/cache.json +++ b/tools/perf/pmu-events/arch/arm64/ampere/ampereone/cache.json @@ -9,7 +9,9 @@ "ArchStdEvent": "L1D_CACHE_REFILL_RD" }, { - "ArchStdEvent": "L1D_CACHE_INVAL" + "ArchStdEvent": "L1D_CACHE_INVAL", + "Errata": "Errata AC03_CPU_41", + "BriefDescription": "L1D cache invalidate. Impacted by errata -" }, { "ArchStdEvent": "L1D_TLB_REFILL_RD" diff --git a/tools/perf/pmu-events/arch/arm64/ampere/ampereonex/cache.json b/tools/perf/pmu-events/arch/arm64/ampere/ampereonex/cache.json index c50d8e930b05..f4bfe7083a6b 100644 --- a/tools/perf/pmu-events/arch/arm64/ampere/ampereonex/cache.json +++ b/tools/perf/pmu-events/arch/arm64/ampere/ampereonex/cache.json @@ -9,7 +9,9 @@ "ArchStdEvent": "L1D_CACHE_REFILL_RD" }, { - "ArchStdEvent": "L1D_CACHE_INVAL" + "ArchStdEvent": "L1D_CACHE_INVAL", + "Errata": "Errata AC04_CPU_1", + "BriefDescription": "L1D cache invalidate. Impacted by errata -" }, { "ArchStdEvent": "L1D_TLB_REFILL_RD" -- cgit v1.2.3-59-g8ed1b From b828a23a75a012b9242166b78ff1c3ff2189f436 Mon Sep 17 00:00:00 2001 From: Chen Pei Date: Mon, 15 Apr 2024 17:55:32 +0800 Subject: perf genelf: Fix compiling with libelf on rv32 When cross-compiling perf with libelf, the following error occurred: In file included from tests/genelf.c:14: tests/../util/genelf.h:50:2: error: #error "unsupported architecture" 50 | #error "unsupported architecture" | ^~~~~ tests/../util/genelf.h:59:5: warning: "GEN_ELF_CLASS" is not defined, evaluates to 0 [-Wundef] 59 | #if GEN_ELF_CLASS == ELFCLASS64 Fix this by adding GEN-ELF-ARCH and GEN-ELF-CLASS definitions for rv32. Reviewed-by: Ian Rogers Signed-off-by: Chen Pei Cc: Albert Ou Cc: Palmer Dabbelt Cc: Paul Walmsley Link: https://lore.kernel.org/r/20240415095532.4930-1-cp0613@linux.alibaba.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/genelf.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/perf/util/genelf.h b/tools/perf/util/genelf.h index 5f18d20ea903..4e2e4f40e134 100644 --- a/tools/perf/util/genelf.h +++ b/tools/perf/util/genelf.h @@ -43,6 +43,9 @@ int jit_add_debug_info(Elf *e, uint64_t code_addr, void *debug, int nr_debug_ent #elif defined(__riscv) && __riscv_xlen == 64 #define GEN_ELF_ARCH EM_RISCV #define GEN_ELF_CLASS ELFCLASS64 +#elif defined(__riscv) && __riscv_xlen == 32 +#define GEN_ELF_ARCH EM_RISCV +#define GEN_ELF_CLASS ELFCLASS32 #elif defined(__loongarch__) #define GEN_ELF_ARCH EM_LOONGARCH #define GEN_ELF_CLASS ELFCLASS64 -- cgit v1.2.3-59-g8ed1b From 10b6ee3b597b1b1b4dc390aaf9d589664af31df9 Mon Sep 17 00:00:00 2001 From: James Clark Date: Tue, 26 Mar 2024 11:37:49 +0000 Subject: perf test shell arm_coresight: Increase buffer size for Coresight basic tests These tests record in a mode that includes kernel trace but look for samples of a userspace process. This makes them sensitive to any kernel compilation options that increase the amount of time spent in the kernel. If the trace buffer is completely filled before userspace is reached then the test will fail. Double the buffer size to fix this. The other tests in the same file aren't sensitive to this for various reasons, for example the iterate devices test filters by userspace trace only. But in order to keep coverage of all the modes, increase the buffer size rather than filtering by userspace for the basic tests. Fixes: d1efa4a0a696e487 ("perf cs-etm: Add separate decode paths for timeless and per-thread modes") Reviewed-by: Anshuman Khandual Signed-off-by: James Clark Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ian Rogers Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Mark Rutland Cc: Mike Leach Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Suzuki Poulouse Link: https://lore.kernel.org/r/20240326113749.257250-1-james.clark@arm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/shell/test_arm_coresight.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/tests/shell/test_arm_coresight.sh b/tools/perf/tests/shell/test_arm_coresight.sh index 65dd85207125..3302ea0b9672 100755 --- a/tools/perf/tests/shell/test_arm_coresight.sh +++ b/tools/perf/tests/shell/test_arm_coresight.sh @@ -188,7 +188,7 @@ arm_cs_etm_snapshot_test() { arm_cs_etm_basic_test() { echo "Recording trace with '$*'" - perf record -o ${perfdata} "$@" -- ls > /dev/null 2>&1 + perf record -o ${perfdata} "$@" -m,8M -- ls > /dev/null 2>&1 perf_script_branch_samples ls && perf_report_branch_samples ls && -- cgit v1.2.3-59-g8ed1b From 03f2357017c37d68e73d7d8d77abfcb72e12bc86 Mon Sep 17 00:00:00 2001 From: Weilin Wang Date: Fri, 12 Apr 2024 14:07:41 -0700 Subject: perf stat: Add new field in stat_config to enable hardware aware grouping Hardware counter and event information could be used to help creating event groups that better utilize hardware counters and improve multiplexing. Reviewed-by: Ian Rogers Signed-off-by: Weilin Wang Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Caleb Biggers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Namhyung Kim Cc: Perry Taylor Cc: Peter Zijlstra Cc: Samantha Alt Link: https://lore.kernel.org/r/20240412210756.309828-2-weilin.wang@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-stat.c | 5 +++++ tools/perf/util/metricgroup.c | 3 +++ tools/perf/util/metricgroup.h | 1 + tools/perf/util/stat.h | 1 + 4 files changed, 10 insertions(+) diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 65388c57bb5d..65a3dd7ffac3 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -2085,6 +2085,7 @@ static int add_default_attributes(void) stat_config.metric_no_threshold, stat_config.user_requested_cpu_list, stat_config.system_wide, + stat_config.hardware_aware_grouping, &stat_config.metric_events); } @@ -2118,6 +2119,7 @@ static int add_default_attributes(void) stat_config.metric_no_threshold, stat_config.user_requested_cpu_list, stat_config.system_wide, + stat_config.hardware_aware_grouping, &stat_config.metric_events); } @@ -2152,6 +2154,7 @@ static int add_default_attributes(void) /*metric_no_threshold=*/true, stat_config.user_requested_cpu_list, stat_config.system_wide, + stat_config.hardware_aware_grouping, &stat_config.metric_events) < 0) return -1; } @@ -2193,6 +2196,7 @@ static int add_default_attributes(void) /*metric_no_threshold=*/true, stat_config.user_requested_cpu_list, stat_config.system_wide, + stat_config.hardware_aware_grouping, &stat_config.metric_events) < 0) return -1; @@ -2727,6 +2731,7 @@ int cmd_stat(int argc, const char **argv) stat_config.metric_no_threshold, stat_config.user_requested_cpu_list, stat_config.system_wide, + stat_config.hardware_aware_grouping, &stat_config.metric_events); zfree(&metrics); diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c index 6ec083af14a1..9be406524617 100644 --- a/tools/perf/util/metricgroup.c +++ b/tools/perf/util/metricgroup.c @@ -1690,12 +1690,15 @@ int metricgroup__parse_groups(struct evlist *perf_evlist, bool metric_no_threshold, const char *user_requested_cpu_list, bool system_wide, + bool hardware_aware_grouping, struct rblist *metric_events) { const struct pmu_metrics_table *table = pmu_metrics_table__find(); if (!table) return -EINVAL; + if (hardware_aware_grouping) + pr_debug("Use hardware aware grouping instead of traditional metric grouping method\n"); return parse_groups(perf_evlist, pmu, str, metric_no_group, metric_no_merge, metric_no_threshold, user_requested_cpu_list, system_wide, diff --git a/tools/perf/util/metricgroup.h b/tools/perf/util/metricgroup.h index d5325c6ec8e1..779f6ede1b51 100644 --- a/tools/perf/util/metricgroup.h +++ b/tools/perf/util/metricgroup.h @@ -77,6 +77,7 @@ int metricgroup__parse_groups(struct evlist *perf_evlist, bool metric_no_threshold, const char *user_requested_cpu_list, bool system_wide, + bool hardware_aware_grouping, struct rblist *metric_events); int metricgroup__parse_groups_test(struct evlist *evlist, const struct pmu_metrics_table *table, diff --git a/tools/perf/util/stat.h b/tools/perf/util/stat.h index d6e5c8787ba2..fd7a187551bd 100644 --- a/tools/perf/util/stat.h +++ b/tools/perf/util/stat.h @@ -87,6 +87,7 @@ struct perf_stat_config { bool metric_no_group; bool metric_no_merge; bool metric_no_threshold; + bool hardware_aware_grouping; bool stop_read_counter; bool iostat_run; char *user_requested_cpu_list; -- cgit v1.2.3-59-g8ed1b From a529bec023d7d14d9fb7d5b456921630e63edc6b Mon Sep 17 00:00:00 2001 From: Dima Kogan Date: Mon, 15 Apr 2024 21:55:10 -0700 Subject: perf probe-event: Un-hardcode sizeof(buf) In several places we had char buf[64]; ... snprintf(buf, 64, ...); This patch changes it to char buf[64]; ... snprintf(buf, sizeof(buf), ...); so the "64" is only stated once. Signed-off-by: Dima Kogan Acked-by: Masami Hiramatsu Link: https://lore.kernel.org/r/20240416045533.162692-2-dima@secretsauce.net Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/probe-event.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 5c12459e9765..c1dbad8a83dc 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -236,7 +236,7 @@ static int convert_exec_to_group(const char *exec, char **result) } } - ret = e_snprintf(buf, 64, "%s_%s", PERFPROBE_GROUP, ptr1); + ret = e_snprintf(buf, sizeof(buf), "%s_%s", PERFPROBE_GROUP, ptr1); if (ret < 0) goto out; @@ -2867,7 +2867,7 @@ static int probe_trace_event__set_name(struct probe_trace_event *tev, group = PERFPROBE_GROUP; /* Get an unused new event name */ - ret = get_new_event_name(buf, 64, event, namelist, + ret = get_new_event_name(buf, sizeof(buf), event, namelist, tev->point.retprobe, allow_suffix); if (ret < 0) return ret; -- cgit v1.2.3-59-g8ed1b From c15ed4442981ccf8e7e0d885f5cb500400dde9d7 Mon Sep 17 00:00:00 2001 From: Dima Kogan Date: Mon, 15 Apr 2024 21:55:11 -0700 Subject: perf probe-event: Better error message for a too-long probe name This is a common failure mode when probing userspace C++ code (where the mangling adds significant length to the symbol names). Prior to this patch, only a very generic error message is produced, making the user guess at what the issue is. Signed-off-by: Dima Kogan Acked-by: Masami Hiramatsu Link: https://lore.kernel.org/r/20240416045533.162692-3-dima@secretsauce.net Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/probe-event.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index c1dbad8a83dc..8a73c9464b70 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -2758,7 +2758,7 @@ static int get_new_event_name(char *buf, size_t len, const char *base, /* Try no suffix number */ ret = e_snprintf(buf, len, "%s%s", nbase, ret_event ? "__return" : ""); if (ret < 0) { - pr_debug("snprintf() failed: %d\n", ret); + pr_warning("snprintf() failed: %d; the event name nbase='%s' is too long\n", ret, nbase); goto out; } if (!strlist__has_entry(namelist, buf)) -- cgit v1.2.3-59-g8ed1b From 61ba075d9911d2a6db181fbb5602762a24d5d0a9 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 18 Apr 2024 18:15:33 -0300 Subject: Revert "tools headers: Remove almost unused copy of uapi/stat.h, add few conditional defines" This reverts commit a672af9139a843eb7a48fd7846bb6df8f81b5f86. By now it is not used for building tools/perf, but Stephen Rothwell reported that when building on a O= directory that had been built with torvalds/master and this perf build command line: $ make -C tools/perf -f Makefile.perf -s -O -j60 O=/home/sfr/next/perf NO_BPF_SKEL=1 If we then merge perf-tools-next, as he did for linux-next, then we end up with a build failure for libbpf: PERF_VERSION = 6.9.rc3.g42c4635c8dee make[3]: *** No rule to make target '/home/sfr/next/next/tools/include/uapi/linux/stat.h', needed by '/home/sfr/next/perf/libbpf/staticobjs/libbpf.o'. Stop. make[2]: *** [Makefile:157: /home/sfr/next/perf/libbpf/staticobjs/libbpf-in.o] Error 2 make[1]: *** [Makefile.perf:892: /home/sfr/next/perf/libbpf/libbpf.a] Error 2 make[1]: *** Waiting for unfinished jobs.... make: *** [Makefile.perf:264: sub-make] Error 2 This needs to be further investigated to figure out how to check if libbpf really needs something that is in that tools/include/uapi/linux/stat.h file and if not to remove that file in a way that we don't break the build in any situation, to avoid requiring doing a 'make clean'. Reported-by: Stephen Rothwell Tested-by: Stephen Rothwell # PowerPC le incermental build Cc: Namhyung Kim Link: https://lore.kernel.org/lkml/20240413124340.4d48c6d8@canb.auug.org.au Signed-off-by: Arnaldo Carvalho de Melo --- tools/include/uapi/linux/stat.h | 195 ++++++++++++++++++++++++++++++++++++++++ tools/perf/check-headers.sh | 1 + 2 files changed, 196 insertions(+) create mode 100644 tools/include/uapi/linux/stat.h diff --git a/tools/include/uapi/linux/stat.h b/tools/include/uapi/linux/stat.h new file mode 100644 index 000000000000..2f2ee82d5517 --- /dev/null +++ b/tools/include/uapi/linux/stat.h @@ -0,0 +1,195 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _UAPI_LINUX_STAT_H +#define _UAPI_LINUX_STAT_H + +#include + +#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) + +#define S_IFMT 00170000 +#define S_IFSOCK 0140000 +#define S_IFLNK 0120000 +#define S_IFREG 0100000 +#define S_IFBLK 0060000 +#define S_IFDIR 0040000 +#define S_IFCHR 0020000 +#define S_IFIFO 0010000 +#define S_ISUID 0004000 +#define S_ISGID 0002000 +#define S_ISVTX 0001000 + +#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) +#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) +#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) +#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) +#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) +#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) + +#define S_IRWXU 00700 +#define S_IRUSR 00400 +#define S_IWUSR 00200 +#define S_IXUSR 00100 + +#define S_IRWXG 00070 +#define S_IRGRP 00040 +#define S_IWGRP 00020 +#define S_IXGRP 00010 + +#define S_IRWXO 00007 +#define S_IROTH 00004 +#define S_IWOTH 00002 +#define S_IXOTH 00001 + +#endif + +/* + * Timestamp structure for the timestamps in struct statx. + * + * tv_sec holds the number of seconds before (negative) or after (positive) + * 00:00:00 1st January 1970 UTC. + * + * tv_nsec holds a number of nanoseconds (0..999,999,999) after the tv_sec time. + * + * __reserved is held in case we need a yet finer resolution. + */ +struct statx_timestamp { + __s64 tv_sec; + __u32 tv_nsec; + __s32 __reserved; +}; + +/* + * Structures for the extended file attribute retrieval system call + * (statx()). + * + * The caller passes a mask of what they're specifically interested in as a + * parameter to statx(). What statx() actually got will be indicated in + * st_mask upon return. + * + * For each bit in the mask argument: + * + * - if the datum is not supported: + * + * - the bit will be cleared, and + * + * - the datum will be set to an appropriate fabricated value if one is + * available (eg. CIFS can take a default uid and gid), otherwise + * + * - the field will be cleared; + * + * - otherwise, if explicitly requested: + * + * - the datum will be synchronised to the server if AT_STATX_FORCE_SYNC is + * set or if the datum is considered out of date, and + * + * - the field will be filled in and the bit will be set; + * + * - otherwise, if not requested, but available in approximate form without any + * effort, it will be filled in anyway, and the bit will be set upon return + * (it might not be up to date, however, and no attempt will be made to + * synchronise the internal state first); + * + * - otherwise the field and the bit will be cleared before returning. + * + * Items in STATX_BASIC_STATS may be marked unavailable on return, but they + * will have values installed for compatibility purposes so that stat() and + * co. can be emulated in userspace. + */ +struct statx { + /* 0x00 */ + __u32 stx_mask; /* What results were written [uncond] */ + __u32 stx_blksize; /* Preferred general I/O size [uncond] */ + __u64 stx_attributes; /* Flags conveying information about the file [uncond] */ + /* 0x10 */ + __u32 stx_nlink; /* Number of hard links */ + __u32 stx_uid; /* User ID of owner */ + __u32 stx_gid; /* Group ID of owner */ + __u16 stx_mode; /* File mode */ + __u16 __spare0[1]; + /* 0x20 */ + __u64 stx_ino; /* Inode number */ + __u64 stx_size; /* File size */ + __u64 stx_blocks; /* Number of 512-byte blocks allocated */ + __u64 stx_attributes_mask; /* Mask to show what's supported in stx_attributes */ + /* 0x40 */ + struct statx_timestamp stx_atime; /* Last access time */ + struct statx_timestamp stx_btime; /* File creation time */ + struct statx_timestamp stx_ctime; /* Last attribute change time */ + struct statx_timestamp stx_mtime; /* Last data modification time */ + /* 0x80 */ + __u32 stx_rdev_major; /* Device ID of special file [if bdev/cdev] */ + __u32 stx_rdev_minor; + __u32 stx_dev_major; /* ID of device containing file [uncond] */ + __u32 stx_dev_minor; + /* 0x90 */ + __u64 stx_mnt_id; + __u32 stx_dio_mem_align; /* Memory buffer alignment for direct I/O */ + __u32 stx_dio_offset_align; /* File offset alignment for direct I/O */ + /* 0xa0 */ + __u64 __spare3[12]; /* Spare space for future expansion */ + /* 0x100 */ +}; + +/* + * Flags to be stx_mask + * + * Query request/result mask for statx() and struct statx::stx_mask. + * + * These bits should be set in the mask argument of statx() to request + * particular items when calling statx(). + */ +#define STATX_TYPE 0x00000001U /* Want/got stx_mode & S_IFMT */ +#define STATX_MODE 0x00000002U /* Want/got stx_mode & ~S_IFMT */ +#define STATX_NLINK 0x00000004U /* Want/got stx_nlink */ +#define STATX_UID 0x00000008U /* Want/got stx_uid */ +#define STATX_GID 0x00000010U /* Want/got stx_gid */ +#define STATX_ATIME 0x00000020U /* Want/got stx_atime */ +#define STATX_MTIME 0x00000040U /* Want/got stx_mtime */ +#define STATX_CTIME 0x00000080U /* Want/got stx_ctime */ +#define STATX_INO 0x00000100U /* Want/got stx_ino */ +#define STATX_SIZE 0x00000200U /* Want/got stx_size */ +#define STATX_BLOCKS 0x00000400U /* Want/got stx_blocks */ +#define STATX_BASIC_STATS 0x000007ffU /* The stuff in the normal stat struct */ +#define STATX_BTIME 0x00000800U /* Want/got stx_btime */ +#define STATX_MNT_ID 0x00001000U /* Got stx_mnt_id */ +#define STATX_DIOALIGN 0x00002000U /* Want/got direct I/O alignment info */ +#define STATX_MNT_ID_UNIQUE 0x00004000U /* Want/got extended stx_mount_id */ + +#define STATX__RESERVED 0x80000000U /* Reserved for future struct statx expansion */ + +#ifndef __KERNEL__ +/* + * This is deprecated, and shall remain the same value in the future. To avoid + * confusion please use the equivalent (STATX_BASIC_STATS | STATX_BTIME) + * instead. + */ +#define STATX_ALL 0x00000fffU +#endif + +/* + * Attributes to be found in stx_attributes and masked in stx_attributes_mask. + * + * These give information about the features or the state of a file that might + * be of use to ordinary userspace programs such as GUIs or ls rather than + * specialised tools. + * + * Note that the flags marked [I] correspond to the FS_IOC_SETFLAGS flags + * semantically. Where possible, the numerical value is picked to correspond + * also. Note that the DAX attribute indicates that the file is in the CPU + * direct access state. It does not correspond to the per-inode flag that + * some filesystems support. + * + */ +#define STATX_ATTR_COMPRESSED 0x00000004 /* [I] File is compressed by the fs */ +#define STATX_ATTR_IMMUTABLE 0x00000010 /* [I] File is marked immutable */ +#define STATX_ATTR_APPEND 0x00000020 /* [I] File is append-only */ +#define STATX_ATTR_NODUMP 0x00000040 /* [I] File is not to be dumped */ +#define STATX_ATTR_ENCRYPTED 0x00000800 /* [I] File requires key to decrypt in fs */ +#define STATX_ATTR_AUTOMOUNT 0x00001000 /* Dir: Automount trigger */ +#define STATX_ATTR_MOUNT_ROOT 0x00002000 /* Root of a mount */ +#define STATX_ATTR_VERITY 0x00100000 /* [I] Verity protected file */ +#define STATX_ATTR_DAX 0x00200000 /* File is currently in DAX state */ + + +#endif /* _UAPI_LINUX_STAT_H */ diff --git a/tools/perf/check-headers.sh b/tools/perf/check-headers.sh index 95a3a404bc6f..9c84fd049070 100755 --- a/tools/perf/check-headers.sh +++ b/tools/perf/check-headers.sh @@ -16,6 +16,7 @@ FILES=( "include/uapi/linux/in.h" "include/uapi/linux/perf_event.h" "include/uapi/linux/seccomp.h" + "include/uapi/linux/stat.h" "include/linux/bits.h" "include/vdso/bits.h" "include/linux/const.h" -- cgit v1.2.3-59-g8ed1b From 668906cf88d5f0c6f124cf4d7d61c38693708681 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Wed, 10 Apr 2024 16:47:51 +0300 Subject: thunderbolt: Use correct error code with ERROR_NOT_SUPPORTED We check for -EOPNOTSUPP but tb_xdp_handle_error() translated it to -ENOTSUPP instead which is dealt as "transient" error and retried after a while. Fix this so that we bail out early when the other side clearly tells us it is does not support this. Signed-off-by: Mika Westerberg --- drivers/thunderbolt/xdomain.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/thunderbolt/xdomain.c b/drivers/thunderbolt/xdomain.c index 940ae97987ff..11a50c86a1e4 100644 --- a/drivers/thunderbolt/xdomain.c +++ b/drivers/thunderbolt/xdomain.c @@ -250,7 +250,7 @@ static int tb_xdp_handle_error(const struct tb_xdp_error_response *res) case ERROR_UNKNOWN_DOMAIN: return -EIO; case ERROR_NOT_SUPPORTED: - return -ENOTSUPP; + return -EOPNOTSUPP; case ERROR_NOT_READY: return -EAGAIN; default: -- cgit v1.2.3-59-g8ed1b From c936e287df26929ad6b5fd7fef22b356e434e90e Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Mon, 12 Feb 2024 10:48:34 +0200 Subject: thunderbolt: Get rid of TB_CFG_PKG_PREPARE_TO_SLEEP This is not used anywhere in the driver so remove it. No functional changes. Signed-off-by: Mika Westerberg --- drivers/thunderbolt/tb_msgs.h | 6 ------ include/linux/thunderbolt.h | 1 - 2 files changed, 7 deletions(-) diff --git a/drivers/thunderbolt/tb_msgs.h b/drivers/thunderbolt/tb_msgs.h index cd750e4b3440..a1670a96cbdc 100644 --- a/drivers/thunderbolt/tb_msgs.h +++ b/drivers/thunderbolt/tb_msgs.h @@ -98,12 +98,6 @@ struct cfg_reset_pkg { struct tb_cfg_header header; } __packed; -/* TB_CFG_PKG_PREPARE_TO_SLEEP */ -struct cfg_pts_pkg { - struct tb_cfg_header header; - u32 data; -} __packed; - /* ICM messages */ enum icm_pkg_code { diff --git a/include/linux/thunderbolt.h b/include/linux/thunderbolt.h index 4338ea9ac4fd..7d902d8c054b 100644 --- a/include/linux/thunderbolt.h +++ b/include/linux/thunderbolt.h @@ -33,7 +33,6 @@ enum tb_cfg_pkg_type { TB_CFG_PKG_ICM_EVENT = 10, TB_CFG_PKG_ICM_CMD = 11, TB_CFG_PKG_ICM_RESP = 12, - TB_CFG_PKG_PREPARE_TO_SLEEP = 13, }; /** -- cgit v1.2.3-59-g8ed1b From f70f95b485d78838ad28dbec804b986d11ad7bb0 Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Fri, 19 Apr 2024 10:09:31 +0200 Subject: serial: msm: check dma_map_sg() return value properly The -next commit f8fef2fa419f (tty: msm_serial: use dmaengine_prep_slave_sg()), switched to using dma_map_sg(). But the return value of dma_map_sg() is special: it returns number of elements mapped. And not a standard error value. The commit also forgot to reset dma->tx_sg in case of this failure. Fix both these mistakes. Thanks to Marek who helped debugging this. Signed-off-by: Jiri Slaby (SUSE) Reported-by: Marek Szyprowski Tested-by: Marek Szyprowski Link: https://lore.kernel.org/r/20240419080931.30949-1-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/msm_serial.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c index ae7a8e3cf467..0a9c5219df88 100644 --- a/drivers/tty/serial/msm_serial.c +++ b/drivers/tty/serial/msm_serial.c @@ -499,15 +499,18 @@ static int msm_handle_tx_dma(struct msm_port *msm_port, unsigned int count) struct uart_port *port = &msm_port->uart; struct tty_port *tport = &port->state->port; struct msm_dma *dma = &msm_port->tx_dma; + unsigned int mapped; int ret; u32 val; sg_init_table(&dma->tx_sg, 1); kfifo_dma_out_prepare(&tport->xmit_fifo, &dma->tx_sg, 1, count); - ret = dma_map_sg(port->dev, &dma->tx_sg, 1, dma->dir); - if (ret) - return ret; + mapped = dma_map_sg(port->dev, &dma->tx_sg, 1, dma->dir); + if (!mapped) { + ret = -EIO; + goto zero_sg; + } dma->desc = dmaengine_prep_slave_sg(dma->chan, &dma->tx_sg, 1, DMA_MEM_TO_DEV, @@ -548,6 +551,7 @@ static int msm_handle_tx_dma(struct msm_port *msm_port, unsigned int count) return 0; unmap: dma_unmap_sg(port->dev, &dma->tx_sg, 1, dma->dir); +zero_sg: sg_init_table(&dma->tx_sg, 1); return ret; } -- cgit v1.2.3-59-g8ed1b From 499eb311513fa30e136d01abfb316c482379afa1 Mon Sep 17 00:00:00 2001 From: Chris Morgan Date: Wed, 17 Apr 2024 12:04:22 -0500 Subject: dt-bindings: iio: adc: Add GPADC for Allwinner H616 Add support for the GPADC for the Allwinner H616. It is identical to the existing ADC for the D1/T113s/R329/T507 SoCs. Signed-off-by: Chris Morgan Acked-by: Rob Herring (Arm) Link: https://lore.kernel.org/r/20240417170423.20640-3-macroalpha82@gmail.com Signed-off-by: Jonathan Cameron --- .../devicetree/bindings/iio/adc/allwinner,sun20i-d1-gpadc.yaml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/iio/adc/allwinner,sun20i-d1-gpadc.yaml b/Documentation/devicetree/bindings/iio/adc/allwinner,sun20i-d1-gpadc.yaml index 7ef46c90ebc8..da605a051b94 100644 --- a/Documentation/devicetree/bindings/iio/adc/allwinner,sun20i-d1-gpadc.yaml +++ b/Documentation/devicetree/bindings/iio/adc/allwinner,sun20i-d1-gpadc.yaml @@ -11,8 +11,13 @@ maintainers: properties: compatible: - enum: - - allwinner,sun20i-d1-gpadc + oneOf: + - enum: + - allwinner,sun20i-d1-gpadc + - items: + - enum: + - allwinner,sun50i-h616-gpadc + - const: allwinner,sun20i-d1-gpadc "#io-channel-cells": const: 1 -- cgit v1.2.3-59-g8ed1b From 9dd6b32e76ff714308964cd9ec91466a343dcb8b Mon Sep 17 00:00:00 2001 From: Thomas Haemmerle Date: Mon, 15 Apr 2024 12:50:27 +0200 Subject: iio: pressure: dps310: support negative temperature values The current implementation interprets negative values returned from `dps310_calculate_temp` as error codes. This has a side effect that when negative temperature values are calculated, they are interpreted as error. Fix this by using the return value only for error handling and passing a pointer for the value. Fixes: ba6ec48e76bc ("iio: Add driver for Infineon DPS310") Signed-off-by: Thomas Haemmerle Link: https://lore.kernel.org/r/20240415105030.1161770-2-thomas.haemmerle@leica-geosystems.com Signed-off-by: Jonathan Cameron --- drivers/iio/pressure/dps310.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/iio/pressure/dps310.c b/drivers/iio/pressure/dps310.c index 1ff091b2f764..d0a516d56da4 100644 --- a/drivers/iio/pressure/dps310.c +++ b/drivers/iio/pressure/dps310.c @@ -730,7 +730,7 @@ static int dps310_read_pressure(struct dps310_data *data, int *val, int *val2, } } -static int dps310_calculate_temp(struct dps310_data *data) +static int dps310_calculate_temp(struct dps310_data *data, int *val) { s64 c0; s64 t; @@ -746,7 +746,9 @@ static int dps310_calculate_temp(struct dps310_data *data) t = c0 + ((s64)data->temp_raw * (s64)data->c1); /* Convert to milliCelsius and scale the temperature */ - return (int)div_s64(t * 1000LL, kt); + *val = (int)div_s64(t * 1000LL, kt); + + return 0; } static int dps310_read_temp(struct dps310_data *data, int *val, int *val2, @@ -768,11 +770,10 @@ static int dps310_read_temp(struct dps310_data *data, int *val, int *val2, if (rc) return rc; - rc = dps310_calculate_temp(data); - if (rc < 0) + rc = dps310_calculate_temp(data, val); + if (rc) return rc; - *val = rc; return IIO_VAL_INT; case IIO_CHAN_INFO_OVERSAMPLING_RATIO: -- cgit v1.2.3-59-g8ed1b From b8189beb2c87cb7aae114734baf19d2bd33342ce Mon Sep 17 00:00:00 2001 From: Thomas Haemmerle Date: Mon, 15 Apr 2024 12:50:28 +0200 Subject: iio: pressure: dps310: introduce consistent error handling Align error handling with `dps310_calculate_temp`, where it's not possible to differentiate between errors and valid calculations by checking if the returned value is negative. Signed-off-by: Thomas Haemmerle Link: https://lore.kernel.org/r/20240415105030.1161770-3-thomas.haemmerle@leica-geosystems.com Signed-off-by: Jonathan Cameron --- drivers/iio/pressure/dps310.c | 129 +++++++++++++++++++++++------------------- 1 file changed, 72 insertions(+), 57 deletions(-) diff --git a/drivers/iio/pressure/dps310.c b/drivers/iio/pressure/dps310.c index d0a516d56da4..3fc436f36fa7 100644 --- a/drivers/iio/pressure/dps310.c +++ b/drivers/iio/pressure/dps310.c @@ -256,24 +256,24 @@ static int dps310_startup(struct dps310_data *data) return dps310_temp_workaround(data); } -static int dps310_get_pres_precision(struct dps310_data *data) +static int dps310_get_pres_precision(struct dps310_data *data, int *val) { - int rc; - int val; + int reg_val, rc; - rc = regmap_read(data->regmap, DPS310_PRS_CFG, &val); + rc = regmap_read(data->regmap, DPS310_PRS_CFG, ®_val); if (rc < 0) return rc; - return BIT(val & GENMASK(2, 0)); + *val = BIT(reg_val & GENMASK(2, 0)); + + return 0; } -static int dps310_get_temp_precision(struct dps310_data *data) +static int dps310_get_temp_precision(struct dps310_data *data, int *val) { - int rc; - int val; + int reg_val, rc; - rc = regmap_read(data->regmap, DPS310_TMP_CFG, &val); + rc = regmap_read(data->regmap, DPS310_TMP_CFG, ®_val); if (rc < 0) return rc; @@ -281,7 +281,9 @@ static int dps310_get_temp_precision(struct dps310_data *data) * Scale factor is bottom 4 bits of the register, but 1111 is * reserved so just grab bottom three */ - return BIT(val & GENMASK(2, 0)); + *val = BIT(reg_val & GENMASK(2, 0)); + + return 0; } /* Called with lock held */ @@ -350,48 +352,56 @@ static int dps310_set_temp_samp_freq(struct dps310_data *data, int freq) DPS310_TMP_RATE_BITS, val); } -static int dps310_get_pres_samp_freq(struct dps310_data *data) +static int dps310_get_pres_samp_freq(struct dps310_data *data, int *val) { - int rc; - int val; + int reg_val, rc; - rc = regmap_read(data->regmap, DPS310_PRS_CFG, &val); + rc = regmap_read(data->regmap, DPS310_PRS_CFG, ®_val); if (rc < 0) return rc; - return BIT((val & DPS310_PRS_RATE_BITS) >> 4); + *val = BIT((reg_val & DPS310_PRS_RATE_BITS) >> 4); + + return 0; } -static int dps310_get_temp_samp_freq(struct dps310_data *data) +static int dps310_get_temp_samp_freq(struct dps310_data *data, int *val) { - int rc; - int val; + int reg_val, rc; - rc = regmap_read(data->regmap, DPS310_TMP_CFG, &val); + rc = regmap_read(data->regmap, DPS310_TMP_CFG, ®_val); if (rc < 0) return rc; - return BIT((val & DPS310_TMP_RATE_BITS) >> 4); + *val = BIT((reg_val & DPS310_TMP_RATE_BITS) >> 4); + + return 0; } -static int dps310_get_pres_k(struct dps310_data *data) +static int dps310_get_pres_k(struct dps310_data *data, int *val) { - int rc = dps310_get_pres_precision(data); + int reg_val, rc; - if (rc < 0) + rc = dps310_get_pres_precision(data, ®_val); + if (rc) return rc; - return scale_factors[ilog2(rc)]; + *val = scale_factors[ilog2(reg_val)]; + + return 0; } -static int dps310_get_temp_k(struct dps310_data *data) +static int dps310_get_temp_k(struct dps310_data *data, int *val) { - int rc = dps310_get_temp_precision(data); + int reg_val, rc; - if (rc < 0) + rc = dps310_get_temp_precision(data, ®_val); + if (rc) return rc; - return scale_factors[ilog2(rc)]; + *val = scale_factors[ilog2(reg_val)]; + + return 0; } static int dps310_reset_wait(struct dps310_data *data) @@ -464,7 +474,10 @@ static int dps310_read_pres_raw(struct dps310_data *data) if (mutex_lock_interruptible(&data->lock)) return -EINTR; - rate = dps310_get_pres_samp_freq(data); + rc = dps310_get_pres_samp_freq(data, &rate); + if (rc) + goto done; + timeout = DPS310_POLL_TIMEOUT_US(rate); /* Poll for sensor readiness; base the timeout upon the sample rate. */ @@ -510,7 +523,10 @@ static int dps310_read_temp_raw(struct dps310_data *data) if (mutex_lock_interruptible(&data->lock)) return -EINTR; - rate = dps310_get_temp_samp_freq(data); + rc = dps310_get_temp_samp_freq(data, &rate); + if (rc) + goto done; + timeout = DPS310_POLL_TIMEOUT_US(rate); /* Poll for sensor readiness; base the timeout upon the sample rate. */ @@ -612,13 +628,13 @@ static int dps310_write_raw(struct iio_dev *iio, return rc; } -static int dps310_calculate_pressure(struct dps310_data *data) +static int dps310_calculate_pressure(struct dps310_data *data, int *val) { int i; int rc; int t_ready; - int kpi = dps310_get_pres_k(data); - int kti = dps310_get_temp_k(data); + int kpi; + int kti; s64 rem = 0ULL; s64 pressure = 0ULL; s64 p; @@ -629,11 +645,13 @@ static int dps310_calculate_pressure(struct dps310_data *data) s64 kp; s64 kt; - if (kpi < 0) - return kpi; + rc = dps310_get_pres_k(data, &kpi); + if (rc) + return rc; - if (kti < 0) - return kti; + rc = dps310_get_temp_k(data, &kti); + if (rc) + return rc; kp = (s64)kpi; kt = (s64)kti; @@ -687,7 +705,9 @@ static int dps310_calculate_pressure(struct dps310_data *data) if (pressure < 0LL) return -ERANGE; - return (int)min_t(s64, pressure, INT_MAX); + *val = (int)min_t(s64, pressure, INT_MAX); + + return 0; } static int dps310_read_pressure(struct dps310_data *data, int *val, int *val2, @@ -697,11 +717,10 @@ static int dps310_read_pressure(struct dps310_data *data, int *val, int *val2, switch (mask) { case IIO_CHAN_INFO_SAMP_FREQ: - rc = dps310_get_pres_samp_freq(data); - if (rc < 0) + rc = dps310_get_pres_samp_freq(data, val); + if (rc) return rc; - *val = rc; return IIO_VAL_INT; case IIO_CHAN_INFO_PROCESSED: @@ -709,20 +728,17 @@ static int dps310_read_pressure(struct dps310_data *data, int *val, int *val2, if (rc) return rc; - rc = dps310_calculate_pressure(data); - if (rc < 0) + rc = dps310_calculate_pressure(data, val); + if (rc) return rc; - *val = rc; *val2 = 1000; /* Convert Pa to KPa per IIO ABI */ return IIO_VAL_FRACTIONAL; case IIO_CHAN_INFO_OVERSAMPLING_RATIO: - rc = dps310_get_pres_precision(data); - if (rc < 0) + rc = dps310_get_pres_precision(data, val); + if (rc) return rc; - - *val = rc; return IIO_VAL_INT; default: @@ -734,10 +750,11 @@ static int dps310_calculate_temp(struct dps310_data *data, int *val) { s64 c0; s64 t; - int kt = dps310_get_temp_k(data); + int kt, rc; - if (kt < 0) - return kt; + rc = dps310_get_temp_k(data, &kt); + if (rc) + return rc; /* Obtain inverse-scaled offset */ c0 = div_s64((s64)kt * (s64)data->c0, 2); @@ -758,11 +775,10 @@ static int dps310_read_temp(struct dps310_data *data, int *val, int *val2, switch (mask) { case IIO_CHAN_INFO_SAMP_FREQ: - rc = dps310_get_temp_samp_freq(data); - if (rc < 0) + rc = dps310_get_temp_samp_freq(data, val); + if (rc) return rc; - *val = rc; return IIO_VAL_INT; case IIO_CHAN_INFO_PROCESSED: @@ -777,11 +793,10 @@ static int dps310_read_temp(struct dps310_data *data, int *val, int *val2, return IIO_VAL_INT; case IIO_CHAN_INFO_OVERSAMPLING_RATIO: - rc = dps310_get_temp_precision(data); - if (rc < 0) + rc = dps310_get_temp_precision(data, val); + if (rc) return rc; - *val = rc; return IIO_VAL_INT; default: -- cgit v1.2.3-59-g8ed1b From c046bb5d9512e3c00b0e17c581f50bbb6c641d58 Mon Sep 17 00:00:00 2001 From: Thomas Haemmerle Date: Mon, 15 Apr 2024 12:50:29 +0200 Subject: iio: pressure: dps310: consistently check return value of `regmap_read` Align the check of return values `regmap_read` so that it's consistent across this driver code. Signed-off-by: Thomas Haemmerle Link: https://lore.kernel.org/r/20240415105030.1161770-4-thomas.haemmerle@leica-geosystems.com Signed-off-by: Jonathan Cameron --- drivers/iio/pressure/dps310.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/pressure/dps310.c b/drivers/iio/pressure/dps310.c index 3fc436f36fa7..c30623d96f0e 100644 --- a/drivers/iio/pressure/dps310.c +++ b/drivers/iio/pressure/dps310.c @@ -171,7 +171,7 @@ static int dps310_temp_workaround(struct dps310_data *data) int reg; rc = regmap_read(data->regmap, 0x32, ®); - if (rc) + if (rc < 0) return rc; /* -- cgit v1.2.3-59-g8ed1b From 5826711e841450755cae32bacc59f6465075db94 Mon Sep 17 00:00:00 2001 From: Thomas Haemmerle Date: Mon, 15 Apr 2024 12:50:30 +0200 Subject: iio: pressure: dps310: simplify scale factor reading Both functions `dps310_get_pres_precision` and `dps310_get_temp_precision` provide the oversampling rate by calling the `BIT()` macro. However, to look up the corresponding scale factor, we need the register value itself. Currently, this is achieved by undoing the calculation of the oversampling rate with `ilog2()`. Simplify the two functions for getting the scale factor and directly use the register content for the lookup. Signed-off-by: Thomas Haemmerle Link: https://lore.kernel.org/r/20240415105030.1161770-5-thomas.haemmerle@leica-geosystems.com Signed-off-by: Jonathan Cameron --- drivers/iio/pressure/dps310.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/iio/pressure/dps310.c b/drivers/iio/pressure/dps310.c index c30623d96f0e..7d882e15e556 100644 --- a/drivers/iio/pressure/dps310.c +++ b/drivers/iio/pressure/dps310.c @@ -382,11 +382,11 @@ static int dps310_get_pres_k(struct dps310_data *data, int *val) { int reg_val, rc; - rc = dps310_get_pres_precision(data, ®_val); - if (rc) + rc = regmap_read(data->regmap, DPS310_PRS_CFG, ®_val); + if (rc < 0) return rc; - *val = scale_factors[ilog2(reg_val)]; + *val = scale_factors[reg_val & GENMASK(2, 0)]; return 0; } @@ -395,11 +395,11 @@ static int dps310_get_temp_k(struct dps310_data *data, int *val) { int reg_val, rc; - rc = dps310_get_temp_precision(data, ®_val); - if (rc) + rc = regmap_read(data->regmap, DPS310_TMP_CFG, ®_val); + if (rc < 0) return rc; - *val = scale_factors[ilog2(reg_val)]; + *val = scale_factors[reg_val & GENMASK(2, 0)]; return 0; } -- cgit v1.2.3-59-g8ed1b From a094de22e2efc2ec7f540d10d1edb7038f863925 Mon Sep 17 00:00:00 2001 From: Nuno Sa Date: Fri, 19 Apr 2024 10:25:34 +0200 Subject: iio: buffer-dma: add iio_dmaengine_buffer_setup() This brings the DMA buffer API more in line with what we have in the triggered buffer. There's no need of having both devm_iio_dmaengine_buffer_setup() and devm_iio_dmaengine_buffer_alloc(). Hence we introduce the new iio_dmaengine_buffer_setup() that together with devm_iio_dmaengine_buffer_setup() should be all we need. Note that as part of this change iio_dmaengine_buffer_alloc() is again static and the axi-adc was updated accordingly. Signed-off-by: Nuno Sa Link: https://lore.kernel.org/r/20240419-iio-backend-axi-dac-v4-1-5ca45b4de294@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/adi-axi-adc.c | 16 +------- drivers/iio/buffer/industrialio-buffer-dmaengine.c | 48 +++++++++------------- include/linux/iio/buffer-dmaengine.h | 5 ++- 3 files changed, 24 insertions(+), 45 deletions(-) diff --git a/drivers/iio/adc/adi-axi-adc.c b/drivers/iio/adc/adi-axi-adc.c index 4156639b3c8b..184b36dca6d0 100644 --- a/drivers/iio/adc/adi-axi-adc.c +++ b/drivers/iio/adc/adi-axi-adc.c @@ -124,26 +124,12 @@ static struct iio_buffer *axi_adc_request_buffer(struct iio_backend *back, struct iio_dev *indio_dev) { struct adi_axi_adc_state *st = iio_backend_get_priv(back); - struct iio_buffer *buffer; const char *dma_name; - int ret; if (device_property_read_string(st->dev, "dma-names", &dma_name)) dma_name = "rx"; - buffer = iio_dmaengine_buffer_alloc(st->dev, dma_name); - if (IS_ERR(buffer)) { - dev_err(st->dev, "Could not get DMA buffer, %ld\n", - PTR_ERR(buffer)); - return ERR_CAST(buffer); - } - - indio_dev->modes |= INDIO_BUFFER_HARDWARE; - ret = iio_device_attach_buffer(indio_dev, buffer); - if (ret) - return ERR_PTR(ret); - - return buffer; + return iio_dmaengine_buffer_setup(st->dev, indio_dev, dma_name); } static void axi_adc_free_buffer(struct iio_backend *back, diff --git a/drivers/iio/buffer/industrialio-buffer-dmaengine.c b/drivers/iio/buffer/industrialio-buffer-dmaengine.c index a18c1da292af..97f3116566f5 100644 --- a/drivers/iio/buffer/industrialio-buffer-dmaengine.c +++ b/drivers/iio/buffer/industrialio-buffer-dmaengine.c @@ -159,7 +159,7 @@ static const struct iio_dev_attr *iio_dmaengine_buffer_attrs[] = { * Once done using the buffer iio_dmaengine_buffer_free() should be used to * release it. */ -struct iio_buffer *iio_dmaengine_buffer_alloc(struct device *dev, +static struct iio_buffer *iio_dmaengine_buffer_alloc(struct device *dev, const char *channel) { struct dmaengine_buffer *dmaengine_buffer; @@ -210,7 +210,6 @@ err_free: kfree(dmaengine_buffer); return ERR_PTR(ret); } -EXPORT_SYMBOL_NS_GPL(iio_dmaengine_buffer_alloc, IIO_DMAENGINE_BUFFER); /** * iio_dmaengine_buffer_free() - Free dmaengine buffer @@ -230,39 +229,33 @@ void iio_dmaengine_buffer_free(struct iio_buffer *buffer) } EXPORT_SYMBOL_NS_GPL(iio_dmaengine_buffer_free, IIO_DMAENGINE_BUFFER); -static void __devm_iio_dmaengine_buffer_free(void *buffer) -{ - iio_dmaengine_buffer_free(buffer); -} - -/** - * devm_iio_dmaengine_buffer_alloc() - Resource-managed iio_dmaengine_buffer_alloc() - * @dev: Parent device for the buffer - * @channel: DMA channel name, typically "rx". - * - * This allocates a new IIO buffer which internally uses the DMAengine framework - * to perform its transfers. The parent device will be used to request the DMA - * channel. - * - * The buffer will be automatically de-allocated once the device gets destroyed. - */ -static struct iio_buffer *devm_iio_dmaengine_buffer_alloc(struct device *dev, - const char *channel) +struct iio_buffer *iio_dmaengine_buffer_setup(struct device *dev, + struct iio_dev *indio_dev, + const char *channel) { struct iio_buffer *buffer; int ret; buffer = iio_dmaengine_buffer_alloc(dev, channel); if (IS_ERR(buffer)) - return buffer; + return ERR_CAST(buffer); + + indio_dev->modes |= INDIO_BUFFER_HARDWARE; - ret = devm_add_action_or_reset(dev, __devm_iio_dmaengine_buffer_free, - buffer); - if (ret) + ret = iio_device_attach_buffer(indio_dev, buffer); + if (ret) { + iio_dmaengine_buffer_free(buffer); return ERR_PTR(ret); + } return buffer; } +EXPORT_SYMBOL_NS_GPL(iio_dmaengine_buffer_setup, IIO_DMAENGINE_BUFFER); + +static void __devm_iio_dmaengine_buffer_free(void *buffer) +{ + iio_dmaengine_buffer_free(buffer); +} /** * devm_iio_dmaengine_buffer_setup() - Setup a DMA buffer for an IIO device @@ -281,13 +274,12 @@ int devm_iio_dmaengine_buffer_setup(struct device *dev, { struct iio_buffer *buffer; - buffer = devm_iio_dmaengine_buffer_alloc(dev, channel); + buffer = iio_dmaengine_buffer_setup(dev, indio_dev, channel); if (IS_ERR(buffer)) return PTR_ERR(buffer); - indio_dev->modes |= INDIO_BUFFER_HARDWARE; - - return iio_device_attach_buffer(indio_dev, buffer); + return devm_add_action_or_reset(dev, __devm_iio_dmaengine_buffer_free, + buffer); } EXPORT_SYMBOL_NS_GPL(devm_iio_dmaengine_buffer_setup, IIO_DMAENGINE_BUFFER); diff --git a/include/linux/iio/buffer-dmaengine.h b/include/linux/iio/buffer-dmaengine.h index cbb8ba957fad..acb60f9a3fff 100644 --- a/include/linux/iio/buffer-dmaengine.h +++ b/include/linux/iio/buffer-dmaengine.h @@ -10,9 +10,10 @@ struct iio_dev; struct device; -struct iio_buffer *iio_dmaengine_buffer_alloc(struct device *dev, - const char *channel); void iio_dmaengine_buffer_free(struct iio_buffer *buffer); +struct iio_buffer *iio_dmaengine_buffer_setup(struct device *dev, + struct iio_dev *indio_dev, + const char *channel); int devm_iio_dmaengine_buffer_setup(struct device *dev, struct iio_dev *indio_dev, const char *channel); -- cgit v1.2.3-59-g8ed1b From 04ae3b1a76b77f98a4a0c8ed2c544007334fc680 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Fri, 19 Apr 2024 10:25:35 +0200 Subject: iio: buffer-dma: Rename iio_dma_buffer_data_available() Change its name to iio_dma_buffer_usage(), as this function can be used both for the .data_available and the .space_available callbacks. Signed-off-by: Paul Cercueil Signed-off-by: Nuno Sa Link: https://lore.kernel.org/r/20240419-iio-backend-axi-dac-v4-2-5ca45b4de294@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/buffer/industrialio-buffer-dma.c | 11 ++++++----- drivers/iio/buffer/industrialio-buffer-dmaengine.c | 2 +- include/linux/iio/buffer-dma.h | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/iio/buffer/industrialio-buffer-dma.c b/drivers/iio/buffer/industrialio-buffer-dma.c index 5610ba67925e..404f9867bdc5 100644 --- a/drivers/iio/buffer/industrialio-buffer-dma.c +++ b/drivers/iio/buffer/industrialio-buffer-dma.c @@ -547,13 +547,14 @@ out_unlock: EXPORT_SYMBOL_GPL(iio_dma_buffer_read); /** - * iio_dma_buffer_data_available() - DMA buffer data_available callback + * iio_dma_buffer_usage() - DMA buffer data_available and + * space_available callback * @buf: Buffer to check for data availability * - * Should be used as the data_available callback for iio_buffer_access_ops - * struct for DMA buffers. + * Should be used as the data_available and space_available callbacks for + * iio_buffer_access_ops struct for DMA buffers. */ -size_t iio_dma_buffer_data_available(struct iio_buffer *buf) +size_t iio_dma_buffer_usage(struct iio_buffer *buf) { struct iio_dma_buffer_queue *queue = iio_buffer_to_queue(buf); struct iio_dma_buffer_block *block; @@ -586,7 +587,7 @@ size_t iio_dma_buffer_data_available(struct iio_buffer *buf) return data_available; } -EXPORT_SYMBOL_GPL(iio_dma_buffer_data_available); +EXPORT_SYMBOL_GPL(iio_dma_buffer_usage); /** * iio_dma_buffer_set_bytes_per_datum() - DMA buffer set_bytes_per_datum callback diff --git a/drivers/iio/buffer/industrialio-buffer-dmaengine.c b/drivers/iio/buffer/industrialio-buffer-dmaengine.c index 97f3116566f5..df05d66afff9 100644 --- a/drivers/iio/buffer/industrialio-buffer-dmaengine.c +++ b/drivers/iio/buffer/industrialio-buffer-dmaengine.c @@ -117,7 +117,7 @@ static const struct iio_buffer_access_funcs iio_dmaengine_buffer_ops = { .request_update = iio_dma_buffer_request_update, .enable = iio_dma_buffer_enable, .disable = iio_dma_buffer_disable, - .data_available = iio_dma_buffer_data_available, + .data_available = iio_dma_buffer_usage, .release = iio_dmaengine_buffer_release, .modes = INDIO_BUFFER_HARDWARE, diff --git a/include/linux/iio/buffer-dma.h b/include/linux/iio/buffer-dma.h index 18d3702fa95d..52a838ec0e57 100644 --- a/include/linux/iio/buffer-dma.h +++ b/include/linux/iio/buffer-dma.h @@ -132,7 +132,7 @@ int iio_dma_buffer_disable(struct iio_buffer *buffer, struct iio_dev *indio_dev); int iio_dma_buffer_read(struct iio_buffer *buffer, size_t n, char __user *user_buffer); -size_t iio_dma_buffer_data_available(struct iio_buffer *buffer); +size_t iio_dma_buffer_usage(struct iio_buffer *buffer); int iio_dma_buffer_set_bytes_per_datum(struct iio_buffer *buffer, size_t bpd); int iio_dma_buffer_set_length(struct iio_buffer *buffer, unsigned int length); int iio_dma_buffer_request_update(struct iio_buffer *buffer); -- cgit v1.2.3-59-g8ed1b From fb09febafd160b7aefd9e61f710a0c50f0472403 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Fri, 19 Apr 2024 10:25:36 +0200 Subject: iio: buffer-dma: Enable buffer write support Adding write support to the buffer-dma code is easy - the write() function basically needs to do the exact same thing as the read() function: dequeue a block, read or write the data, enqueue the block when entirely processed. Therefore, the iio_buffer_dma_read() and the new iio_buffer_dma_write() now both call a function iio_buffer_dma_io(), which will perform this task. Note that we preemptively reset block->bytes_used to the buffer's size in iio_dma_buffer_request_update(), as in the future the iio_dma_buffer_enqueue() function won't reset it. Signed-off-by: Paul Cercueil Reviewed-by: Alexandru Ardelean Signed-off-by: Nuno Sa Link: https://lore.kernel.org/r/20240419-iio-backend-axi-dac-v4-3-5ca45b4de294@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/buffer/industrialio-buffer-dma.c | 89 +++++++++++++++++++++++----- include/linux/iio/buffer-dma.h | 2 + 2 files changed, 75 insertions(+), 16 deletions(-) diff --git a/drivers/iio/buffer/industrialio-buffer-dma.c b/drivers/iio/buffer/industrialio-buffer-dma.c index 404f9867bdc5..13b1a858969e 100644 --- a/drivers/iio/buffer/industrialio-buffer-dma.c +++ b/drivers/iio/buffer/industrialio-buffer-dma.c @@ -195,6 +195,18 @@ static void _iio_dma_buffer_block_done(struct iio_dma_buffer_block *block) block->state = IIO_BLOCK_STATE_DONE; } +static void iio_dma_buffer_queue_wake(struct iio_dma_buffer_queue *queue) +{ + __poll_t flags; + + if (queue->buffer.direction == IIO_BUFFER_DIRECTION_IN) + flags = EPOLLIN | EPOLLRDNORM; + else + flags = EPOLLOUT | EPOLLWRNORM; + + wake_up_interruptible_poll(&queue->buffer.pollq, flags); +} + /** * iio_dma_buffer_block_done() - Indicate that a block has been completed * @block: The completed block @@ -212,7 +224,7 @@ void iio_dma_buffer_block_done(struct iio_dma_buffer_block *block) spin_unlock_irqrestore(&queue->list_lock, flags); iio_buffer_block_put_atomic(block); - wake_up_interruptible_poll(&queue->buffer.pollq, EPOLLIN | EPOLLRDNORM); + iio_dma_buffer_queue_wake(queue); } EXPORT_SYMBOL_GPL(iio_dma_buffer_block_done); @@ -241,7 +253,7 @@ void iio_dma_buffer_block_list_abort(struct iio_dma_buffer_queue *queue, } spin_unlock_irqrestore(&queue->list_lock, flags); - wake_up_interruptible_poll(&queue->buffer.pollq, EPOLLIN | EPOLLRDNORM); + iio_dma_buffer_queue_wake(queue); } EXPORT_SYMBOL_GPL(iio_dma_buffer_block_list_abort); @@ -335,8 +347,24 @@ int iio_dma_buffer_request_update(struct iio_buffer *buffer) queue->fileio.blocks[i] = block; } - block->state = IIO_BLOCK_STATE_QUEUED; - list_add_tail(&block->head, &queue->incoming); + /* + * block->bytes_used may have been modified previously, e.g. by + * iio_dma_buffer_block_list_abort(). Reset it here to the + * block's so that iio_dma_buffer_io() will work. + */ + block->bytes_used = block->size; + + /* + * If it's an input buffer, mark the block as queued, and + * iio_dma_buffer_enable() will submit it. Otherwise mark it as + * done, which means it's ready to be dequeued. + */ + if (queue->buffer.direction == IIO_BUFFER_DIRECTION_IN) { + block->state = IIO_BLOCK_STATE_QUEUED; + list_add_tail(&block->head, &queue->incoming); + } else { + block->state = IIO_BLOCK_STATE_DONE; + } } out_unlock: @@ -488,20 +516,12 @@ static struct iio_dma_buffer_block *iio_dma_buffer_dequeue( return block; } -/** - * iio_dma_buffer_read() - DMA buffer read callback - * @buffer: Buffer to read form - * @n: Number of bytes to read - * @user_buffer: Userspace buffer to copy the data to - * - * Should be used as the read callback for iio_buffer_access_ops - * struct for DMA buffers. - */ -int iio_dma_buffer_read(struct iio_buffer *buffer, size_t n, - char __user *user_buffer) +static int iio_dma_buffer_io(struct iio_buffer *buffer, size_t n, + char __user *user_buffer, bool is_from_user) { struct iio_dma_buffer_queue *queue = iio_buffer_to_queue(buffer); struct iio_dma_buffer_block *block; + void *addr; int ret; if (n < buffer->bytes_per_datum) @@ -524,8 +544,13 @@ int iio_dma_buffer_read(struct iio_buffer *buffer, size_t n, n = rounddown(n, buffer->bytes_per_datum); if (n > block->bytes_used - queue->fileio.pos) n = block->bytes_used - queue->fileio.pos; + addr = block->vaddr + queue->fileio.pos; - if (copy_to_user(user_buffer, block->vaddr + queue->fileio.pos, n)) { + if (is_from_user) + ret = copy_from_user(addr, user_buffer, n); + else + ret = copy_to_user(user_buffer, addr, n); + if (ret) { ret = -EFAULT; goto out_unlock; } @@ -544,8 +569,40 @@ out_unlock: return ret; } + +/** + * iio_dma_buffer_read() - DMA buffer read callback + * @buffer: Buffer to read form + * @n: Number of bytes to read + * @user_buffer: Userspace buffer to copy the data to + * + * Should be used as the read callback for iio_buffer_access_ops + * struct for DMA buffers. + */ +int iio_dma_buffer_read(struct iio_buffer *buffer, size_t n, + char __user *user_buffer) +{ + return iio_dma_buffer_io(buffer, n, user_buffer, false); +} EXPORT_SYMBOL_GPL(iio_dma_buffer_read); +/** + * iio_dma_buffer_write() - DMA buffer write callback + * @buffer: Buffer to read form + * @n: Number of bytes to read + * @user_buffer: Userspace buffer to copy the data from + * + * Should be used as the write callback for iio_buffer_access_ops + * struct for DMA buffers. + */ +int iio_dma_buffer_write(struct iio_buffer *buffer, size_t n, + const char __user *user_buffer) +{ + return iio_dma_buffer_io(buffer, n, + (__force __user char *)user_buffer, true); +} +EXPORT_SYMBOL_GPL(iio_dma_buffer_write); + /** * iio_dma_buffer_usage() - DMA buffer data_available and * space_available callback diff --git a/include/linux/iio/buffer-dma.h b/include/linux/iio/buffer-dma.h index 52a838ec0e57..6e27e47077d5 100644 --- a/include/linux/iio/buffer-dma.h +++ b/include/linux/iio/buffer-dma.h @@ -132,6 +132,8 @@ int iio_dma_buffer_disable(struct iio_buffer *buffer, struct iio_dev *indio_dev); int iio_dma_buffer_read(struct iio_buffer *buffer, size_t n, char __user *user_buffer); +int iio_dma_buffer_write(struct iio_buffer *buffer, size_t n, + const char __user *user_buffer); size_t iio_dma_buffer_usage(struct iio_buffer *buffer); int iio_dma_buffer_set_bytes_per_datum(struct iio_buffer *buffer, size_t bpd); int iio_dma_buffer_set_length(struct iio_buffer *buffer, unsigned int length); -- cgit v1.2.3-59-g8ed1b From c1b91566580c245cf1147745d174be5e059ace6b Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Fri, 19 Apr 2024 10:25:37 +0200 Subject: iio: buffer-dmaengine: Support specifying buffer direction Update the devm_iio_dmaengine_buffer_setup() function to support specifying the buffer direction. Update the iio_dmaengine_buffer_submit() function to handle input buffers as well as output buffers. Signed-off-by: Paul Cercueil Reviewed-by: Alexandru Ardelean Signed-off-by: Nuno Sa Link: https://lore.kernel.org/r/20240419-iio-backend-axi-dac-v4-4-5ca45b4de294@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/buffer/industrialio-buffer-dmaengine.c | 44 +++++++++++++++------- include/linux/iio/buffer-dmaengine.h | 25 +++++++++--- 2 files changed, 49 insertions(+), 20 deletions(-) diff --git a/drivers/iio/buffer/industrialio-buffer-dmaengine.c b/drivers/iio/buffer/industrialio-buffer-dmaengine.c index df05d66afff9..951012651018 100644 --- a/drivers/iio/buffer/industrialio-buffer-dmaengine.c +++ b/drivers/iio/buffer/industrialio-buffer-dmaengine.c @@ -64,14 +64,25 @@ static int iio_dmaengine_buffer_submit_block(struct iio_dma_buffer_queue *queue, struct dmaengine_buffer *dmaengine_buffer = iio_buffer_to_dmaengine_buffer(&queue->buffer); struct dma_async_tx_descriptor *desc; + enum dma_transfer_direction dma_dir; + size_t max_size; dma_cookie_t cookie; - block->bytes_used = min(block->size, dmaengine_buffer->max_size); - block->bytes_used = round_down(block->bytes_used, - dmaengine_buffer->align); + max_size = min(block->size, dmaengine_buffer->max_size); + max_size = round_down(max_size, dmaengine_buffer->align); + + if (queue->buffer.direction == IIO_BUFFER_DIRECTION_IN) { + block->bytes_used = max_size; + dma_dir = DMA_DEV_TO_MEM; + } else { + dma_dir = DMA_MEM_TO_DEV; + } + + if (!block->bytes_used || block->bytes_used > max_size) + return -EINVAL; desc = dmaengine_prep_slave_single(dmaengine_buffer->chan, - block->phys_addr, block->bytes_used, DMA_DEV_TO_MEM, + block->phys_addr, block->bytes_used, dma_dir, DMA_PREP_INTERRUPT); if (!desc) return -ENOMEM; @@ -229,9 +240,10 @@ void iio_dmaengine_buffer_free(struct iio_buffer *buffer) } EXPORT_SYMBOL_NS_GPL(iio_dmaengine_buffer_free, IIO_DMAENGINE_BUFFER); -struct iio_buffer *iio_dmaengine_buffer_setup(struct device *dev, - struct iio_dev *indio_dev, - const char *channel) +struct iio_buffer *iio_dmaengine_buffer_setup_ext(struct device *dev, + struct iio_dev *indio_dev, + const char *channel, + enum iio_buffer_direction dir) { struct iio_buffer *buffer; int ret; @@ -242,6 +254,8 @@ struct iio_buffer *iio_dmaengine_buffer_setup(struct device *dev, indio_dev->modes |= INDIO_BUFFER_HARDWARE; + buffer->direction = dir; + ret = iio_device_attach_buffer(indio_dev, buffer); if (ret) { iio_dmaengine_buffer_free(buffer); @@ -250,7 +264,7 @@ struct iio_buffer *iio_dmaengine_buffer_setup(struct device *dev, return buffer; } -EXPORT_SYMBOL_NS_GPL(iio_dmaengine_buffer_setup, IIO_DMAENGINE_BUFFER); +EXPORT_SYMBOL_NS_GPL(iio_dmaengine_buffer_setup_ext, IIO_DMAENGINE_BUFFER); static void __devm_iio_dmaengine_buffer_free(void *buffer) { @@ -258,30 +272,32 @@ static void __devm_iio_dmaengine_buffer_free(void *buffer) } /** - * devm_iio_dmaengine_buffer_setup() - Setup a DMA buffer for an IIO device + * devm_iio_dmaengine_buffer_setup_ext() - Setup a DMA buffer for an IIO device * @dev: Parent device for the buffer * @indio_dev: IIO device to which to attach this buffer. * @channel: DMA channel name, typically "rx". + * @dir: Direction of buffer (in or out) * * This allocates a new IIO buffer with devm_iio_dmaengine_buffer_alloc() * and attaches it to an IIO device with iio_device_attach_buffer(). * It also appends the INDIO_BUFFER_HARDWARE mode to the supported modes of the * IIO device. */ -int devm_iio_dmaengine_buffer_setup(struct device *dev, - struct iio_dev *indio_dev, - const char *channel) +int devm_iio_dmaengine_buffer_setup_ext(struct device *dev, + struct iio_dev *indio_dev, + const char *channel, + enum iio_buffer_direction dir) { struct iio_buffer *buffer; - buffer = iio_dmaengine_buffer_setup(dev, indio_dev, channel); + buffer = iio_dmaengine_buffer_setup_ext(dev, indio_dev, channel, dir); if (IS_ERR(buffer)) return PTR_ERR(buffer); return devm_add_action_or_reset(dev, __devm_iio_dmaengine_buffer_free, buffer); } -EXPORT_SYMBOL_NS_GPL(devm_iio_dmaengine_buffer_setup, IIO_DMAENGINE_BUFFER); +EXPORT_SYMBOL_NS_GPL(devm_iio_dmaengine_buffer_setup_ext, IIO_DMAENGINE_BUFFER); MODULE_AUTHOR("Lars-Peter Clausen "); MODULE_DESCRIPTION("DMA buffer for the IIO framework"); diff --git a/include/linux/iio/buffer-dmaengine.h b/include/linux/iio/buffer-dmaengine.h index acb60f9a3fff..81d9a19aeb91 100644 --- a/include/linux/iio/buffer-dmaengine.h +++ b/include/linux/iio/buffer-dmaengine.h @@ -7,15 +7,28 @@ #ifndef __IIO_DMAENGINE_H__ #define __IIO_DMAENGINE_H__ +#include + struct iio_dev; struct device; void iio_dmaengine_buffer_free(struct iio_buffer *buffer); -struct iio_buffer *iio_dmaengine_buffer_setup(struct device *dev, - struct iio_dev *indio_dev, - const char *channel); -int devm_iio_dmaengine_buffer_setup(struct device *dev, - struct iio_dev *indio_dev, - const char *channel); +struct iio_buffer *iio_dmaengine_buffer_setup_ext(struct device *dev, + struct iio_dev *indio_dev, + const char *channel, + enum iio_buffer_direction dir); + +#define iio_dmaengine_buffer_setup(dev, indio_dev, channel) \ + iio_dmaengine_buffer_setup_ext(dev, indio_dev, channel, \ + IIO_BUFFER_DIRECTION_IN) + +int devm_iio_dmaengine_buffer_setup_ext(struct device *dev, + struct iio_dev *indio_dev, + const char *channel, + enum iio_buffer_direction dir); + +#define devm_iio_dmaengine_buffer_setup(dev, indio_dev, channel) \ + devm_iio_dmaengine_buffer_setup_ext(dev, indio_dev, channel, \ + IIO_BUFFER_DIRECTION_IN) #endif -- cgit v1.2.3-59-g8ed1b From 3afb27d15f8ddaa5ce5781d18bb249c683d29260 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Fri, 19 Apr 2024 10:25:38 +0200 Subject: iio: buffer-dmaengine: Enable write support Use the iio_dma_buffer_write() and iio_dma_buffer_space_available() functions provided by the buffer-dma core, to enable write support in the buffer-dmaengine code. Signed-off-by: Paul Cercueil Reviewed-by: Alexandru Ardelean Signed-off-by: Nuno Sa Link: https://lore.kernel.org/r/20240419-iio-backend-axi-dac-v4-5-5ca45b4de294@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/buffer/industrialio-buffer-dmaengine.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/iio/buffer/industrialio-buffer-dmaengine.c b/drivers/iio/buffer/industrialio-buffer-dmaengine.c index 951012651018..918f6f8d65b6 100644 --- a/drivers/iio/buffer/industrialio-buffer-dmaengine.c +++ b/drivers/iio/buffer/industrialio-buffer-dmaengine.c @@ -123,12 +123,14 @@ static void iio_dmaengine_buffer_release(struct iio_buffer *buf) static const struct iio_buffer_access_funcs iio_dmaengine_buffer_ops = { .read = iio_dma_buffer_read, + .write = iio_dma_buffer_write, .set_bytes_per_datum = iio_dma_buffer_set_bytes_per_datum, .set_length = iio_dma_buffer_set_length, .request_update = iio_dma_buffer_request_update, .enable = iio_dma_buffer_enable, .disable = iio_dma_buffer_disable, .data_available = iio_dma_buffer_usage, + .space_available = iio_dma_buffer_usage, .release = iio_dmaengine_buffer_release, .modes = INDIO_BUFFER_HARDWARE, -- cgit v1.2.3-59-g8ed1b From 2d1af46cfe2efff7dbfab5041399641e19c30f81 Mon Sep 17 00:00:00 2001 From: Nuno Sa Date: Fri, 19 Apr 2024 10:25:39 +0200 Subject: dt-bindings: iio: dac: add docs for AXI DAC IP This adds the bindings documentation for the Analog Devices AXI DAC IP core. Reviewed-by: Rob Herring Signed-off-by: Nuno Sa Link: https://lore.kernel.org/r/20240419-iio-backend-axi-dac-v4-6-5ca45b4de294@analog.com Signed-off-by: Jonathan Cameron --- .../devicetree/bindings/iio/dac/adi,axi-dac.yaml | 62 ++++++++++++++++++++++ MAINTAINERS | 7 +++ 2 files changed, 69 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/dac/adi,axi-dac.yaml diff --git a/Documentation/devicetree/bindings/iio/dac/adi,axi-dac.yaml b/Documentation/devicetree/bindings/iio/dac/adi,axi-dac.yaml new file mode 100644 index 000000000000..a55e9bfc66d7 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/dac/adi,axi-dac.yaml @@ -0,0 +1,62 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/dac/adi,axi-dac.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices AXI DAC IP core + +maintainers: + - Nuno Sa + +description: | + Analog Devices Generic AXI DAC IP core for interfacing a DAC device + with a high speed serial (JESD204B/C) or source synchronous parallel + interface (LVDS/CMOS). + Usually, some other interface type (i.e SPI) is used as a control + interface for the actual DAC, while this IP core will interface + to the data-lines of the DAC and handle the streaming of data from + memory via DMA into the DAC. + + https://wiki.analog.com/resources/fpga/docs/axi_dac_ip + +properties: + compatible: + enum: + - adi,axi-dac-9.1.b + + reg: + maxItems: 1 + + dmas: + maxItems: 1 + + dma-names: + items: + - const: tx + + clocks: + maxItems: 1 + + '#io-backend-cells': + const: 0 + +required: + - compatible + - dmas + - reg + - clocks + +additionalProperties: false + +examples: + - | + dac@44a00000 { + compatible = "adi,axi-dac-9.1.b"; + reg = <0x44a00000 0x10000>; + dmas = <&tx_dma 0>; + dma-names = "tx"; + #io-backend-cells = <0>; + clocks = <&axi_clk>; + }; +... diff --git a/MAINTAINERS b/MAINTAINERS index a7287cf44869..2137eb452376 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1399,6 +1399,13 @@ F: sound/soc/codecs/adav* F: sound/soc/codecs/sigmadsp.* F: sound/soc/codecs/ssm* +ANALOG DEVICES INC AXI DAC DRIVER +M: Nuno Sa +L: linux-iio@vger.kernel.org +S: Supported +W: https://ez.analog.com/linux-software-drivers +F: Documentation/devicetree/bindings/iio/dac/adi,axi-dac.yaml + ANALOG DEVICES INC DMA DRIVERS M: Lars-Peter Clausen S: Supported -- cgit v1.2.3-59-g8ed1b From a33486d38ea8f2b1446c4dbda8639eb19af6018b Mon Sep 17 00:00:00 2001 From: Nuno Sa Date: Fri, 19 Apr 2024 10:25:40 +0200 Subject: dt-bindings: iio: dac: add docs for AD9739A This adds the bindings documentation for the 14 bit RF Digital-to-Analog converter. Reviewed-by: Rob Herring Signed-off-by: Nuno Sa Link: https://lore.kernel.org/r/20240419-iio-backend-axi-dac-v4-7-5ca45b4de294@analog.com Signed-off-by: Jonathan Cameron --- .../devicetree/bindings/iio/dac/adi,ad9739a.yaml | 95 ++++++++++++++++++++++ MAINTAINERS | 8 ++ 2 files changed, 103 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/dac/adi,ad9739a.yaml diff --git a/Documentation/devicetree/bindings/iio/dac/adi,ad9739a.yaml b/Documentation/devicetree/bindings/iio/dac/adi,ad9739a.yaml new file mode 100644 index 000000000000..c0b36476113a --- /dev/null +++ b/Documentation/devicetree/bindings/iio/dac/adi,ad9739a.yaml @@ -0,0 +1,95 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/dac/adi,ad9739a.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices AD9739A RF DAC + +maintainers: + - Dragos Bogdan + - Nuno Sa + +description: | + The AD9739A is a 14-bit, 2.5 GSPS high performance RF DACs that are capable + of synthesizing wideband signals from dc up to 3 GHz. + + https://www.analog.com/media/en/technical-documentation/data-sheets/ad9737a_9739a.pdf + +properties: + compatible: + enum: + - adi,ad9739a + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + + reset-gpios: + maxItems: 1 + + interrupts: + maxItems: 1 + + vdd-3p3-supply: + description: 3.3V Digital input supply. + + vdd-supply: + description: 1.8V Digital input supply. + + vdda-supply: + description: 3.3V Analog input supply. + + vddc-supply: + description: 1.8V Clock input supply. + + vref-supply: + description: Input/Output reference supply. + + io-backends: + maxItems: 1 + + adi,full-scale-microamp: + description: This property represents the DAC full scale current. + minimum: 8580 + maximum: 31700 + default: 20000 + +required: + - compatible + - reg + - clocks + - io-backends + - vdd-3p3-supply + - vdd-supply + - vdda-supply + - vddc-supply + +allOf: + - $ref: /schemas/spi/spi-peripheral-props.yaml# + +unevaluatedProperties: false + +examples: + - | + spi { + #address-cells = <1>; + #size-cells = <0>; + + dac@0 { + compatible = "adi,ad9739a"; + reg = <0>; + + clocks = <&dac_clk>; + + io-backends = <&iio_backend>; + + vdd-3p3-supply = <&vdd_3_3>; + vdd-supply = <&vdd>; + vdda-supply = <&vdd_3_3>; + vddc-supply = <&vdd>; + }; + }; +... diff --git a/MAINTAINERS b/MAINTAINERS index 2137eb452376..76e872e320d7 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1234,6 +1234,14 @@ W: https://ez.analog.com/linux-software-drivers F: Documentation/devicetree/bindings/iio/adc/adi,ad7780.yaml F: drivers/iio/adc/ad7780.c +ANALOG DEVICES INC AD9739a DRIVER +M: Nuno Sa +M: Dragos Bogdan +L: linux-iio@vger.kernel.org +S: Supported +W: https://ez.analog.com/linux-software-drivers +F: Documentation/devicetree/bindings/iio/dac/adi,ad9739a.yaml + ANALOG DEVICES INC ADA4250 DRIVER M: Antoniu Miclaus L: linux-iio@vger.kernel.org -- cgit v1.2.3-59-g8ed1b From 87800c4342a29d4e1c378ce72d27e3976d094ffa Mon Sep 17 00:00:00 2001 From: Nuno Sa Date: Fri, 19 Apr 2024 10:25:41 +0200 Subject: iio: backend: add new functionality This adds the needed backend ops for supporting a backend inerfacing with an high speed dac. The new ops are: * data_source_set(); * set_sampling_freq(); * extend_chan_spec(); * ext_info_set(); * ext_info_get(). Also to note the new helpers that are meant to be used by the backends when extending an IIO channel (adding extended info): * iio_backend_ext_info_set(); * iio_backend_ext_info_get(). Signed-off-by: Nuno Sa Link: https://lore.kernel.org/r/20240419-iio-backend-axi-dac-v4-8-5ca45b4de294@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/industrialio-backend.c | 179 +++++++++++++++++++++++++++++++++++++ include/linux/iio/backend.h | 49 ++++++++++ 2 files changed, 228 insertions(+) diff --git a/drivers/iio/industrialio-backend.c b/drivers/iio/industrialio-backend.c index 2fea2bbbe47f..f08ed6d70ae5 100644 --- a/drivers/iio/industrialio-backend.c +++ b/drivers/iio/industrialio-backend.c @@ -43,10 +43,12 @@ #include #include +#include struct iio_backend { struct list_head entry; const struct iio_backend_ops *ops; + struct device *frontend_dev; struct device *dev; struct module *owner; void *priv; @@ -186,6 +188,44 @@ int iio_backend_data_format_set(struct iio_backend *back, unsigned int chan, } EXPORT_SYMBOL_NS_GPL(iio_backend_data_format_set, IIO_BACKEND); +/** + * iio_backend_data_source_set - Select data source + * @back: Backend device + * @chan: Channel number + * @data: Data source + * + * A given backend may have different sources to stream/sync data. This allows + * to choose that source. + * + * RETURNS: + * 0 on success, negative error number on failure. + */ +int iio_backend_data_source_set(struct iio_backend *back, unsigned int chan, + enum iio_backend_data_source data) +{ + if (data >= IIO_BACKEND_DATA_SOURCE_MAX) + return -EINVAL; + + return iio_backend_op_call(back, data_source_set, chan, data); +} +EXPORT_SYMBOL_NS_GPL(iio_backend_data_source_set, IIO_BACKEND); + +/** + * iio_backend_set_sampling_freq - Set channel sampling rate + * @back: Backend device + * @chan: Channel number + * @sample_rate_hz: Sample rate + * + * RETURNS: + * 0 on success, negative error number on failure. + */ +int iio_backend_set_sampling_freq(struct iio_backend *back, unsigned int chan, + u64 sample_rate_hz) +{ + return iio_backend_op_call(back, set_sample_rate, chan, sample_rate_hz); +} +EXPORT_SYMBOL_NS_GPL(iio_backend_set_sampling_freq, IIO_BACKEND); + static void iio_backend_free_buffer(void *arg) { struct iio_backend_buffer_pair *pair = arg; @@ -231,6 +271,143 @@ int devm_iio_backend_request_buffer(struct device *dev, } EXPORT_SYMBOL_NS_GPL(devm_iio_backend_request_buffer, IIO_BACKEND); +static struct iio_backend *iio_backend_from_indio_dev_parent(const struct device *dev) +{ + struct iio_backend *back = ERR_PTR(-ENODEV), *iter; + + /* + * We deliberately go through all backends even after finding a match. + * The reason is that we want to catch frontend devices which have more + * than one backend in which case returning the first we find is bogus. + * For those cases, frontends need to explicitly define + * get_iio_backend() in struct iio_info. + */ + guard(mutex)(&iio_back_lock); + list_for_each_entry(iter, &iio_back_list, entry) { + if (dev == iter->frontend_dev) { + if (!IS_ERR(back)) { + dev_warn(dev, + "Multiple backends! get_iio_backend() needs to be implemented"); + return ERR_PTR(-ENODEV); + } + + back = iter; + } + } + + return back; +} + +/** + * iio_backend_ext_info_get - IIO ext_info read callback + * @indio_dev: IIO device + * @private: Data private to the driver + * @chan: IIO channel + * @buf: Buffer where to place the attribute data + * + * This helper is intended to be used by backends that extend an IIO channel + * (through iio_backend_extend_chan_spec()) with extended info. In that case, + * backends are not supposed to give their own callbacks (as they would not have + * a way to get the backend from indio_dev). This is the getter. + * + * RETURNS: + * Number of bytes written to buf, negative error number on failure. + */ +ssize_t iio_backend_ext_info_get(struct iio_dev *indio_dev, uintptr_t private, + const struct iio_chan_spec *chan, char *buf) +{ + struct iio_backend *back; + + /* + * The below should work for the majority of the cases. It will not work + * when one frontend has multiple backends in which case we'll need a + * new callback in struct iio_info so we can directly request the proper + * backend from the frontend. Anyways, let's only introduce new options + * when really needed... + */ + back = iio_backend_from_indio_dev_parent(indio_dev->dev.parent); + if (IS_ERR(back)) + return PTR_ERR(back); + + return iio_backend_op_call(back, ext_info_get, private, chan, buf); +} +EXPORT_SYMBOL_NS_GPL(iio_backend_ext_info_get, IIO_BACKEND); + +/** + * iio_backend_ext_info_set - IIO ext_info write callback + * @indio_dev: IIO device + * @private: Data private to the driver + * @chan: IIO channel + * @buf: Buffer holding the sysfs attribute + * @len: Buffer length + * + * This helper is intended to be used by backends that extend an IIO channel + * (trough iio_backend_extend_chan_spec()) with extended info. In that case, + * backends are not supposed to give their own callbacks (as they would not have + * a way to get the backend from indio_dev). This is the setter. + * + * RETURNS: + * Buffer length on success, negative error number on failure. + */ +ssize_t iio_backend_ext_info_set(struct iio_dev *indio_dev, uintptr_t private, + const struct iio_chan_spec *chan, + const char *buf, size_t len) +{ + struct iio_backend *back; + + back = iio_backend_from_indio_dev_parent(indio_dev->dev.parent); + if (IS_ERR(back)) + return PTR_ERR(back); + + return iio_backend_op_call(back, ext_info_set, private, chan, buf, len); +} +EXPORT_SYMBOL_NS_GPL(iio_backend_ext_info_set, IIO_BACKEND); + +/** + * iio_backend_extend_chan_spec - Extend an IIO channel + * @indio_dev: IIO device + * @back: Backend device + * @chan: IIO channel + * + * Some backends may have their own functionalities and hence capable of + * extending a frontend's channel. + * + * RETURNS: + * 0 on success, negative error number on failure. + */ +int iio_backend_extend_chan_spec(struct iio_dev *indio_dev, + struct iio_backend *back, + struct iio_chan_spec *chan) +{ + const struct iio_chan_spec_ext_info *frontend_ext_info = chan->ext_info; + const struct iio_chan_spec_ext_info *back_ext_info; + int ret; + + ret = iio_backend_op_call(back, extend_chan_spec, chan); + if (ret) + return ret; + /* + * Let's keep things simple for now. Don't allow to overwrite the + * frontend's extended info. If ever needed, we can support appending + * it. + */ + if (frontend_ext_info && chan->ext_info != frontend_ext_info) + return -EOPNOTSUPP; + if (!chan->ext_info) + return 0; + + /* Don't allow backends to get creative and force their own handlers */ + for (back_ext_info = chan->ext_info; back_ext_info->name; back_ext_info++) { + if (back_ext_info->read != iio_backend_ext_info_get) + return -EINVAL; + if (back_ext_info->write != iio_backend_ext_info_set) + return -EINVAL; + } + + return 0; +} +EXPORT_SYMBOL_NS_GPL(iio_backend_extend_chan_spec, IIO_BACKEND); + static void iio_backend_release(void *arg) { struct iio_backend *back = arg; @@ -263,6 +440,8 @@ static int __devm_iio_backend_get(struct device *dev, struct iio_backend *back) "Could not link to supplier(%s)\n", dev_name(back->dev)); + back->frontend_dev = dev; + dev_dbg(dev, "Found backend(%s) device\n", dev_name(back->dev)); return 0; diff --git a/include/linux/iio/backend.h b/include/linux/iio/backend.h index a6d79381866e..9d144631134d 100644 --- a/include/linux/iio/backend.h +++ b/include/linux/iio/backend.h @@ -4,6 +4,7 @@ #include +struct iio_chan_spec; struct fwnode_handle; struct iio_backend; struct device; @@ -15,6 +16,26 @@ enum iio_backend_data_type { IIO_BACKEND_DATA_TYPE_MAX }; +enum iio_backend_data_source { + IIO_BACKEND_INTERNAL_CONTINUOS_WAVE, + IIO_BACKEND_EXTERNAL, + IIO_BACKEND_DATA_SOURCE_MAX +}; + +/** + * IIO_BACKEND_EX_INFO - Helper for an IIO extended channel attribute + * @_name: Attribute name + * @_shared: Whether the attribute is shared between all channels + * @_what: Data private to the driver + */ +#define IIO_BACKEND_EX_INFO(_name, _shared, _what) { \ + .name = (_name), \ + .shared = (_shared), \ + .read = iio_backend_ext_info_get, \ + .write = iio_backend_ext_info_set, \ + .private = (_what), \ +} + /** * struct iio_backend_data_fmt - Backend data format * @type: Data type. @@ -35,8 +56,13 @@ struct iio_backend_data_fmt { * @chan_enable: Enable one channel. * @chan_disable: Disable one channel. * @data_format_set: Configure the data format for a specific channel. + * @data_source_set: Configure the data source for a specific channel. + * @set_sample_rate: Configure the sampling rate for a specific channel. * @request_buffer: Request an IIO buffer. * @free_buffer: Free an IIO buffer. + * @extend_chan_spec: Extend an IIO channel. + * @ext_info_set: Extended info setter. + * @ext_info_get: Extended info getter. **/ struct iio_backend_ops { int (*enable)(struct iio_backend *back); @@ -45,10 +71,21 @@ struct iio_backend_ops { int (*chan_disable)(struct iio_backend *back, unsigned int chan); int (*data_format_set)(struct iio_backend *back, unsigned int chan, const struct iio_backend_data_fmt *data); + int (*data_source_set)(struct iio_backend *back, unsigned int chan, + enum iio_backend_data_source data); + int (*set_sample_rate)(struct iio_backend *back, unsigned int chan, + u64 sample_rate_hz); struct iio_buffer *(*request_buffer)(struct iio_backend *back, struct iio_dev *indio_dev); void (*free_buffer)(struct iio_backend *back, struct iio_buffer *buffer); + int (*extend_chan_spec)(struct iio_backend *back, + struct iio_chan_spec *chan); + int (*ext_info_set)(struct iio_backend *back, uintptr_t private, + const struct iio_chan_spec *chan, + const char *buf, size_t len); + int (*ext_info_get)(struct iio_backend *back, uintptr_t private, + const struct iio_chan_spec *chan, char *buf); }; int iio_backend_chan_enable(struct iio_backend *back, unsigned int chan); @@ -56,10 +93,22 @@ int iio_backend_chan_disable(struct iio_backend *back, unsigned int chan); int devm_iio_backend_enable(struct device *dev, struct iio_backend *back); int iio_backend_data_format_set(struct iio_backend *back, unsigned int chan, const struct iio_backend_data_fmt *data); +int iio_backend_data_source_set(struct iio_backend *back, unsigned int chan, + enum iio_backend_data_source data); +int iio_backend_set_sampling_freq(struct iio_backend *back, unsigned int chan, + u64 sample_rate_hz); int devm_iio_backend_request_buffer(struct device *dev, struct iio_backend *back, struct iio_dev *indio_dev); +ssize_t iio_backend_ext_info_set(struct iio_dev *indio_dev, uintptr_t private, + const struct iio_chan_spec *chan, + const char *buf, size_t len); +ssize_t iio_backend_ext_info_get(struct iio_dev *indio_dev, uintptr_t private, + const struct iio_chan_spec *chan, char *buf); +int iio_backend_extend_chan_spec(struct iio_dev *indio_dev, + struct iio_backend *back, + struct iio_chan_spec *chan); void *iio_backend_get_priv(const struct iio_backend *conv); struct iio_backend *devm_iio_backend_get(struct device *dev, const char *name); struct iio_backend * -- cgit v1.2.3-59-g8ed1b From 4e3949a192e45a8e3543dbdbc853b90c3c25692e Mon Sep 17 00:00:00 2001 From: Nuno Sa Date: Fri, 19 Apr 2024 10:25:42 +0200 Subject: iio: dac: add support for AXI DAC IP core Support the Analog Devices Generic AXI DAC IP core. The IP core is used for interfacing with digital-to-analog (DAC) converters that require either a high-speed serial interface (JESD204B/C) or a source synchronous parallel interface (LVDS/CMOS). Typically (for such devices) SPI will be used for configuration only, while this IP core handles the streaming of data into memory via DMA. Signed-off-by: Nuno Sa Link: https://lore.kernel.org/r/20240419-iio-backend-axi-dac-v4-9-5ca45b4de294@analog.com Signed-off-by: Jonathan Cameron --- MAINTAINERS | 1 + drivers/iio/dac/Kconfig | 21 ++ drivers/iio/dac/Makefile | 1 + drivers/iio/dac/adi-axi-dac.c | 635 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 658 insertions(+) create mode 100644 drivers/iio/dac/adi-axi-dac.c diff --git a/MAINTAINERS b/MAINTAINERS index 76e872e320d7..505f28dc6da6 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1413,6 +1413,7 @@ L: linux-iio@vger.kernel.org S: Supported W: https://ez.analog.com/linux-software-drivers F: Documentation/devicetree/bindings/iio/dac/adi,axi-dac.yaml +F: drivers/iio/dac/adi-axi-dac.c ANALOG DEVICES INC DMA DRIVERS M: Lars-Peter Clausen diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig index 34eb40bb9529..7c0a8caa9a34 100644 --- a/drivers/iio/dac/Kconfig +++ b/drivers/iio/dac/Kconfig @@ -131,6 +131,27 @@ config AD5624R_SPI Say yes here to build support for Analog Devices AD5624R, AD5644R and AD5664R converters (DAC). This driver uses the common SPI interface. +config ADI_AXI_DAC + tristate "Analog Devices Generic AXI DAC IP core driver" + select IIO_BUFFER + select IIO_BUFFER_DMAENGINE + select REGMAP_MMIO + select IIO_BACKEND + help + Say yes here to build support for Analog Devices Generic + AXI DAC IP core. The IP core is used for interfacing with + digital-to-analog (DAC) converters that require either a high-speed + serial interface (JESD204B/C) or a source synchronous parallel + interface (LVDS/CMOS). + Typically (for such devices) SPI will be used for configuration only, + while this IP core handles the streaming of data into memory via DMA. + + Link: https://wiki.analog.com/resources/fpga/docs/axi_dac_ip + If unsure, say N (but it's safe to say "Y"). + + To compile this driver as a module, choose M here: the + module will be called adi-axi-dac. + config LTC2688 tristate "Analog Devices LTC2688 DAC spi driver" depends on SPI diff --git a/drivers/iio/dac/Makefile b/drivers/iio/dac/Makefile index 55bf89739d14..6bcaa65434b2 100644 --- a/drivers/iio/dac/Makefile +++ b/drivers/iio/dac/Makefile @@ -29,6 +29,7 @@ obj-$(CONFIG_AD5696_I2C) += ad5696-i2c.o obj-$(CONFIG_AD7293) += ad7293.o obj-$(CONFIG_AD7303) += ad7303.o obj-$(CONFIG_AD8801) += ad8801.o +obj-$(CONFIG_ADI_AXI_DAC) += adi-axi-dac.o obj-$(CONFIG_CIO_DAC) += cio-dac.o obj-$(CONFIG_DPOT_DAC) += dpot-dac.o obj-$(CONFIG_DS4424) += ds4424.o diff --git a/drivers/iio/dac/adi-axi-dac.c b/drivers/iio/dac/adi-axi-dac.c new file mode 100644 index 000000000000..9047c5aec0ff --- /dev/null +++ b/drivers/iio/dac/adi-axi-dac.c @@ -0,0 +1,635 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Analog Devices Generic AXI DAC IP core + * Link: https://wiki.analog.com/resources/fpga/docs/axi_dac_ip + * + * Copyright 2016-2024 Analog Devices Inc. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* + * Register definitions: + * https://wiki.analog.com/resources/fpga/docs/axi_dac_ip#register_map + */ + +/* Base controls */ +#define AXI_DAC_REG_CONFIG 0x0c +#define AXI_DDS_DISABLE BIT(6) + + /* DAC controls */ +#define AXI_DAC_REG_RSTN 0x0040 +#define AXI_DAC_RSTN_CE_N BIT(2) +#define AXI_DAC_RSTN_MMCM_RSTN BIT(1) +#define AXI_DAC_RSTN_RSTN BIT(0) +#define AXI_DAC_REG_CNTRL_1 0x0044 +#define AXI_DAC_SYNC BIT(0) +#define AXI_DAC_REG_CNTRL_2 0x0048 +#define ADI_DAC_R1_MODE BIT(4) +#define AXI_DAC_DRP_STATUS 0x0074 +#define AXI_DAC_DRP_LOCKED BIT(17) +/* DAC Channel controls */ +#define AXI_DAC_REG_CHAN_CNTRL_1(c) (0x0400 + (c) * 0x40) +#define AXI_DAC_REG_CHAN_CNTRL_3(c) (0x0408 + (c) * 0x40) +#define AXI_DAC_SCALE_SIGN BIT(15) +#define AXI_DAC_SCALE_INT BIT(14) +#define AXI_DAC_SCALE GENMASK(14, 0) +#define AXI_DAC_REG_CHAN_CNTRL_2(c) (0x0404 + (c) * 0x40) +#define AXI_DAC_REG_CHAN_CNTRL_4(c) (0x040c + (c) * 0x40) +#define AXI_DAC_PHASE GENMASK(31, 16) +#define AXI_DAC_FREQUENCY GENMASK(15, 0) +#define AXI_DAC_REG_CHAN_CNTRL_7(c) (0x0418 + (c) * 0x40) +#define AXI_DAC_DATA_SEL GENMASK(3, 0) + +/* 360 degrees in rad */ +#define AXI_DAC_2_PI_MEGA 6283190 +enum { + AXI_DAC_DATA_INTERNAL_TONE, + AXI_DAC_DATA_DMA = 2, +}; + +struct axi_dac_state { + struct regmap *regmap; + struct device *dev; + /* + * lock to protect multiple accesses to the device registers and global + * data/variables. + */ + struct mutex lock; + u64 dac_clk; + u32 reg_config; + bool int_tone; +}; + +static int axi_dac_enable(struct iio_backend *back) +{ + struct axi_dac_state *st = iio_backend_get_priv(back); + unsigned int __val; + int ret; + + guard(mutex)(&st->lock); + ret = regmap_set_bits(st->regmap, AXI_DAC_REG_RSTN, + AXI_DAC_RSTN_MMCM_RSTN); + if (ret) + return ret; + /* + * Make sure the DRP (Dynamic Reconfiguration Port) is locked. Not all + * designs really use it but if they don't we still get the lock bit + * set. So let's do it all the time so the code is generic. + */ + ret = regmap_read_poll_timeout(st->regmap, AXI_DAC_DRP_STATUS, __val, + __val & AXI_DAC_DRP_LOCKED, 100, 1000); + if (ret) + return ret; + + return regmap_set_bits(st->regmap, AXI_DAC_REG_RSTN, + AXI_DAC_RSTN_RSTN | AXI_DAC_RSTN_MMCM_RSTN); +} + +static void axi_dac_disable(struct iio_backend *back) +{ + struct axi_dac_state *st = iio_backend_get_priv(back); + + guard(mutex)(&st->lock); + regmap_write(st->regmap, AXI_DAC_REG_RSTN, 0); +} + +static struct iio_buffer *axi_dac_request_buffer(struct iio_backend *back, + struct iio_dev *indio_dev) +{ + struct axi_dac_state *st = iio_backend_get_priv(back); + const char *dma_name; + + if (device_property_read_string(st->dev, "dma-names", &dma_name)) + dma_name = "tx"; + + return iio_dmaengine_buffer_setup_ext(st->dev, indio_dev, dma_name, + IIO_BUFFER_DIRECTION_OUT); +} + +static void axi_dac_free_buffer(struct iio_backend *back, + struct iio_buffer *buffer) +{ + iio_dmaengine_buffer_free(buffer); +} + +enum { + AXI_DAC_FREQ_TONE_1, + AXI_DAC_FREQ_TONE_2, + AXI_DAC_SCALE_TONE_1, + AXI_DAC_SCALE_TONE_2, + AXI_DAC_PHASE_TONE_1, + AXI_DAC_PHASE_TONE_2, +}; + +static int __axi_dac_frequency_get(struct axi_dac_state *st, unsigned int chan, + unsigned int tone_2, unsigned int *freq) +{ + u32 reg, raw; + int ret; + + if (!st->dac_clk) { + dev_err(st->dev, "Sampling rate is 0...\n"); + return -EINVAL; + } + + if (tone_2) + reg = AXI_DAC_REG_CHAN_CNTRL_4(chan); + else + reg = AXI_DAC_REG_CHAN_CNTRL_2(chan); + + ret = regmap_read(st->regmap, reg, &raw); + if (ret) + return ret; + + raw = FIELD_GET(AXI_DAC_FREQUENCY, raw); + *freq = DIV_ROUND_CLOSEST_ULL(raw * st->dac_clk, BIT(16)); + + return 0; +} + +static int axi_dac_frequency_get(struct axi_dac_state *st, + const struct iio_chan_spec *chan, char *buf, + unsigned int tone_2) +{ + unsigned int freq; + int ret; + + scoped_guard(mutex, &st->lock) { + ret = __axi_dac_frequency_get(st, chan->channel, tone_2, &freq); + if (ret) + return ret; + } + + return sysfs_emit(buf, "%u\n", freq); +} + +static int axi_dac_scale_get(struct axi_dac_state *st, + const struct iio_chan_spec *chan, char *buf, + unsigned int tone_2) +{ + unsigned int scale, sign; + int ret, vals[2]; + u32 reg, raw; + + if (tone_2) + reg = AXI_DAC_REG_CHAN_CNTRL_3(chan->channel); + else + reg = AXI_DAC_REG_CHAN_CNTRL_1(chan->channel); + + ret = regmap_read(st->regmap, reg, &raw); + if (ret) + return ret; + + sign = FIELD_GET(AXI_DAC_SCALE_SIGN, raw); + raw = FIELD_GET(AXI_DAC_SCALE, raw); + scale = DIV_ROUND_CLOSEST_ULL((u64)raw * MEGA, AXI_DAC_SCALE_INT); + + vals[0] = scale / MEGA; + vals[1] = scale % MEGA; + + if (sign) { + vals[0] *= -1; + if (!vals[0]) + vals[1] *= -1; + } + + return iio_format_value(buf, IIO_VAL_INT_PLUS_MICRO, ARRAY_SIZE(vals), + vals); +} + +static int axi_dac_phase_get(struct axi_dac_state *st, + const struct iio_chan_spec *chan, char *buf, + unsigned int tone_2) +{ + u32 reg, raw, phase; + int ret, vals[2]; + + if (tone_2) + reg = AXI_DAC_REG_CHAN_CNTRL_4(chan->channel); + else + reg = AXI_DAC_REG_CHAN_CNTRL_2(chan->channel); + + ret = regmap_read(st->regmap, reg, &raw); + if (ret) + return ret; + + raw = FIELD_GET(AXI_DAC_PHASE, raw); + phase = DIV_ROUND_CLOSEST_ULL((u64)raw * AXI_DAC_2_PI_MEGA, U16_MAX); + + vals[0] = phase / MEGA; + vals[1] = phase % MEGA; + + return iio_format_value(buf, IIO_VAL_INT_PLUS_MICRO, ARRAY_SIZE(vals), + vals); +} + +static int __axi_dac_frequency_set(struct axi_dac_state *st, unsigned int chan, + u64 sample_rate, unsigned int freq, + unsigned int tone_2) +{ + u32 reg; + u16 raw; + int ret; + + if (!sample_rate || freq > sample_rate / 2) { + dev_err(st->dev, "Invalid frequency(%u) dac_clk(%llu)\n", + freq, sample_rate); + return -EINVAL; + } + + if (tone_2) + reg = AXI_DAC_REG_CHAN_CNTRL_4(chan); + else + reg = AXI_DAC_REG_CHAN_CNTRL_2(chan); + + raw = DIV64_U64_ROUND_CLOSEST((u64)freq * BIT(16), sample_rate); + + ret = regmap_update_bits(st->regmap, reg, AXI_DAC_FREQUENCY, raw); + if (ret) + return ret; + + /* synchronize channels */ + return regmap_set_bits(st->regmap, AXI_DAC_REG_CNTRL_1, AXI_DAC_SYNC); +} + +static int axi_dac_frequency_set(struct axi_dac_state *st, + const struct iio_chan_spec *chan, + const char *buf, size_t len, unsigned int tone_2) +{ + unsigned int freq; + int ret; + + ret = kstrtou32(buf, 10, &freq); + if (ret) + return ret; + + guard(mutex)(&st->lock); + ret = __axi_dac_frequency_set(st, chan->channel, st->dac_clk, freq, + tone_2); + if (ret) + return ret; + + return len; +} + +static int axi_dac_scale_set(struct axi_dac_state *st, + const struct iio_chan_spec *chan, + const char *buf, size_t len, unsigned int tone_2) +{ + int integer, frac, scale; + u32 raw = 0, reg; + int ret; + + ret = iio_str_to_fixpoint(buf, 100000, &integer, &frac); + if (ret) + return ret; + + scale = integer * MEGA + frac; + if (scale <= -2 * (int)MEGA || scale >= 2 * (int)MEGA) + return -EINVAL; + + /* format is 1.1.14 (sign, integer and fractional bits) */ + if (scale < 0) { + raw = FIELD_PREP(AXI_DAC_SCALE_SIGN, 1); + scale *= -1; + } + + raw |= div_u64((u64)scale * AXI_DAC_SCALE_INT, MEGA); + + if (tone_2) + reg = AXI_DAC_REG_CHAN_CNTRL_3(chan->channel); + else + reg = AXI_DAC_REG_CHAN_CNTRL_1(chan->channel); + + guard(mutex)(&st->lock); + ret = regmap_write(st->regmap, reg, raw); + if (ret) + return ret; + + /* synchronize channels */ + ret = regmap_set_bits(st->regmap, AXI_DAC_REG_CNTRL_1, AXI_DAC_SYNC); + if (ret) + return ret; + + return len; +} + +static int axi_dac_phase_set(struct axi_dac_state *st, + const struct iio_chan_spec *chan, + const char *buf, size_t len, unsigned int tone_2) +{ + int integer, frac, phase; + u32 raw, reg; + int ret; + + ret = iio_str_to_fixpoint(buf, 100000, &integer, &frac); + if (ret) + return ret; + + phase = integer * MEGA + frac; + if (phase < 0 || phase > AXI_DAC_2_PI_MEGA) + return -EINVAL; + + raw = DIV_ROUND_CLOSEST_ULL((u64)phase * U16_MAX, AXI_DAC_2_PI_MEGA); + + if (tone_2) + reg = AXI_DAC_REG_CHAN_CNTRL_4(chan->channel); + else + reg = AXI_DAC_REG_CHAN_CNTRL_2(chan->channel); + + guard(mutex)(&st->lock); + ret = regmap_update_bits(st->regmap, reg, AXI_DAC_PHASE, + FIELD_PREP(AXI_DAC_PHASE, raw)); + if (ret) + return ret; + + /* synchronize channels */ + ret = regmap_set_bits(st->regmap, AXI_DAC_REG_CNTRL_1, AXI_DAC_SYNC); + if (ret) + return ret; + + return len; +} + +static int axi_dac_ext_info_set(struct iio_backend *back, uintptr_t private, + const struct iio_chan_spec *chan, + const char *buf, size_t len) +{ + struct axi_dac_state *st = iio_backend_get_priv(back); + + switch (private) { + case AXI_DAC_FREQ_TONE_1: + case AXI_DAC_FREQ_TONE_2: + return axi_dac_frequency_set(st, chan, buf, len, + private - AXI_DAC_FREQ_TONE_1); + case AXI_DAC_SCALE_TONE_1: + case AXI_DAC_SCALE_TONE_2: + return axi_dac_scale_set(st, chan, buf, len, + private - AXI_DAC_SCALE_TONE_1); + case AXI_DAC_PHASE_TONE_1: + case AXI_DAC_PHASE_TONE_2: + return axi_dac_phase_set(st, chan, buf, len, + private - AXI_DAC_PHASE_TONE_2); + default: + return -EOPNOTSUPP; + } +} + +static int axi_dac_ext_info_get(struct iio_backend *back, uintptr_t private, + const struct iio_chan_spec *chan, char *buf) +{ + struct axi_dac_state *st = iio_backend_get_priv(back); + + switch (private) { + case AXI_DAC_FREQ_TONE_1: + case AXI_DAC_FREQ_TONE_2: + return axi_dac_frequency_get(st, chan, buf, + private - AXI_DAC_FREQ_TONE_1); + case AXI_DAC_SCALE_TONE_1: + case AXI_DAC_SCALE_TONE_2: + return axi_dac_scale_get(st, chan, buf, + private - AXI_DAC_SCALE_TONE_1); + case AXI_DAC_PHASE_TONE_1: + case AXI_DAC_PHASE_TONE_2: + return axi_dac_phase_get(st, chan, buf, + private - AXI_DAC_PHASE_TONE_1); + default: + return -EOPNOTSUPP; + } +} + +static const struct iio_chan_spec_ext_info axi_dac_ext_info[] = { + IIO_BACKEND_EX_INFO("frequency0", IIO_SEPARATE, AXI_DAC_FREQ_TONE_1), + IIO_BACKEND_EX_INFO("frequency1", IIO_SEPARATE, AXI_DAC_FREQ_TONE_2), + IIO_BACKEND_EX_INFO("scale0", IIO_SEPARATE, AXI_DAC_SCALE_TONE_1), + IIO_BACKEND_EX_INFO("scale1", IIO_SEPARATE, AXI_DAC_SCALE_TONE_2), + IIO_BACKEND_EX_INFO("phase0", IIO_SEPARATE, AXI_DAC_PHASE_TONE_1), + IIO_BACKEND_EX_INFO("phase1", IIO_SEPARATE, AXI_DAC_PHASE_TONE_2), + {} +}; + +static int axi_dac_extend_chan(struct iio_backend *back, + struct iio_chan_spec *chan) +{ + struct axi_dac_state *st = iio_backend_get_priv(back); + + if (chan->type != IIO_ALTVOLTAGE) + return -EINVAL; + if (st->reg_config & AXI_DDS_DISABLE) + /* nothing to extend */ + return 0; + + chan->ext_info = axi_dac_ext_info; + + return 0; +} + +static int axi_dac_data_source_set(struct iio_backend *back, unsigned int chan, + enum iio_backend_data_source data) +{ + struct axi_dac_state *st = iio_backend_get_priv(back); + + switch (data) { + case IIO_BACKEND_INTERNAL_CONTINUOS_WAVE: + return regmap_update_bits(st->regmap, + AXI_DAC_REG_CHAN_CNTRL_7(chan), + AXI_DAC_DATA_SEL, + AXI_DAC_DATA_INTERNAL_TONE); + case IIO_BACKEND_EXTERNAL: + return regmap_update_bits(st->regmap, + AXI_DAC_REG_CHAN_CNTRL_7(chan), + AXI_DAC_DATA_SEL, AXI_DAC_DATA_DMA); + default: + return -EINVAL; + } +} + +static int axi_dac_set_sample_rate(struct iio_backend *back, unsigned int chan, + u64 sample_rate) +{ + struct axi_dac_state *st = iio_backend_get_priv(back); + unsigned int freq; + int ret, tone; + + if (!sample_rate) + return -EINVAL; + if (st->reg_config & AXI_DDS_DISABLE) + /* sample_rate has no meaning if DDS is disabled */ + return 0; + + guard(mutex)(&st->lock); + /* + * If dac_clk is 0 then this must be the first time we're being notified + * about the interface sample rate. Hence, just update our internal + * variable and bail... If it's not 0, then we get the current DDS + * frequency (for the old rate) and update the registers for the new + * sample rate. + */ + if (!st->dac_clk) { + st->dac_clk = sample_rate; + return 0; + } + + for (tone = 0; tone <= AXI_DAC_FREQ_TONE_2; tone++) { + ret = __axi_dac_frequency_get(st, chan, tone, &freq); + if (ret) + return ret; + + ret = __axi_dac_frequency_set(st, chan, sample_rate, tone, freq); + if (ret) + return ret; + } + + st->dac_clk = sample_rate; + + return 0; +} + +static const struct iio_backend_ops axi_dac_generic = { + .enable = axi_dac_enable, + .disable = axi_dac_disable, + .request_buffer = axi_dac_request_buffer, + .free_buffer = axi_dac_free_buffer, + .extend_chan_spec = axi_dac_extend_chan, + .ext_info_set = axi_dac_ext_info_set, + .ext_info_get = axi_dac_ext_info_get, + .data_source_set = axi_dac_data_source_set, + .set_sample_rate = axi_dac_set_sample_rate, +}; + +static const struct regmap_config axi_dac_regmap_config = { + .val_bits = 32, + .reg_bits = 32, + .reg_stride = 4, + .max_register = 0x0800, +}; + +static int axi_dac_probe(struct platform_device *pdev) +{ + const unsigned int *expected_ver; + struct axi_dac_state *st; + void __iomem *base; + unsigned int ver; + struct clk *clk; + int ret; + + st = devm_kzalloc(&pdev->dev, sizeof(*st), GFP_KERNEL); + if (!st) + return -ENOMEM; + + expected_ver = device_get_match_data(&pdev->dev); + if (!expected_ver) + return -ENODEV; + + clk = devm_clk_get_enabled(&pdev->dev, NULL); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(base)) + return PTR_ERR(base); + + st->dev = &pdev->dev; + st->regmap = devm_regmap_init_mmio(&pdev->dev, base, + &axi_dac_regmap_config); + if (IS_ERR(st->regmap)) + return PTR_ERR(st->regmap); + + /* + * Force disable the core. Up to the frontend to enable us. And we can + * still read/write registers... + */ + ret = regmap_write(st->regmap, AXI_DAC_REG_RSTN, 0); + if (ret) + return ret; + + ret = regmap_read(st->regmap, ADI_AXI_REG_VERSION, &ver); + if (ret) + return ret; + + if (ADI_AXI_PCORE_VER_MAJOR(ver) != ADI_AXI_PCORE_VER_MAJOR(*expected_ver)) { + dev_err(&pdev->dev, + "Major version mismatch. Expected %d.%.2d.%c, Reported %d.%.2d.%c\n", + ADI_AXI_PCORE_VER_MAJOR(*expected_ver), + ADI_AXI_PCORE_VER_MINOR(*expected_ver), + ADI_AXI_PCORE_VER_PATCH(*expected_ver), + ADI_AXI_PCORE_VER_MAJOR(ver), + ADI_AXI_PCORE_VER_MINOR(ver), + ADI_AXI_PCORE_VER_PATCH(ver)); + return -ENODEV; + } + + /* Let's get the core read only configuration */ + ret = regmap_read(st->regmap, AXI_DAC_REG_CONFIG, &st->reg_config); + if (ret) + return ret; + + /* + * In some designs, setting the R1_MODE bit to 0 (which is the default + * value) causes all channels of the frontend to be routed to the same + * DMA (so they are sampled together). This is for things like + * Multiple-Input and Multiple-Output (MIMO). As most of the times we + * want independent channels let's override the core's default value and + * set the R1_MODE bit. + */ + ret = regmap_set_bits(st->regmap, AXI_DAC_REG_CNTRL_2, ADI_DAC_R1_MODE); + if (ret) + return ret; + + mutex_init(&st->lock); + ret = devm_iio_backend_register(&pdev->dev, &axi_dac_generic, st); + if (ret) + return ret; + + dev_info(&pdev->dev, "AXI DAC IP core (%d.%.2d.%c) probed\n", + ADI_AXI_PCORE_VER_MAJOR(ver), + ADI_AXI_PCORE_VER_MINOR(ver), + ADI_AXI_PCORE_VER_PATCH(ver)); + + return 0; +} + +static unsigned int axi_dac_9_1_b_info = ADI_AXI_PCORE_VER(9, 1, 'b'); + +static const struct of_device_id axi_dac_of_match[] = { + { .compatible = "adi,axi-dac-9.1.b", .data = &axi_dac_9_1_b_info }, + {} +}; +MODULE_DEVICE_TABLE(of, axi_dac_of_match); + +static struct platform_driver axi_dac_driver = { + .driver = { + .name = "adi-axi-dac", + .of_match_table = axi_dac_of_match, + }, + .probe = axi_dac_probe, +}; +module_platform_driver(axi_dac_driver); + +MODULE_AUTHOR("Nuno Sa "); +MODULE_DESCRIPTION("Analog Devices Generic AXI DAC IP core driver"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(IIO_DMAENGINE_BUFFER); +MODULE_IMPORT_NS(IIO_BACKEND); -- cgit v1.2.3-59-g8ed1b From e77603d5468b9093c111a998a86604e21a9e7f48 Mon Sep 17 00:00:00 2001 From: Nuno Sa Date: Fri, 19 Apr 2024 10:25:43 +0200 Subject: iio: dac: support the ad9739a RF DAC The AD9739A is a 14-bit, 2.5 GSPS high performance RF DACs that are capable of synthesizing wideband signals from DC up to 3 GHz. A dual-port, source synchronous, LVDS interface simplifies the digital interface with existing FGPA/ASIC technology. On-chip controllers are used to manage external and internal clock domain variations over temperature to ensure reliable data transfer from the host to the DAC core. Co-developed-by: Dragos Bogdan Signed-off-by: Dragos Bogdan Signed-off-by: Nuno Sa Link: https://lore.kernel.org/r/20240419-iio-backend-axi-dac-v4-10-5ca45b4de294@analog.com Signed-off-by: Jonathan Cameron --- Documentation/ABI/testing/sysfs-bus-iio-ad9739a | 19 + MAINTAINERS | 1 + drivers/iio/dac/Kconfig | 16 + drivers/iio/dac/Makefile | 1 + drivers/iio/dac/ad9739a.c | 463 ++++++++++++++++++++++++ 5 files changed, 500 insertions(+) create mode 100644 Documentation/ABI/testing/sysfs-bus-iio-ad9739a create mode 100644 drivers/iio/dac/ad9739a.c diff --git a/Documentation/ABI/testing/sysfs-bus-iio-ad9739a b/Documentation/ABI/testing/sysfs-bus-iio-ad9739a new file mode 100644 index 000000000000..ed59299e6f8d --- /dev/null +++ b/Documentation/ABI/testing/sysfs-bus-iio-ad9739a @@ -0,0 +1,19 @@ +What: /sys/bus/iio/devices/iio:deviceX/out_voltageY_operating_mode +KernelVersion: 6.9 +Contact: linux-iio@vger.kernel.org +Description: + DAC operating mode. One of the following modes can be selected: + + * normal: This is DAC normal mode. + * mixed-mode: In this mode the output is effectively chopped at + the DAC sample rate. This has the effect of + reducing the power of the fundamental signal while + increasing the power of the images centered around + the DAC sample rate, thus improving the output + power of these images. + +What: /sys/bus/iio/devices/iio:deviceX/out_voltageY_operating_mode_available +KernelVersion: 6.9 +Contact: linux-iio@vger.kernel.org +Description: + Available operating modes. diff --git a/MAINTAINERS b/MAINTAINERS index 505f28dc6da6..8ad79cf70552 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1241,6 +1241,7 @@ L: linux-iio@vger.kernel.org S: Supported W: https://ez.analog.com/linux-software-drivers F: Documentation/devicetree/bindings/iio/dac/adi,ad9739a.yaml +F: drivers/iio/dac/ad9739a.c ANALOG DEVICES INC ADA4250 DRIVER M: Antoniu Miclaus diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig index 7c0a8caa9a34..3c2bf620f00f 100644 --- a/drivers/iio/dac/Kconfig +++ b/drivers/iio/dac/Kconfig @@ -131,6 +131,22 @@ config AD5624R_SPI Say yes here to build support for Analog Devices AD5624R, AD5644R and AD5664R converters (DAC). This driver uses the common SPI interface. +config AD9739A + tristate "Analog Devices AD9739A RF DAC spi driver" + depends on SPI || COMPILE_TEST + select REGMAP_SPI + select IIO_BACKEND + help + Say yes here to build support for Analog Devices AD9739A Digital-to + Analog Converter. + + The driver requires the assistance of the AXI DAC IP core to operate, + since SPI is used for configuration only, while data has to be + streamed into memory via DMA. + + To compile this driver as a module, choose M here: the module will be + called ad9739a. + config ADI_AXI_DAC tristate "Analog Devices Generic AXI DAC IP core driver" select IIO_BUFFER diff --git a/drivers/iio/dac/Makefile b/drivers/iio/dac/Makefile index 6bcaa65434b2..8432a81a19dc 100644 --- a/drivers/iio/dac/Makefile +++ b/drivers/iio/dac/Makefile @@ -29,6 +29,7 @@ obj-$(CONFIG_AD5696_I2C) += ad5696-i2c.o obj-$(CONFIG_AD7293) += ad7293.o obj-$(CONFIG_AD7303) += ad7303.o obj-$(CONFIG_AD8801) += ad8801.o +obj-$(CONFIG_AD9739A) += ad9739a.o obj-$(CONFIG_ADI_AXI_DAC) += adi-axi-dac.o obj-$(CONFIG_CIO_DAC) += cio-dac.o obj-$(CONFIG_DPOT_DAC) += dpot-dac.o diff --git a/drivers/iio/dac/ad9739a.c b/drivers/iio/dac/ad9739a.c new file mode 100644 index 000000000000..ff33120075bf --- /dev/null +++ b/drivers/iio/dac/ad9739a.c @@ -0,0 +1,463 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Analog Devices AD9739a SPI DAC driver + * + * Copyright 2015-2024 Analog Devices Inc. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define AD9739A_REG_MODE 0 +#define AD9739A_RESET_MASK BIT(5) +#define AD9739A_REG_FSC_1 0x06 +#define AD9739A_REG_FSC_2 0x07 +#define AD9739A_FSC_MSB GENMASK(1, 0) +#define AD9739A_REG_DEC_CNT 0x8 +#define AD9739A_NORMAL_MODE 0 +#define AD9739A_MIXED_MODE 2 +#define AD9739A_DAC_DEC GENMASK(1, 0) +#define AD9739A_REG_LVDS_REC_CNT1 0x10 +#define AD9739A_RCVR_LOOP_EN_MASK GENMASK(1, 0) +#define AD9739A_REG_LVDS_REC_CNT4 0x13 +#define AD9739A_FINE_DEL_SKW_MASK GENMASK(3, 0) +#define AD9739A_REG_LVDS_REC_STAT9 0x21 +#define AD9739A_RCVR_TRACK_AND_LOCK (BIT(3) | BIT(0)) +#define AD9739A_REG_CROSS_CNT1 0x22 +#define AD9739A_REG_CROSS_CNT2 0x23 +#define AD9739A_REG_PHS_DET 0x24 +#define AD9739A_REG_MU_DUTY 0x25 +#define AD9739A_REG_MU_CNT1 0x26 +#define AD9739A_MU_EN_MASK BIT(0) +#define AD9739A_REG_MU_CNT2 0x27 +#define AD9739A_REG_MU_CNT3 0x28 +#define AD9739A_REG_MU_CNT4 0x29 +#define AD9739A_MU_CNT4_DEFAULT 0xcb +#define AD9739A_REG_MU_STAT1 0x2A +#define AD9739A_MU_LOCK_MASK BIT(0) +#define AD9739A_REG_ANA_CNT_1 0x32 +#define AD9739A_REG_ID 0x35 + +#define AD9739A_ID 0x24 +#define AD9739A_REG_IS_RESERVED(reg) \ + ((reg) == 0x5 || (reg) == 0x9 || (reg) == 0x0E || (reg) == 0x0D || \ + (reg) == 0x2B || (reg) == 0x2C || (reg) == 0x34) + +#define AD9739A_FSC_MIN 8580 +#define AD9739A_FSC_MAX 31700 +#define AD9739A_FSC_RANGE (AD9739A_FSC_MAX - AD9739A_FSC_MIN + 1) + +#define AD9739A_MIN_DAC_CLK (1600 * MEGA) +#define AD9739A_MAX_DAC_CLK (2500 * MEGA) +#define AD9739A_DAC_CLK_RANGE (AD9739A_MAX_DAC_CLK - AD9739A_MIN_DAC_CLK + 1) +/* as recommended by the datasheet */ +#define AD9739A_LOCK_N_TRIES 3 + +struct ad9739a_state { + struct iio_backend *back; + struct regmap *regmap; + unsigned long sample_rate; +}; + +static int ad9739a_oper_mode_get(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan) +{ + struct ad9739a_state *st = iio_priv(indio_dev); + u32 mode; + int ret; + + ret = regmap_read(st->regmap, AD9739A_REG_DEC_CNT, &mode); + if (ret) + return ret; + + mode = FIELD_GET(AD9739A_DAC_DEC, mode); + /* sanity check we get valid values from the HW */ + if (mode != AD9739A_NORMAL_MODE && mode != AD9739A_MIXED_MODE) + return -EIO; + if (!mode) + return AD9739A_NORMAL_MODE; + + /* + * We get 2 from the device but for IIO modes, that means 1. Hence the + * minus 1. + */ + return AD9739A_MIXED_MODE - 1; +} + +static int ad9739a_oper_mode_set(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, u32 mode) +{ + struct ad9739a_state *st = iio_priv(indio_dev); + + /* + * On the IIO interface we have 0 and 1 for mode. But for mixed_mode, we + * need to write 2 in the device. That's what the below check is about. + */ + if (mode == AD9739A_MIXED_MODE - 1) + mode = AD9739A_MIXED_MODE; + + return regmap_update_bits(st->regmap, AD9739A_REG_DEC_CNT, + AD9739A_DAC_DEC, mode); +} + +static int ad9739a_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct ad9739a_state *st = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + *val = st->sample_rate; + *val2 = 0; + return IIO_VAL_INT_64; + default: + return -EINVAL; + } +} + +static int ad9739a_buffer_preenable(struct iio_dev *indio_dev) +{ + struct ad9739a_state *st = iio_priv(indio_dev); + + return iio_backend_data_source_set(st->back, 0, IIO_BACKEND_EXTERNAL); +} + +static int ad9739a_buffer_postdisable(struct iio_dev *indio_dev) +{ + struct ad9739a_state *st = iio_priv(indio_dev); + + return iio_backend_data_source_set(st->back, 0, + IIO_BACKEND_INTERNAL_CONTINUOS_WAVE); +} + +static bool ad9739a_reg_accessible(struct device *dev, unsigned int reg) +{ + if (AD9739A_REG_IS_RESERVED(reg)) + return false; + if (reg > AD9739A_REG_MU_STAT1 && reg < AD9739A_REG_ANA_CNT_1) + return false; + + return true; +} + +static int ad9739a_reset(struct device *dev, const struct ad9739a_state *st) +{ + struct gpio_desc *gpio; + int ret; + + gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(gpio)) + return PTR_ERR(gpio); + if (gpio) { + /* minimum pulse width of 40ns */ + ndelay(40); + gpiod_set_value_cansleep(gpio, 0); + return 0; + } + + /* bring all registers to their default state */ + ret = regmap_set_bits(st->regmap, AD9739A_REG_MODE, AD9739A_RESET_MASK); + if (ret) + return ret; + + ndelay(40); + + return regmap_clear_bits(st->regmap, AD9739A_REG_MODE, + AD9739A_RESET_MASK); +} + +/* + * Recommended values (as per datasheet) for the dac clk common mode voltage + * and Mu controller. Look at table 29. + */ +static const struct reg_sequence ad9739a_clk_mu_ctrl[] = { + /* DAC clk common mode voltage */ + { AD9739A_REG_CROSS_CNT1, 0x0f }, + { AD9739A_REG_CROSS_CNT2, 0x0f }, + /* Mu controller configuration */ + { AD9739A_REG_PHS_DET, 0x30 }, + { AD9739A_REG_MU_DUTY, 0x80 }, + { AD9739A_REG_MU_CNT2, 0x44 }, + { AD9739A_REG_MU_CNT3, 0x6c }, +}; + +static int ad9739a_init(struct device *dev, const struct ad9739a_state *st) +{ + unsigned int i = 0, lock, fsc; + u32 fsc_raw; + int ret; + + ret = regmap_multi_reg_write(st->regmap, ad9739a_clk_mu_ctrl, + ARRAY_SIZE(ad9739a_clk_mu_ctrl)); + if (ret) + return ret; + + /* + * Try to get the Mu lock. Repeat the below steps AD9739A_LOCK_N_TRIES + * (as specified by the datasheet) until we get the lock. + */ + do { + ret = regmap_write(st->regmap, AD9739A_REG_MU_CNT4, + AD9739A_MU_CNT4_DEFAULT); + if (ret) + return ret; + + /* Enable the Mu controller search and track mode. */ + ret = regmap_set_bits(st->regmap, AD9739A_REG_MU_CNT1, + AD9739A_MU_EN_MASK); + if (ret) + return ret; + + /* Ensure the DLL loop is locked */ + ret = regmap_read_poll_timeout(st->regmap, AD9739A_REG_MU_STAT1, + lock, lock & AD9739A_MU_LOCK_MASK, + 0, 1000); + if (ret && ret != -ETIMEDOUT) + return ret; + } while (ret && ++i < AD9739A_LOCK_N_TRIES); + + if (i == AD9739A_LOCK_N_TRIES) + return dev_err_probe(dev, ret, "Mu lock timeout\n"); + + /* Receiver tracking and lock. Same deal as the Mu controller */ + i = 0; + do { + ret = regmap_update_bits(st->regmap, AD9739A_REG_LVDS_REC_CNT4, + AD9739A_FINE_DEL_SKW_MASK, + FIELD_PREP(AD9739A_FINE_DEL_SKW_MASK, 2)); + if (ret) + return ret; + + /* Disable the receiver and the loop. */ + ret = regmap_write(st->regmap, AD9739A_REG_LVDS_REC_CNT1, 0); + if (ret) + return ret; + + /* + * Re-enable the loop so it falls out of lock and begins the + * search/track routine again. + */ + ret = regmap_set_bits(st->regmap, AD9739A_REG_LVDS_REC_CNT1, + AD9739A_RCVR_LOOP_EN_MASK); + if (ret) + return ret; + + /* Ensure the DLL loop is locked */ + ret = regmap_read_poll_timeout(st->regmap, + AD9739A_REG_LVDS_REC_STAT9, lock, + lock == AD9739A_RCVR_TRACK_AND_LOCK, + 0, 1000); + if (ret && ret != -ETIMEDOUT) + return ret; + } while (ret && ++i < AD9739A_LOCK_N_TRIES); + + if (i == AD9739A_LOCK_N_TRIES) + return dev_err_probe(dev, ret, "Receiver lock timeout\n"); + + ret = device_property_read_u32(dev, "adi,full-scale-microamp", &fsc); + if (ret && ret == -EINVAL) + return 0; + if (ret) + return ret; + if (!in_range(fsc, AD9739A_FSC_MIN, AD9739A_FSC_RANGE)) + return dev_err_probe(dev, -EINVAL, + "Invalid full scale current(%u) [%u %u]\n", + fsc, AD9739A_FSC_MIN, AD9739A_FSC_MAX); + /* + * IOUTFS is given by + * Ioutfs = 0.0226 * FSC + 8.58 + * and is given in mA. Hence we'll have to multiply by 10 * MILLI in + * order to get rid of the fractional. + */ + fsc_raw = DIV_ROUND_CLOSEST(fsc * 10 - 85800, 226); + + ret = regmap_write(st->regmap, AD9739A_REG_FSC_1, fsc_raw & 0xff); + if (ret) + return ret; + + return regmap_update_bits(st->regmap, AD9739A_REG_FSC_2, + AD9739A_FSC_MSB, fsc_raw >> 8); +} + +static const char * const ad9739a_modes_avail[] = { "normal", "mixed-mode" }; + +static const struct iio_enum ad9739a_modes = { + .items = ad9739a_modes_avail, + .num_items = ARRAY_SIZE(ad9739a_modes_avail), + .get = ad9739a_oper_mode_get, + .set = ad9739a_oper_mode_set, +}; + +static const struct iio_chan_spec_ext_info ad9739a_ext_info[] = { + IIO_ENUM_AVAILABLE("operating_mode", IIO_SEPARATE, &ad9739a_modes), + IIO_ENUM("operating_mode", IIO_SEPARATE, &ad9739a_modes), + { } +}; + +/* + * The reason for having two different channels is because we have, in reality, + * two sources of data: + * ALTVOLTAGE: It's a Continuous Wave that's internally generated by the + * backend device. + * VOLTAGE: It's the typical data we can have in a DAC device and the source + * of it has nothing to do with the backend. The backend will only + * forward it into our data interface to be sent out. + */ +static struct iio_chan_spec ad9739a_channels[] = { + { + .type = IIO_ALTVOLTAGE, + .indexed = 1, + .output = 1, + .scan_index = -1, + }, + { + .type = IIO_VOLTAGE, + .indexed = 1, + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), + .output = 1, + .ext_info = ad9739a_ext_info, + .scan_type = { + .sign = 's', + .storagebits = 16, + .realbits = 16, + }, + } +}; + +static const struct iio_info ad9739a_info = { + .read_raw = ad9739a_read_raw, +}; + +static const struct iio_buffer_setup_ops ad9739a_buffer_setup_ops = { + .preenable = &ad9739a_buffer_preenable, + .postdisable = &ad9739a_buffer_postdisable, +}; + +static const struct regmap_config ad9739a_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .readable_reg = ad9739a_reg_accessible, + .writeable_reg = ad9739a_reg_accessible, + .max_register = AD9739A_REG_ID, +}; + +static int ad9739a_probe(struct spi_device *spi) +{ + struct device *dev = &spi->dev; + struct iio_dev *indio_dev; + struct ad9739a_state *st; + unsigned int id; + struct clk *clk; + int ret; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; + + st = iio_priv(indio_dev); + + clk = devm_clk_get_enabled(dev, NULL); + if (IS_ERR(clk)) + return dev_err_probe(dev, PTR_ERR(clk), "Could not get clkin\n"); + + st->sample_rate = clk_get_rate(clk); + if (!in_range(st->sample_rate, AD9739A_MIN_DAC_CLK, + AD9739A_DAC_CLK_RANGE)) + return dev_err_probe(dev, -EINVAL, + "Invalid dac clk range(%lu) [%lu %lu]\n", + st->sample_rate, AD9739A_MIN_DAC_CLK, + AD9739A_MAX_DAC_CLK); + + st->regmap = devm_regmap_init_spi(spi, &ad9739a_regmap_config); + if (IS_ERR(st->regmap)) + return PTR_ERR(st->regmap); + + ret = regmap_read(st->regmap, AD9739A_REG_ID, &id); + if (ret) + return ret; + + if (id != AD9739A_ID) + dev_warn(dev, "Unrecognized CHIP_ID 0x%X", id); + + ret = ad9739a_reset(dev, st); + if (ret) + return ret; + + ret = ad9739a_init(dev, st); + if (ret) + return ret; + + st->back = devm_iio_backend_get(dev, NULL); + if (IS_ERR(st->back)) + return PTR_ERR(st->back); + + ret = devm_iio_backend_request_buffer(dev, st->back, indio_dev); + if (ret) + return ret; + + ret = iio_backend_extend_chan_spec(indio_dev, st->back, + &ad9739a_channels[0]); + if (ret) + return ret; + + ret = iio_backend_set_sampling_freq(st->back, 0, st->sample_rate); + if (ret) + return ret; + + ret = devm_iio_backend_enable(dev, st->back); + if (ret) + return ret; + + indio_dev->name = "ad9739a"; + indio_dev->info = &ad9739a_info; + indio_dev->channels = ad9739a_channels; + indio_dev->num_channels = ARRAY_SIZE(ad9739a_channels); + indio_dev->setup_ops = &ad9739a_buffer_setup_ops; + + return devm_iio_device_register(&spi->dev, indio_dev); +} + +static const struct of_device_id ad9739a_of_match[] = { + { .compatible = "adi,ad9739a" }, + {} +}; +MODULE_DEVICE_TABLE(of, ad9739a_of_match); + +static const struct spi_device_id ad9739a_id[] = { + {"ad9739a"}, + {} +}; +MODULE_DEVICE_TABLE(spi, ad9739a_id); + +static struct spi_driver ad9739a_driver = { + .driver = { + .name = "ad9739a", + .of_match_table = ad9739a_of_match, + }, + .probe = ad9739a_probe, + .id_table = ad9739a_id, +}; +module_spi_driver(ad9739a_driver); + +MODULE_AUTHOR("Dragos Bogdan "); +MODULE_AUTHOR("Nuno Sa "); +MODULE_DESCRIPTION("Analog Devices AD9739 DAC"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(IIO_BACKEND); -- cgit v1.2.3-59-g8ed1b From cf1c833f89e7c8635a28c3db15c68ead150ea712 Mon Sep 17 00:00:00 2001 From: Nuno Sa Date: Fri, 19 Apr 2024 17:36:45 +0200 Subject: iio: adc: adi-axi-adc: only error out in major version mismatch The IP core only has breaking changes when there major version changes. Hence, only match the major number. This is also in line with the other core ADI has upstream. The current check for erroring out 'expected_version > current_version"' is then wrong as we could just increase the core major with breaking changes and that would go unnoticed. Fixes: ef04070692a2 ("iio: adc: adi-axi-adc: add support for AXI ADC IP core") Signed-off-by: Nuno Sa Link: https://lore.kernel.org/r/20240419-ad9467-new-features-v1-2-3e7628ff6d5e@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/adi-axi-adc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/iio/adc/adi-axi-adc.c b/drivers/iio/adc/adi-axi-adc.c index 184b36dca6d0..9444b0c5a93c 100644 --- a/drivers/iio/adc/adi-axi-adc.c +++ b/drivers/iio/adc/adi-axi-adc.c @@ -193,9 +193,9 @@ static int adi_axi_adc_probe(struct platform_device *pdev) if (ret) return ret; - if (*expected_ver > ver) { + if (ADI_AXI_PCORE_VER_MAJOR(ver) != ADI_AXI_PCORE_VER_MAJOR(*expected_ver)) { dev_err(&pdev->dev, - "IP core version is too old. Expected %d.%.2d.%c, Reported %d.%.2d.%c\n", + "Major version mismatch. Expected %d.%.2d.%c, Reported %d.%.2d.%c\n", ADI_AXI_PCORE_VER_MAJOR(*expected_ver), ADI_AXI_PCORE_VER_MINOR(*expected_ver), ADI_AXI_PCORE_VER_PATCH(*expected_ver), -- cgit v1.2.3-59-g8ed1b From b80ad8e3cd2712b78b98804d1f59199680d8ed91 Mon Sep 17 00:00:00 2001 From: Lorenzo Bertin Salvador Date: Sat, 20 Apr 2024 15:27:43 -0300 Subject: iio: adc: ti-ads131e08: Use device_for_each_child_node_scoped() to simplify error paths. This loop definition automatically releases the handle on early exit reducing the chance of bugs that cause resource leaks. Co-developed-by: Briza Mel Dias de Sousa Signed-off-by: Briza Mel Dias de Sousa Signed-off-by: Lorenzo Bertin Salvador Link: https://lore.kernel.org/r/20240420182744.153184-2-lorenzobs@usp.br Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ti-ads131e08.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/iio/adc/ti-ads131e08.c b/drivers/iio/adc/ti-ads131e08.c index fcfc46254313..cb04a29b3dba 100644 --- a/drivers/iio/adc/ti-ads131e08.c +++ b/drivers/iio/adc/ti-ads131e08.c @@ -694,7 +694,6 @@ static int ads131e08_alloc_channels(struct iio_dev *indio_dev) struct ads131e08_channel_config *channel_config; struct device *dev = &st->spi->dev; struct iio_chan_spec *channels; - struct fwnode_handle *node; unsigned int channel, tmp; int num_channels, i, ret; @@ -736,10 +735,10 @@ static int ads131e08_alloc_channels(struct iio_dev *indio_dev) return -ENOMEM; i = 0; - device_for_each_child_node(dev, node) { + device_for_each_child_node_scoped(dev, node) { ret = fwnode_property_read_u32(node, "reg", &channel); if (ret) - goto err_child_out; + return ret; ret = fwnode_property_read_u32(node, "ti,gain", &tmp); if (ret) { @@ -747,7 +746,7 @@ static int ads131e08_alloc_channels(struct iio_dev *indio_dev) } else { ret = ads131e08_pga_gain_to_field_value(st, tmp); if (ret < 0) - goto err_child_out; + return ret; channel_config[i].pga_gain = tmp; } @@ -758,7 +757,7 @@ static int ads131e08_alloc_channels(struct iio_dev *indio_dev) } else { ret = ads131e08_validate_channel_mux(st, tmp); if (ret) - goto err_child_out; + return ret; channel_config[i].mux = tmp; } @@ -785,9 +784,6 @@ static int ads131e08_alloc_channels(struct iio_dev *indio_dev) return 0; -err_child_out: - fwnode_handle_put(node); - return ret; } static void ads131e08_regulator_disable(void *data) -- cgit v1.2.3-59-g8ed1b From 1e7ba33fa591de1cf60afffcabb45600b3607025 Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Fri, 12 Apr 2024 15:26:59 +0100 Subject: coresight: etm4x: Do not hardcode IOMEM access for register restore When we restore the register state for ETM4x, while coming back from CPU idle, we hardcode IOMEM access. This is wrong and could blow up for an ETM with system instructions access (and for ETE). Fixes: f5bd523690d2 ("coresight: etm4x: Convert all register accesses") Reported-by: Yabin Cui Reviewed-by: Mike Leach Signed-off-by: Suzuki K Poulose Tested-by: Yabin Cui Link: https://lore.kernel.org/r/20240412142702.2882478-2-suzuki.poulose@arm.com --- drivers/hwtracing/coresight/coresight-etm4x-core.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c index 06a9b94b8c13..b9c6c544d759 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c @@ -1843,8 +1843,10 @@ static void __etm4_cpu_restore(struct etmv4_drvdata *drvdata) { int i; struct etmv4_save_state *state = drvdata->save_state; - struct csdev_access tmp_csa = CSDEV_ACCESS_IOMEM(drvdata->base); - struct csdev_access *csa = &tmp_csa; + struct csdev_access *csa = &drvdata->csdev->access; + + if (WARN_ON(!drvdata->csdev)) + return; etm4_cs_unlock(drvdata, csa); etm4x_relaxed_write32(csa, state->trcclaimset, TRCCLAIMSET); -- cgit v1.2.3-59-g8ed1b From 5eb3a0c2c52368cb9902e9a6ea04888e093c487d Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Fri, 12 Apr 2024 15:27:00 +0100 Subject: coresight: etm4x: Do not save/restore Data trace control registers ETM4x doesn't support Data trace on A class CPUs. As such do not access the Data trace control registers during CPU idle. This could cause problems for ETE. While at it, remove all references to the Data trace control registers. Fixes: f188b5e76aae ("coresight: etm4x: Save/restore state across CPU low power states") Reported-by: Yabin Cui Reviewed-by: Mike Leach Signed-off-by: Suzuki K Poulose Tested-by: Yabin Cui Link: https://lore.kernel.org/r/20240412142702.2882478-3-suzuki.poulose@arm.com --- drivers/hwtracing/coresight/coresight-etm4x-core.c | 6 ----- drivers/hwtracing/coresight/coresight-etm4x.h | 28 ---------------------- 2 files changed, 34 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c index b9c6c544d759..a9765d45a0ee 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c @@ -1739,9 +1739,6 @@ static int __etm4_cpu_save(struct etmv4_drvdata *drvdata) state->trcvissctlr = etm4x_read32(csa, TRCVISSCTLR); if (drvdata->nr_pe_cmp) state->trcvipcssctlr = etm4x_read32(csa, TRCVIPCSSCTLR); - state->trcvdctlr = etm4x_read32(csa, TRCVDCTLR); - state->trcvdsacctlr = etm4x_read32(csa, TRCVDSACCTLR); - state->trcvdarcctlr = etm4x_read32(csa, TRCVDARCCTLR); for (i = 0; i < drvdata->nrseqstate - 1; i++) state->trcseqevr[i] = etm4x_read32(csa, TRCSEQEVRn(i)); @@ -1872,9 +1869,6 @@ static void __etm4_cpu_restore(struct etmv4_drvdata *drvdata) etm4x_relaxed_write32(csa, state->trcvissctlr, TRCVISSCTLR); if (drvdata->nr_pe_cmp) etm4x_relaxed_write32(csa, state->trcvipcssctlr, TRCVIPCSSCTLR); - etm4x_relaxed_write32(csa, state->trcvdctlr, TRCVDCTLR); - etm4x_relaxed_write32(csa, state->trcvdsacctlr, TRCVDSACCTLR); - etm4x_relaxed_write32(csa, state->trcvdarcctlr, TRCVDARCCTLR); for (i = 0; i < drvdata->nrseqstate - 1; i++) etm4x_relaxed_write32(csa, state->trcseqevr[i], TRCSEQEVRn(i)); diff --git a/drivers/hwtracing/coresight/coresight-etm4x.h b/drivers/hwtracing/coresight/coresight-etm4x.h index 9ea678bc2e8e..9e430f72bbd6 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x.h +++ b/drivers/hwtracing/coresight/coresight-etm4x.h @@ -43,9 +43,6 @@ #define TRCVIIECTLR 0x084 #define TRCVISSCTLR 0x088 #define TRCVIPCSSCTLR 0x08C -#define TRCVDCTLR 0x0A0 -#define TRCVDSACCTLR 0x0A4 -#define TRCVDARCCTLR 0x0A8 /* Derived resources registers */ #define TRCSEQEVRn(n) (0x100 + (n * 4)) /* n = 0-2 */ #define TRCSEQRSTEVR 0x118 @@ -90,9 +87,6 @@ /* Address Comparator registers n = 0-15 */ #define TRCACVRn(n) (0x400 + (n * 8)) #define TRCACATRn(n) (0x480 + (n * 8)) -/* Data Value Comparator Value registers, n = 0-7 */ -#define TRCDVCVRn(n) (0x500 + (n * 16)) -#define TRCDVCMRn(n) (0x580 + (n * 16)) /* ContextID/Virtual ContextID comparators, n = 0-7 */ #define TRCCIDCVRn(n) (0x600 + (n * 8)) #define TRCVMIDCVRn(n) (0x640 + (n * 8)) @@ -272,9 +266,6 @@ /* List of registers accessible via System instructions */ #define ETM4x_ONLY_SYSREG_LIST(op, val) \ CASE_##op((val), TRCPROCSELR) \ - CASE_##op((val), TRCVDCTLR) \ - CASE_##op((val), TRCVDSACCTLR) \ - CASE_##op((val), TRCVDARCCTLR) \ CASE_##op((val), TRCOSLAR) #define ETM_COMMON_SYSREG_LIST(op, val) \ @@ -422,22 +413,6 @@ CASE_##op((val), TRCACATRn(13)) \ CASE_##op((val), TRCACATRn(14)) \ CASE_##op((val), TRCACATRn(15)) \ - CASE_##op((val), TRCDVCVRn(0)) \ - CASE_##op((val), TRCDVCVRn(1)) \ - CASE_##op((val), TRCDVCVRn(2)) \ - CASE_##op((val), TRCDVCVRn(3)) \ - CASE_##op((val), TRCDVCVRn(4)) \ - CASE_##op((val), TRCDVCVRn(5)) \ - CASE_##op((val), TRCDVCVRn(6)) \ - CASE_##op((val), TRCDVCVRn(7)) \ - CASE_##op((val), TRCDVCMRn(0)) \ - CASE_##op((val), TRCDVCMRn(1)) \ - CASE_##op((val), TRCDVCMRn(2)) \ - CASE_##op((val), TRCDVCMRn(3)) \ - CASE_##op((val), TRCDVCMRn(4)) \ - CASE_##op((val), TRCDVCMRn(5)) \ - CASE_##op((val), TRCDVCMRn(6)) \ - CASE_##op((val), TRCDVCMRn(7)) \ CASE_##op((val), TRCCIDCVRn(0)) \ CASE_##op((val), TRCCIDCVRn(1)) \ CASE_##op((val), TRCCIDCVRn(2)) \ @@ -907,9 +882,6 @@ struct etmv4_save_state { u32 trcviiectlr; u32 trcvissctlr; u32 trcvipcssctlr; - u32 trcvdctlr; - u32 trcvdsacctlr; - u32 trcvdarcctlr; u32 trcseqevr[ETM_MAX_SEQ_STATES]; u32 trcseqrstevr; -- cgit v1.2.3-59-g8ed1b From 46bf8d7cd8530eca607379033b9bc4ac5590a0cd Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Fri, 12 Apr 2024 15:27:01 +0100 Subject: coresight: etm4x: Safe access for TRCQCLTR ETM4x implements TRCQCLTR only when the Q elements are supported and the Q element filtering is supported (TRCIDR0.QFILT). Access to the register otherwise could be fatal. Fix this by tracking the availability, like the others. Fixes: f188b5e76aae ("coresight: etm4x: Save/restore state across CPU low power states") Reported-by: Yabin Cui Reviewed-by: Mike Leach Signed-off-by: Suzuki K Poulose Tested-by: Yabin Cui Link: https://lore.kernel.org/r/20240412142702.2882478-4-suzuki.poulose@arm.com --- drivers/hwtracing/coresight/coresight-etm4x-core.c | 8 ++++++-- drivers/hwtracing/coresight/coresight-etm4x.h | 3 +++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c index a9765d45a0ee..8643b77e50f4 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c @@ -1240,6 +1240,8 @@ static void etm4_init_arch_data(void *info) drvdata->nr_event = FIELD_GET(TRCIDR0_NUMEVENT_MASK, etmidr0); /* QSUPP, bits[16:15] Q element support field */ drvdata->q_support = FIELD_GET(TRCIDR0_QSUPP_MASK, etmidr0); + if (drvdata->q_support) + drvdata->q_filt = !!(etmidr0 & TRCIDR0_QFILT); /* TSSIZE, bits[28:24] Global timestamp size field */ drvdata->ts_size = FIELD_GET(TRCIDR0_TSSIZE_MASK, etmidr0); @@ -1732,7 +1734,8 @@ static int __etm4_cpu_save(struct etmv4_drvdata *drvdata) state->trcccctlr = etm4x_read32(csa, TRCCCCTLR); state->trcbbctlr = etm4x_read32(csa, TRCBBCTLR); state->trctraceidr = etm4x_read32(csa, TRCTRACEIDR); - state->trcqctlr = etm4x_read32(csa, TRCQCTLR); + if (drvdata->q_filt) + state->trcqctlr = etm4x_read32(csa, TRCQCTLR); state->trcvictlr = etm4x_read32(csa, TRCVICTLR); state->trcviiectlr = etm4x_read32(csa, TRCVIIECTLR); @@ -1862,7 +1865,8 @@ static void __etm4_cpu_restore(struct etmv4_drvdata *drvdata) etm4x_relaxed_write32(csa, state->trcccctlr, TRCCCCTLR); etm4x_relaxed_write32(csa, state->trcbbctlr, TRCBBCTLR); etm4x_relaxed_write32(csa, state->trctraceidr, TRCTRACEIDR); - etm4x_relaxed_write32(csa, state->trcqctlr, TRCQCTLR); + if (drvdata->q_filt) + etm4x_relaxed_write32(csa, state->trcqctlr, TRCQCTLR); etm4x_relaxed_write32(csa, state->trcvictlr, TRCVICTLR); etm4x_relaxed_write32(csa, state->trcviiectlr, TRCVIIECTLR); diff --git a/drivers/hwtracing/coresight/coresight-etm4x.h b/drivers/hwtracing/coresight/coresight-etm4x.h index 9e430f72bbd6..9e9165f62e81 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x.h +++ b/drivers/hwtracing/coresight/coresight-etm4x.h @@ -135,6 +135,7 @@ #define TRCIDR0_TRCCCI BIT(7) #define TRCIDR0_RETSTACK BIT(9) #define TRCIDR0_NUMEVENT_MASK GENMASK(11, 10) +#define TRCIDR0_QFILT BIT(14) #define TRCIDR0_QSUPP_MASK GENMASK(16, 15) #define TRCIDR0_TSSIZE_MASK GENMASK(28, 24) @@ -954,6 +955,7 @@ struct etmv4_save_state { * @os_unlock: True if access to management registers is allowed. * @instrp0: Tracing of load and store instructions * as P0 elements is supported. + * @q_filt: Q element filtering support, if Q elements are supported. * @trcbb: Indicates if the trace unit supports branch broadcast tracing. * @trccond: If the trace unit supports conditional * instruction tracing. @@ -1016,6 +1018,7 @@ struct etmv4_drvdata { bool boot_enable; bool os_unlock; bool instrp0; + bool q_filt; bool trcbb; bool trccond; bool retstack; -- cgit v1.2.3-59-g8ed1b From d6fc00d0f640d6010b51054aa8b0fd191177dbc9 Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Fri, 12 Apr 2024 15:27:02 +0100 Subject: coresight: etm4x: Fix access to resource selector registers Resource selector pair 0 is always implemented and reserved. We must not touch it, even during save/restore for CPU Idle. Rest of the driver is well behaved. Fix the offending ones. Reported-by: Yabin Cui Fixes: f188b5e76aae ("coresight: etm4x: Save/restore state across CPU low power states") Signed-off-by: Suzuki K Poulose Tested-by: Yabin Cui Reviewed-by: Mike Leach Link: https://lore.kernel.org/r/20240412142702.2882478-5-suzuki.poulose@arm.com --- drivers/hwtracing/coresight/coresight-etm4x-core.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c index 8643b77e50f4..a0bdfabddbc6 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c @@ -1758,7 +1758,8 @@ static int __etm4_cpu_save(struct etmv4_drvdata *drvdata) state->trccntvr[i] = etm4x_read32(csa, TRCCNTVRn(i)); } - for (i = 0; i < drvdata->nr_resource * 2; i++) + /* Resource selector pair 0 is reserved */ + for (i = 2; i < drvdata->nr_resource * 2; i++) state->trcrsctlr[i] = etm4x_read32(csa, TRCRSCTLRn(i)); for (i = 0; i < drvdata->nr_ss_cmp; i++) { @@ -1889,7 +1890,8 @@ static void __etm4_cpu_restore(struct etmv4_drvdata *drvdata) etm4x_relaxed_write32(csa, state->trccntvr[i], TRCCNTVRn(i)); } - for (i = 0; i < drvdata->nr_resource * 2; i++) + /* Resource selector pair 0 is reserved */ + for (i = 2; i < drvdata->nr_resource * 2; i++) etm4x_relaxed_write32(csa, state->trcrsctlr[i], TRCRSCTLRn(i)); for (i = 0; i < drvdata->nr_ss_cmp; i++) { -- cgit v1.2.3-59-g8ed1b From c32d18e7942d7589b62e301eb426b32623366565 Mon Sep 17 00:00:00 2001 From: Mike Gilbert Date: Wed, 6 Mar 2024 12:11:47 -0500 Subject: sparc: move struct termio to asm/termios.h Every other arch declares struct termio in asm/termios.h, so make sparc match them. Resolves a build failure in the PPP software package, which includes both bits/ioctl-types.h via sys/ioctl.h (glibc) and asm/termbits.h. Closes: https://bugs.gentoo.org/918992 Signed-off-by: Mike Gilbert Cc: stable@vger.kernel.org Reviewed-by: Andreas Larsson Tested-by: Andreas Larsson Link: https://lore.kernel.org/r/20240306171149.3843481-1-floppym@gentoo.org Signed-off-by: Andreas Larsson --- arch/sparc/include/uapi/asm/termbits.h | 10 ---------- arch/sparc/include/uapi/asm/termios.h | 9 +++++++++ 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/arch/sparc/include/uapi/asm/termbits.h b/arch/sparc/include/uapi/asm/termbits.h index 4321322701fc..0da2b1adc0f5 100644 --- a/arch/sparc/include/uapi/asm/termbits.h +++ b/arch/sparc/include/uapi/asm/termbits.h @@ -10,16 +10,6 @@ typedef unsigned int tcflag_t; typedef unsigned long tcflag_t; #endif -#define NCC 8 -struct termio { - unsigned short c_iflag; /* input mode flags */ - unsigned short c_oflag; /* output mode flags */ - unsigned short c_cflag; /* control mode flags */ - unsigned short c_lflag; /* local mode flags */ - unsigned char c_line; /* line discipline */ - unsigned char c_cc[NCC]; /* control characters */ -}; - #define NCCS 17 struct termios { tcflag_t c_iflag; /* input mode flags */ diff --git a/arch/sparc/include/uapi/asm/termios.h b/arch/sparc/include/uapi/asm/termios.h index ee86f4093d83..cceb32260881 100644 --- a/arch/sparc/include/uapi/asm/termios.h +++ b/arch/sparc/include/uapi/asm/termios.h @@ -40,5 +40,14 @@ struct winsize { unsigned short ws_ypixel; }; +#define NCC 8 +struct termio { + unsigned short c_iflag; /* input mode flags */ + unsigned short c_oflag; /* output mode flags */ + unsigned short c_cflag; /* control mode flags */ + unsigned short c_lflag; /* local mode flags */ + unsigned char c_line; /* line discipline */ + unsigned char c_cc[NCC]; /* control characters */ +}; #endif /* _UAPI_SPARC_TERMIOS_H */ -- cgit v1.2.3-59-g8ed1b From 0480fb5be3f127e8e1b8dfdf3fb44814aa760a6c Mon Sep 17 00:00:00 2001 From: Sam Ravnborg Date: Sat, 30 Mar 2024 10:57:37 +0100 Subject: sparc64: Fix prototype warning for init_vdso_image MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix the following warning: arch/sparc/vdso/vma.c:246:12: warning: no previous prototype for ‘init_vdso_image’ init_vdso_image has no users outside vma.c, make it static. Signed-off-by: Sam Ravnborg Cc: Andreas Larsson Cc: David S. Miller Reviewed-by: Andreas Larsson Tested-by: Andreas Larsson Acked-by: Arnd Bergmann Link: https://lore.kernel.org/r/20240330-sparc64-warnings-v1-1-37201023ee2f@ravnborg.org Signed-off-by: Andreas Larsson --- arch/sparc/vdso/vma.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/sparc/vdso/vma.c b/arch/sparc/vdso/vma.c index 1bbf4335de45..bab7a59575e8 100644 --- a/arch/sparc/vdso/vma.c +++ b/arch/sparc/vdso/vma.c @@ -243,8 +243,9 @@ static int stick_patch(const struct vdso_image *image, struct vdso_elfinfo *e, b * Allocate pages for the vdso and vvar, and copy in the vdso text from the * kernel image. */ -int __init init_vdso_image(const struct vdso_image *image, - struct vm_special_mapping *vdso_mapping, bool elf64) +static int __init init_vdso_image(const struct vdso_image *image, + struct vm_special_mapping *vdso_mapping, + bool elf64) { int cnpages = (image->size) / PAGE_SIZE; struct page *dp, **dpp = NULL; -- cgit v1.2.3-59-g8ed1b From 4a433641bb3bfbd7100974a91e85f180b86cb1f9 Mon Sep 17 00:00:00 2001 From: Sam Ravnborg Date: Sat, 30 Mar 2024 10:57:38 +0100 Subject: sparc64: Fix prototype warnings in traps_64.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix the following warnings: arch/sparc/kernel/traps_64.c:253:6: warning: no previous prototype for ‘is_no_fault_exception’ arch/sparc/kernel/traps_64.c:2035:6: warning: no previous prototype for ‘do_mcd_err’ rch/sparc/kernel/traps_64.c:2153:6: warning: no previous prototype for ‘sun4v_nonresum_error_user_handled’ In all cases make the function static as there were no users outside traps_64.c Signed-off-by: Sam Ravnborg Cc: Andreas Larsson Cc: David S. Miller Reviewed-by: Andreas Larsson Tested-by: Andreas Larsson Acked-by: Arnd Bergmann Link: https://lore.kernel.org/r/20240330-sparc64-warnings-v1-2-37201023ee2f@ravnborg.org Signed-off-by: Andreas Larsson --- arch/sparc/kernel/traps_64.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/sparc/kernel/traps_64.c b/arch/sparc/kernel/traps_64.c index dd048023bff5..28cb0d66ab40 100644 --- a/arch/sparc/kernel/traps_64.c +++ b/arch/sparc/kernel/traps_64.c @@ -250,7 +250,7 @@ void sun4v_insn_access_exception_tl1(struct pt_regs *regs, unsigned long addr, u sun4v_insn_access_exception(regs, addr, type_ctx); } -bool is_no_fault_exception(struct pt_regs *regs) +static bool is_no_fault_exception(struct pt_regs *regs) { unsigned char asi; u32 insn; @@ -2032,7 +2032,7 @@ static void sun4v_log_error(struct pt_regs *regs, struct sun4v_error_entry *ent, /* Handle memory corruption detected error which is vectored in * through resumable error trap. */ -void do_mcd_err(struct pt_regs *regs, struct sun4v_error_entry ent) +static void do_mcd_err(struct pt_regs *regs, struct sun4v_error_entry ent) { if (notify_die(DIE_TRAP, "MCD error", regs, 0, 0x34, SIGSEGV) == NOTIFY_STOP) @@ -2150,9 +2150,9 @@ static unsigned long sun4v_get_vaddr(struct pt_regs *regs) /* Attempt to handle non-resumable errors generated from userspace. * Returns true if the signal was handled, false otherwise. */ -bool sun4v_nonresum_error_user_handled(struct pt_regs *regs, - struct sun4v_error_entry *ent) { - +static bool sun4v_nonresum_error_user_handled(struct pt_regs *regs, + struct sun4v_error_entry *ent) +{ unsigned int attrs = ent->err_attrs; if (attrs & SUN4V_ERR_ATTRS_MEMORY) { -- cgit v1.2.3-59-g8ed1b From 39e5611bf756416b90be7da64737760a82a5576b Mon Sep 17 00:00:00 2001 From: Sam Ravnborg Date: Sat, 30 Mar 2024 10:57:39 +0100 Subject: sparc64: Fix prototype warning for vmemmap_free MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix the following warning: arch/sparc/mm/init_64.c:2644:6: warning: no previous prototype for ‘vmemmap_free’ The function vmemmap_free() is only used for systems with CONFIG_MEMORY_HOTPLUG defined - and sparc64 do not support this. Drop the empty function as it has no users. Signed-off-by: Sam Ravnborg Cc: Andreas Larsson Cc: David S. Miller Reviewed-by: Andreas Larsson Tested-by: Andreas Larsson Acked-by: Arnd Bergmann Link: https://lore.kernel.org/r/20240330-sparc64-warnings-v1-3-37201023ee2f@ravnborg.org Signed-off-by: Andreas Larsson --- arch/sparc/mm/init_64.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/arch/sparc/mm/init_64.c b/arch/sparc/mm/init_64.c index 1ca9054d9b97..00b247d924a9 100644 --- a/arch/sparc/mm/init_64.c +++ b/arch/sparc/mm/init_64.c @@ -2640,11 +2640,6 @@ int __meminit vmemmap_populate(unsigned long vstart, unsigned long vend, return 0; } - -void vmemmap_free(unsigned long start, unsigned long end, - struct vmem_altmap *altmap) -{ -} #endif /* CONFIG_SPARSEMEM_VMEMMAP */ /* These are actually filled in at boot time by sun4{u,v}_pgprot_init() */ -- cgit v1.2.3-59-g8ed1b From e6057a644148079bf6b04025670236fb8142006c Mon Sep 17 00:00:00 2001 From: Sam Ravnborg Date: Sat, 30 Mar 2024 10:57:40 +0100 Subject: sparc64: Fix prototype warning for alloc_irqstack_bootmem MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix the following warning: arch/sparc/kernel/setup_64.c:602:13: warning: no previous prototype for ‘alloc_irqstack_bootmem’ The function alloc_irqstack_bootmem had no users outside setup_64.c so declare it static. Signed-off-by: Sam Ravnborg Cc: Andreas Larsson Cc: David S. Miller Reviewed-by: Andreas Larsson Tested-by: Andreas Larsson Acked-by: Arnd Bergmann Link: https://lore.kernel.org/r/20240330-sparc64-warnings-v1-4-37201023ee2f@ravnborg.org Signed-off-by: Andreas Larsson --- arch/sparc/kernel/setup_64.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/sparc/kernel/setup_64.c b/arch/sparc/kernel/setup_64.c index 6a4797dec34b..1d519f18d2b2 100644 --- a/arch/sparc/kernel/setup_64.c +++ b/arch/sparc/kernel/setup_64.c @@ -599,7 +599,7 @@ static void __init init_sparc64_elf_hwcap(void) pause_patch(); } -void __init alloc_irqstack_bootmem(void) +static void __init alloc_irqstack_bootmem(void) { unsigned int i, node; -- cgit v1.2.3-59-g8ed1b From a51b8c83bf2743871d5883c5a179590c4a96fdcd Mon Sep 17 00:00:00 2001 From: Sam Ravnborg Date: Sat, 30 Mar 2024 10:57:41 +0100 Subject: sparc64: Fix prototype warning for uprobe_trap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix the following warning: arch/sparc/kernel/uprobes.c:237:17: warning: no previous prototype for ‘uprobe_trap’ Add a prototype to kernel/kernel.h to silence the warning. This is a fix already used for other trap handlers. Signed-off-by: Sam Ravnborg Cc: Andreas Larsson Cc: David S. Miller Reviewed-by: Andreas Larsson Tested-by: Andreas Larsson Acked-by: Arnd Bergmann Link: https://lore.kernel.org/r/20240330-sparc64-warnings-v1-5-37201023ee2f@ravnborg.org Signed-off-by: Andreas Larsson --- arch/sparc/kernel/kernel.h | 4 ++++ arch/sparc/kernel/uprobes.c | 2 ++ 2 files changed, 6 insertions(+) diff --git a/arch/sparc/kernel/kernel.h b/arch/sparc/kernel/kernel.h index a8fb7c0bf053..8328a3b78a44 100644 --- a/arch/sparc/kernel/kernel.h +++ b/arch/sparc/kernel/kernel.h @@ -40,6 +40,10 @@ int handle_popc(u32 insn, struct pt_regs *regs); void handle_lddfmna(struct pt_regs *regs, unsigned long sfar, unsigned long sfsr); void handle_stdfmna(struct pt_regs *regs, unsigned long sfar, unsigned long sfsr); +/* uprobes.c */ +asmlinkage void uprobe_trap(struct pt_regs *regs, + unsigned long trap_level); + /* smp_64.c */ void __irq_entry smp_call_function_client(int irq, struct pt_regs *regs); void __irq_entry smp_call_function_single_client(int irq, struct pt_regs *regs); diff --git a/arch/sparc/kernel/uprobes.c b/arch/sparc/kernel/uprobes.c index 1a0600206bf5..305017bec164 100644 --- a/arch/sparc/kernel/uprobes.c +++ b/arch/sparc/kernel/uprobes.c @@ -18,6 +18,8 @@ #include +#include "kernel.h" + /* Compute the address of the breakpoint instruction and return it. * * Note that uprobe_get_swbp_addr is defined as a weak symbol in -- cgit v1.2.3-59-g8ed1b From 8f00d28c3537b3eebf4e29aa93a20ce5ce57745b Mon Sep 17 00:00:00 2001 From: Sam Ravnborg Date: Sat, 30 Mar 2024 10:57:42 +0100 Subject: sparc64: Fix prototype warning for dma_4v_iotsb_bind MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix the following warning: sparc/kernel/pci_sun4v.c:259:15: warning: no previous prototype for ‘dma_4v_iotsb_bind’ The function dma_4v_iotsb_bind is not used outside the file, so declare it static. Signed-off-by: Sam Ravnborg Cc: Andreas Larsson Cc: David S. Miller Reviewed-by: Andreas Larsson Tested-by: Andreas Larsson Acked-by: Arnd Bergmann Link: https://lore.kernel.org/r/20240330-sparc64-warnings-v1-6-37201023ee2f@ravnborg.org Signed-off-by: Andreas Larsson --- arch/sparc/kernel/pci_sun4v.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/sparc/kernel/pci_sun4v.c b/arch/sparc/kernel/pci_sun4v.c index 083e5f05a7f0..b720b21ccfbd 100644 --- a/arch/sparc/kernel/pci_sun4v.c +++ b/arch/sparc/kernel/pci_sun4v.c @@ -256,9 +256,9 @@ range_alloc_fail: return NULL; } -unsigned long dma_4v_iotsb_bind(unsigned long devhandle, - unsigned long iotsb_num, - struct pci_bus *bus_dev) +static unsigned long dma_4v_iotsb_bind(unsigned long devhandle, + unsigned long iotsb_num, + struct pci_bus *bus_dev) { struct pci_dev *pdev; unsigned long err; -- cgit v1.2.3-59-g8ed1b From b536adbcf872f970f87a05b0a7344d3f6313ac95 Mon Sep 17 00:00:00 2001 From: Sam Ravnborg Date: Sat, 30 Mar 2024 10:57:43 +0100 Subject: sparc64: Fix prototype warnings in adi_64.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix the following warnings: arch/sparc/kernel/adi_64.c:124:21: warning: no previous prototype for ‘find_tag_store’ arch/sparc/kernel/adi_64.c:156:21: warning: no previous prototype for ‘alloc_tag_store’ arch/sparc/kernel/adi_64.c:299:6: warning: no previous prototype for ‘del_tag_store’ None of the functions were used outside the file, so declare them static. Signed-off-by: Sam Ravnborg Cc: Andreas Larsson Cc: David S. Miller Reviewed-by: Andreas Larsson Tested-by: Andreas Larsson Acked-by: Arnd Bergmann Link: https://lore.kernel.org/r/20240330-sparc64-warnings-v1-7-37201023ee2f@ravnborg.org Signed-off-by: Andreas Larsson --- arch/sparc/kernel/adi_64.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/arch/sparc/kernel/adi_64.c b/arch/sparc/kernel/adi_64.c index ce332942de2d..e0e4fc527b24 100644 --- a/arch/sparc/kernel/adi_64.c +++ b/arch/sparc/kernel/adi_64.c @@ -121,9 +121,9 @@ adi_not_found: mdesc_release(hp); } -tag_storage_desc_t *find_tag_store(struct mm_struct *mm, - struct vm_area_struct *vma, - unsigned long addr) +static tag_storage_desc_t *find_tag_store(struct mm_struct *mm, + struct vm_area_struct *vma, + unsigned long addr) { tag_storage_desc_t *tag_desc = NULL; unsigned long i, max_desc, flags; @@ -153,9 +153,9 @@ tag_storage_desc_t *find_tag_store(struct mm_struct *mm, return tag_desc; } -tag_storage_desc_t *alloc_tag_store(struct mm_struct *mm, - struct vm_area_struct *vma, - unsigned long addr) +static tag_storage_desc_t *alloc_tag_store(struct mm_struct *mm, + struct vm_area_struct *vma, + unsigned long addr) { unsigned char *tags; unsigned long i, size, max_desc, flags; @@ -296,7 +296,7 @@ out: return tag_desc; } -void del_tag_store(tag_storage_desc_t *tag_desc, struct mm_struct *mm) +static void del_tag_store(tag_storage_desc_t *tag_desc, struct mm_struct *mm) { unsigned long flags; unsigned char *tags = NULL; -- cgit v1.2.3-59-g8ed1b From 95706e717c4f55ca62025c151451ccc28863d085 Mon Sep 17 00:00:00 2001 From: Sam Ravnborg Date: Sat, 30 Mar 2024 10:57:44 +0100 Subject: sparc64: Fix prototype warning for sched_clock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix the following warning: arch/sparc/kernel/time_64.c:880:20: warning: no previous prototype for ‘sched_clock’ Add the missing include to pick up the prototype. Signed-off-by: Sam Ravnborg Cc: Andreas Larsson Cc: David S. Miller Reviewed-by: Andreas Larsson Tested-by: Andreas Larsson Acked-by: Arnd Bergmann Link: https://lore.kernel.org/r/20240330-sparc64-warnings-v1-8-37201023ee2f@ravnborg.org Signed-off-by: Andreas Larsson --- arch/sparc/kernel/time_64.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/sparc/kernel/time_64.c b/arch/sparc/kernel/time_64.c index 89fb05f90609..60f1c8cc5363 100644 --- a/arch/sparc/kernel/time_64.c +++ b/arch/sparc/kernel/time_64.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include -- cgit v1.2.3-59-g8ed1b From 98937707fea8375e8acea0aaa0b68a956dd52719 Mon Sep 17 00:00:00 2001 From: Sam Ravnborg Date: Sat, 30 Mar 2024 10:57:45 +0100 Subject: sparc64: Fix number of online CPUs Nick Bowler reported: When using newer kernels on my Ultra 60 with dual 450MHz UltraSPARC-II CPUs, I noticed that only CPU 0 comes up, while older kernels (including 4.7) are working fine with both CPUs. I bisected the failure to this commit: 9b2f753ec23710aa32c0d837d2499db92fe9115b is the first bad commit commit 9b2f753ec23710aa32c0d837d2499db92fe9115b Author: Atish Patra Date: Thu Sep 15 14:54:40 2016 -0600 sparc64: Fix cpu_possible_mask if nr_cpus is set This is a small change that reverts very easily on top of 5.18: there is just one trivial conflict. Once reverted, both CPUs work again. Maybe this is related to the fact that the CPUs on this system are numbered CPU0 and CPU2 (there is no CPU1)? The current code that adjust cpu_possible based on nr_cpu_ids do not take into account that CPU's may not come one after each other. Move the chech to the function that setup the cpu_possible mask so there is no need to adjust it later. Signed-off-by: Sam Ravnborg Fixes: 9b2f753ec237 ("sparc64: Fix cpu_possible_mask if nr_cpus is set") Reported-by: Nick Bowler Tested-by: Nick Bowler Link: https://lore.kernel.org/sparclinux/20201009161924.c8f031c079dd852941307870@gmx.de/ Link: https://lore.kernel.org/all/CADyTPEwt=ZNams+1bpMB1F9w_vUdPsGCt92DBQxxq_VtaLoTdw@mail.gmail.com/ Cc: stable@vger.kernel.org # v4.8+ Cc: Andreas Larsson Cc: David S. Miller Cc: Atish Patra Cc: Bob Picco Cc: Vijay Kumar Cc: David S. Miller Reviewed-by: Andreas Larsson Acked-by: Arnd Bergmann Link: https://lore.kernel.org/r/20240330-sparc64-warnings-v1-9-37201023ee2f@ravnborg.org Signed-off-by: Andreas Larsson --- arch/sparc/include/asm/smp_64.h | 2 -- arch/sparc/kernel/prom_64.c | 4 +++- arch/sparc/kernel/setup_64.c | 1 - arch/sparc/kernel/smp_64.c | 14 -------------- 4 files changed, 3 insertions(+), 18 deletions(-) diff --git a/arch/sparc/include/asm/smp_64.h b/arch/sparc/include/asm/smp_64.h index 505b6700805d..0964fede0b2c 100644 --- a/arch/sparc/include/asm/smp_64.h +++ b/arch/sparc/include/asm/smp_64.h @@ -47,7 +47,6 @@ void arch_send_call_function_ipi_mask(const struct cpumask *mask); int hard_smp_processor_id(void); #define raw_smp_processor_id() (current_thread_info()->cpu) -void smp_fill_in_cpu_possible_map(void); void smp_fill_in_sib_core_maps(void); void __noreturn cpu_play_dead(void); @@ -77,7 +76,6 @@ void __cpu_die(unsigned int cpu); #define smp_fill_in_sib_core_maps() do { } while (0) #define smp_fetch_global_regs() do { } while (0) #define smp_fetch_global_pmu() do { } while (0) -#define smp_fill_in_cpu_possible_map() do { } while (0) #define smp_init_cpu_poke() do { } while (0) #define scheduler_poke() do { } while (0) diff --git a/arch/sparc/kernel/prom_64.c b/arch/sparc/kernel/prom_64.c index 998aa693d491..ba82884cb92a 100644 --- a/arch/sparc/kernel/prom_64.c +++ b/arch/sparc/kernel/prom_64.c @@ -483,7 +483,9 @@ static void *record_one_cpu(struct device_node *dp, int cpuid, int arg) ncpus_probed++; #ifdef CONFIG_SMP set_cpu_present(cpuid, true); - set_cpu_possible(cpuid, true); + + if (num_possible_cpus() < nr_cpu_ids) + set_cpu_possible(cpuid, true); #endif return NULL; } diff --git a/arch/sparc/kernel/setup_64.c b/arch/sparc/kernel/setup_64.c index 1d519f18d2b2..63615f5c99b4 100644 --- a/arch/sparc/kernel/setup_64.c +++ b/arch/sparc/kernel/setup_64.c @@ -671,7 +671,6 @@ void __init setup_arch(char **cmdline_p) paging_init(); init_sparc64_elf_hwcap(); - smp_fill_in_cpu_possible_map(); /* * Once the OF device tree and MDESC have been setup and nr_cpus has * been parsed, we know the list of possible cpus. Therefore we can diff --git a/arch/sparc/kernel/smp_64.c b/arch/sparc/kernel/smp_64.c index a0cc9bb41a92..e40c395db202 100644 --- a/arch/sparc/kernel/smp_64.c +++ b/arch/sparc/kernel/smp_64.c @@ -1216,20 +1216,6 @@ void __init smp_setup_processor_id(void) xcall_deliver_impl = hypervisor_xcall_deliver; } -void __init smp_fill_in_cpu_possible_map(void) -{ - int possible_cpus = num_possible_cpus(); - int i; - - if (possible_cpus > nr_cpu_ids) - possible_cpus = nr_cpu_ids; - - for (i = 0; i < possible_cpus; i++) - set_cpu_possible(i, true); - for (; i < NR_CPUS; i++) - set_cpu_possible(i, false); -} - void smp_fill_in_sib_core_maps(void) { unsigned int i; -- cgit v1.2.3-59-g8ed1b From 839c4dece27426a3f24ca3cb9b6624ce576374bd Mon Sep 17 00:00:00 2001 From: Sam Ravnborg Date: Sun, 24 Mar 2024 07:56:22 +0100 Subject: sparc32: Fix version generation failed warnings An allmodconfig build of sparc32 resulted in several warnings: WARNING: modpost: EXPORT symbol "empty_zero_page" [vmlinux] version generation failed, symbol will not be versioned. Is "empty_zero_page" prototyped in ? WARNING: modpost: EXPORT symbol "__udelay" [vmlinux] version generation failed, symbol will not be versioned. Is "__udelay" prototyped in ? WARNING: modpost: EXPORT symbol "__ndelay" [vmlinux] version generation failed, symbol will not be versioned. Is "__ndelay" prototyped in ? WARNING: modpost: EXPORT symbol "__ashldi3" [vmlinux] version generation failed, symbol will not be versioned. Is "__ashldi3" prototyped in ? WARNING: modpost: EXPORT symbol "__ashrdi3" [vmlinux] version generation failed, symbol will not be versioned. Is "__ashrdi3" prototyped in ? WARNING: modpost: EXPORT symbol "__lshrdi3" [vmlinux] version generation failed, symbol will not be versioned. Is "__lshrdi3" prototyped in ? And later a lot of warnings like this: WARNING: modpost: "__udelay" [kernel/locking/locktorture.ko] has no CRC! WARNING: modpost: "__udelay" [kernel/rcu/rcutorture.ko] has no CRC! WARNING: modpost: "__udelay" [kernel/rcu/rcuscale.ko] has no CRC! WARNING: modpost: "__udelay" [kernel/rcu/refscale.ko] has no CRC! WARNING: modpost: "__ndelay" [kernel/rcu/refscale.ko] has no CRC! WARNING: modpost: "__udelay" [kernel/time/test_udelay.ko] has no CRC! WARNING: modpost: "__udelay" [kernel/scftorture.ko] has no CRC! WARNING: modpost: "__ashrdi3" [fs/quota/quota_tree.ko] has no CRC! WARNING: modpost: "__ashldi3" [fs/ext4/ext4.ko] has no CRC! The fix was, as hinted, to add missing prototypes to asm-prototypes.h. For the __*di3 functions add the prototypes direct to the asm-prototypes.h file. Some of the symbols were already declared, so pulled in the relevant headers (delay.h, pgtable.h). The include files was alphabetically sorted to make the list somehow readable. The .S files exporting the symbols do not include asm-prototypes.h, so they need to be explicit rebuild to generate symbol versioning. One or more of the generic headers pulled in by asm-prototypes.h did not support being used from .S files, so adding asm-prototypes.h as an include file was not an option. Signed-off-by: Sam Ravnborg Cc: Andreas Larsson Cc: David S. Miller Reviewed-by: Andreas Larsson Tested-by: Andreas Larsson Link: https://lore.kernel.org/r/20240324065622.GA1032122@ravnborg.org Signed-off-by: Andreas Larsson --- arch/sparc/include/asm/asm-prototypes.h | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/arch/sparc/include/asm/asm-prototypes.h b/arch/sparc/include/asm/asm-prototypes.h index 4987c735ff56..08810808ca6d 100644 --- a/arch/sparc/include/asm/asm-prototypes.h +++ b/arch/sparc/include/asm/asm-prototypes.h @@ -3,15 +3,18 @@ * Copyright (c) 2017 Oracle and/or its affiliates. All rights reserved. */ -#include -#include -#include +#include #include + #include -#include #include +#include +#include +#include #include -#include +#include +#include +#include void *__memscan_zero(void *, size_t); void *__memscan_generic(void *, int, size_t); @@ -23,3 +26,7 @@ void *memcpy(void *dest, const void *src, size_t n); void *memset(void *s, int c, size_t n); typedef int TItype __attribute__((mode(TI))); TItype __multi3(TItype a, TItype b); + +s64 __ashldi3(s64, int); +s64 __lshrdi3(s64, int); +s64 __ashrdi3(s64, int); -- cgit v1.2.3-59-g8ed1b From 6c94284465ffefa9c5afc5288bb8cec2a020317f Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Thu, 4 Apr 2024 13:23:14 +0200 Subject: sparc: Use swap() to fix Coccinelle warning Fixes the following Coccinelle/coccicheck warning reported by swap.cocci: WARNING opportunity for swap() Signed-off-by: Thorsten Blum Reviewed-by: Andreas Larsson Link: https://lore.kernel.org/r/20240404112313.11898-2-thorsten.blum@toblux.com Signed-off-by: Andreas Larsson --- arch/sparc/include/asm/floppy_64.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/arch/sparc/include/asm/floppy_64.h b/arch/sparc/include/asm/floppy_64.h index 6efeb24b0a92..83decacd0a2d 100644 --- a/arch/sparc/include/asm/floppy_64.h +++ b/arch/sparc/include/asm/floppy_64.h @@ -704,9 +704,7 @@ static unsigned long __init sun_floppy_init(void) ns87303_modify(config, ASC, ASC_DRV2_SEL, 0); ns87303_modify(config, FCR, 0, FCR_LDE); - config = sun_floppy_types[0]; - sun_floppy_types[0] = sun_floppy_types[1]; - sun_floppy_types[1] = config; + swap(sun_floppy_types[0], sun_floppy_types[1]); if (sun_pci_broken_drive != -1) { sun_pci_broken_drive = 1 - sun_pci_broken_drive; -- cgit v1.2.3-59-g8ed1b From c7933eaeaf12dd06a7b721ad50b7a78b0f3cbf46 Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Thu, 4 Apr 2024 21:29:33 +0200 Subject: sparc: Compare pointers to NULL instead of 0 Fixes the following two Coccinelle/coccicheck warnings reported by badzero.cocci: WARNING comparing pointer to 0 WARNING comparing pointer to 0 Signed-off-by: Thorsten Blum Reviewed-by: Andreas Larsson Link: https://lore.kernel.org/r/20240404192932.13075-2-thorsten.blum@toblux.com Signed-off-by: Andreas Larsson --- arch/sparc/prom/tree_64.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/sparc/prom/tree_64.c b/arch/sparc/prom/tree_64.c index 989e7992d629..88793e5b0ab5 100644 --- a/arch/sparc/prom/tree_64.c +++ b/arch/sparc/prom/tree_64.c @@ -332,7 +332,7 @@ prom_setprop(phandle node, const char *pname, char *value, int size) if (size == 0) return 0; - if ((pname == 0) || (value == 0)) + if ((pname == NULL) || (value == NULL)) return 0; #ifdef CONFIG_SUN_LDOMS -- cgit v1.2.3-59-g8ed1b From 9f2072ca33520f5be6e89f410d0e82df72f7821d Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Wed, 10 Apr 2024 15:35:06 +0200 Subject: sparc: parport: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Reviewed-by: Andreas Larsson Link: https://lore.kernel.org/r/2765e090dba2d99f92e16c92b6aa55090aae053b.1712755381.git.u.kleine-koenig@pengutronix.de Signed-off-by: Andreas Larsson --- arch/sparc/include/asm/parport_64.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/arch/sparc/include/asm/parport_64.h b/arch/sparc/include/asm/parport_64.h index 0a7ffcfd59cd..4f530a270760 100644 --- a/arch/sparc/include/asm/parport_64.h +++ b/arch/sparc/include/asm/parport_64.h @@ -196,7 +196,7 @@ out_err: return err; } -static int ecpp_remove(struct platform_device *op) +static void ecpp_remove(struct platform_device *op) { struct parport *p = dev_get_drvdata(&op->dev); int slot = p->dma; @@ -216,8 +216,6 @@ static int ecpp_remove(struct platform_device *op) d_len); clear_bit(slot, dma_slot_map); } - - return 0; } static const struct of_device_id ecpp_match[] = { @@ -245,7 +243,7 @@ static struct platform_driver ecpp_driver = { .of_match_table = ecpp_match, }, .probe = ecpp_probe, - .remove = ecpp_remove, + .remove_new = ecpp_remove, }; static int parport_pc_find_nonpci_ports(int autoirq, int autodma) -- cgit v1.2.3-59-g8ed1b From 48d85acdaa52f9ec0324b6c5aa044d1315ef90b2 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Wed, 10 Apr 2024 15:35:07 +0200 Subject: sparc: chmc: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Reviewed-by: Andreas Larsson Link: https://lore.kernel.org/r/9fbd788bbca4efd2f596e3c56d045db450756c80.1712755381.git.u.kleine-koenig@pengutronix.de Signed-off-by: Andreas Larsson --- arch/sparc/kernel/chmc.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/arch/sparc/kernel/chmc.c b/arch/sparc/kernel/chmc.c index 00e571c30bb5..e02074062001 100644 --- a/arch/sparc/kernel/chmc.c +++ b/arch/sparc/kernel/chmc.c @@ -788,7 +788,7 @@ static void jbusmc_destroy(struct platform_device *op, struct jbusmc *p) kfree(p); } -static int us3mc_remove(struct platform_device *op) +static void us3mc_remove(struct platform_device *op) { void *p = dev_get_drvdata(&op->dev); @@ -798,7 +798,6 @@ static int us3mc_remove(struct platform_device *op) else if (mc_type == MC_TYPE_JBUS) jbusmc_destroy(op, p); } - return 0; } static const struct of_device_id us3mc_match[] = { @@ -815,7 +814,7 @@ static struct platform_driver us3mc_driver = { .of_match_table = us3mc_match, }, .probe = us3mc_probe, - .remove = us3mc_remove, + .remove_new = us3mc_remove, }; static inline bool us3mc_platform(void) -- cgit v1.2.3-59-g8ed1b From a6b974b40f942b3e51124de588383009f6a42d2d Mon Sep 17 00:00:00 2001 From: Tanmay Shah Date: Thu, 18 Apr 2024 15:01:25 -0700 Subject: drivers: remoteproc: xlnx: Add Versal and Versal-NET support AMD-Xilinx Versal platform is successor of ZynqMP platform. Real-time Processing Unit R5 cluster IP on Versal is same as of ZynqMP Platform. Power-domains ids for Versal platform is different than ZynqMP. AMD-Xilinx Versal-NET platform is successor of Versal platform. Versal-NET Real-Time Processing Unit has two clusters and each cluster contains dual core ARM Cortex-R52 processors. Each R52 core is assigned 128KB of TCM memory. Signed-off-by: Tanmay Shah Link: https://lore.kernel.org/r/20240418220125.744322-1-tanmay.shah@amd.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/xlnx_r5_remoteproc.c | 53 +++++++++++---------------------- 1 file changed, 17 insertions(+), 36 deletions(-) diff --git a/drivers/remoteproc/xlnx_r5_remoteproc.c b/drivers/remoteproc/xlnx_r5_remoteproc.c index 7b1c12108bff..a6d8ac7394e7 100644 --- a/drivers/remoteproc/xlnx_r5_remoteproc.c +++ b/drivers/remoteproc/xlnx_r5_remoteproc.c @@ -300,36 +300,6 @@ static void zynqmp_r5_rproc_kick(struct rproc *rproc, int vqid) dev_warn(dev, "failed to send message\n"); } -/* - * zynqmp_r5_set_mode() - * - * set RPU cluster and TCM operation mode - * - * @r5_core: pointer to zynqmp_r5_core type object - * @fw_reg_val: value expected by firmware to configure RPU cluster mode - * @tcm_mode: value expected by fw to configure TCM mode (lockstep or split) - * - * Return: 0 for success and < 0 for failure - */ -static int zynqmp_r5_set_mode(struct zynqmp_r5_core *r5_core, - enum rpu_oper_mode fw_reg_val, - enum rpu_tcm_comb tcm_mode) -{ - int ret; - - ret = zynqmp_pm_set_rpu_mode(r5_core->pm_domain_id, fw_reg_val); - if (ret < 0) { - dev_err(r5_core->dev, "failed to set RPU mode\n"); - return ret; - } - - ret = zynqmp_pm_set_tcm_config(r5_core->pm_domain_id, tcm_mode); - if (ret < 0) - dev_err(r5_core->dev, "failed to configure TCM\n"); - - return ret; -} - /* * zynqmp_r5_rproc_start() * @rproc: single R5 core's corresponding rproc instance @@ -941,7 +911,7 @@ static int zynqmp_r5_core_init(struct zynqmp_r5_cluster *cluster, /* Maintain backward compatibility for zynqmp by using hardcode TCM address. */ if (of_find_property(r5_core->np, "reg", NULL)) ret = zynqmp_r5_get_tcm_node_from_dt(cluster); - else + else if (device_is_compatible(dev, "xlnx,zynqmp-r5fss")) ret = zynqmp_r5_get_tcm_node(cluster); if (ret) { @@ -960,12 +930,21 @@ static int zynqmp_r5_core_init(struct zynqmp_r5_cluster *cluster, return ret; } - ret = zynqmp_r5_set_mode(r5_core, fw_reg_val, tcm_mode); - if (ret) { - dev_err(dev, "failed to set r5 cluster mode %d, err %d\n", - cluster->mode, ret); + ret = zynqmp_pm_set_rpu_mode(r5_core->pm_domain_id, fw_reg_val); + if (ret < 0) { + dev_err(r5_core->dev, "failed to set RPU mode\n"); return ret; } + + if (of_find_property(dev_of_node(dev), "xlnx,tcm-mode", NULL) || + device_is_compatible(dev, "xlnx,zynqmp-r5fss")) { + ret = zynqmp_pm_set_tcm_config(r5_core->pm_domain_id, + tcm_mode); + if (ret < 0) { + dev_err(r5_core->dev, "failed to configure TCM\n"); + return ret; + } + } } return 0; @@ -1022,7 +1001,7 @@ static int zynqmp_r5_cluster_init(struct zynqmp_r5_cluster *cluster) ret = of_property_read_u32(dev_node, "xlnx,tcm-mode", (u32 *)&tcm_mode); if (ret) return ret; - } else { + } else if (device_is_compatible(dev, "xlnx,zynqmp-r5fss")) { if (cluster_mode == LOCKSTEP_MODE) tcm_mode = PM_RPU_TCM_COMB; else @@ -1212,6 +1191,8 @@ static int zynqmp_r5_remoteproc_probe(struct platform_device *pdev) /* Match table for OF platform binding */ static const struct of_device_id zynqmp_r5_remoteproc_match[] = { + { .compatible = "xlnx,versal-net-r52fss", }, + { .compatible = "xlnx,versal-r5fss", }, { .compatible = "xlnx,zynqmp-r5fss", }, { /* end of list */ }, }; -- cgit v1.2.3-59-g8ed1b From 31a5990ed253a66712d7ddc29c92d297a991fdf2 Mon Sep 17 00:00:00 2001 From: Duoming Zhou Date: Wed, 6 Mar 2024 17:12:59 +0800 Subject: um: Fix return value in ubd_init() When kmalloc_array() fails to allocate memory, the ubd_init() should return -ENOMEM instead of -1. So, fix it. Fixes: f88f0bdfc32f ("um: UBD Improvements") Signed-off-by: Duoming Zhou Reviewed-by: Johannes Berg Signed-off-by: Richard Weinberger --- arch/um/drivers/ubd_kern.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c index 63fc062add70..ef805eaa9e01 100644 --- a/arch/um/drivers/ubd_kern.c +++ b/arch/um/drivers/ubd_kern.c @@ -1092,7 +1092,7 @@ static int __init ubd_init(void) if (irq_req_buffer == NULL) { printk(KERN_ERR "Failed to initialize ubd buffering\n"); - return -1; + return -ENOMEM; } io_req_buffer = kmalloc_array(UBD_REQ_BUFFER_SIZE, sizeof(struct io_thread_req *), @@ -1103,7 +1103,7 @@ static int __init ubd_init(void) if (io_req_buffer == NULL) { printk(KERN_ERR "Failed to initialize ubd buffering\n"); - return -1; + return -ENOMEM; } platform_driver_register(&ubd_driver); mutex_lock(&ubd_lock); -- cgit v1.2.3-59-g8ed1b From 53471c574974a3df4a5705b1db431d69058cc6d9 Mon Sep 17 00:00:00 2001 From: Tiwei Bie Date: Wed, 6 Mar 2024 18:19:17 +0800 Subject: um: Make local functions and variables static MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This will also fix the warnings like: warning: no previous prototype for ‘fork_handler’ [-Wmissing-prototypes] 140 | void fork_handler(void) | ^~~~~~~~~~~~ Signed-off-by: Tiwei Bie Signed-off-by: Richard Weinberger --- arch/um/drivers/pcap_kern.c | 4 ++-- arch/um/drivers/ubd_user.c | 2 +- arch/um/kernel/kmsg_dump.c | 2 +- arch/um/kernel/process.c | 8 ++++---- arch/um/kernel/time.c | 6 +++--- arch/um/os-Linux/drivers/ethertap_kern.c | 2 +- arch/um/os-Linux/drivers/tuntap_kern.c | 2 +- arch/um/os-Linux/signal.c | 4 ++-- arch/x86/um/os-Linux/registers.c | 2 +- arch/x86/um/tls_32.c | 2 +- 10 files changed, 17 insertions(+), 17 deletions(-) diff --git a/arch/um/drivers/pcap_kern.c b/arch/um/drivers/pcap_kern.c index 25ee2c97ca21..d9bf95d7867b 100644 --- a/arch/um/drivers/pcap_kern.c +++ b/arch/um/drivers/pcap_kern.c @@ -15,7 +15,7 @@ struct pcap_init { char *filter; }; -void pcap_init_kern(struct net_device *dev, void *data) +static void pcap_init_kern(struct net_device *dev, void *data) { struct uml_net_private *pri; struct pcap_data *ppri; @@ -50,7 +50,7 @@ static const struct net_kern_info pcap_kern_info = { .write = pcap_write, }; -int pcap_setup(char *str, char **mac_out, void *data) +static int pcap_setup(char *str, char **mac_out, void *data) { struct pcap_init *init = data; char *remain, *host_if = NULL, *options[2] = { NULL, NULL }; diff --git a/arch/um/drivers/ubd_user.c b/arch/um/drivers/ubd_user.c index a1afe414ce48..b4f8b8e60564 100644 --- a/arch/um/drivers/ubd_user.c +++ b/arch/um/drivers/ubd_user.c @@ -23,7 +23,7 @@ #include #include -struct pollfd kernel_pollfd; +static struct pollfd kernel_pollfd; int start_io_thread(unsigned long sp, int *fd_out) { diff --git a/arch/um/kernel/kmsg_dump.c b/arch/um/kernel/kmsg_dump.c index 427dd5a61a38..4382cf02a6d1 100644 --- a/arch/um/kernel/kmsg_dump.c +++ b/arch/um/kernel/kmsg_dump.c @@ -57,7 +57,7 @@ static struct kmsg_dumper kmsg_dumper = { .dump = kmsg_dumper_stdout }; -int __init kmsg_dumper_stdout_init(void) +static int __init kmsg_dumper_stdout_init(void) { return kmsg_dump_register(&kmsg_dumper); } diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c index ab95648e93e1..20f3813143d8 100644 --- a/arch/um/kernel/process.c +++ b/arch/um/kernel/process.c @@ -137,7 +137,7 @@ void new_thread_handler(void) } /* Called magically, see new_thread_handler above */ -void fork_handler(void) +static void fork_handler(void) { force_flush_all(); @@ -268,14 +268,14 @@ int clear_user_proc(void __user *buf, int size) static atomic_t using_sysemu = ATOMIC_INIT(0); int sysemu_supported; -void set_using_sysemu(int value) +static void set_using_sysemu(int value) { if (value > sysemu_supported) return; atomic_set(&using_sysemu, value); } -int get_using_sysemu(void) +static int get_using_sysemu(void) { return atomic_read(&using_sysemu); } @@ -313,7 +313,7 @@ static const struct proc_ops sysemu_proc_ops = { .proc_write = sysemu_proc_write, }; -int __init make_proc_sysemu(void) +static int __init make_proc_sysemu(void) { struct proc_dir_entry *ent; if (!sysemu_supported) diff --git a/arch/um/kernel/time.c b/arch/um/kernel/time.c index 3e270da6b6f6..efa5b9c97992 100644 --- a/arch/um/kernel/time.c +++ b/arch/um/kernel/time.c @@ -319,7 +319,7 @@ void time_travel_add_event_rel(struct time_travel_event *e, time_travel_add_event(e, time_travel_time + delay_ns); } -void time_travel_periodic_timer(struct time_travel_event *e) +static void time_travel_periodic_timer(struct time_travel_event *e) { time_travel_add_event(&time_travel_timer_event, time_travel_time + time_travel_timer_interval); @@ -812,7 +812,7 @@ unsigned long calibrate_delay_is_known(void) return 0; } -int setup_time_travel(char *str) +static int setup_time_travel(char *str) { if (strcmp(str, "=inf-cpu") == 0) { time_travel_mode = TT_MODE_INFCPU; @@ -862,7 +862,7 @@ __uml_help(setup_time_travel, "devices using it, assuming the device has the right capabilities.\n" "The optional ID is a 64-bit integer that's sent to the central scheduler.\n"); -int setup_time_travel_start(char *str) +static int setup_time_travel_start(char *str) { int err; diff --git a/arch/um/os-Linux/drivers/ethertap_kern.c b/arch/um/os-Linux/drivers/ethertap_kern.c index 3182e759d8de..5e5ee40680ce 100644 --- a/arch/um/os-Linux/drivers/ethertap_kern.c +++ b/arch/um/os-Linux/drivers/ethertap_kern.c @@ -63,7 +63,7 @@ const struct net_kern_info ethertap_kern_info = { .write = etap_write, }; -int ethertap_setup(char *str, char **mac_out, void *data) +static int ethertap_setup(char *str, char **mac_out, void *data) { struct ethertap_init *init = data; diff --git a/arch/um/os-Linux/drivers/tuntap_kern.c b/arch/um/os-Linux/drivers/tuntap_kern.c index adcb6717be6f..ff022d9cf0dd 100644 --- a/arch/um/os-Linux/drivers/tuntap_kern.c +++ b/arch/um/os-Linux/drivers/tuntap_kern.c @@ -53,7 +53,7 @@ const struct net_kern_info tuntap_kern_info = { .write = tuntap_write, }; -int tuntap_setup(char *str, char **mac_out, void *data) +static int tuntap_setup(char *str, char **mac_out, void *data) { struct tuntap_init *init = data; diff --git a/arch/um/os-Linux/signal.c b/arch/um/os-Linux/signal.c index 24a403a70a02..787cfb9a0308 100644 --- a/arch/um/os-Linux/signal.c +++ b/arch/um/os-Linux/signal.c @@ -72,7 +72,7 @@ static int signals_blocked; static unsigned int signals_pending; static unsigned int signals_active = 0; -void sig_handler(int sig, struct siginfo *si, mcontext_t *mc) +static void sig_handler(int sig, struct siginfo *si, mcontext_t *mc) { int enabled = signals_enabled; @@ -108,7 +108,7 @@ static void timer_real_alarm_handler(mcontext_t *mc) timer_handler(SIGALRM, NULL, ®s); } -void timer_alarm_handler(int sig, struct siginfo *unused_si, mcontext_t *mc) +static void timer_alarm_handler(int sig, struct siginfo *unused_si, mcontext_t *mc) { int enabled; diff --git a/arch/x86/um/os-Linux/registers.c b/arch/x86/um/os-Linux/registers.c index df8f4b4bf98b..f3638dd09cec 100644 --- a/arch/x86/um/os-Linux/registers.c +++ b/arch/x86/um/os-Linux/registers.c @@ -17,7 +17,7 @@ #include #include -int have_xstate_support; +static int have_xstate_support; int save_i387_registers(int pid, unsigned long *fp_regs) { diff --git a/arch/x86/um/tls_32.c b/arch/x86/um/tls_32.c index 66162eafd8e8..ba40b1b8e179 100644 --- a/arch/x86/um/tls_32.c +++ b/arch/x86/um/tls_32.c @@ -20,7 +20,7 @@ static int host_supports_tls = -1; int host_gdt_entry_tls_min; -int do_set_thread_area(struct user_desc *info) +static int do_set_thread_area(struct user_desc *info) { int ret; u32 cpu; -- cgit v1.2.3-59-g8ed1b From 0c2b208c8b790b52587df6c66bfb6d9e0d6c4cd9 Mon Sep 17 00:00:00 2001 From: Tiwei Bie Date: Wed, 6 Mar 2024 18:19:18 +0800 Subject: um: Fix the declaration of vfree The definition of vfree has changed since commit b3bdda02aa54 ("vmalloc: add const to void* parameters"). Update the declaration of vfree in um_malloc.h to match the latest definition. Signed-off-by: Tiwei Bie Signed-off-by: Richard Weinberger --- arch/um/include/shared/um_malloc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/um/include/shared/um_malloc.h b/arch/um/include/shared/um_malloc.h index 13da93284c2c..d25084447c69 100644 --- a/arch/um/include/shared/um_malloc.h +++ b/arch/um/include/shared/um_malloc.h @@ -12,7 +12,7 @@ extern void *uml_kmalloc(int size, int flags); extern void kfree(const void *ptr); extern void *vmalloc(unsigned long size); -extern void vfree(void *ptr); +extern void vfree(const void *ptr); #endif /* __UM_MALLOC_H__ */ -- cgit v1.2.3-59-g8ed1b From b5e0950fd6cb8bd45ea0ac5378d10e1f9ede96c1 Mon Sep 17 00:00:00 2001 From: Tiwei Bie Date: Wed, 6 Mar 2024 18:19:19 +0800 Subject: um: Remove unused functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These functions are not used anymore. Removing them will also address below -Wmissing-prototypes warnings: arch/um/kernel/process.c:51:5: warning: no previous prototype for ‘pid_to_processor_id’ [-Wmissing-prototypes] arch/um/kernel/process.c:253:5: warning: no previous prototype for ‘copy_to_user_proc’ [-Wmissing-prototypes] arch/um/kernel/process.c:263:5: warning: no previous prototype for ‘clear_user_proc’ [-Wmissing-prototypes] arch/um/kernel/tlb.c:579:6: warning: no previous prototype for ‘flush_tlb_mm_range’ [-Wmissing-prototypes] Signed-off-by: Tiwei Bie Signed-off-by: Richard Weinberger --- arch/um/kernel/process.c | 21 --------------------- arch/um/kernel/tlb.c | 6 ------ 2 files changed, 27 deletions(-) diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c index 20f3813143d8..292c8014aaa6 100644 --- a/arch/um/kernel/process.c +++ b/arch/um/kernel/process.c @@ -48,17 +48,6 @@ static inline int external_pid(void) return userspace_pid[0]; } -int pid_to_processor_id(int pid) -{ - int i; - - for (i = 0; i < ncpus; i++) { - if (cpu_tasks[i].pid == pid) - return i; - } - return -1; -} - void free_stack(unsigned long stack, int order) { free_pages(stack, order); @@ -250,21 +239,11 @@ char *uml_strdup(const char *string) } EXPORT_SYMBOL(uml_strdup); -int copy_to_user_proc(void __user *to, void *from, int size) -{ - return copy_to_user(to, from, size); -} - int copy_from_user_proc(void *to, void __user *from, int size) { return copy_from_user(to, from, size); } -int clear_user_proc(void __user *buf, int size) -{ - return clear_user(buf, size); -} - static atomic_t using_sysemu = ATOMIC_INIT(0); int sysemu_supported; diff --git a/arch/um/kernel/tlb.c b/arch/um/kernel/tlb.c index 7d050ab0f78a..70b5e47e9761 100644 --- a/arch/um/kernel/tlb.c +++ b/arch/um/kernel/tlb.c @@ -576,12 +576,6 @@ void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, } EXPORT_SYMBOL(flush_tlb_range); -void flush_tlb_mm_range(struct mm_struct *mm, unsigned long start, - unsigned long end) -{ - fix_range(mm, start, end, 0); -} - void flush_tlb_mm(struct mm_struct *mm) { struct vm_area_struct *vma; -- cgit v1.2.3-59-g8ed1b From 179d83d89c584aa50f87ca3e44b1f1aff914303c Mon Sep 17 00:00:00 2001 From: Tiwei Bie Date: Wed, 6 Mar 2024 18:19:20 +0800 Subject: um: Fix the return type of __switch_to Make it match the declaration in asm-generic/switch_to.h. And also include the header to allow the compiler to check it. Signed-off-by: Tiwei Bie Signed-off-by: Richard Weinberger --- arch/um/kernel/process.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c index 292c8014aaa6..a7607ef1b02f 100644 --- a/arch/um/kernel/process.c +++ b/arch/um/kernel/process.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -73,7 +74,7 @@ static inline void set_current(struct task_struct *task) extern void arch_switch_to(struct task_struct *to); -void *__switch_to(struct task_struct *from, struct task_struct *to) +struct task_struct *__switch_to(struct task_struct *from, struct task_struct *to) { to->thread.prev_sched = from; set_current(to); -- cgit v1.2.3-59-g8ed1b From 9ffc6724a35c9404a99f430f3c35b0b6372390c1 Mon Sep 17 00:00:00 2001 From: Tiwei Bie Date: Wed, 6 Mar 2024 18:19:21 +0800 Subject: um: Add missing headers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This will address below -Wmissing-prototypes warnings: arch/um/kernel/mem.c:202:8: warning: no previous prototype for ‘pgd_alloc’ [-Wmissing-prototypes] arch/um/kernel/mem.c:215:7: warning: no previous prototype for ‘uml_kmalloc’ [-Wmissing-prototypes] arch/um/kernel/process.c:207:6: warning: no previous prototype for ‘arch_cpu_idle’ [-Wmissing-prototypes] arch/um/kernel/process.c:328:15: warning: no previous prototype for ‘arch_align_stack’ [-Wmissing-prototypes] arch/um/kernel/reboot.c:45:6: warning: no previous prototype for ‘machine_restart’ [-Wmissing-prototypes] arch/um/kernel/reboot.c:51:6: warning: no previous prototype for ‘machine_power_off’ [-Wmissing-prototypes] arch/um/kernel/reboot.c:57:6: warning: no previous prototype for ‘machine_halt’ [-Wmissing-prototypes] arch/um/kernel/skas/mmu.c:17:5: warning: no previous prototype for ‘init_new_context’ [-Wmissing-prototypes] arch/um/kernel/skas/mmu.c:60:6: warning: no previous prototype for ‘destroy_context’ [-Wmissing-prototypes] arch/um/kernel/skas/process.c:36:12: warning: no previous prototype for ‘start_uml’ [-Wmissing-prototypes] arch/um/kernel/time.c:807:15: warning: no previous prototype for ‘calibrate_delay_is_known’ [-Wmissing-prototypes] arch/um/kernel/tlb.c:594:6: warning: no previous prototype for ‘force_flush_all’ [-Wmissing-prototypes] arch/x86/um/bugs_32.c:22:6: warning: no previous prototype for ‘arch_check_bugs’ [-Wmissing-prototypes] arch/x86/um/bugs_32.c:44:6: warning: no previous prototype for ‘arch_examine_signal’ [-Wmissing-prototypes] arch/x86/um/bugs_64.c:9:6: warning: no previous prototype for ‘arch_check_bugs’ [-Wmissing-prototypes] arch/x86/um/bugs_64.c:13:6: warning: no previous prototype for ‘arch_examine_signal’ [-Wmissing-prototypes] arch/x86/um/elfcore.c:10:12: warning: no previous prototype for ‘elf_core_extra_phdrs’ [-Wmissing-prototypes] arch/x86/um/elfcore.c:15:5: warning: no previous prototype for ‘elf_core_write_extra_phdrs’ [-Wmissing-prototypes] arch/x86/um/elfcore.c:42:5: warning: no previous prototype for ‘elf_core_write_extra_data’ [-Wmissing-prototypes] arch/x86/um/elfcore.c:63:8: warning: no previous prototype for ‘elf_core_extra_data_size’ [-Wmissing-prototypes] arch/x86/um/fault.c:18:5: warning: no previous prototype for ‘arch_fixup’ [-Wmissing-prototypes] arch/x86/um/os-Linux/mcontext.c:7:6: warning: no previous prototype for ‘get_regs_from_mc’ [-Wmissing-prototypes] arch/x86/um/os-Linux/tls.c:22:6: warning: no previous prototype for ‘check_host_supports_tls’ [-Wmissing-prototypes] Signed-off-by: Tiwei Bie Signed-off-by: Richard Weinberger --- arch/um/kernel/mem.c | 2 ++ arch/um/kernel/process.c | 2 ++ arch/um/kernel/reboot.c | 1 + arch/um/kernel/skas/mmu.c | 1 + arch/um/kernel/skas/process.c | 1 + arch/um/kernel/time.c | 1 + arch/um/kernel/tlb.c | 1 + arch/x86/um/bugs_32.c | 1 + arch/x86/um/bugs_64.c | 1 + arch/x86/um/elfcore.c | 1 + arch/x86/um/fault.c | 1 + arch/x86/um/os-Linux/mcontext.c | 1 + arch/x86/um/os-Linux/tls.c | 1 + 13 files changed, 15 insertions(+) diff --git a/arch/um/kernel/mem.c b/arch/um/kernel/mem.c index 38d5a71a579b..ca91accd64fc 100644 --- a/arch/um/kernel/mem.c +++ b/arch/um/kernel/mem.c @@ -12,12 +12,14 @@ #include #include #include +#include #include #include #include #include #include #include +#include #include #ifdef CONFIG_KASAN diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c index a7607ef1b02f..4235e2ca2664 100644 --- a/arch/um/kernel/process.c +++ b/arch/um/kernel/process.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -27,6 +28,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/um/kernel/reboot.c b/arch/um/kernel/reboot.c index 48c0610d506e..25840eee1068 100644 --- a/arch/um/kernel/reboot.c +++ b/arch/um/kernel/reboot.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/um/kernel/skas/mmu.c b/arch/um/kernel/skas/mmu.c index 656fe16c9b63..aeed1c2aaf3c 100644 --- a/arch/um/kernel/skas/mmu.c +++ b/arch/um/kernel/skas/mmu.c @@ -10,6 +10,7 @@ #include #include +#include #include #include #include diff --git a/arch/um/kernel/skas/process.c b/arch/um/kernel/skas/process.c index f2ac134c9752..fdd5922f9222 100644 --- a/arch/um/kernel/skas/process.c +++ b/arch/um/kernel/skas/process.c @@ -12,6 +12,7 @@ #include #include #include +#include extern void start_kernel(void); diff --git a/arch/um/kernel/time.c b/arch/um/kernel/time.c index efa5b9c97992..a8bfe8be1526 100644 --- a/arch/um/kernel/time.c +++ b/arch/um/kernel/time.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/um/kernel/tlb.c b/arch/um/kernel/tlb.c index 70b5e47e9761..8784f03fa4a6 100644 --- a/arch/um/kernel/tlb.c +++ b/arch/um/kernel/tlb.c @@ -8,6 +8,7 @@ #include #include +#include #include #include #include diff --git a/arch/x86/um/bugs_32.c b/arch/x86/um/bugs_32.c index 33daff4dade4..d29929efcc07 100644 --- a/arch/x86/um/bugs_32.c +++ b/arch/x86/um/bugs_32.c @@ -3,6 +3,7 @@ * Licensed under the GPL */ +#include #include #include #include diff --git a/arch/x86/um/bugs_64.c b/arch/x86/um/bugs_64.c index 8cc8256c698d..b01295e8a676 100644 --- a/arch/x86/um/bugs_64.c +++ b/arch/x86/um/bugs_64.c @@ -4,6 +4,7 @@ * Licensed under the GPL */ +#include #include void arch_check_bugs(void) diff --git a/arch/x86/um/elfcore.c b/arch/x86/um/elfcore.c index 650cdbbdaf45..ef50662fc40d 100644 --- a/arch/x86/um/elfcore.c +++ b/arch/x86/um/elfcore.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 #include +#include #include #include #include diff --git a/arch/x86/um/fault.c b/arch/x86/um/fault.c index 84ac7f7b0257..0dde4d613a87 100644 --- a/arch/x86/um/fault.c +++ b/arch/x86/um/fault.c @@ -3,6 +3,7 @@ * Licensed under the GPL */ +#include #include /* These two are from asm-um/uaccess.h and linux/module.h, check them. */ diff --git a/arch/x86/um/os-Linux/mcontext.c b/arch/x86/um/os-Linux/mcontext.c index 49c3744cac37..e80ab7d28117 100644 --- a/arch/x86/um/os-Linux/mcontext.c +++ b/arch/x86/um/os-Linux/mcontext.c @@ -3,6 +3,7 @@ #define __FRAME_OFFSETS #include #include +#include void get_regs_from_mc(struct uml_pt_regs *regs, mcontext_t *mc) { diff --git a/arch/x86/um/os-Linux/tls.c b/arch/x86/um/os-Linux/tls.c index 3e1b1bf6acbc..eed9efe29ade 100644 --- a/arch/x86/um/os-Linux/tls.c +++ b/arch/x86/um/os-Linux/tls.c @@ -6,6 +6,7 @@ #include #include +#include #include #ifndef PTRACE_GET_THREAD_AREA -- cgit v1.2.3-59-g8ed1b From a4b4382f3e83bb4fa4a421e6cf5a5ef987658475 Mon Sep 17 00:00:00 2001 From: Tiwei Bie Date: Wed, 6 Mar 2024 18:19:23 +0800 Subject: um: Move declarations to proper headers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This will address below -Wmissing-prototypes warnings: arch/um/kernel/initrd.c:18:12: warning: no previous prototype for ‘read_initrd’ [-Wmissing-prototypes] arch/um/kernel/um_arch.c:408:19: warning: no previous prototype for ‘read_initrd’ [-Wmissing-prototypes] arch/um/os-Linux/start_up.c:301:12: warning: no previous prototype for ‘parse_iomem’ [-Wmissing-prototypes] arch/x86/um/ptrace_32.c:15:6: warning: no previous prototype for ‘arch_switch_to’ [-Wmissing-prototypes] arch/x86/um/ptrace_32.c:101:5: warning: no previous prototype for ‘poke_user’ [-Wmissing-prototypes] arch/x86/um/ptrace_32.c:153:5: warning: no previous prototype for ‘peek_user’ [-Wmissing-prototypes] arch/x86/um/ptrace_64.c:111:5: warning: no previous prototype for ‘poke_user’ [-Wmissing-prototypes] arch/x86/um/ptrace_64.c:171:5: warning: no previous prototype for ‘peek_user’ [-Wmissing-prototypes] arch/x86/um/syscalls_64.c:48:6: warning: no previous prototype for ‘arch_switch_to’ [-Wmissing-prototypes] arch/x86/um/tls_32.c:184:5: warning: no previous prototype for ‘arch_switch_tls’ [-Wmissing-prototypes] Signed-off-by: Tiwei Bie Signed-off-by: Richard Weinberger --- arch/um/include/asm/ptrace-generic.h | 3 +++ arch/um/include/shared/kern_util.h | 1 + arch/um/kernel/physmem.c | 3 +-- arch/um/kernel/process.c | 2 -- arch/um/kernel/ptrace.c | 3 --- arch/um/kernel/um_arch.h | 2 ++ arch/um/os-Linux/start_up.c | 1 + arch/x86/um/asm/ptrace.h | 6 ++++++ arch/x86/um/ptrace_32.c | 2 -- 9 files changed, 14 insertions(+), 9 deletions(-) diff --git a/arch/um/include/asm/ptrace-generic.h b/arch/um/include/asm/ptrace-generic.h index adf91ef553ae..4696f24d1492 100644 --- a/arch/um/include/asm/ptrace-generic.h +++ b/arch/um/include/asm/ptrace-generic.h @@ -36,6 +36,9 @@ extern long subarch_ptrace(struct task_struct *child, long request, extern unsigned long getreg(struct task_struct *child, int regno); extern int putreg(struct task_struct *child, int regno, unsigned long value); +extern int poke_user(struct task_struct *child, long addr, long data); +extern int peek_user(struct task_struct *child, long addr, long data); + extern int arch_set_tls(struct task_struct *new, unsigned long tls); extern void clear_flushed_tls(struct task_struct *task); extern int syscall_trace_enter(struct pt_regs *regs); diff --git a/arch/um/include/shared/kern_util.h b/arch/um/include/shared/kern_util.h index 789b83013f35..81bc38a2e3fc 100644 --- a/arch/um/include/shared/kern_util.h +++ b/arch/um/include/shared/kern_util.h @@ -41,6 +41,7 @@ extern void uml_pm_wake(void); extern int start_uml(void); extern void paging_init(void); +extern int parse_iomem(char *str, int *add); extern void uml_cleanup(void); extern void do_uml_exitcalls(void); diff --git a/arch/um/kernel/physmem.c b/arch/um/kernel/physmem.c index 91485119ae67..fb2adfb49945 100644 --- a/arch/um/kernel/physmem.c +++ b/arch/um/kernel/physmem.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -161,8 +162,6 @@ __uml_setup("mem=", uml_mem_setup, " Example: mem=64M\n\n" ); -extern int __init parse_iomem(char *str, int *add); - __uml_setup("iomem=", parse_iomem, "iomem=,\n" " Configure as an IO memory region named .\n\n" diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c index 4235e2ca2664..1395ff3017f0 100644 --- a/arch/um/kernel/process.c +++ b/arch/um/kernel/process.c @@ -74,8 +74,6 @@ static inline void set_current(struct task_struct *task) { external_pid(), task }); } -extern void arch_switch_to(struct task_struct *to); - struct task_struct *__switch_to(struct task_struct *from, struct task_struct *to) { to->thread.prev_sched = from; diff --git a/arch/um/kernel/ptrace.c b/arch/um/kernel/ptrace.c index 6600a2782796..2124624b7817 100644 --- a/arch/um/kernel/ptrace.c +++ b/arch/um/kernel/ptrace.c @@ -35,9 +35,6 @@ void ptrace_disable(struct task_struct *child) user_disable_single_step(child); } -extern int peek_user(struct task_struct * child, long addr, long data); -extern int poke_user(struct task_struct * child, long addr, long data); - long arch_ptrace(struct task_struct *child, long request, unsigned long addr, unsigned long data) { diff --git a/arch/um/kernel/um_arch.h b/arch/um/kernel/um_arch.h index 1e07fb7ee35e..46e731ab9dfc 100644 --- a/arch/um/kernel/um_arch.h +++ b/arch/um/kernel/um_arch.h @@ -11,4 +11,6 @@ extern void __init uml_dtb_init(void); static inline void uml_dtb_init(void) { } #endif +extern int __init read_initrd(void); + #endif diff --git a/arch/um/os-Linux/start_up.c b/arch/um/os-Linux/start_up.c index 8b0e98ab842c..6b21061c431c 100644 --- a/arch/um/os-Linux/start_up.c +++ b/arch/um/os-Linux/start_up.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/x86/um/asm/ptrace.h b/arch/x86/um/asm/ptrace.h index 83822fd42204..2fef3da55533 100644 --- a/arch/x86/um/asm/ptrace.h +++ b/arch/x86/um/asm/ptrace.h @@ -54,6 +54,8 @@ extern int ptrace_get_thread_area(struct task_struct *child, int idx, extern int ptrace_set_thread_area(struct task_struct *child, int idx, struct user_desc __user *user_desc); +extern int arch_switch_tls(struct task_struct *to); + #else #define PT_REGS_R8(r) UPT_R8(&(r)->regs) @@ -83,5 +85,9 @@ extern long arch_prctl(struct task_struct *task, int option, unsigned long __user *addr); #endif + #define user_stack_pointer(regs) PT_REGS_SP(regs) + +extern void arch_switch_to(struct task_struct *to); + #endif /* __UM_X86_PTRACE_H */ diff --git a/arch/x86/um/ptrace_32.c b/arch/x86/um/ptrace_32.c index 7f1abde2c84b..b0a71c6cdc6e 100644 --- a/arch/x86/um/ptrace_32.c +++ b/arch/x86/um/ptrace_32.c @@ -10,8 +10,6 @@ #include #include -extern int arch_switch_tls(struct task_struct *to); - void arch_switch_to(struct task_struct *to) { int err = arch_switch_tls(to); -- cgit v1.2.3-59-g8ed1b From 19cf79157309ea3834caf9ef442722f776b93814 Mon Sep 17 00:00:00 2001 From: Tiwei Bie Date: Wed, 6 Mar 2024 18:19:24 +0800 Subject: um: Fix -Wmissing-prototypes warnings for text_poke* MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The prototypes for text_poke* are declared in asm/text-patching.h under arch/x86/include/. It's safe to include this header, as it's UML-aware (by checking CONFIG_UML_X86). This will address below -Wmissing-prototypes warnings: arch/um/kernel/um_arch.c:461:7: warning: no previous prototype for ‘text_poke’ [-Wmissing-prototypes] arch/um/kernel/um_arch.c:473:6: warning: no previous prototype for ‘text_poke_sync’ [-Wmissing-prototypes] Signed-off-by: Tiwei Bie Signed-off-by: Richard Weinberger --- arch/um/kernel/um_arch.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c index 7a9820797eae..e95f805e5004 100644 --- a/arch/um/kernel/um_arch.c +++ b/arch/um/kernel/um_arch.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include -- cgit v1.2.3-59-g8ed1b From 49ff7d871242d7fd8adb8a2d8347c5d94dda808b Mon Sep 17 00:00:00 2001 From: Tiwei Bie Date: Wed, 6 Mar 2024 18:19:25 +0800 Subject: um: Fix -Wmissing-prototypes warnings for __warp_* and foo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These functions are not called explicitly. Let's just workaround the -Wmissing-prototypes warnings by declaring them locally similar to what was done in arch/x86/kernel/asm-offsets_32.c. This will address below -Wmissing-prototypes warnings: ./arch/x86/um/shared/sysdep/kernel-offsets.h:9:6: warning: no previous prototype for ‘foo’ [-Wmissing-prototypes] arch/um/os-Linux/main.c:187:7: warning: no previous prototype for ‘__wrap_malloc’ [-Wmissing-prototypes] arch/um/os-Linux/main.c:208:7: warning: no previous prototype for ‘__wrap_calloc’ [-Wmissing-prototypes] arch/um/os-Linux/main.c:222:6: warning: no previous prototype for ‘__wrap_free’ [-Wmissing-prototypes] arch/x86/um/user-offsets.c:17:6: warning: no previous prototype for ‘foo’ [-Wmissing-prototypes] Signed-off-by: Tiwei Bie Signed-off-by: Richard Weinberger --- arch/um/os-Linux/main.c | 5 +++++ arch/x86/um/shared/sysdep/kernel-offsets.h | 3 +++ arch/x86/um/user-offsets.c | 3 +++ 3 files changed, 11 insertions(+) diff --git a/arch/um/os-Linux/main.c b/arch/um/os-Linux/main.c index c8a42ecbd7a2..e82164f90288 100644 --- a/arch/um/os-Linux/main.c +++ b/arch/um/os-Linux/main.c @@ -184,6 +184,11 @@ int __init main(int argc, char **argv, char **envp) extern void *__real_malloc(int); +/* workaround for -Wmissing-prototypes warnings */ +void *__wrap_malloc(int size); +void *__wrap_calloc(int n, int size); +void __wrap_free(void *ptr); + void *__wrap_malloc(int size) { void *ret; diff --git a/arch/x86/um/shared/sysdep/kernel-offsets.h b/arch/x86/um/shared/sysdep/kernel-offsets.h index a004bffb7b8d..48de3a71f845 100644 --- a/arch/x86/um/shared/sysdep/kernel-offsets.h +++ b/arch/x86/um/shared/sysdep/kernel-offsets.h @@ -6,6 +6,9 @@ #include #include +/* workaround for a warning with -Wmissing-prototypes */ +void foo(void); + void foo(void) { #include diff --git a/arch/x86/um/user-offsets.c b/arch/x86/um/user-offsets.c index e54a9814ccf1..1c77d9946199 100644 --- a/arch/x86/um/user-offsets.c +++ b/arch/x86/um/user-offsets.c @@ -14,6 +14,9 @@ COMMENT(#val " / sizeof(unsigned long)"); \ DEFINE(sym, val / sizeof(unsigned long)) +/* workaround for a warning with -Wmissing-prototypes */ +void foo(void); + void foo(void) { #ifdef __i386__ -- cgit v1.2.3-59-g8ed1b From a0fbbd36c156b9f7b2276871d499c9943dfe5101 Mon Sep 17 00:00:00 2001 From: Roberto Sassu Date: Thu, 7 Mar 2024 11:49:26 +0100 Subject: um: Add winch to winch_handlers before registering winch IRQ Registering a winch IRQ is racy, an interrupt may occur before the winch is added to the winch_handlers list. If that happens, register_winch_irq() adds to that list a winch that is scheduled to be (or has already been) freed, causing a panic later in winch_cleanup(). Avoid the race by adding the winch to the winch_handlers list before registering the IRQ, and rolling back if um_request_irq() fails. Fixes: 42a359e31a0e ("uml: SIGIO support cleanup") Signed-off-by: Roberto Sassu Reviewed-by: Johannes Berg Signed-off-by: Richard Weinberger --- arch/um/drivers/line.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c index ffc5cb92fa36..d82bc3fdb86e 100644 --- a/arch/um/drivers/line.c +++ b/arch/um/drivers/line.c @@ -676,24 +676,26 @@ void register_winch_irq(int fd, int tty_fd, int pid, struct tty_port *port, goto cleanup; } - *winch = ((struct winch) { .list = LIST_HEAD_INIT(winch->list), - .fd = fd, + *winch = ((struct winch) { .fd = fd, .tty_fd = tty_fd, .pid = pid, .port = port, .stack = stack }); + spin_lock(&winch_handler_lock); + list_add(&winch->list, &winch_handlers); + spin_unlock(&winch_handler_lock); + if (um_request_irq(WINCH_IRQ, fd, IRQ_READ, winch_interrupt, IRQF_SHARED, "winch", winch) < 0) { printk(KERN_ERR "register_winch_irq - failed to register " "IRQ\n"); + spin_lock(&winch_handler_lock); + list_del(&winch->list); + spin_unlock(&winch_handler_lock); goto out_free; } - spin_lock(&winch_handler_lock); - list_add(&winch->list, &winch_handlers); - spin_unlock(&winch_handler_lock); - return; out_free: -- cgit v1.2.3-59-g8ed1b From 19ee69234a7281e4706d789c764f93be6fc7b5b2 Mon Sep 17 00:00:00 2001 From: Yueh-Shun Li Date: Sat, 23 Mar 2024 17:44:25 +0000 Subject: um: Makefile: use bash from the environment Set Makefile SHELL to bash instead of /bin/bash for better portability. Some systems do not install binaries to /bin, and therefore do not provide /bin/bash. This includes Linux distros which intentionally avoid implementing the Filesystem Hierarchy Standard (FHS), such as NixOS and Guix System. The recipies inside arch/um/Makefile don't require top-level Bash to build, and setting "SHELL" to "bash" makes Make pick the Bash executable from the environment, hence this patch. Changes since last roll: - Rebase onto a more recent commit on the master branch. - Remove a dangling in-text citation from the change log. - Reword the change log. Signed-off-by: Yueh-Shun Li Reviewed-by: Johannes Berg --- arch/um/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/um/Makefile b/arch/um/Makefile index 34957dcb88b9..00b63bac5eff 100644 --- a/arch/um/Makefile +++ b/arch/um/Makefile @@ -20,7 +20,7 @@ endif ARCH_DIR := arch/um # We require bash because the vmlinux link and loader script cpp use bash # features. -SHELL := /bin/bash +SHELL := bash MODE_INCLUDE += -I$(srctree)/$(ARCH_DIR)/include/shared/skas -- cgit v1.2.3-59-g8ed1b From 158a6b914c5196cdce2923e642a6acf0ebba3d31 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 28 Mar 2024 10:06:34 +0100 Subject: um: signal: move pid variable where needed We have W=1 warnings on 64-bit because the pid is only used in branches on 32-bit; move it inside to get rid of the warnings. Signed-off-by: Johannes Berg Reviewed-by: Tiwei Bie Signed-off-by: Richard Weinberger --- arch/x86/um/signal.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/arch/x86/um/signal.c b/arch/x86/um/signal.c index 263e1d08f216..16ff097e790d 100644 --- a/arch/x86/um/signal.c +++ b/arch/x86/um/signal.c @@ -155,7 +155,7 @@ static int copy_sc_from_user(struct pt_regs *regs, struct sigcontext __user *from) { struct sigcontext sc; - int err, pid; + int err; /* Always make any pending restarted system calls return -EINTR */ current->restart_block.fn = do_no_restart_syscall; @@ -201,10 +201,10 @@ static int copy_sc_from_user(struct pt_regs *regs, #undef GETREG - pid = userspace_pid[current_thread_info()->cpu]; #ifdef CONFIG_X86_32 if (have_fpx_regs) { struct user_fxsr_struct fpx; + int pid = userspace_pid[current_thread_info()->cpu]; err = copy_from_user(&fpx, &((struct _fpstate __user *)sc.fpstate)->_fxsr_env[0], @@ -240,7 +240,7 @@ static int copy_sc_to_user(struct sigcontext __user *to, { struct sigcontext sc; struct faultinfo * fi = ¤t->thread.arch.faultinfo; - int err, pid; + int err; memset(&sc, 0, sizeof(struct sigcontext)); #define PUTREG(regno, regname) sc.regname = regs->regs.gp[HOST_##regno] @@ -288,10 +288,9 @@ static int copy_sc_to_user(struct sigcontext __user *to, if (err) return 1; - pid = userspace_pid[current_thread_info()->cpu]; - #ifdef CONFIG_X86_32 if (have_fpx_regs) { + int pid = userspace_pid[current_thread_info()->cpu]; struct user_fxsr_struct fpx; err = save_fpx_registers(pid, (unsigned long *) &fpx); -- cgit v1.2.3-59-g8ed1b From e3cce8d87d6407f83a5741c3c5d54bf1365c6ac6 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 28 Mar 2024 10:06:35 +0100 Subject: um: slirp: remove set but unused variable 'pid' The code doesn't use 'pid' here, just remove it. Signed-off-by: Johannes Berg Reviewed-by: Tiwei Bie Signed-off-by: Richard Weinberger --- arch/um/drivers/slirp_user.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/um/drivers/slirp_user.c b/arch/um/drivers/slirp_user.c index 8f633e2e5f3d..97228aa080cb 100644 --- a/arch/um/drivers/slirp_user.c +++ b/arch/um/drivers/slirp_user.c @@ -49,7 +49,7 @@ static int slirp_tramp(char **argv, int fd) static int slirp_open(void *data) { struct slirp_data *pri = data; - int fds[2], pid, err; + int fds[2], err; err = os_pipe(fds, 1, 1); if (err) @@ -60,7 +60,6 @@ static int slirp_open(void *data) printk(UM_KERN_ERR "slirp_tramp failed - errno = %d\n", -err); goto out; } - pid = err; pri->slave = fds[1]; pri->slip.pos = 0; -- cgit v1.2.3-59-g8ed1b From 584ed2f76ff5fe360d87a04d17b6520c7999e06b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 28 Mar 2024 10:06:36 +0100 Subject: um: vector: fix bpfflash parameter evaluation With W=1 the build complains about a pointer compared to zero, clearly the result should've been compared. Fixes: 9807019a62dc ("um: Loadable BPF "Firmware" for vector drivers") Signed-off-by: Johannes Berg Reviewed-by: Tiwei Bie Signed-off-by: Richard Weinberger --- arch/um/drivers/vector_kern.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/um/drivers/vector_kern.c b/arch/um/drivers/vector_kern.c index dc2feae789cb..63e5f108a6b9 100644 --- a/arch/um/drivers/vector_kern.c +++ b/arch/um/drivers/vector_kern.c @@ -141,7 +141,7 @@ static bool get_bpf_flash(struct arglist *def) if (allow != NULL) { if (kstrtoul(allow, 10, &result) == 0) - return (allow > 0); + return result > 0; } return false; } -- cgit v1.2.3-59-g8ed1b From 2caa4982ea8ba601faf8313097720f87aafa7ea5 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 28 Mar 2024 10:06:37 +0100 Subject: um: vector: remove unused len variable/calculation The len variable is unused, so not needed, remove it. Signed-off-by: Johannes Berg Reviewed-by: Tiwei Bie Signed-off-by: Richard Weinberger --- arch/um/drivers/vector_kern.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/arch/um/drivers/vector_kern.c b/arch/um/drivers/vector_kern.c index 63e5f108a6b9..4279793b11b7 100644 --- a/arch/um/drivers/vector_kern.c +++ b/arch/um/drivers/vector_kern.c @@ -712,11 +712,9 @@ static struct vector_device *find_device(int n) static int vector_parse(char *str, int *index_out, char **str_out, char **error_out) { - int n, len, err; + int n, err; char *start = str; - len = strlen(str); - while ((*str != ':') && (strlen(str) > 1)) str++; if (*str != ':') { -- cgit v1.2.3-59-g8ed1b From dac847ae2b718d41b72bd68eb911ca2862ecfb38 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 28 Mar 2024 10:06:38 +0100 Subject: um: process: remove unused 'n' variable The return value of fn() wasn't used for a long time, so no need to assign it to a variable, addressing a W=1 warning. This seems to be - with patches from others posted to the list before - the last W=1 warning in arch/um/. Fixes: 22e2430d60db ("x86, um: convert to saner kernel_execve() semantics") Signed-off-by: Johannes Berg Reviewed-by: Tiwei Bie Signed-off-by: Richard Weinberger --- arch/um/kernel/process.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c index 1395ff3017f0..e5d7d24045a2 100644 --- a/arch/um/kernel/process.c +++ b/arch/um/kernel/process.c @@ -109,7 +109,7 @@ int get_current_pid(void) */ void new_thread_handler(void) { - int (*fn)(void *), n; + int (*fn)(void *); void *arg; if (current->thread.prev_sched != NULL) @@ -122,7 +122,7 @@ void new_thread_handler(void) /* * callback returns only if the kernel thread execs a process */ - n = fn(arg); + fn(arg); userspace(¤t->thread.regs.regs, current_thread_info()->aux_fp_regs); } -- cgit v1.2.3-59-g8ed1b From e7a8074d2f62c7c571e1e794f6eb2c90f68c514e Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 14 Jul 2023 10:00:22 -0300 Subject: tools include UAPI: Sync linux/vhost.h with the kernel sources To get the changes in: 2855c2a7820bc819 ("vhost-vdpa: change ioctl # for VDPA_GET_VRING_SIZE") 1496c47065f9f841 ("vhost-vdpa: uapi to support reporting per vq size") To pick up these changes and support them: $ tools/perf/trace/beauty/vhost_virtio_ioctl.sh > before $ cp include/uapi/linux/vhost.h tools/perf/trace/beauty/include/uapi/linux/vhost.h $ tools/perf/trace/beauty/vhost_virtio_ioctl.sh > after $ diff -u before after --- before 2024-04-22 13:39:37.185674799 -0300 +++ after 2024-04-22 13:39:52.043344784 -0300 @@ -50,5 +50,6 @@ [0x7F] = "VDPA_GET_VRING_DESC_GROUP", [0x80] = "VDPA_GET_VQS_COUNT", [0x81] = "VDPA_GET_GROUP_NUM", + [0x82] = "VDPA_GET_VRING_SIZE", [0x8] = "NEW_WORKER", }; $ For instance, see how those 'cmd' ioctl arguments get translated, now VDPA_GET_VRING_SIZE will be as well: # perf trace -a -e ioctl --max-events=10 0.000 ( 0.011 ms): pipewire/2261 ioctl(fd: 60, cmd: SNDRV_PCM_HWSYNC, arg: 0x1) = 0 21.353 ( 0.014 ms): pipewire/2261 ioctl(fd: 60, cmd: SNDRV_PCM_HWSYNC, arg: 0x1) = 0 25.766 ( 0.014 ms): gnome-shell/2196 ioctl(fd: 14, cmd: DRM_I915_IRQ_WAIT, arg: 0x7ffe4a22c740) = 0 25.845 ( 0.034 ms): gnome-shel:cs0/2212 ioctl(fd: 14, cmd: DRM_I915_IRQ_EMIT, arg: 0x7fd43915dc70) = 0 25.916 ( 0.011 ms): gnome-shell/2196 ioctl(fd: 9, cmd: DRM_MODE_ADDFB2, arg: 0x7ffe4a22c8a0) = 0 25.941 ( 0.025 ms): gnome-shell/2196 ioctl(fd: 9, cmd: DRM_MODE_ATOMIC, arg: 0x7ffe4a22c840) = 0 32.915 ( 0.009 ms): gnome-shell/2196 ioctl(fd: 9, cmd: DRM_MODE_RMFB, arg: 0x7ffe4a22cf9c) = 0 42.522 ( 0.013 ms): gnome-shell/2196 ioctl(fd: 14, cmd: DRM_I915_IRQ_WAIT, arg: 0x7ffe4a22c740) = 0 42.579 ( 0.031 ms): gnome-shel:cs0/2212 ioctl(fd: 14, cmd: DRM_I915_IRQ_EMIT, arg: 0x7fd43915dc70) = 0 42.644 ( 0.010 ms): gnome-shell/2196 ioctl(fd: 9, cmd: DRM_MODE_ADDFB2, arg: 0x7ffe4a22c8a0) = 0 # This addresses this perf tools build warning: diff -u tools/perf/trace/beauty/include/uapi/linux/vhost.h include/uapi/linux/vhost.h But this specific process, usually boring, this time around catch a problem, namely the addition of VDPA_GET_VRING_SIZE used an ioctl number already taken, which went on unnoticed and only got caught when the tools/perf/trace/beauty/vhost_virtio_ioctl.sh script was run as part of the perf tools process of updating the tools copies of system headers it uses for creating id->string tables that, well, broke the perf tools build because there were multiple initializations in the strings table for the 0x80 entry... I'm adding here a link to the discussion, that is lacking in the fix for the reported problem, and a quote from one of the developers involved: "Thanks a lot for taking care of this! So given the header is actually buggy pls hang on to this change until I merge the fix for the header (you were CC'd on the patch). It's great we have this redundancy which allowed us to catch the bug in time, and many thanks to Namhyung Kim for reporting the issue!" This is here as a hint for anyone thinking about ways to automate checking these issues in a more automated way... ;-) Link: https://lore.kernel.org/lkml/ 20240402172151-mutt-send-email-mst@kernel.org Cc: Adrian Hunter Cc: Ian Rogers Cc: Jiri Olsa Cc: Michael S. Tsirkin Cc: Namhyung Kim Cc: Zhu Lingshan Link: https://lore.kernel.org/lkml/ZiaW-csEZLKK48BE@x1 Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/trace/beauty/include/uapi/linux/vhost.h | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/tools/perf/trace/beauty/include/uapi/linux/vhost.h b/tools/perf/trace/beauty/include/uapi/linux/vhost.h index 649560c685f1..b95dd84eef2d 100644 --- a/tools/perf/trace/beauty/include/uapi/linux/vhost.h +++ b/tools/perf/trace/beauty/include/uapi/linux/vhost.h @@ -179,12 +179,6 @@ /* Get the config size */ #define VHOST_VDPA_GET_CONFIG_SIZE _IOR(VHOST_VIRTIO, 0x79, __u32) -/* Get the count of all virtqueues */ -#define VHOST_VDPA_GET_VQS_COUNT _IOR(VHOST_VIRTIO, 0x80, __u32) - -/* Get the number of virtqueue groups. */ -#define VHOST_VDPA_GET_GROUP_NUM _IOR(VHOST_VIRTIO, 0x81, __u32) - /* Get the number of address spaces. */ #define VHOST_VDPA_GET_AS_NUM _IOR(VHOST_VIRTIO, 0x7A, unsigned int) @@ -227,4 +221,18 @@ */ #define VHOST_VDPA_GET_VRING_DESC_GROUP _IOWR(VHOST_VIRTIO, 0x7F, \ struct vhost_vring_state) + + +/* Get the count of all virtqueues */ +#define VHOST_VDPA_GET_VQS_COUNT _IOR(VHOST_VIRTIO, 0x80, __u32) + +/* Get the number of virtqueue groups. */ +#define VHOST_VDPA_GET_GROUP_NUM _IOR(VHOST_VIRTIO, 0x81, __u32) + +/* Get the queue size of a specific virtqueue. + * userspace set the vring index in vhost_vring_state.index + * kernel set the queue size in vhost_vring_state.num + */ +#define VHOST_VDPA_GET_VRING_SIZE _IOWR(VHOST_VIRTIO, 0x82, \ + struct vhost_vring_state) #endif -- cgit v1.2.3-59-g8ed1b From af6605f87ca585f426272e4a5096771ae273f30f Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Mon, 1 Apr 2024 11:02:22 -0600 Subject: MAINTAINERS: Orphan vfio fsl-mc bus driver Email to Diana is bouncing. I've reached out through other channels but not been successful for a couple months. Lore shows no email from Diana for approximately 18 months. Mark this driver as orphaned. Reviewed-by: Kevin Tian Link: https://lore.kernel.org/r/20240401170224.3700774-1-alex.williamson@redhat.com Signed-off-by: Alex Williamson --- MAINTAINERS | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index ebf03f5f0619..aa415ddc6c03 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -23225,9 +23225,8 @@ F: include/linux/vfio_pci_core.h F: include/uapi/linux/vfio.h VFIO FSL-MC DRIVER -M: Diana Craciun L: kvm@vger.kernel.org -S: Maintained +S: Orphan F: drivers/vfio/fsl-mc/ VFIO HISILICON PCI DRIVER -- cgit v1.2.3-59-g8ed1b From 071e7310e69368de551388088827c57df05f59aa Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Mon, 1 Apr 2024 13:54:02 -0600 Subject: vfio/pci: Pass eventfd context to IRQ handler Create a link back to the vfio_pci_core_device on the eventfd context object to avoid lookups in the interrupt path. The context is known valid in the interrupt handler. Reviewed-by: Kevin Tian Link: https://lore.kernel.org/r/20240401195406.3720453-2-alex.williamson@redhat.com Signed-off-by: Alex Williamson --- drivers/vfio/pci/vfio_pci_intrs.c | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/drivers/vfio/pci/vfio_pci_intrs.c b/drivers/vfio/pci/vfio_pci_intrs.c index fb5392b749ff..31dbc2d061f3 100644 --- a/drivers/vfio/pci/vfio_pci_intrs.c +++ b/drivers/vfio/pci/vfio_pci_intrs.c @@ -23,11 +23,12 @@ #include "vfio_pci_priv.h" struct vfio_pci_irq_ctx { - struct eventfd_ctx *trigger; - struct virqfd *unmask; - struct virqfd *mask; - char *name; - bool masked; + struct vfio_pci_core_device *vdev; + struct eventfd_ctx *trigger; + struct virqfd *unmask; + struct virqfd *mask; + char *name; + bool masked; struct irq_bypass_producer producer; }; @@ -228,15 +229,11 @@ void vfio_pci_intx_unmask(struct vfio_pci_core_device *vdev) static irqreturn_t vfio_intx_handler(int irq, void *dev_id) { - struct vfio_pci_core_device *vdev = dev_id; - struct vfio_pci_irq_ctx *ctx; + struct vfio_pci_irq_ctx *ctx = dev_id; + struct vfio_pci_core_device *vdev = ctx->vdev; unsigned long flags; int ret = IRQ_NONE; - ctx = vfio_irq_ctx_get(vdev, 0); - if (WARN_ON_ONCE(!ctx)) - return ret; - spin_lock_irqsave(&vdev->irqlock, flags); if (!vdev->pci_2_3) { @@ -282,6 +279,7 @@ static int vfio_intx_enable(struct vfio_pci_core_device *vdev, ctx->name = name; ctx->trigger = trigger; + ctx->vdev = vdev; /* * Fill the initial masked state based on virq_disabled. After @@ -312,7 +310,7 @@ static int vfio_intx_enable(struct vfio_pci_core_device *vdev, vdev->irq_type = VFIO_PCI_INTX_IRQ_INDEX; ret = request_irq(pdev->irq, vfio_intx_handler, - irqflags, ctx->name, vdev); + irqflags, ctx->name, ctx); if (ret) { vdev->irq_type = VFIO_PCI_NUM_IRQS; kfree(name); @@ -358,7 +356,7 @@ static void vfio_intx_disable(struct vfio_pci_core_device *vdev) if (ctx) { vfio_virqfd_disable(&ctx->unmask); vfio_virqfd_disable(&ctx->mask); - free_irq(pdev->irq, vdev); + free_irq(pdev->irq, ctx); if (ctx->trigger) eventfd_ctx_put(ctx->trigger); kfree(ctx->name); -- cgit v1.2.3-59-g8ed1b From d530531936482f97b7b3784793d3514185b820d4 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Mon, 1 Apr 2024 13:54:03 -0600 Subject: vfio/pci: Pass eventfd context object through irqfd Further avoid lookup of the context object by passing it through the irqfd data field. Reviewed-by: Kevin Tian Link: https://lore.kernel.org/r/20240401195406.3720453-3-alex.williamson@redhat.com Signed-off-by: Alex Williamson --- drivers/vfio/pci/vfio_pci_intrs.c | 33 +++++++++++++-------------------- 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/drivers/vfio/pci/vfio_pci_intrs.c b/drivers/vfio/pci/vfio_pci_intrs.c index 31dbc2d061f3..d52825a096ad 100644 --- a/drivers/vfio/pci/vfio_pci_intrs.c +++ b/drivers/vfio/pci/vfio_pci_intrs.c @@ -85,19 +85,14 @@ vfio_irq_ctx_alloc(struct vfio_pci_core_device *vdev, unsigned long index) /* * INTx */ -static void vfio_send_intx_eventfd(void *opaque, void *unused) +static void vfio_send_intx_eventfd(void *opaque, void *data) { struct vfio_pci_core_device *vdev = opaque; if (likely(is_intx(vdev) && !vdev->virq_disabled)) { - struct vfio_pci_irq_ctx *ctx; - struct eventfd_ctx *trigger; + struct vfio_pci_irq_ctx *ctx = data; + struct eventfd_ctx *trigger = READ_ONCE(ctx->trigger); - ctx = vfio_irq_ctx_get(vdev, 0); - if (WARN_ON_ONCE(!ctx)) - return; - - trigger = READ_ONCE(ctx->trigger); if (likely(trigger)) eventfd_signal(trigger); } @@ -167,11 +162,11 @@ bool vfio_pci_intx_mask(struct vfio_pci_core_device *vdev) * a signal is necessary, which can then be handled via a work queue * or directly depending on the caller. */ -static int vfio_pci_intx_unmask_handler(void *opaque, void *unused) +static int vfio_pci_intx_unmask_handler(void *opaque, void *data) { struct vfio_pci_core_device *vdev = opaque; struct pci_dev *pdev = vdev->pdev; - struct vfio_pci_irq_ctx *ctx; + struct vfio_pci_irq_ctx *ctx = data; unsigned long flags; int ret = 0; @@ -187,10 +182,6 @@ static int vfio_pci_intx_unmask_handler(void *opaque, void *unused) goto out_unlock; } - ctx = vfio_irq_ctx_get(vdev, 0); - if (WARN_ON_ONCE(!ctx)) - goto out_unlock; - if (ctx->masked && !vdev->virq_disabled) { /* * A pending interrupt here would immediately trigger, @@ -214,10 +205,12 @@ out_unlock: static void __vfio_pci_intx_unmask(struct vfio_pci_core_device *vdev) { + struct vfio_pci_irq_ctx *ctx = vfio_irq_ctx_get(vdev, 0); + lockdep_assert_held(&vdev->igate); - if (vfio_pci_intx_unmask_handler(vdev, NULL) > 0) - vfio_send_intx_eventfd(vdev, NULL); + if (vfio_pci_intx_unmask_handler(vdev, ctx) > 0) + vfio_send_intx_eventfd(vdev, ctx); } void vfio_pci_intx_unmask(struct vfio_pci_core_device *vdev) @@ -249,7 +242,7 @@ static irqreturn_t vfio_intx_handler(int irq, void *dev_id) spin_unlock_irqrestore(&vdev->irqlock, flags); if (ret == IRQ_HANDLED) - vfio_send_intx_eventfd(vdev, NULL); + vfio_send_intx_eventfd(vdev, ctx); return ret; } @@ -604,7 +597,7 @@ static int vfio_pci_set_intx_unmask(struct vfio_pci_core_device *vdev, if (fd >= 0) return vfio_virqfd_enable((void *) vdev, vfio_pci_intx_unmask_handler, - vfio_send_intx_eventfd, NULL, + vfio_send_intx_eventfd, ctx, &ctx->unmask, fd); vfio_virqfd_disable(&ctx->unmask); @@ -671,11 +664,11 @@ static int vfio_pci_set_intx_trigger(struct vfio_pci_core_device *vdev, return -EINVAL; if (flags & VFIO_IRQ_SET_DATA_NONE) { - vfio_send_intx_eventfd(vdev, NULL); + vfio_send_intx_eventfd(vdev, vfio_irq_ctx_get(vdev, 0)); } else if (flags & VFIO_IRQ_SET_DATA_BOOL) { uint8_t trigger = *(uint8_t *)data; if (trigger) - vfio_send_intx_eventfd(vdev, NULL); + vfio_send_intx_eventfd(vdev, vfio_irq_ctx_get(vdev, 0)); } return 0; } -- cgit v1.2.3-59-g8ed1b From 82b951e6fbd31d85ae7f4feb5f00ddd4c5d256e2 Mon Sep 17 00:00:00 2001 From: Ye Bin Date: Mon, 15 Apr 2024 09:50:29 +0800 Subject: vfio/pci: fix potential memory leak in vfio_intx_enable() If vfio_irq_ctx_alloc() failed will lead to 'name' memory leak. Fixes: 18c198c96a81 ("vfio/pci: Create persistent INTx handler") Signed-off-by: Ye Bin Reviewed-by: Kevin Tian Acked-by: Reinette Chatre Link: https://lore.kernel.org/r/20240415015029.3699844-1-yebin10@huawei.com Signed-off-by: Alex Williamson --- drivers/vfio/pci/vfio_pci_intrs.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/vfio/pci/vfio_pci_intrs.c b/drivers/vfio/pci/vfio_pci_intrs.c index d52825a096ad..8382c5834335 100644 --- a/drivers/vfio/pci/vfio_pci_intrs.c +++ b/drivers/vfio/pci/vfio_pci_intrs.c @@ -267,8 +267,10 @@ static int vfio_intx_enable(struct vfio_pci_core_device *vdev, return -ENOMEM; ctx = vfio_irq_ctx_alloc(vdev, 0); - if (!ctx) + if (!ctx) { + kfree(name); return -ENOMEM; + } ctx->name = name; ctx->trigger = trigger; -- cgit v1.2.3-59-g8ed1b From 89d5d9e9500826cbd3b15ea7b6e8d9fae966f073 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 22 Apr 2024 17:48:50 +0300 Subject: counter: Don't use "proxy" headers Update header inclusions to follow IWYU (Include What You Use) principle. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240422144850.2031076-1-andriy.shevchenko@linux.intel.com Signed-off-by: William Breathitt Gray --- include/linux/counter.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/linux/counter.h b/include/linux/counter.h index cd35d8574ee2..426b7d58a438 100644 --- a/include/linux/counter.h +++ b/include/linux/counter.h @@ -6,14 +6,15 @@ #ifndef _COUNTER_H_ #define _COUNTER_H_ +#include #include #include -#include #include #include #include #include #include + #include struct counter_device; -- cgit v1.2.3-59-g8ed1b From c6ca1ac9f4722c6aa940d61baa2416624472b7f0 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Fri, 5 Apr 2024 07:50:50 +0300 Subject: thunderbolt: Increase sideband access polling delay The USB4 sideband access is slow compared to the high-speed link and the access timing parameters are tens of milliseconds according the spec. To avoid too much unnecessary polling for the sideband pass the wait delay to usb4_port_wait_for_bit() and use larger (5ms) value compared to the high-speed access. Signed-off-by: Mika Westerberg --- drivers/thunderbolt/usb4.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/drivers/thunderbolt/usb4.c b/drivers/thunderbolt/usb4.c index 9860b49d7a2b..cc62587736e5 100644 --- a/drivers/thunderbolt/usb4.c +++ b/drivers/thunderbolt/usb4.c @@ -52,6 +52,10 @@ enum usb4_ba_index { #define USB4_BA_VALUE_MASK GENMASK(31, 16) #define USB4_BA_VALUE_SHIFT 16 +/* Delays in us used with usb4_port_wait_for_bit() */ +#define USB4_PORT_DELAY 50 +#define USB4_PORT_SB_DELAY 5000 + static int usb4_native_switch_op(struct tb_switch *sw, u16 opcode, u32 *metadata, u8 *status, const void *tx_data, size_t tx_dwords, @@ -1244,7 +1248,7 @@ void usb4_port_unconfigure_xdomain(struct tb_port *port) } static int usb4_port_wait_for_bit(struct tb_port *port, u32 offset, u32 bit, - u32 value, int timeout_msec) + u32 value, int timeout_msec, unsigned long delay_usec) { ktime_t timeout = ktime_add_ms(ktime_get(), timeout_msec); @@ -1259,7 +1263,7 @@ static int usb4_port_wait_for_bit(struct tb_port *port, u32 offset, u32 bit, if ((val & bit) == value) return 0; - usleep_range(50, 100); + fsleep(delay_usec); } while (ktime_before(ktime_get(), timeout)); return -ETIMEDOUT; @@ -1307,7 +1311,7 @@ static int usb4_port_sb_read(struct tb_port *port, enum usb4_sb_target target, return ret; ret = usb4_port_wait_for_bit(port, port->cap_usb4 + PORT_CS_1, - PORT_CS_1_PND, 0, 500); + PORT_CS_1_PND, 0, 500, USB4_PORT_SB_DELAY); if (ret) return ret; @@ -1354,7 +1358,7 @@ static int usb4_port_sb_write(struct tb_port *port, enum usb4_sb_target target, return ret; ret = usb4_port_wait_for_bit(port, port->cap_usb4 + PORT_CS_1, - PORT_CS_1_PND, 0, 500); + PORT_CS_1_PND, 0, 500, USB4_PORT_SB_DELAY); if (ret) return ret; @@ -1409,6 +1413,8 @@ static int usb4_port_sb_op(struct tb_port *port, enum usb4_sb_target target, if (val != opcode) return usb4_port_sb_opcode_err_to_errno(val); + + fsleep(USB4_PORT_SB_DELAY); } while (ktime_before(ktime_get(), timeout)); return -ETIMEDOUT; @@ -1590,13 +1596,14 @@ int usb4_port_asym_start(struct tb_port *port) * port started the symmetry transition. */ ret = usb4_port_wait_for_bit(port, port->cap_usb4 + PORT_CS_19, - PORT_CS_19_START_ASYM, 0, 1000); + PORT_CS_19_START_ASYM, 0, 1000, + USB4_PORT_DELAY); if (ret) return ret; /* Then wait for the transtion to be completed */ return usb4_port_wait_for_bit(port, port->cap_usb4 + PORT_CS_18, - PORT_CS_18_TIP, 0, 5000); + PORT_CS_18_TIP, 0, 5000, USB4_PORT_DELAY); } /** @@ -2122,7 +2129,8 @@ static int usb4_usb3_port_cm_request(struct tb_port *port, bool request) */ val &= ADP_USB3_CS_2_CMR; return usb4_port_wait_for_bit(port, port->cap_adap + ADP_USB3_CS_1, - ADP_USB3_CS_1_HCA, val, 1500); + ADP_USB3_CS_1_HCA, val, 1500, + USB4_PORT_DELAY); } static inline int usb4_usb3_port_set_cm_request(struct tb_port *port) -- cgit v1.2.3-59-g8ed1b From d4d336f8c4d5a4609217ac83116ba3d06b7e918c Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Fri, 5 Apr 2024 07:47:40 +0300 Subject: thunderbolt: No need to loop over all retimers if access fails When we read the NVM authentication status or unsetting the inbound SBTX there is no point to continue the loop after first access to a retimer fails because there won't be any more retimers after this anyway so bail out from the loops early. Signed-off-by: Mika Westerberg --- drivers/thunderbolt/retimer.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/thunderbolt/retimer.c b/drivers/thunderbolt/retimer.c index 6bb49bdcd6c1..6eaaa5074ce8 100644 --- a/drivers/thunderbolt/retimer.c +++ b/drivers/thunderbolt/retimer.c @@ -199,8 +199,10 @@ static void tb_retimer_nvm_authenticate_status(struct tb_port *port, u32 *status * If the retimer has it set, store it for the new retimer * device instance. */ - for (i = 1; i <= TB_MAX_RETIMER_INDEX; i++) - usb4_port_retimer_nvm_authenticate_status(port, i, &status[i]); + for (i = 1; i <= TB_MAX_RETIMER_INDEX; i++) { + if (usb4_port_retimer_nvm_authenticate_status(port, i, &status[i])) + break; + } } static void tb_retimer_set_inbound_sbtx(struct tb_port *port) @@ -234,8 +236,10 @@ static void tb_retimer_unset_inbound_sbtx(struct tb_port *port) tb_port_dbg(port, "disabling sideband transactions\n"); - for (i = TB_MAX_RETIMER_INDEX; i >= 1; i--) - usb4_port_retimer_unset_inbound_sbtx(port, i); + for (i = TB_MAX_RETIMER_INDEX; i >= 1; i--) { + if (usb4_port_retimer_unset_inbound_sbtx(port, i)) + break; + } } static ssize_t nvm_authenticate_store(struct device *dev, -- cgit v1.2.3-59-g8ed1b From 110b24eb1a749bea3440f3ca2ff890a26179050a Mon Sep 17 00:00:00 2001 From: Konstantin Komarov Date: Wed, 17 Apr 2024 10:33:06 +0300 Subject: fs/ntfs3: Taking DOS names into account during link counting When counting and checking hard links in an ntfs file record, struct MFT_REC { struct NTFS_RECORD_HEADER rhdr; // 'FILE' __le16 seq; // 0x10: Sequence number for this record. >> __le16 hard_links; // 0x12: The number of hard links to record. __le16 attr_off; // 0x14: Offset to attributes. ... the ntfs3 driver ignored short names (DOS names), causing the link count to be reduced by 1 and messages to be output to dmesg. For Windows, such a situation is a minor error, meaning chkdsk does not report errors on such a volume, and in the case of using the /f switch, it silently corrects them, reporting that no errors were found. This does not affect the consistency of the file system. Nevertheless, the behavior in the ntfs3 driver is incorrect and changes the content of the file system. This patch should fix that. PS: most likely, there has been a confusion of concepts MFT_REC::hard_links and inode::__i_nlink. Fixes: 82cae269cfa95 ("fs/ntfs3: Add initialization of super block") Signed-off-by: Konstantin Komarov Cc: stable@vger.kernel.org --- fs/ntfs3/inode.c | 7 ++++--- fs/ntfs3/record.c | 11 ++--------- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/fs/ntfs3/inode.c b/fs/ntfs3/inode.c index eb7a8c9fba01..05f169018c4e 100644 --- a/fs/ntfs3/inode.c +++ b/fs/ntfs3/inode.c @@ -37,7 +37,7 @@ static struct inode *ntfs_read_mft(struct inode *inode, bool is_dir; unsigned long ino = inode->i_ino; u32 rp_fa = 0, asize, t32; - u16 roff, rsize, names = 0; + u16 roff, rsize, names = 0, links = 0; const struct ATTR_FILE_NAME *fname = NULL; const struct INDEX_ROOT *root; struct REPARSE_DATA_BUFFER rp; // 0x18 bytes @@ -200,11 +200,12 @@ next_attr: rsize < SIZEOF_ATTRIBUTE_FILENAME) goto out; + names += 1; fname = Add2Ptr(attr, roff); if (fname->type == FILE_NAME_DOS) goto next_attr; - names += 1; + links += 1; if (name && name->len == fname->name_len && !ntfs_cmp_names_cpu(name, (struct le_str *)&fname->name_len, NULL, false)) @@ -429,7 +430,7 @@ end_enum: ni->mi.dirty = true; } - set_nlink(inode, names); + set_nlink(inode, links); if (S_ISDIR(mode)) { ni->std_fa |= FILE_ATTRIBUTE_DIRECTORY; diff --git a/fs/ntfs3/record.c b/fs/ntfs3/record.c index 6aa3a9d44df1..6c76503edc20 100644 --- a/fs/ntfs3/record.c +++ b/fs/ntfs3/record.c @@ -534,16 +534,9 @@ bool mi_remove_attr(struct ntfs_inode *ni, struct mft_inode *mi, if (aoff + asize > used) return false; - if (ni && is_attr_indexed(attr)) { + if (ni && is_attr_indexed(attr) && attr->type == ATTR_NAME) { u16 links = le16_to_cpu(ni->mi.mrec->hard_links); - struct ATTR_FILE_NAME *fname = - attr->type != ATTR_NAME ? - NULL : - resident_data_ex(attr, - SIZEOF_ATTRIBUTE_FILENAME); - if (fname && fname->type == FILE_NAME_DOS) { - /* Do not decrease links count deleting DOS name. */ - } else if (!links) { + if (!links) { /* minor error. Not critical. */ } else { ni->mi.mrec->hard_links = cpu_to_le16(links - 1); -- cgit v1.2.3-59-g8ed1b From a8948b5450e7c65a3a34ebf4ccfcebc19335d4fb Mon Sep 17 00:00:00 2001 From: Konstantin Komarov Date: Wed, 3 Apr 2024 10:08:04 +0300 Subject: fs/ntfs3: Remove max link count info display during driver init Removes the output of this purely informational message from the kernel buffer: "ntfs3: Max link count 4000" Signed-off-by: Konstantin Komarov Cc: stable@vger.kernel.org --- fs/ntfs3/super.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/fs/ntfs3/super.c b/fs/ntfs3/super.c index 9df7c20d066f..ac4722011140 100644 --- a/fs/ntfs3/super.c +++ b/fs/ntfs3/super.c @@ -1804,8 +1804,6 @@ static int __init init_ntfs_fs(void) { int err; - pr_info("ntfs3: Max link count %u\n", NTFS_LINK_MAX); - if (IS_ENABLED(CONFIG_NTFS3_FS_POSIX_ACL)) pr_info("ntfs3: Enabled Linux POSIX ACLs support\n"); if (IS_ENABLED(CONFIG_NTFS3_64BIT_CLUSTER)) -- cgit v1.2.3-59-g8ed1b From b0a5ddee56a3683bdd6400f763158efea78cee3c Mon Sep 17 00:00:00 2001 From: Konstantin Komarov Date: Tue, 16 Apr 2024 09:39:48 +0300 Subject: fs/ntfs3: Missed le32_to_cpu conversion NTFS data structure fields are stored in little-endian, it is necessary to take this into account when working on big-endian architectures. Fixes: 1b7dd28e14c47("fs/ntfs3: Correct function is_rst_area_valid") Signed-off-by: Konstantin Komarov --- fs/ntfs3/fslog.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ntfs3/fslog.c b/fs/ntfs3/fslog.c index 855519713bf7..d9d08823de62 100644 --- a/fs/ntfs3/fslog.c +++ b/fs/ntfs3/fslog.c @@ -517,7 +517,7 @@ static inline bool is_rst_area_valid(const struct RESTART_HDR *rhdr) seq_bits -= 1; } - if (seq_bits != ra->seq_num_bits) + if (seq_bits != le32_to_cpu(ra->seq_num_bits)) return false; /* The log page data offset and record header length must be quad-aligned. */ -- cgit v1.2.3-59-g8ed1b From 1cd6c96219c429ebcfa8e79a865277376c563803 Mon Sep 17 00:00:00 2001 From: Konstantin Komarov Date: Tue, 16 Apr 2024 09:54:34 +0300 Subject: fs/ntfs3: Check 'folio' pointer for NULL It can be NULL if bmap is called. Fixes: 82cae269cfa95 ("fs/ntfs3: Add initialization of super block") Signed-off-by: Konstantin Komarov --- fs/ntfs3/inode.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/fs/ntfs3/inode.c b/fs/ntfs3/inode.c index 05f169018c4e..502a527e51cd 100644 --- a/fs/ntfs3/inode.c +++ b/fs/ntfs3/inode.c @@ -571,13 +571,18 @@ static noinline int ntfs_get_block_vbo(struct inode *inode, u64 vbo, clear_buffer_uptodate(bh); if (is_resident(ni)) { - ni_lock(ni); - err = attr_data_read_resident(ni, &folio->page); - ni_unlock(ni); - - if (!err) - set_buffer_uptodate(bh); + bh->b_blocknr = RESIDENT_LCN; bh->b_size = block_size; + if (!folio) { + err = 0; + } else { + ni_lock(ni); + err = attr_data_read_resident(ni, &folio->page); + ni_unlock(ni); + + if (!err) + set_buffer_uptodate(bh); + } return err; } -- cgit v1.2.3-59-g8ed1b From e931f6b630ffb22d66caab202a52aa8cbb10c649 Mon Sep 17 00:00:00 2001 From: Konstantin Komarov Date: Tue, 16 Apr 2024 09:45:09 +0300 Subject: fs/ntfs3: Use 64 bit variable to avoid 32 bit overflow For example, in the expression: vbo = 2 * vbo + skip Fixes: b46acd6a6a627 ("fs/ntfs3: Add NTFS journal") Signed-off-by: Konstantin Komarov --- fs/ntfs3/fslog.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/ntfs3/fslog.c b/fs/ntfs3/fslog.c index d9d08823de62..d7807d255dfe 100644 --- a/fs/ntfs3/fslog.c +++ b/fs/ntfs3/fslog.c @@ -1184,7 +1184,8 @@ out: static int log_read_rst(struct ntfs_log *log, bool first, struct restart_info *info) { - u32 skip, vbo; + u32 skip; + u64 vbo; struct RESTART_HDR *r_page = NULL; /* Determine which restart area we are looking for. */ -- cgit v1.2.3-59-g8ed1b From 1997cdc3e727526aa5d84b32f7cbb3f56459b7ef Mon Sep 17 00:00:00 2001 From: Konstantin Komarov Date: Tue, 16 Apr 2024 09:43:58 +0300 Subject: fs/ntfs3: Use variable length array instead of fixed size Should fix smatch warning: ntfs_set_label() error: __builtin_memcpy() 'uni->name' too small (20 vs 256) Fixes: 4534a70b7056f ("fs/ntfs3: Add headers and misc files") Reported-by: kernel test robot Reported-by: Dan Carpenter Closes: https://lore.kernel.org/r/202401091421.3RJ24Mn3-lkp@intel.com/ Signed-off-by: Konstantin Komarov --- fs/ntfs3/ntfs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ntfs3/ntfs.h b/fs/ntfs3/ntfs.h index 9c7478150a03..3d6143c7abc0 100644 --- a/fs/ntfs3/ntfs.h +++ b/fs/ntfs3/ntfs.h @@ -59,7 +59,7 @@ struct GUID { struct cpu_str { u8 len; u8 unused; - u16 name[10]; + u16 name[]; }; struct le_str { -- cgit v1.2.3-59-g8ed1b From c935c66878867dc87c36c36b21d35d7e7f08adec Mon Sep 17 00:00:00 2001 From: Konstantin Komarov Date: Tue, 16 Apr 2024 09:52:47 +0300 Subject: fs/ntfs3: Redesign ntfs_create_inode to return error code instead of inode As Al Viro correctly pointed out, there is no need to return the whole structure to check the error. https://lore.kernel.org/ntfs3/20240322023515.GK538574@ZenIV/ Acked-by: Al Viro Signed-off-by: Konstantin Komarov --- fs/ntfs3/inode.c | 22 +++++++++++----------- fs/ntfs3/namei.c | 31 ++++++++----------------------- fs/ntfs3/ntfs_fs.h | 9 ++++----- 3 files changed, 23 insertions(+), 39 deletions(-) diff --git a/fs/ntfs3/inode.c b/fs/ntfs3/inode.c index 502a527e51cd..8fdcf37b3186 100644 --- a/fs/ntfs3/inode.c +++ b/fs/ntfs3/inode.c @@ -1216,11 +1216,10 @@ out: * * NOTE: if fnd != NULL (ntfs_atomic_open) then @dir is locked */ -struct inode *ntfs_create_inode(struct mnt_idmap *idmap, struct inode *dir, - struct dentry *dentry, - const struct cpu_str *uni, umode_t mode, - dev_t dev, const char *symname, u32 size, - struct ntfs_fnd *fnd) +int ntfs_create_inode(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, const struct cpu_str *uni, + umode_t mode, dev_t dev, const char *symname, u32 size, + struct ntfs_fnd *fnd) { int err; struct super_block *sb = dir->i_sb; @@ -1245,6 +1244,9 @@ struct inode *ntfs_create_inode(struct mnt_idmap *idmap, struct inode *dir, struct REPARSE_DATA_BUFFER *rp = NULL; bool rp_inserted = false; + /* New file will be resident or non resident. */ + const bool new_file_resident = 1; + if (!fnd) ni_lock_dir(dir_ni); @@ -1484,7 +1486,7 @@ struct inode *ntfs_create_inode(struct mnt_idmap *idmap, struct inode *dir, attr->size = cpu_to_le32(SIZEOF_RESIDENT); attr->name_off = SIZEOF_RESIDENT_LE; attr->res.data_off = SIZEOF_RESIDENT_LE; - } else if (S_ISREG(mode)) { + } else if (!new_file_resident && S_ISREG(mode)) { /* * Regular file. Create empty non resident data attribute. */ @@ -1721,12 +1723,10 @@ out1: if (!fnd) ni_unlock(dir_ni); - if (err) - return ERR_PTR(err); - - unlock_new_inode(inode); + if (!err) + unlock_new_inode(inode); - return inode; + return err; } int ntfs_link_inode(struct inode *inode, struct dentry *dentry) diff --git a/fs/ntfs3/namei.c b/fs/ntfs3/namei.c index edb6a7141246..71498421ce60 100644 --- a/fs/ntfs3/namei.c +++ b/fs/ntfs3/namei.c @@ -107,12 +107,8 @@ static struct dentry *ntfs_lookup(struct inode *dir, struct dentry *dentry, static int ntfs_create(struct mnt_idmap *idmap, struct inode *dir, struct dentry *dentry, umode_t mode, bool excl) { - struct inode *inode; - - inode = ntfs_create_inode(idmap, dir, dentry, NULL, S_IFREG | mode, 0, - NULL, 0, NULL); - - return IS_ERR(inode) ? PTR_ERR(inode) : 0; + return ntfs_create_inode(idmap, dir, dentry, NULL, S_IFREG | mode, 0, + NULL, 0, NULL); } /* @@ -123,12 +119,8 @@ static int ntfs_create(struct mnt_idmap *idmap, struct inode *dir, static int ntfs_mknod(struct mnt_idmap *idmap, struct inode *dir, struct dentry *dentry, umode_t mode, dev_t rdev) { - struct inode *inode; - - inode = ntfs_create_inode(idmap, dir, dentry, NULL, mode, rdev, NULL, 0, - NULL); - - return IS_ERR(inode) ? PTR_ERR(inode) : 0; + return ntfs_create_inode(idmap, dir, dentry, NULL, mode, rdev, NULL, 0, + NULL); } /* @@ -200,15 +192,12 @@ static int ntfs_symlink(struct mnt_idmap *idmap, struct inode *dir, struct dentry *dentry, const char *symname) { u32 size = strlen(symname); - struct inode *inode; if (unlikely(ntfs3_forced_shutdown(dir->i_sb))) return -EIO; - inode = ntfs_create_inode(idmap, dir, dentry, NULL, S_IFLNK | 0777, 0, - symname, size, NULL); - - return IS_ERR(inode) ? PTR_ERR(inode) : 0; + return ntfs_create_inode(idmap, dir, dentry, NULL, S_IFLNK | 0777, 0, + symname, size, NULL); } /* @@ -217,12 +206,8 @@ static int ntfs_symlink(struct mnt_idmap *idmap, struct inode *dir, static int ntfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, struct dentry *dentry, umode_t mode) { - struct inode *inode; - - inode = ntfs_create_inode(idmap, dir, dentry, NULL, S_IFDIR | mode, 0, - NULL, 0, NULL); - - return IS_ERR(inode) ? PTR_ERR(inode) : 0; + return ntfs_create_inode(idmap, dir, dentry, NULL, S_IFDIR | mode, 0, + NULL, 0, NULL); } /* diff --git a/fs/ntfs3/ntfs_fs.h b/fs/ntfs3/ntfs_fs.h index 79356fd29a14..3db6a61f61dc 100644 --- a/fs/ntfs3/ntfs_fs.h +++ b/fs/ntfs3/ntfs_fs.h @@ -714,11 +714,10 @@ int ntfs_sync_inode(struct inode *inode); int ntfs_flush_inodes(struct super_block *sb, struct inode *i1, struct inode *i2); int inode_write_data(struct inode *inode, const void *data, size_t bytes); -struct inode *ntfs_create_inode(struct mnt_idmap *idmap, struct inode *dir, - struct dentry *dentry, - const struct cpu_str *uni, umode_t mode, - dev_t dev, const char *symname, u32 size, - struct ntfs_fnd *fnd); +int ntfs_create_inode(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, const struct cpu_str *uni, + umode_t mode, dev_t dev, const char *symname, u32 size, + struct ntfs_fnd *fnd); int ntfs_link_inode(struct inode *inode, struct dentry *dentry); int ntfs_unlink_inode(struct inode *dir, const struct dentry *dentry); void ntfs_evict_inode(struct inode *inode); -- cgit v1.2.3-59-g8ed1b From 40bb3c590582f488ec1ff8c31b7fc806e5732f42 Mon Sep 17 00:00:00 2001 From: Konstantin Komarov Date: Tue, 16 Apr 2024 10:08:18 +0300 Subject: fs/ntfs3: Always make file nonresident on fallocate call xfstest 438 is starting to pass with this change. Signed-off-by: Konstantin Komarov --- fs/ntfs3/attrib.c | 32 ++++++++++++++++++++++++++++++++ fs/ntfs3/file.c | 9 +++++++++ fs/ntfs3/ntfs_fs.h | 1 + 3 files changed, 42 insertions(+) diff --git a/fs/ntfs3/attrib.c b/fs/ntfs3/attrib.c index 7aadf5010999..8e6bcdf99770 100644 --- a/fs/ntfs3/attrib.c +++ b/fs/ntfs3/attrib.c @@ -2558,3 +2558,35 @@ undo_insert_range: goto out; } + +/* + * attr_force_nonresident + * + * Convert default data attribute into non resident form. + */ +int attr_force_nonresident(struct ntfs_inode *ni) +{ + int err; + struct ATTRIB *attr; + struct ATTR_LIST_ENTRY *le = NULL; + struct mft_inode *mi; + + attr = ni_find_attr(ni, NULL, &le, ATTR_DATA, NULL, 0, NULL, &mi); + if (!attr) { + ntfs_bad_inode(&ni->vfs_inode, "no data attribute"); + return -ENOENT; + } + + if (attr->non_res) { + /* Already non resident. */ + return 0; + } + + down_write(&ni->file.run_lock); + err = attr_make_nonresident(ni, attr, le, mi, + le32_to_cpu(attr->res.data_size), + &ni->file.run, &attr, NULL); + up_write(&ni->file.run_lock); + + return err; +} diff --git a/fs/ntfs3/file.c b/fs/ntfs3/file.c index 5418662c80d8..fce8ea098d60 100644 --- a/fs/ntfs3/file.c +++ b/fs/ntfs3/file.c @@ -578,6 +578,15 @@ static long ntfs_fallocate(struct file *file, int mode, loff_t vbo, loff_t len) /* Check new size. */ u8 cluster_bits = sbi->cluster_bits; + /* Be sure file is non resident. */ + if (is_resident(ni)) { + ni_lock(ni); + err = attr_force_nonresident(ni); + ni_unlock(ni); + if (err) + goto out; + } + /* generic/213: expected -ENOSPC instead of -EFBIG. */ if (!is_supported_holes) { loff_t to_alloc = new_size - inode_get_bytes(inode); diff --git a/fs/ntfs3/ntfs_fs.h b/fs/ntfs3/ntfs_fs.h index 3db6a61f61dc..00dec0ec5648 100644 --- a/fs/ntfs3/ntfs_fs.h +++ b/fs/ntfs3/ntfs_fs.h @@ -452,6 +452,7 @@ int attr_allocate_frame(struct ntfs_inode *ni, CLST frame, size_t compr_size, int attr_collapse_range(struct ntfs_inode *ni, u64 vbo, u64 bytes); int attr_insert_range(struct ntfs_inode *ni, u64 vbo, u64 bytes); int attr_punch_hole(struct ntfs_inode *ni, u64 vbo, u64 bytes, u32 *frame_size); +int attr_force_nonresident(struct ntfs_inode *ni); /* Functions from attrlist.c */ void al_destroy(struct ntfs_inode *ni); -- cgit v1.2.3-59-g8ed1b From 24f6f5020b0b2c89c2cba5ec224547be95f753ee Mon Sep 17 00:00:00 2001 From: Konstantin Komarov Date: Mon, 22 Apr 2024 17:18:51 +0300 Subject: fs/ntfs3: Mark volume as dirty if xattr is broken Mark a volume as corrupted if the name length exceeds the space occupied by ea. Signed-off-by: Konstantin Komarov --- fs/ntfs3/xattr.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fs/ntfs3/xattr.c b/fs/ntfs3/xattr.c index 53e7d1fa036a..73785dece7a7 100644 --- a/fs/ntfs3/xattr.c +++ b/fs/ntfs3/xattr.c @@ -219,8 +219,11 @@ static ssize_t ntfs_list_ea(struct ntfs_inode *ni, char *buffer, if (!ea->name_len) break; - if (ea->name_len > ea_size) + if (ea->name_len > ea_size) { + ntfs_set_state(ni->mi.sbi, NTFS_DIRTY_ERROR); + err = -EINVAL; /* corrupted fs */ break; + } if (buffer) { /* Check if we can use field ea->name */ -- cgit v1.2.3-59-g8ed1b From 1eb3816c2757f6ba755a313837cc16dd193f5766 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 15 Apr 2024 17:23:28 +0300 Subject: fpga: ice40-spi: Don't use "proxy" headers Update header inclusions to follow IWYU (Include What You Use) principle. Signed-off-by: Andy Shevchenko Acked-by: Xu Yilun Link: https://lore.kernel.org/r/20240415142428.853812-1-andriy.shevchenko@linux.intel.com Signed-off-by: Xu Yilun --- drivers/fpga/ice40-spi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/fpga/ice40-spi.c b/drivers/fpga/ice40-spi.c index c0028ae4c5b7..62c30266130d 100644 --- a/drivers/fpga/ice40-spi.c +++ b/drivers/fpga/ice40-spi.c @@ -10,8 +10,8 @@ #include #include +#include #include -#include #include #include @@ -199,7 +199,7 @@ static struct spi_driver ice40_fpga_driver = { .probe = ice40_fpga_probe, .driver = { .name = "ice40spi", - .of_match_table = of_match_ptr(ice40_fpga_of_match), + .of_match_table = ice40_fpga_of_match, }, .id_table = ice40_fpga_spi_ids, }; -- cgit v1.2.3-59-g8ed1b From 7c2dafa60e7a74bd5fd584e35d3176a439495a16 Mon Sep 17 00:00:00 2001 From: Peter Colberg Date: Mon, 15 Apr 2024 19:57:43 -0400 Subject: fpga: dfl: remove unused function is_dfl_feature_present() The function is_dfl_feature_present() was added but never used. Fixes: 5b57d02a2f94 ("fpga: dfl: add feature device infrastructure") Signed-off-by: Peter Colberg Reviewed-by: Matthew Gerlach Acked-by: Xu Yilun Link: https://lore.kernel.org/r/20240415235743.3045-1-peter.colberg@intel.com Signed-off-by: Xu Yilun --- drivers/fpga/dfl.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/fpga/dfl.h b/drivers/fpga/dfl.h index 1d724a28f00a..5063d73b0d82 100644 --- a/drivers/fpga/dfl.h +++ b/drivers/fpga/dfl.h @@ -437,11 +437,6 @@ void __iomem *dfl_get_feature_ioaddr_by_id(struct device *dev, u16 id) return NULL; } -static inline bool is_dfl_feature_present(struct device *dev, u16 id) -{ - return !!dfl_get_feature_ioaddr_by_id(dev, id); -} - static inline struct device *dfl_fpga_pdata_to_parent(struct dfl_feature_platform_data *pdata) { -- cgit v1.2.3-59-g8ed1b From dbca8048b33c8e612d3bb7d314cfe002d9478daa Mon Sep 17 00:00:00 2001 From: Peter Colberg Date: Mon, 15 Apr 2024 19:59:37 -0400 Subject: fpga: dfl: remove unused member pdata from struct dfl_{afu,fme} The member pdata in struct dfl_{afu,fme} is set in function {afu,fme}_dev_init(), respectively, but never used. Fixes: 857a26222ff7 ("fpga: dfl: afu: add afu sub feature support") Fixes: 29de76240e86 ("fpga: dfl: fme: add partial reconfiguration sub feature support") Signed-off-by: Peter Colberg Reviewed-by: Matthew Gerlach Acked-by: Xu Yilun Link: https://lore.kernel.org/r/20240415235937.3121-1-peter.colberg@intel.com Signed-off-by: Xu Yilun --- drivers/fpga/dfl-afu-main.c | 2 -- drivers/fpga/dfl-afu.h | 3 --- drivers/fpga/dfl-fme-main.c | 2 -- drivers/fpga/dfl-fme.h | 2 -- 4 files changed, 9 deletions(-) diff --git a/drivers/fpga/dfl-afu-main.c b/drivers/fpga/dfl-afu-main.c index c0a75ca360d6..6b97c073849e 100644 --- a/drivers/fpga/dfl-afu-main.c +++ b/drivers/fpga/dfl-afu-main.c @@ -858,8 +858,6 @@ static int afu_dev_init(struct platform_device *pdev) if (!afu) return -ENOMEM; - afu->pdata = pdata; - mutex_lock(&pdata->lock); dfl_fpga_pdata_set_private(pdata, afu); afu_mmio_region_init(pdata); diff --git a/drivers/fpga/dfl-afu.h b/drivers/fpga/dfl-afu.h index 674e9772f0ea..7bef3e300aa2 100644 --- a/drivers/fpga/dfl-afu.h +++ b/drivers/fpga/dfl-afu.h @@ -67,7 +67,6 @@ struct dfl_afu_dma_region { * @regions: the mmio region linked list of this afu feature device. * @dma_regions: root of dma regions rb tree. * @num_umsgs: num of umsgs. - * @pdata: afu platform device's pdata. */ struct dfl_afu { u64 region_cur_offset; @@ -75,8 +74,6 @@ struct dfl_afu { u8 num_umsgs; struct list_head regions; struct rb_root dma_regions; - - struct dfl_feature_platform_data *pdata; }; /* hold pdata->lock when call __afu_port_enable/disable */ diff --git a/drivers/fpga/dfl-fme-main.c b/drivers/fpga/dfl-fme-main.c index a2b5da0093da..864924f68f5e 100644 --- a/drivers/fpga/dfl-fme-main.c +++ b/drivers/fpga/dfl-fme-main.c @@ -679,8 +679,6 @@ static int fme_dev_init(struct platform_device *pdev) if (!fme) return -ENOMEM; - fme->pdata = pdata; - mutex_lock(&pdata->lock); dfl_fpga_pdata_set_private(pdata, fme); mutex_unlock(&pdata->lock); diff --git a/drivers/fpga/dfl-fme.h b/drivers/fpga/dfl-fme.h index 4195dd68193e..a566dbc2b485 100644 --- a/drivers/fpga/dfl-fme.h +++ b/drivers/fpga/dfl-fme.h @@ -24,13 +24,11 @@ * @mgr: FME's FPGA manager platform device. * @region_list: linked list of FME's FPGA regions. * @bridge_list: linked list of FME's FPGA bridges. - * @pdata: fme platform device's pdata. */ struct dfl_fme { struct platform_device *mgr; struct list_head region_list; struct list_head bridge_list; - struct dfl_feature_platform_data *pdata; }; extern const struct dfl_feature_ops fme_pr_mgmt_ops; -- cgit v1.2.3-59-g8ed1b From b7c0e1ecee403a43abc89eb3e75672b01ff2ece9 Mon Sep 17 00:00:00 2001 From: Marco Pagani Date: Fri, 19 Apr 2024 10:35:59 +0200 Subject: fpga: region: add owner module and take its refcount The current implementation of the fpga region assumes that the low-level module registers a driver for the parent device and uses its owner pointer to take the module's refcount. This approach is problematic since it can lead to a null pointer dereference while attempting to get the region during programming if the parent device does not have a driver. To address this problem, add a module owner pointer to the fpga_region struct and use it to take the module's refcount. Modify the functions for registering a region to take an additional owner module parameter and rename them to avoid conflicts. Use the old function names for helper macros that automatically set the module that registers the region as the owner. This ensures compatibility with existing low-level control modules and reduces the chances of registering a region without setting the owner. Also, update the documentation to keep it consistent with the new interface for registering an fpga region. Fixes: 0fa20cdfcc1f ("fpga: fpga-region: device tree control for FPGA") Suggested-by: Greg Kroah-Hartman Suggested-by: Xu Yilun Reviewed-by: Russ Weight Signed-off-by: Marco Pagani Acked-by: Xu Yilun Link: https://lore.kernel.org/r/20240419083601.77403-1-marpagan@redhat.com Signed-off-by: Xu Yilun --- Documentation/driver-api/fpga/fpga-region.rst | 13 ++++++++----- drivers/fpga/fpga-region.c | 24 ++++++++++++++---------- include/linux/fpga/fpga-region.h | 13 ++++++++++--- 3 files changed, 32 insertions(+), 18 deletions(-) diff --git a/Documentation/driver-api/fpga/fpga-region.rst b/Documentation/driver-api/fpga/fpga-region.rst index dc55d60a0b4a..2d03b5fb7657 100644 --- a/Documentation/driver-api/fpga/fpga-region.rst +++ b/Documentation/driver-api/fpga/fpga-region.rst @@ -46,13 +46,16 @@ API to add a new FPGA region ---------------------------- * struct fpga_region - The FPGA region struct -* struct fpga_region_info - Parameter structure for fpga_region_register_full() -* fpga_region_register_full() - Create and register an FPGA region using the +* struct fpga_region_info - Parameter structure for __fpga_region_register_full() +* __fpga_region_register_full() - Create and register an FPGA region using the fpga_region_info structure to provide the full flexibility of options -* fpga_region_register() - Create and register an FPGA region using standard +* __fpga_region_register() - Create and register an FPGA region using standard arguments * fpga_region_unregister() - Unregister an FPGA region +Helper macros ``fpga_region_register()`` and ``fpga_region_register_full()`` +automatically set the module that registers the FPGA region as the owner. + The FPGA region's probe function will need to get a reference to the FPGA Manager it will be using to do the programming. This usually would happen during the region's probe function. @@ -82,10 +85,10 @@ following APIs to handle building or tearing down that list. :functions: fpga_region_info .. kernel-doc:: drivers/fpga/fpga-region.c - :functions: fpga_region_register_full + :functions: __fpga_region_register_full .. kernel-doc:: drivers/fpga/fpga-region.c - :functions: fpga_region_register + :functions: __fpga_region_register .. kernel-doc:: drivers/fpga/fpga-region.c :functions: fpga_region_unregister diff --git a/drivers/fpga/fpga-region.c b/drivers/fpga/fpga-region.c index b364a929425c..753cd142503e 100644 --- a/drivers/fpga/fpga-region.c +++ b/drivers/fpga/fpga-region.c @@ -53,7 +53,7 @@ static struct fpga_region *fpga_region_get(struct fpga_region *region) } get_device(dev); - if (!try_module_get(dev->parent->driver->owner)) { + if (!try_module_get(region->ops_owner)) { put_device(dev); mutex_unlock(®ion->mutex); return ERR_PTR(-ENODEV); @@ -75,7 +75,7 @@ static void fpga_region_put(struct fpga_region *region) dev_dbg(dev, "put\n"); - module_put(dev->parent->driver->owner); + module_put(region->ops_owner); put_device(dev); mutex_unlock(®ion->mutex); } @@ -181,14 +181,16 @@ static struct attribute *fpga_region_attrs[] = { ATTRIBUTE_GROUPS(fpga_region); /** - * fpga_region_register_full - create and register an FPGA Region device + * __fpga_region_register_full - create and register an FPGA Region device * @parent: device parent * @info: parameters for FPGA Region + * @owner: module containing the get_bridges function * * Return: struct fpga_region or ERR_PTR() */ struct fpga_region * -fpga_region_register_full(struct device *parent, const struct fpga_region_info *info) +__fpga_region_register_full(struct device *parent, const struct fpga_region_info *info, + struct module *owner) { struct fpga_region *region; int id, ret = 0; @@ -213,6 +215,7 @@ fpga_region_register_full(struct device *parent, const struct fpga_region_info * region->compat_id = info->compat_id; region->priv = info->priv; region->get_bridges = info->get_bridges; + region->ops_owner = owner; mutex_init(®ion->mutex); INIT_LIST_HEAD(®ion->bridge_list); @@ -241,13 +244,14 @@ err_free: return ERR_PTR(ret); } -EXPORT_SYMBOL_GPL(fpga_region_register_full); +EXPORT_SYMBOL_GPL(__fpga_region_register_full); /** - * fpga_region_register - create and register an FPGA Region device + * __fpga_region_register - create and register an FPGA Region device * @parent: device parent * @mgr: manager that programs this region * @get_bridges: optional function to get bridges to a list + * @owner: module containing the get_bridges function * * This simple version of the register function should be sufficient for most users. * The fpga_region_register_full() function is available for users that need to @@ -256,17 +260,17 @@ EXPORT_SYMBOL_GPL(fpga_region_register_full); * Return: struct fpga_region or ERR_PTR() */ struct fpga_region * -fpga_region_register(struct device *parent, struct fpga_manager *mgr, - int (*get_bridges)(struct fpga_region *)) +__fpga_region_register(struct device *parent, struct fpga_manager *mgr, + int (*get_bridges)(struct fpga_region *), struct module *owner) { struct fpga_region_info info = { 0 }; info.mgr = mgr; info.get_bridges = get_bridges; - return fpga_region_register_full(parent, &info); + return __fpga_region_register_full(parent, &info, owner); } -EXPORT_SYMBOL_GPL(fpga_region_register); +EXPORT_SYMBOL_GPL(__fpga_region_register); /** * fpga_region_unregister - unregister an FPGA region diff --git a/include/linux/fpga/fpga-region.h b/include/linux/fpga/fpga-region.h index 9d4d32909340..5fbc05fe70a6 100644 --- a/include/linux/fpga/fpga-region.h +++ b/include/linux/fpga/fpga-region.h @@ -36,6 +36,7 @@ struct fpga_region_info { * @mgr: FPGA manager * @info: FPGA image info * @compat_id: FPGA region id for compatibility check. + * @ops_owner: module containing the get_bridges function * @priv: private data * @get_bridges: optional function to get bridges to a list */ @@ -46,6 +47,7 @@ struct fpga_region { struct fpga_manager *mgr; struct fpga_image_info *info; struct fpga_compat_id *compat_id; + struct module *ops_owner; void *priv; int (*get_bridges)(struct fpga_region *region); }; @@ -58,12 +60,17 @@ fpga_region_class_find(struct device *start, const void *data, int fpga_region_program_fpga(struct fpga_region *region); +#define fpga_region_register_full(parent, info) \ + __fpga_region_register_full(parent, info, THIS_MODULE) struct fpga_region * -fpga_region_register_full(struct device *parent, const struct fpga_region_info *info); +__fpga_region_register_full(struct device *parent, const struct fpga_region_info *info, + struct module *owner); +#define fpga_region_register(parent, mgr, get_bridges) \ + __fpga_region_register(parent, mgr, get_bridges, THIS_MODULE) struct fpga_region * -fpga_region_register(struct device *parent, struct fpga_manager *mgr, - int (*get_bridges)(struct fpga_region *)); +__fpga_region_register(struct device *parent, struct fpga_manager *mgr, + int (*get_bridges)(struct fpga_region *), struct module *owner); void fpga_region_unregister(struct fpga_region *region); #endif /* _FPGA_REGION_H */ -- cgit v1.2.3-59-g8ed1b From a42f2e9ba13b8a4c556f43ed99e22ae14fb73130 Mon Sep 17 00:00:00 2001 From: Zelong Dong Date: Mon, 22 Apr 2024 19:11:45 +0800 Subject: arm64: dts: amlogic: Add Amlogic T7 reset controller Add the device node and related header file for Amlogic T7 reset controller. Signed-off-by: Zelong Dong Signed-off-by: Kelvin Zhang Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20240422-t7-reset-v2-3-cb82271d3296@amlogic.com Signed-off-by: Neil Armstrong --- arch/arm64/boot/dts/amlogic/amlogic-t7-reset.h | 197 +++++++++++++++++++++++++ arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi | 7 + 2 files changed, 204 insertions(+) create mode 100644 arch/arm64/boot/dts/amlogic/amlogic-t7-reset.h diff --git a/arch/arm64/boot/dts/amlogic/amlogic-t7-reset.h b/arch/arm64/boot/dts/amlogic/amlogic-t7-reset.h new file mode 100644 index 000000000000..ec90a11df508 --- /dev/null +++ b/arch/arm64/boot/dts/amlogic/amlogic-t7-reset.h @@ -0,0 +1,197 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR MIT) */ +/* + * Copyright (c) 2024 Amlogic, Inc. All rights reserved. + */ + +#ifndef __DTS_AMLOGIC_T7_RESET_H +#define __DTS_AMLOGIC_T7_RESET_H + +/* RESET0 */ +/* 0-3 */ +#define RESET_USB 4 +#define RESET_U2DRD 5 +#define RESET_U3DRD 6 +#define RESET_U3DRD_PIPE0 7 +#define RESET_U2PHY20 8 +#define RESET_U2PHY21 9 +#define RESET_GDC 10 +#define RESET_HDMI20_AES 11 +#define RESET_HDMIRX 12 +#define RESET_HDMIRX_APB 13 +#define RESET_DEWARP 14 +/* 15 */ +#define RESET_HDMITX_CAPB3 16 +#define RESET_BRG_VCBUG_DEC 17 +#define RESET_VCBUS 18 +#define RESET_VID_PLL_DIV 19 +#define RESET_VDI6 20 +#define RESET_GE2D 21 +#define RESET_HDMITXPHY 22 +#define RESET_VID_LOCK 23 +#define RESET_VENC0 24 +#define RESET_VDAC 25 +#define RESET_VENC2 26 +#define RESET_VENC1 27 +#define RESET_RDMA 28 +#define RESET_HDMITX 29 +#define RESET_VIU 30 +#define RESET_VENC 31 + +/* RESET1 */ +#define RESET_AUDIO 32 +#define RESET_MALI_CAPB3 33 +#define RESET_MALI 34 +#define RESET_DDR_APB 35 +#define RESET_DDR 36 +#define RESET_DOS_CAPB3 37 +#define RESET_DOS 38 +#define RESET_COMBO_DPHY_CHAN2 39 +#define RESET_DEBUG_B 40 +#define RESET_DEBUG_A 41 +#define RESET_DSP_B 42 +#define RESET_DSP_A 43 +#define RESET_PCIE_A 44 +#define RESET_PCIE_PHY 45 +#define RESET_PCIE_APB 46 +#define RESET_ANAKIN 47 +#define RESET_ETH 48 +#define RESET_EDP0_CTRL 49 +#define RESET_EDP1_CTRL 50 +#define RESET_COMBO_DPHY_CHAN0 51 +#define RESET_COMBO_DPHY_CHAN1 52 +#define RESET_DSI_LVDS_EDP_TOP 53 +#define RESET_PCIE1_PHY 54 +#define RESET_PCIE1_APB 55 +#define RESET_DDR_1 56 +/* 57 */ +#define RESET_EDP1_PIPELINE 58 +#define RESET_EDP0_PIPELINE 59 +#define RESET_MIPI_DSI1_PHY 60 +#define RESET_MIPI_DSI0_PHY 61 +#define RESET_MIPI_DSI_A_HOST 62 +#define RESET_MIPI_DSI_B_HOST 63 + +/* RESET2 */ +#define RESET_DEVICE_MMC_ARB 64 +#define RESET_IR_CTRL 65 +#define RESET_TS_A73 66 +#define RESET_TS_A53 67 +#define RESET_SPICC_2 68 +#define RESET_SPICC_3 69 +#define RESET_SPICC_4 70 +#define RESET_SPICC_5 71 +#define RESET_SMART_CARD 72 +#define RESET_SPICC_0 73 +#define RESET_SPICC_1 74 +#define RESET_RSA 75 +/* 76-79 */ +#define RESET_MSR_CLK 80 +#define RESET_SPIFC 81 +#define RESET_SAR_ADC 82 +#define RESET_BT 83 +/* 84-87 */ +#define RESET_ACODEC 88 +#define RESET_CEC 89 +#define RESET_AFIFO 90 +#define RESET_WATCHDOG 91 +/* 92-95 */ + +/* RESET3 */ +#define RESET_BRG_NIC1_GPV 96 +#define RESET_BRG_NIC2_GPV 97 +#define RESET_BRG_NIC3_GPV 98 +#define RESET_BRG_NIC4_GPV 99 +#define RESET_BRG_NIC5_GPV 100 +/* 101-121 */ +#define RESET_MIPI_ISP 122 +#define RESET_BRG_ADB_MALI_1 123 +#define RESET_BRG_ADB_MALI_0 124 +#define RESET_BRG_ADB_A73 125 +#define RESET_BRG_ADB_A53 126 +#define RESET_BRG_CCI 127 + +/* RESET4 */ +#define RESET_PWM_AO_AB 128 +#define RESET_PWM_AO_CD 129 +#define RESET_PWM_AO_EF 130 +#define RESET_PWM_AO_GH 131 +#define RESET_PWM_AB 132 +#define RESET_PWM_CD 133 +#define RESET_PWM_EF 134 +/* 135-137 */ +#define RESET_UART_A 138 +#define RESET_UART_B 139 +#define RESET_UART_C 140 +#define RESET_UART_D 141 +#define RESET_UART_E 142 +#define RESET_UART_F 143 +#define RESET_I2C_S_A 144 +#define RESET_I2C_M_A 145 +#define RESET_I2C_M_B 146 +#define RESET_I2C_M_C 147 +#define RESET_I2C_M_D 148 +#define RESET_I2C_M_E 149 +#define RESET_I2C_M_F 150 +#define RESET_I2C_M_AO_A 151 +#define RESET_SD_EMMC_A 152 +#define RESET_SD_EMMC_B 153 +#define RESET_SD_EMMC_C 154 +#define RESET_I2C_M_AO_B 155 +#define RESET_TS_GPU 156 +#define RESET_TS_NNA 157 +#define RESET_TS_VPN 158 +#define RESET_TS_HEVC 159 + +/* RESET5 */ +#define RESET_BRG_NOC_DDR_1 160 +#define RESET_BRG_NOC_DDR_0 161 +#define RESET_BRG_NOC_MAIN 162 +#define RESET_BRG_NOC_ALL 163 +/* 164-167 */ +#define RESET_BRG_NIC2_SYS 168 +#define RESET_BRG_NIC2_MAIN 169 +#define RESET_BRG_NIC2_HDMI 170 +#define RESET_BRG_NIC2_ALL 171 +#define RESET_BRG_NIC3_WAVE 172 +#define RESET_BRG_NIC3_VDEC 173 +#define RESET_BRG_NIC3_HEVCF 174 +#define RESET_BRG_NIC3_HEVCB 175 +#define RESET_BRG_NIC3_HCODEC 176 +#define RESET_BRG_NIC3_GE2D 177 +#define RESET_BRG_NIC3_GDC 178 +#define RESET_BRG_NIC3_AMLOGIC 179 +#define RESET_BRG_NIC3_MAIN 180 +#define RESET_BRG_NIC3_ALL 181 +#define RESET_BRG_NIC5_VPU 182 +/* 183-185 */ +#define RESET_BRG_NIC4_DSPB 186 +#define RESET_BRG_NIC4_DSPA 187 +#define RESET_BRG_NIC4_VAPB 188 +#define RESET_BRG_NIC4_CLK81 189 +#define RESET_BRG_NIC4_MAIN 190 +#define RESET_BRG_NIC4_ALL 191 + +/* RESET6 */ +#define RESET_BRG_VDEC_PIPEL 192 +#define RESET_BRG_HEVCF_DMC_PIPEL 193 +#define RESET_BRG_NIC2TONIC4_PIPEL 194 +#define RESET_BRG_HDMIRXTONIC2_PIPEL 195 +#define RESET_BRG_SECTONIC4_PIPEL 196 +#define RESET_BRG_VPUTONOC_PIPEL 197 +#define RESET_BRG_NIC4TONOC_PIPEL 198 +#define RESET_BRG_NIC3TONOC_PIPEL 199 +#define RESET_BRG_NIC2TONOC_PIPEL 200 +#define RESET_BRG_NNATONOC_PIPEL 201 +#define RESET_BRG_FRISP3_PIPEL 202 +#define RESET_BRG_FRISP2_PIPEL 203 +#define RESET_BRG_FRISP1_PIPEL 204 +#define RESET_BRG_FRISP0_PIPEL 205 +/* 206-217 */ +#define RESET_BRG_AMPIPE_NAND 218 +#define RESET_BRG_AMPIPE_ETH 219 +/* 220 */ +#define RESET_BRG_AM2AXI0 221 +#define RESET_BRG_AM2AXI1 222 +#define RESET_BRG_AM2AXI2 223 + +#endif /* ___DTS_AMLOGIC_T7_RESET_H */ diff --git a/arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi b/arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi index 5248bdf824ea..c23efc6c7ac0 100644 --- a/arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi +++ b/arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi @@ -5,6 +5,7 @@ #include #include +#include "amlogic-t7-reset.h" / { interrupt-parent = <&gic>; @@ -149,6 +150,12 @@ #size-cells = <2>; ranges = <0x0 0x0 0x0 0xfe000000 0x0 0x480000>; + reset: reset-controller@2000 { + compatible = "amlogic,t7-reset"; + reg = <0x0 0x2000 0x0 0x98>; + #reset-cells = <1>; + }; + watchdog@2100 { compatible = "amlogic,t7-wdt"; reg = <0x0 0x2100 0x0 0x10>; -- cgit v1.2.3-59-g8ed1b From b29781afaed29d5e41557231c46abd25bdc8d0c4 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 13 Sep 2023 08:50:10 -0300 Subject: tools arch x86: Sync the msr-index.h copy with the kernel sources To pick up the changes from these csets: be482ff9500999f5 ("x86/bhi: Enumerate Branch History Injection (BHI) bug") 0f4a837615ff925b ("x86/bhi: Define SPEC_CTRL_BHI_DIS_S") That cause no changes to tooling: $ tools/perf/trace/beauty/tracepoints/x86_msr.sh > x86_msr.before $ objdump -dS /tmp/build/perf-tools-next/util/amd-sample-raw.o > amd-sample-raw.o.before $ cp arch/x86/include/asm/msr-index.h tools/arch/x86/include/asm/msr-index.h $ make -C tools/perf O=/tmp/build/perf-tools-next CC /tmp/build/perf-tools-next/trace/beauty/tracepoints/x86_msr.o CC /tmp/build/perf-tools-next/util/amd-sample-raw.o $ objdump -dS /tmp/build/perf-tools-next/util/amd-sample-raw.o > amd-sample-raw.o.after $ tools/perf/trace/beauty/tracepoints/x86_msr.sh > x86_msr.after $ diff -u x86_msr.before x86_msr.after $ diff -u amd-sample-raw.o.before amd-sample-raw.o.after Just silences this perf build warning: Warning: Kernel ABI header differences: diff -u tools/arch/x86/include/asm/msr-index.h arch/x86/include/asm/msr-index.h Cc: Adrian Hunter Cc: Daniel Sneddon Cc: Ian Rogers Cc: Jiri Olsa Cc: Kan Liang Cc: Namhyung Kim Cc: Pawan Gupta Cc: Thomas Gleixner Link: https://lore.kernel.org/lkml/ZifCnEZFx5MZQuIW@x1 Signed-off-by: Arnaldo Carvalho de Melo --- tools/arch/x86/include/asm/msr-index.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tools/arch/x86/include/asm/msr-index.h b/tools/arch/x86/include/asm/msr-index.h index 05956bd8bacf..e72c2b872957 100644 --- a/tools/arch/x86/include/asm/msr-index.h +++ b/tools/arch/x86/include/asm/msr-index.h @@ -61,10 +61,13 @@ #define SPEC_CTRL_SSBD BIT(SPEC_CTRL_SSBD_SHIFT) /* Speculative Store Bypass Disable */ #define SPEC_CTRL_RRSBA_DIS_S_SHIFT 6 /* Disable RRSBA behavior */ #define SPEC_CTRL_RRSBA_DIS_S BIT(SPEC_CTRL_RRSBA_DIS_S_SHIFT) +#define SPEC_CTRL_BHI_DIS_S_SHIFT 10 /* Disable Branch History Injection behavior */ +#define SPEC_CTRL_BHI_DIS_S BIT(SPEC_CTRL_BHI_DIS_S_SHIFT) /* A mask for bits which the kernel toggles when controlling mitigations */ #define SPEC_CTRL_MITIGATIONS_MASK (SPEC_CTRL_IBRS | SPEC_CTRL_STIBP | SPEC_CTRL_SSBD \ - | SPEC_CTRL_RRSBA_DIS_S) + | SPEC_CTRL_RRSBA_DIS_S \ + | SPEC_CTRL_BHI_DIS_S) #define MSR_IA32_PRED_CMD 0x00000049 /* Prediction Command */ #define PRED_CMD_IBPB BIT(0) /* Indirect Branch Prediction Barrier */ @@ -163,6 +166,10 @@ * are restricted to targets in * kernel. */ +#define ARCH_CAP_BHI_NO BIT(20) /* + * CPU is not affected by Branch + * History Injection. + */ #define ARCH_CAP_PBRSB_NO BIT(24) /* * Not susceptible to Post-Barrier * Return Stack Buffer Predictions. -- cgit v1.2.3-59-g8ed1b From 084c22964c08752b03cb9d3957265c66e1baf1dc Mon Sep 17 00:00:00 2001 From: Tanmay Shah Date: Tue, 23 Apr 2024 10:02:11 -0700 Subject: drivers: remoteproc: xlnx: Fix uninitialized variable use Fix following warning for clang compiler with W=1 option: initialize the variable 'ret' to silence this warning 907 | int ret, i; | ^ | = 0 Fixes: a6b974b40f94 ("drivers: remoteproc: xlnx: Add Versal and Versal-NET support") Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202404231839.oHiY9Lw8-lkp@intel.com/ Signed-off-by: Tanmay Shah Link: https://lore.kernel.org/r/20240423170210.1035957-1-tanmay.shah@amd.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/xlnx_r5_remoteproc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/remoteproc/xlnx_r5_remoteproc.c b/drivers/remoteproc/xlnx_r5_remoteproc.c index a6d8ac7394e7..d98940d7ef8f 100644 --- a/drivers/remoteproc/xlnx_r5_remoteproc.c +++ b/drivers/remoteproc/xlnx_r5_remoteproc.c @@ -904,7 +904,7 @@ static int zynqmp_r5_core_init(struct zynqmp_r5_cluster *cluster, { struct device *dev = cluster->dev; struct zynqmp_r5_core *r5_core; - int ret, i; + int ret = -EINVAL, i; r5_core = cluster->r5_cores[0]; -- cgit v1.2.3-59-g8ed1b From 06fe8fd6808562971637c6b133c806bcf49097ad Mon Sep 17 00:00:00 2001 From: Nipun Gupta Date: Tue, 23 Apr 2024 16:40:20 +0530 Subject: genirq/msi: Add MSI allocation helper and export MSI functions MSI functions for allocation and free can be directly used by the device drivers without any wrapper provided by bus drivers. So export these MSI functions. Also, add a wrapper API to allocate MSIs providing only the number of interrupts rather than range for simpler driver usage. Signed-off-by: Nipun Gupta Reviewed-by: Thomas Gleixner Link: https://lore.kernel.org/r/20240423111021.1686144-1-nipun.gupta@amd.com Signed-off-by: Alex Williamson --- include/linux/msi.h | 6 ++++++ kernel/irq/msi.c | 2 ++ 2 files changed, 8 insertions(+) diff --git a/include/linux/msi.h b/include/linux/msi.h index 26d07e23052e..765a65581a66 100644 --- a/include/linux/msi.h +++ b/include/linux/msi.h @@ -676,6 +676,12 @@ int platform_device_msi_init_and_alloc_irqs(struct device *dev, unsigned int nve void platform_device_msi_free_irqs_all(struct device *dev); bool msi_device_has_isolated_msi(struct device *dev); + +static inline int msi_domain_alloc_irqs(struct device *dev, unsigned int domid, int nirqs) +{ + return msi_domain_alloc_irqs_range(dev, domid, 0, nirqs - 1); +} + #else /* CONFIG_GENERIC_MSI_IRQ */ static inline bool msi_device_has_isolated_msi(struct device *dev) { diff --git a/kernel/irq/msi.c b/kernel/irq/msi.c index f90952ebc494..2024f89baea4 100644 --- a/kernel/irq/msi.c +++ b/kernel/irq/msi.c @@ -1434,6 +1434,7 @@ int msi_domain_alloc_irqs_range(struct device *dev, unsigned int domid, msi_unlock_descs(dev); return ret; } +EXPORT_SYMBOL_GPL(msi_domain_alloc_irqs_range); /** * msi_domain_alloc_irqs_all_locked - Allocate all interrupts from a MSI interrupt domain @@ -1680,6 +1681,7 @@ void msi_domain_free_irqs_range(struct device *dev, unsigned int domid, msi_domain_free_irqs_range_locked(dev, domid, first, last); msi_unlock_descs(dev); } +EXPORT_SYMBOL_GPL(msi_domain_free_irqs_all); /** * msi_domain_free_irqs_all_locked - Free all interrupts from a MSI interrupt domain -- cgit v1.2.3-59-g8ed1b From 848e447e000c41894ff931dc7c004fd42c8840f8 Mon Sep 17 00:00:00 2001 From: Nipun Gupta Date: Tue, 23 Apr 2024 16:40:21 +0530 Subject: vfio/cdx: add interrupt support Support the following ioctls for CDX devices: - VFIO_DEVICE_GET_IRQ_INFO - VFIO_DEVICE_SET_IRQS This allows user to set an eventfd for cdx device interrupts and trigger this interrupt eventfd from userspace. All CDX device interrupts are MSIs. The MSIs are allocated from the CDX-MSI domain. Signed-off-by: Nipun Gupta Reviewed-by: Pieter Jansen van Vuuren Link: https://lore.kernel.org/r/20240423111021.1686144-2-nipun.gupta@amd.com Signed-off-by: Alex Williamson --- drivers/vfio/cdx/Makefile | 2 +- drivers/vfio/cdx/intr.c | 217 +++++++++++++++++++++++++++++++++++++++++++++ drivers/vfio/cdx/main.c | 63 ++++++++++++- drivers/vfio/cdx/private.h | 18 ++++ 4 files changed, 298 insertions(+), 2 deletions(-) create mode 100644 drivers/vfio/cdx/intr.c diff --git a/drivers/vfio/cdx/Makefile b/drivers/vfio/cdx/Makefile index cd4a2e6fe609..df92b320122a 100644 --- a/drivers/vfio/cdx/Makefile +++ b/drivers/vfio/cdx/Makefile @@ -5,4 +5,4 @@ obj-$(CONFIG_VFIO_CDX) += vfio-cdx.o -vfio-cdx-objs := main.o +vfio-cdx-objs := main.o intr.o diff --git a/drivers/vfio/cdx/intr.c b/drivers/vfio/cdx/intr.c new file mode 100644 index 000000000000..986fa2a45fa4 --- /dev/null +++ b/drivers/vfio/cdx/intr.c @@ -0,0 +1,217 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2022-2023, Advanced Micro Devices, Inc. + */ + +#include +#include +#include +#include +#include +#include + +#include "linux/cdx/cdx_bus.h" +#include "private.h" + +static irqreturn_t vfio_cdx_msihandler(int irq_no, void *arg) +{ + struct eventfd_ctx *trigger = arg; + + eventfd_signal(trigger); + return IRQ_HANDLED; +} + +static int vfio_cdx_msi_enable(struct vfio_cdx_device *vdev, int nvec) +{ + struct cdx_device *cdx_dev = to_cdx_device(vdev->vdev.dev); + struct device *dev = vdev->vdev.dev; + int msi_idx, ret; + + vdev->cdx_irqs = kcalloc(nvec, sizeof(struct vfio_cdx_irq), GFP_KERNEL); + if (!vdev->cdx_irqs) + return -ENOMEM; + + ret = cdx_enable_msi(cdx_dev); + if (ret) { + kfree(vdev->cdx_irqs); + return ret; + } + + /* Allocate cdx MSIs */ + ret = msi_domain_alloc_irqs(dev, MSI_DEFAULT_DOMAIN, nvec); + if (ret) { + cdx_disable_msi(cdx_dev); + kfree(vdev->cdx_irqs); + return ret; + } + + for (msi_idx = 0; msi_idx < nvec; msi_idx++) + vdev->cdx_irqs[msi_idx].irq_no = msi_get_virq(dev, msi_idx); + + vdev->msi_count = nvec; + vdev->config_msi = 1; + + return 0; +} + +static int vfio_cdx_msi_set_vector_signal(struct vfio_cdx_device *vdev, + int vector, int fd) +{ + struct eventfd_ctx *trigger; + int irq_no, ret; + + if (vector < 0 || vector >= vdev->msi_count) + return -EINVAL; + + irq_no = vdev->cdx_irqs[vector].irq_no; + + if (vdev->cdx_irqs[vector].trigger) { + free_irq(irq_no, vdev->cdx_irqs[vector].trigger); + kfree(vdev->cdx_irqs[vector].name); + eventfd_ctx_put(vdev->cdx_irqs[vector].trigger); + vdev->cdx_irqs[vector].trigger = NULL; + } + + if (fd < 0) + return 0; + + vdev->cdx_irqs[vector].name = kasprintf(GFP_KERNEL, "vfio-msi[%d](%s)", + vector, dev_name(vdev->vdev.dev)); + if (!vdev->cdx_irqs[vector].name) + return -ENOMEM; + + trigger = eventfd_ctx_fdget(fd); + if (IS_ERR(trigger)) { + kfree(vdev->cdx_irqs[vector].name); + return PTR_ERR(trigger); + } + + ret = request_irq(irq_no, vfio_cdx_msihandler, 0, + vdev->cdx_irqs[vector].name, trigger); + if (ret) { + kfree(vdev->cdx_irqs[vector].name); + eventfd_ctx_put(trigger); + return ret; + } + + vdev->cdx_irqs[vector].trigger = trigger; + + return 0; +} + +static int vfio_cdx_msi_set_block(struct vfio_cdx_device *vdev, + unsigned int start, unsigned int count, + int32_t *fds) +{ + int i, j, ret = 0; + + if (start >= vdev->msi_count || start + count > vdev->msi_count) + return -EINVAL; + + for (i = 0, j = start; i < count && !ret; i++, j++) { + int fd = fds ? fds[i] : -1; + + ret = vfio_cdx_msi_set_vector_signal(vdev, j, fd); + } + + if (ret) { + for (--j; j >= (int)start; j--) + vfio_cdx_msi_set_vector_signal(vdev, j, -1); + } + + return ret; +} + +static void vfio_cdx_msi_disable(struct vfio_cdx_device *vdev) +{ + struct cdx_device *cdx_dev = to_cdx_device(vdev->vdev.dev); + struct device *dev = vdev->vdev.dev; + + vfio_cdx_msi_set_block(vdev, 0, vdev->msi_count, NULL); + + if (!vdev->config_msi) + return; + + msi_domain_free_irqs_all(dev, MSI_DEFAULT_DOMAIN); + cdx_disable_msi(cdx_dev); + kfree(vdev->cdx_irqs); + + vdev->cdx_irqs = NULL; + vdev->msi_count = 0; + vdev->config_msi = 0; +} + +static int vfio_cdx_set_msi_trigger(struct vfio_cdx_device *vdev, + unsigned int index, unsigned int start, + unsigned int count, u32 flags, + void *data) +{ + struct cdx_device *cdx_dev = to_cdx_device(vdev->vdev.dev); + int i; + + if (start + count > cdx_dev->num_msi) + return -EINVAL; + + if (!count && (flags & VFIO_IRQ_SET_DATA_NONE)) { + vfio_cdx_msi_disable(vdev); + return 0; + } + + if (flags & VFIO_IRQ_SET_DATA_EVENTFD) { + s32 *fds = data; + int ret; + + if (vdev->config_msi) + return vfio_cdx_msi_set_block(vdev, start, count, + fds); + ret = vfio_cdx_msi_enable(vdev, cdx_dev->num_msi); + if (ret) + return ret; + + ret = vfio_cdx_msi_set_block(vdev, start, count, fds); + if (ret) + vfio_cdx_msi_disable(vdev); + + return ret; + } + + for (i = start; i < start + count; i++) { + if (!vdev->cdx_irqs[i].trigger) + continue; + if (flags & VFIO_IRQ_SET_DATA_NONE) { + eventfd_signal(vdev->cdx_irqs[i].trigger); + } else if (flags & VFIO_IRQ_SET_DATA_BOOL) { + u8 *bools = data; + + if (bools[i - start]) + eventfd_signal(vdev->cdx_irqs[i].trigger); + } + } + + return 0; +} + +int vfio_cdx_set_irqs_ioctl(struct vfio_cdx_device *vdev, + u32 flags, unsigned int index, + unsigned int start, unsigned int count, + void *data) +{ + if (flags & VFIO_IRQ_SET_ACTION_TRIGGER) + return vfio_cdx_set_msi_trigger(vdev, index, start, + count, flags, data); + else + return -EINVAL; +} + +/* Free All IRQs for the given device */ +void vfio_cdx_irqs_cleanup(struct vfio_cdx_device *vdev) +{ + /* + * Device does not support any interrupt or the interrupts + * were not configured + */ + if (!vdev->cdx_irqs) + return; + + vfio_cdx_set_msi_trigger(vdev, 0, 0, 0, VFIO_IRQ_SET_DATA_NONE, NULL); +} diff --git a/drivers/vfio/cdx/main.c b/drivers/vfio/cdx/main.c index 9cff8d75789e..67465fad5b4b 100644 --- a/drivers/vfio/cdx/main.c +++ b/drivers/vfio/cdx/main.c @@ -61,6 +61,7 @@ static void vfio_cdx_close_device(struct vfio_device *core_vdev) kfree(vdev->regions); cdx_dev_reset(core_vdev->dev); + vfio_cdx_irqs_cleanup(vdev); } static int vfio_cdx_bm_ctrl(struct vfio_device *core_vdev, u32 flags, @@ -123,7 +124,7 @@ static int vfio_cdx_ioctl_get_info(struct vfio_cdx_device *vdev, info.flags |= VFIO_DEVICE_FLAGS_RESET; info.num_regions = cdx_dev->res_count; - info.num_irqs = 0; + info.num_irqs = cdx_dev->num_msi ? 1 : 0; return copy_to_user(arg, &info, minsz) ? -EFAULT : 0; } @@ -152,6 +153,62 @@ static int vfio_cdx_ioctl_get_region_info(struct vfio_cdx_device *vdev, return copy_to_user(arg, &info, minsz) ? -EFAULT : 0; } +static int vfio_cdx_ioctl_get_irq_info(struct vfio_cdx_device *vdev, + struct vfio_irq_info __user *arg) +{ + unsigned long minsz = offsetofend(struct vfio_irq_info, count); + struct cdx_device *cdx_dev = to_cdx_device(vdev->vdev.dev); + struct vfio_irq_info info; + + if (copy_from_user(&info, arg, minsz)) + return -EFAULT; + + if (info.argsz < minsz) + return -EINVAL; + + if (info.index >= 1) + return -EINVAL; + + if (!cdx_dev->num_msi) + return -EINVAL; + + info.flags = VFIO_IRQ_INFO_EVENTFD | VFIO_IRQ_INFO_NORESIZE; + info.count = cdx_dev->num_msi; + + return copy_to_user(arg, &info, minsz) ? -EFAULT : 0; +} + +static int vfio_cdx_ioctl_set_irqs(struct vfio_cdx_device *vdev, + struct vfio_irq_set __user *arg) +{ + unsigned long minsz = offsetofend(struct vfio_irq_set, count); + struct cdx_device *cdx_dev = to_cdx_device(vdev->vdev.dev); + struct vfio_irq_set hdr; + size_t data_size = 0; + u8 *data = NULL; + int ret = 0; + + if (copy_from_user(&hdr, arg, minsz)) + return -EFAULT; + + ret = vfio_set_irqs_validate_and_prepare(&hdr, cdx_dev->num_msi, + 1, &data_size); + if (ret) + return ret; + + if (data_size) { + data = memdup_user(arg->data, data_size); + if (IS_ERR(data)) + return PTR_ERR(data); + } + + ret = vfio_cdx_set_irqs_ioctl(vdev, hdr.flags, hdr.index, + hdr.start, hdr.count, data); + kfree(data); + + return ret; +} + static long vfio_cdx_ioctl(struct vfio_device *core_vdev, unsigned int cmd, unsigned long arg) { @@ -164,6 +221,10 @@ static long vfio_cdx_ioctl(struct vfio_device *core_vdev, return vfio_cdx_ioctl_get_info(vdev, uarg); case VFIO_DEVICE_GET_REGION_INFO: return vfio_cdx_ioctl_get_region_info(vdev, uarg); + case VFIO_DEVICE_GET_IRQ_INFO: + return vfio_cdx_ioctl_get_irq_info(vdev, uarg); + case VFIO_DEVICE_SET_IRQS: + return vfio_cdx_ioctl_set_irqs(vdev, uarg); case VFIO_DEVICE_RESET: return cdx_dev_reset(core_vdev->dev); default: diff --git a/drivers/vfio/cdx/private.h b/drivers/vfio/cdx/private.h index 8e9d25913728..dc56729b3114 100644 --- a/drivers/vfio/cdx/private.h +++ b/drivers/vfio/cdx/private.h @@ -13,6 +13,14 @@ static inline u64 vfio_cdx_index_to_offset(u32 index) return ((u64)(index) << VFIO_CDX_OFFSET_SHIFT); } +struct vfio_cdx_irq { + u32 flags; + u32 count; + int irq_no; + struct eventfd_ctx *trigger; + char *name; +}; + struct vfio_cdx_region { u32 flags; u32 type; @@ -23,8 +31,18 @@ struct vfio_cdx_region { struct vfio_cdx_device { struct vfio_device vdev; struct vfio_cdx_region *regions; + struct vfio_cdx_irq *cdx_irqs; u32 flags; #define BME_SUPPORT BIT(0) + u32 msi_count; + u8 config_msi; }; +int vfio_cdx_set_irqs_ioctl(struct vfio_cdx_device *vdev, + u32 flags, unsigned int index, + unsigned int start, unsigned int count, + void *data); + +void vfio_cdx_irqs_cleanup(struct vfio_cdx_device *vdev); + #endif /* VFIO_CDX_PRIVATE_H */ -- cgit v1.2.3-59-g8ed1b From 7bf9d2af7e89f65a79225e26d261b52ce4ee3e95 Mon Sep 17 00:00:00 2001 From: Vidya Sagar Date: Tue, 16 Jan 2024 20:02:58 +0530 Subject: PCI: Clear Secondary Status errors after enumeration We enumerate devices by attempting config reads to the Vendor ID of each possible device. On conventional PCI, if no device responds, the read terminates with a Master Abort (PCI r3.0, sec 6.1). On PCIe, the config read is terminated as an Unsupported Request (PCIe r6.0, sec 2.3.2, 7.5.1.3.7). In either case, if the read addressed a device below a bridge, it is logged by setting "Received Master Abort" in the bridge Secondary Status register. Clear any errors logged in the Secondary Status register after enumeration. Link: https://lore.kernel.org/r/20240116143258.483235-1-vidyas@nvidia.com Signed-off-by: Vidya Sagar [bhelgaas: simplify commit log] Signed-off-by: Bjorn Helgaas --- drivers/pci/probe.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 1325fbae2f28..df5171b912e0 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -1482,6 +1482,9 @@ static int pci_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev, } out: + /* Clear errors in the Secondary Status Register */ + pci_write_config_word(dev, PCI_SEC_STATUS, 0xffff); + pci_write_config_word(dev, PCI_BRIDGE_CONTROL, bctl); pm_runtime_put(&dev->dev); -- cgit v1.2.3-59-g8ed1b From 14e37bff3da781ba271bd8d2a76e40713b8a69ec Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Thu, 18 Apr 2024 09:38:35 +0300 Subject: dt-bindings: usb: qcom,pmic-typec: update example to follow connector schema Update Qualcomm PMIC Type-C examples to follow the USB-C connector schema. The USB-C connector should have three ports (USB HS @0, SSTX/RX @1 and SBU @2 lanes). Reorder ports accordingly and add SBU port connected to the SBU mux (e.g. FSA4480). Reported-by: Luca Weiss Acked-by: Konrad Dybcio Signed-off-by: Dmitry Baryshkov Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240418-typec-fix-example-v3-1-08f649b6f368@linaro.org Signed-off-by: Greg Kroah-Hartman --- .../devicetree/bindings/usb/qcom,pmic-typec.yaml | 34 +++++++++++++++++----- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/Documentation/devicetree/bindings/usb/qcom,pmic-typec.yaml b/Documentation/devicetree/bindings/usb/qcom,pmic-typec.yaml index 0cdc60b76fbd..6d3ef364672e 100644 --- a/Documentation/devicetree/bindings/usb/qcom,pmic-typec.yaml +++ b/Documentation/devicetree/bindings/usb/qcom,pmic-typec.yaml @@ -193,15 +193,22 @@ examples: port@0 { reg = <0>; - pmic_typec_mux_out: endpoint { - remote-endpoint = <&usb_phy_typec_mux_in>; + pmic_typec_hs_in: endpoint { + remote-endpoint = <&usb_hs_out>; }; }; port@1 { reg = <1>; - pmic_typec_role_switch_out: endpoint { - remote-endpoint = <&usb_role_switch_in>; + pmic_typec_ss_in: endpoint { + remote-endpoint = <&usb_phy_typec_ss_out>; + }; + }; + + port@2 { + reg = <2>; + pmic_typec_sbu: endpoint { + remote-endpoint = <&usb_mux_sbu>; }; }; }; @@ -213,8 +220,8 @@ examples: dr_mode = "otg"; usb-role-switch; port { - usb_role_switch_in: endpoint { - remote-endpoint = <&pmic_typec_role_switch_out>; + usb_hs_out: endpoint { + remote-endpoint = <&pmic_typec_hs_in>; }; }; }; @@ -222,8 +229,19 @@ examples: usb-phy { orientation-switch; port { - usb_phy_typec_mux_in: endpoint { - remote-endpoint = <&pmic_typec_mux_out>; + usb_phy_typec_ss_out: endpoint { + remote-endpoint = <&pmic_typec_ss_in>; + }; + }; + }; + + usb-mux { + orientation-switch; + mode-switch; + + port { + usb_mux_sbu: endpoint { + remote-endpoint = <&pmic_typec_sbu>; }; }; }; -- cgit v1.2.3-59-g8ed1b From c859d300c5697ac8929a1c860f78e51c7bacf72d Mon Sep 17 00:00:00 2001 From: Mohammad Shehar Yaar Tausif Date: Tue, 23 Apr 2024 20:35:48 +0530 Subject: dt-bindings: usb: uhci: convert to dt schema Convert USB UHCI bindings to DT schema. Documenting aspeed compatibles and missing properties. Adding aspeed/generic-uhci example and fixing nodename for the original example. Signed-off-by: Mohammad Shehar Yaar Tausif Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240423150550.91055-1-sheharyaar48@gmail.com Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/usb/usb-uhci.txt | 18 ------ .../devicetree/bindings/usb/usb-uhci.yaml | 75 ++++++++++++++++++++++ 2 files changed, 75 insertions(+), 18 deletions(-) delete mode 100644 Documentation/devicetree/bindings/usb/usb-uhci.txt create mode 100644 Documentation/devicetree/bindings/usb/usb-uhci.yaml diff --git a/Documentation/devicetree/bindings/usb/usb-uhci.txt b/Documentation/devicetree/bindings/usb/usb-uhci.txt deleted file mode 100644 index d1702eb2c8bd..000000000000 --- a/Documentation/devicetree/bindings/usb/usb-uhci.txt +++ /dev/null @@ -1,18 +0,0 @@ -Generic Platform UHCI Controller ------------------------------------------------------ - -Required properties: -- compatible : "generic-uhci" (deprecated: "platform-uhci") -- reg : Should contain 1 register ranges(address and length) -- interrupts : UHCI controller interrupt - -additionally the properties from usb-hcd.yaml (in the current directory) are -supported. - -Example: - - uhci@d8007b00 { - compatible = "generic-uhci"; - reg = <0xd8007b00 0x200>; - interrupts = <43>; - }; diff --git a/Documentation/devicetree/bindings/usb/usb-uhci.yaml b/Documentation/devicetree/bindings/usb/usb-uhci.yaml new file mode 100644 index 000000000000..d8336f72dc1f --- /dev/null +++ b/Documentation/devicetree/bindings/usb/usb-uhci.yaml @@ -0,0 +1,75 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/usb/usb-uhci.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Generic Platform UHCI Controller + +maintainers: + - Greg Kroah-Hartman + +properties: + compatible: + oneOf: + - const: generic-uhci + - const: platform-uhci + deprecated: true + - items: + - enum: + - aspeed,ast2400-uhci + - aspeed,ast2500-uhci + - aspeed,ast2600-uhci + - const: generic-uhci + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + '#ports': + $ref: /schemas/types.yaml#/definitions/uint32 + + clocks: + maxItems: 1 + +required: + - compatible + - reg + - interrupts + +allOf: + - $ref: usb-hcd.yaml + - if: + properties: + compatible: + contains: + const: generic-uhci + then: + required: + - clocks + +unevaluatedProperties: false + +examples: + - | + #include + + usb@d8007b00 { + compatible = "generic-uhci"; + reg = <0xd8007b00 0x200>; + interrupts = <43>; + clocks = <&syscon ASPEED_CLK_GATE_USBUHCICLK>; + }; + - | + #include + + usb@1e6b0000 { + compatible = "aspeed,ast2500-uhci", "generic-uhci"; + reg = <0x1e6b0000 0x100>; + interrupts = <14>; + #ports = <2>; + clocks = <&syscon ASPEED_CLK_GATE_USBUHCICLK>; + }; +... -- cgit v1.2.3-59-g8ed1b From 9cea6c1f54157fa64f7bbdfd236db281fce3e446 Mon Sep 17 00:00:00 2001 From: Krishna Kurapati Date: Sat, 20 Apr 2024 10:18:53 +0530 Subject: dt-bindings: usb: Add bindings for multiport properties on DWC3 controller Add bindings to indicate properties required to support multiport on Synopsys DWC3 controller. Signed-off-by: Krishna Kurapati Reviewed-by: Bjorn Andersson Reviewed-by: Johan Hovold Reviewed-by: Krzysztof Kozlowski Tested-by: Johan Hovold Link: https://lore.kernel.org/r/20240420044901.884098-2-quic_kriskura@quicinc.com Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/usb/snps,dwc3.yaml | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/Documentation/devicetree/bindings/usb/snps,dwc3.yaml b/Documentation/devicetree/bindings/usb/snps,dwc3.yaml index 203a1eb66691..1cd0ca90127d 100644 --- a/Documentation/devicetree/bindings/usb/snps,dwc3.yaml +++ b/Documentation/devicetree/bindings/usb/snps,dwc3.yaml @@ -85,15 +85,16 @@ properties: phys: minItems: 1 - maxItems: 2 + maxItems: 19 phy-names: minItems: 1 - maxItems: 2 - items: - enum: - - usb2-phy - - usb3-phy + maxItems: 19 + oneOf: + - items: + enum: [ usb2-phy, usb3-phy ] + - items: + pattern: "^usb(2-([0-9]|1[0-4])|3-[0-3])$" power-domains: description: -- cgit v1.2.3-59-g8ed1b From 921e109c6200741499ad0136e41cca9d16431c92 Mon Sep 17 00:00:00 2001 From: Krishna Kurapati Date: Sat, 20 Apr 2024 10:18:54 +0530 Subject: usb: dwc3: core: Access XHCI address space temporarily to read port info All DWC3 Multi Port controllers that exist today only support host mode. Temporarily map XHCI address space for host-only controllers and parse XHCI Extended Capabilities registers to read number of usb2 ports and usb3 ports present on multiport controller. Each USB Port is at least HS capable. The port info for usb2 and usb3 phy are identified as num_usb2_ports and num_usb3_ports and these are used as iterators for phy operations and for modifying GUSB2PHYCFG/ GUSB3PIPECTL registers accordingly. Signed-off-by: Krishna Kurapati Reviewed-by: Bjorn Andersson Acked-by: Thinh Nguyen Reviewed-by: Johan Hovold Tested-by: Johan Hovold Link: https://lore.kernel.org/r/20240420044901.884098-3-quic_kriskura@quicinc.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/core.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++++ drivers/usb/dwc3/core.h | 5 ++++ 2 files changed, 66 insertions(+) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 637194af506f..38fcf530332f 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -39,6 +39,7 @@ #include "io.h" #include "debug.h" +#include "../host/xhci-ext-caps.h" #define DWC3_DEFAULT_AUTOSUSPEND_DELAY 5000 /* ms */ @@ -1884,10 +1885,56 @@ static int dwc3_get_clocks(struct dwc3 *dwc) return 0; } +static int dwc3_get_num_ports(struct dwc3 *dwc) +{ + void __iomem *base; + u8 major_revision; + u32 offset; + u32 val; + + /* + * Remap xHCI address space to access XHCI ext cap regs since it is + * needed to get information on number of ports present. + */ + base = ioremap(dwc->xhci_resources[0].start, + resource_size(&dwc->xhci_resources[0])); + if (!base) + return -ENOMEM; + + offset = 0; + do { + offset = xhci_find_next_ext_cap(base, offset, + XHCI_EXT_CAPS_PROTOCOL); + if (!offset) + break; + + val = readl(base + offset); + major_revision = XHCI_EXT_PORT_MAJOR(val); + + val = readl(base + offset + 0x08); + if (major_revision == 0x03) { + dwc->num_usb3_ports += XHCI_EXT_PORT_COUNT(val); + } else if (major_revision <= 0x02) { + dwc->num_usb2_ports += XHCI_EXT_PORT_COUNT(val); + } else { + dev_warn(dwc->dev, "unrecognized port major revision %d\n", + major_revision); + } + } while (1); + + dev_dbg(dwc->dev, "hs-ports: %u ss-ports: %u\n", + dwc->num_usb2_ports, dwc->num_usb3_ports); + + iounmap(base); + + return 0; +} + static int dwc3_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct resource *res, dwc_res; + unsigned int hw_mode; void __iomem *regs; struct dwc3 *dwc; int ret; @@ -1971,6 +2018,20 @@ static int dwc3_probe(struct platform_device *pdev) goto err_disable_clks; } + /* + * Currently only DWC3 controllers that are host-only capable + * can have more than one port. + */ + hw_mode = DWC3_GHWPARAMS0_MODE(dwc->hwparams.hwparams0); + if (hw_mode == DWC3_GHWPARAMS0_MODE_HOST) { + ret = dwc3_get_num_ports(dwc); + if (ret) + goto err_disable_clks; + } else { + dwc->num_usb2_ports = 1; + dwc->num_usb3_ports = 1; + } + spin_lock_init(&dwc->lock); mutex_init(&dwc->mutex); diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 7e80dd3d466b..341e4c73cb2e 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -1039,6 +1039,8 @@ struct dwc3_scratchpad_array { * @usb3_phy: pointer to USB3 PHY * @usb2_generic_phy: pointer to USB2 PHY * @usb3_generic_phy: pointer to USB3 PHY + * @num_usb2_ports: number of USB2 ports + * @num_usb3_ports: number of USB3 ports * @phys_ready: flag to indicate that PHYs are ready * @ulpi: pointer to ulpi interface * @ulpi_ready: flag to indicate that ULPI is initialized @@ -1187,6 +1189,9 @@ struct dwc3 { struct phy *usb2_generic_phy; struct phy *usb3_generic_phy; + u8 num_usb2_ports; + u8 num_usb3_ports; + bool phys_ready; struct ulpi *ulpi; -- cgit v1.2.3-59-g8ed1b From 89d7f962994604a3e3d480832788d06179abefc5 Mon Sep 17 00:00:00 2001 From: Krishna Kurapati Date: Sat, 20 Apr 2024 10:18:55 +0530 Subject: usb: dwc3: core: Skip setting event buffers for host only controllers On some SoC's like SA8295P where the tertiary controller is host-only capable, GEVTADDRHI/LO, GEVTSIZ, GEVTCOUNT registers are not accessible. Trying to access them leads to a crash. For DRD/Peripheral supported controllers, event buffer setup is done again in gadget_pullup. Skip setup or cleanup of event buffers if controller is host-only capable. Suggested-by: Johan Hovold Signed-off-by: Krishna Kurapati Acked-by: Thinh Nguyen Reviewed-by: Johan Hovold Reviewed-by: Bjorn Andersson Tested-by: Johan Hovold Link: https://lore.kernel.org/r/20240420044901.884098-4-quic_kriskura@quicinc.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/core.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 38fcf530332f..733b1e24af54 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -486,6 +486,13 @@ static void dwc3_free_event_buffers(struct dwc3 *dwc) static int dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned int length) { struct dwc3_event_buffer *evt; + unsigned int hw_mode; + + hw_mode = DWC3_GHWPARAMS0_MODE(dwc->hwparams.hwparams0); + if (hw_mode == DWC3_GHWPARAMS0_MODE_HOST) { + dwc->ev_buf = NULL; + return 0; + } evt = dwc3_alloc_one_event_buffer(dwc, length); if (IS_ERR(evt)) { @@ -507,6 +514,9 @@ int dwc3_event_buffers_setup(struct dwc3 *dwc) { struct dwc3_event_buffer *evt; + if (!dwc->ev_buf) + return 0; + evt = dwc->ev_buf; evt->lpos = 0; dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(0), @@ -524,6 +534,9 @@ void dwc3_event_buffers_cleanup(struct dwc3 *dwc) { struct dwc3_event_buffer *evt; + if (!dwc->ev_buf) + return; + evt = dwc->ev_buf; evt->lpos = 0; -- cgit v1.2.3-59-g8ed1b From 30a46746ca5a1ef4dad3ea72be4fd01872f89ac2 Mon Sep 17 00:00:00 2001 From: Krishna Kurapati Date: Sat, 20 Apr 2024 10:18:56 +0530 Subject: usb: dwc3: core: Refactor PHY logic to support Multiport Controller Currently the DWC3 driver supports only single port controller which requires at least one HS PHY and at most one SS PHY. But the DWC3 USB controller can be connected to multiple ports and each port can have their own PHYs. Each port of the multiport controller can either be HS+SS capable or HS only capable Proper quantification of them is required to modify GUSB2PHYCFG and GUSB3PIPECTL registers appropriately. DWC3 multiport controllers are capable to service at most 15 High Speed PHYs and 4 Supser Speed PHYs. Add support for detecting, obtaining and configuring PHYs supported by a multiport controller. Signed-off-by: Krishna Kurapati Reviewed-by: Bjorn Andersson Acked-by: Thinh Nguyen Reviewed-by: Johan Hovold Tested-by: Johan Hovold Link: https://lore.kernel.org/r/20240420044901.884098-5-quic_kriskura@quicinc.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/core.c | 255 ++++++++++++++++++++++++++++++++++-------------- drivers/usb/dwc3/core.h | 15 ++- drivers/usb/dwc3/drd.c | 15 +-- 3 files changed, 201 insertions(+), 84 deletions(-) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 733b1e24af54..4dc6fc79c6d9 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -124,6 +124,7 @@ static void __dwc3_set_mode(struct work_struct *work) int ret; u32 reg; u32 desired_dr_role; + int i; mutex_lock(&dwc->mutex); spin_lock_irqsave(&dwc->lock, flags); @@ -201,8 +202,12 @@ static void __dwc3_set_mode(struct work_struct *work) } else { if (dwc->usb2_phy) otg_set_vbus(dwc->usb2_phy->otg, true); - phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_HOST); - phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_HOST); + + for (i = 0; i < dwc->num_usb2_ports; i++) + phy_set_mode(dwc->usb2_generic_phy[i], PHY_MODE_USB_HOST); + for (i = 0; i < dwc->num_usb3_ports; i++) + phy_set_mode(dwc->usb3_generic_phy[i], PHY_MODE_USB_HOST); + if (dwc->dis_split_quirk) { reg = dwc3_readl(dwc->regs, DWC3_GUCTL3); reg |= DWC3_GUCTL3_SPLITDISABLE; @@ -217,8 +222,8 @@ static void __dwc3_set_mode(struct work_struct *work) if (dwc->usb2_phy) otg_set_vbus(dwc->usb2_phy->otg, false); - phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_DEVICE); - phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_DEVICE); + phy_set_mode(dwc->usb2_generic_phy[0], PHY_MODE_USB_DEVICE); + phy_set_mode(dwc->usb3_generic_phy[0], PHY_MODE_USB_DEVICE); ret = dwc3_gadget_init(dwc); if (ret) @@ -589,22 +594,14 @@ static int dwc3_core_ulpi_init(struct dwc3 *dwc) return ret; } -/** - * dwc3_phy_setup - Configure USB PHY Interface of DWC3 Core - * @dwc: Pointer to our controller context structure - * - * Returns 0 on success. The USB PHY interfaces are configured but not - * initialized. The PHY interfaces and the PHYs get initialized together with - * the core in dwc3_core_init. - */ -static int dwc3_phy_setup(struct dwc3 *dwc) +static int dwc3_ss_phy_setup(struct dwc3 *dwc, int index) { unsigned int hw_mode; u32 reg; hw_mode = DWC3_GHWPARAMS0_MODE(dwc->hwparams.hwparams0); - reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0)); + reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(index)); /* * Make sure UX_EXIT_PX is cleared as that causes issues with some @@ -659,9 +656,19 @@ static int dwc3_phy_setup(struct dwc3 *dwc) if (dwc->dis_del_phy_power_chg_quirk) reg &= ~DWC3_GUSB3PIPECTL_DEPOCHANGE; - dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); + dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(index), reg); + + return 0; +} + +static int dwc3_hs_phy_setup(struct dwc3 *dwc, int index) +{ + unsigned int hw_mode; + u32 reg; - reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); + hw_mode = DWC3_GHWPARAMS0_MODE(dwc->hwparams.hwparams0); + + reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(index)); /* Select the HS PHY interface */ switch (DWC3_GHWPARAMS3_HSPHY_IFC(dwc->hwparams.hwparams3)) { @@ -673,7 +680,7 @@ static int dwc3_phy_setup(struct dwc3 *dwc) } else if (dwc->hsphy_interface && !strncmp(dwc->hsphy_interface, "ulpi", 4)) { reg |= DWC3_GUSB2PHYCFG_ULPI_UTMI; - dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); + dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(index), reg); } else { /* Relying on default value. */ if (!(reg & DWC3_GUSB2PHYCFG_ULPI_UTMI)) @@ -740,7 +747,35 @@ static int dwc3_phy_setup(struct dwc3 *dwc) if (dwc->ulpi_ext_vbus_drv) reg |= DWC3_GUSB2PHYCFG_ULPIEXTVBUSDRV; - dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); + dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(index), reg); + + return 0; +} + +/** + * dwc3_phy_setup - Configure USB PHY Interface of DWC3 Core + * @dwc: Pointer to our controller context structure + * + * Returns 0 on success. The USB PHY interfaces are configured but not + * initialized. The PHY interfaces and the PHYs get initialized together with + * the core in dwc3_core_init. + */ +static int dwc3_phy_setup(struct dwc3 *dwc) +{ + int i; + int ret; + + for (i = 0; i < dwc->num_usb3_ports; i++) { + ret = dwc3_ss_phy_setup(dwc, i); + if (ret) + return ret; + } + + for (i = 0; i < dwc->num_usb2_ports; i++) { + ret = dwc3_hs_phy_setup(dwc, i); + if (ret) + return ret; + } return 0; } @@ -748,23 +783,34 @@ static int dwc3_phy_setup(struct dwc3 *dwc) static int dwc3_phy_init(struct dwc3 *dwc) { int ret; + int i; + int j; usb_phy_init(dwc->usb2_phy); usb_phy_init(dwc->usb3_phy); - ret = phy_init(dwc->usb2_generic_phy); - if (ret < 0) - goto err_shutdown_usb3_phy; + for (i = 0; i < dwc->num_usb2_ports; i++) { + ret = phy_init(dwc->usb2_generic_phy[i]); + if (ret < 0) + goto err_exit_usb2_phy; + } - ret = phy_init(dwc->usb3_generic_phy); - if (ret < 0) - goto err_exit_usb2_phy; + for (j = 0; j < dwc->num_usb3_ports; j++) { + ret = phy_init(dwc->usb3_generic_phy[j]); + if (ret < 0) + goto err_exit_usb3_phy; + } return 0; +err_exit_usb3_phy: + while (--j >= 0) + phy_exit(dwc->usb3_generic_phy[j]); + err_exit_usb2_phy: - phy_exit(dwc->usb2_generic_phy); -err_shutdown_usb3_phy: + while (--i >= 0) + phy_exit(dwc->usb2_generic_phy[i]); + usb_phy_shutdown(dwc->usb3_phy); usb_phy_shutdown(dwc->usb2_phy); @@ -773,8 +819,13 @@ err_shutdown_usb3_phy: static void dwc3_phy_exit(struct dwc3 *dwc) { - phy_exit(dwc->usb3_generic_phy); - phy_exit(dwc->usb2_generic_phy); + int i; + + for (i = 0; i < dwc->num_usb3_ports; i++) + phy_exit(dwc->usb3_generic_phy[i]); + + for (i = 0; i < dwc->num_usb2_ports; i++) + phy_exit(dwc->usb2_generic_phy[i]); usb_phy_shutdown(dwc->usb3_phy); usb_phy_shutdown(dwc->usb2_phy); @@ -783,23 +834,34 @@ static void dwc3_phy_exit(struct dwc3 *dwc) static int dwc3_phy_power_on(struct dwc3 *dwc) { int ret; + int i; + int j; usb_phy_set_suspend(dwc->usb2_phy, 0); usb_phy_set_suspend(dwc->usb3_phy, 0); - ret = phy_power_on(dwc->usb2_generic_phy); - if (ret < 0) - goto err_suspend_usb3_phy; + for (i = 0; i < dwc->num_usb2_ports; i++) { + ret = phy_power_on(dwc->usb2_generic_phy[i]); + if (ret < 0) + goto err_power_off_usb2_phy; + } - ret = phy_power_on(dwc->usb3_generic_phy); - if (ret < 0) - goto err_power_off_usb2_phy; + for (j = 0; j < dwc->num_usb3_ports; j++) { + ret = phy_power_on(dwc->usb3_generic_phy[j]); + if (ret < 0) + goto err_power_off_usb3_phy; + } return 0; +err_power_off_usb3_phy: + while (--j >= 0) + phy_power_off(dwc->usb3_generic_phy[j]); + err_power_off_usb2_phy: - phy_power_off(dwc->usb2_generic_phy); -err_suspend_usb3_phy: + while (--i >= 0) + phy_power_off(dwc->usb2_generic_phy[i]); + usb_phy_set_suspend(dwc->usb3_phy, 1); usb_phy_set_suspend(dwc->usb2_phy, 1); @@ -808,8 +870,13 @@ err_suspend_usb3_phy: static void dwc3_phy_power_off(struct dwc3 *dwc) { - phy_power_off(dwc->usb3_generic_phy); - phy_power_off(dwc->usb2_generic_phy); + int i; + + for (i = 0; i < dwc->num_usb3_ports; i++) + phy_power_off(dwc->usb3_generic_phy[i]); + + for (i = 0; i < dwc->num_usb2_ports; i++) + phy_power_off(dwc->usb2_generic_phy[i]); usb_phy_set_suspend(dwc->usb3_phy, 1); usb_phy_set_suspend(dwc->usb2_phy, 1); @@ -1201,6 +1268,7 @@ static int dwc3_core_init(struct dwc3 *dwc) unsigned int hw_mode; u32 reg; int ret; + int i; hw_mode = DWC3_GHWPARAMS0_MODE(dwc->hwparams.hwparams0); @@ -1244,15 +1312,19 @@ static int dwc3_core_init(struct dwc3 *dwc) if (hw_mode == DWC3_GHWPARAMS0_MODE_DRD && !DWC3_VER_IS_WITHIN(DWC3, ANY, 194A)) { if (!dwc->dis_u3_susphy_quirk) { - reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0)); - reg |= DWC3_GUSB3PIPECTL_SUSPHY; - dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); + for (i = 0; i < dwc->num_usb3_ports; i++) { + reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(i)); + reg |= DWC3_GUSB3PIPECTL_SUSPHY; + dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(i), reg); + } } if (!dwc->dis_u2_susphy_quirk) { - reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); - reg |= DWC3_GUSB2PHYCFG_SUSPHY; - dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); + for (i = 0; i < dwc->num_usb2_ports; i++) { + reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(i)); + reg |= DWC3_GUSB2PHYCFG_SUSPHY; + dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(i), reg); + } } } @@ -1375,7 +1447,9 @@ static int dwc3_core_get_phy(struct dwc3 *dwc) { struct device *dev = dwc->dev; struct device_node *node = dev->of_node; + char phy_name[9]; int ret; + int i; if (node) { dwc->usb2_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 0); @@ -1401,22 +1475,38 @@ static int dwc3_core_get_phy(struct dwc3 *dwc) return dev_err_probe(dev, ret, "no usb3 phy configured\n"); } - dwc->usb2_generic_phy = devm_phy_get(dev, "usb2-phy"); - if (IS_ERR(dwc->usb2_generic_phy)) { - ret = PTR_ERR(dwc->usb2_generic_phy); - if (ret == -ENOSYS || ret == -ENODEV) - dwc->usb2_generic_phy = NULL; + for (i = 0; i < dwc->num_usb2_ports; i++) { + if (dwc->num_usb2_ports == 1) + snprintf(phy_name, sizeof(phy_name), "usb2-phy"); else - return dev_err_probe(dev, ret, "no usb2 phy configured\n"); + snprintf(phy_name, sizeof(phy_name), "usb2-%d", i); + + dwc->usb2_generic_phy[i] = devm_phy_get(dev, phy_name); + if (IS_ERR(dwc->usb2_generic_phy[i])) { + ret = PTR_ERR(dwc->usb2_generic_phy[i]); + if (ret == -ENOSYS || ret == -ENODEV) + dwc->usb2_generic_phy[i] = NULL; + else + return dev_err_probe(dev, ret, "failed to lookup phy %s\n", + phy_name); + } } - dwc->usb3_generic_phy = devm_phy_get(dev, "usb3-phy"); - if (IS_ERR(dwc->usb3_generic_phy)) { - ret = PTR_ERR(dwc->usb3_generic_phy); - if (ret == -ENOSYS || ret == -ENODEV) - dwc->usb3_generic_phy = NULL; + for (i = 0; i < dwc->num_usb3_ports; i++) { + if (dwc->num_usb3_ports == 1) + snprintf(phy_name, sizeof(phy_name), "usb3-phy"); else - return dev_err_probe(dev, ret, "no usb3 phy configured\n"); + snprintf(phy_name, sizeof(phy_name), "usb3-%d", i); + + dwc->usb3_generic_phy[i] = devm_phy_get(dev, phy_name); + if (IS_ERR(dwc->usb3_generic_phy[i])) { + ret = PTR_ERR(dwc->usb3_generic_phy[i]); + if (ret == -ENOSYS || ret == -ENODEV) + dwc->usb3_generic_phy[i] = NULL; + else + return dev_err_probe(dev, ret, "failed to lookup phy %s\n", + phy_name); + } } return 0; @@ -1426,6 +1516,7 @@ static int dwc3_core_init_mode(struct dwc3 *dwc) { struct device *dev = dwc->dev; int ret; + int i; switch (dwc->dr_mode) { case USB_DR_MODE_PERIPHERAL: @@ -1433,8 +1524,8 @@ static int dwc3_core_init_mode(struct dwc3 *dwc) if (dwc->usb2_phy) otg_set_vbus(dwc->usb2_phy->otg, false); - phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_DEVICE); - phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_DEVICE); + phy_set_mode(dwc->usb2_generic_phy[0], PHY_MODE_USB_DEVICE); + phy_set_mode(dwc->usb3_generic_phy[0], PHY_MODE_USB_DEVICE); ret = dwc3_gadget_init(dwc); if (ret) @@ -1445,8 +1536,10 @@ static int dwc3_core_init_mode(struct dwc3 *dwc) if (dwc->usb2_phy) otg_set_vbus(dwc->usb2_phy->otg, true); - phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_HOST); - phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_HOST); + for (i = 0; i < dwc->num_usb2_ports; i++) + phy_set_mode(dwc->usb2_generic_phy[i], PHY_MODE_USB_HOST); + for (i = 0; i < dwc->num_usb3_ports; i++) + phy_set_mode(dwc->usb3_generic_phy[i], PHY_MODE_USB_HOST); ret = dwc3_host_init(dwc); if (ret) @@ -1940,6 +2033,10 @@ static int dwc3_get_num_ports(struct dwc3 *dwc) iounmap(base); + if (dwc->num_usb2_ports > DWC3_USB2_MAX_PORTS || + dwc->num_usb3_ports > DWC3_USB3_MAX_PORTS) + return -EINVAL; + return 0; } @@ -2177,6 +2274,7 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg) { unsigned long flags; u32 reg; + int i; switch (dwc->current_dr_role) { case DWC3_GCTL_PRTCAP_DEVICE: @@ -2195,17 +2293,21 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg) /* Let controller to suspend HSPHY before PHY driver suspends */ if (dwc->dis_u2_susphy_quirk || dwc->dis_enblslpm_quirk) { - reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); - reg |= DWC3_GUSB2PHYCFG_ENBLSLPM | - DWC3_GUSB2PHYCFG_SUSPHY; - dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); + for (i = 0; i < dwc->num_usb2_ports; i++) { + reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(i)); + reg |= DWC3_GUSB2PHYCFG_ENBLSLPM | + DWC3_GUSB2PHYCFG_SUSPHY; + dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(i), reg); + } /* Give some time for USB2 PHY to suspend */ usleep_range(5000, 6000); } - phy_pm_runtime_put_sync(dwc->usb2_generic_phy); - phy_pm_runtime_put_sync(dwc->usb3_generic_phy); + for (i = 0; i < dwc->num_usb2_ports; i++) + phy_pm_runtime_put_sync(dwc->usb2_generic_phy[i]); + for (i = 0; i < dwc->num_usb3_ports; i++) + phy_pm_runtime_put_sync(dwc->usb3_generic_phy[i]); break; case DWC3_GCTL_PRTCAP_OTG: /* do nothing during runtime_suspend */ @@ -2235,6 +2337,7 @@ static int dwc3_resume_common(struct dwc3 *dwc, pm_message_t msg) unsigned long flags; int ret; u32 reg; + int i; switch (dwc->current_dr_role) { case DWC3_GCTL_PRTCAP_DEVICE: @@ -2254,17 +2357,21 @@ static int dwc3_resume_common(struct dwc3 *dwc, pm_message_t msg) break; } /* Restore GUSB2PHYCFG bits that were modified in suspend */ - reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); - if (dwc->dis_u2_susphy_quirk) - reg &= ~DWC3_GUSB2PHYCFG_SUSPHY; + for (i = 0; i < dwc->num_usb2_ports; i++) { + reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(i)); + if (dwc->dis_u2_susphy_quirk) + reg &= ~DWC3_GUSB2PHYCFG_SUSPHY; - if (dwc->dis_enblslpm_quirk) - reg &= ~DWC3_GUSB2PHYCFG_ENBLSLPM; + if (dwc->dis_enblslpm_quirk) + reg &= ~DWC3_GUSB2PHYCFG_ENBLSLPM; - dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); + dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(i), reg); + } - phy_pm_runtime_get_sync(dwc->usb2_generic_phy); - phy_pm_runtime_get_sync(dwc->usb3_generic_phy); + for (i = 0; i < dwc->num_usb2_ports; i++) + phy_pm_runtime_get_sync(dwc->usb2_generic_phy[i]); + for (i = 0; i < dwc->num_usb3_ports; i++) + phy_pm_runtime_get_sync(dwc->usb3_generic_phy[i]); break; case DWC3_GCTL_PRTCAP_OTG: /* nothing to do on runtime_resume */ diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 341e4c73cb2e..5cbc64883dbc 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -33,6 +33,13 @@ #include +/* + * DWC3 Multiport controllers support up to 15 High-Speed PHYs + * and 4 SuperSpeed PHYs. + */ +#define DWC3_USB2_MAX_PORTS 15 +#define DWC3_USB3_MAX_PORTS 4 + #define DWC3_MSG_MAX 500 /* Global constants */ @@ -1037,8 +1044,8 @@ struct dwc3_scratchpad_array { * @usb_psy: pointer to power supply interface. * @usb2_phy: pointer to USB2 PHY * @usb3_phy: pointer to USB3 PHY - * @usb2_generic_phy: pointer to USB2 PHY - * @usb3_generic_phy: pointer to USB3 PHY + * @usb2_generic_phy: pointer to array of USB2 PHYs + * @usb3_generic_phy: pointer to array of USB3 PHYs * @num_usb2_ports: number of USB2 ports * @num_usb3_ports: number of USB3 ports * @phys_ready: flag to indicate that PHYs are ready @@ -1186,8 +1193,8 @@ struct dwc3 { struct usb_phy *usb2_phy; struct usb_phy *usb3_phy; - struct phy *usb2_generic_phy; - struct phy *usb3_generic_phy; + struct phy *usb2_generic_phy[DWC3_USB2_MAX_PORTS]; + struct phy *usb3_generic_phy[DWC3_USB3_MAX_PORTS]; u8 num_usb2_ports; u8 num_usb3_ports; diff --git a/drivers/usb/dwc3/drd.c b/drivers/usb/dwc3/drd.c index 57ddd2e43022..d76ae676783c 100644 --- a/drivers/usb/dwc3/drd.c +++ b/drivers/usb/dwc3/drd.c @@ -331,6 +331,7 @@ void dwc3_otg_update(struct dwc3 *dwc, bool ignore_idstatus) u32 reg; int id; unsigned long flags; + int i; if (dwc->dr_mode != USB_DR_MODE_OTG) return; @@ -386,9 +387,12 @@ void dwc3_otg_update(struct dwc3 *dwc, bool ignore_idstatus) } else { if (dwc->usb2_phy) otg_set_vbus(dwc->usb2_phy->otg, true); - if (dwc->usb2_generic_phy) - phy_set_mode(dwc->usb2_generic_phy, - PHY_MODE_USB_HOST); + for (i = 0; i < dwc->num_usb2_ports; i++) { + if (dwc->usb2_generic_phy[i]) { + phy_set_mode(dwc->usb2_generic_phy[i], + PHY_MODE_USB_HOST); + } + } } break; case DWC3_OTG_ROLE_DEVICE: @@ -400,9 +404,8 @@ void dwc3_otg_update(struct dwc3 *dwc, bool ignore_idstatus) if (dwc->usb2_phy) otg_set_vbus(dwc->usb2_phy->otg, false); - if (dwc->usb2_generic_phy) - phy_set_mode(dwc->usb2_generic_phy, - PHY_MODE_USB_DEVICE); + if (dwc->usb2_generic_phy[0]) + phy_set_mode(dwc->usb2_generic_phy[0], PHY_MODE_USB_DEVICE); ret = dwc3_gadget_init(dwc); if (ret) dev_err(dwc->dev, "failed to initialize peripheral\n"); -- cgit v1.2.3-59-g8ed1b From 80adfb54044ec6bfa58c3babd86b7b233d44f906 Mon Sep 17 00:00:00 2001 From: Krishna Kurapati Date: Sat, 20 Apr 2024 10:18:57 +0530 Subject: dt-bindings: usb: qcom,dwc3: Add bindings for SC8280 Multiport Add the compatible string for SC8280 Multiport USB controller from Qualcomm. There are 4 power event interrupts supported by this controller (one for each port of multiport controller). Add all the 4 as non-optional interrupts for SC8280XP-MP Also each port of multiport has one DP and one DM IRQ. Add all DP/DM IRQs related to 4 ports of SC8280XP Teritiary controller. Also added SuperSpeed PHY interrupt for both Superspeed ports. Signed-off-by: Krishna Kurapati Reviewed-by: Bjorn Andersson Reviewed-by: Johan Hovold Tested-by: Johan Hovold Link: https://lore.kernel.org/r/20240420044901.884098-6-quic_kriskura@quicinc.com Signed-off-by: Greg Kroah-Hartman --- .../devicetree/bindings/usb/qcom,dwc3.yaml | 34 ++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml b/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml index 38a3404ec71b..f55f601c0329 100644 --- a/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml +++ b/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml @@ -30,6 +30,7 @@ properties: - qcom,sc7180-dwc3 - qcom,sc7280-dwc3 - qcom,sc8280xp-dwc3 + - qcom,sc8280xp-dwc3-mp - qcom,sdm660-dwc3 - qcom,sdm670-dwc3 - qcom,sdm845-dwc3 @@ -282,6 +283,7 @@ allOf: contains: enum: - qcom,sc8280xp-dwc3 + - qcom,sc8280xp-dwc3-mp - qcom,x1e80100-dwc3 then: properties: @@ -470,6 +472,38 @@ allOf: - const: dm_hs_phy_irq - const: ss_phy_irq + - if: + properties: + compatible: + contains: + enum: + - qcom,sc8280xp-dwc3-mp + then: + properties: + interrupts: + minItems: 18 + maxItems: 18 + interrupt-names: + items: + - const: pwr_event_1 + - const: pwr_event_2 + - const: pwr_event_3 + - const: pwr_event_4 + - const: hs_phy_1 + - const: hs_phy_2 + - const: hs_phy_3 + - const: hs_phy_4 + - const: dp_hs_phy_1 + - const: dm_hs_phy_1 + - const: dp_hs_phy_2 + - const: dm_hs_phy_2 + - const: dp_hs_phy_3 + - const: dm_hs_phy_3 + - const: dp_hs_phy_4 + - const: dm_hs_phy_4 + - const: ss_phy_1 + - const: ss_phy_2 + additionalProperties: false examples: -- cgit v1.2.3-59-g8ed1b From 6410c8033ba74bf6be19515be5164161abd5ef63 Mon Sep 17 00:00:00 2001 From: Krishna Kurapati Date: Sat, 20 Apr 2024 10:18:58 +0530 Subject: usb: dwc3: qcom: Add helper function to request wakeup interrupts The logic for requesting interrupts is duplicated for each interrupt. In the upcoming patches that introduces support for multiport, it would be better to clean up the duplication before reading mulitport related interrupts. Refactor interrupt setup call by adding a new helper function for requesting the wakeup interrupts. To simplify implementation, make the display name same as the interrupt name expected in Device tree. Signed-off-by: Krishna Kurapati Reviewed-by: Bjorn Andersson Acked-by: Thinh Nguyen Reviewed-by: Johan Hovold Tested-by: Johan Hovold Link: https://lore.kernel.org/r/20240420044901.884098-7-quic_kriskura@quicinc.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/dwc3-qcom.c | 53 ++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 29 deletions(-) diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c index f6b2fab49d5e..cae5dab8fcfc 100644 --- a/drivers/usb/dwc3/dwc3-qcom.c +++ b/drivers/usb/dwc3/dwc3-qcom.c @@ -501,6 +501,22 @@ static void dwc3_qcom_select_utmi_clk(struct dwc3_qcom *qcom) PIPE_UTMI_CLK_DIS); } +static int dwc3_qcom_request_irq(struct dwc3_qcom *qcom, int irq, + const char *name) +{ + int ret; + + /* Keep wakeup interrupts disabled until suspend */ + ret = devm_request_threaded_irq(qcom->dev, irq, NULL, + qcom_dwc3_resume_irq, + IRQF_ONESHOT | IRQF_NO_AUTOEN, + name, qcom); + if (ret) + dev_err(qcom->dev, "failed to request irq %s: %d\n", name, ret); + + return ret; +} + static int dwc3_qcom_setup_irq(struct platform_device *pdev) { struct dwc3_qcom *qcom = platform_get_drvdata(pdev); @@ -509,54 +525,33 @@ static int dwc3_qcom_setup_irq(struct platform_device *pdev) irq = platform_get_irq_byname_optional(pdev, "qusb2_phy"); if (irq > 0) { - /* Keep wakeup interrupts disabled until suspend */ - ret = devm_request_threaded_irq(qcom->dev, irq, NULL, - qcom_dwc3_resume_irq, - IRQF_ONESHOT | IRQF_NO_AUTOEN, - "qcom_dwc3 QUSB2", qcom); - if (ret) { - dev_err(qcom->dev, "qusb2_phy_irq failed: %d\n", ret); + ret = dwc3_qcom_request_irq(qcom, irq, "qusb2_phy"); + if (ret) return ret; - } qcom->qusb2_phy_irq = irq; } irq = platform_get_irq_byname_optional(pdev, "dp_hs_phy_irq"); if (irq > 0) { - ret = devm_request_threaded_irq(qcom->dev, irq, NULL, - qcom_dwc3_resume_irq, - IRQF_ONESHOT | IRQF_NO_AUTOEN, - "qcom_dwc3 DP_HS", qcom); - if (ret) { - dev_err(qcom->dev, "dp_hs_phy_irq failed: %d\n", ret); + ret = dwc3_qcom_request_irq(qcom, irq, "dp_hs_phy_irq"); + if (ret) return ret; - } qcom->dp_hs_phy_irq = irq; } irq = platform_get_irq_byname_optional(pdev, "dm_hs_phy_irq"); if (irq > 0) { - ret = devm_request_threaded_irq(qcom->dev, irq, NULL, - qcom_dwc3_resume_irq, - IRQF_ONESHOT | IRQF_NO_AUTOEN, - "qcom_dwc3 DM_HS", qcom); - if (ret) { - dev_err(qcom->dev, "dm_hs_phy_irq failed: %d\n", ret); + ret = dwc3_qcom_request_irq(qcom, irq, "dm_hs_phy_irq"); + if (ret) return ret; - } qcom->dm_hs_phy_irq = irq; } irq = platform_get_irq_byname_optional(pdev, "ss_phy_irq"); if (irq > 0) { - ret = devm_request_threaded_irq(qcom->dev, irq, NULL, - qcom_dwc3_resume_irq, - IRQF_ONESHOT | IRQF_NO_AUTOEN, - "qcom_dwc3 SS", qcom); - if (ret) { - dev_err(qcom->dev, "ss_phy_irq failed: %d\n", ret); + ret = dwc3_qcom_request_irq(qcom, irq, "ss_phy_irq"); + if (ret) return ret; - } qcom->ss_phy_irq = irq; } -- cgit v1.2.3-59-g8ed1b From 2bfc9916a0e49a65557d8f5332effdce9ddeb7e0 Mon Sep 17 00:00:00 2001 From: Krishna Kurapati Date: Sat, 20 Apr 2024 10:18:59 +0530 Subject: usb: dwc3: qcom: Refactor IRQ handling in glue driver On multiport supported controllers, each port has its own DP/DM and SuperSpeed (if super speed capable) interrupts. As per the bindings, their interrupt names differ from single-port ones by having a "_x" added as suffix (x being the port number). Identify from the interrupt names whether the controller is a multiport controller or not. Refactor dwc3_qcom_setup_irq() call to parse multiportinterrupts along with non-multiport ones accordingly. Signed-off-by: Krishna Kurapati Reviewed-by: Bjorn Andersson Acked-by: Thinh Nguyen Reviewed-by: Johan Hovold Tested-by: Johan Hovold Link: https://lore.kernel.org/r/20240420044901.884098-8-quic_kriskura@quicinc.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/dwc3-qcom.c | 140 ++++++++++++++++++++++++++++++++----------- 1 file changed, 106 insertions(+), 34 deletions(-) diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c index cae5dab8fcfc..5ddb694dd8e7 100644 --- a/drivers/usb/dwc3/dwc3-qcom.c +++ b/drivers/usb/dwc3/dwc3-qcom.c @@ -52,6 +52,16 @@ #define APPS_USB_AVG_BW 0 #define APPS_USB_PEAK_BW MBps_to_icc(40) +/* Qualcomm SoCs with multiport support has up to 4 ports */ +#define DWC3_QCOM_MAX_PORTS 4 + +struct dwc3_qcom_port { + int qusb2_phy_irq; + int dp_hs_phy_irq; + int dm_hs_phy_irq; + int ss_phy_irq; +}; + struct dwc3_qcom { struct device *dev; void __iomem *qscratch_base; @@ -59,11 +69,8 @@ struct dwc3_qcom { struct clk **clks; int num_clocks; struct reset_control *resets; - - int qusb2_phy_irq; - int dp_hs_phy_irq; - int dm_hs_phy_irq; - int ss_phy_irq; + struct dwc3_qcom_port ports[DWC3_QCOM_MAX_PORTS]; + u8 num_ports; enum usb_device_speed usb2_speed; struct extcon_dev *edev; @@ -354,24 +361,24 @@ static void dwc3_qcom_disable_wakeup_irq(int irq) static void dwc3_qcom_disable_interrupts(struct dwc3_qcom *qcom) { - dwc3_qcom_disable_wakeup_irq(qcom->qusb2_phy_irq); + dwc3_qcom_disable_wakeup_irq(qcom->ports[0].qusb2_phy_irq); if (qcom->usb2_speed == USB_SPEED_LOW) { - dwc3_qcom_disable_wakeup_irq(qcom->dm_hs_phy_irq); + dwc3_qcom_disable_wakeup_irq(qcom->ports[0].dm_hs_phy_irq); } else if ((qcom->usb2_speed == USB_SPEED_HIGH) || (qcom->usb2_speed == USB_SPEED_FULL)) { - dwc3_qcom_disable_wakeup_irq(qcom->dp_hs_phy_irq); + dwc3_qcom_disable_wakeup_irq(qcom->ports[0].dp_hs_phy_irq); } else { - dwc3_qcom_disable_wakeup_irq(qcom->dp_hs_phy_irq); - dwc3_qcom_disable_wakeup_irq(qcom->dm_hs_phy_irq); + dwc3_qcom_disable_wakeup_irq(qcom->ports[0].dp_hs_phy_irq); + dwc3_qcom_disable_wakeup_irq(qcom->ports[0].dm_hs_phy_irq); } - dwc3_qcom_disable_wakeup_irq(qcom->ss_phy_irq); + dwc3_qcom_disable_wakeup_irq(qcom->ports[0].ss_phy_irq); } static void dwc3_qcom_enable_interrupts(struct dwc3_qcom *qcom) { - dwc3_qcom_enable_wakeup_irq(qcom->qusb2_phy_irq, 0); + dwc3_qcom_enable_wakeup_irq(qcom->ports[0].qusb2_phy_irq, 0); /* * Configure DP/DM line interrupts based on the USB2 device attached to @@ -383,20 +390,20 @@ static void dwc3_qcom_enable_interrupts(struct dwc3_qcom *qcom) */ if (qcom->usb2_speed == USB_SPEED_LOW) { - dwc3_qcom_enable_wakeup_irq(qcom->dm_hs_phy_irq, - IRQ_TYPE_EDGE_FALLING); + dwc3_qcom_enable_wakeup_irq(qcom->ports[0].dm_hs_phy_irq, + IRQ_TYPE_EDGE_FALLING); } else if ((qcom->usb2_speed == USB_SPEED_HIGH) || (qcom->usb2_speed == USB_SPEED_FULL)) { - dwc3_qcom_enable_wakeup_irq(qcom->dp_hs_phy_irq, - IRQ_TYPE_EDGE_FALLING); + dwc3_qcom_enable_wakeup_irq(qcom->ports[0].dp_hs_phy_irq, + IRQ_TYPE_EDGE_FALLING); } else { - dwc3_qcom_enable_wakeup_irq(qcom->dp_hs_phy_irq, - IRQ_TYPE_EDGE_RISING); - dwc3_qcom_enable_wakeup_irq(qcom->dm_hs_phy_irq, - IRQ_TYPE_EDGE_RISING); + dwc3_qcom_enable_wakeup_irq(qcom->ports[0].dp_hs_phy_irq, + IRQ_TYPE_EDGE_RISING); + dwc3_qcom_enable_wakeup_irq(qcom->ports[0].dm_hs_phy_irq, + IRQ_TYPE_EDGE_RISING); } - dwc3_qcom_enable_wakeup_irq(qcom->ss_phy_irq, 0); + dwc3_qcom_enable_wakeup_irq(qcom->ports[0].ss_phy_irq, 0); } static int dwc3_qcom_suspend(struct dwc3_qcom *qcom, bool wakeup) @@ -517,42 +524,107 @@ static int dwc3_qcom_request_irq(struct dwc3_qcom *qcom, int irq, return ret; } -static int dwc3_qcom_setup_irq(struct platform_device *pdev) +static int dwc3_qcom_setup_port_irq(struct platform_device *pdev, int port_index, bool is_multiport) { struct dwc3_qcom *qcom = platform_get_drvdata(pdev); + const char *irq_name; int irq; int ret; - irq = platform_get_irq_byname_optional(pdev, "qusb2_phy"); + if (is_multiport) + irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "dp_hs_phy_%d", port_index + 1); + else + irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "dp_hs_phy_irq"); + if (!irq_name) + return -ENOMEM; + + irq = platform_get_irq_byname_optional(pdev, irq_name); if (irq > 0) { - ret = dwc3_qcom_request_irq(qcom, irq, "qusb2_phy"); + ret = dwc3_qcom_request_irq(qcom, irq, irq_name); if (ret) return ret; - qcom->qusb2_phy_irq = irq; + qcom->ports[port_index].dp_hs_phy_irq = irq; } - irq = platform_get_irq_byname_optional(pdev, "dp_hs_phy_irq"); + if (is_multiport) + irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "dm_hs_phy_%d", port_index + 1); + else + irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "dm_hs_phy_irq"); + if (!irq_name) + return -ENOMEM; + + irq = platform_get_irq_byname_optional(pdev, irq_name); if (irq > 0) { - ret = dwc3_qcom_request_irq(qcom, irq, "dp_hs_phy_irq"); + ret = dwc3_qcom_request_irq(qcom, irq, irq_name); if (ret) return ret; - qcom->dp_hs_phy_irq = irq; + qcom->ports[port_index].dm_hs_phy_irq = irq; } - irq = platform_get_irq_byname_optional(pdev, "dm_hs_phy_irq"); + if (is_multiport) + irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "ss_phy_%d", port_index + 1); + else + irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "ss_phy_irq"); + if (!irq_name) + return -ENOMEM; + + irq = platform_get_irq_byname_optional(pdev, irq_name); if (irq > 0) { - ret = dwc3_qcom_request_irq(qcom, irq, "dm_hs_phy_irq"); + ret = dwc3_qcom_request_irq(qcom, irq, irq_name); if (ret) return ret; - qcom->dm_hs_phy_irq = irq; + qcom->ports[port_index].ss_phy_irq = irq; } - irq = platform_get_irq_byname_optional(pdev, "ss_phy_irq"); + if (is_multiport) + return 0; + + irq = platform_get_irq_byname_optional(pdev, "qusb2_phy"); if (irq > 0) { - ret = dwc3_qcom_request_irq(qcom, irq, "ss_phy_irq"); + ret = dwc3_qcom_request_irq(qcom, irq, "qusb2_phy"); + if (ret) + return ret; + qcom->ports[port_index].qusb2_phy_irq = irq; + } + + return 0; +} + +static int dwc3_qcom_find_num_ports(struct platform_device *pdev) +{ + char irq_name[14]; + int port_num; + int irq; + + irq = platform_get_irq_byname_optional(pdev, "dp_hs_phy_1"); + if (irq <= 0) + return 1; + + for (port_num = 2; port_num <= DWC3_QCOM_MAX_PORTS; port_num++) { + sprintf(irq_name, "dp_hs_phy_%d", port_num); + + irq = platform_get_irq_byname_optional(pdev, irq_name); + if (irq <= 0) + return port_num - 1; + } + + return DWC3_QCOM_MAX_PORTS; +} + +static int dwc3_qcom_setup_irq(struct platform_device *pdev) +{ + struct dwc3_qcom *qcom = platform_get_drvdata(pdev); + bool is_multiport; + int ret; + int i; + + qcom->num_ports = dwc3_qcom_find_num_ports(pdev); + is_multiport = (qcom->num_ports > 1); + + for (i = 0; i < qcom->num_ports; i++) { + ret = dwc3_qcom_setup_port_irq(pdev, i, is_multiport); if (ret) return ret; - qcom->ss_phy_irq = irq; } return 0; -- cgit v1.2.3-59-g8ed1b From 5df44c6f4f396b1451f97e734f5812d962f0120f Mon Sep 17 00:00:00 2001 From: Krishna Kurapati Date: Sat, 20 Apr 2024 10:19:00 +0530 Subject: usb: dwc3: qcom: Enable wakeup for applicable ports of multiport DWC3 Qcom wrapper currently supports only wakeup configuration for single port controllers. Read speed of each port connected to the controller and enable wakeup for each of them accordingly. Signed-off-by: Krishna Kurapati Reviewed-by: Johan Hovold Reviewed-by: Bjorn Andersson Acked-by: Thinh Nguyen Tested-by: Johan Hovold Link: https://lore.kernel.org/r/20240420044901.884098-9-quic_kriskura@quicinc.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/dwc3-qcom.c | 71 +++++++++++++++++++++++++------------------- 1 file changed, 41 insertions(+), 30 deletions(-) diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c index 5ddb694dd8e7..b6f13bb14e2c 100644 --- a/drivers/usb/dwc3/dwc3-qcom.c +++ b/drivers/usb/dwc3/dwc3-qcom.c @@ -60,6 +60,7 @@ struct dwc3_qcom_port { int dp_hs_phy_irq; int dm_hs_phy_irq; int ss_phy_irq; + enum usb_device_speed usb2_speed; }; struct dwc3_qcom { @@ -71,7 +72,6 @@ struct dwc3_qcom { struct reset_control *resets; struct dwc3_qcom_port ports[DWC3_QCOM_MAX_PORTS]; u8 num_ports; - enum usb_device_speed usb2_speed; struct extcon_dev *edev; struct extcon_dev *host_edev; @@ -310,7 +310,7 @@ static bool dwc3_qcom_is_host(struct dwc3_qcom *qcom) return dwc->xhci; } -static enum usb_device_speed dwc3_qcom_read_usb2_speed(struct dwc3_qcom *qcom) +static enum usb_device_speed dwc3_qcom_read_usb2_speed(struct dwc3_qcom *qcom, int port_index) { struct dwc3 *dwc = platform_get_drvdata(qcom->dwc3); struct usb_device *udev; @@ -321,14 +321,8 @@ static enum usb_device_speed dwc3_qcom_read_usb2_speed(struct dwc3_qcom *qcom) */ hcd = platform_get_drvdata(dwc->xhci); - /* - * It is possible to query the speed of all children of - * USB2.0 root hub via usb_hub_for_each_child(). DWC3 code - * currently supports only 1 port per controller. So - * this is sufficient. - */ #ifdef CONFIG_USB - udev = usb_hub_find_child(hcd->self.root_hub, 1); + udev = usb_hub_find_child(hcd->self.root_hub, port_index + 1); #else udev = NULL; #endif @@ -359,26 +353,26 @@ static void dwc3_qcom_disable_wakeup_irq(int irq) disable_irq_nosync(irq); } -static void dwc3_qcom_disable_interrupts(struct dwc3_qcom *qcom) +static void dwc3_qcom_disable_port_interrupts(struct dwc3_qcom_port *port) { - dwc3_qcom_disable_wakeup_irq(qcom->ports[0].qusb2_phy_irq); + dwc3_qcom_disable_wakeup_irq(port->qusb2_phy_irq); - if (qcom->usb2_speed == USB_SPEED_LOW) { - dwc3_qcom_disable_wakeup_irq(qcom->ports[0].dm_hs_phy_irq); - } else if ((qcom->usb2_speed == USB_SPEED_HIGH) || - (qcom->usb2_speed == USB_SPEED_FULL)) { - dwc3_qcom_disable_wakeup_irq(qcom->ports[0].dp_hs_phy_irq); + if (port->usb2_speed == USB_SPEED_LOW) { + dwc3_qcom_disable_wakeup_irq(port->dm_hs_phy_irq); + } else if ((port->usb2_speed == USB_SPEED_HIGH) || + (port->usb2_speed == USB_SPEED_FULL)) { + dwc3_qcom_disable_wakeup_irq(port->dp_hs_phy_irq); } else { - dwc3_qcom_disable_wakeup_irq(qcom->ports[0].dp_hs_phy_irq); - dwc3_qcom_disable_wakeup_irq(qcom->ports[0].dm_hs_phy_irq); + dwc3_qcom_disable_wakeup_irq(port->dp_hs_phy_irq); + dwc3_qcom_disable_wakeup_irq(port->dm_hs_phy_irq); } - dwc3_qcom_disable_wakeup_irq(qcom->ports[0].ss_phy_irq); + dwc3_qcom_disable_wakeup_irq(port->ss_phy_irq); } -static void dwc3_qcom_enable_interrupts(struct dwc3_qcom *qcom) +static void dwc3_qcom_enable_port_interrupts(struct dwc3_qcom_port *port) { - dwc3_qcom_enable_wakeup_irq(qcom->ports[0].qusb2_phy_irq, 0); + dwc3_qcom_enable_wakeup_irq(port->qusb2_phy_irq, 0); /* * Configure DP/DM line interrupts based on the USB2 device attached to @@ -389,21 +383,37 @@ static void dwc3_qcom_enable_interrupts(struct dwc3_qcom *qcom) * DP and DM lines as rising edge to detect HS/HS/LS device connect scenario. */ - if (qcom->usb2_speed == USB_SPEED_LOW) { - dwc3_qcom_enable_wakeup_irq(qcom->ports[0].dm_hs_phy_irq, + if (port->usb2_speed == USB_SPEED_LOW) { + dwc3_qcom_enable_wakeup_irq(port->dm_hs_phy_irq, IRQ_TYPE_EDGE_FALLING); - } else if ((qcom->usb2_speed == USB_SPEED_HIGH) || - (qcom->usb2_speed == USB_SPEED_FULL)) { - dwc3_qcom_enable_wakeup_irq(qcom->ports[0].dp_hs_phy_irq, + } else if ((port->usb2_speed == USB_SPEED_HIGH) || + (port->usb2_speed == USB_SPEED_FULL)) { + dwc3_qcom_enable_wakeup_irq(port->dp_hs_phy_irq, IRQ_TYPE_EDGE_FALLING); } else { - dwc3_qcom_enable_wakeup_irq(qcom->ports[0].dp_hs_phy_irq, + dwc3_qcom_enable_wakeup_irq(port->dp_hs_phy_irq, IRQ_TYPE_EDGE_RISING); - dwc3_qcom_enable_wakeup_irq(qcom->ports[0].dm_hs_phy_irq, + dwc3_qcom_enable_wakeup_irq(port->dm_hs_phy_irq, IRQ_TYPE_EDGE_RISING); } - dwc3_qcom_enable_wakeup_irq(qcom->ports[0].ss_phy_irq, 0); + dwc3_qcom_enable_wakeup_irq(port->ss_phy_irq, 0); +} + +static void dwc3_qcom_disable_interrupts(struct dwc3_qcom *qcom) +{ + int i; + + for (i = 0; i < qcom->num_ports; i++) + dwc3_qcom_disable_port_interrupts(&qcom->ports[i]); +} + +static void dwc3_qcom_enable_interrupts(struct dwc3_qcom *qcom) +{ + int i; + + for (i = 0; i < qcom->num_ports; i++) + dwc3_qcom_enable_port_interrupts(&qcom->ports[i]); } static int dwc3_qcom_suspend(struct dwc3_qcom *qcom, bool wakeup) @@ -430,7 +440,8 @@ static int dwc3_qcom_suspend(struct dwc3_qcom *qcom, bool wakeup) * freezable workqueue. */ if (dwc3_qcom_is_host(qcom) && wakeup) { - qcom->usb2_speed = dwc3_qcom_read_usb2_speed(qcom); + for (i = 0; i < qcom->num_ports; i++) + qcom->ports[i].usb2_speed = dwc3_qcom_read_usb2_speed(qcom, i); dwc3_qcom_enable_interrupts(qcom); } -- cgit v1.2.3-59-g8ed1b From a160e1202ca318a85c70cf5831f172cc79a24c57 Mon Sep 17 00:00:00 2001 From: Krishna Kurapati Date: Sat, 20 Apr 2024 10:19:01 +0530 Subject: usb: dwc3: qcom: Add multiport suspend/resume support for wrapper Power event IRQ is used for wakeup either when the controller is SuperSpeed capable but is missing an SuperSpeed PHY interrupt, or when the GIC is not capable of detecting DP/DM High-Speed PHY interrupts. The Power event IRQ stat register indicates whether the High-Speed phy entered and exited L2 successfully during suspend and resume. Indicate the same for all ports of a multiport controller. Signed-off-by: Krishna Kurapati Reviewed-by: Bjorn Andersson Acked-by: Thinh Nguyen Reviewed-by: Johan Hovold Tested-by: Johan Hovold Link: https://lore.kernel.org/r/20240420044901.884098-10-quic_kriskura@quicinc.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/dwc3-qcom.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c index b6f13bb14e2c..88fb6706a18d 100644 --- a/drivers/usb/dwc3/dwc3-qcom.c +++ b/drivers/usb/dwc3/dwc3-qcom.c @@ -36,7 +36,6 @@ #define PIPE3_PHYSTATUS_SW BIT(3) #define PIPE_UTMI_CLK_DIS BIT(8) -#define PWR_EVNT_IRQ_STAT_REG 0x58 #define PWR_EVNT_LPM_IN_L2_MASK BIT(4) #define PWR_EVNT_LPM_OUT_L2_MASK BIT(5) @@ -55,6 +54,13 @@ /* Qualcomm SoCs with multiport support has up to 4 ports */ #define DWC3_QCOM_MAX_PORTS 4 +static const u32 pwr_evnt_irq_stat_reg[DWC3_QCOM_MAX_PORTS] = { + 0x58, + 0x1dc, + 0x228, + 0x238, +}; + struct dwc3_qcom_port { int qusb2_phy_irq; int dp_hs_phy_irq; @@ -424,9 +430,11 @@ static int dwc3_qcom_suspend(struct dwc3_qcom *qcom, bool wakeup) if (qcom->is_suspended) return 0; - val = readl(qcom->qscratch_base + PWR_EVNT_IRQ_STAT_REG); - if (!(val & PWR_EVNT_LPM_IN_L2_MASK)) - dev_err(qcom->dev, "HS-PHY not in L2\n"); + for (i = 0; i < qcom->num_ports; i++) { + val = readl(qcom->qscratch_base + pwr_evnt_irq_stat_reg[i]); + if (!(val & PWR_EVNT_LPM_IN_L2_MASK)) + dev_err(qcom->dev, "port-%d HS-PHY not in L2\n", i + 1); + } for (i = qcom->num_clocks - 1; i >= 0; i--) clk_disable_unprepare(qcom->clks[i]); @@ -475,8 +483,11 @@ static int dwc3_qcom_resume(struct dwc3_qcom *qcom, bool wakeup) dev_warn(qcom->dev, "failed to enable interconnect: %d\n", ret); /* Clear existing events from PHY related to L2 in/out */ - dwc3_qcom_setbits(qcom->qscratch_base, PWR_EVNT_IRQ_STAT_REG, - PWR_EVNT_LPM_IN_L2_MASK | PWR_EVNT_LPM_OUT_L2_MASK); + for (i = 0; i < qcom->num_ports; i++) { + dwc3_qcom_setbits(qcom->qscratch_base, + pwr_evnt_irq_stat_reg[i], + PWR_EVNT_LPM_IN_L2_MASK | PWR_EVNT_LPM_OUT_L2_MASK); + } qcom->is_suspended = false; -- cgit v1.2.3-59-g8ed1b From e22810ab3f5e0de0151a5a0d05a54cfc39a780a8 Mon Sep 17 00:00:00 2001 From: Kunwu Chan Date: Tue, 23 Apr 2024 10:41:33 +0800 Subject: mei: bus: constify the struct mei_cl_bus_type usage Now that the driver core can properly handle constant struct bus_type, move the mei_cl_bus_type variable to be a constant structure as well, placing it into read-only memory which can not be modified at runtime. Signed-off-by: Kunwu Chan Acked-by: Tomas Winkler Link: https://lore.kernel.org/r/20240423024133.1890455-1-chentao@kylinos.cn Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/bus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c index f9bcff197615..99393f610cdf 100644 --- a/drivers/misc/mei/bus.c +++ b/drivers/misc/mei/bus.c @@ -1327,7 +1327,7 @@ static int mei_cl_device_uevent(const struct device *dev, struct kobj_uevent_env return 0; } -static struct bus_type mei_cl_bus_type = { +static const struct bus_type mei_cl_bus_type = { .name = "mei", .dev_groups = mei_cldev_groups, .match = mei_cl_device_match, -- cgit v1.2.3-59-g8ed1b From edc66cf0c4164aa3daf6cc55e970bb94383a6a57 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Thu, 11 Apr 2024 10:21:44 +0200 Subject: microblaze: Remove gcc flag for non existing early_printk.c file early_printk support for removed long time ago but compilation flag for ftrace still points to already removed file that's why remove that line too. Fixes: 96f0e6fcc9ad ("microblaze: remove redundant early_printk support") Signed-off-by: Michal Simek Link: https://lore.kernel.org/r/5493467419cd2510a32854e2807bcd263de981a0.1712823702.git.michal.simek@amd.com --- arch/microblaze/kernel/Makefile | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/microblaze/kernel/Makefile b/arch/microblaze/kernel/Makefile index 4393bee64eaf..85c4d29ef43e 100644 --- a/arch/microblaze/kernel/Makefile +++ b/arch/microblaze/kernel/Makefile @@ -7,7 +7,6 @@ ifdef CONFIG_FUNCTION_TRACER # Do not trace early boot code and low level code CFLAGS_REMOVE_timer.o = -pg CFLAGS_REMOVE_intc.o = -pg -CFLAGS_REMOVE_early_printk.o = -pg CFLAGS_REMOVE_ftrace.o = -pg CFLAGS_REMOVE_process.o = -pg endif -- cgit v1.2.3-59-g8ed1b From 58d647506c92ccd3cfa0c453c68ddd14f40bf06f Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Thu, 11 Apr 2024 10:27:21 +0200 Subject: microblaze: Remove early printk call from cpuinfo-static.c Early printk has been removed already that's why also remove calling it. Similar change has been done in cpuinfo-pvr-full.c by commit cfbd8d1979af ("microblaze: Remove early printk setup"). Fixes: 96f0e6fcc9ad ("microblaze: remove redundant early_printk support") Signed-off-by: Michal Simek Link: https://lore.kernel.org/r/2f10db506be8188fa07b6ec331caca01af1b10f8.1712824039.git.michal.simek@amd.com --- arch/microblaze/kernel/cpu/cpuinfo-static.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/microblaze/kernel/cpu/cpuinfo-static.c b/arch/microblaze/kernel/cpu/cpuinfo-static.c index 85dbda4a08a8..03da36dc6d9c 100644 --- a/arch/microblaze/kernel/cpu/cpuinfo-static.c +++ b/arch/microblaze/kernel/cpu/cpuinfo-static.c @@ -18,7 +18,7 @@ static const char family_string[] = CONFIG_XILINX_MICROBLAZE0_FAMILY; static const char cpu_ver_string[] = CONFIG_XILINX_MICROBLAZE0_HW_VER; #define err_printk(x) \ - early_printk("ERROR: Microblaze " x "-different for kernel and DTS\n"); + pr_err("ERROR: Microblaze " x "-different for kernel and DTS\n"); void __init set_cpuinfo_static(struct cpuinfo *ci, struct device_node *cpu) { -- cgit v1.2.3-59-g8ed1b From a3ad3a90e0a722d9a50c01cfb40e6cfbb975e529 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Fri, 19 Apr 2024 08:17:58 +0300 Subject: thunderbolt: There are only 5 basic router registers in pre-USB4 routers Intel pre-USB4 routers only have ROUTER_CS_0 up to ROUTER_CS_4 and it immediately follows the TMU router registers. Correct this accordingly. Reported-by: Rajaram Regupathy Signed-off-by: Mika Westerberg --- drivers/thunderbolt/debugfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/thunderbolt/debugfs.c b/drivers/thunderbolt/debugfs.c index e324cd899719..193e9dfc983b 100644 --- a/drivers/thunderbolt/debugfs.c +++ b/drivers/thunderbolt/debugfs.c @@ -1346,7 +1346,7 @@ static int switch_basic_regs_show(struct tb_switch *sw, struct seq_file *s) if (tb_switch_is_usb4(sw)) dwords = ARRAY_SIZE(data); else - dwords = 7; + dwords = 5; ret = tb_sw_read(sw, data, TB_CFG_SWITCH, 0, dwords); if (ret) -- cgit v1.2.3-59-g8ed1b From 002026272ba523d2ae62a13b0a9febb0cdaf576e Mon Sep 17 00:00:00 2001 From: Jiapeng Chong Date: Wed, 24 Apr 2024 10:36:05 +0800 Subject: coresight: stm: Remove duplicate linux/acpi.h header ./drivers/hwtracing/coresight/coresight-stm.c: linux/acpi.h is included more than once. Reported-by: Abaci Robot Closes: https://bugzilla.openanolis.cn/show_bug.cgi?id=8871 Signed-off-by: Jiapeng Chong Reviewed-by: James Clark Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20240424023605.90489-1-jiapeng.chong@linux.alibaba.com --- drivers/hwtracing/coresight/coresight-stm.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/hwtracing/coresight/coresight-stm.c b/drivers/hwtracing/coresight/coresight-stm.c index cbf7f17556f8..9ca04fac53fa 100644 --- a/drivers/hwtracing/coresight/coresight-stm.c +++ b/drivers/hwtracing/coresight/coresight-stm.c @@ -30,7 +30,6 @@ #include #include #include -#include #include "coresight-priv.h" #include "coresight-trace-id.h" -- cgit v1.2.3-59-g8ed1b From e8293395b9caa57e38cc05b9102d4ec7835b0a0f Mon Sep 17 00:00:00 2001 From: Jiapeng Chong Date: Wed, 24 Apr 2024 10:24:20 +0800 Subject: coresight: Remove duplicate linux/amba/bus.h header ./include/linux/coresight.h: linux/amba/bus.h is included more than once. Reported-by: Abaci Robot Closes: https://bugzilla.openanolis.cn/show_bug.cgi?id=8869 Signed-off-by: Jiapeng Chong Reviewed-by: James Clark Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20240424022420.58516-1-jiapeng.chong@linux.alibaba.com --- include/linux/coresight.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/linux/coresight.h b/include/linux/coresight.h index 653f1712eb77..f09ace92176e 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -12,7 +12,6 @@ #include #include #include -#include #include /* Peripheral id registers (0xFD0-0xFEC) */ -- cgit v1.2.3-59-g8ed1b From eb1e5037294652ddf1437f62292c0727183f11ae Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Mon, 25 Mar 2024 19:10:37 +0800 Subject: riscv: select ARCH_USE_CMPXCHG_LOCKREF Select ARCH_USE_CMPXCHG_LOCKREF to enable the cmpxchg-based lockless lockref implementation for riscv. Using Linus' test case[1] on TH1520 platform, I see a 11.2% improvement. On JH7110 platform, I see 12.0% improvement. Link: http://marc.info/?l=linux-fsdevel&m=137782380714721&w=4 [1] Signed-off-by: Jisheng Zhang Reviewed-by: Andrea Parri Link: https://lore.kernel.org/r/20240325111038.1700-2-jszhang@kernel.org Signed-off-by: Palmer Dabbelt --- arch/riscv/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index bffbd869a068..b8b96baad058 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -50,6 +50,7 @@ config RISCV select ARCH_SUPPORTS_PAGE_TABLE_CHECK if MMU select ARCH_SUPPORTS_PER_VMA_LOCK if MMU select ARCH_SUPPORTS_SHADOW_CALL_STACK if HAVE_SHADOW_CALL_STACK + select ARCH_USE_CMPXCHG_LOCKREF if 64BIT select ARCH_USE_MEMTEST select ARCH_USE_QUEUED_RWLOCKS select ARCH_USES_CFI_TRAPS if CFI_CLANG -- cgit v1.2.3-59-g8ed1b From 79d6e4eae9662b9103fecf94d52b44deca56743c Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Mon, 25 Mar 2024 19:10:38 +0800 Subject: riscv: cmpxchg: implement arch_cmpxchg64_{relaxed|acquire|release} After selecting ARCH_USE_CMPXCHG_LOCKREF, one straight futher optimization is implementing the arch_cmpxchg64_relaxed() because the lockref code does not need the cmpxchg to have barrier semantics. At the same time, implement arch_cmpxchg64_acquire and arch_cmpxchg64_release as well. However, on both TH1520 and JH7110 platforms, I didn't see obvious performance improvement with Linus' test case [1]. IMHO, this may be related with the fence and lr.d/sc.d hw implementations. In theory, lr/sc without fence could give performance improvement over lr/sc plus fence, so add the code here to leave performance improvement room on newer HW platforms. Link: http://marc.info/?l=linux-fsdevel&m=137782380714721&w=4 [1] Signed-off-by: Jisheng Zhang Reviewed-by: Andrea Parri Link: https://lore.kernel.org/r/20240325111038.1700-3-jszhang@kernel.org Signed-off-by: Palmer Dabbelt --- arch/riscv/include/asm/cmpxchg.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/arch/riscv/include/asm/cmpxchg.h b/arch/riscv/include/asm/cmpxchg.h index 2f4726d3cfcc..6318187f426f 100644 --- a/arch/riscv/include/asm/cmpxchg.h +++ b/arch/riscv/include/asm/cmpxchg.h @@ -360,4 +360,22 @@ arch_cmpxchg_relaxed((ptr), (o), (n)); \ }) +#define arch_cmpxchg64_relaxed(ptr, o, n) \ +({ \ + BUILD_BUG_ON(sizeof(*(ptr)) != 8); \ + arch_cmpxchg_relaxed((ptr), (o), (n)); \ +}) + +#define arch_cmpxchg64_acquire(ptr, o, n) \ +({ \ + BUILD_BUG_ON(sizeof(*(ptr)) != 8); \ + arch_cmpxchg_acquire((ptr), (o), (n)); \ +}) + +#define arch_cmpxchg64_release(ptr, o, n) \ +({ \ + BUILD_BUG_ON(sizeof(*(ptr)) != 8); \ + arch_cmpxchg_release((ptr), (o), (n)); \ +}) + #endif /* _ASM_RISCV_CMPXCHG_H */ -- cgit v1.2.3-59-g8ed1b From b9511056ce5b9f98dd168271071f25792853faf8 Mon Sep 17 00:00:00 2001 From: Tanmay Shah Date: Wed, 24 Apr 2024 09:33:45 -0700 Subject: drivers: remoteproc: xlnx: Fix uninitialized tcm mode Add "else" case for default tcm mode to silent following static check: zynqmp_r5_cluster_init() error: uninitialized symbol 'tcm_mode'. Fixes: a6b974b40f94 ("drivers: remoteproc: xlnx: Add Versal and Versal-NET support") Signed-off-by: Tanmay Shah Reported-by: Dan Carpenter Link: https://lore.kernel.org/r/20240424163344.1344304-1-tanmay.shah@amd.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/xlnx_r5_remoteproc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/remoteproc/xlnx_r5_remoteproc.c b/drivers/remoteproc/xlnx_r5_remoteproc.c index d98940d7ef8f..84243d1dff9f 100644 --- a/drivers/remoteproc/xlnx_r5_remoteproc.c +++ b/drivers/remoteproc/xlnx_r5_remoteproc.c @@ -1006,6 +1006,8 @@ static int zynqmp_r5_cluster_init(struct zynqmp_r5_cluster *cluster) tcm_mode = PM_RPU_TCM_COMB; else tcm_mode = PM_RPU_TCM_SPLIT; + } else { + tcm_mode = PM_RPU_TCM_COMB; } /* -- cgit v1.2.3-59-g8ed1b From 958b9f85f8d9d884045ed4b93b2082090e617f97 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 25 Apr 2024 00:15:46 -0400 Subject: erofs_buf: store address_space instead of inode ... seeing that ->i_mapping is the only thing we want from the inode. Signed-off-by: Al Viro --- fs/erofs/data.c | 7 +++---- fs/erofs/dir.c | 2 +- fs/erofs/internal.h | 2 +- fs/erofs/namei.c | 4 ++-- fs/erofs/xattr.c | 2 +- fs/erofs/zdata.c | 2 +- 6 files changed, 9 insertions(+), 10 deletions(-) diff --git a/fs/erofs/data.c b/fs/erofs/data.c index d3c446dda2ff..e1a170e45c70 100644 --- a/fs/erofs/data.c +++ b/fs/erofs/data.c @@ -32,7 +32,6 @@ void erofs_put_metabuf(struct erofs_buf *buf) void *erofs_bread(struct erofs_buf *buf, erofs_off_t offset, enum erofs_kmap_type type) { - struct inode *inode = buf->inode; pgoff_t index = offset >> PAGE_SHIFT; struct page *page = buf->page; struct folio *folio; @@ -42,7 +41,7 @@ void *erofs_bread(struct erofs_buf *buf, erofs_off_t offset, erofs_put_metabuf(buf); nofs_flag = memalloc_nofs_save(); - folio = read_cache_folio(inode->i_mapping, index, NULL, NULL); + folio = read_cache_folio(buf->mapping, index, NULL, NULL); memalloc_nofs_restore(nofs_flag); if (IS_ERR(folio)) return folio; @@ -67,9 +66,9 @@ void *erofs_bread(struct erofs_buf *buf, erofs_off_t offset, void erofs_init_metabuf(struct erofs_buf *buf, struct super_block *sb) { if (erofs_is_fscache_mode(sb)) - buf->inode = EROFS_SB(sb)->s_fscache->inode; + buf->mapping = EROFS_SB(sb)->s_fscache->inode->i_mapping; else - buf->inode = sb->s_bdev->bd_inode; + buf->mapping = sb->s_bdev->bd_inode->i_mapping; } void *erofs_read_metabuf(struct erofs_buf *buf, struct super_block *sb, diff --git a/fs/erofs/dir.c b/fs/erofs/dir.c index 9d38f39bb4f7..2193a6710c8f 100644 --- a/fs/erofs/dir.c +++ b/fs/erofs/dir.c @@ -58,7 +58,7 @@ static int erofs_readdir(struct file *f, struct dir_context *ctx) int err = 0; bool initial = true; - buf.inode = dir; + buf.mapping = dir->i_mapping; while (ctx->pos < dirsize) { struct erofs_dirent *de; unsigned int nameoff, maxsize; diff --git a/fs/erofs/internal.h b/fs/erofs/internal.h index 9e30c67c135c..12a179818897 100644 --- a/fs/erofs/internal.h +++ b/fs/erofs/internal.h @@ -223,7 +223,7 @@ enum erofs_kmap_type { }; struct erofs_buf { - struct inode *inode; + struct address_space *mapping; struct page *page; void *base; enum erofs_kmap_type kmap_type; diff --git a/fs/erofs/namei.c b/fs/erofs/namei.c index 11afa48996a3..c94d0c1608a8 100644 --- a/fs/erofs/namei.c +++ b/fs/erofs/namei.c @@ -99,7 +99,7 @@ static void *erofs_find_target_block(struct erofs_buf *target, struct erofs_buf buf = __EROFS_BUF_INITIALIZER; struct erofs_dirent *de; - buf.inode = dir; + buf.mapping = dir->i_mapping; de = erofs_bread(&buf, erofs_pos(dir->i_sb, mid), EROFS_KMAP); if (!IS_ERR(de)) { const int nameoff = nameoff_from_disk(de->nameoff, bsz); @@ -171,7 +171,7 @@ int erofs_namei(struct inode *dir, const struct qstr *name, erofs_nid_t *nid, qn.name = name->name; qn.end = name->name + name->len; - buf.inode = dir; + buf.mapping = dir->i_mapping; ndirents = 0; de = erofs_find_target_block(&buf, dir, &qn, &ndirents); diff --git a/fs/erofs/xattr.c b/fs/erofs/xattr.c index ec233917830a..a90d7d649739 100644 --- a/fs/erofs/xattr.c +++ b/fs/erofs/xattr.c @@ -483,7 +483,7 @@ int erofs_xattr_prefixes_init(struct super_block *sb) return -ENOMEM; if (sbi->packed_inode) - buf.inode = sbi->packed_inode; + buf.mapping = sbi->packed_inode->i_mapping; else erofs_init_metabuf(&buf, sb); diff --git a/fs/erofs/zdata.c b/fs/erofs/zdata.c index 9ffdae7fcd5b..283c9c3a611d 100644 --- a/fs/erofs/zdata.c +++ b/fs/erofs/zdata.c @@ -936,7 +936,7 @@ static int z_erofs_read_fragment(struct super_block *sb, struct page *page, if (!packed_inode) return -EFSCORRUPTED; - buf.inode = packed_inode; + buf.mapping = packed_inode->i_mapping; for (; cur < end; cur += cnt, pos += cnt) { cnt = min_t(unsigned int, end - cur, sb->s_blocksize - erofs_blkoff(sb, pos)); -- cgit v1.2.3-59-g8ed1b From d100ffe5048ef10065a2dac426d27dc458d9a94a Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Tue, 23 Apr 2024 11:14:11 -0500 Subject: dmaengine: qcom: Drop hidma DT support The DT support in hidma has been broken since commit 37fa4905d22a ("dmaengine: qcom_hidma: simplify DT resource parsing") in 2018. The issue is the of_address_to_resource() calls bail out on success rather than failure. This driver is for a defunct QCom server platform where DT use was limited to start with. As it seems no one has noticed the breakage, just remove the DT support altogether. Reported-by: Dan Carpenter Signed-off-by: Rob Herring (Arm) Reviewed-by: Konrad Dybcio Reviewed-by: Jeffrey Hugo Link: https://lore.kernel.org/r/20240423161413.481670-1-robh@kernel.org Signed-off-by: Vinod Koul --- drivers/dma/qcom/hidma.c | 11 ----- drivers/dma/qcom/hidma_mgmt.c | 109 +----------------------------------------- 2 files changed, 1 insertion(+), 119 deletions(-) diff --git a/drivers/dma/qcom/hidma.c b/drivers/dma/qcom/hidma.c index 202ac95227cb..721b4ac0857a 100644 --- a/drivers/dma/qcom/hidma.c +++ b/drivers/dma/qcom/hidma.c @@ -50,7 +50,6 @@ #include #include #include -#include #include #include #include @@ -947,22 +946,12 @@ static const struct acpi_device_id hidma_acpi_ids[] = { MODULE_DEVICE_TABLE(acpi, hidma_acpi_ids); #endif -static const struct of_device_id hidma_match[] = { - {.compatible = "qcom,hidma-1.0",}, - {.compatible = "qcom,hidma-1.1", .data = (void *)(HIDMA_MSI_CAP),}, - {.compatible = "qcom,hidma-1.2", - .data = (void *)(HIDMA_MSI_CAP | HIDMA_IDENTITY_CAP),}, - {}, -}; -MODULE_DEVICE_TABLE(of, hidma_match); - static struct platform_driver hidma_driver = { .probe = hidma_probe, .remove_new = hidma_remove, .shutdown = hidma_shutdown, .driver = { .name = "hidma", - .of_match_table = hidma_match, .acpi_match_table = ACPI_PTR(hidma_acpi_ids), }, }; diff --git a/drivers/dma/qcom/hidma_mgmt.c b/drivers/dma/qcom/hidma_mgmt.c index 1d675f31252b..bb883e138ebf 100644 --- a/drivers/dma/qcom/hidma_mgmt.c +++ b/drivers/dma/qcom/hidma_mgmt.c @@ -7,12 +7,7 @@ #include #include -#include #include -#include -#include -#include -#include #include #include #include @@ -327,115 +322,13 @@ static const struct acpi_device_id hidma_mgmt_acpi_ids[] = { MODULE_DEVICE_TABLE(acpi, hidma_mgmt_acpi_ids); #endif -static const struct of_device_id hidma_mgmt_match[] = { - {.compatible = "qcom,hidma-mgmt-1.0",}, - {}, -}; -MODULE_DEVICE_TABLE(of, hidma_mgmt_match); - static struct platform_driver hidma_mgmt_driver = { .probe = hidma_mgmt_probe, .driver = { .name = "hidma-mgmt", - .of_match_table = hidma_mgmt_match, .acpi_match_table = ACPI_PTR(hidma_mgmt_acpi_ids), }, }; -#if defined(CONFIG_OF) && defined(CONFIG_OF_IRQ) -static int object_counter; - -static int __init hidma_mgmt_of_populate_channels(struct device_node *np) -{ - struct platform_device *pdev_parent = of_find_device_by_node(np); - struct platform_device_info pdevinfo; - struct device_node *child; - struct resource *res; - int ret = 0; - - /* allocate a resource array */ - res = kcalloc(3, sizeof(*res), GFP_KERNEL); - if (!res) - return -ENOMEM; - - for_each_available_child_of_node(np, child) { - struct platform_device *new_pdev; - - ret = of_address_to_resource(child, 0, &res[0]); - if (!ret) - goto out; - - ret = of_address_to_resource(child, 1, &res[1]); - if (!ret) - goto out; - - ret = of_irq_to_resource(child, 0, &res[2]); - if (ret <= 0) - goto out; - - memset(&pdevinfo, 0, sizeof(pdevinfo)); - pdevinfo.fwnode = &child->fwnode; - pdevinfo.parent = pdev_parent ? &pdev_parent->dev : NULL; - pdevinfo.name = child->name; - pdevinfo.id = object_counter++; - pdevinfo.res = res; - pdevinfo.num_res = 3; - pdevinfo.data = NULL; - pdevinfo.size_data = 0; - pdevinfo.dma_mask = DMA_BIT_MASK(64); - new_pdev = platform_device_register_full(&pdevinfo); - if (IS_ERR(new_pdev)) { - ret = PTR_ERR(new_pdev); - goto out; - } - new_pdev->dev.of_node = child; - of_dma_configure(&new_pdev->dev, child, true); - /* - * It is assumed that calling of_msi_configure is safe on - * platforms with or without MSI support. - */ - of_msi_configure(&new_pdev->dev, child); - } - - kfree(res); - - return ret; - -out: - of_node_put(child); - kfree(res); - - return ret; -} -#endif - -static int __init hidma_mgmt_init(void) -{ -#if defined(CONFIG_OF) && defined(CONFIG_OF_IRQ) - struct device_node *child; - - for_each_matching_node(child, hidma_mgmt_match) { - /* device tree based firmware here */ - hidma_mgmt_of_populate_channels(child); - } -#endif - /* - * We do not check for return value here, as it is assumed that - * platform_driver_register must not fail. The reason for this is that - * the (potential) hidma_mgmt_of_populate_channels calls above are not - * cleaned up if it does fail, and to do this work is quite - * complicated. In particular, various calls of of_address_to_resource, - * of_irq_to_resource, platform_device_register_full, of_dma_configure, - * and of_msi_configure which then call other functions and so on, must - * be cleaned up - this is not a trivial exercise. - * - * Currently, this module is not intended to be unloaded, and there is - * no module_exit function defined which does the needed cleanup. For - * this reason, we have to assume success here. - */ - platform_driver_register(&hidma_mgmt_driver); - - return 0; -} -module_init(hidma_mgmt_init); +module_platform_driver(hidma_mgmt_driver); MODULE_LICENSE("GPL v2"); -- cgit v1.2.3-59-g8ed1b From e83cd59df0959bd9fbec76b7cff0b717ff8bc16f Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Tue, 23 Apr 2024 11:14:12 -0500 Subject: dt-bindings: dma: Drop unused QCom hidma binding The QCom hidma binding was used on a defunct QCom server platform which mainly used ACPI. DT support in the Linux driver has been broken since 2018, so it seems this binding is unused and can be dropped. Signed-off-by: Rob Herring (Arm) Acked-by: Konrad Dybcio Reviewed-by: Jeffrey Hugo Link: https://lore.kernel.org/r/20240423161413.481670-2-robh@kernel.org Signed-off-by: Vinod Koul --- .../devicetree/bindings/dma/qcom_hidma_mgmt.txt | 95 ---------------------- 1 file changed, 95 deletions(-) delete mode 100644 Documentation/devicetree/bindings/dma/qcom_hidma_mgmt.txt diff --git a/Documentation/devicetree/bindings/dma/qcom_hidma_mgmt.txt b/Documentation/devicetree/bindings/dma/qcom_hidma_mgmt.txt deleted file mode 100644 index 1ae4748730a8..000000000000 --- a/Documentation/devicetree/bindings/dma/qcom_hidma_mgmt.txt +++ /dev/null @@ -1,95 +0,0 @@ -Qualcomm Technologies HIDMA Management interface - -Qualcomm Technologies HIDMA is a high speed DMA device. It only supports -memcpy and memset capabilities. It has been designed for virtualized -environments. - -Each HIDMA HW instance consists of multiple DMA channels. These channels -share the same bandwidth. The bandwidth utilization can be partitioned -among channels based on the priority and weight assignments. - -There are only two priority levels and 15 weigh assignments possible. - -Other parameters here determine how much of the system bus this HIDMA -instance can use like maximum read/write request and number of bytes to -read/write in a single burst. - -Main node required properties: -- compatible: "qcom,hidma-mgmt-1.0"; -- reg: Address range for DMA device -- dma-channels: Number of channels supported by this DMA controller. -- max-write-burst-bytes: Maximum write burst in bytes that HIDMA can - occupy the bus for in a single transaction. A memcpy requested is - fragmented to multiples of this amount. This parameter is used while - writing into destination memory. Setting this value incorrectly can - starve other peripherals in the system. -- max-read-burst-bytes: Maximum read burst in bytes that HIDMA can - occupy the bus for in a single transaction. A memcpy request is - fragmented to multiples of this amount. This parameter is used while - reading the source memory. Setting this value incorrectly can starve - other peripherals in the system. -- max-write-transactions: This value is how many times a write burst is - applied back to back while writing to the destination before yielding - the bus. -- max-read-transactions: This value is how many times a read burst is - applied back to back while reading the source before yielding the bus. -- channel-reset-timeout-cycles: Channel reset timeout in cycles for this SOC. - Once a reset is applied to the HW, HW starts a timer for reset operation - to confirm. If reset is not completed within this time, HW reports reset - failure. - -Sub-nodes: - -HIDMA has one or more DMA channels that are used to move data from one -memory location to another. - -When the OS is not in control of the management interface (i.e. it's a guest), -the channel nodes appear on their own, not under a management node. - -Required properties: -- compatible: must contain "qcom,hidma-1.0" for initial HW or - "qcom,hidma-1.1"/"qcom,hidma-1.2" for MSI capable HW. -- reg: Addresses for the transfer and event channel -- interrupts: Should contain the event interrupt -- desc-count: Number of asynchronous requests this channel can handle -- iommus: required a iommu node - -Optional properties for MSI: -- msi-parent : See the generic MSI binding described in - devicetree/bindings/interrupt-controller/msi.txt for a description of the - msi-parent property. - -Example: - -Hypervisor OS configuration: - - hidma-mgmt@f9984000 = { - compatible = "qcom,hidma-mgmt-1.0"; - reg = <0xf9984000 0x15000>; - dma-channels = <6>; - max-write-burst-bytes = <1024>; - max-read-burst-bytes = <1024>; - max-write-transactions = <31>; - max-read-transactions = <31>; - channel-reset-timeout-cycles = <0x500>; - - hidma_24: dma-controller@5c050000 { - compatible = "qcom,hidma-1.0"; - reg = <0 0x5c050000 0x0 0x1000>, - <0 0x5c0b0000 0x0 0x1000>; - interrupts = <0 389 0>; - desc-count = <10>; - iommus = <&system_mmu>; - }; - }; - -Guest OS configuration: - - hidma_24: dma-controller@5c050000 { - compatible = "qcom,hidma-1.0"; - reg = <0 0x5c050000 0x0 0x1000>, - <0 0x5c0b0000 0x0 0x1000>; - interrupts = <0 389 0>; - desc-count = <10>; - iommus = <&system_mmu>; - }; -- cgit v1.2.3-59-g8ed1b From 77584368a0f3d9eba112c3df69f1df7f282dbfe9 Mon Sep 17 00:00:00 2001 From: Joy Zou Date: Wed, 24 Apr 2024 14:45:07 +0800 Subject: dmaengine: fsl-edma: clean up unused "fsl,imx8qm-adma" compatible string The eDMA hardware issue only exist imx8QM A0. A0 never mass production. So remove the workaround safely. Signed-off-by: Joy Zou Reviewed-by: Frank Li Link: https://lore.kernel.org/r/20240424064508.1886764-2-joy.zou@nxp.com Signed-off-by: Vinod Koul --- drivers/dma/fsl-edma-common.c | 16 ++++------------ drivers/dma/fsl-edma-common.h | 2 -- drivers/dma/fsl-edma-main.c | 8 -------- 3 files changed, 4 insertions(+), 22 deletions(-) diff --git a/drivers/dma/fsl-edma-common.c b/drivers/dma/fsl-edma-common.c index 73628eac8aad..d62f5f452a43 100644 --- a/drivers/dma/fsl-edma-common.c +++ b/drivers/dma/fsl-edma-common.c @@ -76,18 +76,10 @@ static void fsl_edma3_enable_request(struct fsl_edma_chan *fsl_chan) flags = fsl_edma_drvflags(fsl_chan); val = edma_readl_chreg(fsl_chan, ch_sbr); - /* Remote/local swapped wrongly on iMX8 QM Audio edma */ - if (flags & FSL_EDMA_DRV_QUIRK_SWAPPED) { - if (!fsl_chan->is_rxchan) - val |= EDMA_V3_CH_SBR_RD; - else - val |= EDMA_V3_CH_SBR_WR; - } else { - if (fsl_chan->is_rxchan) - val |= EDMA_V3_CH_SBR_RD; - else - val |= EDMA_V3_CH_SBR_WR; - } + if (fsl_chan->is_rxchan) + val |= EDMA_V3_CH_SBR_RD; + else + val |= EDMA_V3_CH_SBR_WR; if (fsl_chan->is_remote) val &= ~(EDMA_V3_CH_SBR_RD | EDMA_V3_CH_SBR_WR); diff --git a/drivers/dma/fsl-edma-common.h b/drivers/dma/fsl-edma-common.h index 01157912bfd5..3f93ebb890b3 100644 --- a/drivers/dma/fsl-edma-common.h +++ b/drivers/dma/fsl-edma-common.h @@ -194,8 +194,6 @@ struct fsl_edma_desc { #define FSL_EDMA_DRV_HAS_PD BIT(5) #define FSL_EDMA_DRV_HAS_CHCLK BIT(6) #define FSL_EDMA_DRV_HAS_CHMUX BIT(7) -/* imx8 QM audio edma remote local swapped */ -#define FSL_EDMA_DRV_QUIRK_SWAPPED BIT(8) /* control and status register is in tcd address space, edma3 reg layout */ #define FSL_EDMA_DRV_SPLIT_REG BIT(9) #define FSL_EDMA_DRV_BUS_8BYTE BIT(10) diff --git a/drivers/dma/fsl-edma-main.c b/drivers/dma/fsl-edma-main.c index de03148aed0b..391e4f13dfeb 100644 --- a/drivers/dma/fsl-edma-main.c +++ b/drivers/dma/fsl-edma-main.c @@ -348,13 +348,6 @@ static struct fsl_edma_drvdata imx8qm_data = { .setup_irq = fsl_edma3_irq_init, }; -static struct fsl_edma_drvdata imx8qm_audio_data = { - .flags = FSL_EDMA_DRV_QUIRK_SWAPPED | FSL_EDMA_DRV_HAS_PD | FSL_EDMA_DRV_EDMA3, - .chreg_space_sz = 0x10000, - .chreg_off = 0x10000, - .setup_irq = fsl_edma3_irq_init, -}; - static struct fsl_edma_drvdata imx8ulp_data = { .flags = FSL_EDMA_DRV_HAS_CHMUX | FSL_EDMA_DRV_HAS_CHCLK | FSL_EDMA_DRV_HAS_DMACLK | FSL_EDMA_DRV_EDMA3, @@ -396,7 +389,6 @@ static const struct of_device_id fsl_edma_dt_ids[] = { { .compatible = "fsl,ls1028a-edma", .data = &ls1028a_data}, { .compatible = "fsl,imx7ulp-edma", .data = &imx7ulp_data}, { .compatible = "fsl,imx8qm-edma", .data = &imx8qm_data}, - { .compatible = "fsl,imx8qm-adma", .data = &imx8qm_audio_data}, { .compatible = "fsl,imx8ulp-edma", .data = &imx8ulp_data}, { .compatible = "fsl,imx93-edma3", .data = &imx93_data3}, { .compatible = "fsl,imx93-edma4", .data = &imx93_data4}, -- cgit v1.2.3-59-g8ed1b From 44177a586fe463150def993de0371f1a82d3465c Mon Sep 17 00:00:00 2001 From: Joy Zou Date: Wed, 24 Apr 2024 14:45:08 +0800 Subject: dt-bindings: fsl-dma: fsl-edma: clean up unused "fsl,imx8qm-adma" compatible string The eDMA hardware issue only exist imx8QM A0. A0 never mass production. The compatible string "fsl,imx8qm-adma" is unused. So remove it safely. Signed-off-by: Joy Zou Reviewed-by: Frank Li Reviewed-by: Rob Herring (Arm) Link: https://lore.kernel.org/r/20240424064508.1886764-3-joy.zou@nxp.com Signed-off-by: Vinod Koul --- Documentation/devicetree/bindings/dma/fsl,edma.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/Documentation/devicetree/bindings/dma/fsl,edma.yaml b/Documentation/devicetree/bindings/dma/fsl,edma.yaml index 825f4715499e..cf97ea86a7a2 100644 --- a/Documentation/devicetree/bindings/dma/fsl,edma.yaml +++ b/Documentation/devicetree/bindings/dma/fsl,edma.yaml @@ -21,7 +21,6 @@ properties: - enum: - fsl,vf610-edma - fsl,imx7ulp-edma - - fsl,imx8qm-adma - fsl,imx8qm-edma - fsl,imx8ulp-edma - fsl,imx93-edma3 @@ -92,7 +91,6 @@ allOf: compatible: contains: enum: - - fsl,imx8qm-adma - fsl,imx8qm-edma - fsl,imx93-edma3 - fsl,imx93-edma4 -- cgit v1.2.3-59-g8ed1b From c01cb419104c4187f2a148f72a7dcc67e77801a5 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Tue, 23 Apr 2024 10:06:58 +0200 Subject: coresight: catu: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Fixes: 23567323857d ("coresight: catu: Move ACPI support from AMBA driver to platform driver") Signed-off-by: Uwe Kleine-König Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/16a7123efa7d97ae62a02ccbf9b39d146b066860.1713858615.git.u.kleine-koenig@pengutronix.de --- drivers/hwtracing/coresight/coresight-catu.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-catu.c b/drivers/hwtracing/coresight/coresight-catu.c index 9712be6acd26..02d9daf265d6 100644 --- a/drivers/hwtracing/coresight/coresight-catu.c +++ b/drivers/hwtracing/coresight/coresight-catu.c @@ -642,18 +642,17 @@ static int catu_platform_probe(struct platform_device *pdev) return ret; } -static int catu_platform_remove(struct platform_device *pdev) +static void catu_platform_remove(struct platform_device *pdev) { struct catu_drvdata *drvdata = dev_get_drvdata(&pdev->dev); if (WARN_ON(!drvdata)) - return -ENODEV; + return; __catu_remove(&pdev->dev); pm_runtime_disable(&pdev->dev); if (!IS_ERR_OR_NULL(drvdata->pclk)) clk_put(drvdata->pclk); - return 0; } #ifdef CONFIG_PM @@ -691,7 +690,7 @@ MODULE_DEVICE_TABLE(acpi, catu_acpi_ids); static struct platform_driver catu_platform_driver = { .probe = catu_platform_probe, - .remove = catu_platform_remove, + .remove_new = catu_platform_remove, .driver = { .name = "coresight-catu-platform", .acpi_match_table = ACPI_PTR(catu_acpi_ids), -- cgit v1.2.3-59-g8ed1b From 971c2b107b5742ef1dfa3a405cd5ee7033502d60 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Tue, 23 Apr 2024 10:06:59 +0200 Subject: coresight: debug: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Fixes: 965edae4e6a2 ("coresight: debug: Move ACPI support from AMBA driver to platform driver") Signed-off-by: Uwe Kleine-König Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/fb3d7db82a2490ace41c51b16ad17ef61549e2f6.1713858615.git.u.kleine-koenig@pengutronix.de --- drivers/hwtracing/coresight/coresight-cpu-debug.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-cpu-debug.c b/drivers/hwtracing/coresight/coresight-cpu-debug.c index 3263fc86cb66..75962dae9aa1 100644 --- a/drivers/hwtracing/coresight/coresight-cpu-debug.c +++ b/drivers/hwtracing/coresight/coresight-cpu-debug.c @@ -716,18 +716,17 @@ static int debug_platform_probe(struct platform_device *pdev) return ret; } -static int debug_platform_remove(struct platform_device *pdev) +static void debug_platform_remove(struct platform_device *pdev) { struct debug_drvdata *drvdata = dev_get_drvdata(&pdev->dev); if (WARN_ON(!drvdata)) - return -ENODEV; + return; __debug_remove(&pdev->dev); pm_runtime_disable(&pdev->dev); if (!IS_ERR_OR_NULL(drvdata->pclk)) clk_put(drvdata->pclk); - return 0; } #ifdef CONFIG_ACPI @@ -764,7 +763,7 @@ static const struct dev_pm_ops debug_dev_pm_ops = { static struct platform_driver debug_platform_driver = { .probe = debug_platform_probe, - .remove = debug_platform_remove, + .remove_new = debug_platform_remove, .driver = { .name = "coresight-debug-platform", .acpi_match_table = ACPI_PTR(debug_platform_ids), -- cgit v1.2.3-59-g8ed1b From 981d5f92ca2e33d1b0ba3e3563de52dc9661fb92 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Tue, 23 Apr 2024 10:07:00 +0200 Subject: coresight: stm: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Fixes: 057256aaacc8 ("coresight: stm: Move ACPI support from AMBA driver to platform driver") Signed-off-by: Uwe Kleine-König Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/3fefa60744fc68c9c4b40aeb69e34cda22582c4b.1713858615.git.u.kleine-koenig@pengutronix.de --- drivers/hwtracing/coresight/coresight-stm.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-stm.c b/drivers/hwtracing/coresight/coresight-stm.c index 9ca04fac53fa..e1c62820dfda 100644 --- a/drivers/hwtracing/coresight/coresight-stm.c +++ b/drivers/hwtracing/coresight/coresight-stm.c @@ -1013,18 +1013,17 @@ static int stm_platform_probe(struct platform_device *pdev) return ret; } -static int stm_platform_remove(struct platform_device *pdev) +static void stm_platform_remove(struct platform_device *pdev) { struct stm_drvdata *drvdata = dev_get_drvdata(&pdev->dev); if (WARN_ON(!drvdata)) - return -ENODEV; + return; __stm_remove(&pdev->dev); pm_runtime_disable(&pdev->dev); if (!IS_ERR_OR_NULL(drvdata->pclk)) clk_put(drvdata->pclk); - return 0; } #ifdef CONFIG_ACPI @@ -1037,7 +1036,7 @@ MODULE_DEVICE_TABLE(acpi, stm_acpi_ids); static struct platform_driver stm_platform_driver = { .probe = stm_platform_probe, - .remove = stm_platform_remove, + .remove_new = stm_platform_remove, .driver = { .name = "coresight-stm-platform", .acpi_match_table = ACPI_PTR(stm_acpi_ids), -- cgit v1.2.3-59-g8ed1b From 38a38da447579f683114edb1c8254491b4176853 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Tue, 23 Apr 2024 10:07:01 +0200 Subject: coresight: tmc: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Fixes: 70750e257aab ("coresight: tmc: Move ACPI support from AMBA driver to platform driver") Signed-off-by: Uwe Kleine-König Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/3cf26d85a8d45f0efb07e07f3307a1b435ebf61e.1713858615.git.u.kleine-koenig@pengutronix.de --- drivers/hwtracing/coresight/coresight-tmc-core.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-tmc-core.c b/drivers/hwtracing/coresight/coresight-tmc-core.c index c9aaf3567565..4b50d043ce04 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-core.c +++ b/drivers/hwtracing/coresight/coresight-tmc-core.c @@ -659,18 +659,17 @@ static int tmc_platform_probe(struct platform_device *pdev) return ret; } -static int tmc_platform_remove(struct platform_device *pdev) +static void tmc_platform_remove(struct platform_device *pdev) { struct tmc_drvdata *drvdata = dev_get_drvdata(&pdev->dev); if (WARN_ON(!drvdata)) - return -ENODEV; + return; __tmc_remove(&pdev->dev); pm_runtime_disable(&pdev->dev); if (!IS_ERR_OR_NULL(drvdata->pclk)) clk_put(drvdata->pclk); - return 0; } #ifdef CONFIG_PM @@ -708,7 +707,7 @@ MODULE_DEVICE_TABLE(acpi, tmc_acpi_ids); static struct platform_driver tmc_platform_driver = { .probe = tmc_platform_probe, - .remove = tmc_platform_remove, + .remove_new = tmc_platform_remove, .driver = { .name = "coresight-tmc-platform", .acpi_match_table = ACPI_PTR(tmc_acpi_ids), -- cgit v1.2.3-59-g8ed1b From ba8c06fe7e16ddfd44ece7fabd9af2dc2e6d49e7 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Tue, 23 Apr 2024 10:07:02 +0200 Subject: coresight: tpiu: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Fixes: 3d83d4d4904a ("coresight: tpiu: Move ACPI support from AMBA driver to platform driver") Signed-off-by: Uwe Kleine-König Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/ad5e0d3ec081444a5ad04a7be277dde3afcb696b.1713858615.git.u.kleine-koenig@pengutronix.de --- drivers/hwtracing/coresight/coresight-tpiu.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-tpiu.c b/drivers/hwtracing/coresight/coresight-tpiu.c index 6bf3039839c1..6ecde7d4a25d 100644 --- a/drivers/hwtracing/coresight/coresight-tpiu.c +++ b/drivers/hwtracing/coresight/coresight-tpiu.c @@ -285,18 +285,17 @@ static int tpiu_platform_probe(struct platform_device *pdev) return ret; } -static int tpiu_platform_remove(struct platform_device *pdev) +static void tpiu_platform_remove(struct platform_device *pdev) { struct tpiu_drvdata *drvdata = dev_get_drvdata(&pdev->dev); if (WARN_ON(!drvdata)) - return -ENODEV; + return; __tpiu_remove(&pdev->dev); pm_runtime_disable(&pdev->dev); if (!IS_ERR_OR_NULL(drvdata->pclk)) clk_put(drvdata->pclk); - return 0; } #ifdef CONFIG_ACPI @@ -309,7 +308,7 @@ MODULE_DEVICE_TABLE(acpi, tpiu_acpi_ids); static struct platform_driver tpiu_platform_driver = { .probe = tpiu_platform_probe, - .remove = tpiu_platform_remove, + .remove_new = tpiu_platform_remove, .driver = { .name = "coresight-tpiu-platform", .acpi_match_table = ACPI_PTR(tpiu_acpi_ids), -- cgit v1.2.3-59-g8ed1b From 458bb56d53c9758ef873b4f373660b1f02b98d86 Mon Sep 17 00:00:00 2001 From: Frank Li Date: Fri, 19 Apr 2024 11:07:27 -0400 Subject: dt-bindings: fsl-imx-sdma: Add I2C peripheral types ID Add peripheral types ID 27 for I2C because sdma firmware (sdma-6q: v3.6, sdma-7d: v4.6) support I2C DMA transfer. Acked-by: Krzysztof Kozlowski Signed-off-by: Frank Li Link: https://lore.kernel.org/r/20240419150729.1071904-1-Frank.Li@nxp.com Signed-off-by: Vinod Koul --- Documentation/devicetree/bindings/dma/fsl,imx-sdma.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/dma/fsl,imx-sdma.yaml b/Documentation/devicetree/bindings/dma/fsl,imx-sdma.yaml index 37135fa024f9..738b25b88b37 100644 --- a/Documentation/devicetree/bindings/dma/fsl,imx-sdma.yaml +++ b/Documentation/devicetree/bindings/dma/fsl,imx-sdma.yaml @@ -94,6 +94,7 @@ properties: - SAI: 24 - Multi SAI: 25 - HDMI Audio: 26 + - I2C: 27 The third cell: transfer priority ID enum: -- cgit v1.2.3-59-g8ed1b From 1cb49f389d5985bd9ad6ef37f856f368c3120f77 Mon Sep 17 00:00:00 2001 From: Frank Li Date: Fri, 19 Apr 2024 11:07:28 -0400 Subject: dmaengine: imx-sdma: utilize compiler to calculate ADDRS_ARRAY_SIZE_V The macros SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V actually related with the struct sdma_script_start_addrs. struct sdma_script_start_addrs { ... /* End of v1 array */ ... /* End of v2 array */ ... /* End of v3 array */ ... /* End of v4 array */ }; When add new field of sdma_script_start_addrs, it is easy to miss update SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V. Employ offsetof for SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V macros instead of hardcoding numbers. the preprocessing stage will calculate the size for each version automatically. Signed-off-by: Frank Li Link: https://lore.kernel.org/r/20240419150729.1071904-2-Frank.Li@nxp.com Signed-off-by: Vinod Koul --- drivers/dma/imx-sdma.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index f68ab34a3c88..4a4d44ed03c8 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c @@ -240,11 +240,11 @@ struct sdma_script_start_addrs { s32 utra_addr; s32 ram_code_start_addr; /* End of v1 array */ - s32 mcu_2_ssish_addr; + union { s32 v1_end; s32 mcu_2_ssish_addr; }; s32 ssish_2_mcu_addr; s32 hdmi_dma_addr; /* End of v2 array */ - s32 zcanfd_2_mcu_addr; + union { s32 v2_end; s32 zcanfd_2_mcu_addr; }; s32 zqspi_2_mcu_addr; s32 mcu_2_ecspi_addr; s32 mcu_2_sai_addr; @@ -252,8 +252,9 @@ struct sdma_script_start_addrs { s32 uart_2_mcu_rom_addr; s32 uartsh_2_mcu_rom_addr; /* End of v3 array */ - s32 mcu_2_zqspi_addr; + union { s32 v3_end; s32 mcu_2_zqspi_addr; }; /* End of v4 array */ + s32 v4_end[0]; }; /* @@ -1915,10 +1916,17 @@ static void sdma_issue_pending(struct dma_chan *chan) spin_unlock_irqrestore(&sdmac->vc.lock, flags); } -#define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1 34 -#define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V2 38 -#define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V3 45 -#define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V4 46 +#define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1 \ +(offsetof(struct sdma_script_start_addrs, v1_end) / sizeof(s32)) + +#define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V2 \ +(offsetof(struct sdma_script_start_addrs, v2_end) / sizeof(s32)) + +#define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V3 \ +(offsetof(struct sdma_script_start_addrs, v3_end) / sizeof(s32)) + +#define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V4 \ +(offsetof(struct sdma_script_start_addrs, v4_end) / sizeof(s32)) static void sdma_add_scripts(struct sdma_engine *sdma, const struct sdma_script_start_addrs *addr) -- cgit v1.2.3-59-g8ed1b From d850b5bae0f5e435360edf0474ff446622f0d899 Mon Sep 17 00:00:00 2001 From: Robin Gong Date: Fri, 19 Apr 2024 11:07:29 -0400 Subject: dmaengine: imx-sdma: Add i2c dma support New sdma script (sdma-6q: v3.6, sdma-7d: v4.6) support i2c at imx8mp and imx6ull. So add I2C dma support. Signed-off-by: Robin Gong Acked-by: Clark Wang Reviewed-by: Joy Zou Reviewed-by: Daniel Baluta Signed-off-by: Frank Li Link: https://lore.kernel.org/r/20240419150729.1071904-3-Frank.Li@nxp.com Signed-off-by: Vinod Koul --- drivers/dma/imx-sdma.c | 7 +++++++ include/linux/dma/imx-dma.h | 1 + 2 files changed, 8 insertions(+) diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index 4a4d44ed03c8..003e1580b902 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c @@ -251,6 +251,8 @@ struct sdma_script_start_addrs { s32 sai_2_mcu_addr; s32 uart_2_mcu_rom_addr; s32 uartsh_2_mcu_rom_addr; + s32 i2c_2_mcu_addr; + s32 mcu_2_i2c_addr; /* End of v3 array */ union { s32 v3_end; s32 mcu_2_zqspi_addr; }; /* End of v4 array */ @@ -1082,6 +1084,11 @@ static int sdma_get_pc(struct sdma_channel *sdmac, per_2_emi = sdma->script_addrs->sai_2_mcu_addr; emi_2_per = sdma->script_addrs->mcu_2_sai_addr; break; + case IMX_DMATYPE_I2C: + per_2_emi = sdma->script_addrs->i2c_2_mcu_addr; + emi_2_per = sdma->script_addrs->mcu_2_i2c_addr; + sdmac->is_ram_script = true; + break; case IMX_DMATYPE_HDMI: emi_2_per = sdma->script_addrs->hdmi_dma_addr; sdmac->is_ram_script = true; diff --git a/include/linux/dma/imx-dma.h b/include/linux/dma/imx-dma.h index cfec5f946e23..76a8de9ae151 100644 --- a/include/linux/dma/imx-dma.h +++ b/include/linux/dma/imx-dma.h @@ -41,6 +41,7 @@ enum sdma_peripheral_type { IMX_DMATYPE_SAI, /* SAI */ IMX_DMATYPE_MULTI_SAI, /* MULTI FIFOs For Audio */ IMX_DMATYPE_HDMI, /* HDMI Audio */ + IMX_DMATYPE_I2C, /* I2C */ }; enum imx_dma_prio { -- cgit v1.2.3-59-g8ed1b From 39def87bc7cae8ddfd6703051fc59931f152a2cb Mon Sep 17 00:00:00 2001 From: Frank Li Date: Thu, 18 Apr 2024 14:58:49 -0400 Subject: dmaengine: fsl-dpaa2-qdma: Fix kernel-doc check warning Fix all kernel-doc warnings under drivers/dma/fsl-dpaa2-qdma. ./scripts/kernel-doc -v -none drivers/dma/fsl-dpaa2-qdma/* drivers/dma/fsl-dpaa2-qdma/dpdmai.c:262: warning: Function parameter or struct member 'queue_idx' not described in 'dpdmai_set_rx_queue' drivers/dma/fsl-dpaa2-qdma/dpdmai.c:339: warning: Excess function parameter 'fqid' description in 'dpdmai_get_tx_queue' ... Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202404190019.t4IhmbHh-lkp@intel.com/ Signed-off-by: Frank Li Link: https://lore.kernel.org/r/20240418185851.3221726-1-Frank.Li@nxp.com Signed-off-by: Vinod Koul --- drivers/dma/fsl-dpaa2-qdma/dpdmai.c | 5 ++++- drivers/dma/fsl-dpaa2-qdma/dpdmai.h | 15 +++++++-------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/drivers/dma/fsl-dpaa2-qdma/dpdmai.c b/drivers/dma/fsl-dpaa2-qdma/dpdmai.c index a824450fe19c..36897b41ee7e 100644 --- a/drivers/dma/fsl-dpaa2-qdma/dpdmai.c +++ b/drivers/dma/fsl-dpaa2-qdma/dpdmai.c @@ -251,6 +251,7 @@ EXPORT_SYMBOL_GPL(dpdmai_get_attributes); * @mc_io: Pointer to MC portal's I/O object * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' * @token: Token of DPDMAI object + * @queue_idx: DMA queue index * @priority: Select the queue relative to number of * priorities configured at DPDMAI creation * @cfg: Rx queue configuration @@ -286,6 +287,7 @@ EXPORT_SYMBOL_GPL(dpdmai_set_rx_queue); * @mc_io: Pointer to MC portal's I/O object * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' * @token: Token of DPDMAI object + * @queue_idx: DMA Queue index * @priority: Select the queue relative to number of * priorities configured at DPDMAI creation * @attr: Returned Rx queue attributes @@ -328,9 +330,10 @@ EXPORT_SYMBOL_GPL(dpdmai_get_rx_queue); * @mc_io: Pointer to MC portal's I/O object * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' * @token: Token of DPDMAI object + * @queue_idx: DMA queue index * @priority: Select the queue relative to number of * priorities configured at DPDMAI creation - * @fqid: Returned Tx queue + * @attr: Returned DMA Tx queue attributes * * Return: '0' on Success; Error code otherwise. */ diff --git a/drivers/dma/fsl-dpaa2-qdma/dpdmai.h b/drivers/dma/fsl-dpaa2-qdma/dpdmai.h index 1efca2a30533..3fe7d8327366 100644 --- a/drivers/dma/fsl-dpaa2-qdma/dpdmai.h +++ b/drivers/dma/fsl-dpaa2-qdma/dpdmai.h @@ -45,25 +45,26 @@ * Contains initialization APIs and runtime control APIs for DPDMAI */ -/** +/* * Maximum number of Tx/Rx priorities per DPDMAI object */ #define DPDMAI_PRIO_NUM 2 /* DPDMAI queue modification options */ -/** +/* * Select to modify the user's context associated with the queue */ #define DPDMAI_QUEUE_OPT_USER_CTX 0x1 -/** +/* * Select to modify the queue's destination */ #define DPDMAI_QUEUE_OPT_DEST 0x2 /** * struct dpdmai_cfg - Structure representing DPDMAI configuration + * @num_queues: Number of the DMA queues * @priorities: Priorities for the DMA hardware processing; valid priorities are * configured with values 1-8; the entry following last valid entry * should be configured with 0 @@ -77,15 +78,13 @@ struct dpdmai_cfg { * struct dpdmai_attr - Structure representing DPDMAI attributes * @id: DPDMAI object ID * @version: DPDMAI version + * @version.major: DPDMAI major version + * @version.minor: DPDMAI minor version * @num_of_priorities: number of priorities + * @num_of_queues: number of the DMA queues */ struct dpdmai_attr { int id; - /** - * struct version - DPDMAI version - * @major: DPDMAI major version - * @minor: DPDMAI minor version - */ struct { u16 major; u16 minor; -- cgit v1.2.3-59-g8ed1b From 9c21bbfa30ec14f8dcf24e7f26fe72368960975c Mon Sep 17 00:00:00 2001 From: Frank Li Date: Wed, 17 Apr 2024 11:24:56 -0400 Subject: dt-bindings: dma: fsl-edma: remove 'clocks' from required fsl,imx8qm-adma and fsl,imx8qm-edma don't require 'clocks'. Remove it from required and add 'if' block for other compatible string to keep the same restrictions. Acked-by: Krzysztof Kozlowski Signed-off-by: Frank Li Link: https://lore.kernel.org/r/20240417152457.361340-1-Frank.Li@nxp.com Signed-off-by: Vinod Koul --- Documentation/devicetree/bindings/dma/fsl,edma.yaml | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/dma/fsl,edma.yaml b/Documentation/devicetree/bindings/dma/fsl,edma.yaml index cf97ea86a7a2..12c54bcf58ca 100644 --- a/Documentation/devicetree/bindings/dma/fsl,edma.yaml +++ b/Documentation/devicetree/bindings/dma/fsl,edma.yaml @@ -81,7 +81,6 @@ required: - compatible - reg - interrupts - - clocks - dma-channels allOf: @@ -185,6 +184,22 @@ allOf: "#dma-cells": const: 3 + - if: + properties: + compatible: + contains: + enum: + - fsl,vf610-edma + - fsl,imx7ulp-edma + - fsl,imx93-edma3 + - fsl,imx93-edma4 + - fsl,imx95-edma5 + - fsl,imx8ulp-edma + - fsl,ls1028a-edma + then: + required: + - clocks + unevaluatedProperties: false examples: -- cgit v1.2.3-59-g8ed1b From 167ec660c247ea4c71a059290b50c100659d6e86 Mon Sep 17 00:00:00 2001 From: Frank Li Date: Wed, 17 Apr 2024 11:24:57 -0400 Subject: dt-bindings: dma: fsl-edma: allow 'power-domains' property Allow 'power-domains' property because i.MX8DXL i.MX8QM and i.MX8QXP need it. EDMA supports each power-domain for each dma channel. So minItems and maxItems align 'dma-channels'. Change fsl,imx93-edma3 example to fsl,imx8qm-edma to reflect this variants. Fixed below DTB_CHECK warning: dma-controller@599f0000: Unevaluated properties are not allowed ('power-domains' was unexpected) Signed-off-by: Frank Li Reviewed-by: Rob Herring (Arm) Link: https://lore.kernel.org/r/20240417152457.361340-2-Frank.Li@nxp.com Signed-off-by: Vinod Koul --- .../devicetree/bindings/dma/fsl,edma.yaml | 80 ++++++++++++---------- 1 file changed, 42 insertions(+), 38 deletions(-) diff --git a/Documentation/devicetree/bindings/dma/fsl,edma.yaml b/Documentation/devicetree/bindings/dma/fsl,edma.yaml index 12c54bcf58ca..acfb4b2ee7a9 100644 --- a/Documentation/devicetree/bindings/dma/fsl,edma.yaml +++ b/Documentation/devicetree/bindings/dma/fsl,edma.yaml @@ -70,6 +70,13 @@ properties: minItems: 1 maxItems: 33 + power-domains: + description: + The number of power domains matches the number of channels, arranged + in ascending order according to their associated DMA channels. + minItems: 1 + maxItems: 64 + big-endian: description: | If present registers and hardware scatter/gather descriptors of the @@ -200,6 +207,20 @@ allOf: required: - clocks + - if: + properties: + compatible: + contains: + enum: + - fsl,imx8qm-adma + - fsl,imx8qm-edma + then: + required: + - power-domains + else: + properties: + power-domains: false + unevaluatedProperties: false examples: @@ -255,44 +276,27 @@ examples: - | #include - #include + #include - dma-controller@44000000 { - compatible = "fsl,imx93-edma3"; - reg = <0x44000000 0x200000>; + dma-controller@5a9f0000 { + compatible = "fsl,imx8qm-edma"; + reg = <0x5a9f0000 0x90000>; #dma-cells = <3>; - dma-channels = <31>; - interrupts = , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - ; - clocks = <&clk IMX93_CLK_EDMA1_GATE>; - clock-names = "dma"; + dma-channels = <8>; + interrupts = , + , + , + , + , + , + , + ; + power-domains = <&pd IMX_SC_R_DMA_3_CH0>, + <&pd IMX_SC_R_DMA_3_CH1>, + <&pd IMX_SC_R_DMA_3_CH2>, + <&pd IMX_SC_R_DMA_3_CH3>, + <&pd IMX_SC_R_DMA_3_CH4>, + <&pd IMX_SC_R_DMA_3_CH5>, + <&pd IMX_SC_R_DMA_3_CH6>, + <&pd IMX_SC_R_DMA_3_CH7>; }; -- cgit v1.2.3-59-g8ed1b From 700b2e1eccb4490752227d4339c3d2c3d52d06a7 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 10 Apr 2024 19:03:17 +0200 Subject: dmaengine: xilinx: xdma: fix module autoloading Add MODULE_DEVICE_TABLE(), so the module could be properly autoloaded based on the alias from of_device_id table. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240410170317.248715-2-krzk@kernel.org Signed-off-by: Vinod Koul --- drivers/dma/xilinx/xdma.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/dma/xilinx/xdma.c b/drivers/dma/xilinx/xdma.c index 170017ff2aad..36e3f84a31fc 100644 --- a/drivers/dma/xilinx/xdma.c +++ b/drivers/dma/xilinx/xdma.c @@ -1295,6 +1295,7 @@ static const struct platform_device_id xdma_id_table[] = { { "xdma", 0}, { }, }; +MODULE_DEVICE_TABLE(platform, xdma_id_table); static struct platform_driver xdma_driver = { .driver = { -- cgit v1.2.3-59-g8ed1b From 17553ba8e19dee8770b3dcc597d49dcc3418f3b0 Mon Sep 17 00:00:00 2001 From: Qiang Yu Date: Wed, 24 Apr 2024 11:21:53 +0800 Subject: bus: mhi: host: Add sysfs entry to force device to enter EDL Add sysfs entry to allow users of MHI bus to force device to enter EDL (Emergency Download) mode to download the device firmware. Since there is no guarantee that all the devices will support EDL mode, the sysfs entry is kept as an optional one and will appear only for the supported devices. Controllers supporting the EDL mode are expected to provide edl_trigger() callback that puts the device into EDL mode. Signed-off-by: Qiang Yu Reviewed-by: Jeffrey Hugo Reviewed-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/1713928915-18229-2-git-send-email-quic_qianyu@quicinc.com [mani: fixed the kernel version and reworded the commit message] Signed-off-by: Manivannan Sadhasivam --- Documentation/ABI/stable/sysfs-bus-mhi | 13 +++++++++++++ drivers/bus/mhi/host/init.c | 33 +++++++++++++++++++++++++++++++++ include/linux/mhi.h | 2 ++ 3 files changed, 48 insertions(+) diff --git a/Documentation/ABI/stable/sysfs-bus-mhi b/Documentation/ABI/stable/sysfs-bus-mhi index 1a47f9e0cc84..8b9698fa0beb 100644 --- a/Documentation/ABI/stable/sysfs-bus-mhi +++ b/Documentation/ABI/stable/sysfs-bus-mhi @@ -29,3 +29,16 @@ Description: Initiates a SoC reset on the MHI controller. A SoC reset is This can be useful as a method of recovery if the device is non-responsive, or as a means of loading new firmware as a system administration task. + +What: /sys/bus/mhi/devices/.../trigger_edl +Date: April 2024 +KernelVersion: 6.10 +Contact: mhi@lists.linux.dev +Description: Writing a non-zero value to this file will force devices to + enter EDL (Emergency Download) mode. This entry only exists for + devices capable of entering the EDL mode using the standard EDL + triggering mechanism defined in the MHI spec v1.2. Once in EDL + mode, the flash programmer image can be downloaded to the + device to enter the flash programmer execution environment. + This can be useful if user wants to use QDL (Qualcomm Download, + which is used to download firmware over EDL) to update firmware. diff --git a/drivers/bus/mhi/host/init.c b/drivers/bus/mhi/host/init.c index 44f934981de8..7104c1856987 100644 --- a/drivers/bus/mhi/host/init.c +++ b/drivers/bus/mhi/host/init.c @@ -127,6 +127,30 @@ static ssize_t soc_reset_store(struct device *dev, } static DEVICE_ATTR_WO(soc_reset); +static ssize_t trigger_edl_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct mhi_device *mhi_dev = to_mhi_device(dev); + struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl; + unsigned long val; + int ret; + + ret = kstrtoul(buf, 10, &val); + if (ret < 0) + return ret; + + if (!val) + return -EINVAL; + + ret = mhi_cntrl->edl_trigger(mhi_cntrl); + if (ret) + return ret; + + return count; +} +static DEVICE_ATTR_WO(trigger_edl); + static struct attribute *mhi_dev_attrs[] = { &dev_attr_serial_number.attr, &dev_attr_oem_pk_hash.attr, @@ -1018,6 +1042,12 @@ int mhi_register_controller(struct mhi_controller *mhi_cntrl, if (ret) goto err_release_dev; + if (mhi_cntrl->edl_trigger) { + ret = sysfs_create_file(&mhi_dev->dev.kobj, &dev_attr_trigger_edl.attr); + if (ret) + goto err_release_dev; + } + mhi_cntrl->mhi_dev = mhi_dev; mhi_create_debugfs(mhi_cntrl); @@ -1051,6 +1081,9 @@ void mhi_unregister_controller(struct mhi_controller *mhi_cntrl) mhi_deinit_free_irq(mhi_cntrl); mhi_destroy_debugfs(mhi_cntrl); + if (mhi_cntrl->edl_trigger) + sysfs_remove_file(&mhi_dev->dev.kobj, &dev_attr_trigger_edl.attr); + destroy_workqueue(mhi_cntrl->hiprio_wq); kfree(mhi_cntrl->mhi_cmd); kfree(mhi_cntrl->mhi_event); diff --git a/include/linux/mhi.h b/include/linux/mhi.h index cde01e133a1b..d968e1ab44dc 100644 --- a/include/linux/mhi.h +++ b/include/linux/mhi.h @@ -353,6 +353,7 @@ struct mhi_controller_config { * @read_reg: Read a MHI register via the physical link (required) * @write_reg: Write a MHI register via the physical link (required) * @reset: Controller specific reset function (optional) + * @edl_trigger: CB function to trigger EDL mode (optional) * @buffer_len: Bounce buffer length * @index: Index of the MHI controller instance * @bounce_buf: Use of bounce buffer @@ -435,6 +436,7 @@ struct mhi_controller { void (*write_reg)(struct mhi_controller *mhi_cntrl, void __iomem *addr, u32 val); void (*reset)(struct mhi_controller *mhi_cntrl); + int (*edl_trigger)(struct mhi_controller *mhi_cntrl); size_t buffer_len; int index; -- cgit v1.2.3-59-g8ed1b From 553f94fc7667259e47a9318e9e5702c9a814d637 Mon Sep 17 00:00:00 2001 From: Qiang Yu Date: Wed, 24 Apr 2024 11:21:54 +0800 Subject: bus: mhi: host: Add a new API for getting channel doorbell offset Some controllers may want to access a specific doorbell register. Hence add a new API that reads the CHDBOFF register and returns the offset of the doorbell registers from MMIO base, so that the controller can calculate the address of the specific doorbell register by adding the register offset with doorbell offset and MMIO base address. Signed-off-by: Qiang Yu Reviewed-by: Jeffrey Hugo Link: https://lore.kernel.org/r/1713928915-18229-3-git-send-email-quic_qianyu@quicinc.com [mani: reworded commit message and Kdoc] Signed-off-by: Manivannan Sadhasivam --- drivers/bus/mhi/host/init.c | 8 +++----- drivers/bus/mhi/host/main.c | 16 ++++++++++++++++ include/linux/mhi.h | 9 +++++++++ 3 files changed, 28 insertions(+), 5 deletions(-) diff --git a/drivers/bus/mhi/host/init.c b/drivers/bus/mhi/host/init.c index 7104c1856987..173f79918741 100644 --- a/drivers/bus/mhi/host/init.c +++ b/drivers/bus/mhi/host/init.c @@ -541,11 +541,9 @@ int mhi_init_mmio(struct mhi_controller *mhi_cntrl) dev_dbg(dev, "Initializing MHI registers\n"); /* Read channel db offset */ - ret = mhi_read_reg(mhi_cntrl, base, CHDBOFF, &val); - if (ret) { - dev_err(dev, "Unable to read CHDBOFF register\n"); - return -EIO; - } + ret = mhi_get_channel_doorbell_offset(mhi_cntrl, &val); + if (ret) + return ret; if (val >= mhi_cntrl->reg_len - (8 * MHI_DEV_WAKE_DB)) { dev_err(dev, "CHDB offset: 0x%x is out of range: 0x%zx\n", diff --git a/drivers/bus/mhi/host/main.c b/drivers/bus/mhi/host/main.c index 15d657af9b5b..4de75674f193 100644 --- a/drivers/bus/mhi/host/main.c +++ b/drivers/bus/mhi/host/main.c @@ -1691,3 +1691,19 @@ void mhi_unprepare_from_transfer(struct mhi_device *mhi_dev) } } EXPORT_SYMBOL_GPL(mhi_unprepare_from_transfer); + +int mhi_get_channel_doorbell_offset(struct mhi_controller *mhi_cntrl, u32 *chdb_offset) +{ + struct device *dev = &mhi_cntrl->mhi_dev->dev; + void __iomem *base = mhi_cntrl->regs; + int ret; + + ret = mhi_read_reg(mhi_cntrl, base, CHDBOFF, chdb_offset); + if (ret) { + dev_err(dev, "Unable to read CHDBOFF register\n"); + return -EIO; + } + + return 0; +} +EXPORT_SYMBOL_GPL(mhi_get_channel_doorbell_offset); diff --git a/include/linux/mhi.h b/include/linux/mhi.h index d968e1ab44dc..b573f15762f8 100644 --- a/include/linux/mhi.h +++ b/include/linux/mhi.h @@ -816,4 +816,13 @@ int mhi_queue_skb(struct mhi_device *mhi_dev, enum dma_data_direction dir, */ bool mhi_queue_is_full(struct mhi_device *mhi_dev, enum dma_data_direction dir); +/** + * mhi_get_channel_doorbell_offset - Get the channel doorbell offset + * @mhi_cntrl: MHI controller + * @chdb_offset: Read channel doorbell offset + * + * Return: 0 if the read succeeds, a negative error code otherwise + */ +int mhi_get_channel_doorbell_offset(struct mhi_controller *mhi_cntrl, u32 *chdb_offset); + #endif /* _MHI_H_ */ -- cgit v1.2.3-59-g8ed1b From 48f98496b1de132f2e056605b5330209136066dc Mon Sep 17 00:00:00 2001 From: Qiang Yu Date: Wed, 24 Apr 2024 11:21:55 +0800 Subject: bus: mhi: host: pci_generic: Add generic edl_trigger to allow devices to enter EDL mode Some of the MHI modems like SDX65 based ones are capable of entering the EDL mode as per the standard triggering mechanism defined in the MHI spec v1.2. So let's add a common mhi_pci_generic_edl_trigger() function that triggers the EDL mode in the device when user writes to the /sys/bus/mhi/devices/.../trigger_edl file. As per the spec, the EDL mode can be triggered by writing a cookie to the EDL doorbell register and then resetting the device. Devices supporting this standard way of entering EDL mode can set the mhi_pci_dev_info::edl_trigger flag. Signed-off-by: Qiang Yu Reviewed-by: Jeffrey Hugo Reviewed-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/1713928915-18229-4-git-send-email-quic_qianyu@quicinc.com [mani: reworded commit message] Signed-off-by: Manivannan Sadhasivam --- drivers/bus/mhi/host/pci_generic.c | 45 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/drivers/bus/mhi/host/pci_generic.c b/drivers/bus/mhi/host/pci_generic.c index 51639bfcfec7..08844ee79654 100644 --- a/drivers/bus/mhi/host/pci_generic.c +++ b/drivers/bus/mhi/host/pci_generic.c @@ -27,12 +27,16 @@ #define PCI_VENDOR_ID_THALES 0x1269 #define PCI_VENDOR_ID_QUECTEL 0x1eac +#define MHI_EDL_DB 91 +#define MHI_EDL_COOKIE 0xEDEDEDED + /** * struct mhi_pci_dev_info - MHI PCI device specific information * @config: MHI controller configuration * @name: name of the PCI module * @fw: firmware path (if any) * @edl: emergency download mode firmware path (if any) + * @edl_trigger: capable of triggering EDL mode in the device (if supported) * @bar_num: PCI base address register to use for MHI MMIO register space * @dma_data_width: DMA transfer word size (32 or 64 bits) * @mru_default: default MRU size for MBIM network packets @@ -44,6 +48,7 @@ struct mhi_pci_dev_info { const char *name; const char *fw; const char *edl; + bool edl_trigger; unsigned int bar_num; unsigned int dma_data_width; unsigned int mru_default; @@ -292,6 +297,7 @@ static const struct mhi_pci_dev_info mhi_qcom_sdx75_info = { .name = "qcom-sdx75m", .fw = "qcom/sdx75m/xbl.elf", .edl = "qcom/sdx75m/edl.mbn", + .edl_trigger = true, .config = &modem_qcom_v2_mhiv_config, .bar_num = MHI_PCI_DEFAULT_BAR_NUM, .dma_data_width = 32, @@ -302,6 +308,7 @@ static const struct mhi_pci_dev_info mhi_qcom_sdx65_info = { .name = "qcom-sdx65m", .fw = "qcom/sdx65m/xbl.elf", .edl = "qcom/sdx65m/edl.mbn", + .edl_trigger = true, .config = &modem_qcom_v1_mhiv_config, .bar_num = MHI_PCI_DEFAULT_BAR_NUM, .dma_data_width = 32, @@ -312,6 +319,7 @@ static const struct mhi_pci_dev_info mhi_qcom_sdx55_info = { .name = "qcom-sdx55m", .fw = "qcom/sdx55m/sbl1.mbn", .edl = "qcom/sdx55m/edl.mbn", + .edl_trigger = true, .config = &modem_qcom_v1_mhiv_config, .bar_num = MHI_PCI_DEFAULT_BAR_NUM, .dma_data_width = 32, @@ -928,6 +936,40 @@ static void health_check(struct timer_list *t) mod_timer(&mhi_pdev->health_check_timer, jiffies + HEALTH_CHECK_PERIOD); } +static int mhi_pci_generic_edl_trigger(struct mhi_controller *mhi_cntrl) +{ + void __iomem *base = mhi_cntrl->regs; + void __iomem *edl_db; + int ret; + u32 val; + + ret = mhi_device_get_sync(mhi_cntrl->mhi_dev); + if (ret) { + dev_err(mhi_cntrl->cntrl_dev, "Failed to wakeup the device\n"); + return ret; + } + + pm_wakeup_event(&mhi_cntrl->mhi_dev->dev, 0); + mhi_cntrl->runtime_get(mhi_cntrl); + + ret = mhi_get_channel_doorbell_offset(mhi_cntrl, &val); + if (ret) + goto err_get_chdb; + + edl_db = base + val + (8 * MHI_EDL_DB); + + mhi_cntrl->write_reg(mhi_cntrl, edl_db + 4, upper_32_bits(MHI_EDL_COOKIE)); + mhi_cntrl->write_reg(mhi_cntrl, edl_db, lower_32_bits(MHI_EDL_COOKIE)); + + mhi_soc_reset(mhi_cntrl); + +err_get_chdb: + mhi_cntrl->runtime_put(mhi_cntrl); + mhi_device_put(mhi_cntrl->mhi_dev); + + return ret; +} + static int mhi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { const struct mhi_pci_dev_info *info = (struct mhi_pci_dev_info *) id->driver_data; @@ -962,6 +1004,9 @@ static int mhi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) mhi_cntrl->runtime_put = mhi_pci_runtime_put; mhi_cntrl->mru = info->mru_default; + if (info->edl_trigger) + mhi_cntrl->edl_trigger = mhi_pci_generic_edl_trigger; + if (info->sideband_wake) { mhi_cntrl->wake_get = mhi_pci_wake_get_nop; mhi_cntrl->wake_put = mhi_pci_wake_put_nop; -- cgit v1.2.3-59-g8ed1b From 73cb3a35f94db723c0211ad099bce55b2155e3f0 Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Tue, 23 Apr 2024 16:08:19 +0300 Subject: PCI: Wait for Link Training==0 before starting Link retrain MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two changes were made in link retraining logic independent of each other. The commit e7e39756363a ("PCI/ASPM: Avoid link retraining race") added a check to pcie_retrain_link() to ensure no Link Training is currently active to address the Implementation Note in PCIe r6.1 sec 7.5.3.7. At that time pcie_wait_for_retrain() only checked for the Link Training (LT) bit being cleared. The commit 680e9c47a229 ("PCI: Add support for polling DLLLA to pcie_retrain_link()") generalized pcie_wait_for_retrain() into pcie_wait_for_link_status() which can wait either for LT or the Data Link Layer Link Active (DLLLA) bit with 'use_lt' argument and supporting waiting for either cleared or set using 'active' argument. In the merge commit 1abb47390350 ("Merge branch 'pci/enumeration'"), those two divergent branches converged. The merge changed LT bit checking added in the commit e7e39756363a ("PCI/ASPM: Avoid link retraining race") to now wait for completion of any ongoing Link Training using DLLLA bit being set if 'use_lt' is false. When 'use_lt' is false, the pseudo-code steps of what occurs in pcie_retrain_link(): 1. Wait for DLLLA==1 2. Trigger link to retrain 3. Wait for DLLLA==1 Step 3 waits for the link to come up from the retraining triggered by Step 2. As Step 1 is supposed to wait for any ongoing retraining to end, using DLLLA also for it does not make sense because link training being active is still indicated using LT bit, not with DLLLA. Correct the pcie_wait_for_link_status() parameters in Step 1 to only wait for LT==0 to ensure there is no ongoing Link Training. This only impacts the Target Speed quirk, which is the only case where waiting for DLLLA bit is used. It currently works in the problematic case by means of link training getting initiated by hardware repeatedly and respecting the new link parameters set by the caller, which then make training succeed and bring the link up, setting DLLLA and causing pcie_wait_for_link_status() to return success. We are not supposed to rely on luck and need to make sure that LT transitioned through the inactive state though before we initiate link training by hand via RL (Retrain Link) bit. Fixes: 1abb47390350 ("Merge branch 'pci/enumeration'") Link: https://lore.kernel.org/r/20240423130820.43824-1-ilpo.jarvinen@linux.intel.com Signed-off-by: Ilpo Järvinen Signed-off-by: Bjorn Helgaas --- drivers/pci/pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index e5f243dd4288..70b8c87055cb 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -4629,7 +4629,7 @@ int pcie_retrain_link(struct pci_dev *pdev, bool use_lt) * avoid LTSSM race as recommended in Implementation Note at the * end of PCIe r6.0.1 sec 7.5.3.7. */ - rc = pcie_wait_for_link_status(pdev, use_lt, !use_lt); + rc = pcie_wait_for_link_status(pdev, true, false); if (rc) return rc; -- cgit v1.2.3-59-g8ed1b From cdc6c4abcb313be1b7118b6e86eb99a85a626578 Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Tue, 23 Apr 2024 16:08:20 +0300 Subject: PCI: Clarify intent of LT wait MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Clarify the comment relating to the LT wait and the purpose of the check that implements the implementation note in PCIe r6.1 sec 7.5.3.7. Suggested-by: Maciej W. Rozycki Link: https://lore.kernel.org/r/20240423130820.43824-2-ilpo.jarvinen@linux.intel.com Signed-off-by: Ilpo Järvinen Signed-off-by: Bjorn Helgaas --- drivers/pci/pci.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 70b8c87055cb..5a25facb3ce7 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -4625,9 +4625,10 @@ int pcie_retrain_link(struct pci_dev *pdev, bool use_lt) /* * Ensure the updated LNKCTL parameters are used during link - * training by checking that there is no ongoing link training to - * avoid LTSSM race as recommended in Implementation Note at the - * end of PCIe r6.0.1 sec 7.5.3.7. + * training by checking that there is no ongoing link training that + * may have started before link parameters were changed, so as to + * avoid LTSSM race as recommended in Implementation Note at the end + * of PCIe r6.1 sec 7.5.3.7. */ rc = pcie_wait_for_link_status(pdev, true, false); if (rc) -- cgit v1.2.3-59-g8ed1b From bb14a6a870548d44e486c7d68d47c2114aafb395 Mon Sep 17 00:00:00 2001 From: Damien Le Moal Date: Mon, 25 Mar 2024 16:09:12 +0900 Subject: PCI/MSI: Use PCI_IRQ_INTX instead of PCI_IRQ_LEGACY In pci_alloc_irq_vectors_affinity(), use the macro PCI_IRQ_INTX instead of the now deprecated PCI_IRQ_LEGACY macro. Link: https://lore.kernel.org/r/20240325070944.3600338-2-dlemoal@kernel.org Signed-off-by: Damien Le Moal Signed-off-by: Bjorn Helgaas --- drivers/pci/msi/api.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/pci/msi/api.c b/drivers/pci/msi/api.c index be679aa5db64..dfba4d6dd535 100644 --- a/drivers/pci/msi/api.c +++ b/drivers/pci/msi/api.c @@ -213,8 +213,8 @@ EXPORT_SYMBOL(pci_disable_msix); * * %PCI_IRQ_MSIX Allow trying MSI-X vector allocations * * %PCI_IRQ_MSI Allow trying MSI vector allocations * - * * %PCI_IRQ_LEGACY Allow trying legacy INTx interrupts, if - * and only if @min_vecs == 1 + * * %PCI_IRQ_INTX Allow trying INTx interrupts, if and + * only if @min_vecs == 1 * * * %PCI_IRQ_AFFINITY Auto-manage IRQs affinity by spreading * the vectors around available CPUs @@ -279,8 +279,8 @@ int pci_alloc_irq_vectors_affinity(struct pci_dev *dev, unsigned int min_vecs, return nvecs; } - /* use legacy IRQ if allowed */ - if (flags & PCI_IRQ_LEGACY) { + /* use INTx IRQ if allowed */ + if (flags & PCI_IRQ_INTX) { if (min_vecs == 1 && dev->irq) { /* * Invoke the affinity spreading logic to ensure that -- cgit v1.2.3-59-g8ed1b From a665b0a93f3bf64b899893938c6fc4ed246ef59f Mon Sep 17 00:00:00 2001 From: Damien Le Moal Date: Mon, 25 Mar 2024 16:09:13 +0900 Subject: PCI/portdrv: Use PCI_IRQ_INTX instead of PCI_IRQ_LEGACY In the PCI Express Port Bus Driver, use the macro PCI_IRQ_INTX instead of the now deprecated PCI_IRQ_LEGACY macro. Link: https://lore.kernel.org/r/20240325070944.3600338-3-dlemoal@kernel.org Signed-off-by: Damien Le Moal Signed-off-by: Bjorn Helgaas --- drivers/pci/pcie/portdrv.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/pci/pcie/portdrv.c b/drivers/pci/pcie/portdrv.c index 14a4b89a3b83..bb65dfe43409 100644 --- a/drivers/pci/pcie/portdrv.c +++ b/drivers/pci/pcie/portdrv.c @@ -187,15 +187,15 @@ static int pcie_init_service_irqs(struct pci_dev *dev, int *irqs, int mask) * interrupt. */ if ((mask & PCIE_PORT_SERVICE_PME) && pcie_pme_no_msi()) - goto legacy_irq; + goto intx_irq; /* Try to use MSI-X or MSI if supported */ if (pcie_port_enable_irq_vec(dev, irqs, mask) == 0) return 0; -legacy_irq: - /* fall back to legacy IRQ */ - ret = pci_alloc_irq_vectors(dev, 1, 1, PCI_IRQ_LEGACY); +intx_irq: + /* fall back to INTX IRQ */ + ret = pci_alloc_irq_vectors(dev, 1, 1, PCI_IRQ_INTX); if (ret < 0) return -ENODEV; -- cgit v1.2.3-59-g8ed1b From b21f89b0c55087e11506900c763ffb7af55a48fc Mon Sep 17 00:00:00 2001 From: Damien Le Moal Date: Mon, 25 Mar 2024 16:09:14 +0900 Subject: Documentation: PCI: Use PCI_IRQ_INTX instead of PCI_IRQ_LEGACY Change all references to PCI_IRQ_LEGACY to PCI_IRQ_INTX in the PCI documentation to reflect that PCI_IRQ_LEGACY is deprecated. Link: https://lore.kernel.org/r/20240325070944.3600338-4-dlemoal@kernel.org Signed-off-by: Damien Le Moal Signed-off-by: Bjorn Helgaas --- Documentation/PCI/msi-howto.rst | 2 +- Documentation/PCI/pci.rst | 2 +- Documentation/translations/zh_CN/PCI/msi-howto.rst | 2 +- Documentation/translations/zh_CN/PCI/pci.rst | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Documentation/PCI/msi-howto.rst b/Documentation/PCI/msi-howto.rst index 783d30b7bb42..0692c9aec66f 100644 --- a/Documentation/PCI/msi-howto.rst +++ b/Documentation/PCI/msi-howto.rst @@ -103,7 +103,7 @@ min_vecs argument set to this limit, and the PCI core will return -ENOSPC if it can't meet the minimum number of vectors. The flags argument is used to specify which type of interrupt can be used -by the device and the driver (PCI_IRQ_LEGACY, PCI_IRQ_MSI, PCI_IRQ_MSIX). +by the device and the driver (PCI_IRQ_INTX, PCI_IRQ_MSI, PCI_IRQ_MSIX). A convenient short-hand (PCI_IRQ_ALL_TYPES) is also available to ask for any possible kind of interrupt. If the PCI_IRQ_AFFINITY flag is set, pci_alloc_irq_vectors() will spread the interrupts around the available CPUs. diff --git a/Documentation/PCI/pci.rst b/Documentation/PCI/pci.rst index cced568d78e9..dd7b1c0c21da 100644 --- a/Documentation/PCI/pci.rst +++ b/Documentation/PCI/pci.rst @@ -335,7 +335,7 @@ causes the PCI support to program CPU vector data into the PCI device capability registers. Many architectures, chip-sets, or BIOSes do NOT support MSI or MSI-X and a call to pci_alloc_irq_vectors with just the PCI_IRQ_MSI and PCI_IRQ_MSIX flags will fail, so try to always -specify PCI_IRQ_LEGACY as well. +specify PCI_IRQ_INTX as well. Drivers that have different interrupt handlers for MSI/MSI-X and legacy INTx should chose the right one based on the msi_enabled diff --git a/Documentation/translations/zh_CN/PCI/msi-howto.rst b/Documentation/translations/zh_CN/PCI/msi-howto.rst index 1b9b5ea790d8..95baadf767e4 100644 --- a/Documentation/translations/zh_CN/PCI/msi-howto.rst +++ b/Documentation/translations/zh_CN/PCI/msi-howto.rst @@ -88,7 +88,7 @@ MSI功能。 如果设备对最小数量的向量有要求,驱动程序可以传递一个min_vecs参数,设置为这个限制, 如果PCI核不能满足最小数量的向量,将返回-ENOSPC。 -flags参数用来指定设备和驱动程序可以使用哪种类型的中断(PCI_IRQ_LEGACY, PCI_IRQ_MSI, +flags参数用来指定设备和驱动程序可以使用哪种类型的中断(PCI_IRQ_INTX, PCI_IRQ_MSI, PCI_IRQ_MSIX)。一个方便的短语(PCI_IRQ_ALL_TYPES)也可以用来要求任何可能的中断类型。 如果PCI_IRQ_AFFINITY标志被设置,pci_alloc_irq_vectors()将把中断分散到可用的CPU上。 diff --git a/Documentation/translations/zh_CN/PCI/pci.rst b/Documentation/translations/zh_CN/PCI/pci.rst index 83c2a41d38d3..347f5c3f5ce9 100644 --- a/Documentation/translations/zh_CN/PCI/pci.rst +++ b/Documentation/translations/zh_CN/PCI/pci.rst @@ -304,7 +304,7 @@ MSI-X可以分配几个单独的向量。 的PCI_IRQ_MSI和/或PCI_IRQ_MSIX标志来启用MSI功能。这将导致PCI支持将CPU向量数 据编程到PCI设备功能寄存器中。许多架构、芯片组或BIOS不支持MSI或MSI-X,调用 ``pci_alloc_irq_vectors`` 时只使用PCI_IRQ_MSI和PCI_IRQ_MSIX标志会失败, -所以尽量也要指定 ``PCI_IRQ_LEGACY`` 。 +所以尽量也要指定 ``PCI_IRQ_INTX`` 。 对MSI/MSI-X和传统INTx有不同中断处理程序的驱动程序应该在调用 ``pci_alloc_irq_vectors`` 后根据 ``pci_dev``结构体中的 ``msi_enabled`` -- cgit v1.2.3-59-g8ed1b From 7c155fdf37bf91a5c378e94412024767bee76bea Mon Sep 17 00:00:00 2001 From: Damien Le Moal Date: Mon, 25 Mar 2024 16:09:15 +0900 Subject: ASoC: Intel: avs: Use PCI_IRQ_INTX instead of PCI_IRQ_LEGACY MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the macro PCI_IRQ_INTX instead of the deprecated PCI_IRQ_LEGACY macro. Link: https://lore.kernel.org/r/20240325070944.3600338-5-dlemoal@kernel.org Signed-off-by: Damien Le Moal Signed-off-by: Bjorn Helgaas Reviewed-by: Amadeusz Sławiński --- sound/soc/intel/avs/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/avs/core.c b/sound/soc/intel/avs/core.c index d7f8940099ce..69818e4b43da 100644 --- a/sound/soc/intel/avs/core.c +++ b/sound/soc/intel/avs/core.c @@ -343,7 +343,7 @@ static int avs_hdac_acquire_irq(struct avs_dev *adev) int ret; /* request one and check that we only got one interrupt */ - ret = pci_alloc_irq_vectors(pci, 1, 1, PCI_IRQ_MSI | PCI_IRQ_LEGACY); + ret = pci_alloc_irq_vectors(pci, 1, 1, PCI_IRQ_MSI | PCI_IRQ_INTX); if (ret != 1) { dev_err(adev->dev, "Failed to allocate IRQ vector: %d\n", ret); return ret; -- cgit v1.2.3-59-g8ed1b From ce1d9ceaf83d7389dcc7e18ae304911a5c7dbcd9 Mon Sep 17 00:00:00 2001 From: Damien Le Moal Date: Mon, 25 Mar 2024 16:09:16 +0900 Subject: usb: hcd-pci: Use PCI_IRQ_INTX instead of PCI_IRQ_LEGACY Use the macro PCI_IRQ_INTX instead of the deprecated PCI_IRQ_LEGACY macro. Link: https://lore.kernel.org/r/20240325070944.3600338-6-dlemoal@kernel.org Signed-off-by: Damien Le Moal Signed-off-by: Bjorn Helgaas Acked-by: Greg Kroah-Hartman --- drivers/usb/core/hcd-pci.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c index ee3156f49533..a08f3f228e6d 100644 --- a/drivers/usb/core/hcd-pci.c +++ b/drivers/usb/core/hcd-pci.c @@ -189,7 +189,8 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct hc_driver *driver) * make sure irq setup is not touched for xhci in generic hcd code */ if ((driver->flags & HCD_MASK) < HCD_USB3) { - retval = pci_alloc_irq_vectors(dev, 1, 1, PCI_IRQ_LEGACY | PCI_IRQ_MSI); + retval = pci_alloc_irq_vectors(dev, 1, 1, + PCI_IRQ_INTX | PCI_IRQ_MSI); if (retval < 0) { dev_err(&dev->dev, "Found HC with no IRQ. Check BIOS/PCI %s setup!\n", -- cgit v1.2.3-59-g8ed1b From 64474e8817aadbf4adacb20d8c8368e232da852a Mon Sep 17 00:00:00 2001 From: Damien Le Moal Date: Mon, 25 Mar 2024 16:09:17 +0900 Subject: tty: 8250_pci: Use PCI_IRQ_INTX instead of PCI_IRQ_LEGACY Use the macro PCI_IRQ_INTX instead of the deprecated PCI_IRQ_LEGACY macro. Link: https://lore.kernel.org/r/20240325070944.3600338-7-dlemoal@kernel.org Signed-off-by: Damien Le Moal Signed-off-by: Bjorn Helgaas Acked-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 0d35c77fad9e..400b16c0336c 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -4108,7 +4108,7 @@ pciserial_init_ports(struct pci_dev *dev, const struct pciserial_board *board) rc = pci_alloc_irq_vectors(dev, 1, 1, PCI_IRQ_ALL_TYPES); } else { pci_dbg(dev, "Using legacy interrupts\n"); - rc = pci_alloc_irq_vectors(dev, 1, 1, PCI_IRQ_LEGACY); + rc = pci_alloc_irq_vectors(dev, 1, 1, PCI_IRQ_INTX); } if (rc < 0) { kfree(priv); -- cgit v1.2.3-59-g8ed1b From 81943949f88008e0cb88fe6803ea415d39d94d6d Mon Sep 17 00:00:00 2001 From: Damien Le Moal Date: Mon, 25 Mar 2024 16:09:18 +0900 Subject: platform/x86: intel_ips: Use PCI_IRQ_INTX instead of PCI_IRQ_LEGACY Use the macro PCI_IRQ_INTX instead of the deprecated PCI_IRQ_LEGACY macro. Link: https://lore.kernel.org/r/20240325070944.3600338-8-dlemoal@kernel.org Signed-off-by: Damien Le Moal Signed-off-by: Bjorn Helgaas Acked-by: Hans de Goede --- drivers/platform/x86/intel_ips.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/x86/intel_ips.c b/drivers/platform/x86/intel_ips.c index ba38649cc142..73ec4460a151 100644 --- a/drivers/platform/x86/intel_ips.c +++ b/drivers/platform/x86/intel_ips.c @@ -1505,7 +1505,7 @@ static int ips_probe(struct pci_dev *dev, const struct pci_device_id *id) * IRQ handler for ME interaction * Note: don't use MSI here as the PCH has bugs. */ - ret = pci_alloc_irq_vectors(dev, 1, 1, PCI_IRQ_LEGACY); + ret = pci_alloc_irq_vectors(dev, 1, 1, PCI_IRQ_INTX); if (ret < 0) return ret; -- cgit v1.2.3-59-g8ed1b From 895e51977d91e0727dd8abc46dee96903a602b48 Mon Sep 17 00:00:00 2001 From: Damien Le Moal Date: Mon, 25 Mar 2024 16:09:19 +0900 Subject: ntb: idt: Use PCI_IRQ_INTX instead of PCI_IRQ_LEGACY Use the macro PCI_IRQ_INTX instead of the deprecated PCI_IRQ_LEGACY macro. Link: https://lore.kernel.org/r/20240325070944.3600338-9-dlemoal@kernel.org Signed-off-by: Damien Le Moal Signed-off-by: Bjorn Helgaas Reviewed-by: Dave Jiang --- drivers/ntb/hw/idt/ntb_hw_idt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ntb/hw/idt/ntb_hw_idt.c b/drivers/ntb/hw/idt/ntb_hw_idt.c index 48823b53ede3..48dfb1a69a77 100644 --- a/drivers/ntb/hw/idt/ntb_hw_idt.c +++ b/drivers/ntb/hw/idt/ntb_hw_idt.c @@ -2129,7 +2129,7 @@ static int idt_init_isr(struct idt_ntb_dev *ndev) int ret; /* Allocate just one interrupt vector for the ISR */ - ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSI | PCI_IRQ_LEGACY); + ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSI | PCI_IRQ_INTX); if (ret != 1) { dev_err(&pdev->dev, "Failed to allocate IRQ vector"); return ret; -- cgit v1.2.3-59-g8ed1b From 002e8e0bab4c0e902d9746f5061ad1ff4d60efb6 Mon Sep 17 00:00:00 2001 From: Damien Le Moal Date: Mon, 25 Mar 2024 16:09:20 +0900 Subject: mfd: intel-lpss: Use PCI_IRQ_INTX instead of PCI_IRQ_LEGACY Use the macro PCI_IRQ_INTX instead of the deprecated PCI_IRQ_LEGACY macro. Link: https://lore.kernel.org/r/20240325070944.3600338-10-dlemoal@kernel.org Signed-off-by: Damien Le Moal Signed-off-by: Bjorn Helgaas --- drivers/mfd/intel-lpss-pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mfd/intel-lpss-pci.c b/drivers/mfd/intel-lpss-pci.c index 8c00e0c695c5..9f4782bdbf4b 100644 --- a/drivers/mfd/intel-lpss-pci.c +++ b/drivers/mfd/intel-lpss-pci.c @@ -54,7 +54,7 @@ static int intel_lpss_pci_probe(struct pci_dev *pdev, if (ret) return ret; - ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_LEGACY); + ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_INTX); if (ret < 0) return ret; -- cgit v1.2.3-59-g8ed1b From 6927b01680599f79c0827fe559415a18d06cdc15 Mon Sep 17 00:00:00 2001 From: Damien Le Moal Date: Mon, 25 Mar 2024 16:09:21 +0900 Subject: drm/amdgpu: Use PCI_IRQ_INTX instead of PCI_IRQ_LEGACY Use the macro PCI_IRQ_INTX instead of the deprecated PCI_IRQ_LEGACY macro. Link: https://lore.kernel.org/r/20240325070944.3600338-11-dlemoal@kernel.org Signed-off-by: Damien Le Moal Signed-off-by: Bjorn Helgaas Acked-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c index 7e6d09730e6d..d18113017ee7 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c @@ -279,7 +279,7 @@ int amdgpu_irq_init(struct amdgpu_device *adev) adev->irq.msi_enabled = false; if (!amdgpu_msi_ok(adev)) - flags = PCI_IRQ_LEGACY; + flags = PCI_IRQ_INTX; else flags = PCI_IRQ_ALL_TYPES; -- cgit v1.2.3-59-g8ed1b From 91d343de201764971212e680ade77542cb7e04de Mon Sep 17 00:00:00 2001 From: Damien Le Moal Date: Mon, 25 Mar 2024 16:09:22 +0900 Subject: IB/qib: Use PCI_IRQ_INTX instead of PCI_IRQ_LEGACY Use the macro PCI_IRQ_INTX instead of the deprecated PCI_IRQ_LEGACY macro. Link: https://lore.kernel.org/r/20240325070944.3600338-12-dlemoal@kernel.org Signed-off-by: Damien Le Moal Signed-off-by: Bjorn Helgaas Acked-by: Dennis Dalessandro --- drivers/infiniband/hw/qib/qib_iba7220.c | 2 +- drivers/infiniband/hw/qib/qib_iba7322.c | 5 ++--- drivers/infiniband/hw/qib/qib_pcie.c | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/infiniband/hw/qib/qib_iba7220.c b/drivers/infiniband/hw/qib/qib_iba7220.c index 6af57067c32e..78dfe98ebcf7 100644 --- a/drivers/infiniband/hw/qib/qib_iba7220.c +++ b/drivers/infiniband/hw/qib/qib_iba7220.c @@ -3281,7 +3281,7 @@ static int qib_7220_intr_fallback(struct qib_devdata *dd) qib_free_irq(dd); dd->msi_lo = 0; - if (pci_alloc_irq_vectors(dd->pcidev, 1, 1, PCI_IRQ_LEGACY) < 0) + if (pci_alloc_irq_vectors(dd->pcidev, 1, 1, PCI_IRQ_INTX) < 0) qib_dev_err(dd, "Failed to enable INTx\n"); qib_setup_7220_interrupt(dd); return 1; diff --git a/drivers/infiniband/hw/qib/qib_iba7322.c b/drivers/infiniband/hw/qib/qib_iba7322.c index f93906d8fc09..9db29916e35a 100644 --- a/drivers/infiniband/hw/qib/qib_iba7322.c +++ b/drivers/infiniband/hw/qib/qib_iba7322.c @@ -3471,8 +3471,7 @@ try_intx: pci_irq_vector(dd->pcidev, msixnum), ret); qib_7322_free_irq(dd); - pci_alloc_irq_vectors(dd->pcidev, 1, 1, - PCI_IRQ_LEGACY); + pci_alloc_irq_vectors(dd->pcidev, 1, 1, PCI_IRQ_INTX); goto try_intx; } dd->cspec->msix_entries[msixnum].arg = arg; @@ -5143,7 +5142,7 @@ static int qib_7322_intr_fallback(struct qib_devdata *dd) qib_devinfo(dd->pcidev, "MSIx interrupt not detected, trying INTx interrupts\n"); qib_7322_free_irq(dd); - if (pci_alloc_irq_vectors(dd->pcidev, 1, 1, PCI_IRQ_LEGACY) < 0) + if (pci_alloc_irq_vectors(dd->pcidev, 1, 1, PCI_IRQ_INTX) < 0) qib_dev_err(dd, "Failed to enable INTx\n"); qib_setup_7322_interrupt(dd, 0); return 1; diff --git a/drivers/infiniband/hw/qib/qib_pcie.c b/drivers/infiniband/hw/qib/qib_pcie.c index 47bf64ace05c..58c1d62d341b 100644 --- a/drivers/infiniband/hw/qib/qib_pcie.c +++ b/drivers/infiniband/hw/qib/qib_pcie.c @@ -210,7 +210,7 @@ int qib_pcie_params(struct qib_devdata *dd, u32 minw, u32 *nent) } if (dd->flags & QIB_HAS_INTX) - flags |= PCI_IRQ_LEGACY; + flags |= PCI_IRQ_INTX; maxvec = (nent && *nent) ? *nent : 1; nvec = pci_alloc_irq_vectors(dd->pcidev, 1, maxvec, flags); if (nvec < 0) -- cgit v1.2.3-59-g8ed1b From d6f0bbcd2fc043b2e498ad3d20ebbb4b04952540 Mon Sep 17 00:00:00 2001 From: Damien Le Moal Date: Mon, 25 Mar 2024 16:09:23 +0900 Subject: RDMA/vmw_pvrdma: Use PCI_IRQ_INTX instead of PCI_IRQ_LEGACY Use the macro PCI_IRQ_INTX instead of the deprecated PCI_IRQ_LEGACY macro. Link: https://lore.kernel.org/r/20240325070944.3600338-13-dlemoal@kernel.org Signed-off-by: Damien Le Moal Signed-off-by: Bjorn Helgaas --- drivers/infiniband/hw/vmw_pvrdma/pvrdma_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_main.c b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_main.c index a5e88185171f..768aad364c89 100644 --- a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_main.c +++ b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_main.c @@ -531,7 +531,7 @@ static int pvrdma_alloc_intrs(struct pvrdma_dev *dev) PCI_IRQ_MSIX); if (ret < 0) { ret = pci_alloc_irq_vectors(pdev, 1, 1, - PCI_IRQ_MSI | PCI_IRQ_LEGACY); + PCI_IRQ_MSI | PCI_IRQ_INTX); if (ret < 0) return ret; } -- cgit v1.2.3-59-g8ed1b From ef083b6376abbae1149fd30b9d63fe158f64c703 Mon Sep 17 00:00:00 2001 From: Damien Le Moal Date: Mon, 25 Mar 2024 16:09:24 +0900 Subject: VMCI: Use PCI_IRQ_ALL_TYPES to remove PCI_IRQ_LEGACY use In vmci_guest_probe_device(), remove the reference to PCI_IRQ_LEGACY by using PCI_IRQ_ALL_TYPES instead of an explicit OR of all IRQ types. Link: https://lore.kernel.org/r/20240325070944.3600338-14-dlemoal@kernel.org Signed-off-by: Damien Le Moal Signed-off-by: Bjorn Helgaas Acked-by: Greg Kroah-Hartman --- drivers/misc/vmw_vmci/vmci_guest.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/misc/vmw_vmci/vmci_guest.c b/drivers/misc/vmw_vmci/vmci_guest.c index 4f8d962bb5b2..c61e8953511d 100644 --- a/drivers/misc/vmw_vmci/vmci_guest.c +++ b/drivers/misc/vmw_vmci/vmci_guest.c @@ -787,8 +787,7 @@ static int vmci_guest_probe_device(struct pci_dev *pdev, error = pci_alloc_irq_vectors(pdev, num_irq_vectors, num_irq_vectors, PCI_IRQ_MSIX); if (error < 0) { - error = pci_alloc_irq_vectors(pdev, 1, 1, - PCI_IRQ_MSIX | PCI_IRQ_MSI | PCI_IRQ_LEGACY); + error = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES); if (error < 0) goto err_unsubscribe_event; } else { -- cgit v1.2.3-59-g8ed1b From 5b44c2a7056c2feb93db29455782efc8fac58eeb Mon Sep 17 00:00:00 2001 From: Damien Le Moal Date: Mon, 25 Mar 2024 16:09:25 +0900 Subject: net: amd-xgbe: Use PCI_IRQ_INTX instead of PCI_IRQ_LEGACY Use the macro PCI_IRQ_INTX instead of the deprecated PCI_IRQ_LEGACY macro. Link: https://lore.kernel.org/r/20240325070944.3600338-15-dlemoal@kernel.org Signed-off-by: Damien Le Moal Signed-off-by: Bjorn Helgaas --- drivers/net/ethernet/amd/xgbe/xgbe-pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-pci.c b/drivers/net/ethernet/amd/xgbe/xgbe-pci.c index f409d7bd1f1e..c5e5fac49779 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-pci.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-pci.c @@ -170,7 +170,7 @@ static int xgbe_config_irqs(struct xgbe_prv_data *pdata) goto out; ret = pci_alloc_irq_vectors(pdata->pcidev, 1, 1, - PCI_IRQ_LEGACY | PCI_IRQ_MSI); + PCI_IRQ_INTX | PCI_IRQ_MSI); if (ret < 0) { dev_info(pdata->dev, "single IRQ enablement failed\n"); return ret; -- cgit v1.2.3-59-g8ed1b From ff9b5e14776c73298f3fd41dd07bdc7529aaf0df Mon Sep 17 00:00:00 2001 From: Damien Le Moal Date: Mon, 25 Mar 2024 16:09:26 +0900 Subject: net: atlantic: Use PCI_IRQ_INTX instead of PCI_IRQ_LEGACY Use the macro PCI_IRQ_INTX instead of the deprecated PCI_IRQ_LEGACY macro. To be consistent with this change, rename AQ_HW_IRQ_LEGACY and AQ_CFG_FORCE_LEGACY_INT to AQ_HW_IRQ_INTX and AQ_CFG_FORCE_INTX. Link: https://lore.kernel.org/r/20240325070944.3600338-16-dlemoal@kernel.org Signed-off-by: Damien Le Moal Signed-off-by: Bjorn Helgaas --- drivers/net/ethernet/aquantia/atlantic/aq_cfg.h | 2 +- drivers/net/ethernet/aquantia/atlantic/aq_hw.h | 2 +- drivers/net/ethernet/aquantia/atlantic/aq_nic.c | 2 +- drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c | 9 +++------ drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c | 2 +- drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c | 2 +- drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2.c | 2 +- 7 files changed, 9 insertions(+), 12 deletions(-) diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_cfg.h b/drivers/net/ethernet/aquantia/atlantic/aq_cfg.h index 7e9c74b141ef..fc2b325f34e7 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_cfg.h +++ b/drivers/net/ethernet/aquantia/atlantic/aq_cfg.h @@ -17,7 +17,7 @@ #define AQ_CFG_IS_POLLING_DEF 0U -#define AQ_CFG_FORCE_LEGACY_INT 0U +#define AQ_CFG_FORCE_INTX 0U #define AQ_CFG_INTERRUPT_MODERATION_OFF 0 #define AQ_CFG_INTERRUPT_MODERATION_ON 1 diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h index dbd284660135..f010bda61c96 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h +++ b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h @@ -104,7 +104,7 @@ struct aq_stats_s { }; #define AQ_HW_IRQ_INVALID 0U -#define AQ_HW_IRQ_LEGACY 1U +#define AQ_HW_IRQ_INTX 1U #define AQ_HW_IRQ_MSI 2U #define AQ_HW_IRQ_MSIX 3U diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c index d6d6d5d37ff3..fe0e3e2a8117 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c @@ -127,7 +127,7 @@ void aq_nic_cfg_start(struct aq_nic_s *self) cfg->irq_type = aq_pci_func_get_irq_type(self); - if ((cfg->irq_type == AQ_HW_IRQ_LEGACY) || + if ((cfg->irq_type == AQ_HW_IRQ_INTX) || (cfg->aq_hw_caps->vecs == 1U) || (cfg->vecs == 1U)) { cfg->is_rss = 0U; diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c b/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c index baa5f8cc31f2..43c71f6b314f 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c @@ -200,7 +200,7 @@ unsigned int aq_pci_func_get_irq_type(struct aq_nic_s *self) if (self->pdev->msi_enabled) return AQ_HW_IRQ_MSI; - return AQ_HW_IRQ_LEGACY; + return AQ_HW_IRQ_INTX; } static void aq_pci_free_irq_vectors(struct aq_nic_s *self) @@ -298,11 +298,8 @@ static int aq_pci_probe(struct pci_dev *pdev, numvecs += AQ_HW_SERVICE_IRQS; /*enable interrupts */ -#if !AQ_CFG_FORCE_LEGACY_INT - err = pci_alloc_irq_vectors(self->pdev, 1, numvecs, - PCI_IRQ_MSIX | PCI_IRQ_MSI | - PCI_IRQ_LEGACY); - +#if !AQ_CFG_FORCE_INTX + err = pci_alloc_irq_vectors(self->pdev, 1, numvecs, PCI_IRQ_ALL_TYPES); if (err < 0) goto err_hwinit; numvecs = err; diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c index 9dfd68f0fda9..8de2cdd09213 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c @@ -352,7 +352,7 @@ static int hw_atl_a0_hw_init(struct aq_hw_s *self, const u8 *mac_addr) { static u32 aq_hw_atl_igcr_table_[4][2] = { [AQ_HW_IRQ_INVALID] = { 0x20000000U, 0x20000000U }, - [AQ_HW_IRQ_LEGACY] = { 0x20000080U, 0x20000080U }, + [AQ_HW_IRQ_INTX] = { 0x20000080U, 0x20000080U }, [AQ_HW_IRQ_MSI] = { 0x20000021U, 0x20000025U }, [AQ_HW_IRQ_MSIX] = { 0x20000022U, 0x20000026U }, }; diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c index 54e70f07b573..56c46266bb0a 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c @@ -562,7 +562,7 @@ static int hw_atl_b0_hw_init(struct aq_hw_s *self, const u8 *mac_addr) { static u32 aq_hw_atl_igcr_table_[4][2] = { [AQ_HW_IRQ_INVALID] = { 0x20000000U, 0x20000000U }, - [AQ_HW_IRQ_LEGACY] = { 0x20000080U, 0x20000080U }, + [AQ_HW_IRQ_INTX] = { 0x20000080U, 0x20000080U }, [AQ_HW_IRQ_MSI] = { 0x20000021U, 0x20000025U }, [AQ_HW_IRQ_MSIX] = { 0x20000022U, 0x20000026U }, }; diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2.c index 220400a633f5..b0ed572e88c6 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2.c @@ -534,7 +534,7 @@ static int hw_atl2_hw_init(struct aq_hw_s *self, const u8 *mac_addr) { static u32 aq_hw_atl2_igcr_table_[4][2] = { [AQ_HW_IRQ_INVALID] = { 0x20000000U, 0x20000000U }, - [AQ_HW_IRQ_LEGACY] = { 0x20000080U, 0x20000080U }, + [AQ_HW_IRQ_INTX] = { 0x20000080U, 0x20000080U }, [AQ_HW_IRQ_MSI] = { 0x20000021U, 0x20000025U }, [AQ_HW_IRQ_MSIX] = { 0x20000022U, 0x20000026U }, }; -- cgit v1.2.3-59-g8ed1b From e0ff0ff74ba37e04e0464bc6eaaadf5b88a4b4af Mon Sep 17 00:00:00 2001 From: Damien Le Moal Date: Mon, 25 Mar 2024 16:09:27 +0900 Subject: net: alx: Use PCI_IRQ_INTX instead of PCI_IRQ_LEGACY Use the macro PCI_IRQ_INTX instead of the deprecated PCI_IRQ_LEGACY macro. Link: https://lore.kernel.org/r/20240325070944.3600338-17-dlemoal@kernel.org Signed-off-by: Damien Le Moal Signed-off-by: Bjorn Helgaas --- drivers/net/ethernet/atheros/alx/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/atheros/alx/main.c b/drivers/net/ethernet/atheros/alx/main.c index 49bb9a8f00e6..0dbb541155f3 100644 --- a/drivers/net/ethernet/atheros/alx/main.c +++ b/drivers/net/ethernet/atheros/alx/main.c @@ -901,7 +901,7 @@ static int alx_init_intr(struct alx_priv *alx) int ret; ret = pci_alloc_irq_vectors(alx->hw.pdev, 1, 1, - PCI_IRQ_MSI | PCI_IRQ_LEGACY); + PCI_IRQ_MSI | PCI_IRQ_INTX); if (ret < 0) return ret; -- cgit v1.2.3-59-g8ed1b From b14ed9867d87ff5c703035d0e7e8d5127a6551bb Mon Sep 17 00:00:00 2001 From: Damien Le Moal Date: Mon, 25 Mar 2024 16:09:28 +0900 Subject: r8169: Use PCI_IRQ_INTX instead of PCI_IRQ_LEGACY Use the macro PCI_IRQ_INTX instead of the deprecated PCI_IRQ_LEGACY macro. Link: https://lore.kernel.org/r/20240325070944.3600338-18-dlemoal@kernel.org Signed-off-by: Damien Le Moal Signed-off-by: Bjorn Helgaas Acked-by: Heiner Kallweit --- drivers/net/ethernet/realtek/r8169_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index 5c879a5c86d7..7288afcc8c94 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -5076,7 +5076,7 @@ static int rtl_alloc_irq(struct rtl8169_private *tp) rtl_lock_config_regs(tp); fallthrough; case RTL_GIGA_MAC_VER_07 ... RTL_GIGA_MAC_VER_17: - flags = PCI_IRQ_LEGACY; + flags = PCI_IRQ_INTX; break; default: flags = PCI_IRQ_ALL_TYPES; -- cgit v1.2.3-59-g8ed1b From 935d5b33ce2b67c2ac6fa279c46b8c32fab4f28d Mon Sep 17 00:00:00 2001 From: Damien Le Moal Date: Mon, 25 Mar 2024 16:09:29 +0900 Subject: net: wangxun: Use PCI_IRQ_INTX instead of PCI_IRQ_LEGACY Use the macro PCI_IRQ_INTX instead of the deprecated PCI_IRQ_LEGACY macro. Link: https://lore.kernel.org/r/20240325070944.3600338-19-dlemoal@kernel.org Signed-off-by: Damien Le Moal Signed-off-by: Bjorn Helgaas --- drivers/net/ethernet/wangxun/libwx/wx_lib.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/wangxun/libwx/wx_lib.c b/drivers/net/ethernet/wangxun/libwx/wx_lib.c index 6dff2c85682d..998c61c22ca1 100644 --- a/drivers/net/ethernet/wangxun/libwx/wx_lib.c +++ b/drivers/net/ethernet/wangxun/libwx/wx_lib.c @@ -1674,14 +1674,14 @@ static int wx_set_interrupt_capability(struct wx *wx) /* minmum one for queue, one for misc*/ nvecs = 1; nvecs = pci_alloc_irq_vectors(pdev, nvecs, - nvecs, PCI_IRQ_MSI | PCI_IRQ_LEGACY); + nvecs, PCI_IRQ_MSI | PCI_IRQ_INTX); if (nvecs == 1) { if (pdev->msi_enabled) wx_err(wx, "Fallback to MSI.\n"); else - wx_err(wx, "Fallback to LEGACY.\n"); + wx_err(wx, "Fallback to INTx.\n"); } else { - wx_err(wx, "Failed to allocate MSI/LEGACY interrupts. Error: %d\n", nvecs); + wx_err(wx, "Failed to allocate MSI/INTx interrupts. Error: %d\n", nvecs); return nvecs; } @@ -2127,7 +2127,7 @@ void wx_write_eitr(struct wx_q_vector *q_vector) * wx_configure_vectors - Configure vectors for hardware * @wx: board private structure * - * wx_configure_vectors sets up the hardware to properly generate MSI-X/MSI/LEGACY + * wx_configure_vectors sets up the hardware to properly generate MSI-X/MSI/INTx * interrupts. **/ void wx_configure_vectors(struct wx *wx) -- cgit v1.2.3-59-g8ed1b From 60706ea99057db56837ad530c6803bb82c1c76e1 Mon Sep 17 00:00:00 2001 From: Damien Le Moal Date: Mon, 25 Mar 2024 16:09:30 +0900 Subject: wifi: ath10k: Refer to INTX instead of LEGACY To be consistent with the deprecation of PCI_IRQ_LEGACY and its replacement with PCI_IRQ_INTX, rename macros and functions referencing "legacy irq" to instead use the term "intx irq". Link: https://lore.kernel.org/r/20240325070944.3600338-20-dlemoal@kernel.org Signed-off-by: Damien Le Moal Signed-off-by: Bjorn Helgaas --- drivers/net/wireless/ath/ath10k/ahb.c | 18 +++++++++--------- drivers/net/wireless/ath/ath10k/pci.c | 36 +++++++++++++++++------------------ drivers/net/wireless/ath/ath10k/pci.h | 6 +++--- 3 files changed, 30 insertions(+), 30 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/ahb.c b/drivers/net/wireless/ath/ath10k/ahb.c index a378bc48b1d2..f0441b3d7dcb 100644 --- a/drivers/net/wireless/ath/ath10k/ahb.c +++ b/drivers/net/wireless/ath/ath10k/ahb.c @@ -394,14 +394,14 @@ static irqreturn_t ath10k_ahb_interrupt_handler(int irq, void *arg) if (!ath10k_pci_irq_pending(ar)) return IRQ_NONE; - ath10k_pci_disable_and_clear_legacy_irq(ar); + ath10k_pci_disable_and_clear_intx_irq(ar); ath10k_pci_irq_msi_fw_mask(ar); napi_schedule(&ar->napi); return IRQ_HANDLED; } -static int ath10k_ahb_request_irq_legacy(struct ath10k *ar) +static int ath10k_ahb_request_irq_intx(struct ath10k *ar) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar); @@ -415,12 +415,12 @@ static int ath10k_ahb_request_irq_legacy(struct ath10k *ar) ar_ahb->irq, ret); return ret; } - ar_pci->oper_irq_mode = ATH10K_PCI_IRQ_LEGACY; + ar_pci->oper_irq_mode = ATH10K_PCI_IRQ_INTX; return 0; } -static void ath10k_ahb_release_irq_legacy(struct ath10k *ar) +static void ath10k_ahb_release_irq_intx(struct ath10k *ar) { struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar); @@ -430,7 +430,7 @@ static void ath10k_ahb_release_irq_legacy(struct ath10k *ar) static void ath10k_ahb_irq_disable(struct ath10k *ar) { ath10k_ce_disable_interrupts(ar); - ath10k_pci_disable_and_clear_legacy_irq(ar); + ath10k_pci_disable_and_clear_intx_irq(ar); } static int ath10k_ahb_resource_init(struct ath10k *ar) @@ -621,7 +621,7 @@ static int ath10k_ahb_hif_start(struct ath10k *ar) ath10k_core_napi_enable(ar); ath10k_ce_enable_interrupts(ar); - ath10k_pci_enable_legacy_irq(ar); + ath10k_pci_enable_intx_irq(ar); ath10k_pci_rx_post(ar); @@ -775,7 +775,7 @@ static int ath10k_ahb_probe(struct platform_device *pdev) ath10k_pci_init_napi(ar); - ret = ath10k_ahb_request_irq_legacy(ar); + ret = ath10k_ahb_request_irq_intx(ar); if (ret) goto err_free_pipes; @@ -806,7 +806,7 @@ err_halt_device: ath10k_ahb_clock_disable(ar); err_free_irq: - ath10k_ahb_release_irq_legacy(ar); + ath10k_ahb_release_irq_intx(ar); err_free_pipes: ath10k_pci_release_resource(ar); @@ -828,7 +828,7 @@ static void ath10k_ahb_remove(struct platform_device *pdev) ath10k_core_unregister(ar); ath10k_ahb_irq_disable(ar); - ath10k_ahb_release_irq_legacy(ar); + ath10k_ahb_release_irq_intx(ar); ath10k_pci_release_resource(ar); ath10k_ahb_halt_chip(ar); ath10k_ahb_clock_disable(ar); diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 5c34b156b4ff..6aeeab2edf5a 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -721,7 +721,7 @@ bool ath10k_pci_irq_pending(struct ath10k *ar) return false; } -void ath10k_pci_disable_and_clear_legacy_irq(struct ath10k *ar) +void ath10k_pci_disable_and_clear_intx_irq(struct ath10k *ar) { /* IMPORTANT: INTR_CLR register has to be set after * INTR_ENABLE is set to 0, otherwise interrupt can not be @@ -739,7 +739,7 @@ void ath10k_pci_disable_and_clear_legacy_irq(struct ath10k *ar) PCIE_INTR_ENABLE_ADDRESS); } -void ath10k_pci_enable_legacy_irq(struct ath10k *ar) +void ath10k_pci_enable_intx_irq(struct ath10k *ar) { ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + PCIE_INTR_ENABLE_ADDRESS, @@ -1935,7 +1935,7 @@ static void ath10k_pci_irq_msi_fw_unmask(struct ath10k *ar) static void ath10k_pci_irq_disable(struct ath10k *ar) { ath10k_ce_disable_interrupts(ar); - ath10k_pci_disable_and_clear_legacy_irq(ar); + ath10k_pci_disable_and_clear_intx_irq(ar); ath10k_pci_irq_msi_fw_mask(ar); } @@ -1949,7 +1949,7 @@ static void ath10k_pci_irq_sync(struct ath10k *ar) static void ath10k_pci_irq_enable(struct ath10k *ar) { ath10k_ce_enable_interrupts(ar); - ath10k_pci_enable_legacy_irq(ar); + ath10k_pci_enable_intx_irq(ar); ath10k_pci_irq_msi_fw_unmask(ar); } @@ -3111,11 +3111,11 @@ static irqreturn_t ath10k_pci_interrupt_handler(int irq, void *arg) return IRQ_NONE; } - if ((ar_pci->oper_irq_mode == ATH10K_PCI_IRQ_LEGACY) && + if ((ar_pci->oper_irq_mode == ATH10K_PCI_IRQ_INTX) && !ath10k_pci_irq_pending(ar)) return IRQ_NONE; - ath10k_pci_disable_and_clear_legacy_irq(ar); + ath10k_pci_disable_and_clear_intx_irq(ar); ath10k_pci_irq_msi_fw_mask(ar); napi_schedule(&ar->napi); @@ -3152,7 +3152,7 @@ static int ath10k_pci_napi_poll(struct napi_struct *ctx, int budget) napi_schedule(ctx); goto out; } - ath10k_pci_enable_legacy_irq(ar); + ath10k_pci_enable_intx_irq(ar); ath10k_pci_irq_msi_fw_unmask(ar); } @@ -3177,7 +3177,7 @@ static int ath10k_pci_request_irq_msi(struct ath10k *ar) return 0; } -static int ath10k_pci_request_irq_legacy(struct ath10k *ar) +static int ath10k_pci_request_irq_intx(struct ath10k *ar) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); int ret; @@ -3199,8 +3199,8 @@ static int ath10k_pci_request_irq(struct ath10k *ar) struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); switch (ar_pci->oper_irq_mode) { - case ATH10K_PCI_IRQ_LEGACY: - return ath10k_pci_request_irq_legacy(ar); + case ATH10K_PCI_IRQ_INTX: + return ath10k_pci_request_irq_intx(ar); case ATH10K_PCI_IRQ_MSI: return ath10k_pci_request_irq_msi(ar); default: @@ -3232,7 +3232,7 @@ static int ath10k_pci_init_irq(struct ath10k *ar) ath10k_pci_irq_mode); /* Try MSI */ - if (ath10k_pci_irq_mode != ATH10K_PCI_IRQ_LEGACY) { + if (ath10k_pci_irq_mode != ATH10K_PCI_IRQ_INTX) { ar_pci->oper_irq_mode = ATH10K_PCI_IRQ_MSI; ret = pci_enable_msi(ar_pci->pdev); if (ret == 0) @@ -3250,7 +3250,7 @@ static int ath10k_pci_init_irq(struct ath10k *ar) * For now, fix the race by repeating the write in below * synchronization checking. */ - ar_pci->oper_irq_mode = ATH10K_PCI_IRQ_LEGACY; + ar_pci->oper_irq_mode = ATH10K_PCI_IRQ_INTX; ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + PCIE_INTR_ENABLE_ADDRESS, PCIE_INTR_FIRMWARE_MASK | PCIE_INTR_CE_MASK_ALL); @@ -3258,7 +3258,7 @@ static int ath10k_pci_init_irq(struct ath10k *ar) return 0; } -static void ath10k_pci_deinit_irq_legacy(struct ath10k *ar) +static void ath10k_pci_deinit_irq_intx(struct ath10k *ar) { ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + PCIE_INTR_ENABLE_ADDRESS, 0); @@ -3269,8 +3269,8 @@ static int ath10k_pci_deinit_irq(struct ath10k *ar) struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); switch (ar_pci->oper_irq_mode) { - case ATH10K_PCI_IRQ_LEGACY: - ath10k_pci_deinit_irq_legacy(ar); + case ATH10K_PCI_IRQ_INTX: + ath10k_pci_deinit_irq_intx(ar); break; default: pci_disable_msi(ar_pci->pdev); @@ -3307,14 +3307,14 @@ int ath10k_pci_wait_for_target_init(struct ath10k *ar) if (val & FW_IND_INITIALIZED) break; - if (ar_pci->oper_irq_mode == ATH10K_PCI_IRQ_LEGACY) + if (ar_pci->oper_irq_mode == ATH10K_PCI_IRQ_INTX) /* Fix potential race by repeating CORE_BASE writes */ - ath10k_pci_enable_legacy_irq(ar); + ath10k_pci_enable_intx_irq(ar); mdelay(10); } while (time_before(jiffies, timeout)); - ath10k_pci_disable_and_clear_legacy_irq(ar); + ath10k_pci_disable_and_clear_intx_irq(ar); ath10k_pci_irq_msi_fw_mask(ar); if (val == 0xffffffff) { diff --git a/drivers/net/wireless/ath/ath10k/pci.h b/drivers/net/wireless/ath/ath10k/pci.h index 27bb4cf2dfea..4c3f536f2ea1 100644 --- a/drivers/net/wireless/ath/ath10k/pci.h +++ b/drivers/net/wireless/ath/ath10k/pci.h @@ -101,7 +101,7 @@ struct ath10k_pci_supp_chip { enum ath10k_pci_irq_mode { ATH10K_PCI_IRQ_AUTO = 0, - ATH10K_PCI_IRQ_LEGACY = 1, + ATH10K_PCI_IRQ_INTX = 1, ATH10K_PCI_IRQ_MSI = 2, }; @@ -243,9 +243,9 @@ int ath10k_pci_init_pipes(struct ath10k *ar); int ath10k_pci_init_config(struct ath10k *ar); void ath10k_pci_rx_post(struct ath10k *ar); void ath10k_pci_flush(struct ath10k *ar); -void ath10k_pci_enable_legacy_irq(struct ath10k *ar); +void ath10k_pci_enable_intx_irq(struct ath10k *ar); bool ath10k_pci_irq_pending(struct ath10k *ar); -void ath10k_pci_disable_and_clear_legacy_irq(struct ath10k *ar); +void ath10k_pci_disable_and_clear_intx_irq(struct ath10k *ar); void ath10k_pci_irq_msi_fw_mask(struct ath10k *ar); int ath10k_pci_wait_for_target_init(struct ath10k *ar); int ath10k_pci_setup_resource(struct ath10k *ar); -- cgit v1.2.3-59-g8ed1b From c3d26b9b26d34a054681cfb25af4841e985640d5 Mon Sep 17 00:00:00 2001 From: Damien Le Moal Date: Mon, 25 Mar 2024 16:09:31 +0900 Subject: wifi: rtw88: Use PCI_IRQ_INTX instead of PCI_IRQ_LEGACY Use the macro PCI_IRQ_INTX instead of the deprecated PCI_IRQ_LEGACY macro. Link: https://lore.kernel.org/r/20240325070944.3600338-21-dlemoal@kernel.org Signed-off-by: Damien Le Moal [bhelgaas: split to separate patch] Signed-off-by: Bjorn Helgaas --- drivers/net/wireless/realtek/rtw88/pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw88/pci.c b/drivers/net/wireless/realtek/rtw88/pci.c index 9986a4cb37eb..282f1e5a882e 100644 --- a/drivers/net/wireless/realtek/rtw88/pci.c +++ b/drivers/net/wireless/realtek/rtw88/pci.c @@ -1612,7 +1612,7 @@ static struct rtw_hci_ops rtw_pci_ops = { static int rtw_pci_request_irq(struct rtw_dev *rtwdev, struct pci_dev *pdev) { - unsigned int flags = PCI_IRQ_LEGACY; + unsigned int flags = PCI_IRQ_INTX; int ret; if (!rtw_disable_msi) -- cgit v1.2.3-59-g8ed1b From 7b4e0b39182cf5e677c1fc092a3ec40e621c25b6 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Mon, 9 Oct 2023 14:10:18 +0200 Subject: Input: cyapa - add missing input core locking to suspend/resume functions Grab input->mutex during suspend/resume functions like it is done in other input drivers. This fixes the following warning during system suspend/resume cycle on Samsung Exynos5250-based Snow Chromebook: ------------[ cut here ]------------ WARNING: CPU: 1 PID: 1680 at drivers/input/input.c:2291 input_device_enabled+0x68/0x6c Modules linked in: ... CPU: 1 PID: 1680 Comm: kworker/u4:12 Tainted: G W 6.6.0-rc5-next-20231009 #14109 Hardware name: Samsung Exynos (Flattened Device Tree) Workqueue: events_unbound async_run_entry_fn unwind_backtrace from show_stack+0x10/0x14 show_stack from dump_stack_lvl+0x58/0x70 dump_stack_lvl from __warn+0x1a8/0x1cc __warn from warn_slowpath_fmt+0x18c/0x1b4 warn_slowpath_fmt from input_device_enabled+0x68/0x6c input_device_enabled from cyapa_gen3_set_power_mode+0x13c/0x1dc cyapa_gen3_set_power_mode from cyapa_reinitialize+0x10c/0x15c cyapa_reinitialize from cyapa_resume+0x48/0x98 cyapa_resume from dpm_run_callback+0x90/0x298 dpm_run_callback from device_resume+0xb4/0x258 device_resume from async_resume+0x20/0x64 async_resume from async_run_entry_fn+0x40/0x15c async_run_entry_fn from process_scheduled_works+0xbc/0x6a8 process_scheduled_works from worker_thread+0x188/0x454 worker_thread from kthread+0x108/0x140 kthread from ret_from_fork+0x14/0x28 Exception stack(0xf1625fb0 to 0xf1625ff8) ... ---[ end trace 0000000000000000 ]--- ... ------------[ cut here ]------------ WARNING: CPU: 1 PID: 1680 at drivers/input/input.c:2291 input_device_enabled+0x68/0x6c Modules linked in: ... CPU: 1 PID: 1680 Comm: kworker/u4:12 Tainted: G W 6.6.0-rc5-next-20231009 #14109 Hardware name: Samsung Exynos (Flattened Device Tree) Workqueue: events_unbound async_run_entry_fn unwind_backtrace from show_stack+0x10/0x14 show_stack from dump_stack_lvl+0x58/0x70 dump_stack_lvl from __warn+0x1a8/0x1cc __warn from warn_slowpath_fmt+0x18c/0x1b4 warn_slowpath_fmt from input_device_enabled+0x68/0x6c input_device_enabled from cyapa_gen3_set_power_mode+0x13c/0x1dc cyapa_gen3_set_power_mode from cyapa_reinitialize+0x10c/0x15c cyapa_reinitialize from cyapa_resume+0x48/0x98 cyapa_resume from dpm_run_callback+0x90/0x298 dpm_run_callback from device_resume+0xb4/0x258 device_resume from async_resume+0x20/0x64 async_resume from async_run_entry_fn+0x40/0x15c async_run_entry_fn from process_scheduled_works+0xbc/0x6a8 process_scheduled_works from worker_thread+0x188/0x454 worker_thread from kthread+0x108/0x140 kthread from ret_from_fork+0x14/0x28 Exception stack(0xf1625fb0 to 0xf1625ff8) ... ---[ end trace 0000000000000000 ]--- Fixes: d69f0a43c677 ("Input: use input_device_enabled()") Signed-off-by: Marek Szyprowski Reviewed-by: Andrzej Pietrasiewicz Link: https://lore.kernel.org/r/20231009121018.1075318-1-m.szyprowski@samsung.com Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/cyapa.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/input/mouse/cyapa.c b/drivers/input/mouse/cyapa.c index 5979deabe23d..256f757a1326 100644 --- a/drivers/input/mouse/cyapa.c +++ b/drivers/input/mouse/cyapa.c @@ -1347,10 +1347,16 @@ static int cyapa_suspend(struct device *dev) u8 power_mode; int error; - error = mutex_lock_interruptible(&cyapa->state_sync_lock); + error = mutex_lock_interruptible(&cyapa->input->mutex); if (error) return error; + error = mutex_lock_interruptible(&cyapa->state_sync_lock); + if (error) { + mutex_unlock(&cyapa->input->mutex); + return error; + } + /* * Runtime PM is enable only when device is in operational mode and * users in use, so need check it before disable it to @@ -1385,6 +1391,8 @@ static int cyapa_suspend(struct device *dev) cyapa->irq_wake = (enable_irq_wake(client->irq) == 0); mutex_unlock(&cyapa->state_sync_lock); + mutex_unlock(&cyapa->input->mutex); + return 0; } @@ -1394,6 +1402,7 @@ static int cyapa_resume(struct device *dev) struct cyapa *cyapa = i2c_get_clientdata(client); int error; + mutex_lock(&cyapa->input->mutex); mutex_lock(&cyapa->state_sync_lock); if (device_may_wakeup(dev) && cyapa->irq_wake) { @@ -1412,6 +1421,7 @@ static int cyapa_resume(struct device *dev) enable_irq(client->irq); mutex_unlock(&cyapa->state_sync_lock); + mutex_unlock(&cyapa->input->mutex); return 0; } -- cgit v1.2.3-59-g8ed1b From 3f12222a4bebeb13ce06ddecc1610ad32fa835dd Mon Sep 17 00:00:00 2001 From: Krishna Kurapati Date: Fri, 26 Apr 2024 10:35:12 +0530 Subject: usb: dwc3: core: Fix compile warning on s390 gcc in dwc3_get_phy call Recent commit introduced support for reading Multiport PHYs and while doing so iterated over an integer variable which runs from [0-254] in the worst case scenario. But S390 compiler treats it as a warning and complains that the integer write to string can go to 11 characters. Fix this by modifying iterator variable to u8. Suggested-by: Johan Hovold Fixes: 30a46746ca5a ("usb: dwc3: core: Refactor PHY logic to support Multiport Controller") Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202404241215.Mib19Cu7-lkp@intel.com/ Signed-off-by: Krishna Kurapati Reviewed-by: Johan Hovold Link: https://lore.kernel.org/r/20240426050512.57384-1-quic_kriskura@quicinc.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 4dc6fc79c6d9..719305ab86c0 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -1449,7 +1449,7 @@ static int dwc3_core_get_phy(struct dwc3 *dwc) struct device_node *node = dev->of_node; char phy_name[9]; int ret; - int i; + u8 i; if (node) { dwc->usb2_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 0); @@ -1479,7 +1479,7 @@ static int dwc3_core_get_phy(struct dwc3 *dwc) if (dwc->num_usb2_ports == 1) snprintf(phy_name, sizeof(phy_name), "usb2-phy"); else - snprintf(phy_name, sizeof(phy_name), "usb2-%d", i); + snprintf(phy_name, sizeof(phy_name), "usb2-%u", i); dwc->usb2_generic_phy[i] = devm_phy_get(dev, phy_name); if (IS_ERR(dwc->usb2_generic_phy[i])) { @@ -1496,7 +1496,7 @@ static int dwc3_core_get_phy(struct dwc3 *dwc) if (dwc->num_usb3_ports == 1) snprintf(phy_name, sizeof(phy_name), "usb3-phy"); else - snprintf(phy_name, sizeof(phy_name), "usb3-%d", i); + snprintf(phy_name, sizeof(phy_name), "usb3-%u", i); dwc->usb3_generic_phy[i] = devm_phy_get(dev, phy_name); if (IS_ERR(dwc->usb3_generic_phy[i])) { -- cgit v1.2.3-59-g8ed1b From 79e7123c078d8f6e9e674d96f541ba696b2c156c Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 26 Apr 2024 06:40:29 +0000 Subject: soundwire: intel_ace2x: fix wakeup handling The initial programming sequence only worked in the case where the OFLEN bit is set, i.e. the DSP handles the SoundWire interface. In the Linux integration, the interface is owned by the host. This disconnect leads to wake-ups being routed to the DSP and not to the host. The suggested update is to rely on the global HDAudio WAKEEN/STATESTS registers, with the SDI bits used to program the wakeups and check the status. Note that there is no way to know which peripheral generated a wake-up. When the hardware detects a change, it sets all the bits corresponding to LSDIIDx. The LSDIIDx information can be used to figure out on which link the wakeup happened, but for further details the software will have to check the status of each peripheral. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Signed-off-by: Bard Liao Link: https://lore.kernel.org/r/20240426064030.2305343-2-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- drivers/soundwire/intel_ace2x.c | 49 +++++++++++++++++++++++++++++------------ 1 file changed, 35 insertions(+), 14 deletions(-) diff --git a/drivers/soundwire/intel_ace2x.c b/drivers/soundwire/intel_ace2x.c index 22afaf055227..8812527af4a8 100644 --- a/drivers/soundwire/intel_ace2x.c +++ b/drivers/soundwire/intel_ace2x.c @@ -10,8 +10,10 @@ #include #include #include -#include +#include #include +#include +#include #include "cadence_master.h" #include "bus.h" #include "intel.h" @@ -49,37 +51,56 @@ static void intel_shim_vs_set_clock_source(struct sdw_intel *sdw, u32 source) static int intel_shim_check_wake(struct sdw_intel *sdw) { - void __iomem *shim_vs; + u16 lsdiid = 0; u16 wake_sts; + int ret; + + /* find out which bits are set in LSDIID for this sublink */ + ret = hdac_bus_eml_sdw_get_lsdiid_unlocked(sdw->link_res->hbus, sdw->instance, &lsdiid); + if (ret < 0) + return ret; - shim_vs = sdw->link_res->shim_vs; - wake_sts = intel_readw(shim_vs, SDW_SHIM2_INTEL_VS_WAKESTS); + /* + * we need to use the global HDaudio WAKEEN/STS to be able to detect + * wakes in low-power modes + */ + wake_sts = snd_hdac_chip_readw(sdw->link_res->hbus, STATESTS); - return wake_sts & SDW_SHIM2_INTEL_VS_WAKEEN_PWS; + return wake_sts & lsdiid; } static void intel_shim_wake(struct sdw_intel *sdw, bool wake_enable) { - void __iomem *shim_vs = sdw->link_res->shim_vs; + u16 lsdiid = 0; u16 wake_en; u16 wake_sts; + int ret; + + mutex_lock(sdw->link_res->shim_lock); - wake_en = intel_readw(shim_vs, SDW_SHIM2_INTEL_VS_WAKEEN); + ret = hdac_bus_eml_sdw_get_lsdiid_unlocked(sdw->link_res->hbus, sdw->instance, &lsdiid); + if (ret < 0) + goto unlock; + + wake_en = snd_hdac_chip_readw(sdw->link_res->hbus, WAKEEN); if (wake_enable) { /* Enable the wakeup */ - wake_en |= SDW_SHIM2_INTEL_VS_WAKEEN_PWE; - intel_writew(shim_vs, SDW_SHIM2_INTEL_VS_WAKEEN, wake_en); + wake_en |= lsdiid; + + snd_hdac_chip_writew(sdw->link_res->hbus, WAKEEN, wake_en); } else { /* Disable the wake up interrupt */ - wake_en &= ~SDW_SHIM2_INTEL_VS_WAKEEN_PWE; - intel_writew(shim_vs, SDW_SHIM2_INTEL_VS_WAKEEN, wake_en); + wake_en &= ~lsdiid; + snd_hdac_chip_writew(sdw->link_res->hbus, WAKEEN, wake_en); /* Clear wake status (W1C) */ - wake_sts = intel_readw(shim_vs, SDW_SHIM2_INTEL_VS_WAKESTS); - wake_sts |= SDW_SHIM2_INTEL_VS_WAKEEN_PWS; - intel_writew(shim_vs, SDW_SHIM2_INTEL_VS_WAKESTS, wake_sts); + wake_sts = snd_hdac_chip_readw(sdw->link_res->hbus, STATESTS); + wake_sts |= lsdiid; + snd_hdac_chip_writew(sdw->link_res->hbus, STATESTS, wake_sts); } +unlock: + mutex_unlock(sdw->link_res->shim_lock); } static int intel_link_power_up(struct sdw_intel *sdw) -- cgit v1.2.3-59-g8ed1b From a36ec5f7625d923212f7b869f7870616b15f20a2 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 26 Apr 2024 06:40:30 +0000 Subject: soundwire: intel_ace2x: simplify check_wake() Since LunarLake, we use the HDadio WAKEEN/WAKESTS to detect wakes for SoundWire codecs. This patch follows the HDaudio example and simplifies the behavior on wake-up by unconditionally waking up all links. This behavior makes a lot of sense when removing the jack, which may signal that the user wants to start rendering audio using the local amplifiers. Resuming all links helps make sure the amplifiers are ready to be used. Worst case, the pm_runtime suspend would kick-in after several seconds of inactivity. Closes: https://github.com/thesofproject/linux/issues/4687 Co-developed-by: Bard Liao Signed-off-by: Bard Liao Signed-off-by: Pierre-Louis Bossart Reviewed-by: Keqiao Zhang Link: https://lore.kernel.org/r/20240426064030.2305343-3-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- drivers/soundwire/intel_ace2x.c | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/drivers/soundwire/intel_ace2x.c b/drivers/soundwire/intel_ace2x.c index 8812527af4a8..75e629c938dc 100644 --- a/drivers/soundwire/intel_ace2x.c +++ b/drivers/soundwire/intel_ace2x.c @@ -51,22 +51,12 @@ static void intel_shim_vs_set_clock_source(struct sdw_intel *sdw, u32 source) static int intel_shim_check_wake(struct sdw_intel *sdw) { - u16 lsdiid = 0; - u16 wake_sts; - int ret; - - /* find out which bits are set in LSDIID for this sublink */ - ret = hdac_bus_eml_sdw_get_lsdiid_unlocked(sdw->link_res->hbus, sdw->instance, &lsdiid); - if (ret < 0) - return ret; - /* - * we need to use the global HDaudio WAKEEN/STS to be able to detect - * wakes in low-power modes + * We follow the HDaudio example and resume unconditionally + * without checking the WAKESTS bit for that specific link */ - wake_sts = snd_hdac_chip_readw(sdw->link_res->hbus, STATESTS); - return wake_sts & lsdiid; + return 1; } static void intel_shim_wake(struct sdw_intel *sdw, bool wake_enable) -- cgit v1.2.3-59-g8ed1b From 0ba5cd94bbc2d21ffb392b6a3b23ee288b4778d5 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 26 Apr 2024 17:40:39 +0300 Subject: PCI/MSI: Make error path handling follow the standard pattern Make error path handling follow the standard pattern, i.e. checking for errors first. This makes code much easier to read and understand despite being a bit longer. Link: https://lore.kernel.org/r/20240426144039.557907-1-andriy.shevchenko@linux.intel.com Signed-off-by: Andy Shevchenko Signed-off-by: Bjorn Helgaas --- drivers/pci/msi/msi.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/pci/msi/msi.c b/drivers/pci/msi/msi.c index 682fa877478f..c5625dd9bf49 100644 --- a/drivers/pci/msi/msi.c +++ b/drivers/pci/msi/msi.c @@ -86,9 +86,11 @@ static int pcim_setup_msi_release(struct pci_dev *dev) return 0; ret = devm_add_action(&dev->dev, pcim_msi_release, dev); - if (!ret) - dev->is_msi_managed = true; - return ret; + if (ret) + return ret; + + dev->is_msi_managed = true; + return 0; } /* @@ -99,9 +101,10 @@ static int pci_setup_msi_context(struct pci_dev *dev) { int ret = msi_setup_device_data(&dev->dev); - if (!ret) - ret = pcim_setup_msi_release(dev); - return ret; + if (ret) + return ret; + + return pcim_setup_msi_release(dev); } /* -- cgit v1.2.3-59-g8ed1b From 7255fcc80d4b525cc10cfaaf7f485830d4ed2000 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 23 Apr 2024 16:45:37 -0300 Subject: perf tests shell kprobes: Add missing description as used by 'perf test' output Before: root@x1:~# perf test 76 76: SPDX-License-Identifier: GPL-2.0 : Ok root@x1:~# After: root@x1:~# perf test 76 76: Add 'perf probe's, list and remove them. : Ok root@x1:~# Reviewed-by: Ian Rogers Cc: Adrian Hunter Cc: Athira Rajeev Cc: Jiri Olsa Cc: Kajol Jain Cc: Michael Petlan Cc: Namhyung Kim Cc: Veronika Molnarova Link: https://lore.kernel.org/lkml/ZigRDKUGkcDqD-yW@x1 Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/shell/base_probe/test_adding_kernel.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/perf/tests/shell/base_probe/test_adding_kernel.sh b/tools/perf/tests/shell/base_probe/test_adding_kernel.sh index a5d707efad85..63bb8974b38e 100755 --- a/tools/perf/tests/shell/base_probe/test_adding_kernel.sh +++ b/tools/perf/tests/shell/base_probe/test_adding_kernel.sh @@ -1,4 +1,5 @@ #!/bin/bash +# Add 'perf probe's, list and remove them # SPDX-License-Identifier: GPL-2.0 # -- cgit v1.2.3-59-g8ed1b From cd88c11c6d89bcd1851736d853eca57bbde1b042 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 23 Apr 2024 17:23:27 -0300 Subject: tools lib rbtree: Pick some improvements from the kernel rbtree code The tools/lib/rbtree.c code came from the kernel, removing the EXPORT_SYMBOL() that make sense only there, unfortunately it is not being checked with tools/perf/check_headers.sh, will try to remedy this, till then pick the improvements from: b0687c1119b4e8c8 ("lib/rbtree: use '+' instead of '|' for setting color.") That I noticed by doing: diff -u tools/lib/rbtree.c lib/rbtree.c diff -u tools/include/linux/rbtree_augmented.h include/linux/rbtree_augmented.h There is one other cases, but lets pick it in separate patches. Cc: Adrian Hunter Cc: Ian Rogers Cc: Jiri Olsa Cc: Kan Liang Cc: Namhyung Kim Cc: Andrew Morton Cc: Noah Goldstein Link: https://lore.kernel.org/lkml/ZigZzeFoukzRKG1Q@x1 Signed-off-by: Arnaldo Carvalho de Melo --- tools/include/linux/rbtree_augmented.h | 4 ++-- tools/lib/rbtree.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/include/linux/rbtree_augmented.h b/tools/include/linux/rbtree_augmented.h index 570bb9794421..95483c7d81df 100644 --- a/tools/include/linux/rbtree_augmented.h +++ b/tools/include/linux/rbtree_augmented.h @@ -158,13 +158,13 @@ RB_DECLARE_CALLBACKS(RBSTATIC, RBNAME, \ static inline void rb_set_parent(struct rb_node *rb, struct rb_node *p) { - rb->__rb_parent_color = rb_color(rb) | (unsigned long)p; + rb->__rb_parent_color = rb_color(rb) + (unsigned long)p; } static inline void rb_set_parent_color(struct rb_node *rb, struct rb_node *p, int color) { - rb->__rb_parent_color = (unsigned long)p | color; + rb->__rb_parent_color = (unsigned long)p + color; } static inline void diff --git a/tools/lib/rbtree.c b/tools/lib/rbtree.c index 727396de6be5..9e7307186b7f 100644 --- a/tools/lib/rbtree.c +++ b/tools/lib/rbtree.c @@ -58,7 +58,7 @@ static inline void rb_set_black(struct rb_node *rb) { - rb->__rb_parent_color |= RB_BLACK; + rb->__rb_parent_color += RB_BLACK; } static inline struct rb_node *rb_red_parent(struct rb_node *red) -- cgit v1.2.3-59-g8ed1b From e0c48bf9e80ceefb83d74999adeeddbdd95f4c1d Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Tue, 23 Apr 2024 16:32:48 +0300 Subject: perf scripts python: Add a script to run instances of 'perf script' in parallel Add a Python script to run a perf script command multiple times in parallel, using perf script options --cpu and --time so that each job processes a different chunk of the data. Extend perf script tests to test also the new script. The script supports the use of normal 'perf script' options like --dlfilter and --script, so that the benefit of running parallel jobs naturally extends to them also. In addition, a command can be provided (refer --pipe-to option) to pipe standard output to a custom command. Refer to the script's own help text at the end of the patch for more details. The script is useful for Intel PT traces, that can be efficiently decoded by 'perf script' when split by CPU and/or time ranges. Running jobs in parallel can decrease the overall decoding time. Committer testing: Ian reported that shellcheck found some issues, I installed it as there are no warnings about it not being available, but when available it fails the build with: TEST /tmp/build/perf-tools-next/tests/shell/script.sh.shellcheck_log CC /tmp/build/perf-tools-next/util/header.o In tests/shell/script.sh line 20: rm -rf "${temp_dir}/"* ^-------------^ SC2115 (warning): Use "${var:?}" to ensure this never expands to /* . In tests/shell/script.sh line 83: output1_dir="${temp_dir}/output1" ^---------^ SC2034 (warning): output1_dir appears unused. Verify use (or export if used externally). In tests/shell/script.sh line 84: output2_dir="${temp_dir}/output2" ^---------^ SC2034 (warning): output2_dir appears unused. Verify use (or export if used externally). In tests/shell/script.sh line 86: python3 "${pp}" -o "${output_dir}" --jobs 4 --verbose -- perf script -i "${perf_data}" ^-----------^ SC2154 (warning): output_dir is referenced but not assigned (did you mean 'output1_dir'?). For more information: https://www.shellcheck.net/wiki/SC2034 -- output1_dir appears unused. Verif... https://www.shellcheck.net/wiki/SC2115 -- Use "${var:?}" to ensure this nev... https://www.shellcheck.net/wiki/SC2154 -- output_dir is referenced but not ... Did these fixes: - rm -rf "${temp_dir}/"* + rm -rf "${temp_dir:?}/"* And: @@ -83,8 +83,8 @@ test_parallel_perf() output1_dir="${temp_dir}/output1" output2_dir="${temp_dir}/output2" perf record -o "${perf_data}" --sample-cpu uname - python3 "${pp}" -o "${output_dir}" --jobs 4 --verbose -- perf script -i "${perf_data}" - python3 "${pp}" -o "${output_dir}" --jobs 4 --verbose --per-cpu -- perf script -i "${perf_data}" + python3 "${pp}" -o "${output1_dir}" --jobs 4 --verbose -- perf script -i "${perf_data}" + python3 "${pp}" -o "${output2_dir}" --jobs 4 --verbose --per-cpu -- perf script -i "${perf_data}" After that: root@number:~# perf test -vv "perf script tests" 97: perf script tests: --- start --- test child forked, pid 4084139 DB test [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.032 MB /tmp/perf-test-script.T4MJDr0L6J/perf.data (7 samples) ] DB test [Success] parallel-perf test Linux [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.034 MB /tmp/perf-test-script.T4MJDr0L6J/pp-perf.data (7 samples) ] Starting: perf script --time=,91898.301878499 -i /tmp/perf-test-script.T4MJDr0L6J/pp-perf.data Starting: perf script --time=91898.301878500,91898.301905999 -i /tmp/perf-test-script.T4MJDr0L6J/pp-perf.data Starting: perf script --time=91898.301906000,91898.301933499 -i /tmp/perf-test-script.T4MJDr0L6J/pp-perf.data Starting: perf script --time=91898.301933500, -i /tmp/perf-test-script.T4MJDr0L6J/pp-perf.data Finished: perf script --time=91898.301878500,91898.301905999 -i /tmp/perf-test-script.T4MJDr0L6J/pp-perf.data Finished: perf script --time=91898.301906000,91898.301933499 -i /tmp/perf-test-script.T4MJDr0L6J/pp-perf.data There are 4 jobs: 2 completed, 2 running Finished: perf script --time=,91898.301878499 -i /tmp/perf-test-script.T4MJDr0L6J/pp-perf.data Finished: perf script --time=91898.301933500, -i /tmp/perf-test-script.T4MJDr0L6J/pp-perf.data There are 4 jobs: 4 completed, 0 running All jobs finished successfully parallel-perf.py done Starting: perf script --cpu=0 -i /tmp/perf-test-script.T4MJDr0L6J/pp-perf.data Starting: perf script --cpu=1 -i /tmp/perf-test-script.T4MJDr0L6J/pp-perf.data Starting: perf script --cpu=2 -i /tmp/perf-test-script.T4MJDr0L6J/pp-perf.data Starting: perf script --cpu=3 -i /tmp/perf-test-script.T4MJDr0L6J/pp-perf.data Finished: perf script --cpu=0 -i /tmp/perf-test-script.T4MJDr0L6J/pp-perf.data Finished: perf script --cpu=1 -i /tmp/perf-test-script.T4MJDr0L6J/pp-perf.data Finished: perf script --cpu=2 -i /tmp/perf-test-script.T4MJDr0L6J/pp-perf.data Finished: perf script --cpu=3 -i /tmp/perf-test-script.T4MJDr0L6J/pp-perf.data There are 28 jobs: 4 completed, 0 running Starting: perf script --cpu=4 -i /tmp/perf-test-script.T4MJDr0L6J/pp-perf.data Starting: perf script --cpu=5 -i /tmp/perf-test-script.T4MJDr0L6J/pp-perf.data Starting: perf script --cpu=6 -i /tmp/perf-test-script.T4MJDr0L6J/pp-perf.data Starting: perf script --cpu=7 -i /tmp/perf-test-script.T4MJDr0L6J/pp-perf.data Finished: perf script --cpu=4 -i /tmp/perf-test-script.T4MJDr0L6J/pp-perf.data Finished: perf script --cpu=5 -i /tmp/perf-test-script.T4MJDr0L6J/pp-perf.data Finished: perf script --cpu=6 -i /tmp/perf-test-script.T4MJDr0L6J/pp-perf.data Finished: perf script --cpu=7 -i /tmp/perf-test-script.T4MJDr0L6J/pp-perf.data There are 28 jobs: 8 completed, 0 running Starting: perf script --cpu=8 -i /tmp/perf-test-script.T4MJDr0L6J/pp-perf.data Starting: perf script --cpu=9 -i /tmp/perf-test-script.T4MJDr0L6J/pp-perf.data Starting: perf script --cpu=10 -i /tmp/perf-test-script.T4MJDr0L6J/pp-perf.data Starting: perf script --cpu=11 -i /tmp/perf-test-script.T4MJDr0L6J/pp-perf.data Finished: perf script --cpu=8 -i /tmp/perf-test-script.T4MJDr0L6J/pp-perf.data Finished: perf script --cpu=9 -i /tmp/perf-test-script.T4MJDr0L6J/pp-perf.data Finished: perf script --cpu=10 -i /tmp/perf-test-script.T4MJDr0L6J/pp-perf.data Finished: perf script --cpu=11 -i /tmp/perf-test-script.T4MJDr0L6J/pp-perf.data There are 28 jobs: 12 completed, 0 running Starting: perf script --cpu=12 -i /tmp/perf-test-script.T4MJDr0L6J/pp-perf.data Starting: perf script --cpu=13 -i /tmp/perf-test-script.T4MJDr0L6J/pp-perf.data Starting: perf script --cpu=14 -i /tmp/perf-test-script.T4MJDr0L6J/pp-perf.data Starting: perf script --cpu=15 -i /tmp/perf-test-script.T4MJDr0L6J/pp-perf.data Finished: perf script --cpu=12 -i /tmp/perf-test-script.T4MJDr0L6J/pp-perf.data Finished: perf script --cpu=13 -i /tmp/perf-test-script.T4MJDr0L6J/pp-perf.data Finished: perf script --cpu=14 -i /tmp/perf-test-script.T4MJDr0L6J/pp-perf.data Finished: perf script --cpu=15 -i /tmp/perf-test-script.T4MJDr0L6J/pp-perf.data There are 28 jobs: 16 completed, 0 running Starting: perf script --cpu=16 -i /tmp/perf-test-script.T4MJDr0L6J/pp-perf.data Starting: perf script --cpu=17 -i /tmp/perf-test-script.T4MJDr0L6J/pp-perf.data Starting: perf script --cpu=18 -i /tmp/perf-test-script.T4MJDr0L6J/pp-perf.data Starting: perf script --cpu=19 -i /tmp/perf-test-script.T4MJDr0L6J/pp-perf.data Finished: perf script --cpu=16 -i /tmp/perf-test-script.T4MJDr0L6J/pp-perf.data Finished: perf script --cpu=17 -i /tmp/perf-test-script.T4MJDr0L6J/pp-perf.data Finished: perf script --cpu=18 -i /tmp/perf-test-script.T4MJDr0L6J/pp-perf.data Finished: perf script --cpu=19 -i /tmp/perf-test-script.T4MJDr0L6J/pp-perf.data There are 28 jobs: 20 completed, 0 running Starting: perf script --cpu=20 -i /tmp/perf-test-script.T4MJDr0L6J/pp-perf.data Starting: perf script --cpu=21 -i /tmp/perf-test-script.T4MJDr0L6J/pp-perf.data Starting: perf script --cpu=22 -i /tmp/perf-test-script.T4MJDr0L6J/pp-perf.data Starting: perf script --cpu=23 -i /tmp/perf-test-script.T4MJDr0L6J/pp-perf.data Finished: perf script --cpu=20 -i /tmp/perf-test-script.T4MJDr0L6J/pp-perf.data Finished: perf script --cpu=21 -i /tmp/perf-test-script.T4MJDr0L6J/pp-perf.data Finished: perf script --cpu=22 -i /tmp/perf-test-script.T4MJDr0L6J/pp-perf.data Finished: perf script --cpu=23 -i /tmp/perf-test-script.T4MJDr0L6J/pp-perf.data There are 28 jobs: 24 completed, 0 running Starting: perf script --cpu=24 -i /tmp/perf-test-script.T4MJDr0L6J/pp-perf.data Starting: perf script --cpu=25 -i /tmp/perf-test-script.T4MJDr0L6J/pp-perf.data Starting: perf script --cpu=26 -i /tmp/perf-test-script.T4MJDr0L6J/pp-perf.data Starting: perf script --cpu=27 -i /tmp/perf-test-script.T4MJDr0L6J/pp-perf.data Finished: perf script --cpu=25 -i /tmp/perf-test-script.T4MJDr0L6J/pp-perf.data Finished: perf script --cpu=26 -i /tmp/perf-test-script.T4MJDr0L6J/pp-perf.data Finished: perf script --cpu=27 -i /tmp/perf-test-script.T4MJDr0L6J/pp-perf.data There are 28 jobs: 27 completed, 1 running Finished: perf script --cpu=24 -i /tmp/perf-test-script.T4MJDr0L6J/pp-perf.data There are 28 jobs: 28 completed, 0 running All jobs finished successfully parallel-perf.py done parallel-perf test [Success] --- Cleaning up --- ---- end(0) ---- 97: perf script tests : Ok root@number:~# Reviewed-by: Andi Kleen Signed-off-by: Adrian Hunter Tested-by: Arnaldo Carvalho de Melo Cc: Ian Rogers Cc: Jiri Olsa Cc: Namhyung Kim Link: https://lore.kernel.org/r/20240423133248.10206-1-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/scripts/python/parallel-perf.py | 988 +++++++++++++++++++++++++++++ tools/perf/tests/shell/script.sh | 26 +- 2 files changed, 1013 insertions(+), 1 deletion(-) create mode 100755 tools/perf/scripts/python/parallel-perf.py diff --git a/tools/perf/scripts/python/parallel-perf.py b/tools/perf/scripts/python/parallel-perf.py new file mode 100755 index 000000000000..21f32ec5ed46 --- /dev/null +++ b/tools/perf/scripts/python/parallel-perf.py @@ -0,0 +1,988 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-2.0 +# +# Run a perf script command multiple times in parallel, using perf script +# options --cpu and --time so that each job processes a different chunk +# of the data. +# +# Copyright (c) 2024, Intel Corporation. + +import subprocess +import argparse +import pathlib +import shlex +import time +import copy +import sys +import os +import re + +glb_prog_name = "parallel-perf.py" +glb_min_interval = 10.0 +glb_min_samples = 64 + +class Verbosity(): + + def __init__(self, quiet=False, verbose=False, debug=False): + self.normal = True + self.verbose = verbose + self.debug = debug + self.self_test = True + if self.debug: + self.verbose = True + if self.verbose: + quiet = False + if quiet: + self.normal = False + +# Manage work (Start/Wait/Kill), as represented by a subprocess.Popen command +class Work(): + + def __init__(self, cmd, pipe_to, output_dir="."): + self.popen = None + self.consumer = None + self.cmd = cmd + self.pipe_to = pipe_to + self.output_dir = output_dir + self.cmdout_name = f"{output_dir}/cmd.txt" + self.stdout_name = f"{output_dir}/out.txt" + self.stderr_name = f"{output_dir}/err.txt" + + def Command(self): + sh_cmd = [ shlex.quote(x) for x in self.cmd ] + return " ".join(self.cmd) + + def Stdout(self): + return open(self.stdout_name, "w") + + def Stderr(self): + return open(self.stderr_name, "w") + + def CreateOutputDir(self): + pathlib.Path(self.output_dir).mkdir(parents=True, exist_ok=True) + + def Start(self): + if self.popen: + return + self.CreateOutputDir() + with open(self.cmdout_name, "w") as f: + f.write(self.Command()) + f.write("\n") + stdout = self.Stdout() + stderr = self.Stderr() + if self.pipe_to: + self.popen = subprocess.Popen(self.cmd, stdout=subprocess.PIPE, stderr=stderr) + args = shlex.split(self.pipe_to) + self.consumer = subprocess.Popen(args, stdin=self.popen.stdout, stdout=stdout, stderr=stderr) + else: + self.popen = subprocess.Popen(self.cmd, stdout=stdout, stderr=stderr) + + def RemoveEmptyErrFile(self): + if os.path.exists(self.stderr_name): + if os.path.getsize(self.stderr_name) == 0: + os.unlink(self.stderr_name) + + def Errors(self): + if os.path.exists(self.stderr_name): + if os.path.getsize(self.stderr_name) != 0: + return [ f"Non-empty error file {self.stderr_name}" ] + return [] + + def TidyUp(self): + self.RemoveEmptyErrFile() + + def RawPollWait(self, p, wait): + if wait: + return p.wait() + return p.poll() + + def Poll(self, wait=False): + if not self.popen: + return None + result = self.RawPollWait(self.popen, wait) + if self.consumer: + res = result + result = self.RawPollWait(self.consumer, wait) + if result != None and res == None: + self.popen.kill() + result = None + elif result == 0 and res != None and res != 0: + result = res + if result != None: + self.TidyUp() + return result + + def Wait(self): + return self.Poll(wait=True) + + def Kill(self): + if not self.popen: + return + self.popen.kill() + if self.consumer: + self.consumer.kill() + +def KillWork(worklist, verbosity): + for w in worklist: + w.Kill() + for w in worklist: + w.Wait() + +def NumberOfCPUs(): + return os.sysconf("SC_NPROCESSORS_ONLN") + +def NanoSecsToSecsStr(x): + if x == None: + return "" + x = str(x) + if len(x) < 10: + x = "0" * (10 - len(x)) + x + return x[:len(x) - 9] + "." + x[-9:] + +def InsertOptionAfter(cmd, option, after): + try: + pos = cmd.index(after) + cmd.insert(pos + 1, option) + except: + cmd.append(option) + +def CreateWorkList(cmd, pipe_to, output_dir, cpus, time_ranges_by_cpu): + max_len = len(str(cpus[-1])) + cpu_dir_fmt = f"cpu-%.{max_len}u" + worklist = [] + pos = 0 + for cpu in cpus: + if cpu >= 0: + cpu_dir = os.path.join(output_dir, cpu_dir_fmt % cpu) + cpu_option = f"--cpu={cpu}" + else: + cpu_dir = output_dir + cpu_option = None + + tr_dir_fmt = "time-range" + + if len(time_ranges_by_cpu) > 1: + time_ranges = time_ranges_by_cpu[pos] + tr_dir_fmt += f"-{pos}" + pos += 1 + else: + time_ranges = time_ranges_by_cpu[0] + + max_len = len(str(len(time_ranges))) + tr_dir_fmt += f"-%.{max_len}u" + + i = 0 + for r in time_ranges: + if r == [None, None]: + time_option = None + work_output_dir = cpu_dir + else: + time_option = "--time=" + NanoSecsToSecsStr(r[0]) + "," + NanoSecsToSecsStr(r[1]) + work_output_dir = os.path.join(cpu_dir, tr_dir_fmt % i) + i += 1 + work_cmd = list(cmd) + if time_option != None: + InsertOptionAfter(work_cmd, time_option, "script") + if cpu_option != None: + InsertOptionAfter(work_cmd, cpu_option, "script") + w = Work(work_cmd, pipe_to, work_output_dir) + worklist.append(w) + return worklist + +def DoRunWork(worklist, nr_jobs, verbosity): + nr_to_do = len(worklist) + not_started = list(worklist) + running = [] + done = [] + chg = False + while True: + nr_done = len(done) + if chg and verbosity.normal: + nr_run = len(running) + print(f"\rThere are {nr_to_do} jobs: {nr_done} completed, {nr_run} running", flush=True, end=" ") + if verbosity.verbose: + print() + chg = False + if nr_done == nr_to_do: + break + while len(running) < nr_jobs and len(not_started): + w = not_started.pop(0) + running.append(w) + if verbosity.verbose: + print("Starting:", w.Command()) + w.Start() + chg = True + if len(running): + time.sleep(0.1) + finished = [] + not_finished = [] + while len(running): + w = running.pop(0) + r = w.Poll() + if r == None: + not_finished.append(w) + continue + if r == 0: + if verbosity.verbose: + print("Finished:", w.Command()) + finished.append(w) + chg = True + continue + if verbosity.normal and not verbosity.verbose: + print() + print("Job failed!\n return code:", r, "\n command: ", w.Command()) + if w.pipe_to: + print(" piped to: ", w.pipe_to) + print("Killing outstanding jobs") + KillWork(not_finished, verbosity) + KillWork(running, verbosity) + return False + running = not_finished + done += finished + errorlist = [] + for w in worklist: + errorlist += w.Errors() + if len(errorlist): + print("Errors:") + for e in errorlist: + print(e) + elif verbosity.normal: + print("\r"," "*50, "\rAll jobs finished successfully", flush=True) + return True + +def RunWork(worklist, nr_jobs=NumberOfCPUs(), verbosity=Verbosity()): + try: + return DoRunWork(worklist, nr_jobs, verbosity) + except: + for w in worklist: + w.Kill() + raise + return True + +def ReadHeader(perf, file_name): + return subprocess.Popen([perf, "script", "--header-only", "--input", file_name], stdout=subprocess.PIPE).stdout.read().decode("utf-8") + +def ParseHeader(hdr): + result = {} + lines = hdr.split("\n") + for line in lines: + if ":" in line and line[0] == "#": + pos = line.index(":") + name = line[1:pos-1].strip() + value = line[pos+1:].strip() + if name in result: + orig_name = name + nr = 2 + while True: + name = f"{orig_name} {nr}" + if name not in result: + break + nr += 1 + result[name] = value + return result + +def HeaderField(hdr_dict, hdr_fld): + if hdr_fld not in hdr_dict: + raise Exception(f"'{hdr_fld}' missing from header information") + return hdr_dict[hdr_fld] + +# Represent the position of an option within a command string +# and provide the option value and/or remove the option +class OptPos(): + + def Init(self, opt_element=-1, value_element=-1, opt_pos=-1, value_pos=-1, error=None): + self.opt_element = opt_element # list element that contains option + self.value_element = value_element # list element that contains option value + self.opt_pos = opt_pos # string position of option + self.value_pos = value_pos # string position of value + self.error = error # error message string + + def __init__(self, args, short_name, long_name, default=None): + self.args = list(args) + self.default = default + n = 2 + len(long_name) + m = len(short_name) + pos = -1 + for opt in args: + pos += 1 + if m and opt[:2] == f"-{short_name}": + if len(opt) == 2: + if pos + 1 < len(args): + self.Init(pos, pos + 1, 0, 0) + else: + self.Init(error = f"-{short_name} option missing value") + else: + self.Init(pos, pos, 0, 2) + return + if opt[:n] == f"--{long_name}": + if len(opt) == n: + if pos + 1 < len(args): + self.Init(pos, pos + 1, 0, 0) + else: + self.Init(error = f"--{long_name} option missing value") + elif opt[n] == "=": + self.Init(pos, pos, 0, n + 1) + else: + self.Init(error = f"--{long_name} option expected '='") + return + if m and opt[:1] == "-" and opt[:2] != "--" and short_name in opt: + ipos = opt.index(short_name) + if "-" in opt[1:]: + hpos = opt[1:].index("-") + if hpos < ipos: + continue + if ipos + 1 == len(opt): + if pos + 1 < len(args): + self.Init(pos, pos + 1, ipos, 0) + else: + self.Init(error = f"-{short_name} option missing value") + else: + self.Init(pos, pos, ipos, ipos + 1) + return + self.Init() + + def Value(self): + if self.opt_element >= 0: + if self.opt_element != self.value_element: + return self.args[self.value_element] + else: + return self.args[self.value_element][self.value_pos:] + return self.default + + def Remove(self, args): + if self.opt_element == -1: + return + if self.opt_element != self.value_element: + del args[self.value_element] + if self.opt_pos: + args[self.opt_element] = args[self.opt_element][:self.opt_pos] + else: + del args[self.opt_element] + +def DetermineInputFileName(cmd): + p = OptPos(cmd, "i", "input", "perf.data") + if p.error: + raise Exception(f"perf command {p.error}") + file_name = p.Value() + if not os.path.exists(file_name): + raise Exception(f"perf command input file '{file_name}' not found") + return file_name + +def ReadOption(args, short_name, long_name, err_prefix, remove=False): + p = OptPos(args, short_name, long_name) + if p.error: + raise Exception(f"{err_prefix}{p.error}") + value = p.Value() + if remove: + p.Remove(args) + return value + +def ExtractOption(args, short_name, long_name, err_prefix): + return ReadOption(args, short_name, long_name, err_prefix, True) + +def ReadPerfOption(args, short_name, long_name): + return ReadOption(args, short_name, long_name, "perf command ") + +def ExtractPerfOption(args, short_name, long_name): + return ExtractOption(args, short_name, long_name, "perf command ") + +def PerfDoubleQuickCommands(cmd, file_name): + cpu_str = ReadPerfOption(cmd, "C", "cpu") + time_str = ReadPerfOption(cmd, "", "time") + # Use double-quick sampling to determine trace data density + times_cmd = ["perf", "script", "--ns", "--input", file_name, "--itrace=qqi"] + if cpu_str != None and cpu_str != "": + times_cmd.append(f"--cpu={cpu_str}") + if time_str != None and time_str != "": + times_cmd.append(f"--time={time_str}") + cnts_cmd = list(times_cmd) + cnts_cmd.append("-Fcpu") + times_cmd.append("-Fcpu,time") + return cnts_cmd, times_cmd + +class CPUTimeRange(): + def __init__(self, cpu): + self.cpu = cpu + self.sample_cnt = 0 + self.time_ranges = None + self.interval = 0 + self.interval_remaining = 0 + self.remaining = 0 + self.tr_pos = 0 + +def CalcTimeRangesByCPU(line, cpu, cpu_time_ranges, max_time): + cpu_time_range = cpu_time_ranges[cpu] + cpu_time_range.remaining -= 1 + cpu_time_range.interval_remaining -= 1 + if cpu_time_range.remaining == 0: + cpu_time_range.time_ranges[cpu_time_range.tr_pos][1] = max_time + return + if cpu_time_range.interval_remaining == 0: + time = TimeVal(line[1][:-1], 0) + time_ranges = cpu_time_range.time_ranges + time_ranges[cpu_time_range.tr_pos][1] = time - 1 + time_ranges.append([time, max_time]) + cpu_time_range.tr_pos += 1 + cpu_time_range.interval_remaining = cpu_time_range.interval + +def CountSamplesByCPU(line, cpu, cpu_time_ranges): + try: + cpu_time_ranges[cpu].sample_cnt += 1 + except: + print("exception") + print("cpu", cpu) + print("len(cpu_time_ranges)", len(cpu_time_ranges)) + raise + +def ProcessCommandOutputLines(cmd, per_cpu, fn, *x): + # Assume CPU number is at beginning of line and enclosed by [] + pat = re.compile(r"\s*\[[0-9]+\]") + p = subprocess.Popen(cmd, stdout=subprocess.PIPE) + while True: + if line := p.stdout.readline(): + line = line.decode("utf-8") + if pat.match(line): + line = line.split() + if per_cpu: + # Assumes CPU number is enclosed by [] + cpu = int(line[0][1:-1]) + else: + cpu = 0 + fn(line, cpu, *x) + else: + break + p.wait() + +def IntersectTimeRanges(new_time_ranges, time_ranges): + pos = 0 + new_pos = 0 + # Can assume len(time_ranges) != 0 and len(new_time_ranges) != 0 + # Note also, there *must* be at least one intersection. + while pos < len(time_ranges) and new_pos < len(new_time_ranges): + # new end < old start => no intersection, remove new + if new_time_ranges[new_pos][1] < time_ranges[pos][0]: + del new_time_ranges[new_pos] + continue + # new start > old end => no intersection, check next + if new_time_ranges[new_pos][0] > time_ranges[pos][1]: + pos += 1 + if pos < len(time_ranges): + continue + # no next, so remove remaining + while new_pos < len(new_time_ranges): + del new_time_ranges[new_pos] + return + # Found an intersection + # new start < old start => adjust new start = old start + if new_time_ranges[new_pos][0] < time_ranges[pos][0]: + new_time_ranges[new_pos][0] = time_ranges[pos][0] + # new end > old end => keep the overlap, insert the remainder + if new_time_ranges[new_pos][1] > time_ranges[pos][1]: + r = [ time_ranges[pos][1] + 1, new_time_ranges[new_pos][1] ] + new_time_ranges[new_pos][1] = time_ranges[pos][1] + new_pos += 1 + new_time_ranges.insert(new_pos, r) + continue + # new [start, end] is within old [start, end] + new_pos += 1 + +def SplitTimeRangesByTraceDataDensity(time_ranges, cpus, nr, cmd, file_name, per_cpu, min_size, min_interval, verbosity): + if verbosity.normal: + print("\rAnalyzing...", flush=True, end=" ") + if verbosity.verbose: + print() + cnts_cmd, times_cmd = PerfDoubleQuickCommands(cmd, file_name) + + nr_cpus = cpus[-1] + 1 if per_cpu else 1 + if per_cpu: + nr_cpus = cpus[-1] + 1 + cpu_time_ranges = [ CPUTimeRange(cpu) for cpu in range(nr_cpus) ] + else: + nr_cpus = 1 + cpu_time_ranges = [ CPUTimeRange(-1) ] + + if verbosity.debug: + print("nr_cpus", nr_cpus) + print("cnts_cmd", cnts_cmd) + print("times_cmd", times_cmd) + + # Count the number of "double quick" samples per CPU + ProcessCommandOutputLines(cnts_cmd, per_cpu, CountSamplesByCPU, cpu_time_ranges) + + tot = 0 + mx = 0 + for cpu_time_range in cpu_time_ranges: + cnt = cpu_time_range.sample_cnt + tot += cnt + if cnt > mx: + mx = cnt + if verbosity.debug: + print("cpu:", cpu_time_range.cpu, "sample_cnt", cnt) + + if min_size < 1: + min_size = 1 + + if mx < min_size: + # Too little data to be worth splitting + if verbosity.debug: + print("Too little data to split by time") + if nr == 0: + nr = 1 + return [ SplitTimeRangesIntoN(time_ranges, nr, min_interval) ] + + if nr: + divisor = nr + min_size = 1 + else: + divisor = NumberOfCPUs() + + interval = int(round(tot / divisor, 0)) + if interval < min_size: + interval = min_size + + if verbosity.debug: + print("divisor", divisor) + print("min_size", min_size) + print("interval", interval) + + min_time = time_ranges[0][0] + max_time = time_ranges[-1][1] + + for cpu_time_range in cpu_time_ranges: + cnt = cpu_time_range.sample_cnt + if cnt == 0: + cpu_time_range.time_ranges = copy.deepcopy(time_ranges) + continue + # Adjust target interval for CPU to give approximately equal interval sizes + # Determine number of intervals, rounding to nearest integer + n = int(round(cnt / interval, 0)) + if n < 1: + n = 1 + # Determine interval size, rounding up + d, m = divmod(cnt, n) + if m: + d += 1 + cpu_time_range.interval = d + cpu_time_range.interval_remaining = d + cpu_time_range.remaining = cnt + # Init. time ranges for each CPU with the start time + cpu_time_range.time_ranges = [ [min_time, max_time] ] + + # Set time ranges so that the same number of "double quick" samples + # will fall into each time range. + ProcessCommandOutputLines(times_cmd, per_cpu, CalcTimeRangesByCPU, cpu_time_ranges, max_time) + + for cpu_time_range in cpu_time_ranges: + if cpu_time_range.sample_cnt: + IntersectTimeRanges(cpu_time_range.time_ranges, time_ranges) + + return [cpu_time_ranges[cpu].time_ranges for cpu in cpus] + +def SplitSingleTimeRangeIntoN(time_range, n): + if n <= 1: + return [time_range] + start = time_range[0] + end = time_range[1] + duration = int((end - start + 1) / n) + if duration < 1: + return [time_range] + time_ranges = [] + for i in range(n): + time_ranges.append([start, start + duration - 1]) + start += duration + time_ranges[-1][1] = end + return time_ranges + +def TimeRangeDuration(r): + return r[1] - r[0] + 1 + +def TotalDuration(time_ranges): + duration = 0 + for r in time_ranges: + duration += TimeRangeDuration(r) + return duration + +def SplitTimeRangesByInterval(time_ranges, interval): + new_ranges = [] + for r in time_ranges: + duration = TimeRangeDuration(r) + n = duration / interval + n = int(round(n, 0)) + new_ranges += SplitSingleTimeRangeIntoN(r, n) + return new_ranges + +def SplitTimeRangesIntoN(time_ranges, n, min_interval): + if n <= len(time_ranges): + return time_ranges + duration = TotalDuration(time_ranges) + interval = duration / n + if interval < min_interval: + interval = min_interval + return SplitTimeRangesByInterval(time_ranges, interval) + +def RecombineTimeRanges(tr): + new_tr = copy.deepcopy(tr) + n = len(new_tr) + i = 1 + while i < len(new_tr): + # if prev end + 1 == cur start, combine them + if new_tr[i - 1][1] + 1 == new_tr[i][0]: + new_tr[i][0] = new_tr[i - 1][0] + del new_tr[i - 1] + else: + i += 1 + return new_tr + +def OpenTimeRangeEnds(time_ranges, min_time, max_time): + if time_ranges[0][0] <= min_time: + time_ranges[0][0] = None + if time_ranges[-1][1] >= max_time: + time_ranges[-1][1] = None + +def BadTimeStr(time_str): + raise Exception(f"perf command bad time option: '{time_str}'\nCheck also 'time of first sample' and 'time of last sample' in perf script --header-only") + +def ValidateTimeRanges(time_ranges, time_str): + n = len(time_ranges) + for i in range(n): + start = time_ranges[i][0] + end = time_ranges[i][1] + if i != 0 and start <= time_ranges[i - 1][1]: + BadTimeStr(time_str) + if start > end: + BadTimeStr(time_str) + +def TimeVal(s, dflt): + s = s.strip() + if s == "": + return dflt + a = s.split(".") + if len(a) > 2: + raise Exception(f"Bad time value'{s}'") + x = int(a[0]) + if x < 0: + raise Exception("Negative time not allowed") + x *= 1000000000 + if len(a) > 1: + x += int((a[1] + "000000000")[:9]) + return x + +def BadCPUStr(cpu_str): + raise Exception(f"perf command bad cpu option: '{cpu_str}'\nCheck also 'nrcpus avail' in perf script --header-only") + +def ParseTimeStr(time_str, min_time, max_time): + if time_str == None or time_str == "": + return [[min_time, max_time]] + time_ranges = [] + for r in time_str.split(): + a = r.split(",") + if len(a) != 2: + BadTimeStr(time_str) + try: + start = TimeVal(a[0], min_time) + end = TimeVal(a[1], max_time) + except: + BadTimeStr(time_str) + time_ranges.append([start, end]) + ValidateTimeRanges(time_ranges, time_str) + return time_ranges + +def ParseCPUStr(cpu_str, nr_cpus): + if cpu_str == None or cpu_str == "": + return [-1] + cpus = [] + for r in cpu_str.split(","): + a = r.split("-") + if len(a) < 1 or len(a) > 2: + BadCPUStr(cpu_str) + try: + start = int(a[0].strip()) + if len(a) > 1: + end = int(a[1].strip()) + else: + end = start + except: + BadCPUStr(cpu_str) + if start < 0 or end < 0 or end < start or end >= nr_cpus: + BadCPUStr(cpu_str) + cpus.extend(range(start, end + 1)) + cpus = list(set(cpus)) # Remove duplicates + cpus.sort() + return cpus + +class ParallelPerf(): + + def __init__(self, a): + for arg_name in vars(a): + setattr(self, arg_name, getattr(a, arg_name)) + self.orig_nr = self.nr + self.orig_cmd = list(self.cmd) + self.perf = self.cmd[0] + if os.path.exists(self.output_dir): + raise Exception(f"Output '{self.output_dir}' already exists") + if self.jobs < 0 or self.nr < 0 or self.interval < 0: + raise Exception("Bad options (negative values): try -h option for help") + if self.nr != 0 and self.interval != 0: + raise Exception("Cannot specify number of time subdivisions and time interval") + if self.jobs == 0: + self.jobs = NumberOfCPUs() + if self.nr == 0 and self.interval == 0: + if self.per_cpu: + self.nr = 1 + else: + self.nr = self.jobs + + def Init(self): + if self.verbosity.debug: + print("cmd", self.cmd) + self.file_name = DetermineInputFileName(self.cmd) + self.hdr = ReadHeader(self.perf, self.file_name) + self.hdr_dict = ParseHeader(self.hdr) + self.cmd_line = HeaderField(self.hdr_dict, "cmdline") + + def ExtractTimeInfo(self): + self.min_time = TimeVal(HeaderField(self.hdr_dict, "time of first sample"), 0) + self.max_time = TimeVal(HeaderField(self.hdr_dict, "time of last sample"), 0) + self.time_str = ExtractPerfOption(self.cmd, "", "time") + self.time_ranges = ParseTimeStr(self.time_str, self.min_time, self.max_time) + if self.verbosity.debug: + print("time_ranges", self.time_ranges) + + def ExtractCPUInfo(self): + if self.per_cpu: + nr_cpus = int(HeaderField(self.hdr_dict, "nrcpus avail")) + self.cpu_str = ExtractPerfOption(self.cmd, "C", "cpu") + if self.cpu_str == None or self.cpu_str == "": + self.cpus = [ x for x in range(nr_cpus) ] + else: + self.cpus = ParseCPUStr(self.cpu_str, nr_cpus) + else: + self.cpu_str = None + self.cpus = [-1] + if self.verbosity.debug: + print("cpus", self.cpus) + + def IsIntelPT(self): + return self.cmd_line.find("intel_pt") >= 0 + + def SplitTimeRanges(self): + if self.IsIntelPT() and self.interval == 0: + self.split_time_ranges_for_each_cpu = \ + SplitTimeRangesByTraceDataDensity(self.time_ranges, self.cpus, self.orig_nr, + self.orig_cmd, self.file_name, self.per_cpu, + self.min_size, self.min_interval, self.verbosity) + elif self.nr: + self.split_time_ranges_for_each_cpu = [ SplitTimeRangesIntoN(self.time_ranges, self.nr, self.min_interval) ] + else: + self.split_time_ranges_for_each_cpu = [ SplitTimeRangesByInterval(self.time_ranges, self.interval) ] + + def CheckTimeRanges(self): + for tr in self.split_time_ranges_for_each_cpu: + # Re-combined time ranges should be the same + new_tr = RecombineTimeRanges(tr) + if new_tr != self.time_ranges: + if self.verbosity.debug: + print("tr", tr) + print("new_tr", new_tr) + raise Exception("Self test failed!") + + def OpenTimeRangeEnds(self): + for time_ranges in self.split_time_ranges_for_each_cpu: + OpenTimeRangeEnds(time_ranges, self.min_time, self.max_time) + + def CreateWorkList(self): + self.worklist = CreateWorkList(self.cmd, self.pipe_to, self.output_dir, self.cpus, self.split_time_ranges_for_each_cpu) + + def PerfDataRecordedPerCPU(self): + if "--per-thread" in self.cmd_line.split(): + return False + return True + + def DefaultToPerCPU(self): + # --no-per-cpu option takes precedence + if self.no_per_cpu: + return False + if not self.PerfDataRecordedPerCPU(): + return False + # Default to per-cpu for Intel PT data that was recorded per-cpu, + # because decoding can be done for each CPU separately. + if self.IsIntelPT(): + return True + return False + + def Config(self): + self.Init() + self.ExtractTimeInfo() + if not self.per_cpu: + self.per_cpu = self.DefaultToPerCPU() + if self.verbosity.debug: + print("per_cpu", self.per_cpu) + self.ExtractCPUInfo() + self.SplitTimeRanges() + if self.verbosity.self_test: + self.CheckTimeRanges() + # Prefer open-ended time range to starting / ending with min_time / max_time resp. + self.OpenTimeRangeEnds() + self.CreateWorkList() + + def Run(self): + if self.dry_run: + print(len(self.worklist),"jobs:") + for w in self.worklist: + print(w.Command()) + return True + result = RunWork(self.worklist, self.jobs, verbosity=self.verbosity) + if self.verbosity.verbose: + print(glb_prog_name, "done") + return result + +def RunParallelPerf(a): + pp = ParallelPerf(a) + pp.Config() + return pp.Run() + +def Main(args): + ap = argparse.ArgumentParser( + prog=glb_prog_name, formatter_class = argparse.RawDescriptionHelpFormatter, + description = +""" +Run a perf script command multiple times in parallel, using perf script options +--cpu and --time so that each job processes a different chunk of the data. +""", + epilog = +""" +Follow the options by '--' and then the perf script command e.g. + + $ perf record -a -- sleep 10 + $ parallel-perf.py --nr=4 -- perf script --ns + All jobs finished successfully + $ tree parallel-perf-output/ + parallel-perf-output/ + ├── time-range-0 + │   ├── cmd.txt + │   └── out.txt + ├── time-range-1 + │   ├── cmd.txt + │   └── out.txt + ├── time-range-2 + │   ├── cmd.txt + │   └── out.txt + └── time-range-3 + ├── cmd.txt + └── out.txt + $ find parallel-perf-output -name cmd.txt | sort | xargs grep -H . + parallel-perf-output/time-range-0/cmd.txt:perf script --time=,9466.504461499 --ns + parallel-perf-output/time-range-1/cmd.txt:perf script --time=9466.504461500,9469.005396999 --ns + parallel-perf-output/time-range-2/cmd.txt:perf script --time=9469.005397000,9471.506332499 --ns + parallel-perf-output/time-range-3/cmd.txt:perf script --time=9471.506332500, --ns + +Any perf script command can be used, including the use of perf script options +--dlfilter and --script, so that the benefit of running parallel jobs +naturally extends to them also. + +If option --pipe-to is used, standard output is first piped through that +command. Beware, if the command fails (e.g. grep with no matches), it will be +considered a fatal error. + +Final standard output is redirected to files named out.txt in separate +subdirectories under the output directory. Similarly, standard error is +written to files named err.txt. In addition, files named cmd.txt contain the +corresponding perf script command. After processing, err.txt files are removed +if they are empty. + +If any job exits with a non-zero exit code, then all jobs are killed and no +more are started. A message is printed if any job results in a non-empty +err.txt file. + +There is a separate output subdirectory for each time range. If the --per-cpu +option is used, these are further grouped under cpu-n subdirectories, e.g. + + $ parallel-perf.py --per-cpu --nr=2 -- perf script --ns --cpu=0,1 + All jobs finished successfully + $ tree parallel-perf-output + parallel-perf-output/ + ├── cpu-0 + │   ├── time-range-0 + │   │   ├── cmd.txt + │   │   └── out.txt + │   └── time-range-1 + │   ├── cmd.txt + │   └── out.txt + └── cpu-1 + ├── time-range-0 + │   ├── cmd.txt + │   └── out.txt + └── time-range-1 + ├── cmd.txt + └── out.txt + $ find parallel-perf-output -name cmd.txt | sort | xargs grep -H . + parallel-perf-output/cpu-0/time-range-0/cmd.txt:perf script --cpu=0 --time=,9469.005396999 --ns + parallel-perf-output/cpu-0/time-range-1/cmd.txt:perf script --cpu=0 --time=9469.005397000, --ns + parallel-perf-output/cpu-1/time-range-0/cmd.txt:perf script --cpu=1 --time=,9469.005396999 --ns + parallel-perf-output/cpu-1/time-range-1/cmd.txt:perf script --cpu=1 --time=9469.005397000, --ns + +Subdivisions of time range, and cpus if the --per-cpu option is used, are +expressed by the --time and --cpu perf script options respectively. If the +supplied perf script command has a --time option, then that time range is +subdivided, otherwise the time range given by 'time of first sample' to +'time of last sample' is used (refer perf script --header-only). Similarly, the +supplied perf script command may provide a --cpu option, and only those CPUs +will be processed. + +To prevent time intervals becoming too small, the --min-interval option can +be used. + +Note there is special handling for processing Intel PT traces. If an interval is +not specified and the perf record command contained the intel_pt event, then the +time range will be subdivided in order to produce subdivisions that contain +approximately the same amount of trace data. That is accomplished by counting +double-quick (--itrace=qqi) samples, and choosing time ranges that encompass +approximately the same number of samples. In that case, time ranges may not be +the same for each CPU processed. For Intel PT, --per-cpu is the default, but +that can be overridden by --no-per-cpu. Note, for Intel PT, double-quick +decoding produces 1 sample for each PSB synchronization packet, which in turn +come after a certain number of bytes output, determined by psb_period (refer +perf Intel PT documentation). The minimum number of double-quick samples that +will define a time range can be set by the --min_size option, which defaults to +64. +""") + ap.add_argument("-o", "--output-dir", default="parallel-perf-output", help="output directory (default 'parallel-perf-output')") + ap.add_argument("-j", "--jobs", type=int, default=0, help="maximum number of jobs to run in parallel at one time (default is the number of CPUs)") + ap.add_argument("-n", "--nr", type=int, default=0, help="number of time subdivisions (default is the number of jobs)") + ap.add_argument("-i", "--interval", type=float, default=0, help="subdivide the time range using this time interval (in seconds e.g. 0.1 for a tenth of a second)") + ap.add_argument("-c", "--per-cpu", action="store_true", help="process data for each CPU in parallel") + ap.add_argument("-m", "--min-interval", type=float, default=glb_min_interval, help=f"minimum interval (default {glb_min_interval} seconds)") + ap.add_argument("-p", "--pipe-to", help="command to pipe output to (optional)") + ap.add_argument("-N", "--no-per-cpu", action="store_true", help="do not process data for each CPU in parallel") + ap.add_argument("-b", "--min_size", type=int, default=glb_min_samples, help="minimum data size (for Intel PT in PSBs)") + ap.add_argument("-D", "--dry-run", action="store_true", help="do not run any jobs, just show the perf script commands") + ap.add_argument("-q", "--quiet", action="store_true", help="do not print any messages except errors") + ap.add_argument("-v", "--verbose", action="store_true", help="print more messages") + ap.add_argument("-d", "--debug", action="store_true", help="print debugging messages") + cmd_line = list(args) + try: + split_pos = cmd_line.index("--") + cmd = cmd_line[split_pos + 1:] + args = cmd_line[:split_pos] + except: + cmd = None + args = cmd_line + a = ap.parse_args(args=args[1:]) + a.cmd = cmd + a.verbosity = Verbosity(a.quiet, a.verbose, a.debug) + try: + if a.cmd == None: + if len(args) <= 1: + ap.print_help() + return True + raise Exception("Command line must contain '--' before perf command") + return RunParallelPerf(a) + except Exception as e: + print("Fatal error: ", str(e)) + if a.debug: + raise + return False + +if __name__ == "__main__": + if not Main(sys.argv): + sys.exit(1) diff --git a/tools/perf/tests/shell/script.sh b/tools/perf/tests/shell/script.sh index fa4d71e2e72a..c1a603653662 100755 --- a/tools/perf/tests/shell/script.sh +++ b/tools/perf/tests/shell/script.sh @@ -17,7 +17,7 @@ cleanup() sane=$(echo "${temp_dir}" | cut -b 1-21) if [ "${sane}" = "/tmp/perf-test-script" ] ; then echo "--- Cleaning up ---" - rm -f "${temp_dir}/"* + rm -rf "${temp_dir:?}/"* rmdir "${temp_dir}" fi } @@ -65,7 +65,31 @@ _end_of_file_ echo "DB test [Success]" } +test_parallel_perf() +{ + echo "parallel-perf test" + if ! python3 --version >/dev/null 2>&1 ; then + echo "SKIP: no python3" + err=2 + return + fi + pp=$(dirname "$0")/../../scripts/python/parallel-perf.py + if [ ! -f "${pp}" ] ; then + echo "SKIP: parallel-perf.py script not found " + err=2 + return + fi + perf_data="${temp_dir}/pp-perf.data" + output1_dir="${temp_dir}/output1" + output2_dir="${temp_dir}/output2" + perf record -o "${perf_data}" --sample-cpu uname + python3 "${pp}" -o "${output1_dir}" --jobs 4 --verbose -- perf script -i "${perf_data}" + python3 "${pp}" -o "${output2_dir}" --jobs 4 --verbose --per-cpu -- perf script -i "${perf_data}" + echo "parallel-perf test [Success]" +} + test_db +test_parallel_perf cleanup -- cgit v1.2.3-59-g8ed1b From 8b734eaa98ac3f22bbaa253273fd16f391b3d5f8 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 15 Apr 2024 23:15:17 -0700 Subject: perf parse-events: Factor out '/.../' parsing Factor out the case of an event or PMU name followed by a slash based term list. This is with a view to sharing the code with new legacy hardware parsing. Use early return to reduce indentation in the code. Make parse_events_add_pmu static now it doesn't need sharing with parse-events.y. Signed-off-by: Ian Rogers Reviewed-by: Kan Liang Tested-by: Atish Patra Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Beeman Strong Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20240416061533.921723-2-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-events.c | 70 +++++++++++++++++++++++++++++++++++++++- tools/perf/util/parse-events.h | 10 +++--- tools/perf/util/parse-events.y | 73 +++--------------------------------------- 3 files changed, 80 insertions(+), 73 deletions(-) diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 6f8b0fa17689..a6f71165ee1a 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -1385,7 +1385,7 @@ static bool config_term_percore(struct list_head *config_terms) return false; } -int parse_events_add_pmu(struct parse_events_state *parse_state, +static int parse_events_add_pmu(struct parse_events_state *parse_state, struct list_head *list, const char *name, const struct parse_events_terms *const_parsed_terms, bool auto_merge_stats, void *loc_) @@ -1618,6 +1618,74 @@ out_err: return ok ? 0 : -1; } +int parse_events_multi_pmu_add_or_add_pmu(struct parse_events_state *parse_state, + const char *event_or_pmu, + const struct parse_events_terms *const_parsed_terms, + struct list_head **listp, + void *loc_) +{ + char *pattern = NULL; + YYLTYPE *loc = loc_; + struct perf_pmu *pmu = NULL; + int ok = 0; + char *help; + + *listp = malloc(sizeof(**listp)); + if (!*listp) + return -ENOMEM; + + INIT_LIST_HEAD(*listp); + + /* Attempt to add to list assuming event_or_pmu is a PMU name. */ + if (!parse_events_add_pmu(parse_state, *listp, event_or_pmu, const_parsed_terms, + /*auto_merge_stats=*/false, loc)) + return 0; + + /* Failed to add, try wildcard expansion of event_or_pmu as a PMU name. */ + if (asprintf(&pattern, "%s*", event_or_pmu) < 0) { + zfree(listp); + return -ENOMEM; + } + + while ((pmu = perf_pmus__scan(pmu)) != NULL) { + const char *name = pmu->name; + + if (parse_events__filter_pmu(parse_state, pmu)) + continue; + + if (!strncmp(name, "uncore_", 7) && + strncmp(event_or_pmu, "uncore_", 7)) + name += 7; + if (!perf_pmu__match(pattern, name, event_or_pmu) || + !perf_pmu__match(pattern, pmu->alias_name, event_or_pmu)) { + bool auto_merge_stats = perf_pmu__auto_merge_stats(pmu); + + if (!parse_events_add_pmu(parse_state, *listp, pmu->name, + const_parsed_terms, + auto_merge_stats, loc)) { + ok++; + parse_state->wild_card_pmus = true; + } + } + } + zfree(&pattern); + if (ok) + return 0; + + /* Failure to add, assume event_or_pmu is an event name. */ + zfree(listp); + if (!parse_events_multi_pmu_add(parse_state, event_or_pmu, const_parsed_terms, listp, loc)) + return 0; + + if (asprintf(&help, "Unable to find PMU or event on a PMU of '%s'", event_or_pmu) < 0) + help = NULL; + parse_events_error__handle(parse_state->error, loc->first_column, + strdup("Bad event or PMU"), + help); + zfree(listp); + return -EINVAL; +} + int parse_events__modifier_group(struct list_head *list, char *event_mod) { diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index 809359e8544e..a331b9f0da2b 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h @@ -209,10 +209,6 @@ int parse_events_add_breakpoint(struct parse_events_state *parse_state, struct list_head *list, u64 addr, char *type, u64 len, struct parse_events_terms *head_config); -int parse_events_add_pmu(struct parse_events_state *parse_state, - struct list_head *list, const char *name, - const struct parse_events_terms *const_parsed_terms, - bool auto_merge_stats, void *loc); struct evsel *parse_events__add_event(int idx, struct perf_event_attr *attr, const char *name, const char *metric_id, @@ -223,6 +219,12 @@ int parse_events_multi_pmu_add(struct parse_events_state *parse_state, const struct parse_events_terms *const_parsed_terms, struct list_head **listp, void *loc); +int parse_events_multi_pmu_add_or_add_pmu(struct parse_events_state *parse_state, + const char *event_or_pmu, + const struct parse_events_terms *const_parsed_terms, + struct list_head **listp, + void *loc_); + void parse_events__set_leader(char *name, struct list_head *list); void parse_events_update_lists(struct list_head *list_event, struct list_head *list_all); diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y index d70f5d84af92..7764e5895210 100644 --- a/tools/perf/util/parse-events.y +++ b/tools/perf/util/parse-events.y @@ -273,78 +273,15 @@ event_def: event_pmu | event_pmu: PE_NAME opt_pmu_config { - struct parse_events_state *parse_state = _parse_state; /* List of created evsels. */ struct list_head *list = NULL; - char *pattern = NULL; - -#define CLEANUP \ - do { \ - parse_events_terms__delete($2); \ - free(list); \ - free($1); \ - free(pattern); \ - } while(0) + int err = parse_events_multi_pmu_add_or_add_pmu(_parse_state, $1, $2, &list, &@1); - list = alloc_list(); - if (!list) { - CLEANUP; - YYNOMEM; - } - /* Attempt to add to list assuming $1 is a PMU name. */ - if (parse_events_add_pmu(parse_state, list, $1, $2, /*auto_merge_stats=*/false, &@1)) { - struct perf_pmu *pmu = NULL; - int ok = 0; - - /* Failure to add, try wildcard expansion of $1 as a PMU name. */ - if (asprintf(&pattern, "%s*", $1) < 0) { - CLEANUP; - YYNOMEM; - } - - while ((pmu = perf_pmus__scan(pmu)) != NULL) { - const char *name = pmu->name; - - if (parse_events__filter_pmu(parse_state, pmu)) - continue; - - if (!strncmp(name, "uncore_", 7) && - strncmp($1, "uncore_", 7)) - name += 7; - if (!perf_pmu__match(pattern, name, $1) || - !perf_pmu__match(pattern, pmu->alias_name, $1)) { - bool auto_merge_stats = perf_pmu__auto_merge_stats(pmu); - - if (!parse_events_add_pmu(parse_state, list, pmu->name, $2, - auto_merge_stats, &@1)) { - ok++; - parse_state->wild_card_pmus = true; - } - } - } - - if (!ok) { - /* Failure to add, assume $1 is an event name. */ - zfree(&list); - ok = !parse_events_multi_pmu_add(parse_state, $1, $2, &list, &@1); - } - if (!ok) { - struct parse_events_error *error = parse_state->error; - char *help; - - if (asprintf(&help, "Unable to find PMU or event on a PMU of '%s'", $1) < 0) - help = NULL; - parse_events_error__handle(error, @1.first_column, - strdup("Bad event or PMU"), - help); - CLEANUP; - YYABORT; - } - } + parse_events_terms__delete($2); + free($1); + if (err) + PE_ABORT(err); $$ = list; - list = NULL; - CLEANUP; -#undef CLEANUP } | PE_NAME sep_dc -- cgit v1.2.3-59-g8ed1b From 63dfcde9779bcab5cff909819e8c82d472ea117a Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 15 Apr 2024 23:15:18 -0700 Subject: perf parse-events: Directly pass PMU to parse_events_add_pmu() Avoid passing the name of a PMU then finding it again, just directly pass the PMU. parse_events_multi_pmu_add_or_add_pmu() is the only version that needs to find a PMU, so move the find there. Remove the error message as parse_events_multi_pmu_add_or_add_pmu will given an error at the end when a name isn't either a PMU name or event name. Without the error message being created the location in the input parameter (loc) can be removed. Signed-off-by: Ian Rogers Reviewed-by: Kan Liang Tested-by: Atish Patra Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Beeman Strong Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20240416061533.921723-3-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-events.c | 46 ++++++++++++++++-------------------------- 1 file changed, 17 insertions(+), 29 deletions(-) diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index a6f71165ee1a..2d5a275dd257 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -1386,32 +1386,18 @@ static bool config_term_percore(struct list_head *config_terms) } static int parse_events_add_pmu(struct parse_events_state *parse_state, - struct list_head *list, const char *name, - const struct parse_events_terms *const_parsed_terms, - bool auto_merge_stats, void *loc_) + struct list_head *list, struct perf_pmu *pmu, + const struct parse_events_terms *const_parsed_terms, + bool auto_merge_stats) { struct perf_event_attr attr; struct perf_pmu_info info; - struct perf_pmu *pmu; struct evsel *evsel; struct parse_events_error *err = parse_state->error; - YYLTYPE *loc = loc_; LIST_HEAD(config_terms); struct parse_events_terms parsed_terms; bool alias_rewrote_terms = false; - pmu = parse_state->fake_pmu ?: perf_pmus__find(name); - - if (!pmu) { - char *err_str; - - if (asprintf(&err_str, - "Cannot find PMU `%s'. Missing kernel support?", - name) >= 0) - parse_events_error__handle(err, loc->first_column, err_str, NULL); - return -EINVAL; - } - parse_events_terms__init(&parsed_terms); if (const_parsed_terms) { int ret = parse_events_terms__copy(const_parsed_terms, &parsed_terms); @@ -1425,9 +1411,9 @@ static int parse_events_add_pmu(struct parse_events_state *parse_state, strbuf_init(&sb, /*hint=*/ 0); if (pmu->selectable && list_empty(&parsed_terms.terms)) { - strbuf_addf(&sb, "%s//", name); + strbuf_addf(&sb, "%s//", pmu->name); } else { - strbuf_addf(&sb, "%s/", name); + strbuf_addf(&sb, "%s/", pmu->name); parse_events_terms__to_strbuf(&parsed_terms, &sb); strbuf_addch(&sb, '/'); } @@ -1469,7 +1455,7 @@ static int parse_events_add_pmu(struct parse_events_state *parse_state, strbuf_init(&sb, /*hint=*/ 0); parse_events_terms__to_strbuf(&parsed_terms, &sb); - fprintf(stderr, "..after resolving event: %s/%s/\n", name, sb.buf); + fprintf(stderr, "..after resolving event: %s/%s/\n", pmu->name, sb.buf); strbuf_release(&sb); } @@ -1583,8 +1569,8 @@ int parse_events_multi_pmu_add(struct parse_events_state *parse_state, continue; auto_merge_stats = perf_pmu__auto_merge_stats(pmu); - if (!parse_events_add_pmu(parse_state, list, pmu->name, - &parsed_terms, auto_merge_stats, loc)) { + if (!parse_events_add_pmu(parse_state, list, pmu, + &parsed_terms, auto_merge_stats)) { struct strbuf sb; strbuf_init(&sb, /*hint=*/ 0); @@ -1596,8 +1582,8 @@ int parse_events_multi_pmu_add(struct parse_events_state *parse_state, } if (parse_state->fake_pmu) { - if (!parse_events_add_pmu(parse_state, list, event_name, &parsed_terms, - /*auto_merge_stats=*/true, loc)) { + if (!parse_events_add_pmu(parse_state, list, parse_state->fake_pmu, &parsed_terms, + /*auto_merge_stats=*/true)) { struct strbuf sb; strbuf_init(&sb, /*hint=*/ 0); @@ -1626,7 +1612,7 @@ int parse_events_multi_pmu_add_or_add_pmu(struct parse_events_state *parse_state { char *pattern = NULL; YYLTYPE *loc = loc_; - struct perf_pmu *pmu = NULL; + struct perf_pmu *pmu; int ok = 0; char *help; @@ -1637,10 +1623,12 @@ int parse_events_multi_pmu_add_or_add_pmu(struct parse_events_state *parse_state INIT_LIST_HEAD(*listp); /* Attempt to add to list assuming event_or_pmu is a PMU name. */ - if (!parse_events_add_pmu(parse_state, *listp, event_or_pmu, const_parsed_terms, - /*auto_merge_stats=*/false, loc)) + pmu = parse_state->fake_pmu ?: perf_pmus__find(event_or_pmu); + if (pmu && !parse_events_add_pmu(parse_state, *listp, pmu, const_parsed_terms, + /*auto_merge_stats=*/false)) return 0; + pmu = NULL; /* Failed to add, try wildcard expansion of event_or_pmu as a PMU name. */ if (asprintf(&pattern, "%s*", event_or_pmu) < 0) { zfree(listp); @@ -1660,9 +1648,9 @@ int parse_events_multi_pmu_add_or_add_pmu(struct parse_events_state *parse_state !perf_pmu__match(pattern, pmu->alias_name, event_or_pmu)) { bool auto_merge_stats = perf_pmu__auto_merge_stats(pmu); - if (!parse_events_add_pmu(parse_state, *listp, pmu->name, + if (!parse_events_add_pmu(parse_state, *listp, pmu, const_parsed_terms, - auto_merge_stats, loc)) { + auto_merge_stats)) { ok++; parse_state->wild_card_pmus = true; } -- cgit v1.2.3-59-g8ed1b From 90b2c210a54e657ea8fcba3d724dba180c716edc Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 15 Apr 2024 23:15:19 -0700 Subject: perf parse-events: Avoid copying an empty list In parse_events_add_pmu, delay copying the list of terms until it is known the list contains terms. Signed-off-by: Ian Rogers Reviewed-by: Kan Liang Tested-by: Atish Patra Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Beeman Strong Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20240416061533.921723-4-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-events.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 2d5a275dd257..3b1f767039fa 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -1398,29 +1398,21 @@ static int parse_events_add_pmu(struct parse_events_state *parse_state, struct parse_events_terms parsed_terms; bool alias_rewrote_terms = false; - parse_events_terms__init(&parsed_terms); - if (const_parsed_terms) { - int ret = parse_events_terms__copy(const_parsed_terms, &parsed_terms); - - if (ret) - return ret; - } - if (verbose > 1) { struct strbuf sb; strbuf_init(&sb, /*hint=*/ 0); - if (pmu->selectable && list_empty(&parsed_terms.terms)) { + if (pmu->selectable && const_parsed_terms && + list_empty(&const_parsed_terms->terms)) { strbuf_addf(&sb, "%s//", pmu->name); } else { strbuf_addf(&sb, "%s/", pmu->name); - parse_events_terms__to_strbuf(&parsed_terms, &sb); + parse_events_terms__to_strbuf(const_parsed_terms, &sb); strbuf_addch(&sb, '/'); } fprintf(stderr, "Attempt to add: %s\n", sb.buf); strbuf_release(&sb); } - fix_raw(&parsed_terms, pmu); memset(&attr, 0, sizeof(attr)); if (pmu->perf_event_attr_init_default) @@ -1428,7 +1420,7 @@ static int parse_events_add_pmu(struct parse_events_state *parse_state, attr.type = pmu->type; - if (list_empty(&parsed_terms.terms)) { + if (!const_parsed_terms || list_empty(&const_parsed_terms->terms)) { evsel = __add_event(list, &parse_state->idx, &attr, /*init_attr=*/true, /*name=*/NULL, /*metric_id=*/NULL, pmu, @@ -1437,6 +1429,15 @@ static int parse_events_add_pmu(struct parse_events_state *parse_state, return evsel ? 0 : -ENOMEM; } + parse_events_terms__init(&parsed_terms); + if (const_parsed_terms) { + int ret = parse_events_terms__copy(const_parsed_terms, &parsed_terms); + + if (ret) + return ret; + } + fix_raw(&parsed_terms, pmu); + /* Configure attr/terms with a known PMU, this will set hardcoded terms. */ if (config_attr(&attr, &parsed_terms, parse_state->error, config_term_pmu)) { parse_events_terms__exit(&parsed_terms); -- cgit v1.2.3-59-g8ed1b From f91fa2ae63604e6fe9eed9ac05eb9ed3b23701cc Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 15 Apr 2024 23:15:20 -0700 Subject: perf pmu: Refactor perf_pmu__match() Move all implementation to pmu code. Don't allocate a fnmatch wildcard pattern, matching ignoring the suffix already handles this, and only use fnmatch if the given PMU name has a '*' in it. Signed-off-by: Ian Rogers Reviewed-by: Kan Liang Tested-by: Atish Patra Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Beeman Strong Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20240416061533.921723-5-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-events.c | 19 ++----------------- tools/perf/util/pmu.c | 27 +++++++++++++++++++-------- tools/perf/util/pmu.h | 2 +- 3 files changed, 22 insertions(+), 26 deletions(-) diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 3b1f767039fa..39548ec645ec 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -1611,7 +1611,6 @@ int parse_events_multi_pmu_add_or_add_pmu(struct parse_events_state *parse_state struct list_head **listp, void *loc_) { - char *pattern = NULL; YYLTYPE *loc = loc_; struct perf_pmu *pmu; int ok = 0; @@ -1631,22 +1630,9 @@ int parse_events_multi_pmu_add_or_add_pmu(struct parse_events_state *parse_state pmu = NULL; /* Failed to add, try wildcard expansion of event_or_pmu as a PMU name. */ - if (asprintf(&pattern, "%s*", event_or_pmu) < 0) { - zfree(listp); - return -ENOMEM; - } - while ((pmu = perf_pmus__scan(pmu)) != NULL) { - const char *name = pmu->name; - - if (parse_events__filter_pmu(parse_state, pmu)) - continue; - - if (!strncmp(name, "uncore_", 7) && - strncmp(event_or_pmu, "uncore_", 7)) - name += 7; - if (!perf_pmu__match(pattern, name, event_or_pmu) || - !perf_pmu__match(pattern, pmu->alias_name, event_or_pmu)) { + if (!parse_events__filter_pmu(parse_state, pmu) && + perf_pmu__match(pmu, event_or_pmu)) { bool auto_merge_stats = perf_pmu__auto_merge_stats(pmu); if (!parse_events_add_pmu(parse_state, *listp, pmu, @@ -1657,7 +1643,6 @@ int parse_events_multi_pmu_add_or_add_pmu(struct parse_events_state *parse_state } } } - zfree(&pattern); if (ok) return 0; diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index ab30f22eaf10..74dd5bd49d9a 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c @@ -2064,18 +2064,29 @@ void perf_pmu__warn_invalid_config(struct perf_pmu *pmu, __u64 config, name ?: "N/A", buf, config_name, config); } -int perf_pmu__match(const char *pattern, const char *name, const char *tok) +bool perf_pmu__match(const struct perf_pmu *pmu, const char *tok) { - if (!name) - return -1; + const char *name = pmu->name; + bool need_fnmatch = strchr(tok, '*') != NULL; - if (fnmatch(pattern, name, 0)) - return -1; + if (!strncmp(tok, "uncore_", 7)) + tok += 7; + if (!strncmp(name, "uncore_", 7)) + name += 7; - if (tok && !perf_pmu__match_ignoring_suffix(name, tok)) - return -1; + if (perf_pmu__match_ignoring_suffix(name, tok) || + (need_fnmatch && !fnmatch(tok, name, 0))) + return true; - return 0; + name = pmu->alias_name; + if (!name) + return false; + + if (!strncmp(name, "uncore_", 7)) + name += 7; + + return perf_pmu__match_ignoring_suffix(name, tok) || + (need_fnmatch && !fnmatch(tok, name, 0)); } double __weak perf_pmu__cpu_slots_per_cycle(void) diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h index 152700f78455..93d03bd3ecbe 100644 --- a/tools/perf/util/pmu.h +++ b/tools/perf/util/pmu.h @@ -263,7 +263,7 @@ void perf_pmu__warn_invalid_config(struct perf_pmu *pmu, __u64 config, const char *config_name); void perf_pmu__warn_invalid_formats(struct perf_pmu *pmu); -int perf_pmu__match(const char *pattern, const char *name, const char *tok); +bool perf_pmu__match(const struct perf_pmu *pmu, const char *tok); double perf_pmu__cpu_slots_per_cycle(void); int perf_pmu__event_source_devices_scnprintf(char *pathname, size_t size); -- cgit v1.2.3-59-g8ed1b From 78fae2071ff790bcc701dcc03a4bc7ad36375856 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 15 Apr 2024 23:15:21 -0700 Subject: perf tests parse-events: Use "branches" rather than "cache-references" Switch from "cache-references" to "branches" in test as Intel has a sysfs event for "cache-references" and changing the priority for sysfs over legacy causes the test to fail. Signed-off-by: Ian Rogers Reviewed-by: Kan Liang Tested-by: Atish Patra Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Beeman Strong Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20240416061533.921723-6-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/parse-events.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c index 0b70451451b3..993e482f094c 100644 --- a/tools/perf/tests/parse-events.c +++ b/tools/perf/tests/parse-events.c @@ -942,8 +942,8 @@ static int test__group2(struct evlist *evlist) continue; } if (evsel->core.attr.type == PERF_TYPE_HARDWARE && - test_config(evsel, PERF_COUNT_HW_CACHE_REFERENCES)) { - /* cache-references + :u modifier */ + test_config(evsel, PERF_COUNT_HW_BRANCH_INSTRUCTIONS)) { + /* branches + :u modifier */ TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); @@ -2032,7 +2032,7 @@ static const struct evlist_test test__events[] = { /* 8 */ }, { - .name = "{faults:k,cache-references}:u,cycles:k", + .name = "{faults:k,branches}:u,cycles:k", .check = test__group2, /* 9 */ }, -- cgit v1.2.3-59-g8ed1b From 62593394f66aaebc8bfc0058bb029cae84bd8748 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 15 Apr 2024 23:15:22 -0700 Subject: perf parse-events: Legacy cache names on all PMUs and lower priority Prior behavior is to not look for legacy cache names in sysfs/JSON and to create events on all core PMUs. New behavior is to look for sysfs/JSON events first on all PMUs, for core PMUs add a legacy event if the sysfs/JSON event isn't present. This is done so that there is consistency with how event names in terms are handled and their prioritization of sysfs/JSON over legacy. It may make sense to use a legacy cache event name as an event name on a non-core PMU so we should allow it. Signed-off-by: Ian Rogers Reviewed-by: Kan Liang Tested-by: Atish Patra Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Beeman Strong Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20240416061533.921723-7-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-events.c | 39 +++++++++++++++++++++++++++++++-------- tools/perf/util/parse-events.h | 2 +- 2 files changed, 32 insertions(+), 9 deletions(-) diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 39548ec645ec..1440a3b4b674 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -442,17 +442,21 @@ bool parse_events__filter_pmu(const struct parse_events_state *parse_state, return strcmp(parse_state->pmu_filter, pmu->name) != 0; } +static int parse_events_add_pmu(struct parse_events_state *parse_state, + struct list_head *list, struct perf_pmu *pmu, + const struct parse_events_terms *const_parsed_terms, + bool auto_merge_stats); + int parse_events_add_cache(struct list_head *list, int *idx, const char *name, struct parse_events_state *parse_state, - struct parse_events_terms *head_config) + struct parse_events_terms *parsed_terms) { struct perf_pmu *pmu = NULL; bool found_supported = false; - const char *config_name = get_config_name(head_config); - const char *metric_id = get_config_metric_id(head_config); + const char *config_name = get_config_name(parsed_terms); + const char *metric_id = get_config_metric_id(parsed_terms); - /* Legacy cache events are only supported by core PMUs. */ - while ((pmu = perf_pmus__scan_core(pmu)) != NULL) { + while ((pmu = perf_pmus__scan(pmu)) != NULL) { LIST_HEAD(config_terms); struct perf_event_attr attr; int ret; @@ -460,6 +464,24 @@ int parse_events_add_cache(struct list_head *list, int *idx, const char *name, if (parse_events__filter_pmu(parse_state, pmu)) continue; + if (perf_pmu__have_event(pmu, name)) { + /* + * The PMU has the event so add as not a legacy cache + * event. + */ + ret = parse_events_add_pmu(parse_state, list, pmu, + parsed_terms, + perf_pmu__auto_merge_stats(pmu)); + if (ret) + return ret; + continue; + } + + if (!pmu->is_core) { + /* Legacy cache events are only supported by core PMUs. */ + continue; + } + memset(&attr, 0, sizeof(attr)); attr.type = PERF_TYPE_HW_CACHE; @@ -469,11 +491,12 @@ int parse_events_add_cache(struct list_head *list, int *idx, const char *name, found_supported = true; - if (head_config) { - if (config_attr(&attr, head_config, parse_state->error, config_term_common)) + if (parsed_terms) { + if (config_attr(&attr, parsed_terms, parse_state->error, + config_term_common)) return -EINVAL; - if (get_config_terms(head_config, &config_terms)) + if (get_config_terms(parsed_terms, &config_terms)) return -ENOMEM; } diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index a331b9f0da2b..db47913e54bc 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h @@ -203,7 +203,7 @@ int parse_events_add_tool(struct parse_events_state *parse_state, int tool_event); int parse_events_add_cache(struct list_head *list, int *idx, const char *name, struct parse_events_state *parse_state, - struct parse_events_terms *head_config); + struct parse_events_terms *parsed_terms); int parse_events__decode_legacy_cache(const char *name, int pmu_type, __u64 *config); int parse_events_add_breakpoint(struct parse_events_state *parse_state, struct list_head *list, -- cgit v1.2.3-59-g8ed1b From 9d0dba2398ff4bdb2eced7eaa7abd927aadf442b Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 15 Apr 2024 23:15:23 -0700 Subject: perf parse-events: Handle PE_TERM_HW in name_or_raw Avoid duplicate logic for name_or_raw and PE_TERM_HW by having a rule to turn PE_TERM_HW into a name_or_raw. Signed-off-by: Ian Rogers Reviewed-by: Kan Liang Tested-by: Atish Patra Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Beeman Strong Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20240416061533.921723-8-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-events.y | 31 +++++-------------------------- 1 file changed, 5 insertions(+), 26 deletions(-) diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y index 7764e5895210..254f8aeca461 100644 --- a/tools/perf/util/parse-events.y +++ b/tools/perf/util/parse-events.y @@ -603,6 +603,11 @@ event_term } name_or_raw: PE_RAW | PE_NAME | PE_LEGACY_CACHE +| +PE_TERM_HW +{ + $$ = $1.str; +} event_term: PE_RAW @@ -644,20 +649,6 @@ name_or_raw '=' PE_VALUE $$ = term; } | -name_or_raw '=' PE_TERM_HW -{ - struct parse_events_term *term; - int err = parse_events_term__str(&term, PARSE_EVENTS__TERM_TYPE_USER, - $1, $3.str, &@1, &@3); - - if (err) { - free($1); - free($3.str); - PE_ABORT(err); - } - $$ = term; -} -| PE_LEGACY_CACHE { struct parse_events_term *term; @@ -710,18 +701,6 @@ PE_TERM '=' name_or_raw $$ = term; } | -PE_TERM '=' PE_TERM_HW -{ - struct parse_events_term *term; - int err = parse_events_term__str(&term, $1, /*config=*/NULL, $3.str, &@1, &@3); - - if (err) { - free($3.str); - PE_ABORT(err); - } - $$ = term; -} -| PE_TERM '=' PE_TERM { struct parse_events_term *term; -- cgit v1.2.3-59-g8ed1b From 5ccc4edfc2a98840d8fb1669963df42d2d433181 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 15 Apr 2024 23:15:24 -0700 Subject: perf parse-events: Constify parse_events_add_numeric Allow the term list to be const so that other functions can pass const term lists. Add const as necessary to called functions. Signed-off-by: Ian Rogers Reviewed-by: Kan Liang Tested-by: Atish Patra Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Beeman Strong Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20240416061533.921723-9-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-events.c | 20 +++++++++++--------- tools/perf/util/parse-events.h | 2 +- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 1440a3b4b674..1b408e3dccc7 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -34,7 +34,8 @@ #ifdef PARSER_DEBUG extern int parse_events_debug; #endif -static int get_config_terms(struct parse_events_terms *head_config, struct list_head *head_terms); +static int get_config_terms(const struct parse_events_terms *head_config, + struct list_head *head_terms); static int parse_events_terms__copy(const struct parse_events_terms *src, struct parse_events_terms *dest); @@ -154,7 +155,7 @@ const char *event_type(int type) return "unknown"; } -static char *get_config_str(struct parse_events_terms *head_terms, +static char *get_config_str(const struct parse_events_terms *head_terms, enum parse_events__term_type type_term) { struct parse_events_term *term; @@ -169,12 +170,12 @@ static char *get_config_str(struct parse_events_terms *head_terms, return NULL; } -static char *get_config_metric_id(struct parse_events_terms *head_terms) +static char *get_config_metric_id(const struct parse_events_terms *head_terms) { return get_config_str(head_terms, PARSE_EVENTS__TERM_TYPE_METRIC_ID); } -static char *get_config_name(struct parse_events_terms *head_terms) +static char *get_config_name(const struct parse_events_terms *head_terms) { return get_config_str(head_terms, PARSE_EVENTS__TERM_TYPE_NAME); } @@ -358,7 +359,7 @@ static int config_term_common(struct perf_event_attr *attr, struct parse_events_term *term, struct parse_events_error *err); static int config_attr(struct perf_event_attr *attr, - struct parse_events_terms *head, + const struct parse_events_terms *head, struct parse_events_error *err, config_term_func_t config_term); @@ -1108,7 +1109,7 @@ static int config_term_tracepoint(struct perf_event_attr *attr, #endif static int config_attr(struct perf_event_attr *attr, - struct parse_events_terms *head, + const struct parse_events_terms *head, struct parse_events_error *err, config_term_func_t config_term) { @@ -1121,7 +1122,8 @@ static int config_attr(struct perf_event_attr *attr, return 0; } -static int get_config_terms(struct parse_events_terms *head_config, struct list_head *head_terms) +static int get_config_terms(const struct parse_events_terms *head_config, + struct list_head *head_terms) { #define ADD_CONFIG_TERM(__type, __weak) \ struct evsel_config_term *__t; \ @@ -1325,7 +1327,7 @@ int parse_events_add_tracepoint(struct list_head *list, int *idx, static int __parse_events_add_numeric(struct parse_events_state *parse_state, struct list_head *list, struct perf_pmu *pmu, u32 type, u32 extended_type, - u64 config, struct parse_events_terms *head_config) + u64 config, const struct parse_events_terms *head_config) { struct perf_event_attr attr; LIST_HEAD(config_terms); @@ -1361,7 +1363,7 @@ static int __parse_events_add_numeric(struct parse_events_state *parse_state, int parse_events_add_numeric(struct parse_events_state *parse_state, struct list_head *list, u32 type, u64 config, - struct parse_events_terms *head_config, + const struct parse_events_terms *head_config, bool wildcard) { struct perf_pmu *pmu = NULL; diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index db47913e54bc..5005782766e9 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h @@ -196,7 +196,7 @@ int parse_events_add_tracepoint(struct list_head *list, int *idx, int parse_events_add_numeric(struct parse_events_state *parse_state, struct list_head *list, u32 type, u64 config, - struct parse_events_terms *head_config, + const struct parse_events_terms *head_config, bool wildcard); int parse_events_add_tool(struct parse_events_state *parse_state, struct list_head *list, -- cgit v1.2.3-59-g8ed1b From 617824a7f0f73e4de325cf8add58e55b28c12493 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 15 Apr 2024 23:15:25 -0700 Subject: perf parse-events: Prefer sysfs/JSON hardware events over legacy It was requested that RISC-V be able to add events to the perf tool so the PMU driver didn't need to map legacy events to config encodings: https://lore.kernel.org/lkml/20240217005738.3744121-1-atishp@rivosinc.com/ This change makes the priority of events specified without a PMU the same as those specified with a PMU, namely sysfs and JSON events are checked first before using the legacy encoding. The hw_term is made more generic as a hardware_event that encodes a pair of string and int value, allowing parse_events_multi_pmu_add to fall back on a known encoding when the sysfs/JSON adding fails for core events. As this covers PE_VALUE_SYM_HW, that token is removed and related code simplified. Signed-off-by: Ian Rogers Reviewed-by: Kan Liang Tested-by: Atish Patra Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Beeman Strong Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20240416061533.921723-10-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-events.c | 31 ++++++++++++----- tools/perf/util/parse-events.h | 2 +- tools/perf/util/parse-events.l | 76 +++++++++++++++++++++--------------------- tools/perf/util/parse-events.y | 62 ++++++++++++++++++++++------------ 4 files changed, 103 insertions(+), 68 deletions(-) diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 1b408e3dccc7..805872c90a3e 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -1543,7 +1543,7 @@ static int parse_events_add_pmu(struct parse_events_state *parse_state, } int parse_events_multi_pmu_add(struct parse_events_state *parse_state, - const char *event_name, + const char *event_name, u64 hw_config, const struct parse_events_terms *const_parsed_terms, struct list_head **listp, void *loc_) { @@ -1551,8 +1551,8 @@ int parse_events_multi_pmu_add(struct parse_events_state *parse_state, struct list_head *list = NULL; struct perf_pmu *pmu = NULL; YYLTYPE *loc = loc_; - int ok = 0; - const char *config; + int ok = 0, core_ok = 0; + const char *tmp; struct parse_events_terms parsed_terms; *listp = NULL; @@ -1565,15 +1565,15 @@ int parse_events_multi_pmu_add(struct parse_events_state *parse_state, return ret; } - config = strdup(event_name); - if (!config) + tmp = strdup(event_name); + if (!tmp) goto out_err; if (parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_USER, - config, /*num=*/1, /*novalue=*/true, + tmp, /*num=*/1, /*novalue=*/true, loc, /*loc_val=*/NULL) < 0) { - zfree(&config); + zfree(&tmp); goto out_err; } list_add_tail(&term->list, &parsed_terms.terms); @@ -1604,6 +1604,8 @@ int parse_events_multi_pmu_add(struct parse_events_state *parse_state, pr_debug("%s -> %s/%s/\n", event_name, pmu->name, sb.buf); strbuf_release(&sb); ok++; + if (pmu->is_core) + core_ok++; } } @@ -1620,6 +1622,18 @@ int parse_events_multi_pmu_add(struct parse_events_state *parse_state, } } + if (hw_config != PERF_COUNT_HW_MAX && !core_ok) { + /* + * The event wasn't found on core PMUs but it has a hardware + * config version to try. + */ + if (!parse_events_add_numeric(parse_state, list, + PERF_TYPE_HARDWARE, hw_config, + const_parsed_terms, + /*wildcard=*/true)) + ok++; + } + out_err: parse_events_terms__exit(&parsed_terms); if (ok) @@ -1673,7 +1687,8 @@ int parse_events_multi_pmu_add_or_add_pmu(struct parse_events_state *parse_state /* Failure to add, assume event_or_pmu is an event name. */ zfree(listp); - if (!parse_events_multi_pmu_add(parse_state, event_or_pmu, const_parsed_terms, listp, loc)) + if (!parse_events_multi_pmu_add(parse_state, event_or_pmu, PERF_COUNT_HW_MAX, + const_parsed_terms, listp, loc)) return 0; if (asprintf(&help, "Unable to find PMU or event on a PMU of '%s'", event_or_pmu) < 0) diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index 5005782766e9..7e5afad3feb8 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h @@ -215,7 +215,7 @@ struct evsel *parse_events__add_event(int idx, struct perf_event_attr *attr, struct perf_pmu *pmu); int parse_events_multi_pmu_add(struct parse_events_state *parse_state, - const char *event_name, + const char *event_name, u64 hw_config, const struct parse_events_terms *const_parsed_terms, struct list_head **listp, void *loc); diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l index e86c45675e1d..6fe37003ab7b 100644 --- a/tools/perf/util/parse-events.l +++ b/tools/perf/util/parse-events.l @@ -100,12 +100,12 @@ do { \ yyless(0); \ } while (0) -static int sym(yyscan_t scanner, int type, int config) +static int sym(yyscan_t scanner, int config) { YYSTYPE *yylval = parse_events_get_lval(scanner); - yylval->num = (type << 16) + config; - return type == PERF_TYPE_HARDWARE ? PE_VALUE_SYM_HW : PE_VALUE_SYM_SW; + yylval->num = config; + return PE_VALUE_SYM_SW; } static int tool(yyscan_t scanner, enum perf_tool_event event) @@ -124,13 +124,13 @@ static int term(yyscan_t scanner, enum parse_events__term_type type) return PE_TERM; } -static int hw_term(yyscan_t scanner, int config) +static int hw(yyscan_t scanner, int config) { YYSTYPE *yylval = parse_events_get_lval(scanner); char *text = parse_events_get_text(scanner); - yylval->hardware_term.str = strdup(text); - yylval->hardware_term.num = PERF_TYPE_HARDWARE + config; + yylval->hardware_event.str = strdup(text); + yylval->hardware_event.num = config; return PE_TERM_HW; } @@ -246,16 +246,16 @@ percore { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_PERCORE); } aux-output { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_AUX_OUTPUT); } aux-sample-size { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_AUX_SAMPLE_SIZE); } metric-id { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_METRIC_ID); } -cpu-cycles|cycles { return hw_term(yyscanner, PERF_COUNT_HW_CPU_CYCLES); } -stalled-cycles-frontend|idle-cycles-frontend { return hw_term(yyscanner, PERF_COUNT_HW_STALLED_CYCLES_FRONTEND); } -stalled-cycles-backend|idle-cycles-backend { return hw_term(yyscanner, PERF_COUNT_HW_STALLED_CYCLES_BACKEND); } -instructions { return hw_term(yyscanner, PERF_COUNT_HW_INSTRUCTIONS); } -cache-references { return hw_term(yyscanner, PERF_COUNT_HW_CACHE_REFERENCES); } -cache-misses { return hw_term(yyscanner, PERF_COUNT_HW_CACHE_MISSES); } -branch-instructions|branches { return hw_term(yyscanner, PERF_COUNT_HW_BRANCH_INSTRUCTIONS); } -branch-misses { return hw_term(yyscanner, PERF_COUNT_HW_BRANCH_MISSES); } -bus-cycles { return hw_term(yyscanner, PERF_COUNT_HW_BUS_CYCLES); } -ref-cycles { return hw_term(yyscanner, PERF_COUNT_HW_REF_CPU_CYCLES); } +cpu-cycles|cycles { return hw(yyscanner, PERF_COUNT_HW_CPU_CYCLES); } +stalled-cycles-frontend|idle-cycles-frontend { return hw(yyscanner, PERF_COUNT_HW_STALLED_CYCLES_FRONTEND); } +stalled-cycles-backend|idle-cycles-backend { return hw(yyscanner, PERF_COUNT_HW_STALLED_CYCLES_BACKEND); } +instructions { return hw(yyscanner, PERF_COUNT_HW_INSTRUCTIONS); } +cache-references { return hw(yyscanner, PERF_COUNT_HW_CACHE_REFERENCES); } +cache-misses { return hw(yyscanner, PERF_COUNT_HW_CACHE_MISSES); } +branch-instructions|branches { return hw(yyscanner, PERF_COUNT_HW_BRANCH_INSTRUCTIONS); } +branch-misses { return hw(yyscanner, PERF_COUNT_HW_BRANCH_MISSES); } +bus-cycles { return hw(yyscanner, PERF_COUNT_HW_BUS_CYCLES); } +ref-cycles { return hw(yyscanner, PERF_COUNT_HW_REF_CPU_CYCLES); } r{num_raw_hex} { return str(yyscanner, PE_RAW); } r0x{num_raw_hex} { return str(yyscanner, PE_RAW); } , { return ','; } @@ -299,31 +299,31 @@ r0x{num_raw_hex} { return str(yyscanner, PE_RAW); } <> { BEGIN(INITIAL); } } -cpu-cycles|cycles { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_CPU_CYCLES); } -stalled-cycles-frontend|idle-cycles-frontend { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_FRONTEND); } -stalled-cycles-backend|idle-cycles-backend { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_BACKEND); } -instructions { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_INSTRUCTIONS); } -cache-references { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_REFERENCES); } -cache-misses { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_MISSES); } -branch-instructions|branches { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_INSTRUCTIONS); } -branch-misses { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_MISSES); } -bus-cycles { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_BUS_CYCLES); } -ref-cycles { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_REF_CPU_CYCLES); } -cpu-clock { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_CLOCK); } -task-clock { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_TASK_CLOCK); } -page-faults|faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS); } -minor-faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS_MIN); } -major-faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS_MAJ); } -context-switches|cs { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CONTEXT_SWITCHES); } -cpu-migrations|migrations { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_MIGRATIONS); } -alignment-faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_ALIGNMENT_FAULTS); } -emulation-faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_EMULATION_FAULTS); } -dummy { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_DUMMY); } +cpu-cycles|cycles { return hw(yyscanner, PERF_COUNT_HW_CPU_CYCLES); } +stalled-cycles-frontend|idle-cycles-frontend { return hw(yyscanner, PERF_COUNT_HW_STALLED_CYCLES_FRONTEND); } +stalled-cycles-backend|idle-cycles-backend { return hw(yyscanner, PERF_COUNT_HW_STALLED_CYCLES_BACKEND); } +instructions { return hw(yyscanner, PERF_COUNT_HW_INSTRUCTIONS); } +cache-references { return hw(yyscanner, PERF_COUNT_HW_CACHE_REFERENCES); } +cache-misses { return hw(yyscanner, PERF_COUNT_HW_CACHE_MISSES); } +branch-instructions|branches { return hw(yyscanner, PERF_COUNT_HW_BRANCH_INSTRUCTIONS); } +branch-misses { return hw(yyscanner, PERF_COUNT_HW_BRANCH_MISSES); } +bus-cycles { return hw(yyscanner, PERF_COUNT_HW_BUS_CYCLES); } +ref-cycles { return hw(yyscanner, PERF_COUNT_HW_REF_CPU_CYCLES); } +cpu-clock { return sym(yyscanner, PERF_COUNT_SW_CPU_CLOCK); } +task-clock { return sym(yyscanner, PERF_COUNT_SW_TASK_CLOCK); } +page-faults|faults { return sym(yyscanner, PERF_COUNT_SW_PAGE_FAULTS); } +minor-faults { return sym(yyscanner, PERF_COUNT_SW_PAGE_FAULTS_MIN); } +major-faults { return sym(yyscanner, PERF_COUNT_SW_PAGE_FAULTS_MAJ); } +context-switches|cs { return sym(yyscanner, PERF_COUNT_SW_CONTEXT_SWITCHES); } +cpu-migrations|migrations { return sym(yyscanner, PERF_COUNT_SW_CPU_MIGRATIONS); } +alignment-faults { return sym(yyscanner, PERF_COUNT_SW_ALIGNMENT_FAULTS); } +emulation-faults { return sym(yyscanner, PERF_COUNT_SW_EMULATION_FAULTS); } +dummy { return sym(yyscanner, PERF_COUNT_SW_DUMMY); } duration_time { return tool(yyscanner, PERF_TOOL_DURATION_TIME); } user_time { return tool(yyscanner, PERF_TOOL_USER_TIME); } system_time { return tool(yyscanner, PERF_TOOL_SYSTEM_TIME); } -bpf-output { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_BPF_OUTPUT); } -cgroup-switches { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CGROUP_SWITCHES); } +bpf-output { return sym(yyscanner, PERF_COUNT_SW_BPF_OUTPUT); } +cgroup-switches { return sym(yyscanner, PERF_COUNT_SW_CGROUP_SWITCHES); } {lc_type} { return str(yyscanner, PE_LEGACY_CACHE); } {lc_type}-{lc_op_result} { return str(yyscanner, PE_LEGACY_CACHE); } diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y index 254f8aeca461..31fe8cf428ff 100644 --- a/tools/perf/util/parse-events.y +++ b/tools/perf/util/parse-events.y @@ -55,7 +55,7 @@ static void free_list_evsel(struct list_head* list_evsel) %} %token PE_START_EVENTS PE_START_TERMS -%token PE_VALUE PE_VALUE_SYM_HW PE_VALUE_SYM_SW PE_TERM +%token PE_VALUE PE_VALUE_SYM_SW PE_TERM %token PE_VALUE_SYM_TOOL %token PE_EVENT_NAME %token PE_RAW PE_NAME @@ -66,11 +66,9 @@ static void free_list_evsel(struct list_head* list_evsel) %token PE_DRV_CFG_TERM %token PE_TERM_HW %type PE_VALUE -%type PE_VALUE_SYM_HW %type PE_VALUE_SYM_SW %type PE_VALUE_SYM_TOOL %type PE_TERM -%type value_sym %type PE_RAW %type PE_NAME %type PE_LEGACY_CACHE @@ -87,6 +85,7 @@ static void free_list_evsel(struct list_head* list_evsel) %type opt_pmu_config %destructor { parse_events_terms__delete ($$); } %type event_pmu +%type event_legacy_hardware %type event_legacy_symbol %type event_legacy_cache %type event_legacy_mem @@ -104,8 +103,8 @@ static void free_list_evsel(struct list_head* list_evsel) %destructor { free_list_evsel ($$); } %type tracepoint_name %destructor { free ($$.sys); free ($$.event); } -%type PE_TERM_HW -%destructor { free ($$.str); } +%type PE_TERM_HW +%destructor { free ($$.str); } %union { @@ -119,10 +118,10 @@ static void free_list_evsel(struct list_head* list_evsel) char *sys; char *event; } tracepoint_name; - struct hardware_term { + struct hardware_event { char *str; u64 num; - } hardware_term; + } hardware_event; } %% @@ -263,6 +262,7 @@ PE_EVENT_NAME event_def event_def event_def: event_pmu | + event_legacy_hardware | event_legacy_symbol | event_legacy_cache sep_dc | event_legacy_mem sep_dc | @@ -289,7 +289,7 @@ PE_NAME sep_dc struct list_head *list; int err; - err = parse_events_multi_pmu_add(_parse_state, $1, NULL, &list, &@1); + err = parse_events_multi_pmu_add(_parse_state, $1, PERF_COUNT_HW_MAX, NULL, &list, &@1); if (err < 0) { struct parse_events_state *parse_state = _parse_state; struct parse_events_error *error = parse_state->error; @@ -305,24 +305,45 @@ PE_NAME sep_dc $$ = list; } -value_sym: -PE_VALUE_SYM_HW +event_legacy_hardware: +PE_TERM_HW opt_pmu_config +{ + /* List of created evsels. */ + struct list_head *list = NULL; + int err = parse_events_multi_pmu_add(_parse_state, $1.str, $1.num, $2, &list, &@1); + + free($1.str); + parse_events_terms__delete($2); + if (err) + PE_ABORT(err); + + $$ = list; +} | -PE_VALUE_SYM_SW +PE_TERM_HW sep_dc +{ + struct list_head *list; + int err; + + err = parse_events_multi_pmu_add(_parse_state, $1.str, $1.num, NULL, &list, &@1); + free($1.str); + if (err) + PE_ABORT(err); + $$ = list; +} event_legacy_symbol: -value_sym '/' event_config '/' +PE_VALUE_SYM_SW '/' event_config '/' { struct list_head *list; - int type = $1 >> 16; - int config = $1 & 255; int err; - bool wildcard = (type == PERF_TYPE_HARDWARE || type == PERF_TYPE_HW_CACHE); list = alloc_list(); if (!list) YYNOMEM; - err = parse_events_add_numeric(_parse_state, list, type, config, $3, wildcard); + err = parse_events_add_numeric(_parse_state, list, + /*type=*/PERF_TYPE_SOFTWARE, /*config=*/$1, + $3, /*wildcard=*/false); parse_events_terms__delete($3); if (err) { free_list_evsel(list); @@ -331,18 +352,17 @@ value_sym '/' event_config '/' $$ = list; } | -value_sym sep_slash_slash_dc +PE_VALUE_SYM_SW sep_slash_slash_dc { struct list_head *list; - int type = $1 >> 16; - int config = $1 & 255; - bool wildcard = (type == PERF_TYPE_HARDWARE || type == PERF_TYPE_HW_CACHE); int err; list = alloc_list(); if (!list) YYNOMEM; - err = parse_events_add_numeric(_parse_state, list, type, config, /*head_config=*/NULL, wildcard); + err = parse_events_add_numeric(_parse_state, list, + /*type=*/PERF_TYPE_SOFTWARE, /*config=*/$1, + /*head_config=*/NULL, /*wildcard=*/false); if (err) PE_ABORT(err); $$ = list; -- cgit v1.2.3-59-g8ed1b From 4e5484b4bfd53d4d12933ab9b19da66909f1598e Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 15 Apr 2024 23:15:26 -0700 Subject: perf parse-events: Inline parse_events_update_lists The helper function just wraps a splice and free. Making the free inline removes a comment, so then it just wraps a splice which we can make inline too. Signed-off-by: Ian Rogers Reviewed-by: Kan Liang Tested-by: Atish Patra Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Beeman Strong Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20240416061533.921723-11-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-events.c | 13 ------------- tools/perf/util/parse-events.h | 2 -- tools/perf/util/parse-events.y | 41 +++++++++++++++++++++++++---------------- 3 files changed, 25 insertions(+), 31 deletions(-) diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 805872c90a3e..7eba714f0d73 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -1720,19 +1720,6 @@ void parse_events__set_leader(char *name, struct list_head *list) leader->group_name = name; } -/* list_event is assumed to point to malloc'ed memory */ -void parse_events_update_lists(struct list_head *list_event, - struct list_head *list_all) -{ - /* - * Called for single event definition. Update the - * 'all event' list, and reinit the 'single event' - * list, for next event definition. - */ - list_splice_tail(list_event, list_all); - free(list_event); -} - struct event_modifier { int eu; int ek; diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index 7e5afad3feb8..e8f2aebea10f 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h @@ -226,8 +226,6 @@ int parse_events_multi_pmu_add_or_add_pmu(struct parse_events_state *parse_state void *loc_); void parse_events__set_leader(char *name, struct list_head *list); -void parse_events_update_lists(struct list_head *list_event, - struct list_head *list_all); void parse_events_evlist_error(struct parse_events_state *parse_state, int idx, const char *str); diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y index 31fe8cf428ff..51490f0f8c50 100644 --- a/tools/perf/util/parse-events.y +++ b/tools/perf/util/parse-events.y @@ -125,6 +125,10 @@ static void free_list_evsel(struct list_head* list_evsel) } %% + /* + * Entry points. We are either parsing events or terminals. Just terminal + * parsing is used for parsing events in sysfs. + */ start: PE_START_EVENTS start_events | @@ -132,31 +136,36 @@ PE_START_TERMS start_terms start_events: groups { + /* Take the parsed events, groups.. and place into parse_state. */ + struct list_head *groups = $1; struct parse_events_state *parse_state = _parse_state; - /* frees $1 */ - parse_events_update_lists($1, &parse_state->list); + list_splice_tail(groups, &parse_state->list); + free(groups); } -groups: +groups: /* A list of groups or events. */ groups ',' group { - struct list_head *list = $1; - struct list_head *group = $3; + /* Merge group into the list of events/groups. */ + struct list_head *groups = $1; + struct list_head *group = $3; - /* frees $3 */ - parse_events_update_lists(group, list); - $$ = list; + list_splice_tail(group, groups); + free(group); + $$ = groups; } | groups ',' event { - struct list_head *list = $1; + /* Merge event into the list of events/groups. */ + struct list_head *groups = $1; struct list_head *event = $3; - /* frees $3 */ - parse_events_update_lists(event, list); - $$ = list; + + list_splice_tail(event, groups); + free(event); + $$ = groups; } | group @@ -206,12 +215,12 @@ PE_NAME '{' events '}' events: events ',' event { + struct list_head *events = $1; struct list_head *event = $3; - struct list_head *list = $1; - /* frees $3 */ - parse_events_update_lists(event, list); - $$ = list; + list_splice_tail(event, events); + free(event); + $$ = events; } | event -- cgit v1.2.3-59-g8ed1b From ba5c371edfd05411522c1fefb00e92b54c08c9db Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 15 Apr 2024 23:15:27 -0700 Subject: perf parse-events: Improve error message for bad numbers Use the error handler from the parse_state to give a more informative error message. Before: $ perf stat -e 'cycles/period=99999999999999999999/' true event syntax error: 'cycles/period=99999999999999999999/' \___ parser error Run 'perf list' for a list of valid events Usage: perf stat [] [] -e, --event event selector. use 'perf list' to list available events After: $ perf stat -e 'cycles/period=99999999999999999999/' true event syntax error: 'cycles/period=99999999999999999999/' \___ parser error event syntax error: '..les/period=99999999999999999999/' \___ Bad base 10 number "99999999999999999999" Run 'perf list' for a list of valid events Usage: perf stat [] [] -e, --event event selector. use 'perf list' to list available events Signed-off-by: Ian Rogers Reviewed-by: Kan Liang Tested-by: Atish Patra Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Beeman Strong Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20240416061533.921723-12-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-events.l | 40 ++++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l index 6fe37003ab7b..0cd68c9f0d4f 100644 --- a/tools/perf/util/parse-events.l +++ b/tools/perf/util/parse-events.l @@ -18,26 +18,34 @@ char *parse_events_get_text(yyscan_t yyscanner); YYSTYPE *parse_events_get_lval(yyscan_t yyscanner); +int parse_events_get_column(yyscan_t yyscanner); +int parse_events_get_leng(yyscan_t yyscanner); -static int __value(YYSTYPE *yylval, char *str, int base, int token) +static int get_column(yyscan_t scanner) { - u64 num; - - errno = 0; - num = strtoull(str, NULL, base); - if (errno) - return PE_ERROR; - - yylval->num = num; - return token; + return parse_events_get_column(scanner) - parse_events_get_leng(scanner); } -static int value(yyscan_t scanner, int base) +static int value(struct parse_events_state *parse_state, yyscan_t scanner, int base) { YYSTYPE *yylval = parse_events_get_lval(scanner); char *text = parse_events_get_text(scanner); + u64 num; - return __value(yylval, text, base, PE_VALUE); + errno = 0; + num = strtoull(text, NULL, base); + if (errno) { + struct parse_events_error *error = parse_state->error; + char *help = NULL; + + if (asprintf(&help, "Bad base %d number \"%s\"", base, text) > 0) + parse_events_error__handle(error, get_column(scanner), help , NULL); + + return PE_ERROR; + } + + yylval->num = num; + return PE_VALUE; } static int str(yyscan_t scanner, int token) @@ -283,8 +291,8 @@ r0x{num_raw_hex} { return str(yyscanner, PE_RAW); } */ "/"/{digit} { return PE_BP_SLASH; } "/"/{non_digit} { BEGIN(config); return '/'; } -{num_dec} { return value(yyscanner, 10); } -{num_hex} { return value(yyscanner, 16); } +{num_dec} { return value(_parse_state, yyscanner, 10); } +{num_hex} { return value(_parse_state, yyscanner, 16); } /* * We need to separate 'mem:' scanner part, in order to get specific * modifier bits parsed out. Otherwise we would need to handle PE_NAME @@ -330,8 +338,8 @@ cgroup-switches { return sym(yyscanner, PERF_COUNT_SW_CGROUP_SWITCHES); } {lc_type}-{lc_op_result}-{lc_op_result} { return str(yyscanner, PE_LEGACY_CACHE); } mem: { BEGIN(mem); return PE_PREFIX_MEM; } r{num_raw_hex} { return str(yyscanner, PE_RAW); } -{num_dec} { return value(yyscanner, 10); } -{num_hex} { return value(yyscanner, 16); } +{num_dec} { return value(_parse_state, yyscanner, 10); } +{num_hex} { return value(_parse_state, yyscanner, 16); } {modifier_event} { return str(yyscanner, PE_MODIFIER_EVENT); } {name} { return str(yyscanner, PE_NAME); } -- cgit v1.2.3-59-g8ed1b From e18601d80ce1917f02396b8b0d85b7587a0d3af5 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 15 Apr 2024 23:15:28 -0700 Subject: perf parse-events: Inline parse_events_evlist_error Inline parse_events_evlist_error that is only used in parse_events_error. Modify parse_events_error to not report a parser error unless errors haven't already been reported. Make it clearer that the latter case only happens for unrecognized input. Before: $ perf stat -e 'cycles/period=99999999999999999999/' true event syntax error: 'cycles/period=99999999999999999999/' \___ parser error event syntax error: '..les/period=99999999999999999999/' \___ Bad base 10 number "99999999999999999999" Run 'perf list' for a list of valid events Usage: perf stat [] [] -e, --event event selector. use 'perf list' to list available events $ perf stat -e 'cycles:xyz' true event syntax error: 'cycles:xyz' \___ parser error Run 'perf list' for a list of valid events Usage: perf stat [] [] -e, --event event selector. use 'perf list' to list available events After: $ perf stat -e 'cycles/period=99999999999999999999/xyz' true event syntax error: '..les/period=99999999999999999999/xyz' \___ Bad base 10 number "99999999999999999999" Run 'perf list' for a list of valid events Usage: perf stat [] [] -e, --event event selector. use 'perf list' to list available events $ perf stat -e 'cycles:xyz' true event syntax error: 'cycles:xyz' \___ Unrecognized input Run 'perf list' for a list of valid events Usage: perf stat [] [] -e, --event event selector. use 'perf list' to list available events Signed-off-by: Ian Rogers Reviewed-by: Kan Liang Tested-by: Atish Patra Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Beeman Strong Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20240416061533.921723-13-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-events.c | 9 --------- tools/perf/util/parse-events.h | 2 -- tools/perf/util/parse-events.y | 10 ++++++++-- 3 files changed, 8 insertions(+), 13 deletions(-) diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 7eba714f0d73..ebada37ef98a 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -2760,15 +2760,6 @@ int parse_events_terms__to_strbuf(const struct parse_events_terms *terms, struct return 0; } -void parse_events_evlist_error(struct parse_events_state *parse_state, - int idx, const char *str) -{ - if (!parse_state->error) - return; - - parse_events_error__handle(parse_state->error, idx, strdup(str), NULL); -} - static void config_terms_list(char *buf, size_t buf_sz) { int i; diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index e8f2aebea10f..290ae6c72ec5 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h @@ -226,8 +226,6 @@ int parse_events_multi_pmu_add_or_add_pmu(struct parse_events_state *parse_state void *loc_); void parse_events__set_leader(char *name, struct list_head *list); -void parse_events_evlist_error(struct parse_events_state *parse_state, - int idx, const char *str); struct event_symbol { const char *symbol; diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y index 51490f0f8c50..2c4817e126c1 100644 --- a/tools/perf/util/parse-events.y +++ b/tools/perf/util/parse-events.y @@ -790,9 +790,15 @@ sep_slash_slash_dc: '/' '/' | ':' | %% -void parse_events_error(YYLTYPE *loc, void *parse_state, +void parse_events_error(YYLTYPE *loc, void *_parse_state, void *scanner __maybe_unused, char const *msg __maybe_unused) { - parse_events_evlist_error(parse_state, loc->last_column, "parser error"); + struct parse_events_state *parse_state = _parse_state; + + if (!parse_state->error || !list_empty(&parse_state->error->list)) + return; + + parse_events_error__handle(parse_state->error, loc->last_column, + strdup("Unrecognized input"), NULL); } -- cgit v1.2.3-59-g8ed1b From e30a7912f498c58062d0b75e59c181dd48f1cc56 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 15 Apr 2024 23:15:29 -0700 Subject: perf parse-events: Improvements to modifier parsing Use a struct/bitmap rather than a copied string from lexer. In lexer give improved error message when too many precise flags are given or repeated modifiers. Before: $ perf stat -e 'cycles:kuk' true event syntax error: 'cycles:kuk' \___ Bad modifier ... $ perf stat -e 'cycles:pppp' true event syntax error: 'cycles:pppp' \___ Bad modifier ... $ perf stat -e '{instructions:p,cycles:pp}:pp' -a true event syntax error: '..cycles:pp}:pp' \___ Bad modifier ... After: $ perf stat -e 'cycles:kuk' true event syntax error: 'cycles:kuk' \___ Duplicate modifier 'k' (kernel) ... $ perf stat -e 'cycles:pppp' true event syntax error: 'cycles:pppp' \___ Maximum precise value is 3 ... $ perf stat -e '{instructions:p,cycles:pp}:pp' true event syntax error: '..cycles:pp}:pp' \___ Maximum combined precise value is 3, adding precision to "cycles:pp" ... Signed-off-by: Ian Rogers Reviewed-by: Kan Liang Tested-by: Atish Patra Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Beeman Strong Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20240416061533.921723-14-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-events.c | 250 +++++++++++++++-------------------------- tools/perf/util/parse-events.h | 23 +++- tools/perf/util/parse-events.l | 75 ++++++++++++- tools/perf/util/parse-events.y | 28 ++--- 4 files changed, 194 insertions(+), 182 deletions(-) diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index ebada37ef98a..3ab533d0e653 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -1700,12 +1700,6 @@ int parse_events_multi_pmu_add_or_add_pmu(struct parse_events_state *parse_state return -EINVAL; } -int parse_events__modifier_group(struct list_head *list, - char *event_mod) -{ - return parse_events__modifier_event(list, event_mod, true); -} - void parse_events__set_leader(char *name, struct list_head *list) { struct evsel *leader; @@ -1720,183 +1714,125 @@ void parse_events__set_leader(char *name, struct list_head *list) leader->group_name = name; } -struct event_modifier { - int eu; - int ek; - int eh; - int eH; - int eG; - int eI; - int precise; - int precise_max; - int exclude_GH; - int sample_read; - int pinned; - int weak; - int exclusive; - int bpf_counter; -}; +static int parse_events__modifier_list(struct parse_events_state *parse_state, + YYLTYPE *loc, + struct list_head *list, + struct parse_events_modifier mod, + bool group) +{ + struct evsel *evsel; -static int get_event_modifier(struct event_modifier *mod, char *str, - struct evsel *evsel) -{ - int eu = evsel ? evsel->core.attr.exclude_user : 0; - int ek = evsel ? evsel->core.attr.exclude_kernel : 0; - int eh = evsel ? evsel->core.attr.exclude_hv : 0; - int eH = evsel ? evsel->core.attr.exclude_host : 0; - int eG = evsel ? evsel->core.attr.exclude_guest : 0; - int eI = evsel ? evsel->core.attr.exclude_idle : 0; - int precise = evsel ? evsel->core.attr.precise_ip : 0; - int precise_max = 0; - int sample_read = 0; - int pinned = evsel ? evsel->core.attr.pinned : 0; - int exclusive = evsel ? evsel->core.attr.exclusive : 0; - - int exclude = eu | ek | eh; - int exclude_GH = evsel ? evsel->exclude_GH : 0; - int weak = 0; - int bpf_counter = 0; - - memset(mod, 0, sizeof(*mod)); - - while (*str) { - if (*str == 'u') { + if (!group && mod.weak) { + parse_events_error__handle(parse_state->error, loc->first_column, + strdup("Weak modifier is for use with groups"), NULL); + return -EINVAL; + } + + __evlist__for_each_entry(list, evsel) { + /* Translate modifiers into the equivalent evsel excludes. */ + int eu = group ? evsel->core.attr.exclude_user : 0; + int ek = group ? evsel->core.attr.exclude_kernel : 0; + int eh = group ? evsel->core.attr.exclude_hv : 0; + int eH = group ? evsel->core.attr.exclude_host : 0; + int eG = group ? evsel->core.attr.exclude_guest : 0; + int exclude = eu | ek | eh; + int exclude_GH = group ? evsel->exclude_GH : 0; + + if (mod.precise) { + /* use of precise requires exclude_guest */ + eG = 1; + } + if (mod.user) { if (!exclude) exclude = eu = ek = eh = 1; if (!exclude_GH && !perf_guest) eG = 1; eu = 0; - } else if (*str == 'k') { + } + if (mod.kernel) { if (!exclude) exclude = eu = ek = eh = 1; ek = 0; - } else if (*str == 'h') { + } + if (mod.hypervisor) { if (!exclude) exclude = eu = ek = eh = 1; eh = 0; - } else if (*str == 'G') { + } + if (mod.guest) { if (!exclude_GH) exclude_GH = eG = eH = 1; eG = 0; - } else if (*str == 'H') { + } + if (mod.host) { if (!exclude_GH) exclude_GH = eG = eH = 1; eH = 0; - } else if (*str == 'I') { - eI = 1; - } else if (*str == 'p') { - precise++; - /* use of precise requires exclude_guest */ - if (!exclude_GH) - eG = 1; - } else if (*str == 'P') { - precise_max = 1; - } else if (*str == 'S') { - sample_read = 1; - } else if (*str == 'D') { - pinned = 1; - } else if (*str == 'e') { - exclusive = 1; - } else if (*str == 'W') { - weak = 1; - } else if (*str == 'b') { - bpf_counter = 1; - } else - break; - - ++str; + } + evsel->core.attr.exclude_user = eu; + evsel->core.attr.exclude_kernel = ek; + evsel->core.attr.exclude_hv = eh; + evsel->core.attr.exclude_host = eH; + evsel->core.attr.exclude_guest = eG; + evsel->exclude_GH = exclude_GH; + + /* Simple modifiers copied to the evsel. */ + if (mod.precise) { + u8 precise = evsel->core.attr.precise_ip + mod.precise; + /* + * precise ip: + * + * 0 - SAMPLE_IP can have arbitrary skid + * 1 - SAMPLE_IP must have constant skid + * 2 - SAMPLE_IP requested to have 0 skid + * 3 - SAMPLE_IP must have 0 skid + * + * See also PERF_RECORD_MISC_EXACT_IP + */ + if (precise > 3) { + char *help; + + if (asprintf(&help, + "Maximum combined precise value is 3, adding precision to \"%s\"", + evsel__name(evsel)) > 0) { + parse_events_error__handle(parse_state->error, + loc->first_column, + help, NULL); + } + return -EINVAL; + } + evsel->core.attr.precise_ip = precise; + } + if (mod.precise_max) + evsel->precise_max = 1; + if (mod.non_idle) + evsel->core.attr.exclude_idle = 1; + if (mod.sample_read) + evsel->sample_read = 1; + if (mod.pinned && evsel__is_group_leader(evsel)) + evsel->core.attr.pinned = 1; + if (mod.exclusive && evsel__is_group_leader(evsel)) + evsel->core.attr.exclusive = 1; + if (mod.weak) + evsel->weak_group = true; + if (mod.bpf) + evsel->bpf_counter = true; } - - /* - * precise ip: - * - * 0 - SAMPLE_IP can have arbitrary skid - * 1 - SAMPLE_IP must have constant skid - * 2 - SAMPLE_IP requested to have 0 skid - * 3 - SAMPLE_IP must have 0 skid - * - * See also PERF_RECORD_MISC_EXACT_IP - */ - if (precise > 3) - return -EINVAL; - - mod->eu = eu; - mod->ek = ek; - mod->eh = eh; - mod->eH = eH; - mod->eG = eG; - mod->eI = eI; - mod->precise = precise; - mod->precise_max = precise_max; - mod->exclude_GH = exclude_GH; - mod->sample_read = sample_read; - mod->pinned = pinned; - mod->weak = weak; - mod->bpf_counter = bpf_counter; - mod->exclusive = exclusive; - return 0; } -/* - * Basic modifier sanity check to validate it contains only one - * instance of any modifier (apart from 'p') present. - */ -static int check_modifier(char *str) +int parse_events__modifier_group(struct parse_events_state *parse_state, void *loc, + struct list_head *list, + struct parse_events_modifier mod) { - char *p = str; - - /* The sizeof includes 0 byte as well. */ - if (strlen(str) > (sizeof("ukhGHpppPSDIWeb") - 1)) - return -1; - - while (*p) { - if (*p != 'p' && strchr(p + 1, *p)) - return -1; - p++; - } - - return 0; + return parse_events__modifier_list(parse_state, loc, list, mod, /*group=*/true); } -int parse_events__modifier_event(struct list_head *list, char *str, bool add) +int parse_events__modifier_event(struct parse_events_state *parse_state, void *loc, + struct list_head *list, + struct parse_events_modifier mod) { - struct evsel *evsel; - struct event_modifier mod; - - if (str == NULL) - return 0; - - if (check_modifier(str)) - return -EINVAL; - - if (!add && get_event_modifier(&mod, str, NULL)) - return -EINVAL; - - __evlist__for_each_entry(list, evsel) { - if (add && get_event_modifier(&mod, str, evsel)) - return -EINVAL; - - evsel->core.attr.exclude_user = mod.eu; - evsel->core.attr.exclude_kernel = mod.ek; - evsel->core.attr.exclude_hv = mod.eh; - evsel->core.attr.precise_ip = mod.precise; - evsel->core.attr.exclude_host = mod.eH; - evsel->core.attr.exclude_guest = mod.eG; - evsel->core.attr.exclude_idle = mod.eI; - evsel->exclude_GH = mod.exclude_GH; - evsel->sample_read = mod.sample_read; - evsel->precise_max = mod.precise_max; - evsel->weak_group = mod.weak; - evsel->bpf_counter = mod.bpf_counter; - - if (evsel__is_group_leader(evsel)) { - evsel->core.attr.pinned = mod.pinned; - evsel->core.attr.exclusive = mod.exclusive; - } - } - - return 0; + return parse_events__modifier_list(parse_state, loc, list, mod, /*group=*/false); } int parse_events_name(struct list_head *list, const char *name) diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index 290ae6c72ec5..f104faef1a78 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h @@ -186,8 +186,27 @@ void parse_events_terms__init(struct parse_events_terms *terms); void parse_events_terms__exit(struct parse_events_terms *terms); int parse_events_terms(struct parse_events_terms *terms, const char *str, FILE *input); int parse_events_terms__to_strbuf(const struct parse_events_terms *terms, struct strbuf *sb); -int parse_events__modifier_event(struct list_head *list, char *str, bool add); -int parse_events__modifier_group(struct list_head *list, char *event_mod); + +struct parse_events_modifier { + u8 precise; /* Number of repeated 'p' for precision. */ + bool precise_max : 1; /* 'P' */ + bool non_idle : 1; /* 'I' */ + bool sample_read : 1; /* 'S' */ + bool pinned : 1; /* 'D' */ + bool exclusive : 1; /* 'e' */ + bool weak : 1; /* 'W' */ + bool bpf : 1; /* 'b' */ + bool user : 1; /* 'u' */ + bool kernel : 1; /* 'k' */ + bool hypervisor : 1; /* 'h' */ + bool guest : 1; /* 'G' */ + bool host : 1; /* 'H' */ +}; + +int parse_events__modifier_event(struct parse_events_state *parse_state, void *loc, + struct list_head *list, struct parse_events_modifier mod); +int parse_events__modifier_group(struct parse_events_state *parse_state, void *loc, + struct list_head *list, struct parse_events_modifier mod); int parse_events_name(struct list_head *list, const char *name); int parse_events_add_tracepoint(struct list_head *list, int *idx, const char *sys, const char *event, diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l index 0cd68c9f0d4f..4aaf0c53d9b6 100644 --- a/tools/perf/util/parse-events.l +++ b/tools/perf/util/parse-events.l @@ -142,6 +142,77 @@ static int hw(yyscan_t scanner, int config) return PE_TERM_HW; } +static void modifiers_error(struct parse_events_state *parse_state, yyscan_t scanner, + int pos, char mod_char, const char *mod_name) +{ + struct parse_events_error *error = parse_state->error; + char *help = NULL; + + if (asprintf(&help, "Duplicate modifier '%c' (%s)", mod_char, mod_name) > 0) + parse_events_error__handle(error, get_column(scanner) + pos, help , NULL); +} + +static int modifiers(struct parse_events_state *parse_state, yyscan_t scanner) +{ + YYSTYPE *yylval = parse_events_get_lval(scanner); + char *text = parse_events_get_text(scanner); + struct parse_events_modifier mod = { .precise = 0, }; + + for (size_t i = 0, n = strlen(text); i < n; i++) { +#define CASE(c, field) \ + case c: \ + if (mod.field) { \ + modifiers_error(parse_state, scanner, i, c, #field); \ + return PE_ERROR; \ + } \ + mod.field = true; \ + break + + switch (text[i]) { + CASE('u', user); + CASE('k', kernel); + CASE('h', hypervisor); + CASE('I', non_idle); + CASE('G', guest); + CASE('H', host); + case 'p': + mod.precise++; + /* + * precise ip: + * + * 0 - SAMPLE_IP can have arbitrary skid + * 1 - SAMPLE_IP must have constant skid + * 2 - SAMPLE_IP requested to have 0 skid + * 3 - SAMPLE_IP must have 0 skid + * + * See also PERF_RECORD_MISC_EXACT_IP + */ + if (mod.precise > 3) { + struct parse_events_error *error = parse_state->error; + char *help = strdup("Maximum precise value is 3"); + + if (help) { + parse_events_error__handle(error, get_column(scanner) + i, + help , NULL); + } + return PE_ERROR; + } + break; + CASE('P', precise_max); + CASE('S', sample_read); + CASE('D', pinned); + CASE('W', weak); + CASE('e', exclusive); + CASE('b', bpf); + default: + return PE_ERROR; + } +#undef CASE + } + yylval->mod = mod; + return PE_MODIFIER_EVENT; +} + #define YY_USER_ACTION \ do { \ yylloc->last_column = yylloc->first_column; \ @@ -174,7 +245,7 @@ drv_cfg_term [a-zA-Z0-9_\.]+(=[a-zA-Z0-9_*?\.:]+)? * If you add a modifier you need to update check_modifier(). * Also, the letters in modifier_event must not be in modifier_bp. */ -modifier_event [ukhpPGHSDIWeb]+ +modifier_event [ukhpPGHSDIWeb]{1,15} modifier_bp [rwx]{1,3} lc_type (L1-dcache|l1-d|l1d|L1-data|L1-icache|l1-i|l1i|L1-instruction|LLC|L2|dTLB|d-tlb|Data-TLB|iTLB|i-tlb|Instruction-TLB|branch|branches|bpu|btb|bpc|node) lc_op_result (load|loads|read|store|stores|write|prefetch|prefetches|speculative-read|speculative-load|refs|Reference|ops|access|misses|miss) @@ -341,7 +412,7 @@ r{num_raw_hex} { return str(yyscanner, PE_RAW); } {num_dec} { return value(_parse_state, yyscanner, 10); } {num_hex} { return value(_parse_state, yyscanner, 16); } -{modifier_event} { return str(yyscanner, PE_MODIFIER_EVENT); } +{modifier_event} { return modifiers(_parse_state, yyscanner); } {name} { return str(yyscanner, PE_NAME); } {name_tag} { return str(yyscanner, PE_NAME); } "/" { BEGIN(config); return '/'; } diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y index 2c4817e126c1..79f254189be6 100644 --- a/tools/perf/util/parse-events.y +++ b/tools/perf/util/parse-events.y @@ -68,11 +68,11 @@ static void free_list_evsel(struct list_head* list_evsel) %type PE_VALUE %type PE_VALUE_SYM_SW %type PE_VALUE_SYM_TOOL +%type PE_MODIFIER_EVENT %type PE_TERM %type PE_RAW %type PE_NAME %type PE_LEGACY_CACHE -%type PE_MODIFIER_EVENT %type PE_MODIFIER_BP %type PE_EVENT_NAME %type PE_DRV_CFG_TERM @@ -110,6 +110,7 @@ static void free_list_evsel(struct list_head* list_evsel) { char *str; u64 num; + struct parse_events_modifier mod; enum parse_events__term_type term_type; struct list_head *list_evsel; struct parse_events_terms *list_terms; @@ -175,20 +176,13 @@ event group: group_def ':' PE_MODIFIER_EVENT { + /* Apply the modifier to the events in the group_def. */ struct list_head *list = $1; int err; - err = parse_events__modifier_group(list, $3); - free($3); - if (err) { - struct parse_events_state *parse_state = _parse_state; - struct parse_events_error *error = parse_state->error; - - parse_events_error__handle(error, @3.first_column, - strdup("Bad modifier"), NULL); - free_list_evsel(list); + err = parse_events__modifier_group(_parse_state, &@3, list, $3); + if (err) YYABORT; - } $$ = list; } | @@ -238,17 +232,9 @@ event_name PE_MODIFIER_EVENT * (there could be more events added for multiple tracepoint * definitions via '*?'. */ - err = parse_events__modifier_event(list, $2, false); - free($2); - if (err) { - struct parse_events_state *parse_state = _parse_state; - struct parse_events_error *error = parse_state->error; - - parse_events_error__handle(error, @2.first_column, - strdup("Bad modifier"), NULL); - free_list_evsel(list); + err = parse_events__modifier_event(_parse_state, &@2, list, $2); + if (err) YYABORT; - } $$ = list; } | -- cgit v1.2.3-59-g8ed1b From 4a20e793652e7742d8c0608a32e6f8adcde9e272 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 15 Apr 2024 23:15:30 -0700 Subject: perf parse-event: Constify event_symbol arrays Moves 352 bytes from .data to .data.rel.ro. Signed-off-by: Ian Rogers Reviewed-by: Kan Liang Tested-by: Atish Patra Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Beeman Strong Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20240416061533.921723-15-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-events.c | 4 ++-- tools/perf/util/parse-events.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 3ab533d0e653..8d3d692d219d 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -39,7 +39,7 @@ static int get_config_terms(const struct parse_events_terms *head_config, static int parse_events_terms__copy(const struct parse_events_terms *src, struct parse_events_terms *dest); -struct event_symbol event_symbols_hw[PERF_COUNT_HW_MAX] = { +const struct event_symbol event_symbols_hw[PERF_COUNT_HW_MAX] = { [PERF_COUNT_HW_CPU_CYCLES] = { .symbol = "cpu-cycles", .alias = "cycles", @@ -82,7 +82,7 @@ struct event_symbol event_symbols_hw[PERF_COUNT_HW_MAX] = { }, }; -struct event_symbol event_symbols_sw[PERF_COUNT_SW_MAX] = { +const struct event_symbol event_symbols_sw[PERF_COUNT_SW_MAX] = { [PERF_COUNT_SW_CPU_CLOCK] = { .symbol = "cpu-clock", .alias = "", diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index f104faef1a78..0bb5f0c80a5e 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h @@ -250,8 +250,8 @@ struct event_symbol { const char *symbol; const char *alias; }; -extern struct event_symbol event_symbols_hw[]; -extern struct event_symbol event_symbols_sw[]; +extern const struct event_symbol event_symbols_hw[]; +extern const struct event_symbol event_symbols_sw[]; char *parse_events_formats_error_string(char *additional_terms); -- cgit v1.2.3-59-g8ed1b From afd876bbdc97664257523bb5f2dcedbb5cef40d0 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 15 Apr 2024 23:15:31 -0700 Subject: perf parse-events: Minor grouping tidy up Add comments. Ensure leader->group_name is freed before overwriting it. Signed-off-by: Ian Rogers Reviewed-by: Kan Liang Tested-by: Atish Patra Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Beeman Strong Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20240416061533.921723-16-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-events.c | 1 + tools/perf/util/parse-events.y | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 8d3d692d219d..1c1b1bcb78e8 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -1711,6 +1711,7 @@ void parse_events__set_leader(char *name, struct list_head *list) leader = list_first_entry(list, struct evsel, core.node); __perf_evlist__set_leader(list, &leader->core); + zfree(&leader->group_name); leader->group_name = name; } diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y index 79f254189be6..6f1042272dda 100644 --- a/tools/perf/util/parse-events.y +++ b/tools/perf/util/parse-events.y @@ -193,7 +193,10 @@ PE_NAME '{' events '}' { struct list_head *list = $3; - /* Takes ownership of $1. */ + /* + * Set the first entry of list to be the leader. Set the group name on + * the leader to $1 taking ownership. + */ parse_events__set_leader($1, list); $$ = list; } @@ -202,6 +205,7 @@ PE_NAME '{' events '}' { struct list_head *list = $2; + /* Set the first entry of list to be the leader clearing the group name. */ parse_events__set_leader(NULL, list); $$ = list; } -- cgit v1.2.3-59-g8ed1b From bb65ff7810b654beb498e7afb4a4688e6ddf0340 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 15 Apr 2024 23:15:32 -0700 Subject: perf parse-events: Tidy the setting of the default event name Add comments. Pass ownership of the event name to save on a strdup. Signed-off-by: Ian Rogers Reviewed-by: Kan Liang Tested-by: Atish Patra Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Beeman Strong Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20240416061533.921723-17-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-events.c | 9 ++++++--- tools/perf/util/parse-events.h | 2 +- tools/perf/util/parse-events.l | 5 +++++ tools/perf/util/parse-events.y | 10 +++++++--- 4 files changed, 19 insertions(+), 7 deletions(-) diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 1c1b1bcb78e8..0f308b4db2b9 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -1836,18 +1836,21 @@ int parse_events__modifier_event(struct parse_events_state *parse_state, void *l return parse_events__modifier_list(parse_state, loc, list, mod, /*group=*/false); } -int parse_events_name(struct list_head *list, const char *name) +int parse_events__set_default_name(struct list_head *list, char *name) { struct evsel *evsel; + bool used_name = false; __evlist__for_each_entry(list, evsel) { if (!evsel->name) { - evsel->name = strdup(name); + evsel->name = used_name ? strdup(name) : name; + used_name = true; if (!evsel->name) return -ENOMEM; } } - + if (!used_name) + free(name); return 0; } diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index 0bb5f0c80a5e..5695308efab9 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h @@ -207,7 +207,7 @@ int parse_events__modifier_event(struct parse_events_state *parse_state, void *l struct list_head *list, struct parse_events_modifier mod); int parse_events__modifier_group(struct parse_events_state *parse_state, void *loc, struct list_head *list, struct parse_events_modifier mod); -int parse_events_name(struct list_head *list, const char *name); +int parse_events__set_default_name(struct list_head *list, char *name); int parse_events_add_tracepoint(struct list_head *list, int *idx, const char *sys, const char *event, struct parse_events_error *error, diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l index 4aaf0c53d9b6..08ea2d845dc3 100644 --- a/tools/perf/util/parse-events.l +++ b/tools/perf/util/parse-events.l @@ -96,6 +96,11 @@ static int drv_str(yyscan_t scanner, int token) return token; } +/* + * Use yyless to return all the characaters to the input. Update the column for + * location debugging. If __alloc is non-zero set yylval to the text for the + * returned token's value. + */ #define REWIND(__alloc) \ do { \ YYSTYPE *__yylval = parse_events_get_lval(yyscanner); \ diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y index 6f1042272dda..68b3b06c7ff0 100644 --- a/tools/perf/util/parse-events.y +++ b/tools/perf/util/parse-events.y @@ -247,10 +247,14 @@ event_name event_name: PE_EVENT_NAME event_def { - int err; + /* + * When an event is parsed the text is rewound and the entire text of + * the event is set to the str of PE_EVENT_NAME token matched here. If + * no name was on an event via a term, set the name to the entire text + * taking ownership of the allocation. + */ + int err = parse_events__set_default_name($2, $1); - err = parse_events_name($2, $1); - free($1); if (err) { free_list_evsel($2); YYNOMEM; -- cgit v1.2.3-59-g8ed1b From 281bf8f63f20b73aafae16e0f1d02b141701b0ed Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 23 Apr 2024 17:12:31 -0700 Subject: perf test: Add a new test for 'perf annotate' Add a basic 'perf annotate' test: $ ./perf test annotate -vv 76: perf annotate basic tests: --- start --- test child forked, pid 846989 fbcd0-fbd55 l noploop perf does have symbol 'noploop' Basic perf annotate test : 0 0xfbcd0 : 0.00 : fbcd0: pushq %rbp 0.00 : fbcd1: movq %rsp, %rbp 0.00 : fbcd4: pushq %r12 0.00 : fbcd6: pushq %rbx 0.00 : fbcd7: movl $1, %ebx 0.00 : fbcdc: subq $0x10, %rsp 0.00 : fbce0: movq %fs:0x28, %rax 0.00 : fbce9: movq %rax, -0x18(%rbp) 0.00 : fbced: xorl %eax, %eax 0.00 : fbcef: testl %edi, %edi 0.00 : fbcf1: jle 0xfbd04 0.00 : fbcf3: movq (%rsi), %rdi 0.00 : fbcf6: movl $0xa, %edx 0.00 : fbcfb: xorl %esi, %esi 0.00 : fbcfd: callq 0x41920 0.00 : fbd02: movl %eax, %ebx 0.00 : fbd04: leaq -0x7b(%rip), %r12 # fbc90 0.00 : fbd0b: movl $2, %edi 0.00 : fbd10: movq %r12, %rsi 0.00 : fbd13: callq 0x40a00 0.00 : fbd18: movl $0xe, %edi 0.00 : fbd1d: movq %r12, %rsi 0.00 : fbd20: callq 0x40a00 0.00 : fbd25: movl %ebx, %edi 0.00 : fbd27: callq 0x407c0 0.10 : fbd2c: movl 0x89785e(%rip), %eax # 993590 0.00 : fbd32: testl %eax, %eax 99.90 : fbd34: je 0xfbd2c 0.00 : fbd36: movq -0x18(%rbp), %rax 0.00 : fbd3a: subq %fs:0x28, %rax 0.00 : fbd43: jne 0xfbd50 0.00 : fbd45: addq $0x10, %rsp 0.00 : fbd49: xorl %eax, %eax 0.00 : fbd4b: popq %rbx 0.00 : fbd4c: popq %r12 0.00 : fbd4e: popq %rbp 0.00 : fbd4f: retq 0.00 : fbd50: callq 0x407e0 0.00 : fbcd0: pushq %rbp 0.00 : fbcd1: movq %rsp, %rbp 0.00 : fbcd4: pushq %r12 0.00 : fbcd0: push %rbp 0.00 : fbcd1: mov %rsp,%rbp 0.00 : fbcd4: push %r12 Basic annotate test [Success] ---- end(0) ---- 76: perf annotate basic tests : Ok Reviewed-by: Ian Rogers Signed-off-by: Namhyung Kim Tested-by: Arnaldo Carvalho de Melo Cc: Adrian Hunter Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20240424001231.849972-1-namhyung@kernel.org [ Improved a bit the error messages ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/shell/annotate.sh | 83 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100755 tools/perf/tests/shell/annotate.sh diff --git a/tools/perf/tests/shell/annotate.sh b/tools/perf/tests/shell/annotate.sh new file mode 100755 index 000000000000..1db1e8113d99 --- /dev/null +++ b/tools/perf/tests/shell/annotate.sh @@ -0,0 +1,83 @@ +#!/bin/sh +# perf annotate basic tests +# SPDX-License-Identifier: GPL-2.0 + +set -e + +shelldir=$(dirname "$0") + +# shellcheck source=lib/perf_has_symbol.sh +. "${shelldir}"/lib/perf_has_symbol.sh + +testsym="noploop" + +skip_test_missing_symbol ${testsym} + +err=0 +perfdata=$(mktemp /tmp/__perf_test.perf.data.XXXXX) +testprog="perf test -w noploop" +# disassembly format: "percent : offset: instruction (operands ...)" +disasm_regex="[0-9]*\.[0-9]* *: *\w*: *\w*" + +cleanup() { + rm -rf "${perfdata}" + rm -rf "${perfdata}".old + + trap - EXIT TERM INT +} + +trap_cleanup() { + cleanup + exit 1 +} +trap trap_cleanup EXIT TERM INT + +test_basic() { + echo "Basic perf annotate test" + if ! perf record -o "${perfdata}" ${testprog} 2> /dev/null + then + echo "Basic annotate [Failed: perf record]" + err=1 + return + fi + + # check if it has the target symbol + if ! perf annotate -i "${perfdata}" 2> /dev/null | grep "${testsym}" + then + echo "Basic annotate [Failed: missing target symbol]" + err=1 + return + fi + + # check if it has the disassembly lines + if ! perf annotate -i "${perfdata}" 2> /dev/null | grep "${disasm_regex}" + then + echo "Basic annotate [Failed: missing disasm output from default disassembler]" + err=1 + return + fi + + # check again with a target symbol name + if ! perf annotate -i "${perfdata}" "${testsym}" 2> /dev/null | \ + grep -m 3 "${disasm_regex}" + then + echo "Basic annotate [Failed: missing disasm output when specifying the target symbol]" + err=1 + return + fi + + # check one more with external objdump tool (forced by --objdump option) + if ! perf annotate -i "${perfdata}" --objdump=objdump 2> /dev/null | \ + grep -m 3 "${disasm_regex}" + then + echo "Basic annotate [Failed: missing disasm output from non default disassembler (using --objdump)]" + err=1 + return + fi + echo "Basic annotate test [Success]" +} + +test_basic + +cleanup +exit $err -- cgit v1.2.3-59-g8ed1b From 47557db99a5decba2192303ed34ec1add5177b51 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 24 Apr 2024 16:00:15 -0700 Subject: perf annotate-data: Check if 'struct annotation_source' was allocated on 'perf report' TUI As it removed the sample accounting for code when no symbol sort key is given for 'perf report' TUI, it might not have allocated the 'struct annotated_source' yet. Let's check if it's NULL first. Fixes: 6cdd977ec24e1538 ("perf report: Do not collect sample histogram unnecessarily") Reviewed-by: Ian Rogers Signed-off-by: Namhyung Kim Cc: Adrian Hunter Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20240424230015.1054013-1-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index dca2c08ab8c5..f5b6b5e5e757 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -906,7 +906,7 @@ int symbol__annotate(struct map_symbol *ms, struct evsel *evsel, if (parch) *parch = arch; - if (!list_empty(¬es->src->source)) + if (notes->src && !list_empty(¬es->src->source)) return 0; args.arch = arch; -- cgit v1.2.3-59-g8ed1b From f35847de2a65137e011e559f38a3de5902a5463f Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 24 Apr 2024 17:51:56 -0700 Subject: perf annotate: Fallback disassemble to objdump when capstone fails I found some cases that capstone failed to disassemble. Probably my capstone is an old version but anyway there's a chance it can fail. And then it silently stopped in the middle. In my case, it didn't understand "RDPKRU" instruction. Let's check if the capstone disassemble reached the end of the function and fallback to objdump if not. Signed-off-by: Namhyung Kim Cc: Adrian Hunter Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20240425005157.1104789-1-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/disasm.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tools/perf/util/disasm.c b/tools/perf/util/disasm.c index 92937809be85..412101f2cf2a 100644 --- a/tools/perf/util/disasm.c +++ b/tools/perf/util/disasm.c @@ -1542,6 +1542,20 @@ static int symbol__disassemble_capstone(char *filename, struct symbol *sym, offset += insn[i].size; } + /* It failed in the middle: probably due to unknown instructions */ + if (offset != len) { + struct list_head *list = ¬es->src->source; + + /* Discard all lines and fallback to objdump */ + while (!list_empty(list)) { + dl = list_first_entry(list, struct disasm_line, al.node); + + list_del_init(&dl->al.node); + disasm_line__free(dl); + } + count = -1; + } + out: if (needs_cs_close) cs_close(&handle); -- cgit v1.2.3-59-g8ed1b From 8f3ec810bb668d421f9d260e3de3bccca954b56f Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 24 Apr 2024 17:51:57 -0700 Subject: perf annotate: Update DSO binary type when trying build-id dso__disassemble_filename() tries to get the filename for objdump (or capstone) using build-id. But I found sometimes it didn't disassemble some functions. It turned out that those functions belong to a DSO which has no binary type set. It seems it sets the binary type for some special files only - like kernel (kallsyms or kcore) or BPF images. And there's a logic to skip dso with DSO_BINARY_TYPE__NOT_FOUND. As it's checked the build-id cache link, it should set the binary type as DSO_BINARY_TYPE__BUILD_ID_CACHE. Fixes: 873a83731f1cc85c ("perf annotate: Skip DSOs not found") Signed-off-by: Namhyung Kim Cc: Adrian Hunter Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20240425005157.1104789-2-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/disasm.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/perf/util/disasm.c b/tools/perf/util/disasm.c index 412101f2cf2a..6d1125e687b7 100644 --- a/tools/perf/util/disasm.c +++ b/tools/perf/util/disasm.c @@ -1156,6 +1156,8 @@ fallback: } } mutex_unlock(&dso->lock); + } else if (dso->binary_type == DSO_BINARY_TYPE__NOT_FOUND) { + dso->binary_type = DSO_BINARY_TYPE__BUILD_ID_CACHE; } free(build_id_path); -- cgit v1.2.3-59-g8ed1b From 7cc72090fbbf87bdd075eeece7f72453cbc1103a Mon Sep 17 00:00:00 2001 From: Howard Chu Date: Thu, 25 Apr 2024 14:04:27 +0800 Subject: perf record: Fix comment misspellings Fix comment misspellings Signed-off-by: Howard Chu Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20240425060427.1800663-1-howardchu95@gmail.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/lib/perf/mmap.c | 2 +- tools/perf/builtin-record.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/lib/perf/mmap.c b/tools/lib/perf/mmap.c index 0c903c2372c9..c1a51d925e0e 100644 --- a/tools/lib/perf/mmap.c +++ b/tools/lib/perf/mmap.c @@ -279,7 +279,7 @@ union perf_event *perf_mmap__read_event(struct perf_mmap *map) if (!refcount_read(&map->refcnt)) return NULL; - /* non-overwirte doesn't pause the ringbuffer */ + /* non-overwrite doesn't pause the ringbuffer */ if (!map->overwrite) map->end = perf_mmap__read_head(map); diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 2ff718d3e202..66a3de8ac661 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -332,7 +332,7 @@ static int record__aio_complete(struct mmap *md, struct aiocb *cblock) } else { /* * aio write request may require restart with the - * reminder if the kernel didn't write whole + * remainder if the kernel didn't write whole * chunk at once. */ rem_off = cblock->aio_offset + written; @@ -400,7 +400,7 @@ static int record__aio_pushfn(struct mmap *map, void *to, void *buf, size_t size * * Coping can be done in two steps in case the chunk of profiling data * crosses the upper bound of the kernel buffer. In this case we first move - * part of data from map->start till the upper bound and then the reminder + * part of data from map->start till the upper bound and then the remainder * from the beginning of the kernel buffer till the end of the data chunk. */ -- cgit v1.2.3-59-g8ed1b From e101a05f79fd4ee3e89d2f3fb716493c33a33708 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Tue, 26 Mar 2024 10:32:23 +0200 Subject: perf intel-pt: Fix unassigned instruction op (discovered by MemorySanitizer) MemorySanitizer discovered instances where the instruction op value was not assigned.: WARNING: MemorySanitizer: use-of-uninitialized-value #0 0x5581c00a76b3 in intel_pt_sample_flags tools/perf/util/intel-pt.c:1527:17 Uninitialized value was stored to memory at #0 0x5581c005ddf8 in intel_pt_walk_insn tools/perf/util/intel-pt-decoder/intel-pt-decoder.c:1256:25 The op value is used to set branch flags for branch instructions encountered when walking the code, so fix by setting op to INTEL_PT_OP_OTHER in other cases. Fixes: 4c761d805bb2d2ea ("perf intel-pt: Fix intel_pt_fup_event() assumptions about setting state type") Reported-by: Ian Rogers Signed-off-by: Adrian Hunter Tested-by: Ian Rogers Cc: Jiri Olsa Cc: Namhyung Kim Closes: https://lore.kernel.org/linux-perf-users/20240320162619.1272015-1-irogers@google.com/ Link: https://lore.kernel.org/r/20240326083223.10883-1-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/intel-pt-decoder/intel-pt-decoder.c | 2 ++ tools/perf/util/intel-pt.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c index b450178e3420..e733f6b1f7ac 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c +++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c @@ -1319,6 +1319,8 @@ static bool intel_pt_fup_event(struct intel_pt_decoder *decoder, bool no_tip) bool ret = false; decoder->state.type &= ~INTEL_PT_BRANCH; + decoder->state.insn_op = INTEL_PT_OP_OTHER; + decoder->state.insn_len = 0; if (decoder->set_fup_cfe_ip || decoder->set_fup_cfe) { bool ip = decoder->set_fup_cfe_ip; diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c index f38893e0b036..4db9a098f592 100644 --- a/tools/perf/util/intel-pt.c +++ b/tools/perf/util/intel-pt.c @@ -764,6 +764,7 @@ static int intel_pt_walk_next_insn(struct intel_pt_insn *intel_pt_insn, addr_location__init(&al); intel_pt_insn->length = 0; + intel_pt_insn->op = INTEL_PT_OP_OTHER; if (to_ip && *ip == to_ip) goto out_no_cache; @@ -898,6 +899,7 @@ static int intel_pt_walk_next_insn(struct intel_pt_insn *intel_pt_insn, if (to_ip && *ip == to_ip) { intel_pt_insn->length = 0; + intel_pt_insn->op = INTEL_PT_OP_OTHER; goto out_no_cache; } -- cgit v1.2.3-59-g8ed1b From 8524d71cebfa6ddcfbb89f0fe0e174c8d0477c6d Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Wed, 20 Mar 2024 09:32:44 -0700 Subject: perf build: Pretend scandirat is missing with msan Memory sanitizer lacks an interceptor for scandirat, reporting all memory it allocates as uninitialized. Memory sanitizer has a scandir interceptor so use the fallback function in this case. This allows 'perf test' to run under memory sanitizer. Additional notes from Ian on running in this mode: Note, as msan needs to instrument memory allocations libraries need to be compiled with it. I lacked the msan built libraries and so built with: ``` $ make -C tools/perf O=/tmp/perf DEBUG=1 EXTRA_CFLAGS="-O0 -g -fno-omit-frame-pointer -fsanitize=memory -fsanitize-memory-track-origins" CC=clang CXX=clang++ HOSTCC=clang NO_LIBTRACEEVENT=1 NO_LIBELF=1 BUILD_BPF_SKEL=0 NO_LIBPFM=1 ``` oh, I disabled libbpf here as the bpf system call also lacks msan interceptors. Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ingo Molnar Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20240320163244.1287780-1-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Makefile.config | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config index 7783479de691..7f1e016a9253 100644 --- a/tools/perf/Makefile.config +++ b/tools/perf/Makefile.config @@ -496,7 +496,10 @@ ifdef NO_DWARF endif ifeq ($(feature-scandirat), 1) - CFLAGS += -DHAVE_SCANDIRAT_SUPPORT + # Ignore having scandirat with memory sanitizer that lacks an interceptor. + ifeq ($(filter s% -fsanitize=memory%,$(EXTRA_CFLAGS),),) + CFLAGS += -DHAVE_SCANDIRAT_SUPPORT + endif endif ifeq ($(feature-sched_getcpu), 1) -- cgit v1.2.3-59-g8ed1b From 2b87383c885c52f051a90574fb857ca3b76b3f5c Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Mon, 22 Apr 2024 19:06:43 -0700 Subject: perf annotate: Fix data type profiling on stdio The loop in hists__find_annotations() never set the 'nd' pointer to NULL and it makes stdio output repeating the last element forever. I think it doesn't set to NULL for TUI to prevent it from exiting unexpectedly. But it should just set on stdio mode. Fixes: d001c7a7f4736743 ("perf annotate-data: Add hist_entry__annotate_data_tui()") Signed-off-by: Namhyung Kim Acked-by: Ian Rogers Cc: Adrian Hunter Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Namhyung Kim Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20240423020643.740029-1-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-annotate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 6f7104f06c42..83812b9d5363 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -491,7 +491,7 @@ find_next: return; } - if (next != NULL) + if (use_browser == 0 || next != NULL) nd = next; continue; -- cgit v1.2.3-59-g8ed1b From 8f21164321eea844ed2ed28d9db9f90f43d2bf7c Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 25 Apr 2024 18:08:42 -0300 Subject: tools headers x86 cpufeatures: Sync with the kernel sources to pick BHI mitigation changes To pick the changes from: 95a6ccbdc7199a14 ("x86/bhi: Mitigate KVM by default") ec9404e40e8f3642 ("x86/bhi: Add BHI mitigation knob") be482ff9500999f5 ("x86/bhi: Enumerate Branch History Injection (BHI) bug") 0f4a837615ff925b ("x86/bhi: Define SPEC_CTRL_BHI_DIS_S") 7390db8aea0d64e9 ("x86/bhi: Add support for clearing branch history at syscall entry") This causes these perf files to be rebuilt and brings some X86_FEATURE that will be used when updating the copies of tools/arch/x86/lib/mem{cpy,set}_64.S with the kernel sources: CC /tmp/build/perf/bench/mem-memcpy-x86-64-asm.o CC /tmp/build/perf/bench/mem-memset-x86-64-asm.o And addresses this perf build warning: Warning: Kernel ABI header differences: diff -u tools/arch/x86/include/asm/cpufeatures.h arch/x86/include/asm/cpufeatures.h Cc: Adrian Hunter Cc: Daniel Sneddon Cc: Ian Rogers Cc: Jiri Olsa Cc: Namhyung Kim Cc: Pawan Gupta Cc: Thomas Gleixner Link: https://lore.kernel.org/lkml/ZirIx4kPtJwGFZS0@x1 Signed-off-by: Arnaldo Carvalho de Melo --- tools/arch/x86/include/asm/cpufeatures.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tools/arch/x86/include/asm/cpufeatures.h b/tools/arch/x86/include/asm/cpufeatures.h index a38f8f9ba657..3c7434329661 100644 --- a/tools/arch/x86/include/asm/cpufeatures.h +++ b/tools/arch/x86/include/asm/cpufeatures.h @@ -461,11 +461,15 @@ /* * Extended auxiliary flags: Linux defined - for features scattered in various - * CPUID levels like 0x80000022, etc. + * CPUID levels like 0x80000022, etc and Linux defined features. * * Reuse free bits when adding new feature flags! */ #define X86_FEATURE_AMD_LBR_PMC_FREEZE (21*32+ 0) /* AMD LBR and PMC Freeze */ +#define X86_FEATURE_CLEAR_BHB_LOOP (21*32+ 1) /* "" Clear branch history at syscall entry using SW loop */ +#define X86_FEATURE_BHI_CTRL (21*32+ 2) /* "" BHI_DIS_S HW control available */ +#define X86_FEATURE_CLEAR_BHB_HW (21*32+ 3) /* "" BHI_DIS_S HW control enabled */ +#define X86_FEATURE_CLEAR_BHB_LOOP_ON_VMEXIT (21*32+ 4) /* "" Clear branch history at vmexit using SW loop */ /* * BUG word(s) @@ -515,4 +519,5 @@ #define X86_BUG_SRSO X86_BUG(1*32 + 0) /* AMD SRSO bug */ #define X86_BUG_DIV0 X86_BUG(1*32 + 1) /* AMD DIV0 speculation bug */ #define X86_BUG_RFDS X86_BUG(1*32 + 2) /* CPU is vulnerable to Register File Data Sampling */ +#define X86_BUG_BHI X86_BUG(1*32 + 3) /* CPU is affected by Branch History Injection */ #endif /* _ASM_X86_CPUFEATURES_H */ -- cgit v1.2.3-59-g8ed1b From 450f941ea9dce7256a485baf36f2b8d85a64e1c0 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 26 Apr 2024 15:52:09 -0300 Subject: tools headers: Synchronize linux/bits.h with the kernel sources To pick up the changes in this cset: 3c7a8e190bc58081 ("uapi: introduce uapi-friendly macros for GENMASK") That just causes perf to rebuild. Its just some macros going to an uapi header that we now have to grab a copy into tools/ as well. This addresses this perf build warning: Warning: Kernel ABI header differences: diff -u tools/include/linux/bits.h include/linux/bits.h Cc: Adrian Hunter Cc: Ian Rogers Cc: Jiri Olsa Cc: Kan Liang Cc: Namhyung Kim Cc: Paolo Bonzini Link: https://lore.kernel.org/lkml/ZiwJsFOBez0MS4r9@x1 Signed-off-by: Arnaldo Carvalho de Melo --- tools/include/linux/bits.h | 8 +------- tools/include/uapi/asm-generic/bitsperlong.h | 4 ++++ tools/include/uapi/linux/bits.h | 15 +++++++++++++++ tools/perf/check-headers.sh | 1 + 4 files changed, 21 insertions(+), 7 deletions(-) create mode 100644 tools/include/uapi/linux/bits.h diff --git a/tools/include/linux/bits.h b/tools/include/linux/bits.h index 7c0cf5031abe..0eb24d21aac2 100644 --- a/tools/include/linux/bits.h +++ b/tools/include/linux/bits.h @@ -4,6 +4,7 @@ #include #include +#include #include #define BIT_MASK(nr) (UL(1) << ((nr) % BITS_PER_LONG)) @@ -30,15 +31,8 @@ #define GENMASK_INPUT_CHECK(h, l) 0 #endif -#define __GENMASK(h, l) \ - (((~UL(0)) - (UL(1) << (l)) + 1) & \ - (~UL(0) >> (BITS_PER_LONG - 1 - (h)))) #define GENMASK(h, l) \ (GENMASK_INPUT_CHECK(h, l) + __GENMASK(h, l)) - -#define __GENMASK_ULL(h, l) \ - (((~ULL(0)) - (ULL(1) << (l)) + 1) & \ - (~ULL(0) >> (BITS_PER_LONG_LONG - 1 - (h)))) #define GENMASK_ULL(h, l) \ (GENMASK_INPUT_CHECK(h, l) + __GENMASK_ULL(h, l)) diff --git a/tools/include/uapi/asm-generic/bitsperlong.h b/tools/include/uapi/asm-generic/bitsperlong.h index 352cb81947b8..fadb3f857f28 100644 --- a/tools/include/uapi/asm-generic/bitsperlong.h +++ b/tools/include/uapi/asm-generic/bitsperlong.h @@ -24,4 +24,8 @@ #endif #endif +#ifndef __BITS_PER_LONG_LONG +#define __BITS_PER_LONG_LONG 64 +#endif + #endif /* _UAPI__ASM_GENERIC_BITS_PER_LONG */ diff --git a/tools/include/uapi/linux/bits.h b/tools/include/uapi/linux/bits.h new file mode 100644 index 000000000000..3c2a101986a3 --- /dev/null +++ b/tools/include/uapi/linux/bits.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* bits.h: Macros for dealing with bitmasks. */ + +#ifndef _UAPI_LINUX_BITS_H +#define _UAPI_LINUX_BITS_H + +#define __GENMASK(h, l) \ + (((~_UL(0)) - (_UL(1) << (l)) + 1) & \ + (~_UL(0) >> (__BITS_PER_LONG - 1 - (h)))) + +#define __GENMASK_ULL(h, l) \ + (((~_ULL(0)) - (_ULL(1) << (l)) + 1) & \ + (~_ULL(0) >> (__BITS_PER_LONG_LONG - 1 - (h)))) + +#endif /* _UAPI_LINUX_BITS_H */ diff --git a/tools/perf/check-headers.sh b/tools/perf/check-headers.sh index 9c84fd049070..672421b858ac 100755 --- a/tools/perf/check-headers.sh +++ b/tools/perf/check-headers.sh @@ -9,6 +9,7 @@ FILES=( "include/uapi/linux/const.h" "include/uapi/drm/drm.h" "include/uapi/drm/i915_drm.h" + "include/uapi/linux/bits.h" "include/uapi/linux/fadvise.h" "include/uapi/linux/fscrypt.h" "include/uapi/linux/kcmp.h" -- cgit v1.2.3-59-g8ed1b From 8c618b58c89ce4c24c0030bd42340938bdf8e29c Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 26 Apr 2024 17:26:26 -0300 Subject: perf test: Reintroduce -p/--parallel and make -S/--sequential the default We can't default to doing parallel tests as there are tests that compete for the same resources and thus clash, for instance tests that put in place 'perf probe' probes, that clean the probes without regard to other tests needs, ARM64 coresight tests, Intel PT ones, etc. So reintroduce --p/--parallel and make -S/--sequential the default. We need to come up with infrastructure that state which tests can't run in parallel because they need exclusive access to some resource, something as simple as "probes" that would then avoid 'perf probe' tests from running while other such test is running, or make the tests more resilient, till then we can't use parallel mode as default. While at it, document all these options in the 'perf test' man page. Reported-by: Adrian Hunter Reported-by: Arnaldo Carvalho de Melo Reported-by: James Clark Reviewed-by: Ian Rogers Cc: Jiri Olsa Cc: Kan Liang Cc: Namhyung Kim Link: https://lore.kernel.org/lkml/Ziwm18BqIn_vc1vn@x1 Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-test.txt | 13 ++++++++++++- tools/perf/tests/builtin-test.c | 8 +++++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/tools/perf/Documentation/perf-test.txt b/tools/perf/Documentation/perf-test.txt index 951a2f262872..9acb8d1f6588 100644 --- a/tools/perf/Documentation/perf-test.txt +++ b/tools/perf/Documentation/perf-test.txt @@ -31,9 +31,20 @@ OPTIONS --verbose:: Be more verbose. +-S:: +--sequential:: + Run tests one after the other, this is the default mode. + +-p:: +--parallel:: + Run tests in parallel, speeds up the whole process but is not safe with + the current infrastructure, where some tests that compete for some resources, + for instance, 'perf probe' tests that add/remove probes or clean all probes, etc. + -F:: --dont-fork:: - Do not fork child for each test, run all tests within single process. + Do not fork child for each test, run all tests within single process, this + sets sequential mode. --dso:: Specify a DSO for the "Symbols" test. diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c index 73f53b02f733..c3d84b67ca8e 100644 --- a/tools/perf/tests/builtin-test.c +++ b/tools/perf/tests/builtin-test.c @@ -40,7 +40,10 @@ */ static bool dont_fork; /* Don't fork the tests in parallel and wait for their completion. */ -static bool sequential; +static bool sequential = true; +/* Do it in parallel, lacks infrastructure to avoid running tests that clash for resources, + * So leave it as the developers choice to enable while working on the needed infra */ +static bool parallel; const char *dso_to_test; const char *test_objdump_path = "objdump"; @@ -536,6 +539,7 @@ int cmd_test(int argc, const char **argv) "be more verbose (show symbol address, etc)"), OPT_BOOLEAN('F', "dont-fork", &dont_fork, "Do not fork for testcase"), + OPT_BOOLEAN('p', "parallel", ¶llel, "Run the tests in parallel"), OPT_BOOLEAN('S', "sequential", &sequential, "Run the tests one after another rather than in parallel"), OPT_STRING('w', "workload", &workload, "work", "workload to run for testing"), @@ -566,6 +570,8 @@ int cmd_test(int argc, const char **argv) if (dont_fork) sequential = true; + else if (parallel) + sequential = false; symbol_conf.priv_size = sizeof(int); symbol_conf.try_vmlinux_path = true; -- cgit v1.2.3-59-g8ed1b From 61684c0ff94ca356ef82220173860223908f1e04 Mon Sep 17 00:00:00 2001 From: Gil Fine Date: Fri, 26 Apr 2024 02:24:17 +0300 Subject: thunderbolt: Fix uninitialized variable in tb_tunnel_alloc_usb3() Currently in case of no bandwidth available for USB3 tunnel, we are left with uninitialized variable that can lead to huge negative allocated bandwidth. Fix this by initializing the variable to zero. While there, fix the kernel-doc to describe more accurately the purpose of the function tb_tunnel_alloc_usb3(). Reported-by: Dan Carpenter Closes: https://lore.kernel.org/linux-usb/6289898b-cd63-4fb8-906a-1b6977321af9@moroto.mountain/ Fixes: 25d905d2b819 ("thunderbolt: Allow USB3 bandwidth to be lower than maximum supported") Signed-off-by: Gil Fine Signed-off-by: Mika Westerberg --- drivers/thunderbolt/tunnel.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/thunderbolt/tunnel.c b/drivers/thunderbolt/tunnel.c index fdc5e8e12ca8..1a3b197001da 100644 --- a/drivers/thunderbolt/tunnel.c +++ b/drivers/thunderbolt/tunnel.c @@ -2048,10 +2048,10 @@ err_free: * @tb: Pointer to the domain structure * @up: USB3 upstream adapter port * @down: USB3 downstream adapter port - * @max_up: Maximum available upstream bandwidth for the USB3 tunnel (%0 - * if not limited). - * @max_down: Maximum available downstream bandwidth for the USB3 tunnel - * (%0 if not limited). + * @max_up: Maximum available upstream bandwidth for the USB3 tunnel. + * %0 if no available bandwidth. + * @max_down: Maximum available downstream bandwidth for the USB3 tunnel. + * %0 if no available bandwidth. * * Allocate an USB3 tunnel. The ports must be of type @TB_TYPE_USB3_UP and * @TB_TYPE_USB3_DOWN. @@ -2064,7 +2064,7 @@ struct tb_tunnel *tb_tunnel_alloc_usb3(struct tb *tb, struct tb_port *up, { struct tb_tunnel *tunnel; struct tb_path *path; - int max_rate; + int max_rate = 0; if (!tb_route(down->sw) && (max_up > 0 || max_down > 0)) { /* -- cgit v1.2.3-59-g8ed1b From 2a0ed2da17d70fb57456fd78bf0798492d44cc17 Mon Sep 17 00:00:00 2001 From: Gil Fine Date: Fri, 26 Apr 2024 02:37:54 +0300 Subject: thunderbolt: Fix kernel-doc for tb_tunnel_alloc_dp() In case of no bandwidth available for DP tunnel, the function get the arguments @max_up and @max_down set to zero. Fix the kernel-doc to describe more accurately the purpose of the function. No functional changes. Signed-off-by: Gil Fine Signed-off-by: Mika Westerberg --- drivers/thunderbolt/tunnel.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/thunderbolt/tunnel.c b/drivers/thunderbolt/tunnel.c index 1a3b197001da..41cf6378ad25 100644 --- a/drivers/thunderbolt/tunnel.c +++ b/drivers/thunderbolt/tunnel.c @@ -1435,10 +1435,10 @@ err_free: * @in: DP in adapter port * @out: DP out adapter port * @link_nr: Preferred lane adapter when the link is not bonded - * @max_up: Maximum available upstream bandwidth for the DP tunnel (%0 - * if not limited) - * @max_down: Maximum available downstream bandwidth for the DP tunnel - * (%0 if not limited) + * @max_up: Maximum available upstream bandwidth for the DP tunnel. + * %0 if no available bandwidth. + * @max_down: Maximum available downstream bandwidth for the DP tunnel. + * %0 if no available bandwidth. * * Allocates a tunnel between @in and @out that is capable of tunneling * Display Port traffic. -- cgit v1.2.3-59-g8ed1b From 0d8d62640763edfc11cc8568fe2115ad5af4e67e Mon Sep 17 00:00:00 2001 From: Subhajit Ghosh Date: Sat, 27 Apr 2024 18:39:14 +0930 Subject: iio: light: apds9306: Fix input arguments to in_range() Third input argument to in_range() function requires the number of values in range, not the last value in that range. Update macro for persistence and adaptive threshold to reflect number of values supported instead of the maximum values supported. Fixes: 620d1e6c7a3f ("iio: light: Add support for APDS9306 Light Sensor") Signed-off-by: Subhajit Ghosh Link: https://lore.kernel.org/r/20240427090914.37274-1-subhajit.ghosh@tweaklogic.com Signed-off-by: Jonathan Cameron --- drivers/iio/light/apds9306.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/iio/light/apds9306.c b/drivers/iio/light/apds9306.c index 46c647ccd44c..d6627b3e6000 100644 --- a/drivers/iio/light/apds9306.c +++ b/drivers/iio/light/apds9306.c @@ -55,8 +55,8 @@ #define APDS9306_ALS_DATA_STAT_MASK BIT(3) #define APDS9306_ALS_THRES_VAL_MAX (BIT(20) - 1) -#define APDS9306_ALS_THRES_VAR_VAL_MAX (BIT(3) - 1) -#define APDS9306_ALS_PERSIST_VAL_MAX (BIT(4) - 1) +#define APDS9306_ALS_THRES_VAR_NUM_VALS 8 +#define APDS9306_ALS_PERSIST_NUM_VALS 16 #define APDS9306_ALS_READ_DATA_DELAY_US (20 * USEC_PER_MSEC) #define APDS9306_NUM_REPEAT_RATES 7 #define APDS9306_INT_SRC_CLEAR 0 @@ -726,7 +726,7 @@ static int apds9306_event_period_get(struct apds9306_data *data, int *val) if (ret) return ret; - if (!in_range(period, 0, APDS9306_ALS_PERSIST_VAL_MAX)) + if (!in_range(period, 0, APDS9306_ALS_PERSIST_NUM_VALS)) return -EINVAL; *val = period; @@ -738,7 +738,7 @@ static int apds9306_event_period_set(struct apds9306_data *data, int val) { struct apds9306_regfields *rf = &data->rf; - if (!in_range(val, 0, APDS9306_ALS_PERSIST_VAL_MAX)) + if (!in_range(val, 0, APDS9306_ALS_PERSIST_NUM_VALS)) return -EINVAL; return regmap_field_write(rf->int_persist_val, val); @@ -796,7 +796,7 @@ static int apds9306_event_thresh_adaptive_get(struct apds9306_data *data, int *v if (ret) return ret; - if (!in_range(thr_adpt, 0, APDS9306_ALS_THRES_VAR_VAL_MAX)) + if (!in_range(thr_adpt, 0, APDS9306_ALS_THRES_VAR_NUM_VALS)) return -EINVAL; *val = thr_adpt; @@ -808,7 +808,7 @@ static int apds9306_event_thresh_adaptive_set(struct apds9306_data *data, int va { struct apds9306_regfields *rf = &data->rf; - if (!in_range(val, 0, APDS9306_ALS_THRES_VAR_VAL_MAX)) + if (!in_range(val, 0, APDS9306_ALS_THRES_VAR_NUM_VALS)) return -EINVAL; return regmap_field_write(rf->int_thresh_var_val, val); -- cgit v1.2.3-59-g8ed1b From 70a57b247251aabadd67795c3097c0fcc616e533 Mon Sep 17 00:00:00 2001 From: Miguel Ojeda Date: Tue, 9 Apr 2024 18:25:16 +0100 Subject: RISC-V: enable building 64-bit kernels with rust support The rust modules work on 64-bit RISC-V, with no twiddling required. Select HAVE_RUST and provide the required flags to kbuild so that the modules can be used. The Makefile and Kconfig changes are lifted from work done by Miguel in the Rust-for-Linux tree, hence his authorship. Following the rabbit hole, the Makefile changes originated in a script, created based on config files originally added by Gary, hence his co-authorship. 32-bit is broken in core rust code, so support is limited to 64-bit: ld.lld: error: undefined symbol: __udivdi3 As 64-bit RISC-V is now supported, add it to the arch support table. Co-developed-by: Gary Guo Signed-off-by: Gary Guo Signed-off-by: Miguel Ojeda Co-developed-by: Conor Dooley Signed-off-by: Conor Dooley Link: https://lore.kernel.org/r/20240409-silencer-book-ce1320f06aab@spud Signed-off-by: Palmer Dabbelt --- Documentation/rust/arch-support.rst | 1 + arch/riscv/Kconfig | 1 + arch/riscv/Makefile | 7 +++++++ scripts/generate_rust_target.rs | 6 ++++++ 4 files changed, 15 insertions(+) diff --git a/Documentation/rust/arch-support.rst b/Documentation/rust/arch-support.rst index 5c4fa9f5d1cd..4d1495ded2aa 100644 --- a/Documentation/rust/arch-support.rst +++ b/Documentation/rust/arch-support.rst @@ -17,6 +17,7 @@ Architecture Level of support Constraints ============= ================ ============================================== ``arm64`` Maintained Little Endian only. ``loongarch`` Maintained - +``riscv`` Maintained ``riscv64`` only. ``um`` Maintained ``x86_64`` only. ``x86`` Maintained ``x86_64`` only. ============= ================ ============================================== diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index be09c8836d56..cad31864fd0f 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -155,6 +155,7 @@ config RISCV select HAVE_REGS_AND_STACK_ACCESS_API select HAVE_RETHOOK if !XIP_KERNEL select HAVE_RSEQ + select HAVE_RUST if 64BIT select HAVE_SAMPLE_FTRACE_DIRECT select HAVE_SAMPLE_FTRACE_DIRECT_MULTI select HAVE_STACKPROTECTOR diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile index a74e70405d3f..1a2dca1e6a96 100644 --- a/arch/riscv/Makefile +++ b/arch/riscv/Makefile @@ -34,6 +34,9 @@ ifeq ($(CONFIG_ARCH_RV64I),y) KBUILD_AFLAGS += -mabi=lp64 KBUILD_LDFLAGS += -melf64lriscv + + KBUILD_RUSTFLAGS += -Ctarget-cpu=generic-rv64 --target=riscv64imac-unknown-none-elf \ + -Cno-redzone else BITS := 32 UTS_MACHINE := riscv32 @@ -68,6 +71,10 @@ riscv-march-$(CONFIG_FPU) := $(riscv-march-y)fd riscv-march-$(CONFIG_RISCV_ISA_C) := $(riscv-march-y)c riscv-march-$(CONFIG_RISCV_ISA_V) := $(riscv-march-y)v +ifneq ($(CONFIG_RISCV_ISA_C),y) + KBUILD_RUSTFLAGS += -Ctarget-feature=-c +endif + ifdef CONFIG_TOOLCHAIN_NEEDS_OLD_ISA_SPEC KBUILD_CFLAGS += -Wa,-misa-spec=2.2 KBUILD_AFLAGS += -Wa,-misa-spec=2.2 diff --git a/scripts/generate_rust_target.rs b/scripts/generate_rust_target.rs index 54919cf48621..8f7846b9029a 100644 --- a/scripts/generate_rust_target.rs +++ b/scripts/generate_rust_target.rs @@ -150,6 +150,12 @@ fn main() { // `llvm-target`s are taken from `scripts/Makefile.clang`. if cfg.has("ARM64") { panic!("arm64 uses the builtin rustc aarch64-unknown-none target"); + } else if cfg.has("RISCV") { + if cfg.has("64BIT") { + panic!("64-bit RISC-V uses the builtin rustc riscv64-unknown-none-elf target"); + } else { + panic!("32-bit RISC-V is an unsupported architecture"); + } } else if cfg.has("X86_64") { ts.push("arch", "x86_64"); ts.push( -- cgit v1.2.3-59-g8ed1b From fa7d7339016ab7850258e85d6adfd4c4abca5498 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Tue, 12 Mar 2024 12:56:38 -0700 Subject: riscv: Do not save the scratch CSR during suspend While the processor is executing kernel code, the value of the scratch CSR is always zero, so there is no need to save the value. Continue to write the CSR during the resume flow, so we do not rely on firmware to initialize it. Signed-off-by: Samuel Holland Reviewed-by: Andrew Jones Link: https://lore.kernel.org/r/20240312195641.1830521-1-samuel.holland@sifive.com Signed-off-by: Palmer Dabbelt --- arch/riscv/include/asm/suspend.h | 1 - arch/riscv/kernel/suspend.c | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/arch/riscv/include/asm/suspend.h b/arch/riscv/include/asm/suspend.h index 4718096fa5e3..4ffb022b097f 100644 --- a/arch/riscv/include/asm/suspend.h +++ b/arch/riscv/include/asm/suspend.h @@ -13,7 +13,6 @@ struct suspend_context { /* Saved and restored by low-level functions */ struct pt_regs regs; /* Saved and restored by high-level functions */ - unsigned long scratch; unsigned long envcfg; unsigned long tvec; unsigned long ie; diff --git a/arch/riscv/kernel/suspend.c b/arch/riscv/kernel/suspend.c index 8a327b485b90..c8cec0cc5833 100644 --- a/arch/riscv/kernel/suspend.c +++ b/arch/riscv/kernel/suspend.c @@ -14,7 +14,6 @@ void suspend_save_csrs(struct suspend_context *context) { - context->scratch = csr_read(CSR_SCRATCH); if (riscv_cpu_has_extension_unlikely(smp_processor_id(), RISCV_ISA_EXT_XLINUXENVCFG)) context->envcfg = csr_read(CSR_ENVCFG); context->tvec = csr_read(CSR_TVEC); @@ -37,7 +36,7 @@ void suspend_save_csrs(struct suspend_context *context) void suspend_restore_csrs(struct suspend_context *context) { - csr_write(CSR_SCRATCH, context->scratch); + csr_write(CSR_SCRATCH, 0); if (riscv_cpu_has_extension_unlikely(smp_processor_id(), RISCV_ISA_EXT_XLINUXENVCFG)) csr_write(CSR_ENVCFG, context->envcfg); csr_write(CSR_TVEC, context->tvec); -- cgit v1.2.3-59-g8ed1b From 441381506ba7ca1cb8b44e651b130ab791d2e298 Mon Sep 17 00:00:00 2001 From: Clément Léger Date: Tue, 6 Feb 2024 16:40:59 +0100 Subject: riscv: misaligned: remove CONFIG_RISCV_M_MODE specific code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While reworking code to fix sparse errors, it appears that the RISCV_M_MODE specific could actually be removed and use the one for normal mode. Even though RISCV_M_MODE can do direct user memory access, using the user uaccess helpers is also going to work. Since there is no need anymore for specific accessors (load_u8()/store_u8()), we can directly use memcpy()/copy_{to/from}_user() and get rid of the copy loop entirely. __read_insn() is also fixed to use an unsigned long instead of a pointer which was cast in __user address space. The insn_addr parameter is now cast from unsigned lnog to the correct address space directly. Signed-off-by: Clément Léger Reviewed-by: Charlie Jenkins Link: https://lore.kernel.org/r/20240206154104.896809-1-cleger@rivosinc.com Signed-off-by: Palmer Dabbelt --- arch/riscv/kernel/traps_misaligned.c | 106 ++++++----------------------------- 1 file changed, 17 insertions(+), 89 deletions(-) diff --git a/arch/riscv/kernel/traps_misaligned.c b/arch/riscv/kernel/traps_misaligned.c index 2adb7c3e4dd5..b62d5a2f4541 100644 --- a/arch/riscv/kernel/traps_misaligned.c +++ b/arch/riscv/kernel/traps_misaligned.c @@ -264,86 +264,14 @@ static unsigned long get_f32_rs(unsigned long insn, u8 fp_reg_offset, #define GET_F32_RS2C(insn, regs) (get_f32_rs(insn, 2, regs)) #define GET_F32_RS2S(insn, regs) (get_f32_rs(RVC_RS2S(insn), 0, regs)) -#ifdef CONFIG_RISCV_M_MODE -static inline int load_u8(struct pt_regs *regs, const u8 *addr, u8 *r_val) -{ - u8 val; - - asm volatile("lbu %0, %1" : "=&r" (val) : "m" (*addr)); - *r_val = val; - - return 0; -} - -static inline int store_u8(struct pt_regs *regs, u8 *addr, u8 val) -{ - asm volatile ("sb %0, %1\n" : : "r" (val), "m" (*addr)); - - return 0; -} - -static inline int get_insn(struct pt_regs *regs, ulong mepc, ulong *r_insn) -{ - register ulong __mepc asm ("a2") = mepc; - ulong val, rvc_mask = 3, tmp; - - asm ("and %[tmp], %[addr], 2\n" - "bnez %[tmp], 1f\n" -#if defined(CONFIG_64BIT) - __stringify(LWU) " %[insn], (%[addr])\n" -#else - __stringify(LW) " %[insn], (%[addr])\n" -#endif - "and %[tmp], %[insn], %[rvc_mask]\n" - "beq %[tmp], %[rvc_mask], 2f\n" - "sll %[insn], %[insn], %[xlen_minus_16]\n" - "srl %[insn], %[insn], %[xlen_minus_16]\n" - "j 2f\n" - "1:\n" - "lhu %[insn], (%[addr])\n" - "and %[tmp], %[insn], %[rvc_mask]\n" - "bne %[tmp], %[rvc_mask], 2f\n" - "lhu %[tmp], 2(%[addr])\n" - "sll %[tmp], %[tmp], 16\n" - "add %[insn], %[insn], %[tmp]\n" - "2:" - : [insn] "=&r" (val), [tmp] "=&r" (tmp) - : [addr] "r" (__mepc), [rvc_mask] "r" (rvc_mask), - [xlen_minus_16] "i" (XLEN_MINUS_16)); - - *r_insn = val; - - return 0; -} -#else -static inline int load_u8(struct pt_regs *regs, const u8 *addr, u8 *r_val) -{ - if (user_mode(regs)) { - return __get_user(*r_val, (u8 __user *)addr); - } else { - *r_val = *addr; - return 0; - } -} - -static inline int store_u8(struct pt_regs *regs, u8 *addr, u8 val) -{ - if (user_mode(regs)) { - return __put_user(val, (u8 __user *)addr); - } else { - *addr = val; - return 0; - } -} - -#define __read_insn(regs, insn, insn_addr) \ +#define __read_insn(regs, insn, insn_addr, type) \ ({ \ int __ret; \ \ if (user_mode(regs)) { \ - __ret = __get_user(insn, insn_addr); \ + __ret = __get_user(insn, (type __user *) insn_addr); \ } else { \ - insn = *(__force u16 *)insn_addr; \ + insn = *(type *)insn_addr; \ __ret = 0; \ } \ \ @@ -356,9 +284,8 @@ static inline int get_insn(struct pt_regs *regs, ulong epc, ulong *r_insn) if (epc & 0x2) { ulong tmp = 0; - u16 __user *insn_addr = (u16 __user *)epc; - if (__read_insn(regs, insn, insn_addr)) + if (__read_insn(regs, insn, epc, u16)) return -EFAULT; /* __get_user() uses regular "lw" which sign extend the loaded * value make sure to clear higher order bits in case we "or" it @@ -369,16 +296,14 @@ static inline int get_insn(struct pt_regs *regs, ulong epc, ulong *r_insn) *r_insn = insn; return 0; } - insn_addr++; - if (__read_insn(regs, tmp, insn_addr)) + epc += sizeof(u16); + if (__read_insn(regs, tmp, epc, u16)) return -EFAULT; *r_insn = (tmp << 16) | insn; return 0; } else { - u32 __user *insn_addr = (u32 __user *)epc; - - if (__read_insn(regs, insn, insn_addr)) + if (__read_insn(regs, insn, epc, u32)) return -EFAULT; if ((insn & __INSN_LENGTH_MASK) == __INSN_LENGTH_32) { *r_insn = insn; @@ -390,7 +315,6 @@ static inline int get_insn(struct pt_regs *regs, ulong epc, ulong *r_insn) return 0; } } -#endif union reg_data { u8 data_bytes[8]; @@ -409,7 +333,7 @@ int handle_misaligned_load(struct pt_regs *regs) unsigned long epc = regs->epc; unsigned long insn; unsigned long addr = regs->badaddr; - int i, fp = 0, shift = 0, len = 0; + int fp = 0, shift = 0, len = 0; perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1, regs, addr); @@ -492,9 +416,11 @@ int handle_misaligned_load(struct pt_regs *regs) return -EOPNOTSUPP; val.data_u64 = 0; - for (i = 0; i < len; i++) { - if (load_u8(regs, (void *)(addr + i), &val.data_bytes[i])) + if (user_mode(regs)) { + if (raw_copy_from_user(&val, (u8 __user *)addr, len)) return -1; + } else { + memcpy(&val, (u8 *)addr, len); } if (!fp) @@ -515,7 +441,7 @@ int handle_misaligned_store(struct pt_regs *regs) unsigned long epc = regs->epc; unsigned long insn; unsigned long addr = regs->badaddr; - int i, len = 0, fp = 0; + int len = 0, fp = 0; perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1, regs, addr); @@ -588,9 +514,11 @@ int handle_misaligned_store(struct pt_regs *regs) if (!IS_ENABLED(CONFIG_FPU) && fp) return -EOPNOTSUPP; - for (i = 0; i < len; i++) { - if (store_u8(regs, (void *)(addr + i), val.data_bytes[i])) + if (user_mode(regs)) { + if (raw_copy_to_user((u8 __user *)addr, &val, len)) return -1; + } else { + memcpy((u8 *)addr, &val, len); } regs->epc = epc + INSN_LEN(insn); -- cgit v1.2.3-59-g8ed1b From 63f93a3ca891fd90353cf81f5d2fc4cbc3508f1a Mon Sep 17 00:00:00 2001 From: Clément Léger Date: Wed, 21 Feb 2024 09:31:06 +0100 Subject: riscv: hwprobe: export Zihintpause ISA extension MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Export the Zihintpause ISA extension through hwprobe which allows using "pause" instructions. Some userspace applications (OpenJDK for instance) uses this to handle some locking back-off. Signed-off-by: Clément Léger Reviewed-by: Atish Patra Link: https://lore.kernel.org/r/20240221083108.1235311-1-cleger@rivosinc.com Signed-off-by: Palmer Dabbelt --- Documentation/arch/riscv/hwprobe.rst | 4 ++++ arch/riscv/include/uapi/asm/hwprobe.h | 1 + arch/riscv/kernel/sys_hwprobe.c | 1 + 3 files changed, 6 insertions(+) diff --git a/Documentation/arch/riscv/hwprobe.rst b/Documentation/arch/riscv/hwprobe.rst index b2bcc9eed9aa..204cd4433af5 100644 --- a/Documentation/arch/riscv/hwprobe.rst +++ b/Documentation/arch/riscv/hwprobe.rst @@ -188,6 +188,10 @@ The following keys are defined: manual starting from commit 95cf1f9 ("Add changes requested by Ved during signoff") + * :c:macro:`RISCV_HWPROBE_EXT_ZIHINTPAUSE`: The Zihintpause extension is + supported as defined in the RISC-V ISA manual starting from commit + d8ab5c78c207 ("Zihintpause is ratified"). + * :c:macro:`RISCV_HWPROBE_KEY_CPUPERF_0`: A bitmask that contains performance information about the selected set of processors. diff --git a/arch/riscv/include/uapi/asm/hwprobe.h b/arch/riscv/include/uapi/asm/hwprobe.h index 9f2a8e3ff204..31c570cbd1c5 100644 --- a/arch/riscv/include/uapi/asm/hwprobe.h +++ b/arch/riscv/include/uapi/asm/hwprobe.h @@ -59,6 +59,7 @@ struct riscv_hwprobe { #define RISCV_HWPROBE_EXT_ZTSO (1ULL << 33) #define RISCV_HWPROBE_EXT_ZACAS (1ULL << 34) #define RISCV_HWPROBE_EXT_ZICOND (1ULL << 35) +#define RISCV_HWPROBE_EXT_ZIHINTPAUSE (1ULL << 36) #define RISCV_HWPROBE_KEY_CPUPERF_0 5 #define RISCV_HWPROBE_MISALIGNED_UNKNOWN (0 << 0) #define RISCV_HWPROBE_MISALIGNED_EMULATED (1 << 0) diff --git a/arch/riscv/kernel/sys_hwprobe.c b/arch/riscv/kernel/sys_hwprobe.c index 8cae41a502dd..969ef3d59dbe 100644 --- a/arch/riscv/kernel/sys_hwprobe.c +++ b/arch/riscv/kernel/sys_hwprobe.c @@ -111,6 +111,7 @@ static void hwprobe_isa_ext0(struct riscv_hwprobe *pair, EXT_KEY(ZTSO); EXT_KEY(ZACAS); EXT_KEY(ZICOND); + EXT_KEY(ZIHINTPAUSE); if (has_vector()) { EXT_KEY(ZVBB); -- cgit v1.2.3-59-g8ed1b From a3dc6d82de9bd88871dbc4ac511409e69ecacbfb Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Fri, 26 Apr 2024 07:58:58 +0300 Subject: thunderbolt: Correct trace output of firmware connection manager packets These are special packets that the drivers sends directly to the firmware connection manager (ICM). These do not have route string because they are always consumed by the firmware connection manager running on the host router, so hard-code that in the output accordingly. Signed-off-by: Mika Westerberg --- drivers/thunderbolt/trace.h | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/thunderbolt/trace.h b/drivers/thunderbolt/trace.h index 4dccfcf7af6a..6d0776514d12 100644 --- a/drivers/thunderbolt/trace.h +++ b/drivers/thunderbolt/trace.h @@ -87,23 +87,32 @@ static inline const char *show_data(struct trace_seq *p, u8 type, const char *prefix = ""; int i; - show_route(p, data); - switch (type) { case TB_CFG_PKG_READ: case TB_CFG_PKG_WRITE: + show_route(p, data); show_data_read_write(p, data); break; case TB_CFG_PKG_ERROR: + show_route(p, data); show_data_error(p, data); break; case TB_CFG_PKG_EVENT: + show_route(p, data); show_data_event(p, data); break; + case TB_CFG_PKG_ICM_EVENT: + case TB_CFG_PKG_ICM_CMD: + case TB_CFG_PKG_ICM_RESP: + /* ICM messages always target the host router */ + trace_seq_puts(p, "route=0, "); + break; + default: + show_route(p, data); break; } -- cgit v1.2.3-59-g8ed1b From 2d7e8a64a1e79f76b9d1165db0b92190d4663848 Mon Sep 17 00:00:00 2001 From: Remington Brasga Date: Sun, 28 Apr 2024 01:14:01 +0000 Subject: coresight: Docs/ABI/testing/sysfs-bus-coresight-devices: Fix spelling errors Fix spelling and gramatical errors Signed-off-by: Remington Brasga [ Adjusted title ] Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20240428011401.1080-1-rbrasga@uci.edu --- Documentation/ABI/testing/sysfs-bus-coresight-devices-etm3x | 2 +- Documentation/ABI/testing/sysfs-bus-coresight-devices-tmc | 2 +- Documentation/ABI/testing/sysfs-bus-coresight-devices-tpdm | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-etm3x b/Documentation/ABI/testing/sysfs-bus-coresight-devices-etm3x index 3acf7fc31659..271b57c571aa 100644 --- a/Documentation/ABI/testing/sysfs-bus-coresight-devices-etm3x +++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-etm3x @@ -22,7 +22,7 @@ Contact: Mathieu Poirier Description: (RW) Used in conjunction with @addr_idx. Specifies characteristics about the address comparator being configure, for example the access type, the kind of instruction to trace, - processor contect ID to trigger on, etc. Individual fields in + processor context ID to trigger on, etc. Individual fields in the access type register may vary on the version of the trace entity. diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tmc b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tmc index 96aafa66b4a5..339cec3b2f1a 100644 --- a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tmc +++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tmc @@ -97,7 +97,7 @@ Date: August 2023 KernelVersion: 6.7 Contact: Anshuman Khandual Description: (Read) Shows all supported Coresight TMC-ETR buffer modes available - for the users to configure explicitly. This file is avaialble only + for the users to configure explicitly. This file is available only for TMC ETR devices. What: /sys/bus/coresight/devices/.tmc/buf_mode_preferred diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpdm b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpdm index b4d0fc8d319d..bf710ea6e0ef 100644 --- a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpdm +++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpdm @@ -244,7 +244,7 @@ KernelVersion 6.9 Contact: Jinlong Mao (QUIC) , Tao Zhang (QUIC) Description: (RW) Read or write the status of timestamp upon all interface. - Only value 0 and 1 can be written to this node. Set this node to 1 to requeset + Only value 0 and 1 can be written to this node. Set this node to 1 to request timestamp to all trace packet. Accepts only one of the 2 values - 0 or 1. 0 : Disable the timestamp of all trace packets. -- cgit v1.2.3-59-g8ed1b From a2c72ed78ab8557ac58cd88d8cf871fcb8c740ee Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Mon, 29 Apr 2024 10:38:25 +0200 Subject: mcb: lpc: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Signed-off-by: Johannes Thumshirn Link: https://lore.kernel.org/r/cd04e21a7e2646bfe44b2304eea2b3fd0ee84018.1714379722.git.jth@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/mcb/mcb-lpc.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/mcb/mcb-lpc.c b/drivers/mcb/mcb-lpc.c index a851e0236464..2bec2086ee17 100644 --- a/drivers/mcb/mcb-lpc.c +++ b/drivers/mcb/mcb-lpc.c @@ -97,13 +97,11 @@ out_mcb_bus: return ret; } -static int mcb_lpc_remove(struct platform_device *pdev) +static void mcb_lpc_remove(struct platform_device *pdev) { struct priv *priv = platform_get_drvdata(pdev); mcb_release_bus(priv->bus); - - return 0; } static struct platform_device *mcb_lpc_pdev; @@ -140,7 +138,7 @@ static struct platform_driver mcb_lpc_driver = { .name = "mcb-lpc", }, .probe = mcb_lpc_probe, - .remove = mcb_lpc_remove, + .remove_new = mcb_lpc_remove, }; static const struct dmi_system_id mcb_lpc_dmi_table[] = { -- cgit v1.2.3-59-g8ed1b From 7c28f964b7febc00edfced0f499630005a800643 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 14 Apr 2024 17:49:55 +0200 Subject: eeprom: at25: drop unneeded MODULE_ALIAS The ID table already has respective entry and MODULE_DEVICE_TABLE and creates proper alias for SPI driver. Having another MODULE_ALIAS causes the alias to be duplicated. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240414154957.127113-1-krzk@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/misc/eeprom/at25.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/misc/eeprom/at25.c b/drivers/misc/eeprom/at25.c index 65d49a6de1a7..595ceb9a7126 100644 --- a/drivers/misc/eeprom/at25.c +++ b/drivers/misc/eeprom/at25.c @@ -529,4 +529,3 @@ module_spi_driver(at25_driver); MODULE_DESCRIPTION("Driver for most SPI EEPROMs"); MODULE_AUTHOR("David Brownell"); MODULE_LICENSE("GPL"); -MODULE_ALIAS("spi:at25"); -- cgit v1.2.3-59-g8ed1b From 2db26427d7d92e34246ee378214b4c2c193b96e7 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 14 Apr 2024 17:49:57 +0200 Subject: eeprom: 93xx46: drop unneeded MODULE_ALIAS The ID table already has respective entry and MODULE_DEVICE_TABLE and creates proper alias for SPI driver. Having another MODULE_ALIAS causes the alias to be duplicated. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240414154957.127113-3-krzk@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/misc/eeprom/eeprom_93xx46.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/misc/eeprom/eeprom_93xx46.c b/drivers/misc/eeprom/eeprom_93xx46.c index e78a76d74ff4..45c8ae0db8f9 100644 --- a/drivers/misc/eeprom/eeprom_93xx46.c +++ b/drivers/misc/eeprom/eeprom_93xx46.c @@ -578,5 +578,3 @@ MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Driver for 93xx46 EEPROMs"); MODULE_AUTHOR("Anatolij Gustschin "); MODULE_ALIAS("spi:93xx46"); -MODULE_ALIAS("spi:eeprom-93xx46"); -MODULE_ALIAS("spi:93lc46b"); -- cgit v1.2.3-59-g8ed1b From 7a5ffa5a21d327e867c8ee226278d60f7e34e1b9 Mon Sep 17 00:00:00 2001 From: Prasad Pandit Date: Fri, 12 Apr 2024 11:22:20 +0530 Subject: misc: sgi_gru: indent SGI_GRU option help text Fix indentation of SGI_GRU option's help text by adding leading spaces. Generally help text is indented by two more spaces beyond the leading tab <\t> character. It helps Kconfig parsers to read file without error. Signed-off-by: Prasad Pandit Link: https://lore.kernel.org/r/20240412055221.69411-2-ppandit@redhat.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/Kconfig | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 801ed229ed7d..c9295a0a3305 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -293,21 +293,21 @@ config SGI_GRU depends on X86_UV && SMP select MMU_NOTIFIER help - The GRU is a hardware resource located in the system chipset. The GRU - contains memory that can be mmapped into the user address space. This memory is - used to communicate with the GRU to perform functions such as load/store, - scatter/gather, bcopy, AMOs, etc. The GRU is directly accessed by user - instructions using user virtual addresses. GRU instructions (ex., bcopy) use - user virtual addresses for operands. + The GRU is a hardware resource located in the system chipset. The GRU + contains memory that can be mmapped into the user address space. + This memory is used to communicate with the GRU to perform functions + such as load/store, scatter/gather, bcopy, AMOs, etc. The GRU is + directly accessed by user instructions using user virtual addresses. + GRU instructions (ex., bcopy) use user virtual addresses for operands. - If you are not running on a SGI UV system, say N. + If you are not running on a SGI UV system, say N. config SGI_GRU_DEBUG bool "SGI GRU driver debug" depends on SGI_GRU help - This option enables additional debugging code for the SGI GRU driver. - If you are unsure, say N. + This option enables additional debugging code for the SGI GRU driver. + If you are unsure, say N. config APDS9802ALS tristate "Medfield Avago APDS9802 ALS Sensor module" -- cgit v1.2.3-59-g8ed1b From 11e5e1aba749cd354e7330bb40f09ffc92282244 Mon Sep 17 00:00:00 2001 From: Prasad Pandit Date: Fri, 12 Apr 2024 11:22:21 +0530 Subject: misc: sgi_gru: remove default attribute of LATTICE_ECP3_CONFIG Remove 'default n' attribute of 'LATTICE_ECP3_CONFIG' option because it is redundant. 'n' is automatic default value when one is not specified. Suggested-by: Greg Kroah-Hartman Signed-off-by: Prasad Pandit Link: https://lore.kernel.org/r/20240412055221.69411-3-ppandit@redhat.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index c9295a0a3305..2907b5c23368 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -428,7 +428,6 @@ config LATTICE_ECP3_CONFIG tristate "Lattice ECP3 FPGA bitstream configuration via SPI" depends on SPI && SYSFS select FW_LOADER - default n help This option enables support for bitstream configuration (programming or loading) of the Lattice ECP3 FPGA family via SPI. -- cgit v1.2.3-59-g8ed1b From 7b51b13733214b0491e935ff6ffc64a5730caa2a Mon Sep 17 00:00:00 2001 From: Thomas Weißschuh Date: Fri, 12 Apr 2024 08:26:40 +0200 Subject: misc/pvpanic: add support for normal shutdowns MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Shutdown requests are normally hardware dependent. By extending pvpanic to also handle shutdown requests, guests can submit such requests with an easily implementable and cross-platform mechanism. Signed-off-by: Thomas Weißschuh Link: https://lore.kernel.org/r/20240412-pvpanic-shutdown-v3-1-c214e9873b3f@weissschuh.net Signed-off-by: Greg Kroah-Hartman --- drivers/misc/pvpanic/pvpanic.c | 43 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/drivers/misc/pvpanic/pvpanic.c b/drivers/misc/pvpanic/pvpanic.c index df3457ce1cb1..17c0eb549463 100644 --- a/drivers/misc/pvpanic/pvpanic.c +++ b/drivers/misc/pvpanic/pvpanic.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -35,6 +36,7 @@ struct pvpanic_instance { void __iomem *base; unsigned int capability; unsigned int events; + struct sys_off_handler *sys_off; struct list_head list; }; @@ -78,6 +80,39 @@ static struct notifier_block pvpanic_panic_nb = { .priority = INT_MAX, }; +static int pvpanic_sys_off(struct sys_off_data *data) +{ + pvpanic_send_event(PVPANIC_SHUTDOWN); + + return NOTIFY_DONE; +} + +static void pvpanic_synchronize_sys_off_handler(struct device *dev, struct pvpanic_instance *pi) +{ + /* The kernel core has logic to fall back to system halt if no + * sys_off_handler is registered. + * When the pvpanic sys_off_handler is disabled via sysfs the kernel + * should use that fallback logic, so the handler needs to be unregistered. + */ + + struct sys_off_handler *sys_off; + + if (!(pi->events & PVPANIC_SHUTDOWN) == !pi->sys_off) + return; + + if (!pi->sys_off) { + sys_off = register_sys_off_handler(SYS_OFF_MODE_POWER_OFF, SYS_OFF_PRIO_LOW, + pvpanic_sys_off, NULL); + if (IS_ERR(sys_off)) + dev_warn(dev, "Could not register sys_off_handler: %pe\n", sys_off); + else + pi->sys_off = sys_off; + } else { + unregister_sys_off_handler(pi->sys_off); + pi->sys_off = NULL; + } +} + static void pvpanic_remove(void *param) { struct pvpanic_instance *pi_cur, *pi_next; @@ -91,6 +126,8 @@ static void pvpanic_remove(void *param) } } spin_unlock(&pvpanic_lock); + + unregister_sys_off_handler(pi->sys_off); } static ssize_t capability_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -123,6 +160,7 @@ static ssize_t events_store(struct device *dev, struct device_attribute *attr, return -EINVAL; pi->events = tmp; + pvpanic_synchronize_sys_off_handler(dev, pi); return count; } @@ -156,12 +194,15 @@ int devm_pvpanic_probe(struct device *dev, void __iomem *base) return -ENOMEM; pi->base = base; - pi->capability = PVPANIC_PANICKED | PVPANIC_CRASH_LOADED; + pi->capability = PVPANIC_PANICKED | PVPANIC_CRASH_LOADED | PVPANIC_SHUTDOWN; /* initlize capability by RDPT */ pi->capability &= ioread8(base); pi->events = pi->capability; + pi->sys_off = NULL; + pvpanic_synchronize_sys_off_handler(dev, pi); + spin_lock(&pvpanic_lock); list_add(&pi->list, &pvpanic_list); spin_unlock(&pvpanic_lock); -- cgit v1.2.3-59-g8ed1b From c9758cc45c2bd442743848eba88e187bda3047f9 Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Mon, 29 Apr 2024 12:47:06 +0300 Subject: PCI/ERR: Cleanup misleading indentation inside if conditions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A few if conditions align misleadingly with the following code block. The checks are really cascading NULL checks that fit into 80 chars so remove newlines in between and realign to the if condition indent. Link: https://lore.kernel.org/r/20240429094707.2529-1-ilpo.jarvinen@linux.intel.com Signed-off-by: Ilpo Järvinen Signed-off-by: Bjorn Helgaas --- drivers/pci/pcie/err.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/drivers/pci/pcie/err.c b/drivers/pci/pcie/err.c index 705893b5f7b0..31090770fffc 100644 --- a/drivers/pci/pcie/err.c +++ b/drivers/pci/pcie/err.c @@ -116,9 +116,7 @@ static int report_mmio_enabled(struct pci_dev *dev, void *data) device_lock(&dev->dev); pdrv = dev->driver; - if (!pdrv || - !pdrv->err_handler || - !pdrv->err_handler->mmio_enabled) + if (!pdrv || !pdrv->err_handler || !pdrv->err_handler->mmio_enabled) goto out; err_handler = pdrv->err_handler; @@ -137,9 +135,7 @@ static int report_slot_reset(struct pci_dev *dev, void *data) device_lock(&dev->dev); pdrv = dev->driver; - if (!pdrv || - !pdrv->err_handler || - !pdrv->err_handler->slot_reset) + if (!pdrv || !pdrv->err_handler || !pdrv->err_handler->slot_reset) goto out; err_handler = pdrv->err_handler; @@ -158,9 +154,7 @@ static int report_resume(struct pci_dev *dev, void *data) device_lock(&dev->dev); pdrv = dev->driver; if (!pci_dev_set_io_state(dev, pci_channel_io_normal) || - !pdrv || - !pdrv->err_handler || - !pdrv->err_handler->resume) + !pdrv || !pdrv->err_handler || !pdrv->err_handler->resume) goto out; err_handler = pdrv->err_handler; -- cgit v1.2.3-59-g8ed1b From 4c407392c1aff30025457972b173a0729830945f Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Mon, 29 Apr 2024 12:47:07 +0300 Subject: PCI: Clean up accessor macro formatting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Clean up formatting of PCI accessor macros: - Put return statements on own line - Add a few empty lines for better readability - Align macro continuation backslashes - Correct function call argument indentation level - Reorder variable declarations to order of use - Drop unnecessary variable initialization Link: https://lore.kernel.org/r/20240429094707.2529-2-ilpo.jarvinen@linux.intel.com Signed-off-by: Ilpo Järvinen [bhelgaas: drop initialization, tweak variables to order of use] Signed-off-by: Bjorn Helgaas --- drivers/pci/access.c | 40 +++++++++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/drivers/pci/access.c b/drivers/pci/access.c index 6449056b57dd..b123da16b63b 100644 --- a/drivers/pci/access.c +++ b/drivers/pci/access.c @@ -36,10 +36,13 @@ DEFINE_RAW_SPINLOCK(pci_lock); int noinline pci_bus_read_config_##size \ (struct pci_bus *bus, unsigned int devfn, int pos, type *value) \ { \ - int res; \ unsigned long flags; \ u32 data = 0; \ - if (PCI_##size##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER; \ + int res; \ + \ + if (PCI_##size##_BAD) \ + return PCIBIOS_BAD_REGISTER_NUMBER; \ + \ pci_lock_config(flags); \ res = bus->ops->read(bus, devfn, pos, len, &data); \ if (res) \ @@ -47,6 +50,7 @@ int noinline pci_bus_read_config_##size \ else \ *value = (type)data; \ pci_unlock_config(flags); \ + \ return res; \ } @@ -54,12 +58,16 @@ int noinline pci_bus_read_config_##size \ int noinline pci_bus_write_config_##size \ (struct pci_bus *bus, unsigned int devfn, int pos, type value) \ { \ - int res; \ unsigned long flags; \ - if (PCI_##size##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER; \ + int res; \ + \ + if (PCI_##size##_BAD) \ + return PCIBIOS_BAD_REGISTER_NUMBER; \ + \ pci_lock_config(flags); \ res = bus->ops->write(bus, devfn, pos, len, value); \ pci_unlock_config(flags); \ + \ return res; \ } @@ -216,24 +224,27 @@ static noinline void pci_wait_cfg(struct pci_dev *dev) } /* Returns 0 on success, negative values indicate error. */ -#define PCI_USER_READ_CONFIG(size, type) \ +#define PCI_USER_READ_CONFIG(size, type) \ int pci_user_read_config_##size \ (struct pci_dev *dev, int pos, type *val) \ { \ - int ret = PCIBIOS_SUCCESSFUL; \ u32 data = -1; \ + int ret; \ + \ if (PCI_##size##_BAD) \ return -EINVAL; \ - raw_spin_lock_irq(&pci_lock); \ + \ + raw_spin_lock_irq(&pci_lock); \ if (unlikely(dev->block_cfg_access)) \ pci_wait_cfg(dev); \ ret = dev->bus->ops->read(dev->bus, dev->devfn, \ - pos, sizeof(type), &data); \ - raw_spin_unlock_irq(&pci_lock); \ + pos, sizeof(type), &data); \ + raw_spin_unlock_irq(&pci_lock); \ if (ret) \ PCI_SET_ERROR_RESPONSE(val); \ else \ *val = (type)data; \ + \ return pcibios_err_to_errno(ret); \ } \ EXPORT_SYMBOL_GPL(pci_user_read_config_##size); @@ -243,15 +254,18 @@ EXPORT_SYMBOL_GPL(pci_user_read_config_##size); int pci_user_write_config_##size \ (struct pci_dev *dev, int pos, type val) \ { \ - int ret = PCIBIOS_SUCCESSFUL; \ + int ret; \ + \ if (PCI_##size##_BAD) \ return -EINVAL; \ - raw_spin_lock_irq(&pci_lock); \ + \ + raw_spin_lock_irq(&pci_lock); \ if (unlikely(dev->block_cfg_access)) \ pci_wait_cfg(dev); \ ret = dev->bus->ops->write(dev->bus, dev->devfn, \ - pos, sizeof(type), val); \ - raw_spin_unlock_irq(&pci_lock); \ + pos, sizeof(type), val); \ + raw_spin_unlock_irq(&pci_lock); \ + \ return pcibios_err_to_errno(ret); \ } \ EXPORT_SYMBOL_GPL(pci_user_write_config_##size); -- cgit v1.2.3-59-g8ed1b From 58661a30f1bcc748475ffd9be6d2fc9e4e6be679 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Tue, 26 Mar 2024 21:49:42 -0700 Subject: riscv: Flush the instruction cache during SMP bringup Instruction cache flush IPIs are sent only to CPUs in cpu_online_mask, so they will not target a CPU until it calls set_cpu_online() earlier in smp_callin(). As a result, if instruction memory is modified between the CPU coming out of reset and that point, then its instruction cache may contain stale data. Therefore, the instruction cache must be flushed after the set_cpu_online() synchronization point. Fixes: 08f051eda33b ("RISC-V: Flush I$ when making a dirty page executable") Reviewed-by: Alexandre Ghiti Signed-off-by: Samuel Holland Link: https://lore.kernel.org/r/20240327045035.368512-2-samuel.holland@sifive.com Signed-off-by: Palmer Dabbelt --- arch/riscv/kernel/smpboot.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/arch/riscv/kernel/smpboot.c b/arch/riscv/kernel/smpboot.c index d41090fc3203..4b3c50da48ba 100644 --- a/arch/riscv/kernel/smpboot.c +++ b/arch/riscv/kernel/smpboot.c @@ -26,7 +26,7 @@ #include #include -#include +#include #include #include #include @@ -234,9 +234,10 @@ asmlinkage __visible void smp_callin(void) riscv_user_isa_enable(); /* - * Remote TLB flushes are ignored while the CPU is offline, so emit - * a local TLB flush right now just in case. + * Remote cache and TLB flushes are ignored while the CPU is offline, + * so flush them both right now just in case. */ + local_flush_icache_all(); local_flush_tlb_all(); complete(&cpu_running); /* -- cgit v1.2.3-59-g8ed1b From aaa56c8f378dd798f4a7f633cbf2eb129e98e6a4 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Tue, 26 Mar 2024 21:49:43 -0700 Subject: riscv: Factor out page table TLB synchronization The logic is the same for all page table levels. See commit 69be3fb111e7 ("riscv: enable MMU_GATHER_RCU_TABLE_FREE for SMP && MMU"). Signed-off-by: Samuel Holland Reviewed-by: Alexandre Ghiti Link: https://lore.kernel.org/r/20240327045035.368512-3-samuel.holland@sifive.com Signed-off-by: Palmer Dabbelt --- arch/riscv/include/asm/pgalloc.h | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/arch/riscv/include/asm/pgalloc.h b/arch/riscv/include/asm/pgalloc.h index deaf971253a2..b34587da8882 100644 --- a/arch/riscv/include/asm/pgalloc.h +++ b/arch/riscv/include/asm/pgalloc.h @@ -15,6 +15,14 @@ #define __HAVE_ARCH_PUD_FREE #include +static inline void riscv_tlb_remove_ptdesc(struct mmu_gather *tlb, void *pt) +{ + if (riscv_use_ipi_for_rfence()) + tlb_remove_page_ptdesc(tlb, pt); + else + tlb_remove_ptdesc(tlb, pt); +} + static inline void pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd, pte_t *pte) { @@ -102,10 +110,7 @@ static inline void __pud_free_tlb(struct mmu_gather *tlb, pud_t *pud, struct ptdesc *ptdesc = virt_to_ptdesc(pud); pagetable_pud_dtor(ptdesc); - if (riscv_use_ipi_for_rfence()) - tlb_remove_page_ptdesc(tlb, ptdesc); - else - tlb_remove_ptdesc(tlb, ptdesc); + riscv_tlb_remove_ptdesc(tlb, ptdesc); } } @@ -139,12 +144,8 @@ static inline void p4d_free(struct mm_struct *mm, p4d_t *p4d) static inline void __p4d_free_tlb(struct mmu_gather *tlb, p4d_t *p4d, unsigned long addr) { - if (pgtable_l5_enabled) { - if (riscv_use_ipi_for_rfence()) - tlb_remove_page_ptdesc(tlb, virt_to_ptdesc(p4d)); - else - tlb_remove_ptdesc(tlb, virt_to_ptdesc(p4d)); - } + if (pgtable_l5_enabled) + riscv_tlb_remove_ptdesc(tlb, virt_to_ptdesc(p4d)); } #endif /* __PAGETABLE_PMD_FOLDED */ @@ -176,10 +177,7 @@ static inline void __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd, struct ptdesc *ptdesc = virt_to_ptdesc(pmd); pagetable_pmd_dtor(ptdesc); - if (riscv_use_ipi_for_rfence()) - tlb_remove_page_ptdesc(tlb, ptdesc); - else - tlb_remove_ptdesc(tlb, ptdesc); + riscv_tlb_remove_ptdesc(tlb, ptdesc); } #endif /* __PAGETABLE_PMD_FOLDED */ @@ -190,10 +188,7 @@ static inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t pte, struct ptdesc *ptdesc = page_ptdesc(pte); pagetable_pte_dtor(ptdesc); - if (riscv_use_ipi_for_rfence()) - tlb_remove_page_ptdesc(tlb, ptdesc); - else - tlb_remove_ptdesc(tlb, ptdesc); + riscv_tlb_remove_ptdesc(tlb, ptdesc); } #endif /* CONFIG_MMU */ -- cgit v1.2.3-59-g8ed1b From dc892fb443224da7018891a5fac9cb6ac50c14b3 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Tue, 26 Mar 2024 21:49:44 -0700 Subject: riscv: Use IPIs for remote cache/TLB flushes by default An IPI backend is always required in an SMP configuration, but an SBI implementation is not. For example, SBI will be unavailable when the kernel runs in M mode. For this reason, consider IPI delivery of cache and TLB flushes to be the base case, and any other implementation (such as the SBI remote fence extension) to be an optimization. Generally, if IPIs can be delivered without firmware assistance, they are assumed to be faster than SBI calls due to the SBI context switch overhead. However, when SBI is used as the IPI backend, then the context switch cost must be paid anyway, and performing the cache/TLB flush directly in the SBI implementation is more efficient than injecting an interrupt to S-mode. This is the only existing scenario where riscv_ipi_set_virq_range() is called with use_for_rfence set to false. sbi_ipi_init() already checks riscv_ipi_have_virq_range(), so it only calls riscv_ipi_set_virq_range() when no other IPI device is available. This allows moving the static key and dropping the use_for_rfence parameter. This decouples the static key from the irqchip driver probe order. Furthermore, the static branch only makes sense when CONFIG_RISCV_SBI is enabled. Optherwise, IPIs must be used. Add a fallback definition of riscv_use_sbi_for_rfence() which handles this case and removes the need to check CONFIG_RISCV_SBI elsewhere, such as in cacheflush.c. Reviewed-by: Anup Patel Signed-off-by: Samuel Holland Reviewed-by: Alexandre Ghiti Link: https://lore.kernel.org/r/20240327045035.368512-4-samuel.holland@sifive.com Signed-off-by: Palmer Dabbelt --- arch/riscv/include/asm/pgalloc.h | 7 ++++--- arch/riscv/include/asm/sbi.h | 4 ++++ arch/riscv/include/asm/smp.h | 15 ++------------- arch/riscv/kernel/sbi-ipi.c | 11 ++++++++++- arch/riscv/kernel/smp.c | 11 +---------- arch/riscv/mm/cacheflush.c | 5 ++--- arch/riscv/mm/tlbflush.c | 31 ++++++++++++++----------------- drivers/clocksource/timer-clint.c | 2 +- 8 files changed, 38 insertions(+), 48 deletions(-) diff --git a/arch/riscv/include/asm/pgalloc.h b/arch/riscv/include/asm/pgalloc.h index b34587da8882..f52264304f77 100644 --- a/arch/riscv/include/asm/pgalloc.h +++ b/arch/riscv/include/asm/pgalloc.h @@ -8,6 +8,7 @@ #define _ASM_RISCV_PGALLOC_H #include +#include #include #ifdef CONFIG_MMU @@ -17,10 +18,10 @@ static inline void riscv_tlb_remove_ptdesc(struct mmu_gather *tlb, void *pt) { - if (riscv_use_ipi_for_rfence()) - tlb_remove_page_ptdesc(tlb, pt); - else + if (riscv_use_sbi_for_rfence()) tlb_remove_ptdesc(tlb, pt); + else + tlb_remove_page_ptdesc(tlb, pt); } static inline void pmd_populate_kernel(struct mm_struct *mm, diff --git a/arch/riscv/include/asm/sbi.h b/arch/riscv/include/asm/sbi.h index 6e68f8dff76b..ea84392ca9d7 100644 --- a/arch/riscv/include/asm/sbi.h +++ b/arch/riscv/include/asm/sbi.h @@ -375,8 +375,12 @@ unsigned long riscv_cached_marchid(unsigned int cpu_id); unsigned long riscv_cached_mimpid(unsigned int cpu_id); #if IS_ENABLED(CONFIG_SMP) && IS_ENABLED(CONFIG_RISCV_SBI) +DECLARE_STATIC_KEY_FALSE(riscv_sbi_for_rfence); +#define riscv_use_sbi_for_rfence() \ + static_branch_unlikely(&riscv_sbi_for_rfence) void sbi_ipi_init(void); #else +static inline bool riscv_use_sbi_for_rfence(void) { return false; } static inline void sbi_ipi_init(void) { } #endif diff --git a/arch/riscv/include/asm/smp.h b/arch/riscv/include/asm/smp.h index 0d555847cde6..7ac80e9f2288 100644 --- a/arch/riscv/include/asm/smp.h +++ b/arch/riscv/include/asm/smp.h @@ -49,12 +49,7 @@ void riscv_ipi_disable(void); bool riscv_ipi_have_virq_range(void); /* Set the IPI interrupt numbers for arch (called by irqchip drivers) */ -void riscv_ipi_set_virq_range(int virq, int nr, bool use_for_rfence); - -/* Check if we can use IPIs for remote FENCEs */ -DECLARE_STATIC_KEY_FALSE(riscv_ipi_for_rfence); -#define riscv_use_ipi_for_rfence() \ - static_branch_unlikely(&riscv_ipi_for_rfence) +void riscv_ipi_set_virq_range(int virq, int nr); /* Check other CPUs stop or not */ bool smp_crash_stop_failed(void); @@ -104,16 +99,10 @@ static inline bool riscv_ipi_have_virq_range(void) return false; } -static inline void riscv_ipi_set_virq_range(int virq, int nr, - bool use_for_rfence) +static inline void riscv_ipi_set_virq_range(int virq, int nr) { } -static inline bool riscv_use_ipi_for_rfence(void) -{ - return false; -} - #endif /* CONFIG_SMP */ #if defined(CONFIG_HOTPLUG_CPU) && (CONFIG_SMP) diff --git a/arch/riscv/kernel/sbi-ipi.c b/arch/riscv/kernel/sbi-ipi.c index a4559695ce62..1026e22955cc 100644 --- a/arch/riscv/kernel/sbi-ipi.c +++ b/arch/riscv/kernel/sbi-ipi.c @@ -13,6 +13,9 @@ #include #include +DEFINE_STATIC_KEY_FALSE(riscv_sbi_for_rfence); +EXPORT_SYMBOL_GPL(riscv_sbi_for_rfence); + static int sbi_ipi_virq; static void sbi_ipi_handle(struct irq_desc *desc) @@ -72,6 +75,12 @@ void __init sbi_ipi_init(void) "irqchip/sbi-ipi:starting", sbi_ipi_starting_cpu, NULL); - riscv_ipi_set_virq_range(virq, BITS_PER_BYTE, false); + riscv_ipi_set_virq_range(virq, BITS_PER_BYTE); pr_info("providing IPIs using SBI IPI extension\n"); + + /* + * Use the SBI remote fence extension to avoid + * the extra context switch needed to handle IPIs. + */ + static_branch_enable(&riscv_sbi_for_rfence); } diff --git a/arch/riscv/kernel/smp.c b/arch/riscv/kernel/smp.c index 45dd4035416e..8e6eb64459af 100644 --- a/arch/riscv/kernel/smp.c +++ b/arch/riscv/kernel/smp.c @@ -171,10 +171,7 @@ bool riscv_ipi_have_virq_range(void) return (ipi_virq_base) ? true : false; } -DEFINE_STATIC_KEY_FALSE(riscv_ipi_for_rfence); -EXPORT_SYMBOL_GPL(riscv_ipi_for_rfence); - -void riscv_ipi_set_virq_range(int virq, int nr, bool use_for_rfence) +void riscv_ipi_set_virq_range(int virq, int nr) { int i, err; @@ -197,12 +194,6 @@ void riscv_ipi_set_virq_range(int virq, int nr, bool use_for_rfence) /* Enabled IPIs for boot CPU immediately */ riscv_ipi_enable(); - - /* Update RFENCE static key */ - if (use_for_rfence) - static_branch_enable(&riscv_ipi_for_rfence); - else - static_branch_disable(&riscv_ipi_for_rfence); } static const char * const ipi_names[] = { diff --git a/arch/riscv/mm/cacheflush.c b/arch/riscv/mm/cacheflush.c index bc61ee5975e4..d76fc73e594b 100644 --- a/arch/riscv/mm/cacheflush.c +++ b/arch/riscv/mm/cacheflush.c @@ -21,7 +21,7 @@ void flush_icache_all(void) { local_flush_icache_all(); - if (IS_ENABLED(CONFIG_RISCV_SBI) && !riscv_use_ipi_for_rfence()) + if (riscv_use_sbi_for_rfence()) sbi_remote_fence_i(NULL); else on_each_cpu(ipi_remote_fence_i, NULL, 1); @@ -69,8 +69,7 @@ void flush_icache_mm(struct mm_struct *mm, bool local) * with flush_icache_deferred(). */ smp_mb(); - } else if (IS_ENABLED(CONFIG_RISCV_SBI) && - !riscv_use_ipi_for_rfence()) { + } else if (riscv_use_sbi_for_rfence()) { sbi_remote_fence_i(&others); } else { on_each_cpu_mask(&others, ipi_remote_fence_i, NULL, 1); diff --git a/arch/riscv/mm/tlbflush.c b/arch/riscv/mm/tlbflush.c index 893566e004b7..0435605b07d0 100644 --- a/arch/riscv/mm/tlbflush.c +++ b/arch/riscv/mm/tlbflush.c @@ -79,10 +79,10 @@ static void __ipi_flush_tlb_all(void *info) void flush_tlb_all(void) { - if (riscv_use_ipi_for_rfence()) - on_each_cpu(__ipi_flush_tlb_all, NULL, 1); - else + if (riscv_use_sbi_for_rfence()) sbi_remote_sfence_vma_asid(NULL, 0, FLUSH_TLB_MAX_SIZE, FLUSH_TLB_NO_ASID); + else + on_each_cpu(__ipi_flush_tlb_all, NULL, 1); } struct flush_tlb_range_data { @@ -103,7 +103,6 @@ static void __flush_tlb_range(struct cpumask *cmask, unsigned long asid, unsigned long start, unsigned long size, unsigned long stride) { - struct flush_tlb_range_data ftd; bool broadcast; if (cpumask_empty(cmask)) @@ -119,20 +118,18 @@ static void __flush_tlb_range(struct cpumask *cmask, unsigned long asid, broadcast = true; } - if (broadcast) { - if (riscv_use_ipi_for_rfence()) { - ftd.asid = asid; - ftd.start = start; - ftd.size = size; - ftd.stride = stride; - on_each_cpu_mask(cmask, - __ipi_flush_tlb_range_asid, - &ftd, 1); - } else - sbi_remote_sfence_vma_asid(cmask, - start, size, asid); - } else { + if (!broadcast) { local_flush_tlb_range_asid(start, size, stride, asid); + } else if (riscv_use_sbi_for_rfence()) { + sbi_remote_sfence_vma_asid(cmask, start, size, asid); + } else { + struct flush_tlb_range_data ftd; + + ftd.asid = asid; + ftd.start = start; + ftd.size = size; + ftd.stride = stride; + on_each_cpu_mask(cmask, __ipi_flush_tlb_range_asid, &ftd, 1); } if (cmask != cpu_online_mask) diff --git a/drivers/clocksource/timer-clint.c b/drivers/clocksource/timer-clint.c index 09fd292eb83d..0bdd9d7ec545 100644 --- a/drivers/clocksource/timer-clint.c +++ b/drivers/clocksource/timer-clint.c @@ -251,7 +251,7 @@ static int __init clint_timer_init_dt(struct device_node *np) } irq_set_chained_handler(clint_ipi_irq, clint_ipi_interrupt); - riscv_ipi_set_virq_range(rc, BITS_PER_BYTE, true); + riscv_ipi_set_virq_range(rc, BITS_PER_BYTE); clint_clear_ipi(); #endif -- cgit v1.2.3-59-g8ed1b From 038ac18aae935c89c874649acde5a82f588a12b4 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Tue, 26 Mar 2024 21:49:45 -0700 Subject: riscv: mm: Broadcast kernel TLB flushes only when needed __flush_tlb_range() avoids broadcasting TLB flushes when an mm context is only active on the local CPU. Apply this same optimization to TLB flushes of kernel memory when only one CPU is online. This check can be constant-folded when SMP is disabled. Reviewed-by: Alexandre Ghiti Signed-off-by: Samuel Holland Link: https://lore.kernel.org/r/20240327045035.368512-5-samuel.holland@sifive.com Signed-off-by: Palmer Dabbelt --- arch/riscv/mm/tlbflush.c | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/arch/riscv/mm/tlbflush.c b/arch/riscv/mm/tlbflush.c index 0435605b07d0..da821315d43e 100644 --- a/arch/riscv/mm/tlbflush.c +++ b/arch/riscv/mm/tlbflush.c @@ -103,22 +103,15 @@ static void __flush_tlb_range(struct cpumask *cmask, unsigned long asid, unsigned long start, unsigned long size, unsigned long stride) { - bool broadcast; + unsigned int cpu; if (cpumask_empty(cmask)) return; - if (cmask != cpu_online_mask) { - unsigned int cpuid; + cpu = get_cpu(); - cpuid = get_cpu(); - /* check if the tlbflush needs to be sent to other CPUs */ - broadcast = cpumask_any_but(cmask, cpuid) < nr_cpu_ids; - } else { - broadcast = true; - } - - if (!broadcast) { + /* Check if the TLB flush needs to be sent to other CPUs. */ + if (cpumask_any_but(cmask, cpu) >= nr_cpu_ids) { local_flush_tlb_range_asid(start, size, stride, asid); } else if (riscv_use_sbi_for_rfence()) { sbi_remote_sfence_vma_asid(cmask, start, size, asid); @@ -132,8 +125,7 @@ static void __flush_tlb_range(struct cpumask *cmask, unsigned long asid, on_each_cpu_mask(cmask, __ipi_flush_tlb_range_asid, &ftd, 1); } - if (cmask != cpu_online_mask) - put_cpu(); + put_cpu(); } static inline unsigned long get_mm_asid(struct mm_struct *mm) -- cgit v1.2.3-59-g8ed1b From 9546f00410ed88b8117388cfd74ea59f4616a158 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Tue, 26 Mar 2024 21:49:46 -0700 Subject: riscv: Only send remote fences when some other CPU is online If no other CPU is online, a local cache or TLB flush is sufficient. These checks can be constant-folded when SMP is disabled. Signed-off-by: Samuel Holland Reviewed-by: Alexandre Ghiti Link: https://lore.kernel.org/r/20240327045035.368512-6-samuel.holland@sifive.com Signed-off-by: Palmer Dabbelt --- arch/riscv/mm/cacheflush.c | 4 +++- arch/riscv/mm/tlbflush.c | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/arch/riscv/mm/cacheflush.c b/arch/riscv/mm/cacheflush.c index d76fc73e594b..f5be1fec8191 100644 --- a/arch/riscv/mm/cacheflush.c +++ b/arch/riscv/mm/cacheflush.c @@ -21,7 +21,9 @@ void flush_icache_all(void) { local_flush_icache_all(); - if (riscv_use_sbi_for_rfence()) + if (num_online_cpus() < 2) + return; + else if (riscv_use_sbi_for_rfence()) sbi_remote_fence_i(NULL); else on_each_cpu(ipi_remote_fence_i, NULL, 1); diff --git a/arch/riscv/mm/tlbflush.c b/arch/riscv/mm/tlbflush.c index da821315d43e..0901aa47b58f 100644 --- a/arch/riscv/mm/tlbflush.c +++ b/arch/riscv/mm/tlbflush.c @@ -79,7 +79,9 @@ static void __ipi_flush_tlb_all(void *info) void flush_tlb_all(void) { - if (riscv_use_sbi_for_rfence()) + if (num_online_cpus() < 2) + local_flush_tlb_all(); + else if (riscv_use_sbi_for_rfence()) sbi_remote_sfence_vma_asid(NULL, 0, FLUSH_TLB_MAX_SIZE, FLUSH_TLB_NO_ASID); else on_each_cpu(__ipi_flush_tlb_all, NULL, 1); -- cgit v1.2.3-59-g8ed1b From c6026d35b6abb5bd954788478bfa800a942e2033 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Tue, 26 Mar 2024 21:49:47 -0700 Subject: riscv: mm: Combine the SMP and UP TLB flush code In SMP configurations, all TLB flushing narrower than flush_tlb_all() goes through __flush_tlb_range(). Do the same in UP configurations. This allows UP configurations to take advantage of recent improvements to the code in tlbflush.c, such as support for huge pages and flushing multiple-page ranges. Reviewed-by: Alexandre Ghiti Signed-off-by: Samuel Holland Reviewed-by: Yunhui Cui Link: https://lore.kernel.org/r/20240327045035.368512-7-samuel.holland@sifive.com Signed-off-by: Palmer Dabbelt --- arch/riscv/Kconfig | 2 +- arch/riscv/include/asm/tlbflush.h | 31 +++---------------------------- arch/riscv/mm/Makefile | 5 +---- 3 files changed, 5 insertions(+), 33 deletions(-) diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index be09c8836d56..442532819a44 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -60,7 +60,7 @@ config RISCV select ARCH_USE_MEMTEST select ARCH_USE_QUEUED_RWLOCKS select ARCH_USES_CFI_TRAPS if CFI_CLANG - select ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH if SMP && MMU + select ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH if MMU select ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT if MMU select ARCH_WANT_FRAME_POINTERS select ARCH_WANT_GENERAL_HUGETLB if !RISCV_ISA_SVNAPOT diff --git a/arch/riscv/include/asm/tlbflush.h b/arch/riscv/include/asm/tlbflush.h index 4112cc8d1d69..4f86424b1ba5 100644 --- a/arch/riscv/include/asm/tlbflush.h +++ b/arch/riscv/include/asm/tlbflush.h @@ -27,12 +27,7 @@ static inline void local_flush_tlb_page(unsigned long addr) { ALT_FLUSH_TLB_PAGE(__asm__ __volatile__ ("sfence.vma %0" : : "r" (addr) : "memory")); } -#else /* CONFIG_MMU */ -#define local_flush_tlb_all() do { } while (0) -#define local_flush_tlb_page(addr) do { } while (0) -#endif /* CONFIG_MMU */ -#if defined(CONFIG_SMP) && defined(CONFIG_MMU) void flush_tlb_all(void); void flush_tlb_mm(struct mm_struct *mm); void flush_tlb_mm_range(struct mm_struct *mm, unsigned long start, @@ -54,28 +49,8 @@ void arch_tlbbatch_add_pending(struct arch_tlbflush_unmap_batch *batch, unsigned long uaddr); void arch_flush_tlb_batched_pending(struct mm_struct *mm); void arch_tlbbatch_flush(struct arch_tlbflush_unmap_batch *batch); - -#else /* CONFIG_SMP && CONFIG_MMU */ - -#define flush_tlb_all() local_flush_tlb_all() -#define flush_tlb_page(vma, addr) local_flush_tlb_page(addr) - -static inline void flush_tlb_range(struct vm_area_struct *vma, - unsigned long start, unsigned long end) -{ - local_flush_tlb_all(); -} - -/* Flush a range of kernel pages */ -static inline void flush_tlb_kernel_range(unsigned long start, - unsigned long end) -{ - local_flush_tlb_all(); -} - -#define flush_tlb_mm(mm) flush_tlb_all() -#define flush_tlb_mm_range(mm, start, end, page_size) flush_tlb_all() -#define local_flush_tlb_kernel_range(start, end) flush_tlb_all() -#endif /* !CONFIG_SMP || !CONFIG_MMU */ +#else /* CONFIG_MMU */ +#define local_flush_tlb_all() do { } while (0) +#endif /* CONFIG_MMU */ #endif /* _ASM_RISCV_TLBFLUSH_H */ diff --git a/arch/riscv/mm/Makefile b/arch/riscv/mm/Makefile index 2c869f8026a8..cbe4d775ef56 100644 --- a/arch/riscv/mm/Makefile +++ b/arch/riscv/mm/Makefile @@ -13,14 +13,11 @@ endif KCOV_INSTRUMENT_init.o := n obj-y += init.o -obj-$(CONFIG_MMU) += extable.o fault.o pageattr.o pgtable.o +obj-$(CONFIG_MMU) += extable.o fault.o pageattr.o pgtable.o tlbflush.o obj-y += cacheflush.o obj-y += context.o obj-y += pmem.o -ifeq ($(CONFIG_MMU),y) -obj-$(CONFIG_SMP) += tlbflush.o -endif obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o obj-$(CONFIG_PTDUMP_CORE) += ptdump.o obj-$(CONFIG_KASAN) += kasan_init.o -- cgit v1.2.3-59-g8ed1b From 20e03d702e00a3e0269a1d6f9549c2e370492054 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Tue, 26 Mar 2024 21:49:48 -0700 Subject: riscv: Apply SiFive CIP-1200 workaround to single-ASID sfence.vma commit 3f1e782998cd ("riscv: add ASID-based tlbflushing methods") added calls to the sfence.vma instruction with rs2 != x0. These single-ASID instruction variants are also affected by SiFive errata CIP-1200. Until now, the errata workaround was not needed for the single-ASID sfence.vma variants, because they were only used when the ASID allocator was enabled, and the affected SiFive platforms do not support multiple ASIDs. However, we are going to start using those sfence.vma variants regardless of ASID support, so now we need alternatives covering them. Signed-off-by: Samuel Holland Link: https://lore.kernel.org/r/20240327045035.368512-8-samuel.holland@sifive.com Signed-off-by: Palmer Dabbelt --- arch/riscv/include/asm/errata_list.h | 12 +++++++++++- arch/riscv/include/asm/tlbflush.h | 19 ++++++++++++++++++- arch/riscv/mm/tlbflush.c | 23 ----------------------- 3 files changed, 29 insertions(+), 25 deletions(-) diff --git a/arch/riscv/include/asm/errata_list.h b/arch/riscv/include/asm/errata_list.h index 1f2dbfb8a8bf..35ce26899960 100644 --- a/arch/riscv/include/asm/errata_list.h +++ b/arch/riscv/include/asm/errata_list.h @@ -43,11 +43,21 @@ ALTERNATIVE(__stringify(RISCV_PTR do_page_fault), \ CONFIG_ERRATA_SIFIVE_CIP_453) #else /* !__ASSEMBLY__ */ -#define ALT_FLUSH_TLB_PAGE(x) \ +#define ALT_SFENCE_VMA_ASID(asid) \ +asm(ALTERNATIVE("sfence.vma x0, %0", "sfence.vma", SIFIVE_VENDOR_ID, \ + ERRATA_SIFIVE_CIP_1200, CONFIG_ERRATA_SIFIVE_CIP_1200) \ + : : "r" (asid) : "memory") + +#define ALT_SFENCE_VMA_ADDR(addr) \ asm(ALTERNATIVE("sfence.vma %0", "sfence.vma", SIFIVE_VENDOR_ID, \ ERRATA_SIFIVE_CIP_1200, CONFIG_ERRATA_SIFIVE_CIP_1200) \ : : "r" (addr) : "memory") +#define ALT_SFENCE_VMA_ADDR_ASID(addr, asid) \ +asm(ALTERNATIVE("sfence.vma %0, %1", "sfence.vma", SIFIVE_VENDOR_ID, \ + ERRATA_SIFIVE_CIP_1200, CONFIG_ERRATA_SIFIVE_CIP_1200) \ + : : "r" (addr), "r" (asid) : "memory") + /* * _val is marked as "will be overwritten", so need to set it to 0 * in the default case. diff --git a/arch/riscv/include/asm/tlbflush.h b/arch/riscv/include/asm/tlbflush.h index 4f86424b1ba5..463b615d7728 100644 --- a/arch/riscv/include/asm/tlbflush.h +++ b/arch/riscv/include/asm/tlbflush.h @@ -22,10 +22,27 @@ static inline void local_flush_tlb_all(void) __asm__ __volatile__ ("sfence.vma" : : : "memory"); } +static inline void local_flush_tlb_all_asid(unsigned long asid) +{ + if (asid != FLUSH_TLB_NO_ASID) + ALT_SFENCE_VMA_ASID(asid); + else + local_flush_tlb_all(); +} + /* Flush one page from local TLB */ static inline void local_flush_tlb_page(unsigned long addr) { - ALT_FLUSH_TLB_PAGE(__asm__ __volatile__ ("sfence.vma %0" : : "r" (addr) : "memory")); + ALT_SFENCE_VMA_ADDR(addr); +} + +static inline void local_flush_tlb_page_asid(unsigned long addr, + unsigned long asid) +{ + if (asid != FLUSH_TLB_NO_ASID) + ALT_SFENCE_VMA_ADDR_ASID(addr, asid); + else + local_flush_tlb_page(addr); } void flush_tlb_all(void); diff --git a/arch/riscv/mm/tlbflush.c b/arch/riscv/mm/tlbflush.c index 0901aa47b58f..ad7bdcfcc219 100644 --- a/arch/riscv/mm/tlbflush.c +++ b/arch/riscv/mm/tlbflush.c @@ -7,29 +7,6 @@ #include #include -static inline void local_flush_tlb_all_asid(unsigned long asid) -{ - if (asid != FLUSH_TLB_NO_ASID) - __asm__ __volatile__ ("sfence.vma x0, %0" - : - : "r" (asid) - : "memory"); - else - local_flush_tlb_all(); -} - -static inline void local_flush_tlb_page_asid(unsigned long addr, - unsigned long asid) -{ - if (asid != FLUSH_TLB_NO_ASID) - __asm__ __volatile__ ("sfence.vma %0, %1" - : - : "r" (addr), "r" (asid) - : "memory"); - else - local_flush_tlb_page(addr); -} - /* * Flush entire TLB if number of entries to be flushed is greater * than the threshold below. -- cgit v1.2.3-59-g8ed1b From d6dcdabafcd7c612b164079d00da6d9775863a0b Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Tue, 26 Mar 2024 21:49:49 -0700 Subject: riscv: Avoid TLB flush loops when affected by SiFive CIP-1200 Implementations affected by SiFive errata CIP-1200 have a bug which forces the kernel to always use the global variant of the sfence.vma instruction. When affected by this errata, do not attempt to flush a range of addresses; each iteration of the loop would actually flush the whole TLB instead. Instead, minimize the overall number of sfence.vma instructions. Signed-off-by: Samuel Holland Reviewed-by: Yunhui Cui Link: https://lore.kernel.org/r/20240327045035.368512-9-samuel.holland@sifive.com Signed-off-by: Palmer Dabbelt --- arch/riscv/errata/sifive/errata.c | 5 +++++ arch/riscv/include/asm/tlbflush.h | 2 ++ arch/riscv/mm/tlbflush.c | 2 +- 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/arch/riscv/errata/sifive/errata.c b/arch/riscv/errata/sifive/errata.c index 3d9a32d791f7..716cfedad3a2 100644 --- a/arch/riscv/errata/sifive/errata.c +++ b/arch/riscv/errata/sifive/errata.c @@ -42,6 +42,11 @@ static bool errata_cip_1200_check_func(unsigned long arch_id, unsigned long imp return false; if ((impid & 0xffffff) > 0x200630 || impid == 0x1200626) return false; + +#ifdef CONFIG_MMU + tlb_flush_all_threshold = 0; +#endif + return true; } diff --git a/arch/riscv/include/asm/tlbflush.h b/arch/riscv/include/asm/tlbflush.h index 463b615d7728..8e329721375b 100644 --- a/arch/riscv/include/asm/tlbflush.h +++ b/arch/riscv/include/asm/tlbflush.h @@ -66,6 +66,8 @@ void arch_tlbbatch_add_pending(struct arch_tlbflush_unmap_batch *batch, unsigned long uaddr); void arch_flush_tlb_batched_pending(struct mm_struct *mm); void arch_tlbbatch_flush(struct arch_tlbflush_unmap_batch *batch); + +extern unsigned long tlb_flush_all_threshold; #else /* CONFIG_MMU */ #define local_flush_tlb_all() do { } while (0) #endif /* CONFIG_MMU */ diff --git a/arch/riscv/mm/tlbflush.c b/arch/riscv/mm/tlbflush.c index ad7bdcfcc219..18af7b5053af 100644 --- a/arch/riscv/mm/tlbflush.c +++ b/arch/riscv/mm/tlbflush.c @@ -11,7 +11,7 @@ * Flush entire TLB if number of entries to be flushed is greater * than the threshold below. */ -static unsigned long tlb_flush_all_threshold __read_mostly = 64; +unsigned long tlb_flush_all_threshold __read_mostly = 64; static void local_flush_tlb_range_threshold_asid(unsigned long start, unsigned long size, -- cgit v1.2.3-59-g8ed1b From 74cd17792d28162fe692d5a25fe5cc081203ad19 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Tue, 26 Mar 2024 21:49:50 -0700 Subject: riscv: mm: Introduce cntx2asid/cntx2version helper macros When using the ASID allocator, the MM context ID contains two values: the ASID in the lower bits, and the allocator version number in the remaining bits. Use macros to make this separation more obvious. Reviewed-by: Alexandre Ghiti Signed-off-by: Samuel Holland Link: https://lore.kernel.org/r/20240327045035.368512-10-samuel.holland@sifive.com Signed-off-by: Palmer Dabbelt --- arch/riscv/include/asm/mmu.h | 3 +++ arch/riscv/mm/context.c | 12 ++++++------ arch/riscv/mm/tlbflush.c | 2 +- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/arch/riscv/include/asm/mmu.h b/arch/riscv/include/asm/mmu.h index 355504b37f8e..a550fbf770be 100644 --- a/arch/riscv/include/asm/mmu.h +++ b/arch/riscv/include/asm/mmu.h @@ -26,6 +26,9 @@ typedef struct { #endif } mm_context_t; +#define cntx2asid(cntx) ((cntx) & asid_mask) +#define cntx2version(cntx) ((cntx) & ~asid_mask) + void __init create_pgd_mapping(pgd_t *pgdp, uintptr_t va, phys_addr_t pa, phys_addr_t sz, pgprot_t prot); #endif /* __ASSEMBLY__ */ diff --git a/arch/riscv/mm/context.c b/arch/riscv/mm/context.c index ba8eb3944687..b562b3c44487 100644 --- a/arch/riscv/mm/context.c +++ b/arch/riscv/mm/context.c @@ -81,7 +81,7 @@ static void __flush_context(void) if (cntx == 0) cntx = per_cpu(reserved_context, i); - __set_bit(cntx & asid_mask, context_asid_map); + __set_bit(cntx2asid(cntx), context_asid_map); per_cpu(reserved_context, i) = cntx; } @@ -102,7 +102,7 @@ static unsigned long __new_context(struct mm_struct *mm) lockdep_assert_held(&context_lock); if (cntx != 0) { - unsigned long newcntx = ver | (cntx & asid_mask); + unsigned long newcntx = ver | cntx2asid(cntx); /* * If our current CONTEXT was active during a rollover, we @@ -115,7 +115,7 @@ static unsigned long __new_context(struct mm_struct *mm) * We had a valid CONTEXT in a previous life, so try to * re-use it if possible. */ - if (!__test_and_set_bit(cntx & asid_mask, context_asid_map)) + if (!__test_and_set_bit(cntx2asid(cntx), context_asid_map)) return newcntx; } @@ -168,7 +168,7 @@ static void set_mm_asid(struct mm_struct *mm, unsigned int cpu) */ old_active_cntx = atomic_long_read(&per_cpu(active_context, cpu)); if (old_active_cntx && - ((cntx & ~asid_mask) == atomic_long_read(¤t_version)) && + (cntx2version(cntx) == atomic_long_read(¤t_version)) && atomic_long_cmpxchg_relaxed(&per_cpu(active_context, cpu), old_active_cntx, cntx)) goto switch_mm_fast; @@ -177,7 +177,7 @@ static void set_mm_asid(struct mm_struct *mm, unsigned int cpu) /* Check that our ASID belongs to the current_version. */ cntx = atomic_long_read(&mm->context.id); - if ((cntx & ~asid_mask) != atomic_long_read(¤t_version)) { + if (cntx2version(cntx) != atomic_long_read(¤t_version)) { cntx = __new_context(mm); atomic_long_set(&mm->context.id, cntx); } @@ -191,7 +191,7 @@ static void set_mm_asid(struct mm_struct *mm, unsigned int cpu) switch_mm_fast: csr_write(CSR_SATP, virt_to_pfn(mm->pgd) | - ((cntx & asid_mask) << SATP_ASID_SHIFT) | + (cntx2asid(cntx) << SATP_ASID_SHIFT) | satp_mode); if (need_flush_tlb) diff --git a/arch/riscv/mm/tlbflush.c b/arch/riscv/mm/tlbflush.c index 18af7b5053af..35266dd9a9a2 100644 --- a/arch/riscv/mm/tlbflush.c +++ b/arch/riscv/mm/tlbflush.c @@ -110,7 +110,7 @@ static void __flush_tlb_range(struct cpumask *cmask, unsigned long asid, static inline unsigned long get_mm_asid(struct mm_struct *mm) { return static_branch_unlikely(&use_asid_allocator) ? - atomic_long_read(&mm->context.id) & asid_mask : FLUSH_TLB_NO_ASID; + cntx2asid(atomic_long_read(&mm->context.id)) : FLUSH_TLB_NO_ASID; } void flush_tlb_mm(struct mm_struct *mm) -- cgit v1.2.3-59-g8ed1b From f58e5dc45fa93a2f2a0028381b2e06fe74ae9e2c Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Tue, 26 Mar 2024 21:49:51 -0700 Subject: riscv: mm: Use a fixed layout for the MM context ID Currently, the size of the ASID field in the MM context ID dynamically depends on the number of hardware-supported ASID bits. This requires reading a global variable to extract either field from the context ID. Instead, allocate the maximum possible number of bits to the ASID field, so the layout of the context ID is known at compile-time. Reviewed-by: Alexandre Ghiti Signed-off-by: Samuel Holland Link: https://lore.kernel.org/r/20240327045035.368512-11-samuel.holland@sifive.com Signed-off-by: Palmer Dabbelt --- arch/riscv/include/asm/mmu.h | 4 ++-- arch/riscv/include/asm/tlbflush.h | 2 -- arch/riscv/mm/context.c | 6 ++---- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/arch/riscv/include/asm/mmu.h b/arch/riscv/include/asm/mmu.h index a550fbf770be..dc0273f7905f 100644 --- a/arch/riscv/include/asm/mmu.h +++ b/arch/riscv/include/asm/mmu.h @@ -26,8 +26,8 @@ typedef struct { #endif } mm_context_t; -#define cntx2asid(cntx) ((cntx) & asid_mask) -#define cntx2version(cntx) ((cntx) & ~asid_mask) +#define cntx2asid(cntx) ((cntx) & SATP_ASID_MASK) +#define cntx2version(cntx) ((cntx) & ~SATP_ASID_MASK) void __init create_pgd_mapping(pgd_t *pgdp, uintptr_t va, phys_addr_t pa, phys_addr_t sz, pgprot_t prot); diff --git a/arch/riscv/include/asm/tlbflush.h b/arch/riscv/include/asm/tlbflush.h index 8e329721375b..72e559934952 100644 --- a/arch/riscv/include/asm/tlbflush.h +++ b/arch/riscv/include/asm/tlbflush.h @@ -15,8 +15,6 @@ #define FLUSH_TLB_NO_ASID ((unsigned long)-1) #ifdef CONFIG_MMU -extern unsigned long asid_mask; - static inline void local_flush_tlb_all(void) { __asm__ __volatile__ ("sfence.vma" : : : "memory"); diff --git a/arch/riscv/mm/context.c b/arch/riscv/mm/context.c index b562b3c44487..5315af06cd4d 100644 --- a/arch/riscv/mm/context.c +++ b/arch/riscv/mm/context.c @@ -22,7 +22,6 @@ DEFINE_STATIC_KEY_FALSE(use_asid_allocator); static unsigned long asid_bits; static unsigned long num_asids; -unsigned long asid_mask; static atomic_long_t current_version; @@ -128,7 +127,7 @@ static unsigned long __new_context(struct mm_struct *mm) goto set_asid; /* We're out of ASIDs, so increment current_version */ - ver = atomic_long_add_return_relaxed(num_asids, ¤t_version); + ver = atomic_long_add_return_relaxed(BIT(SATP_ASID_BITS), ¤t_version); /* Flush everything */ __flush_context(); @@ -247,7 +246,6 @@ static int __init asids_init(void) /* Pre-compute ASID details */ if (asid_bits) { num_asids = 1 << asid_bits; - asid_mask = num_asids - 1; } /* @@ -255,7 +253,7 @@ static int __init asids_init(void) * at-least twice more than CPUs */ if (num_asids > (2 * num_possible_cpus())) { - atomic_long_set(¤t_version, num_asids); + atomic_long_set(¤t_version, BIT(SATP_ASID_BITS)); context_asid_map = bitmap_zalloc(num_asids, GFP_KERNEL); if (!context_asid_map) -- cgit v1.2.3-59-g8ed1b From 8d3e7613f97e4c117467be126d9c0013e9937f77 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Tue, 26 Mar 2024 21:49:52 -0700 Subject: riscv: mm: Make asid_bits a local variable This variable is only used inside asids_init(). Reviewed-by: Alexandre Ghiti Signed-off-by: Samuel Holland Link: https://lore.kernel.org/r/20240327045035.368512-12-samuel.holland@sifive.com Signed-off-by: Palmer Dabbelt --- arch/riscv/mm/context.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/riscv/mm/context.c b/arch/riscv/mm/context.c index 5315af06cd4d..0bf6d0070a14 100644 --- a/arch/riscv/mm/context.c +++ b/arch/riscv/mm/context.c @@ -20,7 +20,6 @@ DEFINE_STATIC_KEY_FALSE(use_asid_allocator); -static unsigned long asid_bits; static unsigned long num_asids; static atomic_long_t current_version; @@ -226,7 +225,7 @@ static inline void set_mm(struct mm_struct *prev, static int __init asids_init(void) { - unsigned long old; + unsigned long asid_bits, old; /* Figure-out number of ASID bits in HW */ old = csr_read(CSR_SATP); -- cgit v1.2.3-59-g8ed1b From 8fc21cc672e8ea7954fdc6b59d9ce350730e9c92 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Tue, 26 Mar 2024 21:49:53 -0700 Subject: riscv: mm: Preserve global TLB entries when switching contexts If the CPU does not support multiple ASIDs, all MM contexts use ASID 0. In this case, it is still beneficial to flush the TLB by ASID, as the single-ASID variant of the sfence.vma instruction preserves TLB entries for global (kernel) pages. This optimization is recommended by the RISC-V privileged specification: If the implementation does not provide ASIDs, or software chooses to always use ASID 0, then after every satp write, software should execute SFENCE.VMA with rs1=x0. In the common case that no global translations have been modified, rs2 should be set to a register other than x0 but which contains the value zero, so that global translations are not flushed. It is not possible to apply this optimization when using the ASID allocator, because that code must flush the TLB for all ASIDs at once when incrementing the version number. Reviewed-by: Alexandre Ghiti Signed-off-by: Samuel Holland Link: https://lore.kernel.org/r/20240327045035.368512-13-samuel.holland@sifive.com Signed-off-by: Palmer Dabbelt --- arch/riscv/mm/context.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/riscv/mm/context.c b/arch/riscv/mm/context.c index 0bf6d0070a14..60cb0b82240e 100644 --- a/arch/riscv/mm/context.c +++ b/arch/riscv/mm/context.c @@ -200,7 +200,7 @@ static void set_mm_noasid(struct mm_struct *mm) { /* Switch the page table and blindly nuke entire local TLB */ csr_write(CSR_SATP, virt_to_pfn(mm->pgd) | satp_mode); - local_flush_tlb_all(); + local_flush_tlb_all_asid(0); } static inline void set_mm(struct mm_struct *prev, -- cgit v1.2.3-59-g8ed1b From daef19263fc102551d734f39d9ad417098ffb360 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Tue, 26 Mar 2024 21:49:54 -0700 Subject: riscv: mm: Always use an ASID to flush mm contexts Even if multiple ASIDs are not supported, using the single-ASID variant of the sfence.vma instruction preserves TLB entries for global (kernel) pages. So it is always more efficient to use the single-ASID code path. Reviewed-by: Alexandre Ghiti Signed-off-by: Samuel Holland Link: https://lore.kernel.org/r/20240327045035.368512-14-samuel.holland@sifive.com Signed-off-by: Palmer Dabbelt --- arch/riscv/mm/tlbflush.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/riscv/mm/tlbflush.c b/arch/riscv/mm/tlbflush.c index 35266dd9a9a2..44e7ed4e194f 100644 --- a/arch/riscv/mm/tlbflush.c +++ b/arch/riscv/mm/tlbflush.c @@ -109,8 +109,7 @@ static void __flush_tlb_range(struct cpumask *cmask, unsigned long asid, static inline unsigned long get_mm_asid(struct mm_struct *mm) { - return static_branch_unlikely(&use_asid_allocator) ? - cntx2asid(atomic_long_read(&mm->context.id)) : FLUSH_TLB_NO_ASID; + return cntx2asid(atomic_long_read(&mm->context.id)); } void flush_tlb_mm(struct mm_struct *mm) -- cgit v1.2.3-59-g8ed1b From bb208810b1abf1c84870cfbe1cc9cf1a1d35c607 Mon Sep 17 00:00:00 2001 From: Xin Zeng Date: Fri, 26 Apr 2024 14:40:51 +0800 Subject: vfio/qat: Add vfio_pci driver for Intel QAT SR-IOV VF devices Add vfio pci variant driver for Intel QAT SR-IOV VF devices. This driver registers to the vfio subsystem through the interfaces exposed by the subsystem. It follows the live migration protocol v2 defined in uapi/linux/vfio.h and interacts with Intel QAT PF driver through a set of interfaces defined in qat/qat_mig_dev.h to support live migration of Intel QAT VF devices. This version only covers migration for Intel QAT GEN4 VF devices. Co-developed-by: Yahui Cao Signed-off-by: Yahui Cao Signed-off-by: Xin Zeng Reviewed-by: Giovanni Cabiddu Reviewed-by: Kevin Tian Link: https://lore.kernel.org/r/20240426064051.2859652-1-xin.zeng@intel.com Signed-off-by: Alex Williamson --- MAINTAINERS | 8 + drivers/vfio/pci/Kconfig | 2 + drivers/vfio/pci/Makefile | 2 + drivers/vfio/pci/qat/Kconfig | 12 + drivers/vfio/pci/qat/Makefile | 3 + drivers/vfio/pci/qat/main.c | 702 ++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 729 insertions(+) create mode 100644 drivers/vfio/pci/qat/Kconfig create mode 100644 drivers/vfio/pci/qat/Makefile create mode 100644 drivers/vfio/pci/qat/main.c diff --git a/MAINTAINERS b/MAINTAINERS index aa415ddc6c03..909d85678f79 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -23280,6 +23280,14 @@ L: kvm@vger.kernel.org S: Maintained F: drivers/vfio/platform/ +VFIO QAT PCI DRIVER +M: Xin Zeng +M: Giovanni Cabiddu +L: kvm@vger.kernel.org +L: qat-linux@intel.com +S: Supported +F: drivers/vfio/pci/qat/ + VFIO VIRTIO PCI DRIVER M: Yishai Hadas L: kvm@vger.kernel.org diff --git a/drivers/vfio/pci/Kconfig b/drivers/vfio/pci/Kconfig index 15821a2d77d2..bf50ffa10bde 100644 --- a/drivers/vfio/pci/Kconfig +++ b/drivers/vfio/pci/Kconfig @@ -69,4 +69,6 @@ source "drivers/vfio/pci/virtio/Kconfig" source "drivers/vfio/pci/nvgrace-gpu/Kconfig" +source "drivers/vfio/pci/qat/Kconfig" + endmenu diff --git a/drivers/vfio/pci/Makefile b/drivers/vfio/pci/Makefile index ce7a61f1d912..cf00c0a7e55c 100644 --- a/drivers/vfio/pci/Makefile +++ b/drivers/vfio/pci/Makefile @@ -17,3 +17,5 @@ obj-$(CONFIG_PDS_VFIO_PCI) += pds/ obj-$(CONFIG_VIRTIO_VFIO_PCI) += virtio/ obj-$(CONFIG_NVGRACE_GPU_VFIO_PCI) += nvgrace-gpu/ + +obj-$(CONFIG_QAT_VFIO_PCI) += qat/ diff --git a/drivers/vfio/pci/qat/Kconfig b/drivers/vfio/pci/qat/Kconfig new file mode 100644 index 000000000000..bf52cfa4b595 --- /dev/null +++ b/drivers/vfio/pci/qat/Kconfig @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-only +config QAT_VFIO_PCI + tristate "VFIO support for QAT VF PCI devices" + select VFIO_PCI_CORE + depends on CRYPTO_DEV_QAT_4XXX + help + This provides migration support for Intel(R) QAT Virtual Function + using the VFIO framework. + + To compile this as a module, choose M here: the module + will be called qat_vfio_pci. If you don't know what to do here, + say N. diff --git a/drivers/vfio/pci/qat/Makefile b/drivers/vfio/pci/qat/Makefile new file mode 100644 index 000000000000..5fe5c4ec19d3 --- /dev/null +++ b/drivers/vfio/pci/qat/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0-only +obj-$(CONFIG_QAT_VFIO_PCI) += qat_vfio_pci.o +qat_vfio_pci-y := main.o diff --git a/drivers/vfio/pci/qat/main.c b/drivers/vfio/pci/qat/main.c new file mode 100644 index 000000000000..e36740a282e7 --- /dev/null +++ b/drivers/vfio/pci/qat/main.c @@ -0,0 +1,702 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright(c) 2024 Intel Corporation */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * The migration data of each Intel QAT VF device is encapsulated into a + * 4096 bytes block. The data consists of two parts. + * The first is a pre-configured set of attributes of the VF being migrated, + * which are only set when it is created. This can be migrated during pre-copy + * stage and used for a device compatibility check. + * The second is the VF state. This includes the required MMIO regions and + * the shadow states maintained by the QAT PF driver. This part can only be + * saved when the VF is fully quiesced and be migrated during stop-copy stage. + * Both these 2 parts of data are saved in hierarchical structures including + * a preamble section and several raw state sections. + * When the pre-configured part of the migration data is fully retrieved from + * user space, the preamble section are used to validate the correctness of + * the data blocks and check the version compatibility. The raw state sections + * are then used to do a device compatibility check. + * When the device transits from RESUMING state, the VF states are extracted + * from the raw state sections of the VF state part of the migration data and + * then loaded into the device. + */ + +struct qat_vf_migration_file { + struct file *filp; + /* protects migration region context */ + struct mutex lock; + bool disabled; + struct qat_vf_core_device *qat_vdev; + ssize_t filled_size; +}; + +struct qat_vf_core_device { + struct vfio_pci_core_device core_device; + struct qat_mig_dev *mdev; + /* protects migration state */ + struct mutex state_mutex; + enum vfio_device_mig_state mig_state; + struct qat_vf_migration_file *resuming_migf; + struct qat_vf_migration_file *saving_migf; +}; + +static int qat_vf_pci_open_device(struct vfio_device *core_vdev) +{ + struct qat_vf_core_device *qat_vdev = + container_of(core_vdev, struct qat_vf_core_device, + core_device.vdev); + struct vfio_pci_core_device *vdev = &qat_vdev->core_device; + int ret; + + ret = vfio_pci_core_enable(vdev); + if (ret) + return ret; + + ret = qat_vfmig_open(qat_vdev->mdev); + if (ret) { + vfio_pci_core_disable(vdev); + return ret; + } + qat_vdev->mig_state = VFIO_DEVICE_STATE_RUNNING; + + vfio_pci_core_finish_enable(vdev); + + return 0; +} + +static void qat_vf_disable_fd(struct qat_vf_migration_file *migf) +{ + mutex_lock(&migf->lock); + migf->disabled = true; + migf->filp->f_pos = 0; + migf->filled_size = 0; + mutex_unlock(&migf->lock); +} + +static void qat_vf_disable_fds(struct qat_vf_core_device *qat_vdev) +{ + if (qat_vdev->resuming_migf) { + qat_vf_disable_fd(qat_vdev->resuming_migf); + fput(qat_vdev->resuming_migf->filp); + qat_vdev->resuming_migf = NULL; + } + + if (qat_vdev->saving_migf) { + qat_vf_disable_fd(qat_vdev->saving_migf); + fput(qat_vdev->saving_migf->filp); + qat_vdev->saving_migf = NULL; + } +} + +static void qat_vf_pci_close_device(struct vfio_device *core_vdev) +{ + struct qat_vf_core_device *qat_vdev = container_of(core_vdev, + struct qat_vf_core_device, core_device.vdev); + + qat_vfmig_close(qat_vdev->mdev); + qat_vf_disable_fds(qat_vdev); + vfio_pci_core_close_device(core_vdev); +} + +static long qat_vf_precopy_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + struct qat_vf_migration_file *migf = filp->private_data; + struct qat_vf_core_device *qat_vdev = migf->qat_vdev; + struct qat_mig_dev *mig_dev = qat_vdev->mdev; + struct vfio_precopy_info info; + loff_t *pos = &filp->f_pos; + unsigned long minsz; + int ret = 0; + + if (cmd != VFIO_MIG_GET_PRECOPY_INFO) + return -ENOTTY; + + minsz = offsetofend(struct vfio_precopy_info, dirty_bytes); + + if (copy_from_user(&info, (void __user *)arg, minsz)) + return -EFAULT; + if (info.argsz < minsz) + return -EINVAL; + + mutex_lock(&qat_vdev->state_mutex); + if (qat_vdev->mig_state != VFIO_DEVICE_STATE_PRE_COPY && + qat_vdev->mig_state != VFIO_DEVICE_STATE_PRE_COPY_P2P) { + mutex_unlock(&qat_vdev->state_mutex); + return -EINVAL; + } + + mutex_lock(&migf->lock); + if (migf->disabled) { + ret = -ENODEV; + goto out; + } + + if (*pos > mig_dev->setup_size) { + ret = -EINVAL; + goto out; + } + + info.dirty_bytes = 0; + info.initial_bytes = mig_dev->setup_size - *pos; + +out: + mutex_unlock(&migf->lock); + mutex_unlock(&qat_vdev->state_mutex); + if (ret) + return ret; + return copy_to_user((void __user *)arg, &info, minsz) ? -EFAULT : 0; +} + +static ssize_t qat_vf_save_read(struct file *filp, char __user *buf, + size_t len, loff_t *pos) +{ + struct qat_vf_migration_file *migf = filp->private_data; + struct qat_mig_dev *mig_dev = migf->qat_vdev->mdev; + ssize_t done = 0; + loff_t *offs; + int ret; + + if (pos) + return -ESPIPE; + offs = &filp->f_pos; + + mutex_lock(&migf->lock); + if (*offs > migf->filled_size || *offs < 0) { + done = -EINVAL; + goto out_unlock; + } + + if (migf->disabled) { + done = -ENODEV; + goto out_unlock; + } + + len = min_t(size_t, migf->filled_size - *offs, len); + if (len) { + ret = copy_to_user(buf, mig_dev->state + *offs, len); + if (ret) { + done = -EFAULT; + goto out_unlock; + } + *offs += len; + done = len; + } + +out_unlock: + mutex_unlock(&migf->lock); + return done; +} + +static int qat_vf_release_file(struct inode *inode, struct file *filp) +{ + struct qat_vf_migration_file *migf = filp->private_data; + + qat_vf_disable_fd(migf); + mutex_destroy(&migf->lock); + kfree(migf); + + return 0; +} + +static const struct file_operations qat_vf_save_fops = { + .owner = THIS_MODULE, + .read = qat_vf_save_read, + .unlocked_ioctl = qat_vf_precopy_ioctl, + .compat_ioctl = compat_ptr_ioctl, + .release = qat_vf_release_file, + .llseek = no_llseek, +}; + +static int qat_vf_save_state(struct qat_vf_core_device *qat_vdev, + struct qat_vf_migration_file *migf) +{ + int ret; + + ret = qat_vfmig_save_state(qat_vdev->mdev); + if (ret) + return ret; + migf->filled_size = qat_vdev->mdev->state_size; + + return 0; +} + +static int qat_vf_save_setup(struct qat_vf_core_device *qat_vdev, + struct qat_vf_migration_file *migf) +{ + int ret; + + ret = qat_vfmig_save_setup(qat_vdev->mdev); + if (ret) + return ret; + migf->filled_size = qat_vdev->mdev->setup_size; + + return 0; +} + +/* + * Allocate a file handler for user space and then save the migration data for + * the device being migrated. If this is called in the pre-copy stage, save the + * pre-configured device data. Otherwise, if this is called in the stop-copy + * stage, save the device state. In both cases, update the data size which can + * then be read from user space. + */ +static struct qat_vf_migration_file * +qat_vf_save_device_data(struct qat_vf_core_device *qat_vdev, bool pre_copy) +{ + struct qat_vf_migration_file *migf; + int ret; + + migf = kzalloc(sizeof(*migf), GFP_KERNEL); + if (!migf) + return ERR_PTR(-ENOMEM); + + migf->filp = anon_inode_getfile("qat_vf_mig", &qat_vf_save_fops, + migf, O_RDONLY); + ret = PTR_ERR_OR_ZERO(migf->filp); + if (ret) { + kfree(migf); + return ERR_PTR(ret); + } + + stream_open(migf->filp->f_inode, migf->filp); + mutex_init(&migf->lock); + + if (pre_copy) + ret = qat_vf_save_setup(qat_vdev, migf); + else + ret = qat_vf_save_state(qat_vdev, migf); + if (ret) { + fput(migf->filp); + return ERR_PTR(ret); + } + + migf->qat_vdev = qat_vdev; + + return migf; +} + +static ssize_t qat_vf_resume_write(struct file *filp, const char __user *buf, + size_t len, loff_t *pos) +{ + struct qat_vf_migration_file *migf = filp->private_data; + struct qat_mig_dev *mig_dev = migf->qat_vdev->mdev; + loff_t end, *offs; + ssize_t done = 0; + int ret; + + if (pos) + return -ESPIPE; + offs = &filp->f_pos; + + if (*offs < 0 || + check_add_overflow((loff_t)len, *offs, &end)) + return -EOVERFLOW; + + if (end > mig_dev->state_size) + return -ENOMEM; + + mutex_lock(&migf->lock); + if (migf->disabled) { + done = -ENODEV; + goto out_unlock; + } + + ret = copy_from_user(mig_dev->state + *offs, buf, len); + if (ret) { + done = -EFAULT; + goto out_unlock; + } + *offs += len; + migf->filled_size += len; + + /* + * Load the pre-configured device data first to check if the target + * device is compatible with the source device. + */ + ret = qat_vfmig_load_setup(mig_dev, migf->filled_size); + if (ret && ret != -EAGAIN) { + done = ret; + goto out_unlock; + } + done = len; + +out_unlock: + mutex_unlock(&migf->lock); + return done; +} + +static const struct file_operations qat_vf_resume_fops = { + .owner = THIS_MODULE, + .write = qat_vf_resume_write, + .release = qat_vf_release_file, + .llseek = no_llseek, +}; + +static struct qat_vf_migration_file * +qat_vf_resume_device_data(struct qat_vf_core_device *qat_vdev) +{ + struct qat_vf_migration_file *migf; + int ret; + + migf = kzalloc(sizeof(*migf), GFP_KERNEL); + if (!migf) + return ERR_PTR(-ENOMEM); + + migf->filp = anon_inode_getfile("qat_vf_mig", &qat_vf_resume_fops, migf, O_WRONLY); + ret = PTR_ERR_OR_ZERO(migf->filp); + if (ret) { + kfree(migf); + return ERR_PTR(ret); + } + + migf->qat_vdev = qat_vdev; + migf->filled_size = 0; + stream_open(migf->filp->f_inode, migf->filp); + mutex_init(&migf->lock); + + return migf; +} + +static int qat_vf_load_device_data(struct qat_vf_core_device *qat_vdev) +{ + return qat_vfmig_load_state(qat_vdev->mdev); +} + +static struct file *qat_vf_pci_step_device_state(struct qat_vf_core_device *qat_vdev, u32 new) +{ + u32 cur = qat_vdev->mig_state; + int ret; + + /* + * As the device is not capable of just stopping P2P DMAs, suspend the + * device completely once any of the P2P states are reached. + * When it is suspended, all its MMIO registers can still be operated + * correctly, jobs submitted through ring are queued while no jobs are + * processed by the device. The MMIO states can be safely migrated to + * the target VF during stop-copy stage and restored correctly in the + * target VF. All queued jobs can be resumed then. + */ + if ((cur == VFIO_DEVICE_STATE_RUNNING && new == VFIO_DEVICE_STATE_RUNNING_P2P) || + (cur == VFIO_DEVICE_STATE_PRE_COPY && new == VFIO_DEVICE_STATE_PRE_COPY_P2P)) { + ret = qat_vfmig_suspend(qat_vdev->mdev); + if (ret) + return ERR_PTR(ret); + return NULL; + } + + if ((cur == VFIO_DEVICE_STATE_RUNNING_P2P && new == VFIO_DEVICE_STATE_RUNNING) || + (cur == VFIO_DEVICE_STATE_PRE_COPY_P2P && new == VFIO_DEVICE_STATE_PRE_COPY)) { + qat_vfmig_resume(qat_vdev->mdev); + return NULL; + } + + if ((cur == VFIO_DEVICE_STATE_RUNNING_P2P && new == VFIO_DEVICE_STATE_STOP) || + (cur == VFIO_DEVICE_STATE_STOP && new == VFIO_DEVICE_STATE_RUNNING_P2P)) + return NULL; + + if (cur == VFIO_DEVICE_STATE_STOP && new == VFIO_DEVICE_STATE_STOP_COPY) { + struct qat_vf_migration_file *migf; + + migf = qat_vf_save_device_data(qat_vdev, false); + if (IS_ERR(migf)) + return ERR_CAST(migf); + get_file(migf->filp); + qat_vdev->saving_migf = migf; + return migf->filp; + } + + if (cur == VFIO_DEVICE_STATE_STOP && new == VFIO_DEVICE_STATE_RESUMING) { + struct qat_vf_migration_file *migf; + + migf = qat_vf_resume_device_data(qat_vdev); + if (IS_ERR(migf)) + return ERR_CAST(migf); + get_file(migf->filp); + qat_vdev->resuming_migf = migf; + return migf->filp; + } + + if ((cur == VFIO_DEVICE_STATE_STOP_COPY && new == VFIO_DEVICE_STATE_STOP) || + (cur == VFIO_DEVICE_STATE_PRE_COPY && new == VFIO_DEVICE_STATE_RUNNING) || + (cur == VFIO_DEVICE_STATE_PRE_COPY_P2P && new == VFIO_DEVICE_STATE_RUNNING_P2P)) { + qat_vf_disable_fds(qat_vdev); + return NULL; + } + + if ((cur == VFIO_DEVICE_STATE_RUNNING && new == VFIO_DEVICE_STATE_PRE_COPY) || + (cur == VFIO_DEVICE_STATE_RUNNING_P2P && new == VFIO_DEVICE_STATE_PRE_COPY_P2P)) { + struct qat_vf_migration_file *migf; + + migf = qat_vf_save_device_data(qat_vdev, true); + if (IS_ERR(migf)) + return ERR_CAST(migf); + get_file(migf->filp); + qat_vdev->saving_migf = migf; + return migf->filp; + } + + if (cur == VFIO_DEVICE_STATE_PRE_COPY_P2P && new == VFIO_DEVICE_STATE_STOP_COPY) { + struct qat_vf_migration_file *migf = qat_vdev->saving_migf; + + if (!migf) + return ERR_PTR(-EINVAL); + ret = qat_vf_save_state(qat_vdev, migf); + if (ret) + return ERR_PTR(ret); + return NULL; + } + + if (cur == VFIO_DEVICE_STATE_RESUMING && new == VFIO_DEVICE_STATE_STOP) { + ret = qat_vf_load_device_data(qat_vdev); + if (ret) + return ERR_PTR(ret); + + qat_vf_disable_fds(qat_vdev); + return NULL; + } + + /* vfio_mig_get_next_state() does not use arcs other than the above */ + WARN_ON(true); + return ERR_PTR(-EINVAL); +} + +static void qat_vf_reset_done(struct qat_vf_core_device *qat_vdev) +{ + qat_vdev->mig_state = VFIO_DEVICE_STATE_RUNNING; + qat_vfmig_reset(qat_vdev->mdev); + qat_vf_disable_fds(qat_vdev); +} + +static struct file *qat_vf_pci_set_device_state(struct vfio_device *vdev, + enum vfio_device_mig_state new_state) +{ + struct qat_vf_core_device *qat_vdev = container_of(vdev, + struct qat_vf_core_device, core_device.vdev); + enum vfio_device_mig_state next_state; + struct file *res = NULL; + int ret; + + mutex_lock(&qat_vdev->state_mutex); + while (new_state != qat_vdev->mig_state) { + ret = vfio_mig_get_next_state(vdev, qat_vdev->mig_state, + new_state, &next_state); + if (ret) { + res = ERR_PTR(ret); + break; + } + res = qat_vf_pci_step_device_state(qat_vdev, next_state); + if (IS_ERR(res)) + break; + qat_vdev->mig_state = next_state; + if (WARN_ON(res && new_state != qat_vdev->mig_state)) { + fput(res); + res = ERR_PTR(-EINVAL); + break; + } + } + mutex_unlock(&qat_vdev->state_mutex); + + return res; +} + +static int qat_vf_pci_get_device_state(struct vfio_device *vdev, + enum vfio_device_mig_state *curr_state) +{ + struct qat_vf_core_device *qat_vdev = container_of(vdev, + struct qat_vf_core_device, core_device.vdev); + + mutex_lock(&qat_vdev->state_mutex); + *curr_state = qat_vdev->mig_state; + mutex_unlock(&qat_vdev->state_mutex); + + return 0; +} + +static int qat_vf_pci_get_data_size(struct vfio_device *vdev, + unsigned long *stop_copy_length) +{ + struct qat_vf_core_device *qat_vdev = container_of(vdev, + struct qat_vf_core_device, core_device.vdev); + + mutex_lock(&qat_vdev->state_mutex); + *stop_copy_length = qat_vdev->mdev->state_size; + mutex_unlock(&qat_vdev->state_mutex); + + return 0; +} + +static const struct vfio_migration_ops qat_vf_pci_mig_ops = { + .migration_set_state = qat_vf_pci_set_device_state, + .migration_get_state = qat_vf_pci_get_device_state, + .migration_get_data_size = qat_vf_pci_get_data_size, +}; + +static void qat_vf_pci_release_dev(struct vfio_device *core_vdev) +{ + struct qat_vf_core_device *qat_vdev = container_of(core_vdev, + struct qat_vf_core_device, core_device.vdev); + + qat_vfmig_cleanup(qat_vdev->mdev); + qat_vfmig_destroy(qat_vdev->mdev); + mutex_destroy(&qat_vdev->state_mutex); + vfio_pci_core_release_dev(core_vdev); +} + +static int qat_vf_pci_init_dev(struct vfio_device *core_vdev) +{ + struct qat_vf_core_device *qat_vdev = container_of(core_vdev, + struct qat_vf_core_device, core_device.vdev); + struct qat_mig_dev *mdev; + struct pci_dev *parent; + int ret, vf_id; + + core_vdev->migration_flags = VFIO_MIGRATION_STOP_COPY | VFIO_MIGRATION_P2P | + VFIO_MIGRATION_PRE_COPY; + core_vdev->mig_ops = &qat_vf_pci_mig_ops; + + ret = vfio_pci_core_init_dev(core_vdev); + if (ret) + return ret; + + mutex_init(&qat_vdev->state_mutex); + + parent = pci_physfn(qat_vdev->core_device.pdev); + vf_id = pci_iov_vf_id(qat_vdev->core_device.pdev); + if (vf_id < 0) { + ret = -ENODEV; + goto err_rel; + } + + mdev = qat_vfmig_create(parent, vf_id); + if (IS_ERR(mdev)) { + ret = PTR_ERR(mdev); + goto err_rel; + } + + ret = qat_vfmig_init(mdev); + if (ret) + goto err_destroy; + + qat_vdev->mdev = mdev; + + return 0; + +err_destroy: + qat_vfmig_destroy(mdev); +err_rel: + vfio_pci_core_release_dev(core_vdev); + return ret; +} + +static const struct vfio_device_ops qat_vf_pci_ops = { + .name = "qat-vf-vfio-pci", + .init = qat_vf_pci_init_dev, + .release = qat_vf_pci_release_dev, + .open_device = qat_vf_pci_open_device, + .close_device = qat_vf_pci_close_device, + .ioctl = vfio_pci_core_ioctl, + .read = vfio_pci_core_read, + .write = vfio_pci_core_write, + .mmap = vfio_pci_core_mmap, + .request = vfio_pci_core_request, + .match = vfio_pci_core_match, + .bind_iommufd = vfio_iommufd_physical_bind, + .unbind_iommufd = vfio_iommufd_physical_unbind, + .attach_ioas = vfio_iommufd_physical_attach_ioas, + .detach_ioas = vfio_iommufd_physical_detach_ioas, +}; + +static struct qat_vf_core_device *qat_vf_drvdata(struct pci_dev *pdev) +{ + struct vfio_pci_core_device *core_device = pci_get_drvdata(pdev); + + return container_of(core_device, struct qat_vf_core_device, core_device); +} + +static void qat_vf_pci_aer_reset_done(struct pci_dev *pdev) +{ + struct qat_vf_core_device *qat_vdev = qat_vf_drvdata(pdev); + + if (!qat_vdev->mdev) + return; + + mutex_lock(&qat_vdev->state_mutex); + qat_vf_reset_done(qat_vdev); + mutex_unlock(&qat_vdev->state_mutex); +} + +static int +qat_vf_vfio_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + struct device *dev = &pdev->dev; + struct qat_vf_core_device *qat_vdev; + int ret; + + qat_vdev = vfio_alloc_device(qat_vf_core_device, core_device.vdev, dev, &qat_vf_pci_ops); + if (IS_ERR(qat_vdev)) + return PTR_ERR(qat_vdev); + + pci_set_drvdata(pdev, &qat_vdev->core_device); + ret = vfio_pci_core_register_device(&qat_vdev->core_device); + if (ret) + goto out_put_device; + + return 0; + +out_put_device: + vfio_put_device(&qat_vdev->core_device.vdev); + return ret; +} + +static void qat_vf_vfio_pci_remove(struct pci_dev *pdev) +{ + struct qat_vf_core_device *qat_vdev = qat_vf_drvdata(pdev); + + vfio_pci_core_unregister_device(&qat_vdev->core_device); + vfio_put_device(&qat_vdev->core_device.vdev); +} + +static const struct pci_device_id qat_vf_vfio_pci_table[] = { + /* Intel QAT GEN4 4xxx VF device */ + { PCI_DRIVER_OVERRIDE_DEVICE_VFIO(PCI_VENDOR_ID_INTEL, 0x4941) }, + { PCI_DRIVER_OVERRIDE_DEVICE_VFIO(PCI_VENDOR_ID_INTEL, 0x4943) }, + { PCI_DRIVER_OVERRIDE_DEVICE_VFIO(PCI_VENDOR_ID_INTEL, 0x4945) }, + {} +}; +MODULE_DEVICE_TABLE(pci, qat_vf_vfio_pci_table); + +static const struct pci_error_handlers qat_vf_err_handlers = { + .reset_done = qat_vf_pci_aer_reset_done, + .error_detected = vfio_pci_core_aer_err_detected, +}; + +static struct pci_driver qat_vf_vfio_pci_driver = { + .name = "qat_vfio_pci", + .id_table = qat_vf_vfio_pci_table, + .probe = qat_vf_vfio_pci_probe, + .remove = qat_vf_vfio_pci_remove, + .err_handler = &qat_vf_err_handlers, + .driver_managed_dma = true, +}; +module_pci_driver(qat_vf_vfio_pci_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Xin Zeng "); +MODULE_DESCRIPTION("QAT VFIO PCI - VFIO PCI driver with live migration support for Intel(R) QAT GEN4 device family"); +MODULE_IMPORT_NS(CRYPTO_QAT); -- cgit v1.2.3-59-g8ed1b From 427298c632952709a33f3205d489ac496ae5b003 Mon Sep 17 00:00:00 2001 From: Gabriel Schwartz Date: Fri, 26 Apr 2024 17:01:14 -0300 Subject: iio: adc: rtq6056: Use automated cleanup for mode handling in write_raw Using iio_device_claim_direct_scoped() to automate mode claim and release simplifies code flow and allows for straight-forward error handling with direct returns on errors. Signed-off-by: Gabriel Schwartz Reviewed-by: Marcelo Schmitt Reviewed-by: ChiYuan Huang Link: https://lore.kernel.org/r/20240426200118.20900-1-gschwartz@usp.br Signed-off-by: Jonathan Cameron --- drivers/iio/adc/rtq6056.c | 34 +++++++++++----------------------- 1 file changed, 11 insertions(+), 23 deletions(-) diff --git a/drivers/iio/adc/rtq6056.c b/drivers/iio/adc/rtq6056.c index a5464737e527..bcb129840908 100644 --- a/drivers/iio/adc/rtq6056.c +++ b/drivers/iio/adc/rtq6056.c @@ -520,32 +520,20 @@ static int rtq6056_adc_write_raw(struct iio_dev *indio_dev, { struct rtq6056_priv *priv = iio_priv(indio_dev); const struct richtek_dev_data *devdata = priv->devdata; - int ret; - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; - - switch (mask) { - case IIO_CHAN_INFO_SAMP_FREQ: - if (devdata->fixed_samp_freq) { - ret = -EINVAL; - break; + iio_device_claim_direct_scoped(return -EBUSY, indio_dev) { + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + if (devdata->fixed_samp_freq) + return -EINVAL; + return rtq6056_adc_set_samp_freq(priv, chan, val); + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + return devdata->set_average(priv, val); + default: + return -EINVAL; } - - ret = rtq6056_adc_set_samp_freq(priv, chan, val); - break; - case IIO_CHAN_INFO_OVERSAMPLING_RATIO: - ret = devdata->set_average(priv, val); - break; - default: - ret = -EINVAL; - break; } - - iio_device_release_direct_mode(indio_dev); - - return ret; + unreachable(); } static const char *rtq6056_channel_labels[RTQ6056_MAX_CHANNEL] = { -- cgit v1.2.3-59-g8ed1b From ef64a4ad8310620976bef97287285fa94799ccc0 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 25 Apr 2024 10:03:27 -0500 Subject: iio: adc: ad7266: don't set masklength The masklength field is marked as [INTERN] and should not be set by drivers, so remove the assignment in the ad7266 driver. __iio_device_register() will populate this field with the correct value. Signed-off-by: David Lechner Link: https://lore.kernel.org/r/20240425-b4-iio-masklength-cleanup-v1-1-d3d16318274d@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7266.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/iio/adc/ad7266.c b/drivers/iio/adc/ad7266.c index 468c2656d2be..353a97f9c086 100644 --- a/drivers/iio/adc/ad7266.c +++ b/drivers/iio/adc/ad7266.c @@ -371,7 +371,6 @@ static void ad7266_init_channels(struct iio_dev *indio_dev) indio_dev->channels = chan_info->channels; indio_dev->num_channels = chan_info->num_channels; indio_dev->available_scan_masks = chan_info->scan_masks; - indio_dev->masklength = chan_info->num_channels - 1; } static const char * const ad7266_gpio_labels[] = { -- cgit v1.2.3-59-g8ed1b From 75616d2e3c9ecb22e41c2bf455d1588ee05f02e2 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 25 Apr 2024 10:03:28 -0500 Subject: iio: adc: mxs-lradc-adc: don't set masklength The masklength field is marked as [INTERN] and should not be set by drivers, so remove the assignment in the mxs-lradc-adc driver. __iio_device_register() will populate this field with the correct value. Signed-off-by: David Lechner Link: https://lore.kernel.org/r/20240425-b4-iio-masklength-cleanup-v1-2-d3d16318274d@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/mxs-lradc-adc.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/iio/adc/mxs-lradc-adc.c b/drivers/iio/adc/mxs-lradc-adc.c index 2e60c10ee4ff..8c7b64e78dbb 100644 --- a/drivers/iio/adc/mxs-lradc-adc.c +++ b/drivers/iio/adc/mxs-lradc-adc.c @@ -724,7 +724,6 @@ static int mxs_lradc_adc_probe(struct platform_device *pdev) iio->dev.of_node = dev->parent->of_node; iio->info = &mxs_lradc_adc_iio_info; iio->modes = INDIO_DIRECT_MODE; - iio->masklength = LRADC_MAX_TOTAL_CHANS; if (lradc->soc == IMX23_LRADC) { iio->channels = mx23_lradc_chan_spec; -- cgit v1.2.3-59-g8ed1b From 79df437b5661b2f7e1c0bad097fd18c4e154bb94 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 25 Apr 2024 10:03:29 -0500 Subject: iio: buffer: initialize masklength accumulator to 0 Since masklength is marked as [INTERN], no drivers should assign it and the value will always be 0. Therefore, the local ml accumulator variable in iio_buffers_alloc_sysfs_and_mask() will always start out as 0. This changes the code to explicitly set ml to 0 to make it clear that drivers should not be trying to override the masklength field. Signed-off-by: David Lechner Link: https://lore.kernel.org/r/20240425-b4-iio-masklength-cleanup-v1-3-d3d16318274d@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/industrialio-buffer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c index 1d950a3e153b..cec58a604d73 100644 --- a/drivers/iio/industrialio-buffer.c +++ b/drivers/iio/industrialio-buffer.c @@ -1744,7 +1744,7 @@ int iio_buffers_alloc_sysfs_and_mask(struct iio_dev *indio_dev) channels = indio_dev->channels; if (channels) { - int ml = indio_dev->masklength; + int ml = 0; for (i = 0; i < indio_dev->num_channels; i++) ml = max(ml, channels[i].scan_index + 1); -- cgit v1.2.3-59-g8ed1b From 02eae0bb9538dc7dcb5a6bc2c3066bd6ca682969 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 25 Apr 2024 14:57:51 +0200 Subject: iio: core: Add iio_read_acpi_mount_matrix() helper function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ACPI "ROTM" rotation matrix parsing code atm is already duplicated between bmc150-accel-core.c and kxcjk-1013.c and a third user of this is coming. Add an iio_read_acpi_mount_matrix() helper function for this. The 2 existing copies of the code are identical, except that the kxcjk-1013.c has slightly better error logging. To new helper is a 1:1 copy of the kxcjk-1013.c version, the only change is the addition of a "char *acpi_method" parameter since some bmc150 dual-accel setups (360° hinges with 1 accel in kbd/base + 1 in display) declare both accels in a single ACPI device with 2 different method names for the 2 matrices. This new acpi_method parameter is not "const char *" because the pathname parameter to acpi_evaluate_object() is not const. The 2 existing copies of this function will be removed in further patches in this series. Acked-by: Rafael J. Wysocki Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20240425125754.76010-2-hdegoede@redhat.com Signed-off-by: Jonathan Cameron --- drivers/iio/Makefile | 1 + drivers/iio/industrialio-acpi.c | 85 +++++++++++++++++++++++++++++++++++++++++ include/linux/iio/iio.h | 13 +++++++ 3 files changed, 99 insertions(+) create mode 100644 drivers/iio/industrialio-acpi.c diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile index 0ba0e1521ba4..cb80ef837e84 100644 --- a/drivers/iio/Makefile +++ b/drivers/iio/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_IIO) += industrialio.o industrialio-y := industrialio-core.o industrialio-event.o inkern.o industrialio-$(CONFIG_IIO_BUFFER) += industrialio-buffer.o industrialio-$(CONFIG_IIO_TRIGGER) += industrialio-trigger.o +industrialio-$(CONFIG_ACPI) += industrialio-acpi.o obj-$(CONFIG_IIO_CONFIGFS) += industrialio-configfs.o obj-$(CONFIG_IIO_GTS_HELPER) += industrialio-gts-helper.o diff --git a/drivers/iio/industrialio-acpi.c b/drivers/iio/industrialio-acpi.c new file mode 100644 index 000000000000..981b75d40780 --- /dev/null +++ b/drivers/iio/industrialio-acpi.c @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* IIO ACPI helper functions */ + +#include +#include +#include +#include + +/** + * iio_read_acpi_mount_matrix() - Read accelerometer mount matrix info from ACPI + * @dev: Device structure + * @orientation: iio_mount_matrix struct to fill + * @acpi_method: ACPI method name to read the matrix from, usually "ROTM" + * + * Try to read the mount-matrix by calling the specified method on the device's + * ACPI firmware-node. If the device has no ACPI firmware-node; or the method + * does not exist then this will fail silently. This expects the method to + * return data in the ACPI "ROTM" format defined by Microsoft: + * https://learn.microsoft.com/en-us/windows-hardware/drivers/sensors/sensors-acpi-entries + * This is a Microsoft extension and not part of the official ACPI spec. + * The method name is configurable because some dual-accel setups define 2 mount + * matrices in a single ACPI device using separate "ROMK" and "ROMS" methods. + * + * Returns: true if the matrix was successfully, false otherwise. + */ +bool iio_read_acpi_mount_matrix(struct device *dev, + struct iio_mount_matrix *orientation, + char *acpi_method) +{ + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + struct acpi_device *adev = ACPI_COMPANION(dev); + char *str; + union acpi_object *obj, *elements; + acpi_status status; + int i, j, val[3]; + bool ret = false; + + if (!adev || !acpi_has_method(adev->handle, acpi_method)) + return false; + + status = acpi_evaluate_object(adev->handle, acpi_method, NULL, &buffer); + if (ACPI_FAILURE(status)) { + dev_err(dev, "Failed to get ACPI mount matrix: %d\n", status); + return false; + } + + obj = buffer.pointer; + if (obj->type != ACPI_TYPE_PACKAGE || obj->package.count != 3) { + dev_err(dev, "Unknown ACPI mount matrix package format\n"); + goto out_free_buffer; + } + + elements = obj->package.elements; + for (i = 0; i < 3; i++) { + if (elements[i].type != ACPI_TYPE_STRING) { + dev_err(dev, "Unknown ACPI mount matrix element format\n"); + goto out_free_buffer; + } + + str = elements[i].string.pointer; + if (sscanf(str, "%d %d %d", &val[0], &val[1], &val[2]) != 3) { + dev_err(dev, "Incorrect ACPI mount matrix string format\n"); + goto out_free_buffer; + } + + for (j = 0; j < 3; j++) { + switch (val[j]) { + case -1: str = "-1"; break; + case 0: str = "0"; break; + case 1: str = "1"; break; + default: + dev_err(dev, "Invalid value in ACPI mount matrix: %d\n", val[j]); + goto out_free_buffer; + } + orientation->rotation[i * 3 + j] = str; + } + } + + ret = true; + +out_free_buffer: + kfree(buffer.pointer); + return ret; +} +EXPORT_SYMBOL_GPL(iio_read_acpi_mount_matrix); diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h index e370a7bb3300..55e2b22086a1 100644 --- a/include/linux/iio/iio.h +++ b/include/linux/iio/iio.h @@ -788,6 +788,19 @@ static inline struct dentry *iio_get_debugfs_dentry(struct iio_dev *indio_dev) } #endif +#ifdef CONFIG_ACPI +bool iio_read_acpi_mount_matrix(struct device *dev, + struct iio_mount_matrix *orientation, + char *acpi_method); +#else +static inline bool iio_read_acpi_mount_matrix(struct device *dev, + struct iio_mount_matrix *orientation, + char *acpi_method) +{ + return false; +} +#endif + ssize_t iio_format_value(char *buf, unsigned int type, int size, int *vals); int iio_str_to_fixpoint(const char *str, int fract_mult, int *integer, -- cgit v1.2.3-59-g8ed1b From e074cc3080d507b3680160248bb5b450d7009efb Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 25 Apr 2024 14:57:52 +0200 Subject: iio: accel: kxcjk-1013: Use new iio_read_acpi_mount_matrix() helper Replace the duplicate ACPI "ROTM" data parsing code with the new shared iio_read_acpi_mount_matrix() helper. This also removes the limiting of the "ROTM" mount matrix to only ACPI devices with an ACPI HID (Hardware-ID) of "KIOX000A". If kxcjk-1013 ACPI devices with another HID have a ROTM method that should still be parsed and if the method is not there then iio_read_acpi_mount_matrix() will fail silently. Acked-by: Rafael J. Wysocki Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20240425125754.76010-3-hdegoede@redhat.com Signed-off-by: Jonathan Cameron --- drivers/iio/accel/kxcjk-1013.c | 80 +----------------------------------------- 1 file changed, 1 insertion(+), 79 deletions(-) diff --git a/drivers/iio/accel/kxcjk-1013.c b/drivers/iio/accel/kxcjk-1013.c index 126e8bdd6d0e..8280d2bef0a3 100644 --- a/drivers/iio/accel/kxcjk-1013.c +++ b/drivers/iio/accel/kxcjk-1013.c @@ -636,84 +636,6 @@ static int kxcjk1013_set_power_state(struct kxcjk1013_data *data, bool on) return 0; } -#ifdef CONFIG_ACPI -static bool kxj_acpi_orientation(struct device *dev, - struct iio_mount_matrix *orientation) -{ - struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; - struct acpi_device *adev = ACPI_COMPANION(dev); - char *str; - union acpi_object *obj, *elements; - acpi_status status; - int i, j, val[3]; - bool ret = false; - - if (!acpi_has_method(adev->handle, "ROTM")) - return false; - - status = acpi_evaluate_object(adev->handle, "ROTM", NULL, &buffer); - if (ACPI_FAILURE(status)) { - dev_err(dev, "Failed to get ACPI mount matrix: %d\n", status); - return false; - } - - obj = buffer.pointer; - if (obj->type != ACPI_TYPE_PACKAGE || obj->package.count != 3) { - dev_err(dev, "Unknown ACPI mount matrix package format\n"); - goto out_free_buffer; - } - - elements = obj->package.elements; - for (i = 0; i < 3; i++) { - if (elements[i].type != ACPI_TYPE_STRING) { - dev_err(dev, "Unknown ACPI mount matrix element format\n"); - goto out_free_buffer; - } - - str = elements[i].string.pointer; - if (sscanf(str, "%d %d %d", &val[0], &val[1], &val[2]) != 3) { - dev_err(dev, "Incorrect ACPI mount matrix string format\n"); - goto out_free_buffer; - } - - for (j = 0; j < 3; j++) { - switch (val[j]) { - case -1: str = "-1"; break; - case 0: str = "0"; break; - case 1: str = "1"; break; - default: - dev_err(dev, "Invalid value in ACPI mount matrix: %d\n", val[j]); - goto out_free_buffer; - } - orientation->rotation[i * 3 + j] = str; - } - } - - ret = true; - -out_free_buffer: - kfree(buffer.pointer); - return ret; -} - -static bool kxj1009_apply_acpi_orientation(struct device *dev, - struct iio_mount_matrix *orientation) -{ - struct acpi_device *adev = ACPI_COMPANION(dev); - - if (adev && acpi_dev_hid_uid_match(adev, "KIOX000A", NULL)) - return kxj_acpi_orientation(dev, orientation); - - return false; -} -#else -static bool kxj1009_apply_acpi_orientation(struct device *dev, - struct iio_mount_matrix *orientation) -{ - return false; -} -#endif - static int kxcjk1013_chip_update_thresholds(struct kxcjk1013_data *data) { int ret; @@ -1544,7 +1466,7 @@ static int kxcjk1013_probe(struct i2c_client *client) } else { data->active_high_intr = true; /* default polarity */ - if (!kxj1009_apply_acpi_orientation(&client->dev, &data->orientation)) { + if (!iio_read_acpi_mount_matrix(&client->dev, &data->orientation, "ROTM")) { ret = iio_read_mount_matrix(&client->dev, &data->orientation); if (ret) return ret; -- cgit v1.2.3-59-g8ed1b From dd3f40b53957541c04a9dceed178df38ddbe3447 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 25 Apr 2024 14:57:53 +0200 Subject: iio: bmc150-accel-core: Use iio_read_acpi_mount_matrix() helper Replace the duplicate ACPI "ROTM" data parsing code with the new shared iio_read_acpi_mount_matrix() helper. Acked-by: Rafael J. Wysocki Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20240425125754.76010-4-hdegoede@redhat.com Signed-off-by: Jonathan Cameron --- drivers/iio/accel/bmc150-accel-core.c | 44 ++--------------------------------- 1 file changed, 2 insertions(+), 42 deletions(-) diff --git a/drivers/iio/accel/bmc150-accel-core.c b/drivers/iio/accel/bmc150-accel-core.c index 110591804b4c..ae0cd48a3e29 100644 --- a/drivers/iio/accel/bmc150-accel-core.c +++ b/drivers/iio/accel/bmc150-accel-core.c @@ -386,13 +386,9 @@ static int bmc150_accel_set_power_state(struct bmc150_accel_data *data, bool on) static bool bmc150_apply_bosc0200_acpi_orientation(struct device *dev, struct iio_mount_matrix *orientation) { - struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; struct iio_dev *indio_dev = dev_get_drvdata(dev); struct acpi_device *adev = ACPI_COMPANION(dev); - char *name, *alt_name, *label, *str; - union acpi_object *obj, *elements; - acpi_status status; - int i, j, val[3]; + char *name, *alt_name, *label; if (strcmp(dev_name(dev), "i2c-BOSC0200:base") == 0) { alt_name = "ROMK"; @@ -411,43 +407,7 @@ static bool bmc150_apply_bosc0200_acpi_orientation(struct device *dev, return false; } - status = acpi_evaluate_object(adev->handle, name, NULL, &buffer); - if (ACPI_FAILURE(status)) { - dev_warn(dev, "Failed to get ACPI mount matrix: %d\n", status); - return false; - } - - obj = buffer.pointer; - if (obj->type != ACPI_TYPE_PACKAGE || obj->package.count != 3) - goto unknown_format; - - elements = obj->package.elements; - for (i = 0; i < 3; i++) { - if (elements[i].type != ACPI_TYPE_STRING) - goto unknown_format; - - str = elements[i].string.pointer; - if (sscanf(str, "%d %d %d", &val[0], &val[1], &val[2]) != 3) - goto unknown_format; - - for (j = 0; j < 3; j++) { - switch (val[j]) { - case -1: str = "-1"; break; - case 0: str = "0"; break; - case 1: str = "1"; break; - default: goto unknown_format; - } - orientation->rotation[i * 3 + j] = str; - } - } - - kfree(buffer.pointer); - return true; - -unknown_format: - dev_warn(dev, "Unknown ACPI mount matrix format, ignoring\n"); - kfree(buffer.pointer); - return false; + return iio_read_acpi_mount_matrix(dev, orientation, name); } static bool bmc150_apply_dual250e_acpi_orientation(struct device *dev, -- cgit v1.2.3-59-g8ed1b From 4a8e1e020a38009d3a352b1e4738f5c4dce70654 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 25 Apr 2024 14:57:54 +0200 Subject: iio: accel: mxc4005: Read orientation matrix from ACPI ROTM method Some devices use the semi-standard ACPI "ROTM" method to store the accelerometers orientation matrix. Add support for this using the new iio_read_acpi_mount_matrix() helper, if the helper fails to read the matrix fall back to iio_read_mount_matrix() which will try to get it from device-properties (devicetree) and if that fails it will fill the matrix with the identity matrix. Link: https://bugzilla.kernel.org/show_bug.cgi?id=218578 Acked-by: Rafael J. Wysocki Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20240425125754.76010-5-hdegoede@redhat.com Signed-off-by: Jonathan Cameron --- drivers/iio/accel/mxc4005.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/drivers/iio/accel/mxc4005.c b/drivers/iio/accel/mxc4005.c index 61839be501c2..34d0f7f3f664 100644 --- a/drivers/iio/accel/mxc4005.c +++ b/drivers/iio/accel/mxc4005.c @@ -56,6 +56,7 @@ struct mxc4005_data { struct mutex mutex; struct regmap *regmap; struct iio_trigger *dready_trig; + struct iio_mount_matrix orientation; /* Ensure timestamp is naturally aligned */ struct { __be16 chans[3]; @@ -259,6 +260,20 @@ static int mxc4005_write_raw(struct iio_dev *indio_dev, } } +static const struct iio_mount_matrix * +mxc4005_get_mount_matrix(const struct iio_dev *indio_dev, + const struct iio_chan_spec *chan) +{ + struct mxc4005_data *data = iio_priv(indio_dev); + + return &data->orientation; +} + +static const struct iio_chan_spec_ext_info mxc4005_ext_info[] = { + IIO_MOUNT_MATRIX(IIO_SHARED_BY_TYPE, mxc4005_get_mount_matrix), + { } +}; + static const struct iio_info mxc4005_info = { .read_raw = mxc4005_read_raw, .write_raw = mxc4005_write_raw, @@ -285,6 +300,7 @@ static const unsigned long mxc4005_scan_masks[] = { .shift = 4, \ .endianness = IIO_BE, \ }, \ + .ext_info = mxc4005_ext_info, \ } static const struct iio_chan_spec mxc4005_channels[] = { @@ -415,6 +431,12 @@ static int mxc4005_probe(struct i2c_client *client) mutex_init(&data->mutex); + if (!iio_read_acpi_mount_matrix(&client->dev, &data->orientation, "ROTM")) { + ret = iio_read_mount_matrix(&client->dev, &data->orientation); + if (ret) + return ret; + } + indio_dev->channels = mxc4005_channels; indio_dev->num_channels = ARRAY_SIZE(mxc4005_channels); indio_dev->available_scan_masks = mxc4005_scan_masks; -- cgit v1.2.3-59-g8ed1b From c19f273cae8ac785f83345f6eb2b2813d35ec148 Mon Sep 17 00:00:00 2001 From: Ramona Gradinariu Date: Wed, 24 Apr 2024 12:41:52 +0300 Subject: docs: iio: adis16475: fix device files tables Remove in_accel_calibbias_x and in_anglvel_calibbias_x device files description, as they do not exist and were added by mistake. Add correct naming for in_accel_y_calibbias and in_anglvel_y_calibbias device files and update their description. Fixes: 8243b2877eef ("docs: iio: add documentation for adis16475 driver") Signed-off-by: Ramona Gradinariu Link: https://lore.kernel.org/r/20240424094152.103667-2-ramona.gradinariu@analog.com Signed-off-by: Jonathan Cameron --- Documentation/iio/adis16475.rst | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/Documentation/iio/adis16475.rst b/Documentation/iio/adis16475.rst index 91cabb7d8d05..130f9e97cc17 100644 --- a/Documentation/iio/adis16475.rst +++ b/Documentation/iio/adis16475.rst @@ -66,11 +66,9 @@ specific device folder path ``/sys/bus/iio/devices/iio:deviceX``. +-------------------------------------------+----------------------------------------------------------+ | in_accel_x_calibbias | Calibration offset for the X-axis accelerometer channel. | +-------------------------------------------+----------------------------------------------------------+ -| in_accel_calibbias_x | x-axis acceleration offset correction | -+-------------------------------------------+----------------------------------------------------------+ | in_accel_x_raw | Raw X-axis accelerometer channel value. | +-------------------------------------------+----------------------------------------------------------+ -| in_accel_calibbias_y | y-axis acceleration offset correction | +| in_accel_y_calibbias | Calibration offset for the Y-axis accelerometer channel. | +-------------------------------------------+----------------------------------------------------------+ | in_accel_y_raw | Raw Y-axis accelerometer channel value. | +-------------------------------------------+----------------------------------------------------------+ @@ -94,11 +92,9 @@ specific device folder path ``/sys/bus/iio/devices/iio:deviceX``. +---------------------------------------+------------------------------------------------------+ | in_anglvel_x_calibbias | Calibration offset for the X-axis gyroscope channel. | +---------------------------------------+------------------------------------------------------+ -| in_anglvel_calibbias_x | x-axis gyroscope offset correction | -+---------------------------------------+------------------------------------------------------+ | in_anglvel_x_raw | Raw X-axis gyroscope channel value. | +---------------------------------------+------------------------------------------------------+ -| in_anglvel_calibbias_y | y-axis gyroscope offset correction | +| in_anglvel_y_calibbias | Calibration offset for the Y-axis gyroscope channel. | +---------------------------------------+------------------------------------------------------+ | in_anglvel_y_raw | Raw Y-axis gyroscope channel value. | +---------------------------------------+------------------------------------------------------+ -- cgit v1.2.3-59-g8ed1b From 62de5e3e31a863000beccc25d6fa65c6ac2cedb8 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 15 Apr 2024 17:18:52 +0300 Subject: iio: light: stk3310: Drop most likely fake ACPI ID The commit in question does not proove that ACPI ID exists. Quite likely it was a cargo cult addition while doint that for DT-based enumeration. Drop most likely fake ACPI ID. Googling for STK3335 gives no useful results in regard to DSDT. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240415141852.853490-1-andriy.shevchenko@linux.intel.com Signed-off-by: Jonathan Cameron --- drivers/iio/light/stk3310.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/iio/light/stk3310.c b/drivers/iio/light/stk3310.c index 7b71ad71d78d..08d471438175 100644 --- a/drivers/iio/light/stk3310.c +++ b/drivers/iio/light/stk3310.c @@ -693,7 +693,6 @@ MODULE_DEVICE_TABLE(i2c, stk3310_i2c_id); static const struct acpi_device_id stk3310_acpi_id[] = { {"STK3310", 0}, {"STK3311", 0}, - {"STK3335", 0}, {} }; -- cgit v1.2.3-59-g8ed1b From 3b0c13361298af009756d040176c8417c5f8146c Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Maneyrol Date: Mon, 22 Apr 2024 15:22:39 +0000 Subject: dt-bindings: iio: imu: add icm42686 inside inv_icm42600 Add bindings for ICM-42686-P chip supporting high FSRs. Signed-off-by: Jean-Baptiste Maneyrol Acked-by: Rob Herring (Arm) Link: https://lore.kernel.org/r/20240422152240.85974-2-inv.git-commit@tdk.com Signed-off-by: Jonathan Cameron --- Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml b/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml index 5e0bed2c45de..3769f8e8e98c 100644 --- a/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml +++ b/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml @@ -32,6 +32,7 @@ properties: - invensense,icm42605 - invensense,icm42622 - invensense,icm42631 + - invensense,icm42686 - invensense,icm42688 reg: -- cgit v1.2.3-59-g8ed1b From a1432b5b4f4c44473ee97152c2f356d372ccd45c Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Maneyrol Date: Mon, 22 Apr 2024 15:22:40 +0000 Subject: iio: imu: inv_icm42600: add support of ICM-42686-P Add ICM-42686-P chip supporting high FSRs (32G, 4000dps). Create accel and gyro iio device states with dynamic scales table set at device init. Signed-off-by: Jean-Baptiste Maneyrol Link: https://lore.kernel.org/r/20240422152240.85974-3-inv.git-commit@tdk.com Signed-off-by: Jonathan Cameron --- drivers/iio/imu/inv_icm42600/inv_icm42600.h | 35 +++++++++ drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c | 75 ++++++++++++++----- drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c | 15 ++-- drivers/iio/imu/inv_icm42600/inv_icm42600_core.c | 21 ++++++ drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c | 84 +++++++++++++++++----- drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c | 3 + drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c | 3 + 7 files changed, 193 insertions(+), 43 deletions(-) diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600.h b/drivers/iio/imu/inv_icm42600/inv_icm42600.h index 0566340b2660..c4ac91f6bafe 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600.h +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600.h @@ -13,6 +13,7 @@ #include #include #include +#include #include "inv_icm42600_buffer.h" @@ -21,6 +22,7 @@ enum inv_icm42600_chip { INV_CHIP_ICM42600, INV_CHIP_ICM42602, INV_CHIP_ICM42605, + INV_CHIP_ICM42686, INV_CHIP_ICM42622, INV_CHIP_ICM42688, INV_CHIP_ICM42631, @@ -57,6 +59,17 @@ enum inv_icm42600_gyro_fs { INV_ICM42600_GYRO_FS_15_625DPS, INV_ICM42600_GYRO_FS_NB, }; +enum inv_icm42686_gyro_fs { + INV_ICM42686_GYRO_FS_4000DPS, + INV_ICM42686_GYRO_FS_2000DPS, + INV_ICM42686_GYRO_FS_1000DPS, + INV_ICM42686_GYRO_FS_500DPS, + INV_ICM42686_GYRO_FS_250DPS, + INV_ICM42686_GYRO_FS_125DPS, + INV_ICM42686_GYRO_FS_62_5DPS, + INV_ICM42686_GYRO_FS_31_25DPS, + INV_ICM42686_GYRO_FS_NB, +}; /* accelerometer fullscale values */ enum inv_icm42600_accel_fs { @@ -66,6 +79,14 @@ enum inv_icm42600_accel_fs { INV_ICM42600_ACCEL_FS_2G, INV_ICM42600_ACCEL_FS_NB, }; +enum inv_icm42686_accel_fs { + INV_ICM42686_ACCEL_FS_32G, + INV_ICM42686_ACCEL_FS_16G, + INV_ICM42686_ACCEL_FS_8G, + INV_ICM42686_ACCEL_FS_4G, + INV_ICM42686_ACCEL_FS_2G, + INV_ICM42686_ACCEL_FS_NB, +}; /* ODR suffixed by LN or LP are Low-Noise or Low-Power mode only */ enum inv_icm42600_odr { @@ -151,6 +172,19 @@ struct inv_icm42600_state { } timestamp; }; + +/** + * struct inv_icm42600_sensor_state - sensor state variables + * @scales: table of scales. + * @scales_len: length (nb of items) of the scales table. + * @ts: timestamp module states. + */ +struct inv_icm42600_sensor_state { + const int *scales; + size_t scales_len; + struct inv_sensors_timestamp ts; +}; + /* Virtual register addresses: @bank on MSB (4 upper bits), @address on LSB */ /* Bank selection register, available in all banks */ @@ -304,6 +338,7 @@ struct inv_icm42600_state { #define INV_ICM42600_WHOAMI_ICM42600 0x40 #define INV_ICM42600_WHOAMI_ICM42602 0x41 #define INV_ICM42600_WHOAMI_ICM42605 0x42 +#define INV_ICM42600_WHOAMI_ICM42686 0x44 #define INV_ICM42600_WHOAMI_ICM42622 0x46 #define INV_ICM42600_WHOAMI_ICM42688 0x47 #define INV_ICM42600_WHOAMI_ICM42631 0x5C diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c index f67bd5a39beb..83d8504ebfff 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c @@ -99,7 +99,8 @@ static int inv_icm42600_accel_update_scan_mode(struct iio_dev *indio_dev, const unsigned long *scan_mask) { struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev); - struct inv_sensors_timestamp *ts = iio_priv(indio_dev); + struct inv_icm42600_sensor_state *accel_st = iio_priv(indio_dev); + struct inv_sensors_timestamp *ts = &accel_st->ts; struct inv_icm42600_sensor_conf conf = INV_ICM42600_SENSOR_CONF_INIT; unsigned int fifo_en = 0; unsigned int sleep_temp = 0; @@ -210,33 +211,54 @@ static const int inv_icm42600_accel_scale[] = { [2 * INV_ICM42600_ACCEL_FS_2G] = 0, [2 * INV_ICM42600_ACCEL_FS_2G + 1] = 598550, }; +static const int inv_icm42686_accel_scale[] = { + /* +/- 32G => 0.009576807 m/s-2 */ + [2 * INV_ICM42686_ACCEL_FS_32G] = 0, + [2 * INV_ICM42686_ACCEL_FS_32G + 1] = 9576807, + /* +/- 16G => 0.004788403 m/s-2 */ + [2 * INV_ICM42686_ACCEL_FS_16G] = 0, + [2 * INV_ICM42686_ACCEL_FS_16G + 1] = 4788403, + /* +/- 8G => 0.002394202 m/s-2 */ + [2 * INV_ICM42686_ACCEL_FS_8G] = 0, + [2 * INV_ICM42686_ACCEL_FS_8G + 1] = 2394202, + /* +/- 4G => 0.001197101 m/s-2 */ + [2 * INV_ICM42686_ACCEL_FS_4G] = 0, + [2 * INV_ICM42686_ACCEL_FS_4G + 1] = 1197101, + /* +/- 2G => 0.000598550 m/s-2 */ + [2 * INV_ICM42686_ACCEL_FS_2G] = 0, + [2 * INV_ICM42686_ACCEL_FS_2G + 1] = 598550, +}; -static int inv_icm42600_accel_read_scale(struct inv_icm42600_state *st, +static int inv_icm42600_accel_read_scale(struct iio_dev *indio_dev, int *val, int *val2) { + struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev); + struct inv_icm42600_sensor_state *accel_st = iio_priv(indio_dev); unsigned int idx; idx = st->conf.accel.fs; - *val = inv_icm42600_accel_scale[2 * idx]; - *val2 = inv_icm42600_accel_scale[2 * idx + 1]; + *val = accel_st->scales[2 * idx]; + *val2 = accel_st->scales[2 * idx + 1]; return IIO_VAL_INT_PLUS_NANO; } -static int inv_icm42600_accel_write_scale(struct inv_icm42600_state *st, +static int inv_icm42600_accel_write_scale(struct iio_dev *indio_dev, int val, int val2) { + struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev); + struct inv_icm42600_sensor_state *accel_st = iio_priv(indio_dev); struct device *dev = regmap_get_device(st->map); unsigned int idx; struct inv_icm42600_sensor_conf conf = INV_ICM42600_SENSOR_CONF_INIT; int ret; - for (idx = 0; idx < ARRAY_SIZE(inv_icm42600_accel_scale); idx += 2) { - if (val == inv_icm42600_accel_scale[idx] && - val2 == inv_icm42600_accel_scale[idx + 1]) + for (idx = 0; idx < accel_st->scales_len; idx += 2) { + if (val == accel_st->scales[idx] && + val2 == accel_st->scales[idx + 1]) break; } - if (idx >= ARRAY_SIZE(inv_icm42600_accel_scale)) + if (idx >= accel_st->scales_len) return -EINVAL; conf.fs = idx / 2; @@ -309,7 +331,8 @@ static int inv_icm42600_accel_write_odr(struct iio_dev *indio_dev, int val, int val2) { struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev); - struct inv_sensors_timestamp *ts = iio_priv(indio_dev); + struct inv_icm42600_sensor_state *accel_st = iio_priv(indio_dev); + struct inv_sensors_timestamp *ts = &accel_st->ts; struct device *dev = regmap_get_device(st->map); unsigned int idx; struct inv_icm42600_sensor_conf conf = INV_ICM42600_SENSOR_CONF_INIT; @@ -565,7 +588,7 @@ static int inv_icm42600_accel_read_raw(struct iio_dev *indio_dev, *val = data; return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: - return inv_icm42600_accel_read_scale(st, val, val2); + return inv_icm42600_accel_read_scale(indio_dev, val, val2); case IIO_CHAN_INFO_SAMP_FREQ: return inv_icm42600_accel_read_odr(st, val, val2); case IIO_CHAN_INFO_CALIBBIAS: @@ -580,14 +603,16 @@ static int inv_icm42600_accel_read_avail(struct iio_dev *indio_dev, const int **vals, int *type, int *length, long mask) { + struct inv_icm42600_sensor_state *accel_st = iio_priv(indio_dev); + if (chan->type != IIO_ACCEL) return -EINVAL; switch (mask) { case IIO_CHAN_INFO_SCALE: - *vals = inv_icm42600_accel_scale; + *vals = accel_st->scales; *type = IIO_VAL_INT_PLUS_NANO; - *length = ARRAY_SIZE(inv_icm42600_accel_scale); + *length = accel_st->scales_len; return IIO_AVAIL_LIST; case IIO_CHAN_INFO_SAMP_FREQ: *vals = inv_icm42600_accel_odr; @@ -618,7 +643,7 @@ static int inv_icm42600_accel_write_raw(struct iio_dev *indio_dev, ret = iio_device_claim_direct_mode(indio_dev); if (ret) return ret; - ret = inv_icm42600_accel_write_scale(st, val, val2); + ret = inv_icm42600_accel_write_scale(indio_dev, val, val2); iio_device_release_direct_mode(indio_dev); return ret; case IIO_CHAN_INFO_SAMP_FREQ: @@ -705,8 +730,8 @@ struct iio_dev *inv_icm42600_accel_init(struct inv_icm42600_state *st) { struct device *dev = regmap_get_device(st->map); const char *name; + struct inv_icm42600_sensor_state *accel_st; struct inv_sensors_timestamp_chip ts_chip; - struct inv_sensors_timestamp *ts; struct iio_dev *indio_dev; int ret; @@ -714,9 +739,21 @@ struct iio_dev *inv_icm42600_accel_init(struct inv_icm42600_state *st) if (!name) return ERR_PTR(-ENOMEM); - indio_dev = devm_iio_device_alloc(dev, sizeof(*ts)); + indio_dev = devm_iio_device_alloc(dev, sizeof(*accel_st)); if (!indio_dev) return ERR_PTR(-ENOMEM); + accel_st = iio_priv(indio_dev); + + switch (st->chip) { + case INV_CHIP_ICM42686: + accel_st->scales = inv_icm42686_accel_scale; + accel_st->scales_len = ARRAY_SIZE(inv_icm42686_accel_scale); + break; + default: + accel_st->scales = inv_icm42600_accel_scale; + accel_st->scales_len = ARRAY_SIZE(inv_icm42600_accel_scale); + break; + } /* * clock period is 32kHz (31250ns) @@ -725,8 +762,7 @@ struct iio_dev *inv_icm42600_accel_init(struct inv_icm42600_state *st) ts_chip.clock_period = 31250; ts_chip.jitter = 20; ts_chip.init_period = inv_icm42600_odr_to_period(st->conf.accel.odr); - ts = iio_priv(indio_dev); - inv_sensors_timestamp_init(ts, &ts_chip); + inv_sensors_timestamp_init(&accel_st->ts, &ts_chip); iio_device_set_drvdata(indio_dev, st); indio_dev->name = name; @@ -751,7 +787,8 @@ struct iio_dev *inv_icm42600_accel_init(struct inv_icm42600_state *st) int inv_icm42600_accel_parse_fifo(struct iio_dev *indio_dev) { struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev); - struct inv_sensors_timestamp *ts = iio_priv(indio_dev); + struct inv_icm42600_sensor_state *accel_st = iio_priv(indio_dev); + struct inv_sensors_timestamp *ts = &accel_st->ts; ssize_t i, size; unsigned int no; const void *accel, *gyro, *timestamp; diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c index b52f328fd26c..cfb4a41ab7c1 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c @@ -276,7 +276,8 @@ static int inv_icm42600_buffer_preenable(struct iio_dev *indio_dev) { struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev); struct device *dev = regmap_get_device(st->map); - struct inv_sensors_timestamp *ts = iio_priv(indio_dev); + struct inv_icm42600_sensor_state *sensor_st = iio_priv(indio_dev); + struct inv_sensors_timestamp *ts = &sensor_st->ts; pm_runtime_get_sync(dev); @@ -502,6 +503,8 @@ int inv_icm42600_buffer_fifo_read(struct inv_icm42600_state *st, int inv_icm42600_buffer_fifo_parse(struct inv_icm42600_state *st) { + struct inv_icm42600_sensor_state *gyro_st = iio_priv(st->indio_gyro); + struct inv_icm42600_sensor_state *accel_st = iio_priv(st->indio_accel); struct inv_sensors_timestamp *ts; int ret; @@ -509,7 +512,7 @@ int inv_icm42600_buffer_fifo_parse(struct inv_icm42600_state *st) return 0; /* handle gyroscope timestamp and FIFO data parsing */ - ts = iio_priv(st->indio_gyro); + ts = &gyro_st->ts; inv_sensors_timestamp_interrupt(ts, st->fifo.period, st->fifo.nb.total, st->fifo.nb.gyro, st->timestamp.gyro); if (st->fifo.nb.gyro > 0) { @@ -519,7 +522,7 @@ int inv_icm42600_buffer_fifo_parse(struct inv_icm42600_state *st) } /* handle accelerometer timestamp and FIFO data parsing */ - ts = iio_priv(st->indio_accel); + ts = &accel_st->ts; inv_sensors_timestamp_interrupt(ts, st->fifo.period, st->fifo.nb.total, st->fifo.nb.accel, st->timestamp.accel); if (st->fifo.nb.accel > 0) { @@ -534,6 +537,8 @@ int inv_icm42600_buffer_fifo_parse(struct inv_icm42600_state *st) int inv_icm42600_buffer_hwfifo_flush(struct inv_icm42600_state *st, unsigned int count) { + struct inv_icm42600_sensor_state *gyro_st = iio_priv(st->indio_gyro); + struct inv_icm42600_sensor_state *accel_st = iio_priv(st->indio_accel); struct inv_sensors_timestamp *ts; int64_t gyro_ts, accel_ts; int ret; @@ -549,7 +554,7 @@ int inv_icm42600_buffer_hwfifo_flush(struct inv_icm42600_state *st, return 0; if (st->fifo.nb.gyro > 0) { - ts = iio_priv(st->indio_gyro); + ts = &gyro_st->ts; inv_sensors_timestamp_interrupt(ts, st->fifo.period, st->fifo.nb.total, st->fifo.nb.gyro, gyro_ts); @@ -559,7 +564,7 @@ int inv_icm42600_buffer_hwfifo_flush(struct inv_icm42600_state *st, } if (st->fifo.nb.accel > 0) { - ts = iio_priv(st->indio_accel); + ts = &accel_st->ts; inv_sensors_timestamp_interrupt(ts, st->fifo.period, st->fifo.nb.total, st->fifo.nb.accel, accel_ts); diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c index 82e0a2e2ad70..96116a68ab29 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c @@ -66,6 +66,22 @@ static const struct inv_icm42600_conf inv_icm42600_default_conf = { .temp_en = false, }; +static const struct inv_icm42600_conf inv_icm42686_default_conf = { + .gyro = { + .mode = INV_ICM42600_SENSOR_MODE_OFF, + .fs = INV_ICM42686_GYRO_FS_4000DPS, + .odr = INV_ICM42600_ODR_50HZ, + .filter = INV_ICM42600_FILTER_BW_ODR_DIV_2, + }, + .accel = { + .mode = INV_ICM42600_SENSOR_MODE_OFF, + .fs = INV_ICM42686_ACCEL_FS_32G, + .odr = INV_ICM42600_ODR_50HZ, + .filter = INV_ICM42600_FILTER_BW_ODR_DIV_2, + }, + .temp_en = false, +}; + static const struct inv_icm42600_hw inv_icm42600_hw[INV_CHIP_NB] = { [INV_CHIP_ICM42600] = { .whoami = INV_ICM42600_WHOAMI_ICM42600, @@ -82,6 +98,11 @@ static const struct inv_icm42600_hw inv_icm42600_hw[INV_CHIP_NB] = { .name = "icm42605", .conf = &inv_icm42600_default_conf, }, + [INV_CHIP_ICM42686] = { + .whoami = INV_ICM42600_WHOAMI_ICM42686, + .name = "icm42686", + .conf = &inv_icm42686_default_conf, + }, [INV_CHIP_ICM42622] = { .whoami = INV_ICM42600_WHOAMI_ICM42622, .name = "icm42622", diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c index 3df0a715e885..e6f8de80128c 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c @@ -99,7 +99,8 @@ static int inv_icm42600_gyro_update_scan_mode(struct iio_dev *indio_dev, const unsigned long *scan_mask) { struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev); - struct inv_sensors_timestamp *ts = iio_priv(indio_dev); + struct inv_icm42600_sensor_state *gyro_st = iio_priv(indio_dev); + struct inv_sensors_timestamp *ts = &gyro_st->ts; struct inv_icm42600_sensor_conf conf = INV_ICM42600_SENSOR_CONF_INIT; unsigned int fifo_en = 0; unsigned int sleep_gyro = 0; @@ -222,33 +223,63 @@ static const int inv_icm42600_gyro_scale[] = { [2 * INV_ICM42600_GYRO_FS_15_625DPS] = 0, [2 * INV_ICM42600_GYRO_FS_15_625DPS + 1] = 8322, }; +static const int inv_icm42686_gyro_scale[] = { + /* +/- 4000dps => 0.002130529 rad/s */ + [2 * INV_ICM42686_GYRO_FS_4000DPS] = 0, + [2 * INV_ICM42686_GYRO_FS_4000DPS + 1] = 2130529, + /* +/- 2000dps => 0.001065264 rad/s */ + [2 * INV_ICM42686_GYRO_FS_2000DPS] = 0, + [2 * INV_ICM42686_GYRO_FS_2000DPS + 1] = 1065264, + /* +/- 1000dps => 0.000532632 rad/s */ + [2 * INV_ICM42686_GYRO_FS_1000DPS] = 0, + [2 * INV_ICM42686_GYRO_FS_1000DPS + 1] = 532632, + /* +/- 500dps => 0.000266316 rad/s */ + [2 * INV_ICM42686_GYRO_FS_500DPS] = 0, + [2 * INV_ICM42686_GYRO_FS_500DPS + 1] = 266316, + /* +/- 250dps => 0.000133158 rad/s */ + [2 * INV_ICM42686_GYRO_FS_250DPS] = 0, + [2 * INV_ICM42686_GYRO_FS_250DPS + 1] = 133158, + /* +/- 125dps => 0.000066579 rad/s */ + [2 * INV_ICM42686_GYRO_FS_125DPS] = 0, + [2 * INV_ICM42686_GYRO_FS_125DPS + 1] = 66579, + /* +/- 62.5dps => 0.000033290 rad/s */ + [2 * INV_ICM42686_GYRO_FS_62_5DPS] = 0, + [2 * INV_ICM42686_GYRO_FS_62_5DPS + 1] = 33290, + /* +/- 31.25dps => 0.000016645 rad/s */ + [2 * INV_ICM42686_GYRO_FS_31_25DPS] = 0, + [2 * INV_ICM42686_GYRO_FS_31_25DPS + 1] = 16645, +}; -static int inv_icm42600_gyro_read_scale(struct inv_icm42600_state *st, +static int inv_icm42600_gyro_read_scale(struct iio_dev *indio_dev, int *val, int *val2) { + struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev); + struct inv_icm42600_sensor_state *gyro_st = iio_priv(indio_dev); unsigned int idx; idx = st->conf.gyro.fs; - *val = inv_icm42600_gyro_scale[2 * idx]; - *val2 = inv_icm42600_gyro_scale[2 * idx + 1]; + *val = gyro_st->scales[2 * idx]; + *val2 = gyro_st->scales[2 * idx + 1]; return IIO_VAL_INT_PLUS_NANO; } -static int inv_icm42600_gyro_write_scale(struct inv_icm42600_state *st, +static int inv_icm42600_gyro_write_scale(struct iio_dev *indio_dev, int val, int val2) { + struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev); + struct inv_icm42600_sensor_state *gyro_st = iio_priv(indio_dev); struct device *dev = regmap_get_device(st->map); unsigned int idx; struct inv_icm42600_sensor_conf conf = INV_ICM42600_SENSOR_CONF_INIT; int ret; - for (idx = 0; idx < ARRAY_SIZE(inv_icm42600_gyro_scale); idx += 2) { - if (val == inv_icm42600_gyro_scale[idx] && - val2 == inv_icm42600_gyro_scale[idx + 1]) + for (idx = 0; idx < gyro_st->scales_len; idx += 2) { + if (val == gyro_st->scales[idx] && + val2 == gyro_st->scales[idx + 1]) break; } - if (idx >= ARRAY_SIZE(inv_icm42600_gyro_scale)) + if (idx >= gyro_st->scales_len) return -EINVAL; conf.fs = idx / 2; @@ -321,7 +352,8 @@ static int inv_icm42600_gyro_write_odr(struct iio_dev *indio_dev, int val, int val2) { struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev); - struct inv_sensors_timestamp *ts = iio_priv(indio_dev); + struct inv_icm42600_sensor_state *gyro_st = iio_priv(indio_dev); + struct inv_sensors_timestamp *ts = &gyro_st->ts; struct device *dev = regmap_get_device(st->map); unsigned int idx; struct inv_icm42600_sensor_conf conf = INV_ICM42600_SENSOR_CONF_INIT; @@ -576,7 +608,7 @@ static int inv_icm42600_gyro_read_raw(struct iio_dev *indio_dev, *val = data; return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: - return inv_icm42600_gyro_read_scale(st, val, val2); + return inv_icm42600_gyro_read_scale(indio_dev, val, val2); case IIO_CHAN_INFO_SAMP_FREQ: return inv_icm42600_gyro_read_odr(st, val, val2); case IIO_CHAN_INFO_CALIBBIAS: @@ -591,14 +623,16 @@ static int inv_icm42600_gyro_read_avail(struct iio_dev *indio_dev, const int **vals, int *type, int *length, long mask) { + struct inv_icm42600_sensor_state *gyro_st = iio_priv(indio_dev); + if (chan->type != IIO_ANGL_VEL) return -EINVAL; switch (mask) { case IIO_CHAN_INFO_SCALE: - *vals = inv_icm42600_gyro_scale; + *vals = gyro_st->scales; *type = IIO_VAL_INT_PLUS_NANO; - *length = ARRAY_SIZE(inv_icm42600_gyro_scale); + *length = gyro_st->scales_len; return IIO_AVAIL_LIST; case IIO_CHAN_INFO_SAMP_FREQ: *vals = inv_icm42600_gyro_odr; @@ -629,7 +663,7 @@ static int inv_icm42600_gyro_write_raw(struct iio_dev *indio_dev, ret = iio_device_claim_direct_mode(indio_dev); if (ret) return ret; - ret = inv_icm42600_gyro_write_scale(st, val, val2); + ret = inv_icm42600_gyro_write_scale(indio_dev, val, val2); iio_device_release_direct_mode(indio_dev); return ret; case IIO_CHAN_INFO_SAMP_FREQ: @@ -716,8 +750,8 @@ struct iio_dev *inv_icm42600_gyro_init(struct inv_icm42600_state *st) { struct device *dev = regmap_get_device(st->map); const char *name; + struct inv_icm42600_sensor_state *gyro_st; struct inv_sensors_timestamp_chip ts_chip; - struct inv_sensors_timestamp *ts; struct iio_dev *indio_dev; int ret; @@ -725,9 +759,21 @@ struct iio_dev *inv_icm42600_gyro_init(struct inv_icm42600_state *st) if (!name) return ERR_PTR(-ENOMEM); - indio_dev = devm_iio_device_alloc(dev, sizeof(*ts)); + indio_dev = devm_iio_device_alloc(dev, sizeof(*gyro_st)); if (!indio_dev) return ERR_PTR(-ENOMEM); + gyro_st = iio_priv(indio_dev); + + switch (st->chip) { + case INV_CHIP_ICM42686: + gyro_st->scales = inv_icm42686_gyro_scale; + gyro_st->scales_len = ARRAY_SIZE(inv_icm42686_gyro_scale); + break; + default: + gyro_st->scales = inv_icm42600_gyro_scale; + gyro_st->scales_len = ARRAY_SIZE(inv_icm42600_gyro_scale); + break; + } /* * clock period is 32kHz (31250ns) @@ -736,8 +782,7 @@ struct iio_dev *inv_icm42600_gyro_init(struct inv_icm42600_state *st) ts_chip.clock_period = 31250; ts_chip.jitter = 20; ts_chip.init_period = inv_icm42600_odr_to_period(st->conf.accel.odr); - ts = iio_priv(indio_dev); - inv_sensors_timestamp_init(ts, &ts_chip); + inv_sensors_timestamp_init(&gyro_st->ts, &ts_chip); iio_device_set_drvdata(indio_dev, st); indio_dev->name = name; @@ -763,7 +808,8 @@ struct iio_dev *inv_icm42600_gyro_init(struct inv_icm42600_state *st) int inv_icm42600_gyro_parse_fifo(struct iio_dev *indio_dev) { struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev); - struct inv_sensors_timestamp *ts = iio_priv(indio_dev); + struct inv_icm42600_sensor_state *gyro_st = iio_priv(indio_dev); + struct inv_sensors_timestamp *ts = &gyro_st->ts; ssize_t i, size; unsigned int no; const void *accel, *gyro, *timestamp; diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c index ebb28f84ba98..8d33504d770f 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c @@ -81,6 +81,9 @@ static const struct of_device_id inv_icm42600_of_matches[] = { }, { .compatible = "invensense,icm42605", .data = (void *)INV_CHIP_ICM42605, + }, { + .compatible = "invensense,icm42686", + .data = (void *)INV_CHIP_ICM42686, }, { .compatible = "invensense,icm42622", .data = (void *)INV_CHIP_ICM42622, diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c index 50217a10e0bb..cc2bf1799a46 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c @@ -77,6 +77,9 @@ static const struct of_device_id inv_icm42600_of_matches[] = { }, { .compatible = "invensense,icm42605", .data = (void *)INV_CHIP_ICM42605, + }, { + .compatible = "invensense,icm42686", + .data = (void *)INV_CHIP_ICM42686, }, { .compatible = "invensense,icm42622", .data = (void *)INV_CHIP_ICM42622, -- cgit v1.2.3-59-g8ed1b From 73e49886a2834b79630cf4db6a98172aa066ce0e Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 24 Apr 2024 14:45:30 +0300 Subject: iio: dac: adi-axi: fix a mistake in axi_dac_ext_info_set() The last parameter of these axi_dac_(frequency|scale|phase)_set() functions is supposed to be true for TONE_2 and false for TONE_1. The bug is the last call where it passes "private - TONE_2". That subtraction is going to be zero/false for TONE_2 and and -1/true for TONE_1. Fix the bug, and re-write it as "private == TONE_2" so it's more obvious what is happening. Fixes: 4e3949a192e4 ("iio: dac: add support for AXI DAC IP core") Signed-off-by: Dan Carpenter Reviewed-by: Nuno Sa Link: https://lore.kernel.org/r/df7c6e1b-b619-40c3-9881-838587ed15d4@moroto.mountain Signed-off-by: Jonathan Cameron --- drivers/iio/dac/adi-axi-dac.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/iio/dac/adi-axi-dac.c b/drivers/iio/dac/adi-axi-dac.c index 9047c5aec0ff..880d83a014a1 100644 --- a/drivers/iio/dac/adi-axi-dac.c +++ b/drivers/iio/dac/adi-axi-dac.c @@ -383,15 +383,15 @@ static int axi_dac_ext_info_set(struct iio_backend *back, uintptr_t private, case AXI_DAC_FREQ_TONE_1: case AXI_DAC_FREQ_TONE_2: return axi_dac_frequency_set(st, chan, buf, len, - private - AXI_DAC_FREQ_TONE_1); + private == AXI_DAC_FREQ_TONE_2); case AXI_DAC_SCALE_TONE_1: case AXI_DAC_SCALE_TONE_2: return axi_dac_scale_set(st, chan, buf, len, - private - AXI_DAC_SCALE_TONE_1); + private == AXI_DAC_SCALE_TONE_2); case AXI_DAC_PHASE_TONE_1: case AXI_DAC_PHASE_TONE_2: return axi_dac_phase_set(st, chan, buf, len, - private - AXI_DAC_PHASE_TONE_2); + private == AXI_DAC_PHASE_TONE_2); default: return -EOPNOTSUPP; } -- cgit v1.2.3-59-g8ed1b From 64ce7d4348be630badad2af22030bebf028b2861 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 25 Apr 2024 09:09:59 -0500 Subject: iio: adc: ad7944: add support for chain mode This adds support for the chain mode of the AD7944 ADC. This mode allows multiple ADCs to be daisy-chained together. Data from all of the ADCs in is read by reading multiple words from the first ADC in the chain. Each chip in the chain adds an extra IIO input voltage channel to the IIO device. Only the wiring configuration where the SPI controller CS line is connected to the CNV pin of all of the ADCs in the chain is supported in this patch. Signed-off-by: David Lechner Link: https://lore.kernel.org/r/20240425-iio-ad7944-chain-mode-v1-1-9d9220ff21e1@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7944.c | 186 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 176 insertions(+), 10 deletions(-) diff --git a/drivers/iio/adc/ad7944.c b/drivers/iio/adc/ad7944.c index 4af574ffa864..4602ab5ed2a6 100644 --- a/drivers/iio/adc/ad7944.c +++ b/drivers/iio/adc/ad7944.c @@ -6,6 +6,7 @@ * Copyright 2024 BayLibre, SAS */ +#include #include #include #include @@ -53,6 +54,7 @@ struct ad7944_adc { enum ad7944_spi_mode spi_mode; struct spi_transfer xfers[3]; struct spi_message msg; + void *chain_mode_buf; /* Chip-specific timing specifications. */ const struct ad7944_timing_spec *timing_spec; /* GPIO connected to CNV pin. */ @@ -214,6 +216,46 @@ static int ad7944_4wire_mode_init_msg(struct device *dev, struct ad7944_adc *adc return devm_add_action_or_reset(dev, ad7944_unoptimize_msg, &adc->msg); } +static int ad7944_chain_mode_init_msg(struct device *dev, struct ad7944_adc *adc, + const struct iio_chan_spec *chan, + u32 n_chain_dev) +{ + struct spi_transfer *xfers = adc->xfers; + int ret; + + /* + * NB: SCLK has to be low before we toggle CS to avoid triggering the + * busy indication. + */ + if (adc->spi->mode & SPI_CPOL) + return dev_err_probe(dev, -EINVAL, + "chain mode requires ~SPI_CPOL\n"); + + /* + * We only support CNV connected to CS in chain mode and we need CNV + * to be high during the transfer to trigger the conversion. + */ + if (!(adc->spi->mode & SPI_CS_HIGH)) + return dev_err_probe(dev, -EINVAL, + "chain mode requires SPI_CS_HIGH\n"); + + /* CNV has to be high for full conversion time before reading data. */ + xfers[0].delay.value = adc->timing_spec->conv_ns; + xfers[0].delay.unit = SPI_DELAY_UNIT_NSECS; + + xfers[1].rx_buf = adc->chain_mode_buf; + xfers[1].len = BITS_TO_BYTES(chan->scan_type.storagebits) * n_chain_dev; + xfers[1].bits_per_word = chan->scan_type.realbits; + + spi_message_init_with_transfers(&adc->msg, xfers, 2); + + ret = spi_optimize_message(adc->spi, &adc->msg); + if (ret) + return ret; + + return devm_add_action_or_reset(dev, ad7944_unoptimize_msg, &adc->msg); +} + /** * ad7944_convert_and_acquire - Perform a single conversion and acquisition * @adc: The ADC device structure @@ -223,7 +265,8 @@ static int ad7944_4wire_mode_init_msg(struct device *dev, struct ad7944_adc *adc * Perform a conversion and acquisition of a single sample using the * pre-optimized adc->msg. * - * Upon successful return adc->sample.raw will contain the conversion result. + * Upon successful return adc->sample.raw will contain the conversion result + * (or adc->chain_mode_buf if the device is using chain mode). */ static int ad7944_convert_and_acquire(struct ad7944_adc *adc, const struct iio_chan_spec *chan) @@ -252,10 +295,17 @@ static int ad7944_single_conversion(struct ad7944_adc *adc, if (ret) return ret; - if (chan->scan_type.storagebits > 16) - *val = adc->sample.raw.u32; - else - *val = adc->sample.raw.u16; + if (adc->spi_mode == AD7944_SPI_MODE_CHAIN) { + if (chan->scan_type.storagebits > 16) + *val = ((u32 *)adc->chain_mode_buf)[chan->scan_index]; + else + *val = ((u16 *)adc->chain_mode_buf)[chan->scan_index]; + } else { + if (chan->scan_type.storagebits > 16) + *val = adc->sample.raw.u32; + else + *val = adc->sample.raw.u16; + } if (chan->scan_type.sign == 's') *val = sign_extend32(*val, chan->scan_type.realbits - 1); @@ -315,8 +365,12 @@ static irqreturn_t ad7944_trigger_handler(int irq, void *p) if (ret) goto out; - iio_push_to_buffers_with_timestamp(indio_dev, &adc->sample.raw, - pf->timestamp); + if (adc->spi_mode == AD7944_SPI_MODE_CHAIN) + iio_push_to_buffers_with_timestamp(indio_dev, adc->chain_mode_buf, + pf->timestamp); + else + iio_push_to_buffers_with_timestamp(indio_dev, &adc->sample.raw, + pf->timestamp); out: iio_trigger_notify_done(indio_dev->trig); @@ -324,6 +378,90 @@ out: return IRQ_HANDLED; } +/** + * ad7944_chain_mode_alloc - allocate and initialize channel specs and buffers + * for daisy-chained devices + * @dev: The device for devm_ functions + * @chan_template: The channel template for the devices (array of 2 channels + * voltage and timestamp) + * @n_chain_dev: The number of devices in the chain + * @chain_chan: Pointer to receive the allocated channel specs + * @chain_mode_buf: Pointer to receive the allocated rx buffer + * @chain_scan_masks: Pointer to receive the allocated scan masks + * Return: 0 on success, a negative error code on failure + */ +static int ad7944_chain_mode_alloc(struct device *dev, + const struct iio_chan_spec *chan_template, + u32 n_chain_dev, + struct iio_chan_spec **chain_chan, + void **chain_mode_buf, + unsigned long **chain_scan_masks) +{ + struct iio_chan_spec *chan; + size_t chain_mode_buf_size; + unsigned long *scan_masks; + void *buf; + int i; + + /* 1 channel for each device in chain plus 1 for soft timestamp */ + + chan = devm_kcalloc(dev, n_chain_dev + 1, sizeof(*chan), GFP_KERNEL); + if (!chan) + return -ENOMEM; + + for (i = 0; i < n_chain_dev; i++) { + chan[i] = chan_template[0]; + + if (chan_template[0].differential) { + chan[i].channel = 2 * i; + chan[i].channel2 = 2 * i + 1; + } else { + chan[i].channel = i; + } + + chan[i].scan_index = i; + } + + /* soft timestamp */ + chan[i] = chan_template[1]; + chan[i].scan_index = i; + + *chain_chan = chan; + + /* 1 word for each voltage channel + aligned u64 for timestamp */ + + chain_mode_buf_size = ALIGN(n_chain_dev * + BITS_TO_BYTES(chan[0].scan_type.storagebits), sizeof(u64)) + + sizeof(u64); + buf = devm_kzalloc(dev, chain_mode_buf_size, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + *chain_mode_buf = buf; + + /* + * Have to limit n_chain_dev due to current implementation of + * available_scan_masks. + */ + if (n_chain_dev > BITS_PER_LONG) + return dev_err_probe(dev, -EINVAL, + "chain is limited to 32 devices\n"); + + scan_masks = devm_kcalloc(dev, 2, sizeof(*scan_masks), GFP_KERNEL); + if (!scan_masks) + return -ENOMEM; + + /* + * Scan mask is needed since we always have to read all devices in the + * chain in one SPI transfer. + */ + scan_masks[0] = GENMASK(n_chain_dev - 1, 0); + + *chain_scan_masks = scan_masks; + + return 0; +} + static const char * const ad7944_power_supplies[] = { "avdd", "dvdd", "bvdd", "vio" }; @@ -341,6 +479,9 @@ static int ad7944_probe(struct spi_device *spi) struct ad7944_adc *adc; bool have_refin = false; struct regulator *ref; + struct iio_chan_spec *chain_chan; + unsigned long *chain_scan_masks; + u32 n_chain_dev; int ret; indio_dev = devm_iio_device_alloc(dev, sizeof(*adc)); @@ -474,14 +615,39 @@ static int ad7944_probe(struct spi_device *spi) break; case AD7944_SPI_MODE_CHAIN: - return dev_err_probe(dev, -EINVAL, "chain mode is not implemented\n"); + ret = device_property_read_u32(dev, "#daisy-chained-devices", + &n_chain_dev); + if (ret) + return dev_err_probe(dev, ret, + "failed to get #daisy-chained-devices\n"); + + ret = ad7944_chain_mode_alloc(dev, chip_info->channels, + n_chain_dev, &chain_chan, + &adc->chain_mode_buf, + &chain_scan_masks); + if (ret) + return ret; + + ret = ad7944_chain_mode_init_msg(dev, adc, &chain_chan[0], + n_chain_dev); + if (ret) + return ret; + + break; } indio_dev->name = chip_info->name; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &ad7944_iio_info; - indio_dev->channels = chip_info->channels; - indio_dev->num_channels = ARRAY_SIZE(chip_info->channels); + + if (adc->spi_mode == AD7944_SPI_MODE_CHAIN) { + indio_dev->available_scan_masks = chain_scan_masks; + indio_dev->channels = chain_chan; + indio_dev->num_channels = n_chain_dev + 1; + } else { + indio_dev->channels = chip_info->channels; + indio_dev->num_channels = ARRAY_SIZE(chip_info->channels); + } ret = devm_iio_triggered_buffer_setup(dev, indio_dev, iio_pollfunc_store_time, -- cgit v1.2.3-59-g8ed1b From 633e3015cae062a424a6dd5099710adfe83a5e14 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 25 Apr 2024 09:10:00 -0500 Subject: docs: iio: ad7944: add documentation for chain mode Add documentation for chain mode support that was recently added to the AD7944 ADC driver. Signed-off-by: David Lechner Link: https://lore.kernel.org/r/20240425-iio-ad7944-chain-mode-v1-2-9d9220ff21e1@baylibre.com Signed-off-by: Jonathan Cameron --- Documentation/iio/ad7944.rst | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/Documentation/iio/ad7944.rst b/Documentation/iio/ad7944.rst index f418ab1288ae..0d26e56aba88 100644 --- a/Documentation/iio/ad7944.rst +++ b/Documentation/iio/ad7944.rst @@ -24,7 +24,7 @@ Supported features SPI wiring modes ---------------- -The driver currently supports two of the many possible SPI wiring configurations. +The driver currently supports three of the many possible SPI wiring configurations. CS mode, 3-wire, without busy indicator ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -68,6 +68,27 @@ CS mode, 4-wire, without busy indicator To select this mode in the device tree, omit the ``adi,spi-mode`` property and provide the ``cnv-gpios`` property. +Chain mode, without busy indicator +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: + + +-------------+ + +-------------------------+--------------------| CS | + v v | | + +--------------------+ +--------------------+ | HOST | + | CNV | | CNV | | | + +--->| SDI AD7944 SDO |--->| SDI AD7944 SDO |-------->| SDI | + | | SCK | | SCK | | | + GND +--------------------+ +--------------------+ | | + ^ ^ | | + +-------------------------+--------------------| SCLK | + +-------------+ + +To select this mode in the device tree, set the ``adi,spi-mode`` property to +``"chain"``, add the ``spi-cs-high`` flag, add the ``#daisy-chained-devices`` +property, and omit the ``cnv-gpios`` property. + Reference voltage ----------------- @@ -86,7 +107,6 @@ Unimplemented features - ``BUSY`` indication - ``TURBO`` mode -- Daisy chain mode Device attributes @@ -108,6 +128,9 @@ AD7944 and AD7985 are pseudo-differential ADCs and have the following attributes | ``in_voltage0_scale`` | Scale factor to convert raw value to mV. | +---------------------------------------+--------------------------------------------------------------+ +In "chain" mode, additional chips will appear as additional voltage input +channels, e.g. ``in_voltage1_raw``. + Fully-differential ADCs ----------------------- @@ -121,6 +144,9 @@ AD7986 is a fully-differential ADC and has the following attributes: | ``in_voltage0-voltage1_scale`` | Scale factor to convert raw value to mV. | +---------------------------------------+--------------------------------------------------------------+ +In "chain" mode, additional chips will appear as additional voltage input +channels, e.g. ``in_voltage2-voltage3_raw``. + Device buffers ============== -- cgit v1.2.3-59-g8ed1b From 19fb11d7220b8abc016aa254dc7e6d9f2d49b178 Mon Sep 17 00:00:00 2001 From: Nuno Sa Date: Fri, 26 Apr 2024 17:42:12 +0200 Subject: dt-bindings: adc: axi-adc: add clocks property Add a required clock property as we can't access the device registers if the AXI bus clock is not properly enabled. Note this clock is a very fundamental one that is typically enabled pretty early during boot. Independently of that, we should really rely on it to be enabled. Reviewed-by: Krzysztof Kozlowski Fixes: 96553a44e96d ("dt-bindings: iio: adc: add bindings doc for AXI ADC driver") Signed-off-by: Nuno Sa Link: https://lore.kernel.org/r/20240426-ad9467-new-features-v2-3-6361fc3ba1cc@analog.com Cc: Signed-off-by: Jonathan Cameron --- Documentation/devicetree/bindings/iio/adc/adi,axi-adc.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Documentation/devicetree/bindings/iio/adc/adi,axi-adc.yaml b/Documentation/devicetree/bindings/iio/adc/adi,axi-adc.yaml index 3d49d21ad33d..e1f450b80db2 100644 --- a/Documentation/devicetree/bindings/iio/adc/adi,axi-adc.yaml +++ b/Documentation/devicetree/bindings/iio/adc/adi,axi-adc.yaml @@ -28,6 +28,9 @@ properties: reg: maxItems: 1 + clocks: + maxItems: 1 + dmas: maxItems: 1 @@ -48,6 +51,7 @@ required: - compatible - dmas - reg + - clocks additionalProperties: false @@ -58,6 +62,7 @@ examples: reg = <0x44a00000 0x10000>; dmas = <&rx_dma 0>; dma-names = "rx"; + clocks = <&axi_clk>; #io-backend-cells = <0>; }; ... -- cgit v1.2.3-59-g8ed1b From 80721776c5af6f6dce7d84ba8df063957aa425a2 Mon Sep 17 00:00:00 2001 From: Nuno Sa Date: Fri, 26 Apr 2024 17:42:13 +0200 Subject: iio: adc: axi-adc: make sure AXI clock is enabled We can only access the IP core registers if the bus clock is enabled. As such we need to get and enable it and not rely on anyone else to do it. Note this clock is a very fundamental one that is typically enabled pretty early during boot. Independently of that, we should really rely on it to be enabled. Fixes: ef04070692a2 ("iio: adc: adi-axi-adc: add support for AXI ADC IP core") Signed-off-by: Nuno Sa Link: https://lore.kernel.org/r/20240426-ad9467-new-features-v2-4-6361fc3ba1cc@analog.com Cc: Signed-off-by: Jonathan Cameron --- drivers/iio/adc/adi-axi-adc.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/iio/adc/adi-axi-adc.c b/drivers/iio/adc/adi-axi-adc.c index 9444b0c5a93c..f54830658da8 100644 --- a/drivers/iio/adc/adi-axi-adc.c +++ b/drivers/iio/adc/adi-axi-adc.c @@ -161,6 +161,7 @@ static int adi_axi_adc_probe(struct platform_device *pdev) struct adi_axi_adc_state *st; void __iomem *base; unsigned int ver; + struct clk *clk; int ret; st = devm_kzalloc(&pdev->dev, sizeof(*st), GFP_KERNEL); @@ -181,6 +182,10 @@ static int adi_axi_adc_probe(struct platform_device *pdev) if (!expected_ver) return -ENODEV; + clk = devm_clk_get_enabled(&pdev->dev, NULL); + if (IS_ERR(clk)) + return PTR_ERR(clk); + /* * Force disable the core. Up to the frontend to enable us. And we can * still read/write registers... -- cgit v1.2.3-59-g8ed1b From 09415814cd1d0b90b898f81d6ad6a1c0a2e22d32 Mon Sep 17 00:00:00 2001 From: Nuno Sa Date: Fri, 26 Apr 2024 17:42:10 +0200 Subject: iio: backend: change docs padding Using tabs and maintaining the start of the docs aligned is a pain and may lead to lot's of unrelated changes when adding new members. Hence, let#s change things now and just have a simple space after the member name. Signed-off-by: Nuno Sa Link: https://lore.kernel.org/r/20240426-ad9467-new-features-v2-1-6361fc3ba1cc@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/industrialio-backend.c | 76 +++++++++++++++++++------------------- include/linux/iio/backend.h | 38 +++++++++---------- 2 files changed, 57 insertions(+), 57 deletions(-) diff --git a/drivers/iio/industrialio-backend.c b/drivers/iio/industrialio-backend.c index f08ed6d70ae5..c27243e88462 100644 --- a/drivers/iio/industrialio-backend.c +++ b/drivers/iio/industrialio-backend.c @@ -115,8 +115,8 @@ static DEFINE_MUTEX(iio_back_lock); /** * iio_backend_chan_enable - Enable a backend channel - * @back: Backend device - * @chan: Channel number + * @back: Backend device + * @chan: Channel number * * RETURNS: * 0 on success, negative error number on failure. @@ -129,8 +129,8 @@ EXPORT_SYMBOL_NS_GPL(iio_backend_chan_enable, IIO_BACKEND); /** * iio_backend_chan_disable - Disable a backend channel - * @back: Backend device - * @chan: Channel number + * @back: Backend device + * @chan: Channel number * * RETURNS: * 0 on success, negative error number on failure. @@ -148,8 +148,8 @@ static void __iio_backend_disable(void *back) /** * devm_iio_backend_enable - Device managed backend enable - * @dev: Consumer device for the backend - * @back: Backend device + * @dev: Consumer device for the backend + * @back: Backend device * * RETURNS: * 0 on success, negative error number on failure. @@ -168,9 +168,9 @@ EXPORT_SYMBOL_NS_GPL(devm_iio_backend_enable, IIO_BACKEND); /** * iio_backend_data_format_set - Configure the channel data format - * @back: Backend device - * @chan: Channel number - * @data: Data format + * @back: Backend device + * @chan: Channel number + * @data: Data format * * Properly configure a channel with respect to the expected data format. A * @struct iio_backend_data_fmt must be passed with the settings. @@ -190,9 +190,9 @@ EXPORT_SYMBOL_NS_GPL(iio_backend_data_format_set, IIO_BACKEND); /** * iio_backend_data_source_set - Select data source - * @back: Backend device - * @chan: Channel number - * @data: Data source + * @back: Backend device + * @chan: Channel number + * @data: Data source * * A given backend may have different sources to stream/sync data. This allows * to choose that source. @@ -212,9 +212,9 @@ EXPORT_SYMBOL_NS_GPL(iio_backend_data_source_set, IIO_BACKEND); /** * iio_backend_set_sampling_freq - Set channel sampling rate - * @back: Backend device - * @chan: Channel number - * @sample_rate_hz: Sample rate + * @back: Backend device + * @chan: Channel number + * @sample_rate_hz: Sample rate * * RETURNS: * 0 on success, negative error number on failure. @@ -235,9 +235,9 @@ static void iio_backend_free_buffer(void *arg) /** * devm_iio_backend_request_buffer - Device managed buffer request - * @dev: Consumer device for the backend - * @back: Backend device - * @indio_dev: IIO device + * @dev: Consumer device for the backend + * @back: Backend device + * @indio_dev: IIO device * * Request an IIO buffer from the backend. The type of the buffer (typically * INDIO_BUFFER_HARDWARE) is up to the backend to decide. This is because, @@ -300,10 +300,10 @@ static struct iio_backend *iio_backend_from_indio_dev_parent(const struct device /** * iio_backend_ext_info_get - IIO ext_info read callback - * @indio_dev: IIO device - * @private: Data private to the driver - * @chan: IIO channel - * @buf: Buffer where to place the attribute data + * @indio_dev: IIO device + * @private: Data private to the driver + * @chan: IIO channel + * @buf: Buffer where to place the attribute data * * This helper is intended to be used by backends that extend an IIO channel * (through iio_backend_extend_chan_spec()) with extended info. In that case, @@ -335,11 +335,11 @@ EXPORT_SYMBOL_NS_GPL(iio_backend_ext_info_get, IIO_BACKEND); /** * iio_backend_ext_info_set - IIO ext_info write callback - * @indio_dev: IIO device - * @private: Data private to the driver - * @chan: IIO channel - * @buf: Buffer holding the sysfs attribute - * @len: Buffer length + * @indio_dev: IIO device + * @private: Data private to the driver + * @chan: IIO channel + * @buf: Buffer holding the sysfs attribute + * @len: Buffer length * * This helper is intended to be used by backends that extend an IIO channel * (trough iio_backend_extend_chan_spec()) with extended info. In that case, @@ -365,9 +365,9 @@ EXPORT_SYMBOL_NS_GPL(iio_backend_ext_info_set, IIO_BACKEND); /** * iio_backend_extend_chan_spec - Extend an IIO channel - * @indio_dev: IIO device - * @back: Backend device - * @chan: IIO channel + * @indio_dev: IIO device + * @back: Backend device + * @chan: IIO channel * * Some backends may have their own functionalities and hence capable of * extending a frontend's channel. @@ -449,8 +449,8 @@ static int __devm_iio_backend_get(struct device *dev, struct iio_backend *back) /** * devm_iio_backend_get - Device managed backend device get - * @dev: Consumer device for the backend - * @name: Backend name + * @dev: Consumer device for the backend + * @name: Backend name * * Get's the backend associated with @dev. * @@ -501,8 +501,8 @@ EXPORT_SYMBOL_NS_GPL(devm_iio_backend_get, IIO_BACKEND); /** * __devm_iio_backend_get_from_fwnode_lookup - Device managed fwnode backend device get - * @dev: Consumer device for the backend - * @fwnode: Firmware node of the backend device + * @dev: Consumer device for the backend + * @fwnode: Firmware node of the backend device * * Search the backend list for a device matching @fwnode. * This API should not be used and it's only present for preventing the first @@ -536,7 +536,7 @@ EXPORT_SYMBOL_NS_GPL(__devm_iio_backend_get_from_fwnode_lookup, IIO_BACKEND); /** * iio_backend_get_priv - Get driver private data - * @back: Backend device + * @back: Backend device */ void *iio_backend_get_priv(const struct iio_backend *back) { @@ -554,9 +554,9 @@ static void iio_backend_unregister(void *arg) /** * devm_iio_backend_register - Device managed backend device register - * @dev: Backend device being registered - * @ops: Backend ops - * @priv: Device private data + * @dev: Backend device being registered + * @ops: Backend ops + * @priv: Device private data * * @ops is mandatory. Not providing it results in -EINVAL. * diff --git a/include/linux/iio/backend.h b/include/linux/iio/backend.h index 9d144631134d..e3e62f65db14 100644 --- a/include/linux/iio/backend.h +++ b/include/linux/iio/backend.h @@ -24,9 +24,9 @@ enum iio_backend_data_source { /** * IIO_BACKEND_EX_INFO - Helper for an IIO extended channel attribute - * @_name: Attribute name - * @_shared: Whether the attribute is shared between all channels - * @_what: Data private to the driver + * @_name: Attribute name + * @_shared: Whether the attribute is shared between all channels + * @_what: Data private to the driver */ #define IIO_BACKEND_EX_INFO(_name, _shared, _what) { \ .name = (_name), \ @@ -38,10 +38,10 @@ enum iio_backend_data_source { /** * struct iio_backend_data_fmt - Backend data format - * @type: Data type. - * @sign_extend: Bool to tell if the data is sign extended. - * @enable: Enable/Disable the data format module. If disabled, - * not formatting will happen. + * @type: Data type. + * @sign_extend: Bool to tell if the data is sign extended. + * @enable: Enable/Disable the data format module. If disabled, + * not formatting will happen. */ struct iio_backend_data_fmt { enum iio_backend_data_type type; @@ -51,18 +51,18 @@ struct iio_backend_data_fmt { /** * struct iio_backend_ops - operations structure for an iio_backend - * @enable: Enable backend. - * @disable: Disable backend. - * @chan_enable: Enable one channel. - * @chan_disable: Disable one channel. - * @data_format_set: Configure the data format for a specific channel. - * @data_source_set: Configure the data source for a specific channel. - * @set_sample_rate: Configure the sampling rate for a specific channel. - * @request_buffer: Request an IIO buffer. - * @free_buffer: Free an IIO buffer. - * @extend_chan_spec: Extend an IIO channel. - * @ext_info_set: Extended info setter. - * @ext_info_get: Extended info getter. + * @enable: Enable backend. + * @disable: Disable backend. + * @chan_enable: Enable one channel. + * @chan_disable: Disable one channel. + * @data_format_set: Configure the data format for a specific channel. + * @data_source_set: Configure the data source for a specific channel. + * @set_sample_rate: Configure the sampling rate for a specific channel. + * @request_buffer: Request an IIO buffer. + * @free_buffer: Free an IIO buffer. + * @extend_chan_spec: Extend an IIO channel. + * @ext_info_set: Extended info setter. + * @ext_info_get: Extended info getter. **/ struct iio_backend_ops { int (*enable)(struct iio_backend *back); -- cgit v1.2.3-59-g8ed1b From c66eabcc1ca64dbf20d0758ce210a85fa83f4b21 Mon Sep 17 00:00:00 2001 From: Nuno Sa Date: Fri, 26 Apr 2024 17:42:11 +0200 Subject: iio: backend: add API for interface tuning This is in preparation for supporting interface tuning in one for the devices using the axi-adc backend. The new added interfaces are all needed for that calibration: * iio_backend_test_pattern_set(); * iio_backend_chan_status(); * iio_backend_iodelay_set(); * iio_backend_data_sample_trigger(). Interface tuning is the process of going through a set of known points (typically by the frontend), change some clk or data delays (or both) and send/receive some known signal (so called test patterns in this change). The receiving end (either frontend or the backend) is responsible for validating the signal and see if it's good or not. The goal for all of this is to come up with ideal delays at the data interface level so we can have a proper, more reliable data transfer. Also note that for some devices we can change the sampling rate (which typically means changing some reference clock) and that can affect the data interface. In that case, it's import to run the tuning algorithm again as the values we had before may no longer be the best (or even valid) ones. Signed-off-by: Nuno Sa Link: https://lore.kernel.org/r/20240426-ad9467-new-features-v2-2-6361fc3ba1cc@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/industrialio-backend.c | 86 ++++++++++++++++++++++++++++++++++++++ include/linux/iio/backend.h | 36 ++++++++++++++++ 2 files changed, 122 insertions(+) diff --git a/drivers/iio/industrialio-backend.c b/drivers/iio/industrialio-backend.c index c27243e88462..929aff4040ed 100644 --- a/drivers/iio/industrialio-backend.c +++ b/drivers/iio/industrialio-backend.c @@ -226,6 +226,92 @@ int iio_backend_set_sampling_freq(struct iio_backend *back, unsigned int chan, } EXPORT_SYMBOL_NS_GPL(iio_backend_set_sampling_freq, IIO_BACKEND); +/** + * iio_backend_test_pattern_set - Configure a test pattern + * @back: Backend device + * @chan: Channel number + * @pattern: Test pattern + * + * Configure a test pattern on the backend. This is typically used for + * calibrating the timings on the data digital interface. + * + * RETURNS: + * 0 on success, negative error number on failure. + */ +int iio_backend_test_pattern_set(struct iio_backend *back, + unsigned int chan, + enum iio_backend_test_pattern pattern) +{ + if (pattern >= IIO_BACKEND_TEST_PATTERN_MAX) + return -EINVAL; + + return iio_backend_op_call(back, test_pattern_set, chan, pattern); +} +EXPORT_SYMBOL_NS_GPL(iio_backend_test_pattern_set, IIO_BACKEND); + +/** + * iio_backend_chan_status - Get the channel status + * @back: Backend device + * @chan: Channel number + * @error: Error indication + * + * Get the current state of the backend channel. Typically used to check if + * there were any errors sending/receiving data. + * + * RETURNS: + * 0 on success, negative error number on failure. + */ +int iio_backend_chan_status(struct iio_backend *back, unsigned int chan, + bool *error) +{ + return iio_backend_op_call(back, chan_status, chan, error); +} +EXPORT_SYMBOL_NS_GPL(iio_backend_chan_status, IIO_BACKEND); + +/** + * iio_backend_iodelay_set - Set digital I/O delay + * @back: Backend device + * @lane: Lane number + * @taps: Number of taps + * + * Controls delays on sending/receiving data. One usecase for this is to + * calibrate the data digital interface so we get the best results when + * transferring data. Note that @taps has no unit since the actual delay per tap + * is very backend specific. Hence, frontend devices typically should go through + * an array of @taps (the size of that array should typically match the size of + * calibration points on the frontend device) and call this API. + * + * RETURNS: + * 0 on success, negative error number on failure. + */ +int iio_backend_iodelay_set(struct iio_backend *back, unsigned int lane, + unsigned int taps) +{ + return iio_backend_op_call(back, iodelay_set, lane, taps); +} +EXPORT_SYMBOL_NS_GPL(iio_backend_iodelay_set, IIO_BACKEND); + +/** + * iio_backend_data_sample_trigger - Control when to sample data + * @back: Backend device + * @trigger: Data trigger + * + * Mostly useful for input backends. Configures the backend for when to sample + * data (eg: rising vs falling edge). + * + * RETURNS: + * 0 on success, negative error number on failure. + */ +int iio_backend_data_sample_trigger(struct iio_backend *back, + enum iio_backend_sample_trigger trigger) +{ + if (trigger >= IIO_BACKEND_SAMPLE_TRIGGER_MAX) + return -EINVAL; + + return iio_backend_op_call(back, data_sample_trigger, trigger); +} +EXPORT_SYMBOL_NS_GPL(iio_backend_data_sample_trigger, IIO_BACKEND); + static void iio_backend_free_buffer(void *arg) { struct iio_backend_buffer_pair *pair = arg; diff --git a/include/linux/iio/backend.h b/include/linux/iio/backend.h index e3e62f65db14..8099759d7242 100644 --- a/include/linux/iio/backend.h +++ b/include/linux/iio/backend.h @@ -49,6 +49,20 @@ struct iio_backend_data_fmt { bool enable; }; +/* vendor specific from 32 */ +enum iio_backend_test_pattern { + IIO_BACKEND_NO_TEST_PATTERN, + /* modified prbs9 */ + IIO_BACKEND_ADI_PRBS_9A = 32, + IIO_BACKEND_TEST_PATTERN_MAX +}; + +enum iio_backend_sample_trigger { + IIO_BACKEND_SAMPLE_TRIGGER_EDGE_FALLING, + IIO_BACKEND_SAMPLE_TRIGGER_EDGE_RISING, + IIO_BACKEND_SAMPLE_TRIGGER_MAX +}; + /** * struct iio_backend_ops - operations structure for an iio_backend * @enable: Enable backend. @@ -58,6 +72,10 @@ struct iio_backend_data_fmt { * @data_format_set: Configure the data format for a specific channel. * @data_source_set: Configure the data source for a specific channel. * @set_sample_rate: Configure the sampling rate for a specific channel. + * @test_pattern_set: Configure a test pattern. + * @chan_status: Get the channel status. + * @iodelay_set: Set digital I/O delay. + * @data_sample_trigger: Control when to sample data. * @request_buffer: Request an IIO buffer. * @free_buffer: Free an IIO buffer. * @extend_chan_spec: Extend an IIO channel. @@ -75,6 +93,15 @@ struct iio_backend_ops { enum iio_backend_data_source data); int (*set_sample_rate)(struct iio_backend *back, unsigned int chan, u64 sample_rate_hz); + int (*test_pattern_set)(struct iio_backend *back, + unsigned int chan, + enum iio_backend_test_pattern pattern); + int (*chan_status)(struct iio_backend *back, unsigned int chan, + bool *error); + int (*iodelay_set)(struct iio_backend *back, unsigned int chan, + unsigned int taps); + int (*data_sample_trigger)(struct iio_backend *back, + enum iio_backend_sample_trigger trigger); struct iio_buffer *(*request_buffer)(struct iio_backend *back, struct iio_dev *indio_dev); void (*free_buffer)(struct iio_backend *back, @@ -97,6 +124,15 @@ int iio_backend_data_source_set(struct iio_backend *back, unsigned int chan, enum iio_backend_data_source data); int iio_backend_set_sampling_freq(struct iio_backend *back, unsigned int chan, u64 sample_rate_hz); +int iio_backend_test_pattern_set(struct iio_backend *back, + unsigned int chan, + enum iio_backend_test_pattern pattern); +int iio_backend_chan_status(struct iio_backend *back, unsigned int chan, + bool *error); +int iio_backend_iodelay_set(struct iio_backend *back, unsigned int lane, + unsigned int taps); +int iio_backend_data_sample_trigger(struct iio_backend *back, + enum iio_backend_sample_trigger trigger); int devm_iio_backend_request_buffer(struct device *dev, struct iio_backend *back, struct iio_dev *indio_dev); -- cgit v1.2.3-59-g8ed1b From fbc186055b41a49678ae3b2793020e67dfd8f7aa Mon Sep 17 00:00:00 2001 From: Nuno Sa Date: Fri, 26 Apr 2024 17:42:14 +0200 Subject: iio: adc: adi-axi-adc: remove regmap max register In one of the following patches, we'll have some new functionality that requires reads/writes on registers bigger than 0x8000. Hence, as this is an highly flexible core, don't bother in setting 'max_register' and remove it from regmap_config. Signed-off-by: Nuno Sa Link: https://lore.kernel.org/r/20240426-ad9467-new-features-v2-5-6361fc3ba1cc@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/adi-axi-adc.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/iio/adc/adi-axi-adc.c b/drivers/iio/adc/adi-axi-adc.c index f54830658da8..316750d92ad1 100644 --- a/drivers/iio/adc/adi-axi-adc.c +++ b/drivers/iio/adc/adi-axi-adc.c @@ -142,7 +142,6 @@ static const struct regmap_config axi_adc_regmap_config = { .val_bits = 32, .reg_bits = 32, .reg_stride = 4, - .max_register = 0x0800, }; static const struct iio_backend_ops adi_axi_adc_generic = { -- cgit v1.2.3-59-g8ed1b From 7ecb8ee5c93be9f00cbf090f7f53b2a32d995184 Mon Sep 17 00:00:00 2001 From: Nuno Sa Date: Fri, 26 Apr 2024 17:42:15 +0200 Subject: iio: adc: adi-axi-adc: support digital interface calibration Implement the new IIO backend APIs for calibrating the data digital interfaces. While at it, removed the tabs in 'struct adi_axi_adc_state' and used spaces for the members. Signed-off-by: Nuno Sa Link: https://lore.kernel.org/r/20240426-ad9467-new-features-v2-6-6361fc3ba1cc@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/adi-axi-adc.c | 121 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 119 insertions(+), 2 deletions(-) diff --git a/drivers/iio/adc/adi-axi-adc.c b/drivers/iio/adc/adi-axi-adc.c index 316750d92ad1..0cf0d81358fd 100644 --- a/drivers/iio/adc/adi-axi-adc.c +++ b/drivers/iio/adc/adi-axi-adc.c @@ -7,11 +7,13 @@ */ #include +#include #include #include #include #include #include +#include #include #include #include @@ -37,6 +39,9 @@ #define ADI_AXI_REG_RSTN_MMCM_RSTN BIT(1) #define ADI_AXI_REG_RSTN_RSTN BIT(0) +#define ADI_AXI_ADC_REG_CTRL 0x0044 +#define ADI_AXI_ADC_CTRL_DDR_EDGESEL_MASK BIT(1) + /* ADC Channel controls */ #define ADI_AXI_REG_CHAN_CTRL(c) (0x0400 + (c) * 0x40) @@ -51,14 +56,28 @@ #define ADI_AXI_REG_CHAN_CTRL_PN_TYPE_OWR BIT(1) #define ADI_AXI_REG_CHAN_CTRL_ENABLE BIT(0) +#define ADI_AXI_ADC_REG_CHAN_STATUS(c) (0x0404 + (c) * 0x40) +#define ADI_AXI_ADC_CHAN_STAT_PN_MASK GENMASK(2, 1) + +#define ADI_AXI_ADC_REG_CHAN_CTRL_3(c) (0x0418 + (c) * 0x40) +#define ADI_AXI_ADC_CHAN_PN_SEL_MASK GENMASK(19, 16) + +/* IO Delays */ +#define ADI_AXI_ADC_REG_DELAY(l) (0x0800 + (l) * 0x4) +#define AXI_ADC_DELAY_CTRL_MASK GENMASK(4, 0) + +#define ADI_AXI_ADC_MAX_IO_NUM_LANES 15 + #define ADI_AXI_REG_CHAN_CTRL_DEFAULTS \ (ADI_AXI_REG_CHAN_CTRL_FMT_SIGNEXT | \ ADI_AXI_REG_CHAN_CTRL_FMT_EN | \ ADI_AXI_REG_CHAN_CTRL_ENABLE) struct adi_axi_adc_state { - struct regmap *regmap; - struct device *dev; + struct regmap *regmap; + struct device *dev; + /* lock to protect multiple accesses to the device registers */ + struct mutex lock; }; static int axi_adc_enable(struct iio_backend *back) @@ -104,6 +123,100 @@ static int axi_adc_data_format_set(struct iio_backend *back, unsigned int chan, ADI_AXI_REG_CHAN_CTRL_FMT_MASK, val); } +static int axi_adc_data_sample_trigger(struct iio_backend *back, + enum iio_backend_sample_trigger trigger) +{ + struct adi_axi_adc_state *st = iio_backend_get_priv(back); + + switch (trigger) { + case IIO_BACKEND_SAMPLE_TRIGGER_EDGE_RISING: + return regmap_clear_bits(st->regmap, ADI_AXI_ADC_REG_CTRL, + ADI_AXI_ADC_CTRL_DDR_EDGESEL_MASK); + case IIO_BACKEND_SAMPLE_TRIGGER_EDGE_FALLING: + return regmap_set_bits(st->regmap, ADI_AXI_ADC_REG_CTRL, + ADI_AXI_ADC_CTRL_DDR_EDGESEL_MASK); + default: + return -EINVAL; + } +} + +static int axi_adc_iodelays_set(struct iio_backend *back, unsigned int lane, + unsigned int tap) +{ + struct adi_axi_adc_state *st = iio_backend_get_priv(back); + int ret; + u32 val; + + if (tap > FIELD_MAX(AXI_ADC_DELAY_CTRL_MASK)) + return -EINVAL; + if (lane > ADI_AXI_ADC_MAX_IO_NUM_LANES) + return -EINVAL; + + guard(mutex)(&st->lock); + ret = regmap_write(st->regmap, ADI_AXI_ADC_REG_DELAY(lane), tap); + if (ret) + return ret; + /* + * If readback is ~0, that means there are issues with the + * delay_clk. + */ + ret = regmap_read(st->regmap, ADI_AXI_ADC_REG_DELAY(lane), &val); + if (ret) + return ret; + if (val == U32_MAX) + return -EIO; + + return 0; +} + +static int axi_adc_test_pattern_set(struct iio_backend *back, + unsigned int chan, + enum iio_backend_test_pattern pattern) +{ + struct adi_axi_adc_state *st = iio_backend_get_priv(back); + + switch (pattern) { + case IIO_BACKEND_NO_TEST_PATTERN: + /* nothing to do */ + return 0; + case IIO_BACKEND_ADI_PRBS_9A: + return regmap_update_bits(st->regmap, ADI_AXI_ADC_REG_CHAN_CTRL_3(chan), + ADI_AXI_ADC_CHAN_PN_SEL_MASK, + FIELD_PREP(ADI_AXI_ADC_CHAN_PN_SEL_MASK, 0)); + default: + return -EINVAL; + } +} + +static int axi_adc_chan_status(struct iio_backend *back, unsigned int chan, + bool *error) +{ + struct adi_axi_adc_state *st = iio_backend_get_priv(back); + int ret; + u32 val; + + guard(mutex)(&st->lock); + /* reset test bits by setting them */ + ret = regmap_write(st->regmap, ADI_AXI_ADC_REG_CHAN_STATUS(chan), + ADI_AXI_ADC_CHAN_STAT_PN_MASK); + if (ret) + return ret; + + /* let's give enough time to validate or erroring the incoming pattern */ + fsleep(1000); + + ret = regmap_read(st->regmap, ADI_AXI_ADC_REG_CHAN_STATUS(chan), &val); + if (ret) + return ret; + + if (ADI_AXI_ADC_CHAN_STAT_PN_MASK & val) + *error = true; + else + *error = false; + + return 0; +} + static int axi_adc_chan_enable(struct iio_backend *back, unsigned int chan) { struct adi_axi_adc_state *st = iio_backend_get_priv(back); @@ -152,6 +265,10 @@ static const struct iio_backend_ops adi_axi_adc_generic = { .chan_disable = axi_adc_chan_disable, .request_buffer = axi_adc_request_buffer, .free_buffer = axi_adc_free_buffer, + .data_sample_trigger = axi_adc_data_sample_trigger, + .iodelay_set = axi_adc_iodelays_set, + .test_pattern_set = axi_adc_test_pattern_set, + .chan_status = axi_adc_chan_status, }; static int adi_axi_adc_probe(struct platform_device *pdev) -- cgit v1.2.3-59-g8ed1b From 05c4081fbf4c98864dcf6c212afe9f611243dc92 Mon Sep 17 00:00:00 2001 From: Nuno Sa Date: Fri, 26 Apr 2024 17:42:16 +0200 Subject: iio: adc: ad9467: support digital interface calibration To make sure that we have the best timings on the serial data interface we should calibrate it. This means going through the device supported values and see for which ones we get a successful result. To do that, we use a prbs test pattern both in the IIO backend and in the frontend devices. Then for each of the test points we see if there are any errors. Note that the backend is responsible to look for those errors. As calibrating the interface also requires that the data format is disabled (the one thing being done in ad9467_setup()), ad9467_setup() was removed and configuring the data fomat is now part of the calibration process. Signed-off-by: Nuno Sa Link: https://lore.kernel.org/r/20240426-ad9467-new-features-v2-7-6361fc3ba1cc@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad9467.c | 374 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 335 insertions(+), 39 deletions(-) diff --git a/drivers/iio/adc/ad9467.c b/drivers/iio/adc/ad9467.c index 7475ec2a56c7..e85b763b9ffc 100644 --- a/drivers/iio/adc/ad9467.c +++ b/drivers/iio/adc/ad9467.c @@ -4,7 +4,11 @@ * * Copyright 2012-2020 Analog Devices Inc. */ + +#include +#include #include +#include #include #include #include @@ -100,6 +104,8 @@ #define AD9467_DEF_OUTPUT_MODE 0x08 #define AD9467_REG_VREF_MASK 0x0F +#define AD9647_MAX_TEST_POINTS 32 + struct ad9467_chip_info { const char *name; unsigned int id; @@ -110,6 +116,9 @@ struct ad9467_chip_info { unsigned long max_rate; unsigned int default_output_mode; unsigned int vref_mask; + unsigned int num_lanes; + /* data clock output */ + bool has_dco; }; struct ad9467_state { @@ -119,7 +128,16 @@ struct ad9467_state { struct clk *clk; unsigned int output_mode; unsigned int (*scales)[2]; - + /* + * Times 2 because we may also invert the signal polarity and run the + * calibration again. For some reference on the test points (ad9265) see: + * https://www.analog.com/media/en/technical-documentation/data-sheets/ad9265.pdf + * at page 38 for the dco output delay. On devices as ad9467, the + * calibration is done at the backend level. For the ADI axi-adc: + * https://wiki.analog.com/resources/fpga/docs/axi_adc_ip + * at the io delay control section. + */ + DECLARE_BITMAP(calib_map, AD9647_MAX_TEST_POINTS * 2); struct gpio_desc *pwrdown_gpio; /* ensure consistent state obtained on multiple related accesses */ struct mutex lock; @@ -242,6 +260,7 @@ static const struct ad9467_chip_info ad9467_chip_tbl = { .num_channels = ARRAY_SIZE(ad9467_channels), .default_output_mode = AD9467_DEF_OUTPUT_MODE, .vref_mask = AD9467_REG_VREF_MASK, + .num_lanes = 8, }; static const struct ad9467_chip_info ad9434_chip_tbl = { @@ -254,6 +273,7 @@ static const struct ad9467_chip_info ad9434_chip_tbl = { .num_channels = ARRAY_SIZE(ad9434_channels), .default_output_mode = AD9434_DEF_OUTPUT_MODE, .vref_mask = AD9434_REG_VREF_MASK, + .num_lanes = 6, }; static const struct ad9467_chip_info ad9265_chip_tbl = { @@ -266,6 +286,7 @@ static const struct ad9467_chip_info ad9265_chip_tbl = { .num_channels = ARRAY_SIZE(ad9467_channels), .default_output_mode = AD9265_DEF_OUTPUT_MODE, .vref_mask = AD9265_REG_VREF_MASK, + .has_dco = true, }; static int ad9467_get_scale(struct ad9467_state *st, int *val, int *val2) @@ -321,6 +342,246 @@ static int ad9467_set_scale(struct ad9467_state *st, int val, int val2) return -EINVAL; } +static int ad9467_outputmode_set(struct spi_device *spi, unsigned int mode) +{ + int ret; + + ret = ad9467_spi_write(spi, AN877_ADC_REG_OUTPUT_MODE, mode); + if (ret < 0) + return ret; + + return ad9467_spi_write(spi, AN877_ADC_REG_TRANSFER, + AN877_ADC_TRANSFER_SYNC); +} + +static int ad9647_calibrate_prepare(const struct ad9467_state *st) +{ + struct iio_backend_data_fmt data = { + .enable = false, + }; + unsigned int c; + int ret; + + ret = ad9467_spi_write(st->spi, AN877_ADC_REG_TEST_IO, + AN877_ADC_TESTMODE_PN9_SEQ); + if (ret) + return ret; + + ret = ad9467_spi_write(st->spi, AN877_ADC_REG_TRANSFER, + AN877_ADC_TRANSFER_SYNC); + if (ret) + return ret; + + ret = ad9467_outputmode_set(st->spi, st->info->default_output_mode); + if (ret) + return ret; + + for (c = 0; c < st->info->num_channels; c++) { + ret = iio_backend_data_format_set(st->back, c, &data); + if (ret) + return ret; + } + + ret = iio_backend_test_pattern_set(st->back, 0, + IIO_BACKEND_ADI_PRBS_9A); + if (ret) + return ret; + + return iio_backend_chan_enable(st->back, 0); +} + +static int ad9647_calibrate_polarity_set(const struct ad9467_state *st, + bool invert) +{ + enum iio_backend_sample_trigger trigger; + + if (st->info->has_dco) { + unsigned int phase = AN877_ADC_OUTPUT_EVEN_ODD_MODE_EN; + + if (invert) + phase |= AN877_ADC_INVERT_DCO_CLK; + + return ad9467_spi_write(st->spi, AN877_ADC_REG_OUTPUT_PHASE, + phase); + } + + if (invert) + trigger = IIO_BACKEND_SAMPLE_TRIGGER_EDGE_FALLING; + else + trigger = IIO_BACKEND_SAMPLE_TRIGGER_EDGE_RISING; + + return iio_backend_data_sample_trigger(st->back, trigger); +} + +/* + * The idea is pretty simple. Find the max number of successful points in a row + * and get the one in the middle. + */ +static unsigned int ad9467_find_optimal_point(const unsigned long *calib_map, + unsigned int start, + unsigned int nbits, + unsigned int *val) +{ + unsigned int bit = start, end, start_cnt, cnt = 0; + + for_each_clear_bitrange_from(bit, end, calib_map, nbits + start) { + if (end - bit > cnt) { + cnt = end - bit; + start_cnt = bit; + } + } + + if (cnt) + *val = start_cnt + cnt / 2; + + return cnt; +} + +static int ad9467_calibrate_apply(const struct ad9467_state *st, + unsigned int val) +{ + unsigned int lane; + int ret; + + if (st->info->has_dco) { + ret = ad9467_spi_write(st->spi, AN877_ADC_REG_OUTPUT_DELAY, + val); + if (ret) + return ret; + + return ad9467_spi_write(st->spi, AN877_ADC_REG_TRANSFER, + AN877_ADC_TRANSFER_SYNC); + } + + for (lane = 0; lane < st->info->num_lanes; lane++) { + ret = iio_backend_iodelay_set(st->back, lane, val); + if (ret) + return ret; + } + + return 0; +} + +static int ad9647_calibrate_stop(const struct ad9467_state *st) +{ + struct iio_backend_data_fmt data = { + .sign_extend = true, + .enable = true, + }; + unsigned int c, mode; + int ret; + + ret = iio_backend_chan_disable(st->back, 0); + if (ret) + return ret; + + ret = iio_backend_test_pattern_set(st->back, 0, + IIO_BACKEND_NO_TEST_PATTERN); + if (ret) + return ret; + + for (c = 0; c < st->info->num_channels; c++) { + ret = iio_backend_data_format_set(st->back, c, &data); + if (ret) + return ret; + } + + mode = st->info->default_output_mode | AN877_ADC_OUTPUT_MODE_TWOS_COMPLEMENT; + ret = ad9467_outputmode_set(st->spi, mode); + if (ret) + return ret; + + ret = ad9467_spi_write(st->spi, AN877_ADC_REG_TEST_IO, + AN877_ADC_TESTMODE_OFF); + if (ret) + return ret; + + return ad9467_spi_write(st->spi, AN877_ADC_REG_TRANSFER, + AN877_ADC_TRANSFER_SYNC); +} + +static int ad9467_calibrate(struct ad9467_state *st) +{ + unsigned int point, val, inv_val, cnt, inv_cnt = 0; + /* + * Half of the bitmap is for the inverted signal. The number of test + * points is the same though... + */ + unsigned int test_points = AD9647_MAX_TEST_POINTS; + unsigned long sample_rate = clk_get_rate(st->clk); + struct device *dev = &st->spi->dev; + bool invert = false, stat; + int ret; + + /* all points invalid */ + bitmap_fill(st->calib_map, BITS_PER_TYPE(st->calib_map)); + + ret = ad9647_calibrate_prepare(st); + if (ret) + return ret; +retune: + ret = ad9647_calibrate_polarity_set(st, invert); + if (ret) + return ret; + + for (point = 0; point < test_points; point++) { + ret = ad9467_calibrate_apply(st, point); + if (ret) + return ret; + + ret = iio_backend_chan_status(st->back, 0, &stat); + if (ret) + return ret; + + __assign_bit(point + invert * test_points, st->calib_map, stat); + } + + if (!invert) { + cnt = ad9467_find_optimal_point(st->calib_map, 0, test_points, + &val); + /* + * We're happy if we find, at least, three good test points in + * a row. + */ + if (cnt < 3) { + invert = true; + goto retune; + } + } else { + inv_cnt = ad9467_find_optimal_point(st->calib_map, test_points, + test_points, &inv_val); + if (!inv_cnt && !cnt) + return -EIO; + } + + if (inv_cnt < cnt) { + ret = ad9647_calibrate_polarity_set(st, false); + if (ret) + return ret; + } else { + /* + * polarity inverted is the last test to run. Hence, there's no + * need to re-do any configuration. We just need to "normalize" + * the selected value. + */ + val = inv_val - test_points; + } + + if (st->info->has_dco) + dev_dbg(dev, "%sDCO 0x%X CLK %lu Hz\n", inv_cnt >= cnt ? "INVERT " : "", + val, sample_rate); + else + dev_dbg(dev, "%sIDELAY 0x%x\n", inv_cnt >= cnt ? "INVERT " : "", + val); + + ret = ad9467_calibrate_apply(st, val); + if (ret) + return ret; + + /* finally apply the optimal value */ + return ad9647_calibrate_stop(st); +} + static int ad9467_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long m) @@ -345,7 +606,9 @@ static int ad9467_write_raw(struct iio_dev *indio_dev, { struct ad9467_state *st = iio_priv(indio_dev); const struct ad9467_chip_info *info = st->info; + unsigned long sample_rate; long r_clk; + int ret; switch (mask) { case IIO_CHAN_INFO_SCALE: @@ -358,7 +621,23 @@ static int ad9467_write_raw(struct iio_dev *indio_dev, return -EINVAL; } - return clk_set_rate(st->clk, r_clk); + sample_rate = clk_get_rate(st->clk); + /* + * clk_set_rate() would also do this but since we would still + * need it for avoiding an unnecessary calibration, do it now. + */ + if (sample_rate == r_clk) + return 0; + + iio_device_claim_direct_scoped(return -EBUSY, indio_dev) { + ret = clk_set_rate(st->clk, r_clk); + if (ret) + return ret; + + guard(mutex)(&st->lock); + ret = ad9467_calibrate(st); + } + return ret; default: return -EINVAL; } @@ -411,18 +690,6 @@ static const struct iio_info ad9467_info = { .read_avail = ad9467_read_avail, }; -static int ad9467_outputmode_set(struct spi_device *spi, unsigned int mode) -{ - int ret; - - ret = ad9467_spi_write(spi, AN877_ADC_REG_OUTPUT_MODE, mode); - if (ret < 0) - return ret; - - return ad9467_spi_write(spi, AN877_ADC_REG_TRANSFER, - AN877_ADC_TRANSFER_SYNC); -} - static int ad9467_scale_fill(struct ad9467_state *st) { const struct ad9467_chip_info *info = st->info; @@ -442,29 +709,6 @@ static int ad9467_scale_fill(struct ad9467_state *st) return 0; } -static int ad9467_setup(struct ad9467_state *st) -{ - struct iio_backend_data_fmt data = { - .sign_extend = true, - .enable = true, - }; - unsigned int c, mode; - int ret; - - mode = st->info->default_output_mode | AN877_ADC_OUTPUT_MODE_TWOS_COMPLEMENT; - ret = ad9467_outputmode_set(st->spi, mode); - if (ret) - return ret; - - for (c = 0; c < st->info->num_channels; c++) { - ret = iio_backend_data_format_set(st->back, c, &data); - if (ret) - return ret; - } - - return 0; -} - static int ad9467_reset(struct device *dev) { struct gpio_desc *gpio; @@ -521,6 +765,52 @@ static int ad9467_iio_backend_get(struct ad9467_state *st) return -ENODEV; } +static ssize_t ad9467_dump_calib_table(struct file *file, + char __user *userbuf, + size_t count, loff_t *ppos) +{ + struct ad9467_state *st = file->private_data; + unsigned int bit, size = BITS_PER_TYPE(st->calib_map); + /* +2 for the newline and +1 for the string termination */ + unsigned char map[AD9647_MAX_TEST_POINTS * 2 + 3]; + ssize_t len = 0; + + guard(mutex)(&st->lock); + if (*ppos) + goto out_read; + + for (bit = 0; bit < size; bit++) { + if (bit == size / 2) + len += scnprintf(map + len, sizeof(map) - len, "\n"); + + len += scnprintf(map + len, sizeof(map) - len, "%c", + test_bit(bit, st->calib_map) ? 'x' : 'o'); + } + + len += scnprintf(map + len, sizeof(map) - len, "\n"); +out_read: + return simple_read_from_buffer(userbuf, count, ppos, map, len); +} + +static const struct file_operations ad9467_calib_table_fops = { + .open = simple_open, + .read = ad9467_dump_calib_table, + .llseek = default_llseek, + .owner = THIS_MODULE, +}; + +static void ad9467_debugfs_init(struct iio_dev *indio_dev) +{ + struct dentry *d = iio_get_debugfs_dentry(indio_dev); + struct ad9467_state *st = iio_priv(indio_dev); + + if (!IS_ENABLED(CONFIG_DEBUG_FS)) + return; + + debugfs_create_file("calibration_table_dump", 0400, d, st, + &ad9467_calib_table_fops); +} + static int ad9467_probe(struct spi_device *spi) { struct iio_dev *indio_dev; @@ -580,11 +870,17 @@ static int ad9467_probe(struct spi_device *spi) if (ret) return ret; - ret = ad9467_setup(st); + ret = ad9467_calibrate(st); + if (ret) + return ret; + + ret = devm_iio_device_register(&spi->dev, indio_dev); if (ret) return ret; - return devm_iio_device_register(&spi->dev, indio_dev); + ad9467_debugfs_init(indio_dev); + + return 0; } static const struct of_device_id ad9467_of_match[] = { -- cgit v1.2.3-59-g8ed1b From 6a28a72ad2a4bbca81ef73f73bbc9190f4d9ab9c Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 28 Apr 2024 18:40:19 +0100 Subject: iio: adc: mcp3564: Use device_for_each_child_node_scoped() Switching to the _scoped() version removes the need for manual calling of fwnode_handle_put() in the paths where the code exits the loop early. In this case that's all in error paths. Reviewed-by: Marcelo Schmitt Reviewed-by: Marius Cristea Link: https://lore.kernel.org/r/20240428174020.1832825-2-jic23@kernel.org Signed-off-by: Jonathan Cameron --- drivers/iio/adc/mcp3564.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/drivers/iio/adc/mcp3564.c b/drivers/iio/adc/mcp3564.c index 311b613b6057..e2ae13f1e842 100644 --- a/drivers/iio/adc/mcp3564.c +++ b/drivers/iio/adc/mcp3564.c @@ -998,7 +998,6 @@ static int mcp3564_parse_fw_children(struct iio_dev *indio_dev) struct mcp3564_state *adc = iio_priv(indio_dev); struct device *dev = &adc->spi->dev; struct iio_chan_spec *channels; - struct fwnode_handle *child; struct iio_chan_spec chanspec = mcp3564_channel_template; struct iio_chan_spec temp_chanspec = mcp3564_temp_channel_template; struct iio_chan_spec burnout_chanspec = mcp3564_burnout_channel_template; @@ -1025,7 +1024,7 @@ static int mcp3564_parse_fw_children(struct iio_dev *indio_dev) if (!channels) return dev_err_probe(dev, -ENOMEM, "Can't allocate memory\n"); - device_for_each_child_node(dev, child) { + device_for_each_child_node_scoped(dev, child) { node_name = fwnode_get_name(child); if (fwnode_property_present(child, "diff-channels")) { @@ -1033,26 +1032,25 @@ static int mcp3564_parse_fw_children(struct iio_dev *indio_dev) "diff-channels", inputs, ARRAY_SIZE(inputs)); + if (ret) + return ret; + chanspec.differential = 1; } else { ret = fwnode_property_read_u32(child, "reg", &inputs[0]); + if (ret) + return ret; chanspec.differential = 0; inputs[1] = MCP3564_AGND; } - if (ret) { - fwnode_handle_put(child); - return ret; - } if (inputs[0] > MCP3564_INTERNAL_VCM || - inputs[1] > MCP3564_INTERNAL_VCM) { - fwnode_handle_put(child); + inputs[1] > MCP3564_INTERNAL_VCM) return dev_err_probe(&indio_dev->dev, -EINVAL, "Channel index > %d, for %s\n", MCP3564_INTERNAL_VCM + 1, node_name); - } chanspec.address = (inputs[0] << 4) | inputs[1]; chanspec.channel = inputs[0]; -- cgit v1.2.3-59-g8ed1b From da8cf0d7327f148d2847f58ae17a4dd6aac6b5bf Mon Sep 17 00:00:00 2001 From: Gustavo Rodrigues Date: Sun, 28 Apr 2024 16:43:24 -0300 Subject: iio: adc: ad799x: change 'unsigned' to 'unsigned int' declaration Prefer 'unsigned int' instead of bare use of 'unsigned' declarations to to improve code readbility. This ceases one of the warning messages pointed by checkpatch. Co-developed-by: Bruna Lopes Signed-off-by: Bruna Lopes Signed-off-by: Gustavo Rodrigues Reviewed-by: Nuno Sa Link: https://lore.kernel.org/r/20240428194326.2836387-2-ogustavo@usp.br Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad799x.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/iio/adc/ad799x.c b/drivers/iio/adc/ad799x.c index b757cc45c4de..3040575793a2 100644 --- a/drivers/iio/adc/ad799x.c +++ b/drivers/iio/adc/ad799x.c @@ -128,7 +128,7 @@ struct ad799x_state { struct regulator *vref; /* lock to protect against multiple access to the device */ struct mutex lock; - unsigned id; + unsigned int id; u16 config; u8 *rx_buf; @@ -253,7 +253,7 @@ static int ad799x_update_scan_mode(struct iio_dev *indio_dev, } } -static int ad799x_scan_direct(struct ad799x_state *st, unsigned ch) +static int ad799x_scan_direct(struct ad799x_state *st, unsigned int ch) { u8 cmd; -- cgit v1.2.3-59-g8ed1b From 0fb3e211acf0b60e6987831136986bc5a664b6d7 Mon Sep 17 00:00:00 2001 From: Gustavo Rodrigues Date: Sun, 28 Apr 2024 16:43:25 -0300 Subject: iio: adc: ad799x: add blank line to avoid warning messages Add a blank line before if statement to avoid warning messages pointed by checkpatch. Co-developed-by: Bruna Lopes Signed-off-by: Bruna Lopes Signed-off-by: Gustavo Rodrigues Reviewed-by: Nuno Sa Link: https://lore.kernel.org/r/20240428194326.2836387-3-ogustavo@usp.br Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad799x.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/iio/adc/ad799x.c b/drivers/iio/adc/ad799x.c index 3040575793a2..9a12e562c259 100644 --- a/drivers/iio/adc/ad799x.c +++ b/drivers/iio/adc/ad799x.c @@ -335,6 +335,7 @@ static ssize_t ad799x_read_frequency(struct device *dev, struct ad799x_state *st = iio_priv(indio_dev); int ret = i2c_smbus_read_byte_data(st->client, AD7998_CYCLE_TMR_REG); + if (ret < 0) return ret; -- cgit v1.2.3-59-g8ed1b From 80f87d6bbc6ddcc47969c996649e8a995587e7ae Mon Sep 17 00:00:00 2001 From: Gustavo Rodrigues Date: Sun, 28 Apr 2024 16:43:26 -0300 Subject: iio: adc: ad799x: Prefer to use octal permission Octal permissions are preferred over the symbolics ones for readbility. This ceases warning message pointed by checkpatch. Co-developed-by: Bruna Lopes Signed-off-by: Bruna Lopes Signed-off-by: Gustavo Rodrigues Reviewed-by: Nuno Sa Link: https://lore.kernel.org/r/20240428194326.2836387-4-ogustavo@usp.br Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad799x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/adc/ad799x.c b/drivers/iio/adc/ad799x.c index 9a12e562c259..0f0dcd9ca6b6 100644 --- a/drivers/iio/adc/ad799x.c +++ b/drivers/iio/adc/ad799x.c @@ -524,7 +524,7 @@ done: return IRQ_HANDLED; } -static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_SAMP_FREQ(0644, ad799x_read_frequency, ad799x_write_frequency); static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("15625 7812 3906 1953 976 488 244 0"); -- cgit v1.2.3-59-g8ed1b From d1648883355a25488836daf1ca26e10577c2c50c Mon Sep 17 00:00:00 2001 From: Lincoln Yuji Date: Mon, 29 Apr 2024 10:22:33 -0300 Subject: iio: adc: ti-ads1015: use device_for_each_child_node_scoped() This loop definition removes the need for manual releasing of the fwnode_handle in early exit paths (here an error path) allow simplification of the code and reducing the chance of future modifications not releasing fwnode_handle correctly. Co-developed-by: Luiza Soezima Signed-off-by: Luiza Soezima Co-developed-by: Sabrina Araujo Signed-off-by: Sabrina Araujo Signed-off-by: Lincoln Yuji Reviewed-by: Marcelo Schmitt Link: https://lore.kernel.org/r/20240429132233.6266-1-lincolnyuji@usp.br Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ti-ads1015.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/iio/adc/ti-ads1015.c b/drivers/iio/adc/ti-ads1015.c index 6ae967e4d8fa..d3363d02f292 100644 --- a/drivers/iio/adc/ti-ads1015.c +++ b/drivers/iio/adc/ti-ads1015.c @@ -902,10 +902,9 @@ static int ads1015_client_get_channels_config(struct i2c_client *client) struct iio_dev *indio_dev = i2c_get_clientdata(client); struct ads1015_data *data = iio_priv(indio_dev); struct device *dev = &client->dev; - struct fwnode_handle *node; int i = -1; - device_for_each_child_node(dev, node) { + device_for_each_child_node_scoped(dev, node) { u32 pval; unsigned int channel; unsigned int pga = ADS1015_DEFAULT_PGA; @@ -927,7 +926,6 @@ static int ads1015_client_get_channels_config(struct i2c_client *client) pga = pval; if (pga > 5) { dev_err(dev, "invalid gain on %pfw\n", node); - fwnode_handle_put(node); return -EINVAL; } } @@ -936,7 +934,6 @@ static int ads1015_client_get_channels_config(struct i2c_client *client) data_rate = pval; if (data_rate > 7) { dev_err(dev, "invalid data_rate on %pfw\n", node); - fwnode_handle_put(node); return -EINVAL; } } -- cgit v1.2.3-59-g8ed1b From 4d68b25c642186e14223ea38bbdf2216d7e13519 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 29 Apr 2024 13:33:04 +0200 Subject: iio: adc: ad_sigma_delta: use 'time_left' variable with wait_for_completion_timeout() There is a confusing pattern in the kernel to use a variable named 'timeout' to store the result of wait_for_completion_timeout() causing patterns like: timeout = wait_for_completion_timeout(...) if (!timeout) return -ETIMEDOUT; with all kinds of permutations. Use 'time_left' as a variable to make the code self explaining. Signed-off-by: Wolfram Sang Reviewed-by: Nuno Sa Link: https://lore.kernel.org/r/20240429113313.68359-2-wsa+renesas@sang-engineering.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad_sigma_delta.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/iio/adc/ad_sigma_delta.c b/drivers/iio/adc/ad_sigma_delta.c index 97a05f325df7..a2b87f6b7a07 100644 --- a/drivers/iio/adc/ad_sigma_delta.c +++ b/drivers/iio/adc/ad_sigma_delta.c @@ -206,7 +206,7 @@ int ad_sd_calibrate(struct ad_sigma_delta *sigma_delta, unsigned int mode, unsigned int channel) { int ret; - unsigned long timeout; + unsigned long time_left; ret = ad_sigma_delta_set_channel(sigma_delta, channel); if (ret) @@ -223,8 +223,8 @@ int ad_sd_calibrate(struct ad_sigma_delta *sigma_delta, sigma_delta->irq_dis = false; enable_irq(sigma_delta->irq_line); - timeout = wait_for_completion_timeout(&sigma_delta->completion, 2 * HZ); - if (timeout == 0) { + time_left = wait_for_completion_timeout(&sigma_delta->completion, 2 * HZ); + if (time_left == 0) { sigma_delta->irq_dis = true; disable_irq_nosync(sigma_delta->irq_line); ret = -EIO; -- cgit v1.2.3-59-g8ed1b From 860e36b7023580068e1857262a7f25a1836fc30b Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 29 Apr 2024 13:33:05 +0200 Subject: iio: adc: exynos_adc: use 'time_left' variable with wait_for_completion_timeout() There is a confusing pattern in the kernel to use a variable named 'timeout' to store the result of wait_for_completion_timeout() causing patterns like: timeout = wait_for_completion_timeout(...) if (!timeout) return -ETIMEDOUT; with all kinds of permutations. Use 'time_left' as a variable to make the code self explaining. Signed-off-by: Wolfram Sang Link: https://lore.kernel.org/r/20240429113313.68359-3-wsa+renesas@sang-engineering.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/exynos_adc.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/iio/adc/exynos_adc.c b/drivers/iio/adc/exynos_adc.c index 614de9644800..78fada4b7b1c 100644 --- a/drivers/iio/adc/exynos_adc.c +++ b/drivers/iio/adc/exynos_adc.c @@ -538,7 +538,7 @@ static int exynos_read_raw(struct iio_dev *indio_dev, long mask) { struct exynos_adc *info = iio_priv(indio_dev); - unsigned long timeout; + unsigned long time_left; int ret; if (mask == IIO_CHAN_INFO_SCALE) { @@ -562,9 +562,9 @@ static int exynos_read_raw(struct iio_dev *indio_dev, if (info->data->start_conv) info->data->start_conv(info, chan->address); - timeout = wait_for_completion_timeout(&info->completion, - EXYNOS_ADC_TIMEOUT); - if (timeout == 0) { + time_left = wait_for_completion_timeout(&info->completion, + EXYNOS_ADC_TIMEOUT); + if (time_left == 0) { dev_warn(&indio_dev->dev, "Conversion timed out! Resetting\n"); if (info->data->init_hw) info->data->init_hw(info); @@ -583,7 +583,7 @@ static int exynos_read_raw(struct iio_dev *indio_dev, static int exynos_read_s3c64xx_ts(struct iio_dev *indio_dev, int *x, int *y) { struct exynos_adc *info = iio_priv(indio_dev); - unsigned long timeout; + unsigned long time_left; int ret; mutex_lock(&info->lock); @@ -597,9 +597,9 @@ static int exynos_read_s3c64xx_ts(struct iio_dev *indio_dev, int *x, int *y) /* Select the ts channel to be used and Trigger conversion */ info->data->start_conv(info, ADC_S3C2410_MUX_TS); - timeout = wait_for_completion_timeout(&info->completion, - EXYNOS_ADC_TIMEOUT); - if (timeout == 0) { + time_left = wait_for_completion_timeout(&info->completion, + EXYNOS_ADC_TIMEOUT); + if (time_left == 0) { dev_warn(&indio_dev->dev, "Conversion timed out! Resetting\n"); if (info->data->init_hw) info->data->init_hw(info); -- cgit v1.2.3-59-g8ed1b From 265b81bb7578d5c30866932cab5acde5a9fa0df0 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 29 Apr 2024 13:33:06 +0200 Subject: iio: adc: fsl-imx25-gcq: use 'time_left' variable with wait_for_completion_interruptible_timeout() There is a confusing pattern in the kernel to use a variable named 'timeout' to store the result of wait_for_completion_interruptible_timeout() causing patterns like: timeout = wait_for_completion_interruptible_timeout(...) if (!timeout) return -ETIMEDOUT; with all kinds of permutations. Use 'time_left' as a variable to make the code self explaining. Signed-off-by: Wolfram Sang Link: https://lore.kernel.org/r/20240429113313.68359-4-wsa+renesas@sang-engineering.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/fsl-imx25-gcq.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/iio/adc/fsl-imx25-gcq.c b/drivers/iio/adc/fsl-imx25-gcq.c index 394396b91630..b680690631db 100644 --- a/drivers/iio/adc/fsl-imx25-gcq.c +++ b/drivers/iio/adc/fsl-imx25-gcq.c @@ -108,7 +108,7 @@ static int mx25_gcq_get_raw_value(struct device *dev, struct mx25_gcq_priv *priv, int *val) { - long timeout; + long time_left; u32 data; /* Setup the configuration we want to use */ @@ -121,12 +121,12 @@ static int mx25_gcq_get_raw_value(struct device *dev, regmap_update_bits(priv->regs, MX25_ADCQ_CR, MX25_ADCQ_CR_FQS, MX25_ADCQ_CR_FQS); - timeout = wait_for_completion_interruptible_timeout( + time_left = wait_for_completion_interruptible_timeout( &priv->completed, MX25_GCQ_TIMEOUT); - if (timeout < 0) { + if (time_left < 0) { dev_err(dev, "ADC wait for measurement failed\n"); - return timeout; - } else if (timeout == 0) { + return time_left; + } else if (time_left == 0) { dev_err(dev, "ADC timed out\n"); return -ETIMEDOUT; } -- cgit v1.2.3-59-g8ed1b From 1fa9d4a0a4ad6ff98f4d96e98161dcd4e4b7e039 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 29 Apr 2024 13:33:07 +0200 Subject: iio: adc: intel_mrfld_adc: use 'time_left' variable with wait_for_completion_interruptible_timeout() There is a confusing pattern in the kernel to use a variable named 'timeout' to store the result of wait_for_completion_interruptible_timeout() causing patterns like: timeout = wait_for_completion_interruptible_timeout(...) if (!timeout) return -ETIMEDOUT; with all kinds of permutations. Use 'time_left' as a variable to make the code self explaining. Signed-off-by: Wolfram Sang Link: https://lore.kernel.org/r/20240429113313.68359-5-wsa+renesas@sang-engineering.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/intel_mrfld_adc.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/iio/adc/intel_mrfld_adc.c b/drivers/iio/adc/intel_mrfld_adc.c index 7263ad76124d..c7f40ae6e608 100644 --- a/drivers/iio/adc/intel_mrfld_adc.c +++ b/drivers/iio/adc/intel_mrfld_adc.c @@ -75,7 +75,7 @@ static int mrfld_adc_single_conv(struct iio_dev *indio_dev, struct mrfld_adc *adc = iio_priv(indio_dev); struct regmap *regmap = adc->regmap; unsigned int req; - long timeout; + long time_left; __be16 value; int ret; @@ -95,13 +95,13 @@ static int mrfld_adc_single_conv(struct iio_dev *indio_dev, if (ret) goto done; - timeout = wait_for_completion_interruptible_timeout(&adc->completion, - BCOVE_ADC_TIMEOUT); - if (timeout < 0) { - ret = timeout; + time_left = wait_for_completion_interruptible_timeout(&adc->completion, + BCOVE_ADC_TIMEOUT); + if (time_left < 0) { + ret = time_left; goto done; } - if (timeout == 0) { + if (time_left == 0) { ret = -ETIMEDOUT; goto done; } -- cgit v1.2.3-59-g8ed1b From 3cd191fce83726c39b74515820b3ec8f23e1768b Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 29 Apr 2024 13:33:08 +0200 Subject: iio: adc: stm32-adc: use 'time_left' variable with wait_for_completion_interruptible_timeout() There is a confusing pattern in the kernel to use a variable named 'timeout' to store the result of wait_for_completion_interruptible_timeout() causing patterns like: timeout = wait_for_completion_interruptible_timeout(...) if (!timeout) return -ETIMEDOUT; with all kinds of permutations. Use 'time_left' as a variable to make the code self explaining. Signed-off-by: Wolfram Sang Link: https://lore.kernel.org/r/20240429113313.68359-6-wsa+renesas@sang-engineering.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/stm32-adc.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c index 36add95212c3..375aa7720f80 100644 --- a/drivers/iio/adc/stm32-adc.c +++ b/drivers/iio/adc/stm32-adc.c @@ -1408,7 +1408,7 @@ static int stm32_adc_single_conv(struct iio_dev *indio_dev, struct stm32_adc *adc = iio_priv(indio_dev); struct device *dev = indio_dev->dev.parent; const struct stm32_adc_regspec *regs = adc->cfg->regs; - long timeout; + long time_left; u32 val; int ret; @@ -1440,12 +1440,12 @@ static int stm32_adc_single_conv(struct iio_dev *indio_dev, adc->cfg->start_conv(indio_dev, false); - timeout = wait_for_completion_interruptible_timeout( + time_left = wait_for_completion_interruptible_timeout( &adc->completion, STM32_ADC_TIMEOUT); - if (timeout == 0) { + if (time_left == 0) { ret = -ETIMEDOUT; - } else if (timeout < 0) { - ret = timeout; + } else if (time_left < 0) { + ret = time_left; } else { *res = adc->buffer[0]; ret = IIO_VAL_INT; -- cgit v1.2.3-59-g8ed1b From 2f62fd78a14500973d757acb2ebf1b831f708efb Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 29 Apr 2024 13:33:09 +0200 Subject: iio: adc: stm32-dfsdm-adc: use 'time_left' variable with wait_for_completion_interruptible_timeout() There is a confusing pattern in the kernel to use a variable named 'timeout' to store the result of wait_for_completion_interruptible_timeout() causing patterns like: timeout = wait_for_completion_interruptible_timeout(...) if (!timeout) return -ETIMEDOUT; with all kinds of permutations. Use 'time_left' as a variable to make the code self explaining. Signed-off-by: Wolfram Sang Link: https://lore.kernel.org/r/20240429113313.68359-7-wsa+renesas@sang-engineering.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/stm32-dfsdm-adc.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/iio/adc/stm32-dfsdm-adc.c b/drivers/iio/adc/stm32-dfsdm-adc.c index ca08ae3108b2..9a47d2c87f05 100644 --- a/drivers/iio/adc/stm32-dfsdm-adc.c +++ b/drivers/iio/adc/stm32-dfsdm-adc.c @@ -1116,7 +1116,7 @@ static int stm32_dfsdm_single_conv(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, int *res) { struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); - long timeout; + long time_left; int ret; reinit_completion(&adc->completion); @@ -1141,17 +1141,17 @@ static int stm32_dfsdm_single_conv(struct iio_dev *indio_dev, goto stop_dfsdm; } - timeout = wait_for_completion_interruptible_timeout(&adc->completion, - DFSDM_TIMEOUT); + time_left = wait_for_completion_interruptible_timeout(&adc->completion, + DFSDM_TIMEOUT); /* Mask IRQ for regular conversion achievement*/ regmap_update_bits(adc->dfsdm->regmap, DFSDM_CR2(adc->fl_id), DFSDM_CR2_REOCIE_MASK, DFSDM_CR2_REOCIE(0)); - if (timeout == 0) + if (time_left == 0) ret = -ETIMEDOUT; - else if (timeout < 0) - ret = timeout; + else if (time_left < 0) + ret = time_left; else ret = IIO_VAL_INT; -- cgit v1.2.3-59-g8ed1b From b0329b3c7ecaaa9a7ebc9fa2c5cdf53fad17ddc9 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 29 Apr 2024 13:33:10 +0200 Subject: iio: adc: twl6030-gpadc: use 'time_left' variable with wait_for_completion_interruptible_timeout() There is a confusing pattern in the kernel to use a variable named 'timeout' to store the result of wait_for_completion_interruptible_timeout() causing patterns like: timeout = wait_for_completion_interruptible_timeout(...) if (!timeout) return -ETIMEDOUT; with all kinds of permutations. Use 'time_left' as a variable to make the code self explaining. Signed-off-by: Wolfram Sang Link: https://lore.kernel.org/r/20240429113313.68359-8-wsa+renesas@sang-engineering.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/twl6030-gpadc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/iio/adc/twl6030-gpadc.c b/drivers/iio/adc/twl6030-gpadc.c index 78bf55438b2c..6a3db2bce460 100644 --- a/drivers/iio/adc/twl6030-gpadc.c +++ b/drivers/iio/adc/twl6030-gpadc.c @@ -519,7 +519,7 @@ static int twl6030_gpadc_read_raw(struct iio_dev *indio_dev, { struct twl6030_gpadc_data *gpadc = iio_priv(indio_dev); int ret; - long timeout; + long time_left; mutex_lock(&gpadc->lock); @@ -529,12 +529,12 @@ static int twl6030_gpadc_read_raw(struct iio_dev *indio_dev, goto err; } /* wait for conversion to complete */ - timeout = wait_for_completion_interruptible_timeout( + time_left = wait_for_completion_interruptible_timeout( &gpadc->irq_complete, msecs_to_jiffies(5000)); - if (timeout == 0) { + if (time_left == 0) { ret = -ETIMEDOUT; goto err; - } else if (timeout < 0) { + } else if (time_left < 0) { ret = -EINTR; goto err; } -- cgit v1.2.3-59-g8ed1b From 8d0c93761606ffc97af0cd00901579c5972017ca Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 29 Apr 2024 13:33:11 +0200 Subject: iio: pressure: zpa2326: use 'time_left' variable with wait_for_completion_interruptible_timeout() There is a confusing pattern in the kernel to use a variable named 'timeout' to store the result of wait_for_completion_interruptible_timeout() causing patterns like: timeout = wait_for_completion_interruptible_timeout(...) if (!timeout) return -ETIMEDOUT; with all kinds of permutations. Use 'time_left' as a variable to make the code self explaining. Signed-off-by: Wolfram Sang Link: https://lore.kernel.org/r/20240429113313.68359-9-wsa+renesas@sang-engineering.com Signed-off-by: Jonathan Cameron --- drivers/iio/pressure/zpa2326.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/iio/pressure/zpa2326.c b/drivers/iio/pressure/zpa2326.c index 421e059d1f19..dcc87a9015e8 100644 --- a/drivers/iio/pressure/zpa2326.c +++ b/drivers/iio/pressure/zpa2326.c @@ -861,13 +861,13 @@ static int zpa2326_wait_oneshot_completion(const struct iio_dev *indio_dev, struct zpa2326_private *private) { unsigned int val; - long timeout; + long time_left; zpa2326_dbg(indio_dev, "waiting for one shot completion interrupt"); - timeout = wait_for_completion_interruptible_timeout( + time_left = wait_for_completion_interruptible_timeout( &private->data_ready, ZPA2326_CONVERSION_JIFFIES); - if (timeout > 0) + if (time_left > 0) /* * Interrupt handler completed before timeout: return operation * status. @@ -877,10 +877,10 @@ static int zpa2326_wait_oneshot_completion(const struct iio_dev *indio_dev, /* Clear all interrupts just to be sure. */ regmap_read(private->regmap, ZPA2326_INT_SOURCE_REG, &val); - if (!timeout) { + if (!time_left) { /* Timed out. */ zpa2326_warn(indio_dev, "no one shot interrupt occurred (%ld)", - timeout); + time_left); return -ETIME; } -- cgit v1.2.3-59-g8ed1b From 561e2e3e90b4307f9a47a6382fa5cd15462aacf9 Mon Sep 17 00:00:00 2001 From: Nuno Sa Date: Mon, 29 Apr 2024 15:54:39 +0200 Subject: iio: dac: ad9739a: write complete MU_CNT1 register during lock As specified by the datasheet we should write the value 0x3 (enable plus tracking gain) into the MU_CNT1 register during the MU lock phase. Currently we were only setting the enable bit (bit 0) as the tracking gain default value is already set to 1. While we should be mostly fine in assuming the tracking gain will have the value it should, better to explicitly write it. On top of that the datasheet also states to re-attempt the writes in case the lock fails which we were not doing for the tracking gain bit. Lastly, the recommended value for the MU phase slope lock (bit 6) is 0 but for some reason the default value is 1 and hence, we were not changing it accordingly. Note there was no problem with the MU lock mechanism so this is not being treated as a fix but rather an improvement. Signed-off-by: Nuno Sa Link: https://lore.kernel.org/r/20240429-ad9739a-improv-v1-1-c076a06a697d@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/dac/ad9739a.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/iio/dac/ad9739a.c b/drivers/iio/dac/ad9739a.c index ff33120075bf..f56eabe53723 100644 --- a/drivers/iio/dac/ad9739a.c +++ b/drivers/iio/dac/ad9739a.c @@ -45,6 +45,7 @@ #define AD9739A_REG_MU_DUTY 0x25 #define AD9739A_REG_MU_CNT1 0x26 #define AD9739A_MU_EN_MASK BIT(0) +#define AD9739A_MU_GAIN_MASK BIT(1) #define AD9739A_REG_MU_CNT2 0x27 #define AD9739A_REG_MU_CNT3 0x28 #define AD9739A_REG_MU_CNT4 0x29 @@ -220,8 +221,8 @@ static int ad9739a_init(struct device *dev, const struct ad9739a_state *st) return ret; /* Enable the Mu controller search and track mode. */ - ret = regmap_set_bits(st->regmap, AD9739A_REG_MU_CNT1, - AD9739A_MU_EN_MASK); + ret = regmap_write(st->regmap, AD9739A_REG_MU_CNT1, + AD9739A_MU_EN_MASK | AD9739A_MU_GAIN_MASK); if (ret) return ret; -- cgit v1.2.3-59-g8ed1b From f95bab86106ee5b180b197a68246282b56ef5d8a Mon Sep 17 00:00:00 2001 From: Tiwei Bie Date: Wed, 6 Mar 2024 18:19:22 +0800 Subject: um: Stop tracking host PID in cpu_tasks The host PID tracked in 'cpu_tasks' is no longer used. Stopping tracking it will also save some cycles. Signed-off-by: Tiwei Bie Signed-off-by: Richard Weinberger --- arch/um/include/shared/as-layout.h | 1 - arch/um/kernel/process.c | 12 ++---------- arch/um/kernel/skas/process.c | 4 ---- 3 files changed, 2 insertions(+), 15 deletions(-) diff --git a/arch/um/include/shared/as-layout.h b/arch/um/include/shared/as-layout.h index 9ec3015bc5e2..c22f46a757dc 100644 --- a/arch/um/include/shared/as-layout.h +++ b/arch/um/include/shared/as-layout.h @@ -31,7 +31,6 @@ #include struct cpu_task { - int pid; void *task; }; diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c index e5d7d24045a2..d2134802f6a8 100644 --- a/arch/um/kernel/process.c +++ b/arch/um/kernel/process.c @@ -43,13 +43,7 @@ * cares about its entry, so it's OK if another processor is modifying its * entry. */ -struct cpu_task cpu_tasks[NR_CPUS] = { [0 ... NR_CPUS - 1] = { -1, NULL } }; - -static inline int external_pid(void) -{ - /* FIXME: Need to look up userspace_pid by cpu */ - return userspace_pid[0]; -} +struct cpu_task cpu_tasks[NR_CPUS] = { [0 ... NR_CPUS - 1] = { NULL } }; void free_stack(unsigned long stack, int order) { @@ -70,8 +64,7 @@ unsigned long alloc_stack(int order, int atomic) static inline void set_current(struct task_struct *task) { - cpu_tasks[task_thread_info(task)->cpu] = ((struct cpu_task) - { external_pid(), task }); + cpu_tasks[task_thread_info(task)->cpu] = ((struct cpu_task) { task }); } struct task_struct *__switch_to(struct task_struct *from, struct task_struct *to) @@ -206,7 +199,6 @@ void um_idle_sleep(void) void arch_cpu_idle(void) { - cpu_tasks[current_thread_info()->cpu].pid = os_getpid(); um_idle_sleep(); } diff --git a/arch/um/kernel/skas/process.c b/arch/um/kernel/skas/process.c index fdd5922f9222..99a5cbb36083 100644 --- a/arch/um/kernel/skas/process.c +++ b/arch/um/kernel/skas/process.c @@ -18,12 +18,8 @@ extern void start_kernel(void); static int __init start_kernel_proc(void *unused) { - int pid; - block_signals_trace(); - pid = os_getpid(); - cpu_tasks[0].pid = pid; cpu_tasks[0].task = current; start_kernel(); -- cgit v1.2.3-59-g8ed1b From 323ced9669a8f70a9ae707cfe46f852ca23ed23e Mon Sep 17 00:00:00 2001 From: Tiwei Bie Date: Tue, 23 Apr 2024 20:58:52 +0800 Subject: um: Fix -Wmissing-prototypes warnings for (rt_)sigreturn MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use SYSCALL_DEFINE0 to define (rt_)sigreturn. This will address below -Wmissing-prototypes warnings: arch/x86/um/signal.c:453:6: warning: no previous prototype for ‘sys_sigreturn’ [-Wmissing-prototypes] arch/x86/um/signal.c:560:6: warning: no previous prototype for ‘sys_rt_sigreturn’ [-Wmissing-prototypes] Signed-off-by: Tiwei Bie Signed-off-by: Richard Weinberger --- arch/x86/um/signal.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/x86/um/signal.c b/arch/x86/um/signal.c index 16ff097e790d..2cc8c2309022 100644 --- a/arch/x86/um/signal.c +++ b/arch/x86/um/signal.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -449,7 +450,7 @@ int setup_signal_stack_si(unsigned long stack_top, struct ksignal *ksig, return 0; } -long sys_sigreturn(void) +SYSCALL_DEFINE0(sigreturn) { unsigned long sp = PT_REGS_SP(¤t->thread.regs); struct sigframe __user *frame = (struct sigframe __user *)(sp - 8); @@ -556,7 +557,7 @@ int setup_signal_stack_si(unsigned long stack_top, struct ksignal *ksig, } #endif -long sys_rt_sigreturn(void) +SYSCALL_DEFINE0(rt_sigreturn) { unsigned long sp = PT_REGS_SP(¤t->thread.regs); struct rt_sigframe __user *frame = -- cgit v1.2.3-59-g8ed1b From 2cbade17b18c0f0fd9963f26c9fc9b057eb1cb3a Mon Sep 17 00:00:00 2001 From: Tiwei Bie Date: Tue, 23 Apr 2024 20:58:53 +0800 Subject: um: Fix the -Wmissing-prototypes warning for __switch_mm The __switch_mm function is defined in the user code, and is called by the kernel code. It should be declared in a shared header. Fixes: 4dc706c2f292 ("um: take um_mmu.h to asm/mmu.h, clean asm/mmu_context.h a bit") Signed-off-by: Tiwei Bie Signed-off-by: Richard Weinberger --- arch/um/include/asm/mmu.h | 2 -- arch/um/include/shared/skas/mm_id.h | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/um/include/asm/mmu.h b/arch/um/include/asm/mmu.h index a7555e43ed14..f2923c767bb9 100644 --- a/arch/um/include/asm/mmu.h +++ b/arch/um/include/asm/mmu.h @@ -14,8 +14,6 @@ typedef struct mm_context { struct uml_arch_mm_context arch; } mm_context_t; -extern void __switch_mm(struct mm_id * mm_idp); - /* Avoid tangled inclusion with asm/ldt.h */ extern long init_new_ldt(struct mm_context *to_mm, struct mm_context *from_mm); extern void free_ldt(struct mm_context *mm); diff --git a/arch/um/include/shared/skas/mm_id.h b/arch/um/include/shared/skas/mm_id.h index e82e203f5f41..92dbf727e384 100644 --- a/arch/um/include/shared/skas/mm_id.h +++ b/arch/um/include/shared/skas/mm_id.h @@ -15,4 +15,6 @@ struct mm_id { int kill; }; +void __switch_mm(struct mm_id *mm_idp); + #endif -- cgit v1.2.3-59-g8ed1b From 3144013e48f4f6e5127223c4ebc488016815dedb Mon Sep 17 00:00:00 2001 From: Tiwei Bie Date: Tue, 23 Apr 2024 20:58:54 +0800 Subject: um: Fix the -Wmissing-prototypes warning for get_thread_reg The get_thread_reg function is defined in the user code, and is called by the kernel code. It should be declared in a shared header. Fixes: dbba7f704aa0 ("um: stop polluting the namespace with registers.h contents") Signed-off-by: Tiwei Bie Signed-off-by: Richard Weinberger --- arch/um/include/asm/processor-generic.h | 1 - arch/x86/um/shared/sysdep/archsetjmp.h | 7 +++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/arch/um/include/asm/processor-generic.h b/arch/um/include/asm/processor-generic.h index 6c3779541845..5a7c05275aa7 100644 --- a/arch/um/include/asm/processor-generic.h +++ b/arch/um/include/asm/processor-generic.h @@ -94,7 +94,6 @@ extern struct cpuinfo_um boot_cpu_data; #define current_cpu_data boot_cpu_data #define cache_line_size() (boot_cpu_data.cache_alignment) -extern unsigned long get_thread_reg(int reg, jmp_buf *buf); #define KSTK_REG(tsk, reg) get_thread_reg(reg, &tsk->thread.switch_buf) extern unsigned long __get_wchan(struct task_struct *p); diff --git a/arch/x86/um/shared/sysdep/archsetjmp.h b/arch/x86/um/shared/sysdep/archsetjmp.h index 166cedbab926..8c81d1a604a9 100644 --- a/arch/x86/um/shared/sysdep/archsetjmp.h +++ b/arch/x86/um/shared/sysdep/archsetjmp.h @@ -1,6 +1,13 @@ /* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __X86_UM_SYSDEP_ARCHSETJMP_H +#define __X86_UM_SYSDEP_ARCHSETJMP_H + #ifdef __i386__ #include "archsetjmp_32.h" #else #include "archsetjmp_64.h" #endif + +unsigned long get_thread_reg(int reg, jmp_buf *buf); + +#endif /* __X86_UM_SYSDEP_ARCHSETJMP_H */ -- cgit v1.2.3-59-g8ed1b From 6a85e34c4d07d2ec0c153067baff338ac0db55ca Mon Sep 17 00:00:00 2001 From: Tiwei Bie Date: Tue, 23 Apr 2024 20:58:55 +0800 Subject: um: Fix the declaration of kasan_map_memory Make it match its definition (size_t vs unsigned long). And declare it in a shared header to fix the -Wmissing-prototypes warning, as it is defined in the user code and called in the kernel code. Fixes: 5b301409e8bc ("UML: add support for KASAN under x86_64") Signed-off-by: Tiwei Bie Signed-off-by: Richard Weinberger --- arch/um/include/asm/kasan.h | 1 - arch/um/include/shared/kern_util.h | 2 ++ arch/um/os-Linux/mem.c | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/um/include/asm/kasan.h b/arch/um/include/asm/kasan.h index 0d6547f4ec85..f97bb1f7b851 100644 --- a/arch/um/include/asm/kasan.h +++ b/arch/um/include/asm/kasan.h @@ -24,7 +24,6 @@ #ifdef CONFIG_KASAN void kasan_init(void); -void kasan_map_memory(void *start, unsigned long len); extern int kasan_um_is_ready; #ifdef CONFIG_STATIC_LINK diff --git a/arch/um/include/shared/kern_util.h b/arch/um/include/shared/kern_util.h index 81bc38a2e3fc..95521b1f5b20 100644 --- a/arch/um/include/shared/kern_util.h +++ b/arch/um/include/shared/kern_util.h @@ -67,4 +67,6 @@ extern void fatal_sigsegv(void) __attribute__ ((noreturn)); void um_idle_sleep(void); +void kasan_map_memory(void *start, size_t len); + #endif diff --git a/arch/um/os-Linux/mem.c b/arch/um/os-Linux/mem.c index 8530b2e08604..c6c9495b1432 100644 --- a/arch/um/os-Linux/mem.c +++ b/arch/um/os-Linux/mem.c @@ -15,6 +15,7 @@ #include #include #include +#include #include /* -- cgit v1.2.3-59-g8ed1b From 847d3abc6aeda1266192d4236e6a766cdf04eb0f Mon Sep 17 00:00:00 2001 From: Tiwei Bie Date: Tue, 23 Apr 2024 20:58:56 +0800 Subject: um: Add an internal header shared among the user code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move relevant declarations to this header. This will address below -Wmissing-prototypes warnings: arch/um/os-Linux/elf_aux.c:26:13: warning: no previous prototype for ‘scan_elf_aux’ [-Wmissing-prototypes] arch/um/os-Linux/mem.c:213:13: warning: no previous prototype for ‘check_tmpexec’ [-Wmissing-prototypes] arch/um/os-Linux/skas/process.c:107:6: warning: no previous prototype for ‘wait_stub_done’ [-Wmissing-prototypes] Signed-off-by: Tiwei Bie Signed-off-by: Richard Weinberger --- arch/um/os-Linux/elf_aux.c | 1 + arch/um/os-Linux/internal.h | 20 ++++++++++++++++++++ arch/um/os-Linux/main.c | 3 +-- arch/um/os-Linux/mem.c | 1 + arch/um/os-Linux/skas/mem.c | 3 +-- arch/um/os-Linux/skas/process.c | 1 + arch/um/os-Linux/start_up.c | 3 +-- 7 files changed, 26 insertions(+), 6 deletions(-) create mode 100644 arch/um/os-Linux/internal.h diff --git a/arch/um/os-Linux/elf_aux.c b/arch/um/os-Linux/elf_aux.c index 344ac403fb5d..0a0f91cf4d6d 100644 --- a/arch/um/os-Linux/elf_aux.c +++ b/arch/um/os-Linux/elf_aux.c @@ -13,6 +13,7 @@ #include #include #include +#include "internal.h" typedef Elf32_auxv_t elf_auxv_t; diff --git a/arch/um/os-Linux/internal.h b/arch/um/os-Linux/internal.h new file mode 100644 index 000000000000..317fca190c2b --- /dev/null +++ b/arch/um/os-Linux/internal.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __UM_OS_LINUX_INTERNAL_H +#define __UM_OS_LINUX_INTERNAL_H + +/* + * elf_aux.c + */ +void scan_elf_aux(char **envp); + +/* + * mem.c + */ +void check_tmpexec(void); + +/* + * skas/process.c + */ +void wait_stub_done(int pid); + +#endif /* __UM_OS_LINUX_INTERNAL_H */ diff --git a/arch/um/os-Linux/main.c b/arch/um/os-Linux/main.c index e82164f90288..f98ff79cdbf7 100644 --- a/arch/um/os-Linux/main.c +++ b/arch/um/os-Linux/main.c @@ -16,6 +16,7 @@ #include #include #include +#include "internal.h" #define PGD_BOUND (4 * 1024 * 1024) #define STACKSIZE (8 * 1024 * 1024) @@ -102,8 +103,6 @@ static void setup_env_path(void) } } -extern void scan_elf_aux( char **envp); - int __init main(int argc, char **argv, char **envp) { char **new_argv; diff --git a/arch/um/os-Linux/mem.c b/arch/um/os-Linux/mem.c index c6c9495b1432..cf44d386f23c 100644 --- a/arch/um/os-Linux/mem.c +++ b/arch/um/os-Linux/mem.c @@ -17,6 +17,7 @@ #include #include #include +#include "internal.h" /* * kasan_map_memory - maps memory from @start with a size of @len. diff --git a/arch/um/os-Linux/skas/mem.c b/arch/um/os-Linux/skas/mem.c index 953fb10f3f93..1f9c1bffc3a6 100644 --- a/arch/um/os-Linux/skas/mem.c +++ b/arch/um/os-Linux/skas/mem.c @@ -17,11 +17,10 @@ #include #include #include +#include "../internal.h" extern char batch_syscall_stub[], __syscall_stub_start[]; -extern void wait_stub_done(int pid); - static inline unsigned long *check_init_stack(struct mm_id * mm_idp, unsigned long *stack) { diff --git a/arch/um/os-Linux/skas/process.c b/arch/um/os-Linux/skas/process.c index 1f5c3f2523d1..41a288dcfc34 100644 --- a/arch/um/os-Linux/skas/process.c +++ b/arch/um/os-Linux/skas/process.c @@ -23,6 +23,7 @@ #include #include #include +#include "../internal.h" int is_skas_winch(int pid, int fd, void *data) { diff --git a/arch/um/os-Linux/start_up.c b/arch/um/os-Linux/start_up.c index 6b21061c431c..89ad9f4f865c 100644 --- a/arch/um/os-Linux/start_up.c +++ b/arch/um/os-Linux/start_up.c @@ -25,6 +25,7 @@ #include #include #include +#include "internal.h" static void ptrace_child(void) { @@ -222,8 +223,6 @@ static void __init check_ptrace(void) check_sysemu(); } -extern void check_tmpexec(void); - static void __init check_coredump_limit(void) { struct rlimit lim; -- cgit v1.2.3-59-g8ed1b From 67c3c7de410c3f1e9f2cd87d7e6cec9e0c6a0e4b Mon Sep 17 00:00:00 2001 From: Tiwei Bie Date: Tue, 23 Apr 2024 20:58:57 +0800 Subject: um: Fix -Wmissing-prototypes warnings for __vdso_* MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The VDSO functions are defined as globals and intended to be called from userspace. Let's just workaround the -Wmissing-prototypes warnings by declaring them locally. This will address below -Wmissing-prototypes warnings: arch/x86/um/vdso/um_vdso.c:16:5: warning: no previous prototype for ‘__vdso_clock_gettime’ [-Wmissing-prototypes] arch/x86/um/vdso/um_vdso.c:30:5: warning: no previous prototype for ‘__vdso_gettimeofday’ [-Wmissing-prototypes] arch/x86/um/vdso/um_vdso.c:44:21: warning: no previous prototype for ‘__vdso_time’ [-Wmissing-prototypes] arch/x86/um/vdso/um_vdso.c:57:1: warning: no previous prototype for ‘__vdso_getcpu’ [-Wmissing-prototypes] While at it, also fix the "WARNING: Prefer 'unsigned int *' to bare use of 'unsigned *'" checkpatch warning. Signed-off-by: Tiwei Bie Signed-off-by: Richard Weinberger --- arch/x86/um/vdso/um_vdso.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/arch/x86/um/vdso/um_vdso.c b/arch/x86/um/vdso/um_vdso.c index ff0f3b4b6c45..cbae2584124f 100644 --- a/arch/x86/um/vdso/um_vdso.c +++ b/arch/x86/um/vdso/um_vdso.c @@ -13,6 +13,12 @@ #include #include +/* workaround for -Wmissing-prototypes warnings */ +int __vdso_clock_gettime(clockid_t clock, struct __kernel_old_timespec *ts); +int __vdso_gettimeofday(struct __kernel_old_timeval *tv, struct timezone *tz); +__kernel_old_time_t __vdso_time(__kernel_old_time_t *t); +long __vdso_getcpu(unsigned int *cpu, unsigned int *node, struct getcpu_cache *unused); + int __vdso_clock_gettime(clockid_t clock, struct __kernel_old_timespec *ts) { long ret; @@ -54,7 +60,7 @@ __kernel_old_time_t __vdso_time(__kernel_old_time_t *t) __kernel_old_time_t time(__kernel_old_time_t *t) __attribute__((weak, alias("__vdso_time"))); long -__vdso_getcpu(unsigned *cpu, unsigned *node, struct getcpu_cache *unused) +__vdso_getcpu(unsigned int *cpu, unsigned int *node, struct getcpu_cache *unused) { /* * UML does not support SMP, we can cheat here. :) @@ -68,5 +74,5 @@ __vdso_getcpu(unsigned *cpu, unsigned *node, struct getcpu_cache *unused) return 0; } -long getcpu(unsigned *cpu, unsigned *node, struct getcpu_cache *tcache) +long getcpu(unsigned int *cpu, unsigned int *node, struct getcpu_cache *tcache) __attribute__((weak, alias("__vdso_getcpu"))); -- cgit v1.2.3-59-g8ed1b From 470dbef50606a4a08dca97133b30cf106207d1ab Mon Sep 17 00:00:00 2001 From: Tiwei Bie Date: Tue, 23 Apr 2024 20:58:58 +0800 Subject: um: Remove unused do_get_thread_area function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's not used since it was introduced by commit aa6758d4867c ("[PATCH] uml: implement {get,set}_thread_area for i386"). Now, it's causing a -Wmissing-prototypes warning: arch/x86/um/tls_32.c:39:5: warning: no previous prototype for ‘do_get_thread_area’ [-Wmissing-prototypes] 39 | int do_get_thread_area(struct user_desc *info) | ^~~~~~~~~~~~~~~~~~ The original author also had doubts about whether it should be used. Considering that 18 years have passed, let's just remove it. Signed-off-by: Tiwei Bie Signed-off-by: Richard Weinberger --- arch/x86/um/tls_32.c | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/arch/x86/um/tls_32.c b/arch/x86/um/tls_32.c index ba40b1b8e179..d301deee041f 100644 --- a/arch/x86/um/tls_32.c +++ b/arch/x86/um/tls_32.c @@ -36,22 +36,6 @@ static int do_set_thread_area(struct user_desc *info) return ret; } -int do_get_thread_area(struct user_desc *info) -{ - int ret; - u32 cpu; - - cpu = get_cpu(); - ret = os_get_thread_area(info, userspace_pid[cpu]); - put_cpu(); - - if (ret) - printk(KERN_ERR "PTRACE_GET_THREAD_AREA failed, err = %d, " - "index = %d\n", ret, info->entry_number); - - return ret; -} - /* * sys_get_thread_area: get a yet unused TLS descriptor index. * XXX: Consider leaving one free slot for glibc usage at first place. This must @@ -231,7 +215,6 @@ out: return ret; } -/* XXX: use do_get_thread_area to read the host value? I'm not at all sure! */ static int get_tls_entry(struct task_struct *task, struct user_desc *info, int idx) { -- cgit v1.2.3-59-g8ed1b From 5aca3252ddb1e21a3d4281c72102e8da4957d41f Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Sun, 10 Mar 2024 08:52:27 +0100 Subject: um: rtc: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Reviewed-by: Geert Uytterhoeven Signed-off-by: Richard Weinberger --- arch/um/drivers/rtc_kern.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/arch/um/drivers/rtc_kern.c b/arch/um/drivers/rtc_kern.c index 97ceb205cfe6..3a1582219c4b 100644 --- a/arch/um/drivers/rtc_kern.c +++ b/arch/um/drivers/rtc_kern.c @@ -168,16 +168,15 @@ cleanup: return err; } -static int uml_rtc_remove(struct platform_device *pdev) +static void uml_rtc_remove(struct platform_device *pdev) { device_init_wakeup(&pdev->dev, 0); uml_rtc_cleanup(); - return 0; } static struct platform_driver uml_rtc_driver = { .probe = uml_rtc_probe, - .remove = uml_rtc_remove, + .remove_new = uml_rtc_remove, .driver = { .name = "uml-rtc", }, -- cgit v1.2.3-59-g8ed1b From 919e3ece7f5aaf7b5f3c54538d5303b6eeeb053b Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Sun, 10 Mar 2024 08:52:28 +0100 Subject: um: virtio_uml: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Reviewed-by: Geert Uytterhoeven Signed-off-by: Richard Weinberger --- arch/um/drivers/virtio_uml.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/arch/um/drivers/virtio_uml.c b/arch/um/drivers/virtio_uml.c index 8adca2000e51..77faa2cf3a13 100644 --- a/arch/um/drivers/virtio_uml.c +++ b/arch/um/drivers/virtio_uml.c @@ -1241,12 +1241,11 @@ error_free: return rc; } -static int virtio_uml_remove(struct platform_device *pdev) +static void virtio_uml_remove(struct platform_device *pdev) { struct virtio_uml_device *vu_dev = platform_get_drvdata(pdev); unregister_virtio_device(&vu_dev->vdev); - return 0; } /* Command line device list */ @@ -1445,7 +1444,7 @@ static int virtio_uml_resume(struct platform_device *pdev) static struct platform_driver virtio_uml_driver = { .probe = virtio_uml_probe, - .remove = virtio_uml_remove, + .remove_new = virtio_uml_remove, .driver = { .name = "virtio-uml", .of_match_table = virtio_uml_match, -- cgit v1.2.3-59-g8ed1b From 32965a3b827581a4cd2c7046ac7809df3579a678 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Wed, 24 Apr 2024 16:12:02 +1000 Subject: USB: fix up for "usb: misc: onboard_hub: rename to onboard_dev" interacting with "usb: misc: onboard_usb_hub: Disable the USB hub clock on failure" Signed-off-by: Stephen Rothwell Link: https://lore.kernel.org/r/20240424161202.7e45e19e@canb.auug.org.au Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/onboard_usb_dev.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/usb/misc/onboard_usb_dev.c b/drivers/usb/misc/onboard_usb_dev.c index 648ea933bdad..f2bcc1a8b95f 100644 --- a/drivers/usb/misc/onboard_usb_dev.c +++ b/drivers/usb/misc/onboard_usb_dev.c @@ -93,7 +93,7 @@ static int onboard_dev_power_on(struct onboard_dev *onboard_dev) if (err) { dev_err(onboard_dev->dev, "failed to enable supplies: %pe\n", ERR_PTR(err)); - return err; + goto disable_clk; } fsleep(onboard_dev->pdata->reset_us); @@ -102,6 +102,10 @@ static int onboard_dev_power_on(struct onboard_dev *onboard_dev) onboard_dev->is_powered_on = true; return 0; + +disable_clk: + clk_disable_unprepare(onboard_dev->clk); + return err; } static int onboard_dev_power_off(struct onboard_dev *onboard_dev) -- cgit v1.2.3-59-g8ed1b From 91e0d560b9fdd48b4bd62167fce14f4188b6e2fd Mon Sep 17 00:00:00 2001 From: Olivia Wen Date: Tue, 30 Apr 2024 09:15:31 +0800 Subject: dt-bindings: remoteproc: mediatek: Support MT8188 dual-core SCP Under different applications, the MT8188 SCP can be used as single-core or dual-core. Signed-off-by: Olivia Wen Acked-by: Krzysztof Kozlowski Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20240430011534.9587-2-olivia.wen@mediatek.com Signed-off-by: Mathieu Poirier --- Documentation/devicetree/bindings/remoteproc/mtk,scp.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/remoteproc/mtk,scp.yaml b/Documentation/devicetree/bindings/remoteproc/mtk,scp.yaml index 507f98f73d23..c5dc3c2820d7 100644 --- a/Documentation/devicetree/bindings/remoteproc/mtk,scp.yaml +++ b/Documentation/devicetree/bindings/remoteproc/mtk,scp.yaml @@ -19,6 +19,7 @@ properties: - mediatek,mt8183-scp - mediatek,mt8186-scp - mediatek,mt8188-scp + - mediatek,mt8188-scp-dual - mediatek,mt8192-scp - mediatek,mt8195-scp - mediatek,mt8195-scp-dual @@ -194,6 +195,7 @@ allOf: properties: compatible: enum: + - mediatek,mt8188-scp-dual - mediatek,mt8195-scp-dual then: properties: -- cgit v1.2.3-59-g8ed1b From 928a55ab1b419ba160e33c1bdee86904f110b638 Mon Sep 17 00:00:00 2001 From: Olivia Wen Date: Tue, 30 Apr 2024 09:15:32 +0800 Subject: remoteproc: mediatek: Support MT8188 SCP core 1 MT8188 SCP has two RISC-V cores which is similar to MT8195 but without L1TCM. We've added MT8188-specific functions to configure L1TCM in multicore setups. Signed-off-by: Olivia Wen Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20240430011534.9587-3-olivia.wen@mediatek.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/mtk_scp.c | 146 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 143 insertions(+), 3 deletions(-) diff --git a/drivers/remoteproc/mtk_scp.c b/drivers/remoteproc/mtk_scp.c index 67518291a8ad..6295148bc8c7 100644 --- a/drivers/remoteproc/mtk_scp.c +++ b/drivers/remoteproc/mtk_scp.c @@ -471,6 +471,86 @@ static int mt8186_scp_before_load(struct mtk_scp *scp) return 0; } +static int mt8188_scp_l2tcm_on(struct mtk_scp *scp) +{ + struct mtk_scp_of_cluster *scp_cluster = scp->cluster; + + mutex_lock(&scp_cluster->cluster_lock); + + if (scp_cluster->l2tcm_refcnt == 0) { + /* clear SPM interrupt, SCP2SPM_IPC_CLR */ + writel(0xff, scp->cluster->reg_base + MT8192_SCP2SPM_IPC_CLR); + + /* Power on L2TCM */ + scp_sram_power_on(scp->cluster->reg_base + MT8192_L2TCM_SRAM_PD_0, 0); + scp_sram_power_on(scp->cluster->reg_base + MT8192_L2TCM_SRAM_PD_1, 0); + scp_sram_power_on(scp->cluster->reg_base + MT8192_L2TCM_SRAM_PD_2, 0); + scp_sram_power_on(scp->cluster->reg_base + MT8192_L1TCM_SRAM_PDN, 0); + } + + scp_cluster->l2tcm_refcnt += 1; + + mutex_unlock(&scp_cluster->cluster_lock); + + return 0; +} + +static int mt8188_scp_before_load(struct mtk_scp *scp) +{ + writel(1, scp->cluster->reg_base + MT8192_CORE0_SW_RSTN_SET); + + mt8188_scp_l2tcm_on(scp); + + scp_sram_power_on(scp->cluster->reg_base + MT8192_CPU0_SRAM_PD, 0); + + /* enable MPU for all memory regions */ + writel(0xff, scp->cluster->reg_base + MT8192_CORE0_MEM_ATT_PREDEF); + + return 0; +} + +static int mt8188_scp_c1_before_load(struct mtk_scp *scp) +{ + u32 sec_ctrl; + struct mtk_scp *scp_c0; + struct mtk_scp_of_cluster *scp_cluster = scp->cluster; + + scp->data->scp_reset_assert(scp); + + mt8188_scp_l2tcm_on(scp); + + scp_sram_power_on(scp->cluster->reg_base + MT8195_CPU1_SRAM_PD, 0); + + /* enable MPU for all memory regions */ + writel(0xff, scp->cluster->reg_base + MT8195_CORE1_MEM_ATT_PREDEF); + + /* + * The L2TCM_OFFSET_RANGE and L2TCM_OFFSET shift the destination address + * on SRAM when SCP core 1 accesses SRAM. + * + * This configuration solves booting the SCP core 0 and core 1 from + * different SRAM address because core 0 and core 1 both boot from + * the head of SRAM by default. this must be configured before boot SCP core 1. + * + * The value of L2TCM_OFFSET_RANGE is from the viewpoint of SCP core 1. + * When SCP core 1 issues address within the range (L2TCM_OFFSET_RANGE), + * the address will be added with a fixed offset (L2TCM_OFFSET) on the bus. + * The shift action is tranparent to software. + */ + writel(0, scp->cluster->reg_base + MT8195_L2TCM_OFFSET_RANGE_0_LOW); + writel(scp->sram_size, scp->cluster->reg_base + MT8195_L2TCM_OFFSET_RANGE_0_HIGH); + + scp_c0 = list_first_entry(&scp_cluster->mtk_scp_list, struct mtk_scp, elem); + writel(scp->sram_phys - scp_c0->sram_phys, scp->cluster->reg_base + MT8195_L2TCM_OFFSET); + + /* enable SRAM offset when fetching instruction and data */ + sec_ctrl = readl(scp->cluster->reg_base + MT8195_SEC_CTRL); + sec_ctrl |= MT8195_CORE_OFFSET_ENABLE_I | MT8195_CORE_OFFSET_ENABLE_D; + writel(sec_ctrl, scp->cluster->reg_base + MT8195_SEC_CTRL); + + return 0; +} + static int mt8192_scp_before_load(struct mtk_scp *scp) { /* clear SPM interrupt, SCP2SPM_IPC_CLR */ @@ -717,6 +797,47 @@ static void mt8183_scp_stop(struct mtk_scp *scp) writel(0, scp->cluster->reg_base + MT8183_WDT_CFG); } +static void mt8188_scp_l2tcm_off(struct mtk_scp *scp) +{ + struct mtk_scp_of_cluster *scp_cluster = scp->cluster; + + mutex_lock(&scp_cluster->cluster_lock); + + if (scp_cluster->l2tcm_refcnt > 0) + scp_cluster->l2tcm_refcnt -= 1; + + if (scp_cluster->l2tcm_refcnt == 0) { + /* Power off L2TCM */ + scp_sram_power_off(scp->cluster->reg_base + MT8192_L2TCM_SRAM_PD_0, 0); + scp_sram_power_off(scp->cluster->reg_base + MT8192_L2TCM_SRAM_PD_1, 0); + scp_sram_power_off(scp->cluster->reg_base + MT8192_L2TCM_SRAM_PD_2, 0); + scp_sram_power_off(scp->cluster->reg_base + MT8192_L1TCM_SRAM_PDN, 0); + } + + mutex_unlock(&scp_cluster->cluster_lock); +} + +static void mt8188_scp_stop(struct mtk_scp *scp) +{ + mt8188_scp_l2tcm_off(scp); + + scp_sram_power_off(scp->cluster->reg_base + MT8192_CPU0_SRAM_PD, 0); + + /* Disable SCP watchdog */ + writel(0, scp->cluster->reg_base + MT8192_CORE0_WDT_CFG); +} + +static void mt8188_scp_c1_stop(struct mtk_scp *scp) +{ + mt8188_scp_l2tcm_off(scp); + + /* Power off CPU SRAM */ + scp_sram_power_off(scp->cluster->reg_base + MT8195_CPU1_SRAM_PD, 0); + + /* Disable SCP watchdog */ + writel(0, scp->cluster->reg_base + MT8195_CORE1_WDT_CFG); +} + static void mt8192_scp_stop(struct mtk_scp *scp) { /* Disable SRAM clock */ @@ -1264,16 +1385,28 @@ static const struct mtk_scp_of_data mt8186_of_data = { static const struct mtk_scp_of_data mt8188_of_data = { .scp_clk_get = mt8195_scp_clk_get, - .scp_before_load = mt8192_scp_before_load, - .scp_irq_handler = mt8192_scp_irq_handler, + .scp_before_load = mt8188_scp_before_load, + .scp_irq_handler = mt8195_scp_irq_handler, .scp_reset_assert = mt8192_scp_reset_assert, .scp_reset_deassert = mt8192_scp_reset_deassert, - .scp_stop = mt8192_scp_stop, + .scp_stop = mt8188_scp_stop, .scp_da_to_va = mt8192_scp_da_to_va, .host_to_scp_reg = MT8192_GIPC_IN_SET, .host_to_scp_int_bit = MT8192_HOST_IPC_INT_BIT, }; +static const struct mtk_scp_of_data mt8188_of_data_c1 = { + .scp_clk_get = mt8195_scp_clk_get, + .scp_before_load = mt8188_scp_c1_before_load, + .scp_irq_handler = mt8195_scp_c1_irq_handler, + .scp_reset_assert = mt8195_scp_c1_reset_assert, + .scp_reset_deassert = mt8195_scp_c1_reset_deassert, + .scp_stop = mt8188_scp_c1_stop, + .scp_da_to_va = mt8192_scp_da_to_va, + .host_to_scp_reg = MT8192_GIPC_IN_SET, + .host_to_scp_int_bit = MT8195_CORE1_HOST_IPC_INT_BIT, +}; + static const struct mtk_scp_of_data mt8192_of_data = { .scp_clk_get = mt8192_scp_clk_get, .scp_before_load = mt8192_scp_before_load, @@ -1310,6 +1443,12 @@ static const struct mtk_scp_of_data mt8195_of_data_c1 = { .host_to_scp_int_bit = MT8195_CORE1_HOST_IPC_INT_BIT, }; +static const struct mtk_scp_of_data *mt8188_of_data_cores[] = { + &mt8188_of_data, + &mt8188_of_data_c1, + NULL +}; + static const struct mtk_scp_of_data *mt8195_of_data_cores[] = { &mt8195_of_data, &mt8195_of_data_c1, @@ -1320,6 +1459,7 @@ static const struct of_device_id mtk_scp_of_match[] = { { .compatible = "mediatek,mt8183-scp", .data = &mt8183_of_data }, { .compatible = "mediatek,mt8186-scp", .data = &mt8186_of_data }, { .compatible = "mediatek,mt8188-scp", .data = &mt8188_of_data }, + { .compatible = "mediatek,mt8188-scp-dual", .data = &mt8188_of_data_cores }, { .compatible = "mediatek,mt8192-scp", .data = &mt8192_of_data }, { .compatible = "mediatek,mt8195-scp", .data = &mt8195_of_data }, { .compatible = "mediatek,mt8195-scp-dual", .data = &mt8195_of_data_cores }, -- cgit v1.2.3-59-g8ed1b From c08a824945009aefcb4d70705f195ad15fe26e64 Mon Sep 17 00:00:00 2001 From: Olivia Wen Date: Tue, 30 Apr 2024 09:15:33 +0800 Subject: remoteproc: mediatek: Support setting DRAM and IPI shared buffer sizes The SCP on different chips will require different DRAM sizes and IPI shared buffer sizes based on varying requirements. Signed-off-by: Olivia Wen Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20240430011534.9587-4-olivia.wen@mediatek.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/mtk_common.h | 11 ++++-- drivers/remoteproc/mtk_scp.c | 84 +++++++++++++++++++++++++++++++--------- drivers/remoteproc/mtk_scp_ipi.c | 7 +++- 3 files changed, 79 insertions(+), 23 deletions(-) diff --git a/drivers/remoteproc/mtk_common.h b/drivers/remoteproc/mtk_common.h index 6d7736a031f7..fd5c539ab2ac 100644 --- a/drivers/remoteproc/mtk_common.h +++ b/drivers/remoteproc/mtk_common.h @@ -78,7 +78,6 @@ #define MT8195_L2TCM_OFFSET 0x850d0 #define SCP_FW_VER_LEN 32 -#define SCP_SHARE_BUFFER_SIZE 288 struct scp_run { u32 signaled; @@ -97,6 +96,11 @@ struct scp_ipi_desc { struct mtk_scp; +struct mtk_scp_sizes_data { + size_t max_dram_size; + size_t ipi_share_buffer_size; +}; + struct mtk_scp_of_data { int (*scp_clk_get)(struct mtk_scp *scp); int (*scp_before_load)(struct mtk_scp *scp); @@ -110,6 +114,7 @@ struct mtk_scp_of_data { u32 host_to_scp_int_bit; size_t ipi_buf_offset; + const struct mtk_scp_sizes_data *scp_sizes; }; struct mtk_scp_of_cluster { @@ -141,10 +146,10 @@ struct mtk_scp { struct scp_ipi_desc ipi_desc[SCP_IPI_MAX]; bool ipi_id_ack[SCP_IPI_MAX]; wait_queue_head_t ack_wq; + u8 *share_buf; void *cpu_addr; dma_addr_t dma_addr; - size_t dram_size; struct rproc_subdev *rpmsg_subdev; @@ -162,7 +167,7 @@ struct mtk_scp { struct mtk_share_obj { u32 id; u32 len; - u8 share_buf[SCP_SHARE_BUFFER_SIZE]; + u8 *share_buf; }; void scp_memcpy_aligned(void __iomem *dst, const void *src, unsigned int len); diff --git a/drivers/remoteproc/mtk_scp.c b/drivers/remoteproc/mtk_scp.c index 6295148bc8c7..e281d28242dd 100644 --- a/drivers/remoteproc/mtk_scp.c +++ b/drivers/remoteproc/mtk_scp.c @@ -20,7 +20,6 @@ #include "mtk_common.h" #include "remoteproc_internal.h" -#define MAX_CODE_SIZE 0x500000 #define SECTION_NAME_IPI_BUFFER ".ipi_buffer" /** @@ -94,14 +93,15 @@ static void scp_ipi_handler(struct mtk_scp *scp) { struct mtk_share_obj __iomem *rcv_obj = scp->recv_buf; struct scp_ipi_desc *ipi_desc = scp->ipi_desc; - u8 tmp_data[SCP_SHARE_BUFFER_SIZE]; scp_ipi_handler_t handler; u32 id = readl(&rcv_obj->id); u32 len = readl(&rcv_obj->len); + const struct mtk_scp_sizes_data *scp_sizes; - if (len > SCP_SHARE_BUFFER_SIZE) { - dev_err(scp->dev, "ipi message too long (len %d, max %d)", len, - SCP_SHARE_BUFFER_SIZE); + scp_sizes = scp->data->scp_sizes; + if (len > scp_sizes->ipi_share_buffer_size) { + dev_err(scp->dev, "ipi message too long (len %d, max %zd)", len, + scp_sizes->ipi_share_buffer_size); return; } if (id >= SCP_IPI_MAX) { @@ -117,8 +117,9 @@ static void scp_ipi_handler(struct mtk_scp *scp) return; } - memcpy_fromio(tmp_data, &rcv_obj->share_buf, len); - handler(tmp_data, len, ipi_desc[id].priv); + memset(scp->share_buf, 0, scp_sizes->ipi_share_buffer_size); + memcpy_fromio(scp->share_buf, &rcv_obj->share_buf, len); + handler(scp->share_buf, len, ipi_desc[id].priv); scp_ipi_unlock(scp, id); scp->ipi_id_ack[id] = true; @@ -133,6 +134,8 @@ static int scp_ipi_init(struct mtk_scp *scp, const struct firmware *fw) { int ret; size_t buf_sz, offset; + size_t share_buf_offset; + const struct mtk_scp_sizes_data *scp_sizes; /* read the ipi buf addr from FW itself first */ ret = scp_elf_read_ipi_buf_addr(scp, fw, &offset); @@ -152,12 +155,15 @@ static int scp_ipi_init(struct mtk_scp *scp, const struct firmware *fw) return -EOVERFLOW; } + scp_sizes = scp->data->scp_sizes; scp->recv_buf = (struct mtk_share_obj __iomem *) (scp->sram_base + offset); + share_buf_offset = sizeof(scp->recv_buf->id) + + sizeof(scp->recv_buf->len) + scp_sizes->ipi_share_buffer_size; scp->send_buf = (struct mtk_share_obj __iomem *) - (scp->sram_base + offset + sizeof(*scp->recv_buf)); - memset_io(scp->recv_buf, 0, sizeof(*scp->recv_buf)); - memset_io(scp->send_buf, 0, sizeof(*scp->send_buf)); + (scp->sram_base + offset + share_buf_offset); + memset_io(scp->recv_buf, 0, share_buf_offset); + memset_io(scp->send_buf, 0, share_buf_offset); return 0; } @@ -741,14 +747,16 @@ stop: static void *mt8183_scp_da_to_va(struct mtk_scp *scp, u64 da, size_t len) { int offset; + const struct mtk_scp_sizes_data *scp_sizes; + scp_sizes = scp->data->scp_sizes; if (da < scp->sram_size) { offset = da; if (offset >= 0 && (offset + len) <= scp->sram_size) return (void __force *)scp->sram_base + offset; - } else if (scp->dram_size) { + } else if (scp_sizes->max_dram_size) { offset = da - scp->dma_addr; - if (offset >= 0 && (offset + len) <= scp->dram_size) + if (offset >= 0 && (offset + len) <= scp_sizes->max_dram_size) return scp->cpu_addr + offset; } @@ -758,7 +766,9 @@ static void *mt8183_scp_da_to_va(struct mtk_scp *scp, u64 da, size_t len) static void *mt8192_scp_da_to_va(struct mtk_scp *scp, u64 da, size_t len) { int offset; + const struct mtk_scp_sizes_data *scp_sizes; + scp_sizes = scp->data->scp_sizes; if (da >= scp->sram_phys && (da + len) <= scp->sram_phys + scp->sram_size) { offset = da - scp->sram_phys; @@ -774,9 +784,9 @@ static void *mt8192_scp_da_to_va(struct mtk_scp *scp, u64 da, size_t len) } /* optional memory region */ - if (scp->dram_size && + if (scp_sizes->max_dram_size && da >= scp->dma_addr && - (da + len) <= scp->dma_addr + scp->dram_size) { + (da + len) <= scp->dma_addr + scp_sizes->max_dram_size) { offset = da - scp->dma_addr; return scp->cpu_addr + offset; } @@ -997,6 +1007,7 @@ EXPORT_SYMBOL_GPL(scp_mapping_dm_addr); static int scp_map_memory_region(struct mtk_scp *scp) { int ret; + const struct mtk_scp_sizes_data *scp_sizes; ret = of_reserved_mem_device_init(scp->dev); @@ -1012,8 +1023,8 @@ static int scp_map_memory_region(struct mtk_scp *scp) } /* Reserved SCP code size */ - scp->dram_size = MAX_CODE_SIZE; - scp->cpu_addr = dma_alloc_coherent(scp->dev, scp->dram_size, + scp_sizes = scp->data->scp_sizes; + scp->cpu_addr = dma_alloc_coherent(scp->dev, scp_sizes->max_dram_size, &scp->dma_addr, GFP_KERNEL); if (!scp->cpu_addr) return -ENOMEM; @@ -1023,10 +1034,13 @@ static int scp_map_memory_region(struct mtk_scp *scp) static void scp_unmap_memory_region(struct mtk_scp *scp) { - if (scp->dram_size == 0) + const struct mtk_scp_sizes_data *scp_sizes; + + scp_sizes = scp->data->scp_sizes; + if (scp_sizes->max_dram_size == 0) return; - dma_free_coherent(scp->dev, scp->dram_size, scp->cpu_addr, + dma_free_coherent(scp->dev, scp_sizes->max_dram_size, scp->cpu_addr, scp->dma_addr); of_reserved_mem_device_release(scp->dev); } @@ -1090,6 +1104,7 @@ static struct mtk_scp *scp_rproc_init(struct platform_device *pdev, struct resource *res; const char *fw_name = "scp.img"; int ret, i; + const struct mtk_scp_sizes_data *scp_sizes; ret = rproc_of_parse_firmware(dev, 0, &fw_name); if (ret < 0 && ret != -EINVAL) @@ -1137,6 +1152,13 @@ static struct mtk_scp *scp_rproc_init(struct platform_device *pdev, goto release_dev_mem; } + scp_sizes = scp->data->scp_sizes; + scp->share_buf = kzalloc(scp_sizes->ipi_share_buffer_size, GFP_KERNEL); + if (!scp->share_buf) { + dev_err(dev, "Failed to allocate IPI share buffer\n"); + goto release_dev_mem; + } + init_waitqueue_head(&scp->run.wq); init_waitqueue_head(&scp->ack_wq); @@ -1156,6 +1178,8 @@ static struct mtk_scp *scp_rproc_init(struct platform_device *pdev, remove_subdev: scp_remove_rpmsg_subdev(scp); scp_ipi_unregister(scp, SCP_IPI_INIT); + kfree(scp->share_buf); + scp->share_buf = NULL; release_dev_mem: scp_unmap_memory_region(scp); for (i = 0; i < SCP_IPI_MAX; i++) @@ -1171,6 +1195,8 @@ static void scp_free(struct mtk_scp *scp) scp_remove_rpmsg_subdev(scp); scp_ipi_unregister(scp, SCP_IPI_INIT); + kfree(scp->share_buf); + scp->share_buf = NULL; scp_unmap_memory_region(scp); for (i = 0; i < SCP_IPI_MAX; i++) mutex_destroy(&scp->ipi_desc[i].lock); @@ -1357,6 +1383,21 @@ static void scp_remove(struct platform_device *pdev) mutex_destroy(&scp_cluster->cluster_lock); } +static const struct mtk_scp_sizes_data default_scp_sizes = { + .max_dram_size = 0x500000, + .ipi_share_buffer_size = 288, +}; + +static const struct mtk_scp_sizes_data mt8188_scp_sizes = { + .max_dram_size = 0x500000, + .ipi_share_buffer_size = 600, +}; + +static const struct mtk_scp_sizes_data mt8188_scp_c1_sizes = { + .max_dram_size = 0xA00000, + .ipi_share_buffer_size = 600, +}; + static const struct mtk_scp_of_data mt8183_of_data = { .scp_clk_get = mt8183_scp_clk_get, .scp_before_load = mt8183_scp_before_load, @@ -1368,6 +1409,7 @@ static const struct mtk_scp_of_data mt8183_of_data = { .host_to_scp_reg = MT8183_HOST_TO_SCP, .host_to_scp_int_bit = MT8183_HOST_IPC_INT_BIT, .ipi_buf_offset = 0x7bdb0, + .scp_sizes = &default_scp_sizes, }; static const struct mtk_scp_of_data mt8186_of_data = { @@ -1381,6 +1423,7 @@ static const struct mtk_scp_of_data mt8186_of_data = { .host_to_scp_reg = MT8183_HOST_TO_SCP, .host_to_scp_int_bit = MT8183_HOST_IPC_INT_BIT, .ipi_buf_offset = 0x3bdb0, + .scp_sizes = &default_scp_sizes, }; static const struct mtk_scp_of_data mt8188_of_data = { @@ -1393,6 +1436,7 @@ static const struct mtk_scp_of_data mt8188_of_data = { .scp_da_to_va = mt8192_scp_da_to_va, .host_to_scp_reg = MT8192_GIPC_IN_SET, .host_to_scp_int_bit = MT8192_HOST_IPC_INT_BIT, + .scp_sizes = &mt8188_scp_sizes, }; static const struct mtk_scp_of_data mt8188_of_data_c1 = { @@ -1405,6 +1449,7 @@ static const struct mtk_scp_of_data mt8188_of_data_c1 = { .scp_da_to_va = mt8192_scp_da_to_va, .host_to_scp_reg = MT8192_GIPC_IN_SET, .host_to_scp_int_bit = MT8195_CORE1_HOST_IPC_INT_BIT, + .scp_sizes = &mt8188_scp_c1_sizes, }; static const struct mtk_scp_of_data mt8192_of_data = { @@ -1417,6 +1462,7 @@ static const struct mtk_scp_of_data mt8192_of_data = { .scp_da_to_va = mt8192_scp_da_to_va, .host_to_scp_reg = MT8192_GIPC_IN_SET, .host_to_scp_int_bit = MT8192_HOST_IPC_INT_BIT, + .scp_sizes = &default_scp_sizes, }; static const struct mtk_scp_of_data mt8195_of_data = { @@ -1429,6 +1475,7 @@ static const struct mtk_scp_of_data mt8195_of_data = { .scp_da_to_va = mt8192_scp_da_to_va, .host_to_scp_reg = MT8192_GIPC_IN_SET, .host_to_scp_int_bit = MT8192_HOST_IPC_INT_BIT, + .scp_sizes = &default_scp_sizes, }; static const struct mtk_scp_of_data mt8195_of_data_c1 = { @@ -1441,6 +1488,7 @@ static const struct mtk_scp_of_data mt8195_of_data_c1 = { .scp_da_to_va = mt8192_scp_da_to_va, .host_to_scp_reg = MT8192_GIPC_IN_SET, .host_to_scp_int_bit = MT8195_CORE1_HOST_IPC_INT_BIT, + .scp_sizes = &default_scp_sizes, }; static const struct mtk_scp_of_data *mt8188_of_data_cores[] = { diff --git a/drivers/remoteproc/mtk_scp_ipi.c b/drivers/remoteproc/mtk_scp_ipi.c index cd0b60106ec2..c068227e251e 100644 --- a/drivers/remoteproc/mtk_scp_ipi.c +++ b/drivers/remoteproc/mtk_scp_ipi.c @@ -162,10 +162,13 @@ int scp_ipi_send(struct mtk_scp *scp, u32 id, void *buf, unsigned int len, struct mtk_share_obj __iomem *send_obj = scp->send_buf; u32 val; int ret; + const struct mtk_scp_sizes_data *scp_sizes; + + scp_sizes = scp->data->scp_sizes; if (WARN_ON(id <= SCP_IPI_INIT) || WARN_ON(id >= SCP_IPI_MAX) || WARN_ON(id == SCP_IPI_NS_SERVICE) || - WARN_ON(len > sizeof(send_obj->share_buf)) || WARN_ON(!buf)) + WARN_ON(len > scp_sizes->ipi_share_buffer_size) || WARN_ON(!buf)) return -EINVAL; ret = clk_prepare_enable(scp->clk); @@ -184,7 +187,7 @@ int scp_ipi_send(struct mtk_scp *scp, u32 id, void *buf, unsigned int len, goto unlock_mutex; } - scp_memcpy_aligned(send_obj->share_buf, buf, len); + scp_memcpy_aligned(&send_obj->share_buf, buf, len); writel(len, &send_obj->len); writel(id, &send_obj->id); -- cgit v1.2.3-59-g8ed1b From faba7db431294e0684d08a51b1f04cda75473d93 Mon Sep 17 00:00:00 2001 From: Olivia Wen Date: Tue, 30 Apr 2024 09:15:34 +0800 Subject: remoteproc: mediatek: Add IMGSYS IPI command Add an IPI command definition for communication with IMGSYS through SCP mailbox. Signed-off-by: Olivia Wen Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20240430011534.9587-5-olivia.wen@mediatek.com Signed-off-by: Mathieu Poirier --- include/linux/remoteproc/mtk_scp.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/remoteproc/mtk_scp.h b/include/linux/remoteproc/mtk_scp.h index 7c2b7cc9fe6c..344ff41c22c7 100644 --- a/include/linux/remoteproc/mtk_scp.h +++ b/include/linux/remoteproc/mtk_scp.h @@ -43,6 +43,7 @@ enum scp_ipi_id { SCP_IPI_CROS_HOST_CMD, SCP_IPI_VDEC_LAT, SCP_IPI_VDEC_CORE, + SCP_IPI_IMGSYS_CMD, SCP_IPI_NS_SERVICE = 0xFF, SCP_IPI_MAX = 0x100, }; -- cgit v1.2.3-59-g8ed1b From 61f6f68447aba08aeaa97593af3a7d85a114891f Mon Sep 17 00:00:00 2001 From: Apurva Nandan Date: Tue, 30 Apr 2024 16:23:06 +0530 Subject: remoteproc: k3-r5: Wait for core0 power-up before powering up core1 PSC controller has a limitation that it can only power-up the second core when the first core is in ON state. Power-state for core0 should be equal to or higher than core1, else the kernel is seen hanging during rproc loading. Make the powering up of cores sequential, by waiting for the current core to power-up before proceeding to the next core, with a timeout of 2sec. Add a wait queue event in k3_r5_cluster_rproc_init call, that will wait for the current core to be released from reset before proceeding with the next core. Fixes: 6dedbd1d5443 ("remoteproc: k3-r5: Add a remoteproc driver for R5F subsystem") Signed-off-by: Apurva Nandan Signed-off-by: Beleswar Padhi Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20240430105307.1190615-2-b-padhi@ti.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/ti_k3_r5_remoteproc.c | 33 ++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/drivers/remoteproc/ti_k3_r5_remoteproc.c b/drivers/remoteproc/ti_k3_r5_remoteproc.c index ad3415a3851b..6d6afd6beb3a 100644 --- a/drivers/remoteproc/ti_k3_r5_remoteproc.c +++ b/drivers/remoteproc/ti_k3_r5_remoteproc.c @@ -103,12 +103,14 @@ struct k3_r5_soc_data { * @dev: cached device pointer * @mode: Mode to configure the Cluster - Split or LockStep * @cores: list of R5 cores within the cluster + * @core_transition: wait queue to sync core state changes * @soc_data: SoC-specific feature data for a R5FSS */ struct k3_r5_cluster { struct device *dev; enum cluster_mode mode; struct list_head cores; + wait_queue_head_t core_transition; const struct k3_r5_soc_data *soc_data; }; @@ -128,6 +130,7 @@ struct k3_r5_cluster { * @atcm_enable: flag to control ATCM enablement * @btcm_enable: flag to control BTCM enablement * @loczrama: flag to dictate which TCM is at device address 0x0 + * @released_from_reset: flag to signal when core is out of reset */ struct k3_r5_core { struct list_head elem; @@ -144,6 +147,7 @@ struct k3_r5_core { u32 atcm_enable; u32 btcm_enable; u32 loczrama; + bool released_from_reset; }; /** @@ -460,6 +464,8 @@ static int k3_r5_rproc_prepare(struct rproc *rproc) ret); return ret; } + core->released_from_reset = true; + wake_up_interruptible(&cluster->core_transition); /* * Newer IP revisions like on J7200 SoCs support h/w auto-initialization @@ -1140,6 +1146,12 @@ static int k3_r5_rproc_configure_mode(struct k3_r5_rproc *kproc) return ret; } + /* + * Skip the waiting mechanism for sequential power-on of cores if the + * core has already been booted by another entity. + */ + core->released_from_reset = c_state; + ret = ti_sci_proc_get_status(core->tsp, &boot_vec, &cfg, &ctrl, &stat); if (ret < 0) { @@ -1280,6 +1292,26 @@ init_rmem: cluster->mode == CLUSTER_MODE_SINGLECPU || cluster->mode == CLUSTER_MODE_SINGLECORE) break; + + /* + * R5 cores require to be powered on sequentially, core0 + * should be in higher power state than core1 in a cluster + * So, wait for current core to power up before proceeding + * to next core and put timeout of 2sec for each core. + * + * This waiting mechanism is necessary because + * rproc_auto_boot_callback() for core1 can be called before + * core0 due to thread execution order. + */ + ret = wait_event_interruptible_timeout(cluster->core_transition, + core->released_from_reset, + msecs_to_jiffies(2000)); + if (ret <= 0) { + dev_err(dev, + "Timed out waiting for %s core to power up!\n", + rproc->name); + return ret; + } } return 0; @@ -1709,6 +1741,7 @@ static int k3_r5_probe(struct platform_device *pdev) cluster->dev = dev; cluster->soc_data = data; INIT_LIST_HEAD(&cluster->cores); + init_waitqueue_head(&cluster->core_transition); ret = of_property_read_u32(np, "ti,cluster-mode", &cluster->mode); if (ret < 0 && ret != -EINVAL) { -- cgit v1.2.3-59-g8ed1b From 3c8a9066d584f5010b6f4ba03bf6b19d28973d52 Mon Sep 17 00:00:00 2001 From: Beleswar Padhi Date: Tue, 30 Apr 2024 16:23:07 +0530 Subject: remoteproc: k3-r5: Do not allow core1 to power up before core0 via sysfs PSC controller has a limitation that it can only power-up the second core when the first core is in ON state. Power-state for core0 should be equal to or higher than core1. Therefore, prevent core1 from powering up before core0 during the start process from sysfs. Similarly, prevent core0 from shutting down before core1 has been shut down from sysfs. Fixes: 6dedbd1d5443 ("remoteproc: k3-r5: Add a remoteproc driver for R5F subsystem") Signed-off-by: Beleswar Padhi Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20240430105307.1190615-3-b-padhi@ti.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/ti_k3_r5_remoteproc.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/drivers/remoteproc/ti_k3_r5_remoteproc.c b/drivers/remoteproc/ti_k3_r5_remoteproc.c index 6d6afd6beb3a..1799b4f6d11e 100644 --- a/drivers/remoteproc/ti_k3_r5_remoteproc.c +++ b/drivers/remoteproc/ti_k3_r5_remoteproc.c @@ -548,7 +548,7 @@ static int k3_r5_rproc_start(struct rproc *rproc) struct k3_r5_rproc *kproc = rproc->priv; struct k3_r5_cluster *cluster = kproc->cluster; struct device *dev = kproc->dev; - struct k3_r5_core *core; + struct k3_r5_core *core0, *core; u32 boot_addr; int ret; @@ -574,6 +574,15 @@ static int k3_r5_rproc_start(struct rproc *rproc) goto unroll_core_run; } } else { + /* do not allow core 1 to start before core 0 */ + core0 = list_first_entry(&cluster->cores, struct k3_r5_core, + elem); + if (core != core0 && core0->rproc->state == RPROC_OFFLINE) { + dev_err(dev, "%s: can not start core 1 before core 0\n", + __func__); + return -EPERM; + } + ret = k3_r5_core_run(core); if (ret) goto put_mbox; @@ -619,7 +628,8 @@ static int k3_r5_rproc_stop(struct rproc *rproc) { struct k3_r5_rproc *kproc = rproc->priv; struct k3_r5_cluster *cluster = kproc->cluster; - struct k3_r5_core *core = kproc->core; + struct device *dev = kproc->dev; + struct k3_r5_core *core1, *core = kproc->core; int ret; /* halt all applicable cores */ @@ -632,6 +642,15 @@ static int k3_r5_rproc_stop(struct rproc *rproc) } } } else { + /* do not allow core 0 to stop before core 1 */ + core1 = list_last_entry(&cluster->cores, struct k3_r5_core, + elem); + if (core != core1 && core1->rproc->state != RPROC_OFFLINE) { + dev_err(dev, "%s: can not stop core 0 before core 1\n", + __func__); + return -EPERM; + } + ret = k3_r5_core_halt(core); if (ret) goto out; -- cgit v1.2.3-59-g8ed1b From 550c88771df05b9a339fe4938927e9d7c191c31a Mon Sep 17 00:00:00 2001 From: André Draszik Date: Tue, 23 Apr 2024 21:19:45 +0100 Subject: dt-bindings: usb: samsung,exynos-dwc3: add gs101 compatible MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Exynos-based Google Tensor gs101 SoC has a DWC3 compatible USB controller and can reuse the existing Exynos glue. Update the dt schema to include the google,gs101-dwusb3 compatible for it. Signed-off-by: André Draszik Reviewed-by: Peter Griffin Reviewed-by: Krzysztof Kozlowski Reviewed-by: Rob Herring (Arm) Link: https://lore.kernel.org/r/20240423-usb-dwc3-gs101-v1-1-2f331f88203f@linaro.org Signed-off-by: Greg Kroah-Hartman --- .../devicetree/bindings/usb/samsung,exynos-dwc3.yaml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Documentation/devicetree/bindings/usb/samsung,exynos-dwc3.yaml b/Documentation/devicetree/bindings/usb/samsung,exynos-dwc3.yaml index 1ade99e85ba8..2b3430cebe99 100644 --- a/Documentation/devicetree/bindings/usb/samsung,exynos-dwc3.yaml +++ b/Documentation/devicetree/bindings/usb/samsung,exynos-dwc3.yaml @@ -12,6 +12,7 @@ maintainers: properties: compatible: enum: + - google,gs101-dwusb3 - samsung,exynos5250-dwusb3 - samsung,exynos5433-dwusb3 - samsung,exynos7-dwusb3 @@ -55,6 +56,23 @@ required: - vdd33-supply allOf: + - if: + properties: + compatible: + contains: + const: google,gs101-dwusb3 + then: + properties: + clocks: + minItems: 4 + maxItems: 4 + clock-names: + items: + - const: bus_early + - const: susp_clk + - const: link_aclk + - const: link_pclk + - if: properties: compatible: -- cgit v1.2.3-59-g8ed1b From 9b780c845fb60e1c0f5ec192fee835c72142173b Mon Sep 17 00:00:00 2001 From: André Draszik Date: Tue, 23 Apr 2024 21:19:46 +0100 Subject: usb: dwc3: exynos: add support for Google Tensor gs101 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Exynos-based Google Tensor gs101 SoC has a DWC3 compatible USB controller and can reuse the existing Exynos glue. Add the google,gs101-dwusb3 compatible and associated driver data. Four clocks are required for USB for this SoC: * bus clock * suspend clock * Link interface AXI clock * Link interface APB clock Signed-off-by: André Draszik Reviewed-by: Peter Griffin Acked-by: Thinh Nguyen Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240423-usb-dwc3-gs101-v1-2-2f331f88203f@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/dwc3-exynos.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/usb/dwc3/dwc3-exynos.c b/drivers/usb/dwc3/dwc3-exynos.c index 3427522a7c6a..9a6e988d165a 100644 --- a/drivers/usb/dwc3/dwc3-exynos.c +++ b/drivers/usb/dwc3/dwc3-exynos.c @@ -169,6 +169,12 @@ static const struct dwc3_exynos_driverdata exynos850_drvdata = { .suspend_clk_idx = -1, }; +static const struct dwc3_exynos_driverdata gs101_drvdata = { + .clk_names = { "bus_early", "susp_clk", "link_aclk", "link_pclk" }, + .num_clks = 4, + .suspend_clk_idx = 1, +}; + static const struct of_device_id exynos_dwc3_match[] = { { .compatible = "samsung,exynos5250-dwusb3", @@ -182,6 +188,9 @@ static const struct of_device_id exynos_dwc3_match[] = { }, { .compatible = "samsung,exynos850-dwusb3", .data = &exynos850_drvdata, + }, { + .compatible = "google,gs101-dwusb3", + .data = &gs101_drvdata, }, { } }; -- cgit v1.2.3-59-g8ed1b From 13953e381ae2891d1699a73c20e8e7fa31699426 Mon Sep 17 00:00:00 2001 From: Dawei Li Date: Wed, 20 Mar 2024 14:47:11 +0800 Subject: riscv: Remove redundant CONFIG_64BIT from pgtable_l{4,5}_enabled IS_ENABLED(CONFIG_64BIT) in initialization of pgtable_l{4,5}_enabled is redundant, remove it. Signed-off-by: Dawei Li Reviewed-by: Alexandre Ghiti Link: https://lore.kernel.org/r/20240320064712.442579-2-dawei.li@shingroup.cn Signed-off-by: Palmer Dabbelt --- arch/riscv/mm/init.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c index 968761843203..9961864850cb 100644 --- a/arch/riscv/mm/init.c +++ b/arch/riscv/mm/init.c @@ -49,8 +49,8 @@ u64 satp_mode __ro_after_init = SATP_MODE_32; EXPORT_SYMBOL(satp_mode); #ifdef CONFIG_64BIT -bool pgtable_l4_enabled = IS_ENABLED(CONFIG_64BIT) && !IS_ENABLED(CONFIG_XIP_KERNEL); -bool pgtable_l5_enabled = IS_ENABLED(CONFIG_64BIT) && !IS_ENABLED(CONFIG_XIP_KERNEL); +bool pgtable_l4_enabled = !IS_ENABLED(CONFIG_XIP_KERNEL); +bool pgtable_l5_enabled = !IS_ENABLED(CONFIG_XIP_KERNEL); EXPORT_SYMBOL(pgtable_l4_enabled); EXPORT_SYMBOL(pgtable_l5_enabled); #endif -- cgit v1.2.3-59-g8ed1b From 0fdbb06379b1126a8c69ceec28e6e506088614a2 Mon Sep 17 00:00:00 2001 From: Dawei Li Date: Wed, 20 Mar 2024 14:47:12 +0800 Subject: riscv: Annotate pgtable_l{4,5}_enabled with __ro_after_init pgtable_l{4,5}_enabled are read only after initialization, make explicit annotation of __ro_after_init on them. Signed-off-by: Dawei Li Reviewed-by: Alexandre Ghiti Link: https://lore.kernel.org/r/20240320064712.442579-3-dawei.li@shingroup.cn Signed-off-by: Palmer Dabbelt --- arch/riscv/mm/init.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c index 9961864850cb..8631b33368ec 100644 --- a/arch/riscv/mm/init.c +++ b/arch/riscv/mm/init.c @@ -49,8 +49,8 @@ u64 satp_mode __ro_after_init = SATP_MODE_32; EXPORT_SYMBOL(satp_mode); #ifdef CONFIG_64BIT -bool pgtable_l4_enabled = !IS_ENABLED(CONFIG_XIP_KERNEL); -bool pgtable_l5_enabled = !IS_ENABLED(CONFIG_XIP_KERNEL); +bool pgtable_l4_enabled __ro_after_init = !IS_ENABLED(CONFIG_XIP_KERNEL); +bool pgtable_l5_enabled __ro_after_init = !IS_ENABLED(CONFIG_XIP_KERNEL); EXPORT_SYMBOL(pgtable_l4_enabled); EXPORT_SYMBOL(pgtable_l5_enabled); #endif -- cgit v1.2.3-59-g8ed1b From dcb2743d1e701fc1a986c187adc11f6148316d21 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Mon, 25 Mar 2024 19:00:36 +0800 Subject: riscv: mm: still create swiotlb buffer for kmalloc() bouncing if required After commit f51f7a0fc2f4 ("riscv: enable DMA_BOUNCE_UNALIGNED_KMALLOC for !dma_coherent"), for non-coherent platforms with less than 4GB memory, we rely on users to pass "swiotlb=mmnn,force" kernel parameters to enable DMA bouncing for unaligned kmalloc() buffers. Now let's go further: If no bouncing needed for ZONE_DMA, let kernel automatically allocate 1MB swiotlb buffer per 1GB of RAM for kmalloc() bouncing on non-coherent platforms, so that no need to pass "swiotlb=mmnn,force" any more. The math of "1MB swiotlb buffer per 1GB of RAM for kmalloc() bouncing" is taken from arm64. Users can still force smaller swiotlb buffer by passing "swiotlb=mmnn". Signed-off-by: Jisheng Zhang Reviewed-by: Alexandre Ghiti Link: https://lore.kernel.org/r/20240325110036.1564-1-jszhang@kernel.org Signed-off-by: Palmer Dabbelt --- arch/riscv/include/asm/cache.h | 2 +- arch/riscv/mm/init.c | 16 +++++++++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/arch/riscv/include/asm/cache.h b/arch/riscv/include/asm/cache.h index 2174fe7bac9a..570e9d8acad1 100644 --- a/arch/riscv/include/asm/cache.h +++ b/arch/riscv/include/asm/cache.h @@ -26,8 +26,8 @@ #ifndef __ASSEMBLY__ -#ifdef CONFIG_RISCV_DMA_NONCOHERENT extern int dma_cache_alignment; +#ifdef CONFIG_RISCV_DMA_NONCOHERENT #define dma_get_cache_alignment dma_get_cache_alignment static inline int dma_get_cache_alignment(void) { diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c index 8631b33368ec..2574f6a3b0e7 100644 --- a/arch/riscv/mm/init.c +++ b/arch/riscv/mm/init.c @@ -161,11 +161,25 @@ static void print_vm_layout(void) { } void __init mem_init(void) { + bool swiotlb = max_pfn > PFN_DOWN(dma32_phys_limit); #ifdef CONFIG_FLATMEM BUG_ON(!mem_map); #endif /* CONFIG_FLATMEM */ - swiotlb_init(max_pfn > PFN_DOWN(dma32_phys_limit), SWIOTLB_VERBOSE); + if (IS_ENABLED(CONFIG_DMA_BOUNCE_UNALIGNED_KMALLOC) && !swiotlb && + dma_cache_alignment != 1) { + /* + * If no bouncing needed for ZONE_DMA, allocate 1MB swiotlb + * buffer per 1GB of RAM for kmalloc() bouncing on + * non-coherent platforms. + */ + unsigned long size = + DIV_ROUND_UP(memblock_phys_mem_size(), 1024); + swiotlb_adjust_size(min(swiotlb_size_or_default(), size)); + swiotlb = true; + } + + swiotlb_init(swiotlb, SWIOTLB_VERBOSE); memblock_free_all(); print_vm_layout(); -- cgit v1.2.3-59-g8ed1b From 48b4fc66939d5ed49da305cad9788dcd953b5cd2 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Mon, 25 Mar 2024 18:58:23 +0800 Subject: riscv: select ARCH_HAS_FAST_MULTIPLIER Currently, riscv linux requires at least IMA, so all platforms have a multiplier. And I assume the 'mul' efficiency is comparable or better than a sequence of five or so register-dependent arithmetic instructions. Select ARCH_HAS_FAST_MULTIPLIER to get slightly nicer codegen. Refer to commit f9b4192923fa ("[PATCH] bitops: hweight() speedup") for more details. In a simple benchmark test calling hweight64() in a loop, it got: about 14% performance improvement on JH7110, tested on Milkv Mars. about 23% performance improvement on TH1520 and SG2042, tested on Sipeed LPI4A and SG2042 platform. a slight performance drop on CV1800B, tested on milkv duo. Among all riscv platforms in my hands, this is the only one which sees a slight performance drop. It means the 'mul' isn't quick enough. However, the situation exists on x86 too, for example, P4 doesn't have fast integer multiplies as said in the above commit, x86 also selects ARCH_HAS_FAST_MULTIPLIER. So let's select ARCH_HAS_FAST_MULTIPLIER which can benefit almost riscv platforms. Samuel also provided some performance numbers: On Unmatched: 20% speedup for __sw_hweight32 and 30% speedup for __sw_hweight64. On D1: 8% speedup for __sw_hweight32 and 8% slowdown for __sw_hweight64. Signed-off-by: Jisheng Zhang Reviewed-by: Samuel Holland Tested-by: Samuel Holland Reviewed-by: Alexandre Ghiti Link: https://lore.kernel.org/r/20240325105823.1483-1-jszhang@kernel.org Signed-off-by: Palmer Dabbelt --- arch/riscv/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 2dac484ea645..6bec1bce6586 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -23,6 +23,7 @@ config RISCV select ARCH_HAS_DEBUG_VIRTUAL if MMU select ARCH_HAS_DEBUG_VM_PGTABLE select ARCH_HAS_DEBUG_WX + select ARCH_HAS_FAST_MULTIPLIER select ARCH_HAS_FORTIFY_SOURCE select ARCH_HAS_GCOV_PROFILE_ALL select ARCH_HAS_GIGANTIC_PAGE -- cgit v1.2.3-59-g8ed1b From 5e7922abddd4aab1dd604aa3fc7905d2c638c92b Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Mon, 29 Apr 2024 08:13:10 +0800 Subject: riscv: dts: starfive: add 'cpus' label to jh7110 and jh7100 soc dtsi Add the 'cpus' label so that we can reference it in board dts files. Signed-off-by: Jisheng Zhang Reviewed-by: Emil Renner Berthing Signed-off-by: Conor Dooley --- arch/riscv/boot/dts/starfive/jh7100.dtsi | 2 +- arch/riscv/boot/dts/starfive/jh7110.dtsi | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/riscv/boot/dts/starfive/jh7100.dtsi b/arch/riscv/boot/dts/starfive/jh7100.dtsi index 9a2e9583af88..7de0732b8eab 100644 --- a/arch/riscv/boot/dts/starfive/jh7100.dtsi +++ b/arch/riscv/boot/dts/starfive/jh7100.dtsi @@ -13,7 +13,7 @@ #address-cells = <2>; #size-cells = <2>; - cpus { + cpus: cpus { #address-cells = <1>; #size-cells = <0>; diff --git a/arch/riscv/boot/dts/starfive/jh7110.dtsi b/arch/riscv/boot/dts/starfive/jh7110.dtsi index 4a5708f7fcf7..18047195c600 100644 --- a/arch/riscv/boot/dts/starfive/jh7110.dtsi +++ b/arch/riscv/boot/dts/starfive/jh7110.dtsi @@ -15,7 +15,7 @@ #address-cells = <2>; #size-cells = <2>; - cpus { + cpus: cpus { #address-cells = <1>; #size-cells = <0>; -- cgit v1.2.3-59-g8ed1b From 4c536aa462f1e2981147487ca29382f4d48f44b6 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Mon, 29 Apr 2024 08:13:11 +0800 Subject: dt-bindings: riscv: starfive: add Milkv Mars board Add device tree bindings for the Milkv Mars board which is equipped with StarFive JH7110 SoC. Signed-off-by: Jisheng Zhang Acked-by: Krzysztof Kozlowski Reviewed-by: Emil Renner Berthing Signed-off-by: Conor Dooley --- Documentation/devicetree/bindings/riscv/starfive.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/riscv/starfive.yaml b/Documentation/devicetree/bindings/riscv/starfive.yaml index cc4d92f0a1bf..b672f8521949 100644 --- a/Documentation/devicetree/bindings/riscv/starfive.yaml +++ b/Documentation/devicetree/bindings/riscv/starfive.yaml @@ -26,6 +26,7 @@ properties: - items: - enum: + - milkv,mars - starfive,visionfive-2-v1.2a - starfive,visionfive-2-v1.3b - const: starfive,jh7110 -- cgit v1.2.3-59-g8ed1b From b9a1481f259ca3b3ec197df945e57e4ffaeceaaa Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Mon, 29 Apr 2024 08:13:12 +0800 Subject: riscv: dts: starfive: visionfive 2: update sound and codec dt node name Use "audio-codec" as the codec dt node name, and "sound" as the simple audio card dt name. Suggested-by: Krzysztof Kozlowski Signed-off-by: Jisheng Zhang Reviewed-by: Emil Renner Berthing Signed-off-by: Conor Dooley --- arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi index ccd0ce55aa53..50955cc45658 100644 --- a/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi +++ b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi @@ -41,12 +41,12 @@ priority = <224>; }; - pwmdac_codec: pwmdac-codec { + pwmdac_codec: audio-codec { compatible = "linux,spdif-dit"; #sound-dai-cells = <0>; }; - sound-pwmdac { + sound { compatible = "simple-audio-card"; simple-audio-card,name = "StarFive-PWMDAC-Sound-Card"; #address-cells = <1>; -- cgit v1.2.3-59-g8ed1b From ffddddf4aa8d0119c5fba6005b10a1e253a19b59 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Mon, 29 Apr 2024 08:13:13 +0800 Subject: riscv: dts: starfive: visionfive 2: use cpus label for timebase freq As pointed out by Krzysztof "Board should not bring new CPU nodes. Override by label instead." Suggested-by: Krzysztof Kozlowski Signed-off-by: Jisheng Zhang Reviewed-by: Emil Renner Berthing Signed-off-by: Conor Dooley --- arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi index 50955cc45658..910c07bd4af9 100644 --- a/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi +++ b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi @@ -26,10 +26,6 @@ stdout-path = "serial0:115200n8"; }; - cpus { - timebase-frequency = <4000000>; - }; - memory@40000000 { device_type = "memory"; reg = <0x0 0x40000000 0x1 0x0>; @@ -69,6 +65,10 @@ }; }; +&cpus { + timebase-frequency = <4000000>; +}; + &dvp_clk { clock-frequency = <74250000>; }; -- cgit v1.2.3-59-g8ed1b From 0ffce9d49abd9492ea4959ebd3a6e9c12bf3ed70 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Mon, 29 Apr 2024 08:13:14 +0800 Subject: riscv: dts: starfive: visionfive 2: add tf cd-gpios Per VisionFive 2 1.2B, and 1.3A boards' SCH, GPIO 41 is used as card detect. So add "cd-gpios" property for this. Signed-off-by: Jisheng Zhang Reviewed-by: Emil Renner Berthing Signed-off-by: Conor Dooley --- arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi index 910c07bd4af9..b6030d63459d 100644 --- a/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi +++ b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi @@ -303,7 +303,7 @@ bus-width = <4>; no-sdio; no-mmc; - broken-cd; + cd-gpios = <&sysgpio 41 GPIO_ACTIVE_LOW>; cap-sd-highspeed; post-power-on-delay-ms = <200>; pinctrl-names = "default"; -- cgit v1.2.3-59-g8ed1b From 07da6ddf510beb47c059f515cbb92835e146aeb1 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Mon, 29 Apr 2024 08:13:15 +0800 Subject: riscv: dts: starfive: visionfive 2: add "disable-wp" for tfcard No physical write-protect line is present, so setting "disable-wp". Signed-off-by: Jisheng Zhang Reviewed-by: Emil Renner Berthing Signed-off-by: Conor Dooley --- arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi index b6030d63459d..e19f26628054 100644 --- a/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi +++ b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi @@ -304,6 +304,7 @@ no-sdio; no-mmc; cd-gpios = <&sysgpio 41 GPIO_ACTIVE_LOW>; + disable-wp; cap-sd-highspeed; post-power-on-delay-ms = <200>; pinctrl-names = "default"; -- cgit v1.2.3-59-g8ed1b From ac9a37e2d6b6373d657366a365d9e05b32221e3d Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Mon, 29 Apr 2024 08:13:16 +0800 Subject: riscv: dts: starfive: introduce a common board dtsi for jh7110 based boards This is to prepare for Milkv Mars board dts support in the following patch. Let's factored out common part into .dtsi. Signed-off-by: Jisheng Zhang Reviewed-by: Emil Renner Berthing Signed-off-by: Conor Dooley --- arch/riscv/boot/dts/starfive/jh7110-common.dtsi | 599 +++++++++++++++++++++ .../dts/starfive/jh7110-starfive-visionfive-2.dtsi | 585 +------------------- 2 files changed, 600 insertions(+), 584 deletions(-) create mode 100644 arch/riscv/boot/dts/starfive/jh7110-common.dtsi diff --git a/arch/riscv/boot/dts/starfive/jh7110-common.dtsi b/arch/riscv/boot/dts/starfive/jh7110-common.dtsi new file mode 100644 index 000000000000..8ff6ea64f048 --- /dev/null +++ b/arch/riscv/boot/dts/starfive/jh7110-common.dtsi @@ -0,0 +1,599 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT +/* + * Copyright (C) 2022 StarFive Technology Co., Ltd. + * Copyright (C) 2022 Emil Renner Berthing + */ + +/dts-v1/; +#include "jh7110.dtsi" +#include "jh7110-pinfunc.h" +#include + +/ { + aliases { + ethernet0 = &gmac0; + i2c0 = &i2c0; + i2c2 = &i2c2; + i2c5 = &i2c5; + i2c6 = &i2c6; + mmc0 = &mmc0; + mmc1 = &mmc1; + serial0 = &uart0; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + memory@40000000 { + device_type = "memory"; + reg = <0x0 0x40000000 0x1 0x0>; + }; + + gpio-restart { + compatible = "gpio-restart"; + gpios = <&sysgpio 35 GPIO_ACTIVE_HIGH>; + priority = <224>; + }; + + pwmdac_codec: audio-codec { + compatible = "linux,spdif-dit"; + #sound-dai-cells = <0>; + }; + + sound { + compatible = "simple-audio-card"; + simple-audio-card,name = "StarFive-PWMDAC-Sound-Card"; + #address-cells = <1>; + #size-cells = <0>; + + simple-audio-card,dai-link@0 { + reg = <0>; + format = "left_j"; + bitclock-master = <&sndcpu0>; + frame-master = <&sndcpu0>; + + sndcpu0: cpu { + sound-dai = <&pwmdac>; + }; + + codec { + sound-dai = <&pwmdac_codec>; + }; + }; + }; +}; + +&cpus { + timebase-frequency = <4000000>; +}; + +&dvp_clk { + clock-frequency = <74250000>; +}; + +&gmac0_rgmii_rxin { + clock-frequency = <125000000>; +}; + +&gmac0_rmii_refin { + clock-frequency = <50000000>; +}; + +&gmac1_rgmii_rxin { + clock-frequency = <125000000>; +}; + +&gmac1_rmii_refin { + clock-frequency = <50000000>; +}; + +&hdmitx0_pixelclk { + clock-frequency = <297000000>; +}; + +&i2srx_bclk_ext { + clock-frequency = <12288000>; +}; + +&i2srx_lrck_ext { + clock-frequency = <192000>; +}; + +&i2stx_bclk_ext { + clock-frequency = <12288000>; +}; + +&i2stx_lrck_ext { + clock-frequency = <192000>; +}; + +&mclk_ext { + clock-frequency = <12288000>; +}; + +&osc { + clock-frequency = <24000000>; +}; + +&rtc_osc { + clock-frequency = <32768>; +}; + +&tdm_ext { + clock-frequency = <49152000>; +}; + +&camss { + assigned-clocks = <&ispcrg JH7110_ISPCLK_DOM4_APB_FUNC>, + <&ispcrg JH7110_ISPCLK_MIPI_RX0_PXL>; + assigned-clock-rates = <49500000>, <198000000>; + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + }; + + port@1 { + reg = <1>; + + camss_from_csi2rx: endpoint { + remote-endpoint = <&csi2rx_to_camss>; + }; + }; + }; +}; + +&csi2rx { + assigned-clocks = <&ispcrg JH7110_ISPCLK_VIN_SYS>; + assigned-clock-rates = <297000000>; + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + /* remote MIPI sensor endpoint */ + }; + + port@1 { + reg = <1>; + + csi2rx_to_camss: endpoint { + remote-endpoint = <&camss_from_csi2rx>; + }; + }; + }; +}; + +&gmac0 { + phy-handle = <&phy0>; + phy-mode = "rgmii-id"; + status = "okay"; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + compatible = "snps,dwmac-mdio"; + + phy0: ethernet-phy@0 { + reg = <0>; + }; + }; +}; + +&i2c0 { + clock-frequency = <100000>; + i2c-sda-hold-time-ns = <300>; + i2c-sda-falling-time-ns = <510>; + i2c-scl-falling-time-ns = <510>; + pinctrl-names = "default"; + pinctrl-0 = <&i2c0_pins>; + status = "okay"; +}; + +&i2c2 { + clock-frequency = <100000>; + i2c-sda-hold-time-ns = <300>; + i2c-sda-falling-time-ns = <510>; + i2c-scl-falling-time-ns = <510>; + pinctrl-names = "default"; + pinctrl-0 = <&i2c2_pins>; + status = "okay"; +}; + +&i2c5 { + clock-frequency = <100000>; + i2c-sda-hold-time-ns = <300>; + i2c-sda-falling-time-ns = <510>; + i2c-scl-falling-time-ns = <510>; + pinctrl-names = "default"; + pinctrl-0 = <&i2c5_pins>; + status = "okay"; + + axp15060: pmic@36 { + compatible = "x-powers,axp15060"; + reg = <0x36>; + interrupt-controller; + #interrupt-cells = <1>; + + regulators { + vcc_3v3: dcdc1 { + regulator-boot-on; + regulator-always-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vcc_3v3"; + }; + + vdd_cpu: dcdc2 { + regulator-always-on; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <1540000>; + regulator-name = "vdd-cpu"; + }; + + emmc_vdd: aldo4 { + regulator-boot-on; + regulator-always-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-name = "emmc_vdd"; + }; + }; + }; +}; + +&i2c6 { + clock-frequency = <100000>; + i2c-sda-hold-time-ns = <300>; + i2c-sda-falling-time-ns = <510>; + i2c-scl-falling-time-ns = <510>; + pinctrl-names = "default"; + pinctrl-0 = <&i2c6_pins>; + status = "okay"; +}; + +&mmc0 { + max-frequency = <100000000>; + assigned-clocks = <&syscrg JH7110_SYSCLK_SDIO0_SDCARD>; + assigned-clock-rates = <50000000>; + bus-width = <8>; + cap-mmc-highspeed; + mmc-ddr-1_8v; + mmc-hs200-1_8v; + cap-mmc-hw-reset; + post-power-on-delay-ms = <200>; + pinctrl-names = "default"; + pinctrl-0 = <&mmc0_pins>; + vmmc-supply = <&vcc_3v3>; + vqmmc-supply = <&emmc_vdd>; + status = "okay"; +}; + +&mmc1 { + max-frequency = <100000000>; + assigned-clocks = <&syscrg JH7110_SYSCLK_SDIO1_SDCARD>; + assigned-clock-rates = <50000000>; + bus-width = <4>; + no-sdio; + no-mmc; + cd-gpios = <&sysgpio 41 GPIO_ACTIVE_LOW>; + disable-wp; + cap-sd-highspeed; + post-power-on-delay-ms = <200>; + pinctrl-names = "default"; + pinctrl-0 = <&mmc1_pins>; + status = "okay"; +}; + +&pwmdac { + pinctrl-names = "default"; + pinctrl-0 = <&pwmdac_pins>; + status = "okay"; +}; + +&qspi { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + nor_flash: flash@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + cdns,read-delay = <5>; + spi-max-frequency = <12000000>; + cdns,tshsl-ns = <1>; + cdns,tsd2d-ns = <1>; + cdns,tchsh-ns = <1>; + cdns,tslch-ns = <1>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + spl@0 { + reg = <0x0 0x80000>; + }; + uboot-env@f0000 { + reg = <0xf0000 0x10000>; + }; + uboot@100000 { + reg = <0x100000 0x400000>; + }; + reserved-data@600000 { + reg = <0x600000 0xa00000>; + }; + }; + }; +}; + +&pwm { + pinctrl-names = "default"; + pinctrl-0 = <&pwm_pins>; + status = "okay"; +}; + +&spi0 { + pinctrl-names = "default"; + pinctrl-0 = <&spi0_pins>; + status = "okay"; + + spi_dev0: spi@0 { + compatible = "rohm,dh2228fv"; + reg = <0>; + spi-max-frequency = <10000000>; + }; +}; + +&sysgpio { + i2c0_pins: i2c0-0 { + i2c-pins { + pinmux = , + ; + bias-disable; /* external pull-up */ + input-enable; + input-schmitt-enable; + }; + }; + + i2c2_pins: i2c2-0 { + i2c-pins { + pinmux = , + ; + bias-disable; /* external pull-up */ + input-enable; + input-schmitt-enable; + }; + }; + + i2c5_pins: i2c5-0 { + i2c-pins { + pinmux = , + ; + bias-disable; /* external pull-up */ + input-enable; + input-schmitt-enable; + }; + }; + + i2c6_pins: i2c6-0 { + i2c-pins { + pinmux = , + ; + bias-disable; /* external pull-up */ + input-enable; + input-schmitt-enable; + }; + }; + + mmc0_pins: mmc0-0 { + rst-pins { + pinmux = ; + bias-pull-up; + drive-strength = <12>; + input-disable; + input-schmitt-disable; + slew-rate = <0>; + }; + + mmc-pins { + pinmux = , + , + , + , + , + , + , + , + , + ; + bias-pull-up; + drive-strength = <12>; + input-enable; + }; + }; + + mmc1_pins: mmc1-0 { + clk-pins { + pinmux = ; + bias-pull-up; + drive-strength = <12>; + input-disable; + input-schmitt-disable; + slew-rate = <0>; + }; + + mmc-pins { + pinmux = , + , + , + , + ; + bias-pull-up; + drive-strength = <12>; + input-enable; + input-schmitt-enable; + slew-rate = <0>; + }; + }; + + pwmdac_pins: pwmdac-0 { + pwmdac-pins { + pinmux = , + ; + bias-disable; + drive-strength = <2>; + input-disable; + input-schmitt-disable; + slew-rate = <0>; + }; + }; + + pwm_pins: pwm-0 { + pwm-pins { + pinmux = , + ; + bias-disable; + drive-strength = <12>; + input-disable; + input-schmitt-disable; + slew-rate = <0>; + }; + }; + + spi0_pins: spi0-0 { + mosi-pins { + pinmux = ; + bias-disable; + input-disable; + input-schmitt-disable; + }; + + miso-pins { + pinmux = ; + bias-pull-up; + input-enable; + input-schmitt-enable; + }; + + sck-pins { + pinmux = ; + bias-disable; + input-disable; + input-schmitt-disable; + }; + + ss-pins { + pinmux = ; + bias-disable; + input-disable; + input-schmitt-disable; + }; + }; + + uart0_pins: uart0-0 { + tx-pins { + pinmux = ; + bias-disable; + drive-strength = <12>; + input-disable; + input-schmitt-disable; + slew-rate = <0>; + }; + + rx-pins { + pinmux = ; + bias-disable; /* external pull-up */ + drive-strength = <2>; + input-enable; + input-schmitt-enable; + slew-rate = <0>; + }; + }; +}; + +&uart0 { + pinctrl-names = "default"; + pinctrl-0 = <&uart0_pins>; + status = "okay"; +}; + +&usb0 { + dr_mode = "peripheral"; + status = "okay"; +}; + +&U74_1 { + cpu-supply = <&vdd_cpu>; +}; + +&U74_2 { + cpu-supply = <&vdd_cpu>; +}; + +&U74_3 { + cpu-supply = <&vdd_cpu>; +}; + +&U74_4 { + cpu-supply = <&vdd_cpu>; +}; diff --git a/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi index e19f26628054..9d70f21c86fc 100644 --- a/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi +++ b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi @@ -5,188 +5,11 @@ */ /dts-v1/; -#include "jh7110.dtsi" -#include "jh7110-pinfunc.h" -#include +#include "jh7110-common.dtsi" / { aliases { - ethernet0 = &gmac0; ethernet1 = &gmac1; - i2c0 = &i2c0; - i2c2 = &i2c2; - i2c5 = &i2c5; - i2c6 = &i2c6; - mmc0 = &mmc0; - mmc1 = &mmc1; - serial0 = &uart0; - }; - - chosen { - stdout-path = "serial0:115200n8"; - }; - - memory@40000000 { - device_type = "memory"; - reg = <0x0 0x40000000 0x1 0x0>; - }; - - gpio-restart { - compatible = "gpio-restart"; - gpios = <&sysgpio 35 GPIO_ACTIVE_HIGH>; - priority = <224>; - }; - - pwmdac_codec: audio-codec { - compatible = "linux,spdif-dit"; - #sound-dai-cells = <0>; - }; - - sound { - compatible = "simple-audio-card"; - simple-audio-card,name = "StarFive-PWMDAC-Sound-Card"; - #address-cells = <1>; - #size-cells = <0>; - - simple-audio-card,dai-link@0 { - reg = <0>; - format = "left_j"; - bitclock-master = <&sndcpu0>; - frame-master = <&sndcpu0>; - - sndcpu0: cpu { - sound-dai = <&pwmdac>; - }; - - codec { - sound-dai = <&pwmdac_codec>; - }; - }; - }; -}; - -&cpus { - timebase-frequency = <4000000>; -}; - -&dvp_clk { - clock-frequency = <74250000>; -}; - -&gmac0_rgmii_rxin { - clock-frequency = <125000000>; -}; - -&gmac0_rmii_refin { - clock-frequency = <50000000>; -}; - -&gmac1_rgmii_rxin { - clock-frequency = <125000000>; -}; - -&gmac1_rmii_refin { - clock-frequency = <50000000>; -}; - -&hdmitx0_pixelclk { - clock-frequency = <297000000>; -}; - -&i2srx_bclk_ext { - clock-frequency = <12288000>; -}; - -&i2srx_lrck_ext { - clock-frequency = <192000>; -}; - -&i2stx_bclk_ext { - clock-frequency = <12288000>; -}; - -&i2stx_lrck_ext { - clock-frequency = <192000>; -}; - -&mclk_ext { - clock-frequency = <12288000>; -}; - -&osc { - clock-frequency = <24000000>; -}; - -&rtc_osc { - clock-frequency = <32768>; -}; - -&tdm_ext { - clock-frequency = <49152000>; -}; - -&camss { - assigned-clocks = <&ispcrg JH7110_ISPCLK_DOM4_APB_FUNC>, - <&ispcrg JH7110_ISPCLK_MIPI_RX0_PXL>; - assigned-clock-rates = <49500000>, <198000000>; - status = "okay"; - - ports { - #address-cells = <1>; - #size-cells = <0>; - - port@0 { - reg = <0>; - }; - - port@1 { - reg = <1>; - - camss_from_csi2rx: endpoint { - remote-endpoint = <&csi2rx_to_camss>; - }; - }; - }; -}; - -&csi2rx { - assigned-clocks = <&ispcrg JH7110_ISPCLK_VIN_SYS>; - assigned-clock-rates = <297000000>; - status = "okay"; - - ports { - #address-cells = <1>; - #size-cells = <0>; - - port@0 { - reg = <0>; - - /* remote MIPI sensor endpoint */ - }; - - port@1 { - reg = <1>; - - csi2rx_to_camss: endpoint { - remote-endpoint = <&camss_from_csi2rx>; - }; - }; - }; -}; - -&gmac0 { - phy-handle = <&phy0>; - phy-mode = "rgmii-id"; - status = "okay"; - - mdio { - #address-cells = <1>; - #size-cells = <0>; - compatible = "snps,dwmac-mdio"; - - phy0: ethernet-phy@0 { - reg = <0>; - }; }; }; @@ -206,412 +29,6 @@ }; }; -&i2c0 { - clock-frequency = <100000>; - i2c-sda-hold-time-ns = <300>; - i2c-sda-falling-time-ns = <510>; - i2c-scl-falling-time-ns = <510>; - pinctrl-names = "default"; - pinctrl-0 = <&i2c0_pins>; - status = "okay"; -}; - -&i2c2 { - clock-frequency = <100000>; - i2c-sda-hold-time-ns = <300>; - i2c-sda-falling-time-ns = <510>; - i2c-scl-falling-time-ns = <510>; - pinctrl-names = "default"; - pinctrl-0 = <&i2c2_pins>; - status = "okay"; -}; - -&i2c5 { - clock-frequency = <100000>; - i2c-sda-hold-time-ns = <300>; - i2c-sda-falling-time-ns = <510>; - i2c-scl-falling-time-ns = <510>; - pinctrl-names = "default"; - pinctrl-0 = <&i2c5_pins>; - status = "okay"; - - axp15060: pmic@36 { - compatible = "x-powers,axp15060"; - reg = <0x36>; - interrupt-controller; - #interrupt-cells = <1>; - - regulators { - vcc_3v3: dcdc1 { - regulator-boot-on; - regulator-always-on; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - regulator-name = "vcc_3v3"; - }; - - vdd_cpu: dcdc2 { - regulator-always-on; - regulator-min-microvolt = <500000>; - regulator-max-microvolt = <1540000>; - regulator-name = "vdd-cpu"; - }; - - emmc_vdd: aldo4 { - regulator-boot-on; - regulator-always-on; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - regulator-name = "emmc_vdd"; - }; - }; - }; -}; - -&i2c6 { - clock-frequency = <100000>; - i2c-sda-hold-time-ns = <300>; - i2c-sda-falling-time-ns = <510>; - i2c-scl-falling-time-ns = <510>; - pinctrl-names = "default"; - pinctrl-0 = <&i2c6_pins>; - status = "okay"; -}; - &mmc0 { - max-frequency = <100000000>; - assigned-clocks = <&syscrg JH7110_SYSCLK_SDIO0_SDCARD>; - assigned-clock-rates = <50000000>; - bus-width = <8>; - cap-mmc-highspeed; - mmc-ddr-1_8v; - mmc-hs200-1_8v; non-removable; - cap-mmc-hw-reset; - post-power-on-delay-ms = <200>; - pinctrl-names = "default"; - pinctrl-0 = <&mmc0_pins>; - vmmc-supply = <&vcc_3v3>; - vqmmc-supply = <&emmc_vdd>; - status = "okay"; -}; - -&mmc1 { - max-frequency = <100000000>; - assigned-clocks = <&syscrg JH7110_SYSCLK_SDIO1_SDCARD>; - assigned-clock-rates = <50000000>; - bus-width = <4>; - no-sdio; - no-mmc; - cd-gpios = <&sysgpio 41 GPIO_ACTIVE_LOW>; - disable-wp; - cap-sd-highspeed; - post-power-on-delay-ms = <200>; - pinctrl-names = "default"; - pinctrl-0 = <&mmc1_pins>; - status = "okay"; -}; - -&pwmdac { - pinctrl-names = "default"; - pinctrl-0 = <&pwmdac_pins>; - status = "okay"; -}; - -&qspi { - #address-cells = <1>; - #size-cells = <0>; - status = "okay"; - - nor_flash: flash@0 { - compatible = "jedec,spi-nor"; - reg = <0>; - cdns,read-delay = <5>; - spi-max-frequency = <12000000>; - cdns,tshsl-ns = <1>; - cdns,tsd2d-ns = <1>; - cdns,tchsh-ns = <1>; - cdns,tslch-ns = <1>; - - partitions { - compatible = "fixed-partitions"; - #address-cells = <1>; - #size-cells = <1>; - - spl@0 { - reg = <0x0 0x80000>; - }; - uboot-env@f0000 { - reg = <0xf0000 0x10000>; - }; - uboot@100000 { - reg = <0x100000 0x400000>; - }; - reserved-data@600000 { - reg = <0x600000 0xa00000>; - }; - }; - }; -}; - -&pwm { - pinctrl-names = "default"; - pinctrl-0 = <&pwm_pins>; - status = "okay"; -}; - -&spi0 { - pinctrl-names = "default"; - pinctrl-0 = <&spi0_pins>; - status = "okay"; - - spi_dev0: spi@0 { - compatible = "rohm,dh2228fv"; - reg = <0>; - spi-max-frequency = <10000000>; - }; -}; - -&sysgpio { - i2c0_pins: i2c0-0 { - i2c-pins { - pinmux = , - ; - bias-disable; /* external pull-up */ - input-enable; - input-schmitt-enable; - }; - }; - - i2c2_pins: i2c2-0 { - i2c-pins { - pinmux = , - ; - bias-disable; /* external pull-up */ - input-enable; - input-schmitt-enable; - }; - }; - - i2c5_pins: i2c5-0 { - i2c-pins { - pinmux = , - ; - bias-disable; /* external pull-up */ - input-enable; - input-schmitt-enable; - }; - }; - - i2c6_pins: i2c6-0 { - i2c-pins { - pinmux = , - ; - bias-disable; /* external pull-up */ - input-enable; - input-schmitt-enable; - }; - }; - - mmc0_pins: mmc0-0 { - rst-pins { - pinmux = ; - bias-pull-up; - drive-strength = <12>; - input-disable; - input-schmitt-disable; - slew-rate = <0>; - }; - - mmc-pins { - pinmux = , - , - , - , - , - , - , - , - , - ; - bias-pull-up; - drive-strength = <12>; - input-enable; - }; - }; - - mmc1_pins: mmc1-0 { - clk-pins { - pinmux = ; - bias-pull-up; - drive-strength = <12>; - input-disable; - input-schmitt-disable; - slew-rate = <0>; - }; - - mmc-pins { - pinmux = , - , - , - , - ; - bias-pull-up; - drive-strength = <12>; - input-enable; - input-schmitt-enable; - slew-rate = <0>; - }; - }; - - pwmdac_pins: pwmdac-0 { - pwmdac-pins { - pinmux = , - ; - bias-disable; - drive-strength = <2>; - input-disable; - input-schmitt-disable; - slew-rate = <0>; - }; - }; - - pwm_pins: pwm-0 { - pwm-pins { - pinmux = , - ; - bias-disable; - drive-strength = <12>; - input-disable; - input-schmitt-disable; - slew-rate = <0>; - }; - }; - - spi0_pins: spi0-0 { - mosi-pins { - pinmux = ; - bias-disable; - input-disable; - input-schmitt-disable; - }; - - miso-pins { - pinmux = ; - bias-pull-up; - input-enable; - input-schmitt-enable; - }; - - sck-pins { - pinmux = ; - bias-disable; - input-disable; - input-schmitt-disable; - }; - - ss-pins { - pinmux = ; - bias-disable; - input-disable; - input-schmitt-disable; - }; - }; - - uart0_pins: uart0-0 { - tx-pins { - pinmux = ; - bias-disable; - drive-strength = <12>; - input-disable; - input-schmitt-disable; - slew-rate = <0>; - }; - - rx-pins { - pinmux = ; - bias-disable; /* external pull-up */ - drive-strength = <2>; - input-enable; - input-schmitt-enable; - slew-rate = <0>; - }; - }; -}; - -&uart0 { - pinctrl-names = "default"; - pinctrl-0 = <&uart0_pins>; - status = "okay"; -}; - -&usb0 { - dr_mode = "peripheral"; - status = "okay"; -}; - -&U74_1 { - cpu-supply = <&vdd_cpu>; -}; - -&U74_2 { - cpu-supply = <&vdd_cpu>; -}; - -&U74_3 { - cpu-supply = <&vdd_cpu>; -}; - -&U74_4 { - cpu-supply = <&vdd_cpu>; }; -- cgit v1.2.3-59-g8ed1b From 9276badd9d03ddadc83dc5db35198bcb2503ced9 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Mon, 29 Apr 2024 08:13:17 +0800 Subject: riscv: dts: starfive: add Milkv Mars board device tree The Milkv Mars is a development board based on the Starfive JH7110 SoC. The board features: - JH7110 SoC - 1/2/4/8 GiB LPDDR4 DRAM - AXP15060 PMIC - 40 pin GPIO header - 3x USB 3.0 host port - 1x USB 2.0 host port - 1x M.2 E-Key - 1x eMMC slot - 1x MicroSD slot - 1x QSPI Flash - 1x 1Gbps Ethernet port - 1x HDMI port - 1x 2-lane DSI and 1x 4-lane DSI - 1x 2-lane CSI Add the devicetree file describing the currently supported features, namely PMIC, UART, I2C, GPIO, SD card, QSPI Flash, eMMC and Ethernet. Signed-off-by: Jisheng Zhang Reviewed-by: Emil Renner Berthing Signed-off-by: Conor Dooley --- arch/riscv/boot/dts/starfive/Makefile | 1 + arch/riscv/boot/dts/starfive/jh7110-milkv-mars.dts | 30 ++++++++++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 arch/riscv/boot/dts/starfive/jh7110-milkv-mars.dts diff --git a/arch/riscv/boot/dts/starfive/Makefile b/arch/riscv/boot/dts/starfive/Makefile index 0141504c0f5c..2fa0cd7f31c3 100644 --- a/arch/riscv/boot/dts/starfive/Makefile +++ b/arch/riscv/boot/dts/starfive/Makefile @@ -8,5 +8,6 @@ DTC_FLAGS_jh7110-starfive-visionfive-2-v1.3b := -@ dtb-$(CONFIG_ARCH_STARFIVE) += jh7100-beaglev-starlight.dtb dtb-$(CONFIG_ARCH_STARFIVE) += jh7100-starfive-visionfive-v1.dtb +dtb-$(CONFIG_ARCH_STARFIVE) += jh7110-milkv-mars.dtb dtb-$(CONFIG_ARCH_STARFIVE) += jh7110-starfive-visionfive-2-v1.2a.dtb dtb-$(CONFIG_ARCH_STARFIVE) += jh7110-starfive-visionfive-2-v1.3b.dtb diff --git a/arch/riscv/boot/dts/starfive/jh7110-milkv-mars.dts b/arch/riscv/boot/dts/starfive/jh7110-milkv-mars.dts new file mode 100644 index 000000000000..fa0eac78e0ba --- /dev/null +++ b/arch/riscv/boot/dts/starfive/jh7110-milkv-mars.dts @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT +/* + * Copyright (C) 2023 Jisheng Zhang + */ + +/dts-v1/; +#include "jh7110-common.dtsi" + +/ { + model = "Milk-V Mars"; + compatible = "milkv,mars", "starfive,jh7110"; +}; + +&gmac0 { + starfive,tx-use-rgmii-clk; + assigned-clocks = <&aoncrg JH7110_AONCLK_GMAC0_TX>; + assigned-clock-parents = <&aoncrg JH7110_AONCLK_GMAC0_RMII_RTX>; +}; + + +&phy0 { + motorcomm,tx-clk-adj-enabled; + motorcomm,tx-clk-10-inverted; + motorcomm,tx-clk-100-inverted; + motorcomm,tx-clk-1000-inverted; + motorcomm,rx-clk-drv-microamp = <3970>; + motorcomm,rx-data-drv-microamp = <2910>; + rx-internal-delay-ps = <1500>; + tx-internal-delay-ps = <1500>; +}; -- cgit v1.2.3-59-g8ed1b From a08b8f8557ad88ffdff8905e5da972afe52e3307 Mon Sep 17 00:00:00 2001 From: Erick Archer Date: Sat, 27 Apr 2024 17:05:56 +0200 Subject: Input: ff-core - prefer struct_size over open coded arithmetic This is an effort to get rid of all multiplications from allocation functions in order to prevent integer overflows [1][2]. As the "ff" variable is a pointer to "struct ff_device" and this structure ends in a flexible array: struct ff_device { [...] struct file *effect_owners[] __counted_by(max_effects); }; the preferred way in the kernel is to use the struct_size() helper to do the arithmetic instead of the calculation "size + count * size" in the kzalloc() function. The struct_size() helper returns SIZE_MAX on overflow. So, refactor the comparison to take advantage of this. This way, the code is more readable and safer. This code was detected with the help of Coccinelle, and audited and modified manually. Link: https://www.kernel.org/doc/html/latest/process/deprecated.html#open-coded-arithmetic-in-allocator-arguments [1] Link: https://github.com/KSPP/linux/issues/160 [2] Signed-off-by: Erick Archer Reviewed-by: Kees Cook Link: https://lore.kernel.org/r/AS8PR02MB72371E646714BAE2E51A6A378B152@AS8PR02MB7237.eurprd02.prod.outlook.com Signed-off-by: Dmitry Torokhov --- drivers/input/ff-core.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/input/ff-core.c b/drivers/input/ff-core.c index 16231fe080b0..609a5f01761b 100644 --- a/drivers/input/ff-core.c +++ b/drivers/input/ff-core.c @@ -9,8 +9,10 @@ /* #define DEBUG */ #include +#include #include #include +#include #include #include @@ -315,9 +317,8 @@ int input_ff_create(struct input_dev *dev, unsigned int max_effects) return -EINVAL; } - ff_dev_size = sizeof(struct ff_device) + - max_effects * sizeof(struct file *); - if (ff_dev_size < max_effects) /* overflow */ + ff_dev_size = struct_size(ff, effect_owners, max_effects); + if (ff_dev_size == SIZE_MAX) /* overflow */ return -EINVAL; ff = kzalloc(ff_dev_size, GFP_KERNEL); -- cgit v1.2.3-59-g8ed1b From 6efb495826a905814e2aaa68dc756694686e864f Mon Sep 17 00:00:00 2001 From: Ben Levinsky Date: Wed, 10 Apr 2024 10:08:23 -0700 Subject: mailbox: zynqmp: Move of_match structure closer to usage The of_match structure zynqmp_ipi_of_match is now adjacent to where it used in the zynqmp_ipi_driver structure for readability. Signed-off-by: Ben Levinsky Signed-off-by: Jassi Brar --- drivers/mailbox/zynqmp-ipi-mailbox.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/mailbox/zynqmp-ipi-mailbox.c b/drivers/mailbox/zynqmp-ipi-mailbox.c index 25c65afc030a..c7ce0826383f 100644 --- a/drivers/mailbox/zynqmp-ipi-mailbox.c +++ b/drivers/mailbox/zynqmp-ipi-mailbox.c @@ -415,12 +415,6 @@ static struct mbox_chan *zynqmp_ipi_of_xlate(struct mbox_controller *mbox, return chan; } -static const struct of_device_id zynqmp_ipi_of_match[] = { - { .compatible = "xlnx,zynqmp-ipi-mailbox" }, - {}, -}; -MODULE_DEVICE_TABLE(of, zynqmp_ipi_of_match); - /** * zynqmp_ipi_mbox_get_buf_res - Get buffer resource from the IPI dev node * @@ -695,6 +689,12 @@ static void zynqmp_ipi_remove(struct platform_device *pdev) zynqmp_ipi_free_mboxes(pdata); } +static const struct of_device_id zynqmp_ipi_of_match[] = { + { .compatible = "xlnx,zynqmp-ipi-mailbox" }, + {}, +}; +MODULE_DEVICE_TABLE(of, zynqmp_ipi_of_match); + static struct platform_driver zynqmp_ipi_driver = { .probe = zynqmp_ipi_probe, .remove_new = zynqmp_ipi_remove, -- cgit v1.2.3-59-g8ed1b From 41bcf30100c521c73f0fcf05c3dc31967e6408be Mon Sep 17 00:00:00 2001 From: Ben Levinsky Date: Wed, 10 Apr 2024 10:08:24 -0700 Subject: mailbox: zynqmp: Move buffered IPI setup to of_match selected routine Move routine that initializes the mailboxes for send and receive to a function pointer that is set based on compatible string. Signed-off-by: Ben Levinsky Signed-off-by: Jassi Brar --- drivers/mailbox/zynqmp-ipi-mailbox.c | 122 +++++++++++++++++++++++++---------- 1 file changed, 87 insertions(+), 35 deletions(-) diff --git a/drivers/mailbox/zynqmp-ipi-mailbox.c b/drivers/mailbox/zynqmp-ipi-mailbox.c index c7ce0826383f..56ba7135db54 100644 --- a/drivers/mailbox/zynqmp-ipi-mailbox.c +++ b/drivers/mailbox/zynqmp-ipi-mailbox.c @@ -72,6 +72,10 @@ struct zynqmp_ipi_mchan { unsigned int chan_type; }; +struct zynqmp_ipi_mbox; + +typedef int (*setup_ipi_fn)(struct zynqmp_ipi_mbox *ipi_mbox, struct device_node *node); + /** * struct zynqmp_ipi_mbox - Description of a ZynqMP IPI mailbox * platform data. @@ -81,6 +85,7 @@ struct zynqmp_ipi_mchan { * @remote_id: remote IPI agent ID * @mbox: mailbox Controller * @mchans: array for channels, tx channel and rx channel. + * @setup_ipi_fn: Function Pointer to set up IPI Channels */ struct zynqmp_ipi_mbox { struct zynqmp_ipi_pdata *pdata; @@ -88,6 +93,7 @@ struct zynqmp_ipi_mbox { u32 remote_id; struct mbox_controller mbox; struct zynqmp_ipi_mchan mchans[2]; + setup_ipi_fn setup_ipi_fn; }; /** @@ -464,12 +470,9 @@ static void zynqmp_ipi_mbox_dev_release(struct device *dev) static int zynqmp_ipi_mbox_probe(struct zynqmp_ipi_mbox *ipi_mbox, struct device_node *node) { - struct zynqmp_ipi_mchan *mchan; struct mbox_chan *chans; struct mbox_controller *mbox; - struct resource res; struct device *dev, *mdev; - const char *name; int ret; dev = ipi_mbox->pdata->dev; @@ -489,6 +492,73 @@ static int zynqmp_ipi_mbox_probe(struct zynqmp_ipi_mbox *ipi_mbox, } mdev = &ipi_mbox->dev; + /* Get the IPI remote agent ID */ + ret = of_property_read_u32(node, "xlnx,ipi-id", &ipi_mbox->remote_id); + if (ret < 0) { + dev_err(dev, "No IPI remote ID is specified.\n"); + return ret; + } + + ret = ipi_mbox->setup_ipi_fn(ipi_mbox, node); + if (ret) { + dev_err(dev, "Failed to set up IPI Buffers.\n"); + return ret; + } + + mbox = &ipi_mbox->mbox; + mbox->dev = mdev; + mbox->ops = &zynqmp_ipi_chan_ops; + mbox->num_chans = 2; + mbox->txdone_irq = false; + mbox->txdone_poll = true; + mbox->txpoll_period = 5; + mbox->of_xlate = zynqmp_ipi_of_xlate; + chans = devm_kzalloc(mdev, 2 * sizeof(*chans), GFP_KERNEL); + if (!chans) + return -ENOMEM; + mbox->chans = chans; + chans[IPI_MB_CHNL_TX].con_priv = &ipi_mbox->mchans[IPI_MB_CHNL_TX]; + chans[IPI_MB_CHNL_RX].con_priv = &ipi_mbox->mchans[IPI_MB_CHNL_RX]; + ipi_mbox->mchans[IPI_MB_CHNL_TX].chan_type = IPI_MB_CHNL_TX; + ipi_mbox->mchans[IPI_MB_CHNL_RX].chan_type = IPI_MB_CHNL_RX; + ret = devm_mbox_controller_register(mdev, mbox); + if (ret) + dev_err(mdev, + "Failed to register mbox_controller(%d)\n", ret); + else + dev_info(mdev, + "Registered ZynqMP IPI mbox with TX/RX channels.\n"); + return ret; +} + +/** + * zynqmp_ipi_setup - set up IPI Buffers for classic flow + * + * @ipi_mbox: pointer to IPI mailbox private data structure + * @node: IPI mailbox device node + * + * This will be used to set up IPI Buffers for ZynqMP SOC if user + * wishes to use classic driver usage model on new SOC's with only + * buffered IPIs. + * + * Note that bufferless IPIs and mixed usage of buffered and bufferless + * IPIs are not supported with this flow. + * + * This will be invoked with compatible string "xlnx,zynqmp-ipi-mailbox". + * + * Return: 0 for success, negative value for failure + */ +static int zynqmp_ipi_setup(struct zynqmp_ipi_mbox *ipi_mbox, + struct device_node *node) +{ + struct zynqmp_ipi_mchan *mchan; + struct device *mdev; + struct resource res; + const char *name; + int ret; + + mdev = &ipi_mbox->dev; + mchan = &ipi_mbox->mchans[IPI_MB_CHNL_TX]; name = "local_request_region"; ret = zynqmp_ipi_mbox_get_buf_res(node, name, &res); @@ -563,37 +633,7 @@ static int zynqmp_ipi_mbox_probe(struct zynqmp_ipi_mbox *ipi_mbox, if (!mchan->rx_buf) return -ENOMEM; - /* Get the IPI remote agent ID */ - ret = of_property_read_u32(node, "xlnx,ipi-id", &ipi_mbox->remote_id); - if (ret < 0) { - dev_err(dev, "No IPI remote ID is specified.\n"); - return ret; - } - - mbox = &ipi_mbox->mbox; - mbox->dev = mdev; - mbox->ops = &zynqmp_ipi_chan_ops; - mbox->num_chans = 2; - mbox->txdone_irq = false; - mbox->txdone_poll = true; - mbox->txpoll_period = 5; - mbox->of_xlate = zynqmp_ipi_of_xlate; - chans = devm_kzalloc(mdev, 2 * sizeof(*chans), GFP_KERNEL); - if (!chans) - return -ENOMEM; - mbox->chans = chans; - chans[IPI_MB_CHNL_TX].con_priv = &ipi_mbox->mchans[IPI_MB_CHNL_TX]; - chans[IPI_MB_CHNL_RX].con_priv = &ipi_mbox->mchans[IPI_MB_CHNL_RX]; - ipi_mbox->mchans[IPI_MB_CHNL_TX].chan_type = IPI_MB_CHNL_TX; - ipi_mbox->mchans[IPI_MB_CHNL_RX].chan_type = IPI_MB_CHNL_RX; - ret = devm_mbox_controller_register(mdev, mbox); - if (ret) - dev_err(mdev, - "Failed to register mbox_controller(%d)\n", ret); - else - dev_info(mdev, - "Registered ZynqMP IPI mbox with TX/RX channels.\n"); - return ret; + return 0; } /** @@ -624,6 +664,7 @@ static int zynqmp_ipi_probe(struct platform_device *pdev) struct zynqmp_ipi_pdata *pdata; struct zynqmp_ipi_mbox *mbox; int num_mboxes, ret = -EINVAL; + setup_ipi_fn ipi_fn; num_mboxes = of_get_available_child_count(np); if (num_mboxes == 0) { @@ -644,9 +685,18 @@ static int zynqmp_ipi_probe(struct platform_device *pdev) return ret; } + ipi_fn = (setup_ipi_fn)device_get_match_data(&pdev->dev); + if (!ipi_fn) { + dev_err(dev, + "Mbox Compatible String is missing IPI Setup fn.\n"); + return -ENODEV; + } + pdata->num_mboxes = num_mboxes; mbox = pdata->ipi_mboxes; + mbox->setup_ipi_fn = ipi_fn; + for_each_available_child_of_node(np, nc) { mbox->pdata = pdata; ret = zynqmp_ipi_mbox_probe(mbox, nc); @@ -690,7 +740,9 @@ static void zynqmp_ipi_remove(struct platform_device *pdev) } static const struct of_device_id zynqmp_ipi_of_match[] = { - { .compatible = "xlnx,zynqmp-ipi-mailbox" }, + { .compatible = "xlnx,zynqmp-ipi-mailbox", + .data = &zynqmp_ipi_setup, + }, {}, }; MODULE_DEVICE_TABLE(of, zynqmp_ipi_of_match); -- cgit v1.2.3-59-g8ed1b From 0ac39d85a7415cb2e68a8d239f3d2f67175a14fe Mon Sep 17 00:00:00 2001 From: Ben Levinsky Date: Wed, 10 Apr 2024 10:08:25 -0700 Subject: mailbox: zynqmp: Enable Bufferless IPI usage on Versal-based SOC's On Xilinx-AMD Versal and Versal-NET, there exist both inter-processor-interrupts with corresponding message buffers and without such buffers. Add a routine that, if the corresponding DT compatible string "xlnx,versal-ipi-mailbox" is used then a Versal-based SOC can use a mailbox Device Tree entry where both host and remote can use either of the buffered or bufferless interrupts. Signed-off-by: Ben Levinsky Signed-off-by: Jassi Brar --- drivers/mailbox/zynqmp-ipi-mailbox.c | 129 +++++++++++++++++++++++++++++++++-- 1 file changed, 122 insertions(+), 7 deletions(-) diff --git a/drivers/mailbox/zynqmp-ipi-mailbox.c b/drivers/mailbox/zynqmp-ipi-mailbox.c index 56ba7135db54..1cb553cced90 100644 --- a/drivers/mailbox/zynqmp-ipi-mailbox.c +++ b/drivers/mailbox/zynqmp-ipi-mailbox.c @@ -52,6 +52,13 @@ #define IPI_MB_CHNL_TX 0 /* IPI mailbox TX channel */ #define IPI_MB_CHNL_RX 1 /* IPI mailbox RX channel */ +/* IPI Message Buffer Information */ +#define RESP_OFFSET 0x20U +#define DEST_OFFSET 0x40U +#define IPI_BUF_SIZE 0x20U +#define DST_BIT_POS 9U +#define SRC_BITMASK GENMASK(11, 8) + /** * struct zynqmp_ipi_mchan - Description of a Xilinx ZynqMP IPI mailbox channel * @is_opened: indicate if the IPI channel is opened @@ -169,9 +176,11 @@ static irqreturn_t zynqmp_ipi_interrupt(int irq, void *data) if (ret > 0 && ret & IPI_MB_STATUS_RECV_PENDING) { if (mchan->is_opened) { msg = mchan->rx_buf; - msg->len = mchan->req_buf_size; - memcpy_fromio(msg->data, mchan->req_buf, - msg->len); + if (msg) { + msg->len = mchan->req_buf_size; + memcpy_fromio(msg->data, mchan->req_buf, + msg->len); + } mbox_chan_received_data(chan, (void *)msg); status = IRQ_HANDLED; } @@ -281,26 +290,26 @@ static int zynqmp_ipi_send_data(struct mbox_chan *chan, void *data) if (mchan->chan_type == IPI_MB_CHNL_TX) { /* Send request message */ - if (msg && msg->len > mchan->req_buf_size) { + if (msg && msg->len > mchan->req_buf_size && mchan->req_buf) { dev_err(dev, "channel %d message length %u > max %lu\n", mchan->chan_type, (unsigned int)msg->len, mchan->req_buf_size); return -EINVAL; } - if (msg && msg->len) + if (msg && msg->len && mchan->req_buf) memcpy_toio(mchan->req_buf, msg->data, msg->len); /* Kick IPI mailbox to send message */ arg0 = SMC_IPI_MAILBOX_NOTIFY; zynqmp_ipi_fw_call(ipi_mbox, arg0, 0, &res); } else { /* Send response message */ - if (msg && msg->len > mchan->resp_buf_size) { + if (msg && msg->len > mchan->resp_buf_size && mchan->resp_buf) { dev_err(dev, "channel %d message length %u > max %lu\n", mchan->chan_type, (unsigned int)msg->len, mchan->resp_buf_size); return -EINVAL; } - if (msg && msg->len) + if (msg && msg->len && mchan->resp_buf) memcpy_toio(mchan->resp_buf, msg->data, msg->len); arg0 = SMC_IPI_MAILBOX_ACK; zynqmp_ipi_fw_call(ipi_mbox, arg0, IPI_SMC_ACK_EIRQ_MASK, @@ -636,6 +645,109 @@ static int zynqmp_ipi_setup(struct zynqmp_ipi_mbox *ipi_mbox, return 0; } +/** + * versal_ipi_setup - Set up IPIs to support mixed usage of + * Buffered and Bufferless IPIs. + * + * @ipi_mbox: pointer to IPI mailbox private data structure + * @node: IPI mailbox device node + * + * Return: 0 for success, negative value for failure + */ +static int versal_ipi_setup(struct zynqmp_ipi_mbox *ipi_mbox, + struct device_node *node) +{ + struct zynqmp_ipi_mchan *tx_mchan, *rx_mchan; + struct resource host_res, remote_res; + struct device_node *parent_node; + int host_idx, remote_idx; + struct device *mdev; + + tx_mchan = &ipi_mbox->mchans[IPI_MB_CHNL_TX]; + rx_mchan = &ipi_mbox->mchans[IPI_MB_CHNL_RX]; + parent_node = of_get_parent(node); + mdev = &ipi_mbox->dev; + + host_idx = zynqmp_ipi_mbox_get_buf_res(parent_node, "msg", &host_res); + remote_idx = zynqmp_ipi_mbox_get_buf_res(node, "msg", &remote_res); + + /* + * Only set up buffers if both sides claim to have msg buffers. + * This is because each buffered IPI's corresponding msg buffers + * are reserved for use by other buffered IPI's. + */ + if (!host_idx && !remote_idx) { + u32 host_src, host_dst, remote_src, remote_dst; + u32 buff_sz; + + buff_sz = resource_size(&host_res); + + host_src = host_res.start & SRC_BITMASK; + remote_src = remote_res.start & SRC_BITMASK; + + host_dst = (host_src >> DST_BIT_POS) * DEST_OFFSET; + remote_dst = (remote_src >> DST_BIT_POS) * DEST_OFFSET; + + /* Validate that IPI IDs is within IPI Message buffer space. */ + if (host_dst >= buff_sz || remote_dst >= buff_sz) { + dev_err(mdev, + "Invalid IPI Message buffer values: %x %x\n", + host_dst, remote_dst); + return -EINVAL; + } + + tx_mchan->req_buf = devm_ioremap(mdev, + host_res.start | remote_dst, + IPI_BUF_SIZE); + if (!tx_mchan->req_buf) { + dev_err(mdev, "Unable to map IPI buffer I/O memory\n"); + return -ENOMEM; + } + + tx_mchan->resp_buf = devm_ioremap(mdev, + (remote_res.start | host_dst) + + RESP_OFFSET, IPI_BUF_SIZE); + if (!tx_mchan->resp_buf) { + dev_err(mdev, "Unable to map IPI buffer I/O memory\n"); + return -ENOMEM; + } + + rx_mchan->req_buf = devm_ioremap(mdev, + remote_res.start | host_dst, + IPI_BUF_SIZE); + if (!rx_mchan->req_buf) { + dev_err(mdev, "Unable to map IPI buffer I/O memory\n"); + return -ENOMEM; + } + + rx_mchan->resp_buf = devm_ioremap(mdev, + (host_res.start | remote_dst) + + RESP_OFFSET, IPI_BUF_SIZE); + if (!rx_mchan->resp_buf) { + dev_err(mdev, "Unable to map IPI buffer I/O memory\n"); + return -ENOMEM; + } + + tx_mchan->resp_buf_size = IPI_BUF_SIZE; + tx_mchan->req_buf_size = IPI_BUF_SIZE; + tx_mchan->rx_buf = devm_kzalloc(mdev, IPI_BUF_SIZE + + sizeof(struct zynqmp_ipi_message), + GFP_KERNEL); + if (!tx_mchan->rx_buf) + return -ENOMEM; + + rx_mchan->resp_buf_size = IPI_BUF_SIZE; + rx_mchan->req_buf_size = IPI_BUF_SIZE; + rx_mchan->rx_buf = devm_kzalloc(mdev, IPI_BUF_SIZE + + sizeof(struct zynqmp_ipi_message), + GFP_KERNEL); + if (!rx_mchan->rx_buf) + return -ENOMEM; + } + + return 0; +} + /** * zynqmp_ipi_free_mboxes - Free IPI mailboxes devices * @@ -743,6 +855,9 @@ static const struct of_device_id zynqmp_ipi_of_match[] = { { .compatible = "xlnx,zynqmp-ipi-mailbox", .data = &zynqmp_ipi_setup, }, + { .compatible = "xlnx,versal-ipi-mailbox", + .data = &versal_ipi_setup, + }, {}, }; MODULE_DEVICE_TABLE(of, zynqmp_ipi_of_match); -- cgit v1.2.3-59-g8ed1b From a3af34284f6dea582f2a6d6dbf08b7c9eb9fc9b7 Mon Sep 17 00:00:00 2001 From: Zev Weiss Date: Mon, 20 Nov 2023 04:19:56 -0800 Subject: dt-bindings: arm: aspeed: document ASRock SPC621D8HM3 Document ASRock SPC621D8HM3 board compatible. Signed-off-by: Zev Weiss Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231120121954.19926-5-zev@bewilderbeest.net Signed-off-by: Joel Stanley Signed-off-by: Andrew Jeffery --- Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml b/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml index 749ee54a3ff8..f8f66821cb5f 100644 --- a/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml +++ b/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml @@ -36,6 +36,7 @@ properties: - aspeed,ast2500-evb - asrock,e3c246d4i-bmc - asrock,romed8hm3-bmc + - asrock,spc621d8hm3-bmc - bytedance,g220a-bmc - facebook,cmm-bmc - facebook,minipack-bmc -- cgit v1.2.3-59-g8ed1b From dc4a65fdfe635da9d6a76032aa1f729c6a3c0edd Mon Sep 17 00:00:00 2001 From: Zev Weiss Date: Mon, 20 Nov 2023 04:19:57 -0800 Subject: ARM: dts: aspeed: Add ASRock SPC621D8HM3 BMC This is a Xeon board broadly similar (aside from CPU vendor) to the already-support romed8hm3 (half-width, single-socket, ast2500). It doesn't require anything terribly special for OpenBMC support, so this device-tree should provide everything necessary for basic functionality with it. Signed-off-by: Zev Weiss Link: https://lore.kernel.org/r/20231120121954.19926-6-zev@bewilderbeest.net Signed-off-by: Joel Stanley Signed-off-by: Andrew Jeffery --- arch/arm/boot/dts/aspeed/Makefile | 1 + .../dts/aspeed/aspeed-bmc-asrock-spc621d8hm3.dts | 324 +++++++++++++++++++++ 2 files changed, 325 insertions(+) create mode 100644 arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-spc621d8hm3.dts diff --git a/arch/arm/boot/dts/aspeed/Makefile b/arch/arm/boot/dts/aspeed/Makefile index d3ac20e316d0..2df0a2e88df7 100644 --- a/arch/arm/boot/dts/aspeed/Makefile +++ b/arch/arm/boot/dts/aspeed/Makefile @@ -10,6 +10,7 @@ dtb-$(CONFIG_ARCH_ASPEED) += \ aspeed-bmc-arm-stardragon4800-rep2.dtb \ aspeed-bmc-asrock-e3c246d4i.dtb \ aspeed-bmc-asrock-romed8hm3.dtb \ + aspeed-bmc-asrock-spc621d8hm3.dtb \ aspeed-bmc-bytedance-g220a.dtb \ aspeed-bmc-delta-ahe50dc.dtb \ aspeed-bmc-facebook-bletchley.dtb \ diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-spc621d8hm3.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-spc621d8hm3.dts new file mode 100644 index 000000000000..555485871e7a --- /dev/null +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-spc621d8hm3.dts @@ -0,0 +1,324 @@ +// SPDX-License-Identifier: GPL-2.0+ +/dts-v1/; + +#include "aspeed-g5.dtsi" +#include +#include +#include +#include + +/{ + model = "ASRock SPC621D8HM3 BMC"; + compatible = "asrock,spc621d8hm3-bmc", "aspeed,ast2500"; + + aliases { + serial4 = &uart5; + + i2c20 = &i2c1mux0ch0; + i2c21 = &i2c1mux0ch1; + }; + + chosen { + stdout-path = &uart5; + }; + + memory@80000000 { + reg = <0x80000000 0x20000000>; + }; + + leds { + compatible = "gpio-leds"; + + /* BMC heartbeat */ + led-0 { + gpios = <&gpio ASPEED_GPIO(H, 6) GPIO_ACTIVE_LOW>; + function = LED_FUNCTION_HEARTBEAT; + color = ; + linux,default-trigger = "timer"; + }; + + /* system fault */ + led-1 { + gpios = <&gpio ASPEED_GPIO(Z, 2) GPIO_ACTIVE_LOW>; + function = LED_FUNCTION_FAULT; + color = ; + panic-indicator; + }; + }; + + iio-hwmon { + compatible = "iio-hwmon"; + io-channels = <&adc 0>, <&adc 1>, <&adc 2>, <&adc 3>, + <&adc 4>, <&adc 5>, <&adc 6>, <&adc 7>, + <&adc 8>, <&adc 9>, <&adc 10>, <&adc 11>, + <&adc 12>, <&adc 13>, <&adc 14>, <&adc 15>; + }; +}; + +&fmc { + status = "okay"; + flash@0 { + status = "okay"; + m25p,fast-read; + label = "bmc"; + spi-max-frequency = <50000000>; /* 50 MHz */ +#include "openbmc-flash-layout-64.dtsi" + }; +}; + +&uart5 { + status = "okay"; +}; + +&vuart { + status = "okay"; + aspeed,lpc-io-reg = <0x2f8>; + aspeed,lpc-interrupts = <3 IRQ_TYPE_LEVEL_HIGH>; +}; + +&mac0 { + status = "okay"; + + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_rgmii1_default &pinctrl_mdio1_default>; + + nvmem-cells = <ð0_macaddress>; + nvmem-cell-names = "mac-address"; +}; + +&i2c0 { + status = "okay"; +}; + +&i2c1 { + status = "okay"; + + /* hardware monitor/thermal sensor */ + temperature-sensor@29 { + compatible = "nuvoton,nct7802"; + reg = <0x29>; + }; + + /* motherboard temp sensor (TMP1, near BMC) */ + temperature-sensor@4c { + compatible = "nuvoton,w83773g"; + reg = <0x4c>; + }; + + /* motherboard FRU eeprom */ + eeprom@50 { + compatible = "st,24c128", "atmel,24c128"; + reg = <0x50>; + pagesize = <16>; + #address-cells = <1>; + #size-cells = <1>; + + eth0_macaddress: macaddress@3f80 { + reg = <0x3f80 6>; + }; + }; + + /* M.2 slot smbus mux */ + i2c-mux@71 { + compatible = "nxp,pca9545"; + reg = <0x71>; + #address-cells = <1>; + #size-cells = <0>; + + i2c1mux0ch0: i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + }; + + i2c1mux0ch1: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + }; + }; +}; + +&i2c2 { + status = "okay"; +}; + +&i2c3 { + status = "okay"; +}; + +&i2c4 { + status = "okay"; +}; + +&i2c5 { + status = "okay"; +}; + +&i2c6 { + status = "okay"; +}; + +&i2c7 { + status = "okay"; +}; + +&i2c8 { + status = "okay"; +}; + +&i2c9 { + status = "okay"; +}; + +&i2c10 { + status = "okay"; +}; + +&i2c11 { + status = "okay"; +}; + +&i2c12 { + status = "okay"; +}; + +&i2c13 { + status = "okay"; +}; + +&video { + status = "okay"; +}; + +&vhub { + status = "okay"; +}; + +&lpc_ctrl { + status = "okay"; +}; + +&lpc_snoop { + status = "okay"; + snoop-ports = <0x80>; +}; + +&kcs3 { + status = "okay"; + aspeed,lpc-io-reg = <0xca2>; +}; + +&peci0 { + status = "okay"; +}; + +&pwm_tacho { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pwm0_default + &pinctrl_pwm2_default + &pinctrl_pwm3_default + &pinctrl_pwm4_default>; + + fan@0 { + reg = <0x00>; + aspeed,fan-tach-ch = /bits/ 8 <0x00>; + }; + + fan@2 { + reg = <0x02>; + aspeed,fan-tach-ch = /bits/ 8 <0x02>; + }; + + fan@3 { + reg = <0x03>; + aspeed,fan-tach-ch = /bits/ 8 <0x03>; + }; + + fan@4 { + reg = <0x04>; + aspeed,fan-tach-ch = /bits/ 8 <0x04>; + }; +}; + +&gpio { + status = "okay"; + gpio-line-names = + /* A */ "LOCATORLED_STATUS_N", "LOCATORBTN_N", + "BMC_READY_N", "FM_SPD_DDRCPU_LVLSHFT_EN", + "", "", "", "", + /* B */ "NODE_ID_1", "NODE_ID_2", "PSU_FAN_FAIL_N", "", + "", "", "", "GPIO_RST", + /* C */ "", "", "", "", "", "", "", "", + /* D */ "FP_PWR_BTN_MUX_N", "FM_BMC_PWRBTN_OUT_N", + "FP_RST_BTN_N", "RST_BMC_RSTBTN_OUT_N", + "NMI_BTN_N", "BMC_NMI", + "", "", + /* E */ "", "", "", "FM_ME_RCVR_N", "", "", "", "", + /* F */ "BMC_SMB_SEL_N", "FM_CPU2_DISABLE_COD_N", + "FM_REMOTE_DEBUG_BMC_EN", "FM_CPU_ERR0_LVT3_EN", + "FM_CPU_ERR1_LVT3_EN", "FM_CPU_ERR2_LVT3_EN", + "FM_MEM_THERM_EVENT_CPU1_LVT3_N", "FM_MEM_THERM_EVENT_CPU2_LVT3_N", + /* G */ "HWM_BAT_EN", "", "BMC_PHYRST_N", "FM_BIOS_SPI_BMC_CTRL", + "BMC_ALERT1_N", "BMC_ALERT2_N", "BMC_ALERT3_N", "IRQ_SML0_ALERT_N", + /* H */ "BMC_SMB_PRESENT_1_N", "FM_PCH_CORE_VID_0", "FM_PCH_CORE_VID_1", "", + "FM_MFG_MODE", "BMC_RTCRST", "BMC_HB_LED_N", "BMC_CASEOPEN", + /* I */ "IRQ_PVDDQ_ABCD_CPU1_VRHOT_LVC3_N", "IRQ_PVDDQ_ABCD_CPU2_VRHOT_LVC3_N", + "IRQ_PVDDQ_EFGH_CPU1_VRHOT_LVC3_N", "IRQ_PVDDQ_EFGH_CPU2_VRHOT_LVC3_N", + "", "", "", "", + /* J */ "", "", "", "", "", "", "", "", + /* K */ "", "", "", "", "", "", "", "", + /* L */ "", "", "", "", "", "", "", "", + /* M */ "FM_PVCCIN_CPU1_PWR_IN_ALERT_N", "FM_PVCCIN_CPU2_PWR_IN_ALERT_N", + "IRQ_PVCCIN_CPU1_VRHOT_LVC3_N", "IRQ_PVCCIN_CPU2_VRHOT_LVC3_N", + "FM_CPU1_PROCHOT_BMC_LVC3_N", "", + "FM_CPU1_MEMHOT_OUT_N", "FM_CPU2_MEMHOT_OUT_N", + /* N */ "", "", "", "", "", "", "", "", + /* O */ "", "", "", "", "", "", "", "", + /* P */ "", "", "", "", "", "", "", "", + /* Q */ "", "", "", "", "", "", "RST_GLB_RST_WARN_N", "PCIE_WAKE_N", + /* R */ "", "", "FM_BMC_SUSACK_N", "FM_BMC_EUP_LOT6_N", + "", "FM_BMC_PCH_SCI_LPC_N", "", "", + /* S */ "FM_DBP_PRESENT_N", "FM_CPU2_SKTOCC_LCT3_N", + "FM_CPU1_FIVR_FAULT_LVT3", "FM_CPU2_FIVR_FAULT_LVT3", + "", "", "", "", + /* T */ "", "", "", "", "", "", "", "", + /* U */ "", "", "", "", "", "", "", "", + /* V */ "", "", "", "", "", "", "", "", + /* W */ "", "", "", "", "", "", "", "", + /* X */ "", "", "", "", "", "", "", "", + /* Y */ "FM_SLPS3_N", "FM_SLPS4_N", "", "FM_BMC_ONCTL_N_PLD", + "", "", "", "", + /* Z */ "FM_CPU_MSMI_CATERR_LVT3_N", "", "SYSTEM_FAULT_LED_N", "BMC_THROTTLE_N", + "", "", "", "", + /* AA */ "FM_CPU1_THERMTRIP_LATCH_LVT3_N", "FM_CPU2_THERMTRIP_LATCH_LVT3_N", + "FM_BIOS_POST_COMPLT_N", "DBP_BMC_SYSPWROK", + "", "IRQ_SML0_ALERT_MUX_N", + "IRQ_SMI_ACTIVE_N", "IRQ_NMI_EVENT_N", + /* AB */ "FM_PCH_BMC_THERMTRIP_N", "PWRGD_SYS_PWROK", + "ME_OVERRIDE", "IRQ_BMC_PCH_SMI_LPC_N", + "", "", "", "", + /* AC */ "", "", "", "", "", "", "", ""; +}; + +&adc { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_adc0_default /* 3VSB */ + &pinctrl_adc1_default /* 5VSB */ + &pinctrl_adc2_default /* CPU1 */ + &pinctrl_adc3_default /* NC */ + &pinctrl_adc4_default /* VCCMABCD */ + &pinctrl_adc5_default /* VCCMEFGH */ + &pinctrl_adc6_default /* NC */ + &pinctrl_adc7_default /* NC */ + &pinctrl_adc8_default /* PVNN_PCH */ + &pinctrl_adc9_default /* 1P05PCH */ + &pinctrl_adc10_default /* 1P8PCH */ + &pinctrl_adc11_default /* BAT */ + &pinctrl_adc12_default /* 3V */ + &pinctrl_adc13_default /* 5V */ + &pinctrl_adc14_default /* 12V */ + &pinctrl_adc15_default>; /* GND */ +}; -- cgit v1.2.3-59-g8ed1b From 59f78076807652902bcae8e7926f7467e0a09f3e Mon Sep 17 00:00:00 2001 From: Renze Nicolai Date: Sat, 2 Dec 2023 01:38:44 +0100 Subject: dt-bindings: arm: aspeed: add Asrock X570D4U board Document Asrock X570D4U compatible. Signed-off-by: Renze Nicolai Acked-by: Krzysztof Kozlowski Reviewed-by: Joel Stanley Link: https://lore.kernel.org/r/20231202003908.3635695-2-renze@rnplus.nl Signed-off-by: Joel Stanley Signed-off-by: Andrew Jeffery --- Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml b/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml index f8f66821cb5f..35d078d03df6 100644 --- a/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml +++ b/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml @@ -37,6 +37,7 @@ properties: - asrock,e3c246d4i-bmc - asrock,romed8hm3-bmc - asrock,spc621d8hm3-bmc + - asrock,x570d4u-bmc - bytedance,g220a-bmc - facebook,cmm-bmc - facebook,minipack-bmc -- cgit v1.2.3-59-g8ed1b From f373cffbdc46f287dd01bb7c4cfbf0b8c9a52d4e Mon Sep 17 00:00:00 2001 From: Renze Nicolai Date: Sat, 2 Dec 2023 01:38:45 +0100 Subject: ARM: dts: aspeed: asrock: Add ASRock X570D4U BMC This is a relatively low-cost AST2500-based Amd Ryzen 5000 Series micro-ATX board that we hope can provide a decent platform for OpenBMC development. This initial device-tree provides the necessary configuration for basic BMC functionality such as serial console, KVM support and POST code snooping. Signed-off-by: Renze Nicolai Reviewed-by: Joel Stanley Link: https://lore.kernel.org/r/20231202003908.3635695-3-renze@rnplus.nl Signed-off-by: Joel Stanley Signed-off-by: Andrew Jeffery --- arch/arm/boot/dts/aspeed/Makefile | 1 + .../boot/dts/aspeed/aspeed-bmc-asrock-x570d4u.dts | 377 +++++++++++++++++++++ 2 files changed, 378 insertions(+) create mode 100644 arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-x570d4u.dts diff --git a/arch/arm/boot/dts/aspeed/Makefile b/arch/arm/boot/dts/aspeed/Makefile index 2df0a2e88df7..d47bb3129881 100644 --- a/arch/arm/boot/dts/aspeed/Makefile +++ b/arch/arm/boot/dts/aspeed/Makefile @@ -11,6 +11,7 @@ dtb-$(CONFIG_ARCH_ASPEED) += \ aspeed-bmc-asrock-e3c246d4i.dtb \ aspeed-bmc-asrock-romed8hm3.dtb \ aspeed-bmc-asrock-spc621d8hm3.dtb \ + aspeed-bmc-asrock-x570d4u.dtb \ aspeed-bmc-bytedance-g220a.dtb \ aspeed-bmc-delta-ahe50dc.dtb \ aspeed-bmc-facebook-bletchley.dtb \ diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-x570d4u.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-x570d4u.dts new file mode 100644 index 000000000000..3c975bc41ae7 --- /dev/null +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-x570d4u.dts @@ -0,0 +1,377 @@ +// SPDX-License-Identifier: GPL-2.0+ +/dts-v1/; +#include "aspeed-g5.dtsi" +#include +#include + +/ { + model = "Asrock Rack X570D4U BMC"; + compatible = "asrock,x570d4u-bmc", "aspeed,ast2500"; + + aliases { + i2c40 = &i2c4mux0ch0; + i2c41 = &i2c4mux0ch1; + i2c42 = &i2c4mux0ch2; + i2c43 = &i2c4mux0ch3; + }; + + chosen { + stdout-path = &uart5; + }; + + memory@80000000 { + reg = <0x80000000 0x20000000>; + }; + + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + pci_memory: region@9a000000 { + no-map; + reg = <0x9a000000 0x00010000>; /* 64K */ + }; + + video_engine_memory: jpegbuffer { + size = <0x02800000>; /* 40M */ + alignment = <0x01000000>; + compatible = "shared-dma-pool"; + reusable; + }; + + gfx_memory: framebuffer { + size = <0x01000000>; + alignment = <0x01000000>; + compatible = "shared-dma-pool"; + reusable; + }; + }; + + leds { + compatible = "gpio-leds"; + + led-0 { + /* led-heartbeat-n */ + gpios = <&gpio ASPEED_GPIO(H, 6) GPIO_ACTIVE_LOW>; + color = ; + function = LED_FUNCTION_HEARTBEAT; + linux,default-trigger = "timer"; + }; + + led-1 { + /* led-fault-n */ + gpios = <&gpio ASPEED_GPIO(Z, 2) GPIO_ACTIVE_LOW>; + color = ; + function = LED_FUNCTION_FAULT; + panic-indicator; + }; + }; + + iio-hwmon { + compatible = "iio-hwmon"; + io-channels = <&adc 0>, <&adc 1>, <&adc 2>, <&adc 3>, <&adc 4>, + <&adc 5>, <&adc 6>, <&adc 7>, <&adc 8>, <&adc 9>, + <&adc 10>, <&adc 11>, <&adc 12>; + }; +}; + +&gpio { + status = "okay"; + gpio-line-names = + /*A0-A3*/ "status-locatorled-n", "", "button-nmi-n", "", + /*A4-A7*/ "", "", "", "", + /*B0-B3*/ "input-bios-post-cmplt-n", "", "", "", + /*B4-B7*/ "", "", "", "", + /*C0-C3*/ "", "", "", "", + /*C4-C7*/ "", "", "control-locatorbutton", "", + /*D0-D3*/ "button-power", "control-power", "button-reset", "control-reset", + /*D4-D7*/ "", "", "", "", + /*E0-E3*/ "", "", "", "", + /*E4-E7*/ "", "", "", "", + /*F0-F3*/ "", "", "", "", + /*F4-F7*/ "", "", "", "", + /*G0-G3*/ "output-rtc-battery-voltage-read-enable", "input-id0", "input-id1", "input-id2", + /*G4-G7*/ "input-alert1-n", "input-alert2-n", "input-alert3-n", "", + /*H0-H3*/ "", "", "", "", + /*H4-H7*/ "input-mfg", "", "led-heartbeat-n", "input-caseopen", + /*I0-I3*/ "", "", "", "", + /*I4-I7*/ "", "", "", "", + /*J0-J3*/ "output-bmc-ready", "", "", "", + /*J4-J7*/ "", "", "", "", + /*K0-K3*/ "", "", "", "", + /*K4-K7*/ "", "", "", "", + /*L0-L3*/ "", "", "", "", + /*L4-L7*/ "", "", "", "", + /*M0-M3*/ "", "", "", "", + /*M4-M7*/ "", "", "", "", + /*N0-N3*/ "", "", "", "", + /*N4-N7*/ "", "", "", "", + /*O0-O3*/ "", "", "", "", + /*O4-O7*/ "", "", "", "", + /*P0-P3*/ "", "", "", "", + /*P4-P7*/ "", "", "", "", + /*Q0-Q3*/ "", "", "", "", + /*Q4-Q7*/ "", "", "", "", + /*R0-R3*/ "", "", "", "", + /*R4-R7*/ "", "", "", "", + /*S0-S3*/ "input-bmc-pchhot-n", "", "", "", + /*S4-S7*/ "", "", "", "", + /*T0-T3*/ "", "", "", "", + /*T4-T7*/ "", "", "", "", + /*U0-U3*/ "", "", "", "", + /*U4-U7*/ "", "", "", "", + /*V0-V3*/ "", "", "", "", + /*V4-V7*/ "", "", "", "", + /*W0-W3*/ "", "", "", "", + /*W4-W7*/ "", "", "", "", + /*X0-X3*/ "", "", "", "", + /*X4-X7*/ "", "", "", "", + /*Y0-Y3*/ "", "", "", "", + /*Y4-Y7*/ "", "", "", "", + /*Z0-Z3*/ "", "", "led-fault-n", "output-bmc-throttle-n", + /*Z4-Z7*/ "", "", "", "", + /*AA0-AA3*/ "input-cpu1-thermtrip-latch-n", "", "input-cpu1-prochot-n", "", + /*AA4-AC7*/ "", "", "", "", + /*AB0-AB3*/ "", "", "", "", + /*AB4-AC7*/ "", "", "", "", + /*AC0-AC3*/ "", "", "", "", + /*AC4-AC7*/ "", "", "", ""; +}; + +&fmc { + status = "okay"; + flash@0 { + status = "okay"; + label = "bmc"; + m25p,fast-read; + spi-max-frequency = <10000000>; +#include "openbmc-flash-layout-64.dtsi" + }; +}; + +&uart5 { + status = "okay"; +}; + +&vuart { + status = "okay"; +}; + +&mac0 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_rgmii1_default &pinctrl_mdio1_default>; + + nvmem-cells = <ð0_macaddress>; + nvmem-cell-names = "mac-address"; +}; + +&mac1 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_rmii2_default &pinctrl_mdio2_default>; + use-ncsi; + + nvmem-cells = <ð1_macaddress>; + nvmem-cell-names = "mac-address"; +}; + +&i2c0 { + /* SMBus on auxiliary panel header (AUX_PANEL1) */ + status = "okay"; +}; + +&i2c1 { + status = "okay"; + + w83773g@4c { + compatible = "nuvoton,w83773g"; + reg = <0x4c>; + }; +}; + +&i2c2 { + /* PSU SMBus (PSU_SMB1) */ + status = "okay"; +}; + +&i2c3 { + status = "okay"; +}; + +&i2c4 { + status = "okay"; + + i2c-mux@70 { + compatible = "nxp,pca9545"; + reg = <0x70>; + #address-cells = <1>; + #size-cells = <0>; + + i2c4mux0ch0: i2c@0 { + /* SMBus on PCI express 16x slot */ + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + }; + + i2c4mux0ch1: i2c@1 { + /* SMBus on PCI express 8x slot */ + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + }; + + i2c4mux0ch2: i2c@2 { + /* Unknown */ + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + }; + + i2c4mux0ch3: i2c@3 { + /* SMBus on PCI express 1x slot */ + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + }; + }; +}; + +&i2c5 { + status = "okay"; +}; + +&i2c7 { + /* FRU and SPD EEPROM SMBus */ + status = "okay"; + + eeprom@57 { + compatible = "st,24c128", "atmel,24c128"; + reg = <0x57>; + pagesize = <16>; + #address-cells = <1>; + #size-cells = <1>; + + eth0_macaddress: macaddress@3f80 { + reg = <0x3f80 6>; + }; + + eth1_macaddress: macaddress@3f88 { + reg = <0x3f88 6>; + }; + }; +}; + +&gfx { + status = "okay"; +}; + +&pinctrl { + aspeed,external-nodes = <&gfx &lhc>; +}; + +&vhub { + status = "okay"; +}; + +&ehci1 { + status = "okay"; +}; + +&uhci { + status = "okay"; +}; + +&kcs3 { + aspeed,lpc-io-reg = <0xca2>; + status = "okay"; +}; + +&lpc_ctrl { + status = "okay"; +}; + +&lpc_snoop { + status = "okay"; + snoop-ports = <0x80>; +}; + +&p2a { + status = "okay"; + memory-region = <&pci_memory>; +}; + +&video { + status = "okay"; + memory-region = <&video_engine_memory>; +}; + +&pwm_tacho { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pwm0_default + &pinctrl_pwm1_default + &pinctrl_pwm2_default + &pinctrl_pwm3_default + &pinctrl_pwm4_default + &pinctrl_pwm5_default>; + + fan@0 { + /* FAN1 (4-pin) */ + reg = <0x00>; + aspeed,fan-tach-ch = /bits/ 8 <0x00>; + }; + + fan@1 { + /* FAN2 (4-pin) */ + reg = <0x01>; + aspeed,fan-tach-ch = /bits/ 8 <0x01>; + }; + + fan@2 { + /* FAN3 (4-pin) */ + reg = <0x02>; + aspeed,fan-tach-ch = /bits/ 8 <0x02>; + }; + + fan@3 { + /* FAN4 (6-pin) */ + reg = <0x03>; + aspeed,fan-tach-ch = /bits/ 8 <0x04 0x0b>; + }; + + fan@4 { + /* FAN6 (6-pin) */ + reg = <0x04>; + aspeed,fan-tach-ch = /bits/ 8 <0x06 0x0d>; + }; + + fan@5 { + /* FAN5 (6-pin) */ + reg = <0x05>; + aspeed,fan-tach-ch = /bits/ 8 <0x05 0x0c>; + }; +}; + +&adc { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_adc0_default + &pinctrl_adc1_default + &pinctrl_adc2_default + &pinctrl_adc3_default + &pinctrl_adc4_default + &pinctrl_adc5_default + &pinctrl_adc6_default + &pinctrl_adc7_default + &pinctrl_adc8_default + &pinctrl_adc9_default + &pinctrl_adc10_default + &pinctrl_adc11_default + &pinctrl_adc12_default + &pinctrl_adc13_default + &pinctrl_adc14_default + &pinctrl_adc15_default>; +}; -- cgit v1.2.3-59-g8ed1b From 1e25f2aed7aec527b28fe998603315fcf32a0dd4 Mon Sep 17 00:00:00 2001 From: Peter Yin Date: Tue, 12 Dec 2023 00:26:54 +0800 Subject: dt-bindings: arm: aspeed: add Meta Harma board Document the new compatibles used on Meta Harma. Acked-by: Krzysztof Kozlowski Signed-off-by: Peter Yin Link: https://lore.kernel.org/r/20231211162656.2564267-2-peteryin.openbmc@gmail.com Signed-off-by: Joel Stanley Signed-off-by: Andrew Jeffery --- Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml b/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml index 35d078d03df6..9b3cb6fa52c0 100644 --- a/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml +++ b/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml @@ -81,6 +81,7 @@ properties: - facebook,elbert-bmc - facebook,fuji-bmc - facebook,greatlakes-bmc + - facebook,harma-bmc - facebook,minerva-cmc - facebook,yosemite4-bmc - ibm,everest-bmc -- cgit v1.2.3-59-g8ed1b From bb3776e564d2190db0ef45609e66f13c60ce5b48 Mon Sep 17 00:00:00 2001 From: Peter Yin Date: Tue, 12 Dec 2023 00:26:55 +0800 Subject: ARM: dts: aspeed: Harma: Add Meta Harma (AST2600) BMC Add linux device tree entry related to the Meta(Facebook) computer-node system use an AT2600 BMC. This node is named "Harma". Signed-off-by: Peter Yin Reviewed-by: Joel Stanley Link: https://lore.kernel.org/r/20231211162656.2564267-3-peteryin.openbmc@gmail.com Signed-off-by: Joel Stanley Signed-off-by: Andrew Jeffery --- arch/arm/boot/dts/aspeed/Makefile | 1 + .../boot/dts/aspeed/aspeed-bmc-facebook-harma.dts | 585 +++++++++++++++++++++ 2 files changed, 586 insertions(+) create mode 100644 arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-harma.dts diff --git a/arch/arm/boot/dts/aspeed/Makefile b/arch/arm/boot/dts/aspeed/Makefile index d47bb3129881..7231d8fa1004 100644 --- a/arch/arm/boot/dts/aspeed/Makefile +++ b/arch/arm/boot/dts/aspeed/Makefile @@ -21,6 +21,7 @@ dtb-$(CONFIG_ARCH_ASPEED) += \ aspeed-bmc-facebook-fuji.dtb \ aspeed-bmc-facebook-galaxy100.dtb \ aspeed-bmc-facebook-greatlakes.dtb \ + aspeed-bmc-facebook-harma.dtb \ aspeed-bmc-facebook-minerva-cmc.dtb \ aspeed-bmc-facebook-minipack.dtb \ aspeed-bmc-facebook-tiogapass.dtb \ diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-harma.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-harma.dts new file mode 100644 index 000000000000..7db3f9eb0016 --- /dev/null +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-harma.dts @@ -0,0 +1,585 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright 2023 Facebook Inc. + +/dts-v1/; +#include "aspeed-g6.dtsi" +#include +#include + +/ { + model = "Facebook Harma"; + compatible = "facebook,harma-bmc", "aspeed,ast2600"; + + aliases { + serial0 = &uart1; + serial1 = &uart6; + serial2 = &uart2; + serial4 = &uart5; + + i2c20 = &imux20; + i2c21 = &imux21; + i2c22 = &imux22; + i2c23 = &imux23; + i2c24 = &imux24; + i2c25 = &imux25; + i2c26 = &imux26; + i2c27 = &imux27; + i2c28 = &imux28; + i2c29 = &imux29; + i2c30 = &imux30; + i2c31 = &imux31; + }; + + chosen { + stdout-path = &uart5; + }; + + memory@80000000 { + device_type = "memory"; + reg = <0x80000000 0x80000000>; + }; + + iio-hwmon { + compatible = "iio-hwmon"; + io-channels = <&adc0 0>, <&adc0 1>, <&adc0 2>, <&adc0 3>, + <&adc0 4>, <&adc0 5>, <&adc0 6>, <&adc0 7>, + <&adc1 2>; + }; + + leds { + compatible = "gpio-leds"; + + led-0 { + label = "bmc_heartbeat_amber"; + gpios = <&gpio0 ASPEED_GPIO(P, 7) GPIO_ACTIVE_LOW>; + linux,default-trigger = "heartbeat"; + }; + + led-1 { + label = "fp_id_amber"; + default-state = "off"; + gpios = <&gpio0 13 GPIO_ACTIVE_HIGH>; + }; + + led-2 { + label = "power_blue"; + default-state = "off"; + gpios = <&gpio0 124 GPIO_ACTIVE_HIGH>; + }; + }; +}; + +// HOST BIOS Debug +&uart1 { + status = "okay"; +}; + +// SOL Host Console +&uart2 { + status = "okay"; + pinctrl-0 = <>; +}; + +// SOL BMC Console +&uart4 { + status = "okay"; + pinctrl-0 = <>; +}; + +// BMC Debug Console +&uart5 { + status = "okay"; +}; + +// MTIA +&uart6 { + status = "okay"; +}; + +&uart_routing { + status = "okay"; +}; + +&vuart1 { + status = "okay"; +}; + +&wdt1 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_wdtrst1_default>; + aspeed,reset-type = "soc"; + aspeed,external-signal; + aspeed,ext-push-pull; + aspeed,ext-active-high; + aspeed,ext-pulse-duration = <256>; +}; + +&mac3 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_rmii4_default>; + use-ncsi; + mlx,multi-host; +}; + +&rtc { + status = "okay"; +}; + +&fmc { + status = "okay"; + + flash@0 { + status = "okay"; + m25p,fast-read; + label = "bmc"; + spi-max-frequency = <50000000>; +#include "openbmc-flash-layout-128.dtsi" + }; + + flash@1 { + status = "okay"; + m25p,fast-read; + label = "alt-bmc"; + spi-max-frequency = <50000000>; + }; +}; + +// BIOS Flash +&spi2 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_spi2_default>; + + flash@0 { + status = "okay"; + m25p,fast-read; + label = "pnor"; + spi-max-frequency = <12000000>; + spi-tx-bus-width = <2>; + spi-rx-bus-width = <2>; + }; +}; + +&kcs2 { + status = "okay"; + aspeed,lpc-io-reg = <0xca8>; +}; + +&kcs3 { + status = "okay"; + aspeed,lpc-io-reg = <0xca2>; +}; + +&i2c0 { + status = "okay"; + + max31790@30{ + compatible = "max31790"; + reg = <0x30>; + #address-cells = <1>; + #size-cells = <0>; + }; +}; + +&i2c1 { + status = "okay"; + + tmp75@4b { + compatible = "ti,tmp75"; + reg = <0x4b>; + }; +}; + +&i2c2 { + status = "okay"; + + max31790@30{ + compatible = "max31790"; + reg = <0x30>; + #address-cells = <1>; + #size-cells = <0>; + }; +}; + +&i2c3 { + status = "okay"; + + i2c-mux@70 { + compatible = "nxp,pca9543"; + reg = <0x70>; + #address-cells = <1>; + #size-cells = <0>; + + imux20: i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + //Retimer Flash + eeprom@50 { + compatible = "atmel,24c2048"; + reg = <0x50>; + pagesize = <128>; + }; + }; + imux21: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + }; + }; +}; + +&i2c4 { + status = "okay"; + // PDB FRU + eeprom@52 { + compatible = "atmel,24c64"; + reg = <0x52>; + }; + + delta_brick@69 { + compatible = "pmbus"; + reg = <0x69>; + }; +}; + +&i2c5 { + status = "okay"; +}; + +&i2c6 { + status = "okay"; + + i2c-mux@70 { + compatible = "nxp,pca9543"; + reg = <0x70>; + #address-cells = <1>; + #size-cells = <0>; + + imux22: i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + }; + imux23: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + }; + }; +}; + +&i2c7 { + status = "okay"; +}; + +&i2c8 { + status = "okay"; +}; + +&i2c9 { + status = "okay"; + + gpio@30 { + compatible = "nxp,pca9555"; + reg = <0x30>; + gpio-controller; + #gpio-cells = <2>; + }; + gpio@31 { + compatible = "nxp,pca9555"; + reg = <0x31>; + gpio-controller; + #gpio-cells = <2>; + }; + + i2c-mux@71 { + compatible = "nxp,pca9546"; + reg = <0x71>; + #address-cells = <1>; + #size-cells = <0>; + + imux24: i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + }; + imux25: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + }; + imux26: i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + }; + imux27: i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + }; + }; + // PTTV FRU + eeprom@52 { + compatible = "atmel,24c64"; + reg = <0x52>; + }; +}; + +&i2c11 { + status = "okay"; +}; + +&i2c12 { + status = "okay"; +}; + +&i2c13 { + status = "okay"; + + i2c-mux@70 { + compatible = "nxp,pca9545"; + reg = <0x70>; + #address-cells = <1>; + #size-cells = <0>; + + imux28: i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + }; + imux29: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + //MB FRU + eeprom@54 { + compatible = "atmel,24c64"; + reg = <0x54>; + }; + }; + imux30: i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + }; + imux31: i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + }; + }; +}; + +// To Debug card +&i2c14 { + status = "okay"; + multi-master; + + ipmb@10 { + compatible = "ipmb-dev"; + reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>; + i2c-protocol; + }; +}; + +&i2c15 { + status = "okay"; + + // SCM FRU + eeprom@50 { + compatible = "atmel,24c64"; + reg = <0x50>; + }; + + // BSM FRU + eeprom@56 { + compatible = "atmel,24c64"; + reg = <0x56>; + }; +}; + +&adc0 { + aspeed,int-vref-microvolt = <2500000>; + status = "okay"; + pinctrl-0 = <&pinctrl_adc0_default &pinctrl_adc1_default + &pinctrl_adc2_default &pinctrl_adc3_default + &pinctrl_adc4_default &pinctrl_adc5_default + &pinctrl_adc6_default &pinctrl_adc7_default>; +}; + +&adc1 { + aspeed,int-vref-microvolt = <2500000>; + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_adc10_default>; +}; + +&ehci0 { + status = "okay"; +}; + +&gpio0 { + pinctrl-names = "default"; + gpio-line-names = + /*A0-A7*/ "","","","","","","","", + /*B0-B7*/ "","","","", + "bmc-spi-mux-select-0","led-identify","","", + /*C0-C7*/ "","","","","","","","", + /*D0-D7*/ "","","sol-uart-select","","","","","", + /*E0-E7*/ "","","","","","","","", + /*F0-F7*/ "","","","","","","","", + /*G0-G7*/ "","","","","","","","", + /*H0-H7*/ "","","","","","","","", + /*I0-I7*/ "","","","","","","","", + /*J0-J7*/ "","","","","","","","", + /*K0-K7*/ "","","","","","","","", + /*L0-L7*/ "","","","","","","","", + /*M0-M7*/ "","","","","","","","", + /*N0-N7*/ "led-postcode-0","led-postcode-1", + "led-postcode-2","led-postcode-3", + "led-postcode-4","led-postcode-5", + "led-postcode-6","led-postcode-7", + /*O0-O7*/ "","","","","","","","", + /*P0-P7*/ "power-button","power-host-control", + "reset-button","","led-power","","","", + /*Q0-Q7*/ "","","","","","","","", + /*R0-R7*/ "","","","","","","","", + /*S0-S7*/ "","","","","","","","", + /*T0-T7*/ "","","","","","","","", + /*U0-U7*/ "","","","","","","led-identify-gate","", + /*V0-V7*/ "","","","", + "rtc-battery-voltage-read-enable","","","", + /*W0-W7*/ "","","","","","","","", + /*X0-X7*/ "","","","","","","","", + /*Y0-Y7*/ "","","","","","","","", + /*Z0-Z7*/ "","","","","","","",""; +}; + +&sgpiom0 { + status = "okay"; + max-ngpios = <128>; + ngpios = <128>; + bus-frequency = <2000000>; + gpio-line-names = + /*in - out - in - out */ + /*A0-A3 line 0-7*/ + "presence-scm-cable","power-config-disable-e1s-0", + "","", + "","power-config-disable-e1s-1", + "","", + /*A4-A7 line 8-15*/ + "","power-config-asic-module-enable", + "","power-config-asic-power-good", + "","power-config-pdb-power-good", + "presence-cpu","smi-control-n", + /*B0-B3 line 16-23*/ + "","nmi-control-n", + "","nmi-control-sync-flood-n", + "","", + "","", + /*B4-B7 line 24-31*/ + "","FM_CPU_SP5R1", + "reset-cause-rsmrst","FM_CPU_SP5R2", + "","FM_CPU_SP5R3", + "","FM_CPU_SP5R4", + /*C0-C3 line 32-39*/ + "","FM_CPU0_SA0", + "","FM_CPU0_SA1", + "","rt-cpu0-p0-enable", + "","rt-cpu0-p1-enable", + /*C4-C7 line 40-47*/ + "","smb-rt-rom-p0-select", + "","smb-rt-rom-p1-select", + "","i3c-cpu-mux0-oe-n", + "","i3c-cpu-mux0-select", + /*D0-D3 line 48-55*/ + "","i3c-cpu-mux1-oe-n", + "","i3c-cpu-mux1-select", + "","reset-control-bmc", + "","reset-control-cpu0-p0-mux", + /*D4-D7 line 56-63*/ + "","reset-control-cpu0-p1-mux", + "","reset-control-e1s-mux", + "power-host-good","reset-control-mb-mux", + "","reset-control-smb-e1s", + /*E0-E3 line 64-71*/ + "","reset-control-smb-e1s", + "host-ready-n","reset-control-srst", + "presence-e1s-0","reset-control-usb-hub", + "","reset-control", + /*E4-E7 line 72-79*/ + "presence-e1s-1","reset-control-cpu-kbrst", + "","reset-control-platrst", + "","bmc-jtag-mux-select-0", + "","bmc-jtag-mux-select-1", + /*F0-F3 line 80-87*/ + "","bmc-jtag-select", + "","bmc-ready-n", + "","bmc-ready-sgpio", + "","rt-cpu0-p0-force-enable", + /*F4-F7 line 88-95*/ + "presence-asic-modules-0","rt-cpu0-p1-force-enable", + "presence-asic-modules-1","bios-debug-msg-disable", + "","uart-control-buffer-select", + "","ac-control-n", + /*G0-G3 line 96-103*/ + "FM_CPU_CORETYPE2","", + "FM_CPU_CORETYPE1","", + "FM_CPU_CORETYPE0","", + "FM_BOARD_REV_ID5","", + /*G4-G7 line 104-111*/ + "FM_BOARD_REV_ID4","", + "FM_BOARD_REV_ID3","", + "FM_BOARD_REV_ID2","", + "FM_BOARD_REV_ID1","", + /*H0-H3 line 112-119*/ + "FM_BOARD_REV_ID0","", + "","","","","","", + /*H4-H7 line 120-127*/ + "","", + "reset-control-pcie-expansion-3","", + "reset-control-pcie-expansion-2","", + "reset-control-pcie-expansion-1","", + /*I0-I3 line 128-135*/ + "reset-control-pcie-expansion-0","", + "FM_EXP_SLOT_ID1","", + "FM_EXP_SLOT_ID0","", + "","", + /*I4-I7 line 136-143*/ + "","","","","","","","", + /*J0-J3 line 144-151*/ + "","","","","","","","", + /*J4-J7 line 152-159*/ + "SLOT_ID_BCB_0","", + "SLOT_ID_BCB_1","", + "SLOT_ID_BCB_2","", + "SLOT_ID_BCB_3","", + /*K0-K3 line 160-167*/ + "","","","","","","","", + /*K4-K7 line 168-175*/ + "","","","","","","","", + /*L0-L3 line 176-183*/ + "","","","","","","","", + /*L4-L7 line 184-191*/ + "","","","","","","","", + /*M0-M3 line 192-199*/ + "","","","","","","","", + /*M4-M7 line 200-207*/ + "","","","","","","","", + /*N0-N3 line 208-215*/ + "","","","","","","","", + /*N4-N7 line 216-223*/ + "","","","","","","","", + /*O0-O3 line 224-231*/ + "","","","","","","","", + /*O4-O7 line 232-239*/ + "","","","","","","","", + /*P0-P3 line 240-247*/ + "","","","","","","","", + /*P4-P7 line 248-255*/ + "","","","","","","",""; +}; -- cgit v1.2.3-59-g8ed1b From 6ee9b93999a9efb4529dbc78deb524ec890aba1a Mon Sep 17 00:00:00 2001 From: Yang Chen Date: Tue, 12 Dec 2023 15:51:50 +0800 Subject: ARM: dts: aspeed: minerva: Revise the name of DTS The project Minerva which is the platform used by Meta has two boards: the Chassis Management Module (Minerva) and the Motherboard (Harma), so change the DTS name to minerva here for CMM use. Signed-off-by: Yang Chen Reviewed-by: Joel Stanley Link: https://lore.kernel.org/r/20231212075200.983536-2-yangchen.openbmc@gmail.com Signed-off-by: Joel Stanley Signed-off-by: Andrew Jeffery --- arch/arm/boot/dts/aspeed/Makefile | 2 +- .../dts/aspeed/aspeed-bmc-facebook-minerva-cmc.dts | 265 --------------------- .../dts/aspeed/aspeed-bmc-facebook-minerva.dts | 265 +++++++++++++++++++++ 3 files changed, 266 insertions(+), 266 deletions(-) delete mode 100644 arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-minerva-cmc.dts create mode 100644 arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-minerva.dts diff --git a/arch/arm/boot/dts/aspeed/Makefile b/arch/arm/boot/dts/aspeed/Makefile index 7231d8fa1004..560be4c3c8ae 100644 --- a/arch/arm/boot/dts/aspeed/Makefile +++ b/arch/arm/boot/dts/aspeed/Makefile @@ -22,7 +22,7 @@ dtb-$(CONFIG_ARCH_ASPEED) += \ aspeed-bmc-facebook-galaxy100.dtb \ aspeed-bmc-facebook-greatlakes.dtb \ aspeed-bmc-facebook-harma.dtb \ - aspeed-bmc-facebook-minerva-cmc.dtb \ + aspeed-bmc-facebook-minerva.dtb \ aspeed-bmc-facebook-minipack.dtb \ aspeed-bmc-facebook-tiogapass.dtb \ aspeed-bmc-facebook-wedge40.dtb \ diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-minerva-cmc.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-minerva-cmc.dts deleted file mode 100644 index f04ef9063520..000000000000 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-minerva-cmc.dts +++ /dev/null @@ -1,265 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -// Copyright (c) 2023 Facebook Inc. -/dts-v1/; - -#include "aspeed-g6.dtsi" -#include -#include - -/ { - model = "Facebook Minerva CMC"; - compatible = "facebook,minerva-cmc", "aspeed,ast2600"; - - aliases { - serial5 = &uart5; - }; - - chosen { - stdout-path = "serial5:57600n8"; - }; - - memory@80000000 { - device_type = "memory"; - reg = <0x80000000 0x80000000>; - }; - - iio-hwmon { - compatible = "iio-hwmon"; - io-channels = <&adc0 0>, <&adc0 1>, <&adc0 2>, <&adc0 3>, - <&adc0 4>, <&adc0 5>, <&adc0 6>, <&adc0 7>, - <&adc1 2>; - }; -}; - -&uart6 { - status = "okay"; -}; - -&wdt1 { - status = "okay"; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_wdtrst1_default>; - aspeed,reset-type = "soc"; - aspeed,external-signal; - aspeed,ext-push-pull; - aspeed,ext-active-high; - aspeed,ext-pulse-duration = <256>; -}; - -&mac3 { - status = "okay"; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_rmii4_default>; - use-ncsi; - mlx,multi-host; -}; - -&fmc { - status = "okay"; - flash@0 { - status = "okay"; - m25p,fast-read; - label = "bmc"; - spi-max-frequency = <50000000>; -#include "openbmc-flash-layout-128.dtsi" - }; - flash@1 { - status = "okay"; - m25p,fast-read; - label = "alt-bmc"; - spi-max-frequency = <50000000>; - }; -}; - -&rtc { - status = "okay"; -}; - -&sgpiom1 { - status = "okay"; - ngpios = <128>; - bus-frequency = <2000000>; -}; - -&i2c0 { - status = "okay"; -}; - -&i2c1 { - status = "okay"; - - temperature-sensor@4b { - compatible = "ti,tmp75"; - reg = <0x4B>; - }; - - eeprom@51 { - compatible = "atmel,24c128"; - reg = <0x51>; - }; -}; - -&i2c2 { - status = "okay"; - - i2c-mux@77 { - compatible = "nxp,pca9548"; - reg = <0x77>; - #address-cells = <1>; - #size-cells = <0>; - i2c-mux-idle-disconnect; - - i2c@0 { - #address-cells = <1>; - #size-cells = <0>; - reg = <0>; - - eeprom@50 { - compatible = "atmel,24c128"; - reg = <0x50>; - }; - }; - - i2c@1 { - #address-cells = <1>; - #size-cells = <0>; - reg = <1>; - - eeprom@50 { - compatible = "atmel,24c128"; - reg = <0x50>; - }; - }; - - i2c@2 { - #address-cells = <1>; - #size-cells = <0>; - reg = <2>; - - eeprom@50 { - compatible = "atmel,24c128"; - reg = <0x50>; - }; - }; - - i2c@3 { - #address-cells = <1>; - #size-cells = <0>; - reg = <3>; - - eeprom@50 { - compatible = "atmel,24c128"; - reg = <0x50>; - }; - }; - - i2c@4 { - #address-cells = <1>; - #size-cells = <0>; - reg = <4>; - - eeprom@50 { - compatible = "atmel,24c128"; - reg = <0x50>; - }; - }; - - i2c@5 { - #address-cells = <1>; - #size-cells = <0>; - reg = <5>; - - eeprom@50 { - compatible = "atmel,24c128"; - reg = <0x50>; - }; - }; - }; -}; - -&i2c3 { - status = "okay"; -}; - -&i2c4 { - status = "okay"; -}; - -&i2c5 { - status = "okay"; -}; - -&i2c6 { - status = "okay"; -}; - -&i2c7 { - status = "okay"; -}; - -&i2c8 { - status = "okay"; -}; - -&i2c9 { - status = "okay"; -}; - -&i2c10 { - status = "okay"; -}; - -&i2c11 { - status = "okay"; -}; - -&i2c12 { - status = "okay"; -}; - -&i2c13 { - status = "okay"; -}; - -&i2c14 { - status = "okay"; - multi-master; - - ipmb@10 { - compatible = "ipmb-dev"; - reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>; - i2c-protocol; - }; -}; - -&i2c15 { - status = "okay"; - - eeprom@50 { - compatible = "atmel,24c128"; - reg = <0x50>; - }; -}; - -&adc0 { - aspeed,int-vref-microvolt = <2500000>; - status = "okay"; - pinctrl-0 = <&pinctrl_adc0_default &pinctrl_adc1_default - &pinctrl_adc2_default &pinctrl_adc3_default - &pinctrl_adc4_default &pinctrl_adc5_default - &pinctrl_adc6_default &pinctrl_adc7_default>; -}; - -&adc1 { - aspeed,int-vref-microvolt = <2500000>; - status = "okay"; - pinctrl-0 = <&pinctrl_adc10_default>; -}; - -&ehci1 { - status = "okay"; -}; - -&uhci { - status = "okay"; -}; diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-minerva.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-minerva.dts new file mode 100644 index 000000000000..c755fb3258a4 --- /dev/null +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-minerva.dts @@ -0,0 +1,265 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright (c) 2023 Facebook Inc. +/dts-v1/; + +#include "aspeed-g6.dtsi" +#include +#include + +/ { + model = "Facebook Minerva CMM"; + compatible = "facebook,minerva-cmc", "aspeed,ast2600"; + + aliases { + serial5 = &uart5; + }; + + chosen { + stdout-path = "serial5:57600n8"; + }; + + memory@80000000 { + device_type = "memory"; + reg = <0x80000000 0x80000000>; + }; + + iio-hwmon { + compatible = "iio-hwmon"; + io-channels = <&adc0 0>, <&adc0 1>, <&adc0 2>, <&adc0 3>, + <&adc0 4>, <&adc0 5>, <&adc0 6>, <&adc0 7>, + <&adc1 2>; + }; +}; + +&uart6 { + status = "okay"; +}; + +&wdt1 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_wdtrst1_default>; + aspeed,reset-type = "soc"; + aspeed,external-signal; + aspeed,ext-push-pull; + aspeed,ext-active-high; + aspeed,ext-pulse-duration = <256>; +}; + +&mac3 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_rmii4_default>; + use-ncsi; + mlx,multi-host; +}; + +&fmc { + status = "okay"; + flash@0 { + status = "okay"; + m25p,fast-read; + label = "bmc"; + spi-max-frequency = <50000000>; +#include "openbmc-flash-layout-128.dtsi" + }; + flash@1 { + status = "okay"; + m25p,fast-read; + label = "alt-bmc"; + spi-max-frequency = <50000000>; + }; +}; + +&rtc { + status = "okay"; +}; + +&sgpiom1 { + status = "okay"; + ngpios = <128>; + bus-frequency = <2000000>; +}; + +&i2c0 { + status = "okay"; +}; + +&i2c1 { + status = "okay"; + + temperature-sensor@4b { + compatible = "ti,tmp75"; + reg = <0x4B>; + }; + + eeprom@51 { + compatible = "atmel,24c128"; + reg = <0x51>; + }; +}; + +&i2c2 { + status = "okay"; + + i2c-mux@77 { + compatible = "nxp,pca9548"; + reg = <0x77>; + #address-cells = <1>; + #size-cells = <0>; + i2c-mux-idle-disconnect; + + i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + + eeprom@50 { + compatible = "atmel,24c128"; + reg = <0x50>; + }; + }; + + i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + + eeprom@50 { + compatible = "atmel,24c128"; + reg = <0x50>; + }; + }; + + i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + + eeprom@50 { + compatible = "atmel,24c128"; + reg = <0x50>; + }; + }; + + i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + + eeprom@50 { + compatible = "atmel,24c128"; + reg = <0x50>; + }; + }; + + i2c@4 { + #address-cells = <1>; + #size-cells = <0>; + reg = <4>; + + eeprom@50 { + compatible = "atmel,24c128"; + reg = <0x50>; + }; + }; + + i2c@5 { + #address-cells = <1>; + #size-cells = <0>; + reg = <5>; + + eeprom@50 { + compatible = "atmel,24c128"; + reg = <0x50>; + }; + }; + }; +}; + +&i2c3 { + status = "okay"; +}; + +&i2c4 { + status = "okay"; +}; + +&i2c5 { + status = "okay"; +}; + +&i2c6 { + status = "okay"; +}; + +&i2c7 { + status = "okay"; +}; + +&i2c8 { + status = "okay"; +}; + +&i2c9 { + status = "okay"; +}; + +&i2c10 { + status = "okay"; +}; + +&i2c11 { + status = "okay"; +}; + +&i2c12 { + status = "okay"; +}; + +&i2c13 { + status = "okay"; +}; + +&i2c14 { + status = "okay"; + multi-master; + + ipmb@10 { + compatible = "ipmb-dev"; + reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>; + i2c-protocol; + }; +}; + +&i2c15 { + status = "okay"; + + eeprom@50 { + compatible = "atmel,24c128"; + reg = <0x50>; + }; +}; + +&adc0 { + aspeed,int-vref-microvolt = <2500000>; + status = "okay"; + pinctrl-0 = <&pinctrl_adc0_default &pinctrl_adc1_default + &pinctrl_adc2_default &pinctrl_adc3_default + &pinctrl_adc4_default &pinctrl_adc5_default + &pinctrl_adc6_default &pinctrl_adc7_default>; +}; + +&adc1 { + aspeed,int-vref-microvolt = <2500000>; + status = "okay"; + pinctrl-0 = <&pinctrl_adc10_default>; +}; + +&ehci1 { + status = "okay"; +}; + +&uhci { + status = "okay"; +}; -- cgit v1.2.3-59-g8ed1b From cb188e3f275fd4827722d271d94d1e77b6207040 Mon Sep 17 00:00:00 2001 From: Yang Chen Date: Tue, 12 Dec 2023 15:51:51 +0800 Subject: ARM: dts: aspeed: minerva: Modify mac3 setting Remove the unuse setting and fix the link to 100 M Signed-off-by: Yang Chen Reviewed-by: Joel Stanley Link: https://lore.kernel.org/r/20231212075200.983536-3-yangchen.openbmc@gmail.com Signed-off-by: Joel Stanley Signed-off-by: Andrew Jeffery --- arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-minerva.dts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-minerva.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-minerva.dts index c755fb3258a4..9979dba1ef0e 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-minerva.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-minerva.dts @@ -48,10 +48,13 @@ &mac3 { status = "okay"; + phy-mode = "rmii"; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_rmii4_default>; - use-ncsi; - mlx,multi-host; + fixed-link { + speed = <100>; + full-duplex; + }; }; &fmc { -- cgit v1.2.3-59-g8ed1b From 8061d80d7a6bd33598d82a4cbcd06dd78c691e7d Mon Sep 17 00:00:00 2001 From: Yang Chen Date: Tue, 12 Dec 2023 15:51:52 +0800 Subject: ARM: dts: aspeed: minerva: Change sgpio use Correct the sgpio use from sgpiom1 to sgpiom0 Signed-off-by: Yang Chen Reviewed-by: Joel Stanley Link: https://lore.kernel.org/r/20231212075200.983536-4-yangchen.openbmc@gmail.com Signed-off-by: Joel Stanley Signed-off-by: Andrew Jeffery --- arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-minerva.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-minerva.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-minerva.dts index 9979dba1ef0e..ad77057f921c 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-minerva.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-minerva.dts @@ -78,7 +78,7 @@ status = "okay"; }; -&sgpiom1 { +&sgpiom0 { status = "okay"; ngpios = <128>; bus-frequency = <2000000>; -- cgit v1.2.3-59-g8ed1b From 331dfa00f4ae8595e86f798951a10c1bbfa67880 Mon Sep 17 00:00:00 2001 From: Yang Chen Date: Tue, 12 Dec 2023 15:51:53 +0800 Subject: ARM: dts: aspeed: minerva: Enable power monitor device Enable power monitor device ina230 and ltc2945 on the i2c bus 0 Signed-off-by: Yang Chen Reviewed-by: Joel Stanley Link: https://lore.kernel.org/r/20231212075200.983536-5-yangchen.openbmc@gmail.com Signed-off-by: Joel Stanley Signed-off-by: Andrew Jeffery --- .../dts/aspeed/aspeed-bmc-facebook-minerva.dts | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-minerva.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-minerva.dts index ad77057f921c..ee9691647e4a 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-minerva.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-minerva.dts @@ -86,6 +86,28 @@ &i2c0 { status = "okay"; + + power-monitor@40 { + compatible = "ti,ina230"; + reg = <0x40>; + shunt-resistor = <1000>; + }; + + power-monitor@41 { + compatible = "ti,ina230"; + reg = <0x41>; + shunt-resistor = <1000>; + }; + + power-monitor@67 { + compatible = "adi,ltc2945"; + reg = <0x67>; + }; + + power-monitor@68 { + compatible = "adi,ltc2945"; + reg = <0x68>; + }; }; &i2c1 { -- cgit v1.2.3-59-g8ed1b From feab10df422f866434ee812c40ce5fd1c30049b8 Mon Sep 17 00:00:00 2001 From: Yang Chen Date: Tue, 12 Dec 2023 15:51:54 +0800 Subject: ARM: dts: aspeed: minerva: Add temperature sensor Add one temperature sensor on i2c bus 1 Signed-off-by: Yang Chen Reviewed-by: Joel Stanley Link: https://lore.kernel.org/r/20231212075200.983536-6-yangchen.openbmc@gmail.com Signed-off-by: Joel Stanley Signed-off-by: Andrew Jeffery --- arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-minerva.dts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-minerva.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-minerva.dts index ee9691647e4a..783d4d5a8f3d 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-minerva.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-minerva.dts @@ -115,7 +115,12 @@ temperature-sensor@4b { compatible = "ti,tmp75"; - reg = <0x4B>; + reg = <0x4b>; + }; + + temperature-sensor@48 { + compatible = "ti,tmp75"; + reg = <0x48>; }; eeprom@51 { -- cgit v1.2.3-59-g8ed1b From 37f295a28eda57e5582add64194358153217c467 Mon Sep 17 00:00:00 2001 From: Yang Chen Date: Tue, 12 Dec 2023 15:51:55 +0800 Subject: ARM: dts: aspeed: minerva: correct the address of eeprom Correct the address from 0x51 to 0x54 of eeprom on the i2c bus 1 Signed-off-by: Yang Chen Reviewed-by: Joel Stanley Link: https://lore.kernel.org/r/20231212075200.983536-7-yangchen.openbmc@gmail.com Signed-off-by: Joel Stanley Signed-off-by: Andrew Jeffery --- arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-minerva.dts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-minerva.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-minerva.dts index 783d4d5a8f3d..f2a48033ac5c 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-minerva.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-minerva.dts @@ -123,9 +123,9 @@ reg = <0x48>; }; - eeprom@51 { + eeprom@54 { compatible = "atmel,24c128"; - reg = <0x51>; + reg = <0x54>; }; }; -- cgit v1.2.3-59-g8ed1b From b2daa191f75b6bd51acc6df7b190ed71a25d9de0 Mon Sep 17 00:00:00 2001 From: Yang Chen Date: Tue, 12 Dec 2023 15:51:56 +0800 Subject: ARM: dts: aspeed: minerva: add bus labels and aliases Add bus labels and aliases for the fan control board. Signed-off-by: Yang Chen Reviewed-by: Joel Stanley Link: https://lore.kernel.org/r/20231212075200.983536-8-yangchen.openbmc@gmail.com Signed-off-by: Joel Stanley Signed-off-by: Andrew Jeffery --- .../dts/aspeed/aspeed-bmc-facebook-minerva.dts | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-minerva.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-minerva.dts index f2a48033ac5c..f4cb5ef72310 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-minerva.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-minerva.dts @@ -12,6 +12,16 @@ aliases { serial5 = &uart5; + /* + * PCA9548 (2-0077) provides 8 channels connecting to + * 6 pcs of FCB (Fan Controller Board). + */ + i2c16 = &imux16; + i2c17 = &imux17; + i2c18 = &imux18; + i2c19 = &imux19; + i2c20 = &imux20; + i2c21 = &imux21; }; chosen { @@ -139,7 +149,7 @@ #size-cells = <0>; i2c-mux-idle-disconnect; - i2c@0 { + imux16: i2c@0 { #address-cells = <1>; #size-cells = <0>; reg = <0>; @@ -150,7 +160,7 @@ }; }; - i2c@1 { + imux17: i2c@1 { #address-cells = <1>; #size-cells = <0>; reg = <1>; @@ -161,7 +171,7 @@ }; }; - i2c@2 { + imux18: i2c@2 { #address-cells = <1>; #size-cells = <0>; reg = <2>; @@ -172,7 +182,7 @@ }; }; - i2c@3 { + imux19: i2c@3 { #address-cells = <1>; #size-cells = <0>; reg = <3>; @@ -183,7 +193,7 @@ }; }; - i2c@4 { + imux20: i2c@4 { #address-cells = <1>; #size-cells = <0>; reg = <4>; @@ -194,7 +204,7 @@ }; }; - i2c@5 { + imux21: i2c@5 { #address-cells = <1>; #size-cells = <0>; reg = <5>; -- cgit v1.2.3-59-g8ed1b From 2dcb5ca763acbaa56b6be3bee49bb2e8b91c92e4 Mon Sep 17 00:00:00 2001 From: Yang Chen Date: Tue, 12 Dec 2023 15:51:57 +0800 Subject: ARM: dts: aspeed: minerva: add fan rpm controller Add fan rpm controller max31790 on all bus of FCB. Signed-off-by: Yang Chen Reviewed-by: Joel Stanley Link: https://lore.kernel.org/r/20231212075200.983536-9-yangchen.openbmc@gmail.com Signed-off-by: Joel Stanley Signed-off-by: Andrew Jeffery --- .../dts/aspeed/aspeed-bmc-facebook-minerva.dts | 42 ++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-minerva.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-minerva.dts index f4cb5ef72310..c7445c819baf 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-minerva.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-minerva.dts @@ -158,6 +158,13 @@ compatible = "atmel,24c128"; reg = <0x50>; }; + + pwm@5e{ + compatible = "max31790"; + reg = <0x5e>; + #address-cells = <1>; + #size-cells = <0>; + }; }; imux17: i2c@1 { @@ -169,6 +176,13 @@ compatible = "atmel,24c128"; reg = <0x50>; }; + + pwm@5e{ + compatible = "max31790"; + reg = <0x5e>; + #address-cells = <1>; + #size-cells = <0>; + }; }; imux18: i2c@2 { @@ -180,6 +194,13 @@ compatible = "atmel,24c128"; reg = <0x50>; }; + + pwm@5e{ + compatible = "max31790"; + reg = <0x5e>; + #address-cells = <1>; + #size-cells = <0>; + }; }; imux19: i2c@3 { @@ -191,6 +212,13 @@ compatible = "atmel,24c128"; reg = <0x50>; }; + + pwm@5e{ + compatible = "max31790"; + reg = <0x5e>; + #address-cells = <1>; + #size-cells = <0>; + }; }; imux20: i2c@4 { @@ -202,6 +230,13 @@ compatible = "atmel,24c128"; reg = <0x50>; }; + + pwm@5e{ + compatible = "max31790"; + reg = <0x5e>; + #address-cells = <1>; + #size-cells = <0>; + }; }; imux21: i2c@5 { @@ -213,6 +248,13 @@ compatible = "atmel,24c128"; reg = <0x50>; }; + + pwm@5e{ + compatible = "max31790"; + reg = <0x5e>; + #address-cells = <1>; + #size-cells = <0>; + }; }; }; }; -- cgit v1.2.3-59-g8ed1b From bb4d30382468705c4084348149ae06af0cc124cc Mon Sep 17 00:00:00 2001 From: Yang Chen Date: Tue, 12 Dec 2023 15:51:58 +0800 Subject: ARM: dts: aspeed: minerva: Add led-fan-fault gpio Add led-fan-fault gpio pin on the PCA9555 on the i2c bus 0. Signed-off-by: Yang Chen Reviewed-by: Joel Stanley Link: https://lore.kernel.org/r/20231212075200.983536-10-yangchen.openbmc@gmail.com Signed-off-by: Joel Stanley Signed-off-by: Andrew Jeffery --- .../arm/boot/dts/aspeed/aspeed-bmc-facebook-minerva.dts | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-minerva.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-minerva.dts index c7445c819baf..090fe2f6b1d8 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-minerva.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-minerva.dts @@ -39,6 +39,16 @@ <&adc0 4>, <&adc0 5>, <&adc0 6>, <&adc0 7>, <&adc1 2>; }; + + leds { + compatible = "gpio-leds"; + + led-fan-fault { + label = "led-fan-fault"; + gpios = <&leds_gpio 9 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + }; }; &uart6 { @@ -118,6 +128,13 @@ compatible = "adi,ltc2945"; reg = <0x68>; }; + + leds_gpio: gpio@19 { + compatible = "nxp,pca9555"; + reg = <0x19>; + gpio-controller; + #gpio-cells = <2>; + }; }; &i2c1 { -- cgit v1.2.3-59-g8ed1b From 25a56a921ca28ec77c1d47c2907fce7d36331863 Mon Sep 17 00:00:00 2001 From: Yang Chen Date: Tue, 12 Dec 2023 15:51:59 +0800 Subject: ARM: dts: aspeed: minerva: add gpio line name Add the GPIO line name that the project's function can use by the meaningful name. Signed-off-by: Yang Chen Reviewed-by: Joel Stanley Link: https://lore.kernel.org/r/20231212075200.983536-11-yangchen.openbmc@gmail.com Signed-off-by: Joel Stanley Signed-off-by: Andrew Jeffery --- .../dts/aspeed/aspeed-bmc-facebook-minerva.dts | 30 ++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-minerva.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-minerva.dts index 090fe2f6b1d8..31197183cc59 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-minerva.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-minerva.dts @@ -362,3 +362,33 @@ &uhci { status = "okay"; }; + +&gpio0 { + gpio-line-names = + /*A0-A7*/ "","","","","","","","", + /*B0-B7*/ "","","","","","","","", + /*C0-C7*/ "","","","","BLADE_UART_SEL2","","","", + /*D0-D7*/ "","","","","","","","", + /*E0-E7*/ "","","","","","","","", + /*F0-F7*/ "","","","","","","","", + /*G0-G7*/ "","","","","","","","", + /*H0-H7*/ "","","","","","","","", + /*I0-I7*/ "","","","","","","","", + /*J0-J7*/ "","","","","","","","", + /*K0-K7*/ "","","","","","","","", + /*L0-L7*/ "","","","","BLADE_UART_SEL0","","","", + /*M0-M7*/ "","","","","","BLADE_UART_SEL1","","", + /*N0-N7*/ "","","","","","","","", + /*O0-O7*/ "","","","","","","","", + /*P0-P7*/ "","","","","","","","", + /*Q0-Q7*/ "","","","","","","","", + /*R0-R7*/ "","","","","","","","", + /*S0-S7*/ "","","","","","","","", + /*T0-T7*/ "","","","","","","","", + /*U0-U7*/ "","","","","","","","", + /*V0-V7*/ "","","","","BAT_DETECT","","","", + /*W0-W7*/ "","","","","","","","", + /*X0-X7*/ "","","BLADE_UART_SEL3","","","","","", + /*Y0-Y7*/ "","","","","","","","", + /*Z0-Z7*/ "","","","","","","",""; +}; -- cgit v1.2.3-59-g8ed1b From 51493f0fd68daf5a60f54314d3424c4c82b106ce Mon Sep 17 00:00:00 2001 From: Yang Chen Date: Tue, 12 Dec 2023 15:52:00 +0800 Subject: ARM: dts: aspeed: minerva: add sgpio line name Add the SGPIO line name that the project's function can use by the meaningful name. Signed-off-by: Yang Chen Reviewed-by: Joel Stanley Link: https://lore.kernel.org/r/20231212075200.983536-12-yangchen.openbmc@gmail.com Signed-off-by: Joel Stanley Signed-off-by: Andrew Jeffery --- .../dts/aspeed/aspeed-bmc-facebook-minerva.dts | 149 +++++++++++++++++++++ 1 file changed, 149 insertions(+) diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-minerva.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-minerva.dts index 31197183cc59..942e53d5c714 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-minerva.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-minerva.dts @@ -392,3 +392,152 @@ /*Y0-Y7*/ "","","","","","","","", /*Z0-Z7*/ "","","","","","","",""; }; + +&sgpiom0 { + gpio-line-names = + /*"input pin","output pin"*/ + /*A0 - A7*/ + "PRSNT_MTIA_BLADE0_N","PWREN_MTIA_BLADE0_EN", + "PRSNT_MTIA_BLADE1_N","PWREN_MTIA_BLADE1_EN", + "PRSNT_MTIA_BLADE2_N","PWREN_MTIA_BLADE2_EN", + "PRSNT_MTIA_BLADE3_N","PWREN_MTIA_BLADE3_EN", + "PRSNT_MTIA_BLADE4_N","PWREN_MTIA_BLADE4_EN", + "PRSNT_MTIA_BLADE5_N","PWREN_MTIA_BLADE5_EN", + "PRSNT_MTIA_BLADE6_N","PWREN_MTIA_BLADE6_EN", + "PRSNT_MTIA_BLADE7_N","PWREN_MTIA_BLADE7_EN", + /*B0 - B7*/ + "PRSNT_MTIA_BLADE8_N","PWREN_MTIA_BLADE8_EN", + "PRSNT_MTIA_BLADE9_N","PWREN_MTIA_BLADE9_EN", + "PRSNT_MTIA_BLADE10_N","PWREN_MTIA_BLADE10_EN", + "PRSNT_MTIA_BLADE11_N","PWREN_MTIA_BLADE11_EN", + "PRSNT_MTIA_BLADE12_N","PWREN_MTIA_BLADE12_EN", + "PRSNT_MTIA_BLADE13_N","PWREN_MTIA_BLADE13_EN", + "PRSNT_MTIA_BLADE14_N","PWREN_MTIA_BLADE14_EN", + "PRSNT_MTIA_BLADE15_N","PWREN_MTIA_BLADE15_EN", + /*C0 - C7*/ + "PRSNT_NW_BLADE0_N","PWREN_NW_BLADE0_EN", + "PRSNT_NW_BLADE1_N","PWREN_NW_BLADE1_EN", + "PRSNT_NW_BLADE2_N","PWREN_NW_BLADE2_EN", + "PRSNT_NW_BLADE3_N","PWREN_NW_BLADE3_EN", + "PRSNT_NW_BLADE4_N","PWREN_NW_BLADE4_EN", + "PRSNT_NW_BLADE5_N","PWREN_NW_BLADE5_EN", + "PRSNT_FCB_TOP_0_N","PWREN_MTIA_BLADE0_HSC_EN", + "PRSNT_FCB_TOP_1_N","PWREN_MTIA_BLADE1_HSC_EN", + /*D0 - D7*/ + "PRSNT_FCB_MIDDLE_0_N","PWREN_MTIA_BLADE2_HSC_EN", + "PRSNT_FCB_MIDDLE_1_N","PWREN_MTIA_BLADE3_HSC_EN", + "PRSNT_FCB_BOTTOM_0_N","PWREN_MTIA_BLADE4_HSC_EN", + "PRSNT_FCB_BOTTOM_1_N","PWREN_MTIA_BLADE5_HSC_EN", + "PWRGD_MTIA_BLADE0_PWROK_L_BUF","PWREN_MTIA_BLADE6_HSC_EN", + "PWRGD_MTIA_BLADE1_PWROK_L_BUF","PWREN_MTIA_BLADE7_HSC_EN", + "PWRGD_MTIA_BLADE2_PWROK_L_BUF","PWREN_MTIA_BLADE8_HSC_EN", + "PWRGD_MTIA_BLADE3_PWROK_L_BUF","PWREN_MTIA_BLADE9_HSC_EN", + /*E0 - E7*/ + "PWRGD_MTIA_BLADE4_PWROK_L_BUF","PWREN_MTIA_BLADE10_HSC_EN", + "PWRGD_MTIA_BLADE5_PWROK_L_BUF","PWREN_MTIA_BLADE11_HSC_EN", + "PWRGD_MTIA_BLADE6_PWROK_L_BUF","PWREN_MTIA_BLADE12_HSC_EN", + "PWRGD_MTIA_BLADE7_PWROK_L_BUF","PWREN_MTIA_BLADE13_HSC_EN", + "PWRGD_MTIA_BLADE8_PWROK_L_BUF","PWREN_MTIA_BLADE14_HSC_EN", + "PWRGD_MTIA_BLADE9_PWROK_L_BUF","PWREN_MTIA_BLADE15_HSC_EN", + "PWRGD_MTIA_BLADE10_PWROK_L_BUF","PWREN_NW_BLADE0_HSC_EN", + "PWRGD_MTIA_BLADE11_PWROK_L_BUF","PWREN_NW_BLADE1_HSC_EN", + /*F0 - F7*/ + "PWRGD_MTIA_BLADE12_PWROK_L_BUF","PWREN_NW_BLADE2_HSC_EN", + "PWRGD_MTIA_BLADE13_PWROK_L_BUF","PWREN_NW_BLADE3_HSC_EN", + "PWRGD_MTIA_BLADE14_PWROK_L_BUF","PWREN_NW_BLADE4_HSC_EN", + "PWRGD_MTIA_BLADE15_PWROK_L_BUF","PWREN_NW_BLADE5_HSC_EN", + "PWRGD_NW_BLADE0_PWROK_L_BUF","PWREN_FCB_TOP_L_EN", + "PWRGD_NW_BLADE1_PWROK_L_BUF","PWREN_FCB_TOP_R_EN", + "PWRGD_NW_BLADE2_PWROK_L_BUF","PWREN_FCB_MIDDLE_L_EN", + "PWRGD_NW_BLADE3_PWROK_L_BUF","PWREN_FCB_MIDDLE_R_EN", + /*G0 - G7*/ + "PWRGD_NW_BLADE4_PWROK_L_BUF","PWREN_FCB_BOTTOM_L_EN", + "PWRGD_NW_BLADE5_PWROK_L_BUF","PWREN_FCB_BOTTOM_R_EN", + "PWRGD_FCB_TOP_0_PWROK_L_BUF","FM_CMM_AC_CYCLE_N", + "PWRGD_FCB_TOP_1_PWROK_L_BUF","MGMT_SFP_TX_DIS", + "PWRGD_FCB_MIDDLE_0_PWROK_L_BUF","", + "PWRGD_FCB_MIDDLE_1_PWROK_L_BUF","RST_I2CRST_MTIA_BLADE0_1_N", + "PWRGD_FCB_BOTTOM_0_PWROK_L_BUF","RST_I2CRST_MTIA_BLADE2_3_N", + "PWRGD_FCB_BOTTOM_1_PWROK_L_BUF","RST_I2CRST_MTIA_BLADE4_5_N", + /*H0 - H7*/ + "LEAK_DETECT_MTIA_BLADE0_N_BUF","RST_I2CRST_MTIA_BLADE6_7_N", + "LEAK_DETECT_MTIA_BLADE1_N_BUF","RST_I2CRST_MTIA_BLADE8_9_N", + "LEAK_DETECT_MTIA_BLADE2_N_BUF","RST_I2CRST_MTIA_BLADE10_11_N", + "LEAK_DETECT_MTIA_BLADE3_N_BUF","RST_I2CRST_MTIA_BLADE12_13_N", + "LEAK_DETECT_MTIA_BLADE4_N_BUF","RST_I2CRST_MTIA_BLADE14_15_N", + "LEAK_DETECT_MTIA_BLADE5_N_BUF","RST_I2CRST_NW_BLADE0_1_2_N", + "LEAK_DETECT_MTIA_BLADE6_N_BUF","RST_I2CRST_NW_BLADE3_4_5_N", + "LEAK_DETECT_MTIA_BLADE7_N_BUF","RST_I2CRST_FCB_N", + /*I0 - I7*/ + "LEAK_DETECT_MTIA_BLADE8_N_BUF","RST_I2CRST_FCB_B_L_N", + "LEAK_DETECT_MTIA_BLADE9_N_BUF","RST_I2CRST_FCB_B_R_N", + "LEAK_DETECT_MTIA_BLADE10_N_BUF","RST_I2CRST_FCB_M_L_N", + "LEAK_DETECT_MTIA_BLADE11_N_BUF","RST_I2CRST_FCB_M_R_N", + "LEAK_DETECT_MTIA_BLADE12_N_BUF","RST_I2CRST_FCB_T_L_N", + "LEAK_DETECT_MTIA_BLADE13_N_BUF","RST_I2CRST_FCB_T_R_N", + "LEAK_DETECT_MTIA_BLADE14_N_BUF","BMC_READY", + "LEAK_DETECT_MTIA_BLADE15_N_BUF","wFM_88E6393X_BIN_UPDATE_EN_N", + /*J0 - J7*/ + "LEAK_DETECT_NW_BLADE0_N_BUF","WATER_VALVE_CLOSED_N", + "LEAK_DETECT_NW_BLADE1_N_BUF","", + "LEAK_DETECT_NW_BLADE2_N_BUF","", + "LEAK_DETECT_NW_BLADE3_N_BUF","", + "LEAK_DETECT_NW_BLADE4_N_BUF","", + "LEAK_DETECT_NW_BLADE5_N_BUF","", + "MTIA_BLADE0_STATUS_LED","", + "MTIA_BLADE1_STATUS_LED","", + /*K0 - K7*/ + "MTIA_BLADE2_STATUS_LED","", + "MTIA_BLADE3_STATUS_LED","", + "MTIA_BLADE4_STATUS_LED","", + "MTIA_BLADE5_STATUS_LED","", + "MTIA_BLADE6_STATUS_LED","", + "MTIA_BLADE7_STATUS_LED","", + "MTIA_BLADE8_STATUS_LED","", + "MTIA_BLADE9_STATUS_LED","", + /*L0 - L7*/ + "MTIA_BLADE10_STATUS_LED","", + "MTIA_BLADE11_STATUS_LED","", + "MTIA_BLADE12_STATUS_LED","", + "MTIA_BLADE13_STATUS_LED","", + "MTIA_BLADE14_STATUS_LED","", + "MTIA_BLADE15_STATUS_LED","", + "NW_BLADE0_STATUS_LED","", + "NW_BLADE1_STATUS_LED","", + /*M0 - M7*/ + "NW_BLADE2_STATUS_LED","", + "NW_BLADE3_STATUS_LED","", + "NW_BLADE4_STATUS_LED","", + "NW_BLADE5_STATUS_LED","", + "RPU_READY","", + "IT_GEAR_RPU_LINK_N","", + "IT_GEAR_LEAK","", + "WATER_VALVE_CLOSED_N","", + /*N0 - N7*/ + "VALVE_STS0","", + "VALVE_STS1","", + "VALVE_STS2","", + "VALVE_STS3","", + "CR_TOGGLE_BOOT_BUF_N","", + "CMM_LC_RDY_LED_N","", + "CMM_LC_UNRDY_LED_N","", + "CMM_CABLE_CARTRIDGE_PRSNT_BOT_N","", + /*O0 - O7*/ + "CMM_CABLE_CARTRIDGE_PRSNT_TOP_N","", + "BOT_BCB_CABLE_PRSNT_N","", + "TOP_BCB_CABLE_PRSNT_N","", + "CHASSIS0_LEAK_Q_N","", + "CHASSIS1_LEAK_Q_N","", + "LEAK0_DETECT","", + "LEAK1_DETECT","", + "MGMT_SFP_PRSNT_N","", + /*P0 - P7*/ + "MGMT_SFP_TX_FAULT","", + "MGMT_SFP_RX_LOS","", + "","", + "","", + "","", + "","", + "","", + "",""; +}; -- cgit v1.2.3-59-g8ed1b From a78bfc109667ee932b4106e482f891188fe66456 Mon Sep 17 00:00:00 2001 From: Peter Yin Date: Fri, 12 Apr 2024 17:15:49 +0800 Subject: ARM: dts: aspeed: Harma: Revise SGPIO line name. The same name as reset-control-smb-e1s change to reset-control-smb-e1s-0 and reset-control-smb-e1s-0. Signed-off-by: Peter Yin Link: https://lore.kernel.org/r/20240412091600.2534693-2-peteryin.openbmc@gmail.com Signed-off-by: Andrew Jeffery --- arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-harma.dts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-harma.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-harma.dts index 7db3f9eb0016..8a173863ef24 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-harma.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-harma.dts @@ -505,9 +505,9 @@ "","reset-control-cpu0-p1-mux", "","reset-control-e1s-mux", "power-host-good","reset-control-mb-mux", - "","reset-control-smb-e1s", + "","reset-control-smb-e1s-0", /*E0-E3 line 64-71*/ - "","reset-control-smb-e1s", + "","reset-control-smb-e1s-1", "host-ready-n","reset-control-srst", "presence-e1s-0","reset-control-usb-hub", "","reset-control", -- cgit v1.2.3-59-g8ed1b From d965bbe65bc026a7f1097993fddc49ad5009f924 Mon Sep 17 00:00:00 2001 From: Peter Yin Date: Fri, 12 Apr 2024 17:15:50 +0800 Subject: ARM: dts: aspeed: Harma: mapping ttyS2 to UART4. Change routing to match SOL(Serial Over LAN) settings. Signed-off-by: Peter Yin Link: https://lore.kernel.org/r/20240412091600.2534693-3-peteryin.openbmc@gmail.com Signed-off-by: Andrew Jeffery --- arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-harma.dts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-harma.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-harma.dts index 8a173863ef24..a0056d633eb1 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-harma.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-harma.dts @@ -12,8 +12,8 @@ aliases { serial0 = &uart1; - serial1 = &uart6; - serial2 = &uart2; + serial1 = &uart2; + serial2 = &uart4; serial4 = &uart5; i2c20 = &imux20; -- cgit v1.2.3-59-g8ed1b From f8bbe984efcc1ee953f4b22369edf18fbac6d2f1 Mon Sep 17 00:00:00 2001 From: Peter Yin Date: Fri, 12 Apr 2024 17:15:51 +0800 Subject: ARM: dts: aspeed: Harma: Remove Vuart Remove vuart to avoid port conflict with uart2 Signed-off-by: Peter Yin Link: https://lore.kernel.org/r/20240412091600.2534693-4-peteryin.openbmc@gmail.com Signed-off-by: Andrew Jeffery --- arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-harma.dts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-harma.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-harma.dts index a0056d633eb1..5d692e9f541e 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-harma.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-harma.dts @@ -100,10 +100,6 @@ status = "okay"; }; -&vuart1 { - status = "okay"; -}; - &wdt1 { status = "okay"; pinctrl-names = "default"; -- cgit v1.2.3-59-g8ed1b From 5a29fd7ad48b8b69a1c5875c726519250a5ea556 Mon Sep 17 00:00:00 2001 From: Peter Yin Date: Fri, 12 Apr 2024 17:15:52 +0800 Subject: ARM: dts: aspeed: Harma: Add cpu power good line name Add a line name for cpu power good. Signed-off-by: Peter Yin Link: https://lore.kernel.org/r/20240412091600.2534693-5-peteryin.openbmc@gmail.com Signed-off-by: Andrew Jeffery --- arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-harma.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-harma.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-harma.dts index 5d692e9f541e..36aad01dda20 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-harma.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-harma.dts @@ -501,7 +501,7 @@ "","reset-control-cpu0-p1-mux", "","reset-control-e1s-mux", "power-host-good","reset-control-mb-mux", - "","reset-control-smb-e1s-0", + "power-cpu-good","reset-control-smb-e1s-0", /*E0-E3 line 64-71*/ "","reset-control-smb-e1s-1", "host-ready-n","reset-control-srst", -- cgit v1.2.3-59-g8ed1b From 3042a7e557cd0cf2be9c58363c1032b6cacac798 Mon Sep 17 00:00:00 2001 From: Peter Yin Date: Fri, 12 Apr 2024 17:15:53 +0800 Subject: ARM: dts: aspeed: Harma: Add spi-gpio Add spi-gpio for tpm device. Signed-off-by: Peter Yin Link: https://lore.kernel.org/r/20240412091600.2534693-6-peteryin.openbmc@gmail.com Signed-off-by: Andrew Jeffery --- .../boot/dts/aspeed/aspeed-bmc-facebook-harma.dts | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-harma.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-harma.dts index 36aad01dda20..ca3052cce0e0 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-harma.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-harma.dts @@ -28,6 +28,8 @@ i2c29 = &imux29; i2c30 = &imux30; i2c31 = &imux31; + + spi1 = &spi_gpio; }; chosen { @@ -67,6 +69,25 @@ gpios = <&gpio0 124 GPIO_ACTIVE_HIGH>; }; }; + + spi_gpio: spi-gpio { + status = "okay"; + compatible = "spi-gpio"; + #address-cells = <1>; + #size-cells = <0>; + + gpio-sck = <&gpio0 ASPEED_GPIO(Z, 3) GPIO_ACTIVE_HIGH>; + gpio-mosi = <&gpio0 ASPEED_GPIO(Z, 4) GPIO_ACTIVE_HIGH>; + gpio-miso = <&gpio0 ASPEED_GPIO(Z, 5) GPIO_ACTIVE_HIGH>; + num-chipselects = <1>; + cs-gpios = <&gpio0 ASPEED_GPIO(Z, 0) GPIO_ACTIVE_LOW>; + + tpmdev@0 { + compatible = "infineon,slb9670", "tcg,tpm_tis-spi"; + spi-max-frequency = <33000000>; + reg = <0>; + }; + }; }; // HOST BIOS Debug -- cgit v1.2.3-59-g8ed1b From 645f9eb1bdb4c3ad867746c80ff714f57c5e8e09 Mon Sep 17 00:00:00 2001 From: Peter Yin Date: Fri, 12 Apr 2024 17:15:54 +0800 Subject: ARM: dts: aspeed: Harma: Add PDB temperature Add PDB temperature sensor. Signed-off-by: Peter Yin Link: https://lore.kernel.org/r/20240412091600.2534693-7-peteryin.openbmc@gmail.com Signed-off-by: Andrew Jeffery --- arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-harma.dts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-harma.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-harma.dts index ca3052cce0e0..5c3fa8bbaced 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-harma.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-harma.dts @@ -203,7 +203,7 @@ &i2c1 { status = "okay"; - tmp75@4b { + temperature-sensor@4b { compatible = "ti,tmp75"; reg = <0x4b>; }; @@ -260,6 +260,11 @@ compatible = "pmbus"; reg = <0x69>; }; + + temperature-sensor@49 { + compatible = "ti,tmp75"; + reg = <0x49>; + }; }; &i2c5 { -- cgit v1.2.3-59-g8ed1b From 7b55cf239cb5b496109b13432ba0e557534268bc Mon Sep 17 00:00:00 2001 From: Peter Yin Date: Fri, 12 Apr 2024 17:15:55 +0800 Subject: ARM: dts: aspeed: Harma: Revise max31790 address Revise max31790 address from 0x30 to 0x5e Signed-off-by: Peter Yin Link: https://lore.kernel.org/r/20240412091600.2534693-8-peteryin.openbmc@gmail.com Signed-off-by: Andrew Jeffery --- arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-harma.dts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-harma.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-harma.dts index 5c3fa8bbaced..7e98af5836cf 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-harma.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-harma.dts @@ -192,9 +192,9 @@ &i2c0 { status = "okay"; - max31790@30{ + max31790@5e{ compatible = "max31790"; - reg = <0x30>; + reg = <0x5e>; #address-cells = <1>; #size-cells = <0>; }; @@ -212,9 +212,9 @@ &i2c2 { status = "okay"; - max31790@30{ + max31790@5e{ compatible = "max31790"; - reg = <0x30>; + reg = <0x5e>; #address-cells = <1>; #size-cells = <0>; }; -- cgit v1.2.3-59-g8ed1b From 0a6821e249fa450a3b37a3ab5a1639d2ca329c5a Mon Sep 17 00:00:00 2001 From: Peter Yin Date: Fri, 12 Apr 2024 17:15:56 +0800 Subject: ARM: dts: aspeed: Harma: Add NIC Fru device Add MB NIC Device Signed-off-by: Peter Yin Link: https://lore.kernel.org/r/20240412091600.2534693-9-peteryin.openbmc@gmail.com Signed-off-by: Andrew Jeffery --- arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-harma.dts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-harma.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-harma.dts index 7e98af5836cf..6e9e6e559838 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-harma.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-harma.dts @@ -207,6 +207,12 @@ compatible = "ti,tmp75"; reg = <0x4b>; }; + + // MB NIC FRU + eeprom@50 { + compatible = "atmel,24c64"; + reg = <0x50>; + }; }; &i2c2 { -- cgit v1.2.3-59-g8ed1b From fc2891c74594994d49c0f5941d50a70d4f022c70 Mon Sep 17 00:00:00 2001 From: Peter Yin Date: Fri, 12 Apr 2024 17:15:57 +0800 Subject: ARM: dts: aspeed: Harma: Add ltc4286 device Add ltc4286 device. Signed-off-by: Peter Yin Link: https://lore.kernel.org/r/20240412091600.2534693-10-peteryin.openbmc@gmail.com Signed-off-by: Andrew Jeffery --- arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-harma.dts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-harma.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-harma.dts index 6e9e6e559838..7dd48c384a4d 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-harma.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-harma.dts @@ -271,6 +271,13 @@ compatible = "ti,tmp75"; reg = <0x49>; }; + + power-monitor@22 { + compatible = "lltc,ltc4286"; + reg = <0x22>; + adi,vrange-low-enable; + shunt-resistor-micro-ohms = <500>; + }; }; &i2c5 { -- cgit v1.2.3-59-g8ed1b From 4187ccb5a45f9207aeadfe9bdecdc581a5c7eab8 Mon Sep 17 00:00:00 2001 From: Peter Yin Date: Fri, 12 Apr 2024 17:15:58 +0800 Subject: ARM: dts: aspeed: Harma: Revise node name Revise max31790 and delta_brick node name. Signed-off-by: Peter Yin Link: https://lore.kernel.org/r/20240412091600.2534693-11-peteryin.openbmc@gmail.com Signed-off-by: Andrew Jeffery --- arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-harma.dts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-harma.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-harma.dts index 7dd48c384a4d..530f69005857 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-harma.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-harma.dts @@ -192,7 +192,7 @@ &i2c0 { status = "okay"; - max31790@5e{ + pwm@5e{ compatible = "max31790"; reg = <0x5e>; #address-cells = <1>; @@ -218,7 +218,7 @@ &i2c2 { status = "okay"; - max31790@5e{ + pwm@5e{ compatible = "max31790"; reg = <0x5e>; #address-cells = <1>; @@ -262,7 +262,7 @@ reg = <0x52>; }; - delta_brick@69 { + power-monitor@69 { compatible = "pmbus"; reg = <0x69>; }; -- cgit v1.2.3-59-g8ed1b From 287ba28a695a92072b8b659bf0ee1fc7136c8a2f Mon Sep 17 00:00:00 2001 From: Peter Yin Date: Fri, 12 Apr 2024 17:15:59 +0800 Subject: ARM: dts: aspeed: Harma: Add retimer device Add pt5161l device in i2c bus12 and bus21. Signed-off-by: Peter Yin Link: https://lore.kernel.org/r/20240412091600.2534693-12-peteryin.openbmc@gmail.com Signed-off-by: Andrew Jeffery --- arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-harma.dts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-harma.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-harma.dts index 530f69005857..a5abb16e5d8b 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-harma.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-harma.dts @@ -250,6 +250,10 @@ #address-cells = <1>; #size-cells = <0>; reg = <1>; + retimer@24 { + compatible = "asteralabs,pt5161l"; + reg = <0x24>; + }; }; }; }; @@ -370,6 +374,10 @@ &i2c12 { status = "okay"; + retimer@24 { + compatible = "asteralabs,pt5161l"; + reg = <0x24>; + }; }; &i2c13 { -- cgit v1.2.3-59-g8ed1b From 4424cd4db6c8f2cb2d965b6b0e20fd99653acc72 Mon Sep 17 00:00:00 2001 From: Peter Yin Date: Fri, 12 Apr 2024 17:16:00 +0800 Subject: ARM: dts: aspeed: Harma: Modify GPIO line name Add: "reset-cause-platrst", "cpu0-err-alert", "leakage-detect-alert", "presence-post-card", "ac-power-button", "P0_I3C_APML_ALERT_L", "irq-uv-detect-alert", "irq-hsc-alert", "cpu0-prochot-alert", "cpu0-thermtrip-alert", "reset-cause-pcie", "pvdd11-ocp-alert" Rename: "power-cpu-good" to "host0-ready", "host-ready-n" to "post-end-n Signed-off-by: Peter Yin Link: https://lore.kernel.org/r/20240412091600.2534693-13-peteryin.openbmc@gmail.com Signed-off-by: Andrew Jeffery --- .../boot/dts/aspeed/aspeed-bmc-facebook-harma.dts | 38 +++++++++++++++++----- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-harma.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-harma.dts index a5abb16e5d8b..e7f4823ca4b3 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-harma.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-harma.dts @@ -332,6 +332,12 @@ reg = <0x31>; gpio-controller; #gpio-cells = <2>; + + gpio-line-names = + "","","","", + "","","presence-cmm","", + "","","","", + "","","",""; }; i2c-mux@71 { @@ -471,7 +477,8 @@ /*A0-A7*/ "","","","","","","","", /*B0-B7*/ "","","","", "bmc-spi-mux-select-0","led-identify","","", - /*C0-C7*/ "","","","","","","","", + /*C0-C7*/ "reset-cause-platrst","","","","", + "cpu0-err-alert","","", /*D0-D7*/ "","","sol-uart-select","","","","","", /*E0-E7*/ "","","","","","","","", /*F0-F7*/ "","","","","","","","", @@ -480,7 +487,8 @@ /*I0-I7*/ "","","","","","","","", /*J0-J7*/ "","","","","","","","", /*K0-K7*/ "","","","","","","","", - /*L0-L7*/ "","","","","","","","", + /*L0-L7*/ "","","","", + "leakage-detect-alert","","","", /*M0-M7*/ "","","","","","","","", /*N0-N7*/ "led-postcode-0","led-postcode-1", "led-postcode-2","led-postcode-3", @@ -499,7 +507,16 @@ /*W0-W7*/ "","","","","","","","", /*X0-X7*/ "","","","","","","","", /*Y0-Y7*/ "","","","","","","","", - /*Z0-Z7*/ "","","","","","","",""; + /*Z0-Z7*/ "","","","","","","presence-post-card",""; +}; + +&gpio1 { + gpio-line-names = + /*18A0-18A7*/ "ac-power-button","","","","","","","", + /*18B0-18B7*/ "","","","","","","","", + /*18C0-18C7*/ "","","","","","","","", + /*18D0-18D7*/ "","","","","","","","", + /*18E0-18E3*/ "","","","","","","",""; }; &sgpiom0 { @@ -548,10 +565,10 @@ "","reset-control-cpu0-p1-mux", "","reset-control-e1s-mux", "power-host-good","reset-control-mb-mux", - "power-cpu-good","reset-control-smb-e1s-0", + "host0-ready","reset-control-smb-e1s-0", /*E0-E3 line 64-71*/ "","reset-control-smb-e1s-1", - "host-ready-n","reset-control-srst", + "post-end-n","reset-control-srst", "presence-e1s-0","reset-control-usb-hub", "","reset-control", /*E4-E7 line 72-79*/ @@ -602,13 +619,16 @@ "SLOT_ID_BCB_2","", "SLOT_ID_BCB_3","", /*K0-K3 line 160-167*/ - "","","","","","","","", + "","","","","","","P0_I3C_APML_ALERT_L","", /*K4-K7 line 168-175*/ - "","","","","","","","", + "","","","","","","irq-uv-detect-alert","", /*L0-L3 line 176-183*/ - "","","","","","","","", + "irq-hsc-alert","", + "cpu0-prochot-alert","", + "cpu0-thermtrip-alert","", + "reset-cause-pcie","", /*L4-L7 line 184-191*/ - "","","","","","","","", + "pvdd11-ocp-alert","","","","","","","", /*M0-M3 line 192-199*/ "","","","","","","","", /*M4-M7 line 200-207*/ -- cgit v1.2.3-59-g8ed1b From dba3e7743e8987610c197c1807372753b4561409 Mon Sep 17 00:00:00 2001 From: Eddie James Date: Thu, 15 Feb 2024 16:07:52 -0600 Subject: ARM: dts: aspeed: FSI interrupt support Enable FSI interrupt controllers for AST2600 and P10BMC hub master. Signed-off-by: Eddie James Link: https://lore.kernel.org/r/20240215220759.976998-27-eajames@linux.ibm.com Signed-off-by: Joel Stanley Signed-off-by: Andrew Jeffery --- arch/arm/boot/dts/aspeed/aspeed-g6.dtsi | 4 ++++ arch/arm/boot/dts/aspeed/ibm-power10-dual.dtsi | 2 ++ 2 files changed, 6 insertions(+) diff --git a/arch/arm/boot/dts/aspeed/aspeed-g6.dtsi b/arch/arm/boot/dts/aspeed/aspeed-g6.dtsi index 29f94696d8b1..7fb421153596 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-g6.dtsi +++ b/arch/arm/boot/dts/aspeed/aspeed-g6.dtsi @@ -867,22 +867,26 @@ }; fsim0: fsi@1e79b000 { + #interrupt-cells = <1>; compatible = "aspeed,ast2600-fsi-master", "fsi-master"; reg = <0x1e79b000 0x94>; interrupts = ; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_fsi1_default>; clocks = <&syscon ASPEED_CLK_GATE_FSICLK>; + interrupt-controller; status = "disabled"; }; fsim1: fsi@1e79b100 { + #interrupt-cells = <1>; compatible = "aspeed,ast2600-fsi-master", "fsi-master"; reg = <0x1e79b100 0x94>; interrupts = ; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_fsi2_default>; clocks = <&syscon ASPEED_CLK_GATE_FSICLK>; + interrupt-controller; status = "disabled"; }; diff --git a/arch/arm/boot/dts/aspeed/ibm-power10-dual.dtsi b/arch/arm/boot/dts/aspeed/ibm-power10-dual.dtsi index cc466910bb52..07ce3b2bc62a 100644 --- a/arch/arm/boot/dts/aspeed/ibm-power10-dual.dtsi +++ b/arch/arm/boot/dts/aspeed/ibm-power10-dual.dtsi @@ -165,10 +165,12 @@ }; fsi_hub0: hub@3400 { + #interrupt-cells = <1>; compatible = "fsi-master-hub"; reg = <0x3400 0x400>; #address-cells = <2>; #size-cells = <0>; + interrupt-controller; }; }; }; -- cgit v1.2.3-59-g8ed1b From 828e3a94e0edd56f721fcb4b91e40f500e6636b1 Mon Sep 17 00:00:00 2001 From: Ninad Palsule Date: Thu, 25 Jan 2024 15:21:53 -0600 Subject: dt-bindings: arm: aspeed: add IBM system1-bmc Document the new compatibles used on IBM system1-bmc Acked-by: Krzysztof Kozlowski Signed-off-by: Ninad Palsule Link: https://lore.kernel.org/r/20240125212154.4028640-2-ninad@linux.ibm.com Signed-off-by: Joel Stanley Signed-off-by: Andrew Jeffery --- Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml b/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml index 9b3cb6fa52c0..d5d6bfb5b3ed 100644 --- a/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml +++ b/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml @@ -86,6 +86,7 @@ properties: - facebook,yosemite4-bmc - ibm,everest-bmc - ibm,rainier-bmc + - ibm,system1-bmc - ibm,tacoma-bmc - inventec,starscream-bmc - inventec,transformer-bmc -- cgit v1.2.3-59-g8ed1b From e83c420ade3fc7d11ce0d69960582806a803833e Mon Sep 17 00:00:00 2001 From: Andrew Geissler Date: Thu, 25 Jan 2024 15:21:54 -0600 Subject: ARM: dts: aspeed: system1: IBM System1 BMC board Added a device tree for IBM system1 BMC board, which uses AST2600 SoC. Signed-off-by: Andrew Geissler Signed-off-by: Ninad Palsule Link: https://lore.kernel.org/r/20240125212154.4028640-3-ninad@linux.ibm.com Signed-off-by: Joel Stanley Signed-off-by: Andrew Jeffery --- arch/arm/boot/dts/aspeed/Makefile | 1 + .../arm/boot/dts/aspeed/aspeed-bmc-ibm-system1.dts | 1623 ++++++++++++++++++++ 2 files changed, 1624 insertions(+) create mode 100644 arch/arm/boot/dts/aspeed/aspeed-bmc-ibm-system1.dts diff --git a/arch/arm/boot/dts/aspeed/Makefile b/arch/arm/boot/dts/aspeed/Makefile index 560be4c3c8ae..2d1c5d283db3 100644 --- a/arch/arm/boot/dts/aspeed/Makefile +++ b/arch/arm/boot/dts/aspeed/Makefile @@ -36,6 +36,7 @@ dtb-$(CONFIG_ARCH_ASPEED) += \ aspeed-bmc-ibm-rainier.dtb \ aspeed-bmc-ibm-rainier-1s4u.dtb \ aspeed-bmc-ibm-rainier-4u.dtb \ + aspeed-bmc-ibm-system1.dtb \ aspeed-bmc-intel-s2600wf.dtb \ aspeed-bmc-inspur-fp5280g2.dtb \ aspeed-bmc-inspur-nf5280m6.dtb \ diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-ibm-system1.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-ibm-system1.dts new file mode 100644 index 000000000000..dcbc16308ab5 --- /dev/null +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-ibm-system1.dts @@ -0,0 +1,1623 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright 2023 IBM Corp. +/dts-v1/; + +#include "aspeed-g6.dtsi" +#include +#include +#include + +/ { + model = "System1"; + compatible = "ibm,system1-bmc", "aspeed,ast2600"; + + aliases { + i2c16 = &i2c8mux1chn0; + i2c17 = &i2c8mux1chn1; + i2c18 = &i2c8mux1chn2; + i2c19 = &i2c8mux1chn3; + i2c20 = &i2c8mux1chn4; + i2c21 = &i2c8mux1chn5; + i2c22 = &i2c8mux1chn6; + i2c23 = &i2c8mux1chn7; + i2c24 = &i2c3mux0chn0; + i2c25 = &i2c3mux0chn1; + i2c26 = &i2c3mux0chn2; + i2c27 = &i2c3mux0chn3; + i2c28 = &i2c3mux0chn4; + i2c29 = &i2c3mux0chn5; + i2c30 = &i2c3mux0chn6; + i2c31 = &i2c3mux0chn7; + i2c32 = &i2c6mux0chn0; + i2c33 = &i2c6mux0chn1; + i2c34 = &i2c6mux0chn2; + i2c35 = &i2c6mux0chn3; + i2c36 = &i2c6mux0chn4; + i2c37 = &i2c6mux0chn5; + i2c38 = &i2c6mux0chn6; + i2c39 = &i2c6mux0chn7; + i2c40 = &i2c7mux0chn0; + i2c41 = &i2c7mux0chn1; + i2c42 = &i2c7mux0chn2; + i2c43 = &i2c7mux0chn3; + i2c44 = &i2c7mux0chn4; + i2c45 = &i2c7mux0chn5; + i2c46 = &i2c7mux0chn6; + i2c47 = &i2c7mux0chn7; + i2c48 = &i2c8mux0chn0; + i2c49 = &i2c8mux0chn1; + i2c50 = &i2c8mux0chn2; + i2c51 = &i2c8mux0chn3; + i2c52 = &i2c8mux0chn4; + i2c53 = &i2c8mux0chn5; + i2c54 = &i2c8mux0chn6; + i2c55 = &i2c8mux0chn7; + i2c56 = &i2c14mux0chn0; + i2c57 = &i2c14mux0chn1; + i2c58 = &i2c14mux0chn2; + i2c59 = &i2c14mux0chn3; + i2c60 = &i2c14mux0chn4; + i2c61 = &i2c14mux0chn5; + i2c62 = &i2c14mux0chn6; + i2c63 = &i2c14mux0chn7; + i2c64 = &i2c15mux0chn0; + i2c65 = &i2c15mux0chn1; + i2c66 = &i2c15mux0chn2; + i2c67 = &i2c15mux0chn3; + i2c68 = &i2c15mux0chn4; + i2c69 = &i2c15mux0chn5; + i2c70 = &i2c15mux0chn6; + i2c71 = &i2c15mux0chn7; + }; + + chosen { + stdout-path = "uart5:115200n8"; + }; + + memory@80000000 { + device_type = "memory"; + reg = <0x80000000 0x40000000>; + }; + + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + eventlog: tcg-event-log@b3d00000 { + no-map; + reg = <0xb3d00000 0x100000>; + }; + + ramoops@b3e00000 { + compatible = "ramoops"; + reg = <0xb3e00000 0x200000>; /* 16 * (4 * 0x8000) */ + record-size = <0x8000>; + console-size = <0x8000>; + ftrace-size = <0x8000>; + pmsg-size = <0x8000>; + max-reason = <3>; /* KMSG_DUMP_EMERG */ + }; + + /* LPC FW cycle bridge region requires natural alignment */ + flash_memory: region@b4000000 { + no-map; + reg = <0xb4000000 0x04000000>; /* 64M */ + }; + + /* VGA region is dictated by hardware strapping */ + vga_memory: region@bf000000 { + no-map; + compatible = "shared-dma-pool"; + reg = <0xbf000000 0x01000000>; /* 16M */ + }; + }; + + leds { + compatible = "gpio-leds"; + + led-0 { + gpios = <&gpio0 ASPEED_GPIO(L, 7) GPIO_ACTIVE_HIGH>; + }; + + led-1 { + gpios = <&gpio0 ASPEED_GPIO(P, 7) GPIO_ACTIVE_HIGH>; + }; + + led-2 { + gpios = <&gpio0 ASPEED_GPIO(S, 6) GPIO_ACTIVE_HIGH>; + }; + + led-3 { + gpios = <&gpio0 ASPEED_GPIO(S, 7) GPIO_ACTIVE_HIGH>; + }; + + led-4 { + gpios = <&pca3 5 GPIO_ACTIVE_LOW>; + }; + + led-5 { + gpios = <&pca3 6 GPIO_ACTIVE_LOW>; + }; + + led-6 { + gpios = <&pca3 7 GPIO_ACTIVE_LOW>; + }; + + led-7 { + gpios = <&pca3 8 GPIO_ACTIVE_LOW>; + }; + + led-8 { + gpios = <&pca3 9 GPIO_ACTIVE_LOW>; + }; + + led-9 { + gpios = <&pca3 10 GPIO_ACTIVE_LOW>; + }; + + led-a { + gpios = <&pca3 11 GPIO_ACTIVE_LOW>; + }; + + led-b { + gpios = <&pca4 4 GPIO_ACTIVE_HIGH>; + }; + + led-c { + gpios = <&pca4 5 GPIO_ACTIVE_HIGH>; + }; + + led-d { + gpios = <&pca4 6 GPIO_ACTIVE_HIGH>; + }; + + led-e { + gpios = <&pca4 7 GPIO_ACTIVE_HIGH>; + }; + }; + + gpio-keys-polled { + compatible = "gpio-keys-polled"; + poll-interval = <1000>; + + event-nvme0-presence { + label = "nvme0-presence"; + gpios = <&pca4 0 GPIO_ACTIVE_LOW>; + linux,code = <0>; + }; + + event-nvme1-presence { + label = "nvme1-presence"; + gpios = <&pca4 1 GPIO_ACTIVE_LOW>; + linux,code = <1>; + }; + + event-nvme2-presence { + label = "nvme2-presence"; + gpios = <&pca4 2 GPIO_ACTIVE_LOW>; + linux,code = <2>; + }; + + event-nvme3-presence { + label = "nvme3-presence"; + gpios = <&pca4 3 GPIO_ACTIVE_LOW>; + linux,code = <3>; + }; + }; + + iio-hwmon { + compatible = "iio-hwmon"; + io-channels = <&p12v_vd 0>, <&p5v_aux_vd 0>, + <&p5v_bmc_aux_vd 0>, <&p3v3_aux_vd 0>, + <&p3v3_bmc_aux_vd 0>, <&p1v8_bmc_aux_vd 0>, + <&adc1 4>, <&adc0 2>, <&adc1 0>, + <&p2v5_aux_vd 0>, <&adc1 7>; + }; + + p12v_vd: voltage-divider1 { + compatible = "voltage-divider"; + io-channels = <&adc1 3>; + #io-channel-cells = <1>; + + /* + * Scale the system voltage by 1127/127 to fit the ADC range. + * Use small nominator to prevent integer overflow. + */ + output-ohms = <15>; + full-ohms = <133>; + }; + + p5v_aux_vd: voltage-divider2 { + compatible = "voltage-divider"; + io-channels = <&adc1 5>; + #io-channel-cells = <1>; + + /* + * Scale the system voltage by 1365/365 to fit the ADC range. + * Use small nominator to prevent integer overflow. + */ + output-ohms = <50>; + full-ohms = <187>; + }; + + p5v_bmc_aux_vd: voltage-divider3 { + compatible = "voltage-divider"; + io-channels = <&adc0 3>; + #io-channel-cells = <1>; + + /* + * Scale the system voltage by 1365/365 to fit the ADC range. + * Use small nominator to prevent integer overflow. + */ + output-ohms = <50>; + full-ohms = <187>; + }; + + p3v3_aux_vd: voltage-divider4 { + compatible = "voltage-divider"; + io-channels = <&adc1 2>; + #io-channel-cells = <1>; + + /* + * Scale the system voltage by 1698/698 to fit the ADC range. + * Use small nominator to prevent integer overflow. + */ + output-ohms = <14>; + full-ohms = <34>; + }; + + p3v3_bmc_aux_vd: voltage-divider5 { + compatible = "voltage-divider"; + io-channels = <&adc0 7>; + #io-channel-cells = <1>; + + /* + * Scale the system voltage by 1698/698 to fit the ADC range. + * Use small nominator to prevent integer overflow. + */ + output-ohms = <14>; + full-ohms = <34>; + }; + + p1v8_bmc_aux_vd: voltage-divider6 { + compatible = "voltage-divider"; + io-channels = <&adc0 6>; + #io-channel-cells = <1>; + + /* + * Scale the system voltage by 4000/3000 to fit the ADC range. + * Use small nominator to prevent integer overflow. + */ + output-ohms = <3>; + full-ohms = <4>; + }; + + p2v5_aux_vd: voltage-divider7 { + compatible = "voltage-divider"; + io-channels = <&adc1 1>; + #io-channel-cells = <1>; + + /* + * Scale the system voltage by 2100/1100 to fit the ADC range. + * Use small nominator to prevent integer overflow. + */ + output-ohms = <11>; + full-ohms = <21>; + }; + + p1v8_bmc_aux: fixedregulator-p1v8-bmc-aux { + compatible = "regulator-fixed"; + regulator-name = "p1v8_bmc_aux"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + }; +}; + +&adc0 { + status = "okay"; + vref-supply = <&p1v8_bmc_aux>; + + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_adc0_default + &pinctrl_adc1_default + &pinctrl_adc2_default + &pinctrl_adc3_default + &pinctrl_adc4_default + &pinctrl_adc5_default + &pinctrl_adc6_default + &pinctrl_adc7_default>; +}; + +&adc1 { + status = "okay"; + vref-supply = <&p1v8_bmc_aux>; + aspeed,battery-sensing; + + aspeed,int-vref-microvolt = <2500000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_adc8_default + &pinctrl_adc9_default + &pinctrl_adc10_default + &pinctrl_adc11_default + &pinctrl_adc12_default + &pinctrl_adc13_default + &pinctrl_adc14_default + &pinctrl_adc15_default>; +}; + +&ehci1 { + status = "okay"; +}; + +&uhci { + status = "okay"; +}; + +&gpio0 { + gpio-line-names = + /*A0-A7*/ "","","","","","","","", + /*B0-B7*/ "","","","","bmc-tpm-reset","","","", + /*C0-C7*/ "","","","","","","","", + /*D0-D7*/ "","","","","","","","", + /*E0-E7*/ "","","","","","","","", + /*F0-F7*/ "","","","","","","","", + /*G0-G7*/ "","","","","","","","", + /*H0-H7*/ "","","","","","","","", + /*I0-I7*/ "","","","","","","","", + /*J0-J7*/ "","","","","","","","", + /*K0-K7*/ "","","","","","","","", + /*L0-L7*/ "","","","","","","","bmc-ready", + /*M0-M7*/ "","","","","","","","", + /*N0-N7*/ "","","","","","","","", + /*O0-O7*/ "","","","","","","","", + /*P0-P7*/ "","","","","","","","bmc-hb", + /*Q0-Q7*/ "","","","","","","","", + /*R0-R7*/ "","","","","","","","", + /*S0-S7*/ "","","","","","","rear-enc-fault0","rear-enc-id0", + /*T0-T7*/ "","","","","","","","", + /*U0-U7*/ "","","","","","","","", + /*V0-V7*/ "","rtc-battery-voltage-read-enable","","power-chassis-control","","","","", + /*W0-W7*/ "","","","","","","","", + /*X0-X7*/ "","power-chassis-good","","","","","","", + /*Y0-Y7*/ "","","","","","","","", + /*Z0-Z7*/ "","","","","","","",""; +}; + +&emmc_controller { + status = "okay"; +}; + +&pinctrl_emmc_default { + bias-disable; +}; + +&emmc { + status = "okay"; + clk-phase-mmc-hs200 = <180>, <180>; +}; + +&ibt { + status = "okay"; +}; + +&uart2 { + status = "okay"; +}; + +&vuart1 { + status = "okay"; +}; + +&vuart2 { + status = "okay"; +}; + +&lpc_ctrl { + status = "okay"; + memory-region = <&flash_memory>; +}; + +&mac2 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_rmii3_default>; + clocks = <&syscon ASPEED_CLK_GATE_MAC3CLK>, + <&syscon ASPEED_CLK_MAC3RCLK>; + clock-names = "MACCLK", "RCLK"; + use-ncsi; +}; + +&mac3 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_rmii4_default>; + clocks = <&syscon ASPEED_CLK_GATE_MAC4CLK>, + <&syscon ASPEED_CLK_MAC4RCLK>; + clock-names = "MACCLK", "RCLK"; + use-ncsi; +}; + +&wdt1 { + aspeed,reset-type = "none"; + aspeed,external-signal; + aspeed,ext-push-pull; + aspeed,ext-active-high; + + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_wdtrst1_default>; +}; + +&wdt2 { + status = "okay"; +}; + +&kcs2 { + status = "okay"; + aspeed,lpc-io-reg = <0xca8 0xcac>; +}; + +&kcs3 { + status = "okay"; + aspeed,lpc-io-reg = <0xca2>; + aspeed,lpc-interrupts = <11 IRQ_TYPE_LEVEL_LOW>; +}; + +&i2c0 { + status = "okay"; + + eeprom@50 { + compatible = "atmel,24c64"; + reg = <0x50>; + }; + + regulator@60 { + compatible = "maxim,max8952"; + reg = <0x60>; + + max8952,default-mode = <0>; + max8952,dvs-mode-microvolt = <1250000>, <1200000>, + <1050000>, <950000>; + max8952,sync-freq = <0>; + max8952,ramp-speed = <0>; + + regulator-name = "VR_v77_1v4"; + regulator-min-microvolt = <770000>; + regulator-max-microvolt = <1400000>; + regulator-always-on; + regulator-boot-on; + }; +}; + +&i2c1 { + status = "okay"; + + regulator@42 { + compatible = "infineon,ir38263"; + reg = <0x42>; + }; + + led-controller@60 { + compatible = "nxp,pca9552"; + reg = <0x60>; + #address-cells = <1>; + #size-cells = <0>; + + gpio-controller; + #gpio-cells = <2>; + + led@0 { + label = "nic1-perst"; + reg = <0>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@1 { + label = "bmc-perst"; + reg = <1>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@2 { + label = "reset-M2-SSD1-2-perst"; + reg = <2>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@3 { + label = "pcie-perst1"; + reg = <3>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@4 { + label = "pcie-perst2"; + reg = <4>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@5 { + label = "pcie-perst3"; + reg = <5>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@6 { + label = "pcie-perst4"; + reg = <6>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@7 { + label = "pcie-perst5"; + reg = <7>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@8 { + label = "pcie-perst6"; + reg = <8>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@9 { + label = "pcie-perst7"; + reg = <9>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@10 { + label = "pcie-perst8"; + reg = <10>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@11 { + label = "PV-cp0-sw1stk4-perst"; + reg = <11>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@12 { + label = "PV-cp0-sw1stk5-perst"; + reg = <12>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@13 { + label = "pe-cp-drv0-perst"; + reg = <13>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@14 { + label = "pe-cp-drv1-perst"; + reg = <14>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@15 { + label = "lom-perst"; + reg = <15>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + }; + + gpio@74 { + compatible = "nxp,pca9539"; + reg = <0x74>; + + gpio-controller; + #gpio-cells = <2>; + + gpio-line-names = + "PLUG_DETECT_PCIE_J101_N", + "PLUG_DETECT_PCIE_J102_N", + "PLUG_DETECT_PCIE_J103_N", + "PLUG_DETECT_PCIE_J104_N", + "PLUG_DETECT_PCIE_J105_N", + "PLUG_DETECT_PCIE_J106_N", + "PLUG_DETECT_PCIE_J107_N", + "PLUG_DETECT_PCIE_J108_N", + "PLUG_DETECT_M2_SSD1_N", + "PLUG_DETECT_NIC1_N", + "SEL_SMB_DIMM_CPU0", + "presence-ps2", + "presence-ps3", + "", "", + "PWRBRD_PLUG_DETECT2_N"; + }; +}; + +&i2c2 { + status = "okay"; + + power-supply@58 { + compatible = "ibm,cffps"; + reg = <0x58>; + }; + + power-supply@59 { + compatible = "ibm,cffps"; + reg = <0x59>; + }; + + power-supply@5a { + compatible = "ibm,cffps"; + reg = <0x5a>; + }; + + power-supply@5b { + compatible = "ibm,cffps"; + reg = <0x5b>; + }; +}; + +&i2c3 { + status = "okay"; + + i2c-mux@70 { + compatible = "nxp,pca9548"; + reg = <0x70>; + #address-cells = <1>; + #size-cells = <0>; + i2c-mux-idle-disconnect; + + i2c3mux0chn0: i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + }; + + i2c3mux0chn1: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + }; + + i2c3mux0chn2: i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + }; + + i2c3mux0chn3: i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + }; + + i2c3mux0chn4: i2c@4 { + #address-cells = <1>; + #size-cells = <0>; + reg = <4>; + }; + + i2c3mux0chn5: i2c@5 { + #address-cells = <1>; + #size-cells = <0>; + reg = <5>; + }; + + i2c3mux0chn6: i2c@6 { + #address-cells = <1>; + #size-cells = <0>; + reg = <6>; + }; + + i2c3mux0chn7: i2c@7 { + #address-cells = <1>; + #size-cells = <0>; + reg = <7>; + }; + }; +}; + +&i2c4 { + status = "okay"; +}; + +&i2c5 { + status = "okay"; + + regulator@42 { + compatible = "infineon,ir38263"; + reg = <0x42>; + }; + + regulator@43 { + compatible = "infineon,ir38060"; + reg = <0x43>; + }; +}; + +&i2c6 { + status = "okay"; + + fan-controller@52 { + compatible = "maxim,max31785a"; + reg = <0x52>; + }; + + fan-controller@54 { + compatible = "maxim,max31785a"; + reg = <0x54>; + }; + + eeprom@55 { + compatible = "atmel,24c64"; + reg = <0x55>; + }; + + i2c-mux@70 { + compatible = "nxp,pca9548"; + reg = <0x70>; + #address-cells = <1>; + #size-cells = <0>; + i2c-mux-idle-disconnect; + + i2c6mux0chn0: i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + }; + + i2c6mux0chn1: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + }; + + i2c6mux0chn2: i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + }; + + i2c6mux0chn3: i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + }; + + i2c6mux0chn4: i2c@4 { + #address-cells = <1>; + #size-cells = <0>; + reg = <4>; + + humidity-sensor@40 { + compatible = "ti,hdc1080"; + reg = <0x40>; + }; + + temperature-sensor@48 { + compatible = "ti,tmp275"; + reg = <0x48>; + }; + + eeprom@50 { + compatible = "atmel,24c32"; + reg = <0x50>; + }; + + led-controller@60 { + compatible = "nxp,pca9551"; + reg = <0x60>; + #address-cells = <1>; + #size-cells = <0>; + + gpio-controller; + #gpio-cells = <2>; + + led@0 { + label = "enclosure-id-led"; + reg = <0>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@1 { + label = "attention-led"; + reg = <1>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@2 { + label = "enclosure-fault-rollup-led"; + reg = <2>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@3 { + label = "power-on-led"; + reg = <3>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + }; + + temperature-sensor@76 { + compatible = "infineon,dps310"; + reg = <0x76>; + }; + }; + + i2c6mux0chn5: i2c@5 { + #address-cells = <1>; + #size-cells = <0>; + reg = <5>; + }; + + i2c6mux0chn6: i2c@6 { + #address-cells = <1>; + #size-cells = <0>; + reg = <6>; + }; + + i2c6mux0chn7: i2c@7 { + #address-cells = <1>; + #size-cells = <0>; + reg = <7>; + }; + }; + + pca3: gpio@74 { + compatible = "nxp,pca9539"; + reg = <0x74>; + + gpio-controller; + #gpio-cells = <2>; + }; + + pca4: gpio@77 { + compatible = "nxp,pca9539"; + reg = <0x77>; + + gpio-controller; + #gpio-cells = <2>; + + gpio-line-names = + "PE_NVMED0_EXP_PRSNT_N", + "PE_NVMED1_EXP_PRSNT_N", + "PE_NVMED2_EXP_PRSNT_N", + "PE_NVMED3_EXP_PRSNT_N", + "LED_FAULT_NVMED0", + "LED_FAULT_NVMED1", + "LED_FAULT_NVMED2", + "LED_FAULT_NVMED3", + "FAN0_PRESENCE_R_N", + "FAN1_PRESENCE_R_N", + "FAN2_PRESENCE_R_N", + "FAN3_PRESENCE_R_N", + "FAN4_PRESENCE_R_N", + "FAN5_PRESENCE_N", + "FAN6_PRESENCE_N", + ""; + }; +}; + +&i2c7 { + status = "okay"; + + i2c-mux@70 { + compatible = "nxp,pca9548"; + reg = <0x70>; + #address-cells = <1>; + #size-cells = <0>; + i2c-mux-idle-disconnect; + + i2c7mux0chn0: i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + }; + + i2c7mux0chn1: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + }; + + i2c7mux0chn2: i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + }; + + i2c7mux0chn3: i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + + regulator@58 { + compatible = "mps,mp2973"; + reg = <0x58>; + }; + }; + + i2c7mux0chn4: i2c@4 { + #address-cells = <1>; + #size-cells = <0>; + reg = <4>; + }; + + i2c7mux0chn5: i2c@5 { + #address-cells = <1>; + #size-cells = <0>; + reg = <5>; + + regulator@40 { + compatible = "infineon,tda38640"; + reg = <0x40>; + }; + }; + + i2c7mux0chn6: i2c@6 { + #address-cells = <1>; + #size-cells = <0>; + reg = <6>; + }; + + i2c7mux0chn7: i2c@7 { + #address-cells = <1>; + #size-cells = <0>; + reg = <7>; + }; + }; +}; + +&i2c8 { + status = "okay"; + + i2c-mux@71 { + compatible = "nxp,pca9548"; + reg = <0x71>; + #address-cells = <1>; + #size-cells = <0>; + i2c-mux-idle-disconnect; + + i2c8mux0chn0: i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + + regulator@58 { + compatible = "mps,mp2971"; + reg = <0x58>; + }; + }; + + i2c8mux0chn1: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + + regulator@40 { + compatible = "infineon,tda38640"; + reg = <0x40>; + }; + + regulator@41 { + compatible = "infineon,tda38640"; + reg = <0x41>; + }; + + regulator@58 { + compatible = "mps,mp2971"; + reg = <0x58>; + }; + + regulator@5b { + compatible = "mps,mp2971"; + reg = <0x5b>; + }; + }; + + i2c8mux0chn2: i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + }; + + i2c8mux0chn3: i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + }; + + i2c8mux0chn4: i2c@4 { + #address-cells = <1>; + #size-cells = <0>; + reg = <4>; + + i2c-mux@70 { + compatible = "nxp,pca9548"; + reg = <0x70>; + #address-cells = <1>; + #size-cells = <0>; + i2c-mux-idle-disconnect; + + i2c8mux1chn0: i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + }; + + i2c8mux1chn1: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + }; + + i2c8mux1chn2: i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + }; + + i2c8mux1chn3: i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + }; + + i2c8mux1chn4: i2c@4 { + #address-cells = <1>; + #size-cells = <0>; + reg = <4>; + }; + + i2c8mux1chn5: i2c@5 { + #address-cells = <1>; + #size-cells = <0>; + reg = <5>; + }; + + i2c8mux1chn6: i2c@6 { + #address-cells = <1>; + #size-cells = <0>; + reg = <6>; + }; + + i2c8mux1chn7: i2c@7 { + #address-cells = <1>; + #size-cells = <0>; + reg = <7>; + }; + }; + }; + + i2c8mux0chn5: i2c@5 { + #address-cells = <1>; + #size-cells = <0>; + reg = <5>; + }; + + i2c8mux0chn6: i2c@6 { + #address-cells = <1>; + #size-cells = <0>; + reg = <6>; + + temperature-sensor@4c { + compatible = "ti,tmp423"; + reg = <0x4c>; + }; + }; + + i2c8mux0chn7: i2c@7 { + #address-cells = <1>; + #size-cells = <0>; + reg = <7>; + + regulator@40 { + compatible = "infineon,ir38060"; + reg = <0x40>; + }; + }; + }; +}; + +&i2c9 { + status = "okay"; + + regulator@40 { + compatible = "infineon,ir38263"; + reg = <0x40>; + }; + + regulator@41 { + compatible = "infineon,ir38263"; + reg = <0x41>; + }; + + eeprom@50 { + compatible = "atmel,24c64"; + reg = <0x50>; + }; + + regulator@60 { + compatible = "maxim,max8952"; + reg = <0x60>; + + max8952,default-mode = <0>; + max8952,dvs-mode-microvolt = <1250000>, <1200000>, + <1050000>, <950000>; + max8952,sync-freq = <0>; + max8952,ramp-speed = <0>; + + regulator-name = "VR_v77_1v4"; + regulator-min-microvolt = <770000>; + regulator-max-microvolt = <1400000>; + regulator-always-on; + regulator-boot-on; + }; +}; + +&i2c11 { + status = "okay"; + + tpm@2e { + compatible = "tcg,tpm-tis-i2c"; + reg = <0x2e>; + memory-region = <&eventlog>; + }; +}; + +&i2c12 { + status = "okay"; +}; + +&i2c13 { + status = "okay"; + + regulator@41 { + compatible = "infineon,ir38263"; + reg = <0x41>; + }; + + led-controller@61 { + compatible = "nxp,pca9552"; + reg = <0x61>; + #address-cells = <1>; + #size-cells = <0>; + + gpio-controller; + #gpio-cells = <2>; + + led@0 { + label = "efuse-12v-slots"; + reg = <0>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@1 { + label = "efuse-3p3v-slot"; + reg = <1>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@3 { + label = "nic2-pert"; + reg = <3>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@4 { + label = "pcie-perst9"; + reg = <4>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@5 { + label = "pcie-perst10"; + reg = <5>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@6 { + label = "pcie-perst11"; + reg = <6>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@7 { + label = "pcie-perst12"; + reg = <7>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@8 { + label = "pcie-perst13"; + reg = <8>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@9 { + label = "pcie-perst14"; + reg = <9>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@10 { + label = "pcie-perst15"; + reg = <10>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@11 { + label = "pcie-perst16"; + reg = <11>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@12 { + label = "PV-cp1-sw1stk4-perst"; + reg = <12>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@13 { + label = "PV-cp1-sw1stk5-perst"; + reg = <13>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@14 { + label = "pe-cp-drv2-perst"; + reg = <14>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + + led@15 { + label = "pe-cp-drv3-perst"; + reg = <15>; + retain-state-shutdown; + default-state = "keep"; + type = ; + }; + }; + + gpio@75 { + compatible = "nxp,pca9539"; + reg = <0x75>; + + gpio-controller; + #gpio-cells = <2>; + + gpio-line-names = + "PLUG_DETECT_PCIE_J109_N", + "PLUG_DETECT_PCIE_J110_N", + "PLUG_DETECT_PCIE_J111_N", + "PLUG_DETECT_PCIE_J112_N", + "PLUG_DETECT_PCIE_J113_N", + "PLUG_DETECT_PCIE_J114_N", + "PLUG_DETECT_PCIE_J115_N", + "PLUG_DETECT_PCIE_J116_N", + "PLUG_DETECT_M2_SSD2_N", + "PLUG_DETECT_NIC2_N", + "SEL_SMB_DIMM_CPU1", + "presence-ps0", + "presence-ps1", + "", "", + "PWRBRD_PLUG_DETECT1_N"; + }; + + gpio@76 { + compatible = "nxp,pca9539"; + reg = <0x76>; + + gpio-controller; + #gpio-cells = <2>; + + gpio-line-names = + "SW1_BOOTRCVRYB1_N", + "SW1_BOOTRCVRYB0_N", + "SW2_BOOTRCVRYB1_N", + "SW2_BOOTRCVRYB0_N", + "SW3_4_BOOTRCVRYB1_N", + "SW3_4_BOOTRCVRYB0_N", + "SW5_BOOTRCVRYB1_N", + "SW5_BOOTRCVRYB0_N", + "SW6_BOOTRCVRYB1_N", + "SW6_BOOTRCVRYB0_N", + "SW1_RESET_N", + "SW3_RESET_N", + "SW4_RESET_N", + "SW2_RESET_N", + "SW5_RESET_N", + "SW6_RESET_N"; + }; +}; + +&i2c14 { + status = "okay"; + + i2c-mux@70 { + compatible = "nxp,pca9548"; + reg = <0x70>; + #address-cells = <1>; + #size-cells = <0>; + i2c-mux-idle-disconnect; + + i2c14mux0chn0: i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + }; + + i2c14mux0chn1: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + }; + + i2c14mux0chn2: i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + }; + + i2c14mux0chn3: i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + + regulator@58 { + compatible = "mps,mp2973"; + reg = <0x58>; + }; + }; + + i2c14mux0chn4: i2c@4 { + #address-cells = <1>; + #size-cells = <0>; + reg = <4>; + }; + + i2c14mux0chn5: i2c@5 { + #address-cells = <1>; + #size-cells = <0>; + reg = <5>; + + regulator@40 { + compatible = "infineon,tda38640"; + reg = <0x40>; + }; + }; + + i2c14mux0chn6: i2c@6 { + #address-cells = <1>; + #size-cells = <0>; + reg = <6>; + }; + + i2c14mux0chn7: i2c@7 { + #address-cells = <1>; + #size-cells = <0>; + reg = <7>; + }; + }; +}; + +&i2c15 { + status = "okay"; + + i2c-mux@71 { + compatible = "nxp,pca9548"; + reg = <0x71>; + #address-cells = <1>; + #size-cells = <0>; + i2c-mux-idle-disconnect; + + i2c15mux0chn0: i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + + regulator@58 { + compatible = "mps,mp2971"; + reg = <0x58>; + }; + }; + + i2c15mux0chn1: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + + regulator@40 { + compatible = "infineon,tda38640"; + reg = <0x40>; + }; + + regulator@41 { + compatible = "infineon,tda38640"; + reg = <0x41>; + }; + + regulator@58 { + compatible = "mps,mp2971"; + reg = <0x58>; + }; + + regulator@5b { + compatible = "mps,mp2971"; + reg = <0x5b>; + }; + }; + + i2c15mux0chn2: i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + }; + + i2c15mux0chn3: i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + }; + + i2c15mux0chn4: i2c@4 { + #address-cells = <1>; + #size-cells = <0>; + reg = <4>; + + i2c-mux@70 { + compatible = "nxp,pca9548"; + reg = <0x70>; + #address-cells = <1>; + #size-cells = <0>; + i2c-mux-idle-disconnect; + + i2c15mux1chn0: i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + }; + + i2c15mux1chn1: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + }; + + i2c15mux1chn2: i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + }; + + i2c15mux1chn3: i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + }; + + i2c15mux1chn4: i2c@4 { + #address-cells = <1>; + #size-cells = <0>; + reg = <4>; + }; + + i2c15mux1chn5: i2c@5 { + #address-cells = <1>; + #size-cells = <0>; + reg = <5>; + }; + + i2c15mux1chn6: i2c@6 { + #address-cells = <1>; + #size-cells = <0>; + reg = <6>; + }; + + i2c15mux1chn7: i2c@7 { + #address-cells = <1>; + #size-cells = <0>; + reg = <7>; + }; + }; + }; + + i2c15mux0chn5: i2c@5 { + #address-cells = <1>; + #size-cells = <0>; + reg = <5>; + }; + + i2c15mux0chn6: i2c@6 { + #address-cells = <1>; + #size-cells = <0>; + reg = <6>; + + temperature-sensor@4c { + compatible = "ti,tmp423"; + reg = <0x4c>; + }; + }; + + i2c15mux0chn7: i2c@7 { + #address-cells = <1>; + #size-cells = <0>; + reg = <7>; + + regulator@40 { + compatible = "infineon,ir38060"; + reg = <0x40>; + }; + + temperature-sensor@4c { + compatible = "ti,tmp423"; + reg = <0x4c>; + }; + }; + }; +}; -- cgit v1.2.3-59-g8ed1b From 247997184b0eb70f7af29fbe3e32f7a4eff2651e Mon Sep 17 00:00:00 2001 From: Zev Weiss Date: Wed, 31 Jan 2024 20:25:54 -0800 Subject: ARM: dts: aspeed: asrock: Use MAC address from FRU EEPROM Like the more recently added ASRock BMC platforms, e3c246d4i and romed8hm3 also have the BMC's MAC address available in the baseboard FRU EEPROM, so let's add support for using it. Signed-off-by: Zev Weiss Signed-off-by: Andrew Jeffery --- arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-e3c246d4i.dts | 9 +++++++++ arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-romed8hm3.dts | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-e3c246d4i.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-e3c246d4i.dts index c4b2efbfdf56..bb2e6ef609af 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-e3c246d4i.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-e3c246d4i.dts @@ -83,6 +83,9 @@ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_rgmii1_default &pinctrl_mdio1_default>; + + nvmem-cells = <ð0_macaddress>; + nvmem-cell-names = "mac-address"; }; &i2c1 { @@ -103,6 +106,12 @@ compatible = "st,24c128", "atmel,24c128"; reg = <0x57>; pagesize = <16>; + #address-cells = <1>; + #size-cells = <1>; + + eth0_macaddress: macaddress@3f80 { + reg = <0x3f80 6>; + }; }; }; diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-romed8hm3.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-romed8hm3.dts index 4554abf0c7cd..f8a1764a4424 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-romed8hm3.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-romed8hm3.dts @@ -71,6 +71,9 @@ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_rgmii1_default &pinctrl_mdio1_default>; + + nvmem-cells = <ð0_macaddress>; + nvmem-cell-names = "mac-address"; }; &i2c0 { @@ -131,6 +134,12 @@ compatible = "st,24c128", "atmel,24c128"; reg = <0x50>; pagesize = <16>; + #address-cells = <1>; + #size-cells = <1>; + + eth0_macaddress: macaddress@3f80 { + reg = <0x3f80 6>; + }; }; }; -- cgit v1.2.3-59-g8ed1b From dc260f505bd57f57b23bb343285e29533a6264f3 Mon Sep 17 00:00:00 2001 From: Zev Weiss Date: Sat, 24 Feb 2024 02:37:07 -0800 Subject: ARM: dts: aspeed: Add vendor prefixes to lm25066 compat strings Due to the way i2c driver matching works (falling back to the driver's id_table if of_match_table fails) this didn't actually cause any misbehavior, but let's add the vendor prefixes so things actually work the way they were intended to. Signed-off-by: Zev Weiss Reviewed-by: Conor Dooley Signed-off-by: Andrew Jeffery --- arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-romed8hm3.dts | 4 ++-- arch/arm/boot/dts/aspeed/aspeed-bmc-delta-ahe50dc.dts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-romed8hm3.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-romed8hm3.dts index f8a1764a4424..6dd221644dc6 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-romed8hm3.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-romed8hm3.dts @@ -101,14 +101,14 @@ /* IPB PMIC */ lm25066@40 { - compatible = "lm25066"; + compatible = "ti,lm25066"; reg = <0x40>; shunt-resistor-micro-ohms = <1000>; }; /* 12VSB PMIC */ lm25066@41 { - compatible = "lm25066"; + compatible = "ti,lm25066"; reg = <0x41>; shunt-resistor-micro-ohms = <10000>; }; diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-delta-ahe50dc.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-delta-ahe50dc.dts index 6600f7e9bf5e..e830fec0570f 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-delta-ahe50dc.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-delta-ahe50dc.dts @@ -14,7 +14,7 @@ #define EFUSE(hexaddr, num) \ efuse@##hexaddr { \ - compatible = "lm25066"; \ + compatible = "ti,lm25066"; \ reg = <0x##hexaddr>; \ shunt-resistor-micro-ohms = <675>; \ regulators { \ -- cgit v1.2.3-59-g8ed1b From 4ed43e8a1b9080a3ba393606b0523cf8bb311083 Mon Sep 17 00:00:00 2001 From: Zev Weiss Date: Mon, 26 Feb 2024 01:17:53 -0800 Subject: ARM: dts: aspeed: ahe50dc: Update lm25066 regulator name A recent change to the lm25066 driver changed the name of its regulator from vout0 to vout; device-tree users of lm25066's regulator functionality (of which ahe50dc is the only one) thus require a corresponding update. Signed-off-by: Zev Weiss Cc: Conor Dooley Cc: Guenter Roeck Acked-by: Guenter Roeck Signed-off-by: Andrew Jeffery --- arch/arm/boot/dts/aspeed/aspeed-bmc-delta-ahe50dc.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-delta-ahe50dc.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-delta-ahe50dc.dts index e830fec0570f..b6bfdaea08e6 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-delta-ahe50dc.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-delta-ahe50dc.dts @@ -18,7 +18,7 @@ reg = <0x##hexaddr>; \ shunt-resistor-micro-ohms = <675>; \ regulators { \ - efuse##num: vout0 { \ + efuse##num: vout { \ regulator-name = __stringify(efuse##num##-reg); \ }; \ }; \ -- cgit v1.2.3-59-g8ed1b From 1c52e1ca90b2a1debe3a4cda936a1d1544cf5a0e Mon Sep 17 00:00:00 2001 From: Delphine CC Chiu Date: Tue, 12 Mar 2024 13:33:19 +0800 Subject: ARM: dts: aspeed: yosemite4: Enable ipmb device for OCP debug card Add OCP debug card devicetree config Signed-off-by: Delphine CC Chiu Signed-off-by: Andrew Jeffery --- arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-yosemite4.dts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-yosemite4.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-yosemite4.dts index 64075cc41d92..b944ed2cf2f8 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-yosemite4.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-yosemite4.dts @@ -370,6 +370,13 @@ &i2c13 { status = "okay"; bus-frequency = <400000>; + multi-master; + + ipmb@10 { + compatible = "ipmb-dev"; + reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>; + i2c-protocol; + }; }; &i2c14 { -- cgit v1.2.3-59-g8ed1b From 48286e1f0763cbaeb24d3d1fbd5e011a19585c96 Mon Sep 17 00:00:00 2001 From: Eddie James Date: Thu, 21 Mar 2024 09:59:52 -0500 Subject: ARM: dts: Aspeed: Bonnell: Fix NVMe LED labels The PCA chip for the NVMe LEDs is wired up backwards, so correct the device tree labels. Signed-off-by: Eddie James Signed-off-by: Andrew Jeffery --- arch/arm/boot/dts/aspeed/aspeed-bmc-ibm-bonnell.dts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-ibm-bonnell.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-ibm-bonnell.dts index cad1b9aac97b..6fdda42575df 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-ibm-bonnell.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-ibm-bonnell.dts @@ -488,7 +488,7 @@ #gpio-cells = <2>; led@0 { - label = "nvme0"; + label = "nvme3"; reg = <0>; retain-state-shutdown; default-state = "keep"; @@ -496,7 +496,7 @@ }; led@1 { - label = "nvme1"; + label = "nvme2"; reg = <1>; retain-state-shutdown; default-state = "keep"; @@ -504,7 +504,7 @@ }; led@2 { - label = "nvme2"; + label = "nvme1"; reg = <2>; retain-state-shutdown; default-state = "keep"; @@ -512,7 +512,7 @@ }; led@3 { - label = "nvme3"; + label = "nvme0"; reg = <3>; retain-state-shutdown; default-state = "keep"; -- cgit v1.2.3-59-g8ed1b From e0e5ed990b3422e972fba52228d8209b5af8e261 Mon Sep 17 00:00:00 2001 From: Delphine CC Chiu Date: Tue, 26 Mar 2024 15:17:13 +0800 Subject: ARM: dts: aspeed: yosemite4: set bus13 frequency to 100k Since the ocp debug card only supports 100k, the bus is also set to 100k. Signed-off-by: Delphine CC Chiu [AJ: Fixed fuzz due to prior IPMB patch] Signed-off-by: Andrew Jeffery --- arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-yosemite4.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-yosemite4.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-yosemite4.dts index b944ed2cf2f8..28ef2a572c07 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-yosemite4.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-yosemite4.dts @@ -369,7 +369,7 @@ &i2c13 { status = "okay"; - bus-frequency = <400000>; + bus-frequency = <100000>; multi-master; ipmb@10 { -- cgit v1.2.3-59-g8ed1b From 3af11cbbb17c2b2082f57dfc5bfc7ee1fc22000e Mon Sep 17 00:00:00 2001 From: Renze Nicolai Date: Wed, 3 Apr 2024 15:28:51 +0200 Subject: ARM: dts: aspeed: Modify GPIO table for Asrock X570D4U BMC Restructure GPIO table to fit maximum line length. Fix mistakes found while working on OpenBMC userland configuration and based on probing the board. Schematic for this board is not available. Because of this the choice was made to use a descriptive method for naming the GPIOs. - Push-pull outputs start with output-* - Open-drain outputs start with control-* - LED outputs start with led-* - Inputs start with input-* - Button inputs start with button-* - Active low signals end with *-n Signed-off-by: Renze Nicolai Signed-off-by: Andrew Jeffery --- .../boot/dts/aspeed/aspeed-bmc-asrock-x570d4u.dts | 95 +++++++++------------- 1 file changed, 37 insertions(+), 58 deletions(-) diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-x570d4u.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-x570d4u.dts index 3c975bc41ae7..dff69d6ff146 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-x570d4u.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-x570d4u.dts @@ -79,64 +79,43 @@ &gpio { status = "okay"; gpio-line-names = - /*A0-A3*/ "status-locatorled-n", "", "button-nmi-n", "", - /*A4-A7*/ "", "", "", "", - /*B0-B3*/ "input-bios-post-cmplt-n", "", "", "", - /*B4-B7*/ "", "", "", "", - /*C0-C3*/ "", "", "", "", - /*C4-C7*/ "", "", "control-locatorbutton", "", - /*D0-D3*/ "button-power", "control-power", "button-reset", "control-reset", - /*D4-D7*/ "", "", "", "", - /*E0-E3*/ "", "", "", "", - /*E4-E7*/ "", "", "", "", - /*F0-F3*/ "", "", "", "", - /*F4-F7*/ "", "", "", "", - /*G0-G3*/ "output-rtc-battery-voltage-read-enable", "input-id0", "input-id1", "input-id2", - /*G4-G7*/ "input-alert1-n", "input-alert2-n", "input-alert3-n", "", - /*H0-H3*/ "", "", "", "", - /*H4-H7*/ "input-mfg", "", "led-heartbeat-n", "input-caseopen", - /*I0-I3*/ "", "", "", "", - /*I4-I7*/ "", "", "", "", - /*J0-J3*/ "output-bmc-ready", "", "", "", - /*J4-J7*/ "", "", "", "", - /*K0-K3*/ "", "", "", "", - /*K4-K7*/ "", "", "", "", - /*L0-L3*/ "", "", "", "", - /*L4-L7*/ "", "", "", "", - /*M0-M3*/ "", "", "", "", - /*M4-M7*/ "", "", "", "", - /*N0-N3*/ "", "", "", "", - /*N4-N7*/ "", "", "", "", - /*O0-O3*/ "", "", "", "", - /*O4-O7*/ "", "", "", "", - /*P0-P3*/ "", "", "", "", - /*P4-P7*/ "", "", "", "", - /*Q0-Q3*/ "", "", "", "", - /*Q4-Q7*/ "", "", "", "", - /*R0-R3*/ "", "", "", "", - /*R4-R7*/ "", "", "", "", - /*S0-S3*/ "input-bmc-pchhot-n", "", "", "", - /*S4-S7*/ "", "", "", "", - /*T0-T3*/ "", "", "", "", - /*T4-T7*/ "", "", "", "", - /*U0-U3*/ "", "", "", "", - /*U4-U7*/ "", "", "", "", - /*V0-V3*/ "", "", "", "", - /*V4-V7*/ "", "", "", "", - /*W0-W3*/ "", "", "", "", - /*W4-W7*/ "", "", "", "", - /*X0-X3*/ "", "", "", "", - /*X4-X7*/ "", "", "", "", - /*Y0-Y3*/ "", "", "", "", - /*Y4-Y7*/ "", "", "", "", - /*Z0-Z3*/ "", "", "led-fault-n", "output-bmc-throttle-n", - /*Z4-Z7*/ "", "", "", "", - /*AA0-AA3*/ "input-cpu1-thermtrip-latch-n", "", "input-cpu1-prochot-n", "", - /*AA4-AC7*/ "", "", "", "", - /*AB0-AB3*/ "", "", "", "", - /*AB4-AC7*/ "", "", "", "", - /*AC0-AC3*/ "", "", "", "", - /*AC4-AC7*/ "", "", "", ""; + /* A */ "input-locatorled-n", "", "", "", "", "", "", "", + /* B */ "input-bios-post-cmplt-n", "", "", "", "", "", "", "", + /* C */ "", "", "", "", "", "", "control-locatorbutton-n", "", + /* D */ "button-power-n", "control-power-n", "button-reset-n", + "control-reset-n", "", "", "", "", + /* E */ "", "", "", "", "", "", "", "", + /* F */ "", "", "", "", "", "", "", "", + /* G */ "output-hwm-vbat-enable", "input-id0-n", "input-id1-n", + "input-id2-n", "input-aux-smb-alert-n", "", + "input-psu-smb-alert-n", "", + /* H */ "", "", "", "", "input-mfg-mode-n", "", + "led-heartbeat-n", "input-case-open-n", + /* I */ "", "", "", "", "", "", "", "", + /* J */ "output-bmc-ready-n", "", "", "", "", "", "", "", + /* K */ "", "", "", "", "", "", "", "", + /* L */ "", "", "", "", "", "", "", "", + /* M */ "", "", "", "", "", "", "", "", + /* N */ "", "", "", "", "", "", "", "", + /* O */ "", "", "", "", "", "", "", "", + /* P */ "", "", "", "", "", "", "", "", + /* Q */ "", "", "", "", "input-bmc-smb-present-n", "", "", + "input-pcie-wake-n", + /* R */ "", "", "", "", "", "", "", "", + /* S */ "input-bmc-pchhot-n", "", "", "", "", "", "", "", + /* T */ "", "", "", "", "", "", "", "", + /* U */ "", "", "", "", "", "", "", "", + /* V */ "", "", "", "", "", "", "", "", + /* W */ "", "", "", "", "", "", "", "", + /* X */ "", "", "", "", "", "", "", "", + /* Y */ "input-sleep-s3-n", "input-sleep-s5-n", "", "", "", "", + "", "", + /* Z */ "", "", "led-fault-n", "output-bmc-throttle-n", "", "", + "", "", + /* AA */ "input-cpu1-thermtrip-latch-n", "", + "input-cpu1-prochot-n", "", "", "", "", "", + /* AB */ "", "input-power-good", "", "", "", "", "", "", + /* AC */ "", "", "", "", "", "", "", ""; }; &fmc { -- cgit v1.2.3-59-g8ed1b From 62429c485a97038b22b1a18bc27df5579bbfe44a Mon Sep 17 00:00:00 2001 From: Renze Nicolai Date: Wed, 3 Apr 2024 15:28:52 +0200 Subject: ARM: dts: aspeed: Disable unused ADC channels for Asrock X570D4U BMC Additionally adds labels describing the ADC channels. Signed-off-by: Renze Nicolai Signed-off-by: Andrew Jeffery --- .../boot/dts/aspeed/aspeed-bmc-asrock-x570d4u.dts | 29 ++++++++++------------ 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-x570d4u.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-x570d4u.dts index dff69d6ff146..66318ef8caae 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-x570d4u.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-x570d4u.dts @@ -337,20 +337,17 @@ &adc { status = "okay"; pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_adc0_default - &pinctrl_adc1_default - &pinctrl_adc2_default - &pinctrl_adc3_default - &pinctrl_adc4_default - &pinctrl_adc5_default - &pinctrl_adc6_default - &pinctrl_adc7_default - &pinctrl_adc8_default - &pinctrl_adc9_default - &pinctrl_adc10_default - &pinctrl_adc11_default - &pinctrl_adc12_default - &pinctrl_adc13_default - &pinctrl_adc14_default - &pinctrl_adc15_default>; + pinctrl-0 = <&pinctrl_adc0_default /* 3VSB */ + &pinctrl_adc1_default /* 5VSB */ + &pinctrl_adc2_default /* VCPU */ + &pinctrl_adc3_default /* VSOC */ + &pinctrl_adc4_default /* VCCM */ + &pinctrl_adc5_default /* APU-VDDP */ + &pinctrl_adc6_default /* PM-VDD-CLDO */ + &pinctrl_adc7_default /* PM-VDDCR-S5 */ + &pinctrl_adc8_default /* PM-VDDCR */ + &pinctrl_adc9_default /* VBAT */ + &pinctrl_adc10_default /* 3V */ + &pinctrl_adc11_default /* 5V */ + &pinctrl_adc12_default>; /* 12V */ }; -- cgit v1.2.3-59-g8ed1b From c61838aa458b5f96d5824733bef164da2d7ee860 Mon Sep 17 00:00:00 2001 From: Renze Nicolai Date: Wed, 3 Apr 2024 15:28:53 +0200 Subject: ARM: dts: aspeed: Modify I2C bus configuration Enable I2C bus 8 which is exposed on the IPMB_1 connector on the X570D4U mainboard. Additionally adds a descriptive comment to I2C busses 1 and 5. Signed-off-by: Renze Nicolai Signed-off-by: Andrew Jeffery --- arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-x570d4u.dts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-x570d4u.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-x570d4u.dts index 66318ef8caae..8dee4faa9e07 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-x570d4u.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-x570d4u.dts @@ -162,6 +162,7 @@ }; &i2c1 { + /* Hardware monitoring SMBus */ status = "okay"; w83773g@4c { @@ -219,6 +220,7 @@ }; &i2c5 { + /* SMBus on BMC connector (BMC_SMB_1) */ status = "okay"; }; @@ -243,6 +245,11 @@ }; }; +&i2c8 { + /* SMBus on intelligent platform management bus header (IPMB_1) */ + status = "okay"; +}; + &gfx { status = "okay"; }; -- cgit v1.2.3-59-g8ed1b From 1a37b6356253cf3d49af31b4597191bf9e196ff2 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 5 Apr 2024 08:46:20 +0200 Subject: ARM: dts: aspeed: greatlakes: correct Mellanox multi-host property "mlx,multi-host" is using incorrect vendor prefix and is not documented. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240405064624.18997-1-krzysztof.kozlowski@linaro.org Signed-off-by: Andrew Jeffery --- arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-greatlakes.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-greatlakes.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-greatlakes.dts index 7a53f54833a0..9a6757dd203f 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-greatlakes.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-greatlakes.dts @@ -66,7 +66,7 @@ pinctrl-0 = <&pinctrl_rmii4_default>; no-hw-checksum; use-ncsi; - mlx,multi-host; + mellanox,multi-host; ncsi-ctrl,start-redo-probe; ncsi-ctrl,no-channel-monitor; ncsi-package = <1>; -- cgit v1.2.3-59-g8ed1b From d043f805c64b5f8e4195f7a89dc7bb651289fe96 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 5 Apr 2024 08:46:21 +0200 Subject: ARM: dts: aspeed: yosemite4: correct Mellanox multi-host property "mlx,multi-host" is using incorrect vendor prefix and is not documented. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240405064624.18997-2-krzysztof.kozlowski@linaro.org Signed-off-by: Andrew Jeffery --- arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-yosemite4.dts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-yosemite4.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-yosemite4.dts index 28ef2a572c07..78b37d43b3d8 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-yosemite4.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-yosemite4.dts @@ -88,7 +88,7 @@ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_rmii3_default>; use-ncsi; - mlx,multi-host; + mellanox,multi-host; }; &mac3 { @@ -96,7 +96,7 @@ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_rmii4_default>; use-ncsi; - mlx,multi-host; + mellanox,multi-host; }; &fmc { -- cgit v1.2.3-59-g8ed1b From f956245e4b74312cb238ce6a21fe02f60ef592f4 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 5 Apr 2024 08:46:22 +0200 Subject: ARM: dts: aspeed: yosemitev2: correct Mellanox multi-host property "mlx,multi-host" is using incorrect vendor prefix and is not documented. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240405064624.18997-3-krzysztof.kozlowski@linaro.org Signed-off-by: Andrew Jeffery --- arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-yosemitev2.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-yosemitev2.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-yosemitev2.dts index 6bf2ff85a40e..5143f85fbd70 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-yosemitev2.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-yosemitev2.dts @@ -95,7 +95,7 @@ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_rmii1_default>; use-ncsi; - mlx,multi-host; + mellanox,multi-host; }; &adc { -- cgit v1.2.3-59-g8ed1b From 10182a125931f07ca86ec27ca1ffc3091034ad82 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 5 Apr 2024 08:46:23 +0200 Subject: ARM: dts: aspeed: harma: correct Mellanox multi-host property "mlx,multi-host" is using incorrect vendor prefix and is not documented. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240405064624.18997-4-krzysztof.kozlowski@linaro.org Signed-off-by: Andrew Jeffery --- arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-harma.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-harma.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-harma.dts index e7f4823ca4b3..c118d473a76f 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-harma.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-harma.dts @@ -137,7 +137,7 @@ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_rmii4_default>; use-ncsi; - mlx,multi-host; + mellanox,multi-host; }; &rtc { -- cgit v1.2.3-59-g8ed1b From 262fa5540aebaa9f5ebd4fa2a04570694c7e9842 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 5 Apr 2024 08:46:24 +0200 Subject: ARM: dts: aspeed: drop unused ref_voltage ADC property Aspeed ADC "ref_voltage" property is neither documented nor used. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240405064624.18997-5-krzysztof.kozlowski@linaro.org Signed-off-by: Andrew Jeffery --- arch/arm/boot/dts/aspeed/aspeed-bmc-ampere-mtmitchell.dts | 1 - arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-greatlakes.dts | 2 -- arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-yosemite4.dts | 2 -- 3 files changed, 5 deletions(-) diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-ampere-mtmitchell.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-ampere-mtmitchell.dts index 7b540880cef9..3c8925034a8c 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-ampere-mtmitchell.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-ampere-mtmitchell.dts @@ -813,7 +813,6 @@ }; &adc0 { - ref_voltage = <2500>; status = "okay"; pinctrl-names = "default"; diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-greatlakes.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-greatlakes.dts index 9a6757dd203f..998598c15fd0 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-greatlakes.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-greatlakes.dts @@ -211,7 +211,6 @@ }; &adc0 { - ref_voltage = <2500>; status = "okay"; pinctrl-0 = <&pinctrl_adc0_default &pinctrl_adc1_default &pinctrl_adc2_default &pinctrl_adc3_default @@ -220,7 +219,6 @@ }; &adc1 { - ref_voltage = <2500>; status = "okay"; pinctrl-0 = <&pinctrl_adc8_default &pinctrl_adc10_default &pinctrl_adc11_default &pinctrl_adc12_default diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-yosemite4.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-yosemite4.dts index 78b37d43b3d8..98477792aa00 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-yosemite4.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-yosemite4.dts @@ -603,7 +603,6 @@ }; &adc0 { - ref_voltage = <2500>; status = "okay"; pinctrl-0 = <&pinctrl_adc0_default &pinctrl_adc1_default &pinctrl_adc2_default &pinctrl_adc3_default @@ -612,7 +611,6 @@ }; &adc1 { - ref_voltage = <2500>; status = "okay"; pinctrl-0 = <&pinctrl_adc8_default &pinctrl_adc9_default>; }; -- cgit v1.2.3-59-g8ed1b From 1bd612936b558f6868ea1c5734e72fcea3bc49f2 Mon Sep 17 00:00:00 2001 From: Tao Ren Date: Wed, 10 Apr 2024 21:56:18 -0700 Subject: ARM: dts: aspeed: Remove Facebook Cloudripper dts Remove Facebook Cloudripper dts because the switch platform is not actively maintained (all the units are deprecated). Signed-off-by: Tao Ren Link: https://lore.kernel.org/r/20240411045622.7915-1-rentao.bupt@gmail.com Signed-off-by: Andrew Jeffery --- arch/arm/boot/dts/aspeed/Makefile | 1 - .../dts/aspeed/aspeed-bmc-facebook-cloudripper.dts | 544 --------------------- 2 files changed, 545 deletions(-) delete mode 100644 arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-cloudripper.dts diff --git a/arch/arm/boot/dts/aspeed/Makefile b/arch/arm/boot/dts/aspeed/Makefile index 2d1c5d283db3..acc725cc561e 100644 --- a/arch/arm/boot/dts/aspeed/Makefile +++ b/arch/arm/boot/dts/aspeed/Makefile @@ -15,7 +15,6 @@ dtb-$(CONFIG_ARCH_ASPEED) += \ aspeed-bmc-bytedance-g220a.dtb \ aspeed-bmc-delta-ahe50dc.dtb \ aspeed-bmc-facebook-bletchley.dtb \ - aspeed-bmc-facebook-cloudripper.dtb \ aspeed-bmc-facebook-cmm.dtb \ aspeed-bmc-facebook-elbert.dtb \ aspeed-bmc-facebook-fuji.dtb \ diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-cloudripper.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-cloudripper.dts deleted file mode 100644 index d49328fa487a..000000000000 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-cloudripper.dts +++ /dev/null @@ -1,544 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -// Copyright (c) 2020 Facebook Inc. - -/dts-v1/; - -#include -#include "ast2600-facebook-netbmc-common.dtsi" - -/ { - model = "Facebook Cloudripper BMC"; - compatible = "facebook,cloudripper-bmc", "aspeed,ast2600"; - - aliases { - /* - * PCA9548 (1-0070) provides 8 channels connecting to - * SMB (Switch Main Board). - */ - i2c16 = &imux16; - i2c17 = &imux17; - i2c18 = &imux18; - i2c19 = &imux19; - i2c20 = &imux20; - i2c21 = &imux21; - i2c22 = &imux22; - i2c23 = &imux23; - - /* - * PCA9548 (2-0070) provides 8 channels connecting to - * SCM (System Controller Module). - */ - i2c24 = &imux24; - i2c25 = &imux25; - i2c26 = &imux26; - i2c27 = &imux27; - i2c28 = &imux28; - i2c29 = &imux29; - i2c30 = &imux30; - i2c31 = &imux31; - - /* - * PCA9548 (3-0070) provides 8 channels connecting to - * SMB (Switch Main Board). - */ - i2c32 = &imux32; - i2c33 = &imux33; - i2c34 = &imux34; - i2c35 = &imux35; - i2c36 = &imux36; - i2c37 = &imux37; - i2c38 = &imux38; - i2c39 = &imux39; - - /* - * PCA9548 (8-0070) provides 8 channels connecting to - * PDB (Power Delivery Board). - */ - i2c40 = &imux40; - i2c41 = &imux41; - i2c42 = &imux42; - i2c43 = &imux43; - i2c44 = &imux44; - i2c45 = &imux45; - i2c46 = &imux46; - i2c47 = &imux47; - - /* - * PCA9548 (15-0076) provides 8 channels connecting to - * FCM (Fan Controller Module). - */ - i2c48 = &imux48; - i2c49 = &imux49; - i2c50 = &imux50; - i2c51 = &imux51; - i2c52 = &imux52; - i2c53 = &imux53; - i2c54 = &imux54; - i2c55 = &imux55; - }; - - spi_gpio: spi { - num-chipselects = <2>; - cs-gpios = <&gpio0 ASPEED_GPIO(X, 0) GPIO_ACTIVE_LOW>, - <&gpio0 ASPEED_GPIO(X, 1) GPIO_ACTIVE_HIGH>; - - eeprom@1 { - compatible = "atmel,at93c46d"; - spi-max-frequency = <250000>; - data-size = <16>; - spi-cs-high; - reg = <1>; - }; - }; -}; - -&ehci1 { - status = "okay"; -}; - -/* - * "mdio1" is connected to the MDC/MDIO interface of the on-board - * management switch (whose ports are connected to BMC, Host and front - * panel ethernet port). - */ -&mdio1 { - status = "okay"; -}; - -&mdio3 { - status = "okay"; - - ethphy1: ethernet-phy@13 { - compatible = "ethernet-phy-ieee802.3-c22"; - reg = <0x0d>; - }; -}; - -&mac3 { - status = "okay"; - phy-mode = "rgmii"; - phy-handle = <ðphy1>; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_rgmii4_default>; -}; - -&i2c0 { - multi-master; - bus-frequency = <1000000>; -}; - -&i2c1 { - /* - * PCA9548 (1-0070) provides 8 channels connecting to SMB (Switch - * Main Board). - */ - i2c-mux@70 { - compatible = "nxp,pca9548"; - #address-cells = <1>; - #size-cells = <0>; - reg = <0x70>; - i2c-mux-idle-disconnect; - - imux16: i2c@0 { - #address-cells = <1>; - #size-cells = <0>; - reg = <0>; - }; - - imux17: i2c@1 { - #address-cells = <1>; - #size-cells = <0>; - reg = <1>; - }; - - imux18: i2c@2 { - #address-cells = <1>; - #size-cells = <0>; - reg = <2>; - }; - - imux19: i2c@3 { - #address-cells = <1>; - #size-cells = <0>; - reg = <3>; - }; - - imux20: i2c@4 { - #address-cells = <1>; - #size-cells = <0>; - reg = <4>; - }; - - imux21: i2c@5 { - #address-cells = <1>; - #size-cells = <0>; - reg = <5>; - }; - - imux22: i2c@6 { - #address-cells = <1>; - #size-cells = <0>; - reg = <6>; - }; - - imux23: i2c@7 { - #address-cells = <1>; - #size-cells = <0>; - reg = <7>; - }; - }; -}; - -&i2c2 { - /* - * PCA9548 (2-0070) provides 8 channels connecting to SCM (System - * Controller Module). - */ - i2c-mux@70 { - compatible = "nxp,pca9548"; - #address-cells = <1>; - #size-cells = <0>; - reg = <0x70>; - i2c-mux-idle-disconnect; - - imux24: i2c@0 { - #address-cells = <1>; - #size-cells = <0>; - reg = <0>; - }; - - imux25: i2c@1 { - #address-cells = <1>; - #size-cells = <0>; - reg = <1>; - }; - - imux26: i2c@2 { - #address-cells = <1>; - #size-cells = <0>; - reg = <2>; - }; - - imux27: i2c@3 { - #address-cells = <1>; - #size-cells = <0>; - reg = <3>; - }; - - imux28: i2c@4 { - #address-cells = <1>; - #size-cells = <0>; - reg = <4>; - }; - - imux29: i2c@5 { - #address-cells = <1>; - #size-cells = <0>; - reg = <5>; - }; - - imux30: i2c@6 { - #address-cells = <1>; - #size-cells = <0>; - reg = <6>; - }; - - imux31: i2c@7 { - #address-cells = <1>; - #size-cells = <0>; - reg = <7>; - }; - }; -}; - -&i2c3 { - /* - * PCA9548 (3-0070) provides 8 channels connecting to SMB (Switch - * Main Board). - */ - i2c-mux@70 { - compatible = "nxp,pca9548"; - #address-cells = <1>; - #size-cells = <0>; - reg = <0x70>; - i2c-mux-idle-disconnect; - - imux32: i2c@0 { - #address-cells = <1>; - #size-cells = <0>; - reg = <0>; - }; - - imux33: i2c@1 { - #address-cells = <1>; - #size-cells = <0>; - reg = <1>; - }; - - imux34: i2c@2 { - #address-cells = <1>; - #size-cells = <0>; - reg = <2>; - }; - - imux35: i2c@3 { - #address-cells = <1>; - #size-cells = <0>; - reg = <3>; - }; - - imux36: i2c@4 { - #address-cells = <1>; - #size-cells = <0>; - reg = <4>; - }; - - imux37: i2c@5 { - #address-cells = <1>; - #size-cells = <0>; - reg = <5>; - }; - - imux38: i2c@6 { - #address-cells = <1>; - #size-cells = <0>; - reg = <6>; - }; - - imux39: i2c@7 { - #address-cells = <1>; - #size-cells = <0>; - reg = <7>; - }; - }; -}; - -&i2c6 { - lp5012@14 { - compatible = "ti,lp5012"; - reg = <0x14>; - #address-cells = <1>; - #size-cells = <0>; - - multi-led@0 { - #address-cells = <1>; - #size-cells = <0>; - reg = <0>; - color = ; - function = LED_FUNCTION_ACTIVITY; - label = "sys"; - - led@0 { - reg = <0>; - color = ; - }; - - led@1 { - reg = <1>; - color = ; - }; - - led@2 { - reg = <2>; - color = ; - }; - }; - - multi-led@1 { - #address-cells = <1>; - #size-cells = <0>; - reg = <1>; - color = ; - function = LED_FUNCTION_ACTIVITY; - label = "fan"; - - led@0 { - reg = <0>; - color = ; - }; - - led@1 { - reg = <1>; - color = ; - }; - - led@2 { - reg = <2>; - color = ; - }; - }; - - multi-led@2 { - #address-cells = <1>; - #size-cells = <0>; - reg = <2>; - color = ; - function = LED_FUNCTION_ACTIVITY; - label = "psu"; - - led@0 { - reg = <0>; - color = ; - }; - - led@1 { - reg = <1>; - color = ; - }; - - led@2 { - reg = <2>; - color = ; - }; - }; - - multi-led@3 { - #address-cells = <1>; - #size-cells = <0>; - reg = <3>; - color = ; - function = LED_FUNCTION_ACTIVITY; - label = "scm"; - - led@0 { - reg = <0>; - color = ; - }; - - led@1 { - reg = <1>; - color = ; - }; - - led@2 { - reg = <2>; - color = ; - }; - }; - }; -}; - -&i2c8 { - /* - * PCA9548 (8-0070) provides 8 channels connecting to PDB (Power - * Delivery Board). - */ - i2c-mux@70 { - compatible = "nxp,pca9548"; - #address-cells = <1>; - #size-cells = <0>; - reg = <0x70>; - i2c-mux-idle-disconnect; - - imux40: i2c@0 { - #address-cells = <1>; - #size-cells = <0>; - reg = <0>; - }; - - imux41: i2c@1 { - #address-cells = <1>; - #size-cells = <0>; - reg = <1>; - }; - - imux42: i2c@2 { - #address-cells = <1>; - #size-cells = <0>; - reg = <2>; - }; - - imux43: i2c@3 { - #address-cells = <1>; - #size-cells = <0>; - reg = <3>; - }; - - imux44: i2c@4 { - #address-cells = <1>; - #size-cells = <0>; - reg = <4>; - }; - - imux45: i2c@5 { - #address-cells = <1>; - #size-cells = <0>; - reg = <5>; - }; - - imux46: i2c@6 { - #address-cells = <1>; - #size-cells = <0>; - reg = <6>; - }; - - imux47: i2c@7 { - #address-cells = <1>; - #size-cells = <0>; - reg = <7>; - }; - - }; -}; - -&i2c15 { - /* - * PCA9548 (15-0076) provides 8 channels connecting to FCM (Fan - * Controller Module). - */ - i2c-mux@76 { - compatible = "nxp,pca9548"; - #address-cells = <1>; - #size-cells = <0>; - reg = <0x76>; - i2c-mux-idle-disconnect; - - imux48: i2c@0 { - #address-cells = <1>; - #size-cells = <0>; - reg = <0>; - }; - - imux49: i2c@1 { - #address-cells = <1>; - #size-cells = <0>; - reg = <1>; - }; - - imux50: i2c@2 { - #address-cells = <1>; - #size-cells = <0>; - reg = <2>; - }; - - imux51: i2c@3 { - #address-cells = <1>; - #size-cells = <0>; - reg = <3>; - }; - - imux52: i2c@4 { - #address-cells = <1>; - #size-cells = <0>; - reg = <4>; - }; - - imux53: i2c@5 { - #address-cells = <1>; - #size-cells = <0>; - reg = <5>; - }; - - imux54: i2c@6 { - #address-cells = <1>; - #size-cells = <0>; - reg = <6>; - }; - - imux55: i2c@7 { - #address-cells = <1>; - #size-cells = <0>; - reg = <7>; - }; - }; -}; -- cgit v1.2.3-59-g8ed1b From dfb3bc5f4d5db43b53efde8835d85d59531b68b0 Mon Sep 17 00:00:00 2001 From: Kelly Hung Date: Tue, 30 Apr 2024 12:58:52 +0800 Subject: dt-bindings: arm: aspeed: add ASUS X4TF board Document the new compatibles used on ASUS X4TF. Signed-off-by: Kelly Hung Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20240430045853.3894633-2-Kelly_Hung@asus.com Signed-off-by: Joel Stanley --- Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml b/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml index d5d6bfb5b3ed..d6c808c377e4 100644 --- a/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml +++ b/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml @@ -76,6 +76,7 @@ properties: - ampere,mtmitchell-bmc - aspeed,ast2600-evb - aspeed,ast2600-evb-a1 + - asus,x4tf-bmc - facebook,bletchley-bmc - facebook,cloudripper-bmc - facebook,elbert-bmc -- cgit v1.2.3-59-g8ed1b From d8bdd1e8acd54631a59c56f637b18816c5381f61 Mon Sep 17 00:00:00 2001 From: Kelly Hung Date: Tue, 30 Apr 2024 12:58:53 +0800 Subject: ARM: dts: aspeed: x4tf: Add dts for asus x4tf project Base on aspeed-g6.dtsi and can boot into BMC console. Signed-off-by: Kelly Hung Reviewed-by: Andrew Jeffery Link: https://lore.kernel.org/r/20240430045853.3894633-3-Kelly_Hung@asus.com Signed-off-by: Joel Stanley --- arch/arm/boot/dts/aspeed/Makefile | 1 + arch/arm/boot/dts/aspeed/aspeed-bmc-asus-x4tf.dts | 581 ++++++++++++++++++++++ 2 files changed, 582 insertions(+) create mode 100644 arch/arm/boot/dts/aspeed/aspeed-bmc-asus-x4tf.dts diff --git a/arch/arm/boot/dts/aspeed/Makefile b/arch/arm/boot/dts/aspeed/Makefile index acc725cc561e..391f0bfa75ce 100644 --- a/arch/arm/boot/dts/aspeed/Makefile +++ b/arch/arm/boot/dts/aspeed/Makefile @@ -12,6 +12,7 @@ dtb-$(CONFIG_ARCH_ASPEED) += \ aspeed-bmc-asrock-romed8hm3.dtb \ aspeed-bmc-asrock-spc621d8hm3.dtb \ aspeed-bmc-asrock-x570d4u.dtb \ + aspeed-bmc-asus-x4tf.dtb \ aspeed-bmc-bytedance-g220a.dtb \ aspeed-bmc-delta-ahe50dc.dtb \ aspeed-bmc-facebook-bletchley.dtb \ diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-asus-x4tf.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-asus-x4tf.dts new file mode 100644 index 000000000000..64f4ed07c7d2 --- /dev/null +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-asus-x4tf.dts @@ -0,0 +1,581 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright 2024 ASUS Corp. + +/dts-v1/; + +#include "aspeed-g6.dtsi" +#include "aspeed-g6-pinctrl.dtsi" +#include +#include + +/ { + model = "ASUS-X4TF"; + compatible = "asus,x4tf-bmc", "aspeed,ast2600"; + + aliases { + serial4 = &uart5; + }; + + chosen { + stdout-path = "serial4:115200n8"; + }; + + memory@80000000 { + device_type = "memory"; + reg = <0x80000000 0x40000000>; + }; + + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + video_engine_memory: video { + size = <0x04000000>; + alignment = <0x01000000>; + compatible = "shared-dma-pool"; + reusable; + }; + }; + + iio-hwmon { + compatible = "iio-hwmon"; + io-channels = <&adc0 0>, <&adc0 1>, <&adc0 2>, <&adc0 3>, + <&adc0 4>, <&adc0 5>, <&adc0 6>, <&adc0 7>, + <&adc1 0>, <&adc1 1>, <&adc1 2>, <&adc1 3>, + <&adc1 4>, <&adc1 5>, <&adc1 6>, <&adc1 7>; + }; + + leds { + compatible = "gpio-leds"; + + led-heartbeat { + gpios = <&gpio0 ASPEED_GPIO(P, 7) GPIO_ACTIVE_LOW>; + linux,default-trigger = "heartbeat"; + }; + + led-uid { + gpios = <&gpio0 ASPEED_GPIO(P, 1) (GPIO_ACTIVE_LOW | GPIO_OPEN_DRAIN)>; + default-state = "off"; + }; + + led-status_Y { + gpios = <&gpio1 ASPEED_GPIO(B, 1) GPIO_ACTIVE_LOW>; + default-state = "off"; + }; + + led-sys_boot_status { + gpios = <&gpio1 ASPEED_GPIO(B, 0) GPIO_ACTIVE_LOW>; + default-state = "off"; + }; + }; +}; + +&adc0 { + vref = <2500>; + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_adc0_default &pinctrl_adc1_default + &pinctrl_adc2_default &pinctrl_adc3_default + &pinctrl_adc4_default &pinctrl_adc5_default + &pinctrl_adc6_default &pinctrl_adc7_default>; +}; + +&adc1 { + vref = <2500>; + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_adc8_default &pinctrl_adc9_default + &pinctrl_adc10_default &pinctrl_adc11_default + &pinctrl_adc12_default &pinctrl_adc13_default + &pinctrl_adc14_default &pinctrl_adc15_default>; +}; + +&peci0 { + status = "okay"; +}; + +&lpc_snoop { + snoop-ports = <0x80>; + status = "okay"; +}; + +&mac2 { + status = "okay"; + phy-mode = "rmii"; + use-ncsi; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_rmii3_default>; +}; + +&mac3 { + status = "okay"; + phy-mode = "rmii"; + use-ncsi; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_rmii4_default>; +}; + +&fmc { + status = "okay"; + + flash@0 { + status = "okay"; + m25p,fast-read; + label = "bmc"; + spi-max-frequency = <50000000>; +#include "openbmc-flash-layout-64.dtsi" + }; +}; + +&spi1 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_spi1_default>; + + flash@0 { + status = "okay"; + label = "bios"; + spi-max-frequency = <50000000>; + }; +}; + +&i2c0 { + status = "okay"; +}; + +&i2c1 { + status = "okay"; +}; + +&i2c2 { + status = "okay"; +}; + +&i2c3 { + status = "okay"; +}; + +&i2c4 { + status = "okay"; + + temperature-sensor@48 { + compatible = "ti,tmp75"; + reg = <0x48>; + }; + + temperature-sensor@49 { + compatible = "ti,tmp75"; + reg = <0x49>; + }; + + pca9555_4_20: gpio@20 { + compatible = "nxp,pca9555"; + reg = <0x20>; + gpio-controller; + #gpio-cells = <2>; + }; + + pca9555_4_22: gpio@22 { + compatible = "nxp,pca9555"; + reg = <0x22>; + gpio-controller; + #gpio-cells = <2>; + }; + + pca9555_4_24: gpio@24 { + compatible = "nxp,pca9555"; + reg = <0x24>; + gpio-controller; + #gpio-cells = <2>; + gpio-line-names = + /*A0 - A3 0*/ "", "STRAP_BMC_BATTERY_GPIO1", "", "", + /*A4 - A7 4*/ "", "", "", "", + /*B0 - B7 8*/ "", "", "", "", "", "", "", ""; + }; + + pca9555_4_26: gpio@26 { + compatible = "nxp,pca9555"; + reg = <0x26>; + gpio-controller; + #gpio-cells = <2>; + }; + + i2c-mux@70 { + compatible = "nxp,pca9546"; + status = "okay"; + reg = <0x70>; + #address-cells = <1>; + #size-cells = <0>; + + channel_1: i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + }; + + channel_2: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + }; + + channel_3: i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + }; + + channel_4: i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + }; + }; +}; + +&i2c5 { + status = "okay"; + + pca9555_5_24: gpio@24 { + compatible = "nxp,pca9555"; + reg = <0x24>; + gpio-controller; + #gpio-cells = <2>; + }; + + i2c-mux@70 { + compatible = "nxp,pca9546"; + status = "okay"; + reg = <0x70 >; + #address-cells = <1>; + #size-cells = <0>; + + channel_5: i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + + pca9555_5_5_20: gpio@20 { + compatible = "nxp,pca9555"; + reg = <0x20>; + gpio-controller; + #gpio-cells = <2>; + gpio-line-names = + "", "", "", "", "", "", "", "", + "", "", "SYS_FAN6", "SYS_FAN5", + "SYS_FAN4", "SYS_FAN3", + "SYS_FAN2", "SYS_FAN1"; + }; + + pca9555_5_5_21: gpio@21 { + compatible = "nxp,pca9555"; + reg = <0x21>; + gpio-controller; + #gpio-cells = <2>; + }; + + power-monitor@44 { + compatible = "ti,ina219"; + reg = <0x44>; + shunt-resistor = <2>; + }; + }; + + channel_6: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + }; + + channel_7: i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + }; + + channel_8: i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + }; + }; +}; + +&i2c6 { + status = "okay"; + + pca9555_6_27: gpio@27 { + compatible = "nxp,pca9555"; + reg = <0x27>; + gpio-controller; + #gpio-cells = <2>; + }; + + pca9555_6_20: gpio@20 { + compatible = "nxp,pca9555"; + reg = <0x20>; + gpio-controller; + #gpio-cells = <2>; + gpio-line-names = + /*A0 0*/ "", "", "", "", "", "", "", "", + /*B0 8*/ "Drive_NVMe1", "Drive_NVMe2", "", "", + /*B4 12*/ "", "", "", ""; + }; + + pca9555_6_21: gpio@21 { + compatible = "nxp,pca9555"; + reg = <0x21>; + gpio-controller; + #gpio-cells = <2>; + }; +}; + +&i2c7 { + status = "okay"; + + i2c-mux@70 { + compatible = "nxp,pca9546"; + status = "okay"; + reg = <0x70>; + #address-cells = <1>; + #size-cells = <0>; + idle-state = <1>; + + channel_9: i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + + temperature-sensor@48 { + compatible = "ti,tmp75"; + reg = <0x48>; + }; + + temperature-sensor@49 { + compatible = "ti,tmp75"; + reg = <0x49>; + }; + + power-monitor@40 { + compatible = "ti,ina219"; + reg = <0x40>; + shunt-resistor = <2>; + }; + + power-monitor@41 { + compatible = "ti,ina219"; + reg = <0x41>; + shunt-resistor = <5>; + }; + }; + + channel_10: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + }; + + channel_11: i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + }; + + channel_12: i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + }; + }; + + i2c-mux@71 { + compatible = "nxp,pca9546"; + status = "okay"; + reg = <0x71>; + #address-cells = <1>; + #size-cells = <0>; + i2c-mux-idle-disconnect; + + channel_13: i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + }; + + channel_14: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + }; + + channel_15: i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + }; + + channel_16: i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + }; + }; +}; + +&i2c8 { + status = "okay"; + + i2c-mux@70 { + compatible = "nxp,pca9546"; + status = "okay"; + reg = <0x70>; + #address-cells = <1>; + #size-cells = <0>; + i2c-mux-idle-disconnect; + + channel_17: i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + }; + + channel_18: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + + temperature-sensor@48 { + compatible = "ti,tmp75"; + reg = <0x48>; + }; + + power-monitor@41 { + compatible = "ti,ina219"; + reg = <0x41>; + shunt-resistor = <5>; + }; + }; + + channel_19: i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + }; + + channel_20: i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + }; + }; +}; + +&i2c9 { + status = "okay"; +}; + +&i2c10 { + status = "okay"; +}; + +&i2c11 { + status = "okay"; +}; + +&i2c14 { + status = "okay"; + multi-master; + + eeprom@50 { + compatible = "atmel,24c08"; + reg = <0x50>; + }; + + eeprom@51 { + compatible = "atmel,24c08"; + reg = <0x51>; + }; +}; + +&sgpiom0 { + status = "okay"; + ngpios = <128>; +}; + +&video { + status = "okay"; + memory-region = <&video_engine_memory>; +}; + +&sdc { + status = "okay"; +}; + +&lpc_snoop { + status = "okay"; + snoop-ports = <0x80>; +}; + +&kcs1 { + aspeed,lpc-io-reg = <0xca0>; + status = "okay"; +}; + +&kcs2 { + aspeed,lpc-io-reg = <0xca8>; + status = "okay"; +}; + +&kcs3 { + aspeed,lpc-io-reg = <0xca2>; + status = "okay"; +}; + +&uart3 { + status = "okay"; +}; + +&uart5 { + status = "okay"; +}; + +&uart_routing { + status = "okay"; +}; + +&vhub { + status = "okay"; +}; + +&gpio0 { + gpio-line-names = + /*A0 0*/ "", "", "", "", "", "", "", "", + /*B0 8*/ "", "", "", "", "", "", "PS_PWROK", "", + /*C0 16*/ "", "", "", "", "", "", "", "", + /*D0 24*/ "", "", "", "", "", "", "", "", + /*E0 32*/ "", "", "", "", "", "", "", "", + /*F0 40*/ "", "", "", "", "", "", "", "", + /*G0 48*/ "", "", "", "", "", "", "", "", + /*H0 56*/ "", "", "", "", "", "", "", "", + /*I0 64*/ "", "", "", "", "", "", "", "", + /*J0 72*/ "", "", "", "", "", "", "", "", + /*K0 80*/ "", "", "", "", "", "", "", "", + /*L0 88*/ "", "", "", "", "", "", "", "", + /*M0 96*/ "", "", "", "", "", "", "", "", + /*N0 104*/ "", "", "", "", + /*N4 108*/ "POST_COMPLETE", "ESR1_GPIO_AST_SPISEL", "", "", + /*O0 112*/ "", "", "", "", "", "", "", "", + /*P0 120*/ "ID_BUTTON", "ID_OUT", "POWER_BUTTON", "POWER_OUT", + /*P4 124*/ "RESET_BUTTON", "RESET_OUT", "", "HEARTBEAT", + /*Q0 128*/ "", "", "", "", "", "", "", "", + /*R0 136*/ "", "", "", "", "", "", "", "", + /*S0 144*/ "", "", "", "", "", "", "", "", + /*T0 152*/ "", "", "", "", "", "", "", "", + /*U0 160*/ "", "", "", "", "", "", "", "", + /*V0 168*/ "", "", "", "", "", "", "", "", + /*W0 176*/ "", "", "", "", "", "", "", "", + /*X0 184*/ "", "", "", "", "", "", "", "", + /*Y0 192*/ "", "", "", "", "", "", "", "", + /*Z0 200*/ "", "", "", "", "", "", "", ""; +}; -- cgit v1.2.3-59-g8ed1b From 63a1f8454962a64746a59441687dc2401290326c Mon Sep 17 00:00:00 2001 From: Mathias Nyman Date: Mon, 29 Apr 2024 17:02:28 +0300 Subject: xhci: stored cached port capability values in one place Port capability flags for USB2 ports have been cached in an u32 xhci->ext_caps[] array long before the driver had struct xhci_port and struct xhci_port_cap structures. Move these cached USB2 port capability values together with the other port capability values into struct xhci_port_cap cability structure. This also gets rid of the cumbersome way of mapping port to USB2 capability based on portnum as each port has a pointer to its capability structure. Signed-off-by: Mathias Nyman Link: https://lore.kernel.org/r/20240429140245.3955523-2-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-mem.c | 12 +----------- drivers/usb/host/xhci.c | 19 +++++-------------- drivers/usb/host/xhci.h | 4 +--- 3 files changed, 7 insertions(+), 28 deletions(-) diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 69dd86669883..7ff2ff29b48e 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -1950,7 +1950,6 @@ no_bw: kfree(xhci->usb3_rhub.ports); kfree(xhci->hw_ports); kfree(xhci->rh_bw); - kfree(xhci->ext_caps); for (i = 0; i < xhci->num_port_caps; i++) kfree(xhci->port_caps[i].psi); kfree(xhci->port_caps); @@ -1961,7 +1960,6 @@ no_bw: xhci->usb3_rhub.ports = NULL; xhci->hw_ports = NULL; xhci->rh_bw = NULL; - xhci->ext_caps = NULL; xhci->port_caps = NULL; xhci->interrupters = NULL; @@ -2089,10 +2087,7 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports, port_cap->maj_rev = major_revision; port_cap->min_rev = minor_revision; - - /* cache usb2 port capabilities */ - if (major_revision < 0x03 && xhci->num_ext_caps < max_caps) - xhci->ext_caps[xhci->num_ext_caps++] = temp; + port_cap->protocol_caps = temp; if ((xhci->hci_version >= 0x100) && (major_revision != 0x03) && (temp & XHCI_HLC)) { @@ -2212,11 +2207,6 @@ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags) XHCI_EXT_CAPS_PROTOCOL); } - xhci->ext_caps = kcalloc_node(cap_count, sizeof(*xhci->ext_caps), - flags, dev_to_node(dev)); - if (!xhci->ext_caps) - return -ENOMEM; - xhci->port_caps = kcalloc_node(cap_count, sizeof(*xhci->port_caps), flags, dev_to_node(dev)); if (!xhci->port_caps) diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 8579603edaff..7f07672d4110 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -4511,23 +4511,14 @@ static int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd, * only USB2 ports extended protocol capability values are cached. * Return 1 if capability is supported */ -static int xhci_check_usb2_port_capability(struct xhci_hcd *xhci, int port, +static bool xhci_check_usb2_port_capability(struct xhci_hcd *xhci, int portnum, unsigned capability) { - u32 port_offset, port_count; - int i; + struct xhci_port *port; - for (i = 0; i < xhci->num_ext_caps; i++) { - if (xhci->ext_caps[i] & capability) { - /* port offsets starts at 1 */ - port_offset = XHCI_EXT_PORT_OFF(xhci->ext_caps[i]) - 1; - port_count = XHCI_EXT_PORT_COUNT(xhci->ext_caps[i]); - if (port >= port_offset && - port < port_offset + port_count) - return 1; - } - } - return 0; + port = xhci->usb2_rhub.ports[portnum]; + + return !!(port->port_cap->protocol_caps & capability); } static int xhci_update_device(struct usb_hcd *hcd, struct usb_device *udev) diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 6f4bf98a6282..1c9519205330 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1451,6 +1451,7 @@ struct xhci_port_cap { u8 psi_uid_count; u8 maj_rev; u8 min_rev; + u32 protocol_caps; }; struct xhci_port { @@ -1640,9 +1641,6 @@ struct xhci_hcd { unsigned broken_suspend:1; /* Indicates that omitting hcd is supported if root hub has no ports */ unsigned allow_single_roothub:1; - /* cached usb2 extened protocol capabilites */ - u32 *ext_caps; - unsigned int num_ext_caps; /* cached extended protocol port capabilities */ struct xhci_port_cap *port_caps; unsigned int num_port_caps; -- cgit v1.2.3-59-g8ed1b From 6d3bc5e941bf94947937281b20c17cc80202de8b Mon Sep 17 00:00:00 2001 From: Mathias Nyman Date: Mon, 29 Apr 2024 17:02:29 +0300 Subject: xhci: remove xhci_check_usb2_port_capability helper This helper was only called from one function. Removing it both reduces lines of code and made it more readable. Signed-off-by: Mathias Nyman Link: https://lore.kernel.org/r/20240429140245.3955523-3-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci.c | 29 ++++++++--------------------- 1 file changed, 8 insertions(+), 21 deletions(-) diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 7f07672d4110..37eb37b0affa 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -4507,26 +4507,13 @@ static int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd, return 0; } -/* check if a usb2 port supports a given extened capability protocol - * only USB2 ports extended protocol capability values are cached. - * Return 1 if capability is supported - */ -static bool xhci_check_usb2_port_capability(struct xhci_hcd *xhci, int portnum, - unsigned capability) -{ - struct xhci_port *port; - - port = xhci->usb2_rhub.ports[portnum]; - - return !!(port->port_cap->protocol_caps & capability); -} - static int xhci_update_device(struct usb_hcd *hcd, struct usb_device *udev) { struct xhci_hcd *xhci = hcd_to_xhci(hcd); - int portnum = udev->portnum - 1; + struct xhci_port *port; + u32 capability; - if (hcd->speed >= HCD_USB3 || !udev->lpm_capable) + if (hcd->speed >= HCD_USB3 || !udev->lpm_capable || !xhci->hw_lpm_support) return 0; /* we only support lpm for non-hub device connected to root hub yet */ @@ -4534,14 +4521,14 @@ static int xhci_update_device(struct usb_hcd *hcd, struct usb_device *udev) udev->descriptor.bDeviceClass == USB_CLASS_HUB) return 0; - if (xhci->hw_lpm_support == 1 && - xhci_check_usb2_port_capability( - xhci, portnum, XHCI_HLC)) { + port = xhci->usb2_rhub.ports[udev->portnum - 1]; + capability = port->port_cap->protocol_caps; + + if (capability & XHCI_HLC) { udev->usb2_hw_lpm_capable = 1; udev->l1_params.timeout = XHCI_L1_TIMEOUT; udev->l1_params.besl = XHCI_DEFAULT_BESL; - if (xhci_check_usb2_port_capability(xhci, portnum, - XHCI_BLC)) + if (capability & XHCI_BLC) udev->usb2_hw_lpm_besl_capable = 1; } -- cgit v1.2.3-59-g8ed1b From db4460b6ecf07574d580f01cd88054a62607068c Mon Sep 17 00:00:00 2001 From: Niklas Neronin Date: Mon, 29 Apr 2024 17:02:30 +0300 Subject: usb: xhci: check if 'requested segments' exceeds ERST capacity Check if requested segments ('segs' or 'ERST_DEFAULT_SEGS') exceeds the maximum amount ERST supports. When 'segs' is '0', 'ERST_DEFAULT_SEGS' is used instead. But both values may not exceed ERST max. Macro 'ERST_MAX_SEGS' is renamed to 'ERST_DEFAULT_SEGS'. The new name better represents the macros, which is the number of Event Ring segments to allocate, when the amount is not specified. Additionally, rename and change xhci_create_secondary_interrupter()'s argument 'int num_segs' to 'unsigned int segs'. This makes it the same as its counter part in xhci_alloc_interrupter(). Fixes: c99b38c41234 ("xhci: add support to allocate several interrupters") Signed-off-by: Niklas Neronin Signed-off-by: Mathias Nyman Link: https://lore.kernel.org/r/20240429140245.3955523-4-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-mem.c | 22 +++++++++++----------- drivers/usb/host/xhci.h | 6 +++--- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 7ff2ff29b48e..1a16b44506da 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -2259,24 +2259,24 @@ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags) } static struct xhci_interrupter * -xhci_alloc_interrupter(struct xhci_hcd *xhci, int segs, gfp_t flags) +xhci_alloc_interrupter(struct xhci_hcd *xhci, unsigned int segs, gfp_t flags) { struct device *dev = xhci_to_hcd(xhci)->self.sysdev; struct xhci_interrupter *ir; - unsigned int num_segs = segs; + unsigned int max_segs; int ret; + if (!segs) + segs = ERST_DEFAULT_SEGS; + + max_segs = BIT(HCS_ERST_MAX(xhci->hcs_params2)); + segs = min(segs, max_segs); + ir = kzalloc_node(sizeof(*ir), flags, dev_to_node(dev)); if (!ir) return NULL; - /* number of ring segments should be greater than 0 */ - if (segs <= 0) - num_segs = min_t(unsigned int, 1 << HCS_ERST_MAX(xhci->hcs_params2), - ERST_MAX_SEGS); - - ir->event_ring = xhci_ring_alloc(xhci, num_segs, 1, TYPE_EVENT, 0, - flags); + ir->event_ring = xhci_ring_alloc(xhci, segs, 1, TYPE_EVENT, 0, flags); if (!ir->event_ring) { xhci_warn(xhci, "Failed to allocate interrupter event ring\n"); kfree(ir); @@ -2334,7 +2334,7 @@ xhci_add_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir, } struct xhci_interrupter * -xhci_create_secondary_interrupter(struct usb_hcd *hcd, int num_seg) +xhci_create_secondary_interrupter(struct usb_hcd *hcd, unsigned int segs) { struct xhci_hcd *xhci = hcd_to_xhci(hcd); struct xhci_interrupter *ir; @@ -2344,7 +2344,7 @@ xhci_create_secondary_interrupter(struct usb_hcd *hcd, int num_seg) if (!xhci->interrupters || xhci->max_interrupters <= 1) return NULL; - ir = xhci_alloc_interrupter(xhci, num_seg, GFP_KERNEL); + ir = xhci_alloc_interrupter(xhci, segs, GFP_KERNEL); if (!ir) return NULL; diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 1c9519205330..8a3ae5049d1c 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1392,8 +1392,8 @@ struct urb_priv { struct xhci_td td[] __counted_by(num_tds); }; -/* Reasonable limit for number of Event Ring segments (spec allows 32k) */ -#define ERST_MAX_SEGS 2 +/* Number of Event Ring segments to allocate, when amount is not specified. (spec allows 32k) */ +#define ERST_DEFAULT_SEGS 2 /* Poll every 60 seconds */ #define POLL_TIMEOUT 60 /* Stop endpoint command timeout (secs) for URB cancellation watchdog timer */ @@ -1831,7 +1831,7 @@ struct xhci_container_ctx *xhci_alloc_container_ctx(struct xhci_hcd *xhci, void xhci_free_container_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx); struct xhci_interrupter * -xhci_create_secondary_interrupter(struct usb_hcd *hcd, int num_seg); +xhci_create_secondary_interrupter(struct usb_hcd *hcd, unsigned int segs); void xhci_remove_secondary_interrupter(struct usb_hcd *hcd, struct xhci_interrupter *ir); -- cgit v1.2.3-59-g8ed1b From 577c867cf8f638b05f5676ed06a1ffe9afbba896 Mon Sep 17 00:00:00 2001 From: Niklas Neronin Date: Mon, 29 Apr 2024 17:02:31 +0300 Subject: usb: xhci: improve debug message in xhci_ring_expansion_needed() Address debug message inaccuracies in xhci_ring_expansion_needed(). Specifically, remove the portion of the debug message that indicates the number of enqueue TRBs to be added to the dequeue segment. This part of the message may mislead and the calculated value is incorrect. Given that this value is not of significant importance and the statement is not consistently accurate, it has been omitted. The specific issues with the debug message that this commit resolves: - The calculation of the number of TRBs is incorrect. The current calculation erroneously includes the link TRB, which is reserved. Furthermore, the calculated number of TRBs can exceed the dequeue segment, resulting in a misleading debug message. - The current phrasing suggests that "ring expansion by X is needed, adding X TRBs moves enqueue Y TRBs into the dequeue segment". The intended message, however, is "IF the ring is NOT expanded by X, THEN adding X TRBs moves enqueue Y TRBs into the dequeue segment". Signed-off-by: Niklas Neronin Signed-off-by: Mathias Nyman Link: https://lore.kernel.org/r/20240429140245.3955523-5-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-ring.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 575f0fd9c9f1..3cc5c70d54c7 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -351,10 +351,8 @@ static unsigned int xhci_ring_expansion_needed(struct xhci_hcd *xhci, struct xhc while (new_segs > 0) { seg = seg->next; if (seg == ring->deq_seg) { - xhci_dbg(xhci, "Ring expansion by %d segments needed\n", - new_segs); - xhci_dbg(xhci, "Adding %d trbs moves enq %d trbs into deq seg\n", - num_trbs, trbs_past_seg % TRBS_PER_SEGMENT); + xhci_dbg(xhci, "Adding %d trbs requires expanding ring by %d segments\n", + num_trbs, new_segs); return new_segs; } new_segs--; -- cgit v1.2.3-59-g8ed1b From 5adc1cc038f4446b11dd260e0a848fdeaac12306 Mon Sep 17 00:00:00 2001 From: Niklas Neronin Date: Mon, 29 Apr 2024 17:02:32 +0300 Subject: usb: xhci: address off-by-one in xhci_num_trbs_free() Reduce the number of do-while loops by 1. The number of loops should be number of segment + 1, the +1 is in case deq and enq are on the same segment. But due to the use of a do-while loop, the expression is evaluated after executing the loop, thus the loop is executed 1 extra time. Changing the do-while loop expression from "<=" to "<", reduces the loop amount by 1. The expression "<=" would also work if it was a while loop instead of a do-while loop. Signed-off-by: Niklas Neronin Signed-off-by: Mathias Nyman Link: https://lore.kernel.org/r/20240429140245.3955523-6-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-ring.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 3cc5c70d54c7..0a7c70ae5edc 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -308,7 +308,7 @@ static unsigned int xhci_num_trbs_free(struct xhci_hcd *xhci, struct xhci_ring * free += last_on_seg - enq; enq_seg = enq_seg->next; enq = enq_seg->trbs; - } while (i++ <= ring->num_segs); + } while (i++ < ring->num_segs); return free; } -- cgit v1.2.3-59-g8ed1b From 7e2bd7dd80841729993ca6903dbf58b3b2b2b565 Mon Sep 17 00:00:00 2001 From: Niklas Neronin Date: Mon, 29 Apr 2024 17:02:33 +0300 Subject: usb: xhci: remove redundant variable 'erst_size' 'erst_size' represents the maximum capacity of entries that ERST can hold, while 'num_entries' indicates the actual number of entries currently held in the ERST. These two values are identical because the xhci driver does not support ERST expansion. Thus, 'erst_size' is removed. Suggested-by: Mathias Nyman Signed-off-by: Niklas Neronin Signed-off-by: Mathias Nyman Link: https://lore.kernel.org/r/20240429140245.3955523-7-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-dbgcap.c | 2 +- drivers/usb/host/xhci.h | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/usb/host/xhci-dbgcap.c b/drivers/usb/host/xhci-dbgcap.c index 8a9869ef0db6..872d9cddbcef 100644 --- a/drivers/usb/host/xhci-dbgcap.c +++ b/drivers/usb/host/xhci-dbgcap.c @@ -516,7 +516,7 @@ static int xhci_dbc_mem_init(struct xhci_dbc *dbc, gfp_t flags) goto string_fail; /* Setup ERST register: */ - writel(dbc->erst.erst_size, &dbc->regs->ersts); + writel(dbc->erst.num_entries, &dbc->regs->ersts); lo_hi_writeq(dbc->erst.erst_dma_addr, &dbc->regs->erstba); deq = xhci_trb_virt_to_dma(dbc->ring_evt->deq_seg, diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 8a3ae5049d1c..10805196e197 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1376,8 +1376,6 @@ struct xhci_erst { unsigned int num_entries; /* xhci->event_ring keeps track of segment dma addresses */ dma_addr_t erst_dma_addr; - /* Num entries the ERST can contain */ - unsigned int erst_size; }; struct xhci_scratchpad { -- cgit v1.2.3-59-g8ed1b From 0c9595089432c152640aa75cf14e76d5510965f4 Mon Sep 17 00:00:00 2001 From: Niklas Neronin Date: Mon, 29 Apr 2024 17:02:34 +0300 Subject: usb: xhci: use array_size() when allocating and freeing memory Replace size_mul() with array_size() in memory allocation and freeing processes, it fits better semantically. Macro array_size() is identical to size_mult(), which clamps the max size, so it's imperative that array_size() is used when freeing said memory. Suggested-by: Andy Shevchenko Reviewed-by: Andy Shevchenko Signed-off-by: Niklas Neronin Signed-off-by: Mathias Nyman Link: https://lore.kernel.org/r/20240429140245.3955523-8-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-mem.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 1a16b44506da..3100219d6496 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -536,7 +536,7 @@ static void xhci_free_stream_ctx(struct xhci_hcd *xhci, struct xhci_stream_ctx *stream_ctx, dma_addr_t dma) { struct device *dev = xhci_to_hcd(xhci)->self.sysdev; - size_t size = sizeof(struct xhci_stream_ctx) * num_stream_ctxs; + size_t size = array_size(sizeof(struct xhci_stream_ctx), num_stream_ctxs); if (size > MEDIUM_STREAM_ARRAY_SIZE) dma_free_coherent(dev, size, stream_ctx, dma); @@ -561,7 +561,7 @@ static struct xhci_stream_ctx *xhci_alloc_stream_ctx(struct xhci_hcd *xhci, gfp_t mem_flags) { struct device *dev = xhci_to_hcd(xhci)->self.sysdev; - size_t size = size_mul(sizeof(struct xhci_stream_ctx), num_stream_ctxs); + size_t size = array_size(sizeof(struct xhci_stream_ctx), num_stream_ctxs); if (size > MEDIUM_STREAM_ARRAY_SIZE) return dma_alloc_coherent(dev, size, dma, mem_flags); @@ -1638,7 +1638,7 @@ static int scratchpad_alloc(struct xhci_hcd *xhci, gfp_t flags) goto fail_sp; xhci->scratchpad->sp_array = dma_alloc_coherent(dev, - size_mul(sizeof(u64), num_sp), + array_size(sizeof(u64), num_sp), &xhci->scratchpad->sp_dma, flags); if (!xhci->scratchpad->sp_array) goto fail_sp2; @@ -1671,7 +1671,7 @@ static int scratchpad_alloc(struct xhci_hcd *xhci, gfp_t flags) kfree(xhci->scratchpad->sp_buffers); fail_sp3: - dma_free_coherent(dev, num_sp * sizeof(u64), + dma_free_coherent(dev, array_size(sizeof(u64), num_sp), xhci->scratchpad->sp_array, xhci->scratchpad->sp_dma); @@ -1700,7 +1700,7 @@ static void scratchpad_free(struct xhci_hcd *xhci) xhci->scratchpad->sp_array[i]); } kfree(xhci->scratchpad->sp_buffers); - dma_free_coherent(dev, num_sp * sizeof(u64), + dma_free_coherent(dev, array_size(sizeof(u64), num_sp), xhci->scratchpad->sp_array, xhci->scratchpad->sp_dma); kfree(xhci->scratchpad); @@ -1778,7 +1778,7 @@ static int xhci_alloc_erst(struct xhci_hcd *xhci, struct xhci_segment *seg; struct xhci_erst_entry *entry; - size = size_mul(sizeof(struct xhci_erst_entry), evt_ring->num_segs); + size = array_size(sizeof(struct xhci_erst_entry), evt_ring->num_segs); erst->entries = dma_alloc_coherent(xhci_to_hcd(xhci)->self.sysdev, size, &erst->erst_dma_addr, flags); if (!erst->entries) @@ -1829,7 +1829,7 @@ xhci_free_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir) if (!ir) return; - erst_size = sizeof(struct xhci_erst_entry) * ir->erst.num_entries; + erst_size = array_size(sizeof(struct xhci_erst_entry), ir->erst.num_entries); if (ir->erst.entries) dma_free_coherent(dev, erst_size, ir->erst.entries, -- cgit v1.2.3-59-g8ed1b From 15a27970e5f3d802fa7ed12410821f01c8a4d8f8 Mon Sep 17 00:00:00 2001 From: Mathias Nyman Date: Mon, 29 Apr 2024 17:02:35 +0300 Subject: xhci: improve PORTSC register debugging output Print the full hex value of PORTSC register in addition to the human readable decoded string while debugging PORTSC value. If PORTSC value is 0xffffffff then don't decode it. This lets us inspect Rsvd bits of PORTSC. Same is done for USBSTS register values. Signed-off-by: Mathias Nyman Link: https://lore.kernel.org/r/20240429140245.3955523-9-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 10805196e197..8c96dd6ef3d4 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -2336,7 +2336,12 @@ static inline const char *xhci_decode_portsc(char *str, u32 portsc) { int ret; - ret = sprintf(str, "%s %s %s Link:%s PortSpeed:%d ", + ret = sprintf(str, "0x%08x ", portsc); + + if (portsc == ~(u32)0) + return str; + + ret += sprintf(str + ret, "%s %s %s Link:%s PortSpeed:%d ", portsc & PORT_POWER ? "Powered" : "Powered-off", portsc & PORT_CONNECT ? "Connected" : "Not-connected", portsc & PORT_PE ? "Enabled" : "Disabled", -- cgit v1.2.3-59-g8ed1b From 34b67198244f2d7d8409fa4eb76204c409c0c97e Mon Sep 17 00:00:00 2001 From: Mathias Nyman Date: Mon, 29 Apr 2024 17:02:36 +0300 Subject: xhci: remove XHCI_TRUST_TX_LENGTH quirk If this quirk was set then driver would treat transfer events with 'Success' completion code as 'Short packet' if there were untransferred bytes left. This is so common that turn it into default behavior. xhci_warn_ratelimited() is no longer used after this, so remove it. A success event with untransferred bytes left doesn't always mean a misbehaving controller. If there was an error mid a multi-TRB TD it's allowed to issue a success event for the last TRB in that TD. See xhci 1.2 spec 4.9.1 Transfer Descriptors "Note: If an error is detected while processing a multi-TRB TD, the xHC shall generate a Transfer Event for the TRB that the error was detected on with the appropriate error Condition Code, then may advance to the next TD. If in the process of advancing to the next TD, a Transfer TRB is encountered with its IOC flag set, then the Condition Code of the Transfer Event generated for that Transfer TRB should be Success, because there was no error actually associated with the TRB that generated the Event. However, an xHC implementation may redundantly assert the original error Condition Code." Co-developed-by: Niklas Neronin Signed-off-by: Niklas Neronin Signed-off-by: Mathias Nyman Link: https://lore.kernel.org/r/20240429140245.3955523-10-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-pci.c | 15 ++------------- drivers/usb/host/xhci-rcar.c | 6 ++---- drivers/usb/host/xhci-ring.c | 15 +++++---------- drivers/usb/host/xhci.h | 4 +--- 4 files changed, 10 insertions(+), 30 deletions(-) diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index 93b697648018..653b47c45591 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -270,17 +270,12 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) "QUIRK: Fresco Logic revision %u " "has broken MSI implementation", pdev->revision); - xhci->quirks |= XHCI_TRUST_TX_LENGTH; } if (pdev->vendor == PCI_VENDOR_ID_FRESCO_LOGIC && pdev->device == PCI_DEVICE_ID_FRESCO_LOGIC_FL1009) xhci->quirks |= XHCI_BROKEN_STREAMS; - if (pdev->vendor == PCI_VENDOR_ID_FRESCO_LOGIC && - pdev->device == PCI_DEVICE_ID_FRESCO_LOGIC_FL1100) - xhci->quirks |= XHCI_TRUST_TX_LENGTH; - if (pdev->vendor == PCI_VENDOR_ID_NEC) xhci->quirks |= XHCI_NEC_HOST; @@ -307,11 +302,8 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) xhci->quirks |= XHCI_RESET_ON_RESUME; } - if (pdev->vendor == PCI_VENDOR_ID_AMD) { - xhci->quirks |= XHCI_TRUST_TX_LENGTH; - if (pdev->device == 0x43f7) - xhci->quirks |= XHCI_DEFAULT_PM_RUNTIME_ALLOW; - } + if (pdev->vendor == PCI_VENDOR_ID_AMD && pdev->device == 0x43f7) + xhci->quirks |= XHCI_DEFAULT_PM_RUNTIME_ALLOW; if ((pdev->vendor == PCI_VENDOR_ID_AMD) && ((pdev->device == PCI_DEVICE_ID_AMD_PROMONTORYA_4) || @@ -399,12 +391,10 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) if (pdev->vendor == PCI_VENDOR_ID_ETRON && pdev->device == PCI_DEVICE_ID_EJ168) { xhci->quirks |= XHCI_RESET_ON_RESUME; - xhci->quirks |= XHCI_TRUST_TX_LENGTH; xhci->quirks |= XHCI_BROKEN_STREAMS; } if (pdev->vendor == PCI_VENDOR_ID_RENESAS && pdev->device == 0x0014) { - xhci->quirks |= XHCI_TRUST_TX_LENGTH; xhci->quirks |= XHCI_ZERO_64B_REGS; } if (pdev->vendor == PCI_VENDOR_ID_RENESAS && @@ -434,7 +424,6 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) } if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA && pdev->device == PCI_DEVICE_ID_ASMEDIA_1042A_XHCI) { - xhci->quirks |= XHCI_TRUST_TX_LENGTH; xhci->quirks |= XHCI_NO_64BIT_SUPPORT; } if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA && diff --git a/drivers/usb/host/xhci-rcar.c b/drivers/usb/host/xhci-rcar.c index ab9c5969e462..8b357647728c 100644 --- a/drivers/usb/host/xhci-rcar.c +++ b/drivers/usb/host/xhci-rcar.c @@ -214,8 +214,7 @@ static int xhci_rcar_resume_quirk(struct usb_hcd *hcd) */ #define SET_XHCI_PLAT_PRIV_FOR_RCAR(firmware) \ .firmware_name = firmware, \ - .quirks = XHCI_NO_64BIT_SUPPORT | XHCI_TRUST_TX_LENGTH | \ - XHCI_SLOW_SUSPEND, \ + .quirks = XHCI_NO_64BIT_SUPPORT | XHCI_SLOW_SUSPEND, \ .init_quirk = xhci_rcar_init_quirk, \ .plat_start = xhci_rcar_start, \ .resume_quirk = xhci_rcar_resume_quirk, @@ -229,8 +228,7 @@ static const struct xhci_plat_priv xhci_plat_renesas_rcar_gen3 = { }; static const struct xhci_plat_priv xhci_plat_renesas_rzv2m = { - .quirks = XHCI_NO_64BIT_SUPPORT | XHCI_TRUST_TX_LENGTH | - XHCI_SLOW_SUSPEND, + .quirks = XHCI_NO_64BIT_SUPPORT | XHCI_SLOW_SUSPEND, .init_quirk = xhci_rzv2m_init_quirk, .plat_start = xhci_rzv2m_start, }; diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 0a7c70ae5edc..07c529e072c9 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -2397,8 +2397,7 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep, break; if (remaining) { frame->status = short_framestatus; - if (xhci->quirks & XHCI_TRUST_TX_LENGTH) - sum_trbs_for_length = true; + sum_trbs_for_length = true; break; } frame->status = 0; @@ -2648,15 +2647,11 @@ static int handle_tx_event(struct xhci_hcd *xhci, * transfer type */ case COMP_SUCCESS: - if (EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)) == 0) - break; - if (xhci->quirks & XHCI_TRUST_TX_LENGTH || - ep_ring->last_td_was_short) + if (EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)) != 0) { trb_comp_code = COMP_SHORT_PACKET; - else - xhci_warn_ratelimited(xhci, - "WARN Successful completion on short TX for slot %u ep %u: needs XHCI_TRUST_TX_LENGTH quirk?\n", - slot_id, ep_index); + xhci_dbg(xhci, "Successful completion on short TX for slot %u ep %u with last td short %d\n", + slot_id, ep_index, ep_ring->last_td_was_short); + } break; case COMP_SHORT_PACKET: break; diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 8c96dd6ef3d4..933f8a296014 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1588,7 +1588,7 @@ struct xhci_hcd { #define XHCI_RESET_ON_RESUME BIT_ULL(7) #define XHCI_SW_BW_CHECKING BIT_ULL(8) #define XHCI_AMD_0x96_HOST BIT_ULL(9) -#define XHCI_TRUST_TX_LENGTH BIT_ULL(10) +#define XHCI_TRUST_TX_LENGTH BIT_ULL(10) /* Deprecated */ #define XHCI_LPM_SUPPORT BIT_ULL(11) #define XHCI_INTEL_HOST BIT_ULL(12) #define XHCI_SPURIOUS_REBOOT BIT_ULL(13) @@ -1725,8 +1725,6 @@ static inline bool xhci_has_one_roothub(struct xhci_hcd *xhci) dev_err(xhci_to_hcd(xhci)->self.controller , fmt , ## args) #define xhci_warn(xhci, fmt, args...) \ dev_warn(xhci_to_hcd(xhci)->self.controller , fmt , ## args) -#define xhci_warn_ratelimited(xhci, fmt, args...) \ - dev_warn_ratelimited(xhci_to_hcd(xhci)->self.controller , fmt , ## args) #define xhci_info(xhci, fmt, args...) \ dev_info(xhci_to_hcd(xhci)->self.controller , fmt , ## args) -- cgit v1.2.3-59-g8ed1b From 66cb618bf0bb82859875b00eeffaf223557cb416 Mon Sep 17 00:00:00 2001 From: Niklas Neronin Date: Mon, 29 Apr 2024 17:02:37 +0300 Subject: usb: xhci: prevent potential failure in handle_tx_event() for Transfer events without TRB Some transfer events don't always point to a TRB, and consequently don't have a endpoint ring. In these cases, function handle_tx_event() should not proceed, because if 'ep->skip' is set, the pointer to the endpoint ring is used. To prevent a potential failure and make the code logical, return after checking the completion code for a Transfer event without TRBs. Signed-off-by: Niklas Neronin Signed-off-by: Mathias Nyman Link: https://lore.kernel.org/r/20240429140245.3955523-11-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-ring.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 07c529e072c9..00f48dd197ac 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -2625,16 +2625,17 @@ static int handle_tx_event(struct xhci_hcd *xhci, else xhci_handle_halted_endpoint(xhci, ep, NULL, EP_SOFT_RESET); - goto cleanup; + break; case COMP_RING_UNDERRUN: case COMP_RING_OVERRUN: case COMP_STOPPED_LENGTH_INVALID: - goto cleanup; + break; default: xhci_err(xhci, "ERROR Transfer event for unknown stream ring slot %u ep %u\n", slot_id, ep_index); goto err_out; } + return 0; } /* Count current td numbers if ep->skip is set */ -- cgit v1.2.3-59-g8ed1b From ae887586bb761508cb28212a3c805d76d0c4e499 Mon Sep 17 00:00:00 2001 From: Niklas Neronin Date: Mon, 29 Apr 2024 17:02:38 +0300 Subject: usb: xhci: remove 'handling_skipped_tds' from handle_tx_event() When handle_tx_event() encounters a COMP_MISSED_SERVICE_ERROR or COMP_NO_PING_RESPONSE_ERROR event, it moves to 'goto cleanup'. Here, it sets a flag, 'handling_skipped_tds', based on conditions that exclude these two error events. Subsequently, the process evaluates the loop that persists as long as 'handling_skipped_tds' remains true. However, since 'trb_comp_code' does not change after its assignment, if it indicates either of the two error conditions, the loop terminates immediately. To simplify this process and enhance clarity, the modification involves returning immediately upon detecting COMP_MISSED_SERVICE_ERROR or COMP_NO_PING_RESPONSE_ERROR. This adjustment allows for the direct use of 'ep->skip', removing the necessity for the 'handling_skipped_tds' flag. Signed-off-by: Niklas Neronin Signed-off-by: Mathias Nyman Link: https://lore.kernel.org/r/20240429140245.3955523-12-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-ring.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 00f48dd197ac..e96ac2d7b9b1 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -2587,7 +2587,6 @@ static int handle_tx_event(struct xhci_hcd *xhci, struct xhci_ep_ctx *ep_ctx; u32 trb_comp_code; int td_num = 0; - bool handling_skipped_tds = false; slot_id = TRB_TO_SLOT_ID(le32_to_cpu(event->flags)); ep_index = TRB_TO_EP_ID(le32_to_cpu(event->flags)) - 1; @@ -2748,13 +2747,13 @@ static int handle_tx_event(struct xhci_hcd *xhci, xhci_dbg(xhci, "Miss service interval error for slot %u ep %u, set skip flag\n", slot_id, ep_index); - goto cleanup; + return 0; case COMP_NO_PING_RESPONSE_ERROR: ep->skip = true; xhci_dbg(xhci, "No Ping response error for slot %u ep %u, Skip one Isoc TD\n", slot_id, ep_index); - goto cleanup; + return 0; case COMP_INCOMPATIBLE_DEVICE_ERROR: /* needs disable slot command to recover */ @@ -2939,18 +2938,14 @@ static int handle_tx_event(struct xhci_hcd *xhci, process_isoc_td(xhci, ep, ep_ring, td, ep_trb, event); else process_bulk_intr_td(xhci, ep, ep_ring, td, ep_trb, event); -cleanup: - handling_skipped_tds = ep->skip && - trb_comp_code != COMP_MISSED_SERVICE_ERROR && - trb_comp_code != COMP_NO_PING_RESPONSE_ERROR; - +cleanup:; /* * If ep->skip is set, it means there are missed tds on the * endpoint ring need to take care of. * Process them as short transfer until reach the td pointed by * the event. */ - } while (handling_skipped_tds); + } while (ep->skip); return 0; -- cgit v1.2.3-59-g8ed1b From 26dffa427f1841ead44bf56415e2c569df0b3a94 Mon Sep 17 00:00:00 2001 From: Niklas Neronin Date: Mon, 29 Apr 2024 17:02:39 +0300 Subject: usb: xhci: replace goto with return when possible in handle_tx_event() Simplifying the handle_tx_event() function by addressing the complexity of its while loop. Replaces specific 'goto cleanup' statements with 'return' statements, applicable only where 'ep->skip' is set to 'false', ensuring loop termination. The original while loop, combined with 'goto cleanup', adds unnecessary complexity. This change aims to untangle the loop's logic, facilitating a more straightforward review of the upcoming comprehensive rework. Signed-off-by: Niklas Neronin Signed-off-by: Mathias Nyman Link: https://lore.kernel.org/r/20240429140245.3955523-13-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-ring.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index e96ac2d7b9b1..0f48f9befc94 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -2804,7 +2804,7 @@ static int handle_tx_event(struct xhci_hcd *xhci, xhci_handle_halted_endpoint(xhci, ep, NULL, EP_HARD_RESET); } - goto cleanup; + return 0; } /* We've skipped all the TDs on the ep ring when ep->skip set */ @@ -2812,7 +2812,7 @@ static int handle_tx_event(struct xhci_hcd *xhci, ep->skip = false; xhci_dbg(xhci, "All tds on the ep_ring skipped. Clear skip flag for slot %u ep %u.\n", slot_id, ep_index); - goto cleanup; + return 0; } td = list_first_entry(&ep_ring->td_list, struct xhci_td, @@ -2851,7 +2851,7 @@ static int handle_tx_event(struct xhci_hcd *xhci, if ((xhci->quirks & XHCI_SPURIOUS_SUCCESS) && ep_ring->last_td_was_short) { ep_ring->last_td_was_short = false; - goto cleanup; + return 0; } /* -- cgit v1.2.3-59-g8ed1b From 608b973b70f87e9a9bafbfdfa16aab68507aef45 Mon Sep 17 00:00:00 2001 From: Niklas Neronin Date: Mon, 29 Apr 2024 17:02:40 +0300 Subject: usb: xhci: remove goto 'cleanup' in handle_tx_event() By removing the goto 'cleanup' statement, and replacing it with 'continue', 'break' and 'return', helps simplify the code and further showcase in which case the while loop iterates. This change prepares for the comprehensive handle_tx_event() rework. Signed-off-by: Niklas Neronin Signed-off-by: Mathias Nyman Link: https://lore.kernel.org/r/20240429140245.3955523-14-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-ring.c | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 0f48f9befc94..b395708c488c 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -2727,7 +2727,9 @@ static int handle_tx_event(struct xhci_hcd *xhci, "still with TDs queued?\n", TRB_TO_SLOT_ID(le32_to_cpu(event->flags)), ep_index); - goto cleanup; + if (ep->skip) + break; + return 0; case COMP_RING_OVERRUN: xhci_dbg(xhci, "overrun event on endpoint\n"); if (!list_empty(&ep_ring->td_list)) @@ -2735,7 +2737,9 @@ static int handle_tx_event(struct xhci_hcd *xhci, "still with TDs queued?\n", TRB_TO_SLOT_ID(le32_to_cpu(event->flags)), ep_index); - goto cleanup; + if (ep->skip) + break; + return 0; case COMP_MISSED_SERVICE_ERROR: /* * When encounter missed service error, one or more isoc tds @@ -2770,7 +2774,9 @@ static int handle_tx_event(struct xhci_hcd *xhci, xhci_warn(xhci, "ERROR Unknown event condition %u for slot %u ep %u , HC probably busted\n", trb_comp_code, slot_id, ep_index); - goto cleanup; + if (ep->skip) + break; + return 0; } do { @@ -2834,14 +2840,14 @@ static int handle_tx_event(struct xhci_hcd *xhci, */ if (!ep_seg && (trb_comp_code == COMP_STOPPED || trb_comp_code == COMP_STOPPED_LENGTH_INVALID)) { - goto cleanup; + continue; } if (!ep_seg) { if (ep->skip && usb_endpoint_xfer_isoc(&td->urb->ep->desc)) { skip_isoc_td(xhci, td, ep, status); - goto cleanup; + continue; } /* @@ -2926,19 +2932,17 @@ static int handle_tx_event(struct xhci_hcd *xhci, trb_comp_code)) xhci_handle_halted_endpoint(xhci, ep, td, EP_HARD_RESET); - goto cleanup; - } - - td->status = status; + } else { + td->status = status; - /* update the urb's actual_length and give back to the core */ - if (usb_endpoint_xfer_control(&td->urb->ep->desc)) - process_ctrl_td(xhci, ep, ep_ring, td, ep_trb, event); - else if (usb_endpoint_xfer_isoc(&td->urb->ep->desc)) - process_isoc_td(xhci, ep, ep_ring, td, ep_trb, event); - else - process_bulk_intr_td(xhci, ep, ep_ring, td, ep_trb, event); -cleanup:; + /* update the urb's actual_length and give back to the core */ + if (usb_endpoint_xfer_control(&td->urb->ep->desc)) + process_ctrl_td(xhci, ep, ep_ring, td, ep_trb, event); + else if (usb_endpoint_xfer_isoc(&td->urb->ep->desc)) + process_isoc_td(xhci, ep, ep_ring, td, ep_trb, event); + else + process_bulk_intr_td(xhci, ep, ep_ring, td, ep_trb, event); + } /* * If ep->skip is set, it means there are missed tds on the * endpoint ring need to take care of. -- cgit v1.2.3-59-g8ed1b From 64f5b51817fe0306f879c76b2817dceca88eac9a Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 29 Apr 2024 17:02:41 +0300 Subject: xhci: pci: Use full names in PCI IDs for Intel platforms There are three out of many Intel platforms that are using TLAs instead of the full names in the PCI IDs. Modify them accordingly. This also fixes the logic of grouping as seemed to be by an LSB byte of the ID. Signed-off-by: Andy Shevchenko Signed-off-by: Mathias Nyman Link: https://lore.kernel.org/r/20240429140245.3955523-15-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-pci.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index 653b47c45591..d45c84062b61 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -45,8 +45,7 @@ #define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_XHCI 0x9d2f #define PCI_DEVICE_ID_INTEL_BROXTON_M_XHCI 0x0aa8 #define PCI_DEVICE_ID_INTEL_BROXTON_B_XHCI 0x1aa8 -#define PCI_DEVICE_ID_INTEL_APL_XHCI 0x5aa8 -#define PCI_DEVICE_ID_INTEL_DNV_XHCI 0x19d0 +#define PCI_DEVICE_ID_INTEL_APOLLO_LAKE_XHCI 0x5aa8 #define PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_2C_XHCI 0x15b5 #define PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_4C_XHCI 0x15b6 #define PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_LP_XHCI 0x15c1 @@ -55,9 +54,10 @@ #define PCI_DEVICE_ID_INTEL_TITAN_RIDGE_2C_XHCI 0x15e9 #define PCI_DEVICE_ID_INTEL_TITAN_RIDGE_4C_XHCI 0x15ec #define PCI_DEVICE_ID_INTEL_TITAN_RIDGE_DD_XHCI 0x15f0 +#define PCI_DEVICE_ID_INTEL_DENVERTON_XHCI 0x19d0 #define PCI_DEVICE_ID_INTEL_ICE_LAKE_XHCI 0x8a13 -#define PCI_DEVICE_ID_INTEL_CML_XHCI 0xa3af #define PCI_DEVICE_ID_INTEL_TIGER_LAKE_XHCI 0x9a13 +#define PCI_DEVICE_ID_INTEL_COMET_LAKE_XHCI 0xa3af #define PCI_DEVICE_ID_INTEL_MAPLE_RIDGE_XHCI 0x1138 #define PCI_DEVICE_ID_INTEL_ALDER_LAKE_PCH_XHCI 0x51ed #define PCI_DEVICE_ID_INTEL_ALDER_LAKE_N_PCH_XHCI 0x54ed @@ -348,9 +348,9 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI || pdev->device == PCI_DEVICE_ID_INTEL_BROXTON_M_XHCI || pdev->device == PCI_DEVICE_ID_INTEL_BROXTON_B_XHCI || - pdev->device == PCI_DEVICE_ID_INTEL_APL_XHCI || - pdev->device == PCI_DEVICE_ID_INTEL_DNV_XHCI || - pdev->device == PCI_DEVICE_ID_INTEL_CML_XHCI)) { + pdev->device == PCI_DEVICE_ID_INTEL_APOLLO_LAKE_XHCI || + pdev->device == PCI_DEVICE_ID_INTEL_DENVERTON_XHCI || + pdev->device == PCI_DEVICE_ID_INTEL_COMET_LAKE_XHCI)) { xhci->quirks |= XHCI_PME_STUCK_QUIRK; } if (pdev->vendor == PCI_VENDOR_ID_INTEL && @@ -359,14 +359,14 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) if (pdev->vendor == PCI_VENDOR_ID_INTEL && (pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI || pdev->device == PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_XHCI || - pdev->device == PCI_DEVICE_ID_INTEL_APL_XHCI)) + pdev->device == PCI_DEVICE_ID_INTEL_APOLLO_LAKE_XHCI)) xhci->quirks |= XHCI_INTEL_USB_ROLE_SW; if (pdev->vendor == PCI_VENDOR_ID_INTEL && (pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI || pdev->device == PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_XHCI || pdev->device == PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_XHCI || - pdev->device == PCI_DEVICE_ID_INTEL_APL_XHCI || - pdev->device == PCI_DEVICE_ID_INTEL_DNV_XHCI)) + pdev->device == PCI_DEVICE_ID_INTEL_APOLLO_LAKE_XHCI || + pdev->device == PCI_DEVICE_ID_INTEL_DENVERTON_XHCI)) xhci->quirks |= XHCI_MISSING_CAS; if (pdev->vendor == PCI_VENDOR_ID_INTEL && -- cgit v1.2.3-59-g8ed1b From 2f8a5b415739adb0fd5191fb52ec9cc447883d58 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 29 Apr 2024 17:02:42 +0300 Subject: xhci: pci: Group out Thunderbolt xHCI IDs It's better to keep track on Thunderbolt xHCI IDs in a separate group. Signed-off-by: Andy Shevchenko Signed-off-by: Mathias Nyman Link: https://lore.kernel.org/r/20240429140245.3955523-16-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-pci.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index d45c84062b61..8e9b720ab330 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -46,6 +46,15 @@ #define PCI_DEVICE_ID_INTEL_BROXTON_M_XHCI 0x0aa8 #define PCI_DEVICE_ID_INTEL_BROXTON_B_XHCI 0x1aa8 #define PCI_DEVICE_ID_INTEL_APOLLO_LAKE_XHCI 0x5aa8 +#define PCI_DEVICE_ID_INTEL_DENVERTON_XHCI 0x19d0 +#define PCI_DEVICE_ID_INTEL_ICE_LAKE_XHCI 0x8a13 +#define PCI_DEVICE_ID_INTEL_TIGER_LAKE_XHCI 0x9a13 +#define PCI_DEVICE_ID_INTEL_COMET_LAKE_XHCI 0xa3af +#define PCI_DEVICE_ID_INTEL_ALDER_LAKE_PCH_XHCI 0x51ed +#define PCI_DEVICE_ID_INTEL_ALDER_LAKE_N_PCH_XHCI 0x54ed + +/* Thunderbolt */ +#define PCI_DEVICE_ID_INTEL_MAPLE_RIDGE_XHCI 0x1138 #define PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_2C_XHCI 0x15b5 #define PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_4C_XHCI 0x15b6 #define PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_LP_XHCI 0x15c1 @@ -54,13 +63,6 @@ #define PCI_DEVICE_ID_INTEL_TITAN_RIDGE_2C_XHCI 0x15e9 #define PCI_DEVICE_ID_INTEL_TITAN_RIDGE_4C_XHCI 0x15ec #define PCI_DEVICE_ID_INTEL_TITAN_RIDGE_DD_XHCI 0x15f0 -#define PCI_DEVICE_ID_INTEL_DENVERTON_XHCI 0x19d0 -#define PCI_DEVICE_ID_INTEL_ICE_LAKE_XHCI 0x8a13 -#define PCI_DEVICE_ID_INTEL_TIGER_LAKE_XHCI 0x9a13 -#define PCI_DEVICE_ID_INTEL_COMET_LAKE_XHCI 0xa3af -#define PCI_DEVICE_ID_INTEL_MAPLE_RIDGE_XHCI 0x1138 -#define PCI_DEVICE_ID_INTEL_ALDER_LAKE_PCH_XHCI 0x51ed -#define PCI_DEVICE_ID_INTEL_ALDER_LAKE_N_PCH_XHCI 0x54ed #define PCI_DEVICE_ID_AMD_RENOIR_XHCI 0x1639 #define PCI_DEVICE_ID_AMD_PROMONTORYA_4 0x43b9 -- cgit v1.2.3-59-g8ed1b From d6b2b694dd536d16566424c395d5642783ed6f34 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 29 Apr 2024 17:02:43 +0300 Subject: xhci: pci: Use PCI_VENDOR_ID_RENESAS Instead of plain hexadecimal, use already defined PCI_VENDOR_ID_RENESAS. Signed-off-by: Andy Shevchenko Signed-off-by: Mathias Nyman Link: https://lore.kernel.org/r/20240429140245.3955523-17-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-pci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index 8e9b720ab330..c040d816e626 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -880,10 +880,10 @@ static const struct xhci_driver_data reneses_data = { /* PCI driver selection metadata; PCI hotplugging uses this */ static const struct pci_device_id pci_ids[] = { - { PCI_DEVICE(0x1912, 0x0014), + { PCI_DEVICE(PCI_VENDOR_ID_RENESAS, 0x0014), .driver_data = (unsigned long)&reneses_data, }, - { PCI_DEVICE(0x1912, 0x0015), + { PCI_DEVICE(PCI_VENDOR_ID_RENESAS, 0x0015), .driver_data = (unsigned long)&reneses_data, }, /* handle any USB 3.0 xHCI controller */ -- cgit v1.2.3-59-g8ed1b From b44c0ce372f2f5106fc70338aaecf92b931a65d6 Mon Sep 17 00:00:00 2001 From: Niklas Neronin Date: Mon, 29 Apr 2024 17:02:44 +0300 Subject: usb: xhci: remove duplicate TRB_TO_SLOT_ID() calls Remove unnecessary repeated calls to TRB_TO_SLOT_ID(). The slot ID is stored in the 'slot_id' variable at the function's start. Signed-off-by: Niklas Neronin Signed-off-by: Mathias Nyman Link: https://lore.kernel.org/r/20240429140245.3955523-18-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-ring.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index b395708c488c..a7423ed992ee 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -2723,20 +2723,16 @@ static int handle_tx_event(struct xhci_hcd *xhci, */ xhci_dbg(xhci, "underrun event on endpoint\n"); if (!list_empty(&ep_ring->td_list)) - xhci_dbg(xhci, "Underrun Event for slot %d ep %d " - "still with TDs queued?\n", - TRB_TO_SLOT_ID(le32_to_cpu(event->flags)), - ep_index); + xhci_dbg(xhci, "Underrun Event for slot %u ep %d still with TDs queued?\n", + slot_id, ep_index); if (ep->skip) break; return 0; case COMP_RING_OVERRUN: xhci_dbg(xhci, "overrun event on endpoint\n"); if (!list_empty(&ep_ring->td_list)) - xhci_dbg(xhci, "Overrun Event for slot %d ep %d " - "still with TDs queued?\n", - TRB_TO_SLOT_ID(le32_to_cpu(event->flags)), - ep_index); + xhci_dbg(xhci, "Overrun Event for slot %u ep %d still with TDs queued?\n", + slot_id, ep_index); if (ep->skip) break; return 0; @@ -2795,9 +2791,8 @@ static int handle_tx_event(struct xhci_hcd *xhci, if (!(trb_comp_code == COMP_STOPPED || trb_comp_code == COMP_STOPPED_LENGTH_INVALID || ep_ring->last_td_was_short)) { - xhci_warn(xhci, "WARN Event TRB for slot %d ep %d with no TDs queued?\n", - TRB_TO_SLOT_ID(le32_to_cpu(event->flags)), - ep_index); + xhci_warn(xhci, "WARN Event TRB for slot %u ep %d with no TDs queued?\n", + slot_id, ep_index); } if (ep->skip) { ep->skip = false; -- cgit v1.2.3-59-g8ed1b From 080e73c9411b9ebc4c22e8ee8a12a9f109b85819 Mon Sep 17 00:00:00 2001 From: Niklas Neronin Date: Mon, 29 Apr 2024 17:02:45 +0300 Subject: usb: xhci: compact 'trb_in_td()' arguments Pass pointer to the TD (struct xhci_td *) directly, instead of its components separately. Signed-off-by: Niklas Neronin Signed-off-by: Mathias Nyman Link: https://lore.kernel.org/r/20240429140245.3955523-19-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-ring.c | 38 ++++++++++++++------------------------ drivers/usb/host/xhci.h | 5 ++--- 2 files changed, 16 insertions(+), 27 deletions(-) diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index a7423ed992ee..9e90d2952760 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1024,8 +1024,7 @@ static int xhci_invalidate_cancelled_tds(struct xhci_virt_ep *ep) td->urb->stream_id); hw_deq &= ~0xf; - if (td->cancel_status == TD_HALTED || - trb_in_td(xhci, td->start_seg, td->first_trb, td->last_trb, hw_deq, false)) { + if (td->cancel_status == TD_HALTED || trb_in_td(xhci, td, hw_deq, false)) { switch (td->cancel_status) { case TD_CLEARED: /* TD is already no-op */ case TD_CLEARING_CACHE: /* set TR deq command already queued */ @@ -1082,8 +1081,7 @@ static struct xhci_td *find_halted_td(struct xhci_virt_ep *ep) hw_deq = xhci_get_hw_deq(ep->xhci, ep->vdev, ep->ep_index, 0); hw_deq &= ~0xf; td = list_first_entry(&ep->ring->td_list, struct xhci_td, td_list); - if (trb_in_td(ep->xhci, td->start_seg, td->first_trb, - td->last_trb, hw_deq, false)) + if (trb_in_td(ep->xhci, td, hw_deq, false)) return td; } return NULL; @@ -2049,25 +2047,19 @@ cleanup: } /* - * This TD is defined by the TRBs starting at start_trb in start_seg and ending - * at end_trb, which may be in another segment. If the suspect DMA address is a - * TRB in this TD, this function returns that TRB's segment. Otherwise it - * returns 0. + * If the suspect DMA address is a TRB in this TD, this function returns that + * TRB's segment. Otherwise it returns 0. */ -struct xhci_segment *trb_in_td(struct xhci_hcd *xhci, - struct xhci_segment *start_seg, - union xhci_trb *start_trb, - union xhci_trb *end_trb, - dma_addr_t suspect_dma, - bool debug) +struct xhci_segment *trb_in_td(struct xhci_hcd *xhci, struct xhci_td *td, dma_addr_t suspect_dma, + bool debug) { dma_addr_t start_dma; dma_addr_t end_seg_dma; dma_addr_t end_trb_dma; struct xhci_segment *cur_seg; - start_dma = xhci_trb_virt_to_dma(start_seg, start_trb); - cur_seg = start_seg; + start_dma = xhci_trb_virt_to_dma(td->start_seg, td->first_trb); + cur_seg = td->start_seg; do { if (start_dma == 0) @@ -2076,7 +2068,7 @@ struct xhci_segment *trb_in_td(struct xhci_hcd *xhci, end_seg_dma = xhci_trb_virt_to_dma(cur_seg, &cur_seg->trbs[TRBS_PER_SEGMENT - 1]); /* If the end TRB isn't in this segment, this is set to 0 */ - end_trb_dma = xhci_trb_virt_to_dma(cur_seg, end_trb); + end_trb_dma = xhci_trb_virt_to_dma(cur_seg, td->last_trb); if (debug) xhci_warn(xhci, @@ -2110,7 +2102,7 @@ struct xhci_segment *trb_in_td(struct xhci_hcd *xhci, } cur_seg = cur_seg->next; start_dma = xhci_trb_virt_to_dma(cur_seg, &cur_seg->trbs[0]); - } while (cur_seg != start_seg); + } while (cur_seg != td->start_seg); return NULL; } @@ -2822,8 +2814,7 @@ static int handle_tx_event(struct xhci_hcd *xhci, td_num--; /* Is this a TRB in the currently executing TD? */ - ep_seg = trb_in_td(xhci, td->start_seg, td->first_trb, - td->last_trb, ep_trb_dma, false); + ep_seg = trb_in_td(xhci, td, ep_trb_dma, false); /* * Skip the Force Stopped Event. The event_trb(event_dma) of FSE @@ -2870,8 +2861,7 @@ static int handle_tx_event(struct xhci_hcd *xhci, !list_is_last(&td->td_list, &ep_ring->td_list)) { struct xhci_td *td_next = list_next_entry(td, td_list); - ep_seg = trb_in_td(xhci, td_next->start_seg, td_next->first_trb, - td_next->last_trb, ep_trb_dma, false); + ep_seg = trb_in_td(xhci, td_next, ep_trb_dma, false); if (ep_seg) { /* give back previous TD, start handling new */ xhci_dbg(xhci, "Missing TD completion event after mid TD error\n"); @@ -2890,8 +2880,8 @@ static int handle_tx_event(struct xhci_hcd *xhci, "part of current TD ep_index %d " "comp_code %u\n", ep_index, trb_comp_code); - trb_in_td(xhci, td->start_seg, td->first_trb, - td->last_trb, ep_trb_dma, true); + trb_in_td(xhci, td, ep_trb_dma, true); + return -ESHUTDOWN; } } diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 933f8a296014..30415158ed3c 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1870,9 +1870,8 @@ int xhci_alloc_tt_info(struct xhci_hcd *xhci, /* xHCI ring, segment, TRB, and TD functions */ dma_addr_t xhci_trb_virt_to_dma(struct xhci_segment *seg, union xhci_trb *trb); -struct xhci_segment *trb_in_td(struct xhci_hcd *xhci, - struct xhci_segment *start_seg, union xhci_trb *start_trb, - union xhci_trb *end_trb, dma_addr_t suspect_dma, bool debug); +struct xhci_segment *trb_in_td(struct xhci_hcd *xhci, struct xhci_td *td, + dma_addr_t suspect_dma, bool debug); int xhci_is_vendor_info_code(struct xhci_hcd *xhci, unsigned int trb_comp_code); void xhci_ring_cmd_db(struct xhci_hcd *xhci); int xhci_queue_slot_control(struct xhci_hcd *xhci, struct xhci_command *cmd, -- cgit v1.2.3-59-g8ed1b From 0340dc4c82590d8735c58cf904a8aa1173273ab5 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Maneyrol Date: Fri, 26 Apr 2024 13:58:14 +0000 Subject: iio: invensense: fix interrupt timestamp alignment Restrict interrupt timestamp alignment for not overflowing max/min period thresholds. Fixes: 0ecc363ccea7 ("iio: make invensense timestamp module generic") Cc: stable@vger.kernel.org Signed-off-by: Jean-Baptiste Maneyrol Link: https://lore.kernel.org/r/20240426135814.141837-1-inv.git-commit@tdk.com Signed-off-by: Jonathan Cameron --- drivers/iio/common/inv_sensors/inv_sensors_timestamp.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/iio/common/inv_sensors/inv_sensors_timestamp.c b/drivers/iio/common/inv_sensors/inv_sensors_timestamp.c index 3b0f9598a7c7..4b8ec16240b5 100644 --- a/drivers/iio/common/inv_sensors/inv_sensors_timestamp.c +++ b/drivers/iio/common/inv_sensors/inv_sensors_timestamp.c @@ -101,6 +101,9 @@ static bool inv_update_chip_period(struct inv_sensors_timestamp *ts, static void inv_align_timestamp_it(struct inv_sensors_timestamp *ts) { + const int64_t period_min = ts->min_period * ts->mult; + const int64_t period_max = ts->max_period * ts->mult; + int64_t add_max, sub_max; int64_t delta, jitter; int64_t adjust; @@ -108,11 +111,13 @@ static void inv_align_timestamp_it(struct inv_sensors_timestamp *ts) delta = ts->it.lo - ts->timestamp; /* adjust timestamp while respecting jitter */ + add_max = period_max - (int64_t)ts->period; + sub_max = period_min - (int64_t)ts->period; jitter = INV_SENSORS_TIMESTAMP_JITTER((int64_t)ts->period, ts->chip.jitter); if (delta > jitter) - adjust = jitter; + adjust = add_max; else if (delta < -jitter) - adjust = -jitter; + adjust = sub_max; else adjust = 0; -- cgit v1.2.3-59-g8ed1b From 213cbada7b07bf66409604e0d0dcd66a6a14891a Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Tue, 30 Apr 2024 15:19:24 +0200 Subject: nvmet: lock config semaphore when accessing DH-HMAC-CHAP key When the DH-HMAC-CHAP key is accessed via configfs we need to take the config semaphore as a reconnect might be running at the same time. Reviewed-by: Sagi Grimberg Reviewed-by: Christoph Hellwig Signed-off-by: Hannes Reinecke Signed-off-by: Daniel Wagner Signed-off-by: Keith Busch --- drivers/nvme/target/auth.c | 2 ++ drivers/nvme/target/configfs.c | 22 +++++++++++++++++----- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/drivers/nvme/target/auth.c b/drivers/nvme/target/auth.c index 3ddbc3880cac..9afc28f1ffac 100644 --- a/drivers/nvme/target/auth.c +++ b/drivers/nvme/target/auth.c @@ -44,6 +44,7 @@ int nvmet_auth_set_key(struct nvmet_host *host, const char *secret, dhchap_secret = kstrdup(secret, GFP_KERNEL); if (!dhchap_secret) return -ENOMEM; + down_write(&nvmet_config_sem); if (set_ctrl) { kfree(host->dhchap_ctrl_secret); host->dhchap_ctrl_secret = strim(dhchap_secret); @@ -53,6 +54,7 @@ int nvmet_auth_set_key(struct nvmet_host *host, const char *secret, host->dhchap_secret = strim(dhchap_secret); host->dhchap_key_hash = key_hash; } + up_write(&nvmet_config_sem); return 0; } diff --git a/drivers/nvme/target/configfs.c b/drivers/nvme/target/configfs.c index 77a6e817b315..7c28b9c0ee57 100644 --- a/drivers/nvme/target/configfs.c +++ b/drivers/nvme/target/configfs.c @@ -1990,11 +1990,17 @@ static struct config_group nvmet_ports_group; static ssize_t nvmet_host_dhchap_key_show(struct config_item *item, char *page) { - u8 *dhchap_secret = to_host(item)->dhchap_secret; + u8 *dhchap_secret; + ssize_t ret; + down_read(&nvmet_config_sem); + dhchap_secret = to_host(item)->dhchap_secret; if (!dhchap_secret) - return sprintf(page, "\n"); - return sprintf(page, "%s\n", dhchap_secret); + ret = sprintf(page, "\n"); + else + ret = sprintf(page, "%s\n", dhchap_secret); + up_read(&nvmet_config_sem); + return ret; } static ssize_t nvmet_host_dhchap_key_store(struct config_item *item, @@ -2018,10 +2024,16 @@ static ssize_t nvmet_host_dhchap_ctrl_key_show(struct config_item *item, char *page) { u8 *dhchap_secret = to_host(item)->dhchap_ctrl_secret; + ssize_t ret; + down_read(&nvmet_config_sem); + dhchap_secret = to_host(item)->dhchap_ctrl_secret; if (!dhchap_secret) - return sprintf(page, "\n"); - return sprintf(page, "%s\n", dhchap_secret); + ret = sprintf(page, "\n"); + else + ret = sprintf(page, "%s\n", dhchap_secret); + up_read(&nvmet_config_sem); + return ret; } static ssize_t nvmet_host_dhchap_ctrl_key_store(struct config_item *item, -- cgit v1.2.3-59-g8ed1b From 44e3c25efae8575e06f1c5d1dc40058a991e3cb2 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Tue, 30 Apr 2024 15:19:25 +0200 Subject: nvmet: return DHCHAP status codes from nvmet_setup_auth() A failure in nvmet_setup_auth() does not mean that the NVMe authentication command failed, so we should rather return a protocol error with a 'failure1' response than an NVMe status. Also update the type used for dhchap_step and dhchap_status to u8 to avoid confusions with nvme status. Furthermore, split dhchap_status and nvme status so we don't accidentally mix these return values. Reviewed-by: Christoph Hellwig Signed-off-by: Hannes Reinecke [dwagner: - use u8 as type for dhchap_{step|status} - separate nvme status from dhcap_status] Signed-off-by: Daniel Wagner Signed-off-by: Keith Busch --- drivers/nvme/target/auth.c | 20 ++++++-------- drivers/nvme/target/fabrics-cmd-auth.c | 49 +++++++++++++++++----------------- drivers/nvme/target/fabrics-cmd.c | 11 ++++---- drivers/nvme/target/nvmet.h | 8 +++--- 4 files changed, 43 insertions(+), 45 deletions(-) diff --git a/drivers/nvme/target/auth.c b/drivers/nvme/target/auth.c index 9afc28f1ffac..53bf1a084469 100644 --- a/drivers/nvme/target/auth.c +++ b/drivers/nvme/target/auth.c @@ -126,12 +126,11 @@ int nvmet_setup_dhgroup(struct nvmet_ctrl *ctrl, u8 dhgroup_id) return ret; } -int nvmet_setup_auth(struct nvmet_ctrl *ctrl) +u8 nvmet_setup_auth(struct nvmet_ctrl *ctrl) { int ret = 0; struct nvmet_host_link *p; struct nvmet_host *host = NULL; - const char *hash_name; down_read(&nvmet_config_sem); if (nvmet_is_disc_subsys(ctrl->subsys)) @@ -149,13 +148,16 @@ int nvmet_setup_auth(struct nvmet_ctrl *ctrl) } if (!host) { pr_debug("host %s not found\n", ctrl->hostnqn); - ret = -EPERM; + ret = NVME_AUTH_DHCHAP_FAILURE_FAILED; goto out_unlock; } ret = nvmet_setup_dhgroup(ctrl, host->dhchap_dhgroup_id); - if (ret < 0) + if (ret < 0) { pr_warn("Failed to setup DH group"); + ret = NVME_AUTH_DHCHAP_FAILURE_DHGROUP_UNUSABLE; + goto out_unlock; + } if (!host->dhchap_secret) { pr_debug("No authentication provided\n"); @@ -166,12 +168,6 @@ int nvmet_setup_auth(struct nvmet_ctrl *ctrl) pr_debug("Re-use existing hash ID %d\n", ctrl->shash_id); } else { - hash_name = nvme_auth_hmac_name(host->dhchap_hash_id); - if (!hash_name) { - pr_warn("Hash ID %d invalid\n", host->dhchap_hash_id); - ret = -EINVAL; - goto out_unlock; - } ctrl->shash_id = host->dhchap_hash_id; } @@ -180,7 +176,7 @@ int nvmet_setup_auth(struct nvmet_ctrl *ctrl) ctrl->host_key = nvme_auth_extract_key(host->dhchap_secret + 10, host->dhchap_key_hash); if (IS_ERR(ctrl->host_key)) { - ret = PTR_ERR(ctrl->host_key); + ret = NVME_AUTH_DHCHAP_FAILURE_NOT_USABLE; ctrl->host_key = NULL; goto out_free_hash; } @@ -198,7 +194,7 @@ int nvmet_setup_auth(struct nvmet_ctrl *ctrl) ctrl->ctrl_key = nvme_auth_extract_key(host->dhchap_ctrl_secret + 10, host->dhchap_ctrl_key_hash); if (IS_ERR(ctrl->ctrl_key)) { - ret = PTR_ERR(ctrl->ctrl_key); + ret = NVME_AUTH_DHCHAP_FAILURE_NOT_USABLE; ctrl->ctrl_key = NULL; goto out_free_hash; } diff --git a/drivers/nvme/target/fabrics-cmd-auth.c b/drivers/nvme/target/fabrics-cmd-auth.c index eb7785be0ca7..d61b8c6ff3b2 100644 --- a/drivers/nvme/target/fabrics-cmd-auth.c +++ b/drivers/nvme/target/fabrics-cmd-auth.c @@ -31,7 +31,7 @@ void nvmet_auth_sq_init(struct nvmet_sq *sq) sq->dhchap_step = NVME_AUTH_DHCHAP_MESSAGE_NEGOTIATE; } -static u16 nvmet_auth_negotiate(struct nvmet_req *req, void *d) +static u8 nvmet_auth_negotiate(struct nvmet_req *req, void *d) { struct nvmet_ctrl *ctrl = req->sq->ctrl; struct nvmf_auth_dhchap_negotiate_data *data = d; @@ -109,7 +109,7 @@ static u16 nvmet_auth_negotiate(struct nvmet_req *req, void *d) return 0; } -static u16 nvmet_auth_reply(struct nvmet_req *req, void *d) +static u8 nvmet_auth_reply(struct nvmet_req *req, void *d) { struct nvmet_ctrl *ctrl = req->sq->ctrl; struct nvmf_auth_dhchap_reply_data *data = d; @@ -172,7 +172,7 @@ static u16 nvmet_auth_reply(struct nvmet_req *req, void *d) return 0; } -static u16 nvmet_auth_failure2(void *d) +static u8 nvmet_auth_failure2(void *d) { struct nvmf_auth_dhchap_failure_data *data = d; @@ -186,6 +186,7 @@ void nvmet_execute_auth_send(struct nvmet_req *req) void *d; u32 tl; u16 status = 0; + u8 dhchap_status; if (req->cmd->auth_send.secp != NVME_AUTH_DHCHAP_PROTOCOL_IDENTIFIER) { status = NVME_SC_INVALID_FIELD | NVME_SC_DNR; @@ -237,30 +238,32 @@ void nvmet_execute_auth_send(struct nvmet_req *req) if (data->auth_type == NVME_AUTH_COMMON_MESSAGES) { if (data->auth_id == NVME_AUTH_DHCHAP_MESSAGE_NEGOTIATE) { /* Restart negotiation */ - pr_debug("%s: ctrl %d qid %d reset negotiation\n", __func__, - ctrl->cntlid, req->sq->qid); + pr_debug("%s: ctrl %d qid %d reset negotiation\n", + __func__, ctrl->cntlid, req->sq->qid); if (!req->sq->qid) { - if (nvmet_setup_auth(ctrl) < 0) { - status = NVME_SC_INTERNAL; - pr_err("ctrl %d qid 0 failed to setup" - "re-authentication", + dhchap_status = nvmet_setup_auth(ctrl); + if (dhchap_status) { + pr_err("ctrl %d qid 0 failed to setup re-authentication\n", ctrl->cntlid); - goto done_failure1; + req->sq->dhchap_status = dhchap_status; + req->sq->dhchap_step = + NVME_AUTH_DHCHAP_MESSAGE_FAILURE1; + goto done_kfree; } } - req->sq->dhchap_step = NVME_AUTH_DHCHAP_MESSAGE_NEGOTIATE; + req->sq->dhchap_step = + NVME_AUTH_DHCHAP_MESSAGE_NEGOTIATE; } else if (data->auth_id != req->sq->dhchap_step) goto done_failure1; /* Validate negotiation parameters */ - status = nvmet_auth_negotiate(req, d); - if (status == 0) + dhchap_status = nvmet_auth_negotiate(req, d); + if (dhchap_status == 0) req->sq->dhchap_step = NVME_AUTH_DHCHAP_MESSAGE_CHALLENGE; else { req->sq->dhchap_step = NVME_AUTH_DHCHAP_MESSAGE_FAILURE1; - req->sq->dhchap_status = status; - status = 0; + req->sq->dhchap_status = dhchap_status; } goto done_kfree; } @@ -284,15 +287,14 @@ void nvmet_execute_auth_send(struct nvmet_req *req) switch (data->auth_id) { case NVME_AUTH_DHCHAP_MESSAGE_REPLY: - status = nvmet_auth_reply(req, d); - if (status == 0) + dhchap_status = nvmet_auth_reply(req, d); + if (dhchap_status == 0) req->sq->dhchap_step = NVME_AUTH_DHCHAP_MESSAGE_SUCCESS1; else { req->sq->dhchap_step = NVME_AUTH_DHCHAP_MESSAGE_FAILURE1; - req->sq->dhchap_status = status; - status = 0; + req->sq->dhchap_status = dhchap_status; } goto done_kfree; case NVME_AUTH_DHCHAP_MESSAGE_SUCCESS2: @@ -301,13 +303,12 @@ void nvmet_execute_auth_send(struct nvmet_req *req) __func__, ctrl->cntlid, req->sq->qid); goto done_kfree; case NVME_AUTH_DHCHAP_MESSAGE_FAILURE2: - status = nvmet_auth_failure2(d); - if (status) { + dhchap_status = nvmet_auth_failure2(d); + if (dhchap_status) { pr_warn("ctrl %d qid %d: authentication failed (%d)\n", - ctrl->cntlid, req->sq->qid, status); - req->sq->dhchap_status = status; + ctrl->cntlid, req->sq->qid, dhchap_status); + req->sq->dhchap_status = dhchap_status; req->sq->authenticated = false; - status = 0; } goto done_kfree; default: diff --git a/drivers/nvme/target/fabrics-cmd.c b/drivers/nvme/target/fabrics-cmd.c index b23f4cf840bd..042b379cbb36 100644 --- a/drivers/nvme/target/fabrics-cmd.c +++ b/drivers/nvme/target/fabrics-cmd.c @@ -211,7 +211,7 @@ static void nvmet_execute_admin_connect(struct nvmet_req *req) struct nvmf_connect_data *d; struct nvmet_ctrl *ctrl = NULL; u16 status; - int ret; + u8 dhchap_status; if (!nvmet_check_transfer_len(req, sizeof(struct nvmf_connect_data))) return; @@ -254,11 +254,12 @@ static void nvmet_execute_admin_connect(struct nvmet_req *req) uuid_copy(&ctrl->hostid, &d->hostid); - ret = nvmet_setup_auth(ctrl); - if (ret < 0) { - pr_err("Failed to setup authentication, error %d\n", ret); + dhchap_status = nvmet_setup_auth(ctrl); + if (dhchap_status) { + pr_err("Failed to setup authentication, dhchap status %u\n", + dhchap_status); nvmet_ctrl_put(ctrl); - if (ret == -EPERM) + if (dhchap_status == NVME_AUTH_DHCHAP_FAILURE_FAILED) status = (NVME_SC_CONNECT_INVALID_HOST | NVME_SC_DNR); else status = NVME_SC_INTERNAL; diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h index f460728e1df1..e4ba54b85511 100644 --- a/drivers/nvme/target/nvmet.h +++ b/drivers/nvme/target/nvmet.h @@ -113,8 +113,8 @@ struct nvmet_sq { bool authenticated; struct delayed_work auth_expired_work; u16 dhchap_tid; - u16 dhchap_status; - int dhchap_step; + u8 dhchap_status; + u8 dhchap_step; u8 *dhchap_c1; u8 *dhchap_c2; u32 dhchap_s1; @@ -713,7 +713,7 @@ void nvmet_execute_auth_receive(struct nvmet_req *req); int nvmet_auth_set_key(struct nvmet_host *host, const char *secret, bool set_ctrl); int nvmet_auth_set_host_hash(struct nvmet_host *host, const char *hash); -int nvmet_setup_auth(struct nvmet_ctrl *ctrl); +u8 nvmet_setup_auth(struct nvmet_ctrl *ctrl); void nvmet_auth_sq_init(struct nvmet_sq *sq); void nvmet_destroy_auth(struct nvmet_ctrl *ctrl); void nvmet_auth_sq_free(struct nvmet_sq *sq); @@ -732,7 +732,7 @@ int nvmet_auth_ctrl_exponential(struct nvmet_req *req, int nvmet_auth_ctrl_sesskey(struct nvmet_req *req, u8 *buf, int buf_size); #else -static inline int nvmet_setup_auth(struct nvmet_ctrl *ctrl) +static inline u8 nvmet_setup_auth(struct nvmet_ctrl *ctrl) { return 0; } -- cgit v1.2.3-59-g8ed1b From 44350336fd9dab7a337dec686978a160cf1abfc5 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Tue, 30 Apr 2024 15:19:26 +0200 Subject: nvme: return kernel error codes for admin queue connect nvmf_connect_admin_queue returns NVMe error status codes and kernel error codes. This mixes the different domains which makes maintainability difficult. Reviewed-by: Christoph Hellwig Reviewed-by: Sagi Grimberg Signed-off-by: Hannes Reinecke Signed-off-by: Daniel Wagner Signed-off-by: Keith Busch --- drivers/nvme/host/core.c | 6 +++--- drivers/nvme/host/fabrics.c | 31 +++++++++++++------------------ drivers/nvme/host/nvme.h | 2 +- 3 files changed, 17 insertions(+), 22 deletions(-) diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index c9955ecd1790..a066429b790d 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -383,14 +383,14 @@ static inline enum nvme_disposition nvme_decide_disposition(struct request *req) if (likely(nvme_req(req)->status == 0)) return COMPLETE; - if ((nvme_req(req)->status & 0x7ff) == NVME_SC_AUTH_REQUIRED) - return AUTHENTICATE; - if (blk_noretry_request(req) || (nvme_req(req)->status & NVME_SC_DNR) || nvme_req(req)->retries >= nvme_max_retries) return COMPLETE; + if ((nvme_req(req)->status & 0x7ff) == NVME_SC_AUTH_REQUIRED) + return AUTHENTICATE; + if (req->cmd_flags & REQ_NVME_MPATH) { if (nvme_is_path_error(nvme_req(req)->status) || blk_queue_dying(req->q)) diff --git a/drivers/nvme/host/fabrics.c b/drivers/nvme/host/fabrics.c index 1f0ea1f32d22..f7eaf9580b4f 100644 --- a/drivers/nvme/host/fabrics.c +++ b/drivers/nvme/host/fabrics.c @@ -428,12 +428,6 @@ static void nvmf_connect_cmd_prep(struct nvme_ctrl *ctrl, u16 qid, * fabrics-protocol connection of the NVMe Admin queue between the * host system device and the allocated NVMe controller on the * target system via a NVMe Fabrics "Connect" command. - * - * Return: - * 0: success - * > 0: NVMe error status code - * < 0: Linux errno error code - * */ int nvmf_connect_admin_queue(struct nvme_ctrl *ctrl) { @@ -467,7 +461,7 @@ int nvmf_connect_admin_queue(struct nvme_ctrl *ctrl) if (result & NVME_CONNECT_AUTHREQ_ASCR) { dev_warn(ctrl->device, "qid 0: secure concatenation is not supported\n"); - ret = NVME_SC_AUTH_REQUIRED; + ret = -EOPNOTSUPP; goto out_free_data; } /* Authentication required */ @@ -475,14 +469,14 @@ int nvmf_connect_admin_queue(struct nvme_ctrl *ctrl) if (ret) { dev_warn(ctrl->device, "qid 0: authentication setup failed\n"); - ret = NVME_SC_AUTH_REQUIRED; goto out_free_data; } ret = nvme_auth_wait(ctrl, 0); - if (ret) + if (ret) { dev_warn(ctrl->device, - "qid 0: authentication failed\n"); - else + "qid 0: authentication failed, error %d\n", + ret); + } else dev_info(ctrl->device, "qid 0: authenticated\n"); } @@ -542,7 +536,7 @@ int nvmf_connect_io_queue(struct nvme_ctrl *ctrl, u16 qid) if (result & NVME_CONNECT_AUTHREQ_ASCR) { dev_warn(ctrl->device, "qid 0: secure concatenation is not supported\n"); - ret = NVME_SC_AUTH_REQUIRED; + ret = -EOPNOTSUPP; goto out_free_data; } /* Authentication required */ @@ -550,12 +544,13 @@ int nvmf_connect_io_queue(struct nvme_ctrl *ctrl, u16 qid) if (ret) { dev_warn(ctrl->device, "qid %d: authentication setup failed\n", qid); - ret = NVME_SC_AUTH_REQUIRED; - } else { - ret = nvme_auth_wait(ctrl, qid); - if (ret) - dev_warn(ctrl->device, - "qid %u: authentication failed\n", qid); + goto out_free_data; + } + ret = nvme_auth_wait(ctrl, qid); + if (ret) { + dev_warn(ctrl->device, + "qid %u: authentication failed, error %d\n", + qid, ret); } } out_free_data: diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h index 24193fcb8bd5..f243a5822c2b 100644 --- a/drivers/nvme/host/nvme.h +++ b/drivers/nvme/host/nvme.h @@ -1114,7 +1114,7 @@ static inline int nvme_auth_negotiate(struct nvme_ctrl *ctrl, int qid) } static inline int nvme_auth_wait(struct nvme_ctrl *ctrl, int qid) { - return NVME_SC_AUTH_REQUIRED; + return -EPROTONOSUPPORT; } static inline void nvme_auth_free(struct nvme_ctrl *ctrl) {}; #endif -- cgit v1.2.3-59-g8ed1b From adfde7ed0b301ef14c37efe3143a8b26849843f6 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Tue, 30 Apr 2024 15:19:27 +0200 Subject: nvme-fabrics: short-circuit reconnect retries Returning a nvme status from nvme_tcp_setup_ctrl() indicates that the association was established and we have received a status from the controller; consequently we should honour the DNR bit. If not any future reconnect attempts will just return the same error, so we can short-circuit the reconnect attempts and fail the connection directly. Signed-off-by: Hannes Reinecke [dwagner: - extended nvme_should_reconnect] Signed-off-by: Daniel Wagner Signed-off-by: Keith Busch --- drivers/nvme/host/fabrics.c | 14 +++++++++++++- drivers/nvme/host/fabrics.h | 2 +- drivers/nvme/host/fc.c | 4 +--- drivers/nvme/host/rdma.c | 19 ++++++++++++------- drivers/nvme/host/tcp.c | 22 ++++++++++++++-------- 5 files changed, 41 insertions(+), 20 deletions(-) diff --git a/drivers/nvme/host/fabrics.c b/drivers/nvme/host/fabrics.c index f7eaf9580b4f..36d3e2ff27f3 100644 --- a/drivers/nvme/host/fabrics.c +++ b/drivers/nvme/host/fabrics.c @@ -559,8 +559,20 @@ out_free_data: } EXPORT_SYMBOL_GPL(nvmf_connect_io_queue); -bool nvmf_should_reconnect(struct nvme_ctrl *ctrl) +/* + * Evaluate the status information returned by the transport in order to decided + * if a reconnect attempt should be scheduled. + * + * Do not retry when: + * + * - the DNR bit is set and the specification states no further connect + * attempts with the same set of paramenters should be attempted. + */ +bool nvmf_should_reconnect(struct nvme_ctrl *ctrl, int status) { + if (status > 0 && (status & NVME_SC_DNR)) + return false; + if (ctrl->opts->max_reconnects == -1 || ctrl->nr_reconnects < ctrl->opts->max_reconnects) return true; diff --git a/drivers/nvme/host/fabrics.h b/drivers/nvme/host/fabrics.h index 37c974c38dcb..602135910ae9 100644 --- a/drivers/nvme/host/fabrics.h +++ b/drivers/nvme/host/fabrics.h @@ -223,7 +223,7 @@ int nvmf_register_transport(struct nvmf_transport_ops *ops); void nvmf_unregister_transport(struct nvmf_transport_ops *ops); void nvmf_free_options(struct nvmf_ctrl_options *opts); int nvmf_get_address(struct nvme_ctrl *ctrl, char *buf, int size); -bool nvmf_should_reconnect(struct nvme_ctrl *ctrl); +bool nvmf_should_reconnect(struct nvme_ctrl *ctrl, int status); bool nvmf_ip_options_match(struct nvme_ctrl *ctrl, struct nvmf_ctrl_options *opts); void nvmf_set_io_queues(struct nvmf_ctrl_options *opts, u32 nr_io_queues, diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c index 68a5d971657b..b330a6a7b63a 100644 --- a/drivers/nvme/host/fc.c +++ b/drivers/nvme/host/fc.c @@ -3310,12 +3310,10 @@ nvme_fc_reconnect_or_delete(struct nvme_fc_ctrl *ctrl, int status) dev_info(ctrl->ctrl.device, "NVME-FC{%d}: reset: Reconnect attempt failed (%d)\n", ctrl->cnum, status); - if (status > 0 && (status & NVME_SC_DNR)) - recon = false; } else if (time_after_eq(jiffies, rport->dev_loss_end)) recon = false; - if (recon && nvmf_should_reconnect(&ctrl->ctrl)) { + if (recon && nvmf_should_reconnect(&ctrl->ctrl, status)) { if (portptr->port_state == FC_OBJSTATE_ONLINE) dev_info(ctrl->ctrl.device, "NVME-FC{%d}: Reconnect attempt in %ld " diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c index 366f0bb4ebfc..821ab3e0fd3b 100644 --- a/drivers/nvme/host/rdma.c +++ b/drivers/nvme/host/rdma.c @@ -982,7 +982,8 @@ free_ctrl: kfree(ctrl); } -static void nvme_rdma_reconnect_or_remove(struct nvme_rdma_ctrl *ctrl) +static void nvme_rdma_reconnect_or_remove(struct nvme_rdma_ctrl *ctrl, + int status) { enum nvme_ctrl_state state = nvme_ctrl_state(&ctrl->ctrl); @@ -992,7 +993,7 @@ static void nvme_rdma_reconnect_or_remove(struct nvme_rdma_ctrl *ctrl) return; } - if (nvmf_should_reconnect(&ctrl->ctrl)) { + if (nvmf_should_reconnect(&ctrl->ctrl, status)) { dev_info(ctrl->ctrl.device, "Reconnecting in %d seconds...\n", ctrl->ctrl.opts->reconnect_delay); queue_delayed_work(nvme_wq, &ctrl->reconnect_work, @@ -1104,10 +1105,12 @@ static void nvme_rdma_reconnect_ctrl_work(struct work_struct *work) { struct nvme_rdma_ctrl *ctrl = container_of(to_delayed_work(work), struct nvme_rdma_ctrl, reconnect_work); + int ret; ++ctrl->ctrl.nr_reconnects; - if (nvme_rdma_setup_ctrl(ctrl, false)) + ret = nvme_rdma_setup_ctrl(ctrl, false); + if (ret) goto requeue; dev_info(ctrl->ctrl.device, "Successfully reconnected (%d attempts)\n", @@ -1120,7 +1123,7 @@ static void nvme_rdma_reconnect_ctrl_work(struct work_struct *work) requeue: dev_info(ctrl->ctrl.device, "Failed reconnect attempt %d\n", ctrl->ctrl.nr_reconnects); - nvme_rdma_reconnect_or_remove(ctrl); + nvme_rdma_reconnect_or_remove(ctrl, ret); } static void nvme_rdma_error_recovery_work(struct work_struct *work) @@ -1145,7 +1148,7 @@ static void nvme_rdma_error_recovery_work(struct work_struct *work) return; } - nvme_rdma_reconnect_or_remove(ctrl); + nvme_rdma_reconnect_or_remove(ctrl, 0); } static void nvme_rdma_error_recovery(struct nvme_rdma_ctrl *ctrl) @@ -2169,6 +2172,7 @@ static void nvme_rdma_reset_ctrl_work(struct work_struct *work) { struct nvme_rdma_ctrl *ctrl = container_of(work, struct nvme_rdma_ctrl, ctrl.reset_work); + int ret; nvme_stop_ctrl(&ctrl->ctrl); nvme_rdma_shutdown_ctrl(ctrl, false); @@ -2179,14 +2183,15 @@ static void nvme_rdma_reset_ctrl_work(struct work_struct *work) return; } - if (nvme_rdma_setup_ctrl(ctrl, false)) + ret = nvme_rdma_setup_ctrl(ctrl, false); + if (ret) goto out_fail; return; out_fail: ++ctrl->ctrl.nr_reconnects; - nvme_rdma_reconnect_or_remove(ctrl); + nvme_rdma_reconnect_or_remove(ctrl, ret); } static const struct nvme_ctrl_ops nvme_rdma_ctrl_ops = { diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c index fdbcdcedcee9..3e0c33323320 100644 --- a/drivers/nvme/host/tcp.c +++ b/drivers/nvme/host/tcp.c @@ -2155,7 +2155,8 @@ static void nvme_tcp_teardown_io_queues(struct nvme_ctrl *ctrl, nvme_tcp_destroy_io_queues(ctrl, remove); } -static void nvme_tcp_reconnect_or_remove(struct nvme_ctrl *ctrl) +static void nvme_tcp_reconnect_or_remove(struct nvme_ctrl *ctrl, + int status) { enum nvme_ctrl_state state = nvme_ctrl_state(ctrl); @@ -2165,13 +2166,14 @@ static void nvme_tcp_reconnect_or_remove(struct nvme_ctrl *ctrl) return; } - if (nvmf_should_reconnect(ctrl)) { + if (nvmf_should_reconnect(ctrl, status)) { dev_info(ctrl->device, "Reconnecting in %d seconds...\n", ctrl->opts->reconnect_delay); queue_delayed_work(nvme_wq, &to_tcp_ctrl(ctrl)->connect_work, ctrl->opts->reconnect_delay * HZ); } else { - dev_info(ctrl->device, "Removing controller...\n"); + dev_info(ctrl->device, "Removing controller (%d)...\n", + status); nvme_delete_ctrl(ctrl); } } @@ -2252,10 +2254,12 @@ static void nvme_tcp_reconnect_ctrl_work(struct work_struct *work) struct nvme_tcp_ctrl *tcp_ctrl = container_of(to_delayed_work(work), struct nvme_tcp_ctrl, connect_work); struct nvme_ctrl *ctrl = &tcp_ctrl->ctrl; + int ret; ++ctrl->nr_reconnects; - if (nvme_tcp_setup_ctrl(ctrl, false)) + ret = nvme_tcp_setup_ctrl(ctrl, false); + if (ret) goto requeue; dev_info(ctrl->device, "Successfully reconnected (%d attempt)\n", @@ -2268,7 +2272,7 @@ static void nvme_tcp_reconnect_ctrl_work(struct work_struct *work) requeue: dev_info(ctrl->device, "Failed reconnect attempt %d\n", ctrl->nr_reconnects); - nvme_tcp_reconnect_or_remove(ctrl); + nvme_tcp_reconnect_or_remove(ctrl, ret); } static void nvme_tcp_error_recovery_work(struct work_struct *work) @@ -2295,7 +2299,7 @@ static void nvme_tcp_error_recovery_work(struct work_struct *work) return; } - nvme_tcp_reconnect_or_remove(ctrl); + nvme_tcp_reconnect_or_remove(ctrl, 0); } static void nvme_tcp_teardown_ctrl(struct nvme_ctrl *ctrl, bool shutdown) @@ -2315,6 +2319,7 @@ static void nvme_reset_ctrl_work(struct work_struct *work) { struct nvme_ctrl *ctrl = container_of(work, struct nvme_ctrl, reset_work); + int ret; nvme_stop_ctrl(ctrl); nvme_tcp_teardown_ctrl(ctrl, false); @@ -2328,14 +2333,15 @@ static void nvme_reset_ctrl_work(struct work_struct *work) return; } - if (nvme_tcp_setup_ctrl(ctrl, false)) + ret = nvme_tcp_setup_ctrl(ctrl, false); + if (ret) goto out_fail; return; out_fail: ++ctrl->nr_reconnects; - nvme_tcp_reconnect_or_remove(ctrl); + nvme_tcp_reconnect_or_remove(ctrl, ret); } static void nvme_tcp_stop_ctrl(struct nvme_ctrl *ctrl) -- cgit v1.2.3-59-g8ed1b From 0e34bd9605f6c95609c32aa82f0a394e2a945908 Mon Sep 17 00:00:00 2001 From: Daniel Wagner Date: Tue, 30 Apr 2024 15:19:28 +0200 Subject: nvme: do not retry authentication failures When the key is invalid there is no point in retrying. Because the auth code returns kernel error codes only, we can't test on the DNR bit. Signed-off-by: Daniel Wagner Signed-off-by: Keith Busch --- drivers/nvme/host/auth.c | 6 +++--- drivers/nvme/host/fabrics.c | 6 ++++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/nvme/host/auth.c b/drivers/nvme/host/auth.c index a264b3ae078b..371e14f0a203 100644 --- a/drivers/nvme/host/auth.c +++ b/drivers/nvme/host/auth.c @@ -730,7 +730,7 @@ static void nvme_queue_auth_work(struct work_struct *work) NVME_AUTH_DHCHAP_MESSAGE_CHALLENGE); if (ret) { chap->status = ret; - chap->error = -ECONNREFUSED; + chap->error = -EKEYREJECTED; return; } @@ -797,7 +797,7 @@ static void nvme_queue_auth_work(struct work_struct *work) NVME_AUTH_DHCHAP_MESSAGE_SUCCESS1); if (ret) { chap->status = ret; - chap->error = -ECONNREFUSED; + chap->error = -EKEYREJECTED; return; } @@ -818,7 +818,7 @@ static void nvme_queue_auth_work(struct work_struct *work) ret = nvme_auth_process_dhchap_success1(ctrl, chap); if (ret) { /* Controller authentication failed */ - chap->error = -ECONNREFUSED; + chap->error = -EKEYREJECTED; goto fail2; } diff --git a/drivers/nvme/host/fabrics.c b/drivers/nvme/host/fabrics.c index 36d3e2ff27f3..c6ad2148c2e0 100644 --- a/drivers/nvme/host/fabrics.c +++ b/drivers/nvme/host/fabrics.c @@ -567,12 +567,18 @@ EXPORT_SYMBOL_GPL(nvmf_connect_io_queue); * * - the DNR bit is set and the specification states no further connect * attempts with the same set of paramenters should be attempted. + * + * - when the authentication attempt fails, because the key was invalid. + * This error code is set on the host side. */ bool nvmf_should_reconnect(struct nvme_ctrl *ctrl, int status) { if (status > 0 && (status & NVME_SC_DNR)) return false; + if (status == -EKEYREJECTED) + return false; + if (ctrl->opts->max_reconnects == -1 || ctrl->nr_reconnects < ctrl->opts->max_reconnects) return true; -- cgit v1.2.3-59-g8ed1b From 8877ef45ef9ec281849870d88039f8dc84cde774 Mon Sep 17 00:00:00 2001 From: Anshuman Khandual Date: Thu, 4 Apr 2024 12:59:34 +0530 Subject: coresight: tmc: Enable SG capability on ACPI based SoC-400 TMC ETR devices This detects and enables the scatter gather capability (SG) on ACPI based Soc-400 TMC ETR devices via a new property called 'arm-armhc97c-sg-enable'. The updated ACPI spec can be found below, which contains this new property. https://developer.arm.com/documentation/den0067/latest/ This preserves current handling for the property 'arm,scatter-gather' both on ACPI and DT based platforms i.e the presence of the property is checked instead of the value. Cc: Suzuki K Poulose Cc: Mike Leach Cc: James Clark Cc: Alexander Shishkin Cc: coresight@lists.linaro.org Cc: linux-arm-kernel@lists.infradead.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Anshuman Khandual Reviewed-by: James Clark Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20240404072934.940760-1-anshuman.khandual@arm.com --- drivers/hwtracing/coresight/coresight-tmc-core.c | 28 +++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/drivers/hwtracing/coresight/coresight-tmc-core.c b/drivers/hwtracing/coresight/coresight-tmc-core.c index 4b50d043ce04..741ce1748e75 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-core.c +++ b/drivers/hwtracing/coresight/coresight-tmc-core.c @@ -4,6 +4,7 @@ * Description: CoreSight Trace Memory Controller driver */ +#include #include #include #include @@ -362,7 +363,32 @@ static const struct attribute_group *coresight_etr_groups[] = { static inline bool tmc_etr_can_use_sg(struct device *dev) { - return fwnode_property_present(dev->fwnode, "arm,scatter-gather"); + int ret; + u8 val_u8; + + /* + * Presence of the property 'arm,scatter-gather' is checked + * on the platform for the feature support, rather than its + * value. + */ + if (is_of_node(dev->fwnode)) { + return fwnode_property_present(dev->fwnode, "arm,scatter-gather"); + } else if (is_acpi_device_node(dev->fwnode)) { + /* + * TMC_DEVID_NOSCAT test in tmc_etr_setup_caps(), has already ensured + * this property is only checked for Coresight SoC 400 TMC configured + * as ETR. + */ + ret = fwnode_property_read_u8(dev->fwnode, "arm-armhc97c-sg-enable", &val_u8); + if (!ret) + return !!val_u8; + + if (fwnode_property_present(dev->fwnode, "arm,scatter-gather")) { + pr_warn_once("Deprecated ACPI property - arm,scatter-gather\n"); + return true; + } + } + return false; } static inline bool tmc_etr_has_non_secure_access(struct tmc_drvdata *drvdata) -- cgit v1.2.3-59-g8ed1b From 4d5569314dcb0a1690ed06835167af61097d6cf6 Mon Sep 17 00:00:00 2001 From: Zhu Lingshan Date: Tue, 27 Feb 2024 22:45:18 +0800 Subject: MAINTAINERS: apply maintainer role of Intel vDPA driver This commit applies maintainer role of Intel vDPA driver for myself. I am the author of this driver and have been contributing to it for long time, I would like to help this solution evolve in future. This driver is still under virtio maintenance. Signed-off-by: Zhu Lingshan Message-Id: <20240227144519.555554-1-lingshan.zhu@intel.com> Signed-off-by: Michael S. Tsirkin Acked-by: Jason Wang --- MAINTAINERS | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index f6dc90559341..2342b34656fb 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -10464,8 +10464,10 @@ F: include/net/nl802154.h F: net/ieee802154/ F: net/mac802154/ -IFCVF VIRTIO DATA PATH ACCELERATOR -R: Zhu Lingshan +Intel VIRTIO DATA PATH ACCELERATOR +M: Zhu Lingshan +L: virtualization@lists.linux.dev +S: Supported F: drivers/vdpa/ifcvf/ IFE PROTOCOL -- cgit v1.2.3-59-g8ed1b From e117d9b6e79a2466faf382cb7e8e8823e82d6bd5 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Fri, 8 Mar 2024 09:51:20 +0100 Subject: virtio-mmio: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Message-Id: Signed-off-by: Michael S. Tsirkin --- drivers/virtio/virtio_mmio.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/virtio/virtio_mmio.c b/drivers/virtio/virtio_mmio.c index 59892a31cf76..173596589c71 100644 --- a/drivers/virtio/virtio_mmio.c +++ b/drivers/virtio/virtio_mmio.c @@ -696,12 +696,10 @@ free_vm_dev: return rc; } -static int virtio_mmio_remove(struct platform_device *pdev) +static void virtio_mmio_remove(struct platform_device *pdev) { struct virtio_mmio_device *vm_dev = platform_get_drvdata(pdev); unregister_virtio_device(&vm_dev->vdev); - - return 0; } @@ -847,7 +845,7 @@ MODULE_DEVICE_TABLE(acpi, virtio_mmio_acpi_match); static struct platform_driver virtio_mmio_driver = { .probe = virtio_mmio_probe, - .remove = virtio_mmio_remove, + .remove_new = virtio_mmio_remove, .driver = { .name = "virtio-mmio", .of_match_table = virtio_mmio_match, -- cgit v1.2.3-59-g8ed1b From b48b41924a212ed663ee3f18e25583770281ee01 Mon Sep 17 00:00:00 2001 From: Zev Weiss Date: Wed, 1 May 2024 17:28:31 -0700 Subject: dt-bindings: trivial-devices: add isil,isl69269 The ISL69269 is a PMBus voltage regulator with no configurable parameters. Signed-off-by: Zev Weiss Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240502002836.17862-6-zev@bewilderbeest.net Signed-off-by: Joel Stanley --- Documentation/devicetree/bindings/trivial-devices.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/trivial-devices.yaml b/Documentation/devicetree/bindings/trivial-devices.yaml index e07be7bf8395..98ad7f3a7853 100644 --- a/Documentation/devicetree/bindings/trivial-devices.yaml +++ b/Documentation/devicetree/bindings/trivial-devices.yaml @@ -160,6 +160,8 @@ properties: - isil,isl29030 # Intersil ISL68137 Digital Output Configurable PWM Controller - isil,isl68137 + # Intersil ISL69269 PMBus Voltage Regulator + - isil,isl69269 # Intersil ISL76682 Ambient Light Sensor - isil,isl76682 # Linear Technology LTC2488 -- cgit v1.2.3-59-g8ed1b From 11726eb66dfe18a9019a292f88a0d4b00cf924f0 Mon Sep 17 00:00:00 2001 From: Zev Weiss Date: Wed, 1 May 2024 17:28:32 -0700 Subject: dt-bindings: arm: aspeed: document ASRock E3C256D4I Document ASRock E3C256D4I board compatible. Signed-off-by: Zev Weiss Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240502002836.17862-7-zev@bewilderbeest.net Signed-off-by: Joel Stanley --- Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml b/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml index d6c808c377e4..95113df178cc 100644 --- a/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml +++ b/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml @@ -35,6 +35,7 @@ properties: - ampere,mtjade-bmc - aspeed,ast2500-evb - asrock,e3c246d4i-bmc + - asrock,e3c256d4i-bmc - asrock,romed8hm3-bmc - asrock,spc621d8hm3-bmc - asrock,x570d4u-bmc -- cgit v1.2.3-59-g8ed1b From c44211af1aa9c6b93178a3993e18a7ebffab7488 Mon Sep 17 00:00:00 2001 From: Zev Weiss Date: Wed, 1 May 2024 17:28:33 -0700 Subject: ARM: dts: aspeed: Add ASRock E3C256D4I BMC Like the E3C246D4I, this is a reasonably affordable off-the-shelf mini-ITX AST2500/Xeon motherboard with good potential as an OpenBMC development platform. Booting the host requires a modicum of eSPI support that's not yet in the mainline kernel, but most other basic BMC functionality is available with this device-tree. Signed-off-by: Zev Weiss Link: https://lore.kernel.org/r/20240502002836.17862-8-zev@bewilderbeest.net Signed-off-by: Joel Stanley --- arch/arm/boot/dts/aspeed/Makefile | 1 + .../dts/aspeed/aspeed-bmc-asrock-e3c256d4i.dts | 322 +++++++++++++++++++++ 2 files changed, 323 insertions(+) create mode 100644 arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-e3c256d4i.dts diff --git a/arch/arm/boot/dts/aspeed/Makefile b/arch/arm/boot/dts/aspeed/Makefile index 391f0bfa75ce..e51c6d203725 100644 --- a/arch/arm/boot/dts/aspeed/Makefile +++ b/arch/arm/boot/dts/aspeed/Makefile @@ -9,6 +9,7 @@ dtb-$(CONFIG_ARCH_ASPEED) += \ aspeed-bmc-ampere-mtmitchell.dtb \ aspeed-bmc-arm-stardragon4800-rep2.dtb \ aspeed-bmc-asrock-e3c246d4i.dtb \ + aspeed-bmc-asrock-e3c256d4i.dtb \ aspeed-bmc-asrock-romed8hm3.dtb \ aspeed-bmc-asrock-spc621d8hm3.dtb \ aspeed-bmc-asrock-x570d4u.dtb \ diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-e3c256d4i.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-e3c256d4i.dts new file mode 100644 index 000000000000..9d00ce9475f2 --- /dev/null +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-asrock-e3c256d4i.dts @@ -0,0 +1,322 @@ +// SPDX-License-Identifier: GPL-2.0+ +/dts-v1/; + +#include "aspeed-g5.dtsi" +#include +#include +#include +#include +#include + +/{ + model = "ASRock E3C256D4I BMC"; + compatible = "asrock,e3c256d4i-bmc", "aspeed,ast2500"; + + aliases { + serial4 = &uart5; + + i2c20 = &i2c2mux0ch0; + i2c21 = &i2c2mux0ch1; + i2c22 = &i2c2mux0ch2; + i2c23 = &i2c2mux0ch3; + }; + + chosen { + stdout-path = &uart5; + }; + + memory@80000000 { + reg = <0x80000000 0x20000000>; + }; + + leds { + compatible = "gpio-leds"; + + /* BMC heartbeat */ + led-0 { + gpios = <&gpio ASPEED_GPIO(H, 6) GPIO_ACTIVE_LOW>; + function = LED_FUNCTION_HEARTBEAT; + color = ; + linux,default-trigger = "timer"; + }; + + /* system fault */ + led-1 { + gpios = <&gpio ASPEED_GPIO(Z, 2) GPIO_ACTIVE_LOW>; + function = LED_FUNCTION_FAULT; + color = ; + panic-indicator; + }; + }; + + iio-hwmon { + compatible = "iio-hwmon"; + io-channels = <&adc 0>, <&adc 1>, <&adc 2>, <&adc 3>, + <&adc 4>, <&adc 5>, <&adc 6>, <&adc 7>, + <&adc 8>, <&adc 9>, <&adc 10>, <&adc 11>, + <&adc 12>, <&adc 13>, <&adc 14>, <&adc 15>; + }; +}; + +&fmc { + status = "okay"; + flash@0 { + status = "okay"; + m25p,fast-read; + label = "bmc"; + spi-max-frequency = <100000000>; /* 100 MHz */ +#include "openbmc-flash-layout-64.dtsi" + }; +}; + +&uart1 { + status = "okay"; +}; + +&uart2 { + status = "okay"; +}; + +&uart3 { + status = "okay"; +}; + +&uart4 { + status = "okay"; +}; + +&uart5 { + status = "okay"; +}; + +&uart_routing { + status = "okay"; +}; + +&mac0 { + status = "okay"; + + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_rgmii1_default &pinctrl_mdio1_default>; + + nvmem-cells = <ð0_macaddress>; + nvmem-cell-names = "mac-address"; +}; + +&i2c0 { + status = "okay"; +}; + +&i2c1 { + status = "okay"; +}; + +&i2c2 { + status = "okay"; + + i2c-mux@70 { + compatible = "nxp,pca9545"; + reg = <0x70>; + #address-cells = <1>; + #size-cells = <0>; + + i2c2mux0ch0: i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + }; + + i2c2mux0ch1: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + }; + + i2c2mux0ch2: i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + }; + + i2c2mux0ch3: i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + }; + }; +}; + +&i2c3 { + status = "okay"; +}; + +&i2c4 { + status = "okay"; +}; + +&i2c5 { + status = "okay"; +}; + +&i2c6 { + status = "okay"; +}; + +&i2c7 { + status = "okay"; +}; + +&i2c9 { + status = "okay"; +}; + +&i2c10 { + status = "okay"; +}; + +&i2c11 { + status = "okay"; + + vrm@60 { + compatible = "isil,isl69269"; + reg = <0x60>; + }; +}; + +&i2c12 { + status = "okay"; + + /* FRU eeprom */ + eeprom@57 { + compatible = "st,24c128", "atmel,24c128"; + reg = <0x57>; + pagesize = <16>; + #address-cells = <1>; + #size-cells = <1>; + + eth0_macaddress: macaddress@3f80 { + reg = <0x3f80 6>; + }; + }; +}; + +&video { + status = "okay"; +}; + +&vhub { + status = "okay"; +}; + +&lpc_ctrl { + status = "okay"; +}; + +&lpc_snoop { + status = "okay"; + snoop-ports = <0x80>; +}; + +&kcs3 { + status = "okay"; + aspeed,lpc-io-reg = <0xca2>; +}; + +&peci0 { + status = "okay"; +}; + +&wdt1 { + aspeed,reset-mask = <(AST2500_WDT_RESET_DEFAULT & ~AST2500_WDT_RESET_LPC)>; +}; + +&wdt2 { + aspeed,reset-mask = <(AST2500_WDT_RESET_DEFAULT & ~AST2500_WDT_RESET_LPC)>; +}; + +&pwm_tacho { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pwm0_default /* CPU */ + &pinctrl_pwm2_default /* rear */ + &pinctrl_pwm4_default>; /* front */ + + /* CPU */ + fan@0 { + reg = <0x00>; + aspeed,fan-tach-ch = /bits/ 8 <0x00>; + }; + + /* rear */ + fan@2 { + reg = <0x02>; + aspeed,fan-tach-ch = /bits/ 8 <0x02>; + }; + + /* front */ + fan@4 { + reg = <0x04>; + aspeed,fan-tach-ch = /bits/ 8 <0x04>; + }; +}; + +&gpio { + status = "okay"; + gpio-line-names = + /* A */ "", "", "NMI_BTN_N", "BMC_NMI", "", "", "", "", + /* B */ "", "", "", "", "", "", "", "", + /* C */ "", "", "", "", "", "", "", "", + /* D */ "BMC_PSIN", "BMC_PSOUT", "BMC_RESETCON", "RESETCON", + "", "", "", "", + /* E */ "", "", "", "", "", "", "", "", + /* F */ "LOCATORLED_STATUS_N", "LOCATORBTN", "", "", + "", "", "BMC_PCH_SCI_LPC", "BMC_NCSI_MUX_CTL", + /* G */ "HWM_BAT_EN", "CHASSIS_ID0", "CHASSIS_ID1", "CHASSIS_ID2", + "", "", "", "", + /* H */ "FM_ME_RCVR_N", "O_PWROK", "", "D4_DIMM_EVENT_3V_N", + "MFG_MODE_N", "BMC_RTCRST", "BMC_HB_LED_N", "BMC_CASEOPEN", + /* I */ "", "", "", "", "", "", "", "", + /* J */ "BMC_READY", "BMC_PCH_BIOS_CS_N", "BMC_SMI", "", "", "", "", "", + /* K */ "", "", "", "", "", "", "", "", + /* L */ "", "", "", "", "", "", "", "", + /* M */ "", "", "", "", "", "", "", "", + /* N */ "", "", "", "", "", "", "", "", + /* O */ "", "", "", "", "", "", "", "", + /* P */ "", "", "", "", "", "", "", "", + /* Q */ "", "", "", "", "", "", "", "", + /* R */ "", "", "", "", "", "", "", "", + /* S */ "PCHHOT_BMC_N", "", "RSMRST", "", "", "", "", "", + /* T */ "", "", "", "", "", "", "", "", + /* U */ "", "", "", "", "", "", "", "", + /* V */ "", "", "", "", "", "", "", "", + /* W */ "", "", "", "", "", "", "", "", + /* X */ "", "", "", "", "", "", "", "", + /* Y */ "SLP_S3", "SLP_S5", "", "", "", "", "", "", + /* Z */ "CPU_CATERR_BMC_N", "", "SYSTEM_FAULT_LED_N", "BMC_THROTTLE_N", + "", "", "", "", + /* AA */ "CPU1_THERMTRIP_LATCH_N", "", "CPU1_PROCHOT_N", "", + "", "", "IRQ_SMI_ACTIVE_N", "FM_BIOS_POST_CMPLT_N", + /* AB */ "", "", "ME_OVERRIDE", "BMC_DMI_MODIFY", "", "", "", "", + /* AC */ "", "", "", "", "", "", "", ""; +}; + +&adc { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_adc0_default /* 3VSB */ + &pinctrl_adc1_default /* 5VSB */ + &pinctrl_adc2_default /* CPU1 */ + &pinctrl_adc3_default /* VCCSA */ + &pinctrl_adc4_default /* VCCM */ + &pinctrl_adc5_default /* V10M */ + &pinctrl_adc6_default /* VCCIO */ + &pinctrl_adc7_default /* VCCGT */ + &pinctrl_adc8_default /* VPPM */ + &pinctrl_adc9_default /* BAT */ + &pinctrl_adc10_default /* 3V */ + &pinctrl_adc11_default /* 5V */ + &pinctrl_adc12_default /* 12V */ + &pinctrl_adc13_default /* GND */ + &pinctrl_adc14_default /* GND */ + &pinctrl_adc15_default>; /* GND */ +}; -- cgit v1.2.3-59-g8ed1b From 1f82d58ddbe21ed75c04d04403d8268a95e0190a Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Fri, 12 Apr 2024 17:10:56 +0100 Subject: Documentation: ABI + trace: hisi_ptt: update paths to bus/event_source To allow for assigning a suitable parent to the struct pmu device update the documentation to describe the device via the event_source bus where it will remain accessible. For the ABI documention file also rename the file as it is named after the path. Reviewed-by: Yicong Yang Signed-off-by: Jonathan Cameron Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20240412161057.14099-30-Jonathan.Cameron@huawei.com --- .../sysfs-bus-event_source-devices-hisi_ptt | 113 +++++++++++++++++++++ Documentation/ABI/testing/sysfs-devices-hisi_ptt | 113 --------------------- Documentation/trace/hisi-ptt.rst | 4 +- MAINTAINERS | 2 +- 4 files changed, 116 insertions(+), 116 deletions(-) create mode 100644 Documentation/ABI/testing/sysfs-bus-event_source-devices-hisi_ptt delete mode 100644 Documentation/ABI/testing/sysfs-devices-hisi_ptt diff --git a/Documentation/ABI/testing/sysfs-bus-event_source-devices-hisi_ptt b/Documentation/ABI/testing/sysfs-bus-event_source-devices-hisi_ptt new file mode 100644 index 000000000000..1119766564d7 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-bus-event_source-devices-hisi_ptt @@ -0,0 +1,113 @@ +What: /sys/bus/event_source/devices/hisi_ptt_/tune +Date: October 2022 +KernelVersion: 6.1 +Contact: Yicong Yang +Description: This directory contains files for tuning the PCIe link + parameters(events). Each file is named after the event + of the PCIe link. + + See Documentation/trace/hisi-ptt.rst for more information. + +What: /sys/bus/event_source/devices/hisi_ptt_/tune/qos_tx_cpl +Date: October 2022 +KernelVersion: 6.1 +Contact: Yicong Yang +Description: (RW) Controls the weight of Tx completion TLPs, which influence + the proportion of outbound completion TLPs on the PCIe link. + The available tune data is [0, 1, 2]. Writing a negative value + will return an error, and out of range values will be converted + to 2. The value indicates a probable level of the event. + +What: /sys/bus/event_source/devices/hisi_ptt_/tune/qos_tx_np +Date: October 2022 +KernelVersion: 6.1 +Contact: Yicong Yang +Description: (RW) Controls the weight of Tx non-posted TLPs, which influence + the proportion of outbound non-posted TLPs on the PCIe link. + The available tune data is [0, 1, 2]. Writing a negative value + will return an error, and out of range values will be converted + to 2. The value indicates a probable level of the event. + +What: /sys/bus/event_source/devices/hisi_ptt_/tune/qos_tx_p +Date: October 2022 +KernelVersion: 6.1 +Contact: Yicong Yang +Description: (RW) Controls the weight of Tx posted TLPs, which influence the + proportion of outbound posted TLPs on the PCIe link. + The available tune data is [0, 1, 2]. Writing a negative value + will return an error, and out of range values will be converted + to 2. The value indicates a probable level of the event. + +What: /sys/bus/event_source/devices/hisi_ptt_/tune/rx_alloc_buf_level +Date: October 2022 +KernelVersion: 6.1 +Contact: Yicong Yang +Description: (RW) Control the allocated buffer watermark for inbound packets. + The packets will be stored in the buffer first and then transmitted + either when the watermark reached or when timed out. + The available tune data is [0, 1, 2]. Writing a negative value + will return an error, and out of range values will be converted + to 2. The value indicates a probable level of the event. + +What: /sys/bus/event_source/devices/hisi_ptt_/tune/tx_alloc_buf_level +Date: October 2022 +KernelVersion: 6.1 +Contact: Yicong Yang +Description: (RW) Control the allocated buffer watermark of outbound packets. + The packets will be stored in the buffer first and then transmitted + either when the watermark reached or when timed out. + The available tune data is [0, 1, 2]. Writing a negative value + will return an error, and out of range values will be converted + to 2. The value indicates a probable level of the event. + +What: /sys/devices/hisi_ptt_/root_port_filters +Date: May 2023 +KernelVersion: 6.5 +Contact: Yicong Yang +Description: This directory contains the files providing the PCIe Root Port filters + information used for PTT trace. Each file is named after the supported + Root Port device name ::.. + + See the description of the "filter" in Documentation/trace/hisi-ptt.rst + for more information. + +What: /sys/devices/hisi_ptt_/root_port_filters/multiselect +Date: May 2023 +KernelVersion: 6.5 +Contact: Yicong Yang +Description: (Read) Indicates if this kind of filter can be selected at the same + time as others filters, or must be used on it's own. 1 indicates + the former case and 0 indicates the latter. + +What: /sys/devices/hisi_ptt_/root_port_filters/ +Date: May 2023 +KernelVersion: 6.5 +Contact: Yicong Yang +Description: (Read) Indicates the filter value of this Root Port filter, which + can be used to control the TLP headers to trace by the PTT trace. + +What: /sys/devices/hisi_ptt_/requester_filters +Date: May 2023 +KernelVersion: 6.5 +Contact: Yicong Yang +Description: This directory contains the files providing the PCIe Requester filters + information used for PTT trace. Each file is named after the supported + Endpoint device name ::.. + + See the description of the "filter" in Documentation/trace/hisi-ptt.rst + for more information. + +What: /sys/devices/hisi_ptt_/requester_filters/multiselect +Date: May 2023 +KernelVersion: 6.5 +Contact: Yicong Yang +Description: (Read) Indicates if this kind of filter can be selected at the same + time as others filters, or must be used on it's own. 1 indicates + the former case and 0 indicates the latter. + +What: /sys/devices/hisi_ptt_/requester_filters/ +Date: May 2023 +KernelVersion: 6.5 +Contact: Yicong Yang +Description: (Read) Indicates the filter value of this Requester filter, which + can be used to control the TLP headers to trace by the PTT trace. diff --git a/Documentation/ABI/testing/sysfs-devices-hisi_ptt b/Documentation/ABI/testing/sysfs-devices-hisi_ptt deleted file mode 100644 index d7e206b4901c..000000000000 --- a/Documentation/ABI/testing/sysfs-devices-hisi_ptt +++ /dev/null @@ -1,113 +0,0 @@ -What: /sys/devices/hisi_ptt_/tune -Date: October 2022 -KernelVersion: 6.1 -Contact: Yicong Yang -Description: This directory contains files for tuning the PCIe link - parameters(events). Each file is named after the event - of the PCIe link. - - See Documentation/trace/hisi-ptt.rst for more information. - -What: /sys/devices/hisi_ptt_/tune/qos_tx_cpl -Date: October 2022 -KernelVersion: 6.1 -Contact: Yicong Yang -Description: (RW) Controls the weight of Tx completion TLPs, which influence - the proportion of outbound completion TLPs on the PCIe link. - The available tune data is [0, 1, 2]. Writing a negative value - will return an error, and out of range values will be converted - to 2. The value indicates a probable level of the event. - -What: /sys/devices/hisi_ptt_/tune/qos_tx_np -Date: October 2022 -KernelVersion: 6.1 -Contact: Yicong Yang -Description: (RW) Controls the weight of Tx non-posted TLPs, which influence - the proportion of outbound non-posted TLPs on the PCIe link. - The available tune data is [0, 1, 2]. Writing a negative value - will return an error, and out of range values will be converted - to 2. The value indicates a probable level of the event. - -What: /sys/devices/hisi_ptt_/tune/qos_tx_p -Date: October 2022 -KernelVersion: 6.1 -Contact: Yicong Yang -Description: (RW) Controls the weight of Tx posted TLPs, which influence the - proportion of outbound posted TLPs on the PCIe link. - The available tune data is [0, 1, 2]. Writing a negative value - will return an error, and out of range values will be converted - to 2. The value indicates a probable level of the event. - -What: /sys/devices/hisi_ptt_/tune/rx_alloc_buf_level -Date: October 2022 -KernelVersion: 6.1 -Contact: Yicong Yang -Description: (RW) Control the allocated buffer watermark for inbound packets. - The packets will be stored in the buffer first and then transmitted - either when the watermark reached or when timed out. - The available tune data is [0, 1, 2]. Writing a negative value - will return an error, and out of range values will be converted - to 2. The value indicates a probable level of the event. - -What: /sys/devices/hisi_ptt_/tune/tx_alloc_buf_level -Date: October 2022 -KernelVersion: 6.1 -Contact: Yicong Yang -Description: (RW) Control the allocated buffer watermark of outbound packets. - The packets will be stored in the buffer first and then transmitted - either when the watermark reached or when timed out. - The available tune data is [0, 1, 2]. Writing a negative value - will return an error, and out of range values will be converted - to 2. The value indicates a probable level of the event. - -What: /sys/devices/hisi_ptt_/root_port_filters -Date: May 2023 -KernelVersion: 6.5 -Contact: Yicong Yang -Description: This directory contains the files providing the PCIe Root Port filters - information used for PTT trace. Each file is named after the supported - Root Port device name ::.. - - See the description of the "filter" in Documentation/trace/hisi-ptt.rst - for more information. - -What: /sys/devices/hisi_ptt_/root_port_filters/multiselect -Date: May 2023 -KernelVersion: 6.5 -Contact: Yicong Yang -Description: (Read) Indicates if this kind of filter can be selected at the same - time as others filters, or must be used on it's own. 1 indicates - the former case and 0 indicates the latter. - -What: /sys/devices/hisi_ptt_/root_port_filters/ -Date: May 2023 -KernelVersion: 6.5 -Contact: Yicong Yang -Description: (Read) Indicates the filter value of this Root Port filter, which - can be used to control the TLP headers to trace by the PTT trace. - -What: /sys/devices/hisi_ptt_/requester_filters -Date: May 2023 -KernelVersion: 6.5 -Contact: Yicong Yang -Description: This directory contains the files providing the PCIe Requester filters - information used for PTT trace. Each file is named after the supported - Endpoint device name ::.. - - See the description of the "filter" in Documentation/trace/hisi-ptt.rst - for more information. - -What: /sys/devices/hisi_ptt_/requester_filters/multiselect -Date: May 2023 -KernelVersion: 6.5 -Contact: Yicong Yang -Description: (Read) Indicates if this kind of filter can be selected at the same - time as others filters, or must be used on it's own. 1 indicates - the former case and 0 indicates the latter. - -What: /sys/devices/hisi_ptt_/requester_filters/ -Date: May 2023 -KernelVersion: 6.5 -Contact: Yicong Yang -Description: (Read) Indicates the filter value of this Requester filter, which - can be used to control the TLP headers to trace by the PTT trace. diff --git a/Documentation/trace/hisi-ptt.rst b/Documentation/trace/hisi-ptt.rst index 989255eb5622..6eef28ebb0c7 100644 --- a/Documentation/trace/hisi-ptt.rst +++ b/Documentation/trace/hisi-ptt.rst @@ -40,7 +40,7 @@ IO dies (SICL, Super I/O Cluster), where there's one PCIe Root Complex for each SICL. :: - /sys/devices/hisi_ptt_ + /sys/bus/event_source/devices/hisi_ptt_ Tune ==== @@ -53,7 +53,7 @@ Each event is presented as a file under $(PTT PMU dir)/tune, and a simple open/read/write/close cycle will be used to tune the event. :: - $ cd /sys/devices/hisi_ptt_/tune + $ cd /sys/bus/event_source/devices/hisi_ptt_/tune $ ls qos_tx_cpl qos_tx_np qos_tx_p tx_path_rx_req_alloc_buf_level diff --git a/MAINTAINERS b/MAINTAINERS index c23fda1aa1f0..63a55f1559f4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9790,7 +9790,7 @@ M: Yicong Yang M: Jonathan Cameron L: linux-kernel@vger.kernel.org S: Maintained -F: Documentation/ABI/testing/sysfs-devices-hisi_ptt +F: Documentation/ABI/testing/sysfs-bus-event_source-devices-hisi_ptt F: Documentation/trace/hisi-ptt.rst F: drivers/hwtracing/ptt/ F: tools/perf/arch/arm64/util/hisi-ptt.c -- cgit v1.2.3-59-g8ed1b From 9b47d9982d1de5adf0abcb8f1a400e51d68cca1f Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Fri, 12 Apr 2024 17:10:57 +0100 Subject: hwtracing: hisi_ptt: Assign parent for event_source device Currently the PMU device appears directly under /sys/devices/ Only root busses should appear there, so instead assign the pmu->dev parent to be the PCI device. Link: https://lore.kernel.org/linux-cxl/ZCLI9A40PJsyqAmq@kroah.com/ Cc: Suzuki K Poulose Reviewed-by: Yicong Yang Signed-off-by: Jonathan Cameron Acked-by: Suzuki K Poulose Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20240412161057.14099-31-Jonathan.Cameron@huawei.com --- drivers/hwtracing/ptt/hisi_ptt.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/hwtracing/ptt/hisi_ptt.c b/drivers/hwtracing/ptt/hisi_ptt.c index 4bf04a977840..3090479a2979 100644 --- a/drivers/hwtracing/ptt/hisi_ptt.c +++ b/drivers/hwtracing/ptt/hisi_ptt.c @@ -1221,6 +1221,7 @@ static int hisi_ptt_register_pmu(struct hisi_ptt *hisi_ptt) hisi_ptt->hisi_ptt_pmu = (struct pmu) { .module = THIS_MODULE, + .parent = &hisi_ptt->pdev->dev, .capabilities = PERF_PMU_CAP_EXCLUSIVE | PERF_PMU_CAP_NO_EXCLUDE, .task_ctx_nr = perf_sw_context, .attr_groups = hisi_ptt_pmu_groups, -- cgit v1.2.3-59-g8ed1b From d7b60803a790b716dc930bde2155c6ecb7537d51 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 1 May 2024 23:00:06 -0700 Subject: perf dwarf-aux: Add die_collect_global_vars() This function is to search all global variables in the CU. We want to have the list of global variables at once and match them later. Signed-off-by: Namhyung Kim Cc: Adrian Hunter Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Masami Hiramatsu Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20240502060011.1838090-2-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/dwarf-aux.c | 62 +++++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/dwarf-aux.h | 8 ++++++ 2 files changed, 70 insertions(+) diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c index 40cfbdfe2d75..c0a492e65388 100644 --- a/tools/perf/util/dwarf-aux.c +++ b/tools/perf/util/dwarf-aux.c @@ -1630,6 +1630,68 @@ void die_collect_vars(Dwarf_Die *sc_die, struct die_var_type **var_types) die_find_child(sc_die, __die_collect_vars_cb, (void *)var_types, &die_mem); } + +static int __die_collect_global_vars_cb(Dwarf_Die *die_mem, void *arg) +{ + struct die_var_type **var_types = arg; + Dwarf_Die type_die; + int tag = dwarf_tag(die_mem); + Dwarf_Attribute attr; + Dwarf_Addr base, start, end; + Dwarf_Op *ops; + size_t nops; + struct die_var_type *vt; + + if (tag != DW_TAG_variable) + return DIE_FIND_CB_SIBLING; + + if (dwarf_attr(die_mem, DW_AT_location, &attr) == NULL) + return DIE_FIND_CB_SIBLING; + + /* Only collect the location with an absolute address. */ + if (dwarf_getlocations(&attr, 0, &base, &start, &end, &ops, &nops) <= 0) + return DIE_FIND_CB_SIBLING; + + if (ops->atom != DW_OP_addr) + return DIE_FIND_CB_SIBLING; + + if (!check_allowed_ops(ops, nops)) + return DIE_FIND_CB_SIBLING; + + if (die_get_real_type(die_mem, &type_die) == NULL) + return DIE_FIND_CB_SIBLING; + + vt = malloc(sizeof(*vt)); + if (vt == NULL) + return DIE_FIND_CB_END; + + vt->die_off = dwarf_dieoffset(&type_die); + vt->addr = ops->number; + vt->reg = -1; + vt->offset = 0; + vt->next = *var_types; + *var_types = vt; + + return DIE_FIND_CB_SIBLING; +} + +/** + * die_collect_global_vars - Save all global variables + * @cu_die: a CU DIE + * @var_types: a pointer to save the resulting list + * + * Save all global variables in the @cu_die and save them to @var_types. + * The @var_types is a singly-linked list containing type and location info. + * Actual type can be retrieved using dwarf_offdie() with 'die_off' later. + * + * Callers should free @var_types. + */ +void die_collect_global_vars(Dwarf_Die *cu_die, struct die_var_type **var_types) +{ + Dwarf_Die die_mem; + + die_find_child(cu_die, __die_collect_global_vars_cb, (void *)var_types, &die_mem); +} #endif /* HAVE_DWARF_GETLOCATIONS_SUPPORT */ #ifdef HAVE_DWARF_CFI_SUPPORT diff --git a/tools/perf/util/dwarf-aux.h b/tools/perf/util/dwarf-aux.h index b0f25fbf9668..24446412b869 100644 --- a/tools/perf/util/dwarf-aux.h +++ b/tools/perf/util/dwarf-aux.h @@ -171,6 +171,9 @@ Dwarf_Die *die_find_variable_by_addr(Dwarf_Die *sc_die, Dwarf_Addr addr, /* Save all variables and parameters in this scope */ void die_collect_vars(Dwarf_Die *sc_die, struct die_var_type **var_types); +/* Save all global variables in this CU */ +void die_collect_global_vars(Dwarf_Die *cu_die, struct die_var_type **var_types); + #else /* HAVE_DWARF_GETLOCATIONS_SUPPORT */ static inline int die_get_var_range(Dwarf_Die *sp_die __maybe_unused, @@ -203,6 +206,11 @@ static inline void die_collect_vars(Dwarf_Die *sc_die __maybe_unused, { } +static inline void die_collect_global_vars(Dwarf_Die *cu_die __maybe_unused, + struct die_var_type **var_types __maybe_unused) +{ +} + #endif /* HAVE_DWARF_GETLOCATIONS_SUPPORT */ #ifdef HAVE_DWARF_CFI_SUPPORT -- cgit v1.2.3-59-g8ed1b From c1da8411e4be2a96a448979baede9a0e86c5baf8 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 1 May 2024 23:00:07 -0700 Subject: perf annotate-data: Collect global variables in advance Currently it looks up global variables from the current CU using address and name. But it sometimes fails to find a variable as the variable can come from a different CU - but it's still strange it failed to find a declaration for some reason. Anyway, it can collect all global variables from all CU once and then lookup them later on. This slightly improves the success rate of my test data set. Signed-off-by: Namhyung Kim Cc: Adrian Hunter Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20240502060011.1838090-3-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate-data.c | 57 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 55 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c index 12d5faff3b7a..4dd0911904f2 100644 --- a/tools/perf/util/annotate-data.c +++ b/tools/perf/util/annotate-data.c @@ -28,6 +28,8 @@ /* register number of the stack pointer */ #define X86_REG_SP 7 +static void delete_var_types(struct die_var_type *var_types); + enum type_state_kind { TSR_KIND_INVALID = 0, TSR_KIND_TYPE, @@ -557,8 +559,8 @@ static bool global_var__add(struct data_loc_info *dloc, u64 addr, if (gvar == NULL) return false; - gvar->name = strdup(name); - if (gvar->name == NULL) { + gvar->name = name ? strdup(name) : NULL; + if (name && gvar->name == NULL) { free(gvar); return false; } @@ -612,6 +614,53 @@ static bool get_global_var_info(struct data_loc_info *dloc, u64 addr, return true; } +static void global_var__collect(struct data_loc_info *dloc) +{ + Dwarf *dwarf = dloc->di->dbg; + Dwarf_Off off, next_off; + Dwarf_Die cu_die, type_die; + size_t header_size; + + /* Iterate all CU and collect global variables that have no location in a register. */ + off = 0; + while (dwarf_nextcu(dwarf, off, &next_off, &header_size, + NULL, NULL, NULL) == 0) { + struct die_var_type *var_types = NULL; + struct die_var_type *pos; + + if (dwarf_offdie(dwarf, off + header_size, &cu_die) == NULL) { + off = next_off; + continue; + } + + die_collect_global_vars(&cu_die, &var_types); + + for (pos = var_types; pos; pos = pos->next) { + const char *var_name = NULL; + int var_offset = 0; + + if (pos->reg != -1) + continue; + + if (!dwarf_offdie(dwarf, pos->die_off, &type_die)) + continue; + + if (!get_global_var_info(dloc, pos->addr, &var_name, + &var_offset)) + continue; + + if (var_offset != 0) + continue; + + global_var__add(dloc, pos->addr, var_name, &type_die); + } + + delete_var_types(var_types); + + off = next_off; + } +} + static bool get_global_var_type(Dwarf_Die *cu_die, struct data_loc_info *dloc, u64 ip, u64 var_addr, int *var_offset, Dwarf_Die *type_die) @@ -620,8 +669,12 @@ static bool get_global_var_type(Dwarf_Die *cu_die, struct data_loc_info *dloc, int offset; const char *var_name = NULL; struct global_var_entry *gvar; + struct dso *dso = map__dso(dloc->ms->map); Dwarf_Die var_die; + if (RB_EMPTY_ROOT(&dso->global_vars)) + global_var__collect(dloc); + gvar = global_var__find(dloc, var_addr); if (gvar) { if (!dwarf_offdie(dloc->di->dbg, gvar->die_offset, type_die)) -- cgit v1.2.3-59-g8ed1b From 4449c9047dc6f9f68333a720958cd7b58225910d Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 1 May 2024 23:00:08 -0700 Subject: perf annotate-data: Handle direct global variable access Like per-cpu base offset array, sometimes it accesses the global variable directly using the offset. Allow this type of instructions as long as it finds a global variable for the address. movslq %edi, %rcx mov -0x7dc94ae0(,%rcx,8), %rcx <<<--- here As %rcx has a valid type (i.e. array index) from the first instruction, it will be checked by the first case in check_matching_type(). But as it's not a pointer type, the match will fail. But in this case, it should check if it accesses the kernel global array variable. Signed-off-by: Namhyung Kim Cc: Adrian Hunter Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20240502060011.1838090-4-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate-data.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c index 4dd0911904f2..f1e52a531563 100644 --- a/tools/perf/util/annotate-data.c +++ b/tools/perf/util/annotate-data.c @@ -1256,14 +1256,19 @@ static int check_matching_type(struct type_state *state, if (state->regs[reg].ok && state->regs[reg].kind == TSR_KIND_TYPE) { int tag = dwarf_tag(&state->regs[reg].type); - pr_debug_dtp("\n"); - /* * Normal registers should hold a pointer (or array) to * dereference a memory location. */ - if (tag != DW_TAG_pointer_type && tag != DW_TAG_array_type) + if (tag != DW_TAG_pointer_type && tag != DW_TAG_array_type) { + if (dloc->op->offset < 0 && reg != state->stack_reg) + goto check_kernel; + + pr_debug_dtp("\n"); return -1; + } + + pr_debug_dtp("\n"); /* Remove the pointer and get the target type */ if (die_get_real_type(&state->regs[reg].type, type_die) == NULL) @@ -1376,12 +1381,14 @@ static int check_matching_type(struct type_state *state, return -1; } - if (map__dso(dloc->ms->map)->kernel && arch__is(dloc->arch, "x86")) { +check_kernel: + if (map__dso(dloc->ms->map)->kernel) { u64 addr; int offset; /* Direct this-cpu access like "%gs:0x34740" */ - if (dloc->op->segment == INSN_SEG_X86_GS && dloc->op->imm) { + if (dloc->op->segment == INSN_SEG_X86_GS && dloc->op->imm && + arch__is(dloc->arch, "x86")) { pr_debug_dtp(" this-cpu var\n"); addr = dloc->op->offset; @@ -1394,17 +1401,13 @@ static int check_matching_type(struct type_state *state, return -1; } - /* Access to per-cpu base like "-0x7dcf0500(,%rdx,8)" */ + /* Access to global variable like "-0x7dcf0500(,%rdx,8)" */ if (dloc->op->offset < 0 && reg != state->stack_reg) { - const char *var_name = NULL; - addr = (s64) dloc->op->offset; - if (get_global_var_info(dloc, addr, &var_name, &offset) && - !strcmp(var_name, "__per_cpu_offset") && offset == 0 && - get_global_var_type(cu_die, dloc, dloc->ip, addr, + if (get_global_var_type(cu_die, dloc, dloc->ip, addr, &offset, type_die)) { - pr_debug_dtp(" percpu base\n"); + pr_debug_dtp(" global var\n"); dloc->type_offset = offset; return 1; -- cgit v1.2.3-59-g8ed1b From eba1f853edf794ec259ec7b5e5a6efee5ede989f Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 1 May 2024 23:00:09 -0700 Subject: perf annotate-data: Check memory access with two registers The following instruction pattern is used to access a global variable. mov $0x231c0, %rax movsql %edi, %rcx mov -0x7dc94ae0(,%rcx,8), %rcx cmpl $0x0, 0xa60(%rcx,%rax,1) <<<--- here The first instruction set the address of the per-cpu variable (here, it is 'runqueues' of type 'struct rq'). The second instruction seems like a cpu number of the per-cpu base. The third instruction get the base offset of per-cpu area for that cpu. The last instruction compares the value of the per-cpu variable at the offset of 0xa60. Signed-off-by: Namhyung Kim Cc: Adrian Hunter Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20240502060011.1838090-5-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate-data.c | 44 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c index f1e52a531563..245e3ef3e2ff 100644 --- a/tools/perf/util/annotate-data.c +++ b/tools/perf/util/annotate-data.c @@ -1031,22 +1031,37 @@ retry: else if (has_reg_type(state, sreg) && state->regs[sreg].kind == TSR_KIND_PERCPU_BASE) { u64 ip = dloc->ms->sym->start + dl->al.offset; + u64 var_addr = src->offset; int offset; + if (src->multi_regs) { + int reg2 = (sreg == src->reg1) ? src->reg2 : src->reg1; + + if (has_reg_type(state, reg2) && state->regs[reg2].ok && + state->regs[reg2].kind == TSR_KIND_CONST) + var_addr += state->regs[reg2].imm_value; + } + /* * In kernel, %gs points to a per-cpu region for the * current CPU. Access with a constant offset should * be treated as a global variable access. */ - if (get_global_var_type(cu_die, dloc, ip, src->offset, + if (get_global_var_type(cu_die, dloc, ip, var_addr, &offset, &type_die) && die_get_member_type(&type_die, offset, &type_die)) { tsr->type = type_die; tsr->kind = TSR_KIND_TYPE; tsr->ok = true; - pr_debug_dtp("mov [%x] percpu %#x(reg%d) -> reg%d", - insn_offset, src->offset, sreg, dst->reg1); + if (src->multi_regs) { + pr_debug_dtp("mov [%x] percpu %#x(reg%d,reg%d) -> reg%d", + insn_offset, src->offset, src->reg1, + src->reg2, dst->reg1); + } else { + pr_debug_dtp("mov [%x] percpu %#x(reg%d) -> reg%d", + insn_offset, src->offset, sreg, dst->reg1); + } pr_debug_type_name(&tsr->type, tsr->kind); } else { tsr->ok = false; @@ -1340,6 +1355,17 @@ static int check_matching_type(struct type_state *state, pr_debug_dtp(" percpu var\n"); + if (dloc->op->multi_regs) { + int reg2 = dloc->op->reg2; + + if (dloc->op->reg2 == reg) + reg2 = dloc->op->reg1; + + if (has_reg_type(state, reg2) && state->regs[reg2].ok && + state->regs[reg2].kind == TSR_KIND_CONST) + var_addr += state->regs[reg2].imm_value; + } + if (get_global_var_type(cu_die, dloc, dloc->ip, var_addr, &var_offset, type_die)) { dloc->type_offset = var_offset; @@ -1527,8 +1553,16 @@ again: found = find_data_type_insn(dloc, reg, &basic_blocks, var_types, cu_die, type_die); if (found > 0) { - pr_debug_dtp("found by insn track: %#x(reg%d) type-offset=%#x\n", - dloc->op->offset, reg, dloc->type_offset); + char buf[64]; + + if (dloc->op->multi_regs) + snprintf(buf, sizeof(buf), "reg%d, reg%d", + dloc->op->reg1, dloc->op->reg2); + else + snprintf(buf, sizeof(buf), "reg%d", dloc->op->reg1); + + pr_debug_dtp("found by insn track: %#x(%s) type-offset=%#x\n", + dloc->op->offset, buf, dloc->type_offset); pr_debug_type_name(type_die, TSR_KIND_TYPE); ret = 0; break; -- cgit v1.2.3-59-g8ed1b From a1191a77351e25ddf091bb1a231cae12ee598b5d Mon Sep 17 00:00:00 2001 From: Julien Panis Date: Thu, 2 May 2024 15:46:03 +0200 Subject: thermal/drivers/mediatek/lvts_thermal: Check NULL ptr on lvts_data Verify that lvts_data is not NULL before using it. Signed-off-by: Julien Panis Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20240502-mtk-thermal-lvts-data-v1-1-65f1b0bfad37@baylibre.com --- drivers/thermal/mediatek/lvts_thermal.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/thermal/mediatek/lvts_thermal.c b/drivers/thermal/mediatek/lvts_thermal.c index 86b2f44355ac..20a64b68f9c0 100644 --- a/drivers/thermal/mediatek/lvts_thermal.c +++ b/drivers/thermal/mediatek/lvts_thermal.c @@ -1271,6 +1271,8 @@ static int lvts_probe(struct platform_device *pdev) return -ENOMEM; lvts_data = of_device_get_match_data(dev); + if (!lvts_data) + return -ENODEV; lvts_td->clk = devm_clk_get_enabled(dev, NULL); if (IS_ERR(lvts_td->clk)) -- cgit v1.2.3-59-g8ed1b From af89e8f2bdb2ff9252317307a755f97dd02f6cd7 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 1 May 2024 23:00:10 -0700 Subject: perf annotate-data: Handle multi regs in find_data_type_block() The instruction tracking should be the same for the both registers. Just do it once and compare the result with multi regs as with the previous patches. Then we don't need to call find_data_type_block() separately for each reg. Let's remove the 'reg' argument from the relevant functions. Signed-off-by: Namhyung Kim Cc: Adrian Hunter Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20240502060011.1838090-6-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate-data.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c index 245e3ef3e2ff..68fe7999f033 100644 --- a/tools/perf/util/annotate-data.c +++ b/tools/perf/util/annotate-data.c @@ -1258,11 +1258,12 @@ static void setup_stack_canary(struct data_loc_info *dloc) * are similar to global variables and no additional info is needed. */ static int check_matching_type(struct type_state *state, - struct data_loc_info *dloc, int reg, + struct data_loc_info *dloc, Dwarf_Die *cu_die, Dwarf_Die *type_die) { Dwarf_Word size; u32 insn_offset = dloc->ip - dloc->ms->sym->start; + int reg = dloc->op->reg1; pr_debug_dtp("chk [%x] reg%d offset=%#x ok=%d kind=%d", insn_offset, reg, dloc->op->offset, @@ -1448,7 +1449,7 @@ check_kernel: } /* Iterate instructions in basic blocks and update type table */ -static int find_data_type_insn(struct data_loc_info *dloc, int reg, +static int find_data_type_insn(struct data_loc_info *dloc, struct list_head *basic_blocks, struct die_var_type *var_types, Dwarf_Die *cu_die, Dwarf_Die *type_die) @@ -1481,7 +1482,7 @@ static int find_data_type_insn(struct data_loc_info *dloc, int reg, update_var_state(&state, dloc, addr, dl->al.offset, var_types); if (this_ip == dloc->ip) { - ret = check_matching_type(&state, dloc, reg, + ret = check_matching_type(&state, dloc, cu_die, type_die); goto out; } @@ -1502,7 +1503,7 @@ out: * Construct a list of basic blocks for each scope with variables and try to find * the data type by updating a type state table through instructions. */ -static int find_data_type_block(struct data_loc_info *dloc, int reg, +static int find_data_type_block(struct data_loc_info *dloc, Dwarf_Die *cu_die, Dwarf_Die *scopes, int nr_scopes, Dwarf_Die *type_die) { @@ -1550,7 +1551,7 @@ again: fixup_var_address(var_types, start); /* Find from start of this scope to the target instruction */ - found = find_data_type_insn(dloc, reg, &basic_blocks, var_types, + found = find_data_type_insn(dloc, &basic_blocks, var_types, cu_die, type_die); if (found > 0) { char buf[64]; @@ -1716,8 +1717,13 @@ retry: goto out; } + if (loc->multi_regs && reg == loc->reg1 && loc->reg1 != loc->reg2) { + reg = loc->reg2; + goto retry; + } + if (reg != DWARF_REG_PC) { - ret = find_data_type_block(dloc, reg, &cu_die, scopes, + ret = find_data_type_block(dloc, &cu_die, scopes, nr_scopes, type_die); if (ret == 0) { ann_data_stat.insn_track++; @@ -1725,11 +1731,6 @@ retry: } } - if (loc->multi_regs && reg == loc->reg1 && loc->reg1 != loc->reg2) { - reg = loc->reg2; - goto retry; - } - if (ret < 0) { pr_debug_dtp("no variable found\n"); ann_data_stat.no_var++; -- cgit v1.2.3-59-g8ed1b From b7d4aacfc894ca2d86b11ef738f94e6c8cf2536b Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 1 May 2024 23:00:11 -0700 Subject: perf annotate-data: Check kind of stack variables I sometimes see ("unknown type") in the result and it was because it didn't check the type of stack variables properly during the instruction tracking. The stack can carry constant values (without type info) and if the target instruction is accessing the stack location, it resulted in the "unknown type". Maybe we could pick one of integer types for the constant, but it doesn't really mean anything useful. Let's just drop the stack slot if it doesn't have a valid type info. Here's an example how it got the unknown type. Note that 0xffffff48 = -0xb8. ----------------------------------------------------------- find data type for 0xffffff48(reg6) at ... CU for ... frame base: cfa=0 fbreg=6 scope: [2/2] (die:11cb97f) bb: [37 - 3a] var [37] reg15 type='int' size=0x4 (die:0x1180633) bb: [40 - 4b] mov [40] imm=0x1 -> reg13 var [45] reg8 type='sigset_t*' size=0x8 (die:0x11a39ee) mov [45] imm=0x1 -> reg2 <--- here reg2 has a constant bb: [215 - 237] mov [218] reg2 -> -0xb8(stack) constant <--- and save it to the stack mov [225] reg13 -> -0xc4(stack) constant call [22f] find_task_by_vgpid call [22f] return -> reg0 type='struct task_struct*' size=0x8 (die:0x11881e8) bb: [5c8 - 5cf] bb: [2fb - 302] mov [2fb] -0xc4(stack) -> reg13 constant bb: [13b - 14d] mov [143] 0xd50(reg3) -> reg5 type='struct task_struct*' size=0x8 (die:0xa31f3c) bb: [153 - 153] chk [153] reg6 offset=0xffffff48 ok=0 kind=0 fbreg <--- access here found by insn track: 0xffffff48(reg6) type-offset=0 type='G^KU' size=0 (die:0xffffffffffffffff) Signed-off-by: Namhyung Kim Cc: Adrian Hunter Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20240502060011.1838090-7-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate-data.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c index 68fe7999f033..2c98813f95cd 100644 --- a/tools/perf/util/annotate-data.c +++ b/tools/perf/util/annotate-data.c @@ -1314,6 +1314,9 @@ static int check_matching_type(struct type_state *state, return -1; } + if (stack->kind != TSR_KIND_TYPE) + return 0; + *type_die = stack->type; /* Update the type offset from the start of slot */ dloc->type_offset -= stack->offset; @@ -1343,6 +1346,9 @@ static int check_matching_type(struct type_state *state, return -1; } + if (stack->kind != TSR_KIND_TYPE) + return 0; + *type_die = stack->type; /* Update the type offset from the start of slot */ dloc->type_offset -= fboff + stack->offset; -- cgit v1.2.3-59-g8ed1b From cbaf2c4f932e08c9e3df2903cf1559a32defbc41 Mon Sep 17 00:00:00 2001 From: James Clark Date: Wed, 1 May 2024 14:57:51 +0100 Subject: perf cs-etm: Use struct perf_cpu as much as possible The perf_cpu struct makes some iterators simpler and avoids some mistakes with interchanging CPU IDs with indexes etc. At the moment in this file the conversion to an integer is done somewhere in the middle of the call tree. Change it to delay the conversion to an int until the leaf functions. Some of the usage patterns are duplicated, so instead of changing them all, make cs_etm_get_ro() more reusable and use that everywhere. cs_etm_get_ro() didn't return an error before, but return one now so that it can also be used where an error is needed. Continue to ignore the error where it was already ignored. Use cs_etm_pmu_path_exists() instead of cs_etm_get_ro() in cs_etm_is_etmv4() because cs_etm_get_ro() prints a warning, but path exists is sufficient for this use case. Signed-off-by: James Clark Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: John Garry Cc: Kan Liang Cc: Leo Yan Cc: Mark Rutland Cc: Mike Leach Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Suzuki Poulouse Cc: Will Deacon Link: https://lore.kernel.org/r/20240501135753.508022-2-james.clark@arm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/arch/arm/util/cs-etm.c | 204 ++++++++++++++++---------------------- 1 file changed, 88 insertions(+), 116 deletions(-) diff --git a/tools/perf/arch/arm/util/cs-etm.c b/tools/perf/arch/arm/util/cs-etm.c index 07be32d99805..a1fa711dc41a 100644 --- a/tools/perf/arch/arm/util/cs-etm.c +++ b/tools/perf/arch/arm/util/cs-etm.c @@ -66,18 +66,19 @@ static const char * const metadata_ete_ro[] = { [CS_ETE_TS_SOURCE] = "ts_source", }; -static bool cs_etm_is_etmv4(struct auxtrace_record *itr, int cpu); -static bool cs_etm_is_ete(struct auxtrace_record *itr, int cpu); +static bool cs_etm_is_etmv4(struct auxtrace_record *itr, struct perf_cpu cpu); +static bool cs_etm_is_ete(struct auxtrace_record *itr, struct perf_cpu cpu); +static int cs_etm_get_ro(struct perf_pmu *pmu, struct perf_cpu cpu, const char *path, __u64 *val); +static bool cs_etm_pmu_path_exists(struct perf_pmu *pmu, struct perf_cpu cpu, const char *path); -static int cs_etm_validate_context_id(struct auxtrace_record *itr, - struct evsel *evsel, int cpu) +static int cs_etm_validate_context_id(struct auxtrace_record *itr, struct evsel *evsel, + struct perf_cpu cpu) { struct cs_etm_recording *ptr = container_of(itr, struct cs_etm_recording, itr); struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; - char path[PATH_MAX]; int err; - u32 val; + __u64 val; u64 contextid = evsel->core.attr.config & (perf_pmu__format_bits(cs_etm_pmu, "contextid") | perf_pmu__format_bits(cs_etm_pmu, "contextid1") | @@ -94,16 +95,9 @@ static int cs_etm_validate_context_id(struct auxtrace_record *itr, } /* Get a handle on TRCIDR2 */ - snprintf(path, PATH_MAX, "cpu%d/%s", - cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR2]); - err = perf_pmu__scan_file(cs_etm_pmu, path, "%x", &val); - - /* There was a problem reading the file, bailing out */ - if (err != 1) { - pr_err("%s: can't read file %s\n", CORESIGHT_ETM_PMU_NAME, - path); + err = cs_etm_get_ro(cs_etm_pmu, cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR2], &val); + if (err) return err; - } if (contextid & perf_pmu__format_bits(cs_etm_pmu, "contextid1")) { @@ -140,15 +134,14 @@ static int cs_etm_validate_context_id(struct auxtrace_record *itr, return 0; } -static int cs_etm_validate_timestamp(struct auxtrace_record *itr, - struct evsel *evsel, int cpu) +static int cs_etm_validate_timestamp(struct auxtrace_record *itr, struct evsel *evsel, + struct perf_cpu cpu) { struct cs_etm_recording *ptr = container_of(itr, struct cs_etm_recording, itr); struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; - char path[PATH_MAX]; int err; - u32 val; + __u64 val; if (!(evsel->core.attr.config & perf_pmu__format_bits(cs_etm_pmu, "timestamp"))) @@ -161,16 +154,9 @@ static int cs_etm_validate_timestamp(struct auxtrace_record *itr, } /* Get a handle on TRCIRD0 */ - snprintf(path, PATH_MAX, "cpu%d/%s", - cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR0]); - err = perf_pmu__scan_file(cs_etm_pmu, path, "%x", &val); - - /* There was a problem reading the file, bailing out */ - if (err != 1) { - pr_err("%s: can't read file %s\n", - CORESIGHT_ETM_PMU_NAME, path); + err = cs_etm_get_ro(cs_etm_pmu, cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR0], &val); + if (err) return err; - } /* * TRCIDR0.TSSIZE, bit [28-24], indicates whether global timestamping @@ -218,11 +204,11 @@ static int cs_etm_validate_config(struct auxtrace_record *itr, } perf_cpu_map__for_each_cpu_skip_any(cpu, idx, intersect_cpus) { - err = cs_etm_validate_context_id(itr, evsel, cpu.cpu); + err = cs_etm_validate_context_id(itr, evsel, cpu); if (err) break; - err = cs_etm_validate_timestamp(itr, evsel, cpu.cpu); + err = cs_etm_validate_timestamp(itr, evsel, cpu); if (err) break; } @@ -549,9 +535,9 @@ cs_etm_info_priv_size(struct auxtrace_record *itr __maybe_unused, intersect_cpus = perf_cpu_map__new_online_cpus(); } perf_cpu_map__for_each_cpu_skip_any(cpu, idx, intersect_cpus) { - if (cs_etm_is_ete(itr, cpu.cpu)) + if (cs_etm_is_ete(itr, cpu)) ete++; - else if (cs_etm_is_etmv4(itr, cpu.cpu)) + else if (cs_etm_is_etmv4(itr, cpu)) etmv4++; else etmv3++; @@ -564,66 +550,59 @@ cs_etm_info_priv_size(struct auxtrace_record *itr __maybe_unused, (etmv3 * CS_ETMV3_PRIV_SIZE)); } -static bool cs_etm_is_etmv4(struct auxtrace_record *itr, int cpu) +static bool cs_etm_is_etmv4(struct auxtrace_record *itr, struct perf_cpu cpu) { - bool ret = false; - char path[PATH_MAX]; - int scan; - unsigned int val; struct cs_etm_recording *ptr = container_of(itr, struct cs_etm_recording, itr); struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; /* Take any of the RO files for ETMv4 and see if it present */ - snprintf(path, PATH_MAX, "cpu%d/%s", - cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR0]); - scan = perf_pmu__scan_file(cs_etm_pmu, path, "%x", &val); - - /* The file was read successfully, we have a winner */ - if (scan == 1) - ret = true; - - return ret; + return cs_etm_pmu_path_exists(cs_etm_pmu, cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR0]); } -static int cs_etm_get_ro(struct perf_pmu *pmu, int cpu, const char *path) +static int cs_etm_get_ro(struct perf_pmu *pmu, struct perf_cpu cpu, const char *path, __u64 *val) { char pmu_path[PATH_MAX]; int scan; - unsigned int val = 0; /* Get RO metadata from sysfs */ - snprintf(pmu_path, PATH_MAX, "cpu%d/%s", cpu, path); + snprintf(pmu_path, PATH_MAX, "cpu%d/%s", cpu.cpu, path); - scan = perf_pmu__scan_file(pmu, pmu_path, "%x", &val); - if (scan != 1) + scan = perf_pmu__scan_file(pmu, pmu_path, "%llx", val); + if (scan != 1) { pr_err("%s: error reading: %s\n", __func__, pmu_path); + return -EINVAL; + } - return val; + return 0; } -static int cs_etm_get_ro_signed(struct perf_pmu *pmu, int cpu, const char *path) +static int cs_etm_get_ro_signed(struct perf_pmu *pmu, struct perf_cpu cpu, const char *path, + __u64 *out_val) { char pmu_path[PATH_MAX]; int scan; int val = 0; /* Get RO metadata from sysfs */ - snprintf(pmu_path, PATH_MAX, "cpu%d/%s", cpu, path); + snprintf(pmu_path, PATH_MAX, "cpu%d/%s", cpu.cpu, path); scan = perf_pmu__scan_file(pmu, pmu_path, "%d", &val); - if (scan != 1) + if (scan != 1) { pr_err("%s: error reading: %s\n", __func__, pmu_path); + return -EINVAL; + } - return val; + *out_val = (__u64) val; + return 0; } -static bool cs_etm_pmu_path_exists(struct perf_pmu *pmu, int cpu, const char *path) +static bool cs_etm_pmu_path_exists(struct perf_pmu *pmu, struct perf_cpu cpu, const char *path) { char pmu_path[PATH_MAX]; /* Get RO metadata from sysfs */ - snprintf(pmu_path, PATH_MAX, "cpu%d/%s", cpu, path); + snprintf(pmu_path, PATH_MAX, "cpu%d/%s", cpu.cpu, path); return perf_pmu__file_exists(pmu, pmu_path); } @@ -636,16 +615,16 @@ static bool cs_etm_pmu_path_exists(struct perf_pmu *pmu, int cpu, const char *pa #define TRCDEVARCH_ARCHVER_MASK GENMASK(15, 12) #define TRCDEVARCH_ARCHVER(x) (((x) & TRCDEVARCH_ARCHVER_MASK) >> TRCDEVARCH_ARCHVER_SHIFT) -static bool cs_etm_is_ete(struct auxtrace_record *itr, int cpu) +static bool cs_etm_is_ete(struct auxtrace_record *itr, struct perf_cpu cpu) { struct cs_etm_recording *ptr = container_of(itr, struct cs_etm_recording, itr); struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; - int trcdevarch; + __u64 trcdevarch; if (!cs_etm_pmu_path_exists(cs_etm_pmu, cpu, metadata_ete_ro[CS_ETE_TRCDEVARCH])) return false; - trcdevarch = cs_etm_get_ro(cs_etm_pmu, cpu, metadata_ete_ro[CS_ETE_TRCDEVARCH]); + cs_etm_get_ro(cs_etm_pmu, cpu, metadata_ete_ro[CS_ETE_TRCDEVARCH], &trcdevarch); /* * ETE if ARCHVER is 5 (ARCHVER is 4 for ETM) and ARCHPART is 0xA13. * See ETM_DEVARCH_ETE_ARCH in coresight-etm4x.h @@ -653,7 +632,12 @@ static bool cs_etm_is_ete(struct auxtrace_record *itr, int cpu) return TRCDEVARCH_ARCHVER(trcdevarch) == 5 && TRCDEVARCH_ARCHPART(trcdevarch) == 0xA13; } -static void cs_etm_save_etmv4_header(__u64 data[], struct auxtrace_record *itr, int cpu) +static __u64 cs_etm_get_legacy_trace_id(struct perf_cpu cpu) +{ + return CORESIGHT_LEGACY_CPU_TRACE_ID(cpu.cpu); +} + +static void cs_etm_save_etmv4_header(__u64 data[], struct auxtrace_record *itr, struct perf_cpu cpu) { struct cs_etm_recording *ptr = container_of(itr, struct cs_etm_recording, itr); struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; @@ -661,33 +645,32 @@ static void cs_etm_save_etmv4_header(__u64 data[], struct auxtrace_record *itr, /* Get trace configuration register */ data[CS_ETMV4_TRCCONFIGR] = cs_etmv4_get_config(itr); /* traceID set to legacy version, in case new perf running on older system */ - data[CS_ETMV4_TRCTRACEIDR] = - CORESIGHT_LEGACY_CPU_TRACE_ID(cpu) | CORESIGHT_TRACE_ID_UNUSED_FLAG; + data[CS_ETMV4_TRCTRACEIDR] = cs_etm_get_legacy_trace_id(cpu) | + CORESIGHT_TRACE_ID_UNUSED_FLAG; /* Get read-only information from sysFS */ - data[CS_ETMV4_TRCIDR0] = cs_etm_get_ro(cs_etm_pmu, cpu, - metadata_etmv4_ro[CS_ETMV4_TRCIDR0]); - data[CS_ETMV4_TRCIDR1] = cs_etm_get_ro(cs_etm_pmu, cpu, - metadata_etmv4_ro[CS_ETMV4_TRCIDR1]); - data[CS_ETMV4_TRCIDR2] = cs_etm_get_ro(cs_etm_pmu, cpu, - metadata_etmv4_ro[CS_ETMV4_TRCIDR2]); - data[CS_ETMV4_TRCIDR8] = cs_etm_get_ro(cs_etm_pmu, cpu, - metadata_etmv4_ro[CS_ETMV4_TRCIDR8]); - data[CS_ETMV4_TRCAUTHSTATUS] = cs_etm_get_ro(cs_etm_pmu, cpu, - metadata_etmv4_ro[CS_ETMV4_TRCAUTHSTATUS]); + cs_etm_get_ro(cs_etm_pmu, cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR0], + &data[CS_ETMV4_TRCIDR0]); + cs_etm_get_ro(cs_etm_pmu, cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR1], + &data[CS_ETMV4_TRCIDR1]); + cs_etm_get_ro(cs_etm_pmu, cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR2], + &data[CS_ETMV4_TRCIDR2]); + cs_etm_get_ro(cs_etm_pmu, cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR8], + &data[CS_ETMV4_TRCIDR8]); + cs_etm_get_ro(cs_etm_pmu, cpu, metadata_etmv4_ro[CS_ETMV4_TRCAUTHSTATUS], + &data[CS_ETMV4_TRCAUTHSTATUS]); /* Kernels older than 5.19 may not expose ts_source */ - if (cs_etm_pmu_path_exists(cs_etm_pmu, cpu, metadata_etmv4_ro[CS_ETMV4_TS_SOURCE])) - data[CS_ETMV4_TS_SOURCE] = (__u64) cs_etm_get_ro_signed(cs_etm_pmu, cpu, - metadata_etmv4_ro[CS_ETMV4_TS_SOURCE]); - else { + if (!cs_etm_pmu_path_exists(cs_etm_pmu, cpu, metadata_etmv4_ro[CS_ETMV4_TS_SOURCE]) || + cs_etm_get_ro_signed(cs_etm_pmu, cpu, metadata_etmv4_ro[CS_ETMV4_TS_SOURCE], + &data[CS_ETMV4_TS_SOURCE])) { pr_debug3("[%03d] pmu file 'ts_source' not found. Fallback to safe value (-1)\n", - cpu); + cpu.cpu); data[CS_ETMV4_TS_SOURCE] = (__u64) -1; } } -static void cs_etm_save_ete_header(__u64 data[], struct auxtrace_record *itr, int cpu) +static void cs_etm_save_ete_header(__u64 data[], struct auxtrace_record *itr, struct perf_cpu cpu) { struct cs_etm_recording *ptr = container_of(itr, struct cs_etm_recording, itr); struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; @@ -695,36 +678,30 @@ static void cs_etm_save_ete_header(__u64 data[], struct auxtrace_record *itr, in /* Get trace configuration register */ data[CS_ETE_TRCCONFIGR] = cs_etmv4_get_config(itr); /* traceID set to legacy version, in case new perf running on older system */ - data[CS_ETE_TRCTRACEIDR] = - CORESIGHT_LEGACY_CPU_TRACE_ID(cpu) | CORESIGHT_TRACE_ID_UNUSED_FLAG; + data[CS_ETE_TRCTRACEIDR] = cs_etm_get_legacy_trace_id(cpu) | CORESIGHT_TRACE_ID_UNUSED_FLAG; /* Get read-only information from sysFS */ - data[CS_ETE_TRCIDR0] = cs_etm_get_ro(cs_etm_pmu, cpu, - metadata_ete_ro[CS_ETE_TRCIDR0]); - data[CS_ETE_TRCIDR1] = cs_etm_get_ro(cs_etm_pmu, cpu, - metadata_ete_ro[CS_ETE_TRCIDR1]); - data[CS_ETE_TRCIDR2] = cs_etm_get_ro(cs_etm_pmu, cpu, - metadata_ete_ro[CS_ETE_TRCIDR2]); - data[CS_ETE_TRCIDR8] = cs_etm_get_ro(cs_etm_pmu, cpu, - metadata_ete_ro[CS_ETE_TRCIDR8]); - data[CS_ETE_TRCAUTHSTATUS] = cs_etm_get_ro(cs_etm_pmu, cpu, - metadata_ete_ro[CS_ETE_TRCAUTHSTATUS]); + cs_etm_get_ro(cs_etm_pmu, cpu, metadata_ete_ro[CS_ETE_TRCIDR0], &data[CS_ETE_TRCIDR0]); + cs_etm_get_ro(cs_etm_pmu, cpu, metadata_ete_ro[CS_ETE_TRCIDR1], &data[CS_ETE_TRCIDR1]); + cs_etm_get_ro(cs_etm_pmu, cpu, metadata_ete_ro[CS_ETE_TRCIDR2], &data[CS_ETE_TRCIDR2]); + cs_etm_get_ro(cs_etm_pmu, cpu, metadata_ete_ro[CS_ETE_TRCIDR8], &data[CS_ETE_TRCIDR8]); + cs_etm_get_ro(cs_etm_pmu, cpu, metadata_ete_ro[CS_ETE_TRCAUTHSTATUS], + &data[CS_ETE_TRCAUTHSTATUS]); /* ETE uses the same registers as ETMv4 plus TRCDEVARCH */ - data[CS_ETE_TRCDEVARCH] = cs_etm_get_ro(cs_etm_pmu, cpu, - metadata_ete_ro[CS_ETE_TRCDEVARCH]); + cs_etm_get_ro(cs_etm_pmu, cpu, metadata_ete_ro[CS_ETE_TRCDEVARCH], + &data[CS_ETE_TRCDEVARCH]); /* Kernels older than 5.19 may not expose ts_source */ - if (cs_etm_pmu_path_exists(cs_etm_pmu, cpu, metadata_ete_ro[CS_ETE_TS_SOURCE])) - data[CS_ETE_TS_SOURCE] = (__u64) cs_etm_get_ro_signed(cs_etm_pmu, cpu, - metadata_ete_ro[CS_ETE_TS_SOURCE]); - else { + if (!cs_etm_pmu_path_exists(cs_etm_pmu, cpu, metadata_ete_ro[CS_ETE_TS_SOURCE]) || + cs_etm_get_ro_signed(cs_etm_pmu, cpu, metadata_ete_ro[CS_ETE_TS_SOURCE], + &data[CS_ETE_TS_SOURCE])) { pr_debug3("[%03d] pmu file 'ts_source' not found. Fallback to safe value (-1)\n", - cpu); + cpu.cpu); data[CS_ETE_TS_SOURCE] = (__u64) -1; } } -static void cs_etm_get_metadata(int cpu, u32 *offset, +static void cs_etm_get_metadata(struct perf_cpu cpu, u32 *offset, struct auxtrace_record *itr, struct perf_record_auxtrace_info *info) { @@ -754,15 +731,13 @@ static void cs_etm_get_metadata(int cpu, u32 *offset, /* Get configuration register */ info->priv[*offset + CS_ETM_ETMCR] = cs_etm_get_config(itr); /* traceID set to legacy value in case new perf running on old system */ - info->priv[*offset + CS_ETM_ETMTRACEIDR] = - CORESIGHT_LEGACY_CPU_TRACE_ID(cpu) | CORESIGHT_TRACE_ID_UNUSED_FLAG; + info->priv[*offset + CS_ETM_ETMTRACEIDR] = cs_etm_get_legacy_trace_id(cpu) | + CORESIGHT_TRACE_ID_UNUSED_FLAG; /* Get read-only information from sysFS */ - info->priv[*offset + CS_ETM_ETMCCER] = - cs_etm_get_ro(cs_etm_pmu, cpu, - metadata_etmv3_ro[CS_ETM_ETMCCER]); - info->priv[*offset + CS_ETM_ETMIDR] = - cs_etm_get_ro(cs_etm_pmu, cpu, - metadata_etmv3_ro[CS_ETM_ETMIDR]); + cs_etm_get_ro(cs_etm_pmu, cpu, metadata_etmv3_ro[CS_ETM_ETMCCER], + &info->priv[*offset + CS_ETM_ETMCCER]); + cs_etm_get_ro(cs_etm_pmu, cpu, metadata_etmv3_ro[CS_ETM_ETMIDR], + &info->priv[*offset + CS_ETM_ETMIDR]); /* How much space was used */ increment = CS_ETM_PRIV_MAX; @@ -771,7 +746,7 @@ static void cs_etm_get_metadata(int cpu, u32 *offset, /* Build generic header portion */ info->priv[*offset + CS_ETM_MAGIC] = magic; - info->priv[*offset + CS_ETM_CPU] = cpu; + info->priv[*offset + CS_ETM_CPU] = cpu.cpu; info->priv[*offset + CS_ETM_NR_TRC_PARAMS] = nr_trc_params; /* Where the next CPU entry should start from */ *offset += increment; @@ -791,6 +766,7 @@ static int cs_etm_info_fill(struct auxtrace_record *itr, struct cs_etm_recording *ptr = container_of(itr, struct cs_etm_recording, itr); struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; + struct perf_cpu cpu; if (priv_size != cs_etm_info_priv_size(itr, session->evlist)) return -EINVAL; @@ -803,8 +779,6 @@ static int cs_etm_info_fill(struct auxtrace_record *itr, cpu_map = online_cpus; } else { /* Make sure all specified CPUs are online */ - struct perf_cpu cpu; - perf_cpu_map__for_each_cpu(cpu, i, event_cpus) { if (!perf_cpu_map__has(online_cpus, cpu)) return -EINVAL; @@ -826,11 +800,9 @@ static int cs_etm_info_fill(struct auxtrace_record *itr, offset = CS_ETM_SNAPSHOT + 1; - for (i = 0; i < cpu__max_cpu().cpu && offset < priv_size; i++) { - struct perf_cpu cpu = { .cpu = i, }; - - if (perf_cpu_map__has(cpu_map, cpu)) - cs_etm_get_metadata(i, &offset, itr, info); + perf_cpu_map__for_each_cpu(cpu, i, cpu_map) { + assert(offset < priv_size); + cs_etm_get_metadata(cpu, &offset, itr, info); } perf_cpu_map__put(online_cpus); -- cgit v1.2.3-59-g8ed1b From bc5e0e1b93565e3760ffb407db836c9f50d4ffae Mon Sep 17 00:00:00 2001 From: James Clark Date: Wed, 1 May 2024 14:57:52 +0100 Subject: perf cs-etm: Remove repeated fetches of the ETM PMU Most functions already have cs_etm_pmu, so it's a bit neater to pass it through rather than itr only to convert it again. Signed-off-by: James Clark Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: John Garry Cc: Kan Liang Cc: Leo Yan Cc: Mark Rutland Cc: Mike Leach Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Suzuki Poulouse Cc: Will Deacon Link: https://lore.kernel.org/r/20240501135753.508022-3-james.clark@arm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/arch/arm/util/cs-etm.c | 60 ++++++++++++++++++--------------------- 1 file changed, 27 insertions(+), 33 deletions(-) diff --git a/tools/perf/arch/arm/util/cs-etm.c b/tools/perf/arch/arm/util/cs-etm.c index a1fa711dc41a..2fc4b41daea1 100644 --- a/tools/perf/arch/arm/util/cs-etm.c +++ b/tools/perf/arch/arm/util/cs-etm.c @@ -66,17 +66,14 @@ static const char * const metadata_ete_ro[] = { [CS_ETE_TS_SOURCE] = "ts_source", }; -static bool cs_etm_is_etmv4(struct auxtrace_record *itr, struct perf_cpu cpu); -static bool cs_etm_is_ete(struct auxtrace_record *itr, struct perf_cpu cpu); +static bool cs_etm_is_etmv4(struct perf_pmu *cs_etm_pmu, struct perf_cpu cpu); +static bool cs_etm_is_ete(struct perf_pmu *cs_etm_pmu, struct perf_cpu cpu); static int cs_etm_get_ro(struct perf_pmu *pmu, struct perf_cpu cpu, const char *path, __u64 *val); static bool cs_etm_pmu_path_exists(struct perf_pmu *pmu, struct perf_cpu cpu, const char *path); -static int cs_etm_validate_context_id(struct auxtrace_record *itr, struct evsel *evsel, +static int cs_etm_validate_context_id(struct perf_pmu *cs_etm_pmu, struct evsel *evsel, struct perf_cpu cpu) { - struct cs_etm_recording *ptr = - container_of(itr, struct cs_etm_recording, itr); - struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; int err; __u64 val; u64 contextid = evsel->core.attr.config & @@ -88,7 +85,7 @@ static int cs_etm_validate_context_id(struct auxtrace_record *itr, struct evsel return 0; /* Not supported in etmv3 */ - if (!cs_etm_is_etmv4(itr, cpu)) { + if (!cs_etm_is_etmv4(cs_etm_pmu, cpu)) { pr_err("%s: contextid not supported in ETMv3, disable with %s/contextid=0/\n", CORESIGHT_ETM_PMU_NAME, CORESIGHT_ETM_PMU_NAME); return -EINVAL; @@ -134,12 +131,9 @@ static int cs_etm_validate_context_id(struct auxtrace_record *itr, struct evsel return 0; } -static int cs_etm_validate_timestamp(struct auxtrace_record *itr, struct evsel *evsel, +static int cs_etm_validate_timestamp(struct perf_pmu *cs_etm_pmu, struct evsel *evsel, struct perf_cpu cpu) { - struct cs_etm_recording *ptr = - container_of(itr, struct cs_etm_recording, itr); - struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; int err; __u64 val; @@ -147,7 +141,7 @@ static int cs_etm_validate_timestamp(struct auxtrace_record *itr, struct evsel * perf_pmu__format_bits(cs_etm_pmu, "timestamp"))) return 0; - if (!cs_etm_is_etmv4(itr, cpu)) { + if (!cs_etm_is_etmv4(cs_etm_pmu, cpu)) { pr_err("%s: timestamp not supported in ETMv3, disable with %s/timestamp=0/\n", CORESIGHT_ETM_PMU_NAME, CORESIGHT_ETM_PMU_NAME); return -EINVAL; @@ -173,6 +167,13 @@ static int cs_etm_validate_timestamp(struct auxtrace_record *itr, struct evsel * return 0; } +static struct perf_pmu *cs_etm_get_pmu(struct auxtrace_record *itr) +{ + struct cs_etm_recording *ptr = container_of(itr, struct cs_etm_recording, itr); + + return ptr->cs_etm_pmu; +} + /* * Check whether the requested timestamp and contextid options should be * available on all requested CPUs and if not, tell the user how to override. @@ -180,7 +181,7 @@ static int cs_etm_validate_timestamp(struct auxtrace_record *itr, struct evsel * * first is better. In theory the kernel could still disable the option for * some other reason so this is best effort only. */ -static int cs_etm_validate_config(struct auxtrace_record *itr, +static int cs_etm_validate_config(struct perf_pmu *cs_etm_pmu, struct evsel *evsel) { int idx, err = 0; @@ -204,11 +205,11 @@ static int cs_etm_validate_config(struct auxtrace_record *itr, } perf_cpu_map__for_each_cpu_skip_any(cpu, idx, intersect_cpus) { - err = cs_etm_validate_context_id(itr, evsel, cpu); + err = cs_etm_validate_context_id(cs_etm_pmu, evsel, cpu); if (err) break; - err = cs_etm_validate_timestamp(itr, evsel, cpu); + err = cs_etm_validate_timestamp(cs_etm_pmu, evsel, cpu); if (err) break; } @@ -449,7 +450,7 @@ static int cs_etm_recording_options(struct auxtrace_record *itr, if (!perf_cpu_map__is_any_cpu_or_is_empty(cpus)) evsel__set_sample_bit(evsel, TIME); - err = cs_etm_validate_config(itr, cs_etm_evsel); + err = cs_etm_validate_config(cs_etm_pmu, cs_etm_evsel); out: return err; } @@ -515,14 +516,15 @@ static u64 cs_etmv4_get_config(struct auxtrace_record *itr) } static size_t -cs_etm_info_priv_size(struct auxtrace_record *itr __maybe_unused, - struct evlist *evlist __maybe_unused) +cs_etm_info_priv_size(struct auxtrace_record *itr, + struct evlist *evlist) { int idx; int etmv3 = 0, etmv4 = 0, ete = 0; struct perf_cpu_map *event_cpus = evlist->core.user_requested_cpus; struct perf_cpu_map *intersect_cpus; struct perf_cpu cpu; + struct perf_pmu *cs_etm_pmu = cs_etm_get_pmu(itr); if (!perf_cpu_map__has_any_cpu(event_cpus)) { /* cpu map is not "any" CPU , we have specific CPUs to work with */ @@ -535,9 +537,9 @@ cs_etm_info_priv_size(struct auxtrace_record *itr __maybe_unused, intersect_cpus = perf_cpu_map__new_online_cpus(); } perf_cpu_map__for_each_cpu_skip_any(cpu, idx, intersect_cpus) { - if (cs_etm_is_ete(itr, cpu)) + if (cs_etm_is_ete(cs_etm_pmu, cpu)) ete++; - else if (cs_etm_is_etmv4(itr, cpu)) + else if (cs_etm_is_etmv4(cs_etm_pmu, cpu)) etmv4++; else etmv3++; @@ -550,12 +552,8 @@ cs_etm_info_priv_size(struct auxtrace_record *itr __maybe_unused, (etmv3 * CS_ETMV3_PRIV_SIZE)); } -static bool cs_etm_is_etmv4(struct auxtrace_record *itr, struct perf_cpu cpu) +static bool cs_etm_is_etmv4(struct perf_pmu *cs_etm_pmu, struct perf_cpu cpu) { - struct cs_etm_recording *ptr = - container_of(itr, struct cs_etm_recording, itr); - struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; - /* Take any of the RO files for ETMv4 and see if it present */ return cs_etm_pmu_path_exists(cs_etm_pmu, cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR0]); } @@ -615,10 +613,8 @@ static bool cs_etm_pmu_path_exists(struct perf_pmu *pmu, struct perf_cpu cpu, co #define TRCDEVARCH_ARCHVER_MASK GENMASK(15, 12) #define TRCDEVARCH_ARCHVER(x) (((x) & TRCDEVARCH_ARCHVER_MASK) >> TRCDEVARCH_ARCHVER_SHIFT) -static bool cs_etm_is_ete(struct auxtrace_record *itr, struct perf_cpu cpu) +static bool cs_etm_is_ete(struct perf_pmu *cs_etm_pmu, struct perf_cpu cpu) { - struct cs_etm_recording *ptr = container_of(itr, struct cs_etm_recording, itr); - struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; __u64 trcdevarch; if (!cs_etm_pmu_path_exists(cs_etm_pmu, cpu, metadata_ete_ro[CS_ETE_TRCDEVARCH])) @@ -707,19 +703,17 @@ static void cs_etm_get_metadata(struct perf_cpu cpu, u32 *offset, { u32 increment, nr_trc_params; u64 magic; - struct cs_etm_recording *ptr = - container_of(itr, struct cs_etm_recording, itr); - struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; + struct perf_pmu *cs_etm_pmu = cs_etm_get_pmu(itr); /* first see what kind of tracer this cpu is affined to */ - if (cs_etm_is_ete(itr, cpu)) { + if (cs_etm_is_ete(cs_etm_pmu, cpu)) { magic = __perf_cs_ete_magic; cs_etm_save_ete_header(&info->priv[*offset], itr, cpu); /* How much space was used */ increment = CS_ETE_PRIV_MAX; nr_trc_params = CS_ETE_PRIV_MAX - CS_ETM_COMMON_BLK_MAX_V1; - } else if (cs_etm_is_etmv4(itr, cpu)) { + } else if (cs_etm_is_etmv4(cs_etm_pmu, cpu)) { magic = __perf_cs_etmv4_magic; cs_etm_save_etmv4_header(&info->priv[*offset], itr, cpu); -- cgit v1.2.3-59-g8ed1b From e3123079b906dc2edb80466de85b2c333a56fbf2 Mon Sep 17 00:00:00 2001 From: James Clark Date: Wed, 1 May 2024 14:57:53 +0100 Subject: perf cs-etm: Improve version detection and error reporting When the config validation functions are warning about ETMv3, they do it based on "not ETMv4". If the drivers aren't all loaded or the hardware doesn't support Coresight it will appear as "not ETMv4" and then Perf will print the error message "... not supported in ETMv3 ..." which is wrong and confusing. cs_etm_is_etmv4() is also misnamed because it also returns true for ETE because ETE has a superset of the ETMv4 metadata files. Although this was always done in the correct order so it wasn't a bug. Improve all this by making a single get version function which also handles not present as a separate case. Change the ETMv3 error message to only print when ETMv3 is detected, and add a new error message for the not present case. Reviewed-by: Ian Rogers Reviewed-by: Leo Yan Signed-off-by: James Clark Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ingo Molnar Cc: Jiri Olsa Cc: John Garry Cc: Kan Liang Cc: Mark Rutland Cc: Mike Leach Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Suzuki Poulouse Cc: Will Deacon Link: https://lore.kernel.org/r/20240501135753.508022-4-james.clark@arm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/arch/arm/util/cs-etm.c | 61 +++++++++++++++++++++++++++------------ 1 file changed, 43 insertions(+), 18 deletions(-) diff --git a/tools/perf/arch/arm/util/cs-etm.c b/tools/perf/arch/arm/util/cs-etm.c index 2fc4b41daea1..da6231367993 100644 --- a/tools/perf/arch/arm/util/cs-etm.c +++ b/tools/perf/arch/arm/util/cs-etm.c @@ -66,11 +66,25 @@ static const char * const metadata_ete_ro[] = { [CS_ETE_TS_SOURCE] = "ts_source", }; -static bool cs_etm_is_etmv4(struct perf_pmu *cs_etm_pmu, struct perf_cpu cpu); +enum cs_etm_version { CS_NOT_PRESENT, CS_ETMV3, CS_ETMV4, CS_ETE }; + static bool cs_etm_is_ete(struct perf_pmu *cs_etm_pmu, struct perf_cpu cpu); static int cs_etm_get_ro(struct perf_pmu *pmu, struct perf_cpu cpu, const char *path, __u64 *val); static bool cs_etm_pmu_path_exists(struct perf_pmu *pmu, struct perf_cpu cpu, const char *path); +static enum cs_etm_version cs_etm_get_version(struct perf_pmu *cs_etm_pmu, + struct perf_cpu cpu) +{ + if (cs_etm_is_ete(cs_etm_pmu, cpu)) + return CS_ETE; + else if (cs_etm_pmu_path_exists(cs_etm_pmu, cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR0])) + return CS_ETMV4; + else if (cs_etm_pmu_path_exists(cs_etm_pmu, cpu, metadata_etmv3_ro[CS_ETM_ETMCCER])) + return CS_ETMV3; + + return CS_NOT_PRESENT; +} + static int cs_etm_validate_context_id(struct perf_pmu *cs_etm_pmu, struct evsel *evsel, struct perf_cpu cpu) { @@ -85,7 +99,7 @@ static int cs_etm_validate_context_id(struct perf_pmu *cs_etm_pmu, struct evsel return 0; /* Not supported in etmv3 */ - if (!cs_etm_is_etmv4(cs_etm_pmu, cpu)) { + if (cs_etm_get_version(cs_etm_pmu, cpu) == CS_ETMV3) { pr_err("%s: contextid not supported in ETMv3, disable with %s/contextid=0/\n", CORESIGHT_ETM_PMU_NAME, CORESIGHT_ETM_PMU_NAME); return -EINVAL; @@ -141,7 +155,7 @@ static int cs_etm_validate_timestamp(struct perf_pmu *cs_etm_pmu, struct evsel * perf_pmu__format_bits(cs_etm_pmu, "timestamp"))) return 0; - if (!cs_etm_is_etmv4(cs_etm_pmu, cpu)) { + if (cs_etm_get_version(cs_etm_pmu, cpu) == CS_ETMV3) { pr_err("%s: timestamp not supported in ETMv3, disable with %s/timestamp=0/\n", CORESIGHT_ETM_PMU_NAME, CORESIGHT_ETM_PMU_NAME); return -EINVAL; @@ -205,6 +219,11 @@ static int cs_etm_validate_config(struct perf_pmu *cs_etm_pmu, } perf_cpu_map__for_each_cpu_skip_any(cpu, idx, intersect_cpus) { + if (cs_etm_get_version(cs_etm_pmu, cpu) == CS_NOT_PRESENT) { + pr_err("%s: Not found on CPU %d. Check hardware and firmware support and that all Coresight drivers are loaded\n", + CORESIGHT_ETM_PMU_NAME, cpu.cpu); + return -EINVAL; + } err = cs_etm_validate_context_id(cs_etm_pmu, evsel, cpu); if (err) break; @@ -536,13 +555,13 @@ cs_etm_info_priv_size(struct auxtrace_record *itr, /* Event can be "any" CPU so count all online CPUs. */ intersect_cpus = perf_cpu_map__new_online_cpus(); } + /* Count number of each type of ETM. Don't count if that CPU has CS_NOT_PRESENT. */ perf_cpu_map__for_each_cpu_skip_any(cpu, idx, intersect_cpus) { - if (cs_etm_is_ete(cs_etm_pmu, cpu)) - ete++; - else if (cs_etm_is_etmv4(cs_etm_pmu, cpu)) - etmv4++; - else - etmv3++; + enum cs_etm_version v = cs_etm_get_version(cs_etm_pmu, cpu); + + ete += v == CS_ETE; + etmv4 += v == CS_ETMV4; + etmv3 += v == CS_ETMV3; } perf_cpu_map__put(intersect_cpus); @@ -552,12 +571,6 @@ cs_etm_info_priv_size(struct auxtrace_record *itr, (etmv3 * CS_ETMV3_PRIV_SIZE)); } -static bool cs_etm_is_etmv4(struct perf_pmu *cs_etm_pmu, struct perf_cpu cpu) -{ - /* Take any of the RO files for ETMv4 and see if it present */ - return cs_etm_pmu_path_exists(cs_etm_pmu, cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR0]); -} - static int cs_etm_get_ro(struct perf_pmu *pmu, struct perf_cpu cpu, const char *path, __u64 *val) { char pmu_path[PATH_MAX]; @@ -706,21 +719,26 @@ static void cs_etm_get_metadata(struct perf_cpu cpu, u32 *offset, struct perf_pmu *cs_etm_pmu = cs_etm_get_pmu(itr); /* first see what kind of tracer this cpu is affined to */ - if (cs_etm_is_ete(cs_etm_pmu, cpu)) { + switch (cs_etm_get_version(cs_etm_pmu, cpu)) { + case CS_ETE: magic = __perf_cs_ete_magic; cs_etm_save_ete_header(&info->priv[*offset], itr, cpu); /* How much space was used */ increment = CS_ETE_PRIV_MAX; nr_trc_params = CS_ETE_PRIV_MAX - CS_ETM_COMMON_BLK_MAX_V1; - } else if (cs_etm_is_etmv4(cs_etm_pmu, cpu)) { + break; + + case CS_ETMV4: magic = __perf_cs_etmv4_magic; cs_etm_save_etmv4_header(&info->priv[*offset], itr, cpu); /* How much space was used */ increment = CS_ETMV4_PRIV_MAX; nr_trc_params = CS_ETMV4_PRIV_MAX - CS_ETMV4_TRCCONFIGR; - } else { + break; + + case CS_ETMV3: magic = __perf_cs_etmv3_magic; /* Get configuration register */ info->priv[*offset + CS_ETM_ETMCR] = cs_etm_get_config(itr); @@ -736,6 +754,13 @@ static void cs_etm_get_metadata(struct perf_cpu cpu, u32 *offset, /* How much space was used */ increment = CS_ETM_PRIV_MAX; nr_trc_params = CS_ETM_PRIV_MAX - CS_ETM_ETMCR; + break; + + default: + case CS_NOT_PRESENT: + /* Unreachable, CPUs already validated in cs_etm_validate_config() */ + assert(true); + return; } /* Build generic header portion */ -- cgit v1.2.3-59-g8ed1b From aa172ba73948e2152e258ead7e9ddbd806e809b0 Mon Sep 17 00:00:00 2001 From: Martin Kurbanov Date: Tue, 16 Apr 2024 23:18:05 +0300 Subject: leds: trigger: pattern: Add support for hrtimer Currently, led pattern trigger uses timer_list to schedule brightness changing. As we know from timer_list API [1], it's not accurate to milliseconds and depends on HZ granularity. Example: "0 10 0 0 50 10 50 0 100 10 100 0 150 10 150 0 200 10 200 0 250 10 250 0", we expect it to be 60ms long, but it can actually be up to ~120ms (add ~10ms for each pattern when HZ == 100). But sometimes, userspace needs time accurate led patterns to make sure that pattern will be executed during expected time slot. To achieve this goal the patch introduces optional hrtimer usage for led trigger pattern, because hrtimer is microseconds accurate timer. [1]: kernel/time/timer.c#L104 Signed-off-by: Martin Kurbanov Link: https://lore.kernel.org/r/20240416201847.357099-1-mmkurbanov@salutedevices.com Signed-off-by: Lee Jones --- .../ABI/testing/sysfs-class-led-trigger-pattern | 10 ++ drivers/leds/trigger/ledtrig-pattern.c | 126 +++++++++++++++++---- 2 files changed, 113 insertions(+), 23 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-class-led-trigger-pattern b/Documentation/ABI/testing/sysfs-class-led-trigger-pattern index 8c57d2780554..22f28f2e9ac4 100644 --- a/Documentation/ABI/testing/sysfs-class-led-trigger-pattern +++ b/Documentation/ABI/testing/sysfs-class-led-trigger-pattern @@ -12,6 +12,16 @@ Description: The exact format is described in: Documentation/devicetree/bindings/leds/leds-trigger-pattern.txt +What: /sys/class/leds//hr_pattern +Date: April 2024 +Description: + Specify a software pattern for the LED, that supports altering + the brightness for the specified duration with one software + timer. It can do gradual dimming and step change of brightness. + + Unlike the /sys/class/leds//pattern, this attribute runs + a pattern on high-resolution timer (hrtimer). + What: /sys/class/leds//hw_pattern Date: September 2018 KernelVersion: 4.20 diff --git a/drivers/leds/trigger/ledtrig-pattern.c b/drivers/leds/trigger/ledtrig-pattern.c index fadd87dbe993..aad48c2540fc 100644 --- a/drivers/leds/trigger/ledtrig-pattern.c +++ b/drivers/leds/trigger/ledtrig-pattern.c @@ -13,6 +13,7 @@ #include #include #include +#include #define MAX_PATTERNS 1024 /* @@ -21,6 +22,12 @@ */ #define UPDATE_INTERVAL 50 +enum pattern_type { + PATTERN_TYPE_SW, /* Use standard timer for software pattern */ + PATTERN_TYPE_HR, /* Use hrtimer for software pattern */ + PATTERN_TYPE_HW, /* Hardware pattern */ +}; + struct pattern_trig_data { struct led_classdev *led_cdev; struct led_pattern patterns[MAX_PATTERNS]; @@ -32,8 +39,9 @@ struct pattern_trig_data { int last_repeat; int delta_t; bool is_indefinite; - bool is_hw_pattern; + enum pattern_type type; struct timer_list timer; + struct hrtimer hrtimer; }; static void pattern_trig_update_patterns(struct pattern_trig_data *data) @@ -71,10 +79,35 @@ static int pattern_trig_compute_brightness(struct pattern_trig_data *data) return data->curr->brightness - step_brightness; } -static void pattern_trig_timer_function(struct timer_list *t) +static void pattern_trig_timer_start(struct pattern_trig_data *data) { - struct pattern_trig_data *data = from_timer(data, t, timer); + if (data->type == PATTERN_TYPE_HR) { + hrtimer_start(&data->hrtimer, ns_to_ktime(0), HRTIMER_MODE_REL); + } else { + data->timer.expires = jiffies; + add_timer(&data->timer); + } +} +static void pattern_trig_timer_cancel(struct pattern_trig_data *data) +{ + if (data->type == PATTERN_TYPE_HR) + hrtimer_cancel(&data->hrtimer); + else + del_timer_sync(&data->timer); +} + +static void pattern_trig_timer_restart(struct pattern_trig_data *data, + unsigned long interval) +{ + if (data->type == PATTERN_TYPE_HR) + hrtimer_forward_now(&data->hrtimer, ms_to_ktime(interval)); + else + mod_timer(&data->timer, jiffies + msecs_to_jiffies(interval)); +} + +static void pattern_trig_timer_common_function(struct pattern_trig_data *data) +{ for (;;) { if (!data->is_indefinite && !data->repeat) break; @@ -83,8 +116,7 @@ static void pattern_trig_timer_function(struct timer_list *t) /* Step change of brightness */ led_set_brightness(data->led_cdev, data->curr->brightness); - mod_timer(&data->timer, - jiffies + msecs_to_jiffies(data->curr->delta_t)); + pattern_trig_timer_restart(data, data->curr->delta_t); if (!data->next->delta_t) { /* Skip the tuple with zero duration */ pattern_trig_update_patterns(data); @@ -106,8 +138,7 @@ static void pattern_trig_timer_function(struct timer_list *t) led_set_brightness(data->led_cdev, pattern_trig_compute_brightness(data)); - mod_timer(&data->timer, - jiffies + msecs_to_jiffies(UPDATE_INTERVAL)); + pattern_trig_timer_restart(data, UPDATE_INTERVAL); /* Accumulate the gradual dimming time */ data->delta_t += UPDATE_INTERVAL; @@ -117,6 +148,25 @@ static void pattern_trig_timer_function(struct timer_list *t) } } +static void pattern_trig_timer_function(struct timer_list *t) +{ + struct pattern_trig_data *data = from_timer(data, t, timer); + + return pattern_trig_timer_common_function(data); +} + +static enum hrtimer_restart pattern_trig_hrtimer_function(struct hrtimer *t) +{ + struct pattern_trig_data *data = + container_of(t, struct pattern_trig_data, hrtimer); + + pattern_trig_timer_common_function(data); + if (!data->is_indefinite && !data->repeat) + return HRTIMER_NORESTART; + + return HRTIMER_RESTART; +} + static int pattern_trig_start_pattern(struct led_classdev *led_cdev) { struct pattern_trig_data *data = led_cdev->trigger_data; @@ -124,7 +174,7 @@ static int pattern_trig_start_pattern(struct led_classdev *led_cdev) if (!data->npatterns) return 0; - if (data->is_hw_pattern) { + if (data->type == PATTERN_TYPE_HW) { return led_cdev->pattern_set(led_cdev, data->patterns, data->npatterns, data->repeat); } @@ -136,8 +186,7 @@ static int pattern_trig_start_pattern(struct led_classdev *led_cdev) data->delta_t = 0; data->curr = data->patterns; data->next = data->patterns + 1; - data->timer.expires = jiffies; - add_timer(&data->timer); + pattern_trig_timer_start(data); return 0; } @@ -175,9 +224,9 @@ static ssize_t repeat_store(struct device *dev, struct device_attribute *attr, mutex_lock(&data->lock); - del_timer_sync(&data->timer); + pattern_trig_timer_cancel(data); - if (data->is_hw_pattern) + if (data->type == PATTERN_TYPE_HW) led_cdev->pattern_clear(led_cdev); data->last_repeat = data->repeat = res; @@ -196,14 +245,14 @@ static ssize_t repeat_store(struct device *dev, struct device_attribute *attr, static DEVICE_ATTR_RW(repeat); static ssize_t pattern_trig_show_patterns(struct pattern_trig_data *data, - char *buf, bool hw_pattern) + char *buf, enum pattern_type type) { ssize_t count = 0; int i; mutex_lock(&data->lock); - if (!data->npatterns || (data->is_hw_pattern ^ hw_pattern)) + if (!data->npatterns || data->type != type) goto out; for (i = 0; i < data->npatterns; i++) { @@ -260,19 +309,19 @@ static int pattern_trig_store_patterns_int(struct pattern_trig_data *data, static ssize_t pattern_trig_store_patterns(struct led_classdev *led_cdev, const char *buf, const u32 *buf_int, - size_t count, bool hw_pattern) + size_t count, enum pattern_type type) { struct pattern_trig_data *data = led_cdev->trigger_data; int err = 0; mutex_lock(&data->lock); - del_timer_sync(&data->timer); + pattern_trig_timer_cancel(data); - if (data->is_hw_pattern) + if (data->type == PATTERN_TYPE_HW) led_cdev->pattern_clear(led_cdev); - data->is_hw_pattern = hw_pattern; + data->type = type; data->npatterns = 0; if (buf) @@ -297,7 +346,7 @@ static ssize_t pattern_show(struct device *dev, struct device_attribute *attr, struct led_classdev *led_cdev = dev_get_drvdata(dev); struct pattern_trig_data *data = led_cdev->trigger_data; - return pattern_trig_show_patterns(data, buf, false); + return pattern_trig_show_patterns(data, buf, PATTERN_TYPE_SW); } static ssize_t pattern_store(struct device *dev, struct device_attribute *attr, @@ -305,7 +354,8 @@ static ssize_t pattern_store(struct device *dev, struct device_attribute *attr, { struct led_classdev *led_cdev = dev_get_drvdata(dev); - return pattern_trig_store_patterns(led_cdev, buf, NULL, count, false); + return pattern_trig_store_patterns(led_cdev, buf, NULL, count, + PATTERN_TYPE_SW); } static DEVICE_ATTR_RW(pattern); @@ -316,7 +366,7 @@ static ssize_t hw_pattern_show(struct device *dev, struct led_classdev *led_cdev = dev_get_drvdata(dev); struct pattern_trig_data *data = led_cdev->trigger_data; - return pattern_trig_show_patterns(data, buf, true); + return pattern_trig_show_patterns(data, buf, PATTERN_TYPE_HW); } static ssize_t hw_pattern_store(struct device *dev, @@ -325,11 +375,33 @@ static ssize_t hw_pattern_store(struct device *dev, { struct led_classdev *led_cdev = dev_get_drvdata(dev); - return pattern_trig_store_patterns(led_cdev, buf, NULL, count, true); + return pattern_trig_store_patterns(led_cdev, buf, NULL, count, + PATTERN_TYPE_HW); } static DEVICE_ATTR_RW(hw_pattern); +static ssize_t hr_pattern_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct pattern_trig_data *data = led_cdev->trigger_data; + + return pattern_trig_show_patterns(data, buf, PATTERN_TYPE_HR); +} + +static ssize_t hr_pattern_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + + return pattern_trig_store_patterns(led_cdev, buf, NULL, count, + PATTERN_TYPE_HR); +} + +static DEVICE_ATTR_RW(hr_pattern); + static umode_t pattern_trig_attrs_mode(struct kobject *kobj, struct attribute *attr, int index) { @@ -338,6 +410,8 @@ static umode_t pattern_trig_attrs_mode(struct kobject *kobj, if (attr == &dev_attr_repeat.attr || attr == &dev_attr_pattern.attr) return attr->mode; + else if (attr == &dev_attr_hr_pattern.attr) + return attr->mode; else if (attr == &dev_attr_hw_pattern.attr && led_cdev->pattern_set) return attr->mode; @@ -347,6 +421,7 @@ static umode_t pattern_trig_attrs_mode(struct kobject *kobj, static struct attribute *pattern_trig_attrs[] = { &dev_attr_pattern.attr, &dev_attr_hw_pattern.attr, + &dev_attr_hr_pattern.attr, &dev_attr_repeat.attr, NULL }; @@ -376,7 +451,8 @@ static void pattern_init(struct led_classdev *led_cdev) goto out; } - err = pattern_trig_store_patterns(led_cdev, NULL, pattern, size, false); + err = pattern_trig_store_patterns(led_cdev, NULL, pattern, size, + PATTERN_TYPE_SW); if (err < 0) dev_warn(led_cdev->dev, "Pattern initialization failed with error %d\n", err); @@ -400,12 +476,15 @@ static int pattern_trig_activate(struct led_classdev *led_cdev) led_cdev->pattern_clear = NULL; } + data->type = PATTERN_TYPE_SW; data->is_indefinite = true; data->last_repeat = -1; mutex_init(&data->lock); data->led_cdev = led_cdev; led_set_trigger_data(led_cdev, data); timer_setup(&data->timer, pattern_trig_timer_function, 0); + hrtimer_init(&data->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + data->hrtimer.function = pattern_trig_hrtimer_function; led_cdev->activated = true; if (led_cdev->flags & LED_INIT_DEFAULT_TRIGGER) { @@ -431,6 +510,7 @@ static void pattern_trig_deactivate(struct led_classdev *led_cdev) led_cdev->pattern_clear(led_cdev); timer_shutdown_sync(&data->timer); + hrtimer_cancel(&data->hrtimer); led_set_brightness(led_cdev, LED_OFF); kfree(data); -- cgit v1.2.3-59-g8ed1b From 974afccd37947a6951a052ef8118c961e57eaf7b Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Wed, 17 Apr 2024 17:38:47 +0200 Subject: leds: pwm: Disable PWM when going to suspend MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On stm32mp1xx based machines (and others) a PWM consumer has to disable the PWM because an enabled PWM refuses to suspend. So check the LED_SUSPENDED flag and depending on that set the .enabled property. Link: https://bugzilla.kernel.org/show_bug.cgi?id=218559 Fixes: 76fe464c8e64 ("leds: pwm: Don't disable the PWM when the LED should be off") Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20240417153846.271751-2-u.kleine-koenig@pengutronix.de Signed-off-by: Lee Jones --- drivers/leds/leds-pwm.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/leds/leds-pwm.c b/drivers/leds/leds-pwm.c index 4e3936a39d0e..e1b414b40353 100644 --- a/drivers/leds/leds-pwm.c +++ b/drivers/leds/leds-pwm.c @@ -53,7 +53,13 @@ static int led_pwm_set(struct led_classdev *led_cdev, duty = led_dat->pwmstate.period - duty; led_dat->pwmstate.duty_cycle = duty; - led_dat->pwmstate.enabled = true; + /* + * Disabling a PWM doesn't guarantee that it emits the inactive level. + * So keep it on. Only for suspending the PWM should be disabled because + * otherwise it refuses to suspend. The possible downside is that the + * LED might stay (or even go) on. + */ + led_dat->pwmstate.enabled = !(led_cdev->flags & LED_SUSPENDED); return pwm_apply_might_sleep(led_dat->pwm, &led_dat->pwmstate); } -- cgit v1.2.3-59-g8ed1b From 3b29c7b9f701e5afbe6b536eb2744acb25cf5bfd Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 26 Apr 2024 18:25:15 +0300 Subject: leds: sun50i-a100: Use match_string() helper to simplify the code match_string() returns the array index of a matching string. Use it instead of the open-coded implementation. Signed-off-by: Andy Shevchenko Reviewed-by: Jernej Skrabec Link: https://lore.kernel.org/r/20240426152515.872917-1-andriy.shevchenko@linux.intel.com Signed-off-by: Lee Jones --- drivers/leds/leds-sun50i-a100.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/leds/leds-sun50i-a100.c b/drivers/leds/leds-sun50i-a100.c index 62d21c3a3575..119eff9471f0 100644 --- a/drivers/leds/leds-sun50i-a100.c +++ b/drivers/leds/leds-sun50i-a100.c @@ -252,18 +252,16 @@ static int sun50i_a100_ledc_parse_format(struct device *dev, struct sun50i_a100_ledc *priv) { const char *format = "grb"; - u32 i; + int i; device_property_read_string(dev, "allwinner,pixel-format", &format); - for (i = 0; i < ARRAY_SIZE(sun50i_a100_ledc_formats); i++) { - if (!strcmp(format, sun50i_a100_ledc_formats[i])) { - priv->format = i; - return 0; - } - } + i = match_string(sun50i_a100_ledc_formats, ARRAY_SIZE(sun50i_a100_ledc_formats), format); + if (i < 0) + return dev_err_probe(dev, i, "Bad pixel format '%s'\n", format); - return dev_err_probe(dev, -EINVAL, "Bad pixel format '%s'\n", format); + priv->format = i; + return 0; } static void sun50i_a100_ledc_set_format(struct sun50i_a100_ledc *priv) -- cgit v1.2.3-59-g8ed1b From 678ba7d25467c06850d0d2922108573ea7346a48 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sun, 28 Apr 2024 17:34:55 +0200 Subject: leds: aat1290: Remove unused field 'torch_brightness' from 'struct aat1290_led' In 'struct aat1290_led', the 'torch_brightness' field is unused. Remove it. Found with cppcheck, unusedStructMember. Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/f7c8c22242544b11e95d9a77d7d0ea17f5a24fd5.1714318454.git.christophe.jaillet@wanadoo.fr Signed-off-by: Lee Jones --- drivers/leds/flash/leds-aat1290.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/leds/flash/leds-aat1290.c b/drivers/leds/flash/leds-aat1290.c index 0195935a7c99..e8f9dd293592 100644 --- a/drivers/leds/flash/leds-aat1290.c +++ b/drivers/leds/flash/leds-aat1290.c @@ -77,8 +77,6 @@ struct aat1290_led { int *mm_current_scale; /* device mode */ bool movie_mode; - /* brightness cache */ - unsigned int torch_brightness; }; static struct aat1290_led *fled_cdev_to_led( -- cgit v1.2.3-59-g8ed1b From 221db0183bebbee146922b5816419bdc9b5425ff Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sun, 28 Apr 2024 19:15:24 +0200 Subject: leds: lp50xx: Remove unused field 'bank_modules' from 'struct lp50xx_led' In 'struct lp50xx_led', the 'bank_modules' field is unused. Remove it. Found with cppcheck, unusedStructMember. Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/bc2e5e57b93ca0a33bcc84e9bdc89f26fc8f6d57.1714324500.git.christophe.jaillet@wanadoo.fr Signed-off-by: Lee Jones --- drivers/leds/leds-lp50xx.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/leds/leds-lp50xx.c b/drivers/leds/leds-lp50xx.c index 68c4d9967d68..407eddcf17c0 100644 --- a/drivers/leds/leds-lp50xx.c +++ b/drivers/leds/leds-lp50xx.c @@ -265,7 +265,6 @@ static const struct lp50xx_chip_info lp50xx_chip_info_tbl[] = { struct lp50xx_led { struct led_classdev_mc mc_cdev; struct lp50xx *priv; - unsigned long bank_modules; u8 ctrl_bank_enabled; int led_number; }; -- cgit v1.2.3-59-g8ed1b From dd66d058565a705980e6d55bd6592958531221b9 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sun, 28 Apr 2024 19:15:25 +0200 Subject: leds: lp50xx: Remove unused field 'num_of_banked_leds' from 'struct lp50xx' In 'struct lp50xx', the 'num_of_banked_leds' field is only written and is never used. Moreover, storing such an information in the 'priv' structure looks pointless, so remove it. Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/a0d472ff587d13a2b91ec32c8776061019caab6a.1714324500.git.christophe.jaillet@wanadoo.fr Signed-off-by: Lee Jones --- drivers/leds/leds-lp50xx.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/leds/leds-lp50xx.c b/drivers/leds/leds-lp50xx.c index 407eddcf17c0..175d4b06659b 100644 --- a/drivers/leds/leds-lp50xx.c +++ b/drivers/leds/leds-lp50xx.c @@ -278,7 +278,6 @@ struct lp50xx_led { * @dev: pointer to the devices device struct * @lock: lock for reading/writing the device * @chip_info: chip specific information (ie num_leds) - * @num_of_banked_leds: holds the number of banked LEDs * @leds: array of LED strings */ struct lp50xx { @@ -289,7 +288,6 @@ struct lp50xx { struct device *dev; struct mutex lock; const struct lp50xx_chip_info *chip_info; - int num_of_banked_leds; /* This needs to be at the end of the struct */ struct lp50xx_led leds[]; @@ -403,8 +401,6 @@ static int lp50xx_probe_leds(struct fwnode_handle *child, struct lp50xx *priv, return -EINVAL; } - priv->num_of_banked_leds = num_leds; - ret = fwnode_property_read_u32_array(child, "reg", led_banks, num_leds); if (ret) { dev_err(priv->dev, "reg property is missing\n"); -- cgit v1.2.3-59-g8ed1b From f2994f5341e03b8680a88abc5f1dee950033c3a9 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sun, 28 Apr 2024 20:27:31 +0200 Subject: leds: mt6370: Remove unused field 'reg_cfgs' from 'struct mt6370_priv' In 'struct mt6370_priv', the 'reg_cfgs' field is unused. Moreover 'struct reg_cfg' isn't defined anywhere, so remove it. Found with cppcheck, unusedStructMember. Signed-off-by: Christophe JAILLET Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/e389be5e1012dc05fc2641123883ca3b0747525a.1714328839.git.christophe.jaillet@wanadoo.fr Signed-off-by: Lee Jones --- drivers/leds/rgb/leds-mt6370-rgb.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/leds/rgb/leds-mt6370-rgb.c b/drivers/leds/rgb/leds-mt6370-rgb.c index 448d0da11848..359ef00498b4 100644 --- a/drivers/leds/rgb/leds-mt6370-rgb.c +++ b/drivers/leds/rgb/leds-mt6370-rgb.c @@ -149,7 +149,6 @@ struct mt6370_priv { struct regmap_field *fields[F_MAX_FIELDS]; const struct reg_field *reg_fields; const struct linear_range *ranges; - struct reg_cfg *reg_cfgs; const struct mt6370_pdata *pdata; unsigned int leds_count; unsigned int leds_active; -- cgit v1.2.3-59-g8ed1b From 9a87907de3597a339cc129229d1a20bc7365ea5f Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Thu, 2 May 2024 20:35:57 +0200 Subject: ovl: implement tmpfile Combine inode creation with opening a file. There are six separate objects that are being set up: the backing inode, dentry and file, and the overlay inode, dentry and file. Cleanup in case of an error is a bit of a challenge and is difficult to test, so careful review is needed. All tmpfile testcases except generic/509 now run/pass, and no regressions are observed with full xfstests. Signed-off-by: Miklos Szeredi Reviewed-by: Amir Goldstein --- fs/backing-file.c | 23 +++++++ fs/internal.h | 3 + fs/namei.c | 6 +- fs/overlayfs/dir.c | 149 +++++++++++++++++++++++++++++++++++++------ fs/overlayfs/file.c | 3 - fs/overlayfs/overlayfs.h | 3 + include/linux/backing-file.h | 3 + 7 files changed, 165 insertions(+), 25 deletions(-) diff --git a/fs/backing-file.c b/fs/backing-file.c index 740185198db3..afb557446c27 100644 --- a/fs/backing-file.c +++ b/fs/backing-file.c @@ -52,6 +52,29 @@ struct file *backing_file_open(const struct path *user_path, int flags, } EXPORT_SYMBOL_GPL(backing_file_open); +struct file *backing_tmpfile_open(const struct path *user_path, int flags, + const struct path *real_parentpath, + umode_t mode, const struct cred *cred) +{ + struct mnt_idmap *real_idmap = mnt_idmap(real_parentpath->mnt); + struct file *f; + int error; + + f = alloc_empty_backing_file(flags, cred); + if (IS_ERR(f)) + return f; + + path_get(user_path); + *backing_file_user_path(f) = *user_path; + error = vfs_tmpfile(real_idmap, real_parentpath, f, mode); + if (error) { + fput(f); + f = ERR_PTR(error); + } + return f; +} +EXPORT_SYMBOL(backing_tmpfile_open); + struct backing_aio { struct kiocb iocb; refcount_t ref; diff --git a/fs/internal.h b/fs/internal.h index 7ca738904e34..ab2225136f60 100644 --- a/fs/internal.h +++ b/fs/internal.h @@ -62,6 +62,9 @@ int do_mkdirat(int dfd, struct filename *name, umode_t mode); int do_symlinkat(struct filename *from, int newdfd, struct filename *to); int do_linkat(int olddfd, struct filename *old, int newdfd, struct filename *new, int flags); +int vfs_tmpfile(struct mnt_idmap *idmap, + const struct path *parentpath, + struct file *file, umode_t mode); /* * namespace.c diff --git a/fs/namei.c b/fs/namei.c index c5b2a25be7d0..13e50b0a49d2 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -3668,9 +3668,9 @@ static int do_open(struct nameidata *nd, * On non-idmapped mounts or if permission checking is to be performed on the * raw inode simply pass @nop_mnt_idmap. */ -static int vfs_tmpfile(struct mnt_idmap *idmap, - const struct path *parentpath, - struct file *file, umode_t mode) +int vfs_tmpfile(struct mnt_idmap *idmap, + const struct path *parentpath, + struct file *file, umode_t mode) { struct dentry *child; struct inode *dir = d_inode(parentpath->dentry); diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c index 0f8b4a719237..c614e923b143 100644 --- a/fs/overlayfs/dir.c +++ b/fs/overlayfs/dir.c @@ -14,6 +14,7 @@ #include #include #include +#include #include "overlayfs.h" static unsigned short ovl_redirect_max = 256; @@ -260,14 +261,13 @@ static int ovl_set_opaque(struct dentry *dentry, struct dentry *upperdentry) * may not use to instantiate the new dentry. */ static int ovl_instantiate(struct dentry *dentry, struct inode *inode, - struct dentry *newdentry, bool hardlink) + struct dentry *newdentry, bool hardlink, struct file *tmpfile) { struct ovl_inode_params oip = { .upperdentry = newdentry, .newinode = inode, }; - ovl_dir_modified(dentry->d_parent, false); ovl_dentry_set_upper_alias(dentry); ovl_dentry_init_reval(dentry, newdentry, NULL); @@ -295,6 +295,9 @@ static int ovl_instantiate(struct dentry *dentry, struct inode *inode, inc_nlink(inode); } + if (tmpfile) + d_mark_tmpfile(tmpfile, inode); + d_instantiate(dentry, inode); if (inode != oip.newinode) { pr_warn_ratelimited("newly created inode found in cache (%pd2)\n", @@ -345,7 +348,8 @@ static int ovl_create_upper(struct dentry *dentry, struct inode *inode, ovl_set_opaque(dentry, newdentry); } - err = ovl_instantiate(dentry, inode, newdentry, !!attr->hardlink); + ovl_dir_modified(dentry->d_parent, false); + err = ovl_instantiate(dentry, inode, newdentry, !!attr->hardlink, NULL); if (err) goto out_cleanup; out_unlock: @@ -529,7 +533,8 @@ static int ovl_create_over_whiteout(struct dentry *dentry, struct inode *inode, if (err) goto out_cleanup; } - err = ovl_instantiate(dentry, inode, newdentry, hardlink); + ovl_dir_modified(dentry->d_parent, false); + err = ovl_instantiate(dentry, inode, newdentry, hardlink, NULL); if (err) { ovl_cleanup(ofs, udir, newdentry); dput(newdentry); @@ -551,12 +556,35 @@ out_cleanup: goto out_dput; } +static int ovl_setup_cred_for_create(struct dentry *dentry, struct inode *inode, + umode_t mode, const struct cred *old_cred) +{ + int err; + struct cred *override_cred; + + override_cred = prepare_creds(); + if (!override_cred) + return -ENOMEM; + + override_cred->fsuid = inode->i_uid; + override_cred->fsgid = inode->i_gid; + err = security_dentry_create_files_as(dentry, mode, &dentry->d_name, + old_cred, override_cred); + if (err) { + put_cred(override_cred); + return err; + } + put_cred(override_creds(override_cred)); + put_cred(override_cred); + + return 0; +} + static int ovl_create_or_link(struct dentry *dentry, struct inode *inode, struct ovl_cattr *attr, bool origin) { int err; const struct cred *old_cred; - struct cred *override_cred; struct dentry *parent = dentry->d_parent; old_cred = ovl_override_creds(dentry->d_sb); @@ -572,10 +600,6 @@ static int ovl_create_or_link(struct dentry *dentry, struct inode *inode, } if (!attr->hardlink) { - err = -ENOMEM; - override_cred = prepare_creds(); - if (!override_cred) - goto out_revert_creds; /* * In the creation cases(create, mkdir, mknod, symlink), * ovl should transfer current's fs{u,g}id to underlying @@ -589,17 +613,9 @@ static int ovl_create_or_link(struct dentry *dentry, struct inode *inode, * create a new inode, so just use the ovl mounter's * fs{u,g}id. */ - override_cred->fsuid = inode->i_uid; - override_cred->fsgid = inode->i_gid; - err = security_dentry_create_files_as(dentry, - attr->mode, &dentry->d_name, old_cred, - override_cred); - if (err) { - put_cred(override_cred); + err = ovl_setup_cred_for_create(dentry, inode, attr->mode, old_cred); + if (err) goto out_revert_creds; - } - put_cred(override_creds(override_cred)); - put_cred(override_cred); } if (!ovl_dentry_is_whiteout(dentry)) @@ -1290,6 +1306,100 @@ out: return err; } +static int ovl_create_tmpfile(struct file *file, struct dentry *dentry, + struct inode *inode, umode_t mode) +{ + const struct cred *old_cred; + struct path realparentpath; + struct file *realfile; + struct dentry *newdentry; + /* It's okay to set O_NOATIME, since the owner will be current fsuid */ + int flags = file->f_flags | OVL_OPEN_FLAGS; + int err; + + err = ovl_copy_up(dentry->d_parent); + if (err) + return err; + + old_cred = ovl_override_creds(dentry->d_sb); + err = ovl_setup_cred_for_create(dentry, inode, mode, old_cred); + if (err) + goto out_revert_creds; + + ovl_path_upper(dentry->d_parent, &realparentpath); + realfile = backing_tmpfile_open(&file->f_path, flags, &realparentpath, + mode, current_cred()); + err = PTR_ERR_OR_ZERO(realfile); + pr_debug("tmpfile/open(%pd2, 0%o) = %i\n", realparentpath.dentry, mode, err); + if (err) + goto out_revert_creds; + + /* ovl_instantiate() consumes the newdentry reference on success */ + newdentry = dget(realfile->f_path.dentry); + err = ovl_instantiate(dentry, inode, newdentry, false, file); + if (!err) { + file->private_data = realfile; + } else { + dput(newdentry); + fput(realfile); + } +out_revert_creds: + revert_creds(old_cred); + return err; +} + +static int ovl_dummy_open(struct inode *inode, struct file *file) +{ + return 0; +} + +static int ovl_tmpfile(struct mnt_idmap *idmap, struct inode *dir, + struct file *file, umode_t mode) +{ + int err; + struct dentry *dentry = file->f_path.dentry; + struct inode *inode; + + if (!OVL_FS(dentry->d_sb)->tmpfile) + return -EOPNOTSUPP; + + err = ovl_want_write(dentry); + if (err) + return err; + + err = -ENOMEM; + inode = ovl_new_inode(dentry->d_sb, mode, 0); + if (!inode) + goto drop_write; + + inode_init_owner(&nop_mnt_idmap, inode, dir, mode); + err = ovl_create_tmpfile(file, dentry, inode, inode->i_mode); + if (err) + goto put_inode; + + /* + * Check if the preallocated inode was actually used. Having something + * else assigned to the dentry shouldn't happen as that would indicate + * that the backing tmpfile "leaked" out of overlayfs. + */ + err = -EIO; + if (WARN_ON(inode != d_inode(dentry))) + goto put_realfile; + + /* inode reference was transferred to dentry */ + inode = NULL; + err = finish_open(file, dentry, ovl_dummy_open); +put_realfile: + /* Without FMODE_OPENED ->release() won't be called on @file */ + if (!(file->f_mode & FMODE_OPENED)) + fput(file->private_data); +put_inode: + iput(inode); +drop_write: + ovl_drop_write(dentry); + return err; +} + const struct inode_operations ovl_dir_inode_operations = { .lookup = ovl_lookup, .mkdir = ovl_mkdir, @@ -1310,4 +1420,5 @@ const struct inode_operations ovl_dir_inode_operations = { .update_time = ovl_update_time, .fileattr_get = ovl_fileattr_get, .fileattr_set = ovl_fileattr_set, + .tmpfile = ovl_tmpfile, }; diff --git a/fs/overlayfs/file.c b/fs/overlayfs/file.c index 05536964d37f..1a411cae57ed 100644 --- a/fs/overlayfs/file.c +++ b/fs/overlayfs/file.c @@ -24,9 +24,6 @@ static char ovl_whatisit(struct inode *inode, struct inode *realinode) return 'm'; } -/* No atime modification on underlying */ -#define OVL_OPEN_FLAGS (O_NOATIME) - static struct file *ovl_open_realfile(const struct file *file, const struct path *realpath) { diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h index ee949f3e7c77..0bfe35da4b7b 100644 --- a/fs/overlayfs/overlayfs.h +++ b/fs/overlayfs/overlayfs.h @@ -175,6 +175,9 @@ static inline int ovl_metadata_digest_size(const struct ovl_metacopy *metacopy) return (int)metacopy->len - OVL_METACOPY_MIN_SIZE; } +/* No atime modification on underlying */ +#define OVL_OPEN_FLAGS (O_NOATIME) + extern const char *const ovl_xattr_table[][2]; static inline const char *ovl_xattr(struct ovl_fs *ofs, enum ovl_xattr ox) { diff --git a/include/linux/backing-file.h b/include/linux/backing-file.h index 3f1fe1774f1b..4b61b0e57720 100644 --- a/include/linux/backing-file.h +++ b/include/linux/backing-file.h @@ -22,6 +22,9 @@ struct backing_file_ctx { struct file *backing_file_open(const struct path *user_path, int flags, const struct path *real_path, const struct cred *cred); +struct file *backing_tmpfile_open(const struct path *user_path, int flags, + const struct path *real_parentpath, + umode_t mode, const struct cred *cred); ssize_t backing_file_read_iter(struct file *file, struct iov_iter *iter, struct kiocb *iocb, int flags, struct backing_file_ctx *ctx); -- cgit v1.2.3-59-g8ed1b From 096802748ea1dea8b476938e0a8dc16f4bd2f1ad Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Thu, 2 May 2024 20:35:57 +0200 Subject: ovl: remove upper umask handling from ovl_create_upper() This is already done by vfs_prepare_mode() when creating the upper object by vfs_create(), vfs_mkdir() and vfs_mknod(). No regressions have been observed in xfstests run with posix acls turned off for the upper filesystem. Fixes: 1639a49ccdce ("fs: move S_ISGID stripping into the vfs_*() helpers") Signed-off-by: Miklos Szeredi --- fs/overlayfs/dir.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c index c614e923b143..116f542442dd 100644 --- a/fs/overlayfs/dir.c +++ b/fs/overlayfs/dir.c @@ -330,9 +330,6 @@ static int ovl_create_upper(struct dentry *dentry, struct inode *inode, struct dentry *newdentry; int err; - if (!attr->hardlink && !IS_POSIXACL(udir)) - attr->mode &= ~current_umask(); - inode_lock_nested(udir, I_MUTEX_PARENT); newdentry = ovl_create_real(ofs, udir, ovl_lookup_upper(ofs, dentry->d_name.name, -- cgit v1.2.3-59-g8ed1b From 3cdd98b42d212160d7aae746a97960a4595cbfc2 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Mon, 29 Apr 2024 15:57:38 -0700 Subject: perf maps: Remove check_invariants() from maps__lock() I found that the debug build was a slowed down a lot by the maps lock code since it checks the invariants whenever it gets the pointer to the lock. This means it checks twice the invariants before and after the access. Instead, let's move the checking code within the lock area but after any modification and remove it from the read paths. This would remove (more than) half of the maps lock overhead. The time for perf report with a huge data file (200k+ of MMAP2 events). Non-debug Before After --------- -------- -------- 2m 43s 6m 45s 4m 21s Reviewed-by: Ian Rogers Signed-off-by: Namhyung Kim Cc: Adrian Hunter Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20240429225738.1491791-1-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/maps.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/tools/perf/util/maps.c b/tools/perf/util/maps.c index ce13145a9f8e..ac9fb880ddc7 100644 --- a/tools/perf/util/maps.c +++ b/tools/perf/util/maps.c @@ -211,11 +211,6 @@ void maps__set_unwind_libunwind_ops(struct maps *maps, const struct unwind_libun static struct rw_semaphore *maps__lock(struct maps *maps) { - /* - * When the lock is acquired or released the maps invariants should - * hold. - */ - check_invariants(maps); return &RC_CHK_ACCESS(maps)->lock; } @@ -358,6 +353,7 @@ static int map__strcmp(const void *a, const void *b) static int maps__sort_by_name(struct maps *maps) { int err = 0; + down_write(maps__lock(maps)); if (!maps__maps_by_name_sorted(maps)) { struct map **maps_by_name = maps__maps_by_name(maps); @@ -384,6 +380,7 @@ static int maps__sort_by_name(struct maps *maps) maps__set_maps_by_name_sorted(maps, true); } } + check_invariants(maps); up_write(maps__lock(maps)); return err; } @@ -502,6 +499,7 @@ int maps__insert(struct maps *maps, struct map *map) down_write(maps__lock(maps)); ret = __maps__insert(maps, map); + check_invariants(maps); up_write(maps__lock(maps)); return ret; } @@ -536,6 +534,7 @@ void maps__remove(struct maps *maps, struct map *map) { down_write(maps__lock(maps)); __maps__remove(maps, map); + check_invariants(maps); up_write(maps__lock(maps)); } @@ -602,6 +601,7 @@ void maps__remove_maps(struct maps *maps, bool (*cb)(struct map *map, void *data else i++; } + check_invariants(maps); up_write(maps__lock(maps)); } @@ -942,6 +942,8 @@ int maps__copy_from(struct maps *dest, struct maps *parent) map__put(new); } } + check_invariants(dest); + up_read(maps__lock(parent)); up_write(maps__lock(dest)); return err; @@ -1097,6 +1099,7 @@ void maps__fixup_end(struct maps *maps) map__set_end(maps_by_address[n - 1], ~0ULL); RC_CHK_ACCESS(maps)->ends_broken = false; + check_invariants(maps); up_write(maps__lock(maps)); } @@ -1147,6 +1150,8 @@ int maps__merge_in(struct maps *kmaps, struct map *new_map) map__start(kmaps_maps_by_address[first_after_]) >= map__end(new_map)) { /* No overlap so regular insert suffices. */ int ret = __maps__insert(kmaps, new_map); + + check_invariants(kmaps); up_write(maps__lock(kmaps)); return ret; } @@ -1184,6 +1189,7 @@ int maps__merge_in(struct maps *kmaps, struct map *new_map) map__zput(kmaps_maps_by_address[i]); free(kmaps_maps_by_address); + check_invariants(kmaps); up_write(maps__lock(kmaps)); return 0; } -- cgit v1.2.3-59-g8ed1b From af63dd715a5c6b66bbd1485c2189b92c1a3fba41 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 16 Apr 2024 20:12:47 -0400 Subject: bcache_register(): don't bother with set_blocksize() We are not using __bread() anymore and read_cache_page_gfp() doesn't care about block size. Moreover, we should *not* change block size on a device that is currently held exclusive - filesystems that use buffer cache expect the block numbers to be interpreted in units set by filesystem. Reviewed-by: Christoph Hellwig Reviewed-by: Christian Brauner ACKed-by: Kent Overstreet Signed-off-by: Al Viro --- drivers/md/bcache/super.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c index 330bcd9ea4a9..0ee5e17ae2dd 100644 --- a/drivers/md/bcache/super.c +++ b/drivers/md/bcache/super.c @@ -2554,10 +2554,6 @@ static ssize_t register_bcache(struct kobject *k, struct kobj_attribute *attr, if (IS_ERR(bdev_file)) goto out_free_sb; - err = "failed to set blocksize"; - if (set_blocksize(file_bdev(bdev_file), 4096)) - goto out_blkdev_put; - err = read_super(sb, file_bdev(bdev_file), &sb_disk); if (err) goto out_blkdev_put; -- cgit v1.2.3-59-g8ed1b From 3a52c03d1ece8f480d6a6c35d92f7c1c6215d2a6 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 17 Apr 2024 00:28:03 -0400 Subject: pktcdvd: sort set_blocksize() calls out 1) it doesn't make any sense to have ->open() call set_blocksize() on the device being opened - the caller will override that anyway. 2) setting block size on underlying device, OTOH, ought to be done when we are opening it exclusive - i.e. as part of pkt_open_dev(). Having it done at setup time doesn't guarantee us anything about the state at the time we start talking to it. Worse, if you happen to have the underlying device containing e.g. ext2 with 4Kb blocks that is currently mounted r/o, that set_blocksize() will confuse the hell out of filesystem. Reviewed-by: Christoph Hellwig Reviewed-by: Christian Brauner Signed-off-by: Al Viro --- drivers/block/pktcdvd.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index 21728e9ea5c3..05933f25b397 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -2215,6 +2215,7 @@ static int pkt_open_dev(struct pktcdvd_device *pd, bool write) } dev_info(ddev, "%lukB available on disc\n", lba << 1); } + set_blocksize(file_bdev(bdev_file), CD_FRAMESIZE); return 0; @@ -2278,11 +2279,6 @@ static int pkt_open(struct gendisk *disk, blk_mode_t mode) ret = pkt_open_dev(pd, mode & BLK_OPEN_WRITE); if (ret) goto out_dec; - /* - * needed here as well, since ext2 (among others) may change - * the blocksize at mount time - */ - set_blocksize(disk->part0, CD_FRAMESIZE); } mutex_unlock(&ctl_mutex); mutex_unlock(&pktcdvd_mutex); @@ -2526,7 +2522,6 @@ static int pkt_new_dev(struct pktcdvd_device *pd, dev_t dev) __module_get(THIS_MODULE); pd->bdev_file = bdev_file; - set_blocksize(file_bdev(bdev_file), CD_FRAMESIZE); atomic_set(&pd->cdrw.pending_bios, 0); pd->cdrw.thread = kthread_run(kcdrwd, pd, "%s", pd->disk->disk_name); -- cgit v1.2.3-59-g8ed1b From 798cb7f9aec35460c383eab57b9fa474d999a2eb Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 17 Apr 2024 18:26:54 -0400 Subject: swapon(2)/swapoff(2): don't bother with block size once upon a time that used to matter; these days we do swap IO for swap devices at the level that doesn't give a damn about block size, buffer_head or anything of that sort - just attach the page to bio, set the location and size (the latter to PAGE_SIZE) and feed into queue. Reviewed-by: Christoph Hellwig Reviewed-by: Christian Brauner Signed-off-by: Al Viro --- include/linux/swap.h | 1 - mm/swapfile.c | 12 +----------- 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/include/linux/swap.h b/include/linux/swap.h index f53d608daa01..a5b640cca459 100644 --- a/include/linux/swap.h +++ b/include/linux/swap.h @@ -301,7 +301,6 @@ struct swap_info_struct { struct file *bdev_file; /* open handle of the bdev */ struct block_device *bdev; /* swap device or bdev of swap file */ struct file *swap_file; /* seldom referenced */ - unsigned int old_block_size; /* seldom referenced */ struct completion comp; /* seldom referenced */ spinlock_t lock; /* * protect map scan related fields like diff --git a/mm/swapfile.c b/mm/swapfile.c index 4919423cce76..304f74d039f3 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -2417,7 +2417,6 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile) struct inode *inode; struct filename *pathname; int err, found = 0; - unsigned int old_block_size; if (!capable(CAP_SYS_ADMIN)) return -EPERM; @@ -2529,7 +2528,6 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile) } swap_file = p->swap_file; - old_block_size = p->old_block_size; p->swap_file = NULL; p->max = 0; swap_map = p->swap_map; @@ -2553,7 +2551,6 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile) inode = mapping->host; if (p->bdev_file) { - set_blocksize(p->bdev, old_block_size); fput(p->bdev_file); p->bdev_file = NULL; } @@ -2782,21 +2779,15 @@ static struct swap_info_struct *alloc_swap_info(void) static int claim_swapfile(struct swap_info_struct *p, struct inode *inode) { - int error; - if (S_ISBLK(inode->i_mode)) { p->bdev_file = bdev_file_open_by_dev(inode->i_rdev, BLK_OPEN_READ | BLK_OPEN_WRITE, p, NULL); if (IS_ERR(p->bdev_file)) { - error = PTR_ERR(p->bdev_file); + int error = PTR_ERR(p->bdev_file); p->bdev_file = NULL; return error; } p->bdev = file_bdev(p->bdev_file); - p->old_block_size = block_size(p->bdev); - error = set_blocksize(p->bdev, PAGE_SIZE); - if (error < 0) - return error; /* * Zoned block devices contain zones that have a sequential * write only restriction. Hence zoned block devices are not @@ -3235,7 +3226,6 @@ bad_swap: free_percpu(p->cluster_next_cpu); p->cluster_next_cpu = NULL; if (p->bdev_file) { - set_blocksize(p->bdev, p->old_block_size); fput(p->bdev_file); p->bdev_file = NULL; } -- cgit v1.2.3-59-g8ed1b From 51d908b3db0e588aeb2d06df37e4df3fb1754bb5 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 17 Apr 2024 18:33:34 -0400 Subject: swapon(2): open swap with O_EXCL ... eliminating the need to reopen block devices so they could be exclusively held. Reviewed-by: Christoph Hellwig Reviewed-by: Christian Brauner Signed-off-by: Al Viro --- include/linux/swap.h | 1 - mm/swapfile.c | 19 ++----------------- 2 files changed, 2 insertions(+), 18 deletions(-) diff --git a/include/linux/swap.h b/include/linux/swap.h index a5b640cca459..7e61a4aef2fc 100644 --- a/include/linux/swap.h +++ b/include/linux/swap.h @@ -298,7 +298,6 @@ struct swap_info_struct { unsigned int __percpu *cluster_next_cpu; /*percpu index for next allocation */ struct percpu_cluster __percpu *percpu_cluster; /* per cpu's swap location */ struct rb_root swap_extent_root;/* root of the swap extent rbtree */ - struct file *bdev_file; /* open handle of the bdev */ struct block_device *bdev; /* swap device or bdev of swap file */ struct file *swap_file; /* seldom referenced */ struct completion comp; /* seldom referenced */ diff --git a/mm/swapfile.c b/mm/swapfile.c index 304f74d039f3..7bba0b0d4924 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -2550,10 +2550,6 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile) exit_swap_address_space(p->type); inode = mapping->host; - if (p->bdev_file) { - fput(p->bdev_file); - p->bdev_file = NULL; - } inode_lock(inode); inode->i_flags &= ~S_SWAPFILE; @@ -2780,14 +2776,7 @@ static struct swap_info_struct *alloc_swap_info(void) static int claim_swapfile(struct swap_info_struct *p, struct inode *inode) { if (S_ISBLK(inode->i_mode)) { - p->bdev_file = bdev_file_open_by_dev(inode->i_rdev, - BLK_OPEN_READ | BLK_OPEN_WRITE, p, NULL); - if (IS_ERR(p->bdev_file)) { - int error = PTR_ERR(p->bdev_file); - p->bdev_file = NULL; - return error; - } - p->bdev = file_bdev(p->bdev_file); + p->bdev = I_BDEV(inode); /* * Zoned block devices contain zones that have a sequential * write only restriction. Hence zoned block devices are not @@ -3028,7 +3017,7 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) name = NULL; goto bad_swap; } - swap_file = file_open_name(name, O_RDWR|O_LARGEFILE, 0); + swap_file = file_open_name(name, O_RDWR | O_LARGEFILE | O_EXCL, 0); if (IS_ERR(swap_file)) { error = PTR_ERR(swap_file); swap_file = NULL; @@ -3225,10 +3214,6 @@ bad_swap: p->percpu_cluster = NULL; free_percpu(p->cluster_next_cpu); p->cluster_next_cpu = NULL; - if (p->bdev_file) { - fput(p->bdev_file); - p->bdev_file = NULL; - } inode = NULL; destroy_swap_extents(p); swap_cgroup_swapoff(p->type); -- cgit v1.2.3-59-g8ed1b From ebb0173df2015187bacf704d16a95119d4bc306d Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 28 Apr 2024 18:55:47 -0400 Subject: zram: don't bother with reopening - just use O_EXCL for open Signed-off-by: Al Viro --- drivers/block/zram/zram_drv.c | 29 +++++++---------------------- drivers/block/zram/zram_drv.h | 2 +- 2 files changed, 8 insertions(+), 23 deletions(-) diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c index f0639df6cd18..58c3466dcb17 100644 --- a/drivers/block/zram/zram_drv.c +++ b/drivers/block/zram/zram_drv.c @@ -426,11 +426,10 @@ static void reset_bdev(struct zram *zram) if (!zram->backing_dev) return; - fput(zram->bdev_file); /* hope filp_close flush all of IO */ filp_close(zram->backing_dev, NULL); zram->backing_dev = NULL; - zram->bdev_file = NULL; + zram->bdev = NULL; zram->disk->fops = &zram_devops; kvfree(zram->bitmap); zram->bitmap = NULL; @@ -473,10 +472,8 @@ static ssize_t backing_dev_store(struct device *dev, size_t sz; struct file *backing_dev = NULL; struct inode *inode; - struct address_space *mapping; unsigned int bitmap_sz; unsigned long nr_pages, *bitmap = NULL; - struct file *bdev_file = NULL; int err; struct zram *zram = dev_to_zram(dev); @@ -497,15 +494,14 @@ static ssize_t backing_dev_store(struct device *dev, if (sz > 0 && file_name[sz - 1] == '\n') file_name[sz - 1] = 0x00; - backing_dev = filp_open(file_name, O_RDWR|O_LARGEFILE, 0); + backing_dev = filp_open(file_name, O_RDWR | O_LARGEFILE | O_EXCL, 0); if (IS_ERR(backing_dev)) { err = PTR_ERR(backing_dev); backing_dev = NULL; goto out; } - mapping = backing_dev->f_mapping; - inode = mapping->host; + inode = backing_dev->f_mapping->host; /* Support only block device in this moment */ if (!S_ISBLK(inode->i_mode)) { @@ -513,14 +509,6 @@ static ssize_t backing_dev_store(struct device *dev, goto out; } - bdev_file = bdev_file_open_by_dev(inode->i_rdev, - BLK_OPEN_READ | BLK_OPEN_WRITE, zram, NULL); - if (IS_ERR(bdev_file)) { - err = PTR_ERR(bdev_file); - bdev_file = NULL; - goto out; - } - nr_pages = i_size_read(inode) >> PAGE_SHIFT; bitmap_sz = BITS_TO_LONGS(nr_pages) * sizeof(long); bitmap = kvzalloc(bitmap_sz, GFP_KERNEL); @@ -531,7 +519,7 @@ static ssize_t backing_dev_store(struct device *dev, reset_bdev(zram); - zram->bdev_file = bdev_file; + zram->bdev = I_BDEV(inode); zram->backing_dev = backing_dev; zram->bitmap = bitmap; zram->nr_pages = nr_pages; @@ -544,9 +532,6 @@ static ssize_t backing_dev_store(struct device *dev, out: kvfree(bitmap); - if (bdev_file) - fput(bdev_file); - if (backing_dev) filp_close(backing_dev, NULL); @@ -587,7 +572,7 @@ static void read_from_bdev_async(struct zram *zram, struct page *page, { struct bio *bio; - bio = bio_alloc(file_bdev(zram->bdev_file), 1, parent->bi_opf, GFP_NOIO); + bio = bio_alloc(zram->bdev, 1, parent->bi_opf, GFP_NOIO); bio->bi_iter.bi_sector = entry * (PAGE_SIZE >> 9); __bio_add_page(bio, page, PAGE_SIZE, 0); bio_chain(bio, parent); @@ -703,7 +688,7 @@ static ssize_t writeback_store(struct device *dev, continue; } - bio_init(&bio, file_bdev(zram->bdev_file), &bio_vec, 1, + bio_init(&bio, zram->bdev, &bio_vec, 1, REQ_OP_WRITE | REQ_SYNC); bio.bi_iter.bi_sector = blk_idx * (PAGE_SIZE >> 9); __bio_add_page(&bio, page, PAGE_SIZE, 0); @@ -785,7 +770,7 @@ static void zram_sync_read(struct work_struct *work) struct bio_vec bv; struct bio bio; - bio_init(&bio, file_bdev(zw->zram->bdev_file), &bv, 1, REQ_OP_READ); + bio_init(&bio, zw->zram->bdev, &bv, 1, REQ_OP_READ); bio.bi_iter.bi_sector = zw->entry * (PAGE_SIZE >> 9); __bio_add_page(&bio, zw->page, PAGE_SIZE, 0); zw->error = submit_bio_wait(&bio); diff --git a/drivers/block/zram/zram_drv.h b/drivers/block/zram/zram_drv.h index 37bf29f34d26..35e322144629 100644 --- a/drivers/block/zram/zram_drv.h +++ b/drivers/block/zram/zram_drv.h @@ -132,7 +132,7 @@ struct zram { spinlock_t wb_limit_lock; bool wb_limit_enable; u64 bd_wb_limit; - struct file *bdev_file; + struct block_device *bdev; unsigned long *bitmap; unsigned long nr_pages; #endif -- cgit v1.2.3-59-g8ed1b From b1439b179d351977641a1df9745a24d08693f9d4 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 17 Apr 2024 18:38:38 -0400 Subject: swsusp: don't bother with setting block size same as with the swap... Reviewed-by: Christoph Hellwig Reviewed-by: Christian Brauner Signed-off-by: Al Viro --- kernel/power/swap.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/kernel/power/swap.c b/kernel/power/swap.c index 5bc04bfe2db1..d9abb7ab031d 100644 --- a/kernel/power/swap.c +++ b/kernel/power/swap.c @@ -368,11 +368,7 @@ static int swsusp_swap_check(void) if (IS_ERR(hib_resume_bdev_file)) return PTR_ERR(hib_resume_bdev_file); - res = set_blocksize(file_bdev(hib_resume_bdev_file), PAGE_SIZE); - if (res < 0) - fput(hib_resume_bdev_file); - - return res; + return 0; } /** @@ -1574,7 +1570,6 @@ int swsusp_check(bool exclusive) hib_resume_bdev_file = bdev_file_open_by_dev(swsusp_resume_device, BLK_OPEN_READ, holder, NULL); if (!IS_ERR(hib_resume_bdev_file)) { - set_blocksize(file_bdev(hib_resume_bdev_file), PAGE_SIZE); clear_page(swsusp_header); error = hib_submit_io(REQ_OP_READ, swsusp_resume_block, swsusp_header, NULL); -- cgit v1.2.3-59-g8ed1b From b85c42981ac4abeeb15d16437c40f52a8a64787d Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 18 Apr 2024 00:21:25 -0400 Subject: btrfs_get_bdev_and_sb(): call set_blocksize() only for exclusive opens btrfs_get_bdev_and_sb() has two callers - btrfs_open_one_device(), which asks for open to be exclusive and btrfs_get_dev_args_from_path(), which doesn't. Currently it does set_blocksize() in all cases. I'm rather dubious about the need to do set_blocksize() anywhere in btrfs, to be honest - there's some access to page cache of underlying block devices in there, but it's nowhere near the hot paths, AFAICT. In any case, btrfs_get_dev_args_from_path() only needs to read the on-disk superblock and copy several fields out of it; all callers are only interested in devices that are already opened and brought into per-filesystem set, so setting the block size is redundant for those and actively harmful if we are given a pathname of unrelated device. So we only need btrfs_get_bdev_and_sb() to call set_blocksize() when it's asked to open exclusive. Reviewed-by: Christoph Hellwig Reviewed-by: Christian Brauner Signed-off-by: Al Viro --- fs/btrfs/volumes.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index f15591f3e54f..43af5a9fb547 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -482,10 +482,12 @@ btrfs_get_bdev_and_sb(const char *device_path, blk_mode_t flags, void *holder, if (flush) sync_blockdev(bdev); - ret = set_blocksize(bdev, BTRFS_BDEV_BLOCKSIZE); - if (ret) { - fput(*bdev_file); - goto error; + if (holder) { + ret = set_blocksize(bdev, BTRFS_BDEV_BLOCKSIZE); + if (ret) { + fput(*bdev_file); + goto error; + } } invalidate_bdev(bdev); *disk_super = btrfs_read_dev_super(bdev); @@ -498,6 +500,7 @@ btrfs_get_bdev_and_sb(const char *device_path, blk_mode_t flags, void *holder, return 0; error: + *disk_super = NULL; *bdev_file = NULL; return ret; } -- cgit v1.2.3-59-g8ed1b From ead083aeeed9df44fab9227e47688f7305c3a233 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 18 Apr 2024 00:34:31 -0400 Subject: set_blocksize(): switch to passing struct file * Signed-off-by: Al Viro --- block/bdev.c | 11 +++++++---- block/ioctl.c | 21 ++++++++++++--------- drivers/block/pktcdvd.c | 2 +- fs/btrfs/dev-replace.c | 2 +- fs/btrfs/volumes.c | 4 ++-- fs/ext4/super.c | 2 +- fs/reiserfs/journal.c | 5 ++--- fs/xfs/xfs_buf.c | 2 +- include/linux/blkdev.h | 2 +- 9 files changed, 28 insertions(+), 23 deletions(-) diff --git a/block/bdev.c b/block/bdev.c index b8e32d933a63..a329ff9be11d 100644 --- a/block/bdev.c +++ b/block/bdev.c @@ -144,8 +144,11 @@ static void set_init_blocksize(struct block_device *bdev) bdev->bd_inode->i_blkbits = blksize_bits(bsize); } -int set_blocksize(struct block_device *bdev, int size) +int set_blocksize(struct file *file, int size) { + struct inode *inode = file->f_mapping->host; + struct block_device *bdev = I_BDEV(inode); + /* Size must be a power of two, and between 512 and PAGE_SIZE */ if (size > PAGE_SIZE || size < 512 || !is_power_of_2(size)) return -EINVAL; @@ -155,9 +158,9 @@ int set_blocksize(struct block_device *bdev, int size) return -EINVAL; /* Don't change the size if it is same as current */ - if (bdev->bd_inode->i_blkbits != blksize_bits(size)) { + if (inode->i_blkbits != blksize_bits(size)) { sync_blockdev(bdev); - bdev->bd_inode->i_blkbits = blksize_bits(size); + inode->i_blkbits = blksize_bits(size); kill_bdev(bdev); } return 0; @@ -167,7 +170,7 @@ EXPORT_SYMBOL(set_blocksize); int sb_set_blocksize(struct super_block *sb, int size) { - if (set_blocksize(sb->s_bdev, size)) + if (set_blocksize(sb->s_bdev_file, size)) return 0; /* If we get here, we know size is power of two * and it's value is between 512 and PAGE_SIZE */ diff --git a/block/ioctl.c b/block/ioctl.c index a9028a2c2db5..1c800364bc70 100644 --- a/block/ioctl.c +++ b/block/ioctl.c @@ -473,11 +473,14 @@ static int compat_hdio_getgeo(struct block_device *bdev, #endif /* set the logical block size */ -static int blkdev_bszset(struct block_device *bdev, blk_mode_t mode, +static int blkdev_bszset(struct file *file, blk_mode_t mode, int __user *argp) { + // this one might be file_inode(file)->i_rdev - a rare valid + // use of file_inode() for those. + dev_t dev = I_BDEV(file->f_mapping->host)->bd_dev; + struct file *excl_file; int ret, n; - struct file *file; if (!capable(CAP_SYS_ADMIN)) return -EACCES; @@ -487,13 +490,13 @@ static int blkdev_bszset(struct block_device *bdev, blk_mode_t mode, return -EFAULT; if (mode & BLK_OPEN_EXCL) - return set_blocksize(bdev, n); + return set_blocksize(file, n); - file = bdev_file_open_by_dev(bdev->bd_dev, mode, &bdev, NULL); - if (IS_ERR(file)) + excl_file = bdev_file_open_by_dev(dev, mode, &dev, NULL); + if (IS_ERR(excl_file)) return -EBUSY; - ret = set_blocksize(bdev, n); - fput(file); + ret = set_blocksize(excl_file, n); + fput(excl_file); return ret; } @@ -621,7 +624,7 @@ long blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg) case BLKBSZGET: /* get block device soft block size (cf. BLKSSZGET) */ return put_int(argp, block_size(bdev)); case BLKBSZSET: - return blkdev_bszset(bdev, mode, argp); + return blkdev_bszset(file, mode, argp); case BLKGETSIZE64: return put_u64(argp, bdev_nr_bytes(bdev)); @@ -681,7 +684,7 @@ long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg) case BLKBSZGET_32: /* get the logical block size (cf. BLKSSZGET) */ return put_int(argp, bdev_logical_block_size(bdev)); case BLKBSZSET_32: - return blkdev_bszset(bdev, mode, argp); + return blkdev_bszset(file, mode, argp); case BLKGETSIZE64_32: return put_u64(argp, bdev_nr_bytes(bdev)); diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index 05933f25b397..8a2ce8070010 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -2215,7 +2215,7 @@ static int pkt_open_dev(struct pktcdvd_device *pd, bool write) } dev_info(ddev, "%lukB available on disc\n", lba << 1); } - set_blocksize(file_bdev(bdev_file), CD_FRAMESIZE); + set_blocksize(bdev_file, CD_FRAMESIZE); return 0; diff --git a/fs/btrfs/dev-replace.c b/fs/btrfs/dev-replace.c index 7696beec4c21..7130040d92ab 100644 --- a/fs/btrfs/dev-replace.c +++ b/fs/btrfs/dev-replace.c @@ -316,7 +316,7 @@ static int btrfs_init_dev_replace_tgtdev(struct btrfs_fs_info *fs_info, set_bit(BTRFS_DEV_STATE_IN_FS_METADATA, &device->dev_state); set_bit(BTRFS_DEV_STATE_REPLACE_TGT, &device->dev_state); device->dev_stats_valid = 1; - set_blocksize(device->bdev, BTRFS_BDEV_BLOCKSIZE); + set_blocksize(bdev_file, BTRFS_BDEV_BLOCKSIZE); device->fs_devices = fs_devices; ret = btrfs_get_dev_zone_info(device, false); diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 43af5a9fb547..65c03ddecc59 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -483,7 +483,7 @@ btrfs_get_bdev_and_sb(const char *device_path, blk_mode_t flags, void *holder, if (flush) sync_blockdev(bdev); if (holder) { - ret = set_blocksize(bdev, BTRFS_BDEV_BLOCKSIZE); + ret = set_blocksize(*bdev_file, BTRFS_BDEV_BLOCKSIZE); if (ret) { fput(*bdev_file); goto error; @@ -2717,7 +2717,7 @@ int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *device_path set_bit(BTRFS_DEV_STATE_IN_FS_METADATA, &device->dev_state); clear_bit(BTRFS_DEV_STATE_REPLACE_TGT, &device->dev_state); device->dev_stats_valid = 1; - set_blocksize(device->bdev, BTRFS_BDEV_BLOCKSIZE); + set_blocksize(device->bdev_file, BTRFS_BDEV_BLOCKSIZE); if (seeding_dev) { btrfs_clear_sb_rdonly(sb); diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 044135796f2b..9988b3a40b42 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -5873,7 +5873,7 @@ static struct file *ext4_get_journal_blkdev(struct super_block *sb, sb_block = EXT4_MIN_BLOCK_SIZE / blocksize; offset = EXT4_MIN_BLOCK_SIZE % blocksize; - set_blocksize(bdev, blocksize); + set_blocksize(bdev_file, blocksize); bh = __bread(bdev, sb_block, blocksize); if (!bh) { ext4_msg(sb, KERN_ERR, "couldn't read superblock of " diff --git a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c index e539ccd39e1e..e477ee0ff35d 100644 --- a/fs/reiserfs/journal.c +++ b/fs/reiserfs/journal.c @@ -2626,8 +2626,7 @@ static int journal_init_dev(struct super_block *super, MAJOR(jdev), MINOR(jdev), result); return result; } else if (jdev != super->s_dev) - set_blocksize(file_bdev(journal->j_bdev_file), - super->s_blocksize); + set_blocksize(journal->j_bdev_file, super->s_blocksize); return 0; } @@ -2643,7 +2642,7 @@ static int journal_init_dev(struct super_block *super, return result; } - set_blocksize(file_bdev(journal->j_bdev_file), super->s_blocksize); + set_blocksize(journal->j_bdev_file, super->s_blocksize); reiserfs_info(super, "journal_init_dev: journal device: %pg\n", file_bdev(journal->j_bdev_file)); diff --git a/fs/xfs/xfs_buf.c b/fs/xfs/xfs_buf.c index f0fa02264eda..2dc0eacb0999 100644 --- a/fs/xfs/xfs_buf.c +++ b/fs/xfs/xfs_buf.c @@ -2043,7 +2043,7 @@ xfs_setsize_buftarg( btp->bt_meta_sectorsize = sectorsize; btp->bt_meta_sectormask = sectorsize - 1; - if (set_blocksize(btp->bt_bdev, sectorsize)) { + if (set_blocksize(btp->bt_bdev_file, sectorsize)) { xfs_warn(btp->bt_mount, "Cannot set_blocksize to %u on device %pg", sectorsize, btp->bt_bdev); diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 172c91879999..20c749b2ebc2 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -1474,7 +1474,7 @@ static inline void bio_end_io_acct(struct bio *bio, unsigned long start_time) } int bdev_read_only(struct block_device *bdev); -int set_blocksize(struct block_device *bdev, int size); +int set_blocksize(struct file *file, int size); int lookup_bdev(const char *pathname, dev_t *dev); -- cgit v1.2.3-59-g8ed1b From d18a8679581e8d1166b68e211d16c5349ae8c38c Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 2 May 2024 17:36:32 -0400 Subject: make set_blocksize() fail unless block device is opened exclusive Signed-off-by: Al Viro --- Documentation/filesystems/porting.rst | 7 +++++++ block/bdev.c | 3 +++ 2 files changed, 10 insertions(+) diff --git a/Documentation/filesystems/porting.rst b/Documentation/filesystems/porting.rst index 1be76ef117b3..5503d5c614a7 100644 --- a/Documentation/filesystems/porting.rst +++ b/Documentation/filesystems/porting.rst @@ -1134,3 +1134,10 @@ superblock of the main block device, i.e., the one stored in sb->s_bdev. Block device freezing now works for any block device owned by a given superblock, not just the main block device. The get_active_super() helper and bd_fsfreeze_sb pointer are gone. + +--- + +**mandatory** + +set_blocksize() takes opened struct file instead of struct block_device now +and it *must* be opened exclusive. diff --git a/block/bdev.c b/block/bdev.c index a329ff9be11d..a89bce368b64 100644 --- a/block/bdev.c +++ b/block/bdev.c @@ -157,6 +157,9 @@ int set_blocksize(struct file *file, int size) if (size < bdev_logical_block_size(bdev)) return -EINVAL; + if (!file->private_data) + return -EINVAL; + /* Don't change the size if it is same as current */ if (inode->i_blkbits != blksize_bits(size)) { sync_blockdev(bdev); -- cgit v1.2.3-59-g8ed1b From 3f9b8fb46e5d20eac314f56747e24e1a4e74539d Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 12 Apr 2024 00:54:19 -0400 Subject: Use bdev_is_paritition() instead of open-coding it Reviewed-by: Christoph Hellwig Signed-off-by: Al Viro --- block/blk-core.c | 5 +++-- block/blk-mq.c | 2 +- include/linux/part_stat.h | 2 +- lib/vsprintf.c | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/block/blk-core.c b/block/blk-core.c index a16b5abdbbf5..20322abc6082 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -759,7 +759,8 @@ void submit_bio_noacct(struct bio *bio) if (!bio_flagged(bio, BIO_REMAPPED)) { if (unlikely(bio_check_eod(bio))) goto end_io; - if (bdev->bd_partno && unlikely(blk_partition_remap(bio))) + if (bdev_is_partition(bdev) && + unlikely(blk_partition_remap(bio))) goto end_io; } @@ -989,7 +990,7 @@ again: if (likely(try_cmpxchg(&part->bd_stamp, &stamp, now))) __part_stat_add(part, io_ticks, end ? now - stamp : 1); } - if (part->bd_partno) { + if (bdev_is_partition(part)) { part = bdev_whole(part); goto again; } diff --git a/block/blk-mq.c b/block/blk-mq.c index 32afb87efbd0..43bb8f50a07c 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -92,7 +92,7 @@ static bool blk_mq_check_inflight(struct request *rq, void *priv) struct mq_inflight *mi = priv; if (rq->part && blk_do_io_stat(rq) && - (!mi->part->bd_partno || rq->part == mi->part) && + (!bdev_is_partition(mi->part) || rq->part == mi->part) && blk_mq_rq_state(rq) == MQ_RQ_IN_FLIGHT) mi->inflight[rq_data_dir(rq)]++; diff --git a/include/linux/part_stat.h b/include/linux/part_stat.h index abeba356bc3f..ac8c44dd8237 100644 --- a/include/linux/part_stat.h +++ b/include/linux/part_stat.h @@ -59,7 +59,7 @@ static inline void part_stat_set_all(struct block_device *part, int value) #define part_stat_add(part, field, addnd) do { \ __part_stat_add((part), field, addnd); \ - if ((part)->bd_partno) \ + if (bdev_is_partition(part)) \ __part_stat_add(bdev_whole(part), field, addnd); \ } while (0) diff --git a/lib/vsprintf.c b/lib/vsprintf.c index 552738f14275..3f9f1b959ef0 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -966,7 +966,7 @@ char *bdev_name(char *buf, char *end, struct block_device *bdev, hd = bdev->bd_disk; buf = string(buf, end, hd->disk_name, spec); - if (bdev->bd_partno) { + if (bdev_is_partition(bdev)) { if (isdigit(hd->disk_name[strlen(hd->disk_name)-1])) { if (buf < end) *buf = 'p'; -- cgit v1.2.3-59-g8ed1b From b8c873edbf35570b93edfeddad9e85da54defa52 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 12 Apr 2024 01:01:36 -0400 Subject: wrapper for access to ->bd_partno On the next step it's going to get folded into a field where flags will go. Signed-off-by: Al Viro --- block/early-lookup.c | 2 +- block/partitions/core.c | 12 ++++++------ include/linux/blkdev.h | 7 ++++++- lib/vsprintf.c | 2 +- 4 files changed, 14 insertions(+), 9 deletions(-) diff --git a/block/early-lookup.c b/block/early-lookup.c index 3effbd0d35e9..3fb57f7d2b12 100644 --- a/block/early-lookup.c +++ b/block/early-lookup.c @@ -78,7 +78,7 @@ static int __init devt_from_partuuid(const char *uuid_str, dev_t *devt) * to the partition number found by UUID. */ *devt = part_devt(dev_to_disk(dev), - dev_to_bdev(dev)->bd_partno + offset); + bdev_partno(dev_to_bdev(dev)) + offset); } else { *devt = dev->devt; } diff --git a/block/partitions/core.c b/block/partitions/core.c index b11e88c82c8c..edd5309dc4ba 100644 --- a/block/partitions/core.c +++ b/block/partitions/core.c @@ -173,7 +173,7 @@ static struct parsed_partitions *check_partition(struct gendisk *hd) static ssize_t part_partition_show(struct device *dev, struct device_attribute *attr, char *buf) { - return sprintf(buf, "%d\n", dev_to_bdev(dev)->bd_partno); + return sprintf(buf, "%d\n", bdev_partno(dev_to_bdev(dev))); } static ssize_t part_start_show(struct device *dev, @@ -250,7 +250,7 @@ static int part_uevent(const struct device *dev, struct kobj_uevent_env *env) { const struct block_device *part = dev_to_bdev(dev); - add_uevent_var(env, "PARTN=%u", part->bd_partno); + add_uevent_var(env, "PARTN=%u", bdev_partno(part)); if (part->bd_meta_info && part->bd_meta_info->volname[0]) add_uevent_var(env, "PARTNAME=%s", part->bd_meta_info->volname); return 0; @@ -267,7 +267,7 @@ void drop_partition(struct block_device *part) { lockdep_assert_held(&part->bd_disk->open_mutex); - xa_erase(&part->bd_disk->part_tbl, part->bd_partno); + xa_erase(&part->bd_disk->part_tbl, bdev_partno(part)); kobject_put(part->bd_holder_dir); device_del(&part->bd_device); @@ -338,8 +338,8 @@ static struct block_device *add_partition(struct gendisk *disk, int partno, pdev->parent = ddev; /* in consecutive minor range? */ - if (bdev->bd_partno < disk->minors) { - devt = MKDEV(disk->major, disk->first_minor + bdev->bd_partno); + if (bdev_partno(bdev) < disk->minors) { + devt = MKDEV(disk->major, disk->first_minor + bdev_partno(bdev)); } else { err = blk_alloc_ext_minor(); if (err < 0) @@ -404,7 +404,7 @@ static bool partition_overlaps(struct gendisk *disk, sector_t start, rcu_read_lock(); xa_for_each_start(&disk->part_tbl, idx, part, 1) { - if (part->bd_partno != skip_partno && + if (bdev_partno(part) != skip_partno && start < part->bd_start_sect + bdev_nr_sectors(part) && start + length > part->bd_start_sect) { overlap = true; diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index c3e8f7cf96be..32549d675955 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -720,6 +720,11 @@ void invalidate_disk(struct gendisk *disk); void set_disk_ro(struct gendisk *disk, bool read_only); void disk_uevent(struct gendisk *disk, enum kobject_action action); +static inline u8 bdev_partno(const struct block_device *bdev) +{ + return bdev->bd_partno; +} + static inline int get_disk_ro(struct gendisk *disk) { return disk->part0->bd_read_only || @@ -1095,7 +1100,7 @@ static inline int sb_issue_zeroout(struct super_block *sb, sector_t block, static inline bool bdev_is_partition(struct block_device *bdev) { - return bdev->bd_partno; + return bdev_partno(bdev) != 0; } enum blk_default_limits { diff --git a/lib/vsprintf.c b/lib/vsprintf.c index 3f9f1b959ef0..cdd4e2314bfc 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -972,7 +972,7 @@ char *bdev_name(char *buf, char *end, struct block_device *bdev, *buf = 'p'; buf++; } - buf = number(buf, end, bdev->bd_partno, spec); + buf = number(buf, end, bdev_partno(bdev), spec); } return buf; } -- cgit v1.2.3-59-g8ed1b From b478e162f227d17d6a29f40ffd464af358334971 Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Fri, 22 Mar 2024 14:39:51 +0200 Subject: PCI/ASPM: Consolidate link state defines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The linux/pci.h and aspm.c files define their own sets of link state related defines which are almost the same. Consolidate the use of defines into those defined by linux/pci.h and expand PCIE_LINK_STATE_L0S to match earlier ASPM_STATE_L0S that includes both upstream and downstream bits. Rename also the defines that are internal to aspm.c to start with PCIE_LINK_STATE for consistency. While the PCIE_LINK_STATE_L0S BIT(0) -> (BIT(0) | BIT(1)) transformation is not 1:1, in practice aspm.c already used ASPM_STATE_L0S that has both bits enabled except during mapping. While at it, place the PCIE_LINK_STATE_CLKPM define last to have more logical grouping. Use static_assert() to ensure PCIE_LINK_STATE_L0S is strictly equal to the combination of PCIE_LINK_STATE_L0S_UP/DW. Link: https://lore.kernel.org/r/20240322123952.6384-2-ilpo.jarvinen@linux.intel.com Signed-off-by: Ilpo Järvinen Signed-off-by: Bjorn Helgaas --- drivers/pci/pcie/aspm.c | 155 ++++++++++++++++++++++++------------------------ include/linux/pci.h | 24 ++++---- 2 files changed, 91 insertions(+), 88 deletions(-) diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index 2428d278e015..994b283b6a0f 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -8,6 +8,8 @@ */ #include +#include +#include #include #include #include @@ -189,21 +191,18 @@ void pci_restore_aspm_l1ss_state(struct pci_dev *pdev) #endif #define MODULE_PARAM_PREFIX "pcie_aspm." -/* Note: those are not register definitions */ -#define ASPM_STATE_L0S_UP (1) /* Upstream direction L0s state */ -#define ASPM_STATE_L0S_DW (2) /* Downstream direction L0s state */ -#define ASPM_STATE_L1 (4) /* L1 state */ -#define ASPM_STATE_L1_1 (8) /* ASPM L1.1 state */ -#define ASPM_STATE_L1_2 (0x10) /* ASPM L1.2 state */ -#define ASPM_STATE_L1_1_PCIPM (0x20) /* PCI PM L1.1 state */ -#define ASPM_STATE_L1_2_PCIPM (0x40) /* PCI PM L1.2 state */ -#define ASPM_STATE_L1_SS_PCIPM (ASPM_STATE_L1_1_PCIPM | ASPM_STATE_L1_2_PCIPM) -#define ASPM_STATE_L1_2_MASK (ASPM_STATE_L1_2 | ASPM_STATE_L1_2_PCIPM) -#define ASPM_STATE_L1SS (ASPM_STATE_L1_1 | ASPM_STATE_L1_1_PCIPM |\ - ASPM_STATE_L1_2_MASK) -#define ASPM_STATE_L0S (ASPM_STATE_L0S_UP | ASPM_STATE_L0S_DW) -#define ASPM_STATE_ALL (ASPM_STATE_L0S | ASPM_STATE_L1 | \ - ASPM_STATE_L1SS) +/* Note: these are not register definitions */ +#define PCIE_LINK_STATE_L0S_UP BIT(0) /* Upstream direction L0s state */ +#define PCIE_LINK_STATE_L0S_DW BIT(1) /* Downstream direction L0s state */ +static_assert(PCIE_LINK_STATE_L0S == (PCIE_LINK_STATE_L0S_UP | PCIE_LINK_STATE_L0S_DW)); + +#define PCIE_LINK_STATE_L1_SS_PCIPM (PCIE_LINK_STATE_L1_1_PCIPM |\ + PCIE_LINK_STATE_L1_2_PCIPM) +#define PCIE_LINK_STATE_L1_2_MASK (PCIE_LINK_STATE_L1_2 |\ + PCIE_LINK_STATE_L1_2_PCIPM) +#define PCIE_LINK_STATE_L1SS (PCIE_LINK_STATE_L1_1 |\ + PCIE_LINK_STATE_L1_1_PCIPM |\ + PCIE_LINK_STATE_L1_2_MASK) struct pcie_link_state { struct pci_dev *pdev; /* Upstream component of the Link */ @@ -275,10 +274,10 @@ static int policy_to_aspm_state(struct pcie_link_state *link) return 0; case POLICY_POWERSAVE: /* Enable ASPM L0s/L1 */ - return (ASPM_STATE_L0S | ASPM_STATE_L1); + return PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1; case POLICY_POWER_SUPERSAVE: /* Enable Everything */ - return ASPM_STATE_ALL; + return PCIE_LINK_STATE_ASPM_ALL; case POLICY_DEFAULT: return link->aspm_default; } @@ -581,14 +580,14 @@ static void pcie_aspm_check_latency(struct pci_dev *endpoint) latency_dw_l1 = calc_l1_latency(lnkcap_dw); /* Check upstream direction L0s latency */ - if ((link->aspm_capable & ASPM_STATE_L0S_UP) && + if ((link->aspm_capable & PCIE_LINK_STATE_L0S_UP) && (latency_up_l0s > acceptable_l0s)) - link->aspm_capable &= ~ASPM_STATE_L0S_UP; + link->aspm_capable &= ~PCIE_LINK_STATE_L0S_UP; /* Check downstream direction L0s latency */ - if ((link->aspm_capable & ASPM_STATE_L0S_DW) && + if ((link->aspm_capable & PCIE_LINK_STATE_L0S_DW) && (latency_dw_l0s > acceptable_l0s)) - link->aspm_capable &= ~ASPM_STATE_L0S_DW; + link->aspm_capable &= ~PCIE_LINK_STATE_L0S_DW; /* * Check L1 latency. * Every switch on the path to root complex need 1 @@ -603,9 +602,9 @@ static void pcie_aspm_check_latency(struct pci_dev *endpoint) * substate latencies (and hence do not do any check). */ latency = max_t(u32, latency_up_l1, latency_dw_l1); - if ((link->aspm_capable & ASPM_STATE_L1) && + if ((link->aspm_capable & PCIE_LINK_STATE_L1) && (latency + l1_switch_latency > acceptable_l1)) - link->aspm_capable &= ~ASPM_STATE_L1; + link->aspm_capable &= ~PCIE_LINK_STATE_L1; l1_switch_latency += NSEC_PER_USEC; link = link->parent; @@ -741,13 +740,13 @@ static void aspm_l1ss_init(struct pcie_link_state *link) child_l1ss_cap &= ~PCI_L1SS_CAP_ASPM_L1_2; if (parent_l1ss_cap & child_l1ss_cap & PCI_L1SS_CAP_ASPM_L1_1) - link->aspm_support |= ASPM_STATE_L1_1; + link->aspm_support |= PCIE_LINK_STATE_L1_1; if (parent_l1ss_cap & child_l1ss_cap & PCI_L1SS_CAP_ASPM_L1_2) - link->aspm_support |= ASPM_STATE_L1_2; + link->aspm_support |= PCIE_LINK_STATE_L1_2; if (parent_l1ss_cap & child_l1ss_cap & PCI_L1SS_CAP_PCIPM_L1_1) - link->aspm_support |= ASPM_STATE_L1_1_PCIPM; + link->aspm_support |= PCIE_LINK_STATE_L1_1_PCIPM; if (parent_l1ss_cap & child_l1ss_cap & PCI_L1SS_CAP_PCIPM_L1_2) - link->aspm_support |= ASPM_STATE_L1_2_PCIPM; + link->aspm_support |= PCIE_LINK_STATE_L1_2_PCIPM; if (parent_l1ss_cap) pci_read_config_dword(parent, parent->l1ss + PCI_L1SS_CTL1, @@ -757,15 +756,15 @@ static void aspm_l1ss_init(struct pcie_link_state *link) &child_l1ss_ctl1); if (parent_l1ss_ctl1 & child_l1ss_ctl1 & PCI_L1SS_CTL1_ASPM_L1_1) - link->aspm_enabled |= ASPM_STATE_L1_1; + link->aspm_enabled |= PCIE_LINK_STATE_L1_1; if (parent_l1ss_ctl1 & child_l1ss_ctl1 & PCI_L1SS_CTL1_ASPM_L1_2) - link->aspm_enabled |= ASPM_STATE_L1_2; + link->aspm_enabled |= PCIE_LINK_STATE_L1_2; if (parent_l1ss_ctl1 & child_l1ss_ctl1 & PCI_L1SS_CTL1_PCIPM_L1_1) - link->aspm_enabled |= ASPM_STATE_L1_1_PCIPM; + link->aspm_enabled |= PCIE_LINK_STATE_L1_1_PCIPM; if (parent_l1ss_ctl1 & child_l1ss_ctl1 & PCI_L1SS_CTL1_PCIPM_L1_2) - link->aspm_enabled |= ASPM_STATE_L1_2_PCIPM; + link->aspm_enabled |= PCIE_LINK_STATE_L1_2_PCIPM; - if (link->aspm_support & ASPM_STATE_L1_2_MASK) + if (link->aspm_support & PCIE_LINK_STATE_L1_2_MASK) aspm_calc_l12_info(link, parent_l1ss_cap, child_l1ss_cap); } @@ -778,8 +777,8 @@ static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist) if (blacklist) { /* Set enabled/disable so that we will disable ASPM later */ - link->aspm_enabled = ASPM_STATE_ALL; - link->aspm_disable = ASPM_STATE_ALL; + link->aspm_enabled = PCIE_LINK_STATE_ASPM_ALL; + link->aspm_disable = PCIE_LINK_STATE_ASPM_ALL; return; } @@ -814,19 +813,19 @@ static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist) * support L0s. */ if (parent_lnkcap & child_lnkcap & PCI_EXP_LNKCAP_ASPM_L0S) - link->aspm_support |= ASPM_STATE_L0S; + link->aspm_support |= PCIE_LINK_STATE_L0S; if (child_lnkctl & PCI_EXP_LNKCTL_ASPM_L0S) - link->aspm_enabled |= ASPM_STATE_L0S_UP; + link->aspm_enabled |= PCIE_LINK_STATE_L0S_UP; if (parent_lnkctl & PCI_EXP_LNKCTL_ASPM_L0S) - link->aspm_enabled |= ASPM_STATE_L0S_DW; + link->aspm_enabled |= PCIE_LINK_STATE_L0S_DW; /* Setup L1 state */ if (parent_lnkcap & child_lnkcap & PCI_EXP_LNKCAP_ASPM_L1) - link->aspm_support |= ASPM_STATE_L1; + link->aspm_support |= PCIE_LINK_STATE_L1; if (parent_lnkctl & child_lnkctl & PCI_EXP_LNKCTL_ASPM_L1) - link->aspm_enabled |= ASPM_STATE_L1; + link->aspm_enabled |= PCIE_LINK_STATE_L1; aspm_l1ss_init(link); @@ -876,7 +875,7 @@ static void pcie_config_aspm_l1ss(struct pcie_link_state *link, u32 state) * If needed, disable L1, and it gets enabled later * in pcie_config_aspm_link(). */ - if (enable_req & (ASPM_STATE_L1_1 | ASPM_STATE_L1_2)) { + if (enable_req & (PCIE_LINK_STATE_L1_1 | PCIE_LINK_STATE_L1_2)) { pcie_capability_clear_word(child, PCI_EXP_LNKCTL, PCI_EXP_LNKCTL_ASPM_L1); pcie_capability_clear_word(parent, PCI_EXP_LNKCTL, @@ -884,13 +883,13 @@ static void pcie_config_aspm_l1ss(struct pcie_link_state *link, u32 state) } val = 0; - if (state & ASPM_STATE_L1_1) + if (state & PCIE_LINK_STATE_L1_1) val |= PCI_L1SS_CTL1_ASPM_L1_1; - if (state & ASPM_STATE_L1_2) + if (state & PCIE_LINK_STATE_L1_2) val |= PCI_L1SS_CTL1_ASPM_L1_2; - if (state & ASPM_STATE_L1_1_PCIPM) + if (state & PCIE_LINK_STATE_L1_1_PCIPM) val |= PCI_L1SS_CTL1_PCIPM_L1_1; - if (state & ASPM_STATE_L1_2_PCIPM) + if (state & PCIE_LINK_STATE_L1_2_PCIPM) val |= PCI_L1SS_CTL1_PCIPM_L1_2; /* Enable what we need to enable */ @@ -916,29 +915,29 @@ static void pcie_config_aspm_link(struct pcie_link_state *link, u32 state) state &= (link->aspm_capable & ~link->aspm_disable); /* Can't enable any substates if L1 is not enabled */ - if (!(state & ASPM_STATE_L1)) - state &= ~ASPM_STATE_L1SS; + if (!(state & PCIE_LINK_STATE_L1)) + state &= ~PCIE_LINK_STATE_L1SS; /* Spec says both ports must be in D0 before enabling PCI PM substates*/ if (parent->current_state != PCI_D0 || child->current_state != PCI_D0) { - state &= ~ASPM_STATE_L1_SS_PCIPM; - state |= (link->aspm_enabled & ASPM_STATE_L1_SS_PCIPM); + state &= ~PCIE_LINK_STATE_L1_SS_PCIPM; + state |= (link->aspm_enabled & PCIE_LINK_STATE_L1_SS_PCIPM); } /* Nothing to do if the link is already in the requested state */ if (link->aspm_enabled == state) return; /* Convert ASPM state to upstream/downstream ASPM register state */ - if (state & ASPM_STATE_L0S_UP) + if (state & PCIE_LINK_STATE_L0S_UP) dwstream |= PCI_EXP_LNKCTL_ASPM_L0S; - if (state & ASPM_STATE_L0S_DW) + if (state & PCIE_LINK_STATE_L0S_DW) upstream |= PCI_EXP_LNKCTL_ASPM_L0S; - if (state & ASPM_STATE_L1) { + if (state & PCIE_LINK_STATE_L1) { upstream |= PCI_EXP_LNKCTL_ASPM_L1; dwstream |= PCI_EXP_LNKCTL_ASPM_L1; } - if (link->aspm_capable & ASPM_STATE_L1SS) + if (link->aspm_capable & PCIE_LINK_STATE_L1SS) pcie_config_aspm_l1ss(link, state); /* @@ -947,11 +946,11 @@ static void pcie_config_aspm_link(struct pcie_link_state *link, u32 state) * upstream component first and then downstream, and vice * versa for disabling ASPM L1. Spec doesn't mention L0S. */ - if (state & ASPM_STATE_L1) + if (state & PCIE_LINK_STATE_L1) pcie_config_aspm_dev(parent, upstream); list_for_each_entry(child, &linkbus->devices, bus_list) pcie_config_aspm_dev(child, dwstream); - if (!(state & ASPM_STATE_L1)) + if (!(state & PCIE_LINK_STATE_L1)) pcie_config_aspm_dev(parent, upstream); link->aspm_enabled = state; @@ -1347,18 +1346,18 @@ static int __pci_disable_link_state(struct pci_dev *pdev, int state, bool locked down_read(&pci_bus_sem); mutex_lock(&aspm_lock); if (state & PCIE_LINK_STATE_L0S) - link->aspm_disable |= ASPM_STATE_L0S; + link->aspm_disable |= PCIE_LINK_STATE_L0S; if (state & PCIE_LINK_STATE_L1) /* L1 PM substates require L1 */ - link->aspm_disable |= ASPM_STATE_L1 | ASPM_STATE_L1SS; + link->aspm_disable |= PCIE_LINK_STATE_L1 | PCIE_LINK_STATE_L1SS; if (state & PCIE_LINK_STATE_L1_1) - link->aspm_disable |= ASPM_STATE_L1_1; + link->aspm_disable |= PCIE_LINK_STATE_L1_1; if (state & PCIE_LINK_STATE_L1_2) - link->aspm_disable |= ASPM_STATE_L1_2; + link->aspm_disable |= PCIE_LINK_STATE_L1_2; if (state & PCIE_LINK_STATE_L1_1_PCIPM) - link->aspm_disable |= ASPM_STATE_L1_1_PCIPM; + link->aspm_disable |= PCIE_LINK_STATE_L1_1_PCIPM; if (state & PCIE_LINK_STATE_L1_2_PCIPM) - link->aspm_disable |= ASPM_STATE_L1_2_PCIPM; + link->aspm_disable |= PCIE_LINK_STATE_L1_2_PCIPM; pcie_config_aspm_link(link, policy_to_aspm_state(link)); if (state & PCIE_LINK_STATE_CLKPM) @@ -1416,18 +1415,18 @@ static int __pci_enable_link_state(struct pci_dev *pdev, int state, bool locked) mutex_lock(&aspm_lock); link->aspm_default = 0; if (state & PCIE_LINK_STATE_L0S) - link->aspm_default |= ASPM_STATE_L0S; + link->aspm_default |= PCIE_LINK_STATE_L0S; if (state & PCIE_LINK_STATE_L1) - link->aspm_default |= ASPM_STATE_L1; + link->aspm_default |= PCIE_LINK_STATE_L1; /* L1 PM substates require L1 */ if (state & PCIE_LINK_STATE_L1_1) - link->aspm_default |= ASPM_STATE_L1_1 | ASPM_STATE_L1; + link->aspm_default |= PCIE_LINK_STATE_L1_1 | PCIE_LINK_STATE_L1; if (state & PCIE_LINK_STATE_L1_2) - link->aspm_default |= ASPM_STATE_L1_2 | ASPM_STATE_L1; + link->aspm_default |= PCIE_LINK_STATE_L1_2 | PCIE_LINK_STATE_L1; if (state & PCIE_LINK_STATE_L1_1_PCIPM) - link->aspm_default |= ASPM_STATE_L1_1_PCIPM | ASPM_STATE_L1; + link->aspm_default |= PCIE_LINK_STATE_L1_1_PCIPM | PCIE_LINK_STATE_L1; if (state & PCIE_LINK_STATE_L1_2_PCIPM) - link->aspm_default |= ASPM_STATE_L1_2_PCIPM | ASPM_STATE_L1; + link->aspm_default |= PCIE_LINK_STATE_L1_2_PCIPM | PCIE_LINK_STATE_L1; pcie_config_aspm_link(link, policy_to_aspm_state(link)); link->clkpm_default = (state & PCIE_LINK_STATE_CLKPM) ? 1 : 0; @@ -1563,12 +1562,12 @@ static ssize_t aspm_attr_store_common(struct device *dev, if (state_enable) { link->aspm_disable &= ~state; /* need to enable L1 for substates */ - if (state & ASPM_STATE_L1SS) - link->aspm_disable &= ~ASPM_STATE_L1; + if (state & PCIE_LINK_STATE_L1SS) + link->aspm_disable &= ~PCIE_LINK_STATE_L1; } else { link->aspm_disable |= state; - if (state & ASPM_STATE_L1) - link->aspm_disable |= ASPM_STATE_L1SS; + if (state & PCIE_LINK_STATE_L1) + link->aspm_disable |= PCIE_LINK_STATE_L1SS; } pcie_config_aspm_link(link, policy_to_aspm_state(link)); @@ -1582,12 +1581,12 @@ static ssize_t aspm_attr_store_common(struct device *dev, #define ASPM_ATTR(_f, _s) \ static ssize_t _f##_show(struct device *dev, \ struct device_attribute *attr, char *buf) \ -{ return aspm_attr_show_common(dev, attr, buf, ASPM_STATE_##_s); } \ +{ return aspm_attr_show_common(dev, attr, buf, PCIE_LINK_STATE_##_s); } \ \ static ssize_t _f##_store(struct device *dev, \ struct device_attribute *attr, \ const char *buf, size_t len) \ -{ return aspm_attr_store_common(dev, attr, buf, len, ASPM_STATE_##_s); } +{ return aspm_attr_store_common(dev, attr, buf, len, PCIE_LINK_STATE_##_s); } ASPM_ATTR(l0s_aspm, L0S) ASPM_ATTR(l1_aspm, L1) @@ -1654,12 +1653,12 @@ static umode_t aspm_ctrl_attrs_are_visible(struct kobject *kobj, struct pci_dev *pdev = to_pci_dev(dev); struct pcie_link_state *link = pcie_aspm_get_link(pdev); static const u8 aspm_state_map[] = { - ASPM_STATE_L0S, - ASPM_STATE_L1, - ASPM_STATE_L1_1, - ASPM_STATE_L1_2, - ASPM_STATE_L1_1_PCIPM, - ASPM_STATE_L1_2_PCIPM, + PCIE_LINK_STATE_L0S, + PCIE_LINK_STATE_L1, + PCIE_LINK_STATE_L1_1, + PCIE_LINK_STATE_L1_2, + PCIE_LINK_STATE_L1_1_PCIPM, + PCIE_LINK_STATE_L1_2_PCIPM, }; if (aspm_disabled || !link) diff --git a/include/linux/pci.h b/include/linux/pci.h index 16493426a04f..08c68d80c01a 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -1821,17 +1821,21 @@ extern bool pcie_ports_native; #define pcie_ports_native false #endif -#define PCIE_LINK_STATE_L0S BIT(0) -#define PCIE_LINK_STATE_L1 BIT(1) -#define PCIE_LINK_STATE_CLKPM BIT(2) -#define PCIE_LINK_STATE_L1_1 BIT(3) -#define PCIE_LINK_STATE_L1_2 BIT(4) -#define PCIE_LINK_STATE_L1_1_PCIPM BIT(5) -#define PCIE_LINK_STATE_L1_2_PCIPM BIT(6) -#define PCIE_LINK_STATE_ALL (PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1 |\ - PCIE_LINK_STATE_CLKPM | PCIE_LINK_STATE_L1_1 |\ - PCIE_LINK_STATE_L1_2 | PCIE_LINK_STATE_L1_1_PCIPM |\ +#define PCIE_LINK_STATE_L0S (BIT(0) | BIT(1)) /* Upstr/dwnstr L0s */ +#define PCIE_LINK_STATE_L1 BIT(2) /* L1 state */ +#define PCIE_LINK_STATE_L1_1 BIT(3) /* ASPM L1.1 state */ +#define PCIE_LINK_STATE_L1_2 BIT(4) /* ASPM L1.2 state */ +#define PCIE_LINK_STATE_L1_1_PCIPM BIT(5) /* PCI-PM L1.1 state */ +#define PCIE_LINK_STATE_L1_2_PCIPM BIT(6) /* PCI-PM L1.2 state */ +#define PCIE_LINK_STATE_ASPM_ALL (PCIE_LINK_STATE_L0S |\ + PCIE_LINK_STATE_L1 |\ + PCIE_LINK_STATE_L1_1 |\ + PCIE_LINK_STATE_L1_2 |\ + PCIE_LINK_STATE_L1_1_PCIPM |\ PCIE_LINK_STATE_L1_2_PCIPM) +#define PCIE_LINK_STATE_CLKPM BIT(7) +#define PCIE_LINK_STATE_ALL (PCIE_LINK_STATE_ASPM_ALL |\ + PCIE_LINK_STATE_CLKPM) #ifdef CONFIG_PCIEASPM int pci_disable_link_state(struct pci_dev *pdev, int state); -- cgit v1.2.3-59-g8ed1b From dc69062a1a73f0fe33a83401e8a3b1d5d54b43af Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Fri, 22 Mar 2024 14:39:52 +0200 Subject: PCI/ASPM: Clean up ASPM disable/enable mask calculation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With only one set of defines remaining, state can be almost used as-is to set ->aspm_disable/default. Only CLKPM and L1 PM substates need special handling. Remove unnecessary if conditions that can use the state variable bits directly. Move ASPM mask calculation into pci_calc_aspm_enable_mask() and pci_calc_aspm_disable_mask() helpers which makes it easier to alter state variable directly. Link: https://lore.kernel.org/r/20240322123952.6384-3-ilpo.jarvinen@linux.intel.com Signed-off-by: Ilpo Järvinen Signed-off-by: Bjorn Helgaas --- drivers/pci/pcie/aspm.c | 51 +++++++++++++++++++++++-------------------------- 1 file changed, 24 insertions(+), 27 deletions(-) diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index 994b283b6a0f..9cbdebb933ee 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -1323,6 +1323,28 @@ static struct pcie_link_state *pcie_aspm_get_link(struct pci_dev *pdev) return bridge->link_state; } +static u8 pci_calc_aspm_disable_mask(int state) +{ + state &= ~PCIE_LINK_STATE_CLKPM; + + /* L1 PM substates require L1 */ + if (state & PCIE_LINK_STATE_L1) + state |= PCIE_LINK_STATE_L1SS; + + return state; +} + +static u8 pci_calc_aspm_enable_mask(int state) +{ + state &= ~PCIE_LINK_STATE_CLKPM; + + /* L1 PM substates require L1 */ + if (state & PCIE_LINK_STATE_L1SS) + state |= PCIE_LINK_STATE_L1; + + return state; +} + static int __pci_disable_link_state(struct pci_dev *pdev, int state, bool locked) { struct pcie_link_state *link = pcie_aspm_get_link(pdev); @@ -1345,19 +1367,7 @@ static int __pci_disable_link_state(struct pci_dev *pdev, int state, bool locked if (!locked) down_read(&pci_bus_sem); mutex_lock(&aspm_lock); - if (state & PCIE_LINK_STATE_L0S) - link->aspm_disable |= PCIE_LINK_STATE_L0S; - if (state & PCIE_LINK_STATE_L1) - /* L1 PM substates require L1 */ - link->aspm_disable |= PCIE_LINK_STATE_L1 | PCIE_LINK_STATE_L1SS; - if (state & PCIE_LINK_STATE_L1_1) - link->aspm_disable |= PCIE_LINK_STATE_L1_1; - if (state & PCIE_LINK_STATE_L1_2) - link->aspm_disable |= PCIE_LINK_STATE_L1_2; - if (state & PCIE_LINK_STATE_L1_1_PCIPM) - link->aspm_disable |= PCIE_LINK_STATE_L1_1_PCIPM; - if (state & PCIE_LINK_STATE_L1_2_PCIPM) - link->aspm_disable |= PCIE_LINK_STATE_L1_2_PCIPM; + link->aspm_disable |= pci_calc_aspm_disable_mask(state); pcie_config_aspm_link(link, policy_to_aspm_state(link)); if (state & PCIE_LINK_STATE_CLKPM) @@ -1413,20 +1423,7 @@ static int __pci_enable_link_state(struct pci_dev *pdev, int state, bool locked) if (!locked) down_read(&pci_bus_sem); mutex_lock(&aspm_lock); - link->aspm_default = 0; - if (state & PCIE_LINK_STATE_L0S) - link->aspm_default |= PCIE_LINK_STATE_L0S; - if (state & PCIE_LINK_STATE_L1) - link->aspm_default |= PCIE_LINK_STATE_L1; - /* L1 PM substates require L1 */ - if (state & PCIE_LINK_STATE_L1_1) - link->aspm_default |= PCIE_LINK_STATE_L1_1 | PCIE_LINK_STATE_L1; - if (state & PCIE_LINK_STATE_L1_2) - link->aspm_default |= PCIE_LINK_STATE_L1_2 | PCIE_LINK_STATE_L1; - if (state & PCIE_LINK_STATE_L1_1_PCIPM) - link->aspm_default |= PCIE_LINK_STATE_L1_1_PCIPM | PCIE_LINK_STATE_L1; - if (state & PCIE_LINK_STATE_L1_2_PCIPM) - link->aspm_default |= PCIE_LINK_STATE_L1_2_PCIPM | PCIE_LINK_STATE_L1; + link->aspm_default = pci_calc_aspm_enable_mask(state); pcie_config_aspm_link(link, policy_to_aspm_state(link)); link->clkpm_default = (state & PCIE_LINK_STATE_CLKPM) ? 1 : 0; -- cgit v1.2.3-59-g8ed1b From e6f7d27df5d208b50cae817a91d128fb434bb12c Mon Sep 17 00:00:00 2001 From: Duoming Zhou Date: Sun, 3 Mar 2024 18:57:29 +0800 Subject: PCI: of_property: Return error for int_map allocation failure Return -ENOMEM from of_pci_prop_intr_map() if kcalloc() fails to prevent a NULL pointer dereference in this case. Fixes: 407d1a51921e ("PCI: Create device tree node for bridge") Link: https://lore.kernel.org/r/20240303105729.78624-1-duoming@zju.edu.cn Signed-off-by: Duoming Zhou [bhelgaas: commit log] Signed-off-by: Bjorn Helgaas --- drivers/pci/of_property.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/pci/of_property.c b/drivers/pci/of_property.c index c2c7334152bc..03539e505372 100644 --- a/drivers/pci/of_property.c +++ b/drivers/pci/of_property.c @@ -238,6 +238,8 @@ static int of_pci_prop_intr_map(struct pci_dev *pdev, struct of_changeset *ocs, return 0; int_map = kcalloc(map_sz, sizeof(u32), GFP_KERNEL); + if (!int_map) + return -ENOMEM; mapp = int_map; list_for_each_entry(child, &pdev->subordinate->devices, bus_list) { -- cgit v1.2.3-59-g8ed1b From 1116b9fa15c09748ae05d2365a305fa22671eb1e Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 12 Apr 2024 01:07:29 -0400 Subject: bdev: infrastructure for flags Replace bd_partno with a 32bit field (__bd_flags). The lower 8 bits contain the partition number, the upper 24 are for flags. Helpers: bdev_{test,set,clear}_flag(bdev, flag), with atomic_or() and atomic_andnot() used to set/clear. NOTE: this commit does not actually move any flags over there - they are still bool fields. As the result, it shifts the fields wrt cacheline boundaries; that's going to be restored once the first 3 flags are dealt with. Signed-off-by: Al Viro --- block/bdev.c | 2 +- include/linux/blk_types.h | 3 ++- include/linux/blkdev.h | 17 ++++++++++++++++- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/block/bdev.c b/block/bdev.c index 7a5f611c3d2e..2ec223315500 100644 --- a/block/bdev.c +++ b/block/bdev.c @@ -411,7 +411,7 @@ struct block_device *bdev_alloc(struct gendisk *disk, u8 partno) mutex_init(&bdev->bd_fsfreeze_mutex); spin_lock_init(&bdev->bd_size_lock); mutex_init(&bdev->bd_holder_lock); - bdev->bd_partno = partno; + atomic_set(&bdev->__bd_flags, partno); bdev->bd_inode = inode; bdev->bd_queue = disk->queue; if (partno) diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h index cb1526ec44b5..04f92737ab08 100644 --- a/include/linux/blk_types.h +++ b/include/linux/blk_types.h @@ -45,8 +45,9 @@ struct block_device { struct request_queue * bd_queue; struct disk_stats __percpu *bd_stats; unsigned long bd_stamp; + atomic_t __bd_flags; // partition number + flags +#define BD_PARTNO 255 // lower 8 bits; assign-once bool bd_read_only; /* read-only policy */ - u8 bd_partno; bool bd_write_holder; bool bd_has_submit_bio; dev_t bd_dev; diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 32549d675955..99917e5860fd 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -722,7 +722,22 @@ void disk_uevent(struct gendisk *disk, enum kobject_action action); static inline u8 bdev_partno(const struct block_device *bdev) { - return bdev->bd_partno; + return atomic_read(&bdev->__bd_flags) & BD_PARTNO; +} + +static inline bool bdev_test_flag(const struct block_device *bdev, unsigned flag) +{ + return atomic_read(&bdev->__bd_flags) & flag; +} + +static inline void bdev_set_flag(struct block_device *bdev, unsigned flag) +{ + atomic_or(flag, &bdev->__bd_flags); +} + +static inline void bdev_clear_flag(struct block_device *bdev, unsigned flag) +{ + atomic_andnot(flag, &bdev->__bd_flags); } static inline int get_disk_ro(struct gendisk *disk) -- cgit v1.2.3-59-g8ed1b From 01e198f01d55880b79d8f5ac73064ff30a89d98a Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 12 Apr 2024 01:15:55 -0400 Subject: bdev: move ->bd_read_only to ->__bd_flags Signed-off-by: Al Viro --- block/ioctl.c | 5 ++++- include/linux/blk_types.h | 2 +- include/linux/blkdev.h | 4 ++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/block/ioctl.c b/block/ioctl.c index 0c76137adcaa..be173e4ff43d 100644 --- a/block/ioctl.c +++ b/block/ioctl.c @@ -402,7 +402,10 @@ static int blkdev_roset(struct block_device *bdev, unsigned cmd, if (ret) return ret; } - bdev->bd_read_only = n; + if (n) + bdev_set_flag(bdev, BD_READ_ONLY); + else + bdev_clear_flag(bdev, BD_READ_ONLY); return 0; } diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h index 04f92737ab08..f70dd31cbcd1 100644 --- a/include/linux/blk_types.h +++ b/include/linux/blk_types.h @@ -47,7 +47,7 @@ struct block_device { unsigned long bd_stamp; atomic_t __bd_flags; // partition number + flags #define BD_PARTNO 255 // lower 8 bits; assign-once - bool bd_read_only; /* read-only policy */ +#define BD_READ_ONLY (1u<<8) // read-only policy bool bd_write_holder; bool bd_has_submit_bio; dev_t bd_dev; diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 99917e5860fd..1fe91231f85b 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -742,13 +742,13 @@ static inline void bdev_clear_flag(struct block_device *bdev, unsigned flag) static inline int get_disk_ro(struct gendisk *disk) { - return disk->part0->bd_read_only || + return bdev_test_flag(disk->part0, BD_READ_ONLY) || test_bit(GD_READ_ONLY, &disk->state); } static inline int bdev_read_only(struct block_device *bdev) { - return bdev->bd_read_only || get_disk_ro(bdev->bd_disk); + return bdev_test_flag(bdev, BD_READ_ONLY) || get_disk_ro(bdev->bd_disk); } bool set_capacity_and_notify(struct gendisk *disk, sector_t size); -- cgit v1.2.3-59-g8ed1b From 4c80105e3909b3aff634a40daa9c29059ce03d6a Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 12 Apr 2024 01:18:24 -0400 Subject: bdev: move ->bd_write_holder into ->__bd_flags Signed-off-by: Al Viro --- block/bdev.c | 9 +++++---- include/linux/blk_types.h | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/block/bdev.c b/block/bdev.c index 2ec223315500..9df9a59f0900 100644 --- a/block/bdev.c +++ b/block/bdev.c @@ -624,7 +624,7 @@ static void bd_end_claim(struct block_device *bdev, void *holder) bdev->bd_holder = NULL; bdev->bd_holder_ops = NULL; mutex_unlock(&bdev->bd_holder_lock); - if (bdev->bd_write_holder) + if (bdev_test_flag(bdev, BD_WRITE_HOLDER)) unblock = true; } if (!whole->bd_holders) @@ -640,7 +640,7 @@ static void bd_end_claim(struct block_device *bdev, void *holder) */ if (unblock) { disk_unblock_events(bdev->bd_disk); - bdev->bd_write_holder = false; + bdev_clear_flag(bdev, BD_WRITE_HOLDER); } } @@ -892,9 +892,10 @@ int bdev_open(struct block_device *bdev, blk_mode_t mode, void *holder, * writeable reference is too fragile given the way @mode is * used in blkdev_get/put(). */ - if ((mode & BLK_OPEN_WRITE) && !bdev->bd_write_holder && + if ((mode & BLK_OPEN_WRITE) && + !bdev_test_flag(bdev, BD_WRITE_HOLDER) && (disk->event_flags & DISK_EVENT_FLAG_BLOCK_ON_EXCL_WRITE)) { - bdev->bd_write_holder = true; + bdev_set_flag(bdev, BD_WRITE_HOLDER); unblock_events = false; } } diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h index f70dd31cbcd1..e45a490d488e 100644 --- a/include/linux/blk_types.h +++ b/include/linux/blk_types.h @@ -48,7 +48,7 @@ struct block_device { atomic_t __bd_flags; // partition number + flags #define BD_PARTNO 255 // lower 8 bits; assign-once #define BD_READ_ONLY (1u<<8) // read-only policy - bool bd_write_holder; +#define BD_WRITE_HOLDER (1u<<9) bool bd_has_submit_bio; dev_t bd_dev; struct inode *bd_inode; /* will die */ -- cgit v1.2.3-59-g8ed1b From ac2b6f9dee8f41d5e9162959a8bbd2c8047ee382 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 12 Apr 2024 01:21:45 -0400 Subject: bdev: move ->bd_has_subit_bio to ->__bd_flags In bdev_alloc() we have all flags initialized to false, so assignment to ->bh_has_submit_bio n there is a no-op unless we have partno != 0 and flag already set on entire device. In device_add_disk() we have just allocated the block_device in question and it had been a full-device one, so the flag is guaranteed to be still clear when we get to assignment. Signed-off-by: Al Viro --- block/bdev.c | 6 ++---- block/blk-core.c | 4 ++-- block/genhd.c | 3 ++- include/linux/blk_types.h | 2 +- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/block/bdev.c b/block/bdev.c index 9df9a59f0900..fae30eae7741 100644 --- a/block/bdev.c +++ b/block/bdev.c @@ -414,10 +414,8 @@ struct block_device *bdev_alloc(struct gendisk *disk, u8 partno) atomic_set(&bdev->__bd_flags, partno); bdev->bd_inode = inode; bdev->bd_queue = disk->queue; - if (partno) - bdev->bd_has_submit_bio = disk->part0->bd_has_submit_bio; - else - bdev->bd_has_submit_bio = false; + if (partno && bdev_test_flag(disk->part0, BD_HAS_SUBMIT_BIO)) + bdev_set_flag(bdev, BD_HAS_SUBMIT_BIO); bdev->bd_stats = alloc_percpu(struct disk_stats); if (!bdev->bd_stats) { iput(inode); diff --git a/block/blk-core.c b/block/blk-core.c index 20322abc6082..f61460b65408 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -615,7 +615,7 @@ static void __submit_bio(struct bio *bio) if (unlikely(!blk_crypto_bio_prep(&bio))) return; - if (!bio->bi_bdev->bd_has_submit_bio) { + if (!bdev_test_flag(bio->bi_bdev, BD_HAS_SUBMIT_BIO)) { blk_mq_submit_bio(bio); } else if (likely(bio_queue_enter(bio) == 0)) { struct gendisk *disk = bio->bi_bdev->bd_disk; @@ -723,7 +723,7 @@ void submit_bio_noacct_nocheck(struct bio *bio) */ if (current->bio_list) bio_list_add(¤t->bio_list[0], bio); - else if (!bio->bi_bdev->bd_has_submit_bio) + else if (!bdev_test_flag(bio->bi_bdev, BD_HAS_SUBMIT_BIO)) __submit_bio_noacct_mq(bio); else __submit_bio_noacct(bio); diff --git a/block/genhd.c b/block/genhd.c index bb29a68e1d67..19cd1a31fa80 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -413,7 +413,8 @@ int __must_check device_add_disk(struct device *parent, struct gendisk *disk, elevator_init_mq(disk->queue); /* Mark bdev as having a submit_bio, if needed */ - disk->part0->bd_has_submit_bio = disk->fops->submit_bio != NULL; + if (disk->fops->submit_bio) + bdev_set_flag(disk->part0, BD_HAS_SUBMIT_BIO); /* * If the driver provides an explicit major number it also must provide diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h index e45a490d488e..11b9e8eeb79f 100644 --- a/include/linux/blk_types.h +++ b/include/linux/blk_types.h @@ -49,7 +49,7 @@ struct block_device { #define BD_PARTNO 255 // lower 8 bits; assign-once #define BD_READ_ONLY (1u<<8) // read-only policy #define BD_WRITE_HOLDER (1u<<9) - bool bd_has_submit_bio; +#define BD_HAS_SUBMIT_BIO (1u<<10) dev_t bd_dev; struct inode *bd_inode; /* will die */ -- cgit v1.2.3-59-g8ed1b From 49a43dae93c8b0ee5c9797f7f407d1244dea8213 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 12 Apr 2024 01:24:27 -0400 Subject: bdev: move ->bd_ro_warned to ->__bd_flags Signed-off-by: Al Viro --- block/blk-core.c | 5 +++-- include/linux/blk_types.h | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/block/blk-core.c b/block/blk-core.c index f61460b65408..1be49be9fac4 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -514,10 +514,11 @@ static inline void bio_check_ro(struct bio *bio) if (op_is_flush(bio->bi_opf) && !bio_sectors(bio)) return; - if (bio->bi_bdev->bd_ro_warned) + if (bdev_test_flag(bio->bi_bdev, BD_RO_WARNED)) return; - bio->bi_bdev->bd_ro_warned = true; + bdev_set_flag(bio->bi_bdev, BD_RO_WARNED); + /* * Use ioctl to set underlying disk of raid/dm to read-only * will trigger this. diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h index 11b9e8eeb79f..4e0c8785090c 100644 --- a/include/linux/blk_types.h +++ b/include/linux/blk_types.h @@ -50,6 +50,7 @@ struct block_device { #define BD_READ_ONLY (1u<<8) // read-only policy #define BD_WRITE_HOLDER (1u<<9) #define BD_HAS_SUBMIT_BIO (1u<<10) +#define BD_RO_WARNED (1u<<11) dev_t bd_dev; struct inode *bd_inode; /* will die */ @@ -69,7 +70,6 @@ struct block_device { #ifdef CONFIG_FAIL_MAKE_REQUEST bool bd_make_it_fail; #endif - bool bd_ro_warned; int bd_writers; /* * keep this out-of-line as it's both big and not needed in the fast -- cgit v1.2.3-59-g8ed1b From 811ba89a8838e7c43ff46b6210ba1878bfe4437e Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 28 Apr 2024 00:15:07 -0400 Subject: bdev: move ->bd_make_it_fail to ->__bd_flags Signed-off-by: Al Viro --- block/blk-core.c | 3 ++- block/genhd.c | 12 ++++++++---- include/linux/blk_types.h | 6 +++--- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/block/blk-core.c b/block/blk-core.c index 1be49be9fac4..1076336dd620 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -494,7 +494,8 @@ __setup("fail_make_request=", setup_fail_make_request); bool should_fail_request(struct block_device *part, unsigned int bytes) { - return part->bd_make_it_fail && should_fail(&fail_make_request, bytes); + return bdev_test_flag(part, BD_MAKE_IT_FAIL) && + should_fail(&fail_make_request, bytes); } static int __init fail_make_request_debugfs(void) diff --git a/block/genhd.c b/block/genhd.c index 19cd1a31fa80..0cce461952f6 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -1066,7 +1066,8 @@ static DEVICE_ATTR(diskseq, 0444, diskseq_show, NULL); ssize_t part_fail_show(struct device *dev, struct device_attribute *attr, char *buf) { - return sprintf(buf, "%d\n", dev_to_bdev(dev)->bd_make_it_fail); + return sprintf(buf, "%d\n", + bdev_test_flag(dev_to_bdev(dev), BD_MAKE_IT_FAIL)); } ssize_t part_fail_store(struct device *dev, @@ -1075,9 +1076,12 @@ ssize_t part_fail_store(struct device *dev, { int i; - if (count > 0 && sscanf(buf, "%d", &i) > 0) - dev_to_bdev(dev)->bd_make_it_fail = i; - + if (count > 0 && sscanf(buf, "%d", &i) > 0) { + if (i) + bdev_set_flag(dev_to_bdev(dev), BD_MAKE_IT_FAIL); + else + bdev_clear_flag(dev_to_bdev(dev), BD_MAKE_IT_FAIL); + } return count; } diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h index 4e0c8785090c..5bb7805927ac 100644 --- a/include/linux/blk_types.h +++ b/include/linux/blk_types.h @@ -51,6 +51,9 @@ struct block_device { #define BD_WRITE_HOLDER (1u<<9) #define BD_HAS_SUBMIT_BIO (1u<<10) #define BD_RO_WARNED (1u<<11) +#ifdef CONFIG_FAIL_MAKE_REQUEST +#define BD_MAKE_IT_FAIL (1u<<12) +#endif dev_t bd_dev; struct inode *bd_inode; /* will die */ @@ -67,9 +70,6 @@ struct block_device { struct mutex bd_fsfreeze_mutex; /* serialize freeze/thaw */ struct partition_meta_info *bd_meta_info; -#ifdef CONFIG_FAIL_MAKE_REQUEST - bool bd_make_it_fail; -#endif int bd_writers; /* * keep this out-of-line as it's both big and not needed in the fast -- cgit v1.2.3-59-g8ed1b From 73df3d6f2e9533e93a5039a33c40dd7216b81801 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Wed, 24 Apr 2024 14:27:23 +0200 Subject: VMCI: Fix an error handling path in vmci_guest_probe_device() After a successful pci_iomap_range() call, pci_iounmap() should be called in the error handling path, as already done in the remove function. Add the missing call. The corresponding call was added in the remove function in commit 5ee109828e73 ("VMCI: dma dg: allocate send and receive buffers for DMA datagrams") Fixes: e283a0e8b7ea ("VMCI: dma dg: add MMIO access to registers") Signed-off-by: Christophe JAILLET Acked-by: Vishnu Dasa Link: https://lore.kernel.org/r/a35bbc3876ae1da70e49dafde4435750e1477be3.1713961553.git.christophe.jaillet@wanadoo.fr Signed-off-by: Greg Kroah-Hartman --- drivers/misc/vmw_vmci/vmci_guest.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/misc/vmw_vmci/vmci_guest.c b/drivers/misc/vmw_vmci/vmci_guest.c index 4f8d962bb5b2..1300ccab3d21 100644 --- a/drivers/misc/vmw_vmci/vmci_guest.c +++ b/drivers/misc/vmw_vmci/vmci_guest.c @@ -625,7 +625,8 @@ static int vmci_guest_probe_device(struct pci_dev *pdev, if (!vmci_dev) { dev_err(&pdev->dev, "Can't allocate memory for VMCI device\n"); - return -ENOMEM; + error = -ENOMEM; + goto err_unmap_mmio_base; } vmci_dev->dev = &pdev->dev; @@ -642,7 +643,8 @@ static int vmci_guest_probe_device(struct pci_dev *pdev, if (!vmci_dev->tx_buffer) { dev_err(&pdev->dev, "Can't allocate memory for datagram tx buffer\n"); - return -ENOMEM; + error = -ENOMEM; + goto err_unmap_mmio_base; } vmci_dev->data_buffer = dma_alloc_coherent(&pdev->dev, VMCI_DMA_DG_BUFFER_SIZE, @@ -893,6 +895,10 @@ err_free_notification_bitmap: err_free_data_buffers: vmci_free_dg_buffers(vmci_dev); +err_unmap_mmio_base: + if (mmio_base != NULL) + pci_iounmap(pdev, mmio_base); + /* The rest are managed resources and will be freed by PCI core */ return error; } -- cgit v1.2.3-59-g8ed1b From 6d0ca4a2a7e25f9ad07c1f335f20b4d9e048cdd5 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 30 Apr 2024 09:49:11 +0100 Subject: nvmem: layouts: store owner from modules with nvmem_layout_driver_register() Modules registering driver with nvmem_layout_driver_register() might forget to set .owner field. The field is used by some of other kernel parts for reference counting (try_module_get()), so it is expected that drivers will set it. Solve the problem by moving this task away from the drivers to the core code, just like we did for platform_driver in commit 9447057eaff8 ("platform_device: use a macro instead of platform_driver_register"). Signed-off-by: Krzysztof Kozlowski Reviewed-by: Michael Walle Reviewed-by: Miquel Raynal Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20240430084921.33387-2-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/layouts.c | 6 ++++-- include/linux/nvmem-provider.h | 5 ++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/nvmem/layouts.c b/drivers/nvmem/layouts.c index 8b5e2de138eb..64dc7013a098 100644 --- a/drivers/nvmem/layouts.c +++ b/drivers/nvmem/layouts.c @@ -52,13 +52,15 @@ static const struct bus_type nvmem_layout_bus_type = { .remove = nvmem_layout_bus_remove, }; -int nvmem_layout_driver_register(struct nvmem_layout_driver *drv) +int __nvmem_layout_driver_register(struct nvmem_layout_driver *drv, + struct module *owner) { drv->driver.bus = &nvmem_layout_bus_type; + drv->driver.owner = owner; return driver_register(&drv->driver); } -EXPORT_SYMBOL_GPL(nvmem_layout_driver_register); +EXPORT_SYMBOL_GPL(__nvmem_layout_driver_register); void nvmem_layout_driver_unregister(struct nvmem_layout_driver *drv) { diff --git a/include/linux/nvmem-provider.h b/include/linux/nvmem-provider.h index f0ba0e03218f..3ebeaa0ded00 100644 --- a/include/linux/nvmem-provider.h +++ b/include/linux/nvmem-provider.h @@ -199,7 +199,10 @@ int nvmem_add_one_cell(struct nvmem_device *nvmem, int nvmem_layout_register(struct nvmem_layout *layout); void nvmem_layout_unregister(struct nvmem_layout *layout); -int nvmem_layout_driver_register(struct nvmem_layout_driver *drv); +#define nvmem_layout_driver_register(drv) \ + __nvmem_layout_driver_register(drv, THIS_MODULE) +int __nvmem_layout_driver_register(struct nvmem_layout_driver *drv, + struct module *owner); void nvmem_layout_driver_unregister(struct nvmem_layout_driver *drv); #define module_nvmem_layout_driver(__nvmem_layout_driver) \ module_driver(__nvmem_layout_driver, nvmem_layout_driver_register, \ -- cgit v1.2.3-59-g8ed1b From 21833338eccb91194fec6ba7548d9c454824eca0 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 30 Apr 2024 09:49:12 +0100 Subject: nvmem: layouts: onie-tlv: drop driver owner initialization Core in nvmem_layout_driver_register() already sets the .owner, so driver does not need to. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Michael Walle Acked-by: Miquel Raynal Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20240430084921.33387-3-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/layouts/onie-tlv.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/nvmem/layouts/onie-tlv.c b/drivers/nvmem/layouts/onie-tlv.c index 9d2ad5f2dc10..0967a32319a2 100644 --- a/drivers/nvmem/layouts/onie-tlv.c +++ b/drivers/nvmem/layouts/onie-tlv.c @@ -247,7 +247,6 @@ MODULE_DEVICE_TABLE(of, onie_tlv_of_match_table); static struct nvmem_layout_driver onie_tlv_layout = { .driver = { - .owner = THIS_MODULE, .name = "onie-tlv-layout", .of_match_table = onie_tlv_of_match_table, }, -- cgit v1.2.3-59-g8ed1b From 23fd602f21953c03c0714257d36685cd6b486f04 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 30 Apr 2024 09:49:13 +0100 Subject: nvmem: layouts: sl28vpd: drop driver owner initialization Core in nvmem_layout_driver_register() already sets the .owner, so driver does not need to. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Michael Walle Reviewed-by: Miquel Raynal Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20240430084921.33387-4-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/layouts/sl28vpd.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/nvmem/layouts/sl28vpd.c b/drivers/nvmem/layouts/sl28vpd.c index 53fa50f17dca..e93b020b0836 100644 --- a/drivers/nvmem/layouts/sl28vpd.c +++ b/drivers/nvmem/layouts/sl28vpd.c @@ -156,7 +156,6 @@ MODULE_DEVICE_TABLE(of, sl28vpd_of_match_table); static struct nvmem_layout_driver sl28vpd_layout = { .driver = { - .owner = THIS_MODULE, .name = "kontron-sl28vpd-layout", .of_match_table = sl28vpd_of_match_table, }, -- cgit v1.2.3-59-g8ed1b From dc3d88ade857ba3dca34f008e0b0aed3ef79cb15 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 30 Apr 2024 09:49:14 +0100 Subject: nvmem: sc27xx: fix module autoloading Add MODULE_DEVICE_TABLE(), so the module could be properly autoloaded based on the alias from of_device_id table. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20240430084921.33387-5-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/sc27xx-efuse.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/nvmem/sc27xx-efuse.c b/drivers/nvmem/sc27xx-efuse.c index bff27011f4ff..4e2ffefac96c 100644 --- a/drivers/nvmem/sc27xx-efuse.c +++ b/drivers/nvmem/sc27xx-efuse.c @@ -262,6 +262,7 @@ static const struct of_device_id sc27xx_efuse_of_match[] = { { .compatible = "sprd,sc2730-efuse", .data = &sc2730_edata}, { } }; +MODULE_DEVICE_TABLE(of, sc27xx_efuse_of_match); static struct platform_driver sc27xx_efuse_driver = { .probe = sc27xx_efuse_probe, -- cgit v1.2.3-59-g8ed1b From 154c1ec943e34f3188c9305b0c91d5e7dc1373b8 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 30 Apr 2024 09:49:15 +0100 Subject: nvmem: sprd: fix module autoloading Add MODULE_DEVICE_TABLE(), so the module could be properly autoloaded based on the alias from of_device_id table. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20240430084921.33387-6-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/sprd-efuse.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/nvmem/sprd-efuse.c b/drivers/nvmem/sprd-efuse.c index bb3105f3291f..1a7e4e5d8b86 100644 --- a/drivers/nvmem/sprd-efuse.c +++ b/drivers/nvmem/sprd-efuse.c @@ -426,6 +426,7 @@ static const struct of_device_id sprd_efuse_of_match[] = { { .compatible = "sprd,ums312-efuse", .data = &ums312_data }, { } }; +MODULE_DEVICE_TABLE(of, sprd_efuse_of_match); static struct platform_driver sprd_efuse_driver = { .probe = sprd_efuse_probe, -- cgit v1.2.3-59-g8ed1b From 8d8fc146dd7a0d6a6b37695747a524310dfb9d57 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 30 Apr 2024 09:49:16 +0100 Subject: nvmem: core: switch to use device_add_groups() devm_device_add_groups() is being removed from the kernel, so move the nvmem driver to use device_add_groups() instead. The logic is identical, when the device is removed the driver core will properly clean up and remove the groups, and the memory used by the attribute groups will be freed because it was created with dev_* calls, so this is functionally identical overall. Cc: Srinivas Kandagatla Signed-off-by: Srinivas Kandagatla Signed-off-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20240430084921.33387-7-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index 2c6b99402df8..e1ec3b7200d7 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -478,7 +478,7 @@ static int nvmem_populate_sysfs_cells(struct nvmem_device *nvmem) nvmem_cells_group.bin_attrs = cells_attrs; - ret = devm_device_add_groups(&nvmem->dev, nvmem_cells_groups); + ret = device_add_groups(&nvmem->dev, nvmem_cells_groups); if (ret) goto unlock_mutex; -- cgit v1.2.3-59-g8ed1b From 693d2f629962628ddefc88f4b6b453edda5ac32e Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Tue, 30 Apr 2024 09:49:17 +0100 Subject: nvmem: lpc18xx_eeprom: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Acked-by: Vladimir Zapolskiy Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20240430084921.33387-8-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/lpc18xx_eeprom.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/nvmem/lpc18xx_eeprom.c b/drivers/nvmem/lpc18xx_eeprom.c index a0275b29afd5..a73acc7377d2 100644 --- a/drivers/nvmem/lpc18xx_eeprom.c +++ b/drivers/nvmem/lpc18xx_eeprom.c @@ -249,13 +249,11 @@ err_clk: return ret; } -static int lpc18xx_eeprom_remove(struct platform_device *pdev) +static void lpc18xx_eeprom_remove(struct platform_device *pdev) { struct lpc18xx_eeprom_dev *eeprom = platform_get_drvdata(pdev); clk_disable_unprepare(eeprom->clk); - - return 0; } static const struct of_device_id lpc18xx_eeprom_of_match[] = { @@ -266,7 +264,7 @@ MODULE_DEVICE_TABLE(of, lpc18xx_eeprom_of_match); static struct platform_driver lpc18xx_eeprom_driver = { .probe = lpc18xx_eeprom_probe, - .remove = lpc18xx_eeprom_remove, + .remove_new = lpc18xx_eeprom_remove, .driver = { .name = "lpc18xx-eeprom", .of_match_table = lpc18xx_eeprom_of_match, -- cgit v1.2.3-59-g8ed1b From e2c7d6e02382d0298779d37f79388498c5173178 Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Tue, 30 Apr 2024 09:49:18 +0100 Subject: dt-bindings: nvmem: Add compatible for sm8450, sm8550 and sm8650 Document QFPROM compatible for sm8450, sm8550 and sm8650 SoCs. Signed-off-by: Mukesh Ojha Reviewed-by: Krzysztof Kozlowski Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20240430084921.33387-9-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml b/Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml index 8c8f05d9eaf1..aed90aff3593 100644 --- a/Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml +++ b/Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml @@ -42,6 +42,9 @@ properties: - qcom,sm6375-qfprom - qcom,sm8150-qfprom - qcom,sm8250-qfprom + - qcom,sm8450-qfprom + - qcom,sm8550-qfprom + - qcom,sm8650-qfprom - const: qcom,qfprom reg: -- cgit v1.2.3-59-g8ed1b From dc5d4043510be6147dd6b4f625a94305a2776441 Mon Sep 17 00:00:00 2001 From: David Collins Date: Tue, 30 Apr 2024 09:49:19 +0100 Subject: dt-bindings: nvmem: qcom,spmi-sdam: update maintainer Emails to Shyam bounce (reason: 585 5.1.1 : Recipient address rejected: undeliverable address: No such user here.) so change the maintainer to be me. I work on qcom,spmi-sdam as well as other PMIC peripheral devices. Signed-off-by: David Collins Acked-by: Krzysztof Kozlowski Reviewed-by: Bjorn Andersson Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20240430084921.33387-10-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/nvmem/qcom,spmi-sdam.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/nvmem/qcom,spmi-sdam.yaml b/Documentation/devicetree/bindings/nvmem/qcom,spmi-sdam.yaml index 068bedf5dbc9..5d7be0b34536 100644 --- a/Documentation/devicetree/bindings/nvmem/qcom,spmi-sdam.yaml +++ b/Documentation/devicetree/bindings/nvmem/qcom,spmi-sdam.yaml @@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# title: Qualcomm Technologies, Inc. SPMI SDAM maintainers: - - Shyam Kumar Thella + - David Collins description: | The SDAM provides scratch register space for the PMIC clients. This -- cgit v1.2.3-59-g8ed1b From a5888ae5b3c33a8b339989e13b5e8ea2f927bcc4 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Tue, 30 Apr 2024 09:49:20 +0100 Subject: dt-bindings: nvmem: Add compatible for SC8280XP Document the QFPROM block found on SC8280XP. Signed-off-by: Konrad Dybcio Acked-by: Rob Herring Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20240430084921.33387-11-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml b/Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml index aed90aff3593..80845c722ae4 100644 --- a/Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml +++ b/Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml @@ -34,6 +34,7 @@ properties: - qcom,qcs404-qfprom - qcom,sc7180-qfprom - qcom,sc7280-qfprom + - qcom,sc8280xp-qfprom - qcom,sdm630-qfprom - qcom,sdm670-qfprom - qcom,sdm845-qfprom -- cgit v1.2.3-59-g8ed1b From 2a1ad6b75292d38aa2f6ded7335979e0632521da Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Tue, 30 Apr 2024 09:49:21 +0100 Subject: nvmem: meson-mx-efuse: Remove nvmem_device from efuse struct nvmem_device is used at one place while registering nvmem device and it is not required to be present in efuse struct for just this purpose. Drop nvmem_device and manage with nvmem device stack variable. Signed-off-by: Mukesh Ojha Reviewed-by: Martin Blumenstingl Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20240430084921.33387-12-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/meson-mx-efuse.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/nvmem/meson-mx-efuse.c b/drivers/nvmem/meson-mx-efuse.c index 3ff04d5ca8f8..8a16f5f02657 100644 --- a/drivers/nvmem/meson-mx-efuse.c +++ b/drivers/nvmem/meson-mx-efuse.c @@ -43,7 +43,6 @@ struct meson_mx_efuse_platform_data { struct meson_mx_efuse { void __iomem *base; struct clk *core_clk; - struct nvmem_device *nvmem; struct nvmem_config config; }; @@ -193,6 +192,7 @@ static int meson_mx_efuse_probe(struct platform_device *pdev) { const struct meson_mx_efuse_platform_data *drvdata; struct meson_mx_efuse *efuse; + struct nvmem_device *nvmem; drvdata = of_device_get_match_data(&pdev->dev); if (!drvdata) @@ -223,9 +223,9 @@ static int meson_mx_efuse_probe(struct platform_device *pdev) return PTR_ERR(efuse->core_clk); } - efuse->nvmem = devm_nvmem_register(&pdev->dev, &efuse->config); + nvmem = devm_nvmem_register(&pdev->dev, &efuse->config); - return PTR_ERR_OR_ZERO(efuse->nvmem); + return PTR_ERR_OR_ZERO(nvmem); } static struct platform_driver meson_mx_efuse_driver = { -- cgit v1.2.3-59-g8ed1b From 4286dbcecc3f8775852fee04c2ea8af265549af3 Mon Sep 17 00:00:00 2001 From: Viken Dadhaniya Date: Tue, 30 Apr 2024 10:16:55 +0100 Subject: slimbus: qcom-ngd-ctrl: Reduce auto suspend delay Currently we have auto suspend delay of 1s which is very high and it takes long time to driver for runtime suspend after use case is done. Hence to optimize runtime PM ops, reduce auto suspend delay to 100ms. Signed-off-by: Viken Dadhaniya Acked-by: Konrad Dybcio Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20240430091657.35428-2-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/slimbus/qcom-ngd-ctrl.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/slimbus/qcom-ngd-ctrl.c b/drivers/slimbus/qcom-ngd-ctrl.c index efeba8275a66..5e132273c6c4 100644 --- a/drivers/slimbus/qcom-ngd-ctrl.c +++ b/drivers/slimbus/qcom-ngd-ctrl.c @@ -81,7 +81,6 @@ #define SLIM_USR_MC_DISCONNECT_PORT 0x2E #define SLIM_USR_MC_REPEAT_CHANGE_VALUE 0x0 -#define QCOM_SLIM_NGD_AUTOSUSPEND MSEC_PER_SEC #define SLIM_RX_MSGQ_TIMEOUT_VAL 0x10000 #define SLIM_LA_MGR 0xFF @@ -1571,7 +1570,7 @@ static int qcom_slim_ngd_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ctrl); pm_runtime_use_autosuspend(dev); - pm_runtime_set_autosuspend_delay(dev, QCOM_SLIM_NGD_AUTOSUSPEND); + pm_runtime_set_autosuspend_delay(dev, 100); pm_runtime_set_suspended(dev); pm_runtime_enable(dev); pm_runtime_get_noresume(dev); -- cgit v1.2.3-59-g8ed1b From 880b33b0580c8ac9d0202b6e592cb116c99d1b65 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Tue, 30 Apr 2024 10:16:56 +0100 Subject: slimbus: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert the slimbus drivers from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20240430091657.35428-3-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/slimbus/qcom-ctrl.c | 5 ++--- drivers/slimbus/qcom-ngd-ctrl.c | 11 ++++------- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/drivers/slimbus/qcom-ctrl.c b/drivers/slimbus/qcom-ctrl.c index 400b7b385a44..7d632fad1300 100644 --- a/drivers/slimbus/qcom-ctrl.c +++ b/drivers/slimbus/qcom-ctrl.c @@ -626,7 +626,7 @@ err_request_irq_failed: return ret; } -static int qcom_slim_remove(struct platform_device *pdev) +static void qcom_slim_remove(struct platform_device *pdev) { struct qcom_slim_ctrl *ctrl = platform_get_drvdata(pdev); @@ -635,7 +635,6 @@ static int qcom_slim_remove(struct platform_device *pdev) clk_disable_unprepare(ctrl->rclk); clk_disable_unprepare(ctrl->hclk); destroy_workqueue(ctrl->rxwq); - return 0; } /* @@ -721,7 +720,7 @@ static const struct of_device_id qcom_slim_dt_match[] = { static struct platform_driver qcom_slim_driver = { .probe = qcom_slim_probe, - .remove = qcom_slim_remove, + .remove_new = qcom_slim_remove, .driver = { .name = "qcom_slim_ctrl", .of_match_table = qcom_slim_dt_match, diff --git a/drivers/slimbus/qcom-ngd-ctrl.c b/drivers/slimbus/qcom-ngd-ctrl.c index 5e132273c6c4..a33b5f9090fe 100644 --- a/drivers/slimbus/qcom-ngd-ctrl.c +++ b/drivers/slimbus/qcom-ngd-ctrl.c @@ -1674,14 +1674,12 @@ err_pdr_lookup: return ret; } -static int qcom_slim_ngd_ctrl_remove(struct platform_device *pdev) +static void qcom_slim_ngd_ctrl_remove(struct platform_device *pdev) { platform_driver_unregister(&qcom_slim_ngd_driver); - - return 0; } -static int qcom_slim_ngd_remove(struct platform_device *pdev) +static void qcom_slim_ngd_remove(struct platform_device *pdev) { struct qcom_slim_ngd_ctrl *ctrl = platform_get_drvdata(pdev); @@ -1696,7 +1694,6 @@ static int qcom_slim_ngd_remove(struct platform_device *pdev) kfree(ctrl->ngd); ctrl->ngd = NULL; - return 0; } static int __maybe_unused qcom_slim_ngd_runtime_idle(struct device *dev) @@ -1739,7 +1736,7 @@ static const struct dev_pm_ops qcom_slim_ngd_dev_pm_ops = { static struct platform_driver qcom_slim_ngd_ctrl_driver = { .probe = qcom_slim_ngd_ctrl_probe, - .remove = qcom_slim_ngd_ctrl_remove, + .remove_new = qcom_slim_ngd_ctrl_remove, .driver = { .name = "qcom,slim-ngd-ctrl", .of_match_table = qcom_slim_ngd_dt_match, @@ -1748,7 +1745,7 @@ static struct platform_driver qcom_slim_ngd_ctrl_driver = { static struct platform_driver qcom_slim_ngd_driver = { .probe = qcom_slim_ngd_probe, - .remove = qcom_slim_ngd_remove, + .remove_new = qcom_slim_ngd_remove, .driver = { .name = QCOM_SLIM_NGD_DRV_NAME, .pm = &qcom_slim_ngd_dev_pm_ops, -- cgit v1.2.3-59-g8ed1b From 35230d31056d82a416bba881cceca420fc90d079 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 30 Apr 2024 10:16:57 +0100 Subject: slimbus: qcom-ctrl: fix module autoloading Add MODULE_DEVICE_TABLE(), so the module could be properly autoloaded based on the alias from of_device_id table. Pin controllers are considered core components, so usually they are built-in, however these Signed-off-by: Krzysztof Kozlowski Reviewed-by: Konrad Dybcio Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20240430091657.35428-4-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/slimbus/qcom-ctrl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/slimbus/qcom-ctrl.c b/drivers/slimbus/qcom-ctrl.c index 7d632fad1300..0274bc285b60 100644 --- a/drivers/slimbus/qcom-ctrl.c +++ b/drivers/slimbus/qcom-ctrl.c @@ -717,6 +717,7 @@ static const struct of_device_id qcom_slim_dt_match[] = { { .compatible = "qcom,slim", }, {} }; +MODULE_DEVICE_TABLE(of, qcom_slim_dt_match); static struct platform_driver qcom_slim_driver = { .probe = qcom_slim_probe, -- cgit v1.2.3-59-g8ed1b From 8003f00d895310d409b2bf9ef907c56b42a4e0f4 Mon Sep 17 00:00:00 2001 From: Hagar Gamal Halim Hemdan Date: Tue, 30 Apr 2024 08:59:16 +0000 Subject: vmci: prevent speculation leaks by sanitizing event in event_deliver() Coverity spotted that event_msg is controlled by user-space, event_msg->event_data.event is passed to event_deliver() and used as an index without sanitization. This change ensures that the event index is sanitized to mitigate any possibility of speculative information leaks. This bug was discovered and resolved using Coverity Static Analysis Security Testing (SAST) by Synopsys, Inc. Only compile tested, no access to HW. Fixes: 1d990201f9bb ("VMCI: event handling implementation.") Cc: stable Signed-off-by: Hagar Gamal Halim Hemdan Link: https://lore.kernel.org/stable/20231127193533.46174-1-hagarhem%40amazon.com Link: https://lore.kernel.org/r/20240430085916.4753-1-hagarhem@amazon.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/vmw_vmci/vmci_event.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/misc/vmw_vmci/vmci_event.c b/drivers/misc/vmw_vmci/vmci_event.c index 5d7ac07623c2..9a41ab65378d 100644 --- a/drivers/misc/vmw_vmci/vmci_event.c +++ b/drivers/misc/vmw_vmci/vmci_event.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -86,9 +87,12 @@ static void event_deliver(struct vmci_event_msg *event_msg) { struct vmci_subscription *cur; struct list_head *subscriber_list; + u32 sanitized_event, max_vmci_event; rcu_read_lock(); - subscriber_list = &subscriber_array[event_msg->event_data.event]; + max_vmci_event = ARRAY_SIZE(subscriber_array); + sanitized_event = array_index_nospec(event_msg->event_data.event, max_vmci_event); + subscriber_list = &subscriber_array[sanitized_event]; list_for_each_entry_rcu(cur, subscriber_list, node) { cur->callback(cur->id, &event_msg->event_data, cur->callback_data); -- cgit v1.2.3-59-g8ed1b From b3e40fc85735b787ce65909619fcd173107113c2 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Thu, 2 May 2024 13:51:40 +0200 Subject: USB: usb_parse_endpoint: ignore reserved bits Reading bEndpointAddress the spec tells is that: b7 is direction, which must be ignored b6:4 are reserved which are to be set to zero b3:0 are the endpoint address In order to be backwards compatible with possible future versions of USB we have to be ready with devices using those bits. That means that we also have to ignore them like we do with the direction bit. In consequence the only illegal address you can encoding in four bits is endpoint zero, for which no descriptor must exist. Hence the check for exceeding the upper limit on endpoint addresses is removed. Signed-off-by: Oliver Neukum Reviewed-by: Alan Stern Link: https://lore.kernel.org/r/20240502115259.31076-1-oneukum@suse.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/config.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index 7f8d33f92ddb..3362af165ef5 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -279,11 +279,11 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, goto skip_to_next_endpoint_or_interface_descriptor; } - i = d->bEndpointAddress & ~USB_ENDPOINT_DIR_MASK; - if (i >= 16 || i == 0) { + i = d->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; + if (i == 0) { dev_notice(ddev, "config %d interface %d altsetting %d has an " - "invalid endpoint with address 0x%X, skipping\n", - cfgno, inum, asnum, d->bEndpointAddress); + "invalid descriptor for endpoint zero, skipping\n", + cfgno, inum, asnum); goto skip_to_next_endpoint_or_interface_descriptor; } -- cgit v1.2.3-59-g8ed1b From 559428a915e8a06e9e61a8327d0b2216116d3b14 Mon Sep 17 00:00:00 2001 From: Yu Kuai Date: Thu, 11 Apr 2024 15:53:42 +0100 Subject: ext4: remove block_device_ejected() block_device_ejected() is added by commit bdfe0cbd746a ("Revert "ext4: remove block_device_ejected"") in 2015. At that time 'bdi->wb' is destroyed synchronized from del_gendisk(), hence if ext4 is still mounted, and then mark_buffer_dirty() will reference destroyed 'wb'. However, such problem doesn't exist anymore: - commit d03f6cdc1fc4 ("block: Dynamically allocate and refcount backing_dev_info") switch bdi to use refcounting; - commit 13eec2363ef0 ("fs: Get proper reference for s_bdi"), will grab additional reference of bdi while mounting, so that 'bdi->wb' will not be destroyed until generic_shutdown_super(). Hence remove this dead function block_device_ejected(). Signed-off-by: Yu Kuai Reviewed-by: Jan Kara Reviewed-by: Christoph Hellwig Signed-off-by: Al Viro Link: https://lore.kernel.org/r/20240411145346.2516848-7-viro@zeniv.linux.org.uk Signed-off-by: Christian Brauner --- fs/ext4/super.c | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 9988b3a40b42..b255f798f449 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -492,22 +492,6 @@ static void ext4_maybe_update_superblock(struct super_block *sb) schedule_work(&EXT4_SB(sb)->s_sb_upd_work); } -/* - * The del_gendisk() function uninitializes the disk-specific data - * structures, including the bdi structure, without telling anyone - * else. Once this happens, any attempt to call mark_buffer_dirty() - * (for example, by ext4_commit_super), will cause a kernel OOPS. - * This is a kludge to prevent these oops until we can put in a proper - * hook in del_gendisk() to inform the VFS and file system layers. - */ -static int block_device_ejected(struct super_block *sb) -{ - struct inode *bd_inode = sb->s_bdev->bd_inode; - struct backing_dev_info *bdi = inode_to_bdi(bd_inode); - - return bdi->dev == NULL; -} - static void ext4_journal_commit_callback(journal_t *journal, transaction_t *txn) { struct super_block *sb = journal->j_private; @@ -6172,8 +6156,6 @@ static int ext4_commit_super(struct super_block *sb) if (!sbh) return -EINVAL; - if (block_device_ejected(sb)) - return -ENODEV; ext4_update_super(sb); -- cgit v1.2.3-59-g8ed1b From 9baf50dfff1c55e704cae74c5f1c65f0fe254f1e Mon Sep 17 00:00:00 2001 From: Yu Kuai Date: Thu, 11 Apr 2024 15:53:45 +0100 Subject: bcachefs: remove dead function bdev_sectors() bdev_sectors() is not used hence remove it. Signed-off-by: Yu Kuai Reviewed-by: Christoph Hellwig Reviewed-by: Jan Kara Signed-off-by: Al Viro Link: https://lore.kernel.org/r/20240411145346.2516848-10-viro@zeniv.linux.org.uk Acked-by: Kent Overstreet Signed-off-by: Christian Brauner --- fs/bcachefs/util.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/fs/bcachefs/util.h b/fs/bcachefs/util.h index 5cf885b09986..5d2c470a49ac 100644 --- a/fs/bcachefs/util.h +++ b/fs/bcachefs/util.h @@ -445,11 +445,6 @@ static inline unsigned fract_exp_two(unsigned x, unsigned fract_bits) void bch2_bio_map(struct bio *bio, void *base, size_t); int bch2_bio_alloc_pages(struct bio *, size_t, gfp_t); -static inline sector_t bdev_sectors(struct block_device *bdev) -{ - return bdev->bd_inode->i_size >> 9; -} - #define closure_bio_submit(bio, cl) \ do { \ closure_get(cl); \ -- cgit v1.2.3-59-g8ed1b From 39c3b4e7d0a0d8876f29ea078b978b3caa924542 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 11 Apr 2024 15:53:40 +0100 Subject: blkdev_write_iter(): saner way to get inode and bdev ... same as in other methods - bdev_file_inode() and I_BDEV() of that. Signed-off-by: Al Viro Link: https://lore.kernel.org/r/20240411145346.2516848-5-viro@zeniv.linux.org.uk Signed-off-by: Christian Brauner --- block/fops.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/block/fops.c b/block/fops.c index 679d9b752fe8..9d0f36688a5d 100644 --- a/block/fops.c +++ b/block/fops.c @@ -668,8 +668,8 @@ static ssize_t blkdev_buffered_write(struct kiocb *iocb, struct iov_iter *from) static ssize_t blkdev_write_iter(struct kiocb *iocb, struct iov_iter *from) { struct file *file = iocb->ki_filp; - struct block_device *bdev = I_BDEV(file->f_mapping->host); - struct inode *bd_inode = bdev->bd_inode; + struct inode *bd_inode = bdev_file_inode(file); + struct block_device *bdev = I_BDEV(bd_inode); loff_t size = bdev_nr_bytes(bdev); size_t shorted = 0; ssize_t ret; -- cgit v1.2.3-59-g8ed1b From dc0fdfc855bea671ee503f9c706303367bdda946 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 11 Apr 2024 15:53:44 +0100 Subject: dm-vdo: use bdev_nr_bytes(bdev) instead of i_size_read(bdev->bd_inode) going to be faster, actually - shift is cheaper than dereference... Signed-off-by: Al Viro Link: https://lore.kernel.org/r/20240411145346.2516848-9-viro@zeniv.linux.org.uk Reviewed-by: Matthew Sakai Signed-off-by: Christian Brauner --- drivers/md/dm-vdo/dm-vdo-target.c | 4 ++-- drivers/md/dm-vdo/indexer/io-factory.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/md/dm-vdo/dm-vdo-target.c b/drivers/md/dm-vdo/dm-vdo-target.c index 5a4b0a927f56..b423bec6458b 100644 --- a/drivers/md/dm-vdo/dm-vdo-target.c +++ b/drivers/md/dm-vdo/dm-vdo-target.c @@ -878,7 +878,7 @@ static int parse_device_config(int argc, char **argv, struct dm_target *ti, } if (config->version == 0) { - u64 device_size = i_size_read(config->owned_device->bdev->bd_inode); + u64 device_size = bdev_nr_bytes(config->owned_device->bdev); config->physical_blocks = device_size / VDO_BLOCK_SIZE; } @@ -1011,7 +1011,7 @@ static void vdo_status(struct dm_target *ti, status_type_t status_type, static block_count_t __must_check get_underlying_device_block_count(const struct vdo *vdo) { - return i_size_read(vdo_get_backing_device(vdo)->bd_inode) / VDO_BLOCK_SIZE; + return bdev_nr_bytes(vdo_get_backing_device(vdo)) / VDO_BLOCK_SIZE; } static int __must_check process_vdo_message_locked(struct vdo *vdo, unsigned int argc, diff --git a/drivers/md/dm-vdo/indexer/io-factory.c b/drivers/md/dm-vdo/indexer/io-factory.c index 515765d35794..1bee9d63dc0a 100644 --- a/drivers/md/dm-vdo/indexer/io-factory.c +++ b/drivers/md/dm-vdo/indexer/io-factory.c @@ -90,7 +90,7 @@ void uds_put_io_factory(struct io_factory *factory) size_t uds_get_writable_size(struct io_factory *factory) { - return i_size_read(factory->bdev->bd_inode); + return bdev_nr_bytes(factory->bdev); } /* Create a struct dm_bufio_client for an index region starting at offset. */ -- cgit v1.2.3-59-g8ed1b From c9600c63a694249100e2bdcbb604c30d8fee2dc7 Mon Sep 17 00:00:00 2001 From: Yu Kuai Date: Thu, 11 Apr 2024 15:53:46 +0100 Subject: block2mtd: prevent direct access of bd_inode All we need is size, and that can be obtained via bdev_nr_bytes() Signed-off-by: Yu Kuai Reviewed-by: Christoph Hellwig Reviewed-by: Jan Kara Signed-off-by: Al Viro Link: https://lore.kernel.org/r/20240411145346.2516848-11-viro@zeniv.linux.org.uk Signed-off-by: Christian Brauner --- drivers/mtd/devices/block2mtd.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c index caacdc0a3819..b06c8dd51562 100644 --- a/drivers/mtd/devices/block2mtd.c +++ b/drivers/mtd/devices/block2mtd.c @@ -265,6 +265,7 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size, struct file *bdev_file; struct block_device *bdev; struct block2mtd_dev *dev; + loff_t size; char *name; if (!devname) @@ -291,7 +292,8 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size, goto err_free_block2mtd; } - if ((long)bdev->bd_inode->i_size % erase_size) { + size = bdev_nr_bytes(bdev); + if ((long)size % erase_size) { pr_err("erasesize must be a divisor of device size\n"); goto err_free_block2mtd; } @@ -309,7 +311,7 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size, dev->mtd.name = name; - dev->mtd.size = bdev->bd_inode->i_size & PAGE_MASK; + dev->mtd.size = size & PAGE_MASK; dev->mtd.erasesize = erase_size; dev->mtd.writesize = 1; dev->mtd.writebufsize = PAGE_SIZE; -- cgit v1.2.3-59-g8ed1b From 186ddac2072a8134798d72635d1ed0f29889369d Mon Sep 17 00:00:00 2001 From: Yu Kuai Date: Thu, 11 Apr 2024 15:53:43 +0100 Subject: block: move two helpers into bdev.c disk_live() and block_size() access bd_inode directly, prepare to remove the field bd_inode from block_device, and only access bd_inode in block layer. Signed-off-by: Yu Kuai Reviewed-by: Christoph Hellwig Reviewed-by: Jan Kara Signed-off-by: Al Viro Link: https://lore.kernel.org/r/20240411145346.2516848-8-viro@zeniv.linux.org.uk Signed-off-by: Christian Brauner --- block/bdev.c | 12 ++++++++++++ include/linux/blkdev.h | 12 ++---------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/block/bdev.c b/block/bdev.c index a89bce368b64..536233ac3e99 100644 --- a/block/bdev.c +++ b/block/bdev.c @@ -1257,6 +1257,18 @@ void bdev_statx_dioalign(struct inode *inode, struct kstat *stat) blkdev_put_no_open(bdev); } +bool disk_live(struct gendisk *disk) +{ + return !inode_unhashed(disk->part0->bd_inode); +} +EXPORT_SYMBOL_GPL(disk_live); + +unsigned int block_size(struct block_device *bdev) +{ + return 1 << bdev->bd_inode->i_blkbits; +} +EXPORT_SYMBOL_GPL(block_size); + static int __init setup_bdev_allow_write_mounted(char *str) { if (kstrtobool(str, &bdev_allow_write_mounted)) diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 20c749b2ebc2..99ac98ed9548 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -211,11 +211,6 @@ struct gendisk { struct blk_independent_access_ranges *ia_ranges; }; -static inline bool disk_live(struct gendisk *disk) -{ - return !inode_unhashed(disk->part0->bd_inode); -} - /** * disk_openers - returns how many openers are there for a disk * @disk: disk to check @@ -1364,11 +1359,6 @@ static inline unsigned int blksize_bits(unsigned int size) return order_base_2(size >> SECTOR_SHIFT) + SECTOR_SHIFT; } -static inline unsigned int block_size(struct block_device *bdev) -{ - return 1 << bdev->bd_inode->i_blkbits; -} - int kblockd_schedule_work(struct work_struct *work); int kblockd_mod_delayed_work_on(int cpu, struct delayed_work *dwork, unsigned long delay); @@ -1536,6 +1526,8 @@ void blkdev_put_no_open(struct block_device *bdev); struct block_device *I_BDEV(struct inode *inode); struct block_device *file_bdev(struct file *bdev_file); +bool disk_live(struct gendisk *disk); +unsigned int block_size(struct block_device *bdev); #ifdef CONFIG_BLOCK void invalidate_bdev(struct block_device *bdev); -- cgit v1.2.3-59-g8ed1b From 2638c20876734f986fd91cfbe196483835ed7095 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 28 Apr 2024 19:01:39 -0400 Subject: missing helpers: bdev_unhash(), bdev_drop() bdev_unhash(): make block device invisible to lookups by device number bdev_drop(): drop reference to associated inode. Both are internal, for use by genhd and partition-related code - similar to bdev_add(). The logics in there (especially the lifetime-related parts of it) ought to be cleaned up, but that's a separate story; here we just encapsulate getting to associated inode. Signed-off-by: Al Viro --- block/bdev.c | 10 ++++++++++ block/blk.h | 2 ++ block/genhd.c | 6 +++--- block/partitions/core.c | 6 +++--- 4 files changed, 18 insertions(+), 6 deletions(-) diff --git a/block/bdev.c b/block/bdev.c index 536233ac3e99..28e6f0423857 100644 --- a/block/bdev.c +++ b/block/bdev.c @@ -451,6 +451,16 @@ void bdev_add(struct block_device *bdev, dev_t dev) insert_inode_hash(bdev->bd_inode); } +void bdev_unhash(struct block_device *bdev) +{ + remove_inode_hash(bdev->bd_inode); +} + +void bdev_drop(struct block_device *bdev) +{ + iput(bdev->bd_inode); +} + long nr_blockdev_pages(void) { struct inode *inode; diff --git a/block/blk.h b/block/blk.h index d9f584984bc4..e3347e1030d5 100644 --- a/block/blk.h +++ b/block/blk.h @@ -428,6 +428,8 @@ static inline int blkdev_zone_mgmt_ioctl(struct block_device *bdev, struct block_device *bdev_alloc(struct gendisk *disk, u8 partno); void bdev_add(struct block_device *bdev, dev_t dev); +void bdev_unhash(struct block_device *bdev); +void bdev_drop(struct block_device *bdev); int blk_alloc_ext_minor(void); void blk_free_ext_minor(unsigned int minor); diff --git a/block/genhd.c b/block/genhd.c index bb29a68e1d67..93f5118b7d41 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -656,7 +656,7 @@ void del_gendisk(struct gendisk *disk) */ mutex_lock(&disk->open_mutex); xa_for_each(&disk->part_tbl, idx, part) - remove_inode_hash(part->bd_inode); + bdev_unhash(part); mutex_unlock(&disk->open_mutex); /* @@ -1191,7 +1191,7 @@ static void disk_release(struct device *dev) if (test_bit(GD_ADDED, &disk->state) && disk->fops->free_disk) disk->fops->free_disk(disk); - iput(disk->part0->bd_inode); /* frees the disk */ + bdev_drop(disk->part0); /* frees the disk */ } static int block_uevent(const struct device *dev, struct kobj_uevent_env *env) @@ -1381,7 +1381,7 @@ out_erase_part0: out_destroy_part_tbl: xa_destroy(&disk->part_tbl); disk->part0->bd_disk = NULL; - iput(disk->part0->bd_inode); + bdev_drop(disk->part0); out_free_bdi: bdi_put(disk->bdi); out_free_bioset: diff --git a/block/partitions/core.c b/block/partitions/core.c index b11e88c82c8c..2b75e325c63b 100644 --- a/block/partitions/core.c +++ b/block/partitions/core.c @@ -243,7 +243,7 @@ static const struct attribute_group *part_attr_groups[] = { static void part_release(struct device *dev) { put_disk(dev_to_bdev(dev)->bd_disk); - iput(dev_to_bdev(dev)->bd_inode); + bdev_drop(dev_to_bdev(dev)); } static int part_uevent(const struct device *dev, struct kobj_uevent_env *env) @@ -469,7 +469,7 @@ int bdev_del_partition(struct gendisk *disk, int partno) * Just delete the partition and invalidate it. */ - remove_inode_hash(part->bd_inode); + bdev_unhash(part); invalidate_bdev(part); drop_partition(part); ret = 0; @@ -655,7 +655,7 @@ rescan: * it cannot be looked up any more even when openers * still hold references. */ - remove_inode_hash(part->bd_inode); + bdev_unhash(part); /* * If @disk->open_partitions isn't elevated but there's -- cgit v1.2.3-59-g8ed1b From e33aef2c58577f51ec22736843a652576ce0ef7a Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 11 Apr 2024 15:53:36 +0100 Subject: block_device: add a pointer to struct address_space (page cache of bdev) points to ->i_data of coallocated inode. Signed-off-by: Al Viro Link: https://lore.kernel.org/r/20240411145346.2516848-1-viro@zeniv.linux.org.uk Signed-off-by: Christian Brauner --- block/bdev.c | 1 + include/linux/blk_types.h | 1 + 2 files changed, 2 insertions(+) diff --git a/block/bdev.c b/block/bdev.c index 28e6f0423857..8e19101cbbb0 100644 --- a/block/bdev.c +++ b/block/bdev.c @@ -419,6 +419,7 @@ struct block_device *bdev_alloc(struct gendisk *disk, u8 partno) mutex_init(&bdev->bd_holder_lock); bdev->bd_partno = partno; bdev->bd_inode = inode; + bdev->bd_mapping = &inode->i_data; bdev->bd_queue = disk->queue; if (partno) bdev->bd_has_submit_bio = disk->part0->bd_has_submit_bio; diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h index cb1526ec44b5..6438c75cbb35 100644 --- a/include/linux/blk_types.h +++ b/include/linux/blk_types.h @@ -51,6 +51,7 @@ struct block_device { bool bd_has_submit_bio; dev_t bd_dev; struct inode *bd_inode; /* will die */ + struct address_space *bd_mapping; /* page cache */ atomic_t bd_openers; spinlock_t bd_size_lock; /* for bd_inode->i_size updates */ -- cgit v1.2.3-59-g8ed1b From 224941e8379a0de8652ffec768cc8394f0b1cb95 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 11 Apr 2024 15:53:37 +0100 Subject: use ->bd_mapping instead of ->bd_inode->i_mapping Just the low-hanging fruit... Signed-off-by: Al Viro Link: https://lore.kernel.org/r/20240411145346.2516848-2-viro@zeniv.linux.org.uk Signed-off-by: Christian Brauner --- block/bdev.c | 18 +++++++++--------- block/blk-zoned.c | 4 ++-- block/genhd.c | 2 +- block/ioctl.c | 4 ++-- block/partitions/core.c | 2 +- drivers/md/bcache/super.c | 2 +- drivers/scsi/scsicam.c | 2 +- fs/btrfs/disk-io.c | 6 +++--- fs/btrfs/volumes.c | 2 +- fs/btrfs/zoned.c | 2 +- fs/buffer.c | 2 +- fs/cramfs/inode.c | 2 +- fs/erofs/data.c | 2 +- fs/ext4/dir.c | 2 +- fs/ext4/ext4_jbd2.c | 2 +- fs/ext4/super.c | 6 +++--- fs/jbd2/journal.c | 2 +- include/linux/buffer_head.h | 4 ++-- include/linux/jbd2.h | 4 ++-- 19 files changed, 35 insertions(+), 35 deletions(-) diff --git a/block/bdev.c b/block/bdev.c index 8e19101cbbb0..00017af92a51 100644 --- a/block/bdev.c +++ b/block/bdev.c @@ -76,7 +76,7 @@ static void bdev_write_inode(struct block_device *bdev) /* Kill _all_ buffers and pagecache , dirty or not.. */ static void kill_bdev(struct block_device *bdev) { - struct address_space *mapping = bdev->bd_inode->i_mapping; + struct address_space *mapping = bdev->bd_mapping; if (mapping_empty(mapping)) return; @@ -88,7 +88,7 @@ static void kill_bdev(struct block_device *bdev) /* Invalidate clean unused buffers and pagecache. */ void invalidate_bdev(struct block_device *bdev) { - struct address_space *mapping = bdev->bd_inode->i_mapping; + struct address_space *mapping = bdev->bd_mapping; if (mapping->nrpages) { invalidate_bh_lrus(); @@ -116,7 +116,7 @@ int truncate_bdev_range(struct block_device *bdev, blk_mode_t mode, goto invalidate; } - truncate_inode_pages_range(bdev->bd_inode->i_mapping, lstart, lend); + truncate_inode_pages_range(bdev->bd_mapping, lstart, lend); if (!(mode & BLK_OPEN_EXCL)) bd_abort_claiming(bdev, truncate_bdev_range); return 0; @@ -126,7 +126,7 @@ invalidate: * Someone else has handle exclusively open. Try invalidating instead. * The 'end' argument is inclusive so the rounding is safe. */ - return invalidate_inode_pages2_range(bdev->bd_inode->i_mapping, + return invalidate_inode_pages2_range(bdev->bd_mapping, lstart >> PAGE_SHIFT, lend >> PAGE_SHIFT); } @@ -198,7 +198,7 @@ int sync_blockdev_nowait(struct block_device *bdev) { if (!bdev) return 0; - return filemap_flush(bdev->bd_inode->i_mapping); + return filemap_flush(bdev->bd_mapping); } EXPORT_SYMBOL_GPL(sync_blockdev_nowait); @@ -210,13 +210,13 @@ int sync_blockdev(struct block_device *bdev) { if (!bdev) return 0; - return filemap_write_and_wait(bdev->bd_inode->i_mapping); + return filemap_write_and_wait(bdev->bd_mapping); } EXPORT_SYMBOL(sync_blockdev); int sync_blockdev_range(struct block_device *bdev, loff_t lstart, loff_t lend) { - return filemap_write_and_wait_range(bdev->bd_inode->i_mapping, + return filemap_write_and_wait_range(bdev->bd_mapping, lstart, lend); } EXPORT_SYMBOL(sync_blockdev_range); @@ -445,7 +445,7 @@ void bdev_set_nr_sectors(struct block_device *bdev, sector_t sectors) void bdev_add(struct block_device *bdev, dev_t dev) { if (bdev_stable_writes(bdev)) - mapping_set_stable_writes(bdev->bd_inode->i_mapping); + mapping_set_stable_writes(bdev->bd_mapping); bdev->bd_dev = dev; bdev->bd_inode->i_rdev = dev; bdev->bd_inode->i_ino = dev; @@ -925,7 +925,7 @@ int bdev_open(struct block_device *bdev, blk_mode_t mode, void *holder, bdev_file->f_mode |= FMODE_NOWAIT; if (mode & BLK_OPEN_RESTRICT_WRITES) bdev_file->f_mode |= FMODE_WRITE_RESTRICTED; - bdev_file->f_mapping = bdev->bd_inode->i_mapping; + bdev_file->f_mapping = bdev->bd_mapping; bdev_file->f_wb_err = filemap_sample_wb_err(bdev_file->f_mapping); bdev_file->private_data = holder; diff --git a/block/blk-zoned.c b/block/blk-zoned.c index da0f4b2a8fa0..b008bcd4889c 100644 --- a/block/blk-zoned.c +++ b/block/blk-zoned.c @@ -398,7 +398,7 @@ int blkdev_zone_mgmt_ioctl(struct block_device *bdev, blk_mode_t mode, op = REQ_OP_ZONE_RESET; /* Invalidate the page cache, including dirty pages. */ - filemap_invalidate_lock(bdev->bd_inode->i_mapping); + filemap_invalidate_lock(bdev->bd_mapping); ret = blkdev_truncate_zone_range(bdev, mode, &zrange); if (ret) goto fail; @@ -420,7 +420,7 @@ int blkdev_zone_mgmt_ioctl(struct block_device *bdev, blk_mode_t mode, fail: if (cmd == BLKRESETZONE) - filemap_invalidate_unlock(bdev->bd_inode->i_mapping); + filemap_invalidate_unlock(bdev->bd_mapping); return ret; } diff --git a/block/genhd.c b/block/genhd.c index 93f5118b7d41..2bf05bd0f071 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -745,7 +745,7 @@ void invalidate_disk(struct gendisk *disk) struct block_device *bdev = disk->part0; invalidate_bdev(bdev); - bdev->bd_inode->i_mapping->wb_err = 0; + bdev->bd_mapping->wb_err = 0; set_capacity(disk, 0); } EXPORT_SYMBOL(invalidate_disk); diff --git a/block/ioctl.c b/block/ioctl.c index 1c800364bc70..7c13d8bed453 100644 --- a/block/ioctl.c +++ b/block/ioctl.c @@ -152,12 +152,12 @@ static int blk_ioctl_secure_erase(struct block_device *bdev, blk_mode_t mode, if (start + len > bdev_nr_bytes(bdev)) return -EINVAL; - filemap_invalidate_lock(bdev->bd_inode->i_mapping); + filemap_invalidate_lock(bdev->bd_mapping); err = truncate_bdev_range(bdev, mode, start, start + len - 1); if (!err) err = blkdev_issue_secure_erase(bdev, start >> 9, len >> 9, GFP_KERNEL); - filemap_invalidate_unlock(bdev->bd_inode->i_mapping); + filemap_invalidate_unlock(bdev->bd_mapping); return err; } diff --git a/block/partitions/core.c b/block/partitions/core.c index 2b75e325c63b..63ee317dfff0 100644 --- a/block/partitions/core.c +++ b/block/partitions/core.c @@ -704,7 +704,7 @@ EXPORT_SYMBOL_GPL(bdev_disk_changed); void *read_part_sector(struct parsed_partitions *state, sector_t n, Sector *p) { - struct address_space *mapping = state->disk->part0->bd_inode->i_mapping; + struct address_space *mapping = state->disk->part0->bd_mapping; struct folio *folio; if (n >= get_capacity(state->disk)) { diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c index 0ee5e17ae2dd..277ad958cf53 100644 --- a/drivers/md/bcache/super.c +++ b/drivers/md/bcache/super.c @@ -171,7 +171,7 @@ static const char *read_super(struct cache_sb *sb, struct block_device *bdev, struct page *page; unsigned int i; - page = read_cache_page_gfp(bdev->bd_inode->i_mapping, + page = read_cache_page_gfp(bdev->bd_mapping, SB_OFFSET >> PAGE_SHIFT, GFP_KERNEL); if (IS_ERR(page)) return "IO error"; diff --git a/drivers/scsi/scsicam.c b/drivers/scsi/scsicam.c index e2c7d8ef205f..dd69342bbe78 100644 --- a/drivers/scsi/scsicam.c +++ b/drivers/scsi/scsicam.c @@ -32,7 +32,7 @@ */ unsigned char *scsi_bios_ptable(struct block_device *dev) { - struct address_space *mapping = bdev_whole(dev)->bd_inode->i_mapping; + struct address_space *mapping = bdev_whole(dev)->bd_mapping; unsigned char *res = NULL; struct folio *folio; diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 3df5477d48a8..f10e894b0bf5 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -3651,7 +3651,7 @@ struct btrfs_super_block *btrfs_read_dev_one_super(struct block_device *bdev, struct btrfs_super_block *super; struct page *page; u64 bytenr, bytenr_orig; - struct address_space *mapping = bdev->bd_inode->i_mapping; + struct address_space *mapping = bdev->bd_mapping; int ret; bytenr_orig = btrfs_sb_offset(copy_num); @@ -3738,7 +3738,7 @@ static int write_dev_supers(struct btrfs_device *device, struct btrfs_super_block *sb, int max_mirrors) { struct btrfs_fs_info *fs_info = device->fs_info; - struct address_space *mapping = device->bdev->bd_inode->i_mapping; + struct address_space *mapping = device->bdev->bd_mapping; SHASH_DESC_ON_STACK(shash, fs_info->csum_shash); int i; int errors = 0; @@ -3855,7 +3855,7 @@ static int wait_dev_supers(struct btrfs_device *device, int max_mirrors) device->commit_total_bytes) break; - page = find_get_page(device->bdev->bd_inode->i_mapping, + page = find_get_page(device->bdev->bd_mapping, bytenr >> PAGE_SHIFT); if (!page) { errors++; diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 65c03ddecc59..33d357e5f9c5 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -1290,7 +1290,7 @@ static struct btrfs_super_block *btrfs_read_disk_super(struct block_device *bdev return ERR_PTR(-EINVAL); /* pull in the page with our super */ - page = read_cache_page_gfp(bdev->bd_inode->i_mapping, index, GFP_KERNEL); + page = read_cache_page_gfp(bdev->bd_mapping, index, GFP_KERNEL); if (IS_ERR(page)) return ERR_CAST(page); diff --git a/fs/btrfs/zoned.c b/fs/btrfs/zoned.c index 4cba80b34387..9b43fa493219 100644 --- a/fs/btrfs/zoned.c +++ b/fs/btrfs/zoned.c @@ -118,7 +118,7 @@ static int sb_write_pointer(struct block_device *bdev, struct blk_zone *zones, return -ENOENT; } else if (full[0] && full[1]) { /* Compare two super blocks */ - struct address_space *mapping = bdev->bd_inode->i_mapping; + struct address_space *mapping = bdev->bd_mapping; struct page *page[BTRFS_NR_SB_LOG_ZONES]; struct btrfs_super_block *super[BTRFS_NR_SB_LOG_ZONES]; int i; diff --git a/fs/buffer.c b/fs/buffer.c index 4f73d23c2c46..d5a0932ae68d 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -1463,7 +1463,7 @@ __bread_gfp(struct block_device *bdev, sector_t block, { struct buffer_head *bh; - gfp |= mapping_gfp_constraint(bdev->bd_inode->i_mapping, ~__GFP_FS); + gfp |= mapping_gfp_constraint(bdev->bd_mapping, ~__GFP_FS); /* * Prefer looping in the allocator rather than here, at least that diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c index 9901057a15ba..460690ca0174 100644 --- a/fs/cramfs/inode.c +++ b/fs/cramfs/inode.c @@ -183,7 +183,7 @@ static int next_buffer; static void *cramfs_blkdev_read(struct super_block *sb, unsigned int offset, unsigned int len) { - struct address_space *mapping = sb->s_bdev->bd_inode->i_mapping; + struct address_space *mapping = sb->s_bdev->bd_mapping; struct file_ra_state ra = {}; struct page *pages[BLKS_PER_BUF]; unsigned i, blocknr, buffer; diff --git a/fs/erofs/data.c b/fs/erofs/data.c index e1a170e45c70..5fc03c1e2757 100644 --- a/fs/erofs/data.c +++ b/fs/erofs/data.c @@ -68,7 +68,7 @@ void erofs_init_metabuf(struct erofs_buf *buf, struct super_block *sb) if (erofs_is_fscache_mode(sb)) buf->mapping = EROFS_SB(sb)->s_fscache->inode->i_mapping; else - buf->mapping = sb->s_bdev->bd_inode->i_mapping; + buf->mapping = sb->s_bdev->bd_mapping; } void *erofs_read_metabuf(struct erofs_buf *buf, struct super_block *sb, diff --git a/fs/ext4/dir.c b/fs/ext4/dir.c index 3985f8c33f95..ff4514e4626b 100644 --- a/fs/ext4/dir.c +++ b/fs/ext4/dir.c @@ -192,7 +192,7 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx) (PAGE_SHIFT - inode->i_blkbits); if (!ra_has_index(&file->f_ra, index)) page_cache_sync_readahead( - sb->s_bdev->bd_inode->i_mapping, + sb->s_bdev->bd_mapping, &file->f_ra, file, index, 1); file->f_ra.prev_pos = (loff_t)index << PAGE_SHIFT; diff --git a/fs/ext4/ext4_jbd2.c b/fs/ext4/ext4_jbd2.c index 5d8055161acd..da4a82456383 100644 --- a/fs/ext4/ext4_jbd2.c +++ b/fs/ext4/ext4_jbd2.c @@ -206,7 +206,7 @@ static void ext4_journal_abort_handle(const char *caller, unsigned int line, static void ext4_check_bdev_write_error(struct super_block *sb) { - struct address_space *mapping = sb->s_bdev->bd_inode->i_mapping; + struct address_space *mapping = sb->s_bdev->bd_mapping; struct ext4_sb_info *sbi = EXT4_SB(sb); int err; diff --git a/fs/ext4/super.c b/fs/ext4/super.c index b255f798f449..02042eb91806 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -244,7 +244,7 @@ static struct buffer_head *__ext4_sb_bread_gfp(struct super_block *sb, struct buffer_head *ext4_sb_bread(struct super_block *sb, sector_t block, blk_opf_t op_flags) { - gfp_t gfp = mapping_gfp_constraint(sb->s_bdev->bd_inode->i_mapping, + gfp_t gfp = mapping_gfp_constraint(sb->s_bdev->bd_mapping, ~__GFP_FS) | __GFP_MOVABLE; return __ext4_sb_bread_gfp(sb, block, op_flags, gfp); @@ -253,7 +253,7 @@ struct buffer_head *ext4_sb_bread(struct super_block *sb, sector_t block, struct buffer_head *ext4_sb_bread_unmovable(struct super_block *sb, sector_t block) { - gfp_t gfp = mapping_gfp_constraint(sb->s_bdev->bd_inode->i_mapping, + gfp_t gfp = mapping_gfp_constraint(sb->s_bdev->bd_mapping, ~__GFP_FS); return __ext4_sb_bread_gfp(sb, block, 0, gfp); @@ -5556,7 +5556,7 @@ static int __ext4_fill_super(struct fs_context *fc, struct super_block *sb) * used to detect the metadata async write error. */ spin_lock_init(&sbi->s_bdev_wb_lock); - errseq_check_and_advance(&sb->s_bdev->bd_inode->i_mapping->wb_err, + errseq_check_and_advance(&sb->s_bdev->bd_mapping->wb_err, &sbi->s_bdev_wb_err); EXT4_SB(sb)->s_mount_state |= EXT4_ORPHAN_FS; ext4_orphan_cleanup(sb, es); diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c index b6c114c11b97..03c4b9214f56 100644 --- a/fs/jbd2/journal.c +++ b/fs/jbd2/journal.c @@ -2009,7 +2009,7 @@ static int __jbd2_journal_erase(journal_t *journal, unsigned int flags) byte_count = (block_stop - block_start + 1) * journal->j_blocksize; - truncate_inode_pages_range(journal->j_dev->bd_inode->i_mapping, + truncate_inode_pages_range(journal->j_dev->bd_mapping, byte_start, byte_stop); if (flags & JBD2_JOURNAL_FLUSH_DISCARD) { diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h index d78454a4dd1f..e58a0d63409a 100644 --- a/include/linux/buffer_head.h +++ b/include/linux/buffer_head.h @@ -338,7 +338,7 @@ static inline struct buffer_head *getblk_unmovable(struct block_device *bdev, { gfp_t gfp; - gfp = mapping_gfp_constraint(bdev->bd_inode->i_mapping, ~__GFP_FS); + gfp = mapping_gfp_constraint(bdev->bd_mapping, ~__GFP_FS); gfp |= __GFP_NOFAIL; return bdev_getblk(bdev, block, size, gfp); @@ -349,7 +349,7 @@ static inline struct buffer_head *__getblk(struct block_device *bdev, { gfp_t gfp; - gfp = mapping_gfp_constraint(bdev->bd_inode->i_mapping, ~__GFP_FS); + gfp = mapping_gfp_constraint(bdev->bd_mapping, ~__GFP_FS); gfp |= __GFP_MOVABLE | __GFP_NOFAIL; return bdev_getblk(bdev, block, size, gfp); diff --git a/include/linux/jbd2.h b/include/linux/jbd2.h index 971f3e826e15..ac31c37816f7 100644 --- a/include/linux/jbd2.h +++ b/include/linux/jbd2.h @@ -1696,7 +1696,7 @@ static inline void jbd2_journal_abort_handle(handle_t *handle) static inline void jbd2_init_fs_dev_write_error(journal_t *journal) { - struct address_space *mapping = journal->j_fs_dev->bd_inode->i_mapping; + struct address_space *mapping = journal->j_fs_dev->bd_mapping; /* * Save the original wb_err value of client fs's bdev mapping which @@ -1707,7 +1707,7 @@ static inline void jbd2_init_fs_dev_write_error(journal_t *journal) static inline int jbd2_check_fs_dev_write_error(journal_t *journal) { - struct address_space *mapping = journal->j_fs_dev->bd_inode->i_mapping; + struct address_space *mapping = journal->j_fs_dev->bd_mapping; return errseq_check(&mapping->wb_err, READ_ONCE(journal->j_fs_dev_wb_err)); -- cgit v1.2.3-59-g8ed1b From 22f89a4f8c049b884c320bc7477397916ee97b63 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 11 Apr 2024 15:53:38 +0100 Subject: grow_dev_folio(): we only want ->bd_inode->i_mapping there Signed-off-by: Al Viro Link: https://lore.kernel.org/r/20240411145346.2516848-3-viro@zeniv.linux.org.uk Reviewed-by: Matthew Wilcox (Oracle) Signed-off-by: Christian Brauner --- fs/buffer.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fs/buffer.c b/fs/buffer.c index d5a0932ae68d..78a4e95ba2f2 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -1034,12 +1034,12 @@ static sector_t folio_init_buffers(struct folio *folio, static bool grow_dev_folio(struct block_device *bdev, sector_t block, pgoff_t index, unsigned size, gfp_t gfp) { - struct inode *inode = bdev->bd_inode; + struct address_space *mapping = bdev->bd_mapping; struct folio *folio; struct buffer_head *bh; sector_t end_block = 0; - folio = __filemap_get_folio(inode->i_mapping, index, + folio = __filemap_get_folio(mapping, index, FGP_LOCK | FGP_ACCESSED | FGP_CREAT, gfp); if (IS_ERR(folio)) return false; @@ -1073,10 +1073,10 @@ static bool grow_dev_folio(struct block_device *bdev, sector_t block, * lock to be atomic wrt __find_get_block(), which does not * run under the folio lock. */ - spin_lock(&inode->i_mapping->i_private_lock); + spin_lock(&mapping->i_private_lock); link_dev_buffers(folio, bh); end_block = folio_init_buffers(folio, bdev, size); - spin_unlock(&inode->i_mapping->i_private_lock); + spin_unlock(&mapping->i_private_lock); unlock: folio_unlock(folio); folio_put(folio); -- cgit v1.2.3-59-g8ed1b From 881494ed031f60d48041549368989a37405a7e50 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 11 Apr 2024 15:53:41 +0100 Subject: blk_ioctl_{discard,zeroout}(): we only want ->bd_inode->i_mapping here... Signed-off-by: Al Viro Link: https://lore.kernel.org/r/20240411145346.2516848-6-viro@zeniv.linux.org.uk Signed-off-by: Christian Brauner --- block/ioctl.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/block/ioctl.c b/block/ioctl.c index 7c13d8bed453..831d6350ca25 100644 --- a/block/ioctl.c +++ b/block/ioctl.c @@ -97,7 +97,6 @@ static int blk_ioctl_discard(struct block_device *bdev, blk_mode_t mode, { uint64_t range[2]; uint64_t start, len, end; - struct inode *inode = bdev->bd_inode; int err; if (!(mode & BLK_OPEN_WRITE)) @@ -121,13 +120,13 @@ static int blk_ioctl_discard(struct block_device *bdev, blk_mode_t mode, end > bdev_nr_bytes(bdev)) return -EINVAL; - filemap_invalidate_lock(inode->i_mapping); + filemap_invalidate_lock(bdev->bd_mapping); err = truncate_bdev_range(bdev, mode, start, start + len - 1); if (err) goto fail; err = blkdev_issue_discard(bdev, start >> 9, len >> 9, GFP_KERNEL); fail: - filemap_invalidate_unlock(inode->i_mapping); + filemap_invalidate_unlock(bdev->bd_mapping); return err; } @@ -167,7 +166,6 @@ static int blk_ioctl_zeroout(struct block_device *bdev, blk_mode_t mode, { uint64_t range[2]; uint64_t start, end, len; - struct inode *inode = bdev->bd_inode; int err; if (!(mode & BLK_OPEN_WRITE)) @@ -190,7 +188,7 @@ static int blk_ioctl_zeroout(struct block_device *bdev, blk_mode_t mode, return -EINVAL; /* Invalidate the page cache, including dirty pages */ - filemap_invalidate_lock(inode->i_mapping); + filemap_invalidate_lock(bdev->bd_mapping); err = truncate_bdev_range(bdev, mode, start, end); if (err) goto fail; @@ -199,7 +197,7 @@ static int blk_ioctl_zeroout(struct block_device *bdev, blk_mode_t mode, BLKDEV_ZERO_NOUNMAP); fail: - filemap_invalidate_unlock(inode->i_mapping); + filemap_invalidate_unlock(bdev->bd_mapping); return err; } -- cgit v1.2.3-59-g8ed1b From 53cd4cd3b12d8a62719bef950f298a2bc5a6b415 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 28 Apr 2024 19:41:13 -0400 Subject: fs/buffer.c: massage the remaining users of ->bd_inode to ->bd_mapping both for ->i_blkbits and both want the address_space in question anyway. Signed-off-by: Al Viro --- fs/buffer.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/fs/buffer.c b/fs/buffer.c index 78a4e95ba2f2..ac29e0f221bc 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -189,8 +189,8 @@ EXPORT_SYMBOL(end_buffer_write_sync); static struct buffer_head * __find_get_block_slow(struct block_device *bdev, sector_t block) { - struct inode *bd_inode = bdev->bd_inode; - struct address_space *bd_mapping = bd_inode->i_mapping; + struct address_space *bd_mapping = bdev->bd_mapping; + const int blkbits = bd_mapping->host->i_blkbits; struct buffer_head *ret = NULL; pgoff_t index; struct buffer_head *bh; @@ -199,7 +199,7 @@ __find_get_block_slow(struct block_device *bdev, sector_t block) int all_mapped = 1; static DEFINE_RATELIMIT_STATE(last_warned, HZ, 1); - index = ((loff_t)block << bd_inode->i_blkbits) / PAGE_SIZE; + index = ((loff_t)block << blkbits) / PAGE_SIZE; folio = __filemap_get_folio(bd_mapping, index, FGP_ACCESSED, 0); if (IS_ERR(folio)) goto out; @@ -233,7 +233,7 @@ __find_get_block_slow(struct block_device *bdev, sector_t block) (unsigned long long)block, (unsigned long long)bh->b_blocknr, bh->b_state, bh->b_size, bdev, - 1 << bd_inode->i_blkbits); + 1 << blkbits); } out_unlock: spin_unlock(&bd_mapping->i_private_lock); @@ -1696,16 +1696,16 @@ EXPORT_SYMBOL(create_empty_buffers); */ void clean_bdev_aliases(struct block_device *bdev, sector_t block, sector_t len) { - struct inode *bd_inode = bdev->bd_inode; - struct address_space *bd_mapping = bd_inode->i_mapping; + struct address_space *bd_mapping = bdev->bd_mapping; + const int blkbits = bd_mapping->host->i_blkbits; struct folio_batch fbatch; - pgoff_t index = ((loff_t)block << bd_inode->i_blkbits) / PAGE_SIZE; + pgoff_t index = ((loff_t)block << blkbits) / PAGE_SIZE; pgoff_t end; int i, count; struct buffer_head *bh; struct buffer_head *head; - end = ((loff_t)(block + len - 1) << bd_inode->i_blkbits) / PAGE_SIZE; + end = ((loff_t)(block + len - 1) << blkbits) / PAGE_SIZE; folio_batch_init(&fbatch); while (filemap_get_folios(bd_mapping, &index, end, &fbatch)) { count = folio_batch_count(&fbatch); -- cgit v1.2.3-59-g8ed1b From 2d0026a4901be98000137af41bb42b6ead5a4c27 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 11 Apr 2024 15:53:39 +0100 Subject: gfs2: more obvious initializations of mapping->host what's going on is copying the ->host of bdev's address_space Signed-off-by: Al Viro Link: https://lore.kernel.org/r/20240411145346.2516848-4-viro@zeniv.linux.org.uk Signed-off-by: Christian Brauner --- fs/gfs2/glock.c | 2 +- fs/gfs2/ops_fstype.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 34540f9d011c..1ebcf6c90f2b 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -1227,7 +1227,7 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number, mapping = gfs2_glock2aspace(gl); if (mapping) { mapping->a_ops = &gfs2_meta_aops; - mapping->host = s->s_bdev->bd_inode; + mapping->host = s->s_bdev->bd_mapping->host; mapping->flags = 0; mapping_set_gfp_mask(mapping, GFP_NOFS); mapping->i_private_data = NULL; diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index 572d58e86296..fcf7dfd14f52 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -114,7 +114,7 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb) address_space_init_once(mapping); mapping->a_ops = &gfs2_rgrp_aops; - mapping->host = sb->s_bdev->bd_inode; + mapping->host = sb->s_bdev->bd_mapping->host; mapping->flags = 0; mapping_set_gfp_mask(mapping, GFP_NOFS); mapping->i_private_data = NULL; -- cgit v1.2.3-59-g8ed1b From df65f1660b6141f0b051d2439cc99222a6ae865b Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 28 Apr 2024 19:09:12 -0400 Subject: block/bdev.c: use the knowledge of inode/bdev coallocation Here we know that bdevfs inodes are coallocated with struct block_device and we can get to ->bd_inode value without any dereferencing. Introduce an inlined helper (static, *not* exported, purely internal for bdev.c) that gets an associated inode by block_device - BD_INODE(bdev). NOTE: leave it static; nobody outside of block/bdev.c has any business playing with that. Signed-off-by: Al Viro --- block/bdev.c | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/block/bdev.c b/block/bdev.c index 00017af92a51..a8c66cc1d6b8 100644 --- a/block/bdev.c +++ b/block/bdev.c @@ -43,6 +43,11 @@ static inline struct bdev_inode *BDEV_I(struct inode *inode) return container_of(inode, struct bdev_inode, vfs_inode); } +static inline struct inode *BD_INODE(struct block_device *bdev) +{ + return &container_of(bdev, struct bdev_inode, bdev)->vfs_inode; +} + struct block_device *I_BDEV(struct inode *inode) { return &BDEV_I(inode)->bdev; @@ -57,7 +62,7 @@ EXPORT_SYMBOL(file_bdev); static void bdev_write_inode(struct block_device *bdev) { - struct inode *inode = bdev->bd_inode; + struct inode *inode = BD_INODE(bdev); int ret; spin_lock(&inode->i_lock); @@ -134,14 +139,14 @@ invalidate: static void set_init_blocksize(struct block_device *bdev) { unsigned int bsize = bdev_logical_block_size(bdev); - loff_t size = i_size_read(bdev->bd_inode); + loff_t size = i_size_read(BD_INODE(bdev)); while (bsize < PAGE_SIZE) { if (size & bsize) break; bsize <<= 1; } - bdev->bd_inode->i_blkbits = blksize_bits(bsize); + BD_INODE(bdev)->i_blkbits = blksize_bits(bsize); } int set_blocksize(struct file *file, int size) @@ -437,29 +442,30 @@ struct block_device *bdev_alloc(struct gendisk *disk, u8 partno) void bdev_set_nr_sectors(struct block_device *bdev, sector_t sectors) { spin_lock(&bdev->bd_size_lock); - i_size_write(bdev->bd_inode, (loff_t)sectors << SECTOR_SHIFT); + i_size_write(BD_INODE(bdev), (loff_t)sectors << SECTOR_SHIFT); bdev->bd_nr_sectors = sectors; spin_unlock(&bdev->bd_size_lock); } void bdev_add(struct block_device *bdev, dev_t dev) { + struct inode *inode = BD_INODE(bdev); if (bdev_stable_writes(bdev)) mapping_set_stable_writes(bdev->bd_mapping); bdev->bd_dev = dev; - bdev->bd_inode->i_rdev = dev; - bdev->bd_inode->i_ino = dev; - insert_inode_hash(bdev->bd_inode); + inode->i_rdev = dev; + inode->i_ino = dev; + insert_inode_hash(inode); } void bdev_unhash(struct block_device *bdev) { - remove_inode_hash(bdev->bd_inode); + remove_inode_hash(BD_INODE(bdev)); } void bdev_drop(struct block_device *bdev) { - iput(bdev->bd_inode); + iput(BD_INODE(bdev)); } long nr_blockdev_pages(void) @@ -987,13 +993,13 @@ struct file *bdev_file_open_by_dev(dev_t dev, blk_mode_t mode, void *holder, return ERR_PTR(-ENXIO); flags = blk_to_file_flags(mode); - bdev_file = alloc_file_pseudo_noaccount(bdev->bd_inode, + bdev_file = alloc_file_pseudo_noaccount(BD_INODE(bdev), blockdev_mnt, "", flags | O_LARGEFILE, &def_blk_fops); if (IS_ERR(bdev_file)) { blkdev_put_no_open(bdev); return bdev_file; } - ihold(bdev->bd_inode); + ihold(BD_INODE(bdev)); ret = bdev_open(bdev, mode, holder, hops, bdev_file); if (ret) { @@ -1270,13 +1276,13 @@ void bdev_statx_dioalign(struct inode *inode, struct kstat *stat) bool disk_live(struct gendisk *disk) { - return !inode_unhashed(disk->part0->bd_inode); + return !inode_unhashed(BD_INODE(disk->part0)); } EXPORT_SYMBOL_GPL(disk_live); unsigned int block_size(struct block_device *bdev) { - return 1 << bdev->bd_inode->i_blkbits; + return 1 << BD_INODE(bdev)->i_blkbits; } EXPORT_SYMBOL_GPL(block_size); -- cgit v1.2.3-59-g8ed1b From 338618338233a8567f48f70b228abca626ffb3ed Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 28 Apr 2024 20:39:55 -0400 Subject: nilfs_attach_log_writer(): use ->bd_mapping->host instead of ->bd_inode I suspect that inode_attach_wb() use is rather unidiomatic, but that's a separate story - in any case, its use is a few times per mount *and* the route by which we access that inode is "the host of address_space a page belongs to". Signed-off-by: Al Viro --- fs/nilfs2/segment.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/nilfs2/segment.c b/fs/nilfs2/segment.c index aa5290cb7467..15188e799580 100644 --- a/fs/nilfs2/segment.c +++ b/fs/nilfs2/segment.c @@ -2790,7 +2790,7 @@ int nilfs_attach_log_writer(struct super_block *sb, struct nilfs_root *root) if (!nilfs->ns_writer) return -ENOMEM; - inode_attach_wb(nilfs->ns_bdev->bd_inode, NULL); + inode_attach_wb(nilfs->ns_bdev->bd_mapping->host, NULL); err = nilfs_segctor_start_thread(nilfs->ns_writer); if (unlikely(err)) -- cgit v1.2.3-59-g8ed1b From 463b3162c96dd5986adb5790ed889c785fefeede Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 28 Apr 2024 20:43:56 -0400 Subject: dasd_format(): killing the last remaining user of ->bd_inode What happens here is almost certainly wrong. However, * it's the last remaining user of ->bd_inode anywhere in the tree * it is *NOT* a fast path by any stretch of imagination Signed-off-by: Al Viro --- drivers/s390/block/dasd_ioctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c index 7e0ed7032f76..eb5dcbe37230 100644 --- a/drivers/s390/block/dasd_ioctl.c +++ b/drivers/s390/block/dasd_ioctl.c @@ -215,7 +215,7 @@ dasd_format(struct dasd_block *block, struct format_data_t *fdata) * enabling the device later. */ if (fdata->start_unit == 0) { - block->gdp->part0->bd_inode->i_blkbits = + block->gdp->part0->bd_mapping->host->i_blkbits = blksize_bits(fdata->blksize); } -- cgit v1.2.3-59-g8ed1b From 203c1ce0bb063d1620698e39637b64f2d09c1368 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 28 Apr 2024 20:47:14 -0400 Subject: RIP ->bd_inode Signed-off-by: Al Viro --- block/bdev.c | 1 - include/linux/blk_types.h | 1 - 2 files changed, 2 deletions(-) diff --git a/block/bdev.c b/block/bdev.c index a8c66cc1d6b8..0849a9cfa2b6 100644 --- a/block/bdev.c +++ b/block/bdev.c @@ -423,7 +423,6 @@ struct block_device *bdev_alloc(struct gendisk *disk, u8 partno) spin_lock_init(&bdev->bd_size_lock); mutex_init(&bdev->bd_holder_lock); bdev->bd_partno = partno; - bdev->bd_inode = inode; bdev->bd_mapping = &inode->i_data; bdev->bd_queue = disk->queue; if (partno) diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h index 6438c75cbb35..5616d059cb23 100644 --- a/include/linux/blk_types.h +++ b/include/linux/blk_types.h @@ -50,7 +50,6 @@ struct block_device { bool bd_write_holder; bool bd_has_submit_bio; dev_t bd_dev; - struct inode *bd_inode; /* will die */ struct address_space *bd_mapping; /* page cache */ atomic_t bd_openers; -- cgit v1.2.3-59-g8ed1b From 06dfb41b1cf8d64327e5c4391e165f466506c4f0 Mon Sep 17 00:00:00 2001 From: Alex Bee Date: Tue, 16 Apr 2024 18:12:33 +0200 Subject: dt-bindings: mfd: Add rk816 binding Add DT binding document for Rockchip's RK816 PMIC Signed-off-by: Alex Bee Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240416161237.2500037-2-knaerzche@gmail.com Signed-off-by: Lee Jones --- .../devicetree/bindings/mfd/rockchip,rk816.yaml | 274 +++++++++++++++++++++ 1 file changed, 274 insertions(+) create mode 100644 Documentation/devicetree/bindings/mfd/rockchip,rk816.yaml diff --git a/Documentation/devicetree/bindings/mfd/rockchip,rk816.yaml b/Documentation/devicetree/bindings/mfd/rockchip,rk816.yaml new file mode 100644 index 000000000000..0676890f101e --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/rockchip,rk816.yaml @@ -0,0 +1,274 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/mfd/rockchip,rk816.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: RK816 Power Management Integrated Circuit + +maintainers: + - Chris Zhong + - Zhang Qing + +description: + Rockchip RK816 series PMIC. This device consists of an i2c controlled MFD + that includes regulators, a RTC, a GPIO controller, a power button, and a + battery charger manager with fuel gauge. + +properties: + compatible: + enum: + - rockchip,rk816 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + '#clock-cells': + description: + See for clock IDs. + const: 1 + + clock-output-names: + maxItems: 2 + + gpio-controller: true + + '#gpio-cells': + const: 2 + + system-power-controller: + type: boolean + description: + Telling whether or not this PMIC is controlling the system power. + + wakeup-source: + type: boolean + + vcc1-supply: + description: + The input supply for dcdc1. + + vcc2-supply: + description: + The input supply for dcdc2. + + vcc3-supply: + description: + The input supply for dcdc3. + + vcc4-supply: + description: + The input supply for dcdc4. + + vcc5-supply: + description: + The input supply for ldo1, ldo2, and ldo3. + + vcc6-supply: + description: + The input supply for ldo4, ldo5, and ldo6. + + vcc7-supply: + description: + The input supply for boost. + + vcc8-supply: + description: + The input supply for otg-switch. + + regulators: + type: object + patternProperties: + '^(boost|dcdc[1-4]|ldo[1-6]|otg-switch)$': + type: object + $ref: /schemas/regulator/regulator.yaml# + unevaluatedProperties: false + additionalProperties: false + +patternProperties: + '-pins$': + type: object + additionalProperties: false + $ref: /schemas/pinctrl/pinmux-node.yaml + + properties: + function: + enum: [gpio, thermistor] + + pins: + $ref: /schemas/types.yaml#/definitions/string + const: gpio0 + +required: + - compatible + - reg + - interrupts + - '#clock-cells' + +additionalProperties: false + +examples: + - | + #include + #include + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + rk816: pmic@1a { + compatible = "rockchip,rk816"; + reg = <0x1a>; + interrupt-parent = <&gpio0>; + interrupts = ; + clock-output-names = "xin32k", "rk816-clkout2"; + pinctrl-names = "default"; + pinctrl-0 = <&pmic_int_l>; + gpio-controller; + system-power-controller; + wakeup-source; + #clock-cells = <1>; + #gpio-cells = <2>; + + vcc1-supply = <&vcc_sys>; + vcc2-supply = <&vcc_sys>; + vcc3-supply = <&vcc_sys>; + vcc4-supply = <&vcc_sys>; + vcc5-supply = <&vcc33_io>; + vcc6-supply = <&vcc_sys>; + + regulators { + vdd_cpu: dcdc1 { + regulator-name = "vdd_cpu"; + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <1450000>; + regulator-ramp-delay = <6001>; + regulator-initial-mode = <1>; + regulator-always-on; + regulator-boot-on; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd_logic: dcdc2 { + regulator-name = "vdd_logic"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1250000>; + regulator-ramp-delay = <6001>; + regulator-initial-mode = <1>; + regulator-always-on; + regulator-boot-on; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1000000>; + }; + }; + + vcc_ddr: dcdc3 { + regulator-name = "vcc_ddr"; + regulator-initial-mode = <1>; + regulator-always-on; + regulator-boot-on; + + regulator-state-mem { + regulator-on-in-suspend; + }; + }; + + vcc33_io: dcdc4 { + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vcc33_io"; + regulator-initial-mode = <1>; + regulator-always-on; + regulator-boot-on; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <3300000>; + }; + }; + + vccio_pmu: ldo1 { + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vccio_pmu"; + regulator-always-on; + regulator-boot-on; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <3300000>; + }; + }; + + vcc_tp: ldo2 { + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vcc_tp"; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd_10: ldo3 { + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1000000>; + regulator-name = "vdd_10"; + regulator-always-on; + regulator-boot-on; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1000000>; + }; + }; + + vcc18_lcd: ldo4 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-name = "vcc18_lcd"; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1800000>; + }; + }; + + vccio_sd: ldo5 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vccio_sd"; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <3300000>; + }; + }; + + vdd10_lcd: ldo6 { + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1000000>; + regulator-name = "vdd10_lcd"; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1000000>; + }; + }; + }; + + rk816_gpio_pins: gpio-pins { + function = "gpio"; + pins = "gpio0"; + }; + }; + }; -- cgit v1.2.3-59-g8ed1b From e9006f81faf8e438ea83626db578610e49f31576 Mon Sep 17 00:00:00 2001 From: Alex Bee Date: Tue, 16 Apr 2024 18:12:34 +0200 Subject: mfd: rk8xx: Add RK816 support This integrates RK816 support in the this existing rk8xx mfd driver. This version has unaligned interrupt registers, which requires to define a separate get_irq_reg callback for the regmap. Apart from that the integration is straightforward and the existing structures can be used as is. The initialization sequence has been taken from vendor kernel. Signed-off-by: Alex Bee Link: https://lore.kernel.org/r/20240416161237.2500037-3-knaerzche@gmail.com Signed-off-by: Lee Jones --- drivers/mfd/Kconfig | 4 +- drivers/mfd/rk8xx-core.c | 104 +++++++++++++++++++++++++++++++++ drivers/mfd/rk8xx-i2c.c | 45 ++++++++++++++- include/linux/mfd/rk808.h | 144 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 294 insertions(+), 3 deletions(-) diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 4b023ee229cf..2e7286cc98e4 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -1225,7 +1225,7 @@ config MFD_RK8XX select MFD_CORE config MFD_RK8XX_I2C - tristate "Rockchip RK805/RK808/RK809/RK817/RK818 Power Management Chip" + tristate "Rockchip RK805/RK808/RK809/RK816/RK817/RK818 Power Management Chip" depends on I2C && OF select MFD_CORE select REGMAP_I2C @@ -1233,7 +1233,7 @@ config MFD_RK8XX_I2C select MFD_RK8XX help If you say yes here you get support for the RK805, RK808, RK809, - RK817 and RK818 Power Management chips. + RK816, RK817 and RK818 Power Management chips. This driver provides common support for accessing the device through I2C interface. The device supports multiple sub-devices including interrupts, RTC, LDO & DCDC regulators, and onkey. diff --git a/drivers/mfd/rk8xx-core.c b/drivers/mfd/rk8xx-core.c index e2261b68b844..5eda3c0dbbdf 100644 --- a/drivers/mfd/rk8xx-core.c +++ b/drivers/mfd/rk8xx-core.c @@ -28,6 +28,10 @@ static const struct resource rtc_resources[] = { DEFINE_RES_IRQ(RK808_IRQ_RTC_ALARM), }; +static const struct resource rk816_rtc_resources[] = { + DEFINE_RES_IRQ(RK816_IRQ_RTC_ALARM), +}; + static const struct resource rk817_rtc_resources[] = { DEFINE_RES_IRQ(RK817_IRQ_RTC_ALARM), }; @@ -87,6 +91,22 @@ static const struct mfd_cell rk808s[] = { }, }; +static const struct mfd_cell rk816s[] = { + { .name = "rk805-pinctrl", }, + { .name = "rk808-clkout", }, + { .name = "rk808-regulator", }, + { + .name = "rk805-pwrkey", + .num_resources = ARRAY_SIZE(rk805_key_resources), + .resources = rk805_key_resources, + }, + { + .name = "rk808-rtc", + .num_resources = ARRAY_SIZE(rk816_rtc_resources), + .resources = rk816_rtc_resources, + }, +}; + static const struct mfd_cell rk817s[] = { { .name = "rk808-clkout", }, { .name = "rk808-regulator", }, @@ -148,6 +168,17 @@ static const struct rk808_reg_data rk808_pre_init_reg[] = { VB_LO_SEL_3500MV }, }; +static const struct rk808_reg_data rk816_pre_init_reg[] = { + { RK818_BUCK1_CONFIG_REG, RK817_RAMP_RATE_MASK, + RK817_RAMP_RATE_12_5MV_PER_US }, + { RK818_BUCK2_CONFIG_REG, RK817_RAMP_RATE_MASK, + RK817_RAMP_RATE_12_5MV_PER_US }, + { RK818_BUCK4_CONFIG_REG, BUCK_ILMIN_MASK, BUCK_ILMIN_250MA }, + { RK808_THERMAL_REG, TEMP_HOTDIE_MSK, TEMP105C}, + { RK808_VB_MON_REG, VBAT_LOW_VOL_MASK | VBAT_LOW_ACT_MASK, + RK808_VBAT_LOW_3V0 | EN_VABT_LOW_SHUT_DOWN }, +}; + static const struct rk808_reg_data rk817_pre_init_reg[] = { {RK817_RTC_CTRL_REG, RTC_STOP, RTC_STOP}, /* Codec specific registers */ @@ -350,6 +381,59 @@ static const struct regmap_irq rk808_irqs[] = { }, }; +static const unsigned int rk816_irq_status_offsets[] = { + RK816_IRQ_STS_OFFSET(RK816_INT_STS_REG1), + RK816_IRQ_STS_OFFSET(RK816_INT_STS_REG2), + RK816_IRQ_STS_OFFSET(RK816_INT_STS_REG3), +}; + +static const unsigned int rk816_irq_mask_offsets[] = { + RK816_IRQ_MSK_OFFSET(RK816_INT_STS_MSK_REG1), + RK816_IRQ_MSK_OFFSET(RK816_INT_STS_MSK_REG2), + RK816_IRQ_MSK_OFFSET(RK816_INT_STS_MSK_REG3), +}; + +static unsigned int rk816_get_irq_reg(struct regmap_irq_chip_data *data, + unsigned int base, int index) +{ + unsigned int irq_reg = base; + + switch (base) { + case RK816_INT_STS_REG1: + irq_reg += rk816_irq_status_offsets[index]; + break; + case RK816_INT_STS_MSK_REG1: + irq_reg += rk816_irq_mask_offsets[index]; + break; + } + + return irq_reg; +}; + +static const struct regmap_irq rk816_irqs[] = { + /* INT_STS_REG1 IRQs */ + REGMAP_IRQ_REG(RK816_IRQ_PWRON_FALL, 0, RK816_INT_STS_PWRON_FALL), + REGMAP_IRQ_REG(RK816_IRQ_PWRON_RISE, 0, RK816_INT_STS_PWRON_RISE), + + /* INT_STS_REG2 IRQs */ + REGMAP_IRQ_REG(RK816_IRQ_VB_LOW, 1, RK816_INT_STS_VB_LOW), + REGMAP_IRQ_REG(RK816_IRQ_PWRON, 1, RK816_INT_STS_PWRON), + REGMAP_IRQ_REG(RK816_IRQ_PWRON_LP, 1, RK816_INT_STS_PWRON_LP), + REGMAP_IRQ_REG(RK816_IRQ_HOTDIE, 1, RK816_INT_STS_HOTDIE), + REGMAP_IRQ_REG(RK816_IRQ_RTC_ALARM, 1, RK816_INT_STS_RTC_ALARM), + REGMAP_IRQ_REG(RK816_IRQ_RTC_PERIOD, 1, RK816_INT_STS_RTC_PERIOD), + REGMAP_IRQ_REG(RK816_IRQ_USB_OV, 1, RK816_INT_STS_USB_OV), + + /* INT_STS3 IRQs */ + REGMAP_IRQ_REG(RK816_IRQ_PLUG_IN, 2, RK816_INT_STS_PLUG_IN), + REGMAP_IRQ_REG(RK816_IRQ_PLUG_OUT, 2, RK816_INT_STS_PLUG_OUT), + REGMAP_IRQ_REG(RK816_IRQ_CHG_OK, 2, RK816_INT_STS_CHG_OK), + REGMAP_IRQ_REG(RK816_IRQ_CHG_TE, 2, RK816_INT_STS_CHG_TE), + REGMAP_IRQ_REG(RK816_IRQ_CHG_TS, 2, RK816_INT_STS_CHG_TS), + REGMAP_IRQ_REG(RK816_IRQ_CHG_CVTLIM, 2, RK816_INT_STS_CHG_CVTLIM), + REGMAP_IRQ_REG(RK816_IRQ_DISCHG_ILIM, 2, RK816_INT_STS_DISCHG_ILIM), +}; + static const struct regmap_irq rk818_irqs[] = { /* INT_STS */ [RK818_IRQ_VOUT_LO] = { @@ -482,6 +566,18 @@ static const struct regmap_irq_chip rk808_irq_chip = { .init_ack_masked = true, }; +static const struct regmap_irq_chip rk816_irq_chip = { + .name = "rk816", + .irqs = rk816_irqs, + .num_irqs = ARRAY_SIZE(rk816_irqs), + .num_regs = 3, + .get_irq_reg = rk816_get_irq_reg, + .status_base = RK816_INT_STS_REG1, + .mask_base = RK816_INT_STS_MSK_REG1, + .ack_base = RK816_INT_STS_REG1, + .init_ack_masked = true, +}; + static struct regmap_irq_chip rk817_irq_chip = { .name = "rk817", .irqs = rk817_irqs, @@ -530,6 +626,7 @@ static int rk808_power_off(struct sys_off_data *data) reg = RK817_SYS_CFG(3); bit = DEV_OFF; break; + case RK816_ID: case RK818_ID: reg = RK818_DEVCTRL_REG; bit = DEV_OFF; @@ -637,6 +734,13 @@ int rk8xx_probe(struct device *dev, int variant, unsigned int irq, struct regmap cells = rk808s; nr_cells = ARRAY_SIZE(rk808s); break; + case RK816_ID: + rk808->regmap_irq_chip = &rk816_irq_chip; + pre_init_reg = rk816_pre_init_reg; + nr_pre_init_regs = ARRAY_SIZE(rk816_pre_init_reg); + cells = rk816s; + nr_cells = ARRAY_SIZE(rk816s); + break; case RK818_ID: rk808->regmap_irq_chip = &rk818_irq_chip; pre_init_reg = rk818_pre_init_reg; diff --git a/drivers/mfd/rk8xx-i2c.c b/drivers/mfd/rk8xx-i2c.c index 75b5cf09d5a0..69a6b297d723 100644 --- a/drivers/mfd/rk8xx-i2c.c +++ b/drivers/mfd/rk8xx-i2c.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Rockchip RK808/RK818 Core (I2C) driver + * Rockchip RK805/RK808/RK816/RK817/RK818 Core (I2C) driver * * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd * Copyright (C) 2016 PHYTEC Messtechnik GmbH @@ -49,6 +49,35 @@ static bool rk808_is_volatile_reg(struct device *dev, unsigned int reg) return false; } +static bool rk816_is_volatile_reg(struct device *dev, unsigned int reg) +{ + /* + * Technically the ROUND_30s bit makes RTC_CTRL_REG volatile, but + * we don't use that feature. It's better to cache. + */ + + switch (reg) { + case RK808_SECONDS_REG ... RK808_WEEKS_REG: + case RK808_RTC_STATUS_REG: + case RK808_VB_MON_REG: + case RK808_THERMAL_REG: + case RK816_DCDC_EN_REG1: + case RK816_DCDC_EN_REG2: + case RK816_INT_STS_REG1: + case RK816_INT_STS_REG2: + case RK816_INT_STS_REG3: + case RK808_DEVCTRL_REG: + case RK816_SUP_STS_REG: + case RK816_GGSTS_REG: + case RK816_ZERO_CUR_ADC_REGH: + case RK816_ZERO_CUR_ADC_REGL: + case RK816_GASCNT_REG(0) ... RK816_BAT_VOL_REGL: + return true; + } + + return false; +} + static bool rk817_is_volatile_reg(struct device *dev, unsigned int reg) { /* @@ -100,6 +129,14 @@ static const struct regmap_config rk808_regmap_config = { .volatile_reg = rk808_is_volatile_reg, }; +static const struct regmap_config rk816_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = RK816_DATA_REG(18), + .cache_type = REGCACHE_MAPLE, + .volatile_reg = rk816_is_volatile_reg, +}; + static const struct regmap_config rk817_regmap_config = { .reg_bits = 8, .val_bits = 8, @@ -123,6 +160,11 @@ static const struct rk8xx_i2c_platform_data rk809_data = { .variant = RK809_ID, }; +static const struct rk8xx_i2c_platform_data rk816_data = { + .regmap_cfg = &rk816_regmap_config, + .variant = RK816_ID, +}; + static const struct rk8xx_i2c_platform_data rk817_data = { .regmap_cfg = &rk817_regmap_config, .variant = RK817_ID, @@ -161,6 +203,7 @@ static const struct of_device_id rk8xx_i2c_of_match[] = { { .compatible = "rockchip,rk805", .data = &rk805_data }, { .compatible = "rockchip,rk808", .data = &rk808_data }, { .compatible = "rockchip,rk809", .data = &rk809_data }, + { .compatible = "rockchip,rk816", .data = &rk816_data }, { .compatible = "rockchip,rk817", .data = &rk817_data }, { .compatible = "rockchip,rk818", .data = &rk818_data }, { }, diff --git a/include/linux/mfd/rk808.h b/include/linux/mfd/rk808.h index 78e167a92483..69cbea78b430 100644 --- a/include/linux/mfd/rk808.h +++ b/include/linux/mfd/rk808.h @@ -113,6 +113,148 @@ enum rk808_reg { #define RK808_INT_STS_MSK_REG2 0x4f #define RK808_IO_POL_REG 0x50 +/* RK816 */ +enum rk816_reg { + RK816_ID_DCDC1, + RK816_ID_DCDC2, + RK816_ID_DCDC3, + RK816_ID_DCDC4, + RK816_ID_LDO1, + RK816_ID_LDO2, + RK816_ID_LDO3, + RK816_ID_LDO4, + RK816_ID_LDO5, + RK816_ID_LDO6, + RK816_ID_BOOST, + RK816_ID_OTG_SW, +}; + +enum rk816_irqs { + /* INT_STS_REG1 */ + RK816_IRQ_PWRON_FALL, + RK816_IRQ_PWRON_RISE, + + /* INT_STS_REG2 */ + RK816_IRQ_VB_LOW, + RK816_IRQ_PWRON, + RK816_IRQ_PWRON_LP, + RK816_IRQ_HOTDIE, + RK816_IRQ_RTC_ALARM, + RK816_IRQ_RTC_PERIOD, + RK816_IRQ_USB_OV, + + /* INT_STS_REG3 */ + RK816_IRQ_PLUG_IN, + RK816_IRQ_PLUG_OUT, + RK816_IRQ_CHG_OK, + RK816_IRQ_CHG_TE, + RK816_IRQ_CHG_TS, + RK816_IRQ_CHG_CVTLIM, + RK816_IRQ_DISCHG_ILIM, +}; + +/* power channel registers */ +#define RK816_DCDC_EN_REG1 0x23 + +#define RK816_DCDC_EN_REG2 0x24 +#define RK816_BOOST_EN BIT(1) +#define RK816_OTG_EN BIT(2) +#define RK816_BOOST_EN_MSK BIT(5) +#define RK816_OTG_EN_MSK BIT(6) +#define RK816_BUCK_DVS_CONFIRM BIT(7) + +#define RK816_LDO_EN_REG1 0x27 + +#define RK816_LDO_EN_REG2 0x28 + +/* interrupt registers and irq definitions */ +#define RK816_INT_STS_REG1 0x49 +#define RK816_INT_STS_MSK_REG1 0x4a +#define RK816_INT_STS_PWRON_FALL BIT(5) +#define RK816_INT_STS_PWRON_RISE BIT(6) + +#define RK816_INT_STS_REG2 0x4c +#define RK816_INT_STS_MSK_REG2 0x4d +#define RK816_INT_STS_VB_LOW BIT(1) +#define RK816_INT_STS_PWRON BIT(2) +#define RK816_INT_STS_PWRON_LP BIT(3) +#define RK816_INT_STS_HOTDIE BIT(4) +#define RK816_INT_STS_RTC_ALARM BIT(5) +#define RK816_INT_STS_RTC_PERIOD BIT(6) +#define RK816_INT_STS_USB_OV BIT(7) + +#define RK816_INT_STS_REG3 0x4e +#define RK816_INT_STS_MSK_REG3 0x4f +#define RK816_INT_STS_PLUG_IN BIT(0) +#define RK816_INT_STS_PLUG_OUT BIT(1) +#define RK816_INT_STS_CHG_OK BIT(2) +#define RK816_INT_STS_CHG_TE BIT(3) +#define RK816_INT_STS_CHG_TS BIT(4) +#define RK816_INT_STS_CHG_CVTLIM BIT(6) +#define RK816_INT_STS_DISCHG_ILIM BIT(7) + +#define RK816_IRQ_STS_OFFSET(x) ((x) - RK816_INT_STS_REG1) +#define RK816_IRQ_MSK_OFFSET(x) ((x) - RK816_INT_STS_MSK_REG1) + +/* charger, boost and OTG registers */ +#define RK816_OTG_BUCK_LDO_CONFIG_REG 0x2a +#define RK816_CHRG_CONFIG_REG 0x2b +#define RK816_BOOST_ON_VESL_REG 0x54 +#define RK816_BOOST_SLP_VSEL_REG 0x55 +#define RK816_CHRG_BOOST_CONFIG_REG 0x9a +#define RK816_SUP_STS_REG 0xa0 +#define RK816_USB_CTRL_REG 0xa1 +#define RK816_CHRG_CTRL(x) (0xa3 + (x)) +#define RK816_BAT_CTRL_REG 0xa6 +#define RK816_BAT_HTS_TS_REG 0xa8 +#define RK816_BAT_LTS_TS_REG 0xa9 + +/* adc and fuel gauge registers */ +#define RK816_TS_CTRL_REG 0xac +#define RK816_ADC_CTRL_REG 0xad +#define RK816_GGCON_REG 0xb0 +#define RK816_GGSTS_REG 0xb1 +#define RK816_ZERO_CUR_ADC_REGH 0xb2 +#define RK816_ZERO_CUR_ADC_REGL 0xb3 +#define RK816_GASCNT_CAL_REG(x) (0xb7 - (x)) +#define RK816_GASCNT_REG(x) (0xbb - (x)) +#define RK816_BAT_CUR_AVG_REGH 0xbc +#define RK816_BAT_CUR_AVG_REGL 0xbd +#define RK816_TS_ADC_REGH 0xbe +#define RK816_TS_ADC_REGL 0xbf +#define RK816_USB_ADC_REGH 0xc0 +#define RK816_USB_ADC_REGL 0xc1 +#define RK816_BAT_OCV_REGH 0xc2 +#define RK816_BAT_OCV_REGL 0xc3 +#define RK816_BAT_VOL_REGH 0xc4 +#define RK816_BAT_VOL_REGL 0xc5 +#define RK816_RELAX_ENTRY_THRES_REGH 0xc6 +#define RK816_RELAX_ENTRY_THRES_REGL 0xc7 +#define RK816_RELAX_EXIT_THRES_REGH 0xc8 +#define RK816_RELAX_EXIT_THRES_REGL 0xc9 +#define RK816_RELAX_VOL1_REGH 0xca +#define RK816_RELAX_VOL1_REGL 0xcb +#define RK816_RELAX_VOL2_REGH 0xcc +#define RK816_RELAX_VOL2_REGL 0xcd +#define RK816_RELAX_CUR1_REGH 0xce +#define RK816_RELAX_CUR1_REGL 0xcf +#define RK816_RELAX_CUR2_REGH 0xd0 +#define RK816_RELAX_CUR2_REGL 0xd1 +#define RK816_CAL_OFFSET_REGH 0xd2 +#define RK816_CAL_OFFSET_REGL 0xd3 +#define RK816_NON_ACT_TIMER_CNT_REG 0xd4 +#define RK816_VCALIB0_REGH 0xd5 +#define RK816_VCALIB0_REGL 0xd6 +#define RK816_VCALIB1_REGH 0xd7 +#define RK816_VCALIB1_REGL 0xd8 +#define RK816_FCC_GASCNT_REG(x) (0xdc - (x)) +#define RK816_IOFFSET_REGH 0xdd +#define RK816_IOFFSET_REGL 0xde +#define RK816_SLEEP_CON_SAMP_CUR_REG 0xdf + +/* general purpose data registers 0xe0 ~ 0xf2 */ +#define RK816_DATA_REG(x) (0xe0 + (x)) + /* RK818 */ #define RK818_DCDC1 0 #define RK818_LDO1 4 @@ -791,6 +933,7 @@ enum rk806_dvs_mode { #define VOUT_LO_INT BIT(0) #define CLK32KOUT2_EN BIT(0) +#define TEMP105C 0x08 #define TEMP115C 0x0c #define TEMP_HOTDIE_MSK 0x0c #define SLP_SD_MSK (0x3 << 2) @@ -1191,6 +1334,7 @@ enum { RK806_ID = 0x8060, RK808_ID = 0x0000, RK809_ID = 0x8090, + RK816_ID = 0x8160, RK817_ID = 0x8170, RK818_ID = 0x8180, }; -- cgit v1.2.3-59-g8ed1b From 1bd97d64b5f0c01d03ecc9473ccfcf180dbbf54a Mon Sep 17 00:00:00 2001 From: Alex Bee Date: Tue, 16 Apr 2024 18:12:35 +0200 Subject: pinctrl: rk805: Add rk816 pinctrl support This adds support for RK816 to the exising rk805 pinctrl driver It has a single pin which can be configured as input from a thermistor (for instance in an attached battery) or as a gpio. Signed-off-by: Alex Bee Reviewed-by: Linus Walleij Link: https://lore.kernel.org/r/20240416161237.2500037-4-knaerzche@gmail.com Signed-off-by: Lee Jones --- drivers/pinctrl/pinctrl-rk805.c | 69 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/drivers/pinctrl/pinctrl-rk805.c b/drivers/pinctrl/pinctrl-rk805.c index 56d916f2cee6..c42f1bf93404 100644 --- a/drivers/pinctrl/pinctrl-rk805.c +++ b/drivers/pinctrl/pinctrl-rk805.c @@ -93,6 +93,11 @@ enum rk806_pinmux_option { RK806_PINMUX_FUN5, }; +enum rk816_pinmux_option { + RK816_PINMUX_THERMISTOR, + RK816_PINMUX_GPIO, +}; + enum { RK805_GPIO0, RK805_GPIO1, @@ -104,6 +109,10 @@ enum { RK806_GPIO_DVS3 }; +enum { + RK816_GPIO0, +}; + static const char *const rk805_gpio_groups[] = { "gpio0", "gpio1", @@ -115,6 +124,10 @@ static const char *const rk806_gpio_groups[] = { "gpio_pwrctrl3", }; +static const char *const rk816_gpio_groups[] = { + "gpio0", +}; + /* RK805: 2 output only GPIOs */ static const struct pinctrl_pin_desc rk805_pins_desc[] = { PINCTRL_PIN(RK805_GPIO0, "gpio0"), @@ -128,6 +141,11 @@ static const struct pinctrl_pin_desc rk806_pins_desc[] = { PINCTRL_PIN(RK806_GPIO_DVS3, "gpio_pwrctrl3"), }; +/* RK816 */ +static const struct pinctrl_pin_desc rk816_pins_desc[] = { + PINCTRL_PIN(RK816_GPIO0, "gpio0"), +}; + static const struct rk805_pin_function rk805_pin_functions[] = { { .name = "gpio", @@ -176,6 +194,21 @@ static const struct rk805_pin_function rk806_pin_functions[] = { }, }; +static const struct rk805_pin_function rk816_pin_functions[] = { + { + .name = "gpio", + .groups = rk816_gpio_groups, + .ngroups = ARRAY_SIZE(rk816_gpio_groups), + .mux_option = RK816_PINMUX_GPIO, + }, + { + .name = "thermistor", + .groups = rk816_gpio_groups, + .ngroups = ARRAY_SIZE(rk816_gpio_groups), + .mux_option = RK816_PINMUX_THERMISTOR, + }, +}; + static const struct rk805_pin_group rk805_pin_groups[] = { { .name = "gpio0", @@ -207,6 +240,14 @@ static const struct rk805_pin_group rk806_pin_groups[] = { } }; +static const struct rk805_pin_group rk816_pin_groups[] = { + { + .name = "gpio0", + .pins = { RK816_GPIO0 }, + .npins = 1, + }, +}; + #define RK805_GPIO0_VAL_MSK BIT(0) #define RK805_GPIO1_VAL_MSK BIT(1) @@ -255,6 +296,20 @@ static struct rk805_pin_config rk806_gpio_cfgs[] = { } }; +#define RK816_FUN_MASK BIT(2) +#define RK816_VAL_MASK BIT(3) +#define RK816_DIR_MASK BIT(4) + +static struct rk805_pin_config rk816_gpio_cfgs[] = { + { + .fun_reg = RK818_IO_POL_REG, + .fun_msk = RK816_FUN_MASK, + .reg = RK818_IO_POL_REG, + .val_msk = RK816_VAL_MASK, + .dir_msk = RK816_DIR_MASK, + }, +}; + /* generic gpio chip */ static int rk805_gpio_get(struct gpio_chip *chip, unsigned int offset) { @@ -439,6 +494,8 @@ static int rk805_pinctrl_gpio_request_enable(struct pinctrl_dev *pctldev, return _rk805_pinctrl_set_mux(pctldev, offset, RK805_PINMUX_GPIO); case RK806_ID: return _rk805_pinctrl_set_mux(pctldev, offset, RK806_PINMUX_FUN5); + case RK816_ID: + return _rk805_pinctrl_set_mux(pctldev, offset, RK816_PINMUX_GPIO); } return -ENOTSUPP; @@ -588,6 +645,18 @@ static int rk805_pinctrl_probe(struct platform_device *pdev) pci->pin_cfg = rk806_gpio_cfgs; pci->gpio_chip.ngpio = ARRAY_SIZE(rk806_gpio_cfgs); break; + case RK816_ID: + pci->pins = rk816_pins_desc; + pci->num_pins = ARRAY_SIZE(rk816_pins_desc); + pci->functions = rk816_pin_functions; + pci->num_functions = ARRAY_SIZE(rk816_pin_functions); + pci->groups = rk816_pin_groups; + pci->num_pin_groups = ARRAY_SIZE(rk816_pin_groups); + pci->pinctrl_desc.pins = rk816_pins_desc; + pci->pinctrl_desc.npins = ARRAY_SIZE(rk816_pins_desc); + pci->pin_cfg = rk816_gpio_cfgs; + pci->gpio_chip.ngpio = ARRAY_SIZE(rk816_gpio_cfgs); + break; default: dev_err(&pdev->dev, "unsupported RK805 ID %lu\n", pci->rk808->variant); -- cgit v1.2.3-59-g8ed1b From 9f4e899c286b5127e2443d50e37ee2112efbfa2c Mon Sep 17 00:00:00 2001 From: Alex Bee Date: Tue, 16 Apr 2024 18:12:36 +0200 Subject: regulator: rk808: Support apply_bit for rk808_set_suspend_voltage_range rk808_set_suspend_voltage_range currently does not account the existence of apply_bit/apply_reg. This adds support for those in same way it is done in regulator_set_voltage_sel_regmap and is required for the upcoming RK816 support Signed-off-by: Alex Bee Acked-by: Mark Brown Link: https://lore.kernel.org/r/20240416161237.2500037-5-knaerzche@gmail.com Signed-off-by: Lee Jones --- drivers/regulator/rk808-regulator.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/drivers/regulator/rk808-regulator.c b/drivers/regulator/rk808-regulator.c index d89ae7f16d7a..a6a563e402d0 100644 --- a/drivers/regulator/rk808-regulator.c +++ b/drivers/regulator/rk808-regulator.c @@ -534,15 +534,25 @@ static int rk808_set_suspend_voltage_range(struct regulator_dev *rdev, int uv) { unsigned int reg; int sel = regulator_map_voltage_linear_range(rdev, uv, uv); + int ret; if (sel < 0) return -EINVAL; reg = rdev->desc->vsel_reg + RK808_SLP_REG_OFFSET; - return regmap_update_bits(rdev->regmap, reg, - rdev->desc->vsel_mask, - sel); + ret = regmap_update_bits(rdev->regmap, reg, + rdev->desc->vsel_mask, + sel); + if (ret) + return ret; + + if (rdev->desc->apply_bit) + ret = regmap_update_bits(rdev->regmap, rdev->desc->apply_reg, + rdev->desc->apply_bit, + rdev->desc->apply_bit); + + return ret; } static int rk805_set_suspend_enable(struct regulator_dev *rdev) -- cgit v1.2.3-59-g8ed1b From 5eb068da74a0b443fb99a89d9e5062691649c470 Mon Sep 17 00:00:00 2001 From: Alex Bee Date: Tue, 16 Apr 2024 18:12:37 +0200 Subject: regulator: rk808: Add RK816 support Add support for rk816 to the existing rk808 regulator driver. The infrastructure of the driver can be re-used as is. A peculiarity for this version is, that BUCK1/BUCK2 have a (common) bit which needs to toggled after a voltage change to confirm the change. Regulator regmap takes care of that by defining a apply_bit and apply_reg for those regulators. Signed-off-by: Alex Bee Reviewed-by: Mark Brown Link: https://lore.kernel.org/r/20240416161237.2500037-6-knaerzche@gmail.com Signed-off-by: Lee Jones --- drivers/regulator/rk808-regulator.c | 202 +++++++++++++++++++++++++++++++++++- 1 file changed, 201 insertions(+), 1 deletion(-) diff --git a/drivers/regulator/rk808-regulator.c b/drivers/regulator/rk808-regulator.c index a6a563e402d0..14b60abd6afc 100644 --- a/drivers/regulator/rk808-regulator.c +++ b/drivers/regulator/rk808-regulator.c @@ -158,6 +158,11 @@ RK8XX_DESC_COM(_id, _match, _supply, _min, _max, _step, _vreg, \ _vmask, _ereg, _emask, 0, 0, _etime, &rk808_reg_ops) +#define RK816_DESC(_id, _match, _supply, _min, _max, _step, _vreg, \ + _vmask, _ereg, _emask, _disval, _etime) \ + RK8XX_DESC_COM(_id, _match, _supply, _min, _max, _step, _vreg, \ + _vmask, _ereg, _emask, _emask, _disval, _etime, &rk816_reg_ops) + #define RK817_DESC(_id, _match, _supply, _min, _max, _step, _vreg, \ _vmask, _ereg, _emask, _disval, _etime) \ RK8XX_DESC_COM(_id, _match, _supply, _min, _max, _step, _vreg, \ @@ -258,7 +263,7 @@ static const unsigned int rk808_buck1_2_ramp_table[] = { 2000, 4000, 6000, 10000 }; -/* RK817 RK809 */ +/* RK817/RK809/RK816 (buck 1/2 only) */ static const unsigned int rk817_buck1_4_ramp_table[] = { 3000, 6300, 12500, 25000 }; @@ -640,6 +645,38 @@ static int rk808_set_suspend_disable(struct regulator_dev *rdev) rdev->desc->enable_mask); } +static const struct rk8xx_register_bit rk816_suspend_bits[] = { + RK8XX_REG_BIT(RK818_SLEEP_SET_OFF_REG1, 0), + RK8XX_REG_BIT(RK818_SLEEP_SET_OFF_REG1, 1), + RK8XX_REG_BIT(RK818_SLEEP_SET_OFF_REG1, 2), + RK8XX_REG_BIT(RK818_SLEEP_SET_OFF_REG1, 3), + RK8XX_REG_BIT(RK818_SLEEP_SET_OFF_REG2, 0), + RK8XX_REG_BIT(RK818_SLEEP_SET_OFF_REG2, 1), + RK8XX_REG_BIT(RK818_SLEEP_SET_OFF_REG2, 2), + RK8XX_REG_BIT(RK818_SLEEP_SET_OFF_REG2, 3), + RK8XX_REG_BIT(RK818_SLEEP_SET_OFF_REG2, 4), + RK8XX_REG_BIT(RK818_SLEEP_SET_OFF_REG2, 5), + RK8XX_REG_BIT(RK818_SLEEP_SET_OFF_REG1, 5), + RK8XX_REG_BIT(RK818_SLEEP_SET_OFF_REG1, 6), +}; + +static int rk816_set_suspend_enable(struct regulator_dev *rdev) +{ + int rid = rdev_get_id(rdev); + + return regmap_update_bits(rdev->regmap, rk816_suspend_bits[rid].reg, + rk816_suspend_bits[rid].bit, + rk816_suspend_bits[rid].bit); +} + +static int rk816_set_suspend_disable(struct regulator_dev *rdev) +{ + int rid = rdev_get_id(rdev); + + return regmap_update_bits(rdev->regmap, rk816_suspend_bits[rid].reg, + rk816_suspend_bits[rid].bit, 0); +} + static int rk817_set_suspend_enable_ctrl(struct regulator_dev *rdev, unsigned int en) { @@ -913,6 +950,54 @@ static const struct regulator_ops rk809_buck5_ops_range = { .set_suspend_disable = rk817_set_suspend_disable, }; +static const struct regulator_ops rk816_buck1_2_ops_ranges = { + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_linear_range, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .set_mode = rk8xx_set_mode, + .get_mode = rk8xx_get_mode, + .set_suspend_mode = rk8xx_set_suspend_mode, + .set_ramp_delay = regulator_set_ramp_delay_regmap, + .set_suspend_voltage = rk808_set_suspend_voltage_range, + .set_suspend_enable = rk816_set_suspend_enable, + .set_suspend_disable = rk816_set_suspend_disable, +}; + +static const struct regulator_ops rk816_buck4_ops_ranges = { + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_linear_range, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .set_mode = rk8xx_set_mode, + .get_mode = rk8xx_get_mode, + .set_suspend_mode = rk8xx_set_suspend_mode, + .set_suspend_voltage = rk808_set_suspend_voltage_range, + .set_suspend_enable = rk816_set_suspend_enable, + .set_suspend_disable = rk816_set_suspend_disable, +}; + +static const struct regulator_ops rk816_reg_ops = { + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = rk8xx_is_enabled_wmsk_regmap, + .set_suspend_voltage = rk808_set_suspend_voltage, + .set_suspend_enable = rk816_set_suspend_enable, + .set_suspend_disable = rk816_set_suspend_disable, +}; + static const struct regulator_ops rk817_reg_ops = { .list_voltage = regulator_list_voltage_linear, .map_voltage = regulator_map_voltage_linear, @@ -1392,6 +1477,117 @@ static const struct regulator_desc rk809_reg[] = { DISABLE_VAL(3)), }; +static const struct linear_range rk816_buck_4_voltage_ranges[] = { + REGULATOR_LINEAR_RANGE(800000, 0, 26, 100000), + REGULATOR_LINEAR_RANGE(3500000, 27, 31, 0), +}; + +static const struct regulator_desc rk816_reg[] = { + { + .name = "dcdc1", + .supply_name = "vcc1", + .of_match = of_match_ptr("dcdc1"), + .regulators_node = of_match_ptr("regulators"), + .id = RK816_ID_DCDC1, + .ops = &rk816_buck1_2_ops_ranges, + .type = REGULATOR_VOLTAGE, + .n_voltages = 64, + .linear_ranges = rk805_buck_1_2_voltage_ranges, + .n_linear_ranges = ARRAY_SIZE(rk805_buck_1_2_voltage_ranges), + .vsel_reg = RK818_BUCK1_ON_VSEL_REG, + .vsel_mask = RK818_BUCK_VSEL_MASK, + .apply_reg = RK816_DCDC_EN_REG2, + .apply_bit = RK816_BUCK_DVS_CONFIRM, + .enable_reg = RK816_DCDC_EN_REG1, + .enable_mask = BIT(4) | BIT(0), + .enable_val = BIT(4) | BIT(0), + .disable_val = BIT(4), + .ramp_reg = RK818_BUCK1_CONFIG_REG, + .ramp_mask = RK808_RAMP_RATE_MASK, + .ramp_delay_table = rk817_buck1_4_ramp_table, + .n_ramp_values = ARRAY_SIZE(rk817_buck1_4_ramp_table), + .of_map_mode = rk8xx_regulator_of_map_mode, + .owner = THIS_MODULE, + }, { + .name = "dcdc2", + .supply_name = "vcc2", + .of_match = of_match_ptr("dcdc2"), + .regulators_node = of_match_ptr("regulators"), + .id = RK816_ID_DCDC2, + .ops = &rk816_buck1_2_ops_ranges, + .type = REGULATOR_VOLTAGE, + .n_voltages = 64, + .linear_ranges = rk805_buck_1_2_voltage_ranges, + .n_linear_ranges = ARRAY_SIZE(rk805_buck_1_2_voltage_ranges), + .vsel_reg = RK818_BUCK2_ON_VSEL_REG, + .vsel_mask = RK818_BUCK_VSEL_MASK, + .apply_reg = RK816_DCDC_EN_REG2, + .apply_bit = RK816_BUCK_DVS_CONFIRM, + .enable_reg = RK816_DCDC_EN_REG1, + .enable_mask = BIT(5) | BIT(1), + .enable_val = BIT(5) | BIT(1), + .disable_val = BIT(5), + .ramp_reg = RK818_BUCK2_CONFIG_REG, + .ramp_mask = RK808_RAMP_RATE_MASK, + .ramp_delay_table = rk817_buck1_4_ramp_table, + .n_ramp_values = ARRAY_SIZE(rk817_buck1_4_ramp_table), + .of_map_mode = rk8xx_regulator_of_map_mode, + .owner = THIS_MODULE, + }, { + .name = "dcdc3", + .supply_name = "vcc3", + .of_match = of_match_ptr("dcdc3"), + .regulators_node = of_match_ptr("regulators"), + .id = RK816_ID_DCDC3, + .ops = &rk808_switch_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = 1, + .enable_reg = RK816_DCDC_EN_REG1, + .enable_mask = BIT(6) | BIT(2), + .enable_val = BIT(6) | BIT(2), + .disable_val = BIT(6), + .of_map_mode = rk8xx_regulator_of_map_mode, + .owner = THIS_MODULE, + }, { + .name = "dcdc4", + .supply_name = "vcc4", + .of_match = of_match_ptr("dcdc4"), + .regulators_node = of_match_ptr("regulators"), + .id = RK816_ID_DCDC4, + .ops = &rk816_buck4_ops_ranges, + .type = REGULATOR_VOLTAGE, + .n_voltages = 32, + .linear_ranges = rk816_buck_4_voltage_ranges, + .n_linear_ranges = ARRAY_SIZE(rk816_buck_4_voltage_ranges), + .vsel_reg = RK818_BUCK4_ON_VSEL_REG, + .vsel_mask = RK818_BUCK4_VSEL_MASK, + .enable_reg = RK816_DCDC_EN_REG1, + .enable_mask = BIT(7) | BIT(3), + .enable_val = BIT(7) | BIT(3), + .disable_val = BIT(7), + .of_map_mode = rk8xx_regulator_of_map_mode, + .owner = THIS_MODULE, + }, + RK816_DESC(RK816_ID_LDO1, "ldo1", "vcc5", 800, 3400, 100, + RK818_LDO1_ON_VSEL_REG, RK818_LDO_VSEL_MASK, + RK816_LDO_EN_REG1, ENABLE_MASK(0), DISABLE_VAL(0), 400), + RK816_DESC(RK816_ID_LDO2, "ldo2", "vcc5", 800, 3400, 100, + RK818_LDO2_ON_VSEL_REG, RK818_LDO_VSEL_MASK, + RK816_LDO_EN_REG1, ENABLE_MASK(1), DISABLE_VAL(1), 400), + RK816_DESC(RK816_ID_LDO3, "ldo3", "vcc5", 800, 3400, 100, + RK818_LDO3_ON_VSEL_REG, RK818_LDO_VSEL_MASK, + RK816_LDO_EN_REG1, ENABLE_MASK(2), DISABLE_VAL(2), 400), + RK816_DESC(RK816_ID_LDO4, "ldo4", "vcc6", 800, 3400, 100, + RK818_LDO4_ON_VSEL_REG, RK818_LDO_VSEL_MASK, + RK816_LDO_EN_REG1, ENABLE_MASK(3), DISABLE_VAL(3), 400), + RK816_DESC(RK816_ID_LDO5, "ldo5", "vcc6", 800, 3400, 100, + RK818_LDO5_ON_VSEL_REG, RK818_LDO_VSEL_MASK, + RK816_LDO_EN_REG2, ENABLE_MASK(0), DISABLE_VAL(0), 400), + RK816_DESC(RK816_ID_LDO6, "ldo6", "vcc6", 800, 3400, 100, + RK818_LDO6_ON_VSEL_REG, RK818_LDO_VSEL_MASK, + RK816_LDO_EN_REG2, ENABLE_MASK(1), DISABLE_VAL(1), 400), +}; + static const struct regulator_desc rk817_reg[] = { { .name = "DCDC_REG1", @@ -1714,6 +1910,10 @@ static int rk808_regulator_probe(struct platform_device *pdev) regulators = rk809_reg; nregulators = RK809_NUM_REGULATORS; break; + case RK816_ID: + regulators = rk816_reg; + nregulators = ARRAY_SIZE(rk816_reg); + break; case RK817_ID: regulators = rk817_reg; nregulators = RK817_NUM_REGULATORS; -- cgit v1.2.3-59-g8ed1b From 84ccfaee29fe46e305244a69c4471e83629ad5d1 Mon Sep 17 00:00:00 2001 From: Nirmala Devi Mal Nadar Date: Tue, 30 Apr 2024 13:16:34 +0000 Subject: mfd: tps6594: Add register definitions for TI TPS65224 PMIC Extend TPS6594 PMIC register and field definitions to support TPS65224 power management IC. TPS65224 is software compatible to TPS6594 and can re-use many of the same definitions, new definitions are added to support additional controls available on TPS65224. Signed-off-by: Nirmala Devi Mal Nadar Signed-off-by: Bhargav Raviprakash Link: https://lore.kernel.org/r/0109018f2f265d30-a87711fa-31d9-48db-b8cb-7109d0213e2e-000000@ap-south-1.amazonses.com Signed-off-by: Lee Jones --- include/linux/mfd/tps6594.h | 347 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 335 insertions(+), 12 deletions(-) diff --git a/include/linux/mfd/tps6594.h b/include/linux/mfd/tps6594.h index 3f7c5e23cd4c..e754c01acc64 100644 --- a/include/linux/mfd/tps6594.h +++ b/include/linux/mfd/tps6594.h @@ -18,12 +18,13 @@ enum pmic_id { TPS6594, TPS6593, LP8764, + TPS65224, }; /* Macro to get page index from register address */ #define TPS6594_REG_TO_PAGE(reg) ((reg) >> 8) -/* Registers for page 0 of TPS6594 */ +/* Registers for page 0 */ #define TPS6594_REG_DEV_REV 0x01 #define TPS6594_REG_NVM_CODE_1 0x02 @@ -56,9 +57,6 @@ enum pmic_id { #define TPS6594_REG_GPIOX_OUT(gpio_inst) (TPS6594_REG_GPIO_OUT_1 + (gpio_inst) / 8) #define TPS6594_REG_GPIOX_IN(gpio_inst) (TPS6594_REG_GPIO_IN_1 + (gpio_inst) / 8) -#define TPS6594_REG_GPIO_IN_1 0x3f -#define TPS6594_REG_GPIO_IN_2 0x40 - #define TPS6594_REG_RAIL_SEL_1 0x41 #define TPS6594_REG_RAIL_SEL_2 0x42 #define TPS6594_REG_RAIL_SEL_3 0x43 @@ -70,13 +68,15 @@ enum pmic_id { #define TPS6594_REG_FSM_TRIG_MASK_3 0x48 #define TPS6594_REG_MASK_BUCK1_2 0x49 +#define TPS65224_REG_MASK_BUCKS 0x49 #define TPS6594_REG_MASK_BUCK3_4 0x4a #define TPS6594_REG_MASK_BUCK5 0x4b #define TPS6594_REG_MASK_LDO1_2 0x4c +#define TPS65224_REG_MASK_LDOS 0x4c #define TPS6594_REG_MASK_LDO3_4 0x4d #define TPS6594_REG_MASK_VMON 0x4e -#define TPS6594_REG_MASK_GPIO1_8_FALL 0x4f -#define TPS6594_REG_MASK_GPIO1_8_RISE 0x50 +#define TPS6594_REG_MASK_GPIO_FALL 0x4f +#define TPS6594_REG_MASK_GPIO_RISE 0x50 #define TPS6594_REG_MASK_GPIO9_11 0x51 #define TPS6594_REG_MASK_STARTUP 0x52 #define TPS6594_REG_MASK_MISC 0x53 @@ -174,6 +174,10 @@ enum pmic_id { #define TPS6594_REG_REGISTER_LOCK 0xa1 +#define TPS65224_REG_SRAM_ACCESS_1 0xa2 +#define TPS65224_REG_SRAM_ACCESS_2 0xa3 +#define TPS65224_REG_SRAM_ADDR_CTRL 0xa4 +#define TPS65224_REG_RECOV_CNT_PFSM_INCR 0xa5 #define TPS6594_REG_MANUFACTURING_VER 0xa6 #define TPS6594_REG_CUSTOMER_NVM_ID_REG 0xa7 @@ -182,6 +186,9 @@ enum pmic_id { #define TPS6594_REG_SOFT_REBOOT_REG 0xab +#define TPS65224_REG_ADC_CTRL 0xac +#define TPS65224_REG_ADC_RESULT_REG_1 0xad +#define TPS65224_REG_ADC_RESULT_REG_2 0xae #define TPS6594_REG_RTC_SECONDS 0xb5 #define TPS6594_REG_RTC_MINUTES 0xb6 #define TPS6594_REG_RTC_HOURS 0xb7 @@ -199,6 +206,7 @@ enum pmic_id { #define TPS6594_REG_RTC_CTRL_1 0xc2 #define TPS6594_REG_RTC_CTRL_2 0xc3 +#define TPS65224_REG_STARTUP_CTRL 0xc3 #define TPS6594_REG_RTC_STATUS 0xc4 #define TPS6594_REG_RTC_INTERRUPTS 0xc5 #define TPS6594_REG_RTC_COMP_LSB 0xc6 @@ -214,13 +222,17 @@ enum pmic_id { #define TPS6594_REG_PFSM_DELAY_REG_2 0xce #define TPS6594_REG_PFSM_DELAY_REG_3 0xcf #define TPS6594_REG_PFSM_DELAY_REG_4 0xd0 +#define TPS65224_REG_ADC_GAIN_COMP_REG 0xd0 +#define TPS65224_REG_CRC_CALC_CONTROL 0xef +#define TPS65224_REG_REGMAP_USER_CRC_LOW 0xf0 +#define TPS65224_REG_REGMAP_USER_CRC_HIGH 0xf1 -/* Registers for page 1 of TPS6594 */ +/* Registers for page 1 */ #define TPS6594_REG_SERIAL_IF_CONFIG 0x11a #define TPS6594_REG_I2C1_ID 0x122 #define TPS6594_REG_I2C2_ID 0x123 -/* Registers for page 4 of TPS6594 */ +/* Registers for page 4 */ #define TPS6594_REG_WD_ANSWER_REG 0x401 #define TPS6594_REG_WD_QUESTION_ANSW_CNT 0x402 #define TPS6594_REG_WD_WIN1_CFG 0x403 @@ -241,16 +253,26 @@ enum pmic_id { #define TPS6594_BIT_BUCK_PLDN BIT(5) #define TPS6594_BIT_BUCK_RV_SEL BIT(7) -/* BUCKX_CONF register field definition */ +/* TPS6594 BUCKX_CONF register field definition */ #define TPS6594_MASK_BUCK_SLEW_RATE GENMASK(2, 0) #define TPS6594_MASK_BUCK_ILIM GENMASK(5, 3) -/* BUCKX_PG_WINDOW register field definition */ +/* TPS65224 BUCKX_CONF register field definition */ +#define TPS65224_MASK_BUCK_SLEW_RATE GENMASK(1, 0) + +/* TPS6594 BUCKX_PG_WINDOW register field definition */ #define TPS6594_MASK_BUCK_OV_THR GENMASK(2, 0) #define TPS6594_MASK_BUCK_UV_THR GENMASK(5, 3) -/* BUCKX VSET */ -#define TPS6594_MASK_BUCKS_VSET GENMASK(7, 0) +/* TPS65224 BUCKX_PG_WINDOW register field definition */ +#define TPS65224_MASK_BUCK_VMON_THR GENMASK(1, 0) + +/* TPS6594 BUCKX_VOUT register field definition */ +#define TPS6594_MASK_BUCKS_VSET GENMASK(7, 0) + +/* TPS65224 BUCKX_VOUT register field definition */ +#define TPS65224_MASK_BUCK1_VSET GENMASK(7, 0) +#define TPS65224_MASK_BUCKS_VSET GENMASK(6, 0) /* LDOX_CTRL register field definition */ #define TPS6594_BIT_LDO_EN BIT(0) @@ -258,6 +280,7 @@ enum pmic_id { #define TPS6594_BIT_LDO_VMON_EN BIT(4) #define TPS6594_MASK_LDO_PLDN GENMASK(6, 5) #define TPS6594_BIT_LDO_RV_SEL BIT(7) +#define TPS65224_BIT_LDO_DISCHARGE_EN BIT(5) /* LDORTC_CTRL register field definition */ #define TPS6594_BIT_LDORTC_DIS BIT(0) @@ -271,6 +294,9 @@ enum pmic_id { #define TPS6594_MASK_LDO_OV_THR GENMASK(2, 0) #define TPS6594_MASK_LDO_UV_THR GENMASK(5, 3) +/* LDOX_PG_WINDOW register field definition */ +#define TPS65224_MASK_LDO_VMON_THR GENMASK(1, 0) + /* VCCA_VMON_CTRL register field definition */ #define TPS6594_BIT_VMON_EN BIT(0) #define TPS6594_BIT_VMON1_EN BIT(1) @@ -278,10 +304,12 @@ enum pmic_id { #define TPS6594_BIT_VMON2_EN BIT(3) #define TPS6594_BIT_VMON2_RV_SEL BIT(4) #define TPS6594_BIT_VMON_DEGLITCH_SEL BIT(5) +#define TPS65224_BIT_VMON_DEGLITCH_SEL GENMASK(7, 5) /* VCCA_PG_WINDOW register field definition */ #define TPS6594_MASK_VCCA_OV_THR GENMASK(2, 0) #define TPS6594_MASK_VCCA_UV_THR GENMASK(5, 3) +#define TPS65224_MASK_VCCA_VMON_THR GENMASK(1, 0) #define TPS6594_BIT_VCCA_PG_SET BIT(6) /* VMONX_PG_WINDOW register field definition */ @@ -289,6 +317,9 @@ enum pmic_id { #define TPS6594_MASK_VMONX_UV_THR GENMASK(5, 3) #define TPS6594_BIT_VMONX_RANGE BIT(6) +/* VMONX_PG_WINDOW register field definition */ +#define TPS65224_MASK_VMONX_THR GENMASK(1, 0) + /* GPIOX_CONF register field definition */ #define TPS6594_BIT_GPIO_DIR BIT(0) #define TPS6594_BIT_GPIO_OD BIT(1) @@ -296,6 +327,8 @@ enum pmic_id { #define TPS6594_BIT_GPIO_PU_PD_EN BIT(3) #define TPS6594_BIT_GPIO_DEGLITCH_EN BIT(4) #define TPS6594_MASK_GPIO_SEL GENMASK(7, 5) +#define TPS65224_MASK_GPIO_SEL GENMASK(6, 5) +#define TPS65224_MASK_GPIO_SEL_GPIO6 GENMASK(7, 5) /* NPWRON_CONF register field definition */ #define TPS6594_BIT_NRSTOUT_OD BIT(0) @@ -305,6 +338,12 @@ enum pmic_id { #define TPS6594_BIT_ENABLE_POL BIT(5) #define TPS6594_MASK_NPWRON_SEL GENMASK(7, 6) +/* POWER_ON_CONFIG register field definition */ +#define TPS65224_BIT_NINT_ENDRV_PU_SEL BIT(0) +#define TPS65224_BIT_NINT_ENDRV_SEL BIT(1) +#define TPS65224_BIT_EN_PB_DEGL BIT(5) +#define TPS65224_MASK_EN_PB_VSENSE_CONFIG GENMASK(7, 6) + /* GPIO_OUT_X register field definition */ #define TPS6594_BIT_GPIOX_OUT(gpio_inst) BIT((gpio_inst) % 8) @@ -312,6 +351,12 @@ enum pmic_id { #define TPS6594_BIT_GPIOX_IN(gpio_inst) BIT((gpio_inst) % 8) #define TPS6594_BIT_NPWRON_IN BIT(3) +/* GPIO_OUT_X register field definition */ +#define TPS65224_BIT_GPIOX_OUT(gpio_inst) BIT((gpio_inst)) + +/* GPIO_IN_X register field definition */ +#define TPS65224_BIT_GPIOX_IN(gpio_inst) BIT((gpio_inst)) + /* RAIL_SEL_1 register field definition */ #define TPS6594_MASK_BUCK1_GRP_SEL GENMASK(1, 0) #define TPS6594_MASK_BUCK2_GRP_SEL GENMASK(3, 2) @@ -343,6 +388,9 @@ enum pmic_id { #define TPS6594_BIT_GPIOX_FSM_MASK(gpio_inst) BIT(((gpio_inst) << 1) % 8) #define TPS6594_BIT_GPIOX_FSM_MASK_POL(gpio_inst) BIT(((gpio_inst) << 1) % 8 + 1) +#define TPS65224_BIT_GPIOX_FSM_MASK(gpio_inst) BIT(((gpio_inst) << 1) % 6) +#define TPS65224_BIT_GPIOX_FSM_MASK_POL(gpio_inst) BIT(((gpio_inst) << 1) % 6 + 1) + /* MASK_BUCKX register field definition */ #define TPS6594_BIT_BUCKX_OV_MASK(buck_inst) BIT(((buck_inst) << 2) % 8) #define TPS6594_BIT_BUCKX_UV_MASK(buck_inst) BIT(((buck_inst) << 2) % 8 + 1) @@ -361,22 +409,46 @@ enum pmic_id { #define TPS6594_BIT_VMON2_OV_MASK BIT(5) #define TPS6594_BIT_VMON2_UV_MASK BIT(6) +/* MASK_BUCK Register field definition */ +#define TPS65224_BIT_BUCK1_UVOV_MASK BIT(0) +#define TPS65224_BIT_BUCK2_UVOV_MASK BIT(1) +#define TPS65224_BIT_BUCK3_UVOV_MASK BIT(2) +#define TPS65224_BIT_BUCK4_UVOV_MASK BIT(4) + +/* MASK_LDO_VMON register field definition */ +#define TPS65224_BIT_LDO1_UVOV_MASK BIT(0) +#define TPS65224_BIT_LDO2_UVOV_MASK BIT(1) +#define TPS65224_BIT_LDO3_UVOV_MASK BIT(2) +#define TPS65224_BIT_VCCA_UVOV_MASK BIT(4) +#define TPS65224_BIT_VMON1_UVOV_MASK BIT(5) +#define TPS65224_BIT_VMON2_UVOV_MASK BIT(6) + /* MASK_GPIOX register field definition */ #define TPS6594_BIT_GPIOX_FALL_MASK(gpio_inst) BIT((gpio_inst) < 8 ? \ (gpio_inst) : (gpio_inst) % 8) #define TPS6594_BIT_GPIOX_RISE_MASK(gpio_inst) BIT((gpio_inst) < 8 ? \ (gpio_inst) : (gpio_inst) % 8 + 3) +/* MASK_GPIOX register field definition */ +#define TPS65224_BIT_GPIOX_FALL_MASK(gpio_inst) BIT((gpio_inst)) +#define TPS65224_BIT_GPIOX_RISE_MASK(gpio_inst) BIT((gpio_inst)) /* MASK_STARTUP register field definition */ #define TPS6594_BIT_NPWRON_START_MASK BIT(0) #define TPS6594_BIT_ENABLE_MASK BIT(1) #define TPS6594_BIT_FSD_MASK BIT(4) #define TPS6594_BIT_SOFT_REBOOT_MASK BIT(5) +#define TPS65224_BIT_VSENSE_MASK BIT(0) +#define TPS65224_BIT_PB_SHORT_MASK BIT(2) /* MASK_MISC register field definition */ #define TPS6594_BIT_BIST_PASS_MASK BIT(0) #define TPS6594_BIT_EXT_CLK_MASK BIT(1) +#define TPS65224_BIT_REG_UNLOCK_MASK BIT(2) #define TPS6594_BIT_TWARN_MASK BIT(3) +#define TPS65224_BIT_PB_LONG_MASK BIT(4) +#define TPS65224_BIT_PB_FALL_MASK BIT(5) +#define TPS65224_BIT_PB_RISE_MASK BIT(6) +#define TPS65224_BIT_ADC_CONV_READY_MASK BIT(7) /* MASK_MODERATE_ERR register field definition */ #define TPS6594_BIT_BIST_FAIL_MASK BIT(1) @@ -391,6 +463,8 @@ enum pmic_id { #define TPS6594_BIT_ORD_SHUTDOWN_MASK BIT(1) #define TPS6594_BIT_MCU_PWR_ERR_MASK BIT(2) #define TPS6594_BIT_SOC_PWR_ERR_MASK BIT(3) +#define TPS65224_BIT_COMM_ERR_MASK BIT(4) +#define TPS65224_BIT_I2C2_ERR_MASK BIT(5) /* MASK_COMM_ERR register field definition */ #define TPS6594_BIT_COMM_FRM_ERR_MASK BIT(0) @@ -426,6 +500,12 @@ enum pmic_id { #define TPS6594_BIT_BUCK3_4_INT BIT(1) #define TPS6594_BIT_BUCK5_INT BIT(2) +/* INT_BUCK register field definition */ +#define TPS65224_BIT_BUCK1_UVOV_INT BIT(0) +#define TPS65224_BIT_BUCK2_UVOV_INT BIT(1) +#define TPS65224_BIT_BUCK3_UVOV_INT BIT(2) +#define TPS65224_BIT_BUCK4_UVOV_INT BIT(3) + /* INT_BUCKX register field definition */ #define TPS6594_BIT_BUCKX_OV_INT(buck_inst) BIT(((buck_inst) << 2) % 8) #define TPS6594_BIT_BUCKX_UV_INT(buck_inst) BIT(((buck_inst) << 2) % 8 + 1) @@ -437,6 +517,14 @@ enum pmic_id { #define TPS6594_BIT_LDO3_4_INT BIT(1) #define TPS6594_BIT_VCCA_INT BIT(4) +/* INT_LDO_VMON register field definition */ +#define TPS65224_BIT_LDO1_UVOV_INT BIT(0) +#define TPS65224_BIT_LDO2_UVOV_INT BIT(1) +#define TPS65224_BIT_LDO3_UVOV_INT BIT(2) +#define TPS65224_BIT_VCCA_UVOV_INT BIT(4) +#define TPS65224_BIT_VMON1_UVOV_INT BIT(5) +#define TPS65224_BIT_VMON2_UVOV_INT BIT(6) + /* INT_LDOX register field definition */ #define TPS6594_BIT_LDOX_OV_INT(ldo_inst) BIT(((ldo_inst) << 2) % 8) #define TPS6594_BIT_LDOX_UV_INT(ldo_inst) BIT(((ldo_inst) << 2) % 8 + 1) @@ -462,17 +550,32 @@ enum pmic_id { /* INT_GPIOX register field definition */ #define TPS6594_BIT_GPIOX_INT(gpio_inst) BIT(gpio_inst) +/* INT_GPIO register field definition */ +#define TPS65224_BIT_GPIO1_INT BIT(0) +#define TPS65224_BIT_GPIO2_INT BIT(1) +#define TPS65224_BIT_GPIO3_INT BIT(2) +#define TPS65224_BIT_GPIO4_INT BIT(3) +#define TPS65224_BIT_GPIO5_INT BIT(4) +#define TPS65224_BIT_GPIO6_INT BIT(5) + /* INT_STARTUP register field definition */ #define TPS6594_BIT_NPWRON_START_INT BIT(0) +#define TPS65224_BIT_VSENSE_INT BIT(0) #define TPS6594_BIT_ENABLE_INT BIT(1) #define TPS6594_BIT_RTC_INT BIT(2) +#define TPS65224_BIT_PB_SHORT_INT BIT(2) #define TPS6594_BIT_FSD_INT BIT(4) #define TPS6594_BIT_SOFT_REBOOT_INT BIT(5) /* INT_MISC register field definition */ #define TPS6594_BIT_BIST_PASS_INT BIT(0) #define TPS6594_BIT_EXT_CLK_INT BIT(1) +#define TPS65224_BIT_REG_UNLOCK_INT BIT(2) #define TPS6594_BIT_TWARN_INT BIT(3) +#define TPS65224_BIT_PB_LONG_INT BIT(4) +#define TPS65224_BIT_PB_FALL_INT BIT(5) +#define TPS65224_BIT_PB_RISE_INT BIT(6) +#define TPS65224_BIT_ADC_CONV_READY_INT BIT(7) /* INT_MODERATE_ERR register field definition */ #define TPS6594_BIT_TSD_ORD_INT BIT(0) @@ -488,6 +591,7 @@ enum pmic_id { #define TPS6594_BIT_TSD_IMM_INT BIT(0) #define TPS6594_BIT_VCCA_OVP_INT BIT(1) #define TPS6594_BIT_PFSM_ERR_INT BIT(2) +#define TPS65224_BIT_BG_XMON_INT BIT(3) /* INT_FSM_ERR register field definition */ #define TPS6594_BIT_IMM_SHUTDOWN_INT BIT(0) @@ -496,6 +600,7 @@ enum pmic_id { #define TPS6594_BIT_SOC_PWR_ERR_INT BIT(3) #define TPS6594_BIT_COMM_ERR_INT BIT(4) #define TPS6594_BIT_READBACK_ERR_INT BIT(5) +#define TPS65224_BIT_I2C2_ERR_INT BIT(5) #define TPS6594_BIT_ESM_INT BIT(6) #define TPS6594_BIT_WD_INT BIT(7) @@ -536,8 +641,18 @@ enum pmic_id { #define TPS6594_BIT_VMON2_OV_STAT BIT(5) #define TPS6594_BIT_VMON2_UV_STAT BIT(6) +/* STAT_LDO_VMON register field definition */ +#define TPS65224_BIT_LDO1_UVOV_STAT BIT(0) +#define TPS65224_BIT_LDO2_UVOV_STAT BIT(1) +#define TPS65224_BIT_LDO3_UVOV_STAT BIT(2) +#define TPS65224_BIT_VCCA_UVOV_STAT BIT(4) +#define TPS65224_BIT_VMON1_UVOV_STAT BIT(5) +#define TPS65224_BIT_VMON2_UVOV_STAT BIT(6) + /* STAT_STARTUP register field definition */ +#define TPS65224_BIT_VSENSE_STAT BIT(0) #define TPS6594_BIT_ENABLE_STAT BIT(1) +#define TPS65224_BIT_PB_LEVEL_STAT BIT(2) /* STAT_MISC register field definition */ #define TPS6594_BIT_EXT_CLK_STAT BIT(1) @@ -549,6 +664,7 @@ enum pmic_id { /* STAT_SEVERE_ERR register field definition */ #define TPS6594_BIT_TSD_IMM_STAT BIT(0) #define TPS6594_BIT_VCCA_OVP_STAT BIT(1) +#define TPS65224_BIT_BG_XMON_STAT BIT(3) /* STAT_READBACK_ERR register field definition */ #define TPS6594_BIT_EN_DRV_READBACK_STAT BIT(0) @@ -597,6 +713,8 @@ enum pmic_id { #define TPS6594_BIT_BB_CHARGER_EN BIT(0) #define TPS6594_BIT_BB_ICHR BIT(1) #define TPS6594_MASK_BB_VEOC GENMASK(3, 2) +#define TPS65224_BIT_I2C1_SPI_CRC_EN BIT(4) +#define TPS65224_BIT_I2C2_CRC_EN BIT(5) #define TPS6594_BB_EOC_RDY BIT(7) /* ENABLE_DRV_REG register field definition */ @@ -617,6 +735,7 @@ enum pmic_id { #define TPS6594_BIT_NRSTOUT_SOC_IN BIT(2) #define TPS6594_BIT_FORCE_EN_DRV_LOW BIT(3) #define TPS6594_BIT_SPMI_LPM_EN BIT(4) +#define TPS65224_BIT_TSD_DISABLE BIT(5) /* RECOV_CNT_REG_1 register field definition */ #define TPS6594_MASK_RECOV_CNT GENMASK(3, 0) @@ -671,15 +790,27 @@ enum pmic_id { /* ESM_SOC_START_REG register field definition */ #define TPS6594_BIT_ESM_SOC_START BIT(0) +/* ESM_MCU_START_REG register field definition */ +#define TPS65224_BIT_ESM_MCU_START BIT(0) + /* ESM_SOC_MODE_CFG register field definition */ #define TPS6594_MASK_ESM_SOC_ERR_CNT_TH GENMASK(3, 0) #define TPS6594_BIT_ESM_SOC_ENDRV BIT(5) #define TPS6594_BIT_ESM_SOC_EN BIT(6) #define TPS6594_BIT_ESM_SOC_MODE BIT(7) +/* ESM_MCU_MODE_CFG register field definition */ +#define TPS65224_MASK_ESM_MCU_ERR_CNT_TH GENMASK(3, 0) +#define TPS65224_BIT_ESM_MCU_ENDRV BIT(5) +#define TPS65224_BIT_ESM_MCU_EN BIT(6) +#define TPS65224_BIT_ESM_MCU_MODE BIT(7) + /* ESM_SOC_ERR_CNT_REG register field definition */ #define TPS6594_MASK_ESM_SOC_ERR_CNT GENMASK(4, 0) +/* ESM_MCU_ERR_CNT_REG register field definition */ +#define TPS6594_MASK_ESM_MCU_ERR_CNT GENMASK(4, 0) + /* REGISTER_LOCK register field definition */ #define TPS6594_BIT_REGISTER_LOCK_STATUS BIT(0) @@ -687,6 +818,29 @@ enum pmic_id { #define TPS6594_MASK_VMON1_SLEW_RATE GENMASK(2, 0) #define TPS6594_MASK_VMON2_SLEW_RATE GENMASK(5, 3) +/* SRAM_ACCESS_1 Register field definition */ +#define TPS65224_MASk_SRAM_UNLOCK_SEQ GENMASK(7, 0) + +/* SRAM_ACCESS_2 Register field definition */ +#define TPS65224_BIT_SRAM_WRITE_MODE BIT(0) +#define TPS65224_BIT_OTP_PROG_USER BIT(1) +#define TPS65224_BIT_OTP_PROG_PFSM BIT(2) +#define TPS65224_BIT_OTP_PROG_STATUS BIT(3) +#define TPS65224_BIT_SRAM_UNLOCKED BIT(6) +#define TPS65224_USER_PROG_ALLOWED BIT(7) + +/* SRAM_ADDR_CTRL Register field definition */ +#define TPS65224_MASk_SRAM_SEL GENMASK(1, 0) + +/* RECOV_CNT_PFSM_INCR Register field definition */ +#define TPS65224_BIT_INCREMENT_RECOV_CNT BIT(0) + +/* MANUFACTURING_VER Register field definition */ +#define TPS65224_MASK_SILICON_REV GENMASK(7, 0) + +/* CUSTOMER_NVM_ID_REG Register field definition */ +#define TPS65224_MASK_CUSTOMER_NVM_ID GENMASK(7, 0) + /* SOFT_REBOOT_REG register field definition */ #define TPS6594_BIT_SOFT_REBOOT BIT(0) @@ -755,14 +909,83 @@ enum pmic_id { #define TPS6594_BIT_I2C2_CRC_EN BIT(2) #define TPS6594_MASK_T_CRC GENMASK(7, 3) +/* ADC_CTRL Register field definition */ +#define TPS65224_BIT_ADC_START BIT(0) +#define TPS65224_BIT_ADC_CONT_CONV BIT(1) +#define TPS65224_BIT_ADC_THERMAL_SEL BIT(2) +#define TPS65224_BIT_ADC_RDIV_EN BIT(3) +#define TPS65224_BIT_ADC_STATUS BIT(7) + +/* ADC_RESULT_REG_1 Register field definition */ +#define TPS65224_MASK_ADC_RESULT_11_4 GENMASK(7, 0) + +/* ADC_RESULT_REG_2 Register field definition */ +#define TPS65224_MASK_ADC_RESULT_3_0 GENMASK(7, 4) + +/* STARTUP_CTRL Register field definition */ +#define TPS65224_MASK_STARTUP_DEST GENMASK(6, 5) +#define TPS65224_BIT_FIRST_STARTUP_DONE BIT(7) + +/* SCRATCH_PAD_REG_1 Register field definition */ +#define TPS6594_MASK_SCRATCH_PAD_1 GENMASK(7, 0) + +/* SCRATCH_PAD_REG_2 Register field definition */ +#define TPS6594_MASK_SCRATCH_PAD_2 GENMASK(7, 0) + +/* SCRATCH_PAD_REG_3 Register field definition */ +#define TPS6594_MASK_SCRATCH_PAD_3 GENMASK(7, 0) + +/* SCRATCH_PAD_REG_4 Register field definition */ +#define TPS6594_MASK_SCRATCH_PAD_4 GENMASK(7, 0) + +/* PFSM_DELAY_REG_1 Register field definition */ +#define TPS6594_MASK_PFSM_DELAY1 GENMASK(7, 0) + +/* PFSM_DELAY_REG_2 Register field definition */ +#define TPS6594_MASK_PFSM_DELAY2 GENMASK(7, 0) + +/* PFSM_DELAY_REG_3 Register field definition */ +#define TPS6594_MASK_PFSM_DELAY3 GENMASK(7, 0) + +/* PFSM_DELAY_REG_4 Register field definition */ +#define TPS6594_MASK_PFSM_DELAY4 GENMASK(7, 0) + +/* CRC_CALC_CONTROL Register field definition */ +#define TPS65224_BIT_RUN_CRC_BIST BIT(0) +#define TPS65224_BIT_RUN_CRC_UPDATE BIT(1) + +/* ADC_GAIN_COMP_REG Register field definition */ +#define TPS65224_MASK_ADC_GAIN_COMP GENMASK(7, 0) + +/* REGMAP_USER_CRC_LOW Register field definition */ +#define TPS65224_MASK_REGMAP_USER_CRC16_LOW GENMASK(7, 0) + +/* REGMAP_USER_CRC_HIGH Register field definition */ +#define TPS65224_MASK_REGMAP_USER_CRC16_HIGH GENMASK(7, 0) + +/* WD_ANSWER_REG Register field definition */ +#define TPS6594_MASK_WD_ANSWER GENMASK(7, 0) + /* WD_QUESTION_ANSW_CNT register field definition */ #define TPS6594_MASK_WD_QUESTION GENMASK(3, 0) #define TPS6594_MASK_WD_ANSW_CNT GENMASK(5, 4) +#define TPS65224_BIT_INT_TOP_STATUS BIT(7) + +/* WD WIN1_CFG register field definition */ +#define TPS6594_MASK_WD_WIN1_CFG GENMASK(6, 0) + +/* WD WIN2_CFG register field definition */ +#define TPS6594_MASK_WD_WIN2_CFG GENMASK(6, 0) + +/* WD LongWin register field definition */ +#define TPS6594_MASK_WD_LONGWIN_CFG GENMASK(7, 0) /* WD_MODE_REG register field definition */ #define TPS6594_BIT_WD_RETURN_LONGWIN BIT(0) #define TPS6594_BIT_WD_MODE_SELECT BIT(1) #define TPS6594_BIT_WD_PWRHOLD BIT(2) +#define TPS65224_BIT_WD_ENDRV_SEL BIT(6) +#define TPS65224_BIT_WD_CNT_SEL BIT(7) /* WD_QA_CFG register field definition */ #define TPS6594_MASK_WD_QUESTION_SEED GENMASK(3, 0) @@ -993,6 +1216,106 @@ enum tps6594_irqs { #define TPS6594_IRQ_NAME_ALARM "alarm" #define TPS6594_IRQ_NAME_POWERUP "powerup" +/* IRQs */ +enum tps65224_irqs { + /* INT_BUCK register */ + TPS65224_IRQ_BUCK1_UVOV, + TPS65224_IRQ_BUCK2_UVOV, + TPS65224_IRQ_BUCK3_UVOV, + TPS65224_IRQ_BUCK4_UVOV, + /* INT_LDO_VMON register */ + TPS65224_IRQ_LDO1_UVOV, + TPS65224_IRQ_LDO2_UVOV, + TPS65224_IRQ_LDO3_UVOV, + TPS65224_IRQ_VCCA_UVOV, + TPS65224_IRQ_VMON1_UVOV, + TPS65224_IRQ_VMON2_UVOV, + /* INT_GPIO register */ + TPS65224_IRQ_GPIO1, + TPS65224_IRQ_GPIO2, + TPS65224_IRQ_GPIO3, + TPS65224_IRQ_GPIO4, + TPS65224_IRQ_GPIO5, + TPS65224_IRQ_GPIO6, + /* INT_STARTUP register */ + TPS65224_IRQ_VSENSE, + TPS65224_IRQ_ENABLE, + TPS65224_IRQ_PB_SHORT, + TPS65224_IRQ_FSD, + TPS65224_IRQ_SOFT_REBOOT, + /* INT_MISC register */ + TPS65224_IRQ_BIST_PASS, + TPS65224_IRQ_EXT_CLK, + TPS65224_IRQ_REG_UNLOCK, + TPS65224_IRQ_TWARN, + TPS65224_IRQ_PB_LONG, + TPS65224_IRQ_PB_FALL, + TPS65224_IRQ_PB_RISE, + TPS65224_IRQ_ADC_CONV_READY, + /* INT_MODERATE_ERR register */ + TPS65224_IRQ_TSD_ORD, + TPS65224_IRQ_BIST_FAIL, + TPS65224_IRQ_REG_CRC_ERR, + TPS65224_IRQ_RECOV_CNT, + /* INT_SEVERE_ERR register */ + TPS65224_IRQ_TSD_IMM, + TPS65224_IRQ_VCCA_OVP, + TPS65224_IRQ_PFSM_ERR, + TPS65224_IRQ_BG_XMON, + /* INT_FSM_ERR register */ + TPS65224_IRQ_IMM_SHUTDOWN, + TPS65224_IRQ_ORD_SHUTDOWN, + TPS65224_IRQ_MCU_PWR_ERR, + TPS65224_IRQ_SOC_PWR_ERR, + TPS65224_IRQ_COMM_ERR, + TPS65224_IRQ_I2C2_ERR, +}; + +#define TPS65224_IRQ_NAME_BUCK1_UVOV "buck1_uvov" +#define TPS65224_IRQ_NAME_BUCK2_UVOV "buck2_uvov" +#define TPS65224_IRQ_NAME_BUCK3_UVOV "buck3_uvov" +#define TPS65224_IRQ_NAME_BUCK4_UVOV "buck4_uvov" +#define TPS65224_IRQ_NAME_LDO1_UVOV "ldo1_uvov" +#define TPS65224_IRQ_NAME_LDO2_UVOV "ldo2_uvov" +#define TPS65224_IRQ_NAME_LDO3_UVOV "ldo3_uvov" +#define TPS65224_IRQ_NAME_VCCA_UVOV "vcca_uvov" +#define TPS65224_IRQ_NAME_VMON1_UVOV "vmon1_uvov" +#define TPS65224_IRQ_NAME_VMON2_UVOV "vmon2_uvov" +#define TPS65224_IRQ_NAME_GPIO1 "gpio1" +#define TPS65224_IRQ_NAME_GPIO2 "gpio2" +#define TPS65224_IRQ_NAME_GPIO3 "gpio3" +#define TPS65224_IRQ_NAME_GPIO4 "gpio4" +#define TPS65224_IRQ_NAME_GPIO5 "gpio5" +#define TPS65224_IRQ_NAME_GPIO6 "gpio6" +#define TPS65224_IRQ_NAME_VSENSE "vsense" +#define TPS65224_IRQ_NAME_ENABLE "enable" +#define TPS65224_IRQ_NAME_PB_SHORT "pb_short" +#define TPS65224_IRQ_NAME_FSD "fsd" +#define TPS65224_IRQ_NAME_SOFT_REBOOT "soft_reboot" +#define TPS65224_IRQ_NAME_BIST_PASS "bist_pass" +#define TPS65224_IRQ_NAME_EXT_CLK "ext_clk" +#define TPS65224_IRQ_NAME_REG_UNLOCK "reg_unlock" +#define TPS65224_IRQ_NAME_TWARN "twarn" +#define TPS65224_IRQ_NAME_PB_LONG "pb_long" +#define TPS65224_IRQ_NAME_PB_FALL "pb_fall" +#define TPS65224_IRQ_NAME_PB_RISE "pb_rise" +#define TPS65224_IRQ_NAME_ADC_CONV_READY "adc_conv_ready" +#define TPS65224_IRQ_NAME_TSD_ORD "tsd_ord" +#define TPS65224_IRQ_NAME_BIST_FAIL "bist_fail" +#define TPS65224_IRQ_NAME_REG_CRC_ERR "reg_crc_err" +#define TPS65224_IRQ_NAME_RECOV_CNT "recov_cnt" +#define TPS65224_IRQ_NAME_TSD_IMM "tsd_imm" +#define TPS65224_IRQ_NAME_VCCA_OVP "vcca_ovp" +#define TPS65224_IRQ_NAME_PFSM_ERR "pfsm_err" +#define TPS65224_IRQ_NAME_BG_XMON "bg_xmon" +#define TPS65224_IRQ_NAME_IMM_SHUTDOWN "imm_shutdown" +#define TPS65224_IRQ_NAME_ORD_SHUTDOWN "ord_shutdown" +#define TPS65224_IRQ_NAME_MCU_PWR_ERR "mcu_pwr_err" +#define TPS65224_IRQ_NAME_SOC_PWR_ERR "soc_pwr_err" +#define TPS65224_IRQ_NAME_COMM_ERR "comm_err" +#define TPS65224_IRQ_NAME_I2C2_ERR "i2c2_err" +#define TPS65224_IRQ_NAME_POWERUP "powerup" + /** * struct tps6594 - device private data structure * -- cgit v1.2.3-59-g8ed1b From 436250638b6d8e6cf8dceed82cdbbfc90ce3a775 Mon Sep 17 00:00:00 2001 From: Bhargav Raviprakash Date: Tue, 30 Apr 2024 13:16:43 +0000 Subject: mfd: tps6594: Use volatile_table instead of volatile_reg In regmap_config use volatile_table instead of volatile_reg. This change makes it easier to add support for TPS65224 PMIC. Signed-off-by: Bhargav Raviprakash Acked-by: Julien Panis Link: https://lore.kernel.org/r/0109018f2f267f6e-3121fa42-4816-45f7-a96d-0d6b4678da5a-000000@ap-south-1.amazonses.com Signed-off-by: Lee Jones --- drivers/mfd/tps6594-core.c | 16 ++++++++++------ drivers/mfd/tps6594-i2c.c | 2 +- drivers/mfd/tps6594-spi.c | 2 +- include/linux/mfd/tps6594.h | 4 +++- 4 files changed, 15 insertions(+), 9 deletions(-) diff --git a/drivers/mfd/tps6594-core.c b/drivers/mfd/tps6594-core.c index 783ee59901e8..089ab8cc8664 100644 --- a/drivers/mfd/tps6594-core.c +++ b/drivers/mfd/tps6594-core.c @@ -319,12 +319,16 @@ static struct regmap_irq_chip tps6594_irq_chip = { .handle_post_irq = tps6594_handle_post_irq, }; -bool tps6594_is_volatile_reg(struct device *dev, unsigned int reg) -{ - return (reg >= TPS6594_REG_INT_TOP && reg <= TPS6594_REG_STAT_READBACK_ERR) || - reg == TPS6594_REG_RTC_STATUS; -} -EXPORT_SYMBOL_GPL(tps6594_is_volatile_reg); +static const struct regmap_range tps6594_volatile_ranges[] = { + regmap_reg_range(TPS6594_REG_INT_TOP, TPS6594_REG_STAT_READBACK_ERR), + regmap_reg_range(TPS6594_REG_RTC_STATUS, TPS6594_REG_RTC_STATUS), +}; + +const struct regmap_access_table tps6594_volatile_table = { + .yes_ranges = tps6594_volatile_ranges, + .n_yes_ranges = ARRAY_SIZE(tps6594_volatile_ranges), +}; +EXPORT_SYMBOL_GPL(tps6594_volatile_table); static int tps6594_check_crc_mode(struct tps6594 *tps, bool primary_pmic) { diff --git a/drivers/mfd/tps6594-i2c.c b/drivers/mfd/tps6594-i2c.c index 899c88c0fe77..c125b474ba8a 100644 --- a/drivers/mfd/tps6594-i2c.c +++ b/drivers/mfd/tps6594-i2c.c @@ -187,7 +187,7 @@ static const struct regmap_config tps6594_i2c_regmap_config = { .reg_bits = 16, .val_bits = 8, .max_register = TPS6594_REG_DWD_FAIL_CNT_REG, - .volatile_reg = tps6594_is_volatile_reg, + .volatile_table = &tps6594_volatile_table, .read = tps6594_i2c_read, .write = tps6594_i2c_write, }; diff --git a/drivers/mfd/tps6594-spi.c b/drivers/mfd/tps6594-spi.c index 24b72847e3f5..5afb1736f0ae 100644 --- a/drivers/mfd/tps6594-spi.c +++ b/drivers/mfd/tps6594-spi.c @@ -70,7 +70,7 @@ static const struct regmap_config tps6594_spi_regmap_config = { .reg_bits = 16, .val_bits = 8, .max_register = TPS6594_REG_DWD_FAIL_CNT_REG, - .volatile_reg = tps6594_is_volatile_reg, + .volatile_table = &tps6594_volatile_table, .reg_read = tps6594_spi_reg_read, .reg_write = tps6594_spi_reg_write, .use_single_read = true, diff --git a/include/linux/mfd/tps6594.h b/include/linux/mfd/tps6594.h index e754c01acc64..16543fd4d83e 100644 --- a/include/linux/mfd/tps6594.h +++ b/include/linux/mfd/tps6594.h @@ -1337,7 +1337,9 @@ struct tps6594 { struct regmap_irq_chip_data *irq_data; }; -bool tps6594_is_volatile_reg(struct device *dev, unsigned int reg); +extern const struct regmap_access_table tps6594_volatile_table; +extern const struct regmap_access_table tps65224_volatile_table; + int tps6594_device_init(struct tps6594 *tps, bool enable_crc); #endif /* __LINUX_MFD_TPS6594_H */ -- cgit v1.2.3-59-g8ed1b From 91fbd800649f62bcc6a002ae9e0c0b6b5bb3f0d0 Mon Sep 17 00:00:00 2001 From: Bhargav Raviprakash Date: Tue, 30 Apr 2024 13:16:51 +0000 Subject: dt-bindings: mfd: ti,tps6594: Add TI TPS65224 PMIC TPS65224 is a Power Management IC with 4 Buck regulators and 3 LDO regulators, it includes additional features like GPIOs, watchdog, ESMs (Error Signal Monitor), and PFSM (Pre-configurable Finite State Machine) managing the state of the device. In addition TPS65224 has support for 12-bit ADC and does not have RTC unlike TPS6594. Signed-off-by: Bhargav Raviprakash Acked-by: Conor Dooley Link: https://lore.kernel.org/r/0109018f2f26a14f-157bb3a2-2f9b-4653-a619-46e1feb8f229-000000@ap-south-1.amazonses.com Signed-off-by: Lee Jones --- Documentation/devicetree/bindings/mfd/ti,tps6594.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/mfd/ti,tps6594.yaml b/Documentation/devicetree/bindings/mfd/ti,tps6594.yaml index 9d43376bebed..6341b6070366 100644 --- a/Documentation/devicetree/bindings/mfd/ti,tps6594.yaml +++ b/Documentation/devicetree/bindings/mfd/ti,tps6594.yaml @@ -21,6 +21,7 @@ properties: - ti,lp8764-q1 - ti,tps6593-q1 - ti,tps6594-q1 + - ti,tps65224-q1 reg: description: I2C slave address or SPI chip select number. -- cgit v1.2.3-59-g8ed1b From f8e5fc60e6666b46ce113b6b6de221ebba88668f Mon Sep 17 00:00:00 2001 From: Bhargav Raviprakash Date: Tue, 30 Apr 2024 16:33:47 +0000 Subject: mfd: tps6594-i2c: Add TI TPS65224 PMIC I2C Add support for TPS65224 PMIC in TPS6594's I2C driver which has significant functional overlap. Signed-off-by: Bhargav Raviprakash Acked-by: Julien Panis Link: https://lore.kernel.org/r/0109018f2fdaecea-12513236-1059-4227-9078-7b3e0d447cc0-000000@ap-south-1.amazonses.com Signed-off-by: Lee Jones --- drivers/mfd/tps6594-i2c.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/drivers/mfd/tps6594-i2c.c b/drivers/mfd/tps6594-i2c.c index c125b474ba8a..4ab91c34d9fb 100644 --- a/drivers/mfd/tps6594-i2c.c +++ b/drivers/mfd/tps6594-i2c.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * I2C access driver for TI TPS6594/TPS6593/LP8764 PMICs + * I2C access driver for TI TPS65224/TPS6594/TPS6593/LP8764 PMICs * * Copyright (C) 2023 BayLibre Incorporated - https://www.baylibre.com/ */ @@ -183,7 +183,7 @@ static int tps6594_i2c_write(void *context, const void *data, size_t count) return ret; } -static const struct regmap_config tps6594_i2c_regmap_config = { +static struct regmap_config tps6594_i2c_regmap_config = { .reg_bits = 16, .val_bits = 8, .max_register = TPS6594_REG_DWD_FAIL_CNT_REG, @@ -196,6 +196,7 @@ static const struct of_device_id tps6594_i2c_of_match_table[] = { { .compatible = "ti,tps6594-q1", .data = (void *)TPS6594, }, { .compatible = "ti,tps6593-q1", .data = (void *)TPS6593, }, { .compatible = "ti,lp8764-q1", .data = (void *)LP8764, }, + { .compatible = "ti,tps65224-q1", .data = (void *)TPS65224, }, {} }; MODULE_DEVICE_TABLE(of, tps6594_i2c_of_match_table); @@ -216,15 +217,18 @@ static int tps6594_i2c_probe(struct i2c_client *client) tps->reg = client->addr; tps->irq = client->irq; - tps->regmap = devm_regmap_init(dev, NULL, client, &tps6594_i2c_regmap_config); - if (IS_ERR(tps->regmap)) - return dev_err_probe(dev, PTR_ERR(tps->regmap), "Failed to init regmap\n"); - match = of_match_device(tps6594_i2c_of_match_table, dev); if (!match) return dev_err_probe(dev, -EINVAL, "Failed to find matching chip ID\n"); tps->chip_id = (unsigned long)match->data; + if (tps->chip_id == TPS65224) + tps6594_i2c_regmap_config.volatile_table = &tps65224_volatile_table; + + tps->regmap = devm_regmap_init(dev, NULL, client, &tps6594_i2c_regmap_config); + if (IS_ERR(tps->regmap)) + return dev_err_probe(dev, PTR_ERR(tps->regmap), "Failed to init regmap\n"); + crc8_populate_msb(tps6594_i2c_crc_table, TPS6594_CRC8_POLYNOMIAL); return tps6594_device_init(tps, enable_crc); @@ -240,5 +244,5 @@ static struct i2c_driver tps6594_i2c_driver = { module_i2c_driver(tps6594_i2c_driver); MODULE_AUTHOR("Julien Panis "); -MODULE_DESCRIPTION("TPS6594 I2C Interface Driver"); +MODULE_DESCRIPTION("I2C Interface Driver for TPS65224, TPS6594/3, and LP8764"); MODULE_LICENSE("GPL"); -- cgit v1.2.3-59-g8ed1b From 02716864fd5a53e057dcecdb36c807be6494120c Mon Sep 17 00:00:00 2001 From: Bhargav Raviprakash Date: Tue, 30 Apr 2024 16:35:23 +0000 Subject: mfd: tps6594-spi: Add TI TPS65224 PMIC SPI Add support for TPS65224 PMIC in TPS6594's SPI driver which has significant functional overlap. Signed-off-by: Bhargav Raviprakash Acked-by: Julien Panis Link: https://lore.kernel.org/r/0109018f2fdc6328-6d13785c-9832-471b-bdfe-fb1dac3bdc60-000000@ap-south-1.amazonses.com Signed-off-by: Lee Jones --- drivers/mfd/tps6594-spi.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/drivers/mfd/tps6594-spi.c b/drivers/mfd/tps6594-spi.c index 5afb1736f0ae..6ebccb79f0cc 100644 --- a/drivers/mfd/tps6594-spi.c +++ b/drivers/mfd/tps6594-spi.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * SPI access driver for TI TPS6594/TPS6593/LP8764 PMICs + * SPI access driver for TI TPS65224/TPS6594/TPS6593/LP8764 PMICs * * Copyright (C) 2023 BayLibre Incorporated - https://www.baylibre.com/ */ @@ -66,7 +66,7 @@ static int tps6594_spi_reg_write(void *context, unsigned int reg, unsigned int v return spi_write(spi, buf, count); } -static const struct regmap_config tps6594_spi_regmap_config = { +static struct regmap_config tps6594_spi_regmap_config = { .reg_bits = 16, .val_bits = 8, .max_register = TPS6594_REG_DWD_FAIL_CNT_REG, @@ -81,6 +81,7 @@ static const struct of_device_id tps6594_spi_of_match_table[] = { { .compatible = "ti,tps6594-q1", .data = (void *)TPS6594, }, { .compatible = "ti,tps6593-q1", .data = (void *)TPS6593, }, { .compatible = "ti,lp8764-q1", .data = (void *)LP8764, }, + { .compatible = "ti,tps65224-q1", .data = (void *)TPS65224, }, {} }; MODULE_DEVICE_TABLE(of, tps6594_spi_of_match_table); @@ -101,15 +102,18 @@ static int tps6594_spi_probe(struct spi_device *spi) tps->reg = spi_get_chipselect(spi, 0); tps->irq = spi->irq; - tps->regmap = devm_regmap_init(dev, NULL, spi, &tps6594_spi_regmap_config); - if (IS_ERR(tps->regmap)) - return dev_err_probe(dev, PTR_ERR(tps->regmap), "Failed to init regmap\n"); - match = of_match_device(tps6594_spi_of_match_table, dev); if (!match) return dev_err_probe(dev, -EINVAL, "Failed to find matching chip ID\n"); tps->chip_id = (unsigned long)match->data; + if (tps->chip_id == TPS65224) + tps6594_spi_regmap_config.volatile_table = &tps65224_volatile_table; + + tps->regmap = devm_regmap_init(dev, NULL, spi, &tps6594_spi_regmap_config); + if (IS_ERR(tps->regmap)) + return dev_err_probe(dev, PTR_ERR(tps->regmap), "Failed to init regmap\n"); + crc8_populate_msb(tps6594_spi_crc_table, TPS6594_CRC8_POLYNOMIAL); return tps6594_device_init(tps, enable_crc); @@ -125,5 +129,5 @@ static struct spi_driver tps6594_spi_driver = { module_spi_driver(tps6594_spi_driver); MODULE_AUTHOR("Julien Panis "); -MODULE_DESCRIPTION("TPS6594 SPI Interface Driver"); +MODULE_DESCRIPTION("SPI Interface Driver for TPS65224, TPS6594/3, and LP8764"); MODULE_LICENSE("GPL"); -- cgit v1.2.3-59-g8ed1b From 9d855b8144e6016357eecdd9b3fe7cf8c61a1de3 Mon Sep 17 00:00:00 2001 From: Bhargav Raviprakash Date: Tue, 30 Apr 2024 16:35:30 +0000 Subject: mfd: tps6594-core: Add TI TPS65224 PMIC core Add functionality of the TPS65224 PMIC to the TPS6594 core driver. This includes adding IRQ resource, MFD cells, and device initialization for TPS65224. Signed-off-by: Bhargav Raviprakash Acked-by: Julien Panis Link: https://lore.kernel.org/r/0109018f2fdc7df4-b986892b-9dac-4af2-90f5-57fd67ed154d-000000@ap-south-1.amazonses.com Signed-off-by: Lee Jones --- drivers/mfd/tps6594-core.c | 237 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 219 insertions(+), 18 deletions(-) diff --git a/drivers/mfd/tps6594-core.c b/drivers/mfd/tps6594-core.c index 089ab8cc8664..c59f3d7e32b0 100644 --- a/drivers/mfd/tps6594-core.c +++ b/drivers/mfd/tps6594-core.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Core functions for TI TPS6594/TPS6593/LP8764 PMICs + * Core functions for TI TPS65224/TPS6594/TPS6593/LP8764 PMICs * * Copyright (C) 2023 BayLibre Incorporated - https://www.baylibre.com/ */ @@ -278,16 +278,159 @@ static const unsigned int tps6594_irq_reg[] = { TPS6594_REG_RTC_STATUS, }; +/* TPS65224 Resources */ + +static const struct resource tps65224_regulator_resources[] = { + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_BUCK1_UVOV, TPS65224_IRQ_NAME_BUCK1_UVOV), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_BUCK2_UVOV, TPS65224_IRQ_NAME_BUCK2_UVOV), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_BUCK3_UVOV, TPS65224_IRQ_NAME_BUCK3_UVOV), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_BUCK4_UVOV, TPS65224_IRQ_NAME_BUCK4_UVOV), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_LDO1_UVOV, TPS65224_IRQ_NAME_LDO1_UVOV), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_LDO2_UVOV, TPS65224_IRQ_NAME_LDO2_UVOV), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_LDO3_UVOV, TPS65224_IRQ_NAME_LDO3_UVOV), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_VCCA_UVOV, TPS65224_IRQ_NAME_VCCA_UVOV), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_VMON1_UVOV, TPS65224_IRQ_NAME_VMON1_UVOV), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_VMON2_UVOV, TPS65224_IRQ_NAME_VMON2_UVOV), +}; + +static const struct resource tps65224_pinctrl_resources[] = { + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_GPIO1, TPS65224_IRQ_NAME_GPIO1), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_GPIO2, TPS65224_IRQ_NAME_GPIO2), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_GPIO3, TPS65224_IRQ_NAME_GPIO3), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_GPIO4, TPS65224_IRQ_NAME_GPIO4), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_GPIO5, TPS65224_IRQ_NAME_GPIO5), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_GPIO6, TPS65224_IRQ_NAME_GPIO6), +}; + +static const struct resource tps65224_pfsm_resources[] = { + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_VSENSE, TPS65224_IRQ_NAME_VSENSE), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_ENABLE, TPS65224_IRQ_NAME_ENABLE), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_PB_SHORT, TPS65224_IRQ_NAME_PB_SHORT), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_FSD, TPS65224_IRQ_NAME_FSD), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_SOFT_REBOOT, TPS65224_IRQ_NAME_SOFT_REBOOT), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_BIST_PASS, TPS65224_IRQ_NAME_BIST_PASS), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_EXT_CLK, TPS65224_IRQ_NAME_EXT_CLK), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_REG_UNLOCK, TPS65224_IRQ_NAME_REG_UNLOCK), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_TWARN, TPS65224_IRQ_NAME_TWARN), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_PB_LONG, TPS65224_IRQ_NAME_PB_LONG), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_PB_FALL, TPS65224_IRQ_NAME_PB_FALL), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_PB_RISE, TPS65224_IRQ_NAME_PB_RISE), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_TSD_ORD, TPS65224_IRQ_NAME_TSD_ORD), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_BIST_FAIL, TPS65224_IRQ_NAME_BIST_FAIL), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_REG_CRC_ERR, TPS65224_IRQ_NAME_REG_CRC_ERR), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_RECOV_CNT, TPS65224_IRQ_NAME_RECOV_CNT), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_TSD_IMM, TPS65224_IRQ_NAME_TSD_IMM), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_VCCA_OVP, TPS65224_IRQ_NAME_VCCA_OVP), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_PFSM_ERR, TPS65224_IRQ_NAME_PFSM_ERR), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_BG_XMON, TPS65224_IRQ_NAME_BG_XMON), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_IMM_SHUTDOWN, TPS65224_IRQ_NAME_IMM_SHUTDOWN), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_ORD_SHUTDOWN, TPS65224_IRQ_NAME_ORD_SHUTDOWN), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_MCU_PWR_ERR, TPS65224_IRQ_NAME_MCU_PWR_ERR), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_SOC_PWR_ERR, TPS65224_IRQ_NAME_SOC_PWR_ERR), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_COMM_ERR, TPS65224_IRQ_NAME_COMM_ERR), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_I2C2_ERR, TPS65224_IRQ_NAME_I2C2_ERR), +}; + +static const struct resource tps65224_adc_resources[] = { + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_ADC_CONV_READY, TPS65224_IRQ_NAME_ADC_CONV_READY), +}; + +static const struct mfd_cell tps65224_common_cells[] = { + MFD_CELL_RES("tps65224-adc", tps65224_adc_resources), + MFD_CELL_RES("tps6594-pfsm", tps65224_pfsm_resources), + MFD_CELL_RES("tps6594-pinctrl", tps65224_pinctrl_resources), + MFD_CELL_RES("tps6594-regulator", tps65224_regulator_resources), +}; + +static const struct regmap_irq tps65224_irqs[] = { + /* INT_BUCK register */ + REGMAP_IRQ_REG(TPS65224_IRQ_BUCK1_UVOV, 0, TPS65224_BIT_BUCK1_UVOV_INT), + REGMAP_IRQ_REG(TPS65224_IRQ_BUCK2_UVOV, 0, TPS65224_BIT_BUCK2_UVOV_INT), + REGMAP_IRQ_REG(TPS65224_IRQ_BUCK3_UVOV, 0, TPS65224_BIT_BUCK3_UVOV_INT), + REGMAP_IRQ_REG(TPS65224_IRQ_BUCK4_UVOV, 0, TPS65224_BIT_BUCK4_UVOV_INT), + + /* INT_VMON_LDO register */ + REGMAP_IRQ_REG(TPS65224_IRQ_LDO1_UVOV, 1, TPS65224_BIT_LDO1_UVOV_INT), + REGMAP_IRQ_REG(TPS65224_IRQ_LDO2_UVOV, 1, TPS65224_BIT_LDO2_UVOV_INT), + REGMAP_IRQ_REG(TPS65224_IRQ_LDO3_UVOV, 1, TPS65224_BIT_LDO3_UVOV_INT), + REGMAP_IRQ_REG(TPS65224_IRQ_VCCA_UVOV, 1, TPS65224_BIT_VCCA_UVOV_INT), + REGMAP_IRQ_REG(TPS65224_IRQ_VMON1_UVOV, 1, TPS65224_BIT_VMON1_UVOV_INT), + REGMAP_IRQ_REG(TPS65224_IRQ_VMON2_UVOV, 1, TPS65224_BIT_VMON2_UVOV_INT), + + /* INT_GPIO register */ + REGMAP_IRQ_REG(TPS65224_IRQ_GPIO1, 2, TPS65224_BIT_GPIO1_INT), + REGMAP_IRQ_REG(TPS65224_IRQ_GPIO2, 2, TPS65224_BIT_GPIO2_INT), + REGMAP_IRQ_REG(TPS65224_IRQ_GPIO3, 2, TPS65224_BIT_GPIO3_INT), + REGMAP_IRQ_REG(TPS65224_IRQ_GPIO4, 2, TPS65224_BIT_GPIO4_INT), + REGMAP_IRQ_REG(TPS65224_IRQ_GPIO5, 2, TPS65224_BIT_GPIO5_INT), + REGMAP_IRQ_REG(TPS65224_IRQ_GPIO6, 2, TPS65224_BIT_GPIO6_INT), + + /* INT_STARTUP register */ + REGMAP_IRQ_REG(TPS65224_IRQ_VSENSE, 3, TPS65224_BIT_VSENSE_INT), + REGMAP_IRQ_REG(TPS65224_IRQ_ENABLE, 3, TPS6594_BIT_ENABLE_INT), + REGMAP_IRQ_REG(TPS65224_IRQ_PB_SHORT, 3, TPS65224_BIT_PB_SHORT_INT), + REGMAP_IRQ_REG(TPS65224_IRQ_FSD, 3, TPS6594_BIT_FSD_INT), + REGMAP_IRQ_REG(TPS65224_IRQ_SOFT_REBOOT, 3, TPS6594_BIT_SOFT_REBOOT_INT), + + /* INT_MISC register */ + REGMAP_IRQ_REG(TPS65224_IRQ_BIST_PASS, 4, TPS6594_BIT_BIST_PASS_INT), + REGMAP_IRQ_REG(TPS65224_IRQ_EXT_CLK, 4, TPS6594_BIT_EXT_CLK_INT), + REGMAP_IRQ_REG(TPS65224_IRQ_REG_UNLOCK, 4, TPS65224_BIT_REG_UNLOCK_INT), + REGMAP_IRQ_REG(TPS65224_IRQ_TWARN, 4, TPS6594_BIT_TWARN_INT), + REGMAP_IRQ_REG(TPS65224_IRQ_PB_LONG, 4, TPS65224_BIT_PB_LONG_INT), + REGMAP_IRQ_REG(TPS65224_IRQ_PB_FALL, 4, TPS65224_BIT_PB_FALL_INT), + REGMAP_IRQ_REG(TPS65224_IRQ_PB_RISE, 4, TPS65224_BIT_PB_RISE_INT), + REGMAP_IRQ_REG(TPS65224_IRQ_ADC_CONV_READY, 4, TPS65224_BIT_ADC_CONV_READY_INT), + + /* INT_MODERATE_ERR register */ + REGMAP_IRQ_REG(TPS65224_IRQ_TSD_ORD, 5, TPS6594_BIT_TSD_ORD_INT), + REGMAP_IRQ_REG(TPS65224_IRQ_BIST_FAIL, 5, TPS6594_BIT_BIST_FAIL_INT), + REGMAP_IRQ_REG(TPS65224_IRQ_REG_CRC_ERR, 5, TPS6594_BIT_REG_CRC_ERR_INT), + REGMAP_IRQ_REG(TPS65224_IRQ_RECOV_CNT, 5, TPS6594_BIT_RECOV_CNT_INT), + + /* INT_SEVERE_ERR register */ + REGMAP_IRQ_REG(TPS65224_IRQ_TSD_IMM, 6, TPS6594_BIT_TSD_IMM_INT), + REGMAP_IRQ_REG(TPS65224_IRQ_VCCA_OVP, 6, TPS6594_BIT_VCCA_OVP_INT), + REGMAP_IRQ_REG(TPS65224_IRQ_PFSM_ERR, 6, TPS6594_BIT_PFSM_ERR_INT), + REGMAP_IRQ_REG(TPS65224_IRQ_BG_XMON, 6, TPS65224_BIT_BG_XMON_INT), + + /* INT_FSM_ERR register */ + REGMAP_IRQ_REG(TPS65224_IRQ_IMM_SHUTDOWN, 7, TPS6594_BIT_IMM_SHUTDOWN_INT), + REGMAP_IRQ_REG(TPS65224_IRQ_ORD_SHUTDOWN, 7, TPS6594_BIT_ORD_SHUTDOWN_INT), + REGMAP_IRQ_REG(TPS65224_IRQ_MCU_PWR_ERR, 7, TPS6594_BIT_MCU_PWR_ERR_INT), + REGMAP_IRQ_REG(TPS65224_IRQ_SOC_PWR_ERR, 7, TPS6594_BIT_SOC_PWR_ERR_INT), + REGMAP_IRQ_REG(TPS65224_IRQ_COMM_ERR, 7, TPS6594_BIT_COMM_ERR_INT), + REGMAP_IRQ_REG(TPS65224_IRQ_I2C2_ERR, 7, TPS65224_BIT_I2C2_ERR_INT), +}; + +static const unsigned int tps65224_irq_reg[] = { + TPS6594_REG_INT_BUCK, + TPS6594_REG_INT_LDO_VMON, + TPS6594_REG_INT_GPIO, + TPS6594_REG_INT_STARTUP, + TPS6594_REG_INT_MISC, + TPS6594_REG_INT_MODERATE_ERR, + TPS6594_REG_INT_SEVERE_ERR, + TPS6594_REG_INT_FSM_ERR, +}; + static inline unsigned int tps6594_get_irq_reg(struct regmap_irq_chip_data *data, unsigned int base, int index) { return tps6594_irq_reg[index]; }; +static inline unsigned int tps65224_get_irq_reg(struct regmap_irq_chip_data *data, + unsigned int base, int index) +{ + return tps65224_irq_reg[index]; +}; + static int tps6594_handle_post_irq(void *irq_drv_data) { struct tps6594 *tps = irq_drv_data; int ret = 0; + unsigned int regmap_reg, mask_val; /* * When CRC is enabled, writing to a read-only bit triggers an error, @@ -299,10 +442,17 @@ static int tps6594_handle_post_irq(void *irq_drv_data) * COMM_ADR_ERR_INT bit set. Clear immediately this bit to avoid raising * a new interrupt. */ - if (tps->use_crc) - ret = regmap_write_bits(tps->regmap, TPS6594_REG_INT_COMM_ERR, - TPS6594_BIT_COMM_ADR_ERR_INT, - TPS6594_BIT_COMM_ADR_ERR_INT); + if (tps->use_crc) { + if (tps->chip_id == TPS65224) { + regmap_reg = TPS6594_REG_INT_FSM_ERR; + mask_val = TPS6594_BIT_COMM_ERR_INT; + } else { + regmap_reg = TPS6594_REG_INT_COMM_ERR; + mask_val = TPS6594_BIT_COMM_ADR_ERR_INT; + } + + ret = regmap_write_bits(tps->regmap, regmap_reg, mask_val, mask_val); + } return ret; }; @@ -319,6 +469,18 @@ static struct regmap_irq_chip tps6594_irq_chip = { .handle_post_irq = tps6594_handle_post_irq, }; +static struct regmap_irq_chip tps65224_irq_chip = { + .ack_base = TPS6594_REG_INT_BUCK, + .ack_invert = 1, + .clear_ack = 1, + .init_ack_masked = 1, + .num_regs = ARRAY_SIZE(tps65224_irq_reg), + .irqs = tps65224_irqs, + .num_irqs = ARRAY_SIZE(tps65224_irqs), + .get_irq_reg = tps65224_get_irq_reg, + .handle_post_irq = tps6594_handle_post_irq, +}; + static const struct regmap_range tps6594_volatile_ranges[] = { regmap_reg_range(TPS6594_REG_INT_TOP, TPS6594_REG_STAT_READBACK_ERR), regmap_reg_range(TPS6594_REG_RTC_STATUS, TPS6594_REG_RTC_STATUS), @@ -330,17 +492,35 @@ const struct regmap_access_table tps6594_volatile_table = { }; EXPORT_SYMBOL_GPL(tps6594_volatile_table); +static const struct regmap_range tps65224_volatile_ranges[] = { + regmap_reg_range(TPS6594_REG_INT_TOP, TPS6594_REG_STAT_SEVERE_ERR), +}; + +const struct regmap_access_table tps65224_volatile_table = { + .yes_ranges = tps65224_volatile_ranges, + .n_yes_ranges = ARRAY_SIZE(tps65224_volatile_ranges), +}; +EXPORT_SYMBOL_GPL(tps65224_volatile_table); + static int tps6594_check_crc_mode(struct tps6594 *tps, bool primary_pmic) { int ret; + unsigned int regmap_reg, mask_val; + + if (tps->chip_id == TPS65224) { + regmap_reg = TPS6594_REG_CONFIG_2; + mask_val = TPS65224_BIT_I2C1_SPI_CRC_EN; + } else { + regmap_reg = TPS6594_REG_SERIAL_IF_CONFIG; + mask_val = TPS6594_BIT_I2C1_SPI_CRC_EN; + }; /* * Check if CRC is enabled. * Once CRC is enabled, it can't be disabled until next power cycle. */ tps->use_crc = true; - ret = regmap_test_bits(tps->regmap, TPS6594_REG_SERIAL_IF_CONFIG, - TPS6594_BIT_I2C1_SPI_CRC_EN); + ret = regmap_test_bits(tps->regmap, regmap_reg, mask_val); if (ret == 0) { ret = -EIO; } else if (ret > 0) { @@ -355,6 +535,15 @@ static int tps6594_check_crc_mode(struct tps6594 *tps, bool primary_pmic) static int tps6594_set_crc_feature(struct tps6594 *tps) { int ret; + unsigned int regmap_reg, mask_val; + + if (tps->chip_id == TPS65224) { + regmap_reg = TPS6594_REG_CONFIG_2; + mask_val = TPS65224_BIT_I2C1_SPI_CRC_EN; + } else { + regmap_reg = TPS6594_REG_FSM_I2C_TRIGGERS; + mask_val = TPS6594_BIT_TRIGGER_I2C(2); + } ret = tps6594_check_crc_mode(tps, true); if (ret) { @@ -363,8 +552,7 @@ static int tps6594_set_crc_feature(struct tps6594 *tps) * on primary PMIC. */ tps->use_crc = false; - ret = regmap_write_bits(tps->regmap, TPS6594_REG_FSM_I2C_TRIGGERS, - TPS6594_BIT_TRIGGER_I2C(2), TPS6594_BIT_TRIGGER_I2C(2)); + ret = regmap_write_bits(tps->regmap, regmap_reg, mask_val, mask_val); if (ret) return ret; @@ -420,6 +608,9 @@ int tps6594_device_init(struct tps6594 *tps, bool enable_crc) { struct device *dev = tps->dev; int ret; + struct regmap_irq_chip *irq_chip; + const struct mfd_cell *cells; + int n_cells; if (enable_crc) { ret = tps6594_enable_crc(tps); @@ -433,26 +624,35 @@ int tps6594_device_init(struct tps6594 *tps, bool enable_crc) if (ret) return dev_err_probe(dev, ret, "Failed to set PMIC state\n"); - tps6594_irq_chip.irq_drv_data = tps; - tps6594_irq_chip.name = devm_kasprintf(dev, GFP_KERNEL, "%s-%ld-0x%02x", - dev->driver->name, tps->chip_id, tps->reg); + if (tps->chip_id == TPS65224) { + irq_chip = &tps65224_irq_chip; + n_cells = ARRAY_SIZE(tps65224_common_cells); + cells = tps65224_common_cells; + } else { + irq_chip = &tps6594_irq_chip; + n_cells = ARRAY_SIZE(tps6594_common_cells); + cells = tps6594_common_cells; + } + + irq_chip->irq_drv_data = tps; + irq_chip->name = devm_kasprintf(dev, GFP_KERNEL, "%s-%ld-0x%02x", + dev->driver->name, tps->chip_id, tps->reg); - if (!tps6594_irq_chip.name) + if (!irq_chip->name) return -ENOMEM; ret = devm_regmap_add_irq_chip(dev, tps->regmap, tps->irq, IRQF_SHARED | IRQF_ONESHOT, - 0, &tps6594_irq_chip, &tps->irq_data); + 0, irq_chip, &tps->irq_data); if (ret) return dev_err_probe(dev, ret, "Failed to add regmap IRQ\n"); - ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO, tps6594_common_cells, - ARRAY_SIZE(tps6594_common_cells), NULL, 0, + ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO, cells, n_cells, NULL, 0, regmap_irq_get_domain(tps->irq_data)); if (ret) return dev_err_probe(dev, ret, "Failed to add common child devices\n"); - /* No RTC for LP8764 */ - if (tps->chip_id != LP8764) { + /* No RTC for LP8764 and TPS65224 */ + if (tps->chip_id != LP8764 && tps->chip_id != TPS65224) { ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO, tps6594_rtc_cells, ARRAY_SIZE(tps6594_rtc_cells), NULL, 0, regmap_irq_get_domain(tps->irq_data)); @@ -465,5 +665,6 @@ int tps6594_device_init(struct tps6594 *tps, bool enable_crc) EXPORT_SYMBOL_GPL(tps6594_device_init); MODULE_AUTHOR("Julien Panis "); +MODULE_AUTHOR("Bhargav Raviprakash Date: Tue, 30 Apr 2024 16:35:38 +0000 Subject: misc: tps6594-pfsm: Add TI TPS65224 PMIC PFSM Add support for TPS65224 PFSM in the TPS6594 PFSM driver as they share significant functionality. Signed-off-by: Bhargav Raviprakash Acked-by: Julien Panis Acked-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/0109018f2fdc9dc4-db5a45c0-0148-48cc-8462-d1c5b577a4bd-000000@ap-south-1.amazonses.com Signed-off-by: Lee Jones --- drivers/misc/tps6594-pfsm.c | 48 +++++++++++++++++++++++++++++++++------------ 1 file changed, 35 insertions(+), 13 deletions(-) diff --git a/drivers/misc/tps6594-pfsm.c b/drivers/misc/tps6594-pfsm.c index 88dcac814892..9bcca1856bfe 100644 --- a/drivers/misc/tps6594-pfsm.c +++ b/drivers/misc/tps6594-pfsm.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * PFSM (Pre-configurable Finite State Machine) driver for TI TPS6594/TPS6593/LP8764 PMICs + * PFSM (Pre-configurable Finite State Machine) driver for TI TPS65224/TPS6594/TPS6593/LP8764 PMICs * * Copyright (C) 2023 BayLibre Incorporated - https://www.baylibre.com/ */ @@ -39,10 +39,12 @@ * * @miscdev: misc device infos * @regmap: regmap for accessing the device registers + * @chip_id: chip identifier of the device */ struct tps6594_pfsm { struct miscdevice miscdev; struct regmap *regmap; + unsigned long chip_id; }; static ssize_t tps6594_pfsm_read(struct file *f, char __user *buf, @@ -133,21 +135,29 @@ static long tps6594_pfsm_ioctl(struct file *f, unsigned int cmd, unsigned long a struct tps6594_pfsm *pfsm = TPS6594_FILE_TO_PFSM(f); struct pmic_state_opt state_opt; void __user *argp = (void __user *)arg; + unsigned int regmap_reg, mask; int ret = -ENOIOCTLCMD; switch (cmd) { case PMIC_GOTO_STANDBY: - /* Disable LP mode */ - ret = regmap_clear_bits(pfsm->regmap, TPS6594_REG_RTC_CTRL_2, - TPS6594_BIT_LP_STANDBY_SEL); - if (ret) - return ret; + /* Disable LP mode on TPS6594 Family PMIC */ + if (pfsm->chip_id != TPS65224) { + ret = regmap_clear_bits(pfsm->regmap, TPS6594_REG_RTC_CTRL_2, + TPS6594_BIT_LP_STANDBY_SEL); + + if (ret) + return ret; + } /* Force trigger */ ret = regmap_write_bits(pfsm->regmap, TPS6594_REG_FSM_I2C_TRIGGERS, TPS6594_BIT_TRIGGER_I2C(0), TPS6594_BIT_TRIGGER_I2C(0)); break; case PMIC_GOTO_LP_STANDBY: + /* TPS65224 does not support LP STANDBY */ + if (pfsm->chip_id == TPS65224) + return ret; + /* Enable LP mode */ ret = regmap_set_bits(pfsm->regmap, TPS6594_REG_RTC_CTRL_2, TPS6594_BIT_LP_STANDBY_SEL); @@ -169,6 +179,10 @@ static long tps6594_pfsm_ioctl(struct file *f, unsigned int cmd, unsigned long a TPS6594_BIT_NSLEEP1B | TPS6594_BIT_NSLEEP2B); break; case PMIC_SET_MCU_ONLY_STATE: + /* TPS65224 does not support MCU_ONLY_STATE */ + if (pfsm->chip_id == TPS65224) + return ret; + if (copy_from_user(&state_opt, argp, sizeof(state_opt))) return -EFAULT; @@ -192,14 +206,20 @@ static long tps6594_pfsm_ioctl(struct file *f, unsigned int cmd, unsigned long a return -EFAULT; /* Configure wake-up destination */ + if (pfsm->chip_id == TPS65224) { + regmap_reg = TPS65224_REG_STARTUP_CTRL; + mask = TPS65224_MASK_STARTUP_DEST; + } else { + regmap_reg = TPS6594_REG_RTC_CTRL_2; + mask = TPS6594_MASK_STARTUP_DEST; + } + if (state_opt.mcu_only_startup_dest) - ret = regmap_write_bits(pfsm->regmap, TPS6594_REG_RTC_CTRL_2, - TPS6594_MASK_STARTUP_DEST, - TPS6594_STARTUP_DEST_MCU_ONLY); + ret = regmap_write_bits(pfsm->regmap, regmap_reg, + mask, TPS6594_STARTUP_DEST_MCU_ONLY); else - ret = regmap_write_bits(pfsm->regmap, TPS6594_REG_RTC_CTRL_2, - TPS6594_MASK_STARTUP_DEST, - TPS6594_STARTUP_DEST_ACTIVE); + ret = regmap_write_bits(pfsm->regmap, regmap_reg, + mask, TPS6594_STARTUP_DEST_ACTIVE); if (ret) return ret; @@ -211,7 +231,8 @@ static long tps6594_pfsm_ioctl(struct file *f, unsigned int cmd, unsigned long a /* Modify NSLEEP1-2 bits */ ret = regmap_clear_bits(pfsm->regmap, TPS6594_REG_FSM_NSLEEP_TRIGGERS, - TPS6594_BIT_NSLEEP2B); + pfsm->chip_id == TPS65224 ? + TPS6594_BIT_NSLEEP1B : TPS6594_BIT_NSLEEP2B); break; } @@ -262,6 +283,7 @@ static int tps6594_pfsm_probe(struct platform_device *pdev) tps->chip_id, tps->reg); pfsm->miscdev.fops = &tps6594_pfsm_fops; pfsm->miscdev.parent = dev->parent; + pfsm->chip_id = tps->chip_id; for (i = 0 ; i < pdev->num_resources ; i++) { irq = platform_get_irq_byname(pdev, pdev->resource[i].name); -- cgit v1.2.3-59-g8ed1b From 00c826525fbae0230f6c3e9879e56d50267deb42 Mon Sep 17 00:00:00 2001 From: Nirmala Devi Mal Nadar Date: Tue, 30 Apr 2024 16:35:48 +0000 Subject: regulator: tps6594-regulator: Add TI TPS65224 PMIC regulators Add support for TPS65224 regulators (bucks and LDOs) to TPS6594 driver as they have significant functional overlap. TPS65224 PMIC has 4 buck regulators and 3 LDOs. BUCK12 can operate in dual phase. The output voltages are configurable and are meant to supply power to the main processor and other components. Signed-off-by: Nirmala Devi Mal Nadar Signed-off-by: Bhargav Raviprakash Reviewed-by: Mark Brown Link: https://lore.kernel.org/r/0109018f2fdcc305-3b817569-21b6-42a7-942c-8edbff3848f2-000000@ap-south-1.amazonses.com Signed-off-by: Lee Jones --- drivers/regulator/Kconfig | 4 +- drivers/regulator/tps6594-regulator.c | 334 +++++++++++++++++++++++++++------- 2 files changed, 268 insertions(+), 70 deletions(-) diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 7db0a29b5b8d..1e4119f00e0f 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -1563,13 +1563,15 @@ config REGULATOR_TPS6594 depends on MFD_TPS6594 && OF default MFD_TPS6594 help - This driver supports TPS6594 voltage regulator chips. + This driver supports TPS6594 series and TPS65224 voltage regulator chips. TPS6594 series of PMICs have 5 BUCKs and 4 LDOs voltage regulators. BUCKs 1,2,3,4 can be used in single phase or multiphase mode. Part number defines which single or multiphase mode is i used. It supports software based voltage control for different voltage domains. + TPS65224 PMIC has 4 BUCKs and 3 LDOs. BUCK12 can be used in dual phase. + All BUCKs and LDOs volatge can be controlled through software. config REGULATOR_TPS6524X tristate "TI TPS6524X Power regulators" diff --git a/drivers/regulator/tps6594-regulator.c b/drivers/regulator/tps6594-regulator.c index b7f0c8779757..9e7886bd4149 100644 --- a/drivers/regulator/tps6594-regulator.c +++ b/drivers/regulator/tps6594-regulator.c @@ -18,10 +18,13 @@ #include -#define BUCK_NB 5 -#define LDO_NB 4 -#define MULTI_PHASE_NB 4 -#define REGS_INT_NB 4 +#define BUCK_NB 5 +#define LDO_NB 4 +#define MULTI_PHASE_NB 4 +/* TPS6593 and LP8764 supports OV, UV, SC, ILIM */ +#define REGS_INT_NB 4 +/* TPS65224 supports OV or UV */ +#define TPS65224_REGS_INT_NB 1 enum tps6594_regulator_id { /* DCDC's */ @@ -66,6 +69,15 @@ static struct tps6594_regulator_irq_type tps6594_ext_regulator_irq_types[] = { REGULATOR_EVENT_OVER_VOLTAGE_WARN }, }; +static struct tps6594_regulator_irq_type tps65224_ext_regulator_irq_types[] = { + { TPS65224_IRQ_NAME_VCCA_UVOV, "VCCA", "voltage out of range", + REGULATOR_EVENT_REGULATION_OUT }, + { TPS65224_IRQ_NAME_VMON1_UVOV, "VMON1", "voltage out of range", + REGULATOR_EVENT_REGULATION_OUT }, + { TPS65224_IRQ_NAME_VMON2_UVOV, "VMON2", "voltage out of range", + REGULATOR_EVENT_REGULATION_OUT }, +}; + struct tps6594_regulator_irq_data { struct device *dev; struct tps6594_regulator_irq_type *type; @@ -122,6 +134,27 @@ static const struct linear_range ldos_4_ranges[] = { REGULATOR_LINEAR_RANGE(1200000, 0x20, 0x74, 25000), }; +/* Voltage range for TPS65224 Bucks and LDOs */ +static const struct linear_range tps65224_bucks_1_ranges[] = { + REGULATOR_LINEAR_RANGE(500000, 0x0a, 0x0e, 20000), + REGULATOR_LINEAR_RANGE(600000, 0x0f, 0x72, 5000), + REGULATOR_LINEAR_RANGE(1100000, 0x73, 0xaa, 10000), + REGULATOR_LINEAR_RANGE(1660000, 0xab, 0xfd, 20000), +}; + +static const struct linear_range tps65224_bucks_2_3_4_ranges[] = { + REGULATOR_LINEAR_RANGE(500000, 0x0, 0x1a, 25000), + REGULATOR_LINEAR_RANGE(1200000, 0x1b, 0x45, 50000), +}; + +static const struct linear_range tps65224_ldos_1_ranges[] = { + REGULATOR_LINEAR_RANGE(1200000, 0xC, 0x36, 50000), +}; + +static const struct linear_range tps65224_ldos_2_3_ranges[] = { + REGULATOR_LINEAR_RANGE(600000, 0x0, 0x38, 50000), +}; + /* Operations permitted on BUCK1/2/3/4/5 */ static const struct regulator_ops tps6594_bucks_ops = { .is_enabled = regulator_is_enabled_regmap, @@ -197,6 +230,38 @@ static const struct regulator_desc buck_regs[] = { 4, 0, 0, NULL, 0, 0), }; +/* Buck configuration for TPS65224 */ +static const struct regulator_desc tps65224_buck_regs[] = { + TPS6594_REGULATOR("BUCK1", "buck1", TPS6594_BUCK_1, + REGULATOR_VOLTAGE, tps6594_bucks_ops, TPS65224_MASK_BUCK1_VSET, + TPS6594_REG_BUCKX_VOUT_1(0), + TPS65224_MASK_BUCK1_VSET, + TPS6594_REG_BUCKX_CTRL(0), + TPS6594_BIT_BUCK_EN, 0, 0, tps65224_bucks_1_ranges, + 4, 0, 0, NULL, 0, 0), + TPS6594_REGULATOR("BUCK2", "buck2", TPS6594_BUCK_2, + REGULATOR_VOLTAGE, tps6594_bucks_ops, TPS65224_MASK_BUCKS_VSET, + TPS6594_REG_BUCKX_VOUT_1(1), + TPS65224_MASK_BUCKS_VSET, + TPS6594_REG_BUCKX_CTRL(1), + TPS6594_BIT_BUCK_EN, 0, 0, tps65224_bucks_2_3_4_ranges, + 4, 0, 0, NULL, 0, 0), + TPS6594_REGULATOR("BUCK3", "buck3", TPS6594_BUCK_3, + REGULATOR_VOLTAGE, tps6594_bucks_ops, TPS65224_MASK_BUCKS_VSET, + TPS6594_REG_BUCKX_VOUT_1(2), + TPS65224_MASK_BUCKS_VSET, + TPS6594_REG_BUCKX_CTRL(2), + TPS6594_BIT_BUCK_EN, 0, 0, tps65224_bucks_2_3_4_ranges, + 4, 0, 0, NULL, 0, 0), + TPS6594_REGULATOR("BUCK4", "buck4", TPS6594_BUCK_4, + REGULATOR_VOLTAGE, tps6594_bucks_ops, TPS65224_MASK_BUCKS_VSET, + TPS6594_REG_BUCKX_VOUT_1(3), + TPS65224_MASK_BUCKS_VSET, + TPS6594_REG_BUCKX_CTRL(3), + TPS6594_BIT_BUCK_EN, 0, 0, tps65224_bucks_2_3_4_ranges, + 4, 0, 0, NULL, 0, 0), +}; + static struct tps6594_regulator_irq_type tps6594_buck1_irq_types[] = { { TPS6594_IRQ_NAME_BUCK1_OV, "BUCK1", "overvoltage", REGULATOR_EVENT_OVER_VOLTAGE_WARN }, { TPS6594_IRQ_NAME_BUCK1_UV, "BUCK1", "undervoltage", REGULATOR_EVENT_UNDER_VOLTAGE }, @@ -269,6 +334,41 @@ static struct tps6594_regulator_irq_type tps6594_ldo4_irq_types[] = { REGULATOR_EVENT_OVER_CURRENT }, }; +static struct tps6594_regulator_irq_type tps65224_buck1_irq_types[] = { + { TPS65224_IRQ_NAME_BUCK1_UVOV, "BUCK1", "voltage out of range", + REGULATOR_EVENT_REGULATION_OUT }, +}; + +static struct tps6594_regulator_irq_type tps65224_buck2_irq_types[] = { + { TPS65224_IRQ_NAME_BUCK2_UVOV, "BUCK2", "voltage out of range", + REGULATOR_EVENT_REGULATION_OUT }, +}; + +static struct tps6594_regulator_irq_type tps65224_buck3_irq_types[] = { + { TPS65224_IRQ_NAME_BUCK3_UVOV, "BUCK3", "voltage out of range", + REGULATOR_EVENT_REGULATION_OUT }, +}; + +static struct tps6594_regulator_irq_type tps65224_buck4_irq_types[] = { + { TPS65224_IRQ_NAME_BUCK4_UVOV, "BUCK4", "voltage out of range", + REGULATOR_EVENT_REGULATION_OUT }, +}; + +static struct tps6594_regulator_irq_type tps65224_ldo1_irq_types[] = { + { TPS65224_IRQ_NAME_LDO1_UVOV, "LDO1", "voltage out of range", + REGULATOR_EVENT_REGULATION_OUT }, +}; + +static struct tps6594_regulator_irq_type tps65224_ldo2_irq_types[] = { + { TPS65224_IRQ_NAME_LDO2_UVOV, "LDO2", "voltage out of range", + REGULATOR_EVENT_REGULATION_OUT }, +}; + +static struct tps6594_regulator_irq_type tps65224_ldo3_irq_types[] = { + { TPS65224_IRQ_NAME_LDO3_UVOV, "LDO3", "voltage out of range", + REGULATOR_EVENT_REGULATION_OUT }, +}; + static struct tps6594_regulator_irq_type *tps6594_bucks_irq_types[] = { tps6594_buck1_irq_types, tps6594_buck2_irq_types, @@ -284,7 +384,20 @@ static struct tps6594_regulator_irq_type *tps6594_ldos_irq_types[] = { tps6594_ldo4_irq_types, }; -static const struct regulator_desc multi_regs[] = { +static struct tps6594_regulator_irq_type *tps65224_bucks_irq_types[] = { + tps65224_buck1_irq_types, + tps65224_buck2_irq_types, + tps65224_buck3_irq_types, + tps65224_buck4_irq_types, +}; + +static struct tps6594_regulator_irq_type *tps65224_ldos_irq_types[] = { + tps65224_ldo1_irq_types, + tps65224_ldo2_irq_types, + tps65224_ldo3_irq_types, +}; + +static const struct regulator_desc tps6594_multi_regs[] = { TPS6594_REGULATOR("BUCK12", "buck12", TPS6594_BUCK_1, REGULATOR_VOLTAGE, tps6594_bucks_ops, TPS6594_MASK_BUCKS_VSET, TPS6594_REG_BUCKX_VOUT_1(1), @@ -315,7 +428,17 @@ static const struct regulator_desc multi_regs[] = { 4, 4000, 0, NULL, 0, 0), }; -static const struct regulator_desc ldo_regs[] = { +static const struct regulator_desc tps65224_multi_regs[] = { + TPS6594_REGULATOR("BUCK12", "buck12", TPS6594_BUCK_1, + REGULATOR_VOLTAGE, tps6594_bucks_ops, TPS65224_MASK_BUCK1_VSET, + TPS6594_REG_BUCKX_VOUT_1(0), + TPS65224_MASK_BUCK1_VSET, + TPS6594_REG_BUCKX_CTRL(0), + TPS6594_BIT_BUCK_EN, 0, 0, tps65224_bucks_1_ranges, + 4, 4000, 0, NULL, 0, 0), +}; + +static const struct regulator_desc tps6594_ldo_regs[] = { TPS6594_REGULATOR("LDO1", "ldo1", TPS6594_LDO_1, REGULATOR_VOLTAGE, tps6594_ldos_1_2_3_ops, TPS6594_MASK_LDO123_VSET, TPS6594_REG_LDOX_VOUT(0), @@ -346,6 +469,30 @@ static const struct regulator_desc ldo_regs[] = { 1, 0, 0, NULL, 0, 0), }; +static const struct regulator_desc tps65224_ldo_regs[] = { + TPS6594_REGULATOR("LDO1", "ldo1", TPS6594_LDO_1, + REGULATOR_VOLTAGE, tps6594_ldos_1_2_3_ops, TPS6594_MASK_LDO123_VSET, + TPS6594_REG_LDOX_VOUT(0), + TPS6594_MASK_LDO123_VSET, + TPS6594_REG_LDOX_CTRL(0), + TPS6594_BIT_LDO_EN, 0, 0, tps65224_ldos_1_ranges, + 1, 0, 0, NULL, 0, TPS6594_BIT_LDO_BYPASS), + TPS6594_REGULATOR("LDO2", "ldo2", TPS6594_LDO_2, + REGULATOR_VOLTAGE, tps6594_ldos_1_2_3_ops, TPS6594_MASK_LDO123_VSET, + TPS6594_REG_LDOX_VOUT(1), + TPS6594_MASK_LDO123_VSET, + TPS6594_REG_LDOX_CTRL(1), + TPS6594_BIT_LDO_EN, 0, 0, tps65224_ldos_2_3_ranges, + 1, 0, 0, NULL, 0, TPS6594_BIT_LDO_BYPASS), + TPS6594_REGULATOR("LDO3", "ldo3", TPS6594_LDO_3, + REGULATOR_VOLTAGE, tps6594_ldos_1_2_3_ops, TPS6594_MASK_LDO123_VSET, + TPS6594_REG_LDOX_VOUT(2), + TPS6594_MASK_LDO123_VSET, + TPS6594_REG_LDOX_CTRL(2), + TPS6594_BIT_LDO_EN, 0, 0, tps65224_ldos_2_3_ranges, + 1, 0, 0, NULL, 0, TPS6594_BIT_LDO_BYPASS), +}; + static irqreturn_t tps6594_regulator_irq_handler(int irq, void *data) { struct tps6594_regulator_irq_data *irq_data = data; @@ -369,17 +516,18 @@ static irqreturn_t tps6594_regulator_irq_handler(int irq, void *data) static int tps6594_request_reg_irqs(struct platform_device *pdev, struct regulator_dev *rdev, struct tps6594_regulator_irq_data *irq_data, - struct tps6594_regulator_irq_type *tps6594_regs_irq_types, + struct tps6594_regulator_irq_type *regs_irq_types, + size_t interrupt_cnt, int *irq_idx) { struct tps6594_regulator_irq_type *irq_type; struct tps6594 *tps = dev_get_drvdata(pdev->dev.parent); - int j; + size_t j; int irq; int error; - for (j = 0; j < REGS_INT_NB; j++) { - irq_type = &tps6594_regs_irq_types[j]; + for (j = 0; j < interrupt_cnt; j++) { + irq_type = ®s_irq_types[j]; irq = platform_get_irq_byname(pdev, irq_type->irq_name); if (irq < 0) return -EINVAL; @@ -411,23 +559,47 @@ static int tps6594_regulator_probe(struct platform_device *pdev) struct tps6594_regulator_irq_data *irq_data; struct tps6594_ext_regulator_irq_data *irq_ext_reg_data; struct tps6594_regulator_irq_type *irq_type; - u8 buck_configured[BUCK_NB] = { 0 }; - u8 buck_multi[MULTI_PHASE_NB] = { 0 }; - static const char * const multiphases[] = {"buck12", "buck123", "buck1234", "buck34"}; + struct tps6594_regulator_irq_type *irq_types; + bool buck_configured[BUCK_NB] = { false }; + bool buck_multi[MULTI_PHASE_NB] = { false }; + static const char *npname; - int error, i, irq, multi, delta; + int error, i, irq, multi; int irq_idx = 0; int buck_idx = 0; - size_t ext_reg_irq_nb = 2; + int nr_ldo; + int nr_buck; + int nr_types; + unsigned int irq_count; + unsigned int multi_phase_cnt; size_t reg_irq_nb; + struct tps6594_regulator_irq_type **bucks_irq_types; + const struct regulator_desc *multi_regs; + struct tps6594_regulator_irq_type **ldos_irq_types; + const struct regulator_desc *ldo_regs; + size_t interrupt_count; + + if (tps->chip_id == TPS65224) { + bucks_irq_types = tps65224_bucks_irq_types; + interrupt_count = ARRAY_SIZE(tps65224_buck1_irq_types); + multi_regs = tps65224_multi_regs; + ldos_irq_types = tps65224_ldos_irq_types; + ldo_regs = tps65224_ldo_regs; + multi_phase_cnt = ARRAY_SIZE(tps65224_multi_regs); + } else { + bucks_irq_types = tps6594_bucks_irq_types; + interrupt_count = ARRAY_SIZE(tps6594_buck1_irq_types); + multi_regs = tps6594_multi_regs; + ldos_irq_types = tps6594_ldos_irq_types; + ldo_regs = tps6594_ldo_regs; + multi_phase_cnt = ARRAY_SIZE(tps6594_multi_regs); + } + enum { MULTI_BUCK12, + MULTI_BUCK12_34, MULTI_BUCK123, MULTI_BUCK1234, - MULTI_BUCK12_34, - MULTI_FIRST = MULTI_BUCK12, - MULTI_LAST = MULTI_BUCK12_34, - MULTI_NUM = MULTI_LAST - MULTI_FIRST + 1 }; config.dev = tps->dev; @@ -442,61 +614,68 @@ static int tps6594_regulator_probe(struct platform_device *pdev) * In case of Multiphase configuration, value should be defined for * buck_configured to avoid creating bucks for every buck in multiphase */ - for (multi = MULTI_FIRST; multi < MULTI_NUM; multi++) { - np = of_find_node_by_name(tps->dev->of_node, multiphases[multi]); + for (multi = 0; multi < multi_phase_cnt; multi++) { + np = of_find_node_by_name(tps->dev->of_node, multi_regs[multi].supply_name); npname = of_node_full_name(np); np_pmic_parent = of_get_parent(of_get_parent(np)); if (of_node_cmp(of_node_full_name(np_pmic_parent), tps->dev->of_node->full_name)) continue; - delta = strcmp(npname, multiphases[multi]); - if (!delta) { + if (strcmp(npname, multi_regs[multi].supply_name) == 0) { switch (multi) { case MULTI_BUCK12: - buck_multi[0] = 1; - buck_configured[0] = 1; - buck_configured[1] = 1; + buck_multi[0] = true; + buck_configured[0] = true; + buck_configured[1] = true; break; /* multiphase buck34 is supported only with buck12 */ case MULTI_BUCK12_34: - buck_multi[0] = 1; - buck_multi[1] = 1; - buck_configured[0] = 1; - buck_configured[1] = 1; - buck_configured[2] = 1; - buck_configured[3] = 1; + buck_multi[0] = true; + buck_multi[1] = true; + buck_configured[0] = true; + buck_configured[1] = true; + buck_configured[2] = true; + buck_configured[3] = true; break; case MULTI_BUCK123: - buck_multi[2] = 1; - buck_configured[0] = 1; - buck_configured[1] = 1; - buck_configured[2] = 1; + buck_multi[2] = true; + buck_configured[0] = true; + buck_configured[1] = true; + buck_configured[2] = true; break; case MULTI_BUCK1234: - buck_multi[3] = 1; - buck_configured[0] = 1; - buck_configured[1] = 1; - buck_configured[2] = 1; - buck_configured[3] = 1; + buck_multi[3] = true; + buck_configured[0] = true; + buck_configured[1] = true; + buck_configured[2] = true; + buck_configured[3] = true; break; } } } if (tps->chip_id == LP8764) { - /* There is only 4 buck on LP8764 */ - buck_configured[4] = 1; - reg_irq_nb = size_mul(REGS_INT_NB, (BUCK_NB - 1)); + nr_buck = ARRAY_SIZE(buck_regs); + nr_ldo = 0; + nr_types = REGS_INT_NB; + } else if (tps->chip_id == TPS65224) { + nr_buck = ARRAY_SIZE(tps65224_buck_regs); + nr_ldo = ARRAY_SIZE(tps65224_ldo_regs); + nr_types = REGS_INT_NB; } else { - reg_irq_nb = size_mul(REGS_INT_NB, (size_add(BUCK_NB, LDO_NB))); + nr_buck = ARRAY_SIZE(buck_regs); + nr_ldo = ARRAY_SIZE(tps6594_ldo_regs); + nr_types = TPS65224_REGS_INT_NB; } + reg_irq_nb = nr_types * (nr_buck + nr_ldo); + irq_data = devm_kmalloc_array(tps->dev, reg_irq_nb, sizeof(struct tps6594_regulator_irq_data), GFP_KERNEL); if (!irq_data) return -ENOMEM; - for (i = 0; i < MULTI_PHASE_NB; i++) { - if (buck_multi[i] == 0) + for (i = 0; i < multi_phase_cnt; i++) { + if (!buck_multi[i]) continue; rdev = devm_regulator_register(&pdev->dev, &multi_regs[i], &config); @@ -506,52 +685,60 @@ static int tps6594_regulator_probe(struct platform_device *pdev) pdev->name); /* config multiphase buck12+buck34 */ - if (i == 1) + if (i == MULTI_BUCK12_34) buck_idx = 2; + error = tps6594_request_reg_irqs(pdev, rdev, irq_data, - tps6594_bucks_irq_types[buck_idx], &irq_idx); + bucks_irq_types[buck_idx], + interrupt_count, &irq_idx); if (error) return error; + error = tps6594_request_reg_irqs(pdev, rdev, irq_data, - tps6594_bucks_irq_types[buck_idx + 1], &irq_idx); + bucks_irq_types[buck_idx + 1], + interrupt_count, &irq_idx); if (error) return error; - if (i == 2 || i == 3) { + if (i == MULTI_BUCK123 || i == MULTI_BUCK1234) { error = tps6594_request_reg_irqs(pdev, rdev, irq_data, tps6594_bucks_irq_types[buck_idx + 2], + interrupt_count, &irq_idx); if (error) return error; } - if (i == 3) { + if (i == MULTI_BUCK1234) { error = tps6594_request_reg_irqs(pdev, rdev, irq_data, tps6594_bucks_irq_types[buck_idx + 3], + interrupt_count, &irq_idx); if (error) return error; } } - for (i = 0; i < BUCK_NB; i++) { - if (buck_configured[i] == 1) + for (i = 0; i < nr_buck; i++) { + if (buck_configured[i]) continue; - rdev = devm_regulator_register(&pdev->dev, &buck_regs[i], &config); + const struct regulator_desc *buck_cfg = (tps->chip_id == TPS65224) ? + tps65224_buck_regs : buck_regs; + + rdev = devm_regulator_register(&pdev->dev, &buck_cfg[i], &config); if (IS_ERR(rdev)) return dev_err_probe(tps->dev, PTR_ERR(rdev), - "failed to register %s regulator\n", - pdev->name); + "failed to register %s regulator\n", pdev->name); error = tps6594_request_reg_irqs(pdev, rdev, irq_data, - tps6594_bucks_irq_types[i], &irq_idx); + bucks_irq_types[i], interrupt_count, &irq_idx); if (error) return error; } - /* LP8764 dosen't have LDO */ + /* LP8764 doesn't have LDO */ if (tps->chip_id != LP8764) { - for (i = 0; i < ARRAY_SIZE(ldo_regs); i++) { + for (i = 0; i < nr_ldo; i++) { rdev = devm_regulator_register(&pdev->dev, &ldo_regs[i], &config); if (IS_ERR(rdev)) return dev_err_probe(tps->dev, PTR_ERR(rdev), @@ -559,26 +746,34 @@ static int tps6594_regulator_probe(struct platform_device *pdev) pdev->name); error = tps6594_request_reg_irqs(pdev, rdev, irq_data, - tps6594_ldos_irq_types[i], + ldos_irq_types[i], interrupt_count, &irq_idx); if (error) return error; } } - if (tps->chip_id == LP8764) - ext_reg_irq_nb = ARRAY_SIZE(tps6594_ext_regulator_irq_types); + if (tps->chip_id == TPS65224) { + irq_types = tps65224_ext_regulator_irq_types; + irq_count = ARRAY_SIZE(tps65224_ext_regulator_irq_types); + } else { + irq_types = tps6594_ext_regulator_irq_types; + if (tps->chip_id == LP8764) + irq_count = ARRAY_SIZE(tps6594_ext_regulator_irq_types); + else + /* TPS6593 supports only VCCA OV and UV */ + irq_count = 2; + } irq_ext_reg_data = devm_kmalloc_array(tps->dev, - ext_reg_irq_nb, - sizeof(struct tps6594_ext_regulator_irq_data), - GFP_KERNEL); + irq_count, + sizeof(struct tps6594_ext_regulator_irq_data), + GFP_KERNEL); if (!irq_ext_reg_data) return -ENOMEM; - for (i = 0; i < ext_reg_irq_nb; ++i) { - irq_type = &tps6594_ext_regulator_irq_types[i]; - + for (i = 0; i < irq_count; ++i) { + irq_type = &irq_types[i]; irq = platform_get_irq_byname(pdev, irq_type->irq_name); if (irq < 0) return -EINVAL; @@ -610,5 +805,6 @@ module_platform_driver(tps6594_regulator_driver); MODULE_ALIAS("platform:tps6594-regulator"); MODULE_AUTHOR("Jerome Neanne "); +MODULE_AUTHOR("Nirmala Devi Mal Nadar "); MODULE_DESCRIPTION("TPS6594 voltage regulator driver"); MODULE_LICENSE("GPL"); -- cgit v1.2.3-59-g8ed1b From 2088297159178ffc7c695fa34a7a88707371927d Mon Sep 17 00:00:00 2001 From: Nirmala Devi Mal Nadar Date: Tue, 30 Apr 2024 16:35:55 +0000 Subject: pinctrl: pinctrl-tps6594: Add TPS65224 PMIC pinctrl and GPIO Add support for TPS65224 pinctrl and GPIOs to TPS6594 driver as they have significant functional overlap. TPS65224 PMIC has 6 GPIOS which can be configured as GPIO or other dedicated device functions. Signed-off-by: Nirmala Devi Mal Nadar Signed-off-by: Bhargav Raviprakash Acked-by: Linus Walleij Link: https://lore.kernel.org/r/0109018f2fdce15d-c13bd809-a11b-4202-9b7f-c9380d51b070-000000@ap-south-1.amazonses.com Signed-off-by: Lee Jones --- drivers/pinctrl/pinctrl-tps6594.c | 277 +++++++++++++++++++++++++++++++------- 1 file changed, 225 insertions(+), 52 deletions(-) diff --git a/drivers/pinctrl/pinctrl-tps6594.c b/drivers/pinctrl/pinctrl-tps6594.c index 66985e54b74a..085047320853 100644 --- a/drivers/pinctrl/pinctrl-tps6594.c +++ b/drivers/pinctrl/pinctrl-tps6594.c @@ -14,8 +14,6 @@ #include -#define TPS6594_PINCTRL_PINS_NB 11 - #define TPS6594_PINCTRL_GPIO_FUNCTION 0 #define TPS6594_PINCTRL_SCL_I2C2_CS_SPI_FUNCTION 1 #define TPS6594_PINCTRL_TRIG_WDOG_FUNCTION 1 @@ -40,17 +38,40 @@ #define TPS6594_PINCTRL_SYNCCLKOUT_FUNCTION_GPIO8 3 #define TPS6594_PINCTRL_CLK32KOUT_FUNCTION_GPIO9 3 +/* TPS65224 pin muxval */ +#define TPS65224_PINCTRL_SDA_I2C2_SDO_SPI_FUNCTION 1 +#define TPS65224_PINCTRL_SCL_I2C2_CS_SPI_FUNCTION 1 +#define TPS65224_PINCTRL_VMON1_FUNCTION 1 +#define TPS65224_PINCTRL_VMON2_FUNCTION 1 +#define TPS65224_PINCTRL_WKUP_FUNCTION 1 +#define TPS65224_PINCTRL_NSLEEP2_FUNCTION 2 +#define TPS65224_PINCTRL_NSLEEP1_FUNCTION 2 +#define TPS65224_PINCTRL_SYNCCLKIN_FUNCTION 2 +#define TPS65224_PINCTRL_NERR_MCU_FUNCTION 2 +#define TPS65224_PINCTRL_NINT_FUNCTION 3 +#define TPS65224_PINCTRL_TRIG_WDOG_FUNCTION 3 +#define TPS65224_PINCTRL_PB_FUNCTION 3 +#define TPS65224_PINCTRL_ADC_IN_FUNCTION 3 + +/* TPS65224 Special muxval for recalcitrant pins */ +#define TPS65224_PINCTRL_NSLEEP2_FUNCTION_GPIO5 1 +#define TPS65224_PINCTRL_WKUP_FUNCTION_GPIO5 4 +#define TPS65224_PINCTRL_SYNCCLKIN_FUNCTION_GPIO5 3 + #define TPS6594_OFFSET_GPIO_SEL 5 -#define FUNCTION(fname, v) \ +#define TPS65224_NGPIO_PER_REG 6 +#define TPS6594_NGPIO_PER_REG 8 + +#define FUNCTION(dev_name, fname, v) \ { \ .pinfunction = PINCTRL_PINFUNCTION(#fname, \ - tps6594_##fname##_func_group_names, \ - ARRAY_SIZE(tps6594_##fname##_func_group_names)),\ + dev_name##_##fname##_func_group_names, \ + ARRAY_SIZE(dev_name##_##fname##_func_group_names)),\ .muxval = v, \ } -static const struct pinctrl_pin_desc tps6594_pins[TPS6594_PINCTRL_PINS_NB] = { +static const struct pinctrl_pin_desc tps6594_pins[] = { PINCTRL_PIN(0, "GPIO0"), PINCTRL_PIN(1, "GPIO1"), PINCTRL_PIN(2, "GPIO2"), PINCTRL_PIN(3, "GPIO3"), PINCTRL_PIN(4, "GPIO4"), PINCTRL_PIN(5, "GPIO5"), @@ -143,30 +164,127 @@ static const char *const tps6594_syncclkin_func_group_names[] = { "GPIO9", }; +static const struct pinctrl_pin_desc tps65224_pins[] = { + PINCTRL_PIN(0, "GPIO0"), PINCTRL_PIN(1, "GPIO1"), + PINCTRL_PIN(2, "GPIO2"), PINCTRL_PIN(3, "GPIO3"), + PINCTRL_PIN(4, "GPIO4"), PINCTRL_PIN(5, "GPIO5"), +}; + +static const char *const tps65224_gpio_func_group_names[] = { + "GPIO0", "GPIO1", "GPIO2", "GPIO3", "GPIO4", "GPIO5", +}; + +static const char *const tps65224_sda_i2c2_sdo_spi_func_group_names[] = { + "GPIO0", +}; + +static const char *const tps65224_nsleep2_func_group_names[] = { + "GPIO0", "GPIO5", +}; + +static const char *const tps65224_nint_func_group_names[] = { + "GPIO0", +}; + +static const char *const tps65224_scl_i2c2_cs_spi_func_group_names[] = { + "GPIO1", +}; + +static const char *const tps65224_nsleep1_func_group_names[] = { + "GPIO1", "GPIO2", "GPIO3", +}; + +static const char *const tps65224_trig_wdog_func_group_names[] = { + "GPIO1", +}; + +static const char *const tps65224_vmon1_func_group_names[] = { + "GPIO2", +}; + +static const char *const tps65224_pb_func_group_names[] = { + "GPIO2", +}; + +static const char *const tps65224_vmon2_func_group_names[] = { + "GPIO3", +}; + +static const char *const tps65224_adc_in_func_group_names[] = { + "GPIO3", "GPIO4", +}; + +static const char *const tps65224_wkup_func_group_names[] = { + "GPIO4", "GPIO5", +}; + +static const char *const tps65224_syncclkin_func_group_names[] = { + "GPIO4", "GPIO5", +}; + +static const char *const tps65224_nerr_mcu_func_group_names[] = { + "GPIO5", +}; + struct tps6594_pinctrl_function { struct pinfunction pinfunction; u8 muxval; }; +struct muxval_remap { + unsigned int group; + u8 muxval; + u8 remap; +}; + +struct muxval_remap tps65224_muxval_remap[] = { + {5, TPS6594_PINCTRL_DISABLE_WDOG_FUNCTION, TPS65224_PINCTRL_WKUP_FUNCTION_GPIO5}, + {5, TPS65224_PINCTRL_SYNCCLKIN_FUNCTION, TPS65224_PINCTRL_SYNCCLKIN_FUNCTION_GPIO5}, + {5, TPS65224_PINCTRL_NSLEEP2_FUNCTION, TPS65224_PINCTRL_NSLEEP2_FUNCTION_GPIO5}, +}; + +struct muxval_remap tps6594_muxval_remap[] = { + {8, TPS6594_PINCTRL_DISABLE_WDOG_FUNCTION, TPS6594_PINCTRL_DISABLE_WDOG_FUNCTION_GPIO8}, + {8, TPS6594_PINCTRL_SYNCCLKOUT_FUNCTION, TPS6594_PINCTRL_SYNCCLKOUT_FUNCTION_GPIO8}, + {9, TPS6594_PINCTRL_CLK32KOUT_FUNCTION, TPS6594_PINCTRL_CLK32KOUT_FUNCTION_GPIO9}, +}; + static const struct tps6594_pinctrl_function pinctrl_functions[] = { - FUNCTION(gpio, TPS6594_PINCTRL_GPIO_FUNCTION), - FUNCTION(nsleep1, TPS6594_PINCTRL_NSLEEP1_FUNCTION), - FUNCTION(nsleep2, TPS6594_PINCTRL_NSLEEP2_FUNCTION), - FUNCTION(wkup1, TPS6594_PINCTRL_WKUP1_FUNCTION), - FUNCTION(wkup2, TPS6594_PINCTRL_WKUP2_FUNCTION), - FUNCTION(scl_i2c2_cs_spi, TPS6594_PINCTRL_SCL_I2C2_CS_SPI_FUNCTION), - FUNCTION(nrstout_soc, TPS6594_PINCTRL_NRSTOUT_SOC_FUNCTION), - FUNCTION(trig_wdog, TPS6594_PINCTRL_TRIG_WDOG_FUNCTION), - FUNCTION(sda_i2c2_sdo_spi, TPS6594_PINCTRL_SDA_I2C2_SDO_SPI_FUNCTION), - FUNCTION(clk32kout, TPS6594_PINCTRL_CLK32KOUT_FUNCTION), - FUNCTION(nerr_soc, TPS6594_PINCTRL_NERR_SOC_FUNCTION), - FUNCTION(sclk_spmi, TPS6594_PINCTRL_SCLK_SPMI_FUNCTION), - FUNCTION(sdata_spmi, TPS6594_PINCTRL_SDATA_SPMI_FUNCTION), - FUNCTION(nerr_mcu, TPS6594_PINCTRL_NERR_MCU_FUNCTION), - FUNCTION(syncclkout, TPS6594_PINCTRL_SYNCCLKOUT_FUNCTION), - FUNCTION(disable_wdog, TPS6594_PINCTRL_DISABLE_WDOG_FUNCTION), - FUNCTION(pdog, TPS6594_PINCTRL_PDOG_FUNCTION), - FUNCTION(syncclkin, TPS6594_PINCTRL_SYNCCLKIN_FUNCTION), + FUNCTION(tps6594, gpio, TPS6594_PINCTRL_GPIO_FUNCTION), + FUNCTION(tps6594, nsleep1, TPS6594_PINCTRL_NSLEEP1_FUNCTION), + FUNCTION(tps6594, nsleep2, TPS6594_PINCTRL_NSLEEP2_FUNCTION), + FUNCTION(tps6594, wkup1, TPS6594_PINCTRL_WKUP1_FUNCTION), + FUNCTION(tps6594, wkup2, TPS6594_PINCTRL_WKUP2_FUNCTION), + FUNCTION(tps6594, scl_i2c2_cs_spi, TPS6594_PINCTRL_SCL_I2C2_CS_SPI_FUNCTION), + FUNCTION(tps6594, nrstout_soc, TPS6594_PINCTRL_NRSTOUT_SOC_FUNCTION), + FUNCTION(tps6594, trig_wdog, TPS6594_PINCTRL_TRIG_WDOG_FUNCTION), + FUNCTION(tps6594, sda_i2c2_sdo_spi, TPS6594_PINCTRL_SDA_I2C2_SDO_SPI_FUNCTION), + FUNCTION(tps6594, clk32kout, TPS6594_PINCTRL_CLK32KOUT_FUNCTION), + FUNCTION(tps6594, nerr_soc, TPS6594_PINCTRL_NERR_SOC_FUNCTION), + FUNCTION(tps6594, sclk_spmi, TPS6594_PINCTRL_SCLK_SPMI_FUNCTION), + FUNCTION(tps6594, sdata_spmi, TPS6594_PINCTRL_SDATA_SPMI_FUNCTION), + FUNCTION(tps6594, nerr_mcu, TPS6594_PINCTRL_NERR_MCU_FUNCTION), + FUNCTION(tps6594, syncclkout, TPS6594_PINCTRL_SYNCCLKOUT_FUNCTION), + FUNCTION(tps6594, disable_wdog, TPS6594_PINCTRL_DISABLE_WDOG_FUNCTION), + FUNCTION(tps6594, pdog, TPS6594_PINCTRL_PDOG_FUNCTION), + FUNCTION(tps6594, syncclkin, TPS6594_PINCTRL_SYNCCLKIN_FUNCTION), +}; + +static const struct tps6594_pinctrl_function tps65224_pinctrl_functions[] = { + FUNCTION(tps65224, gpio, TPS6594_PINCTRL_GPIO_FUNCTION), + FUNCTION(tps65224, sda_i2c2_sdo_spi, TPS65224_PINCTRL_SDA_I2C2_SDO_SPI_FUNCTION), + FUNCTION(tps65224, nsleep2, TPS65224_PINCTRL_NSLEEP2_FUNCTION), + FUNCTION(tps65224, nint, TPS65224_PINCTRL_NINT_FUNCTION), + FUNCTION(tps65224, scl_i2c2_cs_spi, TPS65224_PINCTRL_SCL_I2C2_CS_SPI_FUNCTION), + FUNCTION(tps65224, nsleep1, TPS65224_PINCTRL_NSLEEP1_FUNCTION), + FUNCTION(tps65224, trig_wdog, TPS65224_PINCTRL_TRIG_WDOG_FUNCTION), + FUNCTION(tps65224, vmon1, TPS65224_PINCTRL_VMON1_FUNCTION), + FUNCTION(tps65224, pb, TPS65224_PINCTRL_PB_FUNCTION), + FUNCTION(tps65224, vmon2, TPS65224_PINCTRL_VMON2_FUNCTION), + FUNCTION(tps65224, adc_in, TPS65224_PINCTRL_ADC_IN_FUNCTION), + FUNCTION(tps65224, wkup, TPS65224_PINCTRL_WKUP_FUNCTION), + FUNCTION(tps65224, syncclkin, TPS65224_PINCTRL_SYNCCLKIN_FUNCTION), + FUNCTION(tps65224, nerr_mcu, TPS65224_PINCTRL_NERR_MCU_FUNCTION), }; struct tps6594_pinctrl { @@ -175,6 +293,31 @@ struct tps6594_pinctrl { struct pinctrl_dev *pctl_dev; const struct tps6594_pinctrl_function *funcs; const struct pinctrl_pin_desc *pins; + int func_cnt; + int num_pins; + u8 mux_sel_mask; + unsigned int remap_cnt; + struct muxval_remap *remap; +}; + +static struct tps6594_pinctrl tps65224_template_pinctrl = { + .funcs = tps65224_pinctrl_functions, + .func_cnt = ARRAY_SIZE(tps65224_pinctrl_functions), + .pins = tps65224_pins, + .num_pins = ARRAY_SIZE(tps65224_pins), + .mux_sel_mask = TPS65224_MASK_GPIO_SEL, + .remap = tps65224_muxval_remap, + .remap_cnt = ARRAY_SIZE(tps65224_muxval_remap), +}; + +static struct tps6594_pinctrl tps6594_template_pinctrl = { + .funcs = pinctrl_functions, + .func_cnt = ARRAY_SIZE(pinctrl_functions), + .pins = tps6594_pins, + .num_pins = ARRAY_SIZE(tps6594_pins), + .mux_sel_mask = TPS6594_MASK_GPIO_SEL, + .remap = tps6594_muxval_remap, + .remap_cnt = ARRAY_SIZE(tps6594_muxval_remap), }; static int tps6594_gpio_regmap_xlate(struct gpio_regmap *gpio, @@ -201,7 +344,9 @@ static int tps6594_gpio_regmap_xlate(struct gpio_regmap *gpio, static int tps6594_pmx_func_cnt(struct pinctrl_dev *pctldev) { - return ARRAY_SIZE(pinctrl_functions); + struct tps6594_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctldev); + + return pinctrl->func_cnt; } static const char *tps6594_pmx_func_name(struct pinctrl_dev *pctldev, @@ -229,10 +374,16 @@ static int tps6594_pmx_set(struct tps6594_pinctrl *pinctrl, unsigned int pin, u8 muxval) { u8 mux_sel_val = muxval << TPS6594_OFFSET_GPIO_SEL; + u8 mux_sel_mask = pinctrl->mux_sel_mask; + + if (pinctrl->tps->chip_id == TPS65224 && pin == 5) { + /* GPIO6 has a different mask in TPS65224*/ + mux_sel_mask = TPS65224_MASK_GPIO_SEL_GPIO6; + } return regmap_update_bits(pinctrl->tps->regmap, TPS6594_REG_GPIOX_CONF(pin), - TPS6594_MASK_GPIO_SEL, mux_sel_val); + mux_sel_mask, mux_sel_val); } static int tps6594_pmx_set_mux(struct pinctrl_dev *pctldev, @@ -240,16 +391,14 @@ static int tps6594_pmx_set_mux(struct pinctrl_dev *pctldev, { struct tps6594_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctldev); u8 muxval = pinctrl->funcs[function].muxval; - - /* Some pins don't have the same muxval for the same function... */ - if (group == 8) { - if (muxval == TPS6594_PINCTRL_DISABLE_WDOG_FUNCTION) - muxval = TPS6594_PINCTRL_DISABLE_WDOG_FUNCTION_GPIO8; - else if (muxval == TPS6594_PINCTRL_SYNCCLKOUT_FUNCTION) - muxval = TPS6594_PINCTRL_SYNCCLKOUT_FUNCTION_GPIO8; - } else if (group == 9) { - if (muxval == TPS6594_PINCTRL_CLK32KOUT_FUNCTION) - muxval = TPS6594_PINCTRL_CLK32KOUT_FUNCTION_GPIO9; + unsigned int remap_cnt = pinctrl->remap_cnt; + struct muxval_remap *remap = pinctrl->remap; + + for (unsigned int i = 0; i < remap_cnt; i++) { + if (group == remap[i].group && muxval == remap[i].muxval) { + muxval = remap[i].remap; + break; + } } return tps6594_pmx_set(pinctrl, group, muxval); @@ -276,7 +425,9 @@ static const struct pinmux_ops tps6594_pmx_ops = { static int tps6594_groups_cnt(struct pinctrl_dev *pctldev) { - return ARRAY_SIZE(tps6594_pins); + struct tps6594_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctldev); + + return pinctrl->num_pins; } static int tps6594_group_pins(struct pinctrl_dev *pctldev, @@ -318,33 +469,54 @@ static int tps6594_pinctrl_probe(struct platform_device *pdev) pctrl_desc = devm_kzalloc(dev, sizeof(*pctrl_desc), GFP_KERNEL); if (!pctrl_desc) return -ENOMEM; - pctrl_desc->name = dev_name(dev); - pctrl_desc->owner = THIS_MODULE; - pctrl_desc->pins = tps6594_pins; - pctrl_desc->npins = ARRAY_SIZE(tps6594_pins); - pctrl_desc->pctlops = &tps6594_pctrl_ops; - pctrl_desc->pmxops = &tps6594_pmx_ops; pinctrl = devm_kzalloc(dev, sizeof(*pinctrl), GFP_KERNEL); if (!pinctrl) return -ENOMEM; - pinctrl->tps = dev_get_drvdata(dev->parent); - pinctrl->funcs = pinctrl_functions; - pinctrl->pins = tps6594_pins; - pinctrl->pctl_dev = devm_pinctrl_register(dev, pctrl_desc, pinctrl); - if (IS_ERR(pinctrl->pctl_dev)) - return dev_err_probe(dev, PTR_ERR(pinctrl->pctl_dev), - "Couldn't register pinctrl driver\n"); + + switch (tps->chip_id) { + case TPS65224: + pctrl_desc->pins = tps65224_pins; + pctrl_desc->npins = ARRAY_SIZE(tps65224_pins); + + *pinctrl = tps65224_template_pinctrl; + + config.ngpio = ARRAY_SIZE(tps65224_gpio_func_group_names); + config.ngpio_per_reg = TPS65224_NGPIO_PER_REG; + break; + case TPS6593: + case TPS6594: + pctrl_desc->pins = tps6594_pins; + pctrl_desc->npins = ARRAY_SIZE(tps6594_pins); + + *pinctrl = tps6594_template_pinctrl; + + config.ngpio = ARRAY_SIZE(tps6594_gpio_func_group_names); + config.ngpio_per_reg = TPS6594_NGPIO_PER_REG; + break; + default: + break; + } + + pinctrl->tps = tps; + + pctrl_desc->name = dev_name(dev); + pctrl_desc->owner = THIS_MODULE; + pctrl_desc->pctlops = &tps6594_pctrl_ops; + pctrl_desc->pmxops = &tps6594_pmx_ops; config.parent = tps->dev; config.regmap = tps->regmap; - config.ngpio = TPS6594_PINCTRL_PINS_NB; - config.ngpio_per_reg = 8; config.reg_dat_base = TPS6594_REG_GPIO_IN_1; config.reg_set_base = TPS6594_REG_GPIO_OUT_1; config.reg_dir_out_base = TPS6594_REG_GPIOX_CONF(0); config.reg_mask_xlate = tps6594_gpio_regmap_xlate; + pinctrl->pctl_dev = devm_pinctrl_register(dev, pctrl_desc, pinctrl); + if (IS_ERR(pinctrl->pctl_dev)) + return dev_err_probe(dev, PTR_ERR(pinctrl->pctl_dev), + "Couldn't register pinctrl driver\n"); + pinctrl->gpio_regmap = devm_gpio_regmap_register(dev, &config); if (IS_ERR(pinctrl->gpio_regmap)) return dev_err_probe(dev, PTR_ERR(pinctrl->gpio_regmap), @@ -369,5 +541,6 @@ static struct platform_driver tps6594_pinctrl_driver = { module_platform_driver(tps6594_pinctrl_driver); MODULE_AUTHOR("Esteban Blanc "); +MODULE_AUTHOR("Nirmala Devi Mal Nadar "); MODULE_DESCRIPTION("TPS6594 pinctrl and GPIO driver"); MODULE_LICENSE("GPL"); -- cgit v1.2.3-59-g8ed1b From a2e25c8165f93ca8a2d54bf230e1bb7e0319b46c Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 24 Apr 2024 08:33:27 +0200 Subject: backlight: lcd: Constify lcd_ops 'struct lcd_ops' passed in lcd_device_register() is not modified by core backlight code, so it can be made const for code safety. This allows drivers to also define the structure as const. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Daniel Thompson Link: https://lore.kernel.org/r/20240424-video-backlight-lcd-ops-v2-1-1aaa82b07bc6@kernel.org Signed-off-by: Lee Jones --- drivers/video/backlight/lcd.c | 4 ++-- include/linux/lcd.h | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/video/backlight/lcd.c b/drivers/video/backlight/lcd.c index 77c5cb2a44e2..ba3e37b5b584 100644 --- a/drivers/video/backlight/lcd.c +++ b/drivers/video/backlight/lcd.c @@ -188,7 +188,7 @@ ATTRIBUTE_GROUPS(lcd_device); * or a pointer to the newly allocated device. */ struct lcd_device *lcd_device_register(const char *name, struct device *parent, - void *devdata, struct lcd_ops *ops) + void *devdata, const struct lcd_ops *ops) { struct lcd_device *new_ld; int rc; @@ -276,7 +276,7 @@ static int devm_lcd_device_match(struct device *dev, void *res, void *data) */ struct lcd_device *devm_lcd_device_register(struct device *dev, const char *name, struct device *parent, - void *devdata, struct lcd_ops *ops) + void *devdata, const struct lcd_ops *ops) { struct lcd_device **ptr, *lcd; diff --git a/include/linux/lcd.h b/include/linux/lcd.h index 238fb1dfed98..68703a51dc53 100644 --- a/include/linux/lcd.h +++ b/include/linux/lcd.h @@ -61,7 +61,7 @@ struct lcd_device { points to something in the body of that driver, it is also invalid. */ struct mutex ops_lock; /* If this is NULL, the backing module is unloaded */ - struct lcd_ops *ops; + const struct lcd_ops *ops; /* Serialise access to set_power method */ struct mutex update_lock; /* The framebuffer notifier block */ @@ -102,10 +102,10 @@ static inline void lcd_set_power(struct lcd_device *ld, int power) } extern struct lcd_device *lcd_device_register(const char *name, - struct device *parent, void *devdata, struct lcd_ops *ops); + struct device *parent, void *devdata, const struct lcd_ops *ops); extern struct lcd_device *devm_lcd_device_register(struct device *dev, const char *name, struct device *parent, - void *devdata, struct lcd_ops *ops); + void *devdata, const struct lcd_ops *ops); extern void lcd_device_unregister(struct lcd_device *ld); extern void devm_lcd_device_unregister(struct device *dev, struct lcd_device *ld); -- cgit v1.2.3-59-g8ed1b From 03788e747f57ace3c82956862ec4a70bd95aeca7 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 24 Apr 2024 08:33:28 +0200 Subject: backlight: ams369fg06: Constify lcd_ops 'struct lcd_ops' is not modified by core backlight code, so it can be made const for increased code safety. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Daniel Thompson Link: https://lore.kernel.org/r/20240424-video-backlight-lcd-ops-v2-2-1aaa82b07bc6@kernel.org Signed-off-by: Lee Jones --- drivers/video/backlight/ams369fg06.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/backlight/ams369fg06.c b/drivers/video/backlight/ams369fg06.c index 522dd81110b8..57ec205d2bd2 100644 --- a/drivers/video/backlight/ams369fg06.c +++ b/drivers/video/backlight/ams369fg06.c @@ -427,7 +427,7 @@ static int ams369fg06_set_brightness(struct backlight_device *bd) return ret; } -static struct lcd_ops ams369fg06_lcd_ops = { +static const struct lcd_ops ams369fg06_lcd_ops = { .get_power = ams369fg06_get_power, .set_power = ams369fg06_set_power, }; -- cgit v1.2.3-59-g8ed1b From 94194e314ec81c461b014621f96962cac82ffcc1 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 24 Apr 2024 08:33:29 +0200 Subject: backlight: corgi_lcd: Constify lcd_ops 'struct lcd_ops' is not modified by core backlight code, so it can be made const for increased code safety. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Daniel Thompson Link: https://lore.kernel.org/r/20240424-video-backlight-lcd-ops-v2-3-1aaa82b07bc6@kernel.org Signed-off-by: Lee Jones --- drivers/video/backlight/corgi_lcd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/backlight/corgi_lcd.c b/drivers/video/backlight/corgi_lcd.c index dd765098ad98..aad1680c9075 100644 --- a/drivers/video/backlight/corgi_lcd.c +++ b/drivers/video/backlight/corgi_lcd.c @@ -380,7 +380,7 @@ static int corgi_lcd_get_power(struct lcd_device *ld) return lcd->power; } -static struct lcd_ops corgi_lcd_ops = { +static const struct lcd_ops corgi_lcd_ops = { .get_power = corgi_lcd_get_power, .set_power = corgi_lcd_set_power, .set_mode = corgi_lcd_set_mode, -- cgit v1.2.3-59-g8ed1b From 4c00ff8ebf0cdd8998036f90ad71e254c1f218e8 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 24 Apr 2024 08:33:30 +0200 Subject: backlight: hx8357: Constify lcd_ops 'struct lcd_ops' is not modified by core backlight code, so it can be made const for increased code safety. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Daniel Thompson Link: https://lore.kernel.org/r/20240424-video-backlight-lcd-ops-v2-4-1aaa82b07bc6@kernel.org Signed-off-by: Lee Jones --- drivers/video/backlight/hx8357.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/backlight/hx8357.c b/drivers/video/backlight/hx8357.c index 339d9128fbde..cdd7b7686723 100644 --- a/drivers/video/backlight/hx8357.c +++ b/drivers/video/backlight/hx8357.c @@ -559,7 +559,7 @@ static int hx8357_get_power(struct lcd_device *lcdev) return lcd->state; } -static struct lcd_ops hx8357_ops = { +static const struct lcd_ops hx8357_ops = { .set_power = hx8357_set_power, .get_power = hx8357_get_power, }; -- cgit v1.2.3-59-g8ed1b From c4643239dc56c523f0400543c6ae806328599502 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 24 Apr 2024 08:33:31 +0200 Subject: backlight: ili922x: Constify lcd_ops 'struct lcd_ops' is not modified by core backlight code, so it can be made const for increased code safety. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Daniel Thompson Link: https://lore.kernel.org/r/20240424-video-backlight-lcd-ops-v2-5-1aaa82b07bc6@kernel.org Signed-off-by: Lee Jones --- drivers/video/backlight/ili922x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/backlight/ili922x.c b/drivers/video/backlight/ili922x.c index c8e0e655dc86..7683e209ad6b 100644 --- a/drivers/video/backlight/ili922x.c +++ b/drivers/video/backlight/ili922x.c @@ -472,7 +472,7 @@ static int ili922x_get_power(struct lcd_device *ld) return ili->power; } -static struct lcd_ops ili922x_ops = { +static const struct lcd_ops ili922x_ops = { .get_power = ili922x_get_power, .set_power = ili922x_set_power, }; -- cgit v1.2.3-59-g8ed1b From a2b3af58ce17c9c8aa05374bf4f8217e827619e1 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 24 Apr 2024 08:33:32 +0200 Subject: backlight: ili9320: Constify lcd_ops 'struct lcd_ops' is not modified by core backlight code, so it can be made const for increased code safety. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Daniel Thompson Link: https://lore.kernel.org/r/20240424-video-backlight-lcd-ops-v2-6-1aaa82b07bc6@kernel.org Signed-off-by: Lee Jones --- drivers/video/backlight/ili9320.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/backlight/ili9320.c b/drivers/video/backlight/ili9320.c index 2acd2708f8ca..3e318d1891b6 100644 --- a/drivers/video/backlight/ili9320.c +++ b/drivers/video/backlight/ili9320.c @@ -161,7 +161,7 @@ static int ili9320_get_power(struct lcd_device *ld) return lcd->power; } -static struct lcd_ops ili9320_ops = { +static const struct lcd_ops ili9320_ops = { .get_power = ili9320_get_power, .set_power = ili9320_set_power, }; -- cgit v1.2.3-59-g8ed1b From 26679a701706c4956c0c80382c3a51c59f08654f Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 24 Apr 2024 08:33:33 +0200 Subject: backlight: jornada720_lcd: Constify lcd_ops 'struct lcd_ops' is not modified by core backlight code, so it can be made const for increased code safety. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Daniel Thompson Link: https://lore.kernel.org/r/20240424-video-backlight-lcd-ops-v2-7-1aaa82b07bc6@kernel.org Signed-off-by: Lee Jones --- drivers/video/backlight/jornada720_lcd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/backlight/jornada720_lcd.c b/drivers/video/backlight/jornada720_lcd.c index 6796a7c2db25..5c64fa61e810 100644 --- a/drivers/video/backlight/jornada720_lcd.c +++ b/drivers/video/backlight/jornada720_lcd.c @@ -81,7 +81,7 @@ static int jornada_lcd_set_power(struct lcd_device *ld, int power) return 0; } -static struct lcd_ops jornada_lcd_props = { +static const struct lcd_ops jornada_lcd_props = { .get_contrast = jornada_lcd_get_contrast, .set_contrast = jornada_lcd_set_contrast, .get_power = jornada_lcd_get_power, -- cgit v1.2.3-59-g8ed1b From aefc911e42a35e9d4337c5ab9b2319039f445574 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 24 Apr 2024 08:33:34 +0200 Subject: backlight: l4f00242t03: Constify lcd_ops 'struct lcd_ops' is not modified by core backlight code, so it can be made const for increased code safety. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Daniel Thompson Link: https://lore.kernel.org/r/20240424-video-backlight-lcd-ops-v2-8-1aaa82b07bc6@kernel.org Signed-off-by: Lee Jones --- drivers/video/backlight/l4f00242t03.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/backlight/l4f00242t03.c b/drivers/video/backlight/l4f00242t03.c index bd5137ee203b..dd0874f8c7ff 100644 --- a/drivers/video/backlight/l4f00242t03.c +++ b/drivers/video/backlight/l4f00242t03.c @@ -158,7 +158,7 @@ static int l4f00242t03_lcd_power_set(struct lcd_device *ld, int power) return 0; } -static struct lcd_ops l4f_ops = { +static const struct lcd_ops l4f_ops = { .set_power = l4f00242t03_lcd_power_set, .get_power = l4f00242t03_lcd_power_get, }; -- cgit v1.2.3-59-g8ed1b From 7ae6431a105d07cd5334870edc17496833b5a464 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 24 Apr 2024 08:33:35 +0200 Subject: backlight: lms283gf05: Constify lcd_ops 'struct lcd_ops' is not modified by core backlight code, so it can be made const for increased code safety. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Daniel Thompson Link: https://lore.kernel.org/r/20240424-video-backlight-lcd-ops-v2-9-1aaa82b07bc6@kernel.org Signed-off-by: Lee Jones --- drivers/video/backlight/lms283gf05.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/backlight/lms283gf05.c b/drivers/video/backlight/lms283gf05.c index 36856962ed83..a65490e83d3d 100644 --- a/drivers/video/backlight/lms283gf05.c +++ b/drivers/video/backlight/lms283gf05.c @@ -139,7 +139,7 @@ static int lms283gf05_power_set(struct lcd_device *ld, int power) return 0; } -static struct lcd_ops lms_ops = { +static const struct lcd_ops lms_ops = { .set_power = lms283gf05_power_set, .get_power = NULL, }; -- cgit v1.2.3-59-g8ed1b From 2b472876a46e476bf09b87e1946ba1ccb4a59683 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 24 Apr 2024 08:33:36 +0200 Subject: backlight: lms501kf03: Constify lcd_ops 'struct lcd_ops' is not modified by core backlight code, so it can be made const for increased code safety. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Daniel Thompson Link: https://lore.kernel.org/r/20240424-video-backlight-lcd-ops-v2-10-1aaa82b07bc6@kernel.org Signed-off-by: Lee Jones --- drivers/video/backlight/lms501kf03.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/backlight/lms501kf03.c b/drivers/video/backlight/lms501kf03.c index 5c46df8022bf..8aebe0af3391 100644 --- a/drivers/video/backlight/lms501kf03.c +++ b/drivers/video/backlight/lms501kf03.c @@ -304,7 +304,7 @@ static int lms501kf03_set_power(struct lcd_device *ld, int power) return lms501kf03_power(lcd, power); } -static struct lcd_ops lms501kf03_lcd_ops = { +static const struct lcd_ops lms501kf03_lcd_ops = { .get_power = lms501kf03_get_power, .set_power = lms501kf03_set_power, }; -- cgit v1.2.3-59-g8ed1b From 62560bfafdf358ed5aea99c39753553660e42ba2 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 24 Apr 2024 08:33:37 +0200 Subject: backlight: ltv350qv: Constify lcd_ops 'struct lcd_ops' is not modified by core backlight code, so it can be made const for increased code safety. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Daniel Thompson Link: https://lore.kernel.org/r/20240424-video-backlight-lcd-ops-v2-11-1aaa82b07bc6@kernel.org Signed-off-by: Lee Jones --- drivers/video/backlight/ltv350qv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/backlight/ltv350qv.c b/drivers/video/backlight/ltv350qv.c index d54f501e4285..cdc4c087f230 100644 --- a/drivers/video/backlight/ltv350qv.c +++ b/drivers/video/backlight/ltv350qv.c @@ -217,7 +217,7 @@ static int ltv350qv_get_power(struct lcd_device *ld) return lcd->power; } -static struct lcd_ops ltv_ops = { +static const struct lcd_ops ltv_ops = { .get_power = ltv350qv_get_power, .set_power = ltv350qv_set_power, }; -- cgit v1.2.3-59-g8ed1b From c935555c8a1466af7c36c3e699e3bad1c53cbed9 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 24 Apr 2024 08:33:38 +0200 Subject: backlight: otm3225a: Constify lcd_ops 'struct lcd_ops' is not modified by core backlight code, so it can be made const for increased code safety. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Daniel Thompson Link: https://lore.kernel.org/r/20240424-video-backlight-lcd-ops-v2-12-1aaa82b07bc6@kernel.org Signed-off-by: Lee Jones --- drivers/video/backlight/otm3225a.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/backlight/otm3225a.c b/drivers/video/backlight/otm3225a.c index 2472e2167aae..d7b09c10f908 100644 --- a/drivers/video/backlight/otm3225a.c +++ b/drivers/video/backlight/otm3225a.c @@ -205,7 +205,7 @@ static int otm3225a_get_power(struct lcd_device *ld) return dd->power; } -static struct lcd_ops otm3225a_ops = { +static const struct lcd_ops otm3225a_ops = { .set_power = otm3225a_set_power, .get_power = otm3225a_get_power, }; -- cgit v1.2.3-59-g8ed1b From 02bc4c447e29b29ddbca78d3ea485e0b23cd64b8 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 24 Apr 2024 08:33:39 +0200 Subject: backlight: platform_lcd: Constify lcd_ops 'struct lcd_ops' is not modified by core backlight code, so it can be made const for increased code safety. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Daniel Thompson Link: https://lore.kernel.org/r/20240424-video-backlight-lcd-ops-v2-13-1aaa82b07bc6@kernel.org Signed-off-by: Lee Jones --- drivers/video/backlight/platform_lcd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/backlight/platform_lcd.c b/drivers/video/backlight/platform_lcd.c index dc37494baf42..76872f5c34c5 100644 --- a/drivers/video/backlight/platform_lcd.c +++ b/drivers/video/backlight/platform_lcd.c @@ -62,7 +62,7 @@ static int platform_lcd_match(struct lcd_device *lcd, struct fb_info *info) return plcd->us->parent == info->device; } -static struct lcd_ops platform_lcd_ops = { +static const struct lcd_ops platform_lcd_ops = { .get_power = platform_lcd_get_power, .set_power = platform_lcd_set_power, .check_fb = platform_lcd_match, -- cgit v1.2.3-59-g8ed1b From ee7b1e8465d578189ba5329667bfacda44e15a87 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 24 Apr 2024 08:33:40 +0200 Subject: backlight: tdo24m: Constify lcd_ops 'struct lcd_ops' is not modified by core backlight code, so it can be made const for increased code safety. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Daniel Thompson Link: https://lore.kernel.org/r/20240424-video-backlight-lcd-ops-v2-14-1aaa82b07bc6@kernel.org Signed-off-by: Lee Jones --- drivers/video/backlight/tdo24m.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/backlight/tdo24m.c b/drivers/video/backlight/tdo24m.c index fc6fbaf85594..c413b3c68e95 100644 --- a/drivers/video/backlight/tdo24m.c +++ b/drivers/video/backlight/tdo24m.c @@ -322,7 +322,7 @@ static int tdo24m_set_mode(struct lcd_device *ld, struct fb_videomode *m) return lcd->adj_mode(lcd, mode); } -static struct lcd_ops tdo24m_ops = { +static const struct lcd_ops tdo24m_ops = { .get_power = tdo24m_get_power, .set_power = tdo24m_set_power, .set_mode = tdo24m_set_mode, -- cgit v1.2.3-59-g8ed1b From b8beae949433ab03de0ddfc97bc56db956a04662 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 24 Apr 2024 08:33:41 +0200 Subject: HID: picoLCD: Constify lcd_ops MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 'struct lcd_ops' is not modified by core backlight code, so it can be made const for increased code safety. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Bruno Prémont Link: https://lore.kernel.org/r/20240424-video-backlight-lcd-ops-v2-15-1aaa82b07bc6@kernel.org Signed-off-by: Lee Jones --- drivers/hid/hid-picolcd_lcd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hid/hid-picolcd_lcd.c b/drivers/hid/hid-picolcd_lcd.c index 0c4b76de8ae5..061a33ba7b1d 100644 --- a/drivers/hid/hid-picolcd_lcd.c +++ b/drivers/hid/hid-picolcd_lcd.c @@ -46,7 +46,7 @@ static int picolcd_check_lcd_fb(struct lcd_device *ldev, struct fb_info *fb) return fb && fb == picolcd_fbinfo((struct picolcd_data *)lcd_get_data(ldev)); } -static struct lcd_ops picolcd_lcdops = { +static const struct lcd_ops picolcd_lcdops = { .get_contrast = picolcd_get_contrast, .set_contrast = picolcd_set_contrast, .check_fb = picolcd_check_lcd_fb, -- cgit v1.2.3-59-g8ed1b From 9293c302f493c3c978ef829244545d48528daf59 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 24 Apr 2024 08:33:42 +0200 Subject: fbdev: clps711x: Constify lcd_ops 'struct lcd_ops' is not modified by core backlight code, so it can be made const for increased code safety. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Thomas Zimmermann Link: https://lore.kernel.org/r/20240424-video-backlight-lcd-ops-v2-16-1aaa82b07bc6@kernel.org Signed-off-by: Lee Jones --- drivers/video/fbdev/clps711x-fb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/fbdev/clps711x-fb.c b/drivers/video/fbdev/clps711x-fb.c index dcfd1fbbc7e1..6171a98a48fd 100644 --- a/drivers/video/fbdev/clps711x-fb.c +++ b/drivers/video/fbdev/clps711x-fb.c @@ -197,7 +197,7 @@ static int clps711x_lcd_set_power(struct lcd_device *lcddev, int blank) return 0; } -static struct lcd_ops clps711x_lcd_ops = { +static const struct lcd_ops clps711x_lcd_ops = { .check_fb = clps711x_lcd_check_fb, .get_power = clps711x_lcd_get_power, .set_power = clps711x_lcd_set_power, -- cgit v1.2.3-59-g8ed1b From 8b2d4564eca41581950ee113d41e180db7ea77b9 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 24 Apr 2024 08:33:43 +0200 Subject: fbdev: imx: Constify lcd_ops 'struct lcd_ops' is not modified by core backlight code, so it can be made const for increased code safety. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Thomas Zimmermann Reviewed-by: Peng Fan Link: https://lore.kernel.org/r/20240424-video-backlight-lcd-ops-v2-17-1aaa82b07bc6@kernel.org Signed-off-by: Lee Jones --- drivers/video/fbdev/imxfb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/fbdev/imxfb.c b/drivers/video/fbdev/imxfb.c index a4dbc72f93c3..4ebfe9b9df60 100644 --- a/drivers/video/fbdev/imxfb.c +++ b/drivers/video/fbdev/imxfb.c @@ -857,7 +857,7 @@ static int imxfb_lcd_set_power(struct lcd_device *lcddev, int power) return 0; } -static struct lcd_ops imxfb_lcd_ops = { +static const struct lcd_ops imxfb_lcd_ops = { .check_fb = imxfb_lcd_check_fb, .get_contrast = imxfb_lcd_get_contrast, .set_contrast = imxfb_lcd_set_contrast, -- cgit v1.2.3-59-g8ed1b From feb61a4b34a8b4946d432f73fd8a3d61db82bb87 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 24 Apr 2024 08:33:44 +0200 Subject: fbdev: omap: lcd_ams_delta: Constify lcd_ops 'struct lcd_ops' is not modified by core backlight code, so it can be made const for increased code safety. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Thomas Zimmermann Link: https://lore.kernel.org/r/20240424-video-backlight-lcd-ops-v2-18-1aaa82b07bc6@kernel.org Signed-off-by: Lee Jones --- drivers/video/fbdev/omap/lcd_ams_delta.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/fbdev/omap/lcd_ams_delta.c b/drivers/video/fbdev/omap/lcd_ams_delta.c index 6f860c814d2c..97e2b71b64d7 100644 --- a/drivers/video/fbdev/omap/lcd_ams_delta.c +++ b/drivers/video/fbdev/omap/lcd_ams_delta.c @@ -76,7 +76,7 @@ static int ams_delta_lcd_get_contrast(struct lcd_device *dev) return ams_delta_lcd & AMS_DELTA_MAX_CONTRAST; } -static struct lcd_ops ams_delta_lcd_ops = { +static const struct lcd_ops ams_delta_lcd_ops = { .get_power = ams_delta_lcd_get_power, .set_power = ams_delta_lcd_set_power, .get_contrast = ams_delta_lcd_get_contrast, -- cgit v1.2.3-59-g8ed1b From 82b9007bc4f8c22975d640d7df6743366f25a353 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 24 Apr 2024 08:33:45 +0200 Subject: const_structs.checkpatch: add lcd_ops MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 'struct lcd_ops' is not modified by core code. Signed-off-by: Krzysztof Kozlowski Suggested-by: Thomas Weißschuh Reviewed-by: Daniel Thompson Acked-by: Lee Jones Link: https://lore.kernel.org/r/20240424-video-backlight-lcd-ops-v2-19-1aaa82b07bc6@kernel.org Signed-off-by: Lee Jones --- scripts/const_structs.checkpatch | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/const_structs.checkpatch b/scripts/const_structs.checkpatch index fa96cfd16e99..52e5bfb61fd0 100644 --- a/scripts/const_structs.checkpatch +++ b/scripts/const_structs.checkpatch @@ -39,6 +39,7 @@ kgdb_arch kgdb_io kobj_type kset_uevent_ops +lcd_ops lock_manager_operations machine_desc microcode_ops -- cgit v1.2.3-59-g8ed1b From bf8367b00c33c64a9391c262bb2e11d274c9f2a4 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Maneyrol Date: Fri, 26 Apr 2024 09:48:35 +0000 Subject: iio: invensense: fix timestamp glitches when switching frequency When a sensor is running and there is a FIFO frequency change due to another sensor turned on/off, there are glitches on timestamp. Fix that by using only interrupt timestamp when there is the corresponding sensor data in the FIFO. Delete FIFO period handling and simplify internal functions. Update integration inside inv_mpu6050 and inv_icm42600 drivers. Fixes: 0ecc363ccea7 ("iio: make invensense timestamp module generic") Cc: Stable@vger.kernel.org Signed-off-by: Jean-Baptiste Maneyrol Link: https://lore.kernel.org/r/20240426094835.138389-1-inv.git-commit@tdk.com Signed-off-by: Jonathan Cameron --- .../iio/common/inv_sensors/inv_sensors_timestamp.c | 24 ++++++++++------------ drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c | 20 ++++++++---------- drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c | 2 +- include/linux/iio/common/inv_sensors_timestamp.h | 3 +-- 4 files changed, 21 insertions(+), 28 deletions(-) diff --git a/drivers/iio/common/inv_sensors/inv_sensors_timestamp.c b/drivers/iio/common/inv_sensors/inv_sensors_timestamp.c index 4b8ec16240b5..fa205f17bd90 100644 --- a/drivers/iio/common/inv_sensors/inv_sensors_timestamp.c +++ b/drivers/iio/common/inv_sensors/inv_sensors_timestamp.c @@ -70,13 +70,13 @@ int inv_sensors_timestamp_update_odr(struct inv_sensors_timestamp *ts, } EXPORT_SYMBOL_NS_GPL(inv_sensors_timestamp_update_odr, IIO_INV_SENSORS_TIMESTAMP); -static bool inv_validate_period(struct inv_sensors_timestamp *ts, uint32_t period, uint32_t mult) +static bool inv_validate_period(struct inv_sensors_timestamp *ts, uint32_t period) { uint32_t period_min, period_max; /* check that period is acceptable */ - period_min = ts->min_period * mult; - period_max = ts->max_period * mult; + period_min = ts->min_period * ts->mult; + period_max = ts->max_period * ts->mult; if (period > period_min && period < period_max) return true; else @@ -84,15 +84,15 @@ static bool inv_validate_period(struct inv_sensors_timestamp *ts, uint32_t perio } static bool inv_update_chip_period(struct inv_sensors_timestamp *ts, - uint32_t mult, uint32_t period) + uint32_t period) { uint32_t new_chip_period; - if (!inv_validate_period(ts, period, mult)) + if (!inv_validate_period(ts, period)) return false; /* update chip internal period estimation */ - new_chip_period = period / mult; + new_chip_period = period / ts->mult; inv_update_acc(&ts->chip_period, new_chip_period); ts->period = ts->mult * ts->chip_period.val; @@ -125,16 +125,14 @@ static void inv_align_timestamp_it(struct inv_sensors_timestamp *ts) } void inv_sensors_timestamp_interrupt(struct inv_sensors_timestamp *ts, - uint32_t fifo_period, size_t fifo_nb, - size_t sensor_nb, int64_t timestamp) + size_t sample_nb, int64_t timestamp) { struct inv_sensors_timestamp_interval *it; int64_t delta, interval; - const uint32_t fifo_mult = fifo_period / ts->chip.clock_period; uint32_t period; bool valid = false; - if (fifo_nb == 0) + if (sample_nb == 0) return; /* update interrupt timestamp and compute chip and sensor periods */ @@ -144,14 +142,14 @@ void inv_sensors_timestamp_interrupt(struct inv_sensors_timestamp *ts, delta = it->up - it->lo; if (it->lo != 0) { /* compute period: delta time divided by number of samples */ - period = div_s64(delta, fifo_nb); - valid = inv_update_chip_period(ts, fifo_mult, period); + period = div_s64(delta, sample_nb); + valid = inv_update_chip_period(ts, period); } /* no previous data, compute theoritical value from interrupt */ if (ts->timestamp == 0) { /* elapsed time: sensor period * sensor samples number */ - interval = (int64_t)ts->period * (int64_t)sensor_nb; + interval = (int64_t)ts->period * (int64_t)sample_nb; ts->timestamp = it->up - interval; return; } diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c index cfb4a41ab7c1..63b85ec88c13 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c @@ -512,20 +512,20 @@ int inv_icm42600_buffer_fifo_parse(struct inv_icm42600_state *st) return 0; /* handle gyroscope timestamp and FIFO data parsing */ - ts = &gyro_st->ts; - inv_sensors_timestamp_interrupt(ts, st->fifo.period, st->fifo.nb.total, - st->fifo.nb.gyro, st->timestamp.gyro); if (st->fifo.nb.gyro > 0) { + ts = &gyro_st->ts; + inv_sensors_timestamp_interrupt(ts, st->fifo.nb.gyro, + st->timestamp.gyro); ret = inv_icm42600_gyro_parse_fifo(st->indio_gyro); if (ret) return ret; } /* handle accelerometer timestamp and FIFO data parsing */ - ts = &accel_st->ts; - inv_sensors_timestamp_interrupt(ts, st->fifo.period, st->fifo.nb.total, - st->fifo.nb.accel, st->timestamp.accel); if (st->fifo.nb.accel > 0) { + ts = &accel_st->ts; + inv_sensors_timestamp_interrupt(ts, st->fifo.nb.accel, + st->timestamp.accel); ret = inv_icm42600_accel_parse_fifo(st->indio_accel); if (ret) return ret; @@ -555,9 +555,7 @@ int inv_icm42600_buffer_hwfifo_flush(struct inv_icm42600_state *st, if (st->fifo.nb.gyro > 0) { ts = &gyro_st->ts; - inv_sensors_timestamp_interrupt(ts, st->fifo.period, - st->fifo.nb.total, st->fifo.nb.gyro, - gyro_ts); + inv_sensors_timestamp_interrupt(ts, st->fifo.nb.gyro, gyro_ts); ret = inv_icm42600_gyro_parse_fifo(st->indio_gyro); if (ret) return ret; @@ -565,9 +563,7 @@ int inv_icm42600_buffer_hwfifo_flush(struct inv_icm42600_state *st, if (st->fifo.nb.accel > 0) { ts = &accel_st->ts; - inv_sensors_timestamp_interrupt(ts, st->fifo.period, - st->fifo.nb.total, st->fifo.nb.accel, - accel_ts); + inv_sensors_timestamp_interrupt(ts, st->fifo.nb.accel, accel_ts); ret = inv_icm42600_accel_parse_fifo(st->indio_accel); if (ret) return ret; diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c index 86465226f7e1..0dc0f22a5582 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c @@ -100,7 +100,7 @@ irqreturn_t inv_mpu6050_read_fifo(int irq, void *p) goto end_session; /* Each FIFO data contains all sensors, so same number for FIFO and sensor data */ fifo_period = NSEC_PER_SEC / INV_MPU6050_DIVIDER_TO_FIFO_RATE(st->chip_config.divider); - inv_sensors_timestamp_interrupt(&st->timestamp, fifo_period, nb, nb, pf->timestamp); + inv_sensors_timestamp_interrupt(&st->timestamp, nb, pf->timestamp); inv_sensors_timestamp_apply_odr(&st->timestamp, fifo_period, nb, 0); /* clear internal data buffer for avoiding kernel data leak */ diff --git a/include/linux/iio/common/inv_sensors_timestamp.h b/include/linux/iio/common/inv_sensors_timestamp.h index a47d304d1ba7..8d506f1e9df2 100644 --- a/include/linux/iio/common/inv_sensors_timestamp.h +++ b/include/linux/iio/common/inv_sensors_timestamp.h @@ -71,8 +71,7 @@ int inv_sensors_timestamp_update_odr(struct inv_sensors_timestamp *ts, uint32_t period, bool fifo); void inv_sensors_timestamp_interrupt(struct inv_sensors_timestamp *ts, - uint32_t fifo_period, size_t fifo_nb, - size_t sensor_nb, int64_t timestamp); + size_t sample_nb, int64_t timestamp); static inline int64_t inv_sensors_timestamp_pop(struct inv_sensors_timestamp *ts) { -- cgit v1.2.3-59-g8ed1b From 51fafb3cd7fcf4f4682693b4d2883e2a5bfffe33 Mon Sep 17 00:00:00 2001 From: Marius Cristea Date: Thu, 25 Apr 2024 14:42:32 +0300 Subject: iio: adc: PAC1934: fix accessing out of bounds array index Fix accessing out of bounds array index for average current and voltage measurements. The device itself has only 4 channels, but in sysfs there are "fake" channels for the average voltages and currents too. Fixes: 0fb528c8255b ("iio: adc: adding support for PAC193x") Reported-by: Conor Dooley Signed-off-by: Marius Cristea Closes: https://lore.kernel.org/linux-iio/20240405-embellish-bonnet-ab5f10560d93@wendy/ Tested-by: Conor Dooley Link: https://lore.kernel.org/r/20240425114232.81390-1-marius.cristea@microchip.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/pac1934.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/iio/adc/pac1934.c b/drivers/iio/adc/pac1934.c index f751260605e4..456f12faa348 100644 --- a/drivers/iio/adc/pac1934.c +++ b/drivers/iio/adc/pac1934.c @@ -787,6 +787,15 @@ static int pac1934_read_raw(struct iio_dev *indio_dev, s64 curr_energy; int ret, channel = chan->channel - 1; + /* + * For AVG the index should be between 5 to 8. + * To calculate PAC1934_CH_VOLTAGE_AVERAGE, + * respectively PAC1934_CH_CURRENT real index, we need + * to remove the added offset (PAC1934_MAX_NUM_CHANNELS). + */ + if (channel >= PAC1934_MAX_NUM_CHANNELS) + channel = channel - PAC1934_MAX_NUM_CHANNELS; + ret = pac1934_retrieve_data(info, PAC1934_MIN_UPDATE_WAIT_TIME_US); if (ret < 0) return ret; -- cgit v1.2.3-59-g8ed1b From 827dca3129708a8465bde90c86c2e3c38e62dd4f Mon Sep 17 00:00:00 2001 From: Dimitri Fedrau Date: Wed, 24 Apr 2024 20:59:10 +0200 Subject: iio: temperature: mcp9600: Fix temperature reading for negative values Temperature is stored as 16bit value in two's complement format. Current implementation ignores the sign bit. Make it aware of the sign bit by using sign_extend32. Fixes: 3f6b9598b6df ("iio: temperature: Add MCP9600 thermocouple EMF converter") Signed-off-by: Dimitri Fedrau Reviewed-by: Marcelo Schmitt Tested-by: Andrew Hepp Link: https://lore.kernel.org/r/20240424185913.1177127-1-dima.fedrau@gmail.com Cc: Signed-off-by: Jonathan Cameron --- drivers/iio/temperature/mcp9600.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/iio/temperature/mcp9600.c b/drivers/iio/temperature/mcp9600.c index 46845804292b..7a3eef5d5e75 100644 --- a/drivers/iio/temperature/mcp9600.c +++ b/drivers/iio/temperature/mcp9600.c @@ -52,7 +52,8 @@ static int mcp9600_read(struct mcp9600_data *data, if (ret < 0) return ret; - *val = ret; + + *val = sign_extend32(ret, 15); return 0; } -- cgit v1.2.3-59-g8ed1b From 9c313ccdfc079f71f16c9b3d3a6c6d60996b9367 Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Sun, 21 Apr 2024 00:38:37 +0200 Subject: bitops: Change function return types from long to int Change the return types of bitops functions (ffs, fls, and fns) from long to int. The expected return values are in the range [0, 64], for which int is sufficient. Additionally, int aligns well with the return types of the corresponding __builtin_* functions, potentially reducing overall type conversions. Many of the existing bitops functions already return an int and don't need to be changed. The bitops functions in arch/ should be considered separately. Adjust some return variables to match the function return types. With GCC 13 and defconfig, these changes reduced the size of a test kernel image by 5,432 bytes on arm64 and by 248 bytes on riscv; there were no changes in size on x86_64, powerpc, or m68k. Signed-off-by: Thorsten Blum Signed-off-by: Arnd Bergmann --- include/asm-generic/bitops/__ffs.h | 4 ++-- include/asm-generic/bitops/__fls.h | 4 ++-- include/asm-generic/bitops/builtin-__ffs.h | 2 +- include/asm-generic/bitops/builtin-__fls.h | 2 +- include/linux/bitops.h | 6 +++--- tools/include/asm-generic/bitops/__ffs.h | 4 ++-- tools/include/asm-generic/bitops/__fls.h | 4 ++-- tools/include/linux/bitops.h | 2 +- 8 files changed, 14 insertions(+), 14 deletions(-) diff --git a/include/asm-generic/bitops/__ffs.h b/include/asm-generic/bitops/__ffs.h index 446fea6dda78..2d08c750c8a7 100644 --- a/include/asm-generic/bitops/__ffs.h +++ b/include/asm-generic/bitops/__ffs.h @@ -10,9 +10,9 @@ * * Undefined if no bit exists, so code should check against 0 first. */ -static __always_inline unsigned long generic___ffs(unsigned long word) +static __always_inline unsigned int generic___ffs(unsigned long word) { - int num = 0; + unsigned int num = 0; #if BITS_PER_LONG == 64 if ((word & 0xffffffff) == 0) { diff --git a/include/asm-generic/bitops/__fls.h b/include/asm-generic/bitops/__fls.h index 54ccccf96e21..e974ec932ec1 100644 --- a/include/asm-generic/bitops/__fls.h +++ b/include/asm-generic/bitops/__fls.h @@ -10,9 +10,9 @@ * * Undefined if no set bit exists, so code should check against 0 first. */ -static __always_inline unsigned long generic___fls(unsigned long word) +static __always_inline unsigned int generic___fls(unsigned long word) { - int num = BITS_PER_LONG - 1; + unsigned int num = BITS_PER_LONG - 1; #if BITS_PER_LONG == 64 if (!(word & (~0ul << 32))) { diff --git a/include/asm-generic/bitops/builtin-__ffs.h b/include/asm-generic/bitops/builtin-__ffs.h index 87024da44d10..cf4b3d33bf96 100644 --- a/include/asm-generic/bitops/builtin-__ffs.h +++ b/include/asm-generic/bitops/builtin-__ffs.h @@ -8,7 +8,7 @@ * * Undefined if no bit exists, so code should check against 0 first. */ -static __always_inline unsigned long __ffs(unsigned long word) +static __always_inline unsigned int __ffs(unsigned long word) { return __builtin_ctzl(word); } diff --git a/include/asm-generic/bitops/builtin-__fls.h b/include/asm-generic/bitops/builtin-__fls.h index 43a5aa9afbdb..6d72fc8a5259 100644 --- a/include/asm-generic/bitops/builtin-__fls.h +++ b/include/asm-generic/bitops/builtin-__fls.h @@ -8,7 +8,7 @@ * * Undefined if no set bit exists, so code should check against 0 first. */ -static __always_inline unsigned long __fls(unsigned long word) +static __always_inline unsigned int __fls(unsigned long word) { return (sizeof(word) * 8) - 1 - __builtin_clzl(word); } diff --git a/include/linux/bitops.h b/include/linux/bitops.h index 2ba557e067fe..f60220f119e2 100644 --- a/include/linux/bitops.h +++ b/include/linux/bitops.h @@ -200,7 +200,7 @@ static __always_inline __s64 sign_extend64(__u64 value, int index) return (__s64)(value << shift) >> shift; } -static inline unsigned fls_long(unsigned long l) +static inline unsigned int fls_long(unsigned long l) { if (sizeof(l) == 4) return fls(l); @@ -236,7 +236,7 @@ static inline int get_count_order_long(unsigned long l) * The result is not defined if no bits are set, so check that @word * is non-zero before calling this. */ -static inline unsigned long __ffs64(u64 word) +static inline unsigned int __ffs64(u64 word) { #if BITS_PER_LONG == 32 if (((u32)word) == 0UL) @@ -252,7 +252,7 @@ static inline unsigned long __ffs64(u64 word) * @word: The word to search * @n: Bit to find */ -static inline unsigned long fns(unsigned long word, unsigned int n) +static inline unsigned int fns(unsigned long word, unsigned int n) { unsigned int bit; diff --git a/tools/include/asm-generic/bitops/__ffs.h b/tools/include/asm-generic/bitops/__ffs.h index 9d1310519497..2d94c1e9b2f3 100644 --- a/tools/include/asm-generic/bitops/__ffs.h +++ b/tools/include/asm-generic/bitops/__ffs.h @@ -11,9 +11,9 @@ * * Undefined if no bit exists, so code should check against 0 first. */ -static __always_inline unsigned long __ffs(unsigned long word) +static __always_inline unsigned int __ffs(unsigned long word) { - int num = 0; + unsigned int num = 0; #if __BITS_PER_LONG == 64 if ((word & 0xffffffff) == 0) { diff --git a/tools/include/asm-generic/bitops/__fls.h b/tools/include/asm-generic/bitops/__fls.h index 54ccccf96e21..e974ec932ec1 100644 --- a/tools/include/asm-generic/bitops/__fls.h +++ b/tools/include/asm-generic/bitops/__fls.h @@ -10,9 +10,9 @@ * * Undefined if no set bit exists, so code should check against 0 first. */ -static __always_inline unsigned long generic___fls(unsigned long word) +static __always_inline unsigned int generic___fls(unsigned long word) { - int num = BITS_PER_LONG - 1; + unsigned int num = BITS_PER_LONG - 1; #if BITS_PER_LONG == 64 if (!(word & (~0ul << 32))) { diff --git a/tools/include/linux/bitops.h b/tools/include/linux/bitops.h index 7319f6ced108..8e073a111d2a 100644 --- a/tools/include/linux/bitops.h +++ b/tools/include/linux/bitops.h @@ -70,7 +70,7 @@ static inline unsigned long hweight_long(unsigned long w) return sizeof(w) == 4 ? hweight32(w) : hweight64(w); } -static inline unsigned fls_long(unsigned long l) +static inline unsigned int fls_long(unsigned long l) { if (sizeof(l) == 4) return fls(l); -- cgit v1.2.3-59-g8ed1b From f25eae2c405cbe810f8c52d743ea2b507c3fc301 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Fri, 29 Mar 2024 21:32:10 +0100 Subject: arch: Select fbdev helpers with CONFIG_VIDEO Various Kconfig options selected the per-architecture helpers for fbdev. But none of the contained code depends on fbdev. Standardize on CONFIG_VIDEO, which will allow to add more general helpers for video functionality. CONFIG_VIDEO protects each architecture's video/ directory. This allows for the use of more fine-grained control for each directory's files, such as the use of CONFIG_STI_CORE on parisc. v2: - sparc: rebased onto Makefile changes Signed-off-by: Thomas Zimmermann Reviewed-by: Sam Ravnborg Cc: "James E.J. Bottomley" Cc: Helge Deller Cc: "David S. Miller" Cc: Andreas Larsson Cc: Thomas Gleixner Cc: Ingo Molnar Cc: Borislav Petkov Cc: Dave Hansen Cc: x86@kernel.org Cc: "H. Peter Anvin" Signed-off-by: Arnd Bergmann --- arch/parisc/Makefile | 2 +- arch/sparc/Makefile | 4 ++-- arch/sparc/video/Makefile | 2 +- arch/x86/Makefile | 2 +- arch/x86/video/Makefile | 3 ++- 5 files changed, 7 insertions(+), 6 deletions(-) diff --git a/arch/parisc/Makefile b/arch/parisc/Makefile index 316f84f1d15c..21b8166a6883 100644 --- a/arch/parisc/Makefile +++ b/arch/parisc/Makefile @@ -119,7 +119,7 @@ export LIBGCC libs-y += arch/parisc/lib/ $(LIBGCC) -drivers-y += arch/parisc/video/ +drivers-$(CONFIG_VIDEO) += arch/parisc/video/ boot := arch/parisc/boot diff --git a/arch/sparc/Makefile b/arch/sparc/Makefile index 2a03daa68f28..757451c3ea1d 100644 --- a/arch/sparc/Makefile +++ b/arch/sparc/Makefile @@ -59,8 +59,8 @@ endif libs-y += arch/sparc/prom/ libs-y += arch/sparc/lib/ -drivers-$(CONFIG_PM) += arch/sparc/power/ -drivers-$(CONFIG_FB_CORE) += arch/sparc/video/ +drivers-$(CONFIG_PM) += arch/sparc/power/ +drivers-$(CONFIG_VIDEO) += arch/sparc/video/ boot := arch/sparc/boot diff --git a/arch/sparc/video/Makefile b/arch/sparc/video/Makefile index d4d83f1702c6..9dd82880a027 100644 --- a/arch/sparc/video/Makefile +++ b/arch/sparc/video/Makefile @@ -1,3 +1,3 @@ # SPDX-License-Identifier: GPL-2.0-only -obj-$(CONFIG_FB_CORE) += fbdev.o +obj-y += fbdev.o diff --git a/arch/x86/Makefile b/arch/x86/Makefile index 5ab93fcdd691..e71e5252763f 100644 --- a/arch/x86/Makefile +++ b/arch/x86/Makefile @@ -258,7 +258,7 @@ drivers-$(CONFIG_PCI) += arch/x86/pci/ # suspend and hibernation support drivers-$(CONFIG_PM) += arch/x86/power/ -drivers-$(CONFIG_FB_CORE) += arch/x86/video/ +drivers-$(CONFIG_VIDEO) += arch/x86/video/ #### # boot loader support. Several targets are kept for legacy purposes diff --git a/arch/x86/video/Makefile b/arch/x86/video/Makefile index 5ebe48752ffc..9dd82880a027 100644 --- a/arch/x86/video/Makefile +++ b/arch/x86/video/Makefile @@ -1,2 +1,3 @@ # SPDX-License-Identifier: GPL-2.0-only -obj-$(CONFIG_FB_CORE) += fbdev.o + +obj-y += fbdev.o -- cgit v1.2.3-59-g8ed1b From f178e96de7f0868e1b4d6df687794961f30125f2 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Fri, 29 Mar 2024 21:32:11 +0100 Subject: arch: Remove struct fb_info from video helpers The per-architecture video helpers do not depend on struct fb_info or anything else from fbdev. Remove it from the interface and replace fb_is_primary_device() with video_is_primary_device(). The new helper is similar in functionality, but can operate on non-fbdev devices. Signed-off-by: Thomas Zimmermann Reviewed-by: Sam Ravnborg Cc: "James E.J. Bottomley" Cc: Helge Deller Cc: "David S. Miller" Cc: Andreas Larsson Cc: Thomas Gleixner Cc: Ingo Molnar Cc: Borislav Petkov Cc: Dave Hansen Cc: x86@kernel.org Cc: "H. Peter Anvin" Signed-off-by: Arnd Bergmann --- arch/parisc/include/asm/fb.h | 8 +++++--- arch/parisc/video/fbdev.c | 9 +++++---- arch/sparc/include/asm/fb.h | 7 ++++--- arch/sparc/video/fbdev.c | 17 ++++++++--------- arch/x86/include/asm/fb.h | 8 +++++--- arch/x86/video/fbdev.c | 18 +++++++----------- drivers/video/fbdev/core/fbcon.c | 2 +- include/asm-generic/fb.h | 11 ++++++----- 8 files changed, 41 insertions(+), 39 deletions(-) diff --git a/arch/parisc/include/asm/fb.h b/arch/parisc/include/asm/fb.h index 658a8a7dc531..ed2a195a3e76 100644 --- a/arch/parisc/include/asm/fb.h +++ b/arch/parisc/include/asm/fb.h @@ -2,11 +2,13 @@ #ifndef _ASM_FB_H_ #define _ASM_FB_H_ -struct fb_info; +#include + +struct device; #if defined(CONFIG_STI_CORE) -int fb_is_primary_device(struct fb_info *info); -#define fb_is_primary_device fb_is_primary_device +bool video_is_primary_device(struct device *dev); +#define video_is_primary_device video_is_primary_device #endif #include diff --git a/arch/parisc/video/fbdev.c b/arch/parisc/video/fbdev.c index e4f8ac99fc9e..540fa0c919d5 100644 --- a/arch/parisc/video/fbdev.c +++ b/arch/parisc/video/fbdev.c @@ -5,12 +5,13 @@ * Copyright (C) 2001-2002 Thomas Bogendoerfer */ -#include #include #include