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 | #include <rtw_debug.h> |
9 | |
10 | /* |
11 | * Translate the OS dependent @param error_code to OS independent RTW_STATUS_CODE |
12 | * @return: one of RTW_STATUS_CODE |
13 | */ |
14 | inline int RTW_STATUS_CODE(int error_code) |
15 | { |
16 | if (error_code >= 0) |
17 | return _SUCCESS; |
18 | return _FAIL; |
19 | } |
20 | |
21 | void *_rtw_malloc(u32 sz) |
22 | { |
23 | return kmalloc(size: sz, in_interrupt() ? GFP_ATOMIC : GFP_KERNEL); |
24 | } |
25 | |
26 | void *_rtw_zmalloc(u32 sz) |
27 | { |
28 | void *pbuf = _rtw_malloc(sz); |
29 | |
30 | if (pbuf) |
31 | memset(pbuf, 0, sz); |
32 | |
33 | return pbuf; |
34 | } |
35 | |
36 | inline struct sk_buff *_rtw_skb_alloc(u32 sz) |
37 | { |
38 | return __dev_alloc_skb(length: sz, in_interrupt() ? GFP_ATOMIC : GFP_KERNEL); |
39 | } |
40 | |
41 | inline struct sk_buff *_rtw_skb_copy(const struct sk_buff *skb) |
42 | { |
43 | return skb_copy(skb, in_interrupt() ? GFP_ATOMIC : GFP_KERNEL); |
44 | } |
45 | |
46 | inline int _rtw_netif_rx(struct net_device *ndev, struct sk_buff *skb) |
47 | { |
48 | skb->dev = ndev; |
49 | return netif_rx(skb); |
50 | } |
51 | |
52 | struct net_device *rtw_alloc_etherdev_with_old_priv(int sizeof_priv, void *old_priv) |
53 | { |
54 | struct net_device *pnetdev; |
55 | struct rtw_netdev_priv_indicator *pnpi; |
56 | |
57 | pnetdev = alloc_etherdev_mq(sizeof(struct rtw_netdev_priv_indicator), 4); |
58 | if (!pnetdev) |
59 | goto RETURN; |
60 | |
61 | pnpi = netdev_priv(dev: pnetdev); |
62 | pnpi->priv = old_priv; |
63 | pnpi->sizeof_priv = sizeof_priv; |
64 | |
65 | RETURN: |
66 | return pnetdev; |
67 | } |
68 | |
69 | struct net_device *rtw_alloc_etherdev(int sizeof_priv) |
70 | { |
71 | struct net_device *pnetdev; |
72 | struct rtw_netdev_priv_indicator *pnpi; |
73 | |
74 | pnetdev = alloc_etherdev_mq(sizeof(struct rtw_netdev_priv_indicator), 4); |
75 | if (!pnetdev) |
76 | goto RETURN; |
77 | |
78 | pnpi = netdev_priv(dev: pnetdev); |
79 | |
80 | pnpi->priv = vzalloc(size: sizeof_priv); |
81 | if (!pnpi->priv) { |
82 | free_netdev(dev: pnetdev); |
83 | pnetdev = NULL; |
84 | goto RETURN; |
85 | } |
86 | |
87 | pnpi->sizeof_priv = sizeof_priv; |
88 | RETURN: |
89 | return pnetdev; |
90 | } |
91 | |
92 | void rtw_free_netdev(struct net_device *netdev) |
93 | { |
94 | struct rtw_netdev_priv_indicator *pnpi; |
95 | |
96 | if (!netdev) |
97 | goto RETURN; |
98 | |
99 | pnpi = netdev_priv(dev: netdev); |
100 | |
101 | if (!pnpi->priv) |
102 | goto RETURN; |
103 | |
104 | vfree(addr: pnpi->priv); |
105 | free_netdev(dev: netdev); |
106 | |
107 | RETURN: |
108 | return; |
109 | } |
110 | |
111 | void rtw_buf_free(u8 **buf, u32 *buf_len) |
112 | { |
113 | if (!buf || !buf_len) |
114 | return; |
115 | |
116 | if (*buf) { |
117 | *buf_len = 0; |
118 | kfree(objp: *buf); |
119 | *buf = NULL; |
120 | } |
121 | } |
122 | |
123 | void rtw_buf_update(u8 **buf, u32 *buf_len, u8 *src, u32 src_len) |
124 | { |
125 | u32 ori_len = 0, dup_len = 0; |
126 | u8 *ori = NULL; |
127 | u8 *dup = NULL; |
128 | |
129 | if (!buf || !buf_len) |
130 | return; |
131 | |
132 | if (!src || !src_len) |
133 | goto keep_ori; |
134 | |
135 | /* duplicate src */ |
136 | dup = rtw_malloc(src_len); |
137 | if (dup) { |
138 | dup_len = src_len; |
139 | memcpy(dup, src, dup_len); |
140 | } |
141 | |
142 | keep_ori: |
143 | ori = *buf; |
144 | ori_len = *buf_len; |
145 | |
146 | /* replace buf with dup */ |
147 | *buf_len = 0; |
148 | *buf = dup; |
149 | *buf_len = dup_len; |
150 | |
151 | /* free ori */ |
152 | if (ori && ori_len > 0) |
153 | kfree(objp: ori); |
154 | } |
155 | |
156 | |
157 | /** |
158 | * rtw_cbuf_full - test if cbuf is full |
159 | * @cbuf: pointer of struct rtw_cbuf |
160 | * |
161 | * Returns: true if cbuf is full |
162 | */ |
163 | inline bool rtw_cbuf_full(struct rtw_cbuf *cbuf) |
164 | { |
165 | return (cbuf->write == cbuf->read - 1) ? true : false; |
166 | } |
167 | |
168 | /** |
169 | * rtw_cbuf_empty - test if cbuf is empty |
170 | * @cbuf: pointer of struct rtw_cbuf |
171 | * |
172 | * Returns: true if cbuf is empty |
173 | */ |
174 | inline bool rtw_cbuf_empty(struct rtw_cbuf *cbuf) |
175 | { |
176 | return (cbuf->write == cbuf->read) ? true : false; |
177 | } |
178 | |
179 | /** |
180 | * rtw_cbuf_push - push a pointer into cbuf |
181 | * @cbuf: pointer of struct rtw_cbuf |
182 | * @buf: pointer to push in |
183 | * |
184 | * Lock free operation, be careful of the use scheme |
185 | * Returns: true push success |
186 | */ |
187 | bool rtw_cbuf_push(struct rtw_cbuf *cbuf, void *buf) |
188 | { |
189 | if (rtw_cbuf_full(cbuf)) |
190 | return _FAIL; |
191 | |
192 | cbuf->bufs[cbuf->write] = buf; |
193 | cbuf->write = (cbuf->write + 1) % cbuf->size; |
194 | |
195 | return _SUCCESS; |
196 | } |
197 | |
198 | /** |
199 | * rtw_cbuf_pop - pop a pointer from cbuf |
200 | * @cbuf: pointer of struct rtw_cbuf |
201 | * |
202 | * Lock free operation, be careful of the use scheme |
203 | * Returns: pointer popped out |
204 | */ |
205 | void *rtw_cbuf_pop(struct rtw_cbuf *cbuf) |
206 | { |
207 | void *buf; |
208 | if (rtw_cbuf_empty(cbuf)) |
209 | return NULL; |
210 | |
211 | buf = cbuf->bufs[cbuf->read]; |
212 | cbuf->read = (cbuf->read + 1) % cbuf->size; |
213 | |
214 | return buf; |
215 | } |
216 | |
217 | /** |
218 | * rtw_cbuf_alloc - allocate a rtw_cbuf with given size and do initialization |
219 | * @size: size of pointer |
220 | * |
221 | * Returns: pointer of srtuct rtw_cbuf, NULL for allocation failure |
222 | */ |
223 | struct rtw_cbuf *rtw_cbuf_alloc(u32 size) |
224 | { |
225 | struct rtw_cbuf *cbuf; |
226 | |
227 | cbuf = rtw_malloc(struct_size(cbuf, bufs, size)); |
228 | |
229 | if (cbuf) { |
230 | cbuf->write = cbuf->read = 0; |
231 | cbuf->size = size; |
232 | } |
233 | |
234 | return cbuf; |
235 | } |
236 | |