2 * Copyright (c) 2010 Broadcom Corporation
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.
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.
17 #include <linux/netdevice.h>
18 #include <linux/module.h>
19 #include <brcmu_utils.h>
21 MODULE_AUTHOR("Broadcom Corporation");
22 MODULE_DESCRIPTION("Broadcom 802.11n wireless LAN driver utilities.");
23 MODULE_SUPPORTED_DEVICE("Broadcom 802.11n WLAN cards");
24 MODULE_LICENSE("Dual BSD/GPL");
26 struct sk_buff
*brcmu_pkt_buf_get_skb(uint len
)
30 skb
= dev_alloc_skb(len
);
38 EXPORT_SYMBOL(brcmu_pkt_buf_get_skb
);
40 /* Free the driver packet. Free the tag if present */
41 void brcmu_pkt_buf_free_skb(struct sk_buff
*skb
)
46 /* perversion: we use skb->next to chain multi-skb packets */
52 /* cannot kfree_skb() on hard IRQ (net/core/skbuff.c) if
55 dev_kfree_skb_any(skb
);
57 /* can free immediately (even in_irq()) if destructor
66 EXPORT_SYMBOL(brcmu_pkt_buf_free_skb
);
69 /* copy a buffer into a pkt buffer chain */
70 uint
brcmu_pktfrombuf(struct sk_buff
*p
, uint offset
, int len
,
75 /* skip 'offset' bytes */
76 for (; p
&& offset
; p
= p
->next
) {
77 if (offset
< (uint
) (p
->len
))
86 for (; p
&& len
; p
= p
->next
) {
87 n
= min((uint
) (p
->len
) - offset
, (uint
) len
);
88 memcpy(p
->data
+ offset
, buf
, n
);
97 EXPORT_SYMBOL(brcmu_pktfrombuf
);
99 /* return total length of buffer chain */
100 uint
brcmu_pkttotlen(struct sk_buff
*p
)
105 for (; p
; p
= p
->next
)
109 EXPORT_SYMBOL(brcmu_pkttotlen
);
112 * osl multiple-precedence packet queue
113 * hi_prec is always >= the number of the highest non-empty precedence
115 struct sk_buff
*brcmu_pktq_penq(struct pktq
*pq
, int prec
,
120 if (pktq_full(pq
) || pktq_pfull(pq
, prec
))
135 if (pq
->hi_prec
< prec
)
136 pq
->hi_prec
= (u8
) prec
;
140 EXPORT_SYMBOL(brcmu_pktq_penq
);
142 struct sk_buff
*brcmu_pktq_penq_head(struct pktq
*pq
, int prec
,
147 if (pktq_full(pq
) || pktq_pfull(pq
, prec
))
161 if (pq
->hi_prec
< prec
)
162 pq
->hi_prec
= (u8
) prec
;
166 EXPORT_SYMBOL(brcmu_pktq_penq_head
);
168 struct sk_buff
*brcmu_pktq_pdeq(struct pktq
*pq
, int prec
)
191 EXPORT_SYMBOL(brcmu_pktq_pdeq
);
193 struct sk_buff
*brcmu_pktq_pdeq_tail(struct pktq
*pq
, int prec
)
196 struct sk_buff
*p
, *prev
;
204 for (prev
= NULL
; p
!= q
->tail
; p
= p
->prev
)
219 EXPORT_SYMBOL(brcmu_pktq_pdeq_tail
);
222 brcmu_pktq_pflush(struct pktq
*pq
, int prec
, bool dir
,
223 bool (*fn
)(struct sk_buff
*, void *), void *arg
)
226 struct sk_buff
*p
, *prev
= NULL
;
231 if (fn
== NULL
|| (*fn
) (p
, arg
)) {
232 bool head
= (p
== q
->head
);
236 prev
->prev
= p
->prev
;
238 brcmu_pkt_buf_free_skb(p
);
241 p
= (head
? q
->head
: prev
->prev
);
251 EXPORT_SYMBOL(brcmu_pktq_pflush
);
253 void brcmu_pktq_flush(struct pktq
*pq
, bool dir
,
254 bool (*fn
)(struct sk_buff
*, void *), void *arg
)
257 for (prec
= 0; prec
< pq
->num_prec
; prec
++)
258 brcmu_pktq_pflush(pq
, prec
, dir
, fn
, arg
);
260 EXPORT_SYMBOL(brcmu_pktq_flush
);
262 void brcmu_pktq_init(struct pktq
*pq
, int num_prec
, int max_len
)
266 /* pq is variable size; only zero out what's requested */
268 offsetof(struct pktq
, q
) + (sizeof(struct pktq_prec
) * num_prec
));
270 pq
->num_prec
= (u16
) num_prec
;
272 pq
->max
= (u16
) max_len
;
274 for (prec
= 0; prec
< num_prec
; prec
++)
275 pq
->q
[prec
].max
= pq
->max
;
277 EXPORT_SYMBOL(brcmu_pktq_init
);
279 struct sk_buff
*brcmu_pktq_peek_tail(struct pktq
*pq
, int *prec_out
)
286 for (prec
= 0; prec
< pq
->hi_prec
; prec
++)
287 if (pq
->q
[prec
].head
)
293 return pq
->q
[prec
].tail
;
295 EXPORT_SYMBOL(brcmu_pktq_peek_tail
);
297 /* Return sum of lengths of a specific set of precedences */
298 int brcmu_pktq_mlen(struct pktq
*pq
, uint prec_bmp
)
304 for (prec
= 0; prec
<= pq
->hi_prec
; prec
++)
305 if (prec_bmp
& (1 << prec
))
306 len
+= pq
->q
[prec
].len
;
310 EXPORT_SYMBOL(brcmu_pktq_mlen
);
312 /* Priority dequeue from a specific set of precedences */
313 struct sk_buff
*brcmu_pktq_mdeq(struct pktq
*pq
, uint prec_bmp
,
323 while ((prec
= pq
->hi_prec
) > 0 && pq
->q
[prec
].head
== NULL
)
326 while ((prec_bmp
& (1 << prec
)) == 0 || pq
->q
[prec
].head
== NULL
)
351 EXPORT_SYMBOL(brcmu_pktq_mdeq
);
354 /* pretty hex print a pkt buffer chain */
355 void brcmu_prpkt(const char *msg
, struct sk_buff
*p0
)
359 if (msg
&& (msg
[0] != '\0'))
360 printk(KERN_DEBUG
"%s:\n", msg
);
362 for (p
= p0
; p
; p
= p
->next
)
363 print_hex_dump_bytes("", DUMP_PREFIX_OFFSET
, p
->data
, p
->len
);
365 EXPORT_SYMBOL(brcmu_prpkt
);
366 #endif /* defined(BCMDBG) */
370 * print bytes formatted as hex to a string. return the resulting
373 int brcmu_format_hex(char *str
, const void *bytes
, int len
)
377 const u8
*src
= (const u8
*)bytes
;
379 for (i
= 0; i
< len
; i
++) {
380 p
+= snprintf(p
, 3, "%02X", *src
);
383 return (int)(p
- str
);
385 EXPORT_SYMBOL(brcmu_format_hex
);
386 #endif /* defined(BCMDBG) */