11802d0beSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
262eb01f5SAlexander Aring /*
362eb01f5SAlexander Aring * Copyright (C) 2007-2012 Siemens AG
462eb01f5SAlexander Aring *
562eb01f5SAlexander Aring * Written by:
662eb01f5SAlexander Aring * Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
762eb01f5SAlexander Aring */
862eb01f5SAlexander Aring
962eb01f5SAlexander Aring #include <linux/kernel.h>
1062eb01f5SAlexander Aring #include <linux/module.h>
1162eb01f5SAlexander Aring #include <linux/netdevice.h>
1262eb01f5SAlexander Aring
1362eb01f5SAlexander Aring #include <net/netlink.h>
14944742a3SAlexander Aring #include <net/nl802154.h>
1562eb01f5SAlexander Aring #include <net/mac802154.h>
1662eb01f5SAlexander Aring #include <net/ieee802154_netdev.h>
1762eb01f5SAlexander Aring #include <net/route.h>
185ad60d36SAlexander Aring #include <net/cfg802154.h>
1962eb01f5SAlexander Aring
200f1556bcSAlexander Aring #include "ieee802154_i.h"
211201cd22SAlexander Aring #include "cfg.h"
2262eb01f5SAlexander Aring
ieee802154_tasklet_handler(struct tasklet_struct * t)23b5bd8b62SAllen Pais static void ieee802154_tasklet_handler(struct tasklet_struct *t)
24c5c47e67SAlexander Aring {
25b5bd8b62SAllen Pais struct ieee802154_local *local = from_tasklet(local, t, tasklet);
26c5c47e67SAlexander Aring struct sk_buff *skb;
27c5c47e67SAlexander Aring
28c5c47e67SAlexander Aring while ((skb = skb_dequeue(&local->skb_queue))) {
29c5c47e67SAlexander Aring switch (skb->pkt_type) {
30c5c47e67SAlexander Aring case IEEE802154_RX_MSG:
31c5c47e67SAlexander Aring /* Clear skb->pkt_type in order to not confuse kernel
32c5c47e67SAlexander Aring * netstack.
33c5c47e67SAlexander Aring */
34c5c47e67SAlexander Aring skb->pkt_type = 0;
35d10270ceSVarka Bhadram ieee802154_rx(local, skb);
36c5c47e67SAlexander Aring break;
37c5c47e67SAlexander Aring default:
38c5c47e67SAlexander Aring WARN(1, "mac802154: Packet is of unknown type %d\n",
39c5c47e67SAlexander Aring skb->pkt_type);
40c5c47e67SAlexander Aring kfree_skb(skb);
41c5c47e67SAlexander Aring break;
42c5c47e67SAlexander Aring }
43c5c47e67SAlexander Aring }
44c5c47e67SAlexander Aring }
45c5c47e67SAlexander Aring
465a504397SAlexander Aring struct ieee802154_hw *
ieee802154_alloc_hw(size_t priv_data_len,const struct ieee802154_ops * ops)4716301861SAlexander Aring ieee802154_alloc_hw(size_t priv_data_len, const struct ieee802154_ops *ops)
4862eb01f5SAlexander Aring {
4962eb01f5SAlexander Aring struct wpan_phy *phy;
50a5e1ec53SAlexander Aring struct ieee802154_local *local;
5162eb01f5SAlexander Aring size_t priv_size;
5262eb01f5SAlexander Aring
538f451829SVarka Bhadram if (WARN_ON(!ops || !(ops->xmit_async || ops->xmit_sync) || !ops->ed ||
548f451829SVarka Bhadram !ops->start || !ops->stop || !ops->set_channel))
5562eb01f5SAlexander Aring return NULL;
5662eb01f5SAlexander Aring
5762eb01f5SAlexander Aring /* Ensure 32-byte alignment of our private data and hw private data.
58a5e1ec53SAlexander Aring * We use the wpan_phy priv data for both our ieee802154_local and for
5962eb01f5SAlexander Aring * the driver's private data
6062eb01f5SAlexander Aring *
6162eb01f5SAlexander Aring * in memory it'll be like this:
6262eb01f5SAlexander Aring *
63a5e1ec53SAlexander Aring * +-------------------------+
6462eb01f5SAlexander Aring * | struct wpan_phy |
65a5e1ec53SAlexander Aring * +-------------------------+
66a5e1ec53SAlexander Aring * | struct ieee802154_local |
67a5e1ec53SAlexander Aring * +-------------------------+
6862eb01f5SAlexander Aring * | driver's private data |
69a5e1ec53SAlexander Aring * +-------------------------+
7062eb01f5SAlexander Aring *
7162eb01f5SAlexander Aring * Due to ieee802154 layer isn't aware of driver and MAC structures,
7262eb01f5SAlexander Aring * so lets align them here.
7362eb01f5SAlexander Aring */
7462eb01f5SAlexander Aring
75a5e1ec53SAlexander Aring priv_size = ALIGN(sizeof(*local), NETDEV_ALIGN) + priv_data_len;
7662eb01f5SAlexander Aring
77f601379fSAlexander Aring phy = wpan_phy_new(&mac802154_config_ops, priv_size);
7862eb01f5SAlexander Aring if (!phy) {
7962eb01f5SAlexander Aring pr_err("failure to allocate master IEEE802.15.4 device\n");
8062eb01f5SAlexander Aring return NULL;
8162eb01f5SAlexander Aring }
8262eb01f5SAlexander Aring
836322d50dSAlexander Aring phy->privid = mac802154_wpan_phy_privid;
846322d50dSAlexander Aring
85a5e1ec53SAlexander Aring local = wpan_phy_priv(phy);
86a5e1ec53SAlexander Aring local->phy = phy;
87a5e1ec53SAlexander Aring local->hw.phy = local->phy;
88a5e1ec53SAlexander Aring local->hw.priv = (char *)local + ALIGN(sizeof(*local), NETDEV_ALIGN);
89a5e1ec53SAlexander Aring local->ops = ops;
9062eb01f5SAlexander Aring
91d98be45bSAlexander Aring INIT_LIST_HEAD(&local->interfaces);
9257588c71SMiquel Raynal INIT_LIST_HEAD(&local->rx_beacon_list);
93d021d218SMiquel Raynal INIT_LIST_HEAD(&local->rx_mac_cmd_list);
94d98be45bSAlexander Aring mutex_init(&local->iflist_mtx);
9562eb01f5SAlexander Aring
96b5bd8b62SAllen Pais tasklet_setup(&local->tasklet, ieee802154_tasklet_handler);
97c5c47e67SAlexander Aring
98c5c47e67SAlexander Aring skb_queue_head_init(&local->skb_queue);
99c5c47e67SAlexander Aring
100983a974bSMiquel Raynal INIT_WORK(&local->sync_tx_work, ieee802154_xmit_sync_worker);
10157588c71SMiquel Raynal INIT_DELAYED_WORK(&local->scan_work, mac802154_scan_worker);
10257588c71SMiquel Raynal INIT_WORK(&local->rx_beacon_work, mac802154_rx_beacon_worker);
1033accf476SMiquel Raynal INIT_DELAYED_WORK(&local->beacon_work, mac802154_beacon_worker);
104d021d218SMiquel Raynal INIT_WORK(&local->rx_mac_cmd_work, mac802154_rx_mac_cmd_worker);
105c22ff7b4SLennert Buytenhek
106fea3318dSAlexander Aring /* init supported flags with 802.15.4 default ranges */
107fea3318dSAlexander Aring phy->supported.max_minbe = 8;
108fea3318dSAlexander Aring phy->supported.min_maxbe = 3;
109fea3318dSAlexander Aring phy->supported.max_maxbe = 8;
11089c7d788SAlexander Aring phy->supported.min_frame_retries = 0;
111fea3318dSAlexander Aring phy->supported.max_frame_retries = 7;
112fea3318dSAlexander Aring phy->supported.max_csma_backoffs = 5;
113fea3318dSAlexander Aring phy->supported.lbt = NL802154_SUPPORTED_BOOL_FALSE;
114fea3318dSAlexander Aring
11565318680SAlexander Aring /* always supported */
1162622e785SMiquel Raynal phy->supported.iftypes = BIT(NL802154_IFTYPE_NODE) | BIT(NL802154_IFTYPE_COORD);
11765318680SAlexander Aring
118a5e1ec53SAlexander Aring return &local->hw;
11962eb01f5SAlexander Aring }
1205a504397SAlexander Aring EXPORT_SYMBOL(ieee802154_alloc_hw);
12162eb01f5SAlexander Aring
ieee802154_configure_durations(struct wpan_phy * phy,unsigned int page,unsigned int channel)1225755cd4dSMiquel Raynal void ieee802154_configure_durations(struct wpan_phy *phy,
1235755cd4dSMiquel Raynal unsigned int page, unsigned int channel)
124781830c8SMiquel Raynal {
125781830c8SMiquel Raynal u32 duration = 0;
126781830c8SMiquel Raynal
1275755cd4dSMiquel Raynal switch (page) {
128781830c8SMiquel Raynal case 0:
1295755cd4dSMiquel Raynal if (BIT(channel) & 0x1)
130781830c8SMiquel Raynal /* 868 MHz BPSK 802.15.4-2003: 20 ksym/s */
131781830c8SMiquel Raynal duration = 50 * NSEC_PER_USEC;
1325755cd4dSMiquel Raynal else if (BIT(channel) & 0x7FE)
133781830c8SMiquel Raynal /* 915 MHz BPSK 802.15.4-2003: 40 ksym/s */
134781830c8SMiquel Raynal duration = 25 * NSEC_PER_USEC;
1355755cd4dSMiquel Raynal else if (BIT(channel) & 0x7FFF800)
136781830c8SMiquel Raynal /* 2400 MHz O-QPSK 802.15.4-2006: 62.5 ksym/s */
137781830c8SMiquel Raynal duration = 16 * NSEC_PER_USEC;
138781830c8SMiquel Raynal break;
139781830c8SMiquel Raynal case 2:
1405755cd4dSMiquel Raynal if (BIT(channel) & 0x1)
141781830c8SMiquel Raynal /* 868 MHz O-QPSK 802.15.4-2006: 25 ksym/s */
142781830c8SMiquel Raynal duration = 40 * NSEC_PER_USEC;
1435755cd4dSMiquel Raynal else if (BIT(channel) & 0x7FE)
144781830c8SMiquel Raynal /* 915 MHz O-QPSK 802.15.4-2006: 62.5 ksym/s */
145781830c8SMiquel Raynal duration = 16 * NSEC_PER_USEC;
146781830c8SMiquel Raynal break;
147781830c8SMiquel Raynal case 3:
1485755cd4dSMiquel Raynal if (BIT(channel) & 0x3FFF)
149781830c8SMiquel Raynal /* 2.4 GHz CSS 802.15.4a-2007: 1/6 Msym/s */
150781830c8SMiquel Raynal duration = 6 * NSEC_PER_USEC;
151781830c8SMiquel Raynal break;
152781830c8SMiquel Raynal default:
153781830c8SMiquel Raynal break;
154781830c8SMiquel Raynal }
155781830c8SMiquel Raynal
156781830c8SMiquel Raynal if (!duration) {
157781830c8SMiquel Raynal pr_debug("Unknown PHY symbol duration\n");
158781830c8SMiquel Raynal return;
159781830c8SMiquel Raynal }
160781830c8SMiquel Raynal
161781830c8SMiquel Raynal phy->symbol_duration = duration;
162*61707579SDmitry Antipov phy->lifs_period =
163*61707579SDmitry Antipov (IEEE802154_LIFS_PERIOD * phy->symbol_duration) / NSEC_PER_USEC;
164*61707579SDmitry Antipov phy->sifs_period =
165*61707579SDmitry Antipov (IEEE802154_SIFS_PERIOD * phy->symbol_duration) / NSEC_PER_USEC;
166781830c8SMiquel Raynal }
167781830c8SMiquel Raynal EXPORT_SYMBOL(ieee802154_configure_durations);
168781830c8SMiquel Raynal
ieee802154_free_hw(struct ieee802154_hw * hw)1695a504397SAlexander Aring void ieee802154_free_hw(struct ieee802154_hw *hw)
17062eb01f5SAlexander Aring {
17160741361SAlexander Aring struct ieee802154_local *local = hw_to_local(hw);
17262eb01f5SAlexander Aring
173d98be45bSAlexander Aring BUG_ON(!list_empty(&local->interfaces));
17462eb01f5SAlexander Aring
175d98be45bSAlexander Aring mutex_destroy(&local->iflist_mtx);
17662eb01f5SAlexander Aring
177a5e1ec53SAlexander Aring wpan_phy_free(local->phy);
17862eb01f5SAlexander Aring }
1795a504397SAlexander Aring EXPORT_SYMBOL(ieee802154_free_hw);
18062eb01f5SAlexander Aring
ieee802154_setup_wpan_phy_pib(struct wpan_phy * wpan_phy)18161f2dcbaSAlexander Aring static void ieee802154_setup_wpan_phy_pib(struct wpan_phy *wpan_phy)
18261f2dcbaSAlexander Aring {
18361f2dcbaSAlexander Aring /* TODO warn on empty symbol_duration
18461f2dcbaSAlexander Aring * Should be done when all drivers sets this value.
18561f2dcbaSAlexander Aring */
18661f2dcbaSAlexander Aring
187*61707579SDmitry Antipov wpan_phy->lifs_period = (IEEE802154_LIFS_PERIOD *
188*61707579SDmitry Antipov wpan_phy->symbol_duration) / NSEC_PER_USEC;
189*61707579SDmitry Antipov wpan_phy->sifs_period = (IEEE802154_SIFS_PERIOD *
190*61707579SDmitry Antipov wpan_phy->symbol_duration) / NSEC_PER_USEC;
19161f2dcbaSAlexander Aring }
19261f2dcbaSAlexander Aring
ieee802154_register_hw(struct ieee802154_hw * hw)1935a504397SAlexander Aring int ieee802154_register_hw(struct ieee802154_hw *hw)
19462eb01f5SAlexander Aring {
19560741361SAlexander Aring struct ieee802154_local *local = hw_to_local(hw);
19657588c71SMiquel Raynal char mac_wq_name[IFNAMSIZ + 10] = {};
197e4962a14SAlexander Aring struct net_device *dev;
19862eb01f5SAlexander Aring int rc = -ENOSYS;
19962eb01f5SAlexander Aring
200f7730542SAlexander Aring local->workqueue =
201a5e1ec53SAlexander Aring create_singlethread_workqueue(wpan_phy_name(local->phy));
202f7730542SAlexander Aring if (!local->workqueue) {
20362eb01f5SAlexander Aring rc = -ENOMEM;
20462eb01f5SAlexander Aring goto out;
20562eb01f5SAlexander Aring }
20662eb01f5SAlexander Aring
20757588c71SMiquel Raynal snprintf(mac_wq_name, IFNAMSIZ + 10, "%s-mac-cmds", wpan_phy_name(local->phy));
20857588c71SMiquel Raynal local->mac_wq = create_singlethread_workqueue(mac_wq_name);
20957588c71SMiquel Raynal if (!local->mac_wq) {
21057588c71SMiquel Raynal rc = -ENOMEM;
21157588c71SMiquel Raynal goto out_wq;
21257588c71SMiquel Raynal }
21357588c71SMiquel Raynal
21461f2dcbaSAlexander Aring hrtimer_init(&local->ifs_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
21561f2dcbaSAlexander Aring local->ifs_timer.function = ieee802154_xmit_ifs_timer;
21661f2dcbaSAlexander Aring
217a5e1ec53SAlexander Aring wpan_phy_set_dev(local->phy, local->hw.parent);
21862eb01f5SAlexander Aring
21961f2dcbaSAlexander Aring ieee802154_setup_wpan_phy_pib(local->phy);
22061f2dcbaSAlexander Aring
2215755cd4dSMiquel Raynal ieee802154_configure_durations(local->phy, local->phy->current_page,
2225755cd4dSMiquel Raynal local->phy->current_channel);
223781830c8SMiquel Raynal
224fea3318dSAlexander Aring if (!(hw->flags & IEEE802154_HW_CSMA_PARAMS)) {
225fea3318dSAlexander Aring local->phy->supported.min_csma_backoffs = 4;
226fea3318dSAlexander Aring local->phy->supported.max_csma_backoffs = 4;
227fea3318dSAlexander Aring local->phy->supported.min_maxbe = 5;
228fea3318dSAlexander Aring local->phy->supported.max_maxbe = 5;
229fea3318dSAlexander Aring local->phy->supported.min_minbe = 3;
230fea3318dSAlexander Aring local->phy->supported.max_minbe = 3;
231fea3318dSAlexander Aring }
232fea3318dSAlexander Aring
233fea3318dSAlexander Aring if (!(hw->flags & IEEE802154_HW_FRAME_RETRIES)) {
23489c7d788SAlexander Aring local->phy->supported.min_frame_retries = 3;
23589c7d788SAlexander Aring local->phy->supported.max_frame_retries = 3;
236fea3318dSAlexander Aring }
237fea3318dSAlexander Aring
23865318680SAlexander Aring if (hw->flags & IEEE802154_HW_PROMISCUOUS)
23965318680SAlexander Aring local->phy->supported.iftypes |= BIT(NL802154_IFTYPE_MONITOR);
24065318680SAlexander Aring
241a5e1ec53SAlexander Aring rc = wpan_phy_register(local->phy);
24262eb01f5SAlexander Aring if (rc < 0)
24357588c71SMiquel Raynal goto out_mac_wq;
24462eb01f5SAlexander Aring
245e4962a14SAlexander Aring rtnl_lock();
246e4962a14SAlexander Aring
2475b4a1039SVarka Bhadram dev = ieee802154_if_add(local, "wpan%d", NET_NAME_ENUM,
2485b4a1039SVarka Bhadram NL802154_IFTYPE_NODE,
2490e57547eSAlexander Aring cpu_to_le64(0x0000000000000000ULL));
250e4962a14SAlexander Aring if (IS_ERR(dev)) {
251e4962a14SAlexander Aring rtnl_unlock();
252e4962a14SAlexander Aring rc = PTR_ERR(dev);
2532b4d413cSAlexander Aring goto out_phy;
254e4962a14SAlexander Aring }
255e4962a14SAlexander Aring
256e4962a14SAlexander Aring rtnl_unlock();
257e4962a14SAlexander Aring
25862eb01f5SAlexander Aring return 0;
25962eb01f5SAlexander Aring
2602b4d413cSAlexander Aring out_phy:
2612b4d413cSAlexander Aring wpan_phy_unregister(local->phy);
26257588c71SMiquel Raynal out_mac_wq:
26357588c71SMiquel Raynal destroy_workqueue(local->mac_wq);
26462eb01f5SAlexander Aring out_wq:
265f7730542SAlexander Aring destroy_workqueue(local->workqueue);
26662eb01f5SAlexander Aring out:
26762eb01f5SAlexander Aring return rc;
26862eb01f5SAlexander Aring }
2695a504397SAlexander Aring EXPORT_SYMBOL(ieee802154_register_hw);
27062eb01f5SAlexander Aring
ieee802154_unregister_hw(struct ieee802154_hw * hw)2715a504397SAlexander Aring void ieee802154_unregister_hw(struct ieee802154_hw *hw)
27262eb01f5SAlexander Aring {
27360741361SAlexander Aring struct ieee802154_local *local = hw_to_local(hw);
27462eb01f5SAlexander Aring
275c5c47e67SAlexander Aring tasklet_kill(&local->tasklet);
276f7730542SAlexander Aring flush_workqueue(local->workqueue);
27762eb01f5SAlexander Aring
27862eb01f5SAlexander Aring rtnl_lock();
27962eb01f5SAlexander Aring
280592dfbfcSAlexander Aring ieee802154_remove_interfaces(local);
28162eb01f5SAlexander Aring
28262eb01f5SAlexander Aring rtnl_unlock();
28362eb01f5SAlexander Aring
28457588c71SMiquel Raynal destroy_workqueue(local->mac_wq);
285aef00c15SKoen Zandberg destroy_workqueue(local->workqueue);
286a5e1ec53SAlexander Aring wpan_phy_unregister(local->phy);
28762eb01f5SAlexander Aring }
2885a504397SAlexander Aring EXPORT_SYMBOL(ieee802154_unregister_hw);
28962eb01f5SAlexander Aring
ieee802154_init(void)290be4fd8e5SAlexander Aring static int __init ieee802154_init(void)
291be4fd8e5SAlexander Aring {
292be4fd8e5SAlexander Aring return ieee802154_iface_init();
293be4fd8e5SAlexander Aring }
294be4fd8e5SAlexander Aring
ieee802154_exit(void)295be4fd8e5SAlexander Aring static void __exit ieee802154_exit(void)
296be4fd8e5SAlexander Aring {
297be4fd8e5SAlexander Aring ieee802154_iface_exit();
298be4fd8e5SAlexander Aring
299be4fd8e5SAlexander Aring rcu_barrier();
300be4fd8e5SAlexander Aring }
301be4fd8e5SAlexander Aring
302be4fd8e5SAlexander Aring subsys_initcall(ieee802154_init);
303be4fd8e5SAlexander Aring module_exit(ieee802154_exit);
304be4fd8e5SAlexander Aring
305912f67aeSAlexander Aring MODULE_DESCRIPTION("IEEE 802.15.4 subsystem");
30662eb01f5SAlexander Aring MODULE_LICENSE("GPL v2");
307