From: Luis R. Rodriguez Date: Sat, 22 May 2010 01:21:54 +0000 (-0700) Subject: compat-wireless: add some Atheros crap patches X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=09350253c1284acb3965cc11ac6e31cd011a2e08;p=openwrt%2Fstaging%2Fblogic.git compat-wireless: add some Atheros crap patches The reasoning for reach patch not being posted is explained on the top of each patch. Signed-off-by: Luis R. Rodriguez --- diff --git a/crap/0001-ath9k-Add-debugfs-interface-to-dump-registers.patch b/crap/0001-ath9k-Add-debugfs-interface-to-dump-registers.patch new file mode 100644 index 000000000000..e8011d8fe25e --- /dev/null +++ b/crap/0001-ath9k-Add-debugfs-interface-to-dump-registers.patch @@ -0,0 +1,129 @@ + +Reason for not yet publishing: This code needs more testing. + +From 31c64cc62c514a7aab703a59dc3146e1885fc6aa Mon Sep 17 00:00:00 2001 +From: Vasanthakumar Thiagarajan +Date: Fri, 16 Apr 2010 12:07:51 -0700 +Subject: [PATCH 1/3] ath9k: Add debugfs interface to dump registers + +Signed-off-by: Vasanthakumar Thiagarajan +Signed-off-by: Felix Fietkau +--- + drivers/net/wireless/ath/ath9k/debug.c | 53 +++++++++++++++++++++++++++++++- + drivers/net/wireless/ath/ath9k/debug.h | 8 +++++ + 2 files changed, 60 insertions(+), 1 deletions(-) + +diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c +index ee83877..07a4c7c 100644 +--- a/drivers/net/wireless/ath/ath9k/debug.c ++++ b/drivers/net/wireless/ath/ath9k/debug.c +@@ -15,6 +15,7 @@ + */ + + #include ++#include + #include + + #include "ath9k.h" +@@ -32,6 +33,19 @@ static int ath9k_debugfs_open(struct inode *inode, struct file *file) + return 0; + } + ++static ssize_t ath9k_debugfs_read_buf(struct file *file, char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ u8 *buf = file->private_data; ++ return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf)); ++} ++ ++static int ath9k_debugfs_release_buf (struct inode *inode, struct file *file) ++{ ++ vfree(file->private_data); ++ return 0; ++} ++ + #ifdef CONFIG_ATH_DEBUG + + static ssize_t read_file_debug(struct file *file, char __user *user_buf, +@@ -876,7 +890,38 @@ static ssize_t write_file_regval(struct file *file, const char __user *user_buf, + static const struct file_operations fops_regval = { + .read = read_file_regval, + .write = write_file_regval, +- .open = ath9k_debugfs_open, ++}; ++ ++#define REGDUMP_LINE_SIZE 20 ++#define REGDUMP_NUM_REGS (0x16bd4 / 4 + 1) ++#define REGDUMP_DATA_LEN (REGDUMP_NUM_REGS * REGDUMP_LINE_SIZE + 1) ++ ++static int open_file_regdump(struct inode *inode, struct file *file) ++{ ++ struct ath_softc *sc = inode->i_private; ++ unsigned int len = 0; ++ u8 *buf; ++ int i; ++ ++ buf = vmalloc(REGDUMP_DATA_LEN); ++ if (!buf) ++ return -ENOMEM; ++ ++ ath9k_ps_wakeup(sc); ++ for (i = 0; i < REGDUMP_NUM_REGS; i++) ++ len += scnprintf(buf + len, REGDUMP_DATA_LEN - len, ++ "0x%06x 0x%08x\n", i << 2, REG_READ(sc->sc_ah, i << 2)); ++ ath9k_ps_restore(sc); ++ ++ file->private_data = buf; ++ ++ return 0; ++} ++ ++static const struct file_operations fops_regdump = { ++ .open = open_file_regdump, ++ .read = ath9k_debugfs_read_buf, ++ .release = ath9k_debugfs_release_buf, + .owner = THIS_MODULE + }; + +@@ -940,6 +985,11 @@ int ath9k_init_debug(struct ath_hw *ah) + goto err; + + sc->debug.regidx = 0; ++ ++ if (!debugfs_create_file("regdump", S_IRUSR, sc->debug.debugfs_phy, ++ sc, &fops_regdump)) ++ goto err; ++ + return 0; + err: + ath9k_exit_debug(ah); +@@ -951,6 +1001,7 @@ 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; + ++ debugfs_remove(sc->debug.debugfs_regdump); + debugfs_remove_recursive(sc->debug.debugfs_phy); + } + +diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h +index 5d21704..0950752 100644 +--- a/drivers/net/wireless/ath/ath9k/debug.h ++++ b/drivers/net/wireless/ath/ath9k/debug.h +@@ -156,6 +156,14 @@ struct ath_stats { + struct ath9k_debug { + struct dentry *debugfs_phy; + u32 regidx; ++ struct dentry *debugfs_debug; ++ struct dentry *debugfs_dma; ++ struct dentry *debugfs_interrupt; ++ struct dentry *debugfs_rcstat; ++ struct dentry *debugfs_wiphy; ++ struct dentry *debugfs_xmit; ++ struct dentry *debugfs_recv; ++ struct dentry *debugfs_regdump; + struct ath_stats stats; + }; + +-- +1.6.3.3 + diff --git a/crap/0002-ath9k-Add-pktlog-support.patch b/crap/0002-ath9k-Add-pktlog-support.patch new file mode 100644 index 000000000000..9445dece3bd9 --- /dev/null +++ b/crap/0002-ath9k-Add-pktlog-support.patch @@ -0,0 +1,1450 @@ +Reason for not yet publishing: This code needs more testing and +enhancements. + +From 6f1ee5d1c3a9d4350ef571ac74aa65e4cb17c51c Mon Sep 17 00:00:00 2001 +From: Vasanthakumar Thiagarajan +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 +--- + 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 + +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/ar9002_mac.c b/drivers/net/wireless/ath/ath9k/ar9002_mac.c +index 2be20d2..89ab919 100644 +--- a/drivers/net/wireless/ath/ath9k/ar9002_mac.c ++++ b/drivers/net/wireless/ath/ath9k/ar9002_mac.c +@@ -215,7 +215,8 @@ static void ar9002_hw_fill_txdesc(struct ath_hw *ah, void *ds, u32 seglen, + } + + 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); + +diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.c b/drivers/net/wireless/ath/ath9k/ar9003_mac.c +index 4073107..790507a 100644 +--- 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 ath_hw *ah, void *ds, u32 seglen, + } + + 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; + +@@ -305,6 +306,7 @@ static int ar9003_hw_proc_txdesc(struct ath_hw *ah, void *ds, + + ts->tid = MS(ads->status8, AR_TxTid); + ++ memcpy(txs_desc, ads, sizeof(*ads)); + memset(ads, 0, sizeof(*ads)); + + return 0; +diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h +index cc6ea42..4e3cb63 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 +@@ -508,6 +509,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) +@@ -583,6 +585,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 07a4c7c..81db80c 100644 +--- a/drivers/net/wireless/ath/ath9k/debug.c ++++ b/drivers/net/wireless/ath/ath9k/debug.c +@@ -990,6 +990,9 @@ int ath9k_init_debug(struct ath_hw *ah) + sc, &fops_regdump)) + goto err; + ++ if (ath9k_init_pktlog(sc) != 0) ++ goto err; ++ + return 0; + err: + ath9k_exit_debug(ah); +@@ -1001,6 +1004,7 @@ 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; + ++ ath9k_deinit_pktlog(sc); + debugfs_remove(sc->debug.debugfs_regdump); + debugfs_remove_recursive(sc->debug.debugfs_phy); + } +diff --git a/drivers/net/wireless/ath/ath9k/hw-ops.h b/drivers/net/wireless/ath/ath9k/hw-ops.h +index 624422a..4fbfa66 100644 +--- 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(struct ath_hw *ah, void *ds, u32 seglen, + } + + 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, +diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c +index 1ded0b7..fe0a60b 100644 +--- a/drivers/net/wireless/ath/ath9k/hw.c ++++ b/drivers/net/wireless/ath/ath9k/hw.c +@@ -2465,7 +2465,7 @@ 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, 0xffffffff); + + 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 ba77506..ab19f4e 100644 +--- a/drivers/net/wireless/ath/ath9k/hw.h ++++ b/drivers/net/wireless/ath/ath9k/hw.h +@@ -582,7 +582,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, +@@ -793,6 +793,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..846c662 +--- /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 +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 fc15b4b..b29c284 100644 +--- a/drivers/net/wireless/ath/ath9k/recv.c ++++ b/drivers/net/wireless/ath/ath9k/recv.c +@@ -1079,6 +1079,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) + 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 techncically differ from common->hw when using ath9k + * virtual wiphy so to account for that we iterate over the active +@@ -1156,12 +1157,24 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) + 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); ++ } + + ath9k_rx_skb_postprocess(common, 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, +diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c +index debb62d..7300a30 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 +@@ -2115,7 +2117,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) + 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; +@@ -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); + +@@ -2240,9 +2246,11 @@ void ath_tx_edma_tasklet(struct ath_softc *sc) + 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) { +@@ -2295,14 +2303,18 @@ void ath_tx_edma_tasklet(struct ath_softc *sc) + ath_tx_rc_status(bf, &txs, 0, txok, true); + } + +- if (bf_isampdu(bf)) ++ if (bf_isampdu(bf)) { + ath_tx_complete_aggr(sc, txq, bf, &bf_head, &txs, txok); +- else ++ } else { ++ ath9k_pktlog_txctrl(sc, &bf_head, lastbf); + ath_tx_complete_buf(sc, bf, txq, &bf_head, + &txs, txok, 0); ++ } + + ath_wake_mac80211_queue(sc, txq); + ++ ath_pktlog_txstatus(sc, txs_desc); ++ + spin_lock_bh(&txq->axq_lock); + if (!list_empty(&txq->txq_fifo_pending)) { + INIT_LIST_HEAD(&bf_head); +-- +1.6.3.3 + diff --git a/crap/0003-ath9k-enable-AR9003-PCI-IDs.patch b/crap/0003-ath9k-enable-AR9003-PCI-IDs.patch new file mode 100644 index 000000000000..9f001ed9ebe1 --- /dev/null +++ b/crap/0003-ath9k-enable-AR9003-PCI-IDs.patch @@ -0,0 +1,32 @@ +Reason for not yet publishing: This code will only be added once +AR9003 support is completed. It makes no sense to enable AR9003 +until we are completely satisfied with all the code. + +From a685dc0cdbc728510cd612c613a4382419b85c17 Mon Sep 17 00:00:00 2001 +From: Luis R. Rodriguez +Date: Thu, 13 May 2010 17:33:23 -0700 +Subject: [PATCH 3/3] ath9k: enable AR9003 PCI IDs + +All AR9003 features are now complete so enable AR9003 +support. + +Signed-off-by: Luis R. Rodriguez +--- + drivers/net/wireless/ath/ath9k/pci.c | 1 + + 1 files changed, 1 insertions(+), 0 deletions(-) + +diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c +index 1ec836c..257b10b 100644 +--- a/drivers/net/wireless/ath/ath9k/pci.c ++++ b/drivers/net/wireless/ath/ath9k/pci.c +@@ -28,6 +28,7 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = { + { PCI_VDEVICE(ATHEROS, 0x002C) }, /* PCI-E 802.11n bonded out */ + { PCI_VDEVICE(ATHEROS, 0x002D) }, /* PCI */ + { PCI_VDEVICE(ATHEROS, 0x002E) }, /* PCI-E */ ++ { PCI_VDEVICE(ATHEROS, 0x0030) }, /* PCI-E AR9300 */ + { 0 } + }; + +-- +1.6.3.3 +