From 9b9a4f2acac2a04416ba15242b8666d4f8273e31 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Mon, 6 Feb 2012 08:23:27 +0200 Subject: ath6kl: store firmware logs in skbuffs Currently firmware logs are stored in a circular buffer, but this was not very flexible and fragile. It's a lot easier to store logs to struct skbuffs and store them in a skb queue. Also this makes it possible to easily increase the buffer size, even dynamically if we so want (but that's not yet supported). From user space point of view nothing should change. Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/core.h | 5 +- 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 { #ifdef CONFIG_ATH6KL_DEBUG struct { - struct circ_buf fwlog_buf; - spinlock_t fwlog_lock; - void *fwlog_tmp; + struct sk_buff_head fwlog_queue; u32 fwlog_mask; + unsigned int dbgfs_diag_reg; u32 diag_reg_addr_wr; 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 @@ #include "core.h" -#include +#include #include #include #include @@ -32,9 +32,8 @@ struct ath6kl_fwlog_slot { u8 payload[0]; }; -#define ATH6KL_FWLOG_SIZE 32768 -#define ATH6KL_FWLOG_SLOT_SIZE (sizeof(struct ath6kl_fwlog_slot) + \ - ATH6KL_FWLOG_PAYLOAD_SIZE) +#define ATH6KL_FWLOG_MAX_ENTRIES 20 + #define ATH6KL_FWLOG_VALID_MASK 0x1ffff int ath6kl_printk(const char *level, const char *fmt, ...) @@ -268,105 +267,77 @@ static const struct file_operations fops_war_stats = { .llseek = default_llseek, }; -static void ath6kl_debug_fwlog_add(struct ath6kl *ar, const void *buf, - size_t buf_len) -{ - struct circ_buf *fwlog = &ar->debug.fwlog_buf; - size_t space; - int i; - - /* entries must all be equal size */ - if (WARN_ON(buf_len != ATH6KL_FWLOG_SLOT_SIZE)) - return; - - space = CIRC_SPACE(fwlog->head, fwlog->tail, ATH6KL_FWLOG_SIZE); - if (space < buf_len) - /* discard oldest slot */ - fwlog->tail = (fwlog->tail + ATH6KL_FWLOG_SLOT_SIZE) & - (ATH6KL_FWLOG_SIZE - 1); - - for (i = 0; i < buf_len; i += space) { - space = CIRC_SPACE_TO_END(fwlog->head, fwlog->tail, - ATH6KL_FWLOG_SIZE); - - if ((size_t) space > buf_len - i) - space = buf_len - i; - - memcpy(&fwlog->buf[fwlog->head], buf, space); - fwlog->head = (fwlog->head + space) & (ATH6KL_FWLOG_SIZE - 1); - } - -} - void ath6kl_debug_fwlog_event(struct ath6kl *ar, const void *buf, size_t len) { - struct ath6kl_fwlog_slot *slot = ar->debug.fwlog_tmp; + struct ath6kl_fwlog_slot *slot; + struct sk_buff *skb; size_t slot_len; if (WARN_ON(len > ATH6KL_FWLOG_PAYLOAD_SIZE)) return; - spin_lock_bh(&ar->debug.fwlog_lock); + slot_len = sizeof(*slot) + len; + skb = alloc_skb(slot_len, GFP_KERNEL); + if (!skb) + return; + + slot = (struct ath6kl_fwlog_slot *) skb_put(skb, slot_len); slot->timestamp = cpu_to_le32(jiffies); slot->length = cpu_to_le32(len); memcpy(slot->payload, buf, len); - slot_len = sizeof(*slot) + len; + spin_lock(&ar->debug.fwlog_queue.lock); - if (slot_len < ATH6KL_FWLOG_SLOT_SIZE) - memset(slot->payload + len, 0, - ATH6KL_FWLOG_SLOT_SIZE - slot_len); + __skb_queue_tail(&ar->debug.fwlog_queue, skb); - ath6kl_debug_fwlog_add(ar, slot, ATH6KL_FWLOG_SLOT_SIZE); + /* drop oldest entries */ + while (skb_queue_len(&ar->debug.fwlog_queue) > + ATH6KL_FWLOG_MAX_ENTRIES) { + skb = __skb_dequeue(&ar->debug.fwlog_queue); + kfree_skb(skb); + } - spin_unlock_bh(&ar->debug.fwlog_lock); -} + spin_unlock(&ar->debug.fwlog_queue.lock); -static bool ath6kl_debug_fwlog_empty(struct ath6kl *ar) -{ - return CIRC_CNT(ar->debug.fwlog_buf.head, - ar->debug.fwlog_buf.tail, - ATH6KL_FWLOG_SLOT_SIZE) == 0; + return; } static ssize_t ath6kl_fwlog_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { struct ath6kl *ar = file->private_data; - struct circ_buf *fwlog = &ar->debug.fwlog_buf; - size_t len = 0, buf_len = count; + struct sk_buff *skb; ssize_t ret_cnt; + size_t len = 0; char *buf; - int ccnt; - buf = vmalloc(buf_len); + buf = vmalloc(count); if (!buf) return -ENOMEM; /* read undelivered logs from firmware */ ath6kl_read_fwlogs(ar); - spin_lock_bh(&ar->debug.fwlog_lock); + spin_lock(&ar->debug.fwlog_queue.lock); - while (len < buf_len && !ath6kl_debug_fwlog_empty(ar)) { - ccnt = CIRC_CNT_TO_END(fwlog->head, fwlog->tail, - ATH6KL_FWLOG_SIZE); + while ((skb = __skb_dequeue(&ar->debug.fwlog_queue))) { + if (skb->len > count - len) { + /* not enough space, put skb back and leave */ + __skb_queue_head(&ar->debug.fwlog_queue, skb); + break; + } - if ((size_t) ccnt > buf_len - len) - ccnt = buf_len - len; - memcpy(buf + len, &fwlog->buf[fwlog->tail], ccnt); - len += ccnt; + memcpy(buf + len, skb->data, skb->len); + len += skb->len; - fwlog->tail = (fwlog->tail + ccnt) & - (ATH6KL_FWLOG_SIZE - 1); + kfree_skb(skb); } - spin_unlock_bh(&ar->debug.fwlog_lock); + spin_unlock(&ar->debug.fwlog_queue.lock); - if (WARN_ON(len > buf_len)) - len = buf_len; + /* FIXME: what to do if len == 0? */ ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len); @@ -1651,17 +1622,7 @@ static const struct file_operations fops_power_params = { int ath6kl_debug_init(struct ath6kl *ar) { - ar->debug.fwlog_buf.buf = vmalloc(ATH6KL_FWLOG_SIZE); - if (ar->debug.fwlog_buf.buf == NULL) - return -ENOMEM; - - ar->debug.fwlog_tmp = kmalloc(ATH6KL_FWLOG_SLOT_SIZE, GFP_KERNEL); - if (ar->debug.fwlog_tmp == NULL) { - vfree(ar->debug.fwlog_buf.buf); - return -ENOMEM; - } - - spin_lock_init(&ar->debug.fwlog_lock); + skb_queue_head_init(&ar->debug.fwlog_queue); /* * 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) ar->debugfs_phy = debugfs_create_dir("ath6kl", ar->wiphy->debugfsdir); - if (!ar->debugfs_phy) { - vfree(ar->debug.fwlog_buf.buf); - kfree(ar->debug.fwlog_tmp); + if (!ar->debugfs_phy) return -ENOMEM; - } debugfs_create_file("tgt_stats", S_IRUSR, ar->debugfs_phy, ar, &fops_tgt_stats); @@ -1742,8 +1700,7 @@ int ath6kl_debug_init(struct ath6kl *ar) void ath6kl_debug_cleanup(struct ath6kl *ar) { - vfree(ar->debug.fwlog_buf.buf); - kfree(ar->debug.fwlog_tmp); + skb_queue_purge(&ar->debug.fwlog_queue); kfree(ar->debug.roam_tbl); } -- cgit v1.2.2 From c807b30d2588dd3c74db1f690a0e9e724dd332da Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Mon, 6 Feb 2012 08:23:40 +0200 Subject: ath6kl: add blocking debugfs file for retrieving firmware logs When debugging firmware issues it's not always enough to get the latest firmware logs, sometimes we need to get logs from a longer period. To make this possible, add a debugfs file named fwlog_block. When reading from this file ath6kl will send firmware logs whenever available and otherwise it will block and wait for new logs. Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/core.h | 3 + drivers/net/wireless/ath/ath6kl/debug.c | 104 +++++++++++++++++++++++++++++++- 2 files changed, 106 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h index 9a58214135b9..4ff06a326785 100644 --- a/drivers/net/wireless/ath/ath6kl/core.h +++ b/drivers/net/wireless/ath/ath6kl/core.h @@ -653,6 +653,9 @@ struct ath6kl { #ifdef CONFIG_ATH6KL_DEBUG struct { struct sk_buff_head fwlog_queue; + struct completion fwlog_completion; + bool fwlog_open; + u32 fwlog_mask; unsigned int dbgfs_diag_reg; diff --git a/drivers/net/wireless/ath/ath6kl/debug.c b/drivers/net/wireless/ath/ath6kl/debug.c index 98b5f15f622e..ec32ff692163 100644 --- a/drivers/net/wireless/ath/ath6kl/debug.c +++ b/drivers/net/wireless/ath/ath6kl/debug.c @@ -290,6 +290,7 @@ void ath6kl_debug_fwlog_event(struct ath6kl *ar, const void *buf, size_t len) spin_lock(&ar->debug.fwlog_queue.lock); __skb_queue_tail(&ar->debug.fwlog_queue, skb); + complete(&ar->debug.fwlog_completion); /* drop oldest entries */ while (skb_queue_len(&ar->debug.fwlog_queue) > @@ -303,6 +304,28 @@ void ath6kl_debug_fwlog_event(struct ath6kl *ar, const void *buf, size_t len) return; } +static int ath6kl_fwlog_open(struct inode *inode, struct file *file) +{ + struct ath6kl *ar = inode->i_private; + + if (ar->debug.fwlog_open) + return -EBUSY; + + ar->debug.fwlog_open = true; + + file->private_data = inode->i_private; + return 0; +} + +static int ath6kl_fwlog_release(struct inode *inode, struct file *file) +{ + struct ath6kl *ar = inode->i_private; + + ar->debug.fwlog_open = false; + + return 0; +} + static ssize_t ath6kl_fwlog_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { @@ -347,12 +370,87 @@ static ssize_t ath6kl_fwlog_read(struct file *file, char __user *user_buf, } static const struct file_operations fops_fwlog = { - .open = ath6kl_debugfs_open, + .open = ath6kl_fwlog_open, + .release = ath6kl_fwlog_release, .read = ath6kl_fwlog_read, .owner = THIS_MODULE, .llseek = default_llseek, }; +static ssize_t ath6kl_fwlog_block_read(struct file *file, + char __user *user_buf, + size_t count, + loff_t *ppos) +{ + struct ath6kl *ar = file->private_data; + struct sk_buff *skb; + ssize_t ret_cnt; + size_t len = 0, not_copied; + char *buf; + int ret; + + buf = vmalloc(count); + if (!buf) + return -ENOMEM; + + spin_lock(&ar->debug.fwlog_queue.lock); + + if (skb_queue_len(&ar->debug.fwlog_queue) == 0) { + /* we must init under queue lock */ + init_completion(&ar->debug.fwlog_completion); + + spin_unlock(&ar->debug.fwlog_queue.lock); + + ret = wait_for_completion_interruptible( + &ar->debug.fwlog_completion); + if (ret == -ERESTARTSYS) + return ret; + + spin_lock(&ar->debug.fwlog_queue.lock); + } + + while ((skb = __skb_dequeue(&ar->debug.fwlog_queue))) { + if (skb->len > count - len) { + /* not enough space, put skb back and leave */ + __skb_queue_head(&ar->debug.fwlog_queue, skb); + break; + } + + + memcpy(buf + len, skb->data, skb->len); + len += skb->len; + + kfree_skb(skb); + } + + spin_unlock(&ar->debug.fwlog_queue.lock); + + /* FIXME: what to do if len == 0? */ + + not_copied = copy_to_user(user_buf, buf, len); + if (not_copied != 0) { + ret_cnt = -EFAULT; + goto out; + } + + *ppos = *ppos + len; + + ret_cnt = len; + +out: + vfree(buf); + + return ret_cnt; +} + +static const struct file_operations fops_fwlog_block = { + .open = ath6kl_fwlog_open, + .release = ath6kl_fwlog_release, + .read = ath6kl_fwlog_block_read, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + static ssize_t ath6kl_fwlog_mask_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { @@ -1623,6 +1721,7 @@ static const struct file_operations fops_power_params = { int ath6kl_debug_init(struct ath6kl *ar) { skb_queue_head_init(&ar->debug.fwlog_queue); + init_completion(&ar->debug.fwlog_completion); /* * Actually we are lying here but don't know how to read the mask @@ -1647,6 +1746,9 @@ int ath6kl_debug_init(struct ath6kl *ar) debugfs_create_file("fwlog", S_IRUSR, ar->debugfs_phy, ar, &fops_fwlog); + debugfs_create_file("fwlog_block", S_IRUSR, ar->debugfs_phy, ar, + &fops_fwlog_block); + debugfs_create_file("fwlog_mask", S_IRUSR | S_IWUSR, ar->debugfs_phy, ar, &fops_fwlog_mask); -- cgit v1.2.2 From 1b2df4073447234034e2329f0df584c6346a8ec3 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Mon, 6 Feb 2012 20:15:53 +0530 Subject: ath6kl: Update license header Update license header with the copyright to Qualcomm Atheros, Inc. for the year 2011-2012. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/Makefile | 3 ++- drivers/net/wireless/ath/ath6kl/bmi.c | 1 + drivers/net/wireless/ath/ath6kl/bmi.h | 1 + drivers/net/wireless/ath/ath6kl/cfg80211.c | 1 + drivers/net/wireless/ath/ath6kl/cfg80211.h | 1 + drivers/net/wireless/ath/ath6kl/common.h | 1 + drivers/net/wireless/ath/ath6kl/core.c | 1 + drivers/net/wireless/ath/ath6kl/core.h | 1 + drivers/net/wireless/ath/ath6kl/debug.c | 1 + drivers/net/wireless/ath/ath6kl/debug.h | 1 + drivers/net/wireless/ath/ath6kl/hif-ops.h | 1 + drivers/net/wireless/ath/ath6kl/hif.c | 1 + drivers/net/wireless/ath/ath6kl/hif.h | 1 + drivers/net/wireless/ath/ath6kl/htc.c | 1 + drivers/net/wireless/ath/ath6kl/htc.h | 1 + drivers/net/wireless/ath/ath6kl/init.c | 1 + drivers/net/wireless/ath/ath6kl/main.c | 1 + drivers/net/wireless/ath/ath6kl/sdio.c | 1 + drivers/net/wireless/ath/ath6kl/target.h | 1 + drivers/net/wireless/ath/ath6kl/testmode.c | 1 + drivers/net/wireless/ath/ath6kl/testmode.h | 1 + drivers/net/wireless/ath/ath6kl/txrx.c | 1 + drivers/net/wireless/ath/ath6kl/usb.c | 1 + drivers/net/wireless/ath/ath6kl/wmi.c | 1 + drivers/net/wireless/ath/ath6kl/wmi.h | 1 + 25 files changed, 26 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath6kl/Makefile b/drivers/net/wireless/ath/ath6kl/Makefile index 9ba42fa04962..85746c3eb027 100644 --- a/drivers/net/wireless/ath/ath6kl/Makefile +++ b/drivers/net/wireless/ath/ath6kl/Makefile @@ -1,5 +1,6 @@ #------------------------------------------------------------------------------ -# Copyright (c) 2004-2010 Atheros Communications Inc. +# Copyright (c) 2004-2011 Atheros Communications Inc. +# Copyright (c) 2011-2012 Qualcomm Atheros, Inc. # All rights reserved. # # diff --git a/drivers/net/wireless/ath/ath6kl/bmi.c b/drivers/net/wireless/ath/ath6kl/bmi.c index aef00d5a1438..05d1d8941fd1 100644 --- a/drivers/net/wireless/ath/ath6kl/bmi.c +++ b/drivers/net/wireless/ath/ath6kl/bmi.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2004-2011 Atheros Communications Inc. + * Copyright (c) 2011-2012 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/drivers/net/wireless/ath/ath6kl/bmi.h b/drivers/net/wireless/ath/ath6kl/bmi.h index f1ca6812456d..114f7b265a3a 100644 --- a/drivers/net/wireless/ath/ath6kl/bmi.h +++ b/drivers/net/wireless/ath/ath6kl/bmi.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2004-2011 Atheros Communications Inc. + * Copyright (c) 2011 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index d1922d8eb3bb..a91f521c5227 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2004-2011 Atheros Communications Inc. + * Copyright (c) 2011-2012 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.h b/drivers/net/wireless/ath/ath6kl/cfg80211.h index 3c693b7c0efd..c5def436417f 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.h +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2011 Atheros Communications Inc. + * Copyright (c) 2011-2012 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/drivers/net/wireless/ath/ath6kl/common.h b/drivers/net/wireless/ath/ath6kl/common.h index f89f1e180da3..a60e78c0472f 100644 --- a/drivers/net/wireless/ath/ath6kl/common.h +++ b/drivers/net/wireless/ath/ath6kl/common.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2010-2011 Atheros Communications Inc. + * Copyright (c) 2011-2012 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/drivers/net/wireless/ath/ath6kl/core.c b/drivers/net/wireless/ath/ath6kl/core.c index 722ca59b88ce..c4926cf11213 100644 --- a/drivers/net/wireless/ath/ath6kl/core.c +++ b/drivers/net/wireless/ath/ath6kl/core.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2004-2011 Atheros Communications Inc. + * Copyright (c) 2011-2012 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h index 4ff06a326785..ec7d6b67b7ff 100644 --- a/drivers/net/wireless/ath/ath6kl/core.h +++ b/drivers/net/wireless/ath/ath6kl/core.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2010-2011 Atheros Communications Inc. + * Copyright (c) 2011-2012 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/drivers/net/wireless/ath/ath6kl/debug.c b/drivers/net/wireless/ath/ath6kl/debug.c index ec32ff692163..3d0713dfe3b9 100644 --- a/drivers/net/wireless/ath/ath6kl/debug.c +++ b/drivers/net/wireless/ath/ath6kl/debug.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2004-2011 Atheros Communications Inc. + * Copyright (c) 2011-2012 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/drivers/net/wireless/ath/ath6kl/debug.h b/drivers/net/wireless/ath/ath6kl/debug.h index c4be6e50996b..c5d5e6c8259e 100644 --- a/drivers/net/wireless/ath/ath6kl/debug.h +++ b/drivers/net/wireless/ath/ath6kl/debug.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2011 Atheros Communications Inc. + * Copyright (c) 2011-2012 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/drivers/net/wireless/ath/ath6kl/hif-ops.h b/drivers/net/wireless/ath/ath6kl/hif-ops.h index 2fe1dadfc77a..fd84086638e3 100644 --- a/drivers/net/wireless/ath/ath6kl/hif-ops.h +++ b/drivers/net/wireless/ath/ath6kl/hif-ops.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2004-2011 Atheros Communications Inc. + * Copyright (c) 2011 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/drivers/net/wireless/ath/ath6kl/hif.c b/drivers/net/wireless/ath/ath6kl/hif.c index e911737ab345..18c7f6453313 100644 --- a/drivers/net/wireless/ath/ath6kl/hif.c +++ b/drivers/net/wireless/ath/ath6kl/hif.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2007-2011 Atheros Communications Inc. + * Copyright (c) 2011-2012 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/drivers/net/wireless/ath/ath6kl/hif.h b/drivers/net/wireless/ath/ath6kl/hif.h index 699a036f3a44..fb4186f5d432 100644 --- a/drivers/net/wireless/ath/ath6kl/hif.h +++ b/drivers/net/wireless/ath/ath6kl/hif.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2004-2011 Atheros Communications Inc. + * Copyright (c) 2011 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/drivers/net/wireless/ath/ath6kl/htc.c b/drivers/net/wireless/ath/ath6kl/htc.c index 2d721903640b..1385f719ad07 100644 --- a/drivers/net/wireless/ath/ath6kl/htc.c +++ b/drivers/net/wireless/ath/ath6kl/htc.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2007-2011 Atheros Communications Inc. + * Copyright (c) 2011-2012 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/drivers/net/wireless/ath/ath6kl/htc.h b/drivers/net/wireless/ath/ath6kl/htc.h index 57672e1ed1a6..84a2ab52aa68 100644 --- a/drivers/net/wireless/ath/ath6kl/htc.h +++ b/drivers/net/wireless/ath/ath6kl/htc.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2004-2011 Atheros Communications Inc. + * Copyright (c) 2011 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c index 0d76c3778106..6183d5794929 100644 --- a/drivers/net/wireless/ath/ath6kl/init.c +++ b/drivers/net/wireless/ath/ath6kl/init.c @@ -1,6 +1,7 @@ /* * Copyright (c) 2011 Atheros Communications Inc. + * Copyright (c) 2011-2012 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/drivers/net/wireless/ath/ath6kl/main.c b/drivers/net/wireless/ath/ath6kl/main.c index b96d01a7919b..d463a18332dc 100644 --- a/drivers/net/wireless/ath/ath6kl/main.c +++ b/drivers/net/wireless/ath/ath6kl/main.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2004-2011 Atheros Communications Inc. + * Copyright (c) 2011-2012 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/drivers/net/wireless/ath/ath6kl/sdio.c b/drivers/net/wireless/ath/ath6kl/sdio.c index 4febee723495..2826613b1933 100644 --- a/drivers/net/wireless/ath/ath6kl/sdio.c +++ b/drivers/net/wireless/ath/ath6kl/sdio.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2004-2011 Atheros Communications Inc. + * Copyright (c) 2011-2012 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/drivers/net/wireless/ath/ath6kl/target.h b/drivers/net/wireless/ath/ath6kl/target.h index 108a723a1085..ac27962f8fc1 100644 --- a/drivers/net/wireless/ath/ath6kl/target.h +++ b/drivers/net/wireless/ath/ath6kl/target.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2004-2010 Atheros Communications Inc. + * Copyright (c) 2011 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/drivers/net/wireless/ath/ath6kl/testmode.c b/drivers/net/wireless/ath/ath6kl/testmode.c index f0cd61d6188a..6675c92b542b 100644 --- a/drivers/net/wireless/ath/ath6kl/testmode.c +++ b/drivers/net/wireless/ath/ath6kl/testmode.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2010-2011 Atheros Communications Inc. + * Copyright (c) 2011 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/drivers/net/wireless/ath/ath6kl/testmode.h b/drivers/net/wireless/ath/ath6kl/testmode.h index 7fd47a62d078..fe651d6707df 100644 --- a/drivers/net/wireless/ath/ath6kl/testmode.h +++ b/drivers/net/wireless/ath/ath6kl/testmode.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2010-2011 Atheros Communications Inc. + * Copyright (c) 2011 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/drivers/net/wireless/ath/ath6kl/txrx.c b/drivers/net/wireless/ath/ath6kl/txrx.c index a3dc6943c7f7..87d46460a524 100644 --- a/drivers/net/wireless/ath/ath6kl/txrx.c +++ b/drivers/net/wireless/ath/ath6kl/txrx.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2004-2011 Atheros Communications Inc. + * Copyright (c) 2011-2012 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/drivers/net/wireless/ath/ath6kl/usb.c b/drivers/net/wireless/ath/ath6kl/usb.c index c72567c6d338..325b1224c2b1 100644 --- a/drivers/net/wireless/ath/ath6kl/usb.c +++ b/drivers/net/wireless/ath/ath6kl/usb.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2007-2011 Atheros Communications Inc. + * Copyright (c) 2011-2012 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index 18fa9aa8af92..bbbe0a74d3c3 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2004-2011 Atheros Communications Inc. + * Copyright (c) 2011-2012 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h index e7919869725e..e7d031b8451d 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.h +++ b/drivers/net/wireless/ath/ath6kl/wmi.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2010-2011 Atheros Communications Inc. + * Copyright (c) 2011-2012 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above -- cgit v1.2.2 From b29072cc7b0e08ace48ab709c40cf6246fb2e8b0 Mon Sep 17 00:00:00 2001 From: Chilam Ng Date: Tue, 7 Feb 2012 01:33:00 -0800 Subject: ath6kl: prioritize Tx bundling based on AC priorities Tx bundling is the more efficient use of SDIO bus and allows more packet transfers with fewer bus transactions, and is a way to improve overall throughput. However, Tx bundling has only 4 scatter request resources available. When there are multiple traffic streams of different priorities, it's possible that lower priority traffic may hog all the scatter requests and lock out the higher prioirty traffic from bundling. Tx bundling is now enabled per AC. When an AC do a scatter request and the remaining scatter request resources is lower than a configurable threshold, it will disable Tx bundling for all AC's of lower priorities. When an AC has Tx bundling disabled and has no Tx bundles sent in a consecutive and configurable number of packets, Tx bundling will be re-enabled for that AC. Signed-off-by: Chilam Ng Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/hif.h | 2 + drivers/net/wireless/ath/ath6kl/htc.c | 77 ++++++++++++++++++++++++++++++---- drivers/net/wireless/ath/ath6kl/htc.h | 7 +++- drivers/net/wireless/ath/ath6kl/sdio.c | 2 + 4 files changed, 80 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/ath/ath6kl/hif.h b/drivers/net/wireless/ath/ath6kl/hif.h index fb4186f5d432..904458ab484b 100644 --- a/drivers/net/wireless/ath/ath6kl/hif.h +++ b/drivers/net/wireless/ath/ath6kl/hif.h @@ -198,6 +198,8 @@ struct hif_scatter_req { u8 *virt_dma_buf; struct hif_scatter_item scat_list[1]; + + u32 scat_q_depth; }; struct ath6kl_irq_proc_registers { diff --git a/drivers/net/wireless/ath/ath6kl/htc.c b/drivers/net/wireless/ath/ath6kl/htc.c index 1385f719ad07..c703ef9c5313 100644 --- a/drivers/net/wireless/ath/ath6kl/htc.c +++ b/drivers/net/wireless/ath/ath6kl/htc.c @@ -23,6 +23,9 @@ #define CALC_TXRX_PADDED_LEN(dev, len) (__ALIGN_MASK((len), (dev)->block_mask)) +/* threshold to re-enable Tx bundling for an AC*/ +#define TX_RESUME_BUNDLE_THRESHOLD 1500 + /* Functions for Tx credit handling */ static void ath6kl_credit_deposit(struct ath6kl_htc_credit_info *cred_info, struct htc_endpoint_credit_dist *ep_dist, @@ -745,6 +748,12 @@ static void ath6kl_htc_tx_bundle(struct htc_endpoint *endpoint, struct hif_scatter_req *scat_req = NULL; int n_scat, n_sent_bundle = 0, tot_pkts_bundle = 0; int status; + u32 txb_mask; + u8 ac = WMM_NUM_AC; + + if ((HTC_CTRL_RSVD_SVC != endpoint->svc_id) || + (WMI_CONTROL_SVC != endpoint->svc_id)) + ac = target->dev->ar->ep2ac_map[endpoint->eid]; while (true) { status = 0; @@ -764,6 +773,31 @@ static void ath6kl_htc_tx_bundle(struct htc_endpoint *endpoint, break; } + if ((ac < WMM_NUM_AC) && (ac != WMM_AC_BK)) { + if (WMM_AC_BE == ac) + /* + * BE, BK have priorities and bit + * positions reversed + */ + txb_mask = (1 << WMM_AC_BK); + else + /* + * any AC with priority lower than + * itself + */ + txb_mask = ((1 << ac) - 1); + /* + * when the scatter request resources drop below a + * certain threshold, disable Tx bundling for all + * AC's with priority lower than the current requesting + * AC. Otherwise re-enable Tx bundling for them + */ + if (scat_req->scat_q_depth < ATH6KL_SCATTER_REQS) + target->tx_bndl_mask &= ~txb_mask; + else + target->tx_bndl_mask |= txb_mask; + } + ath6kl_dbg(ATH6KL_DBG_HTC, "htc tx pkts to scatter: %d\n", n_scat); @@ -807,6 +841,7 @@ static void ath6kl_htc_tx_from_queue(struct htc_target *target, struct htc_packet *packet; int bundle_sent; int n_pkts_bundle; + u8 ac = WMM_NUM_AC; spin_lock_bh(&target->tx_lock); @@ -824,6 +859,10 @@ static void ath6kl_htc_tx_from_queue(struct htc_target *target, */ INIT_LIST_HEAD(&txq); + if ((HTC_CTRL_RSVD_SVC != endpoint->svc_id) || + (WMI_CONTROL_SVC != endpoint->svc_id)) + ac = target->dev->ar->ep2ac_map[endpoint->eid]; + while (true) { if (list_empty(&endpoint->txq)) @@ -841,15 +880,18 @@ static void ath6kl_htc_tx_from_queue(struct htc_target *target, while (true) { /* try to send a bundle on each pass */ - if ((target->tx_bndl_enable) && + if ((target->tx_bndl_mask) && (get_queue_depth(&txq) >= HTC_MIN_HTC_MSGS_TO_BUNDLE)) { int temp1 = 0, temp2 = 0; - ath6kl_htc_tx_bundle(endpoint, &txq, - &temp1, &temp2); - bundle_sent += temp1; - n_pkts_bundle += temp2; + /* check if bundling is enabled for an AC */ + if (target->tx_bndl_mask & (1 << ac)) { + ath6kl_htc_tx_bundle(endpoint, &txq, + &temp1, &temp2); + bundle_sent += temp1; + n_pkts_bundle += temp2; + } } if (list_empty(&txq)) @@ -868,6 +910,26 @@ static void ath6kl_htc_tx_from_queue(struct htc_target *target, endpoint->ep_st.tx_bundles += bundle_sent; endpoint->ep_st.tx_pkt_bundled += n_pkts_bundle; + + /* + * if an AC has bundling disabled and no tx bundling + * has occured continously for a certain number of TX, + * enable tx bundling for this AC + */ + if (!bundle_sent) { + if (!(target->tx_bndl_mask & (1 << ac)) && + (ac < WMM_NUM_AC)) { + if (++target->ac_tx_count[ac] >= + TX_RESUME_BUNDLE_THRESHOLD) { + target->ac_tx_count[ac] = 0; + target->tx_bndl_mask |= (1 << ac); + } + } + } else { + /* tx bundling will reset the counter */ + if (ac < WMM_NUM_AC) + target->ac_tx_count[ac] = 0; + } } endpoint->tx_proc_cnt = 0; @@ -2518,7 +2580,8 @@ static void htc_setup_msg_bndl(struct htc_target *target) target->max_rx_bndl_sz, target->max_tx_bndl_sz); if (target->max_tx_bndl_sz) - target->tx_bndl_enable = true; + /* tx_bndl_mask is enabled per AC, each has 1 bit */ + target->tx_bndl_mask = (1 << WMM_NUM_AC) - 1; if (target->max_rx_bndl_sz) target->rx_bndl_enable = true; @@ -2533,7 +2596,7 @@ static void htc_setup_msg_bndl(struct htc_target *target) * padding will spill into the next credit buffer * which is fatal. */ - target->tx_bndl_enable = false; + target->tx_bndl_mask = 0; } } diff --git a/drivers/net/wireless/ath/ath6kl/htc.h b/drivers/net/wireless/ath/ath6kl/htc.h index 84a2ab52aa68..519766571334 100644 --- a/drivers/net/wireless/ath/ath6kl/htc.h +++ b/drivers/net/wireless/ath/ath6kl/htc.h @@ -88,6 +88,8 @@ #define WMI_DATA_VO_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP, 4) #define WMI_MAX_SERVICES 5 +#define WMM_NUM_AC 4 + /* reserved and used to flush ALL packets */ #define HTC_TX_PACKET_TAG_ALL 0 #define HTC_SERVICE_TX_PACKET_TAG 1 @@ -532,7 +534,7 @@ struct htc_target { /* max messages per bundle for HTC */ int msg_per_bndl_max; - bool tx_bndl_enable; + u32 tx_bndl_mask; int rx_bndl_enable; int max_rx_bndl_sz; int max_tx_bndl_sz; @@ -544,6 +546,9 @@ struct htc_target { int max_xfer_szper_scatreq; int chk_irq_status_cnt; + + /* counts the number of Tx without bundling continously per AC */ + u32 ac_tx_count[WMM_NUM_AC]; }; void *ath6kl_htc_create(struct ath6kl *ar); diff --git a/drivers/net/wireless/ath/ath6kl/sdio.c b/drivers/net/wireless/ath/ath6kl/sdio.c index 2826613b1933..cae446bf2129 100644 --- a/drivers/net/wireless/ath/ath6kl/sdio.c +++ b/drivers/net/wireless/ath/ath6kl/sdio.c @@ -602,6 +602,8 @@ static struct hif_scatter_req *ath6kl_sdio_scatter_req_get(struct ath6kl *ar) node = list_first_entry(&ar_sdio->scat_req, struct hif_scatter_req, list); list_del(&node->list); + + node->scat_q_depth = get_queue_depth(&ar_sdio->scat_req); } spin_unlock_bh(&ar_sdio->scat_lock); -- cgit v1.2.2 From fb1ac2efa323de21bc83c1b3d326d06f8251ea4f Mon Sep 17 00:00:00 2001 From: Prasanna Kumar Date: Tue, 7 Feb 2012 14:58:54 -0800 Subject: ath6kl: add support for AR6003 2048 byte board file AR6003 2.1.1 supports both 1792 and 2048 byte board files. Add support for 2048 byte board file. kvalo: add ath6kl prefix to the title Signed-off-by: Prasanna Kumar Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/init.c | 2 ++ drivers/net/wireless/ath/ath6kl/target.h | 1 + 2 files changed, 3 insertions(+) diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c index 6183d5794929..72f1b4f52b2e 100644 --- a/drivers/net/wireless/ath/ath6kl/init.c +++ b/drivers/net/wireless/ath/ath6kl/init.c @@ -1124,6 +1124,8 @@ static int ath6kl_upload_board_file(struct ath6kl *ar) case TARGET_TYPE_AR6003: board_data_size = AR6003_BOARD_DATA_SZ; board_ext_data_size = AR6003_BOARD_EXT_DATA_SZ; + if (ar->fw_board_len > (board_data_size + board_ext_data_size)) + board_ext_data_size = AR6003_BOARD_EXT_DATA_SZ_V2; break; case TARGET_TYPE_AR6004: board_data_size = AR6004_BOARD_DATA_SZ; diff --git a/drivers/net/wireless/ath/ath6kl/target.h b/drivers/net/wireless/ath/ath6kl/target.h index ac27962f8fc1..78e0ef4567a5 100644 --- a/drivers/net/wireless/ath/ath6kl/target.h +++ b/drivers/net/wireless/ath/ath6kl/target.h @@ -20,6 +20,7 @@ #define AR6003_BOARD_DATA_SZ 1024 #define AR6003_BOARD_EXT_DATA_SZ 768 +#define AR6003_BOARD_EXT_DATA_SZ_V2 1024 #define AR6004_BOARD_DATA_SZ 6144 #define AR6004_BOARD_EXT_DATA_SZ 0 -- cgit v1.2.2 From 3b96d49a79021ce4c1ca26aecd784d16aeb91a7c Mon Sep 17 00:00:00 2001 From: Naveen Gangadharan Date: Tue, 7 Feb 2012 22:53:32 -0800 Subject: ath6kl: Fix firmware crash dump The firmware crash dump printout was wrong as it was using incorrect offsets. kvalo: improve commit log, change the "%d:" to print word indexes, not bytes Signed-off-by: Naveen Gangadharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/hif.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath6kl/hif.c b/drivers/net/wireless/ath/ath6kl/hif.c index 18c7f6453313..ef650b61740a 100644 --- a/drivers/net/wireless/ath/ath6kl/hif.c +++ b/drivers/net/wireless/ath/ath6kl/hif.c @@ -107,9 +107,9 @@ static void ath6kl_hif_dump_fw_crash(struct ath6kl *ar) BUILD_BUG_ON(REG_DUMP_COUNT_AR6003 % 4); - for (i = 0; i < REG_DUMP_COUNT_AR6003 / 4; i++) { + for (i = 0; i < REG_DUMP_COUNT_AR6003; i += 4) { ath6kl_info("%d: 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x\n", - 4 * i, + i, le32_to_cpu(regdump_val[i]), le32_to_cpu(regdump_val[i + 1]), le32_to_cpu(regdump_val[i + 2]), -- cgit v1.2.2 From d0ff7383a3164adff7072719717d574436ec1677 Mon Sep 17 00:00:00 2001 From: Naveen Gangadharan Date: Wed, 8 Feb 2012 17:51:36 -0800 Subject: ath6kl: Add unicast mgmt frame buffering PS buffering of unicast Action frames that are sent in a context of a BSS. In AP mode when the recepient station goes to powersave and PS_POLL flag is not set, we would buffer the frames. Send out unicast mgmt bufferred frame when PS_POLL is received. This fixes a bug in P2P GO behavior when sending a GO Discoverability Request to a client that is in sleep mode. kvalo: indentation fixes Signed-off-by: Thirumalai Pachamuthu Signed-off-by: Naveen Gangadharan Signed-off-by: Aarthi Thiruvengadam Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/cfg80211.c | 98 +++++++++++++++++++++++++----- drivers/net/wireless/ath/ath6kl/core.c | 2 + drivers/net/wireless/ath/ath6kl/core.h | 12 ++++ drivers/net/wireless/ath/ath6kl/main.c | 41 ++++++++++--- drivers/net/wireless/ath/ath6kl/txrx.c | 25 ++++++++ drivers/net/wireless/ath/ath6kl/wmi.c | 37 +++++++++-- drivers/net/wireless/ath/ath6kl/wmi.h | 3 - 7 files changed, 188 insertions(+), 30 deletions(-) diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index a91f521c5227..86879896b1ab 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -2573,6 +2573,76 @@ static int ath6kl_send_go_probe_resp(struct ath6kl_vif *vif, return ret; } +static bool ath6kl_mgmt_powersave_ap(struct ath6kl_vif *vif, + u32 id, + u32 freq, + u32 wait, + const u8 *buf, + size_t len, + bool *more_data, + bool no_cck) +{ + struct ieee80211_mgmt *mgmt; + struct ath6kl_sta *conn; + bool is_psq_empty = false; + struct ath6kl_mgmt_buff *mgmt_buf; + size_t mgmt_buf_size; + struct ath6kl *ar = vif->ar; + + mgmt = (struct ieee80211_mgmt *) buf; + if (is_multicast_ether_addr(mgmt->da)) + return false; + + conn = ath6kl_find_sta(vif, mgmt->da); + if (!conn) + return false; + + if (conn->sta_flags & STA_PS_SLEEP) { + if (!(conn->sta_flags & STA_PS_POLLED)) { + /* Queue the frames if the STA is sleeping */ + mgmt_buf_size = len + sizeof(struct ath6kl_mgmt_buff); + mgmt_buf = kmalloc(mgmt_buf_size, GFP_KERNEL); + if (!mgmt_buf) + return false; + + INIT_LIST_HEAD(&mgmt_buf->list); + mgmt_buf->id = id; + mgmt_buf->freq = freq; + mgmt_buf->wait = wait; + mgmt_buf->len = len; + mgmt_buf->no_cck = no_cck; + memcpy(mgmt_buf->buf, buf, len); + spin_lock_bh(&conn->psq_lock); + is_psq_empty = skb_queue_empty(&conn->psq) && + (conn->mgmt_psq_len == 0); + list_add_tail(&mgmt_buf->list, &conn->mgmt_psq); + conn->mgmt_psq_len++; + spin_unlock_bh(&conn->psq_lock); + + /* + * If this is the first pkt getting queued + * for this STA, update the PVB for this + * STA. + */ + if (is_psq_empty) + ath6kl_wmi_set_pvb_cmd(ar->wmi, vif->fw_vif_idx, + conn->aid, 1); + return true; + } + + /* + * This tx is because of a PsPoll. + * Determine if MoreData bit has to be set. + */ + spin_lock_bh(&conn->psq_lock); + if (!skb_queue_empty(&conn->psq) || (conn->mgmt_psq_len != 0)) + *more_data = true; + spin_unlock_bh(&conn->psq_lock); + } + + return false; +} + static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, struct ieee80211_channel *chan, bool offchan, enum nl80211_channel_type channel_type, @@ -2584,6 +2654,7 @@ static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, struct ath6kl_vif *vif = netdev_priv(dev); u32 id; const struct ieee80211_mgmt *mgmt; + bool more_data, queued; mgmt = (const struct ieee80211_mgmt *) buf; if (buf + len >= mgmt->u.probe_resp.variable && @@ -2609,22 +2680,19 @@ static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, *cookie = id; - if (test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX, - ar->fw_capabilities)) { - /* - * If capable of doing P2P mgmt operations using - * station interface, send additional information like - * supported rates to advertise and xmit rates for - * probe requests - */ - return ath6kl_wmi_send_mgmt_cmd(ar->wmi, vif->fw_vif_idx, id, - chan->center_freq, wait, - buf, len, no_cck); - } else { - return ath6kl_wmi_send_action_cmd(ar->wmi, vif->fw_vif_idx, id, - chan->center_freq, wait, - buf, len); + /* AP mode Power saving processing */ + if (vif->nw_type == AP_NETWORK) { + queued = ath6kl_mgmt_powersave_ap(vif, + id, chan->center_freq, + wait, buf, + len, &more_data, no_cck); + if (queued) + return 0; } + + return ath6kl_wmi_send_mgmt_cmd(ar->wmi, vif->fw_vif_idx, id, + chan->center_freq, wait, + buf, len, no_cck); } static void ath6kl_mgmt_frame_register(struct wiphy *wiphy, diff --git a/drivers/net/wireless/ath/ath6kl/core.c b/drivers/net/wireless/ath/ath6kl/core.c index c4926cf11213..6dec186d9ac7 100644 --- a/drivers/net/wireless/ath/ath6kl/core.c +++ b/drivers/net/wireless/ath/ath6kl/core.c @@ -262,6 +262,8 @@ struct ath6kl *ath6kl_core_create(struct device *dev) spin_lock_init(&ar->sta_list[ctr].psq_lock); skb_queue_head_init(&ar->sta_list[ctr].psq); skb_queue_head_init(&ar->sta_list[ctr].apsdq); + ar->sta_list[ctr].mgmt_psq_len = 0; + INIT_LIST_HEAD(&ar->sta_list[ctr].mgmt_psq); ar->sta_list[ctr].aggr_conn = kzalloc(sizeof(struct aggr_info_conn), GFP_KERNEL); if (!ar->sta_list[ctr].aggr_conn) { diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h index ec7d6b67b7ff..09efafa5fef1 100644 --- a/drivers/net/wireless/ath/ath6kl/core.h +++ b/drivers/net/wireless/ath/ath6kl/core.h @@ -286,6 +286,16 @@ struct ath6kl_cookie { struct ath6kl_cookie *arc_list_next; }; +struct ath6kl_mgmt_buff { + struct list_head list; + u32 freq; + u32 wait; + u32 id; + bool no_cck; + size_t len; + u8 buf[0]; +}; + struct ath6kl_sta { u16 sta_flags; u8 mac[ETH_ALEN]; @@ -296,6 +306,8 @@ struct ath6kl_sta { u8 wpa_ie[ATH6KL_MAX_IE]; struct sk_buff_head psq; spinlock_t psq_lock; + struct list_head mgmt_psq; + size_t mgmt_psq_len; u8 apsd_info; struct sk_buff_head apsdq; struct aggr_info_conn *aggr_conn; diff --git a/drivers/net/wireless/ath/ath6kl/main.c b/drivers/net/wireless/ath/ath6kl/main.c index d463a18332dc..0d6e352bfb17 100644 --- a/drivers/net/wireless/ath/ath6kl/main.c +++ b/drivers/net/wireless/ath/ath6kl/main.c @@ -81,11 +81,21 @@ static void ath6kl_add_new_sta(struct ath6kl_vif *vif, u8 *mac, u16 aid, static void ath6kl_sta_cleanup(struct ath6kl *ar, u8 i) { struct ath6kl_sta *sta = &ar->sta_list[i]; + struct ath6kl_mgmt_buff *entry, *tmp; /* empty the queued pkts in the PS queue if any */ spin_lock_bh(&sta->psq_lock); skb_queue_purge(&sta->psq); skb_queue_purge(&sta->apsdq); + + if (sta->mgmt_psq_len != 0) { + list_for_each_entry_safe(entry, tmp, &sta->mgmt_psq, list) { + kfree(entry); + } + INIT_LIST_HEAD(&sta->mgmt_psq); + sta->mgmt_psq_len = 0; + } + spin_unlock_bh(&sta->psq_lock); memset(&ar->ap_stats.sta[sta->aid - 1], 0, @@ -811,6 +821,7 @@ void ath6kl_pspoll_event(struct ath6kl_vif *vif, u8 aid) struct sk_buff *skb; bool psq_empty = false; struct ath6kl *ar = vif->ar; + struct ath6kl_mgmt_buff *mgmt_buf; conn = ath6kl_find_sta_by_aid(ar, aid); @@ -821,7 +832,7 @@ void ath6kl_pspoll_event(struct ath6kl_vif *vif, u8 aid) * becomes empty update the PVB for this station. */ spin_lock_bh(&conn->psq_lock); - psq_empty = skb_queue_empty(&conn->psq); + psq_empty = skb_queue_empty(&conn->psq) && (conn->mgmt_psq_len == 0); spin_unlock_bh(&conn->psq_lock); if (psq_empty) @@ -829,15 +840,31 @@ void ath6kl_pspoll_event(struct ath6kl_vif *vif, u8 aid) return; spin_lock_bh(&conn->psq_lock); - skb = skb_dequeue(&conn->psq); - spin_unlock_bh(&conn->psq_lock); + if (conn->mgmt_psq_len > 0) { + mgmt_buf = list_first_entry(&conn->mgmt_psq, + struct ath6kl_mgmt_buff, list); + list_del(&mgmt_buf->list); + conn->mgmt_psq_len--; + spin_unlock_bh(&conn->psq_lock); + + conn->sta_flags |= STA_PS_POLLED; + ath6kl_wmi_send_mgmt_cmd(ar->wmi, vif->fw_vif_idx, + mgmt_buf->id, mgmt_buf->freq, + mgmt_buf->wait, mgmt_buf->buf, + mgmt_buf->len, mgmt_buf->no_cck); + conn->sta_flags &= ~STA_PS_POLLED; + kfree(mgmt_buf); + } else { + skb = skb_dequeue(&conn->psq); + spin_unlock_bh(&conn->psq_lock); - conn->sta_flags |= STA_PS_POLLED; - ath6kl_data_tx(skb, vif->ndev); - conn->sta_flags &= ~STA_PS_POLLED; + conn->sta_flags |= STA_PS_POLLED; + ath6kl_data_tx(skb, vif->ndev); + conn->sta_flags &= ~STA_PS_POLLED; + } spin_lock_bh(&conn->psq_lock); - psq_empty = skb_queue_empty(&conn->psq); + psq_empty = skb_queue_empty(&conn->psq) && (conn->mgmt_psq_len == 0); spin_unlock_bh(&conn->psq_lock); if (psq_empty) diff --git a/drivers/net/wireless/ath/ath6kl/txrx.c b/drivers/net/wireless/ath/ath6kl/txrx.c index 87d46460a524..633637ace661 100644 --- a/drivers/net/wireless/ath/ath6kl/txrx.c +++ b/drivers/net/wireless/ath/ath6kl/txrx.c @@ -1417,8 +1417,33 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet) if (!(conn->sta_flags & STA_PS_SLEEP)) { struct sk_buff *skbuff = NULL; bool is_apsdq_empty; + struct ath6kl_mgmt_buff *mgmt; + u8 idx; spin_lock_bh(&conn->psq_lock); + while (conn->mgmt_psq_len > 0) { + mgmt = list_first_entry( + &conn->mgmt_psq, + struct ath6kl_mgmt_buff, + list); + list_del(&mgmt->list); + conn->mgmt_psq_len--; + spin_unlock_bh(&conn->psq_lock); + idx = vif->fw_vif_idx; + + ath6kl_wmi_send_mgmt_cmd(ar->wmi, + idx, + mgmt->id, + mgmt->freq, + mgmt->wait, + mgmt->buf, + mgmt->len, + mgmt->no_cck); + + kfree(mgmt); + spin_lock_bh(&conn->psq_lock); + } + conn->mgmt_psq_len = 0; while ((skbuff = skb_dequeue(&conn->psq))) { spin_unlock_bh(&conn->psq_lock); ath6kl_data_tx(skbuff, vif->ndev); diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index bbbe0a74d3c3..fce29f7f2e5c 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -3182,8 +3182,9 @@ int ath6kl_wmi_remain_on_chnl_cmd(struct wmi *wmi, u8 if_idx, u32 freq, u32 dur) * ath6kl_wmi_send_mgmt_cmd instead. The new function supports P2P * mgmt operations using station interface. */ -int ath6kl_wmi_send_action_cmd(struct wmi *wmi, u8 if_idx, u32 id, u32 freq, - u32 wait, const u8 *data, u16 data_len) +static int ath6kl_wmi_send_action_cmd(struct wmi *wmi, u8 if_idx, u32 id, + u32 freq, u32 wait, const u8 *data, + u16 data_len) { struct sk_buff *skb; struct wmi_send_action_cmd *p; @@ -3219,9 +3220,9 @@ int ath6kl_wmi_send_action_cmd(struct wmi *wmi, u8 if_idx, u32 id, u32 freq, NO_SYNC_WMIFLAG); } -int ath6kl_wmi_send_mgmt_cmd(struct wmi *wmi, u8 if_idx, u32 id, u32 freq, - u32 wait, const u8 *data, u16 data_len, - u32 no_cck) +static int __ath6kl_wmi_send_mgmt_cmd(struct wmi *wmi, u8 if_idx, u32 id, + u32 freq, u32 wait, const u8 *data, + u16 data_len, u32 no_cck) { struct sk_buff *skb; struct wmi_send_mgmt_cmd *p; @@ -3258,6 +3259,32 @@ int ath6kl_wmi_send_mgmt_cmd(struct wmi *wmi, u8 if_idx, u32 id, u32 freq, NO_SYNC_WMIFLAG); } +int ath6kl_wmi_send_mgmt_cmd(struct wmi *wmi, u8 if_idx, u32 id, u32 freq, + u32 wait, const u8 *data, u16 data_len, + u32 no_cck) +{ + int status; + struct ath6kl *ar = wmi->parent_dev; + + if (test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX, + ar->fw_capabilities)) { + /* + * If capable of doing P2P mgmt operations using + * station interface, send additional information like + * supported rates to advertise and xmit rates for + * probe requests + */ + status = __ath6kl_wmi_send_mgmt_cmd(ar->wmi, if_idx, id, freq, + wait, data, data_len, + no_cck); + } else { + status = ath6kl_wmi_send_action_cmd(ar->wmi, if_idx, id, freq, + wait, data, data_len); + } + + return status; +} + int ath6kl_wmi_send_probe_response_cmd(struct wmi *wmi, u8 if_idx, u32 freq, const u8 *dst, const u8 *data, u16 data_len) diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h index e7d031b8451d..38907f411225 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.h +++ b/drivers/net/wireless/ath/ath6kl/wmi.h @@ -2506,9 +2506,6 @@ int ath6kl_wmi_disable_11b_rates_cmd(struct wmi *wmi, bool disable); int ath6kl_wmi_remain_on_chnl_cmd(struct wmi *wmi, u8 if_idx, u32 freq, u32 dur); -int ath6kl_wmi_send_action_cmd(struct wmi *wmi, u8 if_idx, u32 id, u32 freq, - u32 wait, const u8 *data, u16 data_len); - int ath6kl_wmi_send_mgmt_cmd(struct wmi *wmi, u8 if_idx, u32 id, u32 freq, u32 wait, const u8 *data, u16 data_len, u32 no_cck); -- cgit v1.2.2 From 0ea10f2b469ee51ed9948dd24cdd9582a98b885e Mon Sep 17 00:00:00 2001 From: Chilam Ng Date: Thu, 9 Feb 2012 02:17:01 -0800 Subject: ath6kl: assign Tx packet drop threshold per endpoint based on AC priority Tx packets will begin to drop when there are multiple traffic priorities and the current traffic is not the highest priority and the remaining cookies drop below a certain number, which is fixed for all AC. It is possilbe that lower priority AC have more traffic which will consume more cookies and lock out higher priority AC from having any. Assign each endpoint (AC) with a different Tx-packet-drop threshold so lower priority AC is more likely to drop packets and the cookies become more available to higher priority AC. Signed-off-by: Chilam Ng Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/htc.c | 9 +++++++++ drivers/net/wireless/ath/ath6kl/htc.h | 1 + drivers/net/wireless/ath/ath6kl/txrx.c | 3 ++- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath6kl/htc.c b/drivers/net/wireless/ath/ath6kl/htc.c index c703ef9c5313..920e7c07fd4f 100644 --- a/drivers/net/wireless/ath/ath6kl/htc.c +++ b/drivers/net/wireless/ath/ath6kl/htc.c @@ -2483,6 +2483,15 @@ int ath6kl_htc_conn_service(struct htc_target *target, endpoint->cred_dist.endpoint = assigned_ep; endpoint->cred_dist.cred_sz = target->tgt_cred_sz; + switch (endpoint->svc_id) { + case WMI_DATA_BK_SVC: + endpoint->tx_drop_packet_threshold = MAX_DEF_COOKIE_NUM / 3; + break; + default: + endpoint->tx_drop_packet_threshold = MAX_HI_COOKIE_NUM; + break; + } + if (conn_req->max_rxmsg_sz) { /* * Override cred_per_msg calculation, this optimizes diff --git a/drivers/net/wireless/ath/ath6kl/htc.h b/drivers/net/wireless/ath/ath6kl/htc.h index 519766571334..2de4d6fc1e32 100644 --- a/drivers/net/wireless/ath/ath6kl/htc.h +++ b/drivers/net/wireless/ath/ath6kl/htc.h @@ -501,6 +501,7 @@ struct htc_endpoint { u8 seqno; u32 conn_flags; struct htc_endpoint_stats ep_st; + u16 tx_drop_packet_threshold; }; struct htc_control_buffer { diff --git a/drivers/net/wireless/ath/ath6kl/txrx.c b/drivers/net/wireless/ath/ath6kl/txrx.c index 633637ace661..802291346d30 100644 --- a/drivers/net/wireless/ath/ath6kl/txrx.c +++ b/drivers/net/wireless/ath/ath6kl/txrx.c @@ -594,7 +594,8 @@ enum htc_send_full_action ath6kl_tx_queue_full(struct htc_target *target, */ if (ar->ac_stream_pri_map[ar->ep2ac_map[endpoint]] < ar->hiac_stream_active_pri && - ar->cookie_count <= MAX_HI_COOKIE_NUM) + ar->cookie_count <= + target->endpoint[endpoint].tx_drop_packet_threshold) /* * Give preference to the highest priority stream by * dropping the packets which overflowed. -- cgit v1.2.2 From e8ad9a0638cb50dad48201f461f4739740f036b3 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Tue, 14 Feb 2012 20:32:59 +0530 Subject: ath6kl: Fix missing release of semaphore in ath6kl_stop_txrx() This fixes smatch warning "inconsistent returns sem:&ar->sem". Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/init.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c index 72f1b4f52b2e..6fed6280174f 100644 --- a/drivers/net/wireless/ath/ath6kl/init.c +++ b/drivers/net/wireless/ath/ath6kl/init.c @@ -1733,5 +1733,7 @@ void ath6kl_stop_txrx(struct ath6kl *ar) ath6kl_reset_device(ar, ar->target_type, true, true); clear_bit(WLAN_ENABLED, &ar->flag); + + up(&ar->sem); } EXPORT_SYMBOL(ath6kl_stop_txrx); -- cgit v1.2.2 From cc4d623de46616825d9330467e0a7375835171be Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Tue, 14 Feb 2012 20:33:00 +0530 Subject: ath6kl: Remove bogus non-NULL pointer check In ath6kl_cfg80211_add_key(), params is checked for non-NULL but this pointer has been deferenced many times before this check. This gives the following smatch warning. add_key() can never carry NULL as params, remove this bogus check. ath6kl_cfg80211_add_key(86) warn: variable dereferenced before check 'params' Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/cfg80211.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index 86879896b1ab..a47688054ce9 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -1059,7 +1059,7 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, if (vif->nw_type == AP_NETWORK && !pairwise && (key_type == TKIP_CRYPT || key_type == AES_CRYPT || - key_type == WAPI_CRYPT) && params) { + key_type == WAPI_CRYPT)) { ar->ap_mode_bkey.valid = true; ar->ap_mode_bkey.key_index = key_index; ar->ap_mode_bkey.key_type = key_type; -- cgit v1.2.2 From bd5b5ac2873da5a153fa32ff58d2fc4e25f7bc8a Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Fri, 10 Feb 2012 20:40:32 +0530 Subject: ath6kl: Make sure to allocate rx buffers after the endpoint connection Rx buffers should be allocated for control and best effort endpoints only after the enpoints connection is esablished. But this is done before the endpoint connection is complete, we don't even the control and BE endpoints that time. Move the buffer allocation after endpoint connection is over, after ath6kl_init_hw_start(). Found in review, never seen any real issue with this. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/core.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath6kl/core.c b/drivers/net/wireless/ath/ath6kl/core.c index 6dec186d9ac7..39684650e843 100644 --- a/drivers/net/wireless/ath/ath6kl/core.c +++ b/drivers/net/wireless/ath/ath6kl/core.c @@ -136,10 +136,6 @@ int ath6kl_core_init(struct ath6kl *ar) ar->ac_stream_pri_map[WMM_AC_VI] = 2; ar->ac_stream_pri_map[WMM_AC_VO] = 3; /* highest */ - /* give our connected endpoints some buffers */ - ath6kl_rx_refill(ar->htc_target, ar->ctrl_ep); - ath6kl_rx_refill(ar->htc_target, ar->ac2ep_map[WMM_AC_BE]); - /* allocate some buffers that handle larger AMSDU frames */ ath6kl_refill_amsdu_rxbufs(ar, ATH6KL_MAX_AMSDU_RX_BUFFERS); @@ -182,6 +178,10 @@ int ath6kl_core_init(struct ath6kl *ar) goto err_rxbuf_cleanup; } + /* give our connected endpoints some buffers */ + ath6kl_rx_refill(ar->htc_target, ar->ctrl_ep); + ath6kl_rx_refill(ar->htc_target, ar->ac2ep_map[WMM_AC_BE]); + /* * Set mac address which is received in ready event * FIXME: Move to ath6kl_interface_add() -- cgit v1.2.2 From 5378f244b677f6696ca8a9a467cef16cd399b0e2 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Fri, 10 Feb 2012 20:40:33 +0530 Subject: ath6kl: Fix memory leak of rx packets in endpoint 0 htc_packet and htc_packet->buf_start are separately allocated for endpoint 0. This is different for other endpoints where packets are allocated as skb where htc_packet is skb->head and they are freed properly. Free htc_packet and htc_packet->buf_start separatly for endpoint 0. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/htc.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath6kl/htc.c b/drivers/net/wireless/ath/ath6kl/htc.c index 920e7c07fd4f..c6f45a744d52 100644 --- a/drivers/net/wireless/ath/ath6kl/htc.c +++ b/drivers/net/wireless/ath/ath6kl/htc.c @@ -2372,7 +2372,21 @@ void ath6kl_htc_flush_rx_buf(struct htc_target *target) "htc rx flush pkt 0x%p len %d ep %d\n", packet, packet->buf_len, packet->endpoint); - dev_kfree_skb(packet->pkt_cntxt); + /* + * packets in rx_bufq of endpoint 0 have originally + * been queued from target->free_ctrl_rxbuf where + * packet and packet->buf_start are allocated + * separately using kmalloc(). For other endpoint + * rx_bufq, it is allocated as skb where packet is + * skb->head. Take care of this difference while freeing + * the memory. + */ + if (packet->endpoint == ENDPOINT_0) { + kfree(packet->buf_start); + kfree(packet); + } else { + dev_kfree_skb(packet->pkt_cntxt); + } spin_lock_bh(&target->rx_lock); } spin_unlock_bh(&target->rx_lock); -- cgit v1.2.2 From 13423c31195efb1a1ac319294f5a0148a13433e6 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Tue, 21 Feb 2012 15:30:42 +0530 Subject: ath6kl: Make foreground scan a deterministic one This makes the device get into scan state as soon as a scan request is received, instead of blocking the scan request till the traffic comes down. It is necessary for the deterministic foreground scan particularly when having multiple vif operating where, if the scan is non- deterministic, scan on one interface will not start as long as there are traffic on the other interface. This change passes 50 msec as foreground scan interval to fix this. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/cfg80211.c | 11 +++++++---- drivers/net/wireless/ath/ath6kl/core.h | 3 +++ 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index a47688054ce9..d8d483798530 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -927,14 +927,17 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, */ ret = ath6kl_wmi_beginscan_cmd(ar->wmi, vif->fw_vif_idx, WMI_LONG_SCAN, force_fg_scan, - false, 0, 0, n_channels, - channels, request->no_cck, + false, 0, + ATH6KL_FG_SCAN_INTERVAL, + n_channels, channels, + request->no_cck, request->rates); } else { ret = ath6kl_wmi_startscan_cmd(ar->wmi, vif->fw_vif_idx, WMI_LONG_SCAN, force_fg_scan, - false, 0, 0, n_channels, - channels); + false, 0, + ATH6KL_FG_SCAN_INTERVAL, + n_channels, channels); } if (ret) ath6kl_err("wmi_startscan_cmd failed\n"); diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h index 09efafa5fef1..5bbc595f23d1 100644 --- a/drivers/net/wireless/ath/ath6kl/core.h +++ b/drivers/net/wireless/ath/ath6kl/core.h @@ -63,6 +63,9 @@ #define A_DEFAULT_LISTEN_INTERVAL 1 /* beacon intervals */ #define A_MAX_WOW_LISTEN_INTERVAL 1000 +/* Channel dwell time in fg scan */ +#define ATH6KL_FG_SCAN_INTERVAL 50 /* in ms */ + /* includes also the null byte */ #define ATH6KL_FIRMWARE_MAGIC "QCA-ATH6KL" -- cgit v1.2.2 From 4480bb59361b317d9a0a7b8cc6daafae14570f49 Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Wed, 22 Feb 2012 12:03:51 +0530 Subject: ath6kl: Lower SDIO pad drive strength for hw2.1.1 board Without this change, SDIO shuts down due to CRC error during data communication to the firmware in some of the platform. for example, scan request issued to the firmware doesn't return scan completed events and cause the socket interface to always return -16 (device busy). SDIO pad drive strength should be reduced for hw2.1.1 board to avoid such errors. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/init.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c index 6fed6280174f..f3b5502362d8 100644 --- a/drivers/net/wireless/ath/ath6kl/init.c +++ b/drivers/net/wireless/ath/ath6kl/init.c @@ -1406,7 +1406,8 @@ static int ath6kl_init_upload(struct ath6kl *ar) return status; /* WAR to avoid SDIO CRC err */ - if (ar->version.target_ver == AR6003_HW_2_0_VERSION) { + if (ar->version.target_ver == AR6003_HW_2_0_VERSION || + ar->version.target_ver == AR6003_HW_2_1_1_VERSION) { ath6kl_err("temporary war to avoid sdio crc error\n"); param = 0x20; -- cgit v1.2.2 From faaf192908b163eaeddc69940e08f2f42d72ea5d Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Mon, 27 Feb 2012 11:44:19 +0530 Subject: ath6kl: Register driver ht capabilities in wiphy Register driver's ht capabilities in wiphy to avoid failures in setting ht channels from hostapd. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/cfg80211.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index d8d483798530..5da0f292ec79 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -69,6 +69,10 @@ static struct ieee80211_rate ath6kl_rates[] = { #define ath6kl_g_rates (ath6kl_rates + 0) #define ath6kl_g_rates_size 12 +#define ath6kl_g_htcap (IEEE80211_HT_CAP_SUP_WIDTH_20_40 | \ + IEEE80211_HT_CAP_SGI_20 | \ + IEEE80211_HT_CAP_SGI_40) + static struct ieee80211_channel ath6kl_2ghz_channels[] = { CHAN2G(1, 2412, 0), CHAN2G(2, 2417, 0), @@ -113,6 +117,8 @@ static struct ieee80211_supported_band ath6kl_band_2ghz = { .channels = ath6kl_2ghz_channels, .n_bitrates = ath6kl_g_rates_size, .bitrates = ath6kl_g_rates, + .ht_cap.cap = ath6kl_g_htcap, + .ht_cap.ht_supported = true, }; static struct ieee80211_supported_band ath6kl_band_5ghz = { @@ -120,6 +126,8 @@ static struct ieee80211_supported_band ath6kl_band_5ghz = { .channels = ath6kl_5ghz_a_channels, .n_bitrates = ath6kl_a_rates_size, .bitrates = ath6kl_a_rates, + .ht_cap.cap = ath6kl_g_htcap, + .ht_cap.ht_supported = true, }; #define CCKM_KRK_CIPHER_SUITE 0x004096ff /* use for KRK */ -- cgit v1.2.2 From f2afdac709546f03cbdb11dc58f2c8250678bc66 Mon Sep 17 00:00:00 2001 From: V