Merge 5.15.96 into android13-5.15-lts
Changes in 5.15.96 drm/etnaviv: don't truncate physical page address wifi: rtl8xxxu: gen2: Turn on the rate control drm/edid: Fix minimum bpc supported with DSC1.2 for HDMI sink clk: mxl: Switch from direct readl/writel based IO to regmap based IO clk: mxl: Remove redundant spinlocks clk: mxl: Add option to override gate clks clk: mxl: Fix a clk entry by adding relevant flags powerpc: dts: t208x: Mark MAC1 and MAC2 as 10G clk: mxl: syscon_node_to_regmap() returns error pointers random: always mix cycle counter in add_latent_entropy() KVM: x86: Fail emulation during EMULTYPE_SKIP on any exception KVM: SVM: Skip WRMSR fastpath on VM-Exit if next RIP isn't valid KVM: VMX: Execute IBPB on emulated VM-exit when guest has IBRS can: kvaser_usb: hydra: help gcc-13 to figure out cmd_len powerpc: dts: t208x: Disable 10G on MAC1 and MAC2 powerpc: use generic version of arch_is_kernel_initmem_freed() powerpc/vmlinux.lds: Ensure STRICT_ALIGN_SIZE is at least page aligned powerpc/vmlinux.lds: Add an explicit symbol for the SRWX boundary powerpc/64s/radix: Fix crash with unaligned relocated kernel powerpc/64s/radix: Fix RWX mapping with relocated kernel drm/i915/gvt: fix double free bug in split_2MB_gtt_entry uaccess: Add speculation barrier to copy_from_user() binder: read pre-translated fds from sender buffer binder: defer copies of pre-patched txn data binder: fix pointer cast warning binder: Address corner cases in deferred copy and fixup binder: Gracefully handle BINDER_TYPE_FDA objects with num_fds=0 nbd: fix possible overflow on 'first_minor' in nbd_dev_add() wifi: mwifiex: Add missing compatible string for SD8787 audit: update the mailing list in MAINTAINERS ext4: Fix function prototype mismatch for ext4_feat_ktype kbuild: Add CONFIG_PAHOLE_VERSION scripts/pahole-flags.sh: Use pahole-version.sh lib/Kconfig.debug: Use CONFIG_PAHOLE_VERSION lib/Kconfig.debug: Allow BTF + DWARF5 with pahole 1.21+ Revert "net/sched: taprio: make qdisc_leaf() see the per-netdev-queue pfifo child qdiscs" bpf: add missing header file include Linux 5.15.96 Change-Id: Ifa4f882dd1c5812fd472298d56e417a8a0854f5f Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
This commit is contained in:
@@ -3114,7 +3114,7 @@ F: drivers/net/ieee802154/atusb.h
|
||||
AUDIT SUBSYSTEM
|
||||
M: Paul Moore <paul@paul-moore.com>
|
||||
M: Eric Paris <eparis@redhat.com>
|
||||
L: linux-audit@redhat.com (moderated for non-subscribers)
|
||||
L: audit@vger.kernel.org
|
||||
S: Supported
|
||||
W: https://github.com/linux-audit
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/audit.git
|
||||
@@ -3407,6 +3407,7 @@ F: net/sched/act_bpf.c
|
||||
F: net/sched/cls_bpf.c
|
||||
F: samples/bpf/
|
||||
F: scripts/bpf_doc.py
|
||||
F: scripts/pahole-version.sh
|
||||
F: tools/bpf/
|
||||
F: tools/lib/bpf/
|
||||
F: tools/testing/selftests/bpf/
|
||||
|
||||
2
Makefile
2
Makefile
@@ -1,7 +1,7 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
VERSION = 5
|
||||
PATCHLEVEL = 15
|
||||
SUBLEVEL = 95
|
||||
SUBLEVEL = 96
|
||||
EXTRAVERSION =
|
||||
NAME = Trick or Treat
|
||||
|
||||
|
||||
44
arch/powerpc/boot/dts/fsl/qoriq-fman3-0-10g-2.dtsi
Normal file
44
arch/powerpc/boot/dts/fsl/qoriq-fman3-0-10g-2.dtsi
Normal file
@@ -0,0 +1,44 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0-or-later
|
||||
/*
|
||||
* QorIQ FMan v3 10g port #2 device tree stub [ controller @ offset 0x400000 ]
|
||||
*
|
||||
* Copyright 2022 Sean Anderson <sean.anderson@seco.com>
|
||||
* Copyright 2012 - 2015 Freescale Semiconductor Inc.
|
||||
*/
|
||||
|
||||
fman@400000 {
|
||||
fman0_rx_0x08: port@88000 {
|
||||
cell-index = <0x8>;
|
||||
compatible = "fsl,fman-v3-port-rx";
|
||||
reg = <0x88000 0x1000>;
|
||||
fsl,fman-10g-port;
|
||||
};
|
||||
|
||||
fman0_tx_0x28: port@a8000 {
|
||||
cell-index = <0x28>;
|
||||
compatible = "fsl,fman-v3-port-tx";
|
||||
reg = <0xa8000 0x1000>;
|
||||
fsl,fman-10g-port;
|
||||
};
|
||||
|
||||
ethernet@e0000 {
|
||||
cell-index = <0>;
|
||||
compatible = "fsl,fman-memac";
|
||||
reg = <0xe0000 0x1000>;
|
||||
fsl,fman-ports = <&fman0_rx_0x08 &fman0_tx_0x28>;
|
||||
ptp-timer = <&ptp_timer0>;
|
||||
pcsphy-handle = <&pcsphy0>;
|
||||
};
|
||||
|
||||
mdio@e1000 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio";
|
||||
reg = <0xe1000 0x1000>;
|
||||
fsl,erratum-a011043; /* must ignore read errors */
|
||||
|
||||
pcsphy0: ethernet-phy@0 {
|
||||
reg = <0x0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
44
arch/powerpc/boot/dts/fsl/qoriq-fman3-0-10g-3.dtsi
Normal file
44
arch/powerpc/boot/dts/fsl/qoriq-fman3-0-10g-3.dtsi
Normal file
@@ -0,0 +1,44 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0-or-later
|
||||
/*
|
||||
* QorIQ FMan v3 10g port #3 device tree stub [ controller @ offset 0x400000 ]
|
||||
*
|
||||
* Copyright 2022 Sean Anderson <sean.anderson@seco.com>
|
||||
* Copyright 2012 - 2015 Freescale Semiconductor Inc.
|
||||
*/
|
||||
|
||||
fman@400000 {
|
||||
fman0_rx_0x09: port@89000 {
|
||||
cell-index = <0x9>;
|
||||
compatible = "fsl,fman-v3-port-rx";
|
||||
reg = <0x89000 0x1000>;
|
||||
fsl,fman-10g-port;
|
||||
};
|
||||
|
||||
fman0_tx_0x29: port@a9000 {
|
||||
cell-index = <0x29>;
|
||||
compatible = "fsl,fman-v3-port-tx";
|
||||
reg = <0xa9000 0x1000>;
|
||||
fsl,fman-10g-port;
|
||||
};
|
||||
|
||||
ethernet@e2000 {
|
||||
cell-index = <1>;
|
||||
compatible = "fsl,fman-memac";
|
||||
reg = <0xe2000 0x1000>;
|
||||
fsl,fman-ports = <&fman0_rx_0x09 &fman0_tx_0x29>;
|
||||
ptp-timer = <&ptp_timer0>;
|
||||
pcsphy-handle = <&pcsphy1>;
|
||||
};
|
||||
|
||||
mdio@e3000 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio";
|
||||
reg = <0xe3000 0x1000>;
|
||||
fsl,erratum-a011043; /* must ignore read errors */
|
||||
|
||||
pcsphy1: ethernet-phy@0 {
|
||||
reg = <0x0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -609,8 +609,8 @@ usb1: usb@211000 {
|
||||
/include/ "qoriq-bman1.dtsi"
|
||||
|
||||
/include/ "qoriq-fman3-0.dtsi"
|
||||
/include/ "qoriq-fman3-0-1g-0.dtsi"
|
||||
/include/ "qoriq-fman3-0-1g-1.dtsi"
|
||||
/include/ "qoriq-fman3-0-10g-2.dtsi"
|
||||
/include/ "qoriq-fman3-0-10g-3.dtsi"
|
||||
/include/ "qoriq-fman3-0-1g-2.dtsi"
|
||||
/include/ "qoriq-fman3-0-1g-3.dtsi"
|
||||
/include/ "qoriq-fman3-0-1g-4.dtsi"
|
||||
@@ -659,3 +659,19 @@ L2_1: l2-cache-controller@c20000 {
|
||||
interrupts = <16 2 1 9>;
|
||||
};
|
||||
};
|
||||
|
||||
&fman0_rx_0x08 {
|
||||
/delete-property/ fsl,fman-10g-port;
|
||||
};
|
||||
|
||||
&fman0_tx_0x28 {
|
||||
/delete-property/ fsl,fman-10g-port;
|
||||
};
|
||||
|
||||
&fman0_rx_0x09 {
|
||||
/delete-property/ fsl,fman-10g-port;
|
||||
};
|
||||
|
||||
&fman0_tx_0x29 {
|
||||
/delete-property/ fsl,fman-10g-port;
|
||||
};
|
||||
|
||||
@@ -6,22 +6,10 @@
|
||||
#include <linux/elf.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#define arch_is_kernel_initmem_freed arch_is_kernel_initmem_freed
|
||||
|
||||
#include <asm-generic/sections.h>
|
||||
|
||||
extern bool init_mem_is_free;
|
||||
|
||||
static inline int arch_is_kernel_initmem_freed(unsigned long addr)
|
||||
{
|
||||
if (!init_mem_is_free)
|
||||
return 0;
|
||||
|
||||
return addr >= (unsigned long)__init_begin &&
|
||||
addr < (unsigned long)__init_end;
|
||||
}
|
||||
|
||||
extern char __head_end[];
|
||||
extern char __srwx_boundary[];
|
||||
|
||||
#ifdef __powerpc64__
|
||||
|
||||
|
||||
@@ -32,6 +32,10 @@
|
||||
|
||||
#define STRICT_ALIGN_SIZE (1 << CONFIG_DATA_SHIFT)
|
||||
|
||||
#if STRICT_ALIGN_SIZE < PAGE_SIZE
|
||||
#error "CONFIG_DATA_SHIFT must be >= PAGE_SHIFT"
|
||||
#endif
|
||||
|
||||
ENTRY(_stext)
|
||||
|
||||
PHDRS {
|
||||
@@ -204,12 +208,16 @@ SECTIONS
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Various code relies on __init_begin being at the strict RWX boundary.
|
||||
*/
|
||||
. = ALIGN(STRICT_ALIGN_SIZE);
|
||||
__srwx_boundary = .;
|
||||
__init_begin = .;
|
||||
|
||||
/*
|
||||
* Init sections discarded at runtime
|
||||
*/
|
||||
. = ALIGN(STRICT_ALIGN_SIZE);
|
||||
__init_begin = .;
|
||||
. = ALIGN(PAGE_SIZE);
|
||||
.init.text : AT(ADDR(.init.text) - LOAD_OFFSET) {
|
||||
_sinittext = .;
|
||||
INIT_TEXT
|
||||
|
||||
@@ -159,7 +159,7 @@ static unsigned long __init __mmu_mapin_ram(unsigned long base, unsigned long to
|
||||
unsigned long __init mmu_mapin_ram(unsigned long base, unsigned long top)
|
||||
{
|
||||
unsigned long done;
|
||||
unsigned long border = (unsigned long)__init_begin - PAGE_OFFSET;
|
||||
unsigned long border = (unsigned long)__srwx_boundary - PAGE_OFFSET;
|
||||
unsigned long size;
|
||||
|
||||
size = roundup_pow_of_two((unsigned long)_einittext - PAGE_OFFSET);
|
||||
|
||||
@@ -232,6 +232,14 @@ void radix__mark_rodata_ro(void)
|
||||
end = (unsigned long)__init_begin;
|
||||
|
||||
radix__change_memory_range(start, end, _PAGE_WRITE);
|
||||
|
||||
for (start = PAGE_OFFSET; start < (unsigned long)_stext; start += PAGE_SIZE) {
|
||||
end = start + PAGE_SIZE;
|
||||
if (overlaps_interrupt_vector_text(start, end))
|
||||
radix__change_memory_range(start, end, _PAGE_WRITE);
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void radix__mark_initmem_nx(void)
|
||||
@@ -260,8 +268,24 @@ print_mapping(unsigned long start, unsigned long end, unsigned long size, bool e
|
||||
static unsigned long next_boundary(unsigned long addr, unsigned long end)
|
||||
{
|
||||
#ifdef CONFIG_STRICT_KERNEL_RWX
|
||||
if (addr < __pa_symbol(__init_begin))
|
||||
return __pa_symbol(__init_begin);
|
||||
unsigned long stext_phys;
|
||||
|
||||
stext_phys = __pa_symbol(_stext);
|
||||
|
||||
// Relocatable kernel running at non-zero real address
|
||||
if (stext_phys != 0) {
|
||||
// The end of interrupts code at zero is a rodata boundary
|
||||
unsigned long end_intr = __pa_symbol(__end_interrupts) - stext_phys;
|
||||
if (addr < end_intr)
|
||||
return end_intr;
|
||||
|
||||
// Start of relocated kernel text is a rodata boundary
|
||||
if (addr < stext_phys)
|
||||
return stext_phys;
|
||||
}
|
||||
|
||||
if (addr < __pa_symbol(__srwx_boundary))
|
||||
return __pa_symbol(__srwx_boundary);
|
||||
#endif
|
||||
return end;
|
||||
}
|
||||
|
||||
@@ -3740,8 +3740,14 @@ static void svm_cancel_injection(struct kvm_vcpu *vcpu)
|
||||
|
||||
static fastpath_t svm_exit_handlers_fastpath(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
if (to_svm(vcpu)->vmcb->control.exit_code == SVM_EXIT_MSR &&
|
||||
to_svm(vcpu)->vmcb->control.exit_info_1)
|
||||
struct vmcb_control_area *control = &to_svm(vcpu)->vmcb->control;
|
||||
|
||||
/*
|
||||
* Note, the next RIP must be provided as SRCU isn't held, i.e. KVM
|
||||
* can't read guest memory (dereference memslots) to decode the WRMSR.
|
||||
*/
|
||||
if (control->exit_code == SVM_EXIT_MSR && control->exit_info_1 &&
|
||||
nrips && control->next_rip)
|
||||
return handle_fastpath_set_msr_irqoff(vcpu);
|
||||
|
||||
return EXIT_FASTPATH_NONE;
|
||||
|
||||
@@ -4617,6 +4617,17 @@ void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 vm_exit_reason,
|
||||
|
||||
vmx_switch_vmcs(vcpu, &vmx->vmcs01);
|
||||
|
||||
/*
|
||||
* If IBRS is advertised to the vCPU, KVM must flush the indirect
|
||||
* branch predictors when transitioning from L2 to L1, as L1 expects
|
||||
* hardware (KVM in this case) to provide separate predictor modes.
|
||||
* Bare metal isolates VMX root (host) from VMX non-root (guest), but
|
||||
* doesn't isolate different VMCSs, i.e. in this case, doesn't provide
|
||||
* separate modes for L2 vs L1.
|
||||
*/
|
||||
if (guest_cpuid_has(vcpu, X86_FEATURE_SPEC_CTRL))
|
||||
indirect_branch_prediction_barrier();
|
||||
|
||||
/* Update any VMCS fields that might have changed while L2 ran */
|
||||
vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, vmx->msr_autoload.host.nr);
|
||||
vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, vmx->msr_autoload.guest.nr);
|
||||
|
||||
@@ -1332,8 +1332,10 @@ void vmx_vcpu_load_vmcs(struct kvm_vcpu *vcpu, int cpu,
|
||||
|
||||
/*
|
||||
* No indirect branch prediction barrier needed when switching
|
||||
* the active VMCS within a guest, e.g. on nested VM-Enter.
|
||||
* The L1 VMM can protect itself with retpolines, IBPB or IBRS.
|
||||
* the active VMCS within a vCPU, unless IBRS is advertised to
|
||||
* the vCPU. To minimize the number of IBPBs executed, KVM
|
||||
* performs IBPB on nested VM-Exit (a single nested transition
|
||||
* may switch the active VMCS multiple times).
|
||||
*/
|
||||
if (!buddy || WARN_ON_ONCE(buddy->vmcs != prev))
|
||||
indirect_branch_prediction_barrier();
|
||||
|
||||
@@ -8116,7 +8116,9 @@ int x86_emulate_instruction(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa,
|
||||
write_fault_to_spt,
|
||||
emulation_type))
|
||||
return 1;
|
||||
if (ctxt->have_exception) {
|
||||
|
||||
if (ctxt->have_exception &&
|
||||
!(emulation_type & EMULTYPE_SKIP)) {
|
||||
/*
|
||||
* #UD should result in just EMULATION_FAILED, and trap-like
|
||||
* exception should not be encountered during decode.
|
||||
|
||||
@@ -2459,16 +2459,266 @@ static int binder_translate_fd(u32 fd, binder_size_t fd_offset,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int binder_translate_fd_array(struct binder_fd_array_object *fda,
|
||||
/**
|
||||
* struct binder_ptr_fixup - data to be fixed-up in target buffer
|
||||
* @offset offset in target buffer to fixup
|
||||
* @skip_size bytes to skip in copy (fixup will be written later)
|
||||
* @fixup_data data to write at fixup offset
|
||||
* @node list node
|
||||
*
|
||||
* This is used for the pointer fixup list (pf) which is created and consumed
|
||||
* during binder_transaction() and is only accessed locally. No
|
||||
* locking is necessary.
|
||||
*
|
||||
* The list is ordered by @offset.
|
||||
*/
|
||||
struct binder_ptr_fixup {
|
||||
binder_size_t offset;
|
||||
size_t skip_size;
|
||||
binder_uintptr_t fixup_data;
|
||||
struct list_head node;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct binder_sg_copy - scatter-gather data to be copied
|
||||
* @offset offset in target buffer
|
||||
* @sender_uaddr user address in source buffer
|
||||
* @length bytes to copy
|
||||
* @node list node
|
||||
*
|
||||
* This is used for the sg copy list (sgc) which is created and consumed
|
||||
* during binder_transaction() and is only accessed locally. No
|
||||
* locking is necessary.
|
||||
*
|
||||
* The list is ordered by @offset.
|
||||
*/
|
||||
struct binder_sg_copy {
|
||||
binder_size_t offset;
|
||||
const void __user *sender_uaddr;
|
||||
size_t length;
|
||||
struct list_head node;
|
||||
};
|
||||
|
||||
/**
|
||||
* binder_do_deferred_txn_copies() - copy and fixup scatter-gather data
|
||||
* @alloc: binder_alloc associated with @buffer
|
||||
* @buffer: binder buffer in target process
|
||||
* @sgc_head: list_head of scatter-gather copy list
|
||||
* @pf_head: list_head of pointer fixup list
|
||||
*
|
||||
* Processes all elements of @sgc_head, applying fixups from @pf_head
|
||||
* and copying the scatter-gather data from the source process' user
|
||||
* buffer to the target's buffer. It is expected that the list creation
|
||||
* and processing all occurs during binder_transaction() so these lists
|
||||
* are only accessed in local context.
|
||||
*
|
||||
* Return: 0=success, else -errno
|
||||
*/
|
||||
static int binder_do_deferred_txn_copies(struct binder_alloc *alloc,
|
||||
struct binder_buffer *buffer,
|
||||
struct list_head *sgc_head,
|
||||
struct list_head *pf_head)
|
||||
{
|
||||
int ret = 0;
|
||||
struct binder_sg_copy *sgc, *tmpsgc;
|
||||
struct binder_ptr_fixup *tmppf;
|
||||
struct binder_ptr_fixup *pf =
|
||||
list_first_entry_or_null(pf_head, struct binder_ptr_fixup,
|
||||
node);
|
||||
|
||||
list_for_each_entry_safe(sgc, tmpsgc, sgc_head, node) {
|
||||
size_t bytes_copied = 0;
|
||||
|
||||
while (bytes_copied < sgc->length) {
|
||||
size_t copy_size;
|
||||
size_t bytes_left = sgc->length - bytes_copied;
|
||||
size_t offset = sgc->offset + bytes_copied;
|
||||
|
||||
/*
|
||||
* We copy up to the fixup (pointed to by pf)
|
||||
*/
|
||||
copy_size = pf ? min(bytes_left, (size_t)pf->offset - offset)
|
||||
: bytes_left;
|
||||
if (!ret && copy_size)
|
||||
ret = binder_alloc_copy_user_to_buffer(
|
||||
alloc, buffer,
|
||||
offset,
|
||||
sgc->sender_uaddr + bytes_copied,
|
||||
copy_size);
|
||||
bytes_copied += copy_size;
|
||||
if (copy_size != bytes_left) {
|
||||
BUG_ON(!pf);
|
||||
/* we stopped at a fixup offset */
|
||||
if (pf->skip_size) {
|
||||
/*
|
||||
* we are just skipping. This is for
|
||||
* BINDER_TYPE_FDA where the translated
|
||||
* fds will be fixed up when we get
|
||||
* to target context.
|
||||
*/
|
||||
bytes_copied += pf->skip_size;
|
||||
} else {
|
||||
/* apply the fixup indicated by pf */
|
||||
if (!ret)
|
||||
ret = binder_alloc_copy_to_buffer(
|
||||
alloc, buffer,
|
||||
pf->offset,
|
||||
&pf->fixup_data,
|
||||
sizeof(pf->fixup_data));
|
||||
bytes_copied += sizeof(pf->fixup_data);
|
||||
}
|
||||
list_del(&pf->node);
|
||||
kfree(pf);
|
||||
pf = list_first_entry_or_null(pf_head,
|
||||
struct binder_ptr_fixup, node);
|
||||
}
|
||||
}
|
||||
list_del(&sgc->node);
|
||||
kfree(sgc);
|
||||
}
|
||||
list_for_each_entry_safe(pf, tmppf, pf_head, node) {
|
||||
BUG_ON(pf->skip_size == 0);
|
||||
list_del(&pf->node);
|
||||
kfree(pf);
|
||||
}
|
||||
BUG_ON(!list_empty(sgc_head));
|
||||
|
||||
return ret > 0 ? -EINVAL : ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* binder_cleanup_deferred_txn_lists() - free specified lists
|
||||
* @sgc_head: list_head of scatter-gather copy list
|
||||
* @pf_head: list_head of pointer fixup list
|
||||
*
|
||||
* Called to clean up @sgc_head and @pf_head if there is an
|
||||
* error.
|
||||
*/
|
||||
static void binder_cleanup_deferred_txn_lists(struct list_head *sgc_head,
|
||||
struct list_head *pf_head)
|
||||
{
|
||||
struct binder_sg_copy *sgc, *tmpsgc;
|
||||
struct binder_ptr_fixup *pf, *tmppf;
|
||||
|
||||
list_for_each_entry_safe(sgc, tmpsgc, sgc_head, node) {
|
||||
list_del(&sgc->node);
|
||||
kfree(sgc);
|
||||
}
|
||||
list_for_each_entry_safe(pf, tmppf, pf_head, node) {
|
||||
list_del(&pf->node);
|
||||
kfree(pf);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* binder_defer_copy() - queue a scatter-gather buffer for copy
|
||||
* @sgc_head: list_head of scatter-gather copy list
|
||||
* @offset: binder buffer offset in target process
|
||||
* @sender_uaddr: user address in source process
|
||||
* @length: bytes to copy
|
||||
*
|
||||
* Specify a scatter-gather block to be copied. The actual copy must
|
||||
* be deferred until all the needed fixups are identified and queued.
|
||||
* Then the copy and fixups are done together so un-translated values
|
||||
* from the source are never visible in the target buffer.
|
||||
*
|
||||
* We are guaranteed that repeated calls to this function will have
|
||||
* monotonically increasing @offset values so the list will naturally
|
||||
* be ordered.
|
||||
*
|
||||
* Return: 0=success, else -errno
|
||||
*/
|
||||
static int binder_defer_copy(struct list_head *sgc_head, binder_size_t offset,
|
||||
const void __user *sender_uaddr, size_t length)
|
||||
{
|
||||
struct binder_sg_copy *bc = kzalloc(sizeof(*bc), GFP_KERNEL);
|
||||
|
||||
if (!bc)
|
||||
return -ENOMEM;
|
||||
|
||||
bc->offset = offset;
|
||||
bc->sender_uaddr = sender_uaddr;
|
||||
bc->length = length;
|
||||
INIT_LIST_HEAD(&bc->node);
|
||||
|
||||
/*
|
||||
* We are guaranteed that the deferred copies are in-order
|
||||
* so just add to the tail.
|
||||
*/
|
||||
list_add_tail(&bc->node, sgc_head);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* binder_add_fixup() - queue a fixup to be applied to sg copy
|
||||
* @pf_head: list_head of binder ptr fixup list
|
||||
* @offset: binder buffer offset in target process
|
||||
* @fixup: bytes to be copied for fixup
|
||||
* @skip_size: bytes to skip when copying (fixup will be applied later)
|
||||
*
|
||||
* Add the specified fixup to a list ordered by @offset. When copying
|
||||
* the scatter-gather buffers, the fixup will be copied instead of
|
||||
* data from the source buffer. For BINDER_TYPE_FDA fixups, the fixup
|
||||
* will be applied later (in target process context), so we just skip
|
||||
* the bytes specified by @skip_size. If @skip_size is 0, we copy the
|
||||
* value in @fixup.
|
||||
*
|
||||
* This function is called *mostly* in @offset order, but there are
|
||||
* exceptions. Since out-of-order inserts are relatively uncommon,
|
||||
* we insert the new element by searching backward from the tail of
|
||||
* the list.
|
||||
*
|
||||
* Return: 0=success, else -errno
|
||||
*/
|
||||
static int binder_add_fixup(struct list_head *pf_head, binder_size_t offset,
|
||||
binder_uintptr_t fixup, size_t skip_size)
|
||||
{
|
||||
struct binder_ptr_fixup *pf = kzalloc(sizeof(*pf), GFP_KERNEL);
|
||||
struct binder_ptr_fixup *tmppf;
|
||||
|
||||
if (!pf)
|
||||
return -ENOMEM;
|
||||
|
||||
pf->offset = offset;
|
||||
pf->fixup_data = fixup;
|
||||
pf->skip_size = skip_size;
|
||||
INIT_LIST_HEAD(&pf->node);
|
||||
|
||||
/* Fixups are *mostly* added in-order, but there are some
|
||||
* exceptions. Look backwards through list for insertion point.
|
||||
*/
|
||||
list_for_each_entry_reverse(tmppf, pf_head, node) {
|
||||
if (tmppf->offset < pf->offset) {
|
||||
list_add(&pf->node, &tmppf->node);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* if we get here, then the new offset is the lowest so
|
||||
* insert at the head
|
||||
*/
|
||||
list_add(&pf->node, pf_head);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int binder_translate_fd_array(struct list_head *pf_head,
|
||||
struct binder_fd_array_object *fda,
|
||||
const void __user *sender_ubuffer,
|
||||
struct binder_buffer_object *parent,
|
||||
struct binder_buffer_object *sender_uparent,
|
||||
struct binder_transaction *t,
|
||||
struct binder_thread *thread,
|
||||
struct binder_transaction *in_reply_to)
|
||||
{
|
||||
binder_size_t fdi, fd_buf_size;
|
||||
binder_size_t fda_offset;
|
||||
const void __user *sender_ufda_base;
|
||||
struct binder_proc *proc = thread->proc;
|
||||
struct binder_proc *target_proc = t->to_proc;
|
||||
int ret;
|
||||
|
||||
if (fda->num_fds == 0)
|
||||
return 0;
|
||||
|
||||
fd_buf_size = sizeof(u32) * fda->num_fds;
|
||||
if (fda->num_fds >= SIZE_MAX / sizeof(u32)) {
|
||||
@@ -2492,19 +2742,25 @@ static int binder_translate_fd_array(struct binder_fd_array_object *fda,
|
||||
*/
|
||||
fda_offset = (parent->buffer - (uintptr_t)t->buffer->user_data) +
|
||||
fda->parent_offset;
|
||||
if (!IS_ALIGNED((unsigned long)fda_offset, sizeof(u32))) {
|
||||
sender_ufda_base = (void __user *)(uintptr_t)sender_uparent->buffer +
|
||||
fda->parent_offset;
|
||||
|
||||
if (!IS_ALIGNED((unsigned long)fda_offset, sizeof(u32)) ||
|
||||
!IS_ALIGNED((unsigned long)sender_ufda_base, sizeof(u32))) {
|
||||
binder_user_error("%d:%d parent offset not aligned correctly.\n",
|
||||
proc->pid, thread->pid);
|
||||
return -EINVAL;
|
||||
}
|
||||
ret = binder_add_fixup(pf_head, fda_offset, 0, fda->num_fds * sizeof(u32));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
for (fdi = 0; fdi < fda->num_fds; fdi++) {
|
||||
u32 fd;
|
||||
int ret;
|
||||
binder_size_t offset = fda_offset + fdi * sizeof(fd);
|
||||
binder_size_t sender_uoffset = fdi * sizeof(fd);
|
||||
|
||||
ret = binder_alloc_copy_from_buffer(&target_proc->alloc,
|
||||
&fd, t->buffer,
|
||||
offset, sizeof(fd));
|
||||
ret = copy_from_user(&fd, sender_ufda_base + sender_uoffset, sizeof(fd));
|
||||
if (!ret)
|
||||
ret = binder_translate_fd(fd, offset, t, thread,
|
||||
in_reply_to);
|
||||
@@ -2514,7 +2770,8 @@ static int binder_translate_fd_array(struct binder_fd_array_object *fda,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int binder_fixup_parent(struct binder_transaction *t,
|
||||
static int binder_fixup_parent(struct list_head *pf_head,
|
||||
struct binder_transaction *t,
|
||||
struct binder_thread *thread,
|
||||
struct binder_buffer_object *bp,
|
||||
binder_size_t off_start_offset,
|
||||
@@ -2560,14 +2817,7 @@ static int binder_fixup_parent(struct binder_transaction *t,
|
||||
}
|
||||
buffer_offset = bp->parent_offset +
|
||||
(uintptr_t)parent->buffer - (uintptr_t)b->user_data;
|
||||
if (binder_alloc_copy_to_buffer(&target_proc->alloc, b, buffer_offset,
|
||||
&bp->buffer, sizeof(bp->buffer))) {
|
||||
binder_user_error("%d:%d got transaction with invalid parent offset\n",
|
||||
proc->pid, thread->pid);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return binder_add_fixup(pf_head, buffer_offset, bp->buffer, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2799,10 +3049,15 @@ static void binder_transaction(struct binder_proc *proc,
|
||||
int t_debug_id = atomic_inc_return(&binder_last_id);
|
||||
char *secctx = NULL;
|
||||
u32 secctx_sz = 0;
|
||||
struct list_head sgc_head;
|
||||
struct list_head pf_head;
|
||||
const void __user *user_buffer = (const void __user *)
|
||||
(uintptr_t)tr->data.ptr.buffer;
|
||||
bool is_nested = false;
|
||||
|
||||
INIT_LIST_HEAD(&sgc_head);
|
||||
INIT_LIST_HEAD(&pf_head);
|
||||
|
||||
e = binder_transaction_log_add(&binder_transaction_log);
|
||||
e->debug_id = t_debug_id;
|
||||
e->call_type = reply ? 2 : !!(tr->flags & TF_ONE_WAY);
|
||||
@@ -3281,6 +3536,8 @@ static void binder_transaction(struct binder_proc *proc,
|
||||
case BINDER_TYPE_FDA: {
|
||||
struct binder_object ptr_object;
|
||||
binder_size_t parent_offset;
|
||||
struct binder_object user_object;
|
||||
size_t user_parent_size;
|
||||
struct binder_fd_array_object *fda =
|
||||
to_binder_fd_array_object(hdr);
|
||||
size_t num_valid = (buffer_offset - off_start_offset) /
|
||||
@@ -3312,8 +3569,27 @@ static void binder_transaction(struct binder_proc *proc,
|
||||
return_error_line = __LINE__;
|
||||
goto err_bad_parent;
|
||||
}
|
||||
ret = binder_translate_fd_array(fda, parent, t, thread,
|
||||
in_reply_to);
|
||||
/*
|
||||
* We need to read the user version of the parent
|
||||
* object to get the original user offset
|
||||
*/
|
||||
user_parent_size =
|
||||
binder_get_object(proc, user_buffer, t->buffer,
|
||||
parent_offset, &user_object);
|
||||
if (user_parent_size != sizeof(user_object.bbo)) {
|
||||
binder_user_error("%d:%d invalid ptr object size: %zd vs %zd\n",
|
||||
proc->pid, thread->pid,
|
||||
user_parent_size,
|
||||
sizeof(user_object.bbo));
|
||||
return_error = BR_FAILED_REPLY;
|
||||
return_error_param = -EINVAL;
|
||||
return_error_line = __LINE__;
|
||||
goto err_bad_parent;
|
||||
}
|
||||
ret = binder_translate_fd_array(&pf_head, fda,
|
||||
user_buffer, parent,
|
||||
&user_object.bbo, t,
|
||||
thread, in_reply_to);
|
||||
if (!ret)
|
||||
ret = binder_alloc_copy_to_buffer(&target_proc->alloc,
|
||||
t->buffer,
|
||||
@@ -3343,19 +3619,14 @@ static void binder_transaction(struct binder_proc *proc,
|
||||
return_error_line = __LINE__;
|
||||
goto err_bad_offset;
|
||||
}
|
||||
if (binder_alloc_copy_user_to_buffer(
|
||||
&target_proc->alloc,
|
||||
t->buffer,
|
||||
sg_buf_offset,
|
||||
(const void __user *)
|
||||
(uintptr_t)bp->buffer,
|
||||
bp->length)) {
|
||||
binder_user_error("%d:%d got transaction with invalid offsets ptr\n",
|
||||
proc->pid, thread->pid);
|
||||
return_error_param = -EFAULT;
|
||||
ret = binder_defer_copy(&sgc_head, sg_buf_offset,
|
||||
(const void __user *)(uintptr_t)bp->buffer,
|
||||
bp->length);
|
||||
if (ret) {
|
||||
return_error = BR_FAILED_REPLY;
|
||||
return_error_param = ret;
|
||||
return_error_line = __LINE__;
|
||||
goto err_copy_data_failed;
|
||||
goto err_translate_failed;
|
||||
}
|
||||
/* Fixup buffer pointer to target proc address space */
|
||||
bp->buffer = (uintptr_t)
|
||||
@@ -3364,7 +3635,8 @@ static void binder_transaction(struct binder_proc *proc,
|
||||
|
||||
num_valid = (buffer_offset - off_start_offset) /
|
||||
sizeof(binder_size_t);
|
||||
ret = binder_fixup_parent(t, thread, bp,
|
||||
ret = binder_fixup_parent(&pf_head, t,
|
||||
thread, bp,
|
||||
off_start_offset,
|
||||
num_valid,
|
||||
last_fixup_obj_off,
|
||||
@@ -3404,6 +3676,17 @@ static void binder_transaction(struct binder_proc *proc,
|
||||
return_error_line = __LINE__;
|
||||
goto err_copy_data_failed;
|
||||
}
|
||||
|
||||
ret = binder_do_deferred_txn_copies(&target_proc->alloc, t->buffer,
|
||||
&sgc_head, &pf_head);
|
||||
if (ret) {
|
||||
binder_user_error("%d:%d got transaction with invalid offsets ptr\n",
|
||||
proc->pid, thread->pid);
|
||||
return_error = BR_FAILED_REPLY;
|
||||
return_error_param = ret;
|
||||
return_error_line = __LINE__;
|
||||
goto err_copy_data_failed;
|
||||
}
|
||||
if (t->buffer->oneway_spam_suspect)
|
||||
tcomplete->type = BINDER_WORK_TRANSACTION_ONEWAY_SPAM_SUSPECT;
|
||||
else
|
||||
@@ -3485,6 +3768,7 @@ static void binder_transaction(struct binder_proc *proc,
|
||||
err_bad_offset:
|
||||
err_bad_parent:
|
||||
err_copy_data_failed:
|
||||
binder_cleanup_deferred_txn_lists(&sgc_head, &pf_head);
|
||||
binder_free_txn_fixups(t);
|
||||
trace_binder_transaction_failed_buffer_release(t->buffer);
|
||||
binder_transaction_buffer_release(target_proc, NULL, t->buffer,
|
||||
|
||||
@@ -1756,17 +1756,7 @@ static struct nbd_device *nbd_dev_add(int index, unsigned int refs)
|
||||
refcount_set(&nbd->refs, 0);
|
||||
INIT_LIST_HEAD(&nbd->list);
|
||||
disk->major = NBD_MAJOR;
|
||||
|
||||
/* Too big first_minor can cause duplicate creation of
|
||||
* sysfs files/links, since index << part_shift might overflow, or
|
||||
* MKDEV() expect that the max bits of first_minor is 20.
|
||||
*/
|
||||
disk->first_minor = index << part_shift;
|
||||
if (disk->first_minor < index || disk->first_minor > MINORMASK) {
|
||||
err = -EINVAL;
|
||||
goto out_free_work;
|
||||
}
|
||||
|
||||
disk->minors = 1 << part_shift;
|
||||
disk->fops = &nbd_fops;
|
||||
disk->private_data = nbd;
|
||||
@@ -1871,8 +1861,19 @@ static int nbd_genl_connect(struct sk_buff *skb, struct genl_info *info)
|
||||
if (!netlink_capable(skb, CAP_SYS_ADMIN))
|
||||
return -EPERM;
|
||||
|
||||
if (info->attrs[NBD_ATTR_INDEX])
|
||||
if (info->attrs[NBD_ATTR_INDEX]) {
|
||||
index = nla_get_u32(info->attrs[NBD_ATTR_INDEX]);
|
||||
|
||||
/*
|
||||
* Too big first_minor can cause duplicate creation of
|
||||
* sysfs files/links, since index << part_shift might overflow, or
|
||||
* MKDEV() expect that the max bits of first_minor is 20.
|
||||
*/
|
||||
if (index < 0 || index > MINORMASK >> part_shift) {
|
||||
printk(KERN_ERR "nbd: illegal input index %d\n", index);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
if (!info->attrs[NBD_ATTR_SOCKETS]) {
|
||||
printk(KERN_ERR "nbd: must specify at least one socket\n");
|
||||
return -EINVAL;
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
config CLK_LGM_CGU
|
||||
depends on OF && HAS_IOMEM && (X86 || COMPILE_TEST)
|
||||
select MFD_SYSCON
|
||||
select OF_EARLY_FLATTREE
|
||||
bool "Clock driver for Lightning Mountain(LGM) platform"
|
||||
help
|
||||
Clock Generation Unit(CGU) driver for Intel Lightning Mountain(LGM)
|
||||
network processor SoC.
|
||||
Clock Generation Unit(CGU) driver for MaxLinear's x86 based
|
||||
Lightning Mountain(LGM) network processor SoC.
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2020-2022 MaxLinear, Inc.
|
||||
* Copyright (C) 2020 Intel Corporation.
|
||||
* Zhu YiXin <yixin.zhu@intel.com>
|
||||
* Rahul Tanwar <rahul.tanwar@intel.com>
|
||||
* Zhu Yixin <yzhu@maxlinear.com>
|
||||
* Rahul Tanwar <rtanwar@maxlinear.com>
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
@@ -40,13 +41,10 @@ static unsigned long lgm_pll_recalc_rate(struct clk_hw *hw, unsigned long prate)
|
||||
{
|
||||
struct lgm_clk_pll *pll = to_lgm_clk_pll(hw);
|
||||
unsigned int div, mult, frac;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&pll->lock, flags);
|
||||
mult = lgm_get_clk_val(pll->membase, PLL_REF_DIV(pll->reg), 0, 12);
|
||||
div = lgm_get_clk_val(pll->membase, PLL_REF_DIV(pll->reg), 18, 6);
|
||||
frac = lgm_get_clk_val(pll->membase, pll->reg, 2, 24);
|
||||
spin_unlock_irqrestore(&pll->lock, flags);
|
||||
|
||||
if (pll->type == TYPE_LJPLL)
|
||||
div *= 4;
|
||||
@@ -57,12 +55,9 @@ static unsigned long lgm_pll_recalc_rate(struct clk_hw *hw, unsigned long prate)
|
||||
static int lgm_pll_is_enabled(struct clk_hw *hw)
|
||||
{
|
||||
struct lgm_clk_pll *pll = to_lgm_clk_pll(hw);
|
||||
unsigned long flags;
|
||||
unsigned int ret;
|
||||
|
||||
spin_lock_irqsave(&pll->lock, flags);
|
||||
ret = lgm_get_clk_val(pll->membase, pll->reg, 0, 1);
|
||||
spin_unlock_irqrestore(&pll->lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -70,15 +65,13 @@ static int lgm_pll_is_enabled(struct clk_hw *hw)
|
||||
static int lgm_pll_enable(struct clk_hw *hw)
|
||||
{
|
||||
struct lgm_clk_pll *pll = to_lgm_clk_pll(hw);
|
||||
unsigned long flags;
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
spin_lock_irqsave(&pll->lock, flags);
|
||||
lgm_set_clk_val(pll->membase, pll->reg, 0, 1, 1);
|
||||
ret = readl_poll_timeout_atomic(pll->membase + pll->reg,
|
||||
val, (val & 0x1), 1, 100);
|
||||
spin_unlock_irqrestore(&pll->lock, flags);
|
||||
ret = regmap_read_poll_timeout_atomic(pll->membase, pll->reg,
|
||||
val, (val & 0x1), 1, 100);
|
||||
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -86,11 +79,8 @@ static int lgm_pll_enable(struct clk_hw *hw)
|
||||
static void lgm_pll_disable(struct clk_hw *hw)
|
||||
{
|
||||
struct lgm_clk_pll *pll = to_lgm_clk_pll(hw);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&pll->lock, flags);
|
||||
lgm_set_clk_val(pll->membase, pll->reg, 0, 1, 0);
|
||||
spin_unlock_irqrestore(&pll->lock, flags);
|
||||
}
|
||||
|
||||
static const struct clk_ops lgm_pll_ops = {
|
||||
@@ -121,7 +111,6 @@ lgm_clk_register_pll(struct lgm_clk_provider *ctx,
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
pll->membase = ctx->membase;
|
||||
pll->lock = ctx->lock;
|
||||
pll->reg = list->reg;
|
||||
pll->flags = list->flags;
|
||||
pll->type = list->type;
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2020-2022 MaxLinear, Inc.
|
||||
* Copyright (C) 2020 Intel Corporation.
|
||||
* Zhu YiXin <yixin.zhu@intel.com>
|
||||
* Rahul Tanwar <rahul.tanwar@intel.com>
|
||||
* Zhu Yixin <yzhu@maxlinear.com>
|
||||
* Rahul Tanwar <rtanwar@maxlinear.com>
|
||||
*/
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/device.h>
|
||||
@@ -24,14 +25,10 @@
|
||||
static struct clk_hw *lgm_clk_register_fixed(struct lgm_clk_provider *ctx,
|
||||
const struct lgm_clk_branch *list)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (list->div_flags & CLOCK_FLAG_VAL_INIT) {
|
||||
spin_lock_irqsave(&ctx->lock, flags);
|
||||
if (list->div_flags & CLOCK_FLAG_VAL_INIT)
|
||||
lgm_set_clk_val(ctx->membase, list->div_off, list->div_shift,
|
||||
list->div_width, list->div_val);
|
||||
spin_unlock_irqrestore(&ctx->lock, flags);
|
||||
}
|
||||
|
||||
return clk_hw_register_fixed_rate(NULL, list->name,
|
||||
list->parent_data[0].name,
|
||||
@@ -41,33 +38,27 @@ static struct clk_hw *lgm_clk_register_fixed(struct lgm_clk_provider *ctx,
|
||||
static u8 lgm_clk_mux_get_parent(struct clk_hw *hw)
|
||||
{
|
||||
struct lgm_clk_mux *mux = to_lgm_clk_mux(hw);
|
||||
unsigned long flags;
|
||||
u32 val;
|
||||
|
||||
spin_lock_irqsave(&mux->lock, flags);
|
||||
if (mux->flags & MUX_CLK_SW)
|
||||
val = mux->reg;
|
||||
else
|
||||
val = lgm_get_clk_val(mux->membase, mux->reg, mux->shift,
|
||||
mux->width);
|
||||
spin_unlock_irqrestore(&mux->lock, flags);
|
||||
return clk_mux_val_to_index(hw, NULL, mux->flags, val);
|
||||
}
|
||||
|
||||
static int lgm_clk_mux_set_parent(struct clk_hw *hw, u8 index)
|
||||
{
|
||||
struct lgm_clk_mux *mux = to_lgm_clk_mux(hw);
|
||||
unsigned long flags;
|
||||
u32 val;
|
||||
|
||||
val = clk_mux_index_to_val(NULL, mux->flags, index);
|
||||
spin_lock_irqsave(&mux->lock, flags);
|
||||
if (mux->flags & MUX_CLK_SW)
|
||||
mux->reg = val;
|
||||
else
|
||||
lgm_set_clk_val(mux->membase, mux->reg, mux->shift,
|
||||
mux->width, val);
|
||||
spin_unlock_irqrestore(&mux->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -90,7 +81,7 @@ static struct clk_hw *
|
||||
lgm_clk_register_mux(struct lgm_clk_provider *ctx,
|
||||
const struct lgm_clk_branch *list)
|
||||
{
|
||||
unsigned long flags, cflags = list->mux_flags;
|
||||
unsigned long cflags = list->mux_flags;
|
||||
struct device *dev = ctx->dev;
|
||||
u8 shift = list->mux_shift;
|
||||
u8 width = list->mux_width;
|
||||
@@ -111,7 +102,6 @@ lgm_clk_register_mux(struct lgm_clk_provider *ctx,
|
||||
init.num_parents = list->num_parents;
|
||||
|
||||
mux->membase = ctx->membase;
|
||||
mux->lock = ctx->lock;
|
||||
mux->reg = reg;
|
||||
mux->shift = shift;
|
||||
mux->width = width;
|
||||
@@ -123,11 +113,8 @@ lgm_clk_register_mux(struct lgm_clk_provider *ctx,
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
if (cflags & CLOCK_FLAG_VAL_INIT) {
|
||||
spin_lock_irqsave(&mux->lock, flags);
|
||||
if (cflags & CLOCK_FLAG_VAL_INIT)
|
||||
lgm_set_clk_val(mux->membase, reg, shift, width, list->mux_val);
|
||||
spin_unlock_irqrestore(&mux->lock, flags);
|
||||
}
|
||||
|
||||
return hw;
|
||||
}
|
||||
@@ -136,13 +123,10 @@ static unsigned long
|
||||
lgm_clk_divider_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
|
||||
{
|
||||
struct lgm_clk_divider *divider = to_lgm_clk_divider(hw);
|
||||
unsigned long flags;
|
||||
unsigned int val;
|
||||
|
||||
spin_lock_irqsave(÷r->lock, flags);
|
||||
val = lgm_get_clk_val(divider->membase, divider->reg,
|
||||
divider->shift, divider->width);
|
||||
spin_unlock_irqrestore(÷r->lock, flags);
|
||||
|
||||
return divider_recalc_rate(hw, parent_rate, val, divider->table,
|
||||
divider->flags, divider->width);
|
||||
@@ -163,7 +147,6 @@ lgm_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long prate)
|
||||
{
|
||||
struct lgm_clk_divider *divider = to_lgm_clk_divider(hw);
|
||||
unsigned long flags;
|
||||
int value;
|
||||
|
||||
value = divider_get_val(rate, prate, divider->table,
|
||||
@@ -171,10 +154,8 @@ lgm_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
if (value < 0)
|
||||
return value;
|
||||
|
||||
spin_lock_irqsave(÷r->lock, flags);
|
||||
lgm_set_clk_val(divider->membase, divider->reg,
|
||||
divider->shift, divider->width, value);
|
||||
spin_unlock_irqrestore(÷r->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -182,12 +163,10 @@ lgm_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
static int lgm_clk_divider_enable_disable(struct clk_hw *hw, int enable)
|
||||
{
|
||||
struct lgm_clk_divider *div = to_lgm_clk_divider(hw);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&div->lock, flags);
|
||||
lgm_set_clk_val(div->membase, div->reg, div->shift_gate,
|
||||
div->width_gate, enable);
|
||||
spin_unlock_irqrestore(&div->lock, flags);
|
||||
if (div->flags != DIV_CLK_NO_MASK)
|
||||
lgm_set_clk_val(div->membase, div->reg, div->shift_gate,
|
||||
div->width_gate, enable);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -213,7 +192,7 @@ static struct clk_hw *
|
||||
lgm_clk_register_divider(struct lgm_clk_provider *ctx,
|
||||
const struct lgm_clk_branch *list)
|
||||
{
|
||||
unsigned long flags, cflags = list->div_flags;
|
||||
unsigned long cflags = list->div_flags;
|
||||
struct device *dev = ctx->dev;
|
||||
struct lgm_clk_divider *div;
|
||||
struct clk_init_data init = {};
|
||||
@@ -236,7 +215,6 @@ lgm_clk_register_divider(struct lgm_clk_provider *ctx,
|
||||
init.num_parents = 1;
|
||||
|
||||
div->membase = ctx->membase;
|
||||
div->lock = ctx->lock;
|
||||
div->reg = reg;
|
||||
div->shift = shift;
|
||||
div->width = width;
|
||||
@@ -251,11 +229,8 @@ lgm_clk_register_divider(struct lgm_clk_provider *ctx,
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
if (cflags & CLOCK_FLAG_VAL_INIT) {
|
||||
spin_lock_irqsave(&div->lock, flags);
|
||||
if (cflags & CLOCK_FLAG_VAL_INIT)
|
||||
lgm_set_clk_val(div->membase, reg, shift, width, list->div_val);
|
||||
spin_unlock_irqrestore(&div->lock, flags);
|
||||
}
|
||||
|
||||
return hw;
|
||||
}
|
||||
@@ -264,7 +239,6 @@ static struct clk_hw *
|
||||
lgm_clk_register_fixed_factor(struct lgm_clk_provider *ctx,
|
||||
const struct lgm_clk_branch *list)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct clk_hw *hw;
|
||||
|
||||
hw = clk_hw_register_fixed_factor(ctx->dev, list->name,
|
||||
@@ -273,12 +247,9 @@ lgm_clk_register_fixed_factor(struct lgm_clk_provider *ctx,
|
||||
if (IS_ERR(hw))
|
||||
return ERR_CAST(hw);
|
||||
|
||||
if (list->div_flags & CLOCK_FLAG_VAL_INIT) {
|
||||
spin_lock_irqsave(&ctx->lock, flags);
|
||||
if (list->div_flags & CLOCK_FLAG_VAL_INIT)
|
||||
lgm_set_clk_val(ctx->membase, list->div_off, list->div_shift,
|
||||
list->div_width, list->div_val);
|
||||
spin_unlock_irqrestore(&ctx->lock, flags);
|
||||
}
|
||||
|
||||
return hw;
|
||||
}
|
||||
@@ -286,13 +257,10 @@ lgm_clk_register_fixed_factor(struct lgm_clk_provider *ctx,
|
||||
static int lgm_clk_gate_enable(struct clk_hw *hw)
|
||||
{
|
||||
struct lgm_clk_gate *gate = to_lgm_clk_gate(hw);
|
||||
unsigned long flags;
|
||||
unsigned int reg;
|
||||
|
||||
spin_lock_irqsave(&gate->lock, flags);
|
||||
reg = GATE_HW_REG_EN(gate->reg);
|
||||
lgm_set_clk_val(gate->membase, reg, gate->shift, 1, 1);
|
||||
spin_unlock_irqrestore(&gate->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -300,25 +268,19 @@ static int lgm_clk_gate_enable(struct clk_hw *hw)
|
||||
static void lgm_clk_gate_disable(struct clk_hw *hw)
|
||||
{
|
||||
struct lgm_clk_gate *gate = to_lgm_clk_gate(hw);
|
||||
unsigned long flags;
|
||||
unsigned int reg;
|
||||
|
||||
spin_lock_irqsave(&gate->lock, flags);
|
||||
reg = GATE_HW_REG_DIS(gate->reg);
|
||||
lgm_set_clk_val(gate->membase, reg, gate->shift, 1, 1);
|
||||
spin_unlock_irqrestore(&gate->lock, flags);
|
||||
}
|
||||
|
||||
static int lgm_clk_gate_is_enabled(struct clk_hw *hw)
|
||||
{
|
||||
struct lgm_clk_gate *gate = to_lgm_clk_gate(hw);
|
||||
unsigned int reg, ret;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&gate->lock, flags);
|
||||
reg = GATE_HW_REG_STAT(gate->reg);
|
||||
ret = lgm_get_clk_val(gate->membase, reg, gate->shift, 1);
|
||||
spin_unlock_irqrestore(&gate->lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -333,7 +295,7 @@ static struct clk_hw *
|
||||
lgm_clk_register_gate(struct lgm_clk_provider *ctx,
|
||||
const struct lgm_clk_branch *list)
|
||||
{
|
||||
unsigned long flags, cflags = list->gate_flags;
|
||||
unsigned long cflags = list->gate_flags;
|
||||
const char *pname = list->parent_data[0].name;
|
||||
struct device *dev = ctx->dev;
|
||||
u8 shift = list->gate_shift;
|
||||
@@ -354,7 +316,6 @@ lgm_clk_register_gate(struct lgm_clk_provider *ctx,
|
||||
init.num_parents = pname ? 1 : 0;
|
||||
|
||||
gate->membase = ctx->membase;
|
||||
gate->lock = ctx->lock;
|
||||
gate->reg = reg;
|
||||
gate->shift = shift;
|
||||
gate->flags = cflags;
|
||||
@@ -366,9 +327,7 @@ lgm_clk_register_gate(struct lgm_clk_provider *ctx,
|
||||
return ERR_PTR(ret);
|
||||
|
||||
if (cflags & CLOCK_FLAG_VAL_INIT) {
|
||||
spin_lock_irqsave(&gate->lock, flags);
|
||||
lgm_set_clk_val(gate->membase, reg, shift, 1, list->gate_val);
|
||||
spin_unlock_irqrestore(&gate->lock, flags);
|
||||
}
|
||||
|
||||
return hw;
|
||||
@@ -396,8 +355,22 @@ int lgm_clk_register_branches(struct lgm_clk_provider *ctx,
|
||||
hw = lgm_clk_register_fixed_factor(ctx, list);
|
||||
break;
|
||||
case CLK_TYPE_GATE:
|
||||
hw = lgm_clk_register_gate(ctx, list);
|
||||
if (list->gate_flags & GATE_CLK_HW) {
|
||||
hw = lgm_clk_register_gate(ctx, list);
|
||||
} else {
|
||||
/*
|
||||
* GATE_CLKs can be controlled either from
|
||||
* CGU clk driver i.e. this driver or directly
|
||||
* from power management driver/daemon. It is
|
||||
* dependent on the power policy/profile requirements
|
||||
* of the end product. To override control of gate
|
||||
* clks from this driver, provide NULL for this index
|
||||
* of gate clk provider.
|
||||
*/
|
||||
hw = NULL;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_err(ctx->dev, "invalid clk type\n");
|
||||
return -EINVAL;
|
||||
@@ -443,24 +416,18 @@ lgm_clk_ddiv_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
|
||||
static int lgm_clk_ddiv_enable(struct clk_hw *hw)
|
||||
{
|
||||
struct lgm_clk_ddiv *ddiv = to_lgm_clk_ddiv(hw);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&ddiv->lock, flags);
|
||||
lgm_set_clk_val(ddiv->membase, ddiv->reg, ddiv->shift_gate,
|
||||
ddiv->width_gate, 1);
|
||||
spin_unlock_irqrestore(&ddiv->lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void lgm_clk_ddiv_disable(struct clk_hw *hw)
|
||||
{
|
||||
struct lgm_clk_ddiv *ddiv = to_lgm_clk_ddiv(hw);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&ddiv->lock, flags);
|
||||
lgm_set_clk_val(ddiv->membase, ddiv->reg, ddiv->shift_gate,
|
||||
ddiv->width_gate, 0);
|
||||
spin_unlock_irqrestore(&ddiv->lock, flags);
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -497,32 +464,25 @@ lgm_clk_ddiv_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
{
|
||||
struct lgm_clk_ddiv *ddiv = to_lgm_clk_ddiv(hw);
|
||||
u32 div, ddiv1, ddiv2;
|
||||
unsigned long flags;
|
||||
|
||||
div = DIV_ROUND_CLOSEST_ULL((u64)prate, rate);
|
||||
|
||||
spin_lock_irqsave(&ddiv->lock, flags);
|
||||
if (lgm_get_clk_val(ddiv->membase, ddiv->reg, ddiv->shift2, 1)) {
|
||||
div = DIV_ROUND_CLOSEST_ULL((u64)div, 5);
|
||||
div = div * 2;
|
||||
}
|
||||
|
||||
if (div <= 0) {
|
||||
spin_unlock_irqrestore(&ddiv->lock, flags);
|
||||
if (div <= 0)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (lgm_clk_get_ddiv_val(div, &ddiv1, &ddiv2)) {
|
||||
spin_unlock_irqrestore(&ddiv->lock, flags);
|
||||
if (lgm_clk_get_ddiv_val(div, &ddiv1, &ddiv2))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
lgm_set_clk_val(ddiv->membase, ddiv->reg, ddiv->shift0, ddiv->width0,
|
||||
ddiv1 - 1);
|
||||
|
||||
lgm_set_clk_val(ddiv->membase, ddiv->reg, ddiv->shift1, ddiv->width1,
|
||||
ddiv2 - 1);
|
||||
spin_unlock_irqrestore(&ddiv->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -533,18 +493,15 @@ lgm_clk_ddiv_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
{
|
||||
struct lgm_clk_ddiv *ddiv = to_lgm_clk_ddiv(hw);
|
||||
u32 div, ddiv1, ddiv2;
|
||||
unsigned long flags;
|
||||
u64 rate64;
|
||||
|
||||
div = DIV_ROUND_CLOSEST_ULL((u64)*prate, rate);
|
||||
|
||||
/* if predivide bit is enabled, modify div by factor of 2.5 */
|
||||
spin_lock_irqsave(&ddiv->lock, flags);
|
||||
if (lgm_get_clk_val(ddiv->membase, ddiv->reg, ddiv->shift2, 1)) {
|
||||
div = div * 2;
|
||||
div = DIV_ROUND_CLOSEST_ULL((u64)div, 5);
|
||||
}
|
||||
spin_unlock_irqrestore(&ddiv->lock, flags);
|
||||
|
||||
if (div <= 0)
|
||||
return *prate;
|
||||
@@ -558,12 +515,10 @@ lgm_clk_ddiv_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
do_div(rate64, ddiv2);
|
||||
|
||||
/* if predivide bit is enabled, modify rounded rate by factor of 2.5 */
|
||||
spin_lock_irqsave(&ddiv->lock, flags);
|
||||
if (lgm_get_clk_val(ddiv->membase, ddiv->reg, ddiv->shift2, 1)) {
|
||||
rate64 = rate64 * 2;
|
||||
rate64 = DIV_ROUND_CLOSEST_ULL(rate64, 5);
|
||||
}
|
||||
spin_unlock_irqrestore(&ddiv->lock, flags);
|
||||
|
||||
return rate64;
|
||||
}
|
||||
@@ -600,7 +555,6 @@ int lgm_clk_register_ddiv(struct lgm_clk_provider *ctx,
|
||||
init.num_parents = 1;
|
||||
|
||||
ddiv->membase = ctx->membase;
|
||||
ddiv->lock = ctx->lock;
|
||||
ddiv->reg = list->reg;
|
||||
ddiv->shift0 = list->shift0;
|
||||
ddiv->width0 = list->width0;
|
||||
|
||||
@@ -1,28 +1,28 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright(c) 2020 Intel Corporation.
|
||||
* Zhu YiXin <yixin.zhu@intel.com>
|
||||
* Rahul Tanwar <rahul.tanwar@intel.com>
|
||||
* Copyright (C) 2020-2022 MaxLinear, Inc.
|
||||
* Copyright (C) 2020 Intel Corporation.
|
||||
* Zhu Yixin <yzhu@maxlinear.com>
|
||||
* Rahul Tanwar <rtanwar@maxlinear.com>
|
||||
*/
|
||||
|
||||
#ifndef __CLK_CGU_H
|
||||
#define __CLK_CGU_H
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
struct lgm_clk_mux {
|
||||
struct clk_hw hw;
|
||||
void __iomem *membase;
|
||||
struct regmap *membase;
|
||||
unsigned int reg;
|
||||
u8 shift;
|
||||
u8 width;
|
||||
unsigned long flags;
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
struct lgm_clk_divider {
|
||||
struct clk_hw hw;
|
||||
void __iomem *membase;
|
||||
struct regmap *membase;
|
||||
unsigned int reg;
|
||||
u8 shift;
|
||||
u8 width;
|
||||
@@ -30,12 +30,11 @@ struct lgm_clk_divider {
|
||||
u8 width_gate;
|
||||
unsigned long flags;
|
||||
const struct clk_div_table *table;
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
struct lgm_clk_ddiv {
|
||||
struct clk_hw hw;
|
||||
void __iomem *membase;
|
||||
struct regmap *membase;
|
||||
unsigned int reg;
|
||||
u8 shift0;
|
||||
u8 width0;
|
||||
@@ -48,16 +47,14 @@ struct lgm_clk_ddiv {
|
||||
unsigned int mult;
|
||||
unsigned int div;
|
||||
unsigned long flags;
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
struct lgm_clk_gate {
|
||||
struct clk_hw hw;
|
||||
void __iomem *membase;
|
||||
struct regmap *membase;
|
||||
unsigned int reg;
|
||||
u8 shift;
|
||||
unsigned long flags;
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
enum lgm_clk_type {
|
||||
@@ -77,11 +74,10 @@ enum lgm_clk_type {
|
||||
* @clk_data: array of hw clocks and clk number.
|
||||
*/
|
||||
struct lgm_clk_provider {
|
||||
void __iomem *membase;
|
||||
struct regmap *membase;
|
||||
struct device_node *np;
|
||||
struct device *dev;
|
||||
struct clk_hw_onecell_data clk_data;
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
enum pll_type {
|
||||
@@ -92,11 +88,10 @@ enum pll_type {
|
||||
|
||||
struct lgm_clk_pll {
|
||||
struct clk_hw hw;
|
||||
void __iomem *membase;
|
||||
struct regmap *membase;
|
||||
unsigned int reg;
|
||||
unsigned long flags;
|
||||
enum pll_type type;
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -202,6 +197,8 @@ struct lgm_clk_branch {
|
||||
/* clock flags definition */
|
||||
#define CLOCK_FLAG_VAL_INIT BIT(16)
|
||||
#define MUX_CLK_SW BIT(17)
|
||||
#define GATE_CLK_HW BIT(18)
|
||||
#define DIV_CLK_NO_MASK BIT(19)
|
||||
|
||||
#define LGM_MUX(_id, _name, _pdata, _f, _reg, \
|
||||
_shift, _width, _cf, _v) \
|
||||
@@ -300,29 +297,32 @@ struct lgm_clk_branch {
|
||||
.div = _d, \
|
||||
}
|
||||
|
||||
static inline void lgm_set_clk_val(void __iomem *membase, u32 reg,
|
||||
static inline void lgm_set_clk_val(struct regmap *membase, u32 reg,
|
||||
u8 shift, u8 width, u32 set_val)
|
||||
{
|
||||
u32 mask = (GENMASK(width - 1, 0) << shift);
|
||||
u32 regval;
|
||||
|
||||
regval = readl(membase + reg);
|
||||
regval = (regval & ~mask) | ((set_val << shift) & mask);
|
||||
writel(regval, membase + reg);
|
||||
regmap_update_bits(membase, reg, mask, set_val << shift);
|
||||
}
|
||||
|
||||
static inline u32 lgm_get_clk_val(void __iomem *membase, u32 reg,
|
||||
static inline u32 lgm_get_clk_val(struct regmap *membase, u32 reg,
|
||||
u8 shift, u8 width)
|
||||
{
|
||||
u32 mask = (GENMASK(width - 1, 0) << shift);
|
||||
u32 val;
|
||||
|
||||
val = readl(membase + reg);
|
||||
if (regmap_read(membase, reg, &val)) {
|
||||
WARN_ONCE(1, "Failed to read clk reg: 0x%x\n", reg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
val = (val & mask) >> shift;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int lgm_clk_register_branches(struct lgm_clk_provider *ctx,
|
||||
const struct lgm_clk_branch *list,
|
||||
unsigned int nr_clk);
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2020-2022 MaxLinear, Inc.
|
||||
* Copyright (C) 2020 Intel Corporation.
|
||||
* Zhu YiXin <yixin.zhu@intel.com>
|
||||
* Rahul Tanwar <rahul.tanwar@intel.com>
|
||||
* Zhu Yixin <yzhu@maxlinear.com>
|
||||
* Rahul Tanwar <rtanwar@maxlinear.com>
|
||||
*/
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <dt-bindings/clock/intel,lgm-clk.h>
|
||||
@@ -253,8 +255,8 @@ static const struct lgm_clk_branch lgm_branch_clks[] = {
|
||||
LGM_FIXED(LGM_CLK_SLIC, "slic", NULL, 0, CGU_IF_CLK1,
|
||||
8, 2, CLOCK_FLAG_VAL_INIT, 8192000, 2),
|
||||
LGM_FIXED(LGM_CLK_DOCSIS, "v_docsis", NULL, 0, 0, 0, 0, 0, 16000000, 0),
|
||||
LGM_DIV(LGM_CLK_DCL, "dcl", "v_ifclk", 0, CGU_PCMCR,
|
||||
25, 3, 0, 0, 0, 0, dcl_div),
|
||||
LGM_DIV(LGM_CLK_DCL, "dcl", "v_ifclk", CLK_SET_RATE_PARENT, CGU_PCMCR,
|
||||
25, 3, 0, 0, DIV_CLK_NO_MASK, 0, dcl_div),
|
||||
LGM_MUX(LGM_CLK_PCM, "pcm", pcm_p, 0, CGU_C55_PCMCR,
|
||||
0, 1, CLK_MUX_ROUND_CLOSEST, 0),
|
||||
LGM_FIXED_FACTOR(LGM_CLK_DDR_PHY, "ddr_phy", "ddr",
|
||||
@@ -433,13 +435,15 @@ static int lgm_cgu_probe(struct platform_device *pdev)
|
||||
|
||||
ctx->clk_data.num = CLK_NR_CLKS;
|
||||
|
||||
ctx->membase = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(ctx->membase))
|
||||
ctx->membase = syscon_node_to_regmap(np);
|
||||
if (IS_ERR(ctx->membase)) {
|
||||
dev_err(dev, "Failed to get clk CGU iomem\n");
|
||||
return PTR_ERR(ctx->membase);
|
||||
}
|
||||
|
||||
|
||||
ctx->np = np;
|
||||
ctx->dev = dev;
|
||||
spin_lock_init(&ctx->lock);
|
||||
|
||||
ret = lgm_clk_register_plls(ctx, lgm_pll_clks,
|
||||
ARRAY_SIZE(lgm_pll_clks));
|
||||
|
||||
@@ -4942,7 +4942,8 @@ static void drm_parse_hdmi_forum_vsdb(struct drm_connector *connector,
|
||||
else if (hf_vsdb[11] & DRM_EDID_DSC_10BPC)
|
||||
hdmi_dsc->bpc_supported = 10;
|
||||
else
|
||||
hdmi_dsc->bpc_supported = 0;
|
||||
/* Supports min 8 BPC if DSC 1.2 is supported*/
|
||||
hdmi_dsc->bpc_supported = 8;
|
||||
|
||||
dsc_max_frl_rate = (hf_vsdb[12] & DRM_EDID_DSC_MAX_FRL_RATE_MASK) >> 4;
|
||||
drm_get_max_frl_rate(dsc_max_frl_rate, &hdmi_dsc->max_lanes,
|
||||
|
||||
@@ -80,10 +80,10 @@ static int etnaviv_iommu_map(struct etnaviv_iommu_context *context, u32 iova,
|
||||
return -EINVAL;
|
||||
|
||||
for_each_sgtable_dma_sg(sgt, sg, i) {
|
||||
u32 pa = sg_dma_address(sg) - sg->offset;
|
||||
phys_addr_t pa = sg_dma_address(sg) - sg->offset;
|
||||
size_t bytes = sg_dma_len(sg) + sg->offset;
|
||||
|
||||
VERB("map[%d]: %08x %08x(%zx)", i, iova, pa, bytes);
|
||||
VERB("map[%d]: %08x %pap(%zx)", i, iova, &pa, bytes);
|
||||
|
||||
ret = etnaviv_context_map(context, da, pa, bytes, prot);
|
||||
if (ret)
|
||||
|
||||
@@ -1195,10 +1195,8 @@ static int split_2MB_gtt_entry(struct intel_vgpu *vgpu,
|
||||
for_each_shadow_entry(sub_spt, &sub_se, sub_index) {
|
||||
ret = intel_gvt_hypervisor_dma_map_guest_page(vgpu,
|
||||
start_gfn + sub_index, PAGE_SIZE, &dma_addr);
|
||||
if (ret) {
|
||||
ppgtt_invalidate_spt(spt);
|
||||
return ret;
|
||||
}
|
||||
if (ret)
|
||||
goto err;
|
||||
sub_se.val64 = se->val64;
|
||||
|
||||
/* Copy the PAT field from PDE. */
|
||||
@@ -1217,6 +1215,17 @@ static int split_2MB_gtt_entry(struct intel_vgpu *vgpu,
|
||||
ops->set_pfn(se, sub_spt->shadow_page.mfn);
|
||||
ppgtt_set_shadow_entry(spt, se, index);
|
||||
return 0;
|
||||
err:
|
||||
/* Cancel the existing addess mappings of DMA addr. */
|
||||
for_each_present_shadow_entry(sub_spt, &sub_se, sub_index) {
|
||||
gvt_vdbg_mm("invalidate 4K entry\n");
|
||||
ppgtt_invalidate_pte(sub_spt, &sub_se);
|
||||
}
|
||||
/* Release the new allocated spt. */
|
||||
trace_spt_change(sub_spt->vgpu->id, "release", sub_spt,
|
||||
sub_spt->guest_page.gfn, sub_spt->shadow_page.type);
|
||||
ppgtt_free_spt(sub_spt);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int split_64KB_gtt_entry(struct intel_vgpu *vgpu,
|
||||
|
||||
@@ -545,6 +545,7 @@ static int kvaser_usb_hydra_send_simple_cmd(struct kvaser_usb *dev,
|
||||
u8 cmd_no, int channel)
|
||||
{
|
||||
struct kvaser_cmd *cmd;
|
||||
size_t cmd_len;
|
||||
int err;
|
||||
|
||||
cmd = kcalloc(1, sizeof(struct kvaser_cmd), GFP_KERNEL);
|
||||
@@ -552,6 +553,7 @@ static int kvaser_usb_hydra_send_simple_cmd(struct kvaser_usb *dev,
|
||||
return -ENOMEM;
|
||||
|
||||
cmd->header.cmd_no = cmd_no;
|
||||
cmd_len = kvaser_usb_hydra_cmd_size(cmd);
|
||||
if (channel < 0) {
|
||||
kvaser_usb_hydra_set_cmd_dest_he
|
||||
(cmd, KVASER_USB_HYDRA_HE_ADDRESS_ILLEGAL);
|
||||
@@ -568,7 +570,7 @@ static int kvaser_usb_hydra_send_simple_cmd(struct kvaser_usb *dev,
|
||||
kvaser_usb_hydra_set_cmd_transid
|
||||
(cmd, kvaser_usb_hydra_get_next_transid(dev));
|
||||
|
||||
err = kvaser_usb_send_cmd(dev, cmd, kvaser_usb_hydra_cmd_size(cmd));
|
||||
err = kvaser_usb_send_cmd(dev, cmd, cmd_len);
|
||||
if (err)
|
||||
goto end;
|
||||
|
||||
@@ -584,6 +586,7 @@ kvaser_usb_hydra_send_simple_cmd_async(struct kvaser_usb_net_priv *priv,
|
||||
{
|
||||
struct kvaser_cmd *cmd;
|
||||
struct kvaser_usb *dev = priv->dev;
|
||||
size_t cmd_len;
|
||||
int err;
|
||||
|
||||
cmd = kcalloc(1, sizeof(struct kvaser_cmd), GFP_ATOMIC);
|
||||
@@ -591,14 +594,14 @@ kvaser_usb_hydra_send_simple_cmd_async(struct kvaser_usb_net_priv *priv,
|
||||
return -ENOMEM;
|
||||
|
||||
cmd->header.cmd_no = cmd_no;
|
||||
cmd_len = kvaser_usb_hydra_cmd_size(cmd);
|
||||
|
||||
kvaser_usb_hydra_set_cmd_dest_he
|
||||
(cmd, dev->card_data.hydra.channel_to_he[priv->channel]);
|
||||
kvaser_usb_hydra_set_cmd_transid
|
||||
(cmd, kvaser_usb_hydra_get_next_transid(dev));
|
||||
|
||||
err = kvaser_usb_send_cmd_async(priv, cmd,
|
||||
kvaser_usb_hydra_cmd_size(cmd));
|
||||
err = kvaser_usb_send_cmd_async(priv, cmd, cmd_len);
|
||||
if (err)
|
||||
kfree(cmd);
|
||||
|
||||
@@ -742,6 +745,7 @@ static int kvaser_usb_hydra_get_single_capability(struct kvaser_usb *dev,
|
||||
{
|
||||
struct kvaser_usb_dev_card_data *card_data = &dev->card_data;
|
||||
struct kvaser_cmd *cmd;
|
||||
size_t cmd_len;
|
||||
u32 value = 0;
|
||||
u32 mask = 0;
|
||||
u16 cap_cmd_res;
|
||||
@@ -753,13 +757,14 @@ static int kvaser_usb_hydra_get_single_capability(struct kvaser_usb *dev,
|
||||
return -ENOMEM;
|
||||
|
||||
cmd->header.cmd_no = CMD_GET_CAPABILITIES_REQ;
|
||||
cmd_len = kvaser_usb_hydra_cmd_size(cmd);
|
||||
cmd->cap_req.cap_cmd = cpu_to_le16(cap_cmd_req);
|
||||
|
||||
kvaser_usb_hydra_set_cmd_dest_he(cmd, card_data->hydra.sysdbg_he);
|
||||
kvaser_usb_hydra_set_cmd_transid
|
||||
(cmd, kvaser_usb_hydra_get_next_transid(dev));
|
||||
|
||||
err = kvaser_usb_send_cmd(dev, cmd, kvaser_usb_hydra_cmd_size(cmd));
|
||||
err = kvaser_usb_send_cmd(dev, cmd, cmd_len);
|
||||
if (err)
|
||||
goto end;
|
||||
|
||||
@@ -1582,6 +1587,7 @@ static int kvaser_usb_hydra_get_busparams(struct kvaser_usb_net_priv *priv,
|
||||
struct kvaser_usb *dev = priv->dev;
|
||||
struct kvaser_usb_net_hydra_priv *hydra = priv->sub_priv;
|
||||
struct kvaser_cmd *cmd;
|
||||
size_t cmd_len;
|
||||
int err;
|
||||
|
||||
if (!hydra)
|
||||
@@ -1592,6 +1598,7 @@ static int kvaser_usb_hydra_get_busparams(struct kvaser_usb_net_priv *priv,
|
||||
return -ENOMEM;
|
||||
|
||||
cmd->header.cmd_no = CMD_GET_BUSPARAMS_REQ;
|
||||
cmd_len = kvaser_usb_hydra_cmd_size(cmd);
|
||||
kvaser_usb_hydra_set_cmd_dest_he
|
||||
(cmd, dev->card_data.hydra.channel_to_he[priv->channel]);
|
||||
kvaser_usb_hydra_set_cmd_transid
|
||||
@@ -1601,7 +1608,7 @@ static int kvaser_usb_hydra_get_busparams(struct kvaser_usb_net_priv *priv,
|
||||
|
||||
reinit_completion(&priv->get_busparams_comp);
|
||||
|
||||
err = kvaser_usb_send_cmd(dev, cmd, kvaser_usb_hydra_cmd_size(cmd));
|
||||
err = kvaser_usb_send_cmd(dev, cmd, cmd_len);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@@ -1628,6 +1635,7 @@ static int kvaser_usb_hydra_set_bittiming(const struct net_device *netdev,
|
||||
struct kvaser_cmd *cmd;
|
||||
struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
|
||||
struct kvaser_usb *dev = priv->dev;
|
||||
size_t cmd_len;
|
||||
int err;
|
||||
|
||||
cmd = kcalloc(1, sizeof(struct kvaser_cmd), GFP_KERNEL);
|
||||
@@ -1635,6 +1643,7 @@ static int kvaser_usb_hydra_set_bittiming(const struct net_device *netdev,
|
||||
return -ENOMEM;
|
||||
|
||||
cmd->header.cmd_no = CMD_SET_BUSPARAMS_REQ;
|
||||
cmd_len = kvaser_usb_hydra_cmd_size(cmd);
|
||||
memcpy(&cmd->set_busparams_req.busparams_nominal, busparams,
|
||||
sizeof(cmd->set_busparams_req.busparams_nominal));
|
||||
|
||||
@@ -1643,7 +1652,7 @@ static int kvaser_usb_hydra_set_bittiming(const struct net_device *netdev,
|
||||
kvaser_usb_hydra_set_cmd_transid
|
||||
(cmd, kvaser_usb_hydra_get_next_transid(dev));
|
||||
|
||||
err = kvaser_usb_send_cmd(dev, cmd, kvaser_usb_hydra_cmd_size(cmd));
|
||||
err = kvaser_usb_send_cmd(dev, cmd, cmd_len);
|
||||
|
||||
kfree(cmd);
|
||||
|
||||
@@ -1656,6 +1665,7 @@ static int kvaser_usb_hydra_set_data_bittiming(const struct net_device *netdev,
|
||||
struct kvaser_cmd *cmd;
|
||||
struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
|
||||
struct kvaser_usb *dev = priv->dev;
|
||||
size_t cmd_len;
|
||||
int err;
|
||||
|
||||
cmd = kcalloc(1, sizeof(struct kvaser_cmd), GFP_KERNEL);
|
||||
@@ -1663,6 +1673,7 @@ static int kvaser_usb_hydra_set_data_bittiming(const struct net_device *netdev,
|
||||
return -ENOMEM;
|
||||
|
||||
cmd->header.cmd_no = CMD_SET_BUSPARAMS_FD_REQ;
|
||||
cmd_len = kvaser_usb_hydra_cmd_size(cmd);
|
||||
memcpy(&cmd->set_busparams_req.busparams_data, busparams,
|
||||
sizeof(cmd->set_busparams_req.busparams_data));
|
||||
|
||||
@@ -1680,7 +1691,7 @@ static int kvaser_usb_hydra_set_data_bittiming(const struct net_device *netdev,
|
||||
kvaser_usb_hydra_set_cmd_transid
|
||||
(cmd, kvaser_usb_hydra_get_next_transid(dev));
|
||||
|
||||
err = kvaser_usb_send_cmd(dev, cmd, kvaser_usb_hydra_cmd_size(cmd));
|
||||
err = kvaser_usb_send_cmd(dev, cmd, cmd_len);
|
||||
|
||||
kfree(cmd);
|
||||
|
||||
@@ -1808,6 +1819,7 @@ static int kvaser_usb_hydra_get_software_info(struct kvaser_usb *dev)
|
||||
static int kvaser_usb_hydra_get_software_details(struct kvaser_usb *dev)
|
||||
{
|
||||
struct kvaser_cmd *cmd;
|
||||
size_t cmd_len;
|
||||
int err;
|
||||
u32 flags;
|
||||
struct kvaser_usb_dev_card_data *card_data = &dev->card_data;
|
||||
@@ -1817,6 +1829,7 @@ static int kvaser_usb_hydra_get_software_details(struct kvaser_usb *dev)
|
||||
return -ENOMEM;
|
||||
|
||||
cmd->header.cmd_no = CMD_GET_SOFTWARE_DETAILS_REQ;
|
||||
cmd_len = kvaser_usb_hydra_cmd_size(cmd);
|
||||
cmd->sw_detail_req.use_ext_cmd = 1;
|
||||
kvaser_usb_hydra_set_cmd_dest_he
|
||||
(cmd, KVASER_USB_HYDRA_HE_ADDRESS_ILLEGAL);
|
||||
@@ -1824,7 +1837,7 @@ static int kvaser_usb_hydra_get_software_details(struct kvaser_usb *dev)
|
||||
kvaser_usb_hydra_set_cmd_transid
|
||||
(cmd, kvaser_usb_hydra_get_next_transid(dev));
|
||||
|
||||
err = kvaser_usb_send_cmd(dev, cmd, kvaser_usb_hydra_cmd_size(cmd));
|
||||
err = kvaser_usb_send_cmd(dev, cmd, cmd_len);
|
||||
if (err)
|
||||
goto end;
|
||||
|
||||
@@ -1942,6 +1955,7 @@ static int kvaser_usb_hydra_set_opt_mode(const struct kvaser_usb_net_priv *priv)
|
||||
{
|
||||
struct kvaser_usb *dev = priv->dev;
|
||||
struct kvaser_cmd *cmd;
|
||||
size_t cmd_len;
|
||||
int err;
|
||||
|
||||
if ((priv->can.ctrlmode &
|
||||
@@ -1957,6 +1971,7 @@ static int kvaser_usb_hydra_set_opt_mode(const struct kvaser_usb_net_priv *priv)
|
||||
return -ENOMEM;
|
||||
|
||||
cmd->header.cmd_no = CMD_SET_DRIVERMODE_REQ;
|
||||
cmd_len = kvaser_usb_hydra_cmd_size(cmd);
|
||||
kvaser_usb_hydra_set_cmd_dest_he
|
||||
(cmd, dev->card_data.hydra.channel_to_he[priv->channel]);
|
||||
kvaser_usb_hydra_set_cmd_transid
|
||||
@@ -1966,7 +1981,7 @@ static int kvaser_usb_hydra_set_opt_mode(const struct kvaser_usb_net_priv *priv)
|
||||
else
|
||||
cmd->set_ctrlmode.mode = KVASER_USB_HYDRA_CTRLMODE_NORMAL;
|
||||
|
||||
err = kvaser_usb_send_cmd(dev, cmd, kvaser_usb_hydra_cmd_size(cmd));
|
||||
err = kvaser_usb_send_cmd(dev, cmd, cmd_len);
|
||||
kfree(cmd);
|
||||
|
||||
return err;
|
||||
|
||||
@@ -485,6 +485,7 @@ static struct memory_type_mapping mem_type_mapping_tbl[] = {
|
||||
};
|
||||
|
||||
static const struct of_device_id mwifiex_sdio_of_match_table[] = {
|
||||
{ .compatible = "marvell,sd8787" },
|
||||
{ .compatible = "marvell,sd8897" },
|
||||
{ .compatible = "marvell,sd8997" },
|
||||
{ }
|
||||
|
||||
@@ -4369,12 +4369,9 @@ void rtl8xxxu_gen1_report_connect(struct rtl8xxxu_priv *priv,
|
||||
void rtl8xxxu_gen2_report_connect(struct rtl8xxxu_priv *priv,
|
||||
u8 macid, bool connect)
|
||||
{
|
||||
#ifdef RTL8XXXU_GEN2_REPORT_CONNECT
|
||||
/*
|
||||
* Barry Day reports this causes issues with 8192eu and 8723bu
|
||||
* devices reconnecting. The reason for this is unclear, but
|
||||
* until it is better understood, leave the code in place but
|
||||
* disabled, so it is not lost.
|
||||
* The firmware turns on the rate control when it knows it's
|
||||
* connected to a network.
|
||||
*/
|
||||
struct h2c_cmd h2c;
|
||||
|
||||
@@ -4387,7 +4384,6 @@ void rtl8xxxu_gen2_report_connect(struct rtl8xxxu_priv *priv,
|
||||
h2c.media_status_rpt.parm &= ~BIT(0);
|
||||
|
||||
rtl8xxxu_gen2_h2c_cmd(priv, &h2c, sizeof(h2c.media_status_rpt));
|
||||
#endif
|
||||
}
|
||||
|
||||
void rtl8xxxu_gen1_init_aggregation(struct rtl8xxxu_priv *priv)
|
||||
|
||||
@@ -489,6 +489,11 @@ static void ext4_sb_release(struct kobject *kobj)
|
||||
complete(&sbi->s_kobj_unregister);
|
||||
}
|
||||
|
||||
static void ext4_feat_release(struct kobject *kobj)
|
||||
{
|
||||
kfree(kobj);
|
||||
}
|
||||
|
||||
static const struct sysfs_ops ext4_attr_ops = {
|
||||
.show = ext4_attr_show,
|
||||
.store = ext4_attr_store,
|
||||
@@ -503,7 +508,7 @@ static struct kobj_type ext4_sb_ktype = {
|
||||
static struct kobj_type ext4_feat_ktype = {
|
||||
.default_groups = ext4_feat_groups,
|
||||
.sysfs_ops = &ext4_attr_ops,
|
||||
.release = (void (*)(struct kobject *))kfree,
|
||||
.release = ext4_feat_release,
|
||||
};
|
||||
|
||||
void ext4_notify_error_sysfs(struct ext4_sb_info *sbi)
|
||||
|
||||
@@ -11,6 +11,10 @@
|
||||
|
||||
struct task_struct;
|
||||
|
||||
#ifndef barrier_nospec
|
||||
# define barrier_nospec() do { } while (0)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* array_index_mask_nospec() - generate a ~0 mask when index < size, 0 otherwise
|
||||
* @index: array element index
|
||||
|
||||
@@ -19,14 +19,14 @@ void add_input_randomness(unsigned int type, unsigned int code,
|
||||
void add_interrupt_randomness(int irq) __latent_entropy;
|
||||
void add_hwgenerator_randomness(const void *buf, size_t len, size_t entropy);
|
||||
|
||||
#if defined(LATENT_ENTROPY_PLUGIN) && !defined(__CHECKER__)
|
||||
static inline void add_latent_entropy(void)
|
||||
{
|
||||
#if defined(LATENT_ENTROPY_PLUGIN) && !defined(__CHECKER__)
|
||||
add_device_randomness((const void *)&latent_entropy, sizeof(latent_entropy));
|
||||
}
|
||||
#else
|
||||
static inline void add_latent_entropy(void) { }
|
||||
add_device_randomness(NULL, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
void get_random_bytes(void *buf, int len);
|
||||
size_t __must_check get_random_bytes_arch(void *buf, size_t len);
|
||||
|
||||
@@ -91,6 +91,10 @@ config CC_HAS_ASM_INLINE
|
||||
config CC_HAS_NO_PROFILE_FN_ATTR
|
||||
def_bool $(success,echo '__attribute__((no_profile_instrument_function)) int x();' | $(CC) -x c - -c -o /dev/null -Werror)
|
||||
|
||||
config PAHOLE_VERSION
|
||||
int
|
||||
default $(shell,$(srctree)/scripts/pahole-version.sh $(PAHOLE))
|
||||
|
||||
config CONSTRUCTORS
|
||||
bool
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include <linux/perf_event.h>
|
||||
#include <linux/extable.h>
|
||||
#include <linux/log2.h>
|
||||
#include <linux/nospec.h>
|
||||
|
||||
#include <asm/barrier.h>
|
||||
#include <asm/unaligned.h>
|
||||
@@ -1648,9 +1649,7 @@ static u64 ___bpf_prog_run(u64 *regs, const struct bpf_insn *insn)
|
||||
* reuse preexisting logic from Spectre v1 mitigation that
|
||||
* happens to produce the required code on x86 for v4 as well.
|
||||
*/
|
||||
#ifdef CONFIG_X86
|
||||
barrier_nospec();
|
||||
#endif
|
||||
CONT;
|
||||
#define LDST(SIZEOP, SIZE) \
|
||||
STX_MEM_##SIZEOP: \
|
||||
|
||||
@@ -302,7 +302,7 @@ config DEBUG_INFO_DWARF4
|
||||
config DEBUG_INFO_DWARF5
|
||||
bool "Generate DWARF Version 5 debuginfo"
|
||||
depends on !CC_IS_CLANG || AS_IS_LLVM || (AS_IS_GNU && AS_VERSION >= 23502 && AS_HAS_NON_CONST_LEB128)
|
||||
depends on !DEBUG_INFO_BTF
|
||||
depends on !DEBUG_INFO_BTF || PAHOLE_VERSION >= 121
|
||||
help
|
||||
Generate DWARF v5 debug info. Requires binutils 2.35.2, gcc 5.0+ (gcc
|
||||
5.0+ accepts the -gdwarf-5 flag but only had partial support for some
|
||||
@@ -328,7 +328,7 @@ config DEBUG_INFO_BTF
|
||||
DWARF type info into equivalent deduplicated BTF type info.
|
||||
|
||||
config PAHOLE_HAS_SPLIT_BTF
|
||||
def_bool $(success, test `$(PAHOLE) --version | sed -E 's/v([0-9]+)\.([0-9]+)/\1\2/'` -ge "119")
|
||||
def_bool PAHOLE_VERSION >= 119
|
||||
|
||||
config DEBUG_INFO_BTF_MODULES
|
||||
def_bool y
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <linux/fault-inject-usercopy.h>
|
||||
#include <linux/instrumented.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/nospec.h>
|
||||
|
||||
/* out-of-line parts */
|
||||
|
||||
@@ -12,6 +13,12 @@ unsigned long _copy_from_user(void *to, const void __user *from, unsigned long n
|
||||
unsigned long res = n;
|
||||
might_fault();
|
||||
if (!should_fail_usercopy() && likely(access_ok(from, n))) {
|
||||
/*
|
||||
* Ensure that bad access_ok() speculation will not
|
||||
* lead to nasty side effects *after* the copy is
|
||||
* finished:
|
||||
*/
|
||||
barrier_nospec();
|
||||
instrument_copy_from_user(to, from, n);
|
||||
res = raw_copy_from_user(to, from, n);
|
||||
}
|
||||
|
||||
@@ -1950,14 +1950,12 @@ static int taprio_dump(struct Qdisc *sch, struct sk_buff *skb)
|
||||
|
||||
static struct Qdisc *taprio_leaf(struct Qdisc *sch, unsigned long cl)
|
||||
{
|
||||
struct taprio_sched *q = qdisc_priv(sch);
|
||||
struct net_device *dev = qdisc_dev(sch);
|
||||
unsigned int ntx = cl - 1;
|
||||
struct netdev_queue *dev_queue = taprio_queue_get(sch, cl);
|
||||
|
||||
if (ntx >= dev->num_tx_queues)
|
||||
if (!dev_queue)
|
||||
return NULL;
|
||||
|
||||
return q->qdiscs[ntx];
|
||||
return dev_queue->qdisc_sleeping;
|
||||
}
|
||||
|
||||
static unsigned long taprio_find(struct Qdisc *sch, u32 classid)
|
||||
|
||||
@@ -7,7 +7,7 @@ if ! [ -x "$(command -v ${PAHOLE})" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
pahole_ver=$(${PAHOLE} --version | sed -E 's/v([0-9]+)\.([0-9]+)/\1\2/')
|
||||
pahole_ver=$($(dirname $0)/pahole-version.sh ${PAHOLE})
|
||||
|
||||
if [ "${pahole_ver}" -ge "118" ] && [ "${pahole_ver}" -le "121" ]; then
|
||||
# pahole 1.18 through 1.21 can't handle zero-sized per-CPU vars
|
||||
|
||||
13
scripts/pahole-version.sh
Executable file
13
scripts/pahole-version.sh
Executable file
@@ -0,0 +1,13 @@
|
||||
#!/bin/sh
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# Usage: $ ./pahole-version.sh pahole
|
||||
#
|
||||
# Prints pahole's version in a 3-digit form, such as 119 for v1.19.
|
||||
|
||||
if [ ! -x "$(command -v "$@")" ]; then
|
||||
echo 0
|
||||
exit 1
|
||||
fi
|
||||
|
||||
"$@" --version | sed -E 's/v([0-9]+)\.([0-9]+)/\1\2/'
|
||||
Reference in New Issue
Block a user