/*
 * Description:
 *	Aggregation packets and send to hardware
 *
 * Return:
 *	0	Success
 *	-1	Hardware resource(TX FIFO) not ready
 *	-2	Software resource(xmitbuf) not ready
 */
static s32 xmit_xmitframes(PADAPTER padapter, struct xmit_priv *pxmitpriv)
{
	s32 err, ret;
	u32 k;
	struct hw_xmit *hwxmits;
	u8 no_res, idx, hwentry;
	_irqL irql;
//	_irqL irqL0, irqL1;
	struct tx_servq *ptxservq;
	_list *sta_plist, *sta_phead, *frame_plist, *frame_phead;
	struct xmit_frame *pxmitframe;
	_queue *pframe_queue;
	struct xmit_buf *pxmitbuf;
	u32 txlen;


	err = 0;
	no_res = _FALSE;
	hwxmits = pxmitpriv->hwxmits;
	hwentry = pxmitpriv->hwxmit_entry;
	ptxservq = NULL;
	pxmitframe = NULL;
	pframe_queue = NULL;
	pxmitbuf = NULL;

	// 0(VO), 1(VI), 2(BE), 3(BK)
	for (idx = 0; idx < hwentry; idx++, hwxmits++)
	{
//		_enter_critical(&hwxmits->sta_queue->lock, &irqL0);
		_enter_critical_bh(&pxmitpriv->lock, &irql);

		sta_phead = get_list_head(hwxmits->sta_queue);
		sta_plist = get_next(sta_phead);

		while (rtw_end_of_queue_search(sta_phead, sta_plist) == _FALSE)
		{
			ptxservq = LIST_CONTAINOR(sta_plist, struct tx_servq, tx_pending);
			sta_plist = get_next(sta_plist);

			pframe_queue = &ptxservq->sta_pending;

//			_enter_critical(&pframe_queue->lock, &irqL1);
			//_enter_critical_bh(&pxmitpriv->lock, &irql);

			frame_phead = get_list_head(pframe_queue);

			while (rtw_is_list_empty(frame_phead) == _FALSE)
			{
				frame_plist = get_next(frame_phead);
				pxmitframe = LIST_CONTAINOR(frame_plist, struct xmit_frame, list);

				// check xmit_buf size enough or not
				txlen = TXDESC_SIZE + rtw_wlan_pkt_size(pxmitframe);
				if ((NULL == pxmitbuf) ||
					((pxmitbuf->ptail + txlen) > pxmitbuf->pend)
#ifdef SDIO_TX_AGG_MAX
					|| (k >= SDIO_TX_AGG_MAX)
#endif
					)
				{
					if (pxmitbuf) {
						struct xmit_frame *pframe;
						pframe = (struct xmit_frame*)pxmitbuf->priv_data;
						pframe->agg_num = k;
						pxmitbuf->agg_num = k;
						rtl8723a_update_txdesc(pframe, pframe->buf_addr);
						rtw_free_xmitframe(pxmitpriv, pframe);
						pxmitbuf->priv_data = NULL;
						enqueue_pending_xmitbuf(pxmitpriv, pxmitbuf);
						//rtw_yield_os();
					}

					pxmitbuf = rtw_alloc_xmitbuf(pxmitpriv);
					if (pxmitbuf == NULL) {
						RT_TRACE(_module_hal_xmit_c_, _drv_err_, ("%s: xmit_buf is not enough!\n", __FUNCTION__));
						err = -2;
						break;
					}
					k = 0;
				}

				// ok to send, remove frame from queue
				//_enter_critical_bh(&pxmitpriv->lock, &irql);
#ifdef CONFIG_AP_MODE
				if (check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE) == _TRUE)
				{
					if ((pxmitframe->attrib.psta->state & WIFI_SLEEP_STATE) &&
						(pxmitframe->attrib.triggered == 0))
					{
						//_exit_critical_bh(&pxmitpriv->lock, &irql);
						
						DBG_8192C("%s: one not triggered pkt in queue when STA sleep\n", __func__);
						break;
					}
				}
#endif
				rtw_list_delete(&pxmitframe->list);
				ptxservq->qcnt--;
				hwxmits->accnt--;
				

				if (k == 0) {
					pxmitbuf->ff_hwaddr = rtw_get_ff_hwaddr(pxmitframe);
					pxmitbuf->priv_data = (u8*)pxmitframe;
				}

				// coalesce the xmitframe to xmitbuf
				pxmitframe->pxmitbuf = pxmitbuf;
				pxmitframe->buf_addr = pxmitbuf->ptail;

				ret = rtw_xmitframe_coalesce(padapter, pxmitframe->pkt, pxmitframe);
				if (ret == _FAIL) {
					RT_TRACE(_module_hal_xmit_c_, _drv_err_, ("%s: coalesce FAIL!", __FUNCTION__));
					// Todo: error handler
					DBG_871X("%s: coalesce FAIL!", __FUNCTION__);
				} else {
					k++;
					if (k != 1)
						rtl8723a_update_txdesc(pxmitframe, pxmitframe->buf_addr);
					rtw_count_tx_stats(padapter, pxmitframe, pxmitframe->attrib.last_txcmdsz);

					txlen = TXDESC_SIZE + pxmitframe->attrib.last_txcmdsz;
					pxmitframe->pg_num = (txlen + 127)/128;
					pxmitbuf->pg_num += (txlen + 127)/128;					
					//if (k != 1)
					//	((struct xmit_frame*)pxmitbuf->priv_data)->pg_num += pxmitframe->pg_num;
					pxmitbuf->ptail += _RND(txlen, 8); // round to 8 bytes alignment
					pxmitbuf->len = _RND(pxmitbuf->len, 8) + txlen;
				}

				if (k != 1)
					rtw_free_xmitframe(pxmitpriv, pxmitframe);
				pxmitframe = NULL;
			}

			//_enter_critical_bh(&pxmitpriv->lock, &irql);
			if (_rtw_queue_empty(pframe_queue) == _TRUE)
				rtw_list_delete(&ptxservq->tx_pending);
			//_exit_critical_bh(&pxmitpriv->lock, &irql);

//			_exit_critical(&pframe_queue->lock, &irqL1);
			//_exit_critical_bh(&pxmitpriv->lock, &irql);

			if (err) break;
		}

//		_exit_critical(&hwxmits->sta_queue->lock, &irqL0);
		_exit_critical_bh(&pxmitpriv->lock, &irql);

		// dump xmit_buf to hw tx fifo
		if (pxmitbuf)
		{
			RT_TRACE(_module_hal_xmit_c_, _drv_notice_, ("pxmitbuf->len=%d enqueue\n",pxmitbuf->len));

			if (pxmitbuf->len > 0) {
				struct xmit_frame *pframe;
				pframe = (struct xmit_frame*)pxmitbuf->priv_data;
				pframe->agg_num = k;
				pxmitbuf->agg_num = k;
				rtl8723a_update_txdesc(pframe, pframe->buf_addr);
				rtw_free_xmitframe(pxmitpriv, pframe);
				pxmitbuf->priv_data = NULL;
				enqueue_pending_xmitbuf(pxmitpriv, pxmitbuf);
				rtw_yield_os();
			}
			else
				rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
			
			pxmitbuf = NULL;
		}

		if (err) break;
	}

	return err;
}
/*
 * Description:
 *	Aggregation packets and send to hardware
 *
 * Return:
 *	0	Success
 *	-1	Hardware resource(TX FIFO) not ready
 *	-2	Software resource(xmitbuf) not ready
 */
static s32 xmit_xmitframes(PADAPTER padapter, struct xmit_priv *pxmitpriv)
{
    s32 err, ret;
    u32 k=0;
    struct hw_xmit *hwxmits, *phwxmit;
    u8 no_res, idx, hwentry;
    _irqL irql;
    struct tx_servq *ptxservq;
    _list *sta_plist, *sta_phead, *frame_plist, *frame_phead;
    struct xmit_frame *pxmitframe;
    _queue *pframe_queue;
    struct xmit_buf *pxmitbuf;
    u32 txlen;
    u8 txdesc_size = TXDESC_SIZE;
    int inx[4];

    err = 0;
    no_res = _FALSE;
    hwxmits = pxmitpriv->hwxmits;
    hwentry = pxmitpriv->hwxmit_entry;
    ptxservq = NULL;
    pxmitframe = NULL;
    pframe_queue = NULL;
    pxmitbuf = NULL;

    if (padapter->registrypriv.wifi_spec == 1) {
        for(idx=0; idx<4; idx++)
            inx[idx] = pxmitpriv->wmm_para_seq[idx];
    } else {
        inx[0] = 0;
        inx[1] = 1;
        inx[2] = 2;
        inx[3] = 3;
    }

    // 0(VO), 1(VI), 2(BE), 3(BK)
    for (idx = 0; idx < hwentry; idx++)
    {
        phwxmit = hwxmits + inx[idx];

        if((check_pending_xmitbuf(pxmitpriv) == _TRUE) && (padapter->mlmepriv.LinkDetectInfo.bHigherBusyTxTraffic == _TRUE)) {
            if ((phwxmit->accnt > 0) && (phwxmit->accnt < 5)) {
                err = -2;
                break;
            }
        }

        _enter_critical_bh(&pxmitpriv->lock, &irql);

        sta_phead = get_list_head(phwxmit->sta_queue);
        sta_plist = get_next(sta_phead);
        //because stop_sta_xmit may delete sta_plist at any time
        //so we should add lock here, or while loop can not exit
        while (rtw_end_of_queue_search(sta_phead, sta_plist) == _FALSE)
        {
            ptxservq = LIST_CONTAINOR(sta_plist, struct tx_servq, tx_pending);
            sta_plist = get_next(sta_plist);

#ifdef DBG_XMIT_BUF
            DBG_871X("%s idx:%d hwxmit_pkt_num:%d ptxservq_pkt_num:%d\n", __func__, idx, phwxmit->accnt, ptxservq->qcnt);
            DBG_871X("%s free_xmit_extbuf_cnt=%d free_xmitbuf_cnt=%d free_xmitframe_cnt=%d \n",
                     __func__, pxmitpriv->free_xmit_extbuf_cnt, pxmitpriv->free_xmitbuf_cnt,
                     pxmitpriv->free_xmitframe_cnt);
#endif
            pframe_queue = &ptxservq->sta_pending;

            frame_phead = get_list_head(pframe_queue);

            while (rtw_is_list_empty(frame_phead) == _FALSE)
            {
                frame_plist = get_next(frame_phead);
                pxmitframe = LIST_CONTAINOR(frame_plist, struct xmit_frame, list);

                // check xmit_buf size enough or not
                txlen = txdesc_size + rtw_wlan_pkt_size(pxmitframe);
                if ((NULL == pxmitbuf) ||
                        ((pxmitbuf->ptail + txlen) > pxmitbuf->pend)
#ifdef SDIO_TX_AGG_MAX
                        || (k >= SDIO_TX_AGG_MAX)
#endif
                   )
                {
                    if (pxmitbuf)
                    {
                        //pxmitbuf->priv_data will be NULL, and will crash here
                        if (pxmitbuf->len > 0 && pxmitbuf->priv_data)
                        {
                            struct xmit_frame *pframe;
                            pframe = (struct xmit_frame*)pxmitbuf->priv_data;
                            pframe->agg_num = k;
                            pxmitbuf->agg_num = k;
                            rtl8723b_update_txdesc(pframe, pframe->buf_addr);
                            rtw_free_xmitframe(pxmitpriv, pframe);
                            pxmitbuf->priv_data = NULL;
                            enqueue_pending_xmitbuf(pxmitpriv, pxmitbuf);
                            //can not yield under lock
                            //rtw_yield_os();
                        } else {
                            rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
                        }
                    }

                    pxmitbuf = rtw_alloc_xmitbuf(pxmitpriv);
                    if (pxmitbuf == NULL) {
#ifdef DBG_XMIT_BUF
                        DBG_871X_LEVEL(_drv_err_, "%s: xmit_buf is not enough!\n", __FUNCTION__);
#endif
                        err = -2;
                        break;
                    }
                    k = 0;
                }

                // ok to send, remove frame from queue
#ifdef CONFIG_AP_MODE
                if (check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE) == _TRUE) {
                    if ((pxmitframe->attrib.psta->state & WIFI_SLEEP_STATE) &&
                            (pxmitframe->attrib.triggered == 0)) {
                        DBG_871X("%s: one not triggered pkt in queue when this STA sleep,"
                                 " break and goto next sta\n", __func__);
                        break;
                    }
                }
#endif
                rtw_list_delete(&pxmitframe->list);
                ptxservq->qcnt--;
                phwxmit->accnt--;

                if (k == 0) {
                    pxmitbuf->ff_hwaddr = rtw_get_ff_hwaddr(pxmitframe);
                    pxmitbuf->priv_data = (u8*)pxmitframe;
                }

                // coalesce the xmitframe to xmitbuf
                pxmitframe->pxmitbuf = pxmitbuf;
                pxmitframe->buf_addr = pxmitbuf->ptail;

                ret = rtw_xmitframe_coalesce(padapter, pxmitframe->pkt, pxmitframe);
                if (ret == _FAIL) {
                    DBG_871X_LEVEL(_drv_err_, "%s: coalesce FAIL!", __FUNCTION__);
                    // Todo: error handler
                } else {
                    k++;
                    if (k != 1)
                        rtl8723b_update_txdesc(pxmitframe, pxmitframe->buf_addr);
                    rtw_count_tx_stats(padapter, pxmitframe, pxmitframe->attrib.last_txcmdsz);

                    txlen = txdesc_size + pxmitframe->attrib.last_txcmdsz;
                    pxmitframe->pg_num = (txlen + 127)/128;
                    pxmitbuf->pg_num += (txlen + 127)/128;
                    //if (k != 1)
                    //	((struct xmit_frame*)pxmitbuf->priv_data)->pg_num += pxmitframe->pg_num;
                    pxmitbuf->ptail += _RND(txlen, 8); // round to 8 bytes alignment
                    pxmitbuf->len = _RND(pxmitbuf->len, 8) + txlen;
                }

                if (k != 1)
                    rtw_free_xmitframe(pxmitpriv, pxmitframe);
                pxmitframe = NULL;
            }

            if (_rtw_queue_empty(pframe_queue) == _TRUE)
                rtw_list_delete(&ptxservq->tx_pending);

            if (err) break;
        }
        _exit_critical_bh(&pxmitpriv->lock, &irql);

        // dump xmit_buf to hw tx fifo
        if (pxmitbuf)
        {
            RT_TRACE(_module_hal_xmit_c_, _drv_info_, ("pxmitbuf->len=%d enqueue\n",pxmitbuf->len));

            if (pxmitbuf->len > 0) {
                struct xmit_frame *pframe;
                pframe = (struct xmit_frame*)pxmitbuf->priv_data;
                pframe->agg_num = k;
                pxmitbuf->agg_num = k;
                rtl8723b_update_txdesc(pframe, pframe->buf_addr);
                rtw_free_xmitframe(pxmitpriv, pframe);
                pxmitbuf->priv_data = NULL;
                enqueue_pending_xmitbuf(pxmitpriv, pxmitbuf);
                rtw_yield_os();
            }
            else
                rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
            pxmitbuf = NULL;
        }

        if (err) break;
    }

    return err;
}
Exemple #3
0
/*
 * Description:
 *Aggregation packets and send to hardware
 *
 * Return:
 *0	Success
 *-1	Hardware resource(TX FIFO) not ready
 *-2	Software resource(xmitbuf) not ready
 */
static s32 xmit_xmitframes(struct adapter *padapter, struct xmit_priv *pxmitpriv)
{
	s32 err, ret;
	u32 k = 0;
	struct hw_xmit *hwxmits, *phwxmit;
	u8 no_res, idx, hwentry;
	struct tx_servq *ptxservq;
	struct list_head *sta_plist, *sta_phead, *frame_plist, *frame_phead;
	struct xmit_frame *pxmitframe;
	struct __queue *pframe_queue;
	struct xmit_buf *pxmitbuf;
	u32 txlen, max_xmit_len;
	u8 txdesc_size = TXDESC_SIZE;
	int inx[4];

	err = 0;
	no_res = false;
	hwxmits = pxmitpriv->hwxmits;
	hwentry = pxmitpriv->hwxmit_entry;
	ptxservq = NULL;
	pxmitframe = NULL;
	pframe_queue = NULL;
	pxmitbuf = NULL;

	if (padapter->registrypriv.wifi_spec == 1) {
		for (idx = 0; idx < 4; idx++)
			inx[idx] = pxmitpriv->wmm_para_seq[idx];
	} else {
		inx[0] = 0;
		inx[1] = 1;
		inx[2] = 2;
		inx[3] = 3;
	}

	/*  0(VO), 1(VI), 2(BE), 3(BK) */
	for (idx = 0; idx < hwentry; idx++) {
		phwxmit = hwxmits + inx[idx];

		if (
			(check_pending_xmitbuf(pxmitpriv) == true) &&
			(padapter->mlmepriv.LinkDetectInfo.bHigherBusyTxTraffic == true)
		) {
			if ((phwxmit->accnt > 0) && (phwxmit->accnt < 5)) {
				err = -2;
				break;
			}
		}

		max_xmit_len = rtw_hal_get_sdio_tx_max_length(padapter, inx[idx]);

		spin_lock_bh(&pxmitpriv->lock);

		sta_phead = get_list_head(phwxmit->sta_queue);
		sta_plist = get_next(sta_phead);
		/* because stop_sta_xmit may delete sta_plist at any time */
		/* so we should add lock here, or while loop can not exit */
		while (sta_phead != sta_plist) {
			ptxservq = LIST_CONTAINOR(sta_plist, struct tx_servq, tx_pending);
			sta_plist = get_next(sta_plist);

#ifdef DBG_XMIT_BUF
			DBG_871X(
				"%s idx:%d hwxmit_pkt_num:%d ptxservq_pkt_num:%d\n",
				__func__,
				idx,
				phwxmit->accnt,
				ptxservq->qcnt
			);
			DBG_871X(
				"%s free_xmit_extbuf_cnt =%d free_xmitbuf_cnt =%d free_xmitframe_cnt =%d\n",
				__func__,
				pxmitpriv->free_xmit_extbuf_cnt,
				pxmitpriv->free_xmitbuf_cnt,
				pxmitpriv->free_xmitframe_cnt
			);
#endif
			pframe_queue = &ptxservq->sta_pending;

			frame_phead = get_list_head(pframe_queue);

			while (list_empty(frame_phead) == false) {
				frame_plist = get_next(frame_phead);
				pxmitframe = LIST_CONTAINOR(frame_plist, struct xmit_frame, list);

				/*  check xmit_buf size enough or not */
				txlen = txdesc_size + rtw_wlan_pkt_size(pxmitframe);
				if (
					(NULL == pxmitbuf) ||
					((_RND(pxmitbuf->len, 8) + txlen) > max_xmit_len) ||
					(k >= (rtw_hal_sdio_max_txoqt_free_space(padapter)-1))
				) {
					if (pxmitbuf) {
						/* pxmitbuf->priv_data will be NULL, and will crash here */
						if (pxmitbuf->len > 0 &&
						    pxmitbuf->priv_data) {
							struct xmit_frame *pframe;
							pframe = (struct xmit_frame *)pxmitbuf->priv_data;
							pframe->agg_num = k;
							pxmitbuf->agg_num = k;
							rtl8723b_update_txdesc(pframe, pframe->buf_addr);
							rtw_free_xmitframe(pxmitpriv, pframe);
							pxmitbuf->priv_data = NULL;
							enqueue_pending_xmitbuf(pxmitpriv, pxmitbuf);
							/* can not yield under lock */
							/* yield(); */
						} else
							rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
					}

					pxmitbuf = rtw_alloc_xmitbuf(pxmitpriv);
					if (pxmitbuf == NULL) {
#ifdef DBG_XMIT_BUF
						DBG_871X_LEVEL(_drv_err_, "%s: xmit_buf is not enough!\n", __func__);
#endif
						err = -2;
						up(&(pxmitpriv->xmit_sema));
						break;
					}
					k = 0;
				}

				/*  ok to send, remove frame from queue */
				if (check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE) == true) {
					if (
						(pxmitframe->attrib.psta->state & WIFI_SLEEP_STATE) &&
						(pxmitframe->attrib.triggered == 0)
					) {
						DBG_871X(
							"%s: one not triggered pkt in queue when this STA sleep,"
							" break and goto next sta\n",
							__func__
						);
						break;
					}
				}

				list_del_init(&pxmitframe->list);
				ptxservq->qcnt--;
				phwxmit->accnt--;

				if (k == 0) {
					pxmitbuf->ff_hwaddr = rtw_get_ff_hwaddr(pxmitframe);
					pxmitbuf->priv_data = (u8 *)pxmitframe;
				}

				/*  coalesce the xmitframe to xmitbuf */
				pxmitframe->pxmitbuf = pxmitbuf;
				pxmitframe->buf_addr = pxmitbuf->ptail;

				ret = rtw_xmitframe_coalesce(padapter, pxmitframe->pkt, pxmitframe);
				if (ret == _FAIL) {
					DBG_871X_LEVEL(_drv_err_, "%s: coalesce FAIL!", __func__);
					/*  Todo: error handler */
				} else {
					k++;
					if (k != 1)
						rtl8723b_update_txdesc(pxmitframe, pxmitframe->buf_addr);
					rtw_count_tx_stats(padapter, pxmitframe, pxmitframe->attrib.last_txcmdsz);

					txlen = txdesc_size + pxmitframe->attrib.last_txcmdsz;
					pxmitframe->pg_num = (txlen + 127)/128;
					pxmitbuf->pg_num += (txlen + 127)/128;
				    /* if (k != 1) */
					/* 	((struct xmit_frame*)pxmitbuf->priv_data)->pg_num += pxmitframe->pg_num; */
					pxmitbuf->ptail += _RND(txlen, 8); /*  round to 8 bytes alignment */
					pxmitbuf->len = _RND(pxmitbuf->len, 8) + txlen;
				}

				if (k != 1)
					rtw_free_xmitframe(pxmitpriv, pxmitframe);
				pxmitframe = NULL;
			}

			if (list_empty(&pframe_queue->queue))
				list_del_init(&ptxservq->tx_pending);

			if (err)
				break;
		}
		spin_unlock_bh(&pxmitpriv->lock);

		/*  dump xmit_buf to hw tx fifo */
		if (pxmitbuf) {
			RT_TRACE(_module_hal_xmit_c_, _drv_info_, ("pxmitbuf->len =%d enqueue\n", pxmitbuf->len));

			if (pxmitbuf->len > 0) {
				struct xmit_frame *pframe;
				pframe = (struct xmit_frame *)pxmitbuf->priv_data;
				pframe->agg_num = k;
				pxmitbuf->agg_num = k;
				rtl8723b_update_txdesc(pframe, pframe->buf_addr);
				rtw_free_xmitframe(pxmitpriv, pframe);
				pxmitbuf->priv_data = NULL;
				enqueue_pending_xmitbuf(pxmitpriv, pxmitbuf);
				yield();
			} else
				rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
			pxmitbuf = NULL;
		}

		if (err)
			break;
	}

	return err;
}