* [PATCH v5 02/14] spi: qup: Setup DMA mode correctly
2017-07-24 7:47 [PATCH v5 00/14] spi: qup: Fixes and add support for >64k transfers Varadarajan Narayanan
@ 2017-07-24 7:47 ` Varadarajan Narayanan
[not found] ` <1500882445-29008-1-git-send-email-varada-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
` (5 subsequent siblings)
6 siblings, 0 replies; 43+ messages in thread
From: Varadarajan Narayanan @ 2017-07-24 7:47 UTC (permalink / raw)
To: broonie-DgEjT+Ai2ygdnm+yROfE0A, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
mark.rutland-5wv7dgnIgG8, andy.gross-QSEj5FYQhm4dnm+yROfE0A,
david.brown-QSEj5FYQhm4dnm+yROfE0A,
linux-spi-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-arm-msm-u79uwXL29TY76Z2rM5mHXA,
linux-soc-u79uwXL29TY76Z2rM5mHXA
Cc: Varadarajan Narayanan
To operate in DMA mode, the buffer should be aligned and
the size of the transfer should be a multiple of block size
(for v1). And the no. of words being transferred should
be programmed in the count registers appropriately.
Signed-off-by: Andy Gross <andy.gross-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Signed-off-by: Varadarajan Narayanan <varada-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
---
drivers/spi/spi-qup.c | 118 +++++++++++++++++++++++---------------------------
1 file changed, 55 insertions(+), 63 deletions(-)
diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c
index c0d4def..abe799b 100644
--- a/drivers/spi/spi-qup.c
+++ b/drivers/spi/spi-qup.c
@@ -149,11 +149,18 @@ struct spi_qup {
int rx_bytes;
int qup_v1;
- int use_dma;
+ int mode;
struct dma_slave_config rx_conf;
struct dma_slave_config tx_conf;
};
+static inline bool spi_qup_is_dma_xfer(int mode)
+{
+ if (mode == QUP_IO_M_MODE_DMOV || mode == QUP_IO_M_MODE_BAM)
+ return true;
+
+ return false;
+}
static inline bool spi_qup_is_valid_state(struct spi_qup *controller)
{
@@ -424,7 +431,7 @@ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id)
error = -EIO;
}
- if (!controller->use_dma) {
+ if (!spi_qup_is_dma_xfer(controller->mode)) {
if (opflags & QUP_OP_IN_SERVICE_FLAG)
spi_qup_fifo_read(controller, xfer);
@@ -443,34 +450,11 @@ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static u32
-spi_qup_get_mode(struct spi_master *master, struct spi_transfer *xfer)
-{
- struct spi_qup *qup = spi_master_get_devdata(master);
- u32 mode;
-
- qup->w_size = 4;
-
- if (xfer->bits_per_word <= 8)
- qup->w_size = 1;
- else if (xfer->bits_per_word <= 16)
- qup->w_size = 2;
-
- qup->n_words = xfer->len / qup->w_size;
-
- if (qup->n_words <= (qup->in_fifo_sz / sizeof(u32)))
- mode = QUP_IO_M_MODE_FIFO;
- else
- mode = QUP_IO_M_MODE_BLOCK;
-
- return mode;
-}
-
/* set clock freq ... bits per word */
static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer)
{
struct spi_qup *controller = spi_master_get_devdata(spi->master);
- u32 config, iomode, mode, control;
+ u32 config, iomode, control;
int ret, n_words;
if (spi->mode & SPI_LOOP && xfer->len > controller->in_fifo_sz) {
@@ -491,25 +475,30 @@ static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer)
return -EIO;
}
- mode = spi_qup_get_mode(spi->master, xfer);
+ controller->w_size = DIV_ROUND_UP(xfer->bits_per_word, 8);
+ controller->n_words = xfer->len / controller->w_size;
n_words = controller->n_words;
- if (mode == QUP_IO_M_MODE_FIFO) {
+ if (n_words <= (controller->in_fifo_sz / sizeof(u32))) {
+
+ controller->mode = QUP_IO_M_MODE_FIFO;
+
writel_relaxed(n_words, controller->base + QUP_MX_READ_CNT);
writel_relaxed(n_words, controller->base + QUP_MX_WRITE_CNT);
/* must be zero for FIFO */
writel_relaxed(0, controller->base + QUP_MX_INPUT_CNT);
writel_relaxed(0, controller->base + QUP_MX_OUTPUT_CNT);
- } else if (!controller->use_dma) {
+ } else if (spi->master->can_dma &&
+ spi->master->can_dma(spi->master, spi, xfer) &&
+ spi->master->cur_msg_mapped) {
+
+ controller->mode = QUP_IO_M_MODE_BAM;
+
writel_relaxed(n_words, controller->base + QUP_MX_INPUT_CNT);
writel_relaxed(n_words, controller->base + QUP_MX_OUTPUT_CNT);
/* must be zero for BLOCK and BAM */
writel_relaxed(0, controller->base + QUP_MX_READ_CNT);
writel_relaxed(0, controller->base + QUP_MX_WRITE_CNT);
- } else {
- mode = QUP_IO_M_MODE_BAM;
- writel_relaxed(0, controller->base + QUP_MX_READ_CNT);
- writel_relaxed(0, controller->base + QUP_MX_WRITE_CNT);
if (!controller->qup_v1) {
void __iomem *input_cnt;
@@ -528,19 +517,28 @@ static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer)
writel_relaxed(0, controller->base + QUP_MX_OUTPUT_CNT);
}
+ } else {
+
+ controller->mode = QUP_IO_M_MODE_BLOCK;
+
+ writel_relaxed(n_words, controller->base + QUP_MX_INPUT_CNT);
+ writel_relaxed(n_words, controller->base + QUP_MX_OUTPUT_CNT);
+ /* must be zero for BLOCK and BAM */
+ writel_relaxed(0, controller->base + QUP_MX_READ_CNT);
+ writel_relaxed(0, controller->base + QUP_MX_WRITE_CNT);
}
iomode = readl_relaxed(controller->base + QUP_IO_M_MODES);
/* Set input and output transfer mode */
iomode &= ~(QUP_IO_M_INPUT_MODE_MASK | QUP_IO_M_OUTPUT_MODE_MASK);
- if (!controller->use_dma)
+ if (!spi_qup_is_dma_xfer(controller->mode))
iomode &= ~(QUP_IO_M_PACK_EN | QUP_IO_M_UNPACK_EN);
else
iomode |= QUP_IO_M_PACK_EN | QUP_IO_M_UNPACK_EN;
- iomode |= (mode << QUP_IO_M_OUTPUT_MODE_MASK_SHIFT);
- iomode |= (mode << QUP_IO_M_INPUT_MODE_MASK_SHIFT);
+ iomode |= (controller->mode << QUP_IO_M_OUTPUT_MODE_MASK_SHIFT);
+ iomode |= (controller->mode << QUP_IO_M_INPUT_MODE_MASK_SHIFT);
writel_relaxed(iomode, controller->base + QUP_IO_M_MODES);
@@ -581,7 +579,7 @@ static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer)
config |= xfer->bits_per_word - 1;
config |= QUP_CONFIG_SPI_MODE;
- if (controller->use_dma) {
+ if (spi_qup_is_dma_xfer(controller->mode)) {
if (!xfer->tx_buf)
config |= QUP_CONFIG_NO_OUTPUT;
if (!xfer->rx_buf)
@@ -599,7 +597,7 @@ static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer)
* status change in BAM mode
*/
- if (mode == QUP_IO_M_MODE_BAM)
+ if (spi_qup_is_dma_xfer(controller->mode))
mask = QUP_OP_IN_SERVICE_FLAG | QUP_OP_OUT_SERVICE_FLAG;
writel_relaxed(mask, controller->base + QUP_OPERATIONAL_MASK);
@@ -633,7 +631,7 @@ static int spi_qup_transfer_one(struct spi_master *master,
controller->tx_bytes = 0;
spin_unlock_irqrestore(&controller->lock, flags);
- if (controller->use_dma)
+ if (spi_qup_is_dma_xfer(controller->mode))
ret = spi_qup_do_dma(master, xfer);
else
ret = spi_qup_do_pio(master, xfer);
@@ -641,14 +639,6 @@ static int spi_qup_transfer_one(struct spi_master *master,
if (ret)
goto exit;
- if (spi_qup_set_state(controller, QUP_STATE_RUN)) {
- dev_warn(controller->dev, "cannot set EXECUTE state\n");
- goto exit;
- }
-
- if (!wait_for_completion_timeout(&controller->done, timeout))
- ret = -ETIMEDOUT;
-
exit:
spi_qup_set_state(controller, QUP_STATE_RESET);
spin_lock_irqsave(&controller->lock, flags);
@@ -657,7 +647,7 @@ static int spi_qup_transfer_one(struct spi_master *master,
ret = controller->error;
spin_unlock_irqrestore(&controller->lock, flags);
- if (ret && controller->use_dma)
+ if (ret && spi_qup_is_dma_xfer(controller->mode))
spi_qup_dma_terminate(master, xfer);
return ret;
@@ -668,26 +658,28 @@ static bool spi_qup_can_dma(struct spi_master *master, struct spi_device *spi,
{
struct spi_qup *qup = spi_master_get_devdata(master);
size_t dma_align = dma_get_cache_alignment();
- u32 mode;
-
- qup->use_dma = 0;
+ int n_words;
- if (xfer->rx_buf && (xfer->len % qup->in_blk_sz ||
- IS_ERR_OR_NULL(master->dma_rx) ||
- !IS_ALIGNED((size_t)xfer->rx_buf, dma_align)))
- return false;
+ if (xfer->rx_buf) {
+ if (!IS_ALIGNED((size_t)xfer->rx_buf, dma_align) ||
+ IS_ERR_OR_NULL(master->dma_rx))
+ return false;
+ if (qup->qup_v1 && (xfer->len % qup->in_blk_sz))
+ return false;
+ }
- if (xfer->tx_buf && (xfer->len % qup->out_blk_sz ||
- IS_ERR_OR_NULL(master->dma_tx) ||
- !IS_ALIGNED((size_t)xfer->tx_buf, dma_align)))
- return false;
+ if (xfer->tx_buf) {
+ if (!IS_ALIGNED((size_t)xfer->tx_buf, dma_align) ||
+ IS_ERR_OR_NULL(master->dma_tx))
+ return false;
+ if (qup->qup_v1 && (xfer->len % qup->out_blk_sz))
+ return false;
+ }
- mode = spi_qup_get_mode(master, xfer);
- if (mode == QUP_IO_M_MODE_FIFO)
+ n_words = xfer->len / DIV_ROUND_UP(xfer->bits_per_word, 8);
+ if (n_words <= (qup->in_fifo_sz / sizeof(u32)))
return false;
- qup->use_dma = 1;
-
return true;
}
--
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [PATCH v5 02/14] spi: qup: Setup DMA mode correctly
@ 2017-07-24 7:47 ` Varadarajan Narayanan
0 siblings, 0 replies; 43+ messages in thread
From: Varadarajan Narayanan @ 2017-07-24 7:47 UTC (permalink / raw)
To: broonie, robh+dt, mark.rutland, andy.gross, david.brown,
linux-spi, devicetree, linux-kernel, linux-arm-msm, linux-soc
Cc: Varadarajan Narayanan
To operate in DMA mode, the buffer should be aligned and
the size of the transfer should be a multiple of block size
(for v1). And the no. of words being transferred should
be programmed in the count registers appropriately.
Signed-off-by: Andy Gross <andy.gross@linaro.org>
Signed-off-by: Varadarajan Narayanan <varada@codeaurora.org>
---
drivers/spi/spi-qup.c | 118 +++++++++++++++++++++++---------------------------
1 file changed, 55 insertions(+), 63 deletions(-)
diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c
index c0d4def..abe799b 100644
--- a/drivers/spi/spi-qup.c
+++ b/drivers/spi/spi-qup.c
@@ -149,11 +149,18 @@ struct spi_qup {
int rx_bytes;
int qup_v1;
- int use_dma;
+ int mode;
struct dma_slave_config rx_conf;
struct dma_slave_config tx_conf;
};
+static inline bool spi_qup_is_dma_xfer(int mode)
+{
+ if (mode == QUP_IO_M_MODE_DMOV || mode == QUP_IO_M_MODE_BAM)
+ return true;
+
+ return false;
+}
static inline bool spi_qup_is_valid_state(struct spi_qup *controller)
{
@@ -424,7 +431,7 @@ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id)
error = -EIO;
}
- if (!controller->use_dma) {
+ if (!spi_qup_is_dma_xfer(controller->mode)) {
if (opflags & QUP_OP_IN_SERVICE_FLAG)
spi_qup_fifo_read(controller, xfer);
@@ -443,34 +450,11 @@ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static u32
-spi_qup_get_mode(struct spi_master *master, struct spi_transfer *xfer)
-{
- struct spi_qup *qup = spi_master_get_devdata(master);
- u32 mode;
-
- qup->w_size = 4;
-
- if (xfer->bits_per_word <= 8)
- qup->w_size = 1;
- else if (xfer->bits_per_word <= 16)
- qup->w_size = 2;
-
- qup->n_words = xfer->len / qup->w_size;
-
- if (qup->n_words <= (qup->in_fifo_sz / sizeof(u32)))
- mode = QUP_IO_M_MODE_FIFO;
- else
- mode = QUP_IO_M_MODE_BLOCK;
-
- return mode;
-}
-
/* set clock freq ... bits per word */
static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer)
{
struct spi_qup *controller = spi_master_get_devdata(spi->master);
- u32 config, iomode, mode, control;
+ u32 config, iomode, control;
int ret, n_words;
if (spi->mode & SPI_LOOP && xfer->len > controller->in_fifo_sz) {
@@ -491,25 +475,30 @@ static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer)
return -EIO;
}
- mode = spi_qup_get_mode(spi->master, xfer);
+ controller->w_size = DIV_ROUND_UP(xfer->bits_per_word, 8);
+ controller->n_words = xfer->len / controller->w_size;
n_words = controller->n_words;
- if (mode == QUP_IO_M_MODE_FIFO) {
+ if (n_words <= (controller->in_fifo_sz / sizeof(u32))) {
+
+ controller->mode = QUP_IO_M_MODE_FIFO;
+
writel_relaxed(n_words, controller->base + QUP_MX_READ_CNT);
writel_relaxed(n_words, controller->base + QUP_MX_WRITE_CNT);
/* must be zero for FIFO */
writel_relaxed(0, controller->base + QUP_MX_INPUT_CNT);
writel_relaxed(0, controller->base + QUP_MX_OUTPUT_CNT);
- } else if (!controller->use_dma) {
+ } else if (spi->master->can_dma &&
+ spi->master->can_dma(spi->master, spi, xfer) &&
+ spi->master->cur_msg_mapped) {
+
+ controller->mode = QUP_IO_M_MODE_BAM;
+
writel_relaxed(n_words, controller->base + QUP_MX_INPUT_CNT);
writel_relaxed(n_words, controller->base + QUP_MX_OUTPUT_CNT);
/* must be zero for BLOCK and BAM */
writel_relaxed(0, controller->base + QUP_MX_READ_CNT);
writel_relaxed(0, controller->base + QUP_MX_WRITE_CNT);
- } else {
- mode = QUP_IO_M_MODE_BAM;
- writel_relaxed(0, controller->base + QUP_MX_READ_CNT);
- writel_relaxed(0, controller->base + QUP_MX_WRITE_CNT);
if (!controller->qup_v1) {
void __iomem *input_cnt;
@@ -528,19 +517,28 @@ static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer)
writel_relaxed(0, controller->base + QUP_MX_OUTPUT_CNT);
}
+ } else {
+
+ controller->mode = QUP_IO_M_MODE_BLOCK;
+
+ writel_relaxed(n_words, controller->base + QUP_MX_INPUT_CNT);
+ writel_relaxed(n_words, controller->base + QUP_MX_OUTPUT_CNT);
+ /* must be zero for BLOCK and BAM */
+ writel_relaxed(0, controller->base + QUP_MX_READ_CNT);
+ writel_relaxed(0, controller->base + QUP_MX_WRITE_CNT);
}
iomode = readl_relaxed(controller->base + QUP_IO_M_MODES);
/* Set input and output transfer mode */
iomode &= ~(QUP_IO_M_INPUT_MODE_MASK | QUP_IO_M_OUTPUT_MODE_MASK);
- if (!controller->use_dma)
+ if (!spi_qup_is_dma_xfer(controller->mode))
iomode &= ~(QUP_IO_M_PACK_EN | QUP_IO_M_UNPACK_EN);
else
iomode |= QUP_IO_M_PACK_EN | QUP_IO_M_UNPACK_EN;
- iomode |= (mode << QUP_IO_M_OUTPUT_MODE_MASK_SHIFT);
- iomode |= (mode << QUP_IO_M_INPUT_MODE_MASK_SHIFT);
+ iomode |= (controller->mode << QUP_IO_M_OUTPUT_MODE_MASK_SHIFT);
+ iomode |= (controller->mode << QUP_IO_M_INPUT_MODE_MASK_SHIFT);
writel_relaxed(iomode, controller->base + QUP_IO_M_MODES);
@@ -581,7 +579,7 @@ static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer)
config |= xfer->bits_per_word - 1;
config |= QUP_CONFIG_SPI_MODE;
- if (controller->use_dma) {
+ if (spi_qup_is_dma_xfer(controller->mode)) {
if (!xfer->tx_buf)
config |= QUP_CONFIG_NO_OUTPUT;
if (!xfer->rx_buf)
@@ -599,7 +597,7 @@ static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer)
* status change in BAM mode
*/
- if (mode == QUP_IO_M_MODE_BAM)
+ if (spi_qup_is_dma_xfer(controller->mode))
mask = QUP_OP_IN_SERVICE_FLAG | QUP_OP_OUT_SERVICE_FLAG;
writel_relaxed(mask, controller->base + QUP_OPERATIONAL_MASK);
@@ -633,7 +631,7 @@ static int spi_qup_transfer_one(struct spi_master *master,
controller->tx_bytes = 0;
spin_unlock_irqrestore(&controller->lock, flags);
- if (controller->use_dma)
+ if (spi_qup_is_dma_xfer(controller->mode))
ret = spi_qup_do_dma(master, xfer);
else
ret = spi_qup_do_pio(master, xfer);
@@ -641,14 +639,6 @@ static int spi_qup_transfer_one(struct spi_master *master,
if (ret)
goto exit;
- if (spi_qup_set_state(controller, QUP_STATE_RUN)) {
- dev_warn(controller->dev, "cannot set EXECUTE state\n");
- goto exit;
- }
-
- if (!wait_for_completion_timeout(&controller->done, timeout))
- ret = -ETIMEDOUT;
-
exit:
spi_qup_set_state(controller, QUP_STATE_RESET);
spin_lock_irqsave(&controller->lock, flags);
@@ -657,7 +647,7 @@ static int spi_qup_transfer_one(struct spi_master *master,
ret = controller->error;
spin_unlock_irqrestore(&controller->lock, flags);
- if (ret && controller->use_dma)
+ if (ret && spi_qup_is_dma_xfer(controller->mode))
spi_qup_dma_terminate(master, xfer);
return ret;
@@ -668,26 +658,28 @@ static bool spi_qup_can_dma(struct spi_master *master, struct spi_device *spi,
{
struct spi_qup *qup = spi_master_get_devdata(master);
size_t dma_align = dma_get_cache_alignment();
- u32 mode;
-
- qup->use_dma = 0;
+ int n_words;
- if (xfer->rx_buf && (xfer->len % qup->in_blk_sz ||
- IS_ERR_OR_NULL(master->dma_rx) ||
- !IS_ALIGNED((size_t)xfer->rx_buf, dma_align)))
- return false;
+ if (xfer->rx_buf) {
+ if (!IS_ALIGNED((size_t)xfer->rx_buf, dma_align) ||
+ IS_ERR_OR_NULL(master->dma_rx))
+ return false;
+ if (qup->qup_v1 && (xfer->len % qup->in_blk_sz))
+ return false;
+ }
- if (xfer->tx_buf && (xfer->len % qup->out_blk_sz ||
- IS_ERR_OR_NULL(master->dma_tx) ||
- !IS_ALIGNED((size_t)xfer->tx_buf, dma_align)))
- return false;
+ if (xfer->tx_buf) {
+ if (!IS_ALIGNED((size_t)xfer->tx_buf, dma_align) ||
+ IS_ERR_OR_NULL(master->dma_tx))
+ return false;
+ if (qup->qup_v1 && (xfer->len % qup->out_blk_sz))
+ return false;
+ }
- mode = spi_qup_get_mode(master, xfer);
- if (mode == QUP_IO_M_MODE_FIFO)
+ n_words = xfer->len / DIV_ROUND_UP(xfer->bits_per_word, 8);
+ if (n_words <= (qup->in_fifo_sz / sizeof(u32)))
return false;
- qup->use_dma = 1;
-
return true;
}
--
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [PATCH v5 03/14] spi: qup: Add completion timeout
2017-07-24 7:47 [PATCH v5 00/14] spi: qup: Fixes and add support for >64k transfers Varadarajan Narayanan
@ 2017-07-24 7:47 ` Varadarajan Narayanan
[not found] ` <1500882445-29008-1-git-send-email-varada-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
` (5 subsequent siblings)
6 siblings, 0 replies; 43+ messages in thread
From: Varadarajan Narayanan @ 2017-07-24 7:47 UTC (permalink / raw)
To: broonie-DgEjT+Ai2ygdnm+yROfE0A, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
mark.rutland-5wv7dgnIgG8, andy.gross-QSEj5FYQhm4dnm+yROfE0A,
david.brown-QSEj5FYQhm4dnm+yROfE0A,
linux-spi-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-arm-msm-u79uwXL29TY76Z2rM5mHXA,
linux-soc-u79uwXL29TY76Z2rM5mHXA
Cc: Varadarajan Narayanan
Add i/o completion timeout for DMA and PIO modes.
Signed-off-by: Andy Gross <andy.gross-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Signed-off-by: Varadarajan Narayanan <varada-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
---
drivers/spi/spi-qup.c | 19 +++++++++++++++----
1 file changed, 15 insertions(+), 4 deletions(-)
diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c
index abe799b..92922b6 100644
--- a/drivers/spi/spi-qup.c
+++ b/drivers/spi/spi-qup.c
@@ -331,7 +331,8 @@ static void spi_qup_dma_terminate(struct spi_master *master,
dmaengine_terminate_all(master->dma_rx);
}
-static int spi_qup_do_dma(struct spi_master *master, struct spi_transfer *xfer)
+static int spi_qup_do_dma(struct spi_master *master, struct spi_transfer *xfer,
+ unsigned long timeout)
{
dma_async_tx_callback rx_done = NULL, tx_done = NULL;
int ret;
@@ -357,10 +358,17 @@ static int spi_qup_do_dma(struct spi_master *master, struct spi_transfer *xfer)
dma_async_issue_pending(master->dma_tx);
}
+ if (rx_done && !wait_for_completion_timeout(&qup->done, timeout))
+ return -ETIMEDOUT;
+
+ if (tx_done && !wait_for_completion_timeout(&qup->done, timeout))
+ return -ETIMEDOUT;
+
return 0;
}
-static int spi_qup_do_pio(struct spi_master *master, struct spi_transfer *xfer)
+static int spi_qup_do_pio(struct spi_master *master, struct spi_transfer *xfer,
+ unsigned long timeout)
{
struct spi_qup *qup = spi_master_get_devdata(master);
int ret;
@@ -379,6 +387,9 @@ static int spi_qup_do_pio(struct spi_master *master, struct spi_transfer *xfer)
spi_qup_fifo_write(qup, xfer);
+ if (!wait_for_completion_timeout(&qup->done, timeout))
+ return -ETIMEDOUT;
+
return 0;
}
@@ -632,9 +643,9 @@ static int spi_qup_transfer_one(struct spi_master *master,
spin_unlock_irqrestore(&controller->lock, flags);
if (spi_qup_is_dma_xfer(controller->mode))
- ret = spi_qup_do_dma(master, xfer);
+ ret = spi_qup_do_dma(master, xfer, timeout);
else
- ret = spi_qup_do_pio(master, xfer);
+ ret = spi_qup_do_pio(master, xfer, timeout);
if (ret)
goto exit;
--
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [PATCH v5 03/14] spi: qup: Add completion timeout
@ 2017-07-24 7:47 ` Varadarajan Narayanan
0 siblings, 0 replies; 43+ messages in thread
From: Varadarajan Narayanan @ 2017-07-24 7:47 UTC (permalink / raw)
To: broonie, robh+dt, mark.rutland, andy.gross, david.brown,
linux-spi, devicetree, linux-kernel, linux-arm-msm, linux-soc
Cc: Varadarajan Narayanan
Add i/o completion timeout for DMA and PIO modes.
Signed-off-by: Andy Gross <andy.gross@linaro.org>
Signed-off-by: Varadarajan Narayanan <varada@codeaurora.org>
---
drivers/spi/spi-qup.c | 19 +++++++++++++++----
1 file changed, 15 insertions(+), 4 deletions(-)
diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c
index abe799b..92922b6 100644
--- a/drivers/spi/spi-qup.c
+++ b/drivers/spi/spi-qup.c
@@ -331,7 +331,8 @@ static void spi_qup_dma_terminate(struct spi_master *master,
dmaengine_terminate_all(master->dma_rx);
}
-static int spi_qup_do_dma(struct spi_master *master, struct spi_transfer *xfer)
+static int spi_qup_do_dma(struct spi_master *master, struct spi_transfer *xfer,
+ unsigned long timeout)
{
dma_async_tx_callback rx_done = NULL, tx_done = NULL;
int ret;
@@ -357,10 +358,17 @@ static int spi_qup_do_dma(struct spi_master *master, struct spi_transfer *xfer)
dma_async_issue_pending(master->dma_tx);
}
+ if (rx_done && !wait_for_completion_timeout(&qup->done, timeout))
+ return -ETIMEDOUT;
+
+ if (tx_done && !wait_for_completion_timeout(&qup->done, timeout))
+ return -ETIMEDOUT;
+
return 0;
}
-static int spi_qup_do_pio(struct spi_master *master, struct spi_transfer *xfer)
+static int spi_qup_do_pio(struct spi_master *master, struct spi_transfer *xfer,
+ unsigned long timeout)
{
struct spi_qup *qup = spi_master_get_devdata(master);
int ret;
@@ -379,6 +387,9 @@ static int spi_qup_do_pio(struct spi_master *master, struct spi_transfer *xfer)
spi_qup_fifo_write(qup, xfer);
+ if (!wait_for_completion_timeout(&qup->done, timeout))
+ return -ETIMEDOUT;
+
return 0;
}
@@ -632,9 +643,9 @@ static int spi_qup_transfer_one(struct spi_master *master,
spin_unlock_irqrestore(&controller->lock, flags);
if (spi_qup_is_dma_xfer(controller->mode))
- ret = spi_qup_do_dma(master, xfer);
+ ret = spi_qup_do_dma(master, xfer, timeout);
else
- ret = spi_qup_do_pio(master, xfer);
+ ret = spi_qup_do_pio(master, xfer, timeout);
if (ret)
goto exit;
--
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
^ permalink raw reply related [flat|nested] 43+ messages in thread
* Re: [PATCH v5 03/14] spi: qup: Add completion timeout
2017-07-24 7:47 ` Varadarajan Narayanan
@ 2017-07-27 8:30 ` kbuild test robot
-1 siblings, 0 replies; 43+ messages in thread
From: kbuild test robot @ 2017-07-27 8:30 UTC (permalink / raw)
Cc: kbuild-all, broonie, robh+dt, mark.rutland, andy.gross,
david.brown, linux-spi, devicetree, linux-kernel, linux-arm-msm,
linux-soc, Varadarajan Narayanan
[-- Attachment #1: Type: text/plain, Size: 2657 bytes --]
Hi Varadarajan,
[auto build test ERROR on spi/for-next]
[also build test ERROR on v4.13-rc2 next-20170726]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
url: https://github.com/0day-ci/linux/commits/Varadarajan-Narayanan/spi-qup-Fixes-and-add-support-for-64k-transfers/20170725-033101
base: https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git for-next
config: arm64-defconfig (attached as .config)
compiler: aarch64-linux-gnu-gcc (Debian 6.1.1-9) 6.1.1 20160705
reproduce:
wget https://raw.githubusercontent.com/01org/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
make.cross ARCH=arm64
Note: the linux-review/Varadarajan-Narayanan/spi-qup-Fixes-and-add-support-for-64k-transfers/20170725-033101 HEAD 88e143f949247832b744d84f5163033eaba09abc builds fine.
It only hurts bisectibility.
All errors (new ones prefixed by >>):
drivers//spi/spi-qup.c: In function 'spi_qup_do_dma':
>> drivers//spi/spi-qup.c:361:47: error: 'qup' undeclared (first use in this function)
if (rx_done && !wait_for_completion_timeout(&qup->done, timeout))
^~~
drivers//spi/spi-qup.c:361:47: note: each undeclared identifier is reported only once for each function it appears in
vim +/qup +361 drivers//spi/spi-qup.c
333
334 static int spi_qup_do_dma(struct spi_master *master, struct spi_transfer *xfer,
335 unsigned long timeout)
336 {
337 dma_async_tx_callback rx_done = NULL, tx_done = NULL;
338 int ret;
339
340 if (xfer->rx_buf)
341 rx_done = spi_qup_dma_done;
342 else if (xfer->tx_buf)
343 tx_done = spi_qup_dma_done;
344
345 if (xfer->rx_buf) {
346 ret = spi_qup_prep_sg(master, xfer, DMA_DEV_TO_MEM, rx_done);
347 if (ret)
348 return ret;
349
350 dma_async_issue_pending(master->dma_rx);
351 }
352
353 if (xfer->tx_buf) {
354 ret = spi_qup_prep_sg(master, xfer, DMA_MEM_TO_DEV, tx_done);
355 if (ret)
356 return ret;
357
358 dma_async_issue_pending(master->dma_tx);
359 }
360
> 361 if (rx_done && !wait_for_completion_timeout(&qup->done, timeout))
362 return -ETIMEDOUT;
363
364 if (tx_done && !wait_for_completion_timeout(&qup->done, timeout))
365 return -ETIMEDOUT;
366
367 return 0;
368 }
369
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 36296 bytes --]
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH v5 03/14] spi: qup: Add completion timeout
@ 2017-07-27 8:30 ` kbuild test robot
0 siblings, 0 replies; 43+ messages in thread
From: kbuild test robot @ 2017-07-27 8:30 UTC (permalink / raw)
To: Varadarajan Narayanan
Cc: kbuild-all, broonie, robh+dt, mark.rutland, andy.gross,
david.brown, linux-spi, devicetree, linux-kernel, linux-arm-msm,
linux-soc, Varadarajan Narayanan
[-- Attachment #1: Type: text/plain, Size: 2657 bytes --]
Hi Varadarajan,
[auto build test ERROR on spi/for-next]
[also build test ERROR on v4.13-rc2 next-20170726]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
url: https://github.com/0day-ci/linux/commits/Varadarajan-Narayanan/spi-qup-Fixes-and-add-support-for-64k-transfers/20170725-033101
base: https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git for-next
config: arm64-defconfig (attached as .config)
compiler: aarch64-linux-gnu-gcc (Debian 6.1.1-9) 6.1.1 20160705
reproduce:
wget https://raw.githubusercontent.com/01org/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
make.cross ARCH=arm64
Note: the linux-review/Varadarajan-Narayanan/spi-qup-Fixes-and-add-support-for-64k-transfers/20170725-033101 HEAD 88e143f949247832b744d84f5163033eaba09abc builds fine.
It only hurts bisectibility.
All errors (new ones prefixed by >>):
drivers//spi/spi-qup.c: In function 'spi_qup_do_dma':
>> drivers//spi/spi-qup.c:361:47: error: 'qup' undeclared (first use in this function)
if (rx_done && !wait_for_completion_timeout(&qup->done, timeout))
^~~
drivers//spi/spi-qup.c:361:47: note: each undeclared identifier is reported only once for each function it appears in
vim +/qup +361 drivers//spi/spi-qup.c
333
334 static int spi_qup_do_dma(struct spi_master *master, struct spi_transfer *xfer,
335 unsigned long timeout)
336 {
337 dma_async_tx_callback rx_done = NULL, tx_done = NULL;
338 int ret;
339
340 if (xfer->rx_buf)
341 rx_done = spi_qup_dma_done;
342 else if (xfer->tx_buf)
343 tx_done = spi_qup_dma_done;
344
345 if (xfer->rx_buf) {
346 ret = spi_qup_prep_sg(master, xfer, DMA_DEV_TO_MEM, rx_done);
347 if (ret)
348 return ret;
349
350 dma_async_issue_pending(master->dma_rx);
351 }
352
353 if (xfer->tx_buf) {
354 ret = spi_qup_prep_sg(master, xfer, DMA_MEM_TO_DEV, tx_done);
355 if (ret)
356 return ret;
357
358 dma_async_issue_pending(master->dma_tx);
359 }
360
> 361 if (rx_done && !wait_for_completion_timeout(&qup->done, timeout))
362 return -ETIMEDOUT;
363
364 if (tx_done && !wait_for_completion_timeout(&qup->done, timeout))
365 return -ETIMEDOUT;
366
367 return 0;
368 }
369
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 36296 bytes --]
^ permalink raw reply [flat|nested] 43+ messages in thread
* [PATCH v5 05/14] spi: qup: Fix error handling in spi_qup_prep_sg
2017-07-24 7:47 [PATCH v5 00/14] spi: qup: Fixes and add support for >64k transfers Varadarajan Narayanan
@ 2017-07-24 7:47 ` Varadarajan Narayanan
[not found] ` <1500882445-29008-1-git-send-email-varada-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
` (5 subsequent siblings)
6 siblings, 0 replies; 43+ messages in thread
From: Varadarajan Narayanan @ 2017-07-24 7:47 UTC (permalink / raw)
To: broonie-DgEjT+Ai2ygdnm+yROfE0A, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
mark.rutland-5wv7dgnIgG8, andy.gross-QSEj5FYQhm4dnm+yROfE0A,
david.brown-QSEj5FYQhm4dnm+yROfE0A,
linux-spi-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-arm-msm-u79uwXL29TY76Z2rM5mHXA,
linux-soc-u79uwXL29TY76Z2rM5mHXA
Cc: Varadarajan Narayanan
Signed-off-by: Varadarajan Narayanan <varada-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
---
drivers/spi/spi-qup.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c
index e6294f8..aa1b7b8 100644
--- a/drivers/spi/spi-qup.c
+++ b/drivers/spi/spi-qup.c
@@ -311,8 +311,8 @@ static int spi_qup_prep_sg(struct spi_master *master, struct spi_transfer *xfer,
}
desc = dmaengine_prep_slave_sg(chan, sgl, nents, dir, flags);
- if (!desc)
- return -EINVAL;
+ if (IS_ERR_OR_NULL(desc))
+ return desc ? PTR_ERR(desc) : -EINVAL;
desc->callback = callback;
desc->callback_param = qup;
--
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [PATCH v5 05/14] spi: qup: Fix error handling in spi_qup_prep_sg
@ 2017-07-24 7:47 ` Varadarajan Narayanan
0 siblings, 0 replies; 43+ messages in thread
From: Varadarajan Narayanan @ 2017-07-24 7:47 UTC (permalink / raw)
To: broonie, robh+dt, mark.rutland, andy.gross, david.brown,
linux-spi, devicetree, linux-kernel, linux-arm-msm, linux-soc
Cc: Varadarajan Narayanan
Signed-off-by: Varadarajan Narayanan <varada@codeaurora.org>
---
drivers/spi/spi-qup.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c
index e6294f8..aa1b7b8 100644
--- a/drivers/spi/spi-qup.c
+++ b/drivers/spi/spi-qup.c
@@ -311,8 +311,8 @@ static int spi_qup_prep_sg(struct spi_master *master, struct spi_transfer *xfer,
}
desc = dmaengine_prep_slave_sg(chan, sgl, nents, dir, flags);
- if (!desc)
- return -EINVAL;
+ if (IS_ERR_OR_NULL(desc))
+ return desc ? PTR_ERR(desc) : -EINVAL;
desc->callback = callback;
desc->callback_param = qup;
--
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
^ permalink raw reply related [flat|nested] 43+ messages in thread
* Applied "spi: qup: Fix error handling in spi_qup_prep_sg" to the spi tree
2017-07-24 7:47 ` Varadarajan Narayanan
@ 2017-08-08 11:18 ` Mark Brown
-1 siblings, 0 replies; 43+ messages in thread
From: Mark Brown @ 2017-08-08 11:18 UTC (permalink / raw)
To: Varadarajan Narayanan; +Cc: Mark Brown
The patch
spi: qup: Fix error handling in spi_qup_prep_sg
has been applied to the spi tree at
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git
All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying
to this mail.
Thanks,
Mark
>From d9a09a6c0c98d57e5a248c3b9bb10f63d475dfdb Mon Sep 17 00:00:00 2001
From: Varadarajan Narayanan <varada@codeaurora.org>
Date: Fri, 28 Jul 2017 12:22:52 +0530
Subject: [PATCH] spi: qup: Fix error handling in spi_qup_prep_sg
Signed-off-by: Varadarajan Narayanan <varada@codeaurora.org>
Signed-off-by: Mark Brown <broonie@kernel.org>
---
drivers/spi/spi-qup.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c
index f1aa5c15d180..ef952946375a 100644
--- a/drivers/spi/spi-qup.c
+++ b/drivers/spi/spi-qup.c
@@ -311,8 +311,8 @@ static int spi_qup_prep_sg(struct spi_master *master, struct spi_transfer *xfer,
}
desc = dmaengine_prep_slave_sg(chan, sgl, nents, dir, flags);
- if (!desc)
- return -EINVAL;
+ if (IS_ERR_OR_NULL(desc))
+ return desc ? PTR_ERR(desc) : -EINVAL;
desc->callback = callback;
desc->callback_param = qup;
--
2.13.2
^ permalink raw reply related [flat|nested] 43+ messages in thread
* Applied "spi: qup: Fix error handling in spi_qup_prep_sg" to the spi tree
@ 2017-08-08 11:18 ` Mark Brown
0 siblings, 0 replies; 43+ messages in thread
From: Mark Brown @ 2017-08-08 11:18 UTC (permalink / raw)
To: Varadarajan Narayanan
Cc: Mark Brown, broonie, robh+dt, mark.rutland, andy.gross,
david.brown, linux-spi, devicetree, linux-kernel, linux-arm-msm,
linux-soc, linux-spi
The patch
spi: qup: Fix error handling in spi_qup_prep_sg
has been applied to the spi tree at
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git
All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying
to this mail.
Thanks,
Mark
>From d9a09a6c0c98d57e5a248c3b9bb10f63d475dfdb Mon Sep 17 00:00:00 2001
From: Varadarajan Narayanan <varada@codeaurora.org>
Date: Fri, 28 Jul 2017 12:22:52 +0530
Subject: [PATCH] spi: qup: Fix error handling in spi_qup_prep_sg
Signed-off-by: Varadarajan Narayanan <varada@codeaurora.org>
Signed-off-by: Mark Brown <broonie@kernel.org>
---
drivers/spi/spi-qup.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c
index f1aa5c15d180..ef952946375a 100644
--- a/drivers/spi/spi-qup.c
+++ b/drivers/spi/spi-qup.c
@@ -311,8 +311,8 @@ static int spi_qup_prep_sg(struct spi_master *master, struct spi_transfer *xfer,
}
desc = dmaengine_prep_slave_sg(chan, sgl, nents, dir, flags);
- if (!desc)
- return -EINVAL;
+ if (IS_ERR_OR_NULL(desc))
+ return desc ? PTR_ERR(desc) : -EINVAL;
desc->callback = callback;
desc->callback_param = qup;
--
2.13.2
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [PATCH v5 07/14] spi: qup: Do block sized read/write in block mode
2017-07-24 7:47 [PATCH v5 00/14] spi: qup: Fixes and add support for >64k transfers Varadarajan Narayanan
@ 2017-07-24 7:47 ` Varadarajan Narayanan
[not found] ` <1500882445-29008-1-git-send-email-varada-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
` (5 subsequent siblings)
6 siblings, 0 replies; 43+ messages in thread
From: Varadarajan Narayanan @ 2017-07-24 7:47 UTC (permalink / raw)
To: broonie-DgEjT+Ai2ygdnm+yROfE0A, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
mark.rutland-5wv7dgnIgG8, andy.gross-QSEj5FYQhm4dnm+yROfE0A,
david.brown-QSEj5FYQhm4dnm+yROfE0A,
linux-spi-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-arm-msm-u79uwXL29TY76Z2rM5mHXA,
linux-soc-u79uwXL29TY76Z2rM5mHXA
Cc: Varadarajan Narayanan
This patch corrects the behavior of the BLOCK
transactions. During block transactions, the controller
must be read/written to in block size transactions.
Signed-off-by: Andy Gross <andy.gross-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Signed-off-by: Varadarajan Narayanan <varada-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
---
drivers/spi/spi-qup.c | 151 +++++++++++++++++++++++++++++++++++++++-----------
1 file changed, 119 insertions(+), 32 deletions(-)
diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c
index 5e6f7e5..d819f87 100644
--- a/drivers/spi/spi-qup.c
+++ b/drivers/spi/spi-qup.c
@@ -82,6 +82,8 @@
#define QUP_IO_M_MODE_BAM 3
/* QUP_OPERATIONAL fields */
+#define QUP_OP_IN_BLOCK_READ_REQ BIT(13)
+#define QUP_OP_OUT_BLOCK_WRITE_REQ BIT(12)
#define QUP_OP_MAX_INPUT_DONE_FLAG BIT(11)
#define QUP_OP_MAX_OUTPUT_DONE_FLAG BIT(10)
#define QUP_OP_IN_SERVICE_FLAG BIT(9)
@@ -154,6 +156,13 @@ struct spi_qup {
struct dma_slave_config tx_conf;
};
+static inline bool spi_qup_is_flag_set(struct spi_qup *controller, u32 flag)
+{
+ u32 opflag = readl_relaxed(controller->base + QUP_OPERATIONAL);
+
+ return (opflag & flag) != 0;
+}
+
static inline bool spi_qup_is_dma_xfer(int mode)
{
if (mode == QUP_IO_M_MODE_DMOV || mode == QUP_IO_M_MODE_BAM)
@@ -214,29 +223,26 @@ static int spi_qup_set_state(struct spi_qup *controller, u32 state)
return 0;
}
-static void spi_qup_fifo_read(struct spi_qup *controller,
- struct spi_transfer *xfer)
+static void spi_qup_read_from_fifo(struct spi_qup *controller,
+ struct spi_transfer *xfer, u32 num_words)
{
u8 *rx_buf = xfer->rx_buf;
- u32 word, state;
- int idx, shift, w_size;
+ int i, shift, num_bytes;
+ u32 word;
- w_size = controller->w_size;
-
- while (controller->rx_bytes < xfer->len) {
-
- state = readl_relaxed(controller->base + QUP_OPERATIONAL);
- if (0 == (state & QUP_OP_IN_FIFO_NOT_EMPTY))
- break;
+ for (; num_words; num_words--) {
word = readl_relaxed(controller->base + QUP_INPUT_FIFO);
+ num_bytes = min_t(int, xfer->len - controller->rx_bytes,
+ controller->w_size);
+
if (!rx_buf) {
- controller->rx_bytes += w_size;
+ controller->rx_bytes += num_bytes;
continue;
}
- for (idx = 0; idx < w_size; idx++, controller->rx_bytes++) {
+ for (i = 0; i < num_bytes; i++, controller->rx_bytes++) {
/*
* The data format depends on bytes per SPI word:
* 4 bytes: 0x12345678
@@ -244,38 +250,80 @@ static void spi_qup_fifo_read(struct spi_qup *controller,
* 1 byte : 0x00000012
*/
shift = BITS_PER_BYTE;
- shift *= (w_size - idx - 1);
+ shift *= (controller->w_size - i - 1);
rx_buf[controller->rx_bytes] = word >> shift;
}
}
}
-static void spi_qup_fifo_write(struct spi_qup *controller,
+static void spi_qup_read(struct spi_qup *controller,
struct spi_transfer *xfer)
{
- const u8 *tx_buf = xfer->tx_buf;
- u32 word, state, data;
- int idx, w_size;
+ u32 remainder, words_per_block, num_words;
+ bool is_block_mode = controller->mode == QUP_IO_M_MODE_BLOCK;
+
+ remainder = DIV_ROUND_UP(xfer->len - controller->rx_bytes,
+ controller->w_size);
+ words_per_block = controller->in_blk_sz >> 2;
+
+ do {
+ /* ACK by clearing service flag */
+ writel_relaxed(QUP_OP_IN_SERVICE_FLAG,
+ controller->base + QUP_OPERATIONAL);
+
+ if (is_block_mode) {
+ num_words = (remainder > words_per_block) ?
+ words_per_block : remainder;
+ } else {
+ if (!spi_qup_is_flag_set(controller,
+ QUP_OP_IN_FIFO_NOT_EMPTY))
+ break;
- w_size = controller->w_size;
+ num_words = 1;
+ }
- while (controller->tx_bytes < xfer->len) {
+ /* read up to the maximum transfer size available */
+ spi_qup_read_from_fifo(controller, xfer, num_words);
- state = readl_relaxed(controller->base + QUP_OPERATIONAL);
- if (state & QUP_OP_OUT_FIFO_FULL)
+ remainder -= num_words;
+
+ /* if block mode, check to see if next block is available */
+ if (is_block_mode && !spi_qup_is_flag_set(controller,
+ QUP_OP_IN_BLOCK_READ_REQ))
break;
+ } while (remainder);
+
+ /*
+ * Due to extra stickiness of the QUP_OP_IN_SERVICE_FLAG during block
+ * mode reads, it has to be cleared again at the very end
+ */
+ if (is_block_mode && spi_qup_is_flag_set(controller,
+ QUP_OP_MAX_INPUT_DONE_FLAG))
+ writel_relaxed(QUP_OP_IN_SERVICE_FLAG,
+ controller->base + QUP_OPERATIONAL);
+
+}
+
+static void spi_qup_write_to_fifo(struct spi_qup *controller,
+ struct spi_transfer *xfer, u32 num_words)
+{
+ const u8 *tx_buf = xfer->tx_buf;
+ int i, num_bytes;
+ u32 word, data;
+
+ for (; num_words; num_words--) {
word = 0;
- for (idx = 0; idx < w_size; idx++, controller->tx_bytes++) {
- if (!tx_buf) {
- controller->tx_bytes += w_size;
- break;
+ num_bytes = min_t(int, xfer->len - controller->tx_bytes,
+ controller->w_size);
+ if (tx_buf)
+ for (i = 0; i < num_bytes; i++) {
+ data = tx_buf[controller->tx_bytes + i];
+ word |= data << (BITS_PER_BYTE * (3 - i));
}
- data = tx_buf[controller->tx_bytes];
- word |= data << (BITS_PER_BYTE * (3 - idx));
- }
+ controller->tx_bytes += num_bytes;
writel_relaxed(word, controller->base + QUP_OUTPUT_FIFO);
}
@@ -288,6 +336,44 @@ static void spi_qup_dma_done(void *data)
complete(&qup->done);
}
+static void spi_qup_write(struct spi_qup *controller,
+ struct spi_transfer *xfer)
+{
+ bool is_block_mode = controller->mode == QUP_IO_M_MODE_BLOCK;
+ u32 remainder, words_per_block, num_words;
+
+ remainder = DIV_ROUND_UP(xfer->len - controller->tx_bytes,
+ controller->w_size);
+ words_per_block = controller->out_blk_sz >> 2;
+
+ do {
+ /* ACK by clearing service flag */
+ writel_relaxed(QUP_OP_OUT_SERVICE_FLAG,
+ controller->base + QUP_OPERATIONAL);
+
+ if (is_block_mode) {
+ num_words = (remainder > words_per_block) ?
+ words_per_block : remainder;
+ } else {
+ if (spi_qup_is_flag_set(controller,
+ QUP_OP_OUT_FIFO_FULL))
+ break;
+
+ num_words = 1;
+ }
+
+ spi_qup_write_to_fifo(controller, xfer, num_words);
+
+ remainder -= num_words;
+
+ /* if block mode, check to see if next block is available */
+ if (is_block_mode && !spi_qup_is_flag_set(controller,
+ QUP_OP_OUT_BLOCK_WRITE_REQ))
+ break;
+
+ } while (remainder);
+}
+
static int spi_qup_prep_sg(struct spi_master *master, struct spi_transfer *xfer,
enum dma_transfer_direction dir,
dma_async_tx_callback callback)
@@ -393,7 +479,8 @@ static int spi_qup_do_pio(struct spi_master *master, struct spi_transfer *xfer,
return ret;
}
- spi_qup_fifo_write(qup, xfer);
+ if (qup->mode == QUP_IO_M_MODE_FIFO)
+ spi_qup_write(qup, xfer);
ret = spi_qup_set_state(qup, QUP_STATE_RUN);
if (ret) {
@@ -448,10 +535,10 @@ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id)
writel_relaxed(opflags, controller->base + QUP_OPERATIONAL);
} else {
if (opflags & QUP_OP_IN_SERVICE_FLAG)
- spi_qup_fifo_read(controller, xfer);
+ spi_qup_read(controller, xfer);
if (opflags & QUP_OP_OUT_SERVICE_FLAG)
- spi_qup_fifo_write(controller, xfer);
+ spi_qup_write(controller, xfer);
}
if ((opflags & QUP_OP_MAX_INPUT_DONE_FLAG) || error)
--
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [PATCH v5 07/14] spi: qup: Do block sized read/write in block mode
@ 2017-07-24 7:47 ` Varadarajan Narayanan
0 siblings, 0 replies; 43+ messages in thread
From: Varadarajan Narayanan @ 2017-07-24 7:47 UTC (permalink / raw)
To: broonie, robh+dt, mark.rutland, andy.gross, david.brown,
linux-spi, devicetree, linux-kernel, linux-arm-msm, linux-soc
Cc: Varadarajan Narayanan
This patch corrects the behavior of the BLOCK
transactions. During block transactions, the controller
must be read/written to in block size transactions.
Signed-off-by: Andy Gross <andy.gross@linaro.org>
Signed-off-by: Varadarajan Narayanan <varada@codeaurora.org>
---
drivers/spi/spi-qup.c | 151 +++++++++++++++++++++++++++++++++++++++-----------
1 file changed, 119 insertions(+), 32 deletions(-)
diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c
index 5e6f7e5..d819f87 100644
--- a/drivers/spi/spi-qup.c
+++ b/drivers/spi/spi-qup.c
@@ -82,6 +82,8 @@
#define QUP_IO_M_MODE_BAM 3
/* QUP_OPERATIONAL fields */
+#define QUP_OP_IN_BLOCK_READ_REQ BIT(13)
+#define QUP_OP_OUT_BLOCK_WRITE_REQ BIT(12)
#define QUP_OP_MAX_INPUT_DONE_FLAG BIT(11)
#define QUP_OP_MAX_OUTPUT_DONE_FLAG BIT(10)
#define QUP_OP_IN_SERVICE_FLAG BIT(9)
@@ -154,6 +156,13 @@ struct spi_qup {
struct dma_slave_config tx_conf;
};
+static inline bool spi_qup_is_flag_set(struct spi_qup *controller, u32 flag)
+{
+ u32 opflag = readl_relaxed(controller->base + QUP_OPERATIONAL);
+
+ return (opflag & flag) != 0;
+}
+
static inline bool spi_qup_is_dma_xfer(int mode)
{
if (mode == QUP_IO_M_MODE_DMOV || mode == QUP_IO_M_MODE_BAM)
@@ -214,29 +223,26 @@ static int spi_qup_set_state(struct spi_qup *controller, u32 state)
return 0;
}
-static void spi_qup_fifo_read(struct spi_qup *controller,
- struct spi_transfer *xfer)
+static void spi_qup_read_from_fifo(struct spi_qup *controller,
+ struct spi_transfer *xfer, u32 num_words)
{
u8 *rx_buf = xfer->rx_buf;
- u32 word, state;
- int idx, shift, w_size;
+ int i, shift, num_bytes;
+ u32 word;
- w_size = controller->w_size;
-
- while (controller->rx_bytes < xfer->len) {
-
- state = readl_relaxed(controller->base + QUP_OPERATIONAL);
- if (0 == (state & QUP_OP_IN_FIFO_NOT_EMPTY))
- break;
+ for (; num_words; num_words--) {
word = readl_relaxed(controller->base + QUP_INPUT_FIFO);
+ num_bytes = min_t(int, xfer->len - controller->rx_bytes,
+ controller->w_size);
+
if (!rx_buf) {
- controller->rx_bytes += w_size;
+ controller->rx_bytes += num_bytes;
continue;
}
- for (idx = 0; idx < w_size; idx++, controller->rx_bytes++) {
+ for (i = 0; i < num_bytes; i++, controller->rx_bytes++) {
/*
* The data format depends on bytes per SPI word:
* 4 bytes: 0x12345678
@@ -244,38 +250,80 @@ static void spi_qup_fifo_read(struct spi_qup *controller,
* 1 byte : 0x00000012
*/
shift = BITS_PER_BYTE;
- shift *= (w_size - idx - 1);
+ shift *= (controller->w_size - i - 1);
rx_buf[controller->rx_bytes] = word >> shift;
}
}
}
-static void spi_qup_fifo_write(struct spi_qup *controller,
+static void spi_qup_read(struct spi_qup *controller,
struct spi_transfer *xfer)
{
- const u8 *tx_buf = xfer->tx_buf;
- u32 word, state, data;
- int idx, w_size;
+ u32 remainder, words_per_block, num_words;
+ bool is_block_mode = controller->mode == QUP_IO_M_MODE_BLOCK;
+
+ remainder = DIV_ROUND_UP(xfer->len - controller->rx_bytes,
+ controller->w_size);
+ words_per_block = controller->in_blk_sz >> 2;
+
+ do {
+ /* ACK by clearing service flag */
+ writel_relaxed(QUP_OP_IN_SERVICE_FLAG,
+ controller->base + QUP_OPERATIONAL);
+
+ if (is_block_mode) {
+ num_words = (remainder > words_per_block) ?
+ words_per_block : remainder;
+ } else {
+ if (!spi_qup_is_flag_set(controller,
+ QUP_OP_IN_FIFO_NOT_EMPTY))
+ break;
- w_size = controller->w_size;
+ num_words = 1;
+ }
- while (controller->tx_bytes < xfer->len) {
+ /* read up to the maximum transfer size available */
+ spi_qup_read_from_fifo(controller, xfer, num_words);
- state = readl_relaxed(controller->base + QUP_OPERATIONAL);
- if (state & QUP_OP_OUT_FIFO_FULL)
+ remainder -= num_words;
+
+ /* if block mode, check to see if next block is available */
+ if (is_block_mode && !spi_qup_is_flag_set(controller,
+ QUP_OP_IN_BLOCK_READ_REQ))
break;
+ } while (remainder);
+
+ /*
+ * Due to extra stickiness of the QUP_OP_IN_SERVICE_FLAG during block
+ * mode reads, it has to be cleared again at the very end
+ */
+ if (is_block_mode && spi_qup_is_flag_set(controller,
+ QUP_OP_MAX_INPUT_DONE_FLAG))
+ writel_relaxed(QUP_OP_IN_SERVICE_FLAG,
+ controller->base + QUP_OPERATIONAL);
+
+}
+
+static void spi_qup_write_to_fifo(struct spi_qup *controller,
+ struct spi_transfer *xfer, u32 num_words)
+{
+ const u8 *tx_buf = xfer->tx_buf;
+ int i, num_bytes;
+ u32 word, data;
+
+ for (; num_words; num_words--) {
word = 0;
- for (idx = 0; idx < w_size; idx++, controller->tx_bytes++) {
- if (!tx_buf) {
- controller->tx_bytes += w_size;
- break;
+ num_bytes = min_t(int, xfer->len - controller->tx_bytes,
+ controller->w_size);
+ if (tx_buf)
+ for (i = 0; i < num_bytes; i++) {
+ data = tx_buf[controller->tx_bytes + i];
+ word |= data << (BITS_PER_BYTE * (3 - i));
}
- data = tx_buf[controller->tx_bytes];
- word |= data << (BITS_PER_BYTE * (3 - idx));
- }
+ controller->tx_bytes += num_bytes;
writel_relaxed(word, controller->base + QUP_OUTPUT_FIFO);
}
@@ -288,6 +336,44 @@ static void spi_qup_dma_done(void *data)
complete(&qup->done);
}
+static void spi_qup_write(struct spi_qup *controller,
+ struct spi_transfer *xfer)
+{
+ bool is_block_mode = controller->mode == QUP_IO_M_MODE_BLOCK;
+ u32 remainder, words_per_block, num_words;
+
+ remainder = DIV_ROUND_UP(xfer->len - controller->tx_bytes,
+ controller->w_size);
+ words_per_block = controller->out_blk_sz >> 2;
+
+ do {
+ /* ACK by clearing service flag */
+ writel_relaxed(QUP_OP_OUT_SERVICE_FLAG,
+ controller->base + QUP_OPERATIONAL);
+
+ if (is_block_mode) {
+ num_words = (remainder > words_per_block) ?
+ words_per_block : remainder;
+ } else {
+ if (spi_qup_is_flag_set(controller,
+ QUP_OP_OUT_FIFO_FULL))
+ break;
+
+ num_words = 1;
+ }
+
+ spi_qup_write_to_fifo(controller, xfer, num_words);
+
+ remainder -= num_words;
+
+ /* if block mode, check to see if next block is available */
+ if (is_block_mode && !spi_qup_is_flag_set(controller,
+ QUP_OP_OUT_BLOCK_WRITE_REQ))
+ break;
+
+ } while (remainder);
+}
+
static int spi_qup_prep_sg(struct spi_master *master, struct spi_transfer *xfer,
enum dma_transfer_direction dir,
dma_async_tx_callback callback)
@@ -393,7 +479,8 @@ static int spi_qup_do_pio(struct spi_master *master, struct spi_transfer *xfer,
return ret;
}
- spi_qup_fifo_write(qup, xfer);
+ if (qup->mode == QUP_IO_M_MODE_FIFO)
+ spi_qup_write(qup, xfer);
ret = spi_qup_set_state(qup, QUP_STATE_RUN);
if (ret) {
@@ -448,10 +535,10 @@ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id)
writel_relaxed(opflags, controller->base + QUP_OPERATIONAL);
} else {
if (opflags & QUP_OP_IN_SERVICE_FLAG)
- spi_qup_fifo_read(controller, xfer);
+ spi_qup_read(controller, xfer);
if (opflags & QUP_OP_OUT_SERVICE_FLAG)
- spi_qup_fifo_write(controller, xfer);
+ spi_qup_write(controller, xfer);
}
if ((opflags & QUP_OP_MAX_INPUT_DONE_FLAG) || error)
--
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
^ permalink raw reply related [flat|nested] 43+ messages in thread
* Applied "spi: qup: Do block sized read/write in block mode" to the spi tree
2017-07-24 7:47 ` Varadarajan Narayanan
@ 2017-08-08 11:18 ` Mark Brown
-1 siblings, 0 replies; 43+ messages in thread
From: Mark Brown @ 2017-08-08 11:18 UTC (permalink / raw)
To: Varadarajan Narayanan; +Cc: Andy Gross, Mark Brown
The patch
spi: qup: Do block sized read/write in block mode
has been applied to the spi tree at
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git
All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying
to this mail.
Thanks,
Mark
>From 7538726f9ddaa53b72d61116728cf2d189b05202 Mon Sep 17 00:00:00 2001
From: Varadarajan Narayanan <varada@codeaurora.org>
Date: Fri, 28 Jul 2017 12:22:54 +0530
Subject: [PATCH] spi: qup: Do block sized read/write in block mode
This patch corrects the behavior of the BLOCK
transactions. During block transactions, the controller
must be read/written to in block size transactions.
Signed-off-by: Andy Gross <andy.gross@linaro.org>
Signed-off-by: Varadarajan Narayanan <varada@codeaurora.org>
Signed-off-by: Mark Brown <broonie@kernel.org>
---
drivers/spi/spi-qup.c | 151 +++++++++++++++++++++++++++++++++++++++-----------
1 file changed, 119 insertions(+), 32 deletions(-)
diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c
index a7c630c4788c..8cfa112bb142 100644
--- a/drivers/spi/spi-qup.c
+++ b/drivers/spi/spi-qup.c
@@ -82,6 +82,8 @@
#define QUP_IO_M_MODE_BAM 3
/* QUP_OPERATIONAL fields */
+#define QUP_OP_IN_BLOCK_READ_REQ BIT(13)
+#define QUP_OP_OUT_BLOCK_WRITE_REQ BIT(12)
#define QUP_OP_MAX_INPUT_DONE_FLAG BIT(11)
#define QUP_OP_MAX_OUTPUT_DONE_FLAG BIT(10)
#define QUP_OP_IN_SERVICE_FLAG BIT(9)
@@ -154,6 +156,13 @@ struct spi_qup {
struct dma_slave_config tx_conf;
};
+static inline bool spi_qup_is_flag_set(struct spi_qup *controller, u32 flag)
+{
+ u32 opflag = readl_relaxed(controller->base + QUP_OPERATIONAL);
+
+ return (opflag & flag) != 0;
+}
+
static inline bool spi_qup_is_dma_xfer(int mode)
{
if (mode == QUP_IO_M_MODE_DMOV || mode == QUP_IO_M_MODE_BAM)
@@ -214,29 +223,26 @@ static int spi_qup_set_state(struct spi_qup *controller, u32 state)
return 0;
}
-static void spi_qup_fifo_read(struct spi_qup *controller,
- struct spi_transfer *xfer)
+static void spi_qup_read_from_fifo(struct spi_qup *controller,
+ struct spi_transfer *xfer, u32 num_words)
{
u8 *rx_buf = xfer->rx_buf;
- u32 word, state;
- int idx, shift, w_size;
+ int i, shift, num_bytes;
+ u32 word;
- w_size = controller->w_size;
-
- while (controller->rx_bytes < xfer->len) {
-
- state = readl_relaxed(controller->base + QUP_OPERATIONAL);
- if (0 == (state & QUP_OP_IN_FIFO_NOT_EMPTY))
- break;
+ for (; num_words; num_words--) {
word = readl_relaxed(controller->base + QUP_INPUT_FIFO);
+ num_bytes = min_t(int, xfer->len - controller->rx_bytes,
+ controller->w_size);
+
if (!rx_buf) {
- controller->rx_bytes += w_size;
+ controller->rx_bytes += num_bytes;
continue;
}
- for (idx = 0; idx < w_size; idx++, controller->rx_bytes++) {
+ for (i = 0; i < num_bytes; i++, controller->rx_bytes++) {
/*
* The data format depends on bytes per SPI word:
* 4 bytes: 0x12345678
@@ -244,38 +250,80 @@ static void spi_qup_fifo_read(struct spi_qup *controller,
* 1 byte : 0x00000012
*/
shift = BITS_PER_BYTE;
- shift *= (w_size - idx - 1);
+ shift *= (controller->w_size - i - 1);
rx_buf[controller->rx_bytes] = word >> shift;
}
}
}
-static void spi_qup_fifo_write(struct spi_qup *controller,
+static void spi_qup_read(struct spi_qup *controller,
struct spi_transfer *xfer)
{
- const u8 *tx_buf = xfer->tx_buf;
- u32 word, state, data;
- int idx, w_size;
+ u32 remainder, words_per_block, num_words;
+ bool is_block_mode = controller->mode == QUP_IO_M_MODE_BLOCK;
+
+ remainder = DIV_ROUND_UP(xfer->len - controller->rx_bytes,
+ controller->w_size);
+ words_per_block = controller->in_blk_sz >> 2;
+
+ do {
+ /* ACK by clearing service flag */
+ writel_relaxed(QUP_OP_IN_SERVICE_FLAG,
+ controller->base + QUP_OPERATIONAL);
+
+ if (is_block_mode) {
+ num_words = (remainder > words_per_block) ?
+ words_per_block : remainder;
+ } else {
+ if (!spi_qup_is_flag_set(controller,
+ QUP_OP_IN_FIFO_NOT_EMPTY))
+ break;
- w_size = controller->w_size;
+ num_words = 1;
+ }
- while (controller->tx_bytes < xfer->len) {
+ /* read up to the maximum transfer size available */
+ spi_qup_read_from_fifo(controller, xfer, num_words);
- state = readl_relaxed(controller->base + QUP_OPERATIONAL);
- if (state & QUP_OP_OUT_FIFO_FULL)
+ remainder -= num_words;
+
+ /* if block mode, check to see if next block is available */
+ if (is_block_mode && !spi_qup_is_flag_set(controller,
+ QUP_OP_IN_BLOCK_READ_REQ))
break;
+ } while (remainder);
+
+ /*
+ * Due to extra stickiness of the QUP_OP_IN_SERVICE_FLAG during block
+ * mode reads, it has to be cleared again at the very end
+ */
+ if (is_block_mode && spi_qup_is_flag_set(controller,
+ QUP_OP_MAX_INPUT_DONE_FLAG))
+ writel_relaxed(QUP_OP_IN_SERVICE_FLAG,
+ controller->base + QUP_OPERATIONAL);
+
+}
+
+static void spi_qup_write_to_fifo(struct spi_qup *controller,
+ struct spi_transfer *xfer, u32 num_words)
+{
+ const u8 *tx_buf = xfer->tx_buf;
+ int i, num_bytes;
+ u32 word, data;
+
+ for (; num_words; num_words--) {
word = 0;
- for (idx = 0; idx < w_size; idx++, controller->tx_bytes++) {
- if (!tx_buf) {
- controller->tx_bytes += w_size;
- break;
+ num_bytes = min_t(int, xfer->len - controller->tx_bytes,
+ controller->w_size);
+ if (tx_buf)
+ for (i = 0; i < num_bytes; i++) {
+ data = tx_buf[controller->tx_bytes + i];
+ word |= data << (BITS_PER_BYTE * (3 - i));
}
- data = tx_buf[controller->tx_bytes];
- word |= data << (BITS_PER_BYTE * (3 - idx));
- }
+ controller->tx_bytes += num_bytes;
writel_relaxed(word, controller->base + QUP_OUTPUT_FIFO);
}
@@ -288,6 +336,44 @@ static void spi_qup_dma_done(void *data)
complete(&qup->done);
}
+static void spi_qup_write(struct spi_qup *controller,
+ struct spi_transfer *xfer)
+{
+ bool is_block_mode = controller->mode == QUP_IO_M_MODE_BLOCK;
+ u32 remainder, words_per_block, num_words;
+
+ remainder = DIV_ROUND_UP(xfer->len - controller->tx_bytes,
+ controller->w_size);
+ words_per_block = controller->out_blk_sz >> 2;
+
+ do {
+ /* ACK by clearing service flag */
+ writel_relaxed(QUP_OP_OUT_SERVICE_FLAG,
+ controller->base + QUP_OPERATIONAL);
+
+ if (is_block_mode) {
+ num_words = (remainder > words_per_block) ?
+ words_per_block : remainder;
+ } else {
+ if (spi_qup_is_flag_set(controller,
+ QUP_OP_OUT_FIFO_FULL))
+ break;
+
+ num_words = 1;
+ }
+
+ spi_qup_write_to_fifo(controller, xfer, num_words);
+
+ remainder -= num_words;
+
+ /* if block mode, check to see if next block is available */
+ if (is_block_mode && !spi_qup_is_flag_set(controller,
+ QUP_OP_OUT_BLOCK_WRITE_REQ))
+ break;
+
+ } while (remainder);
+}
+
static int spi_qup_prep_sg(struct spi_master *master, struct spi_transfer *xfer,
enum dma_transfer_direction dir,
dma_async_tx_callback callback)
@@ -391,7 +477,8 @@ static int spi_qup_do_pio(struct spi_master *master, struct spi_transfer *xfer,
return ret;
}
- spi_qup_fifo_write(qup, xfer);
+ if (qup->mode == QUP_IO_M_MODE_FIFO)
+ spi_qup_write(qup, xfer);
ret = spi_qup_set_state(qup, QUP_STATE_RUN);
if (ret) {
@@ -446,10 +533,10 @@ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id)
writel_relaxed(opflags, controller->base + QUP_OPERATIONAL);
} else {
if (opflags & QUP_OP_IN_SERVICE_FLAG)
- spi_qup_fifo_read(controller, xfer);
+ spi_qup_read(controller, xfer);
if (opflags & QUP_OP_OUT_SERVICE_FLAG)
- spi_qup_fifo_write(controller, xfer);
+ spi_qup_write(controller, xfer);
}
if ((opflags & QUP_OP_MAX_INPUT_DONE_FLAG) || error)
--
2.13.2
^ permalink raw reply related [flat|nested] 43+ messages in thread
* Applied "spi: qup: Do block sized read/write in block mode" to the spi tree
@ 2017-08-08 11:18 ` Mark Brown
0 siblings, 0 replies; 43+ messages in thread
From: Mark Brown @ 2017-08-08 11:18 UTC (permalink / raw)
To: Varadarajan Narayanan
Cc: Andy Gross, Mark Brown, broonie, robh+dt, mark.rutland,
andy.gross, david.brown, linux-spi, devicetree, linux-kernel,
linux-arm-msm, linux-soc, linux-spi
The patch
spi: qup: Do block sized read/write in block mode
has been applied to the spi tree at
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git
All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying
to this mail.
Thanks,
Mark
>From 7538726f9ddaa53b72d61116728cf2d189b05202 Mon Sep 17 00:00:00 2001
From: Varadarajan Narayanan <varada@codeaurora.org>
Date: Fri, 28 Jul 2017 12:22:54 +0530
Subject: [PATCH] spi: qup: Do block sized read/write in block mode
This patch corrects the behavior of the BLOCK
transactions. During block transactions, the controller
must be read/written to in block size transactions.
Signed-off-by: Andy Gross <andy.gross@linaro.org>
Signed-off-by: Varadarajan Narayanan <varada@codeaurora.org>
Signed-off-by: Mark Brown <broonie@kernel.org>
---
drivers/spi/spi-qup.c | 151 +++++++++++++++++++++++++++++++++++++++-----------
1 file changed, 119 insertions(+), 32 deletions(-)
diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c
index a7c630c4788c..8cfa112bb142 100644
--- a/drivers/spi/spi-qup.c
+++ b/drivers/spi/spi-qup.c
@@ -82,6 +82,8 @@
#define QUP_IO_M_MODE_BAM 3
/* QUP_OPERATIONAL fields */
+#define QUP_OP_IN_BLOCK_READ_REQ BIT(13)
+#define QUP_OP_OUT_BLOCK_WRITE_REQ BIT(12)
#define QUP_OP_MAX_INPUT_DONE_FLAG BIT(11)
#define QUP_OP_MAX_OUTPUT_DONE_FLAG BIT(10)
#define QUP_OP_IN_SERVICE_FLAG BIT(9)
@@ -154,6 +156,13 @@ struct spi_qup {
struct dma_slave_config tx_conf;
};
+static inline bool spi_qup_is_flag_set(struct spi_qup *controller, u32 flag)
+{
+ u32 opflag = readl_relaxed(controller->base + QUP_OPERATIONAL);
+
+ return (opflag & flag) != 0;
+}
+
static inline bool spi_qup_is_dma_xfer(int mode)
{
if (mode == QUP_IO_M_MODE_DMOV || mode == QUP_IO_M_MODE_BAM)
@@ -214,29 +223,26 @@ static int spi_qup_set_state(struct spi_qup *controller, u32 state)
return 0;
}
-static void spi_qup_fifo_read(struct spi_qup *controller,
- struct spi_transfer *xfer)
+static void spi_qup_read_from_fifo(struct spi_qup *controller,
+ struct spi_transfer *xfer, u32 num_words)
{
u8 *rx_buf = xfer->rx_buf;
- u32 word, state;
- int idx, shift, w_size;
+ int i, shift, num_bytes;
+ u32 word;
- w_size = controller->w_size;
-
- while (controller->rx_bytes < xfer->len) {
-
- state = readl_relaxed(controller->base + QUP_OPERATIONAL);
- if (0 == (state & QUP_OP_IN_FIFO_NOT_EMPTY))
- break;
+ for (; num_words; num_words--) {
word = readl_relaxed(controller->base + QUP_INPUT_FIFO);
+ num_bytes = min_t(int, xfer->len - controller->rx_bytes,
+ controller->w_size);
+
if (!rx_buf) {
- controller->rx_bytes += w_size;
+ controller->rx_bytes += num_bytes;
continue;
}
- for (idx = 0; idx < w_size; idx++, controller->rx_bytes++) {
+ for (i = 0; i < num_bytes; i++, controller->rx_bytes++) {
/*
* The data format depends on bytes per SPI word:
* 4 bytes: 0x12345678
@@ -244,38 +250,80 @@ static void spi_qup_fifo_read(struct spi_qup *controller,
* 1 byte : 0x00000012
*/
shift = BITS_PER_BYTE;
- shift *= (w_size - idx - 1);
+ shift *= (controller->w_size - i - 1);
rx_buf[controller->rx_bytes] = word >> shift;
}
}
}
-static void spi_qup_fifo_write(struct spi_qup *controller,
+static void spi_qup_read(struct spi_qup *controller,
struct spi_transfer *xfer)
{
- const u8 *tx_buf = xfer->tx_buf;
- u32 word, state, data;
- int idx, w_size;
+ u32 remainder, words_per_block, num_words;
+ bool is_block_mode = controller->mode == QUP_IO_M_MODE_BLOCK;
+
+ remainder = DIV_ROUND_UP(xfer->len - controller->rx_bytes,
+ controller->w_size);
+ words_per_block = controller->in_blk_sz >> 2;
+
+ do {
+ /* ACK by clearing service flag */
+ writel_relaxed(QUP_OP_IN_SERVICE_FLAG,
+ controller->base + QUP_OPERATIONAL);
+
+ if (is_block_mode) {
+ num_words = (remainder > words_per_block) ?
+ words_per_block : remainder;
+ } else {
+ if (!spi_qup_is_flag_set(controller,
+ QUP_OP_IN_FIFO_NOT_EMPTY))
+ break;
- w_size = controller->w_size;
+ num_words = 1;
+ }
- while (controller->tx_bytes < xfer->len) {
+ /* read up to the maximum transfer size available */
+ spi_qup_read_from_fifo(controller, xfer, num_words);
- state = readl_relaxed(controller->base + QUP_OPERATIONAL);
- if (state & QUP_OP_OUT_FIFO_FULL)
+ remainder -= num_words;
+
+ /* if block mode, check to see if next block is available */
+ if (is_block_mode && !spi_qup_is_flag_set(controller,
+ QUP_OP_IN_BLOCK_READ_REQ))
break;
+ } while (remainder);
+
+ /*
+ * Due to extra stickiness of the QUP_OP_IN_SERVICE_FLAG during block
+ * mode reads, it has to be cleared again at the very end
+ */
+ if (is_block_mode && spi_qup_is_flag_set(controller,
+ QUP_OP_MAX_INPUT_DONE_FLAG))
+ writel_relaxed(QUP_OP_IN_SERVICE_FLAG,
+ controller->base + QUP_OPERATIONAL);
+
+}
+
+static void spi_qup_write_to_fifo(struct spi_qup *controller,
+ struct spi_transfer *xfer, u32 num_words)
+{
+ const u8 *tx_buf = xfer->tx_buf;
+ int i, num_bytes;
+ u32 word, data;
+
+ for (; num_words; num_words--) {
word = 0;
- for (idx = 0; idx < w_size; idx++, controller->tx_bytes++) {
- if (!tx_buf) {
- controller->tx_bytes += w_size;
- break;
+ num_bytes = min_t(int, xfer->len - controller->tx_bytes,
+ controller->w_size);
+ if (tx_buf)
+ for (i = 0; i < num_bytes; i++) {
+ data = tx_buf[controller->tx_bytes + i];
+ word |= data << (BITS_PER_BYTE * (3 - i));
}
- data = tx_buf[controller->tx_bytes];
- word |= data << (BITS_PER_BYTE * (3 - idx));
- }
+ controller->tx_bytes += num_bytes;
writel_relaxed(word, controller->base + QUP_OUTPUT_FIFO);
}
@@ -288,6 +336,44 @@ static void spi_qup_dma_done(void *data)
complete(&qup->done);
}
+static void spi_qup_write(struct spi_qup *controller,
+ struct spi_transfer *xfer)
+{
+ bool is_block_mode = controller->mode == QUP_IO_M_MODE_BLOCK;
+ u32 remainder, words_per_block, num_words;
+
+ remainder = DIV_ROUND_UP(xfer->len - controller->tx_bytes,
+ controller->w_size);
+ words_per_block = controller->out_blk_sz >> 2;
+
+ do {
+ /* ACK by clearing service flag */
+ writel_relaxed(QUP_OP_OUT_SERVICE_FLAG,
+ controller->base + QUP_OPERATIONAL);
+
+ if (is_block_mode) {
+ num_words = (remainder > words_per_block) ?
+ words_per_block : remainder;
+ } else {
+ if (spi_qup_is_flag_set(controller,
+ QUP_OP_OUT_FIFO_FULL))
+ break;
+
+ num_words = 1;
+ }
+
+ spi_qup_write_to_fifo(controller, xfer, num_words);
+
+ remainder -= num_words;
+
+ /* if block mode, check to see if next block is available */
+ if (is_block_mode && !spi_qup_is_flag_set(controller,
+ QUP_OP_OUT_BLOCK_WRITE_REQ))
+ break;
+
+ } while (remainder);
+}
+
static int spi_qup_prep_sg(struct spi_master *master, struct spi_transfer *xfer,
enum dma_transfer_direction dir,
dma_async_tx_callback callback)
@@ -391,7 +477,8 @@ static int spi_qup_do_pio(struct spi_master *master, struct spi_transfer *xfer,
return ret;
}
- spi_qup_fifo_write(qup, xfer);
+ if (qup->mode == QUP_IO_M_MODE_FIFO)
+ spi_qup_write(qup, xfer);
ret = spi_qup_set_state(qup, QUP_STATE_RUN);
if (ret) {
@@ -446,10 +533,10 @@ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id)
writel_relaxed(opflags, controller->base + QUP_OPERATIONAL);
} else {
if (opflags & QUP_OP_IN_SERVICE_FLAG)
- spi_qup_fifo_read(controller, xfer);
+ spi_qup_read(controller, xfer);
if (opflags & QUP_OP_OUT_SERVICE_FLAG)
- spi_qup_fifo_write(controller, xfer);
+ spi_qup_write(controller, xfer);
}
if ((opflags & QUP_OP_MAX_INPUT_DONE_FLAG) || error)
--
2.13.2
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [PATCH v5 09/14] spi: qup: call io_config in mode specific function
2017-07-24 7:47 [PATCH v5 00/14] spi: qup: Fixes and add support for >64k transfers Varadarajan Narayanan
@ 2017-07-24 7:47 ` Varadarajan Narayanan
[not found] ` <1500882445-29008-1-git-send-email-varada-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
` (5 subsequent siblings)
6 siblings, 0 replies; 43+ messages in thread
From: Varadarajan Narayanan @ 2017-07-24 7:47 UTC (permalink / raw)
To: broonie-DgEjT+Ai2ygdnm+yROfE0A, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
mark.rutland-5wv7dgnIgG8, andy.gross-QSEj5FYQhm4dnm+yROfE0A,
david.brown-QSEj5FYQhm4dnm+yROfE0A,
linux-spi-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-arm-msm-u79uwXL29TY76Z2rM5mHXA,
linux-soc-u79uwXL29TY76Z2rM5mHXA
Cc: Varadarajan Narayanan, Matthew McClintock
DMA transactions should only only need to call io_config only once, but
block mode might call it several times to setup several transactions so
it can handle reads/writes larger than the max size per transaction, so
we move the call to the do_ functions.
This is just refactoring, there should be no functional change
Signed-off-by: Matthew McClintock <mmcclint-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
Signed-off-by: Varadarajan Narayanan <varada-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
---
drivers/spi/spi-qup.c | 25 +++++++++++++++++--------
1 file changed, 17 insertions(+), 8 deletions(-)
diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c
index 82593f6..b2bda47 100644
--- a/drivers/spi/spi-qup.c
+++ b/drivers/spi/spi-qup.c
@@ -156,6 +156,8 @@ struct spi_qup {
struct dma_slave_config tx_conf;
};
+static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer);
+
static inline bool spi_qup_is_flag_set(struct spi_qup *controller, u32 flag)
{
u32 opflag = readl_relaxed(controller->base + QUP_OPERATIONAL);
@@ -417,10 +419,12 @@ static void spi_qup_dma_terminate(struct spi_master *master,
dmaengine_terminate_all(master->dma_rx);
}
-static int spi_qup_do_dma(struct spi_master *master, struct spi_transfer *xfer,
+static int spi_qup_do_dma(struct spi_device *spi, struct spi_transfer *xfer,
unsigned long timeout)
{
dma_async_tx_callback rx_done = NULL, tx_done = NULL;
+ struct spi_master *master = spi->master;
+ struct spi_qup *qup = spi_master_get_devdata(master);
int ret;
if (xfer->rx_buf)
@@ -428,6 +432,10 @@ static int spi_qup_do_dma(struct spi_master *master, struct spi_transfer *xfer,
else if (xfer->tx_buf)
tx_done = spi_qup_dma_done;
+ ret = spi_qup_io_config(spi, xfer);
+ if (ret)
+ return ret;
+
/* before issuing the descriptors, set the QUP to run */
ret = spi_qup_set_state(qup, QUP_STATE_RUN);
if (ret) {
@@ -461,12 +469,17 @@ static int spi_qup_do_dma(struct spi_master *master, struct spi_transfer *xfer,
return 0;
}
-static int spi_qup_do_pio(struct spi_master *master, struct spi_transfer *xfer,
+static int spi_qup_do_pio(struct spi_device *spi, struct spi_transfer *xfer,
unsigned long timeout)
{
+ struct spi_master *master = spi->master;
struct spi_qup *qup = spi_master_get_devdata(master);
int ret;
+ ret = spi_qup_io_config(spi, xfer);
+ if (ret)
+ return ret;
+
ret = spi_qup_set_state(qup, QUP_STATE_RUN);
if (ret) {
dev_warn(qup->dev, "cannot set RUN state\n");
@@ -744,10 +757,6 @@ static int spi_qup_transfer_one(struct spi_master *master,
if (ret)
return ret;
- ret = spi_qup_io_config(spi, xfer);
- if (ret)
- return ret;
-
timeout = DIV_ROUND_UP(xfer->speed_hz, MSEC_PER_SEC);
timeout = DIV_ROUND_UP(xfer->len * 8, timeout);
timeout = 100 * msecs_to_jiffies(timeout);
@@ -762,9 +771,9 @@ static int spi_qup_transfer_one(struct spi_master *master,
spin_unlock_irqrestore(&controller->lock, flags);
if (spi_qup_is_dma_xfer(controller->mode))
- ret = spi_qup_do_dma(master, xfer, timeout);
+ ret = spi_qup_do_dma(spi, xfer, timeout);
else
- ret = spi_qup_do_pio(master, xfer, timeout);
+ ret = spi_qup_do_pio(spi, xfer, timeout);
if (ret)
goto exit;
--
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [PATCH v5 09/14] spi: qup: call io_config in mode specific function
@ 2017-07-24 7:47 ` Varadarajan Narayanan
0 siblings, 0 replies; 43+ messages in thread
From: Varadarajan Narayanan @ 2017-07-24 7:47 UTC (permalink / raw)
To: broonie, robh+dt, mark.rutland, andy.gross, david.brown,
linux-spi, devicetree, linux-kernel, linux-arm-msm, linux-soc
Cc: Varadarajan Narayanan, Matthew McClintock
DMA transactions should only only need to call io_config only once, but
block mode might call it several times to setup several transactions so
it can handle reads/writes larger than the max size per transaction, so
we move the call to the do_ functions.
This is just refactoring, there should be no functional change
Signed-off-by: Matthew McClintock <mmcclint@codeaurora.org>
Signed-off-by: Varadarajan Narayanan <varada@codeaurora.org>
---
drivers/spi/spi-qup.c | 25 +++++++++++++++++--------
1 file changed, 17 insertions(+), 8 deletions(-)
diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c
index 82593f6..b2bda47 100644
--- a/drivers/spi/spi-qup.c
+++ b/drivers/spi/spi-qup.c
@@ -156,6 +156,8 @@ struct spi_qup {
struct dma_slave_config tx_conf;
};
+static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer);
+
static inline bool spi_qup_is_flag_set(struct spi_qup *controller, u32 flag)
{
u32 opflag = readl_relaxed(controller->base + QUP_OPERATIONAL);
@@ -417,10 +419,12 @@ static void spi_qup_dma_terminate(struct spi_master *master,
dmaengine_terminate_all(master->dma_rx);
}
-static int spi_qup_do_dma(struct spi_master *master, struct spi_transfer *xfer,
+static int spi_qup_do_dma(struct spi_device *spi, struct spi_transfer *xfer,
unsigned long timeout)
{
dma_async_tx_callback rx_done = NULL, tx_done = NULL;
+ struct spi_master *master = spi->master;
+ struct spi_qup *qup = spi_master_get_devdata(master);
int ret;
if (xfer->rx_buf)
@@ -428,6 +432,10 @@ static int spi_qup_do_dma(struct spi_master *master, struct spi_transfer *xfer,
else if (xfer->tx_buf)
tx_done = spi_qup_dma_done;
+ ret = spi_qup_io_config(spi, xfer);
+ if (ret)
+ return ret;
+
/* before issuing the descriptors, set the QUP to run */
ret = spi_qup_set_state(qup, QUP_STATE_RUN);
if (ret) {
@@ -461,12 +469,17 @@ static int spi_qup_do_dma(struct spi_master *master, struct spi_transfer *xfer,
return 0;
}
-static int spi_qup_do_pio(struct spi_master *master, struct spi_transfer *xfer,
+static int spi_qup_do_pio(struct spi_device *spi, struct spi_transfer *xfer,
unsigned long timeout)
{
+ struct spi_master *master = spi->master;
struct spi_qup *qup = spi_master_get_devdata(master);
int ret;
+ ret = spi_qup_io_config(spi, xfer);
+ if (ret)
+ return ret;
+
ret = spi_qup_set_state(qup, QUP_STATE_RUN);
if (ret) {
dev_warn(qup->dev, "cannot set RUN state\n");
@@ -744,10 +757,6 @@ static int spi_qup_transfer_one(struct spi_master *master,
if (ret)
return ret;
- ret = spi_qup_io_config(spi, xfer);
- if (ret)
- return ret;
-
timeout = DIV_ROUND_UP(xfer->speed_hz, MSEC_PER_SEC);
timeout = DIV_ROUND_UP(xfer->len * 8, timeout);
timeout = 100 * msecs_to_jiffies(timeout);
@@ -762,9 +771,9 @@ static int spi_qup_transfer_one(struct spi_master *master,
spin_unlock_irqrestore(&controller->lock, flags);
if (spi_qup_is_dma_xfer(controller->mode))
- ret = spi_qup_do_dma(master, xfer, timeout);
+ ret = spi_qup_do_dma(spi, xfer, timeout);
else
- ret = spi_qup_do_pio(master, xfer, timeout);
+ ret = spi_qup_do_pio(spi, xfer, timeout);
if (ret)
goto exit;
--
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [PATCH v5 10/14] spi: qup: allow block mode to generate multiple transactions
2017-07-24 7:47 [PATCH v5 00/14] spi: qup: Fixes and add support for >64k transfers Varadarajan Narayanan
@ 2017-07-24 7:47 ` Varadarajan Narayanan
[not found] ` <1500882445-29008-1-git-send-email-varada-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
` (5 subsequent siblings)
6 siblings, 0 replies; 43+ messages in thread
From: Varadarajan Narayanan @ 2017-07-24 7:47 UTC (permalink / raw)
To: broonie-DgEjT+Ai2ygdnm+yROfE0A, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
mark.rutland-5wv7dgnIgG8, andy.gross-QSEj5FYQhm4dnm+yROfE0A,
david.brown-QSEj5FYQhm4dnm+yROfE0A,
linux-spi-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-arm-msm-u79uwXL29TY76Z2rM5mHXA,
linux-soc-u79uwXL29TY76Z2rM5mHXA
Cc: Varadarajan Narayanan, Matthew McClintock
This let's you write more to the SPI bus than 64K-1 which is important
if the block size of a SPI device is >= 64K or some other device wants
to do something larger.
This has the benefit of completely removing spi_message from the spi-qup
transactions
Signed-off-by: Matthew McClintock <mmcclint-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
Signed-off-by: Varadarajan Narayanan <varada-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
---
drivers/spi/spi-qup.c | 128 +++++++++++++++++++++++++++++++-------------------
1 file changed, 80 insertions(+), 48 deletions(-)
diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c
index b2bda47..67e7463 100644
--- a/drivers/spi/spi-qup.c
+++ b/drivers/spi/spi-qup.c
@@ -120,7 +120,7 @@
#define SPI_NUM_CHIPSELECTS 4
-#define SPI_MAX_DMA_XFER (SZ_64K - 64)
+#define SPI_MAX_XFER (SZ_64K - 64)
/* high speed mode is when bus rate is greater then 26MHz */
#define SPI_HS_MIN_RATE 26000000
@@ -149,6 +149,8 @@ struct spi_qup {
int n_words;
int tx_bytes;
int rx_bytes;
+ const u8 *tx_buf;
+ u8 *rx_buf;
int qup_v1;
int mode;
@@ -173,6 +175,12 @@ static inline bool spi_qup_is_dma_xfer(int mode)
return false;
}
+/* get's the transaction size length */
+static inline unsigned int spi_qup_len(struct spi_qup *controller)
+{
+ return controller->n_words * controller->w_size;
+}
+
static inline bool spi_qup_is_valid_state(struct spi_qup *controller)
{
u32 opstate = readl_relaxed(controller->base + QUP_STATE);
@@ -225,10 +233,9 @@ static int spi_qup_set_state(struct spi_qup *controller, u32 state)
return 0;
}
-static void spi_qup_read_from_fifo(struct spi_qup *controller,
- struct spi_transfer *xfer, u32 num_words)
+static void spi_qup_read_from_fifo(struct spi_qup *controller, u32 num_words)
{
- u8 *rx_buf = xfer->rx_buf;
+ u8 *rx_buf = controller->rx_buf;
int i, shift, num_bytes;
u32 word;
@@ -236,8 +243,9 @@ static void spi_qup_read_from_fifo(struct spi_qup *controller,
word = readl_relaxed(controller->base + QUP_INPUT_FIFO);
- num_bytes = min_t(int, xfer->len - controller->rx_bytes,
- controller->w_size);
+ num_bytes = min_t(int, spi_qup_len(controller) -
+ controller->rx_bytes,
+ controller->w_size);
if (!rx_buf) {
controller->rx_bytes += num_bytes;
@@ -258,13 +266,12 @@ static void spi_qup_read_from_fifo(struct spi_qup *controller,
}
}
-static void spi_qup_read(struct spi_qup *controller,
- struct spi_transfer *xfer)
+static void spi_qup_read(struct spi_qup *controller)
{
u32 remainder, words_per_block, num_words;
bool is_block_mode = controller->mode == QUP_IO_M_MODE_BLOCK;
- remainder = DIV_ROUND_UP(xfer->len - controller->rx_bytes,
+ remainder = DIV_ROUND_UP(spi_qup_len(controller) - controller->rx_bytes,
controller->w_size);
words_per_block = controller->in_blk_sz >> 2;
@@ -285,7 +292,7 @@ static void spi_qup_read(struct spi_qup *controller,
}
/* read up to the maximum transfer size available */
- spi_qup_read_from_fifo(controller, xfer, num_words);
+ spi_qup_read_from_fifo(controller, num_words);
remainder -= num_words;
@@ -307,18 +314,18 @@ static void spi_qup_read(struct spi_qup *controller,
}
-static void spi_qup_write_to_fifo(struct spi_qup *controller,
- struct spi_transfer *xfer, u32 num_words)
+static void spi_qup_write_to_fifo(struct spi_qup *controller, u32 num_words)
{
- const u8 *tx_buf = xfer->tx_buf;
+ const u8 *tx_buf = controller->tx_buf;
int i, num_bytes;
u32 word, data;
for (; num_words; num_words--) {
word = 0;
- num_bytes = min_t(int, xfer->len - controller->tx_bytes,
- controller->w_size);
+ num_bytes = min_t(int, spi_qup_len(controller) -
+ controller->tx_bytes,
+ controller->w_size);
if (tx_buf)
for (i = 0; i < num_bytes; i++) {
data = tx_buf[controller->tx_bytes + i];
@@ -338,13 +345,12 @@ static void spi_qup_dma_done(void *data)
complete(&qup->done);
}
-static void spi_qup_write(struct spi_qup *controller,
- struct spi_transfer *xfer)
+static void spi_qup_write(struct spi_qup *controller)
{
bool is_block_mode = controller->mode == QUP_IO_M_MODE_BLOCK;
u32 remainder, words_per_block, num_words;
- remainder = DIV_ROUND_UP(xfer->len - controller->tx_bytes,
+ remainder = DIV_ROUND_UP(spi_qup_len(controller) - controller->tx_bytes,
controller->w_size);
words_per_block = controller->out_blk_sz >> 2;
@@ -364,7 +370,7 @@ static void spi_qup_write(struct spi_qup *controller,
num_words = 1;
}
- spi_qup_write_to_fifo(controller, xfer, num_words);
+ spi_qup_write_to_fifo(controller, num_words);
remainder -= num_words;
@@ -474,36 +480,62 @@ static int spi_qup_do_pio(struct spi_device *spi, struct spi_transfer *xfer,
{
struct spi_master *master = spi->master;
struct spi_qup *qup = spi_master_get_devdata(master);
- int ret;
+ int ret, n_words, iterations, offset = 0;
- ret = spi_qup_io_config(spi, xfer);
- if (ret)
- return ret;
+ n_words = qup->n_words;
+ iterations = n_words / SPI_MAX_XFER; /* round down */
+ qup->rx_buf = xfer->rx_buf;
+ qup->tx_buf = xfer->tx_buf;
- ret = spi_qup_set_state(qup, QUP_STATE_RUN);
- if (ret) {
- dev_warn(qup->dev, "cannot set RUN state\n");
- return ret;
- }
+ do {
+ if (iterations)
+ qup->n_words = SPI_MAX_XFER;
+ else
+ qup->n_words = n_words % SPI_MAX_XFER;
- ret = spi_qup_set_state(qup, QUP_STATE_PAUSE);
- if (ret) {
- dev_warn(qup->dev, "cannot set PAUSE state\n");
- return ret;
- }
+ if (qup->tx_buf && offset)
+ qup->tx_buf = xfer->tx_buf + offset * SPI_MAX_XFER;
- if (qup->mode == QUP_IO_M_MODE_FIFO)
- spi_qup_write(qup, xfer);
+ if (qup->rx_buf && offset)
+ qup->rx_buf = xfer->rx_buf + offset * SPI_MAX_XFER;
- ret = spi_qup_set_state(qup, QUP_STATE_RUN);
- if (ret) {
- dev_warn(qup->dev, "%s(%d): cannot set RUN state\n",
- __func__, __LINE__);
- return ret;
- }
+ /*
+ * if the transaction is small enough, we need
+ * to fallback to FIFO mode
+ */
+ if (qup->n_words <= (qup->in_fifo_sz / sizeof(u32)))
+ qup->mode = QUP_IO_M_MODE_FIFO;
- if (!wait_for_completion_timeout(&qup->done, timeout))
- return -ETIMEDOUT;
+ ret = spi_qup_io_config(spi, xfer);
+ if (ret)
+ return ret;
+
+ ret = spi_qup_set_state(qup, QUP_STATE_RUN);
+ if (ret) {
+ dev_warn(qup->dev, "cannot set RUN state\n");
+ return ret;
+ }
+
+ ret = spi_qup_set_state(qup, QUP_STATE_PAUSE);
+ if (ret) {
+ dev_warn(qup->dev, "cannot set PAUSE state\n");
+ return ret;
+ }
+
+ if (qup->mode == QUP_IO_M_MODE_FIFO)
+ spi_qup_write(qup);
+
+ ret = spi_qup_set_state(qup, QUP_STATE_RUN);
+ if (ret) {
+ dev_warn(qup->dev, "cannot set RUN state\n");
+ return ret;
+ }
+
+ if (!wait_for_completion_timeout(&qup->done, timeout))
+ return -ETIMEDOUT;
+
+ offset++;
+ } while (iterations--);
return 0;
}
@@ -511,7 +543,6 @@ static int spi_qup_do_pio(struct spi_device *spi, struct spi_transfer *xfer,
static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id)
{
struct spi_qup *controller = dev_id;
- struct spi_transfer *xfer = controller->xfer;
u32 opflags, qup_err, spi_err;
int error = 0;
@@ -548,10 +579,10 @@ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id)
writel_relaxed(opflags, controller->base + QUP_OPERATIONAL);
} else {
if (opflags & QUP_OP_IN_SERVICE_FLAG)
- spi_qup_read(controller, xfer);
+ spi_qup_read(controller);
if (opflags & QUP_OP_OUT_SERVICE_FLAG)
- spi_qup_write(controller, xfer);
+ spi_qup_write(controller);
}
if ((opflags & QUP_OP_MAX_INPUT_DONE_FLAG) || error)
@@ -758,7 +789,8 @@ static int spi_qup_transfer_one(struct spi_master *master,
return ret;
timeout = DIV_ROUND_UP(xfer->speed_hz, MSEC_PER_SEC);
- timeout = DIV_ROUND_UP(xfer->len * 8, timeout);
+ timeout = DIV_ROUND_UP(min_t(unsigned long, SPI_MAX_XFER,
+ xfer->len) * 8, timeout);
timeout = 100 * msecs_to_jiffies(timeout);
reinit_completion(&controller->done);
@@ -972,7 +1004,7 @@ static int spi_qup_probe(struct platform_device *pdev)
master->dev.of_node = pdev->dev.of_node;
master->auto_runtime_pm = true;
master->dma_alignment = dma_get_cache_alignment();
- master->max_dma_len = SPI_MAX_DMA_XFER;
+ master->max_dma_len = SPI_MAX_XFER;
platform_set_drvdata(pdev, master);
--
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [PATCH v5 10/14] spi: qup: allow block mode to generate multiple transactions
@ 2017-07-24 7:47 ` Varadarajan Narayanan
0 siblings, 0 replies; 43+ messages in thread
From: Varadarajan Narayanan @ 2017-07-24 7:47 UTC (permalink / raw)
To: broonie, robh+dt, mark.rutland, andy.gross, david.brown,
linux-spi, devicetree, linux-kernel, linux-arm-msm, linux-soc
Cc: Varadarajan Narayanan, Matthew McClintock
This let's you write more to the SPI bus than 64K-1 which is important
if the block size of a SPI device is >= 64K or some other device wants
to do something larger.
This has the benefit of completely removing spi_message from the spi-qup
transactions
Signed-off-by: Matthew McClintock <mmcclint@codeaurora.org>
Signed-off-by: Varadarajan Narayanan <varada@codeaurora.org>
---
drivers/spi/spi-qup.c | 128 +++++++++++++++++++++++++++++++-------------------
1 file changed, 80 insertions(+), 48 deletions(-)
diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c
index b2bda47..67e7463 100644
--- a/drivers/spi/spi-qup.c
+++ b/drivers/spi/spi-qup.c
@@ -120,7 +120,7 @@
#define SPI_NUM_CHIPSELECTS 4
-#define SPI_MAX_DMA_XFER (SZ_64K - 64)
+#define SPI_MAX_XFER (SZ_64K - 64)
/* high speed mode is when bus rate is greater then 26MHz */
#define SPI_HS_MIN_RATE 26000000
@@ -149,6 +149,8 @@ struct spi_qup {
int n_words;
int tx_bytes;
int rx_bytes;
+ const u8 *tx_buf;
+ u8 *rx_buf;
int qup_v1;
int mode;
@@ -173,6 +175,12 @@ static inline bool spi_qup_is_dma_xfer(int mode)
return false;
}
+/* get's the transaction size length */
+static inline unsigned int spi_qup_len(struct spi_qup *controller)
+{
+ return controller->n_words * controller->w_size;
+}
+
static inline bool spi_qup_is_valid_state(struct spi_qup *controller)
{
u32 opstate = readl_relaxed(controller->base + QUP_STATE);
@@ -225,10 +233,9 @@ static int spi_qup_set_state(struct spi_qup *controller, u32 state)
return 0;
}
-static void spi_qup_read_from_fifo(struct spi_qup *controller,
- struct spi_transfer *xfer, u32 num_words)
+static void spi_qup_read_from_fifo(struct spi_qup *controller, u32 num_words)
{
- u8 *rx_buf = xfer->rx_buf;
+ u8 *rx_buf = controller->rx_buf;
int i, shift, num_bytes;
u32 word;
@@ -236,8 +243,9 @@ static void spi_qup_read_from_fifo(struct spi_qup *controller,
word = readl_relaxed(controller->base + QUP_INPUT_FIFO);
- num_bytes = min_t(int, xfer->len - controller->rx_bytes,
- controller->w_size);
+ num_bytes = min_t(int, spi_qup_len(controller) -
+ controller->rx_bytes,
+ controller->w_size);
if (!rx_buf) {
controller->rx_bytes += num_bytes;
@@ -258,13 +266,12 @@ static void spi_qup_read_from_fifo(struct spi_qup *controller,
}
}
-static void spi_qup_read(struct spi_qup *controller,
- struct spi_transfer *xfer)
+static void spi_qup_read(struct spi_qup *controller)
{
u32 remainder, words_per_block, num_words;
bool is_block_mode = controller->mode == QUP_IO_M_MODE_BLOCK;
- remainder = DIV_ROUND_UP(xfer->len - controller->rx_bytes,
+ remainder = DIV_ROUND_UP(spi_qup_len(controller) - controller->rx_bytes,
controller->w_size);
words_per_block = controller->in_blk_sz >> 2;
@@ -285,7 +292,7 @@ static void spi_qup_read(struct spi_qup *controller,
}
/* read up to the maximum transfer size available */
- spi_qup_read_from_fifo(controller, xfer, num_words);
+ spi_qup_read_from_fifo(controller, num_words);
remainder -= num_words;
@@ -307,18 +314,18 @@ static void spi_qup_read(struct spi_qup *controller,
}
-static void spi_qup_write_to_fifo(struct spi_qup *controller,
- struct spi_transfer *xfer, u32 num_words)
+static void spi_qup_write_to_fifo(struct spi_qup *controller, u32 num_words)
{
- const u8 *tx_buf = xfer->tx_buf;
+ const u8 *tx_buf = controller->tx_buf;
int i, num_bytes;
u32 word, data;
for (; num_words; num_words--) {
word = 0;
- num_bytes = min_t(int, xfer->len - controller->tx_bytes,
- controller->w_size);
+ num_bytes = min_t(int, spi_qup_len(controller) -
+ controller->tx_bytes,
+ controller->w_size);
if (tx_buf)
for (i = 0; i < num_bytes; i++) {
data = tx_buf[controller->tx_bytes + i];
@@ -338,13 +345,12 @@ static void spi_qup_dma_done(void *data)
complete(&qup->done);
}
-static void spi_qup_write(struct spi_qup *controller,
- struct spi_transfer *xfer)
+static void spi_qup_write(struct spi_qup *controller)
{
bool is_block_mode = controller->mode == QUP_IO_M_MODE_BLOCK;
u32 remainder, words_per_block, num_words;
- remainder = DIV_ROUND_UP(xfer->len - controller->tx_bytes,
+ remainder = DIV_ROUND_UP(spi_qup_len(controller) - controller->tx_bytes,
controller->w_size);
words_per_block = controller->out_blk_sz >> 2;
@@ -364,7 +370,7 @@ static void spi_qup_write(struct spi_qup *controller,
num_words = 1;
}
- spi_qup_write_to_fifo(controller, xfer, num_words);
+ spi_qup_write_to_fifo(controller, num_words);
remainder -= num_words;
@@ -474,36 +480,62 @@ static int spi_qup_do_pio(struct spi_device *spi, struct spi_transfer *xfer,
{
struct spi_master *master = spi->master;
struct spi_qup *qup = spi_master_get_devdata(master);
- int ret;
+ int ret, n_words, iterations, offset = 0;
- ret = spi_qup_io_config(spi, xfer);
- if (ret)
- return ret;
+ n_words = qup->n_words;
+ iterations = n_words / SPI_MAX_XFER; /* round down */
+ qup->rx_buf = xfer->rx_buf;
+ qup->tx_buf = xfer->tx_buf;
- ret = spi_qup_set_state(qup, QUP_STATE_RUN);
- if (ret) {
- dev_warn(qup->dev, "cannot set RUN state\n");
- return ret;
- }
+ do {
+ if (iterations)
+ qup->n_words = SPI_MAX_XFER;
+ else
+ qup->n_words = n_words % SPI_MAX_XFER;
- ret = spi_qup_set_state(qup, QUP_STATE_PAUSE);
- if (ret) {
- dev_warn(qup->dev, "cannot set PAUSE state\n");
- return ret;
- }
+ if (qup->tx_buf && offset)
+ qup->tx_buf = xfer->tx_buf + offset * SPI_MAX_XFER;
- if (qup->mode == QUP_IO_M_MODE_FIFO)
- spi_qup_write(qup, xfer);
+ if (qup->rx_buf && offset)
+ qup->rx_buf = xfer->rx_buf + offset * SPI_MAX_XFER;
- ret = spi_qup_set_state(qup, QUP_STATE_RUN);
- if (ret) {
- dev_warn(qup->dev, "%s(%d): cannot set RUN state\n",
- __func__, __LINE__);
- return ret;
- }
+ /*
+ * if the transaction is small enough, we need
+ * to fallback to FIFO mode
+ */
+ if (qup->n_words <= (qup->in_fifo_sz / sizeof(u32)))
+ qup->mode = QUP_IO_M_MODE_FIFO;
- if (!wait_for_completion_timeout(&qup->done, timeout))
- return -ETIMEDOUT;
+ ret = spi_qup_io_config(spi, xfer);
+ if (ret)
+ return ret;
+
+ ret = spi_qup_set_state(qup, QUP_STATE_RUN);
+ if (ret) {
+ dev_warn(qup->dev, "cannot set RUN state\n");
+ return ret;
+ }
+
+ ret = spi_qup_set_state(qup, QUP_STATE_PAUSE);
+ if (ret) {
+ dev_warn(qup->dev, "cannot set PAUSE state\n");
+ return ret;
+ }
+
+ if (qup->mode == QUP_IO_M_MODE_FIFO)
+ spi_qup_write(qup);
+
+ ret = spi_qup_set_state(qup, QUP_STATE_RUN);
+ if (ret) {
+ dev_warn(qup->dev, "cannot set RUN state\n");
+ return ret;
+ }
+
+ if (!wait_for_completion_timeout(&qup->done, timeout))
+ return -ETIMEDOUT;
+
+ offset++;
+ } while (iterations--);
return 0;
}
@@ -511,7 +543,6 @@ static int spi_qup_do_pio(struct spi_device *spi, struct spi_transfer *xfer,
static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id)
{
struct spi_qup *controller = dev_id;
- struct spi_transfer *xfer = controller->xfer;
u32 opflags, qup_err, spi_err;
int error = 0;
@@ -548,10 +579,10 @@ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id)
writel_relaxed(opflags, controller->base + QUP_OPERATIONAL);
} else {
if (opflags & QUP_OP_IN_SERVICE_FLAG)
- spi_qup_read(controller, xfer);
+ spi_qup_read(controller);
if (opflags & QUP_OP_OUT_SERVICE_FLAG)
- spi_qup_write(controller, xfer);
+ spi_qup_write(controller);
}
if ((opflags & QUP_OP_MAX_INPUT_DONE_FLAG) || error)
@@ -758,7 +789,8 @@ static int spi_qup_transfer_one(struct spi_master *master,
return ret;
timeout = DIV_ROUND_UP(xfer->speed_hz, MSEC_PER_SEC);
- timeout = DIV_ROUND_UP(xfer->len * 8, timeout);
+ timeout = DIV_ROUND_UP(min_t(unsigned long, SPI_MAX_XFER,
+ xfer->len) * 8, timeout);
timeout = 100 * msecs_to_jiffies(timeout);
reinit_completion(&controller->done);
@@ -972,7 +1004,7 @@ static int spi_qup_probe(struct platform_device *pdev)
master->dev.of_node = pdev->dev.of_node;
master->auto_runtime_pm = true;
master->dma_alignment = dma_get_cache_alignment();
- master->max_dma_len = SPI_MAX_DMA_XFER;
+ master->max_dma_len = SPI_MAX_XFER;
platform_set_drvdata(pdev, master);
--
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
^ permalink raw reply related [flat|nested] 43+ messages in thread
* Applied "spi: qup: allow block mode to generate multiple transactions" to the spi tree
2017-07-24 7:47 ` Varadarajan Narayanan
@ 2017-08-08 11:18 ` Mark Brown
-1 siblings, 0 replies; 43+ messages in thread
From: Mark Brown @ 2017-08-08 11:18 UTC (permalink / raw)
To: Varadarajan Narayanan; +Cc: Matthew McClintock, Mark Brown
The patch
spi: qup: allow block mode to generate multiple transactions
has been applied to the spi tree at
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git
All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying
to this mail.
Thanks,
Mark
>From 5dc47fefe1d470da47dd400796bbf93ffe82fd33 Mon Sep 17 00:00:00 2001
From: Varadarajan Narayanan <varada@codeaurora.org>
Date: Fri, 28 Jul 2017 12:22:57 +0530
Subject: [PATCH] spi: qup: allow block mode to generate multiple transactions
This let's you write more to the SPI bus than 64K-1 which is important
if the block size of a SPI device is >= 64K or some other device wants
to do something larger.
This has the benefit of completely removing spi_message from the spi-qup
transactions
Signed-off-by: Matthew McClintock <mmcclint@codeaurora.org>
Signed-off-by: Varadarajan Narayanan <varada@codeaurora.org>
Signed-off-by: Mark Brown <broonie@kernel.org>
---
drivers/spi/spi-qup.c | 128 +++++++++++++++++++++++++++++++-------------------
1 file changed, 80 insertions(+), 48 deletions(-)
diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c
index 1aa60785bf98..707b1ec427fa 100644
--- a/drivers/spi/spi-qup.c
+++ b/drivers/spi/spi-qup.c
@@ -120,7 +120,7 @@
#define SPI_NUM_CHIPSELECTS 4
-#define SPI_MAX_DMA_XFER (SZ_64K - 64)
+#define SPI_MAX_XFER (SZ_64K - 64)
/* high speed mode is when bus rate is greater then 26MHz */
#define SPI_HS_MIN_RATE 26000000
@@ -149,6 +149,8 @@ struct spi_qup {
int n_words;
int tx_bytes;
int rx_bytes;
+ const u8 *tx_buf;
+ u8 *rx_buf;
int qup_v1;
int mode;
@@ -173,6 +175,12 @@ static inline bool spi_qup_is_dma_xfer(int mode)
return false;
}
+/* get's the transaction size length */
+static inline unsigned int spi_qup_len(struct spi_qup *controller)
+{
+ return controller->n_words * controller->w_size;
+}
+
static inline bool spi_qup_is_valid_state(struct spi_qup *controller)
{
u32 opstate = readl_relaxed(controller->base + QUP_STATE);
@@ -225,10 +233,9 @@ static int spi_qup_set_state(struct spi_qup *controller, u32 state)
return 0;
}
-static void spi_qup_read_from_fifo(struct spi_qup *controller,
- struct spi_transfer *xfer, u32 num_words)
+static void spi_qup_read_from_fifo(struct spi_qup *controller, u32 num_words)
{
- u8 *rx_buf = xfer->rx_buf;
+ u8 *rx_buf = controller->rx_buf;
int i, shift, num_bytes;
u32 word;
@@ -236,8 +243,9 @@ static void spi_qup_read_from_fifo(struct spi_qup *controller,
word = readl_relaxed(controller->base + QUP_INPUT_FIFO);
- num_bytes = min_t(int, xfer->len - controller->rx_bytes,
- controller->w_size);
+ num_bytes = min_t(int, spi_qup_len(controller) -
+ controller->rx_bytes,
+ controller->w_size);
if (!rx_buf) {
controller->rx_bytes += num_bytes;
@@ -258,13 +266,12 @@ static void spi_qup_read_from_fifo(struct spi_qup *controller,
}
}
-static void spi_qup_read(struct spi_qup *controller,
- struct spi_transfer *xfer)
+static void spi_qup_read(struct spi_qup *controller)
{
u32 remainder, words_per_block, num_words;
bool is_block_mode = controller->mode == QUP_IO_M_MODE_BLOCK;
- remainder = DIV_ROUND_UP(xfer->len - controller->rx_bytes,
+ remainder = DIV_ROUND_UP(spi_qup_len(controller) - controller->rx_bytes,
controller->w_size);
words_per_block = controller->in_blk_sz >> 2;
@@ -285,7 +292,7 @@ static void spi_qup_read(struct spi_qup *controller,
}
/* read up to the maximum transfer size available */
- spi_qup_read_from_fifo(controller, xfer, num_words);
+ spi_qup_read_from_fifo(controller, num_words);
remainder -= num_words;
@@ -307,18 +314,18 @@ static void spi_qup_read(struct spi_qup *controller,
}
-static void spi_qup_write_to_fifo(struct spi_qup *controller,
- struct spi_transfer *xfer, u32 num_words)
+static void spi_qup_write_to_fifo(struct spi_qup *controller, u32 num_words)
{
- const u8 *tx_buf = xfer->tx_buf;
+ const u8 *tx_buf = controller->tx_buf;
int i, num_bytes;
u32 word, data;
for (; num_words; num_words--) {
word = 0;
- num_bytes = min_t(int, xfer->len - controller->tx_bytes,
- controller->w_size);
+ num_bytes = min_t(int, spi_qup_len(controller) -
+ controller->tx_bytes,
+ controller->w_size);
if (tx_buf)
for (i = 0; i < num_bytes; i++) {
data = tx_buf[controller->tx_bytes + i];
@@ -338,13 +345,12 @@ static void spi_qup_dma_done(void *data)
complete(&qup->done);
}
-static void spi_qup_write(struct spi_qup *controller,
- struct spi_transfer *xfer)
+static void spi_qup_write(struct spi_qup *controller)
{
bool is_block_mode = controller->mode == QUP_IO_M_MODE_BLOCK;
u32 remainder, words_per_block, num_words;
- remainder = DIV_ROUND_UP(xfer->len - controller->tx_bytes,
+ remainder = DIV_ROUND_UP(spi_qup_len(controller) - controller->tx_bytes,
controller->w_size);
words_per_block = controller->out_blk_sz >> 2;
@@ -364,7 +370,7 @@ static void spi_qup_write(struct spi_qup *controller,
num_words = 1;
}
- spi_qup_write_to_fifo(controller, xfer, num_words);
+ spi_qup_write_to_fifo(controller, num_words);
remainder -= num_words;
@@ -471,36 +477,62 @@ static int spi_qup_do_pio(struct spi_device *spi, struct spi_transfer *xfer,
{
struct spi_master *master = spi->master;
struct spi_qup *qup = spi_master_get_devdata(master);
- int ret;
+ int ret, n_words, iterations, offset = 0;
- ret = spi_qup_io_config(spi, xfer);
- if (ret)
- return ret;
+ n_words = qup->n_words;
+ iterations = n_words / SPI_MAX_XFER; /* round down */
+ qup->rx_buf = xfer->rx_buf;
+ qup->tx_buf = xfer->tx_buf;
- ret = spi_qup_set_state(qup, QUP_STATE_RUN);
- if (ret) {
- dev_warn(qup->dev, "cannot set RUN state\n");
- return ret;
- }
+ do {
+ if (iterations)
+ qup->n_words = SPI_MAX_XFER;
+ else
+ qup->n_words = n_words % SPI_MAX_XFER;
- ret = spi_qup_set_state(qup, QUP_STATE_PAUSE);
- if (ret) {
- dev_warn(qup->dev, "cannot set PAUSE state\n");
- return ret;
- }
+ if (qup->tx_buf && offset)
+ qup->tx_buf = xfer->tx_buf + offset * SPI_MAX_XFER;
- if (qup->mode == QUP_IO_M_MODE_FIFO)
- spi_qup_write(qup, xfer);
+ if (qup->rx_buf && offset)
+ qup->rx_buf = xfer->rx_buf + offset * SPI_MAX_XFER;
- ret = spi_qup_set_state(qup, QUP_STATE_RUN);
- if (ret) {
- dev_warn(qup->dev, "%s(%d): cannot set RUN state\n",
- __func__, __LINE__);
- return ret;
- }
+ /*
+ * if the transaction is small enough, we need
+ * to fallback to FIFO mode
+ */
+ if (qup->n_words <= (qup->in_fifo_sz / sizeof(u32)))
+ qup->mode = QUP_IO_M_MODE_FIFO;
- if (!wait_for_completion_timeout(&qup->done, timeout))
- return -ETIMEDOUT;
+ ret = spi_qup_io_config(spi, xfer);
+ if (ret)
+ return ret;
+
+ ret = spi_qup_set_state(qup, QUP_STATE_RUN);
+ if (ret) {
+ dev_warn(qup->dev, "cannot set RUN state\n");
+ return ret;
+ }
+
+ ret = spi_qup_set_state(qup, QUP_STATE_PAUSE);
+ if (ret) {
+ dev_warn(qup->dev, "cannot set PAUSE state\n");
+ return ret;
+ }
+
+ if (qup->mode == QUP_IO_M_MODE_FIFO)
+ spi_qup_write(qup);
+
+ ret = spi_qup_set_state(qup, QUP_STATE_RUN);
+ if (ret) {
+ dev_warn(qup->dev, "cannot set RUN state\n");
+ return ret;
+ }
+
+ if (!wait_for_completion_timeout(&qup->done, timeout))
+ return -ETIMEDOUT;
+
+ offset++;
+ } while (iterations--);
return 0;
}
@@ -508,7 +540,6 @@ static int spi_qup_do_pio(struct spi_device *spi, struct spi_transfer *xfer,
static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id)
{
struct spi_qup *controller = dev_id;
- struct spi_transfer *xfer = controller->xfer;
u32 opflags, qup_err, spi_err;
int error = 0;
@@ -545,10 +576,10 @@ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id)
writel_relaxed(opflags, controller->base + QUP_OPERATIONAL);
} else {
if (opflags & QUP_OP_IN_SERVICE_FLAG)
- spi_qup_read(controller, xfer);
+ spi_qup_read(controller);
if (opflags & QUP_OP_OUT_SERVICE_FLAG)
- spi_qup_write(controller, xfer);
+ spi_qup_write(controller);
}
if ((opflags & QUP_OP_MAX_INPUT_DONE_FLAG) || error)
@@ -755,7 +786,8 @@ static int spi_qup_transfer_one(struct spi_master *master,
return ret;
timeout = DIV_ROUND_UP(xfer->speed_hz, MSEC_PER_SEC);
- timeout = DIV_ROUND_UP(xfer->len * 8, timeout);
+ timeout = DIV_ROUND_UP(min_t(unsigned long, SPI_MAX_XFER,
+ xfer->len) * 8, timeout);
timeout = 100 * msecs_to_jiffies(timeout);
reinit_completion(&controller->done);
@@ -969,7 +1001,7 @@ static int spi_qup_probe(struct platform_device *pdev)
master->dev.of_node = pdev->dev.of_node;
master->auto_runtime_pm = true;
master->dma_alignment = dma_get_cache_alignment();
- master->max_dma_len = SPI_MAX_DMA_XFER;
+ master->max_dma_len = SPI_MAX_XFER;
platform_set_drvdata(pdev, master);
--
2.13.2
^ permalink raw reply related [flat|nested] 43+ messages in thread
* Applied "spi: qup: allow block mode to generate multiple transactions" to the spi tree
@ 2017-08-08 11:18 ` Mark Brown
0 siblings, 0 replies; 43+ messages in thread
From: Mark Brown @ 2017-08-08 11:18 UTC (permalink / raw)
To: Varadarajan Narayanan
Cc: Matthew McClintock, Mark Brown, broonie, robh+dt, mark.rutland,
andy.gross, david.brown, linux-spi, devicetree, linux-kernel,
linux-arm-msm, linux-soc, Matthew McClintock, linux-spi
The patch
spi: qup: allow block mode to generate multiple transactions
has been applied to the spi tree at
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git
All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying
to this mail.
Thanks,
Mark
>From 5dc47fefe1d470da47dd400796bbf93ffe82fd33 Mon Sep 17 00:00:00 2001
From: Varadarajan Narayanan <varada@codeaurora.org>
Date: Fri, 28 Jul 2017 12:22:57 +0530
Subject: [PATCH] spi: qup: allow block mode to generate multiple transactions
This let's you write more to the SPI bus than 64K-1 which is important
if the block size of a SPI device is >= 64K or some other device wants
to do something larger.
This has the benefit of completely removing spi_message from the spi-qup
transactions
Signed-off-by: Matthew McClintock <mmcclint@codeaurora.org>
Signed-off-by: Varadarajan Narayanan <varada@codeaurora.org>
Signed-off-by: Mark Brown <broonie@kernel.org>
---
drivers/spi/spi-qup.c | 128 +++++++++++++++++++++++++++++++-------------------
1 file changed, 80 insertions(+), 48 deletions(-)
diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c
index 1aa60785bf98..707b1ec427fa 100644
--- a/drivers/spi/spi-qup.c
+++ b/drivers/spi/spi-qup.c
@@ -120,7 +120,7 @@
#define SPI_NUM_CHIPSELECTS 4
-#define SPI_MAX_DMA_XFER (SZ_64K - 64)
+#define SPI_MAX_XFER (SZ_64K - 64)
/* high speed mode is when bus rate is greater then 26MHz */
#define SPI_HS_MIN_RATE 26000000
@@ -149,6 +149,8 @@ struct spi_qup {
int n_words;
int tx_bytes;
int rx_bytes;
+ const u8 *tx_buf;
+ u8 *rx_buf;
int qup_v1;
int mode;
@@ -173,6 +175,12 @@ static inline bool spi_qup_is_dma_xfer(int mode)
return false;
}
+/* get's the transaction size length */
+static inline unsigned int spi_qup_len(struct spi_qup *controller)
+{
+ return controller->n_words * controller->w_size;
+}
+
static inline bool spi_qup_is_valid_state(struct spi_qup *controller)
{
u32 opstate = readl_relaxed(controller->base + QUP_STATE);
@@ -225,10 +233,9 @@ static int spi_qup_set_state(struct spi_qup *controller, u32 state)
return 0;
}
-static void spi_qup_read_from_fifo(struct spi_qup *controller,
- struct spi_transfer *xfer, u32 num_words)
+static void spi_qup_read_from_fifo(struct spi_qup *controller, u32 num_words)
{
- u8 *rx_buf = xfer->rx_buf;
+ u8 *rx_buf = controller->rx_buf;
int i, shift, num_bytes;
u32 word;
@@ -236,8 +243,9 @@ static void spi_qup_read_from_fifo(struct spi_qup *controller,
word = readl_relaxed(controller->base + QUP_INPUT_FIFO);
- num_bytes = min_t(int, xfer->len - controller->rx_bytes,
- controller->w_size);
+ num_bytes = min_t(int, spi_qup_len(controller) -
+ controller->rx_bytes,
+ controller->w_size);
if (!rx_buf) {
controller->rx_bytes += num_bytes;
@@ -258,13 +266,12 @@ static void spi_qup_read_from_fifo(struct spi_qup *controller,
}
}
-static void spi_qup_read(struct spi_qup *controller,
- struct spi_transfer *xfer)
+static void spi_qup_read(struct spi_qup *controller)
{
u32 remainder, words_per_block, num_words;
bool is_block_mode = controller->mode == QUP_IO_M_MODE_BLOCK;
- remainder = DIV_ROUND_UP(xfer->len - controller->rx_bytes,
+ remainder = DIV_ROUND_UP(spi_qup_len(controller) - controller->rx_bytes,
controller->w_size);
words_per_block = controller->in_blk_sz >> 2;
@@ -285,7 +292,7 @@ static void spi_qup_read(struct spi_qup *controller,
}
/* read up to the maximum transfer size available */
- spi_qup_read_from_fifo(controller, xfer, num_words);
+ spi_qup_read_from_fifo(controller, num_words);
remainder -= num_words;
@@ -307,18 +314,18 @@ static void spi_qup_read(struct spi_qup *controller,
}
-static void spi_qup_write_to_fifo(struct spi_qup *controller,
- struct spi_transfer *xfer, u32 num_words)
+static void spi_qup_write_to_fifo(struct spi_qup *controller, u32 num_words)
{
- const u8 *tx_buf = xfer->tx_buf;
+ const u8 *tx_buf = controller->tx_buf;
int i, num_bytes;
u32 word, data;
for (; num_words; num_words--) {
word = 0;
- num_bytes = min_t(int, xfer->len - controller->tx_bytes,
- controller->w_size);
+ num_bytes = min_t(int, spi_qup_len(controller) -
+ controller->tx_bytes,
+ controller->w_size);
if (tx_buf)
for (i = 0; i < num_bytes; i++) {
data = tx_buf[controller->tx_bytes + i];
@@ -338,13 +345,12 @@ static void spi_qup_dma_done(void *data)
complete(&qup->done);
}
-static void spi_qup_write(struct spi_qup *controller,
- struct spi_transfer *xfer)
+static void spi_qup_write(struct spi_qup *controller)
{
bool is_block_mode = controller->mode == QUP_IO_M_MODE_BLOCK;
u32 remainder, words_per_block, num_words;
- remainder = DIV_ROUND_UP(xfer->len - controller->tx_bytes,
+ remainder = DIV_ROUND_UP(spi_qup_len(controller) - controller->tx_bytes,
controller->w_size);
words_per_block = controller->out_blk_sz >> 2;
@@ -364,7 +370,7 @@ static void spi_qup_write(struct spi_qup *controller,
num_words = 1;
}
- spi_qup_write_to_fifo(controller, xfer, num_words);
+ spi_qup_write_to_fifo(controller, num_words);
remainder -= num_words;
@@ -471,36 +477,62 @@ static int spi_qup_do_pio(struct spi_device *spi, struct spi_transfer *xfer,
{
struct spi_master *master = spi->master;
struct spi_qup *qup = spi_master_get_devdata(master);
- int ret;
+ int ret, n_words, iterations, offset = 0;
- ret = spi_qup_io_config(spi, xfer);
- if (ret)
- return ret;
+ n_words = qup->n_words;
+ iterations = n_words / SPI_MAX_XFER; /* round down */
+ qup->rx_buf = xfer->rx_buf;
+ qup->tx_buf = xfer->tx_buf;
- ret = spi_qup_set_state(qup, QUP_STATE_RUN);
- if (ret) {
- dev_warn(qup->dev, "cannot set RUN state\n");
- return ret;
- }
+ do {
+ if (iterations)
+ qup->n_words = SPI_MAX_XFER;
+ else
+ qup->n_words = n_words % SPI_MAX_XFER;
- ret = spi_qup_set_state(qup, QUP_STATE_PAUSE);
- if (ret) {
- dev_warn(qup->dev, "cannot set PAUSE state\n");
- return ret;
- }
+ if (qup->tx_buf && offset)
+ qup->tx_buf = xfer->tx_buf + offset * SPI_MAX_XFER;
- if (qup->mode == QUP_IO_M_MODE_FIFO)
- spi_qup_write(qup, xfer);
+ if (qup->rx_buf && offset)
+ qup->rx_buf = xfer->rx_buf + offset * SPI_MAX_XFER;
- ret = spi_qup_set_state(qup, QUP_STATE_RUN);
- if (ret) {
- dev_warn(qup->dev, "%s(%d): cannot set RUN state\n",
- __func__, __LINE__);
- return ret;
- }
+ /*
+ * if the transaction is small enough, we need
+ * to fallback to FIFO mode
+ */
+ if (qup->n_words <= (qup->in_fifo_sz / sizeof(u32)))
+ qup->mode = QUP_IO_M_MODE_FIFO;
- if (!wait_for_completion_timeout(&qup->done, timeout))
- return -ETIMEDOUT;
+ ret = spi_qup_io_config(spi, xfer);
+ if (ret)
+ return ret;
+
+ ret = spi_qup_set_state(qup, QUP_STATE_RUN);
+ if (ret) {
+ dev_warn(qup->dev, "cannot set RUN state\n");
+ return ret;
+ }
+
+ ret = spi_qup_set_state(qup, QUP_STATE_PAUSE);
+ if (ret) {
+ dev_warn(qup->dev, "cannot set PAUSE state\n");
+ return ret;
+ }
+
+ if (qup->mode == QUP_IO_M_MODE_FIFO)
+ spi_qup_write(qup);
+
+ ret = spi_qup_set_state(qup, QUP_STATE_RUN);
+ if (ret) {
+ dev_warn(qup->dev, "cannot set RUN state\n");
+ return ret;
+ }
+
+ if (!wait_for_completion_timeout(&qup->done, timeout))
+ return -ETIMEDOUT;
+
+ offset++;
+ } while (iterations--);
return 0;
}
@@ -508,7 +540,6 @@ static int spi_qup_do_pio(struct spi_device *spi, struct spi_transfer *xfer,
static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id)
{
struct spi_qup *controller = dev_id;
- struct spi_transfer *xfer = controller->xfer;
u32 opflags, qup_err, spi_err;
int error = 0;
@@ -545,10 +576,10 @@ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id)
writel_relaxed(opflags, controller->base + QUP_OPERATIONAL);
} else {
if (opflags & QUP_OP_IN_SERVICE_FLAG)
- spi_qup_read(controller, xfer);
+ spi_qup_read(controller);
if (opflags & QUP_OP_OUT_SERVICE_FLAG)
- spi_qup_write(controller, xfer);
+ spi_qup_write(controller);
}
if ((opflags & QUP_OP_MAX_INPUT_DONE_FLAG) || error)
@@ -755,7 +786,8 @@ static int spi_qup_transfer_one(struct spi_master *master,
return ret;
timeout = DIV_ROUND_UP(xfer->speed_hz, MSEC_PER_SEC);
- timeout = DIV_ROUND_UP(xfer->len * 8, timeout);
+ timeout = DIV_ROUND_UP(min_t(unsigned long, SPI_MAX_XFER,
+ xfer->len) * 8, timeout);
timeout = 100 * msecs_to_jiffies(timeout);
reinit_completion(&controller->done);
@@ -969,7 +1001,7 @@ static int spi_qup_probe(struct platform_device *pdev)
master->dev.of_node = pdev->dev.of_node;
master->auto_runtime_pm = true;
master->dma_alignment = dma_get_cache_alignment();
- master->max_dma_len = SPI_MAX_DMA_XFER;
+ master->max_dma_len = SPI_MAX_XFER;
platform_set_drvdata(pdev, master);
--
2.13.2
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [PATCH v5 11/14] spi: qup: refactor spi_qup_prep_sg
2017-07-24 7:47 [PATCH v5 00/14] spi: qup: Fixes and add support for >64k transfers Varadarajan Narayanan
@ 2017-07-24 7:47 ` Varadarajan Narayanan
[not found] ` <1500882445-29008-1-git-send-email-varada-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
` (5 subsequent siblings)
6 siblings, 0 replies; 43+ messages in thread
From: Varadarajan Narayanan @ 2017-07-24 7:47 UTC (permalink / raw)
To: broonie-DgEjT+Ai2ygdnm+yROfE0A, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
mark.rutland-5wv7dgnIgG8, andy.gross-QSEj5FYQhm4dnm+yROfE0A,
david.brown-QSEj5FYQhm4dnm+yROfE0A,
linux-spi-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-arm-msm-u79uwXL29TY76Z2rM5mHXA,
linux-soc-u79uwXL29TY76Z2rM5mHXA
Cc: Varadarajan Narayanan, Matthew McClintock
Take specific sgl and nent to be prepared. This is in
preparation for splitting DMA into multiple transacations, this
contains no code changes just refactoring.
Signed-off-by: Matthew McClintock <mmcclint-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
Signed-off-by: Varadarajan Narayanan <varada-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
---
drivers/spi/spi-qup.c | 23 ++++++++++-------------
1 file changed, 10 insertions(+), 13 deletions(-)
diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c
index 67e7463..3ac9b25 100644
--- a/drivers/spi/spi-qup.c
+++ b/drivers/spi/spi-qup.c
@@ -382,27 +382,20 @@ static void spi_qup_write(struct spi_qup *controller)
} while (remainder);
}
-static int spi_qup_prep_sg(struct spi_master *master, struct spi_transfer *xfer,
- enum dma_transfer_direction dir,
+static int spi_qup_prep_sg(struct spi_master *master, struct scatterlist *sgl,
+ unsigned int nents, enum dma_transfer_direction dir,
dma_async_tx_callback callback)
{
struct spi_qup *qup = spi_master_get_devdata(master);
unsigned long flags = DMA_PREP_INTERRUPT | DMA_PREP_FENCE;
struct dma_async_tx_descriptor *desc;
- struct scatterlist *sgl;
struct dma_chan *chan;
dma_cookie_t cookie;
- unsigned int nents;
- if (dir == DMA_MEM_TO_DEV) {
+ if (dir == DMA_MEM_TO_DEV)
chan = master->dma_tx;
- nents = xfer->tx_sg.nents;
- sgl = xfer->tx_sg.sgl;
- } else {
+ else
chan = master->dma_rx;
- nents = xfer->rx_sg.nents;
- sgl = xfer->rx_sg.sgl;
- }
desc = dmaengine_prep_slave_sg(chan, sgl, nents, dir, flags);
if (IS_ERR_OR_NULL(desc))
@@ -451,7 +444,9 @@ static int spi_qup_do_dma(struct spi_device *spi, struct spi_transfer *xfer,
}
if (xfer->rx_buf) {
- ret = spi_qup_prep_sg(master, xfer, DMA_DEV_TO_MEM, rx_done);
+ ret = spi_qup_prep_sg(master, xfer->rx_sg.sgl,
+ xfer->rx_sg.nents, DMA_DEV_TO_MEM,
+ rx_done);
if (ret)
return ret;
@@ -459,7 +454,9 @@ static int spi_qup_do_dma(struct spi_device *spi, struct spi_transfer *xfer,
}
if (xfer->tx_buf) {
- ret = spi_qup_prep_sg(master, xfer, DMA_MEM_TO_DEV, tx_done);
+ ret = spi_qup_prep_sg(master, xfer->tx_sg.sgl,
+ xfer->tx_sg.nents, DMA_MEM_TO_DEV,
+ tx_done);
if (ret)
return ret;
--
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [PATCH v5 11/14] spi: qup: refactor spi_qup_prep_sg
@ 2017-07-24 7:47 ` Varadarajan Narayanan
0 siblings, 0 replies; 43+ messages in thread
From: Varadarajan Narayanan @ 2017-07-24 7:47 UTC (permalink / raw)
To: broonie, robh+dt, mark.rutland, andy.gross, david.brown,
linux-spi, devicetree, linux-kernel, linux-arm-msm, linux-soc
Cc: Varadarajan Narayanan, Matthew McClintock
Take specific sgl and nent to be prepared. This is in
preparation for splitting DMA into multiple transacations, this
contains no code changes just refactoring.
Signed-off-by: Matthew McClintock <mmcclint@codeaurora.org>
Signed-off-by: Varadarajan Narayanan <varada@codeaurora.org>
---
drivers/spi/spi-qup.c | 23 ++++++++++-------------
1 file changed, 10 insertions(+), 13 deletions(-)
diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c
index 67e7463..3ac9b25 100644
--- a/drivers/spi/spi-qup.c
+++ b/drivers/spi/spi-qup.c
@@ -382,27 +382,20 @@ static void spi_qup_write(struct spi_qup *controller)
} while (remainder);
}
-static int spi_qup_prep_sg(struct spi_master *master, struct spi_transfer *xfer,
- enum dma_transfer_direction dir,
+static int spi_qup_prep_sg(struct spi_master *master, struct scatterlist *sgl,
+ unsigned int nents, enum dma_transfer_direction dir,
dma_async_tx_callback callback)
{
struct spi_qup *qup = spi_master_get_devdata(master);
unsigned long flags = DMA_PREP_INTERRUPT | DMA_PREP_FENCE;
struct dma_async_tx_descriptor *desc;
- struct scatterlist *sgl;
struct dma_chan *chan;
dma_cookie_t cookie;
- unsigned int nents;
- if (dir == DMA_MEM_TO_DEV) {
+ if (dir == DMA_MEM_TO_DEV)
chan = master->dma_tx;
- nents = xfer->tx_sg.nents;
- sgl = xfer->tx_sg.sgl;
- } else {
+ else
chan = master->dma_rx;
- nents = xfer->rx_sg.nents;
- sgl = xfer->rx_sg.sgl;
- }
desc = dmaengine_prep_slave_sg(chan, sgl, nents, dir, flags);
if (IS_ERR_OR_NULL(desc))
@@ -451,7 +444,9 @@ static int spi_qup_do_dma(struct spi_device *spi, struct spi_transfer *xfer,
}
if (xfer->rx_buf) {
- ret = spi_qup_prep_sg(master, xfer, DMA_DEV_TO_MEM, rx_done);
+ ret = spi_qup_prep_sg(master, xfer->rx_sg.sgl,
+ xfer->rx_sg.nents, DMA_DEV_TO_MEM,
+ rx_done);
if (ret)
return ret;
@@ -459,7 +454,9 @@ static int spi_qup_do_dma(struct spi_device *spi, struct spi_transfer *xfer,
}
if (xfer->tx_buf) {
- ret = spi_qup_prep_sg(master, xfer, DMA_MEM_TO_DEV, tx_done);
+ ret = spi_qup_prep_sg(master, xfer->tx_sg.sgl,
+ xfer->tx_sg.nents, DMA_MEM_TO_DEV,
+ tx_done);
if (ret)
return ret;
--
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
^ permalink raw reply related [flat|nested] 43+ messages in thread
* Applied "spi: qup: refactor spi_qup_prep_sg" to the spi tree
2017-07-24 7:47 ` Varadarajan Narayanan
@ 2017-08-08 11:18 ` Mark Brown
-1 siblings, 0 replies; 43+ messages in thread
From: Mark Brown @ 2017-08-08 11:18 UTC (permalink / raw)
To: Varadarajan Narayanan; +Cc: Matthew McClintock, Mark Brown
The patch
spi: qup: refactor spi_qup_prep_sg
has been applied to the spi tree at
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git
All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying
to this mail.
Thanks,
Mark
>From a841b24e627ca2d3b6a23ca00a4908bfe8f3a5ef Mon Sep 17 00:00:00 2001
From: Varadarajan Narayanan <varada@codeaurora.org>
Date: Fri, 28 Jul 2017 12:22:58 +0530
Subject: [PATCH] spi: qup: refactor spi_qup_prep_sg
Take specific sgl and nent to be prepared. This is in
preparation for splitting DMA into multiple transacations, this
contains no code changes just refactoring.
Signed-off-by: Matthew McClintock <mmcclint@codeaurora.org>
Signed-off-by: Varadarajan Narayanan <varada@codeaurora.org>
Signed-off-by: Mark Brown <broonie@kernel.org>
---
drivers/spi/spi-qup.c | 23 ++++++++++-------------
1 file changed, 10 insertions(+), 13 deletions(-)
diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c
index 707b1ec427fa..1af3b41ac12d 100644
--- a/drivers/spi/spi-qup.c
+++ b/drivers/spi/spi-qup.c
@@ -382,27 +382,20 @@ static void spi_qup_write(struct spi_qup *controller)
} while (remainder);
}
-static int spi_qup_prep_sg(struct spi_master *master, struct spi_transfer *xfer,
- enum dma_transfer_direction dir,
+static int spi_qup_prep_sg(struct spi_master *master, struct scatterlist *sgl,
+ unsigned int nents, enum dma_transfer_direction dir,
dma_async_tx_callback callback)
{
struct spi_qup *qup = spi_master_get_devdata(master);
unsigned long flags = DMA_PREP_INTERRUPT | DMA_PREP_FENCE;
struct dma_async_tx_descriptor *desc;
- struct scatterlist *sgl;
struct dma_chan *chan;
dma_cookie_t cookie;
- unsigned int nents;
- if (dir == DMA_MEM_TO_DEV) {
+ if (dir == DMA_MEM_TO_DEV)
chan = master->dma_tx;
- nents = xfer->tx_sg.nents;
- sgl = xfer->tx_sg.sgl;
- } else {
+ else
chan = master->dma_rx;
- nents = xfer->rx_sg.nents;
- sgl = xfer->rx_sg.sgl;
- }
desc = dmaengine_prep_slave_sg(chan, sgl, nents, dir, flags);
if (IS_ERR_OR_NULL(desc))
@@ -451,7 +444,9 @@ static int spi_qup_do_dma(struct spi_device *spi, struct spi_transfer *xfer,
}
if (xfer->rx_buf) {
- ret = spi_qup_prep_sg(master, xfer, DMA_DEV_TO_MEM, rx_done);
+ ret = spi_qup_prep_sg(master, xfer->rx_sg.sgl,
+ xfer->rx_sg.nents, DMA_DEV_TO_MEM,
+ rx_done);
if (ret)
return ret;
@@ -459,7 +454,9 @@ static int spi_qup_do_dma(struct spi_device *spi, struct spi_transfer *xfer,
}
if (xfer->tx_buf) {
- ret = spi_qup_prep_sg(master, xfer, DMA_MEM_TO_DEV, tx_done);
+ ret = spi_qup_prep_sg(master, xfer->tx_sg.sgl,
+ xfer->tx_sg.nents, DMA_MEM_TO_DEV,
+ tx_done);
if (ret)
return ret;
--
2.13.2
^ permalink raw reply related [flat|nested] 43+ messages in thread
* Applied "spi: qup: refactor spi_qup_prep_sg" to the spi tree
@ 2017-08-08 11:18 ` Mark Brown
0 siblings, 0 replies; 43+ messages in thread
From: Mark Brown @ 2017-08-08 11:18 UTC (permalink / raw)
To: Varadarajan Narayanan
Cc: Matthew McClintock, Mark Brown, broonie, robh+dt, mark.rutland,
andy.gross, david.brown, linux-spi, devicetree, linux-kernel,
linux-arm-msm, linux-soc, Matthew McClintock, linux-spi
The patch
spi: qup: refactor spi_qup_prep_sg
has been applied to the spi tree at
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git
All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying
to this mail.
Thanks,
Mark
>From a841b24e627ca2d3b6a23ca00a4908bfe8f3a5ef Mon Sep 17 00:00:00 2001
From: Varadarajan Narayanan <varada@codeaurora.org>
Date: Fri, 28 Jul 2017 12:22:58 +0530
Subject: [PATCH] spi: qup: refactor spi_qup_prep_sg
Take specific sgl and nent to be prepared. This is in
preparation for splitting DMA into multiple transacations, this
contains no code changes just refactoring.
Signed-off-by: Matthew McClintock <mmcclint@codeaurora.org>
Signed-off-by: Varadarajan Narayanan <varada@codeaurora.org>
Signed-off-by: Mark Brown <broonie@kernel.org>
---
drivers/spi/spi-qup.c | 23 ++++++++++-------------
1 file changed, 10 insertions(+), 13 deletions(-)
diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c
index 707b1ec427fa..1af3b41ac12d 100644
--- a/drivers/spi/spi-qup.c
+++ b/drivers/spi/spi-qup.c
@@ -382,27 +382,20 @@ static void spi_qup_write(struct spi_qup *controller)
} while (remainder);
}
-static int spi_qup_prep_sg(struct spi_master *master, struct spi_transfer *xfer,
- enum dma_transfer_direction dir,
+static int spi_qup_prep_sg(struct spi_master *master, struct scatterlist *sgl,
+ unsigned int nents, enum dma_transfer_direction dir,
dma_async_tx_callback callback)
{
struct spi_qup *qup = spi_master_get_devdata(master);
unsigned long flags = DMA_PREP_INTERRUPT | DMA_PREP_FENCE;
struct dma_async_tx_descriptor *desc;
- struct scatterlist *sgl;
struct dma_chan *chan;
dma_cookie_t cookie;
- unsigned int nents;
- if (dir == DMA_MEM_TO_DEV) {
+ if (dir == DMA_MEM_TO_DEV)
chan = master->dma_tx;
- nents = xfer->tx_sg.nents;
- sgl = xfer->tx_sg.sgl;
- } else {
+ else
chan = master->dma_rx;
- nents = xfer->rx_sg.nents;
- sgl = xfer->rx_sg.sgl;
- }
desc = dmaengine_prep_slave_sg(chan, sgl, nents, dir, flags);
if (IS_ERR_OR_NULL(desc))
@@ -451,7 +444,9 @@ static int spi_qup_do_dma(struct spi_device *spi, struct spi_transfer *xfer,
}
if (xfer->rx_buf) {
- ret = spi_qup_prep_sg(master, xfer, DMA_DEV_TO_MEM, rx_done);
+ ret = spi_qup_prep_sg(master, xfer->rx_sg.sgl,
+ xfer->rx_sg.nents, DMA_DEV_TO_MEM,
+ rx_done);
if (ret)
return ret;
@@ -459,7 +454,9 @@ static int spi_qup_do_dma(struct spi_device *spi, struct spi_transfer *xfer,
}
if (xfer->tx_buf) {
- ret = spi_qup_prep_sg(master, xfer, DMA_MEM_TO_DEV, tx_done);
+ ret = spi_qup_prep_sg(master, xfer->tx_sg.sgl,
+ xfer->tx_sg.nents, DMA_MEM_TO_DEV,
+ tx_done);
if (ret)
return ret;
--
2.13.2
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [PATCH v5 12/14] spi: qup: allow multiple DMA transactions per spi xfer
2017-07-24 7:47 [PATCH v5 00/14] spi: qup: Fixes and add support for >64k transfers Varadarajan Narayanan
@ 2017-07-24 7:47 ` Varadarajan Narayanan
[not found] ` <1500882445-29008-1-git-send-email-varada-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
` (5 subsequent siblings)
6 siblings, 0 replies; 43+ messages in thread
From: Varadarajan Narayanan @ 2017-07-24 7:47 UTC (permalink / raw)
To: broonie-DgEjT+Ai2ygdnm+yROfE0A, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
mark.rutland-5wv7dgnIgG8, andy.gross-QSEj5FYQhm4dnm+yROfE0A,
david.brown-QSEj5FYQhm4dnm+yROfE0A,
linux-spi-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-arm-msm-u79uwXL29TY76Z2rM5mHXA,
linux-soc-u79uwXL29TY76Z2rM5mHXA
Cc: Varadarajan Narayanan, Matthew McClintock
Much like the block mode changes, we are breaking up DMA transactions
into 64K chunks so we can reset the QUP engine.
Signed-off-by: Matthew McClintock <mmcclint-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
Signed-off-by: Varadarajan Narayanan <varada-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
---
drivers/spi/spi-qup.c | 93 +++++++++++++++++++++++++++++++++++----------------
1 file changed, 65 insertions(+), 28 deletions(-)
diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c
index 3ac9b25..3c2c2c0 100644
--- a/drivers/spi/spi-qup.c
+++ b/drivers/spi/spi-qup.c
@@ -418,12 +418,35 @@ static void spi_qup_dma_terminate(struct spi_master *master,
dmaengine_terminate_all(master->dma_rx);
}
+static u32 spi_qup_sgl_get_nents_len(struct scatterlist *sgl, u32 max,
+ u32 *nents)
+{
+ struct scatterlist *sg;
+ u32 total = 0;
+
+ *nents = 0;
+
+ for (sg = sgl; sg; sg = sg_next(sg)) {
+ unsigned int len = sg_dma_len(sg);
+
+ /* check for overflow as well as limit */
+ if (((total + len) < total) || ((total + len) > max))
+ break;
+
+ total += len;
+ (*nents)++;
+ }
+
+ return total;
+}
+
static int spi_qup_do_dma(struct spi_device *spi, struct spi_transfer *xfer,
unsigned long timeout)
{
dma_async_tx_callback rx_done = NULL, tx_done = NULL;
struct spi_master *master = spi->master;
struct spi_qup *qup = spi_master_get_devdata(master);
+ struct scatterlist *tx_sgl, *rx_sgl;
int ret;
if (xfer->rx_buf)
@@ -431,43 +454,57 @@ static int spi_qup_do_dma(struct spi_device *spi, struct spi_transfer *xfer,
else if (xfer->tx_buf)
tx_done = spi_qup_dma_done;
- ret = spi_qup_io_config(spi, xfer);
- if (ret)
- return ret;
+ rx_sgl = xfer->rx_sg.sgl;
+ tx_sgl = xfer->tx_sg.sgl;
- /* before issuing the descriptors, set the QUP to run */
- ret = spi_qup_set_state(qup, QUP_STATE_RUN);
- if (ret) {
- dev_warn(qup->dev, "%s(%d): cannot set RUN state\n",
- __func__, __LINE__);
- return ret;
- }
+ do {
+ u32 rx_nents, tx_nents;
+
+ if (rx_sgl)
+ qup->n_words = spi_qup_sgl_get_nents_len(rx_sgl,
+ SPI_MAX_XFER, &rx_nents) / qup->w_size;
+ if (tx_sgl)
+ qup->n_words = spi_qup_sgl_get_nents_len(tx_sgl,
+ SPI_MAX_XFER, &tx_nents) / qup->w_size;
+ if (!qup->n_words)
+ return -EIO;
- if (xfer->rx_buf) {
- ret = spi_qup_prep_sg(master, xfer->rx_sg.sgl,
- xfer->rx_sg.nents, DMA_DEV_TO_MEM,
- rx_done);
+ ret = spi_qup_io_config(spi, xfer);
if (ret)
return ret;
- dma_async_issue_pending(master->dma_rx);
- }
-
- if (xfer->tx_buf) {
- ret = spi_qup_prep_sg(master, xfer->tx_sg.sgl,
- xfer->tx_sg.nents, DMA_MEM_TO_DEV,
- tx_done);
- if (ret)
+ /* before issuing the descriptors, set the QUP to run */
+ ret = spi_qup_set_state(qup, QUP_STATE_RUN);
+ if (ret) {
+ dev_warn(qup->dev, "cannot set RUN state\n");
return ret;
+ }
+ if (rx_sgl) {
+ ret = spi_qup_prep_sg(master, rx_sgl, rx_nents,
+ DMA_DEV_TO_MEM, rx_done);
+ if (ret)
+ return ret;
+ dma_async_issue_pending(master->dma_rx);
+ }
- dma_async_issue_pending(master->dma_tx);
- }
+ if (tx_sgl) {
+ ret = spi_qup_prep_sg(master, tx_sgl, tx_nents,
+ DMA_MEM_TO_DEV, tx_done);
+ if (ret)
+ return ret;
+
+ dma_async_issue_pending(master->dma_tx);
+ }
+
+ if (!wait_for_completion_timeout(&qup->done, timeout))
+ return -ETIMEDOUT;
- if (rx_done && !wait_for_completion_timeout(&qup->done, timeout))
- return -ETIMEDOUT;
+ for (; rx_sgl && rx_nents--; rx_sgl = sg_next(rx_sgl))
+ ;
+ for (; tx_sgl && tx_nents--; tx_sgl = sg_next(tx_sgl))
+ ;
- if (tx_done && !wait_for_completion_timeout(&qup->done, timeout))
- return -ETIMEDOUT;
+ } while (rx_sgl || tx_sgl);
return 0;
}
--
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [PATCH v5 12/14] spi: qup: allow multiple DMA transactions per spi xfer
@ 2017-07-24 7:47 ` Varadarajan Narayanan
0 siblings, 0 replies; 43+ messages in thread
From: Varadarajan Narayanan @ 2017-07-24 7:47 UTC (permalink / raw)
To: broonie, robh+dt, mark.rutland, andy.gross, david.brown,
linux-spi, devicetree, linux-kernel, linux-arm-msm, linux-soc
Cc: Varadarajan Narayanan, Matthew McClintock
Much like the block mode changes, we are breaking up DMA transactions
into 64K chunks so we can reset the QUP engine.
Signed-off-by: Matthew McClintock <mmcclint@codeaurora.org>
Signed-off-by: Varadarajan Narayanan <varada@codeaurora.org>
---
drivers/spi/spi-qup.c | 93 +++++++++++++++++++++++++++++++++++----------------
1 file changed, 65 insertions(+), 28 deletions(-)
diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c
index 3ac9b25..3c2c2c0 100644
--- a/drivers/spi/spi-qup.c
+++ b/drivers/spi/spi-qup.c
@@ -418,12 +418,35 @@ static void spi_qup_dma_terminate(struct spi_master *master,
dmaengine_terminate_all(master->dma_rx);
}
+static u32 spi_qup_sgl_get_nents_len(struct scatterlist *sgl, u32 max,
+ u32 *nents)
+{
+ struct scatterlist *sg;
+ u32 total = 0;
+
+ *nents = 0;
+
+ for (sg = sgl; sg; sg = sg_next(sg)) {
+ unsigned int len = sg_dma_len(sg);
+
+ /* check for overflow as well as limit */
+ if (((total + len) < total) || ((total + len) > max))
+ break;
+
+ total += len;
+ (*nents)++;
+ }
+
+ return total;
+}
+
static int spi_qup_do_dma(struct spi_device *spi, struct spi_transfer *xfer,
unsigned long timeout)
{
dma_async_tx_callback rx_done = NULL, tx_done = NULL;
struct spi_master *master = spi->master;
struct spi_qup *qup = spi_master_get_devdata(master);
+ struct scatterlist *tx_sgl, *rx_sgl;
int ret;
if (xfer->rx_buf)
@@ -431,43 +454,57 @@ static int spi_qup_do_dma(struct spi_device *spi, struct spi_transfer *xfer,
else if (xfer->tx_buf)
tx_done = spi_qup_dma_done;
- ret = spi_qup_io_config(spi, xfer);
- if (ret)
- return ret;
+ rx_sgl = xfer->rx_sg.sgl;
+ tx_sgl = xfer->tx_sg.sgl;
- /* before issuing the descriptors, set the QUP to run */
- ret = spi_qup_set_state(qup, QUP_STATE_RUN);
- if (ret) {
- dev_warn(qup->dev, "%s(%d): cannot set RUN state\n",
- __func__, __LINE__);
- return ret;
- }
+ do {
+ u32 rx_nents, tx_nents;
+
+ if (rx_sgl)
+ qup->n_words = spi_qup_sgl_get_nents_len(rx_sgl,
+ SPI_MAX_XFER, &rx_nents) / qup->w_size;
+ if (tx_sgl)
+ qup->n_words = spi_qup_sgl_get_nents_len(tx_sgl,
+ SPI_MAX_XFER, &tx_nents) / qup->w_size;
+ if (!qup->n_words)
+ return -EIO;
- if (xfer->rx_buf) {
- ret = spi_qup_prep_sg(master, xfer->rx_sg.sgl,
- xfer->rx_sg.nents, DMA_DEV_TO_MEM,
- rx_done);
+ ret = spi_qup_io_config(spi, xfer);
if (ret)
return ret;
- dma_async_issue_pending(master->dma_rx);
- }
-
- if (xfer->tx_buf) {
- ret = spi_qup_prep_sg(master, xfer->tx_sg.sgl,
- xfer->tx_sg.nents, DMA_MEM_TO_DEV,
- tx_done);
- if (ret)
+ /* before issuing the descriptors, set the QUP to run */
+ ret = spi_qup_set_state(qup, QUP_STATE_RUN);
+ if (ret) {
+ dev_warn(qup->dev, "cannot set RUN state\n");
return ret;
+ }
+ if (rx_sgl) {
+ ret = spi_qup_prep_sg(master, rx_sgl, rx_nents,
+ DMA_DEV_TO_MEM, rx_done);
+ if (ret)
+ return ret;
+ dma_async_issue_pending(master->dma_rx);
+ }
- dma_async_issue_pending(master->dma_tx);
- }
+ if (tx_sgl) {
+ ret = spi_qup_prep_sg(master, tx_sgl, tx_nents,
+ DMA_MEM_TO_DEV, tx_done);
+ if (ret)
+ return ret;
+
+ dma_async_issue_pending(master->dma_tx);
+ }
+
+ if (!wait_for_completion_timeout(&qup->done, timeout))
+ return -ETIMEDOUT;
- if (rx_done && !wait_for_completion_timeout(&qup->done, timeout))
- return -ETIMEDOUT;
+ for (; rx_sgl && rx_nents--; rx_sgl = sg_next(rx_sgl))
+ ;
+ for (; tx_sgl && tx_nents--; tx_sgl = sg_next(tx_sgl))
+ ;
- if (tx_done && !wait_for_completion_timeout(&qup->done, timeout))
- return -ETIMEDOUT;
+ } while (rx_sgl || tx_sgl);
return 0;
}
--
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
^ permalink raw reply related [flat|nested] 43+ messages in thread