Просмотр исходного кода

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>
Alexander Aring 10 лет назад
Родитель
Сommit
3cf24cf8c3
3 измененных файлов с 54 добавлено и 2 удалено
  1. 45 0
      net/mac802154/cfg.c
  2. 1 0
      net/mac802154/ieee802154_i.h
  3. 8 2
      net/mac802154/rx.c

+ 45 - 0
net/mac802154/cfg.c

@@ -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,

+ 1 - 0
net/mac802154/ieee802154_i.h

@@ -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;

+ 8 - 2
net/mac802154/rx.c

@@ -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);
-			return;
+			goto drop;
 		}
 		}
 	}
 	}
 	/* 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);