[][OpenWrt Dev][Force RX buffer DMA aligned]
[Description]
Fix buffer which isn't cache-line aligned
1. If upper filesystem passes buffer which is not cache-line
aligned, we allocate local buffer to catch data.
2. For data in length of more than 0x10000 bytes, we'll split
it into two packets. However, if the second packet isn't
dma-aligned, we'll encounter problems when transferring
the second packet. So we force both packets' buffer dma-aligned.
[Release-log]
N/A
Change-Id: I356a60ce2cd65796310052320ce0022506e723e0
Reviewed-on: https://gerrit.mediatek.inc/c/openwrt/feeds/mtk_openwrt_feeds/+/4531801
diff --git a/target/linux/mediatek/patches-5.4/0670-fix-SPIM-dma-buffer-not-aligned.patch b/target/linux/mediatek/patches-5.4/0670-fix-SPIM-dma-buffer-not-aligned.patch
new file mode 100644
index 0000000..d4534e7
--- /dev/null
+++ b/target/linux/mediatek/patches-5.4/0670-fix-SPIM-dma-buffer-not-aligned.patch
@@ -0,0 +1,81 @@
+--- a/drivers/spi/spi-mt65xx.c
++++ b/drivers/spi/spi-mt65xx.c
+@@ -184,7 +184,7 @@ static const struct mtk_spi_compatible m
+ */
+ static const struct mtk_chip_config mtk_default_chip_info = {
+ .sample_sel = 0,
+- .get_tick_dly = 0,
++ .get_tick_dly = 1,
+ };
+
+ static const struct of_device_id mtk_spi_of_match[] = {
+@@ -730,8 +730,11 @@ static int mtk_spi_mem_adjust_op_size(st
+
+ if (op->data.dir != SPI_MEM_NO_DATA) {
+ opcode_len = 1 + op->addr.nbytes + op->dummy.nbytes;
+- if (opcode_len + op->data.nbytes > MTK_SPI_IPM_PACKET_SIZE)
++ if (opcode_len + op->data.nbytes > MTK_SPI_IPM_PACKET_SIZE) {
+ op->data.nbytes = MTK_SPI_IPM_PACKET_SIZE -opcode_len;
++ /* force data buffer dma-aligned. */
++ op->data.nbytes -= op->data.nbytes % 4;
++ }
+ }
+
+ return 0;
+@@ -758,10 +761,6 @@ static bool mtk_spi_mem_supports_op(stru
+ return false;
+ }
+
+- if (op->data.dir == SPI_MEM_DATA_IN &&
+- !IS_ALIGNED((size_t)op->data.buf.in, 4))
+- return false;
+-
+ return true;
+ }
+
+@@ -820,6 +819,7 @@ static int mtk_spi_mem_exec_op(struct sp
+ struct mtk_spi *mdata = spi_master_get_devdata(mem->spi->master);
+ u32 reg_val, nio = 1, tx_size;
+ char *tx_tmp_buf;
++ char *rx_tmp_buf;
+ int ret = 0;
+
+ mdata->use_spimem = true;
+@@ -914,10 +914,18 @@ static int mtk_spi_mem_exec_op(struct sp
+ }
+
+ if (op->data.dir == SPI_MEM_DATA_IN) {
++ if(!IS_ALIGNED((size_t)op->data.buf.in, 4)) {
++ rx_tmp_buf = kzalloc(op->data.nbytes, GFP_KERNEL | GFP_DMA);
++ if (!rx_tmp_buf)
++ return -ENOMEM;
++ }
++ else
++ rx_tmp_buf = op->data.buf.in;
++
+ mdata->rx_dma = dma_map_single(mdata->dev,
+- op->data.buf.in,
+- op->data.nbytes,
+- DMA_FROM_DEVICE);
++ rx_tmp_buf,
++ op->data.nbytes,
++ DMA_FROM_DEVICE);
+ if (dma_mapping_error(mdata->dev, mdata->rx_dma)) {
+ ret = -ENOMEM;
+ goto unmap_tx_dma;
+@@ -947,9 +955,14 @@ static int mtk_spi_mem_exec_op(struct sp
+ writel(reg_val, mdata->base + SPI_CMD_REG);
+
+ unmap_rx_dma:
+- if (op->data.dir == SPI_MEM_DATA_IN)
++ if (op->data.dir == SPI_MEM_DATA_IN) {
++ if(!IS_ALIGNED((size_t)op->data.buf.in, 4)) {
++ memcpy(op->data.buf.in, rx_tmp_buf, op->data.nbytes);
++ kfree(rx_tmp_buf);
++ }
+ dma_unmap_single(mdata->dev, mdata->rx_dma,
+ op->data.nbytes, DMA_FROM_DEVICE);
++ }
+ unmap_tx_dma:
+ dma_unmap_single(mdata->dev, mdata->tx_dma,
+ tx_size, DMA_TO_DEVICE);