From 7bc79f85bc002beaab72b115cad487f08ecc2cd3 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Wed, 14 Apr 2010 11:36:44 -0700 Subject: [PATCH 11/17] ath9k: Add pktlog support Signed-off-by: Vasanthakumar Thiagarajan --- drivers/net/wireless/ath/ath9k/Kconfig | 8 + drivers/net/wireless/ath/ath9k/Makefile | 1 + drivers/net/wireless/ath/ath9k/ath9k.h | 6 + drivers/net/wireless/ath/ath9k/debug.c | 9 + drivers/net/wireless/ath/ath9k/hw.c | 3 +- drivers/net/wireless/ath/ath9k/hw.h | 2 + drivers/net/wireless/ath/ath9k/pktlog.c | 783 +++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath9k/pktlog.h | 235 +++++++++ drivers/net/wireless/ath/ath9k/rc.c | 22 +- drivers/net/wireless/ath/ath9k/recv.c | 2 + drivers/net/wireless/ath/ath9k/xmit.c | 10 +- 11 files changed, 1071 insertions(+), 10 deletions(-) create mode 100644 drivers/net/wireless/ath/ath9k/pktlog.c create mode 100644 drivers/net/wireless/ath/ath9k/pktlog.h diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig index 35f23bd..a48a916 100644 --- a/drivers/net/wireless/ath/ath9k/Kconfig +++ b/drivers/net/wireless/ath/ath9k/Kconfig @@ -32,6 +32,13 @@ config ATH9K_DEBUGFS Also required for changing debug message flags at run time. +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 @@ -53,3 +60,4 @@ config ATH9K_HTC_DEBUGFS depends on ATH9K_HTC && DEBUG_FS ---help--- Say Y, if you need access to ath9k_htc's statistics. + diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile index dd112be..8b7c4cc 100644 --- a/drivers/net/wireless/ath/ath9k/Makefile +++ b/drivers/net/wireless/ath/ath9k/Makefile @@ -10,6 +10,7 @@ ath9k-y += beacon.o \ 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 diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index fbb7dec..e8ddbae 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -23,6 +23,7 @@ #include "debug.h" #include "common.h" +#include "pktlog.h" /* * Header for the ath9k.ko driver core *only* -- hw code nor any other driver @@ -445,6 +446,7 @@ void ath_deinit_leds(struct ath_softc *sc); #define SC_OP_TSF_RESET BIT(11) #define SC_OP_BT_PRIORITY_DETECTED BIT(12) #define SC_OP_BT_SCAN BIT(13) +#define SC_OP_PKTLOGGING BIT(14) /* Powersave flags */ #define PS_WAIT_FOR_BEACON BIT(0) @@ -520,6 +522,10 @@ struct ath_softc { #ifdef CONFIG_ATH9K_DEBUGFS struct ath9k_debug debug; #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 ath_btcoex btcoex; diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index ee83877..7a5c570 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -940,6 +940,12 @@ int ath9k_init_debug(struct ath_hw *ah) goto err; sc->debug.regidx = 0; + +#ifdef CONFIG_ATH9K_PKTLOG + if (ath9k_init_pktlog(sc) != 0) + goto err; +#endif + return 0; err: ath9k_exit_debug(ah); @@ -951,6 +957,9 @@ void ath9k_exit_debug(struct ath_hw *ah) struct ath_common *common = ath9k_hw_common(ah); struct ath_softc *sc = (struct ath_softc *) common->priv; +#ifdef CONFIG_ATH9K_PKTLOG + ath9k_deinit_pktlog(sc); +#endif debugfs_remove_recursive(sc->debug.debugfs_phy); } diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index b2301bd..813f54a 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -2471,7 +2471,8 @@ void ath9k_hw_setrxfilter(struct ath_hw *ah, u32 bits) 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, ah->is_pkt_logging + ? 0xffffffff : phybits); if (phybits) REG_WRITE(ah, AR_RXCFG, diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 5cf0714..e61e8f9 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -794,6 +794,8 @@ struct ath_hw { u32 bb_watchdog_last_status; u32 bb_watchdog_timeout_ms; /* in ms, 0 to disable */ + + bool is_pkt_logging; }; static inline struct ath_common *ath9k_hw_common(struct ath_hw *ah) diff --git a/drivers/net/wireless/ath/ath9k/pktlog.c b/drivers/net/wireless/ath/ath9k/pktlog.c new file mode 100644 index 0000000..9c25645 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/pktlog.c @@ -0,0 +1,783 @@ + +#include +#include +#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); +} diff --git a/drivers/net/wireless/ath/ath9k/pktlog.h b/drivers/net/wireless/ath/ath9k/pktlog.h new file mode 100644 index 0000000..509a85e --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/pktlog.h @@ -0,0 +1,235 @@ +#ifndef PKTLOG_H +#define PKTLOG_H + +#ifdef CONFIG_ATH9K_PKTLOG +#define CUR_PKTLOG_VER 10009 /* 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 9 + +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) 2 +#define TXCTL_NUMWORDS(ah) (AR_SREV_5416_20_OR_LATER(ah) ? 12 : 8) +#define TXSTATUS_OFFSET(ah) (AR_SREV_5416_20_OR_LATER(ah) ? 14 : 10) +#define TXSTATUS_NUMWORDS(ah) 10 + +#define RXCTL_OFFSET(ah) 3 +#define RXCTL_NUMWORDS(ah) 1 +#define RXSTATUS_OFFSET(ah) 4 +#define RXSTATUS_NUMWORDS(ah) 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) +{ +} +#endif /* CONFIG_ATH9K_PKTLOG */ + +#endif diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index f5180d3..534bb75 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -514,7 +514,7 @@ static u8 ath_rc_setvalid_htrates(struct ath_rate_priv *ath_rc_priv, 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; @@ -602,6 +602,8 @@ static u8 ath_rc_get_highest_rix(struct ath_softc *sc, 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; } @@ -693,7 +695,7 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, try_per_rate = 4; rate_table = sc->cur_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. @@ -933,7 +935,8 @@ static bool ath_rc_update_per(struct ath_softc *sc, 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; @@ -1002,6 +1005,9 @@ static void ath_rc_update_ht(struct ath_softc *sc, ath_debug_stat_retries(sc, 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, @@ -1029,7 +1035,8 @@ static int ath_rc_get_rateindex(const struct ath_rate_table *rate_table, 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; @@ -1058,7 +1065,7 @@ static void ath_rc_tx_status(struct ath_softc *sc, 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 { @@ -1080,7 +1087,7 @@ static void ath_rc_tx_status(struct ath_softc *sc, 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 @@ -1277,7 +1284,8 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband, tx_status = 1; ath_rc_tx_status(sc, ath_rc_priv, tx_info, final_ts_idx, tx_status, - (is_underrun) ? sc->hw->max_rate_tries : long_retry); + (is_underrun) ? sc->hw->max_rate_tries : long_retry, + skb_get_queue_mapping(skb)); /* Check if aggregation has to be enabled for this tid */ if (conf_is_ht(&sc->hw->conf) && diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index dfb11a6..5beeccb 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -908,6 +908,8 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) ath9k_cmn_rx_skb_postprocess(common, skb, &rs, rxs, decrypt_error); + 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, diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index debb62d..b5602ed 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -418,6 +418,8 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, list_move_tail(&bf->list, &bf_head); } + ath9k_pktlog_txcomplete(sc, &bf_head, bf, bf_last); + if (!txpending) { /* * complete the acked-ones/xretried ones; update @@ -2165,10 +2167,14 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) ath_tx_rc_status(bf, &ts, 0, txok, true); } - if (bf_isampdu(bf)) + if (bf_isampdu(bf)) { ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, txok); - 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); ath_wake_mac80211_queue(sc, txq); -- 1.6.3.3