From b292219fa5061e2657ecf518b48426913d0ddae6 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 12 Oct 2012 10:55:53 +0200 Subject: wireless: use OR operation to set wiphy features The next patch will introduce a flag that is set by default in cfg80211 so drivers and mac80211 need to use |= to set features they have so that they don't clear the already-set feature. We could set the flag in wiphy_register() instead of wiphy_new() to avoid this patch, but then the drivers couldn't *unset* flags they don't want to use even though the implementation is generic. Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/ath6kl/cfg80211.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index 7089f8160ad..99a75d92c6c 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -3651,7 +3651,7 @@ int ath6kl_cfg80211_init(struct ath6kl *ar) if (test_bit(ATH6KL_FW_CAPABILITY_INACTIVITY_TIMEOUT, ar->fw_capabilities)) - ar->wiphy->features = NL80211_FEATURE_INACTIVITY_TIMER; + ar->wiphy->features |= NL80211_FEATURE_INACTIVITY_TIMER; ar->wiphy->probe_resp_offload = NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS | -- cgit v1.2.3-18-g5258 From 04b2312a683537eec3dbac013920b0e3cfc06123 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Fri, 12 Oct 2012 12:28:14 +0200 Subject: wireless: drivers: make use of WLAN_EID_VENDOR_SPECIFIC The include file linux/ieee80211.h contains three definitions for the same thing in enum ieee80211_eid due to historic changes: /* Information Element IDs */ enum ieee80211_eid { : WLAN_EID_WPA = 221, WLAN_EID_GENERIC = 221, WLAN_EID_VENDOR_SPECIFIC = 221, : }; The standard refers to this as "vendor specific" element so the other two definitions are better not used. This patch changes the wireless drivers to use one definition, ie. WLAN_EID_VENDOR_SPECIFIC. Cc: Jouni Malinen Cc: Dan Williams Cc: Larry Finger Acked-by: Kalle Valo [ath6kl] Acked-by: Bing Zhao [mwifiex] Acked-by: Stanislav Yakovlev [ipw2x00] Signed-off-by: Arend van Spriel [change libipw as well] Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/ath6kl/cfg80211.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index 99a75d92c6c..277089963eb 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -301,7 +301,7 @@ static bool ath6kl_cfg80211_ready(struct ath6kl_vif *vif) static bool ath6kl_is_wpa_ie(const u8 *pos) { - return pos[0] == WLAN_EID_WPA && pos[1] >= 4 && + return pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 && pos[2] == 0x00 && pos[3] == 0x50 && pos[4] == 0xf2 && pos[5] == 0x01; } -- cgit v1.2.3-18-g5258 From 78b1775ba03c2edcc8d765dd53a7e171b18e79ac Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Sun, 30 Sep 2012 09:03:20 +0530 Subject: ath9k: Use a helper routine for MCI/FTP tuning Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/gpio.c | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c index d9ed141a053..334c98d5f04 100644 --- a/drivers/net/wireless/ath/ath9k/gpio.c +++ b/drivers/net/wireless/ath/ath9k/gpio.c @@ -187,6 +187,25 @@ static void ath9k_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer) } } +static void ath_mci_ftp_adjust(struct ath_softc *sc) +{ + struct ath_btcoex *btcoex = &sc->btcoex; + struct ath_mci_profile *mci = &btcoex->mci; + struct ath_hw *ah = sc->sc_ah; + + btcoex->bt_wait_time += btcoex->btcoex_period; + if (btcoex->bt_wait_time > ATH_BTCOEX_RX_WAIT_TIME) { + if (ar9003_mci_state(ah, MCI_STATE_NEED_FTP_STOMP) && + (mci->num_pan || mci->num_other_acl)) + ah->btcoex_hw.mci.stomp_ftp = + (sc->rx.num_pkts < ATH_BTCOEX_STOMP_FTP_THRESH); + else + ah->btcoex_hw.mci.stomp_ftp = false; + btcoex->bt_wait_time = 0; + sc->rx.num_pkts = 0; + } +} + /* * This is the master bt coex timer which runs for every * 45ms, bt traffic will be given priority during 55% of this @@ -197,7 +216,6 @@ static void ath_btcoex_period_timer(unsigned long data) struct ath_softc *sc = (struct ath_softc *) data; struct ath_hw *ah = sc->sc_ah; struct ath_btcoex *btcoex = &sc->btcoex; - struct ath_mci_profile *mci = &btcoex->mci; u32 timer_period; bool is_btscan; unsigned long flags; @@ -214,17 +232,8 @@ static void ath_btcoex_period_timer(unsigned long data) ath_detect_bt_priority(sc); is_btscan = test_bit(BT_OP_SCAN, &btcoex->op_flags); - btcoex->bt_wait_time += btcoex->btcoex_period; - if (btcoex->bt_wait_time > ATH_BTCOEX_RX_WAIT_TIME) { - if (ar9003_mci_state(ah, MCI_STATE_NEED_FTP_STOMP) && - (mci->num_pan || mci->num_other_acl)) - ah->btcoex_hw.mci.stomp_ftp = - (sc->rx.num_pkts < ATH_BTCOEX_STOMP_FTP_THRESH); - else - ah->btcoex_hw.mci.stomp_ftp = false; - btcoex->bt_wait_time = 0; - sc->rx.num_pkts = 0; - } + if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI) + ath_mci_ftp_adjust(sc); spin_lock_bh(&btcoex->btcoex_lock); -- cgit v1.2.3-18-g5258 From 750f32cf0a6e2a4d798e09da4079ede7d1721e54 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Sun, 30 Sep 2012 09:03:37 +0530 Subject: ath9k: Fix BT_OP_SCAN usage BT_OP_SCAN is applicable only for pre-MCI WLAN/BT combo chips and using it for MCI-based cards is incorrect. Fix this by cleaning up its usage. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/gpio.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c index 334c98d5f04..bf4fb7db15e 100644 --- a/drivers/net/wireless/ath/ath9k/gpio.c +++ b/drivers/net/wireless/ath/ath9k/gpio.c @@ -216,8 +216,8 @@ static void ath_btcoex_period_timer(unsigned long data) struct ath_softc *sc = (struct ath_softc *) data; struct ath_hw *ah = sc->sc_ah; struct ath_btcoex *btcoex = &sc->btcoex; + enum ath_stomp_type stomp_type; u32 timer_period; - bool is_btscan; unsigned long flags; spin_lock_irqsave(&sc->sc_pm_lock, flags); @@ -228,19 +228,28 @@ static void ath_btcoex_period_timer(unsigned long data) spin_unlock_irqrestore(&sc->sc_pm_lock, flags); ath9k_ps_wakeup(sc); + if (!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI)) ath_detect_bt_priority(sc); - is_btscan = test_bit(BT_OP_SCAN, &btcoex->op_flags); if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI) ath_mci_ftp_adjust(sc); spin_lock_bh(&btcoex->btcoex_lock); - ath9k_hw_btcoex_bt_stomp(ah, is_btscan ? ATH_BTCOEX_STOMP_ALL : - btcoex->bt_stomp_type); + stomp_type = btcoex->bt_stomp_type; + timer_period = btcoex->btcoex_no_stomp; + + if (!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI)) { + if (test_bit(BT_OP_SCAN, &btcoex->op_flags)) { + stomp_type = ATH_BTCOEX_STOMP_ALL; + timer_period = btcoex->btscan_no_stomp; + } + } + ath9k_hw_btcoex_bt_stomp(ah, stomp_type); ath9k_hw_btcoex_enable(ah); + spin_unlock_bh(&btcoex->btcoex_lock); /* @@ -252,17 +261,16 @@ static void ath_btcoex_period_timer(unsigned long data) if (btcoex->hw_timer_enabled) ath9k_gen_timer_stop(ah, btcoex->no_stomp_timer); - timer_period = is_btscan ? btcoex->btscan_no_stomp : - btcoex->btcoex_no_stomp; ath9k_gen_timer_start(ah, btcoex->no_stomp_timer, timer_period, timer_period * 10); btcoex->hw_timer_enabled = true; } ath9k_ps_restore(sc); + skip_hw_wakeup: - timer_period = btcoex->btcoex_period; - mod_timer(&btcoex->period_timer, jiffies + msecs_to_jiffies(timer_period)); + mod_timer(&btcoex->period_timer, + jiffies + msecs_to_jiffies(btcoex->btcoex_period)); } /* @@ -282,7 +290,8 @@ static void ath_btcoex_no_stomp_timer(void *arg) spin_lock_bh(&btcoex->btcoex_lock); if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW || - test_bit(BT_OP_SCAN, &btcoex->op_flags)) + (!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI) && + test_bit(BT_OP_SCAN, &btcoex->op_flags))) ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_NONE); else if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_ALL) ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_LOW); -- cgit v1.2.3-18-g5258 From f255b9cccaeaa03ef6e58f7762bf7249b3dd7ea2 Mon Sep 17 00:00:00 2001 From: Peter Senna Tschudin Date: Wed, 10 Oct 2012 18:38:17 +0200 Subject: ath/ath9k/ar9003_eeprom.c: Remove semicolon after if This patch remove a semicolon after if(...) that is preventing the error check to work correctly. Removing this semicolon will change the code behavior, but this is intended. The semantic patch that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @r1@ position p; @@ if (...);@p @script:python@ p0 << r1.p; @@ // Emacs org-mode output cocci.print_main("", p0) cocci.print_secs("", p0) // Signed-off-by: Peter Senna Tschudin Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_eeprom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index 5bbe5057ba1..189aeb22f55 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -2989,7 +2989,7 @@ static u32 ath9k_hw_ar9300_get_eeprom(struct ath_hw *ah, case EEP_PAPRD: if (AR_SREV_9462(ah)) return false; - if (!ah->config.enable_paprd); + if (!ah->config.enable_paprd) return false; return !!(pBase->featureEnable & BIT(5)); case EEP_CHAIN_MASK_REDUCE: -- cgit v1.2.3-18-g5258 From 037fd9b6473393c35a31f0c43e26eb7e874e901d Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Thu, 4 Oct 2012 19:43:15 +0200 Subject: ath_hw: Use common REG_WRITE parameter order All defines for REG_WRITE in Atheros wireless drivers use the order "ah", "register" and "value". hw.c is the only file using the order "ah", "value" and "register". drivers/net/wireless/ath/ath9k/hw.h:#define REG_WRITE(_ah, _reg, _val) \ drivers/net/wireless/ath/key.c:#define REG_WRITE(_ah, _reg, _val) (common->ops->write)(_ah, _val, _reg) This inconsistent definition can easily lead to implementation errors. The modification doesn't change the behavior of the driver or the generated code. Signed-off-by: Sven Eckelmann Signed-off-by: Simon Wunderlich Acked-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/hw.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/hw.c b/drivers/net/wireless/ath/hw.c index 19befb33107..39e8a590d7f 100644 --- a/drivers/net/wireless/ath/hw.c +++ b/drivers/net/wireless/ath/hw.c @@ -20,8 +20,8 @@ #include "ath.h" #include "reg.h" -#define REG_READ (common->ops->read) -#define REG_WRITE (common->ops->write) +#define REG_READ (common->ops->read) +#define REG_WRITE(_ah, _reg, _val) (common->ops->write)(_ah, _val, _reg) /** * ath_hw_set_bssid_mask - filter out bssids we listen @@ -119,8 +119,8 @@ void ath_hw_setbssidmask(struct ath_common *common) { void *ah = common->ah; - REG_WRITE(ah, get_unaligned_le32(common->bssidmask), AR_BSSMSKL); - REG_WRITE(ah, get_unaligned_le16(common->bssidmask + 4), AR_BSSMSKU); + REG_WRITE(ah, AR_BSSMSKL, get_unaligned_le32(common->bssidmask)); + REG_WRITE(ah, AR_BSSMSKU, get_unaligned_le16(common->bssidmask + 4)); } EXPORT_SYMBOL(ath_hw_setbssidmask); @@ -139,7 +139,7 @@ void ath_hw_cycle_counters_update(struct ath_common *common) void *ah = common->ah; /* freeze */ - REG_WRITE(ah, AR_MIBC_FMC, AR_MIBC); + REG_WRITE(ah, AR_MIBC, AR_MIBC_FMC); /* read */ cycles = REG_READ(ah, AR_CCCNT); @@ -148,13 +148,13 @@ void ath_hw_cycle_counters_update(struct ath_common *common) tx = REG_READ(ah, AR_TFCNT); /* clear */ - REG_WRITE(ah, 0, AR_CCCNT); - REG_WRITE(ah, 0, AR_RFCNT); - REG_WRITE(ah, 0, AR_RCCNT); - REG_WRITE(ah, 0, AR_TFCNT); + REG_WRITE(ah, AR_CCCNT, 0); + REG_WRITE(ah, AR_RFCNT, 0); + REG_WRITE(ah, AR_RCCNT, 0); + REG_WRITE(ah, AR_TFCNT, 0); /* unfreeze */ - REG_WRITE(ah, 0, AR_MIBC); + REG_WRITE(ah, AR_MIBC, 0); /* update all cycle counters here */ common->cc_ani.cycles += cycles; -- cgit v1.2.3-18-g5258 From b4764c809a306ea37b6409494896e919bbb5ec5f Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 6 Oct 2012 20:42:54 +0200 Subject: carl9170: handle traps from firmware loader This patch changes the way the driver deals with command responses and traps which are sent through the special interrupt input endpoint 3. While the carl9170 firmware does not use this endpoint for command responses or traps, the firmware loader on the device does. It uses it to notify the host about 'watchdog triggered' in case the firmware/hardware has crashed. Note: Even without this patch, the driver is still able to detect the mishap and reset the device. But previously it did that because the trap event caused an out-of-order message sequence number error, which also triggered a reset. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/ath/carl9170/rx.c | 6 +++--- drivers/net/wireless/ath/carl9170/usb.c | 7 +++++++ 2 files changed, 10 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/carl9170/rx.c b/drivers/net/wireless/ath/carl9170/rx.c index a0b72307854..9cd93f1d8be 100644 --- a/drivers/net/wireless/ath/carl9170/rx.c +++ b/drivers/net/wireless/ath/carl9170/rx.c @@ -164,9 +164,6 @@ void carl9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len) struct carl9170_rsp *cmd = buf; struct ieee80211_vif *vif; - if (carl9170_check_sequence(ar, cmd->hdr.seq)) - return; - if ((cmd->hdr.cmd & CARL9170_RSP_FLAG) != CARL9170_RSP_FLAG) { if (!(cmd->hdr.cmd & CARL9170_CMD_ASYNC_FLAG)) carl9170_cmd_callback(ar, len, buf); @@ -820,6 +817,9 @@ static void carl9170_rx_untie_cmds(struct ar9170 *ar, const u8 *respbuf, if (unlikely(i > resplen)) break; + if (carl9170_check_sequence(ar, cmd->hdr.seq)) + break; + carl9170_handle_command_response(ar, cmd, cmd->hdr.len + 4); } diff --git a/drivers/net/wireless/ath/carl9170/usb.c b/drivers/net/wireless/ath/carl9170/usb.c index 888152ce3ec..307bc0ddff9 100644 --- a/drivers/net/wireless/ath/carl9170/usb.c +++ b/drivers/net/wireless/ath/carl9170/usb.c @@ -295,6 +295,13 @@ static void carl9170_usb_rx_irq_complete(struct urb *urb) goto resubmit; } + /* + * While the carl9170 firmware does not use this EP, the + * firmware loader in the EEPROM unfortunately does. + * Therefore we need to be ready to handle out-of-band + * responses and traps in case the firmware crashed and + * the loader took over again. + */ carl9170_handle_command_response(ar, urb->transfer_buffer, urb->actual_length); -- cgit v1.2.3-18-g5258 From 424749c75daf3611a68a49eca5940ac2b74e4406 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Wed, 10 Oct 2012 23:03:02 +0530 Subject: ath9k: perform ANI cycle in idle state As of now the ANI cycle is executed only when the chip is awake. On idle state case, the station wakes up from network sleep for beacon reception. Since most of the time, ANI cycle is not syncing with beacon wakeup, ANI cycle is ignored. Approx 5 mins once, the calibration is performed. This could affect the connection stability when the station is idle for long. Even though the OFDM and CCK phy error rates are too high, ANI is unable to tune its immunity level as quick enough due to rare execution. Here the experiment shows that OFDM and CCK levels are at default even on higher phy error rate. listenTime=44 OFDM:3 errs=121977/s CCK:2 errs=440818/s ofdm_turn=1 This change ensures that ANI calibration will be exectued atleast once for every 10 seconds. The below result shows improvements and immunity levels are adopted quick enough. listenTime=557 OFDM:4 errs=752/s CCK:4 errs=125/s ofdm_turn=0 Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 2 ++ drivers/net/wireless/ath/ath9k/hw.h | 1 + drivers/net/wireless/ath/ath9k/link.c | 12 +++++++++++- drivers/net/wireless/ath/ath9k/main.c | 3 ++- 4 files changed, 16 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index dfe6a4707fd..77c2c16b696 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -437,6 +437,7 @@ void ath9k_set_beacon(struct ath_softc *sc); #define ATH_LONG_CALINTERVAL_INT 1000 /* 1000 ms */ #define ATH_LONG_CALINTERVAL 30000 /* 30 seconds */ #define ATH_RESTART_CALINTERVAL 1200000 /* 20 minutes */ +#define ATH_ANI_MAX_SKIP_COUNT 10 #define ATH_PAPRD_TIMEOUT 100 /* msecs */ #define ATH_PLL_WORK_INTERVAL 100 @@ -642,6 +643,7 @@ enum sc_op_flags { #define PS_WAIT_FOR_PSPOLL_DATA BIT(2) #define PS_WAIT_FOR_TX_ACK BIT(3) #define PS_BEACON_SYNC BIT(4) +#define PS_WAIT_FOR_ANI BIT(5) struct ath_rate_table; diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index dbc1b7a4cbf..1d4f5f1fdd8 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -834,6 +834,7 @@ struct ath_hw { int coarse_low[5]; int firpwr[5]; enum ath9k_ani_cmd ani_function; + u32 ani_skip_count; #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT struct ath_btcoex_hw btcoex_hw; diff --git a/drivers/net/wireless/ath/ath9k/link.c b/drivers/net/wireless/ath/ath9k/link.c index 7b88b9c39cc..223b9693527 100644 --- a/drivers/net/wireless/ath/ath9k/link.c +++ b/drivers/net/wireless/ath/ath9k/link.c @@ -350,8 +350,18 @@ void ath_ani_calibrate(unsigned long data) ATH_AP_SHORT_CALINTERVAL : ATH_STA_SHORT_CALINTERVAL; /* Only calibrate if awake */ - if (sc->sc_ah->power_mode != ATH9K_PM_AWAKE) + if (sc->sc_ah->power_mode != ATH9K_PM_AWAKE) { + if (++ah->ani_skip_count >= ATH_ANI_MAX_SKIP_COUNT) { + spin_lock_irqsave(&sc->sc_pm_lock, flags); + sc->ps_flags |= PS_WAIT_FOR_ANI; + spin_unlock_irqrestore(&sc->sc_pm_lock, flags); + } goto set_timer; + } + ah->ani_skip_count = 0; + spin_lock_irqsave(&sc->sc_pm_lock, flags); + sc->ps_flags &= ~PS_WAIT_FOR_ANI; + spin_unlock_irqrestore(&sc->sc_pm_lock, flags); ath9k_ps_wakeup(sc); diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index dd45edfa6ba..2da62be081f 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -131,7 +131,8 @@ void ath9k_ps_restore(struct ath_softc *sc) !(sc->ps_flags & (PS_WAIT_FOR_BEACON | PS_WAIT_FOR_CAB | PS_WAIT_FOR_PSPOLL_DATA | - PS_WAIT_FOR_TX_ACK))) { + PS_WAIT_FOR_TX_ACK | + PS_WAIT_FOR_ANI))) { mode = ATH9K_PM_NETWORK_SLEEP; if (ath9k_hw_btcoex_is_enabled(sc->sc_ah)) ath9k_btcoex_stop_gen_timer(sc); -- cgit v1.2.3-18-g5258 From 85b20fc2420c4d20729f3bbdbfe5962dcc58c3b0 Mon Sep 17 00:00:00 2001 From: Thomas Pedersen Date: Thu, 21 Jun 2012 12:50:08 -0700 Subject: ath6kl: support rssi threshold for sched scan The ath6kl firmware can filter scan results based on rssi. This is useful to limit hosts wakeups on scheduled scans. Signed-off-by: Thomas Pedersen Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/cfg80211.c | 19 ++++++++++++++++++- drivers/net/wireless/ath/ath6kl/core.h | 3 +++ drivers/net/wireless/ath/ath6kl/wmi.c | 18 ++++++++++++++++++ drivers/net/wireless/ath/ath6kl/wmi.h | 10 ++++++++++ 4 files changed, 49 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index 277089963eb..a5f3d6e5470 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -3211,7 +3211,7 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy, struct ath6kl *ar = ath6kl_priv(dev); struct ath6kl_vif *vif = netdev_priv(dev); u16 interval; - int ret; + int ret, rssi_thold; if (ar->state != ATH6KL_STATE_ON) return -EIO; @@ -3244,6 +3244,23 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy, return ret; } + if (test_bit(ATH6KL_FW_CAPABILITY_RSSI_SCAN_THOLD, + ar->fw_capabilities)) { + if (request->rssi_thold <= NL80211_SCAN_RSSI_THOLD_OFF) + rssi_thold = 0; + else if (request->rssi_thold < -127) + rssi_thold = -127; + else + rssi_thold = request->rssi_thold; + + ret = ath6kl_wmi_set_rssi_filter_cmd(ar->wmi, vif->fw_vif_idx, + rssi_thold); + if (ret) { + ath6kl_err("failed to set RSSI threshold for scan\n"); + return ret; + } + } + /* fw uses seconds, also make sure that it's >0 */ interval = max_t(u16, 1, request->interval / 1000); diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h index cec49a31029..a6f0d2c40d2 100644 --- a/drivers/net/wireless/ath/ath6kl/core.h +++ b/drivers/net/wireless/ath/ath6kl/core.h @@ -115,6 +115,9 @@ enum ath6kl_fw_capability { */ ATH6KL_FW_CAPABILITY_SCHED_SCAN_MATCH_LIST, + /* Firmware supports filtering BSS results by RSSI */ + ATH6KL_FW_CAPABILITY_RSSI_SCAN_THOLD, + /* this needs to be last */ ATH6KL_FW_CAPABILITY_MAX, }; diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index c30ab4b11d6..9673f277817 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -1531,6 +1531,24 @@ static int ath6kl_wmi_cac_event_rx(struct wmi *wmi, u8 *datap, int len, return 0; } +int ath6kl_wmi_set_rssi_filter_cmd(struct wmi *wmi, u8 if_idx, s8 rssi) +{ + struct sk_buff *skb; + struct wmi_set_rssi_filter_cmd *cmd; + int ret; + + skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_set_rssi_filter_cmd *) skb->data; + cmd->rssi = rssi; + + ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_RSSI_FILTER_CMDID, + NO_SYNC_WMIFLAG); + return ret; +} + static int ath6kl_wmi_send_snr_threshold_params(struct wmi *wmi, struct wmi_snr_threshold_params_cmd *snr_cmd) { diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h index 43339aca585..b5deaffb79e 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.h +++ b/drivers/net/wireless/ath/ath6kl/wmi.h @@ -628,6 +628,10 @@ enum wmi_cmd_id { WMI_SET_MCASTRATE, WMI_STA_BMISS_ENHANCE_CMDID, + + WMI_SET_REGDOMAIN_CMDID, + + WMI_SET_RSSI_FILTER_CMDID, }; enum wmi_mgmt_frame_type { @@ -1276,6 +1280,11 @@ struct wmi_snr_threshold_params_cmd { u8 reserved[3]; } __packed; +/* Don't report BSSs with signal (RSSI) below this threshold */ +struct wmi_set_rssi_filter_cmd { + s8 rssi; +} __packed; + enum wmi_preamble_policy { WMI_IGNORE_BARKER_IN_ERP = 0, WMI_FOLLOW_BARKER_IN_ERP, @@ -2592,6 +2601,7 @@ int ath6kl_wmi_add_wow_pattern_cmd(struct wmi *wmi, u8 if_idx, const u8 *mask); int ath6kl_wmi_del_wow_pattern_cmd(struct wmi *wmi, u8 if_idx, u16 list_id, u16 filter_id); +int ath6kl_wmi_set_rssi_filter_cmd(struct wmi *wmi, u8 if_idx, s8 rssi); int ath6kl_wmi_set_roam_lrssi_cmd(struct wmi *wmi, u8 lrssi); int ath6kl_wmi_ap_set_dtim_cmd(struct wmi *wmi, u8 if_idx, u32 dtim_period); int ath6kl_wmi_force_roam_cmd(struct wmi *wmi, const u8 *bssid); -- cgit v1.2.3-18-g5258 From c95dcb595dde97510dd4bc98c3112fe4d5dbd71f Mon Sep 17 00:00:00 2001 From: Aarthi Thiruvengadam Date: Tue, 10 Jul 2012 13:20:40 -0700 Subject: ath6kl: use custom MAC address for newly created interfaces Firmware and driver generate MAC addresses for the second and third interfaces. In addition to the existing algorithm, flip bit 7 of 5th octet. Since both firmware and driver individually generate the MAC addresses, introduce a new firmware capability bit to keep them compatible. Signed-off-by: Aarthi Thiruvengadam Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/cfg80211.c | 6 +++++- drivers/net/wireless/ath/ath6kl/core.h | 3 +++ 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index a5f3d6e5470..a624a0c5e5f 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -3523,9 +3523,13 @@ struct wireless_dev *ath6kl_interface_add(struct ath6kl *ar, const char *name, vif->htcap[IEEE80211_BAND_5GHZ].ht_enable = true; memcpy(ndev->dev_addr, ar->mac_addr, ETH_ALEN); - if (fw_vif_idx != 0) + if (fw_vif_idx != 0) { ndev->dev_addr[0] = (ndev->dev_addr[0] ^ (1 << fw_vif_idx)) | 0x2; + if (test_bit(ATH6KL_FW_CAPABILITY_CUSTOM_MAC_ADDR, + ar->fw_capabilities)) + ndev->dev_addr[4] ^= 0x80; + } init_netdev(ndev); diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h index a6f0d2c40d2..4e5edd9f16a 100644 --- a/drivers/net/wireless/ath/ath6kl/core.h +++ b/drivers/net/wireless/ath/ath6kl/core.h @@ -118,6 +118,9 @@ enum ath6kl_fw_capability { /* Firmware supports filtering BSS results by RSSI */ ATH6KL_FW_CAPABILITY_RSSI_SCAN_THOLD, + /* FW sets mac_addr[4] ^= 0x80 for newly created interfaces */ + ATH6KL_FW_CAPABILITY_CUSTOM_MAC_ADDR, + /* this needs to be last */ ATH6KL_FW_CAPABILITY_MAX, }; -- cgit v1.2.3-18-g5258 From 4aca81bfb0b13b927320448c6e4820ffb95f095b Mon Sep 17 00:00:00 2001 From: Pandiyarajan Pitchaimuthu Date: Wed, 11 Jul 2012 12:51:43 +0530 Subject: ath6kl: Make use of return value from ath6kl_diag_read() In ath6kl_read_fwlogs(), return value from ath6kl_diag_read()is not used to bail out in case of any errors in reading fw log. No real issue is observed because of this, reported by source code analyzer. kvalo: fix a long line warning Signed-off-by: Pandiyarajan Pitchaimuthu Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/main.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath6kl/main.c b/drivers/net/wireless/ath/ath6kl/main.c index c189e28e86a..6beffdee9a8 100644 --- a/drivers/net/wireless/ath/ath6kl/main.c +++ b/drivers/net/wireless/ath/ath6kl/main.c @@ -293,13 +293,17 @@ int ath6kl_read_fwlogs(struct ath6kl *ar) } address = TARG_VTOP(ar->target_type, debug_hdr_addr); - ath6kl_diag_read(ar, address, &debug_hdr, sizeof(debug_hdr)); + ret = ath6kl_diag_read(ar, address, &debug_hdr, sizeof(debug_hdr)); + if (ret) + goto out; address = TARG_VTOP(ar->target_type, le32_to_cpu(debug_hdr.dbuf_addr)); firstbuf = address; dropped = le32_to_cpu(debug_hdr.dropped); - ath6kl_diag_read(ar, address, &debug_buf, sizeof(debug_buf)); + ret = ath6kl_diag_read(ar, address, &debug_buf, sizeof(debug_buf)); + if (ret) + goto out; loop = 100; @@ -322,7 +326,8 @@ int ath6kl_read_fwlogs(struct ath6kl *ar) address = TARG_VTOP(ar->target_type, le32_to_cpu(debug_buf.next)); - ath6kl_diag_read(ar, address, &debug_buf, sizeof(debug_buf)); + ret = ath6kl_diag_read(ar, address, &debug_buf, + sizeof(debug_buf)); if (ret) goto out; -- cgit v1.2.3-18-g5258 From bf744f11788280bcbd9bb8ec62974274b72a75bf Mon Sep 17 00:00:00 2001 From: Bala Shanmugam Date: Tue, 17 Jul 2012 12:01:55 +0530 Subject: ath6kl: Add support for AR6004 hardware version 1.3 Add support for AR6004 hardware with version 1.3 and has id 0x31c8088a. Signed-off-by: Bala Shanmugam Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/core.h | 7 +++++++ drivers/net/wireless/ath/ath6kl/init.c | 20 ++++++++++++++++++++ drivers/net/wireless/ath/ath6kl/sdio.c | 3 +++ drivers/net/wireless/ath/ath6kl/usb.c | 3 +++ 4 files changed, 33 insertions(+) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h index 4e5edd9f16a..f16f6ba481d 100644 --- a/drivers/net/wireless/ath/ath6kl/core.h +++ b/drivers/net/wireless/ath/ath6kl/core.h @@ -192,6 +192,13 @@ enum ath6kl_hw_flags { #define AR6004_HW_1_2_DEFAULT_BOARD_DATA_FILE \ AR6004_HW_1_2_FW_DIR "/bdata.bin" +/* AR6004 1.3 definitions */ +#define AR6004_HW_1_3_VERSION 0x31c8088a +#define AR6004_HW_1_3_FW_DIR "ath6k/AR6004/hw1.3" +#define AR6004_HW_1_3_FIRMWARE_FILE "fw.ram.bin" +#define AR6004_HW_1_3_BOARD_DATA_FILE "ath6k/AR6004/hw1.3/bdata.bin" +#define AR6004_HW_1_3_DEFAULT_BOARD_DATA_FILE "ath6k/AR6004/hw1.3/bdata.bin" + /* Per STA data, used in AP mode */ #define STA_PS_AWAKE BIT(0) #define STA_PS_SLEEP BIT(1) diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c index f90b5db741c..8bd429975e4 100644 --- a/drivers/net/wireless/ath/ath6kl/init.c +++ b/drivers/net/wireless/ath/ath6kl/init.c @@ -142,6 +142,26 @@ static const struct ath6kl_hw hw_list[] = { .fw_board = AR6004_HW_1_2_BOARD_DATA_FILE, .fw_default_board = AR6004_HW_1_2_DEFAULT_BOARD_DATA_FILE, }, + { + .id = AR6004_HW_1_3_VERSION, + .name = "ar6004 hw 1.3", + .dataset_patch_addr = 0x437860, + .app_load_addr = 0x1234, + .board_ext_data_addr = 0x437000, + .reserved_ram_size = 7168, + .board_addr = 0x436400, + .refclk_hz = 40000000, + .uarttx_pin = 11, + .flags = ATH6KL_HW_FLAG_64BIT_RATES, + + .fw = { + .dir = AR6004_HW_1_3_FW_DIR, + .fw = AR6004_HW_1_3_FIRMWARE_FILE, + }, + + .fw_board = AR6004_HW_1_3_BOARD_DATA_FILE, + .fw_default_board = AR6004_HW_1_3_DEFAULT_BOARD_DATA_FILE, + }, }; /* diff --git a/drivers/net/wireless/ath/ath6kl/sdio.c b/drivers/net/wireless/ath/ath6kl/sdio.c index 05b95405f7b..65e99833151 100644 --- a/drivers/net/wireless/ath/ath6kl/sdio.c +++ b/drivers/net/wireless/ath/ath6kl/sdio.c @@ -1462,3 +1462,6 @@ MODULE_FIRMWARE(AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE); MODULE_FIRMWARE(AR6004_HW_1_2_FW_DIR "/" AR6004_HW_1_2_FIRMWARE_FILE); MODULE_FIRMWARE(AR6004_HW_1_2_BOARD_DATA_FILE); MODULE_FIRMWARE(AR6004_HW_1_2_DEFAULT_BOARD_DATA_FILE); +MODULE_FIRMWARE(AR6004_HW_1_3_FW_DIR "/" AR6004_HW_1_3_FIRMWARE_FILE); +MODULE_FIRMWARE(AR6004_HW_1_3_BOARD_DATA_FILE); +MODULE_FIRMWARE(AR6004_HW_1_3_DEFAULT_BOARD_DATA_FILE); diff --git a/drivers/net/wireless/ath/ath6kl/usb.c b/drivers/net/wireless/ath/ath6kl/usb.c index 3740c3d6ab8..4aa97aa6611 100644 --- a/drivers/net/wireless/ath/ath6kl/usb.c +++ b/drivers/net/wireless/ath/ath6kl/usb.c @@ -1220,3 +1220,6 @@ MODULE_FIRMWARE(AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE); MODULE_FIRMWARE(AR6004_HW_1_2_FIRMWARE_FILE); MODULE_FIRMWARE(AR6004_HW_1_2_BOARD_DATA_FILE); MODULE_FIRMWARE(AR6004_HW_1_2_DEFAULT_BOARD_DATA_FILE); +MODULE_FIRMWARE(AR6004_HW_1_3_FW_DIR "/" AR6004_HW_1_3_FIRMWARE_FILE); +MODULE_FIRMWARE(AR6004_HW_1_3_BOARD_DATA_FILE); +MODULE_FIRMWARE(AR6004_HW_1_3_DEFAULT_BOARD_DATA_FILE); -- cgit v1.2.3-18-g5258 From 279b2862ee6ba9ee950c02044142f8ea137c302e Mon Sep 17 00:00:00 2001 From: Thomas Pedersen Date: Tue, 17 Jul 2012 19:39:55 -0700 Subject: ath6kl: support TX error rate notification The ath6kl firmware can monitor a connection and report when a certain TX failure threshold is crossed. Support this configuration and event reporting on compatible firmwares. Signed-off-by: Thomas Pedersen Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/cfg80211.c | 22 ++++++++++++++ drivers/net/wireless/ath/ath6kl/core.h | 4 +++ drivers/net/wireless/ath/ath6kl/wmi.c | 47 ++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath6kl/wmi.h | 35 ++++++++++++++++++++++ 4 files changed, 108 insertions(+) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index a624a0c5e5f..0194617ff30 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -3326,6 +3326,27 @@ static int ath6kl_cfg80211_set_bitrate(struct wiphy *wiphy, mask); } +static int ath6kl_cfg80211_set_txe_config(struct wiphy *wiphy, + struct net_device *dev, + u32 rate, u32 pkts, u32 intvl) +{ + struct ath6kl *ar = ath6kl_priv(dev); + struct ath6kl_vif *vif = netdev_priv(dev); + + if (vif->nw_type != INFRA_NETWORK || + !test_bit(ATH6KL_FW_CAPABILITY_TX_ERR_NOTIFY, ar->fw_capabilities)) + return -EOPNOTSUPP; + + if (vif->sme_state != SME_CONNECTED) + return -ENOTCONN; + + /* save this since the firmware won't report the interval */ + vif->txe_intvl = intvl; + + return ath6kl_wmi_set_txe_notify(ar->wmi, vif->fw_vif_idx, + rate, pkts, intvl); +} + static const struct ieee80211_txrx_stypes ath6kl_mgmt_stypes[NUM_NL80211_IFTYPES] = { [NL80211_IFTYPE_STATION] = { @@ -3392,6 +3413,7 @@ static struct cfg80211_ops ath6kl_cfg80211_ops = { .sched_scan_start = ath6kl_cfg80211_sscan_start, .sched_scan_stop = ath6kl_cfg80211_sscan_stop, .set_bitrate_mask = ath6kl_cfg80211_set_bitrate, + .set_cqm_txe_config = ath6kl_cfg80211_set_txe_config, }; void ath6kl_cfg80211_stop(struct ath6kl_vif *vif) diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h index f16f6ba481d..a754a153cc8 100644 --- a/drivers/net/wireless/ath/ath6kl/core.h +++ b/drivers/net/wireless/ath/ath6kl/core.h @@ -121,6 +121,9 @@ enum ath6kl_fw_capability { /* FW sets mac_addr[4] ^= 0x80 for newly created interfaces */ ATH6KL_FW_CAPABILITY_CUSTOM_MAC_ADDR, + /* Firmware supports TX error rate notification */ + ATH6KL_FW_CAPABILITY_TX_ERR_NOTIFY, + /* this needs to be last */ ATH6KL_FW_CAPABILITY_MAX, }; @@ -593,6 +596,7 @@ struct ath6kl_vif { u16 assoc_bss_beacon_int; u16 listen_intvl_t; u16 bmiss_time_t; + u32 txe_intvl; u16 bg_scan_period; u8 assoc_bss_dtim_period; struct net_device_stats net_stats; diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index 9673f277817..4762fa57063 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -1531,6 +1531,50 @@ static int ath6kl_wmi_cac_event_rx(struct wmi *wmi, u8 *datap, int len, return 0; } +static int ath6kl_wmi_txe_notify_event_rx(struct wmi *wmi, u8 *datap, int len, + struct ath6kl_vif *vif) +{ + struct wmi_txe_notify_event *ev; + u32 rate, pkts; + + if (len < sizeof(*ev)) + return -EINVAL; + + if (vif->sme_state != SME_CONNECTED) + return -ENOTCONN; + + ev = (struct wmi_txe_notify_event *) datap; + rate = le32_to_cpu(ev->rate); + pkts = le32_to_cpu(ev->pkts); + + ath6kl_dbg(ATH6KL_DBG_WMI, "TXE notify event: peer %pM rate %d% pkts %d intvl %ds\n", + vif->bssid, rate, pkts, vif->txe_intvl); + + cfg80211_cqm_txe_notify(vif->ndev, vif->bssid, pkts, + rate, vif->txe_intvl, GFP_KERNEL); + + return 0; +} + +int ath6kl_wmi_set_txe_notify(struct wmi *wmi, u8 idx, + u32 rate, u32 pkts, u32 intvl) +{ + struct sk_buff *skb; + struct wmi_txe_notify_cmd *cmd; + + skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_txe_notify_cmd *) skb->data; + cmd->rate = cpu_to_le32(rate); + cmd->pkts = cpu_to_le32(pkts); + cmd->intvl = cpu_to_le32(intvl); + + return ath6kl_wmi_cmd_send(wmi, idx, skb, WMI_SET_TXE_NOTIFY_CMDID, + NO_SYNC_WMIFLAG); +} + int ath6kl_wmi_set_rssi_filter_cmd(struct wmi *wmi, u8 if_idx, s8 rssi) { struct sk_buff *skb; @@ -3768,6 +3812,9 @@ static int ath6kl_wmi_proc_events_vif(struct wmi *wmi, u16 if_idx, u16 cmd_id, case WMI_RX_ACTION_EVENTID: ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_RX_ACTION_EVENTID\n"); return ath6kl_wmi_rx_action_event_rx(wmi, datap, len, vif); + case WMI_TXE_NOTIFY_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TXE_NOTIFY_EVENTID\n"); + return ath6kl_wmi_txe_notify_event_rx(wmi, datap, len, vif); default: ath6kl_dbg(ATH6KL_DBG_WMI, "unknown cmd id 0x%x\n", cmd_id); return -EINVAL; diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h index b5deaffb79e..8e8846f1b1a 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.h +++ b/drivers/net/wireless/ath/ath6kl/wmi.h @@ -632,6 +632,12 @@ enum wmi_cmd_id { WMI_SET_REGDOMAIN_CMDID, WMI_SET_RSSI_FILTER_CMDID, + + WMI_SET_KEEP_ALIVE_EXT, + + WMI_VOICE_DETECTION_ENABLE_CMDID, + + WMI_SET_TXE_NOTIFY_CMDID, }; enum wmi_mgmt_frame_type { @@ -1464,6 +1470,20 @@ enum wmi_event_id { WMI_P2P_CAPABILITIES_EVENTID, WMI_RX_ACTION_EVENTID, WMI_P2P_INFO_EVENTID, + + /* WPS Events */ + WMI_WPS_GET_STATUS_EVENTID, + WMI_WPS_PROFILE_EVENTID, + + /* more P2P events */ + WMI_NOA_INFO_EVENTID, + WMI_OPPPS_INFO_EVENTID, + WMI_PORT_STATUS_EVENTID, + + /* 802.11w */ + WMI_GET_RSN_CAP_EVENTID, + + WMI_TXE_NOTIFY_EVENTID, }; struct wmi_ready_event_2 { @@ -2096,6 +2116,19 @@ struct wmi_del_wow_pattern_cmd { __le16 filter_id; } __packed; +/* WMI_SET_TXE_NOTIFY_CMDID */ +struct wmi_txe_notify_cmd { + __le32 rate; + __le32 pkts; + __le32 intvl; +} __packed; + +/* WMI_TXE_NOTIFY_EVENTID */ +struct wmi_txe_notify_event { + __le32 rate; + __le32 pkts; +} __packed; + /* WMI_SET_AKMP_PARAMS_CMD */ struct wmi_pmkid { @@ -2610,6 +2643,8 @@ int ath6kl_wmi_mcast_filter_cmd(struct wmi *wmi, u8 if_idx, bool mc_all_on); int ath6kl_wmi_add_del_mcast_filter_cmd(struct wmi *wmi, u8 if_idx, u8 *filter, bool add_filter); int ath6kl_wmi_sta_bmiss_enhance_cmd(struct wmi *wmi, u8 if_idx, bool enable); +int ath6kl_wmi_set_txe_notify(struct wmi *wmi, u8 idx, + u32 rate, u32 pkts, u32 intvl); /* AP mode uAPSD */ int ath6kl_wmi_ap_set_apsd(struct wmi *wmi, u8 if_idx, u8 enable); -- cgit v1.2.3-18-g5258 From c8c72b74e289a3439e9c2438ca675c5a746bf929 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Thu, 19 Jul 2012 16:00:40 +0300 Subject: ath6kl: move ath6kl_wmi_startscan_cmd() To make it easier to refactor the scan commands move ath6kl_wmi_startscan_cmd() before the beginscan function. No functional changes. Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/wmi.c | 88 +++++++++++++++++------------------ 1 file changed, 44 insertions(+), 44 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index 4762fa57063..a9d7e000017 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -1895,22 +1895,22 @@ int ath6kl_wmi_disconnect_cmd(struct wmi *wmi, u8 if_idx) return ret; } -int ath6kl_wmi_beginscan_cmd(struct wmi *wmi, u8 if_idx, +/* ath6kl_wmi_start_scan_cmd is to be deprecated. Use + * ath6kl_wmi_begin_scan_cmd instead. The new function supports P2P + * mgmt operations using station interface. + */ +int ath6kl_wmi_startscan_cmd(struct wmi *wmi, u8 if_idx, enum wmi_scan_type scan_type, u32 force_fgscan, u32 is_legacy, u32 home_dwell_time, u32 force_scan_interval, - s8 num_chan, u16 *ch_list, u32 no_cck, u32 *rates) + s8 num_chan, u16 *ch_list) { - struct ieee80211_supported_band *sband; struct sk_buff *skb; - struct wmi_begin_scan_cmd *sc; - s8 size, *supp_rates; - int i, band, ret; - struct ath6kl *ar = wmi->parent_dev; - int num_rates; - u32 ratemask; + struct wmi_start_scan_cmd *sc; + s8 size; + int i, ret; - size = sizeof(struct wmi_begin_scan_cmd); + size = sizeof(struct wmi_start_scan_cmd); if ((scan_type != WMI_LONG_SCAN) && (scan_type != WMI_SHORT_SCAN)) return -EINVAL; @@ -1925,59 +1925,39 @@ int ath6kl_wmi_beginscan_cmd(struct wmi *wmi, u8 if_idx, if (!skb) return -ENOMEM; - sc = (struct wmi_begin_scan_cmd *) skb->data; + sc = (struct wmi_start_scan_cmd *) skb->data; sc->scan_type = scan_type; sc->force_fg_scan = cpu_to_le32(force_fgscan); sc->is_legacy = cpu_to_le32(is_legacy); sc->home_dwell_time = cpu_to_le32(home_dwell_time); sc->force_scan_intvl = cpu_to_le32(force_scan_interval); - sc->no_cck = cpu_to_le32(no_cck); sc->num_ch = num_chan; - for (band = 0; band < IEEE80211_NUM_BANDS; band++) { - sband = ar->wiphy->bands[band]; - - if (!sband) - continue; - - ratemask = rates[band]; - supp_rates = sc->supp_rates[band].rates; - num_rates = 0; - - for (i = 0; i < sband->n_bitrates; i++) { - if ((BIT(i) & ratemask) == 0) - continue; /* skip rate */ - supp_rates[num_rates++] = - (u8) (sband->bitrates[i].bitrate / 5); - } - sc->supp_rates[band].nrates = num_rates; - } - for (i = 0; i < num_chan; i++) sc->ch_list[i] = cpu_to_le16(ch_list[i]); - ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_BEGIN_SCAN_CMDID, + ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_START_SCAN_CMDID, NO_SYNC_WMIFLAG); return ret; } -/* ath6kl_wmi_start_scan_cmd is to be deprecated. Use - * ath6kl_wmi_begin_scan_cmd instead. The new function supports P2P - * mgmt operations using station interface. - */ -int ath6kl_wmi_startscan_cmd(struct wmi *wmi, u8 if_idx, +int ath6kl_wmi_beginscan_cmd(struct wmi *wmi, u8 if_idx, enum wmi_scan_type scan_type, u32 force_fgscan, u32 is_legacy, u32 home_dwell_time, u32 force_scan_interval, - s8 num_chan, u16 *ch_list) + s8 num_chan, u16 *ch_list, u32 no_cck, u32 *rates) { + struct ieee80211_supported_band *sband; struct sk_buff *skb; - struct wmi_start_scan_cmd *sc; - s8 size; - int i, ret; + struct wmi_begin_scan_cmd *sc; + s8 size, *supp_rates; + int i, band, ret; + struct ath6kl *ar = wmi->parent_dev; + int num_rates; + u32 ratemask; - size = sizeof(struct wmi_start_scan_cmd); + size = sizeof(struct wmi_begin_scan_cmd); if ((scan_type != WMI_LONG_SCAN) && (scan_type != WMI_SHORT_SCAN)) return -EINVAL; @@ -1992,18 +1972,38 @@ int ath6kl_wmi_startscan_cmd(struct wmi *wmi, u8 if_idx, if (!skb) return -ENOMEM; - sc = (struct wmi_start_scan_cmd *) skb->data; + sc = (struct wmi_begin_scan_cmd *) skb->data; sc->scan_type = scan_type; sc->force_fg_scan = cpu_to_le32(force_fgscan); sc->is_legacy = cpu_to_le32(is_legacy); sc->home_dwell_time = cpu_to_le32(home_dwell_time); sc->force_scan_intvl = cpu_to_le32(force_scan_interval); + sc->no_cck = cpu_to_le32(no_cck); sc->num_ch = num_chan; + for (band = 0; band < IEEE80211_NUM_BANDS; band++) { + sband = ar->wiphy->bands[band]; + + if (!sband) + continue; + + ratemask = rates[band]; + supp_rates = sc->supp_rates[band].rates; + num_rates = 0; + + for (i = 0; i < sband->n_bitrates; i++) { + if ((BIT(i) & ratemask) == 0) + continue; /* skip rate */ + supp_rates[num_rates++] = + (u8) (sband->bitrates[i].bitrate / 5); + } + sc->supp_rates[band].nrates = num_rates; + } + for (i = 0; i < num_chan; i++) sc->ch_list[i] = cpu_to_le16(ch_list[i]); - ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_START_SCAN_CMDID, + ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_BEGIN_SCAN_CMDID, NO_SYNC_WMIFLAG); return ret; -- cgit v1.2.3-18-g5258 From 11f0bfcf73f4a90c8c0e0b244a272379b376adb1 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Thu, 19 Jul 2012 16:00:48 +0300 Subject: ath6kl: refactor wmi scan command ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX was checked in cfg80211.c which is a bit awkward when adding more callsites to the scan functions. Refactor the code to wmi.c so that it's transparent to the callers. Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/cfg80211.c | 31 ++++++++---------------------- drivers/net/wireless/ath/ath6kl/wmi.c | 25 +++++++++++++++++++----- drivers/net/wireless/ath/ath6kl/wmi.h | 5 ----- 3 files changed, 28 insertions(+), 33 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index 0194617ff30..4f538f0027f 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -1031,30 +1031,15 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, vif->scan_req = request; - if (test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX, - ar->fw_capabilities)) { - /* - * If capable of doing P2P mgmt operations using - * station interface, send additional information like - * supported rates to advertise and xmit rates for - * probe requests - */ - ret = ath6kl_wmi_beginscan_cmd(ar->wmi, vif->fw_vif_idx, - WMI_LONG_SCAN, force_fg_scan, - false, 0, - ATH6KL_FG_SCAN_INTERVAL, - n_channels, channels, - request->no_cck, - request->rates); - } else { - ret = ath6kl_wmi_startscan_cmd(ar->wmi, vif->fw_vif_idx, - WMI_LONG_SCAN, force_fg_scan, - false, 0, - ATH6KL_FG_SCAN_INTERVAL, - n_channels, channels); - } + ret = ath6kl_wmi_beginscan_cmd(ar->wmi, vif->fw_vif_idx, + WMI_LONG_SCAN, force_fg_scan, + false, 0, + ATH6KL_FG_SCAN_INTERVAL, + n_channels, channels, + request->no_cck, + request->rates); if (ret) { - ath6kl_err("wmi_startscan_cmd failed\n"); + ath6kl_err("failed to start scan: %d\n", ret); vif->scan_req = NULL; } diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index a9d7e000017..05cc871f824 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -1899,11 +1899,12 @@ int ath6kl_wmi_disconnect_cmd(struct wmi *wmi, u8 if_idx) * ath6kl_wmi_begin_scan_cmd instead. The new function supports P2P * mgmt operations using station interface. */ -int ath6kl_wmi_startscan_cmd(struct wmi *wmi, u8 if_idx, - enum wmi_scan_type scan_type, - u32 force_fgscan, u32 is_legacy, - u32 home_dwell_time, u32 force_scan_interval, - s8 num_chan, u16 *ch_list) +static int ath6kl_wmi_startscan_cmd(struct wmi *wmi, u8 if_idx, + enum wmi_scan_type scan_type, + u32 force_fgscan, u32 is_legacy, + u32 home_dwell_time, + u32 force_scan_interval, + s8 num_chan, u16 *ch_list) { struct sk_buff *skb; struct wmi_start_scan_cmd *sc; @@ -1942,6 +1943,11 @@ int ath6kl_wmi_startscan_cmd(struct wmi *wmi, u8 if_idx, return ret; } +/* + * beginscan supports (compared to old startscan) P2P mgmt operations using + * station interface, send additional information like supported rates to + * advertise and xmit rates for probe requests + */ int ath6kl_wmi_beginscan_cmd(struct wmi *wmi, u8 if_idx, enum wmi_scan_type scan_type, u32 force_fgscan, u32 is_legacy, @@ -1957,6 +1963,15 @@ int ath6kl_wmi_beginscan_cmd(struct wmi *wmi, u8 if_idx, int num_rates; u32 ratemask; + if (!test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX, + ar->fw_capabilities)) { + return ath6kl_wmi_startscan_cmd(wmi, if_idx, + scan_type, force_fgscan, + is_legacy, home_dwell_time, + force_scan_interval, + num_chan, ch_list); + } + size = sizeof(struct wmi_begin_scan_cmd); if ((scan_type != WMI_LONG_SCAN) && (scan_type != WMI_SHORT_SCAN)) diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h index 8e8846f1b1a..5166a8e6492 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.h +++ b/drivers/net/wireless/ath/ath6kl/wmi.h @@ -2547,11 +2547,6 @@ int ath6kl_wmi_connect_cmd(struct wmi *wmi, u8 if_idx, int ath6kl_wmi_reconnect_cmd(struct wmi *wmi, u8 if_idx, u8 *bssid, u16 channel); int ath6kl_wmi_disconnect_cmd(struct wmi *wmi, u8 if_idx); -int ath6kl_wmi_startscan_cmd(struct wmi *wmi, u8 if_idx, - enum wmi_scan_type scan_type, - u32 force_fgscan, u32 is_legacy, - u32 home_dwell_time, u32 force_scan_interval, - s8 num_chan, u16 *ch_list); int ath6kl_wmi_beginscan_cmd(struct wmi *wmi, u8 if_idx, enum wmi_scan_type scan_type, -- cgit v1.2.3-18-g5258 From 84841ba29b1f55fb09703408477f097c7f8952f8 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Thu, 19 Jul 2012 16:00:56 +0300 Subject: ath6kl: add support for changing contry code To make it possible to change the country code from user space via nl80211 add handler for reg_notifier. The feature is only enabled when built time option CONFIG_ATH6KL_REGDOMAIN is enabled, which again depends on CFG80211_CERTIFICATION_ONUS for certication purposes. Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/Kconfig | 9 ++++++ drivers/net/wireless/ath/ath6kl/cfg80211.c | 47 ++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath6kl/core.h | 3 ++ drivers/net/wireless/ath/ath6kl/wmi.c | 17 +++++++++++ drivers/net/wireless/ath/ath6kl/wmi.h | 6 ++++ 5 files changed, 82 insertions(+) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath6kl/Kconfig b/drivers/net/wireless/ath/ath6kl/Kconfig index d755a5e7ed2..26c4b722085 100644 --- a/drivers/net/wireless/ath/ath6kl/Kconfig +++ b/drivers/net/wireless/ath/ath6kl/Kconfig @@ -30,3 +30,12 @@ config ATH6KL_DEBUG depends on ATH6KL ---help--- Enables debug support + +config ATH6KL_REGDOMAIN + bool "Atheros ath6kl regdomain support" + depends on ATH6KL + depends on CFG80211_CERTIFICATION_ONUS + ---help--- + Enabling this makes it possible to change the regdomain in + the firmware. This can be only enabled if regulatory requirements + are taken into account. diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index 4f538f0027f..f620af5e0db 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -3458,6 +3458,49 @@ void ath6kl_cfg80211_stop_all(struct ath6kl *ar) ath6kl_cfg80211_stop(vif); } +static int ath6kl_cfg80211_reg_notify(struct wiphy *wiphy, + struct regulatory_request *request) +{ + struct ath6kl *ar = wiphy_priv(wiphy); + u32 rates[IEEE80211_NUM_BANDS]; + int ret, i; + + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, + "cfg reg_notify %c%c%s%s initiator %d\n", + request->alpha2[0], request->alpha2[1], + request->intersect ? " intersect" : "", + request->processed ? " processed" : "", + request->initiator); + + ret = ath6kl_wmi_set_regdomain_cmd(ar->wmi, request->alpha2); + if (ret) { + ath6kl_err("failed to set regdomain: %d\n", ret); + return ret; + } + + /* + * Firmware will apply the regdomain change only after a scan is + * issued and it will send a WMI_REGDOMAIN_EVENTID when it has been + * changed. + */ + + for (i = 0; i < IEEE80211_NUM_BANDS; i++) + if (wiphy->bands[i]) + rates[i] = (1 << wiphy->bands[i]->n_bitrates) - 1; + + + ret = ath6kl_wmi_beginscan_cmd(ar->wmi, 0, WMI_LONG_SCAN, false, + false, 0, ATH6KL_FG_SCAN_INTERVAL, + 0, NULL, false, rates); + if (ret) { + ath6kl_err("failed to start scan for a regdomain change: %d\n", + ret); + return ret; + } + + return 0; +} + static int ath6kl_cfg80211_vif_init(struct ath6kl_vif *vif) { vif->aggr_cntxt = aggr_init(vif); @@ -3590,6 +3633,10 @@ int ath6kl_cfg80211_init(struct ath6kl *ar) BIT(NL80211_IFTYPE_P2P_CLIENT); } + if (config_enabled(CONFIG_ATH6KL_REGDOMAIN) && + test_bit(ATH6KL_FW_CAPABILITY_REGDOMAIN, ar->fw_capabilities)) + wiphy->reg_notifier = ath6kl_cfg80211_reg_notify; + /* max num of ssids that can be probed during scanning */ wiphy->max_scan_ssids = MAX_PROBED_SSIDS; diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h index a754a153cc8..eb86b315adf 100644 --- a/drivers/net/wireless/ath/ath6kl/core.h +++ b/drivers/net/wireless/ath/ath6kl/core.h @@ -124,6 +124,9 @@ enum ath6kl_fw_capability { /* Firmware supports TX error rate notification */ ATH6KL_FW_CAPABILITY_TX_ERR_NOTIFY, + /* supports WMI_SET_REGDOMAIN_CMDID command */ + ATH6KL_FW_CAPABILITY_REGDOMAIN, + /* this needs to be last */ ATH6KL_FW_CAPABILITY_MAX, }; diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index 05cc871f824..cf91348fdbd 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -3216,6 +3216,23 @@ int ath6kl_wmi_sta_bmiss_enhance_cmd(struct wmi *wmi, u8 if_idx, bool enhance) return ret; } +int ath6kl_wmi_set_regdomain_cmd(struct wmi *wmi, const char *alpha2) +{ + struct sk_buff *skb; + struct wmi_set_regdomain_cmd *cmd; + + skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_set_regdomain_cmd *) skb->data; + memcpy(cmd->iso_name, alpha2, 2); + + return ath6kl_wmi_cmd_send(wmi, 0, skb, + WMI_SET_REGDOMAIN_CMDID, + NO_SYNC_WMIFLAG); +} + s32 ath6kl_wmi_get_rate(s8 rate_index) { if (rate_index == RATE_AUTO) diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h index 5166a8e6492..1d510bae155 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.h +++ b/drivers/net/wireless/ath/ath6kl/wmi.h @@ -1042,6 +1042,11 @@ struct wmi_sta_bmiss_enhance_cmd { u8 enable; } __packed; +struct wmi_set_regdomain_cmd { + u8 length; + u8 iso_name[2]; +} __packed; + /* WMI_SET_POWER_MODE_CMDID */ enum wmi_power_mode { REC_POWER = 0x01, @@ -2640,6 +2645,7 @@ int ath6kl_wmi_add_del_mcast_filter_cmd(struct wmi *wmi, u8 if_idx, int ath6kl_wmi_sta_bmiss_enhance_cmd(struct wmi *wmi, u8 if_idx, bool enable); int ath6kl_wmi_set_txe_notify(struct wmi *wmi, u8 idx, u32 rate, u32 pkts, u32 intvl); +int ath6kl_wmi_set_regdomain_cmd(struct wmi *wmi, const char *alpha2); /* AP mode uAPSD */ int ath6kl_wmi_ap_set_apsd(struct wmi *wmi, u8 if_idx, u8 enable); -- cgit v1.2.3-18-g5258 From f8c0305383121817c77d400c788d82ca1a74582c Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Thu, 12 Jul 2012 12:13:12 +0300 Subject: ath6kl: fix incorrect use of IEEE80211_NUM_BANDS ath6kl was incorrectly assuming that IEEE80211_NUM_BANDS will always be 2 and used that also in the firmware WMI interface definitions. But after the support for 60 GHz was added to cfg80211 IEEE80211_NUM_BANDS changed to 3 and this can cause all sort of problems, possibly even memory corruption. I only found this during code review and didn't notice any bugs, but I'm sure there are a few lurking somewhere. To fix this rename unused A_NUM_BANDS to ATH6KL_NUM_BANDS, which is always defined to be 2, and use that in WMI. Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/wmi.c | 12 ++++++++---- drivers/net/wireless/ath/ath6kl/wmi.h | 4 ++-- 2 files changed, 10 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index cf91348fdbd..d485a7c3428 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -2695,11 +2695,13 @@ static int ath6kl_set_bitrate_mask64(struct wmi *wmi, u8 if_idx, { struct sk_buff *skb; int ret, mode, band; - u64 mcsrate, ratemask[IEEE80211_NUM_BANDS]; + u64 mcsrate, ratemask[ATH6KL_NUM_BANDS]; struct wmi_set_tx_select_rates64_cmd *cmd; memset(&ratemask, 0, sizeof(ratemask)); - for (band = 0; band < IEEE80211_NUM_BANDS; band++) { + + /* only check 2.4 and 5 GHz bands, skip the rest */ + for (band = 0; band <= IEEE80211_BAND_5GHZ; band++) { /* copy legacy rate mask */ ratemask[band] = mask->control[band].legacy; if (band == IEEE80211_BAND_5GHZ) @@ -2745,11 +2747,13 @@ static int ath6kl_set_bitrate_mask32(struct wmi *wmi, u8 if_idx, { struct sk_buff *skb; int ret, mode, band; - u32 mcsrate, ratemask[IEEE80211_NUM_BANDS]; + u32 mcsrate, ratemask[ATH6KL_NUM_BANDS]; struct wmi_set_tx_select_rates32_cmd *cmd; memset(&ratemask, 0, sizeof(ratemask)); - for (band = 0; band < IEEE80211_NUM_BANDS; band++) { + + /* only check 2.4 and 5 GHz bands, skip the rest */ + for (band = 0; band <= IEEE80211_BAND_5GHZ; band++) { /* copy legacy rate mask */ ratemask[band] = mask->control[band].legacy; if (band == IEEE80211_BAND_5GHZ) diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h index 1d510bae155..9c73ae73f26 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.h +++ b/drivers/net/wireless/ath/ath6kl/wmi.h @@ -48,7 +48,7 @@ #define A_BAND_24GHZ 0 #define A_BAND_5GHZ 1 -#define A_NUM_BANDS 2 +#define ATH6KL_NUM_BANDS 2 /* in ms */ #define WMI_IMPLICIT_PSTREAM_INACTIVITY_INT 5000 @@ -853,7 +853,7 @@ struct wmi_begin_scan_cmd { u8 scan_type; /* Supported rates to advertise in the probe request frames */ - struct wmi_supp_rates supp_rates[IEEE80211_NUM_BANDS]; + struct wmi_supp_rates supp_rates[ATH6KL_NUM_BANDS]; /* how many channels follow */ u8 num_ch; -- cgit v1.2.3-18-g5258 From fd4377b6bacc0f04bb1898f3ccab9510172a7561 Mon Sep 17 00:00:00 2001 From: Thomas Pedersen Date: Thu, 9 Aug 2012 17:32:33 -0700 Subject: ath6kl: configure wow filters per-vif Only WoW filters for the first vif were being set, causing failures to wake up on any concurrent connected vifs. Handle all per-vif suspend and resume tasks. Since cfg80211 issues user wow filters on a per-wiphy basis, set any custom filters on all connected vifs. Starting WoW in firmware and setting host sleep mode is still handled on a global per-phy level. The first vif is always used for bookkeeping regardless of whether it is connected or not. WoW is cancelled if no connected vifs are found. No firmware capability bits or API bump is needed for this patch, as setting filters for vifs with index > 0 will simply overwrite the index 0 filters in the current implementation. While not correct, this is identical to the existing behavior. kvalo: fix a checkpatch warning in ath6kl_wow_resume() Signed-off-by: Thomas Pedersen Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/cfg80211.c | 145 ++++++++++++++++++----------- 1 file changed, 93 insertions(+), 52 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index f620af5e0db..e8b9c1e2a04 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -2092,33 +2092,16 @@ static int ath6kl_cfg80211_host_sleep(struct ath6kl *ar, struct ath6kl_vif *vif) return ret; } -static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) +static int ath6kl_wow_suspend_vif(struct ath6kl_vif *vif, + struct cfg80211_wowlan *wow, u32 *filter) { + struct ath6kl *ar = vif->ar; struct in_device *in_dev; struct in_ifaddr *ifa; - struct ath6kl_vif *vif; int ret; - u32 filter = 0; u16 i, bmiss_time; - u8 index = 0; __be32 ips[MAX_IP_ADDRS]; - - /* The FW currently can't support multi-vif WoW properly. */ - if (ar->num_vif > 1) - return -EIO; - - vif = ath6kl_vif_first(ar); - if (!vif) - return -EIO; - - if (!ath6kl_cfg80211_ready(vif)) - return -EIO; - - if (!test_bit(CONNECTED, &vif->flags)) - return -ENOTCONN; - - if (wow && (wow->n_patterns > WOW_MAX_FILTERS_PER_LIST)) - return -EINVAL; + u8 index = 0; if (!test_bit(NETDEV_MCAST_ALL_ON, &vif->flags) && test_bit(ATH6KL_FW_CAPABILITY_WOW_MULTICAST_FILTER, @@ -2140,7 +2123,7 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) * the user. */ if (wow) - ret = ath6kl_wow_usr(ar, vif, wow, &filter); + ret = ath6kl_wow_usr(ar, vif, wow, filter); else if (vif->nw_type == AP_NETWORK) ret = ath6kl_wow_ap(ar, vif); else @@ -2175,12 +2158,10 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) return ret; } - ar->state = ATH6KL_STATE_SUSPENDING; - /* Setup own IP addr for ARP agent. */ in_dev = __in_dev_get_rtnl(vif->ndev); if (!in_dev) - goto skip_arp; + return 0; ifa = in_dev->ifa_list; memset(&ips, 0, sizeof(ips)); @@ -2203,41 +2184,61 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) return ret; } -skip_arp: - ret = ath6kl_wmi_set_wow_mode_cmd(ar->wmi, vif->fw_vif_idx, + return ret; +} + +static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) +{ + struct ath6kl_vif *first_vif, *vif; + int ret = 0; + u32 filter = 0; + bool connected = false; + + /* enter / leave wow suspend on first vif always */ + first_vif = ath6kl_vif_first(ar); + if (WARN_ON(unlikely(!first_vif)) || + !ath6kl_cfg80211_ready(first_vif)) + return -EIO; + + if (wow && (wow->n_patterns > WOW_MAX_FILTERS_PER_LIST)) + return -EINVAL; + + /* install filters for each connected vif */ + spin_lock_bh(&ar->list_lock); + list_for_each_entry(vif, &ar->vif_list, list) { + if (!test_bit(CONNECTED, &vif->flags) || + !ath6kl_cfg80211_ready(vif)) + continue; + connected = true; + + ret = ath6kl_wow_suspend_vif(vif, wow, &filter); + if (ret) + break; + } + spin_unlock_bh(&ar->list_lock); + + if (!connected) + return -ENOTCONN; + else if (ret) + return ret; + + ar->state = ATH6KL_STATE_SUSPENDING; + + ret = ath6kl_wmi_set_wow_mode_cmd(ar->wmi, first_vif->fw_vif_idx, ATH6KL_WOW_MODE_ENABLE, filter, WOW_HOST_REQ_DELAY); if (ret) return ret; - ret = ath6kl_cfg80211_host_sleep(ar, vif); - if (ret) - return ret; - - return 0; + return ath6kl_cfg80211_host_sleep(ar, first_vif); } -static int ath6kl_wow_resume(struct ath6kl *ar) +static int ath6kl_wow_resume_vif(struct ath6kl_vif *vif) { - struct ath6kl_vif *vif; + struct ath6kl *ar = vif->ar; int ret; - vif = ath6kl_vif_first(ar); - if (!vif) - return -EIO; - - ar->state = ATH6KL_STATE_RESUMING; - - ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx, - ATH6KL_HOST_MODE_AWAKE); - if (ret) { - ath6kl_warn("Failed to configure host sleep mode for wow resume: %d\n", - ret); - ar->state = ATH6KL_STATE_WOW; - return ret; - } - if (vif->nw_type != AP_NETWORK) { ret = ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0); @@ -2255,13 +2256,11 @@ static int ath6kl_wow_resume(struct ath6kl *ar) return ret; } - ar->state = ATH6KL_STATE_ON; - if (!test_bit(NETDEV_MCAST_ALL_OFF, &vif->flags) && test_bit(ATH6KL_FW_CAPABILITY_WOW_MULTICAST_FILTER, ar->fw_capabilities)) { ret = ath6kl_wmi_mcast_filter_cmd(vif->ar->wmi, - vif->fw_vif_idx, true); + vif->fw_vif_idx, true); if (ret) return ret; } @@ -2271,6 +2270,48 @@ static int ath6kl_wow_resume(struct ath6kl *ar) return 0; } +static int ath6kl_wow_resume(struct ath6kl *ar) +{ + struct ath6kl_vif *vif; + int ret; + + vif = ath6kl_vif_first(ar); + if (WARN_ON(unlikely(!vif)) || + !ath6kl_cfg80211_ready(vif)) + return -EIO; + + ar->state = ATH6KL_STATE_RESUMING; + + ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx, + ATH6KL_HOST_MODE_AWAKE); + if (ret) { + ath6kl_warn("Failed to configure host sleep mode for wow resume: %d\n", + ret); + goto cleanup; + } + + spin_lock_bh(&ar->list_lock); + list_for_each_entry(vif, &ar->vif_list, list) { + if (!test_bit(CONNECTED, &vif->flags) || + !ath6kl_cfg80211_ready(vif)) + continue; + ret = ath6kl_wow_resume_vif(vif); + if (ret) + break; + } + spin_unlock_bh(&ar->list_lock); + + if (ret) + goto cleanup; + + ar->state = ATH6KL_STATE_ON; + return 0; + +cleanup: + ar->state = ATH6KL_STATE_WOW; + return ret; +} + static int ath6kl_cfg80211_deepsleep_suspend(struct ath6kl *ar) { struct ath6kl_vif *vif; -- cgit v1.2.3-18-g5258 From b5495e666d0b83553f6330e7ba33c0cee2271332 Mon Sep 17 00:00:00 2001 From: Thomas Pedersen Date: Thu, 26 Jul 2012 18:11:11 -0700 Subject: ath6kl: restart concurrent vifs on failed connect When an ath6kl STA vif is issued a connect command, the firmware will disconnect all other beaconing vifs in preparation for a potential channel switch. The case where the connect fails is currently unhandled, so if a connection attempt on a STA vif fails and any vifs were waiting for a new channel, simply restart the concurrent vifs on their previous channel. Requires that we start tracking the last issued channel in ar->last_ch, which is valid since ath6kl only supports 1 channel at a time. Also clear the beaconing vif's want_ch_switch bit regardless of whether channel switch succeeds, to stop recommitting the same failed profile. Signed-off-by: Thomas Pedersen Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/core.h | 1 + drivers/net/wireless/ath/ath6kl/main.c | 18 ++++++++++++------ 2 files changed, 13 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h index eb86b315adf..baf149ef346 100644 --- a/drivers/net/wireless/ath/ath6kl/core.h +++ b/drivers/net/wireless/ath/ath6kl/core.h @@ -699,6 +699,7 @@ struct ath6kl { struct ath6kl_req_key ap_mode_bkey; struct sk_buff_head mcastpsq; u32 want_ch_switch; + u16 last_ch; /* * FIXME: protects access to mcastpsq but is actually useless as diff --git a/drivers/net/wireless/ath/ath6kl/main.c b/drivers/net/wireless/ath/ath6kl/main.c index 6beffdee9a8..eca4d4704ed 100644 --- a/drivers/net/wireless/ath/ath6kl/main.c +++ b/drivers/net/wireless/ath/ath6kl/main.c @@ -441,12 +441,9 @@ void ath6kl_connect_ap_mode_bss(struct ath6kl_vif *vif, u16 channel) break; } - if (ar->want_ch_switch & (1 << vif->fw_vif_idx)) { - ar->want_ch_switch &= ~(1 << vif->fw_vif_idx); + if (ar->last_ch != channel) /* we actually don't know the phymode, default to HT20 */ - ath6kl_cfg80211_ch_switch_notify(vif, channel, - WMI_11G_HT20); - } + ath6kl_cfg80211_ch_switch_notify(vif, channel, WMI_11G_HT20); ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx, NONE_BSS_FILTER, 0); set_bit(CONNECTED, &vif->flags); @@ -633,6 +630,9 @@ static void ath6kl_check_ch_switch(struct ath6kl *ar, u16 channel) if (ar->want_ch_switch & (1 << vif->fw_vif_idx)) res = ath6kl_commit_ch_switch(vif, channel); + /* if channel switch failed, oh well we tried */ + ar->want_ch_switch &= ~(1 << vif->fw_vif_idx); + if (res) ath6kl_err("channel switch failed nw_type %d res %d\n", vif->nw_type, res); @@ -986,8 +986,11 @@ void ath6kl_disconnect_event(struct ath6kl_vif *vif, u8 reason, u8 *bssid, if (vif->nw_type == AP_NETWORK) { /* disconnect due to other STA vif switching channels */ if (reason == BSS_DISCONNECTED && - prot_reason_status == WMI_AP_REASON_STA_ROAM) + prot_reason_status == WMI_AP_REASON_STA_ROAM) { ar->want_ch_switch |= 1 << vif->fw_vif_idx; + /* bail back to this channel if STA vif fails connect */ + ar->last_ch = le16_to_cpu(vif->profile.ch); + } if (!ath6kl_remove_sta(ar, bssid, prot_reason_status)) return; @@ -1046,6 +1049,9 @@ void ath6kl_disconnect_event(struct ath6kl_vif *vif, u8 reason, u8 *bssid, } } + /* restart disconnected concurrent vifs waiting for new channel */ + ath6kl_check_ch_switch(ar, ar->last_ch); + /* update connect & link status atomically */ spin_lock_bh(&vif->if_lock); clear_bit(CONNECTED, &vif->flags); -- cgit v1.2.3-18-g5258 From f21243a82253e34f64187aeb3d7f93fb7cb92536 Mon Sep 17 00:00:00 2001 From: Thomas Pedersen Date: Fri, 27 Jul 2012 18:13:27 -0700 Subject: ath6kl: reconfigure RSN capabilities when restarting AP If the firmware decides to initiate a channel switch on an AP vif running an RSN BSS, reconfigure the saved RSN IE capabilities as well. Fixes a bug where the beacon and 4-way handshake would have a capability mismatch after a channel switch, since the firmware apparently clears these on an AP disconnect. Signed-off-by: Thomas Pedersen Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/cfg80211.c | 1 + drivers/net/wireless/ath/ath6kl/core.h | 1 + drivers/net/wireless/ath/ath6kl/main.c | 12 ++++++++++++ 3 files changed, 14 insertions(+) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index e8b9c1e2a04..75ddfafb11b 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -2924,6 +2924,7 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev, WLAN_EID_RSN, WMI_RSN_IE_CAPB, (const u8 *) &rsn_capab, sizeof(rsn_capab)); + vif->rsn_capab = rsn_capab; if (res < 0) return res; } diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h index baf149ef346..a95bf6ab7ec 100644 --- a/drivers/net/wireless/ath/ath6kl/core.h +++ b/drivers/net/wireless/ath/ath6kl/core.h @@ -605,6 +605,7 @@ struct ath6kl_vif { struct net_device_stats net_stats; struct target_stats target_stats; struct wmi_connect_cmd profile; + u16 rsn_capab; struct list_head mc_filter; }; diff --git a/drivers/net/wireless/ath/ath6kl/main.c b/drivers/net/wireless/ath/ath6kl/main.c index eca4d4704ed..9533558a623 100644 --- a/drivers/net/wireless/ath/ath6kl/main.c +++ b/drivers/net/wireless/ath/ath6kl/main.c @@ -608,6 +608,18 @@ static int ath6kl_commit_ch_switch(struct ath6kl_vif *vif, u16 channel) switch (vif->nw_type) { case AP_NETWORK: + /* + * reconfigure any saved RSN IE capabilites in the beacon / + * probe response to stay in sync with the supplicant. + */ + if (vif->rsn_capab && + test_bit(ATH6KL_FW_CAPABILITY_RSN_CAP_OVERRIDE, + ar->fw_capabilities)) + ath6kl_wmi_set_ie_cmd(ar->wmi, vif->fw_vif_idx, + WLAN_EID_RSN, WMI_RSN_IE_CAPB, + (const u8 *) &vif->rsn_capab, + sizeof(vif->rsn_capab)); + return ath6kl_wmi_ap_profile_commit(ar->wmi, vif->fw_vif_idx, &vif->profile); default: -- cgit v1.2.3-18-g5258 From 0616dc1f2bef563d7916c0dcedbb1bff7d9bd80b Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Tue, 14 Aug 2012 10:10:33 +0530 Subject: ath6kl: Fix potential skb double free in ath6kl_wmi_sync_point() skb given to ath6kl_control_tx() is owned by ath6kl_control_tx(). Calling function should not free the skb for error cases. This is found during code review. kvalo: fix a checkpatch warning in ath6kl_wmi_cmd_send() Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/txrx.c | 4 +++- drivers/net/wireless/ath/ath6kl/wmi.c | 35 ++++++++++++++++++---------------- 2 files changed, 22 insertions(+), 17 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath6kl/txrx.c b/drivers/net/wireless/ath/ath6kl/txrx.c index 7dfa0fd86d7..aab825152b1 100644 --- a/drivers/net/wireless/ath/ath6kl/txrx.c +++ b/drivers/net/wireless/ath/ath6kl/txrx.c @@ -288,8 +288,10 @@ int ath6kl_control_tx(void *devt, struct sk_buff *skb, int status = 0; struct ath6kl_cookie *cookie = NULL; - if (WARN_ON_ONCE(ar->state == ATH6KL_STATE_WOW)) + if (WARN_ON_ONCE(ar->state == ATH6KL_STATE_WOW)) { + dev_kfree_skb(skb); return -EACCES; + } spin_lock_bh(&ar->lock); diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index d485a7c3428..373751f9177 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -1739,8 +1739,11 @@ int ath6kl_wmi_cmd_send(struct wmi *wmi, u8 if_idx, struct sk_buff *skb, int ret; u16 info1; - if (WARN_ON(skb == NULL || (if_idx > (wmi->parent_dev->vif_max - 1)))) + if (WARN_ON(skb == NULL || + (if_idx > (wmi->parent_dev->vif_max - 1)))) { + dev_kfree_skb(skb); return -EINVAL; + } ath6kl_dbg(ATH6KL_DBG_WMI, "wmi tx id %d len %d flag %d\n", cmd_id, skb->len, sync_flag); @@ -2352,8 +2355,10 @@ static int ath6kl_wmi_data_sync_send(struct wmi *wmi, struct sk_buff *skb, struct wmi_data_hdr *data_hdr; int ret; - if (WARN_ON(skb == NULL || ep_id == wmi->ep_id)) + if (WARN_ON(skb == NULL || ep_id == wmi->ep_id)) { + dev_kfree_skb(skb); return -EINVAL; + } skb_push(skb, sizeof(struct wmi_data_hdr)); @@ -2390,10 +2395,8 @@ static int ath6kl_wmi_sync_point(struct wmi *wmi, u8 if_idx) spin_unlock_bh(&wmi->lock); skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); - if (!skb) { - ret = -ENOMEM; - goto free_skb; - } + if (!skb) + return -ENOMEM; cmd = (struct wmi_sync_cmd *) skb->data; @@ -2416,7 +2419,7 @@ static int ath6kl_wmi_sync_point(struct wmi *wmi, u8 if_idx) * then do not send the Synchronize cmd on the control ep */ if (ret) - goto free_skb; + goto free_cmd_skb; /* * Send sync cmd followed by sync data messages on all @@ -2426,15 +2429,12 @@ static int ath6kl_wmi_sync_point(struct wmi *wmi, u8 if_idx) NO_SYNC_WMIFLAG); if (ret) - goto free_skb; - - /* cmd buffer sent, we no longer own it */ - skb = NULL; + goto free_data_skb; for (index = 0; index < num_pri_streams; index++) { if (WARN_ON(!data_sync_bufs[index].skb)) - break; + goto free_data_skb; ep_id = ath6kl_ac2_endpoint_id(wmi->parent_dev, data_sync_bufs[index]. @@ -2443,17 +2443,20 @@ static int ath6kl_wmi_sync_point(struct wmi *wmi, u8 if_idx) ath6kl_wmi_data_sync_send(wmi, data_sync_bufs[index].skb, ep_id, if_idx); - if (ret) - break; - data_sync_bufs[index].skb = NULL; + + if (ret) + goto free_data_skb; } -free_skb: + return 0; + +free_cmd_skb: /* free up any resources left over (possibly due to an error) */ if (skb) dev_kfree_skb(skb); +free_data_skb: for (index = 0; index < num_pri_streams; index++) { if (data_sync_bufs[index].skb != NULL) { dev_kfree_skb((struct sk_buff *)data_sync_bufs[index]. -- cgit v1.2.3-18-g5258 From 8114f9b6d28686de02c3f83f0543665728b1a15b Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Tue, 14 Aug 2012 10:10:34 +0530 Subject: ath6kl: Fix potential memory leak in ath6kl_tx_complete() We bail out from ath6kl_tx_complete() if any of the sanity checks on skb and ath6kl_cookie fails. By doing this we potentially leak few remaining buffers in packet_queue. Make sure to proceed processing the remaining buffers as well. This issue is found during code review. Reported-by: Wang yufeng Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/txrx.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath6kl/txrx.c b/drivers/net/wireless/ath/ath6kl/txrx.c index aab825152b1..740a488ef50 100644 --- a/drivers/net/wireless/ath/ath6kl/txrx.c +++ b/drivers/net/wireless/ath/ath6kl/txrx.c @@ -698,21 +698,26 @@ void ath6kl_tx_complete(struct htc_target *target, list_del(&packet->list); ath6kl_cookie = (struct ath6kl_cookie *)packet->pkt_cntxt; - if (!ath6kl_cookie) - goto fatal; + if (WARN_ON_ONCE(!ath6kl_cookie)) + continue; status = packet->status; skb = ath6kl_cookie->skb; eid = packet->endpoint; map_no = ath6kl_cookie->map_no; - if (!skb || !skb->data) - goto fatal; + if (WARN_ON_ONCE(!skb || !skb->data)) { + dev_kfree_skb(skb); + ath6kl_free_cookie(ar, ath6kl_cookie); + continue; + } __skb_queue_tail(&skb_queue, skb); - if (!status && (packet->act_len != skb->len)) - goto fatal; + if (WARN_ON_ONCE(!status && (packet->act_len != skb->len))) { + ath6kl_free_cookie(ar, ath6kl_cookie); + continue; + } ar->tx_pending[eid]--; @@ -794,11 +799,6 @@ void ath6kl_tx_complete(struct htc_target *target, wake_up(&ar->event_wq); return; - -fatal: - WARN_ON(1); - spin_unlock_bh(&ar->lock); - return; } void ath6kl_tx_data_cleanup(struct ath6kl *ar) -- cgit v1.2.3-18-g5258 From a3b3842c2e27ba07f8f7944a76013425d182c47b Mon Sep 17 00:00:00 2001 From: Marina Makienko Date: Tue, 14 Aug 2012 12:11:30 +0400 Subject: ath6kl: check usb_register() return value ath6kl_usb_init() does not check usb_register() return value. As a result it may incorrectly report success of driver initialization. Found by Linux Driver Verification project (linuxtesting.org). kvalo: fix commit title and make cosmetic changes to the code to follow more the style used in the driver Signed-off-by: Marina Makienko Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/usb.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath6kl/usb.c b/drivers/net/wireless/ath/ath6kl/usb.c index 4aa97aa6611..a6d13775467 100644 --- a/drivers/net/wireless/ath/ath6kl/usb.c +++ b/drivers/net/wireless/ath/ath6kl/usb.c @@ -1196,7 +1196,14 @@ static struct usb_driver ath6kl_usb_driver = { static int ath6kl_usb_init(void) { - usb_register(&ath6kl_usb_driver); + int ret; + + ret = usb_register(&ath6kl_usb_driver); + if (ret) { + ath6kl_err("usb registration failed: %d\n", ret); + return ret; + } + return 0; } -- cgit v1.2.3-18-g5258 From b1f47e3a962b8b69612d1eecf4d50082b402fcc5 Mon Sep 17 00:00:00 2001 From: Thomas Pedersen Date: Wed, 15 Aug 2012 16:51:24 -0700 Subject: ath6kl: rework scheduled scan This patch reflects changes in the firmware scheduled scan implementation to behave better in cases with multiple concurrent vifs. Major changes: - scheduled scan filters and state are now programmed per-vif. - decouple scheduled scan from host sleep. To maintain graceful failure with old firmwares, a new firmware capability bit is introduced: ATH6KL_FW_CAPABILITY_SCHED_SCAN_V2. ath6kl simply won't advertise scheduled scan to cfg80211 if the SCHED_SCAN_V2 is not supported. Since firmwares from here on out won't support the previous implicit API for scheduled scan (set WoW filters and host sleep), bump the firmware API to protect old drivers. Unfortunately, due to firmware RAM constraints ath6kl still cannot expect a scan complete event at the end of a scheduled scan results cycle, so the sched_scan_timer is retained. Signed-off-by: Thomas Pedersen Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/cfg80211.c | 45 +++++------------------------- drivers/net/wireless/ath/ath6kl/cfg80211.h | 1 - drivers/net/wireless/ath/ath6kl/core.h | 6 +++- drivers/net/wireless/ath/ath6kl/init.c | 6 ++++ drivers/net/wireless/ath/ath6kl/sdio.c | 19 ------------- drivers/net/wireless/ath/ath6kl/wmi.c | 23 ++++++++++++++- drivers/net/wireless/ath/ath6kl/wmi.h | 10 +++++++ 7 files changed, 50 insertions(+), 60 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index 75ddfafb11b..850c94f6ebc 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -147,15 +147,11 @@ static bool __ath6kl_cfg80211_sscan_stop(struct ath6kl_vif *vif) { struct ath6kl *ar = vif->ar; - if (ar->state != ATH6KL_STATE_SCHED_SCAN) + if (!test_and_clear_bit(SCHED_SCANNING, &vif->flags)) return false; del_timer_sync(&vif->sched_scan_timer); - - ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx, - ATH6KL_HOST_MODE_AWAKE); - - ar->state = ATH6KL_STATE_ON; + ath6kl_wmi_enable_sched_scan_cmd(ar->wmi, vif->fw_vif_idx, false); return true; } @@ -2448,13 +2444,6 @@ int ath6kl_cfg80211_suspend(struct ath6kl *ar, break; - case ATH6KL_CFG_SUSPEND_SCHED_SCAN: - /* - * Nothing needed for schedule scan, firmware is already in - * wow mode and sleeping most of the time. - */ - break; - default: break; } @@ -2502,9 +2491,6 @@ int ath6kl_cfg80211_resume(struct ath6kl *ar) } break; - case ATH6KL_STATE_SCHED_SCAN: - break; - default: break; } @@ -3246,10 +3232,6 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy, if (vif->sme_state != SME_DISCONNECTED) return -EBUSY; - /* The FW currently can't support multi-vif WoW properly. */ - if (ar->num_vif > 1) - return -EIO; - ath6kl_cfg80211_scan_complete_event(vif, true); ret = ath6kl_set_probed_ssids(ar, vif, request->ssids, @@ -3295,15 +3277,6 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy, interval, interval, vif->bg_scan_period, 0, 0, 0, 3, 0, 0, 0); - ret = ath6kl_wmi_set_wow_mode_cmd(ar->wmi, vif->fw_vif_idx, - ATH6KL_WOW_MODE_ENABLE, - WOW_FILTER_SSID, - WOW_HOST_REQ_DELAY); - if (ret) { - ath6kl_warn("Failed to enable wow with ssid filter: %d\n", ret); - return ret; - } - /* this also clears IE in fw if it's not set */ ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx, WMI_FRAME_PROBE_REQ, @@ -3314,17 +3287,13 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy, return ret; } - ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx, - ATH6KL_HOST_MODE_ASLEEP); - if (ret) { - ath6kl_warn("Failed to enable host sleep mode for sched scan: %d\n", - ret); + ret = ath6kl_wmi_enable_sched_scan_cmd(ar->wmi, vif->fw_vif_idx, true); + if (ret) return ret; - } - ar->state = ATH6KL_STATE_SCHED_SCAN; + set_bit(SCHED_SCANNING, &vif->flags); - return ret; + return 0; } static int ath6kl_cfg80211_sscan_stop(struct wiphy *wiphy, @@ -3763,7 +3732,7 @@ int ath6kl_cfg80211_init(struct ath6kl *ar) WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD; - if (test_bit(ATH6KL_FW_CAPABILITY_SCHED_SCAN, ar->fw_capabilities)) + if (test_bit(ATH6KL_FW_CAPABILITY_SCHED_SCAN_V2, ar->fw_capabilities)) ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; if (test_bit(ATH6KL_FW_CAPABILITY_INACTIVITY_TIMEOUT, diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.h b/drivers/net/wireless/ath/ath6kl/cfg80211.h index 780f77775a9..e5e70f3a8ca 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.h +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.h @@ -22,7 +22,6 @@ enum ath6kl_cfg_suspend_mode { ATH6KL_CFG_SUSPEND_DEEPSLEEP, ATH6KL_CFG_SUSPEND_CUTPOWER, ATH6KL_CFG_SUSPEND_WOW, - ATH6KL_CFG_SUSPEND_SCHED_SCAN, }; struct wireless_dev *ath6kl_interface_add(struct ath6kl *ar, const char *name, diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h index a95bf6ab7ec..8b31b9a0f38 100644 --- a/drivers/net/wireless/ath/ath6kl/core.h +++ b/drivers/net/wireless/ath/ath6kl/core.h @@ -127,6 +127,9 @@ enum ath6kl_fw_capability { /* supports WMI_SET_REGDOMAIN_CMDID command */ ATH6KL_FW_CAPABILITY_REGDOMAIN, + /* Firmware supports sched scan decoupled from host sleep */ + ATH6KL_FW_CAPABILITY_SCHED_SCAN_V2, + /* this needs to be last */ ATH6KL_FW_CAPABILITY_MAX, }; @@ -145,6 +148,7 @@ enum ath6kl_hw_flags { #define ATH6KL_FW_API2_FILE "fw-2.bin" #define ATH6KL_FW_API3_FILE "fw-3.bin" +#define ATH6KL_FW_API4_FILE "fw-4.bin" /* AR6003 1.0 definitions */ #define AR6003_HW_1_0_VERSION 0x300002ba @@ -555,6 +559,7 @@ enum ath6kl_vif_state { HOST_SLEEP_MODE_CMD_PROCESSED, NETDEV_MCAST_ALL_ON, NETDEV_MCAST_ALL_OFF, + SCHED_SCANNING, }; struct ath6kl_vif { @@ -640,7 +645,6 @@ enum ath6kl_state { ATH6KL_STATE_DEEPSLEEP, ATH6KL_STATE_CUTPOWER, ATH6KL_STATE_WOW, - ATH6KL_STATE_SCHED_SCAN, }; struct ath6kl { diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c index 8bd429975e4..eb3677bd6e8 100644 --- a/drivers/net/wireless/ath/ath6kl/init.c +++ b/drivers/net/wireless/ath/ath6kl/init.c @@ -1108,6 +1108,12 @@ int ath6kl_init_fetch_firmwares(struct ath6kl *ar) if (ret) return ret; + ret = ath6kl_fetch_fw_apin(ar, ATH6KL_FW_API4_FILE); + if (ret == 0) { + ar->fw_api = 4; + goto out; + } + ret = ath6kl_fetch_fw_apin(ar, ATH6KL_FW_API3_FILE); if (ret == 0) { ar->fw_api = 3; diff --git a/drivers/net/wireless/ath/ath6kl/sdio.c b/drivers/net/wireless/ath/ath6kl/sdio.c index 65e99833151..cc17fe02bda 100644 --- a/drivers/net/wireless/ath/ath6kl/sdio.c +++ b/drivers/net/wireless/ath/ath6kl/sdio.c @@ -844,22 +844,6 @@ static int ath6kl_sdio_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) bool try_deepsleep = false; int ret; - if (ar->state == ATH6KL_STATE_SCHED_SCAN) { - ath6kl_dbg(ATH6KL_DBG_SUSPEND, "sched scan is in progress\n"); - - ret = ath6kl_set_sdio_pm_caps(ar); - if (ret) - goto cut_pwr; - - ret = ath6kl_cfg80211_suspend(ar, - ATH6KL_CFG_SUSPEND_SCHED_SCAN, - NULL); - if (ret) - goto cut_pwr; - - return 0; - } - if (ar->suspend_mode == WLAN_POWER_STATE_WOW || (!ar->suspend_mode && wow)) { @@ -942,9 +926,6 @@ static int ath6kl_sdio_resume(struct ath6kl *ar) case ATH6KL_STATE_WOW: break; - case ATH6KL_STATE_SCHED_SCAN: - break; - case ATH6KL_STATE_SUSPENDING: break; diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index 373751f9177..e95b035168a 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -1116,7 +1116,7 @@ static int ath6kl_wmi_bssinfo_event_rx(struct wmi *wmi, u8 *datap, int len, * the timer would not ever fire if the scan interval is short * enough. */ - if (ar->state == ATH6KL_STATE_SCHED_SCAN && + if (test_bit(SCHED_SCANNING, &vif->flags) && !timer_pending(&vif->sched_scan_timer)) { mod_timer(&vif->sched_scan_timer, jiffies + msecs_to_jiffies(ATH6KL_SCHED_SCAN_RESULT_DELAY)); @@ -2027,6 +2027,27 @@ int ath6kl_wmi_beginscan_cmd(struct wmi *wmi, u8 if_idx, return ret; } +int ath6kl_wmi_enable_sched_scan_cmd(struct wmi *wmi, u8 if_idx, bool enable) +{ + struct sk_buff *skb; + struct wmi_enable_sched_scan_cmd *sc; + int ret; + + skb = ath6kl_wmi_get_new_buf(sizeof(*sc)); + if (!skb) + return -ENOMEM; + + ath6kl_dbg(ATH6KL_DBG_WMI, "%s scheduled scan on vif %d\n", + enable ? "enabling" : "disabling", if_idx); + sc = (struct wmi_enable_sched_scan_cmd *) skb->data; + sc->enable = enable ? 1 : 0; + + ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, + WMI_ENABLE_SCHED_SCAN_CMDID, + NO_SYNC_WMIFLAG); + return ret; +} + int ath6kl_wmi_scanparams_cmd(struct wmi *wmi, u8 if_idx, u16 fg_start_sec, u16 fg_end_sec, u16 bg_sec, diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h index 9c73ae73f26..a791b1bbe0c 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.h +++ b/drivers/net/wireless/ath/ath6kl/wmi.h @@ -638,6 +638,10 @@ enum wmi_cmd_id { WMI_VOICE_DETECTION_ENABLE_CMDID, WMI_SET_TXE_NOTIFY_CMDID, + + WMI_SET_RECOVERY_TEST_PARAMETER_CMDID, /*0xf094*/ + + WMI_ENABLE_SCHED_SCAN_CMDID, }; enum wmi_mgmt_frame_type { @@ -951,6 +955,11 @@ struct wmi_scan_params_cmd { __le32 max_dfsch_act_time; } __packed; +/* WMI_ENABLE_SCHED_SCAN_CMDID */ +struct wmi_enable_sched_scan_cmd { + u8 enable; +} __packed; + /* WMI_SET_BSS_FILTER_CMDID */ enum wmi_bss_filter { /* no beacons forwarded */ @@ -2559,6 +2568,7 @@ int ath6kl_wmi_beginscan_cmd(struct wmi *wmi, u8 if_idx, u32 home_dwell_time, u32 force_scan_interval, s8 num_chan, u16 *ch_list, u32 no_cck, u32 *rates); +int ath6kl_wmi_enable_sched_scan_cmd(struct wmi *wmi, u8 if_idx, bool enable); int ath6kl_wmi_scanparams_cmd(struct wmi *wmi, u8 if_idx, u16 fg_start_sec, u16 fg_end_sec, u16 bg_sec, -- cgit v1.2.3-18-g5258 From 2c07cf4461c958e52efd9cfca1df67165426ba20 Mon Sep 17 00:00:00 2001 From: Thomas Pedersen Date: Mon, 20 Aug 2012 14:26:50 -0700 Subject: ath6kl: consolidate WoW pattern length Since WOW_MASK_SIZE and WOW_PATTERN_SIZE have the same value, are logically equivalent, and part of the WMI API so therefore unlikely to change, consolidate these into WOW_PATTERN_SIZE. Reported-by Kalle Valo Signed-off-by: Thomas Pedersen Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/cfg80211.c | 2 +- drivers/net/wireless/ath/ath6kl/wmi.h | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index 850c94f6ebc..a7c8ff084c4 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -1870,7 +1870,7 @@ static int ath6kl_wow_usr(struct ath6kl *ar, struct ath6kl_vif *vif, struct cfg80211_wowlan *wow, u32 *filter) { int ret, pos; - u8 mask[WOW_MASK_SIZE]; + u8 mask[WOW_PATTERN_SIZE]; u16 i; /* Configure the patterns that we received from the user. */ diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h index a791b1bbe0c..a638151cf86 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.h +++ b/drivers/net/wireless/ath/ath6kl/wmi.h @@ -2062,7 +2062,6 @@ struct wmi_set_ie_cmd { #define WOW_MAX_FILTERS_PER_LIST 4 #define WOW_PATTERN_SIZE 64 -#define WOW_MASK_SIZE 64 #define MAC_MAX_FILTERS_PER_LIST 4 @@ -2071,7 +2070,7 @@ struct wow_filter { u8 wow_filter_id; u8 wow_filter_size; u8 wow_filter_offset; - u8 wow_filter_mask[WOW_MASK_SIZE]; + u8 wow_filter_mask[WOW_PATTERN_SIZE]; u8 wow_filter_pattern[WOW_PATTERN_SIZE]; } __packed; -- cgit v1.2.3-18-g5258 From 3814264481fecba02ba60f2e6c6baea2d43b757b Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Fri, 24 Aug 2012 19:53:28 +0530 Subject: ath6kl: trivial cleanup on interface type selection a minor cleanup in assigning the driver specific network type based on interface type. Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/cfg80211.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index a7c8ff084c4..b58878648d2 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -365,17 +365,13 @@ static int ath6kl_nliftype_to_drv_iftype(enum nl80211_iftype type, u8 *nw_type) { switch (type) { case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_P2P_CLIENT: *nw_type = INFRA_NETWORK; break; case NL80211_IFTYPE_ADHOC: *nw_type = ADHOC_NETWORK; break; case NL80211_IFTYPE_AP: - *nw_type = AP_NETWORK; - break; - case NL80211_IFTYPE_P2P_CLIENT: - *nw_type = INFRA_NETWORK; - break; case NL80211_IFTYPE_P2P_GO: *nw_type = AP_NETWORK; break; -- cgit v1.2.3-18-g5258 From 83685091acb878980711c3b28fe42e8959583e84 Mon Sep 17 00:00:00 2001 From: Dengke Qiu Date: Tue, 28 Aug 2012 15:33:42 +0800 Subject: ath6kl: fix link speed when using sgi The MSB of rate index from FW is used for sgi. But the ath6kl_wmi_get_rate doesn't handle it. The access to wmi_rate_tbl array may be out of range if sgi is 1. This may cause the return value of ath6kl_wmi_get_rate() function is incorrect link rate. We add sgi adjustment to avoid such case. kvalo: change patch title Signed-off-by: Dengke Qiu Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/wmi.c | 13 ++++++++++++- drivers/net/wireless/ath/ath6kl/wmi.h | 3 +++ 2 files changed, 15 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index e95b035168a..cd2db42c098 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -3263,10 +3263,21 @@ int ath6kl_wmi_set_regdomain_cmd(struct wmi *wmi, const char *alpha2) s32 ath6kl_wmi_get_rate(s8 rate_index) { + u8 sgi = 0; + if (rate_index == RATE_AUTO) return 0; - return wmi_rate_tbl[(u32) rate_index][0]; + /* SGI is stored as the MSB of the rate_index */ + if (rate_index & RATE_INDEX_MSB) { + rate_index &= RATE_INDEX_WITHOUT_SGI_MASK; + sgi = 1; + } + + if (WARN_ON(rate_index > RATE_MCS_7_40)) + rate_index = RATE_MCS_7_40; + + return wmi_rate_tbl[(u32) rate_index][sgi]; } static int ath6kl_wmi_get_pmkid_list_event_rx(struct wmi *wmi, u8 *datap, diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h index a638151cf86..e916e57c9d9 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.h +++ b/drivers/net/wireless/ath/ath6kl/wmi.h @@ -1792,6 +1792,9 @@ struct rx_stats { a_sle32 ucast_rate; } __packed; +#define RATE_INDEX_WITHOUT_SGI_MASK 0x7f +#define RATE_INDEX_MSB 0x80 + struct tkip_ccmp_stats { __le32 tkip_local_mic_fail; __le32 tkip_cnter_measures_invoked; -- cgit v1.2.3-18-g5258 From ede615d2f043539e23bc4022955dbe0c3ec70ca2 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Wed, 29 Aug 2012 19:40:25 +0530 Subject: ath6kl: Refactor ath6kl_init_hw_start() and ath6kl_init_hw_stop() So that these functions will be used to re-initialize the fw upon detecting fw error. This refactoring moves ar->state setting out of core stop/start functionality. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/init.c | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c index eb3677bd6e8..be27ebec905 100644 --- a/drivers/net/wireless/ath/ath6kl/init.c +++ b/drivers/net/wireless/ath/ath6kl/init.c @@ -1546,7 +1546,7 @@ static const char *ath6kl_init_get_hif_name(enum ath6kl_hif_type type) return NULL; } -int ath6kl_init_hw_start(struct ath6kl *ar) +static int __ath6kl_init_hw_start(struct ath6kl *ar) { long timeleft; int ret, i; @@ -1642,8 +1642,6 @@ int ath6kl_init_hw_start(struct ath6kl *ar) goto err_htc_stop; } - ar->state = ATH6KL_STATE_ON; - return 0; err_htc_stop: @@ -1656,7 +1654,18 @@ err_power_off: return ret; } -int ath6kl_init_hw_stop(struct ath6kl *ar) +int ath6kl_init_hw_start(struct ath6kl *ar) +{ + int err; + + err = __ath6kl_init_hw_start(ar); + if (err) + return err; + ar->state = ATH6KL_STATE_ON; + return 0; +} + +static int __ath6kl_init_hw_stop(struct ath6kl *ar) { int ret; @@ -1672,8 +1681,17 @@ int ath6kl_init_hw_stop(struct ath6kl *ar) if (ret) ath6kl_warn("failed to power off hif: %d\n", ret); - ar->state = ATH6KL_STATE_OFF; + return 0; +} +int ath6kl_init_hw_stop(struct ath6kl *ar) +{ + int err; + + err = __ath6kl_init_hw_stop(ar); + if (err) + return err; + ar->state = ATH6KL_STATE_OFF; return 0; } -- cgit v1.2.3-18-g5258 From 84caf8005b09e0a4a57fce44119489d1b0bbbe94 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Wed, 29 Aug 2012 19:40:26 +0530 Subject: ath6kl: Recover from fw crash Re-initialize the target when fw crash is reported. This would make the device functional again after target crash. During the target re-initialization it is made sure that target is not bugged with data/cmd request, ar->state ATH6KL_STATE_RECOVERY is used for this purpose. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/Makefile | 1 + drivers/net/wireless/ath/ath6kl/cfg80211.c | 17 +++++++- drivers/net/wireless/ath/ath6kl/core.c | 4 ++ drivers/net/wireless/ath/ath6kl/core.h | 18 +++++++++ drivers/net/wireless/ath/ath6kl/debug.h | 1 + drivers/net/wireless/ath/ath6kl/hif.c | 1 + drivers/net/wireless/ath/ath6kl/init.c | 19 +++++++++ drivers/net/wireless/ath/ath6kl/recovery.c | 62 ++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath6kl/sdio.c | 3 ++ drivers/net/wireless/ath/ath6kl/txrx.c | 3 +- 10 files changed, 126 insertions(+), 3 deletions(-) create mode 100644 drivers/net/wireless/ath/ath6kl/recovery.c (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath6kl/Makefile b/drivers/net/wireless/ath/ath6kl/Makefile index 8cae8886f17..cab0ec0d538 100644 --- a/drivers/net/wireless/ath/ath6kl/Makefile +++ b/drivers/net/wireless/ath/ath6kl/Makefile @@ -34,6 +34,7 @@ ath6kl_core-y += main.o ath6kl_core-y += txrx.o ath6kl_core-y += wmi.o ath6kl_core-y += core.o +ath6kl_core-y += recovery.o ath6kl_core-$(CONFIG_NL80211_TESTMODE) += testmode.o obj-$(CONFIG_ATH6KL_SDIO) += ath6kl_sdio.o diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index b58878648d2..8cf146b5c57 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -2503,14 +2503,23 @@ static int __ath6kl_cfg80211_suspend(struct wiphy *wiphy, { struct ath6kl *ar = wiphy_priv(wiphy); + ath6kl_recovery_suspend(ar); + return ath6kl_hif_suspend(ar, wow); } static int __ath6kl_cfg80211_resume(struct wiphy *wiphy) { struct ath6kl *ar = wiphy_priv(wiphy); + int err; + + err = ath6kl_hif_resume(ar); + if (err) + return err; - return ath6kl_hif_resume(ar); + ar->fw_recovery.enable = true; + + return 0; } /* @@ -3434,6 +3443,10 @@ void ath6kl_cfg80211_stop(struct ath6kl_vif *vif) clear_bit(CONNECTED, &vif->flags); clear_bit(CONNECT_PEND, &vif->flags); + /* Stop netdev queues, needed during recovery */ + netif_stop_queue(vif->ndev); + netif_carrier_off(vif->ndev); + /* disable scanning */ if (ath6kl_wmi_scanparams_cmd(vif->ar->wmi, vif->fw_vif_idx, 0xFFFF, 0, 0, 0, 0, 0, 0, 0, 0, 0) != 0) @@ -3447,7 +3460,7 @@ void ath6kl_cfg80211_stop_all(struct ath6kl *ar) struct ath6kl_vif *vif; vif = ath6kl_vif_first(ar); - if (!vif) { + if (!vif && ar->state != ATH6KL_STATE_RECOVERY) { /* save the current power mode before enabling power save */ ar->wmi->saved_pwr_mode = ar->wmi->pwr_mode; diff --git a/drivers/net/wireless/ath/ath6kl/core.c b/drivers/net/wireless/ath/ath6kl/core.c index 82c4dd2a960..adcaa965486 100644 --- a/drivers/net/wireless/ath/ath6kl/core.c +++ b/drivers/net/wireless/ath/ath6kl/core.c @@ -202,6 +202,8 @@ int ath6kl_core_init(struct ath6kl *ar, enum ath6kl_htc_type htc_type) ath6kl_dbg(ATH6KL_DBG_TRC, "%s: name=%s dev=0x%p, ar=0x%p\n", __func__, wdev->netdev->name, wdev->netdev, ar); + ath6kl_recovery_init(ar); + return ret; err_rxbuf_cleanup: @@ -291,6 +293,8 @@ void ath6kl_core_cleanup(struct ath6kl *ar) { ath6kl_hif_power_off(ar); + ath6kl_recovery_cleanup(ar); + destroy_workqueue(ar->ath6kl_wq); if (ar->htc_target) diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h index 8b31b9a0f38..c7dcdadd8b8 100644 --- a/drivers/net/wireless/ath/ath6kl/core.h +++ b/drivers/net/wireless/ath/ath6kl/core.h @@ -645,6 +645,12 @@ enum ath6kl_state { ATH6KL_STATE_DEEPSLEEP, ATH6KL_STATE_CUTPOWER, ATH6KL_STATE_WOW, + ATH6KL_STATE_RECOVERY, +}; + +/* Fw error recovery */ +enum ath6kl_fw_err { + ATH6KL_FW_ASSERT, }; struct ath6kl { @@ -790,6 +796,12 @@ struct ath6kl { bool wiphy_registered; + struct ath6kl_fw_recovery { + bool enable; + struct work_struct recovery_work; + unsigned long err_reason; + } fw_recovery; + #ifdef CONFIG_ATH6KL_DEBUG struct { struct sk_buff_head fwlog_queue; @@ -925,4 +937,10 @@ int ath6kl_core_init(struct ath6kl *ar, enum ath6kl_htc_type htc_type); void ath6kl_core_cleanup(struct ath6kl *ar); void ath6kl_core_destroy(struct ath6kl *ar); +/* Fw error recovery */ +void ath6kl_init_hw_restart(struct ath6kl *ar); +void ath6kl_recovery_err_notify(struct ath6kl *ar, enum ath6kl_fw_err reason); +void ath6kl_recovery_init(struct ath6kl *ar); +void ath6kl_recovery_cleanup(struct ath6kl *ar); +void ath6kl_recovery_suspend(struct ath6kl *ar); #endif /* CORE_H */ diff --git a/drivers/net/wireless/ath/ath6kl/debug.h b/drivers/net/wireless/ath/ath6kl/debug.h index 49639d8266c..f97cd4ead54 100644 --- a/drivers/net/wireless/ath/ath6kl/debug.h +++ b/drivers/net/wireless/ath/ath6kl/debug.h @@ -44,6 +44,7 @@ enum ATH6K_DEBUG_MASK { ATH6KL_DBG_SUSPEND = BIT(20), ATH6KL_DBG_USB = BIT(21), ATH6KL_DBG_USB_BULK = BIT(22), + ATH6KL_DBG_RECOVERY = BIT(23), ATH6KL_DBG_ANY = 0xffffffff /* enable all logs */ }; diff --git a/drivers/net/wireless/ath/ath6kl/hif.c b/drivers/net/wireless/ath/ath6kl/hif.c index 68ed6c2665b..029914a22ea 100644 --- a/drivers/net/wireless/ath/ath6kl/hif.c +++ b/drivers/net/wireless/ath/ath6kl/hif.c @@ -136,6 +136,7 @@ static int ath6kl_hif_proc_dbg_intr(struct ath6kl_device *dev) ath6kl_hif_dump_fw_crash(dev->ar); ath6kl_read_fwlogs(dev->ar); + ath6kl_recovery_err_notify(dev->ar, ATH6KL_FW_ASSERT); return ret; } diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c index be27ebec905..301443c9f9e 100644 --- a/drivers/net/wireless/ath/ath6kl/init.c +++ b/drivers/net/wireless/ath/ath6kl/init.c @@ -1695,6 +1695,25 @@ int ath6kl_init_hw_stop(struct ath6kl *ar) return 0; } +void ath6kl_init_hw_restart(struct ath6kl *ar) +{ + + ar->state = ATH6KL_STATE_RECOVERY; + + ath6kl_cfg80211_stop_all(ar); + + if (__ath6kl_init_hw_stop(ar)) + return; + + if (__ath6kl_init_hw_start(ar)) { + ath6kl_dbg(ATH6KL_DBG_RECOVERY, "Failed to restart during fw error recovery\n"); + return; + } + + ar->state = ATH6KL_STATE_ON; + ar->fw_recovery.err_reason = 0; +} + /* FIXME: move this to cfg80211.c and rename to ath6kl_cfg80211_vif_stop() */ void ath6kl_cleanup_vif(struct ath6kl_vif *vif, bool wmi_ready) { diff --git a/drivers/net/wireless/ath/ath6kl/recovery.c b/drivers/net/wireless/ath/ath6kl/recovery.c new file mode 100644 index 00000000000..c225fc4d3d5 --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/recovery.c @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2012 Qualcomm Atheros, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "core.h" +#include "cfg80211.h" +#include "debug.h" + +static void ath6kl_recovery_work(struct work_struct *work) +{ + struct ath6kl *ar = container_of(work, struct ath6kl, + fw_recovery.recovery_work); + + ath6kl_init_hw_restart(ar); +} + +void ath6kl_recovery_err_notify(struct ath6kl *ar, enum ath6kl_fw_err reason) +{ + ath6kl_dbg(ATH6KL_DBG_RECOVERY, "Fw error detected, reason:%d\n", + reason); + + set_bit(reason, &ar->fw_recovery.err_reason); + + if (ar->fw_recovery.enable && ar->state != ATH6KL_STATE_RECOVERY) + queue_work(ar->ath6kl_wq, &ar->fw_recovery.recovery_work); +} + +void ath6kl_recovery_init(struct ath6kl *ar) +{ + struct ath6kl_fw_recovery *recovery = &ar->fw_recovery; + + recovery->enable = true; + INIT_WORK(&recovery->recovery_work, ath6kl_recovery_work); +} + +void ath6kl_recovery_cleanup(struct ath6kl *ar) +{ + ar->fw_recovery.enable = false; + + cancel_work_sync(&ar->fw_recovery.recovery_work); +} + +void ath6kl_recovery_suspend(struct ath6kl *ar) +{ + ath6kl_recovery_cleanup(ar); + + /* Process pending fw error detection */ + if (ar->fw_recovery.err_reason) + ath6kl_init_hw_restart(ar); +} diff --git a/drivers/net/wireless/ath/ath6kl/sdio.c b/drivers/net/wireless/ath/ath6kl/sdio.c index cc17fe02bda..a72a4d02a4c 100644 --- a/drivers/net/wireless/ath/ath6kl/sdio.c +++ b/drivers/net/wireless/ath/ath6kl/sdio.c @@ -931,6 +931,9 @@ static int ath6kl_sdio_resume(struct ath6kl *ar) case ATH6KL_STATE_RESUMING: break; + + case ATH6KL_STATE_RECOVERY: + break; } ath6kl_cfg80211_resume(ar); diff --git a/drivers/net/wireless/ath/ath6kl/txrx.c b/drivers/net/wireless/ath/ath6kl/txrx.c index 740a488ef50..cbe1a9d8911 100644 --- a/drivers/net/wireless/ath/ath6kl/txrx.c +++ b/drivers/net/wireless/ath/ath6kl/txrx.c @@ -288,7 +288,8 @@ int ath6kl_control_tx(void *devt, struct sk_buff *skb, int status = 0; struct ath6kl_cookie *cookie = NULL; - if (WARN_ON_ONCE(ar->state == ATH6KL_STATE_WOW)) { + if (WARN_ON_ONCE(ar->state == ATH6KL_STATE_WOW) || + ar->state == ATH6KL_STATE_RECOVERY) { dev_kfree_skb(skb); return -EACCES; } -- cgit v1.2.3-18-g5258 From 9233299394de1c571e52ab2dbe1995c1fbdc8fda Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Wed, 29 Aug 2012 19:40:27 +0530 Subject: ath6kl: Add support to detect fw error through heart beat This patch adds support to detect fw error condition by sending periodic message (heart beat challenge) to firmware. Upon reception of the message, fw would send a response event to driver. When there are no reponses from fw for about 5 cmd driver would trigger the recovery logic assuming that fw has gone into an error state. Capable fw will advertise this capability through ATH6KL_FW_CAPABILITY_HEART_BEAT_POLL bit. This feature is disabled by default, can be enabled through a modparam (heart_beat_poll). This modparam also confiures the polling interval in msecs. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/cfg80211.c | 2 +- drivers/net/wireless/ath/ath6kl/core.c | 9 +++ drivers/net/wireless/ath/ath6kl/core.h | 16 ++++++ drivers/net/wireless/ath/ath6kl/init.c | 6 -- drivers/net/wireless/ath/ath6kl/recovery.c | 89 +++++++++++++++++++++++++++++- drivers/net/wireless/ath/ath6kl/wmi.c | 14 +++++ drivers/net/wireless/ath/ath6kl/wmi.h | 2 + 7 files changed, 129 insertions(+), 9 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index 8cf146b5c57..c8b6be44fa2 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -2517,7 +2517,7 @@ static int __ath6kl_cfg80211_resume(struct wiphy *wiphy) if (err) return err; - ar->fw_recovery.enable = true; + ath6kl_recovery_resume(ar); return 0; } diff --git a/drivers/net/wireless/ath/ath6kl/core.c b/drivers/net/wireless/ath/ath6kl/core.c index adcaa965486..fd5dd3aca77 100644 --- a/drivers/net/wireless/ath/ath6kl/core.c +++ b/drivers/net/wireless/ath/ath6kl/core.c @@ -33,6 +33,7 @@ static unsigned int wow_mode; static unsigned int uart_debug; static unsigned int ath6kl_p2p; static unsigned int testmode; +static unsigned int heart_beat_poll; module_param(debug_mask, uint, 0644); module_param(suspend_mode, uint, 0644); @@ -40,6 +41,9 @@ module_param(wow_mode, uint, 0644); module_param(uart_debug, uint, 0644); module_param(ath6kl_p2p, uint, 0644); module_param(testmode, uint, 0644); +module_param(heart_beat_poll, uint, 0644); +MODULE_PARM_DESC(heart_beat_poll, "Enable fw error detection periodic" \ + "polling. This also specifies the polling interval in msecs"); void ath6kl_core_tx_complete(struct ath6kl *ar, struct sk_buff *skb) { @@ -202,6 +206,11 @@ int ath6kl_core_init(struct ath6kl *ar, enum ath6kl_htc_type htc_type) ath6kl_dbg(ATH6KL_DBG_TRC, "%s: name=%s dev=0x%p, ar=0x%p\n", __func__, wdev->netdev->name, wdev->netdev, ar); + if (heart_beat_poll && + test_bit(ATH6KL_FW_CAPABILITY_HEART_BEAT_POLL, + ar->fw_capabilities)) + ar->fw_recovery.hb_poll = heart_beat_poll; + ath6kl_recovery_init(ar); return ret; diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h index c7dcdadd8b8..b2cbecf6cfe 100644 --- a/drivers/net/wireless/ath/ath6kl/core.h +++ b/drivers/net/wireless/ath/ath6kl/core.h @@ -130,6 +130,12 @@ enum ath6kl_fw_capability { /* Firmware supports sched scan decoupled from host sleep */ ATH6KL_FW_CAPABILITY_SCHED_SCAN_V2, + /* + * Firmware capability for hang detection through heart beat + * challenge messages. + */ + ATH6KL_FW_CAPABILITY_HEART_BEAT_POLL, + /* this needs to be last */ ATH6KL_FW_CAPABILITY_MAX, }; @@ -649,8 +655,11 @@ enum ath6kl_state { }; /* Fw error recovery */ +#define ATH6KL_HB_RESP_MISS_THRES 5 + enum ath6kl_fw_err { ATH6KL_FW_ASSERT, + ATH6KL_FW_HB_RESP_FAILURE, }; struct ath6kl { @@ -800,6 +809,11 @@ struct ath6kl { bool enable; struct work_struct recovery_work; unsigned long err_reason; + unsigned long hb_poll; + struct timer_list hb_timer; + u32 seq_num; + bool hb_pending; + u8 hb_misscnt; } fw_recovery; #ifdef CONFIG_ATH6KL_DEBUG @@ -940,7 +954,9 @@ void ath6kl_core_destroy(struct ath6kl *ar); /* Fw error recovery */ void ath6kl_init_hw_restart(struct ath6kl *ar); void ath6kl_recovery_err_notify(struct ath6kl *ar, enum ath6kl_fw_err reason); +void ath6kl_recovery_hb_event(struct ath6kl *ar, u32 cookie); void ath6kl_recovery_init(struct ath6kl *ar); void ath6kl_recovery_cleanup(struct ath6kl *ar); void ath6kl_recovery_suspend(struct ath6kl *ar); +void ath6kl_recovery_resume(struct ath6kl *ar); #endif /* CORE_H */ diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c index 301443c9f9e..6e270fa6d63 100644 --- a/drivers/net/wireless/ath/ath6kl/init.c +++ b/drivers/net/wireless/ath/ath6kl/init.c @@ -1697,9 +1697,6 @@ int ath6kl_init_hw_stop(struct ath6kl *ar) void ath6kl_init_hw_restart(struct ath6kl *ar) { - - ar->state = ATH6KL_STATE_RECOVERY; - ath6kl_cfg80211_stop_all(ar); if (__ath6kl_init_hw_stop(ar)) @@ -1709,9 +1706,6 @@ void ath6kl_init_hw_restart(struct ath6kl *ar) ath6kl_dbg(ATH6KL_DBG_RECOVERY, "Failed to restart during fw error recovery\n"); return; } - - ar->state = ATH6KL_STATE_ON; - ar->fw_recovery.err_reason = 0; } /* FIXME: move this to cfg80211.c and rename to ath6kl_cfg80211_vif_stop() */ diff --git a/drivers/net/wireless/ath/ath6kl/recovery.c b/drivers/net/wireless/ath/ath6kl/recovery.c index c225fc4d3d5..4e3f205bb8a 100644 --- a/drivers/net/wireless/ath/ath6kl/recovery.c +++ b/drivers/net/wireless/ath/ath6kl/recovery.c @@ -23,7 +23,18 @@ static void ath6kl_recovery_work(struct work_struct *work) struct ath6kl *ar = container_of(work, struct ath6kl, fw_recovery.recovery_work); + ar->state = ATH6KL_STATE_RECOVERY; + + del_timer_sync(&ar->fw_recovery.hb_timer); + ath6kl_init_hw_restart(ar); + + ar->state = ATH6KL_STATE_ON; + ar->fw_recovery.err_reason = 0; + + if (ar->fw_recovery.enable) + mod_timer(&ar->fw_recovery.hb_timer, jiffies + + msecs_to_jiffies(ar->fw_recovery.hb_poll)); } void ath6kl_recovery_err_notify(struct ath6kl *ar, enum ath6kl_fw_err reason) @@ -37,18 +48,72 @@ void ath6kl_recovery_err_notify(struct ath6kl *ar, enum ath6kl_fw_err reason) queue_work(ar->ath6kl_wq, &ar->fw_recovery.recovery_work); } +void ath6kl_recovery_hb_event(struct ath6kl *ar, u32 cookie) +{ + if (cookie == ar->fw_recovery.seq_num) + ar->fw_recovery.hb_pending = false; +} + +static void ath6kl_recovery_hb_timer(unsigned long data) +{ + struct ath6kl *ar = (struct ath6kl *) data; + int err; + + if (!ar->fw_recovery.enable) + return; + + if (ar->fw_recovery.hb_pending) + ar->fw_recovery.hb_misscnt++; + else + ar->fw_recovery.hb_misscnt = 0; + + if (ar->fw_recovery.hb_misscnt > ATH6KL_HB_RESP_MISS_THRES) { + ar->fw_recovery.hb_misscnt = 0; + ar->fw_recovery.seq_num = 0; + ar->fw_recovery.hb_pending = false; + ath6kl_recovery_err_notify(ar, ATH6KL_FW_HB_RESP_FAILURE); + return; + } + + ar->fw_recovery.seq_num++; + ar->fw_recovery.hb_pending = true; + + err = ath6kl_wmi_get_challenge_resp_cmd(ar->wmi, + ar->fw_recovery.seq_num, 0); + if (err) + ath6kl_warn("Failed to send hb challenge request, err:%d\n", + err); + + if ((ar->state == ATH6KL_STATE_RECOVERY) || !ar->fw_recovery.enable) + return; + + mod_timer(&ar->fw_recovery.hb_timer, jiffies + + msecs_to_jiffies(ar->fw_recovery.hb_poll)); +} + void ath6kl_recovery_init(struct ath6kl *ar) { struct ath6kl_fw_recovery *recovery = &ar->fw_recovery; recovery->enable = true; INIT_WORK(&recovery->recovery_work, ath6kl_recovery_work); + recovery->seq_num = 0; + recovery->hb_misscnt = 0; + ar->fw_recovery.hb_pending = false; + ar->fw_recovery.hb_timer.function = ath6kl_recovery_hb_timer; + ar->fw_recovery.hb_timer.data = (unsigned long) ar; + init_timer_deferrable(&ar->fw_recovery.hb_timer); + + if (ar->fw_recovery.hb_poll) + mod_timer(&ar->fw_recovery.hb_timer, jiffies + + msecs_to_jiffies(ar->fw_recovery.hb_poll)); } void ath6kl_recovery_cleanup(struct ath6kl *ar) { ar->fw_recovery.enable = false; + del_timer_sync(&ar->fw_recovery.hb_timer); cancel_work_sync(&ar->fw_recovery.recovery_work); } @@ -56,7 +121,27 @@ void ath6kl_recovery_suspend(struct ath6kl *ar) { ath6kl_recovery_cleanup(ar); + if (!ar->fw_recovery.err_reason) + return; + /* Process pending fw error detection */ - if (ar->fw_recovery.err_reason) - ath6kl_init_hw_restart(ar); + ar->fw_recovery.err_reason = 0; + WARN_ON(ar->state != ATH6KL_STATE_ON); + ar->state = ATH6KL_STATE_RECOVERY; + ath6kl_init_hw_restart(ar); + ar->state = ATH6KL_STATE_ON; +} + +void ath6kl_recovery_resume(struct ath6kl *ar) +{ + ar->fw_recovery.enable = true; + + if (!ar->fw_recovery.hb_poll) + return; + + ar->fw_recovery.hb_pending = false; + ar->fw_recovery.seq_num = 0; + ar->fw_recovery.hb_misscnt = 0; + mod_timer(&ar->fw_recovery.hb_timer, + jiffies + msecs_to_jiffies(ar->fw_recovery.hb_poll)); } diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index cd2db42c098..68b46bda498 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -3767,6 +3767,19 @@ int ath6kl_wmi_set_inact_period(struct wmi *wmi, u8 if_idx, int inact_timeout) NO_SYNC_WMIFLAG); } +static void ath6kl_wmi_hb_challenge_resp_event(struct wmi *wmi, u8 *datap, + int len) +{ + struct wmix_hb_challenge_resp_cmd *cmd; + + if (len < sizeof(struct wmix_hb_challenge_resp_cmd)) + return; + + cmd = (struct wmix_hb_challenge_resp_cmd *) datap; + ath6kl_recovery_hb_event(wmi->parent_dev, + le32_to_cpu(cmd->cookie)); +} + static int ath6kl_wmi_control_rx_xtnd(struct wmi *wmi, struct sk_buff *skb) { struct wmix_cmd_hdr *cmd; @@ -3791,6 +3804,7 @@ static int ath6kl_wmi_control_rx_xtnd(struct wmi *wmi, struct sk_buff *skb) switch (id) { case WMIX_HB_CHALLENGE_RESP_EVENTID: ath6kl_dbg(ATH6KL_DBG_WMI, "wmi event hb challenge resp\n"); + ath6kl_wmi_hb_challenge_resp_event(wmi, datap, len); break; case WMIX_DBGLOG_EVENTID: ath6kl_dbg(ATH6KL_DBG_WMI, "wmi event dbglog len %d\n", len); diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h index e916e57c9d9..98b1755e67f 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.h +++ b/drivers/net/wireless/ath/ath6kl/wmi.h @@ -2716,6 +2716,8 @@ int ath6kl_wmi_set_inact_period(struct wmi *wmi, u8 if_idx, int inact_timeout); void ath6kl_wmi_sscan_timer(unsigned long ptr); +int ath6kl_wmi_get_challenge_resp_cmd(struct wmi *wmi, u32 cookie, u32 source); + struct ath6kl_vif *ath6kl_get_vif_by_index(struct ath6kl *ar, u8 if_idx); void *ath6kl_wmi_init(struct ath6kl *devt); void ath6kl_wmi_shutdown(struct wmi *wmi); -- cgit v1.2.3-18-g5258 From 77565794eb69cf73a5808c04b01bc2a97ebf32d3 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Wed, 29 Aug 2012 19:40:28 +0530 Subject: ath6kl: Recover from "wmi ctrl ep is full" condition In some error conditions, fw pauses HTC pipes which would result in control endpoint full condition. When we hit this case, most of the time the device will be unusable. Re-initialize the target to recover from this situation. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/core.h | 1 + drivers/net/wireless/ath/ath6kl/recovery.c | 2 ++ drivers/net/wireless/ath/ath6kl/txrx.c | 1 + 3 files changed, 4 insertions(+) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h index b2cbecf6cfe..ac90b31514b 100644 --- a/drivers/net/wireless/ath/ath6kl/core.h +++ b/drivers/net/wireless/ath/ath6kl/core.h @@ -660,6 +660,7 @@ enum ath6kl_state { enum ath6kl_fw_err { ATH6KL_FW_ASSERT, ATH6KL_FW_HB_RESP_FAILURE, + ATH6KL_FW_EP_FULL, }; struct ath6kl { diff --git a/drivers/net/wireless/ath/ath6kl/recovery.c b/drivers/net/wireless/ath/ath6kl/recovery.c index 4e3f205bb8a..03edeb8c2ce 100644 --- a/drivers/net/wireless/ath/ath6kl/recovery.c +++ b/drivers/net/wireless/ath/ath6kl/recovery.c @@ -30,6 +30,8 @@ static void ath6kl_recovery_work(struct work_struct *work) ath6kl_init_hw_restart(ar); ar->state = ATH6KL_STATE_ON; + clear_bit(WMI_CTRL_EP_FULL, &ar->flag); + ar->fw_recovery.err_reason = 0; if (ar->fw_recovery.enable) diff --git a/drivers/net/wireless/ath/ath6kl/txrx.c b/drivers/net/wireless/ath/ath6kl/txrx.c index cbe1a9d8911..e867193373f 100644 --- a/drivers/net/wireless/ath/ath6kl/txrx.c +++ b/drivers/net/wireless/ath/ath6kl/txrx.c @@ -594,6 +594,7 @@ enum htc_send_full_action ath6kl_tx_queue_full(struct htc_target *target, */ set_bit(WMI_CTRL_EP_FULL, &ar->flag); ath6kl_err("wmi ctrl ep is full\n"); + ath6kl_recovery_err_notify(ar, ATH6KL_FW_EP_FULL); return action; } -- cgit v1.2.3-18-g5258 From 9d9188409aef2f3bebd1956d2f15bc970efcea7b Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Mon, 3 Sep 2012 12:49:34 +0530 Subject: ath6kl: Fix bug in scheduling hb_timer hb_timer should be scheduled only when hb_poll is non-zero. But in ath6kl_recovery_work() the timer is scheduled based on fw_recovery.enable instead which is wrong. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/recovery.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath6kl/recovery.c b/drivers/net/wireless/ath/ath6kl/recovery.c index 03edeb8c2ce..c30df50b7ba 100644 --- a/drivers/net/wireless/ath/ath6kl/recovery.c +++ b/drivers/net/wireless/ath/ath6kl/recovery.c @@ -34,7 +34,7 @@ static void ath6kl_recovery_work(struct work_struct *work) ar->fw_recovery.err_reason = 0; - if (ar->fw_recovery.enable) + if (ar->fw_recovery.hb_poll) mod_timer(&ar->fw_recovery.hb_timer, jiffies + msecs_to_jiffies(ar->fw_recovery.hb_poll)); } -- cgit v1.2.3-18-g5258 From e451f947c59d527088ebbd4505e776e968b9539a Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Mon, 3 Sep 2012 12:49:35 +0530 Subject: ath6kl: Remove unnecessary recovery state check in ath6kl_recovery_hb_timer() Checking for recovery state just before re-arming hb_timer is not necessary, this should be done at the begining of the timer instead. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/recovery.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath6kl/recovery.c b/drivers/net/wireless/ath/ath6kl/recovery.c index c30df50b7ba..1a82e8bf03c 100644 --- a/drivers/net/wireless/ath/ath6kl/recovery.c +++ b/drivers/net/wireless/ath/ath6kl/recovery.c @@ -61,7 +61,7 @@ static void ath6kl_recovery_hb_timer(unsigned long data) struct ath6kl *ar = (struct ath6kl *) data; int err; - if (!ar->fw_recovery.enable) + if (!ar->fw_recovery.enable || (ar->state == ATH6KL_STATE_RECOVERY)) return; if (ar->fw_recovery.hb_pending) @@ -86,9 +86,6 @@ static void ath6kl_recovery_hb_timer(unsigned long data) ath6kl_warn("Failed to send hb challenge request, err:%d\n", err); - if ((ar->state == ATH6KL_STATE_RECOVERY) || !ar->fw_recovery.enable) - return; - mod_timer(&ar->fw_recovery.hb_timer, jiffies + msecs_to_jiffies(ar->fw_recovery.hb_poll)); } -- cgit v1.2.3-18-g5258 From a3561706320380027d4ac087e7b92ca19c0150df Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Mon, 3 Sep 2012 12:49:36 +0530 Subject: ath6kl: Add a bit to ath6kl_dev_state for recovery cleanup state Add a bit in ath6kl_dev_state to maintian the run time state of firmware recovery configuration. This would help to have user configuration in fw_recovery which will be added in a separate patch. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/core.h | 2 +- drivers/net/wireless/ath/ath6kl/recovery.c | 12 +++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h index ac90b31514b..40a7b19925d 100644 --- a/drivers/net/wireless/ath/ath6kl/core.h +++ b/drivers/net/wireless/ath/ath6kl/core.h @@ -641,6 +641,7 @@ enum ath6kl_dev_state { SKIP_SCAN, ROAM_TBL_PEND, FIRST_BOOT, + RECOVERY_CLEANUP, }; enum ath6kl_state { @@ -807,7 +808,6 @@ struct ath6kl { bool wiphy_registered; struct ath6kl_fw_recovery { - bool enable; struct work_struct recovery_work; unsigned long err_reason; unsigned long hb_poll; diff --git a/drivers/net/wireless/ath/ath6kl/recovery.c b/drivers/net/wireless/ath/ath6kl/recovery.c index 1a82e8bf03c..98b6aa09e1b 100644 --- a/drivers/net/wireless/ath/ath6kl/recovery.c +++ b/drivers/net/wireless/ath/ath6kl/recovery.c @@ -46,7 +46,8 @@ void ath6kl_recovery_err_notify(struct ath6kl *ar, enum ath6kl_fw_err reason) set_bit(reason, &ar->fw_recovery.err_reason); - if (ar->fw_recovery.enable && ar->state != ATH6KL_STATE_RECOVERY) + if (!test_bit(RECOVERY_CLEANUP, &ar->flag) && + ar->state != ATH6KL_STATE_RECOVERY) queue_work(ar->ath6kl_wq, &ar->fw_recovery.recovery_work); } @@ -61,7 +62,8 @@ static void ath6kl_recovery_hb_timer(unsigned long data) struct ath6kl *ar = (struct ath6kl *) data; int err; - if (!ar->fw_recovery.enable || (ar->state == ATH6KL_STATE_RECOVERY)) + if (test_bit(RECOVERY_CLEANUP, &ar->flag) || + (ar->state == ATH6KL_STATE_RECOVERY)) return; if (ar->fw_recovery.hb_pending) @@ -94,7 +96,7 @@ void ath6kl_recovery_init(struct ath6kl *ar) { struct ath6kl_fw_recovery *recovery = &ar->fw_recovery; - recovery->enable = true; + clear_bit(RECOVERY_CLEANUP, &ar->flag); INIT_WORK(&recovery->recovery_work, ath6kl_recovery_work); recovery->seq_num = 0; recovery->hb_misscnt = 0; @@ -110,7 +112,7 @@ void ath6kl_recovery_init(struct ath6kl *ar) void ath6kl_recovery_cleanup(struct ath6kl *ar) { - ar->fw_recovery.enable = false; + set_bit(RECOVERY_CLEANUP, &ar->flag); del_timer_sync(&ar->fw_recovery.hb_timer); cancel_work_sync(&ar->fw_recovery.recovery_work); @@ -133,7 +135,7 @@ void ath6kl_recovery_suspend(struct ath6kl *ar) void ath6kl_recovery_resume(struct ath6kl *ar) { - ar->fw_recovery.enable = true; + clear_bit(RECOVERY_CLEANUP, &ar->flag); if (!ar->fw_recovery.hb_poll) return; -- cgit v1.2.3-18-g5258 From 66ddcc39420f3c6d2356f7618fbed3dd61177cee Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Mon, 3 Sep 2012 12:49:37 +0530 Subject: ath6kl: Make fw error recovery configurable Add a modparam to configure recovery. Recovery from firmware error is disabled by default to debug the actual issue further. To recovery from error, modprobe ath6kl_core recovery_enable=1. Reported-by: Jin Navy Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/core.c | 12 ++++++++++-- drivers/net/wireless/ath/ath6kl/core.h | 1 + drivers/net/wireless/ath/ath6kl/recovery.c | 12 ++++++++++++ 3 files changed, 23 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath6kl/core.c b/drivers/net/wireless/ath/ath6kl/core.c index fd5dd3aca77..4b46adbe8c9 100644 --- a/drivers/net/wireless/ath/ath6kl/core.c +++ b/drivers/net/wireless/ath/ath6kl/core.c @@ -33,6 +33,7 @@ static unsigned int wow_mode; static unsigned int uart_debug; static unsigned int ath6kl_p2p; static unsigned int testmode; +static unsigned int recovery_enable; static unsigned int heart_beat_poll; module_param(debug_mask, uint, 0644); @@ -41,9 +42,12 @@ module_param(wow_mode, uint, 0644); module_param(uart_debug, uint, 0644); module_param(ath6kl_p2p, uint, 0644); module_param(testmode, uint, 0644); +module_param(recovery_enable, uint, 0644); module_param(heart_beat_poll, uint, 0644); -MODULE_PARM_DESC(heart_beat_poll, "Enable fw error detection periodic" \ - "polling. This also specifies the polling interval in msecs"); +MODULE_PARM_DESC(recovery_enable, "Enable recovery from firmware error"); +MODULE_PARM_DESC(heart_beat_poll, "Enable fw error detection periodic" \ + "polling. This also specifies the polling interval in" \ + "msecs. Set reocvery_enable for this to be effective"); void ath6kl_core_tx_complete(struct ath6kl *ar, struct sk_buff *skb) { @@ -206,6 +210,10 @@ int ath6kl_core_init(struct ath6kl *ar, enum ath6kl_htc_type htc_type) ath6kl_dbg(ATH6KL_DBG_TRC, "%s: name=%s dev=0x%p, ar=0x%p\n", __func__, wdev->netdev->name, wdev->netdev, ar); + ar->fw_recovery.enable = !!recovery_enable; + if (!ar->fw_recovery.enable) + return ret; + if (heart_beat_poll && test_bit(ATH6KL_FW_CAPABILITY_HEART_BEAT_POLL, ar->fw_capabilities)) diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h index 40a7b19925d..3b2dfc18085 100644 --- a/drivers/net/wireless/ath/ath6kl/core.h +++ b/drivers/net/wireless/ath/ath6kl/core.h @@ -815,6 +815,7 @@ struct ath6kl { u32 seq_num; bool hb_pending; u8 hb_misscnt; + bool enable; } fw_recovery; #ifdef CONFIG_ATH6KL_DEBUG diff --git a/drivers/net/wireless/ath/ath6kl/recovery.c b/drivers/net/wireless/ath/ath6kl/recovery.c index 98b6aa09e1b..3a8d5e97dc8 100644 --- a/drivers/net/wireless/ath/ath6kl/recovery.c +++ b/drivers/net/wireless/ath/ath6kl/recovery.c @@ -41,6 +41,9 @@ static void ath6kl_recovery_work(struct work_struct *work) void ath6kl_recovery_err_notify(struct ath6kl *ar, enum ath6kl_fw_err reason) { + if (!ar->fw_recovery.enable) + return; + ath6kl_dbg(ATH6KL_DBG_RECOVERY, "Fw error detected, reason:%d\n", reason); @@ -112,6 +115,9 @@ void ath6kl_recovery_init(struct ath6kl *ar) void ath6kl_recovery_cleanup(struct ath6kl *ar) { + if (!ar->fw_recovery.enable) + return; + set_bit(RECOVERY_CLEANUP, &ar->flag); del_timer_sync(&ar->fw_recovery.hb_timer); @@ -120,6 +126,9 @@ void ath6kl_recovery_cleanup(struct ath6kl *ar) void ath6kl_recovery_suspend(struct ath6kl *ar) { + if (!ar->fw_recovery.enable) + return; + ath6kl_recovery_cleanup(ar); if (!ar->fw_recovery.err_reason) @@ -135,6 +144,9 @@ void ath6kl_recovery_suspend(struct ath6kl *ar) void ath6kl_recovery_resume(struct ath6kl *ar) { + if (!ar->fw_recovery.enable) + return; + clear_bit(RECOVERY_CLEANUP, &ar->flag); if (!ar->fw_recovery.hb_poll) -- cgit v1.2.3-18-g5258 From 527f6570300980251e818e80865b437eefb4e5d3 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Mon, 3 Sep 2012 22:15:36 +0200 Subject: ath6kl: fix uninitialized variable in ath6kl_sdio_enable_scatter() gcc 4.8 warns /backup/lsrc/git/linux-lto-2.6/drivers/net/wireless/ath/ath6kl/sdio.c: In function 'ath6kl_sdio_enable_scatter': /backup/lsrc/git/linux-lto-2.6/drivers/net/wireless/ath/ath6kl/sdio.c:748:16: warning: 'ret' may be used uninitialized in this function [-Wmaybe-uninitialized] if (virt_scat || ret) { ^ The variable can indeed be uninitialized when the previous if branch is skipped. I just set it to zero for now. I'm not fully sure the fix is correct, maybe the || should be an && ? Signed-off-by: Andi Kleen Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/sdio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath6kl/sdio.c b/drivers/net/wireless/ath/ath6kl/sdio.c index a72a4d02a4c..d111980d44c 100644 --- a/drivers/net/wireless/ath/ath6kl/sdio.c +++ b/drivers/net/wireless/ath/ath6kl/sdio.c @@ -709,7 +709,7 @@ static int ath6kl_sdio_enable_scatter(struct ath6kl *ar) { struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar); struct htc_target *target = ar->htc_target; - int ret; + int ret = 0; bool virt_scat = false; if (ar_sdio->scatter_enabled) -- cgit v1.2.3-18-g5258 From f08dbda25f14d6b9c1ba131f65d0c32917733f6c Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Wed, 5 Sep 2012 15:07:29 +0800 Subject: ath6kl: use list_move_tail instead of list_del/list_add_tail Using list_move_tail() instead of list_del() + list_add_tail(). spatch with a semantic match is used to found this problem. (http://coccinelle.lip6.fr/) Signed-off-by: Wei Yongjun Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/htc_pipe.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath6kl/htc_pipe.c b/drivers/net/wireless/ath/ath6kl/htc_pipe.c index f9626c72369..ba6bd497b78 100644 --- a/drivers/net/wireless/ath/ath6kl/htc_pipe.c +++ b/drivers/net/wireless/ath/ath6kl/htc_pipe.c @@ -374,9 +374,8 @@ static enum htc_send_queue_result htc_try_send(struct htc_target *target, packet = list_first_entry(txq, struct htc_packet, list); - list_del(&packet->list); - /* insert into local queue */ - list_add_tail(&packet->list, &send_queue); + /* move to local queue */ + list_move_tail(&packet->list, &send_queue); } /* @@ -399,11 +398,10 @@ static enum htc_send_queue_result htc_try_send(struct htc_target *target, * for cleanup */ } else { /* callback wants to keep this packet, - * remove from caller's queue */ - list_del(&packet->list); - /* put it in the send queue */ - list_add_tail(&packet->list, - &send_queue); + * move from caller's queue to the send + * queue */ + list_move_tail(&packet->list, + &send_queue); } } -- cgit v1.2.3-18-g5258 From 58109df67aa073756eb5a2dc2ae068bc1bbcc125 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Tue, 11 Sep 2012 12:07:00 +0530 Subject: ath6kl: Fix reconnection issue after recovery Disallowing any wmi commands while re-initializing the firmware results in connection failures after recovery is done in open/WEP mode. To fix this, clear WMI_READY, to make sure no wmi command is tried while fw is down. Remove ATH6KL_STATE_RECOVERY state check in ath6kl_control_tx() so that any configuration during fw init time will go through using wmi commands. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/cfg80211.c | 12 +++++++++--- drivers/net/wireless/ath/ath6kl/init.c | 6 +++++- drivers/net/wireless/ath/ath6kl/txrx.c | 3 +-- 3 files changed, 15 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index c8b6be44fa2..530eede4f5e 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -151,6 +151,10 @@ static bool __ath6kl_cfg80211_sscan_stop(struct ath6kl_vif *vif) return false; del_timer_sync(&vif->sched_scan_timer); + + if (ar->state == ATH6KL_STATE_RECOVERY) + return true; + ath6kl_wmi_enable_sched_scan_cmd(ar->wmi, vif->fw_vif_idx, false); return true; @@ -3435,8 +3439,9 @@ void ath6kl_cfg80211_stop(struct ath6kl_vif *vif) break; } - if (test_bit(CONNECTED, &vif->flags) || - test_bit(CONNECT_PEND, &vif->flags)) + if (vif->ar->state != ATH6KL_STATE_RECOVERY && + (test_bit(CONNECTED, &vif->flags) || + test_bit(CONNECT_PEND, &vif->flags))) ath6kl_wmi_disconnect_cmd(vif->ar->wmi, vif->fw_vif_idx); vif->sme_state = SME_DISCONNECTED; @@ -3448,7 +3453,8 @@ void ath6kl_cfg80211_stop(struct ath6kl_vif *vif) netif_carrier_off(vif->ndev); /* disable scanning */ - if (ath6kl_wmi_scanparams_cmd(vif->ar->wmi, vif->fw_vif_idx, 0xFFFF, + if (vif->ar->state != ATH6KL_STATE_RECOVERY && + ath6kl_wmi_scanparams_cmd(vif->ar->wmi, vif->fw_vif_idx, 0xFFFF, 0, 0, 0, 0, 0, 0, 0, 0, 0) != 0) ath6kl_warn("failed to disable scan during stop\n"); diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c index 6e270fa6d63..424676e06b3 100644 --- a/drivers/net/wireless/ath/ath6kl/init.c +++ b/drivers/net/wireless/ath/ath6kl/init.c @@ -1697,10 +1697,14 @@ int ath6kl_init_hw_stop(struct ath6kl *ar) void ath6kl_init_hw_restart(struct ath6kl *ar) { + clear_bit(WMI_READY, &ar->flag); + ath6kl_cfg80211_stop_all(ar); - if (__ath6kl_init_hw_stop(ar)) + if (__ath6kl_init_hw_stop(ar)) { + ath6kl_dbg(ATH6KL_DBG_RECOVERY, "Failed to stop during fw error recovery\n"); return; + } if (__ath6kl_init_hw_start(ar)) { ath6kl_dbg(ATH6KL_DBG_RECOVERY, "Failed to restart during fw error recovery\n"); diff --git a/drivers/net/wireless/ath/ath6kl/txrx.c b/drivers/net/wireless/ath/ath6kl/txrx.c index e867193373f..efee590a234 100644 --- a/drivers/net/wireless/ath/ath6kl/txrx.c +++ b/drivers/net/wireless/ath/ath6kl/txrx.c @@ -288,8 +288,7 @@ int ath6kl_control_tx(void *devt, struct sk_buff *skb, int status = 0; struct ath6kl_cookie *cookie = NULL; - if (WARN_ON_ONCE(ar->state == ATH6KL_STATE_WOW) || - ar->state == ATH6KL_STATE_RECOVERY) { + if (WARN_ON_ONCE(ar->state == ATH6KL_STATE_WOW)) { dev_kfree_skb(skb); return -EACCES; } -- cgit v1.2.3-18-g5258 From 43a06b346d1350009c8f7eaa1a2a137395874ca0 Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Fri, 21 Sep 2012 15:08:53 +0530 Subject: ath6kl: Avoid null ptr dereference while printing reg domain pair Return value of ath6kl_get_regpair() is stored in 'regpair' in ath6kl_wmi_regdomain_event() func and it's directly accessed in the debug prints without checking for NULL value. There are situation to get NULL pointer as a return value from ath6kl_get_regpair() func. Fix this. Found this on code review. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/wmi.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index 68b46bda498..64b81fd554b 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -936,8 +936,12 @@ static void ath6kl_wmi_regdomain_event(struct wmi *wmi, u8 *datap, int len) regpair = ath6kl_get_regpair((u16) reg_code); country = ath6kl_regd_find_country_by_rd((u16) reg_code); - ath6kl_dbg(ATH6KL_DBG_WMI, "Regpair used: 0x%0x\n", - regpair->regDmnEnum); + if (regpair) + ath6kl_dbg(ATH6KL_DBG_WMI, "Regpair used: 0x%0x\n", + regpair->regDmnEnum); + else + ath6kl_warn("Regpair not found reg_code 0x%0x\n", + reg_code); } if (country && wmi->parent_dev->wiphy_registered) { -- cgit v1.2.3-18-g5258 From d54601b92fbde2a7021a844e1373ba8c778cc0a3 Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Fri, 21 Sep 2012 15:08:54 +0530 Subject: ath6kl: Check for valid rate table index There are 28 items defined in rate table array 'wmi_rate_tbl'. The rate table index (reply->rate_index) in ath6kl_wmi_bitrate_reply_rx() func is not checked for the valid max limit index before accessing rate table array. There may be some incidents to get memory crashes without safe max check. Fix this. Found this on code review. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/wmi.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index 64b81fd554b..f3aeebb2fd4 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -1174,6 +1174,9 @@ static int ath6kl_wmi_bitrate_reply_rx(struct wmi *wmi, u8 *datap, int len) rate = RATE_AUTO; } else { index = reply->rate_index & 0x7f; + if (WARN_ON_ONCE(index > (RATE_MCS_7_40 + 1))) + return -EINVAL; + sgi = (reply->rate_index & 0x80) ? 1 : 0; rate = wmi_rate_tbl[index][sgi]; } -- cgit v1.2.3-18-g5258 From 363f149ce37bea91069177eab691111b242bfe73 Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Fri, 21 Sep 2012 15:08:55 +0530 Subject: ath6kl: Check for valid endpoint ID values in ath6kl_control_tx() It's safe to check endpoint id values before it get really used. Found this on code review. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/txrx.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath6kl/txrx.c b/drivers/net/wireless/ath/ath6kl/txrx.c index efee590a234..cf4380d573c 100644 --- a/drivers/net/wireless/ath/ath6kl/txrx.c +++ b/drivers/net/wireless/ath/ath6kl/txrx.c @@ -293,6 +293,12 @@ int ath6kl_control_tx(void *devt, struct sk_buff *skb, return -EACCES; } + if (WARN_ON_ONCE(eid == ENDPOINT_UNUSED || + eid >= ENDPOINT_MAX)) { + status = -EINVAL; + goto fail_ctrl_tx; + } + spin_lock_bh(&ar->lock); ath6kl_dbg(ATH6KL_DBG_WLAN_TX, -- cgit v1.2.3-18-g5258 From baec5c6d0b191a44977a5fca131b5215e1868341 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Fri, 21 Sep 2012 12:45:24 +0530 Subject: ath6kl: Fix random rx data corruption The skb->tail pointer of rx buffers is not adjusted after skb->data pointer is aligned to 4-byte, this causes random rx data corruption. Signed-off-by: Jin Navy Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/txrx.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath6kl/txrx.c b/drivers/net/wireless/ath/ath6kl/txrx.c index cf4380d573c..c4501a9f051 100644 --- a/drivers/net/wireless/ath/ath6kl/txrx.c +++ b/drivers/net/wireless/ath/ath6kl/txrx.c @@ -894,8 +894,11 @@ void ath6kl_rx_refill(struct htc_target *target, enum htc_endpoint_id endpoint) break; packet = (struct htc_packet *) skb->head; - if (!IS_ALIGNED((unsigned long) skb->data, 4)) + if (!IS_ALIGNED((unsigned long) skb->data, 4)) { + size_t len = skb_headlen(skb); skb->data = PTR_ALIGN(skb->data - 4, 4); + skb_set_tail_pointer(skb, len); + } set_htc_rxpkt_info(packet, skb, skb->data, ATH6KL_BUFFER_SIZE, endpoint); packet->skb = skb; @@ -917,8 +920,11 @@ void ath6kl_refill_amsdu_rxbufs(struct ath6kl *ar, int count) return; packet = (struct htc_packet *) skb->head; - if (!IS_ALIGNED((unsigned long) skb->data, 4)) + if (!IS_ALIGNED((unsigned long) skb->data, 4)) { + size_t len = skb_headlen(skb); skb->data = PTR_ALIGN(skb->data - 4, 4); + skb_set_tail_pointer(skb, len); + } set_htc_rxpkt_info(packet, skb, skb->data, ATH6KL_AMSDU_BUFFER_SIZE, 0); packet->skb = skb; -- cgit v1.2.3-18-g5258 From 07033ce2fbfb8d27663d1cd1e9ce36b9661007e0 Mon Sep 17 00:00:00 2001 From: Pandiyarajan Pitchaimuthu Date: Fri, 21 Sep 2012 15:06:14 +0530 Subject: ath6kl: Max clients reached notification When a station requests connection to an AP, that has already been connected to the maximum number of stations it can support, an event is sent to user space via NL80211_CMD_CONN_FAILED command and reason attribute NL80211_ATTR_CONN_FAILED_REASON with NL80211_CONN_FAIL_MAX_CLIENTS as reason. Signed-off-by: Pandiyarajan Pitchaimuthu Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/main.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath6kl/main.c b/drivers/net/wireless/ath/ath6kl/main.c index 9533558a623..cc2749a9e7f 100644 --- a/drivers/net/wireless/ath/ath6kl/main.c +++ b/drivers/net/wireless/ath/ath6kl/main.c @@ -1004,6 +1004,13 @@ void ath6kl_disconnect_event(struct ath6kl_vif *vif, u8 reason, u8 *bssid, ar->last_ch = le16_to_cpu(vif->profile.ch); } + if (prot_reason_status == WMI_AP_REASON_MAX_STA) { + /* send max client reached notification to user space */ + cfg80211_conn_failed(vif->ndev, bssid, + NL80211_CONN_FAIL_MAX_CLIENTS, + GFP_KERNEL); + } + if (!ath6kl_remove_sta(ar, bssid, prot_reason_status)) return; -- cgit v1.2.3-18-g5258 From 698bf867d0d3b5669c4e85b29d2a44043a2c5c99 Mon Sep 17 00:00:00 2001 From: Pandiyarajan Pitchaimuthu Date: Fri, 21 Sep 2012 15:08:53 +0530 Subject: ath6kl: Blocked client notification When a station tries to connect to an AP and if the MAC of the station is in the AP's block list, the station cannot connect to the AP. This is notified to the userspace with event NL80211_CMD_CONN_FAILED and attribute NL80211_ATTR_CONN_FAILED_REASON. The reason sent will be NL80211_CONN_FAIL_BLOCKED_CLIENT. Signed-off-by: Pandiyarajan Pitchaimuthu Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/main.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath6kl/main.c b/drivers/net/wireless/ath/ath6kl/main.c index cc2749a9e7f..bd50b6b7b49 100644 --- a/drivers/net/wireless/ath/ath6kl/main.c +++ b/drivers/net/wireless/ath/ath6kl/main.c @@ -1011,6 +1011,13 @@ void ath6kl_disconnect_event(struct ath6kl_vif *vif, u8 reason, u8 *bssid, GFP_KERNEL); } + if (prot_reason_status == WMI_AP_REASON_ACL) { + /* send blocked client notification to user space */ + cfg80211_conn_failed(vif->ndev, bssid, + NL80211_CONN_FAIL_BLOCKED_CLIENT, + GFP_KERNEL); + } + if (!ath6kl_remove_sta(ar, bssid, prot_reason_status)) return; -- cgit v1.2.3-18-g5258 From 86aa7c1efc63e0969dee575ac9e021dbcbaa95c3 Mon Sep 17 00:00:00 2001 From: Pandiyarajan Pitchaimuthu Date: Fri, 21 Sep 2012 20:11:46 +0530 Subject: ath6kl: Array index out of bounds check The variable assigned_ep can be assigned value of -1 and is never checked if it equals -1. So the endpoint array can have -1 as the index value and can be out of bounds. The value of assigned_ep is checked for -1 and is ensured that the endpoint array doesn't go out of bounds. Signed-off-by: Pandiyarajan Pitchaimuthu Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/htc_mbox.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath6kl/htc_mbox.c b/drivers/net/wireless/ath/ath6kl/htc_mbox.c index cd0e1ba410d..ceaf9219265 100644 --- a/drivers/net/wireless/ath/ath6kl/htc_mbox.c +++ b/drivers/net/wireless/ath/ath6kl/htc_mbox.c @@ -2492,7 +2492,8 @@ static int ath6kl_htc_mbox_conn_service(struct htc_target *target, max_msg_sz = le16_to_cpu(resp_msg->max_msg_sz); } - if (assigned_ep >= ENDPOINT_MAX || !max_msg_sz) { + if (WARN_ON_ONCE(assigned_ep == ENDPOINT_UNUSED || + assigned_ep >= ENDPOINT_MAX || !max_msg_sz)) { status = -ENOMEM; goto fail_tx; } -- cgit v1.2.3-18-g5258 From 307749406d7daea452d55df76f734b4fffddf599 Mon Sep 17 00:00:00 2001 From: Pandiyarajan Pitchaimuthu Date: Fri, 21 Sep 2012 20:13:09 +0530 Subject: ath6kl: Check for valid endpoint ID in ath6kl_tx_complete() Endpoint ID is checked to make sure it is valid. Signed-off-by: Pandiyarajan Pitchaimuthu Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/txrx.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath6kl/txrx.c b/drivers/net/wireless/ath/ath6kl/txrx.c index c4501a9f051..78b36928657 100644 --- a/drivers/net/wireless/ath/ath6kl/txrx.c +++ b/drivers/net/wireless/ath/ath6kl/txrx.c @@ -704,6 +704,10 @@ void ath6kl_tx_complete(struct htc_target *target, list); list_del(&packet->list); + if (WARN_ON_ONCE(packet->endpoint == ENDPOINT_UNUSED || + packet->endpoint >= ENDPOINT_MAX)) + continue; + ath6kl_cookie = (struct ath6kl_cookie *)packet->pkt_cntxt; if (WARN_ON_ONCE(!ath6kl_cookie)) continue; -- cgit v1.2.3-18-g5258 From cf0dfa1330495ae2c3757788224cc043cfb17e77 Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Thu, 27 Sep 2012 18:19:48 +0530 Subject: ath6kl: Remove obselete USB device related checks These checks are no longer needed as the necessary USB support is already present in the driver. Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/hif.c | 5 ----- drivers/net/wireless/ath/ath6kl/htc_mbox.c | 10 +--------- 2 files changed, 1 insertion(+), 14 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath6kl/hif.c b/drivers/net/wireless/ath/ath6kl/hif.c index 029914a22ea..a7a1ec40636 100644 --- a/drivers/net/wireless/ath/ath6kl/hif.c +++ b/drivers/net/wireless/ath/ath6kl/hif.c @@ -696,11 +696,6 @@ int ath6kl_hif_setup(struct ath6kl_device *dev) ath6kl_dbg(ATH6KL_DBG_HIF, "hif block size %d mbox addr 0x%x\n", dev->htc_cnxt->block_sz, dev->ar->mbox_info.htc_addr); - /* usb doesn't support enabling interrupts */ - /* FIXME: remove check once USB support is implemented */ - if (dev->ar->hif_type == ATH6KL_HIF_TYPE_USB) - return 0; - status = ath6kl_hif_disable_intrs(dev); fail_setup: diff --git a/drivers/net/wireless/ath/ath6kl/htc_mbox.c b/drivers/net/wireless/ath/ath6kl/htc_mbox.c index ceaf9219265..fbb78dfe078 100644 --- a/drivers/net/wireless/ath/ath6kl/htc_mbox.c +++ b/drivers/net/wireless/ath/ath6kl/htc_mbox.c @@ -2656,12 +2656,6 @@ static int ath6kl_htc_mbox_wait_target(struct htc_target *target) struct htc_service_connect_resp resp; int status; - /* FIXME: remove once USB support is implemented */ - if (target->dev->ar->hif_type == ATH6KL_HIF_TYPE_USB) { - ath6kl_err("HTC doesn't support USB yet. Patience!\n"); - return -EOPNOTSUPP; - } - /* we should be getting 1 control message that the target is ready */ packet = htc_wait_for_ctrl_msg(target); @@ -2891,9 +2885,7 @@ static void ath6kl_htc_mbox_cleanup(struct htc_target *target) { struct htc_packet *packet, *tmp_packet; - /* FIXME: remove check once USB support is implemented */ - if (target->dev->ar->hif_type != ATH6KL_HIF_TYPE_USB) - ath6kl_hif_cleanup_scatter(target->dev->ar); + ath6kl_hif_cleanup_scatter(target->dev->ar); list_for_each_entry_safe(packet, tmp_packet, &target->free_ctrl_txbuf, list) { -- cgit v1.2.3-18-g5258 From 5dbdf6feecad54b739cb7a5cff521fba86cabba5 Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Thu, 27 Sep 2012 18:19:49 +0530 Subject: ath6kl: Return error case when ath6kl_usb_alloc_pipe_resources fails Incase the resource allocation for the struct ath6kl_urb_context in the function ath6kl_usb_alloc_pipe_resources fails, return this error case so that ath6kl_usb_probe is aware of this error case. Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/usb.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath6kl/usb.c b/drivers/net/wireless/ath/ath6kl/usb.c index a6d13775467..2014fac4274 100644 --- a/drivers/net/wireless/ath/ath6kl/usb.c +++ b/drivers/net/wireless/ath/ath6kl/usb.c @@ -185,9 +185,10 @@ static int ath6kl_usb_alloc_pipe_resources(struct ath6kl_usb_pipe *pipe, for (i = 0; i < urb_cnt; i++) { urb_context = kzalloc(sizeof(struct ath6kl_urb_context), GFP_KERNEL); - if (urb_context == NULL) - /* FIXME: set status to -ENOMEM */ - break; + if (urb_context == NULL) { + status = -ENOMEM; + goto fail_alloc_pipe_resources; + } urb_context->pipe = pipe; @@ -204,6 +205,7 @@ static int ath6kl_usb_alloc_pipe_resources(struct ath6kl_usb_pipe *pipe, pipe->logical_pipe_num, pipe->usb_pipe_handle, pipe->urb_alloc); +fail_alloc_pipe_resources: return status; } -- cgit v1.2.3-18-g5258 From c0b34e2b41cc29c15b4cf247727efdab6a864c1b Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Thu, 27 Sep 2012 18:19:50 +0530 Subject: ath6kl: Rename ATH6KL_HW_FLAG_64BIT_RATES Rename ATH6KL_HW_FLAG_64BIT_RATES to ATH6KL_HW_64BIT_RATES. This seemed to be necessary to add/use new hardware flags without exceeding 80 lines. We shall be adding new hw flags dropping the FLAG term. Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/cfg80211.c | 2 +- drivers/net/wireless/ath/ath6kl/core.h | 2 +- drivers/net/wireless/ath/ath6kl/init.c | 8 ++++---- drivers/net/wireless/ath/ath6kl/wmi.c | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index 530eede4f5e..6d143e453f9 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -3708,7 +3708,7 @@ int ath6kl_cfg80211_init(struct ath6kl *ar) ath6kl_band_5ghz.ht_cap.ht_supported = false; } - if (ar->hw.flags & ATH6KL_HW_FLAG_64BIT_RATES) { + if (ar->hw.flags & ATH6KL_HW_64BIT_RATES) { ath6kl_band_2ghz.ht_cap.mcs.rx_mask[0] = 0xff; ath6kl_band_5ghz.ht_cap.mcs.rx_mask[0] = 0xff; ath6kl_band_2ghz.ht_cap.mcs.rx_mask[1] = 0xff; diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h index 3b2dfc18085..fc5e4b25818 100644 --- a/drivers/net/wireless/ath/ath6kl/core.h +++ b/drivers/net/wireless/ath/ath6kl/core.h @@ -149,7 +149,7 @@ struct ath6kl_fw_ie { }; enum ath6kl_hw_flags { - ATH6KL_HW_FLAG_64BIT_RATES = BIT(0), + ATH6KL_HW_64BIT_RATES = BIT(0), }; #define ATH6KL_FW_API2_FILE "fw-2.bin" diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c index 424676e06b3..18550c51e12 100644 --- a/drivers/net/wireless/ath/ath6kl/init.c +++ b/drivers/net/wireless/ath/ath6kl/init.c @@ -93,7 +93,7 @@ static const struct ath6kl_hw hw_list[] = { .board_addr = 0x433900, .refclk_hz = 26000000, .uarttx_pin = 11, - .flags = ATH6KL_HW_FLAG_64BIT_RATES, + .flags = ATH6KL_HW_64BIT_RATES, .fw = { .dir = AR6004_HW_1_0_FW_DIR, @@ -113,7 +113,7 @@ static const struct ath6kl_hw hw_list[] = { .board_addr = 0x43d400, .refclk_hz = 40000000, .uarttx_pin = 11, - .flags = ATH6KL_HW_FLAG_64BIT_RATES, + .flags = ATH6KL_HW_64BIT_RATES, .fw = { .dir = AR6004_HW_1_1_FW_DIR, @@ -133,7 +133,7 @@ static const struct ath6kl_hw hw_list[] = { .board_addr = 0x435c00, .refclk_hz = 40000000, .uarttx_pin = 11, - .flags = ATH6KL_HW_FLAG_64BIT_RATES, + .flags = ATH6KL_HW_64BIT_RATES, .fw = { .dir = AR6004_HW_1_2_FW_DIR, @@ -152,7 +152,7 @@ static const struct ath6kl_hw hw_list[] = { .board_addr = 0x436400, .refclk_hz = 40000000, .uarttx_pin = 11, - .flags = ATH6KL_HW_FLAG_64BIT_RATES, + .flags = ATH6KL_HW_64BIT_RATES, .fw = { .dir = AR6004_HW_1_3_FW_DIR, diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index f3aeebb2fd4..55ccf977033 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -2828,7 +2828,7 @@ int ath6kl_wmi_set_bitrate_mask(struct wmi *wmi, u8 if_idx, { struct ath6kl *ar = wmi->parent_dev; - if (ar->hw.flags & ATH6KL_HW_FLAG_64BIT_RATES) + if (ar->hw.flags & ATH6KL_HW_64BIT_RATES) return ath6kl_set_bitrate_mask64(wmi, if_idx, mask); else return ath6kl_set_bitrate_mask32(wmi, if_idx, mask); -- cgit v1.2.3-18-g5258 From 7ac25eacc6766617edaac69d928f431a9983ccf2 Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Thu, 27 Sep 2012 18:19:51 +0530 Subject: ath6kl: Fix inactivity timeout for AR6004 Currently AR6004 handles the inactivity timeout resolution in minutes rather than seconds. So parse the inactivity timeout to the firmware in minutes. For now we will cleanup the inactive station entries to the nearest converted minutes (ex: an inactive time of 70 seconds would take atleast 2 - 3 minutes) Tested with surprise removal of client cards/host shutdown. Cc: Manikandan Radhakrishnan Reported-by: Leela Kella Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/cfg80211.c | 10 +++++++++- drivers/net/wireless/ath/ath6kl/core.h | 3 ++- drivers/net/wireless/ath/ath6kl/init.c | 13 ++++++++----- 3 files changed, 19 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index 6d143e453f9..bf5e7d51939 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -2760,6 +2760,7 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev, int res; int i, ret; u16 rsn_capab = 0; + int inactivity_timeout = 0; ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s:\n", __func__); @@ -2896,8 +2897,15 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev, } if (info->inactivity_timeout) { + + inactivity_timeout = info->inactivity_timeout; + + if (ar->hw.flags & ATH6KL_HW_AP_INACTIVITY_MINS) + inactivity_timeout = DIV_ROUND_UP(inactivity_timeout, + 60); + res = ath6kl_wmi_set_inact_period(ar->wmi, vif->fw_vif_idx, - info->inactivity_timeout); + inactivity_timeout); if (res < 0) return res; } diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h index fc5e4b25818..95fc9b37e6a 100644 --- a/drivers/net/wireless/ath/ath6kl/core.h +++ b/drivers/net/wireless/ath/ath6kl/core.h @@ -149,7 +149,8 @@ struct ath6kl_fw_ie { }; enum ath6kl_hw_flags { - ATH6KL_HW_64BIT_RATES = BIT(0), + ATH6KL_HW_64BIT_RATES = BIT(0), + ATH6KL_HW_AP_INACTIVITY_MINS = BIT(1), }; #define ATH6KL_FW_API2_FILE "fw-2.bin" diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c index 18550c51e12..7ffb8533986 100644 --- a/drivers/net/wireless/ath/ath6kl/init.c +++ b/drivers/net/wireless/ath/ath6kl/init.c @@ -93,7 +93,8 @@ static const struct ath6kl_hw hw_list[] = { .board_addr = 0x433900, .refclk_hz = 26000000, .uarttx_pin = 11, - .flags = ATH6KL_HW_64BIT_RATES, + .flags = ATH6KL_HW_64BIT_RATES | + ATH6KL_HW_AP_INACTIVITY_MINS, .fw = { .dir = AR6004_HW_1_0_FW_DIR, @@ -113,8 +114,8 @@ static const struct ath6kl_hw hw_list[] = { .board_addr = 0x43d400, .refclk_hz = 40000000, .uarttx_pin = 11, - .flags = ATH6KL_HW_64BIT_RATES, - + .flags = ATH6KL_HW_64BIT_RATES | + ATH6KL_HW_AP_INACTIVITY_MINS, .fw = { .dir = AR6004_HW_1_1_FW_DIR, .fw = AR6004_HW_1_1_FIRMWARE_FILE, @@ -133,7 +134,8 @@ static const struct ath6kl_hw hw_list[] = { .board_addr = 0x435c00, .refclk_hz = 40000000, .uarttx_pin = 11, - .flags = ATH6KL_HW_64BIT_RATES, + .flags = ATH6KL_HW_64BIT_RATES | + ATH6KL_HW_AP_INACTIVITY_MINS, .fw = { .dir = AR6004_HW_1_2_FW_DIR, @@ -152,7 +154,8 @@ static const struct ath6kl_hw hw_list[] = { .board_addr = 0x436400, .refclk_hz = 40000000, .uarttx_pin = 11, - .flags = ATH6KL_HW_64BIT_RATES, + .flags = ATH6KL_HW_64BIT_RATES | + ATH6KL_HW_AP_INACTIVITY_MINS, .fw = { .dir = AR6004_HW_1_3_FW_DIR, -- cgit v1.2.3-18-g5258 From 171fe76877d3d8071a901e64eb63eeee6c7760a2 Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Thu, 27 Sep 2012 18:19:52 +0530 Subject: ath6kl: Fix mapping uplink endpoint for AR6004 AR6004(UB134) firmware supports only LP Endpoint, So map all Access Categories to Low Priority endpoints. This fixes a WPA2 connection issue as the uplink(tx) endpoint is appropriately mapped in sync with the firmware. Tested-by: Ben Gray Reported-by: Ben Gray Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/core.h | 1 + drivers/net/wireless/ath/ath6kl/init.c | 5 +++-- drivers/net/wireless/ath/ath6kl/usb.c | 12 ++++++++++-- 3 files changed, 14 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h index 95fc9b37e6a..1778bd3c732 100644 --- a/drivers/net/wireless/ath/ath6kl/core.h +++ b/drivers/net/wireless/ath/ath6kl/core.h @@ -151,6 +151,7 @@ struct ath6kl_fw_ie { enum ath6kl_hw_flags { ATH6KL_HW_64BIT_RATES = BIT(0), ATH6KL_HW_AP_INACTIVITY_MINS = BIT(1), + ATH6KL_HW_MAP_LP_ENDPOINT = BIT(2), }; #define ATH6KL_FW_API2_FILE "fw-2.bin" diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c index 7ffb8533986..bb6aeea1c87 100644 --- a/drivers/net/wireless/ath/ath6kl/init.c +++ b/drivers/net/wireless/ath/ath6kl/init.c @@ -155,7 +155,8 @@ static const struct ath6kl_hw hw_list[] = { .refclk_hz = 40000000, .uarttx_pin = 11, .flags = ATH6KL_HW_64BIT_RATES | - ATH6KL_HW_AP_INACTIVITY_MINS, + ATH6KL_HW_AP_INACTIVITY_MINS | + ATH6KL_HW_MAP_LP_ENDPOINT, .fw = { .dir = AR6004_HW_1_3_FW_DIR, @@ -360,7 +361,7 @@ static int ath6kl_init_service_ep(struct ath6kl *ar) if (ath6kl_connectservice(ar, &connect, "WMI DATA BK")) return -EIO; - /* connect to Video service, map this to to HI PRI */ + /* connect to Video service, map this to HI PRI */ connect.svc_id = WMI_DATA_VI_SVC; if (ath6kl_connectservice(ar, &connect, "WMI DATA VI")) return -EIO; diff --git a/drivers/net/wireless/ath/ath6kl/usb.c b/drivers/net/wireless/ath/ath6kl/usb.c index 2014fac4274..62bcc0d5bc2 100644 --- a/drivers/net/wireless/ath/ath6kl/usb.c +++ b/drivers/net/wireless/ath/ath6kl/usb.c @@ -805,7 +805,11 @@ static int ath6kl_usb_map_service_pipe(struct ath6kl *ar, u16 svc_id, *dl_pipe = ATH6KL_USB_PIPE_RX_DATA; break; case WMI_DATA_VI_SVC: - *ul_pipe = ATH6KL_USB_PIPE_TX_DATA_MP; + + if (ar->hw.flags & ATH6KL_HW_MAP_LP_ENDPOINT) + *ul_pipe = ATH6KL_USB_PIPE_TX_DATA_LP; + else + *ul_pipe = ATH6KL_USB_PIPE_TX_DATA_MP; /* * Disable rxdata2 directly, it will be enabled * if FW enable rxdata2 @@ -813,7 +817,11 @@ static int ath6kl_usb_map_service_pipe(struct ath6kl *ar, u16 svc_id, *dl_pipe = ATH6KL_USB_PIPE_RX_DATA; break; case WMI_DATA_VO_SVC: - *ul_pipe = ATH6KL_USB_PIPE_TX_DATA_HP; + + if (ar->hw.flags & ATH6KL_HW_MAP_LP_ENDPOINT) + *ul_pipe = ATH6KL_USB_PIPE_TX_DATA_LP; + else + *ul_pipe = ATH6KL_USB_PIPE_TX_DATA_MP; /* * Disable rxdata2 directly, it will be enabled * if FW enable rxdata2 -- cgit v1.2.3-18-g5258 From a2e1be33a2a762a30e2960c11634a672cdf131cb Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Thu, 27 Sep 2012 18:19:53 +0530 Subject: ath6kl: Add a hardware flag for SDIO CRC error workaround Make use of SDIO CRC error workaround hardware flag and avoid target revision checks. Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/core.h | 1 + drivers/net/wireless/ath/ath6kl/init.c | 7 +++---- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h index 1778bd3c732..189d8faf8c8 100644 --- a/drivers/net/wireless/ath/ath6kl/core.h +++ b/drivers/net/wireless/ath/ath6kl/core.h @@ -152,6 +152,7 @@ enum ath6kl_hw_flags { ATH6KL_HW_64BIT_RATES = BIT(0), ATH6KL_HW_AP_INACTIVITY_MINS = BIT(1), ATH6KL_HW_MAP_LP_ENDPOINT = BIT(2), + ATH6KL_HW_SDIO_CRC_ERROR_WAR = BIT(3), }; #define ATH6KL_FW_API2_FILE "fw-2.bin" diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c index bb6aeea1c87..f21fa322e5c 100644 --- a/drivers/net/wireless/ath/ath6kl/init.c +++ b/drivers/net/wireless/ath/ath6kl/init.c @@ -42,7 +42,7 @@ static const struct ath6kl_hw hw_list[] = { .reserved_ram_size = 6912, .refclk_hz = 26000000, .uarttx_pin = 8, - .flags = 0, + .flags = ATH6KL_HW_SDIO_CRC_ERROR_WAR, /* hw2.0 needs override address hardcoded */ .app_start_override_addr = 0x944C00, @@ -68,7 +68,7 @@ static const struct ath6kl_hw hw_list[] = { .refclk_hz = 26000000, .uarttx_pin = 8, .testscript_addr = 0x57ef74, - .flags = 0, + .flags = ATH6KL_HW_SDIO_CRC_ERROR_WAR, .fw = { .dir = AR6003_HW_2_1_1_FW_DIR, @@ -1431,8 +1431,7 @@ static int ath6kl_init_upload(struct ath6kl *ar) return status; /* WAR to avoid SDIO CRC err */ - if (ar->version.target_ver == AR6003_HW_2_0_VERSION || - ar->version.target_ver == AR6003_HW_2_1_1_VERSION) { + if (ar->hw.flags & ATH6KL_HW_SDIO_CRC_ERROR_WAR) { ath6kl_err("temporary war to avoid sdio crc error\n"); param = 0x28; -- cgit v1.2.3-18-g5258 From e0509d3bdd7365d06c9bf570bf9f118cae6cbd58 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Tue, 11 Sep 2012 23:18:34 +0200 Subject: carl9170: fix spurious transmissions in sniffer mode Several people have complained about an unusual and undocumented feature of the AR9170 hardware: In siffer mode, the hardware generates spurious ACK frames for every received frame... even broadcasts. The reason for this malfunction is unknown: But there's a workaround: Instead of the special sniffer mode, the hardware will be put into station mode and all rx filters are disabled. Reported-by: Johannes Berg Reported-by: Marco Fonseca Reported-by: Janusz Dziedzic Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/ath/carl9170/mac.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/carl9170/mac.c b/drivers/net/wireless/ath/carl9170/mac.c index e3b1b6e8776..24d75ab94f0 100644 --- a/drivers/net/wireless/ath/carl9170/mac.c +++ b/drivers/net/wireless/ath/carl9170/mac.c @@ -343,7 +343,24 @@ int carl9170_set_operating_mode(struct ar9170 *ar) break; } } else { - mac_addr = NULL; + /* + * Enable monitor mode + * + * rx_ctrl |= AR9170_MAC_RX_CTRL_ACK_IN_SNIFFER; + * sniffer |= AR9170_MAC_SNIFFER_ENABLE_PROMISC; + * + * When the hardware is in SNIFFER_PROMISC mode, + * it generates spurious ACKs for every incoming + * frame. This confuses every peer in the + * vicinity and the network throughput will suffer + * badly. + * + * Hence, the hardware will be put into station + * mode and just the rx filters are disabled. + */ + cam_mode |= AR9170_MAC_CAM_STA; + rx_ctrl |= AR9170_MAC_RX_CTRL_PASS_TO_HOST; + mac_addr = common->macaddr; bssid = NULL; } rcu_read_unlock(); @@ -355,8 +372,6 @@ int carl9170_set_operating_mode(struct ar9170 *ar) enc_mode |= AR9170_MAC_ENCRYPTION_RX_SOFTWARE; if (ar->sniffer_enabled) { - rx_ctrl |= AR9170_MAC_RX_CTRL_ACK_IN_SNIFFER; - sniffer |= AR9170_MAC_SNIFFER_ENABLE_PROMISC; enc_mode |= AR9170_MAC_ENCRYPTION_RX_SOFTWARE; } -- cgit v1.2.3-18-g5258 From be41b052029f75a72df3c437a238bf9d574b6461 Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Mon, 8 Oct 2012 21:30:51 +0530 Subject: ath9k: Ensure we set FTP_STOMP_LOW weight when WLAN is idle When WLAN is idle ensure we downgrade to FTP_STOMP_LOW weight (from STOMP_LOW) to provide more bandwidth for BT FTP profile. WLAN's idleness can be estimated by taking into account of the rx data packets and just ignore beacons, qos nullfunc etc. Also update bt_wait_time even if the chip is in NETWORK SLEEP mode. This should help BT throughput when WLAN is idle. Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/gpio.c | 2 +- drivers/net/wireless/ath/ath9k/recv.c | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c index bf4fb7db15e..9e63a03330c 100644 --- a/drivers/net/wireless/ath/ath9k/gpio.c +++ b/drivers/net/wireless/ath/ath9k/gpio.c @@ -193,7 +193,6 @@ static void ath_mci_ftp_adjust(struct ath_softc *sc) struct ath_mci_profile *mci = &btcoex->mci; struct ath_hw *ah = sc->sc_ah; - btcoex->bt_wait_time += btcoex->btcoex_period; if (btcoex->bt_wait_time > ATH_BTCOEX_RX_WAIT_TIME) { if (ar9003_mci_state(ah, MCI_STATE_NEED_FTP_STOMP) && (mci->num_pan || mci->num_other_acl)) @@ -222,6 +221,7 @@ static void ath_btcoex_period_timer(unsigned long data) spin_lock_irqsave(&sc->sc_pm_lock, flags); if (sc->sc_ah->power_mode == ATH9K_PM_NETWORK_SLEEP) { + btcoex->bt_wait_time += btcoex->btcoex_period; spin_unlock_irqrestore(&sc->sc_pm_lock, flags); goto skip_hw_wakeup; } diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 83d16e7ed27..a04028bce28 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -1105,7 +1105,10 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) else rs.is_mybeacon = false; - sc->rx.num_pkts++; + if (ieee80211_is_data_present(hdr->frame_control) && + !ieee80211_is_qos_nullfunc(hdr->frame_control)) + sc->rx.num_pkts++; + ath_debug_stat_rx(sc, &rs); /* -- cgit v1.2.3-18-g5258 From 8b0b6be5cb83e871adf8a134e843c01d75b1d128 Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Mon, 8 Oct 2012 21:30:52 +0530 Subject: ath9k_htc: Advertise interface combinations supported This will allow us to create virtual interface the driver supports. Also this ensures multivif support and limitation advertised by the driver is taken care in cfg80211 itself. Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/htc_drv_init.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index d98255eb1b9..5ecf1287ddd 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -694,6 +694,20 @@ err_hw: return ret; } +static const struct ieee80211_iface_limit if_limits[] = { + { .max = 2, .types = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_P2P_CLIENT) }, + { .max = 2, .types = BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_P2P_GO) }, +}; + +static const struct ieee80211_iface_combination if_comb = { + .limits = if_limits, + .n_limits = ARRAY_SIZE(if_limits), + .max_interfaces = 2, + .num_different_channels = 1, +}; + static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv, struct ieee80211_hw *hw) { @@ -716,6 +730,9 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv, BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_P2P_CLIENT); + hw->wiphy->iface_combinations = &if_comb; + hw->wiphy->n_iface_combinations = 1; + hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN | -- cgit v1.2.3-18-g5258 From 96f99d3db736ad0ac275bfec6f83240b1b3019ec Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Mon, 8 Oct 2012 21:30:53 +0530 Subject: ath9k_htc: Remove interface combination specific checks Once the driver advertizes interface combination logic based on its firmware/hardware limitation, cfg80211 takes care of all the necessary logic such as maximum beaconing vifs, standlone interface etc. Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/htc_drv_main.c | 20 -------------------- 1 file changed, 20 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index ca78e33ca23..66f6a74c508 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -1036,26 +1036,6 @@ static int ath9k_htc_add_interface(struct ieee80211_hw *hw, mutex_lock(&priv->mutex); - if (priv->nvifs >= ATH9K_HTC_MAX_VIF) { - mutex_unlock(&priv->mutex); - return -ENOBUFS; - } - - if (priv->num_ibss_vif || - (priv->nvifs && vif->type == NL80211_IFTYPE_ADHOC)) { - ath_err(common, "IBSS coexistence with other modes is not allowed\n"); - mutex_unlock(&priv->mutex); - return -ENOBUFS; - } - - if (((vif->type == NL80211_IFTYPE_AP) || - (vif->type == NL80211_IFTYPE_ADHOC)) && - ((priv->num_ap_vif + priv->num_ibss_vif) >= ATH9K_HTC_MAX_BCN_VIF)) { - ath_err(common, "Max. number of beaconing interfaces reached\n"); - mutex_unlock(&priv->mutex); - return -ENOBUFS; - } - ath9k_htc_ps_wakeup(priv); memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif)); memcpy(&hvif.myaddr, vif->addr, ETH_ALEN); -- cgit v1.2.3-18-g5258 From aebc0d40f9f7310d4651df2772d208fd9b2d2fa0 Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Mon, 8 Oct 2012 21:30:54 +0530 Subject: ath9k: Advertize beacon_int_infra_match Currently ath9k need to have beacon interval matched between STA mode and beaconing mode. Advertize this through interface combinations. Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/init.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index fad3ccd5cd9..546bae93647 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -687,6 +687,7 @@ static const struct ieee80211_iface_combination if_comb = { .n_limits = ARRAY_SIZE(if_limits), .max_interfaces = 2048, .num_different_channels = 1, + .beacon_int_infra_match = true, }; void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) -- cgit v1.2.3-18-g5258 From 50072ebca3d0aec8c5b8543e767d45c6626523af Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Fri, 12 Oct 2012 14:07:22 +0530 Subject: ath9k: Send WLAN channel info to BT WLAN updates channel bitmap when associated and disassociated. Channel bitmap will reflect whare are the channels used or affected by WLAN and BT should avoid using those. Not doing so, could affect BT traffic as both WLAN and BT is operating on same channel. Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/main.c | 5 ++++ drivers/net/wireless/ath/ath9k/mci.c | 50 +++++++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath9k/mci.h | 23 ++++++++++++++++ 3 files changed, 78 insertions(+) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 2da62be081f..515e184ab47 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1450,6 +1450,9 @@ static void ath9k_set_assoc_state(struct ath_softc *sc, sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON; spin_unlock_irqrestore(&sc->sc_pm_lock, flags); + if (ath9k_hw_mci_is_enabled(sc->sc_ah)) + ath9k_mci_update_wlan_channels(sc, false); + ath_dbg(common, CONFIG, "Primary Station interface: %pM, BSSID: %pM\n", vif->addr, common->curbssid); @@ -1506,6 +1509,8 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, memset(common->curbssid, 0, ETH_ALEN); common->curaid = 0; ath9k_hw_write_associd(sc->sc_ah); + if (ath9k_hw_mci_is_enabled(sc->sc_ah)) + ath9k_mci_update_wlan_channels(sc, true); } } diff --git a/drivers/net/wireless/ath/ath9k/mci.c b/drivers/net/wireless/ath/ath9k/mci.c index ec2d7c80756..1733a5ac327 100644 --- a/drivers/net/wireless/ath/ath9k/mci.c +++ b/drivers/net/wireless/ath/ath9k/mci.c @@ -600,3 +600,53 @@ void ath_mci_enable(struct ath_softc *sc) if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_MCI) sc->sc_ah->imask |= ATH9K_INT_MCI; } + +void ath9k_mci_update_wlan_channels(struct ath_softc *sc, bool allow_all) +{ + struct ath_hw *ah = sc->sc_ah; + struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; + struct ath9k_channel *chan = ah->curchan; + u32 channelmap[] = {0x00000000, 0xffff0000, 0xffffffff, 0x7fffffff}; + int i; + s16 chan_start, chan_end; + u16 wlan_chan; + + if (!chan || !IS_CHAN_2GHZ(chan)) + return; + + if (allow_all) + goto send_wlan_chan; + + wlan_chan = chan->channel - 2402; + + chan_start = wlan_chan - 10; + chan_end = wlan_chan + 10; + + if (chan->chanmode == CHANNEL_G_HT40PLUS) + chan_end += 20; + else if (chan->chanmode == CHANNEL_G_HT40MINUS) + chan_start -= 20; + + /* adjust side band */ + chan_start -= 7; + chan_end += 7; + + if (chan_start <= 0) + chan_start = 0; + if (chan_end >= ATH_MCI_NUM_BT_CHANNELS) + chan_end = ATH_MCI_NUM_BT_CHANNELS - 1; + + ath_dbg(ath9k_hw_common(ah), MCI, + "WLAN current channel %d mask BT channel %d - %d\n", + wlan_chan, chan_start, chan_end); + + for (i = chan_start; i < chan_end; i++) + MCI_GPM_CLR_CHANNEL_BIT(&channelmap, i); + +send_wlan_chan: + /* update and send wlan channels info to BT */ + for (i = 0; i < 4; i++) + mci->wlan_channels[i] = channelmap[i]; + ar9003_mci_send_wlan_channels(ah); + ar9003_mci_state(ah, MCI_STATE_SEND_VERSION_QUERY); +} diff --git a/drivers/net/wireless/ath/ath9k/mci.h b/drivers/net/wireless/ath/ath9k/mci.h index fc14eea034e..a3df314c1e7 100644 --- a/drivers/net/wireless/ath/ath9k/mci.h +++ b/drivers/net/wireless/ath/ath9k/mci.h @@ -32,6 +32,24 @@ #define ATH_MCI_MAX_PROFILE (ATH_MCI_MAX_ACL_PROFILE +\ ATH_MCI_MAX_SCO_PROFILE) +#define ATH_MCI_NUM_BT_CHANNELS 79 + +#define MCI_GPM_SET_CHANNEL_BIT(_p_gpm, _bt_chan) \ + do { \ + if (_bt_chan < ATH_MCI_NUM_BT_CHANNELS) { \ + *(((u8 *)(_p_gpm)) + MCI_GPM_COEX_B_CHANNEL_MAP + \ + (_bt_chan / 8)) |= (1 << (_bt_chan & 7)); \ + } \ + } while (0) + +#define MCI_GPM_CLR_CHANNEL_BIT(_p_gpm, _bt_chan) \ + do { \ + if (_bt_chan < ATH_MCI_NUM_BT_CHANNELS) { \ + *(((u8 *)(_p_gpm)) + MCI_GPM_COEX_B_CHANNEL_MAP + \ + (_bt_chan / 8)) &= ~(1 << (_bt_chan & 7));\ + } \ + } while (0) + #define INC_PROF(_mci, _info) do { \ switch (_info->type) { \ case MCI_GPM_COEX_PROFILE_RFCOMM:\ @@ -133,10 +151,15 @@ void ath_mci_intr(struct ath_softc *sc); #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT void ath_mci_enable(struct ath_softc *sc); +void ath9k_mci_update_wlan_channels(struct ath_softc *sc, bool allow_all); #else static inline void ath_mci_enable(struct ath_softc *sc) { } +static inline void ath9k_mci_update_wlan_channels(struct ath_softc *sc, + bool allow_all) +{ +} #endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */ #endif /* MCI_H*/ -- cgit v1.2.3-18-g5258 From db60428b1af11cf216bb0736b24b2cf0c7b54071 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Fri, 12 Oct 2012 14:07:23 +0530 Subject: ath9k: Add concurrent WLAN and BT tx support for MCI based chips This feature enables both WLAN and BT can transmit simultaneously by setting WLAN and BT to equal priorities. Whenever both are transmitting, it might violate regulatory power limits. To avoid regulatory violation, WLAN tx power will be adjusted according to BT power index based on avaliability of BT scheduling message. If the combined power exceeds threshold, BT transmission will be held off. Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_mci.h | 1 - drivers/net/wireless/ath/ath9k/btcoex.c | 60 +++++++++++++++++++++-------- drivers/net/wireless/ath/ath9k/btcoex.h | 3 ++ drivers/net/wireless/ath/ath9k/mci.c | 60 +++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath9k/mci.h | 3 ++ 5 files changed, 110 insertions(+), 17 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mci.h b/drivers/net/wireless/ath/ath9k/ar9003_mci.h index 2a2d0188961..29282348eb4 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mci.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_mci.h @@ -196,7 +196,6 @@ enum mci_state_type { MCI_STATE_SEND_WLAN_COEX_VERSION, MCI_STATE_SEND_VERSION_QUERY, MCI_STATE_SEND_STATUS_QUERY, - MCI_STATE_SET_CONCUR_TX_PRI, MCI_STATE_RECOVER_RX, MCI_STATE_NEED_FTP_STOMP, MCI_STATE_DEBUG, diff --git a/drivers/net/wireless/ath/ath9k/btcoex.c b/drivers/net/wireless/ath/ath9k/btcoex.c index 419e9a3f2fe..05d9be5be52 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.c +++ b/drivers/net/wireless/ath/ath9k/btcoex.c @@ -218,27 +218,45 @@ void ath9k_hw_btcoex_set_weight(struct ath_hw *ah, enum ath_stomp_type stomp_type) { struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw; + struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci; + u8 txprio_shift[] = { 24, 16, 16, 0 }; /* tx priority weight */ + bool concur_tx = (mci_hw->concur_tx && btcoex_hw->tx_prio[stomp_type]); + const u32 *weight = ar9003_wlan_weights[stomp_type]; + int i; - if (AR_SREV_9300_20_OR_LATER(ah)) { - const u32 *weight = ar9003_wlan_weights[stomp_type]; - int i; - - if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) { - if ((stomp_type == ATH_BTCOEX_STOMP_LOW) && - btcoex_hw->mci.stomp_ftp) - stomp_type = ATH_BTCOEX_STOMP_LOW_FTP; - weight = mci_wlan_weights[stomp_type]; - } - - for (i = 0; i < AR9300_NUM_WLAN_WEIGHTS; i++) { - btcoex_hw->bt_weight[i] = AR9300_BT_WGHT; - btcoex_hw->wlan_weight[i] = weight[i]; - } - } else { + if (!AR_SREV_9300_20_OR_LATER(ah)) { btcoex_hw->bt_coex_weights = SM(bt_weight, AR_BTCOEX_BT_WGHT) | SM(wlan_weight, AR_BTCOEX_WL_WGHT); + return; + } + + if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) { + enum ath_stomp_type stype = + ((stomp_type == ATH_BTCOEX_STOMP_LOW) && + btcoex_hw->mci.stomp_ftp) ? + ATH_BTCOEX_STOMP_LOW_FTP : stomp_type; + weight = mci_wlan_weights[stype]; } + + for (i = 0; i < AR9300_NUM_WLAN_WEIGHTS; i++) { + btcoex_hw->bt_weight[i] = AR9300_BT_WGHT; + btcoex_hw->wlan_weight[i] = weight[i]; + if (concur_tx && i) { + btcoex_hw->wlan_weight[i] &= + ~(0xff << txprio_shift[i-1]); + btcoex_hw->wlan_weight[i] |= + (btcoex_hw->tx_prio[stomp_type] << + txprio_shift[i-1]); + } + } + /* Last WLAN weight has to be adjusted wrt tx priority */ + if (concur_tx) { + btcoex_hw->wlan_weight[i-1] &= ~(0xff << txprio_shift[i-1]); + btcoex_hw->wlan_weight[i-1] |= (btcoex_hw->tx_prio[stomp_type] + << txprio_shift[i-1]); + } + } EXPORT_SYMBOL(ath9k_hw_btcoex_set_weight); @@ -385,3 +403,13 @@ void ath9k_hw_btcoex_bt_stomp(struct ath_hw *ah, } } EXPORT_SYMBOL(ath9k_hw_btcoex_bt_stomp); + +void ath9k_hw_btcoex_set_concur_txprio(struct ath_hw *ah, u8 *stomp_txprio) +{ + struct ath_btcoex_hw *btcoex = &ah->btcoex_hw; + int i; + + for (i = 0; i < ATH_BTCOEX_STOMP_MAX; i++) + btcoex->tx_prio[i] = stomp_txprio[i]; +} +EXPORT_SYMBOL(ath9k_hw_btcoex_set_concur_txprio); diff --git a/drivers/net/wireless/ath/ath9k/btcoex.h b/drivers/net/wireless/ath/ath9k/btcoex.h index 385197ad79b..a260fcb99d1 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.h +++ b/drivers/net/wireless/ath/ath9k/btcoex.h @@ -84,6 +84,7 @@ struct ath9k_hw_mci { u8 bt_ver_minor; u8 bt_state; u8 stomp_ftp; + bool concur_tx; }; struct ath_btcoex_hw { @@ -98,6 +99,7 @@ struct ath_btcoex_hw { u32 bt_coex_mode2; /* Register setting for AR_BT_COEX_MODE2 */ u32 bt_weight[AR9300_NUM_BT_WEIGHTS]; u32 wlan_weight[AR9300_NUM_WLAN_WEIGHTS]; + u8 tx_prio[ATH_BTCOEX_STOMP_MAX]; }; void ath9k_hw_btcoex_init_scheme(struct ath_hw *ah); @@ -112,5 +114,6 @@ void ath9k_hw_btcoex_set_weight(struct ath_hw *ah, void ath9k_hw_btcoex_disable(struct ath_hw *ah); void ath9k_hw_btcoex_bt_stomp(struct ath_hw *ah, enum ath_stomp_type stomp_type); +void ath9k_hw_btcoex_set_concur_txprio(struct ath_hw *ah, u8 *stomp_txprio); #endif diff --git a/drivers/net/wireless/ath/ath9k/mci.c b/drivers/net/wireless/ath/ath9k/mci.c index 1733a5ac327..b37c8af6e02 100644 --- a/drivers/net/wireless/ath/ath9k/mci.c +++ b/drivers/net/wireless/ath/ath9k/mci.c @@ -43,6 +43,7 @@ static bool ath_mci_add_profile(struct ath_common *common, struct ath_mci_profile_info *info) { struct ath_mci_profile_info *entry; + u8 voice_priority[] = { 110, 110, 110, 112, 110, 110, 114, 116, 118 }; if ((mci->num_sco == ATH_MCI_MAX_SCO_PROFILE) && (info->type == MCI_GPM_COEX_PROFILE_VOICE)) @@ -59,6 +60,12 @@ static bool ath_mci_add_profile(struct ath_common *common, memcpy(entry, info, 10); INC_PROF(mci, info); list_add_tail(&entry->list, &mci->info); + if (info->type == MCI_GPM_COEX_PROFILE_VOICE) { + if (info->voice_type < sizeof(voice_priority)) + mci->voice_priority = voice_priority[info->voice_type]; + else + mci->voice_priority = 110; + } return true; } @@ -250,6 +257,57 @@ static void ath9k_mci_work(struct work_struct *work) ath_mci_update_scheme(sc); } +static void ath_mci_update_stomp_txprio(u8 cur_txprio, u8 *stomp_prio) +{ + if (cur_txprio < stomp_prio[ATH_BTCOEX_STOMP_NONE]) + stomp_prio[ATH_BTCOEX_STOMP_NONE] = cur_txprio; + + if (cur_txprio > stomp_prio[ATH_BTCOEX_STOMP_ALL]) + stomp_prio[ATH_BTCOEX_STOMP_ALL] = cur_txprio; + + if ((cur_txprio > ATH_MCI_HI_PRIO) && + (cur_txprio < stomp_prio[ATH_BTCOEX_STOMP_LOW])) + stomp_prio[ATH_BTCOEX_STOMP_LOW] = cur_txprio; +} + +static void ath_mci_set_concur_txprio(struct ath_softc *sc) +{ + struct ath_btcoex *btcoex = &sc->btcoex; + struct ath_mci_profile *mci = &btcoex->mci; + u8 stomp_txprio[] = { 0, 0, 0, 0 }; /* all, low, none, low_ftp */ + + if (mci->num_mgmt) { + stomp_txprio[ATH_BTCOEX_STOMP_ALL] = ATH_MCI_INQUIRY_PRIO; + if (!mci->num_pan && !mci->num_other_acl) + stomp_txprio[ATH_BTCOEX_STOMP_NONE] = + ATH_MCI_INQUIRY_PRIO; + } else { + u8 prof_prio[] = { 50, 90, 94, 52 };/* RFCOMM, A2DP, HID, PAN */ + + stomp_txprio[ATH_BTCOEX_STOMP_LOW] = + stomp_txprio[ATH_BTCOEX_STOMP_NONE] = 0xff; + + if (mci->num_sco) + ath_mci_update_stomp_txprio(mci->voice_priority, + stomp_txprio); + if (mci->num_other_acl) + ath_mci_update_stomp_txprio(prof_prio[0], stomp_txprio); + if (mci->num_a2dp) + ath_mci_update_stomp_txprio(prof_prio[1], stomp_txprio); + if (mci->num_hid) + ath_mci_update_stomp_txprio(prof_prio[2], stomp_txprio); + if (mci->num_pan) + ath_mci_update_stomp_txprio(prof_prio[3], stomp_txprio); + + if (stomp_txprio[ATH_BTCOEX_STOMP_NONE] == 0xff) + stomp_txprio[ATH_BTCOEX_STOMP_NONE] = 0; + + if (stomp_txprio[ATH_BTCOEX_STOMP_LOW] == 0xff) + stomp_txprio[ATH_BTCOEX_STOMP_LOW] = 0; + } + ath9k_hw_btcoex_set_concur_txprio(sc->sc_ah, stomp_txprio); +} + static u8 ath_mci_process_profile(struct ath_softc *sc, struct ath_mci_profile_info *info) { @@ -281,6 +339,7 @@ static u8 ath_mci_process_profile(struct ath_softc *sc, } else ath_mci_del_profile(common, mci, entry); + ath_mci_set_concur_txprio(sc); return 1; } @@ -314,6 +373,7 @@ static u8 ath_mci_process_status(struct ath_softc *sc, mci->num_mgmt++; } while (++i < ATH_MCI_MAX_PROFILE); + ath_mci_set_concur_txprio(sc); if (old_num_mgmt != mci->num_mgmt) return 1; diff --git a/drivers/net/wireless/ath/ath9k/mci.h b/drivers/net/wireless/ath/ath9k/mci.h index a3df314c1e7..e85a0e9506f 100644 --- a/drivers/net/wireless/ath/ath9k/mci.h +++ b/drivers/net/wireless/ath/ath9k/mci.h @@ -32,6 +32,8 @@ #define ATH_MCI_MAX_PROFILE (ATH_MCI_MAX_ACL_PROFILE +\ ATH_MCI_MAX_SCO_PROFILE) +#define ATH_MCI_INQUIRY_PRIO 62 +#define ATH_MCI_HI_PRIO 60 #define ATH_MCI_NUM_BT_CHANNELS 79 #define MCI_GPM_SET_CHANNEL_BIT(_p_gpm, _bt_chan) \ @@ -131,6 +133,7 @@ struct ath_mci_profile { u8 num_pan; u8 num_other_acl; u8 num_bdr; + u8 voice_priority; }; struct ath_mci_buf { -- cgit v1.2.3-18-g5258 From 77d848372875d2e4cbdbf07030f0e08cab5e7f4d Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Fri, 12 Oct 2012 14:07:24 +0530 Subject: ath9k: fill channel mode in caldata It is useful to have channel mode in caldata to find out whether operaing channel is in HT40/20 when we are currently on offchannel. It will be used by BTCOEX to enable/disable concurrent tx mechanism later. Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/calib.c | 1 + drivers/net/wireless/ath/ath9k/hw.h | 1 + 2 files changed, 2 insertions(+) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c index e5cceb07757..f3448a032e6 100644 --- a/drivers/net/wireless/ath/ath9k/calib.c +++ b/drivers/net/wireless/ath/ath9k/calib.c @@ -410,6 +410,7 @@ void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah, ah->caldata->channel = chan->channel; ah->caldata->channelFlags = chan->channelFlags & ~CHANNEL_CW_INT; + ah->caldata->chanmode = chan->chanmode; h = ah->caldata->nfCalHist; default_nf = ath9k_hw_get_default_nf(ah, chan); for (i = 0; i < NUM_NF_READINGS; i++) { diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 1d4f5f1fdd8..3e73bfe2315 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -401,6 +401,7 @@ enum ath9k_int { struct ath9k_hw_cal_data { u16 channel; u32 channelFlags; + u32 chanmode; int32_t CalValid; int8_t iCoff; int8_t qCoff; -- cgit v1.2.3-18-g5258 From e82cb03f5a645533def34923d55404526bc22fae Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Fri, 12 Oct 2012 14:07:25 +0530 Subject: ath9k: adjust WLAN and BT concurrent transmission The simulataneous transmission of both WLAN and BT might cause increase in power levels. To avoid regulatory violation, WLAN tx power will be adjusted according to BT power index based on avaliability of BT scheduling messages. WLAN tx power reduction might affect its performance. So WLAN tx power is only be lowered when the signal strength is good enough. Otherwise concurrent tx will be disabled and WLAN uses it default power levels. Also concurrent tx is disabled whenever WLAN is moving to off-channel which might be used by BT. Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_eeprom.c | 18 ++++++-- drivers/net/wireless/ath/ath9k/ar9003_mci.c | 28 +++++++++++- drivers/net/wireless/ath/ath9k/ar9003_mci.h | 5 +++ drivers/net/wireless/ath/ath9k/ath9k.h | 1 + drivers/net/wireless/ath/ath9k/btcoex.h | 3 ++ drivers/net/wireless/ath/ath9k/gpio.c | 2 + drivers/net/wireless/ath/ath9k/main.c | 4 ++ drivers/net/wireless/ath/ath9k/mci.c | 59 ++++++++++++++++++++++++++ drivers/net/wireless/ath/ath9k/mci.h | 8 ++++ 9 files changed, 124 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index 189aeb22f55..d31399871e8 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -18,6 +18,7 @@ #include "hw.h" #include "ar9003_phy.h" #include "ar9003_eeprom.h" +#include "ar9003_mci.h" #define COMP_HDR_LEN 4 #define COMP_CKSUM_LEN 2 @@ -41,7 +42,6 @@ static int ar9003_hw_power_interpolate(int32_t x, int32_t *px, int32_t *py, u_int16_t np); - static const struct ar9300_eeprom ar9300_default = { .eepromVersion = 2, .templateVersion = 2, @@ -5037,16 +5037,28 @@ static void ar9003_hw_set_power_per_rate_table(struct ath_hw *ah, case CTL_5GHT20: case CTL_2GHT20: for (i = ALL_TARGET_HT20_0_8_16; - i <= ALL_TARGET_HT20_23; i++) + i <= ALL_TARGET_HT20_23; i++) { pPwrArray[i] = (u8)min((u16)pPwrArray[i], minCtlPower); + if (ath9k_hw_mci_is_enabled(ah)) + pPwrArray[i] = + (u8)min((u16)pPwrArray[i], + ar9003_mci_get_max_txpower(ah, + pCtlMode[ctlMode])); + } break; case CTL_5GHT40: case CTL_2GHT40: for (i = ALL_TARGET_HT40_0_8_16; - i <= ALL_TARGET_HT40_23; i++) + i <= ALL_TARGET_HT40_23; i++) { pPwrArray[i] = (u8)min((u16)pPwrArray[i], minCtlPower); + if (ath9k_hw_mci_is_enabled(ah)) + pPwrArray[i] = + (u8)min((u16)pPwrArray[i], + ar9003_mci_get_max_txpower(ah, + pCtlMode[ctlMode])); + } break; default: break; diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mci.c b/drivers/net/wireless/ath/ath9k/ar9003_mci.c index 44c202ce6c6..9aa8704eb3e 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mci.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_mci.c @@ -818,7 +818,7 @@ int ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g, { struct ath_common *common = ath9k_hw_common(ah); struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; - u32 regval; + u32 regval, i; ath_dbg(common, MCI, "MCI Reset (full_sleep = %d, is_2g = %d)\n", is_full_sleep, is_2g); @@ -868,6 +868,18 @@ int ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g, REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, AR_BTCOEX_CTRL2_RX_DEWEIGHT, 1); REG_RMW_FIELD(ah, AR_PCU_MISC, AR_PCU_BT_ANT_PREVENT_RX, 0); + /* concurrent tx priority */ + if (mci->config & ATH_MCI_CONFIG_CONCUR_TX) { + REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, + AR_BTCOEX_CTRL2_DESC_BASED_TXPWR_ENABLE, 0); + REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, + AR_BTCOEX_CTRL2_TXPWR_THRESH, 0x7f); + REG_RMW_FIELD(ah, AR_BTCOEX_CTRL, + AR_BTCOEX_CTRL_REDUCE_TXPWR, 0); + for (i = 0; i < 8; i++) + REG_WRITE(ah, AR_BTCOEX_MAX_TXPWR(i), 0x7f7f7f7f); + } + regval = MS(mci->config, ATH_MCI_CONFIG_CLK_DIV); REG_RMW_FIELD(ah, AR_MCI_TX_CTRL, AR_MCI_TX_CTRL_CLK_DIV, regval); REG_SET_BIT(ah, AR_BTCOEX_CTRL, AR_BTCOEX_CTRL_MCI_MODE_EN); @@ -1426,3 +1438,17 @@ void ar9003_mci_send_wlan_channels(struct ath_hw *ah) ar9003_mci_send_coex_wlan_channels(ah, true); } EXPORT_SYMBOL(ar9003_mci_send_wlan_channels); + +u16 ar9003_mci_get_max_txpower(struct ath_hw *ah, u8 ctlmode) +{ + if (!ah->btcoex_hw.mci.concur_tx) + goto out; + + if (ctlmode == CTL_2GHT20) + return ATH_BTCOEX_HT20_MAX_TXPOWER; + else if (ctlmode == CTL_2GHT40) + return ATH_BTCOEX_HT40_MAX_TXPOWER; + +out: + return -1; +} diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mci.h b/drivers/net/wireless/ath/ath9k/ar9003_mci.h index 29282348eb4..0910310ae83 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mci.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_mci.h @@ -277,6 +277,7 @@ void ar9003_mci_get_isr(struct ath_hw *ah, enum ath9k_int *masked); void ar9003_mci_bt_gain_ctrl(struct ath_hw *ah); void ar9003_mci_set_power_awake(struct ath_hw *ah); void ar9003_mci_check_gpm_offset(struct ath_hw *ah); +u16 ar9003_mci_get_max_txpower(struct ath_hw *ah, u8 ctlmode); #else @@ -323,6 +324,10 @@ static inline void ar9003_mci_set_power_awake(struct ath_hw *ah) static inline void ar9003_mci_check_gpm_offset(struct ath_hw *ah) { } +static inline u16 ar9003_mci_get_max_txpower(struct ath_hw *ah, u8 ctlmode) +{ + return -1; +} #endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */ #endif diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 77c2c16b696..18dfb764eed 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -479,6 +479,7 @@ struct ath_btcoex { u32 btscan_no_stomp; /* in usec */ u32 duty_cycle; u32 bt_wait_time; + int rssi_count; struct ath_gen_timer *no_stomp_timer; /* Timer for no BT stomping */ struct ath_mci_profile mci; }; diff --git a/drivers/net/wireless/ath/ath9k/btcoex.h b/drivers/net/wireless/ath/ath9k/btcoex.h index a260fcb99d1..94e921147e4 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.h +++ b/drivers/net/wireless/ath/ath9k/btcoex.h @@ -39,6 +39,9 @@ #define ATH_BTCOEX_RX_WAIT_TIME 100 #define ATH_BTCOEX_STOMP_FTP_THRESH 5 +#define ATH_BTCOEX_HT20_MAX_TXPOWER 0x14 +#define ATH_BTCOEX_HT40_MAX_TXPOWER 0x10 + #define AR9300_NUM_BT_WEIGHTS 4 #define AR9300_NUM_WLAN_WEIGHTS 4 /* Defines the BT AR_BT_COEX_WGHT used */ diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c index 9e63a03330c..64dde1cd20e 100644 --- a/drivers/net/wireless/ath/ath9k/gpio.c +++ b/drivers/net/wireless/ath/ath9k/gpio.c @@ -227,6 +227,8 @@ static void ath_btcoex_period_timer(unsigned long data) } spin_unlock_irqrestore(&sc->sc_pm_lock, flags); + ath9k_mci_update_rssi(sc); + ath9k_ps_wakeup(sc); if (!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI)) diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 515e184ab47..578a7234aa5 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -293,6 +293,10 @@ static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan, goto out; } + if (ath9k_hw_mci_is_enabled(sc->sc_ah) && + (sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)) + ath9k_mci_set_txpower(sc, true, false); + if (!ath_complete_reset(sc, true)) r = -EIO; diff --git a/drivers/net/wireless/ath/ath9k/mci.c b/drivers/net/wireless/ath/ath9k/mci.c index b37c8af6e02..19dbac42f3d 100644 --- a/drivers/net/wireless/ath/ath9k/mci.c +++ b/drivers/net/wireless/ath/ath9k/mci.c @@ -710,3 +710,62 @@ send_wlan_chan: ar9003_mci_send_wlan_channels(ah); ar9003_mci_state(ah, MCI_STATE_SEND_VERSION_QUERY); } + +void ath9k_mci_set_txpower(struct ath_softc *sc, bool setchannel, + bool concur_tx) +{ + struct ath_hw *ah = sc->sc_ah; + struct ath9k_hw_mci *mci_hw = &sc->sc_ah->btcoex_hw.mci; + bool old_concur_tx = mci_hw->concur_tx; + + if (!(mci_hw->config & ATH_MCI_CONFIG_CONCUR_TX)) { + mci_hw->concur_tx = false; + return; + } + + if (!IS_CHAN_2GHZ(ah->curchan)) + return; + + if (setchannel) { + struct ath9k_hw_cal_data *caldata = &sc->caldata; + if ((caldata->chanmode == CHANNEL_G_HT40PLUS) && + (ah->curchan->channel > caldata->channel) && + (ah->curchan->channel <= caldata->channel + 20)) + return; + if ((caldata->chanmode == CHANNEL_G_HT40MINUS) && + (ah->curchan->channel < caldata->channel) && + (ah->curchan->channel >= caldata->channel - 20)) + return; + mci_hw->concur_tx = false; + } else + mci_hw->concur_tx = concur_tx; + + if (old_concur_tx != mci_hw->concur_tx) + ath9k_hw_set_txpowerlimit(ah, sc->config.txpowlimit, false); +} + +void ath9k_mci_update_rssi(struct ath_softc *sc) +{ + struct ath_hw *ah = sc->sc_ah; + struct ath_btcoex *btcoex = &sc->btcoex; + struct ath9k_hw_mci *mci_hw = &sc->sc_ah->btcoex_hw.mci; + + if (!(mci_hw->config & ATH_MCI_CONFIG_CONCUR_TX)) + return; + + if (ah->stats.avgbrssi >= 40) { + if (btcoex->rssi_count < 0) + btcoex->rssi_count = 0; + if (++btcoex->rssi_count >= ATH_MCI_CONCUR_TX_SWITCH) { + btcoex->rssi_count = 0; + ath9k_mci_set_txpower(sc, false, true); + } + } else { + if (btcoex->rssi_count > 0) + btcoex->rssi_count = 0; + if (--btcoex->rssi_count <= -ATH_MCI_CONCUR_TX_SWITCH) { + btcoex->rssi_count = 0; + ath9k_mci_set_txpower(sc, false, false); + } + } +} diff --git a/drivers/net/wireless/ath/ath9k/mci.h b/drivers/net/wireless/ath/ath9k/mci.h index e85a0e9506f..e5f170a4d66 100644 --- a/drivers/net/wireless/ath/ath9k/mci.h +++ b/drivers/net/wireless/ath/ath9k/mci.h @@ -35,6 +35,7 @@ #define ATH_MCI_INQUIRY_PRIO 62 #define ATH_MCI_HI_PRIO 60 #define ATH_MCI_NUM_BT_CHANNELS 79 +#define ATH_MCI_CONCUR_TX_SWITCH 5 #define MCI_GPM_SET_CHANNEL_BIT(_p_gpm, _bt_chan) \ do { \ @@ -151,10 +152,13 @@ void ath_mci_flush_profile(struct ath_mci_profile *mci); int ath_mci_setup(struct ath_softc *sc); void ath_mci_cleanup(struct ath_softc *sc); void ath_mci_intr(struct ath_softc *sc); +void ath9k_mci_update_rssi(struct ath_softc *sc); #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT void ath_mci_enable(struct ath_softc *sc); void ath9k_mci_update_wlan_channels(struct ath_softc *sc, bool allow_all); +void ath9k_mci_set_txpower(struct ath_softc *sc, bool setchannel, + bool concur_tx); #else static inline void ath_mci_enable(struct ath_softc *sc) { @@ -163,6 +167,10 @@ static inline void ath9k_mci_update_wlan_channels(struct ath_softc *sc, bool allow_all) { } +static inline void ath9k_mci_set_txpower(struct ath_softc *sc, bool setchannel, + bool concur_tx) +{ +} #endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */ #endif /* MCI_H*/ -- cgit v1.2.3-18-g5258 From 4c6231a408c1fbec714f82b4742d19f85130ba97 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Mon, 15 Oct 2012 15:29:45 +0530 Subject: ath9k_hw: Enable OSLA hw fix for AR9565 Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_mci.c | 3 +++ drivers/net/wireless/ath/ath9k/reg.h | 4 ++++ 2 files changed, 7 insertions(+) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mci.c b/drivers/net/wireless/ath/ath9k/ar9003_mci.c index 9aa8704eb3e..9fa6d22179b 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mci.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_mci.c @@ -799,6 +799,9 @@ static void ar9003_mci_osla_setup(struct ath_hw *ah, bool enable) REG_RMW_FIELD(ah, AR_MCI_SCHD_TABLE_2, AR_MCI_SCHD_TABLE_2_MEM_BASED, 1); + if (AR_SREV_9565(ah)) + REG_RMW_FIELD(ah, AR_MCI_MISC, AR_MCI_MISC_HW_FIX_EN, 1); + if (!(mci->config & ATH_MCI_CONFIG_DISABLE_AGGR_THRESH)) { thresh = MS(mci->config, ATH_MCI_CONFIG_AGGR_THRESH); REG_RMW_FIELD(ah, AR_BTCOEX_CTRL, diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index 4e6760f8596..c7a9ea750a4 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -2360,4 +2360,8 @@ enum { #define AR_GLB_SWREG_DISCONT_MODE 0x2002c #define AR_GLB_SWREG_DISCONT_EN_BT_WLAN 0x3 +#define AR_MCI_MISC 0x1a74 +#define AR_MCI_MISC_HW_FIX_EN 0x00000001 +#define AR_MCI_MISC_HW_FIX_EN_S 0 + #endif -- cgit v1.2.3-18-g5258 From 7d47884f306afd1d0215133685f451aaafe3ca7a Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Mon, 15 Oct 2012 15:29:46 +0530 Subject: ath9k_hw: Fix selfgen chainmask for 9565 Self generated MCI messages is configured to use chain 1. As ar9565 is 1x1 solution, It can not use Chain 1. Hence fix Chain 1 for ar9462 alone. Not doing so, could affect WLAN connectivity in ar9565 as LNA sharing is not informed by BT. Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_mci.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mci.c b/drivers/net/wireless/ath/ath9k/ar9003_mci.c index 9fa6d22179b..6fbd376098d 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mci.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_mci.c @@ -1043,7 +1043,9 @@ void ar9003_mci_2g5g_switch(struct ath_hw *ah, bool force) if (!(mci->config & ATH_MCI_CONFIG_DISABLE_OSLA)) ar9003_mci_osla_setup(ah, true); - REG_WRITE(ah, AR_SELFGEN_MASK, 0x02); + + if (AR_SREV_9462(ah)) + REG_WRITE(ah, AR_SELFGEN_MASK, 0x02); } else { ar9003_mci_send_lna_take(ah, true); udelay(5); -- cgit v1.2.3-18-g5258 From d9575dad59de382dd1f1ddcaa6de38d9844691fe Mon Sep 17 00:00:00 2001 From: Bala Shanmugam Date: Mon, 15 Oct 2012 15:29:47 +0530 Subject: ath9k: Set appropriate bit for AR9565 in btc control register Signed-off-by: Bala Shanmugam Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_mci.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mci.c b/drivers/net/wireless/ath/ath9k/ar9003_mci.c index 6fbd376098d..b2b994147ae 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mci.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_mci.c @@ -850,11 +850,18 @@ int ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g, SM(1, AR_BTCOEX_CTRL_WBTIMER_EN) | SM(1, AR_BTCOEX_CTRL_PA_SHARED) | SM(1, AR_BTCOEX_CTRL_LNA_SHARED) | - SM(2, AR_BTCOEX_CTRL_NUM_ANTENNAS) | - SM(3, AR_BTCOEX_CTRL_RX_CHAIN_MASK) | SM(0, AR_BTCOEX_CTRL_1_CHAIN_ACK) | SM(0, AR_BTCOEX_CTRL_1_CHAIN_BCN) | SM(0, AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN); + if (AR_SREV_9565(ah)) { + regval |= SM(1, AR_BTCOEX_CTRL_NUM_ANTENNAS) | + SM(1, AR_BTCOEX_CTRL_RX_CHAIN_MASK); + REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, + AR_BTCOEX_CTRL2_TX_CHAIN_MASK, 0x1); + } else { + regval |= SM(2, AR_BTCOEX_CTRL_NUM_ANTENNAS) | + SM(3, AR_BTCOEX_CTRL_RX_CHAIN_MASK); + } REG_WRITE(ah, AR_BTCOEX_CTRL, regval); -- cgit v1.2.3-18-g5258 From b55f6bb7c3f890c3d537516efa8746a4784c058d Mon Sep 17 00:00:00 2001 From: Bala Shanmugam Date: Mon, 15 Oct 2012 15:29:48 +0530 Subject: ath9k: turn off RXIQ calibration while re-calibrating radio TXIQ and RXIQ share the same data path to upload the measurement result, we should turn off RXIQ calibration while re-calibrating radio Signed-off-by: Bala Shanmugam Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_mci.c | 6 ++++++ drivers/net/wireless/ath/ath9k/ar9003_phy.h | 1 + 2 files changed, 7 insertions(+) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mci.c b/drivers/net/wireless/ath/ath9k/ar9003_mci.c index b2b994147ae..c46d8f18d81 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mci.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_mci.c @@ -750,6 +750,9 @@ int ar9003_mci_end_reset(struct ath_hw *ah, struct ath9k_channel *chan, mci_hw->bt_state = MCI_BT_AWAKE; + REG_CLR_BIT(ah, AR_PHY_TIMING4, + 1 << AR_PHY_TIMING_CONTROL4_DO_GAIN_DC_IQ_CAL_SHIFT); + if (caldata) { caldata->done_txiqcal_once = false; caldata->done_txclcal_once = false; @@ -759,6 +762,9 @@ int ar9003_mci_end_reset(struct ath_hw *ah, struct ath9k_channel *chan, if (!ath9k_hw_init_cal(ah, chan)) return -EIO; + REG_SET_BIT(ah, AR_PHY_TIMING4, + 1 << AR_PHY_TIMING_CONTROL4_DO_GAIN_DC_IQ_CAL_SHIFT); + exit: ar9003_mci_enable_interrupt(ah); return 0; diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h index 9a48e3d2f23..8f585233a78 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h @@ -32,6 +32,7 @@ #define AR_PHY_SPUR_REG (AR_CHAN_BASE + 0x1c) #define AR_PHY_RX_IQCAL_CORR_B0 (AR_CHAN_BASE + 0xdc) #define AR_PHY_TX_IQCAL_CONTROL_3 (AR_CHAN_BASE + 0xb0) +#define AR_PHY_TIMING_CONTROL4_DO_GAIN_DC_IQ_CAL_SHIFT 16 #define AR_PHY_TIMING11_SPUR_FREQ_SD 0x3FF00000 #define AR_PHY_TIMING11_SPUR_FREQ_SD_S 20 -- cgit v1.2.3-18-g5258 From e9f9fd8cdc5fcb718e2ce778cb5e0eea27e2fdc8 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Mon, 15 Oct 2012 15:29:49 +0530 Subject: ath9k_hw: Disable MCI stat counter by default for AR9565 Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_mci.c | 3 +++ drivers/net/wireless/ath/ath9k/reg.h | 3 +++ 2 files changed, 6 insertions(+) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mci.c b/drivers/net/wireless/ath/ath9k/ar9003_mci.c index c46d8f18d81..87d9c348e59 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mci.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_mci.c @@ -938,6 +938,9 @@ int ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g, mci->ready = true; ar9003_mci_prep_interface(ah); + if (AR_SREV_9565(ah)) + REG_RMW_FIELD(ah, AR_MCI_DBG_CNT_CTRL, + AR_MCI_DBG_CNT_CTRL_ENABLE, 0); if (en_int) ar9003_mci_enable_interrupt(ah); diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index c7a9ea750a4..8f40dba9142 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -2363,5 +2363,8 @@ enum { #define AR_MCI_MISC 0x1a74 #define AR_MCI_MISC_HW_FIX_EN 0x00000001 #define AR_MCI_MISC_HW_FIX_EN_S 0 +#define AR_MCI_DBG_CNT_CTRL 0x1a78 +#define AR_MCI_DBG_CNT_CTRL_ENABLE 0x00000001 +#define AR_MCI_DBG_CNT_CTRL_ENABLE_S 0 #endif -- cgit v1.2.3-18-g5258 From 2097fdd7ebdb1674aaf7343b7a1d6cc2758c1dff Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Mon, 15 Oct 2012 15:29:50 +0530 Subject: ath9k_hw: Fix frequent BT rx recovery While resuming from S3, BT host issues HCI reset command and it causes BT firmware to busy with security key calculation. At this movement, WLAN detects MCI hardware error of MCI_CONT_INFO_TIMEOUT and then it starts the recovery sequence repeatedly. Too many recovery sequences would exhaust the BT kernel message pool. This patch imposes a duration between consecutive BT recovery procedure. Thus it solves BT firmware panic issue reported in AR9565. Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_mci.c | 10 +++++++++- drivers/net/wireless/ath/ath9k/ar9003_mci.h | 1 + drivers/net/wireless/ath/ath9k/btcoex.h | 1 + 3 files changed, 11 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mci.c b/drivers/net/wireless/ath/ath9k/ar9003_mci.c index 87d9c348e59..b04fa462282 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mci.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_mci.c @@ -1203,7 +1203,7 @@ EXPORT_SYMBOL(ar9003_mci_cleanup); u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type) { struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; - u32 value = 0; + u32 value = 0, tsf; u8 query_type; switch (state_type) { @@ -1261,6 +1261,14 @@ u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type) ar9003_mci_send_coex_bt_status_query(ah, true, query_type); break; case MCI_STATE_RECOVER_RX: + tsf = ath9k_hw_gettsf32(ah); + if ((tsf - mci->last_recovery) <= MCI_RECOVERY_DUR_TSF) { + ath_dbg(ath9k_hw_common(ah), MCI, + "(MCI) ignore Rx recovery\n"); + break; + } + ath_dbg(ath9k_hw_common(ah), MCI, "(MCI) RECOVER RX\n"); + mci->last_recovery = tsf; ar9003_mci_prep_interface(ah); mci->query_bt = true; mci->need_flush_btinfo = true; diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mci.h b/drivers/net/wireless/ath/ath9k/ar9003_mci.h index 0910310ae83..3e51f54b012 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mci.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_mci.h @@ -18,6 +18,7 @@ #define AR9003_MCI_H #define MCI_FLAG_DISABLE_TIMESTAMP 0x00000001 /* Disable time stamp */ +#define MCI_RECOVERY_DUR_TSF (100 * 1000) /* 100 ms */ /* Default remote BT device MCI COEX version */ #define MCI_GPM_COEX_MAJOR_VERSION_DEFAULT 3 diff --git a/drivers/net/wireless/ath/ath9k/btcoex.h b/drivers/net/wireless/ath/ath9k/btcoex.h index 94e921147e4..2f84ab273d0 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.h +++ b/drivers/net/wireless/ath/ath9k/btcoex.h @@ -88,6 +88,7 @@ struct ath9k_hw_mci { u8 bt_state; u8 stomp_ftp; bool concur_tx; + u32 last_recovery; }; struct ath_btcoex_hw { -- cgit v1.2.3-18-g5258 From 6f37ff96d3bd2a53e68131a7c10ced933815b390 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Mon, 15 Oct 2012 15:29:51 +0530 Subject: ath9k_hw: Fix max rx rate drop for AR9565 Whenever i_coff of IQ calibration is too high, AR9565 drops max rx rate to MCS4. Skipping IQ update at this time can avoid this problem for AR9565. Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_calib.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c index 84b558d126c..162401f22f8 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c @@ -276,6 +276,11 @@ static void ar9003_hw_iqcalibrate(struct ath_hw *ah, u8 numChains) offset_array[i], REG_READ(ah, offset_array[i])); + if (AR_SREV_9565(ah) && + (iCoff == 63 || qCoff == 63 || + iCoff == -63 || qCoff == -63)) + return; + REG_RMW_FIELD(ah, offset_array[i], AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF, iCoff); -- cgit v1.2.3-18-g5258 From 506ed95c27b9e4db521df8433860da78b4747cd8 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Mon, 15 Oct 2012 15:29:52 +0530 Subject: ath9k_hw: Configure new switch table for AR9565 BTCOEX Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_eeprom.c | 2 +- drivers/net/wireless/ath/ath9k/reg.h | 4 ---- drivers/net/wireless/ath/ath9k/wow.c | 2 +- 3 files changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index d31399871e8..c86cb640004 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -3601,7 +3601,7 @@ static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz) * 7:4 R/W SWITCH_TABLE_COM_SPDT_WLAN_IDLE * SWITCH_TABLE_COM_SPDT_WLAN_IDLE */ - if (AR_SREV_9462_20_OR_LATER(ah)) { + if (AR_SREV_9462_20(ah) || AR_SREV_9565(ah)) { value = ar9003_switch_com_spdt_get(ah, is2ghz); REG_RMW_FIELD(ah, AR_PHY_GLB_CONTROL, AR_SWITCH_TABLE_COM_SPDT_ALL, value); diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index 8f40dba9142..e9dec138b91 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -907,10 +907,6 @@ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9462) && \ ((_ah)->hw_version.macRev == AR_SREV_REVISION_9462_20)) -#define AR_SREV_9462_20_OR_LATER(_ah) \ - (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9462) && \ - ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9462_20)) - #define AR_SREV_9565(_ah) \ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9565)) diff --git a/drivers/net/wireless/ath/ath9k/wow.c b/drivers/net/wireless/ath/ath9k/wow.c index a483d518758..9f8563091be 100644 --- a/drivers/net/wireless/ath/ath9k/wow.c +++ b/drivers/net/wireless/ath/ath9k/wow.c @@ -118,7 +118,7 @@ static void ath9k_wow_create_keep_alive_pattern(struct ath_hw *ah) (ap_mac_addr[1] << 8) | (ap_mac_addr[0]); data_word[5] = (ap_mac_addr[5] << 8) | (ap_mac_addr[4]); - if (AR_SREV_9462_20_OR_LATER(ah)) { + if (AR_SREV_9462_20(ah)) { /* AR9462 2.0 has an extra descriptor word (time based * discard) compared to other chips */ REG_WRITE(ah, (AR_WOW_KA_DESC_WORD2 + (12 * 4)), 0); -- cgit v1.2.3-18-g5258 From 3c5c9d04f628135ff57eda5068c9d9513f0a94bf Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Mon, 15 Oct 2012 15:29:53 +0530 Subject: ath9k_hw: Set default MCI config for AR9565 Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/btcoex.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/btcoex.c b/drivers/net/wireless/ath/ath9k/btcoex.c index 05d9be5be52..c90e9bc4b02 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.c +++ b/drivers/net/wireless/ath/ath9k/btcoex.c @@ -195,7 +195,7 @@ void ath9k_hw_btcoex_init_mci(struct ath_hw *ah) ah->btcoex_hw.mci.need_flush_btinfo = false; ah->btcoex_hw.mci.wlan_cal_seq = 0; ah->btcoex_hw.mci.wlan_cal_done = 0; - ah->btcoex_hw.mci.config = 0x2201; + ah->btcoex_hw.mci.config = (AR_SREV_9462(ah)) ? 0x2201 : 0xa4c1; } EXPORT_SYMBOL(ath9k_hw_btcoex_init_mci); -- cgit v1.2.3-18-g5258 From f9401b1e74f33d40d97364be5244b715e8cee6ed Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Mon, 15 Oct 2012 15:29:54 +0530 Subject: ath9k: adjust duty cycle for FTP profile for AR9565 Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/mci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/mci.c b/drivers/net/wireless/ath/ath9k/mci.c index 19dbac42f3d..0dd2cbb52d6 100644 --- a/drivers/net/wireless/ath/ath9k/mci.c +++ b/drivers/net/wireless/ath/ath9k/mci.c @@ -157,7 +157,7 @@ static void ath_mci_update_scheme(struct ath_softc *sc) * For single PAN/FTP profile, allocate 35% for BT * to improve WLAN throughput. */ - btcoex->duty_cycle = 35; + btcoex->duty_cycle = AR_SREV_9565(sc->sc_ah) ? 40 : 35; btcoex->btcoex_period = 53; ath_dbg(common, MCI, "Single PAN/FTP bt period %d ms dutycycle %d\n", -- cgit v1.2.3-18-g5258 From 7bf7a71e0f7ad69358d01f2a7ba7faa9428db90b Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Mon, 15 Oct 2012 15:29:55 +0530 Subject: ath9k: Add new BT profile info A2DP_Voice When the BT connection is initiated by headset, it's possible that headset requests to make one A2DP and one Voice connection over the same link. BT firmware will send a new profile A2DP_Voice in this case. So WLAN has to take care of this new profile for tuning BTCOEX parameters. Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_mci.h | 1 + drivers/net/wireless/ath/ath9k/mci.h | 2 ++ 2 files changed, 3 insertions(+) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mci.h b/drivers/net/wireless/ath/ath9k/ar9003_mci.h index 3e51f54b012..66d7ab9f920 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mci.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_mci.h @@ -126,6 +126,7 @@ enum ath_mci_gpm_coex_profile_type { MCI_GPM_COEX_PROFILE_HID, MCI_GPM_COEX_PROFILE_BNEP, MCI_GPM_COEX_PROFILE_VOICE, + MCI_GPM_COEX_PROFILE_A2DPVO, MCI_GPM_COEX_PROFILE_MAX }; diff --git a/drivers/net/wireless/ath/ath9k/mci.h b/drivers/net/wireless/ath/ath9k/mci.h index e5f170a4d66..06958837620 100644 --- a/drivers/net/wireless/ath/ath9k/mci.h +++ b/drivers/net/wireless/ath/ath9k/mci.h @@ -70,6 +70,7 @@ _mci->num_pan++; \ break; \ case MCI_GPM_COEX_PROFILE_VOICE: \ + case MCI_GPM_COEX_PROFILE_A2DPVO:\ _mci->num_sco++; \ break; \ default: \ @@ -94,6 +95,7 @@ _mci->num_pan--; \ break; \ case MCI_GPM_COEX_PROFILE_VOICE: \ + case MCI_GPM_COEX_PROFILE_A2DPVO:\ _mci->num_sco--; \ break; \ default: \ -- cgit v1.2.3-18-g5258 From 6c4a5f2413da948e7d1d189c9d94f05afde8702a Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Mon, 22 Oct 2012 15:01:29 +0200 Subject: carl9170: split up carl9170_handle_mpdu carl9170_handle_mpdu is the final part of the rx path of the driver. It splits the raw data streams from the device into skb packets and passes them on to mac80211. As a result of continuous updates, it grew over the years when new code was added by the following commits: - report A-MPDU status - fix HT peer BA session corruption - A-MPDU frame type filter - ... This patch splits the routine into two stages. The first stage only deals with the details about extracting and verifying the data from the incoming stream. Whereas the second stage packs it into skbs and passes it on to mac80211. Reported-by: Javier Lopez Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/ath/carl9170/rx.c | 45 ++++++++++++++++++++++++---------- 1 file changed, 32 insertions(+), 13 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/carl9170/rx.c b/drivers/net/wireless/ath/carl9170/rx.c index 9cd93f1d8be..6d22382875b 100644 --- a/drivers/net/wireless/ath/carl9170/rx.c +++ b/drivers/net/wireless/ath/carl9170/rx.c @@ -660,6 +660,35 @@ static bool carl9170_ampdu_check(struct ar9170 *ar, u8 *buf, u8 ms, return false; } +static int carl9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len, + struct ieee80211_rx_status *status) +{ + struct sk_buff *skb; + + /* (driver) frame trap handler + * + * Because power-saving mode handing has to be implemented by + * the driver/firmware. We have to check each incoming beacon + * from the associated AP, if there's new data for us (either + * broadcast/multicast or unicast) we have to react quickly. + * + * So, if you have you want to add additional frame trap + * handlers, this would be the perfect place! + */ + + carl9170_ps_beacon(ar, buf, len); + + carl9170_ba_check(ar, buf, len); + + skb = carl9170_rx_copy_data(buf, len); + if (!skb) + return -ENOMEM; + + memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status)); + ieee80211_rx(ar->hw, skb); + return 0; +} + /* * If the frame alignment is right (or the kernel has * CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS), and there @@ -669,14 +698,12 @@ static bool carl9170_ampdu_check(struct ar9170 *ar, u8 *buf, u8 ms, * mode, and we need to observe the proper ordering, * this is non-trivial. */ - -static void carl9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len) +static void carl9170_rx_untie_data(struct ar9170 *ar, u8 *buf, int len) { struct ar9170_rx_head *head; struct ar9170_rx_macstatus *mac; struct ar9170_rx_phystatus *phy = NULL; struct ieee80211_rx_status status; - struct sk_buff *skb; int mpdu_len; u8 mac_status; @@ -788,18 +815,10 @@ static void carl9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len) if (phy) carl9170_rx_phy_status(ar, phy, &status); - carl9170_ps_beacon(ar, buf, mpdu_len); - - carl9170_ba_check(ar, buf, mpdu_len); - - skb = carl9170_rx_copy_data(buf, mpdu_len); - if (!skb) + if (carl9170_handle_mpdu(ar, buf, mpdu_len, &status)) goto drop; - memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status)); - ieee80211_rx(ar->hw, skb); return; - drop: ar->rx_dropped++; } @@ -851,7 +870,7 @@ static void __carl9170_rx(struct ar9170 *ar, u8 *buf, unsigned int len) if (i == 12) carl9170_rx_untie_cmds(ar, buf, len); else - carl9170_handle_mpdu(ar, buf, len); + carl9170_rx_untie_data(ar, buf, len); } static void carl9170_rx_stream(struct ar9170 *ar, void *buf, unsigned int len) -- cgit v1.2.3-18-g5258 From b7d572e1871df06a96a1c9591c71c5494ff6b624 Mon Sep 17 00:00:00 2001 From: Pontus Fuchs Date: Tue, 23 Oct 2012 20:33:57 +0200 Subject: ar5523: Add new driver This driver is for the AR5523 chipset from Atheros. It was created in 2007 by Christoph Hellwig but it was never finished. I found it a couple of months ago and after some polishing it's working pretty fine. The driver was written with the FreeBSD driver (uath) as reference, which was written with the reverse-engineered windows driver as reference, hence the feature set is very limited. Station mode only, no HW crypto offload. Signed-off-by: Pontus Fuchs Signed-off-by: John W. Linville --- drivers/net/wireless/ath/Kconfig | 1 + drivers/net/wireless/ath/Makefile | 1 + drivers/net/wireless/ath/ar5523/Kconfig | 7 + drivers/net/wireless/ath/ar5523/Makefile | 1 + drivers/net/wireless/ath/ar5523/ar5523.c | 1806 +++++++++++++++++++++++++++ drivers/net/wireless/ath/ar5523/ar5523.h | 152 +++ drivers/net/wireless/ath/ar5523/ar5523_hw.h | 431 +++++++ 7 files changed, 2399 insertions(+) create mode 100644 drivers/net/wireless/ath/ar5523/Kconfig create mode 100644 drivers/net/wireless/ath/ar5523/Makefile create mode 100644 drivers/net/wireless/ath/ar5523/ar5523.c create mode 100644 drivers/net/wireless/ath/ar5523/ar5523.h create mode 100644 drivers/net/wireless/ath/ar5523/ar5523_hw.h (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/Kconfig b/drivers/net/wireless/ath/Kconfig index 09602241901..c25dcf192fe 100644 --- a/drivers/net/wireless/ath/Kconfig +++ b/drivers/net/wireless/ath/Kconfig @@ -26,5 +26,6 @@ source "drivers/net/wireless/ath/ath5k/Kconfig" source "drivers/net/wireless/ath/ath9k/Kconfig" source "drivers/net/wireless/ath/carl9170/Kconfig" source "drivers/net/wireless/ath/ath6kl/Kconfig" +source "drivers/net/wireless/ath/ar5523/Kconfig" endif diff --git a/drivers/net/wireless/ath/Makefile b/drivers/net/wireless/ath/Makefile index d716b748e57..1e18621326d 100644 --- a/drivers/net/wireless/ath/Makefile +++ b/drivers/net/wireless/ath/Makefile @@ -2,6 +2,7 @@ obj-$(CONFIG_ATH5K) += ath5k/ obj-$(CONFIG_ATH9K_HW) += ath9k/ obj-$(CONFIG_CARL9170) += carl9170/ obj-$(CONFIG_ATH6KL) += ath6kl/ +obj-$(CONFIG_AR5523) += ar5523/ obj-$(CONFIG_ATH_COMMON) += ath.o diff --git a/drivers/net/wireless/ath/ar5523/Kconfig b/drivers/net/wireless/ath/ar5523/Kconfig new file mode 100644 index 00000000000..11d99ee8de5 --- /dev/null +++ b/drivers/net/wireless/ath/ar5523/Kconfig @@ -0,0 +1,7 @@ +config AR5523 + tristate "Atheros AR5523 wireless driver support" + depends on MAC80211 && USB + select FW_LOADER + ---help--- + This module add support for AR5523 based USB dongles such as D-Link + DWL-G132, Netgear WPN111 and many more. diff --git a/drivers/net/wireless/ath/ar5523/Makefile b/drivers/net/wireless/ath/ar5523/Makefile new file mode 100644 index 00000000000..ebf7f3bf0a3 --- /dev/null +++ b/drivers/net/wireless/ath/ar5523/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_AR5523) := ar5523.o diff --git a/drivers/net/wireless/ath/ar5523/ar5523.c b/drivers/net/wireless/ath/ar5523/ar5523.c new file mode 100644 index 00000000000..f782b6e502b --- /dev/null +++ b/drivers/net/wireless/ath/ar5523/ar5523.c @@ -0,0 +1,1806 @@ +/* + * Copyright (c) 2006 Damien Bergamini + * Copyright (c) 2006 Sam Leffler, Errno Consulting + * Copyright (c) 2007 Christoph Hellwig + * Copyright (c) 2008-2009 Weongyo Jeong + * Copyright (c) 2012 Pontus Fuchs + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * This driver is based on the uath driver written by Damien Bergamini for + * OpenBSD, who did black-box analysis of the Windows binary driver to find + * out how the hardware works. It contains a lot magic numbers because of + * that and only has minimal functionality. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ar5523.h" +#include "ar5523_hw.h" + +/* + * Various supported device vendors/products. + * UB51: AR5005UG 802.11b/g, UB52: AR5005UX 802.11a/b/g + */ + +static int ar5523_submit_rx_cmd(struct ar5523 *ar); +static void ar5523_data_tx_pkt_put(struct ar5523 *ar); + +static void ar5523_read_reply(struct ar5523 *ar, struct ar5523_cmd_hdr *hdr, + struct ar5523_tx_cmd *cmd) +{ + int dlen, olen; + u32 *rp; + + dlen = hdr->len - sizeof(*hdr); + + if (dlen < 0) { + WARN_ON(1); + goto out; + } + + ar5523_dbg(ar, "Code = %d len = %d\n", hdr->code & 0xff, dlen); + + rp = (u32 *)(hdr + 1); + if (dlen >= sizeof(u32)) { + olen = be32_to_cpu(rp[0]); + dlen -= sizeof(u32); + if (olen == 0) { + /* convention is 0 =>'s one word */ + olen = sizeof(u32); + } + } else + olen = 0; + + if (cmd->odata) { + if (cmd->olen < olen) { + ar5523_err(ar, "olen to small %d < %d\n", + cmd->olen, olen); + cmd->olen = 0; + cmd->res = -EOVERFLOW; + } else { + cmd->olen = olen; + memcpy(cmd->odata, &rp[1], olen); + cmd->res = 0; + } + } + +out: + complete(&cmd->done); +} + +static void ar5523_cmd_rx_cb(struct urb *urb) +{ + struct ar5523 *ar = urb->context; + struct ar5523_tx_cmd *cmd = &ar->tx_cmd; + struct ar5523_cmd_hdr *hdr = ar->rx_cmd_buf; + int dlen; + + if (urb->status) { + if (urb->status != -ESHUTDOWN) + ar5523_err(ar, "RX USB error %d.\n", urb->status); + goto skip; + } + + if (urb->actual_length < sizeof(struct ar5523_cmd_hdr)) { + ar5523_err(ar, "RX USB to short.\n"); + goto skip; + } + + ar5523_dbg(ar, "%s code %02x priv %d\n", __func__, + be32_to_cpu(hdr->code) & 0xff, hdr->priv); + + hdr->code = be32_to_cpu(hdr->code); + hdr->len = be32_to_cpu(hdr->len); + + switch (hdr->code & 0xff) { + default: + /* reply to a read command */ + if (hdr->priv != AR5523_CMD_ID) { + ar5523_err(ar, "Unexpected command id: %02x\n", + hdr->code & 0xff); + goto skip; + } + ar5523_read_reply(ar, hdr, cmd); + break; + + case WDCMSG_DEVICE_AVAIL: + ar5523_dbg(ar, "WDCMSG_DEVICE_AVAIL\n"); + cmd->res = 0; + cmd->olen = 0; + complete(&cmd->done); + break; + + case WDCMSG_SEND_COMPLETE: + ar5523_dbg(ar, "WDCMSG_SEND_COMPLETE: %d pending\n", + atomic_read(&ar->tx_nr_pending)); + if (!test_bit(AR5523_HW_UP, &ar->flags)) + ar5523_dbg(ar, "Unexpected WDCMSG_SEND_COMPLETE\n"); + else { + mod_timer(&ar->tx_wd_timer, + jiffies + AR5523_TX_WD_TIMEOUT); + ar5523_data_tx_pkt_put(ar); + + } + break; + + case WDCMSG_TARGET_START: + /* This command returns a bogus id so it needs special + handling */ + dlen = hdr->len - sizeof(*hdr); + if (dlen != (int)sizeof(u32)) { + ar5523_err(ar, "Invalid reply to WDCMSG_TARGET_START"); + return; + } + memcpy(cmd->odata, hdr + 1, sizeof(u32)); + cmd->olen = sizeof(u32); + cmd->res = 0; + complete(&cmd->done); + break; + + case WDCMSG_STATS_UPDATE: + ar5523_dbg(ar, "WDCMSG_STATS_UPDATE\n"); + break; + } + +skip: + ar5523_submit_rx_cmd(ar); +} + +static int ar5523_alloc_rx_cmd(struct ar5523 *ar) +{ + ar->rx_cmd_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!ar->rx_cmd_urb) + return -ENOMEM; + + ar->rx_cmd_buf = usb_alloc_coherent(ar->dev, AR5523_MAX_RXCMDSZ, + GFP_KERNEL, + &ar->rx_cmd_urb->transfer_dma); + if (!ar->rx_cmd_buf) { + usb_free_urb(ar->rx_cmd_urb); + return -ENOMEM; + } + return 0; +} + +static void ar5523_cancel_rx_cmd(struct ar5523 *ar) +{ + usb_kill_urb(ar->rx_cmd_urb); +} + +static void ar5523_free_rx_cmd(struct ar5523 *ar) +{ + usb_free_coherent(ar->dev, AR5523_MAX_RXCMDSZ, + ar->rx_cmd_buf, ar->rx_cmd_urb->transfer_dma); + usb_free_urb(ar->rx_cmd_urb); +} + +static int ar5523_submit_rx_cmd(struct ar5523 *ar) +{ + int error; + + usb_fill_bulk_urb(ar->rx_cmd_urb, ar->dev, + ar5523_cmd_rx_pipe(ar->dev), ar->rx_cmd_buf, + AR5523_MAX_RXCMDSZ, ar5523_cmd_rx_cb, ar); + ar->rx_cmd_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + + error = usb_submit_urb(ar->rx_cmd_urb, GFP_ATOMIC); + if (error) { + if (error != -ENODEV) + ar5523_err(ar, "error %d when submitting rx urb\n", + error); + return error; + } + return 0; +} + +/* + * Command submitted cb + */ +static void ar5523_cmd_tx_cb(struct urb *urb) +{ + struct ar5523_tx_cmd *cmd = urb->context; + struct ar5523 *ar = cmd->ar; + + if (urb->status) { + ar5523_err(ar, "Failed to TX command. Status = %d\n", + urb->status); + cmd->res = urb->status; + complete(&cmd->done); + return; + } + + if (!(cmd->flags & AR5523_CMD_FLAG_READ)) { + cmd->res = 0; + complete(&cmd->done); + } +} + +static int ar5523_cmd(struct ar5523 *ar, u32 code, const void *idata, + int ilen, void *odata, int olen, int flags) +{ + struct ar5523_cmd_hdr *hdr; + struct ar5523_tx_cmd *cmd = &ar->tx_cmd; + int xferlen, error; + + /* always bulk-out a multiple of 4 bytes */ + xferlen = (sizeof(struct ar5523_cmd_hdr) + ilen + 3) & ~3; + + hdr = (struct ar5523_cmd_hdr *)cmd->buf_tx; + memset(hdr, 0, sizeof(struct ar5523_cmd_hdr)); + hdr->len = cpu_to_be32(xferlen); + hdr->code = cpu_to_be32(code); + hdr->priv = AR5523_CMD_ID; + + if (flags & AR5523_CMD_FLAG_MAGIC) + hdr->magic = cpu_to_be32(1 << 24); + memcpy(hdr + 1, idata, ilen); + + cmd->odata = odata; + cmd->olen = olen; + cmd->flags = flags; + + ar5523_dbg(ar, "do cmd %02x\n", code); + + usb_fill_bulk_urb(cmd->urb_tx, ar->dev, ar5523_cmd_tx_pipe(ar->dev), + cmd->buf_tx, xferlen, ar5523_cmd_tx_cb, cmd); + cmd->urb_tx->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + + error = usb_submit_urb(cmd->urb_tx, GFP_KERNEL); + if (error) { + ar5523_err(ar, "could not send command 0x%x, error=%d\n", + code, error); + return error; + } + + if (!wait_for_completion_timeout(&cmd->done, 2 * HZ)) { + cmd->odata = NULL; + ar5523_err(ar, "timeout waiting for command %02x reply\n", + code); + cmd->res = -ETIMEDOUT; + } + return cmd->res; +} + +static int ar5523_cmd_write(struct ar5523 *ar, u32 code, const void *data, + int len, int flags) +{ + flags &= ~AR5523_CMD_FLAG_READ; + return ar5523_cmd(ar, code, data, len, NULL, 0, flags); +} + +static int ar5523_cmd_read(struct ar5523 *ar, u32 code, const void *idata, + int ilen, void *odata, int olen, int flags) +{ + flags |= AR5523_CMD_FLAG_READ; + return ar5523_cmd(ar, code, idata, ilen, odata, olen, flags); +} + +static int ar5523_config(struct ar5523 *ar, u32 reg, u32 val) +{ + struct ar5523_write_mac write; + int error; + + write.reg = cpu_to_be32(reg); + write.len = cpu_to_be32(0); /* 0 = single write */ + *(u32 *)write.data = cpu_to_be32(val); + + error = ar5523_cmd_write(ar, WDCMSG_TARGET_SET_CONFIG, &write, + 3 * sizeof(u32), 0); + if (error != 0) + ar5523_err(ar, "could not write register 0x%02x\n", reg); + return error; +} + +static int ar5523_config_multi(struct ar5523 *ar, u32 reg, const void *data, + int len) +{ + struct ar5523_write_mac write; + int error; + + write.reg = cpu_to_be32(reg); + write.len = cpu_to_be32(len); + memcpy(write.data, data, len); + + /* properly handle the case where len is zero (reset) */ + error = ar5523_cmd_write(ar, WDCMSG_TARGET_SET_CONFIG, &write, + (len == 0) ? sizeof(u32) : 2 * sizeof(u32) + len, 0); + if (error != 0) + ar5523_err(ar, "could not write %d bytes to register 0x%02x\n", + len, reg); + return error; +} + +static int ar5523_get_status(struct ar5523 *ar, u32 which, void *odata, + int olen) +{ + int error; + + which = cpu_to_be32(which); + error = ar5523_cmd_read(ar, WDCMSG_TARGET_GET_STATUS, + &which, sizeof(which), odata, olen, AR5523_CMD_FLAG_MAGIC); + if (error != 0) + ar5523_err(ar, "could not read EEPROM offset 0x%02x\n", + be32_to_cpu(which)); + return error; +} + +static int ar5523_get_capability(struct ar5523 *ar, u32 cap, u32 *val) +{ + int error; + + cap = cpu_to_be32(cap); + error = ar5523_cmd_read(ar, WDCMSG_TARGET_GET_CAPABILITY, + &cap, sizeof(cap), val, sizeof(u32), AR5523_CMD_FLAG_MAGIC); + if (error != 0) { + ar5523_err(ar, "could not read capability %u\n", + be32_to_cpu(cap)); + return error; + } + *val = be32_to_cpu(*val); + return error; +} + +static int ar5523_get_devcap(struct ar5523 *ar) +{ +#define GETCAP(x) do { \ + error = ar5523_get_capability(ar, x, &cap); \ + if (error != 0) \ + return error; \ + ar5523_info(ar, "Cap: " \ + "%s=0x%08x\n", #x, cap); \ +} while (0) + int error; + u32 cap; + + /* collect device capabilities */ + GETCAP(CAP_TARGET_VERSION); + GETCAP(CAP_TARGET_REVISION); + GETCAP(CAP_MAC_VERSION); + GETCAP(CAP_MAC_REVISION); + GETCAP(CAP_PHY_REVISION); + GETCAP(CAP_ANALOG_5GHz_REVISION); + GETCAP(CAP_ANALOG_2GHz_REVISION); + + GETCAP(CAP_REG_DOMAIN); + GETCAP(CAP_REG_CAP_BITS); + GETCAP(CAP_WIRELESS_MODES); + GETCAP(CAP_CHAN_SPREAD_SUPPORT); + GETCAP(CAP_COMPRESS_SUPPORT); + GETCAP(CAP_BURST_SUPPORT); + GETCAP(CAP_FAST_FRAMES_SUPPORT); + GETCAP(CAP_CHAP_TUNING_SUPPORT); + GETCAP(CAP_TURBOG_SUPPORT); + GETCAP(CAP_TURBO_PRIME_SUPPORT); + GETCAP(CAP_DEVICE_TYPE); + GETCAP(CAP_WME_SUPPORT); + GETCAP(CAP_TOTAL_QUEUES); + GETCAP(CAP_CONNECTION_ID_MAX); + + GETCAP(CAP_LOW_5GHZ_CHAN); + GETCAP(CAP_HIGH_5GHZ_CHAN); + GETCAP(CAP_LOW_2GHZ_CHAN); + GETCAP(CAP_HIGH_2GHZ_CHAN); + GETCAP(CAP_TWICE_ANTENNAGAIN_5G); + GETCAP(CAP_TWICE_ANTENNAGAIN_2G); + + GETCAP(CAP_CIPHER_AES_CCM); + GETCAP(CAP_CIPHER_TKIP); + GETCAP(CAP_MIC_TKIP); + return 0; +} + +static int ar5523_set_ledsteady(struct ar5523 *ar, int lednum, int ledmode) +{ + struct ar5523_cmd_ledsteady led; + + led.lednum = cpu_to_be32(lednum); + led.ledmode = cpu_to_be32(ledmode); + + ar5523_dbg(ar, "set %s led %s (steady)\n", + (lednum == UATH_LED_LINK) ? "link" : "activity", + ledmode ? "on" : "off"); + return ar5523_cmd_write(ar, WDCMSG_SET_LED_STEADY, &led, sizeof(led), + 0); +} + +static int ar5523_set_rxfilter(struct ar5523 *ar, u32 bits, u32 op) +{ + struct ar5523_cmd_rx_filter rxfilter; + + rxfilter.bits = cpu_to_be32(bits); + rxfilter.op = cpu_to_be32(op); + + ar5523_dbg(ar, "setting Rx filter=0x%x flags=0x%x\n", bits, op); + return ar5523_cmd_write(ar, WDCMSG_RX_FILTER, &rxfilter, + sizeof(rxfilter), 0); +} + +static int ar5523_reset_tx_queues(struct ar5523 *ar) +{ + __be32 qid = cpu_to_be32(0); + + ar5523_dbg(ar, "resetting Tx queue\n"); + return ar5523_cmd_write(ar, WDCMSG_RELEASE_TX_QUEUE, + &qid, sizeof(qid), 0); +} + +static int ar5523_set_chan(struct ar5523 *ar) +{ + struct ieee80211_conf *conf = &ar->hw->conf; + + struct ar5523_cmd_reset reset; + + memset(&reset, 0, sizeof(reset)); + reset.flags |= cpu_to_be32(UATH_CHAN_2GHZ); + reset.flags |= cpu_to_be32(UATH_CHAN_OFDM); + reset.freq = cpu_to_be32(conf->channel->center_freq); + reset.maxrdpower = cpu_to_be32(50); /* XXX */ + reset.channelchange = cpu_to_be32(1); + reset.keeprccontent = cpu_to_be32(0); + + ar5523_dbg(ar, "set chan flags 0x%x freq %d\n", + be32_to_cpu(reset.flags), + conf->channel->center_freq); + return ar5523_cmd_write(ar, WDCMSG_RESET, &reset, sizeof(reset), 0); +} + +static int ar5523_queue_init(struct ar5523 *ar) +{ + struct ar5523_cmd_txq_setup qinfo; + + ar5523_dbg(ar, "setting up Tx queue\n"); + qinfo.qid = cpu_to_be32(0); + qinfo.len = cpu_to_be32(sizeof(qinfo.attr)); + qinfo.attr.priority = cpu_to_be32(0); /* XXX */ + qinfo.attr.aifs = cpu_to_be32(3); + qinfo.attr.logcwmin = cpu_to_be32(4); + qinfo.attr.logcwmax = cpu_to_be32(10); + qinfo.attr.bursttime = cpu_to_be32(0); + qinfo.attr.mode = cpu_to_be32(0); + qinfo.attr.qflags = cpu_to_be32(1); /* XXX? */ + return ar5523_cmd_write(ar, WDCMSG_SETUP_TX_QUEUE, &qinfo, + sizeof(qinfo), 0); +} + +static int ar5523_switch_chan(struct ar5523 *ar) +{ + int error; + + error = ar5523_set_chan(ar); + if (error) { + ar5523_err(ar, "could not set chan, error %d\n", error); + goto out_err; + } + + /* reset Tx rings */ + error = ar5523_reset_tx_queues(ar); + if (error) { + ar5523_err(ar, "could not reset Tx queues, error %d\n", + error); + goto out_err; + } + /* set Tx rings WME properties */ + error = ar5523_queue_init(ar); + if (error) + ar5523_err(ar, "could not init wme, error %d\n", error); + +out_err: + return error; +} + +static void ar5523_rx_data_put(struct ar5523 *ar, + struct ar5523_rx_data *data) +{ + unsigned long flags; + spin_lock_irqsave(&ar->rx_data_list_lock, flags); + list_move(&data->list, &ar->rx_data_free); + spin_unlock_irqrestore(&ar->rx_data_list_lock, flags); +} + +static void ar5523_data_rx_cb(struct urb *urb) +{ + struct ar5523_rx_data *data = urb->context; + struct ar5523 *ar = data->ar; + struct ar5523_rx_desc *desc; + struct ar5523_chunk *chunk; + struct ieee80211_hw *hw = ar->hw; + struct ieee80211_rx_status *rx_status; + u32 rxlen; + int usblen = urb->actual_length; + int hdrlen, pad; + + ar5523_dbg(ar, "%s\n", __func__); + /* sync/async unlink faults aren't errors */ + if (urb->status) { + if (urb->status != -ESHUTDOWN) + ar5523_err(ar, "%s: USB err: %d\n", __func__, + urb->status); + goto skip; + } + + if (usblen < AR5523_MIN_RXBUFSZ) { + ar5523_err(ar, "RX: wrong xfer size (usblen=%d)\n", usblen); + goto skip; + } + + chunk = (struct ar5523_chunk *) data->skb->data; + + if (((chunk->flags & UATH_CFLAGS_FINAL) == 0) || + chunk->seqnum != 0) { + ar5523_dbg(ar, "RX: No final flag. s: %d f: %02x l: %d\n", + chunk->seqnum, chunk->flags, + be16_to_cpu(chunk->length)); + goto skip; + } + + /* Rx descriptor is located at the end, 32-bit aligned */ + desc = (struct ar5523_rx_desc *) + (data->skb->data + usblen - sizeof(struct ar5523_rx_desc)); + + rxlen = be32_to_cpu(desc->len); + if (rxlen > ar->rxbufsz) { + ar5523_dbg(ar, "RX: Bad descriptor (len=%d)\n", + be32_to_cpu(desc->len)); + goto skip; + } + + if (!rxlen) { + ar5523_dbg(ar, "RX: rxlen is 0\n"); + goto skip; + } + + if (be32_to_cpu(desc->status) != 0) { + ar5523_dbg(ar, "Bad RX status (0x%x len = %d). Skip\n", + be32_to_cpu(desc->status), be32_to_cpu(desc->len)); + goto skip; + } + + skb_reserve(data->skb, sizeof(*chunk)); + skb_put(data->skb, rxlen - sizeof(struct ar5523_rx_desc)); + + hdrlen = ieee80211_get_hdrlen_from_skb(data->skb); + if (!IS_ALIGNED(hdrlen, 4)) { + ar5523_dbg(ar, "eek, alignment workaround activated\n"); + pad = ALIGN(hdrlen, 4) - hdrlen; + memmove(data->skb->data + pad, data->skb->data, hdrlen); + skb_pull(data->skb, pad); + skb_put(data->skb, pad); + } + + rx_status = IEEE80211_SKB_RXCB(data->skb); + memset(rx_status, 0, sizeof(*rx_status)); + rx_status->freq = be32_to_cpu(desc->channel); + rx_status->band = hw->conf.channel->band; + rx_status->signal = -95 + be32_to_cpu(desc->rssi); + + ieee80211_rx_irqsafe(hw, data->skb); + data->skb = NULL; + +skip: + if (data->skb) { + dev_kfree_skb_irq(data->skb); + data->skb = NULL; + } + + ar5523_rx_data_put(ar, data); + if (atomic_inc_return(&ar->rx_data_free_cnt) >= + AR5523_RX_DATA_REFILL_COUNT && + test_bit(AR5523_HW_UP, &ar->flags)) + queue_work(ar->wq, &ar->rx_refill_work); +} + +static void ar5523_rx_refill_work(struct work_struct *work) +{ + struct ar5523 *ar = container_of(work, struct ar5523, rx_refill_work); + struct ar5523_rx_data *data; + unsigned long flags; + int error; + + ar5523_dbg(ar, "%s\n", __func__); + do { + spin_lock_irqsave(&ar->rx_data_list_lock, flags); + + if (!list_empty(&ar->rx_data_free)) + data = (struct ar5523_rx_data *) ar->rx_data_free.next; + else + data = NULL; + spin_unlock_irqrestore(&ar->rx_data_list_lock, flags); + + if (!data) + goto done; + + data->skb = alloc_skb(ar->rxbufsz, GFP_KERNEL); + if (!data->skb) { + ar5523_err(ar, "could not allocate rx skbuff\n"); + return; + } + + usb_fill_bulk_urb(data->urb, ar->dev, + ar5523_data_rx_pipe(ar->dev), data->skb->data, + ar->rxbufsz, ar5523_data_rx_cb, data); + + spin_lock_irqsave(&ar->rx_data_list_lock, flags); + list_move(&data->list, &ar->rx_data_used); + spin_unlock_irqrestore(&ar->rx_data_list_lock, flags); + atomic_dec(&ar->rx_data_free_cnt); + + error = usb_submit_urb(data->urb, GFP_KERNEL); + if (error) { + kfree_skb(data->skb); + if (error != -ENODEV) + ar5523_err(ar, "Err sending rx data urb %d\n", + error); + ar5523_rx_data_put(ar, data); + atomic_inc(&ar->rx_data_free_cnt); + return; + } + + } while (true); +done: + return; +} + +static void ar5523_cancel_rx_bufs(struct ar5523 *ar) +{ + struct ar5523_rx_data *data; + unsigned long flags; + + do { + spin_lock_irqsave(&ar->rx_data_list_lock, flags); + if (!list_empty(&ar->rx_data_used)) + data = (struct ar5523_rx_data *) ar->rx_data_used.next; + else + data = NULL; + spin_unlock_irqrestore(&ar->rx_data_list_lock, flags); + + if (!data) + break; + + usb_kill_urb(data->urb); + list_move(&data->list, &ar->rx_data_free); + atomic_inc(&ar->rx_data_free_cnt); + } while (data); +} + +static void ar5523_free_rx_bufs(struct ar5523 *ar) +{ + struct ar5523_rx_data *data; + + ar5523_cancel_rx_bufs(ar); + while (!list_empty(&ar->rx_data_free)) { + data = (struct ar5523_rx_data *) ar->rx_data_free.next; + list_del(&data->list); + usb_free_urb(data->urb); + } +} + +static int ar5523_alloc_rx_bufs(struct ar5523 *ar) +{ + int i; + + for (i = 0; i < AR5523_RX_DATA_COUNT; i++) { + struct ar5523_rx_data *data = &ar->rx_data[i]; + + data->ar = ar; + data->urb = usb_alloc_urb(0, GFP_KERNEL); + if (!data->urb) { + ar5523_err(ar, "could not allocate rx data urb\n"); + goto err; + } + list_add_tail(&data->list, &ar->rx_data_free); + atomic_inc(&ar->rx_data_free_cnt); + } + return 0; + +err: + ar5523_free_rx_bufs(ar); + return -ENOMEM; +} + +static void ar5523_data_tx_pkt_put(struct ar5523 *ar) +{ + atomic_dec(&ar->tx_nr_total); + if (!atomic_dec_return(&ar->tx_nr_pending)) { + del_timer(&ar->tx_wd_timer); + wake_up(&ar->tx_flush_waitq); + } + + if (atomic_read(&ar->tx_nr_total) < AR5523_TX_DATA_RESTART_COUNT) { + ar5523_dbg(ar, "restart tx queue\n"); + ieee80211_wake_queues(ar->hw); + } +} + +static void ar5523_data_tx_cb(struct urb *urb) +{ + struct sk_buff *skb = urb->context; + struct ieee80211_tx_info *txi = IEEE80211_SKB_CB(skb); + struct ar5523_tx_data *data = (struct ar5523_tx_data *) + txi->driver_data; + struct ar5523 *ar = data->ar; + unsigned long flags; + + ar5523_dbg(ar, "data tx urb completed: %d\n", urb->status); + + spin_lock_irqsave(&ar->tx_data_list_lock, flags); + list_del(&data->list); + spin_unlock_irqrestore(&ar->tx_data_list_lock, flags); + + if (urb->status) { + ar5523_dbg(ar, "%s: urb status: %d\n", __func__, urb->status); + ar5523_data_tx_pkt_put(ar); + ieee80211_free_txskb(ar->hw, skb); + } else { + skb_pull(skb, sizeof(struct ar5523_tx_desc) + sizeof(__be32)); + ieee80211_tx_status_irqsafe(ar->hw, skb); + } + usb_free_urb(urb); +} + +static void ar5523_tx(struct ieee80211_hw *hw, + struct ieee80211_tx_control *control, + struct sk_buff *skb) +{ + struct ieee80211_tx_info *txi = IEEE80211_SKB_CB(skb); + struct ar5523_tx_data *data = (struct ar5523_tx_data *) + txi->driver_data; + struct ar5523 *ar = hw->priv; + unsigned long flags; + + ar5523_dbg(ar, "tx called\n"); + if (atomic_inc_return(&ar->tx_nr_total) >= AR5523_TX_DATA_COUNT) { + ar5523_dbg(ar, "tx queue full\n"); + ar5523_dbg(ar, "stop queues (tot %d pend %d)\n", + atomic_read(&ar->tx_nr_total), + atomic_read(&ar->tx_nr_pending)); + ieee80211_stop_queues(hw); + } + + data->skb = skb; + + spin_lock_irqsave(&ar->tx_data_list_lock, flags); + list_add_tail(&data->list, &ar->tx_queue_pending); + spin_unlock_irqrestore(&ar->tx_data_list_lock, flags); + + ieee80211_queue_work(ar->hw, &ar->tx_work); +} + +static void ar5523_tx_work_locked(struct ar5523 *ar) +{ + struct ar5523_tx_data *data; + struct ar5523_tx_desc *desc; + struct ar5523_chunk *chunk; + struct ieee80211_tx_info *txi; + struct urb *urb; + struct sk_buff *skb; + int error = 0, paylen; + u32 txqid; + unsigned long flags; + + BUILD_BUG_ON(sizeof(struct ar5523_tx_data) > + IEEE80211_TX_INFO_DRIVER_DATA_SIZE); + + ar5523_dbg(ar, "%s\n", __func__); + do { + spin_lock_irqsave(&ar->tx_data_list_lock, flags); + if (!list_empty(&ar->tx_queue_pending)) { + data = (struct ar5523_tx_data *) + ar->tx_queue_pending.next; + list_del(&data->list); + } else + data = NULL; + spin_unlock_irqrestore(&ar->tx_data_list_lock, flags); + + if (!data) + break; + + skb = data->skb; + txqid = 0; + txi = IEEE80211_SKB_CB(skb); + paylen = skb->len; + urb = usb_alloc_urb(0, GFP_KERNEL); + if (!urb) { + ar5523_err(ar, "Failed to allocate TX urb\n"); + ieee80211_free_txskb(ar->hw, skb); + continue; + } + + data->ar = ar; + data->urb = urb; + + desc = (struct ar5523_tx_desc *)skb_push(skb, sizeof(*desc)); + chunk = (struct ar5523_chunk *)skb_push(skb, sizeof(*chunk)); + + chunk->seqnum = 0; + chunk->flags = UATH_CFLAGS_FINAL; + chunk->length = cpu_to_be16(skb->len); + + desc->msglen = cpu_to_be32(skb->len); + desc->msgid = AR5523_DATA_ID; + desc->buflen = cpu_to_be32(paylen); + desc->type = cpu_to_be32(WDCMSG_SEND); + desc->flags = cpu_to_be32(UATH_TX_NOTIFY); + + if (test_bit(AR5523_CONNECTED, &ar->flags)) + desc->connid = cpu_to_be32(AR5523_ID_BSS); + else + desc->connid = cpu_to_be32(AR5523_ID_BROADCAST); + + if (txi->flags & IEEE80211_TX_CTL_USE_MINRATE) + txqid |= UATH_TXQID_MINRATE; + + desc->txqid = cpu_to_be32(txqid); + + urb->transfer_flags = URB_ZERO_PACKET; + usb_fill_bulk_urb(urb, ar->dev, ar5523_data_tx_pipe(ar->dev), + skb->data, skb->len, ar5523_data_tx_cb, skb); + + spin_lock_irqsave(&ar->tx_data_list_lock, flags); + list_add_tail(&data->list, &ar->tx_queue_submitted); + spin_unlock_irqrestore(&ar->tx_data_list_lock, flags); + mod_timer(&ar->tx_wd_timer, jiffies + AR5523_TX_WD_TIMEOUT); + atomic_inc(&ar->tx_nr_pending); + + ar5523_dbg(ar, "TX Frame (%d pending)\n", + atomic_read(&ar->tx_nr_pending)); + error = usb_submit_urb(urb, GFP_KERNEL); + if (error) { + ar5523_err(ar, "error %d when submitting tx urb\n", + error); + spin_lock_irqsave(&ar->tx_data_list_lock, flags); + list_del(&data->list); + spin_unlock_irqrestore(&ar->tx_data_list_lock, flags); + atomic_dec(&ar->tx_nr_pending); + ar5523_data_tx_pkt_put(ar); + usb_free_urb(urb); + ieee80211_free_txskb(ar->hw, skb); + } + } while (true); +} + +static void ar5523_tx_work(struct work_struct *work) +{ + struct ar5523 *ar = container_of(work, struct ar5523, tx_work); + + ar5523_dbg(ar, "%s\n", __func__); + mutex_lock(&ar->mutex); + ar5523_tx_work_locked(ar); + mutex_unlock(&ar->mutex); +} + +static void ar5523_tx_wd_timer(unsigned long arg) +{ + struct ar5523 *ar = (struct ar5523 *) arg; + + ar5523_dbg(ar, "TX watchdog timer triggered\n"); + ieee80211_queue_work(ar->hw, &ar->tx_wd_work); +} + +static void ar5523_tx_wd_work(struct work_struct *work) +{ + struct ar5523 *ar = container_of(work, struct ar5523, tx_wd_work); + + /* Occasionally the TX queues stop responding. The only way to + * recover seems to be to reset the dongle. + */ + + mutex_lock(&ar->mutex); + ar5523_err(ar, "TX queue stuck (tot %d pend %d)\n", + atomic_read(&ar->tx_nr_total), + atomic_read(&ar->tx_nr_pending)); + + ar5523_err(ar, "Will restart dongle.\n"); + ar5523_cmd_write(ar, WDCMSG_TARGET_RESET, NULL, 0, 0); + mutex_unlock(&ar->mutex); +} + +static void ar5523_flush_tx(struct ar5523 *ar) +{ + ar5523_tx_work_locked(ar); + + /* Don't waste time trying to flush if USB is disconnected */ + if (test_bit(AR5523_USB_DISCONNECTED, &ar->flags)) + return; + if (!wait_event_timeout(ar->tx_flush_waitq, + !atomic_read(&ar->tx_nr_pending), AR5523_FLUSH_TIMEOUT)) + ar5523_err(ar, "flush timeout (tot %d pend %d)\n", + atomic_read(&ar->tx_nr_total), + atomic_read(&ar->tx_nr_pending)); +} + +static void ar5523_free_tx_cmd(struct ar5523 *ar) +{ + struct ar5523_tx_cmd *cmd = &ar->tx_cmd; + + usb_free_coherent(ar->dev, AR5523_MAX_RXCMDSZ, cmd->buf_tx, + cmd->urb_tx->transfer_dma); + usb_free_urb(cmd->urb_tx); +} + +static int ar5523_alloc_tx_cmd(struct ar5523 *ar) +{ + struct ar5523_tx_cmd *cmd = &ar->tx_cmd; + + cmd->ar = ar; + init_completion(&cmd->done); + + cmd->urb_tx = usb_alloc_urb(0, GFP_KERNEL); + if (!cmd->urb_tx) { + ar5523_err(ar, "could not allocate urb\n"); + return -ENOMEM; + } + cmd->buf_tx = usb_alloc_coherent(ar->dev, AR5523_MAX_TXCMDSZ, + GFP_KERNEL, + &cmd->urb_tx->transfer_dma); + if (!cmd->buf_tx) { + usb_free_urb(cmd->urb_tx); + return -ENOMEM; + } + return 0; +} + +/* + * This function is called periodically (every second) when associated to + * query device statistics. + */ +static void ar5523_stat_work(struct work_struct *work) +{ + struct ar5523 *ar = container_of(work, struct ar5523, stat_work.work); + int error; + + ar5523_dbg(ar, "%s\n", __func__); + mutex_lock(&ar->mutex); + + /* + * Send request for statistics asynchronously once a second. This + * seems to be important. Throughput is a lot better if this is done. + */ + error = ar5523_cmd_write(ar, WDCMSG_TARGET_GET_STATS, NULL, 0, 0); + if (error) + ar5523_err(ar, "could not query stats, error %d\n", error); + mutex_unlock(&ar->mutex); + ieee80211_queue_delayed_work(ar->hw, &ar->stat_work, HZ); +} + +/* + * Interface routines to the mac80211 stack. + */ +static int ar5523_start(struct ieee80211_hw *hw) +{ + struct ar5523 *ar = hw->priv; + int error; + __be32 val; + + ar5523_dbg(ar, "start called\n"); + + mutex_lock(&ar->mutex); + val = cpu_to_be32(0); + ar5523_cmd_write(ar, WDCMSG_BIND, &val, sizeof(val), 0); + + /* set MAC address */ + ar5523_config_multi(ar, CFG_MAC_ADDR, &ar->hw->wiphy->perm_addr, + ETH_ALEN); + + /* XXX honor net80211 state */ + ar5523_config(ar, CFG_RATE_CONTROL_ENABLE, 0x00000001); + ar5523_config(ar, CFG_DIVERSITY_CTL, 0x00000001); + ar5523_config(ar, CFG_ABOLT, 0x0000003f); + ar5523_config(ar, CFG_WME_ENABLED, 0x00000000); + + ar5523_config(ar, CFG_SERVICE_TYPE, 1); + ar5523_config(ar, CFG_TP_SCALE, 0x00000000); + ar5523_config(ar, CFG_TPC_HALF_DBM5, 0x0000003c); + ar5523_config(ar, CFG_TPC_HALF_DBM2, 0x0000003c); + ar5523_config(ar, CFG_OVERRD_TX_POWER, 0x00000000); + ar5523_config(ar, CFG_GMODE_PROTECTION, 0x00000000); + ar5523_config(ar, CFG_GMODE_PROTECT_RATE_INDEX, 0x00000003); + ar5523_config(ar, CFG_PROTECTION_TYPE, 0x00000000); + ar5523_config(ar, CFG_MODE_CTS, 0x00000002); + + error = ar5523_cmd_read(ar, WDCMSG_TARGET_START, NULL, 0, + &val, sizeof(val), AR5523_CMD_FLAG_MAGIC); + if (error) { + ar5523_dbg(ar, "could not start target, error %d\n", error); + goto err; + } + ar5523_dbg(ar, "WDCMSG_TARGET_START returns handle: 0x%x\n", + be32_to_cpu(val)); + + ar5523_switch_chan(ar); + + val = cpu_to_be32(TARGET_DEVICE_AWAKE); + ar5523_cmd_write(ar, WDCMSG_SET_PWR_MODE, &val, sizeof(val), 0); + /* XXX? check */ + ar5523_cmd_write(ar, WDCMSG_RESET_KEY_CACHE, NULL, 0, 0); + + set_bit(AR5523_HW_UP, &ar->flags); + queue_work(ar->wq, &ar->rx_refill_work); + + /* enable Rx */ + ar5523_set_rxfilter(ar, 0, UATH_FILTER_OP_INIT); + ar5523_set_rxfilter(ar, + UATH_FILTER_RX_UCAST | UATH_FILTER_RX_MCAST | + UATH_FILTER_RX_BCAST | UATH_FILTER_RX_BEACON, + UATH_FILTER_OP_SET); + + ar5523_set_ledsteady(ar, UATH_LED_ACTIVITY, UATH_LED_ON); + ar5523_dbg(ar, "start OK\n"); + +err: + mutex_unlock(&ar->mutex); + return error; +} + +static void ar5523_stop(struct ieee80211_hw *hw) +{ + struct ar5523 *ar = hw->priv; + + ar5523_dbg(ar, "stop called\n"); + + cancel_delayed_work_sync(&ar->stat_work); + mutex_lock(&ar->mutex); + clear_bit(AR5523_HW_UP, &ar->flags); + + ar5523_set_ledsteady(ar, UATH_LED_LINK, UATH_LED_OFF); + ar5523_set_ledsteady(ar, UATH_LED_ACTIVITY, UATH_LED_OFF); + + ar5523_cmd_write(ar, WDCMSG_TARGET_STOP, NULL, 0, 0); + + del_timer_sync(&ar->tx_wd_timer); + cancel_work_sync(&ar->tx_wd_work); + cancel_work_sync(&ar->rx_refill_work); + ar5523_cancel_rx_bufs(ar); + mutex_unlock(&ar->mutex); +} + +static int ar5523_set_rts_threshold(struct ieee80211_hw *hw, u32 value) +{ + struct ar5523 *ar = hw->priv; + int ret; + + ar5523_dbg(ar, "set_rts_threshold called\n"); + mutex_lock(&ar->mutex); + + ret = ar5523_config(ar, CFG_USER_RTS_THRESHOLD, value); + + mutex_unlock(&ar->mutex); + return ret; +} + +static void ar5523_flush(struct ieee80211_hw *hw, bool drop) +{ + struct ar5523 *ar = hw->priv; + + ar5523_dbg(ar, "flush called\n"); + ar5523_flush_tx(ar); +} + +static int ar5523_add_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct ar5523 *ar = hw->priv; + + ar5523_dbg(ar, "add interface called\n"); + + if (ar->vif) { + ar5523_dbg(ar, "invalid add_interface\n"); + return -EOPNOTSUPP; + } + + switch (vif->type) { + case NL80211_IFTYPE_STATION: + ar->vif = vif; + break; + default: + return -EOPNOTSUPP; + } + return 0; +} + +static void ar5523_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct ar5523 *ar = hw->priv; + + ar5523_dbg(ar, "remove interface called\n"); + ar->vif = NULL; +} + +static int ar5523_hwconfig(struct ieee80211_hw *hw, u32 changed) +{ + struct ar5523 *ar = hw->priv; + + ar5523_dbg(ar, "config called\n"); + mutex_lock(&ar->mutex); + if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { + ar5523_dbg(ar, "Do channel switch\n"); + ar5523_flush_tx(ar); + ar5523_switch_chan(ar); + } + mutex_unlock(&ar->mutex); + return 0; +} + +static int ar5523_get_wlan_mode(struct ar5523 *ar, + struct ieee80211_bss_conf *bss_conf) +{ + struct ieee80211_supported_band *band; + int bit; + struct ieee80211_sta *sta; + u32 sta_rate_set; + + band = ar->hw->wiphy->bands[ar->hw->conf.channel->band]; + sta = ieee80211_find_sta(ar->vif, bss_conf->bssid); + if (!sta) { + ar5523_info(ar, "STA not found!\n"); + return WLAN_MODE_11b; + } + sta_rate_set = sta->supp_rates[ar->hw->conf.channel->band]; + + for (bit = 0; bit < band->n_bitrates; bit++) { + if (sta_rate_set & 1) { + int rate = band->bitrates[bit].bitrate; + switch (rate) { + case 60: + case 90: + case 120: + case 180: + case 240: + case 360: + case 480: + case 540: + return WLAN_MODE_11g; + } + } + sta_rate_set >>= 1; + } + return WLAN_MODE_11b; +} + +static void ar5523_create_rateset(struct ar5523 *ar, + struct ieee80211_bss_conf *bss_conf, + struct ar5523_cmd_rateset *rs, + bool basic) +{ + struct ieee80211_supported_band *band; + struct ieee80211_sta *sta; + int bit, i = 0; + u32 sta_rate_set, basic_rate_set; + + sta = ieee80211_find_sta(ar->vif, bss_conf->bssid); + basic_rate_set = bss_conf->basic_rates; + if (!sta) { + ar5523_info(ar, "STA not found. Cannot set rates\n"); + sta_rate_set = bss_conf->basic_rates; + } + sta_rate_set = sta->supp_rates[ar->hw->conf.channel->band]; + + ar5523_dbg(ar, "sta rate_set = %08x\n", sta_rate_set); + + band = ar->hw->wiphy->bands[ar->hw->conf.channel->band]; + for (bit = 0; bit < band->n_bitrates; bit++) { + BUG_ON(i >= AR5523_MAX_NRATES); + ar5523_dbg(ar, "Considering rate %d : %d\n", + band->bitrates[bit].hw_value, sta_rate_set & 1); + if (sta_rate_set & 1) { + rs->set[i] = band->bitrates[bit].hw_value; + if (basic_rate_set & 1 && basic) + rs->set[i] |= 0x80; + i++; + } + sta_rate_set >>= 1; + basic_rate_set >>= 1; + } + + rs->length = i; +} + +static int ar5523_set_basic_rates(struct ar5523 *ar, + struct ieee80211_bss_conf *bss) +{ + struct ar5523_cmd_rates rates; + + memset(&rates, 0, sizeof(rates)); + rates.connid = cpu_to_be32(2); /* XXX */ + rates.size = cpu_to_be32(sizeof(struct ar5523_cmd_rateset)); + ar5523_create_rateset(ar, bss, &rates.rateset, true); + + return ar5523_cmd_write(ar, WDCMSG_SET_BASIC_RATE, &rates, + sizeof(rates), 0); +} + +static int ar5523_create_connection(struct ar5523 *ar, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss) +{ + struct ar5523_cmd_create_connection create; + int wlan_mode; + + memset(&create, 0, sizeof(create)); + create.connid = cpu_to_be32(2); + create.bssid = cpu_to_be32(0); + /* XXX packed or not? */ + create.size = cpu_to_be32(sizeof(struct ar5523_cmd_rateset)); + + ar5523_create_rateset(ar, bss, &create.connattr.rateset, false); + + wlan_mode = ar5523_get_wlan_mode(ar, bss); + create.connattr.wlanmode = cpu_to_be32(wlan_mode); + + return ar5523_cmd_write(ar, WDCMSG_CREATE_CONNECTION, &create, + sizeof(create), 0); +} + +static int ar5523_write_associd(struct ar5523 *ar, + struct ieee80211_bss_conf *bss) +{ + struct ar5523_cmd_set_associd associd; + + memset(&associd, 0, sizeof(associd)); + associd.defaultrateix = cpu_to_be32(0); /* XXX */ + associd.associd = cpu_to_be32(bss->aid); + associd.timoffset = cpu_to_be32(0x3b); /* XXX */ + memcpy(associd.bssid, bss->bssid, ETH_ALEN); + return ar5523_cmd_write(ar, WDCMSG_WRITE_ASSOCID, &associd, + sizeof(associd), 0); +} + +static void ar5523_bss_info_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss, + u32 changed) +{ + struct ar5523 *ar = hw->priv; + int error; + + ar5523_dbg(ar, "bss_info_changed called\n"); + mutex_lock(&ar->mutex); + + if (!(changed & BSS_CHANGED_ASSOC)) + goto out_unlock; + + if (bss->assoc) { + error = ar5523_create_connection(ar, vif, bss); + if (error) { + ar5523_err(ar, "could not create connection\n"); + goto out_unlock; + } + + error = ar5523_set_basic_rates(ar, bss); + if (error) { + ar5523_err(ar, "could not set negotiated rate set\n"); + goto out_unlock; + } + + error = ar5523_write_associd(ar, bss); + if (error) { + ar5523_err(ar, "could not set association\n"); + goto out_unlock; + } + + /* turn link LED on */ + ar5523_set_ledsteady(ar, UATH_LED_LINK, UATH_LED_ON); + set_bit(AR5523_CONNECTED, &ar->flags); + ieee80211_queue_delayed_work(hw, &ar->stat_work, HZ); + + } else { + cancel_delayed_work(&ar->stat_work); + clear_bit(AR5523_CONNECTED, &ar->flags); + ar5523_set_ledsteady(ar, UATH_LED_LINK, UATH_LED_OFF); + } + +out_unlock: + mutex_unlock(&ar->mutex); + +} + +#define AR5523_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \ + FIF_ALLMULTI | \ + FIF_FCSFAIL | \ + FIF_OTHER_BSS) + +static void ar5523_configure_filter(struct ieee80211_hw *hw, + unsigned int changed_flags, + unsigned int *total_flags, + u64 multicast) +{ + struct ar5523 *ar = hw->priv; + u32 filter = 0; + + ar5523_dbg(ar, "configure_filter called\n"); + mutex_lock(&ar->mutex); + ar5523_flush_tx(ar); + + *total_flags &= AR5523_SUPPORTED_FILTERS; + + /* The filters seems strange. UATH_FILTER_RX_BCAST and + * UATH_FILTER_RX_MCAST does not result in those frames being RXed. + * The only way I have found to get [mb]cast frames seems to be + * to set UATH_FILTER_RX_PROM. */ + filter |= UATH_FILTER_RX_UCAST | UATH_FILTER_RX_MCAST | + UATH_FILTER_RX_BCAST | UATH_FILTER_RX_BEACON | + UATH_FILTER_RX_PROM; + + ar5523_set_rxfilter(ar, 0, UATH_FILTER_OP_INIT); + ar5523_set_rxfilter(ar, filter, UATH_FILTER_OP_SET); + + mutex_unlock(&ar->mutex); +} + +static const struct ieee80211_ops ar5523_ops = { + .start = ar5523_start, + .stop = ar5523_stop, + .tx = ar5523_tx, + .set_rts_threshold = ar5523_set_rts_threshold, + .add_interface = ar5523_add_interface, + .remove_interface = ar5523_remove_interface, + .config = ar5523_hwconfig, + .bss_info_changed = ar5523_bss_info_changed, + .configure_filter = ar5523_configure_filter, + .flush = ar5523_flush, +}; + +static int ar5523_host_available(struct ar5523 *ar) +{ + struct ar5523_cmd_host_available setup; + + /* inform target the host is available */ + setup.sw_ver_major = cpu_to_be32(ATH_SW_VER_MAJOR); + setup.sw_ver_minor = cpu_to_be32(ATH_SW_VER_MINOR); + setup.sw_ver_patch = cpu_to_be32(ATH_SW_VER_PATCH); + setup.sw_ver_build = cpu_to_be32(ATH_SW_VER_BUILD); + return ar5523_cmd_read(ar, WDCMSG_HOST_AVAILABLE, + &setup, sizeof(setup), NULL, 0, 0); +} + +static int ar5523_get_devstatus(struct ar5523 *ar) +{ + u8 macaddr[ETH_ALEN]; + int error; + + /* retrieve MAC address */ + error = ar5523_get_status(ar, ST_MAC_ADDR, macaddr, ETH_ALEN); + if (error) { + ar5523_err(ar, "could not read MAC address\n"); + return error; + } + + SET_IEEE80211_PERM_ADDR(ar->hw, macaddr); + + error = ar5523_get_status(ar, ST_SERIAL_NUMBER, + &ar->serial[0], sizeof(ar->serial)); + if (error) { + ar5523_err(ar, "could not read device serial number\n"); + return error; + } + return 0; +} + +#define AR5523_SANE_RXBUFSZ 2000 + +static int ar5523_get_max_rxsz(struct ar5523 *ar) +{ + int error; + __be32 rxsize; + + /* Get max rx size */ + error = ar5523_get_status(ar, ST_WDC_TRANSPORT_CHUNK_SIZE, &rxsize, + sizeof(rxsize)); + if (error != 0) { + ar5523_err(ar, "could not read max RX size\n"); + return error; + } + + ar->rxbufsz = be32_to_cpu(rxsize); + + if (!ar->rxbufsz || ar->rxbufsz > AR5523_SANE_RXBUFSZ) { + ar5523_err(ar, "Bad rxbufsz from device. Using %d instead\n", + AR5523_SANE_RXBUFSZ); + ar->rxbufsz = AR5523_SANE_RXBUFSZ; + } + + ar5523_dbg(ar, "Max RX buf size: %d\n", ar->rxbufsz); + return 0; +} + +/* + * This is copied from rtl818x, but we should probably move this + * to common code as in OpenBSD. + */ +static const struct ieee80211_rate ar5523_rates[] = { + { .bitrate = 10, .hw_value = 2, }, + { .bitrate = 20, .hw_value = 4 }, + { .bitrate = 55, .hw_value = 11, }, + { .bitrate = 110, .hw_value = 22, }, + { .bitrate = 60, .hw_value = 12, }, + { .bitrate = 90, .hw_value = 18, }, + { .bitrate = 120, .hw_value = 24, }, + { .bitrate = 180, .hw_value = 36, }, + { .bitrate = 240, .hw_value = 48, }, + { .bitrate = 360, .hw_value = 72, }, + { .bitrate = 480, .hw_value = 96, }, + { .bitrate = 540, .hw_value = 108, }, +}; + +static const struct ieee80211_channel ar5523_channels[] = { + { .center_freq = 2412 }, + { .center_freq = 2417 }, + { .center_freq = 2422 }, + { .center_freq = 2427 }, + { .center_freq = 2432 }, + { .center_freq = 2437 }, + { .center_freq = 2442 }, + { .center_freq = 2447 }, + { .center_freq = 2452 }, + { .center_freq = 2457 }, + { .center_freq = 2462 }, + { .center_freq = 2467 }, + { .center_freq = 2472 }, + { .center_freq = 2484 }, +}; + +static int ar5523_init_modes(struct ar5523 *ar) +{ + BUILD_BUG_ON(sizeof(ar->channels) != sizeof(ar5523_channels)); + BUILD_BUG_ON(sizeof(ar->rates) != sizeof(ar5523_rates)); + + memcpy(ar->channels, ar5523_channels, sizeof(ar5523_channels)); + memcpy(ar->rates, ar5523_rates, sizeof(ar5523_rates)); + + ar->band.band = IEEE80211_BAND_2GHZ; + ar->band.channels = ar->channels; + ar->band.n_channels = ARRAY_SIZE(ar5523_channels); + ar->band.bitrates = ar->rates; + ar->band.n_bitrates = ARRAY_SIZE(ar5523_rates); + ar->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &ar->band; + return 0; +} + +/* + * Load the MIPS R4000 microcode into the device. Once the image is loaded, + * the device will detach itself from the bus and reattach later with a new + * product Id (a la ezusb). + */ +static int ar5523_load_firmware(struct usb_device *dev) +{ + struct ar5523_fwblock *txblock, *rxblock; + const struct firmware *fw; + void *fwbuf; + int len, offset; + int foolen; /* XXX(hch): handle short transfers */ + int error = -ENXIO; + + if (request_firmware(&fw, AR5523_FIRMWARE_FILE, &dev->dev)) { + dev_err(&dev->dev, "no firmware found: %s\n", + AR5523_FIRMWARE_FILE); + return -ENOENT; + } + + txblock = kmalloc(sizeof(*txblock), GFP_KERNEL); + if (!txblock) + goto out; + + rxblock = kmalloc(sizeof(*rxblock), GFP_KERNEL); + if (!rxblock) + goto out_free_txblock; + + fwbuf = kmalloc(AR5523_MAX_FWBLOCK_SIZE, GFP_KERNEL); + if (!fwbuf) + goto out_free_rxblock; + + memset(txblock, 0, sizeof(struct ar5523_fwblock)); + txblock->flags = cpu_to_be32(AR5523_WRITE_BLOCK); + txblock->total = cpu_to_be32(fw->size); + + offset = 0; + len = fw->size; + while (len > 0) { + int mlen = min(len, AR5523_MAX_FWBLOCK_SIZE); + + txblock->remain = cpu_to_be32(len - mlen); + txblock->len = cpu_to_be32(mlen); + + /* send firmware block meta-data */ + error = usb_bulk_msg(dev, ar5523_cmd_tx_pipe(dev), + txblock, sizeof(*txblock), &foolen, + AR5523_CMD_TIMEOUT); + if (error) { + dev_err(&dev->dev, + "could not send firmware block info\n"); + goto out_free_fwbuf; + } + + /* send firmware block data */ + memcpy(fwbuf, fw->data + offset, mlen); + error = usb_bulk_msg(dev, ar5523_data_tx_pipe(dev), + fwbuf, mlen, &foolen, + AR5523_DATA_TIMEOUT); + if (error) { + dev_err(&dev->dev, + "could not send firmware block data\n"); + goto out_free_fwbuf; + } + + /* wait for ack from firmware */ + error = usb_bulk_msg(dev, ar5523_cmd_rx_pipe(dev), + rxblock, sizeof(*rxblock), &foolen, + AR5523_CMD_TIMEOUT); + if (error) { + dev_err(&dev->dev, + "could not read firmware answer\n"); + goto out_free_fwbuf; + } + + len -= mlen; + offset += mlen; + } + + /* + * Set the error to -ENXIO to make sure we continue probing for + * a driver. + */ + error = -ENXIO; + + out_free_fwbuf: + kfree(fwbuf); + out_free_rxblock: + kfree(rxblock); + out_free_txblock: + kfree(txblock); + out: + release_firmware(fw); + return error; +} + +static int ar5523_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct usb_device *dev = interface_to_usbdev(intf); + struct ieee80211_hw *hw; + struct ar5523 *ar; + int error = -ENOMEM; + + /* + * Load firmware if the device requires it. This will return + * -ENXIO on success and we'll get called back afer the usb + * id changes to indicate that the firmware is present. + */ + if (id->driver_info & AR5523_FLAG_PRE_FIRMWARE) + return ar5523_load_firmware(dev); + + + hw = ieee80211_alloc_hw(sizeof(*ar), &ar5523_ops); + if (!hw) + goto out; + SET_IEEE80211_DEV(hw, &intf->dev); + + ar = hw->priv; + ar->hw = hw; + ar->dev = dev; + mutex_init(&ar->mutex); + + INIT_DELAYED_WORK(&ar->stat_work, ar5523_stat_work); + init_timer(&ar->tx_wd_timer); + setup_timer(&ar->tx_wd_timer, ar5523_tx_wd_timer, (unsigned long) ar); + INIT_WORK(&ar->tx_wd_work, ar5523_tx_wd_work); + INIT_WORK(&ar->tx_work, ar5523_tx_work); + INIT_LIST_HEAD(&ar->tx_queue_pending); + INIT_LIST_HEAD(&ar->tx_queue_submitted); + spin_lock_init(&ar->tx_data_list_lock); + atomic_set(&ar->tx_nr_total, 0); + atomic_set(&ar->tx_nr_pending, 0); + init_waitqueue_head(&ar->tx_flush_waitq); + + atomic_set(&ar->rx_data_free_cnt, 0); + INIT_WORK(&ar->rx_refill_work, ar5523_rx_refill_work); + INIT_LIST_HEAD(&ar->rx_data_free); + INIT_LIST_HEAD(&ar->rx_data_used); + spin_lock_init(&ar->rx_data_list_lock); + + ar->wq = create_singlethread_workqueue("ar5523"); + if (!ar->wq) { + ar5523_err(ar, "Could not create wq\n"); + goto out_free_ar; + } + + error = ar5523_alloc_rx_bufs(ar); + if (error) { + ar5523_err(ar, "Could not allocate rx buffers\n"); + goto out_free_wq; + } + + error = ar5523_alloc_rx_cmd(ar); + if (error) { + ar5523_err(ar, "Could not allocate rx command buffers\n"); + goto out_free_rx_bufs; + } + + error = ar5523_alloc_tx_cmd(ar); + if (error) { + ar5523_err(ar, "Could not allocate tx command buffers\n"); + goto out_free_rx_cmd; + } + + error = ar5523_submit_rx_cmd(ar); + if (error) { + ar5523_err(ar, "Failed to submit rx cmd\n"); + goto out_free_tx_cmd; + } + + /* + * We're now ready to send/receive firmware commands. + */ + error = ar5523_host_available(ar); + if (error) { + ar5523_err(ar, "could not initialize adapter\n"); + goto out_cancel_rx_cmd; + } + + error = ar5523_get_max_rxsz(ar); + if (error) { + ar5523_err(ar, "could not get caps from adapter\n"); + goto out_cancel_rx_cmd; + } + + error = ar5523_get_devcap(ar); + if (error) { + ar5523_err(ar, "could not get caps from adapter\n"); + goto out_cancel_rx_cmd; + } + + error = ar5523_get_devstatus(ar); + if (error != 0) { + ar5523_err(ar, "could not get device status\n"); + goto out_cancel_rx_cmd; + } + + ar5523_info(ar, "MAC/BBP AR5523, RF AR%c112\n", + (id->driver_info & AR5523_FLAG_ABG) ? '5' : '2'); + + ar->vif = NULL; + hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | + IEEE80211_HW_SIGNAL_DBM | + IEEE80211_HW_HAS_RATE_CONTROL; + hw->extra_tx_headroom = sizeof(struct ar5523_tx_desc) + + sizeof(struct ar5523_chunk); + hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); + hw->queues = 1; + + error = ar5523_init_modes(ar); + if (error) + goto out_cancel_rx_cmd; + + usb_set_intfdata(intf, hw); + + error = ieee80211_register_hw(hw); + if (error) { + ar5523_err(ar, "could not register device\n"); + goto out_cancel_rx_cmd; + } + + ar5523_info(ar, "Found and initialized AR5523 device\n"); + return 0; + +out_cancel_rx_cmd: + ar5523_cancel_rx_cmd(ar); +out_free_tx_cmd: + ar5523_free_tx_cmd(ar); +out_free_rx_cmd: + ar5523_free_rx_cmd(ar); +out_free_rx_bufs: + ar5523_free_rx_bufs(ar); +out_free_wq: + destroy_workqueue(ar->wq); +out_free_ar: + ieee80211_free_hw(hw); +out: + return error; +} + +static void ar5523_disconnect(struct usb_interface *intf) +{ + struct ieee80211_hw *hw = usb_get_intfdata(intf); + struct ar5523 *ar = hw->priv; + + ar5523_dbg(ar, "detaching\n"); + set_bit(AR5523_USB_DISCONNECTED, &ar->flags); + + ieee80211_unregister_hw(hw); + + ar5523_cancel_rx_cmd(ar); + ar5523_free_tx_cmd(ar); + ar5523_free_rx_cmd(ar); + ar5523_free_rx_bufs(ar); + + destroy_workqueue(ar->wq); + + ieee80211_free_hw(hw); + usb_set_intfdata(intf, NULL); +} + +#define AR5523_DEVICE_UG(vendor, device) \ + { USB_DEVICE((vendor), (device)) }, \ + { USB_DEVICE((vendor), (device) + 1), \ + .driver_info = AR5523_FLAG_PRE_FIRMWARE } +#define AR5523_DEVICE_UX(vendor, device) \ + { USB_DEVICE((vendor), (device)), \ + .driver_info = AR5523_FLAG_ABG }, \ + { USB_DEVICE((vendor), (device) + 1), \ + .driver_info = AR5523_FLAG_ABG|AR5523_FLAG_PRE_FIRMWARE } + +static struct usb_device_id ar5523_id_table[] = { + AR5523_DEVICE_UG(0x168c, 0x0001), /* Atheros / AR5523 */ + AR5523_DEVICE_UG(0x0cf3, 0x0001), /* Atheros2 / AR5523_1 */ + AR5523_DEVICE_UG(0x0cf3, 0x0003), /* Atheros2 / AR5523_2 */ + AR5523_DEVICE_UX(0x0cf3, 0x0005), /* Atheros2 / AR5523_3 */ + AR5523_DEVICE_UG(0x0d8e, 0x7801), /* Conceptronic / AR5523_1 */ + AR5523_DEVICE_UX(0x0d8e, 0x7811), /* Conceptronic / AR5523_2 */ + AR5523_DEVICE_UX(0x2001, 0x3a00), /* Dlink / DWLAG132 */ + AR5523_DEVICE_UG(0x2001, 0x3a02), /* Dlink / DWLG132 */ + AR5523_DEVICE_UX(0x2001, 0x3a04), /* Dlink / DWLAG122 */ + AR5523_DEVICE_UG(0x1690, 0x0712), /* Gigaset / AR5523 */ + AR5523_DEVICE_UG(0x1690, 0x0710), /* Gigaset / SMCWUSBTG */ + AR5523_DEVICE_UG(0x129b, 0x160c), /* Gigaset / USB stick 108 + (CyberTAN Technology) */ + AR5523_DEVICE_UG(0x16ab, 0x7801), /* Globalsun / AR5523_1 */ + AR5523_DEVICE_UX(0x16ab, 0x7811), /* Globalsun / AR5523_2 */ + AR5523_DEVICE_UG(0x0d8e, 0x7802), /* Globalsun / AR5523_3 */ + AR5523_DEVICE_UX(0x0846, 0x4300), /* Netgear / WG111U */ + AR5523_DEVICE_UG(0x0846, 0x4250), /* Netgear / WG111T */ + AR5523_DEVICE_UG(0x0846, 0x5f00), /* Netgear / WPN111 */ + AR5523_DEVICE_UG(0x157e, 0x3006), /* Umedia / AR5523_1 */ + AR5523_DEVICE_UX(0x157e, 0x3205), /* Umedia / AR5523_2 */ + AR5523_DEVICE_UG(0x157e, 0x3006), /* Umedia / TEW444UBEU */ + AR5523_DEVICE_UG(0x1435, 0x0826), /* Wistronneweb / AR5523_1 */ + AR5523_DEVICE_UX(0x1435, 0x0828), /* Wistronneweb / AR5523_2 */ + AR5523_DEVICE_UG(0x0cde, 0x0012), /* Zcom / AR5523 */ + AR5523_DEVICE_UG(0x1385, 0x4250), /* Netgear3 / WG111T (2) */ + AR5523_DEVICE_UG(0x1385, 0x5f00), /* Netgear / WPN111 */ + AR5523_DEVICE_UG(0x1385, 0x5f02), /* Netgear / WPN111 */ + { } +}; +MODULE_DEVICE_TABLE(usb, ar5523_id_table); + +static struct usb_driver ar5523_driver = { + .name = "ar5523", + .id_table = ar5523_id_table, + .probe = ar5523_probe, + .disconnect = ar5523_disconnect, +}; + +static int __init ar5523_init(void) +{ + return usb_register(&ar5523_driver); +} + +static void __exit ar5523_exit(void) +{ + usb_deregister(&ar5523_driver); +} + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_FIRMWARE(AR5523_FIRMWARE_FILE); + +module_init(ar5523_init); +module_exit(ar5523_exit); diff --git a/drivers/net/wireless/ath/ar5523/ar5523.h b/drivers/net/wireless/ath/ar5523/ar5523.h new file mode 100644 index 00000000000..6086ba3fb54 --- /dev/null +++ b/drivers/net/wireless/ath/ar5523/ar5523.h @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2006 Damien Bergamini + * Copyright (c) 2006 Sam Leffler, Errno Consulting + * Copyright (c) 2007 Christoph Hellwig + * Copyright (c) 2008-2009 Weongyo Jeong + * Copyright (c) 2012 Pontus Fuchs + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#define AR5523_FLAG_PRE_FIRMWARE (1 << 0) +#define AR5523_FLAG_ABG (1 << 1) + +#define AR5523_FIRMWARE_FILE "ar5523.bin" + +#define AR5523_CMD_TX_PIPE 0x01 +#define AR5523_DATA_TX_PIPE 0x02 +#define AR5523_CMD_RX_PIPE 0x81 +#define AR5523_DATA_RX_PIPE 0x82 + +#define ar5523_cmd_tx_pipe(dev) \ + usb_sndbulkpipe((dev), AR5523_CMD_TX_PIPE) +#define ar5523_data_tx_pipe(dev) \ + usb_sndbulkpipe((dev), AR5523_DATA_TX_PIPE) +#define ar5523_cmd_rx_pipe(dev) \ + usb_rcvbulkpipe((dev), AR5523_CMD_RX_PIPE) +#define ar5523_data_rx_pipe(dev) \ + usb_rcvbulkpipe((dev), AR5523_DATA_RX_PIPE) + +#define AR5523_DATA_TIMEOUT 10000 +#define AR5523_CMD_TIMEOUT 1000 + +#define AR5523_TX_DATA_COUNT 8 +#define AR5523_TX_DATA_RESTART_COUNT 2 +#define AR5523_RX_DATA_COUNT 16 +#define AR5523_RX_DATA_REFILL_COUNT 8 + +#define AR5523_CMD_ID 1 +#define AR5523_DATA_ID 2 + +#define AR5523_TX_WD_TIMEOUT (HZ * 2) +#define AR5523_FLUSH_TIMEOUT (HZ * 3) + +enum AR5523_flags { + AR5523_HW_UP, + AR5523_USB_DISCONNECTED, + AR5523_CONNECTED +}; + +struct ar5523_tx_cmd { + struct ar5523 *ar; + struct urb *urb_tx; + void *buf_tx; + void *odata; + int olen; + int flags; + int res; + struct completion done; +}; + +/* This struct is placed in tx_info->driver_data. It must not be larger + * than IEEE80211_TX_INFO_DRIVER_DATA_SIZE. + */ +struct ar5523_tx_data { + struct list_head list; + struct ar5523 *ar; + struct sk_buff *skb; + struct urb *urb; +}; + +struct ar5523_rx_data { + struct list_head list; + struct ar5523 *ar; + struct urb *urb; + struct sk_buff *skb; +}; + +struct ar5523 { + struct usb_device *dev; + struct ieee80211_hw *hw; + + unsigned long flags; + struct mutex mutex; + struct workqueue_struct *wq; + + struct ar5523_tx_cmd tx_cmd; + + struct delayed_work stat_work; + + struct timer_list tx_wd_timer; + struct work_struct tx_wd_work; + struct work_struct tx_work; + struct list_head tx_queue_pending; + struct list_head tx_queue_submitted; + spinlock_t tx_data_list_lock; + wait_queue_head_t tx_flush_waitq; + + /* Queued + Submitted TX frames */ + atomic_t tx_nr_total; + + /* Submitted TX frames */ + atomic_t tx_nr_pending; + + void *rx_cmd_buf; + struct urb *rx_cmd_urb; + + struct ar5523_rx_data rx_data[AR5523_RX_DATA_COUNT]; + spinlock_t rx_data_list_lock; + struct list_head rx_data_free; + struct list_head rx_data_used; + atomic_t rx_data_free_cnt; + + struct work_struct rx_refill_work; + + int rxbufsz; + u8 serial[16]; + + struct ieee80211_channel channels[14]; + struct ieee80211_rate rates[12]; + struct ieee80211_supported_band band; + struct ieee80211_vif *vif; +}; + +/* flags for sending firmware commands */ +#define AR5523_CMD_FLAG_READ (1 << 1) +#define AR5523_CMD_FLAG_MAGIC (1 << 2) + +#define ar5523_dbg(ar, format, arg...) \ + dev_dbg(&(ar)->dev->dev, format, ## arg) + +/* On USB hot-unplug there can be a lot of URBs in flight and they'll all + * fail. Instead of dealing with them in every possible place just surpress + * any messages on USB disconnect. + */ +#define ar5523_err(ar, format, arg...) \ +do { \ + if (!test_bit(AR5523_USB_DISCONNECTED, &ar->flags)) { \ + dev_err(&(ar)->dev->dev, format, ## arg); \ + } \ +} while (0) +#define ar5523_info(ar, format, arg...) \ + dev_info(&(ar)->dev->dev, format, ## arg) diff --git a/drivers/net/wireless/ath/ar5523/ar5523_hw.h b/drivers/net/wireless/ath/ar5523/ar5523_hw.h new file mode 100644 index 00000000000..a0e8bf46031 --- /dev/null +++ b/drivers/net/wireless/ath/ar5523/ar5523_hw.h @@ -0,0 +1,431 @@ +/* + * Copyright (c) 2006 Damien Bergamini + * Copyright (c) 2006 Sam Leffler, Errno Consulting + * Copyright (c) 2007 Christoph Hellwig + * Copyright (c) 2008-2009 Weongyo Jeong + * Copyright (c) 2012 Pontus Fuchs + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* all fields are big endian */ +struct ar5523_fwblock { + __be32 flags; +#define AR5523_WRITE_BLOCK (1 << 4) + + __be32 len; +#define AR5523_MAX_FWBLOCK_SIZE 2048 + + __be32 total; + __be32 remain; + __be32 rxtotal; + __be32 pad[123]; +} __packed; + +#define AR5523_MAX_RXCMDSZ 1024 +#define AR5523_MAX_TXCMDSZ 1024 + +struct ar5523_cmd_hdr { + __be32 len; + __be32 code; +/* NB: these are defined for rev 1.5 firmware; rev 1.6 is different */ +/* messages from Host -> Target */ +#define WDCMSG_HOST_AVAILABLE 0x01 +#define WDCMSG_BIND 0x02 +#define WDCMSG_TARGET_RESET 0x03 +#define WDCMSG_TARGET_GET_CAPABILITY 0x04 +#define WDCMSG_TARGET_SET_CONFIG 0x05 +#define WDCMSG_TARGET_GET_STATUS 0x06 +#define WDCMSG_TARGET_GET_STATS 0x07 +#define WDCMSG_TARGET_START 0x08 +#define WDCMSG_TARGET_STOP 0x09 +#define WDCMSG_TARGET_ENABLE 0x0a +#define WDCMSG_TARGET_DISABLE 0x0b +#define WDCMSG_CREATE_CONNECTION 0x0c +#define WDCMSG_UPDATE_CONNECT_ATTR 0x0d +#define WDCMSG_DELETE_CONNECT 0x0e +#define WDCMSG_SEND 0x0f +#define WDCMSG_FLUSH 0x10 +/* messages from Target -> Host */ +#define WDCMSG_STATS_UPDATE 0x11 +#define WDCMSG_BMISS 0x12 +#define WDCMSG_DEVICE_AVAIL 0x13 +#define WDCMSG_SEND_COMPLETE 0x14 +#define WDCMSG_DATA_AVAIL 0x15 +#define WDCMSG_SET_PWR_MODE 0x16 +#define WDCMSG_BMISS_ACK 0x17 +#define WDCMSG_SET_LED_STEADY 0x18 +#define WDCMSG_SET_LED_BLINK 0x19 +/* more messages */ +#define WDCMSG_SETUP_BEACON_DESC 0x1a +#define WDCMSG_BEACON_INIT 0x1b +#define WDCMSG_RESET_KEY_CACHE 0x1c +#define WDCMSG_RESET_KEY_CACHE_ENTRY 0x1d +#define WDCMSG_SET_KEY_CACHE_ENTRY 0x1e +#define WDCMSG_SET_DECOMP_MASK 0x1f +#define WDCMSG_SET_REGULATORY_DOMAIN 0x20 +#define WDCMSG_SET_LED_STATE 0x21 +#define WDCMSG_WRITE_ASSOCID 0x22 +#define WDCMSG_SET_STA_BEACON_TIMERS 0x23 +#define WDCMSG_GET_TSF 0x24 +#define WDCMSG_RESET_TSF 0x25 +#define WDCMSG_SET_ADHOC_MODE 0x26 +#define WDCMSG_SET_BASIC_RATE 0x27 +#define WDCMSG_MIB_CONTROL 0x28 +#define WDCMSG_GET_CHANNEL_DATA 0x29 +#define WDCMSG_GET_CUR_RSSI 0x2a +#define WDCMSG_SET_ANTENNA_SWITCH 0x2b +#define WDCMSG_USE_SHORT_SLOT_TIME 0x2f +#define WDCMSG_SET_POWER_MODE 0x30 +#define WDCMSG_SETUP_PSPOLL_DESC 0x31 +#define WDCMSG_SET_RX_MULTICAST_FILTER 0x32 +#define WDCMSG_RX_FILTER 0x33 +#define WDCMSG_PER_CALIBRATION 0x34 +#define WDCMSG_RESET 0x35 +#define WDCMSG_DISABLE 0x36 +#define WDCMSG_PHY_DISABLE 0x37 +#define WDCMSG_SET_TX_POWER_LIMIT 0x38 +#define WDCMSG_SET_TX_QUEUE_PARAMS 0x39 +#define WDCMSG_SETUP_TX_QUEUE 0x3a +#define WDCMSG_RELEASE_TX_QUEUE 0x3b +#define WDCMSG_SET_DEFAULT_KEY 0x43 + + __u32 priv; /* driver private data, + don't care about endianess */ + __be32 magic; + __be32 reserved2[4]; +}; + +struct ar5523_cmd_host_available { + __be32 sw_ver_major; + __be32 sw_ver_minor; + __be32 sw_ver_patch; + __be32 sw_ver_build; +} __packed; + +#define ATH_SW_VER_MAJOR 1 +#define ATH_SW_VER_MINOR 5 +#define ATH_SW_VER_PATCH 0 +#define ATH_SW_VER_BUILD 9999 + +struct ar5523_chunk { + u8 seqnum; /* sequence number for ordering */ + u8 flags; +#define UATH_CFLAGS_FINAL 0x01 /* final chunk of a msg */ +#define UATH_CFLAGS_RXMSG 0x02 /* chunk contains rx completion */ +#define UATH_CFLAGS_DEBUG 0x04 /* for debugging */ + __be16 length; /* chunk size in bytes */ + /* chunk data follows */ +} __packed; + +/* + * Message format for a WDCMSG_DATA_AVAIL message from Target to Host. + */ +struct ar5523_rx_desc { + __be32 len; /* msg length including header */ + __be32 code; /* WDCMSG_DATA_AVAIL */ + __be32 gennum; /* generation number */ + __be32 status; /* start of RECEIVE_INFO */ +#define UATH_STATUS_OK 0 +#define UATH_STATUS_STOP_IN_PROGRESS 1 +#define UATH_STATUS_CRC_ERR 2 +#define UATH_STATUS_PHY_ERR 3 +#define UATH_STATUS_DECRYPT_CRC_ERR 4 +#define UATH_STATUS_DECRYPT_MIC_ERR 5 +#define UATH_STATUS_DECOMP_ERR 6 +#define UATH_STATUS_KEY_ERR 7 +#define UATH_STATUS_ERR 8 + __be32 tstamp_low; /* low-order 32-bits of rx timestamp */ + __be32 tstamp_high; /* high-order 32-bits of rx timestamp */ + __be32 framelen; /* frame length */ + __be32 rate; /* rx rate code */ + __be32 antenna; + __be32 rssi; + __be32 channel; + __be32 phyerror; + __be32 connix; /* key table ix for bss traffic */ + __be32 decrypterror; + __be32 keycachemiss; + __be32 pad; /* XXX? */ +} __packed; + +struct ar5523_tx_desc { + __be32 msglen; + __be32 msgid; /* msg id (supplied by host) */ + __be32 type; /* opcode: WDMSG_SEND or WDCMSG_FLUSH */ + __be32 txqid; /* tx queue id and flags */ +#define UATH_TXQID_MASK 0x0f +#define UATH_TXQID_MINRATE 0x10 /* use min tx rate */ +#define UATH_TXQID_FF 0x20 /* content is fast frame */ + __be32 connid; /* tx connection id */ +#define UATH_ID_INVALID 0xffffffff /* for sending prior to connection */ + __be32 flags; /* non-zero if response desired */ +#define UATH_TX_NOTIFY (1 << 24) /* f/w will send a UATH_NOTIF_TX */ + __be32 buflen; /* payload length */ +} __packed; + + +#define AR5523_ID_BSS 2 +#define AR5523_ID_BROADCAST 0xffffffff + +/* structure for command UATH_CMD_WRITE_MAC */ +struct ar5523_write_mac { + __be32 reg; + __be32 len; + u8 data[32]; +} __packed; + +struct ar5523_cmd_rateset { + __u8 length; +#define AR5523_MAX_NRATES 32 + __u8 set[AR5523_MAX_NRATES]; +}; + +struct ar5523_cmd_set_associd { /* AR5523_WRITE_ASSOCID */ + __be32 defaultrateix; + __be32 associd; + __be32 timoffset; + __be32 turboprime; + __u8 bssid[6]; +} __packed; + +/* structure for command WDCMSG_RESET */ +struct ar5523_cmd_reset { + __be32 flags; /* channel flags */ +#define UATH_CHAN_TURBO 0x0100 +#define UATH_CHAN_CCK 0x0200 +#define UATH_CHAN_OFDM 0x0400 +#define UATH_CHAN_2GHZ 0x1000 +#define UATH_CHAN_5GHZ 0x2000 + __be32 freq; /* channel frequency */ + __be32 maxrdpower; + __be32 cfgctl; + __be32 twiceantennareduction; + __be32 channelchange; + __be32 keeprccontent; +} __packed; + +/* structure for command WDCMSG_SET_BASIC_RATE */ +struct ar5523_cmd_rates { + __be32 connid; + __be32 keeprccontent; + __be32 size; + struct ar5523_cmd_rateset rateset; +} __packed; + +enum { + WLAN_MODE_NONE = 0, + WLAN_MODE_11b, + WLAN_MODE_11a, + WLAN_MODE_11g, + WLAN_MODE_11a_TURBO, + WLAN_MODE_11g_TURBO, + WLAN_MODE_11a_TURBO_PRIME, + WLAN_MODE_11g_TURBO_PRIME, + WLAN_MODE_11a_XR, + WLAN_MODE_11g_XR, +}; + +struct ar5523_cmd_connection_attr { + __be32 longpreambleonly; + struct ar5523_cmd_rateset rateset; + __be32 wlanmode; +} __packed; + +/* structure for command AR5523_CREATE_CONNECTION */ +struct ar5523_cmd_create_connection { + __be32 connid; + __be32 bssid; + __be32 size; + struct ar5523_cmd_connection_attr connattr; +} __packed; + +struct ar5523_cmd_ledsteady { /* WDCMSG_SET_LED_STEADY */ + __be32 lednum; +#define UATH_LED_LINK 0 +#define UATH_LED_ACTIVITY 1 + __be32 ledmode; +#define UATH_LED_OFF 0 +#define UATH_LED_ON 1 +} __packed; + +struct ar5523_cmd_ledblink { /* WDCMSG_SET_LED_BLINK */ + __be32 lednum; + __be32 ledmode; + __be32 blinkrate; + __be32 slowmode; +} __packed; + +struct ar5523_cmd_ledstate { /* WDCMSG_SET_LED_STATE */ + __be32 connected; +} __packed; + +struct ar5523_cmd_txq_attr { + __be32 priority; + __be32 aifs; + __be32 logcwmin; + __be32 logcwmax; + __be32 bursttime; + __be32 mode; + __be32 qflags; +} __packed; + +struct ar5523_cmd_txq_setup { /* WDCMSG_SETUP_TX_QUEUE */ + __be32 qid; + __be32 len; + struct ar5523_cmd_txq_attr attr; +} __packed; + +struct ar5523_cmd_rx_filter { /* WDCMSG_RX_FILTER */ + __be32 bits; +#define UATH_FILTER_RX_UCAST 0x00000001 +#define UATH_FILTER_RX_MCAST 0x00000002 +#define UATH_FILTER_RX_BCAST 0x00000004 +#define UATH_FILTER_RX_CONTROL 0x00000008 +#define UATH_FILTER_RX_BEACON 0x00000010 /* beacon frames */ +#define UATH_FILTER_RX_PROM 0x00000020 /* promiscuous mode */ +#define UATH_FILTER_RX_PHY_ERR 0x00000040 /* phy errors */ +#define UATH_FILTER_RX_PHY_RADAR 0x00000080 /* radar phy errors */ +#define UATH_FILTER_RX_XR_POOL 0x00000400 /* XR group polls */ +#define UATH_FILTER_RX_PROBE_REQ 0x00000800 + __be32 op; +#define UATH_FILTER_OP_INIT 0x0 +#define UATH_FILTER_OP_SET 0x1 +#define UATH_FILTER_OP_CLEAR 0x2 +#define UATH_FILTER_OP_TEMP 0x3 +#define UATH_FILTER_OP_RESTORE 0x4 +} __packed; + +enum { + CFG_NONE, /* Sentinal to indicate "no config" */ + CFG_REG_DOMAIN, /* Regulatory Domain */ + CFG_RATE_CONTROL_ENABLE, + CFG_DEF_XMIT_DATA_RATE, /* NB: if rate control is not enabled */ + CFG_HW_TX_RETRIES, + CFG_SW_TX_RETRIES, + CFG_SLOW_CLOCK_ENABLE, + CFG_COMP_PROC, + CFG_USER_RTS_THRESHOLD, + CFG_XR2NORM_RATE_THRESHOLD, + CFG_XRMODE_SWITCH_COUNT, + CFG_PROTECTION_TYPE, + CFG_BURST_SEQ_THRESHOLD, + CFG_ABOLT, + CFG_IQ_LOG_COUNT_MAX, + CFG_MODE_CTS, + CFG_WME_ENABLED, + CFG_GPRS_CBR_PERIOD, + CFG_SERVICE_TYPE, + /* MAC Address to use. Overrides EEPROM */ + CFG_MAC_ADDR, + CFG_DEBUG_EAR, + CFG_INIT_REGS, + /* An ID for use in error & debug messages */ + CFG_DEBUG_ID, + CFG_COMP_WIN_SZ, + CFG_DIVERSITY_CTL, + CFG_TP_SCALE, + CFG_TPC_HALF_DBM5, + CFG_TPC_HALF_DBM2, + CFG_OVERRD_TX_POWER, + CFG_USE_32KHZ_CLOCK, + CFG_GMODE_PROTECTION, + CFG_GMODE_PROTECT_RATE_INDEX, + CFG_GMODE_NON_ERP_PREAMBLE, + CFG_WDC_TRANSPORT_CHUNK_SIZE, +}; + +enum { + /* Sentinal to indicate "no capability" */ + CAP_NONE, + CAP_ALL, /* ALL capabilities */ + CAP_TARGET_VERSION, + CAP_TARGET_REVISION, + CAP_MAC_VERSION, + CAP_MAC_REVISION, + CAP_PHY_REVISION, + CAP_ANALOG_5GHz_REVISION, + CAP_ANALOG_2GHz_REVISION, + /* Target supports WDC message debug features */ + CAP_DEBUG_WDCMSG_SUPPORT, + + CAP_REG_DOMAIN, + CAP_COUNTRY_CODE, + CAP_REG_CAP_BITS, + + CAP_WIRELESS_MODES, + CAP_CHAN_SPREAD_SUPPORT, + CAP_SLEEP_AFTER_BEACON_BROKEN, + CAP_COMPRESS_SUPPORT, + CAP_BURST_SUPPORT, + CAP_FAST_FRAMES_SUPPORT, + CAP_CHAP_TUNING_SUPPORT, + CAP_TURBOG_SUPPORT, + CAP_TURBO_PRIME_SUPPORT, + CAP_DEVICE_TYPE, + CAP_XR_SUPPORT, + CAP_WME_SUPPORT, + CAP_TOTAL_QUEUES, + CAP_CONNECTION_ID_MAX, /* Should absorb CAP_KEY_CACHE_SIZE */ + + CAP_LOW_5GHZ_CHAN, + CAP_HIGH_5GHZ_CHAN, + CAP_LOW_2GHZ_CHAN, + CAP_HIGH_2GHZ_CHAN, + + CAP_MIC_AES_CCM, + CAP_MIC_CKIP, + CAP_MIC_TKIP, + CAP_MIC_TKIP_WME, + CAP_CIPHER_AES_CCM, + CAP_CIPHER_CKIP, + CAP_CIPHER_TKIP, + + CAP_TWICE_ANTENNAGAIN_5G, + CAP_TWICE_ANTENNAGAIN_2G, +}; + +enum { + ST_NONE, /* Sentinal to indicate "no status" */ + ST_ALL, + ST_SERVICE_TYPE, + ST_WLAN_MODE, + ST_FREQ, + ST_BAND, + ST_LAST_RSSI, + ST_PS_FRAMES_DROPPED, + ST_CACHED_DEF_ANT, + ST_COUNT_OTHER_RX_ANT, + ST_USE_FAST_DIVERSITY, + ST_MAC_ADDR, + ST_RX_GENERATION_NUM, + ST_TX_QUEUE_DEPTH, + ST_SERIAL_NUMBER, + ST_WDC_TRANSPORT_CHUNK_SIZE, +}; + +enum { + TARGET_DEVICE_AWAKE, + TARGET_DEVICE_SLEEP, + TARGET_DEVICE_PWRDN, + TARGET_DEVICE_PWRSAVE, + TARGET_DEVICE_SUSPEND, + TARGET_DEVICE_RESUME, +}; + +/* this is in net/ieee80211.h, but that conflicts with the mac80211 headers */ +#define IEEE80211_2ADDR_LEN 16 + +#define AR5523_MIN_RXBUFSZ \ + (((sizeof(__be32) + IEEE80211_2ADDR_LEN + \ + sizeof(struct ar5523_rx_desc)) + 3) & ~3) -- cgit v1.2.3-18-g5258 From 1680260226a8fd2aab590319da83ad8e610da9bd Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Thu, 25 Oct 2012 17:11:31 +0530 Subject: ath9k_hw: Enable hw PLL power save for AR9462 This reduced the power consumption to half in full and network sleep. Cc: stable@vger.kernel.org Cc: Paul Stewart Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_hw.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c index 1a36fa26263..0a6b7a3385d 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c @@ -219,10 +219,10 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) /* Awake -> Sleep Setting */ INIT_INI_ARRAY(&ah->iniPcieSerdes, - ar9462_pciephy_pll_on_clkreq_disable_L1_2p0); + ar9462_pciephy_clkreq_disable_L1_2p0); /* Sleep -> Awake Setting */ INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower, - ar9462_pciephy_pll_on_clkreq_disable_L1_2p0); + ar9462_pciephy_clkreq_disable_L1_2p0); /* Fast clock modal settings */ INIT_INI_ARRAY(&ah->iniModesFastClock, -- cgit v1.2.3-18-g5258 From 844648423dcf33fed96a4eb65f783f867efbe267 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Thu, 25 Oct 2012 17:16:51 +0530 Subject: ath9k_hw: Enable hw PLL power save for AR9565 This reduced the power consumption to half in full and network sleep. Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_hw.c | 4 ++-- drivers/net/wireless/ath/ath9k/ar9565_1p0_initvals.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c index 0a6b7a3385d..0693cd95b74 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c @@ -328,9 +328,9 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) ar9565_1p0_Modes_lowest_ob_db_tx_gain_table); INIT_INI_ARRAY(&ah->iniPcieSerdes, - ar9565_1p0_pciephy_pll_on_clkreq_disable_L1); + ar9565_1p0_pciephy_clkreq_disable_L1); INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower, - ar9565_1p0_pciephy_pll_on_clkreq_disable_L1); + ar9565_1p0_pciephy_clkreq_disable_L1); INIT_INI_ARRAY(&ah->iniModesFastClock, ar9565_1p0_modes_fast_clock); diff --git a/drivers/net/wireless/ath/ath9k/ar9565_1p0_initvals.h b/drivers/net/wireless/ath/ath9k/ar9565_1p0_initvals.h index 843e79f67ff..0c2ac0c6dc8 100644 --- a/drivers/net/wireless/ath/ath9k/ar9565_1p0_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9565_1p0_initvals.h @@ -768,9 +768,9 @@ static const u32 ar9565_1p0_Modes_lowest_ob_db_tx_gain_table[][5] = { {0x00016054, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, }; -static const u32 ar9565_1p0_pciephy_pll_on_clkreq_disable_L1[][2] = { +static const u32 ar9565_1p0_pciephy_clkreq_disable_L1[][2] = { /* Addr allmodes */ - {0x00018c00, 0x18212ede}, + {0x00018c00, 0x18213ede}, {0x00018c04, 0x000801d8}, {0x00018c08, 0x0003780c}, }; -- cgit v1.2.3-18-g5258 From e75d4ed6a9565fcccd579316b0fd933d2191f513 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Thu, 25 Oct 2012 17:16:52 +0530 Subject: ath9k_hw: Fix concurrent tx on lower tx power Whenever WLAN receives scheduling msg from BT, it reduces tx power based on RSSI level. And then BT starts simultaneous transmission along with WLAN. Sometimes HW MAC compares tx power that is used prior to power reduction which is causing BT transmission to defer. Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_mci.c | 5 ++++- drivers/net/wireless/ath/ath9k/reg.h | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mci.c b/drivers/net/wireless/ath/ath9k/ar9003_mci.c index b04fa462282..42b4412d679 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mci.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_mci.c @@ -881,9 +881,12 @@ int ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g, REG_RMW_FIELD(ah, AR_BTCOEX_CTRL3, AR_BTCOEX_CTRL3_CONT_INFO_TIMEOUT, 20); - REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, AR_BTCOEX_CTRL2_RX_DEWEIGHT, 1); + REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, AR_BTCOEX_CTRL2_RX_DEWEIGHT, 0); REG_RMW_FIELD(ah, AR_PCU_MISC, AR_PCU_BT_ANT_PREVENT_RX, 0); + /* Set the time out to 3.125ms (5 BT slots) */ + REG_RMW_FIELD(ah, AR_BTCOEX_WL_LNA, AR_BTCOEX_WL_LNA_TIMEOUT, 0x3D090); + /* concurrent tx priority */ if (mci->config & ATH_MCI_CONFIG_CONCUR_TX) { REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index e9dec138b91..ad3c82c0917 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -2311,6 +2311,8 @@ enum { #define AR_BTCOEX_MAX_TXPWR(_x) (0x18c0 + ((_x) << 2)) #define AR_BTCOEX_WL_LNA 0x1940 #define AR_BTCOEX_RFGAIN_CTRL 0x1944 +#define AR_BTCOEX_WL_LNA_TIMEOUT 0x003FFFFF +#define AR_BTCOEX_WL_LNA_TIMEOUT_S 0 #define AR_BTCOEX_CTRL2 0x1948 #define AR_BTCOEX_CTRL2_TXPWR_THRESH 0x0007F800 -- cgit v1.2.3-18-g5258 From cdbe408da76d5cc294edb013850cc3a972d80968 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Thu, 25 Oct 2012 17:16:53 +0530 Subject: ath9k_hw: validate MCI stuck after RTC wakeup Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 8e1559aba49..71cd9f0c96a 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -2153,9 +2153,6 @@ static bool ath9k_hw_set_power_awake(struct ath_hw *ah) AR_RTC_FORCE_WAKE_EN); udelay(50); - if (ath9k_hw_mci_is_enabled(ah)) - ar9003_mci_set_power_awake(ah); - for (i = POWER_UP_TIME / 50; i > 0; i--) { val = REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M; if (val == AR_RTC_STATUS_ON) @@ -2171,6 +2168,9 @@ static bool ath9k_hw_set_power_awake(struct ath_hw *ah) return false; } + if (ath9k_hw_mci_is_enabled(ah)) + ar9003_mci_set_power_awake(ah); + REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); return true; -- cgit v1.2.3-18-g5258 From 4df50ca869890581020b95958251bd355c1dc6b1 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Thu, 25 Oct 2012 17:16:54 +0530 Subject: ath9k: Dump BTCOEX tuning parameters Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 6 +++++ drivers/net/wireless/ath/ath9k/debug.c | 34 +++++++++++++++++++++++- drivers/net/wireless/ath/ath9k/gpio.c | 48 ++++++++++++++++++++++++++++++++++ 3 files changed, 87 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 18dfb764eed..4e125d8904a 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -494,6 +494,7 @@ void ath9k_btcoex_timer_pause(struct ath_softc *sc); void ath9k_btcoex_handle_interrupt(struct ath_softc *sc, u32 status); u16 ath9k_btcoex_aggr_limit(struct ath_softc *sc, u32 max_4ms_framelen); void ath9k_btcoex_stop_gen_timer(struct ath_softc *sc); +int ath9k_dump_btcoex(struct ath_softc *sc, u8 *buf, u32 len, u32 size); #else static inline int ath9k_init_btcoex(struct ath_softc *sc) { @@ -520,6 +521,11 @@ static inline u16 ath9k_btcoex_aggr_limit(struct ath_softc *sc, static inline void ath9k_btcoex_stop_gen_timer(struct ath_softc *sc) { } +static inline int ath9k_dump_btcoex(struct ath_softc *sc, u8 *buf, + u32 len, u32 size) +{ + return 0; +} #endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */ struct ath9k_wow_pattern { diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 6727b566d29..a8be94b2a53 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -1586,6 +1586,35 @@ static const struct file_operations fops_samps = { #endif +#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT +static ssize_t read_file_btcoex(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + u32 len = 0, size = 1500; + char *buf; + size_t retval; + + buf = kzalloc(size, GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + + len = ath9k_dump_btcoex(sc, buf, len, size); + + retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); + kfree(buf); + + return retval; +} + +static const struct file_operations fops_btcoex = { + .read = read_file_btcoex, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; +#endif + int ath9k_init_debug(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); @@ -1658,6 +1687,9 @@ int ath9k_init_debug(struct ath_hw *ah) sc->debug.debugfs_phy, &sc->sc_ah->gpio_val); debugfs_create_file("diversity", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, sc, &fops_ant_diversity); - +#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT + debugfs_create_file("btcoex", S_IRUSR, sc->debug.debugfs_phy, sc, + &fops_btcoex); +#endif return 0; } diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c index 64dde1cd20e..a8ea57b9f49 100644 --- a/drivers/net/wireless/ath/ath9k/gpio.c +++ b/drivers/net/wireless/ath/ath9k/gpio.c @@ -494,4 +494,52 @@ int ath9k_init_btcoex(struct ath_softc *sc) return 0; } +int ath9k_dump_btcoex(struct ath_softc *sc, u8 *buf, u32 len, u32 size) +{ +#define ATH_DUMP_BTCOEX(_s, _val) \ + do { \ + len += snprintf(buf + len, size - len, \ + "%20s : %10d\n", _s, (_val)); \ + } while (0) + + struct ath_btcoex *btcoex = &sc->btcoex; + struct ath_mci_profile *mci = &btcoex->mci; + struct ath_hw *ah = sc->sc_ah; + struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw; + int i; + + ATH_DUMP_BTCOEX("Total BT profiles", NUM_PROF(mci)); + ATH_DUMP_BTCOEX("Number of MGMT", mci->num_mgmt); + ATH_DUMP_BTCOEX("Number of SCO", mci->num_sco); + ATH_DUMP_BTCOEX("Number of A2DP", mci->num_a2dp); + ATH_DUMP_BTCOEX("Number of HID", mci->num_hid); + ATH_DUMP_BTCOEX("Number of PAN", mci->num_pan); + ATH_DUMP_BTCOEX("Number of ACL", mci->num_other_acl); + ATH_DUMP_BTCOEX("Number of BDR", mci->num_bdr); + ATH_DUMP_BTCOEX("Aggr. Limit", mci->aggr_limit); + ATH_DUMP_BTCOEX("Stomp Type", btcoex->bt_stomp_type); + ATH_DUMP_BTCOEX("BTCoex Period (msec)", btcoex->btcoex_period); + ATH_DUMP_BTCOEX("Duty Cycle", btcoex->duty_cycle); + ATH_DUMP_BTCOEX("BT Wait time", btcoex->bt_wait_time); + ATH_DUMP_BTCOEX("Concurrent Tx", btcoex_hw->mci.concur_tx); + ATH_DUMP_BTCOEX("Concur RSSI count", btcoex->rssi_count); + len += snprintf(buf + len, size - len, "BT Weights: "); + for (i = 0; i < AR9300_NUM_BT_WEIGHTS; i++) + len += snprintf(buf + len, size - len, "%08x ", + btcoex_hw->bt_weight[i]); + len += snprintf(buf + len, size - len, "\n"); + len += snprintf(buf + len, size - len, "WLAN Weights: "); + for (i = 0; i < AR9300_NUM_BT_WEIGHTS; i++) + len += snprintf(buf + len, size - len, "%08x ", + btcoex_hw->wlan_weight[i]); + len += snprintf(buf + len, size - len, "\n"); + len += snprintf(buf + len, size - len, "Tx Priorities: "); + for (i = 0; i < ATH_BTCOEX_STOMP_MAX; i++) + len += snprintf(buf + len, size - len, "%08x ", + btcoex_hw->tx_prio[i]); + len += snprintf(buf + len, size - len, "\n"); +#undef ATH_DUMP_BTCOEX + + return len; +} #endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */ -- cgit v1.2.3-18-g5258 From c8442118ad9cd05cfe3b993f058e70ab25b1009a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 24 Oct 2012 10:17:18 +0200 Subject: cfg80211: allow per interface TX power setting The TX power setting is currently per wiphy (hardware device) but with multi-channel capabilities that doesn't make much sense any more. Allow drivers (and mac80211) to advertise support for per-interface TX power configuration. When the TX power is configured for the wiphy, the wdev will be NULL and the driver can still handle that, but when a wdev is given the TX power can be set only for that wdev now. Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/ath6kl/cfg80211.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index 277089963eb..d615f9f7506 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -1384,11 +1384,8 @@ static int ath6kl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) return 0; } -/* - * The type nl80211_tx_power_setting replaces the following - * data type from 2.6.36 onwards -*/ static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy, + struct wireless_dev *wdev, enum nl80211_tx_power_setting type, int mbm) { @@ -1423,7 +1420,9 @@ static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy, return 0; } -static int ath6kl_cfg80211_get_txpower(struct wiphy *wiphy, int *dbm) +static int ath6kl_cfg80211_get_txpower(struct wiphy *wiphy, + struct wireless_dev *wdev, + int *dbm) { struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy); struct ath6kl_vif *vif; -- cgit v1.2.3-18-g5258 From 38141fcfaad34a388e61a7a7e98d521330e049d6 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 30 Oct 2012 21:04:26 +0300 Subject: ar5523: make buffer size variable unsigned A negative buffer size doesn't make sense and it breaks this check in ar5523_get_max_rxsz(): if (!ar->rxbufsz || ar->rxbufsz > AR5523_SANE_RXBUFSZ) { ... Signed-off-by: Dan Carpenter Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ar5523/ar5523.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ar5523/ar5523.h b/drivers/net/wireless/ath/ar5523/ar5523.h index 6086ba3fb54..00c6fd346d4 100644 --- a/drivers/net/wireless/ath/ar5523/ar5523.h +++ b/drivers/net/wireless/ath/ar5523/ar5523.h @@ -122,7 +122,7 @@ struct ar5523 { struct work_struct rx_refill_work; - int rxbufsz; + unsigned int rxbufsz; u8 serial[16]; struct ieee80211_channel channels[14]; -- cgit v1.2.3-18-g5258 From 8b2c98243e8d00f9c6b6059976d6de51491ee0c7 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 6 Nov 2012 20:23:30 +0100 Subject: mac80211: clarify interface iteration and make it configurable During hardware restart, all interfaces are iterated even though they haven't been re-added to the driver, document this behaviour. The same also happens during resume, which is even more confusing since all of the interfaces were previously removed from the driver. Make this optional so drivers relying on the current behaviour can still use it, but to let drivers that don't want this behaviour disable it. Also convert all API users, keeping the old semantics except in hwsim, where the new normal ones are desired. Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/ath5k/base.c | 10 ++++++---- drivers/net/wireless/ath/ath5k/mac80211-ops.c | 5 +++-- drivers/net/wireless/ath/ath9k/htc_drv_beacon.c | 6 +++--- drivers/net/wireless/ath/ath9k/htc_drv_main.c | 20 ++++++++++++-------- drivers/net/wireless/ath/ath9k/main.c | 15 +++++++++------ 5 files changed, 33 insertions(+), 23 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 9f31cfa56cc..cdd19232960 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -511,8 +511,9 @@ ath5k_update_bssid_mask_and_opmode(struct ath5k_hw *ah, ath5k_vif_iter(&iter_data, vif->addr, vif); /* Get list of all active MAC addresses */ - ieee80211_iterate_active_interfaces_atomic(ah->hw, ath5k_vif_iter, - &iter_data); + ieee80211_iterate_active_interfaces_atomic( + ah->hw, IEEE80211_IFACE_ITER_RESUME_ALL, + ath5k_vif_iter, &iter_data); memcpy(ah->bssidmask, iter_data.mask, ETH_ALEN); ah->opmode = iter_data.opmode; @@ -3045,8 +3046,9 @@ ath5k_any_vif_assoc(struct ath5k_hw *ah) iter_data.need_set_hw_addr = false; iter_data.found_active = true; - ieee80211_iterate_active_interfaces_atomic(ah->hw, ath5k_vif_iter, - &iter_data); + ieee80211_iterate_active_interfaces_atomic( + ah->hw, IEEE80211_IFACE_ITER_RESUME_ALL, + ath5k_vif_iter, &iter_data); return iter_data.any_assoc; } diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c index 7a28538e6e0..1ea8c8795c8 100644 --- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c +++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c @@ -452,8 +452,9 @@ ath5k_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, iter_data.hw_macaddr = NULL; iter_data.n_stas = 0; iter_data.need_set_hw_addr = false; - ieee80211_iterate_active_interfaces_atomic(ah->hw, ath5k_vif_iter, - &iter_data); + ieee80211_iterate_active_interfaces_atomic( + ah->hw, IEEE80211_IFACE_ITER_RESUME_ALL, + ath5k_vif_iter, &iter_data); /* Set up RX Filter */ if (iter_data.n_stas > 1) { diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c index f42d2eb6af9..1318d79f5c4 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c @@ -587,9 +587,9 @@ static bool ath9k_htc_check_beacon_config(struct ath9k_htc_priv *priv, (priv->num_sta_vif > 1) && (vif->type == NL80211_IFTYPE_STATION)) { beacon_configured = false; - ieee80211_iterate_active_interfaces_atomic(priv->hw, - ath9k_htc_beacon_iter, - &beacon_configured); + ieee80211_iterate_active_interfaces_atomic( + priv->hw, IEEE80211_IFACE_ITER_RESUME_ALL, + ath9k_htc_beacon_iter, &beacon_configured); if (beacon_configured) { ath_dbg(common, CONFIG, diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index 66f6a74c508..02cce95331d 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -127,8 +127,9 @@ static void ath9k_htc_vif_reconfig(struct ath9k_htc_priv *priv) priv->rearm_ani = false; priv->reconfig_beacon = false; - ieee80211_iterate_active_interfaces_atomic(priv->hw, - ath9k_htc_vif_iter, priv); + ieee80211_iterate_active_interfaces_atomic( + priv->hw, IEEE80211_IFACE_ITER_RESUME_ALL, + ath9k_htc_vif_iter, priv); if (priv->rearm_ani) ath9k_htc_start_ani(priv); @@ -165,8 +166,9 @@ static void ath9k_htc_set_bssid_mask(struct ath9k_htc_priv *priv, ath9k_htc_bssid_iter(&iter_data, vif->addr, vif); /* Get list of all active MAC addresses */ - ieee80211_iterate_active_interfaces_atomic(priv->hw, ath9k_htc_bssid_iter, - &iter_data); + ieee80211_iterate_active_interfaces_atomic( + priv->hw, IEEE80211_IFACE_ITER_RESUME_ALL, + ath9k_htc_bssid_iter, &iter_data); memcpy(common->bssidmask, iter_data.mask, ETH_ALEN); ath_hw_setbssidmask(common); @@ -1144,8 +1146,9 @@ static void ath9k_htc_remove_interface(struct ieee80211_hw *hw, */ if ((vif->type == NL80211_IFTYPE_AP) && (priv->num_ap_vif == 0)) { priv->rearm_ani = false; - ieee80211_iterate_active_interfaces_atomic(priv->hw, - ath9k_htc_vif_iter, priv); + ieee80211_iterate_active_interfaces_atomic( + priv->hw, IEEE80211_IFACE_ITER_RESUME_ALL, + ath9k_htc_vif_iter, priv); if (!priv->rearm_ani) ath9k_htc_stop_ani(priv); } @@ -1466,8 +1469,9 @@ static void ath9k_htc_bss_iter(void *data, u8 *mac, struct ieee80211_vif *vif) static void ath9k_htc_choose_set_bssid(struct ath9k_htc_priv *priv) { if (priv->num_sta_assoc_vif == 1) { - ieee80211_iterate_active_interfaces_atomic(priv->hw, - ath9k_htc_bss_iter, priv); + ieee80211_iterate_active_interfaces_atomic( + priv->hw, IEEE80211_IFACE_ITER_RESUME_ALL, + ath9k_htc_bss_iter, priv); ath9k_htc_set_bssid(priv); } } diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 578a7234aa5..c084532291a 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -924,8 +924,9 @@ void ath9k_calculate_iter_data(struct ieee80211_hw *hw, ath9k_vif_iter(iter_data, vif->addr, vif); /* Get list of all active MAC addresses */ - ieee80211_iterate_active_interfaces_atomic(sc->hw, ath9k_vif_iter, - iter_data); + ieee80211_iterate_active_interfaces_atomic( + sc->hw, IEEE80211_IFACE_ITER_RESUME_ALL, + ath9k_vif_iter, iter_data); } /* Called with sc->mutex held. */ @@ -975,8 +976,9 @@ static void ath9k_calculate_summary_state(struct ieee80211_hw *hw, if (ah->opmode == NL80211_IFTYPE_STATION && old_opmode == NL80211_IFTYPE_AP && test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) { - ieee80211_iterate_active_interfaces_atomic(sc->hw, - ath9k_sta_vif_iter, sc); + ieee80211_iterate_active_interfaces_atomic( + sc->hw, IEEE80211_IFACE_ITER_RESUME_ALL, + ath9k_sta_vif_iter, sc); } } @@ -1505,8 +1507,9 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, clear_bit(SC_OP_BEACONS, &sc->sc_flags); } - ieee80211_iterate_active_interfaces_atomic(sc->hw, - ath9k_bss_assoc_iter, sc); + ieee80211_iterate_active_interfaces_atomic( + sc->hw, IEEE80211_IFACE_ITER_RESUME_ALL, + ath9k_bss_assoc_iter, sc); if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags) && ah->opmode == NL80211_IFTYPE_STATION) { -- cgit v1.2.3-18-g5258 From f4bda337bbb6e245e2a07f344990adeb6a70ff35 Mon Sep 17 00:00:00 2001 From: Thomas Pedersen Date: Tue, 13 Nov 2012 10:46:27 -0800 Subject: mac80211: support RX_FLAG_MACTIME_END Allow drivers to indicate their mactime is at RX completion and adjust for this in mac80211. Also rename the existing RX_FLAG_MACTIME_MPDU to RX_FLAG_MACTIME_START to clarify its intent. Based on similar code by Johannes Berg. Signed-off-by: Thomas Pedersen [fix docs, atheros drivers] Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/ath5k/base.c | 2 +- drivers/net/wireless/ath/ath9k/htc_drv_txrx.c | 2 +- drivers/net/wireless/ath/ath9k/recv.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index cdd19232960..2fd5bab2e22 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -1349,7 +1349,7 @@ ath5k_receive_frame(struct ath5k_hw *ah, struct sk_buff *skb, * right now, so it's not too bad... */ rxs->mactime = ath5k_extend_tsf(ah, rs->rs_tstamp); - rxs->flag |= RX_FLAG_MACTIME_MPDU; + rxs->flag |= RX_FLAG_MACTIME_START; rxs->freq = ah->curchan->center_freq; rxs->band = ah->curchan->band; diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c index 06cdcb772d7..e4ec9833298 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c @@ -1082,7 +1082,7 @@ static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv, rx_status->freq = hw->conf.channel->center_freq; rx_status->signal = rxbuf->rxstatus.rs_rssi + ATH_DEFAULT_NOISE_FLOOR; rx_status->antenna = rxbuf->rxstatus.rs_antenna; - rx_status->flag |= RX_FLAG_MACTIME_MPDU; + rx_status->flag |= RX_FLAG_MACTIME_START; return true; diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index a04028bce28..6aafbb77c49 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -976,7 +976,7 @@ static int ath9k_rx_skb_preprocess(struct ath_common *common, rx_status->freq = hw->conf.channel->center_freq; rx_status->signal = ah->noise + rx_stats->rs_rssi; rx_status->antenna = rx_stats->rs_antenna; - rx_status->flag |= RX_FLAG_MACTIME_MPDU; + rx_status->flag |= RX_FLAG_MACTIME_START; if (rx_stats->rs_moreaggr) rx_status->flag |= RX_FLAG_NO_SIGNAL_VAL; -- cgit v1.2.3-18-g5258 From 259bcf87fb51fb80185cf54fac7f00da56a80ac4 Mon Sep 17 00:00:00 2001 From: Zefir Kurtisi Date: Wed, 31 Oct 2012 12:21:56 +0100 Subject: ath9k: resolve name collision in DFS detector set_domain() is already defined in /arch/arm/asm/domain.h Signed-off-by: Zefir Kurtisi Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/dfs_pattern_detector.c | 4 ++-- drivers/net/wireless/ath/ath9k/dfs_pattern_detector.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/dfs_pattern_detector.c b/drivers/net/wireless/ath/ath9k/dfs_pattern_detector.c index ea2a6cf7ef2..f66da35d57a 100644 --- a/drivers/net/wireless/ath/ath9k/dfs_pattern_detector.c +++ b/drivers/net/wireless/ath/ath9k/dfs_pattern_detector.c @@ -274,7 +274,7 @@ static bool dpd_set_domain(struct dfs_pattern_detector *dpd, static struct dfs_pattern_detector default_dpd = { .exit = dpd_exit, - .set_domain = dpd_set_domain, + .set_dfs_domain = dpd_set_domain, .add_pulse = dpd_add_pulse, .region = NL80211_DFS_UNSET, }; @@ -291,7 +291,7 @@ dfs_pattern_detector_init(enum nl80211_dfs_regions region) *dpd = default_dpd; INIT_LIST_HEAD(&dpd->channel_detectors); - if (dpd->set_domain(dpd, region)) + if (dpd->set_dfs_domain(dpd, region)) return dpd; pr_err("Could not set DFS domain to %d. ", region); diff --git a/drivers/net/wireless/ath/ath9k/dfs_pattern_detector.h b/drivers/net/wireless/ath/ath9k/dfs_pattern_detector.h index fd0328a3099..cda52f39f28 100644 --- a/drivers/net/wireless/ath/ath9k/dfs_pattern_detector.h +++ b/drivers/net/wireless/ath/ath9k/dfs_pattern_detector.h @@ -62,7 +62,7 @@ struct radar_detector_specs { /** * struct dfs_pattern_detector - DFS pattern detector * @exit(): destructor - * @set_domain(): set DFS domain, resets detector lines upon domain changes + * @set_dfs_domain(): set DFS domain, resets detector lines upon domain changes * @add_pulse(): add radar pulse to detector, returns true on detection * @region: active DFS region, NL80211_DFS_UNSET until set * @num_radar_types: number of different radar types @@ -72,7 +72,7 @@ struct radar_detector_specs { */ struct dfs_pattern_detector { void (*exit)(struct dfs_pattern_detector *dpd); - bool (*set_domain)(struct dfs_pattern_detector *dpd, + bool (*set_dfs_domain)(struct dfs_pattern_detector *dpd, enum nl80211_dfs_regions region); bool (*add_pulse)(struct dfs_pattern_detector *dpd, struct pulse_event *pe); -- cgit v1.2.3-18-g5258 From 70bf870b54b96887d388286e7d8865406f1aa670 Mon Sep 17 00:00:00 2001 From: Zefir Kurtisi Date: Wed, 31 Oct 2012 12:22:34 +0100 Subject: ath9k: fix memory leak in DFS pattern detector Free instance of pattern detector if requested DFS domain is not supported. Signed-off-by: Zefir Kurtisi Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/dfs_pattern_detector.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/dfs_pattern_detector.c b/drivers/net/wireless/ath/ath9k/dfs_pattern_detector.c index f66da35d57a..3b129143653 100644 --- a/drivers/net/wireless/ath/ath9k/dfs_pattern_detector.c +++ b/drivers/net/wireless/ath/ath9k/dfs_pattern_detector.c @@ -295,6 +295,7 @@ dfs_pattern_detector_init(enum nl80211_dfs_regions region) return dpd; pr_err("Could not set DFS domain to %d. ", region); + kfree(dpd); return NULL; } EXPORT_SYMBOL(dfs_pattern_detector_init); -- cgit v1.2.3-18-g5258 From 158b42edabe82b6adfcd3310d116cc41fdc669ea Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 31 Oct 2012 11:52:51 -0700 Subject: carl9170: kill MODULE_VERSION This is pretty pointless. Lets kill this to stop people from thinking that its actually used. Maybe we should go on a crusade and kill this completely from the kernel. Cc: Vladimir Kondratiev Acked-by: Christian Lamparter Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/carl9170/fw.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/carl9170/fw.c b/drivers/net/wireless/ath/carl9170/fw.c index 24ac2876a73..aaebecd19e5 100644 --- a/drivers/net/wireless/ath/carl9170/fw.c +++ b/drivers/net/wireless/ath/carl9170/fw.c @@ -28,11 +28,6 @@ #include "fwcmd.h" #include "version.h" -#define MAKE_STR(symbol) #symbol -#define TO_STR(symbol) MAKE_STR(symbol) -#define CARL9170FW_API_VER_STR TO_STR(CARL9170FW_API_MAX_VER) -MODULE_VERSION(CARL9170FW_API_VER_STR ":" CARL9170FW_VERSION_GIT); - static const u8 otus_magic[4] = { OTUS_MAGIC }; static const void *carl9170_fw_find_desc(struct ar9170 *ar, const u8 descid[4], -- cgit v1.2.3-18-g5258 From f0a5fd4e7c08554335e2938dccd32c9b9edee345 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Thu, 1 Nov 2012 09:59:13 +0800 Subject: ar5523: use module_usb_driver to simplify the code Use the module_usb_driver() macro to make the code simpler by eliminating module_init and module_exit calls. dpatch engine is used to auto generate this patch. (https://github.com/weiyj/dpatch) Signed-off-by: Wei Yongjun Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ar5523/ar5523.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ar5523/ar5523.c b/drivers/net/wireless/ath/ar5523/ar5523.c index f782b6e502b..402e6d378b2 100644 --- a/drivers/net/wireless/ath/ar5523/ar5523.c +++ b/drivers/net/wireless/ath/ar5523/ar5523.c @@ -1789,18 +1789,7 @@ static struct usb_driver ar5523_driver = { .disconnect = ar5523_disconnect, }; -static int __init ar5523_init(void) -{ - return usb_register(&ar5523_driver); -} - -static void __exit ar5523_exit(void) -{ - usb_deregister(&ar5523_driver); -} +module_usb_driver(ar5523_driver); MODULE_LICENSE("Dual BSD/GPL"); MODULE_FIRMWARE(AR5523_FIRMWARE_FILE); - -module_init(ar5523_init); -module_exit(ar5523_exit); -- cgit v1.2.3-18-g5258 From f3ec3bf527638b8efb576d1bdbaf8d66d1183f92 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 3 Nov 2012 21:30:25 +0100 Subject: drivers/net/wireless/ath/ath6kl/hif.c: drop if around WARN_ON Just use WARN_ON rather than an if containing only WARN_ON(1). A simplified version of the semantic patch that makes this transformation is as follows: (http://coccinelle.lip6.fr/) // @@ expression e; @@ - if (e) WARN_ON(1); + WARN_ON(e); // Signed-off-by: Julia Lawall Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath6kl/hif.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath6kl/hif.c b/drivers/net/wireless/ath/ath6kl/hif.c index 68ed6c2665b..9e47c4a138a 100644 --- a/drivers/net/wireless/ath/ath6kl/hif.c +++ b/drivers/net/wireless/ath/ath6kl/hif.c @@ -338,8 +338,7 @@ static int ath6kl_hif_proc_err_intr(struct ath6kl_device *dev) status = hif_read_write_sync(dev->ar, ERROR_INT_STATUS_ADDRESS, reg_buf, 4, HIF_WR_SYNC_BYTE_FIX); - if (status) - WARN_ON(1); + WARN_ON(status); return status; } @@ -383,8 +382,7 @@ static int ath6kl_hif_proc_cpu_intr(struct ath6kl_device *dev) status = hif_read_write_sync(dev->ar, CPU_INT_STATUS_ADDRESS, reg_buf, 4, HIF_WR_SYNC_BYTE_FIX); - if (status) - WARN_ON(1); + WARN_ON(status); return status; } -- cgit v1.2.3-18-g5258 From d01a303e68310695b6d08327454f4ad76a48716f Mon Sep 17 00:00:00 2001 From: Pontus Fuchs Date: Mon, 5 Nov 2012 21:17:50 +0100 Subject: ar5523: Fix sparse endianness warnings __be32 variables where used a little careless leading to sparse warnings. Treat them a little more gentle. Reported-by: Fengguang Wu Signed-off-by: Pontus Fuchs Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ar5523/ar5523.c | 43 +++++++++++++++-------------- drivers/net/wireless/ath/ar5523/ar5523_hw.h | 2 +- 2 files changed, 24 insertions(+), 21 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ar5523/ar5523.c b/drivers/net/wireless/ath/ar5523/ar5523.c index 402e6d378b2..4bd7714cd66 100644 --- a/drivers/net/wireless/ath/ar5523/ar5523.c +++ b/drivers/net/wireless/ath/ar5523/ar5523.c @@ -50,18 +50,19 @@ static void ar5523_read_reply(struct ar5523 *ar, struct ar5523_cmd_hdr *hdr, struct ar5523_tx_cmd *cmd) { int dlen, olen; - u32 *rp; + __be32 *rp; - dlen = hdr->len - sizeof(*hdr); + dlen = be32_to_cpu(hdr->len) - sizeof(*hdr); if (dlen < 0) { WARN_ON(1); goto out; } - ar5523_dbg(ar, "Code = %d len = %d\n", hdr->code & 0xff, dlen); + ar5523_dbg(ar, "Code = %d len = %d\n", be32_to_cpu(hdr->code) & 0xff, + dlen); - rp = (u32 *)(hdr + 1); + rp = (__be32 *)(hdr + 1); if (dlen >= sizeof(u32)) { olen = be32_to_cpu(rp[0]); dlen -= sizeof(u32); @@ -95,6 +96,7 @@ static void ar5523_cmd_rx_cb(struct urb *urb) struct ar5523_tx_cmd *cmd = &ar->tx_cmd; struct ar5523_cmd_hdr *hdr = ar->rx_cmd_buf; int dlen; + u32 code, hdrlen; if (urb->status) { if (urb->status != -ESHUTDOWN) @@ -110,15 +112,15 @@ static void ar5523_cmd_rx_cb(struct urb *urb) ar5523_dbg(ar, "%s code %02x priv %d\n", __func__, be32_to_cpu(hdr->code) & 0xff, hdr->priv); - hdr->code = be32_to_cpu(hdr->code); - hdr->len = be32_to_cpu(hdr->len); + code = be32_to_cpu(hdr->code); + hdrlen = be32_to_cpu(hdr->len); - switch (hdr->code & 0xff) { + switch (code & 0xff) { default: /* reply to a read command */ if (hdr->priv != AR5523_CMD_ID) { ar5523_err(ar, "Unexpected command id: %02x\n", - hdr->code & 0xff); + code & 0xff); goto skip; } ar5523_read_reply(ar, hdr, cmd); @@ -147,7 +149,7 @@ static void ar5523_cmd_rx_cb(struct urb *urb) case WDCMSG_TARGET_START: /* This command returns a bogus id so it needs special handling */ - dlen = hdr->len - sizeof(*hdr); + dlen = hdrlen - sizeof(*hdr); if (dlen != (int)sizeof(u32)) { ar5523_err(ar, "Invalid reply to WDCMSG_TARGET_START"); return; @@ -303,7 +305,7 @@ static int ar5523_config(struct ar5523 *ar, u32 reg, u32 val) write.reg = cpu_to_be32(reg); write.len = cpu_to_be32(0); /* 0 = single write */ - *(u32 *)write.data = cpu_to_be32(val); + *(__be32 *)write.data = cpu_to_be32(val); error = ar5523_cmd_write(ar, WDCMSG_TARGET_SET_CONFIG, &write, 3 * sizeof(u32), 0); @@ -335,29 +337,30 @@ static int ar5523_get_status(struct ar5523 *ar, u32 which, void *odata, int olen) { int error; + __be32 which_be; - which = cpu_to_be32(which); + which_be = cpu_to_be32(which); error = ar5523_cmd_read(ar, WDCMSG_TARGET_GET_STATUS, - &which, sizeof(which), odata, olen, AR5523_CMD_FLAG_MAGIC); + &which_be, sizeof(which_be), odata, olen, AR5523_CMD_FLAG_MAGIC); if (error != 0) - ar5523_err(ar, "could not read EEPROM offset 0x%02x\n", - be32_to_cpu(which)); + ar5523_err(ar, "could not read EEPROM offset 0x%02x\n", which); return error; } static int ar5523_get_capability(struct ar5523 *ar, u32 cap, u32 *val) { int error; + __be32 cap_be, val_be; - cap = cpu_to_be32(cap); - error = ar5523_cmd_read(ar, WDCMSG_TARGET_GET_CAPABILITY, - &cap, sizeof(cap), val, sizeof(u32), AR5523_CMD_FLAG_MAGIC); + cap_be = cpu_to_be32(cap); + error = ar5523_cmd_read(ar, WDCMSG_TARGET_GET_CAPABILITY, &cap_be, + sizeof(cap_be), &val_be, sizeof(__be32), + AR5523_CMD_FLAG_MAGIC); if (error != 0) { - ar5523_err(ar, "could not read capability %u\n", - be32_to_cpu(cap)); + ar5523_err(ar, "could not read capability %u\n", cap); return error; } - *val = be32_to_cpu(*val); + *val = be32_to_cpu(val_be); return error; } diff --git a/drivers/net/wireless/ath/ar5523/ar5523_hw.h b/drivers/net/wireless/ath/ar5523/ar5523_hw.h index a0e8bf46031..0fe2c803f48 100644 --- a/drivers/net/wireless/ath/ar5523/ar5523_hw.h +++ b/drivers/net/wireless/ath/ar5523/ar5523_hw.h @@ -161,7 +161,7 @@ struct ar5523_rx_desc { struct ar5523_tx_desc { __be32 msglen; - __be32 msgid; /* msg id (supplied by host) */ + u32 msgid; /* msg id (supplied by host) */ __be32 type; /* opcode: WDMSG_SEND or WDCMSG_FLUSH */ __be32 txqid; /* tx queue id and flags */ #define UATH_TXQID_MASK 0x0f -- cgit v1.2.3-18-g5258 From 9ee01b30fdc85a4ab5b0836ad98ac0ae5092fb4f Mon Sep 17 00:00:00 2001 From: Pontus Fuchs Date: Mon, 5 Nov 2012 21:17:51 +0100 Subject: ar5523: Don't dereference sta if NULL A missing else caused a potential NULL dereference. Reported-by: Yuanhan Liu Signed-off-by: Pontus Fuchs Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ar5523/ar5523.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ar5523/ar5523.c b/drivers/net/wireless/ath/ar5523/ar5523.c index 4bd7714cd66..7157f7d311c 100644 --- a/drivers/net/wireless/ath/ar5523/ar5523.c +++ b/drivers/net/wireless/ath/ar5523/ar5523.c @@ -1196,8 +1196,8 @@ static void ar5523_create_rateset(struct ar5523 *ar, if (!sta) { ar5523_info(ar, "STA not found. Cannot set rates\n"); sta_rate_set = bss_conf->basic_rates; - } - sta_rate_set = sta->supp_rates[ar->hw->conf.channel->band]; + } else + sta_rate_set = sta->supp_rates[ar->hw->conf.channel->band]; ar5523_dbg(ar, "sta rate_set = %08x\n", sta_rate_set); -- cgit v1.2.3-18-g5258 From ff7e68670c49b6404acc4fce6ca90d6c89ef0efe Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Thu, 15 Nov 2012 16:34:56 +0200 Subject: ath6kl: support NL80211_USER_REG_HINT_CELL_BASE events As ath6kl firmware can't do intersections the driver should only listen to regdom changes from cellular base stations, all other requests need to be refused. Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/cfg80211.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index bf5e7d51939..41dea0d5fe0 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -3500,11 +3500,18 @@ static int ath6kl_cfg80211_reg_notify(struct wiphy *wiphy, int ret, i; ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, - "cfg reg_notify %c%c%s%s initiator %d\n", + "cfg reg_notify %c%c%s%s initiator %d hint_type %d\n", request->alpha2[0], request->alpha2[1], request->intersect ? " intersect" : "", request->processed ? " processed" : "", - request->initiator); + request->initiator, request->user_reg_hint_type); + + /* + * As firmware is not able intersect regdoms, we can only listen to + * cellular hints. + */ + if (request->user_reg_hint_type != NL80211_USER_REG_HINT_CELL_BASE) + return -EOPNOTSUPP; ret = ath6kl_wmi_set_regdomain_cmd(ar->wmi, request->alpha2); if (ret) { @@ -3668,8 +3675,10 @@ int ath6kl_cfg80211_init(struct ath6kl *ar) } if (config_enabled(CONFIG_ATH6KL_REGDOMAIN) && - test_bit(ATH6KL_FW_CAPABILITY_REGDOMAIN, ar->fw_capabilities)) + test_bit(ATH6KL_FW_CAPABILITY_REGDOMAIN, ar->fw_capabilities)) { wiphy->reg_notifier = ath6kl_cfg80211_reg_notify; + ar->wiphy->features |= NL80211_FEATURE_CELL_BASE_REG_HINTS; + } /* max num of ssids that can be probed during scanning */ wiphy->max_scan_ssids = MAX_PROBED_SSIDS; -- cgit v1.2.3-18-g5258 From a6952287942a13831502838d47e268d05c21c48f Mon Sep 17 00:00:00 2001 From: Zefir Kurtisi Date: Wed, 31 Oct 2012 12:23:01 +0100 Subject: ath9k: [DFS] add pulse width tolerance for ETSI Add 5% width tolerance for radar patterns defined by ETSI. Signed-off-by: Zefir Kurtisi Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/dfs_pattern_detector.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/dfs_pattern_detector.c b/drivers/net/wireless/ath/ath9k/dfs_pattern_detector.c index 3b129143653..24877b00cbf 100644 --- a/drivers/net/wireless/ath/ath9k/dfs_pattern_detector.c +++ b/drivers/net/wireless/ath/ath9k/dfs_pattern_detector.c @@ -42,10 +42,15 @@ struct radar_types { #define MIN_PPB_THRESH 50 #define PPB_THRESH(PPB) ((PPB * MIN_PPB_THRESH + 50) / 100) #define PRF2PRI(PRF) ((1000000 + PRF / 2) / PRF) +/* percentage of pulse width tolerance */ +#define WIDTH_TOLERANCE 5 +#define WIDTH_LOWER(X) ((X*(100-WIDTH_TOLERANCE)+50)/100) +#define WIDTH_UPPER(X) ((X*(100+WIDTH_TOLERANCE)+50)/100) #define ETSI_PATTERN(ID, WMIN, WMAX, PMIN, PMAX, PRF, PPB) \ { \ - ID, WMIN, WMAX, (PRF2PRI(PMAX) - PRI_TOLERANCE), \ + ID, WIDTH_LOWER(WMIN), WIDTH_UPPER(WMAX), \ + (PRF2PRI(PMAX) - PRI_TOLERANCE), \ (PRF2PRI(PMIN) * PRF + PRI_TOLERANCE), PRF, PPB * PRF, \ PPB_THRESH(PPB), PRI_TOLERANCE, \ } -- cgit v1.2.3-18-g5258 From 0b6eb3662210cd06127980d2d5a06d6e129f373e Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Fri, 9 Nov 2012 14:51:30 +0530 Subject: ath9k_hw: Fix wrong peak detector DC offset An issue is reported in AR9462 & AR9565 that NF_cal_not_done is not observed when HW peak detector calibration is disabled. At that state, the HW is stuck at NF calibration which prevents tx output. The root cause is wrong peak detector offset calibrated by HW. To resolve this issue, peak detector calibration is done manually by SW for AR9462 and AR9565. Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_calib.c | 76 ++++++++++++++++++++++ drivers/net/wireless/ath/ath9k/ar9003_phy.h | 46 +++++++++++-- .../net/wireless/ath/ath9k/ar9462_2p0_initvals.h | 2 +- 3 files changed, 116 insertions(+), 8 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c index 162401f22f8..8b0d8dcd762 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c @@ -891,6 +891,74 @@ static void ar9003_hw_tx_iq_cal_reload(struct ath_hw *ah) AR_PHY_RX_IQCAL_CORR_B0_LOOPBACK_IQCORR_EN, 0x1); } +static void ar9003_hw_manual_peak_cal(struct ath_hw *ah, u8 chain, bool is_2g) +{ + int offset[8], total = 0, test; + int agc_out, i; + + REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_GAINSTAGES(chain), + AR_PHY_65NM_RXRF_GAINSTAGES_RX_OVERRIDE, 0x1); + REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_GAINSTAGES(chain), + AR_PHY_65NM_RXRF_GAINSTAGES_LNAON_CALDC, 0x0); + if (is_2g) + REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_GAINSTAGES(chain), + AR_PHY_65NM_RXRF_GAINSTAGES_LNA2G_GAIN_OVR, 0x0); + else + REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_GAINSTAGES(chain), + AR_PHY_65NM_RXRF_GAINSTAGES_LNA5G_GAIN_OVR, 0x0); + + REG_RMW_FIELD(ah, AR_PHY_65NM_RXTX2(chain), + AR_PHY_65NM_RXTX2_RXON_OVR, 0x1); + REG_RMW_FIELD(ah, AR_PHY_65NM_RXTX2(chain), + AR_PHY_65NM_RXTX2_RXON, 0x0); + + REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain), + AR_PHY_65NM_RXRF_AGC_AGC_OVERRIDE, 0x1); + REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain), + AR_PHY_65NM_RXRF_AGC_AGC_ON_OVR, 0x1); + REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain), + AR_PHY_65NM_RXRF_AGC_AGC_CAL_OVR, 0x1); + if (is_2g) + REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain), + AR_PHY_65NM_RXRF_AGC_AGC2G_DBDAC_OVR, 0x0); + else + REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain), + AR_PHY_65NM_RXRF_AGC_AGC5G_DBDAC_OVR, 0x0); + + for (i = 6; i > 0; i--) { + offset[i] = BIT(i - 1); + test = total + offset[i]; + + if (is_2g) + REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain), + AR_PHY_65NM_RXRF_AGC_AGC2G_CALDAC_OVR, + test); + else + REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain), + AR_PHY_65NM_RXRF_AGC_AGC5G_CALDAC_OVR, + test); + udelay(100); + agc_out = REG_READ_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain), + AR_PHY_65NM_RXRF_AGC_AGC_OUT); + offset[i] = (agc_out) ? 0 : 1; + total += (offset[i] << (i - 1)); + } + + if (is_2g) + REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain), + AR_PHY_65NM_RXRF_AGC_AGC2G_CALDAC_OVR, total); + else + REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain), + AR_PHY_65NM_RXRF_AGC_AGC5G_CALDAC_OVR, total); + + REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_GAINSTAGES(chain), + AR_PHY_65NM_RXRF_GAINSTAGES_RX_OVERRIDE, 0); + REG_RMW_FIELD(ah, AR_PHY_65NM_RXTX2(chain), + AR_PHY_65NM_RXTX2_RXON_OVR, 0); + REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain), + AR_PHY_65NM_RXRF_AGC_AGC_CAL_OVR, 0); +} + static bool ar9003_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan) { @@ -989,6 +1057,14 @@ skip_tx_iqcal: status = ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0, AH_WAIT_TIMEOUT); + if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) { + for (i = 0; i < AR9300_MAX_CHAINS; i++) { + if (!(ah->rxchainmask & (1 << i))) + continue; + ar9003_hw_manual_peak_cal(ah, i, + IS_CHAN_2GHZ(chan)); + } + } } if (ath9k_hw_mci_is_enabled(ah) && IS_CHAN_2GHZ(chan) && run_agc_cal) diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h index 8f585233a78..4c3d06de711 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h @@ -698,13 +698,6 @@ #define AR_PHY_65NM_CH0_THERM_SAR_ADC_OUT 0x0000ff00 #define AR_PHY_65NM_CH0_THERM_SAR_ADC_OUT_S 8 -#define AR_PHY_65NM_CH0_RXTX1 0x16100 -#define AR_PHY_65NM_CH0_RXTX2 0x16104 -#define AR_PHY_65NM_CH1_RXTX1 0x16500 -#define AR_PHY_65NM_CH1_RXTX2 0x16504 -#define AR_PHY_65NM_CH2_RXTX1 0x16900 -#define AR_PHY_65NM_CH2_RXTX2 0x16904 - #define AR_CH0_TOP2 (AR_SREV_9300(ah) ? 0x1628c : \ (AR_SREV_9462(ah) ? 0x16290 : 0x16284)) #define AR_CH0_TOP2_XPABIASLVL 0xf000 @@ -1286,4 +1279,43 @@ #define AR_BTCOEX_WL_LNADIV_BT_INACTIVE_THRESHOLD 0xFC000000 #define AR_BTCOEX_WL_LNADIV_BT_INACTIVE_THRESHOLD_S 26 +/* Manual Peak detector calibration */ +#define AR_PHY_65NM_BASE 0x16000 +#define AR_PHY_65NM_RXRF_GAINSTAGES(i) (AR_PHY_65NM_BASE + \ + (i * 0x400) + 0x8) +#define AR_PHY_65NM_RXRF_GAINSTAGES_RX_OVERRIDE 0x80000000 +#define AR_PHY_65NM_RXRF_GAINSTAGES_RX_OVERRIDE_S 31 +#define AR_PHY_65NM_RXRF_GAINSTAGES_LNAON_CALDC 0x00000002 +#define AR_PHY_65NM_RXRF_GAINSTAGES_LNAON_CALDC_S 1 +#define AR_PHY_65NM_RXRF_GAINSTAGES_LNA2G_GAIN_OVR 0x70000000 +#define AR_PHY_65NM_RXRF_GAINSTAGES_LNA2G_GAIN_OVR_S 28 +#define AR_PHY_65NM_RXRF_GAINSTAGES_LNA5G_GAIN_OVR 0x03800000 +#define AR_PHY_65NM_RXRF_GAINSTAGES_LNA5G_GAIN_OVR_S 23 + +#define AR_PHY_65NM_RXTX2(i) (AR_PHY_65NM_BASE + \ + (i * 0x400) + 0x104) +#define AR_PHY_65NM_RXTX2_RXON_OVR 0x00001000 +#define AR_PHY_65NM_RXTX2_RXON_OVR_S 12 +#define AR_PHY_65NM_RXTX2_RXON 0x00000800 +#define AR_PHY_65NM_RXTX2_RXON_S 11 + +#define AR_PHY_65NM_RXRF_AGC(i) (AR_PHY_65NM_BASE + \ + (i * 0x400) + 0xc) +#define AR_PHY_65NM_RXRF_AGC_AGC_OVERRIDE 0x80000000 +#define AR_PHY_65NM_RXRF_AGC_AGC_OVERRIDE_S 31 +#define AR_PHY_65NM_RXRF_AGC_AGC_ON_OVR 0x40000000 +#define AR_PHY_65NM_RXRF_AGC_AGC_ON_OVR_S 30 +#define AR_PHY_65NM_RXRF_AGC_AGC_CAL_OVR 0x20000000 +#define AR_PHY_65NM_RXRF_AGC_AGC_CAL_OVR_S 29 +#define AR_PHY_65NM_RXRF_AGC_AGC2G_DBDAC_OVR 0x1E000000 +#define AR_PHY_65NM_RXRF_AGC_AGC2G_DBDAC_OVR_S 25 +#define AR_PHY_65NM_RXRF_AGC_AGC5G_DBDAC_OVR 0x00078000 +#define AR_PHY_65NM_RXRF_AGC_AGC5G_DBDAC_OVR_S 15 +#define AR_PHY_65NM_RXRF_AGC_AGC2G_CALDAC_OVR 0x01F80000 +#define AR_PHY_65NM_RXRF_AGC_AGC2G_CALDAC_OVR_S 19 +#define AR_PHY_65NM_RXRF_AGC_AGC5G_CALDAC_OVR 0x00007e00 +#define AR_PHY_65NM_RXRF_AGC_AGC5G_CALDAC_OVR_S 9 +#define AR_PHY_65NM_RXRF_AGC_AGC_OUT 0x00000004 +#define AR_PHY_65NM_RXRF_AGC_AGC_OUT_S 2 + #endif /* AR9003_PHY_H */ diff --git a/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h b/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h index 58f30f65c6b..ccc42a71b43 100644 --- a/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h @@ -78,7 +78,7 @@ static const u32 ar9462_2p0_baseband_postamble[][5] = { {0x0000a284, 0x00000000, 0x00000000, 0x00000150, 0x00000150}, {0x0000a288, 0x00000110, 0x00000110, 0x00000110, 0x00000110}, {0x0000a28c, 0x00022222, 0x00022222, 0x00022222, 0x00022222}, - {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18}, + {0x0000a2c4, 0x00058d18, 0x00058d18, 0x00058d18, 0x00058d18}, {0x0000a2d0, 0x00041981, 0x00041981, 0x00041981, 0x00041982}, {0x0000a2d8, 0x7999a83b, 0x7999a83b, 0x7999a83b, 0x7999a83b}, {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, -- cgit v1.2.3-18-g5258 From 413c0303cfbf269cdc7a90653ec15f3cb73cd080 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Mon, 12 Nov 2012 10:56:43 +0530 Subject: ath9k_hw: Update AR9485 initvals Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9485_initvals.h | 336 ++++++++++++++++++----- 1 file changed, 273 insertions(+), 63 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/ar9485_initvals.h b/drivers/net/wireless/ath/ath9k/ar9485_initvals.h index fb4497fc7a3..02e4d977bd4 100644 --- a/drivers/net/wireless/ath/ath9k/ar9485_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9485_initvals.h @@ -18,7 +18,7 @@ #ifndef INITVALS_9485_H #define INITVALS_9485_H -/* AR9485 1.0 */ +/* AR9485 1.1 */ #define ar9485_1_1_mac_postamble ar9300_2p2_mac_postamble @@ -31,6 +31,11 @@ static const u32 ar9485_1_1_pcie_phy_pll_on_clkreq_disable_L1[][2] = { static const u32 ar9485Common_wo_xlna_rx_gain_1_1[][2] = { /* Addr allmodes */ + {0x00009e00, 0x037216a0}, + {0x00009e04, 0x00182020}, + {0x00009e18, 0x00000000}, + {0x00009e2c, 0x00004121}, + {0x00009e44, 0x02282324}, {0x0000a000, 0x00060005}, {0x0000a004, 0x00810080}, {0x0000a008, 0x00830082}, @@ -164,6 +169,11 @@ static const u32 ar9485Common_wo_xlna_rx_gain_1_1[][2] = { static const u32 ar9485Modes_high_power_tx_gain_1_1[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ {0x000098bc, 0x00000002, 0x00000002, 0x00000002, 0x00000002}, + {0x0000a2d8, 0xf999a83a, 0xf999a83a, 0x7999a83a, 0x7999a83a}, + {0x0000a2dc, 0x00000000, 0x00000000, 0xfe2d3552, 0xfe2d3552}, + {0x0000a2e0, 0x00000000, 0x00000000, 0xfe2d3552, 0xfe2d3552}, + {0x0000a2e4, 0x00000000, 0x00000000, 0xfe2d3552, 0xfe2d3552}, + {0x0000a2e8, 0x00000000, 0x00000000, 0xfe2d3552, 0xfe2d3552}, {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8}, {0x0000a458, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000}, @@ -198,6 +208,22 @@ static const u32 ar9485Modes_high_power_tx_gain_1_1[][5] = { {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, + {0x0000a580, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a584, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a588, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a58c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a590, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a594, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a598, 0x00000000, 0x00000000, 0x01404501, 0x01404501}, + {0x0000a59c, 0x00000000, 0x00000000, 0x02808a02, 0x02808a02}, + {0x0000a5a0, 0x00000000, 0x00000000, 0x02808a02, 0x02808a02}, + {0x0000a5a4, 0x00000000, 0x00000000, 0x02808803, 0x02808803}, + {0x0000a5a8, 0x00000000, 0x00000000, 0x04c14b04, 0x04c14b04}, + {0x0000a5ac, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305}, + {0x0000a5b0, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305}, + {0x0000a5b4, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305}, + {0x0000a5b8, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305}, + {0x0000a5bc, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305}, {0x0000b500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000b504, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000b508, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, @@ -234,9 +260,193 @@ static const u32 ar9485Modes_high_power_tx_gain_1_1[][5] = { {0x00016048, 0x6c924260, 0x6c924260, 0x6c924260, 0x6c924260}, }; -#define ar9485Modes_high_ob_db_tx_gain_1_1 ar9485Modes_high_power_tx_gain_1_1 +static const u32 ar9485Modes_high_ob_db_tx_gain_1_1[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x000098bc, 0x00000002, 0x00000002, 0x00000002, 0x00000002}, + {0x0000a2d8, 0xf999a83a, 0xf999a83a, 0x7999a83a, 0x7999a83a}, + {0x0000a2dc, 0x00000000, 0x00000000, 0xfe2d3552, 0xfe2d3552}, + {0x0000a2e0, 0x00000000, 0x00000000, 0xffc63a84, 0xffc63a84}, + {0x0000a2e4, 0x00000000, 0x00000000, 0xfe0fc000, 0xfe0fc000}, + {0x0000a2e8, 0x00000000, 0x00000000, 0xfff00000, 0xfff00000}, + {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8}, + {0x0000a458, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000}, + {0x0000a504, 0x05062002, 0x05062002, 0x04000002, 0x04000002}, + {0x0000a508, 0x0c002e00, 0x0c002e00, 0x08000004, 0x08000004}, + {0x0000a50c, 0x11062202, 0x11062202, 0x0d000200, 0x0d000200}, + {0x0000a510, 0x17022e00, 0x17022e00, 0x11000202, 0x11000202}, + {0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x15000400, 0x15000400}, + {0x0000a518, 0x25020ec0, 0x25020ec0, 0x19000402, 0x19000402}, + {0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x1d000404, 0x1d000404}, + {0x0000a520, 0x2f001f04, 0x2f001f04, 0x21000603, 0x21000603}, + {0x0000a524, 0x35001fc4, 0x35001fc4, 0x25000605, 0x25000605}, + {0x0000a528, 0x3c022f04, 0x3c022f04, 0x2a000a03, 0x2a000a03}, + {0x0000a52c, 0x41023e85, 0x41023e85, 0x2c000a04, 0x2c000a04}, + {0x0000a530, 0x48023ec6, 0x48023ec6, 0x34000e20, 0x34000e20}, + {0x0000a534, 0x4d023f01, 0x4d023f01, 0x35000e21, 0x35000e21}, + {0x0000a538, 0x53023f4b, 0x53023f4b, 0x43000e62, 0x43000e62}, + {0x0000a53c, 0x5a027f09, 0x5a027f09, 0x45000e63, 0x45000e63}, + {0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x49000e65, 0x49000e65}, + {0x0000a544, 0x6502feca, 0x6502feca, 0x4b000e66, 0x4b000e66}, + {0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x4d001645, 0x4d001645}, + {0x0000a54c, 0x7203feca, 0x7203feca, 0x51001865, 0x51001865}, + {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x55001a86, 0x55001a86}, + {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x57001ce9, 0x57001ce9}, + {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001ceb, 0x5a001ceb}, + {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x5e001eeb, 0x5e001eeb}, + {0x0000a560, 0x900fff0b, 0x900fff0b, 0x5e001eeb, 0x5e001eeb}, + {0x0000a564, 0x960fffcb, 0x960fffcb, 0x5e001eeb, 0x5e001eeb}, + {0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, + {0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, + {0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, + {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, + {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, + {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, + {0x0000a580, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a584, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a588, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a58c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a590, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a594, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a598, 0x00000000, 0x00000000, 0x01404501, 0x01404501}, + {0x0000a59c, 0x00000000, 0x00000000, 0x02808a02, 0x02808a02}, + {0x0000a5a0, 0x00000000, 0x00000000, 0x02808a02, 0x02808a02}, + {0x0000a5a4, 0x00000000, 0x00000000, 0x02808803, 0x02808803}, + {0x0000a5a8, 0x00000000, 0x00000000, 0x04c14b04, 0x04c14b04}, + {0x0000a5ac, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305}, + {0x0000a5b0, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305}, + {0x0000a5b4, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305}, + {0x0000a5b8, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305}, + {0x0000a5bc, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305}, + {0x0000b500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b504, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b508, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b50c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b510, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b514, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b518, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b51c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b520, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b524, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b528, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b52c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b530, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b534, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b538, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b53c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b540, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b544, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b548, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b54c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b550, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b554, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b558, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b55c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b560, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b564, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b568, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b56c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b570, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b574, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b578, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b57c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x00016044, 0x05d6b2db, 0x05d6b2db, 0x05d6b2db, 0x05d6b2db}, + {0x00016048, 0x6c924260, 0x6c924260, 0x6c924260, 0x6c924260}, +}; -#define ar9485Modes_low_ob_db_tx_gain_1_1 ar9485Modes_high_ob_db_tx_gain_1_1 +static const u32 ar9485Modes_low_ob_db_tx_gain_1_1[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x000098bc, 0x00000002, 0x00000002, 0x00000002, 0x00000002}, + {0x0000a2d8, 0xf999a83a, 0xf999a83a, 0x7999a83a, 0x7999a83a}, + {0x0000a2dc, 0x00000000, 0x00000000, 0xfe2d3552, 0xfe2d3552}, + {0x0000a2e0, 0x00000000, 0x00000000, 0xfe2d3552, 0xfe2d3552}, + {0x0000a2e4, 0x00000000, 0x00000000, 0xfe2d3552, 0xfe2d3552}, + {0x0000a2e8, 0x00000000, 0x00000000, 0xfe2d3552, 0xfe2d3552}, + {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8}, + {0x0000a458, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000}, + {0x0000a504, 0x05062002, 0x05062002, 0x04000002, 0x04000002}, + {0x0000a508, 0x0c002e00, 0x0c002e00, 0x08000004, 0x08000004}, + {0x0000a50c, 0x11062202, 0x11062202, 0x0d000200, 0x0d000200}, + {0x0000a510, 0x17022e00, 0x17022e00, 0x11000202, 0x11000202}, + {0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x15000400, 0x15000400}, + {0x0000a518, 0x25020ec0, 0x25020ec0, 0x19000402, 0x19000402}, + {0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x1d000404, 0x1d000404}, + {0x0000a520, 0x2f001f04, 0x2f001f04, 0x21000603, 0x21000603}, + {0x0000a524, 0x35001fc4, 0x35001fc4, 0x25000605, 0x25000605}, + {0x0000a528, 0x3c022f04, 0x3c022f04, 0x2a000a03, 0x2a000a03}, + {0x0000a52c, 0x41023e85, 0x41023e85, 0x2c000a04, 0x2c000a04}, + {0x0000a530, 0x48023ec6, 0x48023ec6, 0x34000e20, 0x34000e20}, + {0x0000a534, 0x4d023f01, 0x4d023f01, 0x35000e21, 0x35000e21}, + {0x0000a538, 0x53023f4b, 0x53023f4b, 0x43000e62, 0x43000e62}, + {0x0000a53c, 0x5a027f09, 0x5a027f09, 0x45000e63, 0x45000e63}, + {0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x49000e65, 0x49000e65}, + {0x0000a544, 0x6502feca, 0x6502feca, 0x4b000e66, 0x4b000e66}, + {0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x4d001645, 0x4d001645}, + {0x0000a54c, 0x7203feca, 0x7203feca, 0x51001865, 0x51001865}, + {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x55001a86, 0x55001a86}, + {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x57001ce9, 0x57001ce9}, + {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001ceb, 0x5a001ceb}, + {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x5e001eeb, 0x5e001eeb}, + {0x0000a560, 0x900fff0b, 0x900fff0b, 0x5e001eeb, 0x5e001eeb}, + {0x0000a564, 0x960fffcb, 0x960fffcb, 0x5e001eeb, 0x5e001eeb}, + {0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, + {0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, + {0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, + {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, + {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, + {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, + {0x0000a580, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a584, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a588, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a58c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a590, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a594, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a598, 0x00000000, 0x00000000, 0x01404501, 0x01404501}, + {0x0000a59c, 0x00000000, 0x00000000, 0x02808a02, 0x02808a02}, + {0x0000a5a0, 0x00000000, 0x00000000, 0x02808a02, 0x02808a02}, + {0x0000a5a4, 0x00000000, 0x00000000, 0x02808803, 0x02808803}, + {0x0000a5a8, 0x00000000, 0x00000000, 0x04c14b04, 0x04c14b04}, + {0x0000a5ac, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305}, + {0x0000a5b0, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305}, + {0x0000a5b4, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305}, + {0x0000a5b8, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305}, + {0x0000a5bc, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305}, + {0x0000b500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b504, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b508, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b50c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b510, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b514, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b518, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b51c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b520, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b524, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b528, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b52c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b530, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b534, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b538, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b53c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b540, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b544, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b548, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b54c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b550, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b554, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b558, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b55c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b560, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b564, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b568, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b56c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b570, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b574, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b578, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b57c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x00016044, 0x05d6b2db, 0x05d6b2db, 0x05d6b2db, 0x05d6b2db}, + {0x00016048, 0x6c924260, 0x6c924260, 0x6c924260, 0x6c924260}, +}; #define ar9485_modes_lowest_ob_db_tx_gain_1_1 ar9485Modes_low_ob_db_tx_gain_1_1 @@ -245,19 +455,19 @@ static const u32 ar9485_1_1[][2] = { {0x0000a580, 0x00000000}, {0x0000a584, 0x00000000}, {0x0000a588, 0x00000000}, - {0x0000a58c, 0x00000000}, - {0x0000a590, 0x00000000}, - {0x0000a594, 0x00000000}, - {0x0000a598, 0x00000000}, - {0x0000a59c, 0x00000000}, - {0x0000a5a0, 0x00000000}, - {0x0000a5a4, 0x00000000}, - {0x0000a5a8, 0x00000000}, - {0x0000a5ac, 0x00000000}, - {0x0000a5b0, 0x00000000}, - {0x0000a5b4, 0x00000000}, - {0x0000a5b8, 0x00000000}, - {0x0000a5bc, 0x00000000}, + {0x0000a58c, 0x01804000}, + {0x0000a590, 0x02808a02}, + {0x0000a594, 0x0340ca02}, + {0x0000a598, 0x0340cd03}, + {0x0000a59c, 0x0340cd03}, + {0x0000a5a0, 0x06415304}, + {0x0000a5a4, 0x04c11905}, + {0x0000a5a8, 0x06415905}, + {0x0000a5ac, 0x06415905}, + {0x0000a5b0, 0x06415905}, + {0x0000a5b4, 0x06415905}, + {0x0000a5b8, 0x06415905}, + {0x0000a5bc, 0x06415905}, }; static const u32 ar9485_1_1_radio_core[][2] = { @@ -340,7 +550,7 @@ static const u32 ar9485_1_1_baseband_core[][2] = { {0x00009880, 0x201fff00}, {0x00009884, 0x00001042}, {0x000098a4, 0x00200400}, - {0x000098b0, 0x52440bbe}, + {0x000098b0, 0x32840bbe}, {0x000098d0, 0x004b6a8e}, {0x000098d4, 0x00000820}, {0x000098dc, 0x00000000}, @@ -362,7 +572,7 @@ static const u32 ar9485_1_1_baseband_core[][2] = { {0x00009d18, 0x00000000}, {0x00009d1c, 0x00000000}, {0x00009e08, 0x0038233c}, - {0x00009e24, 0x9927b515}, + {0x00009e24, 0x992bb515}, {0x00009e28, 0x12ef0200}, {0x00009e30, 0x06336f77}, {0x00009e34, 0x6af6532f}, @@ -427,7 +637,7 @@ static const u32 ar9485_1_1_baseband_core[][2] = { {0x0000a408, 0x0e79e5c6}, {0x0000a40c, 0x00820820}, {0x0000a414, 0x1ce739cf}, - {0x0000a418, 0x2d0019ce}, + {0x0000a418, 0x2d0021ce}, {0x0000a41c, 0x1ce739ce}, {0x0000a420, 0x000001ce}, {0x0000a424, 0x1ce739ce}, @@ -443,8 +653,8 @@ static const u32 ar9485_1_1_baseband_core[][2] = { {0x0000a44c, 0x00000001}, {0x0000a450, 0x00010000}, {0x0000a5c4, 0xbfad9d74}, - {0x0000a5c8, 0x0048060a}, - {0x0000a5cc, 0x00000637}, + {0x0000a5c8, 0x00480605}, + {0x0000a5cc, 0x00002e37}, {0x0000a760, 0x03020100}, {0x0000a764, 0x09080504}, {0x0000a768, 0x0d0c0b0a}, @@ -464,17 +674,22 @@ static const u32 ar9485_1_1_baseband_core[][2] = { static const u32 ar9485_common_rx_gain_1_1[][2] = { /* Addr allmodes */ - {0x0000a000, 0x00010000}, - {0x0000a004, 0x00030002}, - {0x0000a008, 0x00050004}, - {0x0000a00c, 0x00810080}, - {0x0000a010, 0x01800082}, - {0x0000a014, 0x01820181}, - {0x0000a018, 0x01840183}, - {0x0000a01c, 0x01880185}, - {0x0000a020, 0x018a0189}, - {0x0000a024, 0x02850284}, - {0x0000a028, 0x02890288}, + {0x00009e00, 0x03721b20}, + {0x00009e04, 0x00082020}, + {0x00009e18, 0x0300501e}, + {0x00009e2c, 0x00002e21}, + {0x00009e44, 0x02182324}, + {0x0000a000, 0x00060005}, + {0x0000a004, 0x00810080}, + {0x0000a008, 0x00830082}, + {0x0000a00c, 0x00850084}, + {0x0000a010, 0x01820181}, + {0x0000a014, 0x01840183}, + {0x0000a018, 0x01880185}, + {0x0000a01c, 0x018a0189}, + {0x0000a020, 0x02850284}, + {0x0000a024, 0x02890288}, + {0x0000a028, 0x028b028a}, {0x0000a02c, 0x03850384}, {0x0000a030, 0x03890388}, {0x0000a034, 0x038b038a}, @@ -496,15 +711,15 @@ static const u32 ar9485_common_rx_gain_1_1[][2] = { {0x0000a074, 0x00000000}, {0x0000a078, 0x00000000}, {0x0000a07c, 0x00000000}, - {0x0000a080, 0x28282828}, - {0x0000a084, 0x28282828}, - {0x0000a088, 0x28282828}, - {0x0000a08c, 0x28282828}, - {0x0000a090, 0x28282828}, - {0x0000a094, 0x21212128}, - {0x0000a098, 0x171c1c1c}, - {0x0000a09c, 0x02020212}, - {0x0000a0a0, 0x00000202}, + {0x0000a080, 0x18181818}, + {0x0000a084, 0x18181818}, + {0x0000a088, 0x18181818}, + {0x0000a08c, 0x18181818}, + {0x0000a090, 0x18181818}, + {0x0000a094, 0x18181818}, + {0x0000a098, 0x17181818}, + {0x0000a09c, 0x02020b0b}, + {0x0000a0a0, 0x02020202}, {0x0000a0a4, 0x00000000}, {0x0000a0a8, 0x00000000}, {0x0000a0ac, 0x00000000}, @@ -512,22 +727,22 @@ static const u32 ar9485_common_rx_gain_1_1[][2] = { {0x0000a0b4, 0x00000000}, {0x0000a0b8, 0x00000000}, {0x0000a0bc, 0x00000000}, - {0x0000a0c0, 0x001f0000}, - {0x0000a0c4, 0x111f1100}, - {0x0000a0c8, 0x111d111e}, - {0x0000a0cc, 0x111b111c}, - {0x0000a0d0, 0x22032204}, - {0x0000a0d4, 0x22012202}, - {0x0000a0d8, 0x221f2200}, - {0x0000a0dc, 0x221d221e}, - {0x0000a0e0, 0x33013302}, - {0x0000a0e4, 0x331f3300}, - {0x0000a0e8, 0x4402331e}, - {0x0000a0ec, 0x44004401}, - {0x0000a0f0, 0x441e441f}, - {0x0000a0f4, 0x55015502}, - {0x0000a0f8, 0x551f5500}, - {0x0000a0fc, 0x6602551e}, + {0x0000a0c0, 0x22072208}, + {0x0000a0c4, 0x22052206}, + {0x0000a0c8, 0x22032204}, + {0x0000a0cc, 0x22012202}, + {0x0000a0d0, 0x221f2200}, + {0x0000a0d4, 0x221d221e}, + {0x0000a0d8, 0x33023303}, + {0x0000a0dc, 0x33003301}, + {0x0000a0e0, 0x331e331f}, + {0x0000a0e4, 0x4402331d}, + {0x0000a0e8, 0x44004401}, + {0x0000a0ec, 0x441e441f}, + {0x0000a0f0, 0x55025503}, + {0x0000a0f4, 0x55005501}, + {0x0000a0f8, 0x551e551f}, + {0x0000a0fc, 0x6602551d}, {0x0000a100, 0x66006601}, {0x0000a104, 0x661e661f}, {0x0000a108, 0x7703661d}, @@ -636,17 +851,12 @@ static const u32 ar9485_1_1_baseband_postamble[][5] = { {0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4}, {0x00009830, 0x0000059c, 0x0000059c, 0x0000059c, 0x0000059c}, {0x00009c00, 0x00000044, 0x00000044, 0x00000044, 0x00000044}, - {0x00009e00, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0}, - {0x00009e04, 0x00182020, 0x00182020, 0x00182020, 0x00182020}, {0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2}, {0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec80d2e, 0x7ec80d2e}, - {0x00009e14, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e}, - {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x00009e14, 0x31395d53, 0x31396053, 0x312e6053, 0x312e5d53}, {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c}, {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce}, - {0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021}, {0x00009e3c, 0xcf946220, 0xcf946220, 0xcf946222, 0xcf946222}, - {0x00009e44, 0x02321e27, 0x02321e27, 0x02282324, 0x02282324}, {0x00009e48, 0x5030201a, 0x5030201a, 0x50302010, 0x50302010}, {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000}, {0x0000a204, 0x01303fc0, 0x01303fc4, 0x01303fc4, 0x01303fc0}, -- cgit v1.2.3-18-g5258 From b126b02796eaac8534b699571bd4209e05b64146 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Mon, 12 Nov 2012 10:56:44 +0530 Subject: ath9k: Remove unused workaround The workaround for ASPM/L0s is needed only for AR9485 1.0, which was never sold and is not supported by ath9k. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 5 ----- drivers/net/wireless/ath/ath9k/hw.h | 3 --- drivers/net/wireless/ath/ath9k/main.c | 3 --- drivers/net/wireless/ath/ath9k/pci.c | 12 ------------ 4 files changed, 23 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 71cd9f0c96a..756191b9eed 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -2561,11 +2561,6 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) pCap->hw_caps |= ATH9K_HW_CAP_ANT_DIV_COMB; } - if (AR_SREV_9485_10(ah)) { - pCap->pcie_lcr_extsync_en = true; - pCap->pcie_lcr_offset = 0x80; - } - if (ath9k_hw_dfs_tested(ah)) pCap->hw_caps |= ATH9K_HW_CAP_DFS; diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 3e73bfe2315..bdabbda5a83 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -273,8 +273,6 @@ struct ath9k_hw_capabilities { u8 rx_status_len; u8 tx_desc_len; u8 txs_len; - u16 pcie_lcr_offset; - bool pcie_lcr_extsync_en; }; struct ath9k_ops_config { @@ -930,7 +928,6 @@ struct ath_bus_ops { void (*read_cachesize)(struct ath_common *common, int *csz); bool (*eeprom_read)(struct ath_common *common, u32 off, u16 *data); void (*bt_coex_prep)(struct ath_common *common); - void (*extn_synch_en)(struct ath_common *common); void (*aspm_init)(struct ath_common *common); }; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index c084532291a..9594b6fcdf0 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -686,9 +686,6 @@ static int ath9k_start(struct ieee80211_hw *hw) spin_unlock_bh(&sc->sc_pcu_lock); - if (ah->caps.pcie_lcr_extsync_en && common->bus_ops->extn_synch_en) - common->bus_ops->extn_synch_en(common); - mutex_unlock(&sc->mutex); ath9k_ps_restore(sc); diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index f088f4bf9a2..9553203ee62 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -96,17 +96,6 @@ static bool ath_pci_eeprom_read(struct ath_common *common, u32 off, u16 *data) return true; } -static void ath_pci_extn_synch_enable(struct ath_common *common) -{ - struct ath_softc *sc = (struct ath_softc *) common->priv; - struct pci_dev *pdev = to_pci_dev(sc->dev); - u8 lnkctl; - - pci_read_config_byte(pdev, sc->sc_ah->caps.pcie_lcr_offset, &lnkctl); - lnkctl |= PCI_EXP_LNKCTL_ES; - pci_write_config_byte(pdev, sc->sc_ah->caps.pcie_lcr_offset, lnkctl); -} - /* Need to be called after we discover btcoex capabilities */ static void ath_pci_aspm_init(struct ath_common *common) { @@ -153,7 +142,6 @@ static const struct ath_bus_ops ath_pci_bus_ops = { .ath_bus_type = ATH_PCI, .read_cachesize = ath_pci_read_cachesize, .eeprom_read = ath_pci_eeprom_read, - .extn_synch_en = ath_pci_extn_synch_enable, .aspm_init = ath_pci_aspm_init, }; -- cgit v1.2.3-18-g5258 From c32f5bbb00cf268f76e977d8cf9c75fa3a89c038 Mon Sep 17 00:00:00 2001 From: Syam Sidhardhan Date: Tue, 13 Nov 2012 21:09:50 +0530 Subject: ath5k: Use module_platform_driver macro for ahb.c Simplify the code by make use of module_platform_driver macro. Signed-off-by: Syam Sidhardhan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/ahb.c | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath5k/ahb.c b/drivers/net/wireless/ath/ath5k/ahb.c index aec33cc207f..8e8bcc7a480 100644 --- a/drivers/net/wireless/ath/ath5k/ahb.c +++ b/drivers/net/wireless/ath/ath5k/ahb.c @@ -236,17 +236,4 @@ static struct platform_driver ath_ahb_driver = { }, }; -static int __init -ath5k_ahb_init(void) -{ - return platform_driver_register(&ath_ahb_driver); -} - -static void __exit -ath5k_ahb_exit(void) -{ - platform_driver_unregister(&ath_ahb_driver); -} - -module_init(ath5k_ahb_init); -module_exit(ath5k_ahb_exit); +module_platform_driver(ath_ahb_driver); -- cgit v1.2.3-18-g5258 From 957708f1a2d3fd41021ea0282e1cd856d23df9ca Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 14 Nov 2012 11:23:07 +0300 Subject: ath5k: precedence error in ath5k_hw_nic_wakeup() '|' has higher precedence than ?:. Since AR5K_PHY_TURBO_MODE is 0x1 and "AR5K_PHY_TURBO_MODE | (ah->ah_radio == AR5K_RF2425)" is true then we always set turbo to zero. Signed-off-by: Dan Carpenter Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/reset.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c index 0c2dd4771c3..4084b107628 100644 --- a/drivers/net/wireless/ath/ath5k/reset.c +++ b/drivers/net/wireless/ath/ath5k/reset.c @@ -789,9 +789,9 @@ ath5k_hw_nic_wakeup(struct ath5k_hw *ah, struct ieee80211_channel *channel) * (I don't think it supports 44MHz) */ /* On 2425 initvals TURBO_SHORT is not present */ if (ah->ah_bwmode == AR5K_BWMODE_40MHZ) { - turbo = AR5K_PHY_TURBO_MODE | - (ah->ah_radio == AR5K_RF2425) ? 0 : - AR5K_PHY_TURBO_SHORT; + turbo = AR5K_PHY_TURBO_MODE; + if (ah->ah_radio != AR5K_RF2425) + turbo |= AR5K_PHY_TURBO_SHORT; } else if (ah->ah_bwmode != AR5K_BWMODE_DEFAULT) { if (ah->ah_radio == AR5K_RF5413) { mode |= (ah->ah_bwmode == AR5K_BWMODE_10MHZ) ? -- cgit v1.2.3-18-g5258 From 57527f8d4d71b5167a02fb6713857f55d3974748 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Tue, 13 Nov 2012 11:33:53 +0530 Subject: ath9k_hw: Program filter coefficients correctly 2484 Mhz (Japan) usage requires filter coefficients to be programmed in the CCK TX FIR registers. This is required for AR9331, AR9485 and AR9462. Fix this and also remove a few useless macros and a duplicate variable. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_hw.c | 22 +++++++++++++--------- drivers/net/wireless/ath/ath9k/ar9003_phy.c | 2 +- drivers/net/wireless/ath/ath9k/ar9485_initvals.h | 2 ++ drivers/net/wireless/ath/ath9k/hw.h | 1 - 4 files changed, 16 insertions(+), 11 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c index 0693cd95b74..74fd3977fee 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c @@ -35,12 +35,6 @@ */ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) { -#define AR9462_BB_CTX_COEFJ(x) \ - ar9462_##x##_baseband_core_txfir_coeff_japan_2484 - -#define AR9462_BBC_TXIFR_COEFFJ \ - ar9462_2p0_baseband_core_txfir_coeff_japan_2484 - if (AR_SREV_9330_11(ah)) { /* mac */ INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE], @@ -70,6 +64,10 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9331_modes_lowest_ob_db_tx_gain_1p1); + /* Japan 2484 Mhz CCK */ + INIT_INI_ARRAY(&ah->iniCckfirJapan2484, + ar9331_1p1_baseband_core_txfir_coeff_japan_2484); + /* additional clock settings */ if (ah->is_clk_25mhz) INIT_INI_ARRAY(&ah->iniAdditional, @@ -106,6 +104,10 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9331_modes_lowest_ob_db_tx_gain_1p2); + /* Japan 2484 Mhz CCK */ + INIT_INI_ARRAY(&ah->iniCckfirJapan2484, + ar9331_1p2_baseband_core_txfir_coeff_japan_2484); + /* additional clock settings */ if (ah->is_clk_25mhz) INIT_INI_ARRAY(&ah->iniAdditional, @@ -180,6 +182,10 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9485_modes_lowest_ob_db_tx_gain_1_1); + /* Japan 2484 Mhz CCK */ + INIT_INI_ARRAY(&ah->iniCckfirJapan2484, + ar9485_1_1_baseband_core_txfir_coeff_japan_2484); + /* Load PCIE SERDES settings from INI */ /* Awake Setting */ @@ -229,9 +235,7 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) ar9462_modes_fast_clock_2p0); INIT_INI_ARRAY(&ah->iniCckfirJapan2484, - AR9462_BB_CTX_COEFJ(2p0)); - - INIT_INI_ARRAY(&ah->ini_japan2484, AR9462_BBC_TXIFR_COEFFJ); + ar9462_2p0_baseband_core_txfir_coeff_japan_2484); } else if (AR_SREV_9550(ah)) { /* mac */ INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE], diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c index 759f5f5a715..ce19c09fa8e 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c @@ -784,7 +784,7 @@ static int ar9003_hw_process_ini(struct ath_hw *ah, REG_WRITE_ARRAY(&ah->iniAdditional, 1, regWrites); if (chan->channel == 2484) - ar9003_hw_prog_ini(ah, &ah->ini_japan2484, 1); + ar9003_hw_prog_ini(ah, &ah->iniCckfirJapan2484, 1); if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) REG_WRITE(ah, AR_GLB_SWREG_DISCONT_MODE, diff --git a/drivers/net/wireless/ath/ath9k/ar9485_initvals.h b/drivers/net/wireless/ath/ath9k/ar9485_initvals.h index 02e4d977bd4..a3710f3bb90 100644 --- a/drivers/net/wireless/ath/ath9k/ar9485_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9485_initvals.h @@ -1060,4 +1060,6 @@ static const u32 ar9485_1_1_mac_core[][2] = { {0x000083d0, 0x000301ff}, }; +#define ar9485_1_1_baseband_core_txfir_coeff_japan_2484 ar9462_2p0_baseband_core_txfir_coeff_japan_2484 + #endif /* INITVALS_9485_H */ diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index bdabbda5a83..3636dabf03e 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -875,7 +875,6 @@ struct ath_hw { struct ar5416IniArray iniModesTxGain; struct ar5416IniArray iniCckfirNormal; struct ar5416IniArray iniCckfirJapan2484; - struct ar5416IniArray ini_japan2484; struct ar5416IniArray iniModes_9271_ANI_reg; struct ar5416IniArray ini_radio_post_sys2ant; -- cgit v1.2.3-18-g5258 From ac46ba4384d2c44c56702d0da591696045fba682 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Mon, 19 Nov 2012 14:24:46 +0530 Subject: ath9k: Fix BTCOEX debugfs file usage The debugfs file for dumping btcoex parameters unconditionally assumes a MCI-based device. This will not work for older btcoex chips. Fix this by branching out the routine into separate functions. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 11 ++++++-- drivers/net/wireless/ath/ath9k/debug.c | 8 +++++- drivers/net/wireless/ath/ath9k/gpio.c | 51 +++++++++++++++++++++++----------- 3 files changed, 50 insertions(+), 20 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 4e125d8904a..9a93d2bb8f6 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -461,6 +461,12 @@ void ath9k_queue_reset(struct ath_softc *sc, enum ath_reset_type type); /* BTCOEX */ /**********/ +#define ATH_DUMP_BTCOEX(_s, _val) \ + do { \ + len += snprintf(buf + len, size - len, \ + "%20s : %10d\n", _s, (_val)); \ + } while (0) + enum bt_op_flags { BT_OP_PRIORITY_DETECTED, BT_OP_SCAN, @@ -494,7 +500,7 @@ void ath9k_btcoex_timer_pause(struct ath_softc *sc); void ath9k_btcoex_handle_interrupt(struct ath_softc *sc, u32 status); u16 ath9k_btcoex_aggr_limit(struct ath_softc *sc, u32 max_4ms_framelen); void ath9k_btcoex_stop_gen_timer(struct ath_softc *sc); -int ath9k_dump_btcoex(struct ath_softc *sc, u8 *buf, u32 len, u32 size); +int ath9k_dump_btcoex(struct ath_softc *sc, u8 *buf, u32 size); #else static inline int ath9k_init_btcoex(struct ath_softc *sc) { @@ -521,8 +527,7 @@ static inline u16 ath9k_btcoex_aggr_limit(struct ath_softc *sc, static inline void ath9k_btcoex_stop_gen_timer(struct ath_softc *sc) { } -static inline int ath9k_dump_btcoex(struct ath_softc *sc, u8 *buf, - u32 len, u32 size) +static inline int ath9k_dump_btcoex(struct ath_softc *sc, u8 *buf, u32 size) { return 0; } diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index a8be94b2a53..585aee47860 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -1599,8 +1599,14 @@ static ssize_t read_file_btcoex(struct file *file, char __user *user_buf, if (buf == NULL) return -ENOMEM; - len = ath9k_dump_btcoex(sc, buf, len, size); + if (!sc->sc_ah->common.btcoex_enabled) { + len = snprintf(buf, size, "%s\n", + "BTCOEX is disabled"); + goto exit; + } + len = ath9k_dump_btcoex(sc, buf, size); +exit: retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); kfree(buf); diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c index a8ea57b9f49..4236df8ffe6 100644 --- a/drivers/net/wireless/ath/ath9k/gpio.c +++ b/drivers/net/wireless/ath/ath9k/gpio.c @@ -494,35 +494,31 @@ int ath9k_init_btcoex(struct ath_softc *sc) return 0; } -int ath9k_dump_btcoex(struct ath_softc *sc, u8 *buf, u32 len, u32 size) +static int ath9k_dump_mci_btcoex(struct ath_softc *sc, u8 *buf, u32 size) { -#define ATH_DUMP_BTCOEX(_s, _val) \ - do { \ - len += snprintf(buf + len, size - len, \ - "%20s : %10d\n", _s, (_val)); \ - } while (0) - struct ath_btcoex *btcoex = &sc->btcoex; struct ath_mci_profile *mci = &btcoex->mci; struct ath_hw *ah = sc->sc_ah; struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw; + u32 len = 0; int i; ATH_DUMP_BTCOEX("Total BT profiles", NUM_PROF(mci)); - ATH_DUMP_BTCOEX("Number of MGMT", mci->num_mgmt); - ATH_DUMP_BTCOEX("Number of SCO", mci->num_sco); - ATH_DUMP_BTCOEX("Number of A2DP", mci->num_a2dp); - ATH_DUMP_BTCOEX("Number of HID", mci->num_hid); - ATH_DUMP_BTCOEX("Number of PAN", mci->num_pan); - ATH_DUMP_BTCOEX("Number of ACL", mci->num_other_acl); - ATH_DUMP_BTCOEX("Number of BDR", mci->num_bdr); + ATH_DUMP_BTCOEX("MGMT", mci->num_mgmt); + ATH_DUMP_BTCOEX("SCO", mci->num_sco); + ATH_DUMP_BTCOEX("A2DP", mci->num_a2dp); + ATH_DUMP_BTCOEX("HID", mci->num_hid); + ATH_DUMP_BTCOEX("PAN", mci->num_pan); + ATH_DUMP_BTCOEX("ACL", mci->num_other_acl); + ATH_DUMP_BTCOEX("BDR", mci->num_bdr); ATH_DUMP_BTCOEX("Aggr. Limit", mci->aggr_limit); ATH_DUMP_BTCOEX("Stomp Type", btcoex->bt_stomp_type); ATH_DUMP_BTCOEX("BTCoex Period (msec)", btcoex->btcoex_period); ATH_DUMP_BTCOEX("Duty Cycle", btcoex->duty_cycle); ATH_DUMP_BTCOEX("BT Wait time", btcoex->bt_wait_time); ATH_DUMP_BTCOEX("Concurrent Tx", btcoex_hw->mci.concur_tx); - ATH_DUMP_BTCOEX("Concur RSSI count", btcoex->rssi_count); + ATH_DUMP_BTCOEX("Concurrent RSSI cnt", btcoex->rssi_count); + len += snprintf(buf + len, size - len, "BT Weights: "); for (i = 0; i < AR9300_NUM_BT_WEIGHTS; i++) len += snprintf(buf + len, size - len, "%08x ", @@ -537,9 +533,32 @@ int ath9k_dump_btcoex(struct ath_softc *sc, u8 *buf, u32 len, u32 size) for (i = 0; i < ATH_BTCOEX_STOMP_MAX; i++) len += snprintf(buf + len, size - len, "%08x ", btcoex_hw->tx_prio[i]); + len += snprintf(buf + len, size - len, "\n"); -#undef ATH_DUMP_BTCOEX return len; } + +static int ath9k_dump_legacy_btcoex(struct ath_softc *sc, u8 *buf, u32 size) +{ + + struct ath_btcoex *btcoex = &sc->btcoex; + u32 len = 0; + + ATH_DUMP_BTCOEX("Stomp Type", btcoex->bt_stomp_type); + ATH_DUMP_BTCOEX("BTCoex Period (msec)", btcoex->btcoex_period); + ATH_DUMP_BTCOEX("Duty Cycle", btcoex->duty_cycle); + ATH_DUMP_BTCOEX("BT Wait time", btcoex->bt_wait_time); + + return len; +} + +int ath9k_dump_btcoex(struct ath_softc *sc, u8 *buf, u32 size) +{ + if (ath9k_hw_mci_is_enabled(sc->sc_ah)) + return ath9k_dump_mci_btcoex(sc, buf, size); + else + return ath9k_dump_legacy_btcoex(sc, buf, size); +} + #endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */ -- cgit v1.2.3-18-g5258 From ca90ef443cab31a5481d8a7f85514d28368fef44 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Tue, 20 Nov 2012 18:29:59 +0530 Subject: ath9k: Process FATAL interrupts at first FATAL and WATCHDOG interrupts should be processed first followed by others. Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/main.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 9594b6fcdf0..e59d8e3fcbc 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -494,17 +494,6 @@ irqreturn_t ath_isr(int irq, void *dev) if (status & SCHED_INTR) sched = true; -#ifdef CONFIG_PM_SLEEP - if (status & ATH9K_INT_BMISS) { - if (atomic_read(&sc->wow_sleep_proc_intr) == 0) { - ath_dbg(common, ANY, "during WoW we got a BMISS\n"); - atomic_inc(&sc->wow_got_bmiss_intr); - atomic_dec(&sc->wow_sleep_proc_intr); - } - ath_dbg(common, INTERRUPT, "beacon miss interrupt\n"); - } -#endif - /* * If a FATAL or RXORN interrupt is received, we have to reset the * chip immediately. @@ -523,7 +512,15 @@ irqreturn_t ath_isr(int irq, void *dev) goto chip_reset; } - +#ifdef CONFIG_PM_SLEEP + if (status & ATH9K_INT_BMISS) { + if (atomic_read(&sc->wow_sleep_proc_intr) == 0) { + ath_dbg(common, ANY, "during WoW we got a BMISS\n"); + atomic_inc(&sc->wow_got_bmiss_intr); + atomic_dec(&sc->wow_sleep_proc_intr); + } + } +#endif if (status & ATH9K_INT_SWBA) tasklet_schedule(&sc->bcon_tasklet); -- cgit v1.2.3-18-g5258 From b88083bfb37297330240a478bef76316ee3f1b9b Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Tue, 20 Nov 2012 18:30:00 +0530 Subject: ath9k: Fix MCI reset in BT cal_req This patch reverts the commit "ath9k_hw: Wait BT calibration to complete" and bail out from MCI interrupt routine for chip reset. The above commit stalls the WLAN TCP traffic while bringing up and down the BT interface iteratively. Fixing this properly by queueing up chip reset and bailing out properly from tasklet routine. Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_mci.c | 1 - drivers/net/wireless/ath/ath9k/debug.c | 3 +++ drivers/net/wireless/ath/ath9k/debug.h | 1 + drivers/net/wireless/ath/ath9k/mci.c | 21 +++------------------ 4 files changed, 7 insertions(+), 19 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mci.c b/drivers/net/wireless/ath/ath9k/ar9003_mci.c index 42b4412d679..8dd069259e7 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mci.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_mci.c @@ -714,7 +714,6 @@ bool ar9003_mci_start_reset(struct ath_hw *ah, struct ath9k_channel *chan) return true; } -EXPORT_SYMBOL(ar9003_mci_start_reset); int ar9003_mci_end_reset(struct ath_hw *ah, struct ath9k_channel *chan, struct ath9k_hw_cal_data *caldata) diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 585aee47860..eed0b9ab8fe 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -837,6 +837,9 @@ static ssize_t read_file_reset(struct file *file, char __user *user_buf, len += snprintf(buf + len, sizeof(buf) - len, "%17s: %2d\n", "PLL RX Hang", sc->debug.stats.reset[RESET_TYPE_PLL_HANG]); + len += snprintf(buf + len, sizeof(buf) - len, + "%17s: %2d\n", "MCI Reset", + sc->debug.stats.reset[RESET_TYPE_MCI]); if (len > sizeof(buf)) len = sizeof(buf); diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h index 2ed9785a38f..61341cda131 100644 --- a/drivers/net/wireless/ath/ath9k/debug.h +++ b/drivers/net/wireless/ath/ath9k/debug.h @@ -41,6 +41,7 @@ enum ath_reset_type { RESET_TYPE_PLL_HANG, RESET_TYPE_MAC_HANG, RESET_TYPE_BEACON_STUCK, + RESET_TYPE_MCI, __RESET_TYPE_MAX }; diff --git a/drivers/net/wireless/ath/ath9k/mci.c b/drivers/net/wireless/ath/ath9k/mci.c index 0dd2cbb52d6..ece192d7735 100644 --- a/drivers/net/wireless/ath/ath9k/mci.c +++ b/drivers/net/wireless/ath/ath9k/mci.c @@ -207,23 +207,6 @@ skip_tuning: ath9k_btcoex_timer_resume(sc); } -static void ath_mci_wait_btcal_done(struct ath_softc *sc) -{ - struct ath_hw *ah = sc->sc_ah; - - /* Stop tx & rx */ - ieee80211_stop_queues(sc->hw); - ath_stoprecv(sc); - ath_drain_all_txq(sc, false); - - /* Wait for cal done */ - ar9003_mci_start_reset(ah, ah->curchan); - - /* Resume tx & rx */ - ath_startrecv(sc); - ieee80211_wake_queues(sc->hw); -} - static void ath_mci_cal_msg(struct ath_softc *sc, u8 opcode, u8 *rx_payload) { struct ath_hw *ah = sc->sc_ah; @@ -235,7 +218,7 @@ static void ath_mci_cal_msg(struct ath_softc *sc, u8 opcode, u8 *rx_payload) case MCI_GPM_BT_CAL_REQ: if (mci_hw->bt_state == MCI_BT_AWAKE) { mci_hw->bt_state = MCI_BT_CAL_START; - ath_mci_wait_btcal_done(sc); + ath9k_queue_reset(sc, RESET_TYPE_MCI); } ath_dbg(common, MCI, "MCI State : %d\n", mci_hw->bt_state); break; @@ -578,6 +561,8 @@ void ath_mci_intr(struct ath_softc *sc) mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_GPM; while (more_data == MCI_GPM_MORE) { + if (test_bit(SC_OP_HW_RESET, &sc->sc_flags)) + return; pgpm = mci->gpm_buf.bf_addr; offset = ar9003_mci_get_next_gpm_offset(ah, false, -- cgit v1.2.3-18-g5258 From 2884561a6472d6f9c960ccf2250a72ca058167a1 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Tue, 20 Nov 2012 18:30:01 +0530 Subject: ath9k: stomp audio profiles on weak signal strength On lower WLAN signal strength, WLAN downlink traffic might suffer from retransmissions. At the mean time, playing SCO/A2DP profiles is affecting WLAN stability. In such scenario, by stomping SCO/A2DP BT traffic completely for a BTCOEX period, gives WLAN traffic an oppertunity to recover PHY rate. It also improves WLAN stability at lower RSSI without sacificing BT traffic. Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 1 + drivers/net/wireless/ath/ath9k/btcoex.c | 1 + drivers/net/wireless/ath/ath9k/btcoex.h | 1 + drivers/net/wireless/ath/ath9k/gpio.c | 5 ++++- drivers/net/wireless/ath/ath9k/mci.c | 18 ++++++++++++++++++ 5 files changed, 25 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 9a93d2bb8f6..04fa5f350e8 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -488,6 +488,7 @@ struct ath_btcoex { int rssi_count; struct ath_gen_timer *no_stomp_timer; /* Timer for no BT stomping */ struct ath_mci_profile mci; + u8 stomp_audio; }; #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT diff --git a/drivers/net/wireless/ath/ath9k/btcoex.c b/drivers/net/wireless/ath/ath9k/btcoex.c index c90e9bc4b02..9963b0bf9f7 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.c +++ b/drivers/net/wireless/ath/ath9k/btcoex.c @@ -49,6 +49,7 @@ static const u32 mci_wlan_weights[ATH_BTCOEX_STOMP_MAX] { 0x01017d01, 0x3b3b3b01, 0x3b3b3b01, 0x3b3b3b3b }, /* STOMP_LOW */ { 0x01017d01, 0x01010101, 0x01010101, 0x01010101 }, /* STOMP_NONE */ { 0x01017d01, 0x013b0101, 0x3b3b0101, 0x3b3b013b }, /* STOMP_LOW_FTP */ + { 0xffffff01, 0xffffffff, 0xffffff01, 0xffffffff }, /* STOMP_AUDIO */ }; void ath9k_hw_init_btcoex_hw(struct ath_hw *ah, int qnum) diff --git a/drivers/net/wireless/ath/ath9k/btcoex.h b/drivers/net/wireless/ath/ath9k/btcoex.h index 2f84ab273d0..6de26ea5d5f 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.h +++ b/drivers/net/wireless/ath/ath9k/btcoex.h @@ -50,6 +50,7 @@ enum ath_stomp_type { ATH_BTCOEX_STOMP_LOW, ATH_BTCOEX_STOMP_NONE, ATH_BTCOEX_STOMP_LOW_FTP, + ATH_BTCOEX_STOMP_AUDIO, ATH_BTCOEX_STOMP_MAX }; diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c index 4236df8ffe6..7b39cc14662 100644 --- a/drivers/net/wireless/ath/ath9k/gpio.c +++ b/drivers/net/wireless/ath/ath9k/gpio.c @@ -247,6 +247,9 @@ static void ath_btcoex_period_timer(unsigned long data) stomp_type = ATH_BTCOEX_STOMP_ALL; timer_period = btcoex->btscan_no_stomp; } + } else if (btcoex->stomp_audio >= 5) { + stomp_type = ATH_BTCOEX_STOMP_AUDIO; + btcoex->stomp_audio = 0; } ath9k_hw_btcoex_bt_stomp(ah, stomp_type); @@ -295,7 +298,7 @@ static void ath_btcoex_no_stomp_timer(void *arg) (!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI) && test_bit(BT_OP_SCAN, &btcoex->op_flags))) ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_NONE); - else if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_ALL) + else if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_ALL) ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_LOW); ath9k_hw_btcoex_enable(ah); diff --git a/drivers/net/wireless/ath/ath9k/mci.c b/drivers/net/wireless/ath/ath9k/mci.c index ece192d7735..706378ea3ba 100644 --- a/drivers/net/wireless/ath/ath9k/mci.c +++ b/drivers/net/wireless/ath/ath9k/mci.c @@ -729,12 +729,30 @@ void ath9k_mci_set_txpower(struct ath_softc *sc, bool setchannel, ath9k_hw_set_txpowerlimit(ah, sc->config.txpowlimit, false); } +static void ath9k_mci_stomp_audio(struct ath_softc *sc) +{ + struct ath_hw *ah = sc->sc_ah; + struct ath_btcoex *btcoex = &sc->btcoex; + struct ath_mci_profile *mci = &btcoex->mci; + + if (!mci->num_sco && !mci->num_a2dp) + return; + + if (ah->stats.avgbrssi > 25) { + btcoex->stomp_audio = 0; + return; + } + + btcoex->stomp_audio++; +} void ath9k_mci_update_rssi(struct ath_softc *sc) { struct ath_hw *ah = sc->sc_ah; struct ath_btcoex *btcoex = &sc->btcoex; struct ath9k_hw_mci *mci_hw = &sc->sc_ah->btcoex_hw.mci; + ath9k_mci_stomp_audio(sc); + if (!(mci_hw->config & ATH_MCI_CONFIG_CONCUR_TX)) return; -- cgit v1.2.3-18-g5258 From bea843c73854becf998047a83af22a90de3fd19b Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 21 Nov 2012 18:13:10 +0530 Subject: ath9k/ath9k_htc: Remove WME macros Use the macros provided by mac80211 and remove redundant declarations inside the drivers. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 16 ++++----- drivers/net/wireless/ath/ath9k/beacon.c | 2 +- drivers/net/wireless/ath/ath9k/common.h | 7 ---- drivers/net/wireless/ath/ath9k/debug.c | 44 ++++++++++++------------- drivers/net/wireless/ath/ath9k/gpio.c | 2 +- drivers/net/wireless/ath/ath9k/htc.h | 4 +-- drivers/net/wireless/ath/ath9k/htc_drv_beacon.c | 2 +- drivers/net/wireless/ath/ath9k/htc_drv_debug.c | 8 ++--- drivers/net/wireless/ath/ath9k/htc_drv_gpio.c | 2 +- drivers/net/wireless/ath/ath9k/htc_drv_init.c | 8 ++--- drivers/net/wireless/ath/ath9k/htc_drv_main.c | 4 +-- drivers/net/wireless/ath/ath9k/htc_drv_txrx.c | 26 +++++++-------- drivers/net/wireless/ath/ath9k/init.c | 2 +- drivers/net/wireless/ath/ath9k/link.c | 2 +- drivers/net/wireless/ath/ath9k/main.c | 26 +++++++-------- drivers/net/wireless/ath/ath9k/xmit.c | 10 +++--- 16 files changed, 79 insertions(+), 86 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 04fa5f350e8..3c1cebe55f6 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -129,10 +129,10 @@ void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd, #define ATH_TXMAXTRY 13 #define TID_TO_WME_AC(_tid) \ - ((((_tid) == 0) || ((_tid) == 3)) ? WME_AC_BE : \ - (((_tid) == 1) || ((_tid) == 2)) ? WME_AC_BK : \ - (((_tid) == 4) || ((_tid) == 5)) ? WME_AC_VI : \ - WME_AC_VO) + ((((_tid) == 0) || ((_tid) == 3)) ? IEEE80211_AC_BE : \ + (((_tid) == 1) || ((_tid) == 2)) ? IEEE80211_AC_BK : \ + (((_tid) == 4) || ((_tid) == 5)) ? IEEE80211_AC_VI : \ + IEEE80211_AC_VO) #define ATH_AGGR_DELIM_SZ 4 #define ATH_AGGR_MINPLEN 256 /* in bytes, minimum packet length */ @@ -265,7 +265,7 @@ struct ath_node { struct ieee80211_sta *sta; /* station struct we're part of */ struct ieee80211_vif *vif; /* interface with which we're associated */ struct ath_atx_tid tid[WME_NUM_TID]; - struct ath_atx_ac ac[WME_NUM_AC]; + struct ath_atx_ac ac[IEEE80211_NUM_ACS]; int ps_key; u16 maxampdu; @@ -299,9 +299,9 @@ struct ath_tx { struct list_head txbuf; struct ath_txq txq[ATH9K_NUM_TX_QUEUES]; struct ath_descdma txdma; - struct ath_txq *txq_map[WME_NUM_AC]; - u32 txq_max_pending[WME_NUM_AC]; - u16 max_aggr_framelen[WME_NUM_AC][4][32]; + struct ath_txq *txq_map[IEEE80211_NUM_ACS]; + u32 txq_max_pending[IEEE80211_NUM_ACS]; + u16 max_aggr_framelen[IEEE80211_NUM_ACS][4][32]; }; struct ath_rx_edma { diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 1b48414dca9..531fffd801a 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -46,7 +46,7 @@ static void ath9k_beaconq_config(struct ath_softc *sc) qi.tqi_cwmax = 0; } else { /* Adhoc mode; important thing is to use 2x cwmin. */ - txq = sc->tx.txq_map[WME_AC_BE]; + txq = sc->tx.txq_map[IEEE80211_AC_BE]; ath9k_hw_get_txq_props(ah, txq->axq_qnum, &qi_be); qi.tqi_aifs = qi_be.tqi_aifs; if (ah->slottime == ATH9K_SLOT_TIME_20) diff --git a/drivers/net/wireless/ath/ath9k/common.h b/drivers/net/wireless/ath/ath9k/common.h index ad14fecc76c..76b54390031 100644 --- a/drivers/net/wireless/ath/ath9k/common.h +++ b/drivers/net/wireless/ath/ath9k/common.h @@ -28,13 +28,6 @@ #define WME_MAX_BA WME_BA_BMP_SIZE #define ATH_TID_MAX_BUFS (2 * WME_MAX_BA) -/* These must match mac80211 skb queue mapping numbers */ -#define WME_AC_VO 0 -#define WME_AC_VI 1 -#define WME_AC_BE 2 -#define WME_AC_BK 3 -#define WME_NUM_AC 4 - #define ATH_RSSI_DUMMY_MARKER 0x127 #define ATH_RSSI_LPF_LEN 10 #define RSSI_LPF_THRESHOLD -20 diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index eed0b9ab8fe..957e38646fd 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -517,10 +517,10 @@ static const struct file_operations fops_interrupt = { do { \ len += snprintf(buf + len, size - len, \ "%s%13u%11u%10u%10u\n", str, \ - sc->debug.stats.txstats[PR_QNUM(WME_AC_BE)].elem, \ - sc->debug.stats.txstats[PR_QNUM(WME_AC_BK)].elem, \ - sc->debug.stats.txstats[PR_QNUM(WME_AC_VI)].elem, \ - sc->debug.stats.txstats[PR_QNUM(WME_AC_VO)].elem); \ + sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_BE)].elem, \ + sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_BK)].elem, \ + sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_VI)].elem, \ + sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_VO)].elem); \ if (len >= size) \ goto done; \ } while(0) @@ -529,10 +529,10 @@ static const struct file_operations fops_interrupt = { do { \ len += snprintf(buf + len, size - len, \ "%s%13u%11u%10u%10u\n", str, \ - (unsigned int)(sc->tx.txq_map[WME_AC_BE]->elem), \ - (unsigned int)(sc->tx.txq_map[WME_AC_BK]->elem), \ - (unsigned int)(sc->tx.txq_map[WME_AC_VI]->elem), \ - (unsigned int)(sc->tx.txq_map[WME_AC_VO]->elem)); \ + (unsigned int)(sc->tx.txq_map[IEEE80211_AC_BE]->elem), \ + (unsigned int)(sc->tx.txq_map[IEEE80211_AC_BK]->elem), \ + (unsigned int)(sc->tx.txq_map[IEEE80211_AC_VI]->elem), \ + (unsigned int)(sc->tx.txq_map[IEEE80211_AC_VO]->elem)); \ if (len >= size) \ goto done; \ } while(0) @@ -541,10 +541,10 @@ do { \ do { \ len += snprintf(buf + len, size - len, \ "%s%13i%11i%10i%10i\n", str, \ - list_empty(&sc->tx.txq_map[WME_AC_BE]->elem), \ - list_empty(&sc->tx.txq_map[WME_AC_BK]->elem), \ - list_empty(&sc->tx.txq_map[WME_AC_VI]->elem), \ - list_empty(&sc->tx.txq_map[WME_AC_VO]->elem)); \ + list_empty(&sc->tx.txq_map[IEEE80211_AC_BE]->elem), \ + list_empty(&sc->tx.txq_map[IEEE80211_AC_BK]->elem), \ + list_empty(&sc->tx.txq_map[IEEE80211_AC_VI]->elem), \ + list_empty(&sc->tx.txq_map[IEEE80211_AC_VO]->elem)); \ if (len >= size) \ goto done; \ } while (0) @@ -593,10 +593,10 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf, PR("TX-Failed: ", txfailed); len += snprintf(buf + len, size - len, "%s%11p%11p%10p%10p\n", "txq-memory-address:", - sc->tx.txq_map[WME_AC_BE], - sc->tx.txq_map[WME_AC_BK], - sc->tx.txq_map[WME_AC_VI], - sc->tx.txq_map[WME_AC_VO]); + sc->tx.txq_map[IEEE80211_AC_BE], + sc->tx.txq_map[IEEE80211_AC_BK], + sc->tx.txq_map[IEEE80211_AC_VI], + sc->tx.txq_map[IEEE80211_AC_VO]); if (len >= size) goto done; @@ -617,7 +617,7 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf, } /* Print out more detailed queue-info */ - for (i = 0; i <= WME_AC_BK; i++) { + for (i = 0; i <= IEEE80211_AC_BK; i++) { struct ath_txq *txq = &(sc->tx.txq[i]); struct ath_atx_ac *ac; struct ath_atx_tid *tid; @@ -695,7 +695,7 @@ static ssize_t read_file_stations(struct file *file, char __user *user_buf, goto done; } - for (q = 0; q < WME_NUM_AC; q++) { + for (q = 0; q < IEEE80211_NUM_ACS; q++) { struct ath_atx_ac *ac = &(an->ac[q]); len += snprintf(buf + len, size - len, " ac: %p %s %i %p\n", @@ -1648,13 +1648,13 @@ int ath9k_init_debug(struct ath_hw *ah) debugfs_create_file("xmit", S_IRUSR, sc->debug.debugfs_phy, sc, &fops_xmit); debugfs_create_u32("qlen_bk", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, - &sc->tx.txq_max_pending[WME_AC_BK]); + &sc->tx.txq_max_pending[IEEE80211_AC_BK]); debugfs_create_u32("qlen_be", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, - &sc->tx.txq_max_pending[WME_AC_BE]); + &sc->tx.txq_max_pending[IEEE80211_AC_BE]); debugfs_create_u32("qlen_vi", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, - &sc->tx.txq_max_pending[WME_AC_VI]); + &sc->tx.txq_max_pending[IEEE80211_AC_VI]); debugfs_create_u32("qlen_vo", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, - &sc->tx.txq_max_pending[WME_AC_VO]); + &sc->tx.txq_max_pending[IEEE80211_AC_VO]); debugfs_create_file("stations", S_IRUSR, sc->debug.debugfs_phy, sc, &fops_stations); debugfs_create_file("misc", S_IRUSR, sc->debug.debugfs_phy, sc, diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c index 7b39cc14662..4b412aaf4f3 100644 --- a/drivers/net/wireless/ath/ath9k/gpio.c +++ b/drivers/net/wireless/ath/ath9k/gpio.c @@ -474,7 +474,7 @@ int ath9k_init_btcoex(struct ath_softc *sc) r = ath_init_btcoex_timer(sc); if (r) return -1; - txq = sc->tx.txq_map[WME_AC_BE]; + txq = sc->tx.txq_map[IEEE80211_AC_BE]; ath9k_hw_init_btcoex_hw(sc->sc_ah, txq->axq_qnum); sc->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW; if (ath9k_hw_mci_is_enabled(ah)) { diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index b30596fcf73..96bfb18078f 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -331,7 +331,7 @@ struct ath_tx_stats { u32 skb_success; u32 skb_failed; u32 cab_queued; - u32 queue_stats[WME_NUM_AC]; + u32 queue_stats[IEEE80211_NUM_ACS]; }; struct ath_rx_stats { @@ -493,7 +493,7 @@ struct ath9k_htc_priv { int beaconq; int cabq; - int hwq_map[WME_NUM_AC]; + int hwq_map[IEEE80211_NUM_ACS]; #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT struct ath_btcoex btcoex; diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c index 1318d79f5c4..d0ce1f5bba1 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c @@ -33,7 +33,7 @@ void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv) qi.tqi_cwmin = 0; qi.tqi_cwmax = 0; } else if (priv->ah->opmode == NL80211_IFTYPE_ADHOC) { - int qnum = priv->hwq_map[WME_AC_BE]; + int qnum = priv->hwq_map[IEEE80211_AC_BE]; ath9k_hw_get_txq_props(ah, qnum, &qi_be); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_debug.c b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c index 3035deb7a0c..87110de577e 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_debug.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c @@ -218,16 +218,16 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf, len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", "BE queued", - priv->debug.tx_stats.queue_stats[WME_AC_BE]); + priv->debug.tx_stats.queue_stats[IEEE80211_AC_BE]); len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", "BK queued", - priv->debug.tx_stats.queue_stats[WME_AC_BK]); + priv->debug.tx_stats.queue_stats[IEEE80211_AC_BK]); len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", "VI queued", - priv->debug.tx_stats.queue_stats[WME_AC_VI]); + priv->debug.tx_stats.queue_stats[IEEE80211_AC_VI]); len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", "VO queued", - priv->debug.tx_stats.queue_stats[WME_AC_VO]); + priv->debug.tx_stats.queue_stats[IEEE80211_AC_VO]); if (len > sizeof(buf)) len = sizeof(buf); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c index 0eacfc13c91..105582d6b71 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c @@ -207,7 +207,7 @@ void ath9k_htc_init_btcoex(struct ath9k_htc_priv *priv, char *product) priv->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW; ath9k_hw_btcoex_init_3wire(priv->ah); ath_htc_init_btcoex_work(priv); - qnum = priv->hwq_map[WME_AC_BE]; + qnum = priv->hwq_map[IEEE80211_AC_BE]; ath9k_hw_init_btcoex_hw(priv->ah, qnum); break; default: diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index 5ecf1287ddd..05d5ba66cac 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -549,20 +549,20 @@ static int ath9k_init_queues(struct ath9k_htc_priv *priv) goto err; } - if (!ath9k_htc_txq_setup(priv, WME_AC_BE)) { + if (!ath9k_htc_txq_setup(priv, IEEE80211_AC_BE)) { ath_err(common, "Unable to setup xmit queue for BE traffic\n"); goto err; } - if (!ath9k_htc_txq_setup(priv, WME_AC_BK)) { + if (!ath9k_htc_txq_setup(priv, IEEE80211_AC_BK)) { ath_err(common, "Unable to setup xmit queue for BK traffic\n"); goto err; } - if (!ath9k_htc_txq_setup(priv, WME_AC_VI)) { + if (!ath9k_htc_txq_setup(priv, IEEE80211_AC_VI)) { ath_err(common, "Unable to setup xmit queue for VI traffic\n"); goto err; } - if (!ath9k_htc_txq_setup(priv, WME_AC_VO)) { + if (!ath9k_htc_txq_setup(priv, IEEE80211_AC_VO)) { ath_err(common, "Unable to setup xmit queue for VO traffic\n"); goto err; } diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index 02cce95331d..9c07a8fa513 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -1349,7 +1349,7 @@ static int ath9k_htc_conf_tx(struct ieee80211_hw *hw, struct ath9k_tx_queue_info qi; int ret = 0, qnum; - if (queue >= WME_NUM_AC) + if (queue >= IEEE80211_NUM_ACS) return 0; mutex_lock(&priv->mutex); @@ -1376,7 +1376,7 @@ static int ath9k_htc_conf_tx(struct ieee80211_hw *hw, } if ((priv->ah->opmode == NL80211_IFTYPE_ADHOC) && - (qnum == priv->hwq_map[WME_AC_BE])) + (qnum == priv->hwq_map[IEEE80211_AC_BE])) ath9k_htc_beaconq_config(priv); out: ath9k_htc_ps_restore(priv); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c index 06cdcb772d7..3a22d17a261 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c @@ -21,10 +21,10 @@ /******/ static const int subtype_txq_to_hwq[] = { - [WME_AC_BE] = ATH_TXQ_AC_BE, - [WME_AC_BK] = ATH_TXQ_AC_BK, - [WME_AC_VI] = ATH_TXQ_AC_VI, - [WME_AC_VO] = ATH_TXQ_AC_VO, + [IEEE80211_AC_BE] = ATH_TXQ_AC_BE, + [IEEE80211_AC_BK] = ATH_TXQ_AC_BK, + [IEEE80211_AC_VI] = ATH_TXQ_AC_VI, + [IEEE80211_AC_VO] = ATH_TXQ_AC_VO, }; #define ATH9K_HTC_INIT_TXQ(subtype) do { \ @@ -41,15 +41,15 @@ int get_hw_qnum(u16 queue, int *hwq_map) { switch (queue) { case 0: - return hwq_map[WME_AC_VO]; + return hwq_map[IEEE80211_AC_VO]; case 1: - return hwq_map[WME_AC_VI]; + return hwq_map[IEEE80211_AC_VI]; case 2: - return hwq_map[WME_AC_BE]; + return hwq_map[IEEE80211_AC_BE]; case 3: - return hwq_map[WME_AC_BK]; + return hwq_map[IEEE80211_AC_BK]; default: - return hwq_map[WME_AC_BE]; + return hwq_map[IEEE80211_AC_BE]; } } @@ -106,20 +106,20 @@ static inline enum htc_endpoint_id get_htc_epid(struct ath9k_htc_priv *priv, switch (qnum) { case 0: - TX_QSTAT_INC(WME_AC_VO); + TX_QSTAT_INC(IEEE80211_AC_VO); epid = priv->data_vo_ep; break; case 1: - TX_QSTAT_INC(WME_AC_VI); + TX_QSTAT_INC(IEEE80211_AC_VI); epid = priv->data_vi_ep; break; case 2: - TX_QSTAT_INC(WME_AC_BE); + TX_QSTAT_INC(IEEE80211_AC_BE); epid = priv->data_be_ep; break; case 3: default: - TX_QSTAT_INC(WME_AC_BK); + TX_QSTAT_INC(IEEE80211_AC_BK); epid = priv->data_bk_ep; break; } diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 546bae93647..345a01af542 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -435,7 +435,7 @@ static int ath9k_init_queues(struct ath_softc *sc) sc->config.cabqReadytime = ATH_CABQ_READY_TIME; ath_cabq_update(sc); - for (i = 0; i < WME_NUM_AC; i++) { + for (i = 0; i < IEEE80211_NUM_ACS; i++) { sc->tx.txq_map[i] = ath_txq_setup(sc, ATH9K_TX_QUEUE_DATA, i); sc->tx.txq_map[i]->mac80211_qnum = i; sc->tx.txq_max_pending[i] = ATH_MAX_QDEPTH; diff --git a/drivers/net/wireless/ath/ath9k/link.c b/drivers/net/wireless/ath/ath9k/link.c index 223b9693527..227fdb81481 100644 --- a/drivers/net/wireless/ath/ath9k/link.c +++ b/drivers/net/wireless/ath/ath9k/link.c @@ -211,7 +211,7 @@ static bool ath_paprd_send_frame(struct ath_softc *sc, struct sk_buff *skb, int int time_left; memset(&txctl, 0, sizeof(txctl)); - txctl.txq = sc->tx.txq_map[WME_AC_BE]; + txctl.txq = sc->tx.txq_map[IEEE80211_AC_BE]; memset(tx_info, 0, sizeof(*tx_info)); tx_info->band = hw->conf.channel->band; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index e59d8e3fcbc..f8b3cacaeac 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1325,7 +1325,7 @@ static int ath9k_conf_tx(struct ieee80211_hw *hw, struct ath9k_tx_queue_info qi; int ret = 0; - if (queue >= WME_NUM_AC) + if (queue >= IEEE80211_NUM_ACS) return 0; txq = sc->tx.txq_map[queue]; @@ -1956,10 +1956,10 @@ static int ath9k_get_et_sset_count(struct ieee80211_hw *hw, #define PR_QNUM(_n) (sc->tx.txq_map[_n]->axq_qnum) #define AWDATA(elem) \ do { \ - data[i++] = sc->debug.stats.txstats[PR_QNUM(WME_AC_BE)].elem; \ - data[i++] = sc->debug.stats.txstats[PR_QNUM(WME_AC_BK)].elem; \ - data[i++] = sc->debug.stats.txstats[PR_QNUM(WME_AC_VI)].elem; \ - data[i++] = sc->debug.stats.txstats[PR_QNUM(WME_AC_VO)].elem; \ + data[i++] = sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_BE)].elem; \ + data[i++] = sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_BK)].elem; \ + data[i++] = sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_VI)].elem; \ + data[i++] = sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_VO)].elem; \ } while (0) #define AWDATA_RX(elem) \ @@ -1974,14 +1974,14 @@ static void ath9k_get_et_stats(struct ieee80211_hw *hw, struct ath_softc *sc = hw->priv; int i = 0; - data[i++] = (sc->debug.stats.txstats[PR_QNUM(WME_AC_BE)].tx_pkts_all + - sc->debug.stats.txstats[PR_QNUM(WME_AC_BK)].tx_pkts_all + - sc->debug.stats.txstats[PR_QNUM(WME_AC_VI)].tx_pkts_all + - sc->debug.stats.txstats[PR_QNUM(WME_AC_VO)].tx_pkts_all); - data[i++] = (sc->debug.stats.txstats[PR_QNUM(WME_AC_BE)].tx_bytes_all + - sc->debug.stats.txstats[PR_QNUM(WME_AC_BK)].tx_bytes_all + - sc->debug.stats.txstats[PR_QNUM(WME_AC_VI)].tx_bytes_all + - sc->debug.stats.txstats[PR_QNUM(WME_AC_VO)].tx_bytes_all); + data[i++] = (sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_BE)].tx_pkts_all + + sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_BK)].tx_pkts_all + + sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_VI)].tx_pkts_all + + sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_VO)].tx_pkts_all); + data[i++] = (sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_BE)].tx_bytes_all + + sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_BK)].tx_bytes_all + + sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_VI)].tx_bytes_all + + sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_VO)].tx_bytes_all); AWDATA_RX(rx_pkts_all); AWDATA_RX(rx_bytes_all); diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 741918a2027..ae7f2897c1a 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1354,10 +1354,10 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype) struct ath_hw *ah = sc->sc_ah; struct ath9k_tx_queue_info qi; static const int subtype_txq_to_hwq[] = { - [WME_AC_BE] = ATH_TXQ_AC_BE, - [WME_AC_BK] = ATH_TXQ_AC_BK, - [WME_AC_VI] = ATH_TXQ_AC_VI, - [WME_AC_VO] = ATH_TXQ_AC_VO, + [IEEE80211_AC_BE] = ATH_TXQ_AC_BE, + [IEEE80211_AC_BK] = ATH_TXQ_AC_BK, + [IEEE80211_AC_VI] = ATH_TXQ_AC_VI, + [IEEE80211_AC_VO] = ATH_TXQ_AC_VO, }; int axq_qnum, i; @@ -2464,7 +2464,7 @@ void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an) } for (acno = 0, ac = &an->ac[acno]; - acno < WME_NUM_AC; acno++, ac++) { + acno < IEEE80211_NUM_ACS; acno++, ac++) { ac->sched = false; ac->txq = sc->tx.txq_map[acno]; INIT_LIST_HEAD(&ac->tid_q); -- cgit v1.2.3-18-g5258 From 78ef731ce549dd9baf6eba8cf52f61727613690a Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 21 Nov 2012 18:13:11 +0530 Subject: ath9k: Fix the 'xmit' debugfs file The 'xmit' debugfs file has become big and unwieldy, fix multiple issues with its usage: * Store TX counters/statistics only for the 4 Access Categories. Use IEEE80211_NUM_ACS instead of ATH9K_NUM_TX_QUEUES. * Move various utility macros to debug.h, they can be reused elsewhere. * Remove tx_complete_poll_work_seen. * Remove code that accesses various internal queue-specific variables without any locking whatsoever. HW/SW queue details will be handled in a subsequent patch. * Do not print internal values like txq_headidx and txq_headidx. They were mostly unused anyway, considering code like: PRX("txq_tailidx: ", txq_headidx); * Handle 'txprocdesc' for EDMA too. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 1 - drivers/net/wireless/ath/ath9k/debug.c | 104 ++------------------------------- drivers/net/wireless/ath/ath9k/debug.h | 17 +++++- drivers/net/wireless/ath/ath9k/link.c | 3 - drivers/net/wireless/ath/ath9k/main.c | 1 - drivers/net/wireless/ath/ath9k/xmit.c | 2 + 6 files changed, 23 insertions(+), 105 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 3c1cebe55f6..e739b56db53 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -725,7 +725,6 @@ struct ath_softc { struct ath9k_debug debug; spinlock_t nodes_lock; struct list_head nodes; /* basically, stations */ - unsigned int tx_complete_poll_work_seen; #endif struct ath_beacon_config cur_beacon_conf; struct delayed_work tx_complete_work; diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 957e38646fd..f9df82bdd21 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -512,62 +512,19 @@ static const struct file_operations fops_interrupt = { .llseek = default_llseek, }; -#define PR_QNUM(_n) sc->tx.txq_map[_n]->axq_qnum -#define PR(str, elem) \ - do { \ - len += snprintf(buf + len, size - len, \ - "%s%13u%11u%10u%10u\n", str, \ - sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_BE)].elem, \ - sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_BK)].elem, \ - sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_VI)].elem, \ - sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_VO)].elem); \ - if (len >= size) \ - goto done; \ -} while(0) - -#define PRX(str, elem) \ -do { \ - len += snprintf(buf + len, size - len, \ - "%s%13u%11u%10u%10u\n", str, \ - (unsigned int)(sc->tx.txq_map[IEEE80211_AC_BE]->elem), \ - (unsigned int)(sc->tx.txq_map[IEEE80211_AC_BK]->elem), \ - (unsigned int)(sc->tx.txq_map[IEEE80211_AC_VI]->elem), \ - (unsigned int)(sc->tx.txq_map[IEEE80211_AC_VO]->elem)); \ - if (len >= size) \ - goto done; \ -} while(0) - -#define PRQLE(str, elem) \ -do { \ - len += snprintf(buf + len, size - len, \ - "%s%13i%11i%10i%10i\n", str, \ - list_empty(&sc->tx.txq_map[IEEE80211_AC_BE]->elem), \ - list_empty(&sc->tx.txq_map[IEEE80211_AC_BK]->elem), \ - list_empty(&sc->tx.txq_map[IEEE80211_AC_VI]->elem), \ - list_empty(&sc->tx.txq_map[IEEE80211_AC_VO]->elem)); \ - if (len >= size) \ - goto done; \ -} while (0) - static ssize_t read_file_xmit(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { struct ath_softc *sc = file->private_data; char *buf; - unsigned int len = 0, size = 8000; - int i; + unsigned int len = 0, size = 2048; ssize_t retval = 0; - char tmp[32]; buf = kzalloc(size, GFP_KERNEL); if (buf == NULL) return -ENOMEM; - len += sprintf(buf, "Num-Tx-Queues: %i tx-queues-setup: 0x%x" - " poll-work-seen: %u\n" - "%30s %10s%10s%10s\n\n", - ATH9K_NUM_TX_QUEUES, sc->tx.txqsetup, - sc->tx_complete_poll_work_seen, + len += sprintf(buf, "%30s %10s%10s%10s\n\n", "BE", "BK", "VI", "VO"); PR("MPDUs Queued: ", queued); @@ -587,62 +544,11 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf, PR("DELIM Underrun: ", delim_underrun); PR("TX-Pkts-All: ", tx_pkts_all); PR("TX-Bytes-All: ", tx_bytes_all); - PR("hw-put-tx-buf: ", puttxbuf); - PR("hw-tx-start: ", txstart); - PR("hw-tx-proc-desc: ", txprocdesc); + PR("HW-put-tx-buf: ", puttxbuf); + PR("HW-tx-start: ", txstart); + PR("HW-tx-proc-desc: ", txprocdesc); PR("TX-Failed: ", txfailed); - len += snprintf(buf + len, size - len, - "%s%11p%11p%10p%10p\n", "txq-memory-address:", - sc->tx.txq_map[IEEE80211_AC_BE], - sc->tx.txq_map[IEEE80211_AC_BK], - sc->tx.txq_map[IEEE80211_AC_VI], - sc->tx.txq_map[IEEE80211_AC_VO]); - if (len >= size) - goto done; - - PRX("axq-qnum: ", axq_qnum); - PRX("axq-depth: ", axq_depth); - PRX("axq-ampdu_depth: ", axq_ampdu_depth); - PRX("axq-stopped ", stopped); - PRX("tx-in-progress ", axq_tx_inprogress); - PRX("pending-frames ", pending_frames); - PRX("txq_headidx: ", txq_headidx); - PRX("txq_tailidx: ", txq_headidx); - - PRQLE("axq_q empty: ", axq_q); - PRQLE("axq_acq empty: ", axq_acq); - for (i = 0; i < ATH_TXFIFO_DEPTH; i++) { - snprintf(tmp, sizeof(tmp) - 1, "txq_fifo[%i] empty: ", i); - PRQLE(tmp, txq_fifo[i]); - } - - /* Print out more detailed queue-info */ - for (i = 0; i <= IEEE80211_AC_BK; i++) { - struct ath_txq *txq = &(sc->tx.txq[i]); - struct ath_atx_ac *ac; - struct ath_atx_tid *tid; - if (len >= size) - goto done; - spin_lock_bh(&txq->axq_lock); - if (!list_empty(&txq->axq_acq)) { - ac = list_first_entry(&txq->axq_acq, struct ath_atx_ac, - list); - len += snprintf(buf + len, size - len, - "txq[%i] first-ac: %p sched: %i\n", - i, ac, ac->sched); - if (list_empty(&ac->tid_q) || (len >= size)) - goto done_for; - tid = list_first_entry(&ac->tid_q, struct ath_atx_tid, - list); - len += snprintf(buf + len, size - len, - " first-tid: %p sched: %i paused: %i\n", - tid, tid->sched, tid->paused); - } - done_for: - spin_unlock_bh(&txq->axq_lock); - } -done: if (len > size) len = size; diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h index 61341cda131..f9bee18de5a 100644 --- a/drivers/net/wireless/ath/ath9k/debug.h +++ b/drivers/net/wireless/ath/ath9k/debug.h @@ -179,6 +179,21 @@ struct ath_tx_stats { u32 txfailed; }; +/* + * Various utility macros to print TX/Queue counters. + */ +#define PR_QNUM(_n) sc->tx.txq_map[_n]->axq_qnum +#define TXSTATS sc->debug.stats.txstats +#define PR(str, elem) \ + do { \ + len += snprintf(buf + len, size - len, \ + "%s%13u%11u%10u%10u\n", str, \ + TXSTATS[PR_QNUM(IEEE80211_AC_BE)].elem, \ + TXSTATS[PR_QNUM(IEEE80211_AC_BK)].elem, \ + TXSTATS[PR_QNUM(IEEE80211_AC_VI)].elem, \ + TXSTATS[PR_QNUM(IEEE80211_AC_VO)].elem); \ + } while(0) + #define RX_STAT_INC(c) (sc->debug.stats.rxstats.c++) /** @@ -227,7 +242,7 @@ struct ath_rx_stats { struct ath_stats { struct ath_interrupt_stats istats; - struct ath_tx_stats txstats[ATH9K_NUM_TX_QUEUES]; + struct ath_tx_stats txstats[IEEE80211_NUM_ACS]; struct ath_rx_stats rxstats; struct ath_dfs_stats dfs_stats; u32 reset[__RESET_TYPE_MAX]; diff --git a/drivers/net/wireless/ath/ath9k/link.c b/drivers/net/wireless/ath/ath9k/link.c index 227fdb81481..fc6b075ad63 100644 --- a/drivers/net/wireless/ath/ath9k/link.c +++ b/drivers/net/wireless/ath/ath9k/link.c @@ -27,9 +27,6 @@ void ath_tx_complete_poll_work(struct work_struct *work) struct ath_txq *txq; int i; bool needreset = false; -#ifdef CONFIG_ATH9K_DEBUGFS - sc->tx_complete_poll_work_seen++; -#endif for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) if (ATH_TXQ_SETUP(sc, i)) { diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index f8b3cacaeac..6a809bfd5aa 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1953,7 +1953,6 @@ static int ath9k_get_et_sset_count(struct ieee80211_hw *hw, return 0; } -#define PR_QNUM(_n) (sc->tx.txq_map[_n]->axq_qnum) #define AWDATA(elem) \ do { \ data[i++] = sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_BE)].elem; \ diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index ae7f2897c1a..34130943f9d 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -2319,6 +2319,8 @@ void ath_tx_edma_tasklet(struct ath_softc *sc) ath_txq_lock(sc, txq); + TX_STAT_INC(txq->axq_qnum, txprocdesc); + if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) { ath_txq_unlock(sc, txq); return; -- cgit v1.2.3-18-g5258 From c0b74876ee4873dc89d80b59f5e890a1d0a87be1 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 21 Nov 2012 18:13:12 +0530 Subject: ath9k: Add a debugfs file to dump queue statistics Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/debug.c | 53 ++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index f9df82bdd21..086dee84162 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -558,6 +558,50 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf, return retval; } +static ssize_t read_file_queues(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + struct ath_txq *txq; + char *buf; + unsigned int len = 0, size = 1024; + ssize_t retval = 0; + int i; + char *qname[4] = {"VO", "VI", "BE", "BK"}; + + buf = kzalloc(size, GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + + for (i = 0; i < IEEE80211_NUM_ACS; i++) { + txq = sc->tx.txq_map[i]; + len += snprintf(buf + len, size - len, "(%s): ", qname[i]); + + ath_txq_lock(sc, txq); + + len += snprintf(buf + len, size - len, "%s: %d ", + "qnum", txq->axq_qnum); + len += snprintf(buf + len, size - len, "%s: %2d ", + "qdepth", txq->axq_depth); + len += snprintf(buf + len, size - len, "%s: %2d ", + "ampdu-depth", txq->axq_ampdu_depth); + len += snprintf(buf + len, size - len, "%s: %3d ", + "pending", txq->pending_frames); + len += snprintf(buf + len, size - len, "%s: %d\n", + "stopped", txq->stopped); + + ath_txq_unlock(sc, txq); + } + + if (len > size) + len = size; + + retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); + kfree(buf); + + return retval; +} + static ssize_t read_file_stations(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { @@ -828,6 +872,13 @@ static const struct file_operations fops_xmit = { .llseek = default_llseek, }; +static const struct file_operations fops_queues = { + .read = read_file_queues, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + static const struct file_operations fops_stations = { .read = read_file_stations, .open = simple_open, @@ -1553,6 +1604,8 @@ int ath9k_init_debug(struct ath_hw *ah) &fops_interrupt); debugfs_create_file("xmit", S_IRUSR, sc->debug.debugfs_phy, sc, &fops_xmit); + debugfs_create_file("queues", S_IRUSR, sc->debug.debugfs_phy, sc, + &fops_queues); debugfs_create_u32("qlen_bk", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, &sc->tx.txq_max_pending[IEEE80211_AC_BK]); debugfs_create_u32("qlen_be", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, -- cgit v1.2.3-18-g5258 From 1c11e10b6a64f14427be518ccc2a242b73fc3d9f Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 21 Nov 2012 18:13:13 +0530 Subject: ath9k: Fill remove_sta_debugfs() callback Remove the rate control statistics debugfs file properly via remove_sta_debugfs(). Also, check for both MAC80211_DEBUGFS and ATH9K_DEBUGFS config options. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/rc.c | 17 +++++++++++++---- drivers/net/wireless/ath/ath9k/rc.h | 2 ++ 2 files changed, 15 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index 27ed80b5488..004f016290d 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -1350,7 +1350,7 @@ static void ath_rate_update(void *priv, struct ieee80211_supported_band *sband, } } -#ifdef CONFIG_ATH9K_DEBUGFS +#if defined(CONFIG_MAC80211_DEBUGFS) && defined(CONFIG_ATH9K_DEBUGFS) static ssize_t read_file_rcstat(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) @@ -1428,10 +1428,17 @@ static void ath_rate_add_sta_debugfs(void *priv, void *priv_sta, struct dentry *dir) { struct ath_rate_priv *rc = priv_sta; - debugfs_create_file("rc_stats", S_IRUGO, dir, rc, &fops_rcstat); + rc->debugfs_rcstats = debugfs_create_file("rc_stats", S_IRUGO, + dir, rc, &fops_rcstat); } -#endif /* CONFIG_ATH9K_DEBUGFS */ +static void ath_rate_remove_sta_debugfs(void *priv, void *priv_sta) +{ + struct ath_rate_priv *rc = priv_sta; + debugfs_remove(rc->debugfs_rcstats); +} + +#endif /* CONFIG_MAC80211_DEBUGFS && CONFIG_ATH9K_DEBUGFS */ static void *ath_rate_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) { @@ -1476,8 +1483,10 @@ static struct rate_control_ops ath_rate_ops = { .free = ath_rate_free, .alloc_sta = ath_rate_alloc_sta, .free_sta = ath_rate_free_sta, -#ifdef CONFIG_ATH9K_DEBUGFS + +#if defined(CONFIG_MAC80211_DEBUGFS) && defined(CONFIG_ATH9K_DEBUGFS) .add_sta_debugfs = ath_rate_add_sta_debugfs, + .remove_sta_debugfs = ath_rate_remove_sta_debugfs, #endif }; diff --git a/drivers/net/wireless/ath/ath9k/rc.h b/drivers/net/wireless/ath/ath9k/rc.h index 268e67dc5fb..528c83cf701 100644 --- a/drivers/net/wireless/ath/ath9k/rc.h +++ b/drivers/net/wireless/ath/ath9k/rc.h @@ -211,7 +211,9 @@ struct ath_rate_priv { struct ath_rateset neg_ht_rates; const struct ath_rate_table *rate_table; +#if defined(CONFIG_MAC80211_DEBUGFS) && defined(CONFIG_ATH9K_DEBUGFS) struct dentry *debugfs_rcstats; +#endif struct ath_rc_stats rcstats[RATE_TABLE_SIZE]; }; -- cgit v1.2.3-18-g5258 From 4d28f771ff2ca0701999b037df38ad06e949edf6 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 21 Nov 2012 18:13:14 +0530 Subject: ath9k: Fix rate control debugging Update the rate statistics only when debugfs has been enabled in ath9k and mac80211 and move the stat() functions under proper conditionals. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/rc.c | 36 ++++++++++++++++++------------------ drivers/net/wireless/ath/ath9k/rc.h | 16 +++++++++++++++- 2 files changed, 33 insertions(+), 19 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index 004f016290d..714558d1ba7 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -982,16 +982,6 @@ static void ath_rc_update_per(struct ath_softc *sc, } } -static void ath_debug_stat_retries(struct ath_rate_priv *rc, int rix, - int xretries, int retries, u8 per) -{ - struct ath_rc_stats *stats = &rc->rcstats[rix]; - - stats->xretries += xretries; - stats->retries += retries; - stats->per = per; -} - static void ath_rc_update_ht(struct ath_softc *sc, struct ath_rate_priv *ath_rc_priv, struct ieee80211_tx_info *tx_info, @@ -1065,14 +1055,6 @@ static void ath_rc_update_ht(struct ath_softc *sc, } -static void ath_debug_stat_rc(struct ath_rate_priv *rc, int final_rate) -{ - struct ath_rc_stats *stats; - - stats = &rc->rcstats[final_rate]; - stats->success++; -} - static void ath_rc_tx_status(struct ath_softc *sc, struct ath_rate_priv *ath_rc_priv, struct sk_buff *skb) @@ -1352,6 +1334,24 @@ static void ath_rate_update(void *priv, struct ieee80211_supported_band *sband, #if defined(CONFIG_MAC80211_DEBUGFS) && defined(CONFIG_ATH9K_DEBUGFS) +void ath_debug_stat_rc(struct ath_rate_priv *rc, int final_rate) +{ + struct ath_rc_stats *stats; + + stats = &rc->rcstats[final_rate]; + stats->success++; +} + +void ath_debug_stat_retries(struct ath_rate_priv *rc, int rix, + int xretries, int retries, u8 per) +{ + struct ath_rc_stats *stats = &rc->rcstats[rix]; + + stats->xretries += xretries; + stats->retries += retries; + stats->per = per; +} + static ssize_t read_file_rcstat(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { diff --git a/drivers/net/wireless/ath/ath9k/rc.h b/drivers/net/wireless/ath/ath9k/rc.h index 528c83cf701..267dbfcfaa9 100644 --- a/drivers/net/wireless/ath/ath9k/rc.h +++ b/drivers/net/wireless/ath/ath9k/rc.h @@ -213,10 +213,24 @@ struct ath_rate_priv { #if defined(CONFIG_MAC80211_DEBUGFS) && defined(CONFIG_ATH9K_DEBUGFS) struct dentry *debugfs_rcstats; -#endif struct ath_rc_stats rcstats[RATE_TABLE_SIZE]; +#endif }; +#if defined(CONFIG_MAC80211_DEBUGFS) && defined(CONFIG_ATH9K_DEBUGFS) +void ath_debug_stat_rc(struct ath_rate_priv *rc, int final_rate); +void ath_debug_stat_retries(struct ath_rate_priv *rc, int rix, + int xretries, int retries, u8 per); +#else +static inline void ath_debug_stat_rc(struct ath_rate_priv *rc, int final_rate) +{ +} +static inline void ath_debug_stat_retries(struct ath_rate_priv *rc, int rix, + int xretries, int retries, u8 per) +{ +} +#endif + #ifdef CONFIG_ATH9K_RATE_CONTROL int ath_rate_control_register(void); void ath_rate_control_unregister(void); -- cgit v1.2.3-18-g5258 From 580bdac386daa25e0432cbb4078d1cc3919127e3 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 21 Nov 2012 18:13:15 +0530 Subject: ath9k: Remove 'stations' debugfs file The 'stations' debugfs file has multiple issues. It doesn't scale to an arbitrary number of associated stations and allocating 64K is not elegant either. Now that changes have been made in mac80211 to support dynamic creation/deletion of driver-specific debugfs files on station addition/removal, remove this file and make use of the mac80211 hooks (which will be done in a sebsequent patch). Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 5 --- drivers/net/wireless/ath/ath9k/debug.c | 74 ---------------------------------- drivers/net/wireless/ath/ath9k/init.c | 4 -- drivers/net/wireless/ath/ath9k/main.c | 12 ------ 4 files changed, 95 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index e739b56db53..80bab1b8447 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -259,9 +259,6 @@ struct ath_atx_tid { }; struct ath_node { -#ifdef CONFIG_ATH9K_DEBUGFS - struct list_head list; /* for sc->nodes */ -#endif struct ieee80211_sta *sta; /* station struct we're part of */ struct ieee80211_vif *vif; /* interface with which we're associated */ struct ath_atx_tid tid[WME_NUM_TID]; @@ -723,8 +720,6 @@ struct ath_softc { #ifdef CONFIG_ATH9K_DEBUGFS struct ath9k_debug debug; - spinlock_t nodes_lock; - struct list_head nodes; /* basically, stations */ #endif struct ath_beacon_config cur_beacon_conf; struct delayed_work tx_complete_work; diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 086dee84162..939308c2571 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -602,71 +602,6 @@ static ssize_t read_file_queues(struct file *file, char __user *user_buf, return retval; } -static ssize_t read_file_stations(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ath_softc *sc = file->private_data; - char *buf; - unsigned int len = 0, size = 64000; - struct ath_node *an = NULL; - ssize_t retval = 0; - int q; - - buf = kzalloc(size, GFP_KERNEL); - if (buf == NULL) - return -ENOMEM; - - len += snprintf(buf + len, size - len, - "Stations:\n" - " tid: addr sched paused buf_q-empty an ac baw\n" - " ac: addr sched tid_q-empty txq\n"); - - spin_lock(&sc->nodes_lock); - list_for_each_entry(an, &sc->nodes, list) { - unsigned short ma = an->maxampdu; - if (ma == 0) - ma = 65535; /* see ath_lookup_rate */ - len += snprintf(buf + len, size - len, - "iface: %pM sta: %pM max-ampdu: %hu mpdu-density: %uus\n", - an->vif->addr, an->sta->addr, ma, - (unsigned int)(an->mpdudensity)); - if (len >= size) - goto done; - - for (q = 0; q < WME_NUM_TID; q++) { - struct ath_atx_tid *tid = &(an->tid[q]); - len += snprintf(buf + len, size - len, - " tid: %p %s %s %i %p %p %hu\n", - tid, tid->sched ? "sched" : "idle", - tid->paused ? "paused" : "running", - skb_queue_empty(&tid->buf_q), - tid->an, tid->ac, tid->baw_size); - if (len >= size) - goto done; - } - - for (q = 0; q < IEEE80211_NUM_ACS; q++) { - struct ath_atx_ac *ac = &(an->ac[q]); - len += snprintf(buf + len, size - len, - " ac: %p %s %i %p\n", - ac, ac->sched ? "sched" : "idle", - list_empty(&ac->tid_q), ac->txq); - if (len >= size) - goto done; - } - } - -done: - spin_unlock(&sc->nodes_lock); - if (len > size) - len = size; - - retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); - kfree(buf); - - return retval; -} - static ssize_t read_file_misc(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { @@ -879,13 +814,6 @@ static const struct file_operations fops_queues = { .llseek = default_llseek, }; -static const struct file_operations fops_stations = { - .read = read_file_stations, - .open = simple_open, - .owner = THIS_MODULE, - .llseek = default_llseek, -}; - static const struct file_operations fops_misc = { .read = read_file_misc, .open = simple_open, @@ -1614,8 +1542,6 @@ int ath9k_init_debug(struct ath_hw *ah) &sc->tx.txq_max_pending[IEEE80211_AC_VI]); debugfs_create_u32("qlen_vo", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, &sc->tx.txq_max_pending[IEEE80211_AC_VO]); - debugfs_create_file("stations", S_IRUSR, sc->debug.debugfs_phy, sc, - &fops_stations); debugfs_create_file("misc", S_IRUSR, sc->debug.debugfs_phy, sc, &fops_misc); debugfs_create_file("reset", S_IRUSR, sc->debug.debugfs_phy, sc, diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 345a01af542..80cae53a33e 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -563,10 +563,6 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, spin_lock_init(&sc->sc_serial_rw); spin_lock_init(&sc->sc_pm_lock); mutex_init(&sc->mutex); -#ifdef CONFIG_ATH9K_DEBUGFS - spin_lock_init(&sc->nodes_lock); - INIT_LIST_HEAD(&sc->nodes); -#endif #ifdef CONFIG_ATH9K_MAC_DEBUG spin_lock_init(&sc->debug.samp_lock); #endif diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 6a809bfd5aa..0653dbc99e3 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -331,11 +331,6 @@ static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta, u8 density; an = (struct ath_node *)sta->drv_priv; -#ifdef CONFIG_ATH9K_DEBUGFS - spin_lock(&sc->nodes_lock); - list_add(&an->list, &sc->nodes); - spin_unlock(&sc->nodes_lock); -#endif an->sta = sta; an->vif = vif; @@ -352,13 +347,6 @@ static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta) { struct ath_node *an = (struct ath_node *)sta->drv_priv; -#ifdef CONFIG_ATH9K_DEBUGFS - spin_lock(&sc->nodes_lock); - list_del(&an->list); - spin_unlock(&sc->nodes_lock); - an->sta = NULL; -#endif - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) ath_tx_node_cleanup(sc, an); } -- cgit v1.2.3-18-g5258 From 42d97a599eb6b2aab3a401b3e5799a399d6c7652 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 8 Nov 2012 18:31:02 +0100 Subject: cfg80211: remove remain-on-channel channel type As mwifiex (and mac80211 in the software case) are the only drivers actually implementing remain-on-channel with channel type, userspace can't be relying on it. This is the case, as it's used only for P2P operations right now. Rather than adding a flag to tell userspace whether or not it can actually rely on it, simplify all the code by removing the ability to use different channel types. Leave only the validation of the attribute, so that if we extend it again later (with the needed capability flag), it can't break userspace sending invalid data. Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/ath6kl/cfg80211.c | 7 ++----- drivers/net/wireless/ath/ath6kl/wmi.c | 5 ++--- 2 files changed, 4 insertions(+), 8 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index d615f9f7506..74091d33ed6 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -2976,7 +2976,6 @@ static int ath6kl_change_station(struct wiphy *wiphy, struct net_device *dev, static int ath6kl_remain_on_channel(struct wiphy *wiphy, struct wireless_dev *wdev, struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type, unsigned int duration, u64 *cookie) { @@ -3135,10 +3134,8 @@ static bool ath6kl_is_p2p_go_ssid(const u8 *buf, size_t len) static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, struct ieee80211_channel *chan, bool offchan, - enum nl80211_channel_type channel_type, - bool channel_type_valid, unsigned int wait, - const u8 *buf, size_t len, bool no_cck, - bool dont_wait_for_ack, u64 *cookie) + unsigned int wait, const u8 *buf, size_t len, + bool no_cck, bool dont_wait_for_ack, u64 *cookie) { struct ath6kl_vif *vif = ath6kl_vif_from_wdev(wdev); struct ath6kl *ar = ath6kl_priv(vif->ndev); diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index c30ab4b11d6..0e05c41cdcf 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -474,7 +474,7 @@ static int ath6kl_wmi_remain_on_chnl_event_rx(struct wmi *wmi, u8 *datap, return -EINVAL; } id = vif->last_roc_id; - cfg80211_ready_on_channel(&vif->wdev, id, chan, NL80211_CHAN_NO_HT, + cfg80211_ready_on_channel(&vif->wdev, id, chan, dur, GFP_ATOMIC); return 0; @@ -513,8 +513,7 @@ static int ath6kl_wmi_cancel_remain_on_chnl_event_rx(struct wmi *wmi, else id = vif->last_roc_id; /* timeout on uncanceled r-o-c */ vif->last_cancel_roc_id = 0; - cfg80211_remain_on_channel_expired(&vif->wdev, id, chan, - NL80211_CHAN_NO_HT, GFP_ATOMIC); + cfg80211_remain_on_channel_expired(&vif->wdev, id, chan, GFP_ATOMIC); return 0; } -- cgit v1.2.3-18-g5258 From 683b6d3b31a51956ea540df00abb0b78894924c1 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 8 Nov 2012 21:25:48 +0100 Subject: cfg80211: pass a channel definition struct Instead of passing a channel pointer and channel type to all functions and driver methods, pass a new channel definition struct. Right now, this struct contains just the control channel and channel type, but for VHT this will change. Also, add a small inline cfg80211_get_chandef_type() so that drivers don't need to use the _type field of the new structure all the time, which will change. Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/ath6kl/cfg80211.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index 74091d33ed6..c0cc2e59fe6 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -1093,15 +1093,20 @@ out: void ath6kl_cfg80211_ch_switch_notify(struct ath6kl_vif *vif, int freq, enum wmi_phy_mode mode) { - enum nl80211_channel_type type; + struct cfg80211_chan_def chandef; ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "channel switch notify nw_type %d freq %d mode %d\n", vif->nw_type, freq, mode); - type = (mode == WMI_11G_HT20) ? NL80211_CHAN_HT20 : NL80211_CHAN_NO_HT; + chandef.chan = ieee80211_get_channel(vif->ar->wiphy, freq); + if (WARN_ON(!chandef.chan)) + return; + + chandef._type = (mode == WMI_11G_HT20) ? + NL80211_CHAN_HT20 : NL80211_CHAN_NO_HT; - cfg80211_ch_switch_notify(vif->ndev, freq, type); + cfg80211_ch_switch_notify(vif->ndev, &chandef); } static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, @@ -1613,8 +1618,8 @@ static int ath6kl_cfg80211_join_ibss(struct wiphy *wiphy, vif->ssid_len = ibss_param->ssid_len; memcpy(vif->ssid, ibss_param->ssid, vif->ssid_len); - if (ibss_param->channel) - vif->ch_hint = ibss_param->channel->center_freq; + if (ibss_param->chandef.chan) + vif->ch_hint = ibss_param->chandef.chan->center_freq; if (ibss_param->channel_fixed) { /* @@ -2856,7 +2861,7 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev, p.ssid_len = vif->ssid_len; memcpy(p.ssid, vif->ssid, vif->ssid_len); p.dot11_auth_mode = vif->dot11_auth_mode; - p.ch = cpu_to_le16(info->channel->center_freq); + p.ch = cpu_to_le16(info->chandef.chan->center_freq); /* Enable uAPSD support by default */ res = ath6kl_wmi_ap_set_apsd(ar->wmi, vif->fw_vif_idx, true); @@ -2880,8 +2885,9 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev, return res; } - if (ath6kl_set_htcap(vif, info->channel->band, - info->channel_type != NL80211_CHAN_NO_HT)) + if (ath6kl_set_htcap(vif, info->chandef.chan->band, + cfg80211_get_chandef_type(&info->chandef) + != NL80211_CHAN_NO_HT)) return -EIO; /* -- cgit v1.2.3-18-g5258 From 3d9d1d6656a73ea8407734cfb00b81d14ef62d4b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 8 Nov 2012 23:14:50 +0100 Subject: nl80211/cfg80211: support VHT channel configuration Change nl80211 to support specifying a VHT (or HT) using the control channel frequency (as before) and new attributes for the channel width and first and second center frequency. The old channel type is of course still supported for HT. Also change the cfg80211 channel definition struct to support these by adding the relevant fields to it (and removing the _type field.) This also adds new helper functions: - cfg80211_chandef_create to create a channel def struct given the control channel and channel type, - cfg80211_chandef_identical to check if two channel definitions are identical - cfg80211_chandef_compatible to check if the given channel definitions are compatible, and return the wider of the two This isn't entirely complete, but that doesn't matter until we have a driver using it. In particular, it's missing - regulatory checks on the usable bandwidth (if that even makes sense) - regulatory TX power (database can't deal with it) - a proper channel compatibility calculation for the new channel types Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/ath6kl/cfg80211.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index c0cc2e59fe6..51bbe85c574 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -1099,12 +1099,10 @@ void ath6kl_cfg80211_ch_switch_notify(struct ath6kl_vif *vif, int freq, "channel switch notify nw_type %d freq %d mode %d\n", vif->nw_type, freq, mode); - chandef.chan = ieee80211_get_channel(vif->ar->wiphy, freq); - if (WARN_ON(!chandef.chan)) - return; - - chandef._type = (mode == WMI_11G_HT20) ? - NL80211_CHAN_HT20 : NL80211_CHAN_NO_HT; + cfg80211_chandef_create(&chandef, + ieee80211_get_channel(vif->ar->wiphy, freq), + (mode == WMI_11G_HT20) ? + NL80211_CHAN_HT20 : NL80211_CHAN_NO_HT); cfg80211_ch_switch_notify(vif->ndev, &chandef); } -- cgit v1.2.3-18-g5258 From d6144d85f830848ab31eb5d073d9bb4742b64e03 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Tue, 27 Nov 2012 13:51:32 +0530 Subject: ath9k: Fix buffer overflow error The commit "ath9k: stomp audio profiles on weak signal strength" failed to take care of new stomp type while programming concurrent tx priority. That leads to array index out of bounds access. drivers/net/wireless/ath/ath9k/btcoex.c:414 ath9k_hw_btcoex_set_concur_txprio() error: buffer overflow 'stomp_txprio' 4 <= 4 Reported-by: Dan Carpenter Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/mci.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/mci.c b/drivers/net/wireless/ath/ath9k/mci.c index 706378ea3ba..5c02702f21e 100644 --- a/drivers/net/wireless/ath/ath9k/mci.c +++ b/drivers/net/wireless/ath/ath9k/mci.c @@ -257,8 +257,9 @@ static void ath_mci_set_concur_txprio(struct ath_softc *sc) { struct ath_btcoex *btcoex = &sc->btcoex; struct ath_mci_profile *mci = &btcoex->mci; - u8 stomp_txprio[] = { 0, 0, 0, 0 }; /* all, low, none, low_ftp */ + u8 stomp_txprio[ATH_BTCOEX_STOMP_MAX]; + memset(stomp_txprio, 0, sizeof(stomp_txprio)); if (mci->num_mgmt) { stomp_txprio[ATH_BTCOEX_STOMP_ALL] = ATH_MCI_INQUIRY_PRIO; if (!mci->num_pan && !mci->num_other_acl) -- cgit v1.2.3-18-g5258 From c175db87411f0e79924a48563d5f595b9a352907 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 28 Nov 2012 15:08:52 +0530 Subject: ath9k: Move ethtool functions to debug.c The ethtool statistics are available only when CONFIG_ATH9K_DEBUGFS is enabled, move these functions to debug.c Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/debug.c | 119 ++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath9k/debug.h | 8 +++ drivers/net/wireless/ath/ath9k/main.c | 127 --------------------------------- 3 files changed, 127 insertions(+), 127 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 939308c2571..cb5e45798ac 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -1509,6 +1509,125 @@ static const struct file_operations fops_btcoex = { }; #endif +/* Ethtool support for get-stats */ + +#define AMKSTR(nm) #nm "_BE", #nm "_BK", #nm "_VI", #nm "_VO" +static const char ath9k_gstrings_stats[][ETH_GSTRING_LEN] = { + "tx_pkts_nic", + "tx_bytes_nic", + "rx_pkts_nic", + "rx_bytes_nic", + AMKSTR(d_tx_pkts), + AMKSTR(d_tx_bytes), + AMKSTR(d_tx_mpdus_queued), + AMKSTR(d_tx_mpdus_completed), + AMKSTR(d_tx_mpdu_xretries), + AMKSTR(d_tx_aggregates), + AMKSTR(d_tx_ampdus_queued_hw), + AMKSTR(d_tx_ampdus_queued_sw), + AMKSTR(d_tx_ampdus_completed), + AMKSTR(d_tx_ampdu_retries), + AMKSTR(d_tx_ampdu_xretries), + AMKSTR(d_tx_fifo_underrun), + AMKSTR(d_tx_op_exceeded), + AMKSTR(d_tx_timer_expiry), + AMKSTR(d_tx_desc_cfg_err), + AMKSTR(d_tx_data_underrun), + AMKSTR(d_tx_delim_underrun), + "d_rx_decrypt_crc_err", + "d_rx_phy_err", + "d_rx_mic_err", + "d_rx_pre_delim_crc_err", + "d_rx_post_delim_crc_err", + "d_rx_decrypt_busy_err", + + "d_rx_phyerr_radar", + "d_rx_phyerr_ofdm_timing", + "d_rx_phyerr_cck_timing", + +}; +#define ATH9K_SSTATS_LEN ARRAY_SIZE(ath9k_gstrings_stats) + +void ath9k_get_et_strings(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + u32 sset, u8 *data) +{ + if (sset == ETH_SS_STATS) + memcpy(data, *ath9k_gstrings_stats, + sizeof(ath9k_gstrings_stats)); +} + +int ath9k_get_et_sset_count(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, int sset) +{ + if (sset == ETH_SS_STATS) + return ATH9K_SSTATS_LEN; + return 0; +} + +#define AWDATA(elem) \ + do { \ + data[i++] = sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_BE)].elem; \ + data[i++] = sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_BK)].elem; \ + data[i++] = sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_VI)].elem; \ + data[i++] = sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_VO)].elem; \ + } while (0) + +#define AWDATA_RX(elem) \ + do { \ + data[i++] = sc->debug.stats.rxstats.elem; \ + } while (0) + +void ath9k_get_et_stats(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ethtool_stats *stats, u64 *data) +{ + struct ath_softc *sc = hw->priv; + int i = 0; + + data[i++] = (sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_BE)].tx_pkts_all + + sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_BK)].tx_pkts_all + + sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_VI)].tx_pkts_all + + sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_VO)].tx_pkts_all); + data[i++] = (sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_BE)].tx_bytes_all + + sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_BK)].tx_bytes_all + + sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_VI)].tx_bytes_all + + sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_VO)].tx_bytes_all); + AWDATA_RX(rx_pkts_all); + AWDATA_RX(rx_bytes_all); + + AWDATA(tx_pkts_all); + AWDATA(tx_bytes_all); + AWDATA(queued); + AWDATA(completed); + AWDATA(xretries); + AWDATA(a_aggr); + AWDATA(a_queued_hw); + AWDATA(a_queued_sw); + AWDATA(a_completed); + AWDATA(a_retries); + AWDATA(a_xretries); + AWDATA(fifo_underrun); + AWDATA(xtxop); + AWDATA(timer_exp); + AWDATA(desc_cfg_err); + AWDATA(data_underrun); + AWDATA(delim_underrun); + + AWDATA_RX(decrypt_crc_err); + AWDATA_RX(phy_err); + AWDATA_RX(mic_err); + AWDATA_RX(pre_delim_crc_err); + AWDATA_RX(post_delim_crc_err); + AWDATA_RX(decrypt_busy_err); + + AWDATA_RX(phy_err_stats[ATH9K_PHYERR_RADAR]); + AWDATA_RX(phy_err_stats[ATH9K_PHYERR_OFDM_TIMING]); + AWDATA_RX(phy_err_stats[ATH9K_PHYERR_CCK_TIMING]); + + WARN_ON(i != ATH9K_SSTATS_LEN); +} + int ath9k_init_debug(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h index f9bee18de5a..bfc21b37cb1 100644 --- a/drivers/net/wireless/ath/ath9k/debug.h +++ b/drivers/net/wireless/ath/ath9k/debug.h @@ -307,6 +307,14 @@ void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf, struct ath_tx_status *ts, struct ath_txq *txq, unsigned int flags); void ath_debug_stat_rx(struct ath_softc *sc, struct ath_rx_status *rs); +int ath9k_get_et_sset_count(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, int sset); +void ath9k_get_et_stats(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ethtool_stats *stats, u64 *data); +void ath9k_get_et_strings(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + u32 sset, u8 *data); #else diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 0653dbc99e3..ffae384276a 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1882,133 +1882,6 @@ static int ath9k_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) return 0; } -#ifdef CONFIG_ATH9K_DEBUGFS - -/* Ethtool support for get-stats */ - -#define AMKSTR(nm) #nm "_BE", #nm "_BK", #nm "_VI", #nm "_VO" -static const char ath9k_gstrings_stats[][ETH_GSTRING_LEN] = { - "tx_pkts_nic", - "tx_bytes_nic", - "rx_pkts_nic", - "rx_bytes_nic", - AMKSTR(d_tx_pkts), - AMKSTR(d_tx_bytes), - AMKSTR(d_tx_mpdus_queued), - AMKSTR(d_tx_mpdus_completed), - AMKSTR(d_tx_mpdu_xretries), - AMKSTR(d_tx_aggregates), - AMKSTR(d_tx_ampdus_queued_hw), - AMKSTR(d_tx_ampdus_queued_sw), - AMKSTR(d_tx_ampdus_completed), - AMKSTR(d_tx_ampdu_retries), - AMKSTR(d_tx_ampdu_xretries), - AMKSTR(d_tx_fifo_underrun), - AMKSTR(d_tx_op_exceeded), - AMKSTR(d_tx_timer_expiry), - AMKSTR(d_tx_desc_cfg_err), - AMKSTR(d_tx_data_underrun), - AMKSTR(d_tx_delim_underrun), - - "d_rx_decrypt_crc_err", - "d_rx_phy_err", - "d_rx_mic_err", - "d_rx_pre_delim_crc_err", - "d_rx_post_delim_crc_err", - "d_rx_decrypt_busy_err", - - "d_rx_phyerr_radar", - "d_rx_phyerr_ofdm_timing", - "d_rx_phyerr_cck_timing", - -}; -#define ATH9K_SSTATS_LEN ARRAY_SIZE(ath9k_gstrings_stats) - -static void ath9k_get_et_strings(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - u32 sset, u8 *data) -{ - if (sset == ETH_SS_STATS) - memcpy(data, *ath9k_gstrings_stats, - sizeof(ath9k_gstrings_stats)); -} - -static int ath9k_get_et_sset_count(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, int sset) -{ - if (sset == ETH_SS_STATS) - return ATH9K_SSTATS_LEN; - return 0; -} - -#define AWDATA(elem) \ - do { \ - data[i++] = sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_BE)].elem; \ - data[i++] = sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_BK)].elem; \ - data[i++] = sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_VI)].elem; \ - data[i++] = sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_VO)].elem; \ - } while (0) - -#define AWDATA_RX(elem) \ - do { \ - data[i++] = sc->debug.stats.rxstats.elem; \ - } while (0) - -static void ath9k_get_et_stats(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ethtool_stats *stats, u64 *data) -{ - struct ath_softc *sc = hw->priv; - int i = 0; - - data[i++] = (sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_BE)].tx_pkts_all + - sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_BK)].tx_pkts_all + - sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_VI)].tx_pkts_all + - sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_VO)].tx_pkts_all); - data[i++] = (sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_BE)].tx_bytes_all + - sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_BK)].tx_bytes_all + - sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_VI)].tx_bytes_all + - sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_VO)].tx_bytes_all); - AWDATA_RX(rx_pkts_all); - AWDATA_RX(rx_bytes_all); - - AWDATA(tx_pkts_all); - AWDATA(tx_bytes_all); - AWDATA(queued); - AWDATA(completed); - AWDATA(xretries); - AWDATA(a_aggr); - AWDATA(a_queued_hw); - AWDATA(a_queued_sw); - AWDATA(a_completed); - AWDATA(a_retries); - AWDATA(a_xretries); - AWDATA(fifo_underrun); - AWDATA(xtxop); - AWDATA(timer_exp); - AWDATA(desc_cfg_err); - AWDATA(data_underrun); - AWDATA(delim_underrun); - - AWDATA_RX(decrypt_crc_err); - AWDATA_RX(phy_err); - AWDATA_RX(mic_err); - AWDATA_RX(pre_delim_crc_err); - AWDATA_RX(post_delim_crc_err); - AWDATA_RX(decrypt_busy_err); - - AWDATA_RX(phy_err_stats[ATH9K_PHYERR_RADAR]); - AWDATA_RX(phy_err_stats[ATH9K_PHYERR_OFDM_TIMING]); - AWDATA_RX(phy_err_stats[ATH9K_PHYERR_CCK_TIMING]); - - WARN_ON(i != ATH9K_SSTATS_LEN); -} - -/* End of ethtool get-stats functions */ - -#endif - - #ifdef CONFIG_PM_SLEEP static void ath9k_wow_map_triggers(struct ath_softc *sc, -- cgit v1.2.3-18-g5258 From de7b7604eae91f00cd587f8541eec11a7fc505aa Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 28 Nov 2012 15:08:53 +0530 Subject: ath9k: Replace WME_NUM_TID with IEEE80211_NUM_TIDS Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 2 +- drivers/net/wireless/ath/ath9k/common.h | 1 - drivers/net/wireless/ath/ath9k/xmit.c | 8 ++++---- 3 files changed, 5 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 80bab1b8447..60bf784e557 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -261,7 +261,7 @@ struct ath_atx_tid { struct ath_node { struct ieee80211_sta *sta; /* station struct we're part of */ struct ieee80211_vif *vif; /* interface with which we're associated */ - struct ath_atx_tid tid[WME_NUM_TID]; + struct ath_atx_tid tid[IEEE80211_NUM_TIDS]; struct ath_atx_ac ac[IEEE80211_NUM_ACS]; int ps_key; diff --git a/drivers/net/wireless/ath/ath9k/common.h b/drivers/net/wireless/ath/ath9k/common.h index 76b54390031..5f845beeb18 100644 --- a/drivers/net/wireless/ath/ath9k/common.h +++ b/drivers/net/wireless/ath/ath9k/common.h @@ -23,7 +23,6 @@ /* Common header for Atheros 802.11n base driver cores */ -#define WME_NUM_TID 16 #define WME_BA_BMP_SIZE 64 #define WME_MAX_BA WME_BA_BMP_SIZE #define ATH_TID_MAX_BUFS (2 * WME_MAX_BA) diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 34130943f9d..a0a3063dae7 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1263,7 +1263,7 @@ void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc, int tidno; for (tidno = 0, tid = &an->tid[tidno]; - tidno < WME_NUM_TID; tidno++, tid++) { + tidno < IEEE80211_NUM_TIDS; tidno++, tid++) { if (!tid->sched) continue; @@ -1297,7 +1297,7 @@ void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an) int tidno; for (tidno = 0, tid = &an->tid[tidno]; - tidno < WME_NUM_TID; tidno++, tid++) { + tidno < IEEE80211_NUM_TIDS; tidno++, tid++) { ac = tid->ac; txq = ac->txq; @@ -2448,7 +2448,7 @@ void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an) int tidno, acno; for (tidno = 0, tid = &an->tid[tidno]; - tidno < WME_NUM_TID; + tidno < IEEE80211_NUM_TIDS; tidno++, tid++) { tid->an = an; tid->tidno = tidno; @@ -2481,7 +2481,7 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an) int tidno; for (tidno = 0, tid = &an->tid[tidno]; - tidno < WME_NUM_TID; tidno++, tid++) { + tidno < IEEE80211_NUM_TIDS; tidno++, tid++) { ac = tid->ac; txq = ac->txq; -- cgit v1.2.3-18-g5258 From a145daf7f04696d0cec98d5328760fe65fe418c5 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 28 Nov 2012 15:08:54 +0530 Subject: ath9k: Implement sta_add_debugfs/sta_remove_debugfs Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 5 ++ drivers/net/wireless/ath/ath9k/debug.c | 90 ++++++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath9k/debug.h | 9 +++- drivers/net/wireless/ath/ath9k/main.c | 10 +++- 4 files changed, 111 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 60bf784e557..86e26a19efd 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -259,6 +259,7 @@ struct ath_atx_tid { }; struct ath_node { + struct ath_softc *sc; struct ieee80211_sta *sta; /* station struct we're part of */ struct ieee80211_vif *vif; /* interface with which we're associated */ struct ath_atx_tid tid[IEEE80211_NUM_TIDS]; @@ -269,6 +270,10 @@ struct ath_node { u8 mpdudensity; bool sleeping; + +#if defined(CONFIG_MAC80211_DEBUGFS) && defined(CONFIG_ATH9K_DEBUGFS) + struct dentry *node_stat; +#endif }; #define AGGR_CLEANUP BIT(1) diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index cb5e45798ac..13ff9edc240 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -1509,6 +1509,96 @@ static const struct file_operations fops_btcoex = { }; #endif +static ssize_t read_file_node_stat(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_node *an = file->private_data; + struct ath_softc *sc = an->sc; + struct ath_atx_tid *tid; + struct ath_atx_ac *ac; + struct ath_txq *txq; + u32 len = 0, size = 4096; + char *buf; + size_t retval; + int tidno, acno; + + buf = kzalloc(size, GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + + if (!an->sta->ht_cap.ht_supported) { + len = snprintf(buf, size, "%s\n", + "HT not supported"); + goto exit; + } + + len = snprintf(buf, size, "Max-AMPDU: %d\n", + an->maxampdu); + len += snprintf(buf + len, size - len, "MPDU Density: %d\n\n", + an->mpdudensity); + + len += snprintf(buf + len, size - len, + "%2s%7s\n", "AC", "SCHED"); + + for (acno = 0, ac = &an->ac[acno]; + acno < IEEE80211_NUM_ACS; acno++, ac++) { + txq = ac->txq; + ath_txq_lock(sc, txq); + len += snprintf(buf + len, size - len, + "%2d%7d\n", + acno, ac->sched); + ath_txq_unlock(sc, txq); + } + + len += snprintf(buf + len, size - len, + "\n%3s%11s%10s%10s%10s%10s%9s%6s%8s\n", + "TID", "SEQ_START", "SEQ_NEXT", "BAW_SIZE", + "BAW_HEAD", "BAW_TAIL", "BAR_IDX", "SCHED", "PAUSED"); + + for (tidno = 0, tid = &an->tid[tidno]; + tidno < IEEE80211_NUM_TIDS; tidno++, tid++) { + txq = tid->ac->txq; + ath_txq_lock(sc, txq); + len += snprintf(buf + len, size - len, + "%3d%11d%10d%10d%10d%10d%9d%6d%8d\n", + tid->tidno, tid->seq_start, tid->seq_next, + tid->baw_size, tid->baw_head, tid->baw_tail, + tid->bar_index, tid->sched, tid->paused); + ath_txq_unlock(sc, txq); + } +exit: + retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); + kfree(buf); + + return retval; +} + +static const struct file_operations fops_node_stat = { + .read = read_file_node_stat, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +void ath9k_sta_add_debugfs(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct dentry *dir) +{ + struct ath_node *an = (struct ath_node *)sta->drv_priv; + an->node_stat = debugfs_create_file("node_stat", S_IRUGO, + dir, an, &fops_node_stat); +} + +void ath9k_sta_remove_debugfs(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct dentry *dir) +{ + struct ath_node *an = (struct ath_node *)sta->drv_priv; + debugfs_remove(an->node_stat); +} + /* Ethtool support for get-stats */ #define AMKSTR(nm) #nm "_BE", #nm "_BK", #nm "_VI", #nm "_VO" diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h index bfc21b37cb1..72d4893311b 100644 --- a/drivers/net/wireless/ath/ath9k/debug.h +++ b/drivers/net/wireless/ath/ath9k/debug.h @@ -315,7 +315,14 @@ void ath9k_get_et_stats(struct ieee80211_hw *hw, void ath9k_get_et_strings(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u32 sset, u8 *data); - +void ath9k_sta_add_debugfs(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct dentry *dir); +void ath9k_sta_remove_debugfs(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct dentry *dir); #else #define RX_STAT_INC(c) /* NOP */ diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index ffae384276a..be30a9af152 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -331,6 +331,7 @@ static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta, u8 density; an = (struct ath_node *)sta->drv_priv; + an->sc = sc; an->sta = sta; an->vif = vif; @@ -2275,7 +2276,12 @@ struct ieee80211_ops ath9k_ops = { #ifdef CONFIG_ATH9K_DEBUGFS .get_et_sset_count = ath9k_get_et_sset_count, - .get_et_stats = ath9k_get_et_stats, - .get_et_strings = ath9k_get_et_strings, + .get_et_stats = ath9k_get_et_stats, + .get_et_strings = ath9k_get_et_strings, +#endif + +#if defined(CONFIG_MAC80211_DEBUGFS) && defined(CONFIG_ATH9K_DEBUGFS) + .sta_add_debugfs = ath9k_sta_add_debugfs, + .sta_remove_debugfs = ath9k_sta_remove_debugfs, #endif }; -- cgit v1.2.3-18-g5258 From a56c919f05eb73f6d791cc14992f4b451059b68c Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 28 Nov 2012 15:08:55 +0530 Subject: ath9k: Remove redundant NULL assignment 'bf_next' is cleared using ATH_TXBUF_RESET() in both the callsites of ath_tx_get_buffer(). Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/xmit.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index a0a3063dae7..90e48a0fafe 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -312,7 +312,6 @@ static struct ath_buf *ath_tx_get_buffer(struct ath_softc *sc) } bf = list_first_entry(&sc->tx.txbuf, struct ath_buf, list); - bf->bf_next = NULL; list_del(&bf->list); spin_unlock_bh(&sc->tx.txbuflock); -- cgit v1.2.3-18-g5258 From 23c1d7f65975762386760e36c00f149059e537e2 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Wed, 28 Nov 2012 18:57:19 +0200 Subject: wireless: allow Atheros card to not depend on ath.ko There are 2 different things: - sub-menu for "Atheros Wireless cards" family - module ath.ko with common Atheros code Until now, they both used to depend on the same Kconfig variable ATH_COMMON. Thus, being "Atheros card" and "depending on ath.ko" was the same. To allow module to belong to the "Atheros Wireless cards" family but not use ath.ko, 2 conditions above need to be separated. So, this patch introduce new Kconfig variable ATH_CARDS for belonging to the "Atheros Wireless Cards" family; while ATH_COMMON becomes hidden variable to express dependency on common Atheros code in ath.ko. Modules that depend on this common code now express it by setting ATH_COMMON. Right now, ath6kl do not depend on common code and thus do not set ATH_COMMON. Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/Kconfig | 7 +++++-- drivers/net/wireless/ath/ar5523/Kconfig | 1 + drivers/net/wireless/ath/ath5k/Kconfig | 1 + drivers/net/wireless/ath/ath9k/Kconfig | 1 + drivers/net/wireless/ath/carl9170/Kconfig | 1 + 5 files changed, 9 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/Kconfig b/drivers/net/wireless/ath/Kconfig index c25dcf192fe..1a67a4f829f 100644 --- a/drivers/net/wireless/ath/Kconfig +++ b/drivers/net/wireless/ath/Kconfig @@ -1,4 +1,7 @@ -menuconfig ATH_COMMON +config ATH_COMMON + tristate + +menuconfig ATH_CARDS tristate "Atheros Wireless Cards" depends on CFG80211 && (!UML || BROKEN) ---help--- @@ -14,7 +17,7 @@ menuconfig ATH_COMMON http://wireless.kernel.org/en/users/Drivers/Atheros -if ATH_COMMON +if ATH_CARDS config ATH_DEBUG bool "Atheros wireless debugging" diff --git a/drivers/net/wireless/ath/ar5523/Kconfig b/drivers/net/wireless/ath/ar5523/Kconfig index 11d99ee8de5..0d320cc7769 100644 --- a/drivers/net/wireless/ath/ar5523/Kconfig +++ b/drivers/net/wireless/ath/ar5523/Kconfig @@ -1,6 +1,7 @@ config AR5523 tristate "Atheros AR5523 wireless driver support" depends on MAC80211 && USB + select ATH_COMMON select FW_LOADER ---help--- This module add support for AR5523 based USB dongles such as D-Link diff --git a/drivers/net/wireless/ath/ath5k/Kconfig b/drivers/net/wireless/ath/ath5k/Kconfig index 338c5c42357..c9f81a388f1 100644 --- a/drivers/net/wireless/ath/ath5k/Kconfig +++ b/drivers/net/wireless/ath/ath5k/Kconfig @@ -1,6 +1,7 @@ config ATH5K tristate "Atheros 5xxx wireless cards support" depends on (PCI || ATHEROS_AR231X) && MAC80211 + select ATH_COMMON select MAC80211_LEDS select LEDS_CLASS select NEW_LEDS diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig index c7aa6646123..5fc15bf8be0 100644 --- a/drivers/net/wireless/ath/ath9k/Kconfig +++ b/drivers/net/wireless/ath/ath9k/Kconfig @@ -17,6 +17,7 @@ config ATH9K_BTCOEX_SUPPORT config ATH9K tristate "Atheros 802.11n wireless cards support" depends on MAC80211 + select ATH_COMMON select ATH9K_HW select MAC80211_LEDS select LEDS_CLASS diff --git a/drivers/net/wireless/ath/carl9170/Kconfig b/drivers/net/wireless/ath/carl9170/Kconfig index 267d5dcf82d..13a20459876 100644 --- a/drivers/net/wireless/ath/carl9170/Kconfig +++ b/drivers/net/wireless/ath/carl9170/Kconfig @@ -1,6 +1,7 @@ config CARL9170 tristate "Linux Community AR9170 802.11n USB support" depends on USB && MAC80211 && EXPERIMENTAL + select ATH_COMMON select FW_LOADER select CRC32 help -- cgit v1.2.3-18-g5258 From 88427588993db079a1b2cdbcba69f3c162f8ee21 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Thu, 29 Nov 2012 23:27:15 +0100 Subject: ath9k: use SIMPLE_DEV_PM_OPS ath9k does not provide any runtime pm callbacks, so support for PM_RUNTIME is not needed and we could go to PM_SLEEP. This also makes it possible to use SIMPLE_DEV_PM_OPS instead of manually filling struct dev_pm_ops. Signed-off-by: Hauke Mehrtens Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/pci.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index 9553203ee62..8e9b826f878 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -287,7 +287,7 @@ static void ath_pci_remove(struct pci_dev *pdev) pci_release_region(pdev, 0); } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int ath_pci_suspend(struct device *device) { @@ -333,22 +333,15 @@ static int ath_pci_resume(struct device *device) return 0; } -static const struct dev_pm_ops ath9k_pm_ops = { - .suspend = ath_pci_suspend, - .resume = ath_pci_resume, - .freeze = ath_pci_suspend, - .thaw = ath_pci_resume, - .poweroff = ath_pci_suspend, - .restore = ath_pci_resume, -}; +static SIMPLE_DEV_PM_OPS(ath9k_pm_ops, ath_pci_suspend, ath_pci_resume); #define ATH9K_PM_OPS (&ath9k_pm_ops) -#else /* !CONFIG_PM */ +#else /* !CONFIG_PM_SLEEP */ #define ATH9K_PM_OPS NULL -#endif /* !CONFIG_PM */ +#endif /* !CONFIG_PM_SLEEP */ MODULE_DEVICE_TABLE(pci, ath_pci_id_table); -- cgit v1.2.3-18-g5258 From 649a6ac4a7d6eab2752893d69f722ccd9674dd4e Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sun, 2 Dec 2012 16:52:00 +0100 Subject: carl9170: fix signal strength reporting issues On A-MPDU frames, the hardware only reports valid signal strength data for the last subframe. This patch fixes it by flagging everything but the last subframe in an A-MPDU to tell mac80211 to ignore the signal strength entirely. Otherwise the empty value (= 0 dbm) will distort the average quite badly. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/ath/carl9170/rx.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/carl9170/rx.c b/drivers/net/wireless/ath/carl9170/rx.c index 6d22382875b..876a773fd0b 100644 --- a/drivers/net/wireless/ath/carl9170/rx.c +++ b/drivers/net/wireless/ath/carl9170/rx.c @@ -814,6 +814,8 @@ static void carl9170_rx_untie_data(struct ar9170 *ar, u8 *buf, int len) if (phy) carl9170_rx_phy_status(ar, phy, &status); + else + status.flag |= RX_FLAG_NO_SIGNAL_VAL; if (carl9170_handle_mpdu(ar, buf, mpdu_len, &status)) goto drop; -- cgit v1.2.3-18-g5258 From 1981e881fd32160bf886a09b12794c640aafffb3 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Mon, 3 Dec 2012 18:48:05 +0100 Subject: carl9170: explain why sta cannot be NULL for ampdus Dan Carpenter reported that smatch detected a potential problem with the code [1]: drivers/net/wireless/ath/carl9170/tx.c:1488 carl9170_op_tx() error: we previously assumed 'sta' could be null (see line 1482) drivers/net/wireless/ath/carl9170/tx.c 1482 if (sta) { ^^^^^ New check. [...] 1485 } 1487 if (info->flags & IEEE80211_TX_CTL_AMPDU) { 1488 run = carl9170_tx_ampdu_queue(ar, sta, skb); ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Old dereference of "sta" inside the call to carl9170_tx_ampdu_queue(). A range of solutions have been discussed in [2] and we agreed on the following: " > we might as well add a comment to carl9170_tx_ampdu_queue > and explain the situation [in a way that's obvious to a > human reader]. This way we can save the "if"... which is > a small win since carl9170_op_tx is sort of a hot-path. Putting a comment there is fine. Without the comment it's easy for a human reader to get confused why the check is there. So long as humans can read the code, that's all that matters." [1] [2] Reported-by: Dan Carpenter Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/ath/carl9170/tx.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/carl9170/tx.c b/drivers/net/wireless/ath/carl9170/tx.c index 84377cf580e..ef4ec0da6e4 100644 --- a/drivers/net/wireless/ath/carl9170/tx.c +++ b/drivers/net/wireless/ath/carl9170/tx.c @@ -1485,6 +1485,13 @@ void carl9170_op_tx(struct ieee80211_hw *hw, } if (info->flags & IEEE80211_TX_CTL_AMPDU) { + /* to static code analyzers and reviewers: + * mac80211 guarantees that a valid "sta" + * reference is present, if a frame is to + * be part of an ampdu. Hence any extra + * sta == NULL checks are redundant in this + * special case. + */ run = carl9170_tx_ampdu_queue(ar, sta, skb); if (run) carl9170_tx_ampdu(ar); -- cgit v1.2.3-18-g5258 From e829cf961bfd3c2c5ef0a2c5a51734c1628ce77e Mon Sep 17 00:00:00 2001 From: Bill Pemberton Date: Mon, 3 Dec 2012 09:56:28 -0500 Subject: ath5k: remove __dev* attributes CONFIG_HOTPLUG is going away as an option. As result the __dev* markings will be going away. Remove use of __devinit, __devexit_p, __devinitdata, __devinitconst, and __devexit. Signed-off-by: Bill Pemberton Cc: Jiri Slaby Cc: Nick Kossifidis Cc: Luis R. Rodriguez Cc: linux-wireless@vger.kernel.org Cc: ath5k-devel@lists.ath5k.org Signed-off-by: Greg Kroah-Hartman Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/base.c | 4 ++-- drivers/net/wireless/ath/ath5k/led.c | 2 +- drivers/net/wireless/ath/ath5k/pci.c | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 2fd5bab2e22..3a5a61e0392 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -2435,7 +2435,7 @@ static const struct ieee80211_iface_combination if_comb = { .num_different_channels = 1, }; -int __devinit +int ath5k_init_ah(struct ath5k_hw *ah, const struct ath_bus_ops *bus_ops) { struct ieee80211_hw *hw = ah->hw; @@ -2861,7 +2861,7 @@ static void ath5k_reset_work(struct work_struct *work) mutex_unlock(&ah->lock); } -static int __devinit +static int ath5k_init(struct ieee80211_hw *hw) { diff --git a/drivers/net/wireless/ath/ath5k/led.c b/drivers/net/wireless/ath/ath5k/led.c index b9f708a45f4..f77ef36acf8 100644 --- a/drivers/net/wireless/ath/ath5k/led.c +++ b/drivers/net/wireless/ath/ath5k/led.c @@ -158,7 +158,7 @@ void ath5k_unregister_leds(struct ath5k_hw *ah) ath5k_unregister_led(&ah->tx_led); } -int __devinit ath5k_init_leds(struct ath5k_hw *ah) +int ath5k_init_leds(struct ath5k_hw *ah) { int ret = 0; struct ieee80211_hw *hw = ah->hw; diff --git a/drivers/net/wireless/ath/ath5k/pci.c b/drivers/net/wireless/ath/ath5k/pci.c index dff48fbc63b..859db7c34f8 100644 --- a/drivers/net/wireless/ath/ath5k/pci.c +++ b/drivers/net/wireless/ath/ath5k/pci.c @@ -155,7 +155,7 @@ static const struct ath_bus_ops ath_pci_bus_ops = { * PCI Initialization * \********************/ -static int __devinit +static int ath5k_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { @@ -285,7 +285,7 @@ err: return ret; } -static void __devexit +static void ath5k_pci_remove(struct pci_dev *pdev) { struct ieee80211_hw *hw = pci_get_drvdata(pdev); @@ -336,7 +336,7 @@ static struct pci_driver ath5k_pci_driver = { .name = KBUILD_MODNAME, .id_table = ath5k_pci_id_table, .probe = ath5k_pci_probe, - .remove = __devexit_p(ath5k_pci_remove), + .remove = ath5k_pci_remove, .driver.pm = ATH5K_PM_OPS, }; -- cgit v1.2.3-18-g5258 From 9c170e068636deb3e3f96114034bb711675f0faa Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 6 Dec 2012 18:40:11 +0100 Subject: Revert "ath9k_hw: Update AR9003 high_power tx gain table" This reverts commit f74b9d365ddd33a375802b064f96a5d0e99af7c0. Turns out reverting commit a240dc7b3c7463bd60cf0a9b2a90f52f78aae0fd "ath9k_hw: Updated AR9003 tx gain table for 5GHz" was not enough to bring the tx power back to normal levels on devices like the Buffalo WZR-HP-G450H, this one needs to be reverted as well. This revert improves tx power by ~10 db on that device Signed-off-by: Felix Fietkau Cc: stable@vger.kernel.org Cc: rmanohar@qca.qualcomm.com Signed-off-by: John W. Linville --- .../net/wireless/ath/ath9k/ar9003_2p2_initvals.h | 172 ++++++++++----------- 1 file changed, 86 insertions(+), 86 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h index 6f7cf49eff4..262e1e036fd 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h @@ -534,98 +534,98 @@ static const u32 ar9300_2p2_baseband_core[][2] = { static const u32 ar9300Modes_high_power_tx_gain_table_2p2[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x0000a2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352}, - {0x0000a2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584}, - {0x0000a2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800}, + {0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, + {0x0000a2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584}, + {0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800}, {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, - {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9}, - {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002}, - {0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004}, - {0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200}, - {0x0000a510, 0x16000220, 0x16000220, 0x0f000202, 0x0f000202}, - {0x0000a514, 0x1c000223, 0x1c000223, 0x12000400, 0x12000400}, - {0x0000a518, 0x21002220, 0x21002220, 0x16000402, 0x16000402}, - {0x0000a51c, 0x27002223, 0x27002223, 0x19000404, 0x19000404}, - {0x0000a520, 0x2b022220, 0x2b022220, 0x1c000603, 0x1c000603}, - {0x0000a524, 0x2f022222, 0x2f022222, 0x21000a02, 0x21000a02}, - {0x0000a528, 0x34022225, 0x34022225, 0x25000a04, 0x25000a04}, - {0x0000a52c, 0x3a02222a, 0x3a02222a, 0x28000a20, 0x28000a20}, - {0x0000a530, 0x3e02222c, 0x3e02222c, 0x2c000e20, 0x2c000e20}, - {0x0000a534, 0x4202242a, 0x4202242a, 0x30000e22, 0x30000e22}, - {0x0000a538, 0x4702244a, 0x4702244a, 0x34000e24, 0x34000e24}, - {0x0000a53c, 0x4b02244c, 0x4b02244c, 0x38001640, 0x38001640}, - {0x0000a540, 0x4e02246c, 0x4e02246c, 0x3c001660, 0x3c001660}, - {0x0000a544, 0x52022470, 0x52022470, 0x3f001861, 0x3f001861}, - {0x0000a548, 0x55022490, 0x55022490, 0x43001a81, 0x43001a81}, - {0x0000a54c, 0x59022492, 0x59022492, 0x47001a83, 0x47001a83}, - {0x0000a550, 0x5d022692, 0x5d022692, 0x4a001c84, 0x4a001c84}, - {0x0000a554, 0x61022892, 0x61022892, 0x4e001ce3, 0x4e001ce3}, - {0x0000a558, 0x65024890, 0x65024890, 0x52001ce5, 0x52001ce5}, - {0x0000a55c, 0x69024892, 0x69024892, 0x56001ce9, 0x56001ce9}, - {0x0000a560, 0x6e024c92, 0x6e024c92, 0x5a001ceb, 0x5a001ceb}, - {0x0000a564, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec}, - {0x0000a568, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec}, - {0x0000a56c, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec}, - {0x0000a570, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec}, - {0x0000a574, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec}, - {0x0000a578, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec}, - {0x0000a57c, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec}, - {0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000}, - {0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002}, - {0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004}, - {0x0000a58c, 0x10800023, 0x10800023, 0x0b800200, 0x0b800200}, - {0x0000a590, 0x16800220, 0x16800220, 0x0f800202, 0x0f800202}, - {0x0000a594, 0x1c800223, 0x1c800223, 0x12800400, 0x12800400}, - {0x0000a598, 0x21802220, 0x21802220, 0x16800402, 0x16800402}, - {0x0000a59c, 0x27802223, 0x27802223, 0x19800404, 0x19800404}, - {0x0000a5a0, 0x2b822220, 0x2b822220, 0x1c800603, 0x1c800603}, - {0x0000a5a4, 0x2f822222, 0x2f822222, 0x21800a02, 0x21800a02}, - {0x0000a5a8, 0x34822225, 0x34822225, 0x25800a04, 0x25800a04}, - {0x0000a5ac, 0x3a82222a, 0x3a82222a, 0x28800a20, 0x28800a20}, - {0x0000a5b0, 0x3e82222c, 0x3e82222c, 0x2c800e20, 0x2c800e20}, - {0x0000a5b4, 0x4282242a, 0x4282242a, 0x30800e22, 0x30800e22}, - {0x0000a5b8, 0x4782244a, 0x4782244a, 0x34800e24, 0x34800e24}, - {0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x38801640, 0x38801640}, - {0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x3c801660, 0x3c801660}, - {0x0000a5c4, 0x52822470, 0x52822470, 0x3f801861, 0x3f801861}, - {0x0000a5c8, 0x55822490, 0x55822490, 0x43801a81, 0x43801a81}, - {0x0000a5cc, 0x59822492, 0x59822492, 0x47801a83, 0x47801a83}, - {0x0000a5d0, 0x5d822692, 0x5d822692, 0x4a801c84, 0x4a801c84}, - {0x0000a5d4, 0x61822892, 0x61822892, 0x4e801ce3, 0x4e801ce3}, - {0x0000a5d8, 0x65824890, 0x65824890, 0x52801ce5, 0x52801ce5}, - {0x0000a5dc, 0x69824892, 0x69824892, 0x56801ce9, 0x56801ce9}, - {0x0000a5e0, 0x6e824c92, 0x6e824c92, 0x5a801ceb, 0x5a801ceb}, - {0x0000a5e4, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec}, - {0x0000a5e8, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec}, - {0x0000a5ec, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec}, - {0x0000a5f0, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec}, - {0x0000a5f4, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec}, - {0x0000a5f8, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec}, - {0x0000a5fc, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec}, + {0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9}, + {0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000}, + {0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002}, + {0x0000a508, 0x09002421, 0x09002421, 0x08000004, 0x08000004}, + {0x0000a50c, 0x0d002621, 0x0d002621, 0x0b000200, 0x0b000200}, + {0x0000a510, 0x13004620, 0x13004620, 0x0f000202, 0x0f000202}, + {0x0000a514, 0x19004a20, 0x19004a20, 0x11000400, 0x11000400}, + {0x0000a518, 0x1d004e20, 0x1d004e20, 0x15000402, 0x15000402}, + {0x0000a51c, 0x21005420, 0x21005420, 0x19000404, 0x19000404}, + {0x0000a520, 0x26005e20, 0x26005e20, 0x1b000603, 0x1b000603}, + {0x0000a524, 0x2b005e40, 0x2b005e40, 0x1f000a02, 0x1f000a02}, + {0x0000a528, 0x2f005e42, 0x2f005e42, 0x23000a04, 0x23000a04}, + {0x0000a52c, 0x33005e44, 0x33005e44, 0x26000a20, 0x26000a20}, + {0x0000a530, 0x38005e65, 0x38005e65, 0x2a000e20, 0x2a000e20}, + {0x0000a534, 0x3c005e69, 0x3c005e69, 0x2e000e22, 0x2e000e22}, + {0x0000a538, 0x40005e6b, 0x40005e6b, 0x31000e24, 0x31000e24}, + {0x0000a53c, 0x44005e6d, 0x44005e6d, 0x34001640, 0x34001640}, + {0x0000a540, 0x49005e72, 0x49005e72, 0x38001660, 0x38001660}, + {0x0000a544, 0x4e005eb2, 0x4e005eb2, 0x3b001861, 0x3b001861}, + {0x0000a548, 0x53005f12, 0x53005f12, 0x3e001a81, 0x3e001a81}, + {0x0000a54c, 0x59025eb2, 0x59025eb2, 0x42001a83, 0x42001a83}, + {0x0000a550, 0x5e025f12, 0x5e025f12, 0x44001c84, 0x44001c84}, + {0x0000a554, 0x61027f12, 0x61027f12, 0x48001ce3, 0x48001ce3}, + {0x0000a558, 0x6702bf12, 0x6702bf12, 0x4c001ce5, 0x4c001ce5}, + {0x0000a55c, 0x6b02bf14, 0x6b02bf14, 0x50001ce9, 0x50001ce9}, + {0x0000a560, 0x6f02bf16, 0x6f02bf16, 0x54001ceb, 0x54001ceb}, + {0x0000a564, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a568, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a56c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a570, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a574, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a578, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a57c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a580, 0x00802220, 0x00802220, 0x00800000, 0x00800000}, + {0x0000a584, 0x04802222, 0x04802222, 0x04800002, 0x04800002}, + {0x0000a588, 0x09802421, 0x09802421, 0x08800004, 0x08800004}, + {0x0000a58c, 0x0d802621, 0x0d802621, 0x0b800200, 0x0b800200}, + {0x0000a590, 0x13804620, 0x13804620, 0x0f800202, 0x0f800202}, + {0x0000a594, 0x19804a20, 0x19804a20, 0x11800400, 0x11800400}, + {0x0000a598, 0x1d804e20, 0x1d804e20, 0x15800402, 0x15800402}, + {0x0000a59c, 0x21805420, 0x21805420, 0x19800404, 0x19800404}, + {0x0000a5a0, 0x26805e20, 0x26805e20, 0x1b800603, 0x1b800603}, + {0x0000a5a4, 0x2b805e40, 0x2b805e40, 0x1f800a02, 0x1f800a02}, + {0x0000a5a8, 0x2f805e42, 0x2f805e42, 0x23800a04, 0x23800a04}, + {0x0000a5ac, 0x33805e44, 0x33805e44, 0x26800a20, 0x26800a20}, + {0x0000a5b0, 0x38805e65, 0x38805e65, 0x2a800e20, 0x2a800e20}, + {0x0000a5b4, 0x3c805e69, 0x3c805e69, 0x2e800e22, 0x2e800e22}, + {0x0000a5b8, 0x40805e6b, 0x40805e6b, 0x31800e24, 0x31800e24}, + {0x0000a5bc, 0x44805e6d, 0x44805e6d, 0x34801640, 0x34801640}, + {0x0000a5c0, 0x49805e72, 0x49805e72, 0x38801660, 0x38801660}, + {0x0000a5c4, 0x4e805eb2, 0x4e805eb2, 0x3b801861, 0x3b801861}, + {0x0000a5c8, 0x53805f12, 0x53805f12, 0x3e801a81, 0x3e801a81}, + {0x0000a5cc, 0x59825eb2, 0x59825eb2, 0x42801a83, 0x42801a83}, + {0x0000a5d0, 0x5e825f12, 0x5e825f12, 0x44801c84, 0x44801c84}, + {0x0000a5d4, 0x61827f12, 0x61827f12, 0x48801ce3, 0x48801ce3}, + {0x0000a5d8, 0x6782bf12, 0x6782bf12, 0x4c801ce5, 0x4c801ce5}, + {0x0000a5dc, 0x6b82bf14, 0x6b82bf14, 0x50801ce9, 0x50801ce9}, + {0x0000a5e0, 0x6f82bf16, 0x6f82bf16, 0x54801ceb, 0x54801ceb}, + {0x0000a5e4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5e8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5ec, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5f0, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5f4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5f8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5fc, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a610, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a614, 0x02004000, 0x02004000, 0x01404000, 0x01404000}, - {0x0000a618, 0x02004801, 0x02004801, 0x01404501, 0x01404501}, - {0x0000a61c, 0x02808a02, 0x02808a02, 0x02008501, 0x02008501}, - {0x0000a620, 0x0380ce03, 0x0380ce03, 0x0280ca03, 0x0280ca03}, - {0x0000a624, 0x04411104, 0x04411104, 0x03010c04, 0x03010c04}, - {0x0000a628, 0x04411104, 0x04411104, 0x04014c04, 0x04014c04}, - {0x0000a62c, 0x04411104, 0x04411104, 0x04015005, 0x04015005}, - {0x0000a630, 0x04411104, 0x04411104, 0x04015005, 0x04015005}, - {0x0000a634, 0x04411104, 0x04411104, 0x04015005, 0x04015005}, - {0x0000a638, 0x04411104, 0x04411104, 0x04015005, 0x04015005}, - {0x0000a63c, 0x04411104, 0x04411104, 0x04015005, 0x04015005}, - {0x0000b2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352}, - {0x0000b2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584}, - {0x0000b2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800}, + {0x0000a610, 0x00804000, 0x00804000, 0x00000000, 0x00000000}, + {0x0000a614, 0x00804201, 0x00804201, 0x01404000, 0x01404000}, + {0x0000a618, 0x0280c802, 0x0280c802, 0x01404501, 0x01404501}, + {0x0000a61c, 0x0280ca03, 0x0280ca03, 0x02008501, 0x02008501}, + {0x0000a620, 0x04c15104, 0x04c15104, 0x0280ca03, 0x0280ca03}, + {0x0000a624, 0x04c15305, 0x04c15305, 0x03010c04, 0x03010c04}, + {0x0000a628, 0x04c15305, 0x04c15305, 0x04014c04, 0x04014c04}, + {0x0000a62c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, + {0x0000a630, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, + {0x0000a634, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, + {0x0000a638, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, + {0x0000a63c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, + {0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, + {0x0000b2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584}, + {0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800}, {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, - {0x0000c2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352}, - {0x0000c2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584}, - {0x0000c2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800}, + {0x0000c2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, + {0x0000c2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584}, + {0x0000c2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800}, {0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, {0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, {0x00016048, 0x66480001, 0x66480001, 0x66480001, 0x66480001}, -- cgit v1.2.3-18-g5258 From 4f7dc951e2dad489fb89b03d3f968d3a229dc9ec Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 7 Dec 2012 20:25:30 +0530 Subject: ath9k: Fix regression in 'xmit' debugfs file Commit "ath9k: Fix the 'xmit' debugfs file" changed the the array size of ath_stats.txstats to IEEE80211_NUM_ACS, which is wrong because the HW queue number is used to update the statistics. Revert back to using ATH9K_NUM_TX_QUEUES. Reported-by: Felix Fietkau Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/debug.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h index 72d4893311b..375c3b46411 100644 --- a/drivers/net/wireless/ath/ath9k/debug.h +++ b/drivers/net/wireless/ath/ath9k/debug.h @@ -242,7 +242,7 @@ struct ath_rx_stats { struct ath_stats { struct ath_interrupt_stats istats; - struct ath_tx_stats txstats[IEEE80211_NUM_ACS]; + struct ath_tx_stats txstats[ATH9K_NUM_TX_QUEUES]; struct ath_rx_stats rxstats; struct ath_dfs_stats dfs_stats; u32 reset[__RESET_TYPE_MAX]; -- cgit v1.2.3-18-g5258 From fc5e286ff4ff6da3e76e6eb58c535e250ad2ff18 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 8 Dec 2012 15:24:56 +0100 Subject: carl9170: fix copy and paste mishap in carl9170_handle_mpdu This patch fixes a regression which was introduced by: "carl9170: split up carl9170_handle_mpdu" Previously, the ieee80211_rx_status was kept on the stack of carl9170_handle_mpdu. Now it's passed into the function as a pointer parameter. Hence, the old memcpy call needs to be fixed. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/ath/carl9170/rx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/carl9170/rx.c b/drivers/net/wireless/ath/carl9170/rx.c index 876a773fd0b..4684dd98949 100644 --- a/drivers/net/wireless/ath/carl9170/rx.c +++ b/drivers/net/wireless/ath/carl9170/rx.c @@ -684,7 +684,7 @@ static int carl9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len, if (!skb) return -ENOMEM; - memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status)); + memcpy(IEEE80211_SKB_RXCB(skb), status, sizeof(*status)); ieee80211_rx(ar->hw, skb); return 0; } -- cgit v1.2.3-18-g5258 From b3cd8021379306c0be6932e4d3b4b01efc681769 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Sun, 9 Dec 2012 23:57:09 +0100 Subject: ath9k: ar9003: fix OTP register offsets for AR9340 Trying to access the OTP memory on the AR9340 causes a data bus error like this: Data bus error, epc == 86e84164, ra == 86e84164 Oops[#1]: Cpu 0 $ 0 : 00000000 00000061 deadc0de 00000000 $ 4 : b8115f18 00015f18 00000007 00000004 $ 8 : 00000001 7c7c3c7c 7c7c7c7c 7c7c7c7c $12 : 7c7c3c7c 001f0041 00000000 7c7c7c3c $16 : 86ee0000 00015f18 00000000 00000007 $20 : 00000004 00000064 00000004 86d71c44 $24 : 00000000 86e6ca00 $28 : 86d70000 86d71b20 86ece0c0 86e84164 Hi : 00000000 Lo : 00000064 epc : 86e84164 ath9k_hw_wait+0x58/0xb0 [ath9k_hw] Tainted: G O ra : 86e84164 ath9k_hw_wait+0x58/0xb0 [ath9k_hw] Status: 1100d403 KERNEL EXL IE Cause : 4080801c PrId : 0001974c (MIPS 74Kc) Modules linked in: ath9k(O+) ath9k_common(O) ath9k_hw(O) ath(O) ar934x_nfc mac80211(O) usbcore usb_common scsi_mod nls_base nand nand_ecc nand_ids crc_ccitt cfg80211(O) compat(O) arc4 aes_generic crypto_blkcipher cryptomgr aead crypto_hash crypto_algapi ledtrig_timer ledtrig_default_on leds_gpio Process insmod (pid: 459, threadinfo=86d70000, task=87942140, tls=779ac440) Stack : 802fb500 000200da 804db150 804e0000 87816130 86ee0000 00010000 86d71b88 86d71bc0 00000004 00000003 86e9fcd0 80305300 0002c0d0 86e74c50 800b4c20 000003e8 00000001 00000000 86ee0000 000003ff 86e9fd64 80305300 80123938 fffffffc 00000004 000058bc 00000000 86ea0000 86ee0000 000001ff 878d6000 99999999 86e9fdc0 86ee0fcc 86e9e664 0000c0d0 86ee0000 0000700000007000 ... Call Trace: [<86e84164>] ath9k_hw_wait+0x58/0xb0 [ath9k_hw] [<86e9fcd0>] ath9k_hw_setup_statusring+0x16b8/0x1c7c [ath9k_hw] Code: 0000a812 0040f809 00000000 <00531024> 1054000b 24020001 0c05b5dc 2404000a 26520001 The cause of the error is that the OTP register offsets are different on the AR9340 than the actually used values. Cc: # 3.0+ Signed-off-by: Gabor Juhos Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_eeprom.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h index 41b1a75e6be..54ba42f4108 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h @@ -68,13 +68,13 @@ #define AR9300_BASE_ADDR 0x3ff #define AR9300_BASE_ADDR_512 0x1ff -#define AR9300_OTP_BASE 0x14000 -#define AR9300_OTP_STATUS 0x15f18 +#define AR9300_OTP_BASE (AR_SREV_9340(ah) ? 0x30000 : 0x14000) +#define AR9300_OTP_STATUS (AR_SREV_9340(ah) ? 0x30018 : 0x15f18) #define AR9300_OTP_STATUS_TYPE 0x7 #define AR9300_OTP_STATUS_VALID 0x4 #define AR9300_OTP_STATUS_ACCESS_BUSY 0x2 #define AR9300_OTP_STATUS_SM_BUSY 0x1 -#define AR9300_OTP_READ_DATA 0x15f1c +#define AR9300_OTP_READ_DATA (AR_SREV_9340(ah) ? 0x3001c : 0x15f1c) enum targetPowerHTRates { HT_TARGET_RATE_0_8_16, -- cgit v1.2.3-18-g5258 From b8a95db7df48b5b2d378ff526f674c877c7fa8a1 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Mon, 10 Dec 2012 07:22:31 +0530 Subject: ath9k_hw: Fix PAPRD registers for AR9485 Various PAPRD registers are at addresses that are different from those for the rest of the chips in the AR9003 family. Fix them. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_phy.h | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h index 4c3d06de711..10795629848 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h @@ -1145,9 +1145,8 @@ #define AR_PHY_PAPRD_CTRL1_PAPRD_MAG_SCALE_FACT 0x0ffe0000 #define AR_PHY_PAPRD_CTRL1_PAPRD_MAG_SCALE_FACT_S 17 -#define AR_PHY_PAPRD_TRAINER_CNTL1 (AR_SM_BASE + \ - (AR_SREV_9485(ah) ? \ - 0x580 : 0x490)) +#define AR_PHY_PAPRD_TRAINER_CNTL1 (AR_SM_BASE + (AR_SREV_9485(ah) ? 0x580 : 0x490)) + #define AR_PHY_PAPRD_TRAINER_CNTL1_CF_CF_PAPRD_TRAIN_ENABLE 0x00000001 #define AR_PHY_PAPRD_TRAINER_CNTL1_CF_CF_PAPRD_TRAIN_ENABLE_S 0 #define AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_AGC2_SETTLING 0x0000007e @@ -1163,15 +1162,13 @@ #define AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_LB_SKIP 0x0003f000 #define AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_LB_SKIP_S 12 -#define AR_PHY_PAPRD_TRAINER_CNTL2 (AR_SM_BASE + \ - (AR_SREV_9485(ah) ? \ - 0x584 : 0x494)) +#define AR_PHY_PAPRD_TRAINER_CNTL2 (AR_SM_BASE + (AR_SREV_9485(ah) ? 0x584 : 0x494)) + #define AR_PHY_PAPRD_TRAINER_CNTL2_CF_PAPRD_INIT_RX_BB_GAIN 0xFFFFFFFF #define AR_PHY_PAPRD_TRAINER_CNTL2_CF_PAPRD_INIT_RX_BB_GAIN_S 0 -#define AR_PHY_PAPRD_TRAINER_CNTL3 (AR_SM_BASE + \ - (AR_SREV_9485(ah) ? \ - 0x588 : 0x498)) +#define AR_PHY_PAPRD_TRAINER_CNTL3 (AR_SM_BASE + (AR_SREV_9485(ah) ? 0x588 : 0x498)) + #define AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_ADC_DESIRED_SIZE 0x0000003f #define AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_ADC_DESIRED_SIZE_S 0 #define AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP 0x00000fc0 @@ -1187,9 +1184,8 @@ #define AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_BBTXMIX_DISABLE 0x20000000 #define AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_BBTXMIX_DISABLE_S 29 -#define AR_PHY_PAPRD_TRAINER_CNTL4 (AR_SM_BASE + \ - (AR_SREV_9485(ah) ? \ - 0x58c : 0x49c)) +#define AR_PHY_PAPRD_TRAINER_CNTL4 (AR_SM_BASE + (AR_SREV_9485(ah) ? 0x58c : 0x49c)) + #define AR_PHY_PAPRD_TRAINER_CNTL4_CF_PAPRD_NUM_TRAIN_SAMPLES 0x03ff0000 #define AR_PHY_PAPRD_TRAINER_CNTL4_CF_PAPRD_NUM_TRAIN_SAMPLES_S 16 #define AR_PHY_PAPRD_TRAINER_CNTL4_CF_PAPRD_SAFETY_DELTA 0x0000f000 @@ -1208,7 +1204,8 @@ #define AR_PHY_PAPRD_PRE_POST_SCALING 0x3FFFF #define AR_PHY_PAPRD_PRE_POST_SCALING_S 0 -#define AR_PHY_PAPRD_TRAINER_STAT1 (AR_SM_BASE + 0x4a0) +#define AR_PHY_PAPRD_TRAINER_STAT1 (AR_SM_BASE + (AR_SREV_9485(ah) ? 0x590 : 0x4a0)) + #define AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE 0x00000001 #define AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE_S 0 #define AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_INCOMPLETE 0x00000002 @@ -1222,7 +1219,8 @@ #define AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_AGC2_PWR 0x0001fe00 #define AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_AGC2_PWR_S 9 -#define AR_PHY_PAPRD_TRAINER_STAT2 (AR_SM_BASE + 0x4a4) +#define AR_PHY_PAPRD_TRAINER_STAT2 (AR_SM_BASE + (AR_SREV_9485(ah) ? 0x594 : 0x4a4)) + #define AR_PHY_PAPRD_TRAINER_STAT2_PAPRD_FINE_VAL 0x0000ffff #define AR_PHY_PAPRD_TRAINER_STAT2_PAPRD_FINE_VAL_S 0 #define AR_PHY_PAPRD_TRAINER_STAT2_PAPRD_COARSE_IDX 0x001f0000 @@ -1230,7 +1228,8 @@ #define AR_PHY_PAPRD_TRAINER_STAT2_PAPRD_FINE_IDX 0x00600000 #define AR_PHY_PAPRD_TRAINER_STAT2_PAPRD_FINE_IDX_S 21 -#define AR_PHY_PAPRD_TRAINER_STAT3 (AR_SM_BASE + 0x4a8) +#define AR_PHY_PAPRD_TRAINER_STAT3 (AR_SM_BASE + (AR_SREV_9485(ah) ? 0x598 : 0x4a8)) + #define AR_PHY_PAPRD_TRAINER_STAT3_PAPRD_TRAIN_SAMPLES_CNT 0x000fffff #define AR_PHY_PAPRD_TRAINER_STAT3_PAPRD_TRAIN_SAMPLES_CNT_S 0 -- cgit v1.2.3-18-g5258 From 8c723e2df2411eb02e697efb31f309136b747f7a Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Mon, 10 Dec 2012 07:22:32 +0530 Subject: ath9k_hw: Fix PAPRD training The PAPRD training control registers have to be programmed with values that depend on the chip. This patch ensures that the correct values are chosen for the chip in use. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_paprd.c | 36 +++++++++++++++++++++------ 1 file changed, 29 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_paprd.c b/drivers/net/wireless/ath/ath9k/ar9003_paprd.c index 0ed3846f9cb..df9158f53fe 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_paprd.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_paprd.c @@ -204,7 +204,20 @@ static int ar9003_paprd_setup_single_table(struct ath_hw *ah) AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_AGC2_SETTLING, 28); REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1, AR_PHY_PAPRD_TRAINER_CNTL1_CF_CF_PAPRD_TRAIN_ENABLE, 1); - val = AR_SREV_9462(ah) ? 0x91 : 147; + + if (AR_SREV_9485(ah)) { + val = 148; + } else { + if (IS_CHAN_2GHZ(ah->curchan)) { + if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) + val = 145; + else + val = 147; + } else { + val = 137; + } + } + REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL2, AR_PHY_PAPRD_TRAINER_CNTL2_CF_PAPRD_INIT_RX_BB_GAIN, val); REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3, @@ -215,15 +228,24 @@ static int ar9003_paprd_setup_single_table(struct ath_hw *ah) AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_NUM_CORR_STAGES, 7); REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3, AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_MIN_LOOPBACK_DEL, 1); - if (AR_SREV_9485(ah) || AR_SREV_9462(ah) || AR_SREV_9550(ah)) + + if (AR_SREV_9485(ah) || + AR_SREV_9462(ah) || + AR_SREV_9565(ah) || + AR_SREV_9550(ah) || + AR_SREV_9330(ah) || + AR_SREV_9340(ah)) REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3, - AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP, - -3); + AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP, -3); else REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3, - AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP, - -6); - val = AR_SREV_9462(ah) ? -10 : -15; + AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP, -6); + + val = -10; + + if (IS_CHAN_2GHZ(ah->curchan) && !AR_SREV_9462(ah) && !AR_SREV_9565(ah)) + val = -15; + REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3, AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_ADC_DESIRED_SIZE, val); -- cgit v1.2.3-18-g5258 From 914d0f4def3817c295d3e8cbb7ea53bef8b0efcb Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Mon, 10 Dec 2012 07:22:33 +0530 Subject: ath9k: Add a few debug messages for PAPRD Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_paprd.c | 3 +++ drivers/net/wireless/ath/ath9k/link.c | 10 ++++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_paprd.c b/drivers/net/wireless/ath/ath9k/ar9003_paprd.c index df9158f53fe..4945fdf61ba 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_paprd.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_paprd.c @@ -169,6 +169,9 @@ static int ar9003_paprd_setup_single_table(struct ath_hw *ah) REG_RMW_FIELD(ah, AR_PHY_PAPRD_HT40, AR_PHY_PAPRD_HT40_MASK, ah->paprd_ratemask_ht40); + ath_dbg(common, CALIBRATE, "PAPRD HT20 mask: 0x%x, HT40 mask: 0x%x\n", + ah->paprd_ratemask, ah->paprd_ratemask_ht40); + for (i = 0; i < ah->caps.max_txchains; i++) { REG_RMW_FIELD(ah, ctrl0[i], AR_PHY_PAPRD_CTRL0_USE_SINGLE_TABLE_MASK, 1); diff --git a/drivers/net/wireless/ath/ath9k/link.c b/drivers/net/wireless/ath/ath9k/link.c index fc6b075ad63..3c996ffe63c 100644 --- a/drivers/net/wireless/ath/ath9k/link.c +++ b/drivers/net/wireless/ath/ath9k/link.c @@ -179,11 +179,14 @@ void ath_rx_poll(unsigned long data) static void ath_paprd_activate(struct ath_softc *sc) { struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); struct ath9k_hw_cal_data *caldata = ah->caldata; int chain; - if (!caldata || !caldata->paprd_done) + if (!caldata || !caldata->paprd_done) { + ath_dbg(common, CALIBRATE, "Failed to activate PAPRD\n"); return; + } ath9k_ps_wakeup(sc); ar9003_paprd_enable(ah, false); @@ -194,6 +197,7 @@ static void ath_paprd_activate(struct ath_softc *sc) ar9003_paprd_populate_single_table(ah, caldata, chain); } + ath_dbg(common, CALIBRATE, "Activating PAPRD\n"); ar9003_paprd_enable(ah, true); ath9k_ps_restore(sc); } @@ -253,8 +257,10 @@ void ath_paprd_calibrate(struct work_struct *work) int len = 1800; int ret; - if (!caldata || !caldata->paprd_packet_sent || caldata->paprd_done) + if (!caldata || !caldata->paprd_packet_sent || caldata->paprd_done) { + ath_dbg(common, CALIBRATE, "Skipping PAPRD calibration\n"); return; + } ath9k_ps_wakeup(sc); -- cgit v1.2.3-18-g5258 From 19f7842240eb30b1fdf4eacdd444bc9f61f97382 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Mon, 10 Dec 2012 07:22:34 +0530 Subject: ath9k: Fix redundant PS wrappers Move the PowerSave wrappers outside ath_paprd_activate(), since they are already being used in ath_paprd_calibrate(). Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/link.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/link.c b/drivers/net/wireless/ath/ath9k/link.c index 3c996ffe63c..c70b31a7255 100644 --- a/drivers/net/wireless/ath/ath9k/link.c +++ b/drivers/net/wireless/ath/ath9k/link.c @@ -188,7 +188,6 @@ static void ath_paprd_activate(struct ath_softc *sc) return; } - ath9k_ps_wakeup(sc); ar9003_paprd_enable(ah, false); for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) { if (!(ah->txchainmask & BIT(chain))) @@ -199,7 +198,6 @@ static void ath_paprd_activate(struct ath_softc *sc) ath_dbg(common, CALIBRATE, "Activating PAPRD\n"); ar9003_paprd_enable(ah, true); - ath9k_ps_restore(sc); } static bool ath_paprd_send_frame(struct ath_softc *sc, struct sk_buff *skb, int chain) @@ -436,11 +434,15 @@ set_timer: cal_interval = min(cal_interval, (u32)short_cal_interval); mod_timer(&common->ani.timer, jiffies + msecs_to_jiffies(cal_interval)); + if (ah->eep_ops->get_eeprom(ah, EEP_PAPRD) && ah->caldata) { - if (!ah->caldata->paprd_done) + if (!ah->caldata->paprd_done) { ieee80211_queue_work(sc->hw, &sc->paprd_work); - else if (!ah->paprd_table_write_done) + } else if (!ah->paprd_table_write_done) { + ath9k_ps_wakeup(sc); ath_paprd_activate(sc); + ath9k_ps_restore(sc); + } } } -- cgit v1.2.3-18-g5258 From 36d2943ba738a601e29cbd86fa6ab6ac838f3905 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Mon, 10 Dec 2012 07:22:35 +0530 Subject: ath9k_hw: Various trivial fixes for PAPRD * Remove unneeded memset. All the values in the PAPRD gain table are filled, so there is no need to zero out the arrays. * Use GFP_KERNEL in ar9003_paprd_create_curve This is called from the PAPRD work, so the atomic variant is not needed. * Change return type of ar9003_paprd_setup_gain_table Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_paprd.c | 9 ++------- drivers/net/wireless/ath/ath9k/hw.h | 2 +- 2 files changed, 3 insertions(+), 8 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_paprd.c b/drivers/net/wireless/ath/ath9k/ar9003_paprd.c index 4945fdf61ba..b28565e8078 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_paprd.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_paprd.c @@ -287,9 +287,6 @@ static void ar9003_paprd_get_gain_table(struct ath_hw *ah) u32 reg = AR_PHY_TXGAIN_TABLE; int i; - memset(entry, 0, sizeof(ah->paprd_gain_table_entries)); - memset(index, 0, sizeof(ah->paprd_gain_table_index)); - for (i = 0; i < PAPRD_GAIN_TABLE_ENTRIES; i++) { entry[i] = REG_READ(ah, reg); index[i] = (entry[i] >> 24) & 0xff; @@ -788,7 +785,7 @@ void ar9003_paprd_populate_single_table(struct ath_hw *ah, } EXPORT_SYMBOL(ar9003_paprd_populate_single_table); -int ar9003_paprd_setup_gain_table(struct ath_hw *ah, int chain) +void ar9003_paprd_setup_gain_table(struct ath_hw *ah, int chain) { unsigned int i, desired_gain, gain_index; unsigned int train_power = ah->paprd_training_power; @@ -806,8 +803,6 @@ int ar9003_paprd_setup_gain_table(struct ath_hw *ah, int chain) REG_CLR_BIT(ah, AR_PHY_PAPRD_TRAINER_STAT1, AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE); - - return 0; } EXPORT_SYMBOL(ar9003_paprd_setup_gain_table); @@ -919,7 +914,7 @@ int ar9003_paprd_create_curve(struct ath_hw *ah, memset(caldata->pa_table[chain], 0, sizeof(caldata->pa_table[chain])); - buf = kmalloc(2 * 48 * sizeof(u32), GFP_ATOMIC); + buf = kmalloc(2 * 48 * sizeof(u32), GFP_KERNEL); if (!buf) return -ENOMEM; diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 3636dabf03e..fe87d0e67a1 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -1058,7 +1058,7 @@ void ar9003_paprd_populate_single_table(struct ath_hw *ah, int chain); int ar9003_paprd_create_curve(struct ath_hw *ah, struct ath9k_hw_cal_data *caldata, int chain); -int ar9003_paprd_setup_gain_table(struct ath_hw *ah, int chain); +void ar9003_paprd_setup_gain_table(struct ath_hw *ah, int chain); int ar9003_paprd_init_table(struct ath_hw *ah); bool ar9003_paprd_is_done(struct ath_hw *ah); -- cgit v1.2.3-18-g5258 From d882d242e4bfb2016e611a5aab0112fcece7a8ac Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Mon, 10 Dec 2012 07:22:36 +0530 Subject: ath9k_hw: Fix PAPRD retraining for AR9485 Retraining of PAPRD based on agc2_pwr is required for chips other than AR9485. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_paprd.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_paprd.c b/drivers/net/wireless/ath/ath9k/ar9003_paprd.c index b28565e8078..fb3a87eeb67 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_paprd.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_paprd.c @@ -965,9 +965,13 @@ EXPORT_SYMBOL(ar9003_paprd_init_table); bool ar9003_paprd_is_done(struct ath_hw *ah) { int paprd_done, agc2_pwr; + paprd_done = REG_READ_FIELD(ah, AR_PHY_PAPRD_TRAINER_STAT1, AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE); + if (AR_SREV_9485(ah)) + goto exit; + if (paprd_done == 0x1) { agc2_pwr = REG_READ_FIELD(ah, AR_PHY_PAPRD_TRAINER_STAT1, AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_AGC2_PWR); @@ -983,7 +987,7 @@ bool ar9003_paprd_is_done(struct ath_hw *ah) if (agc2_pwr <= PAPRD_IDEAL_AGC2_PWR_RANGE) paprd_done = 0; } - +exit: return !!paprd_done; } EXPORT_SYMBOL(ar9003_paprd_is_done); -- cgit v1.2.3-18-g5258 From 0f21ee8d9c8a041b974cfb75d81d07b61bd0869f Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Mon, 10 Dec 2012 07:22:37 +0530 Subject: ath9k_hw: Add HW cap for PAPRD Add a HW capability to indicate whether PAPRD is enabled for the card, since PAPRD could be enabled in the EEPROM, but disabled in the driver. This makes things clearer. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_eeprom.c | 8 ++------ drivers/net/wireless/ath/ath9k/ar9003_paprd.c | 9 +++++++++ drivers/net/wireless/ath/ath9k/hw.c | 4 ++++ drivers/net/wireless/ath/ath9k/hw.h | 2 ++ drivers/net/wireless/ath/ath9k/link.c | 2 +- 5 files changed, 18 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index c86cb640004..6b8861c559e 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -2987,10 +2987,6 @@ static u32 ath9k_hw_ar9300_get_eeprom(struct ath_hw *ah, case EEP_RX_MASK: return pBase->txrxMask & 0xf; case EEP_PAPRD: - if (AR_SREV_9462(ah)) - return false; - if (!ah->config.enable_paprd) - return false; return !!(pBase->featureEnable & BIT(5)); case EEP_CHAIN_MASK_REDUCE: return (pBase->miscConfiguration >> 0x3) & 0x1; @@ -5097,7 +5093,7 @@ static void ath9k_hw_ar9300_set_txpower(struct ath_hw *ah, */ ar9003_hw_get_target_power_eeprom(ah, chan, targetPowerValT2); - if (ah->eep_ops->get_eeprom(ah, EEP_PAPRD)) { + if (ar9003_is_paprd_enabled(ah)) { if (IS_CHAN_2GHZ(chan)) modal_hdr = &eep->modalHeader2G; else @@ -5138,7 +5134,7 @@ static void ath9k_hw_ar9300_set_txpower(struct ath_hw *ah, twiceAntennaReduction, powerLimit); - if (ah->eep_ops->get_eeprom(ah, EEP_PAPRD)) { + if (ar9003_is_paprd_enabled(ah)) { for (i = 0; i < ar9300RateSize; i++) { if ((ah->paprd_ratemask & (1 << i)) && (abs(targetPowerValT2[i] - diff --git a/drivers/net/wireless/ath/ath9k/ar9003_paprd.c b/drivers/net/wireless/ath/ath9k/ar9003_paprd.c index fb3a87eeb67..aea19088314 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_paprd.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_paprd.c @@ -991,3 +991,12 @@ exit: return !!paprd_done; } EXPORT_SYMBOL(ar9003_paprd_is_done); + +bool ar9003_is_paprd_enabled(struct ath_hw *ah) +{ + if ((ah->caps.hw_caps & ATH9K_HW_CAP_PAPRD) && ah->config.enable_paprd) + return true; + + return false; +} +EXPORT_SYMBOL(ar9003_is_paprd_enabled); diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index e06bcec655a..7cb78706591 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -2599,6 +2599,10 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) pCap->hw_caps |= ATH9K_HW_WOW_PATTERN_MATCH_DWORD; } + if (AR_SREV_9300_20_OR_LATER(ah) && + ah->eep_ops->get_eeprom(ah, EEP_PAPRD)) + pCap->hw_caps |= ATH9K_HW_CAP_PAPRD; + return 0; } diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index fe87d0e67a1..eff67592db1 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -247,6 +247,7 @@ enum ath9k_hw_caps { ATH9K_HW_WOW_DEVICE_CAPABLE = BIT(17), ATH9K_HW_WOW_PATTERN_MATCH_EXACT = BIT(18), ATH9K_HW_WOW_PATTERN_MATCH_DWORD = BIT(19), + ATH9K_HW_CAP_PAPRD = BIT(20), }; /* @@ -1061,6 +1062,7 @@ int ar9003_paprd_create_curve(struct ath_hw *ah, void ar9003_paprd_setup_gain_table(struct ath_hw *ah, int chain); int ar9003_paprd_init_table(struct ath_hw *ah); bool ar9003_paprd_is_done(struct ath_hw *ah); +bool ar9003_is_paprd_enabled(struct ath_hw *ah); /* Hardware family op attach helpers */ void ar5008_hw_attach_phy_ops(struct ath_hw *ah); diff --git a/drivers/net/wireless/ath/ath9k/link.c b/drivers/net/wireless/ath/ath9k/link.c index c70b31a7255..ade3afb21f9 100644 --- a/drivers/net/wireless/ath/ath9k/link.c +++ b/drivers/net/wireless/ath/ath9k/link.c @@ -435,7 +435,7 @@ set_timer: mod_timer(&common->ani.timer, jiffies + msecs_to_jiffies(cal_interval)); - if (ah->eep_ops->get_eeprom(ah, EEP_PAPRD) && ah->caldata) { + if (ar9003_is_paprd_enabled(ah) && ah->caldata) { if (!ah->caldata->paprd_done) { ieee80211_queue_work(sc->hw, &sc->paprd_work); } else if (!ah->paprd_table_write_done) { -- cgit v1.2.3-18-g5258 From 1562580e37e7a6936d591fd04cf9d7b79a096bf0 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Mon, 10 Dec 2012 07:22:38 +0530 Subject: ath9k_hw: Calculate the correct training power for PAPRD Assign the training power for PAPRD based on the chip. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_eeprom.c | 41 ++++++++++++++++++-------- drivers/net/wireless/ath/ath9k/ar9003_paprd.c | 22 +++++++++----- 2 files changed, 43 insertions(+), 20 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index 6b8861c559e..11082b417d2 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -5072,6 +5072,33 @@ static inline u8 mcsidx_to_tgtpwridx(unsigned int mcs_idx, u8 base_pwridx) return base_pwridx + 4 * (mcs_idx / 8) + mod_idx - 2; } +static void ar9003_paprd_set_txpower(struct ath_hw *ah, + struct ath9k_channel *chan, + u8 *targetPowerValT2) +{ + int i; + + if (!ar9003_is_paprd_enabled(ah)) + return; + + if (IS_CHAN_HT40(chan)) + i = ALL_TARGET_HT40_7; + else + i = ALL_TARGET_HT20_7; + + if (IS_CHAN_2GHZ(chan)) { + if (!AR_SREV_9330(ah) && !AR_SREV_9340(ah) && + !AR_SREV_9462(ah) && !AR_SREV_9565(ah)) { + if (IS_CHAN_HT40(chan)) + i = ALL_TARGET_HT40_0_8_16; + else + i = ALL_TARGET_HT20_0_8_16; + } + } + + ah->paprd_target_power = targetPowerValT2[i]; +} + static void ath9k_hw_ar9300_set_txpower(struct ath_hw *ah, struct ath9k_channel *chan, u16 cfgCtl, u8 twiceAntennaReduction, @@ -5166,19 +5193,7 @@ static void ath9k_hw_ar9300_set_txpower(struct ath_hw *ah, /* Write target power array to registers */ ar9003_hw_tx_power_regwrite(ah, targetPowerValT2); ar9003_hw_calibration_apply(ah, chan->channel); - - if (IS_CHAN_2GHZ(chan)) { - if (IS_CHAN_HT40(chan)) - i = ALL_TARGET_HT40_0_8_16; - else - i = ALL_TARGET_HT20_0_8_16; - } else { - if (IS_CHAN_HT40(chan)) - i = ALL_TARGET_HT40_7; - else - i = ALL_TARGET_HT20_7; - } - ah->paprd_target_power = targetPowerValT2[i]; + ar9003_paprd_set_txpower(ah, chan, targetPowerValT2); } static u16 ath9k_hw_ar9300_get_spur_channel(struct ath_hw *ah, diff --git a/drivers/net/wireless/ath/ath9k/ar9003_paprd.c b/drivers/net/wireless/ath/ath9k/ar9003_paprd.c index aea19088314..09c1f9da67a 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_paprd.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_paprd.c @@ -74,15 +74,23 @@ static int ar9003_get_training_power_2g(struct ath_hw *ah) unsigned int power, scale, delta; scale = ar9003_get_paprd_scale_factor(ah, chan); - power = REG_READ_FIELD(ah, AR_PHY_POWERTX_RATE5, - AR_PHY_POWERTX_RATE5_POWERTXHT20_0); - delta = abs((int) ah->paprd_target_power - (int) power); - if (delta > scale) - return -1; + if (AR_SREV_9330(ah) || AR_SREV_9340(ah) || + AR_SREV_9462(ah) || AR_SREV_9565(ah)) { + power = ah->paprd_target_power + 2; + } else if (AR_SREV_9485(ah)) { + power = 25; + } else { + power = REG_READ_FIELD(ah, AR_PHY_POWERTX_RATE5, + AR_PHY_POWERTX_RATE5_POWERTXHT20_0); + + delta = abs((int) ah->paprd_target_power - (int) power); + if (delta > scale) + return -1; - if (delta < 4) - power -= 4 - delta; + if (delta < 4) + power -= 4 - delta; + } return power; } -- cgit v1.2.3-18-g5258 From 3edfd10b45ae4ebe8ff905f626708c49e4fdc167 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Mon, 10 Dec 2012 08:20:27 +0530 Subject: ath9k_hw: Update intivals for AR9340 Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9340_initvals.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/ar9340_initvals.h b/drivers/net/wireless/ath/ath9k/ar9340_initvals.h index 1d8235e19f0..f69d292bdc0 100644 --- a/drivers/net/wireless/ath/ath9k/ar9340_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9340_initvals.h @@ -211,6 +211,8 @@ static const u32 ar9340_1p0_radio_core_40M[][2] = { {0x0001609c, 0x02566f3a}, {0x000160ac, 0xa4647c00}, {0x000160b0, 0x01885f5a}, + {0x00008244, 0x0010f400}, + {0x0000824c, 0x0001e800}, }; #define ar9340_1p0_mac_postamble ar9300_2p2_mac_postamble @@ -1273,9 +1275,9 @@ static const u32 ar9340_1p0_mac_core[][2] = { {0x000081f8, 0x00000000}, {0x000081fc, 0x00000000}, {0x00008240, 0x00100000}, - {0x00008244, 0x0010f424}, + {0x00008244, 0x0010f3d7}, {0x00008248, 0x00000800}, - {0x0000824c, 0x0001e848}, + {0x0000824c, 0x0001e7ae}, {0x00008250, 0x00000000}, {0x00008254, 0x00000000}, {0x00008258, 0x00000000}, -- cgit v1.2.3-18-g5258 From b7c0c238898d200e80487516e2b67aba2a522cc0 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 10 Dec 2012 14:03:17 +0100 Subject: ath9k_hw: Fix signal strength / channel noise reporting While AR_PHY_CCA_NOM_VAL_* does contain the expected internal noise floor for a chip measured in clean air, it refers to the lowest expected reading. Depending on the frequency, this measurement can vary by about 6db, thus causing a higher reported channel noise and signal strength. Factor in the 6db offset when converting internal noisefloor to channel noise. This patch makes the reported values more accurate for all chips without affecting NF calibration behavior. Signed-off-by: Felix Fietkau Cc: stable@vger.kernel.org Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/calib.c | 1 + drivers/net/wireless/ath/ath9k/calib.h | 3 +++ 2 files changed, 4 insertions(+) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c index f3448a032e6..1e8508530e9 100644 --- a/drivers/net/wireless/ath/ath9k/calib.c +++ b/drivers/net/wireless/ath/ath9k/calib.c @@ -69,6 +69,7 @@ s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan) if (chan && chan->noisefloor) { s8 delta = chan->noisefloor - + ATH9K_NF_CAL_NOISE_THRESH - ath9k_hw_get_default_nf(ah, chan); if (delta > 0) noise += delta; diff --git a/drivers/net/wireless/ath/ath9k/calib.h b/drivers/net/wireless/ath/ath9k/calib.h index 1060c19a501..60dcb6c22db 100644 --- a/drivers/net/wireless/ath/ath9k/calib.h +++ b/drivers/net/wireless/ath/ath9k/calib.h @@ -21,6 +21,9 @@ #define AR_PHY_CCA_FILTERWINDOW_LENGTH 5 +/* Internal noise floor can vary by about 6db depending on the frequency */ +#define ATH9K_NF_CAL_NOISE_THRESH 6 + #define NUM_NF_READINGS 6 #define ATH9K_NF_CAL_HIST_MAX 5 -- cgit v1.2.3-18-g5258 From 2fd2cdfb6d2f3c3d18f2e47f41679a7bde9bcbf3 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Mon, 10 Dec 2012 15:30:25 +0100 Subject: ath9k: move duplicated debug message to 'ath9k_hw_nvram_read' The fill_eeprom functions are printing the same debug message in case the 'ath9k_hw_nvram_read' function fails. Remove the duplicated code from fill_eeprom functions and add the ath_dbg call directly into 'ath9k_hw_nvram_read'. Signed-off-by: Gabor Juhos Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/eeprom.c | 8 +++++++- drivers/net/wireless/ath/ath9k/eeprom_4k.c | 6 ++---- drivers/net/wireless/ath/ath9k/eeprom_9287.c | 5 +---- drivers/net/wireless/ath/ath9k/eeprom_def.c | 5 +---- 4 files changed, 11 insertions(+), 13 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c index 0512397a293..4b6a9350adc 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.c +++ b/drivers/net/wireless/ath/ath9k/eeprom.c @@ -115,7 +115,13 @@ void ath9k_hw_usb_gen_fill_eeprom(struct ath_hw *ah, u16 *eep_data, bool ath9k_hw_nvram_read(struct ath_common *common, u32 off, u16 *data) { - return common->bus_ops->eeprom_read(common, off, data); + bool ret; + + ret = common->bus_ops->eeprom_read(common, off, data); + if (!ret) + ath_dbg(common, EEPROM, "Unable to read eeprom region\n"); + + return ret; } void ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList, diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c index 7d075105a85..17c843d3721 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c @@ -37,11 +37,9 @@ static bool __ath9k_hw_4k_fill_eeprom(struct ath_hw *ah) int addr, eep_start_loc = 64; for (addr = 0; addr < SIZE_EEPROM_4K; addr++) { - if (!ath9k_hw_nvram_read(common, addr + eep_start_loc, eep_data)) { - ath_dbg(common, EEPROM, - "Unable to read eeprom region\n"); + if (!ath9k_hw_nvram_read(common, addr + eep_start_loc, + eep_data)) return false; - } eep_data++; } diff --git a/drivers/net/wireless/ath/ath9k/eeprom_9287.c b/drivers/net/wireless/ath/ath9k/eeprom_9287.c index cd742fb944c..f2c32bc36f1 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c @@ -40,11 +40,8 @@ static bool __ath9k_hw_ar9287_fill_eeprom(struct ath_hw *ah) for (addr = 0; addr < SIZE_EEPROM_AR9287; addr++) { if (!ath9k_hw_nvram_read(common, addr + eep_start_loc, - eep_data)) { - ath_dbg(common, EEPROM, - "Unable to read eeprom region\n"); + eep_data)) return false; - } eep_data++; } diff --git a/drivers/net/wireless/ath/ath9k/eeprom_def.c b/drivers/net/wireless/ath/ath9k/eeprom_def.c index a8ac30a0072..2654f741b8b 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_def.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_def.c @@ -97,11 +97,8 @@ static bool __ath9k_hw_def_fill_eeprom(struct ath_hw *ah) for (addr = 0; addr < SIZE_EEPROM_DEF; addr++) { if (!ath9k_hw_nvram_read(common, addr + ar5416_eep_start_loc, - eep_data)) { - ath_err(ath9k_hw_common(ah), - "Unable to read eeprom region\n"); + eep_data)) return false; - } eep_data++; } return true; -- cgit v1.2.3-18-g5258 From 7177d8f998c452701ad5352cca12408e26f80b07 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Mon, 10 Dec 2012 15:30:26 +0100 Subject: ath9k: add EEPROM offset to debug message Show the EEPROM offset of the failed read operation in 'ath9k_hw_nvram_read'. The debug message is more informative this way. Signed-off-by: Gabor Juhos Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/eeprom.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c index 4b6a9350adc..bf52ae1fdff 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.c +++ b/drivers/net/wireless/ath/ath9k/eeprom.c @@ -119,7 +119,8 @@ bool ath9k_hw_nvram_read(struct ath_common *common, u32 off, u16 *data) ret = common->bus_ops->eeprom_read(common, off, data); if (!ret) - ath_dbg(common, EEPROM, "Unable to read eeprom region\n"); + ath_dbg(common, EEPROM, + "unable to read eeprom region at offset %u\n", off); return ret; } -- cgit v1.2.3-18-g5258 From 0e4b9f2f12e94686855605eda64ea534a95d77f2 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Mon, 10 Dec 2012 15:30:27 +0100 Subject: ath9k: use 'struct ath_hw *' as the first argument for 'ath9k_hw_nvram_read' The 'ath9k_hw_nvram_read' function takes a 'struct ath_common *' as its first argument. Almost each of its caller has a 'struct ath_hw *' parameter in their argument list, and that is dereferenced in order to get the 'struct ath_common' pointer. Change the first argument of 'ath9k_hw_nvram_read' to be a 'struct ath_hw *', and remove the dereference calls from the callers. Also change the type of the first argument of the ar9300_eeprom_read_{byte,word} functions. Signed-off-by: Gabor Juhos Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_eeprom.c | 17 ++++++++--------- drivers/net/wireless/ath/ath9k/eeprom.c | 3 ++- drivers/net/wireless/ath/ath9k/eeprom.h | 2 +- drivers/net/wireless/ath/ath9k/eeprom_4k.c | 6 ++---- drivers/net/wireless/ath/ath9k/eeprom_9287.c | 6 ++---- drivers/net/wireless/ath/ath9k/eeprom_def.c | 5 ++--- 6 files changed, 17 insertions(+), 22 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index 11082b417d2..562186ca9b5 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -3001,24 +3001,24 @@ static u32 ath9k_hw_ar9300_get_eeprom(struct ath_hw *ah, } } -static bool ar9300_eeprom_read_byte(struct ath_common *common, int address, +static bool ar9300_eeprom_read_byte(struct ath_hw *ah, int address, u8 *buffer) { u16 val; - if (unlikely(!ath9k_hw_nvram_read(common, address / 2, &val))) + if (unlikely(!ath9k_hw_nvram_read(ah, address / 2, &val))) return false; *buffer = (val >> (8 * (address % 2))) & 0xff; return true; } -static bool ar9300_eeprom_read_word(struct ath_common *common, int address, +static bool ar9300_eeprom_read_word(struct ath_hw *ah, int address, u8 *buffer) { u16 val; - if (unlikely(!ath9k_hw_nvram_read(common, address / 2, &val))) + if (unlikely(!ath9k_hw_nvram_read(ah, address / 2, &val))) return false; buffer[0] = val >> 8; @@ -3044,14 +3044,14 @@ static bool ar9300_read_eeprom(struct ath_hw *ah, int address, u8 *buffer, * the 16-bit word at that address */ if (address % 2 == 0) { - if (!ar9300_eeprom_read_byte(common, address--, buffer++)) + if (!ar9300_eeprom_read_byte(ah, address--, buffer++)) goto error; count--; } for (i = 0; i < count / 2; i++) { - if (!ar9300_eeprom_read_word(common, address, buffer)) + if (!ar9300_eeprom_read_word(ah, address, buffer)) goto error; address -= 2; @@ -3059,7 +3059,7 @@ static bool ar9300_read_eeprom(struct ath_hw *ah, int address, u8 *buffer, } if (count % 2) - if (!ar9300_eeprom_read_byte(common, address, buffer)) + if (!ar9300_eeprom_read_byte(ah, address, buffer)) goto error; return true; @@ -3236,12 +3236,11 @@ static bool ar9300_check_eeprom_header(struct ath_hw *ah, eeprom_read_op read, static int ar9300_eeprom_restore_flash(struct ath_hw *ah, u8 *mptr, int mdata_size) { - struct ath_common *common = ath9k_hw_common(ah); u16 *data = (u16 *) mptr; int i; for (i = 0; i < mdata_size / 2; i++, data++) - ath9k_hw_nvram_read(common, i, data); + ath9k_hw_nvram_read(ah, i, data); return 0; } diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c index bf52ae1fdff..eb9ac5ea618 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.c +++ b/drivers/net/wireless/ath/ath9k/eeprom.c @@ -113,8 +113,9 @@ void ath9k_hw_usb_gen_fill_eeprom(struct ath_hw *ah, u16 *eep_data, } } -bool ath9k_hw_nvram_read(struct ath_common *common, u32 off, u16 *data) +bool ath9k_hw_nvram_read(struct ath_hw *ah, u32 off, u16 *data) { + struct ath_common *common = ath9k_hw_common(ah); bool ret; ret = common->bus_ops->eeprom_read(common, off, data); diff --git a/drivers/net/wireless/ath/ath9k/eeprom.h b/drivers/net/wireless/ath/ath9k/eeprom.h index 319c651fa6c..40d4f62d0f1 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.h +++ b/drivers/net/wireless/ath/ath9k/eeprom.h @@ -663,7 +663,7 @@ int16_t ath9k_hw_interpolate(u16 target, u16 srcLeft, u16 srcRight, int16_t targetRight); bool ath9k_hw_get_lower_upper_index(u8 target, u8 *pList, u16 listSize, u16 *indexL, u16 *indexR); -bool ath9k_hw_nvram_read(struct ath_common *common, u32 off, u16 *data); +bool ath9k_hw_nvram_read(struct ath_hw *ah, u32 off, u16 *data); void ath9k_hw_usb_gen_fill_eeprom(struct ath_hw *ah, u16 *eep_data, int eep_start_loc, int size); void ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList, diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c index 17c843d3721..c2bfd748eed 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c @@ -32,13 +32,11 @@ static int ath9k_hw_4k_get_eeprom_rev(struct ath_hw *ah) static bool __ath9k_hw_4k_fill_eeprom(struct ath_hw *ah) { - struct ath_common *common = ath9k_hw_common(ah); u16 *eep_data = (u16 *)&ah->eeprom.map4k; int addr, eep_start_loc = 64; for (addr = 0; addr < SIZE_EEPROM_4K; addr++) { - if (!ath9k_hw_nvram_read(common, addr + eep_start_loc, - eep_data)) + if (!ath9k_hw_nvram_read(ah, addr + eep_start_loc, eep_data)) return false; eep_data++; } @@ -194,7 +192,7 @@ static int ath9k_hw_4k_check_eeprom(struct ath_hw *ah) if (!ath9k_hw_use_flash(ah)) { - if (!ath9k_hw_nvram_read(common, AR5416_EEPROM_MAGIC_OFFSET, + if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) { ath_err(common, "Reading Magic # failed\n"); return false; diff --git a/drivers/net/wireless/ath/ath9k/eeprom_9287.c b/drivers/net/wireless/ath/ath9k/eeprom_9287.c index f2c32bc36f1..3ae1f3df063 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c @@ -33,14 +33,12 @@ static int ath9k_hw_ar9287_get_eeprom_rev(struct ath_hw *ah) static bool __ath9k_hw_ar9287_fill_eeprom(struct ath_hw *ah) { struct ar9287_eeprom *eep = &ah->eeprom.map9287; - struct ath_common *common = ath9k_hw_common(ah); u16 *eep_data; int addr, eep_start_loc = AR9287_EEP_START_LOC; eep_data = (u16 *)eep; for (addr = 0; addr < SIZE_EEPROM_AR9287; addr++) { - if (!ath9k_hw_nvram_read(common, addr + eep_start_loc, - eep_data)) + if (!ath9k_hw_nvram_read(ah, addr + eep_start_loc, eep_data)) return false; eep_data++; } @@ -187,7 +185,7 @@ static int ath9k_hw_ar9287_check_eeprom(struct ath_hw *ah) struct ath_common *common = ath9k_hw_common(ah); if (!ath9k_hw_use_flash(ah)) { - if (!ath9k_hw_nvram_read(common, AR5416_EEPROM_MAGIC_OFFSET, + if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) { ath_err(common, "Reading Magic # failed\n"); return false; diff --git a/drivers/net/wireless/ath/ath9k/eeprom_def.c b/drivers/net/wireless/ath/ath9k/eeprom_def.c index 2654f741b8b..1c25368b383 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_def.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_def.c @@ -91,12 +91,11 @@ static int ath9k_hw_def_get_eeprom_rev(struct ath_hw *ah) static bool __ath9k_hw_def_fill_eeprom(struct ath_hw *ah) { - struct ath_common *common = ath9k_hw_common(ah); u16 *eep_data = (u16 *)&ah->eeprom.def; int addr, ar5416_eep_start_loc = 0x100; for (addr = 0; addr < SIZE_EEPROM_DEF; addr++) { - if (!ath9k_hw_nvram_read(common, addr + ar5416_eep_start_loc, + if (!ath9k_hw_nvram_read(ah, addr + ar5416_eep_start_loc, eep_data)) return false; eep_data++; @@ -268,7 +267,7 @@ static int ath9k_hw_def_check_eeprom(struct ath_hw *ah) bool need_swap = false; int i, addr, size; - if (!ath9k_hw_nvram_read(common, AR5416_EEPROM_MAGIC_OFFSET, &magic)) { + if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) { ath_err(common, "Reading Magic # failed\n"); return false; } -- cgit v1.2.3-18-g5258 From ab5c4f71d8c7add173a2d32e5beefdaaf1b7cbbc Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Mon, 10 Dec 2012 15:30:28 +0100 Subject: ath9k: allow to load EEPROM content via firmware API The calibration data for devices w/o a separate EEPROM chip can be specified via the 'eeprom_data' field of 'ath9k_platform_data'. The 'eeprom_data' is usually filled from board specific setup functions. It is easy if the EEPROM data is mapped to the memory, but it can be complicated if it is stored elsewhere. The patch adds support for loading of the EEPROM data via the firmware API to avoid this limitation. Signed-off-by: Gabor Juhos Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/eeprom.c | 19 ++++++++++- drivers/net/wireless/ath/ath9k/hw.h | 3 ++ drivers/net/wireless/ath/ath9k/init.c | 60 ++++++++++++++++++++++++++++++++- 3 files changed, 80 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c index eb9ac5ea618..971d770722c 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.c +++ b/drivers/net/wireless/ath/ath9k/eeprom.c @@ -113,12 +113,29 @@ void ath9k_hw_usb_gen_fill_eeprom(struct ath_hw *ah, u16 *eep_data, } } +static bool ath9k_hw_nvram_read_blob(struct ath_hw *ah, u32 off, + u16 *data) +{ + u16 *blob_data; + + if (off * sizeof(u16) > ah->eeprom_blob->size) + return false; + + blob_data = (u16 *)ah->eeprom_blob->data; + *data = blob_data[off]; + return true; +} + bool ath9k_hw_nvram_read(struct ath_hw *ah, u32 off, u16 *data) { struct ath_common *common = ath9k_hw_common(ah); bool ret; - ret = common->bus_ops->eeprom_read(common, off, data); + if (ah->eeprom_blob) + ret = ath9k_hw_nvram_read_blob(ah, off, data); + else + ret = common->bus_ops->eeprom_read(common, off, data); + if (!ret) ath_dbg(common, EEPROM, "unable to read eeprom region at offset %u\n", off); diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index eff67592db1..7f1a8e91c90 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -20,6 +20,7 @@ #include #include #include +#include #include "mac.h" #include "ani.h" @@ -921,6 +922,8 @@ struct ath_hw { bool is_clk_25mhz; int (*get_mac_revision)(void); int (*external_reset)(void); + + const struct firmware *eeprom_blob; }; struct ath_bus_ops { diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 80cae53a33e..27703a5e48d 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -23,6 +23,11 @@ #include "ath9k.h" +struct ath9k_eeprom_ctx { + struct completion complete; + struct ath_hw *ah; +}; + static char *dev_info = "ath9k"; MODULE_AUTHOR("Atheros Communications"); @@ -506,6 +511,51 @@ static void ath9k_init_misc(struct ath_softc *sc) sc->ant_comb.count = ATH_ANT_DIV_COMB_INIT_COUNT; } +static void ath9k_eeprom_request_cb(const struct firmware *eeprom_blob, + void *ctx) +{ + struct ath9k_eeprom_ctx *ec = ctx; + + if (eeprom_blob) + ec->ah->eeprom_blob = eeprom_blob; + + complete(&ec->complete); +} + +static int ath9k_eeprom_request(struct ath_softc *sc, const char *name) +{ + struct ath9k_eeprom_ctx ec; + struct ath_hw *ah = ah = sc->sc_ah; + int err; + + /* try to load the EEPROM content asynchronously */ + init_completion(&ec.complete); + ec.ah = sc->sc_ah; + + err = request_firmware_nowait(THIS_MODULE, 1, name, sc->dev, GFP_KERNEL, + &ec, ath9k_eeprom_request_cb); + if (err < 0) { + ath_err(ath9k_hw_common(ah), + "EEPROM request failed\n"); + return err; + } + + wait_for_completion(&ec.complete); + + if (!ah->eeprom_blob) { + ath_err(ath9k_hw_common(ah), + "Unable to load EEPROM file %s\n", name); + return -EINVAL; + } + + return 0; +} + +static void ath9k_eeprom_release(struct ath_softc *sc) +{ + release_firmware(sc->sc_ah->eeprom_blob); +} + static int ath9k_init_softc(u16 devid, struct ath_softc *sc, const struct ath_bus_ops *bus_ops) { @@ -583,6 +633,12 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, ath_read_cachesize(common, &csz); common->cachelsz = csz << 2; /* convert to bytes */ + if (pdata->eeprom_name) { + ret = ath9k_eeprom_request(sc, pdata->eeprom_name); + if (ret) + goto err_eeprom; + } + /* Initializes the hardware for all supported chipsets */ ret = ath9k_hw_init(ah); if (ret) @@ -619,7 +675,8 @@ err_btcoex: err_queues: ath9k_hw_deinit(ah); err_hw: - + ath9k_eeprom_release(sc); +err_eeprom: kfree(ah); sc->sc_ah = NULL; @@ -882,6 +939,7 @@ static void ath9k_deinit_softc(struct ath_softc *sc) if (sc->dfs_detector != NULL) sc->dfs_detector->exit(sc->dfs_detector); + ath9k_eeprom_release(sc); kfree(sc->sc_ah); sc->sc_ah = NULL; } -- cgit v1.2.3-18-g5258 From 596ab5ec3bf10a22be30d7cb1d903a4b83fd607c Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 10 Dec 2012 16:40:41 +0100 Subject: ath5k: fix tx path skb leaks ieee80211_free_txskb() needs to be used instead of dev_kfree_skb_any for tx packets passed to the driver from mac80211 Signed-off-by: Felix Fietkau Cc: stable@vger.kernel.org Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/base.c | 4 ++-- drivers/net/wireless/ath/ath5k/mac80211-ops.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 3a5a61e0392..4ad40cfe9ce 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -849,7 +849,7 @@ ath5k_txbuf_free_skb(struct ath5k_hw *ah, struct ath5k_buf *bf) return; dma_unmap_single(ah->dev, bf->skbaddr, bf->skb->len, DMA_TO_DEVICE); - dev_kfree_skb_any(bf->skb); + ieee80211_free_txskb(ah->hw, bf->skb); bf->skb = NULL; bf->skbaddr = 0; bf->desc->ds_data = 0; @@ -1576,7 +1576,7 @@ ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb, return; drop_packet: - dev_kfree_skb_any(skb); + ieee80211_free_txskb(hw, skb); } static void diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c index 1ea8c8795c8..4264341533e 100644 --- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c +++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c @@ -62,7 +62,7 @@ ath5k_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, u16 qnum = skb_get_queue_mapping(skb); if (WARN_ON(qnum >= ah->ah_capabilities.cap_queues.q_tx_num)) { - dev_kfree_skb_any(skb); + ieee80211_free_txskb(hw, skb); return; } -- cgit v1.2.3-18-g5258 From 96d21371ac8583d0935e5c41a798004084789606 Mon Sep 17 00:00:00 2001 From: Thomas Pedersen Date: Mon, 10 Dec 2012 14:48:01 -0800 Subject: ath9k: RX timestamp is reported at end of frame Accurate RX timestamp reporting is important for proper IBSS merging, mesh synchronization, and MCCA scheduling. Namely, knowing where the TSF is recorded is needed to sync with the beacon timestamp field. Tested with AR9280. Signed-off-by: Thomas Pedersen Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/recv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 6aafbb77c49..d4df98a938b 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -976,7 +976,7 @@ static int ath9k_rx_skb_preprocess(struct ath_common *common, rx_status->freq = hw->conf.channel->center_freq; rx_status->signal = ah->noise + rx_stats->rs_rssi; rx_status->antenna = rx_stats->rs_antenna; - rx_status->flag |= RX_FLAG_MACTIME_START; + rx_status->flag |= RX_FLAG_MACTIME_END; if (rx_stats->rs_moreaggr) rx_status->flag |= RX_FLAG_NO_SIGNAL_VAL; -- cgit v1.2.3-18-g5258 From 75d7dbc280bb75d2bdce59c5969a812f38255f54 Mon Sep 17 00:00:00 2001 From: Thomas Pedersen Date: Mon, 10 Dec 2012 14:48:02 -0800 Subject: ath9k_htc: RX timestamp is reported at end of frame Accurate RX timestamp reporting is important for proper IBSS merging, mesh synchronization, and MCCA scheduling. Namely, knowing where the TSF is recorded is needed to sync with the beacon timestamp field. Tested with AR9271. Signed-off-by: Thomas Pedersen Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/htc_drv_txrx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c index 28cd50ee521..b6a5a08810b 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c @@ -1082,7 +1082,7 @@ static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv, rx_status->freq = hw->conf.channel->center_freq; rx_status->signal = rxbuf->rxstatus.rs_rssi + ATH_DEFAULT_NOISE_FLOOR; rx_status->antenna = rxbuf->rxstatus.rs_antenna; - rx_status->flag |= RX_FLAG_MACTIME_START; + rx_status->flag |= RX_FLAG_MACTIME_END; return true; -- cgit v1.2.3-18-g5258 From e576defd1fe1ade5afe590eadd556dce5473fc26 Mon Sep 17 00:00:00 2001 From: Thomas Pedersen Date: Mon, 10 Dec 2012 14:48:03 -0800 Subject: ath5k: RX timestamp is reported at end of frame This is true for at least AR5213, and shouldn't be different for other ath5k PHYs. Tested on AR2413 and AR5414. Signed-off-by: Thomas Pedersen Tested-by: Bob Copeland Acked-by: Nick Kossifidis Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/base.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 4ad40cfe9ce..30ca0a60a64 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -1336,20 +1336,9 @@ ath5k_receive_frame(struct ath5k_hw *ah, struct sk_buff *skb, * 15bit only. that means TSF extension has to be done within * 32768usec (about 32ms). it might be necessary to move this to * the interrupt handler, like it is done in madwifi. - * - * Unfortunately we don't know when the hardware takes the rx - * timestamp (beginning of phy frame, data frame, end of rx?). - * The only thing we know is that it is hardware specific... - * On AR5213 it seems the rx timestamp is at the end of the - * frame, but I'm not sure. - * - * NOTE: mac80211 defines mactime at the beginning of the first - * data symbol. Since we don't have any time references it's - * impossible to comply to that. This affects IBSS merge only - * right now, so it's not too bad... */ rxs->mactime = ath5k_extend_tsf(ah, rs->rs_tstamp); - rxs->flag |= RX_FLAG_MACTIME_START; + rxs->flag |= RX_FLAG_MACTIME_END; rxs->freq = ah->curchan->center_freq; rxs->band = ah->curchan->band; -- cgit v1.2.3-18-g5258 From 36b07d15a656b657beaf9e6357a341768192fad2 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Tue, 11 Dec 2012 00:06:41 +0100 Subject: ath9k: check pdata variable before dereferencing it Due to my recent commit (ath9k: allow to load EEPROM content via firmware API) smatch complains about that the 'pdata' variable in 'ath9k_hw_init' can be NULL and it is dereferenced before checking that. That is absolutely correct. Check the 'pdata' variable before using it to avoid a NULL pointer dereference. Reported-by: Dan Carpenter Signed-off-by: Gabor Juhos Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless/ath') diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 27703a5e48d..f69ef5d48c7 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -633,7 +633,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, ath_read_cachesize(common, &csz); common->cachelsz = csz << 2; /* convert to bytes */ - if (pdata->eeprom_name) { + if (pdata && pdata->eeprom_name) { ret = ath9k_eeprom_request(sc, pdata->eeprom_name); if (ret) goto err_eeprom; -- cgit v1.2.3-18-g5258