提交 bed5e4d8 编写于 作者: M Mark Brown

Merge tag 'spi-v4.1-rc1' into spi-linus

spi: Fixes for v4.1

A few driver fixes plus two changes for the core, one to make the
setup_transfer() callback optional which fixes crashes in some drivers
which were updated to use new interfaces without apparent testing and
one to ensure we don't expose the data buffers we use for dummy
transfers to drivers which avoids potential issues with multiple
accesses to them or reuse.

# gpg: Signature made Sat 25 Apr 2015 10:59:47 BST using RSA key ID 5D5487D0
# gpg: key CD7BEEBC: no public key for trusted key - skipped
# gpg: key CD7BEEBC marked as ultimately trusted
# gpg: key AF88CD16: no public key for trusted key - skipped
# gpg: key AF88CD16 marked as ultimately trusted
# gpg: key 16005C11: no public key for trusted key - skipped
# gpg: key 16005C11 marked as ultimately trusted
# gpg: key 5621E907: no public key for trusted key - skipped
# gpg: key 5621E907 marked as ultimately trusted
# gpg: key 5C6153AD: no public key for trusted key - skipped
# gpg: key 5C6153AD marked as ultimately trusted
# gpg: Good signature from "Mark Brown <broonie@sirena.org.uk>"
# gpg:                 aka "Mark Brown <broonie@debian.org>"
# gpg:                 aka "Mark Brown <broonie@kernel.org>"
# gpg:                 aka "Mark Brown <broonie@tardis.ed.ac.uk>"
# gpg:                 aka "Mark Brown <broonie@linaro.org>"
# gpg:                 aka "Mark Brown <Mark.Brown@linaro.org>"
...@@ -78,6 +78,7 @@ config SPI_ATMEL ...@@ -78,6 +78,7 @@ config SPI_ATMEL
config SPI_BCM2835 config SPI_BCM2835
tristate "BCM2835 SPI controller" tristate "BCM2835 SPI controller"
depends on ARCH_BCM2835 || COMPILE_TEST depends on ARCH_BCM2835 || COMPILE_TEST
depends on GPIOLIB
help help
This selects a driver for the Broadcom BCM2835 SPI master. This selects a driver for the Broadcom BCM2835 SPI master.
......
...@@ -164,13 +164,12 @@ static int bcm2835_spi_transfer_one_poll(struct spi_master *master, ...@@ -164,13 +164,12 @@ static int bcm2835_spi_transfer_one_poll(struct spi_master *master,
unsigned long xfer_time_us) unsigned long xfer_time_us)
{ {
struct bcm2835_spi *bs = spi_master_get_devdata(master); struct bcm2835_spi *bs = spi_master_get_devdata(master);
unsigned long timeout = jiffies + /* set timeout to 1 second of maximum polling */
max(4 * xfer_time_us * HZ / 1000000, 2uL); unsigned long timeout = jiffies + HZ;
/* enable HW block without interrupts */ /* enable HW block without interrupts */
bcm2835_wr(bs, BCM2835_SPI_CS, cs | BCM2835_SPI_CS_TA); bcm2835_wr(bs, BCM2835_SPI_CS, cs | BCM2835_SPI_CS_TA);
/* set timeout to 4x the expected time, or 2 jiffies */
/* loop until finished the transfer */ /* loop until finished the transfer */
while (bs->rx_len) { while (bs->rx_len) {
/* read from fifo as much as possible */ /* read from fifo as much as possible */
......
...@@ -180,7 +180,6 @@ int spi_bitbang_setup(struct spi_device *spi) ...@@ -180,7 +180,6 @@ int spi_bitbang_setup(struct spi_device *spi)
{ {
struct spi_bitbang_cs *cs = spi->controller_state; struct spi_bitbang_cs *cs = spi->controller_state;
struct spi_bitbang *bitbang; struct spi_bitbang *bitbang;
int retval;
unsigned long flags; unsigned long flags;
bitbang = spi_master_get_devdata(spi->master); bitbang = spi_master_get_devdata(spi->master);
...@@ -197,9 +196,11 @@ int spi_bitbang_setup(struct spi_device *spi) ...@@ -197,9 +196,11 @@ int spi_bitbang_setup(struct spi_device *spi)
if (!cs->txrx_word) if (!cs->txrx_word)
return -EINVAL; return -EINVAL;
retval = bitbang->setup_transfer(spi, NULL); if (bitbang->setup_transfer) {
int retval = bitbang->setup_transfer(spi, NULL);
if (retval < 0) if (retval < 0)
return retval; return retval;
}
dev_dbg(&spi->dev, "%s, %u nsec/bit\n", __func__, 2 * cs->nsecs); dev_dbg(&spi->dev, "%s, %u nsec/bit\n", __func__, 2 * cs->nsecs);
...@@ -295,9 +296,11 @@ static int spi_bitbang_transfer_one(struct spi_master *master, ...@@ -295,9 +296,11 @@ static int spi_bitbang_transfer_one(struct spi_master *master,
/* init (-1) or override (1) transfer params */ /* init (-1) or override (1) transfer params */
if (do_setup != 0) { if (do_setup != 0) {
if (bitbang->setup_transfer) {
status = bitbang->setup_transfer(spi, t); status = bitbang->setup_transfer(spi, t);
if (status < 0) if (status < 0)
break; break;
}
if (do_setup == -1) if (do_setup == -1)
do_setup = 0; do_setup = 0;
} }
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/platform_device.h>
#include "spi-fsl-cpm.h" #include "spi-fsl-cpm.h"
#include "spi-fsl-lib.h" #include "spi-fsl-lib.h"
...@@ -269,17 +270,6 @@ static unsigned long fsl_spi_cpm_get_pram(struct mpc8xxx_spi *mspi) ...@@ -269,17 +270,6 @@ static unsigned long fsl_spi_cpm_get_pram(struct mpc8xxx_spi *mspi)
if (mspi->flags & SPI_CPM2) { if (mspi->flags & SPI_CPM2) {
pram_ofs = cpm_muram_alloc(SPI_PRAM_SIZE, 64); pram_ofs = cpm_muram_alloc(SPI_PRAM_SIZE, 64);
out_be16(spi_base, pram_ofs); out_be16(spi_base, pram_ofs);
} else {
struct spi_pram __iomem *pram = spi_base;
u16 rpbase = in_be16(&pram->rpbase);
/* Microcode relocation patch applied? */
if (rpbase) {
pram_ofs = rpbase;
} else {
pram_ofs = cpm_muram_alloc(SPI_PRAM_SIZE, 64);
out_be16(spi_base, pram_ofs);
}
} }
iounmap(spi_base); iounmap(spi_base);
...@@ -292,7 +282,6 @@ int fsl_spi_cpm_init(struct mpc8xxx_spi *mspi) ...@@ -292,7 +282,6 @@ int fsl_spi_cpm_init(struct mpc8xxx_spi *mspi)
struct device_node *np = dev->of_node; struct device_node *np = dev->of_node;
const u32 *iprop; const u32 *iprop;
int size; int size;
unsigned long pram_ofs;
unsigned long bds_ofs; unsigned long bds_ofs;
if (!(mspi->flags & SPI_CPM_MODE)) if (!(mspi->flags & SPI_CPM_MODE))
...@@ -319,8 +308,21 @@ int fsl_spi_cpm_init(struct mpc8xxx_spi *mspi) ...@@ -319,8 +308,21 @@ int fsl_spi_cpm_init(struct mpc8xxx_spi *mspi)
} }
} }
pram_ofs = fsl_spi_cpm_get_pram(mspi); if (mspi->flags & SPI_CPM1) {
if (IS_ERR_VALUE(pram_ofs)) { struct resource *res;
res = platform_get_resource(to_platform_device(dev),
IORESOURCE_MEM, 1);
mspi->pram = devm_ioremap_resource(dev, res);
} else {
unsigned long pram_ofs = fsl_spi_cpm_get_pram(mspi);
if (IS_ERR_VALUE(pram_ofs))
mspi->pram = NULL;
else
mspi->pram = cpm_muram_addr(pram_ofs);
}
if (mspi->pram == NULL) {
dev_err(dev, "can't allocate spi parameter ram\n"); dev_err(dev, "can't allocate spi parameter ram\n");
goto err_pram; goto err_pram;
} }
...@@ -346,8 +348,6 @@ int fsl_spi_cpm_init(struct mpc8xxx_spi *mspi) ...@@ -346,8 +348,6 @@ int fsl_spi_cpm_init(struct mpc8xxx_spi *mspi)
goto err_dummy_rx; goto err_dummy_rx;
} }
mspi->pram = cpm_muram_addr(pram_ofs);
mspi->tx_bd = cpm_muram_addr(bds_ofs); mspi->tx_bd = cpm_muram_addr(bds_ofs);
mspi->rx_bd = cpm_muram_addr(bds_ofs + sizeof(*mspi->tx_bd)); mspi->rx_bd = cpm_muram_addr(bds_ofs + sizeof(*mspi->tx_bd));
...@@ -375,7 +375,8 @@ int fsl_spi_cpm_init(struct mpc8xxx_spi *mspi) ...@@ -375,7 +375,8 @@ int fsl_spi_cpm_init(struct mpc8xxx_spi *mspi)
err_dummy_tx: err_dummy_tx:
cpm_muram_free(bds_ofs); cpm_muram_free(bds_ofs);
err_bds: err_bds:
cpm_muram_free(pram_ofs); if (!(mspi->flags & SPI_CPM1))
cpm_muram_free(cpm_muram_offset(mspi->pram));
err_pram: err_pram:
fsl_spi_free_dummy_rx(); fsl_spi_free_dummy_rx();
return -ENOMEM; return -ENOMEM;
......
...@@ -1210,6 +1210,7 @@ static int omap2_mcspi_transfer_one_message(struct spi_master *master, ...@@ -1210,6 +1210,7 @@ static int omap2_mcspi_transfer_one_message(struct spi_master *master,
struct omap2_mcspi *mcspi; struct omap2_mcspi *mcspi;
struct omap2_mcspi_dma *mcspi_dma; struct omap2_mcspi_dma *mcspi_dma;
struct spi_transfer *t; struct spi_transfer *t;
int status;
spi = m->spi; spi = m->spi;
mcspi = spi_master_get_devdata(master); mcspi = spi_master_get_devdata(master);
...@@ -1229,7 +1230,8 @@ static int omap2_mcspi_transfer_one_message(struct spi_master *master, ...@@ -1229,7 +1230,8 @@ static int omap2_mcspi_transfer_one_message(struct spi_master *master,
tx_buf ? "tx" : "", tx_buf ? "tx" : "",
rx_buf ? "rx" : "", rx_buf ? "rx" : "",
t->bits_per_word); t->bits_per_word);
return -EINVAL; status = -EINVAL;
goto out;
} }
if (m->is_dma_mapped || len < DMA_MIN_BYTES) if (m->is_dma_mapped || len < DMA_MIN_BYTES)
...@@ -1241,7 +1243,8 @@ static int omap2_mcspi_transfer_one_message(struct spi_master *master, ...@@ -1241,7 +1243,8 @@ static int omap2_mcspi_transfer_one_message(struct spi_master *master,
if (dma_mapping_error(mcspi->dev, t->tx_dma)) { if (dma_mapping_error(mcspi->dev, t->tx_dma)) {
dev_dbg(mcspi->dev, "dma %cX %d bytes error\n", dev_dbg(mcspi->dev, "dma %cX %d bytes error\n",
'T', len); 'T', len);
return -EINVAL; status = -EINVAL;
goto out;
} }
} }
if (mcspi_dma->dma_rx && rx_buf != NULL) { if (mcspi_dma->dma_rx && rx_buf != NULL) {
...@@ -1253,14 +1256,19 @@ static int omap2_mcspi_transfer_one_message(struct spi_master *master, ...@@ -1253,14 +1256,19 @@ static int omap2_mcspi_transfer_one_message(struct spi_master *master,
if (tx_buf != NULL) if (tx_buf != NULL)
dma_unmap_single(mcspi->dev, t->tx_dma, dma_unmap_single(mcspi->dev, t->tx_dma,
len, DMA_TO_DEVICE); len, DMA_TO_DEVICE);
return -EINVAL; status = -EINVAL;
goto out;
} }
} }
} }
omap2_mcspi_work(mcspi, m); omap2_mcspi_work(mcspi, m);
/* spi_finalize_current_message() changes the status inside the
* spi_message, save the status here. */
status = m->status;
out:
spi_finalize_current_message(master); spi_finalize_current_message(master);
return 0; return status;
} }
static int omap2_mcspi_master_setup(struct omap2_mcspi *mcspi) static int omap2_mcspi_master_setup(struct omap2_mcspi *mcspi)
......
...@@ -583,6 +583,15 @@ static int spi_unmap_msg(struct spi_master *master, struct spi_message *msg) ...@@ -583,6 +583,15 @@ static int spi_unmap_msg(struct spi_master *master, struct spi_message *msg)
rx_dev = master->dma_rx->device->dev; rx_dev = master->dma_rx->device->dev;
list_for_each_entry(xfer, &msg->transfers, transfer_list) { list_for_each_entry(xfer, &msg->transfers, transfer_list) {
/*
* Restore the original value of tx_buf or rx_buf if they are
* NULL.
*/
if (xfer->tx_buf == master->dummy_tx)
xfer->tx_buf = NULL;
if (xfer->rx_buf == master->dummy_rx)
xfer->rx_buf = NULL;
if (!master->can_dma(master, msg->spi, xfer)) if (!master->can_dma(master, msg->spi, xfer))
continue; continue;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册