codecs: wcd_spi: do not use on-stack memory for any transfers

Currently, for some small (1/4/8 bytes) transfers, the driver uses
on-stack memory to perform the transfer. This is not safe as the
underlying master/dma driver could try to map/dma this memory.
Change makes sure to never use on-stack memory for any transfers.

Change-Id: I6b157e26ea7ca9f865004a87153c658756f6c368
Signed-off-by: Bhalchandra Gajare <gajare@codeaurora.org>
Signed-off-by: Xiaoyu Ye <benyxy@codeaurora.org>
diff --git a/asoc/codecs/wcd-spi.c b/asoc/codecs/wcd-spi.c
index a25c9a6..bb93334 100644
--- a/asoc/codecs/wcd-spi.c
+++ b/asoc/codecs/wcd-spi.c
@@ -242,6 +242,7 @@
 	struct spi_transfer *tx_xfer = &wcd_spi->xfer2[0];
 	struct spi_transfer *rx_xfer = &wcd_spi->xfer2[1];
 	u8 *tx_buf = wcd_spi->tx_buf;
+	u8 *rx_buf = wcd_spi->rx_buf;
 	u32 frame = 0;
 	int ret;
 
@@ -264,10 +265,15 @@
 	tx_xfer->len = WCD_SPI_READ_SINGLE_LEN;
 
 	wcd_spi_reinit_xfer(rx_xfer);
-	rx_xfer->rx_buf = val;
+	rx_xfer->rx_buf = rx_buf;
 	rx_xfer->len = sizeof(*val);
 
 	ret = spi_sync(spi, &wcd_spi->msg2);
+	if (ret)
+		dev_err(&spi->dev, "%s: spi_sync failed, err %d\n",
+			__func__, ret);
+	else
+		memcpy((u8*) val, rx_buf, sizeof(*val));
 
 	return ret;
 }
@@ -319,22 +325,22 @@
 {
 	struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi);
 	struct spi_transfer *xfer = &wcd_spi->xfer1;
-	u8 buf[WCD_SPI_WRITE_SINGLE_LEN];
+	u8 *tx_buf = wcd_spi->tx_buf;
 	u32 frame = 0;
 
 	dev_dbg(&spi->dev, "%s: remote_addr = 0x%x, val = 0x%x\n",
 		__func__, remote_addr, val);
 
-	memset(buf, 0, WCD_SPI_WRITE_SINGLE_LEN);
+	memset(tx_buf, 0, WCD_SPI_WRITE_SINGLE_LEN);
 	frame |= WCD_SPI_WRITE_FRAME_OPCODE;
 	frame |= (remote_addr & WCD_CMD_ADDR_MASK);
 
 	frame = cpu_to_be32(frame);
-	memcpy(buf, &frame, sizeof(frame));
-	memcpy(buf + sizeof(frame), &val, sizeof(val));
+	memcpy(tx_buf, &frame, sizeof(frame));
+	memcpy(tx_buf + sizeof(frame), &val, sizeof(val));
 
 	wcd_spi_reinit_xfer(xfer);
-	xfer->tx_buf = buf;
+	xfer->tx_buf = tx_buf;
 	xfer->len = WCD_SPI_WRITE_SINGLE_LEN;
 
 	return spi_sync(spi, &wcd_spi->msg1);
@@ -487,21 +493,26 @@
 
 static int wcd_spi_cmd_nop(struct spi_device *spi)
 {
-	u8 nop = WCD_SPI_CMD_NOP;
+	struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi);
+	u8 *tx_buf = wcd_spi->tx_buf;
 
-	return spi_write(spi, &nop, WCD_SPI_CMD_NOP_LEN);
+	tx_buf[0] = WCD_SPI_CMD_NOP;
+
+	return spi_write(spi, tx_buf, WCD_SPI_CMD_NOP_LEN);
 }
 
 static int wcd_spi_cmd_clkreq(struct spi_device *spi)
 {
 	struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi);
 	struct spi_transfer *xfer = &wcd_spi->xfer1;
+	u8 *tx_buf = wcd_spi->tx_buf;
 	u8 cmd[WCD_SPI_CMD_CLKREQ_LEN] = {
 		WCD_SPI_CMD_CLKREQ,
 		0xBA, 0x80, 0x00};
 
+	memcpy(tx_buf, cmd, WCD_SPI_CMD_CLKREQ_LEN);
 	wcd_spi_reinit_xfer(xfer);
-	xfer->tx_buf = cmd;
+	xfer->tx_buf = tx_buf;
 	xfer->len = WCD_SPI_CMD_CLKREQ_LEN;
 	xfer->delay_usecs = WCD_SPI_CLKREQ_DELAY_USECS;
 
@@ -510,9 +521,12 @@
 
 static int wcd_spi_cmd_wr_en(struct spi_device *spi)
 {
-	u8 wr_en = WCD_SPI_CMD_WREN;
+	struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi);
+	u8 *tx_buf = wcd_spi->tx_buf;
 
-	return spi_write(spi, &wr_en, WCD_SPI_CMD_WREN_LEN);
+	tx_buf[0] = WCD_SPI_CMD_WREN;
+
+	return spi_write(spi, tx_buf, WCD_SPI_CMD_WREN_LEN);
 }
 
 static int wcd_spi_cmd_rdsr(struct spi_device *spi,
@@ -521,19 +535,19 @@
 	struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi);
 	struct spi_transfer *tx_xfer = &wcd_spi->xfer2[0];
 	struct spi_transfer *rx_xfer = &wcd_spi->xfer2[1];
-	u8 rdsr_cmd;
-	u32 status = 0;
+	u8 *tx_buf = wcd_spi->tx_buf;
+	u8 *rx_buf = wcd_spi->rx_buf;
 	int ret;
 
-	rdsr_cmd = WCD_SPI_CMD_RDSR;
+	tx_buf[0] = WCD_SPI_CMD_RDSR;
 	wcd_spi_reinit_xfer(tx_xfer);
-	tx_xfer->tx_buf = &rdsr_cmd;
-	tx_xfer->len = sizeof(rdsr_cmd);
+	tx_xfer->tx_buf = tx_buf;
+	tx_xfer->len = WCD_SPI_OPCODE_LEN;
 
-
+	memset(rx_buf, 0, sizeof(*rdsr_status));
 	wcd_spi_reinit_xfer(rx_xfer);
-	rx_xfer->rx_buf = &status;
-	rx_xfer->len = sizeof(status);
+	rx_xfer->rx_buf = rx_buf;
+	rx_xfer->len = sizeof(*rdsr_status);
 
 	ret = spi_sync(spi, &wcd_spi->msg2);
 	if (ret < 0) {
@@ -542,10 +556,10 @@
 		goto done;
 	}
 
-	*rdsr_status = be32_to_cpu(status);
+	*rdsr_status = be32_to_cpu(*((u32*)rx_buf));
 
 	dev_dbg(&spi->dev, "%s: RDSR success, value = 0x%x\n",
-		 __func__, *rdsr_status);
+		__func__, *rdsr_status);
 done:
 	return ret;
 }
@@ -1011,7 +1025,7 @@
 	struct device *dev = context;
 	struct spi_device *spi = to_spi_device(dev);
 	struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi);
-	u8 tx_buf[WCD_SPI_CMD_IRW_LEN];
+	u8 *tx_buf = wcd_spi->tx_buf;
 
 	if (!reg || !val || reg_len != wcd_spi->reg_bytes ||
 	    val_len != wcd_spi->val_bytes) {
@@ -1021,9 +1035,10 @@
 		return -EINVAL;
 	}
 
+	memset(tx_buf, 0, WCD_SPI_CMD_IRW_LEN);
 	tx_buf[0] = WCD_SPI_CMD_IRW;
 	tx_buf[1] = *((u8 *)reg);
-	memcpy(&tx_buf[WCD_SPI_OPCODE_LEN + reg_len],
+	memcpy(tx_buf + WCD_SPI_OPCODE_LEN + reg_len,
 	       val, val_len);
 
 	return spi_write(spi, tx_buf, WCD_SPI_CMD_IRW_LEN);
@@ -1057,7 +1072,9 @@
 	struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi);
 	struct spi_transfer *tx_xfer = &wcd_spi->xfer2[0];
 	struct spi_transfer *rx_xfer = &wcd_spi->xfer2[1];
-	u8 tx_buf[WCD_SPI_CMD_IRR_LEN];
+	u8 *tx_buf = wcd_spi->tx_buf;
+	u8 *rx_buf = wcd_spi->rx_buf;
+	int ret = 0;
 
 	if (!reg || !val || reg_len != wcd_spi->reg_bytes ||
 	    val_len != wcd_spi->val_bytes) {
@@ -1067,7 +1084,7 @@
 		return -EINVAL;
 	}
 
-	memset(tx_buf, 0, WCD_SPI_OPCODE_LEN);
+	memset(tx_buf, 0, WCD_SPI_CMD_IRR_LEN);
 	tx_buf[0] = WCD_SPI_CMD_IRR;
 	tx_buf[1] = *((u8 *)reg);
 
@@ -1078,10 +1095,20 @@
 
 	wcd_spi_reinit_xfer(rx_xfer);
 	rx_xfer->tx_buf = NULL;
-	rx_xfer->rx_buf = val;
+	rx_xfer->rx_buf = rx_buf;
 	rx_xfer->len = val_len;
 
-	return spi_sync(spi, &wcd_spi->msg2);
+	ret = spi_sync(spi, &wcd_spi->msg2);
+	if (ret) {
+		dev_err(&spi->dev, "%s: spi_sync failed, err %d\n",
+			__func__, ret);
+		goto done;
+	}
+
+	memcpy(val, rx_buf, val_len);
+
+done:
+	return ret;
 }
 
 static struct regmap_bus wcd_spi_regmap_bus = {