spi: Fixes for v4.14

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.
 -----BEGIN PGP SIGNATURE-----
 
 iQFHBAABCgAxFiEEreZoqmdXGLWf4p/qJNaLcl1Uh9AFAlnxrd0THGJyb29uaWVA
 a2VybmVsLm9yZwAKCRAk1otyXVSH0BAyB/4mb+sFzmPMeFsXPc+e90SriBSjPOUx
 sNg4F5gZtC4n+I2EiUUucSyTTosxcXGlteVb87hhBp6aa5vqs5Ja6XCjljqVutys
 mz0+l8U5jHoRVKcIosywn2TgJPAIMBXzuMlPD3EQBywBbvXGbAktgY/04xaqQPwz
 5+20OyHW1/IPAR+mLYtAov/MYpd7HjsQphBBz9PJefsRqySk9yWcFEWKFvuNVhEr
 WDGRRsIWfyDJvjDqhKeQGOvNeukTPaNxZRvT2+k9hVq1Vw05PYBpVDjP1Z3ina7G
 CY3rIh/G/FQd9xEkGSIRrkAGFG02BkoJho0KgwlUlgr16BVaFVHLi8Nm
 =yd2a
 -----END PGP SIGNATURE-----

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
This commit is contained in:
Linus Torvalds 2017-10-26 17:06:35 +02:00
commit 832c6b18f9
5 changed files with 65 additions and 107 deletions

View File

@ -99,11 +99,6 @@
/* A3700_SPI_IF_TIME_REG */
#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 spi_master *master;
void __iomem *base;
@ -117,9 +112,6 @@ struct a3700_spi {
u8 byte_len;
u32 wait_mask;
struct completion done;
u32 addr_cnt;
u32 instr_cnt;
size_t hdr_cnt;
};
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,
}
static int a3700_spi_pin_mode_set(struct a3700_spi *a3700_spi,
unsigned int pin_mode)
unsigned int pin_mode, bool receiving)
{
u32 val;
@ -177,6 +169,9 @@ static int a3700_spi_pin_mode_set(struct a3700_spi *a3700_spi,
break;
case SPI_NBITS_QUAD:
val |= A3700_SPI_DATA_PIN1;
/* RX during address reception uses 4-pin */
if (receiving)
val |= A3700_SPI_ADDR_PIN;
break;
default:
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)
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,
@ -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)
{
u32 instr_cnt = 0, addr_cnt = 0, dummy_cnt = 0;
unsigned int addr_cnt;
u32 val = 0;
/* Clear the header registers */
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_RMODE_REG, 0);
spireg_write(a3700_spi, A3700_SPI_IF_HDR_CNT_REG, 0);
/* Set header counters */
if (a3700_spi->tx_buf) {
if (a3700_spi->buf_len <= a3700_spi->instr_cnt) {
instr_cnt = a3700_spi->buf_len;
} else if (a3700_spi->buf_len <= (a3700_spi->instr_cnt +
a3700_spi->addr_cnt)) {
instr_cnt = a3700_spi->instr_cnt;
addr_cnt = a3700_spi->buf_len - instr_cnt;
} else if (a3700_spi->buf_len <= a3700_spi->hdr_cnt) {
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])
dummy_cnt = a3700_spi->buf_len - instr_cnt -
addr_cnt;
/*
* when tx data is not 4 bytes aligned, there will be unexpected
* bytes out of SPI output register, since it always shifts out
* as whole 4 bytes. This might cause incorrect transaction with
* some devices. To avoid that, use SPI header count feature to
* transfer up to 3 bytes of data first, and then make the rest
* of data 4-byte aligned.
*/
addr_cnt = a3700_spi->buf_len % 4;
if (addr_cnt) {
val = (addr_cnt & A3700_SPI_ADDR_CNT_MASK)
<< A3700_SPI_ADDR_CNT_BIT;
spireg_write(a3700_spi, A3700_SPI_IF_HDR_CNT_REG, val);
/* Update the buffer length to be transferred */
a3700_spi->buf_len -= addr_cnt;
/* transfer 1~3 bytes through address count */
val = 0;
while (addr_cnt--) {
val = (val << 8) | a3700_spi->tx_buf[0];
a3700_spi->tx_buf++;
}
spireg_write(a3700_spi, A3700_SPI_IF_ADDR_REG, val);
}
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);
/* Update the buffer length to be transferred */
a3700_spi->buf_len -= (instr_cnt + addr_cnt + dummy_cnt);
/* Set Instruction */
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;
while (addr_cnt--) {
val = (val << 8) | a3700_spi->tx_buf[0];
a3700_spi->tx_buf++;
}
spireg_write(a3700_spi, A3700_SPI_IF_ADDR_REG, val);
}
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)
{
u32 val;
int i = 0;
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);
spireg_write(a3700_spi, A3700_SPI_DATA_OUT_REG, val);
a3700_spi->buf_len -= 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;
}
val = cpu_to_le32(*(u32 *)a3700_spi->tx_buf);
spireg_write(a3700_spi, A3700_SPI_DATA_OUT_REG, val);
a3700_spi->buf_len -= 4;
a3700_spi->tx_buf += 4;
}
return 0;
@ -645,15 +602,18 @@ static int a3700_spi_transfer_one(struct spi_master *master,
a3700_spi->rx_buf = xfer->rx_buf;
a3700_spi->buf_len = xfer->len;
/* SPI transfer headers */
a3700_spi_header_set(a3700_spi);
if (xfer->tx_buf)
nbits = xfer->tx_nbits;
else if (xfer->rx_buf)
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) {
/* Set read data length */
@ -733,16 +693,11 @@ static int a3700_spi_transfer_one(struct spi_master *master,
dev_err(&spi->dev, "wait wfifo empty timed out\n");
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)) {
dev_err(&spi->dev, "wait xfer ready timed out\n");
return -ETIMEDOUT;
}
}
if (!a3700_spi_transfer_wait(spi, A3700_SPI_XFER_RDY)) {
dev_err(&spi->dev, "wait xfer ready timed out\n");
return -ETIMEDOUT;
}
val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG);
@ -834,10 +789,6 @@ static int a3700_spi_probe(struct platform_device *pdev)
memset(spi, 0, sizeof(struct a3700_spi));
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);
spi->base = devm_ioremap_resource(dev, res);

View File

@ -1250,7 +1250,7 @@ int bcm_qspi_probe(struct platform_device *pdev,
goto qspi_probe_err;
}
} else {
goto qspi_probe_err;
goto qspi_resource_err;
}
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "bspi");
@ -1272,7 +1272,7 @@ int bcm_qspi_probe(struct platform_device *pdev,
qspi->base[CHIP_SELECT] = devm_ioremap_resource(dev, res);
if (IS_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,
GFP_KERNEL);
if (!qspi->dev_ids) {
ret = -ENOMEM;
goto qspi_probe_err;
goto qspi_resource_err;
}
for (val = 0; val < num_irqs; val++) {
@ -1369,8 +1369,9 @@ qspi_reg_err:
bcm_qspi_hw_uninit(qspi);
clk_disable_unprepare(qspi->clk);
qspi_probe_err:
spi_master_put(master);
kfree(qspi->dev_ids);
qspi_resource_err:
spi_master_put(master);
return ret;
}
/* probe function to be called by SoC specific platform driver probe */

View File

@ -263,8 +263,8 @@ static int stm32_spi_prepare_mbr(struct stm32_spi *spi, u32 speed_hz)
* no need to check it there.
* However, we need to ensure the following calculations.
*/
if ((div < SPI_MBR_DIV_MIN) &&
(div > SPI_MBR_DIV_MAX))
if (div < SPI_MBR_DIV_MIN ||
div > SPI_MBR_DIV_MAX)
return -EINVAL;
/* Determine the first power of 2 greater than or equal to div */

View File

@ -45,7 +45,6 @@
#define CREATE_TRACE_POINTS
#include <trace/events/spi.h>
#define SPI_DYN_FIRST_BUS_NUM 0
static DEFINE_IDR(spi_master_idr);
@ -2086,7 +2085,7 @@ int spi_register_controller(struct spi_controller *ctlr)
struct device *dev = ctlr->dev.parent;
struct boardinfo *bi;
int status = -ENODEV;
int id;
int id, first_dynamic;
if (!dev)
return -ENODEV;
@ -2116,9 +2115,15 @@ int spi_register_controller(struct spi_controller *ctlr)
}
}
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);
id = idr_alloc(&spi_master_idr, ctlr, SPI_DYN_FIRST_BUS_NUM, 0,
GFP_KERNEL);
id = idr_alloc(&spi_master_idr, ctlr, first_dynamic,
0, GFP_KERNEL);
mutex_unlock(&board_lock);
if (WARN(id < 0, "couldn't get idr"))
return id;

View File

@ -23,6 +23,7 @@
#define SPIDEV_H
#include <linux/types.h>
#include <linux/ioctl.h>
/* User space versions of kernel symbols for SPI clocking modes,
* matching <linux/spi/spi.h>