diff options
74 files changed, 1282 insertions, 218 deletions
diff --git a/Documentation/ABI/testing/sysfs-devices-platform-trackpoint b/Documentation/ABI/testing/sysfs-devices-platform-trackpoint index df11901a6b3d..7954434b0434 100644 --- a/Documentation/ABI/testing/sysfs-devices-platform-trackpoint +++ b/Documentation/ABI/testing/sysfs-devices-platform-trackpoint @@ -5,7 +5,7 @@ Contact: linux-input@vger.kernel.org Description: (RW) Trackpoint sensitivity. -What: /sys/devices/platform/i8042/.../intertia +What: /sys/devices/platform/i8042/.../inertia Date: Aug, 2005 KernelVersion: 2.6.14 Contact: linux-input@vger.kernel.org diff --git a/Documentation/devicetree/bindings/input/mediatek,mt6779-keypad.yaml b/Documentation/devicetree/bindings/input/mediatek,mt6779-keypad.yaml index 914dd3283df3..20fa41f691ed 100644 --- a/Documentation/devicetree/bindings/input/mediatek,mt6779-keypad.yaml +++ b/Documentation/devicetree/bindings/input/mediatek,mt6779-keypad.yaml @@ -26,6 +26,7 @@ properties: - const: mediatek,mt6779-keypad - items: - enum: + - mediatek,mt6572-keypad - mediatek,mt6873-keypad - mediatek,mt8183-keypad - mediatek,mt8365-keypad diff --git a/arch/x86/Kconfig.cpu b/arch/x86/Kconfig.cpu index e4654388d794..6e7a366f0798 100644 --- a/arch/x86/Kconfig.cpu +++ b/arch/x86/Kconfig.cpu @@ -204,10 +204,21 @@ config CC_HAS_MARCH_NATIVE # usage warnings that only appear wth '-march=native'. depends on CC_IS_GCC || CLANG_VERSION >= 190100 +config RUSTC_HAS_APXF + # The kernel isn't ready for in-kernel APX instructions. Without + # explicit frontend gating of APX, the backend may emit those + # instructions in native builds. + # + # Rust 1.88 added the `apxf` feature option, but versions before 1.93 + # emit an `apxf` target attribute that only LLVM 23+ can interpret. + def_bool (RUSTC_VERSION >= 108800 && RUSTC_LLVM_MAJOR_VERSION >= 23) || \ + RUSTC_VERSION >= 109300 + config X86_NATIVE_CPU bool "Build and optimize for local/native CPU" depends on X86_64 depends on CC_HAS_MARCH_NATIVE + depends on !RUST || RUSTC_HAS_APXF help Optimize for the current CPU used to compile the kernel. Use this option if you intend to build the kernel for your diff --git a/arch/x86/Makefile b/arch/x86/Makefile index 598f178102ee..8af6b80cffdd 100644 --- a/arch/x86/Makefile +++ b/arch/x86/Makefile @@ -161,6 +161,11 @@ else ifdef CONFIG_X86_NATIVE_CPU KBUILD_CFLAGS += -march=native + # Prevent the compiler from generating EGPR use. The kernel is + # not yet prepared for general in-kernel use. + KBUILD_CFLAGS += $(call cc-option,-mno-apx-features=egpr) + + # generate_rust_target.rs handles Rust APX gating. KBUILD_RUSTFLAGS += -Ctarget-cpu=native else KBUILD_CFLAGS += -march=x86-64 -mtune=generic diff --git a/arch/x86/entry/entry_fred.c b/arch/x86/entry/entry_fred.c index fb3594ddf731..854899bfec5d 100644 --- a/arch/x86/entry/entry_fred.c +++ b/arch/x86/entry/entry_fred.c @@ -10,6 +10,7 @@ #include <asm/desc.h> #include <asm/fred.h> #include <asm/idtentry.h> +#include <asm/processor-flags.h> #include <asm/syscall.h> #include <asm/trapnr.h> #include <asm/traps.h> @@ -71,7 +72,15 @@ static noinstr void fred_intx(struct pt_regs *regs) #endif default: - return exc_general_protection(regs, 0); + /* + * Reconstruct the #GP fault state that IDT delivery would produce. + * Clear the software event flag so ERETU with TF set does not trap + * before the resumed instruction. See prevent_single_step_upon_eretu(). + */ + regs->ip -= regs->fred_ss.insnlen; + regs->flags |= X86_EFLAGS_RF; + regs->fred_ss.swevent = 0; + return exc_general_protection(regs, (regs->fred_ss.vector << 3) | 2); } } diff --git a/arch/x86/include/asm/text-patching.h b/arch/x86/include/asm/text-patching.h index f2d142a0a862..ea09381070e8 100644 --- a/arch/x86/include/asm/text-patching.h +++ b/arch/x86/include/asm/text-patching.h @@ -164,9 +164,9 @@ unsigned long int3_emulate_pop(struct pt_regs *regs) } static __always_inline -void int3_emulate_call(struct pt_regs *regs, unsigned long func) +void int3_emulate_call(struct pt_regs *regs, unsigned long ip, unsigned long func) { - int3_emulate_push(regs, regs->ip - INT3_INSN_SIZE + CALL_INSN_SIZE); + int3_emulate_push(regs, ip); int3_emulate_jmp(regs, func); } diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c index 741d8767ddf8..582c6d8307d1 100644 --- a/arch/x86/kernel/alternative.c +++ b/arch/x86/kernel/alternative.c @@ -2176,6 +2176,7 @@ int3_exception_notify(struct notifier_block *self, unsigned long val, void *data unsigned long selftest = (unsigned long)&int3_selftest_asm; struct die_args *args = data; struct pt_regs *regs = args->regs; + unsigned long ip; OPTIMIZER_HIDE_VAR(selftest); @@ -2188,7 +2189,8 @@ int3_exception_notify(struct notifier_block *self, unsigned long val, void *data if (regs->ip - INT3_INSN_SIZE != selftest) return NOTIFY_DONE; - int3_emulate_call(regs, (unsigned long)&int3_selftest_callee); + ip = regs->ip - INT3_INSN_SIZE + CALL_INSN_SIZE; + int3_emulate_call(regs, ip, (unsigned long)&int3_selftest_callee); return NOTIFY_STOP; } @@ -2758,7 +2760,7 @@ noinstr int smp_text_poke_int3_handler(struct pt_regs *regs) break; case CALL_INSN_OPCODE: - int3_emulate_call(regs, (long)ip + tpl->disp); + int3_emulate_call(regs, (long)ip, (long)ip + tpl->disp); break; case JMP32_INSN_OPCODE: diff --git a/arch/x86/kernel/cpu/microcode/intel.c b/arch/x86/kernel/cpu/microcode/intel.c index 1142183c950c..9f09d388ed20 100644 --- a/arch/x86/kernel/cpu/microcode/intel.c +++ b/arch/x86/kernel/cpu/microcode/intel.c @@ -309,6 +309,26 @@ static void save_microcode_patch(struct microcode_intel *patch) pr_err("Unable to allocate microcode memory size: %u\n", size); } +static bool revision_is_safe(struct cpu_signature *sig, u32 rev) +{ + u32 vfm = IFM(x86_family(sig->sig), x86_model(sig->sig)); + + /* + * Erratum GNR98 can cause #MCs if "jumping over" revision 0x1000405. + * Avoid the jumps. + */ + if (vfm == INTEL_GRANITERAPIDS_X && + x86_stepping(sig->sig) == 1 && + sig->pf & 0x95 && + sig->rev < 0x1000405 && + rev > 0x1000405) { + pr_err_once("Erratum GNR98: skipping revision 0x%x.\n", rev); + return false; + } + + return true; +} + /* Scan blob for microcode matching the boot CPUs family, model, stepping */ static __init struct microcode_intel *scan_microcode(void *data, size_t size, struct ucode_cpu_info *uci, @@ -330,6 +350,9 @@ static __init struct microcode_intel *scan_microcode(void *data, size_t size, if (!intel_find_matching_signature(data, &uci->cpu_sig)) continue; + if (!revision_is_safe(&uci->cpu_sig, mc_header->rev)) + continue; + /* * For saving the early microcode, find the matching revision which * was loaded on the BSP. @@ -878,6 +901,9 @@ static enum ucode_state parse_microcode_blobs(int cpu, struct iov_iter *iter) if (!intel_find_matching_signature(mc, &uci->cpu_sig)) continue; + if (!revision_is_safe(&uci->cpu_sig, mc_header.rev)) + continue; + is_safe = ucode_validate_minrev(&mc_header); if (force_minrev && !is_safe) continue; diff --git a/arch/x86/kernel/kprobes/core.c b/arch/x86/kernel/kprobes/core.c index 4e5f8c1736ec..133ff20caccd 100644 --- a/arch/x86/kernel/kprobes/core.c +++ b/arch/x86/kernel/kprobes/core.c @@ -510,10 +510,9 @@ NOKPROBE_SYMBOL(kprobe_emulate_ret); static void kprobe_emulate_call(struct kprobe *p, struct pt_regs *regs) { - unsigned long func = regs->ip - INT3_INSN_SIZE + p->ainsn.size; + unsigned long ip = regs->ip - INT3_INSN_SIZE + p->ainsn.size; - func += p->ainsn.rel32; - int3_emulate_call(regs, func); + int3_emulate_call(regs, ip, ip + p->ainsn.rel32); } NOKPROBE_SYMBOL(kprobe_emulate_call); diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c index 6ffd8bd82154..c71763047126 100644 --- a/drivers/dma/dmaengine.c +++ b/drivers/dma/dmaengine.c @@ -428,11 +428,18 @@ static void dma_device_release(struct kref *ref) list_del_rcu(&device->global_node); dma_channel_rebalance(); + synchronize_rcu(); if (device->device_release) device->device_release(device); } +static int __must_check dma_device_get(struct dma_device *device) +{ + lockdep_assert_held(&dma_list_mutex); + return kref_get_unless_zero(&device->ref); +} + static void dma_device_put(struct dma_device *device) { lockdep_assert_held(&dma_list_mutex); @@ -460,8 +467,7 @@ static int dma_chan_get(struct dma_chan *chan) if (!try_module_get(owner)) return -ENODEV; - ret = kref_get_unless_zero(&chan->device->ref); - if (!ret) { + if (!dma_device_get(chan->device)) { ret = -ENODEV; goto module_put_out; } @@ -495,10 +501,13 @@ module_put_out: */ static void dma_chan_put(struct dma_chan *chan) { + struct module *owner; + /* This channel is not in use, bail out */ if (!chan->client_count) return; + owner = dma_chan_to_owner(chan); chan->client_count--; /* This channel is not in use anymore, free it */ @@ -515,8 +524,10 @@ static void dma_chan_put(struct dma_chan *chan) chan->route_data = NULL; } - dma_device_put(chan->device); - module_put(dma_chan_to_owner(chan)); + /* This channel is not in use anymore, drop the device ref */ + if (!chan->client_count) + dma_device_put(chan->device); + module_put(owner); } enum dma_status dma_sync_wait(struct dma_chan *chan, dma_cookie_t cookie) diff --git a/drivers/dma/mmp_pdma.c b/drivers/dma/mmp_pdma.c index 386e85cd4882..ed520737882b 100644 --- a/drivers/dma/mmp_pdma.c +++ b/drivers/dma/mmp_pdma.c @@ -52,7 +52,6 @@ #define DCSR_EORINTR BIT(9) /* The end of Receive */ #define DRCMR_BASE 0x0100 -#define DRCMR_EXT_BASE_K3 0x1000 #define DRCMR_EXT_BASE_DEFAULT 0x1100 #define DRCMR_REQ_LIMIT 64 #define DRCMR_MAPVLD BIT(7) /* Map Valid (read / write) */ @@ -713,7 +712,7 @@ mmp_pdma_prep_slave_sg(struct dma_chan *dchan, struct scatterlist *sgl, for_each_sg(sgl, sg, sg_len, i) { addr = sg_dma_address(sg); - avail = sg_dma_len(sgl); + avail = sg_dma_len(sg); do { len = min_t(size_t, avail, PDMA_MAX_DESC_BYTES); @@ -1219,7 +1218,7 @@ static const struct mmp_pdma_ops spacemit_k3_pdma_ops = { .get_desc_dst_addr = get_desc_dst_addr_64, .run_bits = (DCSR_RUN | DCSR_LPAEEN | DCSR_EORIRQEN | DCSR_EORSTOPEN), .dma_width = 64, - .drcmr_ext_base = DRCMR_EXT_BASE_K3, + .drcmr_ext_base = DRCMR_EXT_BASE_DEFAULT, }; static const struct of_device_id mmp_pdma_dt_ids[] = { diff --git a/drivers/dma/pxa_dma.c b/drivers/dma/pxa_dma.c index fa2ee0b3e09f..fc43124fefa8 100644 --- a/drivers/dma/pxa_dma.c +++ b/drivers/dma/pxa_dma.c @@ -744,6 +744,7 @@ pxad_alloc_desc(struct pxad_chan *chan, unsigned int nb_hw_desc) sw_desc = kzalloc_flex(*sw_desc, hw_desc, nb_hw_desc, GFP_NOWAIT); if (!sw_desc) return NULL; + sw_desc->nb_desc = nb_hw_desc; sw_desc->desc_pool = chan->desc_pool; for (i = 0; i < nb_hw_desc; i++) { @@ -752,10 +753,10 @@ pxad_alloc_desc(struct pxad_chan *chan, unsigned int nb_hw_desc) dev_err(&chan->vc.chan.dev->device, "%s(): Couldn't allocate the %dth hw_desc from dma_pool %p\n", __func__, i, sw_desc->desc_pool); + sw_desc->nb_desc = i; goto err; } - sw_desc->nb_desc++; sw_desc->hw_desc[i] = desc; if (i == 0) diff --git a/drivers/dma/sprd-dma.c b/drivers/dma/sprd-dma.c index 087fea3af2e4..19b32a23c882 100644 --- a/drivers/dma/sprd-dma.c +++ b/drivers/dma/sprd-dma.c @@ -1212,7 +1212,7 @@ static int sprd_dma_probe(struct platform_device *pdev) ret = pm_runtime_get_sync(&pdev->dev); if (ret < 0) - goto err_rpm; + goto err_register; ret = dma_async_device_register(&sdev->dma_dev); if (ret < 0) { @@ -1234,7 +1234,6 @@ err_of_register: err_register: pm_runtime_put_noidle(&pdev->dev); pm_runtime_disable(&pdev->dev); -err_rpm: sprd_dma_disable(sdev); return ret; } diff --git a/drivers/dma/sun6i-dma.c b/drivers/dma/sun6i-dma.c index f47a326dd7ff..7704b016aed8 100644 --- a/drivers/dma/sun6i-dma.c +++ b/drivers/dma/sun6i-dma.c @@ -354,8 +354,10 @@ static size_t sun6i_get_chan_size(struct sun6i_pchan *pchan) size_t bytes; dma_addr_t pos; - pos = readl(pchan->base + DMA_CHAN_LLI_ADDR); - bytes = readl(pchan->base + DMA_CHAN_CUR_CNT); + do { + pos = readl(pchan->base + DMA_CHAN_LLI_ADDR); + bytes = readl(pchan->base + DMA_CHAN_CUR_CNT); + } while (pos != readl(pchan->base + DMA_CHAN_LLI_ADDR)); if (pos == LLI_LAST_ITEM) return bytes; @@ -979,7 +981,6 @@ static enum dma_status sun6i_dma_tx_status(struct dma_chan *chan, struct sun6i_pchan *pchan = vchan->phy; struct sun6i_dma_lli *lli; struct virt_dma_desc *vd; - struct sun6i_desc *txd; enum dma_status ret; unsigned long flags; size_t bytes = 0; @@ -991,9 +992,9 @@ static enum dma_status sun6i_dma_tx_status(struct dma_chan *chan, spin_lock_irqsave(&vchan->vc.lock, flags); vd = vchan_find_desc(&vchan->vc, cookie); - txd = to_sun6i_desc(&vd->tx); if (vd) { + struct sun6i_desc *txd = to_sun6i_desc(&vd->tx); for (lli = txd->v_lli; lli != NULL; lli = lli->v_lli_next) bytes += lli->len; } else if (!pchan || !pchan->desc) { diff --git a/drivers/dma/ti/k3-udma-glue.c b/drivers/dma/ti/k3-udma-glue.c index 686dc140293e..70eaf7ee57e6 100644 --- a/drivers/dma/ti/k3-udma-glue.c +++ b/drivers/dma/ti/k3-udma-glue.c @@ -1243,8 +1243,9 @@ void k3_udma_glue_release_rx_chn(struct k3_udma_glue_rx_channel *rx_chn) rx_chn->psil_paired = false; } - for (i = 0; i < rx_chn->flow_num; i++) - k3_udma_glue_release_rx_flow(rx_chn, i); + if (rx_chn->flows) + for (i = 0; i < rx_chn->flow_num; i++) + k3_udma_glue_release_rx_flow(rx_chn, i); if (xudma_rflow_is_gp(rx_chn->common.udmax, rx_chn->flow_id_base)) xudma_free_gp_rflow_range(rx_chn->common.udmax, diff --git a/drivers/dma/xilinx/xilinx_dma.c b/drivers/dma/xilinx/xilinx_dma.c index bef2b031dba1..cffe7c6fa640 100644 --- a/drivers/dma/xilinx/xilinx_dma.c +++ b/drivers/dma/xilinx/xilinx_dma.c @@ -756,15 +756,25 @@ xilinx_aximcdma_alloc_tx_segment(struct xilinx_dma_chan *chan) return segment; } -static void xilinx_dma_clean_hw_desc(struct xilinx_axidma_desc_hw *hw) +static void xilinx_dma_clean_hw_desc(struct xilinx_dma_chan *chan, + struct xilinx_axidma_tx_segment *segment) { - u32 next_desc = hw->next_desc; - u32 next_desc_msb = hw->next_desc_msb; + dma_addr_t next; + u32 i; - memset(hw, 0, sizeof(struct xilinx_axidma_desc_hw)); + /* + * Restore the buffer descriptor's next descriptor pointer to the value + * set up in xilinx_dma_alloc_chan_resources(). Otherwise using the DMA + * in cyclic mode leaves the next descriptor pointer altered and + * prevents subsequent non-cyclic transfers. + */ + i = segment - chan->seg_v; + next = chan->seg_p + + sizeof(*chan->seg_v) * ((i + 1) % XILINX_DMA_NUM_DESCS); - hw->next_desc = next_desc; - hw->next_desc_msb = next_desc_msb; + memset(&segment->hw, 0, sizeof(segment->hw)); + segment->hw.next_desc = lower_32_bits(next); + segment->hw.next_desc_msb = upper_32_bits(next); } static void xilinx_mcdma_clean_hw_desc(struct xilinx_aximcdma_desc_hw *hw) @@ -786,7 +796,7 @@ static void xilinx_mcdma_clean_hw_desc(struct xilinx_aximcdma_desc_hw *hw) static void xilinx_dma_free_tx_segment(struct xilinx_dma_chan *chan, struct xilinx_axidma_tx_segment *segment) { - xilinx_dma_clean_hw_desc(&segment->hw); + xilinx_dma_clean_hw_desc(chan, segment); list_add_tail(&segment->node, &chan->free_seg_list); } @@ -920,9 +930,9 @@ static void xilinx_dma_free_descriptors(struct xilinx_dma_chan *chan) spin_lock_irqsave(&chan->lock, flags); - xilinx_dma_free_desc_list(chan, &chan->pending_list); xilinx_dma_free_desc_list(chan, &chan->done_list); xilinx_dma_free_desc_list(chan, &chan->active_list); + xilinx_dma_free_desc_list(chan, &chan->pending_list); spin_unlock_irqrestore(&chan->lock, flags); } diff --git a/drivers/i2c/busses/i2c-at91-core.c b/drivers/i2c/busses/i2c-at91-core.c index b64adef778d4..8ca4556d9664 100644 --- a/drivers/i2c/busses/i2c-at91-core.c +++ b/drivers/i2c/busses/i2c-at91-core.c @@ -255,6 +255,7 @@ static int at91_twi_probe(struct platform_device *pdev) if (rc) { pm_runtime_disable(dev->dev); pm_runtime_set_suspended(dev->dev); + at91_twi_dma_release(dev); return rc; } @@ -270,6 +271,8 @@ static void at91_twi_remove(struct platform_device *pdev) i2c_del_adapter(&dev->adapter); + at91_twi_dma_release(dev); + pm_runtime_disable(dev->dev); pm_runtime_set_suspended(dev->dev); } diff --git a/drivers/i2c/busses/i2c-at91-master.c b/drivers/i2c/busses/i2c-at91-master.c index 894cedbca99f..68238cc8aee0 100644 --- a/drivers/i2c/busses/i2c-at91-master.c +++ b/drivers/i2c/busses/i2c-at91-master.c @@ -817,11 +817,21 @@ static int at91_twi_configure_dma(struct at91_twi_dev *dev, u32 phy_addr) error: if (ret != -EPROBE_DEFER) dev_info(dev->dev, "can't get DMA channel, continue without DMA support\n"); + at91_twi_dma_release(dev); + return ret; +} + +void at91_twi_dma_release(struct at91_twi_dev *dev) +{ + struct at91_twi_dma *dma = &dev->dma; + if (dma->chan_rx) dma_release_channel(dma->chan_rx); if (dma->chan_tx) dma_release_channel(dma->chan_tx); - return ret; + dma->chan_rx = NULL; + dma->chan_tx = NULL; + dev->use_dma = false; } static int at91_init_twi_recovery_gpio(struct platform_device *pdev, diff --git a/drivers/i2c/busses/i2c-at91.h b/drivers/i2c/busses/i2c-at91.h index 942e9c3973bb..d68fcbbc3e0f 100644 --- a/drivers/i2c/busses/i2c-at91.h +++ b/drivers/i2c/busses/i2c-at91.h @@ -172,6 +172,7 @@ void at91_twi_irq_restore(struct at91_twi_dev *dev); void at91_init_twi_bus(struct at91_twi_dev *dev); void at91_init_twi_bus_master(struct at91_twi_dev *dev); +void at91_twi_dma_release(struct at91_twi_dev *dev); int at91_twi_probe_master(struct platform_device *pdev, u32 phy_addr, struct at91_twi_dev *dev); diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index 19ec056b00af..ff5a91158df9 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -1880,6 +1880,8 @@ static int i2c_imx_probe(struct platform_device *pdev) clk_notifier_unregister: clk_notifier_unregister(i2c_imx->clk, &i2c_imx->clk_change_nb); + if (i2c_imx->dma) + i2c_imx_dma_free(i2c_imx); free_irq(irq, i2c_imx); rpm_disable: pm_runtime_put_noidle(&pdev->dev); @@ -1920,6 +1922,7 @@ static void i2c_imx_remove(struct platform_device *pdev) pm_runtime_put_noidle(&pdev->dev); pm_runtime_disable(&pdev->dev); + pm_runtime_dont_use_autosuspend(&pdev->dev); } static int i2c_imx_runtime_suspend(struct device *dev) diff --git a/drivers/i2c/busses/i2c-qcom-cci.c b/drivers/i2c/busses/i2c-qcom-cci.c index 25b6e4e9e3fa..873e901a23d7 100644 --- a/drivers/i2c/busses/i2c-qcom-cci.c +++ b/drivers/i2c/busses/i2c-qcom-cci.c @@ -497,10 +497,14 @@ static const struct dev_pm_ops qcom_cci_pm = { SET_RUNTIME_PM_OPS(cci_suspend_runtime, cci_resume_runtime, NULL) }; +static void cci_put_of_node(void *data) +{ + of_node_put(data); +} + static int cci_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct device_node *child; struct resource *r; struct cci *cci; int ret, i; @@ -516,7 +520,7 @@ static int cci_probe(struct platform_device *pdev) if (!cci->data) return -ENOENT; - for_each_available_child_of_node(dev->of_node, child) { + for_each_available_child_of_node_scoped(dev->of_node, child) { struct cci_master *master; u32 idx; @@ -537,6 +541,9 @@ static int cci_probe(struct platform_device *pdev) master->adap.algo = &cci_algo; master->adap.dev.parent = dev; master->adap.dev.of_node = of_node_get(child); + ret = devm_add_action_or_reset(dev, cci_put_of_node, child); + if (ret) + return ret; master->master = idx; master->cci = cci; @@ -606,10 +613,8 @@ static int cci_probe(struct platform_device *pdev) continue; ret = i2c_add_adapter(&cci->master[i].adap); - if (ret < 0) { - of_node_put(cci->master[i].adap.dev.of_node); + if (ret < 0) goto error_i2c; - } } return 0; @@ -617,10 +622,8 @@ static int cci_probe(struct platform_device *pdev) error_i2c: for (--i ; i >= 0; i--) { - if (cci->master[i].cci) { + if (cci->master[i].cci) i2c_del_adapter(&cci->master[i].adap); - of_node_put(cci->master[i].adap.dev.of_node); - } } disable_clocks: cci_disable_clocks(cci); @@ -636,7 +639,6 @@ static void cci_remove(struct platform_device *pdev) for (i = 0; i < cci->data->num_masters; i++) { if (cci->master[i].cci) { i2c_del_adapter(&cci->master[i].adap); - of_node_put(cci->master[i].adap.dev.of_node); cci_halt(cci, i); } } diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c index 00013b41a6f5..e9e41a174c20 100644 --- a/drivers/i2c/busses/i2c-qcom-geni.c +++ b/drivers/i2c/busses/i2c-qcom-geni.c @@ -1189,8 +1189,10 @@ static int geni_i2c_probe(struct platform_device *pdev) return ret; ret = i2c_add_adapter(&gi2c->adap); - if (ret) + if (ret) { + release_gpi_dma(gi2c); return dev_err_probe(dev, ret, "Error adding i2c adapter\n"); + } dev_dbg(dev, "Geni-I2C adaptor successfully added\n"); diff --git a/drivers/i2c/i2c-atr.c b/drivers/i2c/i2c-atr.c index e6d2af659d81..ca29633dcd62 100644 --- a/drivers/i2c/i2c-atr.c +++ b/drivers/i2c/i2c-atr.c @@ -855,6 +855,7 @@ int i2c_atr_add_adapter(struct i2c_atr *atr, struct i2c_atr_adap_desc *desc) ret = i2c_add_adapter(&chan->adap); if (ret) { + atr->adapter[chan_id] = NULL; dev_err(dev, "failed to add atr-adapter %u (error=%d)\n", chan_id, ret); goto err_free_alias_pool; diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 3a718d600006..8bfaaa45e0b9 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -1229,6 +1229,8 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd, t = _IOC_NR(cmd) & ABS_MAX; + memset(&abs, 0, sizeof(abs)); + if (copy_from_user(&abs, p, min_t(size_t, size, sizeof(struct input_absinfo)))) return -EFAULT; diff --git a/drivers/input/input-compat.c b/drivers/input/input-compat.c index a5043193ead8..8860a0730294 100644 --- a/drivers/input/input-compat.c +++ b/drivers/input/input-compat.c @@ -76,6 +76,8 @@ int input_ff_effect_from_user(const char __user *buffer, size_t size, */ compat_effect = (struct ff_effect_compat *)effect; + memset(effect, 0, sizeof(*effect)); + if (copy_from_user(compat_effect, buffer, sizeof(struct ff_effect_compat))) return -EFAULT; diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index 2da0b7f1722a..6406ceab988a 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -215,7 +215,7 @@ static const struct xpad_device { { 0x0e6f, 0x0139, "Afterglow Prismatic Wired Controller", 0, XTYPE_XBOXONE }, { 0x0e6f, 0x013a, "PDP Xbox One Controller", 0, XTYPE_XBOXONE }, { 0x0e6f, 0x0146, "Rock Candy Wired Controller for Xbox One", 0, XTYPE_XBOXONE }, - { 0x0e6f, 0x0147, "PDP Marvel Xbox One Controller", 0, XTYPE_XBOXONE }, + { 0x0e6f, 0x0147, "PDP Marvel Xbox 360 Controller", 0, XTYPE_XBOX360 }, { 0x0e6f, 0x015c, "PDP Xbox One Arcade Stick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOXONE }, { 0x0e6f, 0x015d, "PDP Mirror's Edge Official Wired Controller for Xbox One", 0, XTYPE_XBOXONE }, { 0x0e6f, 0x0161, "PDP Xbox One Controller", 0, XTYPE_XBOXONE }, @@ -227,6 +227,7 @@ static const struct xpad_device { { 0x0e6f, 0x0213, "Afterglow Gamepad for Xbox 360", 0, XTYPE_XBOX360 }, { 0x0e6f, 0x021f, "Rock Candy Gamepad for Xbox 360", 0, XTYPE_XBOX360 }, { 0x0e6f, 0x0246, "Rock Candy Gamepad for Xbox One 2015", 0, XTYPE_XBOXONE }, + { 0x0e6f, 0x024c, "PDP Victrix Pro BFG Wired Controller for Xbox", 0, XTYPE_XBOXONE }, { 0x0e6f, 0x02a0, "PDP Xbox One Controller", 0, XTYPE_XBOXONE }, { 0x0e6f, 0x02a1, "PDP Xbox One Controller", 0, XTYPE_XBOXONE }, { 0x0e6f, 0x02a2, "PDP Wired Controller for Xbox One - Crimson Red", 0, XTYPE_XBOXONE }, @@ -292,6 +293,12 @@ static const struct xpad_device { { 0x1689, 0xfd00, "Razer Onza Tournament Edition", 0, XTYPE_XBOX360 }, { 0x1689, 0xfd01, "Razer Onza Classic Edition", 0, XTYPE_XBOX360 }, { 0x1689, 0xfe00, "Razer Sabertooth", 0, XTYPE_XBOX360 }, + { 0x16d0, 0x1103, "Azeron Cyro", 0, XTYPE_XBOX360 }, + { 0x16d0, 0x113c, "Azeron Cyborg", 0, XTYPE_XBOX360 }, + { 0x16d0, 0x1192, "Azeron Classic/Compact", 0, XTYPE_XBOX360 }, + { 0x16d0, 0x1212, "Azeron Cyro Lefty", 0, XTYPE_XBOX360 }, + { 0x16d0, 0x12f7, "Azeron Cyborg II", 0, XTYPE_XBOX360 }, + { 0x16d0, 0x13ea, "Azeron Keyzen", 0, XTYPE_XBOX360 }, { 0x17ef, 0x6182, "Lenovo Legion Controller for Windows", 0, XTYPE_XBOX360 }, { 0x1949, 0x041a, "Amazon Game Controller", 0, XTYPE_XBOX360 }, { 0x1a86, 0xe310, "Legion Go S", 0, XTYPE_XBOX360 }, @@ -534,6 +541,7 @@ static const struct usb_device_id xpad_table[] = { XPAD_XBOX360_VENDOR(0x15e4), /* Numark Xbox 360 controllers */ XPAD_XBOX360_VENDOR(0x162e), /* Joytech Xbox 360 controllers */ XPAD_XBOX360_VENDOR(0x1689), /* Razer Onza */ + XPAD_XBOX360_VENDOR(0x16d0), /* Azeron controllers */ XPAD_XBOX360_VENDOR(0x17ef), /* Lenovo */ XPAD_XBOX360_VENDOR(0x1949), /* Amazon controllers */ XPAD_XBOX360_VENDOR(0x1a86), /* Nanjing Qinheng Microelectronics (WCH) */ diff --git a/drivers/input/keyboard/adp5588-keys.c b/drivers/input/keyboard/adp5588-keys.c index 40371f5bd9ba..4f0ddff5baba 100644 --- a/drivers/input/keyboard/adp5588-keys.c +++ b/drivers/input/keyboard/adp5588-keys.c @@ -446,12 +446,6 @@ static int adp5588_gpio_add(struct adp5588_kpad *kpad) mutex_init(&kpad->gpio_lock); - error = devm_gpiochip_add_data(dev, &kpad->gc, kpad); - if (error) { - dev_err(dev, "gpiochip_add failed: %d\n", error); - return error; - } - for (i = 0; i <= ADP5588_BANK(ADP5588_MAXGPIO); i++) { kpad->dat_out[i] = adp5588_read(kpad->client, GPIO_DAT_OUT1 + i); @@ -459,6 +453,12 @@ static int adp5588_gpio_add(struct adp5588_kpad *kpad) kpad->pull_dis[i] = adp5588_read(kpad->client, GPIO_PULL1 + i); } + error = devm_gpiochip_add_data(dev, &kpad->gc, kpad); + if (error) { + dev_err(dev, "gpiochip_add failed: %d\n", error); + return error; + } + return 0; } diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c index b9ad2381f885..93650c98206d 100644 --- a/drivers/input/keyboard/atkbd.c +++ b/drivers/input/keyboard/atkbd.c @@ -1946,6 +1946,14 @@ static const struct dmi_system_id atkbd_dmi_quirk_table[] __initconst = { }, .callback = atkbd_deactivate_fixup, }, + { + /* Xiaomi Redmi Book Pro 16 2026 (TM2425) */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "XIAOMI"), + DMI_MATCH(DMI_PRODUCT_NAME, "REDMI Book Pro 16 2026"), + }, + .callback = atkbd_deactivate_fixup, + }, { } }; diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c index a6c984205123..064243677fcf 100644 --- a/drivers/input/misc/soc_button_array.c +++ b/drivers/input/misc/soc_button_array.c @@ -15,6 +15,7 @@ #include <linux/dmi.h> #include <linux/gpio/consumer.h> #include <linux/gpio_keys.h> +#include <linux/platform_data/x86/soc.h> #include <linux/platform_device.h> static bool use_low_level_irq; @@ -159,7 +160,7 @@ soc_button_device_create(struct platform_device *pdev, struct gpio_keys_platform_data *gpio_keys_pdata; const struct dmi_system_id *dmi_id; int invalid_acpi_index = -1; - int error, gpio, irq; + int error, gpio, irq = 0; int n_buttons = 0; for (info = button_info; info->name; info++) @@ -190,8 +191,9 @@ soc_button_device_create(struct platform_device *pdev, error = soc_button_lookup_gpio(&pdev->dev, info->acpi_index, &gpio, &irq); if (error || irq < 0) { /* - * Skip GPIO if not present. Note we deliberately - * ignore -EPROBE_DEFER errors here. On some devices + * Propagate -EPROBE_DEFER, skip button on other errors. + * + * -EPROBE_DEFER is ignored on Bay & Cherry Trail. Here * Intel is using so called virtual GPIOs which are not * GPIOs at all but some way for AML code to check some * random status bits without need a custom opregion. @@ -200,6 +202,12 @@ soc_button_device_create(struct platform_device *pdev, * we do not have a driver for these so they will never * show up, therefore we ignore -EPROBE_DEFER. */ + if ((error == -EPROBE_DEFER || irq == -EPROBE_DEFER) && + !(soc_intel_is_byt() || soc_intel_is_cht())) { + error = -EPROBE_DEFER; + goto err_free_mem; + } + continue; } @@ -368,7 +376,7 @@ static struct soc_button_info *soc_button_get_button_info(struct device *dev) } } - if (!btns_desc) { + if (!btns_desc || !btns_desc->package.count) { dev_err(dev, "ACPI Button Descriptors not found\n"); button_info = ERR_PTR(-ENODEV); goto out; diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index 2170bbe4c589..a8ce89d41faa 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -1838,6 +1838,14 @@ static int synaptics_setup_intertouch(struct psmouse *psmouse, return -ENXIO; } + + /* Disable intertouch on known-broken board revisions */ + if (info->board_id == 2722) { + psmouse_info(psmouse, + "Disabling intertouch for board id %u\n", + info->board_id); + return -ENXIO; + } } psmouse_info(psmouse, "Trying to set up SMBus access\n"); diff --git a/drivers/input/rmi4/rmi_driver.c b/drivers/input/rmi4/rmi_driver.c index 5d49a9021c7d..a349dfd17519 100644 --- a/drivers/input/rmi4/rmi_driver.c +++ b/drivers/input/rmi4/rmi_driver.c @@ -991,6 +991,15 @@ int rmi_driver_suspend(struct rmi_device *rmi_dev, bool enable_wake) { int retval; + /* + * Transport driver will try to suspend RMI device even if physical + * driver did not bind to the RMI device, because transport device + * (I2C, SPI) is fully registered and operational. Exit early if + * there is no driver data attached to the RMI device. + */ + if (!dev_get_drvdata(&rmi_dev->dev)) + return 0; + retval = rmi_suspend_functions(rmi_dev); if (retval) dev_warn(&rmi_dev->dev, "Failed to suspend functions: %d\n", @@ -1005,6 +1014,10 @@ int rmi_driver_resume(struct rmi_device *rmi_dev, bool clear_wake) { int retval; + /* Skip if not fully bound to RMI driver */ + if (!dev_get_drvdata(&rmi_dev->dev)) + return 0; + rmi_enable_irq(rmi_dev, clear_wake); retval = rmi_resume_functions(rmi_dev); diff --git a/drivers/input/rmi4/rmi_smbus.c b/drivers/input/rmi4/rmi_smbus.c index 3160714a514a..8b61c2382297 100644 --- a/drivers/input/rmi4/rmi_smbus.c +++ b/drivers/input/rmi4/rmi_smbus.c @@ -140,7 +140,7 @@ static int rmi_smb_write_block(struct rmi_transport_dev *xport, u16 rmiaddr, u8 commandcode; struct rmi_smb_xport *rmi_smb = container_of(xport, struct rmi_smb_xport, xport); - int cur_len = (int)len; + size_t cur_len = len; mutex_lock(&rmi_smb->page_mutex); @@ -148,7 +148,7 @@ static int rmi_smb_write_block(struct rmi_transport_dev *xport, u16 rmiaddr, /* * break into 32 bytes chunks to write get command code */ - int block_len = min_t(int, len, SMB_MAX_COUNT); + int block_len = min_t(size_t, cur_len, SMB_MAX_COUNT); retval = rmi_smb_get_command_code(xport, rmiaddr, block_len, false, &commandcode); @@ -161,9 +161,9 @@ static int rmi_smb_write_block(struct rmi_transport_dev *xport, u16 rmiaddr, goto exit; /* prepare to write next block of bytes */ - cur_len -= SMB_MAX_COUNT; - databuff += SMB_MAX_COUNT; - rmiaddr += SMB_MAX_COUNT; + cur_len -= block_len; + databuff += block_len; + rmiaddr += block_len; } exit: mutex_unlock(&rmi_smb->page_mutex); diff --git a/drivers/input/serio/hp_sdc.c b/drivers/input/serio/hp_sdc.c index 1461ef319f92..ecf5347b63ab 100644 --- a/drivers/input/serio/hp_sdc.c +++ b/drivers/input/serio/hp_sdc.c @@ -981,7 +981,7 @@ static void hp_sdc_exit(void) free_irq(hp_sdc.irq, &hp_sdc); write_unlock_irq(&hp_sdc.lock); - timer_delete_sync(&hp_sdc.kicker); + timer_shutdown_sync(&hp_sdc.kicker); tasklet_kill(&hp_sdc.task); diff --git a/drivers/input/serio/i8042-acpipnpio.h b/drivers/input/serio/i8042-acpipnpio.h index 9ecb0eed48c4..54eb3687000a 100644 --- a/drivers/input/serio/i8042-acpipnpio.h +++ b/drivers/input/serio/i8042-acpipnpio.h @@ -262,6 +262,13 @@ static const struct dmi_system_id i8042_dmi_quirk_table[] __initconst = { { .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "Aspire AG15-42P"), + }, + .driver_data = (void *)(SERIO_QUIRK_RESET_ALWAYS) + }, + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "Aspire ES1-132"), }, .driver_data = (void *)(SERIO_QUIRK_RESET_ALWAYS) diff --git a/drivers/input/touchscreen/cyttsp5.c b/drivers/input/touchscreen/cyttsp5.c index 9266c07314be..e878a02dc9b7 100644 --- a/drivers/input/touchscreen/cyttsp5.c +++ b/drivers/input/touchscreen/cyttsp5.c @@ -710,6 +710,7 @@ static irqreturn_t cyttsp5_handle_irq(int irq, void *handle) size = 2; } else { report_id = ts->input_buf[2]; + size = min(size, CY_MAX_INPUT); } switch (report_id) { diff --git a/drivers/input/touchscreen/eeti_ts.c b/drivers/input/touchscreen/eeti_ts.c index b12602bc368e..b870a939508b 100644 --- a/drivers/input/touchscreen/eeti_ts.c +++ b/drivers/input/touchscreen/eeti_ts.c @@ -276,6 +276,7 @@ static const struct of_device_id of_eeti_ts_match[] = { { .compatible = "eeti,exc3000-i2c", }, { } }; +MODULE_DEVICE_TABLE(of, of_eeti_ts_match); #endif static struct i2c_driver eeti_ts_driver = { diff --git a/drivers/input/touchscreen/tsc2007_core.c b/drivers/input/touchscreen/tsc2007_core.c index e4d7da0f4434..e2f49b37e18c 100644 --- a/drivers/input/touchscreen/tsc2007_core.c +++ b/drivers/input/touchscreen/tsc2007_core.c @@ -221,7 +221,6 @@ static int tsc2007_get_pendown_state_gpio(struct device *dev) static int tsc2007_probe_properties(struct device *dev, struct tsc2007 *ts) { u32 val32; - u64 val64; if (!device_property_read_u32(dev, "ti,max-rt", &val32)) ts->max_rt = val32; @@ -237,8 +236,8 @@ static int tsc2007_probe_properties(struct device *dev, struct tsc2007 *ts) if (!device_property_read_u32(dev, "ti,fuzzz", &val32)) ts->fuzzz = val32; - if (!device_property_read_u64(dev, "ti,poll-period", &val64)) - ts->poll_period = msecs_to_jiffies(val64); + if (!device_property_read_u32(dev, "ti,poll-period", &val32)) + ts->poll_period = msecs_to_jiffies(val32); else ts->poll_period = msecs_to_jiffies(1); diff --git a/drivers/phy/mediatek/phy-mtk-hdmi-mt8195.c b/drivers/phy/mediatek/phy-mtk-hdmi-mt8195.c index 1426a2db984d..a4bc1268946d 100644 --- a/drivers/phy/mediatek/phy-mtk-hdmi-mt8195.c +++ b/drivers/phy/mediatek/phy-mtk-hdmi-mt8195.c @@ -36,7 +36,7 @@ mtk_phy_tmds_clk_ratio(struct mtk_hdmi_phy *hdmi_phy, bool enable) * clock bit ratio 1:40, under 3.4Gbps, clock bit ratio 1:10 */ if (enable) - mtk_phy_update_field(regs + HDMI20_CLK_CFG, REG_TXC_DIV, 3); + mtk_phy_update_field(regs + HDMI20_CLK_CFG, REG_TXC_DIV, VAL_TXC_DIV4); else mtk_phy_clear_bits(regs + HDMI20_CLK_CFG, REG_TXC_DIV); } @@ -290,7 +290,7 @@ static int mtk_hdmi_pll_calc(struct mtk_hdmi_phy *hdmi_phy, struct clk_hw *hw, posdiv2 = 1; /* Digital clk divider, max /32 */ - digital_div = div_u64(ns_hdmipll_ck, posdiv1 * posdiv2 * pixel_clk); + digital_div = div64_u64(ns_hdmipll_ck, posdiv1 * posdiv2 * pixel_clk); if (!(digital_div <= 32 && digital_div >= 1)) return -EINVAL; diff --git a/drivers/phy/mediatek/phy-mtk-hdmi-mt8195.h b/drivers/phy/mediatek/phy-mtk-hdmi-mt8195.h index e26caaf4d104..58800d7659ca 100644 --- a/drivers/phy/mediatek/phy-mtk-hdmi-mt8195.h +++ b/drivers/phy/mediatek/phy-mtk-hdmi-mt8195.h @@ -17,6 +17,9 @@ #define HDMI20_CLK_CFG 0x70 #define REG_TXC_DIV GENMASK(31, 30) +#define VAL_TXC_DIV2 1 +#define VAL_TXC_DIV4 2 +#define VAL_TXC_DIV8 3 #define HDMI_1_CFG_0 0x00 #define RG_HDMITX21_DRV_IBIAS_CLK GENMASK(10, 5) diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb2.c b/drivers/phy/renesas/phy-rcar-gen3-usb2.c index 9ae9975d3255..b5ba751805aa 100644 --- a/drivers/phy/renesas/phy-rcar-gen3-usb2.c +++ b/drivers/phy/renesas/phy-rcar-gen3-usb2.c @@ -27,6 +27,7 @@ #include <linux/reset.h> #include <linux/string.h> #include <linux/usb/of.h> +#include <linux/wait.h> #include <linux/workqueue.h> /******* USB2.0 Host registers (original offset is +0x200) *******/ @@ -106,6 +107,13 @@ /* RZ/G2L specific */ #define USB2_LINECTRL1_USB2_IDMON BIT(0) +/* + * The OTG initialization is expected to finish in 20ms. Choose a large enough + * timeout to avoid waiters exit prematurely the waiting section under heavy + * CPU load. + */ +#define USB2_OTG_INIT_TIMEOUT msecs_to_jiffies(120) + #define NUM_OF_PHYS 4 enum rcar_gen3_phy_index { PHY_INDEX_BOTH_HC, @@ -138,12 +146,20 @@ struct rcar_gen3_chan { struct rcar_gen3_phy rphys[NUM_OF_PHYS]; struct regulator *vbus; struct work_struct work; + wait_queue_head_t otg_init_done; spinlock_t lock; /* protects access to hardware and driver data structure. */ enum usb_dr_mode dr_mode; bool extcon_host; bool is_otg_channel; bool uses_otg_pins; bool otg_internal_reg; + /* + * The OTG can be initialized only once and needs to release the spinlock + * and wait for 20 ms due to hardware constraints. If a thread executes + * PHY configuration code while the OTG PHY is waiting for the 20 ms, the + * thread will have to wait for the OTG PHY initialization to complete. + */ + bool otg_initializing; }; struct rcar_gen3_phy_drv_data { @@ -392,26 +408,58 @@ static ssize_t role_store(struct device *dev, struct device_attribute *attr, struct rcar_gen3_chan *ch = dev_get_drvdata(dev); bool is_b_device; enum phy_mode cur_mode, new_mode; + int retries = NUM_OF_PHYS; + unsigned long flags; + int ret = -EIO; - guard(spinlock_irqsave)(&ch->lock); + spin_lock_irqsave(&ch->lock, flags); - if (!ch->is_otg_channel || !rcar_gen3_is_any_otg_rphy_initialized(ch)) - return -EIO; + if (!ch->is_otg_channel) + goto unlock; + + while (retries-- && ch->otg_initializing) { + spin_unlock_irqrestore(&ch->lock, flags); + + ret = wait_event_timeout(ch->otg_init_done, !ch->otg_initializing, + USB2_OTG_INIT_TIMEOUT); + ret = ret ? 0 : -ETIMEDOUT; + if (ret && !retries) + goto exit; + + spin_lock_irqsave(&ch->lock, flags); + } + + /* If another thread started a new initialization just return -EBUSY. */ + if (ch->otg_initializing) { + ret = -EBUSY; + goto unlock; + } else { + ret = 0; + } + + if (!rcar_gen3_is_any_otg_rphy_initialized(ch)) { + ret = -EIO; + goto unlock; + } - if (sysfs_streq(buf, "host")) + if (sysfs_streq(buf, "host")) { new_mode = PHY_MODE_USB_HOST; - else if (sysfs_streq(buf, "peripheral")) + } else if (sysfs_streq(buf, "peripheral")) { new_mode = PHY_MODE_USB_DEVICE; - else - return -EINVAL; + } else { + ret = -EINVAL; + goto unlock; + } /* is_b_device: true is B-Device. false is A-Device. */ is_b_device = rcar_gen3_check_id(ch); cur_mode = rcar_gen3_get_phy_mode(ch); /* If current and new mode is the same, this returns the error */ - if (cur_mode == new_mode) - return -EINVAL; + if (cur_mode == new_mode) { + ret = -EINVAL; + goto unlock; + } if (new_mode == PHY_MODE_USB_HOST) { /* And is_host must be false */ if (!is_b_device) /* A-Peripheral */ @@ -425,7 +473,10 @@ static ssize_t role_store(struct device *dev, struct device_attribute *attr, rcar_gen3_init_for_peri(ch); } - return count; +unlock: + spin_unlock_irqrestore(&ch->lock, flags); +exit: + return ret ?: count; } static ssize_t role_show(struct device *dev, struct device_attribute *attr, @@ -441,14 +492,11 @@ static ssize_t role_show(struct device *dev, struct device_attribute *attr, } static DEVICE_ATTR_RW(role); -static void rcar_gen3_init_otg(struct rcar_gen3_chan *ch) +static void rcar_gen3_init_otg_phase0(struct rcar_gen3_chan *ch) { void __iomem *usb2_base = ch->base; u32 val; - if (!ch->is_otg_channel || rcar_gen3_is_any_otg_rphy_initialized(ch)) - return; - /* Should not use functions of read-modify-write a register */ val = readl(usb2_base + USB2_LINECTRL1); val = (val & ~USB2_LINECTRL1_DP_RPD) | USB2_LINECTRL1_DPRPD_EN | @@ -471,7 +519,11 @@ static void rcar_gen3_init_otg(struct rcar_gen3_chan *ch) writel(val | USB2_ADPCTRL_IDPULLUP, usb2_base + USB2_ADPCTRL); } } - mdelay(20); +} + +static void rcar_gen3_init_otg_phase1(struct rcar_gen3_chan *ch) +{ + void __iomem *usb2_base = ch->base; writel(0xffffffff, usb2_base + USB2_OBINTSTA); writel(ch->phy_data->obint_enable_bits, usb2_base + USB2_OBINTEN); @@ -502,6 +554,7 @@ static irqreturn_t rcar_gen3_phy_usb2_irq(int irq, void *_ch) void __iomem *usb2_base = ch->base; struct device *dev = ch->dev; irqreturn_t ret = IRQ_NONE; + unsigned long flags; u32 status; pm_runtime_get_noresume(dev); @@ -509,33 +562,102 @@ static irqreturn_t rcar_gen3_phy_usb2_irq(int irq, void *_ch) if (pm_runtime_suspended(dev)) goto rpm_put; - scoped_guard(spinlock, &ch->lock) { - status = readl(usb2_base + USB2_OBINTSTA); - if (status & ch->phy_data->obint_enable_bits) { - dev_vdbg(dev, "%s: %08x\n", __func__, status); - if (ch->phy_data->vblvl_ctrl) - writel(USB2_OBINTSTA_CLEAR, usb2_base + USB2_OBINTSTA); - else - writel(ch->phy_data->obint_enable_bits, usb2_base + USB2_OBINTSTA); - rcar_gen3_device_recognition(ch); - rcar_gen3_configure_vblvl_ctrl(ch); - ret = IRQ_HANDLED; - } + spin_lock_irqsave(&ch->lock, flags); + + status = readl(usb2_base + USB2_OBINTSTA); + if (status & ch->phy_data->obint_enable_bits) { + dev_vdbg(dev, "%s: %08x\n", __func__, status); + if (ch->phy_data->vblvl_ctrl) + writel(USB2_OBINTSTA_CLEAR, usb2_base + USB2_OBINTSTA); + else + writel(ch->phy_data->obint_enable_bits, usb2_base + USB2_OBINTSTA); + + ret = IRQ_HANDLED; + + /* This should not happen! */ + if (ch->otg_initializing) + goto unlock; + + rcar_gen3_device_recognition(ch); + rcar_gen3_configure_vblvl_ctrl(ch); } +unlock: + spin_unlock_irqrestore(&ch->lock, flags); rpm_put: pm_runtime_put_noidle(dev); return ret; } +static void rcar_gen3_phy_usb2_irqs_mask_all(struct rcar_gen3_chan *channel, + u32 *masked_irqs_bits) +{ + u32 val, bitmask = USB2_INT_ENABLE_UCOM_INTEN; + void __iomem *usb2_base = channel->base; + + for (unsigned int i = 0; i < NUM_OF_PHYS; i++) + bitmask |= channel->rphys[i].int_enable_bits; + + val = readl(usb2_base + USB2_INT_ENABLE); + *masked_irqs_bits = val & bitmask; + val &= ~bitmask; + writel(val, usb2_base + USB2_INT_ENABLE); + + /* + * Don't report channel->phy_data->obint_enable_bits IRQs. These are + * unmasked anyway in rcar_gen3_init_otg_phase1(). + */ + val = readl(usb2_base + USB2_OBINTEN); + val &= ~channel->phy_data->obint_enable_bits; + writel(val, usb2_base + USB2_OBINTEN); +} + +static void rcar_gen3_phy_usb2_irqs_unmask(struct rcar_gen3_chan *channel, + u32 irqs_bits) +{ + u32 val, bitmask = USB2_INT_ENABLE_UCOM_INTEN; + void __iomem *usb2_base = channel->base; + + for (unsigned int i = 0; i < NUM_OF_PHYS; i++) + bitmask |= channel->rphys[i].int_enable_bits; + + val = readl(usb2_base + USB2_INT_ENABLE); + val &= ~bitmask; + val |= irqs_bits; + writel(val, usb2_base + USB2_INT_ENABLE); +} + static int rcar_gen3_phy_usb2_init(struct phy *p) { struct rcar_gen3_phy *rphy = phy_get_drvdata(p); struct rcar_gen3_chan *channel = rphy->ch; void __iomem *usb2_base = channel->base; + int retries = NUM_OF_PHYS; + unsigned long flags; u32 val; + int ret; + + spin_lock_irqsave(&channel->lock, flags); - guard(spinlock_irqsave)(&channel->lock); + while (retries-- && channel->otg_initializing) { + spin_unlock_irqrestore(&channel->lock, flags); + + ret = wait_event_timeout(channel->otg_init_done, !channel->otg_initializing, + USB2_OTG_INIT_TIMEOUT); + ret = ret ? 0 : -ETIMEDOUT; + if (ret && !retries) + return ret; + + spin_lock_irqsave(&channel->lock, flags); + } + + /* If another thread started a new initialization just return -EBUSY. */ + if (channel->otg_initializing) { + ret = -EBUSY; + goto unlock; + } else { + ret = 0; + } /* Initialize USB2 part */ val = readl(usb2_base + USB2_INT_ENABLE); @@ -548,8 +670,23 @@ static int rcar_gen3_phy_usb2_init(struct phy *p) } /* Initialize otg part (only if we initialize a PHY with IRQs). */ - if (rphy->int_enable_bits) - rcar_gen3_init_otg(channel); + if (rphy->int_enable_bits && channel->is_otg_channel && + !rcar_gen3_is_any_otg_rphy_initialized(channel)) { + u32 masked_irq_bits = 0; + + rcar_gen3_init_otg_phase0(channel); + rcar_gen3_phy_usb2_irqs_mask_all(channel, &masked_irq_bits); + channel->otg_initializing = true; + spin_unlock_irqrestore(&channel->lock, flags); + + fsleep(20000); + + spin_lock_irqsave(&channel->lock, flags); + rcar_gen3_phy_usb2_irqs_unmask(channel, masked_irq_bits); + rcar_gen3_init_otg_phase1(channel); + channel->otg_initializing = false; + wake_up_all(&channel->otg_init_done); + } if (channel->phy_data->vblvl_ctrl) { /* SIDDQ mode release */ @@ -568,7 +705,10 @@ static int rcar_gen3_phy_usb2_init(struct phy *p) rphy->initialized = true; - return 0; +unlock: + spin_unlock_irqrestore(&channel->lock, flags); + + return ret; } static int rcar_gen3_phy_usb2_exit(struct phy *p) @@ -576,9 +716,32 @@ static int rcar_gen3_phy_usb2_exit(struct phy *p) struct rcar_gen3_phy *rphy = phy_get_drvdata(p); struct rcar_gen3_chan *channel = rphy->ch; void __iomem *usb2_base = channel->base; + int retries = NUM_OF_PHYS; + unsigned long flags; u32 val; + int ret; + + spin_lock_irqsave(&channel->lock, flags); + + while (retries-- && channel->otg_initializing) { + spin_unlock_irqrestore(&channel->lock, flags); + + ret = wait_event_timeout(channel->otg_init_done, !channel->otg_initializing, + USB2_OTG_INIT_TIMEOUT); + ret = ret ? 0 : -ETIMEDOUT; + if (ret && !retries) + return ret; + + spin_lock_irqsave(&channel->lock, flags); + } - guard(spinlock_irqsave)(&channel->lock); + /* If another thread started a new initialization just return -EBUSY. */ + if (channel->otg_initializing) { + ret = -EBUSY; + goto unlock; + } else { + ret = 0; + } rphy->initialized = false; @@ -588,7 +751,9 @@ static int rcar_gen3_phy_usb2_exit(struct phy *p) val &= ~USB2_INT_ENABLE_UCOM_INTEN; writel(val, usb2_base + USB2_INT_ENABLE); - return 0; +unlock: + spin_unlock_irqrestore(&channel->lock, flags); + return ret; } static int rcar_gen3_phy_usb2_power_on(struct phy *p) @@ -596,8 +761,10 @@ static int rcar_gen3_phy_usb2_power_on(struct phy *p) struct rcar_gen3_phy *rphy = phy_get_drvdata(p); struct rcar_gen3_chan *channel = rphy->ch; void __iomem *usb2_base = channel->base; + int retries = NUM_OF_PHYS; + unsigned long flags; u32 val; - int ret = 0; + int ret; if (channel->vbus && !channel->otg_internal_reg) { ret = regulator_enable(channel->vbus); @@ -605,7 +772,27 @@ static int rcar_gen3_phy_usb2_power_on(struct phy *p) return ret; } - guard(spinlock_irqsave)(&channel->lock); + spin_lock_irqsave(&channel->lock, flags); + + while (retries-- && channel->otg_initializing) { + spin_unlock_irqrestore(&channel->lock, flags); + + ret = wait_event_timeout(channel->otg_init_done, !channel->otg_initializing, + USB2_OTG_INIT_TIMEOUT); + ret = ret ? 0 : -ETIMEDOUT; + if (ret && !retries) + goto disable_regulator; + + spin_lock_irqsave(&channel->lock, flags); + } + + /* If another thread started a new initialization just return -EBUSY. */ + if (channel->otg_initializing) { + ret = -EBUSY; + goto unlock; + } else { + ret = 0; + } if (!rcar_gen3_are_all_rphys_power_off(channel)) goto out; @@ -620,27 +807,59 @@ out: /* The powered flag should be set for any other phys anyway */ rphy->powered = true; - return 0; +unlock: + spin_unlock_irqrestore(&channel->lock, flags); + +disable_regulator: + if (ret && channel->vbus && !channel->otg_internal_reg) + regulator_disable(channel->vbus); + + return ret; } static int rcar_gen3_phy_usb2_power_off(struct phy *p) { struct rcar_gen3_phy *rphy = phy_get_drvdata(p); struct rcar_gen3_chan *channel = rphy->ch; - int ret = 0; + int retries = NUM_OF_PHYS; + unsigned long flags; + int ret; - scoped_guard(spinlock_irqsave, &channel->lock) { - rphy->powered = false; + spin_lock_irqsave(&channel->lock, flags); - if (rcar_gen3_are_all_rphys_power_off(channel)) { - u32 val = readl(channel->base + USB2_USBCTR); + while (retries-- && channel->otg_initializing) { + spin_unlock_irqrestore(&channel->lock, flags); - val |= USB2_USBCTR_PLL_RST; - writel(val, channel->base + USB2_USBCTR); - } + ret = wait_event_timeout(channel->otg_init_done, !channel->otg_initializing, + USB2_OTG_INIT_TIMEOUT); + ret = ret ? 0 : -ETIMEDOUT; + if (ret && !retries) + return ret; + + spin_lock_irqsave(&channel->lock, flags); + } + + /* If another thread started a new initialization just return -EBUSY. */ + if (channel->otg_initializing) { + ret = -EBUSY; + goto unlock; + } else { + ret = 0; + } + + rphy->powered = false; + + if (rcar_gen3_are_all_rphys_power_off(channel)) { + u32 val = readl(channel->base + USB2_USBCTR); + + val |= USB2_USBCTR_PLL_RST; + writel(val, channel->base + USB2_USBCTR); } - if (channel->vbus && !channel->otg_internal_reg) +unlock: + spin_unlock_irqrestore(&channel->lock, flags); + + if (!ret && channel->vbus && !channel->otg_internal_reg) ret = regulator_disable(channel->vbus); return ret; @@ -1022,6 +1241,7 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) return ret; spin_lock_init(&channel->lock); + init_waitqueue_head(&channel->otg_init_done); for (i = 0; i < NUM_OF_PHYS; i++) { channel->rphys[i].phy = devm_phy_create(dev, NULL, channel->phy_data->phy_usb2_ops); diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c index e690237fe981..a0a63b76793e 100644 --- a/drivers/soundwire/cadence_master.c +++ b/drivers/soundwire/cadence_master.c @@ -1702,6 +1702,13 @@ int sdw_cdns_clock_stop(struct sdw_cdns *cdns, bool block_wake) } /* + * wait for any in-flight peripheral event handling to complete before stopping the clock. + * No need to disable peripheral interrupts before canceling the work, as the peripheral + * interrupts are already masked before the work is scheduled. + */ + cancel_work_sync(&cdns->work); + + /* * Before entering clock stop we mask the Slave * interrupts. This helps avoid having to deal with e.g. a * Slave becoming UNATTACHED while the clock is being stopped diff --git a/drivers/soundwire/dmi-quirks.c b/drivers/soundwire/dmi-quirks.c index 768255dd12db..62fa64b22412 100644 --- a/drivers/soundwire/dmi-quirks.c +++ b/drivers/soundwire/dmi-quirks.c @@ -203,6 +203,13 @@ static const struct dmi_system_id adr_remap_quirk_table[] = { { .matches = { DMI_MATCH(DMI_SYS_VENDOR, "ASUS"), + DMI_MATCH(DMI_BOARD_NAME, "GX651AX"), + }, + .driver_data = (void *)ghost_realtek, + }, + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUS"), DMI_MATCH(DMI_BOARD_NAME, "UX5406AA"), }, .driver_data = (void *)ghost_realtek, diff --git a/drivers/spi/spi-fsl-qspi.c b/drivers/spi/spi-fsl-qspi.c index 57358851029b..d2c2090442f8 100644 --- a/drivers/spi/spi-fsl-qspi.c +++ b/drivers/spi/spi-fsl-qspi.c @@ -289,6 +289,7 @@ struct fsl_qspi { struct pm_qos_request pm_qos_req; struct device *dev; int selected; + u32 selected_freq; u32 memmap_phy; }; @@ -551,7 +552,8 @@ static void fsl_qspi_select_mem(struct fsl_qspi *q, struct spi_device *spi, unsigned long rate = op->max_freq; int ret; - if (q->selected == spi_get_chipselect(spi, 0)) + if (q->selected == spi_get_chipselect(spi, 0) && + q->selected_freq == op->max_freq) return; if (needs_4x_clock(q)) @@ -571,6 +573,7 @@ static void fsl_qspi_select_mem(struct fsl_qspi *q, struct spi_device *spi, } q->selected = spi_get_chipselect(spi, 0); + q->selected_freq = op->max_freq; fsl_qspi_invalidate(q); } diff --git a/drivers/spi/spi-qpic-snand.c b/drivers/spi/spi-qpic-snand.c index 61b1f2eb19ce..05efe6313b7f 100644 --- a/drivers/spi/spi-qpic-snand.c +++ b/drivers/spi/spi-qpic-snand.c @@ -765,8 +765,6 @@ static int qcom_spi_read_cw_raw(struct qcom_nand_controller *snandc, u8 *data_bu qcom_write_reg_dma(snandc, &snandc->regs->addr0, NAND_ADDR0, 2, 0); qcom_write_reg_dma(snandc, &snandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0); - qcom_write_reg_dma(snandc, &snandc->regs->ecc_buf_cfg, NAND_EBI2_ECC_BUF_CFG, 1, 0); - qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_clr, NAND_ERASED_CW_DETECT_CFG, 1, 0); qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_set, @@ -1104,8 +1102,6 @@ static void qcom_spi_config_page_write(struct qcom_nand_controller *snandc) { qcom_write_reg_dma(snandc, &snandc->regs->addr0, NAND_ADDR0, 2, 0); qcom_write_reg_dma(snandc, &snandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0); - qcom_write_reg_dma(snandc, &snandc->regs->ecc_buf_cfg, NAND_EBI2_ECC_BUF_CFG, - 1, NAND_BAM_NEXT_SGL); } static void qcom_spi_config_cw_write(struct qcom_nand_controller *snandc) diff --git a/drivers/spi/spi-virtio.c b/drivers/spi/spi-virtio.c index 2256dfec5407..3e181bd8bc94 100644 --- a/drivers/spi/spi-virtio.c +++ b/drivers/spi/spi-virtio.c @@ -168,7 +168,7 @@ static int virtio_spi_transfer_one(struct spi_controller *ctrl, /* Fill struct spi_transfer_head */ th->chip_select_id = spi_get_chipselect(spi, 0); - th->bits_per_word = spi->bits_per_word; + th->bits_per_word = xfer->bits_per_word; th->cs_change = xfer->cs_change; th->tx_nbits = xfer->tx_nbits; th->rx_nbits = xfer->rx_nbits; diff --git a/drivers/spi/spi-zynqmp-gqspi.c b/drivers/spi/spi-zynqmp-gqspi.c index 4d55090fa443..15e9d3ef8839 100644 --- a/drivers/spi/spi-zynqmp-gqspi.c +++ b/drivers/spi/spi-zynqmp-gqspi.c @@ -1373,11 +1373,45 @@ static void zynqmp_qspi_remove(struct platform_device *pdev) clk_disable_unprepare(xqspi->pclk); } +static void zynqmp_qspi_shutdown(struct platform_device *pdev) +{ + struct zynqmp_qspi *xqspi = platform_get_drvdata(pdev); + int ret; + + /* + * Stop the queue and reject any later transfer first, so the write + * below cannot cut into a message that is still being executed. + * Unlike ->suspend this cannot abort on error: a controller left + * mastering the bus is worse than a truncated transfer. + */ + ret = spi_controller_suspend(xqspi->ctlr); + if (ret) + dev_warn(&pdev->dev, "could not stop the queue: %d\n", ret); + + /* + * Only a runtime suspended controller can be left alone: its clocks + * are gated, so it cannot be mastering the bus, and its registers + * must not be accessed either. Any other answer means it may be + * running and has to be stopped. In particular, on a kernel built + * without runtime PM this returns -EINVAL, and there the clocks + * enabled in probe() are never gated at all. + */ + ret = pm_runtime_get_if_in_use(&pdev->dev); + if (!ret) + return; + + zynqmp_gqspi_write(xqspi, GQSPI_EN_OFST, 0x0); + + if (ret > 0) + pm_runtime_put_noidle(&pdev->dev); +} + MODULE_DEVICE_TABLE(of, zynqmp_qspi_of_match); static struct platform_driver zynqmp_qspi_driver = { .probe = zynqmp_qspi_probe, .remove = zynqmp_qspi_remove, + .shutdown = zynqmp_qspi_shutdown, .driver = { .name = "zynqmp-qspi", .of_match_table = zynqmp_qspi_of_match, diff --git a/fs/btrfs/dev-replace.c b/fs/btrfs/dev-replace.c index af1b898029e8..0284be0e4e82 100644 --- a/fs/btrfs/dev-replace.c +++ b/fs/btrfs/dev-replace.c @@ -494,6 +494,7 @@ static int mark_block_group_to_copy(struct btrfs_fs_info *fs_info, path->reada = READA_FORWARD; path->search_commit_root = true; path->skip_locking = true; + path->need_commit_sem = true; key.objectid = src_dev->devid; key.type = BTRFS_DEV_EXTENT_KEY; diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 819727460bcf..dc7ad92876c0 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -2357,6 +2357,10 @@ static int validate_sys_chunk_array(const struct btrfs_fs_info *fs_info, key.type, cur); return -EUCLEAN; } + + if (unlikely(cur + sizeof(*chunk) > sys_array_size)) + goto short_read; + chunk = (struct btrfs_chunk *)(sb->sys_chunk_array + cur); num_stripes = btrfs_stack_chunk_num_stripes(chunk); if (unlikely(cur + btrfs_chunk_item_size(num_stripes) > sys_array_size)) diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 20e15dc30bfb..f978c6524aa0 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -2509,8 +2509,10 @@ int btrfs_replace_file_extents(struct btrfs_inode *inode, inode_set_ctime_current(&inode->vfs_inode)); ret = btrfs_update_inode(trans, inode); - if (ret) + if (unlikely(ret)) { + btrfs_abort_transaction(trans, ret); break; + } btrfs_end_transaction(trans); btrfs_btree_balance_dirty(fs_info); diff --git a/fs/btrfs/free-space-tree.c b/fs/btrfs/free-space-tree.c index 1b3d82ae3de8..b7a4a6ade30f 100644 --- a/fs/btrfs/free-space-tree.c +++ b/fs/btrfs/free-space-tree.c @@ -1353,7 +1353,7 @@ int btrfs_rebuild_free_space_tree(struct btrfs_fs_info *fs_info) if (unlikely(ret)) { btrfs_abort_transaction(trans, ret); btrfs_end_transaction(trans); - return ret; + goto out_clear; } node = rb_first_cached(&fs_info->block_group_cache_tree); @@ -1371,14 +1371,16 @@ int btrfs_rebuild_free_space_tree(struct btrfs_fs_info *fs_info) if (unlikely(ret)) { btrfs_abort_transaction(trans, ret); btrfs_end_transaction(trans); - return ret; + goto out_clear; } next: if (btrfs_should_end_transaction(trans)) { btrfs_end_transaction(trans); trans = btrfs_start_transaction(free_space_root, 1); - if (IS_ERR(trans)) - return PTR_ERR(trans); + if (IS_ERR(trans)) { + ret = PTR_ERR(trans); + goto out_clear; + } } node = rb_next(node); } @@ -1390,6 +1392,10 @@ next: ret = btrfs_commit_transaction(trans); clear_bit(BTRFS_FS_FREE_SPACE_TREE_UNTRUSTED, &fs_info->flags); return ret; + +out_clear: + clear_bit(BTRFS_FS_CREATING_FREE_SPACE_TREE, &fs_info->flags); + return ret; } static int __add_block_group_free_space(struct btrfs_trans_handle *trans, diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 93ef3cec191e..558b4a3f9633 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -2339,12 +2339,27 @@ static int run_delalloc_inline(struct btrfs_inode *inode, struct folio *locked_f } else if (inode->prop_compress) { compress_type = inode->prop_compress; } + /* + * We need to pass blocksize and not i_size, otherwise we can't + * create compressed inline extents for data smaller than sector + * size with lzo. + */ cb = btrfs_compress_bio(inode, 0, blocksize, compress_type, compress_level, 0); if (IS_ERR(cb)) { cb = NULL; /* Just fall back to non-compressed case. */ } else { compressed_size = cb->bbio.bio.bi_iter.bi_size; + /* + * If we did not save space, it's pointless and wasteful + * to have an inline compressed extent, so fallback to + * an uncompressed inline extent. + */ + if (compressed_size >= i_size) { + cleanup_compressed_bio(cb); + cb = NULL; + compressed_size = 0; + } } } if (!can_cow_file_range_inline(inode, 0, i_size, compressed_size)) { @@ -3877,7 +3892,8 @@ int btrfs_orphan_cleanup(struct btrfs_root *root) if (ret) goto out; } - trans = btrfs_start_transaction(root, 1); + /* Only deletes the orphan. */ + trans = btrfs_start_transaction_fallback_global_rsv(root, 1); if (IS_ERR(trans)) { ret = PTR_ERR(trans); goto out; diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 464129b1b0d4..ddb620ac241b 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -1836,8 +1836,12 @@ static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf) f_fsid.val[0] ^= btrfs_root_id(BTRFS_I(d_inode(dentry))->root) >> 32; f_fsid.val[1] ^= btrfs_root_id(BTRFS_I(d_inode(dentry))->root); - /* Hash dev_t to avoid f_fsid collision with cloned filesystems. */ - if (fs_info->fs_devices->total_devices == 1) { + /* + * Hash dev_t to avoid f_fsid collisions with cloned filesystems. + * Only do this when a clone is present so the original filesystem + * (mounted first) maintains backward-compatible f_fsid behavior. + */ + if (fs_info->fs_devices->temp_fsid) { __kernel_fsid_t dev_fsid = u64_to_fsid(huge_encode_dev(fs_info->fs_devices->latest_dev->bdev->bd_dev)); diff --git a/fs/btrfs/tree-checker.c b/fs/btrfs/tree-checker.c index ab5abbb475e2..4b1e47173c63 100644 --- a/fs/btrfs/tree-checker.c +++ b/fs/btrfs/tree-checker.c @@ -2129,7 +2129,7 @@ static int check_dev_extent_item(const struct extent_buffer *leaf, sectorsize))) { generic_err(leaf, slot, "invalid dev extent chunk offset, has %llu not aligned to %u", - btrfs_dev_extent_chunk_objectid(leaf, de), + btrfs_dev_extent_chunk_offset(leaf, de), sectorsize); return -EUCLEAN; } @@ -2306,7 +2306,7 @@ static int check_free_space_extent(struct extent_buffer *leaf, struct btrfs_key if (unlikely(btrfs_item_size(leaf, slot) != 0)) { generic_err(leaf, slot, - "invalid item size for free space info, has %u expect 0", + "invalid item size for free space extent, has %u expect 0", btrfs_item_size(leaf, slot)); return -EUCLEAN; } diff --git a/fs/btrfs/verity.c b/fs/btrfs/verity.c index 4e0ab5842274..600337a84fbe 100644 --- a/fs/btrfs/verity.c +++ b/fs/btrfs/verity.c @@ -94,6 +94,20 @@ static loff_t merkle_file_pos(const struct inode *inode) } /* + * Start a transaction for removing verity items or the verity orphan. + * + * Like unlink, this only deletes items and frees space in the end, so the + * reservation may come from the global reserve when the filesystem is full + * (-ENOSPC) and is not subject to the qgroup limit (-EDQUOT). Otherwise a + * failed enable could never be cleaned up in either situation. + */ +static struct btrfs_trans_handle *start_verity_cleanup_trans(struct btrfs_root *root, + unsigned int num_items) +{ + return btrfs_start_transaction_fallback_global_rsv(root, num_items); +} + +/* * Drop all the items for this inode with this key_type. * * @inode: inode to drop items for @@ -120,7 +134,7 @@ static int drop_verity_items(struct btrfs_inode *inode, u8 key_type) while (1) { /* 1 for the item being dropped */ - trans = btrfs_start_transaction(root, 1); + trans = start_verity_cleanup_trans(root, 1); if (IS_ERR(trans)) return PTR_ERR(trans); @@ -466,7 +480,7 @@ static int rollback_verity(struct btrfs_inode *inode) * 1 for updating the inode flag * 1 for deleting the orphan */ - trans = btrfs_start_transaction(root, 2); + trans = start_verity_cleanup_trans(root, 2); if (IS_ERR(trans)) { ret = PTR_ERR(trans); trans = NULL; diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 74584669507f..85ea9c5d4536 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -749,6 +749,36 @@ const u8 *btrfs_sb_fsid_ptr(const struct btrfs_super_block *sb) return has_metadata_uuid ? sb->metadata_uuid : sb->fsid; } +static bool should_rename_device(const struct btrfs_device *dev) +{ + bool ret; + const char *old_name; + + rcu_read_lock(); + old_name = rcu_dereference(dev->name); + /* + * For systems booted without an initramfs, the rootfs has the device + * name "/dev/root". + * + * Although using btrfs without an initramfs is not recommended (if a + * new device is added to the rootfs, the system can no longer boot, as + * there is no way to register all devices), there is still a minority + * of users doing this. + * + * And after the system is up, a later device scan on the real block + * device file will never get this device's name updated, as the + * device->devt is still the same. + * + * Here we add one and only one exception for "/dev/root", to allow the + * device name to be updated even if the new path points to the same + * block device. + */ + ret = (strcmp(old_name, "/dev/root") == 0); + rcu_read_unlock(); + + return ret; +} + /* * Add new device to list of registered devices * @@ -869,7 +899,8 @@ static noinline struct btrfs_device *device_list_add(const char *path, MAJOR(path_devt), MINOR(path_devt), current->comm, task_pid_nr(current)); - } else if (!device->name || device->devt != path_devt) { + } else if (!device->name || device->devt != path_devt || + should_rename_device(device)) { const char *old_name; /* diff --git a/fs/btrfs/zoned.c b/fs/btrfs/zoned.c index 9cc2c9c1a606..08a15465a087 100644 --- a/fs/btrfs/zoned.c +++ b/fs/btrfs/zoned.c @@ -2688,6 +2688,11 @@ bool btrfs_can_activate_zone(struct btrfs_fs_devices *fs_devices, u64 flags) switch (flags & BTRFS_BLOCK_GROUP_PROFILE_MASK) { case 0: /* single */ + case BTRFS_BLOCK_GROUP_RAID0: + case BTRFS_BLOCK_GROUP_RAID1: + case BTRFS_BLOCK_GROUP_RAID1C3: + case BTRFS_BLOCK_GROUP_RAID1C4: + case BTRFS_BLOCK_GROUP_RAID10: ret = (atomic_read(&zinfo->active_zones_left) >= (1 + reserved)); break; case BTRFS_BLOCK_GROUP_DUP: diff --git a/fs/exec.c b/fs/exec.c index d3081c8f7c10..819643408e6d 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -1115,6 +1115,17 @@ static struct file *bprm_identity_file(const struct linux_binprm *bprm) return bprm->file; } +static void posixtimer_exec(struct task_struct *me) +{ +#ifdef CONFIG_POSIX_TIMERS + spin_lock_irq(&me->sighand->siglock); + posix_cpu_timers_exit(me); + spin_unlock_irq(&me->sighand->siglock); + exit_itimers(me); + flush_itimer_signals(); +#endif +} + /* * Calling this is the point of no return. None of the failures will be * seen by userspace since either the process is already taking a fatal @@ -1152,6 +1163,16 @@ int begin_new_exec(struct linux_binprm * bprm) retval = de_thread(me); if (retval) goto out; + + /* + * This must be done here to ensure that POSIX CPU timers which were + * armed on the current task are dequeued from me::posix_cputimers. + * Otherwise in case of a TID switch the deletion of the related POSIX + * timer would not remove an enqueued timer because the TID lookup + * of the old TID fails. + */ + posixtimer_exec(me); + /* see the comment in check_unsafe_exec() */ current->fs->in_exec = 0; /* @@ -1206,14 +1227,6 @@ int begin_new_exec(struct linux_binprm * bprm) if (retval) goto out_unlock; -#ifdef CONFIG_POSIX_TIMERS - spin_lock_irq(&me->sighand->siglock); - posix_cpu_timers_exit(me); - spin_unlock_irq(&me->sighand->siglock); - exit_itimers(me); - flush_itimer_signals(); -#endif - /* * Make the signal table private. */ diff --git a/include/uapi/linux/input-event-codes.h b/include/uapi/linux/input-event-codes.h index 3528168f7c6d..4217950e5d16 100644 --- a/include/uapi/linux/input-event-codes.h +++ b/include/uapi/linux/input-event-codes.h @@ -970,6 +970,12 @@ /* * LEDs + * + * Do not add any new LED definitions to the input subsystem. The existing + * definitions are legacy and grandfathered for backwards compatibility with + * userspace (via evdev). Any new LEDs should be implemented using the + * LED subsystem (struct led_classdev). The input core provides a bridge to + * the LED subsystem in drivers/input/input-leds.c. */ #define LED_NUML 0x00 diff --git a/kernel/events/core.c b/kernel/events/core.c index fe33fe15689d..db7b76d6b68a 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -6350,6 +6350,9 @@ static DEFINE_MUTEX(perf_mediated_pmu_mutex); /* !exclude_guest event of PMU with PERF_PMU_CAP_MEDIATED_VPMU */ static inline bool is_include_guest_event(struct perf_event *event) { + if (!event->pmu) + return false; + if ((event->pmu->capabilities & PERF_PMU_CAP_MEDIATED_VPMU) && !event->attr.exclude_guest) return true; @@ -13002,6 +13005,7 @@ static void __pmu_detach_event(struct pmu *pmu, struct perf_event *event, exclusive_event_destroy(event); module_put(pmu->module); + mediated_pmu_unaccount_event(event); event->pmu = NULL; /* force fault instead of UAF */ } diff --git a/kernel/exit.c b/kernel/exit.c index 4e028f157597..424c44a42a4d 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -302,12 +302,13 @@ repeat: free_pids(post.pids); release_thread(p); /* - * This task was already removed from the process/thread/pid lists - * and lock_task_sighand(p) can't succeed. Nobody else can touch - * ->pending or, if group dead, signal->shared_pending. We can call - * flush_sigqueue() lockless. + * This task was already removed from the process/thread/pid lists and + * lock_task_sighand(p) can't succeed. If it's the group leader then + * flush tsk->signal->shared_pending. tsk->pending has been flushed + * already in exit_signals(). Nothing else can touch + * signal->shared_pending anymore, so flush_sigqueue() can be invoked + * lockless. */ - flush_sigqueue(&p->pending); if (thread_group_leader(p)) flush_sigqueue(&p->signal->shared_pending); diff --git a/kernel/fork.c b/kernel/fork.c index a5934a317634..5ef413368912 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -1996,9 +1996,9 @@ static bool need_futex_hash_allocate_default(u64 clone_flags) { /* * Allocate a default futex hash for any sibling that will - * share the parent's mm, except vfork. + * share the parent's mm. */ - return (clone_flags & (CLONE_VM | CLONE_VFORK)) == CLONE_VM; + return clone_flags & CLONE_VM; } /* diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 7885ff76e69f..0b846a13c628 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -3351,6 +3351,8 @@ void relax_compatible_cpus_allowed_ptr(struct task_struct *p) void set_task_cpu(struct task_struct *p, unsigned int new_cpu) { unsigned int state = READ_ONCE(p->__state); + bool proxy_migrated = sched_proxy_exec() && p->is_blocked && + task_cpu(p) != p->wake_cpu; /* * We should never call set_task_cpu() on a blocked task, @@ -3386,7 +3388,12 @@ void set_task_cpu(struct task_struct *p, unsigned int new_cpu) */ WARN_ON_ONCE(!cpu_online(new_cpu)); - WARN_ON_ONCE(is_migration_disabled(p)); + /* + * Proxy execution can move a blocked task's scheduling context to any + * CPU without moving its migration-disabled execution context. The + * wakeup path will return the task to a CPU where it can execute. + */ + WARN_ON_ONCE(is_migration_disabled(p) && !proxy_migrated); trace_sched_migrate_task(p, new_cpu); diff --git a/kernel/signal.c b/kernel/signal.c index ec30550951ec..d31ebcb6ed4d 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -457,18 +457,42 @@ static void __sigqueue_free(struct sigqueue *q) kmem_cache_free(sigqueue_cachep, q); } -void flush_sigqueue(struct sigpending *queue) +/* + * flush_sigqueue_list() can only be invoked without holding sighand::siglock in + * the following cases: + * + * 1) When flushing task::pending _after_ setting task::flags PF_EXITING + * + * All functions which try to send a signal to @task will observe PF_EXITING + * and drop the signal. + * + * 2) When flushing task::signal::shared_pending _after_ the last task in a + * thread group was unhashed and task::sighand is NULL. + * + * Nothing can queue a signal anymore because sighand is NULL. + */ +static void flush_sigqueue_list(struct list_head *head) { - struct sigqueue *q; + struct sigqueue *q, *tmp; - sigemptyset(&queue->signal); - while (!list_empty(&queue->list)) { - q = list_entry(queue->list.next, struct sigqueue , list); + list_for_each_entry_safe(q, tmp, head, list) { list_del_init(&q->list); __sigqueue_free(q); } } +void flush_sigqueue(struct sigpending *queue) +{ + sigemptyset(&queue->signal); + flush_sigqueue_list(&queue->list); +} + +static void sigqueue_dequeue_pending(struct sigpending *queue, struct list_head *head) +{ + sigemptyset(&queue->signal); + list_splice_init(&queue->list, head); +} + /* * Flush all pending signals for this kthread. */ @@ -1019,6 +1043,21 @@ static inline bool legacy_queue(struct sigpending *signals, int sig) return (sig < SIGRTMIN) && sigismember(&signals->signal, sig); } +/* + * When PF_EXITING is set the task is on the way out and has t::pending + * flushed already. Prevent queueing of PIDTYPE_PID signals as they would + * be leaked. + */ +static inline bool task_can_queue_signal(struct task_struct *t, enum pid_type type) +{ + lockdep_assert_held(&t->sighand->siglock); + + if (!(t->flags & PF_EXITING)) + return true; + + return type != PIDTYPE_PID; +} + static int __send_signal_locked(int sig, struct kernel_siginfo *info, struct task_struct *t, enum pid_type type, bool force) { @@ -1030,6 +1069,10 @@ static int __send_signal_locked(int sig, struct kernel_siginfo *info, lockdep_assert_held(&t->sighand->siglock); result = TRACE_SIGNAL_IGNORED; + + if (!task_can_queue_signal(t, type)) + goto ret; + if (!prepare_signal(sig, t, force)) goto ret; @@ -1980,11 +2023,25 @@ static inline struct task_struct *posixtimer_get_target(struct k_itimer *tmr) struct task_struct *t = pid_task(tmr->it_pid, tmr->it_pid_type); if (t && tmr->it_pid_type != PIDTYPE_PID && - same_thread_group(t, current) && !current->exit_state) + same_thread_group(t, current) && !(current->flags & PF_EXITING)) t = current; return t; } +/* + * Find the target task for the POSIX timer signal and prevent that a + * PIDTYPE_PID signal is queued on a task which has PF_EXITING set. + */ +static inline struct task_struct *posixtimer_get_unignore_target(struct k_itimer *tmr) +{ + struct task_struct *t = posixtimer_get_target(tmr); + + if (t && task_can_queue_signal(t, tmr->it_pid_type)) + return t; + + return NULL; +} + void posixtimer_send_sigqueue(struct k_itimer *tmr) { struct sigqueue *q = &tmr->sigq; @@ -2002,6 +2059,9 @@ void posixtimer_send_sigqueue(struct k_itimer *tmr) if (!likely(lock_task_sighand(t, &flags))) return; + if (!task_can_queue_signal(t, tmr->it_pid_type)) + goto unlock; + /* * Update @tmr::sigqueue_seq for posix timer signals with sighand * locked to prevent a race against dequeue_signal(). @@ -2093,6 +2153,7 @@ void posixtimer_send_sigqueue(struct k_itimer *tmr) result = TRACE_SIGNAL_DELIVERED; out: trace_signal_generate(sig, &q->info, t, tmr->it_pid_type != PIDTYPE_PID, result); +unlock: unlock_task_sighand(t, &flags); } @@ -2148,7 +2209,7 @@ static void posixtimer_sig_unignore(struct task_struct *tsk, int sig) * has exited by now, drop the reference count. */ guard(rcu)(); - target = posixtimer_get_target(tmr); + target = posixtimer_get_unignore_target(tmr); if (target) posixtimer_queue_sigqueue(&tmr->sigq, target, tmr->it_pid_type); else @@ -3132,42 +3193,36 @@ static void retarget_shared_pending(struct task_struct *tsk, sigset_t *which) void exit_signals(struct task_struct *tsk) { + LIST_HEAD(sigq_list); int group_stop = 0; - sigset_t unblocked; /* * @tsk is about to have PF_EXITING set - lock out users which - * expect stable threadgroup. + * expect a stable threadgroup. */ cgroup_threadgroup_change_begin(tsk); - if (thread_group_empty(tsk) || (tsk->signal->flags & SIGNAL_GROUP_EXIT)) { + scoped_guard(spinlock_irq, &tsk->sighand->siglock) { tsk->flags |= PF_EXITING; - cgroup_threadgroup_change_end(tsk); - return; - } - spin_lock_irq(&tsk->sighand->siglock); - /* - * From now this task is not visible for group-wide signals, - * see wants_signal(), do_signal_stop(). - */ - tsk->flags |= PF_EXITING; + sigqueue_dequeue_pending(&tsk->pending, &sigq_list); - cgroup_threadgroup_change_end(tsk); + if (task_sigpending(tsk) && !thread_group_empty(tsk) && + !(tsk->signal->flags & SIGNAL_GROUP_EXIT)) { + sigset_t unblocked = tsk->blocked; - if (!task_sigpending(tsk)) - goto out; + signotset(&unblocked); + retarget_shared_pending(tsk, &unblocked); - unblocked = tsk->blocked; - signotset(&unblocked); - retarget_shared_pending(tsk, &unblocked); + if (unlikely(tsk->jobctl & JOBCTL_STOP_PENDING) && + task_participate_group_stop(tsk)) + group_stop = CLD_STOPPED; + } + } - if (unlikely(tsk->jobctl & JOBCTL_STOP_PENDING) && - task_participate_group_stop(tsk)) - group_stop = CLD_STOPPED; -out: - spin_unlock_irq(&tsk->sighand->siglock); + cgroup_threadgroup_change_end(tsk); + + flush_sigqueue_list(&sigq_list); /* * If group stop has completed, deliver the notification. This diff --git a/kernel/time/posix-cpu-timers.c b/kernel/time/posix-cpu-timers.c index d73d31c7994f..0bf4fcd969c8 100644 --- a/kernel/time/posix-cpu-timers.c +++ b/kernel/time/posix-cpu-timers.c @@ -408,6 +408,7 @@ static int posix_cpu_timer_create(struct k_itimer *new_timer) new_timer->kclock = &clock_posix_cpu; timerqueue_init(&new_timer->it.cpu.node); + INIT_LIST_HEAD(&new_timer->it.cpu.elist); new_timer->it.cpu.pid = get_pid(pid); rcu_read_unlock(); return 0; @@ -566,6 +567,24 @@ static struct task_struct *timer_lock_sighand(struct k_itimer *timer, unsigned l } /* + * If the timer is queued on the expiry list, then it cannot be dequeued because + * the firing list is not protected by sighand->lock. The delivery path is + * waiting for the timer lock. So go back, unlock and retry. + */ +static bool posix_cpu_timer_on_expiry_list(struct k_itimer *timer) +{ + if (list_empty(&timer->it.cpu.elist)) + return false; + + /* + * Prevent signal delivery as there is no point in delivering a signal + * which is made obsolete right away. + */ + timer->it.cpu.firing = false; + return true; +} + +/* * Clean up a CPU-clock timer that is about to be destroyed. * This is called from timer deletion with the timer already locked. * If we return TIMER_RETRY, it's necessary to release the timer's lock @@ -580,18 +599,10 @@ static int posix_cpu_timer_del(struct k_itimer *timer) p = timer_lock_sighand(timer, &flags); if (likely(p)) { - if (timer->it.cpu.firing) { - /* - * Prevent signal delivery. The timer cannot be dequeued - * because it is on the firing list which is not protected - * by sighand->lock. The delivery path is waiting for - * the timer lock. So go back, unlock and retry. - */ - timer->it.cpu.firing = false; + if (posix_cpu_timer_on_expiry_list(timer)) ret = TIMER_RETRY; - } else { + else disarm_timer(timer, p); - } unlock_task_sighand(p, &flags); } @@ -731,14 +742,7 @@ static int posix_cpu_timer_set(struct k_itimer *timer, int timer_flags, /* Retrieve the current expiry time before disarming the timer */ old_expires = cpu_timer_getexpires(ctmr); - if (unlikely(timer->it.cpu.firing)) { - /* - * Prevent signal delivery. The timer cannot be dequeued - * because it is on the firing list which is not protected - * by sighand->lock. The delivery path is waiting for - * the timer lock. So go back, unlock and retry. - */ - timer->it.cpu.firing = false; + if (posix_cpu_timer_on_expiry_list(timer)) { ret = TIMER_RETRY; } else { cpu_timer_dequeue(ctmr); diff --git a/net/qrtr/af_qrtr.c b/net/qrtr/af_qrtr.c index 78347c937af7..e7b3647424b8 100644 --- a/net/qrtr/af_qrtr.c +++ b/net/qrtr/af_qrtr.c @@ -623,6 +623,19 @@ static void qrtr_hello_work(struct work_struct *work) qrtr_port_put(ctrl); } +/* Trigger the HELLO handshake after the remote has been reset, eg on resume */ +void qrtr_endpoint_hello(struct qrtr_endpoint *ep) +{ + struct qrtr_node *node = ep->node; + + mutex_lock(&node->ep_lock); + node->hello_sent = false; + mutex_unlock(&node->ep_lock); + + schedule_delayed_work(&node->say_hello, 0); +} +EXPORT_SYMBOL_GPL(qrtr_endpoint_hello); + /** * qrtr_endpoint_register() - register a new endpoint * @ep: endpoint to register diff --git a/net/qrtr/mhi.c b/net/qrtr/mhi.c index 3990da1a65dc..e9a4bb92ce76 100644 --- a/net/qrtr/mhi.c +++ b/net/qrtr/mhi.c @@ -183,6 +183,7 @@ static int __maybe_unused qcom_mhi_qrtr_pm_suspend_late(struct device *dev) static int __maybe_unused qcom_mhi_qrtr_pm_resume_early(struct device *dev) { struct mhi_device *mhi_dev = container_of(dev, struct mhi_device, dev); + struct qrtr_mhi_dev *qdev = dev_get_drvdata(dev); enum mhi_state state; int rc; @@ -201,7 +202,13 @@ static int __maybe_unused qcom_mhi_qrtr_pm_resume_early(struct device *dev) return rc; } - return qcom_mhi_qrtr_queue_dl_buffers(mhi_dev); + rc = qcom_mhi_qrtr_queue_dl_buffers(mhi_dev); + if (rc) + return rc; + + qrtr_endpoint_hello(&qdev->ep); + + return 0; } static const struct dev_pm_ops qcom_mhi_qrtr_pm_ops = { diff --git a/net/qrtr/qrtr.h b/net/qrtr/qrtr.h index 3f2d28696062..de2de69a6199 100644 --- a/net/qrtr/qrtr.h +++ b/net/qrtr/qrtr.h @@ -27,6 +27,8 @@ int qrtr_endpoint_register(struct qrtr_endpoint *ep, unsigned int nid); void qrtr_endpoint_unregister(struct qrtr_endpoint *ep); +void qrtr_endpoint_hello(struct qrtr_endpoint *ep); + int qrtr_endpoint_post(struct qrtr_endpoint *ep, const void *data, size_t len); int qrtr_ns_init(void); diff --git a/scripts/generate_rust_target.rs b/scripts/generate_rust_target.rs index 3bf296581a88..7687b0dd5474 100644 --- a/scripts/generate_rust_target.rs +++ b/scripts/generate_rust_target.rs @@ -224,6 +224,11 @@ fn main() { features += ",+harden-sls-ijmp"; features += ",+harden-sls-ret"; } + if cfg.has("X86_NATIVE_CPU") { + // Prevent the backend from generating APX instructions. The kernel is not yet prepared + // for general in-kernel EGPR use. + features += ",-apxf"; + } ts.push("features", features); ts.push("llvm-target", "x86_64-linux-gnu"); ts.push("supported-sanitizers", ["kcfi", "kernel-address"]); diff --git a/security/selinux/avc.c b/security/selinux/avc.c index a9401d6c2e5f..560a82c6d682 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c @@ -1149,8 +1149,11 @@ inline int avc_has_perm_noaudit(u32 ssid, u32 tsid, u32 denied; struct avc_node *node; - if (WARN_ON(!requested)) + if (WARN_ON(!requested)) { + /* Provide a deny-all, audit-all decision to the caller. */ + *avd = (struct av_decision){ .auditdeny = 0xffffffff }; return -EACCES; + } rcu_read_lock(); node = avc_lookup(ssid, tsid, tclass); diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index e5e17f100aae..3f4a6ddee322 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -1674,26 +1674,32 @@ static int cred_has_capability(const struct cred *cred, return rc; } -/* Check whether a task has a particular permission to an inode. - The 'adp' parameter is optional and allows other audit - data to be passed (e.g. the dentry). */ -static int inode_has_perm(const struct cred *cred, - struct inode *inode, - u32 perms, - struct common_audit_data *adp) +/* + * Check whether a SID has a particular permission to an inode. The 'adp' + * parameter is optional and allows other audit data to be passed (e.g. the + * dentry). + */ +static int inode_sid_has_perm(u32 sid, struct inode *inode, u32 perms, + struct common_audit_data *adp) { struct inode_security_struct *isec; - u32 sid; if (unlikely(IS_PRIVATE(inode))) return 0; - sid = cred_sid(cred); isec = selinux_inode(inode); return avc_has_perm(sid, isec->sid, isec->sclass, perms, adp); } +static int inode_has_perm(const struct cred *cred, + struct inode *inode, + u32 perms, + struct common_audit_data *adp) +{ + return inode_sid_has_perm(cred_sid(cred), inode, perms, adp); +} + /* Same as inode_has_perm, but pass explicit audit data containing the dentry to help the auditing code to more easily generate the pathname if needed. */ @@ -3843,17 +3849,74 @@ static int selinux_file_alloc_security(struct file *file) return 0; } +static inline u32 selinux_file_user_sid(const struct file *file) +{ + if (unlikely(file->f_mode & FMODE_BACKING)) + return selinux_backing_file(file)->uf_sid; + return selinux_file(file)->sid; +} + static int selinux_backing_file_alloc(struct file *backing_file, const struct file *user_file) { struct backing_file_security_struct *bfsec; + const struct backing_file_security_struct *ubfsec; + struct backing_file_security_layer *layer; + u32 i; bfsec = selinux_backing_file(backing_file); - bfsec->uf_sid = selinux_file(user_file)->sid; + bfsec->uf_sid = selinux_file_user_sid(user_file); + if (!(user_file->f_mode & FMODE_BACKING)) + return 0; + + ubfsec = selinux_backing_file(user_file); + /* a wrapped count would make kmalloc_array() return ZERO_SIZE_PTR */ + if (unlikely(ubfsec->layer_count == U32_MAX)) + return -EOVERFLOW; + + /* + * The final VMA only retains the lowest backing file, so record the + * whole chain here rather than in the mmap hook, where concurrent + * mappings would have to be serialized. Size it dynamically: erofs + * inode sharing adds a backing file without bumping s_stack_depth. + */ + bfsec->layers = kmalloc_array(ubfsec->layer_count + 1, + sizeof(*bfsec->layers), GFP_KERNEL); + if (!bfsec->layers) + return -ENOMEM; + + for (i = 0; i < ubfsec->layer_count; i++) { + layer = &bfsec->layers[i]; + *layer = ubfsec->layers[i]; + path_get(&layer->path); + } + + /* f_path, not file_user_path(): this layer, not the top-level file */ + layer = &bfsec->layers[i]; + layer->path = user_file->f_path; + layer->mounter_sid = cred_sid(user_file->f_cred); + layer->fd_sid = selinux_file(user_file)->sid; + path_get(&layer->path); + bfsec->layer_count = ubfsec->layer_count + 1; return 0; } +static void selinux_backing_file_free(struct file *backing_file) +{ + struct backing_file_security_struct *bfsec; + + /* security_backing_file_free() may be called twice after an error */ + if (!backing_file_security(backing_file)) + return; + + bfsec = selinux_backing_file(backing_file); + while (bfsec->layer_count) + path_put(&bfsec->layers[--bfsec->layer_count].path); + kfree(bfsec->layers); + bfsec->layers = NULL; +} + /* * Check whether a task has the ioctl permission and cmd * operation to an inode. @@ -3971,6 +4034,53 @@ static int selinux_file_ioctl_compat(struct file *file, unsigned int cmd, static int default_noexec __ro_after_init; +static u32 file_map_prot_to_av(unsigned long prot, bool shared) +{ + u32 av = FILE__READ; + + if (shared && (prot & PROT_WRITE)) + av |= FILE__WRITE; + if (prot & PROT_EXEC) + av |= FILE__EXECUTE; + + return av; +} + +static int backing_mounters_has_perm(const struct file *file, u32 av) +{ + const struct backing_file_security_struct *bfsec; + const struct backing_file_security_layer *layer; + struct common_audit_data ad; + struct inode *inode; + u32 i; + int rc; + + if (WARN_ON_ONCE(!(file->f_mode & FMODE_BACKING))) + return -EIO; + + bfsec = selinux_backing_file(file); + for (i = 0; i < bfsec->layer_count; i++) { + layer = &bfsec->layers[i]; + inode = d_inode(layer->path.dentry); + + ad.type = LSM_AUDIT_DATA_PATH; + ad.u.path = layer->path; + + if (layer->mounter_sid != layer->fd_sid) { + rc = avc_has_perm(layer->mounter_sid, layer->fd_sid, + SECCLASS_FD, FD__USE, &ad); + if (rc) + return rc; + } + + rc = inode_sid_has_perm(layer->mounter_sid, inode, av, &ad); + if (rc) + return rc; + } + + return 0; +} + static int __file_map_prot_check(const struct file *file, unsigned long prot, bool shared, bool mounter_check, bool bf_user_file) @@ -4004,14 +4114,10 @@ static int __file_map_prot_check(const struct file *file, unsigned long prot, if (file) { const struct cred *cred = mounter_check ? file->f_cred : current_cred(); - /* "read" always possible, "write" only if shared */ - u32 av = FILE__READ; - if (shared && prot_write) - av |= FILE__WRITE; - if (prot_exec) - av |= FILE__EXECUTE; - return __file_has_perm(cred, file, av, bf_user_file); + return __file_has_perm(cred, file, + file_map_prot_to_av(prot, shared), + bf_user_file); } return 0; @@ -4106,6 +4212,7 @@ static int selinux_file_mprotect(struct vm_area_struct *vma, int rc; const struct cred *cred = current_cred(); u32 sid = cred_sid(cred); + u32 av; const struct file *file = vma->vm_file; bool backing_file; bool shared = vma->vm_flags & VM_SHARED; @@ -4149,6 +4256,10 @@ static int selinux_file_mprotect(struct vm_area_struct *vma, if (rc) return rc; if (backing_file) { + rc = backing_mounters_has_perm(file, + FILE__EXECMOD); + if (rc) + return rc; rc = file_has_perm(file->f_cred, file, FILE__EXECMOD); if (rc) @@ -4161,6 +4272,10 @@ static int selinux_file_mprotect(struct vm_area_struct *vma, if (rc) return rc; if (backing_file) { + av = file_map_prot_to_av(prot, shared); + rc = backing_mounters_has_perm(file, av); + if (rc) + return rc; rc = file_map_prot_check(file, prot, shared, true); if (rc) return rc; @@ -7619,6 +7734,7 @@ static struct security_hook_list selinux_hooks[] __ro_after_init = { LSM_HOOK_INIT(file_permission, selinux_file_permission), LSM_HOOK_INIT(file_alloc_security, selinux_file_alloc_security), LSM_HOOK_INIT(backing_file_alloc, selinux_backing_file_alloc), + LSM_HOOK_INIT(backing_file_free, selinux_backing_file_free), LSM_HOOK_INIT(file_ioctl, selinux_file_ioctl), LSM_HOOK_INIT(file_ioctl_compat, selinux_file_ioctl_compat), LSM_HOOK_INIT(mmap_file, selinux_mmap_file), diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h index 3c0a16ec978b..2f21568251ff 100644 --- a/security/selinux/include/objsec.h +++ b/security/selinux/include/objsec.h @@ -86,8 +86,16 @@ struct file_security_struct { u32 pseqno; /* Policy seqno at the time of file open */ }; +struct backing_file_security_layer { + struct path path; /* this layer's real path */ + u32 mounter_sid; /* SID of the mounter that opened it */ + u32 fd_sid; /* SID of its open file description */ +}; + struct backing_file_security_struct { - u32 uf_sid; /* associated user file fsec->sid */ + u32 uf_sid; /* top-level user file fsec->sid */ + u32 layer_count; /* number of intermediate backing files */ + struct backing_file_security_layer *layers; }; struct superblock_security_struct { diff --git a/tools/objtool/Makefile b/tools/objtool/Makefile index a4484fd22a96..4cc2e756af84 100644 --- a/tools/objtool/Makefile +++ b/tools/objtool/Makefile @@ -89,9 +89,11 @@ LIBOPCODES_LIBS := $(shell \ "-lopcodes -lbfd" \ "-lopcodes -lbfd -liberty" \ "-lopcodes -lbfd -liberty -lz"; do \ - echo 'extern void disassemble_init_for_target(void *);' \ - 'int main(void) { disassemble_init_for_target(0); return 0; }' | \ - $(HOSTCC) -xc - -o /dev/null $$libs 2>/dev/null && \ + printf '%s\n' \ + '$(pound)include <bfd.h>' \ + '$(pound)include <dis-asm.h>' \ + 'int main(void) { disassemble_init_for_target(0); return 0; }' | \ + $(HOSTCC) $(HOSTCFLAGS) -DPACKAGE='"objtool"' -xc - -o /dev/null $$libs 2>/dev/null && \ echo "$$libs" && break; \ done) diff --git a/tools/testing/selftests/x86/Makefile b/tools/testing/selftests/x86/Makefile index 434065215d12..d478b13cc8d5 100644 --- a/tools/testing/selftests/x86/Makefile +++ b/tools/testing/selftests/x86/Makefile @@ -13,7 +13,7 @@ CAN_BUILD_WITH_NOPIE := $(shell ./check_cc.sh "$(CC)" trivial_program.c -no-pie) TARGETS_C_BOTHBITS := single_step_syscall sysret_ss_attrs syscall_nt test_mremap_vdso \ check_initial_reg_state sigreturn iopl ioperm \ test_vsyscall mov_ss_trap sigtrap_loop \ - syscall_arg_fault fsgsbase_restore sigaltstack + syscall_arg_fault fsgsbase_restore sigaltstack int_signal TARGETS_C_BOTHBITS += nx_stack TARGETS_C_32BIT_ONLY := entry_from_vm86 test_syscall_vdso unwind_vdso \ test_FCMOV test_FCOMI test_FISTTP \ diff --git a/tools/testing/selftests/x86/int_signal.c b/tools/testing/selftests/x86/int_signal.c new file mode 100644 index 000000000000..22676dac72b5 --- /dev/null +++ b/tools/testing/selftests/x86/int_signal.c @@ -0,0 +1,311 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Check the signal context for INT instructions with IDT and FRED entry. */ +#define _GNU_SOURCE + +#include <cpuid.h> +#include <errno.h> +#include <stdbool.h> +#include <stddef.h> +#include <stdint.h> +#include <sys/ptrace.h> +#include <sys/user.h> +#include <sys/wait.h> +#include <unistd.h> +#include <ucontext.h> + +#include "helpers.h" + +#ifdef __x86_64__ +#define REG_IP REG_RIP +#define USER_IP rip +#define STACK_PTR "%rsp" +#else +#define REG_IP REG_EIP +#define USER_IP eip +#define STACK_PTR "%esp" +#endif + +/* + * Each instruction has normal and single-step entry points. Resume at the + * NOP after handling its signal, then expect a trace trap after that NOP + * when TF is set. Explicit labels avoid assuming the kernel's saved IP. + */ +#define PROBE(name, insn) \ + extern void name(void); \ + extern void name##_tf(void); \ + extern const char name##_end[], name##_step[]; \ + asm(".pushsection .text\n" \ + ".globl " #name "_tf\n" \ + ".type " #name "_tf, @function\n" \ + #name "_tf:\n" \ + "pushf\n" \ + "orl $0x100, (" STACK_PTR ")\n" \ + "popf\n" \ + ".globl " #name "\n" \ + ".type " #name ", @function\n" \ + #name ":\n" insn "\n" \ + ".globl " #name "_end\n" \ + #name "_end:\nnop\n" \ + ".globl " #name "_step\n" \ + #name "_step:\nret\n" \ + ".size " #name ", .-" #name "\n" \ + ".size " #name "_tf, .-" #name "_tf\n" \ + ".popsection\n") + +PROBE(int1, ".byte 0xcd, 0x01"); +PROBE(int29, ".byte 0xcd, 0x29"); +PROBE(int2c, ".byte 0xcd, 0x2c"); +PROBE(int2d, ".byte 0xcd, 0x2d"); +PROBE(prefixed_int2d, ".byte 0x66, 0xcd, 0x2d"); +PROBE(long_int2d, ".fill 13, 1, 0x2e\n.byte 0xcd, 0x2d"); +PROBE(int81, ".byte 0xcd, 0x81"); +PROBE(intff, ".byte 0xcd, 0xff"); +PROBE(short_int3, ".byte 0xcc"); +PROBE(long_int3, ".byte 0xcd, 0x03"); +PROBE(int4, ".byte 0xcd, 0x04"); +PROBE(ud2, ".byte 0x0f, 0x0b"); +PROBE(hlt, ".byte 0xf4"); + +struct test { + const char *name; + void (*run)(void); + void (*run_tf)(void); + const char *end, *step; + int signo, trap, error, ip_offset, flags, code; +}; + +#define TEST(name, sig, trap, error, offset, flags, code) \ + { #name, name, name##_tf, name##_end, name##_step, \ + sig, trap, error, offset, flags, code } + +#define GP(name, error) \ + TEST(name, SIGSEGV, 13, error, 0, X86_EFLAGS_RF, SI_KERNEL) + +static const struct test tests[] = { + GP(int1, 0x00a), + GP(int29, 0x14a), + GP(int2c, 0x162), + GP(int2d, 0x16a), + GP(prefixed_int2d, 0x16a), + GP(long_int2d, 0x16a), + GP(int81, 0x40a), + GP(intff, 0x7fa), + GP(hlt, 0), + TEST(short_int3, SIGTRAP, 3, 0, 1, 0, SI_KERNEL), + TEST(long_int3, SIGTRAP, 3, 0, 2, 0, SI_KERNEL), + TEST(int4, SIGSEGV, 4, 0, 2, 0, SI_KERNEL), + TEST(ud2, SIGILL, 6, 0, 0, X86_EFLAGS_RF, ILL_ILLOPN), +}; + +static const struct test *active; +static volatile sig_atomic_t seen, signo, trap, error, ip_offset, flags; +static volatile sig_atomic_t code, addr_ok, single_step, stepped, step_ok; + +static void handler(int sig, siginfo_t *info, void *context) +{ + ucontext_t *uc = context; + uintptr_t ip = uc->uc_mcontext.gregs[REG_IP]; + uintptr_t start = (uintptr_t)active->run; + uintptr_t end = (uintptr_t)active->end; + + if (seen && single_step && sig == SIGTRAP) { + if (stepped++) { + ksft_print_msg("%s: second trace trap at %#lx\n", + active->name, (unsigned long)ip); + _exit(KSFT_FAIL); + } + step_ok = ip == (uintptr_t)active->step && + uc->uc_mcontext.gregs[REG_TRAPNO] == 1 && + info->si_code == TRAP_TRACE; + uc->uc_mcontext.gregs[REG_EFL] &= ~X86_EFLAGS_TF; + return; + } + + if (seen || ip < start || ip > end) { + ksft_print_msg("%s: unexpected signal %d at %#lx\n", + active->name, sig, (unsigned long)ip); + _exit(KSFT_FAIL); + } + + signo = sig; + trap = uc->uc_mcontext.gregs[REG_TRAPNO]; + error = uc->uc_mcontext.gregs[REG_ERR]; + ip_offset = ip - start; + flags = uc->uc_mcontext.gregs[REG_EFL] & (X86_EFLAGS_RF | X86_EFLAGS_TF); + code = info->si_code; + /* force_sig() reports no address, force_sig_fault() reports the IP. */ + addr_ok = info->si_addr == (code == SI_KERNEL ? NULL : (void *)ip); + seen = 1; + uc->uc_mcontext.gregs[REG_IP] = end; +} + +static void wait_for_child(pid_t child, int *status) +{ + pid_t ret; + + do { + ret = waitpid(child, status, 0); + } while (ret < 0 && errno == EINTR); + if (ret != child) + ksft_exit_fail_perror("waitpid"); +} + +/* Resume the tracee and check where the next stop lands. */ +static bool resume_to(pid_t child, int *status, int request, int sig, + const void *ip, const char *what) +{ + struct user_regs_struct regs; + + if (ptrace(request, child, 0, 0)) + return false; + wait_for_child(child, status); + if (!WIFSTOPPED(*status)) { + ksft_print_msg("%s: tracee did not stop\n", what); + return false; + } + if (WSTOPSIG(*status) != sig) { + ksft_print_msg("%s: stopped with signal %d, expected %d\n", + what, WSTOPSIG(*status), sig); + return false; + } + if (ptrace(PTRACE_GETREGS, child, 0, ®s)) + return false; + if ((unsigned long)regs.USER_IP != (unsigned long)ip) { + ksft_print_msg("%s: stopped at %#lx, expected %#lx\n", what, + (unsigned long)regs.USER_IP, (unsigned long)ip); + return false; + } + return true; +} + +static bool set_ip(pid_t child, const void *ip, bool tf) +{ + struct user_regs_struct regs; + + if (ptrace(PTRACE_GETREGS, child, 0, ®s)) + return false; + regs.USER_IP = (unsigned long)ip; + if (tf) + regs.eflags |= X86_EFLAGS_TF; + return !ptrace(PTRACE_SETREGS, child, 0, ®s); +} + +/* + * Exercise the tracer paths that resume through the fault frame rather than + * sigreturn. A stale FRED software event flag on that frame traps before the + * NOP executes instead of after it. + */ +static void test_ptrace(void) +{ + bool into = false, step = false, cont = false; + pid_t child; + int status; + + child = fork(); + if (child < 0) + ksft_exit_fail_perror("fork"); + if (!child) { + if (ptrace(PTRACE_TRACEME, 0, 0, 0)) + _exit(KSFT_FAIL); + /* Start from a breakpoint frame, not the syscall frame of raise(). */ + asm volatile("int3"); + _exit(KSFT_FAIL); + } + + wait_for_child(child, &status); + if (!WIFSTOPPED(status) || WSTOPSIG(status) != SIGTRAP) + goto out; + if (ptrace(PTRACE_SETOPTIONS, child, 0, PTRACE_O_EXITKILL)) + goto out; + + /* Single-step into the INT. The fault must report the INT's address. */ + if (!set_ip(child, int2d, false)) + goto out; + into = resume_to(child, &status, PTRACE_SINGLESTEP, SIGSEGV, int2d, + "single-step into INT"); + if (!into) + goto out; + + /* Suppress SIGSEGV and single-step the NOP. */ + if (!set_ip(child, int2d_end, false)) + goto out; + step = resume_to(child, &status, PTRACE_SINGLESTEP, SIGTRAP, int2d_step, + "single-step after INT"); + if (!step) + goto out; + + /* Fault again, then suppress SIGSEGV and continue with TF set. */ + if (!set_ip(child, int2d, false)) + goto out; + if (!resume_to(child, &status, PTRACE_CONT, SIGSEGV, int2d, + "continue to INT")) + goto out; + if (!set_ip(child, int2d_end, true)) + goto out; + cont = resume_to(child, &status, PTRACE_CONT, SIGTRAP, int2d_step, + "continue with TF after INT"); +out: + if (WIFSTOPPED(status)) { + kill(child, SIGKILL); + wait_for_child(child, &status); + } + ksft_test_result(into, "ptrace single-step into INT faults at the INT\n"); + ksft_test_result(step, "ptrace single-step after suppressing SIGSEGV\n"); + ksft_test_result(cont, "ptrace continue with TF after suppressing SIGSEGV\n"); +} + +static bool cpu_has_fred(void) +{ + unsigned int eax, ebx, ecx, edx; + + if (__get_cpuid_max(0, NULL) < 7) + return false; + __cpuid_count(7, 1, eax, ebx, ecx, edx); + return eax & (1 << 17); +} + +int main(void) +{ + unsigned int i, tf; + int expected_flags, ok; + + ksft_print_header(); + ksft_set_plan(2 * ARRAY_SIZE(tests) + 3); + ksft_print_msg("CPU %s FRED\n", cpu_has_fred() ? "supports" : "lacks"); + sethandler(SIGSEGV, handler, 0); + sethandler(SIGTRAP, handler, 0); + sethandler(SIGILL, handler, 0); + + for (tf = 0; tf < 2; tf++) { + for (i = 0; i < ARRAY_SIZE(tests); i++) { + active = &tests[i]; + single_step = tf; + seen = signo = trap = error = ip_offset = flags = 0; + code = addr_ok = stepped = step_ok = 0; + expected_flags = active->flags | (tf ? X86_EFLAGS_TF : 0); + if (tf) + active->run_tf(); + else + active->run(); + + ok = seen && signo == active->signo && trap == active->trap && + error == active->error && ip_offset == active->ip_offset && + flags == expected_flags && code == active->code && addr_ok && + (!tf || (stepped && step_ok)); + ksft_test_result(ok, "%s%s\n", active->name, tf ? " with TF" : ""); + if (!ok) { + ksft_print_msg("got signal=%d trap=%d error=%#x ip=%d\n", + signo, trap, error, ip_offset); + ksft_print_msg("got flags=%#x code=%d addr_ok=%d step_ok=%d\n", + flags, code, addr_ok, step_ok); + ksft_print_msg("expected signal=%d trap=%d error=%#x ip=%d\n", + active->signo, active->trap, active->error, + active->ip_offset); + ksft_print_msg("expected flags=%#x code=%d\n", + expected_flags, active->code); + } + } + } + test_ptrace(); + ksft_finished(); +} |
