[U-Boot] [PATCH 2/3] common: rework bouncebuf implementation

Stephen Warren swarren at wwwdotorg.org
Tue Nov 6 00:04:01 CET 2012


From: Stephen Warren <swarren at nvidia.com>

The current bouncebuf API requires all parameters to be passed to both
bounce_buffer_start() and bounce_buffer_stop(). This works fine when
both functions are called from the same place. However, Tegra's MMC
driver splits the data setup and post-processing steps between two
functions, and passing all that state around separately would be painful.
Modify the bouncebuf API to accept a state structure as a parameter, so
that only a single struct needs to be passed to both APIs.

Also, don't modify the data pointer, but rather store the temporary
buffer in this state struct. This also avoids passing the buffer pointer
all over the place. The bouncebuf code ensures that client code can
always use a single buffer pointer in the state structure, irrespective
of whether a bounce buffer actually had to be allocated.

Finally, store the aligned/rounded length in the state structure too, so
that client code doesn't need to duplicate the size alignment/rounding
code, and hence have to guess at the value it was aligned/rounded to.

Update the MXS MMC driver for this change.

Signed-off-by: Stephen Warren <swarren at nvidia.com>
---
 common/bouncebuf.c   |   41 ++++++++++++++++-------------------------
 drivers/mmc/mxsmmc.c |   25 ++++++++++++++-----------
 include/bouncebuf.h  |   36 +++++++++++++++++++++++-------------
 3 files changed, 53 insertions(+), 49 deletions(-)

diff --git a/common/bouncebuf.c b/common/bouncebuf.c
index ffd3c90..210d70d 100644
--- a/common/bouncebuf.c
+++ b/common/bouncebuf.c
@@ -50,44 +50,35 @@ static int addr_aligned(void *data, size_t len)
 	return 1;
 }
 
-int bounce_buffer_start(void **data, size_t len, void **backup, uint8_t flags)
+int bounce_buffer_start(struct bounce_buffer_state *state, void *data,
+			size_t len, uint8_t flags)
 {
-	void *tmp;
-	size_t alen;
+	state->user_buffer = data;
+	state->bounce_buffer = data;
+	state->len = len;
+	state->len_aligned = roundup(len, ARCH_DMA_MINALIGN);
+	state->flags = flags;
 
-	if (addr_aligned(*data, len)) {
-		*backup = NULL;
+	if (addr_aligned(data, len))
 		return 0;
-	}
-
-	alen = roundup(len, ARCH_DMA_MINALIGN);
-	tmp = memalign(ARCH_DMA_MINALIGN, alen);
 
-	if (!tmp)
+	state->bounce_buffer = memalign(ARCH_DMA_MINALIGN, state->len_aligned);
+	if (!state->bounce_buffer)
 		return -ENOMEM;
 
-	if (flags & GEN_BB_READ)
-		memcpy(tmp, *data, len);
-
-	*backup = *data;
-	*data = tmp;
+	if (state->flags & GEN_BB_READ)
+		memcpy(state->bounce_buffer, state->user_buffer, state->len);
 
 	return 0;
 }
 
-int bounce_buffer_stop(void **data, size_t len, void **backup, uint8_t flags)
+int bounce_buffer_stop(struct bounce_buffer_state *state)
 {
-	void *tmp = *data;
-
-	/* The buffer was already aligned, since "backup" is NULL. */
-	if (!*backup)
+	if (state->bounce_buffer == state->user_buffer)
 		return 0;
 
-	if (flags & GEN_BB_WRITE)
-		memcpy(*backup, *data, len);
-
-	*data = *backup;
-	free(tmp);
+	if (state->flags & GEN_BB_WRITE)
+		memcpy(state->user_buffer, state->bounce_buffer, state->len);
 
 	return 0;
 }
diff --git a/drivers/mmc/mxsmmc.c b/drivers/mmc/mxsmmc.c
index 109acbf..d314d7d 100644
--- a/drivers/mmc/mxsmmc.c
+++ b/drivers/mmc/mxsmmc.c
@@ -96,11 +96,11 @@ static int mxsmmc_send_cmd_pio(struct mxsmmc_priv *priv, struct mmc_data *data)
 static int mxsmmc_send_cmd_dma(struct mxsmmc_priv *priv, struct mmc_data *data)
 {
 	uint32_t data_count = data->blocksize * data->blocks;
-	uint32_t cache_data_count = roundup(data_count, ARCH_DMA_MINALIGN);
 	int dmach;
 	struct mxs_dma_desc *desc = priv->desc;
-	void *addr, *backup;
+	void *addr;
 	uint8_t flags;
+	struct bounce_buffer_state bbstate;
 
 	memset(desc, 0, sizeof(struct mxs_dma_desc));
 	desc->address = (dma_addr_t)desc;
@@ -115,19 +115,21 @@ static int mxsmmc_send_cmd_dma(struct mxsmmc_priv *priv, struct mmc_data *data)
 		flags = GEN_BB_READ;
 	}
 
-	bounce_buffer_start(&addr, data_count, &backup, flags);
+	bounce_buffer_start(&bbstate, addr, data_count, flags);
 
-	priv->desc->cmd.address = (dma_addr_t)addr;
+	priv->desc->cmd.address = (dma_addr_t)bbstate.bounce_buffer;
 
 	if (data->flags & MMC_DATA_WRITE) {
 		/* Flush data to DRAM so DMA can pick them up */
-		flush_dcache_range((uint32_t)addr,
-			(uint32_t)(addr) + cache_data_count);
+		flush_dcache_range((uint32_t)bbstate.bounce_buffer,
+					(uint32_t)(bbstate.bounce_buffer) +
+						bbstate.len_aligned);
 	}
 
 	/* Invalidate the area, so no writeback into the RAM races with DMA */
 	invalidate_dcache_range((uint32_t)priv->desc->cmd.address,
-			(uint32_t)(priv->desc->cmd.address + cache_data_count));
+				(uint32_t)(priv->desc->cmd.address +
+					bbstate.len_aligned));
 
 	priv->desc->cmd.data |= MXS_DMA_DESC_IRQ | MXS_DMA_DESC_DEC_SEM |
 				(data_count << MXS_DMA_DESC_BYTES_OFFSET);
@@ -135,17 +137,18 @@ static int mxsmmc_send_cmd_dma(struct mxsmmc_priv *priv, struct mmc_data *data)
 	dmach = MXS_DMA_CHANNEL_AHB_APBH_SSP0 + priv->id;
 	mxs_dma_desc_append(dmach, priv->desc);
 	if (mxs_dma_go(dmach)) {
-		bounce_buffer_stop(&addr, data_count, &backup, flags);
+		bounce_buffer_stop(&bbstate);
 		return COMM_ERR;
 	}
 
 	/* The data arrived into DRAM, invalidate cache over them */
 	if (data->flags & MMC_DATA_READ) {
-		invalidate_dcache_range((uint32_t)addr,
-			(uint32_t)(addr) + cache_data_count);
+		invalidate_dcache_range((uint32_t)bbstate.bounce_buffer,
+					(uint32_t)(bbstate.bounce_buffer) +
+						bbstate.len_aligned);
 	}
 
-	bounce_buffer_stop(&addr, data_count, &backup, flags);
+	bounce_buffer_stop(&bbstate);
 
 	return 0;
 }
diff --git a/include/bouncebuf.h b/include/bouncebuf.h
index 31021c5..205a1ed 100644
--- a/include/bouncebuf.h
+++ b/include/bouncebuf.h
@@ -52,33 +52,43 @@
 #define GEN_BB_RW	(GEN_BB_READ | GEN_BB_WRITE)
 
 #ifdef CONFIG_BOUNCE_BUFFER
+struct bounce_buffer_state {
+	void *user_buffer;
+	void *bounce_buffer;
+	size_t len;
+	size_t len_aligned;
+	uint8_t flags;
+};
+
 /**
  * bounce_buffer_start() -- Start the bounce buffer session
+ * state:	stores state passed between bounce_buffer_{start,stop}
  * data:	pointer to buffer to be aligned
  * len:		length of the buffer
- * backup:	pointer to backup buffer (the original value is stored here if
- *              needed
  * flags:	flags describing the transaction, see above.
  */
-int bounce_buffer_start(void **data, size_t len, void **backup, uint8_t flags);
+int bounce_buffer_start(struct bounce_buffer_state *state, void *data,
+			size_t len, uint8_t flags);
 /**
  * bounce_buffer_stop() -- Finish the bounce buffer session
- * data:	pointer to buffer that was aligned
- * len:		length of the buffer
- * backup:	pointer to backup buffer (the original value is stored here if
- *              needed
- * flags:	flags describing the transaction, see above.
+ * state:	stores state passed between bounce_buffer_{start,stop}
  */
-int bounce_buffer_stop(void **data, size_t len, void **backup, uint8_t flags);
+int bounce_buffer_stop(struct bounce_buffer_state *state);
 #else
-static inline int bounce_buffer_start(void **data, size_t len, void **backup,
-					uint8_t flags)
+struct bounce_buffer_state {
+	void *bounce_buffer;
+	size_t len_aligned;
+};
+
+static inline int bounce_buffer_start(struct bounce_buffer_state *state,
+					void *data, size_t len, uint8_t flags)
 {
+	state->bounce_buffer = data;
+	state->len_aligned = len;
 	return 0;
 }
 
-static inline int bounce_buffer_stop(void **data, size_t len, void **backup,
-					uint8_t flags)
+static inline int bounce_buffer_stop(struct bounce_buffer_state *state)
 {
 	return 0;
 }
-- 
1.7.0.4



More information about the U-Boot mailing list