diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 939151e5440e..a5e7f363922f 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -1947,8 +1947,11 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed command ring"); xhci_cleanup_command_queue(xhci); - for (i = xhci->max_slots; i > 0; i--) - xhci_free_virt_devices_depth_first(xhci, i); + if (xhci->devs) { + for (i = xhci->max_slots; i > 0; i--) + xhci_free_virt_devices_depth_first(xhci, i); + kfree(xhci->devs); + } dma_pool_destroy(xhci->segment_pool); xhci->segment_pool = NULL; @@ -2005,6 +2008,7 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) xhci->rh_bw = NULL; xhci->port_caps = NULL; xhci->interrupters = NULL; + xhci->devs = NULL; xhci->usb2_rhub.bus_state.bus_suspended = 0; xhci->usb3_rhub.bus_state.bus_suspended = 0; @@ -2411,6 +2415,12 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Starting %s", __func__); + xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Allocating internal virtual device array"); + xhci->devs = kcalloc_node(xhci->max_slots + 1, sizeof(*xhci->devs), flags, + dev_to_node(dev)); + if (!xhci->devs) + goto fail; + xhci->dcbaa.ctx_array = dma_alloc_coherent(dev, array_size(sizeof(*dcbaa->ctx_array), xhci->max_slots + 1), &dcbaa->dma, flags); diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 14d7f866f220..6922cc5496c1 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -5457,7 +5457,7 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks) if (xhci->hci_version > 0x100) xhci->hcc_params2 = readl(&xhci->cap_regs->hcc_params2); - xhci->max_slots = HCS_MAX_SLOTS(hcs_params1); + xhci->max_slots = min(HCS_MAX_SLOTS(hcs_params1), MAX_HC_SLOTS); xhci->max_ports = min(HCS_MAX_PORTS(hcs_params1), MAX_HC_PORTS); /* xhci-plat or xhci-pci might have set max_interrupters already */ if (!xhci->max_interrupters) @@ -5530,8 +5530,6 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks) init_completion(&xhci->cmd_ring_stop_completion); xhci_hcd_page_size(xhci); - memset(xhci->devs, 0, MAX_HC_SLOTS * sizeof(*xhci->devs)); - /* Allocate xHCI data structures */ retval = xhci_mem_init(xhci, GFP_KERNEL); if (retval) diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index cb80acac97d4..d02046a573e4 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -33,8 +33,11 @@ /* xHCI PCI Configuration Registers */ #define XHCI_SBRN_OFFSET (0x60) -/* Max number of USB devices for any host controller - limit in section 6.1 */ -#define MAX_HC_SLOTS 256 +/* + * Max number of Devices Slots. xHCI specification section 5.3.3 + * Valid values are in the range of 1 to 255. + */ +#define MAX_HC_SLOTS 255 /* * Max Number of Ports. xHCI specification section 5.3.3 * Valid values are in the range of 1 to 255. @@ -1551,7 +1554,7 @@ struct xhci_hcd { /* these are not thread safe so use mutex */ struct mutex mutex; /* Internal mirror of the HW's dcbaa */ - struct xhci_virt_device *devs[MAX_HC_SLOTS]; + struct xhci_virt_device **devs; /* For keeping track of bandwidth domains per roothub. */ struct xhci_root_port_bw_info *rh_bw;