diff options
author | Alexander Aring <alex.aring@gmail.com> | 2015-06-24 05:36:36 -0400 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2015-07-23 11:10:49 -0400 |
commit | 3cf24cf8c3c06f9a6cacc8fc2cad94661b6096b6 (patch) | |
tree | b1192515ba1dcac09a108816386df1145a003a7c | |
parent | a6cb869b3b7c16fd7c3ee766dd9f9a4fdda7edf9 (diff) |
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>
-rw-r--r-- | net/mac802154/cfg.c | 45 | ||||
-rw-r--r-- | net/mac802154/ieee802154_i.h | 1 | ||||
-rw-r--r-- | net/mac802154/rx.c | 10 |
3 files changed, 54 insertions, 2 deletions
diff --git a/net/mac802154/cfg.c b/net/mac802154/cfg.c index 44db8613812e..f7ba51e8b4ca 100644 --- a/net/mac802154/cfg.c +++ b/net/mac802154/cfg.c | |||
@@ -44,6 +44,49 @@ static void ieee802154_del_iface_deprecated(struct wpan_phy *wpan_phy, | |||
44 | ieee802154_if_remove(sdata); | 44 | ieee802154_if_remove(sdata); |
45 | } | 45 | } |
46 | 46 | ||
47 | #ifdef CONFIG_PM | ||
48 | static int ieee802154_suspend(struct wpan_phy *wpan_phy) | ||
49 | { | ||
50 | struct ieee802154_local *local = wpan_phy_priv(wpan_phy); | ||
51 | |||
52 | if (!local->open_count) | ||
53 | goto suspend; | ||
54 | |||
55 | ieee802154_stop_queue(&local->hw); | ||
56 | synchronize_net(); | ||
57 | |||
58 | /* stop hardware - this must stop RX */ | ||
59 | ieee802154_stop_device(local); | ||
60 | |||
61 | suspend: | ||
62 | local->suspended = true; | ||
63 | return 0; | ||
64 | } | ||
65 | |||
66 | static int ieee802154_resume(struct wpan_phy *wpan_phy) | ||
67 | { | ||
68 | struct ieee802154_local *local = wpan_phy_priv(wpan_phy); | ||
69 | int ret; | ||
70 | |||
71 | /* nothing to do if HW shouldn't run */ | ||
72 | if (!local->open_count) | ||
73 | goto wake_up; | ||
74 | |||
75 | /* restart hardware */ | ||
76 | ret = drv_start(local); | ||
77 | if (ret) | ||
78 | return ret; | ||
79 | |||
80 | wake_up: | ||
81 | ieee802154_wake_queue(&local->hw); | ||
82 | local->suspended = false; | ||
83 | return 0; | ||
84 | } | ||
85 | #else | ||
86 | #define ieee802154_suspend NULL | ||
87 | #define ieee802154_resume NULL | ||
88 | #endif | ||
89 | |||
47 | static int | 90 | static int |
48 | ieee802154_add_iface(struct wpan_phy *phy, const char *name, | 91 | ieee802154_add_iface(struct wpan_phy *phy, const char *name, |
49 | unsigned char name_assign_type, | 92 | unsigned char name_assign_type, |
@@ -232,6 +275,8 @@ ieee802154_set_lbt_mode(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev, | |||
232 | const struct cfg802154_ops mac802154_config_ops = { | 275 | const struct cfg802154_ops mac802154_config_ops = { |
233 | .add_virtual_intf_deprecated = ieee802154_add_iface_deprecated, | 276 | .add_virtual_intf_deprecated = ieee802154_add_iface_deprecated, |
234 | .del_virtual_intf_deprecated = ieee802154_del_iface_deprecated, | 277 | .del_virtual_intf_deprecated = ieee802154_del_iface_deprecated, |
278 | .suspend = ieee802154_suspend, | ||
279 | .resume = ieee802154_resume, | ||
235 | .add_virtual_intf = ieee802154_add_iface, | 280 | .add_virtual_intf = ieee802154_add_iface, |
236 | .del_virtual_intf = ieee802154_del_iface, | 281 | .del_virtual_intf = ieee802154_del_iface, |
237 | .set_channel = ieee802154_set_channel, | 282 | .set_channel = ieee802154_set_channel, |
diff --git a/net/mac802154/ieee802154_i.h b/net/mac802154/ieee802154_i.h index 04077830e88c..0054f39d499b 100644 --- a/net/mac802154/ieee802154_i.h +++ b/net/mac802154/ieee802154_i.h | |||
@@ -56,6 +56,7 @@ struct ieee802154_local { | |||
56 | struct hrtimer ifs_timer; | 56 | struct hrtimer ifs_timer; |
57 | 57 | ||
58 | bool started; | 58 | bool started; |
59 | bool suspended; | ||
59 | 60 | ||
60 | struct tasklet_struct tasklet; | 61 | struct tasklet_struct tasklet; |
61 | struct sk_buff_head skb_queue; | 62 | struct sk_buff_head skb_queue; |
diff --git a/net/mac802154/rx.c b/net/mac802154/rx.c index d93ad2d4a4fc..5a258c11ed3b 100644 --- a/net/mac802154/rx.c +++ b/net/mac802154/rx.c | |||
@@ -253,6 +253,9 @@ void ieee802154_rx(struct ieee802154_hw *hw, struct sk_buff *skb) | |||
253 | 253 | ||
254 | WARN_ON_ONCE(softirq_count() == 0); | 254 | WARN_ON_ONCE(softirq_count() == 0); |
255 | 255 | ||
256 | if (local->suspended) | ||
257 | goto drop; | ||
258 | |||
256 | /* TODO: When a transceiver omits the checksum here, we | 259 | /* TODO: When a transceiver omits the checksum here, we |
257 | * add an own calculated one. This is currently an ugly | 260 | * add an own calculated one. This is currently an ugly |
258 | * solution because the monitor needs a crc here. | 261 | * solution because the monitor needs a crc here. |
@@ -273,8 +276,7 @@ void ieee802154_rx(struct ieee802154_hw *hw, struct sk_buff *skb) | |||
273 | crc = crc_ccitt(0, skb->data, skb->len); | 276 | crc = crc_ccitt(0, skb->data, skb->len); |
274 | if (crc) { | 277 | if (crc) { |
275 | rcu_read_unlock(); | 278 | rcu_read_unlock(); |
276 | kfree_skb(skb); | 279 | goto drop; |
277 | return; | ||
278 | } | 280 | } |
279 | } | 281 | } |
280 | /* remove crc */ | 282 | /* remove crc */ |
@@ -283,6 +285,10 @@ void ieee802154_rx(struct ieee802154_hw *hw, struct sk_buff *skb) | |||
283 | __ieee802154_rx_handle_packet(local, skb); | 285 | __ieee802154_rx_handle_packet(local, skb); |
284 | 286 | ||
285 | rcu_read_unlock(); | 287 | rcu_read_unlock(); |
288 | |||
289 | return; | ||
290 | drop: | ||
291 | kfree_skb(skb); | ||
286 | } | 292 | } |
287 | EXPORT_SYMBOL(ieee802154_rx); | 293 | EXPORT_SYMBOL(ieee802154_rx); |
288 | 294 | ||