diff options
author | alex.bluesman.smirnov@gmail.com <alex.bluesman.smirnov@gmail.com> | 2012-05-15 16:50:22 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-05-16 15:16:49 -0400 |
commit | 5b641ebeec348761c9ebac9454c672d4d2d3ef91 (patch) | |
tree | 75cec47761ebbc97e0f35ac5c2a1a97eb332425b /net | |
parent | 1cd829c83eab8b899b85d597c767fcf8b4cf8fd6 (diff) |
mac802154: TX data path
Main TX data path implementation between upper and physical layers.
Signed-off-by: Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/mac802154/Makefile | 2 | ||||
-rw-r--r-- | net/mac802154/mac802154.h | 5 | ||||
-rw-r--r-- | net/mac802154/tx.c | 116 |
3 files changed, 122 insertions, 1 deletions
diff --git a/net/mac802154/Makefile b/net/mac802154/Makefile index e00fe474dce4..490beef7176e 100644 --- a/net/mac802154/Makefile +++ b/net/mac802154/Makefile | |||
@@ -1,2 +1,2 @@ | |||
1 | obj-$(CONFIG_MAC802154) += mac802154.o | 1 | obj-$(CONFIG_MAC802154) += mac802154.o |
2 | mac802154-objs := ieee802154_dev.o rx.o | 2 | mac802154-objs := ieee802154_dev.o rx.o tx.o |
diff --git a/net/mac802154/mac802154.h b/net/mac802154/mac802154.h index 980d0a24040e..4f2d97506c6a 100644 --- a/net/mac802154/mac802154.h +++ b/net/mac802154/mac802154.h | |||
@@ -60,4 +60,9 @@ struct mac802154_priv { | |||
60 | 60 | ||
61 | #define mac802154_to_priv(_hw) container_of(_hw, struct mac802154_priv, hw) | 61 | #define mac802154_to_priv(_hw) container_of(_hw, struct mac802154_priv, hw) |
62 | 62 | ||
63 | #define MAC802154_MAX_XMIT_ATTEMPTS 3 | ||
64 | |||
65 | netdev_tx_t mac802154_tx(struct mac802154_priv *priv, struct sk_buff *skb, | ||
66 | u8 page, u8 chan); | ||
67 | |||
63 | #endif /* MAC802154_H */ | 68 | #endif /* MAC802154_H */ |
diff --git a/net/mac802154/tx.c b/net/mac802154/tx.c new file mode 100644 index 000000000000..8781d8f904d9 --- /dev/null +++ b/net/mac802154/tx.c | |||
@@ -0,0 +1,116 @@ | |||
1 | /* | ||
2 | * Copyright 2007-2012 Siemens AG | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 | ||
6 | * as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License along | ||
14 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
15 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
16 | * | ||
17 | * Written by: | ||
18 | * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> | ||
19 | * Sergey Lapin <slapin@ossfans.org> | ||
20 | * Maxim Gorbachyov <maxim.gorbachev@siemens.com> | ||
21 | * Alexander Smirnov <alex.bluesman.smirnov@gmail.com> | ||
22 | */ | ||
23 | |||
24 | #include <linux/netdevice.h> | ||
25 | #include <linux/if_arp.h> | ||
26 | #include <linux/crc-ccitt.h> | ||
27 | |||
28 | #include <net/mac802154.h> | ||
29 | #include <net/wpan-phy.h> | ||
30 | |||
31 | #include "mac802154.h" | ||
32 | |||
33 | /* IEEE 802.15.4 transceivers can sleep during the xmit session, so process | ||
34 | * packets through the workqueue. | ||
35 | */ | ||
36 | struct xmit_work { | ||
37 | struct sk_buff *skb; | ||
38 | struct work_struct work; | ||
39 | struct mac802154_priv *priv; | ||
40 | u8 chan; | ||
41 | u8 page; | ||
42 | u8 xmit_attempts; | ||
43 | }; | ||
44 | |||
45 | static void mac802154_xmit_worker(struct work_struct *work) | ||
46 | { | ||
47 | struct xmit_work *xw = container_of(work, struct xmit_work, work); | ||
48 | int res; | ||
49 | |||
50 | mutex_lock(&xw->priv->phy->pib_lock); | ||
51 | if (xw->priv->phy->current_channel != xw->chan || | ||
52 | xw->priv->phy->current_page != xw->page) { | ||
53 | res = xw->priv->ops->set_channel(&xw->priv->hw, | ||
54 | xw->page, | ||
55 | xw->chan); | ||
56 | if (res) { | ||
57 | pr_debug("set_channel failed\n"); | ||
58 | goto out; | ||
59 | } | ||
60 | } | ||
61 | |||
62 | res = xw->priv->ops->xmit(&xw->priv->hw, xw->skb); | ||
63 | |||
64 | out: | ||
65 | mutex_unlock(&xw->priv->phy->pib_lock); | ||
66 | |||
67 | if (res) { | ||
68 | if (xw->xmit_attempts++ < MAC802154_MAX_XMIT_ATTEMPTS) { | ||
69 | queue_work(xw->priv->dev_workqueue, &xw->work); | ||
70 | return; | ||
71 | } else | ||
72 | pr_debug("transmission failed for %d times", | ||
73 | MAC802154_MAX_XMIT_ATTEMPTS); | ||
74 | } | ||
75 | |||
76 | dev_kfree_skb(xw->skb); | ||
77 | |||
78 | kfree(xw); | ||
79 | } | ||
80 | |||
81 | netdev_tx_t mac802154_tx(struct mac802154_priv *priv, struct sk_buff *skb, | ||
82 | u8 page, u8 chan) | ||
83 | { | ||
84 | struct xmit_work *work; | ||
85 | |||
86 | if (!(priv->phy->channels_supported[page] & (1 << chan))) | ||
87 | WARN_ON(1); | ||
88 | return NETDEV_TX_OK; | ||
89 | |||
90 | if (!(priv->hw.flags & IEEE802154_HW_OMIT_CKSUM)) { | ||
91 | u16 crc = crc_ccitt(0, skb->data, skb->len); | ||
92 | u8 *data = skb_put(skb, 2); | ||
93 | data[0] = crc & 0xff; | ||
94 | data[1] = crc >> 8; | ||
95 | } | ||
96 | |||
97 | if (skb_cow_head(skb, priv->hw.extra_tx_headroom)) { | ||
98 | dev_kfree_skb(skb); | ||
99 | return NETDEV_TX_OK; | ||
100 | } | ||
101 | |||
102 | work = kzalloc(sizeof(struct xmit_work), GFP_ATOMIC); | ||
103 | if (!work) | ||
104 | return NETDEV_TX_BUSY; | ||
105 | |||
106 | INIT_WORK(&work->work, mac802154_xmit_worker); | ||
107 | work->skb = skb; | ||
108 | work->priv = priv; | ||
109 | work->page = page; | ||
110 | work->chan = chan; | ||
111 | work->xmit_attempts = 0; | ||
112 | |||
113 | queue_work(priv->dev_workqueue, &work->work); | ||
114 | |||
115 | return NETDEV_TX_OK; | ||
116 | } | ||