ieee802154: Improves internal timer logic to handle work serially
Before, the MAC timer used a watchdog to schedule work with the high priority worker queue. However, since everything in the MAC is supposed to be serialized through the use of the high priority work queue, but the timer uses a watchdog, there are some unintended consequences. To simplify, we now use the delayed work feature of the work queue.
This commit is contained in:
parent
19de3372b7
commit
93cdae50fc
@ -92,13 +92,6 @@ static void mac802154_sfevent(FAR const struct ieee802154_radiocb_s *radiocb,
|
||||
|
||||
static void mac802154_purge_worker(FAR void *arg);
|
||||
|
||||
/* Watchdog Timeout Functions */
|
||||
|
||||
static void mac802154_timeout_expiry(int argc, wdparm_t arg, ...);
|
||||
|
||||
static uint32_t mac802154_symtoticks(FAR struct ieee802154_privmac_s *priv,
|
||||
uint32_t symbols);
|
||||
|
||||
static void mac802154_rxdatareq(FAR struct ieee802154_privmac_s *priv,
|
||||
FAR struct ieee802154_data_ind_s *ind);
|
||||
static void mac802154_rxdataframe(FAR struct ieee802154_privmac_s *priv,
|
||||
@ -1918,125 +1911,6 @@ errout:
|
||||
mac802154_notif_free_locked(priv, notif);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: mac802154_symtoticks
|
||||
*
|
||||
* Description:
|
||||
* Helper function for converting symbols to system clock ticks
|
||||
*
|
||||
* Assumptions:
|
||||
* priv MAC struct is locked when calling.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static uint32_t mac802154_symtoticks(FAR struct ieee802154_privmac_s *priv,
|
||||
uint32_t symbols)
|
||||
{
|
||||
union ieee802154_attr_u attrval;
|
||||
uint32_t ret;
|
||||
|
||||
/* First, get the symbol duration from the radio layer. Symbol duration is
|
||||
* returned in picoseconds to ensure precision is kept when multiplying to
|
||||
* get overall times.
|
||||
*/
|
||||
|
||||
priv->radio->getattr(priv->radio, IEEE802154_ATTR_PHY_SYMBOL_DURATION,
|
||||
&attrval);
|
||||
|
||||
/* After this step, ret represents microseconds */
|
||||
|
||||
ret = ((uint64_t)attrval.phy.symdur_picosec * symbols) / (1000 * 1000);
|
||||
|
||||
/* This method should only be used for things that can be late. For instance,
|
||||
* it's always okay to wait a little longer before disabling your receiver.
|
||||
* Therefore, we force the tick count to round up.
|
||||
*/
|
||||
|
||||
if (ret % USEC_PER_TICK == 0)
|
||||
{
|
||||
ret = ret/USEC_PER_TICK;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = ret/USEC_PER_TICK;
|
||||
ret++;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: mac802154_timerstart
|
||||
*
|
||||
* Description:
|
||||
* Helper function wrapping the watchdog timer interface. Helps isolate
|
||||
* different operations from having to worry about work queues and watchdog
|
||||
* timers.
|
||||
*
|
||||
* Assumptions:
|
||||
* priv MAC struct is locked when calling.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int mac802154_timerstart(FAR struct ieee802154_privmac_s *priv,
|
||||
uint32_t numsymbols, mac802154_worker_t worker)
|
||||
{
|
||||
/* TODO: Add check to make sure timer is not already being used. I'd like to
|
||||
* design this so that it absolutely never happens */
|
||||
|
||||
/* Convert the number of symbols to the number of CPU ticks */
|
||||
|
||||
uint32_t ticks = mac802154_symtoticks(priv, numsymbols);
|
||||
|
||||
/* Save the function pointer to call if the timeout expires */
|
||||
|
||||
priv->timeout_worker = worker;
|
||||
|
||||
/* Start the watchdog */
|
||||
|
||||
wd_start(priv->timeout, (int32_t)ticks, mac802154_timeout_expiry,
|
||||
1, (wdparm_t)priv);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Function: mac802154_timeout_expiry
|
||||
*
|
||||
* Description:
|
||||
* The watchdog timed out. Called from the timer interrupt handler.
|
||||
*
|
||||
* Parameters:
|
||||
* argc - The number of available arguments
|
||||
* arg - The first argument
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
* Assumptions:
|
||||
* Global interrupts are disabled by the watchdog logic.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void mac802154_timeout_expiry(int argc, wdparm_t arg, ...)
|
||||
{
|
||||
FAR struct ieee802154_privmac_s *priv = (FAR struct ieee802154_privmac_s *)arg;
|
||||
|
||||
/* There should never be a case where the timeout is used twice at the same
|
||||
* time. */
|
||||
|
||||
DEBUGASSERT(work_available(&priv->timeout_work));
|
||||
|
||||
/* Check to make sure the function pointer is still valid */
|
||||
|
||||
DEBUGASSERT(priv->timeout_worker != NULL);
|
||||
|
||||
wlinfo("Timer expired\n");
|
||||
|
||||
work_queue(MAC802154_WORK, &priv->timeout_work, (worker_t)priv->timeout_worker,
|
||||
priv, 0);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
@ -2092,10 +1966,6 @@ MACHANDLE mac802154_create(FAR struct ieee802154_radio_s *radiodev)
|
||||
|
||||
sem_init(&mac->opsem, 0, 1);
|
||||
|
||||
/* Setup watchdog for extraction timeout */
|
||||
|
||||
mac->timeout = wd_create();
|
||||
|
||||
/* Initialize fields */
|
||||
|
||||
mac->radio = radiodev;
|
||||
|
@ -58,7 +58,7 @@
|
||||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
static void mac802154_assoctimeout(FAR struct ieee802154_privmac_s *priv);
|
||||
static void mac802154_assoctimeout(FAR void *arg);
|
||||
|
||||
/****************************************************************************
|
||||
* Public MAC Functions
|
||||
@ -858,10 +858,22 @@ void mac802154_rx_assocresp(FAR struct ieee802154_privmac_s *priv,
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void mac802154_assoctimeout(FAR struct ieee802154_privmac_s *priv)
|
||||
static void mac802154_assoctimeout(FAR void *arg)
|
||||
{
|
||||
FAR struct ieee802154_privmac_s *priv = (FAR struct ieee802154_privmac_s *)arg;
|
||||
FAR struct ieee802154_notif_s *notif;
|
||||
|
||||
/* If there is work scheduled for the rxframe_worker, we want to reschedule
|
||||
* this work, so that we make sure if the frame we were waiting for was just
|
||||
* received, we don't timeout
|
||||
*/
|
||||
|
||||
if (!work_available(&priv->rx_work))
|
||||
{
|
||||
work_queue(MAC802154_WORK, &priv->timer_work, mac802154_assoctimeout, priv, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUGASSERT(priv->curr_op == MAC802154_OP_ASSOC);
|
||||
|
||||
/* If the device does not extract an association response command
|
||||
|
@ -139,9 +139,6 @@ enum mac802154_operation_e
|
||||
MAC802154_OP_AUTOEXTRACT,
|
||||
};
|
||||
|
||||
struct ieee802154_privmac_s; /* Forward Reference */
|
||||
typedef void (*mac802154_worker_t)(FAR struct ieee802154_privmac_s *priv);
|
||||
|
||||
/* The privmac structure holds the internal state of the MAC and is the
|
||||
* underlying represention of the opaque MACHANDLE. It contains storage for
|
||||
* the IEEE802.15.4 MIB attributes.
|
||||
@ -254,12 +251,8 @@ struct ieee802154_privmac_s
|
||||
|
||||
struct work_s tx_work;
|
||||
struct work_s rx_work;
|
||||
|
||||
struct work_s timeout_work;
|
||||
WDOG_ID timeout; /* Timeout watchdog */
|
||||
mac802154_worker_t timeout_worker;
|
||||
|
||||
struct work_s purge_work;
|
||||
struct work_s timer_work;
|
||||
|
||||
/****************** Uncategorized MAC PIB attributes ***********************/
|
||||
|
||||
@ -375,9 +368,6 @@ int mac802154_txdesc_alloc(FAR struct ieee802154_privmac_s *priv,
|
||||
FAR struct ieee802154_txdesc_s **txdesc,
|
||||
bool allow_interrupt);
|
||||
|
||||
int mac802154_timerstart(FAR struct ieee802154_privmac_s *priv,
|
||||
uint32_t numsymbols, mac802154_worker_t);
|
||||
|
||||
void mac802154_setupindirect(FAR struct ieee802154_privmac_s *priv,
|
||||
FAR struct ieee802154_txdesc_s *txdesc);
|
||||
|
||||
@ -624,6 +614,77 @@ static inline void mac802154_txdesc_free(FAR struct ieee802154_privmac_s *priv,
|
||||
mac802154_givesem(&priv->txdesc_sem);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: mac802154_symtoticks
|
||||
*
|
||||
* Description:
|
||||
* Helper function for converting symbols to system clock ticks
|
||||
*
|
||||
* Assumptions:
|
||||
* priv MAC struct is locked when calling.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static inline uint32_t mac802154_symtoticks(FAR struct ieee802154_privmac_s *priv,
|
||||
uint32_t symbols)
|
||||
{
|
||||
union ieee802154_attr_u attrval;
|
||||
uint32_t ret;
|
||||
|
||||
/* First, get the symbol duration from the radio layer. Symbol duration is
|
||||
* returned in picoseconds to ensure precision is kept when multiplying to
|
||||
* get overall times.
|
||||
*/
|
||||
|
||||
priv->radio->getattr(priv->radio, IEEE802154_ATTR_PHY_SYMBOL_DURATION,
|
||||
&attrval);
|
||||
|
||||
/* After this step, ret represents microseconds */
|
||||
|
||||
ret = ((uint64_t)attrval.phy.symdur_picosec * symbols) / (1000 * 1000);
|
||||
|
||||
/* This method should only be used for things that can be late. For instance,
|
||||
* it's always okay to wait a little longer before disabling your receiver.
|
||||
* Therefore, we force the tick count to round up.
|
||||
*/
|
||||
|
||||
if (ret % USEC_PER_TICK == 0)
|
||||
{
|
||||
ret = ret/USEC_PER_TICK;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = ret/USEC_PER_TICK;
|
||||
ret++;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: mac802154_timerstart
|
||||
*
|
||||
* Description:
|
||||
* Helper function wrapping the watchdog timer interface. Helps isolate
|
||||
* different operations from having to worry about work queues and watchdog
|
||||
* timers.
|
||||
*
|
||||
* Assumptions:
|
||||
* priv MAC struct is locked when calling.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static inline void mac802154_timerstart(FAR struct ieee802154_privmac_s *priv,
|
||||
uint32_t numsymbols, worker_t worker)
|
||||
{
|
||||
DEBUGASSERT(work_available(&priv->timer_work));
|
||||
|
||||
/* Schedule the work, converting the number of symbols to the number of CPU ticks */
|
||||
|
||||
work_queue(MAC802154_WORK, &priv->timer_work, worker, priv,
|
||||
mac802154_symtoticks(priv, numsymbols));
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: mac802154_timercancel
|
||||
*
|
||||
@ -637,8 +698,7 @@ static inline void mac802154_txdesc_free(FAR struct ieee802154_privmac_s *priv,
|
||||
|
||||
static inline int mac802154_timercancel(FAR struct ieee802154_privmac_s *priv)
|
||||
{
|
||||
wd_cancel(priv->timeout);
|
||||
priv->timeout_worker = NULL;
|
||||
work_cancel(MAC802154_WORK, &priv->timer_work);
|
||||
wlinfo("Timer cancelled\n");
|
||||
return OK;
|
||||
}
|
||||
|
@ -60,7 +60,7 @@
|
||||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
static void mac802154_polltimeout(FAR struct ieee802154_privmac_s *priv);
|
||||
static void mac802154_polltimeout(FAR void *arg);
|
||||
|
||||
/****************************************************************************
|
||||
* Public MAC Functions
|
||||
@ -152,6 +152,8 @@ int mac802154_req_poll(MACHANDLE mac, FAR struct ieee802154_poll_req_s *req)
|
||||
|
||||
priv->cmd_desc = txdesc;
|
||||
|
||||
wlinfo("Queuing POLL.request in CSMA queue\n");
|
||||
|
||||
/* Link the transaction into the CSMA transaction list */
|
||||
|
||||
sq_addlast((FAR sq_entry_t *)txdesc, &priv->csma_queue);
|
||||
@ -259,10 +261,22 @@ void mac802154_txdone_datareq_poll(FAR struct ieee802154_privmac_s *priv,
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void mac802154_polltimeout(FAR struct ieee802154_privmac_s *priv)
|
||||
void mac802154_polltimeout(FAR void *arg)
|
||||
{
|
||||
FAR struct ieee802154_privmac_s *priv = (FAR struct ieee802154_privmac_s *)arg;
|
||||
FAR struct ieee802154_notif_s *notif;
|
||||
|
||||
/* If there is work scheduled for the rxframe_worker, we want to reschedule
|
||||
* this work, so that we make sure if the frame we were waiting for was just
|
||||
* received, we don't timeout
|
||||
*/
|
||||
|
||||
if (!work_available(&priv->rx_work))
|
||||
{
|
||||
work_queue(MAC802154_WORK, &priv->timer_work, mac802154_polltimeout, priv, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUGASSERT(priv->curr_op == MAC802154_OP_POLL);
|
||||
|
||||
/* Allocate a notification struct to pass to the next highest layer.
|
||||
|
@ -60,7 +60,7 @@
|
||||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
static void mac802154_scantimeout(FAR struct ieee802154_privmac_s *priv);
|
||||
static void mac802154_scantimeout(FAR void *arg);
|
||||
|
||||
/****************************************************************************
|
||||
* Public MAC Functions
|
||||
@ -251,8 +251,9 @@ void mac802154_scanfinish(FAR struct ieee802154_privmac_s *priv,
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void mac802154_scantimeout(FAR struct ieee802154_privmac_s *priv)
|
||||
static void mac802154_scantimeout(FAR void *arg)
|
||||
{
|
||||
FAR struct ieee802154_privmac_s *priv = (FAR struct ieee802154_privmac_s *)arg;
|
||||
DEBUGASSERT(priv->curr_op == MAC802154_OP_SCAN);
|
||||
|
||||
/* If we got here it means we are done scanning that channel */
|
||||
|
Loading…
Reference in New Issue
Block a user