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:
commit
832c6b18f9
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Reference in New Issue