Skip to contentSkip to conversation

6.18.17-rc1 review

PATCH In review Sasha Levin 16 participants 334 messages Mar 10 – Mar 17 Page 1 of 3

Subsystems (11)
lore
Share & tools
lore

Sasha Levin

author maintainer
#0 lore raw

cover 6.18.17-rc1 review

This is the start of the stable review cycle for the 6.18.17 release. There are 314 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.

Responses should be made by Thu Mar 12 11:19:16 AM UTC 2026. Anything received after that time might be too late.

The whole patch series can be found in one patch at:

        https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.git/rawdiff/?id=linux-6.18.y&id2=v6.18.16

or in the git tree and branch at:
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.git linux-6.18.y
and the diffstat can be found below.

Thanks,
Sasha

-------------
Pseudo-Shortlog of commits:

Aaron Ma (1):
ice: recap the VSI and QoS info after rebuild

Akhilesh Patil (1):
hwmon: (aht10) Add support for dht20

Aksh Garg (1):
PCI: dwc: ep: Fix resizable BAR support for multi-PF configurations

Alain Volmat (1):
spi: stm32: fix missing pointer assignment in case of dma chaining

Alban Bedel (1):
can: mcp251x: fix deadlock in error path of mcp251x_open

Alexander Stein (2):
ASoC: fsl_xcvr: use dev_err_probe() replacing dev_err() + return
ASoC: fsl_xcvr: provide regmap names

Alexandre Courbot (1):
rust: kunit: fix warning when !CONFIG_PRINTK

Allison Henderson (1):
net/rds: Fix circular locking dependency in rds_tcp_tune

Anand Moon (1):
PCI: j721e: Use devm_clk_get_optional_enabled() to get and enable the
clock

Andrew Cooper (1):
x86/fred: Correct speculative safety in fred_extint()

Andrew Lunn (1):
net: phy: register phy led_triggers during probe to avoid AB-BA
deadlock

Ankit Garg (1):
gve: fix incorrect buffer cleanup in gve_tx_clean_pending_packets for
QPL

Ariel Silver (1):
wifi: mac80211: bounds-check link_id in ieee80211_ml_reconfiguration

Bart Van Assche (5):
drm/amdgpu: Unlock a mutex before destroying it drm/amdgpu: Fix locking bugs in error paths
hwmon: (it87) Check the it87_lock() return value
wifi: cw1200: Fix locking in error paths
wifi: wlcore: Fix a locking bug

Bence Csókás (1):
ARM: dts: imx53-usbarmory: Replace license text comment with SPDX
identifier

Bjorn Helgaas (2):
PCI: Correct PCI_CAP_EXP_ENDPOINT_SIZEOF_V2 value
PCI: dwc: Advertise L1 PM Substates only if driver requests it

Bobby Eshleman (1):
net: devmem: use READ_ONCE/WRITE_ONCE on binding->dev

Brad Spengler (1):
drm/vmwgfx: Fix invalid kref_put callback in vmw_bo_dirty_release

Brian Vazquez (1):
idpf: change IRQ naming to match netdev and ethtool queue numbering

Catalin Marinas (1):
arm64: gcs: Do not set PTE_SHARED on GCS mappings if FEAT_LPA2 is
enabled

Charles Haithcock (1):
i2c: i801: Revert "i2c: i801: replace acpi_lock with I2C bus lock"

Chen Ni (1):
drm/imx: parallel-display: check return value of devm_drm_bridge_add()
in imx_pd_probe()

Chintan Vankar (1):
net: ethernet: ti: am65-cpsw-nuss/cpsw-ale: Fix multicast entry
handling in ALE table

Christian Brauner (1):
namespace: fix proc mount iteration

Christoph Böhmwalder (1):
drbd: fix null-pointer dereference on local read error

Christoph Hellwig (2):
zloop: advertise a volatile write cache
zloop: check for spurious options passed to remove

Conor Dooley (1):
pinctrl: generic: move function to amlogic-am4 driver

Corey Minyard (1):
ipmi: Fix use-after-free and list corruption on sender error

Daniel Hodges (1):
wifi: libertas: fix use-after-free in lbs_free_adapter()

Daniil Dulov (1):
wifi: cfg80211: cancel rfkill_block work in wiphy_unregister()

Darrick J. Wong (1):
xfs: fix xfs_group release bug in xfs_dax_notify_dev_failure

Dave Jiang (2):
cxl: Move devm_cxl_add_nvdimm_bridge() to cxl_pmem.ko
cxl: Fix race of nvdimm_bus object when creating nvdimm objects

David Carlier (1):
sched_ext: Fix SCX_EFLAG_INITIALIZED being a no-op flag

David Howells (1):
netfs: Fix unbuffered/DIO writes to dispatch subrequests in strict
sequence

David Thomson (1):
xen/acpi-processor: fix _CST detection using undersized evaluation
buffer

Davide Caratti (1):
net/sched: ets: fix divide by zero in the offload path

Deepanshu Kartikey (1):
mm: thp: deny THP for files on anonymous inodes

Dikshita Agarwal (2):
media: iris: remove v4l2_m2m_ioctl_{de,en}coder_cmd API usage during
STOP handling
media: iris: Add missing platform data entries for SM8750

Eduard Zingerman (1):
bpf: collect only live registers in linked regs

Eric Dumazet (5):
net: annotate data-races around sk->sk_{data_ready,write_space}
inet: annotate data-races around isk->inet_num
indirect_call_wrapper: do not reevaluate function pointer
tcp: secure_seq: add back ports to TS offset
net_sched: sch_fq: clear q->band_pkt_count[] in fq_reset()

Ethan Nelson-Moore (1):
net: arcnet: com20020-pci: fix support for 2.5Mbit cards

Ethan Tidmore (2):
drm/tiny: sharp-memory: fix pointer error dereference
xfs: Fix error pointer dereference

Fabio M. De Francesco (1):
ACPI: APEI: GHES: Add helper for CPER CXL protocol errors checks

Fedor Pchelkin (1):
ksmbd: call ksmbd_vfs_kern_path_end_removing() on some error paths

Felix Gu (4):
drm/logicvc: Fix device node reference leak in
logicvc_drm_config_parse()
regulator: bq257xx: Fix device node reference leak in

    bq257xx_reg_dt_parse_gpio()
  pinctrl: meson: amlogic-a4: Fix device node reference leak in
    aml_dt_node_to_map_pinmux()

pinctrl: cirrus: cs42l43: Fix double-put in cs42l43_pin_probe()

Fernando Fernandez Mancera (2):
net: bridge: fix nd_tbl NULL dereference when IPv6 is disabled
net: vxlan: fix nd_tbl NULL dereference when IPv6 is disabled

Florian Eckert (2):
pinctrl: equilibrium: rename irq_chip function callbacks
pinctrl: equilibrium: fix warning trace on load

Florian Westphal (1):
netfilter: nft_set_pipapo: split gc into unlink and reclaim phase

Francesco Lavra (1):
drm/solomon: Fix page start when updating rectangle in page addressing
mode

Fuad Tabba (3):
KVM: arm64: Hide S1POE from guests when not supported by the host
KVM: arm64: Fix ID register initialization for non-protected pKVM
guests
bpf, arm64: Force 8-byte alignment for JIT buffer to prevent atomic
tearing

Geoffrey D. Bennett (3):
ALSA: scarlett2: Fix DSP filter control array handling
ALSA: usb-audio: Remove VALIDATE_RATES quirk for Focusrite devices
ALSA: usb-audio: Add QUIRK_FLAG_SKIP_IFACE_SETUP

Greg Kroah-Hartman (12):
nfc: pn533: properly drop the usb interface reference on disconnect
net: usb: kaweth: validate USB endpoints
net: usb: kalmia: validate USB endpoints
net: usb: pegasus: validate USB endpoints
can: ems_usb: ems_usb_read_bulk_callback(): check the proper length of
a message
can: usb: f81604: correctly anchor the urb in the read bulk callback
can: ucan: Fix infinite loop from zero-length messages
can: usb: etas_es58x: correctly anchor the urb in the read bulk
callback
can: usb: f81604: handle short interrupt urb messages properly
can: usb: f81604: handle bulk write errors properly
HID: Add HID_CLAIMED_INPUT guards in raw_event callbacks missing them Revert "netfilter: nft_set_rbtree: validate open interval overlap"

Guenter Roeck (3):
dpaa2-switch: Fix interrupt storm after receiving bad if_id in IRQ
handler
ata: libata-eh: Fix detection of deferred qc timeouts
tracing: Add NULL pointer check to trigger_data_free()

Gui-Dong Han (1):
hwmon: (max16065) Use READ/WRITE_ONCE to avoid compiler optimization
induced race

Hao Yu (1):
hwmon: (aht10) Fix initialization commands for AHT20

Haocheng Yu (1):
perf/core: Fix refcount bug and potential UAF in perf_mmap

Harishankar Vishwanathan (1):
bpf: Introduce tnum_step to step through tnum's members

Harry Yoo (1):
mm/slab: use prandom if !allow_spin

Heiko Carstens (2):
s390/idle: Fix cpu idle exit cpu time accounting s390/vtime: Fix virtual timer forwarding

Heitor Alves de Siqueira (1):
Bluetooth: purge error queues in socket destructors

Henrique Carvalho (1):
smb: client: fix cifs_pick_channel when channels are equally loaded

Ian Forbes (1):
drm/vmwgfx: Return the correct value in vmw_translate_ptr functions

Ian Ray (2):
HID: multitouch: new class MT_CLS_EGALAX_P80H84
net: nfc: nci: Fix zero-length proprietary notifications

Imre Deak (2):
drm/i915/dp: Fail state computation for invalid DSC source input BPP
values
drm/i915/dp: Fix pipe BPP clamping due to HDR

Ingo Molnar (3):
sched/fair: Rename cfs_rq::avg_load to cfs_rq::sum_weight sched/fair: Rename cfs_rq::avg_vruntime to ::sum_w_vruntime, and
helper functions
sched/fair: Introduce and use the vruntime_cmp() and vruntime_op()
wrappers for wrapped-signed aritmetics

Jakub Kicinski (6):
tcp: give up on stronger sk_rcvbuf checks (for now)
ipv6: fix NULL pointer deref in ip6_rt_get_dev_rcu()
nfc: nci: free skb on nci_transceive early error paths
nfc: nci: complete pending data exchange on device close
nfc: nci: clear NCI_DATA_EXCHANGE before calling completion callback
nfc: rawsock: cancel tx_work before socket teardown

Jamal Hadi Salim (1):
net/sched: act_ife: Fix metalist update behavior

Jan Stancek (1):
x86/boot: Handle relative CONFIG_EFI_SBAT_FILE file paths

Jann Horn (1):
eventpoll: Fix integer overflow in ep_loop_check_proc()

Jason Gunthorpe (3):
IB/mthca: Add missed mthca_unmap_user_db() for mthca_create_srq() RDMA/irdma: Fix kernel stack leak in irdma_create_user_ah() RDMA/ionic: Fix kernel stack leak in ionic_create_cq()

Jens Axboe (1):
media: dvb-core: fix wrong reinitialization of ringbuffer on reopen

Jiayuan Chen (5):
bpf: Fix race in cpumap on PREEMPT_RT
bpf: Fix race in devmap on PREEMPT_RT
atm: lec: fix null-ptr-deref in lec_arp_clear_vccs bpf/bonding: reject vlan+srcmac xmit_hash_policy change when XDP is
loaded
net: ipv6: fix panic when IPv4 route references loopback IPv6 nexthop

Jinhui Guo (1):
iommu/vt-d: Skip dev-iotlb flush for inaccessible PCIe device without
scalable mode

Johan Hovold (4):
memory: mtk-smi: fix device leaks on common probe
memory: mtk-smi: fix device leak on larb probe drm/tegra: dsi: fix device leak on probe
clk: tegra: tegra124-emc: fix device leak on set_rate()

Johannes Berg (1):
wifi: radiotap: reject radiotap with unknown bits

Jonathan Cavitt (1):
drm/client: Do not destroy NULL modes

Jonathan Teh (1):
platform/x86: thinkpad_acpi: Fix errors reading battery thresholds

Josh Poimboeuf (1):
unwind_user/x86: Enable frame pointer unwinding on x86

Juhyung Park (2):
ALSA: hda/realtek: fix model name typo for Samsung Galaxy Book Flex

    (NT950QCG-X716)
  ALSA: hda/realtek: add quirk for Samsung Galaxy Book Flex
    (NT950QCT-A38A)

Julian Orth (1):
drm/syncobj: Fix handle <-> fd ioctls with dirty stack

Jun Seo (1):
ALSA: usb-audio: Use correct version for UAC3 header validation

Junxiao Bi (1):
scsi: core: Fix refcount leak for tagset_refcnt

Justin Tee (1):
nvmet-fcloop: Check remoteport port_state before calling done callback

Keith Busch (1):
nvme-multipath: fix leak on try_module_get failure

Khushit Shah (1):
KVM: x86: Add x2APIC "features" to control EOI broadcast suppression

Kim Phillips (1):
x86/sev: Allow IBPB-on-Entry feature for SNP guests

Kohei Enju (2):
bpf: Fix stack-out-of-bounds write in devmap
iavf: fix netdev->max_mtu to respect actual hardware limit

Koichiro Den (1):
net: sched: avoid qdisc_reset_all_tx_gt() vs dequeue race for lockless
qdiscs

Kuen-Han Tsai (3):
usb: gadget: u_ether: add gether_opts for config caching
usb: gadget: u_ether: Add auto-cleanup helper for freeing net_device
usb: gadget: f_ncm: align net_device lifecycle with bind/unbind

Kuniyuki Iwashima (2):
nfsd: Fix cred ref leak in nfsd_nl_threads_set_doit().
udp: Unhash auto-bound connected sk from 4-tuple hash table when
disconnected.

Kurt Borja (2):
platform/x86: alienware-wmi-wmax: Add G-Mode support to m18 laptops platform/x86: dell-wmi: Add audio/mic mute key codes

Lang Xu (1):
bpf: Fix a UAF issue in bpf_trampoline_link_cgroup_shim

Lars Ellenberg (1):
drbd: fix "LOGIC BUG" in drbd_al_begin_io_nonblock()

Larysa Zaremba (7):
ice: fix adding AQ LLDP filter for VF
xdp: use modulo operation to calculate XDP frag tailroom
xsk: introduce helper to determine rxq->frag_size
i40e: fix registering XDP RxQ info
i40e: use xdp.frame_sz as XDP RxQ info frag_size
net: enetc: use truesize as XDP RxQ info frag_size
xdp: produce a warning when calculated tailroom is negative

Li Li (1):
idpf: increment completion queue next_to_clean in sw marker wait
routine

Lijo Lazar (1):
drm/amdgpu: Fix error handling in slot reset

Lizhi Hou (3):
accel/amdxdna: Remove buffer size check when creating command BO accel/amdxdna: Prevent ubuf size overflow accel/amdxdna: Validate command buffer payload count

Lorenzo Bianconi (4):
wifi: mt76: mt7996: Fix possible oob access in

    mt7996_mac_write_txwi_80211()
  wifi: mt76: mt7925: Fix possible oob access in
    mt7925_mac_write_txwi_80211()
  wifi: mt76: Fix possible oob access in
    mt76_connac2_mac_write_txwi_80211()

net: ethernet: mtk_eth_soc: Reset prog ptr to old_prog in case of
error in mtk_xdp_setup()

MD Danish Anwar (1):
net: ti: icssg-prueth: Fix ping failure after offload mode setup when
link speed is not 1G

Manivannan Sadhasivam (1):
net: qrtr: Drop the MHI auto_queue feature for IPCR DL channels

Marco Crivellari (1):
Input: synaptics_i2c - replace use of system_wq with system_dfl_wq

Mario Limonciello (2):
drm/amd: Fix hang on amdgpu unload by using pci_dev_is_disconnected() platform/x86: hp-bioscfg: Support allocations of larger data

Mariusz Skamra (1):
Bluetooth: Fix CIS host feature condition

Mark Harmstone (6):
btrfs: fix error message order of parameters in
btrfs_delete_delayed_dir_index()
btrfs: fix incorrect key offset in error message in
check_dev_extent_item()
btrfs: fix objectid value in error message in check_extent_data_ref()
btrfs: fix warning in scrub_verify_one_metadata()
btrfs: print correct subvol num if active swapfile prevents deletion
btrfs: fix compat mask in error messages in btrfs_check_features()

Mathias Krause (1):
scsi: lpfc: Properly set WC for DPP mapping

Mathieu Desnoyers (1):
rseq: Clarify rseq registration rseq_size bound check comment

Matt Roper (1):
drm/xe/wa: Steer RMW of MCR registers while building default LRC

Matthew Brost (1):
drm/xe: Do not preempt fence signaling CS instructions

Matthieu Baerts (NGI0) (4):
mptcp: pm: avoid sending RM_ADDR over same subflow
mptcp: pm: in-kernel: always mark signal+subflow endp as used
selftests: mptcp: join: check RM_ADDR not sent over same subflow
selftests: mptcp: join: check removing signal+subflow endp

Maulik Shah (1):
pinctrl: qcom: qcs615: Add missing dual edge GPIO IRQ errata flag

Michal Swiatkowski (1):
libie: don't unroll if fwlog isn't supported

Mieczyslaw Nalewaj (1):
net: dsa: realtek: rtl8365mb: fix rtl8365mb_phy_ocp_write return value

Mike Rapoport (Microsoft) (1):
x86/efi: defer freeing of boot services memory

Ming Lei (2):
nvme: fix admin queue leak on controller reset
block: use trylock to avoid lockdep circular dependency in sysfs

Ming Qian (1):
media: verisilicon: Avoid G2 bus error while decoding H.264 and HEVC

Minseong Kim (1):
Input: synaptics_i2c - guard polling restart in resume

Miquel Sabaté Solà (2):
btrfs: free pages on error in btrfs_uring_read_extent()
btrfs: define the AUTO_KFREE/AUTO_KVFREE helper macros

Miroslav Lichvar (1):
timekeeping: Fix timex status validation for auxiliary clocks

Nam Cao (1):
irqchip/sifive-plic: Fix frozen interrupt due to affinity setting

Namhyung Kim (1):
perf/core: Fix invalid wait context in ctx_sched_in()

Naohiro Aota (1):
btrfs: zoned: fixup last alloc pointer after extent removal for

    RAID0/10

Natalie Vock (1):
drm/amd/display: Use GFP_ATOMIC in dc_create_stream_for_sink

Nathan Chancellor (2):
ACPI: APEI: GHES: Disable KASAN instrumentation when compile testing
with clang < 18
kbuild: Split .modinfo out from ELF_DETAILS

Nicolas Dufresne (1):
media: v4l2-mem2mem: Add a kref to the v4l2_m2m_dev structure

Nikhil P. Rao (2):
xsk: Fix fragment node deletion to prevent buffer leak
xsk: Fix zero-copy AF_XDP fragment drop

Niklas Cassel (2):
PCI: dwc: ep: Flush MSI-X write before unmapping its ATU entry Revert "PCI: dw-rockchip: Enumerate endpoints based on dll_link_up
IRQ"

Oleg Nesterov (1):
x86/uprobes: Fix XOL allocation failure for 32-bit tasks

Oliver Hartkopp (1):
can: bcm: fix locking for bcm_op runtime updates

Olivier Sobrie (1):
hwmon: (max6639) fix inverted polarity

Ovidiu Panait (4):
net: stmmac: Fix error handling in VLAN add and delete paths
net: stmmac: Improve double VLAN handling
net: stmmac: Fix VLAN HW state restore
net: stmmac: Defer VLAN HW configuration when interface is down

Pablo Neira Ayuso (2):
netfilter: nf_tables: unconditionally bump set->nelems before
insertion
netfilter: nf_tables: clone set on flush only

Panagiotis Foliadis (2):
ALSA: hda/intel: increase default bdl_pos_adj for Nvidia controllers
ALSA: hda/realtek: Add quirk for Acer Aspire V3-572G

Paolo Abeni (1):
selftests: mptcp: more stable simult_flows tests

Paul Chaignon (1):
bpf: Improve bounds when tnum has a single possible value

Paulo Alcantara (2):
smb: client: fix broken multichannel with krb5+signing
smb: client: fix oops due to uninitialised var in smb2_unlink()

Peter Wang (1):
scsi: ufs: core: Move link recovery for hibern8 exit failure to
wl_resume

Peter Zijlstra (8):
x86/cfi: Fix CFI rewrite for odd alignments
sched/fair: Fix zero_vruntime tracking
sched/fair: Only set slice protection at pick time sched/fair: Fix lag clamp
perf: Fix __perf_event_overflow() vs perf_remove_from_context() race
unwind: Simplify unwind_user_next_fp() alignment check
unwind: Implement compat fp unwind
unwind_user/x86: Teach FP unwind about start of function

Petr Pavlu (1):
module: Remove duplicate freeing of lockdep classes

Phillip Lougher (1):
Squashfs: check metadata block offset is within range

Prithvi Tambewagh (1):
scsi: target: Fix recursive locking in __configfs_open_file()

Qiang Yu (3):
PCI: Add preceding capability position support in PCI_FIND_NEXT_*_CAP
macros
PCI: dwc: Add new APIs to remove standard and extended Capability
PCI: dwc: Remove duplicate dw_pcie_ep_hide_ext_capability() function

Qing Wang (1):
tracing: Fix WARN_ON in tracing_buffers_mmap_close

Quentin Schulz (2):
accel/rocket: fix unwinding in error path in rocket_core_init accel/rocket: fix unwinding in error path in rocket_probe

Raju Rangoju (2):
amd-xgbe: fix MAC_TCR_SS register width for 2.5G and 10M speeds
amd-xgbe: fix sleep while atomic on suspend/resume

Richard Fitzgerald (1):
ALSA: hda: cs35l56: Fix signedness error in cs35l56_hda_posture_put()

Rong Zhang (1):
ALSA: doc: usb-audio: Add doc for QUIRK_FLAG_SKIP_IFACE_SETUP

Russell King (Oracle) (1):
net: stmmac: remove support for lpi_intr_o

Salomon Dushimirimana (1):
scsi: pm8001: Fix use-after-free in pm8001_queue_command()

Sasha Levin (1):
Linux 6.18.17-rc1

Sean Christopherson (1):
KVM: x86: Ignore -EBUSY when checking nested events from vcpu_block()

Sebastian Andrzej Siewior (1):
net: Provide a PREEMPT_RT specific check for netdev_queue::_xmit_lock

Sebastian Krzyszkowiak (1):
wifi: rsi: Don't default to -EOPNOTSUPP in rsi_mac80211_config

Shawn Lin (5):
PCI: dw-rockchip: Configure L1SS support
PCI: dwc: Add L1 Substates context to ltssm_status of debugfs
PCI: dw-rockchip: Change get_ltssm() to provide L1 Substates info
arm64: dts: rockchip: Fix rk356x PCIe range mappings
arm64: dts: rockchip: Fix rk3588 PCIe range mappings

Shuicheng Lin (2):
drm/xe/configfs: Free ctx_restore_mid_bb in release drm/xe/reg_sr: Fix leak on xa_store failure

Shuvam Pandey (1):
kunit: tool: copy caller args in run_kernel to prevent mutation

Siddharth Vadapalli (1):
PCI: j721e: Add config guards for Cadence Host and Endpoint library
APIs

Simon Ser (1):
drm/fourcc: fix plane order for 10/12/16-bit YCbCr formats

Sreedevi Joshi (1):
idpf: Fix flow rule delete failure due to invalid validation

Srinivas Pandruvada (1):
cpufreq: intel_pstate: Fix crash during turbo disable

Stefan Hajnoczi (1):
nvme: reject invalid pr_read_keys() num_keys values

Sun Jian (1):
selftests/harness: order TEST_F and XFAIL_ADD constructors

Sungwoo Kim (1):
nvme: fix memory allocation in nvme_pr_read_keys()

T.J. Mercier (1):
selftests/bpf: Fix OOB read in dmabuf_collector

Takashi Iwai (4):
ALSA: usb-audio: Cap the packet size pre-calculations
ALSA: usb-audio: Use inclusive terms
ALSA: usb: qcom: Correct parameter comment for
uaudio_transfer_buffer_setup()
ASoC: SDCA: Fix comments for sdca_irq_request()

Thomas Gleixner (2):
debugobject: Make it work with deferred page initialization - again
i40e: Fix preempt count leak in napi poll tracepoint

Thomas Weißschuh (1):
ARM: clean up the memset64() C wrapper

Thorsten Blum (2):
platform/x86: dell-wmi-sysman: Don't hex dump plaintext password data
smb: client: Don't log plaintext credentials in cifs_set_cifscreds

Tianci Cao (1):
bpf: Add bitwise tracking for BPF_END

Tiezhu Yang (3):
LoongArch: Remove unnecessary checks for ORC unwinder
LoongArch: Handle percpu handler address for ORC unwinder
LoongArch: Remove some extern variables in source files

Tom Lendacky (1):
x86/boot/sev: Move SEV decompressor variables into the .data section

Tomasz Pakuła (1):
HID: pidff: Fix condition effect bit clearing

Tvrtko Ursulin (1):
drm/amdgpu/userq: Do not allow userspace to trivially triger kernel
warnings

Vahagn Vardanian (1):
wifi: mac80211: fix NULL pointer dereference in mesh_rx_csa_frame()

Vimlesh Kumar (4):
octeon_ep: Relocate counter updates before NAPI
octeon_ep: avoid compiler and IQ/OQ reordering
octeon_ep_vf: Relocate counter updates before NAPI
octeon_ep_vf: avoid compiler and IQ/OQ reordering

Vitaly Lifshits (1):
e1000e: clear DPG_EN after reset to avoid autonomous power-gating

Vivek Behera (1):
igb: Fix trigger of incorrect irq in igb_xsk_wakeup

Vlastimil Babka (1):
slub: remove CONFIG_SLUB_TINY specific code paths

Waiman Long (1):
cgroup/cpuset: Fix incorrect use of cpuset_update_tasks_cpumask() in
update_cpumasks_hier()

Wake Liu (1):
kselftest/harness: Use helper to avoid zero-size memset warning

Wang Tao (1):
sched/eevdf: Update se->vprot in reweight_entity()

Werner Sembach (1):
HID: multitouch: Keep latency normal on deactivate for reactivation
gesture

Will Deacon (2):
arm64: io: Rename ioremap_prot() to __ioremap_prot()
arm64: io: Extract user memory type in ioremap_prot()

Xuewen Yan (1):
PM: sleep: core: Avoid bit field races related to work_in_progress

Yang Erkun (1):
ext4: correct the comments place for EXT4_EXT_MAY_ZEROOUT

Yazen Ghannam (1):
x86/acpi/boot: Correct acpi_is_processor_usable() check again

Yifan Wu (1):
selftest/arm64: Fix sve2p1_sigill() to hwcap test

Yujie Liu (1):
drm/sched: Fix kernel-doc warning for drm_sched_job_done()

Yung Chih Su (1):
net: ipv4: fix ARM64 alignment fault in multipath hash seed

Zhang Heng (1):
ALSA: hda/realtek: Add quirk for HP Pavilion 15-eh1xxx to enable mute
LED

Zhang Yi (1):
ext4: don't set EXT4_GET_BLOCKS_CONVERT when splitting before
submitting I/O

ZhangGuoDong (2):
smb/client: fix buffer size for smb311_posix_qinfo in

    smb2_compound_op()
  smb/client: fix buffer size for smb311_posix_qinfo in
    SMB311_posix_query_info()

Zhanjun Dong (1):
drm/xe/gsc: Fix GSC proxy cleanup on early initialization failure

Zide Chen (1):
perf/x86/intel/uncore: Add per-scheduler IMC CAS count events

Zilin Guan (1):
media: tegra-video: Fix memory leak in __tegra_channel_try_format()

 Documentation/hwmon/aht10.rst                 |  10 +-
 Documentation/sound/alsa-configuration.rst    |   4 +
 Documentation/virt/kvm/api.rst                |  28 ++-
 Makefile                                      |   4 +-
 arch/alpha/kernel/vmlinux.lds.S               |   1 +
 arch/arc/kernel/vmlinux.lds.S                 |   1 +
 arch/arm/boot/compressed/vmlinux.lds.S        |   1 +
 arch/arm/boot/dts/nxp/imx/imx53-usbarmory.dts |  39 +--
 arch/arm/include/asm/string.h                 |  14 +-
 arch/arm/kernel/vmlinux-xip.lds.S             |   1 +
 arch/arm/kernel/vmlinux.lds.S                 |   1 +
 arch/arm64/boot/dts/rockchip/rk3568.dtsi      |   4 +-
 arch/arm64/boot/dts/rockchip/rk356x-base.dtsi |   2 +-
 arch/arm64/boot/dts/rockchip/rk3588-base.dtsi |   4 +-
 .../arm64/boot/dts/rockchip/rk3588-extra.dtsi |   6 +-
 arch/arm64/include/asm/io.h                   |  26 +-
 arch/arm64/include/asm/pgtable-prot.h         |   3 -
 arch/arm64/kernel/acpi.c                      |   2 +-
 arch/arm64/kernel/vmlinux.lds.S               |   1 +
 arch/arm64/kvm/hyp/nvhe/pkvm.c                |  35 ++-
 arch/arm64/kvm/sys_regs.c                     |   3 +
 arch/arm64/mm/ioremap.c                       |   6 +-
 arch/arm64/mm/mmap.c                          |   8 +-
 arch/arm64/net/bpf_jit_comp.c                 |   2 +-
 arch/csky/kernel/vmlinux.lds.S                |   1 +
 arch/hexagon/kernel/vmlinux.lds.S             |   1 +
 arch/loongarch/include/asm/setup.h            |   3 +
 arch/loongarch/kernel/unwind_orc.c            |  28 ++-
 arch/loongarch/kernel/unwind_prologue.c       |   4 -
 arch/loongarch/kernel/vmlinux.lds.S           |   1 +
 arch/loongarch/mm/tlb.c                       |   1 -
 arch/m68k/kernel/vmlinux-nommu.lds            |   1 +
 arch/m68k/kernel/vmlinux-std.lds              |   1 +
 arch/m68k/kernel/vmlinux-sun3.lds             |   1 +
 arch/mips/kernel/vmlinux.lds.S                |   1 +
 arch/nios2/kernel/vmlinux.lds.S               |   1 +
 arch/openrisc/kernel/vmlinux.lds.S            |   1 +
 arch/parisc/boot/compressed/vmlinux.lds.S     |   1 +
 arch/parisc/kernel/vmlinux.lds.S              |   1 +
 arch/powerpc/kernel/vmlinux.lds.S             |   1 +
 arch/riscv/kernel/vmlinux.lds.S               |   1 +
 arch/s390/include/asm/idle.h                  |   1 +
 arch/s390/kernel/idle.c                       |  13 +-
 arch/s390/kernel/irq.c                        |  10 +-
 arch/s390/kernel/vmlinux.lds.S                |   1 +
 arch/s390/kernel/vtime.c                      |  18 +-
 arch/sh/kernel/vmlinux.lds.S                  |   1 +
 arch/sparc/kernel/vmlinux.lds.S               |   1 +
 arch/um/kernel/dyn.lds.S                      |   1 +
 arch/um/kernel/uml.lds.S                      |   1 +
 arch/x86/Kconfig                              |   1 +
 arch/x86/boot/compressed/Makefile             |   1 +
 arch/x86/boot/compressed/sev.c                |   9 +-
 arch/x86/boot/compressed/vmlinux.lds.S        |   2 +-
 arch/x86/boot/startup/sev-shared.c            |   2 +-
 arch/x86/coco/sev/core.c                      |   1 +
 arch/x86/entry/entry_fred.c                   |   5 +-
 arch/x86/events/core.c                        |  40 ---
 arch/x86/events/intel/uncore_snbep.c          |  28 ++-
 arch/x86/include/asm/cfi.h                    |  12 +-
 arch/x86/include/asm/efi.h                    |   2 +-
 arch/x86/include/asm/kvm_host.h               |   7 +
 arch/x86/include/asm/linkage.h                |   4 +-
 arch/x86/include/asm/msr-index.h              |   5 +-
 arch/x86/include/asm/unwind_user.h            |  37 +++
 arch/x86/include/asm/uprobes.h                |   9 +
 arch/x86/include/uapi/asm/kvm.h               |   6 +-
 arch/x86/kernel/acpi/boot.c                   |  12 +-
 arch/x86/kernel/alternative.c                 |  29 ++-
 arch/x86/kernel/cpu/topology.c                |  15 --
 arch/x86/kernel/uprobes.c                     |  56 +++++
 arch/x86/kernel/vmlinux.lds.S                 |   1 +
 arch/x86/kvm/ioapic.c                         |   2 +-
 arch/x86/kvm/lapic.c                          |  76 +++++-
 arch/x86/kvm/lapic.h                          |   2 +
 arch/x86/kvm/x86.c                            |  24 +-
 arch/x86/net/bpf_jit_comp.c                   |  13 +-
 arch/x86/platform/efi/efi.c                   |   2 +-
 arch/x86/platform/efi/quirks.c                |  55 +++-
 block/blk-sysfs.c                             |   8 +-
 block/elevator.c                              |  12 +-
 drivers/accel/amdxdna/amdxdna_ctx.c           |   5 +-
 drivers/accel/amdxdna/amdxdna_gem.c           |  38 +--
 drivers/accel/amdxdna/amdxdna_ubuf.c          |   6 +-
 drivers/accel/qaic/mhi_controller.c           |  44 ----
 drivers/accel/rocket/rocket_core.c            |   7 +-
 drivers/accel/rocket/rocket_drv.c             |  15 +-
 drivers/acpi/apei/Makefile                    |   5 +
 drivers/acpi/apei/ghes.c                      |  18 +-
 drivers/acpi/apei/ghes_helpers.c              |  33 +++
 drivers/ata/libata-eh.c                       |   2 +-
 drivers/block/drbd/drbd_actlog.c              |  53 ++--
 drivers/block/drbd/drbd_interval.h            |   5 +-
 drivers/block/drbd/drbd_req.c                 |   3 +-
 drivers/block/zloop.c                         |  31 ++-
 drivers/bus/mhi/host/pci_generic.c            |  20 +-
 drivers/char/ipmi/ipmi_msghandler.c           |  11 +-
 drivers/clk/tegra/clk-tegra124-emc.c          |   2 +-
 drivers/cpufreq/intel_pstate.c                |  10 +-
 drivers/cxl/core/pmem.c                       |  42 +++-
 drivers/cxl/cxl.h                             |   7 +
 drivers/cxl/pmem.c                            |  22 +-
 drivers/firmware/efi/mokvar-table.c           |   2 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_aca.c       |   1 +
 drivers/gpu/drm/amd/amdgpu/amdgpu_device.c    |  21 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_psp_ta.c    |  12 +-
 .../gpu/drm/amd/amdgpu/amdgpu_userq_fence.c   |   8 +-
 .../gpu/drm/amd/display/dc/core/dc_stream.c   |   2 +-
 drivers/gpu/drm/drm_client_modeset.c          |   3 +-
 drivers/gpu/drm/drm_syncobj.c                 |   4 +-
 drivers/gpu/drm/i915/display/intel_dp.c       |  48 +++-
 drivers/gpu/drm/imx/ipuv3/parallel-display.c  |   4 +-
 drivers/gpu/drm/logicvc/logicvc_drm.c         |   4 +-
 drivers/gpu/drm/scheduler/sched_main.c        |   1 +
 drivers/gpu/drm/solomon/ssd130x.c             |   6 +-
 drivers/gpu/drm/tegra/dsi.c                   |   6 +-
 drivers/gpu/drm/tiny/sharp-memory.c           |   4 +-
 drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c       |   4 +-
 drivers/gpu/drm/vmwgfx/vmwgfx_page_dirty.c    |   9 +-
 drivers/gpu/drm/xe/regs/xe_engine_regs.h      |   6 +
 drivers/gpu/drm/xe/xe_configfs.c              |   1 +
 drivers/gpu/drm/xe/xe_gsc_proxy.c             |  43 +++-
 drivers/gpu/drm/xe/xe_gsc_types.h             |   2 +
 drivers/gpu/drm/xe/xe_gt.c                    |  66 ++++-
 drivers/gpu/drm/xe/xe_reg_sr.c                |   4 +-
 drivers/gpu/drm/xe/xe_ring_ops.c              |   9 +
 drivers/hid/hid-cmedia.c                      |   2 +-
 drivers/hid/hid-creative-sb0540.c             |   2 +-
 drivers/hid/hid-multitouch.c                  |  43 +++-
 drivers/hid/hid-zydacron.c                    |   2 +-
 drivers/hid/usbhid/hid-pidff.c                |  11 +-
 drivers/hwmon/Kconfig                         |   6 +-
 drivers/hwmon/aht10.c                         |  21 +-
 drivers/hwmon/it87.c                          |   5 +-
 drivers/hwmon/max16065.c                      |  26 +-
 drivers/hwmon/max6639.c                       |   2 +-
 drivers/i2c/busses/i2c-i801.c                 |  14 +-
 .../infiniband/hw/ionic/ionic_controlpath.c   |   2 +-
 drivers/infiniband/hw/irdma/verbs.c           |   2 +-
 drivers/infiniband/hw/mthca/mthca_provider.c  |   5 +-
 drivers/input/mouse/synaptics_i2c.c           |  13 +-
 drivers/iommu/intel/pasid.c                   |   8 +
 drivers/irqchip/irq-sifive-plic.c             |   7 +-
 drivers/media/dvb-core/dmxdev.c               |   4 +-
 .../platform/qcom/iris/iris_platform_gen2.c   |   2 +
 drivers/media/platform/qcom/iris/iris_vidc.c  |  10 +-
 drivers/media/platform/verisilicon/hantro.h   |   2 +
 .../media/platform/verisilicon/hantro_drv.c   |  42 +++-
 .../media/platform/verisilicon/imx8m_vpu_hw.c |   8 +
 drivers/media/v4l2-core/v4l2-mem2mem.c        |  23 ++
 drivers/memory/mtk-smi.c                      |   3 +
 drivers/net/arcnet/com20020-pci.c             |  16 +-
 drivers/net/bonding/bond_main.c               |   9 +-
 drivers/net/bonding/bond_options.c            |   2 +
 drivers/net/can/spi/mcp251x.c                 |  15 +-
 drivers/net/can/usb/ems_usb.c                 |   7 +-
 drivers/net/can/usb/etas_es58x/es58x_core.c   |   8 +-
 drivers/net/can/usb/f81604.c                  |  45 +++-
 drivers/net/can/usb/ucan.c                    |   2 +-
 drivers/net/dsa/realtek/rtl8365mb.c           |   2 +-
 drivers/net/ethernet/amd/xgbe/xgbe-common.h   |   2 +-
 drivers/net/ethernet/amd/xgbe/xgbe-drv.c      |  10 -
 drivers/net/ethernet/amd/xgbe/xgbe-main.c     |   1 -
 drivers/net/ethernet/amd/xgbe/xgbe.h          |   3 -
 .../ethernet/freescale/dpaa2/dpaa2-switch.c   |   3 +-
 drivers/net/ethernet/freescale/enetc/enetc.c  |   2 +-
 drivers/net/ethernet/google/gve/gve_tx_dqo.c  |  56 ++---
 drivers/net/ethernet/intel/e1000e/defines.h   |   1 +
 drivers/net/ethernet/intel/e1000e/ich8lan.c   |   9 +
 drivers/net/ethernet/intel/i40e/i40e_main.c   |  41 +--
 drivers/net/ethernet/intel/i40e/i40e_trace.h  |   2 +-
 drivers/net/ethernet/intel/i40e/i40e_txrx.c   |   5 +-
 drivers/net/ethernet/intel/iavf/iavf_main.c   |  17 +-
 drivers/net/ethernet/intel/ice/ice.h          |   1 +
 drivers/net/ethernet/intel/ice/ice_common.c   |   2 +-
 drivers/net/ethernet/intel/ice/ice_idc.c      |  44 +++-
 drivers/net/ethernet/intel/ice/ice_main.c     |   7 +-
 .../net/ethernet/intel/idpf/idpf_ethtool.c    |   3 -
 drivers/net/ethernet/intel/idpf/idpf_txrx.c   |   8 +-
 drivers/net/ethernet/intel/igb/igb_xsk.c      |  38 ++-
 drivers/net/ethernet/intel/libie/fwlog.c      |   4 +
 .../ethernet/marvell/octeon_ep/octep_main.c   |  40 ++-
 .../net/ethernet/marvell/octeon_ep/octep_rx.c |  27 +-
 .../marvell/octeon_ep_vf/octep_vf_main.c      |  38 ++-
 .../marvell/octeon_ep_vf/octep_vf_rx.c        |  28 ++-
 drivers/net/ethernet/mediatek/mtk_eth_soc.c   |  15 +-
 drivers/net/ethernet/stmicro/stmmac/common.h  |   1 -
 .../net/ethernet/stmicro/stmmac/dwmac-intel.c |   4 -
 .../ethernet/stmicro/stmmac/dwmac-loongson.c  |   7 -
 drivers/net/ethernet/stmicro/stmmac/stmmac.h  |   3 +-
 .../net/ethernet/stmicro/stmmac/stmmac_main.c |  89 +++----
 .../ethernet/stmicro/stmmac/stmmac_platform.c |   8 -
 .../net/ethernet/stmicro/stmmac/stmmac_vlan.c |  60 ++---
 drivers/net/ethernet/ti/am65-cpsw-nuss.c      |   2 +-
 drivers/net/ethernet/ti/cpsw_ale.c            |   9 +-
 drivers/net/ethernet/ti/icssg/icssg_prueth.c  |   8 +
 drivers/net/phy/phy_device.c                  |  25 +-
 drivers/net/usb/kalmia.c                      |   7 +
 drivers/net/usb/kaweth.c                      |  13 +
 drivers/net/usb/pegasus.c                     |  13 +-
 drivers/net/vxlan/vxlan_core.c                |   5 +
 drivers/net/wireless/ath/ath11k/mhi.c         |   4 -
 drivers/net/wireless/ath/ath12k/mhi.c         |   4 -
 drivers/net/wireless/marvell/libertas/main.c  |   4 +-
 .../wireless/mediatek/mt76/mt76_connac_mac.c  |   1 +
 .../net/wireless/mediatek/mt76/mt7925/mac.c   |   1 +
 .../net/wireless/mediatek/mt76/mt7996/mac.c   |   1 +
 drivers/net/wireless/rsi/rsi_91x_mac80211.c   |   2 +-
 drivers/net/wireless/st/cw1200/pm.c           |   2 +
 drivers/net/wireless/ti/wlcore/main.c         |   4 +-
 drivers/nfc/pn533/usb.c                       |   1 +
 drivers/nvme/host/core.c                      |   7 +
 drivers/nvme/host/multipath.c                 |  12 +-
 drivers/nvme/host/pr.c                        |  10 +-
 drivers/nvme/target/fcloop.c                  |  15 +-
 drivers/pci/controller/cadence/pci-j721e.c    |  57 +++--
 drivers/pci/controller/cadence/pcie-cadence.c |   4 +-
 .../controller/dwc/pcie-designware-debugfs.c  |   2 +
 .../pci/controller/dwc/pcie-designware-ep.c   |  86 +++----
 .../pci/controller/dwc/pcie-designware-host.c |   2 +
 drivers/pci/controller/dwc/pcie-designware.c  |  83 +++++-
 drivers/pci/controller/dwc/pcie-designware.h  |  15 +-
 drivers/pci/controller/dwc/pcie-dw-rockchip.c | 130 +++++-----
 drivers/pci/controller/dwc/pcie-qcom.c        |   2 +
 drivers/pci/controller/dwc/pcie-tegra194.c    |   3 +
 drivers/pci/pci.c                             |   8 +-
 drivers/pci/pci.h                             |  23 +-
 drivers/pinctrl/cirrus/pinctrl-cs42l43.c      |   5 +-
 drivers/pinctrl/meson/pinctrl-amlogic-a4.c    |  70 +++++-
 drivers/pinctrl/pinconf-generic.c             |  69 -----
 drivers/pinctrl/pinctrl-equilibrium.c         |  31 ++-
 drivers/pinctrl/qcom/pinctrl-qcs615.c         |   1 +
 .../platform/x86/dell/alienware-wmi-wmax.c    |   2 +-
 drivers/platform/x86/dell/dell-wmi-base.c     |   6 +
 .../dell-wmi-sysman/passwordattr-interface.c  |   1 -
 .../x86/hp/hp-bioscfg/enum-attributes.c       |   9 +-
 drivers/platform/x86/lenovo/thinkpad_acpi.c   |   6 +-
 drivers/regulator/bq257xx-regulator.c         |   3 +-
 drivers/scsi/lpfc/lpfc_init.c                 |   2 +
 drivers/scsi/lpfc/lpfc_sli.c                  |  36 ++-
 drivers/scsi/lpfc/lpfc_sli4.h                 |   3 +
 drivers/scsi/pm8001/pm8001_sas.c              |   5 +-
 drivers/scsi/scsi_scan.c                      |   1 +
 drivers/spi/spi-stm32.c                       |   3 +
 drivers/staging/media/tegra-video/vi.c        |  13 +-
 drivers/target/target_core_configfs.c         |  15 +-
 drivers/ufs/core/ufshcd.c                     |  18 +-
 drivers/usb/gadget/function/f_ncm.c           | 128 +++++-----
 drivers/usb/gadget/function/u_ether.c         |  45 ++++
 drivers/usb/gadget/function/u_ether.h         |  30 +++
 .../usb/gadget/function/u_ether_configfs.h    | 176 +++++++++++++
 drivers/usb/gadget/function/u_ncm.h           |   4 +-
 drivers/xen/xen-acpi-processor.c              |   7 +-
 fs/btrfs/delayed-inode.c                      |   2 +-
 fs/btrfs/disk-io.c                            |   6 +-
 fs/btrfs/inode.c                              |   2 +-
 fs/btrfs/ioctl.c                              |   7 +-
 fs/btrfs/misc.h                               |   7 +
 fs/btrfs/scrub.c                              |   2 +-
 fs/btrfs/tree-checker.c                       |   4 +-
 fs/btrfs/zoned.c                              | 194 ++++++++++++--
 fs/eventpoll.c                                |   5 +-
 fs/ext4/extents.c                             |  20 +-
 fs/namespace.c                                |  20 +-
 fs/netfs/direct_write.c                       | 228 +++++++++++++++--
 fs/netfs/internal.h                           |   4 +-
 fs/netfs/write_collect.c                      |  21 --
 fs/netfs/write_issue.c                        |  41 +--
 fs/nfsd/nfsctl.c                              |   2 +-
 fs/smb/client/connect.c                       |   1 -
 fs/smb/client/smb2inode.c                     |   8 +-
 fs/smb/client/smb2pdu.c                       |  24 +-
 fs/smb/client/transport.c                     |  21 +-
 fs/smb/server/smb2pdu.c                       |   4 +-
 fs/squashfs/cache.c                           |   3 +
 fs/xfs/scrub/orphanage.c                      |   7 +-
 fs/xfs/xfs_notify_failure.c                   |   4 +-
 include/asm-generic/vmlinux.lds.h             |   4 +-
 include/cxl/event.h                           |  10 +
 include/linux/indirect_call_wrapper.h         |  18 +-
 include/linux/netdevice.h                     |  27 +-
 include/linux/pinctrl/pinconf-generic.h       |   5 -
 include/linux/pm.h                            |   2 +-
 include/linux/ring_buffer.h                   |   1 +
 include/linux/sched.h                         |   1 +
 include/linux/stmmac.h                        |   1 -
 include/linux/tnum.h                          |   8 +
 include/linux/unwind_user_types.h             |   2 +
 include/linux/uprobes.h                       |   1 +
 include/media/v4l2-mem2mem.h                  |  21 ++
 include/net/bonding.h                         |   1 +
 include/net/inet6_hashtables.h                |   2 +-
 include/net/inet_hashtables.h                 |   2 +-
 include/net/ip.h                              |   2 +-
 include/net/ip_fib.h                          |   2 +-
 include/net/netfilter/nf_tables.h             |  11 +-
 include/net/sch_generic.h                     |  10 +
 include/net/secure_seq.h                      |  45 +++-
 include/net/tc_act/tc_ife.h                   |   4 +-
 include/net/tcp.h                             |   6 +-
 include/net/xdp_sock_drv.h                    |  16 +-
 include/trace/events/netfs.h                  |   4 +-
 include/uapi/drm/drm_fourcc.h                 |  12 +-
 include/uapi/linux/pci_regs.h                 |   2 +-
 kernel/bpf/cpumap.c                           |  17 +-
 kernel/bpf/devmap.c                           |  47 +++-
 kernel/bpf/tnum.c                             |  72 ++++++
 kernel/bpf/trampoline.c                       |   4 +-
 kernel/bpf/verifier.c                         | 103 +++++++-
 kernel/cgroup/cpuset.c                        |   2 +-
 kernel/events/core.c                          |  83 ++++--
 kernel/events/uprobes.c                       |  10 +-
 kernel/module/main.c                          |   6 -
 kernel/rseq.c                                 |   5 +-
 kernel/sched/ext_internal.h                   |   2 +-
 kernel/sched/fair.c                           | 238 +++++++++++++-----
 kernel/sched/sched.h                          |   4 +-
 kernel/time/timekeeping.c                     |   6 +-
 kernel/trace/ring_buffer.c                    |  21 ++
 kernel/trace/trace.c                          |  13 +
 kernel/trace/trace_events_trigger.c           |   3 +
 kernel/unwind/user.c                          |  59 ++++-
 lib/Kconfig.debug                             |   1 +
 lib/debugobjects.c                            |  19 +-
 mm/huge_memory.c                              |   3 +
 mm/slab.h                                     |   2 -
 mm/slub.c                                     | 133 ++--------
 net/atm/lec.c                                 |  26 +-
 net/bluetooth/hci_sock.c                      |   1 +
 net/bluetooth/hci_sync.c                      |   2 +-
 net/bluetooth/iso.c                           |   1 +
 net/bluetooth/l2cap_sock.c                    |   1 +
 net/bluetooth/sco.c                           |   1 +
 net/bridge/br_device.c                        |   2 +-
 net/bridge/br_input.c                         |   2 +-
 net/can/bcm.c                                 |   1 +
 net/core/dev.c                                |   7 +-
 net/core/devmem.c                             |   6 +-
 net/core/filter.c                             |   6 +-
 net/core/netpoll.c                            |   2 +-
 net/core/secure_seq.c                         |  80 +++---
 net/core/skmsg.c                              |  14 +-
 net/ipv4/inet_hashtables.c                    |   8 +-
 net/ipv4/syncookies.c                         |  11 +-
 net/ipv4/sysctl_net_ipv4.c                    |   5 +-
 net/ipv4/tcp.c                                |   4 +-
 net/ipv4/tcp_bpf.c                            |   2 +-
 net/ipv4/tcp_diag.c                           |   2 +-
 net/ipv4/tcp_input.c                          |  38 ++-
 net/ipv4/tcp_ipv4.c                           |  37 ++-
 net/ipv4/tcp_minisocks.c                      |   2 +-
 net/ipv4/udp.c                                |  27 +-
 net/ipv4/udp_bpf.c                            |   2 +-
 net/ipv6/inet6_hashtables.c                   |   3 +-
 net/ipv6/route.c                              |  11 +-
 net/ipv6/syncookies.c                         |  11 +-
 net/ipv6/tcp_ipv6.c                           |  37 ++-
 net/mac80211/mesh.c                           |   3 +
 net/mac80211/mlme.c                           |   3 +
 net/mptcp/pm.c                                |  55 +++-
 net/mptcp/pm_kernel.c                         |   9 +
 net/netfilter/nf_tables_api.c                 |  66 +++--
 net/netfilter/nft_set_hash.c                  |   1 +
 net/netfilter/nft_set_pipapo.c                |  62 ++++-
 net/netfilter/nft_set_pipapo.h                |   2 +
 net/netfilter/nft_set_rbtree.c                |  79 ++----
 net/nfc/nci/core.c                            |  30 ++-
 net/nfc/nci/data.c                            |  12 +-
 net/nfc/rawsock.c                             |  11 +
 net/qrtr/mhi.c                                |  69 ++++-
 net/rds/tcp.c                                 |  14 +-
 net/sched/act_ife.c                           |  93 ++++---
 net/sched/sch_ets.c                           |  12 +-
 net/sched/sch_fq.c                            |   1 +
 net/unix/af_unix.c                            |   8 +-
 net/wireless/core.c                           |   1 +
 net/wireless/radiotap.c                       |   4 +-
 net/xdp/xsk.c                                 |  26 +-
 rust/kernel/kunit.rs                          |   8 +
 sound/hda/codecs/realtek/alc269.c             |   5 +-
 sound/hda/codecs/side-codecs/cs35l56_hda.c    |   2 +-
 sound/hda/controllers/intel.c                 |   2 +
 sound/soc/fsl/fsl_xcvr.c                      |  89 +++----
 sound/soc/sdca/sdca_interrupts.c              |   4 +-
 sound/usb/endpoint.c                          |   9 +-
 sound/usb/mixer_scarlett2.c                   |  10 +-
 sound/usb/qcom/qc_audio_offload.c             |   2 +-
 sound/usb/quirks.c                            |   3 +-
 sound/usb/stream.c                            |   3 +
 sound/usb/usbaudio.h                          |   6 +
 sound/usb/validate.c                          |   2 +-
 tools/testing/kunit/kunit_kernel.py           |   6 +-
 tools/testing/kunit/kunit_tool_test.py        |  26 ++
 tools/testing/selftests/arm64/abi/hwcap.c     |   4 +-
 .../testing/selftests/bpf/progs/dmabuf_iter.c |   2 +-
 .../selftests/bpf/progs/exceptions_assert.c   |  34 +--
 .../selftests/bpf/progs/verifier_scalar_ids.c |  56 +++--
 .../testing/selftests/bpf/verifier/precise.c  |   8 +-
 tools/testing/selftests/kselftest_harness.h   |  15 +-
 .../testing/selftests/net/mptcp/mptcp_join.sh |  49 ++++
 .../selftests/net/mptcp/simult_flows.sh       |  11 +-
 401 files changed, 4500 insertions(+), 2112 deletions(-)
 create mode 100644 arch/x86/include/asm/unwind_user.h
 create mode 100644 drivers/acpi/apei/ghes_helpers.c
Signature · 1 line
2.51.0
author maintainer
#1 lore raw

PATCH 1/314 perf/core: Fix refcount bug and potential UAF in perf_mmap

From: Haocheng Yu <[email protected]>

commit 77de62ad3de3967818c3dbe656b7336ebee461d2 upstream.

Syzkaller reported a refcount_t: addition on 0; use-after-free warning in perf_mmap.

The issue is caused by a race condition between a failing mmap() setup and a concurrent mmap() on a dependent event (e.g., using output redirection).

In perf_mmap(), the ring_buffer (rb) is allocated and assigned to event->rb with the mmap_mutex held. The mutex is then released to perform map_range().

If map_range() fails, perf_mmap_close() is called to clean up. However, since the mutex was dropped, another thread attaching to this event (via inherited events or output redirection) can acquire the mutex, observe the valid event->rb pointer, and attempt to increment its reference count. If the cleanup path has already dropped the reference count to zero, this results in a use-after-free or refcount saturation warning.

Fix this by extending the scope of mmap_mutex to cover the map_range() call. This ensures that the ring buffer initialization and mapping (or cleanup on failure) happens atomically effectively, preventing other threads from accessing a half-initialized or dying ring buffer.

---
 kernel/events/core.c | 38 +++++++++++++++++++-------------------
 1 file changed, 19 insertions(+), 19 deletions(-)
kernel/events/core.c +19 -19
index c34b927e5ece3..6889a6bd8a395 100644
@@ -7187,28 +7187,28 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma)
 			ret = perf_mmap_aux(vma, event, nr_pages);
 		if (ret)
 			return ret;
-	}
 
-	/*
-	 * Since pinned accounting is per vm we cannot allow fork() to copy our
-	 * vma.
-	 */
-	vm_flags_set(vma, VM_DONTCOPY | VM_DONTEXPAND | VM_DONTDUMP);
-	vma->vm_ops = &perf_mmap_vmops;
+		/*
+		 * Since pinned accounting is per vm we cannot allow fork() to copy our
+		 * vma.
+		 */
+		vm_flags_set(vma, VM_DONTCOPY | VM_DONTEXPAND | VM_DONTDUMP);
+		vma->vm_ops = &perf_mmap_vmops;
 
-	mapped = get_mapped(event, event_mapped);
-	if (mapped)
-		mapped(event, vma->vm_mm);
+		mapped = get_mapped(event, event_mapped);
+		if (mapped)
+			mapped(event, vma->vm_mm);
 
-	/*
-	 * Try to map it into the page table. On fail, invoke
-	 * perf_mmap_close() to undo the above, as the callsite expects
-	 * full cleanup in this case and therefore does not invoke
-	 * vmops::close().
-	 */
-	ret = map_range(event->rb, vma);
-	if (ret)
-		perf_mmap_close(vma);
+		/*
+		 * Try to map it into the page table. On fail, invoke
+		 * perf_mmap_close() to undo the above, as the callsite expects
+		 * full cleanup in this case and therefore does not invoke
+		 * vmops::close().
+		 */
+		ret = map_range(event->rb, vma);
+		if (ret)
+			perf_mmap_close(vma);
+	}
 
 	return ret;
 }
Signature · 1 line
2.51.0
author maintainer
#2 lore raw

PATCH 2/314 drm/vmwgfx: Fix invalid kref_put callback in vmw_bo_dirty_release

In reply to Sasha Levin

From: Brad Spengler <[email protected]>

[ Upstream commit 211ecfaaef186ee5230a77d054cdec7fbfc6724a ]

The kref_put() call uses (void *)kvfree as the release callback, which is incorrect. kref_put() expects a function with signature void (*release)(struct kref *), but kvfree has signature void (*)(const void *). Calling through an incompatible function pointer is undefined behavior.

The code only worked by accident because ref_count is the first member of vmw_bo_dirty, making the kref pointer equal to the struct pointer.

Fix this by adding a proper release callback that uses container_of() to retrieve the containing structure before freeing.

Fixes c1962742ffff ("drm/vmwgfx: Use kref in vmw_bo_dirty")
Cc Ian Forbes <[email protected]>
---
 drivers/gpu/drm/vmwgfx/vmwgfx_page_dirty.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)
drivers/gpu/drm/vmwgfx/vmwgfx_page_dirty.c +8 -1
index fd4e76486f2d1..45561bc1c9eff 100644
@@ -260,6 +260,13 @@ int vmw_bo_dirty_add(struct vmw_bo *vbo)
 	return ret;
 }
 
+static void vmw_bo_dirty_free(struct kref *kref)
+{
+	struct vmw_bo_dirty *dirty = container_of(kref, struct vmw_bo_dirty, ref_count);
+
+	kvfree(dirty);
+}
+
 /**
  * vmw_bo_dirty_release - Release a dirty-tracking user from a buffer object
  * @vbo: The buffer object
@@ -274,7 +281,7 @@ void vmw_bo_dirty_release(struct vmw_bo *vbo)
 {
 	struct vmw_bo_dirty *dirty = vbo->dirty;
 
-	if (dirty && kref_put(&dirty->ref_count, (void *)kvfree))
+	if (dirty && kref_put(&dirty->ref_count, vmw_bo_dirty_free))
 		vbo->dirty = NULL;
 }
 
Signature · 1 line
2.51.0
author maintainer
#3 lore raw

PATCH 3/314 drm/vmwgfx: Return the correct value in vmw_translate_ptr functions

In reply to Sasha Levin

From: Ian Forbes <[email protected]>

[ Upstream commit 5023ca80f9589295cb60735016e39fc5cc714243 ]

Before the referenced fixes these functions used a lookup function that returned a pointer. This was changed to another lookup function that returned an error code with the pointer becoming an out parameter.

The error path when the lookup failed was not changed to reflect this change and the code continued to return the PTR_ERR of the now uninitialized pointer. This could cause the vmw_translate_ptr functions to return success when they actually failed causing further uninitialized and OOB accesses.

Fixes a309c7194e8a ("drm/vmwgfx: Remove rcu locks from user resources")
---
 drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c +2 -2
index 3057f8baa7d25..e1f18020170ab 100644
@@ -1143,7 +1143,7 @@ static int vmw_translate_mob_ptr(struct vmw_private *dev_priv,
 	ret = vmw_user_bo_lookup(sw_context->filp, handle, &vmw_bo);
 	if (ret != 0) {
 		drm_dbg(&dev_priv->drm, "Could not find or use MOB buffer.\n");
-		return PTR_ERR(vmw_bo);
+		return ret;
 	}
 	vmw_bo_placement_set(vmw_bo, VMW_BO_DOMAIN_MOB, VMW_BO_DOMAIN_MOB);
 	ret = vmw_validation_add_bo(sw_context->ctx, vmw_bo);
@@ -1199,7 +1199,7 @@ static int vmw_translate_guest_ptr(struct vmw_private *dev_priv,
 	ret = vmw_user_bo_lookup(sw_context->filp, handle, &vmw_bo);
 	if (ret != 0) {
 		drm_dbg(&dev_priv->drm, "Could not find or use GMR region.\n");
-		return PTR_ERR(vmw_bo);
+		return ret;
 	}
 	vmw_bo_placement_set(vmw_bo, VMW_BO_DOMAIN_GMR | VMW_BO_DOMAIN_VRAM,
 			     VMW_BO_DOMAIN_GMR | VMW_BO_DOMAIN_VRAM);
Signature · 1 line
2.51.0
author maintainer
#4 lore raw

PATCH 4/314 debugobject: Make it work with deferred page initialization - again

In reply to Sasha Levin

From: Thomas Gleixner <[email protected]>

[ Upstream commit fd3634312a04f336dcbfb481060219f0cd320738 ]

debugobjects uses __GFP_HIGH for allocations as it might be invoked within locked regions. That worked perfectly fine until v6.18. It still works correctly when deferred page initialization is disabled and works by chance when no page allocation is required before deferred page initialization has completed.

Since v6.18 allocations w/o a reclaim flag cause new_slab() to end up in alloc_frozen_pages_nolock_noprof(), which returns early when deferred page initialization has not yet completed. As the deferred page initialization takes quite a while the debugobject pool is depleted and debugobjects are disabled.

This can be worked around when PREEMPT_COUNT is enabled as that allows debugobjects to add __GFP_KSWAPD_RECLAIM to the GFP flags when the context is preemtible. When PREEMPT_COUNT is disabled the context is unknown and the reclaim bit can't be set because the caller might hold locks which might deadlock in the allocator.

In preemptible context the reclaim bit is harmless and not a performance issue as that's usually invoked from slow path initialization context.

That makes debugobjects depend on PREEMPT_COUNT || !DEFERRED_STRUCT_PAGE_INIT.

---
 lib/Kconfig.debug  |  1 +
 lib/debugobjects.c | 19 ++++++++++++++++++-
 2 files changed, 19 insertions(+), 1 deletion(-)
lib/Kconfig.debug +1 -0
index 88fa610e83840..21cd68084e468 100644
@@ -721,6 +721,7 @@ source "mm/Kconfig.debug"
 
 config DEBUG_OBJECTS
 	bool "Debug object operations"
+	depends on PREEMPT_COUNT || !DEFERRED_STRUCT_PAGE_INIT
 	depends on DEBUG_KERNEL
 	help
 	  If you say Y here, additional code will be inserted into the
lib/debugobjects.c +18 -1
index 7f50c4480a4e3..b3151679d0d30 100644
@@ -398,9 +398,26 @@ static void fill_pool(void)
 
 	atomic_inc(&cpus_allocating);
 	while (pool_should_refill(&pool_global)) {
+		gfp_t gfp = __GFP_HIGH | __GFP_NOWARN;
 		HLIST_HEAD(head);
 
-		if (!kmem_alloc_batch(&head, obj_cache, __GFP_HIGH | __GFP_NOWARN))
+		/*
+		 * Allow reclaim only in preemptible context and during
+		 * early boot. If not preemptible, the caller might hold
+		 * locks causing a deadlock in the allocator.
+		 *
+		 * If the reclaim flag is not set during early boot then
+		 * allocations, which happen before deferred page
+		 * initialization has completed, will fail.
+		 *
+		 * In preemptible context the flag is harmless and not a
+		 * performance issue as that's usually invoked from slow
+		 * path initialization context.
+		 */
+		if (preemptible() || system_state < SYSTEM_SCHEDULING)
+			gfp |= __GFP_KSWAPD_RECLAIM;
+
+		if (!kmem_alloc_batch(&head, obj_cache, gfp))
 			break;
 
 		guard(raw_spinlock_irqsave)(&pool_lock);
Signature · 1 line
2.51.0
author maintainer
#5 lore raw

PATCH 5/314 drm/logicvc: Fix device node reference leak in logicvc_drm_config_parse()

In reply to Sasha Levin

From: Felix Gu <[email protected]>

[ Upstream commit fef0e649f8b42bdffe4a916dd46e1b1e9ad2f207 ]

The logicvc_drm_config_parse() function calls of_get_child_by_name() to find the "layers" node but fails to release the reference, leading to a device node reference leak.

Fix this by using the __free(device_node) cleanup attribute to automatic release the reference when the variable goes out of scope.

Fixes efeeaefe9be5 ("drm: Add support for the LogiCVC display controller")
---
 drivers/gpu/drm/logicvc/logicvc_drm.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/gpu/drm/logicvc/logicvc_drm.c +2 -2
index 204b0fee55d0b..bbebf4fc7f51a 100644
@@ -92,7 +92,6 @@ static int logicvc_drm_config_parse(struct logicvc_drm *logicvc)
 	struct device *dev = drm_dev->dev;
 	struct device_node *of_node = dev->of_node;
 	struct logicvc_drm_config *config = &logicvc->config;
-	struct device_node *layers_node;
 	int ret;
 
 	logicvc_of_property_parse_bool(of_node, LOGICVC_OF_PROPERTY_DITHERING,
@@ -128,7 +127,8 @@ static int logicvc_drm_config_parse(struct logicvc_drm *logicvc)
 	if (ret)
 		return ret;
 
-	layers_node = of_get_child_by_name(of_node, "layers");
+	struct device_node *layers_node __free(device_node) =
+		of_get_child_by_name(of_node, "layers");
 	if (!layers_node) {
 		drm_err(drm_dev, "Missing non-optional layers node\n");
 		return -EINVAL;
Signature · 1 line
2.51.0
author maintainer
#6 lore raw

PATCH 6/314 KVM: arm64: Hide S1POE from guests when not supported by the host

In reply to Sasha Levin

From: Fuad Tabba <[email protected]>

[ Upstream commit f66857bafd4f151c5cc6856e47be2e12c1721e43 ]

When CONFIG_ARM64_POE is disabled, KVM does not save/restore POR_EL1. However, ID_AA64MMFR3_EL1 sanitisation currently exposes the feature to guests whenever the hardware supports it, ignoring the host kernel configuration.

If a guest detects this feature and attempts to use it, the host will fail to context-switch POR_EL1, potentially leading to state corruption.

Fix this by masking ID_AA64MMFR3_EL1.S1POE in the sanitised system registers, preventing KVM from advertising the feature when the host does not support it (i.e. system_supports_poe() is false).

Fixes 70ed7238297f ("KVM: arm64: Sanitise ID_AA64MMFR3_EL1")
---
 arch/arm64/kvm/sys_regs.c | 3 +++
 1 file changed, 3 insertions(+)
arch/arm64/kvm/sys_regs.c +3 -0
index ec3fbe0b8d525..7b7f3c932dcd5 100644
@@ -1801,6 +1801,9 @@ static u64 __kvm_read_sanitised_id_reg(const struct kvm_vcpu *vcpu,
 		       ID_AA64MMFR3_EL1_SCTLRX |
 		       ID_AA64MMFR3_EL1_S1POE |
 		       ID_AA64MMFR3_EL1_S1PIE;
+
+		if (!system_supports_poe())
+			val &= ~ID_AA64MMFR3_EL1_S1POE;
 		break;
 	case SYS_ID_MMFR4_EL1:
 		val &= ~ID_MMFR4_EL1_CCIDX;
Signature · 1 line
2.51.0
author maintainer
#7 lore raw

PATCH 7/314 KVM: arm64: Fix ID register initialization for non-protected pKVM guests

In reply to Sasha Levin

From: Fuad Tabba <[email protected]>

[ Upstream commit 7e7c2cf0024d89443a7af52e09e47b1fe634ab17 ]

In protected mode, the hypervisor maintains a separate instance of the kvm structure for each VM. For non-protected VMs, this structure is initialized from the host's kvm state.

Currently, pkvm_init_features_from_host() copies the KVM_ARCH_FLAG_ID_REGS_INITIALIZED flag from the host without the underlying id_regs data being initialized. This results in the hypervisor seeing the flag as set while the ID registers remain zeroed.

Consequently, kvm_has_feat() checks at EL2 fail (return 0) for non-protected VMs. This breaks logic that relies on feature detection, such as ctxt_has_tcrx() for TCR2_EL1 support. As a result, certain system registers (e.g., TCR2_EL1, PIR_EL1, POR_EL1) are not saved/restored during the world switch, which could lead to state corruption.

Fix this by explicitly copying the ID registers from the host kvm to the hypervisor kvm for non-protected VMs during initialization, since we trust the host with its non-protected guests' features. Also ensure KVM_ARCH_FLAG_ID_REGS_INITIALIZED is cleared initially in pkvm_init_features_from_host so that vm_copy_id_regs can properly initialize them and set the flag once done.

Fixes 41d6028e28bd ("KVM: arm64: Convert the SVE guest vcpu flag to a vm flag")
---
 arch/arm64/kvm/hyp/nvhe/pkvm.c | 35 ++++++++++++++++++++++++++++++++--
 1 file changed, 33 insertions(+), 2 deletions(-)
arch/arm64/kvm/hyp/nvhe/pkvm.c +33 -2
index 43bde061b65de..d866f6ba19b5f 100644
@@ -343,6 +343,7 @@ static void pkvm_init_features_from_host(struct pkvm_hyp_vm *hyp_vm, const struc
 	/* No restrictions for non-protected VMs. */
 	if (!kvm_vm_is_protected(kvm)) {
 		hyp_vm->kvm.arch.flags = host_arch_flags;
+		hyp_vm->kvm.arch.flags &= ~BIT_ULL(KVM_ARCH_FLAG_ID_REGS_INITIALIZED);
 
 		bitmap_copy(kvm->arch.vcpu_features,
 			    host_kvm->arch.vcpu_features,
@@ -469,6 +470,35 @@ static int pkvm_vcpu_init_sve(struct pkvm_hyp_vcpu *hyp_vcpu, struct kvm_vcpu *h
 	return ret;
 }
 
+static int vm_copy_id_regs(struct pkvm_hyp_vcpu *hyp_vcpu)
+{
+	struct pkvm_hyp_vm *hyp_vm = pkvm_hyp_vcpu_to_hyp_vm(hyp_vcpu);
+	const struct kvm *host_kvm = hyp_vm->host_kvm;
+	struct kvm *kvm = &hyp_vm->kvm;
+
+	if (!test_bit(KVM_ARCH_FLAG_ID_REGS_INITIALIZED, &host_kvm->arch.flags))
+		return -EINVAL;
+
+	if (test_and_set_bit(KVM_ARCH_FLAG_ID_REGS_INITIALIZED, &kvm->arch.flags))
+		return 0;
+
+	memcpy(kvm->arch.id_regs, host_kvm->arch.id_regs, sizeof(kvm->arch.id_regs));
+
+	return 0;
+}
+
+static int pkvm_vcpu_init_sysregs(struct pkvm_hyp_vcpu *hyp_vcpu)
+{
+	int ret = 0;
+
+	if (pkvm_hyp_vcpu_is_protected(hyp_vcpu))
+		kvm_init_pvm_id_regs(&hyp_vcpu->vcpu);
+	else
+		ret = vm_copy_id_regs(hyp_vcpu);
+
+	return ret;
+}
+
 static int init_pkvm_hyp_vcpu(struct pkvm_hyp_vcpu *hyp_vcpu,
 			      struct pkvm_hyp_vm *hyp_vm,
 			      struct kvm_vcpu *host_vcpu)
@@ -488,8 +518,9 @@ static int init_pkvm_hyp_vcpu(struct pkvm_hyp_vcpu *hyp_vcpu,
 	hyp_vcpu->vcpu.arch.cflags = READ_ONCE(host_vcpu->arch.cflags);
 	hyp_vcpu->vcpu.arch.mp_state.mp_state = KVM_MP_STATE_STOPPED;
 
-	if (pkvm_hyp_vcpu_is_protected(hyp_vcpu))
-		kvm_init_pvm_id_regs(&hyp_vcpu->vcpu);
+	ret = pkvm_vcpu_init_sysregs(hyp_vcpu);
+	if (ret)
+		goto done;
 
 	ret = pkvm_vcpu_init_traps(hyp_vcpu);
 	if (ret)
Signature · 1 line
2.51.0
author maintainer
#8 lore raw

PATCH 8/314 drm/fourcc: fix plane order for 10/12/16-bit YCbCr formats

In reply to Sasha Levin

From: Simon Ser <[email protected]>

[ Upstream commit e9e0b48cd15b46dcb2bbc165f6b0fee698b855d6 ]

The short comments had the correct order, but the long comments had the planes reversed.

Fixes 2271e0a20ef7 ("drm: drm_fourcc: add 10/12/16bit software decoder YCbCr formats")
---
 include/uapi/drm/drm_fourcc.h | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)
include/uapi/drm/drm_fourcc.h +6 -6
index e527b24bd824b..c89aede3cb120 100644
@@ -401,8 +401,8 @@ extern "C" {
  * implementation can multiply the values by 2^6=64. For that reason the padding
  * must only contain zeros.
  * index 0 = Y plane, [15:0] z:Y [6:10] little endian
- * index 1 = Cr plane, [15:0] z:Cr [6:10] little endian
- * index 2 = Cb plane, [15:0] z:Cb [6:10] little endian
+ * index 1 = Cb plane, [15:0] z:Cb [6:10] little endian
+ * index 2 = Cr plane, [15:0] z:Cr [6:10] little endian
  */
 #define DRM_FORMAT_S010	fourcc_code('S', '0', '1', '0') /* 2x2 subsampled Cb (1) and Cr (2) planes 10 bits per channel */
 #define DRM_FORMAT_S210	fourcc_code('S', '2', '1', '0') /* 2x1 subsampled Cb (1) and Cr (2) planes 10 bits per channel */
@@ -414,8 +414,8 @@ extern "C" {
  * implementation can multiply the values by 2^4=16. For that reason the padding
  * must only contain zeros.
  * index 0 = Y plane, [15:0] z:Y [4:12] little endian
- * index 1 = Cr plane, [15:0] z:Cr [4:12] little endian
- * index 2 = Cb plane, [15:0] z:Cb [4:12] little endian
+ * index 1 = Cb plane, [15:0] z:Cb [4:12] little endian
+ * index 2 = Cr plane, [15:0] z:Cr [4:12] little endian
  */
 #define DRM_FORMAT_S012	fourcc_code('S', '0', '1', '2') /* 2x2 subsampled Cb (1) and Cr (2) planes 12 bits per channel */
 #define DRM_FORMAT_S212	fourcc_code('S', '2', '1', '2') /* 2x1 subsampled Cb (1) and Cr (2) planes 12 bits per channel */
@@ -424,8 +424,8 @@ extern "C" {
 /*
  * 3 plane YCbCr
  * index 0 = Y plane, [15:0] Y little endian
- * index 1 = Cr plane, [15:0] Cr little endian
- * index 2 = Cb plane, [15:0] Cb little endian
+ * index 1 = Cb plane, [15:0] Cb little endian
+ * index 2 = Cr plane, [15:0] Cr little endian
  */
 #define DRM_FORMAT_S016	fourcc_code('S', '0', '1', '6') /* 2x2 subsampled Cb (1) and Cr (2) planes 16 bits per channel */
 #define DRM_FORMAT_S216	fourcc_code('S', '2', '1', '6') /* 2x1 subsampled Cb (1) and Cr (2) planes 16 bits per channel */
Signature · 1 line
2.51.0
author maintainer
#9 lore raw

PATCH 9/314 drm/tiny: sharp-memory: fix pointer error dereference

In reply to Sasha Levin

From: Ethan Tidmore <[email protected]>

[ Upstream commit 46120745bb4e7e1f09959624716b4c5d6e2c2e9e ]

The function devm_drm_dev_alloc() returns a pointer error upon failure not NULL. Change null check to pointer error check.

Detected by Smatch:
drivers/gpu/drm/tiny/sharp-memory.c:549 sharp_memory_probe() error:
'smd' dereferencing possible ERR_PTR()

---
 drivers/gpu/drm/tiny/sharp-memory.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/gpu/drm/tiny/sharp-memory.c +2 -2
index 64272cd0f6e22..cbf69460ebf32 100644
@@ -541,8 +541,8 @@ static int sharp_memory_probe(struct spi_device *spi)
 
 	smd = devm_drm_dev_alloc(dev, &sharp_memory_drm_driver,
 				 struct sharp_memory_device, drm);
-	if (!smd)
-		return -ENOMEM;
+	if (IS_ERR(smd))
+		return PTR_ERR(smd);
 
 	spi_set_drvdata(spi, smd);
 
Signature · 1 line
2.51.0
author maintainer
#10 lore raw

PATCH 10/314 irqchip/sifive-plic: Fix frozen interrupt due to affinity setting

In reply to Sasha Levin

From: Nam Cao <[email protected]>

[ Upstream commit 1072020685f4b81f6efad3b412cdae0bd62bb043 ]

PLIC ignores interrupt completion message for disabled interrupt, explained by the specification:

The PLIC signals it has completed executing an interrupt handler by writing the interrupt ID it received from the claim to the claim/complete register. The PLIC does not check whether the completion ID is the same as the last claim ID for that target. If the completion ID does not match an interrupt source that is currently enabled for the target, the completion is silently ignored.

This caused problems in the past, because an interrupt can be disabled while still being handled and plic_irq_eoi() had no effect. That was fixed by checking if the interrupt is disabled, and if so enable it, before sending the completion message. That check is done with irqd_irq_disabled().

However, that is not sufficient because the enable bit for the handling hart can be zero despite irqd_irq_disabled(d) being false. This can happen when affinity setting is changed while a hart is still handling the interrupt.

This problem is easily reproducible by dumping a large file to uart (which generates lots of interrupts) and at the same time keep changing the uart interrupt's affinity setting. The uart port becomes frozen almost instantaneously.

Fix this by checking PLIC's enable bit instead of irqd_irq_disabled().

Fixes cc9f04f9a84f ("irqchip/sifive-plic: Implement irq_set_affinity() for SMP host")
---
 drivers/irqchip/irq-sifive-plic.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)
drivers/irqchip/irq-sifive-plic.c +6 -1
index cbd7697bc1481..0799c15c745d4 100644
@@ -154,8 +154,13 @@ static void plic_irq_disable(struct irq_data *d)
 static void plic_irq_eoi(struct irq_data *d)
 {
 	struct plic_handler *handler = this_cpu_ptr(&plic_handlers);
+	u32 __iomem *reg;
+	bool enabled;
+
+	reg = handler->enable_base + (d->hwirq / 32) * sizeof(u32);
+	enabled = readl(reg) & BIT(d->hwirq % 32);
 
-	if (unlikely(irqd_irq_disabled(d))) {
+	if (unlikely(!enabled)) {
 		plic_toggle(handler, d->hwirq, 1);
 		writel(d->hwirq, handler->hart_base + CONTEXT_CLAIM);
 		plic_toggle(handler, d->hwirq, 0);
Signature · 1 line
2.51.0
author maintainer
#11 lore raw

PATCH 11/314 scsi: lpfc: Properly set WC for DPP mapping

In reply to Sasha Levin

From: Mathias Krause <[email protected]>

[ Upstream commit bffda93a51b40afd67c11bf558dc5aae83ca0943 ]

Using set_memory_wc() to enable write-combining for the DPP portion of the MMIO mapping is wrong as set_memory_*() is meant to operate on RAM only, not MMIO mappings. In fact, as used currently triggers a BUG_ON() with enabled CONFIG_DEBUG_VIRTUAL.

Simply map the DPP region separately and in addition to the already existing mappings, avoiding any possible negative side effects for these.

---
 drivers/scsi/lpfc/lpfc_init.c |  2 ++
 drivers/scsi/lpfc/lpfc_sli.c  | 36 +++++++++++++++++++++++++++++------
 drivers/scsi/lpfc/lpfc_sli4.h |  3 +++
 3 files changed, 35 insertions(+), 6 deletions(-)
drivers/scsi/lpfc/lpfc_init.c +2 -0
index 065eb91de9c0f..adc0beaf5468f 100644
@@ -12040,6 +12040,8 @@ lpfc_sli4_pci_mem_unset(struct lpfc_hba *phba)
 		iounmap(phba->sli4_hba.conf_regs_memmap_p);
 		if (phba->sli4_hba.dpp_regs_memmap_p)
 			iounmap(phba->sli4_hba.dpp_regs_memmap_p);
+		if (phba->sli4_hba.dpp_regs_memmap_wc_p)
+			iounmap(phba->sli4_hba.dpp_regs_memmap_wc_p);
 		break;
 	case LPFC_SLI_INTF_IF_TYPE_1:
 		break;
drivers/scsi/lpfc/lpfc_sli.c +30 -6
index 7ea7c4245c691..7b765719f4f6b 100644
@@ -15911,6 +15911,32 @@ lpfc_dual_chute_pci_bar_map(struct lpfc_hba *phba, uint16_t pci_barset)
 	return NULL;
 }
 
+static __maybe_unused void __iomem *
+lpfc_dpp_wc_map(struct lpfc_hba *phba, uint8_t dpp_barset)
+{
+
+	/* DPP region is supposed to cover 64-bit BAR2 */
+	if (dpp_barset != WQ_PCI_BAR_4_AND_5) {
+		lpfc_log_msg(phba, KERN_WARNING, LOG_INIT,
+			     "3273 dpp_barset x%x != WQ_PCI_BAR_4_AND_5\n",
+			     dpp_barset);
+		return NULL;
+	}
+
+	if (!phba->sli4_hba.dpp_regs_memmap_wc_p) {
+		void __iomem *dpp_map;
+
+		dpp_map = ioremap_wc(phba->pci_bar2_map,
+				     pci_resource_len(phba->pcidev,
+						      PCI_64BIT_BAR4));
+
+		if (dpp_map)
+			phba->sli4_hba.dpp_regs_memmap_wc_p = dpp_map;
+	}
+
+	return phba->sli4_hba.dpp_regs_memmap_wc_p;
+}
+
 /**
  * lpfc_modify_hba_eq_delay - Modify Delay Multiplier on EQs
  * @phba: HBA structure that EQs are on.
@@ -16874,9 +16900,6 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq,
 	uint8_t dpp_barset;
 	uint32_t dpp_offset;
 	uint8_t wq_create_version;
-#ifdef CONFIG_X86
-	unsigned long pg_addr;
-#endif
 
 	/* sanity check on queue memory */
 	if (!wq || !cq)
@@ -17062,14 +17085,15 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq,
 
 #ifdef CONFIG_X86
 			/* Enable combined writes for DPP aperture */
-			pg_addr = (unsigned long)(wq->dpp_regaddr) & PAGE_MASK;
-			rc = set_memory_wc(pg_addr, 1);
-			if (rc) {
+			bar_memmap_p = lpfc_dpp_wc_map(phba, dpp_barset);
+			if (!bar_memmap_p) {
 				lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
 					"3272 Cannot setup Combined "
 					"Write on WQ[%d] - disable DPP\n",
 					wq->queue_id);
 				phba->cfg_enable_dpp = 0;
+			} else {
+				wq->dpp_regaddr = bar_memmap_p + dpp_offset;
 			}
 #else
 			phba->cfg_enable_dpp = 0;
drivers/scsi/lpfc/lpfc_sli4.h +3 -0
index fd6dab1578872..40f313e2769fc 100644
@@ -785,6 +785,9 @@ struct lpfc_sli4_hba {
 	void __iomem *dpp_regs_memmap_p;  /* Kernel memory mapped address for
 					   * dpp registers
 					   */
+	void __iomem *dpp_regs_memmap_wc_p;/* Kernel memory mapped address for
+					    * dpp registers with write combining
+					    */
 	union {
 		struct {
 			/* IF Type 0, BAR 0 PCI cfg space reg mem map */
Signature · 1 line
2.51.0
author maintainer
#12 lore raw

PATCH 12/314 scsi: pm8001: Fix use-after-free in pm8001_queue_command()

In reply to Sasha Levin

From: Salomon Dushimirimana <[email protected]>

[ Upstream commit 38353c26db28efd984f51d426eac2396d299cca7 ]

Commit e29c47fe8946 ("scsi: pm8001: Simplify pm8001_task_exec()") refactors pm8001_queue_command(), however it introduces a potential cause of a double free scenario when it changes the function to return -ENODEV in case of phy down/device gone state.

In this path, pm8001_queue_command() updates task status and calls task_done to indicate to upper layer that the task has been handled. However, this also frees the underlying SAS task. A -ENODEV is then returned to the caller. When libsas sas_ata_qc_issue() receives this error value, it assumes the task wasn't handled/queued by LLDD and proceeds to clean up and free the task again, resulting in a double free.

Since pm8001_queue_command() handles the SAS task in this case, it should return 0 to the caller indicating that the task has been handled.

---
 drivers/scsi/pm8001/pm8001_sas.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/scsi/pm8001/pm8001_sas.c +3 -2
index 6a8d35aea93a5..645524f3fe2d0 100644
@@ -525,8 +525,9 @@ int pm8001_queue_command(struct sas_task *task, gfp_t gfp_flags)
 		} else {
 			task->task_done(task);
 		}
-		rc = -ENODEV;
-		goto err_out;
+		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+		pm8001_dbg(pm8001_ha, IO, "pm8001_task_exec device gone\n");
+		return 0;
 	}
 
 	ccb = pm8001_ccb_alloc(pm8001_ha, pm8001_dev, task);
Signature · 1 line
2.51.0
author maintainer
#13 lore raw

PATCH 13/314 drm/imx: parallel-display: check return value of devm_drm_bridge_add() in imx_pd_probe()

In reply to Sasha Levin

From: Chen Ni <[email protected]>

[ Upstream commit c5f8658f97ec392eeaf355d4e9775ae1f23ca1d3 ]

Return the value of devm_drm_bridge_add() in order to propagate the error properly, if it fails due to resource allocation failure or bridge registration failure.

This ensures that the probe function fails safely rather than proceeding with a potentially incomplete bridge setup.

Fixes bf7e97910b9f ("drm/imx: parallel-display: add the bridge before attaching it")
---
 drivers/gpu/drm/imx/ipuv3/parallel-display.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/gpu/drm/imx/ipuv3/parallel-display.c +3 -1
index 7fc6af7033078..d5f2ee41c03fe 100644
@@ -256,7 +256,9 @@ static int imx_pd_probe(struct platform_device *pdev)
 
 	platform_set_drvdata(pdev, imxpd);
 
-	devm_drm_bridge_add(dev, &imxpd->bridge);
+	ret = devm_drm_bridge_add(dev, &imxpd->bridge);
+	if (ret)
+		return ret;
 
 	return component_add(dev, &imx_pd_ops);
 }
Signature · 1 line
2.51.0
author maintainer
#14 lore raw

PATCH 14/314 ALSA: scarlett2: Fix DSP filter control array handling

In reply to Sasha Levin

From: "Geoffrey D. Bennett" <[email protected]>

[ Upstream commit 1d241483368f2fd87fbaba64d6aec6bad3a1e12e ]

scarlett2_add_dsp_ctls() was incorrectly storing the precomp and PEQ filter coefficient control pointers into the precomp_flt_switch_ctls and peq_flt_switch_ctls arrays instead of the intended targets precomp_flt_ctls and peq_flt_ctls. Pass NULL instead, as the filter coefficient control pointers are not used, and remove the unused precomp_flt_ctls and peq_flt_ctls arrays from struct scarlett2_data.

Additionally, scarlett2_update_filter_values() was reading dsp_input_count * peq_flt_count values for SCARLETT2_CONFIG_PEQ_FLT_SWITCH, but the peq_flt_switch array is indexed only by dsp_input_count (one switch per DSP input, not per filter). Fix the read count.

---
 sound/usb/mixer_scarlett2.c | 10 +++-------
 1 file changed, 3 insertions(+), 7 deletions(-)
sound/usb/mixer_scarlett2.c +3 -7
index bef8c9e544dd3..380beb7ed4cf8 100644
@@ -1328,8 +1328,6 @@ struct scarlett2_data {
 	struct snd_kcontrol *mux_ctls[SCARLETT2_MUX_MAX];
 	struct snd_kcontrol *mix_ctls[SCARLETT2_MIX_MAX];
 	struct snd_kcontrol *compressor_ctls[SCARLETT2_COMPRESSOR_CTLS_MAX];
-	struct snd_kcontrol *precomp_flt_ctls[SCARLETT2_PRECOMP_FLT_CTLS_MAX];
-	struct snd_kcontrol *peq_flt_ctls[SCARLETT2_PEQ_FLT_CTLS_MAX];
 	struct snd_kcontrol *precomp_flt_switch_ctls[SCARLETT2_DSP_SWITCH_MAX];
 	struct snd_kcontrol *peq_flt_switch_ctls[SCARLETT2_DSP_SWITCH_MAX];
 	struct snd_kcontrol *direct_monitor_ctl;
@@ -3447,7 +3445,6 @@ static int scarlett2_update_autogain(struct usb_mixer_interface *mixer)
 			private->autogain_status[i] =
 				private->num_autogain_status_texts - 1;
 
-
 	for (i = 0; i < SCARLETT2_AG_TARGET_COUNT; i++)
 		if (scarlett2_has_config_item(private,
 					      scarlett2_ag_target_configs[i])) {
@@ -5372,8 +5369,7 @@ static int scarlett2_update_filter_values(struct usb_mixer_interface *mixer)
 
 	err = scarlett2_usb_get_config(
 		mixer, SCARLETT2_CONFIG_PEQ_FLT_SWITCH,
-		info->dsp_input_count * info->peq_flt_count,
-		private->peq_flt_switch);
+		info->dsp_input_count, private->peq_flt_switch);
 	if (err < 0)
 		return err;
 
@@ -6546,7 +6542,7 @@ static int scarlett2_add_dsp_ctls(struct usb_mixer_interface *mixer, int i)
 		err = scarlett2_add_new_ctl(
 			mixer, &scarlett2_precomp_flt_ctl,
 			i * info->precomp_flt_count + j,
-			1, s, &private->precomp_flt_switch_ctls[j]);
+			1, s, NULL);
 		if (err < 0)
 			return err;
 	}
@@ -6556,7 +6552,7 @@ static int scarlett2_add_dsp_ctls(struct usb_mixer_interface *mixer, int i)
 		err = scarlett2_add_new_ctl(
 			mixer, &scarlett2_peq_flt_ctl,
 			i * info->peq_flt_count + j,
-			1, s, &private->peq_flt_switch_ctls[j]);
+			1, s, NULL);
 		if (err < 0)
 			return err;
 	}
Signature · 1 line
2.51.0
author maintainer
#15 lore raw

PATCH 15/314 ALSA: usb-audio: Remove VALIDATE_RATES quirk for Focusrite devices

In reply to Sasha Levin

From: "Geoffrey D. Bennett" <[email protected]>

[ Upstream commit a8cc55bf81a45772cad44c83ea7bb0e98431094a ]

Remove QUIRK_FLAG_VALIDATE_RATES for Focusrite. With the previous commit, focusrite_valid_sample_rate() produces correct rate tables without USB probing.

QUIRK_FLAG_VALIDATE_RATES sends SET_CUR requests for each rate (~25ms each) and leaves the device at 192kHz. This is a problem because that
rate: 1) disables the internal mixer, so outputs are silent until an application opens the PCM and sets a lower rate, and 2) the Air and Safe modes get disabled.

Fixes 5963e5262180 ("ALSA: usb-audio: Enable rate validation for Scarlett devices")
---
 sound/usb/quirks.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
sound/usb/quirks.c +1 -1
index 6860b5bd55f1e..ea5de072c36a1 100644
@@ -2421,7 +2421,7 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
 	VENDOR_FLG(0x07fd, /* MOTU */
 		   QUIRK_FLAG_VALIDATE_RATES),
 	VENDOR_FLG(0x1235, /* Focusrite Novation */
-		   QUIRK_FLAG_VALIDATE_RATES),
+		   0),
 	VENDOR_FLG(0x1511, /* AURALiC */
 		   QUIRK_FLAG_DSD_RAW),
 	VENDOR_FLG(0x152a, /* Thesycon devices */
Signature · 1 line
2.51.0
author maintainer
#16 lore raw

PATCH 16/314 ALSA: usb-audio: Add QUIRK_FLAG_SKIP_IFACE_SETUP

In reply to Sasha Levin

From: "Geoffrey D. Bennett" <[email protected]>

[ Upstream commit 38c322068a26a01d7ff64da92179e68cdde9860b ]

Add a quirk flag to skip the usb_set_interface(), snd_usb_init_pitch(), and snd_usb_init_sample_rate() calls in __snd_usb_parse_audio_interface(). These are redundant with snd_usb_endpoint_prepare() at stream-open time.

Enable the quirk for Focusrite devices, as init_sample_rate(rate_max) sets 192kHz during probing, which disables the internal mixer and Air and Safe modes.

Fixes 16f1f838442d ("Revert "ALSA: usb-audio: Drop superfluous interface setup at parsing"")
---
 sound/usb/quirks.c   | 3 ++-
 sound/usb/stream.c   | 3 +++
 sound/usb/usbaudio.h | 6 ++++++
 3 files changed, 11 insertions(+), 1 deletion(-)
sound/usb/quirks.c +2 -1
index ea5de072c36a1..c411005cd4d87 100644
@@ -2421,7 +2421,7 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
 	VENDOR_FLG(0x07fd, /* MOTU */
 		   QUIRK_FLAG_VALIDATE_RATES),
 	VENDOR_FLG(0x1235, /* Focusrite Novation */
-		   0),
+		   QUIRK_FLAG_SKIP_IFACE_SETUP),
 	VENDOR_FLG(0x1511, /* AURALiC */
 		   QUIRK_FLAG_DSD_RAW),
 	VENDOR_FLG(0x152a, /* Thesycon devices */
@@ -2503,6 +2503,7 @@ static const char *const snd_usb_audio_quirk_flag_names[] = {
 	QUIRK_STRING_ENTRY(MIC_RES_384),
 	QUIRK_STRING_ENTRY(MIXER_PLAYBACK_MIN_MUTE),
 	QUIRK_STRING_ENTRY(MIXER_CAPTURE_MIN_MUTE),
+	QUIRK_STRING_ENTRY(SKIP_IFACE_SETUP),
 	NULL
 };
 
sound/usb/stream.c +3 -0
index 5c235a5ba7e1b..3b2526964e4b4 100644
@@ -1261,6 +1261,9 @@ static int __snd_usb_parse_audio_interface(struct snd_usb_audio *chip,
 			set_iface_first = true;
 
 		/* try to set the interface... */
+		if (chip->quirk_flags & QUIRK_FLAG_SKIP_IFACE_SETUP)
+			continue;
+
 		usb_set_interface(chip->dev, iface_no, 0);
 		if (set_iface_first)
 			usb_set_interface(chip->dev, iface_no, altno);
sound/usb/usbaudio.h +6 -0
index 79978cae9799c..085530cf62d92 100644
@@ -224,6 +224,10 @@ extern bool snd_usb_skip_validation;
  *  playback value represents muted state instead of minimum audible volume
  * QUIRK_FLAG_MIXER_CAPTURE_MIN_MUTE
  *  Similar to QUIRK_FLAG_MIXER_PLAYBACK_MIN_MUTE, but for capture streams
+ * QUIRK_FLAG_SKIP_IFACE_SETUP
+ *  Skip the probe-time interface setup (usb_set_interface,
+ *  init_pitch, init_sample_rate); redundant with
+ *  snd_usb_endpoint_prepare() at stream-open time
  */
 
 enum {
@@ -253,6 +257,7 @@ enum {
 	QUIRK_TYPE_MIC_RES_384			= 23,
 	QUIRK_TYPE_MIXER_PLAYBACK_MIN_MUTE	= 24,
 	QUIRK_TYPE_MIXER_CAPTURE_MIN_MUTE	= 25,
+	QUIRK_TYPE_SKIP_IFACE_SETUP		= 26,
 /* Please also edit snd_usb_audio_quirk_flag_names */
 };
 
@@ -284,5 +289,6 @@ enum {
 #define QUIRK_FLAG_MIC_RES_384			QUIRK_FLAG(MIC_RES_384)
 #define QUIRK_FLAG_MIXER_PLAYBACK_MIN_MUTE	QUIRK_FLAG(MIXER_PLAYBACK_MIN_MUTE)
 #define QUIRK_FLAG_MIXER_CAPTURE_MIN_MUTE	QUIRK_FLAG(MIXER_CAPTURE_MIN_MUTE)
+#define QUIRK_FLAG_SKIP_IFACE_SETUP		QUIRK_FLAG(SKIP_IFACE_SETUP)
 
 #endif /* __USBAUDIO_H */
Signature · 1 line
2.51.0
author maintainer
#17 lore raw

PATCH 17/314 x86/fred: Correct speculative safety in fred_extint()

In reply to Sasha Levin

From: Andrew Cooper <[email protected]>

[ Upstream commit aa280a08e7d8fae58557acc345b36b3dc329d595 ]

array_index_nospec() is no use if the result gets spilled to the stack, as it makes the believed safe-under-speculation value subject to memory predictions.

For all practical purposes, this means array_index_nospec() must be used in the expression that accesses the array.

As the code currently stands, it's the wrong side of irqentry_enter(), and 'index' is put into %ebp across the function call.

Remove the index variable and reposition array_index_nospec(), so it's calculated immediately before the array access.

Fixes 14619d912b65 ("x86/fred: FRED entry/exit and dispatch code")
---
 arch/x86/entry/entry_fred.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)
arch/x86/entry/entry_fred.c +2 -3
index f004a4dc74c2d..563e439b743f2 100644
@@ -159,8 +159,6 @@ void __init fred_complete_exception_setup(void)
 static noinstr void fred_extint(struct pt_regs *regs)
 {
 	unsigned int vector = regs->fred_ss.vector;
-	unsigned int index = array_index_nospec(vector - FIRST_SYSTEM_VECTOR,
-						NR_SYSTEM_VECTORS);
 
 	if (WARN_ON_ONCE(vector < FIRST_EXTERNAL_VECTOR))
 		return;
@@ -169,7 +167,8 @@ static noinstr void fred_extint(struct pt_regs *regs)
 		irqentry_state_t state = irqentry_enter(regs);
 
 		instrumentation_begin();
-		sysvec_table[index](regs);
+		sysvec_table[array_index_nospec(vector - FIRST_SYSTEM_VECTOR,
+						NR_SYSTEM_VECTORS)](regs);
 		instrumentation_end();
 		irqentry_exit(regs, state);
 	} else {
Signature · 1 line
2.51.0
author maintainer
#18 lore raw

PATCH 18/314 x86/cfi: Fix CFI rewrite for odd alignments

In reply to Sasha Levin

From: Peter Zijlstra <[email protected]>

[ Upstream commit 24c8147abb39618d74fcc36e325765e8fe7bdd7a ]

Rustam reported his clang builds did not boot properly; turns out his .config has: CONFIG_DEBUG_FORCE_FUNCTION_ALIGN_64B=y set.

Fix up the FineIBT code to deal with this unusual alignment.

Fixes 931ab63664f0 ("x86/ibt: Implement FineIBT")
---
 arch/x86/include/asm/cfi.h     | 12 ++++++++----
 arch/x86/include/asm/linkage.h |  4 ++--
 arch/x86/kernel/alternative.c  | 29 ++++++++++++++++++++++-------
 arch/x86/net/bpf_jit_comp.c    | 13 ++-----------
 4 files changed, 34 insertions(+), 24 deletions(-)
arch/x86/include/asm/cfi.h +8 -4
index c40b9ebc1fb40..ab3fbbd947ed9 100644
@@ -111,6 +111,12 @@ extern bhi_thunk __bhi_args_end[];
 
 struct pt_regs;
 
+#ifdef CONFIG_CALL_PADDING
+#define CFI_OFFSET (CONFIG_FUNCTION_PADDING_CFI+5)
+#else
+#define CFI_OFFSET 5
+#endif
+
 #ifdef CONFIG_CFI
 enum bug_trap_type handle_cfi_failure(struct pt_regs *regs);
 #define __bpfcall
@@ -119,11 +125,9 @@ static inline int cfi_get_offset(void)
 {
 	switch (cfi_mode) {
 	case CFI_FINEIBT:
-		return 16;
+		return /* fineibt_prefix_size */ 16;
 	case CFI_KCFI:
-		if (IS_ENABLED(CONFIG_CALL_PADDING))
-			return 16;
-		return 5;
+		return CFI_OFFSET;
 	default:
 		return 0;
 	}
arch/x86/include/asm/linkage.h +2 -2
index 9d38ae744a2e4..a7294656ad908 100644
@@ -68,7 +68,7 @@
  * Depending on -fpatchable-function-entry=N,N usage (CONFIG_CALL_PADDING) the
  * CFI symbol layout changes.
  *
- * Without CALL_THUNKS:
+ * Without CALL_PADDING:
  *
  * 	.align	FUNCTION_ALIGNMENT
  * __cfi_##name:
@@ -77,7 +77,7 @@
  * 	.long	__kcfi_typeid_##name
  * name:
  *
- * With CALL_THUNKS:
+ * With CALL_PADDING:
  *
  * 	.align FUNCTION_ALIGNMENT
  * __cfi_##name:
arch/x86/kernel/alternative.c +22 -7
index 8ee5ff547357a..bd16e9f40d51a 100644
@@ -1168,7 +1168,7 @@ void __init_or_module noinline apply_seal_endbr(s32 *start, s32 *end)
 
 		poison_endbr(addr);
 		if (IS_ENABLED(CONFIG_FINEIBT))
-			poison_cfi(addr - 16);
+			poison_cfi(addr - CFI_OFFSET);
 	}
 }
 
@@ -1375,6 +1375,8 @@ extern u8 fineibt_preamble_end[];
 #define fineibt_preamble_ud   0x13
 #define fineibt_preamble_hash 5
 
+#define fineibt_prefix_size (fineibt_preamble_size - ENDBR_INSN_SIZE)
+
 /*
  * <fineibt_caller_start>:
  *  0:   b8 78 56 34 12          mov    $0x12345678, %eax
@@ -1620,7 +1622,7 @@ static int cfi_rewrite_preamble(s32 *start, s32 *end)
 		 * have determined there are no indirect calls to it and we
 		 * don't need no CFI either.
 		 */
-		if (!is_endbr(addr + 16))
+		if (!is_endbr(addr + CFI_OFFSET))
 			continue;
 
 		hash = decode_preamble_hash(addr, &arity);
@@ -1628,6 +1630,15 @@ static int cfi_rewrite_preamble(s32 *start, s32 *end)
 			 addr, addr, 5, addr))
 			return -EINVAL;
 
+		/*
+		 * FineIBT relies on being at func-16, so if the preamble is
+		 * actually larger than that, place it the tail end.
+		 *
+		 * NOTE: this is possible with things like DEBUG_CALL_THUNKS
+		 * and DEBUG_FORCE_FUNCTION_ALIGN_64B.
+		 */
+		addr += CFI_OFFSET - fineibt_prefix_size;
+
 		text_poke_early(addr, fineibt_preamble_start, fineibt_preamble_size);
 		WARN_ON(*(u32 *)(addr + fineibt_preamble_hash) != 0x12345678);
 		text_poke_early(addr + fineibt_preamble_hash, &hash, 4);
@@ -1650,10 +1661,10 @@ static void cfi_rewrite_endbr(s32 *start, s32 *end)
 	for (s = start; s < end; s++) {
 		void *addr = (void *)s + *s;
 
-		if (!exact_endbr(addr + 16))
+		if (!exact_endbr(addr + CFI_OFFSET))
 			continue;
 
-		poison_endbr(addr + 16);
+		poison_endbr(addr + CFI_OFFSET);
 	}
 }
 
@@ -1758,7 +1769,8 @@ static void __apply_fineibt(s32 *start_retpoline, s32 *end_retpoline,
 	if (FINEIBT_WARN(fineibt_preamble_size, 20)			||
 	    FINEIBT_WARN(fineibt_preamble_bhi + fineibt_bhi1_size, 20)	||
 	    FINEIBT_WARN(fineibt_caller_size, 14)			||
-	    FINEIBT_WARN(fineibt_paranoid_size, 20))
+	    FINEIBT_WARN(fineibt_paranoid_size, 20)			||
+	    WARN_ON_ONCE(CFI_OFFSET < fineibt_prefix_size))
 		return;
 
 	if (cfi_mode == CFI_AUTO) {
@@ -1871,6 +1883,11 @@ static void poison_cfi(void *addr)
 	 */
 	switch (cfi_mode) {
 	case CFI_FINEIBT:
+		/*
+		 * FineIBT preamble is at func-16.
+		 */
+		addr += CFI_OFFSET - fineibt_prefix_size;
+
 		/*
 		 * FineIBT prefix should start with an ENDBR.
 		 */
@@ -1909,8 +1926,6 @@ static void poison_cfi(void *addr)
 	}
 }
 
-#define fineibt_prefix_size (fineibt_preamble_size - ENDBR_INSN_SIZE)
-
 /*
  * When regs->ip points to a 0xD6 byte in the FineIBT preamble,
  * return true and fill out target and type.
arch/x86/net/bpf_jit_comp.c +2 -11
index de5083cb1d374..788671a32d8ee 100644
@@ -438,17 +438,8 @@ static void emit_kcfi(u8 **pprog, u32 hash)
 
 	EMIT1_off32(0xb8, hash);			/* movl $hash, %eax	*/
 #ifdef CONFIG_CALL_PADDING
-	EMIT1(0x90);
-	EMIT1(0x90);
-	EMIT1(0x90);
-	EMIT1(0x90);
-	EMIT1(0x90);
-	EMIT1(0x90);
-	EMIT1(0x90);
-	EMIT1(0x90);
-	EMIT1(0x90);
-	EMIT1(0x90);
-	EMIT1(0x90);
+	for (int i = 0; i < CONFIG_FUNCTION_PADDING_CFI; i++)
+		EMIT1(0x90);
 #endif
 	EMIT_ENDBR();
 
Signature · 1 line
2.51.0
author maintainer
#19 lore raw

PATCH 19/314 sched/fair: Rename cfs_rq::avg_load to cfs_rq::sum_weight

In reply to Sasha Levin

From: Ingo Molnar <[email protected]>

[ Upstream commit 4ff674fa986c27ec8a0542479258c92d361a2566 ]

The ::avg_load field is a long-standing misnomer: it says it's an 'average load', but in reality it's the momentary sum of the load of all currently runnable tasks. We'd have to also perform a division by nr_running (or use time-decay) to arrive at any sort of average value.

This is clear from comments about the math of fair scheduling:

* \Sum w_i := cfs_rq->avg_load

The sum of all weights is ... the sum of all weights, not the average of all weights.

To make it doubly confusing, there's also an ::avg_load in the load-balancing struct sg_lb_stats, which *is* a true average.

The second part of the field's name is a minor misnomer as well: it says 'load', and it is indeed a load_weight structure as it shares code with the load-balancer - but it's only in an SMP load-balancing context where load = weight, in the fair scheduling context the primary purpose is the weighting of different nice levels.

So rename the field to ::sum_weight instead, which makes the terminology of the EEVDF math match up with our implementation of it:

* \Sum w_i := cfs_rq->sum_weight

Stable-dep-of: b3d99f43c72b ("sched/fair: Fix zero_vruntime tracking")

---
 kernel/sched/fair.c  | 16 ++++++++--------
 kernel/sched/sched.h |  2 +-
 2 files changed, 9 insertions(+), 9 deletions(-)
kernel/sched/fair.c +8 -8
index 82038166d7b0c..e68e894b57559 100644
@@ -608,7 +608,7 @@ static inline s64 entity_key(struct cfs_rq *cfs_rq, struct sched_entity *se)
  *
  *                    v0 := cfs_rq->zero_vruntime
  * \Sum (v_i - v0) * w_i := cfs_rq->avg_vruntime
- *              \Sum w_i := cfs_rq->avg_load
+ *              \Sum w_i := cfs_rq->sum_weight
  *
  * Since zero_vruntime closely tracks the per-task service, these
  * deltas: (v_i - v), will be in the order of the maximal (virtual) lag
@@ -625,7 +625,7 @@ avg_vruntime_add(struct cfs_rq *cfs_rq, struct sched_entity *se)
 	s64 key = entity_key(cfs_rq, se);
 
 	cfs_rq->avg_vruntime += key * weight;
-	cfs_rq->avg_load += weight;
+	cfs_rq->sum_weight += weight;
 }
 
 static void
@@ -635,16 +635,16 @@ avg_vruntime_sub(struct cfs_rq *cfs_rq, struct sched_entity *se)
 	s64 key = entity_key(cfs_rq, se);
 
 	cfs_rq->avg_vruntime -= key * weight;
-	cfs_rq->avg_load -= weight;
+	cfs_rq->sum_weight -= weight;
 }
 
 static inline
 void avg_vruntime_update(struct cfs_rq *cfs_rq, s64 delta)
 {
 	/*
-	 * v' = v + d ==> avg_vruntime' = avg_runtime - d*avg_load
+	 * v' = v + d ==> avg_vruntime' = avg_runtime - d*sum_weight
 	 */
-	cfs_rq->avg_vruntime -= cfs_rq->avg_load * delta;
+	cfs_rq->avg_vruntime -= cfs_rq->sum_weight * delta;
 }
 
 /*
@@ -655,7 +655,7 @@ u64 avg_vruntime(struct cfs_rq *cfs_rq)
 {
 	struct sched_entity *curr = cfs_rq->curr;
 	s64 avg = cfs_rq->avg_vruntime;
-	long load = cfs_rq->avg_load;
+	long load = cfs_rq->sum_weight;
 
 	if (curr && curr->on_rq) {
 		unsigned long weight = scale_load_down(curr->load.weight);
@@ -723,7 +723,7 @@ static int vruntime_eligible(struct cfs_rq *cfs_rq, u64 vruntime)
 {
 	struct sched_entity *curr = cfs_rq->curr;
 	s64 avg = cfs_rq->avg_vruntime;
-	long load = cfs_rq->avg_load;
+	long load = cfs_rq->sum_weight;
 
 	if (curr && curr->on_rq) {
 		unsigned long weight = scale_load_down(curr->load.weight);
@@ -5164,7 +5164,7 @@ place_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags)
 		 *
 		 *   vl_i = (W + w_i)*vl'_i / W
 		 */
-		load = cfs_rq->avg_load;
+		load = cfs_rq->sum_weight;
 		if (curr && curr->on_rq)
 			load += scale_load_down(curr->load.weight);
 
kernel/sched/sched.h +1 -1
index 2f8b06b12a98f..20b2b7746c3c7 100644
@@ -681,7 +681,7 @@ struct cfs_rq {
 	unsigned int		h_nr_idle; /* SCHED_IDLE */
 
 	s64			avg_vruntime;
-	u64			avg_load;
+	u64			sum_weight;
 
 	u64			zero_vruntime;
 #ifdef CONFIG_SCHED_CORE
Signature · 1 line
2.51.0
author maintainer
#20 lore raw

PATCH 20/314 sched/fair: Rename cfs_rq::avg_vruntime to ::sum_w_vruntime, and helper functions

In reply to Sasha Levin

From: Ingo Molnar <[email protected]>

[ Upstream commit dcbc9d3f0e594223275a18f7016001889ad35eff ]

The ::avg_vruntime field is a misnomer: it says it's an 'average vruntime', but in reality it's the momentary sum of the weighted vruntimes of all queued tasks, which is at least a division away from being an average.

This is clear from comments about the math of fair scheduling:

* \Sum (v_i - v0) * w_i := cfs_rq->avg_vruntime

This confusion is increased by the cfs_avg_vruntime() function, which does perform the division and returns a true average.

The sum of all weighted vruntimes should be named thusly, so rename the field to ::sum_w_vruntime. (As arguably ::sum_weighted_vruntime would be a bit of a mouthful.)

Understanding the scheduler is hard enough already, without extra layers of obfuscated naming. ;-)

Also rename related helper functions:

sum_vruntime_add() => sum_w_vruntime_add()
sum_vruntime_sub() => sum_w_vruntime_sub()
sum_vruntime_update() => sum_w_vruntime_update()

With the notable exception of cfs_avg_vruntime(), which was named accurately.

Stable-dep-of: b3d99f43c72b ("sched/fair: Fix zero_vruntime tracking")

---
 kernel/sched/fair.c  | 26 +++++++++++++-------------
 kernel/sched/sched.h |  2 +-
 2 files changed, 14 insertions(+), 14 deletions(-)
kernel/sched/fair.c +13 -13
index e68e894b57559..a5f698ed15032 100644
@@ -607,7 +607,7 @@ static inline s64 entity_key(struct cfs_rq *cfs_rq, struct sched_entity *se)
  * Which we track using:
  *
  *                    v0 := cfs_rq->zero_vruntime
- * \Sum (v_i - v0) * w_i := cfs_rq->avg_vruntime
+ * \Sum (v_i - v0) * w_i := cfs_rq->sum_w_vruntime
  *              \Sum w_i := cfs_rq->sum_weight
  *
  * Since zero_vruntime closely tracks the per-task service, these
@@ -619,32 +619,32 @@ static inline s64 entity_key(struct cfs_rq *cfs_rq, struct sched_entity *se)
  * As measured, the max (key * weight) value was ~44 bits for a kernel build.
  */
 static void
-avg_vruntime_add(struct cfs_rq *cfs_rq, struct sched_entity *se)
+sum_w_vruntime_add(struct cfs_rq *cfs_rq, struct sched_entity *se)
 {
 	unsigned long weight = scale_load_down(se->load.weight);
 	s64 key = entity_key(cfs_rq, se);
 
-	cfs_rq->avg_vruntime += key * weight;
+	cfs_rq->sum_w_vruntime += key * weight;
 	cfs_rq->sum_weight += weight;
 }
 
 static void
-avg_vruntime_sub(struct cfs_rq *cfs_rq, struct sched_entity *se)
+sum_w_vruntime_sub(struct cfs_rq *cfs_rq, struct sched_entity *se)
 {
 	unsigned long weight = scale_load_down(se->load.weight);
 	s64 key = entity_key(cfs_rq, se);
 
-	cfs_rq->avg_vruntime -= key * weight;
+	cfs_rq->sum_w_vruntime -= key * weight;
 	cfs_rq->sum_weight -= weight;
 }
 
 static inline
-void avg_vruntime_update(struct cfs_rq *cfs_rq, s64 delta)
+void sum_w_vruntime_update(struct cfs_rq *cfs_rq, s64 delta)
 {
 	/*
-	 * v' = v + d ==> avg_vruntime' = avg_runtime - d*sum_weight
+	 * v' = v + d ==> sum_w_vruntime' = sum_runtime - d*sum_weight
 	 */
-	cfs_rq->avg_vruntime -= cfs_rq->sum_weight * delta;
+	cfs_rq->sum_w_vruntime -= cfs_rq->sum_weight * delta;
 }
 
 /*
@@ -654,7 +654,7 @@ void avg_vruntime_update(struct cfs_rq *cfs_rq, s64 delta)
 u64 avg_vruntime(struct cfs_rq *cfs_rq)
 {
 	struct sched_entity *curr = cfs_rq->curr;
-	s64 avg = cfs_rq->avg_vruntime;
+	s64 avg = cfs_rq->sum_w_vruntime;
 	long load = cfs_rq->sum_weight;
 
 	if (curr && curr->on_rq) {
@@ -722,7 +722,7 @@ static void update_entity_lag(struct cfs_rq *cfs_rq, struct sched_entity *se)
 static int vruntime_eligible(struct cfs_rq *cfs_rq, u64 vruntime)
 {
 	struct sched_entity *curr = cfs_rq->curr;
-	s64 avg = cfs_rq->avg_vruntime;
+	s64 avg = cfs_rq->sum_w_vruntime;
 	long load = cfs_rq->sum_weight;
 
 	if (curr && curr->on_rq) {
@@ -745,7 +745,7 @@ static void update_zero_vruntime(struct cfs_rq *cfs_rq)
 	u64 vruntime = avg_vruntime(cfs_rq);
 	s64 delta = (s64)(vruntime - cfs_rq->zero_vruntime);
 
-	avg_vruntime_update(cfs_rq, delta);
+	sum_w_vruntime_update(cfs_rq, delta);
 
 	cfs_rq->zero_vruntime = vruntime;
 }
@@ -819,7 +819,7 @@ RB_DECLARE_CALLBACKS(static, min_vruntime_cb, struct sched_entity,
  */
 static void __enqueue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se)
 {
-	avg_vruntime_add(cfs_rq, se);
+	sum_w_vruntime_add(cfs_rq, se);
 	update_zero_vruntime(cfs_rq);
 	se->min_vruntime = se->vruntime;
 	se->min_slice = se->slice;
@@ -831,7 +831,7 @@ static void __dequeue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se)
 {
 	rb_erase_augmented_cached(&se->run_node, &cfs_rq->tasks_timeline,
 				  &min_vruntime_cb);
-	avg_vruntime_sub(cfs_rq, se);
+	sum_w_vruntime_sub(cfs_rq, se);
 	update_zero_vruntime(cfs_rq);
 }
 
kernel/sched/sched.h +1 -1
index 20b2b7746c3c7..ed37ab9209e59 100644
@@ -680,7 +680,7 @@ struct cfs_rq {
 	unsigned int		h_nr_runnable;     /* SCHED_{NORMAL,BATCH,IDLE} */
 	unsigned int		h_nr_idle; /* SCHED_IDLE */
 
-	s64			avg_vruntime;
+	s64			sum_w_vruntime;
 	u64			sum_weight;
 
 	u64			zero_vruntime;
Signature · 1 line
2.51.0
author maintainer
#21 lore raw

PATCH 21/314 sched/fair: Introduce and use the vruntime_cmp() and vruntime_op() wrappers for wrapped-signed aritmetics

In reply to Sasha Levin

From: Ingo Molnar <[email protected]>

[ Upstream commit 5758e48eefaf111d7764d8f1c8b666140fe5fa27 ]

We have to be careful with vruntime comparisons and subtraction, due to the possibility of wrapping, so we have macros like:

   #define vruntime_gt(field, lse, rse) ({ (s64)((lse)->field - (rse)->field) > 0; })

Which is used like this:

		if (vruntime_gt(min_vruntime, se, rse))
			se->min_vruntime = rse->min_vruntime;

Replace this with an easier to read pattern that uses the regular arithmetics operators:

		if (vruntime_cmp(se->min_vruntime, ">", rse->min_vruntime))
			se->min_vruntime = rse->min_vruntime;

Also replace vruntime subtractions with vruntime_op():

- delta = (s64)(sea->vruntime - seb->vruntime) +
- (s64)(cfs_rqb->zero_vruntime_fi - cfs_rqa->zero_vruntime_fi);
+ delta = vruntime_op(sea->vruntime, "-", seb->vruntime) +
+ vruntime_op(cfs_rqb->zero_vruntime_fi, "-", cfs_rqa->zero_vruntime_fi);

In the vruntime_cmp() and vruntime_op() macros use Use __builtin_strcmp(), because of __HAVE_ARCH_STRCMP might turn off the compiler optimizations we rely on here to catch usage bugs.

No change in functionality.

Stable-dep-of: b3d99f43c72b ("sched/fair: Fix zero_vruntime tracking")

---
 kernel/sched/fair.c | 66 ++++++++++++++++++++++++++++++++++-----------
 1 file changed, 51 insertions(+), 15 deletions(-)
kernel/sched/fair.c +51 -15
index a5f698ed15032..f669c84c7c0e9 100644
@@ -524,10 +524,48 @@ void account_cfs_rq_runtime(struct cfs_rq *cfs_rq, u64 delta_exec);
  * Scheduling class tree data structure manipulation methods:
  */
 
+extern void __BUILD_BUG_vruntime_cmp(void);
+
+/* Use __builtin_strcmp() because of __HAVE_ARCH_STRCMP: */
+
+#define vruntime_cmp(A, CMP_STR, B) ({				\
+	int __res = 0;						\
+								\
+	if (!__builtin_strcmp(CMP_STR, "<")) {			\
+		__res = ((s64)((A)-(B)) < 0);			\
+	} else if (!__builtin_strcmp(CMP_STR, "<=")) {		\
+		__res = ((s64)((A)-(B)) <= 0);			\
+	} else if (!__builtin_strcmp(CMP_STR, ">")) {		\
+		__res = ((s64)((A)-(B)) > 0);			\
+	} else if (!__builtin_strcmp(CMP_STR, ">=")) {		\
+		__res = ((s64)((A)-(B)) >= 0);			\
+	} else {						\
+		/* Unknown operator throws linker error: */	\
+		__BUILD_BUG_vruntime_cmp();			\
+	}							\
+								\
+	__res;							\
+})
+
+extern void __BUILD_BUG_vruntime_op(void);
+
+#define vruntime_op(A, OP_STR, B) ({				\
+	s64 __res = 0;						\
+								\
+	if (!__builtin_strcmp(OP_STR, "-")) {			\
+		__res = (s64)((A)-(B));				\
+	} else {						\
+		/* Unknown operator throws linker error: */	\
+		__BUILD_BUG_vruntime_op();			\
+	}							\
+								\
+	__res;						\
+})
+
+
 static inline __maybe_unused u64 max_vruntime(u64 max_vruntime, u64 vruntime)
 {
-	s64 delta = (s64)(vruntime - max_vruntime);
-	if (delta > 0)
+	if (vruntime_cmp(vruntime, ">", max_vruntime))
 		max_vruntime = vruntime;
 
 	return max_vruntime;
@@ -535,8 +573,7 @@ static inline __maybe_unused u64 max_vruntime(u64 max_vruntime, u64 vruntime)
 
 static inline __maybe_unused u64 min_vruntime(u64 min_vruntime, u64 vruntime)
 {
-	s64 delta = (s64)(vruntime - min_vruntime);
-	if (delta < 0)
+	if (vruntime_cmp(vruntime, "<", min_vruntime))
 		min_vruntime = vruntime;
 
 	return min_vruntime;
@@ -549,12 +586,12 @@ static inline bool entity_before(const struct sched_entity *a,
 	 * Tiebreak on vruntime seems unnecessary since it can
 	 * hardly happen.
 	 */
-	return (s64)(a->deadline - b->deadline) < 0;
+	return vruntime_cmp(a->deadline, "<", b->deadline);
 }
 
 static inline s64 entity_key(struct cfs_rq *cfs_rq, struct sched_entity *se)
 {
-	return (s64)(se->vruntime - cfs_rq->zero_vruntime);
+	return vruntime_op(se->vruntime, "-", cfs_rq->zero_vruntime);
 }
 
 #define __node_2_se(node) \
@@ -732,7 +769,7 @@ static int vruntime_eligible(struct cfs_rq *cfs_rq, u64 vruntime)
 		load += weight;
 	}
 
-	return avg >= (s64)(vruntime - cfs_rq->zero_vruntime) * load;
+	return avg >= vruntime_op(vruntime, "-", cfs_rq->zero_vruntime) * load;
 }
 
 int entity_eligible(struct cfs_rq *cfs_rq, struct sched_entity *se)
@@ -743,7 +780,7 @@ int entity_eligible(struct cfs_rq *cfs_rq, struct sched_entity *se)
 static void update_zero_vruntime(struct cfs_rq *cfs_rq)
 {
 	u64 vruntime = avg_vruntime(cfs_rq);
-	s64 delta = (s64)(vruntime - cfs_rq->zero_vruntime);
+	s64 delta = vruntime_op(vruntime, "-", cfs_rq->zero_vruntime);
 
 	sum_w_vruntime_update(cfs_rq, delta);
 
@@ -770,13 +807,12 @@ static inline bool __entity_less(struct rb_node *a, const struct rb_node *b)
 	return entity_before(__node_2_se(a), __node_2_se(b));
 }
 
-#define vruntime_gt(field, lse, rse) ({ (s64)((lse)->field - (rse)->field) > 0; })
-
 static inline void __min_vruntime_update(struct sched_entity *se, struct rb_node *node)
 {
 	if (node) {
 		struct sched_entity *rse = __node_2_se(node);
-		if (vruntime_gt(min_vruntime, se, rse))
+
+		if (vruntime_cmp(se->min_vruntime, ">", rse->min_vruntime))
 			se->min_vruntime = rse->min_vruntime;
 	}
 }
@@ -887,7 +923,7 @@ static inline void update_protect_slice(struct cfs_rq *cfs_rq, struct sched_enti
 
 static inline bool protect_slice(struct sched_entity *se)
 {
-	return ((s64)(se->vprot - se->vruntime) > 0);
+	return vruntime_cmp(se->vruntime, "<", se->vprot);
 }
 
 static inline void cancel_protect_slice(struct sched_entity *se)
@@ -1014,7 +1050,7 @@ static void clear_buddies(struct cfs_rq *cfs_rq, struct sched_entity *se);
  */
 static bool update_deadline(struct cfs_rq *cfs_rq, struct sched_entity *se)
 {
-	if ((s64)(se->vruntime - se->deadline) < 0)
+	if (vruntime_cmp(se->vruntime, "<", se->deadline))
 		return false;
 
 	/*
@@ -13238,8 +13274,8 @@ bool cfs_prio_less(const struct task_struct *a, const struct task_struct *b,
 	 * zero_vruntime_fi, which would have been updated in prior calls
 	 * to se_fi_update().
 	 */
-	delta = (s64)(sea->vruntime - seb->vruntime) +
-		(s64)(cfs_rqb->zero_vruntime_fi - cfs_rqa->zero_vruntime_fi);
+	delta = vruntime_op(sea->vruntime, "-", seb->vruntime) +
+		vruntime_op(cfs_rqb->zero_vruntime_fi, "-", cfs_rqa->zero_vruntime_fi);
 
 	return delta > 0;
 }
Signature · 1 line
2.51.0
author maintainer
#22 lore raw

PATCH 22/314 sched/fair: Fix zero_vruntime tracking

In reply to Sasha Levin

From: Peter Zijlstra <[email protected]>

[ Upstream commit b3d99f43c72b56cf7a104a364e7fb34b0702828b ]

It turns out that zero_vruntime tracking is broken when there is but a single task running. Current update paths are through __{en,de}queue_entity(), and when there is but a single task, pick_next_task() will always return that one task, and put_prev_set_next_task() will end up in neither function.

This can cause entity_key() to grow indefinitely large and cause overflows, leading to much pain and suffering.

Furtermore, doing update_zero_vruntime() from __{de,en}queue_entity(), which are called from {set_next,put_prev}_entity() has problems because:

- set_next_entity() calls __dequeue_entity() before it does cfs_rq->curr = se. This means the avg_vruntime() will see the removal but not current, missing the entity for accounting.

- put_prev_entity() calls __enqueue_entity() before it does cfs_rq->curr = NULL. This means the avg_vruntime() will see the addition *and* current, leading to double accounting.

Both cases are incorrect/inconsistent.

Noting that avg_vruntime is already called on each {en,de}queue, remove the explicit avg_vruntime() calls (which removes an extra 64bit division for each {en,de}queue) and have avg_vruntime() update zero_vruntime itself.

Additionally, have the tick call avg_vruntime() -- discarding the result, but for the side-effect of updating zero_vruntime.

While there, optimize avg_vruntime() by noting that the average of one value is rather trivial to compute.

Test case:

  # taskset -c -p 1 $$
  # taskset -c 2 bash -c 'while :; do :; done&'
  # cat /sys/kernel/debug/sched/debug | awk '/^cpu#/ {P=0} /^cpu#2,/ {P=1} {if (P) print $0}' | grep -e zero_vruntime -e "^>"

PRE:

    .zero_vruntime                 : 31316.407903
Quoted 1 line

R bash 487 50787.345112 E 50789.145972 2.800000 50780.298364 16 120 0.000000 0.000000 0.000000 /

    .zero_vruntime                 : 382548.253179
Quoted 1 line

R bash 487 427275.204288 E 427276.003584 2.800000 427268.157540 23 120 0.000000 0.000000 0.000000 /

POST:

    .zero_vruntime                 : 17259.709467
Quoted 1 line

R bash 526 17259.709467 E 17262.509467 2.800000 16915.031624 9 120 0.000000 0.000000 0.000000 /

    .zero_vruntime                 : 18702.723356
Quoted 1 line

R bash 526 18702.723356 E 18705.523356 2.800000 18358.045513 9 120 0.000000 0.000000 0.000000 /

---
 kernel/sched/fair.c | 84 ++++++++++++++++++++++++++++++---------------
 1 file changed, 57 insertions(+), 27 deletions(-)
kernel/sched/fair.c +57 -27
index f669c84c7c0e9..c3735197c6e7c 100644
@@ -589,6 +589,21 @@ static inline bool entity_before(const struct sched_entity *a,
 	return vruntime_cmp(a->deadline, "<", b->deadline);
 }
 
+/*
+ * Per avg_vruntime() below, cfs_rq::zero_vruntime is only slightly stale
+ * and this value should be no more than two lag bounds. Which puts it in the
+ * general order of:
+ *
+ *	(slice + TICK_NSEC) << NICE_0_LOAD_SHIFT
+ *
+ * which is around 44 bits in size (on 64bit); that is 20 for
+ * NICE_0_LOAD_SHIFT, another 20 for NSEC_PER_MSEC and then a handful for
+ * however many msec the actual slice+tick ends up begin.
+ *
+ * (disregarding the actual divide-by-weight part makes for the worst case
+ * weight of 2, which nicely cancels vs the fuzz in zero_vruntime not actually
+ * being the zero-lag point).
+ */
 static inline s64 entity_key(struct cfs_rq *cfs_rq, struct sched_entity *se)
 {
 	return vruntime_op(se->vruntime, "-", cfs_rq->zero_vruntime);
@@ -676,39 +691,61 @@ sum_w_vruntime_sub(struct cfs_rq *cfs_rq, struct sched_entity *se)
 }
 
 static inline
-void sum_w_vruntime_update(struct cfs_rq *cfs_rq, s64 delta)
+void update_zero_vruntime(struct cfs_rq *cfs_rq, s64 delta)
 {
 	/*
-	 * v' = v + d ==> sum_w_vruntime' = sum_runtime - d*sum_weight
+	 * v' = v + d ==> sum_w_vruntime' = sum_w_vruntime - d*sum_weight
 	 */
 	cfs_rq->sum_w_vruntime -= cfs_rq->sum_weight * delta;
+	cfs_rq->zero_vruntime += delta;
 }
 
 /*
- * Specifically: avg_runtime() + 0 must result in entity_eligible() := true
+ * Specifically: avg_vruntime() + 0 must result in entity_eligible() := true
  * For this to be so, the result of this function must have a left bias.
+ *
+ * Called in:
+ *  - place_entity()      -- before enqueue
+ *  - update_entity_lag() -- before dequeue
+ *  - entity_tick()
+ *
+ * This means it is one entry 'behind' but that puts it close enough to where
+ * the bound on entity_key() is at most two lag bounds.
  */
 u64 avg_vruntime(struct cfs_rq *cfs_rq)
 {
 	struct sched_entity *curr = cfs_rq->curr;
-	s64 avg = cfs_rq->sum_w_vruntime;
-	long load = cfs_rq->sum_weight;
+	long weight = cfs_rq->sum_weight;
+	s64 delta = 0;
 
-	if (curr && curr->on_rq) {
-		unsigned long weight = scale_load_down(curr->load.weight);
+	if (curr && !curr->on_rq)
+		curr = NULL;
 
-		avg += entity_key(cfs_rq, curr) * weight;
-		load += weight;
-	}
+	if (weight) {
+		s64 runtime = cfs_rq->sum_w_vruntime;
+
+		if (curr) {
+			unsigned long w = scale_load_down(curr->load.weight);
+
+			runtime += entity_key(cfs_rq, curr) * w;
+			weight += w;
+		}
 
-	if (load) {
 		/* sign flips effective floor / ceiling */
-		if (avg < 0)
-			avg -= (load - 1);
-		avg = div_s64(avg, load);
+		if (runtime < 0)
+			runtime -= (weight - 1);
+
+		delta = div_s64(runtime, weight);
+	} else if (curr) {
+		/*
+		 * When there is but one element, it is the average.
+		 */
+		delta = curr->vruntime - cfs_rq->zero_vruntime;
 	}
 
-	return cfs_rq->zero_vruntime + avg;
+	update_zero_vruntime(cfs_rq, delta);
+
+	return cfs_rq->zero_vruntime;
 }
 
 /*
@@ -777,16 +814,6 @@ int entity_eligible(struct cfs_rq *cfs_rq, struct sched_entity *se)
 	return vruntime_eligible(cfs_rq, se->vruntime);
 }
 
-static void update_zero_vruntime(struct cfs_rq *cfs_rq)
-{
-	u64 vruntime = avg_vruntime(cfs_rq);
-	s64 delta = vruntime_op(vruntime, "-", cfs_rq->zero_vruntime);
-
-	sum_w_vruntime_update(cfs_rq, delta);
-
-	cfs_rq->zero_vruntime = vruntime;
-}
-
 static inline u64 cfs_rq_min_slice(struct cfs_rq *cfs_rq)
 {
 	struct sched_entity *root = __pick_root_entity(cfs_rq);
@@ -856,7 +883,6 @@ RB_DECLARE_CALLBACKS(static, min_vruntime_cb, struct sched_entity,
 static void __enqueue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se)
 {
 	sum_w_vruntime_add(cfs_rq, se);
-	update_zero_vruntime(cfs_rq);
 	se->min_vruntime = se->vruntime;
 	se->min_slice = se->slice;
 	rb_add_augmented_cached(&se->run_node, &cfs_rq->tasks_timeline,
@@ -868,7 +894,6 @@ static void __dequeue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se)
 	rb_erase_augmented_cached(&se->run_node, &cfs_rq->tasks_timeline,
 				  &min_vruntime_cb);
 	sum_w_vruntime_sub(cfs_rq, se);
-	update_zero_vruntime(cfs_rq);
 }
 
 struct sched_entity *__pick_root_entity(struct cfs_rq *cfs_rq)
@@ -5566,6 +5591,11 @@ entity_tick(struct cfs_rq *cfs_rq, struct sched_entity *curr, int queued)
 	update_load_avg(cfs_rq, curr, UPDATE_TG);
 	update_cfs_group(curr);
 
+	/*
+	 * Pulls along cfs_rq::zero_vruntime.
+	 */
+	avg_vruntime(cfs_rq);
+
 #ifdef CONFIG_SCHED_HRTICK
 	/*
 	 * queued ticks are scheduled to match the slice, so don't bother
Signature · 1 line
2.51.0
#23 lore raw

Re: [PATCH 6.18 022/314] sched/fair: Fix zero_vruntime tracking

Shouldn't this also be applied to the 6.12 stable kernel as well, since it has the patch mentioned in the Fixes: line?

The broken tracking mentioned in the test case is seen in 6.12 kernels as well.

author maintainer
#24 lore raw

Re: [PATCH 6.18 022/314] sched/fair: Fix zero_vruntime tracking

Quoted 4 lines · Eric Hagberg

Shouldn't this also be applied to the 6.12 stable kernel as well, since it has the patch mentioned in the Fixes: line?

The broken tracking mentioned in the test case is seen in 6.12 kernels as well.

Could you send a tested backport please?

Signature · 2 lines
Thanks,
Sasha
#25 lore raw

PATCH 1/1 backport of "sched/fair: Fix zero_vruntime tracking" for 6.12

[ Upstream commit b3d99f43c72b56cf7a104a364e7fb34b0702828b ]

This fixes the same problem that was reported upstream and fixed in 6.18 and 6.19 kernels.

Fixes 79f3f9bedd14 ("sched/eevdf: Fix min_vruntime vs avg_vruntime")
---
 kernel/sched/fair.c | 84 ++++++++++++++++++++++++++++++---------------
 1 file changed, 57 insertions(+), 27 deletions(-)
kernel/sched/fair.c +57 -27
index 6efb1dfcd943..efd3cbefb5a2 100644
@@ -551,6 +551,21 @@ static inline bool entity_before(const struct sched_entity *a,
 	return (s64)(a->deadline - b->deadline) < 0;
 }
 
+/*
+ * Per avg_vruntime() below, cfs_rq::zero_vruntime is only slightly stale
+ * and this value should be no more than two lag bounds. Which puts it in the
+ * general order of:
+ *
+ *	(slice + TICK_NSEC) << NICE_0_LOAD_SHIFT
+ *
+ * which is around 44 bits in size (on 64bit); that is 20 for
+ * NICE_0_LOAD_SHIFT, another 20 for NSEC_PER_MSEC and then a handful for
+ * however many msec the actual slice+tick ends up begin.
+ *
+ * (disregarding the actual divide-by-weight part makes for the worst case
+ * weight of 2, which nicely cancels vs the fuzz in zero_vruntime not actually
+ * being the zero-lag point).
+ */
 static inline s64 entity_key(struct cfs_rq *cfs_rq, struct sched_entity *se)
 {
 	return (s64)(se->vruntime - cfs_rq->zero_vruntime);
@@ -638,39 +653,61 @@ avg_vruntime_sub(struct cfs_rq *cfs_rq, struct sched_entity *se)
 }
 
 static inline
-void avg_vruntime_update(struct cfs_rq *cfs_rq, s64 delta)
+void update_zero_vruntime(struct cfs_rq *cfs_rq, s64 delta)
 {
 	/*
-	 * v' = v + d ==> avg_vruntime' = avg_runtime - d*avg_load
+	 * v' = v + d ==> avg_vruntime' = avg_vruntime - d*avg_load
 	 */
 	cfs_rq->avg_vruntime -= cfs_rq->avg_load * delta;
+       cfs_rq->zero_vruntime += delta;
 }
 
 /*
- * Specifically: avg_runtime() + 0 must result in entity_eligible() := true
+ * Specifically: avg_vruntime() + 0 must result in entity_eligible() := true
  * For this to be so, the result of this function must have a left bias.
+ *
+ * Called in:
+ *  - place_entity()      -- before enqueue
+ *  - update_entity_lag() -- before dequeue
+ *  - entity_tick()
+ *
+ * This means it is one entry 'behind' but that puts it close enough to where
+ * the bound on entity_key() is at most two lag bounds.
  */
 u64 avg_vruntime(struct cfs_rq *cfs_rq)
 {
 	struct sched_entity *curr = cfs_rq->curr;
-	s64 avg = cfs_rq->avg_vruntime;
-	long load = cfs_rq->avg_load;
+       long weight = cfs_rq->avg_load;
+       s64 delta = 0;
 
-	if (curr && curr->on_rq) {
-		unsigned long weight = scale_load_down(curr->load.weight);
+       if (curr && !curr->on_rq)
+               curr = NULL;
 
-		avg += entity_key(cfs_rq, curr) * weight;
-		load += weight;
-	}
+       if (weight) {
+               s64 runtime = cfs_rq->avg_vruntime;
+
+               if (curr) {
+                       unsigned long w = scale_load_down(curr->load.weight);
+
+                       runtime += entity_key(cfs_rq, curr) * w;
+                       weight += w;
+               }
 
-	if (load) {
 		/* sign flips effective floor / ceiling */
-		if (avg < 0)
-			avg -= (load - 1);
-		avg = div_s64(avg, load);
+               if (runtime < 0)
+                       runtime -= (weight - 1);
+
+               delta = div_s64(runtime, weight);
+       } else if (curr) {
+               /*
+                * When there is but one element, it is the average.
+                */
+               delta = curr->vruntime - cfs_rq->zero_vruntime;
 	}
 
-	return cfs_rq->zero_vruntime + avg;
+       update_zero_vruntime(cfs_rq, delta);
+
+       return cfs_rq->zero_vruntime;
 }
 
 /*
@@ -744,16 +781,6 @@ int entity_eligible(struct cfs_rq *cfs_rq, struct sched_entity *se)
 	return vruntime_eligible(cfs_rq, se->vruntime);
 }
 
-static void update_zero_vruntime(struct cfs_rq *cfs_rq)
-{
-	u64 vruntime = avg_vruntime(cfs_rq);
-	s64 delta = (s64)(vruntime - cfs_rq->zero_vruntime);
-
-	avg_vruntime_update(cfs_rq, delta);
-
-	cfs_rq->zero_vruntime = vruntime;
-}
-
 static inline u64 cfs_rq_min_slice(struct cfs_rq *cfs_rq)
 {
 	struct sched_entity *root = __pick_root_entity(cfs_rq);
@@ -824,7 +851,6 @@ RB_DECLARE_CALLBACKS(static, min_vruntime_cb, struct sched_entity,
 static void __enqueue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se)
 {
 	avg_vruntime_add(cfs_rq, se);
-	update_zero_vruntime(cfs_rq);
 	se->min_vruntime = se->vruntime;
 	se->min_slice = se->slice;
 	rb_add_augmented_cached(&se->run_node, &cfs_rq->tasks_timeline,
@@ -836,7 +862,6 @@ static void __dequeue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se)
 	rb_erase_augmented_cached(&se->run_node, &cfs_rq->tasks_timeline,
 				  &min_vruntime_cb);
 	avg_vruntime_sub(cfs_rq, se);
-	update_zero_vruntime(cfs_rq);
 }
 
 struct sched_entity *__pick_root_entity(struct cfs_rq *cfs_rq)
@@ -5700,6 +5725,11 @@ entity_tick(struct cfs_rq *cfs_rq, struct sched_entity *curr, int queued)
 	update_load_avg(cfs_rq, curr, UPDATE_TG);
 	update_cfs_group(curr);
 
+	/*
+	 * Pulls along cfs_rq::zero_vruntime.
+	 */
+	avg_vruntime(cfs_rq);
+
 #ifdef CONFIG_SCHED_HRTICK
 	/*
 	 * queued ticks are scheduled to match the slice, so don't bother
Signature · 1 line
2.43.7
maintainer
#26 lore raw

Re: [PATCH 6.18 022/314] sched/fair: Fix zero_vruntime tracking

In reply to Eric Hagberg
Quoted 5 lines · Eric Hagberg

Shouldn't this also be applied to the 6.12 stable kernel as well, since it has the patch mentioned in the Fixes: line?

The broken tracking mentioned in the test case is seen in 6.12 kernels as well.

If it didn't apply, can you provide a working version that we can apply?

thanks,

greg k-h

author maintainer
#27 lore raw

PATCH 23/314 sched/fair: Only set slice protection at pick time

In reply to Sasha Levin

From: Peter Zijlstra <[email protected]>

[ Upstream commit bcd74b2ffdd0a2233adbf26b65c62fc69a809c8e ]

We should not (re)set slice protection in the sched_change pattern which calls put_prev_task() / set_next_task().

---
 kernel/sched/fair.c | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)
kernel/sched/fair.c +6 -5
index c3735197c6e7c..1644ad90acdca 100644
@@ -5477,7 +5477,7 @@ dequeue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags)
 }
 
 static void
-set_next_entity(struct cfs_rq *cfs_rq, struct sched_entity *se)
+set_next_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, bool first)
 {
 	clear_buddies(cfs_rq, se);
 
@@ -5492,7 +5492,8 @@ set_next_entity(struct cfs_rq *cfs_rq, struct sched_entity *se)
 		__dequeue_entity(cfs_rq, se);
 		update_load_avg(cfs_rq, se, UPDATE_TG);
 
-		set_protect_slice(cfs_rq, se);
+		if (first)
+			set_protect_slice(cfs_rq, se);
 	}
 
 	update_stats_curr_start(cfs_rq, se);
@@ -8932,13 +8933,13 @@ pick_next_task_fair(struct rq *rq, struct task_struct *prev, struct rq_flags *rf
 				pse = parent_entity(pse);
 			}
 			if (se_depth >= pse_depth) {
-				set_next_entity(cfs_rq_of(se), se);
+				set_next_entity(cfs_rq_of(se), se, true);
 				se = parent_entity(se);
 			}
 		}
 
 		put_prev_entity(cfs_rq, pse);
-		set_next_entity(cfs_rq, se);
+		set_next_entity(cfs_rq, se, true);
 
 		__set_next_task_fair(rq, p, true);
 	}
@@ -13530,7 +13531,7 @@ static void set_next_task_fair(struct rq *rq, struct task_struct *p, bool first)
 	for_each_sched_entity(se) {
 		struct cfs_rq *cfs_rq = cfs_rq_of(se);
 
-		set_next_entity(cfs_rq, se);
+		set_next_entity(cfs_rq, se, first);
 		/* ensure bandwidth has been allocated on our new cfs_rq */
 		account_cfs_rq_runtime(cfs_rq, 0);
 	}
Signature · 1 line
2.51.0
author maintainer
#28 lore raw

PATCH 24/314 sched/eevdf: Update se->vprot in reweight_entity()

In reply to Sasha Levin

From: Wang Tao <[email protected]>

[ Upstream commit ff38424030f98976150e42ca35f4b00e6ab8fa23 ]

In the EEVDF framework with Run-to-Parity protection, se->vprot is an independent variable defining the virtual protection timestamp.

When reweight_entity() is called (e.g., via nice/renice), it performs the following actions to preserve Lag consistency:
1. Scales se->vlag based on the new weight.
2. Calls place_entity(), which recalculates se->vruntime based on the new weight and scaled lag.

However, the current implementation fails to update se->vprot, leading to mismatches between the task's actual runtime and its expected duration.

---
 kernel/sched/fair.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)
kernel/sched/fair.c +12 -0
index 1644ad90acdca..8587218ee9073 100644
@@ -3805,6 +3805,8 @@ static void reweight_entity(struct cfs_rq *cfs_rq, struct sched_entity *se,
 			    unsigned long weight)
 {
 	bool curr = cfs_rq->curr == se;
+	bool rel_vprot = false;
+	u64 vprot;
 
 	if (se->on_rq) {
 		/* commit outstanding execution time */
@@ -3812,6 +3814,11 @@ static void reweight_entity(struct cfs_rq *cfs_rq, struct sched_entity *se,
 		update_entity_lag(cfs_rq, se);
 		se->deadline -= se->vruntime;
 		se->rel_deadline = 1;
+		if (curr && protect_slice(se)) {
+			vprot = se->vprot - se->vruntime;
+			rel_vprot = true;
+		}
+
 		cfs_rq->nr_queued--;
 		if (!curr)
 			__dequeue_entity(cfs_rq, se);
@@ -3827,6 +3834,9 @@ static void reweight_entity(struct cfs_rq *cfs_rq, struct sched_entity *se,
 	if (se->rel_deadline)
 		se->deadline = div_s64(se->deadline * se->load.weight, weight);
 
+	if (rel_vprot)
+		vprot = div_s64(vprot * se->load.weight, weight);
+
 	update_load_set(&se->load, weight);
 
 	do {
@@ -3838,6 +3848,8 @@ static void reweight_entity(struct cfs_rq *cfs_rq, struct sched_entity *se,
 	enqueue_load_avg(cfs_rq, se);
 	if (se->on_rq) {
 		place_entity(cfs_rq, se, 0);
+		if (rel_vprot)
+			se->vprot = se->vruntime + vprot;
 		update_load_add(&cfs_rq->load, se->load.weight);
 		if (!curr)
 			__enqueue_entity(cfs_rq, se);
Signature · 1 line
2.51.0
author maintainer
#29 lore raw

PATCH 25/314 sched/fair: Fix lag clamp

In reply to Sasha Levin

From: Peter Zijlstra <[email protected]>

[ Upstream commit 6e3c0a4e1ad1e0455b7880fad02b3ee179f56c09 ]

Vincent reported that he was seeing undue lag clamping in a mixed slice workload. Implement the max_slice tracking as per the todo comment.

---
 include/linux/sched.h |  1 +
 kernel/sched/fair.c   | 39 +++++++++++++++++++++++++++++++++++----
 2 files changed, 36 insertions(+), 4 deletions(-)
include/linux/sched.h +1 -0
index 6ad294330c0b6..3e2005e9e2f0b 100644
@@ -574,6 +574,7 @@ struct sched_entity {
 	u64				deadline;
 	u64				min_vruntime;
 	u64				min_slice;
+	u64				max_slice;
 
 	struct list_head		group_node;
 	unsigned char			on_rq;
kernel/sched/fair.c +35 -4
index 8587218ee9073..292141f4aaa54 100644
@@ -748,6 +748,8 @@ u64 avg_vruntime(struct cfs_rq *cfs_rq)
 	return cfs_rq->zero_vruntime;
 }
 
+static inline u64 cfs_rq_max_slice(struct cfs_rq *cfs_rq);
+
 /*
  * lag_i = S - s_i = w_i * (V - v_i)
  *
@@ -761,17 +763,16 @@ u64 avg_vruntime(struct cfs_rq *cfs_rq)
  * EEVDF gives the following limit for a steady state system:
  *
  *   -r_max < lag < max(r_max, q)
- *
- * XXX could add max_slice to the augmented data to track this.
  */
 static void update_entity_lag(struct cfs_rq *cfs_rq, struct sched_entity *se)
 {
+	u64 max_slice = cfs_rq_max_slice(cfs_rq) + TICK_NSEC;
 	s64 vlag, limit;
 
 	WARN_ON_ONCE(!se->on_rq);
 
 	vlag = avg_vruntime(cfs_rq) - se->vruntime;
-	limit = calc_delta_fair(max_t(u64, 2*se->slice, TICK_NSEC), se);
+	limit = calc_delta_fair(max_slice, se);
 
 	se->vlag = clamp(vlag, -limit, limit);
 }
@@ -829,6 +830,21 @@ static inline u64 cfs_rq_min_slice(struct cfs_rq *cfs_rq)
 	return min_slice;
 }
 
+static inline u64 cfs_rq_max_slice(struct cfs_rq *cfs_rq)
+{
+	struct sched_entity *root = __pick_root_entity(cfs_rq);
+	struct sched_entity *curr = cfs_rq->curr;
+	u64 max_slice = 0ULL;
+
+	if (curr && curr->on_rq)
+		max_slice = curr->slice;
+
+	if (root)
+		max_slice = max(max_slice, root->max_slice);
+
+	return max_slice;
+}
+
 static inline bool __entity_less(struct rb_node *a, const struct rb_node *b)
 {
 	return entity_before(__node_2_se(a), __node_2_se(b));
@@ -853,6 +869,15 @@ static inline void __min_slice_update(struct sched_entity *se, struct rb_node *n
 	}
 }
 
+static inline void __max_slice_update(struct sched_entity *se, struct rb_node *node)
+{
+	if (node) {
+		struct sched_entity *rse = __node_2_se(node);
+		if (rse->max_slice > se->max_slice)
+			se->max_slice = rse->max_slice;
+	}
+}
+
 /*
  * se->min_vruntime = min(se->vruntime, {left,right}->min_vruntime)
  */
@@ -860,6 +885,7 @@ static inline bool min_vruntime_update(struct sched_entity *se, bool exit)
 {
 	u64 old_min_vruntime = se->min_vruntime;
 	u64 old_min_slice = se->min_slice;
+	u64 old_max_slice = se->max_slice;
 	struct rb_node *node = &se->run_node;
 
 	se->min_vruntime = se->vruntime;
@@ -870,8 +896,13 @@ static inline bool min_vruntime_update(struct sched_entity *se, bool exit)
 	__min_slice_update(se, node->rb_right);
 	__min_slice_update(se, node->rb_left);
 
+	se->max_slice = se->slice;
+	__max_slice_update(se, node->rb_right);
+	__max_slice_update(se, node->rb_left);
+
 	return se->min_vruntime == old_min_vruntime &&
-	       se->min_slice == old_min_slice;
+	       se->min_slice == old_min_slice &&
+	       se->max_slice == old_max_slice;
 }
 
 RB_DECLARE_CALLBACKS(static, min_vruntime_cb, struct sched_entity,
Signature · 1 line
2.51.0
author maintainer
#30 lore raw

PATCH 26/314 rseq: Clarify rseq registration rseq_size bound check comment

In reply to Sasha Levin

From: Mathieu Desnoyers <[email protected]>

[ Upstream commit 26d43a90be81fc90e26688a51d3ec83188602731 ]

The rseq registration validates that the rseq_size argument is greater or equal to 32 (the original rseq size), but the comment associated with this check does not clearly state this.

Clarify the comment to that effect.

---
 kernel/rseq.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)
kernel/rseq.c +3 -2
index 2452b7366b00e..07b0b46ec640f 100644
@@ -519,8 +519,9 @@ SYSCALL_DEFINE4(rseq, struct rseq __user *, rseq, u32, rseq_len,
 	 * auxiliary vector AT_RSEQ_ALIGN. If rseq_len is the original rseq
 	 * size, the required alignment is the original struct rseq alignment.
 	 *
-	 * In order to be valid, rseq_len is either the original rseq size, or
-	 * large enough to contain all supported fields, as communicated to
+	 * The rseq_len is required to be greater or equal to the original rseq
+	 * size. In order to be valid, rseq_len is either the original rseq size,
+	 * or large enough to contain all supported fields, as communicated to
 	 * user-space through the ELF auxiliary vector AT_RSEQ_FEATURE_SIZE.
 	 */
 	if (rseq_len < ORIG_RSEQ_SIZE ||
Signature · 1 line
2.51.0
author maintainer
#31 lore raw

PATCH 27/314 perf/core: Fix invalid wait context in ctx_sched_in()

In reply to Sasha Levin

From: Namhyung Kim <[email protected]>

[ Upstream commit 486ff5ad49bc50315bcaf6d45f04a33ef0a45ced ]

Lockdep found a bug in the event scheduling when a pinned event was failed and wakes up the threads in the ring buffer like below.

It seems it should not grab a wait-queue lock under perf-context lock. Let's do it with irq_work.

  [   39.913691] =============================
  [   39.914157] [ BUG: Invalid wait context ]
  [   39.914623] 6.15.0-next-20250530-next-2025053 #1 Not tainted
  [   39.915271] -----------------------------
  [   39.915731] repro/837 is trying to lock:
  [   39.916191] ffff88801acfabd8 (&event->waitq){....}-{3:3}, at: __wake_up+0x26/0x60
  [   39.917182] other info that might help us debug this:
  [   39.917761] context-{5:5}
  [   39.918079] 4 locks held by repro/837:
  [   39.918530]  #0: ffffffff8725cd00 (rcu_read_lock){....}-{1:3}, at: __perf_event_task_sched_in+0xd1/0xbc0
  [   39.919612]  #1: ffff88806ca3c6f8 (&cpuctx_lock){....}-{2:2}, at: __perf_event_task_sched_in+0x1a7/0xbc0
  [   39.920748]  #2: ffff88800d91fc18 (&ctx->lock){....}-{2:2}, at: __perf_event_task_sched_in+0x1f9/0xbc0
  [   39.921819]  #3: ffffffff8725cd00 (rcu_read_lock){....}-{1:3}, at: perf_event_wakeup+0x6c/0x470
---
 kernel/events/core.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
kernel/events/core.c +2 -1
index 6889a6bd8a395..0255795191cc8 100644
@@ -4016,7 +4016,8 @@ static int merge_sched_in(struct perf_event *event, void *data)
 			if (*perf_event_fasync(event))
 				event->pending_kill = POLL_ERR;
 
-			perf_event_wakeup(event);
+			event->pending_wakeup = 1;
+			irq_work_queue(&event->pending_irq);
 		} else {
 			struct perf_cpu_pmu_context *cpc = this_cpc(event->pmu_ctx->pmu);
 
Signature · 1 line
2.51.0
author maintainer
#32 lore raw

PATCH 28/314 accel/amdxdna: Remove buffer size check when creating command BO

In reply to Sasha Levin

From: Lizhi Hou <[email protected]>

[ Upstream commit 08fe1b5166fdc81b010d7bf39cd6440620e7931e ]

Large command buffers may be used, and they do not always need to be mapped or accessed by the driver. Performing a size check at command BO creation time unnecessarily rejects valid use cases.

Remove the buffer size check from command BO creation, and defer vmap and size validation to the paths where the driver actually needs to map and access the command buffer.

Fixes ac49797c1815 ("accel/amdxdna: Add GEM buffer object management")
---
 drivers/accel/amdxdna/amdxdna_gem.c | 38 ++++++++++++++---------------
 1 file changed, 19 insertions(+), 19 deletions(-)
drivers/accel/amdxdna/amdxdna_gem.c +19 -19
index 7f91863c3f24c..a1c9cc4a2b9d8 100644
@@ -20,8 +20,6 @@
 #include "amdxdna_pci_drv.h"
 #include "amdxdna_ubuf.h"
 
-#define XDNA_MAX_CMD_BO_SIZE	SZ_32K
-
 MODULE_IMPORT_NS("DMA_BUF");
 
 static int
@@ -745,12 +743,6 @@ amdxdna_drm_create_cmd_bo(struct drm_device *dev,
 {
 	struct amdxdna_dev *xdna = to_xdna_dev(dev);
 	struct amdxdna_gem_obj *abo;
-	int ret;
-
-	if (args->size > XDNA_MAX_CMD_BO_SIZE) {
-		XDNA_ERR(xdna, "Command bo size 0x%llx too large", args->size);
-		return ERR_PTR(-EINVAL);
-	}
 
 	if (args->size < sizeof(struct amdxdna_cmd)) {
 		XDNA_DBG(xdna, "Command BO size 0x%llx too small", args->size);
@@ -764,17 +756,7 @@ amdxdna_drm_create_cmd_bo(struct drm_device *dev,
 	abo->type = AMDXDNA_BO_CMD;
 	abo->client = filp->driver_priv;
 
-	ret = amdxdna_gem_obj_vmap(abo, &abo->mem.kva);
-	if (ret) {
-		XDNA_ERR(xdna, "Vmap cmd bo failed, ret %d", ret);
-		goto release_obj;
-	}
-
 	return abo;
-
-release_obj:
-	drm_gem_object_put(to_gobj(abo));
-	return ERR_PTR(ret);
 }
 
 int amdxdna_drm_create_bo_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
@@ -871,6 +853,7 @@ struct amdxdna_gem_obj *amdxdna_gem_get_obj(struct amdxdna_client *client,
 	struct amdxdna_dev *xdna = client->xdna;
 	struct amdxdna_gem_obj *abo;
 	struct drm_gem_object *gobj;
+	int ret;
 
 	gobj = drm_gem_object_lookup(client->filp, bo_hdl);
 	if (!gobj) {
@@ -879,9 +862,26 @@ struct amdxdna_gem_obj *amdxdna_gem_get_obj(struct amdxdna_client *client,
 	}
 
 	abo = to_xdna_obj(gobj);
-	if (bo_type == AMDXDNA_BO_INVALID || abo->type == bo_type)
+	if (bo_type != AMDXDNA_BO_INVALID && abo->type != bo_type)
+		goto put_obj;
+
+	if (bo_type != AMDXDNA_BO_CMD || abo->mem.kva)
 		return abo;
 
+	if (abo->mem.size > SZ_32K) {
+		XDNA_ERR(xdna, "Cmd bo is too big %ld", abo->mem.size);
+		goto put_obj;
+	}
+
+	ret = amdxdna_gem_obj_vmap(abo, &abo->mem.kva);
+	if (ret) {
+		XDNA_ERR(xdna, "Vmap cmd bo failed, ret %d", ret);
+		goto put_obj;
+	}
+
+	return abo;
+
+put_obj:
 	drm_gem_object_put(gobj);
 	return NULL;
 }
Signature · 1 line
2.51.0
author maintainer
#33 lore raw

PATCH 29/314 accel/amdxdna: Prevent ubuf size overflow

In reply to Sasha Levin

From: Lizhi Hou <[email protected]>

[ Upstream commit 03808abb1d868aed7478a11a82e5bb4b3f1ca6d6 ]

The ubuf size calculation may overflow, resulting in an undersized allocation and possible memory corruption.

Use check_add_overflow() helpers to validate the size calculation before allocation.

Fixes bd72d4acda10 ("accel/amdxdna: Support user space allocated buffer")
---
 drivers/accel/amdxdna/amdxdna_ubuf.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)
drivers/accel/amdxdna/amdxdna_ubuf.c +5 -1
index 9e3b3b055caa8..62a478f6b45fb 100644
@@ -7,6 +7,7 @@
 #include <drm/drm_device.h>
 #include <drm/drm_print.h>
 #include <linux/dma-buf.h>
+#include <linux/overflow.h>
 #include <linux/pagemap.h>
 #include <linux/vmalloc.h>
 
@@ -176,7 +177,10 @@ struct dma_buf *amdxdna_get_ubuf(struct drm_device *dev,
 			goto free_ent;
 		}
 
-		exp_info.size += va_ent[i].len;
+		if (check_add_overflow(exp_info.size, va_ent[i].len, &exp_info.size)) {
+			ret = -EINVAL;
+			goto free_ent;
+		}
 	}
 
 	ubuf->nr_pages = exp_info.size >> PAGE_SHIFT;
Signature · 1 line
2.51.0
author maintainer
#34 lore raw

PATCH 30/314 accel/amdxdna: Validate command buffer payload count

In reply to Sasha Levin

From: Lizhi Hou <[email protected]>

[ Upstream commit 901ec3470994006bc8dd02399e16b675566c3416 ]

The count field in the command header is used to determine the valid payload size. Verify that the valid payload does not exceed the remaining buffer space.

---
 drivers/accel/amdxdna/amdxdna_ctx.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/accel/amdxdna/amdxdna_ctx.c +4 -1
index 856fb25086f12..cfee89681ff3c 100644
@@ -104,7 +104,10 @@ void *amdxdna_cmd_get_payload(struct amdxdna_gem_obj *abo, u32 *size)
 
 	if (size) {
 		count = FIELD_GET(AMDXDNA_CMD_COUNT, cmd->header);
-		if (unlikely(count <= num_masks)) {
+		if (unlikely(count <= num_masks ||
+			     count * sizeof(u32) +
+			     offsetof(struct amdxdna_cmd, data[0]) >
+			     abo->mem.size)) {
 			*size = 0;
 			return NULL;
 		}
Signature · 1 line
2.51.0
author maintainer
#35 lore raw

PATCH 31/314 drm/xe/wa: Steer RMW of MCR registers while building default LRC

In reply to Sasha Levin

From: Matt Roper <[email protected]>

[ Upstream commit 43d37df67f7770d8d261fdcb64ecc8c314e91303 ]

When generating the default LRC, if a register is not masked, we apply any save-restore programming necessary via a read-modify-write sequence that will ensure we only update the relevant bits/fields without clobbering the rest of the register. However some of the registers that need to be updated might be MCR registers which require steering to a non-terminated instance to ensure we can read back a valid, non-zero value. The steering of reads originating from a command streamer is controlled by register CS_MMIO_GROUP_INSTANCE_SELECT. Emit additional MI_LRI commands to update the steering before any RMW of an MCR register to ensure the reads are performed properly.

Note that needing to perform a RMW of an MCR register while building the default LRC is pretty rare. Most of the MCR registers that are part of an engine's LRCs are also masked registers, so no MCR is necessary.

Fixes f2f90989ccff ("drm/xe: Avoid reading RMW registers in emit_wa_job")
Cc Michal Wajdeczko <[email protected]>
(cherry picked from commit 6c2e331c915ba9e774aa847921262805feb00863)
---
 drivers/gpu/drm/xe/regs/xe_engine_regs.h |  6 +++
 drivers/gpu/drm/xe/xe_gt.c               | 66 +++++++++++++++++++-----
 2 files changed, 60 insertions(+), 12 deletions(-)
drivers/gpu/drm/xe/regs/xe_engine_regs.h +6 -0
index f4c3e1187a00a..27fba92301c4e 100644
@@ -96,6 +96,12 @@
 #define   ENABLE_SEMAPHORE_POLL_BIT		REG_BIT(13)
 
 #define RING_CMD_CCTL(base)			XE_REG((base) + 0xc4, XE_REG_OPTION_MASKED)
+
+#define CS_MMIO_GROUP_INSTANCE_SELECT(base)	XE_REG((base) + 0xcc)
+#define   SELECTIVE_READ_ADDRESSING		REG_BIT(30)
+#define   SELECTIVE_READ_GROUP			REG_GENMASK(29, 23)
+#define   SELECTIVE_READ_INSTANCE		REG_GENMASK(22, 16)
+
 /*
  * CMD_CCTL read/write fields take a MOCS value and _not_ a table index.
  * The lsb of each can be considered a separate enabling bit for encryption.
drivers/gpu/drm/xe/xe_gt.c +54 -12

115 lines not on this page · raw message

Signature · 1 line
2.51.0
author maintainer
#36 lore raw

PATCH 32/314 cgroup/cpuset: Fix incorrect use of cpuset_update_tasks_cpumask() in update_cpumasks_hier()

In reply to Sasha Levin

From: Waiman Long <[email protected]>

[ Upstream commit 68230aac8b9aad243626fbaf3ca170012c17fec5 ]

Commit e2ffe502ba45 ("cgroup/cpuset: Add cpuset.cpus.exclusive for v2") incorrectly changed the 2nd parameter of cpuset_update_tasks_cpumask() from tmp->new_cpus to cp->effective_cpus. This second parameter is just a temporary cpumask for internal use. The cpuset_update_tasks_cpumask() function was originally called update_tasks_cpumask() before commit 381b53c3b549 ("cgroup/cpuset: rename functions shared between v1 and v2").

This mistake can incorrectly change the effective_cpus of the cpuset when it is the top_cpuset or in arm64 architecture where task_cpu_possible_mask() may differ from cpu_possible_mask. So far top_cpuset hasn't been passed to update_cpumasks_hier() yet, but arm64 arch can still be impacted. Fix it by reverting the incorrect change.

Fixes e2ffe502ba45 ("cgroup/cpuset: Add cpuset.cpus.exclusive for v2")
---
 kernel/cgroup/cpuset.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/cgroup/cpuset.c +1 -1
index abaa54037918a..08b0c264bd268 100644
@@ -2301,7 +2301,7 @@ static void update_cpumasks_hier(struct cpuset *cs, struct tmpmasks *tmp,
 		WARN_ON(!is_in_v2_mode() &&
 			!cpumask_equal(cp->cpus_allowed, cp->effective_cpus));
 
-		cpuset_update_tasks_cpumask(cp, cp->effective_cpus);
+		cpuset_update_tasks_cpumask(cp, tmp->new_cpus);
 
 		/*
 		 * On default hierarchy, inherit the CS_SCHED_LOAD_BALANCE
Signature · 1 line
2.51.0
author maintainer
#37 lore raw

PATCH 33/314 cxl: Move devm_cxl_add_nvdimm_bridge() to cxl_pmem.ko

In reply to Sasha Levin

From: Dave Jiang <[email protected]>

[ Upstream commit e7e222ad73d93fe54d6e6e3a15253a0ecf081a1b ]

Moving the symbol devm_cxl_add_nvdimm_bridge() to drivers/cxl/cxl_pmem.c, so that cxl_pmem can export a symbol that gives cxl_acpi a depedency on cxl_pmem kernel module. This is a prepatory patch to resolve the issue of a race for nvdimm_bus object that is created during cxl_acpi_probe().

No functional changes besides moving code.

Stable-dep-of: 96a1fd0d84b1 ("cxl: Fix race of nvdimm_bus object when creating nvdimm objects")

---
 drivers/cxl/core/pmem.c | 13 +++----------
 drivers/cxl/cxl.h       |  2 ++
 drivers/cxl/pmem.c      | 14 ++++++++++++++
 3 files changed, 19 insertions(+), 10 deletions(-)
drivers/cxl/core/pmem.c +3 -10
index 8853415c106a9..e1325936183a6 100644
@@ -115,15 +115,8 @@ static void unregister_nvb(void *_cxl_nvb)
 	device_unregister(&cxl_nvb->dev);
 }
 
-/**
- * devm_cxl_add_nvdimm_bridge() - add the root of a LIBNVDIMM topology
- * @host: platform firmware root device
- * @port: CXL port at the root of a CXL topology
- *
- * Return: bridge device that can host cxl_nvdimm objects
- */
-struct cxl_nvdimm_bridge *devm_cxl_add_nvdimm_bridge(struct device *host,
-						     struct cxl_port *port)
+struct cxl_nvdimm_bridge *__devm_cxl_add_nvdimm_bridge(struct device *host,
+						       struct cxl_port *port)
 {
 	struct cxl_nvdimm_bridge *cxl_nvb;
 	struct device *dev;
@@ -155,7 +148,7 @@ struct cxl_nvdimm_bridge *devm_cxl_add_nvdimm_bridge(struct device *host,
 	put_device(dev);
 	return ERR_PTR(rc);
 }
-EXPORT_SYMBOL_NS_GPL(devm_cxl_add_nvdimm_bridge, "CXL");
+EXPORT_SYMBOL_FOR_MODULES(__devm_cxl_add_nvdimm_bridge, "cxl_pmem");
 
 static void cxl_nvdimm_release(struct device *dev)
 {
drivers/cxl/cxl.h +2 -0
index 231ddccf89773..443296da74db1 100644
@@ -866,6 +866,8 @@ void cxl_driver_unregister(struct cxl_driver *cxl_drv);
 struct cxl_nvdimm_bridge *to_cxl_nvdimm_bridge(struct device *dev);
 struct cxl_nvdimm_bridge *devm_cxl_add_nvdimm_bridge(struct device *host,
 						     struct cxl_port *port);
+struct cxl_nvdimm_bridge *__devm_cxl_add_nvdimm_bridge(struct device *host,
+						       struct cxl_port *port);
 struct cxl_nvdimm *to_cxl_nvdimm(struct device *dev);
 bool is_cxl_nvdimm(struct device *dev);
 int devm_cxl_add_nvdimm(struct cxl_port *parent_port, struct cxl_memdev *cxlmd);
drivers/cxl/pmem.c +14 -0
index e197883690efc..714beaf1704be 100644
@@ -13,6 +13,20 @@
 
 static __read_mostly DECLARE_BITMAP(exclusive_cmds, CXL_MEM_COMMAND_ID_MAX);
 
+/**
+ * __devm_cxl_add_nvdimm_bridge() - add the root of a LIBNVDIMM topology
+ * @host: platform firmware root device
+ * @port: CXL port at the root of a CXL topology
+ *
+ * Return: bridge device that can host cxl_nvdimm objects
+ */
+struct cxl_nvdimm_bridge *devm_cxl_add_nvdimm_bridge(struct device *host,
+						     struct cxl_port *port)
+{
+	return __devm_cxl_add_nvdimm_bridge(host, port);
+}
+EXPORT_SYMBOL_NS_GPL(devm_cxl_add_nvdimm_bridge, "CXL");
+
 static void clear_exclusive(void *mds)
 {
 	clear_exclusive_cxl_commands(mds, exclusive_cmds);
Signature · 1 line
2.51.0
author maintainer
#38 lore raw

PATCH 34/314 cxl: Fix race of nvdimm_bus object when creating nvdimm objects

In reply to Sasha Levin

From: Dave Jiang <[email protected]>

[ Upstream commit 96a1fd0d84b17360840f344826897fa71049870e ]

Found issue during running of cxl-translate.sh unit test. Adding a 3s sleep right before the test seems to make the issue reproduce fairly consistently. The cxl_translate module has dependency on cxl_acpi and causes orphaned nvdimm objects to reprobe after cxl_acpi is removed. The nvdimm_bus object is registered by the cxl_nvb object when cxl_acpi_probe() is called. With the nvdimm_bus object missing, __nd_device_register() will trigger NULL pointer dereference when accessing the dev->parent that points to &nvdimm_bus->dev.

[  192.884510] BUG: kernel NULL pointer dereference, address: 000000000000006c
[  192.895383] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS edk2-20250812-19.fc42 08/12/2025
[  192.897721] Workqueue: cxl_port cxl_bus_rescan_queue [cxl_core]
[  192.899459] RIP: 0010:kobject_get+0xc/0x90
[  192.924871] Call Trace:
[  192.925959]  <TASK>
[  192.926976]  ? pm_runtime_init+0xb9/0xe0
[  192.929712]  __nd_device_register.part.0+0x4d/0xc0 [libnvdimm]
[  192.933314]  __nvdimm_create+0x206/0x290 [libnvdimm]
[  192.936662]  cxl_nvdimm_probe+0x119/0x1d0 [cxl_pmem]
[  192.940245]  cxl_bus_probe+0x1a/0x60 [cxl_core]
[  192.943349]  really_probe+0xde/0x380

This patch also relies on the previous change where devm_cxl_add_nvdimm_bridge() is called from drivers/cxl/pmem.c instead of drivers/cxl/core.c to ensure the dependency of cxl_acpi on cxl_pmem.

1. Set probe_type of cxl_nvb to PROBE_FORCE_SYNCHRONOUS to ensure the driver is probed synchronously when add_device() is called.
2. Add a check in __devm_cxl_add_nvdimm_bridge() to ensure that the cxl_nvb driver is attached during cxl_acpi_probe().
3. Take the cxl_root uport_dev lock and the cxl_nvb->dev lock in devm_cxl_add_nvdimm() before checking nvdimm_bus is valid.
4. Set cxl_nvdimm flag to CXL_NVD_F_INVALIDATED so cxl_nvdimm_probe() will exit with -EBUSY.

The removal of cxl_nvdimm devices should prevent any orphaned devices from probing once the nvdimm_bus is gone.

[ dj: Fixed 0-day reported kdoc issue. ]
[ dj: Fix cxl_nvb reference leak on error. Gregory (kreview-0811365) ]

---
 drivers/cxl/core/pmem.c | 29 +++++++++++++++++++++++++++++
 drivers/cxl/cxl.h       |  5 +++++
 drivers/cxl/pmem.c      | 10 ++++++++--
 3 files changed, 42 insertions(+), 2 deletions(-)
drivers/cxl/core/pmem.c +29 -0
index e1325936183a6..e3a8b8d813333 100644
@@ -115,6 +115,15 @@ static void unregister_nvb(void *_cxl_nvb)
 	device_unregister(&cxl_nvb->dev);
 }
 
+static bool cxl_nvdimm_bridge_failed_attach(struct cxl_nvdimm_bridge *cxl_nvb)
+{
+	struct device *dev = &cxl_nvb->dev;
+
+	guard(device)(dev);
+	/* If the device has no driver, then it failed to attach. */
+	return dev->driver == NULL;
+}
+
 struct cxl_nvdimm_bridge *__devm_cxl_add_nvdimm_bridge(struct device *host,
 						       struct cxl_port *port)
 {
@@ -138,6 +147,11 @@ struct cxl_nvdimm_bridge *__devm_cxl_add_nvdimm_bridge(struct device *host,
 	if (rc)
 		goto err;
 
+	if (cxl_nvdimm_bridge_failed_attach(cxl_nvb)) {
+		unregister_nvb(cxl_nvb);
+		return ERR_PTR(-ENODEV);
+	}
+
 	rc = devm_add_action_or_reset(host, unregister_nvb, cxl_nvb);
 	if (rc)
 		return ERR_PTR(rc);
@@ -247,6 +261,21 @@ int devm_cxl_add_nvdimm(struct cxl_port *parent_port,
 	if (!cxl_nvb)
 		return -ENODEV;
 
+	/*
+	 * Take the uport_dev lock to guard against race of nvdimm_bus object.
+	 * cxl_acpi_probe() registers the nvdimm_bus and is done under the
+	 * root port uport_dev lock.
+	 *
+	 * Take the cxl_nvb device lock to ensure that cxl_nvb driver is in a
+	 * consistent state. And the driver registers nvdimm_bus.
+	 */
+	guard(device)(cxl_nvb->port->uport_dev);
+	guard(device)(&cxl_nvb->dev);
+	if (!cxl_nvb->nvdimm_bus) {
+		rc = -ENODEV;
+		goto err_alloc;
+	}
+
 	cxl_nvd = cxl_nvdimm_alloc(cxl_nvb, cxlmd);
 	if (IS_ERR(cxl_nvd)) {
 		rc = PTR_ERR(cxl_nvd);
drivers/cxl/cxl.h +5 -0
index 443296da74db1..3a794278cc7fe 100644
@@ -555,11 +555,16 @@ struct cxl_nvdimm_bridge {
 
 #define CXL_DEV_ID_LEN 19
 
+enum {
+	CXL_NVD_F_INVALIDATED = 0,
+};
+
 struct cxl_nvdimm {
 	struct device dev;
 	struct cxl_memdev *cxlmd;
 	u8 dev_id[CXL_DEV_ID_LEN]; /* for nvdimm, string of 'serial' */
 	u64 dirty_shutdowns;
+	unsigned long flags;
 };
 
 struct cxl_pmem_region_mapping {
drivers/cxl/pmem.c +8 -2
index 714beaf1704be..c00b84b960761 100644
@@ -14,7 +14,7 @@
 static __read_mostly DECLARE_BITMAP(exclusive_cmds, CXL_MEM_COMMAND_ID_MAX);
 
 /**
- * __devm_cxl_add_nvdimm_bridge() - add the root of a LIBNVDIMM topology
+ * devm_cxl_add_nvdimm_bridge() - add the root of a LIBNVDIMM topology
  * @host: platform firmware root device
  * @port: CXL port at the root of a CXL topology
  *
@@ -143,6 +143,9 @@ static int cxl_nvdimm_probe(struct device *dev)
 	struct nvdimm *nvdimm;
 	int rc;
 
+	if (test_bit(CXL_NVD_F_INVALIDATED, &cxl_nvd->flags))
+		return -EBUSY;
+
 	set_exclusive_cxl_commands(mds, exclusive_cmds);
 	rc = devm_add_action_or_reset(dev, clear_exclusive, mds);
 	if (rc)
@@ -323,8 +326,10 @@ static int detach_nvdimm(struct device *dev, void *data)
 	scoped_guard(device, dev) {
 		if (dev->driver) {
 			cxl_nvd = to_cxl_nvdimm(dev);
-			if (cxl_nvd->cxlmd && cxl_nvd->cxlmd->cxl_nvb == data)
+			if (cxl_nvd->cxlmd && cxl_nvd->cxlmd->cxl_nvb == data) {
 				release = true;
+				set_bit(CXL_NVD_F_INVALIDATED, &cxl_nvd->flags);
+			}
 		}
 	}
 	if (release)
@@ -367,6 +372,7 @@ static struct cxl_driver cxl_nvdimm_bridge_driver = {
 	.probe = cxl_nvdimm_bridge_probe,
 	.id = CXL_DEVICE_NVDIMM_BRIDGE,
 	.drv = {
+		.probe_type = PROBE_FORCE_SYNCHRONOUS,
 		.suppress_bind_attrs = true,
 	},
 };
Signature · 1 line
2.51.0
author maintainer
#39 lore raw

PATCH 35/314 scsi: ufs: core: Move link recovery for hibern8 exit failure to wl_resume

In reply to Sasha Levin

From: Peter Wang <[email protected]>

[ Upstream commit 62c015373e1cdb1cdca824bd2dbce2dac0819467 ]

Move the link recovery trigger from ufshcd_uic_pwr_ctrl() to __ufshcd_wl_resume(). Ensure link recovery is only attempted when hibern8 exit fails during resume, not during hibern8 enter in suspend. Improve error handling and prevent unnecessary link recovery attempts.

Fixes 35dabf4503b9 ("scsi: ufs: core: Use link recovery when h8 exit fails during runtime resume")
---
 drivers/ufs/core/ufshcd.c | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)
drivers/ufs/core/ufshcd.c +9 -9
index 755aa9c0017df..dae23ec4fcea8 100644
@@ -4401,14 +4401,6 @@ static int ufshcd_uic_pwr_ctrl(struct ufs_hba *hba, struct uic_command *cmd)
 	spin_unlock_irqrestore(hba->host->host_lock, flags);
 	mutex_unlock(&hba->uic_cmd_mutex);
 
-	/*
-	 * If the h8 exit fails during the runtime resume process, it becomes
-	 * stuck and cannot be recovered through the error handler.  To fix
-	 * this, use link recovery instead of the error handler.
-	 */
-	if (ret && hba->pm_op_in_progress)
-		ret = ufshcd_link_recovery(hba);
-
 	return ret;
 }
 
@@ -10058,7 +10050,15 @@ static int __ufshcd_wl_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)
 		} else {
 			dev_err(hba->dev, "%s: hibern8 exit failed %d\n",
 					__func__, ret);
-			goto vendor_suspend;
+			/*
+			 * If the h8 exit fails during the runtime resume
+			 * process, it becomes stuck and cannot be recovered
+			 * through the error handler. To fix this, use link
+			 * recovery instead of the error handler.
+			 */
+			ret = ufshcd_link_recovery(hba);
+			if (ret)
+				goto vendor_suspend;
 		}
 	} else if (ufshcd_is_link_off(hba)) {
 		/*
Signature · 1 line
2.51.0
author maintainer
#40 lore raw

PATCH 36/314 regulator: bq257xx: Fix device node reference leak in bq257xx_reg_dt_parse_gpio()

In reply to Sasha Levin

From: Felix Gu <[email protected]>

[ Upstream commit 4baaddaa44af01cd4ce239493060738fd0881835 ]

In bq257xx_reg_dt_parse_gpio(), if fails to get subchild, it returns without calling of_node_put(child), causing the device node reference leak.

Fixes 981dd162b635 ("regulator: bq257xx: Add bq257xx boost regulator driver")
---
 drivers/regulator/bq257xx-regulator.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/regulator/bq257xx-regulator.c +1 -2
index fc1ccede44688..dab8f1ab44503 100644
@@ -115,11 +115,10 @@ static void bq257xx_reg_dt_parse_gpio(struct platform_device *pdev)
 		return;
 
 	subchild = of_get_child_by_name(child, pdata->desc.of_match);
+	of_node_put(child);
 	if (!subchild)
 		return;
 
-	of_node_put(child);
-
 	pdata->otg_en_gpio = devm_fwnode_gpiod_get_index(&pdev->dev,
 							 of_fwnode_handle(subchild),
 							 "enable", 0,
Signature · 1 line
2.51.0
author maintainer
#41 lore raw

PATCH 37/314 zloop: advertise a volatile write cache

In reply to Sasha Levin

From: Christoph Hellwig <[email protected]>

[ Upstream commit 6acf7860dcc79ed045cc9e6a79c8a8bb6959dba7 ]

Zloop is file system backed and thus needs to sync the underlying file system to persist data. Set BLK_FEAT_WRITE_CACHE so that the block layer actually send flush commands, and fix the flush implementation as sync_filesystem requires s_umount to be held and the code currently misses that.

Fixes eb0570c7df23 ("block: new zoned loop block device driver")
---
 drivers/block/zloop.c | 24 ++++++++++++++++++------
 1 file changed, 18 insertions(+), 6 deletions(-)
drivers/block/zloop.c +18 -6
index 39a425db670c8..2419677524453 100644
@@ -499,6 +499,21 @@ static void zloop_rw(struct zloop_cmd *cmd)
 	zloop_put_cmd(cmd);
 }
 
+/*
+ * Sync the entire FS containing the zone files instead of walking all files.
+ */
+static int zloop_flush(struct zloop_device *zlo)
+{
+	struct super_block *sb = file_inode(zlo->data_dir)->i_sb;
+	int ret;
+
+	down_read(&sb->s_umount);
+	ret = sync_filesystem(sb);
+	up_read(&sb->s_umount);
+
+	return ret;
+}
+
 static void zloop_handle_cmd(struct zloop_cmd *cmd)
 {
 	struct request *rq = blk_mq_rq_from_pdu(cmd);
@@ -515,11 +530,7 @@ static void zloop_handle_cmd(struct zloop_cmd *cmd)
 		zloop_rw(cmd);
 		return;
 	case REQ_OP_FLUSH:
-		/*
-		 * Sync the entire FS containing the zone files instead of
-		 * walking all files
-		 */
-		cmd->ret = sync_filesystem(file_inode(zlo->data_dir)->i_sb);
+		cmd->ret = zloop_flush(zlo);
 		break;
 	case REQ_OP_ZONE_RESET:
 		cmd->ret = zloop_reset_zone(zlo, rq_zone_no(rq));
@@ -892,7 +903,8 @@ static int zloop_ctl_add(struct zloop_options *opts)
 		.max_hw_sectors		= SZ_1M >> SECTOR_SHIFT,
 		.max_hw_zone_append_sectors = SZ_1M >> SECTOR_SHIFT,
 		.chunk_sectors		= opts->zone_size,
-		.features		= BLK_FEAT_ZONED,
+		.features		= BLK_FEAT_ZONED | BLK_FEAT_WRITE_CACHE,
+
 	};
 	unsigned int nr_zones, i, j;
 	struct zloop_device *zlo;
Signature · 1 line
2.51.0
author maintainer
#42 lore raw

PATCH 38/314 zloop: check for spurious options passed to remove

In reply to Sasha Levin

From: Christoph Hellwig <[email protected]>

[ Upstream commit 3c4617117a2b7682cf037be5e5533e379707f050 ]

Zloop uses a command option parser for all control commands, but most options are only valid for adding a new device. Check for incorrectly specified options in the remove handler.

Fixes eb0570c7df23 ("block: new zoned loop block device driver")
---
 drivers/block/zloop.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)
drivers/block/zloop.c +6 -1
index 2419677524453..26364e43aeb34 100644
@@ -1076,7 +1076,12 @@ static int zloop_ctl_remove(struct zloop_options *opts)
 	int ret;
 
 	if (!(opts->mask & ZLOOP_OPT_ID)) {
-		pr_err("No ID specified\n");
+		pr_err("No ID specified for remove\n");
+		return -EINVAL;
+	}
+
+	if (opts->mask & ~ZLOOP_OPT_ID) {
+		pr_err("Invalid option specified for remove\n");
 		return -EINVAL;
 	}
 
Signature · 1 line
2.51.0
author maintainer
#43 lore raw

PATCH 39/314 drm/client: Do not destroy NULL modes

In reply to Sasha Levin

From: Jonathan Cavitt <[email protected]>

[ Upstream commit c601fd5414315fc515f746b499110e46272e7243 ]

'modes' in drm_client_modeset_probe may fail to kcalloc. If this occurs, we jump to 'out', calling modes_destroy on it, which dereferences it. This may result in a NULL pointer dereference in the error case. Prevent that.

Fixes 3039cc0c0653 ("drm/client: Make copies of modes")
Cc Ville Syrjälä <[email protected]>
---
 drivers/gpu/drm/drm_client_modeset.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/gpu/drm/drm_client_modeset.c +2 -1
index 9c2c3b0c8c470..eaf71c9ecf136 100644
@@ -930,7 +930,8 @@ int drm_client_modeset_probe(struct drm_client_dev *client, unsigned int width,
 	mutex_unlock(&client->modeset_mutex);
 out:
 	kfree(crtcs);
-	modes_destroy(dev, modes, connector_count);
+	if (modes)
+		modes_destroy(dev, modes, connector_count);
 	kfree(modes);
 	kfree(offsets);
 	kfree(enabled);
Signature · 1 line
2.51.0
author maintainer
#44 lore raw

PATCH 40/314 ALSA: usb-audio: Cap the packet size pre-calculations

In reply to Sasha Levin

From: Takashi Iwai <[email protected]>

[ Upstream commit 7fe8dec3f628e9779f1631576f8e693370050348 ]

We calculate the possible packet sizes beforehand for adaptive and synchronous endpoints, but we didn't take care of the max frame size for those pre-calculated values. When a device or a bus limits the packet size, a high sample rate or a high number of channels may lead to the packet sizes that are larger than the given limit, which results in an error from the USB core at submitting URBs.

As a simple workaround, just add the sanity checks of pre-calculated packet sizes to have the upper boundary of ep->maxframesize.

---
 sound/usb/endpoint.c | 3 +++
 1 file changed, 3 insertions(+)
sound/usb/endpoint.c +3 -0
index 3ac1fbec6327e..173edce027d7b 100644
@@ -1374,6 +1374,9 @@ int snd_usb_endpoint_set_params(struct snd_usb_audio *chip,
 		return -EINVAL;
 	}
 
+	ep->packsize[0] = min(ep->packsize[0], ep->maxframesize);
+	ep->packsize[1] = min(ep->packsize[1], ep->maxframesize);
+
 	/* calculate the frequency in 16.16 format */
 	ep->freqm = ep->freqn;
 	ep->freqshift = INT_MIN;
Signature · 1 line
2.51.0
author maintainer
#45 lore raw

PATCH 41/314 ALSA: usb-audio: Use inclusive terms

In reply to Sasha Levin

From: Takashi Iwai <[email protected]>

[ Upstream commit 4e9113c533acee2ba1f72fd68ee6ecd36b64484e ]

Replace the remaining with inclusive terms; it's only this function name we overlooked at the previous conversion.

Fixes 53837b4ac2bd ("ALSA: usb-audio: Replace slave/master terms")
---
 sound/usb/endpoint.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)
sound/usb/endpoint.c +3 -3
index 173edce027d7b..eff3329d86b7e 100644
@@ -160,8 +160,8 @@ int snd_usb_endpoint_implicit_feedback_sink(struct snd_usb_endpoint *ep)
  * This won't be used for implicit feedback which takes the packet size
  * returned from the sync source
  */
-static int slave_next_packet_size(struct snd_usb_endpoint *ep,
-				  unsigned int avail)
+static int synced_next_packet_size(struct snd_usb_endpoint *ep,
+				   unsigned int avail)
 {
 	unsigned int phase;
 	int ret;
@@ -227,7 +227,7 @@ int snd_usb_endpoint_next_packet_size(struct snd_usb_endpoint *ep,
 	}
 
 	if (ep->sync_source)
-		return slave_next_packet_size(ep, avail);
+		return synced_next_packet_size(ep, avail);
 	else
 		return next_packet_size(ep, avail);
 }
Signature · 1 line
2.51.0
author maintainer
#46 lore raw

PATCH 42/314 perf: Fix __perf_event_overflow() vs perf_remove_from_context() race

In reply to Sasha Levin

From: Peter Zijlstra <[email protected]>

[ Upstream commit c9bc1753b3cc41d0e01fbca7f035258b5f4db0ae ]

Make sure that __perf_event_overflow() runs with IRQs disabled for all possible callchains. Specifically the software events can end up running it with only preemption disabled.

This opens up a race vs perf_event_exit_event() and friends that will go and free various things the overflow path expects to be present, like the BPF program.

---
 kernel/events/core.c | 42 +++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 41 insertions(+), 1 deletion(-)
kernel/events/core.c +41 -1
index 0255795191cc8..b7e73ac3e512f 100644
@@ -10427,6 +10427,13 @@ int perf_event_overflow(struct perf_event *event,
 			struct perf_sample_data *data,
 			struct pt_regs *regs)
 {
+	/*
+	 * Entry point from hardware PMI, interrupts should be disabled here.
+	 * This serializes us against perf_event_remove_from_context() in
+	 * things like perf_event_release_kernel().
+	 */
+	lockdep_assert_irqs_disabled();
+
 	return __perf_event_overflow(event, 1, data, regs);
 }
 
@@ -10503,6 +10510,19 @@ static void perf_swevent_event(struct perf_event *event, u64 nr,
 {
 	struct hw_perf_event *hwc = &event->hw;
 
+	/*
+	 * This is:
+	 *   - software		preempt
+	 *   - tracepoint	preempt
+	 *   -   tp_target_task	irq (ctx->lock)
+	 *   - uprobes		preempt/irq
+	 *   - kprobes		preempt/irq
+	 *   - hw_breakpoint	irq
+	 *
+	 * Any of these are sufficient to hold off RCU and thus ensure @event
+	 * exists.
+	 */
+	lockdep_assert_preemption_disabled();
 	local64_add(nr, &event->count);
 
 	if (!regs)
@@ -10511,6 +10531,16 @@ static void perf_swevent_event(struct perf_event *event, u64 nr,
 	if (!is_sampling_event(event))
 		return;
 
+	/*
+	 * Serialize against event_function_call() IPIs like normal overflow
+	 * event handling. Specifically, must not allow
+	 * perf_event_release_kernel() -> perf_remove_from_context() to make
+	 * progress and 'release' the event from under us.
+	 */
+	guard(irqsave)();
+	if (event->state != PERF_EVENT_STATE_ACTIVE)
+		return;
+
 	if ((event->attr.sample_type & PERF_SAMPLE_PERIOD) && !event->attr.freq) {
 		data->period = nr;
 		return perf_swevent_overflow(event, 1, data, regs);
@@ -11009,6 +11039,11 @@ void perf_tp_event(u16 event_type, u64 count, void *record, int entry_size,
 	struct perf_sample_data data;
 	struct perf_event *event;
 
+	/*
+	 * Per being a tracepoint, this runs with preemption disabled.
+	 */
+	lockdep_assert_preemption_disabled();
+
 	struct perf_raw_record raw = {
 		.frag = {
 			.size = entry_size,
@@ -11341,6 +11376,11 @@ void perf_bp_event(struct perf_event *bp, void *data)
 	struct perf_sample_data sample;
 	struct pt_regs *regs = data;
 
+	/*
+	 * Exception context, will have interrupts disabled.
+	 */
+	lockdep_assert_irqs_disabled();
+
 	perf_sample_data_init(&sample, bp->attr.bp_addr, 0);
 
 	if (!bp->hw.state && !perf_exclude_event(bp, regs))
@@ -11805,7 +11845,7 @@ static enum hrtimer_restart perf_swevent_hrtimer(struct hrtimer *hrtimer)
 
 	if (regs && !perf_exclude_event(event, regs)) {
 		if (!(event->attr.exclude_idle && is_idle_task(current)))
-			if (__perf_event_overflow(event, 1, &data, regs))
+			if (perf_event_overflow(event, &data, regs))
 				ret = HRTIMER_NORESTART;
 	}
 
Signature · 1 line
2.51.0
author maintainer
#47 lore raw

PATCH 43/314 s390/idle: Fix cpu idle exit cpu time accounting

In reply to Sasha Levin

From: Heiko Carstens <[email protected]>

[ Upstream commit 0d785e2c324c90662baa4fe07a0d02233ff92824 ]

With the conversion to generic entry [1] cpu idle exit cpu time accounting was converted from assembly to C. This introduced an reversed order of cpu time accounting.

On cpu idle exit the current accounting happens with the following call chain:

-> do_io_irq()/do_ext_irq()
-> irq_enter_rcu()
-> account_hardirq_enter()
-> vtime_account_irq()

    -> vtime_account_kernel()

vtime_account_kernel() accounts the passed cpu time since last_update_timer as system time, and updates last_update_timer to the current cpu timer value.

However the subsequent call of

-> account_idle_time_irq()

will incorrectly subtract passed cpu time from timer_idle_enter to the updated last_update_timer value from system_timer. Then last_update_timer is updated to a sys_enter_timer, which means that last_update_timer goes back in time.

Subsequently account_hardirq_exit() will account too much cpu time as hardirq time. The sum of all accounted cpu times is still correct, however some cpu time which was previously accounted as system time is now accounted as hardirq time, plus there is the oddity that last_update_timer goes back in time.

Restore previous behavior by extracting cpu time accounting code from account_idle_time_irq() into a new update_timer_idle() function and call it before irq_enter_rcu().

Fixes 56e62a737028 ("s390: convert to generic entry") [1]
---
 arch/s390/include/asm/idle.h |  1 +
 arch/s390/kernel/idle.c      | 13 +++++++++----
 arch/s390/kernel/irq.c       | 10 ++++++++--
 3 files changed, 18 insertions(+), 6 deletions(-)
arch/s390/include/asm/idle.h +1 -0
index 09f763b9eb40a..133059d9a949c 100644
@@ -23,5 +23,6 @@ extern struct device_attribute dev_attr_idle_count;
 extern struct device_attribute dev_attr_idle_time_us;
 
 void psw_idle(struct s390_idle_data *data, unsigned long psw_mask);
+void update_timer_idle(void);
 
 #endif /* _S390_IDLE_H */
arch/s390/kernel/idle.c +9 -4
index 39cb8d0ae3480..0f9e53f0a0686 100644
@@ -21,11 +21,10 @@
 
 static DEFINE_PER_CPU(struct s390_idle_data, s390_idle);
 
-void account_idle_time_irq(void)
+void update_timer_idle(void)
 {
 	struct s390_idle_data *idle = this_cpu_ptr(&s390_idle);
 	struct lowcore *lc = get_lowcore();
-	unsigned long idle_time;
 	u64 cycles_new[8];
 	int i;
 
@@ -35,13 +34,19 @@ void account_idle_time_irq(void)
 			this_cpu_add(mt_cycles[i], cycles_new[i] - idle->mt_cycles_enter[i]);
 	}
 
-	idle_time = lc->int_clock - idle->clock_idle_enter;
-
 	lc->steal_timer += idle->clock_idle_enter - lc->last_update_clock;
 	lc->last_update_clock = lc->int_clock;
 
 	lc->system_timer += lc->last_update_timer - idle->timer_idle_enter;
 	lc->last_update_timer = lc->sys_enter_timer;
+}
+
+void account_idle_time_irq(void)
+{
+	struct s390_idle_data *idle = this_cpu_ptr(&s390_idle);
+	unsigned long idle_time;
+
+	idle_time = get_lowcore()->int_clock - idle->clock_idle_enter;
 
 	/* Account time spent with enabled wait psw loaded as idle time. */
 	WRITE_ONCE(idle->idle_time, READ_ONCE(idle->idle_time) + idle_time);
arch/s390/kernel/irq.c +8 -2
index bdf9c7cb5685b..080e9285b3379 100644
@@ -146,6 +146,10 @@ void noinstr do_io_irq(struct pt_regs *regs)
 	struct pt_regs *old_regs = set_irq_regs(regs);
 	bool from_idle;
 
+	from_idle = test_and_clear_cpu_flag(CIF_ENABLED_WAIT);
+	if (from_idle)
+		update_timer_idle();
+
 	irq_enter_rcu();
 
 	if (user_mode(regs)) {
@@ -154,7 +158,6 @@ void noinstr do_io_irq(struct pt_regs *regs)
 			current->thread.last_break = regs->last_break;
 	}
 
-	from_idle = test_and_clear_cpu_flag(CIF_ENABLED_WAIT);
 	if (from_idle)
 		account_idle_time_irq();
 
@@ -182,6 +185,10 @@ void noinstr do_ext_irq(struct pt_regs *regs)
 	struct pt_regs *old_regs = set_irq_regs(regs);
 	bool from_idle;
 
+	from_idle = test_and_clear_cpu_flag(CIF_ENABLED_WAIT);
+	if (from_idle)
+		update_timer_idle();
+
 	irq_enter_rcu();
 
 	if (user_mode(regs)) {
@@ -194,7 +201,6 @@ void noinstr do_ext_irq(struct pt_regs *regs)
 	regs->int_parm = get_lowcore()->ext_params;
 	regs->int_parm_long = get_lowcore()->ext_params2;
 
-	from_idle = test_and_clear_cpu_flag(CIF_ENABLED_WAIT);
 	if (from_idle)
 		account_idle_time_irq();
 
Signature · 1 line
2.51.0
author maintainer
#48 lore raw

PATCH 44/314 s390/vtime: Fix virtual timer forwarding

In reply to Sasha Levin

From: Heiko Carstens <[email protected]>

[ Upstream commit dbc0fb35679ed5d0adecf7d02137ac2c77244b3b ]

Since delayed accounting of system time [1] the virtual timer is forwarded by do_account_vtime() but also vtime_account_kernel(), vtime_account_softirq(), and vtime_account_hardirq(). This leads to double accounting of system, guest, softirq, and hardirq time.

Remove accounting from the vtime_account*() family to restore old behavior.

There is only one user of the vtimer interface, which might explain why nobody noticed this so far.

Fixes b7394a5f4ce9 ("sched/cputime, s390: Implement delayed accounting of system time") [1]
---
 arch/s390/kernel/vtime.c | 18 ++----------------
 1 file changed, 2 insertions(+), 16 deletions(-)
arch/s390/kernel/vtime.c +2 -16
index 234a0ba305108..122d30b104401 100644
@@ -225,10 +225,6 @@ static u64 vtime_delta(void)
 	return timer - lc->last_update_timer;
 }
 
-/*
- * Update process times based on virtual cpu times stored by entry.S
- * to the lowcore fields user_timer, system_timer & steal_clock.
- */
 void vtime_account_kernel(struct task_struct *tsk)
 {
 	struct lowcore *lc = get_lowcore();
@@ -238,27 +234,17 @@ void vtime_account_kernel(struct task_struct *tsk)
 		lc->guest_timer += delta;
 	else
 		lc->system_timer += delta;
-
-	virt_timer_forward(delta);
 }
 EXPORT_SYMBOL_GPL(vtime_account_kernel);
 
 void vtime_account_softirq(struct task_struct *tsk)
 {
-	u64 delta = vtime_delta();
-
-	get_lowcore()->softirq_timer += delta;
-
-	virt_timer_forward(delta);
+	get_lowcore()->softirq_timer += vtime_delta();
 }
 
 void vtime_account_hardirq(struct task_struct *tsk)
 {
-	u64 delta = vtime_delta();
-
-	get_lowcore()->hardirq_timer += delta;
-
-	virt_timer_forward(delta);
+	get_lowcore()->hardirq_timer += vtime_delta();
 }
 
 /*
Signature · 1 line
2.51.0
author maintainer
#49 lore raw

PATCH 45/314 arm64: io: Rename ioremap_prot() to __ioremap_prot()

In reply to Sasha Levin

From: Will Deacon <[email protected]>

[ Upstream commit f6bf47ab32e0863df50f5501d207dcdddb7fc507 ]

Rename our ioremap_prot() implementation to __ioremap_prot() and convert all arch-internal callers over to the new function.

ioremap_prot() remains as a #define to __ioremap_prot() for generic_access_phys() and will be subsequently extended to handle user permissions in 'prot'.

Stable-dep-of: 8f098037139b ("arm64: io: Extract user memory type in ioremap_prot()")

---
 arch/arm64/include/asm/io.h | 11 ++++++-----
 arch/arm64/kernel/acpi.c    |  2 +-
 arch/arm64/mm/ioremap.c     |  6 +++---
 3 files changed, 10 insertions(+), 9 deletions(-)
arch/arm64/include/asm/io.h +6 -5
index 83e03abbb2ca9..cd2fddfe814ac 100644
@@ -264,19 +264,20 @@ __iowrite64_copy(void __iomem *to, const void *from, size_t count)
 typedef int (*ioremap_prot_hook_t)(phys_addr_t phys_addr, size_t size,
 				   pgprot_t *prot);
 int arm64_ioremap_prot_hook_register(const ioremap_prot_hook_t hook);
+void __iomem *__ioremap_prot(phys_addr_t phys, size_t size, pgprot_t prot);
 
-#define ioremap_prot ioremap_prot
+#define ioremap_prot __ioremap_prot
 
 #define _PAGE_IOREMAP PROT_DEVICE_nGnRE
 
 #define ioremap_wc(addr, size)	\
-	ioremap_prot((addr), (size), __pgprot(PROT_NORMAL_NC))
+	__ioremap_prot((addr), (size), __pgprot(PROT_NORMAL_NC))
 #define ioremap_np(addr, size)	\
-	ioremap_prot((addr), (size), __pgprot(PROT_DEVICE_nGnRnE))
+	__ioremap_prot((addr), (size), __pgprot(PROT_DEVICE_nGnRnE))
 
 
 #define ioremap_encrypted(addr, size)	\
-	ioremap_prot((addr), (size), PAGE_KERNEL)
+	__ioremap_prot((addr), (size), PAGE_KERNEL)
 
 /*
  * io{read,write}{16,32,64}be() macros
@@ -297,7 +298,7 @@ static inline void __iomem *ioremap_cache(phys_addr_t addr, size_t size)
 	if (pfn_is_map_memory(__phys_to_pfn(addr)))
 		return (void __iomem *)__phys_to_virt(addr);
 
-	return ioremap_prot(addr, size, __pgprot(PROT_NORMAL));
+	return __ioremap_prot(addr, size, __pgprot(PROT_NORMAL));
 }
 
 /*
arch/arm64/kernel/acpi.c +1 -1
index f1cb2447afc9c..b285e174f4f51 100644
@@ -377,7 +377,7 @@ void __iomem *acpi_os_ioremap(acpi_physical_address phys, acpi_size size)
 				prot = __acpi_get_writethrough_mem_attribute();
 		}
 	}
-	return ioremap_prot(phys, size, prot);
+	return __ioremap_prot(phys, size, prot);
 }
 
 /*
arch/arm64/mm/ioremap.c +3 -3
index 10e246f112710..1e4794a2af7d6 100644
@@ -14,8 +14,8 @@ int arm64_ioremap_prot_hook_register(ioremap_prot_hook_t hook)
 	return 0;
 }
 
-void __iomem *ioremap_prot(phys_addr_t phys_addr, size_t size,
-			   pgprot_t pgprot)
+void __iomem *__ioremap_prot(phys_addr_t phys_addr, size_t size,
+			     pgprot_t pgprot)
 {
 	unsigned long last_addr = phys_addr + size - 1;
 
@@ -38,7 +38,7 @@ void __iomem *ioremap_prot(phys_addr_t phys_addr, size_t size,
 
 	return generic_ioremap_prot(phys_addr, size, pgprot);
 }
-EXPORT_SYMBOL(ioremap_prot);
+EXPORT_SYMBOL(__ioremap_prot);
 
 /*
  * Must be called after early_fixmap_init
Signature · 1 line
2.51.0
author maintainer
#50 lore raw

PATCH 46/314 arm64: io: Extract user memory type in ioremap_prot()

In reply to Sasha Levin

From: Will Deacon <[email protected]>

[ Upstream commit 8f098037139b294050053123ab2bc0f819d08932 ]

The only caller of ioremap_prot() outside of the generic ioremap() implementation is generic_access_phys(), which passes a 'pgprot_t' value determined from the user mapping of the target 'pfn' being accessed by the kernel. On arm64, the 'pgprot_t' contains all of the non-address bits from the pte, including the permission controls, and so we end up returning a new user mapping from ioremap_prot() which faults when accessed from the kernel on systems with PAN:

  | Unable to handle kernel read from unreadable memory at virtual address ffff80008ea89000
  | ...
  | Call trace:
  |   __memcpy_fromio+0x80/0xf8
  |   generic_access_phys+0x20c/0x2b8
  |   __access_remote_vm+0x46c/0x5b8
  |   access_remote_vm+0x18/0x30
  |   environ_read+0x238/0x3e8
  |   vfs_read+0xe4/0x2b0
  |   ksys_read+0xcc/0x178
  |   __arm64_sys_read+0x4c/0x68

Extract only the memory type from the user 'pgprot_t' in ioremap_prot() and assert that we're being passed a user mapping, to protect us against any changes in future that may require additional handling. To avoid falsely flagging users of ioremap(), provide our own ioremap() macro which simply wraps __ioremap_prot().

Cc Zeng Heng <[email protected]>
Cc Jinjiang Tu <[email protected]>
Cc Catalin Marinas <[email protected]>
Fixes 893dea9ccd08 ("arm64: Add HAVE_IOREMAP_PROT support")
---
 arch/arm64/include/asm/io.h | 17 +++++++++++++++--
 1 file changed, 15 insertions(+), 2 deletions(-)
arch/arm64/include/asm/io.h +15 -2
index cd2fddfe814ac..8cbd1e96fd50b 100644
@@ -266,10 +266,23 @@ typedef int (*ioremap_prot_hook_t)(phys_addr_t phys_addr, size_t size,
 int arm64_ioremap_prot_hook_register(const ioremap_prot_hook_t hook);
 void __iomem *__ioremap_prot(phys_addr_t phys, size_t size, pgprot_t prot);
 
-#define ioremap_prot __ioremap_prot
+static inline void __iomem *ioremap_prot(phys_addr_t phys, size_t size,
+					 pgprot_t user_prot)
+{
+	pgprot_t prot;
+	ptdesc_t user_prot_val = pgprot_val(user_prot);
+
+	if (WARN_ON_ONCE(!(user_prot_val & PTE_USER)))
+		return NULL;
 
-#define _PAGE_IOREMAP PROT_DEVICE_nGnRE
+	prot = __pgprot_modify(PAGE_KERNEL, PTE_ATTRINDX_MASK,
+			       user_prot_val & PTE_ATTRINDX_MASK);
+	return __ioremap_prot(phys, size, prot);
+}
+#define ioremap_prot ioremap_prot
 
+#define ioremap(addr, size)	\
+	__ioremap_prot((addr), (size), __pgprot(PROT_DEVICE_nGnRE))
 #define ioremap_wc(addr, size)	\
 	__ioremap_prot((addr), (size), __pgprot(PROT_NORMAL_NC))
 #define ioremap_np(addr, size)	\
Signature · 1 line
2.51.0
author maintainer
#51 lore raw

PATCH 47/314 PCI: dwc: ep: Flush MSI-X write before unmapping its ATU entry

In reply to Sasha Levin

From: Niklas Cassel <[email protected]>

[ Upstream commit c22533c66ccae10511ad6a7afc34bb26c47577e3 ]

Endpoint drivers use dw_pcie_ep_raise_msix_irq() to raise an MSI-X interrupt to the host using a writel(), which generates a PCI posted write transaction. There's no completion for posted writes, so the writel() may return before the PCI write completes. dw_pcie_ep_raise_msix_irq() also unmaps the outbound ATU entry used for the PCI write, so the write races with the unmap.

If the PCI write loses the race with the ATU unmap, the write may corrupt host memory or cause IOMMU errors, e.g., these when running fio with a larger queue depth against nvmet-pci-epf:

  arm-smmu-v3 fc900000.iommu:      0x0000010000000010
  arm-smmu-v3 fc900000.iommu:      0x0000020000000000
  arm-smmu-v3 fc900000.iommu:      0x000000090000f040
  arm-smmu-v3 fc900000.iommu:      0x0000000000000000

arm-smmu-v3 fc900000.iommu: event: F_TRANSLATION client: 0000:01:00.0 sid: 0x100 ssid: 0x0 iova: 0x90000f040 ipa: 0x0 arm-smmu-v3 fc900000.iommu: unpriv data write s1 "Input address caused fault" stag: 0x0

Flush the write by performing a readl() of the same address to ensure that the write has reached the destination before the ATU entry is unmapped.

The same problem was solved for dw_pcie_ep_raise_msi_irq() in commit 8719c64e76bf ("PCI: dwc: ep: Cache MSI outbound iATU mapping"), but there it was solved by dedicating an outbound iATU only for MSI. We can't do the same for MSI-X because each vector can have a different msg_addr and the msg_addr may be changed while the vector is masked.

Fixes beb4641a787d ("PCI: dwc: Add MSI-X callbacks handler")
[bhelgaas: commit log]
---
 drivers/pci/controller/dwc/pcie-designware-ep.c | 3 +++
 1 file changed, 3 insertions(+)
drivers/pci/controller/dwc/pcie-designware-ep.c +3 -0
index 7f2112c2fb215..6d3beec92b54e 100644
@@ -793,6 +793,9 @@ int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no,
 
 	writel(msg_data, ep->msi_mem + offset);
 
+	/* flush posted write before unmap */
+	readl(ep->msi_mem + offset);
+
 	dw_pcie_ep_unmap_addr(epc, func_no, 0, ep->msi_mem_phys);
 
 	return 0;
Signature · 1 line
2.51.0
author maintainer
#52 lore raw

PATCH 48/314 drm/amdgpu/userq: Do not allow userspace to trivially triger kernel warnings

In reply to Sasha Levin

From: Tvrtko Ursulin <[email protected]>

[ Upstream commit 7b7d7693a55d606d700beb9549c9f7f0e5d9c24f ]

Userspace can either deliberately pass in the too small num_fences, or the required number can legitimately grow between the two calls to the userq wait ioctl. In both cases we do not want the emit the kernel warning backtrace since nothing is wrong with the kernel and userspace will simply get an errno reported back. So lets simply drop the WARN_ONs.

Fixes a292fdecd728 ("drm/amdgpu: Implement userqueue signal/wait IOCTL")
Cc Arunpravin Paneer Selvam <[email protected]>
Cc Christian König <[email protected]>
Cc Alex Deucher <[email protected]>
(cherry picked from commit 2c333ea579de6cc20ea7bc50e9595ef72863e65c)
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c +4 -4
index 5c181ac75d548..ead1538974454 100644
@@ -829,7 +829,7 @@ int amdgpu_userq_wait_ioctl(struct drm_device *dev, void *data,
 
 			dma_resv_for_each_fence(&resv_cursor, gobj_read[i]->resv,
 						DMA_RESV_USAGE_READ, fence) {
-				if (WARN_ON_ONCE(num_fences >= wait_info->num_fences)) {
+				if (num_fences >= wait_info->num_fences) {
 					r = -EINVAL;
 					goto free_fences;
 				}
@@ -846,7 +846,7 @@ int amdgpu_userq_wait_ioctl(struct drm_device *dev, void *data,
 
 			dma_resv_for_each_fence(&resv_cursor, gobj_write[i]->resv,
 						DMA_RESV_USAGE_WRITE, fence) {
-				if (WARN_ON_ONCE(num_fences >= wait_info->num_fences)) {
+				if (num_fences >= wait_info->num_fences) {
 					r = -EINVAL;
 					goto free_fences;
 				}
@@ -870,7 +870,7 @@ int amdgpu_userq_wait_ioctl(struct drm_device *dev, void *data,
 					goto free_fences;
 
 				dma_fence_unwrap_for_each(f, &iter, fence) {
-					if (WARN_ON_ONCE(num_fences >= wait_info->num_fences)) {
+					if (num_fences >= wait_info->num_fences) {
 						r = -EINVAL;
 						goto free_fences;
 					}
@@ -894,7 +894,7 @@ int amdgpu_userq_wait_ioctl(struct drm_device *dev, void *data,
 			if (r)
 				goto free_fences;
 
-			if (WARN_ON_ONCE(num_fences >= wait_info->num_fences)) {
+			if (num_fences >= wait_info->num_fences) {
 				r = -EINVAL;
 				goto free_fences;
 			}
Signature · 1 line
2.51.0
author maintainer
#53 lore raw

PATCH 49/314 drm/amdgpu: Unlock a mutex before destroying it

In reply to Sasha Levin

From: Bart Van Assche <[email protected]>

[ Upstream commit 5e0bcc7b88bcd081aaae6f481b10d9ab294fcb69 ]

Mutexes must be unlocked before these are destroyed. This has been detected by the Clang thread-safety analyzer.

Cc Alex Deucher <[email protected]>
Cc Christian König <[email protected]>
Cc Yang Wang <[email protected]>
Cc Hawking Zhang <[email protected]>
Fixes f5e4cc8461c4 ("drm/amdgpu: implement RAS ACA driver framework")
(cherry picked from commit 270258ba320beb99648dceffb67e86ac76786e55)
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_aca.c | 1 +
 1 file changed, 1 insertion(+)
drivers/gpu/drm/amd/amdgpu/amdgpu_aca.c +1 -0
index 9b31804491500..3f9b094e93a29 100644
@@ -641,6 +641,7 @@ static void aca_error_fini(struct aca_error *aerr)
 		aca_bank_error_remove(aerr, bank_error);
 
 out_unlock:
+	mutex_unlock(&aerr->lock);
 	mutex_destroy(&aerr->lock);
 }
 
Signature · 1 line
2.51.0
author maintainer
#54 lore raw

PATCH 50/314 drm/amdgpu: Fix locking bugs in error paths

In reply to Sasha Levin

From: Bart Van Assche <[email protected]>

[ Upstream commit 480ad5f6ead4a47b969aab6618573cd6822bb6a4 ]

Do not unlock psp->ras_context.mutex if it has not been locked. This has been detected by the Clang thread-safety analyzer.

Cc Alex Deucher <[email protected]>
Cc Christian König <[email protected]>
Cc YiPeng Chai <[email protected]>
Cc Hawking Zhang <[email protected]>
Fixes b3fb79cda568 ("drm/amdgpu: add mutex to protect ras shared memory")
(cherry picked from commit 6fa01b4335978051d2cd80841728fd63cc597970)
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_psp_ta.c | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_psp_ta.c +7 -5
index 6e8aad91bcd30..0d3c18f04ac36 100644
@@ -332,13 +332,13 @@ static ssize_t ta_if_invoke_debugfs_write(struct file *fp, const char *buf, size
 	if (!context || !context->initialized) {
 		dev_err(adev->dev, "TA is not initialized\n");
 		ret = -EINVAL;
-		goto err_free_shared_buf;
+		goto free_shared_buf;
 	}
 
 	if (!psp->ta_funcs || !psp->ta_funcs->fn_ta_invoke) {
 		dev_err(adev->dev, "Unsupported function to invoke TA\n");
 		ret = -EOPNOTSUPP;
-		goto err_free_shared_buf;
+		goto free_shared_buf;
 	}
 
 	context->session_id = ta_id;
@@ -346,7 +346,7 @@ static ssize_t ta_if_invoke_debugfs_write(struct file *fp, const char *buf, size
 	mutex_lock(&psp->ras_context.mutex);
 	ret = prep_ta_mem_context(&context->mem_context, shared_buf, shared_buf_len);
 	if (ret)
-		goto err_free_shared_buf;
+		goto unlock;
 
 	ret = psp_fn_ta_invoke(psp, cmd_id);
 	if (ret || context->resp_status) {
@@ -354,15 +354,17 @@ static ssize_t ta_if_invoke_debugfs_write(struct file *fp, const char *buf, size
 			ret, context->resp_status);
 		if (!ret) {
 			ret = -EINVAL;
-			goto err_free_shared_buf;
+			goto unlock;
 		}
 	}
 
 	if (copy_to_user((char *)&buf[copy_pos], context->mem_context.shared_buf, shared_buf_len))
 		ret = -EFAULT;
 
-err_free_shared_buf:
+unlock:
 	mutex_unlock(&psp->ras_context.mutex);
+
+free_shared_buf:
 	kfree(shared_buf);
 
 	return ret;
Signature · 1 line
2.51.0
author maintainer
#55 lore raw

PATCH 51/314 drm/amdgpu: Fix error handling in slot reset

In reply to Sasha Levin

From: Lijo Lazar <[email protected]>

[ Upstream commit b57c4ec98c17789136a4db948aec6daadceb5024 ]

If the device has not recovered after slot reset is called, it goes to out label for error handling. There it could make decision based on uninitialized hive pointer and could result in accessing an uninitialized list.

Initialize the list and hive properly so that it handles the error situation and also releases the reset domain lock which is acquired during error_detected callback.

Fixes 732c6cefc1ec ("drm/amdgpu: Replace tmp_adev with hive in amdgpu_pci_slot_reset")
(cherry picked from commit bb71362182e59caa227e4192da5a612b09349696)
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 17 ++++++++++-------
 1 file changed, 10 insertions(+), 7 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +10 -7
index b28ebb44c695d..fb096bf551ef2 100644
@@ -7062,6 +7062,15 @@ pci_ers_result_t amdgpu_pci_slot_reset(struct pci_dev *pdev)
 	dev_info(adev->dev, "PCI error: slot reset callback!!\n");
 
 	memset(&reset_context, 0, sizeof(reset_context));
+	INIT_LIST_HEAD(&device_list);
+	hive = amdgpu_get_xgmi_hive(adev);
+	if (hive) {
+		mutex_lock(&hive->hive_lock);
+		list_for_each_entry(tmp_adev, &hive->device_list, gmc.xgmi.head)
+			list_add_tail(&tmp_adev->reset_list, &device_list);
+	} else {
+		list_add_tail(&adev->reset_list, &device_list);
+	}
 
 	if (adev->pcie_reset_ctx.swus)
 		link_dev = adev->pcie_reset_ctx.swus;
@@ -7102,19 +7111,13 @@ pci_ers_result_t amdgpu_pci_slot_reset(struct pci_dev *pdev)
 	reset_context.reset_req_dev = adev;
 	set_bit(AMDGPU_NEED_FULL_RESET, &reset_context.flags);
 	set_bit(AMDGPU_SKIP_COREDUMP, &reset_context.flags);
-	INIT_LIST_HEAD(&device_list);
 
-	hive = amdgpu_get_xgmi_hive(adev);
 	if (hive) {
-		mutex_lock(&hive->hive_lock);
 		reset_context.hive = hive;
-		list_for_each_entry(tmp_adev, &hive->device_list, gmc.xgmi.head) {
+		list_for_each_entry(tmp_adev, &hive->device_list, gmc.xgmi.head)
 			tmp_adev->pcie_reset_ctx.in_link_reset = true;
-			list_add_tail(&tmp_adev->reset_list, &device_list);
-		}
 	} else {
 		set_bit(AMDGPU_SKIP_HW_RESET, &reset_context.flags);
-		list_add_tail(&adev->reset_list, &device_list);
 	}
 
 	r = amdgpu_device_asic_reset(adev, &device_list, &reset_context);
Signature · 1 line
2.51.0
author maintainer
#56 lore raw

PATCH 52/314 ALSA: hda: cs35l56: Fix signedness error in cs35l56_hda_posture_put()

In reply to Sasha Levin

From: Richard Fitzgerald <[email protected]>

[ Upstream commit 003ce8c9b2ca28fbb4860651e76fb1c9a91f2ea1 ]

In cs35l56_hda_posture_put() assign ucontrol->value.integer.value[0] to a long instead of an unsigned long. ucontrol->value.integer.value[0] is a long.

This fixes the sparse warning:

sound/hda/codecs/side-codecs/cs35l56_hda.c:256:20: warning: unsigned value that used to be signed checked against zero? sound/hda/codecs/side-codecs/cs35l56_hda.c:252:29: signed value source

Fixes 73cfbfa9caea8 ("ALSA: hda/cs35l56: Add driver for Cirrus Logic CS35L56 amplifier")
---
 sound/hda/codecs/side-codecs/cs35l56_hda.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
sound/hda/codecs/side-codecs/cs35l56_hda.c +1 -1
index 5bb1c4ebeaf3c..acbacd0766064 100644
@@ -249,7 +249,7 @@ static int cs35l56_hda_posture_put(struct snd_kcontrol *kcontrol,
 				   struct snd_ctl_elem_value *ucontrol)
 {
 	struct cs35l56_hda *cs35l56 = snd_kcontrol_chip(kcontrol);
-	unsigned long pos = ucontrol->value.integer.value[0];
+	long pos = ucontrol->value.integer.value[0];
 	bool changed;
 	int ret;
 
Signature · 1 line
2.51.0
author maintainer
#57 lore raw

PATCH 53/314 btrfs: free pages on error in btrfs_uring_read_extent()

In reply to Sasha Levin

From: Miquel Sabaté Solà <[email protected]>

[ Upstream commit 3f501412f2079ca14bf68a18d80a2b7a823f1f64 ]

In this function the 'pages' object is never freed in the hopes that it is picked up by btrfs_uring_read_finished() whenever that executes in the future. But that's just the happy path. Along the way previous allocations might have gone wrong, or we might not get -EIOCBQUEUED from btrfs_encoded_read_regular_fill_pages(). In all these cases, we go to a cleanup section that frees all memory allocated by this function without assuming any deferred execution, and this also needs to happen for the 'pages' allocation.

Fixes 34310c442e17 ("btrfs: add io_uring command for encoded reads (ENCODED_READ ioctl)")
---
 fs/btrfs/ioctl.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)
fs/btrfs/ioctl.c +6 -1
index 9a34d6530658e..736a1b3170700 100644
@@ -4725,7 +4725,7 @@ static int btrfs_uring_read_extent(struct kiocb *iocb, struct iov_iter *iter,
 {
 	struct btrfs_inode *inode = BTRFS_I(file_inode(iocb->ki_filp));
 	struct extent_io_tree *io_tree = &inode->io_tree;
-	struct page **pages;
+	struct page **pages = NULL;
 	struct btrfs_uring_priv *priv = NULL;
 	unsigned long nr_pages;
 	int ret;
@@ -4783,6 +4783,11 @@ static int btrfs_uring_read_extent(struct kiocb *iocb, struct iov_iter *iter,
 	btrfs_unlock_extent(io_tree, start, lockend, &cached_state);
 	btrfs_inode_unlock(inode, BTRFS_ILOCK_SHARED);
 	kfree(priv);
+	for (int i = 0; i < nr_pages; i++) {
+		if (pages[i])
+			__free_page(pages[i]);
+	}
+	kfree(pages);
 	return ret;
 }
 
Signature · 1 line
2.51.0
author maintainer
#58 lore raw

PATCH 54/314 btrfs: fix error message order of parameters in btrfs_delete_delayed_dir_index()

In reply to Sasha Levin

From: Mark Harmstone <[email protected]>

[ Upstream commit 3cf0f35779d364cf2003c617bb7f3f3e41023372 ]

Fix the error message in btrfs_delete_delayed_dir_index() if __btrfs_add_delayed_item() fails: the message says root, inode, index, error, but we're actually passing index, root, inode, error.

Fixes adc1ef55dc04 ("btrfs: add details to error messages at btrfs_delete_delayed_dir_index()")
---
 fs/btrfs/delayed-inode.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
fs/btrfs/delayed-inode.c +1 -1
index 59b489d7e4b58..ea48706a3d810 100644
@@ -1676,7 +1676,7 @@ int btrfs_delete_delayed_dir_index(struct btrfs_trans_handle *trans,
 	if (unlikely(ret)) {
 		btrfs_err(trans->fs_info,
 "failed to add delayed dir index item, root: %llu, inode: %llu, index: %llu, error: %d",
-			  index, btrfs_root_id(node->root), node->inode_id, ret);
+			  btrfs_root_id(node->root), node->inode_id, index, ret);
 		btrfs_delayed_item_release_metadata(dir->root, item);
 		btrfs_release_delayed_item(item);
 	}
Signature · 1 line
2.51.0
author maintainer
#59 lore raw

PATCH 55/314 btrfs: fix incorrect key offset in error message in check_dev_extent_item()

In reply to Sasha Levin

From: Mark Harmstone <[email protected]>

[ Upstream commit 511dc8912ae3e929c1a182f5e6b2326516fd42a0 ]

Fix the error message in check_dev_extent_item(), when an overlapping stripe is encountered. For dev extents, objectid is the disk number and offset the physical address, so prev_key->objectid should actually be prev_key->offset.

(I can't take any credit for this one - this was discovered by Chris and his friend Claude.)

Fixes 008e2512dc56 ("btrfs: tree-checker: add dev extent item checks")
---
 fs/btrfs/tree-checker.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
fs/btrfs/tree-checker.c +1 -1
index c10b4c242acfc..7bc758ec64a11 100644
@@ -1894,7 +1894,7 @@ static int check_dev_extent_item(const struct extent_buffer *leaf,
 		if (unlikely(prev_key->offset + prev_len > key->offset)) {
 			generic_err(leaf, slot,
 		"dev extent overlap, prev offset %llu len %llu current offset %llu",
-				    prev_key->objectid, prev_len, key->offset);
+				    prev_key->offset, prev_len, key->offset);
 			return -EUCLEAN;
 		}
 	}
Signature · 1 line
2.51.0
author maintainer
#60 lore raw

PATCH 56/314 btrfs: fix objectid value in error message in check_extent_data_ref()

In reply to Sasha Levin

From: Mark Harmstone <[email protected]>

[ Upstream commit a10172780526c2002e062102ad4f2aabac495889 ]

Fix a copy-paste error in check_extent_data_ref(): we're printing root as in the message above, we should be printing objectid.

Fixes f333a3c7e832 ("btrfs: tree-checker: validate dref root and objectid")
---
 fs/btrfs/tree-checker.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
fs/btrfs/tree-checker.c +1 -1
index 7bc758ec64a11..420c0f0e17c85 100644
@@ -1713,7 +1713,7 @@ static int check_extent_data_ref(struct extent_buffer *leaf,
 			     objectid > BTRFS_LAST_FREE_OBJECTID)) {
 			extent_err(leaf, slot,
 				   "invalid extent data backref objectid value %llu",
-				   root);
+				   objectid);
 			return -EUCLEAN;
 		}
 		if (unlikely(!IS_ALIGNED(offset, leaf->fs_info->sectorsize))) {
Signature · 1 line
2.51.0
author maintainer
#61 lore raw

PATCH 57/314 btrfs: fix warning in scrub_verify_one_metadata()

In reply to Sasha Levin

From: Mark Harmstone <[email protected]>

[ Upstream commit 44e2fda66427a0442d8d2c0e6443256fb458ab6b ]

Commit b471965fdb2d ("btrfs: fix replace/scrub failure with metadata_uuid") fixed the comparison in scrub_verify_one_metadata() to use metadata_uuid rather than fsid, but left the warning as it was. Fix it so it matches what we're doing.

Fixes b471965fdb2d ("btrfs: fix replace/scrub failure with metadata_uuid")
---
 fs/btrfs/scrub.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
fs/btrfs/scrub.c +1 -1
index 747e2c748376a..16936d17166ee 100644
@@ -747,7 +747,7 @@ static void scrub_verify_one_metadata(struct scrub_stripe *stripe, int sector_nr
 		btrfs_warn_rl(fs_info,
 	      "scrub: tree block %llu mirror %u has bad fsid, has %pU want %pU",
 			      logical, stripe->mirror_num,
-			      header->fsid, fs_info->fs_devices->fsid);
+			      header->fsid, fs_info->fs_devices->metadata_uuid);
 		return;
 	}
 	if (memcmp(header->chunk_tree_uuid, fs_info->chunk_tree_uuid,
Signature · 1 line
2.51.0
author maintainer
#62 lore raw

PATCH 58/314 btrfs: print correct subvol num if active swapfile prevents deletion

In reply to Sasha Levin

From: Mark Harmstone <[email protected]>

[ Upstream commit 1c7e9111f4e6d6d42bc47759c9af1ef91f03ac2c ]

Fix the error message in btrfs_delete_subvolume() if we can't delete a subvolume because it has an active swapfile: we were printing the number of the parent rather than the target.

Fixes 60021bd754c6 ("btrfs: prevent subvol with swapfile from being deleted")
---
 fs/btrfs/inode.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
fs/btrfs/inode.c +1 -1
index 47e762856521d..2799b10592d5a 100644
@@ -4658,7 +4658,7 @@ int btrfs_delete_subvolume(struct btrfs_inode *dir, struct dentry *dentry)
 		spin_unlock(&dest->root_item_lock);
 		btrfs_warn(fs_info,
 			   "attempt to delete subvolume %llu with active swapfile",
-			   btrfs_root_id(root));
+			   btrfs_root_id(dest));
 		ret = -EPERM;
 		goto out_up_write;
 	}
Signature · 1 line
2.51.0
author maintainer
#63 lore raw

PATCH 59/314 btrfs: fix compat mask in error messages in btrfs_check_features()

In reply to Sasha Levin

From: Mark Harmstone <[email protected]>

[ Upstream commit 587bb33b10bda645a1028c1737ad3992b3d7cf61 ]

Commit d7f67ac9a928 ("btrfs: relax block-group-tree feature dependency checks") introduced a regression when it comes to handling unsupported incompat or compat_ro flags. Beforehand we only printed the flags that we didn't recognize, afterwards we printed them all, which is less useful. Fix the error handling so it behaves like it used to.

Fixes d7f67ac9a928 ("btrfs: relax block-group-tree feature dependency checks")
---
 fs/btrfs/disk-io.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)
fs/btrfs/disk-io.c +3 -3
index 3fd5d6a27d4c0..9c3a944cbc24a 100644
@@ -3160,7 +3160,7 @@ int btrfs_check_features(struct btrfs_fs_info *fs_info, bool is_rw_mount)
 	if (incompat & ~BTRFS_FEATURE_INCOMPAT_SUPP) {
 		btrfs_err(fs_info,
 		"cannot mount because of unknown incompat features (0x%llx)",
-		    incompat);
+		    incompat & ~BTRFS_FEATURE_INCOMPAT_SUPP);
 		return -EINVAL;
 	}
 
@@ -3192,7 +3192,7 @@ int btrfs_check_features(struct btrfs_fs_info *fs_info, bool is_rw_mount)
 	if (compat_ro_unsupp && is_rw_mount) {
 		btrfs_err(fs_info,
 	"cannot mount read-write because of unknown compat_ro features (0x%llx)",
-		       compat_ro);
+		       compat_ro_unsupp);
 		return -EINVAL;
 	}
 
@@ -3205,7 +3205,7 @@ int btrfs_check_features(struct btrfs_fs_info *fs_info, bool is_rw_mount)
 	    !btrfs_test_opt(fs_info, NOLOGREPLAY)) {
 		btrfs_err(fs_info,
 "cannot replay dirty log with unsupported compat_ro features (0x%llx), try rescue=nologreplay",
-			  compat_ro);
+			  compat_ro_unsupp);
 		return -EINVAL;
 	}
 
Signature · 1 line
2.51.0
author maintainer
#64 lore raw

PATCH 60/314 ALSA: usb: qcom: Correct parameter comment for uaudio_transfer_buffer_setup()

In reply to Sasha Levin

From: Takashi Iwai <[email protected]>

[ Upstream commit 1d6452a0ce78cd3f4e48943b5ba21d273a658298 ]

At fixing the memory leak of xfer buffer, we forgot to update the corresponding comment, too. This resulted in a kernel-doc warning with W=1. Let's correct it.

Fixes 5c7ef5001292 ("ALSA: qc_audio_offload: avoid leaking xfer_buf allocation")
---
 sound/usb/qcom/qc_audio_offload.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
sound/usb/qcom/qc_audio_offload.c +1 -1
index cfb30a195364a..297490f0f5874 100644
@@ -1007,7 +1007,7 @@ static int enable_audio_stream(struct snd_usb_substream *subs,
 /**
  * uaudio_transfer_buffer_setup() - fetch and populate xfer buffer params
  * @subs: usb substream
- * @xfer_buf: xfer buf to be allocated
+ * @xfer_buf_cpu: xfer buf to be allocated
  * @xfer_buf_len: size of allocation
  * @mem_info: QMI response info
  *
Signature · 1 line
2.51.0
author maintainer
#65 lore raw

PATCH 61/314 ASoC: SDCA: Fix comments for sdca_irq_request()

In reply to Sasha Levin

From: Takashi Iwai <[email protected]>

[ Upstream commit 71c1978ab6d2c6d48c31311855f1a85377c152ae ]

The kernel-doc comments for sdca_irq_request() contained some typos that lead to build warnings with W=1. Let's correct them.

Fixes b126394d9ec6 ("ASoC: SDCA: Generic interrupt support")
---
 sound/soc/sdca/sdca_interrupts.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
sound/soc/sdca/sdca_interrupts.c +2 -2
index 79bf3042f57d4..f83413587da5a 100644
@@ -246,9 +246,9 @@ static int sdca_irq_request_locked(struct device *dev,
 }
 
 /**
- * sdca_request_irq - request an individual SDCA interrupt
+ * sdca_irq_request - request an individual SDCA interrupt
  * @dev: Pointer to the struct device against which things should be allocated.
- * @interrupt_info: Pointer to the interrupt information structure.
+ * @info: Pointer to the interrupt information structure.
  * @sdca_irq: SDCA interrupt position.
  * @name: Name to be given to the IRQ.
  * @handler: A callback thread function to be called for the IRQ.
Signature · 1 line
2.51.0
author maintainer
#66 lore raw

PATCH 62/314 bpf, arm64: Force 8-byte alignment for JIT buffer to prevent atomic tearing

In reply to Sasha Levin

From: Fuad Tabba <[email protected]>

[ Upstream commit ef06fd16d48704eac868441d98d4ef083d8f3d07 ]

struct bpf_plt contains a u64 target field. Currently, the BPF JIT allocator requests an alignment of 4 bytes (sizeof(u32)) for the JIT buffer.

Because the base address of the JIT buffer can be 4-byte aligned (e.g., ending in 0x4 or 0xc), the relative padding logic in build_plt() fails to ensure that target lands on an 8-byte boundary.

This leads to two issues:
1. UBSAN reports misaligned-access warnings when dereferencing the structure.
2. More critically, target is updated concurrently via WRITE_ONCE() in bpf_arch_text_poke() while the JIT'd code executes ldr. On arm64, 64-bit loads/stores are only guaranteed to be single-copy atomic if they are 64-bit aligned. A misaligned target risks a torn read, causing the JIT to jump to a corrupted address.

Fix this by increasing the allocation alignment requirement to 8 bytes (sizeof(u64)) in bpf_jit_binary_pack_alloc(). This anchors the base of the JIT buffer to an 8-byte boundary, allowing the relative padding math in build_plt() to correctly align the target field.

Fixes b2ad54e1533e ("bpf, arm64: Implement bpf_arch_text_poke() for arm64")
---
 arch/arm64/net/bpf_jit_comp.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
arch/arm64/net/bpf_jit_comp.c +1 -1
index 83a6ca613f9c2..107eb71b533a0 100644
@@ -2122,7 +2122,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
 	extable_offset = round_up(prog_size + PLT_TARGET_SIZE, extable_align);
 	image_size = extable_offset + extable_size;
 	ro_header = bpf_jit_binary_pack_alloc(image_size, &ro_image_ptr,
-					      sizeof(u32), &header, &image_ptr,
+					      sizeof(u64), &header, &image_ptr,
 					      jit_fill_hole);
 	if (!ro_header) {
 		prog = orig_prog;
Signature · 1 line
2.51.0
author maintainer
#67 lore raw

PATCH 63/314 bpf: Fix stack-out-of-bounds write in devmap

In reply to Sasha Levin

From: Kohei Enju <[email protected]>

[ Upstream commit b7bf516c3ecd9a2aae2dc2635178ab87b734fef1 ]

get_upper_ifindexes() iterates over all upper devices and writes their indices into an array without checking bounds.

Also the callers assume that the max number of upper devices is MAX_NEST_DEV and allocate excluded_devices[1+MAX_NEST_DEV] on the stack, but that assumption is not correct and the number of upper devices could be larger than MAX_NEST_DEV (e.g., many macvlans), causing a stack-out-of-bounds write.

Add a max parameter to get_upper_ifindexes() to avoid the issue. When there are too many upper devices, return -EOVERFLOW and abort the redirect.

To reproduce, create more than MAX_NEST_DEV(8) macvlans on a device with an XDP program attached using BPF_F_BROADCAST | BPF_F_EXCLUDE_INGRESS. Then send a packet to the device to trigger the XDP redirect path.

---
 kernel/bpf/devmap.c | 22 +++++++++++++++++-----
 1 file changed, 17 insertions(+), 5 deletions(-)
kernel/bpf/devmap.c +17 -5
index 2625601de76e9..2984e938f94dc 100644
@@ -588,18 +588,22 @@ static inline bool is_ifindex_excluded(int *excluded, int num_excluded, int ifin
 }
 
 /* Get ifindex of each upper device. 'indexes' must be able to hold at
- * least MAX_NEST_DEV elements.
- * Returns the number of ifindexes added.
+ * least 'max' elements.
+ * Returns the number of ifindexes added, or -EOVERFLOW if there are too
+ * many upper devices.
  */
-static int get_upper_ifindexes(struct net_device *dev, int *indexes)
+static int get_upper_ifindexes(struct net_device *dev, int *indexes, int max)
 {
 	struct net_device *upper;
 	struct list_head *iter;
 	int n = 0;
 
 	netdev_for_each_upper_dev_rcu(dev, upper, iter) {
+		if (n >= max)
+			return -EOVERFLOW;
 		indexes[n++] = upper->ifindex;
 	}
+
 	return n;
 }
 
@@ -615,7 +619,11 @@ int dev_map_enqueue_multi(struct xdp_frame *xdpf, struct net_device *dev_rx,
 	int err;
 
 	if (exclude_ingress) {
-		num_excluded = get_upper_ifindexes(dev_rx, excluded_devices);
+		num_excluded = get_upper_ifindexes(dev_rx, excluded_devices,
+						   ARRAY_SIZE(excluded_devices) - 1);
+		if (num_excluded < 0)
+			return num_excluded;
+
 		excluded_devices[num_excluded++] = dev_rx->ifindex;
 	}
 
@@ -733,7 +741,11 @@ int dev_map_redirect_multi(struct net_device *dev, struct sk_buff *skb,
 	int err;
 
 	if (exclude_ingress) {
-		num_excluded = get_upper_ifindexes(dev, excluded_devices);
+		num_excluded = get_upper_ifindexes(dev, excluded_devices,
+						   ARRAY_SIZE(excluded_devices) - 1);
+		if (num_excluded < 0)
+			return num_excluded;
+
 		excluded_devices[num_excluded++] = dev->ifindex;
 	}
 
Signature · 1 line
2.51.0
author maintainer
#68 lore raw

PATCH 64/314 selftests/bpf: Fix OOB read in dmabuf_collector

In reply to Sasha Levin

From: "T.J. Mercier" <[email protected]>

[ Upstream commit 6881af27f9ea0f5ca8f606f573ef5cc25ca31fe4 ]

Dmabuf name allocations can be less than DMA_BUF_NAME_LEN characters, but bpf_probe_read_kernel always tries to read exactly that many bytes. If a name is less than DMA_BUF_NAME_LEN characters, bpf_probe_read_kernel will read past the end. bpf_probe_read_kernel_str stops at the first NUL terminator so use it instead, like iter_dmabuf_for_each already does.

---
 tools/testing/selftests/bpf/progs/dmabuf_iter.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
tools/testing/selftests/bpf/progs/dmabuf_iter.c +1 -1
index 13cdb11fdeb2b..9cbb7442646e5 100644
@@ -48,7 +48,7 @@ int dmabuf_collector(struct bpf_iter__dmabuf *ctx)
 
 	/* Buffers are not required to be named */
 	if (pname) {
-		if (bpf_probe_read_kernel(name, sizeof(name), pname))
+		if (bpf_probe_read_kernel_str(name, sizeof(name), pname) < 0)
 			return 1;
 
 		/* Name strings can be provided by userspace */
Signature · 1 line
2.51.0
author maintainer
#69 lore raw

PATCH 65/314 sched_ext: Fix SCX_EFLAG_INITIALIZED being a no-op flag

In reply to Sasha Levin

From: David Carlier <[email protected]>

[ Upstream commit 749989b2d90ddc7dd253ad3b11a77cf882721acf ]

SCX_EFLAG_INITIALIZED is the sole member of enum scx_exit_flags with no explicit value, so the compiler assigns it 0. This makes the bitwise OR in scx_ops_init() a no-op:

    sch->exit_info->flags |= SCX_EFLAG_INITIALIZED; /* |= 0 */

As a result, BPF schedulers cannot distinguish whether ops.init() completed successfully by inspecting exit_info->flags.

Assign the value 1LLU << 0 so the flag is actually set.

Fixes f3aec2adce8d ("sched_ext: Add SCX_EFLAG_INITIALIZED to indicate successful ops.init()")
---
 kernel/sched/ext_internal.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/sched/ext_internal.h +1 -1
index 601cfae8cc765..8039a750490f8 100644
@@ -69,7 +69,7 @@ enum scx_exit_flags {
 	 * info communication. The following flag indicates whether ops.init()
 	 * finished successfully.
 	 */
-	SCX_EFLAG_INITIALIZED,
+	SCX_EFLAG_INITIALIZED   = 1LLU << 0,
 };
 
 /*
Signature · 1 line
2.51.0
author maintainer
#70 lore raw

PATCH 66/314 spi: stm32: fix missing pointer assignment in case of dma chaining

In reply to Sasha Levin

From: Alain Volmat <[email protected]>

[ Upstream commit e96493229a6399e902062213c6381162464cdd50 ]

Commit c4f2c05ab029 ("spi: stm32: fix pointer-to-pointer variables usage") introduced a regression since dma descriptors generated as part of the stm32_spi_prepare_rx_dma_mdma_chaining function are not well propagated to the caller function, leading to mdma-dma chaining being no more functional.

Fixes c4f2c05ab029 ("spi: stm32: fix pointer-to-pointer variables usage")
---
 drivers/spi/spi-stm32.c | 3 +++
 1 file changed, 3 insertions(+)
drivers/spi/spi-stm32.c +3 -0
index 80986bd251d29..7a6ee93be9bd4 100644
@@ -1570,6 +1570,9 @@ static int stm32_spi_prepare_rx_dma_mdma_chaining(struct stm32_spi *spi,
 		return -EINVAL;
 	}
 
+	*rx_mdma_desc = _mdma_desc;
+	*rx_dma_desc = _dma_desc;
+
 	return 0;
 }
 
Signature · 1 line
2.51.0
author maintainer
#71 lore raw

PATCH 67/314 PCI: Correct PCI_CAP_EXP_ENDPOINT_SIZEOF_V2 value

In reply to Sasha Levin

From: Bjorn Helgaas <[email protected]>

[ Upstream commit 39195990e4c093c9eecf88f29811c6de29265214 ]

fb82437fdd8c ("PCI: Change capability register offsets to hex") incorrectly converted the PCI_CAP_EXP_ENDPOINT_SIZEOF_V2 value from decimal 52 to hex 0x32:

-#define PCI_CAP_EXP_ENDPOINT_SIZEOF_V2 52 /* v2 endpoints with link end here */
+#define PCI_CAP_EXP_ENDPOINT_SIZEOF_V2 0x32 /* end of v2 EPs w/ link */

This broke PCI capabilities in a VMM because subsequent ones weren't DWORD-aligned.

Change PCI_CAP_EXP_ENDPOINT_SIZEOF_V2 to the correct value of 0x34.

fb82437fdd8c was from Baruch Siach <[email protected]>, but this was not Baruch's fault; it's a mistake I made when applying the patch.

---
 include/uapi/linux/pci_regs.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
include/uapi/linux/pci_regs.h +1 -1
index 07e06aafec502..1172bda87abff 100644
@@ -706,7 +706,7 @@
 #define  PCI_EXP_LNKCTL2_HASD		0x0020 /* HW Autonomous Speed Disable */
 #define PCI_EXP_LNKSTA2		0x32	/* Link Status 2 */
 #define  PCI_EXP_LNKSTA2_FLIT		0x0400 /* Flit Mode Status */
-#define PCI_CAP_EXP_ENDPOINT_SIZEOF_V2	0x32	/* end of v2 EPs w/ link */
+#define PCI_CAP_EXP_ENDPOINT_SIZEOF_V2	0x34	/* end of v2 EPs w/ link */
 #define PCI_EXP_SLTCAP2		0x34	/* Slot Capabilities 2 */
 #define  PCI_EXP_SLTCAP2_IBPD	0x00000001 /* In-band PD Disable Supported */
 #define PCI_EXP_SLTCTL2		0x38	/* Slot Control 2 */
Signature · 1 line
2.51.0
author maintainer
#72 lore raw

PATCH 68/314 bpf: Fix race in cpumap on PREEMPT_RT

In reply to Sasha Levin

From: Jiayuan Chen <[email protected]>

[ Upstream commit 869c63d5975d55e97f6b168e885452b3da20ea47 ]

On PREEMPT_RT kernels, the per-CPU xdp_bulk_queue (bq) can be accessed concurrently by multiple preemptible tasks on the same CPU.

The original code assumes bq_enqueue() and __cpu_map_flush() run atomically with respect to each other on the same CPU, relying on local_bh_disable() to prevent preemption. However, on PREEMPT_RT, local_bh_disable() only calls migrate_disable() (when PREEMPT_RT_NEEDS_BH_LOCK is not set) and does not disable preemption, which allows CFS scheduling to preempt a task during bq_flush_to_queue(), enabling another task on the same CPU to enter bq_enqueue() and operate on the same per-CPU bq concurrently.

This leads to several races:

1. Double __list_del_clearprev(): after bq->count is reset in bq_flush_to_queue(), a preempting task can call bq_enqueue() -> bq_flush_to_queue() on the same bq when bq->count reaches CPU_MAP_BULK_SIZE. Both tasks then call __list_del_clearprev() on the same bq->flush_node, the second call dereferences the prev pointer that was already set to NULL by the first.

2. bq->count and bq->q[] races: concurrent bq_enqueue() can corrupt the packet queue while bq_flush_to_queue() is processing it.

The race between task A (__cpu_map_flush -> bq_flush_to_queue) and task B (bq_enqueue -> bq_flush_to_queue) on the same CPU:

Task A (xdp_do_flush) Task B (cpu_map_enqueue)
---------------------- ------------------------
bq_flush_to_queue(bq)

    spin_lock(&q->producer_lock)
    /* flush bq->q[] to ptr_ring */
    bq->count = 0
    spin_unlock(&q->producer_lock)
                                   bq_enqueue(rcpu, xdpf)
    <-- CFS preempts Task A -->      bq->q[bq->count++] = xdpf
                                     /* ... more enqueues until full ... */
                                     bq_flush_to_queue(bq)
                                       spin_lock(&q->producer_lock)
                                       /* flush to ptr_ring */
                                       spin_unlock(&q->producer_lock)
                                       __list_del_clearprev(flush_node)
                                         /* sets flush_node.prev = NULL */
    <-- Task A resumes -->
    __list_del_clearprev(flush_node)
      flush_node.prev->next = ...
      /* prev is NULL -> kernel oops */

Fix this by adding a local_lock_t to xdp_bulk_queue and acquiring it in bq_enqueue() and __cpu_map_flush(). These paths already run under local_bh_disable(), so use local_lock_nested_bh() which on non-RT is a pure annotation with no overhead, and on PREEMPT_RT provides a per-CPU sleeping lock that serializes access to the bq.

To reproduce, insert an mdelay(100) between bq->count = 0 and __list_del_clearprev() in bq_flush_to_queue(), then run reproducer provided by syzkaller.

---
 kernel/bpf/cpumap.c | 17 +++++++++++++++--
 1 file changed, 15 insertions(+), 2 deletions(-)
kernel/bpf/cpumap.c +15 -2
index 703e5df1f4ef9..306bf98378041 100644
@@ -29,6 +29,7 @@
 #include <linux/sched.h>
 #include <linux/workqueue.h>
 #include <linux/kthread.h>
+#include <linux/local_lock.h>
 #include <linux/completion.h>
 #include <trace/events/xdp.h>
 #include <linux/btf_ids.h>
@@ -52,6 +53,7 @@ struct xdp_bulk_queue {
 	struct list_head flush_node;
 	struct bpf_cpu_map_entry *obj;
 	unsigned int count;
+	local_lock_t bq_lock;
 };
 
 /* Struct for every remote "destination" CPU in map */
@@ -451,6 +453,7 @@ __cpu_map_entry_alloc(struct bpf_map *map, struct bpf_cpumap_val *value,
 	for_each_possible_cpu(i) {
 		bq = per_cpu_ptr(rcpu->bulkq, i);
 		bq->obj = rcpu;
+		local_lock_init(&bq->bq_lock);
 	}
 
 	/* Alloc queue */
@@ -717,6 +720,8 @@ static void bq_flush_to_queue(struct xdp_bulk_queue *bq)
 	struct ptr_ring *q;
 	int i;
 
+	lockdep_assert_held(&bq->bq_lock);
+
 	if (unlikely(!bq->count))
 		return;
 
@@ -744,11 +749,15 @@ static void bq_flush_to_queue(struct xdp_bulk_queue *bq)
 }
 
 /* Runs under RCU-read-side, plus in softirq under NAPI protection.
- * Thus, safe percpu variable access.
+ * Thus, safe percpu variable access. PREEMPT_RT relies on
+ * local_lock_nested_bh() to serialise access to the per-CPU bq.
  */
 static void bq_enqueue(struct bpf_cpu_map_entry *rcpu, struct xdp_frame *xdpf)
 {
-	struct xdp_bulk_queue *bq = this_cpu_ptr(rcpu->bulkq);
+	struct xdp_bulk_queue *bq;
+
+	local_lock_nested_bh(&rcpu->bulkq->bq_lock);
+	bq = this_cpu_ptr(rcpu->bulkq);
 
 	if (unlikely(bq->count == CPU_MAP_BULK_SIZE))
 		bq_flush_to_queue(bq);
@@ -769,6 +778,8 @@ static void bq_enqueue(struct bpf_cpu_map_entry *rcpu, struct xdp_frame *xdpf)
 
 		list_add(&bq->flush_node, flush_list);
 	}
+
+	local_unlock_nested_bh(&rcpu->bulkq->bq_lock);
 }
 
 int cpu_map_enqueue(struct bpf_cpu_map_entry *rcpu, struct xdp_frame *xdpf,
@@ -805,7 +816,9 @@ void __cpu_map_flush(struct list_head *flush_list)
 	struct xdp_bulk_queue *bq, *tmp;
 
 	list_for_each_entry_safe(bq, tmp, flush_list, flush_node) {
+		local_lock_nested_bh(&bq->obj->bulkq->bq_lock);
 		bq_flush_to_queue(bq);
+		local_unlock_nested_bh(&bq->obj->bulkq->bq_lock);
 
 		/* If already running, costs spin_lock_irqsave + smb_mb */
 		wake_up_process(bq->obj->kthread);
Signature · 1 line
2.51.0
author maintainer
#73 lore raw

PATCH 69/314 bpf: Fix race in devmap on PREEMPT_RT

In reply to Sasha Levin

From: Jiayuan Chen <[email protected]>

[ Upstream commit 1872e75375c40add4a35990de3be77b5741c252c ]

On PREEMPT_RT kernels, the per-CPU xdp_dev_bulk_queue (bq) can be accessed concurrently by multiple preemptible tasks on the same CPU.

The original code assumes bq_enqueue() and __dev_flush() run atomically with respect to each other on the same CPU, relying on local_bh_disable() to prevent preemption. However, on PREEMPT_RT, local_bh_disable() only calls migrate_disable() (when PREEMPT_RT_NEEDS_BH_LOCK is not set) and does not disable preemption, which allows CFS scheduling to preempt a task during bq_xmit_all(), enabling another task on the same CPU to enter bq_enqueue() and operate on the same per-CPU bq concurrently.

This leads to several races:

1. Double-free / use-after-free on bq->q[]: bq_xmit_all() snapshots cnt = bq->count, then iterates bq->q[0..cnt-1] to transmit frames. If preempted after the snapshot, a second task can call bq_enqueue() -> bq_xmit_all() on the same bq, transmitting (and freeing) the same frames. When the first task resumes, it operates on stale pointers in bq->q[], causing use-after-free.

2. bq->count and bq->q[] corruption: concurrent bq_enqueue() modifying bq->count and bq->q[] while bq_xmit_all() is reading them.

3. dev_rx/xdp_prog teardown race: __dev_flush() clears bq->dev_rx and bq->xdp_prog after bq_xmit_all(). If preempted between bq_xmit_all() return and bq->dev_rx = NULL, a preempting bq_enqueue() sees dev_rx still set (non-NULL), skips adding bq to the flush_list, and enqueues a frame. When __dev_flush() resumes, it clears dev_rx and removes bq from the flush_list, orphaning the newly enqueued frame.

4. __list_del_clearprev() on flush_node: similar to the cpumap race, both tasks can call __list_del_clearprev() on the same flush_node, the second dereferences the prev pointer already set to NULL.

The race between task A (__dev_flush -> bq_xmit_all) and task B (bq_enqueue -> bq_xmit_all) on the same CPU:

Task A (xdp_do_flush) Task B (ndo_xdp_xmit redirect)
---------------------- --------------------------------
__dev_flush(flush_list)

    bq_xmit_all(bq)
      cnt = bq->count  /* e.g. 16 */
      /* start iterating bq->q[] */
    <-- CFS preempts Task A -->
                                   bq_enqueue(dev, xdpf)
                                     bq->count == DEV_MAP_BULK_SIZE
                                     bq_xmit_all(bq, 0)
                                       cnt = bq->count  /* same 16! */
                                       ndo_xdp_xmit(bq->q[])
                                       /* frames freed by driver */
                                       bq->count = 0
    <-- Task A resumes -->
      ndo_xdp_xmit(bq->q[])
      /* use-after-free: frames already freed! */

Fix this by adding a local_lock_t to xdp_dev_bulk_queue and acquiring it in bq_enqueue() and __dev_flush(). These paths already run under local_bh_disable(), so use local_lock_nested_bh() which on non-RT is a pure annotation with no overhead, and on PREEMPT_RT provides a per-CPU sleeping lock that serializes access to the bq.

---
 kernel/bpf/devmap.c | 25 +++++++++++++++++++++----
 1 file changed, 21 insertions(+), 4 deletions(-)
kernel/bpf/devmap.c +21 -4
index 2984e938f94dc..3d619d01088e3 100644
@@ -45,6 +45,7 @@
  * types of devmap; only the lookup and insertion is different.
  */
 #include <linux/bpf.h>
+#include <linux/local_lock.h>
 #include <net/xdp.h>
 #include <linux/filter.h>
 #include <trace/events/xdp.h>
@@ -60,6 +61,7 @@ struct xdp_dev_bulk_queue {
 	struct net_device *dev_rx;
 	struct bpf_prog *xdp_prog;
 	unsigned int count;
+	local_lock_t bq_lock;
 };
 
 struct bpf_dtab_netdev {
@@ -381,6 +383,8 @@ static void bq_xmit_all(struct xdp_dev_bulk_queue *bq, u32 flags)
 	int to_send = cnt;
 	int i;
 
+	lockdep_assert_held(&bq->bq_lock);
+
 	if (unlikely(!cnt))
 		return;
 
@@ -425,10 +429,12 @@ void __dev_flush(struct list_head *flush_list)
 	struct xdp_dev_bulk_queue *bq, *tmp;
 
 	list_for_each_entry_safe(bq, tmp, flush_list, flush_node) {
+		local_lock_nested_bh(&bq->dev->xdp_bulkq->bq_lock);
 		bq_xmit_all(bq, XDP_XMIT_FLUSH);
 		bq->dev_rx = NULL;
 		bq->xdp_prog = NULL;
 		__list_del_clearprev(&bq->flush_node);
+		local_unlock_nested_bh(&bq->dev->xdp_bulkq->bq_lock);
 	}
 }
 
@@ -451,12 +457,16 @@ static void *__dev_map_lookup_elem(struct bpf_map *map, u32 key)
 
 /* Runs in NAPI, i.e., softirq under local_bh_disable(). Thus, safe percpu
  * variable access, and map elements stick around. See comment above
- * xdp_do_flush() in filter.c.
+ * xdp_do_flush() in filter.c. PREEMPT_RT relies on local_lock_nested_bh()
+ * to serialise access to the per-CPU bq.
  */
 static void bq_enqueue(struct net_device *dev, struct xdp_frame *xdpf,
 		       struct net_device *dev_rx, struct bpf_prog *xdp_prog)
 {
-	struct xdp_dev_bulk_queue *bq = this_cpu_ptr(dev->xdp_bulkq);
+	struct xdp_dev_bulk_queue *bq;
+
+	local_lock_nested_bh(&dev->xdp_bulkq->bq_lock);
+	bq = this_cpu_ptr(dev->xdp_bulkq);
 
 	if (unlikely(bq->count == DEV_MAP_BULK_SIZE))
 		bq_xmit_all(bq, 0);
@@ -477,6 +487,8 @@ static void bq_enqueue(struct net_device *dev, struct xdp_frame *xdpf,
 	}
 
 	bq->q[bq->count++] = xdpf;
+
+	local_unlock_nested_bh(&dev->xdp_bulkq->bq_lock);
 }
 
 static inline int __xdp_enqueue(struct net_device *dev, struct xdp_frame *xdpf,
@@ -1127,8 +1139,13 @@ static int dev_map_notification(struct notifier_block *notifier,
 		if (!netdev->xdp_bulkq)
 			return NOTIFY_BAD;
 
-		for_each_possible_cpu(cpu)
-			per_cpu_ptr(netdev->xdp_bulkq, cpu)->dev = netdev;
+		for_each_possible_cpu(cpu) {
+			struct xdp_dev_bulk_queue *bq;
+
+			bq = per_cpu_ptr(netdev->xdp_bulkq, cpu);
+			bq->dev = netdev;
+			local_lock_init(&bq->bq_lock);
+		}
 		break;
 	case NETDEV_UNREGISTER:
 		/* This rcu_read_lock/unlock pair is needed because
Signature · 1 line
2.51.0
author maintainer
#74 lore raw

PATCH 70/314 bpf: Add bitwise tracking for BPF_END

In reply to Sasha Levin

From: Tianci Cao <[email protected]>

[ Upstream commit 9d21199842247ab05c675fb9b6c6ca393a5c0024 ]

This patch implements bitwise tracking (tnum analysis) for BPF_END (byte swap) operation.

Currently, the BPF verifier does not track value for BPF_END operation, treating the result as completely unknown. This limits the verifier's ability to prove safety of programs that perform endianness conversions, which are common in networking code.

For example, the following code pattern for port number validation:

int test(struct pt_regs *ctx) {
    __u64 x = bpf_get_prandom_u32();
    x &= 0x3f00;           // Range: [0, 0x3f00], var_off: (0x0; 0x3f00)
    x = bswap16(x);        // Should swap to range [0, 0x3f], var_off: (0x0; 0x3f)
    if (x > 0x3f) goto trap;
    return 0;

trap:
return *(u64 *)NULL; // Should be unreachable
}

Currently generates verifier output:

1: (54) w0 &= 16128                   ; R0=scalar(smin=smin32=0,smax=umax=smax32=umax32=16128,var_off=(0x0; 0x3f00))
2: (d7) r0 = bswap16 r0               ; R0=scalar()
3: (25) if r0 > 0x3f goto pc+2        ; R0=scalar(smin=smin32=0,smax=umax=smax32=umax32=63,var_off=(0x0; 0x3f))

Without this patch, even though the verifier knows x has certain bits set, after bswap16, it loses all tracking information and treats port as having a completely unknown value [0, 65535].

According to the BPF instruction set[1], there are 3 kinds of BPF_END:

1. bswap(16|32|64): opcode=0xd7 (BPF_END | BPF_ALU64 | BPF_TO_LE)
- do unconditional swap
2. le(16|32|64): opcode=0xd4 (BPF_END | BPF_ALU | BPF_TO_LE)
- on big-endian: do swap
- on little-endian: truncation (16/32-bit) or no-op (64-bit)
3. be(16|32|64): opcode=0xdc (BPF_END | BPF_ALU | BPF_TO_BE)
- on little-endian: do swap
- on big-endian: truncation (16/32-bit) or no-op (64-bit)

Since BPF_END operations are inherently bit-wise permutations, tnum (bitwise tracking) offers the most efficient and precise mechanism for value analysis. By implementing tnum_bswap16, tnum_bswap32, and tnum_bswap64, we can derive exact var_off values concisely, directly reflecting the bit-level changes.

Here is the overview of changes:

1. In tnum_bswap(16|32|64) (kernel/bpf/tnum.c):

Call swab(16|32|64) function on the value and mask of var_off, and do truncation for 16/32-bit cases.

2. In adjust_scalar_min_max_vals (kernel/bpf/verifier.c):

Call helper function scalar_byte_swap.
- Only do byte swap when
* alu64 (unconditional swap) OR
* switching between big-endian and little-endian machines.
- If need do byte swap:
* Firstly call tnum_bswap(16|32|64) to update var_off.
* Then reset the bound since byte swap scrambles the range.
- For 16/32-bit cases, truncate dst register to match the swapped size.

This enables better verification of networking code that frequently uses byte swaps for protocol processing, reducing false positive rejections.

[1] https://www.kernel.org/doc/Documentation/bpf/standardization/instruction-set.rst

Stable-dep-of: efc11a667878 ("bpf: Improve bounds when tnum has a single possible value")

---
 include/linux/tnum.h  |  5 ++++
 kernel/bpf/tnum.c     | 16 ++++++++++++
 kernel/bpf/verifier.c | 60 ++++++++++++++++++++++++++++++++++++++++---
 3 files changed, 78 insertions(+), 3 deletions(-)
include/linux/tnum.h +5 -0
index c52b862dad45b..fa4654ffb6217 100644
@@ -63,6 +63,11 @@ struct tnum tnum_union(struct tnum t1, struct tnum t2);
 /* Return @a with all but the lowest @size bytes cleared */
 struct tnum tnum_cast(struct tnum a, u8 size);
 
+/* Swap the bytes of a tnum */
+struct tnum tnum_bswap16(struct tnum a);
+struct tnum tnum_bswap32(struct tnum a);
+struct tnum tnum_bswap64(struct tnum a);
+
 /* Returns true if @a is a known constant */
 static inline bool tnum_is_const(struct tnum a)
 {
kernel/bpf/tnum.c +16 -0
index f8e70e9c3998d..26fbfbb017001 100644
@@ -8,6 +8,7 @@
  */
 #include <linux/kernel.h>
 #include <linux/tnum.h>
+#include <linux/swab.h>
 
 #define TNUM(_v, _m)	(struct tnum){.value = _v, .mask = _m}
 /* A completely unknown value */
@@ -253,3 +254,18 @@ struct tnum tnum_const_subreg(struct tnum a, u32 value)
 {
 	return tnum_with_subreg(a, tnum_const(value));
 }
+
+struct tnum tnum_bswap16(struct tnum a)
+{
+	return TNUM(swab16(a.value & 0xFFFF), swab16(a.mask & 0xFFFF));
+}
+
+struct tnum tnum_bswap32(struct tnum a)
+{
+	return TNUM(swab32(a.value & 0xFFFFFFFF), swab32(a.mask & 0xFFFFFFFF));
+}
+
+struct tnum tnum_bswap64(struct tnum a)
+{
+	return TNUM(swab64(a.value), swab64(a.mask));
+}
kernel/bpf/verifier.c +57 -3

88 lines not on this page · raw message

Signature · 1 line
2.51.0
author maintainer
#75 lore raw

PATCH 71/314 bpf: Introduce tnum_step to step through tnum's members

In reply to Sasha Levin

From: Harishankar Vishwanathan <[email protected]>

[ Upstream commit 76e954155b45294c502e3d3a9e15757c858ca55e ]

This commit introduces tnum_step(), a function that, when given t, and a number z returns the smallest member of t larger than z. The number z must be greater or equal to the smallest member of t and less than the largest member of t.

The first step is to compute j, a number that keeps all of t's known bits, and matches all unknown bits to z's bits. Since j is a member of the t, it is already a candidate for result. However, we want our result to be (minimally) greater than z.

There are only two possible cases:

(1) Case j <= z. In this case, we want to increase the value of j and make it > z.
(2) Case j > z. In this case, we want to decrease the value of j while keeping it > z.

(Case 1) j <= z

t = xx11x0x0
z = 10111101 (189)
j = 10111000 (184)

         ^
         k

(Case 1.1) Let's first consider the case where j < z. We will address j == z later.

Since z > j, there had to be a bit position that was 1 in z and a 0 in j, beyond which all positions of higher significance are equal in j and z. Further, this position could not have been unknown in a, because the unknown positions of a match z. This position had to be a 1 in z and known 0 in t.

Let k be position of the most significant 1-to-0 flip. In our example, k = 3 (starting the count at 1 at the least significant bit). Setting (to
1) the unknown bits of t in positions of significance smaller than k will not produce a result > z. Hence, we must set/unset the unknown bits at positions of significance higher than k. Specifically, we look for the next larger combination of 1s and 0s to place in those positions, relative to the combination that exists in z. We can achieve this by concatenating bits at unknown positions of t into an integer, adding 1, and writing the bits of that result back into the corresponding bit positions previously extracted from z.

Quoted 1 line

From our example, considering only positions of significance greater

than k:

t = xx..x
z = 10..1

    +    1
     -----
     11..0

This is the exact combination 1s and 0s we need at the unknown bits of t in positions of significance greater than k. Further, our result must only increase the value minimally above z. Hence, unknown bits in positions of significance smaller than k should remain 0. We finally have,

result = 11110000 (240)

(Case 1.2) Now consider the case when j = z, for example

t = 1x1x0xxx
z = 10110100 (180)
j = 10110100 (180)

Matching the unknown bits of the t to the bits of z yielded exactly z. To produce a number greater than z, we must set/unset the unknown bits in t, and *all* the unknown bits of t candidates for being set/unset. We can do this similar to Case 1.1, by adding 1 to the bits extracted from the masked bit positions of z. Essentially, this case is equivalent to Case 1.1, with k = 0.

t = 1x1x0xxx
z = .0.1.100

    +       1
    ---------
     .0.1.101

This is the exact combination of bits needed in the unknown positions of t. After recalling the known positions of t, we get

result = 10110101 (181)

(Case 2) j > z

t = x00010x1
z = 10000010 (130)
j = 10001011 (139)

	^
	k

Since j > z, there had to be a bit position which was 0 in z, and a 1 in j, beyond which all positions of higher significance are equal in j and z. This position had to be a 0 in z and known 1 in t. Let k be the position of the most significant 0-to-1 flip. In our example, k = 4.

Because of the 0-to-1 flip at position k, a member of t can become greater than z if the bits in positions greater than k are themselves >= to z. To make that member *minimally* greater than z, the bits in positions greater than k must be exactly = z. Hence, we simply match all of t's unknown bits in positions more significant than k to z's bits. In positions less significant than k, we set all t's unknown bits to 0 to retain minimality.

In our example, in positions of greater significance than k (=4), t=x000. These positions are matched with z (1000) to produce 1000. In positions of lower significance than k, t=10x1. All unknown bits are set to 0 to produce 1001. The final result is:

result = 10001001 (137)

This concludes the computation for a result > z that is a member of t.

The procedure for tnum_step() in this commit implements the idea described above. As a proof of correctness, we verified the algorithm against a logical specification of tnum_step. The specification asserts the following about the inputs t, z and output res that:

1. res is a member of t, and
2. res is strictly greater than z, and
3. there does not exist another value res2 such that 3a. res2 is also a member of t, and 3b. res2 is greater than z
3c. res2 is smaller than res

We checked the implementation against this logical specification using an SMT solver. The verification formula in SMTLIB format is available at [1]. The verification returned an "unsat": indicating that no input assignment exists for which the implementation and the specification produce different outputs.

In addition, we also automatically generated the logical encoding of the C implementation using Agni [2] and verified it against the same specification. This verification also returned an "unsat", confirming that the implementation is equivalent to the specification. The formula for this check is also available at [3].

Stable-dep-of: efc11a667878 ("bpf: Improve bounds when tnum has a single possible value")

---
 include/linux/tnum.h |  3 +++
 kernel/bpf/tnum.c    | 56 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 59 insertions(+)
include/linux/tnum.h +3 -0
index fa4654ffb6217..ca2cfec8de08a 100644
@@ -131,4 +131,7 @@ static inline bool tnum_subreg_is_const(struct tnum a)
 	return !(tnum_subreg(a)).mask;
 }
 
+/* Returns the smallest member of t larger than z */
+u64 tnum_step(struct tnum t, u64 z);
+
 #endif /* _LINUX_TNUM_H */
kernel/bpf/tnum.c +56 -0

59 lines not on this page · raw message

Signature · 1 line
2.51.0
author maintainer
#76 lore raw

PATCH 72/314 bpf: Improve bounds when tnum has a single possible value

In reply to Sasha Levin

From: Paul Chaignon <[email protected]>

[ Upstream commit efc11a667878a1d655ff034a93a539debbfedb12 ]

We're hitting an invariant violation in Cilium that sometimes leads to BPF programs being rejected and Cilium failing to start [1]. The following extract from verifier logs shows what's happening:

  from 201 to 236: R1=0 R6=ctx() R7=1 R9=scalar(smin=umin=smin32=umin32=3584,smax=umax=smax32=umax32=3840,var_off=(0xe00; 0x100)) R10=fp0
  236: R1=0 R6=ctx() R7=1 R9=scalar(smin=umin=smin32=umin32=3584,smax=umax=smax32=umax32=3840,var_off=(0xe00; 0x100)) R10=fp0
  ; if (magic == MARK_MAGIC_HOST || magic == MARK_MAGIC_OVERLAY || magic == MARK_MAGIC_ENCRYPT) @ bpf_host.c:1337
  236: (16) if w9 == 0xe00 goto pc+45   ; R9=scalar(smin=umin=smin32=umin32=3585,smax=umax=smax32=umax32=3840,var_off=(0xe00; 0x100))
  237: (16) if w9 == 0xf00 goto pc+1
  verifier bug: REG INVARIANTS VIOLATION (false_reg1): range bounds violation u64=[0xe01, 0xe00] s64=[0xe01, 0xe00] u32=[0xe01, 0xe00] s32=[0xe01, 0xe00] var_off=(0xe00, 0x0)

We reach instruction 236 with two possible values for R9, 0xe00 and 0xf00. This is perfectly reflected in the tnum, but of course the ranges are less accurate and cover [0xe00; 0xf00]. Taking the fallthrough path at instruction 236 allows the verifier to reduce the range to [0xe01; 0xf00]. The tnum is however not updated.

With these ranges, at instruction 237, the verifier is not able to deduce that R9 is always equal to 0xf00. Hence the fallthrough pass is explored first, the verifier refines the bounds using the assumption that R9 != 0xf00, and ends up with an invariant violation.

This pattern of impossible branch + bounds refinement is common to all invariant violations seen so far. The long-term solution is likely to rely on the refinement + invariant violation check to detect dead branches, as started by Eduard. To fix the current issue, we need something with less refactoring that we can backport.

This patch uses the tnum_step helper introduced in the previous patch to detect the above situation. In particular, three cases are now detected in the bounds refinement:

1. The u64 range and the tnum only overlap in umin.
u64: ---[xxxxxx]-----
tnum: --xx----------x-

2. The u64 range and the tnum only overlap in the maximum value represented by the tnum, called tmax.
u64: ---[xxxxxx]-----
tnum: xx-----x--------

3. The u64 range and the tnum only overlap in between umin (excluded) and umax.
u64: ---[xxxxxx]-----
tnum: xx----x-------x-

To detect these three cases, we call tnum_step(tnum, umin), which returns the smallest member of the tnum greater than umin, called tnum_next here. We're in case (1) if umin is part of the tnum and tnum_next is greater than umax. We're in case (2) if umin is not part of the tnum and tnum_next is equal to tmax. Finally, we're in case (3) if umin is not part of the tnum, tnum_next is inferior or equal to umax, and calling tnum_step a second time gives us a value past umax.

This change implements these three cases. With it, the above bytecode looks as follows:

  0: (85) call bpf_get_prandom_u32#7    ; R0=scalar()
  1: (47) r0 |= 3584                    ; R0=scalar(smin=0x8000000000000e00,umin=umin32=3584,smin32=0x80000e00,var_off=(0xe00; 0xfffffffffffff1ff))
  2: (57) r0 &= 3840                    ; R0=scalar(smin=umin=smin32=umin32=3584,smax=umax=smax32=umax32=3840,var_off=(0xe00; 0x100))
  3: (15) if r0 == 0xe00 goto pc+2      ; R0=3840

4: (15) if r0 == 0xf00 goto pc+1
4: R0=3840
6: (95) exit

In addition to the new selftests, this change was also verified with Agni [3]. For the record, the raw SMT is available at [4]. The property it verifies is that: If a concrete value x is contained in all input abstract values, after __update_reg_bounds, it will continue to be contained in all output abstract values.

---
 kernel/bpf/verifier.c | 30 ++++++++++++++++++++++++++++++
 1 file changed, 30 insertions(+)
kernel/bpf/verifier.c +30 -0
index 449997aa77a06..e37ff28e3cd9d 100644
@@ -2347,6 +2347,9 @@ static void __update_reg32_bounds(struct bpf_reg_state *reg)
 
 static void __update_reg64_bounds(struct bpf_reg_state *reg)
 {
+	u64 tnum_next, tmax;
+	bool umin_in_tnum;
+
 	/* min signed is max(sign bit) | min(other bits) */
 	reg->smin_value = max_t(s64, reg->smin_value,
 				reg->var_off.value | (reg->var_off.mask & S64_MIN));
@@ -2356,6 +2359,33 @@ static void __update_reg64_bounds(struct bpf_reg_state *reg)
 	reg->umin_value = max(reg->umin_value, reg->var_off.value);
 	reg->umax_value = min(reg->umax_value,
 			      reg->var_off.value | reg->var_off.mask);
+
+	/* Check if u64 and tnum overlap in a single value */
+	tnum_next = tnum_step(reg->var_off, reg->umin_value);
+	umin_in_tnum = (reg->umin_value & ~reg->var_off.mask) == reg->var_off.value;
+	tmax = reg->var_off.value | reg->var_off.mask;
+	if (umin_in_tnum && tnum_next > reg->umax_value) {
+		/* The u64 range and the tnum only overlap in umin.
+		 * u64:  ---[xxxxxx]-----
+		 * tnum: --xx----------x-
+		 */
+		___mark_reg_known(reg, reg->umin_value);
+	} else if (!umin_in_tnum && tnum_next == tmax) {
+		/* The u64 range and the tnum only overlap in the maximum value
+		 * represented by the tnum, called tmax.
+		 * u64:  ---[xxxxxx]-----
+		 * tnum: xx-----x--------
+		 */
+		___mark_reg_known(reg, tmax);
+	} else if (!umin_in_tnum && tnum_next <= reg->umax_value &&
+		   tnum_step(reg->var_off, tnum_next) > reg->umax_value) {
+		/* The u64 range and the tnum only overlap in between umin
+		 * (excluded) and umax.
+		 * u64:  ---[xxxxxx]-----
+		 * tnum: xx----x-------x-
+		 */
+		___mark_reg_known(reg, tnum_next);
+	}
 }
 
 static void __update_reg_bounds(struct bpf_reg_state *reg)
Signature · 1 line
2.51.0
author maintainer
#77 lore raw

PATCH 73/314 x86/acpi/boot: Correct acpi_is_processor_usable() check again

In reply to Sasha Levin

From: Yazen Ghannam <[email protected]>

[ Upstream commit adbf61cc47cb72b102682e690ad323e1eda652c2 ]

ACPI v6.3 defined a new "Online Capable" MADT LAPIC flag. This bit is used in conjunction with the "Enabled" MADT LAPIC flag to determine if a CPU can be enabled/hotplugged by the OS after boot.

Before the new bit was defined, the "Enabled" bit was explicitly described like this (ACPI v6.0 wording provided):

"If zero, this processor is unusable, and the operating system support will not attempt to use it"

This means that CPU hotplug (based on MADT) is not possible. Many BIOS implementations follow this guidance. They may include LAPIC entries in MADT for unavailable CPUs, but since these entries are marked with "Enabled=0" it is expected that the OS will completely ignore these entries.

However, QEMU will do the same (include entries with "Enabled=0") for the purpose of allowing CPU hotplug within the guest.

Comment from QEMU function pc_madt_cpu_entry():

/* ACPI spec says that LAPIC entry for non present
* CPU may be omitted from MADT or it must be marked
* as disabled. However omitting non present CPU from
* MADT breaks hotplug on linux. So possible CPUs
* should be put in MADT but kept disabled. */

Recent Linux topology changes broke the QEMU use case. A following fix for the QEMU use case broke bare metal topology enumeration.

Rework the Linux MADT LAPIC flags check to allow the QEMU use case only for guests and to maintain the ACPI spec behavior for bare metal.

Remove an unnecessary check added to fix a bare metal case introduced by the QEMU "fix".

[ bp: Change logic as Michal suggested. ]
[ mingo: Removed misapplied -stable tag. ]

Fixes fed8d8773b8e ("x86/acpi/boot: Correct acpi_is_processor_usable() check")
Fixes f0551af02130 ("x86/topology: Ignore non-present APIC IDs in a present package")
---
 arch/x86/kernel/acpi/boot.c    | 12 ++++++++----
 arch/x86/kernel/cpu/topology.c | 15 ---------------
 2 files changed, 8 insertions(+), 19 deletions(-)
arch/x86/kernel/acpi/boot.c +8 -4
index 9fa321a95eb33..d6138b2b633a3 100644
@@ -35,6 +35,7 @@
 #include <asm/smp.h>
 #include <asm/i8259.h>
 #include <asm/setup.h>
+#include <asm/hypervisor.h>
 
 #include "sleep.h" /* To include x86_acpi_suspend_lowlevel */
 static int __initdata acpi_force = 0;
@@ -164,11 +165,14 @@ static bool __init acpi_is_processor_usable(u32 lapic_flags)
 	if (lapic_flags & ACPI_MADT_ENABLED)
 		return true;
 
-	if (!acpi_support_online_capable ||
-	    (lapic_flags & ACPI_MADT_ONLINE_CAPABLE))
-		return true;
+	if (acpi_support_online_capable)
+		return lapic_flags & ACPI_MADT_ONLINE_CAPABLE;
 
-	return false;
+	/*
+	 * QEMU expects legacy "Enabled=0" LAPIC entries to be counted as usable
+	 * in order to support CPU hotplug in guests.
+	 */
+	return !hypervisor_is_type(X86_HYPER_NATIVE);
 }
 
 static int __init
arch/x86/kernel/cpu/topology.c +0 -15
index 6073a16628f9e..425404e7b7b42 100644
@@ -27,7 +27,6 @@
 #include <xen/xen.h>
 
 #include <asm/apic.h>
-#include <asm/hypervisor.h>
 #include <asm/io_apic.h>
 #include <asm/mpspec.h>
 #include <asm/msr.h>
@@ -240,20 +239,6 @@ static __init void topo_register_apic(u32 apic_id, u32 acpi_id, bool present)
 		cpuid_to_apicid[cpu] = apic_id;
 		topo_set_cpuids(cpu, apic_id, acpi_id);
 	} else {
-		u32 pkgid = topo_apicid(apic_id, TOPO_PKG_DOMAIN);
-
-		/*
-		 * Check for present APICs in the same package when running
-		 * on bare metal. Allow the bogosity in a guest.
-		 */
-		if (hypervisor_is_type(X86_HYPER_NATIVE) &&
-		    topo_unit_count(pkgid, TOPO_PKG_DOMAIN, phys_cpu_present_map)) {
-			pr_info_once("Ignoring hot-pluggable APIC ID %x in present package.\n",
-				     apic_id);
-			topo_info.nr_rejected_cpus++;
-			return;
-		}
-
 		topo_info.nr_disabled_cpus++;
 	}
 
Signature · 1 line
2.51.0
author maintainer
#78 lore raw

PATCH 74/314 memory: mtk-smi: fix device leaks on common probe

In reply to Sasha Levin

From: Johan Hovold <[email protected]>

[ Upstream commit 6cfa038bddd710f544076ea2ef7792fc82fbedd6 ]

Make sure to drop the reference taken when looking up the SMI device during common probe on late probe failure (e.g. probe deferral) and on driver unbind.

Fixes 47404757702e ("memory: mtk-smi: Add device link for smi-sub-common")
Fixes 038ae37c510f ("memory: mtk-smi: add missing put_device() call in mtk_smi_device_link_common")
Cc [email protected] # 5.16: 038ae37c510f
Cc Yong Wu <[email protected]>
Cc Miaoqian Lin <[email protected]>
---
 drivers/memory/mtk-smi.c | 2 ++
 1 file changed, 2 insertions(+)
drivers/memory/mtk-smi.c +2 -0
index 733e22f695ab7..dd6150d200e89 100644
@@ -674,6 +674,7 @@ static int mtk_smi_larb_probe(struct platform_device *pdev)
 err_pm_disable:
 	pm_runtime_disable(dev);
 	device_link_remove(dev, larb->smi_common_dev);
+	put_device(larb->smi_common_dev);
 	return ret;
 }
 
@@ -917,6 +918,7 @@ static void mtk_smi_common_remove(struct platform_device *pdev)
 	if (common->plat->type == MTK_SMI_GEN2_SUB_COMM)
 		device_link_remove(&pdev->dev, common->smi_common_dev);
 	pm_runtime_disable(&pdev->dev);
+	put_device(common->smi_common_dev);
 }
 
 static int __maybe_unused mtk_smi_common_resume(struct device *dev)
Signature · 1 line
2.51.0
author maintainer
#79 lore raw

PATCH 75/314 memory: mtk-smi: fix device leak on larb probe

In reply to Sasha Levin

From: Johan Hovold <[email protected]>

[ Upstream commit 9dae65913b32d05dbc8ff4b8a6bf04a0e49a8eb6 ]

Make sure to drop the reference taken when looking up the SMI device during larb probe on late probe failure (e.g. probe deferral) and on driver unbind.

Fixes cc8bbe1a8312 ("memory: mediatek: Add SMI driver")
Fixes 038ae37c510f ("memory: mtk-smi: add missing put_device() call in mtk_smi_device_link_common")
Cc [email protected] # 4.6: 038ae37c510f
Cc Yong Wu <[email protected]>
Cc Miaoqian Lin <[email protected]>
---
 drivers/memory/mtk-smi.c | 1 +
 1 file changed, 1 insertion(+)
drivers/memory/mtk-smi.c +1 -0
index dd6150d200e89..3609bfd3c64be 100644
@@ -685,6 +685,7 @@ static void mtk_smi_larb_remove(struct platform_device *pdev)
 	device_link_remove(&pdev->dev, larb->smi_common_dev);
 	pm_runtime_disable(&pdev->dev);
 	component_del(&pdev->dev, &mtk_smi_larb_component_ops);
+	put_device(larb->smi_common_dev);
 }
 
 static int __maybe_unused mtk_smi_larb_resume(struct device *dev)
Signature · 1 line
2.51.0
author maintainer
#80 lore raw

PATCH 76/314 PCI: j721e: Use devm_clk_get_optional_enabled() to get and enable the clock

In reply to Sasha Levin

From: Anand Moon <[email protected]>

[ Upstream commit 6fad11c61d0dbf87601ab9e2e37cba7a9a427f7b ]

Use devm_clk_get_optional_enabled() helper instead of calling devm_clk_get_optional() and then clk_prepare_enable().

Assign the result of devm_clk_get_optional_enabled() directly to pcie->refclk to avoid using a local 'clk' variable.

Stable-dep-of: 4b361b1e92be ("PCI: j721e: Add config guards for Cadence Host and Endpoint library APIs")

---
 drivers/pci/controller/cadence/pci-j721e.c | 20 +++++---------------
 1 file changed, 5 insertions(+), 15 deletions(-)
drivers/pci/controller/cadence/pci-j721e.c +5 -15
index 5bc5ab20aa6d9..a88b2e52fd782 100644
@@ -479,7 +479,6 @@ static int j721e_pcie_probe(struct platform_device *pdev)
 	struct cdns_pcie_ep *ep = NULL;
 	struct gpio_desc *gpiod;
 	void __iomem *base;
-	struct clk *clk;
 	u32 num_lanes;
 	u32 mode;
 	int ret;
@@ -603,19 +602,13 @@ static int j721e_pcie_probe(struct platform_device *pdev)
 			goto err_get_sync;
 		}
 
-		clk = devm_clk_get_optional(dev, "pcie_refclk");
-		if (IS_ERR(clk)) {
-			ret = dev_err_probe(dev, PTR_ERR(clk), "failed to get pcie_refclk\n");
+		pcie->refclk = devm_clk_get_optional_enabled(dev, "pcie_refclk");
+		if (IS_ERR(pcie->refclk)) {
+			ret = dev_err_probe(dev, PTR_ERR(pcie->refclk),
+					    "failed to enable pcie_refclk\n");
 			goto err_pcie_setup;
 		}
 
-		ret = clk_prepare_enable(clk);
-		if (ret) {
-			dev_err_probe(dev, ret, "failed to enable pcie_refclk\n");
-			goto err_pcie_setup;
-		}
-		pcie->refclk = clk;
-
 		/*
 		 * Section 2.2 of the PCI Express Card Electromechanical
 		 * Specification (Revision 5.1) mandates that the deassertion
@@ -629,10 +622,8 @@ static int j721e_pcie_probe(struct platform_device *pdev)
 		}
 
 		ret = cdns_pcie_host_setup(rc);
-		if (ret < 0) {
-			clk_disable_unprepare(pcie->refclk);
+		if (ret < 0)
 			goto err_pcie_setup;
-		}
 
 		break;
 	case PCI_MODE_EP:
@@ -679,7 +670,6 @@ static void j721e_pcie_remove(struct platform_device *pdev)
 
 	gpiod_set_value_cansleep(pcie->reset_gpio, 0);
 
-	clk_disable_unprepare(pcie->refclk);
 	cdns_pcie_disable_phy(cdns_pcie);
 	j721e_pcie_disable_link_irq(pcie);
 	pm_runtime_put(dev);
Signature · 1 line
2.51.0
author maintainer
#81 lore raw

PATCH 77/314 PCI: j721e: Add config guards for Cadence Host and Endpoint library APIs

In reply to Sasha Levin

From: Siddharth Vadapalli <[email protected]>

[ Upstream commit 4b361b1e92be255ff923453fe8db74086cc7cf66 ]

Commit under Fixes enabled loadable module support for the driver under the assumption that it shall be the sole user of the Cadence Host and Endpoint library APIs. This assumption guarantees that we won't end up in a case where the driver is built-in and the library support is built as a loadable module.

With the introduction of [1], this assumption is no longer valid. The SG2042 driver could be built as a loadable module, implying that the Cadence Host library is also selected as a loadable module. However, the pci-j721e.c driver could be built-in as indicated by CONFIG_PCI_J721E=y due to which the Cadence Endpoint library is built-in. Despite the library drivers being built as specified by their respective consumers, since the 'pci-j721e.c' driver has references to the Cadence Host library APIs as well, we run into a build error as reported at [0].

Fix this by adding config guards as a temporary workaround. The proper fix is to split the 'pci-j721e.c' driver into independent Host and Endpoint drivers as aligned at [2].

[0]: https://lore.kernel.org/r/[email protected]/
[1]: commit 1c72774df028 ("PCI: sg2042: Add Sophgo SG2042 PCIe driver") [2]: https://lore.kernel.org/r/[email protected]/

---
 drivers/pci/controller/cadence/pci-j721e.c | 41 +++++++++++++---------
 1 file changed, 25 insertions(+), 16 deletions(-)
drivers/pci/controller/cadence/pci-j721e.c +25 -16
index a88b2e52fd782..0413d163cfea0 100644
@@ -621,9 +621,11 @@ static int j721e_pcie_probe(struct platform_device *pdev)
 			gpiod_set_value_cansleep(gpiod, 1);
 		}
 
-		ret = cdns_pcie_host_setup(rc);
-		if (ret < 0)
-			goto err_pcie_setup;
+		if (IS_ENABLED(CONFIG_PCI_J721E_HOST)) {
+			ret = cdns_pcie_host_setup(rc);
+			if (ret < 0)
+				goto err_pcie_setup;
+		}
 
 		break;
 	case PCI_MODE_EP:
@@ -633,9 +635,11 @@ static int j721e_pcie_probe(struct platform_device *pdev)
 			goto err_get_sync;
 		}
 
-		ret = cdns_pcie_ep_setup(ep);
-		if (ret < 0)
-			goto err_pcie_setup;
+		if (IS_ENABLED(CONFIG_PCI_J721E_EP)) {
+			ret = cdns_pcie_ep_setup(ep);
+			if (ret < 0)
+				goto err_pcie_setup;
+		}
 
 		break;
 	}
@@ -660,10 +664,11 @@ static void j721e_pcie_remove(struct platform_device *pdev)
 	struct cdns_pcie_ep *ep;
 	struct cdns_pcie_rc *rc;
 
-	if (pcie->mode == PCI_MODE_RC) {
+	if (IS_ENABLED(CONFIG_PCI_J721E_HOST) &&
+	    pcie->mode == PCI_MODE_RC) {
 		rc = container_of(cdns_pcie, struct cdns_pcie_rc, pcie);
 		cdns_pcie_host_disable(rc);
-	} else {
+	} else if (IS_ENABLED(CONFIG_PCI_J721E_EP)) {
 		ep = container_of(cdns_pcie, struct cdns_pcie_ep, pcie);
 		cdns_pcie_ep_disable(ep);
 	}
@@ -729,10 +734,12 @@ static int j721e_pcie_resume_noirq(struct device *dev)
 			gpiod_set_value_cansleep(pcie->reset_gpio, 1);
 		}
 
-		ret = cdns_pcie_host_link_setup(rc);
-		if (ret < 0) {
-			clk_disable_unprepare(pcie->refclk);
-			return ret;
+		if (IS_ENABLED(CONFIG_PCI_J721E_HOST)) {
+			ret = cdns_pcie_host_link_setup(rc);
+			if (ret < 0) {
+				clk_disable_unprepare(pcie->refclk);
+				return ret;
+			}
 		}
 
 		/*
@@ -742,10 +749,12 @@ static int j721e_pcie_resume_noirq(struct device *dev)
 		for (enum cdns_pcie_rp_bar bar = RP_BAR0; bar <= RP_NO_BAR; bar++)
 			rc->avail_ib_bar[bar] = true;
 
-		ret = cdns_pcie_host_init(rc);
-		if (ret) {
-			clk_disable_unprepare(pcie->refclk);
-			return ret;
+		if (IS_ENABLED(CONFIG_PCI_J721E_HOST)) {
+			ret = cdns_pcie_host_init(rc);
+			if (ret) {
+				clk_disable_unprepare(pcie->refclk);
+				return ret;
+			}
 		}
 	}
 
Signature · 1 line
2.51.0
author maintainer
#82 lore raw

PATCH 78/314 PCI: dwc: Advertise L1 PM Substates only if driver requests it

In reply to Sasha Levin

From: Bjorn Helgaas <[email protected]>

[ Upstream commit a00bba406b5a682764ecb507e580ca8159196aa3 ]

L1 PM Substates require the CLKREQ# signal and may also require device-specific support. If CLKREQ# is not supported or driver support is lacking, enabling L1.1 or L1.2 may cause errors when accessing devices, e.g.,

nvme nvme0: controller is down; will reset: CSTS=0xffffffff, PCI_STATUS=0x10

If the kernel is built with CONFIG_PCIEASPM_POWER_SUPERSAVE=y or users enable L1.x via sysfs, users may trip over these errors even if L1 Substates haven't been enabled by firmware or the driver.

To prevent such errors, disable advertising the L1 PM Substates unless the driver sets "dw_pcie.l1ss_support" to indicate that it knows CLKREQ# is present and any device-specific configuration has been done.

Set "dw_pcie.l1ss_support" in tegra194 (if DT includes the "supports-clkreq' property) and qcom (for cfg_2_7_0, cfg_1_9_0, cfg_1_34_0, and cfg_sc8280xp controllers) so they can continue to use L1 Substates.

Based on Niklas's patch:
https://patch.msgid.link/[email protected]

Stable-dep-of: 180c3cfe3678 ("Revert "PCI: dw-rockchip: Enumerate endpoints based on dll_link_up IRQ"")

---
 .../pci/controller/dwc/pcie-designware-host.c |  2 ++
 drivers/pci/controller/dwc/pcie-designware.c  | 24 +++++++++++++++++++
 drivers/pci/controller/dwc/pcie-designware.h  |  2 ++
 drivers/pci/controller/dwc/pcie-qcom.c        |  2 ++
 drivers/pci/controller/dwc/pcie-tegra194.c    |  3 +++
 5 files changed, 33 insertions(+)
drivers/pci/controller/dwc/pcie-designware-host.c +2 -0
index 925d5f818f12b..894bf23529df5 100644
@@ -1081,6 +1081,8 @@ int dw_pcie_setup_rc(struct dw_pcie_rp *pp)
 		PCI_COMMAND_MASTER | PCI_COMMAND_SERR;
 	dw_pcie_writel_dbi(pci, PCI_COMMAND, val);
 
+	dw_pcie_hide_unsupported_l1ss(pci);
+
 	dw_pcie_config_presets(pp);
 	/*
 	 * If the platform provides its own child bus config accesses, it means
drivers/pci/controller/dwc/pcie-designware.c +24 -0
index 06eca858eb1b3..75fc8b767fccf 100644
@@ -1083,6 +1083,30 @@ void dw_pcie_edma_remove(struct dw_pcie *pci)
 	dw_edma_remove(&pci->edma);
 }
 
+void dw_pcie_hide_unsupported_l1ss(struct dw_pcie *pci)
+{
+	u16 l1ss;
+	u32 l1ss_cap;
+
+	if (pci->l1ss_support)
+		return;
+
+	l1ss = dw_pcie_find_ext_capability(pci, PCI_EXT_CAP_ID_L1SS);
+	if (!l1ss)
+		return;
+
+	/*
+	 * Unless the driver claims "l1ss_support", don't advertise L1 PM
+	 * Substates because they require CLKREQ# and possibly other
+	 * device-specific configuration.
+	 */
+	l1ss_cap = dw_pcie_readl_dbi(pci, l1ss + PCI_L1SS_CAP);
+	l1ss_cap &= ~(PCI_L1SS_CAP_PCIPM_L1_1 | PCI_L1SS_CAP_ASPM_L1_1 |
+		      PCI_L1SS_CAP_PCIPM_L1_2 | PCI_L1SS_CAP_ASPM_L1_2 |
+		      PCI_L1SS_CAP_L1_PM_SS);
+	dw_pcie_writel_dbi(pci, l1ss + PCI_L1SS_CAP, l1ss_cap);
+}
+
 void dw_pcie_setup(struct dw_pcie *pci)
 {
 	u32 val;
drivers/pci/controller/dwc/pcie-designware.h +2 -0
index 96e89046614da..82336a204569f 100644
@@ -516,6 +516,7 @@ struct dw_pcie {
 	int			max_link_speed;
 	u8			n_fts[2];
 	struct dw_edma_chip	edma;
+	bool			l1ss_support;	/* L1 PM Substates support */
 	struct clk_bulk_data	app_clks[DW_PCIE_NUM_APP_CLKS];
 	struct clk_bulk_data	core_clks[DW_PCIE_NUM_CORE_CLKS];
 	struct reset_control_bulk_data	app_rsts[DW_PCIE_NUM_APP_RSTS];
@@ -573,6 +574,7 @@ int dw_pcie_prog_ep_inbound_atu(struct dw_pcie *pci, u8 func_no, int index,
 				int type, u64 parent_bus_addr,
 				u8 bar, size_t size);
 void dw_pcie_disable_atu(struct dw_pcie *pci, u32 dir, int index);
+void dw_pcie_hide_unsupported_l1ss(struct dw_pcie *pci);
 void dw_pcie_setup(struct dw_pcie *pci);
 void dw_pcie_iatu_detect(struct dw_pcie *pci);
 int dw_pcie_edma_detect(struct dw_pcie *pci);
drivers/pci/controller/dwc/pcie-qcom.c +2 -0
index 5311cd5d96372..789cc0e3c10da 100644
@@ -1005,6 +1005,8 @@ static int qcom_pcie_init_2_7_0(struct qcom_pcie *pcie)
 	val &= ~REQ_NOT_ENTR_L1;
 	writel(val, pcie->parf + PARF_PM_CTRL);
 
+	pci->l1ss_support = true;
+
 	val = readl(pcie->parf + PARF_AXI_MSTR_WR_ADDR_HALT_V2);
 	val |= EN;
 	writel(val, pcie->parf + PARF_AXI_MSTR_WR_ADDR_HALT_V2);
drivers/pci/controller/dwc/pcie-tegra194.c +3 -0
index 10e74458e667b..3934757baa30c 100644
@@ -703,6 +703,9 @@ static void init_host_aspm(struct tegra_pcie_dw *pcie)
 	val |= (pcie->aspm_pwr_on_t << 19);
 	dw_pcie_writel_dbi(pci, pcie->cfg_link_cap_l1sub, val);
 
+	if (pcie->supports_clkreq)
+		pci->l1ss_support = true;
+
 	/* Program L0s and L1 entrance latencies */
 	val = dw_pcie_readl_dbi(pci, PCIE_PORT_AFR);
 	val &= ~PORT_AFR_L0S_ENTRANCE_LAT_MASK;
Signature · 1 line
2.51.0
author maintainer
#83 lore raw

PATCH 79/314 PCI: dw-rockchip: Configure L1SS support

In reply to Sasha Levin

From: Shawn Lin <[email protected]>

[ Upstream commit b5e719f26107f4a7f82946dc5be92dceb9b443cb ]

L1 PM Substates for RC mode require support in the dw-rockchip driver including proper handling of the CLKREQ# sideband signal. It is mostly handled by hardware, but software still needs to set the clkreq fields in the PCIE_CLIENT_POWER_CON register to match the hardware implementation.

For more details, see section '18.6.6.4 L1 Substate' in the RK3568 TRM 1.1 Part 2, or section '11.6.6.4 L1 Substate' in the RK3588 TRM 1.0 Part2.

[bhelgaas: set pci->l1ss_support so DWC core preserves L1SS Capability bits; drop corresponding code here, include updates from
https://lore.kernel.org/r/aRRG8wv13HxOCqgA@ryzen]

Stable-dep-of: 180c3cfe3678 ("Revert "PCI: dw-rockchip: Enumerate endpoints based on dll_link_up IRQ"")

---
 drivers/pci/controller/dwc/pcie-dw-rockchip.c | 40 +++++++++++++++++++
 1 file changed, 40 insertions(+)
drivers/pci/controller/dwc/pcie-dw-rockchip.c +40 -0
index 7be6351686e21..85999fc316c9f 100644
@@ -62,6 +62,12 @@
 /* Interrupt Mask Register Related to Miscellaneous Operation */
 #define PCIE_CLIENT_INTR_MASK_MISC	0x24
 
+/* Power Management Control Register */
+#define PCIE_CLIENT_POWER_CON		0x2c
+#define  PCIE_CLKREQ_READY		FIELD_PREP_WM16(BIT(0), 1)
+#define  PCIE_CLKREQ_NOT_READY		FIELD_PREP_WM16(BIT(0), 0)
+#define  PCIE_CLKREQ_PULL_DOWN		FIELD_PREP_WM16(GENMASK(13, 12), 1)
+
 /* Hot Reset Control Register */
 #define PCIE_CLIENT_HOT_RESET_CTRL	0x180
 #define  PCIE_LTSSM_APP_DLY2_EN		BIT(1)
@@ -87,6 +93,7 @@ struct rockchip_pcie {
 	struct regulator *vpcie3v3;
 	struct irq_domain *irq_domain;
 	const struct rockchip_pcie_of_data *data;
+	bool supports_clkreq;
 };
 
 struct rockchip_pcie_of_data {
@@ -202,6 +209,35 @@ static bool rockchip_pcie_link_up(struct dw_pcie *pci)
 	return FIELD_GET(PCIE_LINKUP_MASK, val) == PCIE_LINKUP;
 }
 
+/*
+ * See e.g. section '11.6.6.4 L1 Substate' in the RK3588 TRM V1.0 for the steps
+ * needed to support L1 substates. Currently, just enable L1 substates for RC
+ * mode if CLKREQ# is properly connected and supports-clkreq is present in DT.
+ * For EP mode, there are more things should be done to actually save power in
+ * L1 substates, so disable L1 substates until there is proper support.
+ */
+static void rockchip_pcie_configure_l1ss(struct dw_pcie *pci)
+{
+	struct rockchip_pcie *rockchip = to_rockchip_pcie(pci);
+
+	/* Enable L1 substates if CLKREQ# is properly connected */
+	if (rockchip->supports_clkreq) {
+		rockchip_pcie_writel_apb(rockchip, PCIE_CLKREQ_READY,
+					 PCIE_CLIENT_POWER_CON);
+		pci->l1ss_support = true;
+		return;
+	}
+
+	/*
+	 * Otherwise, assert CLKREQ# unconditionally.  Since
+	 * pci->l1ss_support is not set, the DWC core will prevent L1
+	 * Substates support from being advertised.
+	 */
+	rockchip_pcie_writel_apb(rockchip,
+				 PCIE_CLKREQ_PULL_DOWN | PCIE_CLKREQ_NOT_READY,
+				 PCIE_CLIENT_POWER_CON);
+}
+
 static void rockchip_pcie_enable_l0s(struct dw_pcie *pci)
 {
 	u32 cap, lnkcap;
@@ -268,6 +304,7 @@ static int rockchip_pcie_host_init(struct dw_pcie_rp *pp)
 	irq_set_chained_handler_and_data(irq, rockchip_pcie_intx_handler,
 					 rockchip);
 
+	rockchip_pcie_configure_l1ss(pci);
 	rockchip_pcie_enable_l0s(pci);
 
 	/* Disable Root Ports BAR0 and BAR1 as they report bogus size */
@@ -420,6 +457,9 @@ static int rockchip_pcie_resource_get(struct platform_device *pdev,
 		return dev_err_probe(&pdev->dev, PTR_ERR(rockchip->rst),
 				     "failed to get reset lines\n");
 
+	rockchip->supports_clkreq = of_property_read_bool(pdev->dev.of_node,
+							  "supports-clkreq");
+
 	return 0;
 }
 
Signature · 1 line
2.51.0
author maintainer
#84 lore raw

PATCH 80/314 PCI: dwc: Add L1 Substates context to ltssm_status of debugfs

In reply to Sasha Levin

From: Shawn Lin <[email protected]>

[ Upstream commit 679ec639f29cbdaf36bd79bf3e98240fffa335ee ]

DWC core couldn't distinguish LTSSM state among L1.0, L1.1 and L1.2. But the vendor glue driver may implement additional logic to convey this information. So add two pseudo definitions for vendor glue drivers to translate their internal L1 Substates for debugfs to show.

Stable-dep-of: 180c3cfe3678 ("Revert "PCI: dw-rockchip: Enumerate endpoints based on dll_link_up IRQ"")

---
 drivers/pci/controller/dwc/pcie-designware-debugfs.c | 2 ++
 drivers/pci/controller/dwc/pcie-designware.h         | 4 ++++
 2 files changed, 6 insertions(+)
drivers/pci/controller/dwc/pcie-designware-debugfs.c +2 -0
index 0fbf86c0b97e0..df98fee69892b 100644
@@ -485,6 +485,8 @@ static const char *ltssm_status_string(enum dw_pcie_ltssm ltssm)
 	DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_RCVRY_EQ1);
 	DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_RCVRY_EQ2);
 	DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_RCVRY_EQ3);
+	DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_L1_1);
+	DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_L1_2);
 	default:
 		str = "DW_PCIE_LTSSM_UNKNOWN";
 		break;
drivers/pci/controller/dwc/pcie-designware.h +4 -0
index 82336a204569f..6c04ac0196794 100644
@@ -380,6 +380,10 @@ enum dw_pcie_ltssm {
 	DW_PCIE_LTSSM_RCVRY_EQ2 = 0x22,
 	DW_PCIE_LTSSM_RCVRY_EQ3 = 0x23,
 
+	/* Vendor glue drivers provide pseudo L1 substates from get_ltssm() */
+	DW_PCIE_LTSSM_L1_1 = 0x141,
+	DW_PCIE_LTSSM_L1_2 = 0x142,
+
 	DW_PCIE_LTSSM_UNKNOWN = 0xFFFFFFFF,
 };
 
Signature · 1 line
2.51.0
author maintainer
#85 lore raw

PATCH 81/314 PCI: dw-rockchip: Change get_ltssm() to provide L1 Substates info

In reply to Sasha Levin

From: Shawn Lin <[email protected]>

[ Upstream commit f994bb8f1c94726e0124356ccd31c3c23a8a69f4 ]

Rename rockchip_pcie_get_ltssm() to rockchip_pcie_get_ltssm_reg() and add rockchip_pcie_get_ltssm() to get_ltssm() callback in order to show the proper L1 Substates. The PCIE_CLIENT_LTSSM_STATUS[5:0] register returns the same LTSSM layout as enum dw_pcie_ltssm. So the driver just need to convey L1 PM Substates by returning the proper value defined in pcie-designware.h.

cat /sys/kernel/debug/dwc_pcie_a40000000.pcie/ltssm_status L1_2 (0x142)

Stable-dep-of: 180c3cfe3678 ("Revert "PCI: dw-rockchip: Enumerate endpoints based on dll_link_up IRQ"")

---
 drivers/pci/controller/dwc/pcie-dw-rockchip.c | 29 ++++++++++++++++---
 1 file changed, 25 insertions(+), 4 deletions(-)
drivers/pci/controller/dwc/pcie-dw-rockchip.c +25 -4
index 85999fc316c9f..0a5d1cfb88437 100644
@@ -68,6 +68,11 @@
 #define  PCIE_CLKREQ_NOT_READY		FIELD_PREP_WM16(BIT(0), 0)
 #define  PCIE_CLKREQ_PULL_DOWN		FIELD_PREP_WM16(GENMASK(13, 12), 1)
 
+/* RASDES TBA information */
+#define PCIE_CLIENT_CDM_RASDES_TBA_INFO_CMN	0x154
+#define  PCIE_CLIENT_CDM_RASDES_TBA_L1_1	BIT(4)
+#define  PCIE_CLIENT_CDM_RASDES_TBA_L1_2	BIT(5)
+
 /* Hot Reset Control Register */
 #define PCIE_CLIENT_HOT_RESET_CTRL	0x180
 #define  PCIE_LTSSM_APP_DLY2_EN		BIT(1)
@@ -184,11 +189,26 @@ static int rockchip_pcie_init_irq_domain(struct rockchip_pcie *rockchip)
 	return 0;
 }
 
-static u32 rockchip_pcie_get_ltssm(struct rockchip_pcie *rockchip)
+static u32 rockchip_pcie_get_ltssm_reg(struct rockchip_pcie *rockchip)
 {
 	return rockchip_pcie_readl_apb(rockchip, PCIE_CLIENT_LTSSM_STATUS);
 }
 
+static enum dw_pcie_ltssm rockchip_pcie_get_ltssm(struct dw_pcie *pci)
+{
+	struct rockchip_pcie *rockchip = to_rockchip_pcie(pci);
+	u32 val = rockchip_pcie_readl_apb(rockchip,
+			PCIE_CLIENT_CDM_RASDES_TBA_INFO_CMN);
+
+	if (val & PCIE_CLIENT_CDM_RASDES_TBA_L1_1)
+		return DW_PCIE_LTSSM_L1_1;
+
+	if (val & PCIE_CLIENT_CDM_RASDES_TBA_L1_2)
+		return DW_PCIE_LTSSM_L1_2;
+
+	return rockchip_pcie_get_ltssm_reg(rockchip) & PCIE_LTSSM_STATUS_MASK;
+}
+
 static void rockchip_pcie_enable_ltssm(struct rockchip_pcie *rockchip)
 {
 	rockchip_pcie_writel_apb(rockchip, PCIE_CLIENT_ENABLE_LTSSM,
@@ -204,7 +224,7 @@ static void rockchip_pcie_disable_ltssm(struct rockchip_pcie *rockchip)
 static bool rockchip_pcie_link_up(struct dw_pcie *pci)
 {
 	struct rockchip_pcie *rockchip = to_rockchip_pcie(pci);
-	u32 val = rockchip_pcie_get_ltssm(rockchip);
+	u32 val = rockchip_pcie_get_ltssm_reg(rockchip);
 
 	return FIELD_GET(PCIE_LINKUP_MASK, val) == PCIE_LINKUP;
 }
@@ -494,6 +514,7 @@ static const struct dw_pcie_ops dw_pcie_ops = {
 	.link_up = rockchip_pcie_link_up,
 	.start_link = rockchip_pcie_start_link,
 	.stop_link = rockchip_pcie_stop_link,
+	.get_ltssm = rockchip_pcie_get_ltssm,
 };
 
 static irqreturn_t rockchip_pcie_rc_sys_irq_thread(int irq, void *arg)
@@ -508,7 +529,7 @@ static irqreturn_t rockchip_pcie_rc_sys_irq_thread(int irq, void *arg)
 	rockchip_pcie_writel_apb(rockchip, reg, PCIE_CLIENT_INTR_STATUS_MISC);
 
 	dev_dbg(dev, "PCIE_CLIENT_INTR_STATUS_MISC: %#x\n", reg);
-	dev_dbg(dev, "LTSSM_STATUS: %#x\n", rockchip_pcie_get_ltssm(rockchip));
+	dev_dbg(dev, "LTSSM_STATUS: %#x\n", rockchip_pcie_get_ltssm_reg(rockchip));
 
 	if (reg & PCIE_RDLH_LINK_UP_CHGED) {
 		if (rockchip_pcie_link_up(pci)) {
@@ -535,7 +556,7 @@ static irqreturn_t rockchip_pcie_ep_sys_irq_thread(int irq, void *arg)
 	rockchip_pcie_writel_apb(rockchip, reg, PCIE_CLIENT_INTR_STATUS_MISC);
 
 	dev_dbg(dev, "PCIE_CLIENT_INTR_STATUS_MISC: %#x\n", reg);
-	dev_dbg(dev, "LTSSM_STATUS: %#x\n", rockchip_pcie_get_ltssm(rockchip));
+	dev_dbg(dev, "LTSSM_STATUS: %#x\n", rockchip_pcie_get_ltssm_reg(rockchip));
 
 	if (reg & PCIE_LINK_REQ_RST_NOT_INT) {
 		dev_dbg(dev, "hot reset or link-down reset\n");
Signature · 1 line
2.51.0
author maintainer
#86 lore raw

PATCH 82/314 Revert "PCI: dw-rockchip: Enumerate endpoints based on dll_link_up IRQ"

In reply to Sasha Levin

From: Niklas Cassel <[email protected]>

[ Upstream commit 180c3cfe36786d261a55da52a161f9e279b19a6f ]

This reverts commit 0e0b45ab5d770a748487ba0ae8f77d1fb0f0de3e.

While this fake hotplugging was a nice idea, it has shown that this feature
does not handle PCIe switches correctly:
pci_bus 0004:43: busn_res: can not insert [bus 43-41] under [bus 42-41] (conflicts with (null) [bus 42-41]) pci_bus 0004:43: busn_res: [bus 43-41] end is updated to 43
pci_bus 0004:43: busn_res: can not insert [bus 43] under [bus 42-41] (conflicts with (null) [bus 42-41]) pci 0004:42:00.0: devices behind bridge are unusable because [bus 43] cannot be assigned for them pci_bus 0004:44: busn_res: can not insert [bus 44-41] under [bus 42-41] (conflicts with (null) [bus 42-41]) pci_bus 0004:44: busn_res: [bus 44-41] end is updated to 44
pci_bus 0004:44: busn_res: can not insert [bus 44] under [bus 42-41] (conflicts with (null) [bus 42-41]) pci 0004:42:02.0: devices behind bridge are unusable because [bus 44] cannot be assigned for them pci_bus 0004:45: busn_res: can not insert [bus 45-41] under [bus 42-41] (conflicts with (null) [bus 42-41]) pci_bus 0004:45: busn_res: [bus 45-41] end is updated to 45
pci_bus 0004:45: busn_res: can not insert [bus 45] under [bus 42-41] (conflicts with (null) [bus 42-41]) pci 0004:42:06.0: devices behind bridge are unusable because [bus 45] cannot be assigned for them pci_bus 0004:46: busn_res: can not insert [bus 46-41] under [bus 42-41] (conflicts with (null) [bus 42-41]) pci_bus 0004:46: busn_res: [bus 46-41] end is updated to 46
pci_bus 0004:46: busn_res: can not insert [bus 46] under [bus 42-41] (conflicts with (null) [bus 42-41]) pci 0004:42:0e.0: devices behind bridge are unusable because [bus 46] cannot be assigned for them pci_bus 0004:42: busn_res: [bus 42-41] end is updated to 46
pci_bus 0004:42: busn_res: can not insert [bus 42-46] under [bus 41] (conflicts with (null) [bus 41]) pci 0004:41:00.0: devices behind bridge are unusable because [bus 42-46] cannot be assigned for them pcieport 0004:40:00.0: bridge has subordinate 41 but max busn 46

During the initial scan, PCI core doesn't see the switch and since the Root Port is not hot plug capable, the secondary bus number gets assigned as the subordinate bus number. This means, the PCI core assumes that only one bus will appear behind the Root Port since the Root Port is not hot plug capable.

This works perfectly fine for PCIe endpoints connected to the Root Port, since they don't extend the bus. However, if a PCIe switch is connected, then there is a problem when the downstream busses starts showing up and the PCI core doesn't extend the subordinate bus number and bridge resources after initial scan during boot.

The long term plan is to migrate this driver to the upcoming pwrctrl APIs that are supposed to handle this problem elegantly.

---
 drivers/pci/controller/dwc/pcie-dw-rockchip.c | 59 +------------------
 1 file changed, 3 insertions(+), 56 deletions(-)
drivers/pci/controller/dwc/pcie-dw-rockchip.c +3 -56
index 0a5d1cfb88437..b5442ee2920e5 100644
@@ -517,34 +517,6 @@ static const struct dw_pcie_ops dw_pcie_ops = {
 	.get_ltssm = rockchip_pcie_get_ltssm,
 };
 
-static irqreturn_t rockchip_pcie_rc_sys_irq_thread(int irq, void *arg)
-{
-	struct rockchip_pcie *rockchip = arg;
-	struct dw_pcie *pci = &rockchip->pci;
-	struct dw_pcie_rp *pp = &pci->pp;
-	struct device *dev = pci->dev;
-	u32 reg;
-
-	reg = rockchip_pcie_readl_apb(rockchip, PCIE_CLIENT_INTR_STATUS_MISC);
-	rockchip_pcie_writel_apb(rockchip, reg, PCIE_CLIENT_INTR_STATUS_MISC);
-
-	dev_dbg(dev, "PCIE_CLIENT_INTR_STATUS_MISC: %#x\n", reg);
-	dev_dbg(dev, "LTSSM_STATUS: %#x\n", rockchip_pcie_get_ltssm_reg(rockchip));
-
-	if (reg & PCIE_RDLH_LINK_UP_CHGED) {
-		if (rockchip_pcie_link_up(pci)) {
-			msleep(PCIE_RESET_CONFIG_WAIT_MS);
-			dev_dbg(dev, "Received Link up event. Starting enumeration!\n");
-			/* Rescan the bus to enumerate endpoint devices */
-			pci_lock_rescan_remove();
-			pci_rescan_bus(pp->bridge->bus);
-			pci_unlock_rescan_remove();
-		}
-	}
-
-	return IRQ_HANDLED;
-}
-
 static irqreturn_t rockchip_pcie_ep_sys_irq_thread(int irq, void *arg)
 {
 	struct rockchip_pcie *rockchip = arg;
@@ -577,29 +549,14 @@ static irqreturn_t rockchip_pcie_ep_sys_irq_thread(int irq, void *arg)
 	return IRQ_HANDLED;
 }
 
-static int rockchip_pcie_configure_rc(struct platform_device *pdev,
-				      struct rockchip_pcie *rockchip)
+static int rockchip_pcie_configure_rc(struct rockchip_pcie *rockchip)
 {
-	struct device *dev = &pdev->dev;
 	struct dw_pcie_rp *pp;
-	int irq, ret;
 	u32 val;
 
 	if (!IS_ENABLED(CONFIG_PCIE_ROCKCHIP_DW_HOST))
 		return -ENODEV;
 
-	irq = platform_get_irq_byname(pdev, "sys");
-	if (irq < 0)
-		return irq;
-
-	ret = devm_request_threaded_irq(dev, irq, NULL,
-					rockchip_pcie_rc_sys_irq_thread,
-					IRQF_ONESHOT, "pcie-sys-rc", rockchip);
-	if (ret) {
-		dev_err(dev, "failed to request PCIe sys IRQ\n");
-		return ret;
-	}
-
 	/* LTSSM enable control mode */
 	val = FIELD_PREP_WM16(PCIE_LTSSM_ENABLE_ENHANCE, 1);
 	rockchip_pcie_writel_apb(rockchip, val, PCIE_CLIENT_HOT_RESET_CTRL);
@@ -611,17 +568,7 @@ static int rockchip_pcie_configure_rc(struct platform_device *pdev,
 	pp = &rockchip->pci.pp;
 	pp->ops = &rockchip_pcie_host_ops;
 
-	ret = dw_pcie_host_init(pp);
-	if (ret) {
-		dev_err(dev, "failed to initialize host\n");
-		return ret;
-	}
-
-	/* unmask DLL up/down indicator */
-	val = FIELD_PREP_WM16(PCIE_RDLH_LINK_UP_CHGED, 0);
-	rockchip_pcie_writel_apb(rockchip, val, PCIE_CLIENT_INTR_MASK_MISC);
-
-	return ret;
+	return dw_pcie_host_init(pp);
 }
 
 static int rockchip_pcie_configure_ep(struct platform_device *pdev,
@@ -747,7 +694,7 @@ static int rockchip_pcie_probe(struct platform_device *pdev)
 
 	switch (data->mode) {
 	case DW_PCIE_RC_TYPE:
-		ret = rockchip_pcie_configure_rc(pdev, rockchip);
+		ret = rockchip_pcie_configure_rc(rockchip);
 		if (ret)
 			goto deinit_clk;
 		break;
Signature · 1 line
2.51.0
author maintainer
#87 lore raw

PATCH 83/314 net: qrtr: Drop the MHI auto_queue feature for IPCR DL channels

In reply to Sasha Levin

From: Manivannan Sadhasivam <[email protected]>

[ Upstream commit 51731792a25cb312ca94cdccfa139eb46de1b2ef ]

MHI stack offers the 'auto_queue' feature, which allows the MHI stack to auto queue the buffers for the RX path (DL channel). Though this feature simplifies the client driver design, it introduces race between the client drivers and the MHI stack. For instance, with auto_queue, the 'dl_callback' for the DL channel may get called before the client driver is fully probed. This means, by the time the dl_callback gets called, the client driver's structures might not be initialized, leading to NULL ptr dereference.

Currently, the drivers have to workaround this issue by initializing the internal structures before calling mhi_prepare_for_transfer_autoqueue(). But even so, there is a chance that the client driver's internal code path may call the MHI queue APIs before mhi_prepare_for_transfer_autoqueue() is called, leading to similar NULL ptr dereference. This issue has been reported on the Qcom X1E80100 CRD machines affecting boot.

So to properly fix all these races, drop the MHI 'auto_queue' feature altogether and let the client driver (QRTR) manage the RX buffers manually. In the QRTR driver, queue the RX buffers based on the ring length during probe and recycle the buffers in 'dl_callback' once they are consumed. This also warrants removing the setting of 'auto_queue' flag from controller drivers.

Currently, this 'auto_queue' feature is only enabled for IPCR DL channel. So only the QRTR client driver requires the modification.

---
 drivers/accel/qaic/mhi_controller.c   | 44 -----------------
 drivers/bus/mhi/host/pci_generic.c    | 20 +-------
 drivers/net/wireless/ath/ath11k/mhi.c |  4 --
 drivers/net/wireless/ath/ath12k/mhi.c |  4 --
 net/qrtr/mhi.c                        | 69 ++++++++++++++++++++++-----
 5 files changed, 60 insertions(+), 81 deletions(-)
drivers/accel/qaic/mhi_controller.c +0 -44
index 13a14c6c61689..4d787f77ce419 100644
@@ -39,7 +39,6 @@ static const struct mhi_channel_config aic100_channels[] = {
 		.lpm_notify = false,
 		.offload_channel = false,
 		.doorbell_mode_switch = false,
-		.auto_queue = false,
 		.wake_capable = false,
 	},
 	{
@@ -55,7 +54,6 @@ static const struct mhi_channel_config aic100_channels[] = {
 		.lpm_notify = false,
 		.offload_channel = false,
 		.doorbell_mode_switch = false,
-		.auto_queue = false,
 		.wake_capable = false,
 	},
 	{
@@ -71,7 +69,6 @@ static const struct mhi_channel_config aic100_channels[] = {
 		.lpm_notify = false,
 		.offload_channel = false,
 		.doorbell_mode_switch = false,
-		.auto_queue = false,
 		.wake_capable = false,
 	},
 	{
@@ -87,7 +84,6 @@ static const struct mhi_channel_config aic100_channels[] = {
 		.lpm_notify = false,
 		.offload_channel = false,
 		.doorbell_mode_switch = false,
-		.auto_queue = false,
 		.wake_capable = false,
 	},
 	{
@@ -103,7 +99,6 @@ static const struct mhi_channel_config aic100_channels[] = {
 		.lpm_notify = false,
 		.offload_channel = false,
 		.doorbell_mode_switch = false,
-		.auto_queue = false,
 		.wake_capable = false,
 	},
 	{
@@ -119,7 +114,6 @@ static const struct mhi_channel_config aic100_channels[] = {
 		.lpm_notify = false,
 		.offload_channel = false,
 		.doorbell_mode_switch = false,
-		.auto_queue = false,
 		.wake_capable = false,
 	},
 	{
@@ -135,7 +129,6 @@ static const struct mhi_channel_config aic100_channels[] = {
 		.lpm_notify = false,
 		.offload_channel = false,
 		.doorbell_mode_switch = false,
-		.auto_queue = false,
 		.wake_capable = false,
 	},
 	{
@@ -151,7 +144,6 @@ static const struct mhi_channel_config aic100_channels[] = {
 		.lpm_notify = false,
 		.offload_channel = false,
 		.doorbell_mode_switch = false,
-		.auto_queue = false,
 		.wake_capable = false,
 	},
 	{
@@ -167,7 +159,6 @@ static const struct mhi_channel_config aic100_channels[] = {
 		.lpm_notify = false,
 		.offload_channel = false,
 		.doorbell_mode_switch = false,
-		.auto_queue = false,
 		.wake_capable = false,
 	},
 	{
@@ -183,7 +174,6 @@ static const struct mhi_channel_config aic100_channels[] = {
 		.lpm_notify = false,
 		.offload_channel = false,
 		.doorbell_mode_switch = false,
-		.auto_queue = false,
 		.wake_capable = false,
 	},
 	{
@@ -199,7 +189,6 @@ static const struct mhi_channel_config aic100_channels[] = {
 		.lpm_notify = false,
 		.offload_channel = false,
 		.doorbell_mode_switch = false,
-		.auto_queue = false,
 		.wake_capable = false,
 	},
 	{
@@ -215,7 +204,6 @@ static const struct mhi_channel_config aic100_channels[] = {
 		.lpm_notify = false,
 		.offload_channel = false,
 		.doorbell_mode_switch = false,
-		.auto_queue = false,
 		.wake_capable = false,
 	},
 	{
@@ -231,7 +219,6 @@ static const struct mhi_channel_config aic100_channels[] = {
 		.lpm_notify = false,
 		.offload_channel = false,
 		.doorbell_mode_switch = false,
-		.auto_queue = false,
 		.wake_capable = false,
 	},
 	{
@@ -247,7 +234,6 @@ static const struct mhi_channel_config aic100_channels[] = {
 		.lpm_notify = false,
 		.offload_channel = false,
 		.doorbell_mode_switch = false,
-		.auto_queue = false,
 		.wake_capable = false,
 	},
 	{
@@ -263,7 +249,6 @@ static const struct mhi_channel_config aic100_channels[] = {
 		.lpm_notify = false,
 		.offload_channel = false,
 		.doorbell_mode_switch = false,
-		.auto_queue = false,
 		.wake_capable = false,
 	},
 	{
@@ -279,7 +264,6 @@ static const struct mhi_channel_config aic100_channels[] = {
 		.lpm_notify = false,
 		.offload_channel = false,
 		.doorbell_mode_switch = false,
-		.auto_queue = false,
 		.wake_capable = false,
 	},
 	{
@@ -295,7 +279,6 @@ static const struct mhi_channel_config aic100_channels[] = {
 		.lpm_notify = false,
 		.offload_channel = false,
 		.doorbell_mode_switch = false,
-		.auto_queue = false,
 		.wake_capable = false,
 	},
 	{
@@ -311,7 +294,6 @@ static const struct mhi_channel_config aic100_channels[] = {
 		.lpm_notify = false,
 		.offload_channel = false,
 		.doorbell_mode_switch = false,
-		.auto_queue = false,
 		.wake_capable = false,
 	},
 	{
@@ -327,7 +309,6 @@ static const struct mhi_channel_config aic100_channels[] = {
 		.lpm_notify = false,
 		.offload_channel = false,
 		.doorbell_mode_switch = false,
-		.auto_queue = false,
 		.wake_capable = false,
 	},
 	{
@@ -343,7 +324,6 @@ static const struct mhi_channel_config aic100_channels[] = {
 		.lpm_notify = false,
 		.offload_channel = false,
 		.doorbell_mode_switch = false,
-		.auto_queue = false,
 		.wake_capable = false,
 	},
 	{
@@ -359,7 +339,6 @@ static const struct mhi_channel_config aic100_channels[] = {
 		.lpm_notify = false,
 		.offload_channel = false,
 		.doorbell_mode_switch = false,
-		.auto_queue = false,
 		.wake_capable = false,
 	},
 	{
@@ -375,7 +354,6 @@ static const struct mhi_channel_config aic100_channels[] = {
 		.lpm_notify = false,
 		.offload_channel = false,
 		.doorbell_mode_switch = false,
-		.auto_queue = false,
 		.wake_capable = false,
 	},
 	{
@@ -391,7 +369,6 @@ static const struct mhi_channel_config aic100_channels[] = {
 		.lpm_notify = false,
 		.offload_channel = false,
 		.doorbell_mode_switch = false,
-		.auto_queue = false,
 		.wake_capable = false,
 	},
 	{
@@ -407,7 +384,6 @@ static const struct mhi_channel_config aic100_channels[] = {
 		.lpm_notify = false,
 		.offload_channel = false,
 		.doorbell_mode_switch = false,
-		.auto_queue = false,
 		.wake_capable = false,
 	},
 	{
@@ -423,7 +399,6 @@ static const struct mhi_channel_config aic100_channels[] = {
 		.lpm_notify = false,
 		.offload_channel = false,
 		.doorbell_mode_switch = false,
-		.auto_queue = false,
 		.wake_capable = false,
 	},
 	{
@@ -439,7 +414,6 @@ static const struct mhi_channel_config aic100_channels[] = {
 		.lpm_notify = false,
 		.offload_channel = false,
 		.doorbell_mode_switch = false,
-		.auto_queue = true,
 		.wake_capable = false,
 	},
 };
@@ -458,7 +432,6 @@ static const struct mhi_channel_config aic200_channels[] = {
 		.lpm_notify = false,
 		.offload_channel = false,
 		.doorbell_mode_switch = false,
-		.auto_queue = false,
 		.wake_capable = false,
 	},
 	{
@@ -474,7 +447,6 @@ static const struct mhi_channel_config aic200_channels[] = {
 		.lpm_notify = false,
 		.offload_channel = false,
 		.doorbell_mode_switch = false,
-		.auto_queue = false,
 		.wake_capable = false,
 	},
 	{
@@ -490,7 +462,6 @@ static const struct mhi_channel_config aic200_channels[] = {
 		.lpm_notify = false,
 		.offload_channel = false,
 		.doorbell_mode_switch = false,
-		.auto_queue = false,
 		.wake_capable = false,
 	},
 	{
@@ -506,7 +477,6 @@ static const struct mhi_channel_config aic200_channels[] = {
 		.lpm_notify = false,
 		.offload_channel = false,
 		.doorbell_mode_switch = false,
-		.auto_queue = false,
 		.wake_capable = false,
 	},
 	{
@@ -522,7 +492,6 @@ static const struct mhi_channel_config aic200_channels[] = {
 		.lpm_notify = false,
 		.offload_channel = false,
 		.doorbell_mode_switch = false,
-		.auto_queue = false,
 		.wake_capable = false,
 	},
 	{
@@ -538,7 +507,6 @@ static const struct mhi_channel_config aic200_channels[] = {
 		.lpm_notify = false,
 		.offload_channel = false,
 		.doorbell_mode_switch = false,
-		.auto_queue = false,
 		.wake_capable = false,
 	},
 	{
@@ -554,7 +522,6 @@ static const struct mhi_channel_config aic200_channels[] = {
 		.lpm_notify = false,
 		.offload_channel = false,
 		.doorbell_mode_switch = false,
-		.auto_queue = false,
 		.wake_capable = false,
 	},
 	{
@@ -570,7 +537,6 @@ static const struct mhi_channel_config aic200_channels[] = {
 		.lpm_notify = false,
 		.offload_channel = false,
 		.doorbell_mode_switch = false,
-		.auto_queue = false,
 		.wake_capable = false,
 	},
 	{
@@ -586,7 +552,6 @@ static const struct mhi_channel_config aic200_channels[] = {
 		.lpm_notify = false,
 		.offload_channel = false,
 		.doorbell_mode_switch = false,
-		.auto_queue = false,
 		.wake_capable = false,
 	},
 	{
@@ -602,7 +567,6 @@ static const struct mhi_channel_config aic200_channels[] = {
 		.lpm_notify = false,
 		.offload_channel = false,
 		.doorbell_mode_switch = false,
-		.auto_queue = false,
 		.wake_capable = false,
 	},
 	{
@@ -618,7 +582,6 @@ static const struct mhi_channel_config aic200_channels[] = {
 		.lpm_notify = false,
 		.offload_channel = false,
 		.doorbell_mode_switch = false,
-		.auto_queue = false,
 		.wake_capable = false,
 	},
 	{
@@ -634,7 +597,6 @@ static const struct mhi_channel_config aic200_channels[] = {
 		.lpm_notify = false,
 		.offload_channel = false,
 		.doorbell_mode_switch = false,
-		.auto_queue = false,
 		.wake_capable = false,
 	},
 	{
@@ -650,7 +612,6 @@ static const struct mhi_channel_config aic200_channels[] = {
 		.lpm_notify = false,
 		.offload_channel = false,
 		.doorbell_mode_switch = false,
-		.auto_queue = false,
 		.wake_capable = false,
 	},
 	{
@@ -666,7 +627,6 @@ static const struct mhi_channel_config aic200_channels[] = {
 		.lpm_notify = false,
 		.offload_channel = false,
 		.doorbell_mode_switch = false,
-		.auto_queue = false,
 		.wake_capable = false,
 	},
 	{
@@ -682,7 +642,6 @@ static const struct mhi_channel_config aic200_channels[] = {
 		.lpm_notify = false,
 		.offload_channel = false,
 		.doorbell_mode_switch = false,
-		.auto_queue = false,
 		.wake_capable = false,
 	},
 	{
@@ -698,7 +657,6 @@ static const struct mhi_channel_config aic200_channels[] = {
 		.lpm_notify = false,
 		.offload_channel = false,
 		.doorbell_mode_switch = false,
-		.auto_queue = false,
 		.wake_capable = false,
 	},
 	{
@@ -714,7 +672,6 @@ static const struct mhi_channel_config aic200_channels[] = {
 		.lpm_notify = false,
 		.offload_channel = false,
 		.doorbell_mode_switch = false,
-		.auto_queue = false,
 		.wake_capable = false,
 	},
 	{
@@ -730,7 +687,6 @@ static const struct mhi_channel_config aic200_channels[] = {
 		.lpm_notify = false,
 		.offload_channel = false,
 		.doorbell_mode_switch = false,
-		.auto_queue = true,
 		.wake_capable = false,
 	},
 };
drivers/bus/mhi/host/pci_generic.c +2 -18
index 3d8c9729fcfc5..21f0522d9ff29 100644
@@ -94,22 +94,6 @@ struct mhi_pci_dev_info {
 		.doorbell_mode_switch = false,		\
 	}
 
-#define MHI_CHANNEL_CONFIG_DL_AUTOQUEUE(ch_num, ch_name, el_count, ev_ring) \
-	{						\
-		.num = ch_num,				\
-		.name = ch_name,			\
-		.num_elements = el_count,		\
-		.event_ring = ev_ring,			\
-		.dir = DMA_FROM_DEVICE,			\
-		.ee_mask = BIT(MHI_EE_AMSS),		\
-		.pollcfg = 0,				\
-		.doorbell = MHI_DB_BRST_DISABLE,	\
-		.lpm_notify = false,			\
-		.offload_channel = false,		\
-		.doorbell_mode_switch = false,		\
-		.auto_queue = true,			\
-	}
-
 #define MHI_EVENT_CONFIG_CTRL(ev_ring, el_count) \
 	{					\
 		.num_elements = el_count,	\
@@ -329,7 +313,7 @@ static const struct mhi_channel_config modem_qcom_v1_mhi_channels[] = {
 	MHI_CHANNEL_CONFIG_UL(14, "QMI", 4, 0),
 	MHI_CHANNEL_CONFIG_DL(15, "QMI", 4, 0),
 	MHI_CHANNEL_CONFIG_UL(20, "IPCR", 8, 0),
-	MHI_CHANNEL_CONFIG_DL_AUTOQUEUE(21, "IPCR", 8, 0),
+	MHI_CHANNEL_CONFIG_DL(21, "IPCR", 8, 0),
 	MHI_CHANNEL_CONFIG_UL_FP(34, "FIREHOSE", 32, 0),
 	MHI_CHANNEL_CONFIG_DL_FP(35, "FIREHOSE", 32, 0),
 	MHI_CHANNEL_CONFIG_UL(46, "IP_SW0", 64, 2),
@@ -751,7 +735,7 @@ static const struct mhi_channel_config mhi_telit_fn980_hw_v1_channels[] = {
 	MHI_CHANNEL_CONFIG_UL(14, "QMI", 32, 0),
 	MHI_CHANNEL_CONFIG_DL(15, "QMI", 32, 0),
 	MHI_CHANNEL_CONFIG_UL(20, "IPCR", 16, 0),
-	MHI_CHANNEL_CONFIG_DL_AUTOQUEUE(21, "IPCR", 16, 0),
+	MHI_CHANNEL_CONFIG_DL(21, "IPCR", 16, 0),
 	MHI_CHANNEL_CONFIG_HW_UL(100, "IP_HW0", 128, 1),
 	MHI_CHANNEL_CONFIG_HW_DL(101, "IP_HW0", 128, 2),
 };
drivers/net/wireless/ath/ath11k/mhi.c +0 -4
index acd76e9392d31..d2c44f7f9b622 100644
@@ -34,7 +34,6 @@ static const struct mhi_channel_config ath11k_mhi_channels_qca6390[] = {
 		.lpm_notify = false,
 		.offload_channel = false,
 		.doorbell_mode_switch = false,
-		.auto_queue = false,
 	},
 	{
 		.num = 21,
@@ -48,7 +47,6 @@ static const struct mhi_channel_config ath11k_mhi_channels_qca6390[] = {
 		.lpm_notify = false,
 		.offload_channel = false,
 		.doorbell_mode_switch = false,
-		.auto_queue = true,
 	},
 };
 
@@ -99,7 +97,6 @@ static const struct mhi_channel_config ath11k_mhi_channels_qcn9074[] = {
 		.lpm_notify = false,
 		.offload_channel = false,
 		.doorbell_mode_switch = false,
-		.auto_queue = false,
 	},
 	{
 		.num = 21,
@@ -113,7 +110,6 @@ static const struct mhi_channel_config ath11k_mhi_channels_qcn9074[] = {
 		.lpm_notify = false,
 		.offload_channel = false,
 		.doorbell_mode_switch = false,
-		.auto_queue = true,
 	},
 };
 
drivers/net/wireless/ath/ath12k/mhi.c +0 -4
index 08f44baf182a5..2dbdb95ae7bea 100644
@@ -31,7 +31,6 @@ static const struct mhi_channel_config ath12k_mhi_channels_qcn9274[] = {
 		.lpm_notify = false,
 		.offload_channel = false,
 		.doorbell_mode_switch = false,
-		.auto_queue = false,
 	},
 	{
 		.num = 21,
@@ -45,7 +44,6 @@ static const struct mhi_channel_config ath12k_mhi_channels_qcn9274[] = {
 		.lpm_notify = false,
 		.offload_channel = false,
 		.doorbell_mode_switch = false,
-		.auto_queue = true,
 	},
 };
 
@@ -96,7 +94,6 @@ static const struct mhi_channel_config ath12k_mhi_channels_wcn7850[] = {
 		.lpm_notify = false,
 		.offload_channel = false,
 		.doorbell_mode_switch = false,
-		.auto_queue = false,
 	},
 	{
 		.num = 21,
@@ -110,7 +107,6 @@ static const struct mhi_channel_config ath12k_mhi_channels_wcn7850[] = {
 		.lpm_notify = false,
 		.offload_channel = false,
 		.doorbell_mode_switch = false,
-		.auto_queue = true,
 	},
 };
 
net/qrtr/mhi.c +58 -11

108 lines not on this page · raw message

Signature · 1 line
2.51.0
author maintainer
#88 lore raw

PATCH 84/314 media: v4l2-mem2mem: Add a kref to the v4l2_m2m_dev structure

In reply to Sasha Levin

From: Nicolas Dufresne <[email protected]>

[ Upstream commit db6b97a4f8041e479be9ef4b8b07022636c96f50 ]

Adding a reference count to the v4l2_m2m_dev structure allow safely sharing it across multiple hardware nodes. This can be used to prevent running jobs concurrently on m2m cores that have some internal resource sharing.

[hverkuil: fix typos in v4l2_m2m_put documentation]

Stable-dep-of: e0203ddf9af7 ("media: verisilicon: Avoid G2 bus error while decoding H.264 and HEVC")

---
 drivers/media/v4l2-core/v4l2-mem2mem.c | 23 +++++++++++++++++++++++
 include/media/v4l2-mem2mem.h           | 21 +++++++++++++++++++++
 2 files changed, 44 insertions(+)
drivers/media/v4l2-core/v4l2-mem2mem.c +23 -0
index 21acd9bc86071..bc8218d1cab9f 100644
@@ -90,6 +90,7 @@ static const char * const m2m_entity_name[] = {
  * @job_work:		worker to run queued jobs.
  * @job_queue_flags:	flags of the queue status, %QUEUE_PAUSED.
  * @m2m_ops:		driver callbacks
+ * @kref:		device reference count
  */
 struct v4l2_m2m_dev {
 	struct v4l2_m2m_ctx	*curr_ctx;
@@ -109,6 +110,8 @@ struct v4l2_m2m_dev {
 	unsigned long		job_queue_flags;
 
 	const struct v4l2_m2m_ops *m2m_ops;
+
+	struct kref kref;
 };
 
 static struct v4l2_m2m_queue_ctx *get_queue_ctx(struct v4l2_m2m_ctx *m2m_ctx,
@@ -1206,6 +1209,7 @@ struct v4l2_m2m_dev *v4l2_m2m_init(const struct v4l2_m2m_ops *m2m_ops)
 	INIT_LIST_HEAD(&m2m_dev->job_queue);
 	spin_lock_init(&m2m_dev->job_spinlock);
 	INIT_WORK(&m2m_dev->job_work, v4l2_m2m_device_run_work);
+	kref_init(&m2m_dev->kref);
 
 	return m2m_dev;
 }
@@ -1217,6 +1221,25 @@ void v4l2_m2m_release(struct v4l2_m2m_dev *m2m_dev)
 }
 EXPORT_SYMBOL_GPL(v4l2_m2m_release);
 
+void v4l2_m2m_get(struct v4l2_m2m_dev *m2m_dev)
+{
+	kref_get(&m2m_dev->kref);
+}
+EXPORT_SYMBOL_GPL(v4l2_m2m_get);
+
+static void v4l2_m2m_release_from_kref(struct kref *kref)
+{
+	struct v4l2_m2m_dev *m2m_dev = container_of(kref, struct v4l2_m2m_dev, kref);
+
+	v4l2_m2m_release(m2m_dev);
+}
+
+void v4l2_m2m_put(struct v4l2_m2m_dev *m2m_dev)
+{
+	kref_put(&m2m_dev->kref, v4l2_m2m_release_from_kref);
+}
+EXPORT_SYMBOL_GPL(v4l2_m2m_put);
+
 struct v4l2_m2m_ctx *v4l2_m2m_ctx_init(struct v4l2_m2m_dev *m2m_dev,
 		void *drv_priv,
 		int (*queue_init)(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq))
include/media/v4l2-mem2mem.h +21 -0
index 500f81f399dfa..08e3c9c4f1e9d 100644
@@ -544,6 +544,27 @@ v4l2_m2m_register_media_controller(struct v4l2_m2m_dev *m2m_dev,
  */
 void v4l2_m2m_release(struct v4l2_m2m_dev *m2m_dev);
 
+/**
+ * v4l2_m2m_get() - take a reference to the m2m_dev structure
+ *
+ * @m2m_dev: opaque pointer to the internal data to handle M2M context
+ *
+ * This is used to share the M2M device across multiple devices. This
+ * can be used to avoid scheduling two hardware nodes concurrently.
+ */
+void v4l2_m2m_get(struct v4l2_m2m_dev *m2m_dev);
+
+/**
+ * v4l2_m2m_put() - remove a reference to the m2m_dev structure
+ *
+ * @m2m_dev: opaque pointer to the internal data to handle M2M context
+ *
+ * Once the M2M device has no more references, v4l2_m2m_release() will be
+ * called automatically. Users of this method should never call
+ * v4l2_m2m_release() directly. See v4l2_m2m_get() for more details.
+ */
+void v4l2_m2m_put(struct v4l2_m2m_dev *m2m_dev);
+
 /**
  * v4l2_m2m_ctx_init() - allocate and initialize a m2m context
  *
Signature · 1 line
2.51.0
author maintainer
#89 lore raw

PATCH 85/314 media: verisilicon: Avoid G2 bus error while decoding H.264 and HEVC

In reply to Sasha Levin

From: Ming Qian <[email protected]>

[ Upstream commit e0203ddf9af7c8e170e1e99ce83b4dc07f0cd765 ]

For the i.MX8MQ platform, there is a hardware limitation: the g1 VPU and g2 VPU cannot decode simultaneously; otherwise, it will cause below bus error and produce corrupted pictures, even potentially lead to system hang.

[  110.527986] hantro-vpu 38310000.video-codec: frame decode timed out.
[  110.583517] hantro-vpu 38310000.video-codec: bus error detected.

Therefore, it is necessary to ensure that g1 and g2 operate alternately. This allows for successful multi-instance decoding of H.264 and HEVC.

To achieve this, g1 and g2 share the same v4l2_m2m_dev, and then the v4l2_m2m_dev can handle the scheduling.

Fixes cb5dd5a0fa518 ("media: hantro: Introduce G2/HEVC decoder")
---
 drivers/media/platform/verisilicon/hantro.h   |  2 +
 .../media/platform/verisilicon/hantro_drv.c   | 42 +++++++++++++++++--
 .../media/platform/verisilicon/imx8m_vpu_hw.c |  8 ++++
 3 files changed, 49 insertions(+), 3 deletions(-)
drivers/media/platform/verisilicon/hantro.h +2 -0
index e0fdc4535b2d7..0353de154a1ec 100644
@@ -77,6 +77,7 @@ struct hantro_irq {
  * @double_buffer:		core needs double buffering
  * @legacy_regs:		core uses legacy register set
  * @late_postproc:		postproc must be set up at the end of the job
+ * @shared_devices:		an array of device ids that cannot run concurrently
  */
 struct hantro_variant {
 	unsigned int enc_offset;
@@ -101,6 +102,7 @@ struct hantro_variant {
 	unsigned int double_buffer : 1;
 	unsigned int legacy_regs : 1;
 	unsigned int late_postproc : 1;
+	const struct of_device_id *shared_devices;
 };
 
 /**
drivers/media/platform/verisilicon/hantro_drv.c +39 -3

72 lines not on this page · raw message

drivers/media/platform/verisilicon/imx8m_vpu_hw.c +8 -0
index 5be0e2e76882f..6f8e43b7f1575 100644
@@ -343,6 +343,12 @@ const struct hantro_variant imx8mq_vpu_variant = {
 	.num_regs = ARRAY_SIZE(imx8mq_reg_names)
 };
 
+static const struct of_device_id imx8mq_vpu_shared_resources[] __initconst = {
+	{ .compatible = "nxp,imx8mq-vpu-g1", },
+	{ .compatible = "nxp,imx8mq-vpu-g2", },
+	{ /* sentinel */ }
+};
+
 const struct hantro_variant imx8mq_vpu_g1_variant = {
 	.dec_fmts = imx8m_vpu_dec_fmts,
 	.num_dec_fmts = ARRAY_SIZE(imx8m_vpu_dec_fmts),
@@ -356,6 +362,7 @@ const struct hantro_variant imx8mq_vpu_g1_variant = {
 	.num_irqs = ARRAY_SIZE(imx8mq_irqs),
 	.clk_names = imx8mq_g1_clk_names,
 	.num_clocks = ARRAY_SIZE(imx8mq_g1_clk_names),
+	.shared_devices = imx8mq_vpu_shared_resources,
 };
 
 const struct hantro_variant imx8mq_vpu_g2_variant = {
@@ -371,6 +378,7 @@ const struct hantro_variant imx8mq_vpu_g2_variant = {
 	.num_irqs = ARRAY_SIZE(imx8mq_g2_irqs),
 	.clk_names = imx8mq_g2_clk_names,
 	.num_clocks = ARRAY_SIZE(imx8mq_g2_clk_names),
+	.shared_devices = imx8mq_vpu_shared_resources,
 };
 
 const struct hantro_variant imx8mm_vpu_g1_variant = {
Signature · 1 line
2.51.0
#90 lore raw

Re: [PATCH 6.18 085/314] media: verisilicon: Avoid G2 bus error while decoding H.264 and HEVC

Quoted 25 lines · On wtorek, 10 marca 2026 12:15:44 czas środkowoeuropejski standardowy Sasha…

From: Ming Qian <[email protected]>

[ Upstream commit e0203ddf9af7c8e170e1e99ce83b4dc07f0cd765 ]

For the i.MX8MQ platform, there is a hardware limitation: the g1 VPU and g2 VPU cannot decode simultaneously; otherwise, it will cause below bus error and produce corrupted pictures, even potentially lead to system hang.

[  110.527986] hantro-vpu 38310000.video-codec: frame decode timed out.
[  110.583517] hantro-vpu 38310000.video-codec: bus error detected.

Therefore, it is necessary to ensure that g1 and g2 operate alternately. This allows for successful multi-instance decoding of H.264 and HEVC.

To achieve this, g1 and g2 share the same v4l2_m2m_dev, and then the v4l2_m2m_dev can handle the scheduling.

Fixes cb5dd5a0fa518 ("media: hantro: Introduce G2/HEVC decoder")
Quoted 6 lines
---
 drivers/media/platform/verisilicon/hantro.h   |  2 +
 .../media/platform/verisilicon/hantro_drv.c   | 42 +++++++++++++++++--
 .../media/platform/verisilicon/imx8m_vpu_hw.c |  8 ++++
 3 files changed, 49 insertions(+), 3 deletions(-)

This one introduces a regression that's being fixed in https://lore.kernel.org/
lkml/[email protected]/T/, so they should probably be applied together once the fix lands.

author maintainer
#91 lore raw

Re: [PATCH 6.18 085/314] media: verisilicon: Avoid G2 bus error while decoding H.264 and HEVC

Quoted 34 lines · Sebastian Krzyszkowiak
Quoted 25 lines · On wtorek, 10 marca 2026 12:15:44 czas środkowoeuropejski standardowy Sasha…

From: Ming Qian <[email protected]>

[ Upstream commit e0203ddf9af7c8e170e1e99ce83b4dc07f0cd765 ]

For the i.MX8MQ platform, there is a hardware limitation: the g1 VPU and g2 VPU cannot decode simultaneously; otherwise, it will cause below bus error and produce corrupted pictures, even potentially lead to system hang.

[  110.527986] hantro-vpu 38310000.video-codec: frame decode timed out.
[  110.583517] hantro-vpu 38310000.video-codec: bus error detected.

Therefore, it is necessary to ensure that g1 and g2 operate alternately. This allows for successful multi-instance decoding of H.264 and HEVC.

To achieve this, g1 and g2 share the same v4l2_m2m_dev, and then the v4l2_m2m_dev can handle the scheduling.

Fixes cb5dd5a0fa518 ("media: hantro: Introduce G2/HEVC decoder")
Quoted 6 lines
---
 drivers/media/platform/verisilicon/hantro.h   |  2 +
 .../media/platform/verisilicon/hantro_drv.c   | 42 +++++++++++++++++--
 .../media/platform/verisilicon/imx8m_vpu_hw.c |  8 ++++
 3 files changed, 49 insertions(+), 3 deletions(-)
Quoted 3 lines

This one introduces a regression that's being fixed in https://lore.kernel.org/
lkml/[email protected]/T/, so they should probably be applied together once the fix lands.

I can drop it from 6.18<=, but note that it was already released as part of 6.19.

We can revisit a revert or cherry picking the fix for 6.19 after the current release cycle.

Signature · 2 lines
Thanks,
Sasha
author maintainer
#92 lore raw

PATCH 86/314 usb: gadget: u_ether: add gether_opts for config caching

In reply to Sasha Levin

From: Kuen-Han Tsai <[email protected]>

[ Upstream commit e065c6a7e46c2ee9c677fdbf50035323d2de1215 ]

Currently, the net_device is allocated when the function instance is created (e.g., in ncm_alloc_inst()). While this allows userspace to configure the device early, it decouples the net_device lifecycle from the actual USB connection state (bind/unbind). The goal is to defer net_device creation to the bind callback to properly align the lifecycle with its parent gadget device.

However, deferring net_device allocation would prevent userspace from configuring parameters (like interface name or MAC address) before the net_device exists.

Introduce a new structure, struct gether_opts, associated with the usb_function_instance, to cache settings independently of the net_device. These settings include the interface name pattern, MAC addresses (device and host), queue multiplier, and address assignment type.

New helper functions are added:
- gether_setup_opts_default(): Initializes struct gether_opts with defaults, including random MAC addresses.
- gether_apply_opts(): Applies the cached options from a struct gether_opts to a valid net_device.

To expose these options to userspace, new configfs macros (USB_ETHER_OPTS_ITEM and USB_ETHER_OPTS_ATTR_*) are defined in u_ether_configfs.h. These attributes are part of the function instance's configfs group.

This refactoring is a preparatory step. It allows the subsequent patch to safely move the net_device allocation from the instance creation phase to the bind phase without losing the ability to pre-configure the interface via configfs.

Stable-dep-of: 56a512a9b410 ("usb: gadget: f_ncm: align net_device lifecycle with bind/unbind")

---
 drivers/usb/gadget/function/u_ether.c         |  30 +++
 drivers/usb/gadget/function/u_ether.h         |  28 +++
 .../usb/gadget/function/u_ether_configfs.h    | 176 ++++++++++++++++++
 3 files changed, 234 insertions(+)
drivers/usb/gadget/function/u_ether.c +30 -0
index f58590bf5e02f..745ed2c212e3a 100644
@@ -1039,6 +1039,36 @@ int gether_set_ifname(struct net_device *net, const char *name, int len)
 }
 EXPORT_SYMBOL_GPL(gether_set_ifname);
 
+void gether_setup_opts_default(struct gether_opts *opts, const char *name)
+{
+	opts->qmult = QMULT_DEFAULT;
+	snprintf(opts->name, sizeof(opts->name), "%s%%d", name);
+	eth_random_addr(opts->dev_mac);
+	opts->addr_assign_type = NET_ADDR_RANDOM;
+	eth_random_addr(opts->host_mac);
+}
+EXPORT_SYMBOL_GPL(gether_setup_opts_default);
+
+void gether_apply_opts(struct net_device *net, struct gether_opts *opts)
+{
+	struct eth_dev *dev = netdev_priv(net);
+
+	dev->qmult = opts->qmult;
+
+	if (opts->ifname_set) {
+		strscpy(net->name, opts->name, sizeof(net->name));
+		dev->ifname_set = true;
+	}
+
+	memcpy(dev->host_mac, opts->host_mac, sizeof(dev->host_mac));
+
+	if (opts->addr_assign_type == NET_ADDR_SET) {
+		memcpy(dev->dev_mac, opts->dev_mac, sizeof(dev->dev_mac));
+		net->addr_assign_type = opts->addr_assign_type;
+	}
+}
+EXPORT_SYMBOL_GPL(gether_apply_opts);
+
 void gether_suspend(struct gether *link)
 {
 	struct eth_dev *dev = link->ioport;
drivers/usb/gadget/function/u_ether.h +28 -0
index 34be220cef77c..63a0240df4d74 100644
@@ -38,6 +38,31 @@
 
 struct eth_dev;
 
+/**
+ * struct gether_opts - Options for Ethernet gadget function instances
+ * @name: Pattern for the network interface name (e.g., "usb%d").
+ *        Used to generate the net device name.
+ * @qmult: Queue length multiplier for high/super speed.
+ * @host_mac: The MAC address to be used by the host side.
+ * @dev_mac: The MAC address to be used by the device side.
+ * @ifname_set: True if the interface name pattern has been set by userspace.
+ * @addr_assign_type: The method used for assigning the device MAC address
+ *                    (e.g., NET_ADDR_RANDOM, NET_ADDR_SET).
+ *
+ * This structure caches network-related settings provided through configfs
+ * before the net_device is fully instantiated. This allows for early
+ * configuration while deferring net_device allocation until the function
+ * is bound.
+ */
+struct gether_opts {
+	char			name[IFNAMSIZ];
+	unsigned int		qmult;
+	u8			host_mac[ETH_ALEN];
+	u8			dev_mac[ETH_ALEN];
+	bool			ifname_set;
+	unsigned char		addr_assign_type;
+};
+
 /*
  * This represents the USB side of an "ethernet" link, managed by a USB
  * function which provides control and (maybe) framing.  Two functions
@@ -259,6 +284,9 @@ int gether_set_ifname(struct net_device *net, const char *name, int len);
 
 void gether_cleanup(struct eth_dev *dev);
 
+void gether_setup_opts_default(struct gether_opts *opts, const char *name);
+void gether_apply_opts(struct net_device *net, struct gether_opts *opts);
+
 void gether_suspend(struct gether *link);
 void gether_resume(struct gether *link);
 
drivers/usb/gadget/function/u_ether_configfs.h +176 -0

186 lines not on this page · raw message

Signature · 1 line
2.51.0
author maintainer
#93 lore raw

PATCH 87/314 usb: gadget: u_ether: Add auto-cleanup helper for freeing net_device

In reply to Sasha Levin

From: Kuen-Han Tsai <[email protected]>

[ Upstream commit 0c0981126b99288ed354d3d414c8a5fd42ac9e25 ]

The net_device in the u_ether framework currently requires explicit calls to unregister and free the device.

Introduce gether_unregister_free_netdev() and the corresponding auto-cleanup macro. This ensures that if a net_device is registered, it is properly unregistered and the associated work queue is flushed before the memory is freed.

This is a preparatory patch to simplify error handling paths in gadget drivers by removing the need for explicit goto labels for net_device cleanup.

Stable-dep-of: 56a512a9b410 ("usb: gadget: f_ncm: align net_device lifecycle with bind/unbind")

---
 drivers/usb/gadget/function/u_ether.c | 15 +++++++++++++++
 drivers/usb/gadget/function/u_ether.h |  2 ++
 2 files changed, 17 insertions(+)
drivers/usb/gadget/function/u_ether.c +15 -0
index 745ed2c212e3a..6c32665538cc0 100644
@@ -1125,6 +1125,21 @@ void gether_cleanup(struct eth_dev *dev)
 }
 EXPORT_SYMBOL_GPL(gether_cleanup);
 
+void gether_unregister_free_netdev(struct net_device *net)
+{
+	if (!net)
+		return;
+
+	struct eth_dev *dev = netdev_priv(net);
+
+	if (net->reg_state == NETREG_REGISTERED) {
+		unregister_netdev(net);
+		flush_work(&dev->work);
+	}
+	free_netdev(net);
+}
+EXPORT_SYMBOL_GPL(gether_unregister_free_netdev);
+
 /**
  * gether_connect - notify network layer that USB link is active
  * @link: the USB link, set up with endpoints, descriptors matching
drivers/usb/gadget/function/u_ether.h +2 -0
index 63a0240df4d74..a212a8ec5eb1b 100644
@@ -283,6 +283,8 @@ int gether_get_ifname(struct net_device *net, char *name, int len);
 int gether_set_ifname(struct net_device *net, const char *name, int len);
 
 void gether_cleanup(struct eth_dev *dev);
+void gether_unregister_free_netdev(struct net_device *net);
+DEFINE_FREE(free_gether_netdev, struct net_device *, gether_unregister_free_netdev(_T));
 
 void gether_setup_opts_default(struct gether_opts *opts, const char *name);
 void gether_apply_opts(struct net_device *net, struct gether_opts *opts);
Signature · 1 line
2.51.0
author maintainer
#94 lore raw

PATCH 88/314 usb: gadget: f_ncm: align net_device lifecycle with bind/unbind

In reply to Sasha Levin

From: Kuen-Han Tsai <[email protected]>

[ Upstream commit 56a512a9b4107079f68701e7d55da8507eb963d9 ]

Currently, the net_device is allocated in ncm_alloc_inst() and freed in ncm_free_inst(). This ties the network interface's lifetime to the configuration instance rather than the USB connection (bind/unbind).

This decoupling causes issues when the USB gadget is disconnected where the underlying gadget device is removed. The net_device can outlive its parent, leading to dangling sysfs links and NULL pointer dereferences when accessing the freed gadget device.

Problem 1: NULL pointer dereference on disconnect

 Unable to handle kernel NULL pointer dereference at virtual address
 0000000000000000
 Call trace:
   __pi_strlen+0x14/0x150
   rtnl_fill_ifinfo+0x6b4/0x708
   rtmsg_ifinfo_build_skb+0xd8/0x13c
   rtmsg_ifinfo+0x50/0xa0
   __dev_notify_flags+0x4c/0x1f0
   dev_change_flags+0x54/0x70
   do_setlink+0x390/0xebc
   rtnl_newlink+0x7d0/0xac8
   rtnetlink_rcv_msg+0x27c/0x410
   netlink_rcv_skb+0x134/0x150
   rtnetlink_rcv+0x18/0x28
   netlink_unicast+0x254/0x3f0
   netlink_sendmsg+0x2e0/0x3d4

Problem 2: Dangling sysfs symlinks
console:/ # ls -l /sys/class/net/ncm0
lrwxrwxrwx ... /sys/class/net/ncm0 -> /sys/devices/platform/.../gadget.0/net/ncm0 console:/ # ls -l /sys/devices/platform/.../gadget.0/net/ncm0
ls: .../gadget.0/net/ncm0: No such file or directory

Move the net_device allocation to ncm_bind() and deallocation to ncm_unbind(). This ensures the network interface exists only when the gadget function is actually bound to a configuration.

To support pre-bind configuration (e.g., setting interface name or MAC address via configfs), cache user-provided options in f_ncm_opts using the gether_opts structure. Apply these cached settings to the net_device upon creation in ncm_bind().

Preserve the use-after-free fix from commit 6334b8e4553c ("usb: gadget:
f_ncm: Fix UAF ncm object at re-bind after usb ep transport error"). Check opts->net in ncm_set_alt() and ncm_disable() to ensure gether_disconnect() runs only if a connection was established.

Fixes 40d133d7f542 ("usb: gadget: f_ncm: convert to new function interface with backward compatibility")
---
 drivers/usb/gadget/function/f_ncm.c | 128 ++++++++++++++--------------
 drivers/usb/gadget/function/u_ncm.h |   4 +-
 2 files changed, 66 insertions(+), 66 deletions(-)
drivers/usb/gadget/function/f_ncm.c +63 -65
index 0e38330271d5a..e23adc132f886 100644
@@ -83,6 +83,11 @@ static inline struct f_ncm *func_to_ncm(struct usb_function *f)
 	return container_of(f, struct f_ncm, port.func);
 }
 
+static inline struct f_ncm_opts *func_to_ncm_opts(struct usb_function *f)
+{
+	return container_of(f->fi, struct f_ncm_opts, func_inst);
+}
+
 /*-------------------------------------------------------------------------*/
 
 /*
@@ -859,6 +864,7 @@ static int ncm_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
 static int ncm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 {
 	struct f_ncm		*ncm = func_to_ncm(f);
+	struct f_ncm_opts	*opts = func_to_ncm_opts(f);
 	struct usb_composite_dev *cdev = f->config->cdev;
 
 	/* Control interface has only altsetting 0 */
@@ -881,12 +887,13 @@ static int ncm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 		if (alt > 1)
 			goto fail;
 
-		if (ncm->netdev) {
-			DBG(cdev, "reset ncm\n");
-			ncm->netdev = NULL;
-			gether_disconnect(&ncm->port);
-			ncm_reset_values(ncm);
-		}
+		scoped_guard(mutex, &opts->lock)
+			if (opts->net) {
+				DBG(cdev, "reset ncm\n");
+				opts->net = NULL;
+				gether_disconnect(&ncm->port);
+				ncm_reset_values(ncm);
+			}
 
 		/*
 		 * CDC Network only sends data in non-default altsettings.
@@ -919,7 +926,8 @@ static int ncm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 			net = gether_connect(&ncm->port);
 			if (IS_ERR(net))
 				return PTR_ERR(net);
-			ncm->netdev = net;
+			scoped_guard(mutex, &opts->lock)
+				opts->net = net;
 		}
 
 		spin_lock(&ncm->lock);
@@ -1366,14 +1374,16 @@ static int ncm_unwrap_ntb(struct gether *port,
 static void ncm_disable(struct usb_function *f)
 {
 	struct f_ncm		*ncm = func_to_ncm(f);
+	struct f_ncm_opts	*opts = func_to_ncm_opts(f);
 	struct usb_composite_dev *cdev = f->config->cdev;
 
 	DBG(cdev, "ncm deactivated\n");
 
-	if (ncm->netdev) {
-		ncm->netdev = NULL;
-		gether_disconnect(&ncm->port);
-	}
+	scoped_guard(mutex, &opts->lock)
+		if (opts->net) {
+			opts->net = NULL;
+			gether_disconnect(&ncm->port);
+		}
 
 	if (ncm->notify->enabled) {
 		usb_ep_disable(ncm->notify);
@@ -1433,39 +1443,44 @@ static int ncm_bind(struct usb_configuration *c, struct usb_function *f)
 {
 	struct usb_composite_dev *cdev = c->cdev;
 	struct f_ncm		*ncm = func_to_ncm(f);
+	struct f_ncm_opts	*ncm_opts = func_to_ncm_opts(f);
 	struct usb_string	*us;
 	int			status = 0;
 	struct usb_ep		*ep;
-	struct f_ncm_opts	*ncm_opts;
 
 	struct usb_os_desc_table	*os_desc_table __free(kfree) = NULL;
+	struct net_device		*netdev __free(free_gether_netdev) = NULL;
 	struct usb_request		*request __free(free_usb_request) = NULL;
 
 	if (!can_support_ecm(cdev->gadget))
 		return -EINVAL;
 
-	ncm_opts = container_of(f->fi, struct f_ncm_opts, func_inst);
-
 	if (cdev->use_os_string) {
 		os_desc_table = kzalloc(sizeof(*os_desc_table), GFP_KERNEL);
 		if (!os_desc_table)
 			return -ENOMEM;
 	}
 
-	mutex_lock(&ncm_opts->lock);
-	gether_set_gadget(ncm_opts->net, cdev->gadget);
-	if (!ncm_opts->bound) {
-		ncm_opts->net->mtu = (ncm_opts->max_segment_size - ETH_HLEN);
-		status = gether_register_netdev(ncm_opts->net);
+	netdev = gether_setup_default();
+	if (IS_ERR(netdev))
+		return -ENOMEM;
+
+	scoped_guard(mutex, &ncm_opts->lock) {
+		gether_apply_opts(netdev, &ncm_opts->net_opts);
+		netdev->mtu = ncm_opts->max_segment_size - ETH_HLEN;
 	}
-	mutex_unlock(&ncm_opts->lock);
 
+	gether_set_gadget(netdev, cdev->gadget);
+	status = gether_register_netdev(netdev);
 	if (status)
 		return status;
 
-	ncm_opts->bound = true;
-
-	ncm_string_defs[1].s = ncm->ethaddr;
+	/* export host's Ethernet address in CDC format */
+	status = gether_get_host_addr_cdc(netdev, ncm->ethaddr,
+					  sizeof(ncm->ethaddr));
+	if (status < 12)
+		return -EINVAL;
+	ncm_string_defs[STRING_MAC_IDX].s = ncm->ethaddr;
 
 	us = usb_gstrings_attach(cdev, ncm_strings,
 				 ARRAY_SIZE(ncm_string_defs));
@@ -1563,6 +1578,8 @@ static int ncm_bind(struct usb_configuration *c, struct usb_function *f)
 		f->os_desc_n = 1;
 	}
 	ncm->notify_req = no_free_ptr(request);
+	ncm->netdev = no_free_ptr(netdev);
+	ncm->port.ioport = netdev_priv(ncm->netdev);
 
 	DBG(cdev, "CDC Network: IN/%s OUT/%s NOTIFY/%s\n",
 			ncm->port.in_ep->name, ncm->port.out_ep->name,
@@ -1577,19 +1594,19 @@ static inline struct f_ncm_opts *to_f_ncm_opts(struct config_item *item)
 }
 
 /* f_ncm_item_ops */
-USB_ETHERNET_CONFIGFS_ITEM(ncm);
+USB_ETHER_OPTS_ITEM(ncm);
 
 /* f_ncm_opts_dev_addr */
-USB_ETHERNET_CONFIGFS_ITEM_ATTR_DEV_ADDR(ncm);
+USB_ETHER_OPTS_ATTR_DEV_ADDR(ncm);
 
 /* f_ncm_opts_host_addr */
-USB_ETHERNET_CONFIGFS_ITEM_ATTR_HOST_ADDR(ncm);
+USB_ETHER_OPTS_ATTR_HOST_ADDR(ncm);
 
 /* f_ncm_opts_qmult */
-USB_ETHERNET_CONFIGFS_ITEM_ATTR_QMULT(ncm);
+USB_ETHER_OPTS_ATTR_QMULT(ncm);
 
 /* f_ncm_opts_ifname */
-USB_ETHERNET_CONFIGFS_ITEM_ATTR_IFNAME(ncm);
+USB_ETHER_OPTS_ATTR_IFNAME(ncm);
 
 static ssize_t ncm_opts_max_segment_size_show(struct config_item *item,
 					      char *page)
@@ -1655,34 +1672,27 @@ static void ncm_free_inst(struct usb_function_instance *f)
 	struct f_ncm_opts *opts;
 
 	opts = container_of(f, struct f_ncm_opts, func_inst);
-	if (opts->bound)
-		gether_cleanup(netdev_priv(opts->net));
-	else
-		free_netdev(opts->net);
 	kfree(opts->ncm_interf_group);
 	kfree(opts);
 }
 
 static struct usb_function_instance *ncm_alloc_inst(void)
 {
-	struct f_ncm_opts *opts;
+	struct usb_function_instance *ret;
 	struct usb_os_desc *descs[1];
 	char *names[1];
 	struct config_group *ncm_interf_group;
 
-	opts = kzalloc(sizeof(*opts), GFP_KERNEL);
+	struct f_ncm_opts *opts __free(kfree) = kzalloc(sizeof(*opts), GFP_KERNEL);
 	if (!opts)
 		return ERR_PTR(-ENOMEM);
+
+	opts->net = NULL;
 	opts->ncm_os_desc.ext_compat_id = opts->ncm_ext_compat_id;
+	gether_setup_opts_default(&opts->net_opts, "usb");
 
 	mutex_init(&opts->lock);
 	opts->func_inst.free_func_inst = ncm_free_inst;
-	opts->net = gether_setup_default();
-	if (IS_ERR(opts->net)) {
-		struct net_device *net = opts->net;
-		kfree(opts);
-		return ERR_CAST(net);
-	}
 	opts->max_segment_size = ETH_FRAME_LEN;
 	INIT_LIST_HEAD(&opts->ncm_os_desc.ext_prop);
 
@@ -1693,26 +1703,22 @@ static struct usb_function_instance *ncm_alloc_inst(void)
 	ncm_interf_group =
 		usb_os_desc_prepare_interf_dir(&opts->func_inst.group, 1, descs,
 					       names, THIS_MODULE);
-	if (IS_ERR(ncm_interf_group)) {
-		ncm_free_inst(&opts->func_inst);
+	if (IS_ERR(ncm_interf_group))
 		return ERR_CAST(ncm_interf_group);
-	}
 	opts->ncm_interf_group = ncm_interf_group;
 
-	return &opts->func_inst;
+	ret = &opts->func_inst;
+	retain_and_null_ptr(opts);
+	return ret;
 }
 
 static void ncm_free(struct usb_function *f)
 {
-	struct f_ncm *ncm;
-	struct f_ncm_opts *opts;
+	struct f_ncm_opts *opts = func_to_ncm_opts(f);
 
-	ncm = func_to_ncm(f);
-	opts = container_of(f->fi, struct f_ncm_opts, func_inst);
-	kfree(ncm);
-	mutex_lock(&opts->lock);
-	opts->refcnt--;
-	mutex_unlock(&opts->lock);
+	scoped_guard(mutex, &opts->lock)
+		opts->refcnt--;
+	kfree(func_to_ncm(f));
 }
 
 static void ncm_unbind(struct usb_configuration *c, struct usb_function *f)
@@ -1736,13 +1742,15 @@ static void ncm_unbind(struct usb_configuration *c, struct usb_function *f)
 
 	kfree(ncm->notify_req->buf);
 	usb_ep_free_request(ncm->notify, ncm->notify_req);
+
+	ncm->port.ioport = NULL;
+	gether_cleanup(netdev_priv(ncm->netdev));
 }
 
 static struct usb_function *ncm_alloc(struct usb_function_instance *fi)
 {
 	struct f_ncm		*ncm;
 	struct f_ncm_opts	*opts;
-	int status;
 
 	/* allocate and initialize one new instance */
 	ncm = kzalloc(sizeof(*ncm), GFP_KERNEL);
@@ -1750,22 +1758,12 @@ static struct usb_function *ncm_alloc(struct usb_function_instance *fi)
 		return ERR_PTR(-ENOMEM);
 
 	opts = container_of(fi, struct f_ncm_opts, func_inst);
-	mutex_lock(&opts->lock);
-	opts->refcnt++;
 
-	/* export host's Ethernet address in CDC format */
-	status = gether_get_host_addr_cdc(opts->net, ncm->ethaddr,
-				      sizeof(ncm->ethaddr));
-	if (status < 12) { /* strlen("01234567890a") */
-		kfree(ncm);
-		mutex_unlock(&opts->lock);
-		return ERR_PTR(-EINVAL);
-	}
+	scoped_guard(mutex, &opts->lock)
+		opts->refcnt++;
 
 	spin_lock_init(&ncm->lock);
 	ncm_reset_values(ncm);
-	ncm->port.ioport = netdev_priv(opts->net);
-	mutex_unlock(&opts->lock);
 	ncm->port.is_fixed = true;
 	ncm->port.supports_multi_frame = true;
 
drivers/usb/gadget/function/u_ncm.h +3 -1
index 49ec095cdb4b6..d99330fe31e88 100644
@@ -15,11 +15,13 @@
 
 #include <linux/usb/composite.h>
 
+#include "u_ether.h"
+
 struct f_ncm_opts {
 	struct usb_function_instance	func_inst;
 	struct net_device		*net;
-	bool				bound;
 
+	struct gether_opts		net_opts;
 	struct config_group		*ncm_interf_group;
 	struct usb_os_desc		ncm_os_desc;
 	char				ncm_ext_compat_id[16];
Signature · 1 line
2.51.0
author maintainer
#95 lore raw

PATCH 89/314 accel/rocket: fix unwinding in error path in rocket_core_init

In reply to Sasha Levin

From: Quentin Schulz <[email protected]>

[ Upstream commit f509a081f6a289f7c66856333b3becce7a33c97e ]

When rocket_job_init() is called, iommu_group_get() has already been called, therefore we should call iommu_group_put() and make the iommu_group pointer NULL. This aligns with what's done in rocket_core_fini().

If pm_runtime_resume_and_get() somehow fails, not only should rocket_job_fini() be called but we should also unwind everything done before that, that is, disable PM, put the iommu_group, NULLify it and then call rocket_job_fini(). This is exactly what's done in rocket_core_fini() so let's call that function instead of duplicating the code.

---
 drivers/accel/rocket/rocket_core.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)
drivers/accel/rocket/rocket_core.c +5 -2
index abe7719c1db46..b3b2fa9ba645a 100644
@@ -59,8 +59,11 @@ int rocket_core_init(struct rocket_core *core)
 	core->iommu_group = iommu_group_get(dev);
 
 	err = rocket_job_init(core);
-	if (err)
+	if (err) {
+		iommu_group_put(core->iommu_group);
+		core->iommu_group = NULL;
 		return err;
+	}
 
 	pm_runtime_use_autosuspend(dev);
 
@@ -76,7 +79,7 @@ int rocket_core_init(struct rocket_core *core)
 
 	err = pm_runtime_resume_and_get(dev);
 	if (err) {
-		rocket_job_fini(core);
+		rocket_core_fini(core);
 		return err;
 	}
 
Signature · 1 line
2.51.0
author maintainer
#96 lore raw

PATCH 90/314 accel/rocket: fix unwinding in error path in rocket_probe

In reply to Sasha Levin

From: Quentin Schulz <[email protected]>

[ Upstream commit 34f4495a7f72895776b81969639f527c99eb12b9 ]

When rocket_core_init() fails (as could be the case with EPROBE_DEFER), we need to properly unwind by decrementing the counter we just incremented and if this is the first core we failed to probe, remove the rocket DRM device with rocket_device_fini() as well. This matches the logic in rocket_remove(). Failing to properly unwind results in out-of-bounds accesses.

---
 drivers/accel/rocket/rocket_drv.c | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)
drivers/accel/rocket/rocket_drv.c +14 -1
index 5c0b63f0a8f00..f6ef4c7aeef11 100644
@@ -13,6 +13,7 @@
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 
+#include "rocket_device.h"
 #include "rocket_drv.h"
 #include "rocket_gem.h"
 #include "rocket_job.h"
@@ -158,6 +159,8 @@ static const struct drm_driver rocket_drm_driver = {
 
 static int rocket_probe(struct platform_device *pdev)
 {
+	int ret;
+
 	if (rdev == NULL) {
 		/* First core probing, initialize DRM device. */
 		rdev = rocket_device_init(drm_dev, &rocket_drm_driver);
@@ -177,7 +180,17 @@ static int rocket_probe(struct platform_device *pdev)
 
 	rdev->num_cores++;
 
-	return rocket_core_init(&rdev->cores[core]);
+	ret = rocket_core_init(&rdev->cores[core]);
+	if (ret) {
+		rdev->num_cores--;
+
+		if (rdev->num_cores == 0) {
+			rocket_device_fini(rdev);
+			rdev = NULL;
+		}
+	}
+
+	return ret;
 }
 
 static void rocket_remove(struct platform_device *pdev)
Signature · 1 line
2.51.0
author maintainer
#97 lore raw

PATCH 91/314 media: tegra-video: Fix memory leak in __tegra_channel_try_format()

In reply to Sasha Levin

From: Zilin Guan <[email protected]>

[ Upstream commit 43e5302d22334f1183dec3e0d5d8007eefe2817c ]

The state object allocated by __v4l2_subdev_state_alloc() must be freed with __v4l2_subdev_state_free() when it is no longer needed.

In __tegra_channel_try_format(), two error paths return directly after v4l2_subdev_call() fails, without freeing the allocated 'sd_state' object. This violates the requirement and causes a memory leak.

Fix this by introducing a cleanup label and using goto statements in the error paths to ensure that __v4l2_subdev_state_free() is always called before the function returns.

Fixes 56f64b82356b7 ("media: tegra-video: Use zero crop settings if subdev has no get_selection")
Fixes 1ebaeb09830f3 ("media: tegra-video: Add support for external sensor capture")
---
 drivers/staging/media/tegra-video/vi.c | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)
drivers/staging/media/tegra-video/vi.c +8 -5
index c9276ff76157f..14b327afe045e 100644
@@ -438,7 +438,7 @@ static int __tegra_channel_try_format(struct tegra_vi_channel *chan,
 		.target = V4L2_SEL_TGT_CROP_BOUNDS,
 	};
 	struct v4l2_rect *try_crop;
-	int ret;
+	int ret = 0;
 
 	subdev = tegra_channel_get_remote_source_subdev(chan);
 	if (!subdev)
@@ -482,8 +482,10 @@ static int __tegra_channel_try_format(struct tegra_vi_channel *chan,
 		} else {
 			ret = v4l2_subdev_call(subdev, pad, get_selection,
 					       NULL, &sdsel);
-			if (ret)
-				return -EINVAL;
+			if (ret) {
+				ret = -EINVAL;
+				goto out_free;
+			}
 
 			try_crop->width = sdsel.r.width;
 			try_crop->height = sdsel.r.height;
@@ -495,14 +497,15 @@ static int __tegra_channel_try_format(struct tegra_vi_channel *chan,
 
 	ret = v4l2_subdev_call(subdev, pad, set_fmt, sd_state, &fmt);
 	if (ret < 0)
-		return ret;
+		goto out_free;
 
 	v4l2_fill_pix_format(pix, &fmt.format);
 	chan->vi->ops->vi_fmt_align(pix, fmtinfo->bpp);
 
+out_free:
 	__v4l2_subdev_state_free(sd_state);
 
-	return 0;
+	return ret;
 }
 
 static int tegra_channel_try_format(struct file *file, void *fh,
Signature · 1 line
2.51.0
author maintainer
#98 lore raw

PATCH 92/314 KVM: x86: Ignore -EBUSY when checking nested events from vcpu_block()

In reply to Sasha Levin

From: Sean Christopherson <[email protected]>

[ Upstream commit ead63640d4e72e6f6d464f4e31f7fecb79af8869 ]

Ignore -EBUSY when checking nested events after exiting a blocking state while L2 is active, as exiting to userspace will generate a spurious userspace exit, usually with KVM_EXIT_UNKNOWN, and likely lead to the VM's demise. Continuing with the wakeup isn't perfect either, as *something* has gone sideways if a vCPU is awakened in L2 with an injected event (or worse, a nested run pending), but continuing on gives the VM a decent chance of surviving without any major side effects.

As explained in the Fixes commits, it _should_ be impossible for a vCPU to be put into a blocking state with an already-injected event (exception, IRQ, or NMI). Unfortunately, userspace can stuff MP_STATE and/or injected events, and thus put the vCPU into what should be an impossible state.

Don't bother trying to preserve the WARN, e.g. with an anti-syzkaller Kconfig, as WARNs can (hopefully) be added in paths where _KVM_ would be violating x86 architecture, e.g. by WARNing if KVM attempts to inject an exception or interrupt while the vCPU isn't running.

Cc Alessandro Ratti <[email protected]>
Fixes 26844fee6ade ("KVM: x86: never write to memory from kvm_vcpu_check_block()")
Fixes 45405155d876 ("KVM: x86: WARN if a vCPU gets a valid wakeup that KVM can't yet inject")
Reported-by [email protected]
---
 arch/x86/kvm/x86.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)
arch/x86/kvm/x86.c +1 -2
index aeb7f902b3c7f..2ab445c0126b3 100644
@@ -11598,8 +11598,7 @@ static inline int vcpu_block(struct kvm_vcpu *vcpu)
 	if (is_guest_mode(vcpu)) {
 		int r = kvm_check_nested_events(vcpu);
 
-		WARN_ON_ONCE(r == -EBUSY);
-		if (r < 0)
+		if (r < 0 && r != -EBUSY)
 			return 0;
 	}
 
Signature · 1 line
2.51.0
author maintainer
#99 lore raw

PATCH 93/314 drm/tegra: dsi: fix device leak on probe

In reply to Sasha Levin

From: Johan Hovold <[email protected]>

[ Upstream commit bfef062695570842cf96358f2f46f4c6642c6689 ]

Make sure to drop the reference taken when looking up the companion (ganged) device and its driver data during probe().

Note that holding a reference to a device does not prevent its driver data from going away so there is no point in keeping the reference.

Fixes e94236cde4d5 ("drm/tegra: dsi: Add ganged mode support")
Fixes 221e3638feb8 ("drm/tegra: Fix reference leak in tegra_dsi_ganged_probe")
Cc [email protected] # 3.19: 221e3638feb8
Cc Thierry Reding <[email protected]>
---
 drivers/gpu/drm/tegra/dsi.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)
drivers/gpu/drm/tegra/dsi.c +2 -4
index ddfb2858acbf1..5aa78b902adac 100644
@@ -1540,11 +1540,9 @@ static int tegra_dsi_ganged_probe(struct tegra_dsi *dsi)
 			return -EPROBE_DEFER;
 
 		dsi->slave = platform_get_drvdata(gangster);
-
-		if (!dsi->slave) {
-			put_device(&gangster->dev);
+		put_device(&gangster->dev);
+		if (!dsi->slave)
 			return -EPROBE_DEFER;
-		}
 
 		dsi->slave->master = dsi;
 	}
Signature · 1 line
2.51.0
author maintainer
#100 lore raw

PATCH 94/314 unwind: Simplify unwind_user_next_fp() alignment check

In reply to Sasha Levin

From: Peter Zijlstra <[email protected]>

[ Upstream commit 5578534e4b92350995a20068f2e6ea3186c62d7f ]

2^log_2(n) == n

Stable-dep-of: d55c571e4333 ("x86/uprobes: Fix XOL allocation failure for 32-bit tasks")

---
 kernel/unwind/user.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)
kernel/unwind/user.c +1 -3
index 97a8415e3216f..9dcde797b5d93 100644
@@ -19,7 +19,6 @@ static int unwind_user_next_fp(struct unwind_user_state *state)
 {
 	const struct unwind_user_frame *frame = &fp_frame;
 	unsigned long cfa, fp, ra;
-	unsigned int shift;
 
 	if (frame->use_fp) {
 		if (state->fp < state->sp)
@@ -37,8 +36,7 @@ static int unwind_user_next_fp(struct unwind_user_state *state)
 		return -EINVAL;
 
 	/* Make sure that the address is word aligned */
-	shift = sizeof(long) == 4 ? 2 : 3;
-	if (cfa & ((1 << shift) - 1))
+	if (cfa & (sizeof(long) - 1))
 		return -EINVAL;
 
 	/* Find the Return Address (RA) */
Signature · 1 line
2.51.0
author maintainer
#101 lore raw

PATCH 95/314 unwind: Implement compat fp unwind

In reply to Sasha Levin

From: Peter Zijlstra <[email protected]>

[ Upstream commit c79dd946e370af3537edb854f210cba3a94b4516 ]

It is important to be able to unwind compat tasks too.

Stable-dep-of: d55c571e4333 ("x86/uprobes: Fix XOL allocation failure for 32-bit tasks")

---
 include/linux/unwind_user_types.h |  1 +
 kernel/unwind/user.c              | 40 ++++++++++++++++++++++---------
 2 files changed, 30 insertions(+), 11 deletions(-)
include/linux/unwind_user_types.h +1 -0
index a449f15be8902..938f7e6233327 100644
@@ -36,6 +36,7 @@ struct unwind_user_state {
 	unsigned long				ip;
 	unsigned long				sp;
 	unsigned long				fp;
+	unsigned int				ws;
 	enum unwind_user_type			current_type;
 	unsigned int				available_types;
 	bool					done;
kernel/unwind/user.c +29 -11
index 9dcde797b5d93..642871527a132 100644
@@ -8,19 +8,32 @@
 #include <linux/unwind_user.h>
 #include <linux/uaccess.h>
 
-static const struct unwind_user_frame fp_frame = {
-	ARCH_INIT_USER_FP_FRAME
-};
-
 #define for_each_user_frame(state) \
 	for (unwind_user_start(state); !(state)->done; unwind_user_next(state))
 
+static inline int
+get_user_word(unsigned long *word, unsigned long base, int off, unsigned int ws)
+{
+	unsigned long __user *addr = (void __user *)base + off;
+#ifdef CONFIG_COMPAT
+	if (ws == sizeof(int)) {
+		unsigned int data;
+		int ret = get_user(data, (unsigned int __user *)addr);
+		*word = data;
+		return ret;
+	}
+#endif
+	return get_user(*word, addr);
+}
+
 static int unwind_user_next_fp(struct unwind_user_state *state)
 {
-	const struct unwind_user_frame *frame = &fp_frame;
+	const struct unwind_user_frame frame = {
+		ARCH_INIT_USER_FP_FRAME(state->ws)
+	};
 	unsigned long cfa, fp, ra;
 
-	if (frame->use_fp) {
+	if (frame.use_fp) {
 		if (state->fp < state->sp)
 			return -EINVAL;
 		cfa = state->fp;
@@ -29,26 +42,26 @@ static int unwind_user_next_fp(struct unwind_user_state *state)
 	}
 
 	/* Get the Canonical Frame Address (CFA) */
-	cfa += frame->cfa_off;
+	cfa += frame.cfa_off;
 
 	/* stack going in wrong direction? */
 	if (cfa <= state->sp)
 		return -EINVAL;
 
 	/* Make sure that the address is word aligned */
-	if (cfa & (sizeof(long) - 1))
+	if (cfa & (state->ws - 1))
 		return -EINVAL;
 
 	/* Find the Return Address (RA) */
-	if (get_user(ra, (unsigned long *)(cfa + frame->ra_off)))
+	if (get_user_word(&ra, cfa, frame.ra_off, state->ws))
 		return -EINVAL;
 
-	if (frame->fp_off && get_user(fp, (unsigned long __user *)(cfa + frame->fp_off)))
+	if (frame.fp_off && get_user_word(&fp, cfa, frame.fp_off, state->ws))
 		return -EINVAL;
 
 	state->ip = ra;
 	state->sp = cfa;
-	if (frame->fp_off)
+	if (frame.fp_off)
 		state->fp = fp;
 	return 0;
 }
@@ -100,6 +113,11 @@ static int unwind_user_start(struct unwind_user_state *state)
 	state->ip = instruction_pointer(regs);
 	state->sp = user_stack_pointer(regs);
 	state->fp = frame_pointer(regs);
+	state->ws = unwind_user_word_size(regs);
+	if (!state->ws) {
+		state->done = true;
+		return -EINVAL;
+	}
 
 	return 0;
 }
Signature · 1 line
2.51.0
author maintainer
#102 lore raw

PATCH 96/314 unwind_user/x86: Enable frame pointer unwinding on x86

In reply to Sasha Levin

From: Josh Poimboeuf <[email protected]>

[ Upstream commit 49cf34c0815f93fb2ea3ab5cfbac1124bd9b45d0 ]

Use ARCH_INIT_USER_FP_FRAME to describe how frame pointers are unwound on x86, and enable CONFIG_HAVE_UNWIND_USER_FP accordingly so the unwind_user interfaces can be used.

Stable-dep-of: d55c571e4333 ("x86/uprobes: Fix XOL allocation failure for 32-bit tasks")

---
 arch/x86/Kconfig                   |  1 +
 arch/x86/include/asm/unwind_user.h | 25 +++++++++++++++++++++++++
 2 files changed, 26 insertions(+)
 create mode 100644 arch/x86/include/asm/unwind_user.h
arch/x86/Kconfig +1 -0
index a3700766a8c08..ee41af778a9dc 100644
@@ -298,6 +298,7 @@ config X86
 	select HAVE_SYSCALL_TRACEPOINTS
 	select HAVE_UACCESS_VALIDATION		if HAVE_OBJTOOL
 	select HAVE_UNSTABLE_SCHED_CLOCK
+	select HAVE_UNWIND_USER_FP		if X86_64
 	select HAVE_USER_RETURN_NOTIFIER
 	select HAVE_GENERIC_VDSO
 	select VDSO_GETRANDOM			if X86_64
arch/x86/include/asm/unwind_user.h new file +25 -0
new file mode 100644
index 0000000000000..b166e102d4445
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_X86_UNWIND_USER_H
+#define _ASM_X86_UNWIND_USER_H
+
+#include <asm/ptrace.h>
+
+#define ARCH_INIT_USER_FP_FRAME(ws)			\
+	.cfa_off	=  2*(ws),			\
+	.ra_off		= -1*(ws),			\
+	.fp_off		= -2*(ws),			\
+	.use_fp		= true,
+
+static inline int unwind_user_word_size(struct pt_regs *regs)
+{
+	/* We can't unwind VM86 stacks */
+	if (regs->flags & X86_VM_MASK)
+		return 0;
+#ifdef CONFIG_X86_64
+	if (!user_64bit_mode(regs))
+		return sizeof(int);
+#endif
+	return sizeof(long);
+}
+
+#endif /* _ASM_X86_UNWIND_USER_H */
Signature · 1 line
2.51.0
author maintainer
#103 lore raw

PATCH 97/314 unwind_user/x86: Teach FP unwind about start of function

In reply to Sasha Levin

From: Peter Zijlstra <[email protected]>

[ Upstream commit ae25884ad749e7f6e0c3565513bdc8aa2554a425 ]

When userspace is interrupted at the start of a function, before we get a chance to complete the frame, unwind will miss one caller.

X86 has a uprobe specific fixup for this, add bits to the generic unwinder to support this.

Stable-dep-of: d55c571e4333 ("x86/uprobes: Fix XOL allocation failure for 32-bit tasks")

---
 arch/x86/events/core.c             | 40 ------------------------------
 arch/x86/include/asm/unwind_user.h | 12 +++++++++
 arch/x86/include/asm/uprobes.h     |  9 +++++++
 arch/x86/kernel/uprobes.c          | 32 ++++++++++++++++++++++++
 include/linux/unwind_user_types.h  |  1 +
 kernel/unwind/user.c               | 39 ++++++++++++++++++++++-------
 6 files changed, 84 insertions(+), 49 deletions(-)
arch/x86/events/core.c +0 -40
index 56df4855f38e9..64e2bf2d4a615 100644
@@ -2846,46 +2846,6 @@ static unsigned long get_segment_base(unsigned int segment)
 	return get_desc_base(desc);
 }
 
-#ifdef CONFIG_UPROBES
-/*
- * Heuristic-based check if uprobe is installed at the function entry.
- *
- * Under assumption of user code being compiled with frame pointers,
- * `push %rbp/%ebp` is a good indicator that we indeed are.
- *
- * Similarly, `endbr64` (assuming 64-bit mode) is also a common pattern.
- * If we get this wrong, captured stack trace might have one extra bogus
- * entry, but the rest of stack trace will still be meaningful.
- */
-static bool is_uprobe_at_func_entry(struct pt_regs *regs)
-{
-	struct arch_uprobe *auprobe;
-
-	if (!current->utask)
-		return false;
-
-	auprobe = current->utask->auprobe;
-	if (!auprobe)
-		return false;
-
-	/* push %rbp/%ebp */
-	if (auprobe->insn[0] == 0x55)
-		return true;
-
-	/* endbr64 (64-bit only) */
-	if (user_64bit_mode(regs) && is_endbr((u32 *)auprobe->insn))
-		return true;
-
-	return false;
-}
-
-#else
-static bool is_uprobe_at_func_entry(struct pt_regs *regs)
-{
-	return false;
-}
-#endif /* CONFIG_UPROBES */
-
 #ifdef CONFIG_IA32_EMULATION
 
 #include <linux/compat.h>
arch/x86/include/asm/unwind_user.h +12 -0
index b166e102d4445..c4f1ff8874d67 100644
@@ -3,6 +3,7 @@
 #define _ASM_X86_UNWIND_USER_H
 
 #include <asm/ptrace.h>
+#include <asm/uprobes.h>
 
 #define ARCH_INIT_USER_FP_FRAME(ws)			\
 	.cfa_off	=  2*(ws),			\
@@ -10,6 +11,12 @@
 	.fp_off		= -2*(ws),			\
 	.use_fp		= true,
 
+#define ARCH_INIT_USER_FP_ENTRY_FRAME(ws)		\
+	.cfa_off	=  1*(ws),			\
+	.ra_off		= -1*(ws),			\
+	.fp_off		= 0,				\
+	.use_fp		= false,
+
 static inline int unwind_user_word_size(struct pt_regs *regs)
 {
 	/* We can't unwind VM86 stacks */
@@ -22,4 +29,9 @@ static inline int unwind_user_word_size(struct pt_regs *regs)
 	return sizeof(long);
 }
 
+static inline bool unwind_user_at_function_start(struct pt_regs *regs)
+{
+	return is_uprobe_at_func_entry(regs);
+}
+
 #endif /* _ASM_X86_UNWIND_USER_H */
arch/x86/include/asm/uprobes.h +9 -0
index 1ee2e5115955c..362210c799987 100644
@@ -62,4 +62,13 @@ struct arch_uprobe_task {
 	unsigned int			saved_tf;
 };
 
+#ifdef CONFIG_UPROBES
+extern bool is_uprobe_at_func_entry(struct pt_regs *regs);
+#else
+static bool is_uprobe_at_func_entry(struct pt_regs *regs)
+{
+	return false;
+}
+#endif /* CONFIG_UPROBES */
+
 #endif	/* _ASM_UPROBES_H */
arch/x86/kernel/uprobes.c +32 -0
index 845aeaf36b8d2..7ef0535fcd547 100644
@@ -1819,3 +1819,35 @@ bool arch_uretprobe_is_alive(struct return_instance *ret, enum rp_check ctx,
 	else
 		return regs->sp <= ret->stack;
 }
+
+/*
+ * Heuristic-based check if uprobe is installed at the function entry.
+ *
+ * Under assumption of user code being compiled with frame pointers,
+ * `push %rbp/%ebp` is a good indicator that we indeed are.
+ *
+ * Similarly, `endbr64` (assuming 64-bit mode) is also a common pattern.
+ * If we get this wrong, captured stack trace might have one extra bogus
+ * entry, but the rest of stack trace will still be meaningful.
+ */
+bool is_uprobe_at_func_entry(struct pt_regs *regs)
+{
+	struct arch_uprobe *auprobe;
+
+	if (!current->utask)
+		return false;
+
+	auprobe = current->utask->auprobe;
+	if (!auprobe)
+		return false;
+
+	/* push %rbp/%ebp */
+	if (auprobe->insn[0] == 0x55)
+		return true;
+
+	/* endbr64 (64-bit only) */
+	if (user_64bit_mode(regs) && is_endbr((u32 *)auprobe->insn))
+		return true;
+
+	return false;
+}
include/linux/unwind_user_types.h +1 -0
index 938f7e6233327..412729a269bcc 100644
@@ -39,6 +39,7 @@ struct unwind_user_state {
 	unsigned int				ws;
 	enum unwind_user_type			current_type;
 	unsigned int				available_types;
+	bool					topmost;
 	bool					done;
 };
 
kernel/unwind/user.c +30 -9
index 642871527a132..39e2707894447 100644
@@ -26,14 +26,12 @@ get_user_word(unsigned long *word, unsigned long base, int off, unsigned int ws)
 	return get_user(*word, addr);
 }
 
-static int unwind_user_next_fp(struct unwind_user_state *state)
+static int unwind_user_next_common(struct unwind_user_state *state,
+				   const struct unwind_user_frame *frame)
 {
-	const struct unwind_user_frame frame = {
-		ARCH_INIT_USER_FP_FRAME(state->ws)
-	};
 	unsigned long cfa, fp, ra;
 
-	if (frame.use_fp) {
+	if (frame->use_fp) {
 		if (state->fp < state->sp)
 			return -EINVAL;
 		cfa = state->fp;
@@ -42,7 +40,7 @@ static int unwind_user_next_fp(struct unwind_user_state *state)
 	}
 
 	/* Get the Canonical Frame Address (CFA) */
-	cfa += frame.cfa_off;
+	cfa += frame->cfa_off;
 
 	/* stack going in wrong direction? */
 	if (cfa <= state->sp)
@@ -53,19 +51,41 @@ static int unwind_user_next_fp(struct unwind_user_state *state)
 		return -EINVAL;
 
 	/* Find the Return Address (RA) */
-	if (get_user_word(&ra, cfa, frame.ra_off, state->ws))
+	if (get_user_word(&ra, cfa, frame->ra_off, state->ws))
 		return -EINVAL;
 
-	if (frame.fp_off && get_user_word(&fp, cfa, frame.fp_off, state->ws))
+	if (frame->fp_off && get_user_word(&fp, cfa, frame->fp_off, state->ws))
 		return -EINVAL;
 
 	state->ip = ra;
 	state->sp = cfa;
-	if (frame.fp_off)
+	if (frame->fp_off)
 		state->fp = fp;
+	state->topmost = false;
 	return 0;
 }
 
+static int unwind_user_next_fp(struct unwind_user_state *state)
+{
+#ifdef CONFIG_HAVE_UNWIND_USER_FP
+	struct pt_regs *regs = task_pt_regs(current);
+
+	if (state->topmost && unwind_user_at_function_start(regs)) {
+		const struct unwind_user_frame fp_entry_frame = {
+			ARCH_INIT_USER_FP_ENTRY_FRAME(state->ws)
+		};
+		return unwind_user_next_common(state, &fp_entry_frame);
+	}
+
+	const struct unwind_user_frame fp_frame = {
+		ARCH_INIT_USER_FP_FRAME(state->ws)
+	};
+	return unwind_user_next_common(state, &fp_frame);
+#else
+	return -EINVAL;
+#endif
+}
+
 static int unwind_user_next(struct unwind_user_state *state)
 {
 	unsigned long iter_mask = state->available_types;
@@ -118,6 +138,7 @@ static int unwind_user_start(struct unwind_user_state *state)
 		state->done = true;
 		return -EINVAL;
 	}
+	state->topmost = true;
 
 	return 0;
 }
Signature · 1 line
2.51.0
author maintainer
#104 lore raw

PATCH 98/314 x86/uprobes: Fix XOL allocation failure for 32-bit tasks

In reply to Sasha Levin

From: Oleg Nesterov <[email protected]>

[ Upstream commit d55c571e4333fac71826e8db3b9753fadfbead6a ]

This script

#!/usr/bin/bash

echo 0 > /proc/sys/kernel/randomize_va_space

echo 'void main(void) {}' > TEST.c

# -fcf-protection to ensure that the 1st endbr32 insn can't be emulated gcc -m32 -fcf-protection=branch TEST.c -o test

bpftrace -e 'uprobe:./test:main {}' -c ./test

"hangs", the probed ./test task enters an endless loop.

The problem is that with randomize_va_space == 0 get_unmapped_area(TASK_SIZE - PAGE_SIZE) called by xol_add_vma() can not just return the "addr == TASK_SIZE - PAGE_SIZE" hint, this addr is used by the stack vma.

arch_get_unmapped_area_topdown() doesn't take TIF_ADDR32 into account and in_32bit_syscall() is false, this leads to info.high_limit > TASK_SIZE. vm_unmapped_area() happily returns the high address > TASK_SIZE and then get_unmapped_area() returns -ENOMEM after the "if (addr > TASK_SIZE - len)" check.

handle_swbp() doesn't report this failure (probably it should) and silently restarts the probed insn. Endless loop.

I think that the right fix should change the x86 get_unmapped_area() paths to rely on TIF_ADDR32 rather than in_32bit_syscall(). Note also that if CONFIG_X86_X32_ABI=y, in_x32_syscall() falsely returns true in this case because ->orig_ax = -1.

But we need a simple fix for -stable, so this patch just sets TS_COMPAT if the probed task is 32-bit to make in_ia32_syscall() true.

---
 arch/x86/kernel/uprobes.c | 24 ++++++++++++++++++++++++
 include/linux/uprobes.h   |  1 +
 kernel/events/uprobes.c   | 10 +++++++---
 3 files changed, 32 insertions(+), 3 deletions(-)
arch/x86/kernel/uprobes.c +24 -0
index 7ef0535fcd547..46aed82243964 100644
@@ -1851,3 +1851,27 @@ bool is_uprobe_at_func_entry(struct pt_regs *regs)
 
 	return false;
 }
+
+#ifdef CONFIG_IA32_EMULATION
+unsigned long arch_uprobe_get_xol_area(void)
+{
+	struct thread_info *ti = current_thread_info();
+	unsigned long vaddr;
+
+	/*
+	 * HACK: we are not in a syscall, but x86 get_unmapped_area() paths
+	 * ignore TIF_ADDR32 and rely on in_32bit_syscall() to calculate
+	 * vm_unmapped_area_info.high_limit.
+	 *
+	 * The #ifdef above doesn't cover the CONFIG_X86_X32_ABI=y case,
+	 * but in this case in_32bit_syscall() -> in_x32_syscall() always
+	 * (falsely) returns true because ->orig_ax == -1.
+	 */
+	if (test_thread_flag(TIF_ADDR32))
+		ti->status |= TS_COMPAT;
+	vaddr = get_unmapped_area(NULL, TASK_SIZE - PAGE_SIZE, PAGE_SIZE, 0, 0);
+	ti->status &= ~TS_COMPAT;
+
+	return vaddr;
+}
+#endif
include/linux/uprobes.h +1 -0
index ee3d36eda45dd..f548fea2adec8 100644
@@ -242,6 +242,7 @@ extern void arch_uprobe_clear_state(struct mm_struct *mm);
 extern void arch_uprobe_init_state(struct mm_struct *mm);
 extern void handle_syscall_uprobe(struct pt_regs *regs, unsigned long bp_vaddr);
 extern void arch_uprobe_optimize(struct arch_uprobe *auprobe, unsigned long vaddr);
+extern unsigned long arch_uprobe_get_xol_area(void);
 #else /* !CONFIG_UPROBES */
 struct uprobes_state {
 };
kernel/events/uprobes.c +7 -3
index 4f42e7af575f5..725c5772429dc 100644
@@ -1694,6 +1694,12 @@ static const struct vm_special_mapping xol_mapping = {
 	.mremap = xol_mremap,
 };
 
+unsigned long __weak arch_uprobe_get_xol_area(void)
+{
+	/* Try to map as high as possible, this is only a hint. */
+	return get_unmapped_area(NULL, TASK_SIZE - PAGE_SIZE, PAGE_SIZE, 0, 0);
+}
+
 /* Slot allocation for XOL */
 static int xol_add_vma(struct mm_struct *mm, struct xol_area *area)
 {
@@ -1709,9 +1715,7 @@ static int xol_add_vma(struct mm_struct *mm, struct xol_area *area)
 	}
 
 	if (!area->vaddr) {
-		/* Try to map as high as possible, this is only a hint. */
-		area->vaddr = get_unmapped_area(NULL, TASK_SIZE - PAGE_SIZE,
-						PAGE_SIZE, 0, 0);
+		area->vaddr = arch_uprobe_get_xol_area();
 		if (IS_ERR_VALUE(area->vaddr)) {
 			ret = area->vaddr;
 			goto fail;
Signature · 1 line
2.51.0
author maintainer
#105 lore raw

PATCH 99/314 ext4: correct the comments place for EXT4_EXT_MAY_ZEROOUT

In reply to Sasha Levin

From: Yang Erkun <[email protected]>

[ Upstream commit cc742fd1d184bb2a11bacf50587d2c85290622e4 ]

Move the comments just before we set EXT4_EXT_MAY_ZEROOUT in ext4_split_convert_extents.

Message-ID: <[email protected]>

Stable-dep-of: feaf2a80e78f ("ext4: don't set EXT4_GET_BLOCKS_CONVERT when splitting before submitting I/O")

---
 fs/ext4/extents.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
fs/ext4/extents.c +4 -4
index 88187fddc6424..459453e8bb16b 100644
@@ -3756,10 +3756,6 @@ static struct ext4_ext_path *ext4_split_convert_extents(handle_t *handle,
 			>> inode->i_sb->s_blocksize_bits;
 	if (eof_block < map->m_lblk + map->m_len)
 		eof_block = map->m_lblk + map->m_len;
-	/*
-	 * It is safe to convert extent to initialized via explicit
-	 * zeroout only if extent is fully inside i_size or new_size.
-	 */
 	depth = ext_depth(inode);
 	ex = path[depth].p_ext;
 	ee_block = le32_to_cpu(ex->ee_block);
@@ -3770,6 +3766,10 @@ static struct ext4_ext_path *ext4_split_convert_extents(handle_t *handle,
 		split_flag |= EXT4_EXT_DATA_ENTIRE_VALID1;
 	/* Convert to initialized */
 	} else if (flags & EXT4_GET_BLOCKS_CONVERT) {
+		/*
+		 * It is safe to convert extent to initialized via explicit
+		 * zeroout only if extent is fully inside i_size or new_size.
+		 */
 		split_flag |= ee_block + ee_len <= eof_block ?
 			      EXT4_EXT_MAY_ZEROOUT : 0;
 		split_flag |= (EXT4_EXT_MARK_UNWRIT2 | EXT4_EXT_DATA_VALID2);
Signature · 1 line
2.51.0
author maintainer
#106 lore raw

PATCH 100/314 ext4: don't set EXT4_GET_BLOCKS_CONVERT when splitting before submitting I/O

In reply to Sasha Levin

From: Zhang Yi <[email protected]>

[ Upstream commit feaf2a80e78f89ee8a3464126077ba8683b62791 ]

When allocating blocks during within-EOF DIO and writeback with dioread_nolock enabled, EXT4_GET_BLOCKS_PRE_IO was set to split an existing large unwritten extent. However, EXT4_GET_BLOCKS_CONVERT was set when calling ext4_split_convert_extents(), which may potentially result in stale data issues.

Assume we have an unwritten extent, and then DIO writes the second half.

[UUUUUUUUUUUUUUUU] on-disk extent U: unwritten extent
[UUUUUUUUUUUUUUUU] extent status tree

            |<-   ->| ----> dio write this range

First, ext4_iomap_alloc() call ext4_map_blocks() with EXT4_GET_BLOCKS_PRE_IO, EXT4_GET_BLOCKS_UNWRIT_EXT and EXT4_GET_BLOCKS_CREATE flags set. ext4_map_blocks() find this extent and call ext4_split_convert_extents() with EXT4_GET_BLOCKS_CONVERT and the above flags set.

Then, ext4_split_convert_extents() calls ext4_split_extent() with EXT4_EXT_MAY_ZEROOUT, EXT4_EXT_MARK_UNWRIT2 and EXT4_EXT_DATA_VALID2 flags set, and it calls ext4_split_extent_at() to split the second half with EXT4_EXT_DATA_VALID2, EXT4_EXT_MARK_UNWRIT1, EXT4_EXT_MAY_ZEROOUT and EXT4_EXT_MARK_UNWRIT2 flags set. However, ext4_split_extent_at() failed to insert extent since a temporary lack -ENOSPC. It zeroes out the first half but convert the entire on-disk extent to written since the EXT4_EXT_DATA_VALID2 flag set, but left the second half as unwritten in the extent status tree.

   [0000000000SSSSSS]  data                S: stale data, 0: zeroed
   [WWWWWWWWWWWWWWWW]  on-disk extent      W: written extent
   [WWWWWWWWWWUUUUUU]  extent status tree

Finally, if the DIO failed to write data to the disk, the stale data in the second half will be exposed once the cached extent entry is gone.

Fix this issue by not passing EXT4_GET_BLOCKS_CONVERT when splitting an unwritten extent before submitting I/O, and make ext4_split_convert_extents() to zero out the entire extent range to zero for this case, and also mark the extent in the extent status tree for consistency.

Fixes b8a8684502a0 ("ext4: Introduce FALLOC_FL_ZERO_RANGE flag for fallocate")

Message-ID: <[email protected]>

---
 fs/ext4/extents.c | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)
fs/ext4/extents.c +8 -4
index 459453e8bb16b..3ff8dcdd80ce9 100644
@@ -3764,15 +3764,19 @@ static struct ext4_ext_path *ext4_split_convert_extents(handle_t *handle,
 	/* Convert to unwritten */
 	if (flags & EXT4_GET_BLOCKS_CONVERT_UNWRITTEN) {
 		split_flag |= EXT4_EXT_DATA_ENTIRE_VALID1;
-	/* Convert to initialized */
-	} else if (flags & EXT4_GET_BLOCKS_CONVERT) {
+	/* Split the existing unwritten extent */
+	} else if (flags & (EXT4_GET_BLOCKS_UNWRIT_EXT |
+			    EXT4_GET_BLOCKS_CONVERT)) {
 		/*
 		 * It is safe to convert extent to initialized via explicit
 		 * zeroout only if extent is fully inside i_size or new_size.
 		 */
 		split_flag |= ee_block + ee_len <= eof_block ?
 			      EXT4_EXT_MAY_ZEROOUT : 0;
-		split_flag |= (EXT4_EXT_MARK_UNWRIT2 | EXT4_EXT_DATA_VALID2);
+		split_flag |= EXT4_EXT_MARK_UNWRIT2;
+		/* Convert to initialized */
+		if (flags & EXT4_GET_BLOCKS_CONVERT)
+			split_flag |= EXT4_EXT_DATA_VALID2;
 	}
 	flags |= EXT4_GET_BLOCKS_PRE_IO;
 	return ext4_split_extent(handle, inode, path, map, split_flag, flags,
@@ -3951,7 +3955,7 @@ ext4_ext_handle_unwritten_extents(handle_t *handle, struct inode *inode,
 	/* get_block() before submitting IO, split the extent */
 	if (flags & EXT4_GET_BLOCKS_PRE_IO) {
 		path = ext4_split_convert_extents(handle, inode, map, path,
-				flags | EXT4_GET_BLOCKS_CONVERT, allocated);
+						  flags, allocated);
 		if (IS_ERR(path))
 			return path;
 		/*
Signature · 1 line
2.51.0
author maintainer
#107 lore raw

PATCH 101/314 media: iris: remove v4l2_m2m_ioctl_{de,en}coder_cmd API usage during STOP handling

In reply to Sasha Levin

From: Dikshita Agarwal <[email protected]>

[ Upstream commit 8fc707d13df517222db12b465af4aa9df05c99e1 ]

Currently v4l2_m2m_ioctl_{de,enc}coder_cmd is being invoked during STOP command handling. However, this is not required as the iris driver has its own drain and stop handling mechanism in place.

Using the m2m command API in this context leads to incorrect behavior, where the LAST flag is prematurely attached to a capture buffer, when there are no buffers in m2m source queue. But, in this scenario even though the source buffers are returned to client, hardware might still need to process the pending capture buffers.

Attaching LAST flag prematurely can result in the capture buffer being removed from the destination queue before the hardware has finished processing it, causing issues when the buffer is eventually returned by the hardware.

To prevent this, remove the m2m API usage in stop handling.

Fixes d09100763bed ("media: iris: add support for drain sequence")
Fixes 75db90ae067d ("media: iris: Add support for drain sequence in encoder video device")
---
 drivers/media/platform/qcom/iris/iris_vidc.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)
drivers/media/platform/qcom/iris/iris_vidc.c +6 -4
index d38d0f6961cd5..07682400de690 100644
@@ -572,9 +572,10 @@ static int iris_dec_cmd(struct file *filp, void *fh,
 
 	mutex_lock(&inst->lock);
 
-	ret = v4l2_m2m_ioctl_decoder_cmd(filp, fh, dec);
-	if (ret)
+	if (dec->cmd != V4L2_DEC_CMD_STOP && dec->cmd != V4L2_DEC_CMD_START) {
+		ret = -EINVAL;
 		goto unlock;
+	}
 
 	if (inst->state == IRIS_INST_DEINIT)
 		goto unlock;
@@ -605,9 +606,10 @@ static int iris_enc_cmd(struct file *filp, void *fh,
 
 	mutex_lock(&inst->lock);
 
-	ret = v4l2_m2m_ioctl_encoder_cmd(filp, fh, enc);
-	if (ret)
+	if (enc->cmd != V4L2_ENC_CMD_STOP && enc->cmd != V4L2_ENC_CMD_START) {
+		ret = -EINVAL;
 		goto unlock;
+	}
 
 	if (inst->state == IRIS_INST_DEINIT)
 		goto unlock;
Signature · 1 line
2.51.0
author maintainer
#108 lore raw

PATCH 102/314 media: iris: Add missing platform data entries for SM8750

In reply to Sasha Levin

From: Dikshita Agarwal <[email protected]>

[ Upstream commit bbef55f414100853d5bcea56a41f8b171bac8fcb ]

Two platform-data fields for SM8750 were missed:

- get_vpu_buffer_size = iris_vpu33_buf_size
Without this, the driver fails to allocate the required internal buffers, leading to basic decode/encode failures during session bring-up.

- max_core_mbps = ((7680 * 4320) / 256) * 60
Without this capability exposed, capability checks are incomplete and v4l2-compliance for encoder fails.

Fixes a5925a2ce077 ("media: iris: add VPU33 specific encoding buffer calculation")
Fixes a6882431a138 ("media: iris: Add support for ENUM_FRAMESIZES/FRAMEINTERVALS for encoder")
---
 drivers/media/platform/qcom/iris/iris_platform_gen2.c | 2 ++
 1 file changed, 2 insertions(+)
drivers/media/platform/qcom/iris/iris_platform_gen2.c +2 -0
index 36d69cc73986b..85beb80476de8 100644
@@ -916,6 +916,7 @@ struct iris_platform_data sm8750_data = {
 	.get_instance = iris_hfi_gen2_get_instance,
 	.init_hfi_command_ops = iris_hfi_gen2_command_ops_init,
 	.init_hfi_response_ops = iris_hfi_gen2_response_ops_init,
+	.get_vpu_buffer_size = iris_vpu33_buf_size,
 	.vpu_ops = &iris_vpu35_ops,
 	.set_preset_registers = iris_set_sm8550_preset_registers,
 	.icc_tbl = sm8550_icc_table,
@@ -946,6 +947,7 @@ struct iris_platform_data sm8750_data = {
 	.num_vpp_pipe = 4,
 	.max_session_count = 16,
 	.max_core_mbpf = NUM_MBS_8K * 2,
+	.max_core_mbps = ((7680 * 4320) / 256) * 60,
 	.dec_input_config_params_default =
 		sm8550_vdec_input_config_params_default,
 	.dec_input_config_params_default_size =
Signature · 1 line
2.51.0
author maintainer
#109 lore raw

PATCH 103/314 Input: synaptics_i2c - replace use of system_wq with system_dfl_wq

In reply to Sasha Levin

From: Marco Crivellari <[email protected]>

[ Upstream commit b3ee88e27798f0e8dd3a81867804d693da74d57d ]

Currently if a user enqueues a work item using schedule_delayed_work() the used wq is "system_wq" (per-cpu wq) while queue_delayed_work() use WORK_CPU_UNBOUND (used when a cpu is not specified). The same applies to schedule_work() that is using system_wq and queue_work(), that makes use again of WORK_CPU_UNBOUND.

This lack of consistency cannot be addressed without refactoring the API.

This patch continues the effort to refactor worqueue APIs, which has begun with the change introducing new workqueues and a new alloc_workqueue flag:

commit 128ea9f6ccfb ("workqueue: Add system_percpu_wq and system_dfl_wq") commit 930c2ea566af ("workqueue: Add new WQ_PERCPU flag")

This specific workload do not benefit from a per-cpu workqueue, so use the default unbound workqueue (system_dfl_wq) instead.

Stable-dep-of: 870c2e7cd881 ("Input: synaptics_i2c - guard polling restart in resume")

---
 drivers/input/mouse/synaptics_i2c.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/input/mouse/synaptics_i2c.c +4 -4
index a0d707e47d932..c8ddfff2605ff 100644
@@ -372,7 +372,7 @@ static irqreturn_t synaptics_i2c_irq(int irq, void *dev_id)
 {
 	struct synaptics_i2c *touch = dev_id;
 
-	mod_delayed_work(system_wq, &touch->dwork, 0);
+	mod_delayed_work(system_dfl_wq, &touch->dwork, 0);
 
 	return IRQ_HANDLED;
 }
@@ -448,7 +448,7 @@ static void synaptics_i2c_work_handler(struct work_struct *work)
 	 * We poll the device once in THREAD_IRQ_SLEEP_SECS and
 	 * if error is detected, we try to reset and reconfigure the touchpad.
 	 */
-	mod_delayed_work(system_wq, &touch->dwork, delay);
+	mod_delayed_work(system_dfl_wq, &touch->dwork, delay);
 }
 
 static int synaptics_i2c_open(struct input_dev *input)
@@ -461,7 +461,7 @@ static int synaptics_i2c_open(struct input_dev *input)
 		return ret;
 
 	if (polling_req)
-		mod_delayed_work(system_wq, &touch->dwork,
+		mod_delayed_work(system_dfl_wq, &touch->dwork,
 				msecs_to_jiffies(NO_DATA_SLEEP_MSECS));
 
 	return 0;
@@ -620,7 +620,7 @@ static int synaptics_i2c_resume(struct device *dev)
 	if (ret)
 		return ret;
 
-	mod_delayed_work(system_wq, &touch->dwork,
+	mod_delayed_work(system_dfl_wq, &touch->dwork,
 				msecs_to_jiffies(NO_DATA_SLEEP_MSECS));
 
 	return 0;
Signature · 1 line
2.51.0
author maintainer
#110 lore raw

PATCH 104/314 Input: synaptics_i2c - guard polling restart in resume

In reply to Sasha Levin

From: Minseong Kim <[email protected]>

[ Upstream commit 870c2e7cd881d7a10abb91f2b38135622d9f9f65 ]

synaptics_i2c_resume() restarts delayed work unconditionally, even when the input device is not opened. Guard the polling restart by taking the input device mutex and checking input_device_enabled() before re-queuing the delayed work.

Fixes eef3e4cab72ea ("Input: add driver for Synaptics I2C touchpad")
---
 drivers/input/mouse/synaptics_i2c.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)
drivers/input/mouse/synaptics_i2c.c +5 -2
index c8ddfff2605ff..29da66af36d74 100644
@@ -615,13 +615,16 @@ static int synaptics_i2c_resume(struct device *dev)
 	int ret;
 	struct i2c_client *client = to_i2c_client(dev);
 	struct synaptics_i2c *touch = i2c_get_clientdata(client);
+	struct input_dev *input = touch->input;
 
 	ret = synaptics_i2c_reset_config(client);
 	if (ret)
 		return ret;
 
-	mod_delayed_work(system_dfl_wq, &touch->dwork,
-				msecs_to_jiffies(NO_DATA_SLEEP_MSECS));
+	guard(mutex)(&input->mutex);
+	if (input_device_enabled(input))
+		mod_delayed_work(system_dfl_wq, &touch->dwork,
+				 msecs_to_jiffies(NO_DATA_SLEEP_MSECS));
 
 	return 0;
 }
Signature · 1 line
2.51.0
author maintainer
#111 lore raw

PATCH 105/314 iommu/vt-d: Skip dev-iotlb flush for inaccessible PCIe device without scalable mode

In reply to Sasha Levin

From: Jinhui Guo <[email protected]>

[ Upstream commit 42662d19839f34735b718129ea200e3734b07e50 ]

PCIe endpoints with ATS enabled and passed through to userspace (e.g., QEMU, DPDK) can hard-lock the host when their link drops, either by surprise removal or by a link fault.

Commit 4fc82cd907ac ("iommu/vt-d: Don't issue ATS Invalidation request when device is disconnected") adds pci_dev_is_disconnected() to devtlb_invalidation_with_pasid() so ATS invalidation is skipped only when the device is being safely removed, but it applies only when Intel IOMMU scalable mode is enabled.

With scalable mode disabled or unsupported, a system hard-lock occurs when a PCIe endpoint's link drops because the Intel IOMMU waits indefinitely for an ATS invalidation that cannot complete.

Call Trace:
 qi_submit_sync
 qi_flush_dev_iotlb
 __context_flush_dev_iotlb.part.0
 domain_context_clear_one_cb
 pci_for_each_dma_alias
 device_block_translation
 blocking_domain_attach_dev
 iommu_deinit_device
 __iommu_group_remove_device
 iommu_release_device
 iommu_bus_notifier
 blocking_notifier_call_chain
 bus_notify
 device_del
 pci_remove_bus_device
 pci_stop_and_remove_bus_device
 pciehp_unconfigure_device
 pciehp_disable_slot
 pciehp_handle_presence_or_link_change
 pciehp_ist

Commit 81e921fd3216 ("iommu/vt-d: Fix NULL domain on device release") adds intel_pasid_teardown_sm_context() to intel_iommu_release_device(), which calls qi_flush_dev_iotlb() and can also hard-lock the system when a PCIe endpoint's link drops.

Call Trace:
 qi_submit_sync
 qi_flush_dev_iotlb
 __context_flush_dev_iotlb.part.0
 intel_context_flush_no_pasid
 device_pasid_table_teardown
 pci_pasid_table_teardown
 pci_for_each_dma_alias
 intel_pasid_teardown_sm_context
 intel_iommu_release_device
 iommu_deinit_device
 __iommu_group_remove_device
 iommu_release_device
 iommu_bus_notifier
 blocking_notifier_call_chain
 bus_notify
 device_del
 pci_remove_bus_device
 pci_stop_and_remove_bus_device
 pciehp_unconfigure_device
 pciehp_disable_slot
 pciehp_handle_presence_or_link_change
 pciehp_ist

Sometimes the endpoint loses connection without a link-down event (e.g., due to a link fault); killing the process (virsh destroy) then hard-locks the host.

Call Trace:
 qi_submit_sync
 qi_flush_dev_iotlb
 __context_flush_dev_iotlb.part.0
 domain_context_clear_one_cb
 pci_for_each_dma_alias
 device_block_translation
 blocking_domain_attach_dev
 __iommu_attach_device
 __iommu_device_set_domain
 __iommu_group_set_domain_internal
 iommu_detach_group
 vfio_iommu_type1_detach_group
 vfio_group_detach_container
 vfio_group_fops_release
 __fput

pci_dev_is_disconnected() only covers safe-removal paths; pci_device_is_present() tests accessibility by reading vendor/device IDs and internally calls pci_dev_is_disconnected(). On a ConnectX-5 (8 GT/s, x2) this costs ~70 µs.

Since __context_flush_dev_iotlb() is only called on {attach,release}_dev paths (not hot), add pci_device_is_present() there to skip inaccessible devices and avoid the hard-lock.

Fixes 37764b952e1b ("iommu/vt-d: Global devTLB flush when present context entry changed")
Fixes 81e921fd3216 ("iommu/vt-d: Fix NULL domain on device release")
---
 drivers/iommu/intel/pasid.c | 8 ++++++++
 1 file changed, 8 insertions(+)
drivers/iommu/intel/pasid.c +8 -0
index 6782ba5f5e57f..7a64a55fb5887 100644
@@ -1114,6 +1114,14 @@ static void __context_flush_dev_iotlb(struct device_domain_info *info)
 	if (!info->ats_enabled)
 		return;
 
+	/*
+	 * Skip dev-IOTLB flush for inaccessible PCIe devices to prevent the
+	 * Intel IOMMU from waiting indefinitely for an ATS invalidation that
+	 * cannot complete.
+	 */
+	if (!pci_device_is_present(to_pci_dev(info->dev)))
+		return;
+
 	qi_flush_dev_iotlb(info->iommu, PCI_DEVID(info->bus, info->devfn),
 			   info->pfsid, info->ats_qdep, 0, MAX_AGAW_PFN_WIDTH);
 
Signature · 1 line
2.51.0
author maintainer
#112 lore raw

PATCH 106/314 arm64: dts: rockchip: Fix rk356x PCIe range mappings

In reply to Sasha Levin

From: Shawn Lin <[email protected]>

[ Upstream commit f63ea193a404481f080ca2958f73e9f364682db9 ]

The pcie bus address should be mapped 1:1 to the cpu side MMIO address, so that there is no same address allocated from normal system memory. Otherwise it's broken if the same address assigned to the EP for DMA purpose.Fix it to sync with the vendor BSP.

Fixes 568a67e742df ("arm64: dts: rockchip: Fix rk356x PCIe register and range mappings")
Fixes 66b51ea7d70f ("arm64: dts: rockchip: Add rk3568 PCIe2x1 controller")
Cc Andrew Powers-Holmes <[email protected]>
---
 arch/arm64/boot/dts/rockchip/rk3568.dtsi      | 4 ++--
 arch/arm64/boot/dts/rockchip/rk356x-base.dtsi | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)
arch/arm64/boot/dts/rockchip/rk3568.dtsi +2 -2
index e719a3df126c5..658097ed69714 100644
@@ -185,7 +185,7 @@ pcie3x1: pcie@fe270000 {
 		      <0x0 0xf2000000 0x0 0x00100000>;
 		ranges = <0x01000000 0x0 0xf2100000 0x0 0xf2100000 0x0 0x00100000>,
 			 <0x02000000 0x0 0xf2200000 0x0 0xf2200000 0x0 0x01e00000>,
-			 <0x03000000 0x0 0x40000000 0x3 0x40000000 0x0 0x40000000>;
+			 <0x03000000 0x3 0x40000000 0x3 0x40000000 0x0 0x40000000>;
 		reg-names = "dbi", "apb", "config";
 		resets = <&cru SRST_PCIE30X1_POWERUP>;
 		reset-names = "pipe";
@@ -238,7 +238,7 @@ pcie3x2: pcie@fe280000 {
 		      <0x0 0xf0000000 0x0 0x00100000>;
 		ranges = <0x01000000 0x0 0xf0100000 0x0 0xf0100000 0x0 0x00100000>,
 			 <0x02000000 0x0 0xf0200000 0x0 0xf0200000 0x0 0x01e00000>,
-			 <0x03000000 0x0 0x40000000 0x3 0x80000000 0x0 0x40000000>;
+			 <0x03000000 0x3 0x80000000 0x3 0x80000000 0x0 0x40000000>;
 		reg-names = "dbi", "apb", "config";
 		resets = <&cru SRST_PCIE30X2_POWERUP>;
 		reset-names = "pipe";
arch/arm64/boot/dts/rockchip/rk356x-base.dtsi +1 -1
index fd2214b6fad40..d654f98460ec0 100644
@@ -975,7 +975,7 @@ pcie2x1: pcie@fe260000 {
 		power-domains = <&power RK3568_PD_PIPE>;
 		ranges = <0x01000000 0x0 0xf4100000 0x0 0xf4100000 0x0 0x00100000>,
 			 <0x02000000 0x0 0xf4200000 0x0 0xf4200000 0x0 0x01e00000>,
-			 <0x03000000 0x0 0x40000000 0x3 0x00000000 0x0 0x40000000>;
+			 <0x03000000 0x3 0x00000000 0x3 0x00000000 0x0 0x40000000>;
 		resets = <&cru SRST_PCIE20_POWERUP>;
 		reset-names = "pipe";
 		#address-cells = <3>;
Signature · 1 line
2.51.0
author maintainer
#113 lore raw

PATCH 107/314 arm64: dts: rockchip: Fix rk3588 PCIe range mappings

In reply to Sasha Levin

From: Shawn Lin <[email protected]>

[ Upstream commit 46c56b737161060dfa468f25ae699749047902a2 ]

The pcie bus address should be mapped 1:1 to the cpu side MMIO address, so that there is no same address allocated from normal system memory. Otherwise it's broken if the same address assigned to the EP for DMA purpose.Fix it to sync with the vendor BSP.

Fixes 0acf4fa7f187 ("arm64: dts: rockchip: add PCIe3 support for rk3588")
Fixes 8d81b77f4c49 ("arm64: dts: rockchip: add rk3588 PCIe2 support")
Cc Sebastian Reichel <[email protected]>
---
 arch/arm64/boot/dts/rockchip/rk3588-base.dtsi  | 4 ++--
 arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi | 6 +++---
 2 files changed, 5 insertions(+), 5 deletions(-)
arch/arm64/boot/dts/rockchip/rk3588-base.dtsi +2 -2
index 2973f6bae1716..7e74e04057cfd 100644
@@ -1955,7 +1955,7 @@ pcie2x1l1: pcie@fe180000 {
 		power-domains = <&power RK3588_PD_PCIE>;
 		ranges = <0x01000000 0x0 0xf3100000 0x0 0xf3100000 0x0 0x00100000>,
 			 <0x02000000 0x0 0xf3200000 0x0 0xf3200000 0x0 0x00e00000>,
-			 <0x03000000 0x0 0x40000000 0x9 0xc0000000 0x0 0x40000000>;
+			 <0x03000000 0x9 0xc0000000 0x9 0xc0000000 0x0 0x40000000>;
 		reg = <0xa 0x40c00000 0x0 0x00400000>,
 		      <0x0 0xfe180000 0x0 0x00010000>,
 		      <0x0 0xf3000000 0x0 0x00100000>;
@@ -2007,7 +2007,7 @@ pcie2x1l2: pcie@fe190000 {
 		power-domains = <&power RK3588_PD_PCIE>;
 		ranges = <0x01000000 0x0 0xf4100000 0x0 0xf4100000 0x0 0x00100000>,
 			 <0x02000000 0x0 0xf4200000 0x0 0xf4200000 0x0 0x00e00000>,
-			 <0x03000000 0x0 0x40000000 0xa 0x00000000 0x0 0x40000000>;
+			 <0x03000000 0xa 0x00000000 0xa 0x00000000 0x0 0x40000000>;
 		reg = <0xa 0x41000000 0x0 0x00400000>,
 		      <0x0 0xfe190000 0x0 0x00010000>,
 		      <0x0 0xf4000000 0x0 0x00100000>;
arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi +3 -3
index 6e5a58428bbab..a2640014ee042 100644
@@ -375,7 +375,7 @@ pcie3x4: pcie@fe150000 {
 		power-domains = <&power RK3588_PD_PCIE>;
 		ranges = <0x01000000 0x0 0xf0100000 0x0 0xf0100000 0x0 0x00100000>,
 			 <0x02000000 0x0 0xf0200000 0x0 0xf0200000 0x0 0x00e00000>,
-			 <0x03000000 0x0 0x40000000 0x9 0x00000000 0x0 0x40000000>;
+			 <0x03000000 0x9 0x00000000 0x9 0x00000000 0x0 0x40000000>;
 		reg = <0xa 0x40000000 0x0 0x00400000>,
 		      <0x0 0xfe150000 0x0 0x00010000>,
 		      <0x0 0xf0000000 0x0 0x00100000>;
@@ -462,7 +462,7 @@ pcie3x2: pcie@fe160000 {
 		power-domains = <&power RK3588_PD_PCIE>;
 		ranges = <0x01000000 0x0 0xf1100000 0x0 0xf1100000 0x0 0x00100000>,
 			 <0x02000000 0x0 0xf1200000 0x0 0xf1200000 0x0 0x00e00000>,
-			 <0x03000000 0x0 0x40000000 0x9 0x40000000 0x0 0x40000000>;
+			 <0x03000000 0x9 0x40000000 0x9 0x40000000 0x0 0x40000000>;
 		reg = <0xa 0x40400000 0x0 0x00400000>,
 		      <0x0 0xfe160000 0x0 0x00010000>,
 		      <0x0 0xf1000000 0x0 0x00100000>;
@@ -512,7 +512,7 @@ pcie2x1l0: pcie@fe170000 {
 		power-domains = <&power RK3588_PD_PCIE>;
 		ranges = <0x01000000 0x0 0xf2100000 0x0 0xf2100000 0x0 0x00100000>,
 			 <0x02000000 0x0 0xf2200000 0x0 0xf2200000 0x0 0x00e00000>,
-			 <0x03000000 0x0 0x40000000 0x9 0x80000000 0x0 0x40000000>;
+			 <0x03000000 0x9 0x80000000 0x9 0x80000000 0x0 0x40000000>;
 		reg = <0xa 0x40800000 0x0 0x00400000>,
 		      <0x0 0xfe170000 0x0 0x00010000>,
 		      <0x0 0xf2000000 0x0 0x00100000>;
Signature · 1 line
2.51.0
author maintainer
#114 lore raw

PATCH 108/314 clk: tegra: tegra124-emc: fix device leak on set_rate()

In reply to Sasha Levin

From: Johan Hovold <[email protected]>

[ Upstream commit da61439c63d34ae6503d080a847f144d587e3a48 ]

Make sure to drop the reference taken when looking up the EMC device and its driver data on first set_rate().

Note that holding a reference to a device does not prevent its driver data from going away so there is no point in keeping the reference.

Fixes 2db04f16b589 ("clk: tegra: Add EMC clock driver")
Fixes 6d6ef58c2470 ("clk: tegra: tegra124-emc: Fix missing put_device() call in emc_ensure_emc_driver")
Cc [email protected] # 4.2: 6d6ef58c2470
Cc Mikko Perttunen <[email protected]>
Cc Miaoqian Lin <[email protected]>
---
 drivers/clk/tegra/clk-tegra124-emc.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/clk/tegra/clk-tegra124-emc.c +1 -1
index 0f6fb776b2298..5f1af6dfe7154 100644
@@ -197,8 +197,8 @@ static struct tegra_emc *emc_ensure_emc_driver(struct tegra_clk_emc *tegra)
 	tegra->emc_node = NULL;
 
 	tegra->emc = platform_get_drvdata(pdev);
+	put_device(&pdev->dev);
 	if (!tegra->emc) {
-		put_device(&pdev->dev);
 		pr_err("%s: cannot find EMC driver\n", __func__);
 		return NULL;
 	}
Signature · 1 line
2.51.0
author maintainer
#115 lore raw

PATCH 109/314 ACPI: APEI: GHES: Add helper for CPER CXL protocol errors checks

In reply to Sasha Levin

From: "Fabio M. De Francesco" <[email protected]>

[ Upstream commit 70205869686212eb8e4cddf02bf87fd5fd597bc2 ]

Move the CPER CXL protocol errors validity check out of cxl_cper_post_prot_err() to new cxl_cper_sec_prot_err_valid() and limit the serial number check only to CXL agents that are CXL devices (UEFI v2.10, Appendix N.2.13).

Export the new symbol for reuse by ELOG.

Stable-dep-of: b584bfbd7ec4 ("ACPI: APEI: GHES: Disable KASAN instrumentation when compile testing with clang < 18")

---
 drivers/acpi/apei/Makefile       |  1 +
 drivers/acpi/apei/ghes.c         | 18 +----------------
 drivers/acpi/apei/ghes_helpers.c | 33 ++++++++++++++++++++++++++++++++
 include/cxl/event.h              | 10 ++++++++++
 4 files changed, 45 insertions(+), 17 deletions(-)
 create mode 100644 drivers/acpi/apei/ghes_helpers.c
drivers/acpi/apei/Makefile +1 -0
index 2c474e6477e12..5db61dfb46915 100644
@@ -1,6 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0
 obj-$(CONFIG_ACPI_APEI)		+= apei.o
 obj-$(CONFIG_ACPI_APEI_GHES)	+= ghes.o
+obj-$(CONFIG_ACPI_APEI_PCIEAER)	+= ghes_helpers.o
 obj-$(CONFIG_ACPI_APEI_EINJ)	+= einj.o
 einj-y				:= einj-core.o
 einj-$(CONFIG_ACPI_APEI_EINJ_CXL) += einj-cxl.o
drivers/acpi/apei/ghes.c +1 -17
index 42872fdc36bfc..fc96a5e234f06 100644
@@ -746,24 +746,8 @@ static void cxl_cper_post_prot_err(struct cxl_cper_sec_prot_err *prot_err,
 	struct cxl_cper_prot_err_work_data wd;
 	u8 *dvsec_start, *cap_start;
 
-	if (!(prot_err->valid_bits & PROT_ERR_VALID_AGENT_ADDRESS)) {
-		pr_err_ratelimited("CXL CPER invalid agent type\n");
+	if (cxl_cper_sec_prot_err_valid(prot_err))
 		return;
-	}
-
-	if (!(prot_err->valid_bits & PROT_ERR_VALID_ERROR_LOG)) {
-		pr_err_ratelimited("CXL CPER invalid protocol error log\n");
-		return;
-	}
-
-	if (prot_err->err_len != sizeof(struct cxl_ras_capability_regs)) {
-		pr_err_ratelimited("CXL CPER invalid RAS Cap size (%u)\n",
-				   prot_err->err_len);
-		return;
-	}
-
-	if (!(prot_err->valid_bits & PROT_ERR_VALID_SERIAL_NUMBER))
-		pr_warn(FW_WARN "CXL CPER no device serial number\n");
 
 	guard(spinlock_irqsave)(&cxl_cper_prot_err_work_lock);
 
drivers/acpi/apei/ghes_helpers.c new file +33 -0
new file mode 100644
index 0000000000000..f3d162139a974
@@ -0,0 +1,33 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright(c) 2025 Intel Corporation. All rights reserved
+
+#include <linux/printk.h>
+#include <cxl/event.h>
+
+int cxl_cper_sec_prot_err_valid(struct cxl_cper_sec_prot_err *prot_err)
+{
+	if (!(prot_err->valid_bits & PROT_ERR_VALID_AGENT_ADDRESS)) {
+		pr_err_ratelimited("CXL CPER invalid agent type\n");
+		return -EINVAL;
+	}
+
+	if (!(prot_err->valid_bits & PROT_ERR_VALID_ERROR_LOG)) {
+		pr_err_ratelimited("CXL CPER invalid protocol error log\n");
+		return -EINVAL;
+	}
+
+	if (prot_err->err_len != sizeof(struct cxl_ras_capability_regs)) {
+		pr_err_ratelimited("CXL CPER invalid RAS Cap size (%u)\n",
+				   prot_err->err_len);
+		return -EINVAL;
+	}
+
+	if ((prot_err->agent_type == RCD || prot_err->agent_type == DEVICE ||
+	     prot_err->agent_type == LD || prot_err->agent_type == FMLD) &&
+	    !(prot_err->valid_bits & PROT_ERR_VALID_SERIAL_NUMBER))
+		pr_warn_ratelimited(FW_WARN
+				    "CXL CPER no device serial number\n");
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(cxl_cper_sec_prot_err_valid);
include/cxl/event.h +10 -0
index 6fd90f9cc2034..4d7d1036ea9cb 100644
@@ -320,4 +320,14 @@ static inline int cxl_cper_prot_err_kfifo_get(struct cxl_cper_prot_err_work_data
 }
 #endif
 
+#ifdef CONFIG_ACPI_APEI_PCIEAER
+int cxl_cper_sec_prot_err_valid(struct cxl_cper_sec_prot_err *prot_err);
+#else
+static inline int
+cxl_cper_sec_prot_err_valid(struct cxl_cper_sec_prot_err *prot_err)
+{
+	return -EOPNOTSUPP;
+}
+#endif
+
 #endif /* _LINUX_CXL_EVENT_H */
Signature · 1 line
2.51.0
author maintainer
#116 lore raw

PATCH 110/314 ACPI: APEI: GHES: Disable KASAN instrumentation when compile testing with clang < 18

In reply to Sasha Levin

From: Nathan Chancellor <[email protected]>

[ Upstream commit b584bfbd7ec417f257f651cc00a90c66e31dfbf1 ]

After a recent innocuous change to drivers/acpi/apei/ghes.c, building ARCH=arm64 allmodconfig with clang-17 or older (which has both CONFIG_KASAN=y and CONFIG_WERROR=y) fails with:

drivers/acpi/apei/ghes.c:902:13: error: stack frame size (2768) exceeds limit (2048) in 'ghes_do_proc' [-Werror,-Wframe-larger-than]
902 | static void ghes_do_proc(struct ghes *ghes,
| ^

A KASAN pass that removes unneeded stack instrumentation, enabled by default in clang-18 [1], drastically improves stack usage in this case.

To avoid the warning in the common allmodconfig case when it can break the build, disable KASAN for ghes.o when compile testing with clang-17 and older. Disabling KASAN outright may hide legitimate runtime issues, so live with the warning in that case; the user can either increase the frame warning limit or disable -Werror, which they should probably do when debugging with KASAN anyways.

---
 drivers/acpi/apei/Makefile | 4 ++++
 1 file changed, 4 insertions(+)
drivers/acpi/apei/Makefile +4 -0
index 5db61dfb46915..1a0b85923cd42 100644
@@ -1,6 +1,10 @@
 # SPDX-License-Identifier: GPL-2.0
 obj-$(CONFIG_ACPI_APEI)		+= apei.o
 obj-$(CONFIG_ACPI_APEI_GHES)	+= ghes.o
+# clang versions prior to 18 may blow out the stack with KASAN
+ifeq ($(CONFIG_COMPILE_TEST)_$(CONFIG_CC_IS_CLANG)_$(call clang-min-version, 180000),y_y_)
+KASAN_SANITIZE_ghes.o := n
+endif
 obj-$(CONFIG_ACPI_APEI_PCIEAER)	+= ghes_helpers.o
 obj-$(CONFIG_ACPI_APEI_EINJ)	+= einj.o
 einj-y				:= einj-core.o
Signature · 1 line
2.51.0
author maintainer
#117 lore raw

PATCH 111/314 ARM: dts: imx53-usbarmory: Replace license text comment with SPDX identifier

In reply to Sasha Levin

From: Bence Csókás <[email protected]>

[ Upstream commit faa6baa36497958dd8fd5561daa37249779446d7 ]

Replace verbatim license text with a SPDX-License-Identifier.

The comment header mis-attributes this license to be "X11", but the license text does not include the last line "Except as contained in this notice, the name of the X Consortium shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from the X Consortium.". Therefore, this license is actually equivalent to the SPDX "MIT" license (confirmed by text diffing).

Stable-dep-of: 43d67ec26b32 ("PCI: dwc: ep: Fix resizable BAR support for multi-PF configurations")

---
 arch/arm/boot/dts/nxp/imx/imx53-usbarmory.dts | 39 +------------------
 1 file changed, 1 insertion(+), 38 deletions(-)
arch/arm/boot/dts/nxp/imx/imx53-usbarmory.dts +1 -38
index acc44010d5106..3ad9db4b14425 100644
@@ -1,47 +1,10 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR MIT)
 /*
  * USB armory MkI device tree file
  * https://inversepath.com/usbarmory
  *
  * Copyright (C) 2015, Inverse Path
  * Andrej Rosano <[email protected]>
- *
- * This file is dual-licensed: you can use it either under the terms
- * of the GPL or the X11 license, at your option. Note that this dual
- * licensing only applies to this file, and not this project as a
- * whole.
- *
- *  a) This file is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License as
- *     published by the Free Software Foundation; either version 2 of the
- *     License, or (at your option) any later version.
- *
- *     This file is distributed in the hope that it will be useful,
- *     but WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *     GNU General Public License for more details.
- *
- * Or, alternatively,
- *
- *  b) Permission is hereby granted, free of charge, to any person
- *     obtaining a copy of this software and associated documentation
- *     files (the "Software"), to deal in the Software without
- *     restriction, including without limitation the rights to use,
- *     copy, modify, merge, publish, distribute, sublicense, and/or
- *     sell copies of the Software, and to permit persons to whom the
- *     Software is furnished to do so, subject to the following
- *     conditions:
- *
- *     The above copyright notice and this permission notice shall be
- *     included in all copies or substantial portions of the Software.
- *
- *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- *     OTHER DEALINGS IN THE SOFTWARE.
  */
 
 /dts-v1/;
Signature · 1 line
2.51.0
author maintainer
#118 lore raw

PATCH 112/314 PCI: Add preceding capability position support in PCI_FIND_NEXT_*_CAP macros

In reply to Sasha Levin

From: Qiang Yu <[email protected]>

[ Upstream commit a2582e05e39adf9ab82a02561cd6f70738540ae0 ]

Add support for finding the preceding capability position in PCI capability list by extending the capability finding macros with an additional parameter. This functionality is essential for modifying PCI capability list, as it provides the necessary information to update the "next" pointer of the predecessor capability when removing entries.

Modify two macros to accept a new 'prev_ptr' parameter:
- PCI_FIND_NEXT_CAP - Now accepts 'prev_ptr' parameter for standard capabilities
- PCI_FIND_NEXT_EXT_CAP - Now accepts 'prev_ptr' parameter for extended capabilities

When a capability is found, these macros:
- Store the position of the preceding capability in *prev_ptr (if prev_ptr != NULL)
- Maintain all existing functionality when prev_ptr is NULL

Update current callers to accommodate this API change by passing NULL to 'prev_ptr' argument if they do not care about the preceding capability position.

No functional changes to driver behavior result from this commit as it maintains the existing capability finding functionality while adding the infrastructure for future capability removal operations.

Stable-dep-of: 43d67ec26b32 ("PCI: dwc: ep: Fix resizable BAR support for multi-PF configurations")

---
 drivers/pci/controller/cadence/pcie-cadence.c |  4 ++--
 .../pci/controller/dwc/pcie-designware-ep.c   |  2 +-
 drivers/pci/controller/dwc/pcie-designware.c  |  6 ++---
 drivers/pci/pci.c                             |  8 +++----
 drivers/pci/pci.h                             | 23 +++++++++++++++----
 5 files changed, 29 insertions(+), 14 deletions(-)
drivers/pci/controller/cadence/pcie-cadence.c +2 -2
index bd683d0fecb22..d614452861f77 100644
@@ -13,13 +13,13 @@
 u8 cdns_pcie_find_capability(struct cdns_pcie *pcie, u8 cap)
 {
 	return PCI_FIND_NEXT_CAP(cdns_pcie_read_cfg, PCI_CAPABILITY_LIST,
-				 cap, pcie);
+				 cap, NULL, pcie);
 }
 EXPORT_SYMBOL_GPL(cdns_pcie_find_capability);
 
 u16 cdns_pcie_find_ext_capability(struct cdns_pcie *pcie, u8 cap)
 {
-	return PCI_FIND_NEXT_EXT_CAP(cdns_pcie_read_cfg, 0, cap, pcie);
+	return PCI_FIND_NEXT_EXT_CAP(cdns_pcie_read_cfg, 0, cap, NULL, pcie);
 }
 EXPORT_SYMBOL_GPL(cdns_pcie_find_ext_capability);
 
drivers/pci/controller/dwc/pcie-designware-ep.c +1 -1
index 6d3beec92b54e..7f10d764f52b0 100644
@@ -72,7 +72,7 @@ EXPORT_SYMBOL_GPL(dw_pcie_ep_reset_bar);
 static u8 dw_pcie_ep_find_capability(struct dw_pcie_ep *ep, u8 func_no, u8 cap)
 {
 	return PCI_FIND_NEXT_CAP(dw_pcie_ep_read_cfg, PCI_CAPABILITY_LIST,
-				 cap, ep, func_no);
+				 cap, NULL, ep, func_no);
 }
 
 /**
drivers/pci/controller/dwc/pcie-designware.c +3 -3
index 75fc8b767fccf..5d7a7e6f5724e 100644
@@ -226,13 +226,13 @@ void dw_pcie_version_detect(struct dw_pcie *pci)
 u8 dw_pcie_find_capability(struct dw_pcie *pci, u8 cap)
 {
 	return PCI_FIND_NEXT_CAP(dw_pcie_read_cfg, PCI_CAPABILITY_LIST, cap,
-				 pci);
+				 NULL, pci);
 }
 EXPORT_SYMBOL_GPL(dw_pcie_find_capability);
 
 u16 dw_pcie_find_ext_capability(struct dw_pcie *pci, u8 cap)
 {
-	return PCI_FIND_NEXT_EXT_CAP(dw_pcie_read_cfg, 0, cap, pci);
+	return PCI_FIND_NEXT_EXT_CAP(dw_pcie_read_cfg, 0, cap, NULL, pci);
 }
 EXPORT_SYMBOL_GPL(dw_pcie_find_ext_capability);
 
@@ -246,7 +246,7 @@ static u16 __dw_pcie_find_vsec_capability(struct dw_pcie *pci, u16 vendor_id,
 		return 0;
 
 	while ((vsec = PCI_FIND_NEXT_EXT_CAP(dw_pcie_read_cfg, vsec,
-					     PCI_EXT_CAP_ID_VNDR, pci))) {
+					     PCI_EXT_CAP_ID_VNDR, NULL, pci))) {
 		header = dw_pcie_readl_dbi(pci, vsec + PCI_VNDR_HEADER);
 		if (PCI_VNDR_HEADER_ID(header) == vsec_id)
 			return vsec;
drivers/pci/pci.c +4 -4
index d4e70570d09f2..e128696d5b761 100644
@@ -426,7 +426,7 @@ static int pci_dev_str_match(struct pci_dev *dev, const char *p,
 static u8 __pci_find_next_cap(struct pci_bus *bus, unsigned int devfn,
 			      u8 pos, int cap)
 {
-	return PCI_FIND_NEXT_CAP(pci_bus_read_config, pos, cap, bus, devfn);
+	return PCI_FIND_NEXT_CAP(pci_bus_read_config, pos, cap, NULL, bus, devfn);
 }
 
 u8 pci_find_next_capability(struct pci_dev *dev, u8 pos, int cap)
@@ -531,7 +531,7 @@ u16 pci_find_next_ext_capability(struct pci_dev *dev, u16 start, int cap)
 		return 0;
 
 	return PCI_FIND_NEXT_EXT_CAP(pci_bus_read_config, start, cap,
-				     dev->bus, dev->devfn);
+				     NULL, dev->bus, dev->devfn);
 }
 EXPORT_SYMBOL_GPL(pci_find_next_ext_capability);
 
@@ -600,7 +600,7 @@ static u8 __pci_find_next_ht_cap(struct pci_dev *dev, u8 pos, int ht_cap)
 		mask = HT_5BIT_CAP_MASK;
 
 	pos = PCI_FIND_NEXT_CAP(pci_bus_read_config, pos,
-				PCI_CAP_ID_HT, dev->bus, dev->devfn);
+				PCI_CAP_ID_HT, NULL, dev->bus, dev->devfn);
 	while (pos) {
 		rc = pci_read_config_byte(dev, pos + 3, &cap);
 		if (rc != PCIBIOS_SUCCESSFUL)
@@ -611,7 +611,7 @@ static u8 __pci_find_next_ht_cap(struct pci_dev *dev, u8 pos, int ht_cap)
 
 		pos = PCI_FIND_NEXT_CAP(pci_bus_read_config,
 					pos + PCI_CAP_LIST_NEXT,
-					PCI_CAP_ID_HT, dev->bus,
+					PCI_CAP_ID_HT, NULL, dev->bus,
 					dev->devfn);
 	}
 
drivers/pci/pci.h +19 -4
index 36cf1ffb2023c..5510c103be2d3 100644
@@ -106,17 +106,21 @@ bool pcie_cap_has_rtctl(const struct pci_dev *dev);
  * @read_cfg: Function pointer for reading PCI config space
  * @start: Starting position to begin search
  * @cap: Capability ID to find
+ * @prev_ptr: Pointer to store position of preceding capability (optional)
  * @args: Arguments to pass to read_cfg function
  *
- * Search the capability list in PCI config space to find @cap.
+ * Search the capability list in PCI config space to find @cap. If
+ * found, update *prev_ptr with the position of the preceding capability
+ * (if prev_ptr != NULL)
  * Implements TTL (time-to-live) protection against infinite loops.
  *
  * Return: Position of the capability if found, 0 otherwise.
  */
-#define PCI_FIND_NEXT_CAP(read_cfg, start, cap, args...)		\
+#define PCI_FIND_NEXT_CAP(read_cfg, start, cap, prev_ptr, args...)	\
 ({									\
 	int __ttl = PCI_FIND_CAP_TTL;					\
-	u8 __id, __found_pos = 0;					\
+	u8 __id,  __found_pos = 0;					\
+	u8 __prev_pos = (start);					\
 	u8 __pos = (start);						\
 	u16 __ent;							\
 									\
@@ -135,9 +139,12 @@ bool pcie_cap_has_rtctl(const struct pci_dev *dev);
 									\
 		if (__id == (cap)) {					\
 			__found_pos = __pos;				\
+			if (prev_ptr != NULL)				\
+				*(u8 *)prev_ptr = __prev_pos;		\
 			break;						\
 		}							\
 									\
+		__prev_pos = __pos;					\
 		__pos = FIELD_GET(PCI_CAP_LIST_NEXT_MASK, __ent);	\
 	}								\
 	__found_pos;							\
@@ -149,21 +156,26 @@ bool pcie_cap_has_rtctl(const struct pci_dev *dev);
  * @read_cfg: Function pointer for reading PCI config space
  * @start: Starting position to begin search (0 for initial search)
  * @cap: Extended capability ID to find
+ * @prev_ptr: Pointer to store position of preceding capability (optional)
  * @args: Arguments to pass to read_cfg function
  *
  * Search the extended capability list in PCI config space to find @cap.
+ * If found, update *prev_ptr with the position of the preceding capability
+ * (if prev_ptr != NULL)
  * Implements TTL protection against infinite loops using a calculated
  * maximum search count.
  *
  * Return: Position of the capability if found, 0 otherwise.
  */
-#define PCI_FIND_NEXT_EXT_CAP(read_cfg, start, cap, args...)		\
+#define PCI_FIND_NEXT_EXT_CAP(read_cfg, start, cap, prev_ptr, args...)	\
 ({									\
 	u16 __pos = (start) ?: PCI_CFG_SPACE_SIZE;			\
 	u16 __found_pos = 0;						\
+	u16 __prev_pos;							\
 	int __ttl, __ret;						\
 	u32 __header;							\
 									\
+	__prev_pos = __pos;						\
 	__ttl = (PCI_CFG_SPACE_EXP_SIZE - PCI_CFG_SPACE_SIZE) / 8;	\
 	while (__ttl-- > 0 && __pos >= PCI_CFG_SPACE_SIZE) {		\
 		__ret = read_cfg##_dword(args, __pos, &__header);	\
@@ -175,9 +187,12 @@ bool pcie_cap_has_rtctl(const struct pci_dev *dev);
 									\
 		if (PCI_EXT_CAP_ID(__header) == (cap) && __pos != start) {\
 			__found_pos = __pos;				\
+			if (prev_ptr != NULL)				\
+				*(u16 *)prev_ptr = __prev_pos;		\
 			break;						\
 		}							\
 									\
+		__prev_pos = __pos;					\
 		__pos = PCI_EXT_CAP_NEXT(__header);			\
 	}								\
 	__found_pos;							\
Signature · 1 line
2.51.0
author maintainer
#119 lore raw

PATCH 113/314 PCI: dwc: Add new APIs to remove standard and extended Capability

In reply to Sasha Levin

From: Qiang Yu <[email protected]>

[ Upstream commit 0183562f1e824c0ca6c918309a0978e9a269af3e ]

On some platforms, certain PCIe Capabilities may be present in hardware but are not fully implemented as defined in PCIe spec. These incomplete capabilities should be hidden from the PCI framework to prevent unexpected behavior.

Introduce two APIs to remove a specific PCIe Capability and Extended Capability by updating the previous capability's next offset field to skip over the unwanted capability. These APIs allow RC drivers to easily hide unsupported or partially implemented capabilities from software.

Stable-dep-of: 43d67ec26b32 ("PCI: dwc: ep: Fix resizable BAR support for multi-PF configurations")

---
 drivers/pci/controller/dwc/pcie-designware.c | 53 ++++++++++++++++++++
 drivers/pci/controller/dwc/pcie-designware.h |  2 +
 2 files changed, 55 insertions(+)
drivers/pci/controller/dwc/pcie-designware.c +53 -0
index 5d7a7e6f5724e..345365ea97c74 100644
@@ -236,6 +236,59 @@ u16 dw_pcie_find_ext_capability(struct dw_pcie *pci, u8 cap)
 }
 EXPORT_SYMBOL_GPL(dw_pcie_find_ext_capability);
 
+void dw_pcie_remove_capability(struct dw_pcie *pci, u8 cap)
+{
+	u8 cap_pos, pre_pos, next_pos;
+	u16 reg;
+
+	cap_pos = PCI_FIND_NEXT_CAP(dw_pcie_read_cfg, PCI_CAPABILITY_LIST, cap,
+				 &pre_pos, pci);
+	if (!cap_pos)
+		return;
+
+	reg = dw_pcie_readw_dbi(pci, cap_pos);
+	next_pos = (reg & 0xff00) >> 8;
+
+	dw_pcie_dbi_ro_wr_en(pci);
+	if (pre_pos == PCI_CAPABILITY_LIST)
+		dw_pcie_writeb_dbi(pci, PCI_CAPABILITY_LIST, next_pos);
+	else
+		dw_pcie_writeb_dbi(pci, pre_pos + 1, next_pos);
+	dw_pcie_dbi_ro_wr_dis(pci);
+}
+EXPORT_SYMBOL_GPL(dw_pcie_remove_capability);
+
+void dw_pcie_remove_ext_capability(struct dw_pcie *pci, u8 cap)
+{
+	int cap_pos, next_pos, pre_pos;
+	u32 pre_header, header;
+
+	cap_pos = PCI_FIND_NEXT_EXT_CAP(dw_pcie_read_cfg, 0, cap, &pre_pos, pci);
+	if (!cap_pos)
+		return;
+
+	header = dw_pcie_readl_dbi(pci, cap_pos);
+	/*
+	 * If the first cap at offset PCI_CFG_SPACE_SIZE is removed,
+	 * only set it's capid to zero as it cannot be skipped.
+	 */
+	if (cap_pos == PCI_CFG_SPACE_SIZE) {
+		dw_pcie_dbi_ro_wr_en(pci);
+		dw_pcie_writel_dbi(pci, cap_pos, header & 0xffff0000);
+		dw_pcie_dbi_ro_wr_dis(pci);
+		return;
+	}
+
+	pre_header = dw_pcie_readl_dbi(pci, pre_pos);
+	next_pos = PCI_EXT_CAP_NEXT(header);
+
+	dw_pcie_dbi_ro_wr_en(pci);
+	dw_pcie_writel_dbi(pci, pre_pos,
+			  (pre_header & 0xfffff) | (next_pos << 20));
+	dw_pcie_dbi_ro_wr_dis(pci);
+}
+EXPORT_SYMBOL_GPL(dw_pcie_remove_ext_capability);
+
 static u16 __dw_pcie_find_vsec_capability(struct dw_pcie *pci, u16 vendor_id,
 					  u16 vsec_id)
 {
drivers/pci/controller/dwc/pcie-designware.h +2 -0
index 6c04ac0196794..a59ea4078cca8 100644
@@ -557,6 +557,8 @@ void dw_pcie_version_detect(struct dw_pcie *pci);
 
 u8 dw_pcie_find_capability(struct dw_pcie *pci, u8 cap);
 u16 dw_pcie_find_ext_capability(struct dw_pcie *pci, u8 cap);
+void dw_pcie_remove_capability(struct dw_pcie *pci, u8 cap);
+void dw_pcie_remove_ext_capability(struct dw_pcie *pci, u8 cap);
 u16 dw_pcie_find_rasdes_capability(struct dw_pcie *pci);
 u16 dw_pcie_find_ptm_capability(struct dw_pcie *pci);
 
Signature · 1 line
2.51.0
author maintainer
#120 lore raw

PATCH 114/314 PCI: dwc: Remove duplicate dw_pcie_ep_hide_ext_capability() function

In reply to Sasha Levin

From: Qiang Yu <[email protected]>

[ Upstream commit 86291f774fe8524178446cb2c792939640b4970c ]

Remove dw_pcie_ep_hide_ext_capability() and replace its usage with dw_pcie_remove_ext_capability(). Both functions serve the same purpose of hiding PCIe extended capabilities, but dw_pcie_remove_ext_capability() provides a cleaner API that doesn't require the caller to specify the previous capability ID.

Stable-dep-of: 43d67ec26b32 ("PCI: dwc: ep: Fix resizable BAR support for multi-PF configurations")

---
 .../pci/controller/dwc/pcie-designware-ep.c   | 39 -------------------
 drivers/pci/controller/dwc/pcie-designware.h  |  7 ----
 drivers/pci/controller/dwc/pcie-dw-rockchip.c |  4 +-
 3 files changed, 1 insertion(+), 49 deletions(-)
drivers/pci/controller/dwc/pcie-designware-ep.c +0 -39
index 7f10d764f52b0..b6cee9eaa1165 100644
@@ -75,45 +75,6 @@ static u8 dw_pcie_ep_find_capability(struct dw_pcie_ep *ep, u8 func_no, u8 cap)
 				 cap, NULL, ep, func_no);
 }
 
-/**
- * dw_pcie_ep_hide_ext_capability - Hide a capability from the linked list
- * @pci: DWC PCI device
- * @prev_cap: Capability preceding the capability that should be hidden
- * @cap: Capability that should be hidden
- *
- * Return: 0 if success, errno otherwise.
- */
-int dw_pcie_ep_hide_ext_capability(struct dw_pcie *pci, u8 prev_cap, u8 cap)
-{
-	u16 prev_cap_offset, cap_offset;
-	u32 prev_cap_header, cap_header;
-
-	prev_cap_offset = dw_pcie_find_ext_capability(pci, prev_cap);
-	if (!prev_cap_offset)
-		return -EINVAL;
-
-	prev_cap_header = dw_pcie_readl_dbi(pci, prev_cap_offset);
-	cap_offset = PCI_EXT_CAP_NEXT(prev_cap_header);
-	cap_header = dw_pcie_readl_dbi(pci, cap_offset);
-
-	/* cap must immediately follow prev_cap. */
-	if (PCI_EXT_CAP_ID(cap_header) != cap)
-		return -EINVAL;
-
-	/* Clear next ptr. */
-	prev_cap_header &= ~GENMASK(31, 20);
-
-	/* Set next ptr to next ptr of cap. */
-	prev_cap_header |= cap_header & GENMASK(31, 20);
-
-	dw_pcie_dbi_ro_wr_en(pci);
-	dw_pcie_writel_dbi(pci, prev_cap_offset, prev_cap_header);
-	dw_pcie_dbi_ro_wr_dis(pci);
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(dw_pcie_ep_hide_ext_capability);
-
 static int dw_pcie_ep_write_header(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
 				   struct pci_epf_header *hdr)
 {
drivers/pci/controller/dwc/pcie-designware.h +0 -7
index a59ea4078cca8..d32ee1fa3cf85 100644
@@ -888,7 +888,6 @@ int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no,
 int dw_pcie_ep_raise_msix_irq_doorbell(struct dw_pcie_ep *ep, u8 func_no,
 				       u16 interrupt_num);
 void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar);
-int dw_pcie_ep_hide_ext_capability(struct dw_pcie *pci, u8 prev_cap, u8 cap);
 struct dw_pcie_ep_func *
 dw_pcie_ep_get_func_from_ep(struct dw_pcie_ep *ep, u8 func_no);
 #else
@@ -946,12 +945,6 @@ static inline void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar)
 {
 }
 
-static inline int dw_pcie_ep_hide_ext_capability(struct dw_pcie *pci,
-						 u8 prev_cap, u8 cap)
-{
-	return 0;
-}
-
 static inline struct dw_pcie_ep_func *
 dw_pcie_ep_get_func_from_ep(struct dw_pcie_ep *ep, u8 func_no)
 {
drivers/pci/controller/dwc/pcie-dw-rockchip.c +1 -3
index b5442ee2920e5..c2c36290be061 100644
@@ -356,9 +356,7 @@ static void rockchip_pcie_ep_hide_broken_ats_cap_rk3588(struct dw_pcie_ep *ep)
 	if (!of_device_is_compatible(dev->of_node, "rockchip,rk3588-pcie-ep"))
 		return;
 
-	if (dw_pcie_ep_hide_ext_capability(pci, PCI_EXT_CAP_ID_SECPCI,
-					   PCI_EXT_CAP_ID_ATS))
-		dev_err(dev, "failed to hide ATS capability\n");
+	dw_pcie_remove_ext_capability(pci, PCI_EXT_CAP_ID_ATS);
 }
 
 static void rockchip_pcie_ep_init(struct dw_pcie_ep *ep)
Signature · 1 line
2.51.0
author maintainer
#121 lore raw

PATCH 115/314 PCI: dwc: ep: Fix resizable BAR support for multi-PF configurations

In reply to Sasha Levin

From: Aksh Garg <[email protected]>

[ Upstream commit 43d67ec26b329f8aea34ba9dff23d69b84a8e564 ]

The resizable BAR support added by the commit 3a3d4cabe681 ("PCI: dwc: ep:
Allow EPF drivers to configure the size of Resizable BARs") incorrectly configures the resizable BARs only for the first Physical Function (PF0) in EP mode.

The resizable BAR configuration functions use generic dw_pcie_*_dbi() operations instead of physical function specific dw_pcie_ep_*_dbi() operations. This causes resizable BAR configuration to always target PF0 regardless of the requested function number.

Additionally, dw_pcie_ep_init_non_sticky_registers() only initializes resizable BAR registers for PF0, leaving other PFs unconfigured during the execution of this function.

Fix this by using physical function specific configuration space access operations throughout the resizable BAR code path and initializing registers for all the physical functions that support resizable BARs.

Fixes 3a3d4cabe681 ("PCI: dwc: ep: Allow EPF drivers to configure the size of Resizable BARs")
[mani: added stable tag]
---
 .../pci/controller/dwc/pcie-designware-ep.c   | 48 ++++++++++++-------
 1 file changed, 32 insertions(+), 16 deletions(-)
drivers/pci/controller/dwc/pcie-designware-ep.c +32 -16
index b6cee9eaa1165..e2e18beb2951d 100644
@@ -75,6 +75,13 @@ static u8 dw_pcie_ep_find_capability(struct dw_pcie_ep *ep, u8 func_no, u8 cap)
 				 cap, NULL, ep, func_no);
 }
 
+static u16 dw_pcie_ep_find_ext_capability(struct dw_pcie_ep *ep,
+					  u8 func_no, u8 cap)
+{
+	return PCI_FIND_NEXT_EXT_CAP(dw_pcie_ep_read_cfg, 0,
+				     cap, NULL, ep, func_no);
+}
+
 static int dw_pcie_ep_write_header(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
 				   struct pci_epf_header *hdr)
 {
@@ -178,22 +185,22 @@ static void dw_pcie_ep_clear_bar(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
 	ep->bar_to_atu[bar] = 0;
 }
 
-static unsigned int dw_pcie_ep_get_rebar_offset(struct dw_pcie *pci,
+static unsigned int dw_pcie_ep_get_rebar_offset(struct dw_pcie_ep *ep, u8 func_no,
 						enum pci_barno bar)
 {
 	u32 reg, bar_index;
 	unsigned int offset, nbars;
 	int i;
 
-	offset = dw_pcie_find_ext_capability(pci, PCI_EXT_CAP_ID_REBAR);
+	offset = dw_pcie_ep_find_ext_capability(ep, func_no, PCI_EXT_CAP_ID_REBAR);
 	if (!offset)
 		return offset;
 
-	reg = dw_pcie_readl_dbi(pci, offset + PCI_REBAR_CTRL);
+	reg = dw_pcie_ep_readl_dbi(ep, func_no, offset + PCI_REBAR_CTRL);
 	nbars = FIELD_GET(PCI_REBAR_CTRL_NBAR_MASK, reg);
 
 	for (i = 0; i < nbars; i++, offset += PCI_REBAR_CTRL) {
-		reg = dw_pcie_readl_dbi(pci, offset + PCI_REBAR_CTRL);
+		reg = dw_pcie_ep_readl_dbi(ep, func_no, offset + PCI_REBAR_CTRL);
 		bar_index = FIELD_GET(PCI_REBAR_CTRL_BAR_IDX, reg);
 		if (bar_index == bar)
 			return offset;
@@ -214,7 +221,7 @@ static int dw_pcie_ep_set_bar_resizable(struct dw_pcie_ep *ep, u8 func_no,
 	u32 rebar_cap, rebar_ctrl;
 	int ret;
 
-	rebar_offset = dw_pcie_ep_get_rebar_offset(pci, bar);
+	rebar_offset = dw_pcie_ep_get_rebar_offset(ep, func_no, bar);
 	if (!rebar_offset)
 		return -EINVAL;
 
@@ -244,16 +251,16 @@ static int dw_pcie_ep_set_bar_resizable(struct dw_pcie_ep *ep, u8 func_no,
 	 * 1 MB to 128 TB. Bits 31:16 in PCI_REBAR_CTRL define "supported sizes"
 	 * bits for sizes 256 TB to 8 EB. Disallow sizes 256 TB to 8 EB.
 	 */
-	rebar_ctrl = dw_pcie_readl_dbi(pci, rebar_offset + PCI_REBAR_CTRL);
+	rebar_ctrl = dw_pcie_ep_readl_dbi(ep, func_no, rebar_offset + PCI_REBAR_CTRL);
 	rebar_ctrl &= ~GENMASK(31, 16);
-	dw_pcie_writel_dbi(pci, rebar_offset + PCI_REBAR_CTRL, rebar_ctrl);
+	dw_pcie_ep_writel_dbi(ep, func_no, rebar_offset + PCI_REBAR_CTRL, rebar_ctrl);
 
 	/*
 	 * The "selected size" (bits 13:8) in PCI_REBAR_CTRL are automatically
 	 * updated when writing PCI_REBAR_CAP, see "Figure 3-26 Resizable BAR
 	 * Example for 32-bit Memory BAR0" in DWC EP databook 5.96a.
 	 */
-	dw_pcie_writel_dbi(pci, rebar_offset + PCI_REBAR_CAP, rebar_cap);
+	dw_pcie_ep_writel_dbi(ep, func_no, rebar_offset + PCI_REBAR_CAP, rebar_cap);
 
 	dw_pcie_dbi_ro_wr_dis(pci);
 
@@ -799,20 +806,17 @@ void dw_pcie_ep_deinit(struct dw_pcie_ep *ep)
 }
 EXPORT_SYMBOL_GPL(dw_pcie_ep_deinit);
 
-static void dw_pcie_ep_init_non_sticky_registers(struct dw_pcie *pci)
+static void dw_pcie_ep_init_rebar_registers(struct dw_pcie_ep *ep, u8 func_no)
 {
-	struct dw_pcie_ep *ep = &pci->ep;
 	unsigned int offset;
 	unsigned int nbars;
 	enum pci_barno bar;
 	u32 reg, i, val;
 
-	offset = dw_pcie_find_ext_capability(pci, PCI_EXT_CAP_ID_REBAR);
-
-	dw_pcie_dbi_ro_wr_en(pci);
+	offset = dw_pcie_ep_find_ext_capability(ep, func_no, PCI_EXT_CAP_ID_REBAR);
 
 	if (offset) {
-		reg = dw_pcie_readl_dbi(pci, offset + PCI_REBAR_CTRL);
+		reg = dw_pcie_ep_readl_dbi(ep, func_no, offset + PCI_REBAR_CTRL);
 		nbars = FIELD_GET(PCI_REBAR_CTRL_NBAR_MASK, reg);
 
 		/*
@@ -833,16 +837,28 @@ static void dw_pcie_ep_init_non_sticky_registers(struct dw_pcie *pci)
 			 * the controller when RESBAR_CAP_REG is written, which
 			 * is why RESBAR_CAP_REG is written here.
 			 */
-			val = dw_pcie_readl_dbi(pci, offset + PCI_REBAR_CTRL);
+			val = dw_pcie_ep_readl_dbi(ep, func_no, offset + PCI_REBAR_CTRL);
 			bar = FIELD_GET(PCI_REBAR_CTRL_BAR_IDX, val);
 			if (ep->epf_bar[bar])
 				pci_epc_bar_size_to_rebar_cap(ep->epf_bar[bar]->size, &val);
 			else
 				val = BIT(4);
 
-			dw_pcie_writel_dbi(pci, offset + PCI_REBAR_CAP, val);
+			dw_pcie_ep_writel_dbi(ep, func_no, offset + PCI_REBAR_CAP, val);
 		}
 	}
+}
+
+static void dw_pcie_ep_init_non_sticky_registers(struct dw_pcie *pci)
+{
+	struct dw_pcie_ep *ep = &pci->ep;
+	u8 funcs = ep->epc->max_functions;
+	u8 func_no;
+
+	dw_pcie_dbi_ro_wr_en(pci);
+
+	for (func_no = 0; func_no < funcs; func_no++)
+		dw_pcie_ep_init_rebar_registers(ep, func_no);
 
 	dw_pcie_setup(pci);
 	dw_pcie_dbi_ro_wr_dis(pci);
Signature · 1 line
2.51.0
author maintainer
#122 lore raw

PATCH 116/314 KVM: x86: Add x2APIC "features" to control EOI broadcast suppression

In reply to Sasha Levin

From: Khushit Shah <[email protected]>

[ Upstream commit 6517dfbcc918f970a928d9dc17586904bac06893 ]

Add two flags for KVM_CAP_X2APIC_API to allow userspace to control support for Suppress EOI Broadcasts when using a split IRQCHIP (I/O APIC emulated by userspace), which KVM completely mishandles. When x2APIC support was first added, KVM incorrectly advertised and "enabled" Suppress EOI Broadcast, without fully supporting the I/O APIC side of the equation, i.e. without adding directed EOI to KVM's in-kernel I/O APIC.

That flaw was carried over to split IRQCHIP support, i.e. KVM advertised support for Suppress EOI Broadcasts irrespective of whether or not the userspace I/O APIC implementation supported directed EOIs. Even worse, KVM didn't actually suppress EOI broadcasts, i.e. userspace VMMs without support for directed EOI came to rely on the "spurious" broadcasts.

KVM "fixed" the in-kernel I/O APIC implementation by completely disabling support for Suppress EOI Broadcasts in commit 0bcc3fb95b97 ("KVM: lapic:
stop advertising DIRECTED_EOI when in-kernel IOAPIC is in use"), but didn't do anything to remedy userspace I/O APIC implementations.

KVM's bogus handling of Suppress EOI Broadcast is problematic when the guest relies on interrupts being masked in the I/O APIC until well after the initial local APIC EOI. E.g. Windows with Credential Guard enabled handles interrupts in the following order:
1. Interrupt for L2 arrives.
2. L1 APIC EOIs the interrupt.
3. L1 resumes L2 and injects the interrupt.
4. L2 EOIs after servicing.
5. L1 performs the I/O APIC EOI.

Because KVM EOIs the I/O APIC at step #2, the guest can get an interrupt storm, e.g. if the IRQ line is still asserted and userspace reacts to the EOI by re-injecting the IRQ, because the guest doesn't de-assert the line until step #4, and doesn't expect the interrupt to be re-enabled until step #5.

Unfortunately, simply "fixing" the bug isn't an option, as KVM has no way of knowing if the userspace I/O APIC supports directed EOIs, i.e. suppressing EOI broadcasts would result in interrupts being stuck masked in the userspace I/O APIC due to step #5 being ignored by userspace. And fully disabling support for Suppress EOI Broadcast is also undesirable, as picking up the fix would require a guest reboot, *and* more importantly would change the virtual CPU model exposed to the guest without any buy-in from userspace.

Add KVM_X2APIC_ENABLE_SUPPRESS_EOI_BROADCAST and KVM_X2APIC_DISABLE_SUPPRESS_EOI_BROADCAST flags to allow userspace to explicitly enable or disable support for Suppress EOI Broadcasts. This gives userspace control over the virtual CPU model exposed to the guest, as KVM should never have enabled support for Suppress EOI Broadcast without userspace opt-in. Not setting either flag will result in legacy quirky behavior for backward compatibility.

Disallow fully enabling SUPPRESS_EOI_BROADCAST when using an in-kernel I/O APIC, as KVM's history/support is just as tragic. E.g. it's not clear that commit c806a6ad35bf ("KVM: x86: call irq notifiers with directed EOI") was entirely correct, i.e. it may have simply papered over the lack of Directed EOI emulation in the I/O APIC.

Note, Suppress EOI Broadcasts is defined only in Intel's SDM, not in AMD's APM. But the bit is writable on some AMD CPUs, e.g. Turin, and KVM's ABI is to support Directed EOI (KVM's name) irrespective of guest CPU vendor.

Fixes 7543a635aa09 ("KVM: x86: Add KVM exit for IOAPIC EOIs")
[sean: clean up minor formatting goofs and fix a comment typo]
---
 Documentation/virt/kvm/api.rst  | 28 +++++++++++-
 arch/x86/include/asm/kvm_host.h |  7 +++
 arch/x86/include/uapi/asm/kvm.h |  6 ++-
 arch/x86/kvm/ioapic.c           |  2 +-
 arch/x86/kvm/lapic.c            | 76 +++++++++++++++++++++++++++++----
 arch/x86/kvm/lapic.h            |  2 +
 arch/x86/kvm/x86.c              | 21 ++++++++-
 7 files changed, 127 insertions(+), 15 deletions(-)
Documentation/virt/kvm/api.rst +26 -2
index 57061fa29e6a0..ae8b02eb776a5 100644
@@ -7800,8 +7800,10 @@ Will return -EBUSY if a VCPU has already been created.
 
 Valid feature flags in args[0] are::
 
-  #define KVM_X2APIC_API_USE_32BIT_IDS            (1ULL << 0)
-  #define KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK  (1ULL << 1)
+  #define KVM_X2APIC_API_USE_32BIT_IDS                          (1ULL << 0)
+  #define KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK                (1ULL << 1)
+  #define KVM_X2APIC_ENABLE_SUPPRESS_EOI_BROADCAST              (1ULL << 2)
+  #define KVM_X2APIC_DISABLE_SUPPRESS_EOI_BROADCAST             (1ULL << 3)
 
 Enabling KVM_X2APIC_API_USE_32BIT_IDS changes the behavior of
 KVM_SET_GSI_ROUTING, KVM_SIGNAL_MSI, KVM_SET_LAPIC, and KVM_GET_LAPIC,
@@ -7814,6 +7816,28 @@ as a broadcast even in x2APIC mode in order to support physical x2APIC
 without interrupt remapping.  This is undesirable in logical mode,
 where 0xff represents CPUs 0-7 in cluster 0.
 
+Setting KVM_X2APIC_ENABLE_SUPPRESS_EOI_BROADCAST instructs KVM to enable
+Suppress EOI Broadcasts.  KVM will advertise support for Suppress EOI
+Broadcast to the guest and suppress LAPIC EOI broadcasts when the guest
+sets the Suppress EOI Broadcast bit in the SPIV register.  This flag is
+supported only when using a split IRQCHIP.
+
+Setting KVM_X2APIC_DISABLE_SUPPRESS_EOI_BROADCAST disables support for
+Suppress EOI Broadcasts entirely, i.e. instructs KVM to NOT advertise
+support to the guest.
+
+Modern VMMs should either enable KVM_X2APIC_ENABLE_SUPPRESS_EOI_BROADCAST
+or KVM_X2APIC_DISABLE_SUPPRESS_EOI_BROADCAST.  If not, legacy quirky
+behavior will be used by KVM: in split IRQCHIP mode, KVM will advertise
+support for Suppress EOI Broadcasts but not actually suppress EOI
+broadcasts; for in-kernel IRQCHIP mode, KVM will not advertise support for
+Suppress EOI Broadcasts.
+
+Setting both KVM_X2APIC_ENABLE_SUPPRESS_EOI_BROADCAST and
+KVM_X2APIC_DISABLE_SUPPRESS_EOI_BROADCAST will fail with an EINVAL error,
+as will setting KVM_X2APIC_ENABLE_SUPPRESS_EOI_BROADCAST without a split
+IRCHIP.
+
 7.8 KVM_CAP_S390_USER_INSTR0
 ----------------------------
 
arch/x86/include/asm/kvm_host.h +7 -0
index b74ae7183f3ae..0f2f9f1552a4f 100644
@@ -1229,6 +1229,12 @@ enum kvm_irqchip_mode {
 	KVM_IRQCHIP_SPLIT,        /* created with KVM_CAP_SPLIT_IRQCHIP */
 };
 
+enum kvm_suppress_eoi_broadcast_mode {
+	KVM_SUPPRESS_EOI_BROADCAST_QUIRKED, /* Legacy behavior */
+	KVM_SUPPRESS_EOI_BROADCAST_ENABLED, /* Enable Suppress EOI broadcast */
+	KVM_SUPPRESS_EOI_BROADCAST_DISABLED /* Disable Suppress EOI broadcast */
+};
+
 struct kvm_x86_msr_filter {
 	u8 count;
 	bool default_allow:1;
@@ -1480,6 +1486,7 @@ struct kvm_arch {
 
 	bool x2apic_format;
 	bool x2apic_broadcast_quirk_disabled;
+	enum kvm_suppress_eoi_broadcast_mode suppress_eoi_broadcast_mode;
 
 	bool has_mapped_host_mmio;
 	bool guest_can_read_msr_platform_info;
arch/x86/include/uapi/asm/kvm.h +4 -2
index d420c9c066d48..1584926cd1f4f 100644
@@ -913,8 +913,10 @@ struct kvm_sev_snp_launch_finish {
 	__u64 pad1[4];
 };
 
-#define KVM_X2APIC_API_USE_32BIT_IDS            (1ULL << 0)
-#define KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK  (1ULL << 1)
+#define KVM_X2APIC_API_USE_32BIT_IDS			_BITULL(0)
+#define KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK		_BITULL(1)
+#define KVM_X2APIC_ENABLE_SUPPRESS_EOI_BROADCAST	_BITULL(2)
+#define KVM_X2APIC_DISABLE_SUPPRESS_EOI_BROADCAST	_BITULL(3)
 
 struct kvm_hyperv_eventfd {
 	__u32 conn_id;
arch/x86/kvm/ioapic.c +1 -1
index 2c2783296aedb..a26fa4222f292 100644
@@ -561,7 +561,7 @@ static void kvm_ioapic_update_eoi_one(struct kvm_vcpu *vcpu,
 	spin_lock(&ioapic->lock);
 
 	if (trigger_mode != IOAPIC_LEVEL_TRIG ||
-	    kvm_lapic_get_reg(apic, APIC_SPIV) & APIC_SPIV_DIRECTED_EOI)
+	    kvm_lapic_suppress_eoi_broadcast(apic))
 		return;
 
 	ASSERT(ent->fields.trig_mode == IOAPIC_LEVEL_TRIG);
arch/x86/kvm/lapic.c +68 -8

95 lines not on this page · raw message

arch/x86/kvm/lapic.h +2 -0
index 282b9b7da98cd..e5f5a222eced0 100644
@@ -231,6 +231,8 @@ static inline int kvm_lapic_latched_init(struct kvm_vcpu *vcpu)
 
 bool kvm_apic_pending_eoi(struct kvm_vcpu *vcpu, int vector);
 
+bool kvm_lapic_suppress_eoi_broadcast(struct kvm_lapic *apic);
+
 void kvm_wait_lapic_expire(struct kvm_vcpu *vcpu);
 
 void kvm_bitmap_or_dest_vcpus(struct kvm *kvm, struct kvm_lapic_irq *irq,
arch/x86/kvm/x86.c +19 -2
index 2ab445c0126b3..d15bd078a2d98 100644
@@ -121,8 +121,10 @@ static u64 __read_mostly efer_reserved_bits = ~((u64)EFER_SCE);
 
 #define KVM_CAP_PMU_VALID_MASK KVM_PMU_CAP_DISABLE
 
-#define KVM_X2APIC_API_VALID_FLAGS (KVM_X2APIC_API_USE_32BIT_IDS | \
-                                    KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK)
+#define KVM_X2APIC_API_VALID_FLAGS (KVM_X2APIC_API_USE_32BIT_IDS		| \
+				    KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK	| \
+				    KVM_X2APIC_ENABLE_SUPPRESS_EOI_BROADCAST	| \
+				    KVM_X2APIC_DISABLE_SUPPRESS_EOI_BROADCAST)
 
 static void update_cr8_intercept(struct kvm_vcpu *vcpu);
 static void process_nmi(struct kvm_vcpu *vcpu);
@@ -4966,6 +4968,8 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
 		break;
 	case KVM_CAP_X2APIC_API:
 		r = KVM_X2APIC_API_VALID_FLAGS;
+		if (kvm && !irqchip_split(kvm))
+			r &= ~KVM_X2APIC_ENABLE_SUPPRESS_EOI_BROADCAST;
 		break;
 	case KVM_CAP_NESTED_STATE:
 		r = kvm_x86_ops.nested_ops->get_state ?
@@ -6783,11 +6787,24 @@ int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
 		if (cap->args[0] & ~KVM_X2APIC_API_VALID_FLAGS)
 			break;
 
+		if ((cap->args[0] & KVM_X2APIC_ENABLE_SUPPRESS_EOI_BROADCAST) &&
+		    (cap->args[0] & KVM_X2APIC_DISABLE_SUPPRESS_EOI_BROADCAST))
+			break;
+
+		if ((cap->args[0] & KVM_X2APIC_ENABLE_SUPPRESS_EOI_BROADCAST) &&
+		    !irqchip_split(kvm))
+			break;
+
 		if (cap->args[0] & KVM_X2APIC_API_USE_32BIT_IDS)
 			kvm->arch.x2apic_format = true;
 		if (cap->args[0] & KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK)
 			kvm->arch.x2apic_broadcast_quirk_disabled = true;
 
+		if (cap->args[0] & KVM_X2APIC_ENABLE_SUPPRESS_EOI_BROADCAST)
+			kvm->arch.suppress_eoi_broadcast_mode = KVM_SUPPRESS_EOI_BROADCAST_ENABLED;
+		if (cap->args[0] & KVM_X2APIC_DISABLE_SUPPRESS_EOI_BROADCAST)
+			kvm->arch.suppress_eoi_broadcast_mode = KVM_SUPPRESS_EOI_BROADCAST_DISABLED;
+
 		r = 0;
 		break;
 	case KVM_CAP_X86_DISABLE_EXITS:
Signature · 1 line
2.51.0
author maintainer
#123 lore raw

PATCH 117/314 btrfs: define the AUTO_KFREE/AUTO_KVFREE helper macros

In reply to Sasha Levin

From: Miquel Sabaté Solà <[email protected]>

[ Upstream commit d00cbce0a7d5de5fc31bf60abd59b44d36806b6e ]

These are two simple macros which ensure that a pointer is initialized to NULL and with the proper cleanup attribute for it.

Stable-dep-of: 52ee9965d09b ("btrfs: zoned: fixup last alloc pointer after extent removal for RAID0/10")

---
 fs/btrfs/misc.h | 7 +++++++
 1 file changed, 7 insertions(+)
fs/btrfs/misc.h +7 -0
index 60f9b000d644b..a82032c66ccd3 100644
@@ -13,6 +13,13 @@
 #include <linux/rbtree.h>
 #include <linux/bio.h>
 
+/*
+ * Convenience macros to define a pointer with the __free(kfree) and
+ * __free(kvfree) cleanup attributes and initialized to NULL.
+ */
+#define AUTO_KFREE(name)       *name __free(kfree) = NULL
+#define AUTO_KVFREE(name)      *name __free(kvfree) = NULL
+
 /*
  * Enumerate bits using enum autoincrement. Define the @name as the n-th bit.
  */
Signature · 1 line
2.51.0