diff options
author | Shimin Zhou <shimingx.zhou@intel.com> | 2015-12-11 13:57:10 +0800 |
---|---|---|
committer | Bruce Beare <bbeare1@gmail.com> | 2015-12-21 16:22:01 -0800 |
commit | 298a18e9ab8f9f4aa337d3acdbd20e9fdccc69aa (patch) | |
tree | 35adda9f849b588085e9bdb5424fa677b50579ee | |
parent | 2bb54da1b71c760ac5e04f57d7baf28ebdd3b899 (diff) | |
download | edison-v3.10-298a18e9ab8f9f4aa337d3acdbd20e9fdccc69aa.tar.gz |
spi: fix freeze issue when spi transferring special length of data
Fix DMA mode will freeze when transfering
8 bytes/8 bits,16 bytes/16 bits, 32 bytes/32 bits.
and enable DMA mode in spi transferring.
Cherry-pick from:
https://github.com/01org/edison-linux/commit/2d7dacd26d06afec9fd4d7a5df73bc4f77571195
Signed-off-by: Shimin Zhou <shimingx.zhou@intel.com>
Signed-off-by: Zhenming Zhao <zhenmingx.zhao@intel.com>
BUG=26065307
Change-Id: I851219a761b6c65cd7a8edc1370c054ce6c35883
-rw-r--r-- | arch/x86/platform/intel-mid/device_libs/platform_spidev.c | 2 | ||||
-rw-r--r-- | drivers/spi/intel_mid_ssp_spi.c | 28 | ||||
-rw-r--r-- | drivers/spi/spidev.c | 6 |
3 files changed, 14 insertions, 22 deletions
diff --git a/arch/x86/platform/intel-mid/device_libs/platform_spidev.c b/arch/x86/platform/intel-mid/device_libs/platform_spidev.c index cc7512943a2..40827d64011 100644 --- a/arch/x86/platform/intel-mid/device_libs/platform_spidev.c +++ b/arch/x86/platform/intel-mid/device_libs/platform_spidev.c @@ -26,7 +26,7 @@ static struct intel_mid_ssp_spi_chip chip = { .burst_size = DFLT_FIFO_BURST_SIZE, .timeout = DFLT_TIMEOUT_VAL, /* SPI DMA is currently usable on Tangier */ - .dma_enabled = false, + .dma_enabled = true, .cs_control = tng_ssp_spi_cs_control, .platform_pinmux = tng_ssp_spi_platform_pinmux, }; diff --git a/drivers/spi/intel_mid_ssp_spi.c b/drivers/spi/intel_mid_ssp_spi.c index 0ccffed4af5..f68691082f9 100644 --- a/drivers/spi/intel_mid_ssp_spi.c +++ b/drivers/spi/intel_mid_ssp_spi.c @@ -544,7 +544,7 @@ static void dma_transfer(struct ssp_drv_context *sspc) /* In Rx direction, TRAIL Bytes are handled by memcpy */ if (sspc->rx_dma && - (sspc->len_dma_rx > + (sspc->len_dma_rx >= sspc->rx_fifo_threshold * sspc->n_bytes)) { sspc->len_dma_rx = TRUNCATE(sspc->len_dma_rx, @@ -961,7 +961,6 @@ static int handle_message(struct ssp_drv_context *sspc) u32 mask = 0; int bits_per_word, saved_bits_per_word; unsigned long flags; - u8 normal_enabled = 0; chip = spi_get_ctldata(msg->spi); @@ -1056,28 +1055,16 @@ static int handle_message(struct ssp_drv_context *sspc) sspc->n_bytes = 1; sspc->read = u8_reader; sspc->write = u8_writer; - /* It maybe has some unclear issue in dma mode, as workaround, - use normal mode to transfer when len equal 8 bytes */ - if (transfer->len == 8) - normal_enabled = 1; } else if (bits_per_word <= 16) { sspc->n_bytes = 2; sspc->read = u16_reader; sspc->write = u16_writer; - /* It maybe has some unclear issue in dma mode, as workaround, - use normal mode to transfer when len equal 16 bytes */ - if (transfer->len == 16) - normal_enabled = 1; } else if (bits_per_word <= 32) { if (!ssp_timing_wr) cr0 |= SSCR0_EDSS; sspc->n_bytes = 4; sspc->read = u32_reader; sspc->write = u32_writer; - /* It maybe has some unclear issue in dma mode, as workaround, - use normal mode to transfer when len equal 32 bytes */ - if (transfer->len == 32) - normal_enabled = 1; } sspc->tx = (void *)transfer->tx_buf; @@ -1116,7 +1103,7 @@ static int handle_message(struct ssp_drv_context *sspc) /* value. The RX fifo threshold must be aligned with the DMA */ /* RX transfer size, which may be limited to a multiple of 4 */ /* bytes due to 32bits DDR access. */ - if (sspc->len / sspc->n_bytes <= sspc->rx_fifo_threshold) { + if (sspc->len / sspc->n_bytes < sspc->rx_fifo_threshold) { u32 rx_fifo_threshold; rx_fifo_threshold = (sspc->len & ~(4 - 1)) / @@ -1178,7 +1165,7 @@ static int handle_message(struct ssp_drv_context *sspc) if (sspc->cs_control) sspc->cs_control(sspc->cs_assert); - if (likely(dma_enabled) && (!normal_enabled)) { + if (likely(dma_enabled)) { if (unlikely(sspc->quirks & QUIRKS_USE_PM_QOS)) pm_qos_update_request(&sspc->pm_qos_req, MIN_EXIT_LATENCY); @@ -1255,10 +1242,11 @@ static int setup(struct spi_device *spi) if (!spi->bits_per_word) spi->bits_per_word = DFLT_BITS_PER_WORD; - if ((spi->bits_per_word < MIN_BITS_PER_WORD - || spi->bits_per_word > MAX_BITS_PER_WORD)) { - ret = -EINVAL; - goto exit_setup; + if ((spi->bits_per_word != 8) && (spi->bits_per_word != 16) + && (spi->bits_per_word != 32)) { + spin_unlock_irqrestore(&sspc->lock, flags); + dev_warn(&spi->dev, "invalid wordsize, system only support 8,16,32 bits per word.\n"); + return -EINVAL; } chip = spi_get_ctldata(spi); diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c index a08f923b992..12112a1f3ed 100644 --- a/drivers/spi/spidev.c +++ b/drivers/spi/spidev.c @@ -438,7 +438,8 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) break; default: - /* segmented and/or full-duplex I/O request */ + /* segmented and/or full-duplex I/O request. + Note: Maximum support 511 n_ioc at a time */ if (_IOC_NR(cmd) != _IOC_NR(SPI_IOC_MESSAGE(0)) || _IOC_DIR(cmd) != _IOC_WRITE) { retval = -ENOTTY; @@ -452,7 +453,10 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) } n_ioc = tmp / sizeof(struct spi_ioc_transfer); if (n_ioc == 0) + { + dev_err(&spi->dev, "Value of n_ioc is out of range( 1 ~ 511 ).\n"); break; + } /* copy into scratch area */ ioc = kmalloc(tmp, GFP_KERNEL); |