Received: by 2002:a25:8b91:0:0:0:0:0 with SMTP id j17csp8289977ybl; Thu, 16 Jan 2020 14:02:01 -0800 (PST) X-Google-Smtp-Source: APXvYqxAIJJGYta23lbJvWLGlrFaoMGY8gYVaRVSv+xMkgqCGjlMYeUlxMNBDtMBJ/1gKzNwhhs1 X-Received: by 2002:a9d:3b09:: with SMTP id z9mr3856176otb.195.1579212120857; Thu, 16 Jan 2020 14:02:00 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1579212120; cv=none; d=google.com; s=arc-20160816; b=lCsj6WUO/8yXEriSGdG6Q9XOG5h8fAhnucez93JhHBYHu1kgBnE4OZ81SZNmHM4ZEB g+hG98J75MDdNpDdJlSugHVrXsu7Wv09oZW1m0moZluqJO7mC3bwX7uOyA9/qkqW3+Oi /3N0haGA8R6kzbGevxOpplWV3EWOTcd9vUpw4aZFxslLSwABq95crU6EIfJzmOG5/4Jg mTJzasEu3nVcXgRAKddF4m+xtr6WlQ6aDQkdMigkkNFufHwlJx5ybSwaIfiy7pocAf8u hzYrhUjgr6At9E+tyi6nbij2mCcF/aIOdpjp1Wgc50d0h6ZGDVA5N0bvVlrO1pFffZDh XSiw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=1Vs7qgOewA7k5EE6JifpfJiI5meQKx76cs+LQ/Q/1wY=; b=mgG+GB/YlPunb+FICqkLor+P0RCht54eJBJ50FFeu4WzOTT//XtIGgb5G8Q5E7rnjP m+YAuEYEX34WsyuuuqeipA07WPfY6JmQl1tnXS/2XMXZ+w8wpNR6mLMFWE9L+KpatK+n yFLMSMaEC/grCBOezrwe1DbooiuzqILD2oCmvdVefhka5cqtBjL+dCOeP5xGnfHMXO4O qmhgVepM6SJ3+XfRePhsseCmMILKaNj1xmTGOG7zfeNhbapkgRcnrGLLa582VvVRRT6v i3Lrjkgf1ZHiyBFpZGfuvfFeG3FcS7RGkCkoKYN/8a1C/euOZcXsCYZ9RHpe/afXGy1i tbyg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=kExHSSNM; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id w19si7596558oih.201.2020.01.16.14.01.48; Thu, 16 Jan 2020 14:02:00 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=kExHSSNM; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2388162AbgAPRiv (ORCPT + 99 others); Thu, 16 Jan 2020 12:38:51 -0500 Received: from mail.kernel.org ([198.145.29.99]:54044 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1731821AbgAPRiQ (ORCPT ); Thu, 16 Jan 2020 12:38:16 -0500 Received: from sasha-vm.mshome.net (c-73-47-72-35.hsd1.nh.comcast.net [73.47.72.35]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id F0F3D246EF; Thu, 16 Jan 2020 17:38:13 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1579196294; bh=TLArYIutKqupwEtg535b8YL/colwHHdoN9E+nmd9Vkw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=kExHSSNMrplNFcccxf92jvligKKRRPe3j8zldbxMkOuq59Vf0c+VhRvkcK8nQJf6V 1S1UiQrc3WvnTp3qho43vHnDRSs9LVBpKnOIgXA9Q9EBc9Ms4+WMvV0+qQos7rciSX WruNelRI+O75RpCaJNxKCIjRXNXCm57AsQc66qXs= From: Sasha Levin To: linux-kernel@vger.kernel.org, stable@vger.kernel.org Cc: Sowjanya Komatineni , Mark Brown , Sasha Levin , linux-spi@vger.kernel.org, linux-tegra@vger.kernel.org Subject: [PATCH AUTOSEL 4.9 108/251] spi: tegra114: fix for unpacked mode transfers Date: Thu, 16 Jan 2020 12:34:17 -0500 Message-Id: <20200116173641.22137-68-sashal@kernel.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200116173641.22137-1-sashal@kernel.org> References: <20200116173641.22137-1-sashal@kernel.org> MIME-Version: 1.0 X-stable: review X-Patchwork-Hint: Ignore Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Sowjanya Komatineni [ Upstream commit 1a89ac5b91895127f7c586ec5075c3753ca25501 ] Fixes: computation of actual bytes to fill/receive in/from FIFO in unpacked mode when transfer length is not a multiple of requested bits per word. unpacked mode transfers fails when the transfer includes partial bytes in the last word. Total words to be written/read to/from FIFO is computed based on transfer length and bits per word. Unpacked mode includes 0 padding bytes for partial words to align with bits per word and these extra bytes are also accounted for calculating bytes left to transfer in the current driver. This causes extra bytes access of tx/rx buffers along with buffer index position crossing actual length where remain_len becomes negative and due to unsigned type, negative value is a 32 bit representation of signed value and transferred bytes never meets the actual transfer length resulting in transfer timeout and a hang. This patch fixes this with proper computation of the actual bytes to fill in FIFO during transmit and the actual bytes to read from FIFO during receive ignoring 0 padded bytes. Signed-off-by: Sowjanya Komatineni Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- drivers/spi/spi-tegra114.c | 43 +++++++++++++++++++++++++++++++------- 1 file changed, 36 insertions(+), 7 deletions(-) diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c index d98c502a9c47..e37712bed0b2 100644 --- a/drivers/spi/spi-tegra114.c +++ b/drivers/spi/spi-tegra114.c @@ -307,10 +307,16 @@ static unsigned tegra_spi_fill_tx_fifo_from_client_txbuf( x |= (u32)(*tx_buf++) << (i * 8); tegra_spi_writel(tspi, x, SPI_TX_FIFO); } + + tspi->cur_tx_pos += written_words * tspi->bytes_per_word; } else { + unsigned int write_bytes; max_n_32bit = min(tspi->curr_dma_words, tx_empty_count); written_words = max_n_32bit; nbytes = written_words * tspi->bytes_per_word; + if (nbytes > t->len - tspi->cur_pos) + nbytes = t->len - tspi->cur_pos; + write_bytes = nbytes; for (count = 0; count < max_n_32bit; count++) { u32 x = 0; @@ -319,8 +325,10 @@ static unsigned tegra_spi_fill_tx_fifo_from_client_txbuf( x |= (u32)(*tx_buf++) << (i * 8); tegra_spi_writel(tspi, x, SPI_TX_FIFO); } + + tspi->cur_tx_pos += write_bytes; } - tspi->cur_tx_pos += written_words * tspi->bytes_per_word; + return written_words; } @@ -344,20 +352,27 @@ static unsigned int tegra_spi_read_rx_fifo_to_client_rxbuf( for (i = 0; len && (i < 4); i++, len--) *rx_buf++ = (x >> i*8) & 0xFF; } - tspi->cur_rx_pos += tspi->curr_dma_words * tspi->bytes_per_word; read_words += tspi->curr_dma_words; + tspi->cur_rx_pos += tspi->curr_dma_words * tspi->bytes_per_word; } else { u32 rx_mask = ((u32)1 << t->bits_per_word) - 1; + u8 bytes_per_word = tspi->bytes_per_word; + unsigned int read_bytes; + len = rx_full_count * bytes_per_word; + if (len > t->len - tspi->cur_pos) + len = t->len - tspi->cur_pos; + read_bytes = len; for (count = 0; count < rx_full_count; count++) { u32 x = tegra_spi_readl(tspi, SPI_RX_FIFO) & rx_mask; - for (i = 0; (i < tspi->bytes_per_word); i++) + for (i = 0; len && (i < bytes_per_word); i++, len--) *rx_buf++ = (x >> (i*8)) & 0xFF; } - tspi->cur_rx_pos += rx_full_count * tspi->bytes_per_word; read_words += rx_full_count; + tspi->cur_rx_pos += read_bytes; } + return read_words; } @@ -372,12 +387,17 @@ static void tegra_spi_copy_client_txbuf_to_spi_txbuf( unsigned len = tspi->curr_dma_words * tspi->bytes_per_word; memcpy(tspi->tx_dma_buf, t->tx_buf + tspi->cur_pos, len); + tspi->cur_tx_pos += tspi->curr_dma_words * tspi->bytes_per_word; } else { unsigned int i; unsigned int count; u8 *tx_buf = (u8 *)t->tx_buf + tspi->cur_tx_pos; unsigned consume = tspi->curr_dma_words * tspi->bytes_per_word; + unsigned int write_bytes; + if (consume > t->len - tspi->cur_pos) + consume = t->len - tspi->cur_pos; + write_bytes = consume; for (count = 0; count < tspi->curr_dma_words; count++) { u32 x = 0; @@ -386,8 +406,9 @@ static void tegra_spi_copy_client_txbuf_to_spi_txbuf( x |= (u32)(*tx_buf++) << (i * 8); tspi->tx_dma_buf[count] = x; } + + tspi->cur_tx_pos += write_bytes; } - tspi->cur_tx_pos += tspi->curr_dma_words * tspi->bytes_per_word; /* Make the dma buffer to read by dma */ dma_sync_single_for_device(tspi->dev, tspi->tx_dma_phys, @@ -405,20 +426,28 @@ static void tegra_spi_copy_spi_rxbuf_to_client_rxbuf( unsigned len = tspi->curr_dma_words * tspi->bytes_per_word; memcpy(t->rx_buf + tspi->cur_rx_pos, tspi->rx_dma_buf, len); + tspi->cur_rx_pos += tspi->curr_dma_words * tspi->bytes_per_word; } else { unsigned int i; unsigned int count; unsigned char *rx_buf = t->rx_buf + tspi->cur_rx_pos; u32 rx_mask = ((u32)1 << t->bits_per_word) - 1; + unsigned consume = tspi->curr_dma_words * tspi->bytes_per_word; + unsigned int read_bytes; + if (consume > t->len - tspi->cur_pos) + consume = t->len - tspi->cur_pos; + read_bytes = consume; for (count = 0; count < tspi->curr_dma_words; count++) { u32 x = tspi->rx_dma_buf[count] & rx_mask; - for (i = 0; (i < tspi->bytes_per_word); i++) + for (i = 0; consume && (i < tspi->bytes_per_word); + i++, consume--) *rx_buf++ = (x >> (i*8)) & 0xFF; } + + tspi->cur_rx_pos += read_bytes; } - tspi->cur_rx_pos += tspi->curr_dma_words * tspi->bytes_per_word; /* Make the dma buffer to read by dma */ dma_sync_single_for_device(tspi->dev, tspi->rx_dma_phys, -- 2.20.1