// SPDX-License-Identifier: GPL-2.0
/******************************************************************************
* rtl871x_xmit.c
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
* Linux device driver for RTL8192SU
*
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
* Contact information:
* WLAN FAE <wlanfae@realtek.com>
* Larry Finger <Larry.Finger@lwfinger.net>
*
******************************************************************************/
#define _RTL871X_XMIT_C_
#include "osdep_service.h"
#include "drv_types.h"
#include "osdep_intf.h"
#include "usb_ops.h"
#include <linux/usb.h>
#include <linux/ieee80211.h>
static const u8 P802_1H_OUI[P80211_OUI_LEN] = {0x00, 0x00, 0xf8};
static const u8 RFC1042_OUI[P80211_OUI_LEN] = {0x00, 0x00, 0x00};
static void init_hwxmits(struct hw_xmit *phwxmit, sint entry);
static void alloc_hwxmits(struct _adapter *padapter);
static void free_hwxmits(struct _adapter *padapter);
static void _init_txservq(struct tx_servq *ptxservq)
{
INIT_LIST_HEAD(&ptxservq->tx_pending);
_init_queue(&ptxservq->sta_pending);
ptxservq->qcnt = 0;
}
void _r8712_init_sta_xmit_priv(struct sta_xmit_priv *psta_xmitpriv)
{
memset((unsigned char *)psta_xmitpriv, 0,
sizeof(struct sta_xmit_priv));
spin_lock_init(&psta_xmitpriv->lock);
_init_txservq(&psta_xmitpriv->be_q);
_init_txservq(&psta_xmitpriv->bk_q);
_init_txservq(&psta_xmitpriv->vi_q);
_init_txservq(&psta_xmitpriv->vo_q);
INIT_LIST_HEAD(&psta_xmitpriv->legacy_dz);
INIT_LIST_HEAD(&psta_xmitpriv->apsd);
}
int _r8712_init_xmit_priv(struct xmit_priv *pxmitpriv,
struct _adapter *padapter)
{
sint i;
struct xmit_buf *pxmitbuf;
struct xmit_frame *pxframe;
int j;
memset((unsigned char *)pxmitpriv, 0, sizeof(struct xmit_priv));
spin_lock_init(&pxmitpriv->lock);
/*
*Please insert all the queue initialization using _init_queue below
*/
pxmitpriv->adapter = padapter;
_init_queue(&pxmitpriv->be_pending);
_init_queue(&pxmitpriv->bk_pending);
_init_queue(&pxmitpriv->vi_pending);
_init_queue(&pxmitpriv->vo_pending);
_init_queue(&pxmitpriv->bm_pending);
_init_queue(&pxmitpriv->legacy_dz_queue);
_init_queue(&pxmitpriv->apsd_queue);
_init_queue(&pxmitpriv->free_xmit_queue);
/*
* Please allocate memory with sz = (struct xmit_frame) * NR_XMITFRAME,
* and initialize free_xmit_frame below.
* Please also apply free_txobj to link_up all the xmit_frames...
*/
pxmitpriv->pallocated_frame_buf =
kmalloc(NR_XMITFRAME * sizeof(struct xmit_frame) + 4,
GFP_ATOMIC);
if (!pxmitpriv->pallocated_frame_buf) {
pxmitpriv->pxmit_frame_buf = NULL;
return -ENOMEM;
}
pxmitpriv->pxmit_frame_buf = pxmitpriv->pallocated_frame_buf + 4 -
((addr_t) (pxmitpriv->pallocated_frame_buf) & 3);
pxframe = (struct xmit_frame *) pxmitpriv->pxmit_frame_buf;
for (i = 0; i < NR_XMITFRAME; i++) {
INIT_LIST_HEAD(&(pxframe->list));
pxframe->padapter = padapter;
pxframe->frame_tag = DATA_FRAMETAG;
pxframe->pkt = NULL;
pxframe->buf_addr = NULL;
pxframe->pxmitbuf = NULL;
list_add_tail(&(pxframe->list),
&(pxmitpriv->free_xmit_queue.queue));
pxframe++;
}
pxmitpriv->free_xmitframe_cnt = NR_XMITFRAME;
/*
* init xmit hw_txqueue
*/
_r8712_init_hw_txqueue(&pxmitpriv->be_txqueue, BE_QUEUE_INX);
_r8712_init_hw_txqueue(&pxmitpriv->bk_txqueue, BK_QUEUE_INX);
_r8712_init_hw_txqueue(&pxmitpriv->vi_txqueue, VI_QUEUE_INX);
_r8712_init_hw_txqueue(&pxmitpriv->vo_txqueue, VO_QUEUE_INX);
_r8712_init_hw_txqueue(&pxmitpriv->bmc_txqueue, BMC_QUEUE_INX);
pxmitpriv->frag_len = MAX_FRAG_THRESHOLD;
pxmitpriv->txirp_cnt = 1;
/*per AC pending irp*/
pxmitpriv->beq_cnt = 0;
pxmitpriv->bkq_cnt = 0;
pxmitpriv->viq_cnt = 0;
pxmitpriv->voq_cnt = 0;
/*init xmit_buf*/
_init_queue(&pxmitpriv->free_xmitbuf_queue);
_init_queue(&pxmitpriv->pending_xmitbuf_queue);
pxmitpriv->pxmitbuf = kmalloc(NR_XMITBUFF * sizeof(struct xmit_buf), GFP_ATOMIC);
if (!pxmitpriv->pxmitbuf)
goto clean_up_frame_buf;
pxmitbuf = (struct xmit_buf *)pxmitpriv->pxmitbuf;
for (i = 0; i < NR_XMITBUFF; i++) {
INIT_LIST_HEAD(&pxmitbuf->list);
pxmitbuf->pallocated_buf =
kmalloc(MAX_XMITBUF_SZ + XMITBUF_ALIGN_SZ, GFP_ATOMIC);
if (!pxmitbuf->pallocated_buf) {
j = 0;
goto clean_up_alloc_buf;
}
pxmitbuf->pbuf = pxmitbuf->pallocated_buf + XMITBUF_ALIGN_SZ -
((addr_t) (pxmitbuf->pallocated_buf) &
(XMITBUF_ALIGN_SZ - 1));
if (r8712_xmit_resource_alloc(padapter, pxmitbuf)) {
j = 1;
goto