Commit 604eeadd authored by Bruno Randolf's avatar Bruno Randolf Committed by John W. Linville

ath5k: add antenna statistics and debugfs file for antenna settings

keep statistics about which antenna was used for TX and RX. this is used only
for debugging right now, but might have other applications later.

add a new file 'antenna' in debugfs (/sys/kernel/debug/ath5k/phy0/antenna) to show
antenna use statistics and antenna diversity related register values. it can
also be used to set the antenna mode until we have proper support for that in
iw:
  - echo diversity > antenna: use default antenna mode (RX and TX diversity)
  - echo fixed-a > antenna: use fixed antenna A for RX and TX
  - echo fixed-b > antenna: use fixed antenna B for RX and TX
  - echo clear > antenna: reset antenna statistics
Signed-off-by: default avatarBruno Randolf <br1@einfach.org>
Acked-by: default avatarNick Kossifidis <mickflemm@gmail.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 5a7d0583
...@@ -1997,6 +1997,12 @@ ath5k_tasklet_rx(unsigned long data) ...@@ -1997,6 +1997,12 @@ ath5k_tasklet_rx(unsigned long data)
rxs->signal = rxs->noise + rs.rs_rssi; rxs->signal = rxs->noise + rs.rs_rssi;
rxs->antenna = rs.rs_antenna; rxs->antenna = rs.rs_antenna;
if (rs.rs_antenna > 0 && rs.rs_antenna < 5)
sc->stats.antenna_rx[rs.rs_antenna]++;
else
sc->stats.antenna_rx[0]++; /* invalid */
rxs->rate_idx = ath5k_hw_to_driver_rix(sc, rs.rs_rate); rxs->rate_idx = ath5k_hw_to_driver_rix(sc, rs.rs_rate);
rxs->flag |= ath5k_rx_decrypted(sc, ds, skb, &rs); rxs->flag |= ath5k_rx_decrypted(sc, ds, skb, &rs);
...@@ -2090,6 +2096,11 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq) ...@@ -2090,6 +2096,11 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq)
*/ */
ath5k_remove_padding(skb); ath5k_remove_padding(skb);
if (ts.ts_antenna > 0 && ts.ts_antenna < 5)
sc->stats.antenna_tx[ts.ts_antenna]++;
else
sc->stats.antenna_tx[0]++; /* invalid */
ieee80211_tx_status(sc->hw, skb); ieee80211_tx_status(sc->hw, skb);
spin_lock(&sc->txbuflock); spin_lock(&sc->txbuflock);
......
...@@ -105,6 +105,12 @@ struct ath5k_rfkill { ...@@ -105,6 +105,12 @@ struct ath5k_rfkill {
struct tasklet_struct toggleq; struct tasklet_struct toggleq;
}; };
/* statistics (only used for debugging now) */
struct ath5k_statistics {
unsigned int antenna_rx[5]; /* frames count per antenna RX */
unsigned int antenna_tx[5]; /* frames count per antenna TX */
};
#if CHAN_DEBUG #if CHAN_DEBUG
#define ATH_CHAN_MAX (26+26+26+200+200) #define ATH_CHAN_MAX (26+26+26+200+200)
#else #else
...@@ -191,6 +197,8 @@ struct ath5k_softc { ...@@ -191,6 +197,8 @@ struct ath5k_softc {
int power_level; /* Requested tx power in dbm */ int power_level; /* Requested tx power in dbm */
bool assoc; /* associate state */ bool assoc; /* associate state */
bool enable_beacon; /* true if beacons are on */ bool enable_beacon; /* true if beacons are on */
struct ath5k_statistics stats;
}; };
#define ath5k_hw_hasbssidmask(_ah) \ #define ath5k_hw_hasbssidmask(_ah) \
......
...@@ -364,6 +364,107 @@ static const struct file_operations fops_debug = { ...@@ -364,6 +364,107 @@ static const struct file_operations fops_debug = {
}; };
/* debugfs: antenna */
static ssize_t read_file_antenna(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath5k_softc *sc = file->private_data;
char buf[700];
unsigned int len = 0;
unsigned int i;
unsigned int v;
len += snprintf(buf+len, sizeof(buf)-len, "antenna mode\t%d\n",
sc->ah->ah_ant_mode);
len += snprintf(buf+len, sizeof(buf)-len, "default antenna\t%d\n",
sc->ah->ah_def_ant);
len += snprintf(buf+len, sizeof(buf)-len, "tx antenna\t%d\n",
sc->ah->ah_tx_ant);
len += snprintf(buf+len, sizeof(buf)-len, "\nANTENNA\t\tRX\tTX\n");
for (i = 1; i < ARRAY_SIZE(sc->stats.antenna_rx); i++) {
len += snprintf(buf+len, sizeof(buf)-len,
"[antenna %d]\t%d\t%d\n",
i, sc->stats.antenna_rx[i], sc->stats.antenna_tx[i]);
}
len += snprintf(buf+len, sizeof(buf)-len, "[invalid]\t%d\t%d\n",
sc->stats.antenna_rx[0], sc->stats.antenna_tx[0]);
v = ath5k_hw_reg_read(sc->ah, AR5K_DEFAULT_ANTENNA);
len += snprintf(buf+len, sizeof(buf)-len,
"\nAR5K_DEFAULT_ANTENNA\t0x%08x\n", v);
v = ath5k_hw_reg_read(sc->ah, AR5K_STA_ID1);
len += snprintf(buf+len, sizeof(buf)-len,
"AR5K_STA_ID1_DEFAULT_ANTENNA\t%d\n",
(v & AR5K_STA_ID1_DEFAULT_ANTENNA) != 0);
len += snprintf(buf+len, sizeof(buf)-len,
"AR5K_STA_ID1_DESC_ANTENNA\t%d\n",
(v & AR5K_STA_ID1_DESC_ANTENNA) != 0);
len += snprintf(buf+len, sizeof(buf)-len,
"AR5K_STA_ID1_RTS_DEF_ANTENNA\t%d\n",
(v & AR5K_STA_ID1_RTS_DEF_ANTENNA) != 0);
len += snprintf(buf+len, sizeof(buf)-len,
"AR5K_STA_ID1_SELFGEN_DEF_ANT\t%d\n",
(v & AR5K_STA_ID1_SELFGEN_DEF_ANT) != 0);
v = ath5k_hw_reg_read(sc->ah, AR5K_PHY_AGCCTL);
len += snprintf(buf+len, sizeof(buf)-len,
"\nAR5K_PHY_AGCCTL_OFDM_DIV_DIS\t%d\n",
(v & AR5K_PHY_AGCCTL_OFDM_DIV_DIS) != 0);
v = ath5k_hw_reg_read(sc->ah, AR5K_PHY_RESTART);
len += snprintf(buf+len, sizeof(buf)-len,
"AR5K_PHY_RESTART_DIV_GC\t\t%x\n",
(v & AR5K_PHY_RESTART_DIV_GC) >> AR5K_PHY_RESTART_DIV_GC_S);
v = ath5k_hw_reg_read(sc->ah, AR5K_PHY_FAST_ANT_DIV);
len += snprintf(buf+len, sizeof(buf)-len,
"AR5K_PHY_FAST_ANT_DIV_EN\t%d\n",
(v & AR5K_PHY_FAST_ANT_DIV_EN) != 0);
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
static ssize_t write_file_antenna(struct file *file,
const char __user *userbuf,
size_t count, loff_t *ppos)
{
struct ath5k_softc *sc = file->private_data;
unsigned int i;
char buf[20];
if (copy_from_user(buf, userbuf, min(count, sizeof(buf))))
return -EFAULT;
if (strncmp(buf, "diversity", 9) == 0) {
ath5k_hw_set_antenna_mode(sc->ah, AR5K_ANTMODE_DEFAULT);
printk(KERN_INFO "ath5k debug: enable diversity\n");
} else if (strncmp(buf, "fixed-a", 7) == 0) {
ath5k_hw_set_antenna_mode(sc->ah, AR5K_ANTMODE_FIXED_A);
printk(KERN_INFO "ath5k debugfs: fixed antenna A\n");
} else if (strncmp(buf, "fixed-b", 7) == 0) {
ath5k_hw_set_antenna_mode(sc->ah, AR5K_ANTMODE_FIXED_B);
printk(KERN_INFO "ath5k debug: fixed antenna B\n");
} else if (strncmp(buf, "clear", 5) == 0) {
for (i = 0; i < ARRAY_SIZE(sc->stats.antenna_rx); i++) {
sc->stats.antenna_rx[i] = 0;
sc->stats.antenna_tx[i] = 0;
}
printk(KERN_INFO "ath5k debug: cleared antenna stats\n");
}
return count;
}
static const struct file_operations fops_antenna = {
.read = read_file_antenna,
.write = write_file_antenna,
.open = ath5k_debugfs_open,
.owner = THIS_MODULE,
};
/* init */ /* init */
void void
...@@ -393,6 +494,10 @@ ath5k_debug_init_device(struct ath5k_softc *sc) ...@@ -393,6 +494,10 @@ ath5k_debug_init_device(struct ath5k_softc *sc)
sc->debug.debugfs_reset = debugfs_create_file("reset", S_IWUSR, sc->debug.debugfs_reset = debugfs_create_file("reset", S_IWUSR,
sc->debug.debugfs_phydir, sc, &fops_reset); sc->debug.debugfs_phydir, sc, &fops_reset);
sc->debug.debugfs_antenna = debugfs_create_file("antenna",
S_IWUSR | S_IRUSR,
sc->debug.debugfs_phydir, sc, &fops_antenna);
} }
void void
...@@ -408,6 +513,7 @@ ath5k_debug_finish_device(struct ath5k_softc *sc) ...@@ -408,6 +513,7 @@ ath5k_debug_finish_device(struct ath5k_softc *sc)
debugfs_remove(sc->debug.debugfs_registers); debugfs_remove(sc->debug.debugfs_registers);
debugfs_remove(sc->debug.debugfs_beacon); debugfs_remove(sc->debug.debugfs_beacon);
debugfs_remove(sc->debug.debugfs_reset); debugfs_remove(sc->debug.debugfs_reset);
debugfs_remove(sc->debug.debugfs_antenna);
debugfs_remove(sc->debug.debugfs_phydir); debugfs_remove(sc->debug.debugfs_phydir);
} }
......
...@@ -74,6 +74,7 @@ struct ath5k_dbg_info { ...@@ -74,6 +74,7 @@ struct ath5k_dbg_info {
struct dentry *debugfs_registers; struct dentry *debugfs_registers;
struct dentry *debugfs_beacon; struct dentry *debugfs_beacon;
struct dentry *debugfs_reset; struct dentry *debugfs_reset;
struct dentry *debugfs_antenna;
}; };
/** /**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment