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: Alexander Aring <alex.aring@gmail.com> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
This commit is contained in:
parent
a6cb869b3b
commit
3cf24cf8c3
@ -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,
|
|||||||
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 {
|
|||||||
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)
|
|||||||
|
|
||||||
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)
|
|||||||
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)
|
|||||||
__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);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user