| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 1 | /* | 
|  | 2 | * This file is part of wl1271 | 
|  | 3 | * | 
|  | 4 | * Copyright (C) 2009 Nokia Corporation | 
|  | 5 | * | 
|  | 6 | * Contact: Luciano Coelho <luciano.coelho@nokia.com> | 
|  | 7 | * | 
|  | 8 | * This program is free software; you can redistribute it and/or | 
|  | 9 | * modify it under the terms of the GNU General Public License | 
|  | 10 | * version 2 as published by the Free Software Foundation. | 
|  | 11 | * | 
|  | 12 | * This program is distributed in the hope that it will be useful, but | 
|  | 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
|  | 15 | * General Public License for more details. | 
|  | 16 | * | 
|  | 17 | * You should have received a copy of the GNU General Public License | 
|  | 18 | * along with this program; if not, write to the Free Software | 
|  | 19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | 
|  | 20 | * 02110-1301 USA | 
|  | 21 | * | 
|  | 22 | */ | 
|  | 23 |  | 
| Tejun Heo | 5a0e3ad | 2010-03-24 17:04:11 +0900 | [diff] [blame] | 24 | #include <linux/gfp.h> | 
| Ido Yariv | 95dac04f | 2011-06-06 14:57:06 +0300 | [diff] [blame] | 25 | #include <linux/sched.h> | 
| Tejun Heo | 5a0e3ad | 2010-03-24 17:04:11 +0900 | [diff] [blame] | 26 |  | 
| Shahar Levi | 00d2010 | 2010-11-08 11:20:10 +0000 | [diff] [blame] | 27 | #include "wl12xx.h" | 
| Luciano Coelho | 0f4e312 | 2011-10-07 11:02:42 +0300 | [diff] [blame] | 28 | #include "debug.h" | 
| Shahar Levi | 00d2010 | 2010-11-08 11:20:10 +0000 | [diff] [blame] | 29 | #include "acx.h" | 
|  | 30 | #include "reg.h" | 
|  | 31 | #include "rx.h" | 
| Eliad Peller | 9eb599e | 2011-10-10 10:12:59 +0200 | [diff] [blame] | 32 | #include "tx.h" | 
| Shahar Levi | 00d2010 | 2010-11-08 11:20:10 +0000 | [diff] [blame] | 33 | #include "io.h" | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 34 |  | 
| Eliad Peller | 4d56ad9 | 2011-08-14 13:17:05 +0300 | [diff] [blame] | 35 | static u8 wl12xx_rx_get_mem_block(struct wl12xx_fw_status *status, | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 36 | u32 drv_rx_counter) | 
|  | 37 | { | 
| Luciano Coelho | d0f63b2 | 2009-10-15 10:33:29 +0300 | [diff] [blame] | 38 | return le32_to_cpu(status->rx_pkt_descs[drv_rx_counter]) & | 
|  | 39 | RX_MEM_BLOCK_MASK; | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 40 | } | 
|  | 41 |  | 
| Eliad Peller | 4d56ad9 | 2011-08-14 13:17:05 +0300 | [diff] [blame] | 42 | static u32 wl12xx_rx_get_buf_size(struct wl12xx_fw_status *status, | 
|  | 43 | u32 drv_rx_counter) | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 44 | { | 
| Luciano Coelho | d0f63b2 | 2009-10-15 10:33:29 +0300 | [diff] [blame] | 45 | return (le32_to_cpu(status->rx_pkt_descs[drv_rx_counter]) & | 
|  | 46 | RX_BUF_SIZE_MASK) >> RX_BUF_SIZE_SHIFT_DIV; | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 47 | } | 
|  | 48 |  | 
| Eliad Peller | 4d56ad9 | 2011-08-14 13:17:05 +0300 | [diff] [blame] | 49 | static bool wl12xx_rx_get_unaligned(struct wl12xx_fw_status *status, | 
| Shahar Levi | 0a1d3ab | 2011-07-14 11:50:27 +0300 | [diff] [blame] | 50 | u32 drv_rx_counter) | 
|  | 51 | { | 
|  | 52 | /* Convert the value to bool */ | 
|  | 53 | return !!(le32_to_cpu(status->rx_pkt_descs[drv_rx_counter]) & | 
|  | 54 | RX_BUF_UNALIGNED_PAYLOAD); | 
|  | 55 | } | 
|  | 56 |  | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 57 | static void wl1271_rx_status(struct wl1271 *wl, | 
|  | 58 | struct wl1271_rx_descriptor *desc, | 
|  | 59 | struct ieee80211_rx_status *status, | 
|  | 60 | u8 beacon) | 
|  | 61 | { | 
|  | 62 | memset(status, 0, sizeof(struct ieee80211_rx_status)); | 
|  | 63 |  | 
| Teemu Paasikivi | 6a2de93 | 2010-10-14 11:00:04 +0200 | [diff] [blame] | 64 | if ((desc->flags & WL1271_RX_DESC_BAND_MASK) == WL1271_RX_DESC_BAND_BG) | 
| Juuso Oikarinen | 0af0467 | 2011-03-10 10:01:43 +0200 | [diff] [blame] | 65 | status->band = IEEE80211_BAND_2GHZ; | 
| Teemu Paasikivi | 6a2de93 | 2010-10-14 11:00:04 +0200 | [diff] [blame] | 66 | else | 
| Juuso Oikarinen | 0af0467 | 2011-03-10 10:01:43 +0200 | [diff] [blame] | 67 | status->band = IEEE80211_BAND_5GHZ; | 
| Teemu Paasikivi | 6a2de93 | 2010-10-14 11:00:04 +0200 | [diff] [blame] | 68 |  | 
| Juuso Oikarinen | 0af0467 | 2011-03-10 10:01:43 +0200 | [diff] [blame] | 69 | status->rate_idx = wl1271_rate_to_idx(desc->rate, status->band); | 
| Teemu Paasikivi | a410264 | 2009-10-13 12:47:51 +0300 | [diff] [blame] | 70 |  | 
| Shahar Levi | 1835785 | 2010-10-13 16:09:41 +0200 | [diff] [blame] | 71 | /* 11n support */ | 
|  | 72 | if (desc->rate <= CONF_HW_RXTX_RATE_MCS0) | 
|  | 73 | status->flag |= RX_FLAG_HT; | 
| Shahar Levi | 1835785 | 2010-10-13 16:09:41 +0200 | [diff] [blame] | 74 |  | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 75 | status->signal = desc->rssi; | 
|  | 76 |  | 
| John W. Linville | ece550d | 2010-07-28 16:41:06 -0400 | [diff] [blame] | 77 | /* | 
|  | 78 | * FIXME: In wl1251, the SNR should be divided by two.  In wl1271 we | 
|  | 79 | * need to divide by two for now, but TI has been discussing about | 
|  | 80 | * changing it.  This needs to be rechecked. | 
|  | 81 | */ | 
|  | 82 | wl->noise = desc->rssi - (desc->snr >> 1); | 
|  | 83 |  | 
| Juuso Oikarinen | 0af0467 | 2011-03-10 10:01:43 +0200 | [diff] [blame] | 84 | status->freq = ieee80211_channel_to_frequency(desc->channel, | 
|  | 85 | status->band); | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 86 |  | 
|  | 87 | if (desc->flags & WL1271_RX_DESC_ENCRYPT_MASK) { | 
| Arik Nemtsov | 34c8e3d | 2011-04-26 23:35:40 +0300 | [diff] [blame] | 88 | u8 desc_err_code = desc->status & WL1271_RX_DESC_STATUS_MASK; | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 89 |  | 
| Arik Nemtsov | 34c8e3d | 2011-04-26 23:35:40 +0300 | [diff] [blame] | 90 | status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED | | 
|  | 91 | RX_FLAG_DECRYPTED; | 
|  | 92 |  | 
|  | 93 | if (unlikely(desc_err_code == WL1271_RX_DESC_MIC_FAIL)) { | 
| Teemu Paasikivi | 5d07b66 | 2009-10-13 12:47:52 +0300 | [diff] [blame] | 94 | status->flag |= RX_FLAG_MMIC_ERROR; | 
| Arik Nemtsov | 34c8e3d | 2011-04-26 23:35:40 +0300 | [diff] [blame] | 95 | wl1271_warning("Michael MIC error"); | 
|  | 96 | } | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 97 | } | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 98 | } | 
|  | 99 |  | 
| Shahar Levi | 0a1d3ab | 2011-07-14 11:50:27 +0300 | [diff] [blame] | 100 | static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length, | 
| Eliad Peller | 9eb599e | 2011-10-10 10:12:59 +0200 | [diff] [blame] | 101 | bool unaligned, u8 *hlid) | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 102 | { | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 103 | struct wl1271_rx_descriptor *desc; | 
|  | 104 | struct sk_buff *skb; | 
| Eliad Peller | 92fe9b5 | 2011-02-09 12:25:14 +0200 | [diff] [blame] | 105 | struct ieee80211_hdr *hdr; | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 106 | u8 *buf; | 
|  | 107 | u8 beacon = 0; | 
| Eliad Peller | 77ddaa1 | 2011-05-15 11:10:29 +0300 | [diff] [blame] | 108 | u8 is_data = 0; | 
| Shahar Levi | 0a1d3ab | 2011-07-14 11:50:27 +0300 | [diff] [blame] | 109 | u8 reserved = unaligned ? NET_IP_ALIGN : 0; | 
| Eliad Peller | 5c47214 | 2011-08-25 18:10:58 +0300 | [diff] [blame] | 110 | u16 seq_num; | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 111 |  | 
| Kalle Valo | 93c5bb6 | 2010-02-22 08:38:30 +0200 | [diff] [blame] | 112 | /* | 
|  | 113 | * In PLT mode we seem to get frames and mac80211 warns about them, | 
|  | 114 | * workaround this by not retrieving them at all. | 
|  | 115 | */ | 
| Eliad Peller | 3fcdab7 | 2012-02-06 12:47:54 +0200 | [diff] [blame] | 116 | if (unlikely(wl->plt)) | 
| Ido Yariv | 1f37cbc | 2010-09-30 13:28:27 +0200 | [diff] [blame] | 117 | return -EINVAL; | 
| Kalle Valo | 93c5bb6 | 2010-02-22 08:38:30 +0200 | [diff] [blame] | 118 |  | 
| Arik Nemtsov | 34c8e3d | 2011-04-26 23:35:40 +0300 | [diff] [blame] | 119 | /* the data read starts with the descriptor */ | 
|  | 120 | desc = (struct wl1271_rx_descriptor *) data; | 
|  | 121 |  | 
| Ido Yariv | 95dac04f | 2011-06-06 14:57:06 +0300 | [diff] [blame] | 122 | if (desc->packet_class == WL12XX_RX_CLASS_LOGGER) { | 
|  | 123 | size_t len = length - sizeof(*desc); | 
|  | 124 | wl12xx_copy_fwlog(wl, data + sizeof(*desc), len); | 
|  | 125 | wake_up_interruptible(&wl->fwlog_waitq); | 
|  | 126 | return 0; | 
|  | 127 | } | 
|  | 128 |  | 
| Arik Nemtsov | 34c8e3d | 2011-04-26 23:35:40 +0300 | [diff] [blame] | 129 | switch (desc->status & WL1271_RX_DESC_STATUS_MASK) { | 
|  | 130 | /* discard corrupted packets */ | 
|  | 131 | case WL1271_RX_DESC_DRIVER_RX_Q_FAIL: | 
|  | 132 | case WL1271_RX_DESC_DECRYPT_FAIL: | 
|  | 133 | wl1271_warning("corrupted packet in RX with status: 0x%x", | 
|  | 134 | desc->status & WL1271_RX_DESC_STATUS_MASK); | 
|  | 135 | return -EINVAL; | 
|  | 136 | case WL1271_RX_DESC_SUCCESS: | 
|  | 137 | case WL1271_RX_DESC_MIC_FAIL: | 
|  | 138 | break; | 
|  | 139 | default: | 
|  | 140 | wl1271_error("invalid RX descriptor status: 0x%x", | 
|  | 141 | desc->status & WL1271_RX_DESC_STATUS_MASK); | 
|  | 142 | return -EINVAL; | 
|  | 143 | } | 
|  | 144 |  | 
| Shahar Levi | 0a1d3ab | 2011-07-14 11:50:27 +0300 | [diff] [blame] | 145 | /* skb length not included rx descriptor */ | 
|  | 146 | skb = __dev_alloc_skb(length + reserved - sizeof(*desc), GFP_KERNEL); | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 147 | if (!skb) { | 
|  | 148 | wl1271_error("Couldn't allocate RX frame"); | 
| Ido Yariv | 1f37cbc | 2010-09-30 13:28:27 +0200 | [diff] [blame] | 149 | return -ENOMEM; | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 150 | } | 
|  | 151 |  | 
| Shahar Levi | 0a1d3ab | 2011-07-14 11:50:27 +0300 | [diff] [blame] | 152 | /* reserve the unaligned payload(if any) */ | 
|  | 153 | skb_reserve(skb, reserved); | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 154 |  | 
| Shahar Levi | 0a1d3ab | 2011-07-14 11:50:27 +0300 | [diff] [blame] | 155 | buf = skb_put(skb, length - sizeof(*desc)); | 
|  | 156 |  | 
|  | 157 | /* | 
|  | 158 | * Copy packets from aggregation buffer to the skbs without rx | 
|  | 159 | * descriptor and with packet payload aligned care. In case of unaligned | 
|  | 160 | * packets copy the packets in offset of 2 bytes guarantee IP header | 
|  | 161 | * payload aligned to 4 bytes. | 
|  | 162 | */ | 
|  | 163 | memcpy(buf, data + sizeof(*desc), length - sizeof(*desc)); | 
| Eliad Peller | 9eb599e | 2011-10-10 10:12:59 +0200 | [diff] [blame] | 164 | *hlid = desc->hlid; | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 165 |  | 
| Eliad Peller | 92fe9b5 | 2011-02-09 12:25:14 +0200 | [diff] [blame] | 166 | hdr = (struct ieee80211_hdr *)skb->data; | 
|  | 167 | if (ieee80211_is_beacon(hdr->frame_control)) | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 168 | beacon = 1; | 
| Eliad Peller | 77ddaa1 | 2011-05-15 11:10:29 +0300 | [diff] [blame] | 169 | if (ieee80211_is_data_present(hdr->frame_control)) | 
|  | 170 | is_data = 1; | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 171 |  | 
| Eliad Peller | 58be460 | 2010-09-19 18:55:08 +0200 | [diff] [blame] | 172 | wl1271_rx_status(wl, desc, IEEE80211_SKB_RXCB(skb), beacon); | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 173 |  | 
| Eliad Peller | 5c47214 | 2011-08-25 18:10:58 +0300 | [diff] [blame] | 174 | seq_num = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; | 
| Eliad Peller | 9eb599e | 2011-10-10 10:12:59 +0200 | [diff] [blame] | 175 | wl1271_debug(DEBUG_RX, "rx skb 0x%p: %d B %s seq %d hlid %d", skb, | 
| Eliad Peller | a20a5b7 | 2011-04-05 18:21:31 +0300 | [diff] [blame] | 176 | skb->len - desc->pad_len, | 
| Eliad Peller | 5c47214 | 2011-08-25 18:10:58 +0300 | [diff] [blame] | 177 | beacon ? "beacon" : "", | 
| Eliad Peller | 9eb599e | 2011-10-10 10:12:59 +0200 | [diff] [blame] | 178 | seq_num, *hlid); | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 179 |  | 
| Juuso Oikarinen | b9f2e39 | 2010-05-14 10:46:24 +0300 | [diff] [blame] | 180 | skb_trim(skb, skb->len - desc->pad_len); | 
|  | 181 |  | 
| Ido Yariv | a620865 | 2011-03-01 15:14:41 +0200 | [diff] [blame] | 182 | skb_queue_tail(&wl->deferred_rx_queue, skb); | 
| Eliad Peller | 92ef896 | 2011-06-07 12:50:46 +0300 | [diff] [blame] | 183 | queue_work(wl->freezable_wq, &wl->netstack_work); | 
| Ido Yariv | 1f37cbc | 2010-09-30 13:28:27 +0200 | [diff] [blame] | 184 |  | 
| Eliad Peller | 77ddaa1 | 2011-05-15 11:10:29 +0300 | [diff] [blame] | 185 | return is_data; | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 186 | } | 
|  | 187 |  | 
| Eliad Peller | 4d56ad9 | 2011-08-14 13:17:05 +0300 | [diff] [blame] | 188 | void wl12xx_rx(struct wl1271 *wl, struct wl12xx_fw_status *status) | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 189 | { | 
|  | 190 | struct wl1271_acx_mem_map *wl_mem_map = wl->target_mem_map; | 
| Eliad Peller | 9eb599e | 2011-10-10 10:12:59 +0200 | [diff] [blame] | 191 | unsigned long active_hlids[BITS_TO_LONGS(WL12XX_MAX_LINKS)] = {0}; | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 192 | u32 buf_size; | 
|  | 193 | u32 fw_rx_counter  = status->fw_rx_counter & NUM_RX_PKT_DESC_MOD_MASK; | 
|  | 194 | u32 drv_rx_counter = wl->rx_counter & NUM_RX_PKT_DESC_MOD_MASK; | 
| Ido Yariv | 1f37cbc | 2010-09-30 13:28:27 +0200 | [diff] [blame] | 195 | u32 rx_counter; | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 196 | u32 mem_block; | 
| Ido Yariv | 1f37cbc | 2010-09-30 13:28:27 +0200 | [diff] [blame] | 197 | u32 pkt_length; | 
|  | 198 | u32 pkt_offset; | 
| Eliad Peller | 9eb599e | 2011-10-10 10:12:59 +0200 | [diff] [blame] | 199 | u8 hlid; | 
| Shahar Levi | 0a1d3ab | 2011-07-14 11:50:27 +0300 | [diff] [blame] | 200 | bool unaligned = false; | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 201 |  | 
|  | 202 | while (drv_rx_counter != fw_rx_counter) { | 
| Ido Yariv | 1f37cbc | 2010-09-30 13:28:27 +0200 | [diff] [blame] | 203 | buf_size = 0; | 
|  | 204 | rx_counter = drv_rx_counter; | 
|  | 205 | while (rx_counter != fw_rx_counter) { | 
| Eliad Peller | 4d56ad9 | 2011-08-14 13:17:05 +0300 | [diff] [blame] | 206 | pkt_length = wl12xx_rx_get_buf_size(status, rx_counter); | 
| Ido Yariv | 1f37cbc | 2010-09-30 13:28:27 +0200 | [diff] [blame] | 207 | if (buf_size + pkt_length > WL1271_AGGR_BUFFER_SIZE) | 
|  | 208 | break; | 
|  | 209 | buf_size += pkt_length; | 
|  | 210 | rx_counter++; | 
|  | 211 | rx_counter &= NUM_RX_PKT_DESC_MOD_MASK; | 
|  | 212 | } | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 213 |  | 
|  | 214 | if (buf_size == 0) { | 
|  | 215 | wl1271_warning("received empty data"); | 
|  | 216 | break; | 
|  | 217 | } | 
|  | 218 |  | 
| Shahar Levi | ae77ecc | 2011-03-06 16:32:13 +0200 | [diff] [blame] | 219 | if (wl->chip.id != CHIP_ID_1283_PG20) { | 
|  | 220 | /* | 
|  | 221 | * Choose the block we want to read | 
|  | 222 | * For aggregated packets, only the first memory block | 
|  | 223 | * should be retrieved. The FW takes care of the rest. | 
|  | 224 | */ | 
| Eliad Peller | 4d56ad9 | 2011-08-14 13:17:05 +0300 | [diff] [blame] | 225 | mem_block = wl12xx_rx_get_mem_block(status, | 
| Shahar Levi | ae77ecc | 2011-03-06 16:32:13 +0200 | [diff] [blame] | 226 | drv_rx_counter); | 
|  | 227 |  | 
|  | 228 | wl->rx_mem_pool_addr.addr = (mem_block << 8) + | 
|  | 229 | le32_to_cpu(wl_mem_map->packet_memory_pool_start); | 
|  | 230 |  | 
|  | 231 | wl->rx_mem_pool_addr.addr_extra = | 
|  | 232 | wl->rx_mem_pool_addr.addr + 4; | 
|  | 233 |  | 
|  | 234 | wl1271_write(wl, WL1271_SLV_REG_DATA, | 
|  | 235 | &wl->rx_mem_pool_addr, | 
|  | 236 | sizeof(wl->rx_mem_pool_addr), false); | 
|  | 237 | } | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 238 |  | 
| Ido Yariv | 1f37cbc | 2010-09-30 13:28:27 +0200 | [diff] [blame] | 239 | /* Read all available packets at once */ | 
|  | 240 | wl1271_read(wl, WL1271_SLV_MEM_DATA, wl->aggr_buf, | 
|  | 241 | buf_size, true); | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 242 |  | 
| Ido Yariv | 1f37cbc | 2010-09-30 13:28:27 +0200 | [diff] [blame] | 243 | /* Split data into separate packets */ | 
|  | 244 | pkt_offset = 0; | 
|  | 245 | while (pkt_offset < buf_size) { | 
| Eliad Peller | 4d56ad9 | 2011-08-14 13:17:05 +0300 | [diff] [blame] | 246 | pkt_length = wl12xx_rx_get_buf_size(status, | 
| Ido Yariv | 1f37cbc | 2010-09-30 13:28:27 +0200 | [diff] [blame] | 247 | drv_rx_counter); | 
| Shahar Levi | 0a1d3ab | 2011-07-14 11:50:27 +0300 | [diff] [blame] | 248 |  | 
| Eliad Peller | 4d56ad9 | 2011-08-14 13:17:05 +0300 | [diff] [blame] | 249 | unaligned = wl12xx_rx_get_unaligned(status, | 
| Shahar Levi | 0a1d3ab | 2011-07-14 11:50:27 +0300 | [diff] [blame] | 250 | drv_rx_counter); | 
|  | 251 |  | 
| Juuso Oikarinen | fb2382c | 2010-10-25 11:24:29 +0200 | [diff] [blame] | 252 | /* | 
|  | 253 | * the handle data call can only fail in memory-outage | 
|  | 254 | * conditions, in that case the received frame will just | 
|  | 255 | * be dropped. | 
|  | 256 | */ | 
| Eliad Peller | 77ddaa1 | 2011-05-15 11:10:29 +0300 | [diff] [blame] | 257 | if (wl1271_rx_handle_data(wl, | 
|  | 258 | wl->aggr_buf + pkt_offset, | 
| Eliad Peller | 9eb599e | 2011-10-10 10:12:59 +0200 | [diff] [blame] | 259 | pkt_length, unaligned, | 
|  | 260 | &hlid) == 1) { | 
| Luciano Coelho | f414218 | 2011-12-13 11:39:02 +0200 | [diff] [blame] | 261 | if (hlid < WL12XX_MAX_LINKS) | 
|  | 262 | __set_bit(hlid, active_hlids); | 
|  | 263 | else | 
|  | 264 | WARN(1, | 
|  | 265 | "hlid exceeded WL12XX_MAX_LINKS " | 
|  | 266 | "(%d)\n", hlid); | 
| Eliad Peller | 9eb599e | 2011-10-10 10:12:59 +0200 | [diff] [blame] | 267 | } | 
| Eliad Peller | 77ddaa1 | 2011-05-15 11:10:29 +0300 | [diff] [blame] | 268 |  | 
| Ido Yariv | 1f37cbc | 2010-09-30 13:28:27 +0200 | [diff] [blame] | 269 | wl->rx_counter++; | 
|  | 270 | drv_rx_counter++; | 
|  | 271 | drv_rx_counter &= NUM_RX_PKT_DESC_MOD_MASK; | 
|  | 272 | pkt_offset += pkt_length; | 
|  | 273 | } | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 274 | } | 
| Ido Yariv | 606ea9f | 2011-03-01 15:14:39 +0200 | [diff] [blame] | 275 |  | 
|  | 276 | /* | 
|  | 277 | * Write the driver's packet counter to the FW. This is only required | 
|  | 278 | * for older hardware revisions | 
|  | 279 | */ | 
|  | 280 | if (wl->quirks & WL12XX_QUIRK_END_OF_TRANSACTION) | 
|  | 281 | wl1271_write32(wl, RX_DRIVER_COUNTER_ADDRESS, wl->rx_counter); | 
| Eliad Peller | 77ddaa1 | 2011-05-15 11:10:29 +0300 | [diff] [blame] | 282 |  | 
| Eliad Peller | 9eb599e | 2011-10-10 10:12:59 +0200 | [diff] [blame] | 283 | wl12xx_rearm_rx_streaming(wl, active_hlids); | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 284 | } |