[PATCH 37/37] usb: host: xhci: dynamically allocate dcbaa

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Instead of *always* allocating an array of 256 pointers, we can
dynamically allocate it based on number of maximum slots $this XHCI
implementation supports.

Signed-off-by: Felipe Balbi <felipe.balbi@xxxxxxxxxxxxxxx>
---
 drivers/usb/host/xhci-mem.c | 45 ++++++++++++++++++++++++++++++---------------
 drivers/usb/host/xhci.h     |  4 +---
 2 files changed, 31 insertions(+), 18 deletions(-)

diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index 2b7c3504a95a..916eb2e30029 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -1815,6 +1815,7 @@ void xhci_free_command(struct xhci_hcd *xhci,
 void xhci_mem_cleanup(struct xhci_hcd *xhci)
 {
 	struct device	*dev = xhci_to_hcd(xhci)->self.controller;
+	int max_slots;
 	int size;
 	int i, j, num_ports;
 
@@ -1851,7 +1852,8 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
 		}
 	}
 
-	for (i = 1; i <= HCS_MAX_SLOTS(xhci->hcs_params1); i++)
+	max_slots = HCS_MAX_SLOTS(xhci->hcs_params1) + 1;
+	for (i = 1; i < max_slots; i++)
 		xhci_free_virt_device(xhci, i);
 
 	dma_pool_destroy(xhci->segment_pool);
@@ -1872,11 +1874,13 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
 	xhci_dbg_trace(xhci, trace_xhci_dbg_init,
 			"Freed medium stream array pool");
 
-	if (xhci->dcbaa)
-		dma_free_coherent(dev, sizeof(*xhci->dcbaa),
-				xhci->dcbaa, xhci->dcbaa->dma);
-	xhci->dcbaa = NULL;
+	if (xhci->dcbaa->dev_context_ptrs)
+		dma_free_coherent(dev, sizeof(__le64) * max_slots,
+				xhci->dcbaa->dev_context_ptrs,
+				xhci->dcbaa->dma);
 
+	kfree(xhci->dcbaa);
+	xhci->dcbaa = NULL;
 	scratchpad_free(xhci);
 
 	if (!xhci->rh_bw)
@@ -2205,6 +2209,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
 	u64		val_64;
 	struct xhci_segment	*seg;
 	u32 page_size, temp;
+	int max_slots;
 	int i;
 
 	INIT_LIST_HEAD(&xhci->cmd_list);
@@ -2236,17 +2241,22 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
 	 * Program the Number of Device Slots Enabled field in the CONFIG
 	 * register with the max value of slots the HC can handle.
 	 */
-	val = HCS_MAX_SLOTS(readl(&xhci->cap_regs->hcs_params1));
+	max_slots = HCS_MAX_SLOTS(readl(&xhci->cap_regs->hcs_params1));
 	xhci_dbg_trace(xhci, trace_xhci_dbg_init,
-			"// xHC can handle at most %d device slots.", val);
+			"// xHC can handle at most %d device slots.", max_slots);
+
 	val2 = readl(&xhci->op_regs->config_reg);
-	val |= (val2 & ~HCS_SLOTS_MASK);
+	val = max_slots | (val2 & ~HCS_SLOTS_MASK);
+
+	/* XHCI needs offset 0 to be unused */
+	max_slots += 1;
+
 	xhci_dbg_trace(xhci, trace_xhci_dbg_init,
 			"// Setting Max device slots reg = 0x%x.", val);
 	writel(val, &xhci->op_regs->config_reg);
 
-	xhci->devs = kcalloc(HCS_MAX_SLOTS(xhci->hcs_params1) + 1,
-			sizeof(struct xhci_virt_device *), GFP_KERNEL);
+	xhci->devs = kcalloc(max_slots, sizeof(struct xhci_virt_device *),
+			GFP_KERNEL);
 	if (!xhci->devs)
 		goto fail;
 
@@ -2254,16 +2264,21 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
 	 * Section 5.4.8 - doorbell array must be
 	 * "physically contiguous and 64-byte (cache line) aligned".
 	 */
-	xhci->dcbaa = dma_alloc_coherent(dev, sizeof(*xhci->dcbaa), &dma,
-			flags);
+	xhci->dcbaa = kzalloc(sizeof(*xhci->dcbaa), GFP_KERNEL);
 	if (!xhci->dcbaa)
 		goto fail;
-	memset(xhci->dcbaa, 0, sizeof *(xhci->dcbaa));
-	xhci->dcbaa->dma = dma;
+
+	xhci->dcbaa->dev_context_ptrs = dma_alloc_coherent(dev, sizeof(__le64) *
+			max_slots, &xhci->dcbaa->dma, flags);
+	if (!xhci->dcbaa->dev_context_ptrs)
+		goto fail;
+
+	memset(xhci->dcbaa->dev_context_ptrs, 0, sizeof (__le64) *
+			max_slots);
 	xhci_dbg_trace(xhci, trace_xhci_dbg_init,
 			"// Device context base array address = 0x%llx (DMA), %p (virt)",
 			(unsigned long long)xhci->dcbaa->dma, xhci->dcbaa);
-	xhci_write_64(xhci, dma, &xhci->op_regs->dcbaa_ptr);
+	xhci_write_64(xhci, xhci->dcbaa->dma, &xhci->op_regs->dcbaa_ptr);
 
 	/*
 	 * Initialize the ring segment pool.  The ring must be a contiguous
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 57731f6dba6c..37fd2b27f5b7 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -37,8 +37,6 @@
 /* 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
 /* Section 5.3.3 - MaxPorts */
 #define MAX_HC_PORTS		127
 
@@ -1033,7 +1031,7 @@ struct xhci_tt_bw_info {
  */
 struct xhci_device_context_array {
 	/* 64-bit device addresses; we only write 32-bit addresses */
-	__le64			dev_context_ptrs[MAX_HC_SLOTS];
+	__le64			*dev_context_ptrs;
 	/* private xHCD pointers */
 	dma_addr_t	dma;
 };
-- 
2.11.0

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux