Received: by 2002:a05:6a10:5bc5:0:0:0:0 with SMTP id os5csp1332509pxb; Tue, 26 Oct 2021 07:10:59 -0700 (PDT) X-Google-Smtp-Source: ABdhPJyfbx2U5+F3W6A7kWQjImKBm/ynUUQqHgbNtHEn0KqYtKLuKWn+kPm1RGYisLbmX43gBeqL X-Received: by 2002:a63:9b0a:: with SMTP id r10mr18784185pgd.389.1635257459112; Tue, 26 Oct 2021 07:10:59 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1635257459; cv=none; d=google.com; s=arc-20160816; b=an+prPUTHUSiW5gYuQCi8vkKJ9J1cyy4ZGVdAh8D6rIcvhtgUZfPylqkIz7JlU3XFf NlW2VR+/ygRv8R5aXZh4IzC2alfAFem7G+p+NjPhsYiParbvbxF/misKfmz/tavwuWHp B3BMuwUT4PPOMpHeklAJn9UrYsU4UzZcdlidhOGg1oUyDiSlkW3NXEkMXud6OD6ZX8eD 8oaEs1pNTInfMMao4tC8+lnydsJzxfRgj6Ket+7rpeTrv1S9uiQRNBY37HSqfjkBD0RV sU25zGvfFs0QBYeeDwYFuMw1l4/8zVdBqd416K2UGmXhgXlT0drCB6VdeL6SBP1coYNv pevg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :message-id:date:subject:cc:to:from; bh=fvL0e5e1YlRA4udHcdWe20qIXJsOTeo4/NYrYVuQb24=; b=pKR4sG6QzCBFrHWGJqQYNDtiogBU7wEqcvPL2FpTAEsRjSF/BmXIUGyeHOwDjD8sND u+tRcnAl/7PLJRTVnl6r5HFv9HeHIto7RqypZwqbZYoybcA3wiaWTxchl+4ZcLCZykPw vWyiZ3YFZPQTRFw0Zl/xiV0kSMEnQZjcyOcy8kzL7A8jA9ewTfiKujzLRTggPPGbdA7y EKSlBdAvuZwe3nED9eNhtgQSTgDaEREru1bCnEqhUncysMuGKy/iM9Cvv+EzuKWlHsm6 ylubmrLU+UTHnhhgRTvt2ihCBShx79BEPYLb+B1uDCZ3oP5/NMnG3XsTtmGh6UgYUsny tyFg== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=bitwise.fi Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id o9si12959883pgq.146.2021.10.26.07.10.45; Tue, 26 Oct 2021 07:10:59 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=bitwise.fi Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234449AbhJZKio (ORCPT + 99 others); Tue, 26 Oct 2021 06:38:44 -0400 Received: from mail.bitwise.fi ([109.204.228.163]:58476 "EHLO mail.bitwise.fi" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234330AbhJZKiS (ORCPT ); Tue, 26 Oct 2021 06:38:18 -0400 X-Greylist: delayed 380 seconds by postgrey-1.27 at vger.kernel.org; Tue, 26 Oct 2021 06:38:10 EDT Received: from localhost (localhost [127.0.0.1]) by mail.bitwise.fi (Postfix) with ESMTP id 175E9460029; Tue, 26 Oct 2021 13:29:15 +0300 (EEST) X-Virus-Scanned: Debian amavisd-new at Received: from mail.bitwise.fi ([127.0.0.1]) by localhost (mustetatti.dmz.bitwise.fi [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id SmpeHPaUqtwC; Tue, 26 Oct 2021 13:29:09 +0300 (EEST) Received: from localhost.net (fw1.dmz.bitwise.fi [192.168.69.1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: anssiha) by mail.bitwise.fi (Postfix) with ESMTPSA id B9E01460026; Tue, 26 Oct 2021 13:29:09 +0300 (EEST) From: Anssi Hannula To: Michal Simek Cc: linux-serial@vger.kernel.org, Greg Kroah-Hartman , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org Subject: [PATCH] serial: xilinx_uartps: Fix race condition causing stuck TX Date: Tue, 26 Oct 2021 13:27:41 +0300 Message-Id: <20211026102741.2910441-1-anssi.hannula@bitwise.fi> X-Mailer: git-send-email 2.31.1 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org xilinx_uartps .start_tx() clears TXEMPTY when enabling TXEMPTY to avoid any previous TXEVENT event asserting the UART interrupt. This clear operation is done immediately after filling the TX FIFO. However, if the bytes inserted by cdns_uart_handle_tx() are consumed by the UART before the TXEMPTY is cleared, the clear operation eats the new TXEMPTY event as well, causing cdns_uart_isr() to never receive the TXEMPTY event. If there are bytes still queued in circbuf, TX will get stuck as they will never get transferred to FIFO (unless new bytes are queued to circbuf in which case .start_tx() is called again). While the racy missed TXEMPTY occurs fairly often with short data sequences (e.g. write 1 byte), in those cases circbuf is usually empty so no action on TXEMPTY would have been needed anyway. On the other hand, longer data sequences make the race much more unlikely as UART takes longer to consume the TX FIFO. Therefore it is rare for this race to cause visible issues in general. Fix the race by clearing the TXEMPTY bit in ISR *before* filling the FIFO. The TXEMPTY bit in ISR will only get asserted at the exact moment the TX FIFO *becomes* empty, so clearing the bit before filling FIFO does not cause an extra immediate assertion even if the FIFO is initially empty. This is hard to reproduce directly on a normal system, but inserting e.g. udelay(200) after cdns_uart_handle_tx(port), setting 4000000 baud, and then running "dd if=/dev/zero bs=128 of=/dev/ttyPS0 count=50" reliably reproduces the issue on my ZynqMP test system unless this fix is applied. Fixes: 85baf542d54e ("tty: xuartps: support 64 byte FIFO size") Signed-off-by: Anssi Hannula --- drivers/tty/serial/xilinx_uartps.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c index 962e522ccc45..d5e243908d9f 100644 --- a/drivers/tty/serial/xilinx_uartps.c +++ b/drivers/tty/serial/xilinx_uartps.c @@ -601,9 +601,10 @@ static void cdns_uart_start_tx(struct uart_port *port) if (uart_circ_empty(&port->state->xmit)) return; + writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_ISR); + cdns_uart_handle_tx(port); - writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_ISR); /* Enable the TX Empty interrupt */ writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_IER); } -- 2.31.1