+++ /dev/null
-Reason for not yet publishing: This code needs more testing and
-enhancements.
-
-From 067eeff8bf0ddb90ea77bf088f924c2a165a98d1 Mon Sep 17 00:00:00 2001
-From: Vasanthakumar Thiagarajan <vasanth@atheros.com>
-Date: Wed, 14 Apr 2010 11:36:44 -0700
-Subject: [PATCH 2/3] ath9k: Add pktlog support
-
-This adds packet log support for all of the supported
-Atheros hardware families under ath9k, AR5008, AR9001, AR9002
-and AR9003. Packet log is used to extract specific descriptor
-and rate control data into a binary file parsed for analysis
-by our systems team.
-
-Signed-off-by: Vasanthakumar Thiagarajan <vasanth@atheros.com>
----
- drivers/net/wireless/ath/ath9k/Kconfig | 8 +
- drivers/net/wireless/ath/ath9k/Makefile | 1 +
- drivers/net/wireless/ath/ath9k/ar9002_mac.c | 3 +-
- drivers/net/wireless/ath/ath9k/ar9003_mac.c | 4 +-
- drivers/net/wireless/ath/ath9k/ath9k.h | 6 +
- drivers/net/wireless/ath/ath9k/debug.c | 4 +
- drivers/net/wireless/ath/ath9k/hw-ops.h | 5 +-
- drivers/net/wireless/ath/ath9k/hw.c | 2 +-
- drivers/net/wireless/ath/ath9k/hw.h | 4 +-
- drivers/net/wireless/ath/ath9k/pktlog.c | 783 +++++++++++++++++++++++++++
- drivers/net/wireless/ath/ath9k/pktlog.h | 242 +++++++++
- drivers/net/wireless/ath/ath9k/rc.c | 22 +-
- drivers/net/wireless/ath/ath9k/recv.c | 15 +-
- drivers/net/wireless/ath/ath9k/xmit.c | 24 +-
- 14 files changed, 1103 insertions(+), 20 deletions(-)
- create mode 100644 drivers/net/wireless/ath/ath9k/pktlog.c
- create mode 100644 drivers/net/wireless/ath/ath9k/pktlog.h
-
---- a/drivers/net/wireless/ath/ath9k/Kconfig
-+++ b/drivers/net/wireless/ath/ath9k/Kconfig
-@@ -40,6 +40,13 @@ config ATH9K_RATE_CONTROL
- Say Y, if you want to use the ath9k specific rate control
- module instead of minstrel_ht.
-
-+config ATH9K_PKTLOG
-+ bool "ath9k packet logging support"
-+ depends on ATH9K_DEBUGFS
-+ ---help---
-+ Say Y to dump frame information during tx/rx, rate information
-+ and ani state.
-+
- config ATH9K_HTC
- tristate "Atheros HTC based wireless cards support"
- depends on USB && MAC80211
-@@ -61,3 +68,4 @@ config ATH9K_HTC_DEBUGFS
- depends on ATH9K_HTC && DEBUG_FS
- ---help---
- Say Y, if you need access to ath9k_htc's statistics.
-+
---- a/drivers/net/wireless/ath/ath9k/Makefile
-+++ b/drivers/net/wireless/ath/ath9k/Makefile
-@@ -9,6 +9,7 @@ ath9k-$(CONFIG_ATH9K_RATE_CONTROL) += rc
- ath9k-$(CONFIG_PCI) += pci.o
- ath9k-$(CONFIG_ATHEROS_AR71XX) += ahb.o
- ath9k-$(CONFIG_ATH9K_DEBUGFS) += debug.o
-+ath9k-$(CONFIG_ATH9K_PKTLOG) += pktlog.o
-
- obj-$(CONFIG_ATH9K) += ath9k.o
-
---- a/drivers/net/wireless/ath/ath9k/ar9002_mac.c
-+++ b/drivers/net/wireless/ath/ath9k/ar9002_mac.c
-@@ -205,7 +205,8 @@ static void ar9002_hw_fill_txdesc(struct
- }
-
- static int ar9002_hw_proc_txdesc(struct ath_hw *ah, void *ds,
-- struct ath_tx_status *ts)
-+ struct ath_tx_status *ts,
-+ void *txs_desc)
- {
- struct ar5416_desc *ads = AR5416DESC(ds);
- u32 status;
---- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c
-+++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c
-@@ -234,7 +234,8 @@ static void ar9003_hw_fill_txdesc(struct
- }
-
- static int ar9003_hw_proc_txdesc(struct ath_hw *ah, void *ds,
-- struct ath_tx_status *ts)
-+ struct ath_tx_status *ts,
-+ void *txs_desc)
- {
- struct ar9003_txs *ads;
- u32 status;
-@@ -308,6 +309,7 @@ static int ar9003_hw_proc_txdesc(struct
- ts->ts_rssi_ext1 = MS(status, AR_TxRSSIAnt11);
- ts->ts_rssi_ext2 = MS(status, AR_TxRSSIAnt12);
-
-+ memcpy(txs_desc, ads, sizeof(*ads));
- memset(ads, 0, sizeof(*ads));
-
- return 0;
---- a/drivers/net/wireless/ath/ath9k/ath9k.h
-+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
-@@ -24,6 +24,7 @@
-
- #include "debug.h"
- #include "common.h"
-+#include "pktlog.h"
-
- /*
- * Header for the ath9k.ko driver core *only* -- hw code nor any other driver
-@@ -550,6 +551,7 @@ struct ath_ant_comb {
- #define SC_OP_BT_SCAN BIT(13)
- #define SC_OP_ANI_RUN BIT(14)
- #define SC_OP_ENABLE_APM BIT(15)
-+#define SC_OP_PKTLOGGING BIT(16)
-
- /* Powersave flags */
- #define PS_WAIT_FOR_BEACON BIT(0)
-@@ -629,6 +631,10 @@ struct ath_softc {
- struct list_head nodes; /* basically, stations */
- unsigned int tx_complete_poll_work_seen;
- #endif
-+#ifdef CONFIG_ATH9K_PKTLOG
-+ struct ath_pktlog_debugfs pktlog;
-+#endif
-+ bool is_pkt_logging;
- struct ath_beacon_config cur_beacon_conf;
- struct delayed_work tx_complete_work;
- struct delayed_work hw_pll_work;
---- a/drivers/net/wireless/ath/ath9k/debug.c
-+++ b/drivers/net/wireless/ath/ath9k/debug.c
-@@ -1066,6 +1066,9 @@ static int open_file_regdump(struct inod
-
- file->private_data = buf;
-
-+ if (ath9k_init_pktlog(sc) != 0)
-+ return -EINVAL;
-+
- return 0;
- }
-
-@@ -1148,6 +1151,7 @@ int ath9k_init_debug(struct ath_hw *ah)
- sc->debug.regidx = 0;
- return 0;
- err:
-+ ath9k_deinit_pktlog(sc);
- debugfs_remove_recursive(sc->debug.debugfs_phy);
- sc->debug.debugfs_phy = NULL;
- return -ENOMEM;
---- a/drivers/net/wireless/ath/ath9k/hw-ops.h
-+++ b/drivers/net/wireless/ath/ath9k/hw-ops.h
-@@ -67,9 +67,10 @@ static inline void ath9k_hw_filltxdesc(s
- }
-
- static inline int ath9k_hw_txprocdesc(struct ath_hw *ah, void *ds,
-- struct ath_tx_status *ts)
-+ struct ath_tx_status *ts,
-+ void *txs_desc)
- {
-- return ath9k_hw_ops(ah)->proc_txdesc(ah, ds, ts);
-+ return ath9k_hw_ops(ah)->proc_txdesc(ah, ds, ts, txs_desc);
- }
-
- static inline void ath9k_hw_set11n_txdesc(struct ath_hw *ah, void *ds,
---- a/drivers/net/wireless/ath/ath9k/hw.c
-+++ b/drivers/net/wireless/ath/ath9k/hw.c
-@@ -2192,7 +2192,7 @@ void ath9k_hw_setrxfilter(struct ath_hw
- phybits |= AR_PHY_ERR_RADAR;
- if (bits & ATH9K_RX_FILTER_PHYERR)
- phybits |= AR_PHY_ERR_OFDM_TIMING | AR_PHY_ERR_CCK_TIMING;
-- REG_WRITE(ah, AR_PHY_ERR, phybits);
-+ REG_WRITE(ah, AR_PHY_ERR, 0xffffffff);
-
- if (phybits)
- REG_WRITE(ah, AR_RXCFG,
---- a/drivers/net/wireless/ath/ath9k/hw.h
-+++ b/drivers/net/wireless/ath/ath9k/hw.h
-@@ -620,7 +620,7 @@ struct ath_hw_ops {
- const void *ds0, dma_addr_t buf_addr,
- unsigned int qcu);
- int (*proc_txdesc)(struct ath_hw *ah, void *ds,
-- struct ath_tx_status *ts);
-+ struct ath_tx_status *ts, void* txs_desc);
- void (*set11n_txdesc)(struct ath_hw *ah, void *ds,
- u32 pktLen, enum ath9k_pkt_type type,
- u32 txPower, u32 keyIx,
-@@ -856,6 +856,8 @@ struct ath_hw {
-
- /* Enterprise mode cap */
- u32 ent_mode;
-+
-+ bool is_pkt_logging;
- };
-
- static inline struct ath_common *ath9k_hw_common(struct ath_hw *ah)
---- /dev/null
-+++ b/drivers/net/wireless/ath/ath9k/pktlog.c
-@@ -0,0 +1,783 @@
-+
-+#include <linux/vmalloc.h>
-+#include <linux/highmem.h>
-+#include "ath9k.h"
-+
-+static int ath9k_debugfs_open(struct inode *inode, struct file *file)
-+{
-+ file->private_data = inode->i_private;
-+ return 0;
-+}
-+
-+static struct page *pktlog_virt_to_logical(void *addr)
-+{
-+ struct page *page;
-+ unsigned long vpage = 0UL;
-+
-+ page = vmalloc_to_page(addr);
-+ if (page) {
-+ vpage = (unsigned long) page_address(page);
-+ vpage |= ((unsigned long) addr & (PAGE_SIZE - 1));
-+ }
-+ return virt_to_page((void *) vpage);
-+}
-+
-+static void ath_pktlog_release(struct ath_pktlog *pktlog)
-+{
-+ unsigned long page_cnt, vaddr;
-+ struct page *page;
-+
-+ page_cnt =
-+ ((sizeof(*(pktlog->pktlog_buf)) +
-+ pktlog->pktlog_buf_size) / PAGE_SIZE) + 1;
-+
-+ for (vaddr = (unsigned long) (pktlog->pktlog_buf); vaddr <
-+ (unsigned long) (pktlog->pktlog_buf) +
-+ (page_cnt * PAGE_SIZE);
-+ vaddr += PAGE_SIZE) {
-+ page = pktlog_virt_to_logical((void *) vaddr);
-+ clear_bit(PG_reserved, &page->flags);
-+ }
-+
-+ vfree(pktlog->pktlog_buf);
-+ pktlog->pktlog_buf = NULL;
-+}
-+
-+static int ath_alloc_pktlog_buf(struct ath_softc *sc)
-+{
-+ u32 page_cnt;
-+ unsigned long vaddr;
-+ struct page *page;
-+ struct ath_pktlog *pktlog = &sc->pktlog.pktlog;
-+
-+ if (pktlog->pktlog_buf_size == 0)
-+ return -EINVAL;
-+
-+ page_cnt = (sizeof(*(pktlog->pktlog_buf)) +
-+ pktlog->pktlog_buf_size) / PAGE_SIZE;
-+
-+ pktlog->pktlog_buf = vmalloc((page_cnt + 2) * PAGE_SIZE);
-+ if (pktlog->pktlog_buf == NULL) {
-+ printk(KERN_ERR "Failed to allocate memory for pktlog");
-+ return -ENOMEM;
-+ }
-+
-+ pktlog->pktlog_buf = (struct ath_pktlog_buf *)
-+ (((unsigned long)
-+ (pktlog->pktlog_buf)
-+ + PAGE_SIZE - 1) & PAGE_MASK);
-+
-+ for (vaddr = (unsigned long) (pktlog->pktlog_buf);
-+ vaddr < ((unsigned long) (pktlog->pktlog_buf)
-+ + (page_cnt * PAGE_SIZE)); vaddr += PAGE_SIZE) {
-+ page = pktlog_virt_to_logical((void *)vaddr);
-+ set_bit(PG_reserved, &page->flags);
-+ }
-+
-+ return 0;
-+}
-+
-+static void ath_init_pktlog_buf(struct ath_pktlog *pktlog)
-+{
-+ pktlog->pktlog_buf->bufhdr.magic_num = PKTLOG_MAGIC_NUM;
-+ pktlog->pktlog_buf->bufhdr.version = CUR_PKTLOG_VER;
-+ pktlog->pktlog_buf->rd_offset = -1;
-+ pktlog->pktlog_buf->wr_offset = 0;
-+ if (pktlog->pktlog_filter == 0)
-+ pktlog->pktlog_filter = ATH_PKTLOG_FILTER_DEFAULT;
-+}
-+
-+static char *ath_pktlog_getbuf(struct ath_pktlog *pl_info,
-+ u16 log_type, size_t log_size,
-+ u32 flags)
-+{
-+ struct ath_pktlog_buf *log_buf;
-+ struct ath_pktlog_hdr *log_hdr;
-+ int32_t cur_wr_offset, buf_size;
-+ char *log_ptr;
-+
-+ log_buf = pl_info->pktlog_buf;
-+ buf_size = pl_info->pktlog_buf_size;
-+
-+ spin_lock_bh(&pl_info->pktlog_lock);
-+ cur_wr_offset = log_buf->wr_offset;
-+ /* Move read offset to the next entry if there is a buffer overlap */
-+ if (log_buf->rd_offset >= 0) {
-+ if ((cur_wr_offset <= log_buf->rd_offset)
-+ && (cur_wr_offset +
-+ sizeof(struct ath_pktlog_hdr)) >
-+ log_buf->rd_offset)
-+ PKTLOG_MOV_RD_IDX(log_buf->rd_offset, log_buf,
-+ buf_size);
-+ } else {
-+ log_buf->rd_offset = cur_wr_offset;
-+ }
-+
-+ log_hdr =
-+ (struct ath_pktlog_hdr *) (log_buf->log_data + cur_wr_offset);
-+ log_hdr->log_type = log_type;
-+ log_hdr->flags = flags;
-+ log_hdr->timestamp = jiffies;
-+ log_hdr->size = (u16) log_size;
-+
-+ cur_wr_offset += sizeof(*log_hdr);
-+
-+ if ((buf_size - cur_wr_offset) < log_size) {
-+ while ((cur_wr_offset <= log_buf->rd_offset)
-+ && (log_buf->rd_offset < buf_size))
-+ PKTLOG_MOV_RD_IDX(log_buf->rd_offset, log_buf,
-+ buf_size);
-+ cur_wr_offset = 0;
-+ }
-+
-+ while ((cur_wr_offset <= log_buf->rd_offset)
-+ && (cur_wr_offset + log_size) > log_buf->rd_offset)
-+ PKTLOG_MOV_RD_IDX(log_buf->rd_offset, log_buf, buf_size);
-+
-+ log_ptr = &(log_buf->log_data[cur_wr_offset]);
-+
-+ cur_wr_offset += log_hdr->size;
-+
-+ log_buf->wr_offset =
-+ ((buf_size - cur_wr_offset) >=
-+ sizeof(struct ath_pktlog_hdr)) ? cur_wr_offset : 0;
-+ spin_unlock_bh(&pl_info->pktlog_lock);
-+
-+ return log_ptr;
-+}
-+
-+static void ath9k_hw_get_descinfo(struct ath_hw *ah, struct ath_desc_info *desc_info)
-+{
-+ desc_info->txctl_numwords = TXCTL_NUMWORDS(ah);
-+ desc_info->txctl_offset = TXCTL_OFFSET(ah);
-+ desc_info->txstatus_numwords = TXSTATUS_NUMWORDS(ah);
-+ desc_info->txstatus_offset = TXSTATUS_OFFSET(ah);
-+
-+ desc_info->rxctl_numwords = RXCTL_NUMWORDS(ah);
-+ desc_info->rxctl_offset = RXCTL_OFFSET(ah);
-+ desc_info->rxstatus_numwords = RXSTATUS_NUMWORDS(ah);
-+ desc_info->rxstatus_offset = RXSTATUS_OFFSET(ah);
-+}
-+
-+static int pktlog_pgfault(struct vm_area_struct *vma, struct vm_fault *vmf)
-+{
-+ unsigned long address = (unsigned long) vmf->virtual_address;
-+
-+ if (address == 0UL)
-+ return VM_FAULT_NOPAGE;
-+
-+ if (vmf->pgoff > vma->vm_end)
-+ return VM_FAULT_SIGBUS;
-+
-+ get_page(virt_to_page(address));
-+ vmf->page = virt_to_page(address);
-+ return VM_FAULT_MINOR;
-+}
-+
-+static struct vm_operations_struct pktlog_vmops = {
-+ .fault = pktlog_pgfault
-+};
-+
-+static int ath_pktlog_mmap(struct file *file, struct vm_area_struct *vma)
-+{
-+ struct ath_softc *sc = file->private_data;
-+
-+ /* entire buffer should be mapped */
-+ if (vma->vm_pgoff != 0)
-+ return -EINVAL;
-+
-+ if (!sc->pktlog.pktlog.pktlog_buf) {
-+ printk(KERN_ERR "Can't allocate pktlog buf");
-+ return -ENOMEM;
-+ }
-+
-+ vma->vm_flags |= VM_LOCKED;
-+ vma->vm_ops = &pktlog_vmops;
-+
-+ return 0;
-+}
-+
-+static ssize_t ath_pktlog_read(struct file *file, char __user *userbuf,
-+ size_t count, loff_t *ppos)
-+{
-+ size_t bufhdr_size;
-+ size_t nbytes = 0, ret_val = 0;
-+ int rem_len;
-+ int start_offset, end_offset;
-+ int fold_offset, ppos_data, cur_rd_offset;
-+ struct ath_softc *sc = file->private_data;
-+ struct ath_pktlog *pktlog_info = &sc->pktlog.pktlog;
-+ struct ath_pktlog_buf *log_buf = pktlog_info->pktlog_buf;
-+
-+ if (log_buf == NULL)
-+ return 0;
-+
-+ bufhdr_size = sizeof(log_buf->bufhdr);
-+
-+ /* copy valid log entries from circular buffer into user space */
-+ rem_len = count;
-+
-+ nbytes = 0;
-+
-+ if (*ppos < bufhdr_size) {
-+ nbytes = min((int) (bufhdr_size - *ppos), rem_len);
-+ if (copy_to_user(userbuf,
-+ ((char *) &log_buf->bufhdr) + *ppos, nbytes))
-+ return -EFAULT;
-+ rem_len -= nbytes;
-+ ret_val += nbytes;
-+ }
-+
-+ start_offset = log_buf->rd_offset;
-+
-+ if ((rem_len == 0) || (start_offset < 0))
-+ goto read_done;
-+
-+ fold_offset = -1;
-+ cur_rd_offset = start_offset;
-+
-+ /* Find the last offset and fold-offset if the buffer is folded */
-+ do {
-+ struct ath_pktlog_hdr *log_hdr;
-+ int log_data_offset;
-+
-+ log_hdr =
-+ (struct ath_pktlog_hdr *) (log_buf->log_data +
-+ cur_rd_offset);
-+
-+ log_data_offset = cur_rd_offset + sizeof(struct ath_pktlog_hdr);
-+
-+ if ((fold_offset == -1)
-+ && ((pktlog_info->pktlog_buf_size -
-+ log_data_offset) <= log_hdr->size))
-+ fold_offset = log_data_offset - 1;
-+
-+ PKTLOG_MOV_RD_IDX(cur_rd_offset, log_buf,
-+ pktlog_info->pktlog_buf_size);
-+
-+ if ((fold_offset == -1) && (cur_rd_offset == 0)
-+ && (cur_rd_offset != log_buf->wr_offset))
-+ fold_offset = log_data_offset + log_hdr->size - 1;
-+
-+ end_offset = log_data_offset + log_hdr->size - 1;
-+ } while (cur_rd_offset != log_buf->wr_offset);
-+
-+ ppos_data = *ppos + ret_val - bufhdr_size + start_offset;
-+
-+ if (fold_offset == -1) {
-+ if (ppos_data > end_offset)
-+ goto read_done;
-+
-+ nbytes = min(rem_len, end_offset - ppos_data + 1);
-+ if (copy_to_user(userbuf + ret_val,
-+ log_buf->log_data + ppos_data, nbytes))
-+ return -EFAULT;
-+ ret_val += nbytes;
-+ rem_len -= nbytes;
-+ } else {
-+ if (ppos_data <= fold_offset) {
-+ nbytes = min(rem_len, fold_offset - ppos_data + 1);
-+ if (copy_to_user(userbuf + ret_val,
-+ log_buf->log_data + ppos_data,
-+ nbytes))
-+ return -EFAULT;
-+ ret_val += nbytes;
-+ rem_len -= nbytes;
-+ }
-+
-+ if (rem_len == 0)
-+ goto read_done;
-+
-+ ppos_data =
-+ *ppos + ret_val - (bufhdr_size +
-+ (fold_offset - start_offset + 1));
-+
-+ if (ppos_data <= end_offset) {
-+ nbytes = min(rem_len, end_offset - ppos_data + 1);
-+ if (copy_to_user(userbuf + ret_val, log_buf->log_data
-+ + ppos_data,
-+ nbytes))
-+ return -EFAULT;
-+ ret_val += nbytes;
-+ rem_len -= nbytes;
-+ }
-+ }
-+
-+read_done:
-+ *ppos += ret_val;
-+
-+ return ret_val;
-+}
-+
-+static const struct file_operations fops_pktlog_dump = {
-+ .read = ath_pktlog_read,
-+ .mmap = ath_pktlog_mmap,
-+ .open = ath9k_debugfs_open
-+};
-+
-+static ssize_t write_pktlog_start(struct file *file, const char __user *ubuf,
-+ size_t count, loff_t *ppos)
-+{
-+ struct ath_softc *sc = file->private_data;
-+ struct ath_pktlog *pktlog = &sc->pktlog.pktlog;
-+ char buf[32];
-+ int buf_size;
-+ int start_pktlog, err;
-+
-+ buf_size = min(count, sizeof(buf) - 1);
-+ if (copy_from_user(buf, ubuf, buf_size))
-+ return -EFAULT;
-+
-+ sscanf(buf, "%d", &start_pktlog);
-+ if (start_pktlog) {
-+ if (pktlog->pktlog_buf != NULL)
-+ ath_pktlog_release(pktlog);
-+
-+ err = ath_alloc_pktlog_buf(sc);
-+ if (err != 0)
-+ return err;
-+
-+ ath_init_pktlog_buf(pktlog);
-+ pktlog->pktlog_buf->rd_offset = -1;
-+ pktlog->pktlog_buf->wr_offset = 0;
-+ sc->is_pkt_logging = 1;
-+ } else {
-+ sc->is_pkt_logging = 0;
-+ }
-+
-+ sc->sc_ah->is_pkt_logging = sc->is_pkt_logging;
-+ return count;
-+}
-+
-+static ssize_t read_pktlog_start(struct file *file, char __user *ubuf,
-+ size_t count, loff_t *ppos)
-+{
-+ char buf[32];
-+ struct ath_softc *sc = file->private_data;
-+ int len = 0;
-+
-+ len = scnprintf(buf, sizeof(buf) - len, "%d", sc->is_pkt_logging);
-+ return simple_read_from_buffer(ubuf, count, ppos, buf, len);
-+}
-+
-+static const struct file_operations fops_pktlog_start = {
-+ .read = read_pktlog_start,
-+ .write = write_pktlog_start,
-+ .open = ath9k_debugfs_open
-+};
-+
-+static ssize_t pktlog_size_write(struct file *file, const char __user *ubuf,
-+ size_t count, loff_t *ppos)
-+{
-+ struct ath_softc *sc = file->private_data;
-+ char buf[32];
-+ u32 pktlog_size;
-+ int buf_size;
-+
-+ buf_size = min(count, sizeof(buf) - 1);
-+ if (copy_from_user(buf, ubuf, buf_size))
-+ return -EFAULT;
-+
-+ sscanf(buf, "%d", &pktlog_size);
-+
-+ if (pktlog_size == sc->pktlog.pktlog.pktlog_buf_size)
-+ return count;
-+
-+ if (sc->is_pkt_logging) {
-+ printk(KERN_DEBUG "Stop packet logging before"
-+ " changing the pktlog size \n");
-+ return -EINVAL;
-+ }
-+
-+ sc->pktlog.pktlog.pktlog_buf_size = pktlog_size;
-+
-+ return count;
-+}
-+
-+static ssize_t pktlog_size_read(struct file *file, char __user *ubuf,
-+ size_t count, loff_t *ppos)
-+{
-+ char buf[32];
-+ struct ath_softc *sc = file->private_data;
-+ int len = 0;
-+
-+ len = scnprintf(buf, sizeof(buf) - len, "%ul",
-+ sc->pktlog.pktlog.pktlog_buf_size);
-+ return simple_read_from_buffer(ubuf, count, ppos, buf, len);
-+}
-+
-+static const struct file_operations fops_pktlog_size = {
-+ .read = pktlog_size_read,
-+ .write = pktlog_size_write,
-+ .open = ath9k_debugfs_open
-+};
-+
-+static ssize_t pktlog_filter_write(struct file *file, const char __user *ubuf,
-+ size_t count, loff_t *ppos)
-+{
-+ char buf[32];
-+ struct ath_softc *sc = file->private_data;
-+ u32 filter;
-+ int buf_count;
-+
-+ buf_count = min(count, sizeof(buf) - 1);
-+ if (copy_from_user(buf, ubuf, buf_count))
-+ return -EFAULT;
-+
-+ if (sscanf(buf, "%x", &filter))
-+ sc->pktlog.pktlog.pktlog_filter = filter;
-+ else
-+ sc->pktlog.pktlog.pktlog_filter = 0;
-+
-+ return count;
-+}
-+
-+static ssize_t pktlog_filter_read(struct file *file, char __user *ubuf,
-+ size_t count, loff_t *ppos)
-+{
-+ char buf[32];
-+ struct ath_softc *sc = file->private_data;
-+ int len = 0;
-+
-+ len = scnprintf(buf, sizeof(buf) - len, "%ul",
-+ sc->pktlog.pktlog.pktlog_filter);
-+
-+ return simple_read_from_buffer(ubuf, count, ppos, buf, len);
-+}
-+
-+static const struct file_operations fops_pktlog_filter = {
-+ .read = pktlog_filter_read,
-+ .write = pktlog_filter_write,
-+ .open = ath9k_debugfs_open
-+};
-+
-+void ath_pktlog_txctl(struct ath_softc *sc, struct ath_buf *bf)
-+{
-+ struct ath_pktlog_txctl *tx_log;
-+ struct ath_pktlog *pl_info;
-+ struct ieee80211_hdr *hdr;
-+ struct ath_desc_info desc_info;
-+ int i;
-+ u32 *ds_words, flags = 0;
-+
-+ pl_info = &sc->pktlog.pktlog;
-+
-+ if ((pl_info->pktlog_filter & ATH_PKTLOG_TX) == 0 ||
-+ bf->bf_mpdu == NULL || !sc->is_pkt_logging)
-+ return;
-+
-+ flags |= (((sc->sc_ah->hw_version.macRev <<
-+ PHFLAGS_MACREV_SFT) & PHFLAGS_MACREV_MASK) |
-+ ((sc->sc_ah->hw_version.macVersion << PHFLAGS_MACVERSION_SFT)
-+ & PHFLAGS_MACVERSION_MASK));
-+
-+ tx_log = (struct ath_pktlog_txctl *)ath_pktlog_getbuf(pl_info,
-+ PKTLOG_TYPE_TXCTL, sizeof(*tx_log), flags);
-+
-+ memset(tx_log, 0, sizeof(*tx_log));
-+
-+ hdr = (struct ieee80211_hdr *) bf->bf_mpdu->data;
-+ tx_log->framectrl = hdr->frame_control;
-+ tx_log->seqctrl = hdr->seq_ctrl;
-+
-+ if (ieee80211_has_tods(tx_log->framectrl)) {
-+ tx_log->bssid_tail = (hdr->addr1[ETH_ALEN - 2] << 8) |
-+ (hdr->addr1[ETH_ALEN - 1]);
-+ tx_log->sa_tail = (hdr->addr2[ETH_ALEN - 2] << 8) |
-+ (hdr->addr2[ETH_ALEN - 1]);
-+ tx_log->da_tail = (hdr->addr3[ETH_ALEN - 2] << 8) |
-+ (hdr->addr3[ETH_ALEN - 1]);
-+ } else if (ieee80211_has_fromds(tx_log->framectrl)) {
-+ tx_log->bssid_tail = (hdr->addr2[ETH_ALEN - 2] << 8) |
-+ (hdr->addr2[ETH_ALEN - 1]);
-+ tx_log->sa_tail = (hdr->addr3[ETH_ALEN - 2] << 8) |
-+ (hdr->addr3[ETH_ALEN - 1]);
-+ tx_log->da_tail = (hdr->addr1[ETH_ALEN - 2] << 8) |
-+ (hdr->addr1[ETH_ALEN - 1]);
-+ } else {
-+ tx_log->bssid_tail = (hdr->addr3[ETH_ALEN - 2] << 8) |
-+ (hdr->addr3[ETH_ALEN - 1]);
-+ tx_log->sa_tail = (hdr->addr2[ETH_ALEN - 2] << 8) |
-+ (hdr->addr2[ETH_ALEN - 1]);
-+ tx_log->da_tail = (hdr->addr1[ETH_ALEN - 2] << 8) |
-+ (hdr->addr1[ETH_ALEN - 1]);
-+ }
-+
-+ ath9k_hw_get_descinfo(sc->sc_ah, &desc_info);
-+
-+ ds_words = (u32 *)(bf->bf_desc) + desc_info.txctl_offset;
-+ for (i = 0; i < desc_info.txctl_numwords; i++)
-+ tx_log->txdesc_ctl[i] = ds_words[i];
-+}
-+
-+void ath_pktlog_txstatus(struct ath_softc *sc, void *ds)
-+{
-+ struct ath_pktlog_txstatus *tx_log;
-+ struct ath_pktlog *pl_info;
-+ struct ath_desc_info desc_info;
-+ int i;
-+ u32 *ds_words, flags = 0;
-+
-+ pl_info = &sc->pktlog.pktlog;
-+
-+ if ((pl_info->pktlog_filter & ATH_PKTLOG_TX) == 0 ||
-+ !sc->is_pkt_logging)
-+ return;
-+
-+ flags |= (((sc->sc_ah->hw_version.macRev <<
-+ PHFLAGS_MACREV_SFT) & PHFLAGS_MACREV_MASK) |
-+ ((sc->sc_ah->hw_version.macVersion << PHFLAGS_MACVERSION_SFT)
-+ & PHFLAGS_MACVERSION_MASK));
-+ tx_log = (struct ath_pktlog_txstatus *)ath_pktlog_getbuf(pl_info,
-+ PKTLOG_TYPE_TXSTATUS, sizeof(*tx_log), flags);
-+
-+ memset(tx_log, 0, sizeof(*tx_log));
-+
-+ ath9k_hw_get_descinfo(sc->sc_ah, &desc_info);
-+
-+ ds_words = (u32 *)(ds) + desc_info.txstatus_offset;
-+
-+ for (i = 0; i < desc_info.txstatus_numwords; i++)
-+ tx_log->txdesc_status[i] = ds_words[i];
-+}
-+
-+void ath_pktlog_rx(struct ath_softc *sc, void *desc, struct sk_buff *skb)
-+{
-+ struct ath_pktlog_rx *rx_log;
-+ struct ath_pktlog *pl_info;
-+ struct ieee80211_hdr *hdr;
-+ struct ath_desc_info desc_info;
-+ int i;
-+ u32 *ds_words, flags = 0;
-+
-+ pl_info = &sc->pktlog.pktlog;
-+
-+ if ((pl_info->pktlog_filter & ATH_PKTLOG_RX) == 0 ||
-+ !sc->is_pkt_logging)
-+ return;
-+
-+ flags |= (((sc->sc_ah->hw_version.macRev <<
-+ PHFLAGS_MACREV_SFT) & PHFLAGS_MACREV_MASK) |
-+ ((sc->sc_ah->hw_version.macVersion <<
-+ PHFLAGS_MACVERSION_SFT) & PHFLAGS_MACVERSION_MASK));
-+
-+ rx_log = (struct ath_pktlog_rx *)ath_pktlog_getbuf(pl_info, PKTLOG_TYPE_RX,
-+ sizeof(*rx_log), flags);
-+
-+ memset(rx_log, 0, sizeof(*rx_log));
-+
-+ if (skb->len > sizeof(struct ieee80211_hdr)) {
-+ hdr = (struct ieee80211_hdr *) skb->data;
-+ rx_log->framectrl = hdr->frame_control;
-+ rx_log->seqctrl = hdr->seq_ctrl;
-+
-+ if (ieee80211_has_tods(rx_log->framectrl)) {
-+ rx_log->bssid_tail = (hdr->addr1[ETH_ALEN - 2] << 8) |
-+ (hdr->addr1[ETH_ALEN - 1]);
-+ rx_log->sa_tail = (hdr->addr2[ETH_ALEN - 2] << 8) |
-+ (hdr->addr2[ETH_ALEN - 1]);
-+ rx_log->da_tail = (hdr->addr3[ETH_ALEN - 2] << 8) |
-+ (hdr->addr3[ETH_ALEN - 1]);
-+ } else if (ieee80211_has_fromds(rx_log->framectrl)) {
-+ rx_log->bssid_tail = (hdr->addr2[ETH_ALEN - 2] << 8) |
-+ (hdr->addr2[ETH_ALEN - 1]);
-+ rx_log->sa_tail = (hdr->addr3[ETH_ALEN - 2] << 8) |
-+ (hdr->addr3[ETH_ALEN - 1]);
-+ rx_log->da_tail = (hdr->addr1[ETH_ALEN - 2] << 8) |
-+ (hdr->addr1[ETH_ALEN - 1]);
-+ } else {
-+ rx_log->bssid_tail = (hdr->addr3[ETH_ALEN - 2] << 8) |
-+ (hdr->addr3[ETH_ALEN - 1]);
-+ rx_log->sa_tail = (hdr->addr2[ETH_ALEN - 2] << 8) |
-+ (hdr->addr2[ETH_ALEN - 1]);
-+ rx_log->da_tail = (hdr->addr1[ETH_ALEN - 2] << 8) |
-+ (hdr->addr1[ETH_ALEN - 1]);
-+ }
-+ } else {
-+ hdr = (struct ieee80211_hdr *) skb->data;
-+
-+ if (ieee80211_is_ctl(hdr->frame_control)) {
-+ rx_log->framectrl = hdr->frame_control;
-+ rx_log->da_tail = (hdr->addr1[ETH_ALEN - 2] << 8) |
-+ (hdr->addr1[ETH_ALEN - 1]);
-+ if (skb->len < sizeof(struct ieee80211_rts)) {
-+ rx_log->sa_tail = 0;
-+ } else {
-+ rx_log->sa_tail = (hdr->addr2[ETH_ALEN - 2]
-+ << 8) |
-+ (hdr->addr2[ETH_ALEN - 1]);
-+ }
-+ } else {
-+ rx_log->framectrl = 0xFFFF;
-+ rx_log->da_tail = 0;
-+ rx_log->sa_tail = 0;
-+ }
-+
-+ rx_log->seqctrl = 0;
-+ rx_log->bssid_tail = 0;
-+ }
-+
-+ ath9k_hw_get_descinfo(sc->sc_ah, &desc_info);
-+
-+ ds_words = (u32 *)(desc) + desc_info.rxstatus_offset;
-+
-+ for (i = 0; i < desc_info.rxstatus_numwords; i++)
-+ rx_log->rxdesc_status[i] = ds_words[i];
-+}
-+
-+void ath9k_pktlog_rc(struct ath_softc *sc, struct ath_rate_priv *ath_rc_priv,
-+ int8_t ratecode, u8 rate, int8_t is_probing, u16 ac)
-+{
-+ struct ath_pktlog_rcfind *rcf_log;
-+ struct ath_pktlog *pl_info;
-+ u32 flags = 0;
-+
-+ pl_info = &sc->pktlog.pktlog;
-+
-+ if ((pl_info->pktlog_filter & ATH_PKTLOG_RCFIND) == 0 ||
-+ !sc->is_pkt_logging)
-+ return;
-+
-+ flags |= (((sc->sc_ah->hw_version.macRev <<
-+ PHFLAGS_MACREV_SFT) & PHFLAGS_MACREV_MASK) |
-+ ((sc->sc_ah->hw_version.macVersion <<
-+ PHFLAGS_MACVERSION_SFT) & PHFLAGS_MACVERSION_MASK));
-+ rcf_log = (struct ath_pktlog_rcfind *)ath_pktlog_getbuf(pl_info,
-+ PKTLOG_TYPE_RCFIND, sizeof(*rcf_log), flags);
-+
-+ rcf_log->rate = rate;
-+ rcf_log->rateCode = ratecode;
-+ rcf_log->rcProbeRate = is_probing ? ath_rc_priv->probe_rate : 0;
-+ rcf_log->isProbing = is_probing;
-+ rcf_log->ac = ac;
-+ rcf_log->rcRateMax = ath_rc_priv->rate_max_phy;
-+ rcf_log->rcRateTableSize = ath_rc_priv->rate_table_size;
-+}
-+
-+void ath9k_pktlog_rcupdate(struct ath_softc *sc, struct ath_rate_priv *ath_rc_priv, u8 tx_rate,
-+ u8 rate_code, u8 xretries, u8 retries, int8_t rssi, u16 ac)
-+{
-+ struct ath_pktlog_rcupdate *rcu_log;
-+ struct ath_pktlog *pl_info;
-+ int i;
-+ u32 flags = 0;
-+
-+ pl_info = &sc->pktlog.pktlog;
-+
-+ if ((pl_info->pktlog_filter & ATH_PKTLOG_RCUPDATE) == 0 ||
-+ !sc->is_pkt_logging)
-+ return;
-+
-+ flags |= (((sc->sc_ah->hw_version.macRev <<
-+ PHFLAGS_MACREV_SFT) & PHFLAGS_MACREV_MASK) |
-+ ((sc->sc_ah->hw_version.macVersion <<
-+ PHFLAGS_MACVERSION_SFT) & PHFLAGS_MACVERSION_MASK));
-+ rcu_log = (struct ath_pktlog_rcupdate *)ath_pktlog_getbuf(pl_info,
-+ PKTLOG_TYPE_RCUPDATE,
-+ sizeof(*rcu_log), flags);
-+
-+ memset(rcu_log, 0, sizeof(*rcu_log));
-+
-+ rcu_log->txRate = tx_rate;
-+ rcu_log->rateCode = rate_code;
-+ rcu_log->Xretries = xretries;
-+ rcu_log->retries = retries;
-+ rcu_log->rssiAck = rssi;
-+ rcu_log->ac = ac;
-+ rcu_log->rcProbeRate = ath_rc_priv->probe_rate;
-+ rcu_log->rcRateMax = ath_rc_priv->rate_max_phy;
-+
-+ for (i = 0; i < RATE_TABLE_SIZE; i++) {
-+ rcu_log->rcPer[i] = ath_rc_priv->per[i];
-+ }
-+}
-+
-+void ath9k_pktlog_txcomplete(struct ath_softc *sc, struct list_head *bf_head,
-+ struct ath_buf *bf, struct ath_buf *bf_last)
-+{
-+ struct log_tx ;
-+ struct ath_buf *tbf;
-+
-+ list_for_each_entry(tbf, bf_head, list)
-+ ath_pktlog_txctl(sc, tbf);
-+
-+ if (bf->bf_next == NULL && bf_last->bf_stale)
-+ ath_pktlog_txctl(sc, bf_last);
-+}
-+
-+void ath9k_pktlog_txctrl(struct ath_softc *sc, struct list_head *bf_head, struct ath_buf *lastbf)
-+{
-+ struct log_tx ;
-+ struct ath_buf *tbf;
-+
-+ list_for_each_entry(tbf, bf_head, list)
-+ ath_pktlog_txctl(sc, tbf);
-+
-+ /* log the last descriptor. */
-+ ath_pktlog_txctl(sc, lastbf);
-+}
-+
-+static void pktlog_init(struct ath_softc *sc)
-+{
-+ spin_lock_init(&sc->pktlog.pktlog.pktlog_lock);
-+ sc->pktlog.pktlog.pktlog_buf_size = ATH_DEBUGFS_PKTLOG_SIZE_DEFAULT;
-+ sc->pktlog.pktlog.pktlog_buf = NULL;
-+ sc->pktlog.pktlog.pktlog_filter = 0;
-+}
-+
-+int ath9k_init_pktlog(struct ath_softc *sc)
-+{
-+ sc->pktlog.debugfs_pktlog = debugfs_create_dir("pktlog",
-+ sc->debug.debugfs_phy);
-+ if (!sc->pktlog.debugfs_pktlog)
-+ goto err;
-+
-+ sc->pktlog.pktlog_start = debugfs_create_file("pktlog_start",
-+ S_IRUGO | S_IWUSR,
-+ sc->pktlog.debugfs_pktlog,
-+ sc, &fops_pktlog_start);
-+ if (!sc->pktlog.pktlog_start)
-+ goto err;
-+
-+ sc->pktlog.pktlog_size = debugfs_create_file("pktlog_size",
-+ S_IRUGO | S_IWUSR,
-+ sc->pktlog.debugfs_pktlog,
-+ sc, &fops_pktlog_size);
-+ if (!sc->pktlog.pktlog_size)
-+ goto err;
-+
-+ sc->pktlog.pktlog_filter = debugfs_create_file("pktlog_filter",
-+ S_IRUGO | S_IWUSR,
-+ sc->pktlog.debugfs_pktlog,
-+ sc, &fops_pktlog_filter);
-+ if (!sc->pktlog.pktlog_filter)
-+ goto err;
-+
-+ sc->pktlog.pktlog_dump = debugfs_create_file("pktlog_dump",
-+ S_IRUGO,
-+ sc->pktlog.debugfs_pktlog,
-+ sc, &fops_pktlog_dump);
-+ if (!sc->pktlog.pktlog_dump)
-+ goto err;
-+
-+ pktlog_init(sc);
-+
-+ return 0;
-+
-+err:
-+ return -ENOMEM;
-+}
-+
-+void ath9k_deinit_pktlog(struct ath_softc *sc)
-+{
-+ struct ath_pktlog *pktlog = &sc->pktlog.pktlog;
-+
-+ if (pktlog->pktlog_buf != NULL)
-+ ath_pktlog_release(pktlog);
-+
-+ debugfs_remove(sc->pktlog.pktlog_start);
-+ debugfs_remove(sc->pktlog.pktlog_size);
-+ debugfs_remove(sc->pktlog.pktlog_filter);
-+ debugfs_remove(sc->pktlog.pktlog_dump);
-+ debugfs_remove(sc->pktlog.debugfs_pktlog);
-+}
---- /dev/null
-+++ b/drivers/net/wireless/ath/ath9k/pktlog.h
-@@ -0,0 +1,242 @@
-+#ifndef PKTLOG_H
-+#define PKTLOG_H
-+
-+#ifdef CONFIG_ATH9K_PKTLOG
-+#define CUR_PKTLOG_VER 10010 /* Packet log version */
-+#define PKTLOG_MAGIC_NUM 7735225
-+#define ATH_PKTLOG_TX 0x000000001
-+#define ATH_PKTLOG_RX 0x000000002
-+#define ATH_PKTLOG_RCFIND 0x000000004
-+#define ATH_PKTLOG_RCUPDATE 0x000000008
-+
-+#define ATH_DEBUGFS_PKTLOG_SIZE_DEFAULT (1024 * 1024)
-+#define ATH_PKTLOG_FILTER_DEFAULT (ATH_PKTLOG_TX | ATH_PKTLOG_RX | \
-+ ATH_PKTLOG_RCFIND | ATH_PKTLOG_RCUPDATE)
-+
-+#define PHFLAGS_MACVERSION_MASK 0x00ff0000
-+#define PHFLAGS_MACVERSION_SFT 16
-+#define PHFLAGS_MACREV_MASK 0xff0 /* MAC revision */
-+#define PHFLAGS_MACREV_SFT 4
-+
-+struct ath_pktlog_hdr {
-+ u32 flags;
-+ u16 log_type; /* Type of log information foll this header */
-+ int16_t size; /* Size of variable length log information in bytes */
-+ u32 timestamp;
-+} __packed;
-+
-+/* Types of packet log events */
-+#define PKTLOG_TYPE_TXCTL 0
-+#define PKTLOG_TYPE_TXSTATUS 1
-+#define PKTLOG_TYPE_RX 2
-+#define PKTLOG_TYPE_RCFIND 3
-+#define PKTLOG_TYPE_RCUPDATE 4
-+
-+#define PKTLOG_MAX_TXCTL_WORDS 12
-+#define PKTLOG_MAX_TXSTATUS_WORDS 10
-+#define PKTLOG_MAX_PROTO_WORDS 16
-+
-+struct ath_pktlog_txctl {
-+ __le16 framectrl; /* frame control field from header */
-+ __le16 seqctrl; /* frame control field from header */
-+ u16 bssid_tail; /* last two octets of bssid */
-+ u16 sa_tail; /* last two octets of SA */
-+ u16 da_tail; /* last two octets of DA */
-+ u16 resvd;
-+ u32 txdesc_ctl[PKTLOG_MAX_TXCTL_WORDS]; /* Tx descriptor words */
-+ unsigned long proto_hdr; /* protocol header (variable length!) */
-+ int32_t misc[0]; /* Can be used for HT specific or other misc info */
-+} __packed;
-+
-+struct ath_pktlog_txstatus {
-+ /* Tx descriptor status words */
-+ u32 txdesc_status[PKTLOG_MAX_TXSTATUS_WORDS];
-+ int32_t misc[0]; /* Can be used for HT specific or other misc info */
-+} __packed;
-+
-+#define PKTLOG_MAX_RXSTATUS_WORDS 11
-+
-+struct ath_pktlog_rx {
-+ u16 framectrl; /* frame control field from header */
-+ u16 seqctrl; /* sequence control field */
-+ u16 bssid_tail; /* last two octets of bssid */
-+ u16 sa_tail; /* last two octets of SA */
-+ u16 da_tail; /* last two octets of DA */
-+ u16 resvd;
-+ u32 rxdesc_status[PKTLOG_MAX_RXSTATUS_WORDS]; /* Rx descriptor words */
-+ unsigned long proto_hdr; /* protocol header (variable length!) */
-+ int32_t misc[0]; /* Can be used for HT specific or other misc info */
-+} __packed;
-+
-+struct ath_pktlog_rcfind {
-+ u8 rate;
-+ u8 rateCode;
-+ s8 rcRssiLast;
-+ s8 rcRssiLastPrev;
-+ s8 rcRssiLastPrev2;
-+ s8 rssiReduce;
-+ u8 rcProbeRate;
-+ s8 isProbing;
-+ s8 primeInUse;
-+ s8 currentPrimeState;
-+ u8 rcRateTableSize;
-+ u8 rcRateMax;
-+ u8 ac;
-+ int32_t misc[0]; /* Can be used for HT specific or other misc info */
-+} __packed;
-+
-+struct ath_pktlog_rcupdate {
-+ u8 txRate;
-+ u8 rateCode;
-+ s8 rssiAck;
-+ u8 Xretries;
-+ u8 retries;
-+ s8 rcRssiLast;
-+ s8 rcRssiLastLkup;
-+ s8 rcRssiLastPrev;
-+ s8 rcRssiLastPrev2;
-+ u8 rcProbeRate;
-+ u8 rcRateMax;
-+ s8 useTurboPrime;
-+ s8 currentBoostState;
-+ u8 rcHwMaxRetryRate;
-+ u8 ac;
-+ u8 resvd[2];
-+ s8 rcRssiThres[RATE_TABLE_SIZE];
-+ u8 rcPer[RATE_TABLE_SIZE];
-+ u8 resv2[RATE_TABLE_SIZE + 5];
-+ int32_t misc[0]; /* Can be used for HT specific or other misc info */
-+};
-+
-+#define TXCTL_OFFSET(ah) (AR_SREV_9300_20_OR_LATER(ah) ? 11 : 2)
-+#define TXCTL_NUMWORDS(ah) (AR_SREV_5416_20_OR_LATER(ah) ? 12 : 8)
-+#define TXSTATUS_OFFSET(ah) (AR_SREV_9300_20_OR_LATER(ah) ? 2 : 14)
-+#define TXSTATUS_NUMWORDS(ah) (AR_SREV_9300_20_OR_LATER(ah) ? 7 : 10)
-+
-+#define RXCTL_OFFSET(ah) (AR_SREV_9300_20_OR_LATER(ah) ? 0 : 3)
-+#define RXCTL_NUMWORDS(ah) (AR_SREV_9300_20_OR_LATER(ah) ? 0 : 1)
-+#define RXSTATUS_OFFSET(ah) (AR_SREV_9300_20_OR_LATER(ah) ? 1 : 4)
-+#define RXSTATUS_NUMWORDS(ah) (AR_SREV_9300_20_OR_LATER(ah) ? 11 : 9)
-+
-+struct ath_desc_info {
-+ u8 txctl_offset;
-+ u8 txctl_numwords;
-+ u8 txstatus_offset;
-+ u8 txstatus_numwords;
-+ u8 rxctl_offset;
-+ u8 rxctl_numwords;
-+ u8 rxstatus_offset;
-+ u8 rxstatus_numwords;
-+};
-+
-+#define PKTLOG_MOV_RD_IDX(_rd_offset, _log_buf, _log_size) \
-+ do { \
-+ if ((_rd_offset + sizeof(struct ath_pktlog_hdr) + \
-+ ((struct ath_pktlog_hdr *)((_log_buf)->log_data + \
-+ (_rd_offset)))->size) <= _log_size) { \
-+ _rd_offset = ((_rd_offset) + \
-+ sizeof(struct ath_pktlog_hdr) + \
-+ ((struct ath_pktlog_hdr *) \
-+ ((_log_buf)->log_data + \
-+ (_rd_offset)))->size); \
-+ } else { \
-+ _rd_offset = ((struct ath_pktlog_hdr *) \
-+ ((_log_buf)->log_data + \
-+ (_rd_offset)))->size; \
-+ } \
-+ (_rd_offset) = (((_log_size) - (_rd_offset)) >= \
-+ sizeof(struct ath_pktlog_hdr)) ? \
-+ _rd_offset : 0; \
-+ } while (0);
-+
-+struct ath_pktlog_bufhdr {
-+ u32 magic_num; /* Used by post processing scripts */
-+ u32 version; /* Set to CUR_PKTLOG_VER */
-+};
-+
-+struct ath_pktlog_buf {
-+ struct ath_pktlog_bufhdr bufhdr;
-+ int32_t rd_offset;
-+ int32_t wr_offset;
-+ char log_data[0];
-+};
-+
-+struct ath_pktlog {
-+ struct ath_pktlog_buf *pktlog_buf;
-+ u32 pktlog_filter;
-+ u32 pktlog_buf_size; /* Size of buffer in bytes */
-+ spinlock_t pktlog_lock;
-+};
-+
-+struct ath_pktlog_debugfs {
-+ struct dentry *debugfs_pktlog;
-+ struct dentry *pktlog_enable;
-+ struct dentry *pktlog_start;
-+ struct dentry *pktlog_filter;
-+ struct dentry *pktlog_size;
-+ struct dentry *pktlog_dump;
-+ struct ath_pktlog pktlog;
-+};
-+
-+void ath_pktlog_txctl(struct ath_softc *sc, struct ath_buf *bf);
-+void ath_pktlog_txstatus(struct ath_softc *sc, void *ds);
-+void ath_pktlog_rx(struct ath_softc *sc, void *ds, struct sk_buff *skb);
-+void ath9k_pktlog_rc(struct ath_softc *sc, struct ath_rate_priv *ath_rc_priv,
-+ int8_t ratecode, u8 rate, int8_t is_probing, u16 ac);
-+void ath9k_pktlog_rcupdate(struct ath_softc *sc,
-+ struct ath_rate_priv *ath_rc_priv, u8 tx_rate,
-+ u8 rate_code, u8 xretries, u8 retries, int8_t rssi,
-+ u16 ac);
-+void ath9k_pktlog_txcomplete(struct ath_softc *sc ,struct list_head *bf_head,
-+ struct ath_buf *bf, struct ath_buf *bf_last);
-+void ath9k_pktlog_txctrl(struct ath_softc *sc, struct list_head *bf_head,
-+ struct ath_buf *lastbf);
-+int ath9k_init_pktlog(struct ath_softc *sc);
-+void ath9k_deinit_pktlog(struct ath_softc *sc);
-+#else /* CONFIG_ATH9K_PKTLOG */
-+static inline void ath_pktlog_txstatus(struct ath_softc *sc, void *ds)
-+{
-+}
-+
-+static inline void ath_pktlog_rx(struct ath_softc *sc, void *ds,
-+ struct sk_buff *skb)
-+{
-+}
-+
-+static inline void ath9k_pktlog_rc(struct ath_softc *sc,
-+ struct ath_rate_priv *ath_rc_priv,
-+ int8_t ratecode, u8 rate,
-+ int8_t is_probing, u16 ac)
-+{
-+}
-+
-+static inline void ath9k_pktlog_rcupdate(struct ath_softc *sc,
-+ struct ath_rate_priv *ath_rc_priv,
-+ u8 tx_rate, u8 rate_code,
-+ u8 xretries, u8 retries,
-+ int8_t rssi, u16 ac)
-+{
-+}
-+
-+static inline void ath9k_pktlog_txcomplete(struct ath_softc *sc,
-+ struct list_head *bf_head,
-+ struct ath_buf *bf,
-+ struct ath_buf *bf_last)
-+{
-+}
-+
-+static inline void ath9k_pktlog_txctrl(struct ath_softc *sc,
-+ struct list_head *bf_head,
-+ struct ath_buf *lastbf)
-+{
-+}
-+static inline int ath9k_init_pktlog(struct ath_softc *sc)
-+{
-+ return 0;
-+}
-+static inline void ath9k_deinit_pktlog(struct ath_softc *sc)
-+{
-+}
-+#endif /* CONFIG_ATH9K_PKTLOG */
-+
-+#endif
---- a/drivers/net/wireless/ath/ath9k/rc.c
-+++ b/drivers/net/wireless/ath/ath9k/rc.c
-@@ -580,7 +580,7 @@ static u8 ath_rc_setvalid_htrates(struct
- static u8 ath_rc_get_highest_rix(struct ath_softc *sc,
- struct ath_rate_priv *ath_rc_priv,
- const struct ath_rate_table *rate_table,
-- int *is_probing)
-+ int *is_probing, u16 ac)
- {
- u32 best_thruput, this_thruput, now_msec;
- u8 rate, next_rate, best_rate, maxindex, minindex;
-@@ -671,6 +671,8 @@ static u8 ath_rc_get_highest_rix(struct
-
- rate = ath_rc_priv->valid_rate_index[0];
-
-+ ath9k_pktlog_rc(sc, ath_rc_priv, rate_table->info[rate].ratecode,
-+ rate, *is_probing, ac);
- return rate;
- }
-
-@@ -762,7 +764,7 @@ static void ath_get_rate(void *priv, str
- try_per_rate = 4;
-
- rate_table = ath_rc_priv->rate_table;
-- rix = ath_rc_get_highest_rix(sc, ath_rc_priv, rate_table, &is_probe);
-+ rix = ath_rc_get_highest_rix(sc, ath_rc_priv, rate_table, &is_probe, skb_get_queue_mapping(skb));
-
- /*
- * If we're in HT mode and both us and our peer supports LDPC.
-@@ -1012,7 +1014,8 @@ static void ath_debug_stat_retries(struc
- static void ath_rc_update_ht(struct ath_softc *sc,
- struct ath_rate_priv *ath_rc_priv,
- struct ieee80211_tx_info *tx_info,
-- int tx_rate, int xretries, int retries)
-+ int tx_rate, int xretries, int retries,
-+ u16 ac)
- {
- u32 now_msec = jiffies_to_msecs(jiffies);
- int rate;
-@@ -1081,6 +1084,9 @@ static void ath_rc_update_ht(struct ath_
- ath_debug_stat_retries(ath_rc_priv, tx_rate, xretries, retries,
- ath_rc_priv->per[tx_rate]);
-
-+ ath9k_pktlog_rcupdate(sc, ath_rc_priv, tx_rate,
-+ rate_table->info[tx_rate].ratecode,
-+ xretries, retries, tx_info->status.ack_signal, ac);
- }
-
- static int ath_rc_get_rateindex(const struct ath_rate_table *rate_table,
-@@ -1113,7 +1119,8 @@ static int ath_rc_get_rateindex(const st
- static void ath_rc_tx_status(struct ath_softc *sc,
- struct ath_rate_priv *ath_rc_priv,
- struct ieee80211_tx_info *tx_info,
-- int final_ts_idx, int xretries, int long_retry)
-+ int final_ts_idx, int xretries, int long_retry,
-+ u16 ac)
- {
- const struct ath_rate_table *rate_table;
- struct ieee80211_tx_rate *rates = tx_info->status.rates;
-@@ -1142,7 +1149,7 @@ static void ath_rc_tx_status(struct ath_
- rix = ath_rc_get_rateindex(rate_table, &rates[i]);
- ath_rc_update_ht(sc, ath_rc_priv, tx_info,
- rix, xretries ? 1 : 2,
-- rates[i].count);
-+ rates[i].count, ac);
- }
- }
- } else {
-@@ -1164,7 +1171,7 @@ static void ath_rc_tx_status(struct ath_
- return;
-
- rix = ath_rc_get_rateindex(rate_table, &rates[i]);
-- ath_rc_update_ht(sc, ath_rc_priv, tx_info, rix, xretries, long_retry);
-+ ath_rc_update_ht(sc, ath_rc_priv, tx_info, rix, xretries, long_retry, ac);
- }
-
- static const
-@@ -1358,7 +1365,7 @@ static void ath_tx_status(void *priv, st
- tx_status = 1;
-
- ath_rc_tx_status(sc, ath_rc_priv, tx_info, final_ts_idx, tx_status,
-- long_retry);
-+ long_retry, skb_get_queue_mapping(skb));
-
- /* Check if aggregation has to be enabled for this tid */
- if (conf_is_ht(&sc->hw->conf) &&
---- a/drivers/net/wireless/ath/ath9k/recv.c
-+++ b/drivers/net/wireless/ath/ath9k/recv.c
-@@ -1577,6 +1577,7 @@ int ath_rx_tasklet(struct ath_softc *sc,
- struct ieee80211_rx_status *rxs;
- struct ath_hw *ah = sc->sc_ah;
- struct ath_common *common = ath9k_hw_common(ah);
-+ u32 *rx_desc = NULL;
- /*
- * The hw can technically differ from common->hw when using ath9k
- * virtual wiphy so to account for that we iterate over the active
-@@ -1676,13 +1677,24 @@ int ath_rx_tasklet(struct ath_softc *sc,
- dma_type);
-
- skb_put(skb, rs.rs_datalen + ah->caps.rx_status_len);
-- if (ah->caps.rx_status_len)
-+ if (ah->caps.rx_status_len) {
-+ rx_desc = kzalloc(ah->caps.rx_status_len, GFP_ATOMIC);
-+ if (rx_desc == NULL)
-+ BUG_ON(1);
-+ memcpy(rx_desc, skb->data, ah->caps.rx_status_len);
- skb_pull(skb, ah->caps.rx_status_len);
-+}
-
- if (!rs.rs_more)
- ath9k_rx_skb_postprocess(common, hdr_skb, &rs,
- rxs, decrypt_error);
-
-+ if (rx_desc) {
-+ ath_pktlog_rx(sc, (void *) rx_desc, skb);
-+ kfree(rx_desc);
-+ } else
-+ ath_pktlog_rx(sc, bf->bf_desc, skb);
-+
- /* We will now give hardware our shiny new allocated skb */
- bf->bf_mpdu = requeue_skb;
- bf->bf_buf_addr = dma_map_single(sc->dev, requeue_skb->data,
---- a/drivers/net/wireless/ath/ath9k/xmit.c
-+++ b/drivers/net/wireless/ath/ath9k/xmit.c
-@@ -475,6 +475,8 @@ static void ath_tx_complete_aggr(struct
- list_move_tail(&bf->list, &bf_head);
- }
-
-+ ath9k_pktlog_txcomplete(sc, &bf_head, bf, bf_last);
-+
- if (!txpending || (tid->state & AGGR_CLEANUP)) {
- /*
- * complete the acked-ones/xretried ones; update
-@@ -2043,7 +2045,7 @@ static void ath_tx_processq(struct ath_s
- ds = lastbf->bf_desc;
-
- memset(&ts, 0, sizeof(ts));
-- status = ath9k_hw_txprocdesc(ah, ds, &ts);
-+ status = ath9k_hw_txprocdesc(ah, ds, &ts, NULL);
- if (status == -EINPROGRESS) {
- spin_unlock_bh(&txq->axq_lock);
- break;
-@@ -2085,11 +2087,15 @@ static void ath_tx_processq(struct ath_s
- ath_tx_rc_status(sc, bf, &ts, 1, txok ? 0 : 1, txok, true);
- }
-
-- if (bf_isampdu(bf))
-+ if (bf_isampdu(bf)) {
- ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, txok,
- true);
-- else
-+ } else {
-+ ath9k_pktlog_txctrl(sc, &bf_head, lastbf);
- ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, txok, 0);
-+ }
-+
-+ ath_pktlog_txstatus(sc, lastbf->bf_desc);
-
- spin_lock_bh(&txq->axq_lock);
-
-@@ -2210,9 +2216,11 @@ void ath_tx_edma_tasklet(struct ath_soft
- struct list_head bf_head;
- int status;
- int txok;
-+ u32 txs_desc[9];
-
- for (;;) {
-- status = ath9k_hw_txprocdesc(ah, NULL, (void *)&txs);
-+ status = ath9k_hw_txprocdesc(ah, NULL, (void *)&txs,
-+ (void *) txs_desc);
- if (status == -EINPROGRESS)
- break;
- if (status == -EIO) {
-@@ -2258,9 +2266,13 @@ void ath_tx_edma_tasklet(struct ath_soft
- if (bf_isampdu(bf))
- ath_tx_complete_aggr(sc, txq, bf, &bf_head, &txs,
- txok, true);
-- else
-+ else {
-+ ath9k_pktlog_txctrl(sc, &bf_head, lastbf);
- ath_tx_complete_buf(sc, bf, txq, &bf_head,
- &txs, txok, 0);
-+ }
-+
-+ ath_pktlog_txstatus(sc, txs_desc);
-
- spin_lock_bh(&txq->axq_lock);
-