From 7684acd7ee242fa2c80c4a240f6dcfd93f3f688a Mon Sep 17 00:00:00 2001 From: Yue Wang Date: Tue, 16 Jul 2019 15:41:04 +0800 Subject: [PATCH] usb: dma-mapping: prevent writeback deadlock in CMA allocator [1/1] PD#SWPL-11362 Problem: A deadlock happens when a task initiates a CMA allocation that triggers a page migration *AND* the tasks holding the subsequent pages have to writeback their pages using CMA allocations. In such a situation, the task that has triggered the page migration holds a mutex that prevents other tasks from migrating their pages using that same CMA allocator. This leads to a deadlock. Solution: The CMA is incapable of honoring the NOIO flags in some scenario, thus cannot be used for writeback. The fix allows the code that chooses which allocator to use in the ARM platform to avoid the CMA case for that scenario. The ARM DMA layer checks for allow blocking flag (_GFP_BDEV) to decide whether to go for CMA or not. That test is not sufficient to cover the case of writeback (GFP_NOIO). The fix consists in adding a gfp_allow_writeback helper that tests for the __GFP_IO flag. Then, the DMA layer uses it to decide not to go for CMA in case of writeback. Verify: TL1 Change-Id: I175eb94de588234d3de2dc7f65dafe980e2636af Signed-off-by: Yue Wang --- arch/arm/mm/dma-mapping.c | 5 ++++- drivers/usb/host/xhci.c | 5 +++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index 00e9e79b6cb8..0cf1b787f4c9 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -800,7 +800,10 @@ static void *__dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, *handle = DMA_ERROR_CODE; allowblock = gfpflags_allow_blocking(gfp); cma = allowblock ? dev_get_cma_area(dev) : false; - +#ifdef CONFIG_AMLOGIC_CMA + if (!!(gfp & __GFP_BDEV)) + cma = false; +#endif if (cma) buf->allocator = &cma_allocator; else if (nommu() || is_coherent) diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 7c7a79851489..7d5ae4b86f80 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -1780,7 +1780,12 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev, * process context, not interrupt context (or so documenation * for usb_set_interface() and usb_set_configuration() claim). */ +#ifdef CONFIG_AMLOGIC_CMA + if (xhci_endpoint_init(xhci, virt_dev, udev, ep, + GFP_NOIO | __GFP_BDEV) < 0) { +#else if (xhci_endpoint_init(xhci, virt_dev, udev, ep, GFP_NOIO) < 0) { +#endif dev_dbg(&udev->dev, "%s - could not initialize ep %#x\n", __func__, ep->desc.bEndpointAddress); return -ENOMEM;