[RFC v3] xhci: fix dma mask setup in xhci.c

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

 



The function dma_set_mask() tests internally whether the dma_mask pointer
for the device is initialized and fails if the dma_mask pointer is NULL.
On pci platforms, the initialization of the device dma_mask pointer is
performed when pci devices are enumerated and is set to point to the
pci_dev->dma_mask which is 0xffffffff. However, for non-pci platforms,
the dma_mask pointer remains uninitialized and dma_set_mask() will fail.

Also, a call to dma_set_mask() does not set the device coherent_dma_mask.
Since the xhci-hcd driver calls dma_alloc_coherent() and dma_pool_alloc()
to allocate consistent DMA memory blocks, the coherent DMA address mask
has to be set explicitly, otherwise the DMA mapping interface will return
by default DMA addresses which are 32-bit addressable.

This patch removes the dma_mask setup code from xhci_gen_setup() and places
it in xhci_pci_setup() and xhci_plat_setup(). The dma_mask setup must be
done before the call to xhci_gen_setup() which allocates and maps to dma
addresses the xhci-hcd buffers.

For pci platforms, the dma_mask and coherent_dma_mask are set by default
to 32bit DMA addresses. If both the xHC controller and the host support
64bit DMA addresses, the device dma_mask and coherent_dma_mask will be
set to 64bits.

For non-pci platforms, the dma_mask pointer is initialized to point to
the coherent_dma_mask since the same value will be assigned to both.

If dma_set_mask() succeeds, for a given bitmask, it is guaranteed that
the given bitmask is also supported for consistent DMA mappings.
That is the reason why this patch does not add checks when setting the
coherent_dma_mask.

Signed-off-by: Xenia Ragiadakou <burzalodowa@xxxxxxxxx>
---

Differences from version 1 and 2:

The dma_mask setup code was removed from the xhci_gen_setup()
function defined in xhci.c and was placed in xhci_pci_setup(),
defined in xhci-pci.c, and in xhci_plat_setup(), defined in
xhci-plat.c. The dma mask setup code has to be called after
the mapping of host controller registers and before the
allocation of xhci memory buffers, so it was placed in the
driver's 'reset' callback function before the call to
xhci_gen_setup().

Initialization of the dma_mask pointer was added for non-pci
platforms, following a remark made by Andy Shevchenco.

 drivers/usb/host/xhci-pci.c  | 19 ++++++++++++++++++-
 drivers/usb/host/xhci-plat.c | 26 ++++++++++++++++++++++++++
 drivers/usb/host/xhci.c      | 17 -----------------
 3 files changed, 44 insertions(+), 18 deletions(-)

diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index cc24e39..dff5a22 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -122,9 +122,26 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
 static int xhci_pci_setup(struct usb_hcd *hcd)
 {
 	struct xhci_hcd		*xhci;
-	struct pci_dev		*pdev = to_pci_dev(hcd->self.controller);
+	struct pci_dev		*pdev;
+	struct device		*dev;
 	int			retval;
 
+	dev = hcd->self.controller;
+	pdev = to_pci_dev(dev);
+
+	if (usb_hcd_is_primary_hcd(hcd)) {
+		struct xhci_cap_regs __iomem 	*cap_regs;
+		u32				hcc_params;
+
+		cap_regs = hcd->regs;
+		hcc_params = readl(&cap_regs->hcc_params);
+		if (HCC_64BIT_ADDR(hcc_params) &&
+				!dma_set_mask(dev, DMA_BIT_MASK(64))) {
+			dev_dbg(dev, "Enabling 64-bit DMA addresses.\n");
+			dma_set_coherent_mask(dev, DMA_BIT_MASK(64));
+		}
+	}
+
 	retval = xhci_gen_setup(hcd, xhci_pci_quirks);
 	if (retval)
 		return retval;
diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
index 51e22bf..d718134 100644
--- a/drivers/usb/host/xhci-plat.c
+++ b/drivers/usb/host/xhci-plat.c
@@ -30,6 +30,32 @@ static void xhci_plat_quirks(struct device *dev, struct xhci_hcd *xhci)
 /* called during probe() after chip reset completes */
 static int xhci_plat_setup(struct usb_hcd *hcd)
 {
+	struct device			*dev;
+	int				retval;
+
+	dev = hcd->self.controller;
+	dev->dma_mask = &dev->dma_coherent_mask;
+
+	if (usb_hcd_is_primary_hcd(hcd)) {
+		struct xhci_cap_regs __iomem 	*cap_regs;
+		u32				hcc_params;
+
+		cap_regs = hcd->regs;
+		hcc_params = readl(&cap_regs->hcc_params);
+		if (HCC_64BIT_ADDR(hcc_params) &&
+				!dma_set_mask(dev, DMA_BIT_MASK(64))) {
+			dev_dbg(dev, "Enabling 64-bit DMA addresses.\n");
+		} else {
+			retval = dma_set_mask(dev, DMA_BIT_MASK(32));
+			if (retval) {
+				dev->dma_mask = NULL;
+				hcd->self.uses_dma = 0;
+				return retval;
+			}
+		}
+		hcd->self.uses_dma = 1;
+	}
+
 	return xhci_gen_setup(hcd, xhci_plat_quirks);
 }
 
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 189ca85..32e5493 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -4761,7 +4761,6 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
 	struct xhci_hcd		*xhci;
 	struct device		*dev = hcd->self.controller;
 	int			retval;
-	u32			temp;
 
 	/* Accept arbitrarily long scatter-gather lists */
 	hcd->self.sg_tablesize = ~0;
@@ -4789,14 +4788,6 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
 		/* xHCI private pointer was set in xhci_pci_probe for the second
 		 * registered roothub.
 		 */
-		xhci = hcd_to_xhci(hcd);
-		temp = xhci_readl(xhci, &xhci->cap_regs->hcc_params);
-		if (HCC_64BIT_ADDR(temp)) {
-			xhci_dbg(xhci, "Enabling 64-bit DMA addresses.\n");
-			dma_set_mask(hcd->self.controller, DMA_BIT_MASK(64));
-		} else {
-			dma_set_mask(hcd->self.controller, DMA_BIT_MASK(32));
-		}
 		return 0;
 	}
 
@@ -4828,14 +4819,6 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
 		goto error;
 	xhci_dbg(xhci, "Reset complete\n");
 
-	temp = xhci_readl(xhci, &xhci->cap_regs->hcc_params);
-	if (HCC_64BIT_ADDR(temp)) {
-		xhci_dbg(xhci, "Enabling 64-bit DMA addresses.\n");
-		dma_set_mask(hcd->self.controller, DMA_BIT_MASK(64));
-	} else {
-		dma_set_mask(hcd->self.controller, DMA_BIT_MASK(32));
-	}
-
 	xhci_dbg(xhci, "Calling HCD init\n");
 	/* Initialize HCD and host controller data structures. */
 	retval = xhci_init(hcd);
-- 
1.8.3.1

--
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