summaryrefslogtreecommitdiff
path: root/cesar/hal/phy/src/bridgedma.c
diff options
context:
space:
mode:
authorNélio Laranjeiro2011-06-07 10:59:47 +0200
committerNélio Laranjeiro2011-06-07 11:06:14 +0200
commit6167fb9f71a4de0b46ce8eeeab07d6536e818481 (patch)
tree02e25258bb55d7b01090aa624367d60080dc7644 /cesar/hal/phy/src/bridgedma.c
parentc21326e64931f04bdfe28f5f038b8014baf4b33f (diff)
cesar/hal/phy: don't chain DMA's jobs dynamically, closes #2537
workaround bug maria:#971
Diffstat (limited to 'cesar/hal/phy/src/bridgedma.c')
-rw-r--r--cesar/hal/phy/src/bridgedma.c92
1 files changed, 51 insertions, 41 deletions
diff --git a/cesar/hal/phy/src/bridgedma.c b/cesar/hal/phy/src/bridgedma.c
index 3511c3389e..108bb67e3a 100644
--- a/cesar/hal/phy/src/bridgedma.c
+++ b/cesar/hal/phy/src/bridgedma.c
@@ -19,9 +19,14 @@
#include "hal/phy/bridgedma.h"
#include "hal/phy/inc/bridgedma.h"
#include "hal/phy/inc/bridgedma_regs.h"
+#include "lib/slist.h"
#include <string.h>
+/** Quick access to start bit. */
+#define PHY_BRGDMA_START_BIT \
+ BF_GET (PHY_BRIDGEDMA_CONTROL__START, PHY_BDGDMA_CONTROL_CONFIG)
+
/** Quick access to Running bit. */
#define PHY_BRGDMA_RUNNING_BIT \
BF_GET (PHY_BRIDGEDMA_STATUS_ERROR__RUNNING, PHY_BDGDMA_STATUS_ERROR)
@@ -42,11 +47,7 @@ static inline void
phy_bridge_dma_start__configure (phy_bridgedma_t *ctx,
phy_bridgedma_job_t *job)
{
- dbg_assert (ctx);
- dbg_assert (job);
-
PHY_BDGDMA_FIRST_JOBD_PTR = (u32) job;
-
/* Start the bridgedma. */
PHY_BDGDMA_CONTROL_CONFIG = BF_SET (PHY_BDGDMA_CONTROL_CONFIG,
PHY_BRIDGEDMA_CONTROL__START,
@@ -54,16 +55,52 @@ phy_bridge_dma_start__configure (phy_bridgedma_t *ctx,
}
/**
- * Read twice running bit (see maria:#913)
- * Running bit goes down if the current chain is ended and bit start is set.
- * Reading twice avoid to return a false status.
+ * Start the BRGDMA with the pending DMA list.
+ * \param ctx the bridgedma context.
+ */
+static void
+phy_bridgedma_start_jobs_pending (phy_bridgedma_t *ctx)
+{
+ /* Set the last bit to true in the last job. */
+ ctx->jobs_pending.tail->last = true;
+ ctx->jobs_pending.tail->next =
+ (phy_bridgedma_job_t *) PHY_BRGDMA_SPC_ADDRESS (
+ (u32)ctx->jobs_pending.tail);
+ arch_write_buffer_flush ();
+ phy_bridge_dma_start__configure (ctx, ctx->jobs_pending.head);
+ /* Bridge DMA head is not null, chain the list to the
+ tail. */
+ if (ctx->bridge.job_head)
+ ctx->bridge.job_tail->next = ctx->jobs_pending.head;
+ else
+ ctx->bridge.job_head = ctx->jobs_pending.head;
+ ctx->bridge.job_tail = ctx->jobs_pending.tail;
+ slist_init (ctx->jobs_pending., bare);
+}
+
+/**
+ * Return the BRG DMA status. (see maria:#913, and maria:#971)
+ * \param ctx the bridgedma context.
+ * \return true if pending jobs list is not empty, or start bit or running
+ * bit is true.
*/
static inline bool
_phy_bridgedma_status (phy_bridgedma_t *ctx)
{
- bool run1 = PHY_BRGDMA_RUNNING_BIT;
- bool run2 = PHY_BRGDMA_RUNNING_BIT;
- return run1 || run2;
+ if (ctx->jobs_pending.head)
+ {
+ if (!PHY_BRGDMA_START_BIT)
+ phy_bridgedma_start_jobs_pending (ctx);
+ return true;
+ }
+ else
+ {
+ bool started = PHY_BRGDMA_START_BIT;
+ bool running =
+ BF_GET (PHY_BRIDGEDMA_STATUS_ERROR__RUNNING,
+ PHY_BDGDMA_STATUS_ERROR);
+ return started || running;
+ }
}
/** eCos ISR called by eCos each time the bridgedma ends a job with the it
@@ -144,6 +181,7 @@ phy_bridgedma_init (void *user_data, phy_bridgedma_cb_t bridgedma_cb,
cyg_interrupt_unmask(PHY_BRIDGEDMA_END_INTERRUPT);
}
+ slist_init (phy_bridgedma_global.jobs_pending., bare);
return &phy_bridgedma_global;
}
@@ -162,38 +200,10 @@ phy_bridgedma_start (phy_bridgedma_t *ctx, phy_bridgedma_job_t *job_first,
dbg_assert (job_first);
dbg_assert (job_last);
dbg_assert (job_last->next == NULL);
-
- /* Set the last bit to true in the last job. */
- job_last->last = true;
- job_last->next =
- (phy_bridgedma_job_t *) PHY_BRGDMA_SPC_ADDRESS ((u32)job_last);
-
+ slist_push_back_range (ctx->jobs_pending., job_first, job_last, bare);
/* Bridge DMA is stopped, add the job and start it. */
- if (!_phy_bridgedma_status (ctx))
- {
- arch_write_buffer_flush ();
- phy_bridge_dma_start__configure (ctx, job_first);
- /* Bridge DMA head is not null, chain the list to the tail. */
- if (ctx->bridge.job_head)
- ctx->bridge.job_tail->next = job_first;
- else
- ctx->bridge.job_head = job_first;
- }
- else
- {
- ctx->bridge.job_tail->next = job_first;
- arch_reorder_barrier ();
- ctx->bridge.job_tail->last = false;
- arch_write_buffer_flush ();
-
- /* if last_job is loaded before last has been written. */
- if ((PHY_BDGDMA_CURRENT_JOBD_PTR == (u32) ctx->bridge.job_tail
- && PHY_BRGDMA_LAST_BIT)
- || (!_phy_bridgedma_status (ctx)
- && PHY_BDGDMA_CURRENT_JOBD_PTR == (u32) job_first))
- phy_bridge_dma_start__configure (ctx, job_first);
- }
- ctx->bridge.job_tail = job_last;
+ if (!PHY_BRGDMA_START_BIT)
+ phy_bridgedma_start_jobs_pending (ctx);
}
/**