[Madwifi-cvs] revision 3497 committed
Status: Beta
Brought to you by:
otaku
From: Michael T. <svn...@ma...> - 2008-04-09 22:25:57
|
Project : madwifi Revision : 3497 Author : mtaylor (Michael Taylor) Date : 2008-04-10 00:25:51 +0200 (Thu, 10 Apr 2008) Log Message : Debugging updates: * Updated register dump based on ath5k database (refresh the list) * Added a generic debug iwpriv delegation method to if_ath * Added some functions to help diagnose lost ath_buf pointers [resultant fixes will be checked in subsequent commits] Affected Files: * madwifi/trunk/ath/if_ath.c updated * madwifi/trunk/ath/if_ath_hal.h updated * madwifi/trunk/ath/if_athvar.h updated * madwifi/trunk/net80211/ieee80211_ioctl.h updated * madwifi/trunk/net80211/ieee80211_proto.h updated * madwifi/trunk/net80211/ieee80211_var.h updated * madwifi/trunk/net80211/ieee80211_wireless.c updated Modified: madwifi/trunk/ath/if_ath.c =================================================================== --- madwifi/trunk/ath/if_ath.c 2008-04-09 22:03:18 UTC (rev 3496) +++ madwifi/trunk/ath/if_ath.c 2008-04-09 22:25:51 UTC (rev 3497) @@ -57,6 +57,9 @@ #include <linux/random.h> #include <linux/delay.h> #include <linux/cache.h> +#include <linux/bitmap.h> +#include <linux/bitops.h> +#include <linux/types.h> #include <linux/sysctl.h> #include <linux/proc_fs.h> #include <linux/if_arp.h> @@ -135,9 +138,6 @@ static void ath_bstuck_tasklet(TQUEUE_ARG); static int ath_stop_locked(struct net_device *); static int ath_stop(struct net_device *); -#if 0 -static void ath_initkeytable(struct ath_softc *); -#endif static ieee80211_keyix_t ath_key_alloc(struct ieee80211vap *, const struct ieee80211_key *); static int ath_key_delete(struct ieee80211vap *, const struct ieee80211_key *, @@ -248,10 +248,6 @@ static unsigned int ath_write_register(struct ieee80211com *ic, unsigned int address, unsigned int value); static void ath_ar5212_registers_dump(struct ath_softc *sc); -static void ath_print_register(struct ath_softc *sc, const char* name, - u_int32_t address, u_int32_t v); -static void ath_print_register_delta(struct ath_softc *sc, const char* name, - u_int32_t address, u_int32_t v_old, u_int32_t v_new); #endif /* #ifdef ATH_REVERSE_ENGINEERING */ static int ath_set_mac_address(struct net_device *, void *); @@ -372,6 +368,12 @@ static u_int32_t ath_get_clamped_maxtxpower(struct ath_softc *sc); static u_int32_t ath_set_clamped_maxtxpower(struct ath_softc *sc, u_int32_t new_clamped_maxtxpower); + +static void ath_scanbufs(struct ath_softc *sc); +static int ath_debug_iwpriv(struct ieee80211com *ic, + unsigned int param, unsigned int value); +static __inline int txqactive(struct ath_hal *ah, int qnum); + static u_int32_t ath_get_real_maxtxpower(struct ath_softc *sc); /* calibrate every 30 secs in steady state but check every second at first. */ @@ -1065,6 +1067,7 @@ ic->ic_registers_dump_delta = ath_registers_dump_delta; ic->ic_registers_mark = ath_registers_mark; #endif /* #ifdef ATH_REVERSE_ENGINEERING */ + ic->ic_debug_ath_iwpriv = ath_debug_iwpriv; ic->ic_set_coverageclass = ath_set_coverageclass; ic->ic_mhz2ieee = ath_mhz2ieee; @@ -1094,7 +1097,7 @@ sc->sc_invalid = 0; if (autocreate) { - if (!strcmp(autocreate, "none")) + if (!strcmp(autocreate, "none") || !strlen(autocreate)) autocreatemode = -1; else if (!strcmp(autocreate, "sta")) autocreatemode = IEEE80211_M_STA; @@ -3097,6 +3100,14 @@ #endif atomic_inc(&sc->sc_txbuf_counter); #ifdef IEEE80211_DEBUG_REFCNT + bf->bf_taken_at_func = func; + bf->bf_taken_at_line = line; +#else /* IEEE80211_DEBUG_REFCNT */ + /* This isn't very useful, but it keeps the lost buffer scanning code simpler */ + bf->bf_taken_at_func = __func__; + bf->bf_taken_at_line = __LINE__; +#endif /* IEEE80211_DEBUG_REFCNT */ +#ifdef IEEE80211_DEBUG_REFCNT DPRINTF(sc, ATH_DEBUG_TXBUF, "[TXBUF=%03d/%03d] (from %s:%d) took txbuf %p.\n", ath_get_buffer_count(sc), ATH_TXBUF, @@ -5382,6 +5393,8 @@ dd->dd_name = name; dd->dd_desc_len = sizeof(struct ath_desc) * nbuf * ndesc; + dd->dd_nbuf = nbuf; + dd->dd_ndesc = ndesc; /* allocate descriptors */ dd->dd_desc = bus_alloc_consistent(sc->sc_bdev, @@ -11876,619 +11889,6 @@ return 0; } -/* For any addresses we wish to get a symbolic representation of (i.e. flag - * names) we can add it to this helper function and a subsequent line is - * printed with the status in symbolic form. */ -#ifdef ATH_REVERSE_ENGINEERING -static void -ath_print_register_details(struct ath_softc *sc, const char* name, - u_int32_t address, u_int32_t v) -{ -/* constants from openhal ar5212reg.h */ -#define AR5K_AR5212_PHY_ERR_FIL 0x810c -#define AR5K_AR5212_PHY_ERR_FIL_RADAR 0x00000020 -#define AR5K_AR5212_PHY_ERR_FIL_OFDM 0x00020000 -#define AR5K_AR5212_PHY_ERR_FIL_CCK 0x02000000 -#define AR5K_AR5212_PIMR 0x00a0 -#define AR5K_AR5212_PISR 0x0080 -#define AR5K_AR5212_PIMR_RXOK 0x00000001 -#define AR5K_AR5212_PIMR_RXDESC 0x00000002 -#define AR5K_AR5212_PIMR_RXERR 0x00000004 -#define AR5K_AR5212_PIMR_RXNOFRM 0x00000008 -#define AR5K_AR5212_PIMR_RXEOL 0x00000010 -#define AR5K_AR5212_PIMR_RXORN 0x00000020 -#define AR5K_AR5212_PIMR_TXOK 0x00000040 -#define AR5K_AR5212_PIMR_TXDESC 0x00000080 -#define AR5K_AR5212_PIMR_TXERR 0x00000100 -#define AR5K_AR5212_PIMR_TXNOFRM 0x00000200 -#define AR5K_AR5212_PIMR_TXEOL 0x00000400 -#define AR5K_AR5212_PIMR_TXURN 0x00000800 -#define AR5K_AR5212_PIMR_MIB 0x00001000 -#define AR5K_AR5212_PIMR_SWI 0x00002000 -#define AR5K_AR5212_PIMR_RXPHY 0x00004000 -#define AR5K_AR5212_PIMR_RXKCM 0x00008000 -#define AR5K_AR5212_PIMR_SWBA 0x00010000 -#define AR5K_AR5212_PIMR_BRSSI 0x00020000 -#define AR5K_AR5212_PIMR_BMISS 0x00040000 -#define AR5K_AR5212_PIMR_HIUERR 0x00080000 -#define AR5K_AR5212_PIMR_BNR 0x00100000 -#define AR5K_AR5212_PIMR_RXCHIRP 0x00200000 -#define AR5K_AR5212_PIMR_TIM 0x00800000 -#define AR5K_AR5212_PIMR_BCNMISC 0x00800000 -#define AR5K_AR5212_PIMR_GPIO 0x01000000 -#define AR5K_AR5212_PIMR_QCBRORN 0x02000000 -#define AR5K_AR5212_PIMR_QCBRURN 0x04000000 -#define AR5K_AR5212_PIMR_QTRIG 0x08000000 - - if (address == AR5K_AR5212_PHY_ERR_FIL) { - IPRINTF(sc, "%18s info:%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" - "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", - (name == strstr(name, "AR5K_AR5212_") ? - (name + strlen("AR5K_AR5212_")) : - name), - (v & (1 << 31) ? " (1 << 31)" : ""), - (v & (1 << 30) ? " (1 << 30)" : ""), - (v & (1 << 29) ? " (1 << 29)" : ""), - (v & (1 << 28) ? " (1 << 28)" : ""), - (v & (1 << 27) ? " (1 << 27)" : ""), - (v & (1 << 26) ? " (1 << 26)" : ""), - (v & AR5K_AR5212_PHY_ERR_FIL_CCK ? " CCK" : ""), - (v & (1 << 24) ? " (1 << 24)" : ""), - (v & (1 << 23) ? " (1 << 23)" : ""), - (v & (1 << 22) ? " (1 << 22)" : ""), - (v & (1 << 21) ? " (1 << 21)" : ""), - (v & (1 << 20) ? " (1 << 20)" : ""), - (v & (1 << 19) ? " (1 << 19)" : ""), - (v & (1 << 18) ? " (1 << 18)" : ""), - (v & AR5K_AR5212_PHY_ERR_FIL_OFDM ? " OFDM" : ""), - (v & (1 << 16) ? " (1 << 16)" : ""), - (v & (1 << 15) ? " (1 << 15)" : ""), - (v & (1 << 14) ? " (1 << 14)" : ""), - (v & (1 << 13) ? " (1 << 13)" : ""), - (v & (1 << 12) ? " (1 << 12)" : ""), - (v & (1 << 11) ? " (1 << 11)" : ""), - (v & (1 << 10) ? " (1 << 10)" : ""), - (v & (1 << 9) ? " (1 << 9)" : ""), - (v & (1 << 8) ? " (1 << 8)" : ""), - (v & (1 << 7) ? " (1 << 7)" : ""), - (v & (1 << 6) ? " (1 << 6)" : ""), - (v & AR5K_AR5212_PHY_ERR_FIL_RADAR ? " RADAR" : ""), - (v & (1 << 4) ? " (1 << 4)" : ""), - (v & (1 << 3) ? " (1 << 3)" : ""), - (v & (1 << 2) ? " (1 << 2)" : ""), - (v & (1 << 1) ? " (1 << 1)" : ""), - (v & (1 << 0) ? " (1 << 0)" : "") - ); - } - if (address == AR5K_AR5212_PISR || address == AR5K_AR5212_PIMR) { - IPRINTF(sc, "%18s info:%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" - "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", - (name == strstr(name, "AR5K_AR5212_") ? - (name + strlen("AR5K_AR5212_")) : - name), - (v & HAL_INT_GLOBAL ? " HAL_INT_GLOBAL" : ""), - (v & HAL_INT_FATAL ? " HAL_INT_FATAL" : ""), - (v & (1 << 29) ? " (1 << 29)" : ""), - (v & (1 << 28) ? " (1 << 28)" : ""), - (v & AR5K_AR5212_PIMR_RXOK ? " RXOK" : ""), - (v & AR5K_AR5212_PIMR_RXDESC ? " RXDESC" : ""), - (v & AR5K_AR5212_PIMR_RXERR ? " RXERR" : ""), - (v & AR5K_AR5212_PIMR_RXNOFRM ? " RXNOFRM" : ""), - (v & AR5K_AR5212_PIMR_RXEOL ? " RXEOL" : ""), - (v & AR5K_AR5212_PIMR_RXORN ? " RXORN" : ""), - (v & AR5K_AR5212_PIMR_TXOK ? " TXOK" : ""), - (v & AR5K_AR5212_PIMR_TXDESC ? " TXDESC" : ""), - (v & AR5K_AR5212_PIMR_TXERR ? " TXERR" : ""), - (v & AR5K_AR5212_PIMR_TXNOFRM ? " TXNOFRM" : ""), - (v & AR5K_AR5212_PIMR_TXEOL ? " TXEOL" : ""), - (v & AR5K_AR5212_PIMR_TXURN ? " TXURN" : ""), - (v & AR5K_AR5212_PIMR_MIB ? " MIB" : ""), - (v & AR5K_AR5212_PIMR_SWI ? " SWI" : ""), - (v & AR5K_AR5212_PIMR_RXPHY ? " RXPHY" : ""), - (v & AR5K_AR5212_PIMR_RXKCM ? " RXKCM" : ""), - (v & AR5K_AR5212_PIMR_SWBA ? " SWBA" : ""), - (v & AR5K_AR5212_PIMR_BRSSI ? " BRSSI" : ""), - (v & AR5K_AR5212_PIMR_BMISS ? " BMISS" : ""), - (v & AR5K_AR5212_PIMR_HIUERR ? " HIUERR" : ""), - (v & AR5K_AR5212_PIMR_BNR ? " BNR" : ""), - (v & AR5K_AR5212_PIMR_RXCHIRP ? " RXCHIRP" : ""), - (v & AR5K_AR5212_PIMR_TIM ? " TIM" : ""), - (v & AR5K_AR5212_PIMR_BCNMISC ? " BCNMISC" : ""), - (v & AR5K_AR5212_PIMR_GPIO ? " GPIO" : ""), - (v & AR5K_AR5212_PIMR_QCBRORN ? " QCBRORN" : ""), - (v & AR5K_AR5212_PIMR_QCBRURN ? " QCBRURN" : ""), - (v & AR5K_AR5212_PIMR_QTRIG ? " QTRIG" : "") - ); - } -#undef AR5K_AR5212_PHY_ERR_FIL -#undef AR5K_AR5212_PHY_ERR_FIL_RADAR -#undef AR5K_AR5212_PHY_ERR_FIL_OFDM -#undef AR5K_AR5212_PHY_ERR_FIL_CCK -#undef AR5K_AR5212_PIMR -#undef AR5K_AR5212_PISR -#undef AR5K_AR5212_PIMR_RXOK -#undef AR5K_AR5212_PIMR_RXDESC -#undef AR5K_AR5212_PIMR_RXERR -#undef AR5K_AR5212_PIMR_RXNOFRM -#undef AR5K_AR5212_PIMR_RXEOL -#undef AR5K_AR5212_PIMR_RXORN -#undef AR5K_AR5212_PIMR_TXOK -#undef AR5K_AR5212_PIMR_TXDESC -#undef AR5K_AR5212_PIMR_TXERR -#undef AR5K_AR5212_PIMR_TXNOFRM -#undef AR5K_AR5212_PIMR_TXEOL -#undef AR5K_AR5212_PIMR_TXURN -#undef AR5K_AR5212_PIMR_MIB -#undef AR5K_AR5212_PIMR_SWI -#undef AR5K_AR5212_PIMR_RXPHY -#undef AR5K_AR5212_PIMR_RXKCM -#undef AR5K_AR5212_PIMR_SWBA -#undef AR5K_AR5212_PIMR_BRSSI -#undef AR5K_AR5212_PIMR_BMISS -#undef AR5K_AR5212_PIMR_HIUERR -#undef AR5K_AR5212_PIMR_BNR -#undef AR5K_AR5212_PIMR_RXCHIRP -#undef AR5K_AR5212_PIMR_TIM -#undef AR5K_AR5212_PIMR_BCNMISC -#undef AR5K_AR5212_PIMR_GPIO -#undef AR5K_AR5212_PIMR_QCBRORN -#undef AR5K_AR5212_PIMR_QCBRURN -#undef AR5K_AR5212_PIMR_QTRIG -} -#endif /* #ifdef ATH_REVERSE_ENGINEERING */ - -/* Print out a register with name, address and value in hex and binary. If - * v_old and v_new are the same we just dump the binary out (zeros are listed - * using dots for easier reading). If v_old and v_new are NOT the same, we - * indicate which bits were activated or de-activated using differnet - * characters than 1. */ -#ifdef ATH_REVERSE_ENGINEERING -static void -ath_print_register_delta(struct ath_softc *sc, const char* name, - u_int32_t address, u_int32_t v_old, u_int32_t v_new) -{ -#define BIT_UNCHANGED_ON "1" -#define BIT_UNCHANGED_OFF "." -#define BIT_CHANGED_ON "+" -#define BIT_CHANGED_OFF "-" -#define NYBBLE_SEPARATOR "" -#define BYTE_SEPARATOR " " -#define BIT_STATUS(_shift) \ - (((v_old & (1 << _shift)) == (v_new & (1 << _shift))) ? \ - (v_new & (1 << _shift) ? \ - BIT_UNCHANGED_ON : BIT_UNCHANGED_OFF) : \ - (v_new & (1 << _shift) ? \ - BIT_CHANGED_ON : BIT_CHANGED_OFF)) - - /* Used for formatting hex data with spacing */ - static char nybbles[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', - '9', 'a', 'b', 'c', 'd', 'e', 'f'}; - char address_string[10] = ""; - - if (address != 0xffffffff) { - address_string[0] = '*'; - address_string[1] = '0'; - address_string[2] = 'x'; - address_string[3] = nybbles[(address >> 12) & 0x0f]; - address_string[4] = nybbles[(address >> 8) & 0x0f]; - address_string[5] = nybbles[(address >> 4) & 0x0f]; - address_string[6] = nybbles[(address >> 0) & 0x0f]; - address_string[7] = '='; - address_string[9] = '\0'; - } - IPRINTF(sc, - "%23s: %s0x%08x%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" - "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", - (name == strstr(name, "AR5K_AR5212_") ? - (name+strlen("AR5K_AR5212_")) : - name), - address_string, - v_new, - " ", - BIT_STATUS(31), - BIT_STATUS(30), - BIT_STATUS(29), - BIT_STATUS(28), - NYBBLE_SEPARATOR, - BIT_STATUS(27), - BIT_STATUS(26), - BIT_STATUS(25), - BIT_STATUS(24), - BYTE_SEPARATOR, - BIT_STATUS(23), - BIT_STATUS(22), - BIT_STATUS(21), - BIT_STATUS(20), - NYBBLE_SEPARATOR, - BIT_STATUS(19), - BIT_STATUS(18), - BIT_STATUS(17), - BIT_STATUS(16), - BYTE_SEPARATOR, - BIT_STATUS(15), - BIT_STATUS(14), - BIT_STATUS(13), - BIT_STATUS(12), - NYBBLE_SEPARATOR, - BIT_STATUS(11), - BIT_STATUS(10), - BIT_STATUS( 9), - BIT_STATUS( 8), - BYTE_SEPARATOR, - BIT_STATUS( 7), - BIT_STATUS( 6), - BIT_STATUS( 5), - BIT_STATUS( 4), - NYBBLE_SEPARATOR, - BIT_STATUS( 3), - BIT_STATUS( 2), - BIT_STATUS( 1), - BIT_STATUS( 0), - "" - ); -#undef BIT_UNCHANGED_ON -#undef BIT_UNCHANGED_OFF -#undef BIT_CHANGED_ON -#undef BIT_CHANGED_OFF -#undef NYBBLE_SEPARATOR -#undef BYTE_SEPARATOR -#undef BIT_STATUS -} -#endif /* #ifdef ATH_REVERSE_ENGINEERING */ - -/* Lookup a friendly name for a register address (for any we have nicknames - * for). Names were taken from openhal ar5212regs.h. Return AH_TRUE if the - * name is a known ar5212 register, and AH_FALSE otherwise. */ -#ifdef ATH_REVERSE_ENGINEERING -static HAL_BOOL -ath_lookup_register_name(struct ath_softc *sc, char* buf, int buflen, - u_int32_t address) { - const char* static_label = NULL; - memset(buf, 0, buflen); - - if ((ar_device(sc->devid) == 5212) || (ar_device(sc->devid) == 5213)) { - /* Handle Static Register Labels (unique stuff we know about) */ - switch (address) { - case 0x0008: static_label = "CR"; break; - case 0x000c: static_label = "RXDP"; break; - case 0x0014: static_label = "CFG"; break; - case 0x0024: static_label = "IER"; break; - case 0x0030: static_label = "TXCFG"; break; - case 0x0034: static_label = "RXCFG"; break; - case 0x0040: static_label = "MIBC"; break; - case 0x0044: static_label = "TOPS"; break; - case 0x0048: static_label = "RXNOFRM"; break; - case 0x004c: static_label = "TXNOFRM"; break; - case 0x0050: static_label = "RPGTO"; break; - case 0x0054: static_label = "RFCNT"; break; - case 0x0058: static_label = "MISC"; break; - case 0x0080: static_label = "PISR"; break; - case 0x0084: static_label = "SISR0"; break; - case 0x0088: static_label = "SISR1"; break; - case 0x008c: static_label = "SISR2"; break; - case 0x0090: static_label = "SISR3"; break; - case 0x0094: static_label = "SISR4"; break; - case 0x00a0: static_label = "PIMR"; break; - case 0x00a4: static_label = "SIMR0"; break; - case 0x00a8: static_label = "SIMR1"; break; - case 0x00ac: static_label = "SIMR2"; break; - case 0x00b0: static_label = "SIMR3"; break; - case 0x00b4: static_label = "SIMR4"; break; - case 0x0400: static_label = "DCM_ADDR"; break; - case 0x0404: static_label = "DCM_DATA"; break; - case 0x0420: static_label = "DCCFG"; break; - case 0x0600: static_label = "CCFG"; break; - case 0x0604: static_label = "CCFG_CUP"; break; - case 0x0610: static_label = "CPC0"; break; - case 0x0614: static_label = "CPC1"; break; - case 0x0618: static_label = "CPC2"; break; - case 0x061c: static_label = "CPC3"; break; - case 0x0620: static_label = "CPCORN"; break; - case 0x0800: static_label = "QCU_TXDP(0)"; break; - case 0x0804: static_label = "QCU_TXDP(1)"; break; - case 0x0808: static_label = "QCU_TXDP(2)"; break; - case 0x080c: static_label = "QCU_TXDP(3)"; break; - case 0x0810: static_label = "QCU_TXDP(4)"; break; - case 0x0814: static_label = "QCU_TXDP(5)"; break; - case 0x0818: static_label = "QCU_TXDP(6)"; break; - case 0x081c: static_label = "QCU_TXDP(7)"; break; - case 0x0820: static_label = "QCU_TXDP(8)"; break; - case 0x0824: static_label = "QCU_TXDP(9)"; break; - case 0x0840: static_label = "QCU_TXE"; break; - case 0x0880: static_label = "QCU_TXD"; break; - case 0x08c0: static_label = "QCU_CBRCFG(0)"; break; - case 0x08c4: static_label = "QCU_CBRCFG(1)"; break; - case 0x08c8: static_label = "QCU_CBRCFG(2)"; break; - case 0x08cc: static_label = "QCU_CBRCFG(3)"; break; - case 0x08d0: static_label = "QCU_CBRCFG(4)"; break; - case 0x08d4: static_label = "QCU_CBRCFG(5)"; break; - case 0x08d8: static_label = "QCU_CBRCFG(6)"; break; - case 0x08dc: static_label = "QCU_CBRCFG(7)"; break; - case 0x08e0: static_label = "QCU_CBRCFG(8)"; break; - case 0x08e4: static_label = "QCU_CBRCFG(9)"; break; - case 0x0900: static_label = "QCU_RDYTIMECFG(0)"; break; - case 0x0904: static_label = "QCU_RDYTIMECFG(1)"; break; - case 0x0908: static_label = "QCU_RDYTIMECFG(2)"; break; - case 0x090c: static_label = "QCU_RDYTIMECFG(3)"; break; - case 0x0910: static_label = "QCU_RDYTIMECFG(4)"; break; - case 0x0914: static_label = "QCU_RDYTIMECFG(5)"; break; - case 0x0918: static_label = "QCU_RDYTIMECFG(6)"; break; - case 0x091c: static_label = "QCU_RDYTIMECFG(7)"; break; - case 0x0920: static_label = "QCU_RDYTIMECFG(8)"; break; - case 0x0924: static_label = "QCU_RDYTIMECFG(9)"; break; - case 0x0940: static_label = "QCU_ONESHOTARM_SET(0)"; break; - case 0x0944: static_label = "QCU_ONESHOTARM_SET(1)"; break; - case 0x0948: static_label = "QCU_ONESHOTARM_SET(2)"; break; - case 0x094c: static_label = "QCU_ONESHOTARM_SET(3)"; break; - case 0x0950: static_label = "QCU_ONESHOTARM_SET(4)"; break; - case 0x0954: static_label = "QCU_ONESHOTARM_SET(5)"; break; - case 0x0958: static_label = "QCU_ONESHOTARM_SET(6)"; break; - case 0x095c: static_label = "QCU_ONESHOTARM_SET(7)"; break; - case 0x0960: static_label = "QCU_ONESHOTARM_SET(8)"; break; - case 0x0964: static_label = "QCU_ONESHOTARM_SET(9)"; break; - case 0x0980: static_label = "QCU_ONESHOTARM_CLR(0)"; break; - case 0x0984: static_label = "QCU_ONESHOTARM_CLR(1)"; break; - case 0x0988: static_label = "QCU_ONESHOTARM_CLR(2)"; break; - case 0x098c: static_label = "QCU_ONESHOTARM_CLR(3)"; break; - case 0x0990: static_label = "QCU_ONESHOTARM_CLR(4)"; break; - case 0x0994: static_label = "QCU_ONESHOTARM_CLR(5)"; break; - case 0x0998: static_label = "QCU_ONESHOTARM_CLR(6)"; break; - case 0x099c: static_label = "QCU_ONESHOTARM_CLR(7)"; break; - case 0x09a0: static_label = "QCU_ONESHOTARM_CLR(8)"; break; - case 0x09a4: static_label = "QCU_ONESHOTARM_CLR(9)"; break; - case 0x09c0: static_label = "QCU_MISC(0)"; break; - case 0x09c4: static_label = "QCU_MISC(1)"; break; - case 0x09c8: static_label = "QCU_MISC(2)"; break; - case 0x09cc: static_label = "QCU_MISC(3)"; break; - case 0x09d0: static_label = "QCU_MISC(4)"; break; - case 0x09d4: static_label = "QCU_MISC(5)"; break; - case 0x09d8: static_label = "QCU_MISC(6)"; break; - case 0x09dc: static_label = "QCU_MISC(7)"; break; - case 0x09e0: static_label = "QCU_MISC(8)"; break; - case 0x09e4: static_label = "QCU_MISC(9)"; break; - case 0x0a00: static_label = "QCU_STS(0)"; break; - case 0x0a04: static_label = "QCU_STS(1)"; break; - case 0x0a08: static_label = "QCU_STS(2)"; break; - case 0x0a0c: static_label = "QCU_STS(3)"; break; - case 0x0a10: static_label = "QCU_STS(4)"; break; - case 0x0a14: static_label = "QCU_STS(5)"; break; - case 0x0a18: static_label = "QCU_STS(6)"; break; - case 0x0a1c: static_label = "QCU_STS(7)"; break; - case 0x0a20: static_label = "QCU_STS(8)"; break; - case 0x0a24: static_label = "QCU_STS(9)"; break; - case 0x0a40: static_label = "QCU_RDYTIMESHDN"; break; - case 0x0b00: static_label = "QCU_CBB_SELECT"; break; - case 0x0b04: static_label = "QCU_CBB_ADDR"; break; - case 0x0b08: static_label = "QCU_CBCFG"; break; - case 0x1000: static_label = "DCU_QCUMASK(9)"; break; - case 0x1004: static_label = "DCU_QCUMASK(0)"; break; - case 0x1008: static_label = "DCU_QCUMASK(1)"; break; - case 0x100c: static_label = "DCU_QCUMASK(2)"; break; - case 0x1010: static_label = "DCU_QCUMASK(3)"; break; - case 0x1014: static_label = "DCU_QCUMASK(4)"; break; - case 0x1018: static_label = "DCU_QCUMASK(5)"; break; - case 0x101c: static_label = "DCU_QCUMASK(6)"; break; - case 0x1020: static_label = "DCU_QCUMASK(7)"; break; - case 0x1024: static_label = "DCU_QCUMASK(8)"; break; - case 0x1030: static_label = "DCU_GBL_IFS_SIFS"; break; - case 0x1038: static_label = "DCU_TX_FILTER"; break; - case 0x1040: static_label = "DCU_LCL_IFS(0)"; break; - case 0x1044: static_label = "DCU_LCL_IFS(1)"; break; - case 0x1048: static_label = "DCU_LCL_IFS(2)"; break; - case 0x104c: static_label = "DCU_LCL_IFS(3)"; break; - case 0x1050: static_label = "DCU_LCL_IFS(4)"; break; - case 0x1054: static_label = "DCU_LCL_IFS(5)"; break; - case 0x1058: static_label = "DCU_LCL_IFS(6)"; break; - case 0x105c: static_label = "DCU_LCL_IFS(7)"; break; - case 0x1060: static_label = "DCU_LCL_IFS(8)"; break; - case 0x1064: static_label = "DCU_LCL_IFS(9)"; break; - case 0x1070: static_label = "DCU_GBL_IFS_SLOT"; break; - case 0x1080: static_label = "DCU_RETRY_LIMIT(0)"; break; - case 0x1084: static_label = "DCU_RETRY_LIMIT(1)"; break; - case 0x1088: static_label = "DCU_RETRY_LIMIT(2)"; break; - case 0x108c: static_label = "DCU_RETRY_LIMIT(3)"; break; - case 0x1090: static_label = "DCU_RETRY_LIMIT(4)"; break; - case 0x1094: static_label = "DCU_RETRY_LIMIT(5)"; break; - case 0x1098: static_label = "DCU_RETRY_LIMIT(6)"; break; - case 0x109c: static_label = "DCU_RETRY_LIMIT(7)"; break; - case 0x10a0: static_label = "DCU_RETRY_LIMIT(8)"; break; - case 0x10a4: static_label = "DCU_RETRY_LIMIT(9)"; break; - case 0x10b0: static_label = "DCU_GBL_IFS_EIFS"; break; - case 0x10c0: static_label = "DCU_CHAN_TIME(0)"; break; - case 0x10c4: static_label = "DCU_CHAN_TIME(1)"; break; - case 0x10c8: static_label = "DCU_CHAN_TIME(2)"; break; - case 0x10cc: static_label = "DCU_CHAN_TIME(3)"; break; - case 0x10d0: static_label = "DCU_CHAN_TIME(4)"; break; - case 0x10d4: static_label = "DCU_CHAN_TIME(5)"; break; - case 0x10d8: static_label = "DCU_CHAN_TIME(6)"; break; - case 0x10dc: static_label = "DCU_CHAN_TIME(7)"; break; - case 0x10e0: static_label = "DCU_CHAN_TIME(8)"; break; - case 0x10e4: static_label = "DCU_CHAN_TIME(9)"; break; - case 0x10f0: static_label = "DCU_GBL_IFS_MISC"; break; - case 0x1100: static_label = "DCU_MISC(0)"; break; - case 0x1104: static_label = "DCU_MISC(1)"; break; - case 0x1108: static_label = "DCU_MISC(2)"; break; - case 0x110c: static_label = "DCU_MISC(3)"; break; - case 0x1110: static_label = "DCU_MISC(4)"; break; - case 0x1114: static_label = "DCU_MISC(5)"; break; - case 0x1118: static_label = "DCU_MISC(6)"; break; - case 0x111c: static_label = "DCU_MISC(7)"; break; - case 0x1120: static_label = "DCU_MISC(8)"; break; - case 0x1124: static_label = "DCU_MISC(9)"; break; - case 0x1140: static_label = "DCU_SEQ_NUM(0)"; break; - case 0x1144: static_label = "DCU_SEQ_NUM(1)"; break; - case 0x1148: static_label = "DCU_SEQ_NUM(2)"; break; - case 0x114c: static_label = "DCU_SEQ_NUM(3)"; break; - case 0x1150: static_label = "DCU_SEQ_NUM(4)"; break; - case 0x1154: static_label = "DCU_SEQ_NUM(5)"; break; - case 0x1158: static_label = "DCU_SEQ_NUM(6)"; break; - case 0x115c: static_label = "DCU_SEQ_NUM(7)"; break; - case 0x1160: static_label = "DCU_SEQ_NUM(8)"; break; - case 0x1164: static_label = "DCU_SEQ_NUM(9)"; break; - case 0x1230: static_label = "DCU_FP"; break; - case 0x1270: static_label = "DCU_TXP"; break; - case 0x143c: static_label = "DCU_TX_FILTER_CLR"; break; - case 0x147c: static_label = "DCU_TX_FILTER_SET"; break; - case 0x4000: static_label = "RESET_CONTROL"; break; - case 0x4004: static_label = "SLEEP_CONTROL"; break; - case 0x4008: static_label = "INTERRUPT_PENDING"; break; - case 0x400c: static_label = "SLEEP_FORCE"; break; - case 0x4010: static_label = "PCICFG"; break; - case 0x4014: static_label = "GPIOCR"; break; - case 0x4018: static_label = "GPIODO"; break; - case 0x401c: static_label = "GPIODI"; break; - case 0x4020: static_label = "SREV"; break; - case 0x6000: static_label = "EEPROM_BASE"; break; - case 0x6004: static_label = "EEPROM_DATA"; break; - case 0x6008: static_label = "EEPROM_CMD"; break; - case 0x6010: static_label = "EEPROM_CFG"; break; - case 0x8000: static_label = "STA_ID0"; break; - case 0x8004: static_label = "STA_ID1"; break; - case 0x8008: static_label = "BSS_ID0"; break; - case 0x800c: static_label = "BSS_ID1"; break; - case 0x8010: static_label = "SLOT_TIME"; break; - case 0x8014: static_label = "TIME_OUT"; break; - case 0x8018: static_label = "RSSI_THR"; break; - case 0x801c: static_label = "USEC"; break; - case 0x8020: static_label = "BEACON"; break; - case 0x8024: static_label = "CFP_PERIOD"; break; - case 0x8028: static_label = "TIMER0"; break; - case 0x802c: static_label = "TIMER1"; break; - case 0x8030: static_label = "TIMER2"; break; - case 0x8034: static_label = "TIMER3"; break; - case 0x8038: static_label = "CFP_DUR"; break; - case 0x803c: static_label = "RX_FILTER"; break; - case 0x8040: static_label = "MCAST_FIL0"; break; - case 0x8044: static_label = "MCAST_FIL1"; break; - case 0x8048: static_label = "DIAG_SW"; break; - case 0x804c: static_label = "TSF_L32"; break; - case 0x8050: static_label = "TSF_U32"; break; - case 0x8054: static_label = "ADDAC_TEST"; break; - case 0x8058: static_label = "DEFAULT_ANTENNA"; break; - case 0x8080: static_label = "LAST_TSTP"; break; - case 0x8084: static_label = "NAV"; break; - case 0x8088: static_label = "RTS_OK"; break; - case 0x808c: static_label = "RTS_FAIL"; break; - case 0x8090: static_label = "ACK_FAIL"; break; - case 0x8094: static_label = "FCS_FAIL"; break; - case 0x8098: static_label = "BEACON_CNT"; break; - case 0x80c0: static_label = "XRMODE"; break; - case 0x80c4: static_label = "XRDELAY"; break; - case 0x80c8: static_label = "XRTIMETOUT"; break; - case 0x80cc: static_label = "XRCHIRP"; break; - case 0x80d0: static_label = "XRSTOMP"; break; - case 0x80d4: static_label = "SLEEP0"; break; - case 0x80d8: static_label = "SLEEP1"; break; - case 0x80dc: static_label = "SLEEP2"; break; - case 0x80e0: static_label = "BSS_IDM0"; break; - case 0x80e4: static_label = "BSS_IDM1"; break; - case 0x80e8: static_label = "TXPC"; break; - case 0x80ec: static_label = "PROFCNT_TX"; break; - case 0x80f0: static_label = "PROFCNT_RX"; break; - case 0x80f4: static_label = "PROFCNT_RXCLR"; break; - case 0x80f8: static_label = "PROFCNT_CYCLE"; break; - case 0x8104: static_label = "TSF_PARM"; break; - case 0x810c: static_label = "PHY_ERR_FIL"; break; - case 0x9800: static_label = "PHY(0)"; break; - case 0x9804: static_label = "PHY_TURBO"; break; - case 0x9808: static_label = "PHY_AGC"; break; - case 0x9814: static_label = "PHY_TIMING_3"; break; - case 0x9818: static_label = "PHY_CHIP_ID"; break; - case 0x981c: static_label = "PHY_ACTIVE"; break; - case 0x9860: static_label = "PHY_AGCCTL"; break; - case 0x9864: static_label = "PHY_NF"; break; - case 0x9870: static_label = "PHY_SCR"; break; - case 0x9874: static_label = "PHY_SLMT"; break; - case 0x9878: static_label = "PHY_SCAL"; break; - case 0x987c: static_label = "PHY_PLL"; break; - case 0x9914: static_label = "PHY_RX_DELAY"; break; - case 0x9920: static_label = "PHY_IQ"; break; - case 0x9930: static_label = "PHY_PAPD_PROBE"; break; - case 0x9934: static_label = "PHY_TXPOWER_RATE1"; break; - case 0x9938: static_label = "PHY_TXPOWER_RATE2"; break; - case 0x993c: static_label = "PHY_TXPOWER_RATE_MAX"; break; - case 0x9944: static_label = "PHY_FC"; break; - case 0x9954: static_label = "PHY_RADAR"; break; - case 0x9960: static_label = "PHY_ANT_SWITCH_TABLE_0"; break; - case 0x9964: static_label = "PHY_ANT_SWITCH_TABLE_1"; break; - case 0x99f0: static_label = "PHY_SCLOCK"; break; - case 0x99f4: static_label = "PHY_SDELAY"; break; - case 0x99f8: static_label = "PHY_SPENDING"; break; - case 0x9c10: static_label = "PHY_IQRES_CAL_PWR_I"; break; - case 0x9c14: static_label = "PHY_IQRES_CAL_PWR_Q"; break; - case 0x9c18: static_label = "PHY_IQRES_CAL_CORR"; break; - case 0x9c1c: static_label = "PHY_CURRENT_RSSI"; break; - case 0xa200: static_label = "PHY_MODE"; break; - case 0xa204: static_label = "PHY_CCKTXCTL"; break; - case 0xa20c: static_label = "PHY_GAIN_2GHZ"; break; - case 0xa234: static_label = "PHY_TXPOWER_RATE3"; break; - case 0xa238: static_label = "PHY_TXPOWER_RATE4"; break; - default: - break; - } - if (static_label) { - snprintf(buf, buflen, static_label); - return AH_TRUE; - } - - /* Handle Key Table */ - if ((address >= 0x8800) && (address < 0x9800)) { -#define keytable_entry_reg_count (8) -#define keytable_entry_size (keytable_entry_reg_count * sizeof(u_int32_t)) - int key = ((address - 0x8800) / keytable_entry_size); - int reg = ((address - 0x8800) % keytable_entry_size) / - sizeof(u_int32_t); - char* format = NULL; - switch (reg) { - case 0: format = "KEY(%3d).KEYBITS[031:000]"; break; - case 1: format = "KEY(%3d).KEYBITS[047:032]"; break; - case 2: format = "KEY(%3d).KEYBITS[079:048]"; break; - case 3: format = "KEY(%3d).KEYBITS[095:080]"; break; - case 4: format = "KEY(%3d).KEYBITS[127:096]"; break; - case 5: format = "KEY(%3d).TYPE............"; break; - case 6: format = "KEY(%3d).MAC[32:01]......"; break; - case 7: format = "KEY(%3d).MAC[47:33]......"; break; - default: - BUG(); - } - snprintf(buf, buflen, format, key); -#undef keytable_entry_reg_count -#undef keytable_entry_size - return AH_TRUE; - } - - /* Handle Rate Duration Table */ - if (address >= 0x8700 && address < 0x8780) { - snprintf(buf, buflen, "RATE(%2d).DURATION", - ((address - 0x8700) / sizeof(u_int32_t))); - return AH_TRUE; - } - - /* Handle txpower Table */ - if (address >= 0xa180 && address < 0xa200) { - snprintf(buf, buflen, "PCDAC_TXPOWER(%2d)", - ((address - 0xa180) / sizeof(u_int32_t))); - return AH_TRUE; - } - } - - /* Everything else... */ - snprintf(buf, buflen, UNKNOWN_NAME); - return AH_FALSE; -} -#endif /* #ifdef ATH_REVERSE_ENGINEERING */ - -/* Print out a single register name/address/value in hex and binary */ -#ifdef ATH_REVERSE_ENGINEERING -static void -ath_print_register(struct ath_softc *sc, const char* name, u_int32_t address, - u_int32_t v) -{ - ath_print_register_delta(sc, name, address, v, v); - ath_print_register_details(sc, name, address, v); -} -#endif /* #ifdef ATH_REVERSE_ENGINEERING */ - /* A filter for hiding the addresses we don't think are very interesting or * which have adverse side effects. Return AH_TRUE if the address should be * exlucded, and AH_FALSE otherwise. */ @@ -12509,13 +11909,15 @@ if ((address >= 0x143c) && (address <= 0x143f)) return FILTERED; /* PCI timing registers are not interesting */ if ((address >= 0x4000) && (address <= 0x5000)) return FILTERED; + /* reading 0x9200-0x092c causes crashes in turbo A mode? */ + if ((address >= 0x0920) && (address <= 0x092c)) return FILTERED; #ifndef ATH_REVERSE_ENGINEERING_WITH_NO_FEAR /* We are being conservative, and do not want to access addresses that * may crash the system, so we will only consider addresses we know * the names of from previous reverse engineering efforts (AKA * openHAL). */ - return (AH_TRUE == ath_lookup_register_name(sc, buf, + return (AH_TRUE == ath_hal_lookup_register_name(sc->sc_ah, buf, MAX_REGISTER_NAME_LEN, address)) ? UNFILTERED : FILTERED; #else /* #ifndef ATH_REVERSE_ENGINEERING_WITH_NO_FEAR */ @@ -12531,17 +11933,16 @@ #ifdef ATH_REVERSE_ENGINEERING static void ath_ar5212_registers_dump(struct ath_softc *sc) { - char name[MAX_REGISTER_NAME_LEN]; unsigned int address = MIN_REGISTER_ADDRESS; unsigned int value = 0; do { if (ath_regdump_filter(sc, address)) continue; - ath_lookup_register_name(sc, name, - MAX_REGISTER_NAME_LEN, address); value = ath_reg_read(sc, address); - ath_print_register(sc, name, address, value); + ath_hal_print_decoded_register(sc->sc_ah, SC_DEV_NAME(sc), + address, value, value, + AH_FALSE); } while ((address += 4) < MAX_REGISTER_ADDRESS); } #endif /* #ifdef ATH_REVERSE_ENGINEERING */ @@ -12554,7 +11955,6 @@ { unsigned int address = MIN_REGISTER_ADDRESS; unsigned int value = 0; - char name[MAX_REGISTER_NAME_LEN]; unsigned int *p_old = 0; do { @@ -12563,10 +11963,8 @@ value = ath_reg_read(sc, address); p_old = (unsigned int*)&sc->register_snapshot[address]; if (*p_old != value) { - ath_lookup_register_name(sc, name, - MAX_REGISTER_NAME_LEN, address); - ath_print_register_delta(sc, name, address, *p_old, value); - ath_print_register_details(sc, name, address, value); + ath_hal_print_decoded_register(sc->sc_ah, SC_DEV_NAME(sc), + address, *p_old, value, AH_FALSE); } } while ((address += 4) < MAX_REGISTER_ADDRESS); } @@ -12867,6 +12265,355 @@ if (bf->bf_skb != NULL) ieee80211_dev_kfree_skb_list(&bf->bf_skb); + bf->bf_taken_at_line = 0; + bf->bf_taken_at_func = NULL; return bf; } +#define SCANTXBUF_NAMSIZ 64 +static inline int +descdma_contains_buffer(struct ath_descdma* dd, struct ath_buf* bf) { + return (bf >= (dd->dd_bufptr)) && + bf < (dd->dd_bufptr + dd->dd_nbuf); +} + +static inline int +descdma_index_of_buffer(struct ath_descdma* dd, struct ath_buf* bf) { + if (!descdma_contains_buffer(dd, bf)) + return -1; + return bf - dd->dd_bufptr; +} + +static inline struct ath_buf* +descdma_get_buffer(struct ath_descdma* dd, int index) +{ + KASSERT((index >= 0 && index < dd->dd_nbuf), + ("Invalid index, %d, requested for %s dma buffers.\n", index, dd->dd_name)); + return dd->dd_bufptr + index; +} + +static int ath_debug_iwpriv(struct ieee80211com *ic, + unsigned int param, unsigned int value) +{ + struct ath_softc *sc = ic->ic_dev->priv; + switch(param) { + case IEEE80211_PARAM_DRAINTXQ: + printk("Draining tx queue...\n"); + ath_draintxq(sc); + break; + case IEEE80211_PARAM_STOP_QUEUE: + printk("Stopping device queue...\n"); + netif_stop_queue(sc->sc_dev); + break; + case IEEE80211_PARAM_ATHRESET: + printk("Forcing device to reset...\n"); + ath_reset(sc->sc_dev); + break; + case IEEE80211_PARAM_TXTIMEOUT: + printk("Simulating tx watchdog timeout...\n"); + ath_tx_timeout(sc->sc_dev); + break; + case IEEE80211_PARAM_RESETTXBUFS: + printk("Brute force reset of tx buffer pool...\n"); + ATH_TXBUF_LOCK_IRQ(sc); + netif_stop_queue(sc->sc_dev); + ath_draintxq(sc); + ath_descdma_cleanup(sc, &sc->sc_txdma, &sc->sc_txbuf, + BUS_DMA_TODEVICE); + ath_descdma_setup(sc, &sc->sc_txdma, &sc->sc_txbuf, + "tx", ATH_TXBUF, ATH_TXDESC); + atomic_set(&sc->sc_txbuf_counter, ATH_TXBUF); + ATH_TXBUF_UNLOCK_IRQ(sc); + break; + case IEEE80211_PARAM_LEAKTXBUFS: + { + int j; + for(j = 0; j < value; j++) { + if(!ath_take_txbuf_mgmt(sc)) { + printk("Leaked %d tx buffers (of the %d tx buffers requested).\n", j, value); + return 0; + } + } + printk("Leaked %d tx buffers.\n", value); + } + break; + case IEEE80211_PARAM_SCANBUFS: + printk("Scanning DMA buffer heaps...\n"); + ath_scanbufs(sc); + break; + default: + printk("%s: Unknown command: %d.\n", __func__, param); + return -EINVAL; + } + + return 0; +} + +static void +ath_scanbufs_found_buf_locked(struct ath_softc *sc, struct ath_descdma* dd, + unsigned long* dd_bufs_found, struct ath_buf *tbf, + const char* context) +{ + int index = descdma_index_of_buffer(dd, tbf); + if (-1 != index) { + printk("FOUND %s[%3d] (%p) in %s. status: 0x%08x.\n", + dd->dd_name, index, tbf, context, tbf->bf_status); + if (test_and_set_bit(index, dd_bufs_found)) { + printk("FOUND %s[%3d] (%p) multiple times!!!\n", + dd->dd_name, index, tbf); + } + } +#if 0 +/* XXX: To make this work right, must know which hw queues are used + * with each kind of buffer, and make a more selective call... */ + else { + EPRINTF(sc, "Detected a martian %s (%p) in %s!!\n", + dd->dd_name, tbf, context); + } +#endif +} + +static void +ath_scanbufs_in_buflist_locked(struct ath_softc *sc, struct ath_descdma* dd, + unsigned long* dd_bufs_found, ath_bufhead *bufs, + const char* context) +{ + struct ath_buf *tbf; + STAILQ_FOREACH(tbf, bufs, bf_list) { + ath_scanbufs_found_buf_locked(sc, dd, dd_bufs_found, tbf, + context); + } +} + +static void +ath_scanbufs_in_txq_locked(struct ath_softc *sc, struct ath_descdma* dd, + unsigned long* dd_bufs_found, struct ath_txq* txq, + const char* context) +{ + struct ath_buf *tbf; + char sacontext[SCANTXBUF_NAMSIZ]; + + STAILQ_FOREACH(tbf, &txq->axq_q, bf_list) { + ath_scanbufs_found_buf_locked(sc, dd, dd_bufs_found, tbf, + context); + } + + snprintf(sacontext, sizeof(sacontext), "%s staging area", context); + TAILQ_FOREACH(tbf, &txq->axq_stageq, bf_stagelist) { + ath_scanbufs_found_buf_locked(sc, dd, dd_bufs_found, tbf, + sacontext); + } +} + +static void +ath_scanbufs_in_vap_locked(struct ath_softc *sc, struct ath_descdma* dd, + unsigned long* dd_bufs_found, struct ath_vap *av) +{ + char context[SCANTXBUF_NAMSIZ]; + if (av->av_bcbuf && dd == &sc->sc_bdma) { + snprintf(context, sizeof(context), "vap %s %p[" MAC_FMT + "] bcbuf*", + DEV_NAME(av->av_vap.iv_dev), av, + MAC_ADDR(av->av_vap.iv_bssid)); + ath_scanbufs_found_buf_locked(sc, dd, dd_bufs_found, + av->av_bcbuf, context); + } + else if(dd == &sc->sc_txdma) { + struct ath_buf *tbf = NULL; + + snprintf(context, sizeof(context), "vap %s %p[" MAC_FMT + "] mcast queue", + DEV_NAME(av->av_vap.iv_dev), av, + MAC_ADDR(av->av_vap.iv_bssid)); + STAILQ_FOREACH(tbf, &av->av_mcastq.axq_q, bf_list) { + ath_scanbufs_found_buf_locked(sc, dd, dd_bufs_found, + tbf, context); + } + + snprintf(context, sizeof(context), "vap %s %p[" MAC_FMT + "] mcast queue staging area", + DEV_NAME(av->av_vap.iv_dev), av, + MAC_ADDR(av->av_vap.iv_bssid)); + TAILQ_FOREACH(tbf, &av->av_mcastq.axq_stageq, bf_stagelist) { + ath_scanbufs_found_buf_locked(sc, dd, dd_bufs_found, tbf, + context); + } + } +} + +static void +ath_scanbufs_in_all_vaps_locked(struct ath_softc *sc, struct ath_descdma* dd, + unsigned long* dd_bufs_found) +{ + struct ieee80211vap *vap; + TAILQ_FOREACH(vap, &sc->sc_ic.ic_vaps, iv_next) { + ath_scanbufs_in_vap_locked(sc, dd, dd_bufs_found, ATH_VAP(vap)); + } +} + +static void +ath_scanbufs_in_all_nodetable_locked(struct ath_softc *sc, struct ath_descdma* dd, + unsigned long* dd_bufs_found, + struct ieee80211_node_table *nt) +{ + struct ieee80211_node *node = NULL; + struct ath_node *athnode = NULL; + char context[SCANTXBUF_NAMSIZ]; + TAILQ_FOREACH(node, &nt->nt_node, ni_list) { + athnode = ATH_NODE(node); + + snprintf(context, sizeof(context), + "node %p[" MAC_FMT " on %s[" MAC_FMT "]] uapsd_q", + athnode, + MAC_ADDR(athnode->an_node.ni_macaddr), + DEV_NAME(athnode->an_node.ni_vap->iv_dev), + MAC_ADDR(athnode->an_node.ni_bssid)); + ath_scanbufs_in_buflist_locked(sc, dd, dd_bufs_found, + &athnode->an_uapsd_q, context); + + snprintf(context, sizeof(context), + "node %p[" MAC_FMT " on %s[" MAC_FMT "]] uapsd_overflowq", + athnode, + MAC_ADDR(athnode->an_node.ni_macaddr), + DEV_NAME(athnode->an_node.ni_vap->iv_dev), + MAC_ADDR(athnode->an_node.ni_bssid)); + ath_scanbufs_in_buflist_locked(sc, dd, dd_bufs_found, + &athnode->an_uapsd_overflowq, + context); + } +} + +static void +ath_scanbufs_in_all_hwtxq_locked(struct ath_softc *sc, + struct ath_descdma* dd, + unsigned long* dd_bufs_found) +{ + int q = HAL_NUM_TX_QUEUES; + char context[SCANTXBUF_NAMSIZ]; + while (--q >= 0) + if (ATH_TXQ_SETUP(sc, q)) { + snprintf(context, sizeof(context), "txq[%d]", q); + ath_scanbufs_in_txq_locked(sc, dd, + dd_bufs_found, &sc->sc_txq[q], context); + } +} +static void +ath_scanbufs_print_leaks(struct ath_softc *sc, + struct ath_descdma* dd, + unsigned long* dd_bufs_found) +{ + int index; + struct ath_buf *lostbf; + for(index = 0; index < dd->dd_nbuf; index++) { + if (!test_bit(index, dd_bufs_found)) { + lostbf = descdma_get_buffer(dd, index); + /* XXX: Full alloc backtrace */ + EPRINTF(sc, "LOST %s[%3d] (%p) -- " + "taken at line %s:%d!!\n", + dd->dd_name, index, lostbf, + (lostbf->bf_taken_at_func ? + lostbf->bf_taken_at_func : "(null)"), + lostbf->bf_taken_at_line); + } + } +} + +static void +ath_scanbufs(struct ath_softc *sc) +{ + struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211_node_table *nt = &ic->ic_sta; + int qnum = 0; + struct ieee80211_node *ni; + int i; + /* Set up a list of dma areas to scan for. Unfortunately the locks + * are all external to this, so they were specified above with the + * standard lock macros... */ + struct ath_descdma* descdma[] = { + &sc->sc_txdma, + &sc->sc_rxdma, + &sc->sc_bdma, + &sc->sc_grppolldma + }; + struct ath_descdma* dd; + unsigned long *dd_bufs_found; + + /* NB: Locking sequence is critical to avoid deadlocks !!! */ + IEEE80211_LOCK_IRQ(&sc->sc_ic); + IEEE80211_SCAN_LOCK_IRQ(nt); + IEEE80211_NODE_TABLE_LOCK_IRQ(nt); + ATH_LOCK(sc); + ATH_HAL_LOCK_IRQ(sc); + ATH_GBUF_LOCK_IRQ(sc); + ATH_BBUF_LOCK_IRQ(sc); + ATH_TXBUF_LOCK_IRQ(sc); + ATH_RXBUF_LOCK_IRQ(sc); + while (qnum++ < HAL_NUM_TX_QUEUES) { + if (ATH_TXQ_SETUP(sc, qnum)) { + ATH_TXQ_LOCK_IRQ_INSIDE(&sc->sc_txq[qnum]); + } + } + TAILQ_FOREACH(ni, &nt->nt_node, ni_list) { + /* IEEE80211_NODE_LOCK_IRQ_INSIDE(ni); NB: ifdef'd out */ + IEEE80211_NODE_SAVEQ_LOCK_IRQ_INSIDE(ni); + ATH_NODE_UAPSD_LOCK_IRQ_INSIDE(ATH_NODE(ni)); + } + + /* NB: We have all you base... */ + for(i = 0; i < ARRAY_SIZE(descdma); i++) { + printk("\n"); + dd = descdma[i]; + if (dd->dd_bufptr) { + printk("Analyzing %s DMA buffers...\n", dd->dd_name); + dd_bufs_found = kzalloc(BITS_TO_LONGS(dd->dd_nbuf) * + sizeof(unsigned long), GFP_KERNEL); + if(dd == &sc->sc_txdma) { + ath_scanbufs_in_buflist_locked(sc, dd, dd_bufs_found, + &sc->sc_txbuf, "free list"); + ath_scanbufs_in_all_hwtxq_locked(sc, dd, dd_bufs_found); + ath_scanbufs_in_all_vaps_locked(sc, dd, dd_bufs_found); + ath_scanbufs_in_all_nodetable_locked(sc, dd, dd_bufs_found, nt); + } + else if(dd == &sc->sc_rxdma) { + ath_scanbufs_in_buflist_locked(sc, dd, dd_bufs_found, + &sc->sc_rxbuf, "queue"); + } + else if(dd == &sc->sc_bdma) { + ath_scanbufs_in_buflist_locked(sc, dd, dd_bufs_found, + &sc->sc_bbuf, "free list"); + ath_scanbufs_in_all_vaps_locked(sc, dd, dd_bufs_found); + ath_scanbufs_in_all_hwtxq_locked(sc, dd, dd_bufs_found); + } + else if(dd == &sc->sc_grppolldma) { + ath_scanbufs_in_buflist_locked(sc, dd, dd_bufs_found, + &sc->sc_grppollbuf, "free list"); + ath_scanbufs_in_txq_locked(sc, dd, dd_bufs_found, + &sc->sc_grpplq, "group poll queue"); + } + + /* print out what we found was missing and what line led to it */ + ath_scanbufs_print_leaks(sc, dd, dd_bufs_found); + kfree(dd_bufs_found); + dd_bufs_found = NULL; + } + } + printk("\n"); + /* NB: Reversing above locking sequence is critical to avoid deadlocks !!! */ + TAILQ_FOREACH(ni, &nt->nt_node, ni_list) { + /* IEEE80211_NODE_UNLOCK_IRQ_INSIDE(ni); NB: ifdef'd out */ + IEEE80211_NODE_SAVEQ_UNLOCK_IRQ_INSIDE(ni); + ATH_NODE_UAPSD_UNLOCK_IRQ_INSIDE(ATH_NODE(ni)); + } + while (--qnum >= 0) + if (ATH_TXQ_SETUP(sc, qnum)) + ATH_TXQ_UNLOCK_IRQ_INSIDE(&sc->sc_txq[qnum]); + ATH_RXBUF_UNLOCK_IRQ(sc); + ATH_TXBUF_UNLOCK_IRQ(sc); + ATH_BBUF_UNLOCK_IRQ(sc); + ATH_GBUF_UNLOCK_IRQ(sc); + ATH_HAL_UNLOCK_IRQ(sc); + ATH_UNLOCK(sc); + IEEE80211_NODE_TABLE_UNLOCK_IRQ(nt); + IEEE80211_SCAN_UNLOCK_IRQ(nt); + IEEE80211_UNLOCK_IRQ(ic); +} Modified: madwifi/trunk/ath/if_ath_hal.h =================================================================== --- madwifi/trunk/ath/if_ath_hal.h 2008-04-09 22:03:18 UTC (rev 3496) +++ madwifi/trunk/ath/if_ath_hal.h 2008-04-09 22:25:51 UTC (rev 3497) @@ -1529,6 +1529,7 @@ } #include "if_ath_hal_wrappers.h" +#include "if_ath_hal_extensions.h" #endif /* #ifndef _IF_ATH_HAL_H_ */ /* *** THIS IS A GENERATED FILE -- DO NOT EDIT *** */ Modified: madwifi/trunk/ath/if_athvar.h =================================================================== --- madwifi/trunk/ath/if_athvar.h 2008-04-09 22:03:18 UTC (rev 3496) +++ madwifi/trunk/ath/if_athvar.h 2008-04-09 22:25:51 UTC (rev 3497) @@ -452,6 +452,8 @@ u_int32_t bf_queueage; /* "age" of txq when this buffer placed on stageq */ dma_addr_t bf_skbaddrff[ATH_TXDESC - 1]; /* extra addrs for FF */ #endif + int bf_taken_at_line; /* XXX: Want full alloc backtrace */ + const char* bf_taken_at_func; }; /* @@ -477,6 +479,8 @@ struct ath_desc *dd_desc; /* descriptors */ dma_addr_t dd_desc_paddr; /* physical addr of dd_desc */ size_t dd_desc_len; /* size of dd_desc */ + unsigned int dd_ndesc; + unsigned int dd_nbuf; struct ath_buf *dd_bufptr; /* associated buffers */ }; @@ -718,7 +722,7 @@ u_int sc_ledpin; /* GPIO pin for driving LED */ u_int sc_ledon; /* pin setting for LED on */ u_int sc_ledidle; /* idle polling interval */ - int sc_ledevent; /* time of last LED event */ + long unsigned int sc_ledevent; /* time of last LED event */ u_int8_t sc_rxrate; /* current rx rate for LED */ u_int8_t sc_txrate; /* current tx rate for LED */ u_int16_t sc_ledoff; /* off time for current blink */ @@ -751,6 +755,7 @@ u_int8_t sc_grppoll_str[GRPPOLL_RATE_STR_LEN]; struct ath_descdma sc_bdma; /* beacon descriptors */ ath_bufhead sc_bbuf; /* beacon buffers */ + spinlock_t sc_bbuflock; /* beacon buffers lock */ u_int sc_bhalq; /* HAL q for outgoing beacons */ u_int sc_bmisscount; /* missed beacon transmits */ u_int32_t sc_ant_tx[8]; /* recent tx frames/antenna */ @@ -759,6 +764,7 @@ struct ath_txq *sc_xrtxq; /* tx q for XR data */ struct ath_descdma sc_grppolldma; /* TX descriptors for grppoll */ ath_bufhead sc_grppollbuf; /* transmit buffers for grouppoll */ + spinlock_t sc_grppollbuflock; /* grouppoll lock */ u_int16_t sc_xrpollint; /* xr poll interval */ u_int16_t sc_xrpollcount; /* xr poll count */ struct ath_txq *sc_uapsdq; /* tx q for uapsd */ Modified: madwifi/trunk/net80211/ieee80211_ioctl.h =================================================================== --- madwifi/trunk/net80211/ieee80211_ioctl.h 2008-04-09 22:03:18 UTC (rev 3496) +++ madwifi/trunk/net80211/ieee80211_ioctl.h 2008-04-09 22:25:51 UTC (rev 3497) @@ -642,6 +642,13 @@ IEEE80211_PARAM_BEACON_MISS_THRESH = 73, /* Beacon miss threshold (in beacons) */ IEEE80211_PARAM_BEACON_MISS_THRESH_MS = 74, /* Beacon miss threshold (in ms) */ IEEE80211_PARAM_RSSI_EWMA = 75, + IEEE80211_PARAM_DRAINTXQ = 76, /* Drain transmit queues */ + IEEE80211_PARAM_STOP_QUEUE = 77, /* Stop the device queue (for testing) */ + IEEE80211_PARAM_TXTIMEOUT = 78, /* Simulate Transmit timeout */ + IEEE80211_PARAM_ATHRESET = 79, /* Force device reset */ + IEEE80211_PARAM_RESETTXBUFS = 80, /* Reset transmit DMA */ + IEEE80211_PARAM_SCANBUFS = 81, /* Heap analysis for TX DMA */ + IEEE80211_PARAM_LEAKTXBUFS = 82, /* Leak tx buffers */ }; #define SIOCG80211STATS (SIOCDEVPRIVATE+2) Modified: madwifi/trunk/net80211/ieee80211_proto.h =================================================================== --- madwifi/trunk/net80211/ieee80211_proto.h 2008-04-09 22:03:18 UTC (rev 3496) +++ madwifi/trunk/net80211/ieee80211_proto.h 2008-04-09 22:25:51 UTC (rev 3497) @@ -55,6 +55,7 @@ extern const char *ieee80211_state_name[IEEE80211_S_MAX]; extern const char *ieee80211_wme_acnames[]; extern const char *ieee80211_phymode_name[]; +extern const char *ieee80211_opmode_name[]; void ieee80211_proto_attach(struct ieee80211com *); void ieee80211_proto_detach(struct ieee80211com *); Modified: madwifi/trunk/net80211/ieee80211_var.h =================================================================== --- madwifi/trunk/net80211/ieee80211_var.h 2008-04-09 22:03:18 UTC (rev 3496) +++ madwifi/trunk/net80211/ieee80211_var.h 2008-04-09 22:25:51 UTC (rev 3497) @@ -518,6 +518,7 @@ unsigned int (*ic_write_register)(struct ieee80211com *, unsigned int, unsigned int); unsigned int (*ic_read_register)(struct ieee80211com *, unsigned int, unsigned int*); #endif /* #ifdef ATH_REVERSE_ENGINEERING */ + int (*ic_debug_ath_iwpriv)(struct ieee80211com *, unsigned int param, unsigned int value); }; #define MAX_PROC_IEEE80211_SIZE 16383 Modified: madwifi/trunk/net80211/ieee80211_wireless.c =================================================================== --- madwifi/trunk/net80211/ieee80211_wireless.c 2008-04-09 22:03:18 UTC (rev 3496) +++ madwifi/trunk/net80211/ieee80211_wireless.c 2008-04-09 22:25:51 UTC (rev 3497) @@ -372,6 +372,9 @@ retv = ifmedia_ioctl(vap->iv_dev, &ifr, &vap->iv_media, SIOCSIFMEDIA); if (retv == -ENETRESET) retv = IS_UP_AUTO(vap) ? ieee80211_open(vap->iv_dev) : 0; + if (retv) + IEEE80211_DPRINTF(vap, IEEE80211_MSG_DEBUG, "%s returns %d\n", + __func__, retv); return retv; } @@ -767,7 +770,8 @@ * effect when we are transitioned to RUN state later. */ if (IS_UP(vap->iv_dev) && (0 == (vap->iv_des_chan->ic_flags & CHANNEL_DFS))) { - pre_announced_chanswitch(dev, ieee80211_chan2ieee(ic, vap->iv_des_chan), + pre_announced_chanswitch(dev, + ieee80211_chan2ieee(ic, vap->iv_des_chan), IEEE80211_DEFAULT_CHANCHANGE_TBTT_COUNT); } else if (vap->iv_state == IEEE80211_S_RUN) { @@ -2575,6 +2579,16 @@ } else retv = EINVAL; break; + case IEEE80211_PARAM_DRAINTXQ: /* fallthrough */ + case IEEE80211_PARAM_STOP_QUEUE: /* fallthrough */ + case IEEE80211_PARAM_ATHRESET: /* fallthrough */ + case IEEE80211_PARAM_TXTIMEOUT: /* fallthrough */ + case IEEE80211_PARAM_RESETTXBUFS: /* fallthrough */ + case IEEE80211_PARAM_SCANBUFS: /* fallthrough */ + case IEEE80211_PARAM_LEAKTXBUFS: /* fallthrough */ + retv = ic->ic_debug_ath_iwpriv(ic, param, value); + break; + case IEEE80211_PARAM_BEACON_MISS_THRESH_MS: if ((vap->iv_opmode != IEEE80211_M_IBSS) && (vap->iv_opmode != IEEE80211_M_STA)) @@ -5582,12 +5596,25 @@ 0, IW_PRIV_TYPE_APPIEBUF, "getiebuf" }, { IEEE80211_IOCTL_FILTERFRAME, IW_PRIV_TYPE_FILTER , 0, "setfilter" }, - { IEEE80211_PARAM_RSSI_EWMA, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "rssi_ewma" }, { IEEE80211_PARAM_RSSI_EWMA, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_rssi_ewma" }, - + { IEEE80211_PARAM_DRAINTXQ, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "debug_draintxq" }, + { IEEE80211_PARAM_STOP_QUEUE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "debug_stopq" }, + { IEEE80211_PARAM_TXTIMEOUT, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "debug_txtimeout" }, + { IEEE80211_PARAM_ATHRESET, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "debug_athreset" }, + { IEEE80211_PARAM_RESETTXBUFS, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "debug_newtxbufs" }, + { IEEE80211_PARAM_SCANBUFS, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "debug_scanbufs" }, + { IEEE80211_PARAM_LEAKTXBUFS, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "debug_leaktxbufs" }, + #ifdef ATH_REVERSE_ENGINEERING /* Diagnostic dump of device registers |