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
do_queue_select(struct rtw_adapter * padapter,struct pkt_attrib * pattrib)24 static 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
urb_zero_packet_chk(struct rtw_adapter * padapter,int sz)36 static 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
rtl8192cu_cal_txdesc_chksum(struct tx_desc * ptxdesc)55 static 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
fill_txdesc_sectype(struct pkt_attrib * pattrib,struct tx_desc * ptxdesc)71 static 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
fill_txdesc_vcs(struct pkt_attrib * pattrib,u32 * pdw)94 static 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
fill_txdesc_phy(struct pkt_attrib * pattrib,u32 * pdw)129 static 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
update_txdesc(struct xmit_frame * pxmitframe,u8 * pmem,s32 sz,u8 bagg_pkt)145 static 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
rtw_dump_xframe(struct rtw_adapter * padapter,struct xmit_frame * pxmitframe)297 static 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
rtl8723au_xmitframe_complete(struct rtw_adapter * padapter,struct xmit_priv * pxmitpriv,struct xmit_buf * pxmitbuf)367 bool 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
xmitframe_direct(struct rtw_adapter * padapter,struct xmit_frame * pxmitframe)418 static 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 */
rtl8723au_hal_xmit(struct rtw_adapter * padapter,struct xmit_frame * pxmitframe)434 bool 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
489 enqueue:
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
rtl8723au_mgnt_xmit(struct rtw_adapter * padapter,struct xmit_frame * pmgntframe)506 int rtl8723au_mgnt_xmit(struct rtw_adapter *padapter,
507 struct xmit_frame *pmgntframe)
508 {
509 return rtw_dump_xframe(padapter, pmgntframe);
510 }
511
rtl8723au_hal_xmitframe_enqueue(struct rtw_adapter * padapter,struct xmit_frame * pxmitframe)512 int 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