Commit 832c6b18 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'spi-fix-v4.14-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi

Pull spi fixes from Mark Brown:
 "There are a bunch of device specific fixes (more than I'd like, I've
  been lax sending these) plus one important core fix for the conversion
  to use an IDR for bus number allocation which avoids issues with
  collisions when some but not all of the buses in the system have a
  fixed bus number specified.

  The Armada changes are rather large, specificially "spi: armada-3700:
  Fix padding when sending not 4-byte aligned data", but it's a storage
  corruption issue and there's things like indentation changes which
  make it look bigger than it really is. It's been cooking in -next for
  quite a while now and is part of the reason for the delay"

* tag 'spi-fix-v4.14-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi:
  spi: fix IDR collision on systems with both fixed and dynamic SPI bus numbers
  spi: bcm-qspi: Fix use after free in bcm_qspi_probe() in error path
  spi: a3700: Return correct value on timeout detection
  spi: uapi: spidev: add missing ioctl header
  spi: stm32: Fix logical error in stm32_spi_prepare_mbr()
  spi: armada-3700: Fix padding when sending not 4-byte aligned data
  spi: armada-3700: Fix failing commands with quad-SPI
parents 601c5c2e 7555aa76
...@@ -99,11 +99,6 @@ ...@@ -99,11 +99,6 @@
/* A3700_SPI_IF_TIME_REG */ /* A3700_SPI_IF_TIME_REG */
#define A3700_SPI_CLK_CAPT_EDGE BIT(7) #define A3700_SPI_CLK_CAPT_EDGE BIT(7)
/* Flags and macros for struct a3700_spi */
#define A3700_INSTR_CNT 1
#define A3700_ADDR_CNT 3
#define A3700_DUMMY_CNT 1
struct a3700_spi { struct a3700_spi {
struct spi_master *master; struct spi_master *master;
void __iomem *base; void __iomem *base;
...@@ -117,9 +112,6 @@ struct a3700_spi { ...@@ -117,9 +112,6 @@ struct a3700_spi {
u8 byte_len; u8 byte_len;
u32 wait_mask; u32 wait_mask;
struct completion done; struct completion done;
u32 addr_cnt;
u32 instr_cnt;
size_t hdr_cnt;
}; };
static u32 spireg_read(struct a3700_spi *a3700_spi, u32 offset) static u32 spireg_read(struct a3700_spi *a3700_spi, u32 offset)
...@@ -161,7 +153,7 @@ static void a3700_spi_deactivate_cs(struct a3700_spi *a3700_spi, ...@@ -161,7 +153,7 @@ static void a3700_spi_deactivate_cs(struct a3700_spi *a3700_spi,
} }
static int a3700_spi_pin_mode_set(struct a3700_spi *a3700_spi, static int a3700_spi_pin_mode_set(struct a3700_spi *a3700_spi,
unsigned int pin_mode) unsigned int pin_mode, bool receiving)
{ {
u32 val; u32 val;
...@@ -177,6 +169,9 @@ static int a3700_spi_pin_mode_set(struct a3700_spi *a3700_spi, ...@@ -177,6 +169,9 @@ static int a3700_spi_pin_mode_set(struct a3700_spi *a3700_spi,
break; break;
case SPI_NBITS_QUAD: case SPI_NBITS_QUAD:
val |= A3700_SPI_DATA_PIN1; val |= A3700_SPI_DATA_PIN1;
/* RX during address reception uses 4-pin */
if (receiving)
val |= A3700_SPI_ADDR_PIN;
break; break;
default: default:
dev_err(&a3700_spi->master->dev, "wrong pin mode %u", pin_mode); dev_err(&a3700_spi->master->dev, "wrong pin mode %u", pin_mode);
...@@ -392,7 +387,8 @@ static bool a3700_spi_wait_completion(struct spi_device *spi) ...@@ -392,7 +387,8 @@ static bool a3700_spi_wait_completion(struct spi_device *spi)
spireg_write(a3700_spi, A3700_SPI_INT_MASK_REG, 0); spireg_write(a3700_spi, A3700_SPI_INT_MASK_REG, 0);
return true; /* Timeout was reached */
return false;
} }
static bool a3700_spi_transfer_wait(struct spi_device *spi, static bool a3700_spi_transfer_wait(struct spi_device *spi,
...@@ -446,59 +442,43 @@ static void a3700_spi_set_cs(struct spi_device *spi, bool enable) ...@@ -446,59 +442,43 @@ static void a3700_spi_set_cs(struct spi_device *spi, bool enable)
static void a3700_spi_header_set(struct a3700_spi *a3700_spi) static void a3700_spi_header_set(struct a3700_spi *a3700_spi)
{ {
u32 instr_cnt = 0, addr_cnt = 0, dummy_cnt = 0; unsigned int addr_cnt;
u32 val = 0; u32 val = 0;
/* Clear the header registers */ /* Clear the header registers */
spireg_write(a3700_spi, A3700_SPI_IF_INST_REG, 0); spireg_write(a3700_spi, A3700_SPI_IF_INST_REG, 0);
spireg_write(a3700_spi, A3700_SPI_IF_ADDR_REG, 0); spireg_write(a3700_spi, A3700_SPI_IF_ADDR_REG, 0);
spireg_write(a3700_spi, A3700_SPI_IF_RMODE_REG, 0); spireg_write(a3700_spi, A3700_SPI_IF_RMODE_REG, 0);
spireg_write(a3700_spi, A3700_SPI_IF_HDR_CNT_REG, 0);
/* Set header counters */ /* Set header counters */
if (a3700_spi->tx_buf) { if (a3700_spi->tx_buf) {
if (a3700_spi->buf_len <= a3700_spi->instr_cnt) { /*
instr_cnt = a3700_spi->buf_len; * when tx data is not 4 bytes aligned, there will be unexpected
} else if (a3700_spi->buf_len <= (a3700_spi->instr_cnt + * bytes out of SPI output register, since it always shifts out
a3700_spi->addr_cnt)) { * as whole 4 bytes. This might cause incorrect transaction with
instr_cnt = a3700_spi->instr_cnt; * some devices. To avoid that, use SPI header count feature to
addr_cnt = a3700_spi->buf_len - instr_cnt; * transfer up to 3 bytes of data first, and then make the rest
} else if (a3700_spi->buf_len <= a3700_spi->hdr_cnt) { * of data 4-byte aligned.
instr_cnt = a3700_spi->instr_cnt;
addr_cnt = a3700_spi->addr_cnt;
/* Need to handle the normal write case with 1 byte
* data
*/ */
if (!a3700_spi->tx_buf[instr_cnt + addr_cnt]) addr_cnt = a3700_spi->buf_len % 4;
dummy_cnt = a3700_spi->buf_len - instr_cnt - if (addr_cnt) {
addr_cnt; val = (addr_cnt & A3700_SPI_ADDR_CNT_MASK)
} << A3700_SPI_ADDR_CNT_BIT;
val |= ((instr_cnt & A3700_SPI_INSTR_CNT_MASK)
<< A3700_SPI_INSTR_CNT_BIT);
val |= ((addr_cnt & A3700_SPI_ADDR_CNT_MASK)
<< A3700_SPI_ADDR_CNT_BIT);
val |= ((dummy_cnt & A3700_SPI_DUMMY_CNT_MASK)
<< A3700_SPI_DUMMY_CNT_BIT);
}
spireg_write(a3700_spi, A3700_SPI_IF_HDR_CNT_REG, val); spireg_write(a3700_spi, A3700_SPI_IF_HDR_CNT_REG, val);
/* Update the buffer length to be transferred */ /* Update the buffer length to be transferred */
a3700_spi->buf_len -= (instr_cnt + addr_cnt + dummy_cnt); a3700_spi->buf_len -= addr_cnt;
/* Set Instruction */ /* transfer 1~3 bytes through address count */
val = 0;
while (instr_cnt--) {
val = (val << 8) | a3700_spi->tx_buf[0];
a3700_spi->tx_buf++;
}
spireg_write(a3700_spi, A3700_SPI_IF_INST_REG, val);
/* Set Address */
val = 0; val = 0;
while (addr_cnt--) { while (addr_cnt--) {
val = (val << 8) | a3700_spi->tx_buf[0]; val = (val << 8) | a3700_spi->tx_buf[0];
a3700_spi->tx_buf++; a3700_spi->tx_buf++;
} }
spireg_write(a3700_spi, A3700_SPI_IF_ADDR_REG, val); spireg_write(a3700_spi, A3700_SPI_IF_ADDR_REG, val);
}
}
} }
static int a3700_is_wfifo_full(struct a3700_spi *a3700_spi) static int a3700_is_wfifo_full(struct a3700_spi *a3700_spi)
...@@ -512,35 +492,12 @@ static int a3700_is_wfifo_full(struct a3700_spi *a3700_spi) ...@@ -512,35 +492,12 @@ static int a3700_is_wfifo_full(struct a3700_spi *a3700_spi)
static int a3700_spi_fifo_write(struct a3700_spi *a3700_spi) static int a3700_spi_fifo_write(struct a3700_spi *a3700_spi)
{ {
u32 val; u32 val;
int i = 0;
while (!a3700_is_wfifo_full(a3700_spi) && a3700_spi->buf_len) { while (!a3700_is_wfifo_full(a3700_spi) && a3700_spi->buf_len) {
val = 0;
if (a3700_spi->buf_len >= 4) {
val = cpu_to_le32(*(u32 *)a3700_spi->tx_buf); val = cpu_to_le32(*(u32 *)a3700_spi->tx_buf);
spireg_write(a3700_spi, A3700_SPI_DATA_OUT_REG, val); spireg_write(a3700_spi, A3700_SPI_DATA_OUT_REG, val);
a3700_spi->buf_len -= 4; a3700_spi->buf_len -= 4;
a3700_spi->tx_buf += 4; a3700_spi->tx_buf += 4;
} else {
/*
* If the remained buffer length is less than 4-bytes,
* we should pad the write buffer with all ones. So that
* it avoids overwrite the unexpected bytes following
* the last one.
*/
val = GENMASK(31, 0);
while (a3700_spi->buf_len) {
val &= ~(0xff << (8 * i));
val |= *a3700_spi->tx_buf++ << (8 * i);
i++;
a3700_spi->buf_len--;
spireg_write(a3700_spi, A3700_SPI_DATA_OUT_REG,
val);
}
break;
}
} }
return 0; return 0;
...@@ -645,15 +602,18 @@ static int a3700_spi_transfer_one(struct spi_master *master, ...@@ -645,15 +602,18 @@ static int a3700_spi_transfer_one(struct spi_master *master,
a3700_spi->rx_buf = xfer->rx_buf; a3700_spi->rx_buf = xfer->rx_buf;
a3700_spi->buf_len = xfer->len; a3700_spi->buf_len = xfer->len;
/* SPI transfer headers */
a3700_spi_header_set(a3700_spi);
if (xfer->tx_buf) if (xfer->tx_buf)
nbits = xfer->tx_nbits; nbits = xfer->tx_nbits;
else if (xfer->rx_buf) else if (xfer->rx_buf)
nbits = xfer->rx_nbits; nbits = xfer->rx_nbits;
a3700_spi_pin_mode_set(a3700_spi, nbits); a3700_spi_pin_mode_set(a3700_spi, nbits, xfer->rx_buf ? true : false);
/* Flush the FIFOs */
a3700_spi_fifo_flush(a3700_spi);
/* Transfer first bytes of data when buffer is not 4-byte aligned */
a3700_spi_header_set(a3700_spi);
if (xfer->rx_buf) { if (xfer->rx_buf) {
/* Set read data length */ /* Set read data length */
...@@ -733,17 +693,12 @@ static int a3700_spi_transfer_one(struct spi_master *master, ...@@ -733,17 +693,12 @@ static int a3700_spi_transfer_one(struct spi_master *master,
dev_err(&spi->dev, "wait wfifo empty timed out\n"); dev_err(&spi->dev, "wait wfifo empty timed out\n");
return -ETIMEDOUT; return -ETIMEDOUT;
} }
} else { }
/*
* If the instruction in SPI_INSTR does not require data
* to be written to the SPI device, wait until SPI_RDY
* is 1 for the SPI interface to be in idle.
*/
if (!a3700_spi_transfer_wait(spi, A3700_SPI_XFER_RDY)) { if (!a3700_spi_transfer_wait(spi, A3700_SPI_XFER_RDY)) {
dev_err(&spi->dev, "wait xfer ready timed out\n"); dev_err(&spi->dev, "wait xfer ready timed out\n");
return -ETIMEDOUT; return -ETIMEDOUT;
} }
}
val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG); val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG);
val |= A3700_SPI_XFER_STOP; val |= A3700_SPI_XFER_STOP;
...@@ -834,10 +789,6 @@ static int a3700_spi_probe(struct platform_device *pdev) ...@@ -834,10 +789,6 @@ static int a3700_spi_probe(struct platform_device *pdev)
memset(spi, 0, sizeof(struct a3700_spi)); memset(spi, 0, sizeof(struct a3700_spi));
spi->master = master; spi->master = master;
spi->instr_cnt = A3700_INSTR_CNT;
spi->addr_cnt = A3700_ADDR_CNT;
spi->hdr_cnt = A3700_INSTR_CNT + A3700_ADDR_CNT +
A3700_DUMMY_CNT;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
spi->base = devm_ioremap_resource(dev, res); spi->base = devm_ioremap_resource(dev, res);
......
...@@ -1250,7 +1250,7 @@ int bcm_qspi_probe(struct platform_device *pdev, ...@@ -1250,7 +1250,7 @@ int bcm_qspi_probe(struct platform_device *pdev,
goto qspi_probe_err; goto qspi_probe_err;
} }
} else { } else {
goto qspi_probe_err; goto qspi_resource_err;
} }
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "bspi"); res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "bspi");
...@@ -1272,7 +1272,7 @@ int bcm_qspi_probe(struct platform_device *pdev, ...@@ -1272,7 +1272,7 @@ int bcm_qspi_probe(struct platform_device *pdev,
qspi->base[CHIP_SELECT] = devm_ioremap_resource(dev, res); qspi->base[CHIP_SELECT] = devm_ioremap_resource(dev, res);
if (IS_ERR(qspi->base[CHIP_SELECT])) { if (IS_ERR(qspi->base[CHIP_SELECT])) {
ret = PTR_ERR(qspi->base[CHIP_SELECT]); ret = PTR_ERR(qspi->base[CHIP_SELECT]);
goto qspi_probe_err; goto qspi_resource_err;
} }
} }
...@@ -1280,7 +1280,7 @@ int bcm_qspi_probe(struct platform_device *pdev, ...@@ -1280,7 +1280,7 @@ int bcm_qspi_probe(struct platform_device *pdev,
GFP_KERNEL); GFP_KERNEL);
if (!qspi->dev_ids) { if (!qspi->dev_ids) {
ret = -ENOMEM; ret = -ENOMEM;
goto qspi_probe_err; goto qspi_resource_err;
} }
for (val = 0; val < num_irqs; val++) { for (val = 0; val < num_irqs; val++) {
...@@ -1369,8 +1369,9 @@ int bcm_qspi_probe(struct platform_device *pdev, ...@@ -1369,8 +1369,9 @@ int bcm_qspi_probe(struct platform_device *pdev,
bcm_qspi_hw_uninit(qspi); bcm_qspi_hw_uninit(qspi);
clk_disable_unprepare(qspi->clk); clk_disable_unprepare(qspi->clk);
qspi_probe_err: qspi_probe_err:
spi_master_put(master);
kfree(qspi->dev_ids); kfree(qspi->dev_ids);
qspi_resource_err:
spi_master_put(master);
return ret; return ret;
} }
/* probe function to be called by SoC specific platform driver probe */ /* probe function to be called by SoC specific platform driver probe */
......
...@@ -263,8 +263,8 @@ static int stm32_spi_prepare_mbr(struct stm32_spi *spi, u32 speed_hz) ...@@ -263,8 +263,8 @@ static int stm32_spi_prepare_mbr(struct stm32_spi *spi, u32 speed_hz)
* no need to check it there. * no need to check it there.
* However, we need to ensure the following calculations. * However, we need to ensure the following calculations.
*/ */
if ((div < SPI_MBR_DIV_MIN) && if (div < SPI_MBR_DIV_MIN ||
(div > SPI_MBR_DIV_MAX)) div > SPI_MBR_DIV_MAX)
return -EINVAL; return -EINVAL;
/* Determine the first power of 2 greater than or equal to div */ /* Determine the first power of 2 greater than or equal to div */
......
...@@ -45,7 +45,6 @@ ...@@ -45,7 +45,6 @@
#define CREATE_TRACE_POINTS #define CREATE_TRACE_POINTS
#include <trace/events/spi.h> #include <trace/events/spi.h>
#define SPI_DYN_FIRST_BUS_NUM 0
static DEFINE_IDR(spi_master_idr); static DEFINE_IDR(spi_master_idr);
...@@ -2086,7 +2085,7 @@ int spi_register_controller(struct spi_controller *ctlr) ...@@ -2086,7 +2085,7 @@ int spi_register_controller(struct spi_controller *ctlr)
struct device *dev = ctlr->dev.parent; struct device *dev = ctlr->dev.parent;
struct boardinfo *bi; struct boardinfo *bi;
int status = -ENODEV; int status = -ENODEV;
int id; int id, first_dynamic;
if (!dev) if (!dev)
return -ENODEV; return -ENODEV;
...@@ -2116,9 +2115,15 @@ int spi_register_controller(struct spi_controller *ctlr) ...@@ -2116,9 +2115,15 @@ int spi_register_controller(struct spi_controller *ctlr)
} }
} }
if (ctlr->bus_num < 0) { if (ctlr->bus_num < 0) {
first_dynamic = of_alias_get_highest_id("spi");
if (first_dynamic < 0)
first_dynamic = 0;
else
first_dynamic++;
mutex_lock(&board_lock); mutex_lock(&board_lock);
id = idr_alloc(&spi_master_idr, ctlr, SPI_DYN_FIRST_BUS_NUM, 0, id = idr_alloc(&spi_master_idr, ctlr, first_dynamic,
GFP_KERNEL); 0, GFP_KERNEL);
mutex_unlock(&board_lock); mutex_unlock(&board_lock);
if (WARN(id < 0, "couldn't get idr")) if (WARN(id < 0, "couldn't get idr"))
return id; return id;
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#define SPIDEV_H #define SPIDEV_H
#include <linux/types.h> #include <linux/types.h>
#include <linux/ioctl.h>
/* User space versions of kernel symbols for SPI clocking modes, /* User space versions of kernel symbols for SPI clocking modes,
* matching <linux/spi/spi.h> * matching <linux/spi/spi.h>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment