fw/sercomm: Additional locking needed in drv_pull
[osmocom-bb.git] / src / target / firmware / comm / sercomm.c
index c78b362..ddc852c 100644 (file)
 #include <stdio.h>
 #include <errno.h>
 
-#include <osmocore/msgb.h>
+#include <osmocom/core/msgb.h>
 
 #ifdef HOST_BUILD
-#define SERCOMM_RX_MSG_SIZE    2048
-#ifndef ARRAY_SIZE
-#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
-#endif
-#include <sercomm.h>
-#define local_irq_save(x) (void) x
-#define local_fiq_disable()
-#define local_irq_restore(x) (void) x
+
+# define SERCOMM_RX_MSG_SIZE   2048
+# ifndef ARRAY_SIZE
+#  define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
+# endif
+# include <sercomm.h>
+
+static inline void sercomm_lock(unsigned long __attribute__((unused)) *flags) {}
+static inline void sercomm_unlock(unsigned long __attribute__((unused)) *flags) {}
 
 #else
-#define SERCOMM_RX_MSG_SIZE    256
-#include <debug.h>
-#include <osmocore/linuxlist.h>
-#include <asm/system.h>
 
-#include <comm/sercomm.h>
-#include <calypso/uart.h>
+# define SERCOMM_RX_MSG_SIZE   256
+# include <debug.h>
+# include <osmocom/core/linuxlist.h>
+# include <asm/system.h>
+
+static inline void sercomm_lock(unsigned long *flags)
+{
+       local_firq_save(*flags);
+}
+
+static inline void sercomm_unlock(unsigned long *flags)
+{
+       local_irq_restore(*flags);
+}
+
+# include <comm/sercomm.h>
+# include <uart.h>
+
 #endif
 
 
@@ -108,10 +121,9 @@ void sercomm_sendmsg(uint8_t dlci, struct msgb *msg)
 
        /* This functiion can be called from any context: FIQ, IRQ
         * and supervisor context.  Proper locking is important! */
-       local_irq_save(flags);
-       local_fiq_disable();
+       sercomm_lock(&flags);
        msgb_enqueue(&sercomm.tx.dlci_queues[dlci], msg);
-       local_irq_restore(flags);
+       sercomm_unlock(&flags);
 
 #ifndef HOST_BUILD
        /* tell UART that we have something to send */
@@ -135,9 +147,13 @@ unsigned int sercomm_tx_queue_depth(uint8_t dlci)
 /* fetch one octet of to-be-transmitted serial data */
 int sercomm_drv_pull(uint8_t *ch)
 {
-       /* we are always called from interrupt context in this function,
-        * which means that any data structures we use need to be for
-        * our exclusive access */
+       unsigned long flags;
+
+       /* we may be called from interrupt context, but we stiff need to lock
+        * because sercomm could be accessed from a FIQ context ... */
+
+       sercomm_lock(&flags);
+
        if (!sercomm.tx.msg) {
                unsigned int i;
                /* dequeue a new message from the queues */
@@ -150,16 +166,18 @@ int sercomm_drv_pull(uint8_t *ch)
                        /* start of a new message, send start flag octet */
                        *ch = HDLC_FLAG;
                        sercomm.tx.next_char = sercomm.tx.msg->data;
+                       sercomm_unlock(&flags);
                        return 1;
                } else {
                        /* no more data avilable */
+                       sercomm_unlock(&flags);
                        return 0;
                }
        }
 
        if (sercomm.tx.state == RX_ST_ESCAPE) {
                /* we've already transmitted the ESCAPE octet,
-                * we now need to trnsmit the escaped data */
+                * we now need to transmit the escaped data */
                *ch = *sercomm.tx.next_char++;
                sercomm.tx.state = RX_ST_DATA;
        } else if (sercomm.tx.next_char >= sercomm.tx.msg->tail) {
@@ -183,6 +201,8 @@ int sercomm_drv_pull(uint8_t *ch)
                /* standard case, simply send next octet */
                *ch = *sercomm.tx.next_char++;
        }
+
+       sercomm_unlock(&flags);
        return 1;
 }
 
@@ -199,7 +219,7 @@ int sercomm_register_rx_cb(uint8_t dlci, dlci_cb_t cb)
        return 0;
 }
 
-/* dispatch an incomnig message once it is completely received */
+/* dispatch an incoming message once it is completely received */
 static void dispatch_rx_msg(uint8_t dlci, struct msgb *msg)
 {
        if (dlci >= ARRAY_SIZE(sercomm.rx.dlci_handler) ||
@@ -268,7 +288,7 @@ int sercomm_drv_rx_char(uint8_t ch)
                ch ^= (1 << 5);
                ptr = msgb_put(sercomm.rx.msg, 1);
                *ptr = ch;
-               /* transition back to nromal DATA state */
+               /* transition back to normal DATA state */
                sercomm.rx.state = RX_ST_DATA;
                break;
        }