mirror of
https://github.com/armbian/build.git
synced 2025-08-15 15:46:58 +02:00
5581 lines
184 KiB
Diff
5581 lines
184 KiB
Diff
diff --git a/Documentation/devicetree/bindings/serial/8250.yaml b/Documentation/devicetree/bindings/serial/8250.yaml
|
|
index 692aa05500fd53..6ba0325039be21 100644
|
|
--- a/Documentation/devicetree/bindings/serial/8250.yaml
|
|
+++ b/Documentation/devicetree/bindings/serial/8250.yaml
|
|
@@ -45,7 +45,7 @@ allOf:
|
|
- ns16550
|
|
- ns16550a
|
|
then:
|
|
- anyOf:
|
|
+ oneOf:
|
|
- required: [ clock-frequency ]
|
|
- required: [ clocks ]
|
|
|
|
diff --git a/Makefile b/Makefile
|
|
index 679dff5e165c07..038fc8e0982bdc 100644
|
|
--- a/Makefile
|
|
+++ b/Makefile
|
|
@@ -1,7 +1,7 @@
|
|
# SPDX-License-Identifier: GPL-2.0
|
|
VERSION = 6
|
|
PATCHLEVEL = 6
|
|
-SUBLEVEL = 95
|
|
+SUBLEVEL = 96
|
|
EXTRAVERSION =
|
|
NAME = Pinguïn Aangedreven
|
|
|
|
diff --git a/arch/arm/include/asm/ptrace.h b/arch/arm/include/asm/ptrace.h
|
|
index 7f44e88d1f25bc..14a38cc67e0bc9 100644
|
|
--- a/arch/arm/include/asm/ptrace.h
|
|
+++ b/arch/arm/include/asm/ptrace.h
|
|
@@ -10,6 +10,7 @@
|
|
#include <uapi/asm/ptrace.h>
|
|
|
|
#ifndef __ASSEMBLY__
|
|
+#include <linux/bitfield.h>
|
|
#include <linux/types.h>
|
|
|
|
struct pt_regs {
|
|
@@ -35,8 +36,8 @@ struct svc_pt_regs {
|
|
|
|
#ifndef CONFIG_CPU_V7M
|
|
#define isa_mode(regs) \
|
|
- ((((regs)->ARM_cpsr & PSR_J_BIT) >> (__ffs(PSR_J_BIT) - 1)) | \
|
|
- (((regs)->ARM_cpsr & PSR_T_BIT) >> (__ffs(PSR_T_BIT))))
|
|
+ (FIELD_GET(PSR_J_BIT, (regs)->ARM_cpsr) << 1 | \
|
|
+ FIELD_GET(PSR_T_BIT, (regs)->ARM_cpsr))
|
|
#else
|
|
#define isa_mode(regs) 1 /* Thumb */
|
|
#endif
|
|
diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S
|
|
index ebad8c8b8c57dd..0476ce7700dfaa 100644
|
|
--- a/arch/s390/kernel/entry.S
|
|
+++ b/arch/s390/kernel/entry.S
|
|
@@ -639,7 +639,7 @@ SYM_CODE_START(stack_overflow)
|
|
stmg %r0,%r7,__PT_R0(%r11)
|
|
stmg %r8,%r9,__PT_PSW(%r11)
|
|
mvc __PT_R8(64,%r11),0(%r14)
|
|
- stg %r10,__PT_ORIG_GPR2(%r11) # store last break to orig_gpr2
|
|
+ mvc __PT_ORIG_GPR2(8,%r11),__LC_PGM_LAST_BREAK
|
|
xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
|
|
lgr %r2,%r11 # pass pointer to pt_regs
|
|
jg kernel_stack_overflow
|
|
diff --git a/arch/um/drivers/ubd_user.c b/arch/um/drivers/ubd_user.c
|
|
index a1afe414ce4814..fb5b1e7c133d86 100644
|
|
--- a/arch/um/drivers/ubd_user.c
|
|
+++ b/arch/um/drivers/ubd_user.c
|
|
@@ -41,7 +41,7 @@ int start_io_thread(unsigned long sp, int *fd_out)
|
|
*fd_out = fds[1];
|
|
|
|
err = os_set_fd_block(*fd_out, 0);
|
|
- err = os_set_fd_block(kernel_fd, 0);
|
|
+ err |= os_set_fd_block(kernel_fd, 0);
|
|
if (err) {
|
|
printk("start_io_thread - failed to set nonblocking I/O.\n");
|
|
goto out_close;
|
|
diff --git a/arch/um/include/asm/asm-prototypes.h b/arch/um/include/asm/asm-prototypes.h
|
|
index 5898a26daa0dd4..408b31d591279d 100644
|
|
--- a/arch/um/include/asm/asm-prototypes.h
|
|
+++ b/arch/um/include/asm/asm-prototypes.h
|
|
@@ -1 +1,6 @@
|
|
#include <asm-generic/asm-prototypes.h>
|
|
+#include <asm/checksum.h>
|
|
+
|
|
+#ifdef CONFIG_UML_X86
|
|
+extern void cmpxchg8b_emu(void);
|
|
+#endif
|
|
diff --git a/arch/um/kernel/trap.c b/arch/um/kernel/trap.c
|
|
index 6d8ae86ae978fd..c16b80011adaac 100644
|
|
--- a/arch/um/kernel/trap.c
|
|
+++ b/arch/um/kernel/trap.c
|
|
@@ -17,6 +17,122 @@
|
|
#include <os.h>
|
|
#include <skas.h>
|
|
|
|
+/*
|
|
+ * NOTE: UML does not have exception tables. As such, this is almost a copy
|
|
+ * of the code in mm/memory.c, only adjusting the logic to simply check whether
|
|
+ * we are coming from the kernel instead of doing an additional lookup in the
|
|
+ * exception table.
|
|
+ * We can do this simplification because we never get here if the exception was
|
|
+ * fixable.
|
|
+ */
|
|
+static inline bool get_mmap_lock_carefully(struct mm_struct *mm, bool is_user)
|
|
+{
|
|
+ if (likely(mmap_read_trylock(mm)))
|
|
+ return true;
|
|
+
|
|
+ if (!is_user)
|
|
+ return false;
|
|
+
|
|
+ return !mmap_read_lock_killable(mm);
|
|
+}
|
|
+
|
|
+static inline bool mmap_upgrade_trylock(struct mm_struct *mm)
|
|
+{
|
|
+ /*
|
|
+ * We don't have this operation yet.
|
|
+ *
|
|
+ * It should be easy enough to do: it's basically a
|
|
+ * atomic_long_try_cmpxchg_acquire()
|
|
+ * from RWSEM_READER_BIAS -> RWSEM_WRITER_LOCKED, but
|
|
+ * it also needs the proper lockdep magic etc.
|
|
+ */
|
|
+ return false;
|
|
+}
|
|
+
|
|
+static inline bool upgrade_mmap_lock_carefully(struct mm_struct *mm, bool is_user)
|
|
+{
|
|
+ mmap_read_unlock(mm);
|
|
+ if (!is_user)
|
|
+ return false;
|
|
+
|
|
+ return !mmap_write_lock_killable(mm);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * Helper for page fault handling.
|
|
+ *
|
|
+ * This is kind of equivalend to "mmap_read_lock()" followed
|
|
+ * by "find_extend_vma()", except it's a lot more careful about
|
|
+ * the locking (and will drop the lock on failure).
|
|
+ *
|
|
+ * For example, if we have a kernel bug that causes a page
|
|
+ * fault, we don't want to just use mmap_read_lock() to get
|
|
+ * the mm lock, because that would deadlock if the bug were
|
|
+ * to happen while we're holding the mm lock for writing.
|
|
+ *
|
|
+ * So this checks the exception tables on kernel faults in
|
|
+ * order to only do this all for instructions that are actually
|
|
+ * expected to fault.
|
|
+ *
|
|
+ * We can also actually take the mm lock for writing if we
|
|
+ * need to extend the vma, which helps the VM layer a lot.
|
|
+ */
|
|
+static struct vm_area_struct *
|
|
+um_lock_mm_and_find_vma(struct mm_struct *mm,
|
|
+ unsigned long addr, bool is_user)
|
|
+{
|
|
+ struct vm_area_struct *vma;
|
|
+
|
|
+ if (!get_mmap_lock_carefully(mm, is_user))
|
|
+ return NULL;
|
|
+
|
|
+ vma = find_vma(mm, addr);
|
|
+ if (likely(vma && (vma->vm_start <= addr)))
|
|
+ return vma;
|
|
+
|
|
+ /*
|
|
+ * Well, dang. We might still be successful, but only
|
|
+ * if we can extend a vma to do so.
|
|
+ */
|
|
+ if (!vma || !(vma->vm_flags & VM_GROWSDOWN)) {
|
|
+ mmap_read_unlock(mm);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * We can try to upgrade the mmap lock atomically,
|
|
+ * in which case we can continue to use the vma
|
|
+ * we already looked up.
|
|
+ *
|
|
+ * Otherwise we'll have to drop the mmap lock and
|
|
+ * re-take it, and also look up the vma again,
|
|
+ * re-checking it.
|
|
+ */
|
|
+ if (!mmap_upgrade_trylock(mm)) {
|
|
+ if (!upgrade_mmap_lock_carefully(mm, is_user))
|
|
+ return NULL;
|
|
+
|
|
+ vma = find_vma(mm, addr);
|
|
+ if (!vma)
|
|
+ goto fail;
|
|
+ if (vma->vm_start <= addr)
|
|
+ goto success;
|
|
+ if (!(vma->vm_flags & VM_GROWSDOWN))
|
|
+ goto fail;
|
|
+ }
|
|
+
|
|
+ if (expand_stack_locked(vma, addr))
|
|
+ goto fail;
|
|
+
|
|
+success:
|
|
+ mmap_write_downgrade(mm);
|
|
+ return vma;
|
|
+
|
|
+fail:
|
|
+ mmap_write_unlock(mm);
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
/*
|
|
* Note this is constrained to return 0, -EFAULT, -EACCES, -ENOMEM by
|
|
* segv().
|
|
@@ -43,21 +159,10 @@ int handle_page_fault(unsigned long address, unsigned long ip,
|
|
if (is_user)
|
|
flags |= FAULT_FLAG_USER;
|
|
retry:
|
|
- mmap_read_lock(mm);
|
|
- vma = find_vma(mm, address);
|
|
- if (!vma)
|
|
- goto out;
|
|
- if (vma->vm_start <= address)
|
|
- goto good_area;
|
|
- if (!(vma->vm_flags & VM_GROWSDOWN))
|
|
- goto out;
|
|
- if (is_user && !ARCH_IS_STACKGROW(address))
|
|
- goto out;
|
|
- vma = expand_stack(mm, address);
|
|
+ vma = um_lock_mm_and_find_vma(mm, address, is_user);
|
|
if (!vma)
|
|
goto out_nosemaphore;
|
|
|
|
-good_area:
|
|
*code_out = SEGV_ACCERR;
|
|
if (is_write) {
|
|
if (!(vma->vm_flags & VM_WRITE))
|
|
diff --git a/arch/x86/tools/insn_decoder_test.c b/arch/x86/tools/insn_decoder_test.c
|
|
index 472540aeabc235..08cd913cbd4e9a 100644
|
|
--- a/arch/x86/tools/insn_decoder_test.c
|
|
+++ b/arch/x86/tools/insn_decoder_test.c
|
|
@@ -10,8 +10,7 @@
|
|
#include <assert.h>
|
|
#include <unistd.h>
|
|
#include <stdarg.h>
|
|
-
|
|
-#define unlikely(cond) (cond)
|
|
+#include <linux/kallsyms.h>
|
|
|
|
#include <asm/insn.h>
|
|
#include <inat.c>
|
|
@@ -106,7 +105,7 @@ static void parse_args(int argc, char **argv)
|
|
}
|
|
}
|
|
|
|
-#define BUFSIZE 256
|
|
+#define BUFSIZE (256 + KSYM_NAME_LEN)
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
diff --git a/arch/x86/um/asm/checksum.h b/arch/x86/um/asm/checksum.h
|
|
index b07824500363fa..ddc144657efad9 100644
|
|
--- a/arch/x86/um/asm/checksum.h
|
|
+++ b/arch/x86/um/asm/checksum.h
|
|
@@ -20,6 +20,9 @@
|
|
*/
|
|
extern __wsum csum_partial(const void *buff, int len, __wsum sum);
|
|
|
|
+/* Do not call this directly. Declared for export type visibility. */
|
|
+extern __visible __wsum csum_partial_copy_generic(const void *src, void *dst, int len);
|
|
+
|
|
/**
|
|
* csum_fold - Fold and invert a 32bit checksum.
|
|
* sum: 32bit unfolded sum
|
|
diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c
|
|
index d7f7f88009d7db..1728cae1e8409f 100644
|
|
--- a/drivers/cxl/core/region.c
|
|
+++ b/drivers/cxl/core/region.c
|
|
@@ -1653,6 +1653,13 @@ static int find_pos_and_ways(struct cxl_port *port, struct range *range,
|
|
}
|
|
put_device(dev);
|
|
|
|
+ if (rc)
|
|
+ dev_err(port->uport_dev,
|
|
+ "failed to find %s:%s in target list of %s\n",
|
|
+ dev_name(&port->dev),
|
|
+ dev_name(port->parent_dport->dport_dev),
|
|
+ dev_name(&cxlsd->cxld.dev));
|
|
+
|
|
return rc;
|
|
}
|
|
|
|
diff --git a/drivers/dma/idxd/cdev.c b/drivers/dma/idxd/cdev.c
|
|
index 7e3a67f9f0a654..aa39fcd389a942 100644
|
|
--- a/drivers/dma/idxd/cdev.c
|
|
+++ b/drivers/dma/idxd/cdev.c
|
|
@@ -354,7 +354,9 @@ static void idxd_cdev_evl_drain_pasid(struct idxd_wq *wq, u32 pasid)
|
|
set_bit(h, evl->bmap);
|
|
h = (h + 1) % size;
|
|
}
|
|
- drain_workqueue(wq->wq);
|
|
+ if (wq->wq)
|
|
+ drain_workqueue(wq->wq);
|
|
+
|
|
mutex_unlock(&evl->lock);
|
|
}
|
|
|
|
diff --git a/drivers/dma/xilinx/xilinx_dma.c b/drivers/dma/xilinx/xilinx_dma.c
|
|
index 0a3b2e22f23dbb..14c4c5031b556f 100644
|
|
--- a/drivers/dma/xilinx/xilinx_dma.c
|
|
+++ b/drivers/dma/xilinx/xilinx_dma.c
|
|
@@ -2900,6 +2900,8 @@ static int xilinx_dma_chan_probe(struct xilinx_dma_device *xdev,
|
|
return -EINVAL;
|
|
}
|
|
|
|
+ xdev->common.directions |= chan->direction;
|
|
+
|
|
/* Request the interrupt */
|
|
chan->irq = of_irq_get(node, chan->tdest);
|
|
if (chan->irq < 0)
|
|
diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c
|
|
index 10119cf27ffde5..a8db2bde638401 100644
|
|
--- a/drivers/edac/amd64_edac.c
|
|
+++ b/drivers/edac/amd64_edac.c
|
|
@@ -1475,7 +1475,9 @@ static int umc_get_cs_mode(int dimm, u8 ctrl, struct amd64_pvt *pvt)
|
|
if (csrow_enabled(2 * dimm + 1, ctrl, pvt))
|
|
cs_mode |= CS_ODD_PRIMARY;
|
|
|
|
- /* Asymmetric dual-rank DIMM support. */
|
|
+ if (csrow_sec_enabled(2 * dimm, ctrl, pvt))
|
|
+ cs_mode |= CS_EVEN_SECONDARY;
|
|
+
|
|
if (csrow_sec_enabled(2 * dimm + 1, ctrl, pvt))
|
|
cs_mode |= CS_ODD_SECONDARY;
|
|
|
|
@@ -1496,12 +1498,13 @@ static int umc_get_cs_mode(int dimm, u8 ctrl, struct amd64_pvt *pvt)
|
|
return cs_mode;
|
|
}
|
|
|
|
-static int __addr_mask_to_cs_size(u32 addr_mask_orig, unsigned int cs_mode,
|
|
- int csrow_nr, int dimm)
|
|
+static int calculate_cs_size(u32 mask, unsigned int cs_mode)
|
|
{
|
|
- u32 msb, weight, num_zero_bits;
|
|
- u32 addr_mask_deinterleaved;
|
|
- int size = 0;
|
|
+ int msb, weight, num_zero_bits;
|
|
+ u32 deinterleaved_mask;
|
|
+
|
|
+ if (!mask)
|
|
+ return 0;
|
|
|
|
/*
|
|
* The number of zero bits in the mask is equal to the number of bits
|
|
@@ -1514,19 +1517,30 @@ static int __addr_mask_to_cs_size(u32 addr_mask_orig, unsigned int cs_mode,
|
|
* without swapping with the most significant bit. This can be handled
|
|
* by keeping the MSB where it is and ignoring the single zero bit.
|
|
*/
|
|
- msb = fls(addr_mask_orig) - 1;
|
|
- weight = hweight_long(addr_mask_orig);
|
|
+ msb = fls(mask) - 1;
|
|
+ weight = hweight_long(mask);
|
|
num_zero_bits = msb - weight - !!(cs_mode & CS_3R_INTERLEAVE);
|
|
|
|
/* Take the number of zero bits off from the top of the mask. */
|
|
- addr_mask_deinterleaved = GENMASK_ULL(msb - num_zero_bits, 1);
|
|
+ deinterleaved_mask = GENMASK(msb - num_zero_bits, 1);
|
|
+ edac_dbg(1, " Deinterleaved AddrMask: 0x%x\n", deinterleaved_mask);
|
|
+
|
|
+ return (deinterleaved_mask >> 2) + 1;
|
|
+}
|
|
+
|
|
+static int __addr_mask_to_cs_size(u32 addr_mask, u32 addr_mask_sec,
|
|
+ unsigned int cs_mode, int csrow_nr, int dimm)
|
|
+{
|
|
+ int size;
|
|
|
|
edac_dbg(1, "CS%d DIMM%d AddrMasks:\n", csrow_nr, dimm);
|
|
- edac_dbg(1, " Original AddrMask: 0x%x\n", addr_mask_orig);
|
|
- edac_dbg(1, " Deinterleaved AddrMask: 0x%x\n", addr_mask_deinterleaved);
|
|
+ edac_dbg(1, " Primary AddrMask: 0x%x\n", addr_mask);
|
|
|
|
/* Register [31:1] = Address [39:9]. Size is in kBs here. */
|
|
- size = (addr_mask_deinterleaved >> 2) + 1;
|
|
+ size = calculate_cs_size(addr_mask, cs_mode);
|
|
+
|
|
+ edac_dbg(1, " Secondary AddrMask: 0x%x\n", addr_mask_sec);
|
|
+ size += calculate_cs_size(addr_mask_sec, cs_mode);
|
|
|
|
/* Return size in MBs. */
|
|
return size >> 10;
|
|
@@ -1535,8 +1549,8 @@ static int __addr_mask_to_cs_size(u32 addr_mask_orig, unsigned int cs_mode,
|
|
static int umc_addr_mask_to_cs_size(struct amd64_pvt *pvt, u8 umc,
|
|
unsigned int cs_mode, int csrow_nr)
|
|
{
|
|
+ u32 addr_mask = 0, addr_mask_sec = 0;
|
|
int cs_mask_nr = csrow_nr;
|
|
- u32 addr_mask_orig;
|
|
int dimm, size = 0;
|
|
|
|
/* No Chip Selects are enabled. */
|
|
@@ -1574,13 +1588,13 @@ static int umc_addr_mask_to_cs_size(struct amd64_pvt *pvt, u8 umc,
|
|
if (!pvt->flags.zn_regs_v2)
|
|
cs_mask_nr >>= 1;
|
|
|
|
- /* Asymmetric dual-rank DIMM support. */
|
|
- if ((csrow_nr & 1) && (cs_mode & CS_ODD_SECONDARY))
|
|
- addr_mask_orig = pvt->csels[umc].csmasks_sec[cs_mask_nr];
|
|
- else
|
|
- addr_mask_orig = pvt->csels[umc].csmasks[cs_mask_nr];
|
|
+ if (cs_mode & (CS_EVEN_PRIMARY | CS_ODD_PRIMARY))
|
|
+ addr_mask = pvt->csels[umc].csmasks[cs_mask_nr];
|
|
+
|
|
+ if (cs_mode & (CS_EVEN_SECONDARY | CS_ODD_SECONDARY))
|
|
+ addr_mask_sec = pvt->csels[umc].csmasks_sec[cs_mask_nr];
|
|
|
|
- return __addr_mask_to_cs_size(addr_mask_orig, cs_mode, csrow_nr, dimm);
|
|
+ return __addr_mask_to_cs_size(addr_mask, addr_mask_sec, cs_mode, csrow_nr, dimm);
|
|
}
|
|
|
|
static void umc_debug_display_dimm_sizes(struct amd64_pvt *pvt, u8 ctrl)
|
|
@@ -3773,9 +3787,10 @@ static void gpu_get_err_info(struct mce *m, struct err_info *err)
|
|
static int gpu_addr_mask_to_cs_size(struct amd64_pvt *pvt, u8 umc,
|
|
unsigned int cs_mode, int csrow_nr)
|
|
{
|
|
- u32 addr_mask_orig = pvt->csels[umc].csmasks[csrow_nr];
|
|
+ u32 addr_mask = pvt->csels[umc].csmasks[csrow_nr];
|
|
+ u32 addr_mask_sec = pvt->csels[umc].csmasks_sec[csrow_nr];
|
|
|
|
- return __addr_mask_to_cs_size(addr_mask_orig, cs_mode, csrow_nr, csrow_nr >> 1);
|
|
+ return __addr_mask_to_cs_size(addr_mask, addr_mask_sec, cs_mode, csrow_nr, csrow_nr >> 1);
|
|
}
|
|
|
|
static void gpu_debug_display_dimm_sizes(struct amd64_pvt *pvt, u8 ctrl)
|
|
diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c
|
|
index 65d1e66a347d75..d1fd2e492909e5 100644
|
|
--- a/drivers/firmware/arm_scmi/driver.c
|
|
+++ b/drivers/firmware/arm_scmi/driver.c
|
|
@@ -1547,6 +1547,39 @@ static int scmi_common_extended_name_get(const struct scmi_protocol_handle *ph,
|
|
return ret;
|
|
}
|
|
|
|
+/**
|
|
+ * scmi_protocol_msg_check - Check protocol message attributes
|
|
+ *
|
|
+ * @ph: A reference to the protocol handle.
|
|
+ * @message_id: The ID of the message to check.
|
|
+ * @attributes: A parameter to optionally return the retrieved message
|
|
+ * attributes, in case of Success.
|
|
+ *
|
|
+ * An helper to check protocol message attributes for a specific protocol
|
|
+ * and message pair.
|
|
+ *
|
|
+ * Return: 0 on SUCCESS
|
|
+ */
|
|
+static int scmi_protocol_msg_check(const struct scmi_protocol_handle *ph,
|
|
+ u32 message_id, u32 *attributes)
|
|
+{
|
|
+ int ret;
|
|
+ struct scmi_xfer *t;
|
|
+
|
|
+ ret = xfer_get_init(ph, PROTOCOL_MESSAGE_ATTRIBUTES,
|
|
+ sizeof(__le32), 0, &t);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ put_unaligned_le32(message_id, t->tx.buf);
|
|
+ ret = do_xfer(ph, t);
|
|
+ if (!ret && attributes)
|
|
+ *attributes = get_unaligned_le32(t->rx.buf);
|
|
+ xfer_put(ph, t);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
/**
|
|
* struct scmi_iterator - Iterator descriptor
|
|
* @msg: A reference to the message TX buffer; filled by @prepare_message with
|
|
@@ -1688,6 +1721,7 @@ scmi_common_fastchannel_init(const struct scmi_protocol_handle *ph,
|
|
int ret;
|
|
u32 flags;
|
|
u64 phys_addr;
|
|
+ u32 attributes;
|
|
u8 size;
|
|
void __iomem *addr;
|
|
struct scmi_xfer *t;
|
|
@@ -1696,6 +1730,15 @@ scmi_common_fastchannel_init(const struct scmi_protocol_handle *ph,
|
|
struct scmi_msg_resp_desc_fc *resp;
|
|
const struct scmi_protocol_instance *pi = ph_to_pi(ph);
|
|
|
|
+ /* Check if the MSG_ID supports fastchannel */
|
|
+ ret = scmi_protocol_msg_check(ph, message_id, &attributes);
|
|
+ if (ret || !MSG_SUPPORTS_FASTCHANNEL(attributes)) {
|
|
+ dev_dbg(ph->dev,
|
|
+ "Skip FC init for 0x%02X/%d domain:%d - ret:%d\n",
|
|
+ pi->proto->id, message_id, domain, ret);
|
|
+ return;
|
|
+ }
|
|
+
|
|
if (!p_addr) {
|
|
ret = -EINVAL;
|
|
goto err_out;
|
|
@@ -1824,6 +1867,7 @@ static const struct scmi_proto_helpers_ops helpers_ops = {
|
|
.extended_name_get = scmi_common_extended_name_get,
|
|
.iter_response_init = scmi_iterator_init,
|
|
.iter_response_run = scmi_iterator_run,
|
|
+ .protocol_msg_check = scmi_protocol_msg_check,
|
|
.fastchannel_init = scmi_common_fastchannel_init,
|
|
.fastchannel_db_ring = scmi_common_fastchannel_db_ring,
|
|
};
|
|
diff --git a/drivers/firmware/arm_scmi/protocols.h b/drivers/firmware/arm_scmi/protocols.h
|
|
index 78e1a01eb656e3..095b14a2d0a3f6 100644
|
|
--- a/drivers/firmware/arm_scmi/protocols.h
|
|
+++ b/drivers/firmware/arm_scmi/protocols.h
|
|
@@ -29,6 +29,8 @@
|
|
#define PROTOCOL_REV_MAJOR(x) ((u16)(FIELD_GET(PROTOCOL_REV_MAJOR_MASK, (x))))
|
|
#define PROTOCOL_REV_MINOR(x) ((u16)(FIELD_GET(PROTOCOL_REV_MINOR_MASK, (x))))
|
|
|
|
+#define MSG_SUPPORTS_FASTCHANNEL(x) ((x) & BIT(0))
|
|
+
|
|
enum scmi_common_cmd {
|
|
PROTOCOL_VERSION = 0x0,
|
|
PROTOCOL_ATTRIBUTES = 0x1,
|
|
@@ -250,6 +252,8 @@ struct scmi_fc_info {
|
|
* provided in @ops.
|
|
* @iter_response_run: A common helper to trigger the run of a previously
|
|
* initialized iterator.
|
|
+ * @protocol_msg_check: A common helper to check is a specific protocol message
|
|
+ * is supported.
|
|
* @fastchannel_init: A common helper used to initialize FC descriptors by
|
|
* gathering FC descriptions from the SCMI platform server.
|
|
* @fastchannel_db_ring: A common helper to ring a FC doorbell.
|
|
@@ -262,6 +266,8 @@ struct scmi_proto_helpers_ops {
|
|
unsigned int max_resources, u8 msg_id,
|
|
size_t tx_size, void *priv);
|
|
int (*iter_response_run)(void *iter);
|
|
+ int (*protocol_msg_check)(const struct scmi_protocol_handle *ph,
|
|
+ u32 message_id, u32 *attributes);
|
|
void (*fastchannel_init)(const struct scmi_protocol_handle *ph,
|
|
u8 describe_id, u32 message_id,
|
|
u32 valid_size, u32 domain,
|
|
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c
|
|
index 963e106d32eed0..256cc15fc9b5a1 100644
|
|
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c
|
|
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c
|
|
@@ -1890,7 +1890,7 @@ static void amdgpu_ib_preempt_mark_partial_job(struct amdgpu_ring *ring)
|
|
continue;
|
|
}
|
|
job = to_amdgpu_job(s_job);
|
|
- if (preempted && (&job->hw_fence) == fence)
|
|
+ if (preempted && (&job->hw_fence.base) == fence)
|
|
/* mark the job as preempted */
|
|
job->preemption_status |= AMDGPU_IB_PREEMPTED;
|
|
}
|
|
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
|
|
index f8058dd5356a13..200b59318759da 100644
|
|
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
|
|
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
|
|
@@ -5367,7 +5367,7 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev,
|
|
*
|
|
* job->base holds a reference to parent fence
|
|
*/
|
|
- if (job && dma_fence_is_signaled(&job->hw_fence)) {
|
|
+ if (job && dma_fence_is_signaled(&job->hw_fence.base)) {
|
|
job_signaled = true;
|
|
dev_info(adev->dev, "Guilty job already signaled, skipping HW reset");
|
|
goto skip_hw_reset;
|
|
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c
|
|
index 7537f5aa76f0c0..017dd494d0a2f6 100644
|
|
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c
|
|
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c
|
|
@@ -41,22 +41,6 @@
|
|
#include "amdgpu_trace.h"
|
|
#include "amdgpu_reset.h"
|
|
|
|
-/*
|
|
- * Fences mark an event in the GPUs pipeline and are used
|
|
- * for GPU/CPU synchronization. When the fence is written,
|
|
- * it is expected that all buffers associated with that fence
|
|
- * are no longer in use by the associated ring on the GPU and
|
|
- * that the relevant GPU caches have been flushed.
|
|
- */
|
|
-
|
|
-struct amdgpu_fence {
|
|
- struct dma_fence base;
|
|
-
|
|
- /* RB, DMA, etc. */
|
|
- struct amdgpu_ring *ring;
|
|
- ktime_t start_timestamp;
|
|
-};
|
|
-
|
|
static struct kmem_cache *amdgpu_fence_slab;
|
|
|
|
int amdgpu_fence_slab_init(void)
|
|
@@ -153,12 +137,12 @@ int amdgpu_fence_emit(struct amdgpu_ring *ring, struct dma_fence **f, struct amd
|
|
am_fence = kmem_cache_alloc(amdgpu_fence_slab, GFP_ATOMIC);
|
|
if (am_fence == NULL)
|
|
return -ENOMEM;
|
|
- fence = &am_fence->base;
|
|
- am_fence->ring = ring;
|
|
} else {
|
|
/* take use of job-embedded fence */
|
|
- fence = &job->hw_fence;
|
|
+ am_fence = &job->hw_fence;
|
|
}
|
|
+ fence = &am_fence->base;
|
|
+ am_fence->ring = ring;
|
|
|
|
seq = ++ring->fence_drv.sync_seq;
|
|
if (job && job->job_run_counter) {
|
|
@@ -719,7 +703,7 @@ void amdgpu_fence_driver_clear_job_fences(struct amdgpu_ring *ring)
|
|
* it right here or we won't be able to track them in fence_drv
|
|
* and they will remain unsignaled during sa_bo free.
|
|
*/
|
|
- job = container_of(old, struct amdgpu_job, hw_fence);
|
|
+ job = container_of(old, struct amdgpu_job, hw_fence.base);
|
|
if (!job->base.s_fence && !dma_fence_is_signaled(old))
|
|
dma_fence_signal(old);
|
|
RCU_INIT_POINTER(*ptr, NULL);
|
|
@@ -781,7 +765,7 @@ static const char *amdgpu_fence_get_timeline_name(struct dma_fence *f)
|
|
|
|
static const char *amdgpu_job_fence_get_timeline_name(struct dma_fence *f)
|
|
{
|
|
- struct amdgpu_job *job = container_of(f, struct amdgpu_job, hw_fence);
|
|
+ struct amdgpu_job *job = container_of(f, struct amdgpu_job, hw_fence.base);
|
|
|
|
return (const char *)to_amdgpu_ring(job->base.sched)->name;
|
|
}
|
|
@@ -811,7 +795,7 @@ static bool amdgpu_fence_enable_signaling(struct dma_fence *f)
|
|
*/
|
|
static bool amdgpu_job_fence_enable_signaling(struct dma_fence *f)
|
|
{
|
|
- struct amdgpu_job *job = container_of(f, struct amdgpu_job, hw_fence);
|
|
+ struct amdgpu_job *job = container_of(f, struct amdgpu_job, hw_fence.base);
|
|
|
|
if (!timer_pending(&to_amdgpu_ring(job->base.sched)->fence_drv.fallback_timer))
|
|
amdgpu_fence_schedule_fallback(to_amdgpu_ring(job->base.sched));
|
|
@@ -846,7 +830,7 @@ static void amdgpu_job_fence_free(struct rcu_head *rcu)
|
|
struct dma_fence *f = container_of(rcu, struct dma_fence, rcu);
|
|
|
|
/* free job if fence has a parent job */
|
|
- kfree(container_of(f, struct amdgpu_job, hw_fence));
|
|
+ kfree(container_of(f, struct amdgpu_job, hw_fence.base));
|
|
}
|
|
|
|
/**
|
|
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c
|
|
index 49a6b6b88843dd..e9adfc88a54ab1 100644
|
|
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c
|
|
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c
|
|
@@ -165,8 +165,8 @@ void amdgpu_job_free_resources(struct amdgpu_job *job)
|
|
/* Check if any fences where initialized */
|
|
if (job->base.s_fence && job->base.s_fence->finished.ops)
|
|
f = &job->base.s_fence->finished;
|
|
- else if (job->hw_fence.ops)
|
|
- f = &job->hw_fence;
|
|
+ else if (job->hw_fence.base.ops)
|
|
+ f = &job->hw_fence.base;
|
|
else
|
|
f = NULL;
|
|
|
|
@@ -183,10 +183,10 @@ static void amdgpu_job_free_cb(struct drm_sched_job *s_job)
|
|
amdgpu_sync_free(&job->explicit_sync);
|
|
|
|
/* only put the hw fence if has embedded fence */
|
|
- if (!job->hw_fence.ops)
|
|
+ if (!job->hw_fence.base.ops)
|
|
kfree(job);
|
|
else
|
|
- dma_fence_put(&job->hw_fence);
|
|
+ dma_fence_put(&job->hw_fence.base);
|
|
}
|
|
|
|
void amdgpu_job_set_gang_leader(struct amdgpu_job *job,
|
|
@@ -215,10 +215,10 @@ void amdgpu_job_free(struct amdgpu_job *job)
|
|
if (job->gang_submit != &job->base.s_fence->scheduled)
|
|
dma_fence_put(job->gang_submit);
|
|
|
|
- if (!job->hw_fence.ops)
|
|
+ if (!job->hw_fence.base.ops)
|
|
kfree(job);
|
|
else
|
|
- dma_fence_put(&job->hw_fence);
|
|
+ dma_fence_put(&job->hw_fence.base);
|
|
}
|
|
|
|
struct dma_fence *amdgpu_job_submit(struct amdgpu_job *job)
|
|
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.h
|
|
index a963a25ddd6209..65b6fbab544e5f 100644
|
|
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.h
|
|
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.h
|
|
@@ -48,7 +48,7 @@ struct amdgpu_job {
|
|
struct drm_sched_job base;
|
|
struct amdgpu_vm *vm;
|
|
struct amdgpu_sync explicit_sync;
|
|
- struct dma_fence hw_fence;
|
|
+ struct amdgpu_fence hw_fence;
|
|
struct dma_fence *gang_submit;
|
|
uint32_t preamble_status;
|
|
uint32_t preemption_status;
|
|
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
|
|
index e2ab303ad2708e..60f770b99c2c54 100644
|
|
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
|
|
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
|
|
@@ -123,6 +123,22 @@ struct amdgpu_fence_driver {
|
|
struct dma_fence **fences;
|
|
};
|
|
|
|
+/*
|
|
+ * Fences mark an event in the GPUs pipeline and are used
|
|
+ * for GPU/CPU synchronization. When the fence is written,
|
|
+ * it is expected that all buffers associated with that fence
|
|
+ * are no longer in use by the associated ring on the GPU and
|
|
+ * that the relevant GPU caches have been flushed.
|
|
+ */
|
|
+
|
|
+struct amdgpu_fence {
|
|
+ struct dma_fence base;
|
|
+
|
|
+ /* RB, DMA, etc. */
|
|
+ struct amdgpu_ring *ring;
|
|
+ ktime_t start_timestamp;
|
|
+};
|
|
+
|
|
extern const struct drm_sched_backend_ops amdgpu_sched_ops;
|
|
|
|
void amdgpu_fence_driver_clear_job_fences(struct amdgpu_ring *ring);
|
|
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c
|
|
index bef7541770641c..e9d2fcdde0e1c6 100644
|
|
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c
|
|
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c
|
|
@@ -28,6 +28,10 @@
|
|
#include "amdgpu.h"
|
|
#include "amdgpu_ucode.h"
|
|
|
|
+static const struct kicker_device kicker_device_list[] = {
|
|
+ {0x744B, 0x00},
|
|
+};
|
|
+
|
|
static void amdgpu_ucode_print_common_hdr(const struct common_firmware_header *hdr)
|
|
{
|
|
DRM_DEBUG("size_bytes: %u\n", le32_to_cpu(hdr->size_bytes));
|
|
@@ -1268,6 +1272,19 @@ static const char *amdgpu_ucode_legacy_naming(struct amdgpu_device *adev, int bl
|
|
return NULL;
|
|
}
|
|
|
|
+bool amdgpu_is_kicker_fw(struct amdgpu_device *adev)
|
|
+{
|
|
+ int i;
|
|
+
|
|
+ for (i = 0; i < ARRAY_SIZE(kicker_device_list); i++) {
|
|
+ if (adev->pdev->device == kicker_device_list[i].device &&
|
|
+ adev->pdev->revision == kicker_device_list[i].revision)
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ return false;
|
|
+}
|
|
+
|
|
void amdgpu_ucode_ip_version_decode(struct amdgpu_device *adev, int block_type, char *ucode_prefix, int len)
|
|
{
|
|
int maj, min, rev;
|
|
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h
|
|
index b03321e7d2d893..4760092aafd723 100644
|
|
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h
|
|
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h
|
|
@@ -536,6 +536,11 @@ struct amdgpu_firmware {
|
|
uint64_t fw_buf_mc;
|
|
};
|
|
|
|
+struct kicker_device{
|
|
+ unsigned short device;
|
|
+ u8 revision;
|
|
+};
|
|
+
|
|
void amdgpu_ucode_print_mc_hdr(const struct common_firmware_header *hdr);
|
|
void amdgpu_ucode_print_smc_hdr(const struct common_firmware_header *hdr);
|
|
void amdgpu_ucode_print_imu_hdr(const struct common_firmware_header *hdr);
|
|
@@ -562,5 +567,6 @@ amdgpu_ucode_get_load_type(struct amdgpu_device *adev, int load_type);
|
|
const char *amdgpu_ucode_name(enum AMDGPU_UCODE_ID ucode_id);
|
|
|
|
void amdgpu_ucode_ip_version_decode(struct amdgpu_device *adev, int block_type, char *ucode_prefix, int len);
|
|
+bool amdgpu_is_kicker_fw(struct amdgpu_device *adev);
|
|
|
|
#endif
|
|
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
|
|
index c7085a747b03b7..451c37d04e4567 100644
|
|
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
|
|
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
|
|
@@ -435,7 +435,7 @@ static int amdgpu_vram_mgr_new(struct ttm_resource_manager *man,
|
|
int r;
|
|
|
|
lpfn = (u64)place->lpfn << PAGE_SHIFT;
|
|
- if (!lpfn)
|
|
+ if (!lpfn || lpfn > man->size)
|
|
lpfn = man->size;
|
|
|
|
fpfn = (u64)place->fpfn << PAGE_SHIFT;
|
|
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_events.c b/drivers/gpu/drm/amd/amdkfd/kfd_events.c
|
|
index 0f58be65132fc0..2b07c0000df6eb 100644
|
|
--- a/drivers/gpu/drm/amd/amdkfd/kfd_events.c
|
|
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_events.c
|
|
@@ -1287,6 +1287,7 @@ void kfd_signal_poison_consumed_event(struct kfd_node *dev, u32 pasid)
|
|
user_gpu_id = kfd_process_get_user_gpu_id(p, dev->id);
|
|
if (unlikely(user_gpu_id == -EINVAL)) {
|
|
WARN_ONCE(1, "Could not get user_gpu_id from dev->id:%x\n", dev->id);
|
|
+ kfd_unref_process(p);
|
|
return;
|
|
}
|
|
|
|
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager_v9.c b/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager_v9.c
|
|
index 1a03173e231337..18e82d0da75bcd 100644
|
|
--- a/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager_v9.c
|
|
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager_v9.c
|
|
@@ -225,7 +225,7 @@ static int pm_map_queues_v9(struct packet_manager *pm, uint32_t *buffer,
|
|
|
|
packet->bitfields2.engine_sel =
|
|
engine_sel__mes_map_queues__compute_vi;
|
|
- packet->bitfields2.gws_control_queue = q->gws ? 1 : 0;
|
|
+ packet->bitfields2.gws_control_queue = q->properties.is_gws ? 1 : 0;
|
|
packet->bitfields2.extended_engine_sel =
|
|
extended_engine_sel__mes_map_queues__legacy_engine_sel;
|
|
packet->bitfields2.queue_type =
|
|
diff --git a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_psp.c b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_psp.c
|
|
index ff930a71e496a9..7f8f127e7722de 100644
|
|
--- a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_psp.c
|
|
+++ b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_psp.c
|
|
@@ -368,6 +368,9 @@ enum mod_hdcp_status mod_hdcp_hdcp1_enable_encryption(struct mod_hdcp *hdcp)
|
|
struct mod_hdcp_display *display = get_first_active_display(hdcp);
|
|
enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS;
|
|
|
|
+ if (!display)
|
|
+ return MOD_HDCP_STATUS_DISPLAY_NOT_FOUND;
|
|
+
|
|
mutex_lock(&psp->hdcp_context.mutex);
|
|
hdcp_cmd = (struct ta_hdcp_shared_memory *)psp->hdcp_context.context.mem_context.shared_buf;
|
|
memset(hdcp_cmd, 0, sizeof(struct ta_hdcp_shared_memory));
|
|
diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c
|
|
index 5f58da6ebaadb4..27e660e92489f6 100644
|
|
--- a/drivers/gpu/drm/ast/ast_mode.c
|
|
+++ b/drivers/gpu/drm/ast/ast_mode.c
|
|
@@ -1868,9 +1868,9 @@ static void ast_mode_config_helper_atomic_commit_tail(struct drm_atomic_state *s
|
|
|
|
/*
|
|
* Concurrent operations could possibly trigger a call to
|
|
- * drm_connector_helper_funcs.get_modes by trying to read the
|
|
- * display modes. Protect access to I/O registers by acquiring
|
|
- * the I/O-register lock. Released in atomic_flush().
|
|
+ * drm_connector_helper_funcs.get_modes by reading the display
|
|
+ * modes. Protect access to registers by acquiring the modeset
|
|
+ * lock.
|
|
*/
|
|
mutex_lock(&ast->ioregs_lock);
|
|
drm_atomic_helper_commit_tail_rpm(state);
|
|
diff --git a/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c
|
|
index 7457d38622b0c7..89eed0668bfb24 100644
|
|
--- a/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c
|
|
+++ b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c
|
|
@@ -568,15 +568,18 @@ static int cdns_dsi_check_conf(struct cdns_dsi *dsi,
|
|
struct phy_configure_opts_mipi_dphy *phy_cfg = &output->phy_opts.mipi_dphy;
|
|
unsigned long dsi_hss_hsa_hse_hbp;
|
|
unsigned int nlanes = output->dev->lanes;
|
|
+ int mode_clock = (mode_valid_check ? mode->clock : mode->crtc_clock);
|
|
int ret;
|
|
|
|
ret = cdns_dsi_mode2cfg(dsi, mode, dsi_cfg, mode_valid_check);
|
|
if (ret)
|
|
return ret;
|
|
|
|
- phy_mipi_dphy_get_default_config(mode->crtc_clock * 1000,
|
|
- mipi_dsi_pixel_format_to_bpp(output->dev->format),
|
|
- nlanes, phy_cfg);
|
|
+ ret = phy_mipi_dphy_get_default_config(mode_clock * 1000,
|
|
+ mipi_dsi_pixel_format_to_bpp(output->dev->format),
|
|
+ nlanes, phy_cfg);
|
|
+ if (ret)
|
|
+ return ret;
|
|
|
|
ret = cdns_dsi_adjust_phy_config(dsi, dsi_cfg, phy_cfg, mode, mode_valid_check);
|
|
if (ret)
|
|
@@ -680,6 +683,11 @@ static void cdns_dsi_bridge_post_disable(struct drm_bridge *bridge)
|
|
struct cdns_dsi_input *input = bridge_to_cdns_dsi_input(bridge);
|
|
struct cdns_dsi *dsi = input_to_dsi(input);
|
|
|
|
+ dsi->phy_initialized = false;
|
|
+ dsi->link_initialized = false;
|
|
+ phy_power_off(dsi->dphy);
|
|
+ phy_exit(dsi->dphy);
|
|
+
|
|
pm_runtime_put(dsi->base.dev);
|
|
}
|
|
|
|
@@ -761,7 +769,7 @@ static void cdns_dsi_bridge_enable(struct drm_bridge *bridge)
|
|
struct phy_configure_opts_mipi_dphy *phy_cfg = &output->phy_opts.mipi_dphy;
|
|
unsigned long tx_byte_period;
|
|
struct cdns_dsi_cfg dsi_cfg;
|
|
- u32 tmp, reg_wakeup, div;
|
|
+ u32 tmp, reg_wakeup, div, status;
|
|
int nlanes;
|
|
|
|
if (WARN_ON(pm_runtime_get_sync(dsi->base.dev) < 0))
|
|
@@ -778,6 +786,19 @@ static void cdns_dsi_bridge_enable(struct drm_bridge *bridge)
|
|
cdns_dsi_hs_init(dsi);
|
|
cdns_dsi_init_link(dsi);
|
|
|
|
+ /*
|
|
+ * Now that the DSI Link and DSI Phy are initialized,
|
|
+ * wait for the CLK and Data Lanes to be ready.
|
|
+ */
|
|
+ tmp = CLK_LANE_RDY;
|
|
+ for (int i = 0; i < nlanes; i++)
|
|
+ tmp |= DATA_LANE_RDY(i);
|
|
+
|
|
+ if (readl_poll_timeout(dsi->regs + MCTL_MAIN_STS, status,
|
|
+ (tmp == (status & tmp)), 100, 500000))
|
|
+ dev_err(dsi->base.dev,
|
|
+ "Timed Out: DSI-DPhy Clock and Data Lanes not ready.\n");
|
|
+
|
|
writel(HBP_LEN(dsi_cfg.hbp) | HSA_LEN(dsi_cfg.hsa),
|
|
dsi->regs + VID_HSIZE1);
|
|
writel(HFP_LEN(dsi_cfg.hfp) | HACT_LEN(dsi_cfg.hact),
|
|
@@ -952,7 +973,7 @@ static int cdns_dsi_attach(struct mipi_dsi_host *host,
|
|
bridge = drm_panel_bridge_add_typed(panel,
|
|
DRM_MODE_CONNECTOR_DSI);
|
|
} else {
|
|
- bridge = of_drm_find_bridge(dev->dev.of_node);
|
|
+ bridge = of_drm_find_bridge(np);
|
|
if (!bridge)
|
|
bridge = ERR_PTR(-EINVAL);
|
|
}
|
|
@@ -1152,7 +1173,6 @@ static int __maybe_unused cdns_dsi_suspend(struct device *dev)
|
|
clk_disable_unprepare(dsi->dsi_sys_clk);
|
|
clk_disable_unprepare(dsi->dsi_p_clk);
|
|
reset_control_assert(dsi->dsi_p_rst);
|
|
- dsi->link_initialized = false;
|
|
return 0;
|
|
}
|
|
|
|
diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi86.c b/drivers/gpu/drm/bridge/ti-sn65dsi86.c
|
|
index bfbd3fee125671..002f8aaa509bc9 100644
|
|
--- a/drivers/gpu/drm/bridge/ti-sn65dsi86.c
|
|
+++ b/drivers/gpu/drm/bridge/ti-sn65dsi86.c
|
|
@@ -331,12 +331,18 @@ static void ti_sn65dsi86_enable_comms(struct ti_sn65dsi86 *pdata)
|
|
* 200 ms. We'll assume that the panel driver will have the hardcoded
|
|
* delay in its prepare and always disable HPD.
|
|
*
|
|
- * If HPD somehow makes sense on some future panel we'll have to
|
|
- * change this to be conditional on someone specifying that HPD should
|
|
- * be used.
|
|
+ * For DisplayPort bridge type, we need HPD. So we use the bridge type
|
|
+ * to conditionally disable HPD.
|
|
+ * NOTE: The bridge type is set in ti_sn_bridge_probe() but enable_comms()
|
|
+ * can be called before. So for DisplayPort, HPD will be enabled once
|
|
+ * bridge type is set. We are using bridge type instead of "no-hpd"
|
|
+ * property because it is not used properly in devicetree description
|
|
+ * and hence is unreliable.
|
|
*/
|
|
- regmap_update_bits(pdata->regmap, SN_HPD_DISABLE_REG, HPD_DISABLE,
|
|
- HPD_DISABLE);
|
|
+
|
|
+ if (pdata->bridge.type != DRM_MODE_CONNECTOR_DisplayPort)
|
|
+ regmap_update_bits(pdata->regmap, SN_HPD_DISABLE_REG, HPD_DISABLE,
|
|
+ HPD_DISABLE);
|
|
|
|
pdata->comms_enabled = true;
|
|
|
|
@@ -424,36 +430,8 @@ static int status_show(struct seq_file *s, void *data)
|
|
|
|
return 0;
|
|
}
|
|
-
|
|
DEFINE_SHOW_ATTRIBUTE(status);
|
|
|
|
-static void ti_sn65dsi86_debugfs_remove(void *data)
|
|
-{
|
|
- debugfs_remove_recursive(data);
|
|
-}
|
|
-
|
|
-static void ti_sn65dsi86_debugfs_init(struct ti_sn65dsi86 *pdata)
|
|
-{
|
|
- struct device *dev = pdata->dev;
|
|
- struct dentry *debugfs;
|
|
- int ret;
|
|
-
|
|
- debugfs = debugfs_create_dir(dev_name(dev), NULL);
|
|
-
|
|
- /*
|
|
- * We might get an error back if debugfs wasn't enabled in the kernel
|
|
- * so let's just silently return upon failure.
|
|
- */
|
|
- if (IS_ERR_OR_NULL(debugfs))
|
|
- return;
|
|
-
|
|
- ret = devm_add_action_or_reset(dev, ti_sn65dsi86_debugfs_remove, debugfs);
|
|
- if (ret)
|
|
- return;
|
|
-
|
|
- debugfs_create_file("status", 0600, debugfs, pdata, &status_fops);
|
|
-}
|
|
-
|
|
/* -----------------------------------------------------------------------------
|
|
* Auxiliary Devices (*not* AUX)
|
|
*/
|
|
@@ -1201,9 +1179,14 @@ static enum drm_connector_status ti_sn_bridge_detect(struct drm_bridge *bridge)
|
|
struct ti_sn65dsi86 *pdata = bridge_to_ti_sn65dsi86(bridge);
|
|
int val = 0;
|
|
|
|
- pm_runtime_get_sync(pdata->dev);
|
|
+ /*
|
|
+ * Runtime reference is grabbed in ti_sn_bridge_hpd_enable()
|
|
+ * as the chip won't report HPD just after being powered on.
|
|
+ * HPD_DEBOUNCED_STATE reflects correct state only after the
|
|
+ * debounce time (~100-400 ms).
|
|
+ */
|
|
+
|
|
regmap_read(pdata->regmap, SN_HPD_DISABLE_REG, &val);
|
|
- pm_runtime_put_autosuspend(pdata->dev);
|
|
|
|
return val & HPD_DEBOUNCED_STATE ? connector_status_connected
|
|
: connector_status_disconnected;
|
|
@@ -1217,6 +1200,35 @@ static struct edid *ti_sn_bridge_get_edid(struct drm_bridge *bridge,
|
|
return drm_get_edid(connector, &pdata->aux.ddc);
|
|
}
|
|
|
|
+static void ti_sn65dsi86_debugfs_init(struct drm_bridge *bridge, struct dentry *root)
|
|
+{
|
|
+ struct ti_sn65dsi86 *pdata = bridge_to_ti_sn65dsi86(bridge);
|
|
+ struct dentry *debugfs;
|
|
+
|
|
+ debugfs = debugfs_create_dir(dev_name(pdata->dev), root);
|
|
+ debugfs_create_file("status", 0600, debugfs, pdata, &status_fops);
|
|
+}
|
|
+
|
|
+static void ti_sn_bridge_hpd_enable(struct drm_bridge *bridge)
|
|
+{
|
|
+ struct ti_sn65dsi86 *pdata = bridge_to_ti_sn65dsi86(bridge);
|
|
+
|
|
+ /*
|
|
+ * Device needs to be powered on before reading the HPD state
|
|
+ * for reliable hpd detection in ti_sn_bridge_detect() due to
|
|
+ * the high debounce time.
|
|
+ */
|
|
+
|
|
+ pm_runtime_get_sync(pdata->dev);
|
|
+}
|
|
+
|
|
+static void ti_sn_bridge_hpd_disable(struct drm_bridge *bridge)
|
|
+{
|
|
+ struct ti_sn65dsi86 *pdata = bridge_to_ti_sn65dsi86(bridge);
|
|
+
|
|
+ pm_runtime_put_autosuspend(pdata->dev);
|
|
+}
|
|
+
|
|
static const struct drm_bridge_funcs ti_sn_bridge_funcs = {
|
|
.attach = ti_sn_bridge_attach,
|
|
.detach = ti_sn_bridge_detach,
|
|
@@ -1230,6 +1242,9 @@ static const struct drm_bridge_funcs ti_sn_bridge_funcs = {
|
|
.atomic_reset = drm_atomic_helper_bridge_reset,
|
|
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
|
|
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
|
|
+ .debugfs_init = ti_sn65dsi86_debugfs_init,
|
|
+ .hpd_enable = ti_sn_bridge_hpd_enable,
|
|
+ .hpd_disable = ti_sn_bridge_hpd_disable,
|
|
};
|
|
|
|
static void ti_sn_bridge_parse_lanes(struct ti_sn65dsi86 *pdata,
|
|
@@ -1318,8 +1333,26 @@ static int ti_sn_bridge_probe(struct auxiliary_device *adev,
|
|
pdata->bridge.type = pdata->next_bridge->type == DRM_MODE_CONNECTOR_DisplayPort
|
|
? DRM_MODE_CONNECTOR_DisplayPort : DRM_MODE_CONNECTOR_eDP;
|
|
|
|
- if (pdata->bridge.type == DRM_MODE_CONNECTOR_DisplayPort)
|
|
- pdata->bridge.ops = DRM_BRIDGE_OP_EDID | DRM_BRIDGE_OP_DETECT;
|
|
+ if (pdata->bridge.type == DRM_MODE_CONNECTOR_DisplayPort) {
|
|
+ pdata->bridge.ops = DRM_BRIDGE_OP_EDID | DRM_BRIDGE_OP_DETECT |
|
|
+ DRM_BRIDGE_OP_HPD;
|
|
+ /*
|
|
+ * If comms were already enabled they would have been enabled
|
|
+ * with the wrong value of HPD_DISABLE. Update it now. Comms
|
|
+ * could be enabled if anyone is holding a pm_runtime reference
|
|
+ * (like if a GPIO is in use). Note that in most cases nobody
|
|
+ * is doing AUX channel xfers before the bridge is added so
|
|
+ * HPD doesn't _really_ matter then. The only exception is in
|
|
+ * the eDP case where the panel wants to read the EDID before
|
|
+ * the bridge is added. We always consistently have HPD disabled
|
|
+ * for eDP.
|
|
+ */
|
|
+ mutex_lock(&pdata->comms_mutex);
|
|
+ if (pdata->comms_enabled)
|
|
+ regmap_update_bits(pdata->regmap, SN_HPD_DISABLE_REG,
|
|
+ HPD_DISABLE, 0);
|
|
+ mutex_unlock(&pdata->comms_mutex);
|
|
+ };
|
|
|
|
drm_bridge_add(&pdata->bridge);
|
|
|
|
@@ -1935,8 +1968,6 @@ static int ti_sn65dsi86_probe(struct i2c_client *client)
|
|
if (ret)
|
|
return ret;
|
|
|
|
- ti_sn65dsi86_debugfs_init(pdata);
|
|
-
|
|
/*
|
|
* Break ourselves up into a collection of aux devices. The only real
|
|
* motiviation here is to solve the chicken-and-egg problem of probe
|
|
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_sched.c b/drivers/gpu/drm/etnaviv/etnaviv_sched.c
|
|
index 97e406d9ac06f4..a3bd396c9d829d 100644
|
|
--- a/drivers/gpu/drm/etnaviv/etnaviv_sched.c
|
|
+++ b/drivers/gpu/drm/etnaviv/etnaviv_sched.c
|
|
@@ -34,6 +34,7 @@ static enum drm_gpu_sched_stat etnaviv_sched_timedout_job(struct drm_sched_job
|
|
*sched_job)
|
|
{
|
|
struct etnaviv_gem_submit *submit = to_etnaviv_submit(sched_job);
|
|
+ struct drm_gpu_scheduler *sched = sched_job->sched;
|
|
struct etnaviv_gpu *gpu = submit->gpu;
|
|
u32 dma_addr;
|
|
int change;
|
|
@@ -76,7 +77,9 @@ static enum drm_gpu_sched_stat etnaviv_sched_timedout_job(struct drm_sched_job
|
|
return DRM_GPU_SCHED_STAT_NOMINAL;
|
|
|
|
out_no_timeout:
|
|
- list_add(&sched_job->list, &sched_job->sched->pending_list);
|
|
+ spin_lock(&sched->job_list_lock);
|
|
+ list_add(&sched_job->list, &sched->pending_list);
|
|
+ spin_unlock(&sched->job_list_lock);
|
|
return DRM_GPU_SCHED_STAT_NOMINAL;
|
|
}
|
|
|
|
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
|
|
index 5a687a3686bd53..023b2ea74c3601 100644
|
|
--- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
|
|
+++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
|
|
@@ -2013,7 +2013,7 @@ static int eb_capture_stage(struct i915_execbuffer *eb)
|
|
continue;
|
|
|
|
if (i915_gem_context_is_recoverable(eb->gem_context) &&
|
|
- (IS_DGFX(eb->i915) || GRAPHICS_VER_FULL(eb->i915) > IP_VER(12, 0)))
|
|
+ GRAPHICS_VER_FULL(eb->i915) > IP_VER(12, 10))
|
|
return -EINVAL;
|
|
|
|
for_each_batch_create_order(eb, j) {
|
|
diff --git a/drivers/gpu/drm/i915/i915_pmu.c b/drivers/gpu/drm/i915/i915_pmu.c
|
|
index 33ab82c334a881..461aafc2ae9afa 100644
|
|
--- a/drivers/gpu/drm/i915/i915_pmu.c
|
|
+++ b/drivers/gpu/drm/i915/i915_pmu.c
|
|
@@ -101,7 +101,7 @@ static unsigned int config_bit(const u64 config)
|
|
return other_bit(config);
|
|
}
|
|
|
|
-static u32 config_mask(const u64 config)
|
|
+static __always_inline u32 config_mask(const u64 config)
|
|
{
|
|
unsigned int bit = config_bit(config);
|
|
|
|
diff --git a/drivers/gpu/drm/msm/msm_gpu_devfreq.c b/drivers/gpu/drm/msm/msm_gpu_devfreq.c
|
|
index 6970b0f7f457c8..2e1d5c3432728c 100644
|
|
--- a/drivers/gpu/drm/msm/msm_gpu_devfreq.c
|
|
+++ b/drivers/gpu/drm/msm/msm_gpu_devfreq.c
|
|
@@ -156,6 +156,7 @@ void msm_devfreq_init(struct msm_gpu *gpu)
|
|
priv->gpu_devfreq_config.downdifferential = 10;
|
|
|
|
mutex_init(&df->lock);
|
|
+ df->suspended = true;
|
|
|
|
ret = dev_pm_qos_add_request(&gpu->pdev->dev, &df->boost_freq,
|
|
DEV_PM_QOS_MIN_FREQUENCY, 0);
|
|
diff --git a/drivers/gpu/drm/scheduler/sched_entity.c b/drivers/gpu/drm/scheduler/sched_entity.c
|
|
index 53130a50584ca0..eed3b8bed9e40f 100644
|
|
--- a/drivers/gpu/drm/scheduler/sched_entity.c
|
|
+++ b/drivers/gpu/drm/scheduler/sched_entity.c
|
|
@@ -167,6 +167,7 @@ static void drm_sched_entity_kill_jobs_work(struct work_struct *wrk)
|
|
{
|
|
struct drm_sched_job *job = container_of(wrk, typeof(*job), work);
|
|
|
|
+ drm_sched_fence_scheduled(job->s_fence, NULL);
|
|
drm_sched_fence_finished(job->s_fence, -ESRCH);
|
|
WARN_ON(job->s_fence->parent);
|
|
job->sched->ops->free_job(job);
|
|
diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c
|
|
index 13b182ab905fb0..980d85bc7f3745 100644
|
|
--- a/drivers/gpu/drm/tegra/dc.c
|
|
+++ b/drivers/gpu/drm/tegra/dc.c
|
|
@@ -1320,10 +1320,16 @@ static struct drm_plane *tegra_dc_add_shared_planes(struct drm_device *drm,
|
|
if (wgrp->dc == dc->pipe) {
|
|
for (j = 0; j < wgrp->num_windows; j++) {
|
|
unsigned int index = wgrp->windows[j];
|
|
+ enum drm_plane_type type;
|
|
+
|
|
+ if (primary)
|
|
+ type = DRM_PLANE_TYPE_OVERLAY;
|
|
+ else
|
|
+ type = DRM_PLANE_TYPE_PRIMARY;
|
|
|
|
plane = tegra_shared_plane_create(drm, dc,
|
|
wgrp->index,
|
|
- index);
|
|
+ index, type);
|
|
if (IS_ERR(plane))
|
|
return plane;
|
|
|
|
@@ -1331,10 +1337,8 @@ static struct drm_plane *tegra_dc_add_shared_planes(struct drm_device *drm,
|
|
* Choose the first shared plane owned by this
|
|
* head as the primary plane.
|
|
*/
|
|
- if (!primary) {
|
|
- plane->type = DRM_PLANE_TYPE_PRIMARY;
|
|
+ if (!primary)
|
|
primary = plane;
|
|
- }
|
|
}
|
|
}
|
|
}
|
|
@@ -1388,7 +1392,10 @@ static void tegra_crtc_reset(struct drm_crtc *crtc)
|
|
if (crtc->state)
|
|
tegra_crtc_atomic_destroy_state(crtc, crtc->state);
|
|
|
|
- __drm_atomic_helper_crtc_reset(crtc, &state->base);
|
|
+ if (state)
|
|
+ __drm_atomic_helper_crtc_reset(crtc, &state->base);
|
|
+ else
|
|
+ __drm_atomic_helper_crtc_reset(crtc, NULL);
|
|
}
|
|
|
|
static struct drm_crtc_state *
|
|
diff --git a/drivers/gpu/drm/tegra/hub.c b/drivers/gpu/drm/tegra/hub.c
|
|
index 1af5f8318d9146..0f88cbb3331706 100644
|
|
--- a/drivers/gpu/drm/tegra/hub.c
|
|
+++ b/drivers/gpu/drm/tegra/hub.c
|
|
@@ -756,9 +756,9 @@ static const struct drm_plane_helper_funcs tegra_shared_plane_helper_funcs = {
|
|
struct drm_plane *tegra_shared_plane_create(struct drm_device *drm,
|
|
struct tegra_dc *dc,
|
|
unsigned int wgrp,
|
|
- unsigned int index)
|
|
+ unsigned int index,
|
|
+ enum drm_plane_type type)
|
|
{
|
|
- enum drm_plane_type type = DRM_PLANE_TYPE_OVERLAY;
|
|
struct tegra_drm *tegra = drm->dev_private;
|
|
struct tegra_display_hub *hub = tegra->hub;
|
|
struct tegra_shared_plane *plane;
|
|
diff --git a/drivers/gpu/drm/tegra/hub.h b/drivers/gpu/drm/tegra/hub.h
|
|
index 23c4b2115ed1e3..a66f18c4facc9d 100644
|
|
--- a/drivers/gpu/drm/tegra/hub.h
|
|
+++ b/drivers/gpu/drm/tegra/hub.h
|
|
@@ -80,7 +80,8 @@ void tegra_display_hub_cleanup(struct tegra_display_hub *hub);
|
|
struct drm_plane *tegra_shared_plane_create(struct drm_device *drm,
|
|
struct tegra_dc *dc,
|
|
unsigned int wgrp,
|
|
- unsigned int index);
|
|
+ unsigned int index,
|
|
+ enum drm_plane_type type);
|
|
|
|
int tegra_display_hub_atomic_check(struct drm_device *drm,
|
|
struct drm_atomic_state *state);
|
|
diff --git a/drivers/gpu/drm/tiny/cirrus.c b/drivers/gpu/drm/tiny/cirrus.c
|
|
index 594bc472862fe6..b0361ef53c4635 100644
|
|
--- a/drivers/gpu/drm/tiny/cirrus.c
|
|
+++ b/drivers/gpu/drm/tiny/cirrus.c
|
|
@@ -318,7 +318,6 @@ static void cirrus_pitch_set(struct cirrus_device *cirrus, unsigned int pitch)
|
|
/* Enable extended blanking and pitch bits, and enable full memory */
|
|
cr1b = 0x22;
|
|
cr1b |= (pitch >> 7) & 0x10;
|
|
- cr1b |= (pitch >> 6) & 0x40;
|
|
wreg_crt(cirrus, 0x1b, cr1b);
|
|
|
|
cirrus_set_start_address(cirrus, 0);
|
|
diff --git a/drivers/gpu/drm/udl/udl_drv.c b/drivers/gpu/drm/udl/udl_drv.c
|
|
index 1506094a800983..ac357ab1aee544 100644
|
|
--- a/drivers/gpu/drm/udl/udl_drv.c
|
|
+++ b/drivers/gpu/drm/udl/udl_drv.c
|
|
@@ -126,9 +126,9 @@ static void udl_usb_disconnect(struct usb_interface *interface)
|
|
{
|
|
struct drm_device *dev = usb_get_intfdata(interface);
|
|
|
|
+ drm_dev_unplug(dev);
|
|
drm_kms_helper_poll_fini(dev);
|
|
udl_drop_usb(dev);
|
|
- drm_dev_unplug(dev);
|
|
}
|
|
|
|
/*
|
|
diff --git a/drivers/hid/hid-lenovo.c b/drivers/hid/hid-lenovo.c
|
|
index a4062f617ba202..ee65da98c7d5b5 100644
|
|
--- a/drivers/hid/hid-lenovo.c
|
|
+++ b/drivers/hid/hid-lenovo.c
|
|
@@ -529,11 +529,14 @@ static void lenovo_features_set_cptkbd(struct hid_device *hdev)
|
|
|
|
/*
|
|
* Tell the keyboard a driver understands it, and turn F7, F9, F11 into
|
|
- * regular keys
|
|
+ * regular keys (Compact only)
|
|
*/
|
|
- ret = lenovo_send_cmd_cptkbd(hdev, 0x01, 0x03);
|
|
- if (ret)
|
|
- hid_warn(hdev, "Failed to switch F7/9/11 mode: %d\n", ret);
|
|
+ if (hdev->product == USB_DEVICE_ID_LENOVO_CUSBKBD ||
|
|
+ hdev->product == USB_DEVICE_ID_LENOVO_CBTKBD) {
|
|
+ ret = lenovo_send_cmd_cptkbd(hdev, 0x01, 0x03);
|
|
+ if (ret)
|
|
+ hid_warn(hdev, "Failed to switch F7/9/11 mode: %d\n", ret);
|
|
+ }
|
|
|
|
/* Switch middle button to native mode */
|
|
ret = lenovo_send_cmd_cptkbd(hdev, 0x09, 0x01);
|
|
diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c
|
|
index 5a72cf8d6944fa..52011503ff3bac 100644
|
|
--- a/drivers/hid/wacom_sys.c
|
|
+++ b/drivers/hid/wacom_sys.c
|
|
@@ -2012,14 +2012,18 @@ static int wacom_initialize_remotes(struct wacom *wacom)
|
|
|
|
remote->remote_dir = kobject_create_and_add("wacom_remote",
|
|
&wacom->hdev->dev.kobj);
|
|
- if (!remote->remote_dir)
|
|
+ if (!remote->remote_dir) {
|
|
+ kfifo_free(&remote->remote_fifo);
|
|
return -ENOMEM;
|
|
+ }
|
|
|
|
error = sysfs_create_files(remote->remote_dir, remote_unpair_attrs);
|
|
|
|
if (error) {
|
|
hid_err(wacom->hdev,
|
|
"cannot create sysfs group err: %d\n", error);
|
|
+ kfifo_free(&remote->remote_fifo);
|
|
+ kobject_put(remote->remote_dir);
|
|
return error;
|
|
}
|
|
|
|
diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c
|
|
index 2f4d09ce027a3f..3c6011a48dabe7 100644
|
|
--- a/drivers/hv/channel_mgmt.c
|
|
+++ b/drivers/hv/channel_mgmt.c
|
|
@@ -120,7 +120,9 @@ const struct vmbus_device vmbus_devs[] = {
|
|
},
|
|
|
|
/* File copy */
|
|
- { .dev_type = HV_FCOPY,
|
|
+ /* fcopy always uses 16KB ring buffer size and is working well for last many years */
|
|
+ { .pref_ring_size = 0x4000,
|
|
+ .dev_type = HV_FCOPY,
|
|
HV_FCOPY_GUID,
|
|
.perf_device = false,
|
|
.allowed_in_isolated = false,
|
|
@@ -140,12 +142,19 @@ const struct vmbus_device vmbus_devs[] = {
|
|
.allowed_in_isolated = false,
|
|
},
|
|
|
|
- /* Unknown GUID */
|
|
- { .dev_type = HV_UNKNOWN,
|
|
+ /*
|
|
+ * Unknown GUID
|
|
+ * 64 KB ring buffer + 4 KB header should be sufficient size for any Hyper-V device apart
|
|
+ * from HV_NIC and HV_SCSI. This case avoid the fallback for unknown devices to allocate
|
|
+ * much bigger (2 MB) of ring size.
|
|
+ */
|
|
+ { .pref_ring_size = 0x11000,
|
|
+ .dev_type = HV_UNKNOWN,
|
|
.perf_device = false,
|
|
.allowed_in_isolated = false,
|
|
},
|
|
};
|
|
+EXPORT_SYMBOL_GPL(vmbus_devs);
|
|
|
|
static const struct {
|
|
guid_t guid;
|
|
diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h
|
|
index 787b1506864188..34b60009114a69 100644
|
|
--- a/drivers/hv/hyperv_vmbus.h
|
|
+++ b/drivers/hv/hyperv_vmbus.h
|
|
@@ -419,6 +419,11 @@ static inline bool hv_is_perf_channel(struct vmbus_channel *channel)
|
|
return vmbus_devs[channel->device_id].perf_device;
|
|
}
|
|
|
|
+static inline size_t hv_dev_ring_size(struct vmbus_channel *channel)
|
|
+{
|
|
+ return vmbus_devs[channel->device_id].pref_ring_size;
|
|
+}
|
|
+
|
|
static inline bool hv_is_allocated_cpu(unsigned int cpu)
|
|
{
|
|
struct vmbus_channel *channel, *sc;
|
|
diff --git a/drivers/hwmon/pmbus/max34440.c b/drivers/hwmon/pmbus/max34440.c
|
|
index fe7f6b1b09851e..e14be8ebaad30e 100644
|
|
--- a/drivers/hwmon/pmbus/max34440.c
|
|
+++ b/drivers/hwmon/pmbus/max34440.c
|
|
@@ -34,16 +34,21 @@ enum chips { max34440, max34441, max34446, max34451, max34460, max34461 };
|
|
/*
|
|
* The whole max344* family have IOUT_OC_WARN_LIMIT and IOUT_OC_FAULT_LIMIT
|
|
* swapped from the standard pmbus spec addresses.
|
|
+ * For max34451, version MAX34451ETNA6+ and later has this issue fixed.
|
|
*/
|
|
#define MAX34440_IOUT_OC_WARN_LIMIT 0x46
|
|
#define MAX34440_IOUT_OC_FAULT_LIMIT 0x4A
|
|
|
|
+#define MAX34451ETNA6_MFR_REV 0x0012
|
|
+
|
|
#define MAX34451_MFR_CHANNEL_CONFIG 0xe4
|
|
#define MAX34451_MFR_CHANNEL_CONFIG_SEL_MASK 0x3f
|
|
|
|
struct max34440_data {
|
|
int id;
|
|
struct pmbus_driver_info info;
|
|
+ u8 iout_oc_warn_limit;
|
|
+ u8 iout_oc_fault_limit;
|
|
};
|
|
|
|
#define to_max34440_data(x) container_of(x, struct max34440_data, info)
|
|
@@ -60,11 +65,11 @@ static int max34440_read_word_data(struct i2c_client *client, int page,
|
|
switch (reg) {
|
|
case PMBUS_IOUT_OC_FAULT_LIMIT:
|
|
ret = pmbus_read_word_data(client, page, phase,
|
|
- MAX34440_IOUT_OC_FAULT_LIMIT);
|
|
+ data->iout_oc_fault_limit);
|
|
break;
|
|
case PMBUS_IOUT_OC_WARN_LIMIT:
|
|
ret = pmbus_read_word_data(client, page, phase,
|
|
- MAX34440_IOUT_OC_WARN_LIMIT);
|
|
+ data->iout_oc_warn_limit);
|
|
break;
|
|
case PMBUS_VIRT_READ_VOUT_MIN:
|
|
ret = pmbus_read_word_data(client, page, phase,
|
|
@@ -133,11 +138,11 @@ static int max34440_write_word_data(struct i2c_client *client, int page,
|
|
|
|
switch (reg) {
|
|
case PMBUS_IOUT_OC_FAULT_LIMIT:
|
|
- ret = pmbus_write_word_data(client, page, MAX34440_IOUT_OC_FAULT_LIMIT,
|
|
+ ret = pmbus_write_word_data(client, page, data->iout_oc_fault_limit,
|
|
word);
|
|
break;
|
|
case PMBUS_IOUT_OC_WARN_LIMIT:
|
|
- ret = pmbus_write_word_data(client, page, MAX34440_IOUT_OC_WARN_LIMIT,
|
|
+ ret = pmbus_write_word_data(client, page, data->iout_oc_warn_limit,
|
|
word);
|
|
break;
|
|
case PMBUS_VIRT_RESET_POUT_HISTORY:
|
|
@@ -235,6 +240,25 @@ static int max34451_set_supported_funcs(struct i2c_client *client,
|
|
*/
|
|
|
|
int page, rv;
|
|
+ bool max34451_na6 = false;
|
|
+
|
|
+ rv = i2c_smbus_read_word_data(client, PMBUS_MFR_REVISION);
|
|
+ if (rv < 0)
|
|
+ return rv;
|
|
+
|
|
+ if (rv >= MAX34451ETNA6_MFR_REV) {
|
|
+ max34451_na6 = true;
|
|
+ data->info.format[PSC_VOLTAGE_IN] = direct;
|
|
+ data->info.format[PSC_CURRENT_IN] = direct;
|
|
+ data->info.m[PSC_VOLTAGE_IN] = 1;
|
|
+ data->info.b[PSC_VOLTAGE_IN] = 0;
|
|
+ data->info.R[PSC_VOLTAGE_IN] = 3;
|
|
+ data->info.m[PSC_CURRENT_IN] = 1;
|
|
+ data->info.b[PSC_CURRENT_IN] = 0;
|
|
+ data->info.R[PSC_CURRENT_IN] = 2;
|
|
+ data->iout_oc_fault_limit = PMBUS_IOUT_OC_FAULT_LIMIT;
|
|
+ data->iout_oc_warn_limit = PMBUS_IOUT_OC_WARN_LIMIT;
|
|
+ }
|
|
|
|
for (page = 0; page < 16; page++) {
|
|
rv = i2c_smbus_write_byte_data(client, PMBUS_PAGE, page);
|
|
@@ -251,16 +275,30 @@ static int max34451_set_supported_funcs(struct i2c_client *client,
|
|
case 0x20:
|
|
data->info.func[page] = PMBUS_HAVE_VOUT |
|
|
PMBUS_HAVE_STATUS_VOUT;
|
|
+
|
|
+ if (max34451_na6)
|
|
+ data->info.func[page] |= PMBUS_HAVE_VIN |
|
|
+ PMBUS_HAVE_STATUS_INPUT;
|
|
break;
|
|
case 0x21:
|
|
data->info.func[page] = PMBUS_HAVE_VOUT;
|
|
+
|
|
+ if (max34451_na6)
|
|
+ data->info.func[page] |= PMBUS_HAVE_VIN;
|
|
break;
|
|
case 0x22:
|
|
data->info.func[page] = PMBUS_HAVE_IOUT |
|
|
PMBUS_HAVE_STATUS_IOUT;
|
|
+
|
|
+ if (max34451_na6)
|
|
+ data->info.func[page] |= PMBUS_HAVE_IIN |
|
|
+ PMBUS_HAVE_STATUS_INPUT;
|
|
break;
|
|
case 0x23:
|
|
data->info.func[page] = PMBUS_HAVE_IOUT;
|
|
+
|
|
+ if (max34451_na6)
|
|
+ data->info.func[page] |= PMBUS_HAVE_IIN;
|
|
break;
|
|
default:
|
|
break;
|
|
@@ -494,6 +532,8 @@ static int max34440_probe(struct i2c_client *client)
|
|
return -ENOMEM;
|
|
data->id = i2c_match_id(max34440_id, client)->driver_data;
|
|
data->info = max34440_info[data->id];
|
|
+ data->iout_oc_fault_limit = MAX34440_IOUT_OC_FAULT_LIMIT;
|
|
+ data->iout_oc_warn_limit = MAX34440_IOUT_OC_WARN_LIMIT;
|
|
|
|
if (data->id == max34451) {
|
|
rv = max34451_set_supported_funcs(client, data);
|
|
diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c
|
|
index 783e259c376121..3b57851869eaae 100644
|
|
--- a/drivers/hwtracing/coresight/coresight-core.c
|
|
+++ b/drivers/hwtracing/coresight/coresight-core.c
|
|
@@ -135,7 +135,8 @@ coresight_find_out_connection(struct coresight_device *src_dev,
|
|
|
|
static inline u32 coresight_read_claim_tags(struct coresight_device *csdev)
|
|
{
|
|
- return csdev_access_relaxed_read32(&csdev->access, CORESIGHT_CLAIMCLR);
|
|
+ return FIELD_GET(CORESIGHT_CLAIM_MASK,
|
|
+ csdev_access_relaxed_read32(&csdev->access, CORESIGHT_CLAIMCLR));
|
|
}
|
|
|
|
static inline bool coresight_is_claimed_self_hosted(struct coresight_device *csdev)
|
|
diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h
|
|
index 30c051055e54b3..b758a42ed8c734 100644
|
|
--- a/drivers/hwtracing/coresight/coresight-priv.h
|
|
+++ b/drivers/hwtracing/coresight/coresight-priv.h
|
|
@@ -32,6 +32,7 @@
|
|
* Coresight device CLAIM protocol.
|
|
* See PSCI - ARM DEN 0022D, Section: 6.8.1 Debug and Trace save and restore.
|
|
*/
|
|
+#define CORESIGHT_CLAIM_MASK GENMASK(1, 0)
|
|
#define CORESIGHT_CLAIM_SELF_HOSTED BIT(1)
|
|
|
|
#define TIMEOUT_US 100
|
|
diff --git a/drivers/i2c/busses/i2c-robotfuzz-osif.c b/drivers/i2c/busses/i2c-robotfuzz-osif.c
|
|
index 66dfa211e736b1..8e4cf9028b2342 100644
|
|
--- a/drivers/i2c/busses/i2c-robotfuzz-osif.c
|
|
+++ b/drivers/i2c/busses/i2c-robotfuzz-osif.c
|
|
@@ -111,6 +111,11 @@ static u32 osif_func(struct i2c_adapter *adapter)
|
|
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
|
|
}
|
|
|
|
+/* prevent invalid 0-length usb_control_msg */
|
|
+static const struct i2c_adapter_quirks osif_quirks = {
|
|
+ .flags = I2C_AQ_NO_ZERO_LEN_READ,
|
|
+};
|
|
+
|
|
static const struct i2c_algorithm osif_algorithm = {
|
|
.master_xfer = osif_xfer,
|
|
.functionality = osif_func,
|
|
@@ -143,6 +148,7 @@ static int osif_probe(struct usb_interface *interface,
|
|
|
|
priv->adapter.owner = THIS_MODULE;
|
|
priv->adapter.class = I2C_CLASS_HWMON;
|
|
+ priv->adapter.quirks = &osif_quirks;
|
|
priv->adapter.algo = &osif_algorithm;
|
|
priv->adapter.algo_data = priv;
|
|
snprintf(priv->adapter.name, sizeof(priv->adapter.name),
|
|
diff --git a/drivers/i2c/busses/i2c-tiny-usb.c b/drivers/i2c/busses/i2c-tiny-usb.c
|
|
index 1bffe36c40ad89..d984b90b352701 100644
|
|
--- a/drivers/i2c/busses/i2c-tiny-usb.c
|
|
+++ b/drivers/i2c/busses/i2c-tiny-usb.c
|
|
@@ -140,6 +140,11 @@ static u32 usb_func(struct i2c_adapter *adapter)
|
|
return ret;
|
|
}
|
|
|
|
+/* prevent invalid 0-length usb_control_msg */
|
|
+static const struct i2c_adapter_quirks usb_quirks = {
|
|
+ .flags = I2C_AQ_NO_ZERO_LEN_READ,
|
|
+};
|
|
+
|
|
/* This is the actual algorithm we define */
|
|
static const struct i2c_algorithm usb_algorithm = {
|
|
.master_xfer = usb_xfer,
|
|
@@ -248,6 +253,7 @@ static int i2c_tiny_usb_probe(struct usb_interface *interface,
|
|
/* setup i2c adapter description */
|
|
dev->adapter.owner = THIS_MODULE;
|
|
dev->adapter.class = I2C_CLASS_HWMON;
|
|
+ dev->adapter.quirks = &usb_quirks;
|
|
dev->adapter.algo = &usb_algorithm;
|
|
dev->adapter.algo_data = dev;
|
|
snprintf(dev->adapter.name, sizeof(dev->adapter.name),
|
|
diff --git a/drivers/iio/adc/ad_sigma_delta.c b/drivers/iio/adc/ad_sigma_delta.c
|
|
index 7e21928707437b..533667eefe419c 100644
|
|
--- a/drivers/iio/adc/ad_sigma_delta.c
|
|
+++ b/drivers/iio/adc/ad_sigma_delta.c
|
|
@@ -476,6 +476,10 @@ static irqreturn_t ad_sd_trigger_handler(int irq, void *p)
|
|
* byte set to zero. */
|
|
ad_sd_read_reg_raw(sigma_delta, data_reg, transfer_size, &data[1]);
|
|
break;
|
|
+
|
|
+ default:
|
|
+ dev_err_ratelimited(&indio_dev->dev, "Unsupported reg_size: %u\n", reg_size);
|
|
+ goto irq_handled;
|
|
}
|
|
|
|
/*
|
|
diff --git a/drivers/iio/pressure/zpa2326.c b/drivers/iio/pressure/zpa2326.c
|
|
index ef1d0349f4247d..a1c694199c9896 100644
|
|
--- a/drivers/iio/pressure/zpa2326.c
|
|
+++ b/drivers/iio/pressure/zpa2326.c
|
|
@@ -582,7 +582,7 @@ static int zpa2326_fill_sample_buffer(struct iio_dev *indio_dev,
|
|
struct {
|
|
u32 pressure;
|
|
u16 temperature;
|
|
- u64 timestamp;
|
|
+ aligned_s64 timestamp;
|
|
} sample;
|
|
int err;
|
|
|
|
diff --git a/drivers/leds/led-class-multicolor.c b/drivers/leds/led-class-multicolor.c
|
|
index ec62a48116135c..e0785935f4ba67 100644
|
|
--- a/drivers/leds/led-class-multicolor.c
|
|
+++ b/drivers/leds/led-class-multicolor.c
|
|
@@ -61,7 +61,8 @@ static ssize_t multi_intensity_store(struct device *dev,
|
|
for (i = 0; i < mcled_cdev->num_colors; i++)
|
|
mcled_cdev->subled_info[i].intensity = intensity_value[i];
|
|
|
|
- led_set_brightness(led_cdev, led_cdev->brightness);
|
|
+ if (!test_bit(LED_BLINK_SW, &led_cdev->work_flags))
|
|
+ led_set_brightness(led_cdev, led_cdev->brightness);
|
|
ret = size;
|
|
err_out:
|
|
mutex_unlock(&led_cdev->led_access);
|
|
diff --git a/drivers/mailbox/mailbox.c b/drivers/mailbox/mailbox.c
|
|
index f13d705f7861af..cb59b4dbad6269 100644
|
|
--- a/drivers/mailbox/mailbox.c
|
|
+++ b/drivers/mailbox/mailbox.c
|
|
@@ -500,8 +500,8 @@ void mbox_free_channel(struct mbox_chan *chan)
|
|
if (chan->txdone_method == TXDONE_BY_ACK)
|
|
chan->txdone_method = TXDONE_BY_POLL;
|
|
|
|
- module_put(chan->mbox->dev->driver->owner);
|
|
spin_unlock_irqrestore(&chan->lock, flags);
|
|
+ module_put(chan->mbox->dev->driver->owner);
|
|
}
|
|
EXPORT_SYMBOL_GPL(mbox_free_channel);
|
|
|
|
diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c
|
|
index 8440b56e385d5c..b9dfebaa9eae55 100644
|
|
--- a/drivers/md/bcache/super.c
|
|
+++ b/drivers/md/bcache/super.c
|
|
@@ -1739,7 +1739,12 @@ static void cache_set_flush(struct closure *cl)
|
|
mutex_unlock(&b->write_lock);
|
|
}
|
|
|
|
- if (ca->alloc_thread)
|
|
+ /*
|
|
+ * If the register_cache_set() call to bch_cache_set_alloc() failed,
|
|
+ * ca has not been assigned a value and return error.
|
|
+ * So we need check ca is not NULL during bch_cache_set_unregister().
|
|
+ */
|
|
+ if (ca && ca->alloc_thread)
|
|
kthread_stop(ca->alloc_thread);
|
|
|
|
if (c->journal.cur) {
|
|
diff --git a/drivers/md/dm-raid.c b/drivers/md/dm-raid.c
|
|
index 385e24f55ec002..f23edd79df45e5 100644
|
|
--- a/drivers/md/dm-raid.c
|
|
+++ b/drivers/md/dm-raid.c
|
|
@@ -2378,7 +2378,7 @@ static int super_init_validation(struct raid_set *rs, struct md_rdev *rdev)
|
|
*/
|
|
sb_retrieve_failed_devices(sb, failed_devices);
|
|
rdev_for_each(r, mddev) {
|
|
- if (test_bit(Journal, &rdev->flags) ||
|
|
+ if (test_bit(Journal, &r->flags) ||
|
|
!r->sb_page)
|
|
continue;
|
|
sb2 = page_address(r->sb_page);
|
|
diff --git a/drivers/md/md-bitmap.c b/drivers/md/md-bitmap.c
|
|
index 8317e07b326d0d..21decb97bc050b 100644
|
|
--- a/drivers/md/md-bitmap.c
|
|
+++ b/drivers/md/md-bitmap.c
|
|
@@ -589,7 +589,7 @@ static int md_bitmap_new_disk_sb(struct bitmap *bitmap)
|
|
* is a good choice? We choose COUNTER_MAX / 2 arbitrarily.
|
|
*/
|
|
write_behind = bitmap->mddev->bitmap_info.max_write_behind;
|
|
- if (write_behind > COUNTER_MAX)
|
|
+ if (write_behind > COUNTER_MAX / 2)
|
|
write_behind = COUNTER_MAX / 2;
|
|
sb->write_behind = cpu_to_le32(write_behind);
|
|
bitmap->mddev->bitmap_info.max_write_behind = write_behind;
|
|
diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
|
|
index 59e21746f55073..bd90d8bacd5ef1 100644
|
|
--- a/drivers/media/usb/uvc/uvc_ctrl.c
|
|
+++ b/drivers/media/usb/uvc/uvc_ctrl.c
|
|
@@ -1801,7 +1801,7 @@ static int uvc_ctrl_commit_entity(struct uvc_device *dev,
|
|
unsigned int processed_ctrls = 0;
|
|
struct uvc_control *ctrl;
|
|
unsigned int i;
|
|
- int ret;
|
|
+ int ret = 0;
|
|
|
|
if (entity == NULL)
|
|
return 0;
|
|
@@ -1830,8 +1830,6 @@ static int uvc_ctrl_commit_entity(struct uvc_device *dev,
|
|
dev->intfnum, ctrl->info.selector,
|
|
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
|
|
ctrl->info.size);
|
|
- else
|
|
- ret = 0;
|
|
|
|
if (!ret)
|
|
processed_ctrls++;
|
|
@@ -1843,17 +1841,25 @@ static int uvc_ctrl_commit_entity(struct uvc_device *dev,
|
|
|
|
ctrl->dirty = 0;
|
|
|
|
- if (ret < 0) {
|
|
+ if (!rollback && handle &&
|
|
+ ctrl->info.flags & UVC_CTRL_FLAG_ASYNCHRONOUS)
|
|
+ uvc_ctrl_set_handle(handle, ctrl, handle);
|
|
+
|
|
+ if (ret < 0 && !rollback) {
|
|
if (err_ctrl)
|
|
*err_ctrl = ctrl;
|
|
- return ret;
|
|
+ /*
|
|
+ * If we fail to set a control, we need to rollback
|
|
+ * the next ones.
|
|
+ */
|
|
+ rollback = 1;
|
|
}
|
|
|
|
- if (!rollback && handle &&
|
|
- ctrl->info.flags & UVC_CTRL_FLAG_ASYNCHRONOUS)
|
|
- uvc_ctrl_set_handle(handle, ctrl, handle);
|
|
}
|
|
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
return processed_ctrls;
|
|
}
|
|
|
|
@@ -1884,7 +1890,8 @@ int __uvc_ctrl_commit(struct uvc_fh *handle, int rollback,
|
|
struct uvc_video_chain *chain = handle->chain;
|
|
struct uvc_control *err_ctrl;
|
|
struct uvc_entity *entity;
|
|
- int ret = 0;
|
|
+ int ret_out = 0;
|
|
+ int ret;
|
|
|
|
/* Find the control. */
|
|
list_for_each_entry(entity, &chain->entities, chain) {
|
|
@@ -1895,17 +1902,23 @@ int __uvc_ctrl_commit(struct uvc_fh *handle, int rollback,
|
|
ctrls->error_idx =
|
|
uvc_ctrl_find_ctrl_idx(entity, ctrls,
|
|
err_ctrl);
|
|
- goto done;
|
|
+ /*
|
|
+ * When we fail to commit an entity, we need to
|
|
+ * restore the UVC_CTRL_DATA_BACKUP for all the
|
|
+ * controls in the other entities, otherwise our cache
|
|
+ * and the hardware will be out of sync.
|
|
+ */
|
|
+ rollback = 1;
|
|
+
|
|
+ ret_out = ret;
|
|
} else if (ret > 0 && !rollback) {
|
|
uvc_ctrl_send_events(handle, entity,
|
|
ctrls->controls, ctrls->count);
|
|
}
|
|
}
|
|
|
|
- ret = 0;
|
|
-done:
|
|
mutex_unlock(&chain->ctrl_mutex);
|
|
- return ret;
|
|
+ return ret_out;
|
|
}
|
|
|
|
int uvc_ctrl_get(struct uvc_video_chain *chain,
|
|
diff --git a/drivers/mfd/max14577.c b/drivers/mfd/max14577.c
|
|
index 1f4f5002595c0a..17672eeb1732a2 100644
|
|
--- a/drivers/mfd/max14577.c
|
|
+++ b/drivers/mfd/max14577.c
|
|
@@ -463,6 +463,7 @@ static void max14577_i2c_remove(struct i2c_client *i2c)
|
|
{
|
|
struct max14577 *max14577 = i2c_get_clientdata(i2c);
|
|
|
|
+ device_init_wakeup(max14577->dev, false);
|
|
mfd_remove_devices(max14577->dev);
|
|
regmap_del_irq_chip(max14577->irq, max14577->irq_data);
|
|
if (max14577->dev_type == MAXIM_DEVICE_TYPE_MAX77836)
|
|
diff --git a/drivers/misc/tps6594-pfsm.c b/drivers/misc/tps6594-pfsm.c
|
|
index 88dcac8148922c..71fbe31542e562 100644
|
|
--- a/drivers/misc/tps6594-pfsm.c
|
|
+++ b/drivers/misc/tps6594-pfsm.c
|
|
@@ -260,6 +260,9 @@ static int tps6594_pfsm_probe(struct platform_device *pdev)
|
|
pfsm->miscdev.minor = MISC_DYNAMIC_MINOR;
|
|
pfsm->miscdev.name = devm_kasprintf(dev, GFP_KERNEL, "pfsm-%ld-0x%02x",
|
|
tps->chip_id, tps->reg);
|
|
+ if (!pfsm->miscdev.name)
|
|
+ return -ENOMEM;
|
|
+
|
|
pfsm->miscdev.fops = &tps6594_pfsm_fops;
|
|
pfsm->miscdev.parent = dev->parent;
|
|
|
|
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_hw.h b/drivers/net/ethernet/freescale/enetc/enetc_hw.h
|
|
index 1619943fb2637a..4e8881b479e487 100644
|
|
--- a/drivers/net/ethernet/freescale/enetc/enetc_hw.h
|
|
+++ b/drivers/net/ethernet/freescale/enetc/enetc_hw.h
|
|
@@ -485,7 +485,7 @@ static inline u64 _enetc_rd_reg64(void __iomem *reg)
|
|
tmp = ioread32(reg + 4);
|
|
} while (high != tmp);
|
|
|
|
- return le64_to_cpu((__le64)high << 32 | low);
|
|
+ return (u64)high << 32 | low;
|
|
}
|
|
#endif
|
|
|
|
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_lib.c b/drivers/net/ethernet/wangxun/libwx/wx_lib.c
|
|
index c019fe964eceaf..97c6b4d2763433 100644
|
|
--- a/drivers/net/ethernet/wangxun/libwx/wx_lib.c
|
|
+++ b/drivers/net/ethernet/wangxun/libwx/wx_lib.c
|
|
@@ -2368,7 +2368,7 @@ static int wx_alloc_page_pool(struct wx_ring *rx_ring)
|
|
struct page_pool_params pp_params = {
|
|
.flags = PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV,
|
|
.order = 0,
|
|
- .pool_size = rx_ring->size,
|
|
+ .pool_size = rx_ring->count,
|
|
.nid = dev_to_node(rx_ring->dev),
|
|
.dev = rx_ring->dev,
|
|
.dma_dir = DMA_FROM_DEVICE,
|
|
diff --git a/drivers/nvme/host/ioctl.c b/drivers/nvme/host/ioctl.c
|
|
index 4ce31f9f069475..5cf050e562b734 100644
|
|
--- a/drivers/nvme/host/ioctl.c
|
|
+++ b/drivers/nvme/host/ioctl.c
|
|
@@ -526,16 +526,14 @@ static enum rq_end_io_ret nvme_uring_cmd_end_io(struct request *req,
|
|
pdu->u.result = le64_to_cpu(nvme_req(req)->result.u64);
|
|
|
|
/*
|
|
- * For iopoll, complete it directly.
|
|
- * Otherwise, move the completion to task work.
|
|
+ * IOPOLL could potentially complete this request directly, but
|
|
+ * if multiple rings are polling on the same queue, then it's possible
|
|
+ * for one ring to find completions for another ring. Punting the
|
|
+ * completion via task_work will always direct it to the right
|
|
+ * location, rather than potentially complete requests for ringA
|
|
+ * under iopoll invocations from ringB.
|
|
*/
|
|
- if (blk_rq_is_poll(req)) {
|
|
- WRITE_ONCE(ioucmd->cookie, NULL);
|
|
- nvme_uring_task_cb(ioucmd, IO_URING_F_UNLOCKED);
|
|
- } else {
|
|
- io_uring_cmd_do_in_task_lazy(ioucmd, nvme_uring_task_cb);
|
|
- }
|
|
-
|
|
+ io_uring_cmd_do_in_task_lazy(ioucmd, nvme_uring_task_cb);
|
|
return RQ_END_IO_FREE;
|
|
}
|
|
|
|
diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c
|
|
index 2b60d20dfdf59d..717af1b757f0a5 100644
|
|
--- a/drivers/pci/controller/dwc/pcie-designware.c
|
|
+++ b/drivers/pci/controller/dwc/pcie-designware.c
|
|
@@ -748,22 +748,19 @@ static void dw_pcie_link_set_max_link_width(struct dw_pcie *pci, u32 num_lanes)
|
|
/* Set link width speed control register */
|
|
lwsc = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL);
|
|
lwsc &= ~PORT_LOGIC_LINK_WIDTH_MASK;
|
|
+ lwsc |= PORT_LOGIC_LINK_WIDTH_1_LANES;
|
|
switch (num_lanes) {
|
|
case 1:
|
|
plc |= PORT_LINK_MODE_1_LANES;
|
|
- lwsc |= PORT_LOGIC_LINK_WIDTH_1_LANES;
|
|
break;
|
|
case 2:
|
|
plc |= PORT_LINK_MODE_2_LANES;
|
|
- lwsc |= PORT_LOGIC_LINK_WIDTH_2_LANES;
|
|
break;
|
|
case 4:
|
|
plc |= PORT_LINK_MODE_4_LANES;
|
|
- lwsc |= PORT_LOGIC_LINK_WIDTH_4_LANES;
|
|
break;
|
|
case 8:
|
|
plc |= PORT_LINK_MODE_8_LANES;
|
|
- lwsc |= PORT_LOGIC_LINK_WIDTH_8_LANES;
|
|
break;
|
|
default:
|
|
dev_err(pci->dev, "num-lanes %u: invalid value\n", num_lanes);
|
|
diff --git a/drivers/pci/controller/pcie-apple.c b/drivers/pci/controller/pcie-apple.c
|
|
index 7e6bd63a6425e6..8dfea64a51e0f8 100644
|
|
--- a/drivers/pci/controller/pcie-apple.c
|
|
+++ b/drivers/pci/controller/pcie-apple.c
|
|
@@ -585,6 +585,9 @@ static int apple_pcie_setup_port(struct apple_pcie *pcie,
|
|
list_add_tail(&port->entry, &pcie->ports);
|
|
init_completion(&pcie->event);
|
|
|
|
+ /* In the success path, we keep a reference to np around */
|
|
+ of_node_get(np);
|
|
+
|
|
ret = apple_pcie_port_register_irqs(port);
|
|
WARN_ON(ret);
|
|
|
|
@@ -764,7 +767,6 @@ static int apple_pcie_init(struct pci_config_window *cfg)
|
|
{
|
|
struct device *dev = cfg->parent;
|
|
struct platform_device *platform = to_platform_device(dev);
|
|
- struct device_node *of_port;
|
|
struct apple_pcie *pcie;
|
|
int ret;
|
|
|
|
@@ -787,11 +789,10 @@ static int apple_pcie_init(struct pci_config_window *cfg)
|
|
if (ret)
|
|
return ret;
|
|
|
|
- for_each_child_of_node(dev->of_node, of_port) {
|
|
+ for_each_available_child_of_node_scoped(dev->of_node, of_port) {
|
|
ret = apple_pcie_setup_port(pcie, of_port);
|
|
if (ret) {
|
|
dev_err(pcie->dev, "Port %pOF setup fail: %d\n", of_port, ret);
|
|
- of_node_put(of_port);
|
|
return ret;
|
|
}
|
|
}
|
|
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
|
|
index 07eea525091b08..1fd57eb867662a 100644
|
|
--- a/drivers/platform/x86/Kconfig
|
|
+++ b/drivers/platform/x86/Kconfig
|
|
@@ -466,6 +466,7 @@ config LENOVO_YMC
|
|
tristate "Lenovo Yoga Tablet Mode Control"
|
|
depends on ACPI_WMI
|
|
depends on INPUT
|
|
+ depends on IDEAPAD_LAPTOP
|
|
select INPUT_SPARSEKMAP
|
|
help
|
|
This driver maps the Tablet Mode Control switch to SW_TABLET_MODE input
|
|
diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c
|
|
index 50013af0537c36..e84fcb444d872a 100644
|
|
--- a/drivers/platform/x86/ideapad-laptop.c
|
|
+++ b/drivers/platform/x86/ideapad-laptop.c
|
|
@@ -14,6 +14,7 @@
|
|
#include <linux/bitops.h>
|
|
#include <linux/bug.h>
|
|
#include <linux/debugfs.h>
|
|
+#include <linux/delay.h>
|
|
#include <linux/device.h>
|
|
#include <linux/dmi.h>
|
|
#include <linux/fb.h>
|
|
@@ -21,6 +22,7 @@
|
|
#include <linux/init.h>
|
|
#include <linux/input.h>
|
|
#include <linux/input/sparse-keymap.h>
|
|
+#include <linux/jiffies.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/leds.h>
|
|
#include <linux/module.h>
|
|
@@ -86,6 +88,34 @@ enum {
|
|
SALS_FNLOCK_OFF = 0xf,
|
|
};
|
|
|
|
+enum {
|
|
+ VPCCMD_R_VPC1 = 0x10,
|
|
+ VPCCMD_R_BL_MAX,
|
|
+ VPCCMD_R_BL,
|
|
+ VPCCMD_W_BL,
|
|
+ VPCCMD_R_WIFI,
|
|
+ VPCCMD_W_WIFI,
|
|
+ VPCCMD_R_BT,
|
|
+ VPCCMD_W_BT,
|
|
+ VPCCMD_R_BL_POWER,
|
|
+ VPCCMD_R_NOVO,
|
|
+ VPCCMD_R_VPC2,
|
|
+ VPCCMD_R_TOUCHPAD,
|
|
+ VPCCMD_W_TOUCHPAD,
|
|
+ VPCCMD_R_CAMERA,
|
|
+ VPCCMD_W_CAMERA,
|
|
+ VPCCMD_R_3G,
|
|
+ VPCCMD_W_3G,
|
|
+ VPCCMD_R_ODD, /* 0x21 */
|
|
+ VPCCMD_W_FAN,
|
|
+ VPCCMD_R_RF,
|
|
+ VPCCMD_W_RF,
|
|
+ VPCCMD_W_YMC = 0x2A,
|
|
+ VPCCMD_R_FAN = 0x2B,
|
|
+ VPCCMD_R_SPECIAL_BUTTONS = 0x31,
|
|
+ VPCCMD_W_BL_POWER = 0x33,
|
|
+};
|
|
+
|
|
/*
|
|
* These correspond to the number of supported states - 1
|
|
* Future keyboard types may need a new system, if there's a collision
|
|
@@ -145,6 +175,7 @@ struct ideapad_private {
|
|
bool touchpad_ctrl_via_ec : 1;
|
|
bool ctrl_ps2_aux_port : 1;
|
|
bool usb_charging : 1;
|
|
+ bool ymc_ec_trigger : 1;
|
|
} features;
|
|
struct {
|
|
bool initialized;
|
|
@@ -188,6 +219,12 @@ MODULE_PARM_DESC(touchpad_ctrl_via_ec,
|
|
"Enable registering a 'touchpad' sysfs-attribute which can be used to manually "
|
|
"tell the EC to enable/disable the touchpad. This may not work on all models.");
|
|
|
|
+static bool ymc_ec_trigger __read_mostly;
|
|
+module_param(ymc_ec_trigger, bool, 0444);
|
|
+MODULE_PARM_DESC(ymc_ec_trigger,
|
|
+ "Enable EC triggering work-around to force emitting tablet mode events. "
|
|
+ "If you need this please report this to: platform-driver-x86@vger.kernel.org");
|
|
+
|
|
/*
|
|
* shared data
|
|
*/
|
|
@@ -227,6 +264,21 @@ static void ideapad_shared_exit(struct ideapad_private *priv)
|
|
/*
|
|
* ACPI Helpers
|
|
*/
|
|
+#define IDEAPAD_EC_TIMEOUT 200 /* in ms */
|
|
+
|
|
+/*
|
|
+ * Some models (e.g., ThinkBook since 2024) have a low tolerance for being
|
|
+ * polled too frequently. Doing so may break the state machine in the EC,
|
|
+ * resulting in a hard shutdown.
|
|
+ *
|
|
+ * It is also observed that frequent polls may disturb the ongoing operation
|
|
+ * and notably delay the availability of EC response.
|
|
+ *
|
|
+ * These values are used as the delay before the first poll and the interval
|
|
+ * between subsequent polls to solve the above issues.
|
|
+ */
|
|
+#define IDEAPAD_EC_POLL_MIN_US 150
|
|
+#define IDEAPAD_EC_POLL_MAX_US 300
|
|
|
|
static int eval_int(acpi_handle handle, const char *name, unsigned long *res)
|
|
{
|
|
@@ -242,6 +294,29 @@ static int eval_int(acpi_handle handle, const char *name, unsigned long *res)
|
|
return 0;
|
|
}
|
|
|
|
+static int eval_int_with_arg(acpi_handle handle, const char *name, unsigned long arg,
|
|
+ unsigned long *res)
|
|
+{
|
|
+ struct acpi_object_list params;
|
|
+ unsigned long long result;
|
|
+ union acpi_object in_obj;
|
|
+ acpi_status status;
|
|
+
|
|
+ params.count = 1;
|
|
+ params.pointer = &in_obj;
|
|
+ in_obj.type = ACPI_TYPE_INTEGER;
|
|
+ in_obj.integer.value = arg;
|
|
+
|
|
+ status = acpi_evaluate_integer(handle, (char *)name, ¶ms, &result);
|
|
+ if (ACPI_FAILURE(status))
|
|
+ return -EIO;
|
|
+
|
|
+ if (res)
|
|
+ *res = result;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
static int exec_simple_method(acpi_handle handle, const char *name, unsigned long arg)
|
|
{
|
|
acpi_status status = acpi_execute_simple_method(handle, (char *)name, arg);
|
|
@@ -284,6 +359,89 @@ static int eval_dytc(acpi_handle handle, unsigned long cmd, unsigned long *res)
|
|
return eval_int_with_arg(handle, "DYTC", cmd, res);
|
|
}
|
|
|
|
+static int eval_vpcr(acpi_handle handle, unsigned long cmd, unsigned long *res)
|
|
+{
|
|
+ return eval_int_with_arg(handle, "VPCR", cmd, res);
|
|
+}
|
|
+
|
|
+static int eval_vpcw(acpi_handle handle, unsigned long cmd, unsigned long data)
|
|
+{
|
|
+ struct acpi_object_list params;
|
|
+ union acpi_object in_obj[2];
|
|
+ acpi_status status;
|
|
+
|
|
+ params.count = 2;
|
|
+ params.pointer = in_obj;
|
|
+ in_obj[0].type = ACPI_TYPE_INTEGER;
|
|
+ in_obj[0].integer.value = cmd;
|
|
+ in_obj[1].type = ACPI_TYPE_INTEGER;
|
|
+ in_obj[1].integer.value = data;
|
|
+
|
|
+ status = acpi_evaluate_object(handle, "VPCW", ¶ms, NULL);
|
|
+ if (ACPI_FAILURE(status))
|
|
+ return -EIO;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int read_ec_data(acpi_handle handle, unsigned long cmd, unsigned long *data)
|
|
+{
|
|
+ unsigned long end_jiffies, val;
|
|
+ int err;
|
|
+
|
|
+ err = eval_vpcw(handle, 1, cmd);
|
|
+ if (err)
|
|
+ return err;
|
|
+
|
|
+ end_jiffies = jiffies + msecs_to_jiffies(IDEAPAD_EC_TIMEOUT) + 1;
|
|
+
|
|
+ while (time_before(jiffies, end_jiffies)) {
|
|
+ usleep_range(IDEAPAD_EC_POLL_MIN_US, IDEAPAD_EC_POLL_MAX_US);
|
|
+
|
|
+ err = eval_vpcr(handle, 1, &val);
|
|
+ if (err)
|
|
+ return err;
|
|
+
|
|
+ if (val == 0)
|
|
+ return eval_vpcr(handle, 0, data);
|
|
+ }
|
|
+
|
|
+ acpi_handle_err(handle, "timeout in %s\n", __func__);
|
|
+
|
|
+ return -ETIMEDOUT;
|
|
+}
|
|
+
|
|
+static int write_ec_cmd(acpi_handle handle, unsigned long cmd, unsigned long data)
|
|
+{
|
|
+ unsigned long end_jiffies, val;
|
|
+ int err;
|
|
+
|
|
+ err = eval_vpcw(handle, 0, data);
|
|
+ if (err)
|
|
+ return err;
|
|
+
|
|
+ err = eval_vpcw(handle, 1, cmd);
|
|
+ if (err)
|
|
+ return err;
|
|
+
|
|
+ end_jiffies = jiffies + msecs_to_jiffies(IDEAPAD_EC_TIMEOUT) + 1;
|
|
+
|
|
+ while (time_before(jiffies, end_jiffies)) {
|
|
+ usleep_range(IDEAPAD_EC_POLL_MIN_US, IDEAPAD_EC_POLL_MAX_US);
|
|
+
|
|
+ err = eval_vpcr(handle, 1, &val);
|
|
+ if (err)
|
|
+ return err;
|
|
+
|
|
+ if (val == 0)
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ acpi_handle_err(handle, "timeout in %s\n", __func__);
|
|
+
|
|
+ return -ETIMEDOUT;
|
|
+}
|
|
+
|
|
/*
|
|
* debugfs
|
|
*/
|
|
@@ -1501,6 +1659,79 @@ static void ideapad_sync_touchpad_state(struct ideapad_private *priv, bool send_
|
|
priv->r_touchpad_val = value;
|
|
}
|
|
|
|
+static const struct dmi_system_id ymc_ec_trigger_quirk_dmi_table[] = {
|
|
+ {
|
|
+ /* Lenovo Yoga 7 14ARB7 */
|
|
+ .matches = {
|
|
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
|
+ DMI_MATCH(DMI_PRODUCT_NAME, "82QF"),
|
|
+ },
|
|
+ },
|
|
+ {
|
|
+ /* Lenovo Yoga 7 14ACN6 */
|
|
+ .matches = {
|
|
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
|
+ DMI_MATCH(DMI_PRODUCT_NAME, "82N7"),
|
|
+ },
|
|
+ },
|
|
+ { }
|
|
+};
|
|
+
|
|
+static void ideapad_laptop_trigger_ec(void)
|
|
+{
|
|
+ struct ideapad_private *priv;
|
|
+ int ret;
|
|
+
|
|
+ guard(mutex)(&ideapad_shared_mutex);
|
|
+
|
|
+ priv = ideapad_shared;
|
|
+ if (!priv)
|
|
+ return;
|
|
+
|
|
+ if (!priv->features.ymc_ec_trigger)
|
|
+ return;
|
|
+
|
|
+ ret = write_ec_cmd(priv->adev->handle, VPCCMD_W_YMC, 1);
|
|
+ if (ret)
|
|
+ dev_warn(&priv->platform_device->dev, "Could not write YMC: %d\n", ret);
|
|
+}
|
|
+
|
|
+static int ideapad_laptop_nb_notify(struct notifier_block *nb,
|
|
+ unsigned long action, void *data)
|
|
+{
|
|
+ switch (action) {
|
|
+ case IDEAPAD_LAPTOP_YMC_EVENT:
|
|
+ ideapad_laptop_trigger_ec();
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static struct notifier_block ideapad_laptop_notifier = {
|
|
+ .notifier_call = ideapad_laptop_nb_notify,
|
|
+};
|
|
+
|
|
+static BLOCKING_NOTIFIER_HEAD(ideapad_laptop_chain_head);
|
|
+
|
|
+int ideapad_laptop_register_notifier(struct notifier_block *nb)
|
|
+{
|
|
+ return blocking_notifier_chain_register(&ideapad_laptop_chain_head, nb);
|
|
+}
|
|
+EXPORT_SYMBOL_NS_GPL(ideapad_laptop_register_notifier, IDEAPAD_LAPTOP);
|
|
+
|
|
+int ideapad_laptop_unregister_notifier(struct notifier_block *nb)
|
|
+{
|
|
+ return blocking_notifier_chain_unregister(&ideapad_laptop_chain_head, nb);
|
|
+}
|
|
+EXPORT_SYMBOL_NS_GPL(ideapad_laptop_unregister_notifier, IDEAPAD_LAPTOP);
|
|
+
|
|
+void ideapad_laptop_call_notifier(unsigned long action, void *data)
|
|
+{
|
|
+ blocking_notifier_call_chain(&ideapad_laptop_chain_head, action, data);
|
|
+}
|
|
+EXPORT_SYMBOL_NS_GPL(ideapad_laptop_call_notifier, IDEAPAD_LAPTOP);
|
|
+
|
|
static void ideapad_acpi_notify(acpi_handle handle, u32 event, void *data)
|
|
{
|
|
struct ideapad_private *priv = data;
|
|
@@ -1637,6 +1868,8 @@ static void ideapad_check_features(struct ideapad_private *priv)
|
|
priv->features.ctrl_ps2_aux_port =
|
|
ctrl_ps2_aux_port || dmi_check_system(ctrl_ps2_aux_port_list);
|
|
priv->features.touchpad_ctrl_via_ec = touchpad_ctrl_via_ec;
|
|
+ priv->features.ymc_ec_trigger =
|
|
+ ymc_ec_trigger || dmi_check_system(ymc_ec_trigger_quirk_dmi_table);
|
|
|
|
if (!read_ec_data(handle, VPCCMD_R_FAN, &val))
|
|
priv->features.fan_mode = true;
|
|
@@ -1872,6 +2105,8 @@ static int ideapad_acpi_add(struct platform_device *pdev)
|
|
if (err)
|
|
goto shared_init_failed;
|
|
|
|
+ ideapad_laptop_register_notifier(&ideapad_laptop_notifier);
|
|
+
|
|
return 0;
|
|
|
|
shared_init_failed:
|
|
@@ -1903,6 +2138,8 @@ static void ideapad_acpi_remove(struct platform_device *pdev)
|
|
struct ideapad_private *priv = dev_get_drvdata(&pdev->dev);
|
|
int i;
|
|
|
|
+ ideapad_laptop_unregister_notifier(&ideapad_laptop_notifier);
|
|
+
|
|
ideapad_shared_exit(priv);
|
|
|
|
acpi_remove_notify_handler(priv->adev->handle,
|
|
diff --git a/drivers/platform/x86/ideapad-laptop.h b/drivers/platform/x86/ideapad-laptop.h
|
|
index 4498a96de59769..1e52f2aa0aac38 100644
|
|
--- a/drivers/platform/x86/ideapad-laptop.h
|
|
+++ b/drivers/platform/x86/ideapad-laptop.h
|
|
@@ -9,144 +9,14 @@
|
|
#ifndef _IDEAPAD_LAPTOP_H_
|
|
#define _IDEAPAD_LAPTOP_H_
|
|
|
|
-#include <linux/acpi.h>
|
|
-#include <linux/jiffies.h>
|
|
-#include <linux/errno.h>
|
|
+#include <linux/notifier.h>
|
|
|
|
-enum {
|
|
- VPCCMD_R_VPC1 = 0x10,
|
|
- VPCCMD_R_BL_MAX,
|
|
- VPCCMD_R_BL,
|
|
- VPCCMD_W_BL,
|
|
- VPCCMD_R_WIFI,
|
|
- VPCCMD_W_WIFI,
|
|
- VPCCMD_R_BT,
|
|
- VPCCMD_W_BT,
|
|
- VPCCMD_R_BL_POWER,
|
|
- VPCCMD_R_NOVO,
|
|
- VPCCMD_R_VPC2,
|
|
- VPCCMD_R_TOUCHPAD,
|
|
- VPCCMD_W_TOUCHPAD,
|
|
- VPCCMD_R_CAMERA,
|
|
- VPCCMD_W_CAMERA,
|
|
- VPCCMD_R_3G,
|
|
- VPCCMD_W_3G,
|
|
- VPCCMD_R_ODD, /* 0x21 */
|
|
- VPCCMD_W_FAN,
|
|
- VPCCMD_R_RF,
|
|
- VPCCMD_W_RF,
|
|
- VPCCMD_W_YMC = 0x2A,
|
|
- VPCCMD_R_FAN = 0x2B,
|
|
- VPCCMD_R_SPECIAL_BUTTONS = 0x31,
|
|
- VPCCMD_W_BL_POWER = 0x33,
|
|
+enum ideapad_laptop_notifier_actions {
|
|
+ IDEAPAD_LAPTOP_YMC_EVENT,
|
|
};
|
|
|
|
-static inline int eval_int_with_arg(acpi_handle handle, const char *name, unsigned long arg, unsigned long *res)
|
|
-{
|
|
- struct acpi_object_list params;
|
|
- unsigned long long result;
|
|
- union acpi_object in_obj;
|
|
- acpi_status status;
|
|
+int ideapad_laptop_register_notifier(struct notifier_block *nb);
|
|
+int ideapad_laptop_unregister_notifier(struct notifier_block *nb);
|
|
+void ideapad_laptop_call_notifier(unsigned long action, void *data);
|
|
|
|
- params.count = 1;
|
|
- params.pointer = &in_obj;
|
|
- in_obj.type = ACPI_TYPE_INTEGER;
|
|
- in_obj.integer.value = arg;
|
|
-
|
|
- status = acpi_evaluate_integer(handle, (char *)name, ¶ms, &result);
|
|
- if (ACPI_FAILURE(status))
|
|
- return -EIO;
|
|
-
|
|
- if (res)
|
|
- *res = result;
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
-static inline int eval_vpcr(acpi_handle handle, unsigned long cmd, unsigned long *res)
|
|
-{
|
|
- return eval_int_with_arg(handle, "VPCR", cmd, res);
|
|
-}
|
|
-
|
|
-static inline int eval_vpcw(acpi_handle handle, unsigned long cmd, unsigned long data)
|
|
-{
|
|
- struct acpi_object_list params;
|
|
- union acpi_object in_obj[2];
|
|
- acpi_status status;
|
|
-
|
|
- params.count = 2;
|
|
- params.pointer = in_obj;
|
|
- in_obj[0].type = ACPI_TYPE_INTEGER;
|
|
- in_obj[0].integer.value = cmd;
|
|
- in_obj[1].type = ACPI_TYPE_INTEGER;
|
|
- in_obj[1].integer.value = data;
|
|
-
|
|
- status = acpi_evaluate_object(handle, "VPCW", ¶ms, NULL);
|
|
- if (ACPI_FAILURE(status))
|
|
- return -EIO;
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
-#define IDEAPAD_EC_TIMEOUT 200 /* in ms */
|
|
-
|
|
-static inline int read_ec_data(acpi_handle handle, unsigned long cmd, unsigned long *data)
|
|
-{
|
|
- unsigned long end_jiffies, val;
|
|
- int err;
|
|
-
|
|
- err = eval_vpcw(handle, 1, cmd);
|
|
- if (err)
|
|
- return err;
|
|
-
|
|
- end_jiffies = jiffies + msecs_to_jiffies(IDEAPAD_EC_TIMEOUT) + 1;
|
|
-
|
|
- while (time_before(jiffies, end_jiffies)) {
|
|
- schedule();
|
|
-
|
|
- err = eval_vpcr(handle, 1, &val);
|
|
- if (err)
|
|
- return err;
|
|
-
|
|
- if (val == 0)
|
|
- return eval_vpcr(handle, 0, data);
|
|
- }
|
|
-
|
|
- acpi_handle_err(handle, "timeout in %s\n", __func__);
|
|
-
|
|
- return -ETIMEDOUT;
|
|
-}
|
|
-
|
|
-static inline int write_ec_cmd(acpi_handle handle, unsigned long cmd, unsigned long data)
|
|
-{
|
|
- unsigned long end_jiffies, val;
|
|
- int err;
|
|
-
|
|
- err = eval_vpcw(handle, 0, data);
|
|
- if (err)
|
|
- return err;
|
|
-
|
|
- err = eval_vpcw(handle, 1, cmd);
|
|
- if (err)
|
|
- return err;
|
|
-
|
|
- end_jiffies = jiffies + msecs_to_jiffies(IDEAPAD_EC_TIMEOUT) + 1;
|
|
-
|
|
- while (time_before(jiffies, end_jiffies)) {
|
|
- schedule();
|
|
-
|
|
- err = eval_vpcr(handle, 1, &val);
|
|
- if (err)
|
|
- return err;
|
|
-
|
|
- if (val == 0)
|
|
- return 0;
|
|
- }
|
|
-
|
|
- acpi_handle_err(handle, "timeout in %s\n", __func__);
|
|
-
|
|
- return -ETIMEDOUT;
|
|
-}
|
|
-
|
|
-#undef IDEAPAD_EC_TIMEOUT
|
|
#endif /* !_IDEAPAD_LAPTOP_H_ */
|
|
diff --git a/drivers/platform/x86/lenovo-ymc.c b/drivers/platform/x86/lenovo-ymc.c
|
|
index ef2c267ab485cd..bd9f95404c7cb0 100644
|
|
--- a/drivers/platform/x86/lenovo-ymc.c
|
|
+++ b/drivers/platform/x86/lenovo-ymc.c
|
|
@@ -20,32 +20,10 @@
|
|
#define LENOVO_YMC_QUERY_INSTANCE 0
|
|
#define LENOVO_YMC_QUERY_METHOD 0x01
|
|
|
|
-static bool ec_trigger __read_mostly;
|
|
-module_param(ec_trigger, bool, 0444);
|
|
-MODULE_PARM_DESC(ec_trigger, "Enable EC triggering work-around to force emitting tablet mode events");
|
|
-
|
|
static bool force;
|
|
module_param(force, bool, 0444);
|
|
MODULE_PARM_DESC(force, "Force loading on boards without a convertible DMI chassis-type");
|
|
|
|
-static const struct dmi_system_id ec_trigger_quirk_dmi_table[] = {
|
|
- {
|
|
- /* Lenovo Yoga 7 14ARB7 */
|
|
- .matches = {
|
|
- DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
|
- DMI_MATCH(DMI_PRODUCT_NAME, "82QF"),
|
|
- },
|
|
- },
|
|
- {
|
|
- /* Lenovo Yoga 7 14ACN6 */
|
|
- .matches = {
|
|
- DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
|
- DMI_MATCH(DMI_PRODUCT_NAME, "82N7"),
|
|
- },
|
|
- },
|
|
- { }
|
|
-};
|
|
-
|
|
static const struct dmi_system_id allowed_chasis_types_dmi_table[] = {
|
|
{
|
|
.matches = {
|
|
@@ -62,21 +40,8 @@ static const struct dmi_system_id allowed_chasis_types_dmi_table[] = {
|
|
|
|
struct lenovo_ymc_private {
|
|
struct input_dev *input_dev;
|
|
- struct acpi_device *ec_acpi_dev;
|
|
};
|
|
|
|
-static void lenovo_ymc_trigger_ec(struct wmi_device *wdev, struct lenovo_ymc_private *priv)
|
|
-{
|
|
- int err;
|
|
-
|
|
- if (!priv->ec_acpi_dev)
|
|
- return;
|
|
-
|
|
- err = write_ec_cmd(priv->ec_acpi_dev->handle, VPCCMD_W_YMC, 1);
|
|
- if (err)
|
|
- dev_warn(&wdev->dev, "Could not write YMC: %d\n", err);
|
|
-}
|
|
-
|
|
static const struct key_entry lenovo_ymc_keymap[] = {
|
|
/* Ignore the uninitialized state */
|
|
{ KE_IGNORE, 0x00 },
|
|
@@ -127,11 +92,9 @@ static void lenovo_ymc_notify(struct wmi_device *wdev, union acpi_object *data)
|
|
|
|
free_obj:
|
|
kfree(obj);
|
|
- lenovo_ymc_trigger_ec(wdev, priv);
|
|
+ ideapad_laptop_call_notifier(IDEAPAD_LAPTOP_YMC_EVENT, &code);
|
|
}
|
|
|
|
-static void acpi_dev_put_helper(void *p) { acpi_dev_put(p); }
|
|
-
|
|
static int lenovo_ymc_probe(struct wmi_device *wdev, const void *ctx)
|
|
{
|
|
struct lenovo_ymc_private *priv;
|
|
@@ -145,29 +108,10 @@ static int lenovo_ymc_probe(struct wmi_device *wdev, const void *ctx)
|
|
return -ENODEV;
|
|
}
|
|
|
|
- ec_trigger |= dmi_check_system(ec_trigger_quirk_dmi_table);
|
|
-
|
|
priv = devm_kzalloc(&wdev->dev, sizeof(*priv), GFP_KERNEL);
|
|
if (!priv)
|
|
return -ENOMEM;
|
|
|
|
- if (ec_trigger) {
|
|
- pr_debug("Lenovo YMC enable EC triggering.\n");
|
|
- priv->ec_acpi_dev = acpi_dev_get_first_match_dev("VPC2004", NULL, -1);
|
|
-
|
|
- if (!priv->ec_acpi_dev) {
|
|
- dev_err(&wdev->dev, "Could not find EC ACPI device.\n");
|
|
- return -ENODEV;
|
|
- }
|
|
- err = devm_add_action_or_reset(&wdev->dev,
|
|
- acpi_dev_put_helper, priv->ec_acpi_dev);
|
|
- if (err) {
|
|
- dev_err(&wdev->dev,
|
|
- "Could not clean up EC ACPI device: %d\n", err);
|
|
- return err;
|
|
- }
|
|
- }
|
|
-
|
|
input_dev = devm_input_allocate_device(&wdev->dev);
|
|
if (!input_dev)
|
|
return -ENOMEM;
|
|
@@ -194,7 +138,6 @@ static int lenovo_ymc_probe(struct wmi_device *wdev, const void *ctx)
|
|
dev_set_drvdata(&wdev->dev, priv);
|
|
|
|
/* Report the state for the first time on probe */
|
|
- lenovo_ymc_trigger_ec(wdev, priv);
|
|
lenovo_ymc_notify(wdev, NULL);
|
|
return 0;
|
|
}
|
|
@@ -219,3 +162,4 @@ module_wmi_driver(lenovo_ymc_driver);
|
|
MODULE_AUTHOR("Gergo Koteles <soyer@irl.hu>");
|
|
MODULE_DESCRIPTION("Lenovo Yoga Mode Control driver");
|
|
MODULE_LICENSE("GPL");
|
|
+MODULE_IMPORT_NS(IDEAPAD_LAPTOP);
|
|
diff --git a/drivers/s390/crypto/pkey_api.c b/drivers/s390/crypto/pkey_api.c
|
|
index 70fcb5c40cfe32..21fc6151af79f5 100644
|
|
--- a/drivers/s390/crypto/pkey_api.c
|
|
+++ b/drivers/s390/crypto/pkey_api.c
|
|
@@ -1333,7 +1333,7 @@ static void *_copy_apqns_from_user(void __user *uapqns, size_t nr_apqns)
|
|
if (!uapqns || nr_apqns == 0)
|
|
return NULL;
|
|
|
|
- return memdup_user(uapqns, nr_apqns * sizeof(struct pkey_apqn));
|
|
+ return memdup_array_user(uapqns, nr_apqns, sizeof(struct pkey_apqn));
|
|
}
|
|
|
|
static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,
|
|
diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
|
|
index dd3630b09aa241..54f66142e14a82 100644
|
|
--- a/drivers/scsi/megaraid/megaraid_sas_base.c
|
|
+++ b/drivers/scsi/megaraid/megaraid_sas_base.c
|
|
@@ -5908,7 +5908,11 @@ megasas_set_high_iops_queue_affinity_and_hint(struct megasas_instance *instance)
|
|
const struct cpumask *mask;
|
|
|
|
if (instance->perf_mode == MR_BALANCED_PERF_MODE) {
|
|
- mask = cpumask_of_node(dev_to_node(&instance->pdev->dev));
|
|
+ int nid = dev_to_node(&instance->pdev->dev);
|
|
+
|
|
+ if (nid == NUMA_NO_NODE)
|
|
+ nid = 0;
|
|
+ mask = cpumask_of_node(nid);
|
|
|
|
for (i = 0; i < instance->low_latency_index_start; i++) {
|
|
irq = pci_irq_vector(instance->pdev, i);
|
|
diff --git a/drivers/spi/spi-cadence-quadspi.c b/drivers/spi/spi-cadence-quadspi.c
|
|
index bf9b816637d02e..9285a683324f4f 100644
|
|
--- a/drivers/spi/spi-cadence-quadspi.c
|
|
+++ b/drivers/spi/spi-cadence-quadspi.c
|
|
@@ -1868,6 +1868,13 @@ static int cqspi_probe(struct platform_device *pdev)
|
|
goto probe_setup_failed;
|
|
}
|
|
|
|
+ pm_runtime_enable(dev);
|
|
+
|
|
+ if (cqspi->rx_chan) {
|
|
+ dma_release_channel(cqspi->rx_chan);
|
|
+ goto probe_setup_failed;
|
|
+ }
|
|
+
|
|
ret = spi_register_controller(host);
|
|
if (ret) {
|
|
dev_err(&pdev->dev, "failed to register SPI ctlr %d\n", ret);
|
|
@@ -1877,6 +1884,7 @@ static int cqspi_probe(struct platform_device *pdev)
|
|
return 0;
|
|
probe_setup_failed:
|
|
cqspi_controller_enable(cqspi, 0);
|
|
+ pm_runtime_disable(dev);
|
|
probe_reset_failed:
|
|
if (cqspi->is_jh7110)
|
|
cqspi_jh7110_disable_clk(pdev, cqspi);
|
|
@@ -1898,7 +1906,8 @@ static void cqspi_remove(struct platform_device *pdev)
|
|
if (cqspi->rx_chan)
|
|
dma_release_channel(cqspi->rx_chan);
|
|
|
|
- clk_disable_unprepare(cqspi->clk);
|
|
+ if (pm_runtime_get_sync(&pdev->dev) >= 0)
|
|
+ clk_disable(cqspi->clk);
|
|
|
|
if (cqspi->is_jh7110)
|
|
cqspi_jh7110_disable_clk(pdev, cqspi);
|
|
diff --git a/drivers/staging/rtl8723bs/core/rtw_security.c b/drivers/staging/rtl8723bs/core/rtw_security.c
|
|
index 7ecdaa2eeaf33e..83fdee444c1c03 100644
|
|
--- a/drivers/staging/rtl8723bs/core/rtw_security.c
|
|
+++ b/drivers/staging/rtl8723bs/core/rtw_security.c
|
|
@@ -869,29 +869,21 @@ static signed int aes_cipher(u8 *key, uint hdrlen,
|
|
num_blocks, payload_index;
|
|
|
|
u8 pn_vector[6];
|
|
- u8 mic_iv[16];
|
|
- u8 mic_header1[16];
|
|
- u8 mic_header2[16];
|
|
- u8 ctr_preload[16];
|
|
+ u8 mic_iv[16] = {};
|
|
+ u8 mic_header1[16] = {};
|
|
+ u8 mic_header2[16] = {};
|
|
+ u8 ctr_preload[16] = {};
|
|
|
|
/* Intermediate Buffers */
|
|
- u8 chain_buffer[16];
|
|
- u8 aes_out[16];
|
|
- u8 padded_buffer[16];
|
|
+ u8 chain_buffer[16] = {};
|
|
+ u8 aes_out[16] = {};
|
|
+ u8 padded_buffer[16] = {};
|
|
u8 mic[8];
|
|
uint frtype = GetFrameType(pframe);
|
|
uint frsubtype = GetFrameSubType(pframe);
|
|
|
|
frsubtype = frsubtype>>4;
|
|
|
|
- memset((void *)mic_iv, 0, 16);
|
|
- memset((void *)mic_header1, 0, 16);
|
|
- memset((void *)mic_header2, 0, 16);
|
|
- memset((void *)ctr_preload, 0, 16);
|
|
- memset((void *)chain_buffer, 0, 16);
|
|
- memset((void *)aes_out, 0, 16);
|
|
- memset((void *)padded_buffer, 0, 16);
|
|
-
|
|
if ((hdrlen == WLAN_HDR_A3_LEN) || (hdrlen == WLAN_HDR_A3_QOS_LEN))
|
|
a4_exists = 0;
|
|
else
|
|
@@ -1081,15 +1073,15 @@ static signed int aes_decipher(u8 *key, uint hdrlen,
|
|
num_blocks, payload_index;
|
|
signed int res = _SUCCESS;
|
|
u8 pn_vector[6];
|
|
- u8 mic_iv[16];
|
|
- u8 mic_header1[16];
|
|
- u8 mic_header2[16];
|
|
- u8 ctr_preload[16];
|
|
+ u8 mic_iv[16] = {};
|
|
+ u8 mic_header1[16] = {};
|
|
+ u8 mic_header2[16] = {};
|
|
+ u8 ctr_preload[16] = {};
|
|
|
|
/* Intermediate Buffers */
|
|
- u8 chain_buffer[16];
|
|
- u8 aes_out[16];
|
|
- u8 padded_buffer[16];
|
|
+ u8 chain_buffer[16] = {};
|
|
+ u8 aes_out[16] = {};
|
|
+ u8 padded_buffer[16] = {};
|
|
u8 mic[8];
|
|
|
|
uint frtype = GetFrameType(pframe);
|
|
@@ -1097,14 +1089,6 @@ static signed int aes_decipher(u8 *key, uint hdrlen,
|
|
|
|
frsubtype = frsubtype>>4;
|
|
|
|
- memset((void *)mic_iv, 0, 16);
|
|
- memset((void *)mic_header1, 0, 16);
|
|
- memset((void *)mic_header2, 0, 16);
|
|
- memset((void *)ctr_preload, 0, 16);
|
|
- memset((void *)chain_buffer, 0, 16);
|
|
- memset((void *)aes_out, 0, 16);
|
|
- memset((void *)padded_buffer, 0, 16);
|
|
-
|
|
/* start to decrypt the payload */
|
|
|
|
num_blocks = (plen-8) / 16; /* plen including LLC, payload_length and mic) */
|
|
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
|
|
index 04809b781f45be..60d48d857b1c00 100644
|
|
--- a/drivers/tty/serial/imx.c
|
|
+++ b/drivers/tty/serial/imx.c
|
|
@@ -234,6 +234,7 @@ struct imx_port {
|
|
enum imx_tx_state tx_state;
|
|
struct hrtimer trigger_start_tx;
|
|
struct hrtimer trigger_stop_tx;
|
|
+ unsigned int rxtl;
|
|
};
|
|
|
|
struct imx_port_ucrs {
|
|
@@ -1337,6 +1338,7 @@ static void imx_uart_clear_rx_errors(struct imx_port *sport)
|
|
|
|
#define TXTL_DEFAULT 8
|
|
#define RXTL_DEFAULT 8 /* 8 characters or aging timer */
|
|
+#define RXTL_CONSOLE_DEFAULT 1
|
|
#define TXTL_DMA 8 /* DMA burst setting */
|
|
#define RXTL_DMA 9 /* DMA burst setting */
|
|
|
|
@@ -1449,7 +1451,7 @@ static void imx_uart_disable_dma(struct imx_port *sport)
|
|
ucr1 &= ~(UCR1_RXDMAEN | UCR1_TXDMAEN | UCR1_ATDMAEN);
|
|
imx_uart_writel(sport, ucr1, UCR1);
|
|
|
|
- imx_uart_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT);
|
|
+ imx_uart_setup_ufcr(sport, TXTL_DEFAULT, sport->rxtl);
|
|
|
|
sport->dma_is_enabled = 0;
|
|
}
|
|
@@ -1474,7 +1476,12 @@ static int imx_uart_startup(struct uart_port *port)
|
|
return retval;
|
|
}
|
|
|
|
- imx_uart_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT);
|
|
+ if (uart_console(&sport->port))
|
|
+ sport->rxtl = RXTL_CONSOLE_DEFAULT;
|
|
+ else
|
|
+ sport->rxtl = RXTL_DEFAULT;
|
|
+
|
|
+ imx_uart_setup_ufcr(sport, TXTL_DEFAULT, sport->rxtl);
|
|
|
|
/* disable the DREN bit (Data Ready interrupt enable) before
|
|
* requesting IRQs
|
|
@@ -1887,7 +1894,7 @@ static int imx_uart_poll_init(struct uart_port *port)
|
|
if (retval)
|
|
clk_disable_unprepare(sport->clk_ipg);
|
|
|
|
- imx_uart_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT);
|
|
+ imx_uart_setup_ufcr(sport, TXTL_DEFAULT, sport->rxtl);
|
|
|
|
spin_lock_irqsave(&sport->port.lock, flags);
|
|
|
|
@@ -1979,7 +1986,7 @@ static int imx_uart_rs485_config(struct uart_port *port, struct ktermios *termio
|
|
/* If the receiver trigger is 0, set it to a default value */
|
|
ufcr = imx_uart_readl(sport, UFCR);
|
|
if ((ufcr & UFCR_RXTL_MASK) == 0)
|
|
- imx_uart_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT);
|
|
+ imx_uart_setup_ufcr(sport, TXTL_DEFAULT, sport->rxtl);
|
|
imx_uart_start_rx(port);
|
|
}
|
|
|
|
@@ -2164,7 +2171,7 @@ imx_uart_console_setup(struct console *co, char *options)
|
|
else
|
|
imx_uart_console_get_options(sport, &baud, &parity, &bits);
|
|
|
|
- imx_uart_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT);
|
|
+ imx_uart_setup_ufcr(sport, TXTL_DEFAULT, sport->rxtl);
|
|
|
|
retval = uart_set_options(&sport->port, co, baud, parity, bits, flow);
|
|
|
|
diff --git a/drivers/tty/serial/uartlite.c b/drivers/tty/serial/uartlite.c
|
|
index b225a78f6175f3..9f39bafa7fa968 100644
|
|
--- a/drivers/tty/serial/uartlite.c
|
|
+++ b/drivers/tty/serial/uartlite.c
|
|
@@ -872,16 +872,6 @@ static int ulite_probe(struct platform_device *pdev)
|
|
pm_runtime_set_active(&pdev->dev);
|
|
pm_runtime_enable(&pdev->dev);
|
|
|
|
- if (!ulite_uart_driver.state) {
|
|
- dev_dbg(&pdev->dev, "uartlite: calling uart_register_driver()\n");
|
|
- ret = uart_register_driver(&ulite_uart_driver);
|
|
- if (ret < 0) {
|
|
- dev_err(&pdev->dev, "Failed to register driver\n");
|
|
- clk_disable_unprepare(pdata->clk);
|
|
- return ret;
|
|
- }
|
|
- }
|
|
-
|
|
ret = ulite_assign(&pdev->dev, id, res->start, irq, pdata);
|
|
|
|
pm_runtime_mark_last_busy(&pdev->dev);
|
|
@@ -922,16 +912,25 @@ static struct platform_driver ulite_platform_driver = {
|
|
|
|
static int __init ulite_init(void)
|
|
{
|
|
+ int ret;
|
|
+
|
|
+ pr_debug("uartlite: calling uart_register_driver()\n");
|
|
+ ret = uart_register_driver(&ulite_uart_driver);
|
|
+ if (ret)
|
|
+ return ret;
|
|
|
|
pr_debug("uartlite: calling platform_driver_register()\n");
|
|
- return platform_driver_register(&ulite_platform_driver);
|
|
+ ret = platform_driver_register(&ulite_platform_driver);
|
|
+ if (ret)
|
|
+ uart_unregister_driver(&ulite_uart_driver);
|
|
+
|
|
+ return ret;
|
|
}
|
|
|
|
static void __exit ulite_exit(void)
|
|
{
|
|
platform_driver_unregister(&ulite_platform_driver);
|
|
- if (ulite_uart_driver.state)
|
|
- uart_unregister_driver(&ulite_uart_driver);
|
|
+ uart_unregister_driver(&ulite_uart_driver);
|
|
}
|
|
|
|
module_init(ulite_init);
|
|
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
|
|
index 6bd1a7785e888c..c5ec7306aa7130 100644
|
|
--- a/drivers/tty/vt/vt.c
|
|
+++ b/drivers/tty/vt/vt.c
|
|
@@ -962,7 +962,7 @@ void redraw_screen(struct vc_data *vc, int is_switch)
|
|
}
|
|
|
|
if (redraw) {
|
|
- int update;
|
|
+ bool update;
|
|
int old_was_color = vc->vc_can_do_color;
|
|
|
|
set_origin(vc);
|
|
@@ -999,7 +999,7 @@ int vc_cons_allocated(unsigned int i)
|
|
return (i < MAX_NR_CONSOLES && vc_cons[i].d);
|
|
}
|
|
|
|
-static void visual_init(struct vc_data *vc, int num, int init)
|
|
+static void visual_init(struct vc_data *vc, int num, bool init)
|
|
{
|
|
/* ++Geert: vc->vc_sw->con_init determines console size */
|
|
if (vc->vc_sw)
|
|
@@ -1083,7 +1083,7 @@ int vc_allocate(unsigned int currcons) /* return 0 on success */
|
|
vc->port.ops = &vc_port_ops;
|
|
INIT_WORK(&vc_cons[currcons].SAK_work, vc_SAK);
|
|
|
|
- visual_init(vc, currcons, 1);
|
|
+ visual_init(vc, currcons, true);
|
|
|
|
if (!*vc->uni_pagedict_loc)
|
|
con_set_default_unimap(vc);
|
|
@@ -1582,7 +1582,7 @@ static void csi_X(struct vc_data *vc, unsigned int vpar)
|
|
vc_uniscr_clear_line(vc, vc->state.x, count);
|
|
scr_memsetw((unsigned short *)vc->vc_pos, vc->vc_video_erase_char, 2 * count);
|
|
if (con_should_update(vc))
|
|
- vc->vc_sw->con_clear(vc, vc->state.y, vc->state.x, 1, count);
|
|
+ vc->vc_sw->con_clear(vc, vc->state.y, vc->state.x, count);
|
|
vc->vc_need_wrap = 0;
|
|
}
|
|
|
|
@@ -3474,7 +3474,7 @@ static int __init con_init(void)
|
|
vc_cons[currcons].d = vc = kzalloc(sizeof(struct vc_data), GFP_NOWAIT);
|
|
INIT_WORK(&vc_cons[currcons].SAK_work, vc_SAK);
|
|
tty_port_init(&vc->port);
|
|
- visual_init(vc, currcons, 1);
|
|
+ visual_init(vc, currcons, true);
|
|
/* Assuming vc->vc_{cols,rows,screenbuf_size} are sane here. */
|
|
vc->vc_screenbuf = kzalloc(vc->vc_screenbuf_size, GFP_NOWAIT);
|
|
vc_init(vc, currcons || !vc->vc_sw->con_save_screen);
|
|
@@ -3642,7 +3642,7 @@ static int do_bind_con_driver(const struct consw *csw, int first, int last,
|
|
old_was_color = vc->vc_can_do_color;
|
|
vc->vc_sw->con_deinit(vc);
|
|
vc->vc_origin = (unsigned long)vc->vc_screenbuf;
|
|
- visual_init(vc, i, 0);
|
|
+ visual_init(vc, i, false);
|
|
set_origin(vc);
|
|
update_attr(vc);
|
|
|
|
diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c
|
|
index 9dabc03675b00a..412931cf240f64 100644
|
|
--- a/drivers/ufs/core/ufshcd.c
|
|
+++ b/drivers/ufs/core/ufshcd.c
|
|
@@ -1284,6 +1284,7 @@ static int ufshcd_clock_scaling_prepare(struct ufs_hba *hba, u64 timeout_us)
|
|
* make sure that there are no outstanding requests when
|
|
* clock scaling is in progress
|
|
*/
|
|
+ mutex_lock(&hba->host->scan_mutex);
|
|
blk_mq_quiesce_tagset(&hba->host->tag_set);
|
|
mutex_lock(&hba->wb_mutex);
|
|
down_write(&hba->clk_scaling_lock);
|
|
@@ -1294,6 +1295,7 @@ static int ufshcd_clock_scaling_prepare(struct ufs_hba *hba, u64 timeout_us)
|
|
up_write(&hba->clk_scaling_lock);
|
|
mutex_unlock(&hba->wb_mutex);
|
|
blk_mq_unquiesce_tagset(&hba->host->tag_set);
|
|
+ mutex_unlock(&hba->host->scan_mutex);
|
|
goto out;
|
|
}
|
|
|
|
@@ -1315,6 +1317,7 @@ static void ufshcd_clock_scaling_unprepare(struct ufs_hba *hba, int err, bool sc
|
|
mutex_unlock(&hba->wb_mutex);
|
|
|
|
blk_mq_unquiesce_tagset(&hba->host->tag_set);
|
|
+ mutex_unlock(&hba->host->scan_mutex);
|
|
ufshcd_release(hba);
|
|
}
|
|
|
|
diff --git a/drivers/uio/uio_hv_generic.c b/drivers/uio/uio_hv_generic.c
|
|
index 2804a4f749750a..17c1f85f2b7ba2 100644
|
|
--- a/drivers/uio/uio_hv_generic.c
|
|
+++ b/drivers/uio/uio_hv_generic.c
|
|
@@ -249,6 +249,7 @@ hv_uio_probe(struct hv_device *dev,
|
|
struct hv_uio_private_data *pdata;
|
|
void *ring_buffer;
|
|
int ret;
|
|
+ size_t ring_size = hv_dev_ring_size(channel);
|
|
|
|
/* Communicating with host has to be via shared memory not hypercall */
|
|
if (!channel->offermsg.monitor_allocated) {
|
|
@@ -256,12 +257,17 @@ hv_uio_probe(struct hv_device *dev,
|
|
return -ENOTSUPP;
|
|
}
|
|
|
|
+ if (!ring_size)
|
|
+ ring_size = HV_RING_SIZE * PAGE_SIZE;
|
|
+
|
|
+ /* Adjust ring size if necessary to have it page aligned */
|
|
+ ring_size = VMBUS_RING_SIZE(ring_size);
|
|
+
|
|
pdata = devm_kzalloc(&dev->device, sizeof(*pdata), GFP_KERNEL);
|
|
if (!pdata)
|
|
return -ENOMEM;
|
|
|
|
- ret = vmbus_alloc_ring(channel, HV_RING_SIZE * PAGE_SIZE,
|
|
- HV_RING_SIZE * PAGE_SIZE);
|
|
+ ret = vmbus_alloc_ring(channel, ring_size, ring_size);
|
|
if (ret)
|
|
return ret;
|
|
|
|
diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c
|
|
index 559c121f092300..600ad9412c146b 100644
|
|
--- a/drivers/usb/class/cdc-wdm.c
|
|
+++ b/drivers/usb/class/cdc-wdm.c
|
|
@@ -92,7 +92,6 @@ struct wdm_device {
|
|
u16 wMaxCommand;
|
|
u16 wMaxPacketSize;
|
|
__le16 inum;
|
|
- int reslength;
|
|
int length;
|
|
int read;
|
|
int count;
|
|
@@ -214,6 +213,11 @@ static void wdm_in_callback(struct urb *urb)
|
|
if (desc->rerr == 0 && status != -EPIPE)
|
|
desc->rerr = status;
|
|
|
|
+ if (length == 0) {
|
|
+ dev_dbg(&desc->intf->dev, "received ZLP\n");
|
|
+ goto skip_zlp;
|
|
+ }
|
|
+
|
|
if (length + desc->length > desc->wMaxCommand) {
|
|
/* The buffer would overflow */
|
|
set_bit(WDM_OVERFLOW, &desc->flags);
|
|
@@ -222,18 +226,18 @@ static void wdm_in_callback(struct urb *urb)
|
|
if (!test_bit(WDM_OVERFLOW, &desc->flags)) {
|
|
memmove(desc->ubuf + desc->length, desc->inbuf, length);
|
|
desc->length += length;
|
|
- desc->reslength = length;
|
|
}
|
|
}
|
|
skip_error:
|
|
|
|
if (desc->rerr) {
|
|
/*
|
|
- * Since there was an error, userspace may decide to not read
|
|
- * any data after poll'ing.
|
|
+ * If there was a ZLP or an error, userspace may decide to not
|
|
+ * read any data after poll'ing.
|
|
* We should respond to further attempts from the device to send
|
|
* data, so that we can get unstuck.
|
|
*/
|
|
+skip_zlp:
|
|
schedule_work(&desc->service_outs_intr);
|
|
} else {
|
|
set_bit(WDM_READ, &desc->flags);
|
|
@@ -585,15 +589,6 @@ static ssize_t wdm_read
|
|
goto retry;
|
|
}
|
|
|
|
- if (!desc->reslength) { /* zero length read */
|
|
- dev_dbg(&desc->intf->dev, "zero length - clearing WDM_READ\n");
|
|
- clear_bit(WDM_READ, &desc->flags);
|
|
- rv = service_outstanding_interrupt(desc);
|
|
- spin_unlock_irq(&desc->iuspin);
|
|
- if (rv < 0)
|
|
- goto err;
|
|
- goto retry;
|
|
- }
|
|
cntr = desc->length;
|
|
spin_unlock_irq(&desc->iuspin);
|
|
}
|
|
@@ -1016,7 +1011,7 @@ static void service_interrupt_work(struct work_struct *work)
|
|
|
|
spin_lock_irq(&desc->iuspin);
|
|
service_outstanding_interrupt(desc);
|
|
- if (!desc->resp_count) {
|
|
+ if (!desc->resp_count && (desc->length || desc->rerr)) {
|
|
set_bit(WDM_READ, &desc->flags);
|
|
wake_up(&desc->wait);
|
|
}
|
|
diff --git a/drivers/usb/common/usb-conn-gpio.c b/drivers/usb/common/usb-conn-gpio.c
|
|
index 501e8bc9738eba..1096a884c8d705 100644
|
|
--- a/drivers/usb/common/usb-conn-gpio.c
|
|
+++ b/drivers/usb/common/usb-conn-gpio.c
|
|
@@ -20,6 +20,9 @@
|
|
#include <linux/power_supply.h>
|
|
#include <linux/regulator/consumer.h>
|
|
#include <linux/usb/role.h>
|
|
+#include <linux/idr.h>
|
|
+
|
|
+static DEFINE_IDA(usb_conn_ida);
|
|
|
|
#define USB_GPIO_DEB_MS 20 /* ms */
|
|
#define USB_GPIO_DEB_US ((USB_GPIO_DEB_MS) * 1000) /* us */
|
|
@@ -29,6 +32,7 @@
|
|
|
|
struct usb_conn_info {
|
|
struct device *dev;
|
|
+ int conn_id; /* store the IDA-allocated ID */
|
|
struct usb_role_switch *role_sw;
|
|
enum usb_role last_role;
|
|
struct regulator *vbus;
|
|
@@ -160,7 +164,17 @@ static int usb_conn_psy_register(struct usb_conn_info *info)
|
|
.of_node = dev->of_node,
|
|
};
|
|
|
|
- desc->name = "usb-charger";
|
|
+ info->conn_id = ida_alloc(&usb_conn_ida, GFP_KERNEL);
|
|
+ if (info->conn_id < 0)
|
|
+ return info->conn_id;
|
|
+
|
|
+ desc->name = devm_kasprintf(dev, GFP_KERNEL, "usb-charger-%d",
|
|
+ info->conn_id);
|
|
+ if (!desc->name) {
|
|
+ ida_free(&usb_conn_ida, info->conn_id);
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+
|
|
desc->properties = usb_charger_properties;
|
|
desc->num_properties = ARRAY_SIZE(usb_charger_properties);
|
|
desc->get_property = usb_charger_get_property;
|
|
@@ -168,8 +182,10 @@ static int usb_conn_psy_register(struct usb_conn_info *info)
|
|
cfg.drv_data = info;
|
|
|
|
info->charger = devm_power_supply_register(dev, desc, &cfg);
|
|
- if (IS_ERR(info->charger))
|
|
- dev_err(dev, "Unable to register charger\n");
|
|
+ if (IS_ERR(info->charger)) {
|
|
+ dev_err(dev, "Unable to register charger %d\n", info->conn_id);
|
|
+ ida_free(&usb_conn_ida, info->conn_id);
|
|
+ }
|
|
|
|
return PTR_ERR_OR_ZERO(info->charger);
|
|
}
|
|
@@ -277,6 +293,9 @@ static void usb_conn_remove(struct platform_device *pdev)
|
|
|
|
cancel_delayed_work_sync(&info->dw_det);
|
|
|
|
+ if (info->charger)
|
|
+ ida_free(&usb_conn_ida, info->conn_id);
|
|
+
|
|
if (info->last_role == USB_ROLE_HOST && info->vbus)
|
|
regulator_disable(info->vbus);
|
|
|
|
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
|
|
index 2a938cf47ccd62..da6d5e5f79e7a5 100644
|
|
--- a/drivers/usb/core/usb.c
|
|
+++ b/drivers/usb/core/usb.c
|
|
@@ -695,15 +695,16 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent,
|
|
device_set_of_node_from_dev(&dev->dev, bus->sysdev);
|
|
dev_set_name(&dev->dev, "usb%d", bus->busnum);
|
|
} else {
|
|
+ int n;
|
|
+
|
|
/* match any labeling on the hubs; it's one-based */
|
|
if (parent->devpath[0] == '0') {
|
|
- snprintf(dev->devpath, sizeof dev->devpath,
|
|
- "%d", port1);
|
|
+ n = snprintf(dev->devpath, sizeof(dev->devpath), "%d", port1);
|
|
/* Root ports are not counted in route string */
|
|
dev->route = 0;
|
|
} else {
|
|
- snprintf(dev->devpath, sizeof dev->devpath,
|
|
- "%s.%d", parent->devpath, port1);
|
|
+ n = snprintf(dev->devpath, sizeof(dev->devpath), "%s.%d",
|
|
+ parent->devpath, port1);
|
|
/* Route string assumes hubs have less than 16 ports */
|
|
if (port1 < 15)
|
|
dev->route = parent->route +
|
|
@@ -712,6 +713,11 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent,
|
|
dev->route = parent->route +
|
|
(15 << ((parent->level - 1)*4));
|
|
}
|
|
+ if (n >= sizeof(dev->devpath)) {
|
|
+ usb_put_hcd(bus_to_hcd(bus));
|
|
+ usb_put_dev(dev);
|
|
+ return NULL;
|
|
+ }
|
|
|
|
dev->dev.parent = &parent->dev;
|
|
dev_set_name(&dev->dev, "%d-%s", bus->busnum, dev->devpath);
|
|
diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c
|
|
index ce20c06a902531..c0db3c52831a2d 100644
|
|
--- a/drivers/usb/dwc2/gadget.c
|
|
+++ b/drivers/usb/dwc2/gadget.c
|
|
@@ -4601,6 +4601,12 @@ static int dwc2_hsotg_udc_stop(struct usb_gadget *gadget)
|
|
if (!hsotg)
|
|
return -ENODEV;
|
|
|
|
+ /* Exit clock gating when driver is stopped. */
|
|
+ if (hsotg->params.power_down == DWC2_POWER_DOWN_PARAM_NONE &&
|
|
+ hsotg->bus_suspended && !hsotg->params.no_clock_gating) {
|
|
+ dwc2_gadget_exit_clock_gating(hsotg, 0);
|
|
+ }
|
|
+
|
|
/* all endpoints should be shutdown */
|
|
for (ep = 1; ep < hsotg->num_of_eps; ep++) {
|
|
if (hsotg->eps_in[ep])
|
|
diff --git a/drivers/usb/gadget/function/f_tcm.c b/drivers/usb/gadget/function/f_tcm.c
|
|
index a7cd0a06879e61..5d0d8949539539 100644
|
|
--- a/drivers/usb/gadget/function/f_tcm.c
|
|
+++ b/drivers/usb/gadget/function/f_tcm.c
|
|
@@ -1297,14 +1297,14 @@ static struct se_portal_group *usbg_make_tpg(struct se_wwn *wwn,
|
|
struct usbg_tport *tport = container_of(wwn, struct usbg_tport,
|
|
tport_wwn);
|
|
struct usbg_tpg *tpg;
|
|
- unsigned long tpgt;
|
|
+ u16 tpgt;
|
|
int ret;
|
|
struct f_tcm_opts *opts;
|
|
unsigned i;
|
|
|
|
if (strstr(name, "tpgt_") != name)
|
|
return ERR_PTR(-EINVAL);
|
|
- if (kstrtoul(name + 5, 0, &tpgt) || tpgt > UINT_MAX)
|
|
+ if (kstrtou16(name + 5, 0, &tpgt))
|
|
return ERR_PTR(-EINVAL);
|
|
ret = -ENODEV;
|
|
mutex_lock(&tpg_instances_lock);
|
|
diff --git a/drivers/usb/typec/altmodes/displayport.c b/drivers/usb/typec/altmodes/displayport.c
|
|
index ccff838ab89e12..5f6fc5b79212ef 100644
|
|
--- a/drivers/usb/typec/altmodes/displayport.c
|
|
+++ b/drivers/usb/typec/altmodes/displayport.c
|
|
@@ -323,6 +323,10 @@ static int dp_altmode_vdm(struct typec_altmode *alt,
|
|
break;
|
|
case CMDT_RSP_NAK:
|
|
switch (cmd) {
|
|
+ case DP_CMD_STATUS_UPDATE:
|
|
+ if (typec_altmode_exit(alt))
|
|
+ dev_err(&dp->alt->dev, "Exit Mode Failed!\n");
|
|
+ break;
|
|
case DP_CMD_CONFIGURE:
|
|
dp->data.conf = 0;
|
|
ret = dp_altmode_configured(dp);
|
|
diff --git a/drivers/usb/typec/mux.c b/drivers/usb/typec/mux.c
|
|
index 80dd91938d9606..a5b2a6f9c57950 100644
|
|
--- a/drivers/usb/typec/mux.c
|
|
+++ b/drivers/usb/typec/mux.c
|
|
@@ -214,7 +214,7 @@ int typec_switch_set(struct typec_switch *sw,
|
|
sw_dev = sw->sw_devs[i];
|
|
|
|
ret = sw_dev->set(sw_dev, orientation);
|
|
- if (ret)
|
|
+ if (ret && ret != -EOPNOTSUPP)
|
|
return ret;
|
|
}
|
|
|
|
@@ -378,7 +378,7 @@ int typec_mux_set(struct typec_mux *mux, struct typec_mux_state *state)
|
|
mux_dev = mux->mux_devs[i];
|
|
|
|
ret = mux_dev->set(mux_dev, state);
|
|
- if (ret)
|
|
+ if (ret && ret != -EOPNOTSUPP)
|
|
return ret;
|
|
}
|
|
|
|
diff --git a/drivers/video/console/dummycon.c b/drivers/video/console/dummycon.c
|
|
index f1711b2f9ff057..d99e1b3e4e5c1a 100644
|
|
--- a/drivers/video/console/dummycon.c
|
|
+++ b/drivers/video/console/dummycon.c
|
|
@@ -82,6 +82,15 @@ static int dummycon_blank(struct vc_data *vc, int blank, int mode_switch)
|
|
/* Redraw, so that we get putc(s) for output done while blanked */
|
|
return 1;
|
|
}
|
|
+
|
|
+static bool dummycon_switch(struct vc_data *vc)
|
|
+{
|
|
+ /*
|
|
+ * Redraw, so that we get putc(s) for output done while switched
|
|
+ * away. Informs deferred consoles to take over the display.
|
|
+ */
|
|
+ return true;
|
|
+}
|
|
#else
|
|
static void dummycon_putc(struct vc_data *vc, int c, int ypos, int xpos) { }
|
|
static void dummycon_putcs(struct vc_data *vc, const unsigned short *s,
|
|
@@ -90,6 +99,10 @@ static int dummycon_blank(struct vc_data *vc, int blank, int mode_switch)
|
|
{
|
|
return 0;
|
|
}
|
|
+static bool dummycon_switch(struct vc_data *vc)
|
|
+{
|
|
+ return false;
|
|
+}
|
|
#endif
|
|
|
|
static const char *dummycon_startup(void)
|
|
@@ -97,7 +110,7 @@ static const char *dummycon_startup(void)
|
|
return "dummy device";
|
|
}
|
|
|
|
-static void dummycon_init(struct vc_data *vc, int init)
|
|
+static void dummycon_init(struct vc_data *vc, bool init)
|
|
{
|
|
vc->vc_can_do_color = 1;
|
|
if (init) {
|
|
@@ -108,8 +121,8 @@ static void dummycon_init(struct vc_data *vc, int init)
|
|
}
|
|
|
|
static void dummycon_deinit(struct vc_data *vc) { }
|
|
-static void dummycon_clear(struct vc_data *vc, int sy, int sx, int height,
|
|
- int width) { }
|
|
+static void dummycon_clear(struct vc_data *vc, unsigned int sy, unsigned int sx,
|
|
+ unsigned int width) { }
|
|
static void dummycon_cursor(struct vc_data *vc, int mode) { }
|
|
|
|
static bool dummycon_scroll(struct vc_data *vc, unsigned int top,
|
|
@@ -119,11 +132,6 @@ static bool dummycon_scroll(struct vc_data *vc, unsigned int top,
|
|
return false;
|
|
}
|
|
|
|
-static int dummycon_switch(struct vc_data *vc)
|
|
-{
|
|
- return 0;
|
|
-}
|
|
-
|
|
/*
|
|
* The console `switch' structure for the dummy console
|
|
*
|
|
diff --git a/drivers/video/console/mdacon.c b/drivers/video/console/mdacon.c
|
|
index ef29b321967f07..26b41a8f36c870 100644
|
|
--- a/drivers/video/console/mdacon.c
|
|
+++ b/drivers/video/console/mdacon.c
|
|
@@ -352,7 +352,7 @@ static const char *mdacon_startup(void)
|
|
return "MDA-2";
|
|
}
|
|
|
|
-static void mdacon_init(struct vc_data *c, int init)
|
|
+static void mdacon_init(struct vc_data *c, bool init)
|
|
{
|
|
c->vc_complement_mask = 0x0800; /* reverse video */
|
|
c->vc_display_fg = &mda_display_fg;
|
|
@@ -442,26 +442,21 @@ static void mdacon_putcs(struct vc_data *c, const unsigned short *s,
|
|
}
|
|
}
|
|
|
|
-static void mdacon_clear(struct vc_data *c, int y, int x,
|
|
- int height, int width)
|
|
+static void mdacon_clear(struct vc_data *c, unsigned int y, unsigned int x,
|
|
+ unsigned int width)
|
|
{
|
|
u16 *dest = mda_addr(x, y);
|
|
u16 eattr = mda_convert_attr(c->vc_video_erase_char);
|
|
|
|
- if (width <= 0 || height <= 0)
|
|
+ if (width <= 0)
|
|
return;
|
|
|
|
- if (x==0 && width==mda_num_columns) {
|
|
- scr_memsetw(dest, eattr, height*width*2);
|
|
- } else {
|
|
- for (; height > 0; height--, dest+=mda_num_columns)
|
|
- scr_memsetw(dest, eattr, width*2);
|
|
- }
|
|
+ scr_memsetw(dest, eattr, width * 2);
|
|
}
|
|
-
|
|
-static int mdacon_switch(struct vc_data *c)
|
|
+
|
|
+static bool mdacon_switch(struct vc_data *c)
|
|
{
|
|
- return 1; /* redrawing needed */
|
|
+ return true; /* redrawing needed */
|
|
}
|
|
|
|
static int mdacon_blank(struct vc_data *c, int blank, int mode_switch)
|
|
diff --git a/drivers/video/console/newport_con.c b/drivers/video/console/newport_con.c
|
|
index e8e4f82cd4a1b8..63d96c4bbdccd3 100644
|
|
--- a/drivers/video/console/newport_con.c
|
|
+++ b/drivers/video/console/newport_con.c
|
|
@@ -324,7 +324,7 @@ static const char *newport_startup(void)
|
|
return NULL;
|
|
}
|
|
|
|
-static void newport_init(struct vc_data *vc, int init)
|
|
+static void newport_init(struct vc_data *vc, bool init)
|
|
{
|
|
int cols, rows;
|
|
|
|
@@ -346,12 +346,12 @@ static void newport_deinit(struct vc_data *c)
|
|
}
|
|
}
|
|
|
|
-static void newport_clear(struct vc_data *vc, int sy, int sx, int height,
|
|
- int width)
|
|
+static void newport_clear(struct vc_data *vc, unsigned int sy, unsigned int sx,
|
|
+ unsigned int width)
|
|
{
|
|
int xend = ((sx + width) << 3) - 1;
|
|
int ystart = ((sy << 4) + topscan) & 0x3ff;
|
|
- int yend = (((sy + height) << 4) + topscan - 1) & 0x3ff;
|
|
+ int yend = (((sy + 1) << 4) + topscan - 1) & 0x3ff;
|
|
|
|
if (logo_active)
|
|
return;
|
|
@@ -462,7 +462,7 @@ static void newport_cursor(struct vc_data *vc, int mode)
|
|
}
|
|
}
|
|
|
|
-static int newport_switch(struct vc_data *vc)
|
|
+static bool newport_switch(struct vc_data *vc)
|
|
{
|
|
static int logo_drawn = 0;
|
|
|
|
@@ -476,7 +476,7 @@ static int newport_switch(struct vc_data *vc)
|
|
}
|
|
}
|
|
|
|
- return 1;
|
|
+ return true;
|
|
}
|
|
|
|
static int newport_blank(struct vc_data *c, int blank, int mode_switch)
|
|
diff --git a/drivers/video/console/sticon.c b/drivers/video/console/sticon.c
|
|
index 992a4fa431aaa9..87900600eff11f 100644
|
|
--- a/drivers/video/console/sticon.c
|
|
+++ b/drivers/video/console/sticon.c
|
|
@@ -273,7 +273,7 @@ static int sticon_font_set(struct vc_data *vc, struct console_font *font,
|
|
return sticon_set_font(vc, font, vpitch);
|
|
}
|
|
|
|
-static void sticon_init(struct vc_data *c, int init)
|
|
+static void sticon_init(struct vc_data *c, bool init)
|
|
{
|
|
struct sti_struct *sti = sticon_sti;
|
|
int vc_cols, vc_rows;
|
|
@@ -300,19 +300,19 @@ static void sticon_deinit(struct vc_data *c)
|
|
sticon_set_def_font(i);
|
|
}
|
|
|
|
-static void sticon_clear(struct vc_data *conp, int sy, int sx, int height,
|
|
- int width)
|
|
+static void sticon_clear(struct vc_data *conp, unsigned int sy, unsigned int sx,
|
|
+ unsigned int width)
|
|
{
|
|
- if (!height || !width)
|
|
+ if (!width)
|
|
return;
|
|
|
|
- sti_clear(sticon_sti, sy, sx, height, width,
|
|
+ sti_clear(sticon_sti, sy, sx, 1, width,
|
|
conp->vc_video_erase_char, font_data[conp->vc_num]);
|
|
}
|
|
|
|
-static int sticon_switch(struct vc_data *conp)
|
|
+static bool sticon_switch(struct vc_data *conp)
|
|
{
|
|
- return 1; /* needs refreshing */
|
|
+ return true; /* needs refreshing */
|
|
}
|
|
|
|
static int sticon_blank(struct vc_data *c, int blank, int mode_switch)
|
|
diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c
|
|
index c9ec89649b0552..bbc362db40c586 100644
|
|
--- a/drivers/video/console/vgacon.c
|
|
+++ b/drivers/video/console/vgacon.c
|
|
@@ -332,7 +332,7 @@ static const char *vgacon_startup(void)
|
|
return display_desc;
|
|
}
|
|
|
|
-static void vgacon_init(struct vc_data *c, int init)
|
|
+static void vgacon_init(struct vc_data *c, bool init)
|
|
{
|
|
struct uni_pagedict *p;
|
|
|
|
@@ -349,7 +349,7 @@ static void vgacon_init(struct vc_data *c, int init)
|
|
c->vc_scan_lines = vga_scan_lines;
|
|
c->vc_font.height = c->vc_cell_height = vga_video_font_height;
|
|
|
|
- /* set dimensions manually if init != 0 since vc_resize() will fail */
|
|
+ /* set dimensions manually if init is true since vc_resize() will fail */
|
|
if (init) {
|
|
c->vc_cols = vga_video_num_columns;
|
|
c->vc_rows = vga_video_num_lines;
|
|
@@ -585,7 +585,7 @@ static void vgacon_doresize(struct vc_data *c,
|
|
raw_spin_unlock_irqrestore(&vga_lock, flags);
|
|
}
|
|
|
|
-static int vgacon_switch(struct vc_data *c)
|
|
+static bool vgacon_switch(struct vc_data *c)
|
|
{
|
|
int x = c->vc_cols * VGA_FONTWIDTH;
|
|
int y = c->vc_rows * c->vc_cell_height;
|
|
@@ -614,7 +614,7 @@ static int vgacon_switch(struct vc_data *c)
|
|
vgacon_doresize(c, c->vc_cols, c->vc_rows);
|
|
}
|
|
|
|
- return 0; /* Redrawing not needed */
|
|
+ return false; /* Redrawing not needed */
|
|
}
|
|
|
|
static void vga_set_palette(struct vc_data *vc, const unsigned char *table)
|
|
@@ -1156,8 +1156,8 @@ static bool vgacon_scroll(struct vc_data *c, unsigned int t, unsigned int b,
|
|
* The console `switch' structure for the VGA based console
|
|
*/
|
|
|
|
-static void vgacon_clear(struct vc_data *vc, int sy, int sx, int height,
|
|
- int width) { }
|
|
+static void vgacon_clear(struct vc_data *vc, unsigned int sy, unsigned int sx,
|
|
+ unsigned int width) { }
|
|
static void vgacon_putc(struct vc_data *vc, int c, int ypos, int xpos) { }
|
|
static void vgacon_putcs(struct vc_data *vc, const unsigned short *s,
|
|
int count, int ypos, int xpos) { }
|
|
diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
|
|
index 75996ef9992e41..9d095fe03e18ba 100644
|
|
--- a/drivers/video/fbdev/core/fbcon.c
|
|
+++ b/drivers/video/fbdev/core/fbcon.c
|
|
@@ -993,7 +993,7 @@ static const char *fbcon_startup(void)
|
|
return display_desc;
|
|
}
|
|
|
|
-static void fbcon_init(struct vc_data *vc, int init)
|
|
+static void fbcon_init(struct vc_data *vc, bool init)
|
|
{
|
|
struct fb_info *info;
|
|
struct fbcon_ops *ops;
|
|
@@ -1240,8 +1240,8 @@ static void fbcon_deinit(struct vc_data *vc)
|
|
* restriction is simplicity & efficiency at the moment.
|
|
*/
|
|
|
|
-static void fbcon_clear(struct vc_data *vc, int sy, int sx, int height,
|
|
- int width)
|
|
+static void __fbcon_clear(struct vc_data *vc, unsigned int sy, unsigned int sx,
|
|
+ unsigned int height, unsigned int width)
|
|
{
|
|
struct fb_info *info = fbcon_info_from_console(vc->vc_num);
|
|
struct fbcon_ops *ops = info->fbcon_par;
|
|
@@ -1280,6 +1280,12 @@ static void fbcon_clear(struct vc_data *vc, int sy, int sx, int height,
|
|
ops->clear(vc, info, real_y(p, sy), sx, height, width, fg, bg);
|
|
}
|
|
|
|
+static void fbcon_clear(struct vc_data *vc, unsigned int sy, unsigned int sx,
|
|
+ unsigned int width)
|
|
+{
|
|
+ __fbcon_clear(vc, sy, sx, 1, width);
|
|
+}
|
|
+
|
|
static void fbcon_putcs(struct vc_data *vc, const unsigned short *s,
|
|
int count, int ypos, int xpos)
|
|
{
|
|
@@ -1767,7 +1773,7 @@ static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
|
|
case SCROLL_MOVE:
|
|
fbcon_redraw_blit(vc, info, p, t, b - t - count,
|
|
count);
|
|
- fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
|
|
+ __fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
|
|
scr_memsetw((unsigned short *) (vc->vc_origin +
|
|
vc->vc_size_row *
|
|
(b - count)),
|
|
@@ -1790,7 +1796,7 @@ static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
|
|
b - t - count, vc->vc_cols);
|
|
else
|
|
goto redraw_up;
|
|
- fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
|
|
+ __fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
|
|
break;
|
|
|
|
case SCROLL_PAN_REDRAW:
|
|
@@ -1808,7 +1814,7 @@ static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
|
|
vc->vc_rows - b, b);
|
|
} else
|
|
fbcon_redraw_move(vc, p, t + count, b - t - count, t);
|
|
- fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
|
|
+ __fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
|
|
break;
|
|
|
|
case SCROLL_PAN_MOVE:
|
|
@@ -1831,14 +1837,14 @@ static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
|
|
b - t - count, vc->vc_cols);
|
|
else
|
|
goto redraw_up;
|
|
- fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
|
|
+ __fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
|
|
break;
|
|
|
|
case SCROLL_REDRAW:
|
|
redraw_up:
|
|
fbcon_redraw(vc, t, b - t - count,
|
|
count * vc->vc_cols);
|
|
- fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
|
|
+ __fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
|
|
scr_memsetw((unsigned short *) (vc->vc_origin +
|
|
vc->vc_size_row *
|
|
(b - count)),
|
|
@@ -1855,7 +1861,7 @@ static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
|
|
case SCROLL_MOVE:
|
|
fbcon_redraw_blit(vc, info, p, b - 1, b - t - count,
|
|
-count);
|
|
- fbcon_clear(vc, t, 0, count, vc->vc_cols);
|
|
+ __fbcon_clear(vc, t, 0, count, vc->vc_cols);
|
|
scr_memsetw((unsigned short *) (vc->vc_origin +
|
|
vc->vc_size_row *
|
|
t),
|
|
@@ -1878,7 +1884,7 @@ static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
|
|
b - t - count, vc->vc_cols);
|
|
else
|
|
goto redraw_down;
|
|
- fbcon_clear(vc, t, 0, count, vc->vc_cols);
|
|
+ __fbcon_clear(vc, t, 0, count, vc->vc_cols);
|
|
break;
|
|
|
|
case SCROLL_PAN_MOVE:
|
|
@@ -1900,7 +1906,7 @@ static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
|
|
b - t - count, vc->vc_cols);
|
|
else
|
|
goto redraw_down;
|
|
- fbcon_clear(vc, t, 0, count, vc->vc_cols);
|
|
+ __fbcon_clear(vc, t, 0, count, vc->vc_cols);
|
|
break;
|
|
|
|
case SCROLL_PAN_REDRAW:
|
|
@@ -1917,14 +1923,14 @@ static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
|
|
fbcon_redraw_move(vc, p, count, t, 0);
|
|
} else
|
|
fbcon_redraw_move(vc, p, t, b - t - count, t + count);
|
|
- fbcon_clear(vc, t, 0, count, vc->vc_cols);
|
|
+ __fbcon_clear(vc, t, 0, count, vc->vc_cols);
|
|
break;
|
|
|
|
case SCROLL_REDRAW:
|
|
redraw_down:
|
|
fbcon_redraw(vc, b - 1, b - t - count,
|
|
-count * vc->vc_cols);
|
|
- fbcon_clear(vc, t, 0, count, vc->vc_cols);
|
|
+ __fbcon_clear(vc, t, 0, count, vc->vc_cols);
|
|
scr_memsetw((unsigned short *) (vc->vc_origin +
|
|
vc->vc_size_row *
|
|
t),
|
|
@@ -2066,7 +2072,7 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width,
|
|
return 0;
|
|
}
|
|
|
|
-static int fbcon_switch(struct vc_data *vc)
|
|
+static bool fbcon_switch(struct vc_data *vc)
|
|
{
|
|
struct fb_info *info, *old_info = NULL;
|
|
struct fbcon_ops *ops;
|
|
@@ -2188,9 +2194,9 @@ static int fbcon_switch(struct vc_data *vc)
|
|
vc->vc_origin + vc->vc_size_row * vc->vc_top,
|
|
vc->vc_size_row * (vc->vc_bottom -
|
|
vc->vc_top) / 2);
|
|
- return 0;
|
|
+ return false;
|
|
}
|
|
- return 1;
|
|
+ return true;
|
|
}
|
|
|
|
static void fbcon_generic_blank(struct vc_data *vc, struct fb_info *info,
|
|
@@ -2203,7 +2209,7 @@ static void fbcon_generic_blank(struct vc_data *vc, struct fb_info *info,
|
|
|
|
oldc = vc->vc_video_erase_char;
|
|
vc->vc_video_erase_char &= charmask;
|
|
- fbcon_clear(vc, 0, 0, vc->vc_rows, vc->vc_cols);
|
|
+ __fbcon_clear(vc, 0, 0, vc->vc_rows, vc->vc_cols);
|
|
vc->vc_video_erase_char = oldc;
|
|
}
|
|
}
|
|
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
|
|
index 34a30d61b470c3..bb5f7911d473cb 100644
|
|
--- a/fs/btrfs/disk-io.c
|
|
+++ b/fs/btrfs/disk-io.c
|
|
@@ -2148,8 +2148,7 @@ static int load_global_roots_objectid(struct btrfs_root *tree_root,
|
|
found = true;
|
|
root = read_tree_root_path(tree_root, path, &key);
|
|
if (IS_ERR(root)) {
|
|
- if (!btrfs_test_opt(fs_info, IGNOREBADROOTS))
|
|
- ret = PTR_ERR(root);
|
|
+ ret = PTR_ERR(root);
|
|
break;
|
|
}
|
|
set_bit(BTRFS_ROOT_TRACK_DIRTY, &root->state);
|
|
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
|
|
index 48d2579236729d..af1f22b3cff7dc 100644
|
|
--- a/fs/btrfs/inode.c
|
|
+++ b/fs/btrfs/inode.c
|
|
@@ -8754,6 +8754,7 @@ static int btrfs_rename_exchange(struct inode *old_dir,
|
|
int ret;
|
|
int ret2;
|
|
bool need_abort = false;
|
|
+ bool logs_pinned = false;
|
|
struct fscrypt_name old_fname, new_fname;
|
|
struct fscrypt_str *old_name, *new_name;
|
|
|
|
@@ -8877,6 +8878,31 @@ static int btrfs_rename_exchange(struct inode *old_dir,
|
|
inode_inc_iversion(new_inode);
|
|
simple_rename_timestamp(old_dir, old_dentry, new_dir, new_dentry);
|
|
|
|
+ if (old_ino != BTRFS_FIRST_FREE_OBJECTID &&
|
|
+ new_ino != BTRFS_FIRST_FREE_OBJECTID) {
|
|
+ /*
|
|
+ * If we are renaming in the same directory (and it's not for
|
|
+ * root entries) pin the log early to prevent any concurrent
|
|
+ * task from logging the directory after we removed the old
|
|
+ * entries and before we add the new entries, otherwise that
|
|
+ * task can sync a log without any entry for the inodes we are
|
|
+ * renaming and therefore replaying that log, if a power failure
|
|
+ * happens after syncing the log, would result in deleting the
|
|
+ * inodes.
|
|
+ *
|
|
+ * If the rename affects two different directories, we want to
|
|
+ * make sure the that there's no log commit that contains
|
|
+ * updates for only one of the directories but not for the
|
|
+ * other.
|
|
+ *
|
|
+ * If we are renaming an entry for a root, we don't care about
|
|
+ * log updates since we called btrfs_set_log_full_commit().
|
|
+ */
|
|
+ btrfs_pin_log_trans(root);
|
|
+ btrfs_pin_log_trans(dest);
|
|
+ logs_pinned = true;
|
|
+ }
|
|
+
|
|
if (old_dentry->d_parent != new_dentry->d_parent) {
|
|
btrfs_record_unlink_dir(trans, BTRFS_I(old_dir),
|
|
BTRFS_I(old_inode), true);
|
|
@@ -8934,30 +8960,23 @@ static int btrfs_rename_exchange(struct inode *old_dir,
|
|
BTRFS_I(new_inode)->dir_index = new_idx;
|
|
|
|
/*
|
|
- * Now pin the logs of the roots. We do it to ensure that no other task
|
|
- * can sync the logs while we are in progress with the rename, because
|
|
- * that could result in an inconsistency in case any of the inodes that
|
|
- * are part of this rename operation were logged before.
|
|
+ * Do the log updates for all inodes.
|
|
+ *
|
|
+ * If either entry is for a root we don't need to update the logs since
|
|
+ * we've called btrfs_set_log_full_commit() before.
|
|
*/
|
|
- if (old_ino != BTRFS_FIRST_FREE_OBJECTID)
|
|
- btrfs_pin_log_trans(root);
|
|
- if (new_ino != BTRFS_FIRST_FREE_OBJECTID)
|
|
- btrfs_pin_log_trans(dest);
|
|
-
|
|
- /* Do the log updates for all inodes. */
|
|
- if (old_ino != BTRFS_FIRST_FREE_OBJECTID)
|
|
+ if (logs_pinned) {
|
|
btrfs_log_new_name(trans, old_dentry, BTRFS_I(old_dir),
|
|
old_rename_ctx.index, new_dentry->d_parent);
|
|
- if (new_ino != BTRFS_FIRST_FREE_OBJECTID)
|
|
btrfs_log_new_name(trans, new_dentry, BTRFS_I(new_dir),
|
|
new_rename_ctx.index, old_dentry->d_parent);
|
|
+ }
|
|
|
|
- /* Now unpin the logs. */
|
|
- if (old_ino != BTRFS_FIRST_FREE_OBJECTID)
|
|
+out_fail:
|
|
+ if (logs_pinned) {
|
|
btrfs_end_log_trans(root);
|
|
- if (new_ino != BTRFS_FIRST_FREE_OBJECTID)
|
|
btrfs_end_log_trans(dest);
|
|
-out_fail:
|
|
+ }
|
|
ret2 = btrfs_end_transaction(trans);
|
|
ret = ret ? ret : ret2;
|
|
out_notrans:
|
|
@@ -9007,6 +9026,7 @@ static int btrfs_rename(struct mnt_idmap *idmap,
|
|
int ret2;
|
|
u64 old_ino = btrfs_ino(BTRFS_I(old_inode));
|
|
struct fscrypt_name old_fname, new_fname;
|
|
+ bool logs_pinned = false;
|
|
|
|
if (btrfs_ino(BTRFS_I(new_dir)) == BTRFS_EMPTY_SUBVOL_DIR_OBJECTID)
|
|
return -EPERM;
|
|
@@ -9141,6 +9161,29 @@ static int btrfs_rename(struct mnt_idmap *idmap,
|
|
inode_inc_iversion(old_inode);
|
|
simple_rename_timestamp(old_dir, old_dentry, new_dir, new_dentry);
|
|
|
|
+ if (old_ino != BTRFS_FIRST_FREE_OBJECTID) {
|
|
+ /*
|
|
+ * If we are renaming in the same directory (and it's not a
|
|
+ * root entry) pin the log to prevent any concurrent task from
|
|
+ * logging the directory after we removed the old entry and
|
|
+ * before we add the new entry, otherwise that task can sync
|
|
+ * a log without any entry for the inode we are renaming and
|
|
+ * therefore replaying that log, if a power failure happens
|
|
+ * after syncing the log, would result in deleting the inode.
|
|
+ *
|
|
+ * If the rename affects two different directories, we want to
|
|
+ * make sure the that there's no log commit that contains
|
|
+ * updates for only one of the directories but not for the
|
|
+ * other.
|
|
+ *
|
|
+ * If we are renaming an entry for a root, we don't care about
|
|
+ * log updates since we called btrfs_set_log_full_commit().
|
|
+ */
|
|
+ btrfs_pin_log_trans(root);
|
|
+ btrfs_pin_log_trans(dest);
|
|
+ logs_pinned = true;
|
|
+ }
|
|
+
|
|
if (old_dentry->d_parent != new_dentry->d_parent)
|
|
btrfs_record_unlink_dir(trans, BTRFS_I(old_dir),
|
|
BTRFS_I(old_inode), true);
|
|
@@ -9189,7 +9232,7 @@ static int btrfs_rename(struct mnt_idmap *idmap,
|
|
if (old_inode->i_nlink == 1)
|
|
BTRFS_I(old_inode)->dir_index = index;
|
|
|
|
- if (old_ino != BTRFS_FIRST_FREE_OBJECTID)
|
|
+ if (logs_pinned)
|
|
btrfs_log_new_name(trans, old_dentry, BTRFS_I(old_dir),
|
|
rename_ctx.index, new_dentry->d_parent);
|
|
|
|
@@ -9205,6 +9248,10 @@ static int btrfs_rename(struct mnt_idmap *idmap,
|
|
}
|
|
}
|
|
out_fail:
|
|
+ if (logs_pinned) {
|
|
+ btrfs_end_log_trans(root);
|
|
+ btrfs_end_log_trans(dest);
|
|
+ }
|
|
ret2 = btrfs_end_transaction(trans);
|
|
ret = ret ? ret : ret2;
|
|
out_notrans:
|
|
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
|
|
index b9a0b26d08e1c4..1eb543602ff12f 100644
|
|
--- a/fs/btrfs/volumes.c
|
|
+++ b/fs/btrfs/volumes.c
|
|
@@ -3174,6 +3174,12 @@ int btrfs_remove_chunk(struct btrfs_trans_handle *trans, u64 chunk_offset)
|
|
device->bytes_used - dev_extent_len);
|
|
atomic64_add(dev_extent_len, &fs_info->free_chunk_space);
|
|
btrfs_clear_space_info_full(fs_info);
|
|
+
|
|
+ if (list_empty(&device->post_commit_list)) {
|
|
+ list_add_tail(&device->post_commit_list,
|
|
+ &trans->transaction->dev_update_list);
|
|
+ }
|
|
+
|
|
mutex_unlock(&fs_info->chunk_mutex);
|
|
}
|
|
}
|
|
diff --git a/fs/ceph/file.c b/fs/ceph/file.c
|
|
index a03b11cf788721..e12657b4c3e042 100644
|
|
--- a/fs/ceph/file.c
|
|
+++ b/fs/ceph/file.c
|
|
@@ -2513,7 +2513,7 @@ static int ceph_zero_objects(struct inode *inode, loff_t offset, loff_t length)
|
|
s32 stripe_unit = ci->i_layout.stripe_unit;
|
|
s32 stripe_count = ci->i_layout.stripe_count;
|
|
s32 object_size = ci->i_layout.object_size;
|
|
- u64 object_set_size = object_size * stripe_count;
|
|
+ u64 object_set_size = (u64) object_size * stripe_count;
|
|
u64 nearly, t;
|
|
|
|
/* round offset up to next period boundary */
|
|
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
|
|
index 702137eafaa675..b9913ab526fd1a 100644
|
|
--- a/fs/f2fs/super.c
|
|
+++ b/fs/f2fs/super.c
|
|
@@ -1774,26 +1774,32 @@ static int f2fs_statfs_project(struct super_block *sb,
|
|
|
|
limit = min_not_zero(dquot->dq_dqb.dqb_bsoftlimit,
|
|
dquot->dq_dqb.dqb_bhardlimit);
|
|
- if (limit)
|
|
- limit >>= sb->s_blocksize_bits;
|
|
+ limit >>= sb->s_blocksize_bits;
|
|
+
|
|
+ if (limit) {
|
|
+ uint64_t remaining = 0;
|
|
|
|
- if (limit && buf->f_blocks > limit) {
|
|
curblock = (dquot->dq_dqb.dqb_curspace +
|
|
dquot->dq_dqb.dqb_rsvspace) >> sb->s_blocksize_bits;
|
|
- buf->f_blocks = limit;
|
|
- buf->f_bfree = buf->f_bavail =
|
|
- (buf->f_blocks > curblock) ?
|
|
- (buf->f_blocks - curblock) : 0;
|
|
+ if (limit > curblock)
|
|
+ remaining = limit - curblock;
|
|
+
|
|
+ buf->f_blocks = min(buf->f_blocks, limit);
|
|
+ buf->f_bfree = min(buf->f_bfree, remaining);
|
|
+ buf->f_bavail = min(buf->f_bavail, remaining);
|
|
}
|
|
|
|
limit = min_not_zero(dquot->dq_dqb.dqb_isoftlimit,
|
|
dquot->dq_dqb.dqb_ihardlimit);
|
|
|
|
- if (limit && buf->f_files > limit) {
|
|
- buf->f_files = limit;
|
|
- buf->f_ffree =
|
|
- (buf->f_files > dquot->dq_dqb.dqb_curinodes) ?
|
|
- (buf->f_files - dquot->dq_dqb.dqb_curinodes) : 0;
|
|
+ if (limit) {
|
|
+ uint64_t remaining = 0;
|
|
+
|
|
+ if (limit > dquot->dq_dqb.dqb_curinodes)
|
|
+ remaining = limit - dquot->dq_dqb.dqb_curinodes;
|
|
+
|
|
+ buf->f_files = min(buf->f_files, limit);
|
|
+ buf->f_ffree = min(buf->f_ffree, remaining);
|
|
}
|
|
|
|
spin_unlock(&dquot->dq_dqb_lock);
|
|
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
|
|
index 82951a535d2d4d..0b84284ece98fa 100644
|
|
--- a/fs/fuse/dir.c
|
|
+++ b/fs/fuse/dir.c
|
|
@@ -1860,6 +1860,7 @@ int fuse_do_setattr(struct dentry *dentry, struct iattr *attr,
|
|
int err;
|
|
bool trust_local_cmtime = is_wb;
|
|
bool fault_blocked = false;
|
|
+ u64 attr_version;
|
|
|
|
if (!fc->default_permissions)
|
|
attr->ia_valid |= ATTR_FORCE;
|
|
@@ -1944,6 +1945,8 @@ int fuse_do_setattr(struct dentry *dentry, struct iattr *attr,
|
|
if (fc->handle_killpriv_v2 && !capable(CAP_FSETID))
|
|
inarg.valid |= FATTR_KILL_SUIDGID;
|
|
}
|
|
+
|
|
+ attr_version = fuse_get_attr_version(fm->fc);
|
|
fuse_setattr_fill(fc, &args, inode, &inarg, &outarg);
|
|
err = fuse_simple_request(fm, &args);
|
|
if (err) {
|
|
@@ -1969,6 +1972,14 @@ int fuse_do_setattr(struct dentry *dentry, struct iattr *attr,
|
|
/* FIXME: clear I_DIRTY_SYNC? */
|
|
}
|
|
|
|
+ if (fi->attr_version > attr_version) {
|
|
+ /*
|
|
+ * Apply attributes, for example for fsnotify_change(), but set
|
|
+ * attribute timeout to zero.
|
|
+ */
|
|
+ outarg.attr_valid = outarg.attr_valid_nsec = 0;
|
|
+ }
|
|
+
|
|
fuse_change_attributes_common(inode, &outarg.attr, NULL,
|
|
ATTR_TIMEOUT(&outarg),
|
|
fuse_get_cache_mask(inode));
|
|
diff --git a/fs/jfs/jfs_dmap.c b/fs/jfs/jfs_dmap.c
|
|
index 0e1019382cf519..35e063c9f3a42e 100644
|
|
--- a/fs/jfs/jfs_dmap.c
|
|
+++ b/fs/jfs/jfs_dmap.c
|
|
@@ -178,45 +178,30 @@ int dbMount(struct inode *ipbmap)
|
|
dbmp_le = (struct dbmap_disk *) mp->data;
|
|
bmp->db_mapsize = le64_to_cpu(dbmp_le->dn_mapsize);
|
|
bmp->db_nfree = le64_to_cpu(dbmp_le->dn_nfree);
|
|
-
|
|
bmp->db_l2nbperpage = le32_to_cpu(dbmp_le->dn_l2nbperpage);
|
|
- if (bmp->db_l2nbperpage > L2PSIZE - L2MINBLOCKSIZE ||
|
|
- bmp->db_l2nbperpage < 0) {
|
|
- err = -EINVAL;
|
|
- goto err_release_metapage;
|
|
- }
|
|
-
|
|
bmp->db_numag = le32_to_cpu(dbmp_le->dn_numag);
|
|
- if (!bmp->db_numag || bmp->db_numag > MAXAG) {
|
|
- err = -EINVAL;
|
|
- goto err_release_metapage;
|
|
- }
|
|
-
|
|
bmp->db_maxlevel = le32_to_cpu(dbmp_le->dn_maxlevel);
|
|
bmp->db_maxag = le32_to_cpu(dbmp_le->dn_maxag);
|
|
bmp->db_agpref = le32_to_cpu(dbmp_le->dn_agpref);
|
|
- if (bmp->db_maxag >= MAXAG || bmp->db_maxag < 0 ||
|
|
- bmp->db_agpref >= MAXAG || bmp->db_agpref < 0) {
|
|
- err = -EINVAL;
|
|
- goto err_release_metapage;
|
|
- }
|
|
-
|
|
bmp->db_aglevel = le32_to_cpu(dbmp_le->dn_aglevel);
|
|
bmp->db_agheight = le32_to_cpu(dbmp_le->dn_agheight);
|
|
bmp->db_agwidth = le32_to_cpu(dbmp_le->dn_agwidth);
|
|
- if (!bmp->db_agwidth) {
|
|
- err = -EINVAL;
|
|
- goto err_release_metapage;
|
|
- }
|
|
bmp->db_agstart = le32_to_cpu(dbmp_le->dn_agstart);
|
|
bmp->db_agl2size = le32_to_cpu(dbmp_le->dn_agl2size);
|
|
- if (bmp->db_agl2size > L2MAXL2SIZE - L2MAXAG ||
|
|
- bmp->db_agl2size < 0) {
|
|
- err = -EINVAL;
|
|
- goto err_release_metapage;
|
|
- }
|
|
|
|
- if (((bmp->db_mapsize - 1) >> bmp->db_agl2size) > MAXAG) {
|
|
+ if ((bmp->db_l2nbperpage > L2PSIZE - L2MINBLOCKSIZE) ||
|
|
+ (bmp->db_l2nbperpage < 0) ||
|
|
+ !bmp->db_numag || (bmp->db_numag > MAXAG) ||
|
|
+ (bmp->db_maxag >= MAXAG) || (bmp->db_maxag < 0) ||
|
|
+ (bmp->db_agpref >= MAXAG) || (bmp->db_agpref < 0) ||
|
|
+ (bmp->db_agheight < 0) || (bmp->db_agheight > (L2LPERCTL >> 1)) ||
|
|
+ (bmp->db_agwidth < 1) || (bmp->db_agwidth > (LPERCTL / MAXAG)) ||
|
|
+ (bmp->db_agwidth > (1 << (L2LPERCTL - (bmp->db_agheight << 1)))) ||
|
|
+ (bmp->db_agstart < 0) ||
|
|
+ (bmp->db_agstart > (CTLTREESIZE - 1 - bmp->db_agwidth * (MAXAG - 1))) ||
|
|
+ (bmp->db_agl2size > L2MAXL2SIZE - L2MAXAG) ||
|
|
+ (bmp->db_agl2size < 0) ||
|
|
+ ((bmp->db_mapsize - 1) >> bmp->db_agl2size) > MAXAG) {
|
|
err = -EINVAL;
|
|
goto err_release_metapage;
|
|
}
|
|
diff --git a/fs/namespace.c b/fs/namespace.c
|
|
index eab9185e228584..cebcb9fa2acc07 100644
|
|
--- a/fs/namespace.c
|
|
+++ b/fs/namespace.c
|
|
@@ -2364,14 +2364,14 @@ static int attach_recursive_mnt(struct mount *source_mnt,
|
|
hlist_for_each_entry_safe(child, n, &tree_list, mnt_hash) {
|
|
struct mount *q;
|
|
hlist_del_init(&child->mnt_hash);
|
|
- q = __lookup_mnt(&child->mnt_parent->mnt,
|
|
- child->mnt_mountpoint);
|
|
- if (q)
|
|
- mnt_change_mountpoint(child, smp, q);
|
|
/* Notice when we are propagating across user namespaces */
|
|
if (child->mnt_parent->mnt_ns->user_ns != user_ns)
|
|
lock_mnt_tree(child);
|
|
child->mnt.mnt_flags &= ~MNT_LOCKED;
|
|
+ q = __lookup_mnt(&child->mnt_parent->mnt,
|
|
+ child->mnt_mountpoint);
|
|
+ if (q)
|
|
+ mnt_change_mountpoint(child, smp, q);
|
|
commit_tree(child);
|
|
}
|
|
put_mountpoint(smp);
|
|
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
|
|
index 06230baaa554e7..419d98cf9e29f1 100644
|
|
--- a/fs/nfs/inode.c
|
|
+++ b/fs/nfs/inode.c
|
|
@@ -555,6 +555,8 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
|
|
set_nlink(inode, fattr->nlink);
|
|
else if (fattr_supported & NFS_ATTR_FATTR_NLINK)
|
|
nfs_set_cache_invalid(inode, NFS_INO_INVALID_NLINK);
|
|
+ else
|
|
+ set_nlink(inode, 1);
|
|
if (fattr->valid & NFS_ATTR_FATTR_OWNER)
|
|
inode->i_uid = fattr->uid;
|
|
else if (fattr_supported & NFS_ATTR_FATTR_OWNER)
|
|
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
|
|
index 1b94a55215e7de..3085a2faab2d34 100644
|
|
--- a/fs/nfs/nfs4proc.c
|
|
+++ b/fs/nfs/nfs4proc.c
|
|
@@ -6059,6 +6059,8 @@ static ssize_t nfs4_proc_get_acl(struct inode *inode, void *buf, size_t buflen,
|
|
struct nfs_server *server = NFS_SERVER(inode);
|
|
int ret;
|
|
|
|
+ if (unlikely(NFS_FH(inode)->size == 0))
|
|
+ return -ENODATA;
|
|
if (!nfs4_server_supports_acls(server, type))
|
|
return -EOPNOTSUPP;
|
|
ret = nfs_revalidate_inode(inode, NFS_INO_INVALID_CHANGE);
|
|
@@ -6133,6 +6135,9 @@ static int nfs4_proc_set_acl(struct inode *inode, const void *buf,
|
|
{
|
|
struct nfs4_exception exception = { };
|
|
int err;
|
|
+
|
|
+ if (unlikely(NFS_FH(inode)->size == 0))
|
|
+ return -ENODATA;
|
|
do {
|
|
err = __nfs4_proc_set_acl(inode, buf, buflen, type);
|
|
trace_nfs4_set_acl(inode, err);
|
|
@@ -10625,7 +10630,7 @@ const struct nfs4_minor_version_ops *nfs_v4_minor_ops[] = {
|
|
|
|
static ssize_t nfs4_listxattr(struct dentry *dentry, char *list, size_t size)
|
|
{
|
|
- ssize_t error, error2, error3;
|
|
+ ssize_t error, error2, error3, error4;
|
|
size_t left = size;
|
|
|
|
error = generic_listxattr(dentry, list, left);
|
|
@@ -10648,8 +10653,16 @@ static ssize_t nfs4_listxattr(struct dentry *dentry, char *list, size_t size)
|
|
error3 = nfs4_listxattr_nfs4_user(d_inode(dentry), list, left);
|
|
if (error3 < 0)
|
|
return error3;
|
|
+ if (list) {
|
|
+ list += error3;
|
|
+ left -= error3;
|
|
+ }
|
|
+
|
|
+ error4 = security_inode_listsecurity(d_inode(dentry), list, left);
|
|
+ if (error4 < 0)
|
|
+ return error4;
|
|
|
|
- error += error2 + error3;
|
|
+ error += error2 + error3 + error4;
|
|
if (size && error > size)
|
|
return -ERANGE;
|
|
return error;
|
|
diff --git a/fs/overlayfs/util.c b/fs/overlayfs/util.c
|
|
index 0bf3ffcd072f6a..0da1cd01d01cf7 100644
|
|
--- a/fs/overlayfs/util.c
|
|
+++ b/fs/overlayfs/util.c
|
|
@@ -274,7 +274,9 @@ enum ovl_path_type ovl_path_realdata(struct dentry *dentry, struct path *path)
|
|
|
|
struct dentry *ovl_dentry_upper(struct dentry *dentry)
|
|
{
|
|
- return ovl_upperdentry_dereference(OVL_I(d_inode(dentry)));
|
|
+ struct inode *inode = d_inode(dentry);
|
|
+
|
|
+ return inode ? ovl_upperdentry_dereference(OVL_I(inode)) : NULL;
|
|
}
|
|
|
|
struct dentry *ovl_dentry_lower(struct dentry *dentry)
|
|
diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h
|
|
index 6a4ed99e162c5d..d776340ad91ce6 100644
|
|
--- a/fs/smb/client/cifsglob.h
|
|
+++ b/fs/smb/client/cifsglob.h
|
|
@@ -677,6 +677,7 @@ inc_rfc1001_len(void *buf, int count)
|
|
struct TCP_Server_Info {
|
|
struct list_head tcp_ses_list;
|
|
struct list_head smb_ses_list;
|
|
+ struct list_head rlist; /* reconnect list */
|
|
spinlock_t srv_lock; /* protect anything here that is not protected */
|
|
__u64 conn_id; /* connection identifier (useful for debugging) */
|
|
int srv_count; /* reference counter */
|
|
@@ -739,6 +740,7 @@ struct TCP_Server_Info {
|
|
char workstation_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL];
|
|
__u32 sequence_number; /* for signing, protected by srv_mutex */
|
|
__u32 reconnect_instance; /* incremented on each reconnect */
|
|
+ __le32 session_key_id; /* retrieved from negotiate response and send in session setup request */
|
|
struct session_key session_key;
|
|
unsigned long lstrp; /* when we got last response from this server */
|
|
struct cifs_secmech secmech; /* crypto sec mech functs, descriptors */
|
|
diff --git a/fs/smb/client/cifspdu.h b/fs/smb/client/cifspdu.h
|
|
index ca33f6cd6a8004..763178b7745424 100644
|
|
--- a/fs/smb/client/cifspdu.h
|
|
+++ b/fs/smb/client/cifspdu.h
|
|
@@ -557,7 +557,7 @@ typedef union smb_com_session_setup_andx {
|
|
__le16 MaxBufferSize;
|
|
__le16 MaxMpxCount;
|
|
__le16 VcNumber;
|
|
- __u32 SessionKey;
|
|
+ __le32 SessionKey;
|
|
__le16 SecurityBlobLength;
|
|
__u32 Reserved;
|
|
__le32 Capabilities; /* see below */
|
|
@@ -576,7 +576,7 @@ typedef union smb_com_session_setup_andx {
|
|
__le16 MaxBufferSize;
|
|
__le16 MaxMpxCount;
|
|
__le16 VcNumber;
|
|
- __u32 SessionKey;
|
|
+ __le32 SessionKey;
|
|
__le16 CaseInsensitivePasswordLength; /* ASCII password len */
|
|
__le16 CaseSensitivePasswordLength; /* Unicode password length*/
|
|
__u32 Reserved; /* see below */
|
|
@@ -614,7 +614,7 @@ typedef union smb_com_session_setup_andx {
|
|
__le16 MaxBufferSize;
|
|
__le16 MaxMpxCount;
|
|
__le16 VcNumber;
|
|
- __u32 SessionKey;
|
|
+ __le32 SessionKey;
|
|
__le16 PasswordLength;
|
|
__u32 Reserved; /* encrypt key len and offset */
|
|
__le16 ByteCount;
|
|
diff --git a/fs/smb/client/cifssmb.c b/fs/smb/client/cifssmb.c
|
|
index c36ab20050c16d..db35e68e8a5830 100644
|
|
--- a/fs/smb/client/cifssmb.c
|
|
+++ b/fs/smb/client/cifssmb.c
|
|
@@ -479,6 +479,7 @@ CIFSSMBNegotiate(const unsigned int xid,
|
|
server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
|
|
cifs_dbg(NOISY, "Max buf = %d\n", ses->server->maxBuf);
|
|
server->capabilities = le32_to_cpu(pSMBr->Capabilities);
|
|
+ server->session_key_id = pSMBr->SessionKey;
|
|
server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
|
|
server->timeAdj *= 60;
|
|
|
|
diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c
|
|
index 8fa5fe0a8c5c59..454420aa02220f 100644
|
|
--- a/fs/smb/client/connect.c
|
|
+++ b/fs/smb/client/connect.c
|
|
@@ -140,6 +140,14 @@ static void smb2_query_server_interfaces(struct work_struct *work)
|
|
(SMB_INTERFACE_POLL_INTERVAL * HZ));
|
|
}
|
|
|
|
+#define set_need_reco(server) \
|
|
+do { \
|
|
+ spin_lock(&server->srv_lock); \
|
|
+ if (server->tcpStatus != CifsExiting) \
|
|
+ server->tcpStatus = CifsNeedReconnect; \
|
|
+ spin_unlock(&server->srv_lock); \
|
|
+} while (0)
|
|
+
|
|
/*
|
|
* Update the tcpStatus for the server.
|
|
* This is used to signal the cifsd thread to call cifs_reconnect
|
|
@@ -153,39 +161,45 @@ void
|
|
cifs_signal_cifsd_for_reconnect(struct TCP_Server_Info *server,
|
|
bool all_channels)
|
|
{
|
|
- struct TCP_Server_Info *pserver;
|
|
+ struct TCP_Server_Info *nserver;
|
|
struct cifs_ses *ses;
|
|
+ LIST_HEAD(reco);
|
|
int i;
|
|
|
|
- /* If server is a channel, select the primary channel */
|
|
- pserver = SERVER_IS_CHAN(server) ? server->primary_server : server;
|
|
-
|
|
/* if we need to signal just this channel */
|
|
if (!all_channels) {
|
|
- spin_lock(&server->srv_lock);
|
|
- if (server->tcpStatus != CifsExiting)
|
|
- server->tcpStatus = CifsNeedReconnect;
|
|
- spin_unlock(&server->srv_lock);
|
|
+ set_need_reco(server);
|
|
return;
|
|
}
|
|
|
|
- spin_lock(&cifs_tcp_ses_lock);
|
|
- list_for_each_entry(ses, &pserver->smb_ses_list, smb_ses_list) {
|
|
- if (cifs_ses_exiting(ses))
|
|
- continue;
|
|
- spin_lock(&ses->chan_lock);
|
|
- for (i = 0; i < ses->chan_count; i++) {
|
|
- if (!ses->chans[i].server)
|
|
+ if (SERVER_IS_CHAN(server))
|
|
+ server = server->primary_server;
|
|
+ scoped_guard(spinlock, &cifs_tcp_ses_lock) {
|
|
+ set_need_reco(server);
|
|
+ list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
|
|
+ spin_lock(&ses->ses_lock);
|
|
+ if (ses->ses_status == SES_EXITING) {
|
|
+ spin_unlock(&ses->ses_lock);
|
|
continue;
|
|
-
|
|
- spin_lock(&ses->chans[i].server->srv_lock);
|
|
- if (ses->chans[i].server->tcpStatus != CifsExiting)
|
|
- ses->chans[i].server->tcpStatus = CifsNeedReconnect;
|
|
- spin_unlock(&ses->chans[i].server->srv_lock);
|
|
+ }
|
|
+ spin_lock(&ses->chan_lock);
|
|
+ for (i = 1; i < ses->chan_count; i++) {
|
|
+ nserver = ses->chans[i].server;
|
|
+ if (!nserver)
|
|
+ continue;
|
|
+ nserver->srv_count++;
|
|
+ list_add(&nserver->rlist, &reco);
|
|
+ }
|
|
+ spin_unlock(&ses->chan_lock);
|
|
+ spin_unlock(&ses->ses_lock);
|
|
}
|
|
- spin_unlock(&ses->chan_lock);
|
|
}
|
|
- spin_unlock(&cifs_tcp_ses_lock);
|
|
+
|
|
+ list_for_each_entry_safe(server, nserver, &reco, rlist) {
|
|
+ list_del_init(&server->rlist);
|
|
+ set_need_reco(server);
|
|
+ cifs_put_tcp_session(server, 0);
|
|
+ }
|
|
}
|
|
|
|
/*
|
|
diff --git a/fs/smb/client/misc.c b/fs/smb/client/misc.c
|
|
index 65d4b72b4d51a9..9e8e0a01ae8eb0 100644
|
|
--- a/fs/smb/client/misc.c
|
|
+++ b/fs/smb/client/misc.c
|
|
@@ -320,6 +320,14 @@ check_smb_hdr(struct smb_hdr *smb)
|
|
if (smb->Command == SMB_COM_LOCKING_ANDX)
|
|
return 0;
|
|
|
|
+ /*
|
|
+ * Windows NT server returns error resposne (e.g. STATUS_DELETE_PENDING
|
|
+ * or STATUS_OBJECT_NAME_NOT_FOUND or ERRDOS/ERRbadfile or any other)
|
|
+ * for some TRANS2 requests without the RESPONSE flag set in header.
|
|
+ */
|
|
+ if (smb->Command == SMB_COM_TRANSACTION2 && smb->Status.CifsError != 0)
|
|
+ return 0;
|
|
+
|
|
cifs_dbg(VFS, "Server sent request, not response. mid=%u\n",
|
|
get_mid(smb));
|
|
return 1;
|
|
diff --git a/fs/smb/client/sess.c b/fs/smb/client/sess.c
|
|
index 8959206a0353eb..c351da8c3e2eaf 100644
|
|
--- a/fs/smb/client/sess.c
|
|
+++ b/fs/smb/client/sess.c
|
|
@@ -683,6 +683,7 @@ static __u32 cifs_ssetup_hdr(struct cifs_ses *ses,
|
|
USHRT_MAX));
|
|
pSMB->req.MaxMpxCount = cpu_to_le16(server->maxReq);
|
|
pSMB->req.VcNumber = cpu_to_le16(1);
|
|
+ pSMB->req.SessionKey = server->session_key_id;
|
|
|
|
/* Now no need to set SMBFLG_CASELESS or obsolete CANONICAL PATH */
|
|
|
|
@@ -1739,22 +1740,22 @@ _sess_auth_rawntlmssp_assemble_req(struct sess_data *sess_data)
|
|
pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base;
|
|
|
|
capabilities = cifs_ssetup_hdr(ses, server, pSMB);
|
|
- if ((pSMB->req.hdr.Flags2 & SMBFLG2_UNICODE) == 0) {
|
|
- cifs_dbg(VFS, "NTLMSSP requires Unicode support\n");
|
|
- return -ENOSYS;
|
|
- }
|
|
-
|
|
pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
|
|
capabilities |= CAP_EXTENDED_SECURITY;
|
|
pSMB->req.Capabilities |= cpu_to_le32(capabilities);
|
|
|
|
bcc_ptr = sess_data->iov[2].iov_base;
|
|
- /* unicode strings must be word aligned */
|
|
- if (!IS_ALIGNED(sess_data->iov[0].iov_len + sess_data->iov[1].iov_len, 2)) {
|
|
- *bcc_ptr = 0;
|
|
- bcc_ptr++;
|
|
+
|
|
+ if (pSMB->req.hdr.Flags2 & SMBFLG2_UNICODE) {
|
|
+ /* unicode strings must be word aligned */
|
|
+ if (!IS_ALIGNED(sess_data->iov[0].iov_len + sess_data->iov[1].iov_len, 2)) {
|
|
+ *bcc_ptr = 0;
|
|
+ bcc_ptr++;
|
|
+ }
|
|
+ unicode_oslm_strings(&bcc_ptr, sess_data->nls_cp);
|
|
+ } else {
|
|
+ ascii_oslm_strings(&bcc_ptr, sess_data->nls_cp);
|
|
}
|
|
- unicode_oslm_strings(&bcc_ptr, sess_data->nls_cp);
|
|
|
|
sess_data->iov[2].iov_len = (long) bcc_ptr -
|
|
(long) sess_data->iov[2].iov_base;
|
|
diff --git a/fs/smb/server/connection.h b/fs/smb/server/connection.h
|
|
index 4fdd76ce53b90c..dc07c6eb8c1921 100644
|
|
--- a/fs/smb/server/connection.h
|
|
+++ b/fs/smb/server/connection.h
|
|
@@ -107,6 +107,7 @@ struct ksmbd_conn {
|
|
__le16 signing_algorithm;
|
|
bool binding;
|
|
atomic_t refcnt;
|
|
+ bool is_aapl;
|
|
};
|
|
|
|
struct ksmbd_conn_ops {
|
|
diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
|
|
index d8325504a1624b..6c22240368abf4 100644
|
|
--- a/fs/smb/server/smb2pdu.c
|
|
+++ b/fs/smb/server/smb2pdu.c
|
|
@@ -1345,8 +1345,7 @@ static int ntlm_negotiate(struct ksmbd_work *work,
|
|
return rc;
|
|
|
|
sz = le16_to_cpu(rsp->SecurityBufferOffset);
|
|
- chgblob =
|
|
- (struct challenge_message *)((char *)&rsp->hdr.ProtocolId + sz);
|
|
+ chgblob = (struct challenge_message *)rsp->Buffer;
|
|
memset(chgblob, 0, sizeof(struct challenge_message));
|
|
|
|
if (!work->conn->use_spnego) {
|
|
@@ -1379,8 +1378,7 @@ static int ntlm_negotiate(struct ksmbd_work *work,
|
|
goto out;
|
|
}
|
|
|
|
- sz = le16_to_cpu(rsp->SecurityBufferOffset);
|
|
- memcpy((char *)&rsp->hdr.ProtocolId + sz, spnego_blob, spnego_blob_len);
|
|
+ memcpy(rsp->Buffer, spnego_blob, spnego_blob_len);
|
|
rsp->SecurityBufferLength = cpu_to_le16(spnego_blob_len);
|
|
|
|
out:
|
|
@@ -1462,8 +1460,7 @@ static int ntlm_authenticate(struct ksmbd_work *work,
|
|
if (rc)
|
|
return -ENOMEM;
|
|
|
|
- sz = le16_to_cpu(rsp->SecurityBufferOffset);
|
|
- memcpy((char *)&rsp->hdr.ProtocolId + sz, spnego_blob, spnego_blob_len);
|
|
+ memcpy(rsp->Buffer, spnego_blob, spnego_blob_len);
|
|
rsp->SecurityBufferLength = cpu_to_le16(spnego_blob_len);
|
|
kfree(spnego_blob);
|
|
}
|
|
@@ -2862,7 +2859,7 @@ int smb2_open(struct ksmbd_work *work)
|
|
int req_op_level = 0, open_flags = 0, may_flags = 0, file_info = 0;
|
|
int rc = 0;
|
|
int contxt_cnt = 0, query_disk_id = 0;
|
|
- int maximal_access_ctxt = 0, posix_ctxt = 0;
|
|
+ bool maximal_access_ctxt = false, posix_ctxt = false;
|
|
int s_type = 0;
|
|
int next_off = 0;
|
|
char *name = NULL;
|
|
@@ -2889,6 +2886,27 @@ int smb2_open(struct ksmbd_work *work)
|
|
return create_smb2_pipe(work);
|
|
}
|
|
|
|
+ if (req->CreateContextsOffset && tcon->posix_extensions) {
|
|
+ context = smb2_find_context_vals(req, SMB2_CREATE_TAG_POSIX, 16);
|
|
+ if (IS_ERR(context)) {
|
|
+ rc = PTR_ERR(context);
|
|
+ goto err_out2;
|
|
+ } else if (context) {
|
|
+ struct create_posix *posix = (struct create_posix *)context;
|
|
+
|
|
+ if (le16_to_cpu(context->DataOffset) +
|
|
+ le32_to_cpu(context->DataLength) <
|
|
+ sizeof(struct create_posix) - 4) {
|
|
+ rc = -EINVAL;
|
|
+ goto err_out2;
|
|
+ }
|
|
+ ksmbd_debug(SMB, "get posix context\n");
|
|
+
|
|
+ posix_mode = le32_to_cpu(posix->Mode);
|
|
+ posix_ctxt = true;
|
|
+ }
|
|
+ }
|
|
+
|
|
if (req->NameLength) {
|
|
name = smb2_get_name((char *)req + le16_to_cpu(req->NameOffset),
|
|
le16_to_cpu(req->NameLength),
|
|
@@ -2911,9 +2929,11 @@ int smb2_open(struct ksmbd_work *work)
|
|
goto err_out2;
|
|
}
|
|
|
|
- rc = ksmbd_validate_filename(name);
|
|
- if (rc < 0)
|
|
- goto err_out2;
|
|
+ if (posix_ctxt == false) {
|
|
+ rc = ksmbd_validate_filename(name);
|
|
+ if (rc < 0)
|
|
+ goto err_out2;
|
|
+ }
|
|
|
|
if (ksmbd_share_veto_filename(share, name)) {
|
|
rc = -ENOENT;
|
|
@@ -3071,28 +3091,6 @@ int smb2_open(struct ksmbd_work *work)
|
|
rc = -EBADF;
|
|
goto err_out2;
|
|
}
|
|
-
|
|
- if (tcon->posix_extensions) {
|
|
- context = smb2_find_context_vals(req,
|
|
- SMB2_CREATE_TAG_POSIX, 16);
|
|
- if (IS_ERR(context)) {
|
|
- rc = PTR_ERR(context);
|
|
- goto err_out2;
|
|
- } else if (context) {
|
|
- struct create_posix *posix =
|
|
- (struct create_posix *)context;
|
|
- if (le16_to_cpu(context->DataOffset) +
|
|
- le32_to_cpu(context->DataLength) <
|
|
- sizeof(struct create_posix) - 4) {
|
|
- rc = -EINVAL;
|
|
- goto err_out2;
|
|
- }
|
|
- ksmbd_debug(SMB, "get posix context\n");
|
|
-
|
|
- posix_mode = le32_to_cpu(posix->Mode);
|
|
- posix_ctxt = 1;
|
|
- }
|
|
- }
|
|
}
|
|
|
|
if (ksmbd_override_fsids(work)) {
|
|
@@ -3526,6 +3524,15 @@ int smb2_open(struct ksmbd_work *work)
|
|
ksmbd_debug(SMB, "get query on disk id context\n");
|
|
query_disk_id = 1;
|
|
}
|
|
+
|
|
+ if (conn->is_aapl == false) {
|
|
+ context = smb2_find_context_vals(req, SMB2_CREATE_AAPL, 4);
|
|
+ if (IS_ERR(context)) {
|
|
+ rc = PTR_ERR(context);
|
|
+ goto err_out1;
|
|
+ } else if (context)
|
|
+ conn->is_aapl = true;
|
|
+ }
|
|
}
|
|
|
|
rc = ksmbd_vfs_getattr(&path, &stat);
|
|
@@ -3964,7 +3971,10 @@ static int smb2_populate_readdir_entry(struct ksmbd_conn *conn, int info_level,
|
|
if (dinfo->EaSize)
|
|
dinfo->ExtFileAttributes = FILE_ATTRIBUTE_REPARSE_POINT_LE;
|
|
dinfo->Reserved = 0;
|
|
- dinfo->UniqueId = cpu_to_le64(ksmbd_kstat->kstat->ino);
|
|
+ if (conn->is_aapl)
|
|
+ dinfo->UniqueId = 0;
|
|
+ else
|
|
+ dinfo->UniqueId = cpu_to_le64(ksmbd_kstat->kstat->ino);
|
|
if (d_info->hide_dot_file && d_info->name[0] == '.')
|
|
dinfo->ExtFileAttributes |= FILE_ATTRIBUTE_HIDDEN_LE;
|
|
memcpy(dinfo->FileName, conv_name, conv_len);
|
|
@@ -3981,7 +3991,10 @@ static int smb2_populate_readdir_entry(struct ksmbd_conn *conn, int info_level,
|
|
smb2_get_reparse_tag_special_file(ksmbd_kstat->kstat->mode);
|
|
if (fibdinfo->EaSize)
|
|
fibdinfo->ExtFileAttributes = FILE_ATTRIBUTE_REPARSE_POINT_LE;
|
|
- fibdinfo->UniqueId = cpu_to_le64(ksmbd_kstat->kstat->ino);
|
|
+ if (conn->is_aapl)
|
|
+ fibdinfo->UniqueId = 0;
|
|
+ else
|
|
+ fibdinfo->UniqueId = cpu_to_le64(ksmbd_kstat->kstat->ino);
|
|
fibdinfo->ShortNameLength = 0;
|
|
fibdinfo->Reserved = 0;
|
|
fibdinfo->Reserved2 = cpu_to_le16(0);
|
|
diff --git a/fs/smb/server/smb2pdu.h b/fs/smb/server/smb2pdu.h
|
|
index 25cc81aac350f2..2821e6c8298f4d 100644
|
|
--- a/fs/smb/server/smb2pdu.h
|
|
+++ b/fs/smb/server/smb2pdu.h
|
|
@@ -63,6 +63,9 @@ struct preauth_integrity_info {
|
|
|
|
#define SMB2_SESSION_TIMEOUT (10 * HZ)
|
|
|
|
+/* Apple Defined Contexts */
|
|
+#define SMB2_CREATE_AAPL "AAPL"
|
|
+
|
|
struct create_durable_req_v2 {
|
|
struct create_context_hdr ccontext;
|
|
__u8 Name[8];
|
|
diff --git a/include/linux/console.h b/include/linux/console.h
|
|
index 7de11c763eb35d..38571607065d76 100644
|
|
--- a/include/linux/console.h
|
|
+++ b/include/linux/console.h
|
|
@@ -36,9 +36,14 @@ enum vc_intensity;
|
|
/**
|
|
* struct consw - callbacks for consoles
|
|
*
|
|
+ * @con_init: initialize the console on @vc. @init is true for the very first
|
|
+ * call on this @vc.
|
|
+ * @con_clear: erase @count characters at [@x, @y] on @vc. @count >= 1.
|
|
* @con_scroll: move lines from @top to @bottom in direction @dir by @lines.
|
|
* Return true if no generic handling should be done.
|
|
* Invoked by csi_M and printing to the console.
|
|
+ * @con_switch: notifier about the console switch; it is supposed to return
|
|
+ * true if a redraw is needed.
|
|
* @con_set_palette: sets the palette of the console to @table (optional)
|
|
* @con_scrolldelta: the contents of the console should be scrolled by @lines.
|
|
* Invoked by user. (optional)
|
|
@@ -46,10 +51,10 @@ enum vc_intensity;
|
|
struct consw {
|
|
struct module *owner;
|
|
const char *(*con_startup)(void);
|
|
- void (*con_init)(struct vc_data *vc, int init);
|
|
+ void (*con_init)(struct vc_data *vc, bool init);
|
|
void (*con_deinit)(struct vc_data *vc);
|
|
- void (*con_clear)(struct vc_data *vc, int sy, int sx, int height,
|
|
- int width);
|
|
+ void (*con_clear)(struct vc_data *vc, unsigned int y,
|
|
+ unsigned int x, unsigned int count);
|
|
void (*con_putc)(struct vc_data *vc, int c, int ypos, int xpos);
|
|
void (*con_putcs)(struct vc_data *vc, const unsigned short *s,
|
|
int count, int ypos, int xpos);
|
|
@@ -57,7 +62,7 @@ struct consw {
|
|
bool (*con_scroll)(struct vc_data *vc, unsigned int top,
|
|
unsigned int bottom, enum con_scroll dir,
|
|
unsigned int lines);
|
|
- int (*con_switch)(struct vc_data *vc);
|
|
+ bool (*con_switch)(struct vc_data *vc);
|
|
int (*con_blank)(struct vc_data *vc, int blank, int mode_switch);
|
|
int (*con_font_set)(struct vc_data *vc, struct console_font *font,
|
|
unsigned int vpitch, unsigned int flags);
|
|
diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h
|
|
index b5bf5315ca8c10..e4ad9760774e14 100644
|
|
--- a/include/linux/hyperv.h
|
|
+++ b/include/linux/hyperv.h
|
|
@@ -820,6 +820,8 @@ struct vmbus_requestor {
|
|
#define VMBUS_RQST_RESET (U64_MAX - 3)
|
|
|
|
struct vmbus_device {
|
|
+ /* preferred ring buffer size in KB, 0 means no preferred size for this device */
|
|
+ size_t pref_ring_size;
|
|
u16 dev_type;
|
|
guid_t guid;
|
|
bool perf_device;
|
|
diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
|
|
index d79851c5fabd86..af8a771a053c51 100644
|
|
--- a/include/linux/ipv6.h
|
|
+++ b/include/linux/ipv6.h
|
|
@@ -199,7 +199,6 @@ struct inet6_cork {
|
|
struct ipv6_txoptions *opt;
|
|
u8 hop_limit;
|
|
u8 tclass;
|
|
- u8 dontfrag:1;
|
|
};
|
|
|
|
/* struct ipv6_pinfo - ipv6 private area */
|
|
diff --git a/include/uapi/linux/vm_sockets.h b/include/uapi/linux/vm_sockets.h
|
|
index ed07181d4eff91..e05280e4152286 100644
|
|
--- a/include/uapi/linux/vm_sockets.h
|
|
+++ b/include/uapi/linux/vm_sockets.h
|
|
@@ -17,6 +17,10 @@
|
|
#ifndef _UAPI_VM_SOCKETS_H
|
|
#define _UAPI_VM_SOCKETS_H
|
|
|
|
+#ifndef __KERNEL__
|
|
+#include <sys/socket.h> /* for struct sockaddr and sa_family_t */
|
|
+#endif
|
|
+
|
|
#include <linux/socket.h>
|
|
#include <linux/types.h>
|
|
|
|
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
|
|
index e809b6d8bc5373..1aae81c57b2c9a 100644
|
|
--- a/lib/Kconfig.debug
|
|
+++ b/lib/Kconfig.debug
|
|
@@ -2747,6 +2747,15 @@ config FORTIFY_KUNIT_TEST
|
|
by the str*() and mem*() family of functions. For testing runtime
|
|
traps of FORTIFY_SOURCE, see LKDTM's "FORTIFY_*" tests.
|
|
|
|
+config LONGEST_SYM_KUNIT_TEST
|
|
+ tristate "Test the longest symbol possible" if !KUNIT_ALL_TESTS
|
|
+ depends on KUNIT && KPROBES
|
|
+ default KUNIT_ALL_TESTS
|
|
+ help
|
|
+ Tests the longest symbol possible
|
|
+
|
|
+ If unsure, say N.
|
|
+
|
|
config HW_BREAKPOINT_KUNIT_TEST
|
|
bool "Test hw_breakpoint constraints accounting" if !KUNIT_ALL_TESTS
|
|
depends on HAVE_HW_BREAKPOINT
|
|
diff --git a/lib/Makefile b/lib/Makefile
|
|
index 740109b6e2c89f..b9d2577fbbe190 100644
|
|
--- a/lib/Makefile
|
|
+++ b/lib/Makefile
|
|
@@ -402,6 +402,8 @@ obj-$(CONFIG_FORTIFY_KUNIT_TEST) += fortify_kunit.o
|
|
obj-$(CONFIG_STRCAT_KUNIT_TEST) += strcat_kunit.o
|
|
obj-$(CONFIG_STRSCPY_KUNIT_TEST) += strscpy_kunit.o
|
|
obj-$(CONFIG_SIPHASH_KUNIT_TEST) += siphash_kunit.o
|
|
+obj-$(CONFIG_LONGEST_SYM_KUNIT_TEST) += longest_symbol_kunit.o
|
|
+CFLAGS_longest_symbol_kunit.o += $(call cc-disable-warning, missing-prototypes)
|
|
|
|
obj-$(CONFIG_GENERIC_LIB_DEVMEM_IS_ALLOWED) += devmem_is_allowed.o
|
|
|
|
diff --git a/lib/group_cpus.c b/lib/group_cpus.c
|
|
index ee272c4cefcc13..18d43a406114b9 100644
|
|
--- a/lib/group_cpus.c
|
|
+++ b/lib/group_cpus.c
|
|
@@ -352,6 +352,9 @@ struct cpumask *group_cpus_evenly(unsigned int numgrps)
|
|
int ret = -ENOMEM;
|
|
struct cpumask *masks = NULL;
|
|
|
|
+ if (numgrps == 0)
|
|
+ return NULL;
|
|
+
|
|
if (!zalloc_cpumask_var(&nmsk, GFP_KERNEL))
|
|
return NULL;
|
|
|
|
@@ -426,8 +429,12 @@ struct cpumask *group_cpus_evenly(unsigned int numgrps)
|
|
#else /* CONFIG_SMP */
|
|
struct cpumask *group_cpus_evenly(unsigned int numgrps)
|
|
{
|
|
- struct cpumask *masks = kcalloc(numgrps, sizeof(*masks), GFP_KERNEL);
|
|
+ struct cpumask *masks;
|
|
|
|
+ if (numgrps == 0)
|
|
+ return NULL;
|
|
+
|
|
+ masks = kcalloc(numgrps, sizeof(*masks), GFP_KERNEL);
|
|
if (!masks)
|
|
return NULL;
|
|
|
|
diff --git a/lib/longest_symbol_kunit.c b/lib/longest_symbol_kunit.c
|
|
new file mode 100644
|
|
index 00000000000000..2fea82a6d34e5c
|
|
--- /dev/null
|
|
+++ b/lib/longest_symbol_kunit.c
|
|
@@ -0,0 +1,82 @@
|
|
+// SPDX-License-Identifier: GPL-2.0
|
|
+/*
|
|
+ * Test the longest symbol length. Execute with:
|
|
+ * ./tools/testing/kunit/kunit.py run longest-symbol
|
|
+ * --arch=x86_64 --kconfig_add CONFIG_KPROBES=y --kconfig_add CONFIG_MODULES=y
|
|
+ * --kconfig_add CONFIG_RETPOLINE=n --kconfig_add CONFIG_CFI_CLANG=n
|
|
+ * --kconfig_add CONFIG_MITIGATION_RETPOLINE=n
|
|
+ */
|
|
+
|
|
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
|
+
|
|
+#include <kunit/test.h>
|
|
+#include <linux/stringify.h>
|
|
+#include <linux/kprobes.h>
|
|
+#include <linux/kallsyms.h>
|
|
+
|
|
+#define DI(name) s##name##name
|
|
+#define DDI(name) DI(n##name##name)
|
|
+#define DDDI(name) DDI(n##name##name)
|
|
+#define DDDDI(name) DDDI(n##name##name)
|
|
+#define DDDDDI(name) DDDDI(n##name##name)
|
|
+
|
|
+/*Generate a symbol whose name length is 511 */
|
|
+#define LONGEST_SYM_NAME DDDDDI(g1h2i3j4k5l6m7n)
|
|
+
|
|
+#define RETURN_LONGEST_SYM 0xAAAAA
|
|
+
|
|
+noinline int LONGEST_SYM_NAME(void);
|
|
+noinline int LONGEST_SYM_NAME(void)
|
|
+{
|
|
+ return RETURN_LONGEST_SYM;
|
|
+}
|
|
+
|
|
+_Static_assert(sizeof(__stringify(LONGEST_SYM_NAME)) == KSYM_NAME_LEN,
|
|
+"Incorrect symbol length found. Expected KSYM_NAME_LEN: "
|
|
+__stringify(KSYM_NAME_LEN) ", but found: "
|
|
+__stringify(sizeof(LONGEST_SYM_NAME)));
|
|
+
|
|
+static void test_longest_symbol(struct kunit *test)
|
|
+{
|
|
+ KUNIT_EXPECT_EQ(test, RETURN_LONGEST_SYM, LONGEST_SYM_NAME());
|
|
+};
|
|
+
|
|
+static void test_longest_symbol_kallsyms(struct kunit *test)
|
|
+{
|
|
+ unsigned long (*kallsyms_lookup_name)(const char *name);
|
|
+ static int (*longest_sym)(void);
|
|
+
|
|
+ struct kprobe kp = {
|
|
+ .symbol_name = "kallsyms_lookup_name",
|
|
+ };
|
|
+
|
|
+ if (register_kprobe(&kp) < 0) {
|
|
+ pr_info("%s: kprobe not registered", __func__);
|
|
+ KUNIT_FAIL(test, "test_longest_symbol kallsyms: kprobe not registered\n");
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ kunit_warn(test, "test_longest_symbol kallsyms: kprobe registered\n");
|
|
+ kallsyms_lookup_name = (unsigned long (*)(const char *name))kp.addr;
|
|
+ unregister_kprobe(&kp);
|
|
+
|
|
+ longest_sym =
|
|
+ (void *) kallsyms_lookup_name(__stringify(LONGEST_SYM_NAME));
|
|
+ KUNIT_EXPECT_EQ(test, RETURN_LONGEST_SYM, longest_sym());
|
|
+};
|
|
+
|
|
+static struct kunit_case longest_symbol_test_cases[] = {
|
|
+ KUNIT_CASE(test_longest_symbol),
|
|
+ KUNIT_CASE(test_longest_symbol_kallsyms),
|
|
+ {}
|
|
+};
|
|
+
|
|
+static struct kunit_suite longest_symbol_test_suite = {
|
|
+ .name = "longest-symbol",
|
|
+ .test_cases = longest_symbol_test_cases,
|
|
+};
|
|
+kunit_test_suite(longest_symbol_test_suite);
|
|
+
|
|
+MODULE_LICENSE("GPL");
|
|
+MODULE_DESCRIPTION("Test the longest symbol length");
|
|
+MODULE_AUTHOR("Sergio González Collado");
|
|
diff --git a/mm/damon/sysfs-schemes.c b/mm/damon/sysfs-schemes.c
|
|
index 26c948f87489ee..19d661889cf796 100644
|
|
--- a/mm/damon/sysfs-schemes.c
|
|
+++ b/mm/damon/sysfs-schemes.c
|
|
@@ -376,6 +376,7 @@ static ssize_t memcg_path_store(struct kobject *kobj,
|
|
return -ENOMEM;
|
|
|
|
strscpy(path, buf, count + 1);
|
|
+ kfree(filter->memcg_path);
|
|
filter->memcg_path = path;
|
|
return count;
|
|
}
|
|
diff --git a/net/atm/clip.c b/net/atm/clip.c
|
|
index 294cb9efe3d382..511467bb7fe40d 100644
|
|
--- a/net/atm/clip.c
|
|
+++ b/net/atm/clip.c
|
|
@@ -193,12 +193,6 @@ static void clip_push(struct atm_vcc *vcc, struct sk_buff *skb)
|
|
|
|
pr_debug("\n");
|
|
|
|
- if (!clip_devs) {
|
|
- atm_return(vcc, skb->truesize);
|
|
- kfree_skb(skb);
|
|
- return;
|
|
- }
|
|
-
|
|
if (!skb) {
|
|
pr_debug("removing VCC %p\n", clip_vcc);
|
|
if (clip_vcc->entry)
|
|
@@ -208,6 +202,11 @@ static void clip_push(struct atm_vcc *vcc, struct sk_buff *skb)
|
|
return;
|
|
}
|
|
atm_return(vcc, skb->truesize);
|
|
+ if (!clip_devs) {
|
|
+ kfree_skb(skb);
|
|
+ return;
|
|
+ }
|
|
+
|
|
skb->dev = clip_vcc->entry ? clip_vcc->entry->neigh->dev : clip_devs;
|
|
/* clip_vcc->entry == NULL if we don't have an IP address yet */
|
|
if (!skb->dev) {
|
|
diff --git a/net/atm/resources.c b/net/atm/resources.c
|
|
index 995d29e7fb138c..b19d851e1f4439 100644
|
|
--- a/net/atm/resources.c
|
|
+++ b/net/atm/resources.c
|
|
@@ -146,11 +146,10 @@ void atm_dev_deregister(struct atm_dev *dev)
|
|
*/
|
|
mutex_lock(&atm_dev_mutex);
|
|
list_del(&dev->dev_list);
|
|
- mutex_unlock(&atm_dev_mutex);
|
|
-
|
|
atm_dev_release_vccs(dev);
|
|
atm_unregister_sysfs(dev);
|
|
atm_proc_dev_deregister(dev);
|
|
+ mutex_unlock(&atm_dev_mutex);
|
|
|
|
atm_dev_put(dev);
|
|
}
|
|
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
|
|
index 2744ad11687c65..f9995a405e35c3 100644
|
|
--- a/net/bluetooth/l2cap_core.c
|
|
+++ b/net/bluetooth/l2cap_core.c
|
|
@@ -3380,7 +3380,7 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data, size_t data
|
|
struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC };
|
|
struct l2cap_conf_efs efs;
|
|
u8 remote_efs = 0;
|
|
- u16 mtu = L2CAP_DEFAULT_MTU;
|
|
+ u16 mtu = 0;
|
|
u16 result = L2CAP_CONF_SUCCESS;
|
|
u16 size;
|
|
|
|
@@ -3485,6 +3485,13 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data, size_t data
|
|
/* Configure output options and let the other side know
|
|
* which ones we don't like. */
|
|
|
|
+ /* If MTU is not provided in configure request, use the most recently
|
|
+ * explicitly or implicitly accepted value for the other direction,
|
|
+ * or the default value.
|
|
+ */
|
|
+ if (mtu == 0)
|
|
+ mtu = chan->imtu ? chan->imtu : L2CAP_DEFAULT_MTU;
|
|
+
|
|
if (mtu < L2CAP_DEFAULT_MIN_MTU)
|
|
result = L2CAP_CONF_UNACCEPT;
|
|
else {
|
|
diff --git a/net/core/selftests.c b/net/core/selftests.c
|
|
index 7af99d07762ea0..946e92cca21110 100644
|
|
--- a/net/core/selftests.c
|
|
+++ b/net/core/selftests.c
|
|
@@ -160,8 +160,9 @@ static struct sk_buff *net_test_get_skb(struct net_device *ndev,
|
|
skb->csum = 0;
|
|
skb->ip_summed = CHECKSUM_PARTIAL;
|
|
if (attr->tcp) {
|
|
- thdr->check = ~tcp_v4_check(skb->len, ihdr->saddr,
|
|
- ihdr->daddr, 0);
|
|
+ int l4len = skb->len - skb_transport_offset(skb);
|
|
+
|
|
+ thdr->check = ~tcp_v4_check(l4len, ihdr->saddr, ihdr->daddr, 0);
|
|
skb->csum_start = skb_transport_header(skb) - skb->head;
|
|
skb->csum_offset = offsetof(struct tcphdr, check);
|
|
} else {
|
|
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
|
|
index 28777b14224048..c86d5dca29df01 100644
|
|
--- a/net/ipv6/ip6_output.c
|
|
+++ b/net/ipv6/ip6_output.c
|
|
@@ -1452,7 +1452,6 @@ static int ip6_setup_cork(struct sock *sk, struct inet_cork_full *cork,
|
|
}
|
|
v6_cork->hop_limit = ipc6->hlimit;
|
|
v6_cork->tclass = ipc6->tclass;
|
|
- v6_cork->dontfrag = ipc6->dontfrag;
|
|
if (rt->dst.flags & DST_XFRM_TUNNEL)
|
|
mtu = np->pmtudisc >= IPV6_PMTUDISC_PROBE ?
|
|
READ_ONCE(rt->dst.dev->mtu) : dst_mtu(&rt->dst);
|
|
@@ -1486,7 +1485,7 @@ static int __ip6_append_data(struct sock *sk,
|
|
int getfrag(void *from, char *to, int offset,
|
|
int len, int odd, struct sk_buff *skb),
|
|
void *from, size_t length, int transhdrlen,
|
|
- unsigned int flags)
|
|
+ unsigned int flags, struct ipcm6_cookie *ipc6)
|
|
{
|
|
struct sk_buff *skb, *skb_prev = NULL;
|
|
struct inet_cork *cork = &cork_full->base;
|
|
@@ -1542,7 +1541,7 @@ static int __ip6_append_data(struct sock *sk,
|
|
if (headersize + transhdrlen > mtu)
|
|
goto emsgsize;
|
|
|
|
- if (cork->length + length > mtu - headersize && v6_cork->dontfrag &&
|
|
+ if (cork->length + length > mtu - headersize && ipc6->dontfrag &&
|
|
(sk->sk_protocol == IPPROTO_UDP ||
|
|
sk->sk_protocol == IPPROTO_ICMPV6 ||
|
|
sk->sk_protocol == IPPROTO_RAW)) {
|
|
@@ -1914,7 +1913,7 @@ int ip6_append_data(struct sock *sk,
|
|
|
|
return __ip6_append_data(sk, &sk->sk_write_queue, &inet->cork,
|
|
&np->cork, sk_page_frag(sk), getfrag,
|
|
- from, length, transhdrlen, flags);
|
|
+ from, length, transhdrlen, flags, ipc6);
|
|
}
|
|
EXPORT_SYMBOL_GPL(ip6_append_data);
|
|
|
|
@@ -2119,7 +2118,7 @@ struct sk_buff *ip6_make_skb(struct sock *sk,
|
|
err = __ip6_append_data(sk, &queue, cork, &v6_cork,
|
|
¤t->task_frag, getfrag, from,
|
|
length + exthdrlen, transhdrlen + exthdrlen,
|
|
- flags);
|
|
+ flags, ipc6);
|
|
if (err) {
|
|
__ip6_flush_pending_frames(sk, &queue, cork, &v6_cork);
|
|
return ERR_PTR(err);
|
|
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
|
|
index 154b41af4157d0..3a3cd09bdab658 100644
|
|
--- a/net/mac80211/util.c
|
|
+++ b/net/mac80211/util.c
|
|
@@ -4753,7 +4753,7 @@ void ieee80211_recalc_dtim(struct ieee80211_local *local,
|
|
{
|
|
u64 tsf = drv_get_tsf(local, sdata);
|
|
u64 dtim_count = 0;
|
|
- u16 beacon_int = sdata->vif.bss_conf.beacon_int * 1024;
|
|
+ u32 beacon_int = sdata->vif.bss_conf.beacon_int * 1024;
|
|
u8 dtim_period = sdata->vif.bss_conf.dtim_period;
|
|
struct ps_data *ps;
|
|
u8 bcns_from_dtim;
|
|
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
|
|
index 4ffb2bcaf3648e..63756607f63272 100644
|
|
--- a/net/sunrpc/clnt.c
|
|
+++ b/net/sunrpc/clnt.c
|
|
@@ -2733,8 +2733,13 @@ rpc_decode_header(struct rpc_task *task, struct xdr_stream *xdr)
|
|
case -EPROTONOSUPPORT:
|
|
goto out_err;
|
|
case -EACCES:
|
|
- /* Re-encode with a fresh cred */
|
|
- fallthrough;
|
|
+ /* possible RPCSEC_GSS out-of-sequence event (RFC2203),
|
|
+ * reset recv state and keep waiting, don't retransmit
|
|
+ */
|
|
+ task->tk_rqstp->rq_reply_bytes_recvd = 0;
|
|
+ task->tk_status = xprt_request_enqueue_receive(task);
|
|
+ task->tk_action = call_transmit_status;
|
|
+ return -EBADMSG;
|
|
default:
|
|
goto out_garbage;
|
|
}
|
|
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
|
|
index 236a2cd2bc93d2..f89cd01247f6bb 100644
|
|
--- a/net/unix/af_unix.c
|
|
+++ b/net/unix/af_unix.c
|
|
@@ -125,6 +125,46 @@ static spinlock_t bsd_socket_locks[UNIX_HASH_SIZE / 2];
|
|
* hash table is protected with spinlock.
|
|
* each socket state is protected by separate spinlock.
|
|
*/
|
|
+#ifdef CONFIG_PROVE_LOCKING
|
|
+#define cmp_ptr(l, r) (((l) > (r)) - ((l) < (r)))
|
|
+
|
|
+static int unix_table_lock_cmp_fn(const struct lockdep_map *a,
|
|
+ const struct lockdep_map *b)
|
|
+{
|
|
+ return cmp_ptr(a, b);
|
|
+}
|
|
+
|
|
+static int unix_state_lock_cmp_fn(const struct lockdep_map *_a,
|
|
+ const struct lockdep_map *_b)
|
|
+{
|
|
+ const struct unix_sock *a, *b;
|
|
+
|
|
+ a = container_of(_a, struct unix_sock, lock.dep_map);
|
|
+ b = container_of(_b, struct unix_sock, lock.dep_map);
|
|
+
|
|
+ /* unix_state_double_lock(): ascending address order. */
|
|
+ return cmp_ptr(a, b);
|
|
+}
|
|
+
|
|
+static int unix_recvq_lock_cmp_fn(const struct lockdep_map *_a,
|
|
+ const struct lockdep_map *_b)
|
|
+{
|
|
+ const struct sock *a, *b;
|
|
+
|
|
+ a = container_of(_a, struct sock, sk_receive_queue.lock.dep_map);
|
|
+ b = container_of(_b, struct sock, sk_receive_queue.lock.dep_map);
|
|
+
|
|
+ /* unix_collect_skb(): listener -> embryo order. */
|
|
+ if (a->sk_state == TCP_LISTEN && unix_sk(b)->listener == a)
|
|
+ return -1;
|
|
+
|
|
+ /* Should never happen. Just to be symmetric. */
|
|
+ if (b->sk_state == TCP_LISTEN && unix_sk(a)->listener == b)
|
|
+ return 1;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+#endif
|
|
|
|
static unsigned int unix_unbound_hash(struct sock *sk)
|
|
{
|
|
@@ -167,7 +207,7 @@ static void unix_table_double_lock(struct net *net,
|
|
swap(hash1, hash2);
|
|
|
|
spin_lock(&net->unx.table.locks[hash1]);
|
|
- spin_lock_nested(&net->unx.table.locks[hash2], SINGLE_DEPTH_NESTING);
|
|
+ spin_lock(&net->unx.table.locks[hash2]);
|
|
}
|
|
|
|
static void unix_table_double_unlock(struct net *net,
|
|
@@ -590,6 +630,11 @@ static void unix_sock_destructor(struct sock *sk)
|
|
#endif
|
|
}
|
|
|
|
+static unsigned int unix_skb_len(const struct sk_buff *skb)
|
|
+{
|
|
+ return skb->len - UNIXCB(skb).consumed;
|
|
+}
|
|
+
|
|
static void unix_release_sock(struct sock *sk, int embrion)
|
|
{
|
|
struct unix_sock *u = unix_sk(sk);
|
|
@@ -617,20 +662,23 @@ static void unix_release_sock(struct sock *sk, int embrion)
|
|
unix_state_unlock(sk);
|
|
|
|
#if IS_ENABLED(CONFIG_AF_UNIX_OOB)
|
|
- if (u->oob_skb) {
|
|
- kfree_skb(u->oob_skb);
|
|
- u->oob_skb = NULL;
|
|
- }
|
|
+ u->oob_skb = NULL;
|
|
#endif
|
|
|
|
wake_up_interruptible_all(&u->peer_wait);
|
|
|
|
if (skpair != NULL) {
|
|
if (sk->sk_type == SOCK_STREAM || sk->sk_type == SOCK_SEQPACKET) {
|
|
+ struct sk_buff *skb = skb_peek(&sk->sk_receive_queue);
|
|
+
|
|
+#if IS_ENABLED(CONFIG_AF_UNIX_OOB)
|
|
+ if (skb && !unix_skb_len(skb))
|
|
+ skb = skb_peek_next(skb, &sk->sk_receive_queue);
|
|
+#endif
|
|
unix_state_lock(skpair);
|
|
/* No more writes */
|
|
WRITE_ONCE(skpair->sk_shutdown, SHUTDOWN_MASK);
|
|
- if (!skb_queue_empty_lockless(&sk->sk_receive_queue) || embrion)
|
|
+ if (skb || embrion)
|
|
WRITE_ONCE(skpair->sk_err, ECONNRESET);
|
|
unix_state_unlock(skpair);
|
|
skpair->sk_state_change(skpair);
|
|
@@ -977,12 +1025,15 @@ static struct sock *unix_create1(struct net *net, struct socket *sock, int kern,
|
|
sk->sk_write_space = unix_write_space;
|
|
sk->sk_max_ack_backlog = READ_ONCE(net->unx.sysctl_max_dgram_qlen);
|
|
sk->sk_destruct = unix_sock_destructor;
|
|
+ lock_set_cmp_fn(&sk->sk_receive_queue.lock, unix_recvq_lock_cmp_fn, NULL);
|
|
+
|
|
u = unix_sk(sk);
|
|
u->listener = NULL;
|
|
u->vertex = NULL;
|
|
u->path.dentry = NULL;
|
|
u->path.mnt = NULL;
|
|
spin_lock_init(&u->lock);
|
|
+ lock_set_cmp_fn(&u->lock, unix_state_lock_cmp_fn, NULL);
|
|
mutex_init(&u->iolock); /* single task reading lock */
|
|
mutex_init(&u->bindlock); /* single task binding lock */
|
|
init_waitqueue_head(&u->peer_wait);
|
|
@@ -1331,11 +1382,12 @@ static void unix_state_double_lock(struct sock *sk1, struct sock *sk2)
|
|
unix_state_lock(sk1);
|
|
return;
|
|
}
|
|
+
|
|
if (sk1 > sk2)
|
|
swap(sk1, sk2);
|
|
|
|
unix_state_lock(sk1);
|
|
- unix_state_lock_nested(sk2, U_LOCK_SECOND);
|
|
+ unix_state_lock(sk2);
|
|
}
|
|
|
|
static void unix_state_double_unlock(struct sock *sk1, struct sock *sk2)
|
|
@@ -2145,13 +2197,9 @@ static int queue_oob(struct socket *sock, struct msghdr *msg, struct sock *other
|
|
}
|
|
|
|
maybe_add_creds(skb, sock, other);
|
|
- skb_get(skb);
|
|
-
|
|
scm_stat_add(other, skb);
|
|
|
|
spin_lock(&other->sk_receive_queue.lock);
|
|
- if (ousk->oob_skb)
|
|
- consume_skb(ousk->oob_skb);
|
|
WRITE_ONCE(ousk->oob_skb, skb);
|
|
__skb_queue_tail(&other->sk_receive_queue, skb);
|
|
spin_unlock(&other->sk_receive_queue.lock);
|
|
@@ -2515,11 +2563,6 @@ static long unix_stream_data_wait(struct sock *sk, long timeo,
|
|
return timeo;
|
|
}
|
|
|
|
-static unsigned int unix_skb_len(const struct sk_buff *skb)
|
|
-{
|
|
- return skb->len - UNIXCB(skb).consumed;
|
|
-}
|
|
-
|
|
struct unix_stream_read_state {
|
|
int (*recv_actor)(struct sk_buff *, int, int,
|
|
struct unix_stream_read_state *);
|
|
@@ -2534,11 +2577,11 @@ struct unix_stream_read_state {
|
|
#if IS_ENABLED(CONFIG_AF_UNIX_OOB)
|
|
static int unix_stream_recv_urg(struct unix_stream_read_state *state)
|
|
{
|
|
+ struct sk_buff *oob_skb, *read_skb = NULL;
|
|
struct socket *sock = state->socket;
|
|
struct sock *sk = sock->sk;
|
|
struct unix_sock *u = unix_sk(sk);
|
|
int chunk = 1;
|
|
- struct sk_buff *oob_skb;
|
|
|
|
mutex_lock(&u->iolock);
|
|
unix_state_lock(sk);
|
|
@@ -2553,10 +2596,15 @@ static int unix_stream_recv_urg(struct unix_stream_read_state *state)
|
|
|
|
oob_skb = u->oob_skb;
|
|
|
|
- if (!(state->flags & MSG_PEEK))
|
|
+ if (!(state->flags & MSG_PEEK)) {
|
|
WRITE_ONCE(u->oob_skb, NULL);
|
|
- else
|
|
- skb_get(oob_skb);
|
|
+
|
|
+ if (oob_skb->prev != (struct sk_buff *)&sk->sk_receive_queue &&
|
|
+ !unix_skb_len(oob_skb->prev)) {
|
|
+ read_skb = oob_skb->prev;
|
|
+ __skb_unlink(read_skb, &sk->sk_receive_queue);
|
|
+ }
|
|
+ }
|
|
|
|
spin_unlock(&sk->sk_receive_queue.lock);
|
|
unix_state_unlock(sk);
|
|
@@ -2566,10 +2614,10 @@ static int unix_stream_recv_urg(struct unix_stream_read_state *state)
|
|
if (!(state->flags & MSG_PEEK))
|
|
UNIXCB(oob_skb).consumed += 1;
|
|
|
|
- consume_skb(oob_skb);
|
|
-
|
|
mutex_unlock(&u->iolock);
|
|
|
|
+ consume_skb(read_skb);
|
|
+
|
|
if (chunk < 0)
|
|
return -EFAULT;
|
|
|
|
@@ -2595,12 +2643,10 @@ static struct sk_buff *manage_oob(struct sk_buff *skb, struct sock *sk,
|
|
if (copied) {
|
|
skb = NULL;
|
|
} else if (!(flags & MSG_PEEK)) {
|
|
- if (sock_flag(sk, SOCK_URGINLINE)) {
|
|
- WRITE_ONCE(u->oob_skb, NULL);
|
|
- consume_skb(skb);
|
|
- } else {
|
|
+ WRITE_ONCE(u->oob_skb, NULL);
|
|
+
|
|
+ if (!sock_flag(sk, SOCK_URGINLINE)) {
|
|
__skb_unlink(skb, &sk->sk_receive_queue);
|
|
- WRITE_ONCE(u->oob_skb, NULL);
|
|
unlinked_skb = skb;
|
|
skb = skb_peek(&sk->sk_receive_queue);
|
|
}
|
|
@@ -2611,10 +2657,7 @@ static struct sk_buff *manage_oob(struct sk_buff *skb, struct sock *sk,
|
|
|
|
spin_unlock(&sk->sk_receive_queue.lock);
|
|
|
|
- if (unlinked_skb) {
|
|
- WARN_ON_ONCE(skb_unref(unlinked_skb));
|
|
- kfree_skb(unlinked_skb);
|
|
- }
|
|
+ kfree_skb(unlinked_skb);
|
|
}
|
|
return skb;
|
|
}
|
|
@@ -2657,7 +2700,6 @@ static int unix_stream_read_skb(struct sock *sk, skb_read_actor_t recv_actor)
|
|
unix_state_unlock(sk);
|
|
|
|
if (drop) {
|
|
- WARN_ON_ONCE(skb_unref(skb));
|
|
kfree_skb(skb);
|
|
return -EAGAIN;
|
|
}
|
|
@@ -3598,6 +3640,7 @@ static int __net_init unix_net_init(struct net *net)
|
|
|
|
for (i = 0; i < UNIX_HASH_SIZE; i++) {
|
|
spin_lock_init(&net->unx.table.locks[i]);
|
|
+ lock_set_cmp_fn(&net->unx.table.locks[i], unix_table_lock_cmp_fn, NULL);
|
|
INIT_HLIST_HEAD(&net->unx.table.buckets[i]);
|
|
}
|
|
|
|
diff --git a/net/unix/garbage.c b/net/unix/garbage.c
|
|
index 23efb78fe9ef4b..0068e758be4ddb 100644
|
|
--- a/net/unix/garbage.c
|
|
+++ b/net/unix/garbage.c
|
|
@@ -337,23 +337,6 @@ static bool unix_vertex_dead(struct unix_vertex *vertex)
|
|
return true;
|
|
}
|
|
|
|
-enum unix_recv_queue_lock_class {
|
|
- U_RECVQ_LOCK_NORMAL,
|
|
- U_RECVQ_LOCK_EMBRYO,
|
|
-};
|
|
-
|
|
-static void unix_collect_queue(struct unix_sock *u, struct sk_buff_head *hitlist)
|
|
-{
|
|
- skb_queue_splice_init(&u->sk.sk_receive_queue, hitlist);
|
|
-
|
|
-#if IS_ENABLED(CONFIG_AF_UNIX_OOB)
|
|
- if (u->oob_skb) {
|
|
- WARN_ON_ONCE(skb_unref(u->oob_skb));
|
|
- u->oob_skb = NULL;
|
|
- }
|
|
-#endif
|
|
-}
|
|
-
|
|
static void unix_collect_skb(struct list_head *scc, struct sk_buff_head *hitlist)
|
|
{
|
|
struct unix_vertex *vertex;
|
|
@@ -375,13 +358,12 @@ static void unix_collect_skb(struct list_head *scc, struct sk_buff_head *hitlist
|
|
skb_queue_walk(queue, skb) {
|
|
struct sk_buff_head *embryo_queue = &skb->sk->sk_receive_queue;
|
|
|
|
- /* listener -> embryo order, the inversion never happens. */
|
|
- spin_lock_nested(&embryo_queue->lock, U_RECVQ_LOCK_EMBRYO);
|
|
- unix_collect_queue(unix_sk(skb->sk), hitlist);
|
|
+ spin_lock(&embryo_queue->lock);
|
|
+ skb_queue_splice_init(embryo_queue, hitlist);
|
|
spin_unlock(&embryo_queue->lock);
|
|
}
|
|
} else {
|
|
- unix_collect_queue(u, hitlist);
|
|
+ skb_queue_splice_init(queue, hitlist);
|
|
}
|
|
|
|
spin_unlock(&queue->lock);
|
|
diff --git a/rust/macros/module.rs b/rust/macros/module.rs
|
|
index 7dee348ef0cc82..7614a7198ce206 100644
|
|
--- a/rust/macros/module.rs
|
|
+++ b/rust/macros/module.rs
|
|
@@ -249,6 +249,7 @@ mod __module_init {{
|
|
#[cfg(MODULE)]
|
|
#[doc(hidden)]
|
|
#[no_mangle]
|
|
+ #[link_section = \".exit.text\"]
|
|
pub extern \"C\" fn cleanup_module() {{
|
|
// SAFETY:
|
|
// - This function is inaccessible to the outside due to the double
|
|
diff --git a/scripts/checkstack.pl b/scripts/checkstack.pl
|
|
index f27d552aec43f2..aad423c5181a96 100755
|
|
--- a/scripts/checkstack.pl
|
|
+++ b/scripts/checkstack.pl
|
|
@@ -68,9 +68,6 @@ my (@stack, $re, $dre, $sub, $x, $xs, $funcre, $min_stack);
|
|
# 2f60: 48 81 ec e8 05 00 00 sub $0x5e8,%rsp
|
|
$re = qr/^.*[as][du][db] \$(0x$x{1,8}),\%(e|r)sp$/o;
|
|
$dre = qr/^.*[as][du][db] (%.*),\%(e|r)sp$/o;
|
|
- } elsif ($arch eq 'ia64') {
|
|
- #e0000000044011fc: 01 0f fc 8c adds r12=-384,r12
|
|
- $re = qr/.*adds.*r12=-(([0-9]{2}|[3-9])[0-9]{2}),r12/o;
|
|
} elsif ($arch eq 'm68k') {
|
|
# 2b6c: 4e56 fb70 linkw %fp,#-1168
|
|
# 1df770: defc ffe4 addaw #-28,%sp
|
|
diff --git a/scripts/gdb/linux/tasks.py b/scripts/gdb/linux/tasks.py
|
|
index 17ec19e9b5bf6a..5be53b372a6938 100644
|
|
--- a/scripts/gdb/linux/tasks.py
|
|
+++ b/scripts/gdb/linux/tasks.py
|
|
@@ -86,21 +86,12 @@ LxPs()
|
|
|
|
thread_info_type = utils.CachedType("struct thread_info")
|
|
|
|
-ia64_task_size = None
|
|
-
|
|
|
|
def get_thread_info(task):
|
|
thread_info_ptr_type = thread_info_type.get_type().pointer()
|
|
- if utils.is_target_arch("ia64"):
|
|
- global ia64_task_size
|
|
- if ia64_task_size is None:
|
|
- ia64_task_size = gdb.parse_and_eval("sizeof(struct task_struct)")
|
|
- thread_info_addr = task.address + ia64_task_size
|
|
- thread_info = thread_info_addr.cast(thread_info_ptr_type)
|
|
- else:
|
|
- if task.type.fields()[0].type == thread_info_type.get_type():
|
|
- return task['thread_info']
|
|
- thread_info = task['stack'].cast(thread_info_ptr_type)
|
|
+ if task.type.fields()[0].type == thread_info_type.get_type():
|
|
+ return task['thread_info']
|
|
+ thread_info = task['stack'].cast(thread_info_ptr_type)
|
|
return thread_info.dereference()
|
|
|
|
|
|
diff --git a/scripts/head-object-list.txt b/scripts/head-object-list.txt
|
|
index 26359968744ef1..890f69005bab41 100644
|
|
--- a/scripts/head-object-list.txt
|
|
+++ b/scripts/head-object-list.txt
|
|
@@ -17,7 +17,6 @@ arch/arm/kernel/head-nommu.o
|
|
arch/arm/kernel/head.o
|
|
arch/csky/kernel/head.o
|
|
arch/hexagon/kernel/head.o
|
|
-arch/ia64/kernel/head.o
|
|
arch/loongarch/kernel/head.o
|
|
arch/m68k/68000/head.o
|
|
arch/m68k/coldfire/head.o
|
|
diff --git a/scripts/kconfig/mconf.c b/scripts/kconfig/mconf.c
|
|
index eccc87a441e713..3795c36a9181aa 100644
|
|
--- a/scripts/kconfig/mconf.c
|
|
+++ b/scripts/kconfig/mconf.c
|
|
@@ -247,7 +247,7 @@ search_help[] =
|
|
" -> PCI support (PCI [=y])\n"
|
|
"(1) -> PCI access mode (<choice> [=y])\n"
|
|
" Defined at drivers/pci/Kconfig:47\n"
|
|
- " Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n"
|
|
+ " Depends on: X86_LOCAL_APIC && X86_IO_APIC\n"
|
|
" Selects: LIBCRC32\n"
|
|
" Selected by: BAR [=n]\n"
|
|
"-----------------------------------------------------------------\n"
|
|
diff --git a/scripts/kconfig/nconf.c b/scripts/kconfig/nconf.c
|
|
index 143a2c351d5764..8cd72fe2597405 100644
|
|
--- a/scripts/kconfig/nconf.c
|
|
+++ b/scripts/kconfig/nconf.c
|
|
@@ -216,7 +216,7 @@ search_help[] =
|
|
"Symbol: FOO [ = m]\n"
|
|
"Prompt: Foo bus is used to drive the bar HW\n"
|
|
"Defined at drivers/pci/Kconfig:47\n"
|
|
-"Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n"
|
|
+"Depends on: X86_LOCAL_APIC && X86_IO_APIC\n"
|
|
"Location:\n"
|
|
" -> Bus options (PCI, PCMCIA, EISA, ISA)\n"
|
|
" -> PCI support (PCI [ = y])\n"
|
|
diff --git a/scripts/package/kernel.spec b/scripts/package/kernel.spec
|
|
index 3eee0143e0c5cc..f58726671fb374 100644
|
|
--- a/scripts/package/kernel.spec
|
|
+++ b/scripts/package/kernel.spec
|
|
@@ -55,18 +55,12 @@ patch -p1 < %{SOURCE2}
|
|
%{make} %{makeflags} KERNELRELEASE=%{KERNELRELEASE} KBUILD_BUILD_VERSION=%{release}
|
|
|
|
%install
|
|
-mkdir -p %{buildroot}/boot
|
|
-%ifarch ia64
|
|
-mkdir -p %{buildroot}/boot/efi
|
|
-cp $(%{make} %{makeflags} -s image_name) %{buildroot}/boot/efi/vmlinuz-%{KERNELRELEASE}
|
|
-ln -s efi/vmlinuz-%{KERNELRELEASE} %{buildroot}/boot/
|
|
-%else
|
|
-cp $(%{make} %{makeflags} -s image_name) %{buildroot}/boot/vmlinuz-%{KERNELRELEASE}
|
|
-%endif
|
|
+mkdir -p %{buildroot}/lib/modules/%{KERNELRELEASE}
|
|
+cp $(%{make} %{makeflags} -s image_name) %{buildroot}/lib/modules/%{KERNELRELEASE}/vmlinuz
|
|
%{make} %{makeflags} INSTALL_MOD_PATH=%{buildroot} modules_install
|
|
%{make} %{makeflags} INSTALL_HDR_PATH=%{buildroot}/usr headers_install
|
|
-cp System.map %{buildroot}/boot/System.map-%{KERNELRELEASE}
|
|
-cp .config %{buildroot}/boot/config-%{KERNELRELEASE}
|
|
+cp System.map %{buildroot}/lib/modules/%{KERNELRELEASE}
|
|
+cp .config %{buildroot}/lib/modules/%{KERNELRELEASE}/config
|
|
ln -fns /usr/src/kernels/%{KERNELRELEASE} %{buildroot}/lib/modules/%{KERNELRELEASE}/build
|
|
%if %{with_devel}
|
|
%{make} %{makeflags} run-command KBUILD_RUN_COMMAND='${srctree}/scripts/package/install-extmod-build %{buildroot}/usr/src/kernels/%{KERNELRELEASE}'
|
|
@@ -76,13 +70,14 @@ ln -fns /usr/src/kernels/%{KERNELRELEASE} %{buildroot}/lib/modules/%{KERNELRELEA
|
|
rm -rf %{buildroot}
|
|
|
|
%post
|
|
-if [ -x /sbin/installkernel -a -r /boot/vmlinuz-%{KERNELRELEASE} -a -r /boot/System.map-%{KERNELRELEASE} ]; then
|
|
-cp /boot/vmlinuz-%{KERNELRELEASE} /boot/.vmlinuz-%{KERNELRELEASE}-rpm
|
|
-cp /boot/System.map-%{KERNELRELEASE} /boot/.System.map-%{KERNELRELEASE}-rpm
|
|
-rm -f /boot/vmlinuz-%{KERNELRELEASE} /boot/System.map-%{KERNELRELEASE}
|
|
-/sbin/installkernel %{KERNELRELEASE} /boot/.vmlinuz-%{KERNELRELEASE}-rpm /boot/.System.map-%{KERNELRELEASE}-rpm
|
|
-rm -f /boot/.vmlinuz-%{KERNELRELEASE}-rpm /boot/.System.map-%{KERNELRELEASE}-rpm
|
|
+if [ -x /usr/bin/kernel-install ]; then
|
|
+ /usr/bin/kernel-install add %{KERNELRELEASE} /lib/modules/%{KERNELRELEASE}/vmlinuz
|
|
fi
|
|
+for file in vmlinuz System.map config; do
|
|
+ if ! cmp --silent "/lib/modules/%{KERNELRELEASE}/${file}" "/boot/${file}-%{KERNELRELEASE}"; then
|
|
+ cp "/lib/modules/%{KERNELRELEASE}/${file}" "/boot/${file}-%{KERNELRELEASE}"
|
|
+ fi
|
|
+done
|
|
|
|
%preun
|
|
if [ -x /sbin/new-kernel-pkg ]; then
|
|
@@ -100,7 +95,6 @@ fi
|
|
%defattr (-, root, root)
|
|
/lib/modules/%{KERNELRELEASE}
|
|
%exclude /lib/modules/%{KERNELRELEASE}/build
|
|
-/boot/*
|
|
|
|
%files headers
|
|
%defattr (-, root, root)
|
|
diff --git a/scripts/package/mkdebian b/scripts/package/mkdebian
|
|
index 5044224cf6714b..c1a36da85e84f6 100755
|
|
--- a/scripts/package/mkdebian
|
|
+++ b/scripts/package/mkdebian
|
|
@@ -26,7 +26,7 @@ set_debarch() {
|
|
|
|
# Attempt to find the correct Debian architecture
|
|
case "$UTS_MACHINE" in
|
|
- i386|ia64|alpha|m68k|riscv*)
|
|
+ i386|alpha|m68k|riscv*)
|
|
debarch="$UTS_MACHINE" ;;
|
|
x86_64)
|
|
debarch=amd64 ;;
|
|
diff --git a/scripts/recordmcount.c b/scripts/recordmcount.c
|
|
index 40ae6b2c7a6da5..3e4f54799cc0a5 100644
|
|
--- a/scripts/recordmcount.c
|
|
+++ b/scripts/recordmcount.c
|
|
@@ -590,7 +590,6 @@ static int do_file(char const *const fname)
|
|
ideal_nop = ideal_nop4_arm64;
|
|
is_fake_mcount64 = arm64_is_fake_mcount;
|
|
break;
|
|
- case EM_IA_64: reltype = R_IA64_IMM64; break;
|
|
case EM_MIPS: /* reltype: e_class */ break;
|
|
case EM_LOONGARCH: /* reltype: e_class */ break;
|
|
case EM_PPC: reltype = R_PPC_ADDR32; break;
|
|
diff --git a/scripts/recordmcount.pl b/scripts/recordmcount.pl
|
|
index 6a4645a5797603..f84df9e383fd0a 100755
|
|
--- a/scripts/recordmcount.pl
|
|
+++ b/scripts/recordmcount.pl
|
|
@@ -275,13 +275,6 @@ if ($arch eq "x86_64") {
|
|
$section_type = '%progbits';
|
|
$mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*R_AARCH64_CALL26\\s+_mcount\$";
|
|
$type = ".quad";
|
|
-} elsif ($arch eq "ia64") {
|
|
- $mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\s_mcount\$";
|
|
- $type = "data8";
|
|
-
|
|
- if ($is_module eq "0") {
|
|
- $cc .= " -mconstant-gp";
|
|
- }
|
|
} elsif ($arch eq "sparc64") {
|
|
# In the objdump output there are giblets like:
|
|
# 0000000000000000 <igmp_net_exit-0x18>:
|
|
diff --git a/scripts/xz_wrap.sh b/scripts/xz_wrap.sh
|
|
index 76e9cbcfbeab45..d06baf626abe79 100755
|
|
--- a/scripts/xz_wrap.sh
|
|
+++ b/scripts/xz_wrap.sh
|
|
@@ -15,7 +15,6 @@ LZMA2OPTS=
|
|
case $SRCARCH in
|
|
x86) BCJ=--x86 ;;
|
|
powerpc) BCJ=--powerpc ;;
|
|
- ia64) BCJ=--ia64; LZMA2OPTS=pb=4 ;;
|
|
arm) BCJ=--arm ;;
|
|
sparc) BCJ=--sparc ;;
|
|
esac
|
|
diff --git a/sound/pci/hda/hda_bind.c b/sound/pci/hda/hda_bind.c
|
|
index b7ca2a83fbb086..95786bdadfe6a5 100644
|
|
--- a/sound/pci/hda/hda_bind.c
|
|
+++ b/sound/pci/hda/hda_bind.c
|
|
@@ -44,7 +44,7 @@ static void hda_codec_unsol_event(struct hdac_device *dev, unsigned int ev)
|
|
struct hda_codec *codec = container_of(dev, struct hda_codec, core);
|
|
|
|
/* ignore unsol events during shutdown */
|
|
- if (codec->bus->shutdown)
|
|
+ if (codec->card->shutdown || codec->bus->shutdown)
|
|
return;
|
|
|
|
/* ignore unsol events during system suspend/resume */
|
|
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
|
|
index 3cd5b7da8e1528..059693e03fd962 100644
|
|
--- a/sound/pci/hda/hda_intel.c
|
|
+++ b/sound/pci/hda/hda_intel.c
|
|
@@ -2727,6 +2727,9 @@ static const struct pci_device_id azx_ids[] = {
|
|
{ PCI_VDEVICE(ATI, 0xab38),
|
|
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
|
|
AZX_DCAPS_PM_RUNTIME },
|
|
+ { PCI_VDEVICE(ATI, 0xab40),
|
|
+ .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
|
|
+ AZX_DCAPS_PM_RUNTIME },
|
|
/* GLENFLY */
|
|
{ PCI_DEVICE(PCI_VENDOR_ID_GLENFLY, PCI_ANY_ID),
|
|
.class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
|
|
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
|
|
index 82210b1e3b9782..0d367cec03adef 100644
|
|
--- a/sound/pci/hda/patch_realtek.c
|
|
+++ b/sound/pci/hda/patch_realtek.c
|
|
@@ -10325,6 +10325,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
|
|
SND_PCI_QUIRK(0x1043, 0x1d4e, "ASUS TM420", ALC256_FIXUP_ASUS_HPE),
|
|
SND_PCI_QUIRK(0x1043, 0x1da2, "ASUS UP6502ZA/ZD", ALC245_FIXUP_CS35L41_SPI_2),
|
|
SND_PCI_QUIRK(0x1043, 0x1e02, "ASUS UX3402ZA", ALC245_FIXUP_CS35L41_SPI_2),
|
|
+ SND_PCI_QUIRK(0x1043, 0x1e10, "ASUS VivoBook X507UAR", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE),
|
|
SND_PCI_QUIRK(0x1043, 0x1e11, "ASUS Zephyrus G15", ALC289_FIXUP_ASUS_GA502),
|
|
SND_PCI_QUIRK(0x1043, 0x1e12, "ASUS UM3402", ALC287_FIXUP_CS35L41_I2C_2),
|
|
SND_PCI_QUIRK(0x1043, 0x1e51, "ASUS Zephyrus M15", ALC294_FIXUP_ASUS_GU502_PINS),
|
|
diff --git a/sound/soc/amd/yc/acp6x-mach.c b/sound/soc/amd/yc/acp6x-mach.c
|
|
index 9fdee74c28df27..40e2b5a87916a8 100644
|
|
--- a/sound/soc/amd/yc/acp6x-mach.c
|
|
+++ b/sound/soc/amd/yc/acp6x-mach.c
|
|
@@ -353,6 +353,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
|
|
DMI_MATCH(DMI_PRODUCT_NAME, "83J2"),
|
|
}
|
|
},
|
|
+ {
|
|
+ .driver_data = &acp6x_card,
|
|
+ .matches = {
|
|
+ DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
|
|
+ DMI_MATCH(DMI_PRODUCT_NAME, "83J3"),
|
|
+ }
|
|
+ },
|
|
{
|
|
.driver_data = &acp6x_card,
|
|
.matches = {
|
|
diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c
|
|
index a05b553e6472f4..8d5d186fd58022 100644
|
|
--- a/sound/soc/codecs/wcd9335.c
|
|
+++ b/sound/soc/codecs/wcd9335.c
|
|
@@ -16,7 +16,7 @@
|
|
#include <sound/soc.h>
|
|
#include <sound/pcm_params.h>
|
|
#include <sound/soc-dapm.h>
|
|
-#include <linux/of_gpio.h>
|
|
+#include <linux/gpio/consumer.h>
|
|
#include <linux/of.h>
|
|
#include <linux/of_irq.h>
|
|
#include <sound/tlv.h>
|
|
@@ -329,8 +329,7 @@ struct wcd9335_codec {
|
|
int comp_enabled[COMPANDER_MAX];
|
|
|
|
int intr1;
|
|
- int reset_gpio;
|
|
- struct regulator_bulk_data supplies[WCD9335_MAX_SUPPLY];
|
|
+ struct gpio_desc *reset_gpio;
|
|
|
|
unsigned int rx_port_value[WCD9335_RX_MAX];
|
|
unsigned int tx_port_value[WCD9335_TX_MAX];
|
|
@@ -357,6 +356,10 @@ struct wcd9335_irq {
|
|
char *name;
|
|
};
|
|
|
|
+static const char * const wcd9335_supplies[] = {
|
|
+ "vdd-buck", "vdd-buck-sido", "vdd-tx", "vdd-rx", "vdd-io",
|
|
+};
|
|
+
|
|
static const struct wcd9335_slim_ch wcd9335_tx_chs[WCD9335_TX_MAX] = {
|
|
WCD9335_SLIM_TX_CH(0),
|
|
WCD9335_SLIM_TX_CH(1),
|
|
@@ -5032,53 +5035,30 @@ static const struct regmap_irq_chip wcd9335_regmap_irq1_chip = {
|
|
static int wcd9335_parse_dt(struct wcd9335_codec *wcd)
|
|
{
|
|
struct device *dev = wcd->dev;
|
|
- struct device_node *np = dev->of_node;
|
|
int ret;
|
|
|
|
- wcd->reset_gpio = of_get_named_gpio(np, "reset-gpios", 0);
|
|
- if (wcd->reset_gpio < 0) {
|
|
- dev_err(dev, "Reset GPIO missing from DT\n");
|
|
- return wcd->reset_gpio;
|
|
- }
|
|
+ wcd->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
|
|
+ if (IS_ERR(wcd->reset_gpio))
|
|
+ return dev_err_probe(dev, PTR_ERR(wcd->reset_gpio), "Reset GPIO missing from DT\n");
|
|
|
|
wcd->mclk = devm_clk_get(dev, "mclk");
|
|
- if (IS_ERR(wcd->mclk)) {
|
|
- dev_err(dev, "mclk not found\n");
|
|
- return PTR_ERR(wcd->mclk);
|
|
- }
|
|
+ if (IS_ERR(wcd->mclk))
|
|
+ return dev_err_probe(dev, PTR_ERR(wcd->mclk), "mclk not found\n");
|
|
|
|
wcd->native_clk = devm_clk_get(dev, "slimbus");
|
|
- if (IS_ERR(wcd->native_clk)) {
|
|
- dev_err(dev, "slimbus clock not found\n");
|
|
- return PTR_ERR(wcd->native_clk);
|
|
- }
|
|
+ if (IS_ERR(wcd->native_clk))
|
|
+ return dev_err_probe(dev, PTR_ERR(wcd->native_clk), "slimbus clock not found\n");
|
|
|
|
- wcd->supplies[0].supply = "vdd-buck";
|
|
- wcd->supplies[1].supply = "vdd-buck-sido";
|
|
- wcd->supplies[2].supply = "vdd-tx";
|
|
- wcd->supplies[3].supply = "vdd-rx";
|
|
- wcd->supplies[4].supply = "vdd-io";
|
|
-
|
|
- ret = regulator_bulk_get(dev, WCD9335_MAX_SUPPLY, wcd->supplies);
|
|
- if (ret) {
|
|
- dev_err(dev, "Failed to get supplies: err = %d\n", ret);
|
|
- return ret;
|
|
- }
|
|
+ ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(wcd9335_supplies),
|
|
+ wcd9335_supplies);
|
|
+ if (ret)
|
|
+ return dev_err_probe(dev, ret, "Failed to get and enable supplies\n");
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int wcd9335_power_on_reset(struct wcd9335_codec *wcd)
|
|
{
|
|
- struct device *dev = wcd->dev;
|
|
- int ret;
|
|
-
|
|
- ret = regulator_bulk_enable(WCD9335_MAX_SUPPLY, wcd->supplies);
|
|
- if (ret) {
|
|
- dev_err(dev, "Failed to get supplies: err = %d\n", ret);
|
|
- return ret;
|
|
- }
|
|
-
|
|
/*
|
|
* For WCD9335, it takes about 600us for the Vout_A and
|
|
* Vout_D to be ready after BUCK_SIDO is powered up.
|
|
@@ -5088,9 +5068,9 @@ static int wcd9335_power_on_reset(struct wcd9335_codec *wcd)
|
|
*/
|
|
usleep_range(600, 650);
|
|
|
|
- gpio_direction_output(wcd->reset_gpio, 0);
|
|
+ gpiod_set_value(wcd->reset_gpio, 1);
|
|
msleep(20);
|
|
- gpio_set_value(wcd->reset_gpio, 1);
|
|
+ gpiod_set_value(wcd->reset_gpio, 0);
|
|
msleep(20);
|
|
|
|
return 0;
|
|
@@ -5163,10 +5143,8 @@ static int wcd9335_slim_probe(struct slim_device *slim)
|
|
|
|
wcd->dev = dev;
|
|
ret = wcd9335_parse_dt(wcd);
|
|
- if (ret) {
|
|
- dev_err(dev, "Error parsing DT: %d\n", ret);
|
|
+ if (ret)
|
|
return ret;
|
|
- }
|
|
|
|
ret = wcd9335_power_on_reset(wcd);
|
|
if (ret)
|
|
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
|
|
index 0b8b20550ab381..f19c808444c97a 100644
|
|
--- a/sound/usb/quirks.c
|
|
+++ b/sound/usb/quirks.c
|
|
@@ -2182,6 +2182,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
|
|
QUIRK_FLAG_DISABLE_AUTOSUSPEND),
|
|
DEVICE_FLG(0x17aa, 0x104d, /* Lenovo ThinkStation P620 Internal Speaker + Front Headset */
|
|
QUIRK_FLAG_DISABLE_AUTOSUSPEND),
|
|
+ DEVICE_FLG(0x17ef, 0x3083, /* Lenovo TBT3 dock */
|
|
+ QUIRK_FLAG_GET_SAMPLE_RATE),
|
|
DEVICE_FLG(0x1852, 0x5062, /* Luxman D-08u */
|
|
QUIRK_FLAG_ITF_USB_DSD_DAC | QUIRK_FLAG_CTL_MSG_DELAY),
|
|
DEVICE_FLG(0x1852, 0x5065, /* Luxman DA-06 */
|
|
diff --git a/sound/usb/stream.c b/sound/usb/stream.c
|
|
index e14c725acebf2c..0f1558ef855535 100644
|
|
--- a/sound/usb/stream.c
|
|
+++ b/sound/usb/stream.c
|
|
@@ -982,6 +982,8 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip,
|
|
* and request Cluster Descriptor
|
|
*/
|
|
wLength = le16_to_cpu(hc_header.wLength);
|
|
+ if (wLength < sizeof(cluster))
|
|
+ return NULL;
|
|
cluster = kzalloc(wLength, GFP_KERNEL);
|
|
if (!cluster)
|
|
return ERR_PTR(-ENOMEM);
|
|
diff --git a/tools/lib/bpf/btf_dump.c b/tools/lib/bpf/btf_dump.c
|
|
index ebf56d21d08eed..cf4db51b99eb5d 100644
|
|
--- a/tools/lib/bpf/btf_dump.c
|
|
+++ b/tools/lib/bpf/btf_dump.c
|
|
@@ -225,6 +225,9 @@ static void btf_dump_free_names(struct hashmap *map)
|
|
size_t bkt;
|
|
struct hashmap_entry *cur;
|
|
|
|
+ if (!map)
|
|
+ return;
|
|
+
|
|
hashmap__for_each_entry(map, cur, bkt)
|
|
free((void *)cur->pkey);
|
|
|
|
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
|
|
index 5dc2e555533586..aefbfa2df6207c 100644
|
|
--- a/tools/lib/bpf/libbpf.c
|
|
+++ b/tools/lib/bpf/libbpf.c
|
|
@@ -554,7 +554,7 @@ struct extern_desc {
|
|
int sym_idx;
|
|
int btf_id;
|
|
int sec_btf_id;
|
|
- const char *name;
|
|
+ char *name;
|
|
char *essent_name;
|
|
bool is_set;
|
|
bool is_weak;
|
|
@@ -3822,7 +3822,9 @@ static int bpf_object__collect_externs(struct bpf_object *obj)
|
|
return ext->btf_id;
|
|
}
|
|
t = btf__type_by_id(obj->btf, ext->btf_id);
|
|
- ext->name = btf__name_by_offset(obj->btf, t->name_off);
|
|
+ ext->name = strdup(btf__name_by_offset(obj->btf, t->name_off));
|
|
+ if (!ext->name)
|
|
+ return -ENOMEM;
|
|
ext->sym_idx = i;
|
|
ext->is_weak = ELF64_ST_BIND(sym->st_info) == STB_WEAK;
|
|
|
|
@@ -8457,8 +8459,10 @@ void bpf_object__close(struct bpf_object *obj)
|
|
zfree(&obj->btf_custom_path);
|
|
zfree(&obj->kconfig);
|
|
|
|
- for (i = 0; i < obj->nr_extern; i++)
|
|
+ for (i = 0; i < obj->nr_extern; i++) {
|
|
+ zfree(&obj->externs[i].name);
|
|
zfree(&obj->externs[i].essent_name);
|
|
+ }
|
|
|
|
zfree(&obj->externs);
|
|
obj->nr_extern = 0;
|
|
diff --git a/tools/testing/selftests/bpf/progs/test_global_map_resize.c b/tools/testing/selftests/bpf/progs/test_global_map_resize.c
|
|
index 1fbb73d3e5d5a0..9be0e32cfeeea4 100644
|
|
--- a/tools/testing/selftests/bpf/progs/test_global_map_resize.c
|
|
+++ b/tools/testing/selftests/bpf/progs/test_global_map_resize.c
|
|
@@ -31,6 +31,16 @@ int my_int_last SEC(".data.array_not_last");
|
|
|
|
int percpu_arr[1] SEC(".data.percpu_arr");
|
|
|
|
+/* at least one extern is included, to ensure that a specific
|
|
+ * regression is tested whereby resizing resulted in a free-after-use
|
|
+ * bug after type information is invalidated by the resize operation.
|
|
+ *
|
|
+ * There isn't a particularly good API to test for this specific condition,
|
|
+ * but by having externs for the resizing tests it will cover this path.
|
|
+ */
|
|
+extern int LINUX_KERNEL_VERSION __kconfig;
|
|
+long version_sink;
|
|
+
|
|
SEC("tp/syscalls/sys_enter_getpid")
|
|
int bss_array_sum(void *ctx)
|
|
{
|
|
@@ -43,6 +53,9 @@ int bss_array_sum(void *ctx)
|
|
for (size_t i = 0; i < bss_array_len; ++i)
|
|
sum += array[i];
|
|
|
|
+ /* see above; ensure this is not optimized out */
|
|
+ version_sink = LINUX_KERNEL_VERSION;
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
@@ -58,5 +71,8 @@ int data_array_sum(void *ctx)
|
|
for (size_t i = 0; i < data_array_len; ++i)
|
|
sum += my_array[i];
|
|
|
|
+ /* see above; ensure this is not optimized out */
|
|
+ version_sink = LINUX_KERNEL_VERSION;
|
|
+
|
|
return 0;
|
|
}
|