From: Niklas Neronin <niklas.neronin@linux.intel.com> mainline inclusion from mainline-v6.11-rc1 commit 7476a2215c07703db5e95efaa3fc5b9f957b9417 category: bugfix bugzilla: https://gitee.com/src-openeuler/kernel/issues/IC1PGD CVE: CVE-2025-22022 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i... -------------------------------- Older 0.95 xHCI hosts and some other specific newer hosts require the chain bit to be set for Link TRBs even if the link TRB is not in the middle of a transfer descriptor (TD). move the checks for all those cases into one xhci_link_chain_quirk() function to clean up and avoid code duplication. No functional changes. [skip renaming chain_links flag, reword commit message -Mathias] Signed-off-by: Niklas Neronin <niklas.neronin@linux.intel.com> Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com> Link: https://lore.kernel.org/r/20240626124835.1023046-10-mathias.nyman@linux.inte... Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Conflicts: drivers/usb/host/xhci-mem.c [just context conflicts] Signed-off-by: Wang Hai <wanghai38@huawei.com> --- drivers/usb/host/xhci-mem.c | 10 ++-------- drivers/usb/host/xhci-ring.c | 8 ++------ drivers/usb/host/xhci.h | 7 +++++-- 3 files changed, 9 insertions(+), 16 deletions(-) diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index fe0827e4701b..6e5c231a4bbc 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -131,14 +131,11 @@ static void xhci_link_rings(struct xhci_hcd *xhci, struct xhci_ring *ring, bool chain_links; if (!ring || !first || !last) return; - /* Set chain bit for 0.95 hosts, and for isoc rings on AMD 0.96 host */ - chain_links = !!(xhci_link_trb_quirk(xhci) || - (ring->type == TYPE_ISOC && - (xhci->quirks & XHCI_AMD_0x96_HOST))); + chain_links = xhci_link_chain_quirk(xhci, ring->type); next = ring->enq_seg->next; xhci_link_segments(ring->enq_seg, first, ring->type, chain_links); xhci_link_segments(last, next, ring->type, chain_links); ring->num_segs += num_segs; @@ -324,14 +321,11 @@ static int xhci_alloc_segments_for_ring(struct xhci_hcd *xhci, enum xhci_ring_type type, unsigned int max_packet, gfp_t flags) { struct xhci_segment *prev; bool chain_links; - /* Set chain bit for 0.95 hosts, and for isoc rings on AMD 0.96 host */ - chain_links = !!(xhci_link_trb_quirk(xhci) || - (type == TYPE_ISOC && - (xhci->quirks & XHCI_AMD_0x96_HOST))); + chain_links = xhci_link_chain_quirk(xhci, type); prev = xhci_segment_alloc(xhci, cycle_state, max_packet, flags); if (!prev) return -ENOMEM; num_segs--; diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index f5fbfc2a9b69..747403de8cb2 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -232,13 +232,11 @@ static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring, /* If we're not dealing with 0.95 hardware or isoc rings on * AMD 0.96 host, carry over the chain bit of the previous TRB * (which may mean the chain bit is cleared). */ - if (!(ring->type == TYPE_ISOC && - (xhci->quirks & XHCI_AMD_0x96_HOST)) && - !xhci_link_trb_quirk(xhci)) { + if (!xhci_link_chain_quirk(xhci, ring->type)) { next->link.control &= cpu_to_le32(~TRB_CHAIN); next->link.control |= cpu_to_le32(chain); } /* Give this link TRB to the hardware */ wmb(); @@ -3317,13 +3315,11 @@ static int prepare_ring(struct xhci_hcd *xhci, struct xhci_ring *ep_ring, while (trb_is_link(ep_ring->enqueue)) { /* If we're not dealing with 0.95 hardware or isoc rings * on AMD 0.96 host, clear the chain bit. */ - if (!xhci_link_trb_quirk(xhci) && - !(ep_ring->type == TYPE_ISOC && - (xhci->quirks & XHCI_AMD_0x96_HOST))) + if (!xhci_link_chain_quirk(xhci, ep_ring->type)) ep_ring->enqueue->link.control &= cpu_to_le32(~TRB_CHAIN); else ep_ring->enqueue->link.control |= cpu_to_le32(TRB_CHAIN); diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index e4fa4300bee0..6950f01b4f2f 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -2001,13 +2001,16 @@ static inline void xhci_write_64(struct xhci_hcd *xhci, const u64 val, __le64 __iomem *regs) { lo_hi_writeq(val, regs); } -static inline int xhci_link_trb_quirk(struct xhci_hcd *xhci) + +/* Link TRB chain should always be set on 0.95 hosts, and AMD 0.96 ISOC rings */ +static inline bool xhci_link_chain_quirk(struct xhci_hcd *xhci, enum xhci_ring_type type) { - return xhci->quirks & XHCI_LINK_TRB_QUIRK; + return (xhci->quirks & XHCI_LINK_TRB_QUIRK) || + (type == TYPE_ISOC && (xhci->quirks & XHCI_AMD_0x96_HOST)); } /* xHCI debugging */ char *xhci_get_slot_state(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx); -- 2.17.1