From 8b4e47b1164756e843662d4f3063425fddd8c232 Mon Sep 17 00:00:00 2001 From: smckown Date: Wed, 6 May 2009 18:08:23 +0000 Subject: [PATCH] Fix race conditions when SPI peripheral is unconfigured during activity. --- tos/chips/msp430/usci/Msp430SpiP.nc | 92 ++++++++++++++++++++++------- 1 file changed, 72 insertions(+), 20 deletions(-) diff --git a/tos/chips/msp430/usci/Msp430SpiP.nc b/tos/chips/msp430/usci/Msp430SpiP.nc index 12b22932..b230f607 100644 --- a/tos/chips/msp430/usci/Msp430SpiP.nc +++ b/tos/chips/msp430/usci/Msp430SpiP.nc @@ -158,12 +158,25 @@ implementation { } } + task void signalSendDone() + { + atomic { + uint16_t len = m_len; + m_len = 0; + signal SpiPacket.sendDone(m_txBuf, m_rxBuf, len, SUCCESS); + } + } + async command void ResourceConfigure.unconfigure() { atomic { /* Disable the device */ call Registers.setCtl1(UCSWRST); + /* Ensure SpiPacket.sendDone is posted if a trx was in progress */ + if (m_len) + post signalSendDone(); + /* Clear interrupts and interrupt flags. We only used Rx */ call Registers.clrIeRx(); call Registers.clrIfgRx(); @@ -204,7 +217,50 @@ implementation { } } - void sendData() + bool waitOnRx() + { + if (call Registers.getCtl0(UCMST)) { + while (!call Registers.getIfgRx() && !call Registers.getCtl1(UCSWRST)); + return TRUE; + } else { + /* If SPI slave, the host could quit clocking any time, so we need a + * timeout. + */ + unsigned i = 0; + + while (++i) { + if (call Registers.getIfgRx()) + return TRUE; + if (call Registers.getCtl1(UCSWRST)) + return FALSE; + } + return FALSE; + } + } + + bool waitOnTx() + { + if (call Registers.getCtl0(UCMST)) { + while (!call Registers.getIfgTx() && !call Registers.getCtl1(UCSWRST)); + return TRUE; + } else { + /* If SPI slave, the host could quit clocking any time, so we need a + * timeout. + */ + unsigned i = 0; + + while (++i) { + if (call Registers.getIfgTx()) + return TRUE; + if (call Registers.getCtl1(UCSWRST)) + return FALSE; + } + return FALSE; + } + } + + /* Return FALSE if we are in reset, so callers can clean up as appropriate. */ + bool sendData() { atomic { uint16_t end = m_pos + (blockSize ? blockSize : BLOCKSIZE_DEFAULT); @@ -214,13 +270,14 @@ implementation { end = m_len; call Registers.setTxbuf(m_txBuf ? m_txBuf[m_pos] : 0); while (++m_pos < end) { - while (!call Registers.getIfgRx() && !call Registers.getCtl1(UCSWRST)); + waitOnRx(); tmp = call Registers.getRxbuf(); if (m_rxBuf) m_rxBuf[m_pos - 1] = tmp; - while (!call Registers.getIfgTx() && !call Registers.getCtl1(UCSWRST)); + waitOnTx(); call Registers.setTxbuf(m_txBuf ? m_txBuf[m_pos] : 0); } + return call Registers.getCtl1(UCSWRST) ? FALSE : TRUE; } } @@ -235,35 +292,30 @@ implementation { m_rxBuf = rxBuf; m_len = len; m_pos = 0; - call Registers.setIeRx(); - sendData(); - return SUCCESS; + if (sendData()) { + call Registers.setIeRx(); + return SUCCESS; + } else { + m_len = 0; + return FAIL; + } } } } async event void Interrupts.tx() {} - task void signalSendDone() - { - atomic { - uint16_t len = m_len; - m_len = 0; - signal SpiPacket.sendDone(m_txBuf, m_rxBuf, len, SUCCESS); - } - } - async event void Interrupts.rx(uint8_t byte) { if (m_rxBuf) m_rxBuf[m_pos - 1] = byte; - if (m_pos < m_len) - sendData(); - else { - call Registers.clrIeRx(); - post signalSendDone(); /* Don't signal from ISR context */ + if (m_pos < m_len) { + if (sendData()) + return; } + call Registers.clrIeRx(); + post signalSendDone(); /* Don't signal from ISR context */ } default async event void SpiPacket.sendDone(uint8_t*, uint8_t*, uint16_t, -- 2.39.2