1/****************************************************************************** 2 * 3 * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. 4 * 5 * This program is free software; you can redistribute it and/or modify it 6 * under the terms of version 2 of the GNU General Public License as 7 * published by the Free Software Foundation. 8 * 9 * This program is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 12 * more details. 13 * 14 ******************************************************************************/ 15#define _RTL8192C_XMIT_C_ 16#include <osdep_service.h> 17#include <drv_types.h> 18#include <wifi.h> 19#include <osdep_intf.h> 20#include <usb_ops.h> 21/* include <rtl8192c_hal.h> */ 22#include <rtl8723a_hal.h> 23 24static void do_queue_select(struct rtw_adapter *padapter, struct pkt_attrib *pattrib) 25{ 26 u8 qsel; 27 28 qsel = pattrib->priority; 29 RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, 30 ("### do_queue_select priority =%d , qsel = %d\n", 31 pattrib->priority, qsel)); 32 33 pattrib->qsel = qsel; 34} 35 36static int urb_zero_packet_chk(struct rtw_adapter *padapter, int sz) 37{ 38 int blnSetTxDescOffset; 39 struct dvobj_priv *pdvobj = adapter_to_dvobj(padapter); 40 41 if (pdvobj->ishighspeed) { 42 if (((sz + TXDESC_SIZE) % 512) == 0) 43 blnSetTxDescOffset = 1; 44 else 45 blnSetTxDescOffset = 0; 46 } else { 47 if (((sz + TXDESC_SIZE) % 64) == 0) 48 blnSetTxDescOffset = 1; 49 else 50 blnSetTxDescOffset = 0; 51 } 52 return blnSetTxDescOffset; 53} 54 55static void rtl8192cu_cal_txdesc_chksum(struct tx_desc *ptxdesc) 56{ 57 u16 *usPtr = (u16 *)ptxdesc; 58 u32 count = 16; /* (32 bytes / 2 bytes per XOR) => 16 times */ 59 u32 index; 60 u16 checksum = 0; 61 62 /* Clear first */ 63 ptxdesc->txdw7 &= cpu_to_le32(0xffff0000); 64 65 for (index = 0 ; index < count ; index++) 66 checksum = checksum ^ le16_to_cpu(*(usPtr + index)); 67 68 ptxdesc->txdw7 |= cpu_to_le32(0x0000ffff&checksum); 69} 70 71static void fill_txdesc_sectype(struct pkt_attrib *pattrib, struct tx_desc *ptxdesc) 72{ 73 if ((pattrib->encrypt > 0) && !pattrib->bswenc) { 74 switch (pattrib->encrypt) { 75 /* SEC_TYPE */ 76 case WLAN_CIPHER_SUITE_WEP40: 77 case WLAN_CIPHER_SUITE_WEP104: 78 ptxdesc->txdw1 |= cpu_to_le32((0x01<<22)&0x00c00000); 79 break; 80 case WLAN_CIPHER_SUITE_TKIP: 81 /* ptxdesc->txdw1 |= cpu_to_le32((0x02<<22)&0x00c00000); */ 82 ptxdesc->txdw1 |= cpu_to_le32((0x01<<22)&0x00c00000); 83 break; 84 case WLAN_CIPHER_SUITE_CCMP: 85 ptxdesc->txdw1 |= cpu_to_le32((0x03<<22)&0x00c00000); 86 break; 87 case 0: 88 default: 89 break; 90 } 91 } 92} 93 94static void fill_txdesc_vcs(struct pkt_attrib *pattrib, u32 *pdw) 95{ 96 /* DBG_8723A("cvs_mode =%d\n", pattrib->vcs_mode); */ 97 98 switch (pattrib->vcs_mode) { 99 case RTS_CTS: 100 *pdw |= cpu_to_le32(BIT(12)); 101 break; 102 case CTS_TO_SELF: 103 *pdw |= cpu_to_le32(BIT(11)); 104 break; 105 case NONE_VCS: 106 default: 107 break; 108 } 109 110 if (pattrib->vcs_mode) { 111 *pdw |= cpu_to_le32(BIT(13)); 112 113 /* Set RTS BW */ 114 if (pattrib->ht_en) { 115 *pdw |= (pattrib->bwmode&HT_CHANNEL_WIDTH_40) ? cpu_to_le32(BIT(27)) : 0; 116 117 if (pattrib->ch_offset == HAL_PRIME_CHNL_OFFSET_LOWER) 118 *pdw |= cpu_to_le32((0x01<<28)&0x30000000); 119 else if (pattrib->ch_offset == HAL_PRIME_CHNL_OFFSET_UPPER) 120 *pdw |= cpu_to_le32((0x02<<28)&0x30000000); 121 else if (pattrib->ch_offset == HAL_PRIME_CHNL_OFFSET_DONT_CARE) 122 *pdw |= 0; 123 else 124 *pdw |= cpu_to_le32((0x03<<28)&0x30000000); 125 } 126 } 127} 128 129static void fill_txdesc_phy(struct pkt_attrib *pattrib, u32 *pdw) 130{ 131 if (pattrib->ht_en) { 132 *pdw |= (pattrib->bwmode&HT_CHANNEL_WIDTH_40) ? cpu_to_le32(BIT(25)) : 0; 133 134 if (pattrib->ch_offset == HAL_PRIME_CHNL_OFFSET_LOWER) 135 *pdw |= cpu_to_le32((0x01<<20)&0x003f0000); 136 else if (pattrib->ch_offset == HAL_PRIME_CHNL_OFFSET_UPPER) 137 *pdw |= cpu_to_le32((0x02<<20)&0x003f0000); 138 else if (pattrib->ch_offset == HAL_PRIME_CHNL_OFFSET_DONT_CARE) 139 *pdw |= 0; 140 else 141 *pdw |= cpu_to_le32((0x03<<20)&0x003f0000); 142 } 143} 144 145static s32 update_txdesc(struct xmit_frame *pxmitframe, u8 *pmem, s32 sz, u8 bagg_pkt) 146{ 147 int pull = 0; 148 uint qsel; 149 struct rtw_adapter *padapter = pxmitframe->padapter; 150 struct pkt_attrib *pattrib = &pxmitframe->attrib; 151 struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); 152 struct dm_priv *pdmpriv = &pHalData->dmpriv; 153 struct tx_desc *ptxdesc = (struct tx_desc *)pmem; 154 struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; 155 struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; 156 int bmcst = is_multicast_ether_addr(pattrib->ra); 157 158 if ((!bagg_pkt) && (urb_zero_packet_chk(padapter, sz) == 0)) { 159 ptxdesc = (struct tx_desc *)(pmem+PACKET_OFFSET_SZ); 160 pull = 1; 161 pxmitframe->pkt_offset--; 162 } 163 164 memset(ptxdesc, 0, sizeof(struct tx_desc)); 165 166 if ((pxmitframe->frame_tag&0x0f) == DATA_FRAMETAG) { 167 /* offset 4 */ 168 ptxdesc->txdw1 |= cpu_to_le32(pattrib->mac_id&0x1f); 169 170 qsel = (uint)(pattrib->qsel & 0x0000001f); 171 ptxdesc->txdw1 |= cpu_to_le32((qsel << QSEL_SHT) & 0x00001f00); 172 173 ptxdesc->txdw1 |= cpu_to_le32((pattrib->raid<<16) & 0x000f0000); 174 175 fill_txdesc_sectype(pattrib, ptxdesc); 176 177 if (pattrib->ampdu_en) 178 ptxdesc->txdw1 |= cpu_to_le32(BIT(5));/* AGG EN */ 179 else 180 ptxdesc->txdw1 |= cpu_to_le32(BIT(6));/* AGG BK */ 181 182 /* offset 8 */ 183 184 /* offset 12 */ 185 ptxdesc->txdw3 |= cpu_to_le32((pattrib->seqnum<<16)&0xffff0000); 186 187 /* offset 16 , offset 20 */ 188 if (pattrib->qos_en) 189 ptxdesc->txdw4 |= cpu_to_le32(BIT(6));/* QoS */ 190 191 if ((pattrib->ether_type != 0x888e) && 192 (pattrib->ether_type != 0x0806) && 193 (pattrib->dhcp_pkt != 1)) { 194 /* Non EAP & ARP & DHCP type data packet */ 195 196 fill_txdesc_vcs(pattrib, &ptxdesc->txdw4); 197 fill_txdesc_phy(pattrib, &ptxdesc->txdw4); 198 199 ptxdesc->txdw4 |= cpu_to_le32(0x00000008);/* RTS Rate = 24M */ 200 ptxdesc->txdw5 |= cpu_to_le32(0x0001ff00);/* */ 201 202 /* use REG_INIDATA_RATE_SEL value */ 203 ptxdesc->txdw5 |= cpu_to_le32(pdmpriv->INIDATA_RATE[pattrib->mac_id]); 204 } else { 205 /* EAP data packet and ARP packet. */ 206 /* Use the 1M data rate to send the EAP/ARP packet. */ 207 /* This will maybe make the handshake smooth. */ 208 209 ptxdesc->txdw1 |= cpu_to_le32(BIT(6));/* AGG BK */ 210 211 ptxdesc->txdw4 |= cpu_to_le32(BIT(8));/* driver uses rate */ 212 213 if (pmlmeinfo->preamble_mode == PREAMBLE_SHORT) 214 ptxdesc->txdw4 |= cpu_to_le32(BIT(24));/* DATA_SHORT */ 215 216 ptxdesc->txdw5 |= cpu_to_le32(MRateToHwRate23a(pmlmeext->tx_rate)); 217 } 218 } else if ((pxmitframe->frame_tag&0x0f) == MGNT_FRAMETAG) { 219 /* offset 4 */ 220 ptxdesc->txdw1 |= cpu_to_le32(pattrib->mac_id&0x1f); 221 222 qsel = (uint)(pattrib->qsel&0x0000001f); 223 ptxdesc->txdw1 |= cpu_to_le32((qsel<<QSEL_SHT)&0x00001f00); 224 225 ptxdesc->txdw1 |= cpu_to_le32((pattrib->raid<<16) & 0x000f0000); 226 227 /* offset 8 */ 228 /* CCX-TXRPT ack for xmit mgmt frames. */ 229 if (pxmitframe->ack_report) 230 ptxdesc->txdw2 |= cpu_to_le32(BIT(19)); 231 232 /* offset 12 */ 233 ptxdesc->txdw3 |= cpu_to_le32((pattrib->seqnum<<16)&0xffff0000); 234 235 /* offset 16 */ 236 ptxdesc->txdw4 |= cpu_to_le32(BIT(8));/* driver uses rate */ 237 238 /* offset 20 */ 239 ptxdesc->txdw5 |= cpu_to_le32(BIT(17));/* retry limit enable */ 240 ptxdesc->txdw5 |= cpu_to_le32(0x00180000);/* retry limit = 6 */ 241 242 ptxdesc->txdw5 |= cpu_to_le32(MRateToHwRate23a(pmlmeext->tx_rate)); 243 } else if ((pxmitframe->frame_tag&0x0f) == TXAGG_FRAMETAG) { 244 DBG_8723A("pxmitframe->frame_tag == TXAGG_FRAMETAG\n"); 245 } else { 246 DBG_8723A("pxmitframe->frame_tag = %d\n", pxmitframe->frame_tag); 247 248 /* offset 4 */ 249 ptxdesc->txdw1 |= cpu_to_le32((4)&0x1f);/* CAM_ID(MAC_ID) */ 250 251 ptxdesc->txdw1 |= cpu_to_le32((6<<16) & 0x000f0000);/* raid */ 252 253 /* offset 8 */ 254 255 /* offset 12 */ 256 ptxdesc->txdw3 |= cpu_to_le32((pattrib->seqnum<<16)&0xffff0000); 257 258 /* offset 16 */ 259 ptxdesc->txdw4 |= cpu_to_le32(BIT(8));/* driver uses rate */ 260 261 /* offset 20 */ 262 ptxdesc->txdw5 |= cpu_to_le32(MRateToHwRate23a(pmlmeext->tx_rate)); 263 } 264 265 /* (1) The sequence number of each non-Qos frame / broadcast / multicast / */ 266 /* mgnt frame should be controled by Hw because Fw will also send null data */ 267 /* which we cannot control when Fw LPS enable. */ 268 /* --> default enable non-Qos data sequense number. 2010.06.23. by tynli. */ 269 /* (2) Enable HW SEQ control for beacon packet, because we use Hw beacon. */ 270 /* (3) Use HW Qos SEQ to control the seq num of Ext port non-Qos packets. */ 271 if (!pattrib->qos_en) { 272 /* Hw set sequence number */ 273 ptxdesc->txdw4 |= cpu_to_le32(BIT(7)); 274 /* set bit3 to 1. */ 275 ptxdesc->txdw3 |= cpu_to_le32((8 << 28)); 276 } 277 278 /* offset 0 */ 279 ptxdesc->txdw0 |= cpu_to_le32(sz&0x0000ffff); 280 ptxdesc->txdw0 |= cpu_to_le32(OWN | FSG | LSG); 281 ptxdesc->txdw0 |= cpu_to_le32(((TXDESC_SIZE+OFFSET_SZ)<<OFFSET_SHT)&0x00ff0000);/* 32 bytes for TX Desc */ 282 283 if (bmcst) 284 ptxdesc->txdw0 |= cpu_to_le32(BIT(24)); 285 286 RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("offset0-txdesc = 0x%x\n", ptxdesc->txdw0)); 287 288 /* offset 4 */ 289 /* pkt_offset, unit:8 bytes padding */ 290 if (pxmitframe->pkt_offset > 0) 291 ptxdesc->txdw1 |= cpu_to_le32((pxmitframe->pkt_offset << 26) & 0x7c000000); 292 293 rtl8192cu_cal_txdesc_chksum(ptxdesc); 294 return pull; 295} 296 297static int rtw_dump_xframe(struct rtw_adapter *padapter, 298 struct xmit_frame *pxmitframe) 299{ 300 int ret = _SUCCESS; 301 int inner_ret = _SUCCESS; 302 int t, sz, w_sz, pull = 0; 303 u8 *mem_addr; 304 u32 ff_hwaddr; 305 struct xmit_buf *pxmitbuf = pxmitframe->pxmitbuf; 306 struct pkt_attrib *pattrib = &pxmitframe->attrib; 307 struct xmit_priv *pxmitpriv = &padapter->xmitpriv; 308 309 if ((pxmitframe->frame_tag == DATA_FRAMETAG) && 310 (pxmitframe->attrib.ether_type != 0x0806) && 311 (pxmitframe->attrib.ether_type != 0x888e) && 312 (pxmitframe->attrib.dhcp_pkt != 1)) 313 rtw_issue_addbareq_cmd23a(padapter, pxmitframe); 314 315 mem_addr = pxmitframe->buf_addr; 316 317 RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_dump_xframe()\n")); 318 319 for (t = 0; t < pattrib->nr_frags; t++) { 320 if (inner_ret != _SUCCESS && ret == _SUCCESS) 321 ret = _FAIL; 322 323 if (t != (pattrib->nr_frags - 1)) { 324 RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, 325 ("pattrib->nr_frags =%d\n", pattrib->nr_frags)); 326 327 sz = pxmitpriv->frag_len; 328 sz = sz - 4 - pattrib->icv_len; 329 } else { 330 /* no frag */ 331 sz = pattrib->last_txcmdsz; 332 } 333 334 pull = update_txdesc(pxmitframe, mem_addr, sz, false); 335 336 if (pull) { 337 mem_addr += PACKET_OFFSET_SZ; /* pull txdesc head */ 338 339 pxmitframe->buf_addr = mem_addr; 340 341 w_sz = sz + TXDESC_SIZE; 342 } else { 343 w_sz = sz + TXDESC_SIZE + PACKET_OFFSET_SZ; 344 } 345 346 ff_hwaddr = rtw_get_ff_hwaddr23a(pxmitframe); 347 inner_ret = rtl8723au_write_port(padapter, ff_hwaddr, 348 w_sz, pxmitbuf); 349 rtw_count_tx_stats23a(padapter, pxmitframe, sz); 350 351 RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, 352 ("rtw_write_port, w_sz =%d\n", w_sz)); 353 354 mem_addr += w_sz; 355 356 mem_addr = PTR_ALIGN(mem_addr, 4); 357 } 358 359 rtw_free_xmitframe23a(pxmitpriv, pxmitframe); 360 361 if (ret != _SUCCESS) 362 rtw23a_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_UNKNOWN); 363 364 return ret; 365} 366 367bool rtl8723au_xmitframe_complete(struct rtw_adapter *padapter, 368 struct xmit_priv *pxmitpriv, 369 struct xmit_buf *pxmitbuf) 370{ 371 struct hw_xmit *phwxmits; 372 struct xmit_frame *pxmitframe; 373 int hwentry; 374 int res = _SUCCESS, xcnt = 0; 375 376 phwxmits = pxmitpriv->hwxmits; 377 hwentry = pxmitpriv->hwxmit_entry; 378 379 RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("xmitframe_complete()\n")); 380 381 if (pxmitbuf == NULL) { 382 pxmitbuf = rtw_alloc_xmitbuf23a(pxmitpriv); 383 if (!pxmitbuf) 384 return false; 385 } 386 pxmitframe = rtw_dequeue_xframe23a(pxmitpriv, phwxmits, hwentry); 387 388 if (pxmitframe) { 389 pxmitframe->pxmitbuf = pxmitbuf; 390 391 pxmitframe->buf_addr = pxmitbuf->pbuf; 392 393 pxmitbuf->priv_data = pxmitframe; 394 395 if ((pxmitframe->frame_tag&0x0f) == DATA_FRAMETAG) { 396 if (pxmitframe->attrib.priority <= 15)/* TID0~15 */ 397 res = rtw_xmitframe_coalesce23a(padapter, pxmitframe->pkt, pxmitframe); 398 399 rtw_os_xmit_complete23a(padapter, pxmitframe);/* always return ndis_packet after rtw_xmitframe_coalesce23a */ 400 } 401 402 RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("xmitframe_complete(): rtw_dump_xframe\n")); 403 404 if (res == _SUCCESS) { 405 rtw_dump_xframe(padapter, pxmitframe); 406 } else { 407 rtw_free_xmitbuf23a(pxmitpriv, pxmitbuf); 408 rtw_free_xmitframe23a(pxmitpriv, pxmitframe); 409 } 410 xcnt++; 411 } else { 412 rtw_free_xmitbuf23a(pxmitpriv, pxmitbuf); 413 return false; 414 } 415 return true; 416} 417 418static int xmitframe_direct(struct rtw_adapter *padapter, 419 struct xmit_frame *pxmitframe) 420{ 421 int res; 422 423 res = rtw_xmitframe_coalesce23a(padapter, pxmitframe->pkt, pxmitframe); 424 if (res == _SUCCESS) 425 rtw_dump_xframe(padapter, pxmitframe); 426 return res; 427} 428 429/* 430 * Return 431 * true dump packet directly 432 * false enqueue packet 433 */ 434bool rtl8723au_hal_xmit(struct rtw_adapter *padapter, 435 struct xmit_frame *pxmitframe) 436{ 437 int res; 438 struct xmit_buf *pxmitbuf = NULL; 439 struct xmit_priv *pxmitpriv = &padapter->xmitpriv; 440 struct pkt_attrib *pattrib = &pxmitframe->attrib; 441 struct mlme_priv *pmlmepriv = &padapter->mlmepriv; 442 443 do_queue_select(padapter, pattrib); 444 spin_lock_bh(&pxmitpriv->lock); 445 446#ifdef CONFIG_8723AU_AP_MODE 447 if (xmitframe_enqueue_for_sleeping_sta23a(padapter, pxmitframe)) { 448 struct sta_info *psta; 449 struct sta_priv *pstapriv = &padapter->stapriv; 450 451 spin_unlock_bh(&pxmitpriv->lock); 452 453 if (pattrib->psta) 454 psta = pattrib->psta; 455 else 456 psta = rtw_get_stainfo23a(pstapriv, pattrib->ra); 457 458 if (psta) { 459 if (psta->sleepq_len > (NR_XMITFRAME>>3)) 460 wakeup_sta_to_xmit23a(padapter, psta); 461 } 462 463 return false; 464 } 465#endif 466 467 if (rtw_txframes_sta_ac_pending23a(padapter, pattrib) > 0) 468 goto enqueue; 469 470 if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY|_FW_UNDER_LINKING) == true) 471 goto enqueue; 472 473 pxmitbuf = rtw_alloc_xmitbuf23a(pxmitpriv); 474 if (pxmitbuf == NULL) 475 goto enqueue; 476 477 spin_unlock_bh(&pxmitpriv->lock); 478 479 pxmitframe->pxmitbuf = pxmitbuf; 480 pxmitframe->buf_addr = pxmitbuf->pbuf; 481 pxmitbuf->priv_data = pxmitframe; 482 483 if (xmitframe_direct(padapter, pxmitframe) != _SUCCESS) { 484 rtw_free_xmitbuf23a(pxmitpriv, pxmitbuf); 485 rtw_free_xmitframe23a(pxmitpriv, pxmitframe); 486 } 487 return true; 488 489enqueue: 490 res = rtw_xmitframe_enqueue23a(padapter, pxmitframe); 491 spin_unlock_bh(&pxmitpriv->lock); 492 493 if (res != _SUCCESS) { 494 RT_TRACE(_module_xmit_osdep_c_, _drv_err_, 495 ("pre_xmitframe: enqueue xmitframe fail\n")); 496 rtw_free_xmitframe23a(pxmitpriv, pxmitframe); 497 498 /* Trick, make the statistics correct */ 499 pxmitpriv->tx_pkts--; 500 pxmitpriv->tx_drop++; 501 return true; 502 } 503 return false; 504} 505 506int rtl8723au_mgnt_xmit(struct rtw_adapter *padapter, 507 struct xmit_frame *pmgntframe) 508{ 509 return rtw_dump_xframe(padapter, pmgntframe); 510} 511 512int rtl8723au_hal_xmitframe_enqueue(struct rtw_adapter *padapter, 513 struct xmit_frame *pxmitframe) 514{ 515 struct xmit_priv *pxmitpriv = &padapter->xmitpriv; 516 int err; 517 518 err = rtw_xmitframe_enqueue23a(padapter, pxmitframe); 519 if (err != _SUCCESS) { 520 rtw_free_xmitframe23a(pxmitpriv, pxmitframe); 521 522 /* Trick, make the statistics correct */ 523 pxmitpriv->tx_pkts--; 524 pxmitpriv->tx_drop++; 525 } else { 526 tasklet_hi_schedule(&pxmitpriv->xmit_tasklet); 527 } 528 return err; 529} 530