Commit 3cf24cf8 authored by Alexander Aring's avatar Alexander Aring Committed by Marcel Holtmann

mac802154: cfg: add suspend and resume callbacks

This patch introduces suspend and resume callbacks to mac802154. When
doing suspend we calling the stop driver callback which should stop the
receiving of frames. A transceiver should go into low-power mode then.
Calling resume will call the start driver callback, which starts receiving
again and allow to transmit frames.

This was tested only with the fakelb driver and a qemu vm by doing the
following commands:

echo "devices" > /sys/power/pm_test
echo "freeze" > /sys/power/state

while doing some high traffic between two fakelb phys.
Signed-off-by: default avatarAlexander Aring <alex.aring@gmail.com>
Signed-off-by: default avatarMarcel Holtmann <marcel@holtmann.org>
parent a6cb869b
...@@ -44,6 +44,49 @@ static void ieee802154_del_iface_deprecated(struct wpan_phy *wpan_phy, ...@@ -44,6 +44,49 @@ static void ieee802154_del_iface_deprecated(struct wpan_phy *wpan_phy,
ieee802154_if_remove(sdata); ieee802154_if_remove(sdata);
} }
#ifdef CONFIG_PM
static int ieee802154_suspend(struct wpan_phy *wpan_phy)
{
struct ieee802154_local *local = wpan_phy_priv(wpan_phy);
if (!local->open_count)
goto suspend;
ieee802154_stop_queue(&local->hw);
synchronize_net();
/* stop hardware - this must stop RX */
ieee802154_stop_device(local);
suspend:
local->suspended = true;
return 0;
}
static int ieee802154_resume(struct wpan_phy *wpan_phy)
{
struct ieee802154_local *local = wpan_phy_priv(wpan_phy);
int ret;
/* nothing to do if HW shouldn't run */
if (!local->open_count)
goto wake_up;
/* restart hardware */
ret = drv_start(local);
if (ret)
return ret;
wake_up:
ieee802154_wake_queue(&local->hw);
local->suspended = false;
return 0;
}
#else
#define ieee802154_suspend NULL
#define ieee802154_resume NULL
#endif
static int static int
ieee802154_add_iface(struct wpan_phy *phy, const char *name, ieee802154_add_iface(struct wpan_phy *phy, const char *name,
unsigned char name_assign_type, unsigned char name_assign_type,
...@@ -232,6 +275,8 @@ ieee802154_set_lbt_mode(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev, ...@@ -232,6 +275,8 @@ ieee802154_set_lbt_mode(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev,
const struct cfg802154_ops mac802154_config_ops = { const struct cfg802154_ops mac802154_config_ops = {
.add_virtual_intf_deprecated = ieee802154_add_iface_deprecated, .add_virtual_intf_deprecated = ieee802154_add_iface_deprecated,
.del_virtual_intf_deprecated = ieee802154_del_iface_deprecated, .del_virtual_intf_deprecated = ieee802154_del_iface_deprecated,
.suspend = ieee802154_suspend,
.resume = ieee802154_resume,
.add_virtual_intf = ieee802154_add_iface, .add_virtual_intf = ieee802154_add_iface,
.del_virtual_intf = ieee802154_del_iface, .del_virtual_intf = ieee802154_del_iface,
.set_channel = ieee802154_set_channel, .set_channel = ieee802154_set_channel,
......
...@@ -56,6 +56,7 @@ struct ieee802154_local { ...@@ -56,6 +56,7 @@ struct ieee802154_local {
struct hrtimer ifs_timer; struct hrtimer ifs_timer;
bool started; bool started;
bool suspended;
struct tasklet_struct tasklet; struct tasklet_struct tasklet;
struct sk_buff_head skb_queue; struct sk_buff_head skb_queue;
......
...@@ -253,6 +253,9 @@ void ieee802154_rx(struct ieee802154_hw *hw, struct sk_buff *skb) ...@@ -253,6 +253,9 @@ void ieee802154_rx(struct ieee802154_hw *hw, struct sk_buff *skb)
WARN_ON_ONCE(softirq_count() == 0); WARN_ON_ONCE(softirq_count() == 0);
if (local->suspended)
goto drop;
/* TODO: When a transceiver omits the checksum here, we /* TODO: When a transceiver omits the checksum here, we
* add an own calculated one. This is currently an ugly * add an own calculated one. This is currently an ugly
* solution because the monitor needs a crc here. * solution because the monitor needs a crc here.
...@@ -273,8 +276,7 @@ void ieee802154_rx(struct ieee802154_hw *hw, struct sk_buff *skb) ...@@ -273,8 +276,7 @@ void ieee802154_rx(struct ieee802154_hw *hw, struct sk_buff *skb)
crc = crc_ccitt(0, skb->data, skb->len); crc = crc_ccitt(0, skb->data, skb->len);
if (crc) { if (crc) {
rcu_read_unlock(); rcu_read_unlock();
kfree_skb(skb); goto drop;
return;
} }
} }
/* remove crc */ /* remove crc */
...@@ -283,6 +285,10 @@ void ieee802154_rx(struct ieee802154_hw *hw, struct sk_buff *skb) ...@@ -283,6 +285,10 @@ void ieee802154_rx(struct ieee802154_hw *hw, struct sk_buff *skb)
__ieee802154_rx_handle_packet(local, skb); __ieee802154_rx_handle_packet(local, skb);
rcu_read_unlock(); rcu_read_unlock();
return;
drop:
kfree_skb(skb);
} }
EXPORT_SYMBOL(ieee802154_rx); EXPORT_SYMBOL(ieee802154_rx);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment