diff options
Diffstat (limited to 'drivers/net/wireless/mwifiex/txrx.c')
-rw-r--r-- | drivers/net/wireless/mwifiex/txrx.c | 202 |
1 files changed, 202 insertions, 0 deletions
diff --git a/drivers/net/wireless/mwifiex/txrx.c b/drivers/net/wireless/mwifiex/txrx.c new file mode 100644 index 000000000000..aaa50c074196 --- /dev/null +++ b/drivers/net/wireless/mwifiex/txrx.c | |||
@@ -0,0 +1,202 @@ | |||
1 | /* | ||
2 | * Marvell Wireless LAN device driver: generic TX/RX data handling | ||
3 | * | ||
4 | * Copyright (C) 2011, Marvell International Ltd. | ||
5 | * | ||
6 | * This software file (the "File") is distributed by Marvell International | ||
7 | * Ltd. under the terms of the GNU General Public License Version 2, June 1991 | ||
8 | * (the "License"). You may use, redistribute and/or modify this File in | ||
9 | * accordance with the terms and conditions of the License, a copy of which | ||
10 | * is available by writing to the Free Software Foundation, Inc., | ||
11 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the | ||
12 | * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. | ||
13 | * | ||
14 | * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE | ||
15 | * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE | ||
16 | * ARE EXPRESSLY DISCLAIMED. The License provides additional details about | ||
17 | * this warranty disclaimer. | ||
18 | */ | ||
19 | |||
20 | #include "decl.h" | ||
21 | #include "ioctl.h" | ||
22 | #include "util.h" | ||
23 | #include "fw.h" | ||
24 | #include "main.h" | ||
25 | #include "wmm.h" | ||
26 | |||
27 | /* | ||
28 | * This function processes the received buffer. | ||
29 | * | ||
30 | * Main responsibility of this function is to parse the RxPD to | ||
31 | * identify the correct interface this packet is headed for and | ||
32 | * forwarding it to the associated handling function, where the | ||
33 | * packet will be further processed and sent to kernel/upper layer | ||
34 | * if required. | ||
35 | */ | ||
36 | int mwifiex_handle_rx_packet(struct mwifiex_adapter *adapter, | ||
37 | struct sk_buff *skb) | ||
38 | { | ||
39 | struct mwifiex_private *priv = | ||
40 | mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); | ||
41 | struct rxpd *local_rx_pd; | ||
42 | struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb); | ||
43 | |||
44 | local_rx_pd = (struct rxpd *) (skb->data); | ||
45 | /* Get the BSS number from rxpd, get corresponding priv */ | ||
46 | priv = mwifiex_get_priv_by_id(adapter, local_rx_pd->bss_num & | ||
47 | BSS_NUM_MASK, local_rx_pd->bss_type); | ||
48 | if (!priv) | ||
49 | priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); | ||
50 | |||
51 | rx_info->bss_index = priv->bss_index; | ||
52 | |||
53 | return mwifiex_process_sta_rx_packet(adapter, skb); | ||
54 | } | ||
55 | EXPORT_SYMBOL_GPL(mwifiex_handle_rx_packet); | ||
56 | |||
57 | /* | ||
58 | * This function sends a packet to device. | ||
59 | * | ||
60 | * It processes the packet to add the TxPD, checks condition and | ||
61 | * sends the processed packet to firmware for transmission. | ||
62 | * | ||
63 | * On successful completion, the function calls the completion callback | ||
64 | * and logs the time. | ||
65 | */ | ||
66 | int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb, | ||
67 | struct mwifiex_tx_param *tx_param) | ||
68 | { | ||
69 | int ret = -1; | ||
70 | struct mwifiex_adapter *adapter = priv->adapter; | ||
71 | u8 *head_ptr; | ||
72 | struct txpd *local_tx_pd = NULL; | ||
73 | |||
74 | head_ptr = (u8 *) mwifiex_process_sta_txpd(priv, skb); | ||
75 | if (head_ptr) { | ||
76 | if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) | ||
77 | local_tx_pd = | ||
78 | (struct txpd *) (head_ptr + INTF_HEADER_LEN); | ||
79 | |||
80 | ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA, | ||
81 | skb->data, skb->len, tx_param); | ||
82 | } | ||
83 | |||
84 | switch (ret) { | ||
85 | case -EBUSY: | ||
86 | if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) && | ||
87 | (adapter->pps_uapsd_mode) && | ||
88 | (adapter->tx_lock_flag)) { | ||
89 | priv->adapter->tx_lock_flag = false; | ||
90 | local_tx_pd->flags = 0; | ||
91 | } | ||
92 | dev_dbg(adapter->dev, "data: -EBUSY is returned\n"); | ||
93 | break; | ||
94 | case -1: | ||
95 | adapter->data_sent = false; | ||
96 | dev_err(adapter->dev, "mwifiex_write_data_async failed: 0x%X\n", | ||
97 | ret); | ||
98 | adapter->dbg.num_tx_host_to_card_failure++; | ||
99 | mwifiex_write_data_complete(adapter, skb, ret); | ||
100 | break; | ||
101 | case -EINPROGRESS: | ||
102 | adapter->data_sent = false; | ||
103 | break; | ||
104 | case 0: | ||
105 | mwifiex_write_data_complete(adapter, skb, ret); | ||
106 | break; | ||
107 | default: | ||
108 | break; | ||
109 | } | ||
110 | |||
111 | return ret; | ||
112 | } | ||
113 | |||
114 | /* | ||
115 | * Packet send completion callback handler. | ||
116 | * | ||
117 | * It either frees the buffer directly or forwards it to another | ||
118 | * completion callback which checks conditions, updates statistics, | ||
119 | * wakes up stalled traffic queue if required, and then frees the buffer. | ||
120 | */ | ||
121 | int mwifiex_write_data_complete(struct mwifiex_adapter *adapter, | ||
122 | struct sk_buff *skb, int status) | ||
123 | { | ||
124 | struct mwifiex_private *priv, *tpriv; | ||
125 | struct mwifiex_txinfo *tx_info; | ||
126 | int i; | ||
127 | |||
128 | if (!skb) | ||
129 | return 0; | ||
130 | |||
131 | tx_info = MWIFIEX_SKB_TXCB(skb); | ||
132 | priv = mwifiex_bss_index_to_priv(adapter, tx_info->bss_index); | ||
133 | if (!priv) | ||
134 | goto done; | ||
135 | |||
136 | priv->netdev->trans_start = jiffies; | ||
137 | if (!status) { | ||
138 | priv->stats.tx_packets++; | ||
139 | priv->stats.tx_bytes += skb->len; | ||
140 | } else { | ||
141 | priv->stats.tx_errors++; | ||
142 | } | ||
143 | |||
144 | if (atomic_dec_return(&adapter->tx_pending) >= LOW_TX_PENDING) | ||
145 | goto done; | ||
146 | |||
147 | for (i = 0; i < adapter->priv_num; i++) { | ||
148 | |||
149 | tpriv = adapter->priv[i]; | ||
150 | |||
151 | if ((GET_BSS_ROLE(tpriv) == MWIFIEX_BSS_ROLE_STA) | ||
152 | && (tpriv->media_connected)) { | ||
153 | if (netif_queue_stopped(tpriv->netdev)) | ||
154 | netif_wake_queue(tpriv->netdev); | ||
155 | } | ||
156 | } | ||
157 | done: | ||
158 | dev_kfree_skb_any(skb); | ||
159 | |||
160 | return 0; | ||
161 | } | ||
162 | |||
163 | /* | ||
164 | * Packet receive completion callback handler. | ||
165 | * | ||
166 | * This function calls another completion callback handler which | ||
167 | * updates the statistics, and optionally updates the parent buffer | ||
168 | * use count before freeing the received packet. | ||
169 | */ | ||
170 | int mwifiex_recv_packet_complete(struct mwifiex_adapter *adapter, | ||
171 | struct sk_buff *skb, int status) | ||
172 | { | ||
173 | struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb); | ||
174 | struct mwifiex_rxinfo *rx_info_parent; | ||
175 | struct mwifiex_private *priv; | ||
176 | struct sk_buff *skb_parent; | ||
177 | unsigned long flags; | ||
178 | |||
179 | priv = adapter->priv[rx_info->bss_index]; | ||
180 | |||
181 | if (priv && (status == -1)) | ||
182 | priv->stats.rx_dropped++; | ||
183 | |||
184 | if (rx_info->parent) { | ||
185 | skb_parent = rx_info->parent; | ||
186 | rx_info_parent = MWIFIEX_SKB_RXCB(skb_parent); | ||
187 | |||
188 | spin_lock_irqsave(&priv->rx_pkt_lock, flags); | ||
189 | --rx_info_parent->use_count; | ||
190 | |||
191 | if (!rx_info_parent->use_count) { | ||
192 | spin_unlock_irqrestore(&priv->rx_pkt_lock, flags); | ||
193 | dev_kfree_skb_any(skb_parent); | ||
194 | } else { | ||
195 | spin_unlock_irqrestore(&priv->rx_pkt_lock, flags); | ||
196 | } | ||
197 | } else { | ||
198 | dev_kfree_skb_any(skb); | ||
199 | } | ||
200 | |||
201 | return 0; | ||
202 | } | ||