usb: xhci: check if 'requested segments' exceeds ERST capacity
authorNiklas Neronin <niklas.neronin@linux.intel.com>
Mon, 29 Apr 2024 14:02:30 +0000 (17:02 +0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 1 May 2024 06:47:14 +0000 (08:47 +0200)
Check if requested segments ('segs' or 'ERST_DEFAULT_SEGS') exceeds the
maximum amount ERST supports.

When 'segs' is '0', 'ERST_DEFAULT_SEGS' is used instead. But both values
may not exceed ERST max.

Macro 'ERST_MAX_SEGS' is renamed to 'ERST_DEFAULT_SEGS'. The new name
better represents the macros, which is the number of Event Ring segments
to allocate, when the amount is not specified.

Additionally, rename and change xhci_create_secondary_interrupter()'s
argument 'int num_segs' to 'unsigned int segs'. This makes it the same
as its counter part in xhci_alloc_interrupter().

Fixes: c99b38c41234 ("xhci: add support to allocate several interrupters")
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/20240429140245.3955523-4-mathias.nyman@linux.intel.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/host/xhci-mem.c
drivers/usb/host/xhci.h

index 7ff2ff29b48e79e726456ac7dadf311a99c59909..1a16b44506da1dde83bd0d1ea872994125ad3dd3 100644 (file)
@@ -2259,24 +2259,24 @@ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags)
 }
 
 static struct xhci_interrupter *
-xhci_alloc_interrupter(struct xhci_hcd *xhci, int segs, gfp_t flags)
+xhci_alloc_interrupter(struct xhci_hcd *xhci, unsigned int segs, gfp_t flags)
 {
        struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
        struct xhci_interrupter *ir;
-       unsigned int num_segs = segs;
+       unsigned int max_segs;
        int ret;
 
+       if (!segs)
+               segs = ERST_DEFAULT_SEGS;
+
+       max_segs = BIT(HCS_ERST_MAX(xhci->hcs_params2));
+       segs = min(segs, max_segs);
+
        ir = kzalloc_node(sizeof(*ir), flags, dev_to_node(dev));
        if (!ir)
                return NULL;
 
-       /* number of ring segments should be greater than 0 */
-       if (segs <= 0)
-               num_segs = min_t(unsigned int, 1 << HCS_ERST_MAX(xhci->hcs_params2),
-                        ERST_MAX_SEGS);
-
-       ir->event_ring = xhci_ring_alloc(xhci, num_segs, 1, TYPE_EVENT, 0,
-                                        flags);
+       ir->event_ring = xhci_ring_alloc(xhci, segs, 1, TYPE_EVENT, 0, flags);
        if (!ir->event_ring) {
                xhci_warn(xhci, "Failed to allocate interrupter event ring\n");
                kfree(ir);
@@ -2334,7 +2334,7 @@ xhci_add_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir,
 }
 
 struct xhci_interrupter *
-xhci_create_secondary_interrupter(struct usb_hcd *hcd, int num_seg)
+xhci_create_secondary_interrupter(struct usb_hcd *hcd, unsigned int segs)
 {
        struct xhci_hcd *xhci = hcd_to_xhci(hcd);
        struct xhci_interrupter *ir;
@@ -2344,7 +2344,7 @@ xhci_create_secondary_interrupter(struct usb_hcd *hcd, int num_seg)
        if (!xhci->interrupters || xhci->max_interrupters <= 1)
                return NULL;
 
-       ir = xhci_alloc_interrupter(xhci, num_seg, GFP_KERNEL);
+       ir = xhci_alloc_interrupter(xhci, segs, GFP_KERNEL);
        if (!ir)
                return NULL;
 
index 1c9519205330cfbaa064a26b13237a3791b2dc3a..8a3ae5049d1cef50245ae4a2798b5606df507cf2 100644 (file)
@@ -1392,8 +1392,8 @@ struct urb_priv {
        struct  xhci_td td[] __counted_by(num_tds);
 };
 
-/* Reasonable limit for number of Event Ring segments (spec allows 32k) */
-#define        ERST_MAX_SEGS   2
+/* Number of Event Ring segments to allocate, when amount is not specified. (spec allows 32k) */
+#define        ERST_DEFAULT_SEGS       2
 /* Poll every 60 seconds */
 #define        POLL_TIMEOUT    60
 /* Stop endpoint command timeout (secs) for URB cancellation watchdog timer */
@@ -1831,7 +1831,7 @@ struct xhci_container_ctx *xhci_alloc_container_ctx(struct xhci_hcd *xhci,
 void xhci_free_container_ctx(struct xhci_hcd *xhci,
                struct xhci_container_ctx *ctx);
 struct xhci_interrupter *
-xhci_create_secondary_interrupter(struct usb_hcd *hcd, int num_seg);
+xhci_create_secondary_interrupter(struct usb_hcd *hcd, unsigned int segs);
 void xhci_remove_secondary_interrupter(struct usb_hcd
                                       *hcd, struct xhci_interrupter *ir);