All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v5 08/21] kvm: x86: Enable dynamic xfeatures at KVM_SET_CPUID2
From: Yang Zhong @ 2022-01-05 12:35 UTC (permalink / raw)
  To: x86, kvm, linux-kernel, linux-doc, linux-kselftest, tglx, mingo,
	bp, dave.hansen, pbonzini, corbet, shuah, seanjc
  Cc: jun.nakajima, kevin.tian, jing2.liu, jing2.liu, guang.zeng,
	wei.w.wang, yang.zhong
In-Reply-To: <20220105123532.12586-1-yang.zhong@intel.com>

From: Jing Liu <jing2.liu@intel.com>

KVM can request fpstate expansion in two approaches:

  1) When intercepting guest updates to XCR0 and XFD MSR;

  2) Before vcpu runs (e.g. at KVM_SET_CPUID2);

The first option doesn't waste memory for legacy guest if it doesn't
support XFD. However doing so introduces more complexity and also
imposes an order requirement in the restoring path, i.e. XCR0/XFD
must be restored before XSTATE.

Given that the agreement is to do the static approach. This is
considered a better tradeoff though it does waste 8K memory for
legacy guest if its CPUID includes dynamically-enabled xfeatures.

Successful fpstate expansion requires userspace VMM to acquire
guest xstate permissions before calling KVM_SET_CPUID2.

Also take the chance to adjust the indent in kvm_set_cpuid().

Signed-off-by: Jing Liu <jing2.liu@intel.com>
Signed-off-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Yang Zhong <yang.zhong@intel.com>
---
 arch/x86/kvm/cpuid.c | 42 +++++++++++++++++++++++++++++-------------
 1 file changed, 29 insertions(+), 13 deletions(-)

diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
index eb52dde5deec..a0fedf1514ab 100644
--- a/arch/x86/kvm/cpuid.c
+++ b/arch/x86/kvm/cpuid.c
@@ -84,9 +84,12 @@ static inline struct kvm_cpuid_entry2 *cpuid_entry2_find(
 	return NULL;
 }
 
-static int kvm_check_cpuid(struct kvm_cpuid_entry2 *entries, int nent)
+static int kvm_check_cpuid(struct kvm_vcpu *vcpu,
+			   struct kvm_cpuid_entry2 *entries,
+			   int nent)
 {
 	struct kvm_cpuid_entry2 *best;
+	u64 xfeatures;
 
 	/*
 	 * The existing code assumes virtual address is 48-bit or 57-bit in the
@@ -100,7 +103,20 @@ static int kvm_check_cpuid(struct kvm_cpuid_entry2 *entries, int nent)
 			return -EINVAL;
 	}
 
-	return 0;
+	/*
+	 * Exposing dynamic xfeatures to the guest requires additional
+	 * enabling in the FPU, e.g. to expand the guest XSAVE state size.
+	 */
+	best = cpuid_entry2_find(entries, nent, 0xd, 0);
+	if (!best)
+		return 0;
+
+	xfeatures = best->eax | ((u64)best->edx << 32);
+	xfeatures &= XFEATURE_MASK_USER_DYNAMIC;
+	if (!xfeatures)
+		return 0;
+
+	return fpu_enable_guest_xfd_features(&vcpu->arch.guest_fpu, xfeatures);
 }
 
 static void kvm_update_kvm_cpuid_base(struct kvm_vcpu *vcpu)
@@ -280,21 +296,21 @@ u64 kvm_vcpu_reserved_gpa_bits_raw(struct kvm_vcpu *vcpu)
 static int kvm_set_cpuid(struct kvm_vcpu *vcpu, struct kvm_cpuid_entry2 *e2,
                         int nent)
 {
-    int r;
+	int r;
 
-    r = kvm_check_cpuid(e2, nent);
-    if (r)
-        return r;
+	r = kvm_check_cpuid(vcpu, e2, nent);
+	if (r)
+		return r;
 
-    kvfree(vcpu->arch.cpuid_entries);
-    vcpu->arch.cpuid_entries = e2;
-    vcpu->arch.cpuid_nent = nent;
+	kvfree(vcpu->arch.cpuid_entries);
+	vcpu->arch.cpuid_entries = e2;
+	vcpu->arch.cpuid_nent = nent;
 
-    kvm_update_kvm_cpuid_base(vcpu);
-    kvm_update_cpuid_runtime(vcpu);
-    kvm_vcpu_after_set_cpuid(vcpu);
+	kvm_update_kvm_cpuid_base(vcpu);
+	kvm_update_cpuid_runtime(vcpu);
+	kvm_vcpu_after_set_cpuid(vcpu);
 
-    return 0;
+	return 0;
 }
 
 /* when an old userspace process fills a new kernel module */

^ permalink raw reply related

* [PATCH v5 07/21] x86/fpu: Provide fpu_enable_guest_xfd_features() for KVM
From: Yang Zhong @ 2022-01-05 12:35 UTC (permalink / raw)
  To: x86, kvm, linux-kernel, linux-doc, linux-kselftest, tglx, mingo,
	bp, dave.hansen, pbonzini, corbet, shuah, seanjc
  Cc: jun.nakajima, kevin.tian, jing2.liu, jing2.liu, guang.zeng,
	wei.w.wang, yang.zhong
In-Reply-To: <20220105123532.12586-1-yang.zhong@intel.com>

From: Sean Christopherson <seanjc@google.com>

Provide a wrapper for expanding the guest fpstate buffer according
to requested xfeatures. KVM wants to call this wrapper to manage
any dynamic xstate used by the guest.

Suggested-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Yang Zhong <yang.zhong@intel.com>
---
 arch/x86/include/asm/fpu/api.h |  1 +
 arch/x86/kernel/fpu/core.c     | 17 +++++++++++++++++
 2 files changed, 18 insertions(+)

diff --git a/arch/x86/include/asm/fpu/api.h b/arch/x86/include/asm/fpu/api.h
index d8c222290e68..1ed2a247a84e 100644
--- a/arch/x86/include/asm/fpu/api.h
+++ b/arch/x86/include/asm/fpu/api.h
@@ -138,6 +138,7 @@ extern inline u64 xstate_get_guest_group_perm(void);
 extern bool fpu_alloc_guest_fpstate(struct fpu_guest *gfpu);
 extern void fpu_free_guest_fpstate(struct fpu_guest *gfpu);
 extern int fpu_swap_kvm_fpstate(struct fpu_guest *gfpu, bool enter_guest);
+extern int fpu_enable_guest_xfd_features(struct fpu_guest *guest_fpu, u64 xfeatures);
 
 extern void fpu_copy_guest_fpstate_to_uabi(struct fpu_guest *gfpu, void *buf, unsigned int size, u32 pkru);
 extern int fpu_copy_uabi_to_guest_fpstate(struct fpu_guest *gfpu, const void *buf, u64 xcr0, u32 *vpkru);
diff --git a/arch/x86/kernel/fpu/core.c b/arch/x86/kernel/fpu/core.c
index a78bc547fc03..5b08d20a4005 100644
--- a/arch/x86/kernel/fpu/core.c
+++ b/arch/x86/kernel/fpu/core.c
@@ -261,6 +261,23 @@ void fpu_free_guest_fpstate(struct fpu_guest *gfpu)
 }
 EXPORT_SYMBOL_GPL(fpu_free_guest_fpstate);
 
+int fpu_enable_guest_xfd_features(struct fpu_guest *guest_fpu, u64 xfeatures)
+{
+	lockdep_assert_preemption_enabled();
+
+	/* Nothing to do if all requested features are already enabled. */
+	xfeatures &= ~guest_fpu->xfeatures;
+	if (!xfeatures)
+		return 0;
+
+	/* Dynamic xfeatures are not supported with 32-bit kernels. */
+	if (!IS_ENABLED(CONFIG_X86_64))
+		return 0;
+
+	return __xfd_enable_feature(xfeatures, guest_fpu);
+}
+EXPORT_SYMBOL_GPL(fpu_enable_guest_xfd_features);
+
 int fpu_swap_kvm_fpstate(struct fpu_guest *guest_fpu, bool enter_guest)
 {
 	struct fpstate *guest_fps = guest_fpu->fpstate;

^ permalink raw reply related

* [PATCH v5 13/21] kvm: x86: Emulate IA32_XFD_ERR for guest
From: Yang Zhong @ 2022-01-05 12:35 UTC (permalink / raw)
  To: x86, kvm, linux-kernel, linux-doc, linux-kselftest, tglx, mingo,
	bp, dave.hansen, pbonzini, corbet, shuah, seanjc
  Cc: jun.nakajima, kevin.tian, jing2.liu, jing2.liu, guang.zeng,
	wei.w.wang, yang.zhong
In-Reply-To: <20220105123532.12586-1-yang.zhong@intel.com>

From: Jing Liu <jing2.liu@intel.com>

Emulate read/write to IA32_XFD_ERR MSR.

Only the saved value in the guest_fpu container is touched in the
emulation handler. Actual MSR update is handled right before entering
the guest (with preemption disabled)

Signed-off-by: Zeng Guang <guang.zeng@intel.com>
Signed-off-by: Wei Wang <wei.w.wang@intel.com>
Signed-off-by: Jing Liu <jing2.liu@intel.com>
Signed-off-by: Yang Zhong <yang.zhong@intel.com>
---
 arch/x86/kvm/x86.c | 21 ++++++++++++++++++++-
 1 file changed, 20 insertions(+), 1 deletion(-)

diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 2c988f8ca616..434986928552 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -1377,7 +1377,7 @@ static const u32 msrs_to_save_all[] = {
 	MSR_F15H_PERF_CTL3, MSR_F15H_PERF_CTL4, MSR_F15H_PERF_CTL5,
 	MSR_F15H_PERF_CTR0, MSR_F15H_PERF_CTR1, MSR_F15H_PERF_CTR2,
 	MSR_F15H_PERF_CTR3, MSR_F15H_PERF_CTR4, MSR_F15H_PERF_CTR5,
-	MSR_IA32_XFD,
+	MSR_IA32_XFD, MSR_IA32_XFD_ERR,
 };
 
 static u32 msrs_to_save[ARRAY_SIZE(msrs_to_save_all)];
@@ -3699,6 +3699,17 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
 
 		fpu_update_guest_xfd(&vcpu->arch.guest_fpu, data);
 		break;
+	case MSR_IA32_XFD_ERR:
+		if (!msr_info->host_initiated &&
+		    !guest_cpuid_has(vcpu, X86_FEATURE_XFD))
+			return 1;
+
+		if (data & ~(XFEATURE_MASK_USER_DYNAMIC &
+			     vcpu->arch.guest_supported_xcr0))
+			return 1;
+
+		vcpu->arch.guest_fpu.xfd_err = data;
+		break;
 #endif
 	default:
 		if (kvm_pmu_is_valid_msr(vcpu, msr))
@@ -4028,6 +4039,13 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
 
 		msr_info->data = vcpu->arch.guest_fpu.fpstate->xfd;
 		break;
+	case MSR_IA32_XFD_ERR:
+		if (!msr_info->host_initiated &&
+		    !guest_cpuid_has(vcpu, X86_FEATURE_XFD))
+			return 1;
+
+		msr_info->data = vcpu->arch.guest_fpu.xfd_err;
+		break;
 #endif
 	default:
 		if (kvm_pmu_is_valid_msr(vcpu, msr_info->index))
@@ -6465,6 +6483,7 @@ static void kvm_init_msr_list(void)
 				continue;
 			break;
 		case MSR_IA32_XFD:
+		case MSR_IA32_XFD_ERR:
 			if (!kvm_cpu_cap_has(X86_FEATURE_XFD))
 				continue;
 			break;

^ permalink raw reply related

* [PATCH v5 03/21] kvm: x86: Fix xstate_required_size() to follow XSTATE alignment rule
From: Yang Zhong @ 2022-01-05 12:35 UTC (permalink / raw)
  To: x86, kvm, linux-kernel, linux-doc, linux-kselftest, tglx, mingo,
	bp, dave.hansen, pbonzini, corbet, shuah, seanjc
  Cc: jun.nakajima, kevin.tian, jing2.liu, jing2.liu, guang.zeng,
	wei.w.wang, yang.zhong
In-Reply-To: <20220105123532.12586-1-yang.zhong@intel.com>

From: Jing Liu <jing2.liu@intel.com>

CPUID.0xD.1.EBX enumerates the size of the XSAVE area (in compacted
format) required by XSAVES. If CPUID.0xD.i.ECX[1] is set for a state
component (i), this state component should be located on the next
64-bytes boundary following the preceding state component in the
compacted layout.

Fix xstate_required_size() to follow the alignment rule. AMX is the
first state component with 64-bytes alignment to catch this bug.

Signed-off-by: Jing Liu <jing2.liu@intel.com>
Signed-off-by: Yang Zhong <yang.zhong@intel.com>
---
 arch/x86/kvm/cpuid.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
index 0b920e12bb6d..f3e6fda6b858 100644
--- a/arch/x86/kvm/cpuid.c
+++ b/arch/x86/kvm/cpuid.c
@@ -42,7 +42,11 @@ static u32 xstate_required_size(u64 xstate_bv, bool compacted)
 		if (xstate_bv & 0x1) {
 		        u32 eax, ebx, ecx, edx, offset;
 		        cpuid_count(0xD, feature_bit, &eax, &ebx, &ecx, &edx);
-			offset = compacted ? ret : ebx;
+			/* ECX[1]: 64B alignment in compacted form */
+			if (compacted)
+				offset = (ecx & 0x2) ? ALIGN(ret, 64) : ret;
+			else
+				offset = ebx;
 			ret = max(ret, offset + eax);
 		}
 

^ permalink raw reply related

* [PATCH v5 04/21] kvm: x86: Exclude unpermitted xfeatures at KVM_GET_SUPPORTED_CPUID
From: Yang Zhong @ 2022-01-05 12:35 UTC (permalink / raw)
  To: x86, kvm, linux-kernel, linux-doc, linux-kselftest, tglx, mingo,
	bp, dave.hansen, pbonzini, corbet, shuah, seanjc
  Cc: jun.nakajima, kevin.tian, jing2.liu, jing2.liu, guang.zeng,
	wei.w.wang, yang.zhong
In-Reply-To: <20220105123532.12586-1-yang.zhong@intel.com>

From: Jing Liu <jing2.liu@intel.com>

KVM_GET_SUPPORTED_CPUID should not include any dynamic xstates in
CPUID[0xD] if they have not been requested with prctl. Otherwise
a process which directly passes KVM_GET_SUPPORTED_CPUID to
KVM_SET_CPUID2 would now fail even if it doesn't intend to use a
dynamically enabled feature. Userspace must know that prctl is
required and allocate >4K xstate buffer before setting any dynamic
bit.

Suggested-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Jing Liu <jing2.liu@intel.com>
Signed-off-by: Yang Zhong <yang.zhong@intel.com>
---
 Documentation/virt/kvm/api.rst | 4 ++++
 arch/x86/kvm/cpuid.c           | 9 ++++++---
 2 files changed, 10 insertions(+), 3 deletions(-)

diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst
index 6b683dfea8f2..f4ea5e41a4d0 100644
--- a/Documentation/virt/kvm/api.rst
+++ b/Documentation/virt/kvm/api.rst
@@ -1687,6 +1687,10 @@ userspace capabilities, and with user requirements (for example, the
 user may wish to constrain cpuid to emulate older hardware, or for
 feature consistency across a cluster).
 
+Dynamically-enabled feature bits need to be requested with
+``arch_prctl()`` before calling this ioctl. Feature bits that have not
+been requested are excluded from the result.
+
 Note that certain capabilities, such as KVM_CAP_X86_DISABLE_EXITS, may
 expose cpuid features (e.g. MONITOR) which are not supported by kvm in
 its default configuration. If userspace enables such capabilities, it
diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
index f3e6fda6b858..eb52dde5deec 100644
--- a/arch/x86/kvm/cpuid.c
+++ b/arch/x86/kvm/cpuid.c
@@ -815,11 +815,13 @@ static inline int __do_cpuid_func(struct kvm_cpuid_array *array, u32 function)
 				goto out;
 		}
 		break;
-	case 0xd:
-		entry->eax &= supported_xcr0;
+	case 0xd: {
+		u64 guest_perm = xstate_get_guest_group_perm();
+
+		entry->eax &= supported_xcr0 & guest_perm;
 		entry->ebx = xstate_required_size(supported_xcr0, false);
 		entry->ecx = entry->ebx;
-		entry->edx &= supported_xcr0 >> 32;
+		entry->edx &= (supported_xcr0 & guest_perm) >> 32;
 		if (!supported_xcr0)
 			break;
 
@@ -866,6 +868,7 @@ static inline int __do_cpuid_func(struct kvm_cpuid_array *array, u32 function)
 			entry->edx = 0;
 		}
 		break;
+	}
 	case 0x12:
 		/* Intel SGX */
 		if (!kvm_cpu_cap_has(X86_FEATURE_SGX)) {

^ permalink raw reply related

* [PATCH v5 05/21] x86/fpu: Make XFD initialization in __fpstate_reset() a function argument
From: Yang Zhong @ 2022-01-05 12:35 UTC (permalink / raw)
  To: x86, kvm, linux-kernel, linux-doc, linux-kselftest, tglx, mingo,
	bp, dave.hansen, pbonzini, corbet, shuah, seanjc
  Cc: jun.nakajima, kevin.tian, jing2.liu, jing2.liu, guang.zeng,
	wei.w.wang, yang.zhong
In-Reply-To: <20220105123532.12586-1-yang.zhong@intel.com>

From: Jing Liu <jing2.liu@intel.com>

vCPU threads are different from native tasks regarding to the initial XFD
value. While all native tasks follow a fixed value (init_fpstate::xfd)
established by the FPU core at boot, vCPU threads need to obey the reset
value (i.e. ZERO) defined by the specification, to meet the expectation of
the guest.

Let the caller supply an argument and adjust the host and guest related
invocations accordingly.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Jing Liu <jing2.liu@intel.com>
Signed-off-by: Yang Zhong <yang.zhong@intel.com>
---
 arch/x86/kernel/fpu/core.c | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/arch/x86/kernel/fpu/core.c b/arch/x86/kernel/fpu/core.c
index eddeeb4ed2f5..a78bc547fc03 100644
--- a/arch/x86/kernel/fpu/core.c
+++ b/arch/x86/kernel/fpu/core.c
@@ -199,7 +199,7 @@ void fpu_reset_from_exception_fixup(void)
 }
 
 #if IS_ENABLED(CONFIG_KVM)
-static void __fpstate_reset(struct fpstate *fpstate);
+static void __fpstate_reset(struct fpstate *fpstate, u64 xfd);
 
 static void fpu_init_guest_permissions(struct fpu_guest *gfpu)
 {
@@ -231,7 +231,8 @@ bool fpu_alloc_guest_fpstate(struct fpu_guest *gfpu)
 	if (!fpstate)
 		return false;
 
-	__fpstate_reset(fpstate);
+	/* Leave xfd to 0 (the reset value defined by spec) */
+	__fpstate_reset(fpstate, 0);
 	fpstate_init_user(fpstate);
 	fpstate->is_valloc	= true;
 	fpstate->is_guest	= true;
@@ -454,21 +455,21 @@ void fpstate_init_user(struct fpstate *fpstate)
 		fpstate_init_fstate(fpstate);
 }
 
-static void __fpstate_reset(struct fpstate *fpstate)
+static void __fpstate_reset(struct fpstate *fpstate, u64 xfd)
 {
 	/* Initialize sizes and feature masks */
 	fpstate->size		= fpu_kernel_cfg.default_size;
 	fpstate->user_size	= fpu_user_cfg.default_size;
 	fpstate->xfeatures	= fpu_kernel_cfg.default_features;
 	fpstate->user_xfeatures	= fpu_user_cfg.default_features;
-	fpstate->xfd		= init_fpstate.xfd;
+	fpstate->xfd		= xfd;
 }
 
 void fpstate_reset(struct fpu *fpu)
 {
 	/* Set the fpstate pointer to the default fpstate */
 	fpu->fpstate = &fpu->__fpstate;
-	__fpstate_reset(fpu->fpstate);
+	__fpstate_reset(fpu->fpstate, init_fpstate.xfd);
 
 	/* Initialize the permission related info in fpu */
 	fpu->perm.__state_perm		= fpu_kernel_cfg.default_features;

^ permalink raw reply related

* Re: [PATCH] docs/sphinx: fix compatibility with sphinx < 1.8
From: Alex Bennée @ 2022-01-05 12:35 UTC (permalink / raw)
  To: marcandre.lureau; +Cc: thuth, qemu-devel
In-Reply-To: <20220104074649.1712440-1-marcandre.lureau@redhat.com>


marcandre.lureau@redhat.com writes:

> From: Marc-André Lureau <marcandre.lureau@redhat.com>
>
> SphinxDirective was added with sphinx 1.8 (2018-09-13).
>
> Reported-by: Thomas Huth <thuth@redhat.com>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

Queued to testing/next (as I need it for Thomas's API updates), thanks.


-- 
Alex Bennée


^ permalink raw reply

* [PULL 0/8] Misc patches (tests, docs, compat machines)
From: Thomas Huth @ 2022-01-05 12:36 UTC (permalink / raw)
  To: qemu-devel; +Cc: Richard Henderson

 Hi!

The following changes since commit fb084237a3b78b20fd9d888dffd673b6656ea3be:

  common-user: Really fix i386 calls to safe_syscall_set_errno_tail (2022-01-04 21:14:23 -0800)

are available in the Git repository at:

  https://gitlab.com/thuth/qemu.git tags/pull-request-2022-01-05

for you to fetch changes up to 057dc9a635fe37118a98b32e8bd9d8ed47b1a102:

  docs/tools/qemu-trace-stap.rst: Do not hard-code the QEMU binary name (2022-01-05 11:10:13 +0100)

----------------------------------------------------------------
* Add compat machines for 7.0
* Some minor qtest and unit test improvements
* Remove -no-quit option
* Fixes for the docs

----------------------------------------------------------------
Cornelia Huck (1):
      hw: Add compat machines for 7.0

Marc-André Lureau (1):
      docs/sphinx: fix compatibility with sphinx < 1.8

Philippe Mathieu-Daudé (1):
      tests/unit/test-util-sockets: Use g_file_open_tmp() to create temp file

Thomas Huth (5):
      tests/qtest/test-x86-cpuid-compat: Check for machines before using them
      tests/qtest/hd-geo-test: Check for the lsi53c895a controller before using it
      qemu-options: Remove the deprecated -no-quit option
      gitlab-ci: Enable docs in the centos job
      docs/tools/qemu-trace-stap.rst: Do not hard-code the QEMU binary name

 .gitlab-ci.d/buildtest.yml          |  2 +-
 docs/about/deprecated.rst           |  6 ---
 docs/about/removed-features.rst     |  7 +++
 docs/sphinx/fakedbusdoc.py          |  4 +-
 docs/tools/qemu-trace-stap.rst      | 24 +++++------
 hw/arm/virt.c                       |  9 +++-
 hw/core/machine.c                   |  3 ++
 hw/i386/pc.c                        |  3 ++
 hw/i386/pc_piix.c                   | 14 +++++-
 hw/i386/pc_q35.c                    | 13 +++++-
 hw/ppc/spapr.c                      | 15 ++++++-
 hw/s390x/s390-virtio-ccw.c          | 14 +++++-
 include/hw/boards.h                 |  3 ++
 include/hw/i386/pc.h                |  3 ++
 qemu-options.hx                     |  8 ----
 softmmu/vl.c                        |  8 +---
 tests/qtest/hd-geo-test.c           |  8 ++--
 tests/qtest/test-x86-cpuid-compat.c | 85 +++++++++++++++++++++----------------
 tests/unit/test-util-sockets.c      |  6 ++-
 19 files changed, 151 insertions(+), 84 deletions(-)



^ permalink raw reply

* [PULL 1/8] hw: Add compat machines for 7.0
From: Thomas Huth @ 2022-01-05 12:36 UTC (permalink / raw)
  To: qemu-devel
  Cc: Andrew Jones, Daniel P . Berrangé, Juan Quintela,
	Cornelia Huck, Richard Henderson, Christian Borntraeger,
	Cédric Le Goater
In-Reply-To: <20220105123612.432038-1-thuth@redhat.com>

From: Cornelia Huck <cohuck@redhat.com>

Add 7.0 machine types for arm/i440fx/q35/s390x/spapr.

Signed-off-by: Cornelia Huck <cohuck@redhat.com>
Reviewed-by: Juan Quintela <quintela@redhat.com>
Reviewed-by: Andrew Jones <drjones@redhat.com>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Reviewed-by: Christian Borntraeger <borntraeger@de.ibm.com>
Acked-by: Cédric Le Goater <clg@kaod.org>
Message-Id: <20211217143948.289995-1-cohuck@redhat.com>
Signed-off-by: Thomas Huth <thuth@redhat.com>
---
 hw/arm/virt.c              |  9 ++++++++-
 hw/core/machine.c          |  3 +++
 hw/i386/pc.c               |  3 +++
 hw/i386/pc_piix.c          | 14 +++++++++++++-
 hw/i386/pc_q35.c           | 13 ++++++++++++-
 hw/ppc/spapr.c             | 15 +++++++++++++--
 hw/s390x/s390-virtio-ccw.c | 14 +++++++++++++-
 include/hw/boards.h        |  3 +++
 include/hw/i386/pc.h       |  3 +++
 9 files changed, 71 insertions(+), 6 deletions(-)

diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 6bce595aba..4593fea1ce 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -2856,10 +2856,17 @@ static void machvirt_machine_init(void)
 }
 type_init(machvirt_machine_init);
 
+static void virt_machine_7_0_options(MachineClass *mc)
+{
+}
+DEFINE_VIRT_MACHINE_AS_LATEST(7, 0)
+
 static void virt_machine_6_2_options(MachineClass *mc)
 {
+    virt_machine_7_0_options(mc);
+    compat_props_add(mc->compat_props, hw_compat_6_2, hw_compat_6_2_len);
 }
-DEFINE_VIRT_MACHINE_AS_LATEST(6, 2)
+DEFINE_VIRT_MACHINE(6, 2)
 
 static void virt_machine_6_1_options(MachineClass *mc)
 {
diff --git a/hw/core/machine.c b/hw/core/machine.c
index a4a2df405f..debcdc0e70 100644
--- a/hw/core/machine.c
+++ b/hw/core/machine.c
@@ -37,6 +37,9 @@
 #include "hw/virtio/virtio.h"
 #include "hw/virtio/virtio-pci.h"
 
+GlobalProperty hw_compat_6_2[] = {};
+const size_t hw_compat_6_2_len = G_N_ELEMENTS(hw_compat_6_2);
+
 GlobalProperty hw_compat_6_1[] = {
     { "vhost-user-vsock-device", "seqpacket", "off" },
     { "nvme-ns", "shared", "off" },
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index a2ef40ecbc..fccde2ef39 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -94,6 +94,9 @@
 #include "trace.h"
 #include CONFIG_DEVICES
 
+GlobalProperty pc_compat_6_2[] = {};
+const size_t pc_compat_6_2_len = G_N_ELEMENTS(pc_compat_6_2);
+
 GlobalProperty pc_compat_6_1[] = {
     { TYPE_X86_CPU, "hv-version-id-build", "0x1bbc" },
     { TYPE_X86_CPU, "hv-version-id-major", "0x0006" },
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index 223dd3e05d..1999190276 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -413,7 +413,7 @@ static void pc_i440fx_machine_options(MachineClass *m)
     machine_class_allow_dynamic_sysbus_dev(m, TYPE_VMBUS_BRIDGE);
 }
 
-static void pc_i440fx_6_2_machine_options(MachineClass *m)
+static void pc_i440fx_7_0_machine_options(MachineClass *m)
 {
     PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
     pc_i440fx_machine_options(m);
@@ -422,6 +422,18 @@ static void pc_i440fx_6_2_machine_options(MachineClass *m)
     pcmc->default_cpu_version = 1;
 }
 
+DEFINE_I440FX_MACHINE(v7_0, "pc-i440fx-7.0", NULL,
+                      pc_i440fx_7_0_machine_options);
+
+static void pc_i440fx_6_2_machine_options(MachineClass *m)
+{
+    pc_i440fx_7_0_machine_options(m);
+    m->alias = NULL;
+    m->is_default = false;
+    compat_props_add(m->compat_props, hw_compat_6_2, hw_compat_6_2_len);
+    compat_props_add(m->compat_props, pc_compat_6_2, pc_compat_6_2_len);
+}
+
 DEFINE_I440FX_MACHINE(v6_2, "pc-i440fx-6.2", NULL,
                       pc_i440fx_6_2_machine_options);
 
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index e1e100316d..2e981f436c 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -360,7 +360,7 @@ static void pc_q35_machine_options(MachineClass *m)
     m->max_cpus = 288;
 }
 
-static void pc_q35_6_2_machine_options(MachineClass *m)
+static void pc_q35_7_0_machine_options(MachineClass *m)
 {
     PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
     pc_q35_machine_options(m);
@@ -368,6 +368,17 @@ static void pc_q35_6_2_machine_options(MachineClass *m)
     pcmc->default_cpu_version = 1;
 }
 
+DEFINE_Q35_MACHINE(v7_0, "pc-q35-7.0", NULL,
+                   pc_q35_7_0_machine_options);
+
+static void pc_q35_6_2_machine_options(MachineClass *m)
+{
+    pc_q35_7_0_machine_options(m);
+    m->alias = NULL;
+    compat_props_add(m->compat_props, hw_compat_6_2, hw_compat_6_2_len);
+    compat_props_add(m->compat_props, pc_compat_6_2, pc_compat_6_2_len);
+}
+
 DEFINE_Q35_MACHINE(v6_2, "pc-q35-6.2", NULL,
                    pc_q35_6_2_machine_options);
 
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index 3b5fd749be..8373429325 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -4665,15 +4665,26 @@ static void spapr_machine_latest_class_options(MachineClass *mc)
     }                                                                \
     type_init(spapr_machine_register_##suffix)
 
+/*
+ * pseries-7.0
+ */
+static void spapr_machine_7_0_class_options(MachineClass *mc)
+{
+    /* Defaults for the latest behaviour inherited from the base class */
+}
+
+DEFINE_SPAPR_MACHINE(7_0, "7.0", true);
+
 /*
  * pseries-6.2
  */
 static void spapr_machine_6_2_class_options(MachineClass *mc)
 {
-    /* Defaults for the latest behaviour inherited from the base class */
+    spapr_machine_7_0_class_options(mc);
+    compat_props_add(mc->compat_props, hw_compat_6_2, hw_compat_6_2_len);
 }
 
-DEFINE_SPAPR_MACHINE(6_2, "6.2", true);
+DEFINE_SPAPR_MACHINE(6_2, "6.2", false);
 
 /*
  * pseries-6.1
diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c
index 653587ea62..84e3e63c43 100644
--- a/hw/s390x/s390-virtio-ccw.c
+++ b/hw/s390x/s390-virtio-ccw.c
@@ -791,14 +791,26 @@ bool css_migration_enabled(void)
     }                                                                         \
     type_init(ccw_machine_register_##suffix)
 
+static void ccw_machine_7_0_instance_options(MachineState *machine)
+{
+}
+
+static void ccw_machine_7_0_class_options(MachineClass *mc)
+{
+}
+DEFINE_CCW_MACHINE(7_0, "7.0", true);
+
 static void ccw_machine_6_2_instance_options(MachineState *machine)
 {
+    ccw_machine_7_0_instance_options(machine);
 }
 
 static void ccw_machine_6_2_class_options(MachineClass *mc)
 {
+    ccw_machine_7_0_class_options(mc);
+    compat_props_add(mc->compat_props, hw_compat_6_2, hw_compat_6_2_len);
 }
-DEFINE_CCW_MACHINE(6_2, "6.2", true);
+DEFINE_CCW_MACHINE(6_2, "6.2", false);
 
 static void ccw_machine_6_1_instance_options(MachineState *machine)
 {
diff --git a/include/hw/boards.h b/include/hw/boards.h
index f49a2578ea..c92ac8815c 100644
--- a/include/hw/boards.h
+++ b/include/hw/boards.h
@@ -380,6 +380,9 @@ struct MachineState {
     } \
     type_init(machine_initfn##_register_types)
 
+extern GlobalProperty hw_compat_6_2[];
+extern const size_t hw_compat_6_2_len;
+
 extern GlobalProperty hw_compat_6_1[];
 extern const size_t hw_compat_6_1_len;
 
diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
index 9ab39e428f..b38947c224 100644
--- a/include/hw/i386/pc.h
+++ b/include/hw/i386/pc.h
@@ -196,6 +196,9 @@ void pc_madt_cpu_entry(AcpiDeviceIf *adev, int uid,
 /* sgx.c */
 void pc_machine_init_sgx_epc(PCMachineState *pcms);
 
+extern GlobalProperty pc_compat_6_2[];
+extern const size_t pc_compat_6_2_len;
+
 extern GlobalProperty pc_compat_6_1[];
 extern const size_t pc_compat_6_1_len;
 
-- 
2.27.0



^ permalink raw reply related

* [PATCH] phy: mapphone-mdm6600: Fix PM disable depth imbalance in phy_mdm6600_probe
From: Miaoqian Lin @ 2022-01-05 12:39 UTC (permalink / raw)
  Cc: linmq006, Kishon Vijay Abraham I, Vinod Koul, Tony Lindgren,
	linux-phy, linux-kernel

The pm_runtime_enable will increase power disable depth.
If the probe fails, we should use pm_runtime_disable() to balance
pm_runtime_enable().

Fixes: f7f50b2 ("phy: mapphone-mdm6600: Add runtime PM support for n_gsm on USB suspend")
Signed-off-by: Miaoqian Lin <linmq006@gmail.com>
---
 drivers/phy/motorola/phy-mapphone-mdm6600.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/phy/motorola/phy-mapphone-mdm6600.c b/drivers/phy/motorola/phy-mapphone-mdm6600.c
index 5172971f4c36..14666750946c 100644
--- a/drivers/phy/motorola/phy-mapphone-mdm6600.c
+++ b/drivers/phy/motorola/phy-mapphone-mdm6600.c
@@ -630,6 +630,9 @@ static int phy_mdm6600_probe(struct platform_device *pdev)
 	if (error < 0)
 		phy_mdm6600_device_power_off(ddata);
 
+disable_pm:
+	pm_runtime_disable(ddata->dev);
+
 	return error;
 }
 
-- 
2.17.1


-- 
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy

^ permalink raw reply related

* [PATCH] phy: mapphone-mdm6600: Fix PM disable depth imbalance in phy_mdm6600_probe
From: Miaoqian Lin @ 2022-01-05 12:39 UTC (permalink / raw)
  Cc: linmq006, Kishon Vijay Abraham I, Vinod Koul, Tony Lindgren,
	linux-phy, linux-kernel

The pm_runtime_enable will increase power disable depth.
If the probe fails, we should use pm_runtime_disable() to balance
pm_runtime_enable().

Fixes: f7f50b2 ("phy: mapphone-mdm6600: Add runtime PM support for n_gsm on USB suspend")
Signed-off-by: Miaoqian Lin <linmq006@gmail.com>
---
 drivers/phy/motorola/phy-mapphone-mdm6600.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/phy/motorola/phy-mapphone-mdm6600.c b/drivers/phy/motorola/phy-mapphone-mdm6600.c
index 5172971f4c36..14666750946c 100644
--- a/drivers/phy/motorola/phy-mapphone-mdm6600.c
+++ b/drivers/phy/motorola/phy-mapphone-mdm6600.c
@@ -630,6 +630,9 @@ static int phy_mdm6600_probe(struct platform_device *pdev)
 	if (error < 0)
 		phy_mdm6600_device_power_off(ddata);
 
+disable_pm:
+	pm_runtime_disable(ddata->dev);
+
 	return error;
 }
 
-- 
2.17.1


^ permalink raw reply related

* [PATCH V3 1/2] dt-bindings: pinctrl: Add binding for BCM4908 pinctrl
From: Rafał Miłecki @ 2022-01-05 12:40 UTC (permalink / raw)
  To: Rob Herring, Linus Walleij
  Cc: Álvaro Fernández Rojas, Jonas Gorski, Randy Dunlap,
	Florian Fainelli, linux-gpio, devicetree,
	bcm-kernel-feedback-list, Andy Shevchenko,
	Rafał Miłecki, Rob Herring

From: Rafał Miłecki <rafal@milecki.pl>

It's hardware block that is part of every SoC from BCM4908 family.

Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
Reviewed-by: Rob Herring <robh@kernel.org>
---
This patch targets linux-pinctrl.git for-next. It requires commit
896568e5b9c8 ("dt-bindings: pinctrl: convert controller description to the json-schema")
---
 .../pinctrl/brcm,bcm4908-pinctrl.yaml         | 72 +++++++++++++++++++
 MAINTAINERS                                   |  7 ++
 2 files changed, 79 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pinctrl/brcm,bcm4908-pinctrl.yaml

diff --git a/Documentation/devicetree/bindings/pinctrl/brcm,bcm4908-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/brcm,bcm4908-pinctrl.yaml
new file mode 100644
index 000000000000..175a992f15e1
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/brcm,bcm4908-pinctrl.yaml
@@ -0,0 +1,72 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pinctrl/brcm,bcm4908-pinctrl.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Broadcom BCM4908 pin controller
+
+maintainers:
+  - Rafał Miłecki <rafal@milecki.pl>
+
+description:
+  Binding for pin controller present on BCM4908 family SoCs.
+
+properties:
+  compatible:
+    const: brcm,bcm4908-pinctrl
+
+  reg:
+    maxItems: 1
+
+patternProperties:
+  '-pins$':
+    type: object
+    $ref: pinmux-node.yaml#
+
+    properties:
+      function:
+        enum: [ led_0, led_1, led_2, led_3, led_4, led_5, led_6, led_7, led_8,
+                led_9, led_10, led_11, led_12, led_13, led_14, led_15, led_16,
+                led_17, led_18, led_19, led_20, led_21, led_22, led_23, led_24,
+                led_25, led_26, led_27, led_28, led_29, led_30, led_31,
+                hs_uart, i2c, i2s, nand_ctrl, nand_data, emmc_ctrl, usb0_pwr,
+                usb1_pwr ]
+
+      groups:
+        minItems: 1
+        maxItems: 2
+        items:
+          enum: [ led_0_grp_a, led_1_grp_a, led_2_grp_a, led_3_grp_a,
+                  led_4_grp_a, led_5_grp_a, led_6_grp_a, led_7_grp_a,
+                  led_8_grp_a, led_9_grp_a, led_10_grp_a, led_10_grp_b,
+                  led_11_grp_a, led_11_grp_b, led_12_grp_a, led_12_grp_b,
+                  led_13_grp_a, led_13_grp_b, led_14_grp_a, led_15_grp_a,
+                  led_16_grp_a, led_17_grp_a, led_18_grp_a, led_19_grp_a,
+                  led_20_grp_a, led_21_grp_a, led_22_grp_a, led_23_grp_a,
+                  led_24_grp_a, led_25_grp_a, led_26_grp_a, led_27_grp_a,
+                  led_28_grp_a, led_29_grp_a, led_30_grp_a, led_31_grp_a,
+                  led_31_grp_b, hs_uart_grp, i2c_grp_a, i2c_grp_b, i2s_grp,
+                  nand_ctrl_grp, nand_data_grp, emmc_ctrl_grp, usb0_pwr_grp,
+                  usb1_pwr_grp ]
+
+allOf:
+  - $ref: pinctrl.yaml#
+
+required:
+  - compatible
+  - reg
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    pinctrl@ff800560 {
+        compatible = "brcm,bcm4908-pinctrl";
+        reg = <0xff800560 0x10>;
+
+        led_0-a-pins {
+            function = "led_0";
+            groups = "led_0_grp_a";
+        };
+    };
diff --git a/MAINTAINERS b/MAINTAINERS
index 9c8129679c4f..579fa0f0a785 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3668,6 +3668,13 @@ F:	Documentation/devicetree/bindings/net/brcm,bcm4908-enet.yaml
 F:	drivers/net/ethernet/broadcom/bcm4908_enet.*
 F:	drivers/net/ethernet/broadcom/unimac.h
 
+BROADCOM BCM4908 PINMUX DRIVER
+M:	Rafał Miłecki <rafal@milecki.pl>
+M:	bcm-kernel-feedback-list@broadcom.com
+L:	linux-gpio@vger.kernel.org
+S:	Maintained
+F:	Documentation/devicetree/bindings/pinctrl/brcm,bcm4908-pinctrl.yaml
+
 BROADCOM BCM5301X ARM ARCHITECTURE
 M:	Hauke Mehrtens <hauke@hauke-m.de>
 M:	Rafał Miłecki <zajec5@gmail.com>
-- 
2.31.1


^ permalink raw reply related

* [PATCH V3 2/2] pinctrl: bcm: add driver for BCM4908 pinmux
From: Rafał Miłecki @ 2022-01-05 12:40 UTC (permalink / raw)
  To: Rob Herring, Linus Walleij
  Cc: Álvaro Fernández Rojas, Jonas Gorski, Randy Dunlap,
	Florian Fainelli, linux-gpio, devicetree,
	bcm-kernel-feedback-list, Andy Shevchenko,
	Rafał Miłecki
In-Reply-To: <20220105124003.11319-1-zajec5@gmail.com>

From: Rafał Miłecki <rafal@milecki.pl>

BCM4908 has its own pins layout so it needs a custom binding and a Linux
driver.

Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
---
This patch targets linux-pinctrl.git for-next. It requires commit
bd0aae66c482 ("pinctrl: add one more "const" for generic function groups")

V2: Formatting fixes
    Kconfig fix
    Cleanup of #include-s
    Use devm_kasprintf_strarray()
V3: Bring back OF dependency - required by pinconf_generic_dt_node_to_map()
---
 MAINTAINERS                           |   1 +
 drivers/pinctrl/bcm/Kconfig           |  14 +
 drivers/pinctrl/bcm/Makefile          |   1 +
 drivers/pinctrl/bcm/pinctrl-bcm4908.c | 563 ++++++++++++++++++++++++++
 4 files changed, 579 insertions(+)
 create mode 100644 drivers/pinctrl/bcm/pinctrl-bcm4908.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 579fa0f0a785..67558097bb66 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3674,6 +3674,7 @@ M:	bcm-kernel-feedback-list@broadcom.com
 L:	linux-gpio@vger.kernel.org
 S:	Maintained
 F:	Documentation/devicetree/bindings/pinctrl/brcm,bcm4908-pinctrl.yaml
+F:	drivers/pinctrl/bcm/pinctrl-bcm4908.c
 
 BROADCOM BCM5301X ARM ARCHITECTURE
 M:	Hauke Mehrtens <hauke@hauke-m.de>
diff --git a/drivers/pinctrl/bcm/Kconfig b/drivers/pinctrl/bcm/Kconfig
index 5123f4c33854..042ec2494698 100644
--- a/drivers/pinctrl/bcm/Kconfig
+++ b/drivers/pinctrl/bcm/Kconfig
@@ -29,6 +29,20 @@ config PINCTRL_BCM2835
 	help
 	   Say Y here to enable the Broadcom BCM2835 GPIO driver.
 
+config PINCTRL_BCM4908
+	tristate "Broadcom BCM4908 pinmux driver"
+	depends on OF && (ARCH_BCM4908 || COMPILE_TEST)
+	select PINMUX
+	select PINCONF
+	select GENERIC_PINCONF
+	select GENERIC_PINCTRL_GROUPS
+	select GENERIC_PINMUX_FUNCTIONS
+	default ARCH_BCM4908
+	help
+	  Driver for BCM4908 family SoCs with integrated pin controller.
+
+	  If compiled as module it will be called pinctrl-bcm4908.
+
 config PINCTRL_BCM63XX
 	bool
 	select PINMUX
diff --git a/drivers/pinctrl/bcm/Makefile b/drivers/pinctrl/bcm/Makefile
index 00c7b7775e63..82b868ec1471 100644
--- a/drivers/pinctrl/bcm/Makefile
+++ b/drivers/pinctrl/bcm/Makefile
@@ -3,6 +3,7 @@
 
 obj-$(CONFIG_PINCTRL_BCM281XX)		+= pinctrl-bcm281xx.o
 obj-$(CONFIG_PINCTRL_BCM2835)		+= pinctrl-bcm2835.o
+obj-$(CONFIG_PINCTRL_BCM4908)		+= pinctrl-bcm4908.o
 obj-$(CONFIG_PINCTRL_BCM63XX)		+= pinctrl-bcm63xx.o
 obj-$(CONFIG_PINCTRL_BCM6318)		+= pinctrl-bcm6318.o
 obj-$(CONFIG_PINCTRL_BCM6328)		+= pinctrl-bcm6328.o
diff --git a/drivers/pinctrl/bcm/pinctrl-bcm4908.c b/drivers/pinctrl/bcm/pinctrl-bcm4908.c
new file mode 100644
index 000000000000..cdfa165fc033
--- /dev/null
+++ b/drivers/pinctrl/bcm/pinctrl-bcm4908.c
@@ -0,0 +1,563 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (C) 2021 Rafał Miłecki <rafal@milecki.pl> */
+
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/string_helpers.h>
+
+#include "../core.h"
+#include "../pinmux.h"
+
+#define BCM4908_NUM_PINS			86
+
+#define BCM4908_TEST_PORT_BLOCK_EN_LSB			0x00
+#define BCM4908_TEST_PORT_BLOCK_DATA_MSB		0x04
+#define BCM4908_TEST_PORT_BLOCK_DATA_LSB		0x08
+#define  BCM4908_TEST_PORT_LSB_PINMUX_DATA_SHIFT	12
+#define BCM4908_TEST_PORT_COMMAND			0x0c
+#define  BCM4908_TEST_PORT_CMD_LOAD_MUX_REG		0x00000021
+
+struct bcm4908_pinctrl {
+	struct device *dev;
+	void __iomem *base;
+	struct mutex mutex;
+	struct pinctrl_dev *pctldev;
+	struct pinctrl_desc pctldesc;
+};
+
+/*
+ * Groups
+ */
+
+struct bcm4908_pinctrl_pin_setup {
+	unsigned int number;
+	unsigned int function;
+};
+
+static const struct bcm4908_pinctrl_pin_setup led_0_pins_a[] = {
+	{ 0, 3 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup led_1_pins_a[] = {
+	{ 1, 3 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup led_2_pins_a[] = {
+	{ 2, 3 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup led_3_pins_a[] = {
+	{ 3, 3 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup led_4_pins_a[] = {
+	{ 4, 3 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup led_5_pins_a[] = {
+	{ 5, 3 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup led_6_pins_a[] = {
+	{ 6, 3 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup led_7_pins_a[] = {
+	{ 7, 3 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup led_8_pins_a[] = {
+	{ 8, 3 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup led_9_pins_a[] = {
+	{ 9, 3 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup led_10_pins_a[] = {
+	{ 10, 3 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup led_11_pins_a[] = {
+	{ 11, 3 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup led_12_pins_a[] = {
+	{ 12, 3 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup led_13_pins_a[] = {
+	{ 13, 3 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup led_14_pins_a[] = {
+	{ 14, 3 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup led_15_pins_a[] = {
+	{ 15, 3 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup led_16_pins_a[] = {
+	{ 16, 3 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup led_17_pins_a[] = {
+	{ 17, 3 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup led_18_pins_a[] = {
+	{ 18, 3 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup led_19_pins_a[] = {
+	{ 19, 3 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup led_20_pins_a[] = {
+	{ 20, 3 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup led_21_pins_a[] = {
+	{ 21, 3 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup led_22_pins_a[] = {
+	{ 22, 3 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup led_23_pins_a[] = {
+	{ 23, 3 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup led_24_pins_a[] = {
+	{ 24, 3 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup led_25_pins_a[] = {
+	{ 25, 3 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup led_26_pins_a[] = {
+	{ 26, 3 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup led_27_pins_a[] = {
+	{ 27, 3 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup led_28_pins_a[] = {
+	{ 28, 3 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup led_29_pins_a[] = {
+	{ 29, 3 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup led_30_pins_a[] = {
+	{ 30, 3 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup led_31_pins_a[] = {
+	{ 31, 3 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup led_10_pins_b[] = {
+	{ 8, 2 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup led_11_pins_b[] = {
+	{ 9, 2 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup led_12_pins_b[] = {
+	{ 0, 2 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup led_13_pins_b[] = {
+	{ 1, 2 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup led_31_pins_b[] = {
+	{ 30, 2 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup hs_uart_pins[] = {
+	{ 10, 0 },	/* CTS */
+	{ 11, 0 },	/* RTS */
+	{ 12, 0 },	/* RXD */
+	{ 13, 0 },	/* TXD */
+};
+
+static const struct bcm4908_pinctrl_pin_setup i2c_pins_a[] = {
+	{ 18, 0 },	/* SDA */
+	{ 19, 0 },	/* SCL */
+};
+
+static const struct bcm4908_pinctrl_pin_setup i2c_pins_b[] = {
+	{ 22, 0 },	/* SDA */
+	{ 23, 0 },	/* SCL */
+};
+
+static const struct bcm4908_pinctrl_pin_setup i2s_pins[] = {
+	{ 27, 0 },	/* MCLK */
+	{ 28, 0 },	/* LRCK */
+	{ 29, 0 },	/* SDATA */
+	{ 30, 0 },	/* SCLK */
+};
+
+static const struct bcm4908_pinctrl_pin_setup nand_ctrl_pins[] = {
+	{ 32, 0 },
+	{ 33, 0 },
+	{ 34, 0 },
+	{ 43, 0 },
+	{ 44, 0 },
+	{ 45, 0 },
+	{ 56, 1 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup nand_data_pins[] = {
+	{ 35, 0 },
+	{ 36, 0 },
+	{ 37, 0 },
+	{ 38, 0 },
+	{ 39, 0 },
+	{ 40, 0 },
+	{ 41, 0 },
+	{ 42, 0 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup emmc_ctrl_pins[] = {
+	{ 46, 0 },
+	{ 47, 0 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup usb0_pwr_pins[] = {
+	{ 63, 0 },
+	{ 64, 0 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup usb1_pwr_pins[] = {
+	{ 66, 0 },
+	{ 67, 0 },
+};
+
+struct bcm4908_pinctrl_grp {
+	const char *name;
+	const struct bcm4908_pinctrl_pin_setup *pins;
+	const unsigned int num_pins;
+};
+
+static const struct bcm4908_pinctrl_grp bcm4908_pinctrl_grps[] = {
+	{ "led_0_grp_a", led_0_pins_a, ARRAY_SIZE(led_0_pins_a) },
+	{ "led_1_grp_a", led_1_pins_a, ARRAY_SIZE(led_1_pins_a) },
+	{ "led_2_grp_a", led_2_pins_a, ARRAY_SIZE(led_2_pins_a) },
+	{ "led_3_grp_a", led_3_pins_a, ARRAY_SIZE(led_3_pins_a) },
+	{ "led_4_grp_a", led_4_pins_a, ARRAY_SIZE(led_4_pins_a) },
+	{ "led_5_grp_a", led_5_pins_a, ARRAY_SIZE(led_5_pins_a) },
+	{ "led_6_grp_a", led_6_pins_a, ARRAY_SIZE(led_6_pins_a) },
+	{ "led_7_grp_a", led_7_pins_a, ARRAY_SIZE(led_7_pins_a) },
+	{ "led_8_grp_a", led_8_pins_a, ARRAY_SIZE(led_8_pins_a) },
+	{ "led_9_grp_a", led_9_pins_a, ARRAY_SIZE(led_9_pins_a) },
+	{ "led_10_grp_a", led_10_pins_a, ARRAY_SIZE(led_10_pins_a) },
+	{ "led_11_grp_a", led_11_pins_a, ARRAY_SIZE(led_11_pins_a) },
+	{ "led_12_grp_a", led_12_pins_a, ARRAY_SIZE(led_12_pins_a) },
+	{ "led_13_grp_a", led_13_pins_a, ARRAY_SIZE(led_13_pins_a) },
+	{ "led_14_grp_a", led_14_pins_a, ARRAY_SIZE(led_14_pins_a) },
+	{ "led_15_grp_a", led_15_pins_a, ARRAY_SIZE(led_15_pins_a) },
+	{ "led_16_grp_a", led_16_pins_a, ARRAY_SIZE(led_16_pins_a) },
+	{ "led_17_grp_a", led_17_pins_a, ARRAY_SIZE(led_17_pins_a) },
+	{ "led_18_grp_a", led_18_pins_a, ARRAY_SIZE(led_18_pins_a) },
+	{ "led_19_grp_a", led_19_pins_a, ARRAY_SIZE(led_19_pins_a) },
+	{ "led_20_grp_a", led_20_pins_a, ARRAY_SIZE(led_20_pins_a) },
+	{ "led_21_grp_a", led_21_pins_a, ARRAY_SIZE(led_21_pins_a) },
+	{ "led_22_grp_a", led_22_pins_a, ARRAY_SIZE(led_22_pins_a) },
+	{ "led_23_grp_a", led_23_pins_a, ARRAY_SIZE(led_23_pins_a) },
+	{ "led_24_grp_a", led_24_pins_a, ARRAY_SIZE(led_24_pins_a) },
+	{ "led_25_grp_a", led_25_pins_a, ARRAY_SIZE(led_25_pins_a) },
+	{ "led_26_grp_a", led_26_pins_a, ARRAY_SIZE(led_26_pins_a) },
+	{ "led_27_grp_a", led_27_pins_a, ARRAY_SIZE(led_27_pins_a) },
+	{ "led_28_grp_a", led_28_pins_a, ARRAY_SIZE(led_28_pins_a) },
+	{ "led_29_grp_a", led_29_pins_a, ARRAY_SIZE(led_29_pins_a) },
+	{ "led_30_grp_a", led_30_pins_a, ARRAY_SIZE(led_30_pins_a) },
+	{ "led_31_grp_a", led_31_pins_a, ARRAY_SIZE(led_31_pins_a) },
+	{ "led_10_grp_b", led_10_pins_b, ARRAY_SIZE(led_10_pins_b) },
+	{ "led_11_grp_b", led_11_pins_b, ARRAY_SIZE(led_11_pins_b) },
+	{ "led_12_grp_b", led_12_pins_b, ARRAY_SIZE(led_12_pins_b) },
+	{ "led_13_grp_b", led_13_pins_b, ARRAY_SIZE(led_13_pins_b) },
+	{ "led_31_grp_b", led_31_pins_b, ARRAY_SIZE(led_31_pins_b) },
+	{ "hs_uart_grp", hs_uart_pins, ARRAY_SIZE(hs_uart_pins) },
+	{ "i2c_grp_a", i2c_pins_a, ARRAY_SIZE(i2c_pins_a) },
+	{ "i2c_grp_b", i2c_pins_b, ARRAY_SIZE(i2c_pins_b) },
+	{ "i2s_grp", i2s_pins, ARRAY_SIZE(i2s_pins) },
+	{ "nand_ctrl_grp", nand_ctrl_pins, ARRAY_SIZE(nand_ctrl_pins) },
+	{ "nand_data_grp", nand_data_pins, ARRAY_SIZE(nand_data_pins) },
+	{ "emmc_ctrl_grp", emmc_ctrl_pins, ARRAY_SIZE(emmc_ctrl_pins) },
+	{ "usb0_pwr_grp", usb0_pwr_pins, ARRAY_SIZE(usb0_pwr_pins) },
+	{ "usb1_pwr_grp", usb1_pwr_pins, ARRAY_SIZE(usb1_pwr_pins) },
+};
+
+/*
+ * Functions
+ */
+
+struct bcm4908_pinctrl_function {
+	const char *name;
+	const char * const *groups;
+	const unsigned int num_groups;
+};
+
+static const char * const led_0_groups[] = { "led_0_grp_a" };
+static const char * const led_1_groups[] = { "led_1_grp_a" };
+static const char * const led_2_groups[] = { "led_2_grp_a" };
+static const char * const led_3_groups[] = { "led_3_grp_a" };
+static const char * const led_4_groups[] = { "led_4_grp_a" };
+static const char * const led_5_groups[] = { "led_5_grp_a" };
+static const char * const led_6_groups[] = { "led_6_grp_a" };
+static const char * const led_7_groups[] = { "led_7_grp_a" };
+static const char * const led_8_groups[] = { "led_8_grp_a" };
+static const char * const led_9_groups[] = { "led_9_grp_a" };
+static const char * const led_10_groups[] = { "led_10_grp_a", "led_10_grp_b" };
+static const char * const led_11_groups[] = { "led_11_grp_a", "led_11_grp_b" };
+static const char * const led_12_groups[] = { "led_12_grp_a", "led_12_grp_b" };
+static const char * const led_13_groups[] = { "led_13_grp_a", "led_13_grp_b" };
+static const char * const led_14_groups[] = { "led_14_grp_a" };
+static const char * const led_15_groups[] = { "led_15_grp_a" };
+static const char * const led_16_groups[] = { "led_16_grp_a" };
+static const char * const led_17_groups[] = { "led_17_grp_a" };
+static const char * const led_18_groups[] = { "led_18_grp_a" };
+static const char * const led_19_groups[] = { "led_19_grp_a" };
+static const char * const led_20_groups[] = { "led_20_grp_a" };
+static const char * const led_21_groups[] = { "led_21_grp_a" };
+static const char * const led_22_groups[] = { "led_22_grp_a" };
+static const char * const led_23_groups[] = { "led_23_grp_a" };
+static const char * const led_24_groups[] = { "led_24_grp_a" };
+static const char * const led_25_groups[] = { "led_25_grp_a" };
+static const char * const led_26_groups[] = { "led_26_grp_a" };
+static const char * const led_27_groups[] = { "led_27_grp_a" };
+static const char * const led_28_groups[] = { "led_28_grp_a" };
+static const char * const led_29_groups[] = { "led_29_grp_a" };
+static const char * const led_30_groups[] = { "led_30_grp_a" };
+static const char * const led_31_groups[] = { "led_31_grp_a", "led_31_grp_b" };
+static const char * const hs_uart_groups[] = { "hs_uart_grp" };
+static const char * const i2c_groups[] = { "i2c_grp_a", "i2c_grp_b" };
+static const char * const i2s_groups[] = { "i2s_grp" };
+static const char * const nand_ctrl_groups[] = { "nand_ctrl_grp" };
+static const char * const nand_data_groups[] = { "nand_data_grp" };
+static const char * const emmc_ctrl_groups[] = { "emmc_ctrl_grp" };
+static const char * const usb0_pwr_groups[] = { "usb0_pwr_grp" };
+static const char * const usb1_pwr_groups[] = { "usb1_pwr_grp" };
+
+static const struct bcm4908_pinctrl_function bcm4908_pinctrl_functions[] = {
+	{ "led_0", led_0_groups, ARRAY_SIZE(led_0_groups) },
+	{ "led_1", led_1_groups, ARRAY_SIZE(led_1_groups) },
+	{ "led_2", led_2_groups, ARRAY_SIZE(led_2_groups) },
+	{ "led_3", led_3_groups, ARRAY_SIZE(led_3_groups) },
+	{ "led_4", led_4_groups, ARRAY_SIZE(led_4_groups) },
+	{ "led_5", led_5_groups, ARRAY_SIZE(led_5_groups) },
+	{ "led_6", led_6_groups, ARRAY_SIZE(led_6_groups) },
+	{ "led_7", led_7_groups, ARRAY_SIZE(led_7_groups) },
+	{ "led_8", led_8_groups, ARRAY_SIZE(led_8_groups) },
+	{ "led_9", led_9_groups, ARRAY_SIZE(led_9_groups) },
+	{ "led_10", led_10_groups, ARRAY_SIZE(led_10_groups) },
+	{ "led_11", led_11_groups, ARRAY_SIZE(led_11_groups) },
+	{ "led_12", led_12_groups, ARRAY_SIZE(led_12_groups) },
+	{ "led_13", led_13_groups, ARRAY_SIZE(led_13_groups) },
+	{ "led_14", led_14_groups, ARRAY_SIZE(led_14_groups) },
+	{ "led_15", led_15_groups, ARRAY_SIZE(led_15_groups) },
+	{ "led_16", led_16_groups, ARRAY_SIZE(led_16_groups) },
+	{ "led_17", led_17_groups, ARRAY_SIZE(led_17_groups) },
+	{ "led_18", led_18_groups, ARRAY_SIZE(led_18_groups) },
+	{ "led_19", led_19_groups, ARRAY_SIZE(led_19_groups) },
+	{ "led_20", led_20_groups, ARRAY_SIZE(led_20_groups) },
+	{ "led_21", led_21_groups, ARRAY_SIZE(led_21_groups) },
+	{ "led_22", led_22_groups, ARRAY_SIZE(led_22_groups) },
+	{ "led_23", led_23_groups, ARRAY_SIZE(led_23_groups) },
+	{ "led_24", led_24_groups, ARRAY_SIZE(led_24_groups) },
+	{ "led_25", led_25_groups, ARRAY_SIZE(led_25_groups) },
+	{ "led_26", led_26_groups, ARRAY_SIZE(led_26_groups) },
+	{ "led_27", led_27_groups, ARRAY_SIZE(led_27_groups) },
+	{ "led_28", led_28_groups, ARRAY_SIZE(led_28_groups) },
+	{ "led_29", led_29_groups, ARRAY_SIZE(led_29_groups) },
+	{ "led_30", led_30_groups, ARRAY_SIZE(led_30_groups) },
+	{ "led_31", led_31_groups, ARRAY_SIZE(led_31_groups) },
+	{ "hs_uart", hs_uart_groups, ARRAY_SIZE(hs_uart_groups) },
+	{ "i2c", i2c_groups, ARRAY_SIZE(i2c_groups) },
+	{ "i2s", i2s_groups, ARRAY_SIZE(i2s_groups) },
+	{ "nand_ctrl", nand_ctrl_groups, ARRAY_SIZE(nand_ctrl_groups) },
+	{ "nand_data", nand_data_groups, ARRAY_SIZE(nand_data_groups) },
+	{ "emmc_ctrl", emmc_ctrl_groups, ARRAY_SIZE(emmc_ctrl_groups) },
+	{ "usb0_pwr", usb0_pwr_groups, ARRAY_SIZE(usb0_pwr_groups) },
+	{ "usb1_pwr", usb1_pwr_groups, ARRAY_SIZE(usb1_pwr_groups) },
+};
+
+/*
+ * Groups code
+ */
+
+static const struct pinctrl_ops bcm4908_pinctrl_ops = {
+	.get_groups_count = pinctrl_generic_get_group_count,
+	.get_group_name = pinctrl_generic_get_group_name,
+	.get_group_pins = pinctrl_generic_get_group_pins,
+	.dt_node_to_map = pinconf_generic_dt_node_to_map_group,
+	.dt_free_map = pinconf_generic_dt_free_map,
+};
+
+/*
+ * Functions code
+ */
+
+static int bcm4908_pinctrl_set_mux(struct pinctrl_dev *pctrl_dev,
+			      unsigned int func_selector,
+			      unsigned int group_selector)
+{
+	struct bcm4908_pinctrl *bcm4908_pinctrl = pinctrl_dev_get_drvdata(pctrl_dev);
+	const struct bcm4908_pinctrl_grp *group;
+	struct group_desc *group_desc;
+	int i;
+
+	group_desc = pinctrl_generic_get_group(pctrl_dev, group_selector);
+	if (!group_desc)
+		return -EINVAL;
+	group = group_desc->data;
+
+	mutex_lock(&bcm4908_pinctrl->mutex);
+	for (i = 0; i < group->num_pins; i++) {
+		u32 lsb = 0;
+
+		lsb |= group->pins[i].number;
+		lsb |= group->pins[i].function << BCM4908_TEST_PORT_LSB_PINMUX_DATA_SHIFT;
+
+		writel(0x0, bcm4908_pinctrl->base + BCM4908_TEST_PORT_BLOCK_DATA_MSB);
+		writel(lsb, bcm4908_pinctrl->base + BCM4908_TEST_PORT_BLOCK_DATA_LSB);
+		writel(BCM4908_TEST_PORT_CMD_LOAD_MUX_REG,
+		       bcm4908_pinctrl->base + BCM4908_TEST_PORT_COMMAND);
+	}
+	mutex_unlock(&bcm4908_pinctrl->mutex);
+
+	return 0;
+}
+
+static const struct pinmux_ops bcm4908_pinctrl_pmxops = {
+	.get_functions_count = pinmux_generic_get_function_count,
+	.get_function_name = pinmux_generic_get_function_name,
+	.get_function_groups = pinmux_generic_get_function_groups,
+	.set_mux = bcm4908_pinctrl_set_mux,
+};
+
+/*
+ * Controller code
+ */
+
+static struct pinctrl_desc bcm4908_pinctrl_desc = {
+	.name = "bcm4908-pinctrl",
+	.pctlops = &bcm4908_pinctrl_ops,
+	.pmxops = &bcm4908_pinctrl_pmxops,
+};
+
+static const struct of_device_id bcm4908_pinctrl_of_match_table[] = {
+	{ .compatible = "brcm,bcm4908-pinctrl", },
+	{ }
+};
+
+static int bcm4908_pinctrl_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct bcm4908_pinctrl *bcm4908_pinctrl;
+	struct pinctrl_desc *pctldesc;
+	struct pinctrl_pin_desc *pins;
+	char **pin_names;
+	int i;
+
+	bcm4908_pinctrl = devm_kzalloc(dev, sizeof(*bcm4908_pinctrl), GFP_KERNEL);
+	if (!bcm4908_pinctrl)
+		return -ENOMEM;
+	pctldesc = &bcm4908_pinctrl->pctldesc;
+	platform_set_drvdata(pdev, bcm4908_pinctrl);
+
+	/* Set basic properties */
+
+	bcm4908_pinctrl->dev = dev;
+
+	bcm4908_pinctrl->base = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(bcm4908_pinctrl->base))
+		return PTR_ERR(bcm4908_pinctrl->base);
+
+	mutex_init(&bcm4908_pinctrl->mutex);
+
+	memcpy(pctldesc, &bcm4908_pinctrl_desc, sizeof(*pctldesc));
+
+	/* Set pinctrl properties */
+
+	pin_names = devm_kasprintf_strarray(dev, "pin", BCM4908_NUM_PINS);
+	if (IS_ERR(pin_names))
+		return PTR_ERR(pin_names);
+
+	pins = devm_kcalloc(dev, BCM4908_NUM_PINS, sizeof(*pins), GFP_KERNEL);
+	if (!pins)
+		return -ENOMEM;
+	for (i = 0; i < BCM4908_NUM_PINS; i++) {
+		pins[i].number = i;
+		pins[i].name = pin_names[i];
+	}
+	pctldesc->pins = pins;
+	pctldesc->npins = BCM4908_NUM_PINS;
+
+	/* Register */
+
+	bcm4908_pinctrl->pctldev = devm_pinctrl_register(dev, pctldesc, bcm4908_pinctrl);
+	if (IS_ERR(bcm4908_pinctrl->pctldev))
+		return dev_err_probe(dev, PTR_ERR(bcm4908_pinctrl->pctldev),
+				     "Failed to register pinctrl\n");
+
+	/* Groups */
+
+	for (i = 0; i < ARRAY_SIZE(bcm4908_pinctrl_grps); i++) {
+		const struct bcm4908_pinctrl_grp *group = &bcm4908_pinctrl_grps[i];
+		int *pins;
+		int j;
+
+		pins = devm_kcalloc(dev, group->num_pins, sizeof(*pins), GFP_KERNEL);
+		if (!pins)
+			return -ENOMEM;
+		for (j = 0; j < group->num_pins; j++)
+			pins[j] = group->pins[j].number;
+
+		pinctrl_generic_add_group(bcm4908_pinctrl->pctldev, group->name,
+					  pins, group->num_pins, (void *)group);
+	}
+
+	/* Functions */
+
+	for (i = 0; i < ARRAY_SIZE(bcm4908_pinctrl_functions); i++) {
+		const struct bcm4908_pinctrl_function *function = &bcm4908_pinctrl_functions[i];
+
+		pinmux_generic_add_function(bcm4908_pinctrl->pctldev,
+					    function->name,
+					    function->groups,
+					    function->num_groups, NULL);
+	}
+
+	return 0;
+}
+
+static struct platform_driver bcm4908_pinctrl_driver = {
+	.probe = bcm4908_pinctrl_probe,
+	.driver = {
+		.name = "bcm4908-pinctrl",
+		.of_match_table = bcm4908_pinctrl_of_match_table,
+	},
+};
+
+module_platform_driver(bcm4908_pinctrl_driver);
+
+MODULE_AUTHOR("Rafał Miłecki");
+MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(of, bcm4908_pinctrl_of_match_table);
-- 
2.31.1


^ permalink raw reply related

* Re: [PATCH] bpf/selftests: Fix namespace mount setup in tc_redirect
From: patchwork-bot+netdevbpf @ 2022-01-05 12:40 UTC (permalink / raw)
  To: Jiri Olsa
  Cc: ast, daniel, andrii, joamaki, haliu, netdev, bpf, kafai,
	songliubraving, yhs, john.fastabend, kpsingh
In-Reply-To: <20220104121030.138216-1-jolsa@kernel.org>

Hello:

This patch was applied to bpf/bpf-next.git (master)
by Daniel Borkmann <daniel@iogearbox.net>:

On Tue,  4 Jan 2022 13:10:30 +0100 you wrote:
> The tc_redirect umounts /sys in the new namespace, which can be
> mounted as shared and cause global umount. The lazy umount also
> takes down mounted trees under /sys like debugfs, which won't be
> available after sysfs mounts again and could cause fails in other
> tests.
> 
>   # cat /proc/self/mountinfo | grep debugfs
>   34 23 0:7 / /sys/kernel/debug rw,nosuid,nodev,noexec,relatime shared:14 - debugfs debugfs rw
>   # cat /proc/self/mountinfo | grep sysfs
>   23 86 0:22 / /sys rw,nosuid,nodev,noexec,relatime shared:2 - sysfs sysfs rw
>   # mount | grep debugfs
>   debugfs on /sys/kernel/debug type debugfs (rw,nosuid,nodev,noexec,relatime)
> 
> [...]

Here is the summary with links:
  - bpf/selftests: Fix namespace mount setup in tc_redirect
    https://git.kernel.org/bpf/bpf-next/c/5e22dd186267

You are awesome, thank you!
-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html



^ permalink raw reply

* Re: [PATCH bpf-next 0/3] bpftool: Probes for bounded loops and instruction set extensions
From: patchwork-bot+netdevbpf @ 2022-01-05 12:40 UTC (permalink / raw)
  To: Paul Chaignon; +Cc: ast, daniel, andrii, bpf, quentin
In-Reply-To: <cover.1641314075.git.paul@isovalent.com>

Hello:

This series was applied to bpf/bpf-next.git (master)
by Daniel Borkmann <daniel@iogearbox.net>:

On Tue, 4 Jan 2022 18:57:54 +0100 you wrote:
> This patchset adds feature probes for bounded loops and instruction set
> extensions. The first patch refactors the existing miscellaneous probe
> to avoid code duplication in subsequent patches.
> 
> The four miscellaneous probes were tested on kernels 4.9, 4.19, and 5.4.
> 
> The feature probe for bounded loops was previously submitted as part of
> patchset https://lore.kernel.org/bpf/20211217211135.GA42088@Mem/T/.
> 
> [...]

Here is the summary with links:
  - [bpf-next,1/3] bpftool: Refactor misc. feature probe
    https://git.kernel.org/bpf/bpf-next/c/b22bf1b9979a
  - [bpf-next,2/3] bpftool: Probe for bounded loop support
    https://git.kernel.org/bpf/bpf-next/c/c04fb2b0bd92
  - [bpf-next,3/3] bpftool: Probe for instruction set extensions
    https://git.kernel.org/bpf/bpf-next/c/0fd800b2456c

You are awesome, thank you!
-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html



^ permalink raw reply

* Re: [PATCH 4/4] coresight: trbe: Workaround TRBE trace data corruption
From: Anshuman Khandual @ 2022-01-05 12:39 UTC (permalink / raw)
  To: Suzuki K Poulose, linux-arm-kernel
  Cc: Catalin Marinas, Will Deacon, Mathieu Poirier, coresight,
	linux-doc, linux-kernel
In-Reply-To: <adbe2a0a-4ed8-4b86-453d-94fec96757e2@arm.com>



On 1/5/22 5:29 PM, Suzuki K Poulose wrote:
> On 05/01/2022 05:05, Anshuman Khandual wrote:
>> TRBE implementations affected by Arm erratum #1902691 might corrupt trace
>> data or deadlock, when it's being written into the memory. Workaround this
>> problem in the driver, by preventing TRBE initialization on affected cpus.
>> This adds a new cpu errata in arm64 errata framework and also updates TRBE
>> driver as required.
>>
>> Cc: Catalin Marinas <catalin.marinas@arm.com>
>> Cc: Will Deacon <will@kernel.org>
>> Cc: Mathieu Poirier <mathieu.poirier@linaro.org>
>> Cc: Suzuki Poulose <suzuki.poulose@arm.com>
>> Cc: coresight@lists.linaro.org
>> Cc: linux-doc@vger.kernel.org
>> Cc: linux-arm-kernel@lists.infradead.org
>> Cc: linux-kernel@vger.kernel.org
>> Signed-off-by: Anshuman Khandual <anshuman.khandual@arm.com>
>> ---
>>   Documentation/arm64/silicon-errata.rst       |  2 ++
>>   arch/arm64/Kconfig                           | 16 ++++++++++++++++
>>   arch/arm64/kernel/cpu_errata.c               |  9 +++++++++
>>   arch/arm64/tools/cpucaps                     |  1 +
>>   drivers/hwtracing/coresight/coresight-trbe.c | 12 ++++++++++++
>>   5 files changed, 40 insertions(+)
>>
>> diff --git a/Documentation/arm64/silicon-errata.rst b/Documentation/arm64/silicon-errata.rst
>> index e0ef3e9a4b8b..50018f60c4d4 100644
>> --- a/Documentation/arm64/silicon-errata.rst
>> +++ b/Documentation/arm64/silicon-errata.rst
>> @@ -56,6 +56,8 @@ stable kernels.
>>   +----------------+-----------------+-----------------+-----------------------------+
>>   | ARM            | Cortex-A510     | #2038923        | ARM64_ERRATUM_2038923       |
>>   +----------------+-----------------+-----------------+-----------------------------+
>> +| ARM            | Cortex-A510     | #1902691        | ARM64_ERRATUM_1902691       |
>> ++----------------+-----------------+-----------------+-----------------------------+
>>   | ARM            | Cortex-A53      | #826319         | ARM64_ERRATUM_826319        |
>>   +----------------+-----------------+-----------------+-----------------------------+
>>   | ARM            | Cortex-A53      | #827319         | ARM64_ERRATUM_827319        |
>> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
>> index 026e34fb6fad..1ea5c3b4aac0 100644
>> --- a/arch/arm64/Kconfig
>> +++ b/arch/arm64/Kconfig
>> @@ -819,6 +819,22 @@ config ARM64_ERRATUM_2038923
>>           If unsure, say Y.
>>   +config ARM64_ERRATUM_1902691
>> +    bool "Cortex-A510: 1902691: workaround TRBE trace corruption"
>> +    depends on CORESIGHT_TRBE
>> +    default y
>> +    help
>> +      This option adds the workaround for ARM Cortex-A510 erratum 1902691.
>> +
>> +      Affected Cortex-A510 core might cause trace data corruption, when being written
>> +      into the memory. Effectively TRBE is broken and hence cannot be used to capture
>> +      trace data.
>> +
>> +      Work around this problem in the driver by just preventing TRBE initialization on
>> +      affected cpus.
>> +
>> +      If unsure, say Y.
>> +
> 
> It might be better to add :
> 
> "The firmware must have disabled the access to TRBE for the kernel on such implementations. This will cover the kernel for any firmware that
> doesn't do this already"

Right, will add it.

> 
> 
>>   config CAVIUM_ERRATUM_22375
>>       bool "Cavium erratum 22375, 24313"
>>       default y
>> diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c
>> index 60b0c1f1d912..a3336dfb5a8a 100644
>> --- a/arch/arm64/kernel/cpu_errata.c
>> +++ b/arch/arm64/kernel/cpu_errata.c
>> @@ -615,6 +615,15 @@ const struct arm64_cpu_capabilities arm64_errata[] = {   
>>           /* Cortex-A510 r0p0 - r0p2 */
>>           ERRATA_MIDR_REV_RANGE(MIDR_CORTEX_A510, 0, 0, 2)
>>       },
>> +#endif
>> +#ifdef CONFIG_ARM64_ERRATUM_1902691
>> +    {
>> +        .desc = "ARM erratum 1902691",
>> +        .capability = ARM64_WORKAROUND_1902691,
>> +
>> +        /* Cortex-A510 r0p0 - r0p1 */
>> +        ERRATA_MIDR_REV_RANGE(MIDR_CORTEX_A510, 0, 0, 1)
>> +    },
>>   #endif
>>       {
>>       }
>> diff --git a/arch/arm64/tools/cpucaps b/arch/arm64/tools/cpucaps
>> index 45a06d36d080..e7719e8f18de 100644
>> --- a/arch/arm64/tools/cpucaps
>> +++ b/arch/arm64/tools/cpucaps
>> @@ -57,6 +57,7 @@ WORKAROUND_1508412
>>   WORKAROUND_1542419
>>   WORKAROUND_2064142
>>   WORKAROUND_2038923
>> +WORKAROUND_1902691
>>   WORKAROUND_TRBE_OVERWRITE_FILL_MODE
>>   WORKAROUND_TSB_FLUSH_FAILURE
>>   WORKAROUND_TRBE_WRITE_OUT_OF_RANGE
>> diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c
>> index 0689c6dab96d..b9b4e34fac15 100644
>> --- a/drivers/hwtracing/coresight/coresight-trbe.c
>> +++ b/drivers/hwtracing/coresight/coresight-trbe.c
>> @@ -93,12 +93,14 @@ struct trbe_buf {
>>   #define TRBE_WORKAROUND_WRITE_OUT_OF_RANGE    1
>>   #define TRBE_WORKAROUND_SYSREG_WRITE_FAILURE    2
>>   #define TRBE_WORKAROUND_CORRUPTION_WITH_ENABLE    3
>> +#define TRBE_IS_BROKEN    4
>>     static int trbe_errata_cpucaps[] = {
>>       [TRBE_WORKAROUND_OVERWRITE_FILL_MODE] = ARM64_WORKAROUND_TRBE_OVERWRITE_FILL_MODE,
>>       [TRBE_WORKAROUND_WRITE_OUT_OF_RANGE] = ARM64_WORKAROUND_TRBE_WRITE_OUT_OF_RANGE,
>>       [TRBE_WORKAROUND_SYSREG_WRITE_FAILURE] = ARM64_WORKAROUND_2064142,
>>       [TRBE_WORKAROUND_CORRUPTION_WITH_ENABLE] = ARM64_WORKAROUND_2038923,
>> +    [TRBE_IS_BROKEN] = ARM64_WORKAROUND_1902691,
>>       -1,        /* Sentinel, must be the last entry */
>>   };
>>   @@ -181,6 +183,11 @@ static inline bool trbe_may_corrupt_with_enable(struct trbe_cpudata *cpudata)
>>       return trbe_has_erratum(cpudata, TRBE_WORKAROUND_CORRUPTION_WITH_ENABLE);
>>   }
>>   +static inline bool trbe_is_broken(struct trbe_cpudata *cpudata)
>> +{
>> +    return trbe_has_erratum(cpudata, TRBE_IS_BROKEN);
>> +}
>> +
>>   static int trbe_alloc_node(struct perf_event *event)
>>   {
>>       if (event->cpu == -1)
>> @@ -1291,6 +1298,11 @@ static void arm_trbe_probe_cpu(void *info)
>>        */
>>       trbe_check_errata(cpudata);
>>   +    if (trbe_is_broken(cpudata)) {
>> +        pr_err("TRBE might corrupt the trace on cpu %d\n", cpu);
> 
> It may be better to say:
> 
>         "Disabling TRBE on CPU%d due to erratum"

Mention the erratum #1902691 as well or not required ?

> 
> Otherwise looks good to me.
> 
> Suzuki

^ permalink raw reply

* Re: [PATCH 4/4] coresight: trbe: Workaround TRBE trace data corruption
From: Anshuman Khandual @ 2022-01-05 12:39 UTC (permalink / raw)
  To: Suzuki K Poulose, linux-arm-kernel
  Cc: Catalin Marinas, Will Deacon, Mathieu Poirier, coresight,
	linux-doc, linux-kernel
In-Reply-To: <adbe2a0a-4ed8-4b86-453d-94fec96757e2@arm.com>



On 1/5/22 5:29 PM, Suzuki K Poulose wrote:
> On 05/01/2022 05:05, Anshuman Khandual wrote:
>> TRBE implementations affected by Arm erratum #1902691 might corrupt trace
>> data or deadlock, when it's being written into the memory. Workaround this
>> problem in the driver, by preventing TRBE initialization on affected cpus.
>> This adds a new cpu errata in arm64 errata framework and also updates TRBE
>> driver as required.
>>
>> Cc: Catalin Marinas <catalin.marinas@arm.com>
>> Cc: Will Deacon <will@kernel.org>
>> Cc: Mathieu Poirier <mathieu.poirier@linaro.org>
>> Cc: Suzuki Poulose <suzuki.poulose@arm.com>
>> Cc: coresight@lists.linaro.org
>> Cc: linux-doc@vger.kernel.org
>> Cc: linux-arm-kernel@lists.infradead.org
>> Cc: linux-kernel@vger.kernel.org
>> Signed-off-by: Anshuman Khandual <anshuman.khandual@arm.com>
>> ---
>>   Documentation/arm64/silicon-errata.rst       |  2 ++
>>   arch/arm64/Kconfig                           | 16 ++++++++++++++++
>>   arch/arm64/kernel/cpu_errata.c               |  9 +++++++++
>>   arch/arm64/tools/cpucaps                     |  1 +
>>   drivers/hwtracing/coresight/coresight-trbe.c | 12 ++++++++++++
>>   5 files changed, 40 insertions(+)
>>
>> diff --git a/Documentation/arm64/silicon-errata.rst b/Documentation/arm64/silicon-errata.rst
>> index e0ef3e9a4b8b..50018f60c4d4 100644
>> --- a/Documentation/arm64/silicon-errata.rst
>> +++ b/Documentation/arm64/silicon-errata.rst
>> @@ -56,6 +56,8 @@ stable kernels.
>>   +----------------+-----------------+-----------------+-----------------------------+
>>   | ARM            | Cortex-A510     | #2038923        | ARM64_ERRATUM_2038923       |
>>   +----------------+-----------------+-----------------+-----------------------------+
>> +| ARM            | Cortex-A510     | #1902691        | ARM64_ERRATUM_1902691       |
>> ++----------------+-----------------+-----------------+-----------------------------+
>>   | ARM            | Cortex-A53      | #826319         | ARM64_ERRATUM_826319        |
>>   +----------------+-----------------+-----------------+-----------------------------+
>>   | ARM            | Cortex-A53      | #827319         | ARM64_ERRATUM_827319        |
>> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
>> index 026e34fb6fad..1ea5c3b4aac0 100644
>> --- a/arch/arm64/Kconfig
>> +++ b/arch/arm64/Kconfig
>> @@ -819,6 +819,22 @@ config ARM64_ERRATUM_2038923
>>           If unsure, say Y.
>>   +config ARM64_ERRATUM_1902691
>> +    bool "Cortex-A510: 1902691: workaround TRBE trace corruption"
>> +    depends on CORESIGHT_TRBE
>> +    default y
>> +    help
>> +      This option adds the workaround for ARM Cortex-A510 erratum 1902691.
>> +
>> +      Affected Cortex-A510 core might cause trace data corruption, when being written
>> +      into the memory. Effectively TRBE is broken and hence cannot be used to capture
>> +      trace data.
>> +
>> +      Work around this problem in the driver by just preventing TRBE initialization on
>> +      affected cpus.
>> +
>> +      If unsure, say Y.
>> +
> 
> It might be better to add :
> 
> "The firmware must have disabled the access to TRBE for the kernel on such implementations. This will cover the kernel for any firmware that
> doesn't do this already"

Right, will add it.

> 
> 
>>   config CAVIUM_ERRATUM_22375
>>       bool "Cavium erratum 22375, 24313"
>>       default y
>> diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c
>> index 60b0c1f1d912..a3336dfb5a8a 100644
>> --- a/arch/arm64/kernel/cpu_errata.c
>> +++ b/arch/arm64/kernel/cpu_errata.c
>> @@ -615,6 +615,15 @@ const struct arm64_cpu_capabilities arm64_errata[] = {   
>>           /* Cortex-A510 r0p0 - r0p2 */
>>           ERRATA_MIDR_REV_RANGE(MIDR_CORTEX_A510, 0, 0, 2)
>>       },
>> +#endif
>> +#ifdef CONFIG_ARM64_ERRATUM_1902691
>> +    {
>> +        .desc = "ARM erratum 1902691",
>> +        .capability = ARM64_WORKAROUND_1902691,
>> +
>> +        /* Cortex-A510 r0p0 - r0p1 */
>> +        ERRATA_MIDR_REV_RANGE(MIDR_CORTEX_A510, 0, 0, 1)
>> +    },
>>   #endif
>>       {
>>       }
>> diff --git a/arch/arm64/tools/cpucaps b/arch/arm64/tools/cpucaps
>> index 45a06d36d080..e7719e8f18de 100644
>> --- a/arch/arm64/tools/cpucaps
>> +++ b/arch/arm64/tools/cpucaps
>> @@ -57,6 +57,7 @@ WORKAROUND_1508412
>>   WORKAROUND_1542419
>>   WORKAROUND_2064142
>>   WORKAROUND_2038923
>> +WORKAROUND_1902691
>>   WORKAROUND_TRBE_OVERWRITE_FILL_MODE
>>   WORKAROUND_TSB_FLUSH_FAILURE
>>   WORKAROUND_TRBE_WRITE_OUT_OF_RANGE
>> diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c
>> index 0689c6dab96d..b9b4e34fac15 100644
>> --- a/drivers/hwtracing/coresight/coresight-trbe.c
>> +++ b/drivers/hwtracing/coresight/coresight-trbe.c
>> @@ -93,12 +93,14 @@ struct trbe_buf {
>>   #define TRBE_WORKAROUND_WRITE_OUT_OF_RANGE    1
>>   #define TRBE_WORKAROUND_SYSREG_WRITE_FAILURE    2
>>   #define TRBE_WORKAROUND_CORRUPTION_WITH_ENABLE    3
>> +#define TRBE_IS_BROKEN    4
>>     static int trbe_errata_cpucaps[] = {
>>       [TRBE_WORKAROUND_OVERWRITE_FILL_MODE] = ARM64_WORKAROUND_TRBE_OVERWRITE_FILL_MODE,
>>       [TRBE_WORKAROUND_WRITE_OUT_OF_RANGE] = ARM64_WORKAROUND_TRBE_WRITE_OUT_OF_RANGE,
>>       [TRBE_WORKAROUND_SYSREG_WRITE_FAILURE] = ARM64_WORKAROUND_2064142,
>>       [TRBE_WORKAROUND_CORRUPTION_WITH_ENABLE] = ARM64_WORKAROUND_2038923,
>> +    [TRBE_IS_BROKEN] = ARM64_WORKAROUND_1902691,
>>       -1,        /* Sentinel, must be the last entry */
>>   };
>>   @@ -181,6 +183,11 @@ static inline bool trbe_may_corrupt_with_enable(struct trbe_cpudata *cpudata)
>>       return trbe_has_erratum(cpudata, TRBE_WORKAROUND_CORRUPTION_WITH_ENABLE);
>>   }
>>   +static inline bool trbe_is_broken(struct trbe_cpudata *cpudata)
>> +{
>> +    return trbe_has_erratum(cpudata, TRBE_IS_BROKEN);
>> +}
>> +
>>   static int trbe_alloc_node(struct perf_event *event)
>>   {
>>       if (event->cpu == -1)
>> @@ -1291,6 +1298,11 @@ static void arm_trbe_probe_cpu(void *info)
>>        */
>>       trbe_check_errata(cpudata);
>>   +    if (trbe_is_broken(cpudata)) {
>> +        pr_err("TRBE might corrupt the trace on cpu %d\n", cpu);
> 
> It may be better to say:
> 
>         "Disabling TRBE on CPU%d due to erratum"

Mention the erratum #1902691 as well or not required ?

> 
> Otherwise looks good to me.
> 
> Suzuki

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* Re: [PATCH 4/5] RDMA/rxe: Use the standard method to produce udp source port
From: Zhu Yanjun @ 2022-01-05 12:42 UTC (permalink / raw)
  To: Leon Romanovsky
  Cc: yanjun.zhu, liangwenpeng, Jason Gunthorpe, mustafa.ismail,
	Shiraz Saleem, RDMA mailing list
In-Reply-To: <YdVc5BMAaOh2aO2C@unreal>

On Wed, Jan 5, 2022 at 4:55 PM Leon Romanovsky <leon@kernel.org> wrote:
>
> On Wed, Jan 05, 2022 at 04:27:38PM +0800, Zhu Yanjun wrote:
> > On Wed, Jan 5, 2022 at 3:52 PM Leon Romanovsky <leon@kernel.org> wrote:
> > >
> > > On Wed, Jan 05, 2022 at 05:12:36PM -0500, yanjun.zhu@linux.dev wrote:
> > > > From: Zhu Yanjun <yanjun.zhu@linux.dev>
> > > >
> > > > Use the standard method to produce udp source port.
> > > >
> > > > Signed-off-by: Zhu Yanjun <yanjun.zhu@linux.dev>
> > > > ---
> > > >  drivers/infiniband/sw/rxe/rxe_verbs.c | 6 ++++++
> > > >  1 file changed, 6 insertions(+)
> > > >
> > > > diff --git a/drivers/infiniband/sw/rxe/rxe_verbs.c b/drivers/infiniband/sw/rxe/rxe_verbs.c
> > > > index 0aa0d7e52773..42fa81b455de 100644
> > > > --- a/drivers/infiniband/sw/rxe/rxe_verbs.c
> > > > +++ b/drivers/infiniband/sw/rxe/rxe_verbs.c
> > > > @@ -469,6 +469,12 @@ static int rxe_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
> > > >       if (err)
> > > >               goto err1;
> > > >
> > > > +     if ((mask & IB_QP_AV) && (attr->ah_attr.ah_flags & IB_AH_GRH))
> > >
> > > You are leaving src_port default and wired to same port as other QPs
> > > without any randomization.
> >
> > Hi,
> >
> > I do not get you. Why do you think I am leaving src_pport default?
>
> Because in original code, you randomized src_port without any relation
> to mask flags.
>
>        qp->src_port = RXE_ROCE_V2_SPORT +
>                (hash_32_generic(qp_num(qp), 14) & 0x3fff);
>
> After patch #5, if user doesn't pass "proper" mask, you will leave
> qp->src_port to be equal to RXE_ROCE_V2_SPORT, which is different from
> the current behaviour.

Hi, Leon Romanovsky

I read your comments again and checked the source code.
And I found this https://lkml.org/lkml/2015/12/15/566, Jason commented:
"
...
The GRH is optional for in-subnet communications.
...
"
I agree with you. When in-subnet communications, GRH is optional.
It is possible that qp->src_port is set to RXE_ROCE_V2_SPORT.

So I will remove patch #5 and send the patch series again.
Thanks.
Zhu Yanjun

>
> Thanks
>
>
> > Thanks.
> >
> > Zhu Yanjun
> >
> > >
> > > Thanks
> > >
> > > > +             qp->src_port = rdma_get_udp_sport(attr->ah_attr.grh.flow_label,
> > > > +                                               qp->ibqp.qp_num,
> > > > +                                               qp->attr.dest_qp_num);
> > > > +
> > > > +
> > > >       return 0;
> > > >
> > > >  err1:
> > > > --
> > > > 2.27.0
> > > >

^ permalink raw reply

* [PATCH] clocksource/drivers/imx-tpm: exclude sched clock for ARM64
From: Peng Fan (OSS) @ 2022-01-05 12:43 UTC (permalink / raw)
  To: daniel.lezcano, tglx
  Cc: shawnguo, s.hauer, kernel, festevam, linux-imx, linux-kernel,
	linux-arm-kernel, Peng Fan

From: Peng Fan <peng.fan@nxp.com>

For ARM64 platform such as i.MX8ULP which has ARMv8 generic timer as sched
clock, which is much faster compared with tpm sched clock. Reading the
tpm count register in i.MX8ULP requires about 290ns, this is slow and
introduce scheduler latency. So exclude tpm sched clock for ARM64
platform.

Signed-off-by: Peng Fan <peng.fan@nxp.com>
---
 drivers/clocksource/timer-imx-tpm.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/clocksource/timer-imx-tpm.c b/drivers/clocksource/timer-imx-tpm.c
index 2cdc077a39f5..2bd530b9adc4 100644
--- a/drivers/clocksource/timer-imx-tpm.c
+++ b/drivers/clocksource/timer-imx-tpm.c
@@ -150,10 +150,10 @@ static int __init tpm_clocksource_init(void)
 	tpm_delay_timer.read_current_timer = &tpm_read_current_timer;
 	tpm_delay_timer.freq = timer_of_rate(&to_tpm) >> 3;
 	register_current_timer_delay(&tpm_delay_timer);
-#endif
 
 	sched_clock_register(tpm_read_sched_clock, counter_width,
 			     timer_of_rate(&to_tpm) >> 3);
+#endif
 
 	return clocksource_mmio_init(timer_base + TPM_CNT,
 				     "imx-tpm",
-- 
2.25.1


^ permalink raw reply related

* Re: [PATCH v2 03/11] usb: gadget: f_uac2: Support multiple sampling rates
From: John Keeping @ 2022-01-05 12:44 UTC (permalink / raw)
  To: Pavel Hofman
  Cc: linux-usb, Ruslan Bilovol, Felipe Balbi, Jerome Brunet,
	Julian Scheel, Greg Kroah-Hartman
In-Reply-To: <7b135fce-d822-61e4-a2e0-e44ff9558fbd@ivitera.com>

On Wed, Jan 05, 2022 at 01:20:01PM +0100, Pavel Hofman wrote:
> Dne 04. 01. 22 v 16:33 John Keeping napsal(a):
> > On Wed, Dec 22, 2021 at 11:01:16AM +0100, Pavel Hofman wrote:
> > > 
> > > Dne 21. 12. 21 v 12:59 John Keeping napsal(a):
> > > > On Mon, Dec 20, 2021 at 10:11:22PM +0100, Pavel Hofman wrote:
> > > > > From: Julian Scheel <julian@jusst.de>
> > > > > 
> > > > > A list of sampling rates can be specified via configfs. All enabled
> > > > > sampling rates are sent to the USB host on request. When the host
> > > > > selects a sampling rate the internal active rate is updated.
> > > > > 
> > > > > Config strings with single value stay compatible with the previous version.
> > > > > 
> > > > > Multiple samplerates passed as configuration arrays to g_audio module
> > > > > when built for f_uac2.
> > > > > 
> > > > > Signed-off-by: Julian Scheel <julian@jusst.de>
> > > > > Signed-off-by: Pavel Hofman <pavel.hofman@ivitera.com>
> > > > > ---
> > [snip]
> > > > >    };
> > > > >    static inline struct f_uac2 *func_to_uac2(struct usb_function *f)
> > > > > @@ -166,7 +167,7 @@ static struct uac_clock_source_descriptor in_clk_src_desc = {
> > > > >    	.bDescriptorSubtype = UAC2_CLOCK_SOURCE,
> > > > >    	/* .bClockID = DYNAMIC */
> > > > >    	.bmAttributes = UAC_CLOCK_SOURCE_TYPE_INT_FIXED,
> > > > > -	.bmControls = (CONTROL_RDONLY << CLK_FREQ_CTRL),
> > > > > +	.bmControls = (CONTROL_RDWR << CLK_FREQ_CTRL),
> > > > >    	.bAssocTerminal = 0,
> > > > >    };
> > > > > @@ -178,7 +179,7 @@ static struct uac_clock_source_descriptor out_clk_src_desc = {
> > > > >    	.bDescriptorSubtype = UAC2_CLOCK_SOURCE,
> > > > >    	/* .bClockID = DYNAMIC */
> > > > >    	.bmAttributes = UAC_CLOCK_SOURCE_TYPE_INT_FIXED,
> > > > > -	.bmControls = (CONTROL_RDONLY << CLK_FREQ_CTRL),
> > > > > +	.bmControls = (CONTROL_RDWR << CLK_FREQ_CTRL),
> > > > >    	.bAssocTerminal = 0,
> > > > >    };
> > > > > @@ -635,12 +636,32 @@ struct cntrl_cur_lay3 {
> > > > >    };
> > > > >    struct cntrl_range_lay3 {
> > > > > -	__le16	wNumSubRanges;
> > > > >    	__le32	dMIN;
> > > > >    	__le32	dMAX;
> > > > >    	__le32	dRES;
> > > > >    } __packed;
> > > > > +#define ranges_size(c) (sizeof(c.wNumSubRanges) + c.wNumSubRanges \
> > > > > +		* sizeof(struct cntrl_ranges_lay3))
> > > > > +
> > > > > +struct cntrl_ranges_lay3 {
> > > > > +	__u16	wNumSubRanges;
> > > > > +	struct cntrl_range_lay3 r[UAC_MAX_RATES];
> > > > > +} __packed;
> > > > 
> > > > These structures are now inconsistent between cntrl_range_lay2 and
> > > > cntrl_range_lay3.  Would it be better to make these flex arrays?  I
> > > > guess that will make the code that uses it more complicated, but at the
> > > > moment it looks like these are trying to be generic while in reality
> > > > being quite specific to the one place that uses them at the moment.
> > > 
> > > I am afraid I do not know exactly how to do that. Please can you post an
> > > example? The rate control requires u32 (u16 is too small). Thanks a lot.
> > 
> > After the change in this patch, we end up with:
> > 
> > 	struct cntrl_range_lay2 {
> > 		__le16	wNumSubRanges;
> > 		__le16	wMIN;
> > 		__le16	wMAX;
> > 		__le16	wRES;
> > 	} __packed;
> > 
> > 	struct cntrl_range_lay3 {
> > 		__le32	dMIN;
> > 		__le32	dMAX;
> > 		__le32	dRES;
> > 	} __packed;
> > 
> > so there are two structures with similar names but totally different
> > structure, which I think risks confusion in the future.
> > 
> > I wonder if DECLARE_UAC2_FEATURE_UNIT_DESCRIPTOR in linux/usb/audio-v2.h
> > provides inspiration here, so potentially something like:
> > 
> > 	#define DECLARE_UAC2_CNTRL_RANGE_LAY3(n)	\
> > 		struct uac2_cntrl_range_lay3_##n {	\
> > 			__le16 wNumSubRanges;		\
> > 			struct cntrl_range_le32 r[n];	\
> > 		} __packed;
> > 
> > 	DECLARE_UAC2_CNTRL_RANGE_LAY3(UAC_MAX_RATES);
> 
> Thanks, I will try to follow your suggestion in the next patchset version.
> 
> > 
> > > > > +static int get_max_srate(const int *srates)
> > > > > +{
> > > > > +	int i, max_srate = 0;
> > > > > +
> > > > > +	for (i = 0; i < UAC_MAX_RATES; i++) {
> > > > > +		if (srates[i] == 0)
> > > > > +			break;
> > > > > +		if (srates[i] > max_srate)
> > > > > +			max_srate = srates[i];
> > > > > +	}
> > > > > +	return max_srate;
> > > > > +}
> > > > > +
> > > > >    static int set_ep_max_packet_size(const struct f_uac2_opts *uac2_opts,
> > > > >    	struct usb_endpoint_descriptor *ep_desc,
> > > > >    	enum usb_device_speed speed, bool is_playback)
> > > > > @@ -667,11 +688,11 @@ static int set_ep_max_packet_size(const struct f_uac2_opts *uac2_opts,
> > > > >    	if (is_playback) {
> > > > >    		chmask = uac2_opts->p_chmask;
> > > > > -		srate = uac2_opts->p_srate;
> > > > > +		srate = get_max_srate(uac2_opts->p_srates);
> > > > >    		ssize = uac2_opts->p_ssize;
> > > > >    	} else {
> > > > >    		chmask = uac2_opts->c_chmask;
> > > > > -		srate = uac2_opts->c_srate;
> > > > > +		srate = get_max_srate(uac2_opts->c_srates);
> > > > >    		ssize = uac2_opts->c_ssize;
> > > > >    	}
> > > > > @@ -912,10 +933,10 @@ static int afunc_validate_opts(struct g_audio *agdev, struct device *dev)
> > > > >    	} else if ((opts->c_ssize < 1) || (opts->c_ssize > 4)) {
> > > > >    		dev_err(dev, "Error: incorrect capture sample size\n");
> > > > >    		return -EINVAL;
> > > > > -	} else if (!opts->p_srate) {
> > > > > +	} else if (!opts->p_srates[0]) {
> > > > >    		dev_err(dev, "Error: incorrect playback sampling rate\n");
> > > > >    		return -EINVAL;
> > > > > -	} else if (!opts->c_srate) {
> > > > > +	} else if (!opts->c_srates[0]) {
> > > > >    		dev_err(dev, "Error: incorrect capture sampling rate\n");
> > > > >    		return -EINVAL;
> > > > >    	}
> > > > > @@ -1210,7 +1231,8 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
> > > > >    	agdev->params.p_chmask = uac2_opts->p_chmask;
> > > > >    	agdev->params.p_srate = uac2_opts->p_srate;
> > > > > -	agdev->params.p_srates[0] = uac2_opts->p_srate;
> > > > > +	memcpy(agdev->params.p_srates, uac2_opts->p_srates,
> > > > > +			sizeof(agdev->params.p_srates));
> > > > >    	agdev->params.p_ssize = uac2_opts->p_ssize;
> > > > >    	if (FUIN_EN(uac2_opts)) {
> > > > >    		agdev->params.p_fu.id = USB_IN_FU_ID;
> > > > > @@ -1222,7 +1244,8 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
> > > > >    	}
> > > > >    	agdev->params.c_chmask = uac2_opts->c_chmask;
> > > > >    	agdev->params.c_srate = uac2_opts->c_srate;
> > > > > -	agdev->params.c_srates[0] = uac2_opts->c_srate;
> > > > > +	memcpy(agdev->params.c_srates, uac2_opts->c_srates,
> > > > > +			sizeof(agdev->params.c_srates));
> > > > >    	agdev->params.c_ssize = uac2_opts->c_ssize;
> > > > >    	if (FUOUT_EN(uac2_opts)) {
> > > > >    		agdev->params.c_fu.id = USB_OUT_FU_ID;
> > > > > @@ -1502,28 +1525,39 @@ in_rq_range(struct usb_function *fn, const struct usb_ctrlrequest *cr)
> > > > >    	u8 entity_id = (w_index >> 8) & 0xff;
> > > > >    	u8 control_selector = w_value >> 8;
> > > > >    	int value = -EOPNOTSUPP;
> > > > > -	int p_srate, c_srate;
> > > > > -
> > > > > -	p_srate = opts->p_srate;
> > > > > -	c_srate = opts->c_srate;
> > > > >    	if ((entity_id == USB_IN_CLK_ID) || (entity_id == USB_OUT_CLK_ID)) {
> > > > >    		if (control_selector == UAC2_CS_CONTROL_SAM_FREQ) {
> > > > > -			struct cntrl_range_lay3 r;
> > > > > +			struct cntrl_ranges_lay3 rs;
> > > > > +			int i;
> > > > > +			int wNumSubRanges = 0;
> > > > > +			int srate;
> > > > > +			int *srates;
> > > > >    			if (entity_id == USB_IN_CLK_ID)
> > > > > -				r.dMIN = cpu_to_le32(p_srate);
> > > > > +				srates = opts->p_srates;
> > > > >    			else if (entity_id == USB_OUT_CLK_ID)
> > > > > -				r.dMIN = cpu_to_le32(c_srate);
> > > > > +				srates = opts->c_srates;
> > > > >    			else
> > > > >    				return -EOPNOTSUPP;
> > > > > -
> > > > > -			r.dMAX = r.dMIN;
> > > > > -			r.dRES = 0;
> > > > > -			r.wNumSubRanges = cpu_to_le16(1);
> > > > > -
> > > > > -			value = min_t(unsigned int, w_length, sizeof(r));
> > > > > -			memcpy(req->buf, &r, value);
> > > > > +			for (i = 0; i < UAC_MAX_RATES; i++) {
> > > > > +				srate = srates[i];
> > > > > +				if (srate == 0)
> > > > > +					break;
> > > > > +
> > > > > +				rs.r[wNumSubRanges].dMIN = cpu_to_le32(srate);
> > > > > +				rs.r[wNumSubRanges].dMAX = cpu_to_le32(srate);
> > > > > +				rs.r[wNumSubRanges].dRES = 0;
> > > > > +				wNumSubRanges++;
> > > > > +				dev_dbg(&agdev->gadget->dev,
> > > > > +					"%s(): clk %d: rate ID %d: %d\n",
> > > > > +					__func__, entity_id, wNumSubRanges, srate);
> > > > > +			}
> > > > > +			rs.wNumSubRanges = cpu_to_le16(wNumSubRanges);
> > > > > +			value = min_t(unsigned int, w_length, ranges_size(rs));
> > > > > +			dev_dbg(&agdev->gadget->dev, "%s(): sending %d rates, size %d\n",
> > > > > +				__func__, rs.wNumSubRanges, value);
> > > > > +			memcpy(req->buf, &rs, value);
> > > > >    		} else {
> > > > >    			dev_err(&agdev->gadget->dev,
> > > > >    				"%s:%d control_selector=%d TODO!\n",
> > > > > @@ -1582,6 +1616,28 @@ ac_rq_in(struct usb_function *fn, const struct usb_ctrlrequest *cr)
> > > > >    		return -EOPNOTSUPP;
> > > > >    }
> > > > > +static void uac2_cs_control_sam_freq(struct usb_ep *ep, struct usb_request *req)
> > > > > +{
> > > > > +	struct usb_function *fn = ep->driver_data;
> > > > > +	struct g_audio *agdev = func_to_g_audio(fn);
> > > > > +	struct f_uac2 *uac2 = func_to_uac2(fn);
> > > > > +	struct f_uac2_opts *opts = g_audio_to_uac2_opts(agdev);
> > > > > +	u32 val;
> > > > > +
> > > > > +	if (req->actual != 4)
> > > > > +		return;
> > > > > +
> > > > > +	val = le32_to_cpu(*((u32 *)req->buf));
> > > > > +	dev_dbg(&agdev->gadget->dev, "%s val: %d.\n", __func__, val);
> > > > > +	if (uac2->ctl_id == USB_IN_CLK_ID) {
> > > > > +		opts->p_srate = val;
> > > > 
> > > > Don't you need to hold opts->lock to change this?
> > > > I'm not sure opts should be changed here though - that's the setup phase
> > > > and this is "current state", so shouldn't it move to struct f_uac2?
> > > 
> > > OK. I moved the current p_srate/c_srate from struct opts to f_uac2,
> > > initialized with first value of opts->p_srates/c_srates[0] in afunc_bind.
> > > The struct f_uac2 has no lock yet. Should I add the lock mutex to f_uac2 and
> > > be locking f_uac2 access here in uac2_cs_control_sam_freq?
> > 
> > Could we move this into struct uac_rtd_params and use the existing lock
> > there to guard it?
> > 
> > It would need accessor functions as that structure's local to u_audio.c,
> > but there's already u_audio_set_playback_srate() so that isn't a big
> > change.
> 
> I have already moved p_/c_srate from uac_params to uac_rtd_params in
> u_audio.c in the next version of the patchset. But IIUC the currently
> selected playback/capture rate is required within f_uac2 too, in in_rq_cur()
> in:
> 
> if (control_selector == UAC2_CS_CONTROL_SAM_FREQ) {
> 	...
> 	if (entity_id == USB_IN_CLK_ID)
> 		c.dCUR = cpu_to_le32(p_srate);
> 	else if (entity_id == USB_OUT_CLK_ID)
> 		c.dCUR = cpu_to_le32(c_srate);
> 	...
> }

Can this can be u_audio_get_playback_srate(agdev) (and equivalent for
capture)?


John

^ permalink raw reply

* [PATCH] clocksource/drivers/imx-tpm: exclude sched clock for ARM64
From: Peng Fan (OSS) @ 2022-01-05 12:43 UTC (permalink / raw)
  To: daniel.lezcano, tglx
  Cc: shawnguo, s.hauer, kernel, festevam, linux-imx, linux-kernel,
	linux-arm-kernel, Peng Fan

From: Peng Fan <peng.fan@nxp.com>

For ARM64 platform such as i.MX8ULP which has ARMv8 generic timer as sched
clock, which is much faster compared with tpm sched clock. Reading the
tpm count register in i.MX8ULP requires about 290ns, this is slow and
introduce scheduler latency. So exclude tpm sched clock for ARM64
platform.

Signed-off-by: Peng Fan <peng.fan@nxp.com>
---
 drivers/clocksource/timer-imx-tpm.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/clocksource/timer-imx-tpm.c b/drivers/clocksource/timer-imx-tpm.c
index 2cdc077a39f5..2bd530b9adc4 100644
--- a/drivers/clocksource/timer-imx-tpm.c
+++ b/drivers/clocksource/timer-imx-tpm.c
@@ -150,10 +150,10 @@ static int __init tpm_clocksource_init(void)
 	tpm_delay_timer.read_current_timer = &tpm_read_current_timer;
 	tpm_delay_timer.freq = timer_of_rate(&to_tpm) >> 3;
 	register_current_timer_delay(&tpm_delay_timer);
-#endif
 
 	sched_clock_register(tpm_read_sched_clock, counter_width,
 			     timer_of_rate(&to_tpm) >> 3);
+#endif
 
 	return clocksource_mmio_init(timer_base + TPM_CNT,
 				     "imx-tpm",
-- 
2.25.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* Re: [RFC PATCH] vfio: Update/Clarify migration uAPI, add NDMA state
From: Jason Gunthorpe @ 2022-01-05 12:45 UTC (permalink / raw)
  To: Tian, Kevin
  Cc: Alex Williamson, cohuck@redhat.com, corbet@lwn.net,
	kvm@vger.kernel.org, linux-doc@vger.kernel.org,
	farman@linux.ibm.com, mjrosato@linux.ibm.com, pasic@linux.ibm.com,
	Lu, Baolu
In-Reply-To: <BN9PR11MB527662CA4820107EA7B6CC278C4B9@BN9PR11MB5276.namprd11.prod.outlook.com>

On Wed, Jan 05, 2022 at 01:59:31AM +0000, Tian, Kevin wrote:

> > This will block the hypervisor from ever migrating the VM in a very
> > poor way - it will just hang in the middle of a migration request.
> 
> it's poor but 'hang' won't happen. PCI spec defines completion timeout
> for ATS translation request. If timeout the device will abort the in-fly
> request and report error back to software. 

The PRI time outs have to be long enough to handle swap back from
disk, so 'hang' will be a fair amount of time..
 
> > Regardless of the complaints of the IP designers, this is a very poor
> > direction.
> > 
> > Progress in the hypervisor should never be contingent on a guest VM.
> > 
> 
> Whether the said DOS is a real concern and how severe it is are usage 
> specific things. Why would we want to hardcode such restriction on
> an uAPI? Just give the choice to the admin (as long as this restriction is
> clearly communicated to userspace clearly)...

IMHO it is not just DOS, PRI can become dependent on IO which requires
DMA to complete.

You could quickly get yourself into a deadlock situation where the
hypervisor has disabled DMA activities of other devices and the vPRI
simply cannot be completed.

I just don't see how this scheme is generally workable without a lot
of limitations.

While I do agree we should support the HW that exists, we should
recognize this is not a long term workable design and treat it as
such.

Jason

^ permalink raw reply

* [Bug 215445] AMDGPU -- UBSAN: invalid-load in amdgpu_dm.c:5882:84 - load of value 32 is not a valid value for type '_Bool'
From: bugzilla-daemon @ 2022-01-05 12:45 UTC (permalink / raw)
  To: dri-devel
In-Reply-To: <bug-215445-2300@https.bugzilla.kernel.org/>

https://bugzilla.kernel.org/show_bug.cgi?id=215445

Martin Pecka (peci1@seznam.cz) changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |peci1@seznam.cz

--- Comment #3 from Martin Pecka (peci1@seznam.cz) ---
I have this problem too on Thinkpad T14s AMD, kernel 5.15.12.

-- 
You may reply to this email to add a comment.

You are receiving this mail because:
You are watching the assignee of the bug.

^ permalink raw reply

* [Intel-wired-lan] [syzbot] kernel BUG in pskb_expand_head
From: Oliver Hartkopp @ 2022-01-05 12:46 UTC (permalink / raw)
  To: intel-wired-lan
In-Reply-To: <20220105114410.brzea3f5flgn5nl2@pengutronix.de>



On 05.01.22 12:44, Marc Kleine-Budde wrote:
> On 19.12.2021 16:19:20, syzbot wrote:
>>   skb_over_panic net/core/skbuff.c:118 [inline]
>>   skb_over_panic net/core/skbuff.c:118 [inline] net/core/skbuff.c:1986
>>   skb_put.cold+0x24/0x24 net/core/skbuff.c:1986 net/core/skbuff.c:1986
>>   isotp_rcv_cf net/can/isotp.c:570 [inline]
>>   isotp_rcv_cf net/can/isotp.c:570 [inline] net/can/isotp.c:668
>>   isotp_rcv+0xa38/0x1e30 net/can/isotp.c:668 net/can/isotp.c:668
> 
>> struct tpcon {
>> 	int idx;
>> 	int len;
>          ^^^
>> 	u32 state;
>> 	u8 bs;
>> 	u8 sn;
>> 	u8 ll_dl;
>> 	u8 buf[MAX_MSG_LENGTH + 1];
>> };
>>
>> static int isotp_rcv_ff(struct sock *sk, struct canfd_frame *cf, int ae)
>> {
> 
> [...]
> 
>> 	/* Check for FF_DL escape sequence supporting 32 bit PDU length */
>> 	if (so->rx.len) {
>> 		ff_pci_sz = FF_PCI_SZ12;
>> 	} else {
>> 		/* FF_DL = 0 => get real length from next 4 bytes */
>> 		so->rx.len = cf->data[ae + 2] << 24;
>> 		so->rx.len += cf->data[ae + 3] << 16;
>> 		so->rx.len += cf->data[ae + 4] << 8;
>> 		so->rx.len += cf->data[ae + 5];
>> 		ff_pci_sz = FF_PCI_SZ32;
>> 	}
> 
> Full 32 Bit PDUs don't work with struct tpcon::len being an "int". I
> think converting it to "unsigned int" should be done.
> 
> [...]
> 
>> }
>>
>> static int isotp_rcv_cf(struct sock *sk, struct canfd_frame *cf, int ae,
>> 			struct sk_buff *skb)
>> {
>> 	struct isotp_sock *so = isotp_sk(sk);
>> 	struct sk_buff *nskb;
>> 	int i;
>>
>> 	if (so->rx.state != ISOTP_WAIT_DATA)
>> 		return 0;
>>
>> 	/* drop if timestamp gap is less than force_rx_stmin nano secs */
>> 	if (so->opt.flags & CAN_ISOTP_FORCE_RXSTMIN) {
>> 		if (ktime_to_ns(ktime_sub(skb->tstamp, so->lastrxcf_tstamp)) <
>> 		    so->force_rx_stmin)
>> 			return 0;
>>
>> 		so->lastrxcf_tstamp = skb->tstamp;
>> 	}
>>
>> 	hrtimer_cancel(&so->rxtimer);
>>
>> 	/* CFs are never longer than the FF */
>> 	if (cf->len > so->rx.ll_dl)
>> 		return 1;
>>
>> 	/* CFs have usually the LL_DL length */
>> 	if (cf->len < so->rx.ll_dl) {
>> 		/* this is only allowed for the last CF */
>> 		if (so->rx.len - so->rx.idx > so->rx.ll_dl - ae - N_PCI_SZ)
>> 			return 1;
>> 	}
>>
>> 	if ((cf->data[ae] & 0x0F) != so->rx.sn) {
>> 		/* wrong sn detected - report 'illegal byte sequence' */
>> 		sk->sk_err = EILSEQ;
>> 		if (!sock_flag(sk, SOCK_DEAD))
>> 			sk_error_report(sk);
>>
>> 		/* reset rx state */
>> 		so->rx.state = ISOTP_IDLE;
>> 		return 1;
>> 	}
>> 	so->rx.sn++;
>> 	so->rx.sn %= 16;
>>
>> 	for (i = ae + N_PCI_SZ; i < cf->len; i++) {
>> 		so->rx.buf[so->rx.idx++] = cf->data[i];
>> 		if (so->rx.idx >= so->rx.len)
>> 			break;
>> 	}
>>
>> 	if (so->rx.idx >= so->rx.len) {
>> 		/* we are done */
>> 		so->rx.state = ISOTP_IDLE;
>>
>> 		if ((so->opt.flags & ISOTP_CHECK_PADDING) &&
>> 		    check_pad(so, cf, i + 1, so->opt.rxpad_content)) {
>> 			/* malformed PDU - report 'not a data message' */
>> 			sk->sk_err = EBADMSG;
>> 			if (!sock_flag(sk, SOCK_DEAD))
>> 				sk_error_report(sk);
>> 			return 1;
>> 		}
>>
>> 		nskb = alloc_skb(so->rx.len, gfp_any());
>> 		if (!nskb)
>> 			return 1;
>>
>> 		memcpy(skb_put(nskb, so->rx.len), so->rx.buf,
>                         ^^^^^^^
>> 		       so->rx.len);
> 
> This is where the skb_over_panic() happens.
> 

Thanks Marc!

Yes I went to this piece of code too - but was not able to find anything 
wrong, as the values at this point should be far(!!) away from INT_MAX.

Due to this check in isotp_rcv_ff():

if (so->rx.len > MAX_MSG_LENGTH) { ... exit

And MAX_MSG_LENGTH is define as 8200.

Btw. making tpcon:len an unsigned int is really the solution to this! 
Which makes the above if-statement act correctly also with values like 
0x80001234.

m(

Thanks for the finding!

Best regards,
Oliver

^ permalink raw reply

* Re: [syzbot] kernel BUG in pskb_expand_head
From: Oliver Hartkopp @ 2022-01-05 12:46 UTC (permalink / raw)
  To: Marc Kleine-Budde, syzbot
  Cc: anthony.l.nguyen, davem, eric.dumazet, hawk,
	intel-wired-lan-owner, intel-wired-lan, jesse.brandeburg, kuba,
	linux-can, linux-kernel, netdev, syzkaller-bugs
In-Reply-To: <20220105114410.brzea3f5flgn5nl2@pengutronix.de>



On 05.01.22 12:44, Marc Kleine-Budde wrote:
> On 19.12.2021 16:19:20, syzbot wrote:
>>   skb_over_panic net/core/skbuff.c:118 [inline]
>>   skb_over_panic net/core/skbuff.c:118 [inline] net/core/skbuff.c:1986
>>   skb_put.cold+0x24/0x24 net/core/skbuff.c:1986 net/core/skbuff.c:1986
>>   isotp_rcv_cf net/can/isotp.c:570 [inline]
>>   isotp_rcv_cf net/can/isotp.c:570 [inline] net/can/isotp.c:668
>>   isotp_rcv+0xa38/0x1e30 net/can/isotp.c:668 net/can/isotp.c:668
> 
>> struct tpcon {
>> 	int idx;
>> 	int len;
>          ^^^
>> 	u32 state;
>> 	u8 bs;
>> 	u8 sn;
>> 	u8 ll_dl;
>> 	u8 buf[MAX_MSG_LENGTH + 1];
>> };
>>
>> static int isotp_rcv_ff(struct sock *sk, struct canfd_frame *cf, int ae)
>> {
> 
> [...]
> 
>> 	/* Check for FF_DL escape sequence supporting 32 bit PDU length */
>> 	if (so->rx.len) {
>> 		ff_pci_sz = FF_PCI_SZ12;
>> 	} else {
>> 		/* FF_DL = 0 => get real length from next 4 bytes */
>> 		so->rx.len = cf->data[ae + 2] << 24;
>> 		so->rx.len += cf->data[ae + 3] << 16;
>> 		so->rx.len += cf->data[ae + 4] << 8;
>> 		so->rx.len += cf->data[ae + 5];
>> 		ff_pci_sz = FF_PCI_SZ32;
>> 	}
> 
> Full 32 Bit PDUs don't work with struct tpcon::len being an "int". I
> think converting it to "unsigned int" should be done.
> 
> [...]
> 
>> }
>>
>> static int isotp_rcv_cf(struct sock *sk, struct canfd_frame *cf, int ae,
>> 			struct sk_buff *skb)
>> {
>> 	struct isotp_sock *so = isotp_sk(sk);
>> 	struct sk_buff *nskb;
>> 	int i;
>>
>> 	if (so->rx.state != ISOTP_WAIT_DATA)
>> 		return 0;
>>
>> 	/* drop if timestamp gap is less than force_rx_stmin nano secs */
>> 	if (so->opt.flags & CAN_ISOTP_FORCE_RXSTMIN) {
>> 		if (ktime_to_ns(ktime_sub(skb->tstamp, so->lastrxcf_tstamp)) <
>> 		    so->force_rx_stmin)
>> 			return 0;
>>
>> 		so->lastrxcf_tstamp = skb->tstamp;
>> 	}
>>
>> 	hrtimer_cancel(&so->rxtimer);
>>
>> 	/* CFs are never longer than the FF */
>> 	if (cf->len > so->rx.ll_dl)
>> 		return 1;
>>
>> 	/* CFs have usually the LL_DL length */
>> 	if (cf->len < so->rx.ll_dl) {
>> 		/* this is only allowed for the last CF */
>> 		if (so->rx.len - so->rx.idx > so->rx.ll_dl - ae - N_PCI_SZ)
>> 			return 1;
>> 	}
>>
>> 	if ((cf->data[ae] & 0x0F) != so->rx.sn) {
>> 		/* wrong sn detected - report 'illegal byte sequence' */
>> 		sk->sk_err = EILSEQ;
>> 		if (!sock_flag(sk, SOCK_DEAD))
>> 			sk_error_report(sk);
>>
>> 		/* reset rx state */
>> 		so->rx.state = ISOTP_IDLE;
>> 		return 1;
>> 	}
>> 	so->rx.sn++;
>> 	so->rx.sn %= 16;
>>
>> 	for (i = ae + N_PCI_SZ; i < cf->len; i++) {
>> 		so->rx.buf[so->rx.idx++] = cf->data[i];
>> 		if (so->rx.idx >= so->rx.len)
>> 			break;
>> 	}
>>
>> 	if (so->rx.idx >= so->rx.len) {
>> 		/* we are done */
>> 		so->rx.state = ISOTP_IDLE;
>>
>> 		if ((so->opt.flags & ISOTP_CHECK_PADDING) &&
>> 		    check_pad(so, cf, i + 1, so->opt.rxpad_content)) {
>> 			/* malformed PDU - report 'not a data message' */
>> 			sk->sk_err = EBADMSG;
>> 			if (!sock_flag(sk, SOCK_DEAD))
>> 				sk_error_report(sk);
>> 			return 1;
>> 		}
>>
>> 		nskb = alloc_skb(so->rx.len, gfp_any());
>> 		if (!nskb)
>> 			return 1;
>>
>> 		memcpy(skb_put(nskb, so->rx.len), so->rx.buf,
>                         ^^^^^^^
>> 		       so->rx.len);
> 
> This is where the skb_over_panic() happens.
> 

Thanks Marc!

Yes I went to this piece of code too - but was not able to find anything 
wrong, as the values at this point should be far(!!) away from INT_MAX.

Due to this check in isotp_rcv_ff():

if (so->rx.len > MAX_MSG_LENGTH) { ... exit

And MAX_MSG_LENGTH is define as 8200.

Btw. making tpcon:len an unsigned int is really the solution to this! 
Which makes the above if-statement act correctly also with values like 
0x80001234.

m(

Thanks for the finding!

Best regards,
Oliver

^ permalink raw reply


This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.