diff options
-rw-r--r-- | drivers/net/wireless/ath/ath6kl/core.h | 5 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath6kl/debug.c | 121 |
2 files changed, 41 insertions, 85 deletions
diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h index c4d66e066dc9..9a58214135b9 100644 --- a/drivers/net/wireless/ath/ath6kl/core.h +++ b/drivers/net/wireless/ath/ath6kl/core.h | |||
@@ -652,10 +652,9 @@ struct ath6kl { | |||
652 | 652 | ||
653 | #ifdef CONFIG_ATH6KL_DEBUG | 653 | #ifdef CONFIG_ATH6KL_DEBUG |
654 | struct { | 654 | struct { |
655 | struct circ_buf fwlog_buf; | 655 | struct sk_buff_head fwlog_queue; |
656 | spinlock_t fwlog_lock; | ||
657 | void *fwlog_tmp; | ||
658 | u32 fwlog_mask; | 656 | u32 fwlog_mask; |
657 | |||
659 | unsigned int dbgfs_diag_reg; | 658 | unsigned int dbgfs_diag_reg; |
660 | u32 diag_reg_addr_wr; | 659 | u32 diag_reg_addr_wr; |
661 | u32 diag_reg_val_wr; | 660 | u32 diag_reg_val_wr; |
diff --git a/drivers/net/wireless/ath/ath6kl/debug.c b/drivers/net/wireless/ath/ath6kl/debug.c index d832058816fe..98b5f15f622e 100644 --- a/drivers/net/wireless/ath/ath6kl/debug.c +++ b/drivers/net/wireless/ath/ath6kl/debug.c | |||
@@ -16,7 +16,7 @@ | |||
16 | 16 | ||
17 | #include "core.h" | 17 | #include "core.h" |
18 | 18 | ||
19 | #include <linux/circ_buf.h> | 19 | #include <linux/skbuff.h> |
20 | #include <linux/fs.h> | 20 | #include <linux/fs.h> |
21 | #include <linux/vmalloc.h> | 21 | #include <linux/vmalloc.h> |
22 | #include <linux/export.h> | 22 | #include <linux/export.h> |
@@ -32,9 +32,8 @@ struct ath6kl_fwlog_slot { | |||
32 | u8 payload[0]; | 32 | u8 payload[0]; |
33 | }; | 33 | }; |
34 | 34 | ||
35 | #define ATH6KL_FWLOG_SIZE 32768 | 35 | #define ATH6KL_FWLOG_MAX_ENTRIES 20 |
36 | #define ATH6KL_FWLOG_SLOT_SIZE (sizeof(struct ath6kl_fwlog_slot) + \ | 36 | |
37 | ATH6KL_FWLOG_PAYLOAD_SIZE) | ||
38 | #define ATH6KL_FWLOG_VALID_MASK 0x1ffff | 37 | #define ATH6KL_FWLOG_VALID_MASK 0x1ffff |
39 | 38 | ||
40 | int ath6kl_printk(const char *level, const char *fmt, ...) | 39 | int ath6kl_printk(const char *level, const char *fmt, ...) |
@@ -268,105 +267,77 @@ static const struct file_operations fops_war_stats = { | |||
268 | .llseek = default_llseek, | 267 | .llseek = default_llseek, |
269 | }; | 268 | }; |
270 | 269 | ||
271 | static void ath6kl_debug_fwlog_add(struct ath6kl *ar, const void *buf, | ||
272 | size_t buf_len) | ||
273 | { | ||
274 | struct circ_buf *fwlog = &ar->debug.fwlog_buf; | ||
275 | size_t space; | ||
276 | int i; | ||
277 | |||
278 | /* entries must all be equal size */ | ||
279 | if (WARN_ON(buf_len != ATH6KL_FWLOG_SLOT_SIZE)) | ||
280 | return; | ||
281 | |||
282 | space = CIRC_SPACE(fwlog->head, fwlog->tail, ATH6KL_FWLOG_SIZE); | ||
283 | if (space < buf_len) | ||
284 | /* discard oldest slot */ | ||
285 | fwlog->tail = (fwlog->tail + ATH6KL_FWLOG_SLOT_SIZE) & | ||
286 | (ATH6KL_FWLOG_SIZE - 1); | ||
287 | |||
288 | for (i = 0; i < buf_len; i += space) { | ||
289 | space = CIRC_SPACE_TO_END(fwlog->head, fwlog->tail, | ||
290 | ATH6KL_FWLOG_SIZE); | ||
291 | |||
292 | if ((size_t) space > buf_len - i) | ||
293 | space = buf_len - i; | ||
294 | |||
295 | memcpy(&fwlog->buf[fwlog->head], buf, space); | ||
296 | fwlog->head = (fwlog->head + space) & (ATH6KL_FWLOG_SIZE - 1); | ||
297 | } | ||
298 | |||
299 | } | ||
300 | |||
301 | void ath6kl_debug_fwlog_event(struct ath6kl *ar, const void *buf, size_t len) | 270 | void ath6kl_debug_fwlog_event(struct ath6kl *ar, const void *buf, size_t len) |
302 | { | 271 | { |
303 | struct ath6kl_fwlog_slot *slot = ar->debug.fwlog_tmp; | 272 | struct ath6kl_fwlog_slot *slot; |
273 | struct sk_buff *skb; | ||
304 | size_t slot_len; | 274 | size_t slot_len; |
305 | 275 | ||
306 | if (WARN_ON(len > ATH6KL_FWLOG_PAYLOAD_SIZE)) | 276 | if (WARN_ON(len > ATH6KL_FWLOG_PAYLOAD_SIZE)) |
307 | return; | 277 | return; |
308 | 278 | ||
309 | spin_lock_bh(&ar->debug.fwlog_lock); | 279 | slot_len = sizeof(*slot) + len; |
310 | 280 | ||
281 | skb = alloc_skb(slot_len, GFP_KERNEL); | ||
282 | if (!skb) | ||
283 | return; | ||
284 | |||
285 | slot = (struct ath6kl_fwlog_slot *) skb_put(skb, slot_len); | ||
311 | slot->timestamp = cpu_to_le32(jiffies); | 286 | slot->timestamp = cpu_to_le32(jiffies); |
312 | slot->length = cpu_to_le32(len); | 287 | slot->length = cpu_to_le32(len); |
313 | memcpy(slot->payload, buf, len); | 288 | memcpy(slot->payload, buf, len); |
314 | 289 | ||
315 | slot_len = sizeof(*slot) + len; | 290 | spin_lock(&ar->debug.fwlog_queue.lock); |
316 | 291 | ||
317 | if (slot_len < ATH6KL_FWLOG_SLOT_SIZE) | 292 | __skb_queue_tail(&ar->debug.fwlog_queue, skb); |
318 | memset(slot->payload + len, 0, | ||
319 | ATH6KL_FWLOG_SLOT_SIZE - slot_len); | ||
320 | 293 | ||
321 | ath6kl_debug_fwlog_add(ar, slot, ATH6KL_FWLOG_SLOT_SIZE); | 294 | /* drop oldest entries */ |
295 | while (skb_queue_len(&ar->debug.fwlog_queue) > | ||
296 | ATH6KL_FWLOG_MAX_ENTRIES) { | ||
297 | skb = __skb_dequeue(&ar->debug.fwlog_queue); | ||
298 | kfree_skb(skb); | ||
299 | } | ||
322 | 300 | ||
323 | spin_unlock_bh(&ar->debug.fwlog_lock); | 301 | spin_unlock(&ar->debug.fwlog_queue.lock); |
324 | } | ||
325 | 302 | ||
326 | static bool ath6kl_debug_fwlog_empty(struct ath6kl *ar) | 303 | return; |
327 | { | ||
328 | return CIRC_CNT(ar->debug.fwlog_buf.head, | ||
329 | ar->debug.fwlog_buf.tail, | ||
330 | ATH6KL_FWLOG_SLOT_SIZE) == 0; | ||
331 | } | 304 | } |
332 | 305 | ||
333 | static ssize_t ath6kl_fwlog_read(struct file *file, char __user *user_buf, | 306 | static ssize_t ath6kl_fwlog_read(struct file *file, char __user *user_buf, |
334 | size_t count, loff_t *ppos) | 307 | size_t count, loff_t *ppos) |
335 | { | 308 | { |
336 | struct ath6kl *ar = file->private_data; | 309 | struct ath6kl *ar = file->private_data; |
337 | struct circ_buf *fwlog = &ar->debug.fwlog_buf; | 310 | struct sk_buff *skb; |
338 | size_t len = 0, buf_len = count; | ||
339 | ssize_t ret_cnt; | 311 | ssize_t ret_cnt; |
312 | size_t len = 0; | ||
340 | char *buf; | 313 | char *buf; |
341 | int ccnt; | ||
342 | 314 | ||
343 | buf = vmalloc(buf_len); | 315 | buf = vmalloc(count); |
344 | if (!buf) | 316 | if (!buf) |
345 | return -ENOMEM; | 317 | return -ENOMEM; |
346 | 318 | ||
347 | /* read undelivered logs from firmware */ | 319 | /* read undelivered logs from firmware */ |
348 | ath6kl_read_fwlogs(ar); | 320 | ath6kl_read_fwlogs(ar); |
349 | 321 | ||
350 | spin_lock_bh(&ar->debug.fwlog_lock); | 322 | spin_lock(&ar->debug.fwlog_queue.lock); |
351 | 323 | ||
352 | while (len < buf_len && !ath6kl_debug_fwlog_empty(ar)) { | 324 | while ((skb = __skb_dequeue(&ar->debug.fwlog_queue))) { |
353 | ccnt = CIRC_CNT_TO_END(fwlog->head, fwlog->tail, | 325 | if (skb->len > count - len) { |
354 | ATH6KL_FWLOG_SIZE); | 326 | /* not enough space, put skb back and leave */ |
327 | __skb_queue_head(&ar->debug.fwlog_queue, skb); | ||
328 | break; | ||
329 | } | ||
355 | 330 | ||
356 | if ((size_t) ccnt > buf_len - len) | ||
357 | ccnt = buf_len - len; | ||
358 | 331 | ||
359 | memcpy(buf + len, &fwlog->buf[fwlog->tail], ccnt); | 332 | memcpy(buf + len, skb->data, skb->len); |
360 | len += ccnt; | 333 | len += skb->len; |
361 | 334 | ||
362 | fwlog->tail = (fwlog->tail + ccnt) & | 335 | kfree_skb(skb); |
363 | (ATH6KL_FWLOG_SIZE - 1); | ||
364 | } | 336 | } |
365 | 337 | ||
366 | spin_unlock_bh(&ar->debug.fwlog_lock); | 338 | spin_unlock(&ar->debug.fwlog_queue.lock); |
367 | 339 | ||
368 | if (WARN_ON(len > buf_len)) | 340 | /* FIXME: what to do if len == 0? */ |
369 | len = buf_len; | ||
370 | 341 | ||
371 | ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len); | 342 | ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len); |
372 | 343 | ||
@@ -1651,17 +1622,7 @@ static const struct file_operations fops_power_params = { | |||
1651 | 1622 | ||
1652 | int ath6kl_debug_init(struct ath6kl *ar) | 1623 | int ath6kl_debug_init(struct ath6kl *ar) |
1653 | { | 1624 | { |
1654 | ar->debug.fwlog_buf.buf = vmalloc(ATH6KL_FWLOG_SIZE); | 1625 | skb_queue_head_init(&ar->debug.fwlog_queue); |
1655 | if (ar->debug.fwlog_buf.buf == NULL) | ||
1656 | return -ENOMEM; | ||
1657 | |||
1658 | ar->debug.fwlog_tmp = kmalloc(ATH6KL_FWLOG_SLOT_SIZE, GFP_KERNEL); | ||
1659 | if (ar->debug.fwlog_tmp == NULL) { | ||
1660 | vfree(ar->debug.fwlog_buf.buf); | ||
1661 | return -ENOMEM; | ||
1662 | } | ||
1663 | |||
1664 | spin_lock_init(&ar->debug.fwlog_lock); | ||
1665 | 1626 | ||
1666 | /* | 1627 | /* |
1667 | * Actually we are lying here but don't know how to read the mask | 1628 | * Actually we are lying here but don't know how to read the mask |
@@ -1671,11 +1632,8 @@ int ath6kl_debug_init(struct ath6kl *ar) | |||
1671 | 1632 | ||
1672 | ar->debugfs_phy = debugfs_create_dir("ath6kl", | 1633 | ar->debugfs_phy = debugfs_create_dir("ath6kl", |
1673 | ar->wiphy->debugfsdir); | 1634 | ar->wiphy->debugfsdir); |
1674 | if (!ar->debugfs_phy) { | 1635 | if (!ar->debugfs_phy) |
1675 | vfree(ar->debug.fwlog_buf.buf); | ||
1676 | kfree(ar->debug.fwlog_tmp); | ||
1677 | return -ENOMEM; | 1636 | return -ENOMEM; |
1678 | } | ||
1679 | 1637 | ||
1680 | debugfs_create_file("tgt_stats", S_IRUSR, ar->debugfs_phy, ar, | 1638 | debugfs_create_file("tgt_stats", S_IRUSR, ar->debugfs_phy, ar, |
1681 | &fops_tgt_stats); | 1639 | &fops_tgt_stats); |
@@ -1742,8 +1700,7 @@ int ath6kl_debug_init(struct ath6kl *ar) | |||
1742 | 1700 | ||
1743 | void ath6kl_debug_cleanup(struct ath6kl *ar) | 1701 | void ath6kl_debug_cleanup(struct ath6kl *ar) |
1744 | { | 1702 | { |
1745 | vfree(ar->debug.fwlog_buf.buf); | 1703 | skb_queue_purge(&ar->debug.fwlog_queue); |
1746 | kfree(ar->debug.fwlog_tmp); | ||
1747 | kfree(ar->debug.roam_tbl); | 1704 | kfree(ar->debug.roam_tbl); |
1748 | } | 1705 | } |
1749 | 1706 | ||