xref: /linux/drivers/staging/rtl8723bs/os_dep/xmit_linux.c (revision 3a39d672e7f48b8d6b91a09afa4b55352773b4b5)
1 // SPDX-License-Identifier: GPL-2.0
2 /******************************************************************************
3  *
4  * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
5  *
6  ******************************************************************************/
7 #include <drv_types.h>
8 
9 
rtw_remainder_len(struct pkt_file * pfile)10 uint rtw_remainder_len(struct pkt_file *pfile)
11 {
12 	return (pfile->buf_len - ((SIZE_PTR)(pfile->cur_addr) - (SIZE_PTR)(pfile->buf_start)));
13 }
14 
_rtw_open_pktfile(struct sk_buff * pktptr,struct pkt_file * pfile)15 void _rtw_open_pktfile(struct sk_buff *pktptr, struct pkt_file *pfile)
16 {
17 	pfile->pkt = pktptr;
18 	pfile->cur_addr = pfile->buf_start = pktptr->data;
19 	pfile->pkt_len = pfile->buf_len = pktptr->len;
20 
21 	pfile->cur_buffer = pfile->buf_start;
22 }
23 
_rtw_pktfile_read(struct pkt_file * pfile,u8 * rmem,uint rlen)24 uint _rtw_pktfile_read(struct pkt_file *pfile, u8 *rmem, uint rlen)
25 {
26 	uint	len = 0;
27 
28 	len =  rtw_remainder_len(pfile);
29 	len = (rlen > len) ? len : rlen;
30 
31 	if (rmem)
32 		skb_copy_bits(pfile->pkt, pfile->buf_len - pfile->pkt_len, rmem, len);
33 
34 	pfile->cur_addr += len;
35 	pfile->pkt_len -= len;
36 	return len;
37 }
38 
rtw_endofpktfile(struct pkt_file * pfile)39 signed int rtw_endofpktfile(struct pkt_file *pfile)
40 {
41 	if (pfile->pkt_len == 0)
42 		return true;
43 	return false;
44 }
45 
rtw_os_xmit_resource_alloc(struct adapter * padapter,struct xmit_buf * pxmitbuf,u32 alloc_sz,u8 flag)46 int rtw_os_xmit_resource_alloc(struct adapter *padapter, struct xmit_buf *pxmitbuf, u32 alloc_sz, u8 flag)
47 {
48 	if (alloc_sz > 0) {
49 		pxmitbuf->pallocated_buf = rtw_zmalloc(alloc_sz);
50 		if (!pxmitbuf->pallocated_buf)
51 			return _FAIL;
52 
53 		pxmitbuf->pbuf = (u8 *)N_BYTE_ALIGMENT((SIZE_PTR)(pxmitbuf->pallocated_buf), XMITBUF_ALIGN_SZ);
54 	}
55 
56 	return _SUCCESS;
57 }
58 
rtw_os_xmit_resource_free(struct adapter * padapter,struct xmit_buf * pxmitbuf,u32 free_sz,u8 flag)59 void rtw_os_xmit_resource_free(struct adapter *padapter, struct xmit_buf *pxmitbuf, u32 free_sz, u8 flag)
60 {
61 	if (free_sz > 0)
62 		kfree(pxmitbuf->pallocated_buf);
63 }
64 
65 #define WMM_XMIT_THRESHOLD	(NR_XMITFRAME * 2 / 5)
66 
rtw_os_pkt_complete(struct adapter * padapter,struct sk_buff * pkt)67 void rtw_os_pkt_complete(struct adapter *padapter, struct sk_buff *pkt)
68 {
69 	u16 queue;
70 	struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
71 
72 	queue = skb_get_queue_mapping(pkt);
73 	if (padapter->registrypriv.wifi_spec) {
74 		if (__netif_subqueue_stopped(padapter->pnetdev, queue) &&
75 		    (pxmitpriv->hwxmits[queue].accnt < WMM_XMIT_THRESHOLD))
76 			netif_wake_subqueue(padapter->pnetdev, queue);
77 	} else {
78 		if (__netif_subqueue_stopped(padapter->pnetdev, queue))
79 			netif_wake_subqueue(padapter->pnetdev, queue);
80 	}
81 
82 	dev_kfree_skb_any(pkt);
83 }
84 
rtw_os_xmit_complete(struct adapter * padapter,struct xmit_frame * pxframe)85 void rtw_os_xmit_complete(struct adapter *padapter, struct xmit_frame *pxframe)
86 {
87 	if (pxframe->pkt)
88 		rtw_os_pkt_complete(padapter, pxframe->pkt);
89 
90 	pxframe->pkt = NULL;
91 }
92 
rtw_os_xmit_schedule(struct adapter * padapter)93 void rtw_os_xmit_schedule(struct adapter *padapter)
94 {
95 	struct adapter *pri_adapter = padapter;
96 
97 	if (!padapter)
98 		return;
99 
100 	if (!list_empty(&padapter->xmitpriv.pending_xmitbuf_queue.queue))
101 		complete(&pri_adapter->xmitpriv.xmit_comp);
102 }
103 
rtw_check_xmit_resource(struct adapter * padapter,struct sk_buff * pkt)104 static void rtw_check_xmit_resource(struct adapter *padapter, struct sk_buff *pkt)
105 {
106 	struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
107 	u16 queue;
108 
109 	queue = skb_get_queue_mapping(pkt);
110 	if (padapter->registrypriv.wifi_spec) {
111 		/* No free space for Tx, tx_worker is too slow */
112 		if (pxmitpriv->hwxmits[queue].accnt > WMM_XMIT_THRESHOLD)
113 			netif_stop_subqueue(padapter->pnetdev, queue);
114 	} else {
115 		if (pxmitpriv->free_xmitframe_cnt <= 4) {
116 			if (!netif_tx_queue_stopped(netdev_get_tx_queue(padapter->pnetdev, queue)))
117 				netif_stop_subqueue(padapter->pnetdev, queue);
118 		}
119 	}
120 }
121 
rtw_mlcst2unicst(struct adapter * padapter,struct sk_buff * skb)122 static int rtw_mlcst2unicst(struct adapter *padapter, struct sk_buff *skb)
123 {
124 	struct	sta_priv *pstapriv = &padapter->stapriv;
125 	struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
126 	struct list_head	*phead, *plist;
127 	struct sk_buff *newskb;
128 	struct sta_info *psta = NULL;
129 	u8 chk_alive_num = 0;
130 	char chk_alive_list[NUM_STA];
131 	u8 bc_addr[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
132 	u8 null_addr[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
133 
134 	int i;
135 	s32	res;
136 
137 	spin_lock_bh(&pstapriv->asoc_list_lock);
138 	phead = &pstapriv->asoc_list;
139 	/* free sta asoc_queue */
140 	list_for_each(plist, phead) {
141 		int stainfo_offset;
142 
143 		psta = list_entry(plist, struct sta_info, asoc_list);
144 
145 		stainfo_offset = rtw_stainfo_offset(pstapriv, psta);
146 		if (stainfo_offset_valid(stainfo_offset))
147 			chk_alive_list[chk_alive_num++] = stainfo_offset;
148 	}
149 	spin_unlock_bh(&pstapriv->asoc_list_lock);
150 
151 	for (i = 0; i < chk_alive_num; i++) {
152 		psta = rtw_get_stainfo_by_offset(pstapriv, chk_alive_list[i]);
153 		if (!(psta->state & _FW_LINKED))
154 			continue;
155 
156 		/* avoid come from STA1 and send back STA1 */
157 		if (!memcmp(psta->hwaddr, &skb->data[6], 6) ||
158 		    !memcmp(psta->hwaddr, null_addr, 6) ||
159 		    !memcmp(psta->hwaddr, bc_addr, 6))
160 			continue;
161 
162 		newskb = rtw_skb_copy(skb);
163 
164 		if (newskb) {
165 			memcpy(newskb->data, psta->hwaddr, 6);
166 			res = rtw_xmit(padapter, &newskb);
167 			if (res < 0) {
168 				pxmitpriv->tx_drop++;
169 				dev_kfree_skb_any(newskb);
170 			}
171 		} else {
172 			pxmitpriv->tx_drop++;
173 			/* dev_kfree_skb_any(skb); */
174 			return false;	/*  Caller shall tx this multicast frame via normal way. */
175 		}
176 	}
177 
178 	dev_kfree_skb_any(skb);
179 	return true;
180 }
181 
_rtw_xmit_entry(struct sk_buff * pkt,struct net_device * pnetdev)182 void _rtw_xmit_entry(struct sk_buff *pkt, struct net_device *pnetdev)
183 {
184 	struct adapter *padapter = rtw_netdev_priv(pnetdev);
185 	struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
186 	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
187 	s32 res = 0;
188 
189 	if (rtw_if_up(padapter) == false)
190 		goto drop_packet;
191 
192 	rtw_check_xmit_resource(padapter, pkt);
193 
194 	if (!rtw_mc2u_disable
195 		&& check_fwstate(pmlmepriv, WIFI_AP_STATE) == true
196 		&& (IP_MCAST_MAC(pkt->data)
197 			|| ICMPV6_MCAST_MAC(pkt->data)
198 			)
199 		&& padapter->registrypriv.wifi_spec == 0) {
200 		if (pxmitpriv->free_xmitframe_cnt > (NR_XMITFRAME / 4)) {
201 			res = rtw_mlcst2unicst(padapter, pkt);
202 			if (res)
203 				return;
204 		}
205 	}
206 
207 	res = rtw_xmit(padapter, &pkt);
208 	if (res < 0)
209 		goto drop_packet;
210 
211 	return;
212 
213 drop_packet:
214 	pxmitpriv->tx_drop++;
215 	dev_kfree_skb_any(pkt);
216 }
217 
rtw_xmit_entry(struct sk_buff * pkt,struct net_device * pnetdev)218 netdev_tx_t rtw_xmit_entry(struct sk_buff *pkt, struct net_device *pnetdev)
219 {
220 	if (pkt)
221 		_rtw_xmit_entry(pkt, pnetdev);
222 
223 	return NETDEV_TX_OK;
224 }
225