From patchwork Tue Feb 24 03:46:53 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: 44925 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-wg0-f69.google.com (mail-wg0-f69.google.com [74.125.82.69]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id 0D62B2029F for ; Tue, 24 Feb 2015 03:49:06 +0000 (UTC) Received: by wggy19 with SMTP id y19sf1778363wgg.1 for ; Mon, 23 Feb 2015 19:49:05 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:delivered-to:from:to:subject:date:message-id :in-reply-to:references:precedence:list-id:list-unsubscribe :list-archive:list-post:list-help:list-subscribe:mime-version :content-type:content-transfer-encoding:sender:errors-to :x-original-sender:x-original-authentication-results:mailing-list; bh=vk+zhrtL8js3FlzdKrBaj6lYEIPMeJr9KDruqP2+j54=; b=M4HtXAExyiYnTcplRmZVC38TLBgi9NpzjGPsymUTjhdnlkCtx99qxPwJBQy7XDtIt3 RvE9CQEhfmw+Y9gnKIVcGYoefsG/p4zba8mVnXXeP2iv5v3Gk3TFVO6qRgapAC/ITjrL ULhnOAIDTOlIttFuKPrCjk2bZf0GfhDLJzm7yHNYIMS4O+Ut1bP40Ol476JqIoz/sca+ DBqNhDgayTHD7yOKFMRjbm3kkjgZigGUwE55qdJ0hDNPWjLk05ijdz54hEjs6Vsy6MIe Bl+6GnTapAVzH5pJ6S940XoDZRTDhVQScLyM5p5L7fAy4BoYxlsVR19QUxWPdNbqTY8f bOqg== X-Gm-Message-State: ALoCoQkJo+3yT9XHO4xxnHyiU+snMznI7bQNlW0Bga6kqSIjkveLEpz9T/WPABbwE9BLRCBC352x X-Received: by 10.152.4.229 with SMTP id n5mr1777235lan.1.1424749745279; Mon, 23 Feb 2015 19:49:05 -0800 (PST) X-BeenThere: patchwork-forward@linaro.org Received: by 10.152.36.232 with SMTP id t8ls614784laj.100.gmail; Mon, 23 Feb 2015 19:49:05 -0800 (PST) X-Received: by 10.112.162.42 with SMTP id xx10mr12514273lbb.6.1424749745138; Mon, 23 Feb 2015 19:49:05 -0800 (PST) Received: from mail-lb0-f169.google.com (mail-lb0-f169.google.com. [209.85.217.169]) by mx.google.com with ESMTPS id ay10si27440178lab.8.2015.02.23.19.49.05 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 23 Feb 2015 19:49:05 -0800 (PST) Received-SPF: pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.217.169 as permitted sender) client-ip=209.85.217.169; Received: by lbjb6 with SMTP id b6so22457820lbj.2 for ; Mon, 23 Feb 2015 19:49:05 -0800 (PST) X-Received: by 10.112.57.139 with SMTP id i11mr12637750lbq.106.1424749745009; Mon, 23 Feb 2015 19:49:05 -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 h5csp1664124lbj; Mon, 23 Feb 2015 19:49:04 -0800 (PST) X-Received: by 10.70.127.196 with SMTP id ni4mr25530166pdb.29.1424749743107; Mon, 23 Feb 2015 19:49:03 -0800 (PST) Received: from bombadil.infradead.org (bombadil.infradead.org. [2001:1868:205::9]) by mx.google.com with ESMTPS id e17si6248881pdm.59.2015.02.23.19.49.02 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 23 Feb 2015 19:49:03 -0800 (PST) Received-SPF: none (google.com: linux-arm-kernel-bounces+patch=linaro.org@lists.infradead.org does not designate permitted sender hosts) client-ip=2001:1868:205::9; 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 1YQ6T3-0000Um-M4; Tue, 24 Feb 2015 03:47:29 +0000 Received: from mail-qg0-f51.google.com ([209.85.192.51]) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1YQ6Sy-0000Np-9h for linux-arm-kernel@lists.infradead.org; Tue, 24 Feb 2015 03:47:25 +0000 Received: by mail-qg0-f51.google.com with SMTP id z60so28061341qgd.10 for ; Mon, 23 Feb 2015 19:47:02 -0800 (PST) X-Received: by 10.140.48.133 with SMTP id o5mr31468188qga.8.1424749622583; Mon, 23 Feb 2015 19:47:02 -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 v76sm6869356qge.18.2015.02.23.19.47.01 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 23 Feb 2015 19:47:02 -0800 (PST) From: Jorge Ramirez-Ortiz To: jorge.ramirez-ortiz@linaro.org, linux-arm-kernel@lists.infradead.org, robh@kernel.org, viresh.kumar@linaro.org, linux@arm.linux.org.uk Subject: [PATCH] drivers/tty: amba-pl011: defer driver probing if external dma is not ready. Date: Mon, 23 Feb 2015 22:46:53 -0500 Message-Id: <1424749613-24765-2-git-send-email-jorge.ramirez-ortiz@linaro.org> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1424749613-24765-1-git-send-email-jorge.ramirez-ortiz@linaro.org> References: <1424749613-24765-1-git-send-email-jorge.ramirez-ortiz@linaro.org> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20150223_194724_453848_EB7E3714 X-CRM114-Status: GOOD ( 20.70 ) X-Spam-Score: -0.7 (/) X-Spam-Report: SpamAssassin version 3.4.0 on bombadil.infradead.org summary: Content analysis details: (-0.7 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.7 RCVD_IN_DNSWL_LOW RBL: Sender listed at http://www.dnswl.org/, low trust [209.85.192.51 listed in list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record -0.0 RCVD_IN_MSPIKE_H2 RBL: Average reputation (+2) [209.85.192.51 listed in wl.mailspike.net] 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+patch=linaro.org@lists.infradead.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.217.169 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 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 for OF and ACPI uses deferred driver probing to wait for the DMA controller to be registered. It defaults to legacy behaviour when platform data is present. Signed-off-by: Jorge Ramirez-Ortiz --- drivers/tty/serial/amba-pl011.c | 67 ++++++++++++++++++++++++++--------------- 1 file changed, 43 insertions(+), 24 deletions(-) diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 8d94c19..d631a0a 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,8 @@ 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, + void (*queue_dma_probe)(struct device *, struct uart_amba_port *)) { /* DMA is the sole user of the platform data right now */ struct amba_pl011_data *plat = dev_get_platdata(uap->port.dev); @@ -275,15 +277,23 @@ 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"); + if (queue_dma_probe && plat && plat->dma_filter) { + (*queue_dma_probe)(dev, uap); + return 0; + } + + 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 */ dma_cap_zero(mask); dma_cap_set(DMA_SLAVE, mask); @@ -292,7 +302,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 +320,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,14 +393,16 @@ 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)); } + + return 0; } -#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. + * On platforms with no OF or ACPI support, we stack up the UARTs and let the + * below initcall be done at late 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; @@ -400,22 +412,23 @@ struct dma_uap { static LIST_HEAD(pl011_dma_uarts); -static int __init pl011_dma_initcall(void) +static int __init pl011_dequeue_dma_probe_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); + pl011_dma_probe(dmau->dev, dmau->uap, NULL); list_del(node); kfree(dmau); } return 0; } -device_initcall(pl011_dma_initcall); +late_initcall_sync(pl011_dequeue_dma_probe_initcall); -static void pl011_dma_probe(struct device *dev, struct uart_amba_port *uap) +static void pl011_queue_dma_probe(struct device *dev, + struct uart_amba_port *uap) { struct dma_uap *dmau = kzalloc(sizeof(struct dma_uap), GFP_KERNEL); if (dmau) { @@ -424,12 +437,6 @@ static void pl011_dma_probe(struct device *dev, struct uart_amba_port *uap) 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) { @@ -1142,7 +1149,14 @@ 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, + void (*queue_dma_probe)(struct device *, struct uart_amba_port *)) +{ + return 0; +} + +static void pl011_queue_dma_probe(struct device *dev, + struct uart_amba_port *uap) { } @@ -2218,7 +2232,12 @@ 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, &pl011_queue_dma_probe); + if (ret == -EPROBE_DEFER) { + devm_kfree(&dev->dev, uap); + return ret; + } /* Ensure interrupts from this UART are masked and cleared */ writew(0, uap->port.membase + UART011_IMSC);