Florian Schilhabel | a6f81aa | 2010-07-14 14:43:26 +0200 | [diff] [blame] | 1 | /****************************************************************************** |
| 2 | * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. |
| 3 | * Linux device driver for RTL8192U |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 4 | * |
Florian Schilhabel | a6f81aa | 2010-07-14 14:43:26 +0200 | [diff] [blame] | 5 | * This program is distributed in the hope that it will be useful, but WITHOUT |
| 6 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| 7 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
| 8 | * more details. |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 9 | * |
Florian Schilhabel | a6f81aa | 2010-07-14 14:43:26 +0200 | [diff] [blame] | 10 | * You should have received a copy of the GNU General Public License along with |
| 11 | * this program; if not, write to the Free Software Foundation, Inc., |
| 12 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA |
| 13 | * |
| 14 | * The full GNU General Public License is included in this distribution in the |
| 15 | * file called LICENSE. |
| 16 | * |
| 17 | * Contact Information: |
| 18 | * wlanfae <wlanfae@realtek.com> |
| 19 | ******************************************************************************/ |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 20 | #include "r8192U.h" |
| 21 | #include "r819xU_cmdpkt.h" |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 22 | |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 23 | bool SendTxCommandPacket(struct net_device *dev, void *pData, u32 DataLen) |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 24 | { |
| 25 | bool rtStatus = true; |
| 26 | struct r8192_priv *priv = ieee80211_priv(dev); |
| 27 | struct sk_buff *skb; |
| 28 | cb_desc *tcb_desc; |
| 29 | unsigned char *ptr_buf; |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 30 | |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 31 | /* |
| 32 | * Get TCB and local buffer from common pool. |
| 33 | * (It is shared by CmdQ, MgntQ, and USB coalesce DataQ) |
| 34 | */ |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 35 | skb = dev_alloc_skb(USB_HWDESC_HEADER_LEN + DataLen + 4); |
Florian Schilhabel | a6f81aa | 2010-07-14 14:43:26 +0200 | [diff] [blame] | 36 | if (!skb) |
| 37 | return false; |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 38 | memcpy((unsigned char *)(skb->cb), &dev, sizeof(dev)); |
| 39 | tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE); |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 40 | tcb_desc->queue_index = TXCMD_QUEUE; |
| 41 | tcb_desc->bCmdOrInit = DESC_PACKET_TYPE_NORMAL; |
| 42 | tcb_desc->bLastIniPkt = 0; |
| 43 | skb_reserve(skb, USB_HWDESC_HEADER_LEN); |
| 44 | ptr_buf = skb_put(skb, DataLen); |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 45 | memcpy(ptr_buf, pData, DataLen); |
| 46 | tcb_desc->txbuf_size = (u16)DataLen; |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 47 | |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 48 | if (!priv->ieee80211->check_nic_enough_desc(dev, tcb_desc->queue_index) || |
| 49 | (!skb_queue_empty(&priv->ieee80211->skb_waitQ[tcb_desc->queue_index])) || |
| 50 | (priv->ieee80211->queue_stop)) { |
| 51 | RT_TRACE(COMP_FIRMWARE, "NULL packet => tx full\n"); |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 52 | skb_queue_tail(&priv->ieee80211->skb_waitQ[tcb_desc->queue_index], skb); |
| 53 | } else { |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 54 | priv->ieee80211->softmac_hard_start_xmit(skb, dev); |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 55 | } |
| 56 | |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 57 | return rtStatus; |
| 58 | } |
| 59 | |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 60 | /* |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 61 | * Function: cmpk_message_handle_tx() |
| 62 | * |
| 63 | * Overview: Driver internal module can call the API to send message to |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 64 | * firmware side. For example, you can send a debug command packet. |
| 65 | * Or you can send a request for FW to modify RLX4181 LBUS HW bank. |
| 66 | * Otherwise, you can change MAC/PHT/RF register by firmware at |
| 67 | * run time. We do not support message more than one segment now. |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 68 | * |
| 69 | * Input: NONE |
| 70 | * |
| 71 | * Output: NONE |
| 72 | * |
| 73 | * Return: NONE |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 74 | */ |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 75 | extern bool cmpk_message_handle_tx( |
| 76 | struct net_device *dev, |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 77 | u8 *codevirtualaddress, |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 78 | u32 packettype, |
| 79 | u32 buffer_len) |
| 80 | { |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 81 | bool rt_status = true; |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 82 | return rt_status; |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 83 | } |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 84 | |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 85 | /* |
| 86 | * Function: cmpk_counttxstatistic() |
| 87 | */ |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 88 | static void |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 89 | cmpk_count_txstatistic(struct net_device *dev, cmpk_txfb_t *pstx_fb) |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 90 | { |
| 91 | struct r8192_priv *priv = ieee80211_priv(dev); |
| 92 | #ifdef ENABLE_PS |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 93 | RT_RF_POWER_STATE rtState; |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 94 | |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 95 | pAdapter->HalFunc.GetHwRegHandler(pAdapter, |
| 96 | HW_VAR_RF_STATE, |
| 97 | (pu1Byte)(&rtState)); |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 98 | |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 99 | /* |
| 100 | * When RF is off, we should not count the packet for hw/sw synchronize |
| 101 | * reason, ie. there may be a duration while sw switch is changed and hw |
| 102 | * switch is being changed. |
| 103 | */ |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 104 | if (rtState == eRfOff) |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 105 | return; |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 106 | #endif |
| 107 | |
| 108 | #ifdef TODO |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 109 | if (pAdapter->bInHctTest) |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 110 | return; |
| 111 | #endif |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 112 | /* |
| 113 | * We can not know the packet length and transmit type: |
| 114 | * broadcast or uni or multicast. |
| 115 | * So the relative statistics must be collected in tx feedback info |
| 116 | */ |
| 117 | if (pstx_fb->tok) { |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 118 | priv->stats.txfeedbackok++; |
| 119 | priv->stats.txoktotal++; |
| 120 | priv->stats.txokbytestotal += pstx_fb->pkt_length; |
| 121 | priv->stats.txokinperiod++; |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 122 | /* We can not make sure broadcast/multicast or unicast mode. */ |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 123 | if (pstx_fb->pkt_type == PACKET_MULTICAST) { |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 124 | priv->stats.txmulticast++; |
| 125 | priv->stats.txbytesmulticast += pstx_fb->pkt_length; |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 126 | } else if (pstx_fb->pkt_type == PACKET_BROADCAST) { |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 127 | priv->stats.txbroadcast++; |
| 128 | priv->stats.txbytesbroadcast += pstx_fb->pkt_length; |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 129 | } else { |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 130 | priv->stats.txunicast++; |
| 131 | priv->stats.txbytesunicast += pstx_fb->pkt_length; |
| 132 | } |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 133 | } else { |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 134 | priv->stats.txfeedbackfail++; |
| 135 | priv->stats.txerrtotal++; |
| 136 | priv->stats.txerrbytestotal += pstx_fb->pkt_length; |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 137 | /* We can not make sure broadcast/multicast or unicast mode. */ |
| 138 | if (pstx_fb->pkt_type == PACKET_MULTICAST) |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 139 | priv->stats.txerrmulticast++; |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 140 | else if (pstx_fb->pkt_type == PACKET_BROADCAST) |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 141 | priv->stats.txerrbroadcast++; |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 142 | else |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 143 | priv->stats.txerrunicast++; |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 144 | } |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 145 | priv->stats.txretrycount += pstx_fb->retry_cnt; |
| 146 | priv->stats.txfeedbackretry += pstx_fb->retry_cnt; |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 147 | } |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 148 | |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 149 | /* |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 150 | * Function: cmpk_handle_tx_feedback() |
| 151 | * |
| 152 | * Overview: The function is responsible for extract the message inside TX |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 153 | * feedbck message from firmware. It will contain dedicated info in |
| 154 | * ws-06-0063-rtl8190-command-packet-specification. Please |
| 155 | * refer to chapter "TX Feedback Element". We have to read 20 bytes |
| 156 | * in the command packet. |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 157 | * |
| 158 | * Input: struct net_device * dev |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 159 | * u8 *pmsg - Msg Ptr of the command packet. |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 160 | * |
| 161 | * Output: NONE |
| 162 | * |
| 163 | * Return: NONE |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 164 | */ |
| 165 | static void cmpk_handle_tx_feedback(struct net_device *dev, u8 *pmsg) |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 166 | { |
| 167 | struct r8192_priv *priv = ieee80211_priv(dev); |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 168 | cmpk_txfb_t rx_tx_fb; |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 169 | |
| 170 | priv->stats.txfeedback++; |
| 171 | |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 172 | /* 1. Extract TX feedback info from RFD to temp structure buffer. */ |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 173 | memcpy((u8 *)&rx_tx_fb, pmsg, sizeof(cmpk_txfb_t)); |
Bartlomiej Zolnierkiewicz | 35c1b46 | 2009-07-03 16:08:32 +0200 | [diff] [blame] | 174 | |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 175 | /* 2. Use tx feedback info to count TX statistics. */ |
| 176 | cmpk_count_txstatistic(dev, &rx_tx_fb); |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 177 | } |
Bartlomiej Zolnierkiewicz | 35c1b46 | 2009-07-03 16:08:32 +0200 | [diff] [blame] | 178 | |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 179 | void cmdpkt_beacontimerinterrupt_819xusb(struct net_device *dev) |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 180 | { |
| 181 | struct r8192_priv *priv = ieee80211_priv(dev); |
| 182 | u16 tx_rate; |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 183 | |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 184 | if (priv->ieee80211->current_network.mode == IEEE_A || |
| 185 | priv->ieee80211->current_network.mode == IEEE_N_5G || |
| 186 | (priv->ieee80211->current_network.mode == IEEE_N_24G && |
| 187 | (!priv->ieee80211->pHTInfo->bCurSuppCCK))) { |
| 188 | tx_rate = 60; |
| 189 | DMESG("send beacon frame tx rate is 6Mbpm\n"); |
| 190 | } else { |
| 191 | tx_rate = 10; |
| 192 | DMESG("send beacon frame tx rate is 1Mbpm\n"); |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 193 | } |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 194 | rtl819xusb_beacon_tx(dev, tx_rate); /* HW Beacon */ |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 195 | } |
| 196 | |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 197 | /* |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 198 | * Function: cmpk_handle_interrupt_status() |
| 199 | * |
| 200 | * Overview: The function is responsible for extract the message from |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 201 | * firmware. It will contain dedicated info in |
| 202 | * ws-07-0063-v06-rtl819x-command-packet-specification-070315.doc. |
| 203 | * Please refer to chapter "Interrupt Status Element". |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 204 | * |
| 205 | * Input: struct net_device *dev, |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 206 | * u8* pmsg - Message Pointer of the command packet. |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 207 | * |
| 208 | * Output: NONE |
| 209 | * |
| 210 | * Return: NONE |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 211 | */ |
| 212 | static void cmpk_handle_interrupt_status(struct net_device *dev, u8 *pmsg) |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 213 | { |
| 214 | cmpk_intr_sta_t rx_intr_status; /* */ |
| 215 | struct r8192_priv *priv = ieee80211_priv(dev); |
| 216 | |
| 217 | DMESG("---> cmpk_Handle_Interrupt_Status()\n"); |
| 218 | |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 219 | /* 1. Extract TX feedback info from RFD to temp structure buffer. */ |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 220 | rx_intr_status.length = pmsg[1]; |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 221 | if (rx_intr_status.length != (sizeof(cmpk_intr_sta_t) - 2)) { |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 222 | DMESG("cmpk_Handle_Interrupt_Status: wrong length!\n"); |
| 223 | return; |
| 224 | } |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 225 | /* Statistics of beacon for ad-hoc mode. */ |
| 226 | if (priv->ieee80211->iw_mode == IW_MODE_ADHOC) { |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 227 | //2 maybe need endian transform? |
| 228 | rx_intr_status.interrupt_status = *((u32 *)(pmsg + 4)); |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 229 | |
| 230 | DMESG("interrupt status = 0x%x\n", rx_intr_status.interrupt_status); |
| 231 | |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 232 | if (rx_intr_status.interrupt_status & ISR_TxBcnOk) { |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 233 | priv->ieee80211->bibsscoordinator = true; |
| 234 | priv->stats.txbeaconokint++; |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 235 | } else if (rx_intr_status.interrupt_status & ISR_TxBcnErr) { |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 236 | priv->ieee80211->bibsscoordinator = false; |
| 237 | priv->stats.txbeaconerr++; |
| 238 | } |
| 239 | |
| 240 | if (rx_intr_status.interrupt_status & ISR_BcnTimerIntr) |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 241 | cmdpkt_beacontimerinterrupt_819xusb(dev); |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 242 | } |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 243 | /* Other informations in interrupt status we need? */ |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 244 | DMESG("<---- cmpk_handle_interrupt_status()\n"); |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 245 | } |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 246 | |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 247 | /* |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 248 | * Function: cmpk_handle_query_config_rx() |
| 249 | * |
| 250 | * Overview: The function is responsible for extract the message from |
| 251 | * firmware. It will contain dedicated info in |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 252 | * ws-06-0063-rtl8190-command-packet-specification |
| 253 | * Please refer to chapter "Beacon State Element". |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 254 | * |
| 255 | * Input: u8 * pmsg - Message Pointer of the command packet. |
| 256 | * |
| 257 | * Output: NONE |
| 258 | * |
| 259 | * Return: NONE |
| 260 | * |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 261 | */ |
| 262 | static void cmpk_handle_query_config_rx(struct net_device *dev, u8 *pmsg) |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 263 | { |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 264 | cmpk_query_cfg_t rx_query_cfg; |
| 265 | /* |
| 266 | * Extract TX feedback info from RFD to temp structure buffer. |
| 267 | */ |
| 268 | rx_query_cfg.cfg_action = (pmsg[4] & 0x80000000) >> 31; |
| 269 | rx_query_cfg.cfg_type = (pmsg[4] & 0x60) >> 5; |
| 270 | rx_query_cfg.cfg_size = (pmsg[4] & 0x18) >> 3; |
| 271 | rx_query_cfg.cfg_page = (pmsg[6] & 0x0F) >> 0; |
| 272 | rx_query_cfg.cfg_offset = pmsg[7]; |
| 273 | rx_query_cfg.value = (pmsg[8] << 24) | (pmsg[9] << 16) | |
| 274 | (pmsg[10] << 8) | (pmsg[11] << 0); |
| 275 | rx_query_cfg.mask = (pmsg[12] << 24) | (pmsg[13] << 16) | |
| 276 | (pmsg[14] << 8) | (pmsg[15] << 0); |
| 277 | } |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 278 | |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 279 | /* |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 280 | * Function: cmpk_count_tx_status() |
| 281 | * |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 282 | * Overview: Count aggregated tx status from firmware of one type rx command |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 283 | * packet element id = RX_TX_STATUS. |
| 284 | * |
| 285 | * Input: NONE |
| 286 | * |
| 287 | * Output: NONE |
| 288 | * |
| 289 | * Return: NONE |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 290 | */ |
| 291 | static void cmpk_count_tx_status(struct net_device *dev, |
| 292 | cmpk_tx_status_t *pstx_status) |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 293 | { |
| 294 | struct r8192_priv *priv = ieee80211_priv(dev); |
| 295 | |
| 296 | #ifdef ENABLE_PS |
| 297 | |
| 298 | RT_RF_POWER_STATE rtstate; |
| 299 | |
| 300 | pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE, (pu1Byte)(&rtState)); |
| 301 | |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 302 | /* |
| 303 | * When RF is off, we should not count the packet for hw/sw synchronize |
| 304 | * reason, ie. there may be a duration while sw switch is changed and hw |
| 305 | * switch is being changed. |
| 306 | */ |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 307 | if (rtState == eRfOff) |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 308 | return; |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 309 | #endif |
| 310 | |
| 311 | priv->stats.txfeedbackok += pstx_status->txok; |
| 312 | priv->stats.txoktotal += pstx_status->txok; |
| 313 | |
| 314 | priv->stats.txfeedbackfail += pstx_status->txfail; |
| 315 | priv->stats.txerrtotal += pstx_status->txfail; |
| 316 | |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 317 | priv->stats.txretrycount += pstx_status->txretry; |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 318 | priv->stats.txfeedbackretry += pstx_status->txretry; |
| 319 | |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 320 | priv->stats.txmulticast += pstx_status->txmcok; |
| 321 | priv->stats.txbroadcast += pstx_status->txbcok; |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 322 | priv->stats.txunicast += pstx_status->txucok; |
| 323 | |
| 324 | priv->stats.txerrmulticast += pstx_status->txmcfail; |
| 325 | priv->stats.txerrbroadcast += pstx_status->txbcfail; |
| 326 | priv->stats.txerrunicast += pstx_status->txucfail; |
| 327 | |
| 328 | priv->stats.txbytesmulticast += pstx_status->txmclength; |
| 329 | priv->stats.txbytesbroadcast += pstx_status->txbclength; |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 330 | priv->stats.txbytesunicast += pstx_status->txuclength; |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 331 | |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 332 | priv->stats.last_packet_rate = pstx_status->rate; |
| 333 | } |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 334 | |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 335 | /* |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 336 | * Function: cmpk_handle_tx_status() |
| 337 | * |
| 338 | * Overview: Firmware add a new tx feedback status to reduce rx command |
| 339 | * packet buffer operation load. |
| 340 | * |
| 341 | * Input: NONE |
| 342 | * |
| 343 | * Output: NONE |
| 344 | * |
| 345 | * Return: NONE |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 346 | */ |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 347 | static void |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 348 | cmpk_handle_tx_status(struct net_device *dev, u8 *pmsg) |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 349 | { |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 350 | cmpk_tx_status_t rx_tx_sts; |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 351 | |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 352 | memcpy((void *)&rx_tx_sts, (void *)pmsg, sizeof(cmpk_tx_status_t)); |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 353 | /* 2. Use tx feedback info to count TX statistics. */ |
| 354 | cmpk_count_tx_status(dev, &rx_tx_sts); |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 355 | } |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 356 | |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 357 | /* |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 358 | * Function: cmpk_handle_tx_rate_history() |
| 359 | * |
| 360 | * Overview: Firmware add a new tx rate history |
| 361 | * |
| 362 | * Input: NONE |
| 363 | * |
| 364 | * Output: NONE |
| 365 | * |
| 366 | * Return: NONE |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 367 | */ |
| 368 | static void cmpk_handle_tx_rate_history(struct net_device *dev, u8 *pmsg) |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 369 | { |
| 370 | cmpk_tx_rahis_t *ptxrate; |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 371 | u8 i, j; |
| 372 | u16 length = sizeof(cmpk_tx_rahis_t); |
| 373 | u32 *ptemp; |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 374 | struct r8192_priv *priv = ieee80211_priv(dev); |
| 375 | |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 376 | #ifdef ENABLE_PS |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 377 | pAdapter->HalFunc.GetHwRegHandler(pAdapter, |
| 378 | HW_VAR_RF_STATE, |
| 379 | (pu1Byte)(&rtState)); |
| 380 | /* |
| 381 | * When RF is off, we should not count the packet for hw/sw synchronize |
| 382 | * reason, ie. there may be a duration while sw switch is changed and hw |
| 383 | * switch is being changed. |
| 384 | */ |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 385 | if (rtState == eRfOff) |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 386 | return; |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 387 | #endif |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 388 | ptemp = (u32 *)pmsg; |
| 389 | |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 390 | /* |
| 391 | * Do endian transfer to word alignment(16 bits) for windows system. |
| 392 | * You must do different endian transfer for linux and MAC OS |
| 393 | */ |
| 394 | for (i = 0; i < (length/4); i++) { |
| 395 | u16 temp1, temp2; |
| 396 | temp1 = ptemp[i] & 0x0000FFFF; |
| 397 | temp2 = ptemp[i] >> 16; |
| 398 | ptemp[i] = (temp1 << 16) | temp2; |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 399 | } |
| 400 | |
| 401 | ptxrate = (cmpk_tx_rahis_t *)pmsg; |
| 402 | |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 403 | if (ptxrate == NULL) |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 404 | return; |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 405 | |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 406 | for (i = 0; i < 16; i++) { |
| 407 | /* Collect CCK rate packet num */ |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 408 | if (i < 4) |
| 409 | priv->stats.txrate.cck[i] += ptxrate->cck[i]; |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 410 | /* Collect OFDM rate packet num */ |
| 411 | if (i < 8) |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 412 | priv->stats.txrate.ofdm[i] += ptxrate->ofdm[i]; |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 413 | for (j = 0; j < 4; j++) |
| 414 | priv->stats.txrate.ht_mcs[j][i] += ptxrate->ht_mcs[j][i]; |
| 415 | } |
| 416 | |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 417 | } |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 418 | |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 419 | /* |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 420 | * Function: cmpk_message_handle_rx() |
| 421 | * |
| 422 | * Overview: In the function, we will capture different RX command packet |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 423 | * info. Every RX command packet element has different message |
| 424 | * length and meaning in content. We only support three type of RX |
| 425 | * command packet now. Please refer to document |
| 426 | * ws-06-0063-rtl8190-command-packet-specification. |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 427 | * |
| 428 | * Input: NONE |
| 429 | * |
| 430 | * Output: NONE |
| 431 | * |
| 432 | * Return: NONE |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 433 | */ |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 434 | extern u32 |
| 435 | cmpk_message_handle_rx( |
| 436 | struct net_device *dev, |
| 437 | struct ieee80211_rx_stats *pstats) |
| 438 | { |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 439 | struct r8192_priv *priv = ieee80211_priv(dev); |
| 440 | int total_length; |
| 441 | u8 cmd_length, exe_cnt = 0; |
| 442 | u8 element_id; |
| 443 | u8 *pcmd_buff; |
| 444 | |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 445 | /* |
| 446 | * 0. Check input arguments. |
| 447 | * If is is a command queue message or pointer is null |
| 448 | */ |
| 449 | if ((pstats == NULL)) |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 450 | return 0; /* This is not a command packet. */ |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 451 | |
| 452 | /* 1. Read received command packet message length from RFD. */ |
| 453 | total_length = pstats->Length; |
| 454 | |
| 455 | /* 2. Read virtual address from RFD. */ |
| 456 | pcmd_buff = pstats->virtual_address; |
| 457 | |
| 458 | /* 3. Read command pakcet element id and length. */ |
| 459 | element_id = pcmd_buff[0]; |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 460 | |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 461 | /* |
| 462 | * 4. Check every received command packet conent according to different |
| 463 | * element type. Because FW may aggregate RX command packet to minimize |
| 464 | * transmit time between DRV and FW. |
| 465 | */ |
| 466 | |
| 467 | /* Add a counter to prevent to locked in the loop too long */ |
| 468 | while (total_length > 0 || exe_cnt++ > 100) { |
| 469 | /* We support aggregation of different cmd in the same packet */ |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 470 | element_id = pcmd_buff[0]; |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 471 | switch (element_id) { |
| 472 | case RX_TX_FEEDBACK: |
| 473 | cmpk_handle_tx_feedback(dev, pcmd_buff); |
| 474 | cmd_length = CMPK_RX_TX_FB_SIZE; |
| 475 | break; |
| 476 | case RX_INTERRUPT_STATUS: |
| 477 | cmpk_handle_interrupt_status(dev, pcmd_buff); |
| 478 | cmd_length = sizeof(cmpk_intr_sta_t); |
| 479 | break; |
| 480 | case BOTH_QUERY_CONFIG: |
| 481 | cmpk_handle_query_config_rx(dev, pcmd_buff); |
| 482 | cmd_length = CMPK_BOTH_QUERY_CONFIG_SIZE; |
| 483 | break; |
| 484 | case RX_TX_STATUS: |
| 485 | cmpk_handle_tx_status(dev, pcmd_buff); |
| 486 | cmd_length = CMPK_RX_TX_STS_SIZE; |
| 487 | break; |
| 488 | case RX_TX_PER_PKT_FEEDBACK: |
| 489 | cmd_length = CMPK_RX_TX_FB_SIZE; |
| 490 | break; |
| 491 | case RX_TX_RATE_HISTORY: |
| 492 | cmpk_handle_tx_rate_history(dev, pcmd_buff); |
| 493 | cmd_length = CMPK_TX_RAHIS_SIZE; |
| 494 | break; |
Florian Schilhabel | a6f81aa | 2010-07-14 14:43:26 +0200 | [diff] [blame] | 495 | case RX_TX_TSSI_MEAN_BACK: |
| 496 | { |
| 497 | u32 *pMsg; |
| 498 | pMsg = (u32 *)pcmd_buff; |
| 499 | } |
| 500 | cmd_length = 32; |
| 501 | break; |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 502 | default: |
| 503 | RT_TRACE(COMP_ERR, "(%s): unknown CMD Element\n", |
| 504 | __func__); |
| 505 | return 1; /* This is a command packet. */ |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 506 | } |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 507 | priv->stats.rxcmdpkt[element_id]++; |
Jerry Chuang | 5f53d8c | 2009-05-21 22:16:02 -0700 | [diff] [blame] | 508 | total_length -= cmd_length; |
| 509 | pcmd_buff += cmd_length; |
Florian Schilhabel | 8dba599 | 2010-03-06 20:45:25 +0100 | [diff] [blame] | 510 | } |
| 511 | return 1; /* This is a command packet. */ |
| 512 | } |