From patchwork Fri Mar 6 18:05:40 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jorge Ramirez-Ortiz X-Patchwork-Id: 45493 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-we0-f197.google.com (mail-we0-f197.google.com [74.125.82.197]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id 92C42214A0 for ; Fri, 6 Mar 2015 18:06:24 +0000 (UTC) Received: by wesp10 with SMTP id p10sf5730510wes.2 for ; Fri, 06 Mar 2015 10:06:23 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:delivered-to:from:to:subject:date :message-id:sender:precedence:list-id:x-original-sender :x-original-authentication-results:mailing-list:list-post:list-help :list-archive:list-unsubscribe; bh=/JEBcwOPQPddqGh6F5zVxcN5XL9WKHjsSiFAE3AfF6g=; b=fHAkSv9tAIB/uAsA2gIdSYoLRk9rlRmw19oDtaBdAT7A24glOxhYk4HcDx1wwro7PX eB+RAxtkxAgtDMF0yfr196kfe+CcdgVthakd30TBOQ2ttw6UYINf2UeQbTEqyt3n2DAR cKlfIrdttuau0C9IFqYFGk1aycyc9UzZhMNzQXdo9zWujOb1g+frywpX6EOJi0go6TJb iguOwMmA6bfb3BhrdYzbp/W5UyGvKnxATETmZ4v31ztb/RAtLJ41XrA4GBmzTYaUxNk4 eusQTSEMZmd2wMSPeJkyiWd93IZ9E4GGpy3eaJeLxJEoZbjrXm5qCpehhexG7jHmlZx3 QuDg== X-Gm-Message-State: ALoCoQmkHQ2hPGE+m02CarcclB+5OWsYfHIWaaFIOD4qL3iX0ssjVqRyOCetZS4TitETGsgthxia X-Received: by 10.112.40.81 with SMTP id v17mr2485339lbk.5.1425665183895; Fri, 06 Mar 2015 10:06:23 -0800 (PST) MIME-Version: 1.0 X-BeenThere: patchwork-forward@linaro.org Received: by 10.152.88.50 with SMTP id bd18ls103499lab.108.gmail; Fri, 06 Mar 2015 10:06:23 -0800 (PST) X-Received: by 10.112.46.201 with SMTP id x9mr14133336lbm.65.1425665183667; Fri, 06 Mar 2015 10:06:23 -0800 (PST) Received: from mail-la0-f50.google.com (mail-la0-f50.google.com. [209.85.215.50]) by mx.google.com with ESMTPS id os2si7624758lbb.177.2015.03.06.10.06.23 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 06 Mar 2015 10:06:23 -0800 (PST) Received-SPF: pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.215.50 as permitted sender) client-ip=209.85.215.50; Received: by labgd6 with SMTP id gd6so12183725lab.6 for ; Fri, 06 Mar 2015 10:06:23 -0800 (PST) X-Received: by 10.112.130.39 with SMTP id ob7mr14586269lbb.32.1425665183389; Fri, 06 Mar 2015 10:06:23 -0800 (PST) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patch@linaro.org Received: by 10.112.35.133 with SMTP id h5csp57110lbj; Fri, 6 Mar 2015 10:06:22 -0800 (PST) X-Received: by 10.68.196.136 with SMTP id im8mr27526510pbc.125.1425665179558; Fri, 06 Mar 2015 10:06:19 -0800 (PST) Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id bv3si15877349pbb.133.2015.03.06.10.06.18 for ; Fri, 06 Mar 2015 10:06:19 -0800 (PST) Received-SPF: none (google.com: linux-serial-owner@vger.kernel.org does not designate permitted sender hosts) client-ip=209.132.180.67; Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755049AbbCFSGD (ORCPT ); Fri, 6 Mar 2015 13:06:03 -0500 Received: from mail-qg0-f47.google.com ([209.85.192.47]:41043 "EHLO mail-qg0-f47.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754539AbbCFSGC (ORCPT ); Fri, 6 Mar 2015 13:06:02 -0500 Received: by qgea108 with SMTP id a108so14484043qge.8 for ; Fri, 06 Mar 2015 10:06:01 -0800 (PST) X-Received: by 10.140.152.10 with SMTP id 10mr20626854qhy.54.1425665161141; Fri, 06 Mar 2015 10:06:01 -0800 (PST) Received: from localhost.localdomain (cpe-67-247-86-207.rochester.res.rr.com. [67.247.86.207]) by mx.google.com with ESMTPSA id f46sm6208151qgd.3.2015.03.06.10.05.59 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Fri, 06 Mar 2015 10:06:00 -0800 (PST) From: Jorge Ramirez-Ortiz To: jorge.ramirez-ortiz@linaro.org, gregkh@linuxfoundation.org, linux-serial@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux@arm.linux.org.uk, robh@kernel.org Subject: [PATCH v6] drivers/tty: amba: defer DMA probe until the DMA channel is required. Date: Fri, 6 Mar 2015 13:05:40 -0500 Message-Id: <1425665140-1827-1-git-send-email-jorge.ramirez-ortiz@linaro.org> X-Mailer: git-send-email 1.9.1 Sender: linux-serial-owner@vger.kernel.org Precedence: list List-ID: X-Mailing-List: linux-serial@vger.kernel.org X-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: jorge.ramirez-ortiz@linaro.org X-Original-Authentication-Results: mx.google.com; spf=pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.215.50 as permitted sender) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org X-Google-Group-Id: 836684582541 List-Post: , List-Help: , List-Archive: List-Unsubscribe: , Fix a race condition that happens when device_initcall(pl011_dma_initicall) is executed before all the devices have been probed - this issue was observed on a hisi_6220 SoC (HiKey board from Linaro). The deferred driver probing framework relies on late_initcall to trigger deferred probes so it is just possible that, even with a valid DMA driver ready to be loaded, we fail to synchronize with it. The proposed implementation delays probing the DMA until dma_startup. As this is invoked on port startup and port resume - but DMA probing is only required once - we avoid calling multiple times using a new field in uart_amba_port to track this scenario. This commit allows for subsequent attempts to associate an external DMA if the DMA driver itself is not available (but present in the deferred probe pending list). Signed-off-by: Jorge Ramirez-Ortiz Reviewed-by: Rob Herring --- drivers/tty/serial/amba-pl011.c | 71 ++++++++++------------------------------- 1 file changed, 17 insertions(+), 54 deletions(-) diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 8d94c19..f34f85c 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -164,6 +164,7 @@ struct uart_amba_port { bool using_rx_dma; struct pl011_dmarx_data dmarx; struct pl011_dmatx_data dmatx; + bool dma_probed; #endif }; @@ -261,10 +262,11 @@ static void pl011_sgbuf_free(struct dma_chan *chan, struct pl011_sgbuf *sg, } } -static void pl011_dma_probe_initcall(struct device *dev, struct uart_amba_port *uap) +static void pl011_dma_probe(struct uart_amba_port *uap) { /* DMA is the sole user of the platform data right now */ struct amba_pl011_data *plat = dev_get_platdata(uap->port.dev); + struct device *dev = uap->port.dev; struct dma_slave_config tx_conf = { .dst_addr = uap->port.mapbase + UART01x_DR, .dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE, @@ -275,9 +277,15 @@ static void pl011_dma_probe_initcall(struct device *dev, struct uart_amba_port * struct dma_chan *chan; dma_cap_mask_t mask; - chan = dma_request_slave_channel(dev, "tx"); + uap->dma_probed = true; + chan = dma_request_slave_channel_reason(dev, "tx"); + if (IS_ERR(chan)) { + if (PTR_ERR(chan) == -EPROBE_DEFER) { + dev_info(uap->port.dev, "DMA driver not ready\n"); + uap->dma_probed = false; + return; + } - if (!chan) { /* We need platform data */ if (!plat || !plat->dma_filter) { dev_info(uap->port.dev, "no DMA platform data\n"); @@ -385,55 +393,8 @@ static void pl011_dma_probe_initcall(struct device *dev, struct uart_amba_port * } } -#ifndef MODULE -/* - * Stack up the UARTs and let the above initcall be done at device - * initcall time, because the serial driver is called as an arch - * initcall, and at this time the DMA subsystem is not yet registered. - * At this point the driver will switch over to using DMA where desired. - */ -struct dma_uap { - struct list_head node; - struct uart_amba_port *uap; - struct device *dev; -}; - -static LIST_HEAD(pl011_dma_uarts); - -static int __init pl011_dma_initcall(void) -{ - struct list_head *node, *tmp; - - list_for_each_safe(node, tmp, &pl011_dma_uarts) { - struct dma_uap *dmau = list_entry(node, struct dma_uap, node); - pl011_dma_probe_initcall(dmau->dev, dmau->uap); - list_del(node); - kfree(dmau); - } - return 0; -} - -device_initcall(pl011_dma_initcall); - -static void pl011_dma_probe(struct device *dev, struct uart_amba_port *uap) -{ - struct dma_uap *dmau = kzalloc(sizeof(struct dma_uap), GFP_KERNEL); - if (dmau) { - dmau->uap = uap; - dmau->dev = dev; - list_add_tail(&dmau->node, &pl011_dma_uarts); - } -} -#else -static void pl011_dma_probe(struct device *dev, struct uart_amba_port *uap) -{ - pl011_dma_probe_initcall(dev, uap); -} -#endif - static void pl011_dma_remove(struct uart_amba_port *uap) { - /* TODO: remove the initcall if it has not yet executed */ if (uap->dmatx.chan) dma_release_channel(uap->dmatx.chan); if (uap->dmarx.chan) @@ -1021,6 +982,9 @@ static void pl011_dma_startup(struct uart_amba_port *uap) { int ret; + if (!uap->dma_probed) + pl011_dma_probe(uap); + if (!uap->dmatx.chan) return; @@ -1142,7 +1106,7 @@ static inline bool pl011_dma_rx_running(struct uart_amba_port *uap) #else /* Blank functions if the DMA engine is not available */ -static inline void pl011_dma_probe(struct device *dev, struct uart_amba_port *uap) +static inline void pl011_dma_probe(struct uart_amba_port *uap) { } @@ -2218,7 +2182,6 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id) uap->port.ops = &amba_pl011_pops; uap->port.flags = UPF_BOOT_AUTOCONF; uap->port.line = i; - pl011_dma_probe(&dev->dev, uap); /* Ensure interrupts from this UART are masked and cleared */ writew(0, uap->port.membase + UART011_IMSC); @@ -2233,7 +2196,8 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id) if (!amba_reg.state) { ret = uart_register_driver(&amba_reg); if (ret < 0) { - pr_err("Failed to register AMBA-PL011 driver\n"); + dev_err(&dev->dev, + "Failed to register AMBA-PL011 driver\n"); return ret; } } @@ -2242,7 +2206,6 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id) if (ret) { amba_ports[i] = NULL; uart_unregister_driver(&amba_reg); - pl011_dma_remove(uap); } return ret;