Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
utils.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2010 Broadcom Corporation
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
11  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
13  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
18 
19 #include <linux/netdevice.h>
20 #include <linux/module.h>
21 
22 #include <brcmu_utils.h>
23 
24 MODULE_AUTHOR("Broadcom Corporation");
25 MODULE_DESCRIPTION("Broadcom 802.11n wireless LAN driver utilities.");
26 MODULE_SUPPORTED_DEVICE("Broadcom 802.11n WLAN cards");
27 MODULE_LICENSE("Dual BSD/GPL");
28 
30 {
31  struct sk_buff *skb;
32 
33  skb = dev_alloc_skb(len);
34  if (skb) {
35  skb_put(skb, len);
36  skb->priority = 0;
37  }
38 
39  return skb;
40 }
42 
43 /* Free the driver packet. Free the tag if present */
45 {
46  if (!skb)
47  return;
48  WARN_ON(skb->next);
49  if (skb->destructor)
50  /* cannot kfree_skb() on hard IRQ (net/core/skbuff.c) if
51  * destructor exists
52  */
53  dev_kfree_skb_any(skb);
54  else
55  /* can free immediately (even in_irq()) if destructor
56  * does not exist
57  */
58  dev_kfree_skb(skb);
59 }
61 
62 /*
63  * osl multiple-precedence packet queue
64  * hi_prec is always >= the number of the highest non-empty precedence
65  */
66 struct sk_buff *brcmu_pktq_penq(struct pktq *pq, int prec,
67  struct sk_buff *p)
68 {
69  struct sk_buff_head *q;
70 
71  if (pktq_full(pq) || pktq_pfull(pq, prec))
72  return NULL;
73 
74  q = &pq->q[prec].skblist;
75  skb_queue_tail(q, p);
76  pq->len++;
77 
78  if (pq->hi_prec < prec)
79  pq->hi_prec = (u8) prec;
80 
81  return p;
82 }
84 
85 struct sk_buff *brcmu_pktq_penq_head(struct pktq *pq, int prec,
86  struct sk_buff *p)
87 {
88  struct sk_buff_head *q;
89 
90  if (pktq_full(pq) || pktq_pfull(pq, prec))
91  return NULL;
92 
93  q = &pq->q[prec].skblist;
94  skb_queue_head(q, p);
95  pq->len++;
96 
97  if (pq->hi_prec < prec)
98  pq->hi_prec = (u8) prec;
99 
100  return p;
101 }
103 
104 struct sk_buff *brcmu_pktq_pdeq(struct pktq *pq, int prec)
105 {
106  struct sk_buff_head *q;
107  struct sk_buff *p;
108 
109  q = &pq->q[prec].skblist;
110  p = skb_dequeue(q);
111  if (p == NULL)
112  return NULL;
113 
114  pq->len--;
115  return p;
116 }
118 
119 struct sk_buff *brcmu_pktq_pdeq_tail(struct pktq *pq, int prec)
120 {
121  struct sk_buff_head *q;
122  struct sk_buff *p;
123 
124  q = &pq->q[prec].skblist;
125  p = skb_dequeue_tail(q);
126  if (p == NULL)
127  return NULL;
128 
129  pq->len--;
130  return p;
131 }
133 
134 void
135 brcmu_pktq_pflush(struct pktq *pq, int prec, bool dir,
136  bool (*fn)(struct sk_buff *, void *), void *arg)
137 {
138  struct sk_buff_head *q;
139  struct sk_buff *p, *next;
140 
141  q = &pq->q[prec].skblist;
142  skb_queue_walk_safe(q, p, next) {
143  if (fn == NULL || (*fn) (p, arg)) {
144  skb_unlink(p, q);
146  pq->len--;
147  }
148  }
149 }
151 
152 void brcmu_pktq_flush(struct pktq *pq, bool dir,
153  bool (*fn)(struct sk_buff *, void *), void *arg)
154 {
155  int prec;
156  for (prec = 0; prec < pq->num_prec; prec++)
157  brcmu_pktq_pflush(pq, prec, dir, fn, arg);
158 }
160 
161 void brcmu_pktq_init(struct pktq *pq, int num_prec, int max_len)
162 {
163  int prec;
164 
165  /* pq is variable size; only zero out what's requested */
166  memset(pq, 0,
167  offsetof(struct pktq, q) + (sizeof(struct pktq_prec) * num_prec));
168 
169  pq->num_prec = (u16) num_prec;
170 
171  pq->max = (u16) max_len;
172 
173  for (prec = 0; prec < num_prec; prec++) {
174  pq->q[prec].max = pq->max;
175  skb_queue_head_init(&pq->q[prec].skblist);
176  }
177 }
179 
180 struct sk_buff *brcmu_pktq_peek_tail(struct pktq *pq, int *prec_out)
181 {
182  int prec;
183 
184  if (pq->len == 0)
185  return NULL;
186 
187  for (prec = 0; prec < pq->hi_prec; prec++)
188  if (!skb_queue_empty(&pq->q[prec].skblist))
189  break;
190 
191  if (prec_out)
192  *prec_out = prec;
193 
194  return skb_peek_tail(&pq->q[prec].skblist);
195 }
197 
198 /* Return sum of lengths of a specific set of precedences */
199 int brcmu_pktq_mlen(struct pktq *pq, uint prec_bmp)
200 {
201  int prec, len;
202 
203  len = 0;
204 
205  for (prec = 0; prec <= pq->hi_prec; prec++)
206  if (prec_bmp & (1 << prec))
207  len += pq->q[prec].skblist.qlen;
208 
209  return len;
210 }
212 
213 /* Priority dequeue from a specific set of precedences */
214 struct sk_buff *brcmu_pktq_mdeq(struct pktq *pq, uint prec_bmp,
215  int *prec_out)
216 {
217  struct sk_buff_head *q;
218  struct sk_buff *p;
219  int prec;
220 
221  if (pq->len == 0)
222  return NULL;
223 
224  while ((prec = pq->hi_prec) > 0 &&
225  skb_queue_empty(&pq->q[prec].skblist))
226  pq->hi_prec--;
227 
228  while ((prec_bmp & (1 << prec)) == 0 ||
229  skb_queue_empty(&pq->q[prec].skblist))
230  if (prec-- == 0)
231  return NULL;
232 
233  q = &pq->q[prec].skblist;
234  p = skb_dequeue(q);
235  if (p == NULL)
236  return NULL;
237 
238  pq->len--;
239 
240  if (prec_out)
241  *prec_out = prec;
242 
243  return p;
244 }
246 
247 #if defined(DEBUG)
248 /* pretty hex print a pkt buffer chain */
249 void brcmu_prpkt(const char *msg, struct sk_buff *p0)
250 {
251  struct sk_buff *p;
252 
253  if (msg && (msg[0] != '\0'))
254  pr_debug("%s:\n", msg);
255 
256  for (p = p0; p; p = p->next)
257  print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, p->data, p->len);
258 }
260 
261 void brcmu_dbg_hex_dump(const void *data, size_t size, const char *fmt, ...)
262 {
263  struct va_format vaf;
264  va_list args;
265 
266  va_start(args, fmt);
267 
268  vaf.fmt = fmt;
269  vaf.va = &args;
270 
271  pr_debug("%pV", &vaf);
272 
273  va_end(args);
274 
275  print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, data, size);
276 }
277 EXPORT_SYMBOL(brcmu_dbg_hex_dump);
278 #endif /* defined(DEBUG) */