[rtems commit] bsp/atsam: Reduce context switches for SPI transf

Sebastian Huber sebh at rtems.org
Wed Dec 14 12:10:18 UTC 2016


Module:    rtems
Branch:    master
Commit:    de7c17192a7592a27f68c0143f28cb8003c790f8
Changeset: http://git.rtems.org/rtems/commit/?id=de7c17192a7592a27f68c0143f28cb8003c790f8

Author:    Sebastian Huber <sebastian.huber at embedded-brains.de>
Date:      Wed Dec 14 09:41:30 2016 +0100

bsp/atsam: Reduce context switches for SPI transf

---

 c/src/lib/libbsp/arm/atsam/spi/atsam_spi_bus.c | 206 +++++++++++++------------
 1 file changed, 107 insertions(+), 99 deletions(-)

diff --git a/c/src/lib/libbsp/arm/atsam/spi/atsam_spi_bus.c b/c/src/lib/libbsp/arm/atsam/spi/atsam_spi_bus.c
index cf4d446..7dee4d5 100644
--- a/c/src/lib/libbsp/arm/atsam/spi/atsam_spi_bus.c
+++ b/c/src/lib/libbsp/arm/atsam/spi/atsam_spi_bus.c
@@ -38,9 +38,11 @@
 
 typedef struct {
   spi_bus base;
+  bool msg_cs_change;
+  const spi_ioc_transfer *msg_current;
   uint32_t msg_todo;
-  const spi_ioc_transfer *msgs;
-  rtems_id task_id;
+  int msg_error;
+  rtems_id msg_task;
   sXdmad xdma;
   Spid SpiDma;
   uint32_t dma_tx_channel;
@@ -50,77 +52,12 @@ typedef struct {
   bool chip_select_active;
 } atsam_spi_bus;
 
-static void atsam_spi_interrupt(void *arg)
+static void atsam_spi_wakeup_task(atsam_spi_bus *bus)
 {
-  atsam_spi_bus *bus = (atsam_spi_bus *)arg;
-  sXdmad *xdma = &bus->xdma;
-  Spid *spid = &bus->SpiDma;
-  Xdmac *xdmac;
-  sXdmadChannel *ch;
-  uint32_t xdmaChannelIntStatus, xdmaGlobaIntStatus, xdmaGlobalChStatus;
-  uint8_t channel;
-  uint8_t bExec = 0;
   rtems_status_code sc;
-  assert(xdma != NULL);
-
-  xdmac = xdma->pXdmacs;
-  xdmaGlobaIntStatus = XDMAC_GetGIsr(xdmac);
-
-  if ((xdmaGlobaIntStatus & 0xFFFFFF) != 0) {
-    xdmaGlobalChStatus = XDMAC_GetGlobalChStatus(xdmac);
-
-    for (channel = 0; channel < xdma->numChannels; channel ++) {
-      if (!(xdmaGlobaIntStatus & (1 << channel))) {
-        continue;
-      }
-
-      ch = &xdma->XdmaChannels[channel];
-
-      if (ch->state == XDMAD_STATE_FREE) {
-        return;
-      }
-
-      if ((xdmaGlobalChStatus & (XDMAC_GS_ST0 << channel)) == 0) {
-        bExec = 0;
-        xdmaChannelIntStatus = XDMAC_GetMaskChannelIsr(xdmac, channel);
-
-        if (xdmaChannelIntStatus & XDMAC_CIS_BIS) {
-          if ((XDMAC_GetChannelItMask(xdmac, channel) & XDMAC_CIM_LIM) == 0) {
-            ch->state = XDMAD_STATE_DONE;
-            bExec = 1;
-          }
-        }
-
-        if (xdmaChannelIntStatus & XDMAC_CIS_LIS) {
-          ch->state = XDMAD_STATE_DONE;
-          bExec = 1;
-        }
-
-        if (xdmaChannelIntStatus & XDMAC_CIS_DIS) {
-          ch->state = XDMAD_STATE_DONE;
-          bExec = 1;
-        }
-
-      } else {
-        /* Block end interrupt for LLI dma mode */
-        if (XDMAC_GetChannelIsr(xdmac, channel) & XDMAC_CIS_BIS) {
-        }
-      }
 
-      if (bExec == 1 && (channel == bus->dma_rx_channel)) {
-        bus->rx_transfer_done = true;
-        XDMAC_DisableGIt(spid->pXdmad->pXdmacs, bus->dma_rx_channel);
-      } else if (bExec == 1 && (channel == bus->dma_tx_channel)) {
-        bus->tx_transfer_done = true;
-        XDMAC_DisableGIt(spid->pXdmad->pXdmacs, bus->dma_tx_channel);
-      }
-
-      if (bus->rx_transfer_done && bus->tx_transfer_done) {
-        sc = rtems_event_transient_send(bus->task_id);
-        assert(sc == RTEMS_SUCCESSFUL);
-      }
-    }
-  }
+  sc = rtems_event_transient_send(bus->msg_task);
+  assert(sc == RTEMS_SUCCESSFUL);
 }
 
 static uint8_t atsam_calculate_dlybcs(uint16_t delay_in_us)
@@ -328,33 +265,108 @@ static int atsam_check_configure_spi(atsam_spi_bus *bus, const spi_ioc_transfer
   return 0;
 }
 
-static int atsam_spi_setup_transfer(atsam_spi_bus *bus)
+static void atsam_spi_setup_transfer(atsam_spi_bus *bus)
 {
-  const spi_ioc_transfer *msgs = bus->msgs;
   uint32_t msg_todo = bus->msg_todo;
-  uint32_t i;
-  int error;
 
-  for (i = 0; i < msg_todo; ++i) {
-    error = atsam_check_configure_spi(bus, &msgs[i]);
-    if (error < 0) {
-      return error;
-    }
+  bus->rx_transfer_done = false;
+  bus->tx_transfer_done = false;
 
-    atsam_spi_do_transfer(bus, &msgs[i]);
-    rtems_event_transient_receive(RTEMS_WAIT, RTEMS_NO_TIMEOUT);
+  if (bus->msg_cs_change) {
+    bus->chip_select_active = false;
+    SPI_ReleaseCS(bus->SpiDma.pSpiHw);
+    SPI_Disable(bus->SpiDma.pSpiHw);
+  }
+
+  if (msg_todo > 0) {
+    const spi_ioc_transfer *msg = bus->msg_current;
+    int error;
 
-    bus->rx_transfer_done = false;
-    bus->tx_transfer_done = false;
+    bus->msg_cs_change = msg->cs_change;
+    bus->msg_current = msg + 1;
+    bus->msg_todo = msg_todo - 1;
 
-    if (msgs[i].cs_change > 0) {
-      bus->chip_select_active = false;
-      SPI_ReleaseCS(bus->SpiDma.pSpiHw);
-      SPI_Disable(bus->SpiDma.pSpiHw);
+    error = atsam_check_configure_spi(bus, msg);
+    if (error == 0) {
+      atsam_spi_do_transfer(bus, msg);
+    } else {
+      bus->msg_error = error;
+      atsam_spi_wakeup_task(bus);
     }
+  } else {
+    atsam_spi_wakeup_task(bus);
   }
+}
 
-  return 0;
+static void atsam_spi_interrupt(void *arg)
+{
+  atsam_spi_bus *bus = (atsam_spi_bus *)arg;
+  sXdmad *xdma = &bus->xdma;
+  Spid *spid = &bus->SpiDma;
+  Xdmac *xdmac;
+  sXdmadChannel *ch;
+  uint32_t xdmaChannelIntStatus, xdmaGlobaIntStatus, xdmaGlobalChStatus;
+  uint8_t channel;
+  uint8_t bExec = 0;
+  assert(xdma != NULL);
+
+  xdmac = xdma->pXdmacs;
+  xdmaGlobaIntStatus = XDMAC_GetGIsr(xdmac);
+
+  if ((xdmaGlobaIntStatus & 0xFFFFFF) != 0) {
+    xdmaGlobalChStatus = XDMAC_GetGlobalChStatus(xdmac);
+
+    for (channel = 0; channel < xdma->numChannels; channel ++) {
+      if (!(xdmaGlobaIntStatus & (1 << channel))) {
+        continue;
+      }
+
+      ch = &xdma->XdmaChannels[channel];
+
+      if (ch->state == XDMAD_STATE_FREE) {
+        return;
+      }
+
+      if ((xdmaGlobalChStatus & (XDMAC_GS_ST0 << channel)) == 0) {
+        bExec = 0;
+        xdmaChannelIntStatus = XDMAC_GetMaskChannelIsr(xdmac, channel);
+
+        if (xdmaChannelIntStatus & XDMAC_CIS_BIS) {
+          if ((XDMAC_GetChannelItMask(xdmac, channel) & XDMAC_CIM_LIM) == 0) {
+            ch->state = XDMAD_STATE_DONE;
+            bExec = 1;
+          }
+        }
+
+        if (xdmaChannelIntStatus & XDMAC_CIS_LIS) {
+          ch->state = XDMAD_STATE_DONE;
+          bExec = 1;
+        }
+
+        if (xdmaChannelIntStatus & XDMAC_CIS_DIS) {
+          ch->state = XDMAD_STATE_DONE;
+          bExec = 1;
+        }
+
+      } else {
+        /* Block end interrupt for LLI dma mode */
+        if (XDMAC_GetChannelIsr(xdmac, channel) & XDMAC_CIS_BIS) {
+        }
+      }
+
+      if (bExec == 1 && (channel == bus->dma_rx_channel)) {
+        bus->rx_transfer_done = true;
+        XDMAC_DisableGIt(spid->pXdmad->pXdmacs, bus->dma_rx_channel);
+      } else if (bExec == 1 && (channel == bus->dma_tx_channel)) {
+        bus->tx_transfer_done = true;
+        XDMAC_DisableGIt(spid->pXdmad->pXdmacs, bus->dma_tx_channel);
+      }
+
+      if (bus->rx_transfer_done && bus->tx_transfer_done) {
+        atsam_spi_setup_transfer(bus);
+      }
+    }
+  }
 }
 
 static int atsam_spi_transfer(
@@ -363,20 +375,16 @@ static int atsam_spi_transfer(
   uint32_t msg_count
 )
 {
-  int rv;
   atsam_spi_bus *bus = (atsam_spi_bus *)base;
 
-  if (msg_count == 0) {
-    return 0;
-  }
-
-  bus->msgs = &msgs[0];
+  bus->msg_cs_change = false;
+  bus->msg_current = &msgs[0];
   bus->msg_todo = msg_count;
-  bus->task_id = rtems_task_self();
-
-  rv = atsam_spi_setup_transfer(bus);
-
-  return rv;
+  bus->msg_error = 0;
+  bus->msg_task = rtems_task_self();
+  atsam_spi_setup_transfer(bus);
+  rtems_event_transient_receive(RTEMS_WAIT, RTEMS_NO_TIMEOUT);
+  return bus->msg_error;
 }
 
 



More information about the vc mailing list