Import of kernel-6.12.0-124.27.1.el10_1
This commit is contained in:
parent
d0ce8b55b0
commit
85c1100e1e
@ -49,3 +49,17 @@ The ``zl3073x`` driver reports the following versions
|
||||
- running
|
||||
- 1.3.0.1
|
||||
- Device configuration version customized by OEM
|
||||
|
||||
Flash Update
|
||||
============
|
||||
|
||||
The ``zl3073x`` driver implements support for flash update using the
|
||||
``devlink-flash`` interface. It supports updating the device flash using a
|
||||
combined flash image ("bundle") that contains multiple components (firmware
|
||||
parts and configurations).
|
||||
|
||||
During the flash procedure, the standard firmware interface is not available,
|
||||
so the driver unregisters all DPLLs and associated pins, and re-registers them
|
||||
once the flash procedure is complete.
|
||||
|
||||
The driver does not support any overwrite mask flags.
|
||||
|
||||
@ -12,7 +12,7 @@ RHEL_MINOR = 1
|
||||
#
|
||||
# Use this spot to avoid future merge conflicts.
|
||||
# Do not trim this comment.
|
||||
RHEL_RELEASE = 124.21.1
|
||||
RHEL_RELEASE = 124.27.1
|
||||
|
||||
#
|
||||
# RHEL_REBASE_NUM
|
||||
|
||||
@ -75,6 +75,7 @@
|
||||
#define ARM_CPU_PART_CORTEX_A76 0xD0B
|
||||
#define ARM_CPU_PART_NEOVERSE_N1 0xD0C
|
||||
#define ARM_CPU_PART_CORTEX_A77 0xD0D
|
||||
#define ARM_CPU_PART_CORTEX_A76AE 0xD0E
|
||||
#define ARM_CPU_PART_NEOVERSE_V1 0xD40
|
||||
#define ARM_CPU_PART_CORTEX_A78 0xD41
|
||||
#define ARM_CPU_PART_CORTEX_A78AE 0xD42
|
||||
@ -95,6 +96,7 @@
|
||||
#define ARM_CPU_PART_NEOVERSE_V3 0xD84
|
||||
#define ARM_CPU_PART_CORTEX_X925 0xD85
|
||||
#define ARM_CPU_PART_CORTEX_A725 0xD87
|
||||
#define ARM_CPU_PART_CORTEX_A720AE 0xD89
|
||||
#define ARM_CPU_PART_NEOVERSE_N3 0xD8E
|
||||
|
||||
#define APM_CPU_PART_XGENE 0x000
|
||||
@ -131,6 +133,7 @@
|
||||
#define FUJITSU_CPU_PART_A64FX 0x001
|
||||
|
||||
#define HISI_CPU_PART_TSV110 0xD01
|
||||
#define HISI_CPU_PART_HIP09 0xD02
|
||||
|
||||
#define APPLE_CPU_PART_M1_ICESTORM 0x022
|
||||
#define APPLE_CPU_PART_M1_FIRESTORM 0x023
|
||||
@ -160,6 +163,7 @@
|
||||
#define MIDR_CORTEX_A76 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A76)
|
||||
#define MIDR_NEOVERSE_N1 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_NEOVERSE_N1)
|
||||
#define MIDR_CORTEX_A77 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A77)
|
||||
#define MIDR_CORTEX_A76AE MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A76AE)
|
||||
#define MIDR_NEOVERSE_V1 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_NEOVERSE_V1)
|
||||
#define MIDR_CORTEX_A78 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A78)
|
||||
#define MIDR_CORTEX_A78AE MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A78AE)
|
||||
@ -180,6 +184,7 @@
|
||||
#define MIDR_NEOVERSE_V3 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_NEOVERSE_V3)
|
||||
#define MIDR_CORTEX_X925 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_X925)
|
||||
#define MIDR_CORTEX_A725 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A725)
|
||||
#define MIDR_CORTEX_A720AE MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A720AE)
|
||||
#define MIDR_NEOVERSE_N3 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_NEOVERSE_N3)
|
||||
#define MIDR_THUNDERX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX)
|
||||
#define MIDR_THUNDERX_81XX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX_81XX)
|
||||
@ -206,6 +211,7 @@
|
||||
#define MIDR_NVIDIA_CARMEL MIDR_CPU_MODEL(ARM_CPU_IMP_NVIDIA, NVIDIA_CPU_PART_CARMEL)
|
||||
#define MIDR_FUJITSU_A64FX MIDR_CPU_MODEL(ARM_CPU_IMP_FUJITSU, FUJITSU_CPU_PART_A64FX)
|
||||
#define MIDR_HISI_TSV110 MIDR_CPU_MODEL(ARM_CPU_IMP_HISI, HISI_CPU_PART_TSV110)
|
||||
#define MIDR_HISI_HIP09 MIDR_CPU_MODEL(ARM_CPU_IMP_HISI, HISI_CPU_PART_HIP09)
|
||||
#define MIDR_APPLE_M1_ICESTORM MIDR_CPU_MODEL(ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M1_ICESTORM)
|
||||
#define MIDR_APPLE_M1_FIRESTORM MIDR_CPU_MODEL(ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M1_FIRESTORM)
|
||||
#define MIDR_APPLE_M1_ICESTORM_PRO MIDR_CPU_MODEL(ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M1_ICESTORM_PRO)
|
||||
|
||||
@ -494,6 +494,7 @@ static const struct midr_range erratum_spec_ssbs_list[] = {
|
||||
MIDR_ALL_VERSIONS(MIDR_CORTEX_A710),
|
||||
MIDR_ALL_VERSIONS(MIDR_CORTEX_A715),
|
||||
MIDR_ALL_VERSIONS(MIDR_CORTEX_A720),
|
||||
MIDR_ALL_VERSIONS(MIDR_CORTEX_A720AE),
|
||||
MIDR_ALL_VERSIONS(MIDR_CORTEX_A725),
|
||||
MIDR_ALL_VERSIONS(MIDR_CORTEX_X1),
|
||||
MIDR_ALL_VERSIONS(MIDR_CORTEX_X1C),
|
||||
|
||||
@ -854,6 +854,9 @@ static bool is_spectre_bhb_safe(int scope)
|
||||
MIDR_ALL_VERSIONS(MIDR_CORTEX_A510),
|
||||
MIDR_ALL_VERSIONS(MIDR_CORTEX_A520),
|
||||
MIDR_ALL_VERSIONS(MIDR_BRAHMA_B53),
|
||||
MIDR_ALL_VERSIONS(MIDR_QCOM_KRYO_2XX_SILVER),
|
||||
MIDR_ALL_VERSIONS(MIDR_QCOM_KRYO_3XX_SILVER),
|
||||
MIDR_ALL_VERSIONS(MIDR_QCOM_KRYO_4XX_SILVER),
|
||||
{},
|
||||
};
|
||||
static bool all_safe = true;
|
||||
@ -873,6 +876,17 @@ static u8 spectre_bhb_loop_affected(void)
|
||||
{
|
||||
u8 k = 0;
|
||||
|
||||
static const struct midr_range spectre_bhb_k132_list[] = {
|
||||
MIDR_ALL_VERSIONS(MIDR_CORTEX_X3),
|
||||
MIDR_ALL_VERSIONS(MIDR_NEOVERSE_V2),
|
||||
{},
|
||||
};
|
||||
static const struct midr_range spectre_bhb_k38_list[] = {
|
||||
MIDR_ALL_VERSIONS(MIDR_CORTEX_A715),
|
||||
MIDR_ALL_VERSIONS(MIDR_CORTEX_A720),
|
||||
MIDR_ALL_VERSIONS(MIDR_CORTEX_A720AE),
|
||||
{},
|
||||
};
|
||||
static const struct midr_range spectre_bhb_k32_list[] = {
|
||||
MIDR_ALL_VERSIONS(MIDR_CORTEX_A78),
|
||||
MIDR_ALL_VERSIONS(MIDR_CORTEX_A78AE),
|
||||
@ -887,9 +901,11 @@ static u8 spectre_bhb_loop_affected(void)
|
||||
};
|
||||
static const struct midr_range spectre_bhb_k24_list[] = {
|
||||
MIDR_ALL_VERSIONS(MIDR_CORTEX_A76),
|
||||
MIDR_ALL_VERSIONS(MIDR_CORTEX_A76AE),
|
||||
MIDR_ALL_VERSIONS(MIDR_CORTEX_A77),
|
||||
MIDR_ALL_VERSIONS(MIDR_NEOVERSE_N1),
|
||||
MIDR_ALL_VERSIONS(MIDR_QCOM_KRYO_4XX_GOLD),
|
||||
MIDR_ALL_VERSIONS(MIDR_HISI_HIP09),
|
||||
{},
|
||||
};
|
||||
static const struct midr_range spectre_bhb_k11_list[] = {
|
||||
@ -902,7 +918,11 @@ static u8 spectre_bhb_loop_affected(void)
|
||||
{},
|
||||
};
|
||||
|
||||
if (is_midr_in_range_list(spectre_bhb_k32_list))
|
||||
if (is_midr_in_range_list(spectre_bhb_k132_list))
|
||||
k = 132;
|
||||
else if (is_midr_in_range_list(spectre_bhb_k38_list))
|
||||
k = 38;
|
||||
else if (is_midr_in_range_list(spectre_bhb_k32_list))
|
||||
k = 32;
|
||||
else if (is_midr_in_range_list(spectre_bhb_k24_list))
|
||||
k = 24;
|
||||
|
||||
@ -500,6 +500,9 @@ CONFIG_PPC_TRANSACTIONAL_MEM=y
|
||||
CONFIG_PPC_UV=y
|
||||
# CONFIG_LD_HEAD_STUB_CATCH is not set
|
||||
CONFIG_MPROFILE_KERNEL=y
|
||||
CONFIG_ARCH_USING_PATCHABLE_FUNCTION_ENTRY=y
|
||||
CONFIG_PPC_FTRACE_OUT_OF_LINE=y
|
||||
CONFIG_PPC_FTRACE_OUT_OF_LINE_NUM_RESERVE=32768
|
||||
CONFIG_HOTPLUG_CPU=y
|
||||
CONFIG_INTERRUPT_SANITIZE_REGISTERS=y
|
||||
CONFIG_PPC_QUEUED_SPINLOCKS=y
|
||||
@ -722,6 +725,7 @@ CONFIG_FUNCTION_ALIGNMENT_4B=y
|
||||
CONFIG_FUNCTION_ALIGNMENT=4
|
||||
CONFIG_CC_HAS_MIN_FUNCTION_ALIGNMENT=y
|
||||
CONFIG_CC_HAS_SANE_FUNCTION_ALIGNMENT=y
|
||||
CONFIG_ARCH_WANTS_PRE_LINK_VMLINUX=y
|
||||
# end of General architecture-dependent options
|
||||
|
||||
CONFIG_RT_MUTEXES=y
|
||||
@ -5026,6 +5030,7 @@ CONFIG_HID_KUNIT_TEST=m
|
||||
#
|
||||
# HID-BPF support
|
||||
#
|
||||
CONFIG_HID_BPF=y
|
||||
# end of HID-BPF support
|
||||
|
||||
CONFIG_I2C_HID=y
|
||||
@ -7127,6 +7132,8 @@ CONFIG_HAVE_FUNCTION_TRACER=y
|
||||
CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
|
||||
CONFIG_HAVE_DYNAMIC_FTRACE=y
|
||||
CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS=y
|
||||
CONFIG_HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS=y
|
||||
CONFIG_HAVE_DYNAMIC_FTRACE_WITH_CALL_OPS=y
|
||||
CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS=y
|
||||
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
|
||||
CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
|
||||
@ -7147,6 +7154,8 @@ CONFIG_FUNCTION_TRACER=y
|
||||
CONFIG_FUNCTION_GRAPH_TRACER=y
|
||||
CONFIG_DYNAMIC_FTRACE=y
|
||||
CONFIG_DYNAMIC_FTRACE_WITH_REGS=y
|
||||
CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS=y
|
||||
CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS=y
|
||||
CONFIG_DYNAMIC_FTRACE_WITH_ARGS=y
|
||||
CONFIG_FPROBE=y
|
||||
CONFIG_FUNCTION_PROFILER=y
|
||||
@ -7171,7 +7180,7 @@ CONFIG_BPF_EVENTS=y
|
||||
CONFIG_DYNAMIC_EVENTS=y
|
||||
CONFIG_PROBE_EVENTS=y
|
||||
CONFIG_FTRACE_MCOUNT_RECORD=y
|
||||
CONFIG_FTRACE_MCOUNT_USE_CC=y
|
||||
CONFIG_FTRACE_MCOUNT_USE_PATCHABLE_FUNCTION_ENTRY=y
|
||||
CONFIG_TRACING_MAP=y
|
||||
CONFIG_SYNTH_EVENTS=y
|
||||
# CONFIG_USER_EVENTS is not set
|
||||
@ -7197,6 +7206,8 @@ CONFIG_RV_REACTORS=y
|
||||
CONFIG_RV_REACT_PRINTK=y
|
||||
CONFIG_RV_REACT_PANIC=y
|
||||
# CONFIG_SAMPLES is not set
|
||||
CONFIG_HAVE_SAMPLE_FTRACE_DIRECT=y
|
||||
CONFIG_HAVE_SAMPLE_FTRACE_DIRECT_MULTI=y
|
||||
CONFIG_ARCH_HAS_DEVMEM_IS_ALLOWED=y
|
||||
CONFIG_STRICT_DEVMEM=y
|
||||
# CONFIG_IO_STRICT_DEVMEM is not set
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
obj-$(CONFIG_ZL3073X) += zl3073x.o
|
||||
zl3073x-objs := core.o devlink.o dpll.o prop.o
|
||||
zl3073x-objs := core.o devlink.o dpll.o flash.o fw.o prop.o
|
||||
|
||||
obj-$(CONFIG_ZL3073X_I2C) += zl3073x_i2c.o
|
||||
zl3073x_i2c-objs := i2c.o
|
||||
|
||||
@ -95,9 +95,9 @@ EXPORT_SYMBOL_NS_GPL(zl30735_chip_info, "ZL3073X");
|
||||
|
||||
#define ZL_RANGE_OFFSET 0x80
|
||||
#define ZL_PAGE_SIZE 0x80
|
||||
#define ZL_NUM_PAGES 15
|
||||
#define ZL_NUM_PAGES 256
|
||||
#define ZL_PAGE_SEL 0x7F
|
||||
#define ZL_PAGE_SEL_MASK GENMASK(3, 0)
|
||||
#define ZL_PAGE_SEL_MASK GENMASK(7, 0)
|
||||
#define ZL_NUM_REGS (ZL_NUM_PAGES * ZL_PAGE_SIZE)
|
||||
|
||||
/* Regmap range configuration */
|
||||
@ -174,9 +174,10 @@ static bool
|
||||
zl3073x_check_reg(struct zl3073x_dev *zldev, unsigned int reg, size_t size)
|
||||
{
|
||||
/* Check that multiop lock is held when accessing registers
|
||||
* from page 10 and above.
|
||||
* from page 10 and above except the page 255 that does not
|
||||
* need this protection.
|
||||
*/
|
||||
if (ZL_REG_PAGE(reg) >= 10)
|
||||
if (ZL_REG_PAGE(reg) >= 10 && ZL_REG_PAGE(reg) < 255)
|
||||
lockdep_assert_held(&zldev->multiop_lock);
|
||||
|
||||
/* Check the index is in valid range for indexed register */
|
||||
@ -446,6 +447,152 @@ int zl3073x_mb_op(struct zl3073x_dev *zldev, unsigned int op_reg, u8 op_val,
|
||||
return zl3073x_poll_zero_u8(zldev, op_reg, op_val);
|
||||
}
|
||||
|
||||
/**
|
||||
* zl3073x_do_hwreg_op - Perform HW register read/write operation
|
||||
* @zldev: zl3073x device pointer
|
||||
* @op: operation to perform
|
||||
*
|
||||
* Performs requested operation and waits for its completion.
|
||||
*
|
||||
* Return: 0 on success, <0 on error
|
||||
*/
|
||||
static int
|
||||
zl3073x_do_hwreg_op(struct zl3073x_dev *zldev, u8 op)
|
||||
{
|
||||
int rc;
|
||||
|
||||
/* Set requested operation and set pending bit */
|
||||
rc = zl3073x_write_u8(zldev, ZL_REG_HWREG_OP, op | ZL_HWREG_OP_PENDING);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* Poll for completion - pending bit cleared */
|
||||
return zl3073x_poll_zero_u8(zldev, ZL_REG_HWREG_OP,
|
||||
ZL_HWREG_OP_PENDING);
|
||||
}
|
||||
|
||||
/**
|
||||
* zl3073x_read_hwreg - Read HW register
|
||||
* @zldev: zl3073x device pointer
|
||||
* @addr: HW register address
|
||||
* @value: Value of the HW register
|
||||
*
|
||||
* Reads HW register value and stores it into @value.
|
||||
*
|
||||
* Return: 0 on success, <0 on error
|
||||
*/
|
||||
int zl3073x_read_hwreg(struct zl3073x_dev *zldev, u32 addr, u32 *value)
|
||||
{
|
||||
int rc;
|
||||
|
||||
/* Set address to read data from */
|
||||
rc = zl3073x_write_u32(zldev, ZL_REG_HWREG_ADDR, addr);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* Perform the read operation */
|
||||
rc = zl3073x_do_hwreg_op(zldev, ZL_HWREG_OP_READ);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* Read the received data */
|
||||
return zl3073x_read_u32(zldev, ZL_REG_HWREG_READ_DATA, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* zl3073x_write_hwreg - Write value to HW register
|
||||
* @zldev: zl3073x device pointer
|
||||
* @addr: HW registers address
|
||||
* @value: Value to be written to HW register
|
||||
*
|
||||
* Stores the requested value into HW register.
|
||||
*
|
||||
* Return: 0 on success, <0 on error
|
||||
*/
|
||||
int zl3073x_write_hwreg(struct zl3073x_dev *zldev, u32 addr, u32 value)
|
||||
{
|
||||
int rc;
|
||||
|
||||
/* Set address to write data to */
|
||||
rc = zl3073x_write_u32(zldev, ZL_REG_HWREG_ADDR, addr);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* Set data to be written */
|
||||
rc = zl3073x_write_u32(zldev, ZL_REG_HWREG_WRITE_DATA, value);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* Perform the write operation */
|
||||
return zl3073x_do_hwreg_op(zldev, ZL_HWREG_OP_WRITE);
|
||||
}
|
||||
|
||||
/**
|
||||
* zl3073x_update_hwreg - Update certain bits in HW register
|
||||
* @zldev: zl3073x device pointer
|
||||
* @addr: HW register address
|
||||
* @value: Value to be written into HW register
|
||||
* @mask: Bitmask indicating bits to be updated
|
||||
*
|
||||
* Reads given HW register, updates requested bits specified by value and
|
||||
* mask and writes result back to HW register.
|
||||
*
|
||||
* Return: 0 on success, <0 on error
|
||||
*/
|
||||
int zl3073x_update_hwreg(struct zl3073x_dev *zldev, u32 addr, u32 value,
|
||||
u32 mask)
|
||||
{
|
||||
u32 tmp;
|
||||
int rc;
|
||||
|
||||
rc = zl3073x_read_hwreg(zldev, addr, &tmp);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
tmp &= ~mask;
|
||||
tmp |= value & mask;
|
||||
|
||||
return zl3073x_write_hwreg(zldev, addr, tmp);
|
||||
}
|
||||
|
||||
/**
|
||||
* zl3073x_write_hwreg_seq - Write HW registers sequence
|
||||
* @zldev: pointer to device structure
|
||||
* @seq: pointer to first sequence item
|
||||
* @num_items: number of items in sequence
|
||||
*
|
||||
* Writes given HW registers sequence.
|
||||
*
|
||||
* Return: 0 on success, <0 on error
|
||||
*/
|
||||
int zl3073x_write_hwreg_seq(struct zl3073x_dev *zldev,
|
||||
const struct zl3073x_hwreg_seq_item *seq,
|
||||
size_t num_items)
|
||||
{
|
||||
int i, rc = 0;
|
||||
|
||||
for (i = 0; i < num_items; i++) {
|
||||
dev_dbg(zldev->dev, "Write 0x%0x [0x%0x] to 0x%0x",
|
||||
seq[i].value, seq[i].mask, seq[i].addr);
|
||||
|
||||
if (seq[i].mask == U32_MAX)
|
||||
/* Write value directly */
|
||||
rc = zl3073x_write_hwreg(zldev, seq[i].addr,
|
||||
seq[i].value);
|
||||
else
|
||||
/* Update only bits specified by the mask */
|
||||
rc = zl3073x_update_hwreg(zldev, seq[i].addr,
|
||||
seq[i].value, seq[i].mask);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (seq->wait)
|
||||
msleep(seq->wait);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* zl3073x_ref_state_fetch - get input reference state
|
||||
* @zldev: pointer to zl3073x_dev structure
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
#ifndef _ZL3073X_CORE_H
|
||||
#define _ZL3073X_CORE_H
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/mutex.h>
|
||||
@ -118,6 +119,28 @@ void zl3073x_dev_stop(struct zl3073x_dev *zldev);
|
||||
* Registers operations
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* struct zl3073x_hwreg_seq_item - HW register write sequence item
|
||||
* @addr: HW register to be written
|
||||
* @value: value to be written to HW register
|
||||
* @mask: bitmask indicating bits to be updated
|
||||
* @wait: number of ms to wait after register write
|
||||
*/
|
||||
struct zl3073x_hwreg_seq_item {
|
||||
u32 addr;
|
||||
u32 value;
|
||||
u32 mask;
|
||||
u32 wait;
|
||||
};
|
||||
|
||||
#define HWREG_SEQ_ITEM(_addr, _value, _mask, _wait) \
|
||||
{ \
|
||||
.addr = _addr, \
|
||||
.value = FIELD_PREP_CONST(_mask, _value), \
|
||||
.mask = _mask, \
|
||||
.wait = _wait, \
|
||||
}
|
||||
|
||||
int zl3073x_mb_op(struct zl3073x_dev *zldev, unsigned int op_reg, u8 op_val,
|
||||
unsigned int mask_reg, u16 mask_val);
|
||||
int zl3073x_poll_zero_u8(struct zl3073x_dev *zldev, unsigned int reg, u8 mask);
|
||||
@ -129,6 +152,13 @@ int zl3073x_write_u8(struct zl3073x_dev *zldev, unsigned int reg, u8 val);
|
||||
int zl3073x_write_u16(struct zl3073x_dev *zldev, unsigned int reg, u16 val);
|
||||
int zl3073x_write_u32(struct zl3073x_dev *zldev, unsigned int reg, u32 val);
|
||||
int zl3073x_write_u48(struct zl3073x_dev *zldev, unsigned int reg, u64 val);
|
||||
int zl3073x_read_hwreg(struct zl3073x_dev *zldev, u32 addr, u32 *value);
|
||||
int zl3073x_write_hwreg(struct zl3073x_dev *zldev, u32 addr, u32 value);
|
||||
int zl3073x_update_hwreg(struct zl3073x_dev *zldev, u32 addr, u32 value,
|
||||
u32 mask);
|
||||
int zl3073x_write_hwreg_seq(struct zl3073x_dev *zldev,
|
||||
const struct zl3073x_hwreg_seq_item *seq,
|
||||
size_t num_items);
|
||||
|
||||
/*****************
|
||||
* Misc operations
|
||||
|
||||
@ -9,6 +9,8 @@
|
||||
#include "core.h"
|
||||
#include "devlink.h"
|
||||
#include "dpll.h"
|
||||
#include "flash.h"
|
||||
#include "fw.h"
|
||||
#include "regs.h"
|
||||
|
||||
/**
|
||||
@ -132,11 +134,146 @@ zl3073x_devlink_reload_up(struct devlink *devlink,
|
||||
return 0;
|
||||
}
|
||||
|
||||
void zl3073x_devlink_flash_notify(struct zl3073x_dev *zldev, const char *msg,
|
||||
const char *component, u32 done, u32 total)
|
||||
{
|
||||
struct devlink *devlink = priv_to_devlink(zldev);
|
||||
|
||||
devlink_flash_update_status_notify(devlink, msg, component, done,
|
||||
total);
|
||||
}
|
||||
|
||||
/**
|
||||
* zl3073x_devlink_flash_prepare - Prepare and enter flash mode
|
||||
* @zldev: zl3073x device pointer
|
||||
* @zlfw: pointer to loaded firmware
|
||||
* @extack: netlink extack pointer to report errors
|
||||
*
|
||||
* The function stops normal operation and switches the device to flash mode.
|
||||
* If an error occurs the normal operation is resumed.
|
||||
*
|
||||
* Return: 0 on success, <0 on error
|
||||
*/
|
||||
static int
|
||||
zl3073x_devlink_flash_prepare(struct zl3073x_dev *zldev,
|
||||
struct zl3073x_fw *zlfw,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct zl3073x_fw_component *util;
|
||||
int rc;
|
||||
|
||||
util = zlfw->component[ZL_FW_COMPONENT_UTIL];
|
||||
if (!util) {
|
||||
zl3073x_devlink_flash_notify(zldev,
|
||||
"Utility is missing in firmware",
|
||||
NULL, 0, 0);
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
/* Stop normal operation prior entering flash mode */
|
||||
zl3073x_dev_stop(zldev);
|
||||
|
||||
rc = zl3073x_flash_mode_enter(zldev, util->data, util->size, extack);
|
||||
if (rc) {
|
||||
zl3073x_devlink_flash_notify(zldev,
|
||||
"Failed to enter flash mode",
|
||||
NULL, 0, 0);
|
||||
|
||||
/* Resume normal operation */
|
||||
zl3073x_dev_start(zldev, true);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* zl3073x_devlink_flash_finish - Leave flash mode and resume normal operation
|
||||
* @zldev: zl3073x device pointer
|
||||
* @extack: netlink extack pointer to report errors
|
||||
*
|
||||
* The function switches the device back to standard mode and resumes normal
|
||||
* operation.
|
||||
*
|
||||
* Return: 0 on success, <0 on error
|
||||
*/
|
||||
static int
|
||||
zl3073x_devlink_flash_finish(struct zl3073x_dev *zldev,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
int rc;
|
||||
|
||||
/* Reset device CPU to normal mode */
|
||||
zl3073x_flash_mode_leave(zldev, extack);
|
||||
|
||||
/* Resume normal operation */
|
||||
rc = zl3073x_dev_start(zldev, true);
|
||||
if (rc)
|
||||
zl3073x_devlink_flash_notify(zldev,
|
||||
"Failed to start normal operation",
|
||||
NULL, 0, 0);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* zl3073x_devlink_flash_update - Devlink flash update callback
|
||||
* @devlink: devlink structure pointer
|
||||
* @params: flashing parameters pointer
|
||||
* @extack: netlink extack pointer to report errors
|
||||
*
|
||||
* Return: 0 on success, <0 on error
|
||||
*/
|
||||
static int
|
||||
zl3073x_devlink_flash_update(struct devlink *devlink,
|
||||
struct devlink_flash_update_params *params,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct zl3073x_dev *zldev = devlink_priv(devlink);
|
||||
struct zl3073x_fw *zlfw;
|
||||
int rc = 0;
|
||||
|
||||
zlfw = zl3073x_fw_load(zldev, params->fw->data, params->fw->size,
|
||||
extack);
|
||||
if (IS_ERR(zlfw)) {
|
||||
zl3073x_devlink_flash_notify(zldev, "Failed to load firmware",
|
||||
NULL, 0, 0);
|
||||
rc = PTR_ERR(zlfw);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
/* Stop normal operation and enter flash mode */
|
||||
rc = zl3073x_devlink_flash_prepare(zldev, zlfw, extack);
|
||||
if (rc)
|
||||
goto finish;
|
||||
|
||||
rc = zl3073x_fw_flash(zldev, zlfw, extack);
|
||||
if (rc) {
|
||||
zl3073x_devlink_flash_finish(zldev, extack);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
/* Resume normal mode */
|
||||
rc = zl3073x_devlink_flash_finish(zldev, extack);
|
||||
|
||||
finish:
|
||||
if (!IS_ERR(zlfw))
|
||||
zl3073x_fw_free(zlfw);
|
||||
|
||||
zl3073x_devlink_flash_notify(zldev,
|
||||
rc ? "Flashing failed" : "Flashing done",
|
||||
NULL, 0, 0);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static const struct devlink_ops zl3073x_devlink_ops = {
|
||||
.info_get = zl3073x_devlink_info_get,
|
||||
.reload_actions = BIT(DEVLINK_RELOAD_ACTION_DRIVER_REINIT),
|
||||
.reload_down = zl3073x_devlink_reload_down,
|
||||
.reload_up = zl3073x_devlink_reload_up,
|
||||
.flash_update = zl3073x_devlink_flash_update,
|
||||
};
|
||||
|
||||
static void
|
||||
|
||||
@ -9,4 +9,7 @@ struct zl3073x_dev *zl3073x_devm_alloc(struct device *dev);
|
||||
|
||||
int zl3073x_devlink_register(struct zl3073x_dev *zldev);
|
||||
|
||||
void zl3073x_devlink_flash_notify(struct zl3073x_dev *zldev, const char *msg,
|
||||
const char *component, u32 done, u32 total);
|
||||
|
||||
#endif /* _ZL3073X_DEVLINK_H */
|
||||
|
||||
666
drivers/dpll/zl3073x/flash.c
Normal file
666
drivers/dpll/zl3073x/flash.c
Normal file
@ -0,0 +1,666 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <linux/array_size.h>
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/bits.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/dev_printk.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/minmax.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/sched/signal.h>
|
||||
#include <linux/sizes.h>
|
||||
#include <linux/sprintf.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/unaligned.h>
|
||||
#include <net/devlink.h>
|
||||
|
||||
#include "core.h"
|
||||
#include "devlink.h"
|
||||
#include "flash.h"
|
||||
|
||||
#define ZL_FLASH_ERR_PFX "FW update failed: "
|
||||
#define ZL_FLASH_ERR_MSG(_extack, _msg, ...) \
|
||||
NL_SET_ERR_MSG_FMT_MOD((_extack), ZL_FLASH_ERR_PFX _msg, \
|
||||
## __VA_ARGS__)
|
||||
|
||||
/**
|
||||
* zl3073x_flash_download - Download image block to device memory
|
||||
* @zldev: zl3073x device structure
|
||||
* @component: name of the component to be downloaded
|
||||
* @addr: device memory target address
|
||||
* @data: pointer to data to download
|
||||
* @size: size of data to download
|
||||
* @extack: netlink extack pointer to report errors
|
||||
*
|
||||
* Return: 0 on success, <0 on error
|
||||
*/
|
||||
static int
|
||||
zl3073x_flash_download(struct zl3073x_dev *zldev, const char *component,
|
||||
u32 addr, const void *data, size_t size,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
#define ZL_CHECK_DELAY 5000 /* Check for interrupt each 5 seconds */
|
||||
unsigned long check_time;
|
||||
const void *ptr, *end;
|
||||
int rc = 0;
|
||||
|
||||
dev_dbg(zldev->dev, "Downloading %zu bytes to device memory at 0x%0x\n",
|
||||
size, addr);
|
||||
|
||||
check_time = jiffies + msecs_to_jiffies(ZL_CHECK_DELAY);
|
||||
|
||||
for (ptr = data, end = data + size; ptr < end; ptr += 4, addr += 4) {
|
||||
/* Write current word to HW memory */
|
||||
rc = zl3073x_write_hwreg(zldev, addr,
|
||||
get_unaligned((u32 *)ptr));
|
||||
if (rc) {
|
||||
ZL_FLASH_ERR_MSG(extack,
|
||||
"failed to write to memory at 0x%0x",
|
||||
addr);
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (time_is_before_jiffies(check_time)) {
|
||||
if (signal_pending(current)) {
|
||||
ZL_FLASH_ERR_MSG(extack,
|
||||
"Flashing interrupted");
|
||||
return -EINTR;
|
||||
}
|
||||
|
||||
check_time = jiffies + msecs_to_jiffies(ZL_CHECK_DELAY);
|
||||
}
|
||||
|
||||
/* Report status each 1 kB block */
|
||||
if ((ptr - data) % 1024 == 0)
|
||||
zl3073x_devlink_flash_notify(zldev, "Downloading image",
|
||||
component, ptr - data,
|
||||
size);
|
||||
}
|
||||
|
||||
zl3073x_devlink_flash_notify(zldev, "Downloading image", component,
|
||||
ptr - data, size);
|
||||
|
||||
dev_dbg(zldev->dev, "%zu bytes downloaded to device memory\n", size);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* zl3073x_flash_error_check - Check for flash utility errors
|
||||
* @zldev: zl3073x device structure
|
||||
* @extack: netlink extack pointer to report errors
|
||||
*
|
||||
* The function checks for errors detected by the flash utility and
|
||||
* reports them if any were found.
|
||||
*
|
||||
* Return: 0 on success, -EIO when errors are detected
|
||||
*/
|
||||
static int
|
||||
zl3073x_flash_error_check(struct zl3073x_dev *zldev,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
u32 count, cause;
|
||||
int rc;
|
||||
|
||||
rc = zl3073x_read_u32(zldev, ZL_REG_ERROR_COUNT, &count);
|
||||
if (rc)
|
||||
return rc;
|
||||
else if (!count)
|
||||
return 0; /* No error */
|
||||
|
||||
rc = zl3073x_read_u32(zldev, ZL_REG_ERROR_CAUSE, &cause);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* Report errors */
|
||||
ZL_FLASH_ERR_MSG(extack,
|
||||
"utility error occurred: count=%u cause=0x%x", count,
|
||||
cause);
|
||||
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/**
|
||||
* zl3073x_flash_wait_ready - Check or wait for utility to be ready to flash
|
||||
* @zldev: zl3073x device structure
|
||||
* @timeout_ms: timeout for the waiting
|
||||
*
|
||||
* Return: 0 on success, <0 on error
|
||||
*/
|
||||
static int
|
||||
zl3073x_flash_wait_ready(struct zl3073x_dev *zldev, unsigned int timeout_ms)
|
||||
{
|
||||
#define ZL_FLASH_POLL_DELAY_MS 100
|
||||
unsigned long timeout;
|
||||
int rc, i;
|
||||
|
||||
dev_dbg(zldev->dev, "Waiting for flashing to be ready\n");
|
||||
|
||||
timeout = jiffies + msecs_to_jiffies(timeout_ms);
|
||||
|
||||
for (i = 0; time_is_after_jiffies(timeout); i++) {
|
||||
u8 value;
|
||||
|
||||
/* Check for interrupt each 1s */
|
||||
if (i > 9) {
|
||||
if (signal_pending(current))
|
||||
return -EINTR;
|
||||
i = 0;
|
||||
}
|
||||
|
||||
rc = zl3073x_read_u8(zldev, ZL_REG_WRITE_FLASH, &value);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
value = FIELD_GET(ZL_WRITE_FLASH_OP, value);
|
||||
|
||||
if (value == ZL_WRITE_FLASH_OP_DONE)
|
||||
return 0; /* Successfully done */
|
||||
|
||||
msleep(ZL_FLASH_POLL_DELAY_MS);
|
||||
}
|
||||
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
/**
|
||||
* zl3073x_flash_cmd_wait - Perform flash operation and wait for finish
|
||||
* @zldev: zl3073x device structure
|
||||
* @operation: operation to perform
|
||||
* @extack: netlink extack pointer to report errors
|
||||
*
|
||||
* Return: 0 on success, <0 on error
|
||||
*/
|
||||
static int
|
||||
zl3073x_flash_cmd_wait(struct zl3073x_dev *zldev, u32 operation,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
#define ZL_FLASH_PHASE1_TIMEOUT_MS 60000 /* up to 1 minute */
|
||||
#define ZL_FLASH_PHASE2_TIMEOUT_MS 120000 /* up to 2 minutes */
|
||||
u8 value;
|
||||
int rc;
|
||||
|
||||
dev_dbg(zldev->dev, "Sending flash command: 0x%x\n", operation);
|
||||
|
||||
rc = zl3073x_flash_wait_ready(zldev, ZL_FLASH_PHASE1_TIMEOUT_MS);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* Issue the requested operation */
|
||||
rc = zl3073x_read_u8(zldev, ZL_REG_WRITE_FLASH, &value);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
value &= ~ZL_WRITE_FLASH_OP;
|
||||
value |= FIELD_PREP(ZL_WRITE_FLASH_OP, operation);
|
||||
|
||||
rc = zl3073x_write_u8(zldev, ZL_REG_WRITE_FLASH, value);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* Wait for command completion */
|
||||
rc = zl3073x_flash_wait_ready(zldev, ZL_FLASH_PHASE2_TIMEOUT_MS);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
return zl3073x_flash_error_check(zldev, extack);
|
||||
}
|
||||
|
||||
/**
|
||||
* zl3073x_flash_get_sector_size - Get flash sector size
|
||||
* @zldev: zl3073x device structure
|
||||
* @sector_size: sector size returned by the function
|
||||
*
|
||||
* The function reads the flash sector size detected by flash utility and
|
||||
* stores it into @sector_size.
|
||||
*
|
||||
* Return: 0 on success, <0 on error
|
||||
*/
|
||||
static int
|
||||
zl3073x_flash_get_sector_size(struct zl3073x_dev *zldev, size_t *sector_size)
|
||||
{
|
||||
u8 flash_info;
|
||||
int rc;
|
||||
|
||||
rc = zl3073x_read_u8(zldev, ZL_REG_FLASH_INFO, &flash_info);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
switch (FIELD_GET(ZL_FLASH_INFO_SECTOR_SIZE, flash_info)) {
|
||||
case ZL_FLASH_INFO_SECTOR_4K:
|
||||
*sector_size = SZ_4K;
|
||||
break;
|
||||
case ZL_FLASH_INFO_SECTOR_64K:
|
||||
*sector_size = SZ_64K;
|
||||
break;
|
||||
default:
|
||||
rc = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* zl3073x_flash_block - Download and flash memory block
|
||||
* @zldev: zl3073x device structure
|
||||
* @component: component name
|
||||
* @operation: flash operation to perform
|
||||
* @page: destination flash page
|
||||
* @addr: device memory address to load data
|
||||
* @data: pointer to data to be flashed
|
||||
* @size: size of data
|
||||
* @extack: netlink extack pointer to report errors
|
||||
*
|
||||
* The function downloads the memory block given by the @data pointer and
|
||||
* the size @size and flashes it into internal memory on flash page @page.
|
||||
* The internal flash operation performed by the firmware is specified by
|
||||
* the @operation parameter.
|
||||
*
|
||||
* Return: 0 on success, <0 on error
|
||||
*/
|
||||
static int
|
||||
zl3073x_flash_block(struct zl3073x_dev *zldev, const char *component,
|
||||
u32 operation, u32 page, u32 addr, const void *data,
|
||||
size_t size, struct netlink_ext_ack *extack)
|
||||
{
|
||||
int rc;
|
||||
|
||||
/* Download block to device memory */
|
||||
rc = zl3073x_flash_download(zldev, component, addr, data, size, extack);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* Set address to flash from */
|
||||
rc = zl3073x_write_u32(zldev, ZL_REG_IMAGE_START_ADDR, addr);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* Set size of block to flash */
|
||||
rc = zl3073x_write_u32(zldev, ZL_REG_IMAGE_SIZE, size);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* Set destination page to flash */
|
||||
rc = zl3073x_write_u32(zldev, ZL_REG_FLASH_INDEX_WRITE, page);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* Set filling pattern */
|
||||
rc = zl3073x_write_u32(zldev, ZL_REG_FILL_PATTERN, U32_MAX);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
zl3073x_devlink_flash_notify(zldev, "Flashing image", component, 0,
|
||||
size);
|
||||
|
||||
dev_dbg(zldev->dev, "Flashing %zu bytes to page %u\n", size, page);
|
||||
|
||||
/* Execute sectors flash operation */
|
||||
rc = zl3073x_flash_cmd_wait(zldev, operation, extack);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
zl3073x_devlink_flash_notify(zldev, "Flashing image", component, size,
|
||||
size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* zl3073x_flash_sectors - Flash sectors
|
||||
* @zldev: zl3073x device structure
|
||||
* @component: component name
|
||||
* @page: destination flash page
|
||||
* @addr: device memory address to load data
|
||||
* @data: pointer to data to be flashed
|
||||
* @size: size of data
|
||||
* @extack: netlink extack pointer to report errors
|
||||
*
|
||||
* The function flashes given @data with size of @size to the internal flash
|
||||
* memory block starting from page @page. The function uses sector flash
|
||||
* method and has to take into account the flash sector size reported by
|
||||
* flashing utility. Input data are spliced into blocks according this
|
||||
* sector size and each block is flashed separately.
|
||||
*
|
||||
* Return: 0 on success, <0 on error
|
||||
*/
|
||||
int zl3073x_flash_sectors(struct zl3073x_dev *zldev, const char *component,
|
||||
u32 page, u32 addr, const void *data, size_t size,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
#define ZL_FLASH_MAX_BLOCK_SIZE 0x0001E000
|
||||
#define ZL_FLASH_PAGE_SIZE 256
|
||||
size_t max_block_size, block_size, sector_size;
|
||||
const void *ptr, *end;
|
||||
int rc;
|
||||
|
||||
/* Get flash sector size */
|
||||
rc = zl3073x_flash_get_sector_size(zldev, §or_size);
|
||||
if (rc) {
|
||||
ZL_FLASH_ERR_MSG(extack, "Failed to get flash sector size");
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Determine max block size depending on sector size */
|
||||
max_block_size = ALIGN_DOWN(ZL_FLASH_MAX_BLOCK_SIZE, sector_size);
|
||||
|
||||
for (ptr = data, end = data + size; ptr < end; ptr += block_size) {
|
||||
char comp_str[32];
|
||||
|
||||
block_size = min_t(size_t, max_block_size, end - ptr);
|
||||
|
||||
/* Add suffix '-partN' if the requested component size is
|
||||
* greater than max_block_size.
|
||||
*/
|
||||
if (max_block_size < size)
|
||||
snprintf(comp_str, sizeof(comp_str), "%s-part%zu",
|
||||
component, (ptr - data) / max_block_size + 1);
|
||||
else
|
||||
strscpy(comp_str, component);
|
||||
|
||||
/* Flash the memory block */
|
||||
rc = zl3073x_flash_block(zldev, comp_str,
|
||||
ZL_WRITE_FLASH_OP_SECTORS, page, addr,
|
||||
ptr, block_size, extack);
|
||||
if (rc)
|
||||
goto finish;
|
||||
|
||||
/* Move to next page */
|
||||
page += block_size / ZL_FLASH_PAGE_SIZE;
|
||||
}
|
||||
|
||||
finish:
|
||||
zl3073x_devlink_flash_notify(zldev,
|
||||
rc ? "Flashing failed" : "Flashing done",
|
||||
component, 0, 0);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* zl3073x_flash_page - Flash page
|
||||
* @zldev: zl3073x device structure
|
||||
* @component: component name
|
||||
* @page: destination flash page
|
||||
* @addr: device memory address to load data
|
||||
* @data: pointer to data to be flashed
|
||||
* @size: size of data
|
||||
* @extack: netlink extack pointer to report errors
|
||||
*
|
||||
* The function flashes given @data with size of @size to the internal flash
|
||||
* memory block starting with page @page.
|
||||
*
|
||||
* Return: 0 on success, <0 on error
|
||||
*/
|
||||
int zl3073x_flash_page(struct zl3073x_dev *zldev, const char *component,
|
||||
u32 page, u32 addr, const void *data, size_t size,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
int rc;
|
||||
|
||||
/* Flash the memory block */
|
||||
rc = zl3073x_flash_block(zldev, component, ZL_WRITE_FLASH_OP_PAGE, page,
|
||||
addr, data, size, extack);
|
||||
|
||||
zl3073x_devlink_flash_notify(zldev,
|
||||
rc ? "Flashing failed" : "Flashing done",
|
||||
component, 0, 0);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* zl3073x_flash_page_copy - Copy flash page
|
||||
* @zldev: zl3073x device structure
|
||||
* @component: component name
|
||||
* @src_page: source page to copy
|
||||
* @dst_page: destination page
|
||||
* @extack: netlink extack pointer to report errors
|
||||
*
|
||||
* The function copies one flash page specified by @src_page into the flash
|
||||
* page specified by @dst_page.
|
||||
*
|
||||
* Return: 0 on success, <0 on error
|
||||
*/
|
||||
int zl3073x_flash_page_copy(struct zl3073x_dev *zldev, const char *component,
|
||||
u32 src_page, u32 dst_page,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
int rc;
|
||||
|
||||
/* Set source page to be copied */
|
||||
rc = zl3073x_write_u32(zldev, ZL_REG_FLASH_INDEX_READ, src_page);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* Set destination page for the copy */
|
||||
rc = zl3073x_write_u32(zldev, ZL_REG_FLASH_INDEX_WRITE, dst_page);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* Perform copy operation */
|
||||
rc = zl3073x_flash_cmd_wait(zldev, ZL_WRITE_FLASH_OP_COPY_PAGE, extack);
|
||||
if (rc)
|
||||
ZL_FLASH_ERR_MSG(extack, "Failed to copy page %u to page %u",
|
||||
src_page, dst_page);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* zl3073x_flash_mode_verify - Check flash utility
|
||||
* @zldev: zl3073x device structure
|
||||
*
|
||||
* Return: 0 if the flash utility is ready, <0 on error
|
||||
*/
|
||||
static int
|
||||
zl3073x_flash_mode_verify(struct zl3073x_dev *zldev)
|
||||
{
|
||||
u8 family, release;
|
||||
u32 hash;
|
||||
int rc;
|
||||
|
||||
rc = zl3073x_read_u32(zldev, ZL_REG_FLASH_HASH, &hash);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = zl3073x_read_u8(zldev, ZL_REG_FLASH_FAMILY, &family);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = zl3073x_read_u8(zldev, ZL_REG_FLASH_RELEASE, &release);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
dev_dbg(zldev->dev,
|
||||
"Flash utility check: hash 0x%08x, fam 0x%02x, rel 0x%02x\n",
|
||||
hash, family, release);
|
||||
|
||||
/* Return success for correct family */
|
||||
return (family == 0x21) ? 0 : -ENODEV;
|
||||
}
|
||||
|
||||
static int
|
||||
zl3073x_flash_host_ctrl_enable(struct zl3073x_dev *zldev)
|
||||
{
|
||||
u8 host_ctrl;
|
||||
int rc;
|
||||
|
||||
/* Enable host control */
|
||||
rc = zl3073x_read_u8(zldev, ZL_REG_HOST_CONTROL, &host_ctrl);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
host_ctrl |= ZL_HOST_CONTROL_ENABLE;
|
||||
|
||||
return zl3073x_write_u8(zldev, ZL_REG_HOST_CONTROL, host_ctrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* zl3073x_flash_mode_enter - Switch the device to flash mode
|
||||
* @zldev: zl3073x device structure
|
||||
* @util_ptr: buffer with flash utility
|
||||
* @util_size: size of buffer with flash utility
|
||||
* @extack: netlink extack pointer to report errors
|
||||
*
|
||||
* The function prepares and switches the device into flash mode.
|
||||
*
|
||||
* The procedure:
|
||||
* 1) Stop device CPU by specific HW register sequence
|
||||
* 2) Download flash utility to device memory
|
||||
* 3) Resume device CPU by specific HW register sequence
|
||||
* 4) Check communication with flash utility
|
||||
* 5) Enable host control necessary to access flash API
|
||||
* 6) Check for potential error detected by the utility
|
||||
*
|
||||
* The API provided by normal firmware is not available in flash mode
|
||||
* so the caller has to ensure that this API is not used in this mode.
|
||||
*
|
||||
* After performing flash operation the caller should call
|
||||
* @zl3073x_flash_mode_leave to return back to normal operation.
|
||||
*
|
||||
* Return: 0 on success, <0 on error.
|
||||
*/
|
||||
int zl3073x_flash_mode_enter(struct zl3073x_dev *zldev, const void *util_ptr,
|
||||
size_t util_size, struct netlink_ext_ack *extack)
|
||||
{
|
||||
/* Sequence to be written prior utility download */
|
||||
static const struct zl3073x_hwreg_seq_item pre_seq[] = {
|
||||
HWREG_SEQ_ITEM(0x80000400, 1, BIT(0), 0),
|
||||
HWREG_SEQ_ITEM(0x80206340, 1, BIT(4), 0),
|
||||
HWREG_SEQ_ITEM(0x10000000, 1, BIT(2), 0),
|
||||
HWREG_SEQ_ITEM(0x10000024, 0x00000001, U32_MAX, 0),
|
||||
HWREG_SEQ_ITEM(0x10000020, 0x00000001, U32_MAX, 0),
|
||||
HWREG_SEQ_ITEM(0x10000000, 1, BIT(10), 1000),
|
||||
};
|
||||
/* Sequence to be written after utility download */
|
||||
static const struct zl3073x_hwreg_seq_item post_seq[] = {
|
||||
HWREG_SEQ_ITEM(0x10400004, 0x000000C0, U32_MAX, 0),
|
||||
HWREG_SEQ_ITEM(0x10400008, 0x00000000, U32_MAX, 0),
|
||||
HWREG_SEQ_ITEM(0x10400010, 0x20000000, U32_MAX, 0),
|
||||
HWREG_SEQ_ITEM(0x10400014, 0x20000004, U32_MAX, 0),
|
||||
HWREG_SEQ_ITEM(0x10000000, 1, GENMASK(10, 9), 0),
|
||||
HWREG_SEQ_ITEM(0x10000020, 0x00000000, U32_MAX, 0),
|
||||
HWREG_SEQ_ITEM(0x10000000, 0, BIT(0), 1000),
|
||||
};
|
||||
int rc;
|
||||
|
||||
zl3073x_devlink_flash_notify(zldev, "Prepare flash mode", "utility",
|
||||
0, 0);
|
||||
|
||||
/* Execure pre-load sequence */
|
||||
rc = zl3073x_write_hwreg_seq(zldev, pre_seq, ARRAY_SIZE(pre_seq));
|
||||
if (rc) {
|
||||
ZL_FLASH_ERR_MSG(extack, "cannot execute pre-load sequence");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Download utility image to device memory */
|
||||
rc = zl3073x_flash_download(zldev, "utility", 0x20000000, util_ptr,
|
||||
util_size, extack);
|
||||
if (rc) {
|
||||
ZL_FLASH_ERR_MSG(extack, "cannot download flash utility");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Execute post-load sequence */
|
||||
rc = zl3073x_write_hwreg_seq(zldev, post_seq, ARRAY_SIZE(post_seq));
|
||||
if (rc) {
|
||||
ZL_FLASH_ERR_MSG(extack, "cannot execute post-load sequence");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Check that utility identifies itself correctly */
|
||||
rc = zl3073x_flash_mode_verify(zldev);
|
||||
if (rc) {
|
||||
ZL_FLASH_ERR_MSG(extack, "flash utility check failed");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Enable host control */
|
||||
rc = zl3073x_flash_host_ctrl_enable(zldev);
|
||||
if (rc) {
|
||||
ZL_FLASH_ERR_MSG(extack, "cannot enable host control");
|
||||
goto error;
|
||||
}
|
||||
|
||||
zl3073x_devlink_flash_notify(zldev, "Flash mode enabled", "utility",
|
||||
0, 0);
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
zl3073x_flash_mode_leave(zldev, extack);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* zl3073x_flash_mode_leave - Leave flash mode
|
||||
* @zldev: zl3073x device structure
|
||||
* @extack: netlink extack pointer to report errors
|
||||
*
|
||||
* The function instructs the device to leave the flash mode and
|
||||
* to return back to normal operation.
|
||||
*
|
||||
* The procedure:
|
||||
* 1) Set reset flag
|
||||
* 2) Reset the device CPU by specific HW register sequence
|
||||
* 3) Wait for the device to be ready
|
||||
* 4) Check the reset flag was cleared
|
||||
*
|
||||
* Return: 0 on success, <0 on error
|
||||
*/
|
||||
int zl3073x_flash_mode_leave(struct zl3073x_dev *zldev,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
/* Sequence to be written after flash */
|
||||
static const struct zl3073x_hwreg_seq_item fw_reset_seq[] = {
|
||||
HWREG_SEQ_ITEM(0x80000404, 1, BIT(0), 0),
|
||||
HWREG_SEQ_ITEM(0x80000410, 1, BIT(0), 0),
|
||||
};
|
||||
u8 reset_status;
|
||||
int rc;
|
||||
|
||||
zl3073x_devlink_flash_notify(zldev, "Leaving flash mode", "utility",
|
||||
0, 0);
|
||||
|
||||
/* Read reset status register */
|
||||
rc = zl3073x_read_u8(zldev, ZL_REG_RESET_STATUS, &reset_status);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* Set reset bit */
|
||||
reset_status |= ZL_REG_RESET_STATUS_RESET;
|
||||
|
||||
/* Update reset status register */
|
||||
rc = zl3073x_write_u8(zldev, ZL_REG_RESET_STATUS, reset_status);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* We do not check the return value here as the sequence resets
|
||||
* the device CPU and the last write always return an error.
|
||||
*/
|
||||
zl3073x_write_hwreg_seq(zldev, fw_reset_seq, ARRAY_SIZE(fw_reset_seq));
|
||||
|
||||
/* Wait for the device to be ready */
|
||||
msleep(500);
|
||||
|
||||
/* Read again the reset status register */
|
||||
rc = zl3073x_read_u8(zldev, ZL_REG_RESET_STATUS, &reset_status);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* Check the reset bit was cleared */
|
||||
if (reset_status & ZL_REG_RESET_STATUS_RESET) {
|
||||
dev_err(zldev->dev,
|
||||
"Reset not confirmed after switch to normal mode\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
29
drivers/dpll/zl3073x/flash.h
Normal file
29
drivers/dpll/zl3073x/flash.h
Normal file
@ -0,0 +1,29 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
|
||||
#ifndef __ZL3073X_FLASH_H
|
||||
#define __ZL3073X_FLASH_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
struct netlink_ext_ack;
|
||||
struct zl3073x_dev;
|
||||
|
||||
int zl3073x_flash_mode_enter(struct zl3073x_dev *zldev, const void *util_ptr,
|
||||
size_t util_size, struct netlink_ext_ack *extack);
|
||||
|
||||
int zl3073x_flash_mode_leave(struct zl3073x_dev *zldev,
|
||||
struct netlink_ext_ack *extack);
|
||||
|
||||
int zl3073x_flash_page(struct zl3073x_dev *zldev, const char *component,
|
||||
u32 page, u32 addr, const void *data, size_t size,
|
||||
struct netlink_ext_ack *extack);
|
||||
|
||||
int zl3073x_flash_page_copy(struct zl3073x_dev *zldev, const char *component,
|
||||
u32 src_page, u32 dst_page,
|
||||
struct netlink_ext_ack *extack);
|
||||
|
||||
int zl3073x_flash_sectors(struct zl3073x_dev *zldev, const char *component,
|
||||
u32 page, u32 addr, const void *data, size_t size,
|
||||
struct netlink_ext_ack *extack);
|
||||
|
||||
#endif /* __ZL3073X_FLASH_H */
|
||||
419
drivers/dpll/zl3073x/fw.c
Normal file
419
drivers/dpll/zl3073x/fw.c
Normal file
@ -0,0 +1,419 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <linux/array_size.h>
|
||||
#include <linux/build_bug.h>
|
||||
#include <linux/dev_printk.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
#include "core.h"
|
||||
#include "flash.h"
|
||||
#include "fw.h"
|
||||
|
||||
#define ZL3073X_FW_ERR_PFX "FW load failed: "
|
||||
#define ZL3073X_FW_ERR_MSG(_extack, _msg, ...) \
|
||||
NL_SET_ERR_MSG_FMT_MOD((_extack), ZL3073X_FW_ERR_PFX _msg, \
|
||||
## __VA_ARGS__)
|
||||
|
||||
enum zl3073x_flash_type {
|
||||
ZL3073X_FLASH_TYPE_NONE = 0,
|
||||
ZL3073X_FLASH_TYPE_SECTORS,
|
||||
ZL3073X_FLASH_TYPE_PAGE,
|
||||
ZL3073X_FLASH_TYPE_PAGE_AND_COPY,
|
||||
};
|
||||
|
||||
struct zl3073x_fw_component_info {
|
||||
const char *name;
|
||||
size_t max_size;
|
||||
enum zl3073x_flash_type flash_type;
|
||||
u32 load_addr;
|
||||
u32 dest_page;
|
||||
u32 copy_page;
|
||||
};
|
||||
|
||||
static const struct zl3073x_fw_component_info component_info[] = {
|
||||
[ZL_FW_COMPONENT_UTIL] = {
|
||||
.name = "utility",
|
||||
.max_size = 0x4000,
|
||||
.load_addr = 0x20000000,
|
||||
.flash_type = ZL3073X_FLASH_TYPE_NONE,
|
||||
},
|
||||
[ZL_FW_COMPONENT_FW1] = {
|
||||
.name = "firmware1",
|
||||
.max_size = 0x35000,
|
||||
.load_addr = 0x20002000,
|
||||
.flash_type = ZL3073X_FLASH_TYPE_SECTORS,
|
||||
.dest_page = 0x020,
|
||||
},
|
||||
[ZL_FW_COMPONENT_FW2] = {
|
||||
.name = "firmware2",
|
||||
.max_size = 0x0040,
|
||||
.load_addr = 0x20000000,
|
||||
.flash_type = ZL3073X_FLASH_TYPE_PAGE_AND_COPY,
|
||||
.dest_page = 0x3e0,
|
||||
.copy_page = 0x000,
|
||||
},
|
||||
[ZL_FW_COMPONENT_FW3] = {
|
||||
.name = "firmware3",
|
||||
.max_size = 0x0248,
|
||||
.load_addr = 0x20000400,
|
||||
.flash_type = ZL3073X_FLASH_TYPE_PAGE_AND_COPY,
|
||||
.dest_page = 0x3e4,
|
||||
.copy_page = 0x004,
|
||||
},
|
||||
[ZL_FW_COMPONENT_CFG0] = {
|
||||
.name = "config0",
|
||||
.max_size = 0x1000,
|
||||
.load_addr = 0x20000000,
|
||||
.flash_type = ZL3073X_FLASH_TYPE_PAGE,
|
||||
.dest_page = 0x3d0,
|
||||
},
|
||||
[ZL_FW_COMPONENT_CFG1] = {
|
||||
.name = "config1",
|
||||
.max_size = 0x1000,
|
||||
.load_addr = 0x20000000,
|
||||
.flash_type = ZL3073X_FLASH_TYPE_PAGE,
|
||||
.dest_page = 0x3c0,
|
||||
},
|
||||
[ZL_FW_COMPONENT_CFG2] = {
|
||||
.name = "config2",
|
||||
.max_size = 0x1000,
|
||||
.load_addr = 0x20000000,
|
||||
.flash_type = ZL3073X_FLASH_TYPE_PAGE,
|
||||
.dest_page = 0x3b0,
|
||||
},
|
||||
[ZL_FW_COMPONENT_CFG3] = {
|
||||
.name = "config3",
|
||||
.max_size = 0x1000,
|
||||
.load_addr = 0x20000000,
|
||||
.flash_type = ZL3073X_FLASH_TYPE_PAGE,
|
||||
.dest_page = 0x3a0,
|
||||
},
|
||||
[ZL_FW_COMPONENT_CFG4] = {
|
||||
.name = "config4",
|
||||
.max_size = 0x1000,
|
||||
.load_addr = 0x20000000,
|
||||
.flash_type = ZL3073X_FLASH_TYPE_PAGE,
|
||||
.dest_page = 0x390,
|
||||
},
|
||||
[ZL_FW_COMPONENT_CFG5] = {
|
||||
.name = "config5",
|
||||
.max_size = 0x1000,
|
||||
.load_addr = 0x20000000,
|
||||
.flash_type = ZL3073X_FLASH_TYPE_PAGE,
|
||||
.dest_page = 0x380,
|
||||
},
|
||||
[ZL_FW_COMPONENT_CFG6] = {
|
||||
.name = "config6",
|
||||
.max_size = 0x1000,
|
||||
.load_addr = 0x20000000,
|
||||
.flash_type = ZL3073X_FLASH_TYPE_PAGE,
|
||||
.dest_page = 0x370,
|
||||
},
|
||||
};
|
||||
|
||||
/* Sanity check */
|
||||
static_assert(ARRAY_SIZE(component_info) == ZL_FW_NUM_COMPONENTS);
|
||||
|
||||
/**
|
||||
* zl3073x_fw_component_alloc - Alloc structure to hold firmware component
|
||||
* @size: size of buffer to store data
|
||||
*
|
||||
* Return: pointer to allocated component structure or NULL on error.
|
||||
*/
|
||||
static struct zl3073x_fw_component *
|
||||
zl3073x_fw_component_alloc(size_t size)
|
||||
{
|
||||
struct zl3073x_fw_component *comp;
|
||||
|
||||
comp = kzalloc(sizeof(*comp), GFP_KERNEL);
|
||||
if (!comp)
|
||||
return NULL;
|
||||
|
||||
comp->size = size;
|
||||
comp->data = kzalloc(size, GFP_KERNEL);
|
||||
if (!comp->data) {
|
||||
kfree(comp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return comp;
|
||||
}
|
||||
|
||||
/**
|
||||
* zl3073x_fw_component_free - Free allocated component structure
|
||||
* @comp: pointer to allocated component
|
||||
*/
|
||||
static void
|
||||
zl3073x_fw_component_free(struct zl3073x_fw_component *comp)
|
||||
{
|
||||
if (comp)
|
||||
kfree(comp->data);
|
||||
|
||||
kfree(comp);
|
||||
}
|
||||
|
||||
/**
|
||||
* zl3073x_fw_component_id_get - Get ID for firmware component name
|
||||
* @name: input firmware component name
|
||||
*
|
||||
* Return:
|
||||
* - ZL3073X_FW_COMPONENT_* ID for known component name
|
||||
* - ZL3073X_FW_COMPONENT_INVALID if the given name is unknown
|
||||
*/
|
||||
static enum zl3073x_fw_component_id
|
||||
zl3073x_fw_component_id_get(const char *name)
|
||||
{
|
||||
enum zl3073x_fw_component_id id;
|
||||
|
||||
for (id = 0; id < ZL_FW_NUM_COMPONENTS; id++)
|
||||
if (!strcasecmp(name, component_info[id].name))
|
||||
return id;
|
||||
|
||||
return ZL_FW_COMPONENT_INVALID;
|
||||
}
|
||||
|
||||
/**
|
||||
* zl3073x_fw_component_load - Load component from firmware source
|
||||
* @zldev: zl3073x device structure
|
||||
* @pcomp: pointer to loaded component
|
||||
* @psrc: data pointer to load component from
|
||||
* @psize: remaining bytes in buffer
|
||||
* @extack: netlink extack pointer to report errors
|
||||
*
|
||||
* The function allocates single firmware component and loads the data from
|
||||
* the buffer specified by @psrc and @psize. Pointer to allocated component
|
||||
* is stored in output @pcomp. Source data pointer @psrc and remaining bytes
|
||||
* @psize are updated accordingly.
|
||||
*
|
||||
* Return:
|
||||
* * 1 when component was allocated and loaded
|
||||
* * 0 when there is no component to load
|
||||
* * <0 on error
|
||||
*/
|
||||
static ssize_t
|
||||
zl3073x_fw_component_load(struct zl3073x_dev *zldev,
|
||||
struct zl3073x_fw_component **pcomp,
|
||||
const char **psrc, size_t *psize,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
const struct zl3073x_fw_component_info *info;
|
||||
struct zl3073x_fw_component *comp = NULL;
|
||||
struct device *dev = zldev->dev;
|
||||
enum zl3073x_fw_component_id id;
|
||||
char buf[32], name[16];
|
||||
u32 count, size, *dest;
|
||||
int pos, rc;
|
||||
|
||||
/* Fetch image name and size from input */
|
||||
strscpy(buf, *psrc, min(sizeof(buf), *psize));
|
||||
rc = sscanf(buf, "%15s %u %n", name, &count, &pos);
|
||||
if (!rc) {
|
||||
/* No more data */
|
||||
return 0;
|
||||
} else if (rc == 1 || count > U32_MAX / sizeof(u32)) {
|
||||
ZL3073X_FW_ERR_MSG(extack, "invalid component size");
|
||||
return -EINVAL;
|
||||
}
|
||||
*psrc += pos;
|
||||
*psize -= pos;
|
||||
|
||||
dev_dbg(dev, "Firmware component '%s' found\n", name);
|
||||
|
||||
id = zl3073x_fw_component_id_get(name);
|
||||
if (id == ZL_FW_COMPONENT_INVALID) {
|
||||
ZL3073X_FW_ERR_MSG(extack, "unknown component type '%s'", name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
info = &component_info[id];
|
||||
size = count * sizeof(u32); /* get size in bytes */
|
||||
|
||||
/* Check image size validity */
|
||||
if (size > component_info[id].max_size) {
|
||||
ZL3073X_FW_ERR_MSG(extack,
|
||||
"[%s] component is too big (%u bytes)\n",
|
||||
info->name, size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dev_dbg(dev, "Indicated component image size: %u bytes\n", size);
|
||||
|
||||
/* Alloc component */
|
||||
comp = zl3073x_fw_component_alloc(size);
|
||||
if (!comp) {
|
||||
ZL3073X_FW_ERR_MSG(extack, "failed to alloc memory");
|
||||
return -ENOMEM;
|
||||
}
|
||||
comp->id = id;
|
||||
|
||||
/* Load component data from firmware source */
|
||||
for (dest = comp->data; count; count--, dest++) {
|
||||
strscpy(buf, *psrc, min(sizeof(buf), *psize));
|
||||
rc = sscanf(buf, "%x %n", dest, &pos);
|
||||
if (!rc)
|
||||
goto err_data;
|
||||
|
||||
*psrc += pos;
|
||||
*psize -= pos;
|
||||
}
|
||||
|
||||
*pcomp = comp;
|
||||
|
||||
return 1;
|
||||
|
||||
err_data:
|
||||
ZL3073X_FW_ERR_MSG(extack, "[%s] invalid or missing data", info->name);
|
||||
|
||||
zl3073x_fw_component_free(comp);
|
||||
|
||||
return -ENODATA;
|
||||
}
|
||||
|
||||
/**
|
||||
* zl3073x_fw_free - Free allocated firmware
|
||||
* @fw: firmware pointer
|
||||
*
|
||||
* The function frees existing firmware allocated by @zl3073x_fw_load.
|
||||
*/
|
||||
void zl3073x_fw_free(struct zl3073x_fw *fw)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (!fw)
|
||||
return;
|
||||
|
||||
for (i = 0; i < ZL_FW_NUM_COMPONENTS; i++)
|
||||
zl3073x_fw_component_free(fw->component[i]);
|
||||
|
||||
kfree(fw);
|
||||
}
|
||||
|
||||
/**
|
||||
* zl3073x_fw_load - Load all components from source
|
||||
* @zldev: zl3073x device structure
|
||||
* @data: source buffer pointer
|
||||
* @size: size of source buffer
|
||||
* @extack: netlink extack pointer to report errors
|
||||
*
|
||||
* The functions allocate firmware structure and loads all components from
|
||||
* the given buffer specified by @data and @size.
|
||||
*
|
||||
* Return: pointer to firmware on success, error pointer on error
|
||||
*/
|
||||
struct zl3073x_fw *zl3073x_fw_load(struct zl3073x_dev *zldev, const char *data,
|
||||
size_t size, struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct zl3073x_fw_component *comp;
|
||||
enum zl3073x_fw_component_id id;
|
||||
struct zl3073x_fw *fw;
|
||||
ssize_t rc;
|
||||
|
||||
/* Allocate firmware structure */
|
||||
fw = kzalloc(sizeof(*fw), GFP_KERNEL);
|
||||
if (!fw)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
do {
|
||||
/* Load single component */
|
||||
rc = zl3073x_fw_component_load(zldev, &comp, &data, &size,
|
||||
extack);
|
||||
if (rc <= 0)
|
||||
/* Everything was read or error occurred */
|
||||
break;
|
||||
|
||||
id = comp->id;
|
||||
|
||||
/* Report error if the given component is present twice
|
||||
* or more.
|
||||
*/
|
||||
if (fw->component[id]) {
|
||||
ZL3073X_FW_ERR_MSG(extack,
|
||||
"duplicate component '%s' detected",
|
||||
component_info[id].name);
|
||||
zl3073x_fw_component_free(comp);
|
||||
rc = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
fw->component[id] = comp;
|
||||
} while (true);
|
||||
|
||||
if (rc) {
|
||||
/* Free allocated firmware in case of error */
|
||||
zl3073x_fw_free(fw);
|
||||
return ERR_PTR(rc);
|
||||
}
|
||||
|
||||
return fw;
|
||||
}
|
||||
|
||||
/**
|
||||
* zl3073x_flash_bundle_flash - Flash all components
|
||||
* @zldev: zl3073x device structure
|
||||
* @components: pointer to components array
|
||||
* @extack: netlink extack pointer to report errors
|
||||
*
|
||||
* Returns 0 in case of success or negative number otherwise.
|
||||
*/
|
||||
static int
|
||||
zl3073x_fw_component_flash(struct zl3073x_dev *zldev,
|
||||
struct zl3073x_fw_component *comp,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
const struct zl3073x_fw_component_info *info;
|
||||
int rc;
|
||||
|
||||
info = &component_info[comp->id];
|
||||
|
||||
switch (info->flash_type) {
|
||||
case ZL3073X_FLASH_TYPE_NONE:
|
||||
/* Non-flashable component - used for utility */
|
||||
return 0;
|
||||
case ZL3073X_FLASH_TYPE_SECTORS:
|
||||
rc = zl3073x_flash_sectors(zldev, info->name, info->dest_page,
|
||||
info->load_addr, comp->data,
|
||||
comp->size, extack);
|
||||
break;
|
||||
case ZL3073X_FLASH_TYPE_PAGE:
|
||||
rc = zl3073x_flash_page(zldev, info->name, info->dest_page,
|
||||
info->load_addr, comp->data, comp->size,
|
||||
extack);
|
||||
break;
|
||||
case ZL3073X_FLASH_TYPE_PAGE_AND_COPY:
|
||||
rc = zl3073x_flash_page(zldev, info->name, info->dest_page,
|
||||
info->load_addr, comp->data, comp->size,
|
||||
extack);
|
||||
if (!rc)
|
||||
rc = zl3073x_flash_page_copy(zldev, info->name,
|
||||
info->dest_page,
|
||||
info->copy_page, extack);
|
||||
break;
|
||||
}
|
||||
if (rc)
|
||||
ZL3073X_FW_ERR_MSG(extack, "Failed to flash component '%s'",
|
||||
info->name);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int zl3073x_fw_flash(struct zl3073x_dev *zldev, struct zl3073x_fw *zlfw,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
int i, rc = 0;
|
||||
|
||||
for (i = 0; i < ZL_FW_NUM_COMPONENTS; i++) {
|
||||
if (!zlfw->component[i])
|
||||
continue; /* Component is not present */
|
||||
|
||||
rc = zl3073x_fw_component_flash(zldev, zlfw->component[i],
|
||||
extack);
|
||||
if (rc)
|
||||
break;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
52
drivers/dpll/zl3073x/fw.h
Normal file
52
drivers/dpll/zl3073x/fw.h
Normal file
@ -0,0 +1,52 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
|
||||
#ifndef _ZL3073X_FW_H
|
||||
#define _ZL3073X_FW_H
|
||||
|
||||
/*
|
||||
* enum zl3073x_fw_component_id - Identifiers for possible flash components
|
||||
*/
|
||||
enum zl3073x_fw_component_id {
|
||||
ZL_FW_COMPONENT_INVALID = -1,
|
||||
ZL_FW_COMPONENT_UTIL = 0,
|
||||
ZL_FW_COMPONENT_FW1,
|
||||
ZL_FW_COMPONENT_FW2,
|
||||
ZL_FW_COMPONENT_FW3,
|
||||
ZL_FW_COMPONENT_CFG0,
|
||||
ZL_FW_COMPONENT_CFG1,
|
||||
ZL_FW_COMPONENT_CFG2,
|
||||
ZL_FW_COMPONENT_CFG3,
|
||||
ZL_FW_COMPONENT_CFG4,
|
||||
ZL_FW_COMPONENT_CFG5,
|
||||
ZL_FW_COMPONENT_CFG6,
|
||||
ZL_FW_NUM_COMPONENTS
|
||||
};
|
||||
|
||||
/**
|
||||
* struct zl3073x_fw_component - Firmware component
|
||||
* @id: Flash component ID
|
||||
* @size: Size of the buffer
|
||||
* @data: Pointer to buffer with component data
|
||||
*/
|
||||
struct zl3073x_fw_component {
|
||||
enum zl3073x_fw_component_id id;
|
||||
size_t size;
|
||||
void *data;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct zl3073x_fw - Firmware bundle
|
||||
* @component: firmware components array
|
||||
*/
|
||||
struct zl3073x_fw {
|
||||
struct zl3073x_fw_component *component[ZL_FW_NUM_COMPONENTS];
|
||||
};
|
||||
|
||||
struct zl3073x_fw *zl3073x_fw_load(struct zl3073x_dev *zldev, const char *data,
|
||||
size_t size, struct netlink_ext_ack *extack);
|
||||
void zl3073x_fw_free(struct zl3073x_fw *fw);
|
||||
|
||||
int zl3073x_fw_flash(struct zl3073x_dev *zldev, struct zl3073x_fw *zlfw,
|
||||
struct netlink_ext_ack *extack);
|
||||
|
||||
#endif /* _ZL3073X_FW_H */
|
||||
@ -75,6 +75,9 @@
|
||||
#define ZL_REG_FW_VER ZL_REG(0, 0x05, 2)
|
||||
#define ZL_REG_CUSTOM_CONFIG_VER ZL_REG(0, 0x07, 4)
|
||||
|
||||
#define ZL_REG_RESET_STATUS ZL_REG(0, 0x18, 1)
|
||||
#define ZL_REG_RESET_STATUS_RESET BIT(0)
|
||||
|
||||
/*************************
|
||||
* Register Page 2, Status
|
||||
*************************/
|
||||
@ -263,4 +266,52 @@
|
||||
#define ZL_REG_OUTPUT_ESYNC_WIDTH ZL_REG(14, 0x18, 4)
|
||||
#define ZL_REG_OUTPUT_PHASE_COMP ZL_REG(14, 0x20, 4)
|
||||
|
||||
/*
|
||||
* Register Page 255 - HW registers access
|
||||
*/
|
||||
#define ZL_REG_HWREG_OP ZL_REG(0xff, 0x00, 1)
|
||||
#define ZL_HWREG_OP_WRITE 0x28
|
||||
#define ZL_HWREG_OP_READ 0x29
|
||||
#define ZL_HWREG_OP_PENDING BIT(1)
|
||||
|
||||
#define ZL_REG_HWREG_ADDR ZL_REG(0xff, 0x04, 4)
|
||||
#define ZL_REG_HWREG_WRITE_DATA ZL_REG(0xff, 0x08, 4)
|
||||
#define ZL_REG_HWREG_READ_DATA ZL_REG(0xff, 0x0c, 4)
|
||||
|
||||
/*
|
||||
* Registers available in flash mode
|
||||
*/
|
||||
#define ZL_REG_FLASH_HASH ZL_REG(0, 0x78, 4)
|
||||
#define ZL_REG_FLASH_FAMILY ZL_REG(0, 0x7c, 1)
|
||||
#define ZL_REG_FLASH_RELEASE ZL_REG(0, 0x7d, 1)
|
||||
|
||||
#define ZL_REG_HOST_CONTROL ZL_REG(1, 0x02, 1)
|
||||
#define ZL_HOST_CONTROL_ENABLE BIT(0)
|
||||
|
||||
#define ZL_REG_IMAGE_START_ADDR ZL_REG(1, 0x04, 4)
|
||||
#define ZL_REG_IMAGE_SIZE ZL_REG(1, 0x08, 4)
|
||||
#define ZL_REG_FLASH_INDEX_READ ZL_REG(1, 0x0c, 4)
|
||||
#define ZL_REG_FLASH_INDEX_WRITE ZL_REG(1, 0x10, 4)
|
||||
#define ZL_REG_FILL_PATTERN ZL_REG(1, 0x14, 4)
|
||||
|
||||
#define ZL_REG_WRITE_FLASH ZL_REG(1, 0x18, 1)
|
||||
#define ZL_WRITE_FLASH_OP GENMASK(2, 0)
|
||||
#define ZL_WRITE_FLASH_OP_DONE 0x0
|
||||
#define ZL_WRITE_FLASH_OP_SECTORS 0x2
|
||||
#define ZL_WRITE_FLASH_OP_PAGE 0x3
|
||||
#define ZL_WRITE_FLASH_OP_COPY_PAGE 0x4
|
||||
|
||||
#define ZL_REG_FLASH_INFO ZL_REG(2, 0x00, 1)
|
||||
#define ZL_FLASH_INFO_SECTOR_SIZE GENMASK(3, 0)
|
||||
#define ZL_FLASH_INFO_SECTOR_4K 0
|
||||
#define ZL_FLASH_INFO_SECTOR_64K 1
|
||||
|
||||
#define ZL_REG_ERROR_COUNT ZL_REG(2, 0x04, 4)
|
||||
#define ZL_REG_ERROR_CAUSE ZL_REG(2, 0x08, 4)
|
||||
|
||||
#define ZL_REG_OP_STATE ZL_REG(2, 0x14, 1)
|
||||
#define ZL_OP_STATE_NO_COMMAND 0
|
||||
#define ZL_OP_STATE_PENDING 1
|
||||
#define ZL_OP_STATE_DONE 2
|
||||
|
||||
#endif /* _ZL3073X_REGS_H */
|
||||
|
||||
@ -3679,6 +3679,11 @@ static int vmw_cmd_check(struct vmw_private *dev_priv,
|
||||
|
||||
|
||||
cmd_id = header->id;
|
||||
if (header->size > SVGA_CMD_MAX_DATASIZE) {
|
||||
VMW_DEBUG_USER("SVGA3D command: %d is too big.\n",
|
||||
cmd_id + SVGA_3D_CMD_BASE);
|
||||
return -E2BIG;
|
||||
}
|
||||
*size = header->size + sizeof(SVGA3dCmdHeader);
|
||||
|
||||
cmd_id -= SVGA_3D_CMD_BASE;
|
||||
|
||||
@ -1461,6 +1461,14 @@ static const __u8 *mt_report_fixup(struct hid_device *hdev, __u8 *rdesc,
|
||||
if (hdev->vendor == I2C_VENDOR_ID_GOODIX &&
|
||||
(hdev->product == I2C_DEVICE_ID_GOODIX_01E8 ||
|
||||
hdev->product == I2C_DEVICE_ID_GOODIX_01E9)) {
|
||||
if (*size < 608) {
|
||||
dev_info(
|
||||
&hdev->dev,
|
||||
"GT7868Q fixup: report descriptor is only %u bytes, skipping\n",
|
||||
*size);
|
||||
return rdesc;
|
||||
}
|
||||
|
||||
if (rdesc[607] == 0x15) {
|
||||
rdesc[607] = 0x25;
|
||||
dev_info(
|
||||
|
||||
@ -76,6 +76,13 @@ static int i2c_hid_acpi_get_descriptor(struct i2c_hid_acpi *ihid_acpi)
|
||||
return hid_descriptor_address;
|
||||
}
|
||||
|
||||
static void i2c_hid_acpi_restore_sequence(struct i2chid_ops *ops)
|
||||
{
|
||||
struct i2c_hid_acpi *ihid_acpi = container_of(ops, struct i2c_hid_acpi, ops);
|
||||
|
||||
i2c_hid_acpi_get_descriptor(ihid_acpi);
|
||||
}
|
||||
|
||||
static void i2c_hid_acpi_shutdown_tail(struct i2chid_ops *ops)
|
||||
{
|
||||
struct i2c_hid_acpi *ihid_acpi = container_of(ops, struct i2c_hid_acpi, ops);
|
||||
@ -96,6 +103,7 @@ static int i2c_hid_acpi_probe(struct i2c_client *client)
|
||||
|
||||
ihid_acpi->adev = ACPI_COMPANION(dev);
|
||||
ihid_acpi->ops.shutdown_tail = i2c_hid_acpi_shutdown_tail;
|
||||
ihid_acpi->ops.restore_sequence = i2c_hid_acpi_restore_sequence;
|
||||
|
||||
ret = i2c_hid_acpi_get_descriptor(ihid_acpi);
|
||||
if (ret < 0)
|
||||
|
||||
@ -961,6 +961,14 @@ static void i2c_hid_core_shutdown_tail(struct i2c_hid *ihid)
|
||||
ihid->ops->shutdown_tail(ihid->ops);
|
||||
}
|
||||
|
||||
static void i2c_hid_core_restore_sequence(struct i2c_hid *ihid)
|
||||
{
|
||||
if (!ihid->ops->restore_sequence)
|
||||
return;
|
||||
|
||||
ihid->ops->restore_sequence(ihid->ops);
|
||||
}
|
||||
|
||||
static int i2c_hid_core_suspend(struct i2c_hid *ihid, bool force_poweroff)
|
||||
{
|
||||
struct i2c_client *client = ihid->client;
|
||||
@ -1360,8 +1368,26 @@ static int i2c_hid_core_pm_resume(struct device *dev)
|
||||
return i2c_hid_core_resume(ihid);
|
||||
}
|
||||
|
||||
static int i2c_hid_core_pm_restore(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct i2c_hid *ihid = i2c_get_clientdata(client);
|
||||
|
||||
if (ihid->is_panel_follower)
|
||||
return 0;
|
||||
|
||||
i2c_hid_core_restore_sequence(ihid);
|
||||
|
||||
return i2c_hid_core_resume(ihid);
|
||||
}
|
||||
|
||||
const struct dev_pm_ops i2c_hid_core_pm = {
|
||||
SYSTEM_SLEEP_PM_OPS(i2c_hid_core_pm_suspend, i2c_hid_core_pm_resume)
|
||||
.suspend = pm_sleep_ptr(i2c_hid_core_pm_suspend),
|
||||
.resume = pm_sleep_ptr(i2c_hid_core_pm_resume),
|
||||
.freeze = pm_sleep_ptr(i2c_hid_core_pm_suspend),
|
||||
.thaw = pm_sleep_ptr(i2c_hid_core_pm_resume),
|
||||
.poweroff = pm_sleep_ptr(i2c_hid_core_pm_suspend),
|
||||
.restore = pm_sleep_ptr(i2c_hid_core_pm_restore),
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(i2c_hid_core_pm);
|
||||
|
||||
|
||||
@ -27,11 +27,13 @@ static inline u32 i2c_hid_get_dmi_quirks(const u16 vendor, const u16 product)
|
||||
* @power_up: do sequencing to power up the device.
|
||||
* @power_down: do sequencing to power down the device.
|
||||
* @shutdown_tail: called at the end of shutdown.
|
||||
* @restore_sequence: hibernation restore sequence.
|
||||
*/
|
||||
struct i2chid_ops {
|
||||
int (*power_up)(struct i2chid_ops *ops);
|
||||
void (*power_down)(struct i2chid_ops *ops);
|
||||
void (*shutdown_tail)(struct i2chid_ops *ops);
|
||||
void (*restore_sequence)(struct i2chid_ops *ops);
|
||||
};
|
||||
|
||||
int i2c_hid_core_probe(struct i2c_client *client, struct i2chid_ops *ops,
|
||||
|
||||
@ -439,12 +439,12 @@ static int iommufd_eventq_init(struct iommufd_eventq *eventq, char *name,
|
||||
const struct file_operations *fops)
|
||||
{
|
||||
struct file *filep;
|
||||
int fdno;
|
||||
|
||||
spin_lock_init(&eventq->lock);
|
||||
INIT_LIST_HEAD(&eventq->deliver);
|
||||
init_waitqueue_head(&eventq->wait_queue);
|
||||
|
||||
/* The filep is fput() by the core code during failure */
|
||||
filep = anon_inode_getfile(name, fops, eventq, O_RDWR);
|
||||
if (IS_ERR(filep))
|
||||
return PTR_ERR(filep);
|
||||
@ -454,10 +454,7 @@ static int iommufd_eventq_init(struct iommufd_eventq *eventq, char *name,
|
||||
eventq->filep = filep;
|
||||
refcount_inc(&eventq->obj.users);
|
||||
|
||||
fdno = get_unused_fd_flags(O_CLOEXEC);
|
||||
if (fdno < 0)
|
||||
fput(filep);
|
||||
return fdno;
|
||||
return get_unused_fd_flags(O_CLOEXEC);
|
||||
}
|
||||
|
||||
static const struct file_operations iommufd_fault_fops =
|
||||
@ -501,7 +498,6 @@ int iommufd_fault_alloc(struct iommufd_ucmd *ucmd)
|
||||
return 0;
|
||||
out_put_fdno:
|
||||
put_unused_fd(fdno);
|
||||
fput(fault->common.filep);
|
||||
out_abort:
|
||||
iommufd_object_abort_and_destroy(ucmd->ictx, &fault->common.obj);
|
||||
|
||||
@ -588,7 +584,6 @@ int iommufd_veventq_alloc(struct iommufd_ucmd *ucmd)
|
||||
|
||||
out_put_fdno:
|
||||
put_unused_fd(fdno);
|
||||
fput(veventq->common.filep);
|
||||
out_abort:
|
||||
iommufd_object_abort_and_destroy(ucmd->ictx, &veventq->common.obj);
|
||||
out_unlock_veventqs:
|
||||
|
||||
@ -23,6 +23,7 @@
|
||||
#include "iommufd_test.h"
|
||||
|
||||
struct iommufd_object_ops {
|
||||
size_t file_offset;
|
||||
void (*destroy)(struct iommufd_object *obj);
|
||||
void (*abort)(struct iommufd_object *obj);
|
||||
};
|
||||
@ -71,10 +72,30 @@ void iommufd_object_abort(struct iommufd_ctx *ictx, struct iommufd_object *obj)
|
||||
void iommufd_object_abort_and_destroy(struct iommufd_ctx *ictx,
|
||||
struct iommufd_object *obj)
|
||||
{
|
||||
if (iommufd_object_ops[obj->type].abort)
|
||||
iommufd_object_ops[obj->type].abort(obj);
|
||||
const struct iommufd_object_ops *ops = &iommufd_object_ops[obj->type];
|
||||
|
||||
if (ops->file_offset) {
|
||||
struct file **filep = ((void *)obj) + ops->file_offset;
|
||||
|
||||
/*
|
||||
* A file should hold a users refcount while the file is open
|
||||
* and put it back in its release. The file should hold a
|
||||
* pointer to obj in their private data. Normal fput() is
|
||||
* deferred to a workqueue and can get out of order with the
|
||||
* following kfree(obj). Using the sync version ensures the
|
||||
* release happens immediately. During abort we require the file
|
||||
* refcount is one at this point - meaning the object alloc
|
||||
* function cannot do anything to allow another thread to take a
|
||||
* refcount prior to a guaranteed success.
|
||||
*/
|
||||
if (*filep)
|
||||
__fput_sync(*filep);
|
||||
}
|
||||
|
||||
if (ops->abort)
|
||||
ops->abort(obj);
|
||||
else
|
||||
iommufd_object_ops[obj->type].destroy(obj);
|
||||
ops->destroy(obj);
|
||||
iommufd_object_abort(ictx, obj);
|
||||
}
|
||||
|
||||
@ -493,6 +514,12 @@ void iommufd_ctx_put(struct iommufd_ctx *ictx)
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(iommufd_ctx_put, "IOMMUFD");
|
||||
|
||||
#define IOMMUFD_FILE_OFFSET(_struct, _filep, _obj) \
|
||||
.file_offset = (offsetof(_struct, _filep) + \
|
||||
BUILD_BUG_ON_ZERO(!__same_type( \
|
||||
struct file *, ((_struct *)NULL)->_filep)) + \
|
||||
BUILD_BUG_ON_ZERO(offsetof(_struct, _obj)))
|
||||
|
||||
static const struct iommufd_object_ops iommufd_object_ops[] = {
|
||||
[IOMMUFD_OBJ_ACCESS] = {
|
||||
.destroy = iommufd_access_destroy_object,
|
||||
@ -502,6 +529,7 @@ static const struct iommufd_object_ops iommufd_object_ops[] = {
|
||||
},
|
||||
[IOMMUFD_OBJ_FAULT] = {
|
||||
.destroy = iommufd_fault_destroy,
|
||||
IOMMUFD_FILE_OFFSET(struct iommufd_fault, common.filep, common.obj),
|
||||
},
|
||||
[IOMMUFD_OBJ_HWPT_PAGING] = {
|
||||
.destroy = iommufd_hwpt_paging_destroy,
|
||||
@ -520,6 +548,7 @@ static const struct iommufd_object_ops iommufd_object_ops[] = {
|
||||
[IOMMUFD_OBJ_VEVENTQ] = {
|
||||
.destroy = iommufd_veventq_destroy,
|
||||
.abort = iommufd_veventq_abort,
|
||||
IOMMUFD_FILE_OFFSET(struct iommufd_veventq, common.filep, common.obj),
|
||||
},
|
||||
[IOMMUFD_OBJ_VIOMMU] = {
|
||||
.destroy = iommufd_viommu_destroy,
|
||||
|
||||
@ -67,6 +67,8 @@ struct phylink {
|
||||
struct timer_list link_poll;
|
||||
|
||||
struct mutex state_mutex;
|
||||
/* Serialize updates to pl->phydev with phylink_resolve() */
|
||||
struct mutex phydev_mutex;
|
||||
struct phylink_link_state phy_state;
|
||||
unsigned int phy_ib_mode;
|
||||
struct work_struct resolve;
|
||||
@ -1588,8 +1590,11 @@ static void phylink_resolve(struct work_struct *w)
|
||||
struct phylink_link_state link_state;
|
||||
bool mac_config = false;
|
||||
bool retrigger = false;
|
||||
struct phy_device *phy;
|
||||
bool cur_link_state;
|
||||
|
||||
mutex_lock(&pl->phydev_mutex);
|
||||
phy = pl->phydev;
|
||||
mutex_lock(&pl->state_mutex);
|
||||
cur_link_state = phylink_link_is_up(pl);
|
||||
|
||||
@ -1623,11 +1628,11 @@ static void phylink_resolve(struct work_struct *w)
|
||||
/* If we have a phy, the "up" state is the union of both the
|
||||
* PHY and the MAC
|
||||
*/
|
||||
if (pl->phydev)
|
||||
if (phy)
|
||||
link_state.link &= pl->phy_state.link;
|
||||
|
||||
/* Only update if the PHY link is up */
|
||||
if (pl->phydev && pl->phy_state.link) {
|
||||
if (phy && pl->phy_state.link) {
|
||||
/* If the interface has changed, force a link down
|
||||
* event if the link isn't already down, and re-resolve.
|
||||
*/
|
||||
@ -1691,6 +1696,7 @@ static void phylink_resolve(struct work_struct *w)
|
||||
queue_work(system_power_efficient_wq, &pl->resolve);
|
||||
}
|
||||
mutex_unlock(&pl->state_mutex);
|
||||
mutex_unlock(&pl->phydev_mutex);
|
||||
}
|
||||
|
||||
static void phylink_run_resolve(struct phylink *pl)
|
||||
@ -1826,6 +1832,7 @@ struct phylink *phylink_create(struct phylink_config *config,
|
||||
if (!pl)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
mutex_init(&pl->phydev_mutex);
|
||||
mutex_init(&pl->state_mutex);
|
||||
INIT_WORK(&pl->resolve, phylink_resolve);
|
||||
|
||||
@ -2086,6 +2093,7 @@ static int phylink_bringup_phy(struct phylink *pl, struct phy_device *phy,
|
||||
dev_name(&phy->mdio.dev), phy->drv->name, irq_str);
|
||||
kfree(irq_str);
|
||||
|
||||
mutex_lock(&pl->phydev_mutex);
|
||||
mutex_lock(&phy->lock);
|
||||
mutex_lock(&pl->state_mutex);
|
||||
pl->phydev = phy;
|
||||
@ -2131,6 +2139,7 @@ static int phylink_bringup_phy(struct phylink *pl, struct phy_device *phy,
|
||||
|
||||
mutex_unlock(&pl->state_mutex);
|
||||
mutex_unlock(&phy->lock);
|
||||
mutex_unlock(&pl->phydev_mutex);
|
||||
|
||||
phylink_dbg(pl,
|
||||
"phy: %s setting supported %*pb advertising %*pb\n",
|
||||
@ -2309,6 +2318,7 @@ void phylink_disconnect_phy(struct phylink *pl)
|
||||
|
||||
ASSERT_RTNL();
|
||||
|
||||
mutex_lock(&pl->phydev_mutex);
|
||||
phy = pl->phydev;
|
||||
if (phy) {
|
||||
mutex_lock(&phy->lock);
|
||||
@ -2318,8 +2328,11 @@ void phylink_disconnect_phy(struct phylink *pl)
|
||||
pl->mac_tx_clk_stop = false;
|
||||
mutex_unlock(&pl->state_mutex);
|
||||
mutex_unlock(&phy->lock);
|
||||
flush_work(&pl->resolve);
|
||||
}
|
||||
mutex_unlock(&pl->phydev_mutex);
|
||||
|
||||
if (phy) {
|
||||
flush_work(&pl->resolve);
|
||||
phy_disconnect(phy);
|
||||
}
|
||||
}
|
||||
|
||||
@ -94,6 +94,7 @@ static int __dwc3_gadget_ep0_queue(struct dwc3_ep *dep,
|
||||
req->request.actual = 0;
|
||||
req->request.status = -EINPROGRESS;
|
||||
req->epnum = dep->number;
|
||||
req->status = DWC3_REQUEST_STATUS_QUEUED;
|
||||
|
||||
list_add_tail(&req->list, &dep->pending_list);
|
||||
|
||||
|
||||
@ -228,6 +228,13 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
|
||||
{
|
||||
struct dwc3 *dwc = dep->dwc;
|
||||
|
||||
/*
|
||||
* The request might have been processed and completed while the
|
||||
* spinlock was released. Skip processing if already completed.
|
||||
*/
|
||||
if (req->status == DWC3_REQUEST_STATUS_COMPLETED)
|
||||
return;
|
||||
|
||||
dwc3_gadget_del_and_unmap_request(dep, req, status);
|
||||
req->status = DWC3_REQUEST_STATUS_COMPLETED;
|
||||
|
||||
|
||||
@ -615,6 +615,8 @@ extern int E_md4hash(const unsigned char *passwd, unsigned char *p16,
|
||||
extern struct TCP_Server_Info *
|
||||
cifs_find_tcp_session(struct smb3_fs_context *ctx);
|
||||
|
||||
struct cifs_tcon *cifs_setup_ipc(struct cifs_ses *ses, bool seal);
|
||||
|
||||
void __cifs_put_smb_ses(struct cifs_ses *ses);
|
||||
|
||||
extern struct cifs_ses *
|
||||
|
||||
@ -2015,39 +2015,31 @@ static int match_session(struct cifs_ses *ses,
|
||||
/**
|
||||
* cifs_setup_ipc - helper to setup the IPC tcon for the session
|
||||
* @ses: smb session to issue the request on
|
||||
* @ctx: the superblock configuration context to use for building the
|
||||
* new tree connection for the IPC (interprocess communication RPC)
|
||||
* @seal: if encryption is requested
|
||||
*
|
||||
* A new IPC connection is made and stored in the session
|
||||
* tcon_ipc. The IPC tcon has the same lifetime as the session.
|
||||
*/
|
||||
static int
|
||||
cifs_setup_ipc(struct cifs_ses *ses, struct smb3_fs_context *ctx)
|
||||
struct cifs_tcon *cifs_setup_ipc(struct cifs_ses *ses, bool seal)
|
||||
{
|
||||
int rc = 0, xid;
|
||||
struct cifs_tcon *tcon;
|
||||
char unc[SERVER_NAME_LENGTH + sizeof("//x/IPC$")] = {0};
|
||||
bool seal = false;
|
||||
struct TCP_Server_Info *server = ses->server;
|
||||
|
||||
/*
|
||||
* If the mount request that resulted in the creation of the
|
||||
* session requires encryption, force IPC to be encrypted too.
|
||||
*/
|
||||
if (ctx->seal) {
|
||||
if (server->capabilities & SMB2_GLOBAL_CAP_ENCRYPTION)
|
||||
seal = true;
|
||||
else {
|
||||
cifs_server_dbg(VFS,
|
||||
"IPC: server doesn't support encryption\n");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
if (seal && !(server->capabilities & SMB2_GLOBAL_CAP_ENCRYPTION)) {
|
||||
cifs_server_dbg(VFS, "IPC: server doesn't support encryption\n");
|
||||
return ERR_PTR(-EOPNOTSUPP);
|
||||
}
|
||||
|
||||
/* no need to setup directory caching on IPC share, so pass in false */
|
||||
tcon = tcon_info_alloc(false, netfs_trace_tcon_ref_new_ipc);
|
||||
if (tcon == NULL)
|
||||
return -ENOMEM;
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
spin_lock(&server->srv_lock);
|
||||
scnprintf(unc, sizeof(unc), "\\\\%s\\IPC$", server->hostname);
|
||||
@ -2057,13 +2049,13 @@ cifs_setup_ipc(struct cifs_ses *ses, struct smb3_fs_context *ctx)
|
||||
tcon->ses = ses;
|
||||
tcon->ipc = true;
|
||||
tcon->seal = seal;
|
||||
rc = server->ops->tree_connect(xid, ses, unc, tcon, ctx->local_nls);
|
||||
rc = server->ops->tree_connect(xid, ses, unc, tcon, ses->local_nls);
|
||||
free_xid(xid);
|
||||
|
||||
if (rc) {
|
||||
cifs_server_dbg(VFS, "failed to connect to IPC (rc=%d)\n", rc);
|
||||
cifs_server_dbg(VFS | ONCE, "failed to connect to IPC (rc=%d)\n", rc);
|
||||
tconInfoFree(tcon, netfs_trace_tcon_ref_free_ipc_fail);
|
||||
goto out;
|
||||
return ERR_PTR(rc);
|
||||
}
|
||||
|
||||
cifs_dbg(FYI, "IPC tcon rc=%d ipc tid=0x%x\n", rc, tcon->tid);
|
||||
@ -2071,9 +2063,7 @@ cifs_setup_ipc(struct cifs_ses *ses, struct smb3_fs_context *ctx)
|
||||
spin_lock(&tcon->tc_lock);
|
||||
tcon->status = TID_GOOD;
|
||||
spin_unlock(&tcon->tc_lock);
|
||||
ses->tcon_ipc = tcon;
|
||||
out:
|
||||
return rc;
|
||||
return tcon;
|
||||
}
|
||||
|
||||
static struct cifs_ses *
|
||||
@ -2347,6 +2337,7 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx)
|
||||
{
|
||||
struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&server->dstaddr;
|
||||
struct sockaddr_in *addr = (struct sockaddr_in *)&server->dstaddr;
|
||||
struct cifs_tcon *ipc;
|
||||
struct cifs_ses *ses;
|
||||
unsigned int xid;
|
||||
int retries = 0;
|
||||
@ -2525,7 +2516,12 @@ retry_new_session:
|
||||
list_add(&ses->smb_ses_list, &server->smb_ses_list);
|
||||
spin_unlock(&cifs_tcp_ses_lock);
|
||||
|
||||
cifs_setup_ipc(ses, ctx);
|
||||
ipc = cifs_setup_ipc(ses, ctx->seal);
|
||||
spin_lock(&cifs_tcp_ses_lock);
|
||||
spin_lock(&ses->ses_lock);
|
||||
ses->tcon_ipc = !IS_ERR(ipc) ? ipc : NULL;
|
||||
spin_unlock(&ses->ses_lock);
|
||||
spin_unlock(&cifs_tcp_ses_lock);
|
||||
|
||||
free_xid(xid);
|
||||
|
||||
|
||||
@ -1120,24 +1120,63 @@ static bool target_share_equal(struct cifs_tcon *tcon, const char *s1)
|
||||
return match;
|
||||
}
|
||||
|
||||
static bool is_ses_good(struct cifs_ses *ses)
|
||||
static bool is_ses_good(struct cifs_tcon *tcon, struct cifs_ses *ses)
|
||||
{
|
||||
struct TCP_Server_Info *server = ses->server;
|
||||
struct cifs_tcon *tcon = ses->tcon_ipc;
|
||||
struct cifs_tcon *ipc = NULL;
|
||||
bool ret;
|
||||
|
||||
spin_lock(&cifs_tcp_ses_lock);
|
||||
spin_lock(&ses->ses_lock);
|
||||
spin_lock(&ses->chan_lock);
|
||||
|
||||
ret = !cifs_chan_needs_reconnect(ses, server) &&
|
||||
ses->ses_status == SES_GOOD &&
|
||||
!tcon->need_reconnect;
|
||||
ses->ses_status == SES_GOOD;
|
||||
|
||||
spin_unlock(&ses->chan_lock);
|
||||
|
||||
if (!ret)
|
||||
goto out;
|
||||
|
||||
if (likely(ses->tcon_ipc)) {
|
||||
if (ses->tcon_ipc->need_reconnect) {
|
||||
ret = false;
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
spin_unlock(&ses->ses_lock);
|
||||
spin_unlock(&cifs_tcp_ses_lock);
|
||||
|
||||
ipc = cifs_setup_ipc(ses, tcon->seal);
|
||||
|
||||
spin_lock(&cifs_tcp_ses_lock);
|
||||
spin_lock(&ses->ses_lock);
|
||||
if (!IS_ERR(ipc)) {
|
||||
if (!ses->tcon_ipc) {
|
||||
ses->tcon_ipc = ipc;
|
||||
ipc = NULL;
|
||||
}
|
||||
} else {
|
||||
ret = false;
|
||||
ipc = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
spin_unlock(&ses->ses_lock);
|
||||
spin_unlock(&cifs_tcp_ses_lock);
|
||||
if (ipc && server->ops->tree_disconnect) {
|
||||
unsigned int xid = get_xid();
|
||||
|
||||
(void)server->ops->tree_disconnect(xid, ipc);
|
||||
_free_xid(xid);
|
||||
}
|
||||
tconInfoFree(ipc, netfs_trace_tcon_ref_free_ipc);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Refresh dfs referral of @ses */
|
||||
static void refresh_ses_referral(struct cifs_ses *ses)
|
||||
static void refresh_ses_referral(struct cifs_tcon *tcon, struct cifs_ses *ses)
|
||||
{
|
||||
struct cache_entry *ce;
|
||||
unsigned int xid;
|
||||
@ -1153,7 +1192,7 @@ static void refresh_ses_referral(struct cifs_ses *ses)
|
||||
}
|
||||
|
||||
ses = CIFS_DFS_ROOT_SES(ses);
|
||||
if (!is_ses_good(ses)) {
|
||||
if (!is_ses_good(tcon, ses)) {
|
||||
cifs_dbg(FYI, "%s: skip cache refresh due to disconnected ipc\n",
|
||||
__func__);
|
||||
goto out;
|
||||
@ -1241,7 +1280,7 @@ static void refresh_tcon_referral(struct cifs_tcon *tcon, bool force_refresh)
|
||||
up_read(&htable_rw_lock);
|
||||
|
||||
ses = CIFS_DFS_ROOT_SES(ses);
|
||||
if (!is_ses_good(ses)) {
|
||||
if (!is_ses_good(tcon, ses)) {
|
||||
cifs_dbg(FYI, "%s: skip cache refresh due to disconnected ipc\n",
|
||||
__func__);
|
||||
goto out;
|
||||
@ -1309,7 +1348,7 @@ void dfs_cache_refresh(struct work_struct *work)
|
||||
tcon = container_of(work, struct cifs_tcon, dfs_cache_work.work);
|
||||
|
||||
list_for_each_entry(ses, &tcon->dfs_ses_list, dlist)
|
||||
refresh_ses_referral(ses);
|
||||
refresh_ses_referral(tcon, ses);
|
||||
refresh_tcon_referral(tcon, false);
|
||||
|
||||
queue_delayed_work(dfscache_wq, &tcon->dfs_cache_work,
|
||||
|
||||
@ -217,7 +217,21 @@ enum node_stat_item {
|
||||
#endif
|
||||
#ifdef CONFIG_NUMA_BALANCING
|
||||
PGPROMOTE_SUCCESS, /* promote successfully */
|
||||
PGPROMOTE_CANDIDATE, /* candidate pages to promote */
|
||||
/**
|
||||
* Candidate pages for promotion based on hint fault latency. This
|
||||
* counter is used to control the promotion rate and adjust the hot
|
||||
* threshold.
|
||||
*/
|
||||
PGPROMOTE_CANDIDATE,
|
||||
/**
|
||||
* Not rate-limited (NRL) candidate pages for those can be promoted
|
||||
* without considering hot threshold because of enough free pages in
|
||||
* fast-tier node. These promotions bypass the regular hotness checks
|
||||
* and do NOT influence the promotion rate-limiter or
|
||||
* threshold-adjustment logic.
|
||||
* This is for statistics/monitoring purposes.
|
||||
*/
|
||||
RH_KABI_BROKEN_INSERT_ENUM(PGPROMOTE_CANDIDATE_NRL)
|
||||
#endif
|
||||
/* PGDEMOTE_*: pages demoted */
|
||||
PGDEMOTE_KSWAPD,
|
||||
|
||||
@ -96,30 +96,28 @@ static inline struct in6_addr *inetpeer_get_addr_v6(struct inetpeer_addr *iaddr)
|
||||
|
||||
/* can be called with or without local BH being disabled */
|
||||
struct inet_peer *inet_getpeer(struct inet_peer_base *base,
|
||||
const struct inetpeer_addr *daddr,
|
||||
int create);
|
||||
const struct inetpeer_addr *daddr);
|
||||
|
||||
static inline struct inet_peer *inet_getpeer_v4(struct inet_peer_base *base,
|
||||
__be32 v4daddr,
|
||||
int vif, int create)
|
||||
int vif)
|
||||
{
|
||||
struct inetpeer_addr daddr;
|
||||
|
||||
daddr.a4.addr = v4daddr;
|
||||
daddr.a4.vif = vif;
|
||||
daddr.family = AF_INET;
|
||||
return inet_getpeer(base, &daddr, create);
|
||||
return inet_getpeer(base, &daddr);
|
||||
}
|
||||
|
||||
static inline struct inet_peer *inet_getpeer_v6(struct inet_peer_base *base,
|
||||
const struct in6_addr *v6daddr,
|
||||
int create)
|
||||
const struct in6_addr *v6daddr)
|
||||
{
|
||||
struct inetpeer_addr daddr;
|
||||
|
||||
daddr.a6 = *v6daddr;
|
||||
daddr.family = AF_INET6;
|
||||
return inet_getpeer(base, &daddr, create);
|
||||
return inet_getpeer(base, &daddr);
|
||||
}
|
||||
|
||||
static inline int inetpeer_addr_cmp(const struct inetpeer_addr *a,
|
||||
|
||||
@ -22,6 +22,7 @@ TRACE_EVENT(kmem_cache_alloc,
|
||||
TP_STRUCT__entry(
|
||||
__field( unsigned long, call_site )
|
||||
__field( const void *, ptr )
|
||||
__string( name, s->name )
|
||||
__field( size_t, bytes_req )
|
||||
__field( size_t, bytes_alloc )
|
||||
__field( unsigned long, gfp_flags )
|
||||
@ -32,6 +33,7 @@ TRACE_EVENT(kmem_cache_alloc,
|
||||
TP_fast_assign(
|
||||
__entry->call_site = call_site;
|
||||
__entry->ptr = ptr;
|
||||
__assign_str(name);
|
||||
__entry->bytes_req = s->object_size;
|
||||
__entry->bytes_alloc = s->size;
|
||||
__entry->gfp_flags = (__force unsigned long)gfp_flags;
|
||||
@ -41,9 +43,10 @@ TRACE_EVENT(kmem_cache_alloc,
|
||||
(s->flags & SLAB_ACCOUNT)) : false;
|
||||
),
|
||||
|
||||
TP_printk("call_site=%pS ptr=%p bytes_req=%zu bytes_alloc=%zu gfp_flags=%s node=%d accounted=%s",
|
||||
TP_printk("call_site=%pS ptr=%p name=%s bytes_req=%zu bytes_alloc=%zu gfp_flags=%s node=%d accounted=%s",
|
||||
(void *)__entry->call_site,
|
||||
__entry->ptr,
|
||||
__get_str(name),
|
||||
__entry->bytes_req,
|
||||
__entry->bytes_alloc,
|
||||
show_gfp_flags(__entry->gfp_flags),
|
||||
|
||||
@ -1326,7 +1326,7 @@ int audit_compare_dname_path(const struct qstr *dname, const char *path, int par
|
||||
|
||||
/* handle trailing slashes */
|
||||
pathlen -= parentlen;
|
||||
while (p[pathlen - 1] == '/')
|
||||
while (pathlen > 0 && p[pathlen - 1] == '/')
|
||||
pathlen--;
|
||||
|
||||
if (pathlen != dlen)
|
||||
|
||||
@ -1564,10 +1564,12 @@ throttle:
|
||||
}
|
||||
|
||||
if (unlikely(is_dl_boosted(dl_se) || !start_dl_timer(dl_se))) {
|
||||
if (dl_server(dl_se))
|
||||
enqueue_dl_entity(dl_se, ENQUEUE_REPLENISH);
|
||||
else
|
||||
if (dl_server(dl_se)) {
|
||||
replenish_dl_new_period(dl_se, rq);
|
||||
start_dl_timer(dl_se);
|
||||
} else {
|
||||
enqueue_task_dl(rq, dl_task_of(dl_se), ENQUEUE_REPLENISH);
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_leftmost(dl_se, &rq->dl))
|
||||
|
||||
@ -1936,11 +1936,13 @@ bool should_numa_migrate_memory(struct task_struct *p, struct folio *folio,
|
||||
struct pglist_data *pgdat;
|
||||
unsigned long rate_limit;
|
||||
unsigned int latency, th, def_th;
|
||||
long nr = folio_nr_pages(folio);
|
||||
|
||||
pgdat = NODE_DATA(dst_nid);
|
||||
if (pgdat_free_space_enough(pgdat)) {
|
||||
/* workload changed, reset hot threshold */
|
||||
pgdat->nbp_threshold = 0;
|
||||
mod_node_page_state(pgdat, PGPROMOTE_CANDIDATE_NRL, nr);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1954,8 +1956,7 @@ bool should_numa_migrate_memory(struct task_struct *p, struct folio *folio,
|
||||
if (latency >= th)
|
||||
return false;
|
||||
|
||||
return !numa_promotion_rate_limit(pgdat, rate_limit,
|
||||
folio_nr_pages(folio));
|
||||
return !numa_promotion_rate_limit(pgdat, rate_limit, nr);
|
||||
}
|
||||
|
||||
this_cpupid = cpu_pid_to_cpupid(dst_cpu, current->pid);
|
||||
|
||||
30
mm/slub.c
30
mm/slub.c
@ -925,19 +925,19 @@ static struct track *get_track(struct kmem_cache *s, void *object,
|
||||
}
|
||||
|
||||
#ifdef CONFIG_STACKDEPOT
|
||||
static noinline depot_stack_handle_t set_track_prepare(void)
|
||||
static noinline depot_stack_handle_t set_track_prepare(gfp_t gfp_flags)
|
||||
{
|
||||
depot_stack_handle_t handle;
|
||||
unsigned long entries[TRACK_ADDRS_COUNT];
|
||||
unsigned int nr_entries;
|
||||
|
||||
nr_entries = stack_trace_save(entries, ARRAY_SIZE(entries), 3);
|
||||
handle = stack_depot_save(entries, nr_entries, GFP_NOWAIT);
|
||||
handle = stack_depot_save(entries, nr_entries, gfp_flags);
|
||||
|
||||
return handle;
|
||||
}
|
||||
#else
|
||||
static inline depot_stack_handle_t set_track_prepare(void)
|
||||
static inline depot_stack_handle_t set_track_prepare(gfp_t gfp_flags)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@ -959,9 +959,9 @@ static void set_track_update(struct kmem_cache *s, void *object,
|
||||
}
|
||||
|
||||
static __always_inline void set_track(struct kmem_cache *s, void *object,
|
||||
enum track_item alloc, unsigned long addr)
|
||||
enum track_item alloc, unsigned long addr, gfp_t gfp_flags)
|
||||
{
|
||||
depot_stack_handle_t handle = set_track_prepare();
|
||||
depot_stack_handle_t handle = set_track_prepare(gfp_flags);
|
||||
|
||||
set_track_update(s, object, alloc, addr, handle);
|
||||
}
|
||||
@ -1868,9 +1868,9 @@ static inline bool free_debug_processing(struct kmem_cache *s,
|
||||
static inline void slab_pad_check(struct kmem_cache *s, struct slab *slab) {}
|
||||
static inline int check_object(struct kmem_cache *s, struct slab *slab,
|
||||
void *object, u8 val) { return 1; }
|
||||
static inline depot_stack_handle_t set_track_prepare(void) { return 0; }
|
||||
static inline depot_stack_handle_t set_track_prepare(gfp_t gfp_flags) { return 0; }
|
||||
static inline void set_track(struct kmem_cache *s, void *object,
|
||||
enum track_item alloc, unsigned long addr) {}
|
||||
enum track_item alloc, unsigned long addr, gfp_t gfp_flags) {}
|
||||
static inline void add_full(struct kmem_cache *s, struct kmem_cache_node *n,
|
||||
struct slab *slab) {}
|
||||
static inline void remove_full(struct kmem_cache *s, struct kmem_cache_node *n,
|
||||
@ -3831,9 +3831,14 @@ new_objects:
|
||||
* For debug caches here we had to go through
|
||||
* alloc_single_from_partial() so just store the
|
||||
* tracking info and return the object.
|
||||
*
|
||||
* Due to disabled preemption we need to disallow
|
||||
* blocking. The flags are further adjusted by
|
||||
* gfp_nested_mask() in stack_depot itself.
|
||||
*/
|
||||
if (s->flags & SLAB_STORE_USER)
|
||||
set_track(s, freelist, TRACK_ALLOC, addr);
|
||||
set_track(s, freelist, TRACK_ALLOC, addr,
|
||||
gfpflags & ~(__GFP_DIRECT_RECLAIM));
|
||||
|
||||
return freelist;
|
||||
}
|
||||
@ -3865,7 +3870,8 @@ new_objects:
|
||||
goto new_objects;
|
||||
|
||||
if (s->flags & SLAB_STORE_USER)
|
||||
set_track(s, freelist, TRACK_ALLOC, addr);
|
||||
set_track(s, freelist, TRACK_ALLOC, addr,
|
||||
gfpflags & ~(__GFP_DIRECT_RECLAIM));
|
||||
|
||||
return freelist;
|
||||
}
|
||||
@ -4370,8 +4376,12 @@ static noinline void free_to_partial_list(
|
||||
unsigned long flags;
|
||||
depot_stack_handle_t handle = 0;
|
||||
|
||||
/*
|
||||
* We cannot use GFP_NOWAIT as there are callsites where waking up
|
||||
* kswapd could deadlock
|
||||
*/
|
||||
if (s->flags & SLAB_STORE_USER)
|
||||
handle = set_track_prepare();
|
||||
handle = set_track_prepare(__GFP_NOWARN);
|
||||
|
||||
spin_lock_irqsave(&n->list_lock, flags);
|
||||
|
||||
|
||||
@ -1269,6 +1269,7 @@ const char * const vmstat_text[] = {
|
||||
#ifdef CONFIG_NUMA_BALANCING
|
||||
"pgpromote_success",
|
||||
"pgpromote_candidate",
|
||||
"pgpromote_candidate_nrl",
|
||||
#endif
|
||||
"pgdemote_kswapd",
|
||||
"pgdemote_direct",
|
||||
|
||||
@ -312,7 +312,6 @@ static bool icmpv4_xrlim_allow(struct net *net, struct rtable *rt,
|
||||
struct dst_entry *dst = &rt->dst;
|
||||
struct inet_peer *peer;
|
||||
bool rc = true;
|
||||
int vif;
|
||||
|
||||
if (!apply_ratelimit)
|
||||
return true;
|
||||
@ -321,12 +320,12 @@ static bool icmpv4_xrlim_allow(struct net *net, struct rtable *rt,
|
||||
if (dst->dev && (dst->dev->flags&IFF_LOOPBACK))
|
||||
goto out;
|
||||
|
||||
vif = l3mdev_master_ifindex(dst->dev);
|
||||
peer = inet_getpeer_v4(net->ipv4.peers, fl4->daddr, vif, 1);
|
||||
rcu_read_lock();
|
||||
peer = inet_getpeer_v4(net->ipv4.peers, fl4->daddr,
|
||||
l3mdev_master_ifindex_rcu(dst->dev));
|
||||
rc = inet_peer_xrlim_allow(peer,
|
||||
READ_ONCE(net->ipv4.sysctl_icmp_ratelimit));
|
||||
if (peer)
|
||||
inet_putpeer(peer);
|
||||
rcu_read_unlock();
|
||||
out:
|
||||
if (!rc)
|
||||
__ICMP_INC_STATS(net, ICMP_MIB_RATELIMITHOST);
|
||||
|
||||
@ -95,6 +95,7 @@ static struct inet_peer *lookup(const struct inetpeer_addr *daddr,
|
||||
{
|
||||
struct rb_node **pp, *parent, *next;
|
||||
struct inet_peer *p;
|
||||
u32 now;
|
||||
|
||||
pp = &base->rb_root.rb_node;
|
||||
parent = NULL;
|
||||
@ -108,8 +109,9 @@ static struct inet_peer *lookup(const struct inetpeer_addr *daddr,
|
||||
p = rb_entry(parent, struct inet_peer, rb_node);
|
||||
cmp = inetpeer_addr_cmp(daddr, &p->daddr);
|
||||
if (cmp == 0) {
|
||||
if (!refcount_inc_not_zero(&p->refcnt))
|
||||
break;
|
||||
now = jiffies;
|
||||
if (READ_ONCE(p->dtime) != now)
|
||||
WRITE_ONCE(p->dtime, now);
|
||||
return p;
|
||||
}
|
||||
if (gc_stack) {
|
||||
@ -155,9 +157,6 @@ static void inet_peer_gc(struct inet_peer_base *base,
|
||||
for (i = 0; i < gc_cnt; i++) {
|
||||
p = gc_stack[i];
|
||||
|
||||
/* The READ_ONCE() pairs with the WRITE_ONCE()
|
||||
* in inet_putpeer()
|
||||
*/
|
||||
delta = (__u32)jiffies - READ_ONCE(p->dtime);
|
||||
|
||||
if (delta < ttl || !refcount_dec_if_one(&p->refcnt))
|
||||
@ -173,31 +172,23 @@ static void inet_peer_gc(struct inet_peer_base *base,
|
||||
}
|
||||
}
|
||||
|
||||
/* Must be called under RCU : No refcount change is done here. */
|
||||
struct inet_peer *inet_getpeer(struct inet_peer_base *base,
|
||||
const struct inetpeer_addr *daddr,
|
||||
int create)
|
||||
const struct inetpeer_addr *daddr)
|
||||
{
|
||||
struct inet_peer *p, *gc_stack[PEER_MAX_GC];
|
||||
struct rb_node **pp, *parent;
|
||||
unsigned int gc_cnt, seq;
|
||||
int invalidated;
|
||||
|
||||
/* Attempt a lockless lookup first.
|
||||
* Because of a concurrent writer, we might not find an existing entry.
|
||||
*/
|
||||
rcu_read_lock();
|
||||
seq = read_seqbegin(&base->lock);
|
||||
p = lookup(daddr, base, seq, NULL, &gc_cnt, &parent, &pp);
|
||||
invalidated = read_seqretry(&base->lock, seq);
|
||||
rcu_read_unlock();
|
||||
|
||||
if (p)
|
||||
return p;
|
||||
|
||||
/* If no writer did a change during our lookup, we can return early. */
|
||||
if (!create && !invalidated)
|
||||
return NULL;
|
||||
|
||||
/* retry an exact lookup, taking the lock before.
|
||||
* At least, nodes should be hot in our cache.
|
||||
*/
|
||||
@ -206,12 +197,12 @@ struct inet_peer *inet_getpeer(struct inet_peer_base *base,
|
||||
|
||||
gc_cnt = 0;
|
||||
p = lookup(daddr, base, seq, gc_stack, &gc_cnt, &parent, &pp);
|
||||
if (!p && create) {
|
||||
if (!p) {
|
||||
p = kmem_cache_alloc(peer_cachep, GFP_ATOMIC);
|
||||
if (p) {
|
||||
p->daddr = *daddr;
|
||||
p->dtime = (__u32)jiffies;
|
||||
refcount_set(&p->refcnt, 2);
|
||||
refcount_set(&p->refcnt, 1);
|
||||
atomic_set(&p->rid, 0);
|
||||
p->metrics[RTAX_LOCK-1] = INETPEER_METRICS_NEW;
|
||||
p->rate_tokens = 0;
|
||||
@ -236,15 +227,9 @@ EXPORT_SYMBOL_GPL(inet_getpeer);
|
||||
|
||||
void inet_putpeer(struct inet_peer *p)
|
||||
{
|
||||
/* The WRITE_ONCE() pairs with itself (we run lockless)
|
||||
* and the READ_ONCE() in inet_peer_gc()
|
||||
*/
|
||||
WRITE_ONCE(p->dtime, (__u32)jiffies);
|
||||
|
||||
if (refcount_dec_and_test(&p->refcnt))
|
||||
call_rcu(&p->rcu, inetpeer_free_rcu);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(inet_putpeer);
|
||||
|
||||
/*
|
||||
* Check transmit rate limitation for given message.
|
||||
|
||||
@ -82,15 +82,20 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *skb,
|
||||
static void ip4_frag_init(struct inet_frag_queue *q, const void *a)
|
||||
{
|
||||
struct ipq *qp = container_of(q, struct ipq, q);
|
||||
struct net *net = q->fqdir->net;
|
||||
|
||||
const struct frag_v4_compare_key *key = a;
|
||||
struct net *net = q->fqdir->net;
|
||||
struct inet_peer *p = NULL;
|
||||
|
||||
q->key.v4 = *key;
|
||||
qp->ecn = 0;
|
||||
qp->peer = q->fqdir->max_dist ?
|
||||
inet_getpeer_v4(net->ipv4.peers, key->saddr, key->vif, 1) :
|
||||
NULL;
|
||||
if (q->fqdir->max_dist) {
|
||||
rcu_read_lock();
|
||||
p = inet_getpeer_v4(net->ipv4.peers, key->saddr, key->vif);
|
||||
if (p && !refcount_inc_not_zero(&p->refcnt))
|
||||
p = NULL;
|
||||
rcu_read_unlock();
|
||||
}
|
||||
qp->peer = p;
|
||||
}
|
||||
|
||||
static void ip4_frag_free(struct inet_frag_queue *q)
|
||||
|
||||
@ -876,11 +876,11 @@ void ip_rt_send_redirect(struct sk_buff *skb)
|
||||
}
|
||||
log_martians = IN_DEV_LOG_MARTIANS(in_dev);
|
||||
vif = l3mdev_master_ifindex_rcu(rt->dst.dev);
|
||||
rcu_read_unlock();
|
||||
|
||||
net = dev_net(rt->dst.dev);
|
||||
peer = inet_getpeer_v4(net->ipv4.peers, ip_hdr(skb)->saddr, vif, 1);
|
||||
peer = inet_getpeer_v4(net->ipv4.peers, ip_hdr(skb)->saddr, vif);
|
||||
if (!peer) {
|
||||
rcu_read_unlock();
|
||||
icmp_send(skb, ICMP_REDIRECT, ICMP_REDIR_HOST,
|
||||
rt_nexthop(rt, ip_hdr(skb)->daddr));
|
||||
return;
|
||||
@ -899,7 +899,7 @@ void ip_rt_send_redirect(struct sk_buff *skb)
|
||||
*/
|
||||
if (peer->n_redirects >= ip_rt_redirect_number) {
|
||||
peer->rate_last = jiffies;
|
||||
goto out_put_peer;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
/* Check for load limit; set rate_last to the latest sent
|
||||
@ -920,8 +920,8 @@ void ip_rt_send_redirect(struct sk_buff *skb)
|
||||
&ip_hdr(skb)->saddr, inet_iif(skb),
|
||||
&ip_hdr(skb)->daddr, &gw);
|
||||
}
|
||||
out_put_peer:
|
||||
inet_putpeer(peer);
|
||||
out_unlock:
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
static int ip_error(struct sk_buff *skb)
|
||||
@ -981,9 +981,9 @@ static int ip_error(struct sk_buff *skb)
|
||||
break;
|
||||
}
|
||||
|
||||
rcu_read_lock();
|
||||
peer = inet_getpeer_v4(net->ipv4.peers, ip_hdr(skb)->saddr,
|
||||
l3mdev_master_ifindex(skb->dev), 1);
|
||||
|
||||
l3mdev_master_ifindex_rcu(skb->dev));
|
||||
send = true;
|
||||
if (peer) {
|
||||
now = jiffies;
|
||||
@ -995,8 +995,9 @@ static int ip_error(struct sk_buff *skb)
|
||||
peer->rate_tokens -= ip_rt_error_cost;
|
||||
else
|
||||
send = false;
|
||||
inet_putpeer(peer);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
if (send)
|
||||
icmp_send(skb, ICMP_DEST_UNREACH, code, 0);
|
||||
|
||||
|
||||
@ -222,10 +222,10 @@ static bool icmpv6_xrlim_allow(struct sock *sk, u8 type,
|
||||
if (rt->rt6i_dst.plen < 128)
|
||||
tmo >>= ((128 - rt->rt6i_dst.plen)>>5);
|
||||
|
||||
peer = inet_getpeer_v6(net->ipv6.peers, &fl6->daddr, 1);
|
||||
rcu_read_lock();
|
||||
peer = inet_getpeer_v6(net->ipv6.peers, &fl6->daddr);
|
||||
res = inet_peer_xrlim_allow(peer, tmo);
|
||||
if (peer)
|
||||
inet_putpeer(peer);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
if (!res)
|
||||
__ICMP6_INC_STATS(net, ip6_dst_idev(dst),
|
||||
|
||||
@ -613,15 +613,15 @@ int ip6_forward(struct sk_buff *skb)
|
||||
else
|
||||
target = &hdr->daddr;
|
||||
|
||||
peer = inet_getpeer_v6(net->ipv6.peers, &hdr->daddr, 1);
|
||||
rcu_read_lock();
|
||||
peer = inet_getpeer_v6(net->ipv6.peers, &hdr->daddr);
|
||||
|
||||
/* Limit redirects both by destination (here)
|
||||
and by source (inside ndisc_send_redirect)
|
||||
*/
|
||||
if (inet_peer_xrlim_allow(peer, 1*HZ))
|
||||
ndisc_send_redirect(skb, target);
|
||||
if (peer)
|
||||
inet_putpeer(peer);
|
||||
rcu_read_unlock();
|
||||
} else {
|
||||
int addrtype = ipv6_addr_type(&hdr->saddr);
|
||||
|
||||
|
||||
@ -1729,10 +1729,12 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target)
|
||||
"Redirect: destination is not a neighbour\n");
|
||||
goto release;
|
||||
}
|
||||
peer = inet_getpeer_v6(net->ipv6.peers, &ipv6_hdr(skb)->saddr, 1);
|
||||
|
||||
rcu_read_lock();
|
||||
peer = inet_getpeer_v6(net->ipv6.peers, &ipv6_hdr(skb)->saddr);
|
||||
ret = inet_peer_xrlim_allow(peer, 1*HZ);
|
||||
if (peer)
|
||||
inet_putpeer(peer);
|
||||
rcu_read_unlock();
|
||||
|
||||
if (!ret)
|
||||
goto release;
|
||||
|
||||
|
||||
@ -169,13 +169,14 @@ next_chunk:
|
||||
chunk->head_skb = chunk->skb;
|
||||
|
||||
/* skbs with "cover letter" */
|
||||
if (chunk->head_skb && chunk->skb->data_len == chunk->skb->len)
|
||||
if (chunk->head_skb && chunk->skb->data_len == chunk->skb->len) {
|
||||
if (WARN_ON(!skb_shinfo(chunk->skb)->frag_list)) {
|
||||
__SCTP_INC_STATS(dev_net(chunk->skb->dev),
|
||||
SCTP_MIB_IN_PKT_DISCARDS);
|
||||
sctp_chunk_free(chunk);
|
||||
goto next_chunk;
|
||||
}
|
||||
chunk->skb = skb_shinfo(chunk->skb)->frag_list;
|
||||
|
||||
if (WARN_ON(!chunk->skb)) {
|
||||
__SCTP_INC_STATS(dev_net(chunk->skb->dev), SCTP_MIB_IN_PKT_DISCARDS);
|
||||
sctp_chunk_free(chunk);
|
||||
goto next_chunk;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1612,8 +1612,10 @@ static int tls_decrypt_sg(struct sock *sk, struct iov_iter *out_iov,
|
||||
|
||||
if (unlikely(darg->async)) {
|
||||
err = tls_strp_msg_hold(&ctx->strp, &ctx->async_hold);
|
||||
if (err)
|
||||
__skb_queue_tail(&ctx->async_hold, darg->skb);
|
||||
if (err) {
|
||||
err = tls_decrypt_async_wait(ctx);
|
||||
darg->async = false;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
@ -115,21 +115,29 @@ ifndef RHJOBS
|
||||
fi)
|
||||
endif
|
||||
|
||||
LOCVERFILE:=../localversion
|
||||
# create an empty localversion file if you don't want a local buildid
|
||||
ifneq ($(wildcard $(LOCVERFILE)),)
|
||||
DISTLOCALVERSION:=$(shell cat $(LOCVERFILE))
|
||||
ifeq (,$(findstring s,$(firstword -$(MAKEFLAGS))))
|
||||
$(info DISTLOCALVERSION is "$(DISTLOCALVERSION)". Update '$(shell dirname $(REDHAT))/localversion' to change.)
|
||||
endif
|
||||
else
|
||||
ifeq ($(DISTLOCALVERSION),)
|
||||
DISTLOCALVERSION:=.test
|
||||
endif
|
||||
# for official builds use RELEASE_LOCALVERSION persisted in Makefile.variables
|
||||
ifneq ($(filter $(MAKECMDGOALS),dist-release dist-release-tag dist-release-git dist-rtg dist-get-tag),)
|
||||
DISTLOCALVERSION:=$(RELEASE_LOCALVERSION)
|
||||
ifeq (,$(findstring s,$(firstword -$(MAKEFLAGS))))
|
||||
$(info DISTLOCALVERSION is "$(DISTLOCALVERSION)".)
|
||||
endif
|
||||
endif
|
||||
else
|
||||
LOCVERFILE:=../localversion
|
||||
# create an empty localversion file if you don't want a local buildid
|
||||
ifneq ($(wildcard $(LOCVERFILE)),)
|
||||
DISTLOCALVERSION:=$(shell cat $(LOCVERFILE))
|
||||
ifeq (,$(findstring s,$(firstword -$(MAKEFLAGS))))
|
||||
$(info DISTLOCALVERSION is "$(DISTLOCALVERSION)". Update '$(shell dirname $(REDHAT))/localversion' to change.)
|
||||
endif
|
||||
else
|
||||
ifeq ($(DISTLOCALVERSION),)
|
||||
DISTLOCALVERSION:=.test
|
||||
endif
|
||||
ifeq (,$(findstring s,$(firstword -$(MAKEFLAGS))))
|
||||
$(info DISTLOCALVERSION is "$(DISTLOCALVERSION)".)
|
||||
endif
|
||||
endif
|
||||
endif # MAKECMDGOALS
|
||||
|
||||
# options for process_configs.sh script
|
||||
ifdef NO_CONFIGCHECKS
|
||||
|
||||
@ -94,6 +94,10 @@ PATCHLIST_URL ?= none
|
||||
# unreleased kernel development snapshot.
|
||||
RELEASED_KERNEL:=0
|
||||
|
||||
# Local version to be used for official (non-scratch) builds. Makefile
|
||||
# dist-{release/tag/git} targets will ignore localversion and DISTLOCALVERSION
|
||||
RELEASE_LOCALVERSION:=
|
||||
|
||||
# This variable is used by the redhat/self-tests. It should not be
|
||||
# considered stable and my be changed or removed without warning.
|
||||
RHDISTDATADIR ?=
|
||||
|
||||
@ -1,3 +1,55 @@
|
||||
* Sat Dec 27 2025 CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> [6.12.0-124.27.1.el10_1]
|
||||
- arm64: errata: Expand speculative SSBS workaround for Cortex-A720AE (Waiman Long) [RHEL-120684]
|
||||
- arm64: cputype: Add Cortex-A720AE definitions (Waiman Long) [RHEL-120684]
|
||||
- arm64: errata: Add missing sentinels to Spectre-BHB MIDR arrays (Waiman Long) [RHEL-120684]
|
||||
- arm64: Add support for HIP09 Spectre-BHB mitigation (Waiman Long) [RHEL-120684]
|
||||
- arm64: errata: Add newer ARM cores to the spectre_bhb_loop_affected() lists (Waiman Long) [RHEL-120684]
|
||||
- arm64: cputype: Add MIDR_CORTEX_A76AE (Waiman Long) [RHEL-120684]
|
||||
- arm64: errata: Add KRYO 2XX/3XX/4XX silver cores to Spectre BHB safe list (Waiman Long) [RHEL-120684]
|
||||
- kmem/tracing: add kmem name to kmem_cache_alloc tracepoint (Charles Haithcock) [RHEL-129882]
|
||||
- mm: memory-tiering: fix PGPROMOTE_CANDIDATE counting (Rafael Aquini) [RHEL-128383]
|
||||
Resolves: RHEL-120684, RHEL-128383, RHEL-129882
|
||||
|
||||
* Tue Dec 23 2025 CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> [6.12.0-124.26.1.el10_1]
|
||||
- usb: dwc3: Fix race condition between concurrent dwc3_remove_requests() call paths (CKI Backport Bot) [RHEL-137150] {CVE-2025-68287}
|
||||
- drm/vmwgfx: Validate command header size against SVGA_CMD_MAX_DATASIZE (CKI Backport Bot) [RHEL-134431] {CVE-2025-40277}
|
||||
- net: phylink: add lock for serializing concurrent pl->phydev writes with resolver (CKI Backport Bot) [RHEL-129812] {CVE-2025-39905}
|
||||
Resolves: RHEL-129812, RHEL-134431, RHEL-137150
|
||||
|
||||
* Sat Dec 20 2025 CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> [6.12.0-124.25.1.el10_1]
|
||||
- sctp: avoid NULL dereference when chunk data buffer is missing (CKI Backport Bot) [RHEL-134010] {CVE-2025-40240}
|
||||
- HID: i2c-hid: Resolve touchpad issues on Dell systems during S4 (CKI Backport Bot) [RHEL-128281]
|
||||
- HID: multitouch: fix slab out-of-bounds access in mt_report_fixup() (CKI Backport Bot) [RHEL-124610] {CVE-2025-39806}
|
||||
- inetpeer: do not get a refcount in inet_getpeer() (Guillaume Nault) [RHEL-115287]
|
||||
- inetpeer: update inetpeer timestamp in inet_getpeer() (Guillaume Nault) [RHEL-115287]
|
||||
- inetpeer: remove create argument of inet_getpeer() (Guillaume Nault) [RHEL-115287]
|
||||
- inetpeer: remove create argument of inet_getpeer_v[46]() (Guillaume Nault) [RHEL-115287]
|
||||
Resolves: RHEL-115287, RHEL-124610, RHEL-128281, RHEL-134010
|
||||
|
||||
* Tue Dec 16 2025 CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> [6.12.0-124.24.1.el10_1]
|
||||
- audit: fix out-of-bounds read in audit_compare_dname_path() (Richard Guy Briggs) [RHEL-119185] {CVE-2025-39840}
|
||||
Resolves: RHEL-119185
|
||||
|
||||
* Sat Dec 13 2025 CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> [6.12.0-124.23.1.el10_1]
|
||||
- redhat: use RELEASE_LOCALVERSION also for dist-get-tag (Jan Stancek)
|
||||
- redhat: introduce RELEASE_LOCALVERSION variable (Jan Stancek)
|
||||
- iommufd: Fix race during abort for file descriptors (Eder Zulian) [RHEL-123789] {CVE-2025-39966}
|
||||
- smb: client: handle lack of IPC in dfs_cache_refresh() (Paulo Alcantara) [RHEL-126227]
|
||||
- mm: slub: avoid wake up kswapd in set_track_prepare (Audra Mitchell) [RHEL-125522] {CVE-2025-39843}
|
||||
- dpll: zl3073x: Increase maximum size of flash utility (Ivan Vecera) [RHEL-116157]
|
||||
- dpll: zl3073x: Fix double free in zl3073x_devlink_flash_update() (Ivan Vecera) [RHEL-116157]
|
||||
- dpll: zl3073x: Implement devlink flash callback (Ivan Vecera) [RHEL-116157]
|
||||
- dpll: zl3073x: Add firmware loading functionality (Ivan Vecera) [RHEL-116157]
|
||||
- dpll: zl3073x: Add low-level flash functions (Ivan Vecera) [RHEL-116157]
|
||||
- dpll: zl3073x: Add functions to access hardware registers (Ivan Vecera) [RHEL-116157]
|
||||
Resolves: RHEL-116157, RHEL-123789, RHEL-125522, RHEL-126227
|
||||
|
||||
* Sun Dec 07 2025 CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> [6.12.0-124.22.1.el10_1]
|
||||
- ASoC: Intel: sof_sdw: Add quirks for Lenovo P1 and P16 (CKI Backport Bot) [RHEL-130550]
|
||||
- tls: wait for pending async decryptions if tls_strp_msg_hold fails (CKI Backport Bot) [RHEL-128866] {CVE-2025-40176}
|
||||
- sched/deadline: Fix RT task potential starvation when expiry time passed (CKI Backport Bot) [RHEL-124660]
|
||||
Resolves: RHEL-124660, RHEL-128866, RHEL-130550
|
||||
|
||||
* Thu Dec 04 2025 CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> [6.12.0-124.21.1.el10_1]
|
||||
- CVE-2025-38499 kernel: clone_private_mnt(): make sure that caller has CAP_SYS_ADMIN in the right userns (Abhi Das) [RHEL-129282] {CVE-2025-38499}
|
||||
- net: tun: Update napi->skb after XDP process (CKI Backport Bot) [RHEL-122247] {CVE-2025-39984}
|
||||
|
||||
@ -57,6 +57,7 @@ PROCESS_CONFIGS_OPTS=-n -w -c
|
||||
REDHAT=../redhat
|
||||
RELEASED_KERNEL=0
|
||||
RELEASETAG=kernel-5.16.0-0.rc5.6.test
|
||||
RELEASE_LOCALVERSION=
|
||||
RHDISTGIT_BRANCH=c10s
|
||||
RHDISTGIT_CACHE=
|
||||
RHDISTGIT_TMP=/tmp
|
||||
|
||||
@ -57,6 +57,7 @@ PROCESS_CONFIGS_OPTS=-n -w -c
|
||||
REDHAT=../redhat
|
||||
RELEASED_KERNEL=0
|
||||
RELEASETAG=kernel-5.16.0-0.rc5.6.test
|
||||
RELEASE_LOCALVERSION=
|
||||
RHDISTGIT_BRANCH=c10s
|
||||
RHDISTGIT_CACHE=
|
||||
RHDISTGIT_TMP=/tmp
|
||||
|
||||
@ -57,6 +57,7 @@ PROCESS_CONFIGS_OPTS=-n -w -c
|
||||
REDHAT=../redhat
|
||||
RELEASED_KERNEL=0
|
||||
RELEASETAG=kernel-5.16.0-6.test
|
||||
RELEASE_LOCALVERSION=
|
||||
RHDISTGIT_BRANCH=c10s
|
||||
RHDISTGIT_CACHE=
|
||||
RHDISTGIT_TMP=/tmp
|
||||
|
||||
@ -57,6 +57,7 @@ PROCESS_CONFIGS_OPTS=-n -w -c
|
||||
REDHAT=../redhat
|
||||
RELEASED_KERNEL=0
|
||||
RELEASETAG=kernel-5.16.0-6.test
|
||||
RELEASE_LOCALVERSION=
|
||||
RHDISTGIT_BRANCH=c10s
|
||||
RHDISTGIT_CACHE=
|
||||
RHDISTGIT_TMP=/tmp
|
||||
|
||||
@ -57,6 +57,7 @@ PROCESS_CONFIGS_OPTS=-n -w -c
|
||||
REDHAT=../redhat
|
||||
RELEASED_KERNEL=0
|
||||
RELEASETAG=kernel-5.16.0-6.test
|
||||
RELEASE_LOCALVERSION=
|
||||
RHDISTGIT_BRANCH=c10s
|
||||
RHDISTGIT_CACHE=
|
||||
RHDISTGIT_TMP=/tmp
|
||||
|
||||
@ -57,6 +57,7 @@ PROCESS_CONFIGS_OPTS=-n -w -c
|
||||
REDHAT=../redhat
|
||||
RELEASED_KERNEL=0
|
||||
RELEASETAG=kernel-5.16.0-6.test
|
||||
RELEASE_LOCALVERSION=
|
||||
RHDISTGIT_BRANCH=c10s
|
||||
RHDISTGIT_CACHE=
|
||||
RHDISTGIT_TMP=/tmp
|
||||
|
||||
@ -57,6 +57,7 @@ PROCESS_CONFIGS_OPTS=-n -w -c
|
||||
REDHAT=../redhat
|
||||
RELEASED_KERNEL=0
|
||||
RELEASETAG=kernel-5.16.0-0.rc5.6.test
|
||||
RELEASE_LOCALVERSION=
|
||||
RHDISTGIT_BRANCH=c10s
|
||||
RHDISTGIT_CACHE=
|
||||
RHDISTGIT_TMP=/tmp
|
||||
|
||||
@ -57,6 +57,7 @@ PROCESS_CONFIGS_OPTS=-n -w -c
|
||||
REDHAT=../redhat
|
||||
RELEASED_KERNEL=0
|
||||
RELEASETAG=kernel-5.16.0-0.rc5.6.test
|
||||
RELEASE_LOCALVERSION=
|
||||
RHDISTGIT_BRANCH=c10s
|
||||
RHDISTGIT_CACHE=
|
||||
RHDISTGIT_TMP=/tmp
|
||||
|
||||
@ -57,6 +57,7 @@ PROCESS_CONFIGS_OPTS=-n -w -c
|
||||
REDHAT=../redhat
|
||||
RELEASED_KERNEL=0
|
||||
RELEASETAG=kernel-5.16.0-0.rc5.6.test
|
||||
RELEASE_LOCALVERSION=
|
||||
RHDISTGIT_BRANCH=rawhide
|
||||
RHDISTGIT_CACHE=
|
||||
RHDISTGIT_TMP=/tmp
|
||||
|
||||
@ -57,6 +57,7 @@ PROCESS_CONFIGS_OPTS=-n -w -c
|
||||
REDHAT=../redhat
|
||||
RELEASED_KERNEL=0
|
||||
RELEASETAG=kernel-5.16.0-0.rc5.6.test
|
||||
RELEASE_LOCALVERSION=
|
||||
RHDISTGIT_BRANCH=rawhide
|
||||
RHDISTGIT_CACHE=
|
||||
RHDISTGIT_TMP=/tmp
|
||||
|
||||
@ -57,6 +57,7 @@ PROCESS_CONFIGS_OPTS=-n -w -c
|
||||
REDHAT=../redhat
|
||||
RELEASED_KERNEL=0
|
||||
RELEASETAG=kernel-5.16.0-6.test
|
||||
RELEASE_LOCALVERSION=
|
||||
RHDISTGIT_BRANCH=rawhide
|
||||
RHDISTGIT_CACHE=
|
||||
RHDISTGIT_TMP=/tmp
|
||||
|
||||
@ -57,6 +57,7 @@ PROCESS_CONFIGS_OPTS=-n -w -c
|
||||
REDHAT=../redhat
|
||||
RELEASED_KERNEL=0
|
||||
RELEASETAG=kernel-5.16.0-6.test
|
||||
RELEASE_LOCALVERSION=
|
||||
RHDISTGIT_BRANCH=rawhide
|
||||
RHDISTGIT_CACHE=
|
||||
RHDISTGIT_TMP=/tmp
|
||||
|
||||
@ -57,6 +57,7 @@ PROCESS_CONFIGS_OPTS=-n -w -c
|
||||
REDHAT=../redhat
|
||||
RELEASED_KERNEL=0
|
||||
RELEASETAG=kernel-5.16.0-6.test
|
||||
RELEASE_LOCALVERSION=
|
||||
RHDISTGIT_BRANCH=rawhide
|
||||
RHDISTGIT_CACHE=
|
||||
RHDISTGIT_TMP=/tmp
|
||||
|
||||
@ -57,6 +57,7 @@ PROCESS_CONFIGS_OPTS=-n -w -c
|
||||
REDHAT=../redhat
|
||||
RELEASED_KERNEL=0
|
||||
RELEASETAG=kernel-5.16.0-6.test
|
||||
RELEASE_LOCALVERSION=
|
||||
RHDISTGIT_BRANCH=rawhide
|
||||
RHDISTGIT_CACHE=
|
||||
RHDISTGIT_TMP=/tmp
|
||||
|
||||
@ -57,6 +57,7 @@ PROCESS_CONFIGS_OPTS=-n -w -c
|
||||
REDHAT=../redhat
|
||||
RELEASED_KERNEL=0
|
||||
RELEASETAG=kernel-5.16.0-0.rc5.6.test
|
||||
RELEASE_LOCALVERSION=
|
||||
RHDISTGIT_BRANCH=rawhide
|
||||
RHDISTGIT_CACHE=
|
||||
RHDISTGIT_TMP=/tmp
|
||||
|
||||
@ -57,6 +57,7 @@ PROCESS_CONFIGS_OPTS=-n -w -c
|
||||
REDHAT=../redhat
|
||||
RELEASED_KERNEL=0
|
||||
RELEASETAG=kernel-5.16.0-0.rc5.6.test
|
||||
RELEASE_LOCALVERSION=
|
||||
RHDISTGIT_BRANCH=rawhide
|
||||
RHDISTGIT_CACHE=
|
||||
RHDISTGIT_TMP=/tmp
|
||||
|
||||
@ -57,6 +57,7 @@ PROCESS_CONFIGS_OPTS=-n -w -c
|
||||
REDHAT=../redhat
|
||||
RELEASED_KERNEL=0
|
||||
RELEASETAG=kernel-5.16.0-0.rc5.6.test
|
||||
RELEASE_LOCALVERSION=
|
||||
RHDISTGIT_BRANCH=rhel-10.1
|
||||
RHDISTGIT_CACHE=
|
||||
RHDISTGIT_TMP=/tmp
|
||||
|
||||
@ -57,6 +57,7 @@ PROCESS_CONFIGS_OPTS=-n -w -c
|
||||
REDHAT=../redhat
|
||||
RELEASED_KERNEL=0
|
||||
RELEASETAG=kernel-5.16.0-0.rc5.6.test
|
||||
RELEASE_LOCALVERSION=
|
||||
RHDISTGIT_BRANCH=rhel-10.1
|
||||
RHDISTGIT_CACHE=
|
||||
RHDISTGIT_TMP=/tmp
|
||||
|
||||
@ -57,6 +57,7 @@ PROCESS_CONFIGS_OPTS=-n -w -c
|
||||
REDHAT=../redhat
|
||||
RELEASED_KERNEL=0
|
||||
RELEASETAG=kernel-5.16.0-6.test
|
||||
RELEASE_LOCALVERSION=
|
||||
RHDISTGIT_BRANCH=rhel-10.1
|
||||
RHDISTGIT_CACHE=
|
||||
RHDISTGIT_TMP=/tmp
|
||||
|
||||
@ -57,6 +57,7 @@ PROCESS_CONFIGS_OPTS=-n -w -c
|
||||
REDHAT=../redhat
|
||||
RELEASED_KERNEL=0
|
||||
RELEASETAG=kernel-5.16.0-6.test
|
||||
RELEASE_LOCALVERSION=
|
||||
RHDISTGIT_BRANCH=rhel-10.1
|
||||
RHDISTGIT_CACHE=
|
||||
RHDISTGIT_TMP=/tmp
|
||||
|
||||
@ -57,6 +57,7 @@ PROCESS_CONFIGS_OPTS=-n -w -c
|
||||
REDHAT=../redhat
|
||||
RELEASED_KERNEL=0
|
||||
RELEASETAG=kernel-5.16.0-6.test
|
||||
RELEASE_LOCALVERSION=
|
||||
RHDISTGIT_BRANCH=rhel-10.1
|
||||
RHDISTGIT_CACHE=
|
||||
RHDISTGIT_TMP=/tmp
|
||||
|
||||
@ -57,6 +57,7 @@ PROCESS_CONFIGS_OPTS=-n -w -c
|
||||
REDHAT=../redhat
|
||||
RELEASED_KERNEL=0
|
||||
RELEASETAG=kernel-5.16.0-6.test
|
||||
RELEASE_LOCALVERSION=
|
||||
RHDISTGIT_BRANCH=rhel-10.1
|
||||
RHDISTGIT_CACHE=
|
||||
RHDISTGIT_TMP=/tmp
|
||||
|
||||
@ -57,6 +57,7 @@ PROCESS_CONFIGS_OPTS=-n -w -c
|
||||
REDHAT=../redhat
|
||||
RELEASED_KERNEL=0
|
||||
RELEASETAG=kernel-5.16.0-0.rc5.6.test
|
||||
RELEASE_LOCALVERSION=
|
||||
RHDISTGIT_BRANCH=rhel-10.1
|
||||
RHDISTGIT_CACHE=
|
||||
RHDISTGIT_TMP=/tmp
|
||||
|
||||
@ -57,6 +57,7 @@ PROCESS_CONFIGS_OPTS=-n -w -c
|
||||
REDHAT=../redhat
|
||||
RELEASED_KERNEL=0
|
||||
RELEASETAG=kernel-5.16.0-0.rc5.6.test
|
||||
RELEASE_LOCALVERSION=
|
||||
RHDISTGIT_BRANCH=rhel-10.1
|
||||
RHDISTGIT_CACHE=
|
||||
RHDISTGIT_TMP=/tmp
|
||||
|
||||
@ -765,6 +765,9 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
|
||||
static const struct snd_pci_quirk sof_sdw_ssid_quirk_table[] = {
|
||||
SND_PCI_QUIRK(0x1043, 0x1e13, "ASUS Zenbook S14", SOC_SDW_CODEC_MIC),
|
||||
SND_PCI_QUIRK(0x1043, 0x1f43, "ASUS Zenbook S16", SOC_SDW_CODEC_MIC),
|
||||
SND_PCI_QUIRK(0x17aa, 0x2347, "Lenovo P16", SOC_SDW_CODEC_MIC),
|
||||
SND_PCI_QUIRK(0x17aa, 0x2348, "Lenovo P16", SOC_SDW_CODEC_MIC),
|
||||
SND_PCI_QUIRK(0x17aa, 0x2349, "Lenovo P1", SOC_SDW_CODEC_MIC),
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md
|
||||
kernel-uki-virt-addons.centos,1,Red Hat,kernel-uki-virt-addons,6.12.0-124.21.1.el10.x86_64,mailto:secalert@redhat.com
|
||||
kernel-uki-virt-addons.almalinux,1,AlmaLinux,kernel-uki-virt-addons,6.12.0-124.21.1.el10.x86_64,mailto:security@almalinux.org
|
||||
kernel-uki-virt-addons.centos,1,Red Hat,kernel-uki-virt-addons,6.12.0-124.27.1.el10.x86_64,mailto:secalert@redhat.com
|
||||
kernel-uki-virt-addons.almalinux,1,AlmaLinux,kernel-uki-virt-addons,6.12.0-124.27.1.el10.x86_64,mailto:security@almalinux.org
|
||||
|
||||
4
uki.sbat
4
uki.sbat
@ -1,3 +1,3 @@
|
||||
sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md
|
||||
kernel-uki-virt.centos,1,Red Hat,kernel-uki-virt,6.12.0-124.21.1.el10.x86_64,mailto:secalert@redhat.com
|
||||
kernel-uki-virt.almalinux,1,AlmaLinux,kernel-uki-virt,6.12.0-124.21.1.el10.x86_64,mailto:security@almalinux.org
|
||||
kernel-uki-virt.centos,1,Red Hat,kernel-uki-virt,6.12.0-124.27.1.el10.x86_64,mailto:secalert@redhat.com
|
||||
kernel-uki-virt.almalinux,1,AlmaLinux,kernel-uki-virt,6.12.0-124.27.1.el10.x86_64,mailto:security@almalinux.org
|
||||
|
||||
Loading…
Reference in New Issue
Block a user