netdev_upper: Protect quota by spin lock to allow netpkt_xxx be called in interrupt context
Before atomic is ready on every platform, we need a way to protect quota, previously it's protected by net_lock, but this makes netpkt_xxx interfaces unable to be called under interrupt context, so changed to spin lock. Also, we can easily change them into atomic under this implementation. Signed-off-by: Zhe Weng <wengzhe@xiaomi.com>
This commit is contained in:
parent
36591af615
commit
eb47312518
@ -37,6 +37,7 @@
|
|||||||
#include <nuttx/net/netdev_lowerhalf.h>
|
#include <nuttx/net/netdev_lowerhalf.h>
|
||||||
#include <nuttx/net/pkt.h>
|
#include <nuttx/net/pkt.h>
|
||||||
#include <nuttx/semaphore.h>
|
#include <nuttx/semaphore.h>
|
||||||
|
#include <nuttx/spinlock.h>
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Pre-processor Definitions
|
* Pre-processor Definitions
|
||||||
@ -77,6 +78,51 @@ struct netdev_upperhalf_s
|
|||||||
* Private Functions
|
* Private Functions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: quota_fetch_inc/dec
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Fetch the quota and add/sub one to it. It works like atomic_fetch_xxx,
|
||||||
|
* just because currently we don't have atomic on some platform. We may
|
||||||
|
* switch to atomic later.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static int quota_fetch_inc(FAR struct netdev_lowerhalf_s *lower,
|
||||||
|
enum netpkt_type_e type)
|
||||||
|
{
|
||||||
|
irqstate_t flags = spin_lock_irqsave(NULL);
|
||||||
|
int ret = lower->quota[type]++;
|
||||||
|
spin_unlock_irqrestore(NULL, flags);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int quota_fetch_dec(FAR struct netdev_lowerhalf_s *lower,
|
||||||
|
enum netpkt_type_e type)
|
||||||
|
{
|
||||||
|
irqstate_t flags = spin_lock_irqsave(NULL);
|
||||||
|
int ret = lower->quota[type]--;
|
||||||
|
spin_unlock_irqrestore(NULL, flags);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: quota_load
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Fetch the quota, works like atomic_load.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static int quota_load(FAR struct netdev_lowerhalf_s *lower,
|
||||||
|
enum netpkt_type_e type)
|
||||||
|
{
|
||||||
|
irqstate_t flags = spin_lock_irqsave(NULL);
|
||||||
|
int ret = lower->quota[type];
|
||||||
|
spin_unlock_irqrestore(NULL, flags);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Name: netpkt_get
|
* Name: netpkt_get
|
||||||
*
|
*
|
||||||
@ -105,7 +151,7 @@ static FAR netpkt_t *netpkt_get(FAR struct net_driver_s *dev,
|
|||||||
* cases will be limited by netdev_upper_can_tx and seldom reaches here.
|
* cases will be limited by netdev_upper_can_tx and seldom reaches here.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (upper->lower->quota[type]-- <= 0)
|
if (quota_fetch_dec(upper->lower, type) <= 0)
|
||||||
{
|
{
|
||||||
nwarn("WARNING: Allowing temperarily exceeding quota of %s.\n",
|
nwarn("WARNING: Allowing temperarily exceeding quota of %s.\n",
|
||||||
dev->d_ifname);
|
dev->d_ifname);
|
||||||
@ -137,7 +183,7 @@ static void netpkt_put(FAR struct net_driver_s *dev, FAR netpkt_t *pkt,
|
|||||||
* but we don't want these changes.
|
* but we don't want these changes.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
upper->lower->quota[type]++;
|
quota_fetch_inc(upper->lower, type);
|
||||||
netdev_iob_release(dev);
|
netdev_iob_release(dev);
|
||||||
dev->d_iob = pkt;
|
dev->d_iob = pkt;
|
||||||
dev->d_len = netpkt_getdatalen(upper->lower, pkt);
|
dev->d_len = netpkt_getdatalen(upper->lower, pkt);
|
||||||
@ -186,7 +232,7 @@ netdev_upper_alloc(FAR struct netdev_lowerhalf_s *dev)
|
|||||||
|
|
||||||
static inline bool netdev_upper_can_tx(FAR struct netdev_upperhalf_s *upper)
|
static inline bool netdev_upper_can_tx(FAR struct netdev_upperhalf_s *upper)
|
||||||
{
|
{
|
||||||
return upper->lower->quota[NETPKT_TX] > 0;
|
return quota_load(upper->lower, NETPKT_TX) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
@ -814,21 +860,19 @@ FAR netpkt_t *netpkt_alloc(FAR struct netdev_lowerhalf_s *dev,
|
|||||||
{
|
{
|
||||||
FAR netpkt_t *pkt;
|
FAR netpkt_t *pkt;
|
||||||
|
|
||||||
if (dev->quota[type] <= 0)
|
if (quota_fetch_dec(dev, type) <= 0)
|
||||||
{
|
{
|
||||||
|
quota_fetch_inc(dev, type);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
pkt = iob_tryalloc(false);
|
pkt = iob_tryalloc(false);
|
||||||
if (pkt == NULL)
|
if (pkt == NULL)
|
||||||
{
|
{
|
||||||
|
quota_fetch_inc(dev, type);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
net_lock(); /* REVISIT: Do we have better solution? */
|
|
||||||
dev->quota[type]--;
|
|
||||||
net_unlock();
|
|
||||||
|
|
||||||
iob_reserve(pkt, CONFIG_NET_LL_GUARDSIZE);
|
iob_reserve(pkt, CONFIG_NET_LL_GUARDSIZE);
|
||||||
return pkt;
|
return pkt;
|
||||||
}
|
}
|
||||||
@ -849,10 +893,7 @@ FAR netpkt_t *netpkt_alloc(FAR struct netdev_lowerhalf_s *dev,
|
|||||||
void netpkt_free(FAR struct netdev_lowerhalf_s *dev, FAR netpkt_t *pkt,
|
void netpkt_free(FAR struct netdev_lowerhalf_s *dev, FAR netpkt_t *pkt,
|
||||||
enum netpkt_type_e type)
|
enum netpkt_type_e type)
|
||||||
{
|
{
|
||||||
net_lock(); /* REVISIT: Do we have better solution? */
|
quota_fetch_inc(dev, type);
|
||||||
dev->quota[type]++;
|
|
||||||
net_unlock();
|
|
||||||
|
|
||||||
iob_free_chain(pkt);
|
iob_free_chain(pkt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user