From patchwork Mon Feb 23 20:16:39 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: 5868071 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 85A04BF440 for ; Mon, 23 Feb 2015 20:19:50 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 896CC2064B for ; Mon, 23 Feb 2015 20:19:49 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 9032F20644 for ; Mon, 23 Feb 2015 20:19:48 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1YPzRW-0006Nf-Rq; Mon, 23 Feb 2015 20:17:26 +0000 Received: from mail-qc0-f173.google.com ([209.85.216.173]) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1YPzRQ-0006JL-SK for linux-arm-kernel@lists.infradead.org; Mon, 23 Feb 2015 20:17:22 +0000 Received: by qcwb13 with SMTP id b13so13131301qcw.7 for ; Mon, 23 Feb 2015 12:16:52 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:subject:date:message-id; bh=g+cnjmkqr/ePEGAfGY2PLTGrIc9bzwTBv2O48yHWlhw=; b=QBHy52wGVw/dIxrtHlLoPW2nHxCaTLpcO39ov2eXsg6/26h3iMrqKYCmeIVnE6CoWj dJBEFC9sK7axW/GQda5vPljWX9cffDs3Xk0TLO/kMeSP3s2dL0Wj1o+JOcgXmeG2gjy3 4ZOUFRB6cTKPQc+C9Ao5RUV8d5O61gEvvu2Ge86SZZujNVwE1fVxa5lM0jy1BcDZ5a7r jgv99nblw30ecXphw7kP3t9yWSXuer/axtt6mkA2JKl3EN4KmyiaU7nDmFqR7Sxyesax /jaHzLA3w87YyZQU2RRaM5uR/OufMDiJkeN26O8zrfIlCW3PFduQJ+n30kPqo+PkjdaB ifQA== X-Gm-Message-State: ALoCoQlb2Z+FFJFhGGM6iHoB4eSvnVIDLcbQmeuWqgHfyrXOFFgduAOnhhPAvdhjCaLf3Yj/1mlS X-Received: by 10.140.44.134 with SMTP id g6mr26759597qga.85.1424722611898; Mon, 23 Feb 2015 12:16:51 -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 d19sm18117565qhc.42.2015.02.23.12.16.50 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 23 Feb 2015 12:16:51 -0800 (PST) From: Jorge Ramirez-Ortiz To: jorge.ramirez-ortiz@linaro.org, linux@arm.linux.org.uk, linux-arm-kernel@lists.infradead.org, robh@kernel.org Subject: [PATCH] drivers/tty: amba-pl011: defer driver probing if external dma is not ready. Date: Mon, 23 Feb 2015 15:16:39 -0500 Message-Id: <1424722599-9215-1-git-send-email-jorge.ramirez-ortiz@linaro.org> X-Mailer: git-send-email 1.9.1 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20150223_121722_271582_72831B8F X-CRM114-Status: GOOD ( 19.32 ) X-Spam-Score: -0.7 (/) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-4.2 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP This patch addresses 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 an hisi_6220 SoC (HiKey board from Linaro). The proposed implementation uses deferred driver probing to wait for the DMA controller to be registered. Signed-off-by: Jorge Ramirez-Ortiz --- drivers/tty/serial/amba-pl011.c | 70 +++++++++++------------------------------ 1 file changed, 18 insertions(+), 52 deletions(-) diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 8d94c19..40219e5 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -29,6 +29,7 @@ * and hooked into this driver. */ +#define pr_fmt(fmt) "amba-pl011: "fmt #if defined(CONFIG_SERIAL_AMBA_PL011_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) #define SUPPORT_SYSRQ @@ -261,7 +262,7 @@ 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 int pl011_dma_probe(struct device *dev, 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); @@ -275,13 +276,17 @@ 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"); + chan = dma_request_slave_channel_reason(dev, "tx"); + if (IS_ERR(chan)) { + + /* the dma driver has not been initialized yet */ + if (PTR_ERR(chan) == -EPROBE_DEFER) + return -EPROBE_DEFER; - if (!chan) { /* We need platform data */ if (!plat || !plat->dma_filter) { dev_info(uap->port.dev, "no DMA platform data\n"); - return; + return 0; } /* Try to acquire a generic DMA engine slave TX channel */ @@ -292,7 +297,7 @@ static void pl011_dma_probe_initcall(struct device *dev, struct uart_amba_port * plat->dma_tx_param); if (!chan) { dev_err(uap->port.dev, "no TX DMA channel!\n"); - return; + return 0; } } @@ -310,7 +315,7 @@ static void pl011_dma_probe_initcall(struct device *dev, struct uart_amba_port * if (!chan) { dev_err(uap->port.dev, "no RX DMA channel!\n"); - return; + return 0; } } @@ -383,54 +388,10 @@ static void pl011_dma_probe_initcall(struct device *dev, struct uart_amba_port * dev_info(uap->port.dev, "DMA channel RX %s\n", dma_chan_name(uap->dmarx.chan)); } -} - -#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 */ @@ -1142,8 +1103,9 @@ 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 int pl011_dma_probe(struct device *dev, struct uart_amba_port *uap) { + return 0; } static inline void pl011_dma_remove(struct uart_amba_port *uap) @@ -2218,7 +2180,11 @@ 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); + ret = pl011_dma_probe(&dev->dev, uap); + if (ret) { + devm_kfree(&dev->dev, uap); + return ret; + } /* Ensure interrupts from this UART are masked and cleared */ writew(0, uap->port.membase + UART011_IMSC);