blob: ff0de0f990cb42dc3dd58ba5ec929cb82a5c255e [file] [log] [blame]
alex.bluesman.smirnov@gmail.com1010f542012-05-15 20:50:20 +00001/*
2 * Copyright (C) 2007-2012 Siemens AG
3 *
4 * Written by:
5 * Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
6 *
7 * Based on the code from 'linux-zigbee.sourceforge.net' project.
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2
11 * as published by the Free Software Foundation.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
alex.bluesman.smirnov@gmail.com1010f542012-05-15 20:50:20 +000017 */
18
19#include <linux/kernel.h>
20#include <linux/module.h>
21#include <linux/netdevice.h>
22
alex.bluesman.smirnov@gmail.com62610ad2012-05-15 20:50:28 +000023#include <net/netlink.h>
24#include <linux/nl802154.h>
alex.bluesman.smirnov@gmail.com1010f542012-05-15 20:50:20 +000025#include <net/mac802154.h>
Phoebe Buckheisterb70ab2e2014-03-14 21:23:59 +010026#include <net/ieee802154_netdev.h>
alex.bluesman.smirnov@gmail.com1010f542012-05-15 20:50:20 +000027#include <net/route.h>
Alexander Aring5ad60d32014-10-25 09:41:02 +020028#include <net/cfg802154.h>
alex.bluesman.smirnov@gmail.com1010f542012-05-15 20:50:20 +000029
Alexander Aring0f1556b2014-10-25 09:41:00 +020030#include "ieee802154_i.h"
alex.bluesman.smirnov@gmail.com1010f542012-05-15 20:50:20 +000031
alex.bluesman.smirnov@gmail.com62610ad2012-05-15 20:50:28 +000032int mac802154_slave_open(struct net_device *dev)
33{
Alexander Aring59d19cd2014-10-25 17:16:40 +020034 struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
Alexander Aring036562f2014-10-25 17:16:36 +020035 struct ieee802154_sub_if_data *subif;
Alexander Aring04e850f2014-10-25 17:16:37 +020036 struct ieee802154_local *local = sdata->local;
alex.bluesman.smirnov@gmail.com62610ad2012-05-15 20:50:28 +000037 int res = 0;
38
Phoebe Buckheister336908f2014-03-31 21:37:45 +020039 ASSERT_RTNL();
40
Alexander Aring036562f2014-10-25 17:16:36 +020041 if (sdata->type == IEEE802154_DEV_WPAN) {
Alexander Aringd98be452014-10-25 17:16:38 +020042 mutex_lock(&sdata->local->iflist_mtx);
43 list_for_each_entry(subif, &sdata->local->interfaces, list) {
Alexander Aring036562f2014-10-25 17:16:36 +020044 if (subif != sdata && subif->type == sdata->type &&
Phoebe Buckheister336908f2014-03-31 21:37:45 +020045 subif->running) {
Alexander Aringd98be452014-10-25 17:16:38 +020046 mutex_unlock(&sdata->local->iflist_mtx);
Phoebe Buckheister336908f2014-03-31 21:37:45 +020047 return -EBUSY;
48 }
49 }
Alexander Aringd98be452014-10-25 17:16:38 +020050 mutex_unlock(&sdata->local->iflist_mtx);
Phoebe Buckheister336908f2014-03-31 21:37:45 +020051 }
52
Alexander Aringd98be452014-10-25 17:16:38 +020053 mutex_lock(&sdata->local->iflist_mtx);
Alexander Aring036562f2014-10-25 17:16:36 +020054 sdata->running = true;
Alexander Aringd98be452014-10-25 17:16:38 +020055 mutex_unlock(&sdata->local->iflist_mtx);
Phoebe Buckheister336908f2014-03-31 21:37:45 +020056
Alexander Aringa5e1ec52014-10-25 17:16:35 +020057 if (local->open_count++ == 0) {
58 res = local->ops->start(&local->hw);
alex.bluesman.smirnov@gmail.com62610ad2012-05-15 20:50:28 +000059 WARN_ON(res);
60 if (res)
61 goto err;
62 }
63
alex.bluesman.smirnov@gmail.com62610ad2012-05-15 20:50:28 +000064 netif_start_queue(dev);
65 return 0;
66err:
Alexander Aring04e850f2014-10-25 17:16:37 +020067 sdata->local->open_count--;
alex.bluesman.smirnov@gmail.com62610ad2012-05-15 20:50:28 +000068
69 return res;
70}
71
72int mac802154_slave_close(struct net_device *dev)
73{
Alexander Aring59d19cd2014-10-25 17:16:40 +020074 struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
Alexander Aring04e850f2014-10-25 17:16:37 +020075 struct ieee802154_local *local = sdata->local;
alex.bluesman.smirnov@gmail.com62610ad2012-05-15 20:50:28 +000076
Phoebe Buckheister336908f2014-03-31 21:37:45 +020077 ASSERT_RTNL();
78
alex.bluesman.smirnov@gmail.com62610ad2012-05-15 20:50:28 +000079 netif_stop_queue(dev);
80
Alexander Aringd98be452014-10-25 17:16:38 +020081 mutex_lock(&sdata->local->iflist_mtx);
Alexander Aring036562f2014-10-25 17:16:36 +020082 sdata->running = false;
Alexander Aringd98be452014-10-25 17:16:38 +020083 mutex_unlock(&sdata->local->iflist_mtx);
Phoebe Buckheister336908f2014-03-31 21:37:45 +020084
Alexander Aringa5e1ec52014-10-25 17:16:35 +020085 if (!--local->open_count)
86 local->ops->stop(&local->hw);
alex.bluesman.smirnov@gmail.com62610ad2012-05-15 20:50:28 +000087
88 return 0;
89}
90
91static int
92mac802154_netdev_register(struct wpan_phy *phy, struct net_device *dev)
93{
Alexander Aring59d19cd2014-10-25 17:16:40 +020094 struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
Alexander Aringa5e1ec52014-10-25 17:16:35 +020095 struct ieee802154_local *local;
alex.bluesman.smirnov@gmail.com62610ad2012-05-15 20:50:28 +000096 int err;
97
Alexander Aringa5e1ec52014-10-25 17:16:35 +020098 local = wpan_phy_priv(phy);
alex.bluesman.smirnov@gmail.com62610ad2012-05-15 20:50:28 +000099
Alexander Aring036562f2014-10-25 17:16:36 +0200100 sdata->dev = dev;
Alexander Aring04e850f2014-10-25 17:16:37 +0200101 sdata->local = local;
alex.bluesman.smirnov@gmail.com62610ad2012-05-15 20:50:28 +0000102
Alexander Aringa5e1ec52014-10-25 17:16:35 +0200103 dev->needed_headroom = local->hw.extra_tx_headroom;
alex.bluesman.smirnov@gmail.com62610ad2012-05-15 20:50:28 +0000104
Alexander Aringa5e1ec52014-10-25 17:16:35 +0200105 SET_NETDEV_DEV(dev, &local->phy->dev);
alex.bluesman.smirnov@gmail.com62610ad2012-05-15 20:50:28 +0000106
Alexander Aringd98be452014-10-25 17:16:38 +0200107 mutex_lock(&local->iflist_mtx);
Alexander Aringa5e1ec52014-10-25 17:16:35 +0200108 if (!local->running) {
Alexander Aringd98be452014-10-25 17:16:38 +0200109 mutex_unlock(&local->iflist_mtx);
alex.bluesman.smirnov@gmail.com62610ad2012-05-15 20:50:28 +0000110 return -ENODEV;
111 }
Alexander Aringd98be452014-10-25 17:16:38 +0200112 mutex_unlock(&local->iflist_mtx);
alex.bluesman.smirnov@gmail.com62610ad2012-05-15 20:50:28 +0000113
114 err = register_netdev(dev);
115 if (err < 0)
116 return err;
117
118 rtnl_lock();
Alexander Aringd98be452014-10-25 17:16:38 +0200119 mutex_lock(&local->iflist_mtx);
120 list_add_tail_rcu(&sdata->list, &local->interfaces);
121 mutex_unlock(&local->iflist_mtx);
alex.bluesman.smirnov@gmail.com62610ad2012-05-15 20:50:28 +0000122 rtnl_unlock();
123
124 return 0;
125}
126
127static void
128mac802154_del_iface(struct wpan_phy *phy, struct net_device *dev)
129{
Alexander Aring59d19cd2014-10-25 17:16:40 +0200130 struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
Varka Bhadram4710d802014-07-02 09:01:09 +0530131
alex.bluesman.smirnov@gmail.com62610ad2012-05-15 20:50:28 +0000132 ASSERT_RTNL();
133
Alexander Aring04e850f2014-10-25 17:16:37 +0200134 BUG_ON(sdata->local->phy != phy);
alex.bluesman.smirnov@gmail.com62610ad2012-05-15 20:50:28 +0000135
Alexander Aringd98be452014-10-25 17:16:38 +0200136 mutex_lock(&sdata->local->iflist_mtx);
alex.bluesman.smirnov@gmail.com62610ad2012-05-15 20:50:28 +0000137 list_del_rcu(&sdata->list);
Alexander Aringd98be452014-10-25 17:16:38 +0200138 mutex_unlock(&sdata->local->iflist_mtx);
alex.bluesman.smirnov@gmail.com62610ad2012-05-15 20:50:28 +0000139
140 synchronize_rcu();
141 unregister_netdevice(sdata->dev);
142}
143
144static struct net_device *
145mac802154_add_iface(struct wpan_phy *phy, const char *name, int type)
146{
147 struct net_device *dev;
148 int err = -ENOMEM;
149
alex.bluesman.smirnov@gmail.com62610ad2012-05-15 20:50:28 +0000150 switch (type) {
alex.bluesman.smirnov@gmail.com06060692012-05-15 20:50:29 +0000151 case IEEE802154_DEV_MONITOR:
Alexander Aring036562f2014-10-25 17:16:36 +0200152 dev = alloc_netdev(sizeof(struct ieee802154_sub_if_data),
Tom Gundersenc835a672014-07-14 16:37:24 +0200153 name, NET_NAME_UNKNOWN,
154 mac802154_monitor_setup);
alex.bluesman.smirnov@gmail.com06060692012-05-15 20:50:29 +0000155 break;
alex.bluesman.smirnov@gmail.com32bad7e2012-06-25 23:24:48 +0000156 case IEEE802154_DEV_WPAN:
Alexander Aring036562f2014-10-25 17:16:36 +0200157 dev = alloc_netdev(sizeof(struct ieee802154_sub_if_data),
Tom Gundersenc835a672014-07-14 16:37:24 +0200158 name, NET_NAME_UNKNOWN,
159 mac802154_wpan_setup);
alex.bluesman.smirnov@gmail.com32bad7e2012-06-25 23:24:48 +0000160 break;
alex.bluesman.smirnov@gmail.com62610ad2012-05-15 20:50:28 +0000161 default:
162 dev = NULL;
163 err = -EINVAL;
164 break;
165 }
166 if (!dev)
167 goto err;
168
169 err = mac802154_netdev_register(phy, dev);
170 if (err)
171 goto err_free;
172
173 dev_hold(dev); /* we return an incremented device refcount */
174 return dev;
175
176err_free:
177 free_netdev(dev);
178err:
179 return ERR_PTR(err);
180}
181
Phoebe Buckheister9b2777d2014-02-17 11:34:08 +0100182static int mac802154_set_txpower(struct wpan_phy *phy, int db)
183{
Alexander Aringa5e1ec52014-10-25 17:16:35 +0200184 struct ieee802154_local *local = wpan_phy_priv(phy);
Phoebe Buckheister9b2777d2014-02-17 11:34:08 +0100185
Alexander Aringa5e1ec52014-10-25 17:16:35 +0200186 return local->ops->set_txpower(&local->hw, db);
Phoebe Buckheister9b2777d2014-02-17 11:34:08 +0100187}
188
Phoebe Buckheister84dda3c2014-02-17 11:34:10 +0100189static int mac802154_set_lbt(struct wpan_phy *phy, bool on)
190{
Alexander Aringa5e1ec52014-10-25 17:16:35 +0200191 struct ieee802154_local *local = wpan_phy_priv(phy);
Phoebe Buckheister84dda3c2014-02-17 11:34:10 +0100192
Alexander Aringa5e1ec52014-10-25 17:16:35 +0200193 return local->ops->set_lbt(&local->hw, on);
Phoebe Buckheister84dda3c2014-02-17 11:34:10 +0100194}
195
Phoebe Buckheisterba08fea2014-02-17 11:34:11 +0100196static int mac802154_set_cca_mode(struct wpan_phy *phy, u8 mode)
197{
Alexander Aringa5e1ec52014-10-25 17:16:35 +0200198 struct ieee802154_local *local = wpan_phy_priv(phy);
Phoebe Buckheisterba08fea2014-02-17 11:34:11 +0100199
Alexander Aringa5e1ec52014-10-25 17:16:35 +0200200 return local->ops->set_cca_mode(&local->hw, mode);
Phoebe Buckheisterba08fea2014-02-17 11:34:11 +0100201}
202
Phoebe Buckheister6ca00192014-02-17 11:34:12 +0100203static int mac802154_set_cca_ed_level(struct wpan_phy *phy, s32 level)
204{
Alexander Aringa5e1ec52014-10-25 17:16:35 +0200205 struct ieee802154_local *local = wpan_phy_priv(phy);
Phoebe Buckheister6ca00192014-02-17 11:34:12 +0100206
Alexander Aringa5e1ec52014-10-25 17:16:35 +0200207 return local->ops->set_cca_ed_level(&local->hw, level);
Phoebe Buckheister6ca00192014-02-17 11:34:12 +0100208}
209
Phoebe Buckheister4244db12014-02-17 11:34:14 +0100210static int mac802154_set_csma_params(struct wpan_phy *phy, u8 min_be,
211 u8 max_be, u8 retries)
212{
Alexander Aringa5e1ec52014-10-25 17:16:35 +0200213 struct ieee802154_local *local = wpan_phy_priv(phy);
Phoebe Buckheister4244db12014-02-17 11:34:14 +0100214
Alexander Aringa5e1ec52014-10-25 17:16:35 +0200215 return local->ops->set_csma_params(&local->hw, min_be, max_be, retries);
Phoebe Buckheister4244db12014-02-17 11:34:14 +0100216}
217
218static int mac802154_set_frame_retries(struct wpan_phy *phy, s8 retries)
219{
Alexander Aringa5e1ec52014-10-25 17:16:35 +0200220 struct ieee802154_local *local = wpan_phy_priv(phy);
Phoebe Buckheister4244db12014-02-17 11:34:14 +0100221
Alexander Aringa5e1ec52014-10-25 17:16:35 +0200222 return local->ops->set_frame_retries(&local->hw, retries);
Phoebe Buckheister4244db12014-02-17 11:34:14 +0100223}
224
Alexander Aringc5c47e62014-10-27 17:13:30 +0100225static void ieee802154_tasklet_handler(unsigned long data)
226{
227 struct ieee802154_local *local = (struct ieee802154_local *)data;
228 struct sk_buff *skb;
229
230 while ((skb = skb_dequeue(&local->skb_queue))) {
231 switch (skb->pkt_type) {
232 case IEEE802154_RX_MSG:
233 /* Clear skb->pkt_type in order to not confuse kernel
234 * netstack.
235 */
236 skb->pkt_type = 0;
237 ieee802154_rx(&local->hw, skb);
238 break;
239 default:
240 WARN(1, "mac802154: Packet is of unknown type %d\n",
241 skb->pkt_type);
242 kfree_skb(skb);
243 break;
244 }
245 }
246}
247
Alexander Aring5a504392014-10-25 17:16:34 +0200248struct ieee802154_hw *
249ieee802154_alloc_hw(size_t priv_data_len, struct ieee802154_ops *ops)
alex.bluesman.smirnov@gmail.com1010f542012-05-15 20:50:20 +0000250{
251 struct wpan_phy *phy;
Alexander Aringa5e1ec52014-10-25 17:16:35 +0200252 struct ieee802154_local *local;
alex.bluesman.smirnov@gmail.com1010f542012-05-15 20:50:20 +0000253 size_t priv_size;
254
Alexander Aringed0a5dc2014-10-26 09:37:08 +0100255 if (!ops || !(ops->xmit_async || ops->xmit_sync) || !ops->ed ||
256 !ops->start || !ops->stop || !ops->set_channel) {
Chen Weilong83a1a7c2013-10-30 15:28:07 +0800257 pr_err("undefined IEEE802.15.4 device operations\n");
alex.bluesman.smirnov@gmail.com1010f542012-05-15 20:50:20 +0000258 return NULL;
259 }
260
261 /* Ensure 32-byte alignment of our private data and hw private data.
Alexander Aringa5e1ec52014-10-25 17:16:35 +0200262 * We use the wpan_phy priv data for both our ieee802154_local and for
alex.bluesman.smirnov@gmail.com1010f542012-05-15 20:50:20 +0000263 * the driver's private data
264 *
265 * in memory it'll be like this:
266 *
Alexander Aringa5e1ec52014-10-25 17:16:35 +0200267 * +-------------------------+
268 * | struct wpan_phy |
269 * +-------------------------+
270 * | struct ieee802154_local |
271 * +-------------------------+
272 * | driver's private data |
273 * +-------------------------+
alex.bluesman.smirnov@gmail.com1010f542012-05-15 20:50:20 +0000274 *
275 * Due to ieee802154 layer isn't aware of driver and MAC structures,
Alexander Aring139f14a2014-10-25 05:25:08 +0200276 * so lets align them here.
alex.bluesman.smirnov@gmail.com1010f542012-05-15 20:50:20 +0000277 */
278
Alexander Aringa5e1ec52014-10-25 17:16:35 +0200279 priv_size = ALIGN(sizeof(*local), NETDEV_ALIGN) + priv_data_len;
alex.bluesman.smirnov@gmail.com1010f542012-05-15 20:50:20 +0000280
281 phy = wpan_phy_alloc(priv_size);
282 if (!phy) {
Chen Weilong83a1a7c2013-10-30 15:28:07 +0800283 pr_err("failure to allocate master IEEE802.15.4 device\n");
alex.bluesman.smirnov@gmail.com1010f542012-05-15 20:50:20 +0000284 return NULL;
285 }
286
Alexander Aringa5e1ec52014-10-25 17:16:35 +0200287 local = wpan_phy_priv(phy);
288 local->phy = phy;
289 local->hw.phy = local->phy;
290 local->hw.priv = (char *)local + ALIGN(sizeof(*local), NETDEV_ALIGN);
291 local->ops = ops;
alex.bluesman.smirnov@gmail.com1010f542012-05-15 20:50:20 +0000292
Alexander Aringd98be452014-10-25 17:16:38 +0200293 INIT_LIST_HEAD(&local->interfaces);
294 mutex_init(&local->iflist_mtx);
alex.bluesman.smirnov@gmail.com1010f542012-05-15 20:50:20 +0000295
Alexander Aringc5c47e62014-10-27 17:13:30 +0100296 tasklet_init(&local->tasklet,
297 ieee802154_tasklet_handler,
298 (unsigned long)local);
299
300 skb_queue_head_init(&local->skb_queue);
301
Alexander Aringa5e1ec52014-10-25 17:16:35 +0200302 return &local->hw;
alex.bluesman.smirnov@gmail.com1010f542012-05-15 20:50:20 +0000303}
Alexander Aring5a504392014-10-25 17:16:34 +0200304EXPORT_SYMBOL(ieee802154_alloc_hw);
alex.bluesman.smirnov@gmail.com1010f542012-05-15 20:50:20 +0000305
Alexander Aring5a504392014-10-25 17:16:34 +0200306void ieee802154_free_hw(struct ieee802154_hw *hw)
alex.bluesman.smirnov@gmail.com1010f542012-05-15 20:50:20 +0000307{
Alexander Aring60741362014-10-25 17:16:39 +0200308 struct ieee802154_local *local = hw_to_local(hw);
alex.bluesman.smirnov@gmail.com1010f542012-05-15 20:50:20 +0000309
Alexander Aringd98be452014-10-25 17:16:38 +0200310 BUG_ON(!list_empty(&local->interfaces));
alex.bluesman.smirnov@gmail.com62610ad2012-05-15 20:50:28 +0000311
Alexander Aringd98be452014-10-25 17:16:38 +0200312 mutex_destroy(&local->iflist_mtx);
Konstantin Khlebnikov1e9f9542012-12-14 01:03:03 +0000313
Alexander Aringa5e1ec52014-10-25 17:16:35 +0200314 wpan_phy_free(local->phy);
alex.bluesman.smirnov@gmail.com1010f542012-05-15 20:50:20 +0000315}
Alexander Aring5a504392014-10-25 17:16:34 +0200316EXPORT_SYMBOL(ieee802154_free_hw);
alex.bluesman.smirnov@gmail.com1010f542012-05-15 20:50:20 +0000317
Alexander Aring5a504392014-10-25 17:16:34 +0200318int ieee802154_register_hw(struct ieee802154_hw *hw)
alex.bluesman.smirnov@gmail.com1010f542012-05-15 20:50:20 +0000319{
Alexander Aring60741362014-10-25 17:16:39 +0200320 struct ieee802154_local *local = hw_to_local(hw);
Alexander Aring640985e2014-07-03 00:20:43 +0200321 int rc = -ENOSYS;
322
Alexander Aring5a504392014-10-25 17:16:34 +0200323 if (hw->flags & IEEE802154_HW_TXPOWER) {
Alexander Aringa5e1ec52014-10-25 17:16:35 +0200324 if (!local->ops->set_txpower)
Alexander Aring640985e2014-07-03 00:20:43 +0200325 goto out;
326
Alexander Aringa5e1ec52014-10-25 17:16:35 +0200327 local->phy->set_txpower = mac802154_set_txpower;
Alexander Aring640985e2014-07-03 00:20:43 +0200328 }
329
Alexander Aring5a504392014-10-25 17:16:34 +0200330 if (hw->flags & IEEE802154_HW_LBT) {
Alexander Aringa5e1ec52014-10-25 17:16:35 +0200331 if (!local->ops->set_lbt)
Alexander Aring640985e2014-07-03 00:20:43 +0200332 goto out;
333
Alexander Aringa5e1ec52014-10-25 17:16:35 +0200334 local->phy->set_lbt = mac802154_set_lbt;
Alexander Aring640985e2014-07-03 00:20:43 +0200335 }
336
Alexander Aring5a504392014-10-25 17:16:34 +0200337 if (hw->flags & IEEE802154_HW_CCA_MODE) {
Alexander Aringa5e1ec52014-10-25 17:16:35 +0200338 if (!local->ops->set_cca_mode)
Alexander Aring640985e2014-07-03 00:20:43 +0200339 goto out;
340
Alexander Aringa5e1ec52014-10-25 17:16:35 +0200341 local->phy->set_cca_mode = mac802154_set_cca_mode;
Alexander Aring640985e2014-07-03 00:20:43 +0200342 }
343
Alexander Aring5a504392014-10-25 17:16:34 +0200344 if (hw->flags & IEEE802154_HW_CCA_ED_LEVEL) {
Alexander Aringa5e1ec52014-10-25 17:16:35 +0200345 if (!local->ops->set_cca_ed_level)
Alexander Aring640985e2014-07-03 00:20:43 +0200346 goto out;
347
Alexander Aringa5e1ec52014-10-25 17:16:35 +0200348 local->phy->set_cca_ed_level = mac802154_set_cca_ed_level;
Alexander Aring640985e2014-07-03 00:20:43 +0200349 }
350
Alexander Aring5a504392014-10-25 17:16:34 +0200351 if (hw->flags & IEEE802154_HW_CSMA_PARAMS) {
Alexander Aringa5e1ec52014-10-25 17:16:35 +0200352 if (!local->ops->set_csma_params)
Alexander Aring640985e2014-07-03 00:20:43 +0200353 goto out;
354
Alexander Aringa5e1ec52014-10-25 17:16:35 +0200355 local->phy->set_csma_params = mac802154_set_csma_params;
Alexander Aring640985e2014-07-03 00:20:43 +0200356 }
357
Alexander Aring5a504392014-10-25 17:16:34 +0200358 if (hw->flags & IEEE802154_HW_FRAME_RETRIES) {
Alexander Aringa5e1ec52014-10-25 17:16:35 +0200359 if (!local->ops->set_frame_retries)
Alexander Aring640985e2014-07-03 00:20:43 +0200360 goto out;
361
Alexander Aringa5e1ec52014-10-25 17:16:35 +0200362 local->phy->set_frame_retries = mac802154_set_frame_retries;
Alexander Aring640985e2014-07-03 00:20:43 +0200363 }
alex.bluesman.smirnov@gmail.com1010f542012-05-15 20:50:20 +0000364
Alexander Aringf7730542014-10-25 17:16:41 +0200365 local->workqueue =
Alexander Aringa5e1ec52014-10-25 17:16:35 +0200366 create_singlethread_workqueue(wpan_phy_name(local->phy));
Alexander Aringf7730542014-10-25 17:16:41 +0200367 if (!local->workqueue) {
Alexander Aring640985e2014-07-03 00:20:43 +0200368 rc = -ENOMEM;
alex.bluesman.smirnov@gmail.com1010f542012-05-15 20:50:20 +0000369 goto out;
Alexander Aring640985e2014-07-03 00:20:43 +0200370 }
alex.bluesman.smirnov@gmail.com1010f542012-05-15 20:50:20 +0000371
Alexander Aringa5e1ec52014-10-25 17:16:35 +0200372 wpan_phy_set_dev(local->phy, local->hw.parent);
alex.bluesman.smirnov@gmail.com1010f542012-05-15 20:50:20 +0000373
Alexander Aringa5e1ec52014-10-25 17:16:35 +0200374 local->phy->add_iface = mac802154_add_iface;
375 local->phy->del_iface = mac802154_del_iface;
alex.bluesman.smirnov@gmail.com62610ad2012-05-15 20:50:28 +0000376
Alexander Aringa5e1ec52014-10-25 17:16:35 +0200377 rc = wpan_phy_register(local->phy);
alex.bluesman.smirnov@gmail.com1010f542012-05-15 20:50:20 +0000378 if (rc < 0)
379 goto out_wq;
380
381 rtnl_lock();
382
Alexander Aringd98be452014-10-25 17:16:38 +0200383 mutex_lock(&local->iflist_mtx);
Alexander Aringa5e1ec52014-10-25 17:16:35 +0200384 local->running = MAC802154_DEVICE_RUN;
Alexander Aringd98be452014-10-25 17:16:38 +0200385 mutex_unlock(&local->iflist_mtx);
alex.bluesman.smirnov@gmail.com1010f542012-05-15 20:50:20 +0000386
387 rtnl_unlock();
388
389 return 0;
390
391out_wq:
Alexander Aringf7730542014-10-25 17:16:41 +0200392 destroy_workqueue(local->workqueue);
alex.bluesman.smirnov@gmail.com1010f542012-05-15 20:50:20 +0000393out:
394 return rc;
395}
Alexander Aring5a504392014-10-25 17:16:34 +0200396EXPORT_SYMBOL(ieee802154_register_hw);
alex.bluesman.smirnov@gmail.com1010f542012-05-15 20:50:20 +0000397
Alexander Aring5a504392014-10-25 17:16:34 +0200398void ieee802154_unregister_hw(struct ieee802154_hw *hw)
alex.bluesman.smirnov@gmail.com1010f542012-05-15 20:50:20 +0000399{
Alexander Aring60741362014-10-25 17:16:39 +0200400 struct ieee802154_local *local = hw_to_local(hw);
Alexander Aring036562f2014-10-25 17:16:36 +0200401 struct ieee802154_sub_if_data *sdata, *next;
alex.bluesman.smirnov@gmail.com1010f542012-05-15 20:50:20 +0000402
Alexander Aringc5c47e62014-10-27 17:13:30 +0100403 tasklet_kill(&local->tasklet);
Alexander Aringf7730542014-10-25 17:16:41 +0200404 flush_workqueue(local->workqueue);
405 destroy_workqueue(local->workqueue);
alex.bluesman.smirnov@gmail.com1010f542012-05-15 20:50:20 +0000406
407 rtnl_lock();
408
Alexander Aringd98be452014-10-25 17:16:38 +0200409 mutex_lock(&local->iflist_mtx);
Alexander Aringa5e1ec52014-10-25 17:16:35 +0200410 local->running = MAC802154_DEVICE_STOPPED;
Alexander Aringd98be452014-10-25 17:16:38 +0200411 mutex_unlock(&local->iflist_mtx);
alex.bluesman.smirnov@gmail.com1010f542012-05-15 20:50:20 +0000412
Alexander Aringd98be452014-10-25 17:16:38 +0200413 list_for_each_entry_safe(sdata, next, &local->interfaces, list) {
414 mutex_lock(&sdata->local->iflist_mtx);
alex.bluesman.smirnov@gmail.com62610ad2012-05-15 20:50:28 +0000415 list_del(&sdata->list);
Alexander Aringd98be452014-10-25 17:16:38 +0200416 mutex_unlock(&sdata->local->iflist_mtx);
alex.bluesman.smirnov@gmail.com62610ad2012-05-15 20:50:28 +0000417
418 unregister_netdevice(sdata->dev);
419 }
420
alex.bluesman.smirnov@gmail.com1010f542012-05-15 20:50:20 +0000421 rtnl_unlock();
422
Alexander Aringa5e1ec52014-10-25 17:16:35 +0200423 wpan_phy_unregister(local->phy);
alex.bluesman.smirnov@gmail.com1010f542012-05-15 20:50:20 +0000424}
Alexander Aring5a504392014-10-25 17:16:34 +0200425EXPORT_SYMBOL(ieee802154_unregister_hw);
alex.bluesman.smirnov@gmail.com1010f542012-05-15 20:50:20 +0000426
427MODULE_DESCRIPTION("IEEE 802.15.4 implementation");
428MODULE_LICENSE("GPL v2");