6.18.17-rc1 review
Subsystems (11)
Sasha Levin
maintainercover 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
Sasha Levin
maintainerPATCH 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
@@ -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
Sasha Levin
maintainerPATCH 2/314 drm/vmwgfx: Fix invalid kref_put callback in vmw_bo_dirty_release
In reply to Sasha LevinFrom: 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.
--- 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
@@ -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
Sasha Levin
maintainerPATCH 3/314 drm/vmwgfx: Return the correct value in vmw_translate_ptr functions
In reply to Sasha LevinFrom: 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.
--- drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c +2 -2
@@ -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
Sasha Levin
maintainerPATCH 4/314 debugobject: Make it work with deferred page initialization - again
In reply to Sasha LevinFrom: 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
@@ -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
@@ -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
Sasha Levin
maintainerPATCH 5/314 drm/logicvc: Fix device node reference leak in logicvc_drm_config_parse()
In reply to Sasha LevinFrom: 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.
--- drivers/gpu/drm/logicvc/logicvc_drm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/gpu/drm/logicvc/logicvc_drm.c +2 -2
@@ -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
Sasha Levin
maintainerPATCH 6/314 KVM: arm64: Hide S1POE from guests when not supported by the host
In reply to Sasha LevinFrom: 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).
--- arch/arm64/kvm/sys_regs.c | 3 +++ 1 file changed, 3 insertions(+)
arch/arm64/kvm/sys_regs.c +3 -0
@@ -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
Sasha Levin
maintainerPATCH 7/314 KVM: arm64: Fix ID register initialization for non-protected pKVM guests
In reply to Sasha LevinFrom: 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.
--- arch/arm64/kvm/hyp/nvhe/pkvm.c | 35 ++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-)
arch/arm64/kvm/hyp/nvhe/pkvm.c +33 -2
@@ -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 *hreturn 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
Sasha Levin
maintainerPATCH 8/314 drm/fourcc: fix plane order for 10/12/16-bit YCbCr formats
In reply to Sasha LevinFrom: Simon Ser <[email protected]>
[ Upstream commit e9e0b48cd15b46dcb2bbc165f6b0fee698b855d6 ]
The short comments had the correct order, but the long comments had the planes reversed.
--- include/uapi/drm/drm_fourcc.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)
include/uapi/drm/drm_fourcc.h +6 -6
@@ -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
Sasha Levin
maintainerPATCH 9/314 drm/tiny: sharp-memory: fix pointer error dereference
In reply to Sasha LevinFrom: 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
@@ -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
Sasha Levin
maintainerPATCH 10/314 irqchip/sifive-plic: Fix frozen interrupt due to affinity setting
In reply to Sasha LevinFrom: 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().
--- drivers/irqchip/irq-sifive-plic.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
drivers/irqchip/irq-sifive-plic.c +6 -1
@@ -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
Sasha Levin
maintainerPATCH 11/314 scsi: lpfc: Properly set WC for DPP mapping
In reply to Sasha LevinFrom: 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
@@ -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
@@ -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
@@ -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
Sasha Levin
maintainerPATCH 12/314 scsi: pm8001: Fix use-after-free in pm8001_queue_command()
In reply to Sasha LevinFrom: 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
@@ -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
Sasha Levin
maintainerPATCH 13/314 drm/imx: parallel-display: check return value of devm_drm_bridge_add() in imx_pd_probe()
In reply to Sasha LevinFrom: 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.
--- 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
@@ -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
Sasha Levin
maintainerPATCH 14/314 ALSA: scarlett2: Fix DSP filter control array handling
In reply to Sasha LevinFrom: "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
@@ -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
Sasha Levin
maintainerPATCH 15/314 ALSA: usb-audio: Remove VALIDATE_RATES quirk for Focusrite devices
In reply to Sasha LevinFrom: "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.
--- sound/usb/quirks.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
sound/usb/quirks.c +1 -1
@@ -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
Sasha Levin
maintainerPATCH 16/314 ALSA: usb-audio: Add QUIRK_FLAG_SKIP_IFACE_SETUP
In reply to Sasha LevinFrom: "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.
--- 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
@@ -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
@@ -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
@@ -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
Sasha Levin
maintainerPATCH 17/314 x86/fred: Correct speculative safety in fred_extint()
In reply to Sasha LevinFrom: 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.
--- arch/x86/entry/entry_fred.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
arch/x86/entry/entry_fred.c +2 -3
@@ -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
Sasha Levin
maintainerPATCH 18/314 x86/cfi: Fix CFI rewrite for odd alignments
In reply to Sasha LevinFrom: 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.
--- 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
@@ -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
@@ -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
@@ -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
@@ -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
Sasha Levin
maintainerPATCH 19/314 sched/fair: Rename cfs_rq::avg_load to cfs_rq::sum_weight
In reply to Sasha LevinFrom: 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
@@ -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
@@ -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
Sasha Levin
maintainerPATCH 20/314 sched/fair: Rename cfs_rq::avg_vruntime to ::sum_w_vruntime, and helper functions
In reply to Sasha LevinFrom: 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
@@ -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
@@ -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
Sasha Levin
maintainerPATCH 21/314 sched/fair: Introduce and use the vruntime_cmp() and vruntime_op() wrappers for wrapped-signed aritmetics
In reply to Sasha LevinFrom: 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
@@ -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_entistatic 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
Sasha Levin
maintainerPATCH 22/314 sched/fair: Fix zero_vruntime tracking
In reply to Sasha LevinFrom: 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
@@ -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
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.
Sasha Levin
maintainerRe: [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
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.
--- kernel/sched/fair.c | 84 ++++++++++++++++++++++++++++++--------------- 1 file changed, 57 insertions(+), 27 deletions(-)
kernel/sched/fair.c +57 -27
@@ -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
Greg KH
maintainerRe: [PATCH 6.18 022/314] sched/fair: Fix zero_vruntime tracking
In reply to Eric HagbergQuoted 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
Sasha Levin
maintainerPATCH 23/314 sched/fair: Only set slice protection at pick time
In reply to Sasha LevinFrom: 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
@@ -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
Sasha Levin
maintainerPATCH 24/314 sched/eevdf: Update se->vprot in reweight_entity()
In reply to Sasha LevinFrom: 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
@@ -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
Sasha Levin
maintainerPATCH 25/314 sched/fair: Fix lag clamp
In reply to Sasha LevinFrom: 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
@@ -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
@@ -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
Sasha Levin
maintainerPATCH 26/314 rseq: Clarify rseq registration rseq_size bound check comment
In reply to Sasha LevinFrom: 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
@@ -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
Sasha Levin
maintainerPATCH 27/314 perf/core: Fix invalid wait context in ctx_sched_in()
In reply to Sasha LevinFrom: 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
@@ -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
Sasha Levin
maintainerPATCH 28/314 accel/amdxdna: Remove buffer size check when creating command BO
In reply to Sasha LevinFrom: 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.
--- drivers/accel/amdxdna/amdxdna_gem.c | 38 ++++++++++++++--------------- 1 file changed, 19 insertions(+), 19 deletions(-)
drivers/accel/amdxdna/amdxdna_gem.c +19 -19
@@ -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
Sasha Levin
maintainerPATCH 29/314 accel/amdxdna: Prevent ubuf size overflow
In reply to Sasha LevinFrom: 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.
--- drivers/accel/amdxdna/amdxdna_ubuf.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
drivers/accel/amdxdna/amdxdna_ubuf.c +5 -1
@@ -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
Sasha Levin
maintainerPATCH 30/314 accel/amdxdna: Validate command buffer payload count
In reply to Sasha LevinFrom: 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
@@ -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
Sasha Levin
maintainerPATCH 31/314 drm/xe/wa: Steer RMW of MCR registers while building default LRC
In reply to Sasha LevinFrom: 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.
--- 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
@@ -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
Sasha Levin
maintainerPATCH 32/314 cgroup/cpuset: Fix incorrect use of cpuset_update_tasks_cpumask() in update_cpumasks_hier()
In reply to Sasha LevinFrom: 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.
--- kernel/cgroup/cpuset.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/cgroup/cpuset.c +1 -1
@@ -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
Sasha Levin
maintainerPATCH 33/314 cxl: Move devm_cxl_add_nvdimm_bridge() to cxl_pmem.ko
In reply to Sasha LevinFrom: 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
@@ -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
@@ -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
@@ -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
Sasha Levin
maintainerPATCH 34/314 cxl: Fix race of nvdimm_bus object when creating nvdimm objects
In reply to Sasha LevinFrom: 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
@@ -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
@@ -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
@@ -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
Sasha Levin
maintainerPATCH 35/314 scsi: ufs: core: Move link recovery for hibern8 exit failure to wl_resume
In reply to Sasha LevinFrom: 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.
--- drivers/ufs/core/ufshcd.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-)
drivers/ufs/core/ufshcd.c +9 -9
@@ -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
Sasha Levin
maintainerPATCH 36/314 regulator: bq257xx: Fix device node reference leak in bq257xx_reg_dt_parse_gpio()
In reply to Sasha LevinFrom: 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.
--- drivers/regulator/bq257xx-regulator.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/regulator/bq257xx-regulator.c +1 -2
@@ -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
Sasha Levin
maintainerPATCH 37/314 zloop: advertise a volatile write cache
In reply to Sasha LevinFrom: 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.
--- drivers/block/zloop.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-)
drivers/block/zloop.c +18 -6
@@ -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
Sasha Levin
maintainerPATCH 38/314 zloop: check for spurious options passed to remove
In reply to Sasha LevinFrom: 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.
--- drivers/block/zloop.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
drivers/block/zloop.c +6 -1
@@ -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
Sasha Levin
maintainerPATCH 39/314 drm/client: Do not destroy NULL modes
In reply to Sasha LevinFrom: 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.
--- drivers/gpu/drm/drm_client_modeset.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/gpu/drm/drm_client_modeset.c +2 -1
@@ -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
Sasha Levin
maintainerPATCH 40/314 ALSA: usb-audio: Cap the packet size pre-calculations
In reply to Sasha LevinFrom: 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
@@ -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
Sasha Levin
maintainerPATCH 41/314 ALSA: usb-audio: Use inclusive terms
In reply to Sasha LevinFrom: 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.
--- sound/usb/endpoint.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
sound/usb/endpoint.c +3 -3
@@ -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
Sasha Levin
maintainerPATCH 42/314 perf: Fix __perf_event_overflow() vs perf_remove_from_context() race
In reply to Sasha LevinFrom: 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
@@ -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
Sasha Levin
maintainerPATCH 43/314 s390/idle: Fix cpu idle exit cpu time accounting
In reply to Sasha LevinFrom: 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().
--- 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
@@ -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
@@ -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
@@ -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
Sasha Levin
maintainerPATCH 44/314 s390/vtime: Fix virtual timer forwarding
In reply to Sasha LevinFrom: 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.
--- arch/s390/kernel/vtime.c | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-)
arch/s390/kernel/vtime.c +2 -16
@@ -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
Sasha Levin
maintainerPATCH 45/314 arm64: io: Rename ioremap_prot() to __ioremap_prot()
In reply to Sasha LevinFrom: 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
@@ -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
@@ -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
@@ -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
Sasha Levin
maintainerPATCH 46/314 arm64: io: Extract user memory type in ioremap_prot()
In reply to Sasha LevinFrom: 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().
--- arch/arm64/include/asm/io.h | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-)
arch/arm64/include/asm/io.h +15 -2
@@ -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
Sasha Levin
maintainerPATCH 47/314 PCI: dwc: ep: Flush MSI-X write before unmapping its ATU entry
In reply to Sasha LevinFrom: 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.
--- drivers/pci/controller/dwc/pcie-designware-ep.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/pci/controller/dwc/pcie-designware-ep.c +3 -0
@@ -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
Sasha Levin
maintainerPATCH 48/314 drm/amdgpu/userq: Do not allow userspace to trivially triger kernel warnings
In reply to Sasha LevinFrom: 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.
--- 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
@@ -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
Sasha Levin
maintainerPATCH 49/314 drm/amdgpu: Unlock a mutex before destroying it
In reply to Sasha LevinFrom: 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.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_aca.c | 1 + 1 file changed, 1 insertion(+)
drivers/gpu/drm/amd/amdgpu/amdgpu_aca.c +1 -0
@@ -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
Sasha Levin
maintainerPATCH 50/314 drm/amdgpu: Fix locking bugs in error paths
In reply to Sasha LevinFrom: 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.
--- 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
@@ -332,13 +332,13 @@ static ssize_t ta_if_invoke_debugfs_write(struct file *fp, const char *buf, sizeif (!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, sizemutex_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
Sasha Levin
maintainerPATCH 51/314 drm/amdgpu: Fix error handling in slot reset
In reply to Sasha LevinFrom: 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.
--- 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
@@ -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
Sasha Levin
maintainerPATCH 52/314 ALSA: hda: cs35l56: Fix signedness error in cs35l56_hda_posture_put()
In reply to Sasha LevinFrom: 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
--- 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
@@ -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
Sasha Levin
maintainerPATCH 53/314 btrfs: free pages on error in btrfs_uring_read_extent()
In reply to Sasha LevinFrom: 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.
--- fs/btrfs/ioctl.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
fs/btrfs/ioctl.c +6 -1
@@ -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
Sasha Levin
maintainerPATCH 54/314 btrfs: fix error message order of parameters in btrfs_delete_delayed_dir_index()
In reply to Sasha LevinFrom: 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.
--- fs/btrfs/delayed-inode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/btrfs/delayed-inode.c +1 -1
@@ -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
Sasha Levin
maintainerPATCH 55/314 btrfs: fix incorrect key offset in error message in check_dev_extent_item()
In reply to Sasha LevinFrom: 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.)
--- fs/btrfs/tree-checker.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/btrfs/tree-checker.c +1 -1
@@ -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
Sasha Levin
maintainerPATCH 56/314 btrfs: fix objectid value in error message in check_extent_data_ref()
In reply to Sasha LevinFrom: 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.
--- fs/btrfs/tree-checker.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/btrfs/tree-checker.c +1 -1
@@ -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
Sasha Levin
maintainerPATCH 57/314 btrfs: fix warning in scrub_verify_one_metadata()
In reply to Sasha LevinFrom: 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.
--- fs/btrfs/scrub.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/btrfs/scrub.c +1 -1
@@ -747,7 +747,7 @@ static void scrub_verify_one_metadata(struct scrub_stripe *stripe, int sector_nrbtrfs_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
Sasha Levin
maintainerPATCH 58/314 btrfs: print correct subvol num if active swapfile prevents deletion
In reply to Sasha LevinFrom: 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.
--- fs/btrfs/inode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/btrfs/inode.c +1 -1
@@ -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
Sasha Levin
maintainerPATCH 59/314 btrfs: fix compat mask in error messages in btrfs_check_features()
In reply to Sasha LevinFrom: 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.
--- fs/btrfs/disk-io.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
fs/btrfs/disk-io.c +3 -3
@@ -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
Sasha Levin
maintainerPATCH 60/314 ALSA: usb: qcom: Correct parameter comment for uaudio_transfer_buffer_setup()
In reply to Sasha LevinFrom: 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.
--- sound/usb/qcom/qc_audio_offload.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
sound/usb/qcom/qc_audio_offload.c +1 -1
@@ -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
Sasha Levin
maintainerPATCH 61/314 ASoC: SDCA: Fix comments for sdca_irq_request()
In reply to Sasha LevinFrom: 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.
--- sound/soc/sdca/sdca_interrupts.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
sound/soc/sdca/sdca_interrupts.c +2 -2
@@ -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
Sasha Levin
maintainerPATCH 62/314 bpf, arm64: Force 8-byte alignment for JIT buffer to prevent atomic tearing
In reply to Sasha LevinFrom: 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.
--- arch/arm64/net/bpf_jit_comp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/arm64/net/bpf_jit_comp.c +1 -1
@@ -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
Sasha Levin
maintainerPATCH 63/314 bpf: Fix stack-out-of-bounds write in devmap
In reply to Sasha LevinFrom: 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
@@ -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
Sasha Levin
maintainerPATCH 64/314 selftests/bpf: Fix OOB read in dmabuf_collector
In reply to Sasha LevinFrom: "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
@@ -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
Sasha Levin
maintainerPATCH 65/314 sched_ext: Fix SCX_EFLAG_INITIALIZED being a no-op flag
In reply to Sasha LevinFrom: 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.
--- kernel/sched/ext_internal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/sched/ext_internal.h +1 -1
@@ -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
Sasha Levin
maintainerPATCH 66/314 spi: stm32: fix missing pointer assignment in case of dma chaining
In reply to Sasha LevinFrom: 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.
--- drivers/spi/spi-stm32.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/spi/spi-stm32.c +3 -0
@@ -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
Sasha Levin
maintainerPATCH 67/314 PCI: Correct PCI_CAP_EXP_ENDPOINT_SIZEOF_V2 value
In reply to Sasha LevinFrom: 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
@@ -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
Sasha Levin
maintainerPATCH 68/314 bpf: Fix race in cpumap on PREEMPT_RT
In reply to Sasha LevinFrom: 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
@@ -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
Sasha Levin
maintainerPATCH 69/314 bpf: Fix race in devmap on PREEMPT_RT
In reply to Sasha LevinFrom: 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
@@ -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
Sasha Levin
maintainerPATCH 70/314 bpf: Add bitwise tracking for BPF_END
In reply to Sasha LevinFrom: 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
@@ -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
@@ -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
Sasha Levin
maintainerPATCH 71/314 bpf: Introduce tnum_step to step through tnum's members
In reply to Sasha LevinFrom: 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..0This 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.101This 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
@@ -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
Sasha Levin
maintainerPATCH 72/314 bpf: Improve bounds when tnum has a single possible value
In reply to Sasha LevinFrom: 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
@@ -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
Sasha Levin
maintainerPATCH 73/314 x86/acpi/boot: Correct acpi_is_processor_usable() check again
In reply to Sasha LevinFrom: 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. ]
--- 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
@@ -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
@@ -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
Sasha Levin
maintainerPATCH 74/314 memory: mtk-smi: fix device leaks on common probe
In reply to Sasha LevinFrom: 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.
--- drivers/memory/mtk-smi.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/memory/mtk-smi.c +2 -0
@@ -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
Sasha Levin
maintainerPATCH 75/314 memory: mtk-smi: fix device leak on larb probe
In reply to Sasha LevinFrom: 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.
--- drivers/memory/mtk-smi.c | 1 + 1 file changed, 1 insertion(+)
drivers/memory/mtk-smi.c +1 -0
@@ -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
Sasha Levin
maintainerPATCH 76/314 PCI: j721e: Use devm_clk_get_optional_enabled() to get and enable the clock
In reply to Sasha LevinFrom: 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
@@ -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
Sasha Levin
maintainerPATCH 77/314 PCI: j721e: Add config guards for Cadence Host and Endpoint library APIs
In reply to Sasha LevinFrom: 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
@@ -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
Sasha Levin
maintainerPATCH 78/314 PCI: dwc: Advertise L1 PM Substates only if driver requests it
In reply to Sasha LevinFrom: 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
Sasha Levin
maintainerPATCH 79/314 PCI: dw-rockchip: Configure L1SS support
In reply to Sasha LevinFrom: 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
@@ -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
Sasha Levin
maintainerPATCH 80/314 PCI: dwc: Add L1 Substates context to ltssm_status of debugfs
In reply to Sasha LevinFrom: 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
@@ -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
@@ -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
Sasha Levin
maintainerPATCH 81/314 PCI: dw-rockchip: Change get_ltssm() to provide L1 Substates info
In reply to Sasha LevinFrom: 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
@@ -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
Sasha Levin
maintainerPATCH 82/314 Revert "PCI: dw-rockchip: Enumerate endpoints based on dll_link_up IRQ"
In reply to Sasha LevinFrom: 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 43pci_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 44pci_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 45pci_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 46pci_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 46pci_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
@@ -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
Sasha Levin
maintainerPATCH 83/314 net: qrtr: Drop the MHI auto_queue feature for IPCR DL channels
In reply to Sasha LevinFrom: 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
@@ -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
@@ -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
@@ -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
@@ -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
Sasha Levin
maintainerPATCH 84/314 media: v4l2-mem2mem: Add a kref to the v4l2_m2m_dev structure
In reply to Sasha LevinFrom: 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.
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
@@ -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
@@ -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
Sasha Levin
maintainerPATCH 85/314 media: verisilicon: Avoid G2 bus error while decoding H.264 and HEVC
In reply to Sasha LevinFrom: 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.
--- 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
@@ -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
@@ -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
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 thev4l2_m2m_devcan handle the scheduling.Fixes cb5dd5a0fa518 ("media: hantro: Introduce G2/HEVC decoder")Signed-off-by Ming Qian <[email protected]>Reviewed-by Frank Li <[email protected]>Co-developed-by Nicolas Dufresne <[email protected]>Signed-off-by Nicolas Dufresne <[email protected]>Signed-off-by Hans Verkuil <[email protected]>Signed-off-by Sasha Levin <[email protected]>
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.
Sasha Levin
maintainerRe: [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 thev4l2_m2m_devcan handle the scheduling.Fixes cb5dd5a0fa518 ("media: hantro: Introduce G2/HEVC decoder")Signed-off-by Ming Qian <[email protected]>Reviewed-by Frank Li <[email protected]>Co-developed-by Nicolas Dufresne <[email protected]>Signed-off-by Nicolas Dufresne <[email protected]>Signed-off-by Hans Verkuil <[email protected]>Signed-off-by Sasha Levin <[email protected]>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
Sasha Levin
maintainerPATCH 86/314 usb: gadget: u_ether: add gether_opts for config caching
In reply to Sasha LevinFrom: 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
@@ -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
@@ -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
Sasha Levin
maintainerPATCH 87/314 usb: gadget: u_ether: Add auto-cleanup helper for freeing net_device
In reply to Sasha LevinFrom: 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
@@ -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
@@ -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
Sasha Levin
maintainerPATCH 88/314 usb: gadget: f_ncm: align net_device lifecycle with bind/unbind
In reply to Sasha LevinFrom: 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.
--- 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
@@ -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
@@ -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
Sasha Levin
maintainerPATCH 89/314 accel/rocket: fix unwinding in error path in rocket_core_init
In reply to Sasha LevinFrom: 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
@@ -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
Sasha Levin
maintainerPATCH 90/314 accel/rocket: fix unwinding in error path in rocket_probe
In reply to Sasha LevinFrom: 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
@@ -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
Sasha Levin
maintainerPATCH 91/314 media: tegra-video: Fix memory leak in __tegra_channel_try_format()
In reply to Sasha LevinFrom: 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.
--- drivers/staging/media/tegra-video/vi.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-)
drivers/staging/media/tegra-video/vi.c +8 -5
@@ -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
Sasha Levin
maintainerPATCH 92/314 KVM: x86: Ignore -EBUSY when checking nested events from vcpu_block()
In reply to Sasha LevinFrom: 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.
--- arch/x86/kvm/x86.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
arch/x86/kvm/x86.c +1 -2
@@ -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
Sasha Levin
maintainerPATCH 93/314 drm/tegra: dsi: fix device leak on probe
In reply to Sasha LevinFrom: 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.
--- drivers/gpu/drm/tegra/dsi.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-)
drivers/gpu/drm/tegra/dsi.c +2 -4
@@ -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
Sasha Levin
maintainerPATCH 94/314 unwind: Simplify unwind_user_next_fp() alignment check
In reply to Sasha LevinFrom: 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
@@ -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
Sasha Levin
maintainerPATCH 95/314 unwind: Implement compat fp unwind
In reply to Sasha LevinFrom: 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
@@ -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
@@ -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
Sasha Levin
maintainerPATCH 96/314 unwind_user/x86: Enable frame pointer unwinding on x86
In reply to Sasha LevinFrom: 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
@@ -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
@@ -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
Sasha Levin
maintainerPATCH 97/314 unwind_user/x86: Teach FP unwind about start of function
In reply to Sasha LevinFrom: 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
Sasha Levin
maintainerPATCH 98/314 x86/uprobes: Fix XOL allocation failure for 32-bit tasks
In reply to Sasha LevinFrom: 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
@@ -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
@@ -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
@@ -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
Sasha Levin
maintainerPATCH 99/314 ext4: correct the comments place for EXT4_EXT_MAY_ZEROOUT
In reply to Sasha LevinFrom: 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
@@ -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
Sasha Levin
maintainerPATCH 100/314 ext4: don't set EXT4_GET_BLOCKS_CONVERT when splitting before submitting I/O
In reply to Sasha LevinFrom: 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.
Message-ID: <[email protected]>
--- fs/ext4/extents.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-)
fs/ext4/extents.c +8 -4
@@ -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
Sasha Levin
maintainerPATCH 101/314 media: iris: remove v4l2_m2m_ioctl_{de,en}coder_cmd API usage during STOP handling
In reply to Sasha LevinFrom: 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.
--- 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
@@ -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
Sasha Levin
maintainerPATCH 102/314 media: iris: Add missing platform data entries for SM8750
In reply to Sasha LevinFrom: 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.
--- 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
@@ -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
Sasha Levin
maintainerPATCH 103/314 Input: synaptics_i2c - replace use of system_wq with system_dfl_wq
In reply to Sasha LevinFrom: 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
@@ -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
Sasha Levin
maintainerPATCH 104/314 Input: synaptics_i2c - guard polling restart in resume
In reply to Sasha LevinFrom: 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.
--- drivers/input/mouse/synaptics_i2c.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
drivers/input/mouse/synaptics_i2c.c +5 -2
@@ -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
Sasha Levin
maintainerPATCH 105/314 iommu/vt-d: Skip dev-iotlb flush for inaccessible PCIe device without scalable mode
In reply to Sasha LevinFrom: 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.
--- drivers/iommu/intel/pasid.c | 8 ++++++++ 1 file changed, 8 insertions(+)
drivers/iommu/intel/pasid.c +8 -0
@@ -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
Sasha Levin
maintainerPATCH 106/314 arm64: dts: rockchip: Fix rk356x PCIe range mappings
In reply to Sasha LevinFrom: 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.
--- 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
@@ -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
@@ -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
Sasha Levin
maintainerPATCH 107/314 arm64: dts: rockchip: Fix rk3588 PCIe range mappings
In reply to Sasha LevinFrom: 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.
--- 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
@@ -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
@@ -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
Sasha Levin
maintainerPATCH 108/314 clk: tegra: tegra124-emc: fix device leak on set_rate()
In reply to Sasha LevinFrom: 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.
--- drivers/clk/tegra/clk-tegra124-emc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/clk/tegra/clk-tegra124-emc.c +1 -1
@@ -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
Sasha Levin
maintainerPATCH 109/314 ACPI: APEI: GHES: Add helper for CPER CXL protocol errors checks
In reply to Sasha LevinFrom: "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
@@ -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
@@ -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
@@ -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
@@ -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
Sasha Levin
maintainerPATCH 110/314 ACPI: APEI: GHES: Disable KASAN instrumentation when compile testing with clang < 18
In reply to Sasha LevinFrom: 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
@@ -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
Sasha Levin
maintainerPATCH 111/314 ARM: dts: imx53-usbarmory: Replace license text comment with SPDX identifier
In reply to Sasha LevinFrom: 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
@@ -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
Sasha Levin
maintainerPATCH 112/314 PCI: Add preceding capability position support in PCI_FIND_NEXT_*_CAP macros
In reply to Sasha LevinFrom: 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
Sasha Levin
maintainerPATCH 113/314 PCI: dwc: Add new APIs to remove standard and extended Capability
In reply to Sasha LevinFrom: 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
@@ -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
@@ -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
Sasha Levin
maintainerPATCH 114/314 PCI: dwc: Remove duplicate dw_pcie_ep_hide_ext_capability() function
In reply to Sasha LevinFrom: 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
@@ -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
@@ -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
@@ -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
Sasha Levin
maintainerPATCH 115/314 PCI: dwc: ep: Fix resizable BAR support for multi-PF configurations
In reply to Sasha LevinFrom: 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.
--- .../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
@@ -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
Sasha Levin
maintainerPATCH 116/314 KVM: x86: Add x2APIC "features" to control EOI broadcast suppression
In reply to Sasha LevinFrom: 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.
--- 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
Sasha Levin
maintainerPATCH 117/314 btrfs: define the AUTO_KFREE/AUTO_KVFREE helper macros
In reply to Sasha LevinFrom: 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
@@ -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