[PATCH 4/7] dmaengine: stm32-dma: Improve memory burst management

2018-10-08 Thread Joel Fernandes (Google)
From: Pierre Yves MORDRET 

This patch improves memory burst capability using best burst size
according to transferred buffer size from/to memory.

>From now on, memory burst is not necessarily same as with peripheral
burst one and fifo threshold is directly managed by this driver in order
to fit with computed memory burst.

Signed-off-by: M'boumba Cedric Madianga 
Signed-off-by: Pierre-Yves MORDRET 
Signed-off-by: Vinod Koul 
---
 drivers/dma/stm32-dma.c | 204 ++--
 1 file changed, 175 insertions(+), 29 deletions(-)

diff --git a/drivers/dma/stm32-dma.c b/drivers/dma/stm32-dma.c
index b64e14a83dec..21ad359a5a59 100644
--- a/drivers/dma/stm32-dma.c
+++ b/drivers/dma/stm32-dma.c
@@ -5,6 +5,7 @@
  *
  * Copyright (C) M'boumba Cedric Madianga 2015
  * Author: M'boumba Cedric Madianga 
+ * Pierre-Yves Mordret 
  *
  * License terms:  GNU General Public License (GPL), version 2
  */
@@ -115,6 +116,8 @@
 #define STM32_DMA_MAX_CHANNELS 0x08
 #define STM32_DMA_MAX_REQUEST_ID   0x08
 #define STM32_DMA_MAX_DATA_PARAM   0x03
+#define STM32_DMA_FIFO_SIZE16  /* FIFO is 16 bytes */
+#define STM32_DMA_MIN_BURST4
 #define STM32_DMA_MAX_BURST16
 
 /* DMA Features */
@@ -184,6 +187,8 @@ struct stm32_dma_chan {
struct dma_slave_config dma_sconfig;
struct stm32_dma_chan_reg chan_reg;
u32 threshold;
+   u32 mem_burst;
+   u32 mem_width;
 };
 
 struct stm32_dma_device {
@@ -248,6 +253,85 @@ static int stm32_dma_get_width(struct stm32_dma_chan *chan,
}
 }
 
+static enum dma_slave_buswidth stm32_dma_get_max_width(u32 buf_len,
+  u32 threshold)
+{
+   enum dma_slave_buswidth max_width;
+
+   if (threshold == STM32_DMA_FIFO_THRESHOLD_FULL)
+   max_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+   else
+   max_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+
+   while ((buf_len < max_width  || buf_len % max_width) &&
+  max_width > DMA_SLAVE_BUSWIDTH_1_BYTE)
+   max_width = max_width >> 1;
+
+   return max_width;
+}
+
+static bool stm32_dma_fifo_threshold_is_allowed(u32 burst, u32 threshold,
+   enum dma_slave_buswidth width)
+{
+   u32 remaining;
+
+   if (width != DMA_SLAVE_BUSWIDTH_UNDEFINED) {
+   if (burst != 0) {
+   /*
+* If number of beats fit in several whole bursts
+* this configuration is allowed.
+*/
+   remaining = ((STM32_DMA_FIFO_SIZE / width) *
+(threshold + 1) / 4) % burst;
+
+   if (remaining == 0)
+   return true;
+   } else {
+   return true;
+   }
+   }
+
+   return false;
+}
+
+static bool stm32_dma_is_burst_possible(u32 buf_len, u32 threshold)
+{
+   switch (threshold) {
+   case STM32_DMA_FIFO_THRESHOLD_FULL:
+   if (buf_len >= STM32_DMA_MAX_BURST)
+   return true;
+   else
+   return false;
+   case STM32_DMA_FIFO_THRESHOLD_HALFFULL:
+   if (buf_len >= STM32_DMA_MAX_BURST / 2)
+   return true;
+   else
+   return false;
+   default:
+   return false;
+   }
+}
+
+static u32 stm32_dma_get_best_burst(u32 buf_len, u32 max_burst, u32 threshold,
+   enum dma_slave_buswidth width)
+{
+   u32 best_burst = max_burst;
+
+   if (best_burst == 1 || !stm32_dma_is_burst_possible(buf_len, threshold))
+   return 0;
+
+   while ((buf_len < best_burst * width && best_burst > 1) ||
+  !stm32_dma_fifo_threshold_is_allowed(best_burst, threshold,
+   width)) {
+   if (best_burst > STM32_DMA_MIN_BURST)
+   best_burst = best_burst >> 1;
+   else
+   best_burst = 0;
+   }
+
+   return best_burst;
+}
+
 static int stm32_dma_get_burst(struct stm32_dma_chan *chan, u32 maxburst)
 {
switch (maxburst) {
@@ -267,12 +351,12 @@ static int stm32_dma_get_burst(struct stm32_dma_chan 
*chan, u32 maxburst)
 }
 
 static void stm32_dma_set_fifo_config(struct stm32_dma_chan *chan,
- u32 src_maxburst, u32 dst_maxburst)
+ u32 src_burst, u32 dst_burst)
 {
chan->chan_reg.dma_sfcr &= ~STM32_DMA_SFCR_MASK;
chan->chan_reg.dma_scr &= ~STM32_DMA_SCR_DMEIE;
 
-   if ((!src_maxburst) && (!dst_maxburst)) {
+   if (!src_burst && !dst_burst) {
/* Using direct mode */
chan->chan_reg.dma_scr |= STM32_DMA_SCR_DMEIE;
} else {
@@ -589,37 

[PATCH 4/7] dmaengine: stm32-dma: Improve memory burst management

2018-10-08 Thread Joel Fernandes (Google)
From: Pierre Yves MORDRET 

This patch improves memory burst capability using best burst size
according to transferred buffer size from/to memory.

>From now on, memory burst is not necessarily same as with peripheral
burst one and fifo threshold is directly managed by this driver in order
to fit with computed memory burst.

Signed-off-by: M'boumba Cedric Madianga 
Signed-off-by: Pierre-Yves MORDRET 
Signed-off-by: Vinod Koul 
---
 drivers/dma/stm32-dma.c | 204 ++--
 1 file changed, 175 insertions(+), 29 deletions(-)

diff --git a/drivers/dma/stm32-dma.c b/drivers/dma/stm32-dma.c
index b64e14a83dec..21ad359a5a59 100644
--- a/drivers/dma/stm32-dma.c
+++ b/drivers/dma/stm32-dma.c
@@ -5,6 +5,7 @@
  *
  * Copyright (C) M'boumba Cedric Madianga 2015
  * Author: M'boumba Cedric Madianga 
+ * Pierre-Yves Mordret 
  *
  * License terms:  GNU General Public License (GPL), version 2
  */
@@ -115,6 +116,8 @@
 #define STM32_DMA_MAX_CHANNELS 0x08
 #define STM32_DMA_MAX_REQUEST_ID   0x08
 #define STM32_DMA_MAX_DATA_PARAM   0x03
+#define STM32_DMA_FIFO_SIZE16  /* FIFO is 16 bytes */
+#define STM32_DMA_MIN_BURST4
 #define STM32_DMA_MAX_BURST16
 
 /* DMA Features */
@@ -184,6 +187,8 @@ struct stm32_dma_chan {
struct dma_slave_config dma_sconfig;
struct stm32_dma_chan_reg chan_reg;
u32 threshold;
+   u32 mem_burst;
+   u32 mem_width;
 };
 
 struct stm32_dma_device {
@@ -248,6 +253,85 @@ static int stm32_dma_get_width(struct stm32_dma_chan *chan,
}
 }
 
+static enum dma_slave_buswidth stm32_dma_get_max_width(u32 buf_len,
+  u32 threshold)
+{
+   enum dma_slave_buswidth max_width;
+
+   if (threshold == STM32_DMA_FIFO_THRESHOLD_FULL)
+   max_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+   else
+   max_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+
+   while ((buf_len < max_width  || buf_len % max_width) &&
+  max_width > DMA_SLAVE_BUSWIDTH_1_BYTE)
+   max_width = max_width >> 1;
+
+   return max_width;
+}
+
+static bool stm32_dma_fifo_threshold_is_allowed(u32 burst, u32 threshold,
+   enum dma_slave_buswidth width)
+{
+   u32 remaining;
+
+   if (width != DMA_SLAVE_BUSWIDTH_UNDEFINED) {
+   if (burst != 0) {
+   /*
+* If number of beats fit in several whole bursts
+* this configuration is allowed.
+*/
+   remaining = ((STM32_DMA_FIFO_SIZE / width) *
+(threshold + 1) / 4) % burst;
+
+   if (remaining == 0)
+   return true;
+   } else {
+   return true;
+   }
+   }
+
+   return false;
+}
+
+static bool stm32_dma_is_burst_possible(u32 buf_len, u32 threshold)
+{
+   switch (threshold) {
+   case STM32_DMA_FIFO_THRESHOLD_FULL:
+   if (buf_len >= STM32_DMA_MAX_BURST)
+   return true;
+   else
+   return false;
+   case STM32_DMA_FIFO_THRESHOLD_HALFFULL:
+   if (buf_len >= STM32_DMA_MAX_BURST / 2)
+   return true;
+   else
+   return false;
+   default:
+   return false;
+   }
+}
+
+static u32 stm32_dma_get_best_burst(u32 buf_len, u32 max_burst, u32 threshold,
+   enum dma_slave_buswidth width)
+{
+   u32 best_burst = max_burst;
+
+   if (best_burst == 1 || !stm32_dma_is_burst_possible(buf_len, threshold))
+   return 0;
+
+   while ((buf_len < best_burst * width && best_burst > 1) ||
+  !stm32_dma_fifo_threshold_is_allowed(best_burst, threshold,
+   width)) {
+   if (best_burst > STM32_DMA_MIN_BURST)
+   best_burst = best_burst >> 1;
+   else
+   best_burst = 0;
+   }
+
+   return best_burst;
+}
+
 static int stm32_dma_get_burst(struct stm32_dma_chan *chan, u32 maxburst)
 {
switch (maxburst) {
@@ -267,12 +351,12 @@ static int stm32_dma_get_burst(struct stm32_dma_chan 
*chan, u32 maxburst)
 }
 
 static void stm32_dma_set_fifo_config(struct stm32_dma_chan *chan,
- u32 src_maxburst, u32 dst_maxburst)
+ u32 src_burst, u32 dst_burst)
 {
chan->chan_reg.dma_sfcr &= ~STM32_DMA_SFCR_MASK;
chan->chan_reg.dma_scr &= ~STM32_DMA_SCR_DMEIE;
 
-   if ((!src_maxburst) && (!dst_maxburst)) {
+   if (!src_burst && !dst_burst) {
/* Using direct mode */
chan->chan_reg.dma_scr |= STM32_DMA_SCR_DMEIE;
} else {
@@ -589,37