mirror of
https://github.com/torvalds/linux.git
synced 2024-11-17 01:22:07 +00:00
spi: Fixes for v3.15
A few core fixes around outlying cases here, nothing that should affect most users but useful fixes. The diffstat is rather larger than one might hope due some simple code motion in the fix for !CONFIG_DMA, the actual meaningful change is much smaller. - Fix handling of unsupported dual and quad mode support on slave registration so that drivers that can degrade gracefully do so, preventing regressions for drivers this is added. - Fix build in !CONFIG_DMA cases following addition of generic DMA mapping support. - Fix error handling for queue creation which due to wider kernel changes can be triggered more easily. - A couple of driver specific fixes. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJTc5CkAAoJELSic+t+oim9p+cP/2qp1ud28ZPSRk4bxcjoNZng 0bR7JF5Ji0t2Md7KkvJx4/1k1A7OvAk/i3WM2TUHkjQDcUaIhfoYEEViie2xzX4H UN9PvCvE+NcEDewQfos54mT7lQgWt2D31NsfQLAK/wtQBauj7yEDpqToGzvMRdz6 4ni+LG9/TDu7PN76pNzV0yth5ckrjAjSC9TZH5B0N7S80aZurGG2EkJU6UoyOnK1 zFxHtUq+lBJw+DsOF8J6fIRCexoLyv1vw5cMO5AqXW6OPzCD7WEt0kpm2L4y3Ois NcOf3rnEJLHd8+4BeICgT6e9LStyeHhtRbGJB6b+YvBr0dR309+vAxSrIQvlFi7T U+f4CdbxlBWW6u07R39iUM+OPMYic4BE3gE9Z7NxlwdLWKJVUNvQ6ICazLnUITbL Qoqmk7cERMKeOjTtqm/fFI27tkvEq+rqhdRBzOldWxweuoeaSFnBFseWd0nAj3M8 KrZtVuBcoldDpzx05cF/nwrYgbdScAJYp9XAepZRLBidb7Epyh78t6uWJWnyOz/N VZvgw+DkX2v6Gyhrb5/+c6jt6T1NGdbBILX7vTG1ZqWn0VanNP6oFiCTJvT2lOsm wQQ7HrTKUQJsJSV015l9rGnYZeg3h1gDRnsnE8SPc5wWTxJ+60U0Pvd51iE6l4uR Kb+pVOx+xVh9kiEgJwhV =WbM5 -----END PGP SIGNATURE----- Merge tag 'spi-v3.15-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi Pull spi fixes from Mark Brown: "A few core fixes around outlying cases here, nothing that should affect most users but useful fixes. The diffstat is rather larger than one might hope due some simple code motion in the fix for !CONFIG_DMA, the actual meaningful change is much smaller. - Fix handling of unsupported dual and quad mode support on slave registration so that drivers that can degrade gracefully do so, preventing regressions for drivers this is added. - Fix build in !CONFIG_DMA cases following addition of generic DMA mapping support. - Fix error handling for queue creation which due to wider kernel changes can be triggered more easily. - A couple of driver specific fixes" * tag 'spi-v3.15-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi: spi/pxa2xx: Prevent DMA from transferring too many bytes spi: core: Don't destroy master queue if we fail to create it spi: qup: Fix return value checking for pm_runtime_get_sync() spi: core: Protect DMA code by #ifdef CONFIG_HAS_DMA spi: core: Ignore unsupported Dual/Quad Transfer Mode bits
This commit is contained in:
commit
b2e3432af1
@ -29,18 +29,6 @@ static int pxa2xx_spi_map_dma_buffer(struct driver_data *drv_data,
|
||||
struct sg_table *sgt;
|
||||
void *buf, *pbuf;
|
||||
|
||||
/*
|
||||
* Some DMA controllers have problems transferring buffers that are
|
||||
* not multiple of 4 bytes. So we truncate the transfer so that it
|
||||
* is suitable for such controllers, and handle the trailing bytes
|
||||
* manually after the DMA completes.
|
||||
*
|
||||
* REVISIT: It would be better if this information could be
|
||||
* retrieved directly from the DMA device in a similar way than
|
||||
* ->copy_align etc. is done.
|
||||
*/
|
||||
len = ALIGN(drv_data->len, 4);
|
||||
|
||||
if (dir == DMA_TO_DEVICE) {
|
||||
dmadev = drv_data->tx_chan->device->dev;
|
||||
sgt = &drv_data->tx_sgt;
|
||||
@ -144,12 +132,8 @@ static void pxa2xx_spi_dma_transfer_complete(struct driver_data *drv_data,
|
||||
if (!error) {
|
||||
pxa2xx_spi_unmap_dma_buffers(drv_data);
|
||||
|
||||
/* Handle the last bytes of unaligned transfer */
|
||||
drv_data->tx += drv_data->tx_map_len;
|
||||
drv_data->write(drv_data);
|
||||
|
||||
drv_data->rx += drv_data->rx_map_len;
|
||||
drv_data->read(drv_data);
|
||||
|
||||
msg->actual_length += drv_data->len;
|
||||
msg->state = pxa2xx_spi_next_transfer(drv_data);
|
||||
|
@ -734,7 +734,7 @@ static int spi_qup_remove(struct platform_device *pdev)
|
||||
int ret;
|
||||
|
||||
ret = pm_runtime_get_sync(&pdev->dev);
|
||||
if (ret)
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = spi_qup_set_state(controller, QUP_STATE_RESET);
|
||||
|
@ -580,6 +580,7 @@ static void spi_set_cs(struct spi_device *spi, bool enable)
|
||||
spi->master->set_cs(spi, !enable);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HAS_DMA
|
||||
static int spi_map_buf(struct spi_master *master, struct device *dev,
|
||||
struct sg_table *sgt, void *buf, size_t len,
|
||||
enum dma_data_direction dir)
|
||||
@ -637,55 +638,12 @@ static void spi_unmap_buf(struct spi_master *master, struct device *dev,
|
||||
}
|
||||
}
|
||||
|
||||
static int spi_map_msg(struct spi_master *master, struct spi_message *msg)
|
||||
static int __spi_map_msg(struct spi_master *master, struct spi_message *msg)
|
||||
{
|
||||
struct device *tx_dev, *rx_dev;
|
||||
struct spi_transfer *xfer;
|
||||
void *tmp;
|
||||
unsigned int max_tx, max_rx;
|
||||
int ret;
|
||||
|
||||
if (master->flags & (SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX)) {
|
||||
max_tx = 0;
|
||||
max_rx = 0;
|
||||
|
||||
list_for_each_entry(xfer, &msg->transfers, transfer_list) {
|
||||
if ((master->flags & SPI_MASTER_MUST_TX) &&
|
||||
!xfer->tx_buf)
|
||||
max_tx = max(xfer->len, max_tx);
|
||||
if ((master->flags & SPI_MASTER_MUST_RX) &&
|
||||
!xfer->rx_buf)
|
||||
max_rx = max(xfer->len, max_rx);
|
||||
}
|
||||
|
||||
if (max_tx) {
|
||||
tmp = krealloc(master->dummy_tx, max_tx,
|
||||
GFP_KERNEL | GFP_DMA);
|
||||
if (!tmp)
|
||||
return -ENOMEM;
|
||||
master->dummy_tx = tmp;
|
||||
memset(tmp, 0, max_tx);
|
||||
}
|
||||
|
||||
if (max_rx) {
|
||||
tmp = krealloc(master->dummy_rx, max_rx,
|
||||
GFP_KERNEL | GFP_DMA);
|
||||
if (!tmp)
|
||||
return -ENOMEM;
|
||||
master->dummy_rx = tmp;
|
||||
}
|
||||
|
||||
if (max_tx || max_rx) {
|
||||
list_for_each_entry(xfer, &msg->transfers,
|
||||
transfer_list) {
|
||||
if (!xfer->tx_buf)
|
||||
xfer->tx_buf = master->dummy_tx;
|
||||
if (!xfer->rx_buf)
|
||||
xfer->rx_buf = master->dummy_rx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!master->can_dma)
|
||||
return 0;
|
||||
|
||||
@ -742,6 +700,69 @@ static int spi_unmap_msg(struct spi_master *master, struct spi_message *msg)
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else /* !CONFIG_HAS_DMA */
|
||||
static inline int __spi_map_msg(struct spi_master *master,
|
||||
struct spi_message *msg)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int spi_unmap_msg(struct spi_master *master,
|
||||
struct spi_message *msg)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif /* !CONFIG_HAS_DMA */
|
||||
|
||||
static int spi_map_msg(struct spi_master *master, struct spi_message *msg)
|
||||
{
|
||||
struct spi_transfer *xfer;
|
||||
void *tmp;
|
||||
unsigned int max_tx, max_rx;
|
||||
|
||||
if (master->flags & (SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX)) {
|
||||
max_tx = 0;
|
||||
max_rx = 0;
|
||||
|
||||
list_for_each_entry(xfer, &msg->transfers, transfer_list) {
|
||||
if ((master->flags & SPI_MASTER_MUST_TX) &&
|
||||
!xfer->tx_buf)
|
||||
max_tx = max(xfer->len, max_tx);
|
||||
if ((master->flags & SPI_MASTER_MUST_RX) &&
|
||||
!xfer->rx_buf)
|
||||
max_rx = max(xfer->len, max_rx);
|
||||
}
|
||||
|
||||
if (max_tx) {
|
||||
tmp = krealloc(master->dummy_tx, max_tx,
|
||||
GFP_KERNEL | GFP_DMA);
|
||||
if (!tmp)
|
||||
return -ENOMEM;
|
||||
master->dummy_tx = tmp;
|
||||
memset(tmp, 0, max_tx);
|
||||
}
|
||||
|
||||
if (max_rx) {
|
||||
tmp = krealloc(master->dummy_rx, max_rx,
|
||||
GFP_KERNEL | GFP_DMA);
|
||||
if (!tmp)
|
||||
return -ENOMEM;
|
||||
master->dummy_rx = tmp;
|
||||
}
|
||||
|
||||
if (max_tx || max_rx) {
|
||||
list_for_each_entry(xfer, &msg->transfers,
|
||||
transfer_list) {
|
||||
if (!xfer->tx_buf)
|
||||
xfer->tx_buf = master->dummy_tx;
|
||||
if (!xfer->rx_buf)
|
||||
xfer->rx_buf = master->dummy_rx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return __spi_map_msg(master, msg);
|
||||
}
|
||||
|
||||
/*
|
||||
* spi_transfer_one_message - Default implementation of transfer_one_message()
|
||||
@ -1151,7 +1172,6 @@ static int spi_master_initialize_queue(struct spi_master *master)
|
||||
{
|
||||
int ret;
|
||||
|
||||
master->queued = true;
|
||||
master->transfer = spi_queued_transfer;
|
||||
if (!master->transfer_one_message)
|
||||
master->transfer_one_message = spi_transfer_one_message;
|
||||
@ -1162,6 +1182,7 @@ static int spi_master_initialize_queue(struct spi_master *master)
|
||||
dev_err(&master->dev, "problem initializing queue\n");
|
||||
goto err_init_queue;
|
||||
}
|
||||
master->queued = true;
|
||||
ret = spi_start_queue(master);
|
||||
if (ret) {
|
||||
dev_err(&master->dev, "problem starting queue\n");
|
||||
@ -1171,8 +1192,8 @@ static int spi_master_initialize_queue(struct spi_master *master)
|
||||
return 0;
|
||||
|
||||
err_start_queue:
|
||||
err_init_queue:
|
||||
spi_destroy_queue(master);
|
||||
err_init_queue:
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1756,7 +1777,7 @@ EXPORT_SYMBOL_GPL(spi_busnum_to_master);
|
||||
*/
|
||||
int spi_setup(struct spi_device *spi)
|
||||
{
|
||||
unsigned bad_bits;
|
||||
unsigned bad_bits, ugly_bits;
|
||||
int status = 0;
|
||||
|
||||
/* check mode to prevent that DUAL and QUAD set at the same time
|
||||
@ -1776,6 +1797,15 @@ int spi_setup(struct spi_device *spi)
|
||||
* that aren't supported with their current master
|
||||
*/
|
||||
bad_bits = spi->mode & ~spi->master->mode_bits;
|
||||
ugly_bits = bad_bits &
|
||||
(SPI_TX_DUAL | SPI_TX_QUAD | SPI_RX_DUAL | SPI_RX_QUAD);
|
||||
if (ugly_bits) {
|
||||
dev_warn(&spi->dev,
|
||||
"setup: ignoring unsupported mode bits %x\n",
|
||||
ugly_bits);
|
||||
spi->mode &= ~ugly_bits;
|
||||
bad_bits &= ~ugly_bits;
|
||||
}
|
||||
if (bad_bits) {
|
||||
dev_err(&spi->dev, "setup: unsupported mode bits %x\n",
|
||||
bad_bits);
|
||||
|
Loading…
Reference in New Issue
Block a user