1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2d3466830SKalle Valo /*
3d3466830SKalle Valo * Common code for mac80211 Prism54 drivers
4d3466830SKalle Valo *
5d3466830SKalle Valo * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
6d3466830SKalle Valo * Copyright (c) 2007-2009, Christian Lamparter <chunkeey@web.de>
7d3466830SKalle Valo * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
8d3466830SKalle Valo *
9d3466830SKalle Valo * Based on:
10d3466830SKalle Valo * - the islsm (softmac prism54) driver, which is:
11d3466830SKalle Valo * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
12d3466830SKalle Valo * - stlc45xx driver
13d3466830SKalle Valo * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
14d3466830SKalle Valo */
15d3466830SKalle Valo
16d3466830SKalle Valo #include <linux/export.h>
17d3466830SKalle Valo #include <linux/firmware.h>
18d3466830SKalle Valo #include <linux/etherdevice.h>
19d3466830SKalle Valo #include <asm/div64.h>
20d3466830SKalle Valo
21d3466830SKalle Valo #include <net/mac80211.h>
22d3466830SKalle Valo
23d3466830SKalle Valo #include "p54.h"
24d3466830SKalle Valo #include "lmac.h"
25d3466830SKalle Valo
26d3466830SKalle Valo #ifdef P54_MM_DEBUG
p54_dump_tx_queue(struct p54_common * priv)27d3466830SKalle Valo static void p54_dump_tx_queue(struct p54_common *priv)
28d3466830SKalle Valo {
29d3466830SKalle Valo unsigned long flags;
30d3466830SKalle Valo struct ieee80211_tx_info *info;
31d3466830SKalle Valo struct p54_tx_info *range;
32d3466830SKalle Valo struct sk_buff *skb;
33d3466830SKalle Valo struct p54_hdr *hdr;
34d3466830SKalle Valo unsigned int i = 0;
35d3466830SKalle Valo u32 prev_addr;
36d3466830SKalle Valo u32 largest_hole = 0, free;
37d3466830SKalle Valo
38d3466830SKalle Valo spin_lock_irqsave(&priv->tx_queue.lock, flags);
39d3466830SKalle Valo wiphy_debug(priv->hw->wiphy, "/ --- tx queue dump (%d entries) ---\n",
40d3466830SKalle Valo skb_queue_len(&priv->tx_queue));
41d3466830SKalle Valo
42d3466830SKalle Valo prev_addr = priv->rx_start;
43d3466830SKalle Valo skb_queue_walk(&priv->tx_queue, skb) {
44d3466830SKalle Valo info = IEEE80211_SKB_CB(skb);
45d3466830SKalle Valo range = (void *) info->rate_driver_data;
46d3466830SKalle Valo hdr = (void *) skb->data;
47d3466830SKalle Valo
48d3466830SKalle Valo free = range->start_addr - prev_addr;
49d3466830SKalle Valo wiphy_debug(priv->hw->wiphy,
50d3466830SKalle Valo "| [%02d] => [skb:%p skb_len:0x%04x "
51d3466830SKalle Valo "hdr:{flags:%02x len:%04x req_id:%04x type:%02x} "
52d3466830SKalle Valo "mem:{start:%04x end:%04x, free:%d}]\n",
53d3466830SKalle Valo i++, skb, skb->len,
54d3466830SKalle Valo le16_to_cpu(hdr->flags), le16_to_cpu(hdr->len),
55d3466830SKalle Valo le32_to_cpu(hdr->req_id), le16_to_cpu(hdr->type),
56d3466830SKalle Valo range->start_addr, range->end_addr, free);
57d3466830SKalle Valo
58d3466830SKalle Valo prev_addr = range->end_addr;
59d3466830SKalle Valo largest_hole = max(largest_hole, free);
60d3466830SKalle Valo }
61d3466830SKalle Valo free = priv->rx_end - prev_addr;
62d3466830SKalle Valo largest_hole = max(largest_hole, free);
63d3466830SKalle Valo wiphy_debug(priv->hw->wiphy,
64d3466830SKalle Valo "\\ --- [free: %d], largest free block: %d ---\n",
65d3466830SKalle Valo free, largest_hole);
66d3466830SKalle Valo spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
67d3466830SKalle Valo }
68d3466830SKalle Valo #endif /* P54_MM_DEBUG */
69d3466830SKalle Valo
70d3466830SKalle Valo /*
71d3466830SKalle Valo * So, the firmware is somewhat stupid and doesn't know what places in its
72d3466830SKalle Valo * memory incoming data should go to. By poking around in the firmware, we
73d3466830SKalle Valo * can find some unused memory to upload our packets to. However, data that we
74d3466830SKalle Valo * want the card to TX needs to stay intact until the card has told us that
75d3466830SKalle Valo * it is done with it. This function finds empty places we can upload to and
76d3466830SKalle Valo * marks allocated areas as reserved if necessary. p54_find_and_unlink_skb or
77d3466830SKalle Valo * p54_free_skb frees allocated areas.
78d3466830SKalle Valo */
p54_assign_address(struct p54_common * priv,struct sk_buff * skb)79d3466830SKalle Valo static int p54_assign_address(struct p54_common *priv, struct sk_buff *skb)
80d3466830SKalle Valo {
81d3466830SKalle Valo struct sk_buff *entry, *target_skb = NULL;
82d3466830SKalle Valo struct ieee80211_tx_info *info;
83d3466830SKalle Valo struct p54_tx_info *range;
84d3466830SKalle Valo struct p54_hdr *data = (void *) skb->data;
85d3466830SKalle Valo unsigned long flags;
86d3466830SKalle Valo u32 last_addr = priv->rx_start;
87d3466830SKalle Valo u32 target_addr = priv->rx_start;
88d3466830SKalle Valo u16 len = priv->headroom + skb->len + priv->tailroom + 3;
89d3466830SKalle Valo
90d3466830SKalle Valo info = IEEE80211_SKB_CB(skb);
91d3466830SKalle Valo range = (void *) info->rate_driver_data;
92d3466830SKalle Valo len = (range->extra_len + len) & ~0x3;
93d3466830SKalle Valo
94d3466830SKalle Valo spin_lock_irqsave(&priv->tx_queue.lock, flags);
95d3466830SKalle Valo if (unlikely(skb_queue_len(&priv->tx_queue) == 32)) {
96d3466830SKalle Valo /*
97d3466830SKalle Valo * The tx_queue is now really full.
98d3466830SKalle Valo *
99d3466830SKalle Valo * TODO: check if the device has crashed and reset it.
100d3466830SKalle Valo */
101d3466830SKalle Valo spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
102d3466830SKalle Valo return -EBUSY;
103d3466830SKalle Valo }
104d3466830SKalle Valo
105d3466830SKalle Valo skb_queue_walk(&priv->tx_queue, entry) {
106d3466830SKalle Valo u32 hole_size;
107d3466830SKalle Valo info = IEEE80211_SKB_CB(entry);
108d3466830SKalle Valo range = (void *) info->rate_driver_data;
109d3466830SKalle Valo hole_size = range->start_addr - last_addr;
110d3466830SKalle Valo
111d3466830SKalle Valo if (!target_skb && hole_size >= len) {
112d3466830SKalle Valo target_skb = entry->prev;
113d3466830SKalle Valo hole_size -= len;
114d3466830SKalle Valo target_addr = last_addr;
115d3466830SKalle Valo break;
116d3466830SKalle Valo }
117d3466830SKalle Valo last_addr = range->end_addr;
118d3466830SKalle Valo }
119d3466830SKalle Valo if (unlikely(!target_skb)) {
120d3466830SKalle Valo if (priv->rx_end - last_addr >= len) {
121e3554197SDavid S. Miller target_skb = skb_peek_tail(&priv->tx_queue);
122e3554197SDavid S. Miller if (target_skb) {
123d3466830SKalle Valo info = IEEE80211_SKB_CB(target_skb);
124d3466830SKalle Valo range = (void *)info->rate_driver_data;
125d3466830SKalle Valo target_addr = range->end_addr;
126d3466830SKalle Valo }
127d3466830SKalle Valo } else {
128d3466830SKalle Valo spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
129d3466830SKalle Valo return -ENOSPC;
130d3466830SKalle Valo }
131d3466830SKalle Valo }
132d3466830SKalle Valo
133d3466830SKalle Valo info = IEEE80211_SKB_CB(skb);
134d3466830SKalle Valo range = (void *) info->rate_driver_data;
135d3466830SKalle Valo range->start_addr = target_addr;
136d3466830SKalle Valo range->end_addr = target_addr + len;
137d3466830SKalle Valo data->req_id = cpu_to_le32(target_addr + priv->headroom);
138d3466830SKalle Valo if (IS_DATA_FRAME(skb) &&
139d3466830SKalle Valo unlikely(GET_HW_QUEUE(skb) == P54_QUEUE_BEACON))
140d3466830SKalle Valo priv->beacon_req_id = data->req_id;
141d3466830SKalle Valo
1421645ab93SChristian Lamparter if (target_skb)
143d3466830SKalle Valo __skb_queue_after(&priv->tx_queue, target_skb, skb);
1441645ab93SChristian Lamparter else
1451645ab93SChristian Lamparter __skb_queue_head(&priv->tx_queue, skb);
146d3466830SKalle Valo spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
147d3466830SKalle Valo return 0;
148d3466830SKalle Valo }
149d3466830SKalle Valo
p54_tx_pending(struct p54_common * priv)150d3466830SKalle Valo static void p54_tx_pending(struct p54_common *priv)
151d3466830SKalle Valo {
152d3466830SKalle Valo struct sk_buff *skb;
153d3466830SKalle Valo int ret;
154d3466830SKalle Valo
155d3466830SKalle Valo skb = skb_dequeue(&priv->tx_pending);
156d3466830SKalle Valo if (unlikely(!skb))
157d3466830SKalle Valo return ;
158d3466830SKalle Valo
159d3466830SKalle Valo ret = p54_assign_address(priv, skb);
160d3466830SKalle Valo if (unlikely(ret))
161d3466830SKalle Valo skb_queue_head(&priv->tx_pending, skb);
162d3466830SKalle Valo else
163d3466830SKalle Valo priv->tx(priv->hw, skb);
164d3466830SKalle Valo }
165d3466830SKalle Valo
p54_wake_queues(struct p54_common * priv)166d3466830SKalle Valo static void p54_wake_queues(struct p54_common *priv)
167d3466830SKalle Valo {
168d3466830SKalle Valo unsigned long flags;
169d3466830SKalle Valo unsigned int i;
170d3466830SKalle Valo
171d3466830SKalle Valo if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED))
172d3466830SKalle Valo return ;
173d3466830SKalle Valo
174d3466830SKalle Valo p54_tx_pending(priv);
175d3466830SKalle Valo
176d3466830SKalle Valo spin_lock_irqsave(&priv->tx_stats_lock, flags);
177d3466830SKalle Valo for (i = 0; i < priv->hw->queues; i++) {
178d3466830SKalle Valo if (priv->tx_stats[i + P54_QUEUE_DATA].len <
179d3466830SKalle Valo priv->tx_stats[i + P54_QUEUE_DATA].limit)
180d3466830SKalle Valo ieee80211_wake_queue(priv->hw, i);
181d3466830SKalle Valo }
182d3466830SKalle Valo spin_unlock_irqrestore(&priv->tx_stats_lock, flags);
183d3466830SKalle Valo }
184d3466830SKalle Valo
p54_tx_qos_accounting_alloc(struct p54_common * priv,struct sk_buff * skb,const u16 p54_queue)185d3466830SKalle Valo static int p54_tx_qos_accounting_alloc(struct p54_common *priv,
186d3466830SKalle Valo struct sk_buff *skb,
187d3466830SKalle Valo const u16 p54_queue)
188d3466830SKalle Valo {
189d3466830SKalle Valo struct p54_tx_queue_stats *queue;
190d3466830SKalle Valo unsigned long flags;
191d3466830SKalle Valo
192d3466830SKalle Valo if (WARN_ON(p54_queue >= P54_QUEUE_NUM))
193d3466830SKalle Valo return -EINVAL;
194d3466830SKalle Valo
195d3466830SKalle Valo queue = &priv->tx_stats[p54_queue];
196d3466830SKalle Valo
197d3466830SKalle Valo spin_lock_irqsave(&priv->tx_stats_lock, flags);
198d3466830SKalle Valo if (unlikely(queue->len >= queue->limit && IS_QOS_QUEUE(p54_queue))) {
199d3466830SKalle Valo spin_unlock_irqrestore(&priv->tx_stats_lock, flags);
200d3466830SKalle Valo return -ENOSPC;
201d3466830SKalle Valo }
202d3466830SKalle Valo
203d3466830SKalle Valo queue->len++;
204d3466830SKalle Valo queue->count++;
205d3466830SKalle Valo
206d3466830SKalle Valo if (unlikely(queue->len == queue->limit && IS_QOS_QUEUE(p54_queue))) {
207d3466830SKalle Valo u16 ac_queue = p54_queue - P54_QUEUE_DATA;
208d3466830SKalle Valo ieee80211_stop_queue(priv->hw, ac_queue);
209d3466830SKalle Valo }
210d3466830SKalle Valo
211d3466830SKalle Valo spin_unlock_irqrestore(&priv->tx_stats_lock, flags);
212d3466830SKalle Valo return 0;
213d3466830SKalle Valo }
214d3466830SKalle Valo
p54_tx_qos_accounting_free(struct p54_common * priv,struct sk_buff * skb)215d3466830SKalle Valo static void p54_tx_qos_accounting_free(struct p54_common *priv,
216d3466830SKalle Valo struct sk_buff *skb)
217d3466830SKalle Valo {
218d3466830SKalle Valo if (IS_DATA_FRAME(skb)) {
219d3466830SKalle Valo unsigned long flags;
220d3466830SKalle Valo
221d3466830SKalle Valo spin_lock_irqsave(&priv->tx_stats_lock, flags);
222d3466830SKalle Valo priv->tx_stats[GET_HW_QUEUE(skb)].len--;
223d3466830SKalle Valo spin_unlock_irqrestore(&priv->tx_stats_lock, flags);
224d3466830SKalle Valo
225d3466830SKalle Valo if (unlikely(GET_HW_QUEUE(skb) == P54_QUEUE_BEACON)) {
226d3466830SKalle Valo if (priv->beacon_req_id == GET_REQ_ID(skb)) {
227d3466830SKalle Valo /* this is the active beacon set anymore */
228d3466830SKalle Valo priv->beacon_req_id = 0;
229d3466830SKalle Valo }
230d3466830SKalle Valo complete(&priv->beacon_comp);
231d3466830SKalle Valo }
232d3466830SKalle Valo }
233d3466830SKalle Valo p54_wake_queues(priv);
234d3466830SKalle Valo }
235d3466830SKalle Valo
p54_free_skb(struct ieee80211_hw * dev,struct sk_buff * skb)236d3466830SKalle Valo void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb)
237d3466830SKalle Valo {
238d3466830SKalle Valo struct p54_common *priv = dev->priv;
239d3466830SKalle Valo if (unlikely(!skb))
240d3466830SKalle Valo return ;
241d3466830SKalle Valo
242d3466830SKalle Valo skb_unlink(skb, &priv->tx_queue);
243d3466830SKalle Valo p54_tx_qos_accounting_free(priv, skb);
244d3466830SKalle Valo ieee80211_free_txskb(dev, skb);
245d3466830SKalle Valo }
246d3466830SKalle Valo EXPORT_SYMBOL_GPL(p54_free_skb);
247d3466830SKalle Valo
p54_find_and_unlink_skb(struct p54_common * priv,const __le32 req_id)248d3466830SKalle Valo static struct sk_buff *p54_find_and_unlink_skb(struct p54_common *priv,
249d3466830SKalle Valo const __le32 req_id)
250d3466830SKalle Valo {
251d3466830SKalle Valo struct sk_buff *entry;
252d3466830SKalle Valo unsigned long flags;
253d3466830SKalle Valo
254d3466830SKalle Valo spin_lock_irqsave(&priv->tx_queue.lock, flags);
255d3466830SKalle Valo skb_queue_walk(&priv->tx_queue, entry) {
256d3466830SKalle Valo struct p54_hdr *hdr = (struct p54_hdr *) entry->data;
257d3466830SKalle Valo
258d3466830SKalle Valo if (hdr->req_id == req_id) {
259d3466830SKalle Valo __skb_unlink(entry, &priv->tx_queue);
260d3466830SKalle Valo spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
261d3466830SKalle Valo p54_tx_qos_accounting_free(priv, entry);
262d3466830SKalle Valo return entry;
263d3466830SKalle Valo }
264d3466830SKalle Valo }
265d3466830SKalle Valo spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
266d3466830SKalle Valo return NULL;
267d3466830SKalle Valo }
268d3466830SKalle Valo
p54_tx(struct p54_common * priv,struct sk_buff * skb)269d3466830SKalle Valo void p54_tx(struct p54_common *priv, struct sk_buff *skb)
270d3466830SKalle Valo {
271d3466830SKalle Valo skb_queue_tail(&priv->tx_pending, skb);
272d3466830SKalle Valo p54_tx_pending(priv);
273d3466830SKalle Valo }
274d3466830SKalle Valo
p54_rssi_to_dbm(struct p54_common * priv,int rssi)275d3466830SKalle Valo static int p54_rssi_to_dbm(struct p54_common *priv, int rssi)
276d3466830SKalle Valo {
277d3466830SKalle Valo if (priv->rxhw != 5) {
278d3466830SKalle Valo return ((rssi * priv->cur_rssi->mul) / 64 +
279d3466830SKalle Valo priv->cur_rssi->add) / 4;
280d3466830SKalle Valo } else {
281d3466830SKalle Valo /*
282d3466830SKalle Valo * TODO: find the correct formula
283d3466830SKalle Valo */
284d3466830SKalle Valo return rssi / 2 - 110;
285d3466830SKalle Valo }
286d3466830SKalle Valo }
287d3466830SKalle Valo
288d3466830SKalle Valo /*
289d3466830SKalle Valo * Even if the firmware is capable of dealing with incoming traffic,
290d3466830SKalle Valo * while dozing, we have to prepared in case mac80211 uses PS-POLL
291d3466830SKalle Valo * to retrieve outstanding frames from our AP.
292d3466830SKalle Valo * (see comment in net/mac80211/mlme.c @ line 1993)
293d3466830SKalle Valo */
p54_pspoll_workaround(struct p54_common * priv,struct sk_buff * skb)294d3466830SKalle Valo static void p54_pspoll_workaround(struct p54_common *priv, struct sk_buff *skb)
295d3466830SKalle Valo {
296d3466830SKalle Valo struct ieee80211_hdr *hdr = (void *) skb->data;
297d3466830SKalle Valo struct ieee80211_tim_ie *tim_ie;
298d3466830SKalle Valo u8 *tim;
299d3466830SKalle Valo u8 tim_len;
300d3466830SKalle Valo bool new_psm;
301d3466830SKalle Valo
302d3466830SKalle Valo /* only beacons have a TIM IE */
303d3466830SKalle Valo if (!ieee80211_is_beacon(hdr->frame_control))
304d3466830SKalle Valo return;
305d3466830SKalle Valo
306d3466830SKalle Valo if (!priv->aid)
307d3466830SKalle Valo return;
308d3466830SKalle Valo
309d3466830SKalle Valo /* only consider beacons from the associated BSSID */
310d3466830SKalle Valo if (!ether_addr_equal_64bits(hdr->addr3, priv->bssid))
311d3466830SKalle Valo return;
312d3466830SKalle Valo
313d3466830SKalle Valo tim = p54_find_ie(skb, WLAN_EID_TIM);
314d3466830SKalle Valo if (!tim)
315d3466830SKalle Valo return;
316d3466830SKalle Valo
317d3466830SKalle Valo tim_len = tim[1];
318d3466830SKalle Valo tim_ie = (struct ieee80211_tim_ie *) &tim[2];
319d3466830SKalle Valo
320d3466830SKalle Valo new_psm = ieee80211_check_tim(tim_ie, tim_len, priv->aid);
321d3466830SKalle Valo if (new_psm != priv->powersave_override) {
322d3466830SKalle Valo priv->powersave_override = new_psm;
323d3466830SKalle Valo p54_set_ps(priv);
324d3466830SKalle Valo }
325d3466830SKalle Valo }
326d3466830SKalle Valo
p54_rx_data(struct p54_common * priv,struct sk_buff * skb)327d3466830SKalle Valo static int p54_rx_data(struct p54_common *priv, struct sk_buff *skb)
328d3466830SKalle Valo {
329d3466830SKalle Valo struct p54_rx_data *hdr = (struct p54_rx_data *) skb->data;
330d3466830SKalle Valo struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb);
331d3466830SKalle Valo u16 freq = le16_to_cpu(hdr->freq);
332d3466830SKalle Valo size_t header_len = sizeof(*hdr);
333d3466830SKalle Valo u32 tsf32;
334c11c75ecSChristian Lamparter __le16 fc;
335d3466830SKalle Valo u8 rate = hdr->rate & 0xf;
336d3466830SKalle Valo
337d3466830SKalle Valo /*
338d3466830SKalle Valo * If the device is in a unspecified state we have to
339d3466830SKalle Valo * ignore all data frames. Else we could end up with a
340d3466830SKalle Valo * nasty crash.
341d3466830SKalle Valo */
342d3466830SKalle Valo if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED))
343d3466830SKalle Valo return 0;
344d3466830SKalle Valo
345d3466830SKalle Valo if (!(hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_IN_FCS_GOOD)))
346d3466830SKalle Valo return 0;
347d3466830SKalle Valo
348d3466830SKalle Valo if (hdr->decrypt_status == P54_DECRYPT_OK)
349d3466830SKalle Valo rx_status->flag |= RX_FLAG_DECRYPTED;
350d3466830SKalle Valo if ((hdr->decrypt_status == P54_DECRYPT_FAIL_MICHAEL) ||
351d3466830SKalle Valo (hdr->decrypt_status == P54_DECRYPT_FAIL_TKIP))
352d3466830SKalle Valo rx_status->flag |= RX_FLAG_MMIC_ERROR;
353d3466830SKalle Valo
354d3466830SKalle Valo rx_status->signal = p54_rssi_to_dbm(priv, hdr->rssi);
355d3466830SKalle Valo if (hdr->rate & 0x10)
3567fdd69c5SJohannes Berg rx_status->enc_flags |= RX_ENC_FLAG_SHORTPRE;
35757fbcce3SJohannes Berg if (priv->hw->conf.chandef.chan->band == NL80211_BAND_5GHZ)
358d3466830SKalle Valo rx_status->rate_idx = (rate < 4) ? 0 : rate - 4;
359d3466830SKalle Valo else
360d3466830SKalle Valo rx_status->rate_idx = rate;
361d3466830SKalle Valo
362d3466830SKalle Valo rx_status->freq = freq;
363d3466830SKalle Valo rx_status->band = priv->hw->conf.chandef.chan->band;
364d3466830SKalle Valo rx_status->antenna = hdr->antenna;
365d3466830SKalle Valo
366d3466830SKalle Valo tsf32 = le32_to_cpu(hdr->tsf32);
367d3466830SKalle Valo if (tsf32 < priv->tsf_low32)
368d3466830SKalle Valo priv->tsf_high32++;
369d3466830SKalle Valo rx_status->mactime = ((u64)priv->tsf_high32) << 32 | tsf32;
370d3466830SKalle Valo priv->tsf_low32 = tsf32;
371d3466830SKalle Valo
372d3466830SKalle Valo /* LMAC API Page 10/29 - s_lm_data_in - clock
373d3466830SKalle Valo * "usec accurate timestamp of hardware clock
374d3466830SKalle Valo * at end of frame (before OFDM SIFS EOF padding"
375d3466830SKalle Valo */
376d3466830SKalle Valo rx_status->flag |= RX_FLAG_MACTIME_END;
377d3466830SKalle Valo
378d3466830SKalle Valo if (hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_ALIGN))
379d3466830SKalle Valo header_len += hdr->align[0];
380d3466830SKalle Valo
381d3466830SKalle Valo skb_pull(skb, header_len);
382d3466830SKalle Valo skb_trim(skb, le16_to_cpu(hdr->len));
383c11c75ecSChristian Lamparter
384c11c75ecSChristian Lamparter fc = ((struct ieee80211_hdr *)skb->data)->frame_control;
385c11c75ecSChristian Lamparter if (ieee80211_is_probe_resp(fc) || ieee80211_is_beacon(fc))
386237f83dfSLinus Torvalds rx_status->boottime_ns = ktime_get_boottime_ns();
387c11c75ecSChristian Lamparter
388d3466830SKalle Valo if (unlikely(priv->hw->conf.flags & IEEE80211_CONF_PS))
389d3466830SKalle Valo p54_pspoll_workaround(priv, skb);
390d3466830SKalle Valo
391d3466830SKalle Valo ieee80211_rx_irqsafe(priv->hw, skb);
392d3466830SKalle Valo
393d3466830SKalle Valo ieee80211_queue_delayed_work(priv->hw, &priv->work,
394d3466830SKalle Valo msecs_to_jiffies(P54_STATISTICS_UPDATE));
395d3466830SKalle Valo
396d3466830SKalle Valo return -1;
397d3466830SKalle Valo }
398d3466830SKalle Valo
p54_rx_frame_sent(struct p54_common * priv,struct sk_buff * skb)399d3466830SKalle Valo static void p54_rx_frame_sent(struct p54_common *priv, struct sk_buff *skb)
400d3466830SKalle Valo {
401d3466830SKalle Valo struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
402d3466830SKalle Valo struct p54_frame_sent *payload = (struct p54_frame_sent *) hdr->data;
403d3466830SKalle Valo struct ieee80211_tx_info *info;
404d3466830SKalle Valo struct p54_hdr *entry_hdr;
405d3466830SKalle Valo struct p54_tx_data *entry_data;
406d3466830SKalle Valo struct sk_buff *entry;
407d3466830SKalle Valo unsigned int pad = 0, frame_len;
408d3466830SKalle Valo int count, idx;
409d3466830SKalle Valo
410d3466830SKalle Valo entry = p54_find_and_unlink_skb(priv, hdr->req_id);
411d3466830SKalle Valo if (unlikely(!entry))
412d3466830SKalle Valo return ;
413d3466830SKalle Valo
414d3466830SKalle Valo frame_len = entry->len;
415d3466830SKalle Valo info = IEEE80211_SKB_CB(entry);
416d3466830SKalle Valo entry_hdr = (struct p54_hdr *) entry->data;
417d3466830SKalle Valo entry_data = (struct p54_tx_data *) entry_hdr->data;
418d3466830SKalle Valo priv->stats.dot11ACKFailureCount += payload->tries - 1;
419d3466830SKalle Valo
420d3466830SKalle Valo /*
421d3466830SKalle Valo * Frames in P54_QUEUE_FWSCAN and P54_QUEUE_BEACON are
422d3466830SKalle Valo * generated by the driver. Therefore tx_status is bogus
423d3466830SKalle Valo * and we don't want to confuse the mac80211 stack.
424d3466830SKalle Valo */
425d3466830SKalle Valo if (unlikely(entry_data->hw_queue < P54_QUEUE_FWSCAN)) {
426d3466830SKalle Valo dev_kfree_skb_any(entry);
427d3466830SKalle Valo return ;
428d3466830SKalle Valo }
429d3466830SKalle Valo
430d3466830SKalle Valo /*
431d3466830SKalle Valo * Clear manually, ieee80211_tx_info_clear_status would
432d3466830SKalle Valo * clear the counts too and we need them.
433d3466830SKalle Valo */
434*fb5f6a0eSKees Cook memset_after(&info->status, 0, rates);
435d3466830SKalle Valo
436d3466830SKalle Valo if (entry_hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_ALIGN))
437d3466830SKalle Valo pad = entry_data->align[0];
438d3466830SKalle Valo
439d3466830SKalle Valo /* walk through the rates array and adjust the counts */
440d3466830SKalle Valo count = payload->tries;
441d3466830SKalle Valo for (idx = 0; idx < 4; idx++) {
442d3466830SKalle Valo if (count >= info->status.rates[idx].count) {
443d3466830SKalle Valo count -= info->status.rates[idx].count;
444d3466830SKalle Valo } else if (count > 0) {
445d3466830SKalle Valo info->status.rates[idx].count = count;
446d3466830SKalle Valo count = 0;
447d3466830SKalle Valo } else {
448d3466830SKalle Valo info->status.rates[idx].idx = -1;
449d3466830SKalle Valo info->status.rates[idx].count = 0;
450d3466830SKalle Valo }
451d3466830SKalle Valo }
452d3466830SKalle Valo
453d3466830SKalle Valo if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) &&
454d3466830SKalle Valo !(payload->status & P54_TX_FAILED))
455d3466830SKalle Valo info->flags |= IEEE80211_TX_STAT_ACK;
456d3466830SKalle Valo if (payload->status & P54_TX_PSM_CANCELLED)
457d3466830SKalle Valo info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
458d3466830SKalle Valo info->status.ack_signal = p54_rssi_to_dbm(priv,
459d3466830SKalle Valo (int)payload->ack_rssi);
460d3466830SKalle Valo
461d3466830SKalle Valo /* Undo all changes to the frame. */
462d3466830SKalle Valo switch (entry_data->key_type) {
463d3466830SKalle Valo case P54_CRYPTO_TKIPMICHAEL: {
464d3466830SKalle Valo u8 *iv = (u8 *)(entry_data->align + pad +
465d3466830SKalle Valo entry_data->crypt_offset);
466d3466830SKalle Valo
467d3466830SKalle Valo /* Restore the original TKIP IV. */
468d3466830SKalle Valo iv[2] = iv[0];
469d3466830SKalle Valo iv[0] = iv[1];
470d3466830SKalle Valo iv[1] = (iv[0] | 0x20) & 0x7f; /* WEPSeed - 8.3.2.2 */
471d3466830SKalle Valo
472d3466830SKalle Valo frame_len -= 12; /* remove TKIP_MMIC + TKIP_ICV */
473d3466830SKalle Valo break;
474d3466830SKalle Valo }
475d3466830SKalle Valo case P54_CRYPTO_AESCCMP:
476d3466830SKalle Valo frame_len -= 8; /* remove CCMP_MIC */
477d3466830SKalle Valo break;
478d3466830SKalle Valo case P54_CRYPTO_WEP:
479d3466830SKalle Valo frame_len -= 4; /* remove WEP_ICV */
480d3466830SKalle Valo break;
481d3466830SKalle Valo }
482d3466830SKalle Valo
483d3466830SKalle Valo skb_trim(entry, frame_len);
484d3466830SKalle Valo skb_pull(entry, sizeof(*hdr) + pad + sizeof(*entry_data));
485d3466830SKalle Valo ieee80211_tx_status_irqsafe(priv->hw, entry);
486d3466830SKalle Valo }
487d3466830SKalle Valo
p54_rx_eeprom_readback(struct p54_common * priv,struct sk_buff * skb)488d3466830SKalle Valo static void p54_rx_eeprom_readback(struct p54_common *priv,
489d3466830SKalle Valo struct sk_buff *skb)
490d3466830SKalle Valo {
491d3466830SKalle Valo struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
492d3466830SKalle Valo struct p54_eeprom_lm86 *eeprom = (struct p54_eeprom_lm86 *) hdr->data;
493d3466830SKalle Valo struct sk_buff *tmp;
494d3466830SKalle Valo
495d3466830SKalle Valo if (!priv->eeprom)
496d3466830SKalle Valo return ;
497d3466830SKalle Valo
498d3466830SKalle Valo if (priv->fw_var >= 0x509) {
499d3466830SKalle Valo memcpy(priv->eeprom, eeprom->v2.data,
500d3466830SKalle Valo le16_to_cpu(eeprom->v2.len));
501d3466830SKalle Valo } else {
502d3466830SKalle Valo memcpy(priv->eeprom, eeprom->v1.data,
503d3466830SKalle Valo le16_to_cpu(eeprom->v1.len));
504d3466830SKalle Valo }
505d3466830SKalle Valo
506d3466830SKalle Valo priv->eeprom = NULL;
507d3466830SKalle Valo tmp = p54_find_and_unlink_skb(priv, hdr->req_id);
508d3466830SKalle Valo dev_kfree_skb_any(tmp);
509d3466830SKalle Valo complete(&priv->eeprom_comp);
510d3466830SKalle Valo }
511d3466830SKalle Valo
p54_rx_stats(struct p54_common * priv,struct sk_buff * skb)512d3466830SKalle Valo static void p54_rx_stats(struct p54_common *priv, struct sk_buff *skb)
513d3466830SKalle Valo {
514d3466830SKalle Valo struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
515d3466830SKalle Valo struct p54_statistics *stats = (struct p54_statistics *) hdr->data;
516d3466830SKalle Valo struct sk_buff *tmp;
517d3466830SKalle Valo struct ieee80211_channel *chan;
518d3466830SKalle Valo unsigned int i, rssi, tx, cca, dtime, dtotal, dcca, dtx, drssi, unit;
519d3466830SKalle Valo u32 tsf32;
520d3466830SKalle Valo
521d3466830SKalle Valo if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED))
522d3466830SKalle Valo return ;
523d3466830SKalle Valo
524d3466830SKalle Valo tsf32 = le32_to_cpu(stats->tsf32);
525d3466830SKalle Valo if (tsf32 < priv->tsf_low32)
526d3466830SKalle Valo priv->tsf_high32++;
527d3466830SKalle Valo priv->tsf_low32 = tsf32;
528d3466830SKalle Valo
529d3466830SKalle Valo priv->stats.dot11RTSFailureCount = le32_to_cpu(stats->rts_fail);
530d3466830SKalle Valo priv->stats.dot11RTSSuccessCount = le32_to_cpu(stats->rts_success);
531d3466830SKalle Valo priv->stats.dot11FCSErrorCount = le32_to_cpu(stats->rx_bad_fcs);
532d3466830SKalle Valo
533d3466830SKalle Valo priv->noise = p54_rssi_to_dbm(priv, le32_to_cpu(stats->noise));
534d3466830SKalle Valo
535d3466830SKalle Valo /*
536d3466830SKalle Valo * STSW450X LMAC API page 26 - 3.8 Statistics
537d3466830SKalle Valo * "The exact measurement period can be derived from the
538d3466830SKalle Valo * timestamp member".
539d3466830SKalle Valo */
540d3466830SKalle Valo dtime = tsf32 - priv->survey_raw.timestamp;
541d3466830SKalle Valo
542d3466830SKalle Valo /*
543d3466830SKalle Valo * STSW450X LMAC API page 26 - 3.8.1 Noise histogram
544d3466830SKalle Valo * The LMAC samples RSSI, CCA and transmit state at regular
545d3466830SKalle Valo * periods (typically 8 times per 1k [as in 1024] usec).
546d3466830SKalle Valo */
547d3466830SKalle Valo cca = le32_to_cpu(stats->sample_cca);
548d3466830SKalle Valo tx = le32_to_cpu(stats->sample_tx);
549d3466830SKalle Valo rssi = 0;
550d3466830SKalle Valo for (i = 0; i < ARRAY_SIZE(stats->sample_noise); i++)
551d3466830SKalle Valo rssi += le32_to_cpu(stats->sample_noise[i]);
552d3466830SKalle Valo
553d3466830SKalle Valo dcca = cca - priv->survey_raw.cached_cca;
554d3466830SKalle Valo drssi = rssi - priv->survey_raw.cached_rssi;
555d3466830SKalle Valo dtx = tx - priv->survey_raw.cached_tx;
556d3466830SKalle Valo dtotal = dcca + drssi + dtx;
557d3466830SKalle Valo
558d3466830SKalle Valo /*
559d3466830SKalle Valo * update statistics when more than a second is over since the
560d3466830SKalle Valo * last call, or when a update is badly needed.
561d3466830SKalle Valo */
562d3466830SKalle Valo if (dtotal && (priv->update_stats || dtime >= USEC_PER_SEC) &&
563d3466830SKalle Valo dtime >= dtotal) {
564d3466830SKalle Valo priv->survey_raw.timestamp = tsf32;
565d3466830SKalle Valo priv->update_stats = false;
566d3466830SKalle Valo unit = dtime / dtotal;
567d3466830SKalle Valo
568d3466830SKalle Valo if (dcca) {
569d3466830SKalle Valo priv->survey_raw.cca += dcca * unit;
570d3466830SKalle Valo priv->survey_raw.cached_cca = cca;
571d3466830SKalle Valo }
572d3466830SKalle Valo if (dtx) {
573d3466830SKalle Valo priv->survey_raw.tx += dtx * unit;
574d3466830SKalle Valo priv->survey_raw.cached_tx = tx;
575d3466830SKalle Valo }
576d3466830SKalle Valo if (drssi) {
577d3466830SKalle Valo priv->survey_raw.rssi += drssi * unit;
578d3466830SKalle Valo priv->survey_raw.cached_rssi = rssi;
579d3466830SKalle Valo }
580d3466830SKalle Valo
581d3466830SKalle Valo /* 1024 usec / 8 times = 128 usec / time */
582d3466830SKalle Valo if (!(priv->phy_ps || priv->phy_idle))
583d3466830SKalle Valo priv->survey_raw.active += dtotal * unit;
584d3466830SKalle Valo else
585d3466830SKalle Valo priv->survey_raw.active += (dcca + dtx) * unit;
586d3466830SKalle Valo }
587d3466830SKalle Valo
588d3466830SKalle Valo chan = priv->curchan;
589d3466830SKalle Valo if (chan) {
590d3466830SKalle Valo struct survey_info *survey = &priv->survey[chan->hw_value];
591d3466830SKalle Valo survey->noise = clamp(priv->noise, -128, 127);
592d3466830SKalle Valo survey->time = priv->survey_raw.active;
593d3466830SKalle Valo survey->time_tx = priv->survey_raw.tx;
594d3466830SKalle Valo survey->time_busy = priv->survey_raw.tx +
595d3466830SKalle Valo priv->survey_raw.cca;
596d3466830SKalle Valo do_div(survey->time, 1024);
597d3466830SKalle Valo do_div(survey->time_tx, 1024);
598d3466830SKalle Valo do_div(survey->time_busy, 1024);
599d3466830SKalle Valo }
600d3466830SKalle Valo
601d3466830SKalle Valo tmp = p54_find_and_unlink_skb(priv, hdr->req_id);
602d3466830SKalle Valo dev_kfree_skb_any(tmp);
603d3466830SKalle Valo complete(&priv->stat_comp);
604d3466830SKalle Valo }
605d3466830SKalle Valo
p54_rx_trap(struct p54_common * priv,struct sk_buff * skb)606d3466830SKalle Valo static void p54_rx_trap(struct p54_common *priv, struct sk_buff *skb)
607d3466830SKalle Valo {
608d3466830SKalle Valo struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
609d3466830SKalle Valo struct p54_trap *trap = (struct p54_trap *) hdr->data;
610d3466830SKalle Valo u16 event = le16_to_cpu(trap->event);
611d3466830SKalle Valo u16 freq = le16_to_cpu(trap->frequency);
612d3466830SKalle Valo
613d3466830SKalle Valo switch (event) {
614d3466830SKalle Valo case P54_TRAP_BEACON_TX:
615d3466830SKalle Valo break;
616d3466830SKalle Valo case P54_TRAP_RADAR:
617d3466830SKalle Valo wiphy_info(priv->hw->wiphy, "radar (freq:%d MHz)\n", freq);
618d3466830SKalle Valo break;
619d3466830SKalle Valo case P54_TRAP_NO_BEACON:
620d3466830SKalle Valo if (priv->vif)
621d3466830SKalle Valo ieee80211_beacon_loss(priv->vif);
622d3466830SKalle Valo break;
623d3466830SKalle Valo case P54_TRAP_SCAN:
624d3466830SKalle Valo break;
625d3466830SKalle Valo case P54_TRAP_TBTT:
626d3466830SKalle Valo break;
627d3466830SKalle Valo case P54_TRAP_TIMER:
628d3466830SKalle Valo break;
629d3466830SKalle Valo case P54_TRAP_FAA_RADIO_OFF:
630d3466830SKalle Valo wiphy_rfkill_set_hw_state(priv->hw->wiphy, true);
631d3466830SKalle Valo break;
632d3466830SKalle Valo case P54_TRAP_FAA_RADIO_ON:
633d3466830SKalle Valo wiphy_rfkill_set_hw_state(priv->hw->wiphy, false);
634d3466830SKalle Valo break;
635d3466830SKalle Valo default:
636d3466830SKalle Valo wiphy_info(priv->hw->wiphy, "received event:%x freq:%d\n",
637d3466830SKalle Valo event, freq);
638d3466830SKalle Valo break;
639d3466830SKalle Valo }
640d3466830SKalle Valo }
641d3466830SKalle Valo
p54_rx_control(struct p54_common * priv,struct sk_buff * skb)642d3466830SKalle Valo static int p54_rx_control(struct p54_common *priv, struct sk_buff *skb)
643d3466830SKalle Valo {
644d3466830SKalle Valo struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
645d3466830SKalle Valo
646d3466830SKalle Valo switch (le16_to_cpu(hdr->type)) {
647d3466830SKalle Valo case P54_CONTROL_TYPE_TXDONE:
648d3466830SKalle Valo p54_rx_frame_sent(priv, skb);
649d3466830SKalle Valo break;
650d3466830SKalle Valo case P54_CONTROL_TYPE_TRAP:
651d3466830SKalle Valo p54_rx_trap(priv, skb);
652d3466830SKalle Valo break;
653d3466830SKalle Valo case P54_CONTROL_TYPE_BBP:
654d3466830SKalle Valo break;
655d3466830SKalle Valo case P54_CONTROL_TYPE_STAT_READBACK:
656d3466830SKalle Valo p54_rx_stats(priv, skb);
657d3466830SKalle Valo break;
658d3466830SKalle Valo case P54_CONTROL_TYPE_EEPROM_READBACK:
659d3466830SKalle Valo p54_rx_eeprom_readback(priv, skb);
660d3466830SKalle Valo break;
661d3466830SKalle Valo default:
662d3466830SKalle Valo wiphy_debug(priv->hw->wiphy,
663d3466830SKalle Valo "not handling 0x%02x type control frame\n",
664d3466830SKalle Valo le16_to_cpu(hdr->type));
665d3466830SKalle Valo break;
666d3466830SKalle Valo }
667d3466830SKalle Valo return 0;
668d3466830SKalle Valo }
669d3466830SKalle Valo
670d3466830SKalle Valo /* returns zero if skb can be reused */
p54_rx(struct ieee80211_hw * dev,struct sk_buff * skb)671d3466830SKalle Valo int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb)
672d3466830SKalle Valo {
673d3466830SKalle Valo struct p54_common *priv = dev->priv;
674d3466830SKalle Valo u16 type = le16_to_cpu(*((__le16 *)skb->data));
675d3466830SKalle Valo
676d3466830SKalle Valo if (type & P54_HDR_FLAG_CONTROL)
677d3466830SKalle Valo return p54_rx_control(priv, skb);
678d3466830SKalle Valo else
679d3466830SKalle Valo return p54_rx_data(priv, skb);
680d3466830SKalle Valo }
681d3466830SKalle Valo EXPORT_SYMBOL_GPL(p54_rx);
682d3466830SKalle Valo
p54_tx_80211_header(struct p54_common * priv,struct sk_buff * skb,struct ieee80211_tx_info * info,struct ieee80211_sta * sta,u8 * queue,u32 * extra_len,u16 * flags,u16 * aid,bool * burst_possible)683d3466830SKalle Valo static void p54_tx_80211_header(struct p54_common *priv, struct sk_buff *skb,
684d3466830SKalle Valo struct ieee80211_tx_info *info,
685d3466830SKalle Valo struct ieee80211_sta *sta,
686d3466830SKalle Valo u8 *queue, u32 *extra_len, u16 *flags, u16 *aid,
687d3466830SKalle Valo bool *burst_possible)
688d3466830SKalle Valo {
689d3466830SKalle Valo struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
690d3466830SKalle Valo
691d3466830SKalle Valo if (ieee80211_is_data_qos(hdr->frame_control))
692d3466830SKalle Valo *burst_possible = true;
693d3466830SKalle Valo else
694d3466830SKalle Valo *burst_possible = false;
695d3466830SKalle Valo
696d3466830SKalle Valo if (!(info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ))
697d3466830SKalle Valo *flags |= P54_HDR_FLAG_DATA_OUT_SEQNR;
698d3466830SKalle Valo
699d3466830SKalle Valo if (info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER)
700d3466830SKalle Valo *flags |= P54_HDR_FLAG_DATA_OUT_NOCANCEL;
701d3466830SKalle Valo
702d3466830SKalle Valo if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT)
703d3466830SKalle Valo *flags |= P54_HDR_FLAG_DATA_OUT_NOCANCEL;
704d3466830SKalle Valo
705d3466830SKalle Valo *queue = skb_get_queue_mapping(skb) + P54_QUEUE_DATA;
706d3466830SKalle Valo
707d3466830SKalle Valo switch (priv->mode) {
708d3466830SKalle Valo case NL80211_IFTYPE_MONITOR:
709d3466830SKalle Valo /*
710d3466830SKalle Valo * We have to set P54_HDR_FLAG_DATA_OUT_PROMISC for
711d3466830SKalle Valo * every frame in promiscuous/monitor mode.
712d3466830SKalle Valo * see STSW45x0C LMAC API - page 12.
713d3466830SKalle Valo */
714d3466830SKalle Valo *aid = 0;
715d3466830SKalle Valo *flags |= P54_HDR_FLAG_DATA_OUT_PROMISC;
716d3466830SKalle Valo break;
717d3466830SKalle Valo case NL80211_IFTYPE_STATION:
718d3466830SKalle Valo *aid = 1;
719d3466830SKalle Valo break;
720d3466830SKalle Valo case NL80211_IFTYPE_AP:
721d3466830SKalle Valo case NL80211_IFTYPE_ADHOC:
722d3466830SKalle Valo case NL80211_IFTYPE_MESH_POINT:
723d3466830SKalle Valo if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) {
724d3466830SKalle Valo *aid = 0;
725d3466830SKalle Valo *queue = P54_QUEUE_CAB;
726d3466830SKalle Valo return;
727d3466830SKalle Valo }
728d3466830SKalle Valo
729d3466830SKalle Valo if (unlikely(ieee80211_is_mgmt(hdr->frame_control))) {
730d3466830SKalle Valo if (ieee80211_is_probe_resp(hdr->frame_control)) {
731d3466830SKalle Valo *aid = 0;
732d3466830SKalle Valo *flags |= P54_HDR_FLAG_DATA_OUT_TIMESTAMP |
733d3466830SKalle Valo P54_HDR_FLAG_DATA_OUT_NOCANCEL;
734d3466830SKalle Valo return;
735d3466830SKalle Valo } else if (ieee80211_is_beacon(hdr->frame_control)) {
736d3466830SKalle Valo *aid = 0;
737d3466830SKalle Valo
738d3466830SKalle Valo if (info->flags & IEEE80211_TX_CTL_INJECTED) {
739d3466830SKalle Valo /*
740d3466830SKalle Valo * Injecting beacons on top of a AP is
741d3466830SKalle Valo * not a good idea... nevertheless,
742d3466830SKalle Valo * it should be doable.
743d3466830SKalle Valo */
744d3466830SKalle Valo
745d3466830SKalle Valo return;
746d3466830SKalle Valo }
747d3466830SKalle Valo
748d3466830SKalle Valo *flags |= P54_HDR_FLAG_DATA_OUT_TIMESTAMP;
749d3466830SKalle Valo *queue = P54_QUEUE_BEACON;
750d3466830SKalle Valo *extra_len = IEEE80211_MAX_TIM_LEN;
751d3466830SKalle Valo return;
752d3466830SKalle Valo }
753d3466830SKalle Valo }
754d3466830SKalle Valo
755d3466830SKalle Valo if (sta)
756d3466830SKalle Valo *aid = sta->aid;
757d3466830SKalle Valo break;
758d3466830SKalle Valo }
759d3466830SKalle Valo }
760d3466830SKalle Valo
p54_convert_algo(u32 cipher)761d3466830SKalle Valo static u8 p54_convert_algo(u32 cipher)
762d3466830SKalle Valo {
763d3466830SKalle Valo switch (cipher) {
764d3466830SKalle Valo case WLAN_CIPHER_SUITE_WEP40:
765d3466830SKalle Valo case WLAN_CIPHER_SUITE_WEP104:
766d3466830SKalle Valo return P54_CRYPTO_WEP;
767d3466830SKalle Valo case WLAN_CIPHER_SUITE_TKIP:
768d3466830SKalle Valo return P54_CRYPTO_TKIPMICHAEL;
769d3466830SKalle Valo case WLAN_CIPHER_SUITE_CCMP:
770d3466830SKalle Valo return P54_CRYPTO_AESCCMP;
771d3466830SKalle Valo default:
772d3466830SKalle Valo return 0;
773d3466830SKalle Valo }
774d3466830SKalle Valo }
775d3466830SKalle Valo
p54_tx_80211(struct ieee80211_hw * dev,struct ieee80211_tx_control * control,struct sk_buff * skb)776d3466830SKalle Valo void p54_tx_80211(struct ieee80211_hw *dev,
777d3466830SKalle Valo struct ieee80211_tx_control *control,
778d3466830SKalle Valo struct sk_buff *skb)
779d3466830SKalle Valo {
780d3466830SKalle Valo struct p54_common *priv = dev->priv;
781d3466830SKalle Valo struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
782d3466830SKalle Valo struct p54_tx_info *p54info;
783d3466830SKalle Valo struct p54_hdr *hdr;
784d3466830SKalle Valo struct p54_tx_data *txhdr;
785d3466830SKalle Valo unsigned int padding, len, extra_len = 0;
786d3466830SKalle Valo int i, j, ridx;
787d3466830SKalle Valo u16 hdr_flags = 0, aid = 0;
788d3466830SKalle Valo u8 rate, queue = 0, crypt_offset = 0;
789d3466830SKalle Valo u8 cts_rate = 0x20;
790d3466830SKalle Valo u8 rc_flags;
791d3466830SKalle Valo u8 calculated_tries[4];
792d3466830SKalle Valo u8 nrates = 0, nremaining = 8;
793d3466830SKalle Valo bool burst_allowed = false;
794d3466830SKalle Valo
795d3466830SKalle Valo p54_tx_80211_header(priv, skb, info, control->sta, &queue, &extra_len,
796d3466830SKalle Valo &hdr_flags, &aid, &burst_allowed);
797d3466830SKalle Valo
798d3466830SKalle Valo if (p54_tx_qos_accounting_alloc(priv, skb, queue)) {
799d3466830SKalle Valo ieee80211_free_txskb(dev, skb);
800d3466830SKalle Valo return;
801d3466830SKalle Valo }
802d3466830SKalle Valo
803d3466830SKalle Valo padding = (unsigned long)(skb->data - (sizeof(*hdr) + sizeof(*txhdr))) & 3;
804d3466830SKalle Valo len = skb->len;
805d3466830SKalle Valo
806d3466830SKalle Valo if (info->control.hw_key) {
807d3466830SKalle Valo crypt_offset = ieee80211_get_hdrlen_from_skb(skb);
808d3466830SKalle Valo if (info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) {
809d3466830SKalle Valo u8 *iv = (u8 *)(skb->data + crypt_offset);
810d3466830SKalle Valo /*
811d3466830SKalle Valo * The firmware excepts that the IV has to have
812d3466830SKalle Valo * this special format
813d3466830SKalle Valo */
814d3466830SKalle Valo iv[1] = iv[0];
815d3466830SKalle Valo iv[0] = iv[2];
816d3466830SKalle Valo iv[2] = 0;
817d3466830SKalle Valo }
818d3466830SKalle Valo }
819d3466830SKalle Valo
820d58ff351SJohannes Berg txhdr = skb_push(skb, sizeof(*txhdr) + padding);
821d58ff351SJohannes Berg hdr = skb_push(skb, sizeof(*hdr));
822d3466830SKalle Valo
823d3466830SKalle Valo if (padding)
824d3466830SKalle Valo hdr_flags |= P54_HDR_FLAG_DATA_ALIGN;
825d3466830SKalle Valo hdr->type = cpu_to_le16(aid);
826d3466830SKalle Valo hdr->rts_tries = info->control.rates[0].count;
827d3466830SKalle Valo
828d3466830SKalle Valo /*
829d3466830SKalle Valo * we register the rates in perfect order, and
830d3466830SKalle Valo * RTS/CTS won't happen on 5 GHz
831d3466830SKalle Valo */
832d3466830SKalle Valo cts_rate = info->control.rts_cts_rate_idx;
833d3466830SKalle Valo
834d3466830SKalle Valo memset(&txhdr->rateset, 0, sizeof(txhdr->rateset));
835d3466830SKalle Valo
836d3466830SKalle Valo /* see how many rates got used */
837d3466830SKalle Valo for (i = 0; i < dev->max_rates; i++) {
838d3466830SKalle Valo if (info->control.rates[i].idx < 0)
839d3466830SKalle Valo break;
840d3466830SKalle Valo nrates++;
841d3466830SKalle Valo }
842d3466830SKalle Valo
843d3466830SKalle Valo /* limit tries to 8/nrates per rate */
844d3466830SKalle Valo for (i = 0; i < nrates; i++) {
845d3466830SKalle Valo /*
846d3466830SKalle Valo * The magic expression here is equivalent to 8/nrates for
847d3466830SKalle Valo * all values that matter, but avoids division and jumps.
848d3466830SKalle Valo * Note that nrates can only take the values 1 through 4.
849d3466830SKalle Valo */
850d3466830SKalle Valo calculated_tries[i] = min_t(int, ((15 >> nrates) | 1) + 1,
851d3466830SKalle Valo info->control.rates[i].count);
852d3466830SKalle Valo nremaining -= calculated_tries[i];
853d3466830SKalle Valo }
854d3466830SKalle Valo
855d3466830SKalle Valo /* if there are tries left, distribute from back to front */
856d3466830SKalle Valo for (i = nrates - 1; nremaining > 0 && i >= 0; i--) {
857d3466830SKalle Valo int tmp = info->control.rates[i].count - calculated_tries[i];
858d3466830SKalle Valo
859d3466830SKalle Valo if (tmp <= 0)
860d3466830SKalle Valo continue;
861d3466830SKalle Valo /* RC requested more tries at this rate */
862d3466830SKalle Valo
863d3466830SKalle Valo tmp = min_t(int, tmp, nremaining);
864d3466830SKalle Valo calculated_tries[i] += tmp;
865d3466830SKalle Valo nremaining -= tmp;
866d3466830SKalle Valo }
867d3466830SKalle Valo
868d3466830SKalle Valo ridx = 0;
869d3466830SKalle Valo for (i = 0; i < nrates && ridx < 8; i++) {
870d3466830SKalle Valo /* we register the rates in perfect order */
871d3466830SKalle Valo rate = info->control.rates[i].idx;
87257fbcce3SJohannes Berg if (info->band == NL80211_BAND_5GHZ)
873d3466830SKalle Valo rate += 4;
874d3466830SKalle Valo
875d3466830SKalle Valo /* store the count we actually calculated for TX status */
876d3466830SKalle Valo info->control.rates[i].count = calculated_tries[i];
877d3466830SKalle Valo
878d3466830SKalle Valo rc_flags = info->control.rates[i].flags;
879d3466830SKalle Valo if (rc_flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) {
880d3466830SKalle Valo rate |= 0x10;
881d3466830SKalle Valo cts_rate |= 0x10;
882d3466830SKalle Valo }
883d3466830SKalle Valo if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) {
884d3466830SKalle Valo burst_allowed = false;
885d3466830SKalle Valo rate |= 0x40;
886d3466830SKalle Valo } else if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
887d3466830SKalle Valo rate |= 0x20;
888d3466830SKalle Valo burst_allowed = false;
889d3466830SKalle Valo }
890d3466830SKalle Valo for (j = 0; j < calculated_tries[i] && ridx < 8; j++) {
891d3466830SKalle Valo txhdr->rateset[ridx] = rate;
892d3466830SKalle Valo ridx++;
893d3466830SKalle Valo }
894d3466830SKalle Valo }
895d3466830SKalle Valo
896d3466830SKalle Valo if (burst_allowed)
897d3466830SKalle Valo hdr_flags |= P54_HDR_FLAG_DATA_OUT_BURST;
898d3466830SKalle Valo
899d3466830SKalle Valo /* TODO: enable bursting */
900d3466830SKalle Valo hdr->flags = cpu_to_le16(hdr_flags);
901d3466830SKalle Valo hdr->tries = ridx;
902d3466830SKalle Valo txhdr->rts_rate_idx = 0;
903d3466830SKalle Valo if (info->control.hw_key) {
904d3466830SKalle Valo txhdr->key_type = p54_convert_algo(info->control.hw_key->cipher);
905d3466830SKalle Valo txhdr->key_len = min((u8)16, info->control.hw_key->keylen);
906d3466830SKalle Valo memcpy(txhdr->key, info->control.hw_key->key, txhdr->key_len);
907d3466830SKalle Valo if (info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) {
908d3466830SKalle Valo /* reserve space for the MIC key */
909d3466830SKalle Valo len += 8;
91059ae1d12SJohannes Berg skb_put_data(skb,
91159ae1d12SJohannes Berg &(info->control.hw_key->key[NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY]),
91259ae1d12SJohannes Berg 8);
913d3466830SKalle Valo }
914d3466830SKalle Valo /* reserve some space for ICV */
915d3466830SKalle Valo len += info->control.hw_key->icv_len;
916b080db58SJohannes Berg skb_put_zero(skb, info->control.hw_key->icv_len);
917d3466830SKalle Valo } else {
918d3466830SKalle Valo txhdr->key_type = 0;
919d3466830SKalle Valo txhdr->key_len = 0;
920d3466830SKalle Valo }
921d3466830SKalle Valo txhdr->crypt_offset = crypt_offset;
922d3466830SKalle Valo txhdr->hw_queue = queue;
923d3466830SKalle Valo txhdr->backlog = priv->tx_stats[queue].len - 1;
924d3466830SKalle Valo memset(txhdr->durations, 0, sizeof(txhdr->durations));
925d3466830SKalle Valo txhdr->tx_antenna = 2 & priv->tx_diversity_mask;
926d3466830SKalle Valo if (priv->rxhw == 5) {
927d3466830SKalle Valo txhdr->longbow.cts_rate = cts_rate;
928d3466830SKalle Valo txhdr->longbow.output_power = cpu_to_le16(priv->output_power);
929d3466830SKalle Valo } else {
930d3466830SKalle Valo txhdr->normal.output_power = priv->output_power;
931d3466830SKalle Valo txhdr->normal.cts_rate = cts_rate;
932d3466830SKalle Valo }
933d3466830SKalle Valo if (padding)
934d3466830SKalle Valo txhdr->align[0] = padding;
935d3466830SKalle Valo
936d3466830SKalle Valo hdr->len = cpu_to_le16(len);
937d3466830SKalle Valo /* modifies skb->cb and with it info, so must be last! */
938d3466830SKalle Valo p54info = (void *) info->rate_driver_data;
939d3466830SKalle Valo p54info->extra_len = extra_len;
940d3466830SKalle Valo
941d3466830SKalle Valo p54_tx(priv, skb);
942d3466830SKalle Valo }
943