1 /******************************************************************************
2  * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
3  *
4  * This program is distributed in the hope that it will be useful, but WITHOUT
5  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
6  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
7  * more details.
8  *
9  * You should have received a copy of the GNU General Public License along with
10  * this program; if not, write to the Free Software Foundation, Inc.,
11  * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
12  *
13  * The full GNU General Public License is included in this distribution in the
14  * file called LICENSE.
15  *
16  * Contact Information:
17  * wlanfae <wlanfae@realtek.com>
18 ******************************************************************************/
19 
20 #include "rtl_core.h"
21 #include "r8192E_hw.h"
22 #include "r8192E_cmdpkt.h"
23 
cmpk_message_handle_tx(struct net_device * dev,u8 * code_virtual_address,u32 packettype,u32 buffer_len)24 bool cmpk_message_handle_tx(
25 	struct net_device *dev,
26 	u8	*code_virtual_address,
27 	u32	packettype,
28 	u32	buffer_len)
29 {
30 
31 	bool				rt_status = true;
32 	struct r8192_priv *priv = rtllib_priv(dev);
33 	u16				frag_threshold;
34 	u16				frag_length = 0, frag_offset = 0;
35 	struct rt_firmware *pfirmware = priv->pFirmware;
36 	struct sk_buff		*skb;
37 	unsigned char		*seg_ptr;
38 	struct cb_desc *tcb_desc;
39 	u8				bLastIniPkt;
40 
41 	struct tx_fwinfo_8190pci *pTxFwInfo = NULL;
42 
43 	RT_TRACE(COMP_CMDPKT, "%s(),buffer_len is %d\n", __func__, buffer_len);
44 	firmware_init_param(dev);
45 	frag_threshold = pfirmware->cmdpacket_frag_thresold;
46 
47 	do {
48 		if ((buffer_len - frag_offset) > frag_threshold) {
49 			frag_length = frag_threshold;
50 			bLastIniPkt = 0;
51 
52 		} else {
53 			frag_length = (u16)(buffer_len - frag_offset);
54 			bLastIniPkt = 1;
55 		}
56 
57 		skb  = dev_alloc_skb(frag_length +
58 				     priv->rtllib->tx_headroom + 4);
59 
60 		if (skb == NULL) {
61 			rt_status = false;
62 			goto Failed;
63 		}
64 
65 		memcpy((unsigned char *)(skb->cb), &dev, sizeof(dev));
66 		tcb_desc = (struct cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE);
67 		tcb_desc->queue_index = TXCMD_QUEUE;
68 		tcb_desc->bCmdOrInit = DESC_PACKET_TYPE_NORMAL;
69 		tcb_desc->bLastIniPkt = bLastIniPkt;
70 		tcb_desc->pkt_size = frag_length;
71 
72 		seg_ptr = skb_put(skb, priv->rtllib->tx_headroom);
73 		pTxFwInfo = (struct tx_fwinfo_8190pci *)seg_ptr;
74 		memset(pTxFwInfo, 0, sizeof(struct tx_fwinfo_8190pci));
75 		memset(pTxFwInfo, 0x12, 8);
76 
77 		seg_ptr = skb_put(skb, frag_length);
78 		memcpy(seg_ptr, code_virtual_address, (u32)frag_length);
79 
80 		priv->rtllib->softmac_hard_start_xmit(skb, dev);
81 
82 		code_virtual_address += frag_length;
83 		frag_offset += frag_length;
84 
85 	} while (frag_offset < buffer_len);
86 
87 	write_nic_byte(dev, TPPoll, TPPoll_CQ);
88 Failed:
89 	return rt_status;
90 }
91 
92 static	void
cmpk_count_txstatistic(struct net_device * dev,struct cmpk_txfb * pstx_fb)93 cmpk_count_txstatistic(
94 	struct net_device *dev,
95 	struct cmpk_txfb *pstx_fb)
96 {
97 	struct r8192_priv *priv = rtllib_priv(dev);
98 #ifdef ENABLE_PS
99 	enum rt_rf_power_state rtState;
100 
101 	pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE,
102 					  (pu1Byte)(&rtState));
103 
104 	if (rtState == eRfOff)
105 		return;
106 #endif
107 
108 	if (pstx_fb->tok) {
109 		priv->stats.txfeedbackok++;
110 		priv->stats.txoktotal++;
111 		priv->stats.txokbytestotal += pstx_fb->pkt_length;
112 		priv->stats.txokinperiod++;
113 
114 		if (pstx_fb->pkt_type == PACKET_MULTICAST) {
115 			priv->stats.txmulticast++;
116 			priv->stats.txbytesmulticast += pstx_fb->pkt_length;
117 		} else if (pstx_fb->pkt_type == PACKET_BROADCAST) {
118 			priv->stats.txbroadcast++;
119 			priv->stats.txbytesbroadcast += pstx_fb->pkt_length;
120 		} else {
121 			priv->stats.txunicast++;
122 			priv->stats.txbytesunicast += pstx_fb->pkt_length;
123 		}
124 	} else {
125 		priv->stats.txfeedbackfail++;
126 		priv->stats.txerrtotal++;
127 		priv->stats.txerrbytestotal += pstx_fb->pkt_length;
128 
129 		if (pstx_fb->pkt_type == PACKET_MULTICAST)
130 			priv->stats.txerrmulticast++;
131 		else if (pstx_fb->pkt_type == PACKET_BROADCAST)
132 			priv->stats.txerrbroadcast++;
133 		else
134 			priv->stats.txerrunicast++;
135 	}
136 
137 	priv->stats.txretrycount += pstx_fb->retry_cnt;
138 	priv->stats.txfeedbackretry += pstx_fb->retry_cnt;
139 }
140 
cmpk_handle_tx_feedback(struct net_device * dev,u8 * pmsg)141 static void cmpk_handle_tx_feedback(struct net_device *dev, u8 *pmsg)
142 {
143 	struct r8192_priv *priv = rtllib_priv(dev);
144 	struct cmpk_txfb rx_tx_fb;
145 
146 	priv->stats.txfeedback++;
147 
148 
149 	memcpy((u8 *)&rx_tx_fb, pmsg, sizeof(struct cmpk_txfb));
150 	cmpk_count_txstatistic(dev, &rx_tx_fb);
151 }
152 
cmdpkt_beacontimerinterrupt_819xusb(struct net_device * dev)153 static void cmdpkt_beacontimerinterrupt_819xusb(struct net_device *dev)
154 {
155 	struct r8192_priv *priv = rtllib_priv(dev);
156 
157 	if ((priv->rtllib->current_network.mode == IEEE_A)  ||
158 	    (priv->rtllib->current_network.mode == IEEE_N_5G) ||
159 	    ((priv->rtllib->current_network.mode == IEEE_N_24G)  &&
160 	    (!priv->rtllib->pHTInfo->bCurSuppCCK)))
161 		DMESG("send beacon frame  tx rate is 6Mbpm\n");
162 	else
163 		DMESG("send beacon frame  tx rate is 1Mbpm\n");
164 }
165 
cmpk_handle_interrupt_status(struct net_device * dev,u8 * pmsg)166 static void cmpk_handle_interrupt_status(struct net_device *dev, u8 *pmsg)
167 {
168 	struct cmpk_intr_sta rx_intr_status;
169 	struct r8192_priv *priv = rtllib_priv(dev);
170 
171 	DMESG("---> cmpk_Handle_Interrupt_Status()\n");
172 
173 	rx_intr_status.length = pmsg[1];
174 	if (rx_intr_status.length != (sizeof(struct cmpk_intr_sta) - 2)) {
175 		DMESG("cmpk_Handle_Interrupt_Status: wrong length!\n");
176 		return;
177 	}
178 
179 	if (priv->rtllib->iw_mode == IW_MODE_ADHOC) {
180 		rx_intr_status.interrupt_status = *((u32 *)(pmsg + 4));
181 
182 		DMESG("interrupt status = 0x%x\n",
183 		      rx_intr_status.interrupt_status);
184 
185 		if (rx_intr_status.interrupt_status & ISR_TxBcnOk) {
186 			priv->rtllib->bibsscoordinator = true;
187 			priv->stats.txbeaconokint++;
188 		} else if (rx_intr_status.interrupt_status & ISR_TxBcnErr) {
189 			priv->rtllib->bibsscoordinator = false;
190 			priv->stats.txbeaconerr++;
191 		}
192 
193 		if (rx_intr_status.interrupt_status & ISR_BcnTimerIntr)
194 			cmdpkt_beacontimerinterrupt_819xusb(dev);
195 	}
196 
197 	DMESG("<---- cmpk_handle_interrupt_status()\n");
198 
199 }
200 
cmpk_handle_query_config_rx(struct net_device * dev,u8 * pmsg)201 static	void cmpk_handle_query_config_rx(struct net_device *dev, u8 *pmsg)
202 {
203 	cmpk_query_cfg_t	rx_query_cfg;
204 
205 
206 	rx_query_cfg.cfg_action = (pmsg[4] & 0x80000000)>>31;
207 	rx_query_cfg.cfg_type = (pmsg[4] & 0x60) >> 5;
208 	rx_query_cfg.cfg_size = (pmsg[4] & 0x18) >> 3;
209 	rx_query_cfg.cfg_page = (pmsg[6] & 0x0F) >> 0;
210 	rx_query_cfg.cfg_offset	 = pmsg[7];
211 	rx_query_cfg.value = (pmsg[8] << 24) | (pmsg[9] << 16) |
212 			     (pmsg[10] << 8) | (pmsg[11] << 0);
213 	rx_query_cfg.mask = (pmsg[12] << 24) | (pmsg[13] << 16) |
214 			    (pmsg[14] << 8) | (pmsg[15] << 0);
215 
216 }
217 
cmpk_count_tx_status(struct net_device * dev,struct cmpk_tx_status * pstx_status)218 static void cmpk_count_tx_status(struct net_device *dev,
219 				 struct cmpk_tx_status *pstx_status)
220 {
221 	struct r8192_priv *priv = rtllib_priv(dev);
222 
223 #ifdef ENABLE_PS
224 
225 	enum rt_rf_power_state rtstate;
226 
227 	pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE,
228 					  (pu1Byte)(&rtState));
229 
230 	if (rtState == eRfOff)
231 		return;
232 #endif
233 
234 	priv->stats.txfeedbackok	+= pstx_status->txok;
235 	priv->stats.txoktotal		+= pstx_status->txok;
236 
237 	priv->stats.txfeedbackfail	+= pstx_status->txfail;
238 	priv->stats.txerrtotal		+= pstx_status->txfail;
239 
240 	priv->stats.txretrycount		+= pstx_status->txretry;
241 	priv->stats.txfeedbackretry	+= pstx_status->txretry;
242 
243 
244 	priv->stats.txmulticast	+= pstx_status->txmcok;
245 	priv->stats.txbroadcast	+= pstx_status->txbcok;
246 	priv->stats.txunicast		+= pstx_status->txucok;
247 
248 	priv->stats.txerrmulticast	+= pstx_status->txmcfail;
249 	priv->stats.txerrbroadcast	+= pstx_status->txbcfail;
250 	priv->stats.txerrunicast	+= pstx_status->txucfail;
251 
252 	priv->stats.txbytesmulticast	+= pstx_status->txmclength;
253 	priv->stats.txbytesbroadcast	+= pstx_status->txbclength;
254 	priv->stats.txbytesunicast		+= pstx_status->txuclength;
255 
256 	priv->stats.last_packet_rate		= pstx_status->rate;
257 }
258 
cmpk_handle_tx_status(struct net_device * dev,u8 * pmsg)259 static	void cmpk_handle_tx_status(struct net_device *dev, u8 *pmsg)
260 {
261 	struct cmpk_tx_status rx_tx_sts;
262 
263 	memcpy((void *)&rx_tx_sts, (void *)pmsg, sizeof(struct cmpk_tx_status));
264 	cmpk_count_tx_status(dev, &rx_tx_sts);
265 }
266 
cmpk_handle_tx_rate_history(struct net_device * dev,u8 * pmsg)267 static	void cmpk_handle_tx_rate_history(struct net_device *dev, u8 *pmsg)
268 {
269 	struct cmpk_tx_rahis *ptxrate;
270 	u8 i, j;
271 	u16				length = sizeof(struct cmpk_tx_rahis);
272 	u32 *ptemp;
273 	struct r8192_priv *priv = rtllib_priv(dev);
274 
275 #ifdef ENABLE_PS
276 	pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE,
277 					 (pu1Byte)(&rtState));
278 
279 	if (rtState == eRfOff)
280 		return;
281 #endif
282 
283 	ptemp = (u32 *)pmsg;
284 
285 	for (i = 0; i < (length / 4); i++) {
286 		u16	 temp1, temp2;
287 
288 		temp1 = ptemp[i] & 0x0000FFFF;
289 		temp2 = ptemp[i] >> 16;
290 		ptemp[i] = (temp1 << 16) | temp2;
291 	}
292 
293 	ptxrate = (struct cmpk_tx_rahis *)pmsg;
294 
295 	if (ptxrate == NULL)
296 		return;
297 
298 	for (i = 0; i < 16; i++) {
299 		if (i < 4)
300 			priv->stats.txrate.cck[i] += ptxrate->cck[i];
301 
302 		if (i < 8)
303 			priv->stats.txrate.ofdm[i] += ptxrate->ofdm[i];
304 
305 		for (j = 0; j < 4; j++)
306 			priv->stats.txrate.ht_mcs[j][i] +=
307 							 ptxrate->ht_mcs[j][i];
308 	}
309 }
310 
cmpk_message_handle_rx(struct net_device * dev,struct rtllib_rx_stats * pstats)311 u32 cmpk_message_handle_rx(struct net_device *dev,
312 			   struct rtllib_rx_stats *pstats)
313 {
314 	int			total_length;
315 	u8			cmd_length, exe_cnt = 0;
316 	u8			element_id;
317 	u8			*pcmd_buff;
318 
319 	RT_TRACE(COMP_CMDPKT, "---->cmpk_message_handle_rx()\n");
320 
321 	if (pstats == NULL)
322 		return 0;
323 
324 	total_length = pstats->Length;
325 
326 	pcmd_buff = pstats->virtual_address;
327 
328 	element_id = pcmd_buff[0];
329 
330 	while (total_length > 0 || exe_cnt++ > 100) {
331 		element_id = pcmd_buff[0];
332 
333 		switch (element_id) {
334 		case RX_TX_FEEDBACK:
335 			RT_TRACE(COMP_CMDPKT,
336 				 "---->cmpk_message_handle_rx():RX_TX_FEEDBACK\n");
337 			cmpk_handle_tx_feedback(dev, pcmd_buff);
338 			cmd_length = CMPK_RX_TX_FB_SIZE;
339 			break;
340 		case RX_INTERRUPT_STATUS:
341 			RT_TRACE(COMP_CMDPKT,
342 				 "---->cmpk_message_handle_rx():RX_INTERRUPT_STATUS\n");
343 			cmpk_handle_interrupt_status(dev, pcmd_buff);
344 			cmd_length = sizeof(struct cmpk_intr_sta);
345 			break;
346 		case BOTH_QUERY_CONFIG:
347 			RT_TRACE(COMP_CMDPKT,
348 				 "---->cmpk_message_handle_rx():BOTH_QUERY_CONFIG\n");
349 			cmpk_handle_query_config_rx(dev, pcmd_buff);
350 			cmd_length = CMPK_BOTH_QUERY_CONFIG_SIZE;
351 			break;
352 		case RX_TX_STATUS:
353 			RT_TRACE(COMP_CMDPKT,
354 				 "---->cmpk_message_handle_rx():RX_TX_STATUS\n");
355 			cmpk_handle_tx_status(dev, pcmd_buff);
356 			cmd_length = CMPK_RX_TX_STS_SIZE;
357 			break;
358 		case RX_TX_PER_PKT_FEEDBACK:
359 			RT_TRACE(COMP_CMDPKT,
360 				 "---->cmpk_message_handle_rx():RX_TX_PER_PKT_FEEDBACK\n");
361 			cmd_length = CMPK_RX_TX_FB_SIZE;
362 			break;
363 		case RX_TX_RATE_HISTORY:
364 			RT_TRACE(COMP_CMDPKT,
365 				 "---->cmpk_message_handle_rx():RX_TX_HISTORY\n");
366 			cmpk_handle_tx_rate_history(dev, pcmd_buff);
367 			cmd_length = CMPK_TX_RAHIS_SIZE;
368 			break;
369 		default:
370 
371 			RT_TRACE(COMP_CMDPKT,
372 				 "---->cmpk_message_handle_rx():unknown CMD Element\n");
373 			return 1;
374 		}
375 
376 		total_length -= cmd_length;
377 		pcmd_buff    += cmd_length;
378 	}
379 	return	1;
380 }
381