From: Benoit Papillault Date: Thu, 8 Apr 2010 21:53:39 +0000 (+0200) Subject: ath5k & ath9k: Add the ability to disable physical & virtual carrier sense. X-Git-Url: http://git.popipo.fr/?p=rt2x00.git;a=commitdiff_plain;h=6e617aef04e78aa09fdaf029ff2095bda8509606 ath5k & ath9k: Add the ability to disable physical & virtual carrier sense. This patch adds 2 debugfs file in ath5k and ath9k debugfs directory, called : - physical_carrier_sense : when set to 1, physical carrier sense is disabled. - virtual_carrier_sense : when set to 1, virtual carrier sense is disabled Carrier sense settings are restored after a hardware reset. --- diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index ac67f02..1f90dde 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -1135,6 +1135,10 @@ struct ath5k_hw { /* Software interrupt mask */ u8 ah_swi_mask; + /* Saved values of physical & virtual carrier sense */ + int saved_phy_cs; + int saved_virt_cs; + /* * Function pointers */ @@ -1310,6 +1314,11 @@ extern unsigned int ath5k_hw_get_def_antenna(struct ath5k_hw *ah); /* TX power setup */ extern int ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel, u8 ee_mode, u8 txpower); extern int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, u8 txpower); +/* physical & virtual carrier sense get/set methods */ +int ath5k_hw_get_phy_cs(struct ath5k_hw *ah); +void ath5k_hw_set_phy_cs(struct ath5k_hw *ah, int val); +int ath5k_hw_get_virt_cs(struct ath5k_hw *ah); +void ath5k_hw_set_virt_cs(struct ath5k_hw *ah, int val); /* * Functions used internaly diff --git a/drivers/net/wireless/ath/ath5k/debug.c b/drivers/net/wireless/ath/ath5k/debug.c index 747508c..246c62d 100644 --- a/drivers/net/wireless/ath/ath5k/debug.c +++ b/drivers/net/wireless/ath/ath5k/debug.c @@ -363,6 +363,90 @@ static const struct file_operations fops_debug = { .owner = THIS_MODULE, }; +static ssize_t read_file_phy_cs(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath5k_softc *sc = file->private_data; + struct ath5k_hw *ah = sc->ah; + char buf[32]; + unsigned int len; + int val; + + val = ath5k_hw_get_phy_cs(ah); + len = snprintf(buf, sizeof(buf), "%d\n", val); + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t write_file_phy_cs(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath5k_softc *sc = file->private_data; + struct ath5k_hw *ah = sc->ah; + unsigned long val; + char buf[32]; + ssize_t len; + + len = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, len)) + return -EINVAL; + + buf[len] = '\0'; + if (strict_strtoul(buf, 0, &val)) + return -EINVAL; + + ath5k_hw_set_phy_cs(ah, val); + return count; +} + +static const struct file_operations fops_phy_cs = { + .read = read_file_phy_cs, + .write = write_file_phy_cs, + .open = ath5k_debugfs_open, + .owner = THIS_MODULE +}; + +static ssize_t read_file_virt_cs(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath5k_softc *sc = file->private_data; + struct ath5k_hw *ah = sc->ah; + char buf[32]; + unsigned int len; + int val; + + val = ath5k_hw_get_virt_cs(ah); + len = snprintf(buf, sizeof(buf), "%d\n",val); + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t write_file_virt_cs(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath5k_softc *sc = file->private_data; + struct ath5k_hw *ah = sc->ah; + unsigned long val; + char buf[32]; + ssize_t len; + + len = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, len)) + return -EINVAL; + + buf[len] = '\0'; + if (strict_strtoul(buf, 0, &val)) + return -EINVAL; + + ath5k_hw_set_virt_cs(ah, val); + + return count; +} + +static const struct file_operations fops_virt_cs = { + .read = read_file_virt_cs, + .write = write_file_virt_cs, + .open = ath5k_debugfs_open, + .owner = THIS_MODULE +}; /* init */ @@ -393,6 +477,14 @@ ath5k_debug_init_device(struct ath5k_softc *sc) sc->debug.debugfs_reset = debugfs_create_file("reset", S_IWUSR, sc->debug.debugfs_phydir, sc, &fops_reset); + + sc->debug.debugfs_phy_cs = debugfs_create_file("physical_carrier_sense", + S_IRUSR|S_IWUSR, + sc->debug.debugfs_phydir, sc, &fops_phy_cs); + + sc->debug.debugfs_virt_cs = debugfs_create_file("virtual_carrier_sense", + S_IRUSR|S_IWUSR, + sc->debug.debugfs_phydir, sc, &fops_virt_cs); } void @@ -404,6 +496,8 @@ ath5k_debug_finish(void) void ath5k_debug_finish_device(struct ath5k_softc *sc) { + debugfs_remove(sc->debug.debugfs_virt_cs); + debugfs_remove(sc->debug.debugfs_phy_cs); debugfs_remove(sc->debug.debugfs_debug); debugfs_remove(sc->debug.debugfs_registers); debugfs_remove(sc->debug.debugfs_beacon); diff --git a/drivers/net/wireless/ath/ath5k/debug.h b/drivers/net/wireless/ath/ath5k/debug.h index 66f69f0..070226c 100644 --- a/drivers/net/wireless/ath/ath5k/debug.h +++ b/drivers/net/wireless/ath/ath5k/debug.h @@ -74,6 +74,8 @@ struct ath5k_dbg_info { struct dentry *debugfs_registers; struct dentry *debugfs_beacon; struct dentry *debugfs_reset; + struct dentry *debugfs_phy_cs; + struct dentry *debugfs_virt_cs; }; /** diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c index eff3323..4604e8f 100644 --- a/drivers/net/wireless/ath/ath5k/phy.c +++ b/drivers/net/wireless/ath/ath5k/phy.c @@ -3145,3 +3145,41 @@ int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, u8 txpower) } #undef _ATH5K_PHY +int ath5k_hw_get_phy_cs(struct ath5k_hw *ah) +{ + u32 regval; + + regval = ath5k_hw_reg_read(ah, AR5K_DIAG_SW); + return !!(regval & AR5K_DIAG_SW_RX_CLEAR_HIGH); +} + +void ath5k_hw_set_phy_cs(struct ath5k_hw *ah, int val) +{ + if (val) + AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW, + AR5K_DIAG_SW_RX_CLEAR_HIGH); + else + AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW, + AR5K_DIAG_SW_RX_CLEAR_HIGH); + ah->saved_phy_cs = val; +} + +int ath5k_hw_get_virt_cs(struct ath5k_hw *ah) +{ + u32 regval; + + regval = ath5k_hw_reg_read(ah, AR5K_DIAG_SW); + return !!(regval & AR5K_DIAG_SW_IGNORE_CARR_SENSE); +} + +void ath5k_hw_set_virt_cs(struct ath5k_hw *ah, int val) +{ + if (val) + AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW, + AR5K_DIAG_SW_IGNORE_CARR_SENSE); + else + AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW, + AR5K_DIAG_SW_IGNORE_CARR_SENSE); + ah->saved_virt_cs = val; +} + diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c index cbf28e3..7d337f3 100644 --- a/drivers/net/wireless/ath/ath5k/reset.c +++ b/drivers/net/wireless/ath/ath5k/reset.c @@ -1386,6 +1386,9 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, */ AR5K_REG_DISABLE_BITS(ah, AR5K_BEACON, AR5K_BEACON_ENABLE); ath5k_hw_reset_tsf(ah); + + ath5k_hw_set_phy_cs(ah, ah->saved_phy_cs); + ath5k_hw_set_virt_cs(ah, ah->saved_virt_cs); return 0; } diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 42d2a50..a65d9fc 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -699,6 +699,75 @@ static const struct file_operations fops_recv = { .owner = THIS_MODULE }; +static ssize_t write_file_phy_cs(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + unsigned long val; + char buf[32]; + ssize_t len; + + len = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, len)) + return -EINVAL; + + buf[len] = '\0'; + if (strict_strtoul(buf, 0, &val)) + return -EINVAL; + + ath9k_hw_set_phy_cs(sc->sc_ah, val); + + return count; +} + +static const struct file_operations fops_phy_cs = { + .read = read_file_phy_cs, + .write = write_file_phy_cs, + .open = ath9k_debugfs_open, + .owner = THIS_MODULE +}; + +static ssize_t read_file_virt_cs(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + char buf[32]; + unsigned int len; + int val; + + val = ath9k_hw_get_virt_cs(sc->sc_ah); + len = snprintf(buf, sizeof(buf), "%d\n", val); + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t write_file_virt_cs(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + unsigned long val; + char buf[32]; + ssize_t len; + + len = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, len)) + return -EINVAL; + + buf[len] = '\0'; + if (strict_strtoul(buf, 0, &val)) + return -EINVAL; + + ath9k_hw_set_virt_cs(sc->sc_ah, val); + + return count; +} + +static const struct file_operations fops_virt_cs = { + .read = read_file_virt_cs, + .write = write_file_virt_cs, + .open = ath9k_debugfs_open, + .owner = THIS_MODULE +}; + int ath9k_init_debug(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); @@ -758,6 +827,20 @@ int ath9k_init_debug(struct ath_hw *ah) if (!sc->debug.debugfs_recv) goto err; + sc->debug.debugfs_phy_cs = debugfs_create_file("physical_carrier_sense", + S_IRUSR|S_IWUSR, + sc->debug.debugfs_phy, + sc, &fops_phy_cs); + if (!sc->debug.debugfs_phy_cs) + goto err; + + sc->debug.debugfs_virt_cs = debugfs_create_file("virtual_carrier_sense", + S_IRUSR|S_IWUSR, + sc->debug.debugfs_phy, + sc, &fops_virt_cs); + if (!sc->debug.debugfs_virt_cs) + goto err; + return 0; err: ath9k_exit_debug(ah); @@ -769,6 +852,8 @@ 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_virt_cs); + debugfs_remove(sc->debug.debugfs_phy_cs); debugfs_remove(sc->debug.debugfs_recv); debugfs_remove(sc->debug.debugfs_xmit); debugfs_remove(sc->debug.debugfs_wiphy); diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h index 86780e6..d86bbe5 100644 --- a/drivers/net/wireless/ath/ath9k/debug.h +++ b/drivers/net/wireless/ath/ath9k/debug.h @@ -156,6 +156,8 @@ struct ath9k_debug { struct dentry *debugfs_wiphy; struct dentry *debugfs_xmit; struct dentry *debugfs_recv; + struct dentry *debugfs_phy_cs; + struct dentry *debugfs_virt_cs; struct ath_stats stats; }; diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 2e767cf..aef52aa 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -954,6 +954,10 @@ int ath9k_hw_init(struct ath_hw *ah) common->state = ATH_HW_INITIALIZED; + /* Initially, physical and virtual carrier sense are enabled */ + ah->saved_phy_cs = 0; + ah->saved_virt_cs = 0; + return 0; } @@ -1913,6 +1917,44 @@ static void ath9k_enable_rfkill(struct ath_hw *ah) REG_SET_BIT(ah, AR_PHY_TEST, RFSILENT_BB); } +int ath9k_hw_get_phy_cs(struct ath_hw *ah) +{ + u32 regval; + + regval = REG_READ(ah, AR_DIAG_SW); + return !!(regval & AR_DIAG_FORCE_RX_CLEAR); +} +EXPORT_SYMBOL(ath9k_hw_get_phy_cs); + +void ath9k_hw_set_phy_cs(struct ath_hw *ah, int val) +{ + if (val) + REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_RX_CLEAR); + else + REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_RX_CLEAR); + ah->saved_phy_cs = val; +} +EXPORT_SYMBOL(ath9k_hw_set_phy_cs); + +int ath9k_hw_get_virt_cs(struct ath_hw *ah) +{ + u32 regval; + + regval = REG_READ(ah, AR_DIAG_SW); + return !!(regval & AR_DIAG_IGNORE_VIRT_CS); +} +EXPORT_SYMBOL(ath9k_hw_get_virt_cs); + +void ath9k_hw_set_virt_cs(struct ath_hw *ah, int val) +{ + if (val) + REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_IGNORE_VIRT_CS); + else + REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_IGNORE_VIRT_CS); + ah->saved_virt_cs = val; +} +EXPORT_SYMBOL(ath9k_hw_set_virt_cs); + int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, bool bChannelChange) { @@ -2142,6 +2184,9 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, if (ah->btcoex_hw.enabled) ath9k_hw_btcoex_enable(ah); + ath9k_hw_set_phy_cs(ah, ah->saved_phy_cs); + ath9k_hw_set_virt_cs(ah, ah->saved_virt_cs); + return 0; } EXPORT_SYMBOL(ath9k_hw_reset); diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index dbbf7ca..2c1dac4 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -602,6 +602,10 @@ struct ath_hw { u32 intr_gen_timer_trigger; u32 intr_gen_timer_thresh; struct ath_gen_timer_table hw_gen_timers; + + /* Saved values of physical & virtual carrier sense */ + int saved_phy_cs; + int saved_virt_cs; }; static inline struct ath_common *ath9k_hw_common(struct ath_hw *ah) @@ -618,6 +622,10 @@ static inline struct ath_regulatory *ath9k_hw_regulatory(struct ath_hw *ah) const char *ath9k_hw_probe(u16 vendorid, u16 devid); void ath9k_hw_deinit(struct ath_hw *ah); int ath9k_hw_init(struct ath_hw *ah); +int ath9k_hw_get_phy_cs(struct ath_hw *ah); +void ath9k_hw_set_phy_cs(struct ath_hw *ah, int val); +int ath9k_hw_get_virt_cs(struct ath_hw *ah); +void ath9k_hw_set_virt_cs(struct ath_hw *ah, int val); int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, bool bChannelChange); int ath9k_hw_fill_cap_info(struct ath_hw *ah);