From a60e77e5a41330334fd0ca428f18919d1ea6ed62 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 4 Jun 2009 18:26:06 +0200 Subject: iwlwifi: port to cfg80211 rfkill This ports the iwlwifi rfkill code to the new API offered by cfg80211 and thus removes a lot of useless stuff. The soft- rfkill is completely removed since that is now handled by setting the interfaces down. Signed-off-by: Johannes Berg Tested-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/Kconfig | 4 - drivers/net/wireless/iwlwifi/Makefile | 1 - drivers/net/wireless/iwlwifi/iwl-3945.h | 5 - drivers/net/wireless/iwlwifi/iwl-agn.c | 42 +++------ drivers/net/wireless/iwlwifi/iwl-core.c | 138 ---------------------------- drivers/net/wireless/iwlwifi/iwl-core.h | 16 +--- drivers/net/wireless/iwlwifi/iwl-debugfs.c | 2 - drivers/net/wireless/iwlwifi/iwl-dev.h | 5 - drivers/net/wireless/iwlwifi/iwl-rfkill.c | 131 -------------------------- drivers/net/wireless/iwlwifi/iwl-rfkill.h | 48 ---------- drivers/net/wireless/iwlwifi/iwl3945-base.c | 41 ++------- 11 files changed, 19 insertions(+), 414 deletions(-) delete mode 100644 drivers/net/wireless/iwlwifi/iwl-rfkill.c delete mode 100644 drivers/net/wireless/iwlwifi/iwl-rfkill.h diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig index 6fe259fcfb8..029ccb6bdba 100644 --- a/drivers/net/wireless/iwlwifi/Kconfig +++ b/drivers/net/wireless/iwlwifi/Kconfig @@ -10,10 +10,6 @@ config IWLWIFI_LEDS bool "Enable LED support in iwlagn and iwl3945 drivers" depends on IWLWIFI -config IWLWIFI_RFKILL - def_bool y - depends on IWLWIFI && RFKILL - config IWLWIFI_SPECTRUM_MEASUREMENT bool "Enable Spectrum Measurement in iwlagn driver" depends on IWLWIFI diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile index d79d97ad61a..1d4e0a226fd 100644 --- a/drivers/net/wireless/iwlwifi/Makefile +++ b/drivers/net/wireless/iwlwifi/Makefile @@ -4,7 +4,6 @@ iwlcore-objs += iwl-rx.o iwl-tx.o iwl-sta.o iwl-calib.o iwlcore-objs += iwl-scan.o iwlcore-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o iwlcore-$(CONFIG_IWLWIFI_LEDS) += iwl-led.o -iwlcore-$(CONFIG_IWLWIFI_RFKILL) += iwl-rfkill.o iwlcore-$(CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT) += iwl-spectrum.o obj-$(CONFIG_IWLAGN) += iwlagn.o diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h index 4d8a325ea9d..fbb3a573463 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h @@ -36,10 +36,6 @@ #include #include -/*used for rfkill*/ -#include -#include - /* Hardware specific file defines the PCI IDs table for that hardware module */ extern struct pci_device_id iwl3945_hw_card_ids[]; @@ -155,7 +151,6 @@ struct iwl3945_frame { #define STATUS_HCMD_SYNC_ACTIVE 1 /* sync host command in progress */ #define STATUS_INT_ENABLED 2 #define STATUS_RF_KILL_HW 3 -#define STATUS_RF_KILL_SW 4 #define STATUS_INIT 5 #define STATUS_ALIVE 6 #define STATUS_READY 7 diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index b77208de92a..a5637c4aa85 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -737,19 +737,13 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv, clear_bit(STATUS_RF_KILL_HW, &priv->status); - if (flags & SW_CARD_DISABLED) - set_bit(STATUS_RF_KILL_SW, &priv->status); - else - clear_bit(STATUS_RF_KILL_SW, &priv->status); - if (!(flags & RXON_CARD_DISABLED)) iwl_scan_cancel(priv); if ((test_bit(STATUS_RF_KILL_HW, &status) != - test_bit(STATUS_RF_KILL_HW, &priv->status)) || - (test_bit(STATUS_RF_KILL_SW, &status) != - test_bit(STATUS_RF_KILL_SW, &priv->status))) - queue_work(priv->workqueue, &priv->rf_kill); + test_bit(STATUS_RF_KILL_HW, &priv->status))) + wiphy_rfkill_set_hw_state(priv->hw->wiphy, + test_bit(STATUS_RF_KILL_HW, &priv->status)); else wake_up_interruptible(&priv->wait_command_queue); } @@ -1045,7 +1039,7 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv) set_bit(STATUS_RF_KILL_HW, &priv->status); else clear_bit(STATUS_RF_KILL_HW, &priv->status); - queue_work(priv->workqueue, &priv->rf_kill); + wiphy_rfkill_set_hw_state(priv->hw->wiphy, hw_rf_kill); } handled |= CSR_INT_BIT_RF_KILL; @@ -1218,7 +1212,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) set_bit(STATUS_RF_KILL_HW, &priv->status); else clear_bit(STATUS_RF_KILL_HW, &priv->status); - queue_work(priv->workqueue, &priv->rf_kill); + wiphy_rfkill_set_hw_state(priv->hw->wiphy, hw_rf_kill); } handled |= CSR_INT_BIT_RF_KILL; @@ -1726,12 +1720,10 @@ static void __iwl_down(struct iwl_priv *priv) ieee80211_stop_queues(priv->hw); /* If we have not previously called iwl_init() then - * clear all bits but the RF Kill bits and return */ + * clear all bits but the RF Kill bit and return */ if (!iwl_is_init(priv)) { priv->status = test_bit(STATUS_RF_KILL_HW, &priv->status) << STATUS_RF_KILL_HW | - test_bit(STATUS_RF_KILL_SW, &priv->status) << - STATUS_RF_KILL_SW | test_bit(STATUS_GEO_CONFIGURED, &priv->status) << STATUS_GEO_CONFIGURED | test_bit(STATUS_EXIT_PENDING, &priv->status) << @@ -1740,11 +1732,9 @@ static void __iwl_down(struct iwl_priv *priv) } /* ...otherwise clear out all the status bits but the RF Kill - * bits and continue taking the NIC down. */ + * bit and continue taking the NIC down. */ priv->status &= test_bit(STATUS_RF_KILL_HW, &priv->status) << STATUS_RF_KILL_HW | - test_bit(STATUS_RF_KILL_SW, &priv->status) << - STATUS_RF_KILL_SW | test_bit(STATUS_GEO_CONFIGURED, &priv->status) << STATUS_GEO_CONFIGURED | test_bit(STATUS_FW_ERROR, &priv->status) << @@ -1866,9 +1856,10 @@ static int __iwl_up(struct iwl_priv *priv) set_bit(STATUS_RF_KILL_HW, &priv->status); if (iwl_is_rfkill(priv)) { + wiphy_rfkill_set_hw_state(priv->hw->wiphy, true); + iwl_enable_interrupts(priv); - IWL_WARN(priv, "Radio disabled by %s RF Kill switch\n", - test_bit(STATUS_RF_KILL_HW, &priv->status) ? "HW" : "SW"); + IWL_WARN(priv, "Radio disabled by HW RF Kill switch\n"); return 0; } @@ -2001,7 +1992,6 @@ static void iwl_bg_up(struct work_struct *data) mutex_lock(&priv->mutex); __iwl_up(priv); mutex_unlock(&priv->mutex); - iwl_rfkill_set_hw_state(priv); } static void iwl_bg_restart(struct work_struct *data) @@ -2179,8 +2169,6 @@ static int iwl_mac_start(struct ieee80211_hw *hw) mutex_unlock(&priv->mutex); - iwl_rfkill_set_hw_state(priv); - if (ret) return ret; @@ -2775,7 +2763,6 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv) INIT_WORK(&priv->up, iwl_bg_up); INIT_WORK(&priv->restart, iwl_bg_restart); INIT_WORK(&priv->rx_replenish, iwl_bg_rx_replenish); - INIT_WORK(&priv->rf_kill, iwl_bg_rf_kill); INIT_WORK(&priv->beacon_update, iwl_bg_beacon_update); INIT_WORK(&priv->run_time_calib_work, iwl_bg_run_time_calib_work); INIT_DELAYED_WORK(&priv->init_alive_start, iwl_bg_init_alive_start); @@ -3046,12 +3033,8 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) else set_bit(STATUS_RF_KILL_HW, &priv->status); - err = iwl_rfkill_init(priv); - if (err) - IWL_ERR(priv, "Unable to initialize RFKILL system. " - "Ignoring error: %d\n", err); - else - iwl_rfkill_set_hw_state(priv); + wiphy_rfkill_set_hw_state(priv->hw->wiphy, + test_bit(STATUS_RF_KILL_HW, &priv->status)); iwl_power_initialize(priv); return 0; @@ -3115,7 +3098,6 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev) iwl_synchronize_irq(priv); - iwl_rfkill_unregister(priv); iwl_dealloc_ucode_pci(priv); if (priv->rxq.bd) diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 51cae4ec26a..f9d16ca5b3d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -36,7 +36,6 @@ #include "iwl-debug.h" #include "iwl-core.h" #include "iwl-io.h" -#include "iwl-rfkill.h" #include "iwl-power.h" #include "iwl-sta.h" #include "iwl-helpers.h" @@ -2211,126 +2210,6 @@ int iwl_send_card_state(struct iwl_priv *priv, u32 flags, u8 meta_flag) } EXPORT_SYMBOL(iwl_send_card_state); -void iwl_radio_kill_sw_disable_radio(struct iwl_priv *priv) -{ - unsigned long flags; - - if (test_bit(STATUS_RF_KILL_SW, &priv->status)) - return; - - IWL_DEBUG_RF_KILL(priv, "Manual SW RF KILL set to: RADIO OFF\n"); - - iwl_scan_cancel(priv); - /* FIXME: This is a workaround for AP */ - if (priv->iw_mode != NL80211_IFTYPE_AP) { - spin_lock_irqsave(&priv->lock, flags); - iwl_write32(priv, CSR_UCODE_DRV_GP1_SET, - CSR_UCODE_SW_BIT_RFKILL); - spin_unlock_irqrestore(&priv->lock, flags); - /* call the host command only if no hw rf-kill set */ - if (!test_bit(STATUS_RF_KILL_HW, &priv->status) && - iwl_is_ready(priv)) - iwl_send_card_state(priv, - CARD_STATE_CMD_DISABLE, 0); - set_bit(STATUS_RF_KILL_SW, &priv->status); - /* make sure mac80211 stop sending Tx frame */ - if (priv->mac80211_registered) - ieee80211_stop_queues(priv->hw); - } -} -EXPORT_SYMBOL(iwl_radio_kill_sw_disable_radio); - -int iwl_radio_kill_sw_enable_radio(struct iwl_priv *priv) -{ - unsigned long flags; - - if (!test_bit(STATUS_RF_KILL_SW, &priv->status)) - return 0; - - IWL_DEBUG_RF_KILL(priv, "Manual SW RF KILL set to: RADIO ON\n"); - - spin_lock_irqsave(&priv->lock, flags); - iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); - - /* If the driver is up it will receive CARD_STATE_NOTIFICATION - * notification where it will clear SW rfkill status. - * Setting it here would break the handler. Only if the - * interface is down we can set here since we don't - * receive any further notification. - */ - if (!priv->is_open) - clear_bit(STATUS_RF_KILL_SW, &priv->status); - spin_unlock_irqrestore(&priv->lock, flags); - - /* wake up ucode */ - msleep(10); - - iwl_read32(priv, CSR_UCODE_DRV_GP1); - spin_lock_irqsave(&priv->reg_lock, flags); - if (!iwl_grab_nic_access(priv)) - iwl_release_nic_access(priv); - spin_unlock_irqrestore(&priv->reg_lock, flags); - - if (test_bit(STATUS_RF_KILL_HW, &priv->status)) { - IWL_DEBUG_RF_KILL(priv, "Can not turn radio back on - " - "disabled by HW switch\n"); - return 0; - } - - /* when driver is up while rfkill is on, it wont receive - * any CARD_STATE_NOTIFICATION notifications so we have to - * restart it in here - */ - if (priv->is_open && !test_bit(STATUS_ALIVE, &priv->status)) { - clear_bit(STATUS_RF_KILL_SW, &priv->status); - if (!iwl_is_rfkill(priv)) - queue_work(priv->workqueue, &priv->up); - } - - /* If the driver is already loaded, it will receive - * CARD_STATE_NOTIFICATION notifications and the handler will - * call restart to reload the driver. - */ - return 1; -} -EXPORT_SYMBOL(iwl_radio_kill_sw_enable_radio); - -void iwl_bg_rf_kill(struct work_struct *work) -{ - struct iwl_priv *priv = container_of(work, struct iwl_priv, rf_kill); - - wake_up_interruptible(&priv->wait_command_queue); - - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; - - mutex_lock(&priv->mutex); - - if (!iwl_is_rfkill(priv)) { - IWL_DEBUG_RF_KILL(priv, - "HW and/or SW RF Kill no longer active, restarting " - "device\n"); - if (!test_bit(STATUS_EXIT_PENDING, &priv->status) && - priv->is_open) - queue_work(priv->workqueue, &priv->restart); - } else { - /* make sure mac80211 stop sending Tx frame */ - if (priv->mac80211_registered) - ieee80211_stop_queues(priv->hw); - - if (!test_bit(STATUS_RF_KILL_HW, &priv->status)) - IWL_DEBUG_RF_KILL(priv, "Can not turn radio back on - " - "disabled by SW switch\n"); - else - IWL_WARN(priv, "Radio Frequency Kill Switch is On:\n" - "Kill switch must be turned off for " - "wireless networking to work.\n"); - } - mutex_unlock(&priv->mutex); - iwl_rfkill_set_hw_state(priv); -} -EXPORT_SYMBOL(iwl_bg_rf_kill); - void iwl_rx_pm_sleep_notif(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { @@ -2849,23 +2728,6 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed) if (priv->cfg->ops->hcmd->set_rxon_chain) priv->cfg->ops->hcmd->set_rxon_chain(priv); - if (changed & IEEE80211_CONF_CHANGE_RADIO_ENABLED) { - if (conf->radio_enabled && - iwl_radio_kill_sw_enable_radio(priv)) { - IWL_DEBUG_MAC80211(priv, "leave - RF-KILL - " - "waiting for uCode\n"); - goto out; - } - - if (!conf->radio_enabled) - iwl_radio_kill_sw_disable_radio(priv); - } - - if (!conf->radio_enabled) { - IWL_DEBUG_MAC80211(priv, "leave - radio disabled\n"); - goto out; - } - if (!iwl_is_ready(priv)) { IWL_DEBUG_MAC80211(priv, "leave - not ready\n"); goto out; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index b52d0fb1606..dabf663e36e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -348,14 +348,6 @@ int iwl_txq_check_empty(struct iwl_priv *priv, int sta_id, u8 tid, int txq_id); ****************************************************/ int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force); -/***************************************************** - * RF -Kill - here and not in iwl-rfkill.h to be available when - * RF-kill subsystem is not compiled. - ****************************************************/ -void iwl_bg_rf_kill(struct work_struct *work); -void iwl_radio_kill_sw_disable_radio(struct iwl_priv *priv); -int iwl_radio_kill_sw_enable_radio(struct iwl_priv *priv); - /******************************************************************************* * Rate ******************************************************************************/ @@ -498,7 +490,6 @@ void iwlcore_free_geos(struct iwl_priv *priv); #define STATUS_HCMD_SYNC_ACTIVE 1 /* sync host command in progress */ #define STATUS_INT_ENABLED 2 #define STATUS_RF_KILL_HW 3 -#define STATUS_RF_KILL_SW 4 #define STATUS_INIT 5 #define STATUS_ALIVE 6 #define STATUS_READY 7 @@ -533,11 +524,6 @@ static inline int iwl_is_init(struct iwl_priv *priv) return test_bit(STATUS_INIT, &priv->status); } -static inline int iwl_is_rfkill_sw(struct iwl_priv *priv) -{ - return test_bit(STATUS_RF_KILL_SW, &priv->status); -} - static inline int iwl_is_rfkill_hw(struct iwl_priv *priv) { return test_bit(STATUS_RF_KILL_HW, &priv->status); @@ -545,7 +531,7 @@ static inline int iwl_is_rfkill_hw(struct iwl_priv *priv) static inline int iwl_is_rfkill(struct iwl_priv *priv) { - return iwl_is_rfkill_hw(priv) || iwl_is_rfkill_sw(priv); + return iwl_is_rfkill_hw(priv); } static inline int iwl_is_ready_rf(struct iwl_priv *priv) diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index af70229144b..11e08c06891 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -449,8 +449,6 @@ static ssize_t iwl_dbgfs_status_read(struct file *file, test_bit(STATUS_INT_ENABLED, &priv->status)); pos += scnprintf(buf + pos, bufsz - pos, "STATUS_RF_KILL_HW:\t %d\n", test_bit(STATUS_RF_KILL_HW, &priv->status)); - pos += scnprintf(buf + pos, bufsz - pos, "STATUS_RF_KILL_SW:\t %d\n", - test_bit(STATUS_RF_KILL_SW, &priv->status)); pos += scnprintf(buf + pos, bufsz - pos, "STATUS_INIT:\t\t %d\n", test_bit(STATUS_INIT, &priv->status)); pos += scnprintf(buf + pos, bufsz - pos, "STATUS_ALIVE:\t\t %d\n", diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 28c39cf8b12..e2d620f0b6e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -41,7 +41,6 @@ #include "iwl-prph.h" #include "iwl-fh.h" #include "iwl-debug.h" -#include "iwl-rfkill.h" #include "iwl-4965-hw.h" #include "iwl-3945-hw.h" #include "iwl-3945-led.h" @@ -936,9 +935,6 @@ struct iwl_priv { * 4965's initialize alive response contains some calibration data. */ struct iwl_init_alive_resp card_alive_init; struct iwl_alive_resp card_alive; -#if defined(CONFIG_IWLWIFI_RFKILL) - struct rfkill *rfkill; -#endif #ifdef CONFIG_IWLWIFI_LEDS unsigned long last_blink_time; @@ -1072,7 +1068,6 @@ struct iwl_priv { struct work_struct calibrated_work; struct work_struct scan_completed; struct work_struct rx_replenish; - struct work_struct rf_kill; struct work_struct abort_scan; struct work_struct update_link_led; struct work_struct auth_work; diff --git a/drivers/net/wireless/iwlwifi/iwl-rfkill.c b/drivers/net/wireless/iwlwifi/iwl-rfkill.c deleted file mode 100644 index 13149936fd2..00000000000 --- a/drivers/net/wireless/iwlwifi/iwl-rfkill.c +++ /dev/null @@ -1,131 +0,0 @@ -/****************************************************************************** - * - * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved. - * - * Portions of this file are derived from the ipw3945 project, as well - * as portions of the ieee80211 subsystem header files. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * - * The full GNU General Public License is included in this distribution in the - * file called LICENSE. - * - * Contact Information: - * Intel Linux Wireless - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - *****************************************************************************/ -#include -#include -#include - -#include - -#include "iwl-eeprom.h" -#include "iwl-dev.h" -#include "iwl-core.h" - -/* software rf-kill from user */ -static int iwl_rfkill_soft_rf_kill(void *data, bool blocked) -{ - struct iwl_priv *priv = data; - - if (!priv->rfkill) - return -EINVAL; - - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return 0; - - IWL_DEBUG_RF_KILL(priv, "received soft RFKILL: block=%d\n", blocked); - - mutex_lock(&priv->mutex); - - if (iwl_is_rfkill_hw(priv)) - goto out_unlock; - - if (!blocked) - iwl_radio_kill_sw_enable_radio(priv); - else - iwl_radio_kill_sw_disable_radio(priv); - -out_unlock: - mutex_unlock(&priv->mutex); - return 0; -} - -static const struct rfkill_ops iwl_rfkill_ops = { - .set_block = iwl_rfkill_soft_rf_kill, -}; - -int iwl_rfkill_init(struct iwl_priv *priv) -{ - struct device *device = wiphy_dev(priv->hw->wiphy); - int ret = 0; - - BUG_ON(device == NULL); - - IWL_DEBUG_RF_KILL(priv, "Initializing RFKILL.\n"); - priv->rfkill = rfkill_alloc(priv->cfg->name, - device, - RFKILL_TYPE_WLAN, - &iwl_rfkill_ops, priv); - if (!priv->rfkill) { - IWL_ERR(priv, "Unable to allocate RFKILL device.\n"); - ret = -ENOMEM; - goto error; - } - - ret = rfkill_register(priv->rfkill); - if (ret) { - IWL_ERR(priv, "Unable to register RFKILL: %d\n", ret); - goto free_rfkill; - } - - IWL_DEBUG_RF_KILL(priv, "RFKILL initialization complete.\n"); - return 0; - -free_rfkill: - rfkill_destroy(priv->rfkill); - priv->rfkill = NULL; - -error: - IWL_DEBUG_RF_KILL(priv, "RFKILL initialization complete.\n"); - return ret; -} -EXPORT_SYMBOL(iwl_rfkill_init); - -void iwl_rfkill_unregister(struct iwl_priv *priv) -{ - - if (priv->rfkill) { - rfkill_unregister(priv->rfkill); - rfkill_destroy(priv->rfkill); - } - - priv->rfkill = NULL; -} -EXPORT_SYMBOL(iwl_rfkill_unregister); - -/* set RFKILL to the right state. */ -void iwl_rfkill_set_hw_state(struct iwl_priv *priv) -{ - if (!priv->rfkill) - return; - - if (rfkill_set_hw_state(priv->rfkill, - !!iwl_is_rfkill_hw(priv))) - iwl_radio_kill_sw_disable_radio(priv); - else - iwl_radio_kill_sw_enable_radio(priv); -} -EXPORT_SYMBOL(iwl_rfkill_set_hw_state); diff --git a/drivers/net/wireless/iwlwifi/iwl-rfkill.h b/drivers/net/wireless/iwlwifi/iwl-rfkill.h deleted file mode 100644 index 633dafb4bf1..00000000000 --- a/drivers/net/wireless/iwlwifi/iwl-rfkill.h +++ /dev/null @@ -1,48 +0,0 @@ -/****************************************************************************** - * - * Copyright(c) 2007 - 2009 Intel Corporation. All rights reserved. - * - * Portions of this file are derived from the ipw3945 project, as well - * as portions of the ieee80211 subsystem header files. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * - * The full GNU General Public License is included in this distribution in the - * file called LICENSE. - * - * Contact Information: - * Intel Linux Wireless - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - *****************************************************************************/ -#ifndef __iwl_rf_kill_h__ -#define __iwl_rf_kill_h__ - -struct iwl_priv; - -#include - -#ifdef CONFIG_IWLWIFI_RFKILL - -void iwl_rfkill_set_hw_state(struct iwl_priv *priv); -void iwl_rfkill_unregister(struct iwl_priv *priv); -int iwl_rfkill_init(struct iwl_priv *priv); -#else -static inline void iwl_rfkill_set_hw_state(struct iwl_priv *priv) {} -static inline void iwl_rfkill_unregister(struct iwl_priv *priv) {} -static inline int iwl_rfkill_init(struct iwl_priv *priv) { return 0; } -#endif - - - -#endif /* __iwl_rf_kill_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 92fa1a39c44..83d31606dd0 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -1009,18 +1009,12 @@ static void iwl3945_rx_card_state_notif(struct iwl_priv *priv, clear_bit(STATUS_RF_KILL_HW, &priv->status); - if (flags & SW_CARD_DISABLED) - set_bit(STATUS_RF_KILL_SW, &priv->status); - else - clear_bit(STATUS_RF_KILL_SW, &priv->status); - iwl_scan_cancel(priv); if ((test_bit(STATUS_RF_KILL_HW, &status) != - test_bit(STATUS_RF_KILL_HW, &priv->status)) || - (test_bit(STATUS_RF_KILL_SW, &status) != - test_bit(STATUS_RF_KILL_SW, &priv->status))) - queue_work(priv->workqueue, &priv->rf_kill); + test_bit(STATUS_RF_KILL_HW, &priv->status))) + wiphy_rfkill_set_hw_state(priv->hw->wiphy, + test_bit(STATUS_RF_KILL_HW, &priv->status)); else wake_up_interruptible(&priv->wait_command_queue); } @@ -2586,8 +2580,6 @@ static void __iwl3945_down(struct iwl_priv *priv) if (!iwl_is_init(priv)) { priv->status = test_bit(STATUS_RF_KILL_HW, &priv->status) << STATUS_RF_KILL_HW | - test_bit(STATUS_RF_KILL_SW, &priv->status) << - STATUS_RF_KILL_SW | test_bit(STATUS_GEO_CONFIGURED, &priv->status) << STATUS_GEO_CONFIGURED | test_bit(STATUS_EXIT_PENDING, &priv->status) << @@ -2596,11 +2588,9 @@ static void __iwl3945_down(struct iwl_priv *priv) } /* ...otherwise clear out all the status bits but the RF Kill - * bits and continue taking the NIC down. */ + * bit and continue taking the NIC down. */ priv->status &= test_bit(STATUS_RF_KILL_HW, &priv->status) << STATUS_RF_KILL_HW | - test_bit(STATUS_RF_KILL_SW, &priv->status) << - STATUS_RF_KILL_SW | test_bit(STATUS_GEO_CONFIGURED, &priv->status) << STATUS_GEO_CONFIGURED | test_bit(STATUS_FW_ERROR, &priv->status) << @@ -2657,12 +2647,6 @@ static int __iwl3945_up(struct iwl_priv *priv) return -EIO; } - if (test_bit(STATUS_RF_KILL_SW, &priv->status)) { - IWL_WARN(priv, "Radio disabled by SW RF kill (module " - "parameter)\n"); - return -ENODEV; - } - if (!priv->ucode_data_backup.v_addr || !priv->ucode_data.v_addr) { IWL_ERR(priv, "ucode not available for device bring up\n"); return -EIO; @@ -2779,15 +2763,14 @@ static void iwl3945_rfkill_poll(struct work_struct *data) { struct iwl_priv *priv = container_of(data, struct iwl_priv, rfkill_poll.work); - unsigned long status = priv->status; if (iwl_read32(priv, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW) clear_bit(STATUS_RF_KILL_HW, &priv->status); else set_bit(STATUS_RF_KILL_HW, &priv->status); - if (test_bit(STATUS_RF_KILL_HW, &status) != test_bit(STATUS_RF_KILL_HW, &priv->status)) - queue_work(priv->workqueue, &priv->rf_kill); + wiphy_rfkill_set_hw_state(priv->hw->wiphy, + test_bit(STATUS_RF_KILL_HW, &priv->status)); queue_delayed_work(priv->workqueue, &priv->rfkill_poll, round_jiffies_relative(2 * HZ)); @@ -3019,7 +3002,6 @@ static void iwl3945_bg_up(struct work_struct *data) mutex_lock(&priv->mutex); __iwl3945_up(priv); mutex_unlock(&priv->mutex); - iwl_rfkill_set_hw_state(priv); } static void iwl3945_bg_restart(struct work_struct *data) @@ -3182,8 +3164,6 @@ static int iwl3945_mac_start(struct ieee80211_hw *hw) mutex_unlock(&priv->mutex); - iwl_rfkill_set_hw_state(priv); - if (ret) goto out_release_irq; @@ -3836,7 +3816,6 @@ static void iwl3945_setup_deferred_work(struct iwl_priv *priv) INIT_WORK(&priv->up, iwl3945_bg_up); INIT_WORK(&priv->restart, iwl3945_bg_restart); INIT_WORK(&priv->rx_replenish, iwl3945_bg_rx_replenish); - INIT_WORK(&priv->rf_kill, iwl_bg_rf_kill); INIT_WORK(&priv->beacon_update, iwl3945_bg_beacon_update); INIT_DELAYED_WORK(&priv->init_alive_start, iwl3945_bg_init_alive_start); INIT_DELAYED_WORK(&priv->alive_start, iwl3945_bg_alive_start); @@ -4203,13 +4182,6 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e if (err) IWL_ERR(priv, "failed to create debugfs files. Ignoring error: %d\n", err); - err = iwl_rfkill_init(priv); - if (err) - IWL_ERR(priv, "Unable to initialize RFKILL system. " - "Ignoring error: %d\n", err); - else - iwl_rfkill_set_hw_state(priv); - /* Start monitoring the killswitch */ queue_delayed_work(priv->workqueue, &priv->rfkill_poll, 2 * HZ); @@ -4275,7 +4247,6 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev) sysfs_remove_group(&pdev->dev.kobj, &iwl3945_attribute_group); - iwl_rfkill_unregister(priv); cancel_delayed_work_sync(&priv->rfkill_poll); iwl3945_dealloc_ucode_pci(priv); -- cgit v1.2.3 From aa18294a289548f45ea6a784f008295ccddf6b14 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Thu, 4 Jun 2009 20:13:19 +0300 Subject: rndis_wlan: cleanup: capitalize enum labels Capitalize enum labels as told in Documents/CodingStyle. Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville --- drivers/net/wireless/rndis_wlan.c | 136 +++++++++++++++++++------------------- 1 file changed, 68 insertions(+), 68 deletions(-) diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index c254fdf446f..de94496cb0e 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -157,55 +157,55 @@ MODULE_PARM_DESC(workaround_interval, #define NDIS_802_11_LENGTH_RATES_EX 16 enum ndis_80211_net_type { - ndis_80211_type_freq_hop, - ndis_80211_type_direct_seq, - ndis_80211_type_ofdm_a, - ndis_80211_type_ofdm_g + NDIS_80211_TYPE_FREQ_HOP, + NDIS_80211_TYPE_DIRECT_SEQ, + NDIS_80211_TYPE_OFDM_A, + NDIS_80211_TYPE_OFDM_G }; enum ndis_80211_net_infra { - ndis_80211_infra_adhoc, - ndis_80211_infra_infra, - ndis_80211_infra_auto_unknown + NDIS_80211_INFRA_ADHOC, + NDIS_80211_INFRA_INFRA, + NDIS_80211_INFRA_AUTO_UNKNOWN }; enum ndis_80211_auth_mode { - ndis_80211_auth_open, - ndis_80211_auth_shared, - ndis_80211_auth_auto_switch, - ndis_80211_auth_wpa, - ndis_80211_auth_wpa_psk, - ndis_80211_auth_wpa_none, - ndis_80211_auth_wpa2, - ndis_80211_auth_wpa2_psk + NDIS_80211_AUTH_OPEN, + NDIS_80211_AUTH_SHARED, + NDIS_80211_AUTH_AUTO_SWITCH, + NDIS_80211_AUTH_WPA, + NDIS_80211_AUTH_WPA_PSK, + NDIS_80211_AUTH_WPA_NONE, + NDIS_80211_AUTH_WPA2, + NDIS_80211_AUTH_WPA2_PSK }; enum ndis_80211_encr_status { - ndis_80211_encr_wep_enabled, - ndis_80211_encr_disabled, - ndis_80211_encr_wep_key_absent, - ndis_80211_encr_not_supported, - ndis_80211_encr_tkip_enabled, - ndis_80211_encr_tkip_key_absent, - ndis_80211_encr_ccmp_enabled, - ndis_80211_encr_ccmp_key_absent + NDIS_80211_ENCR_WEP_ENABLED, + NDIS_80211_ENCR_DISABLED, + NDIS_80211_ENCR_WEP_KEY_ABSENT, + NDIS_80211_ENCR_NOT_SUPPORTED, + NDIS_80211_ENCR_TKIP_ENABLED, + NDIS_80211_ENCR_TKIP_KEY_ABSENT, + NDIS_80211_ENCR_CCMP_ENABLED, + NDIS_80211_ENCR_CCMP_KEY_ABSENT }; enum ndis_80211_priv_filter { - ndis_80211_priv_accept_all, - ndis_80211_priv_8021x_wep + NDIS_80211_PRIV_ACCEPT_ALL, + NDIS_80211_PRIV_8021X_WEP }; enum ndis_80211_addkey_bits { - ndis_80211_addkey_8021x_auth = cpu_to_le32(1 << 28), - ndis_80211_addkey_set_init_recv_seq = cpu_to_le32(1 << 29), - ndis_80211_addkey_pairwise_key = cpu_to_le32(1 << 30), - ndis_80211_addkey_transmit_key = cpu_to_le32(1 << 31), + NDIS_80211_ADDKEY_8021X_AUTH = cpu_to_le32(1 << 28), + NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ = cpu_to_le32(1 << 29), + NDIS_80211_ADDKEY_PAIRWISE_KEY = cpu_to_le32(1 << 30), + NDIS_80211_ADDKEY_TRANSMIT_KEY = cpu_to_le32(1 << 31) }; enum ndis_80211_addwep_bits { - ndis_80211_addwep_perclient_key = cpu_to_le32(1 << 30), - ndis_80211_addwep_transmit_key = cpu_to_le32(1 << 31), + NDIS_80211_ADDWEP_PERCLIENT_KEY = cpu_to_le32(1 << 30), + NDIS_80211_ADDWEP_TRANSMIT_KEY = cpu_to_le32(1 << 31) }; struct ndis_80211_ssid { @@ -835,23 +835,23 @@ static int set_auth_mode(struct usbnet *usbdev, int wpa_version, int authalg) if (wpa_version & IW_AUTH_WPA_VERSION_WPA2) { if (priv->wpa_keymgmt & IW_AUTH_KEY_MGMT_802_1X) - auth_mode = ndis_80211_auth_wpa2; + auth_mode = NDIS_80211_AUTH_WPA2; else - auth_mode = ndis_80211_auth_wpa2_psk; + auth_mode = NDIS_80211_AUTH_WPA2_PSK; } else if (wpa_version & IW_AUTH_WPA_VERSION_WPA) { if (priv->wpa_keymgmt & IW_AUTH_KEY_MGMT_802_1X) - auth_mode = ndis_80211_auth_wpa; + auth_mode = NDIS_80211_AUTH_WPA; else if (priv->wpa_keymgmt & IW_AUTH_KEY_MGMT_PSK) - auth_mode = ndis_80211_auth_wpa_psk; + auth_mode = NDIS_80211_AUTH_WPA_PSK; else - auth_mode = ndis_80211_auth_wpa_none; + auth_mode = NDIS_80211_AUTH_WPA_NONE; } else if (authalg & IW_AUTH_ALG_SHARED_KEY) { if (authalg & IW_AUTH_ALG_OPEN_SYSTEM) - auth_mode = ndis_80211_auth_auto_switch; + auth_mode = NDIS_80211_AUTH_AUTO_SWITCH; else - auth_mode = ndis_80211_auth_shared; + auth_mode = NDIS_80211_AUTH_SHARED; } else - auth_mode = ndis_80211_auth_open; + auth_mode = NDIS_80211_AUTH_OPEN; tmp = cpu_to_le32(auth_mode); ret = rndis_set_oid(usbdev, OID_802_11_AUTHENTICATION_MODE, &tmp, @@ -876,9 +876,9 @@ static int set_priv_filter(struct usbnet *usbdev) if (priv->wpa_version & IW_AUTH_WPA_VERSION_WPA2 || priv->wpa_version & IW_AUTH_WPA_VERSION_WPA) - tmp = cpu_to_le32(ndis_80211_priv_8021x_wep); + tmp = cpu_to_le32(NDIS_80211_PRIV_8021X_WEP); else - tmp = cpu_to_le32(ndis_80211_priv_accept_all); + tmp = cpu_to_le32(NDIS_80211_PRIV_ACCEPT_ALL); return rndis_set_oid(usbdev, OID_802_11_PRIVACY_FILTER, &tmp, sizeof(tmp)); @@ -896,18 +896,18 @@ static int set_encr_mode(struct usbnet *usbdev, int pairwise, int groupwise) groupwise); if (pairwise & IW_AUTH_CIPHER_CCMP) - encr_mode = ndis_80211_encr_ccmp_enabled; + encr_mode = NDIS_80211_ENCR_CCMP_ENABLED; else if (pairwise & IW_AUTH_CIPHER_TKIP) - encr_mode = ndis_80211_encr_tkip_enabled; + encr_mode = NDIS_80211_ENCR_TKIP_ENABLED; else if (pairwise & (IW_AUTH_CIPHER_WEP40 | IW_AUTH_CIPHER_WEP104)) - encr_mode = ndis_80211_encr_wep_enabled; + encr_mode = NDIS_80211_ENCR_WEP_ENABLED; else if (groupwise & IW_AUTH_CIPHER_CCMP) - encr_mode = ndis_80211_encr_ccmp_enabled; + encr_mode = NDIS_80211_ENCR_CCMP_ENABLED; else if (groupwise & IW_AUTH_CIPHER_TKIP) - encr_mode = ndis_80211_encr_tkip_enabled; + encr_mode = NDIS_80211_ENCR_TKIP_ENABLED; else - encr_mode = ndis_80211_encr_disabled; + encr_mode = NDIS_80211_ENCR_DISABLED; tmp = cpu_to_le32(encr_mode); ret = rndis_set_oid(usbdev, OID_802_11_ENCRYPTION_STATUS, &tmp, @@ -975,7 +975,7 @@ static void set_default_iw_params(struct usbnet *usbdev) priv->wpa_keymgmt = 0; priv->wpa_version = 0; - set_infra_mode(usbdev, ndis_80211_infra_infra); + set_infra_mode(usbdev, NDIS_80211_INFRA_INFRA); set_auth_mode(usbdev, IW_AUTH_WPA_VERSION_DISABLED, IW_AUTH_ALG_OPEN_SYSTEM); set_priv_filter(usbdev); @@ -1011,7 +1011,7 @@ static int add_wep_key(struct usbnet *usbdev, char *key, int key_len, int index) memcpy(&ndis_key.material, key, key_len); if (index == priv->encr_tx_key_index) { - ndis_key.index |= ndis_80211_addwep_transmit_key; + ndis_key.index |= NDIS_80211_ADDWEP_TRANSMIT_KEY; ret = set_encr_mode(usbdev, IW_AUTH_CIPHER_WEP104, IW_AUTH_CIPHER_NONE); if (ret) @@ -1047,15 +1047,15 @@ static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len, return -EINVAL; if (key_len > sizeof(ndis_key.material) || key_len < 0) return -EINVAL; - if ((flags & ndis_80211_addkey_set_init_recv_seq) && !rx_seq) + if ((flags & NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ) && !rx_seq) return -EINVAL; - if ((flags & ndis_80211_addkey_pairwise_key) && !addr) + if ((flags & NDIS_80211_ADDKEY_PAIRWISE_KEY) && !addr) return -EINVAL; devdbg(usbdev, "add_wpa_key(%i): flags:%i%i%i", index, - !!(flags & ndis_80211_addkey_transmit_key), - !!(flags & ndis_80211_addkey_pairwise_key), - !!(flags & ndis_80211_addkey_set_init_recv_seq)); + !!(flags & NDIS_80211_ADDKEY_TRANSMIT_KEY), + !!(flags & NDIS_80211_ADDKEY_PAIRWISE_KEY), + !!(flags & NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ)); memset(&ndis_key, 0, sizeof(ndis_key)); @@ -1073,15 +1073,15 @@ static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len, } else memcpy(ndis_key.material, key, key_len); - if (flags & ndis_80211_addkey_set_init_recv_seq) + if (flags & NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ) memcpy(ndis_key.rsc, rx_seq, 6); - if (flags & ndis_80211_addkey_pairwise_key) { + if (flags & NDIS_80211_ADDKEY_PAIRWISE_KEY) { /* pairwise key */ memcpy(ndis_key.bssid, addr->sa_data, ETH_ALEN); } else { /* group key */ - if (priv->infra_mode == ndis_80211_infra_adhoc) + if (priv->infra_mode == NDIS_80211_INFRA_ADHOC) memset(ndis_key.bssid, 0xff, ETH_ALEN); else get_bssid(usbdev, ndis_key.bssid); @@ -1096,7 +1096,7 @@ static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len, priv->encr_key_len[index] = key_len; priv->encr_key_wpa[index] = 1; - if (flags & ndis_80211_addkey_transmit_key) + if (flags & NDIS_80211_ADDKEY_TRANSMIT_KEY) priv->encr_tx_key_index = index; return 0; @@ -1128,7 +1128,7 @@ static int remove_key(struct usbnet *usbdev, int index, u8 bssid[ETH_ALEN]) /* pairwise key */ if (memcmp(bssid, ffff_bssid, ETH_ALEN) != 0) remove_key.index |= - ndis_80211_addkey_pairwise_key; + NDIS_80211_ADDKEY_PAIRWISE_KEY; memcpy(remove_key.bssid, bssid, sizeof(remove_key.bssid)); } else @@ -1238,10 +1238,10 @@ static int rndis_change_virtual_intf(struct wiphy *wiphy, int ifindex, switch (type) { case NL80211_IFTYPE_ADHOC: - mode = ndis_80211_infra_adhoc; + mode = NDIS_80211_INFRA_ADHOC; break; case NL80211_IFTYPE_STATION: - mode = ndis_80211_infra_infra; + mode = NDIS_80211_INFRA_INFRA; break; default: return -EINVAL; @@ -1698,11 +1698,11 @@ static int rndis_iw_set_encode_ext(struct net_device *dev, flags = 0; if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) - flags |= ndis_80211_addkey_set_init_recv_seq; + flags |= NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ; if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY)) - flags |= ndis_80211_addkey_pairwise_key; + flags |= NDIS_80211_ADDKEY_PAIRWISE_KEY; if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) - flags |= ndis_80211_addkey_transmit_key; + flags |= NDIS_80211_ADDKEY_TRANSMIT_KEY; return add_wpa_key(usbdev, ext->key, ext->key_len, keyidx, &ext->addr, ext->rx_seq, ext->alg, flags); @@ -2160,14 +2160,14 @@ static int rndis_wext_get_caps(struct usbnet *usbdev) n = 8; for (i = 0; i < n; i++) { switch (le32_to_cpu(networks_supported.items[i])) { - case ndis_80211_type_freq_hop: - case ndis_80211_type_direct_seq: + case NDIS_80211_TYPE_FREQ_HOP: + case NDIS_80211_TYPE_DIRECT_SEQ: priv->caps |= CAP_MODE_80211B; break; - case ndis_80211_type_ofdm_a: + case NDIS_80211_TYPE_OFDM_A: priv->caps |= CAP_MODE_80211A; break; - case ndis_80211_type_ofdm_g: + case NDIS_80211_TYPE_OFDM_G: priv->caps |= CAP_MODE_80211G; break; } -- cgit v1.2.3 From 582241a08409c89b086774c60b55c1a1706a7e5d Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Thu, 4 Jun 2009 20:13:25 +0300 Subject: rndis_wlan: cleanup: rename all rndis_wext* objects to rndis_wlan* Driver used to be named rndis_wext before inclusion to upstream. Since rndis_wlan is being converted to cfg80211, use of rndis_wext* names can be confusing. So rename all rndis_wext to rndis_wlan (as should have been when driver was renamed). Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville --- drivers/net/wireless/rndis_wlan.c | 156 +++++++++++++++++++------------------- 1 file changed, 78 insertions(+), 78 deletions(-) diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index de94496cb0e..7441d558511 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -361,7 +361,7 @@ static const struct ieee80211_rate rndis_rates[] = { }; /* RNDIS device private data */ -struct rndis_wext_private { +struct rndis_wlan_private { struct usbnet *usbdev; struct wireless_dev wdev; @@ -441,13 +441,13 @@ static const unsigned char ffff_bssid[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; -static struct rndis_wext_private *get_rndis_wext_priv(struct usbnet *dev) +static struct rndis_wlan_private *get_rndis_wlan_priv(struct usbnet *dev) { - return (struct rndis_wext_private *)dev->driver_priv; + return (struct rndis_wlan_private *)dev->driver_priv; } -static u32 get_bcm4320_power(struct rndis_wext_private *priv) +static u32 get_bcm4320_power(struct rndis_wlan_private *priv) { return BCM4320_DEFAULT_TXPOWER * bcm4320_power_output[priv->param_power_output] / 100; @@ -480,7 +480,7 @@ static int rndis_error_status(__le32 rndis_status) static int rndis_query_oid(struct usbnet *dev, __le32 oid, void *data, int *len) { - struct rndis_wext_private *priv = get_rndis_wext_priv(dev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(dev); union { void *buf; struct rndis_msg_hdr *header; @@ -526,7 +526,7 @@ static int rndis_query_oid(struct usbnet *dev, __le32 oid, void *data, int *len) static int rndis_set_oid(struct usbnet *dev, __le32 oid, void *data, int len) { - struct rndis_wext_private *priv = get_rndis_wext_priv(dev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(dev); union { void *buf; struct rndis_msg_hdr *header; @@ -747,7 +747,7 @@ static int get_essid(struct usbnet *usbdev, struct ndis_80211_ssid *ssid) static int set_essid(struct usbnet *usbdev, struct ndis_80211_ssid *ssid) { - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); int ret; ret = rndis_set_oid(usbdev, OID_802_11_SSID, ssid, sizeof(*ssid)); @@ -794,7 +794,7 @@ static int is_associated(struct usbnet *usbdev) static int disassociate(struct usbnet *usbdev, int reset_ssid) { - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); struct ndis_80211_ssid ssid; int i, ret = 0; @@ -826,7 +826,7 @@ static int disassociate(struct usbnet *usbdev, int reset_ssid) static int set_auth_mode(struct usbnet *usbdev, int wpa_version, int authalg) { - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); __le32 tmp; int auth_mode, ret; @@ -869,7 +869,7 @@ static int set_auth_mode(struct usbnet *usbdev, int wpa_version, int authalg) static int set_priv_filter(struct usbnet *usbdev) { - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); __le32 tmp; devdbg(usbdev, "set_priv_filter: wpa_version=0x%x", priv->wpa_version); @@ -887,7 +887,7 @@ static int set_priv_filter(struct usbnet *usbdev) static int set_encr_mode(struct usbnet *usbdev, int pairwise, int groupwise) { - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); __le32 tmp; int encr_mode, ret; @@ -925,7 +925,7 @@ static int set_encr_mode(struct usbnet *usbdev, int pairwise, int groupwise) static int set_assoc_params(struct usbnet *usbdev) { - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); set_auth_mode(usbdev, priv->wpa_version, priv->wpa_authalg); set_priv_filter(usbdev); @@ -937,7 +937,7 @@ static int set_assoc_params(struct usbnet *usbdev) static int set_infra_mode(struct usbnet *usbdev, int mode) { - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); __le32 tmp; int ret, i; @@ -970,7 +970,7 @@ static int set_infra_mode(struct usbnet *usbdev, int mode) static void set_default_iw_params(struct usbnet *usbdev) { - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); priv->wpa_keymgmt = 0; priv->wpa_version = 0; @@ -996,7 +996,7 @@ static int deauthenticate(struct usbnet *usbdev) /* index must be 0 - N, as per NDIS */ static int add_wep_key(struct usbnet *usbdev, char *key, int key_len, int index) { - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); struct ndis_80211_wep_key ndis_key; int ret; @@ -1039,7 +1039,7 @@ static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len, int index, const struct sockaddr *addr, const u8 *rx_seq, int alg, int flags) { - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); struct ndis_80211_key ndis_key; int ret; @@ -1106,7 +1106,7 @@ static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len, /* remove_key is for both wep and wpa */ static int remove_key(struct usbnet *usbdev, int index, u8 bssid[ETH_ALEN]) { - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); struct ndis_80211_remove_key remove_key; __le32 keyindex; int ret; @@ -1161,7 +1161,7 @@ static int remove_key(struct usbnet *usbdev, int index, u8 bssid[ETH_ALEN]) static void set_multicast_list(struct usbnet *usbdev) { - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); struct dev_mc_list *mclist; __le32 filter; int ret, i, size; @@ -1256,7 +1256,7 @@ static int rndis_scan(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_scan_request *request) { struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); int ret; __le32 tmp; @@ -1286,7 +1286,7 @@ static int rndis_scan(struct wiphy *wiphy, struct net_device *dev, static struct cfg80211_bss *rndis_bss_info_update(struct usbnet *usbdev, struct ndis_80211_bssid_ex *bssid) { - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); struct ieee80211_channel *channel; s32 signal; u64 timestamp; @@ -1371,8 +1371,8 @@ out: static void rndis_get_scan_results(struct work_struct *work) { - struct rndis_wext_private *priv = - container_of(work, struct rndis_wext_private, scan_work.work); + struct rndis_wlan_private *priv = + container_of(work, struct rndis_wlan_private, scan_work.work); struct usbnet *usbdev = priv->usbdev; int ret; @@ -1497,7 +1497,7 @@ static int rndis_iw_set_auth(struct net_device *dev, { struct iw_param *p = &wrqu->param; struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); int ret = -ENOTSUPP; switch (p->flags & IW_AUTH_INDEX) { @@ -1578,7 +1578,7 @@ static int rndis_iw_get_auth(struct net_device *dev, { struct iw_param *p = &wrqu->param; struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); switch (p->flags & IW_AUTH_INDEX) { case IW_AUTH_WPA_VERSION: @@ -1609,7 +1609,7 @@ static int rndis_iw_set_encode(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); int ret, index, key_len; u8 *key; @@ -1672,7 +1672,7 @@ static int rndis_iw_set_encode_ext(struct net_device *dev, { struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); int keyidx, flags; keyidx = wrqu->encoding.flags & IW_ENCODE_INDEX; @@ -1713,7 +1713,7 @@ static int rndis_iw_set_genie(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); int ret = 0; #ifdef DEBUG @@ -1747,7 +1747,7 @@ static int rndis_iw_get_genie(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); devdbg(usbdev, "SIOCGIWGENIE"); @@ -1886,7 +1886,7 @@ static int rndis_iw_get_txpower(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); __le32 tx_power; if (priv->radio_on) { @@ -1912,7 +1912,7 @@ static int rndis_iw_set_txpower(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); __le32 tx_power = 0; if (!wrqu->txpower.disabled) { @@ -1969,7 +1969,7 @@ static int rndis_iw_set_mlme(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); struct iw_mlme *mlme = (struct iw_mlme *)extra; unsigned char bssid[ETH_ALEN]; @@ -1994,7 +1994,7 @@ static int rndis_iw_set_mlme(struct net_device *dev, static struct iw_statistics *rndis_get_wireless_stats(struct net_device *dev) { struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); unsigned long flags; spin_lock_irqsave(&priv->stats_lock, flags); @@ -2037,28 +2037,28 @@ static const iw_handler rndis_iw_handler[] = IW_IOCTL(SIOCSIWMLME) = rndis_iw_set_mlme, }; -static const iw_handler rndis_wext_private_handler[] = { +static const iw_handler rndis_wlan_private_handler[] = { }; -static const struct iw_priv_args rndis_wext_private_args[] = { +static const struct iw_priv_args rndis_wlan_private_args[] = { }; static const struct iw_handler_def rndis_iw_handlers = { .num_standard = ARRAY_SIZE(rndis_iw_handler), - .num_private = ARRAY_SIZE(rndis_wext_private_handler), - .num_private_args = ARRAY_SIZE(rndis_wext_private_args), + .num_private = ARRAY_SIZE(rndis_wlan_private_handler), + .num_private_args = ARRAY_SIZE(rndis_wlan_private_args), .standard = (iw_handler *)rndis_iw_handler, - .private = (iw_handler *)rndis_wext_private_handler, - .private_args = (struct iw_priv_args *)rndis_wext_private_args, + .private = (iw_handler *)rndis_wlan_private_handler, + .private_args = (struct iw_priv_args *)rndis_wlan_private_args, .get_wireless_stats = rndis_get_wireless_stats, }; -static void rndis_wext_worker(struct work_struct *work) +static void rndis_wlan_worker(struct work_struct *work) { - struct rndis_wext_private *priv = - container_of(work, struct rndis_wext_private, work); + struct rndis_wlan_private *priv = + container_of(work, struct rndis_wlan_private, work); struct usbnet *usbdev = priv->usbdev; union iwreq_data evt; unsigned char bssid[ETH_ALEN]; @@ -2119,10 +2119,10 @@ get_bssid: set_multicast_list(usbdev); } -static void rndis_wext_set_multicast_list(struct net_device *dev) +static void rndis_wlan_set_multicast_list(struct net_device *dev) { struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); if (test_bit(WORK_SET_MULTICAST_LIST, &priv->work_pending)) return; @@ -2131,9 +2131,9 @@ static void rndis_wext_set_multicast_list(struct net_device *dev) queue_work(priv->workqueue, &priv->work); } -static void rndis_wext_link_change(struct usbnet *usbdev, int state) +static void rndis_wlan_link_change(struct usbnet *usbdev, int state) { - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); /* queue work to avoid recursive calls into rndis_command */ set_bit(state ? WORK_LINK_UP : WORK_LINK_DOWN, &priv->work_pending); @@ -2141,14 +2141,14 @@ static void rndis_wext_link_change(struct usbnet *usbdev, int state) } -static int rndis_wext_get_caps(struct usbnet *usbdev) +static int rndis_wlan_get_caps(struct usbnet *usbdev) { struct { __le32 num_items; __le32 items[8]; } networks_supported; int len, retval, i, n; - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); /* determine supported modes */ len = sizeof(networks_supported); @@ -2181,8 +2181,8 @@ static int rndis_wext_get_caps(struct usbnet *usbdev) #define STATS_UPDATE_JIFFIES (HZ) static void rndis_update_wireless_stats(struct work_struct *work) { - struct rndis_wext_private *priv = - container_of(work, struct rndis_wext_private, stats_work.work); + struct rndis_wlan_private *priv = + container_of(work, struct rndis_wlan_private, stats_work.work); struct usbnet *usbdev = priv->usbdev; struct iw_statistics iwstats; __le32 rssi, tmp; @@ -2297,7 +2297,7 @@ static int bcm4320a_early_init(struct usbnet *usbdev) static int bcm4320b_early_init(struct usbnet *usbdev) { - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); char buf[8]; /* Early initialization settings, setting these won't have effect @@ -2363,21 +2363,21 @@ static int bcm4320b_early_init(struct usbnet *usbdev) } /* same as rndis_netdev_ops but with local multicast handler */ -static const struct net_device_ops rndis_wext_netdev_ops = { +static const struct net_device_ops rndis_wlan_netdev_ops = { .ndo_open = usbnet_open, .ndo_stop = usbnet_stop, .ndo_start_xmit = usbnet_start_xmit, .ndo_tx_timeout = usbnet_tx_timeout, .ndo_set_mac_address = eth_mac_addr, .ndo_validate_addr = eth_validate_addr, - .ndo_set_multicast_list = rndis_wext_set_multicast_list, + .ndo_set_multicast_list = rndis_wlan_set_multicast_list, }; -static int rndis_wext_bind(struct usbnet *usbdev, struct usb_interface *intf) +static int rndis_wlan_bind(struct usbnet *usbdev, struct usb_interface *intf) { struct wiphy *wiphy; - struct rndis_wext_private *priv; + struct rndis_wlan_private *priv; int retval, len; __le32 tmp; @@ -2385,7 +2385,7 @@ static int rndis_wext_bind(struct usbnet *usbdev, struct usb_interface *intf) * NOTE: We only support a single virtual interface, so wiphy * and wireless_dev are somewhat synonymous for this device. */ - wiphy = wiphy_new(&rndis_config_ops, sizeof(struct rndis_wext_private)); + wiphy = wiphy_new(&rndis_config_ops, sizeof(struct rndis_wlan_private)); if (!wiphy) return -ENOMEM; @@ -2395,7 +2395,7 @@ static int rndis_wext_bind(struct usbnet *usbdev, struct usb_interface *intf) priv->wdev.iftype = NL80211_IFTYPE_STATION; /* These have to be initialized before calling generic_rndis_bind(). - * Otherwise we'll be in big trouble in rndis_wext_early_init(). + * Otherwise we'll be in big trouble in rndis_wlan_early_init(). */ usbdev->driver_priv = priv; usbdev->net->wireless_handlers = &rndis_iw_handlers; @@ -2406,7 +2406,7 @@ static int rndis_wext_bind(struct usbnet *usbdev, struct usb_interface *intf) /* because rndis_command() sleeps we need to use workqueue */ priv->workqueue = create_singlethread_workqueue("rndis_wlan"); - INIT_WORK(&priv->work, rndis_wext_worker); + INIT_WORK(&priv->work, rndis_wlan_worker); INIT_DELAYED_WORK(&priv->stats_work, rndis_update_wireless_stats); INIT_DELAYED_WORK(&priv->scan_work, rndis_get_scan_results); @@ -2420,9 +2420,9 @@ static int rndis_wext_bind(struct usbnet *usbdev, struct usb_interface *intf) * picks up rssi to closest station instead of to access point). * * rndis_host wants to avoid all OID as much as possible - * so do promisc/multicast handling in rndis_wext. + * so do promisc/multicast handling in rndis_wlan. */ - usbdev->net->netdev_ops = &rndis_wext_netdev_ops; + usbdev->net->netdev_ops = &rndis_wlan_netdev_ops; tmp = RNDIS_PACKET_TYPE_DIRECTED | RNDIS_PACKET_TYPE_BROADCAST; retval = rndis_set_oid(usbdev, OID_GEN_CURRENT_PACKET_FILTER, &tmp, @@ -2455,7 +2455,7 @@ static int rndis_wext_bind(struct usbnet *usbdev, struct usb_interface *intf) wiphy->max_scan_ssids = 1; /* TODO: fill-out band information based on priv->caps */ - rndis_wext_get_caps(usbdev); + rndis_wlan_get_caps(usbdev); memcpy(priv->channels, rndis_channels, sizeof(rndis_channels)); memcpy(priv->rates, rndis_rates, sizeof(rndis_rates)); @@ -2497,9 +2497,9 @@ fail: } -static void rndis_wext_unbind(struct usbnet *usbdev, struct usb_interface *intf) +static void rndis_wlan_unbind(struct usbnet *usbdev, struct usb_interface *intf) { - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); /* turn radio off */ disassociate(usbdev, 0); @@ -2520,7 +2520,7 @@ static void rndis_wext_unbind(struct usbnet *usbdev, struct usb_interface *intf) } -static int rndis_wext_reset(struct usbnet *usbdev) +static int rndis_wlan_reset(struct usbnet *usbdev) { return deauthenticate(usbdev); } @@ -2529,40 +2529,40 @@ static int rndis_wext_reset(struct usbnet *usbdev) static const struct driver_info bcm4320b_info = { .description = "Wireless RNDIS device, BCM4320b based", .flags = FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT, - .bind = rndis_wext_bind, - .unbind = rndis_wext_unbind, + .bind = rndis_wlan_bind, + .unbind = rndis_wlan_unbind, .status = rndis_status, .rx_fixup = rndis_rx_fixup, .tx_fixup = rndis_tx_fixup, - .reset = rndis_wext_reset, + .reset = rndis_wlan_reset, .early_init = bcm4320b_early_init, - .link_change = rndis_wext_link_change, + .link_change = rndis_wlan_link_change, }; static const struct driver_info bcm4320a_info = { .description = "Wireless RNDIS device, BCM4320a based", .flags = FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT, - .bind = rndis_wext_bind, - .unbind = rndis_wext_unbind, + .bind = rndis_wlan_bind, + .unbind = rndis_wlan_unbind, .status = rndis_status, .rx_fixup = rndis_rx_fixup, .tx_fixup = rndis_tx_fixup, - .reset = rndis_wext_reset, + .reset = rndis_wlan_reset, .early_init = bcm4320a_early_init, - .link_change = rndis_wext_link_change, + .link_change = rndis_wlan_link_change, }; -static const struct driver_info rndis_wext_info = { +static const struct driver_info rndis_wlan_info = { .description = "Wireless RNDIS device", .flags = FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT, - .bind = rndis_wext_bind, - .unbind = rndis_wext_unbind, + .bind = rndis_wlan_bind, + .unbind = rndis_wlan_unbind, .status = rndis_status, .rx_fixup = rndis_rx_fixup, .tx_fixup = rndis_tx_fixup, - .reset = rndis_wext_reset, + .reset = rndis_wlan_reset, .early_init = bcm4320a_early_init, - .link_change = rndis_wext_link_change, + .link_change = rndis_wlan_link_change, }; /*-------------------------------------------------------------------------*/ @@ -2672,11 +2672,11 @@ static const struct usb_device_id products [] = { { /* RNDIS is MSFT's un-official variant of CDC ACM */ USB_INTERFACE_INFO(USB_CLASS_COMM, 2 /* ACM */, 0x0ff), - .driver_info = (unsigned long) &rndis_wext_info, + .driver_info = (unsigned long) &rndis_wlan_info, }, { /* "ActiveSync" is an undocumented variant of RNDIS, used in WM5 */ USB_INTERFACE_INFO(USB_CLASS_MISC, 1, 1), - .driver_info = (unsigned long) &rndis_wext_info, + .driver_info = (unsigned long) &rndis_wlan_info, }, { }, // END }; -- cgit v1.2.3 From 4d1d49858c0a5a4fb1be4bc7972754cd640245ba Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Thu, 4 Jun 2009 21:57:03 +0200 Subject: net/libertas: remove GPIO-CS handling in SPI interface code This removes the dependency on GPIO framework and lets the SPI host driver handle the chip select. The SPI host driver is required to keep the CS active for the entire message unless cs_change says otherwise. This patch collects the two/three single SPI transfers into a message. Also the delay in read path in case use_dummy_writes are not used is moved into the SPI host driver. Tested-by: Mike Rapoport Tested-by: Andrey Yurovsky Signed-off-by: Sebastian Andrzej Siewior Acked-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/Kconfig | 2 +- drivers/net/wireless/libertas/if_spi.c | 92 ++++++++++++++++------------------ include/linux/spi/libertas_spi.h | 3 -- 3 files changed, 45 insertions(+), 52 deletions(-) diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index daf4c805be5..fb7541c28e5 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -153,7 +153,7 @@ config LIBERTAS_SDIO config LIBERTAS_SPI tristate "Marvell Libertas 8686 SPI 802.11b/g cards" - depends on LIBERTAS && SPI && GENERIC_GPIO + depends on LIBERTAS && SPI ---help--- A driver for Marvell Libertas 8686 SPI devices. diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c index ea23c5de142..f8c2898d82b 100644 --- a/drivers/net/wireless/libertas/if_spi.c +++ b/drivers/net/wireless/libertas/if_spi.c @@ -19,7 +19,6 @@ #include #include -#include #include #include #include @@ -51,13 +50,6 @@ struct if_spi_card { u16 card_id; u8 card_rev; - /* Pin number for our GPIO chip-select. */ - /* TODO: Once the generic SPI layer has some additional features, we - * should take this out and use the normal chip select here. - * We need support for chip select delays, and not dropping chipselect - * after each word. */ - int gpio_cs; - /* The last time that we initiated an SPU operation */ unsigned long prev_xfer_time; @@ -130,12 +122,10 @@ static void spu_transaction_init(struct if_spi_card *card) * If not, we have to busy-wait to be on the safe side. */ ndelay(400); } - gpio_set_value(card->gpio_cs, 0); /* assert CS */ } static void spu_transaction_finish(struct if_spi_card *card) { - gpio_set_value(card->gpio_cs, 1); /* drop CS */ card->prev_xfer_time = jiffies; } @@ -145,6 +135,13 @@ static int spu_write(struct if_spi_card *card, u16 reg, const u8 *buf, int len) { int err = 0; u16 reg_out = cpu_to_le16(reg | IF_SPI_WRITE_OPERATION_MASK); + struct spi_message m; + struct spi_transfer reg_trans; + struct spi_transfer data_trans; + + spi_message_init(&m); + memset(®_trans, 0, sizeof(reg_trans)); + memset(&data_trans, 0, sizeof(data_trans)); /* You must give an even number of bytes to the SPU, even if it * doesn't care about the last one. */ @@ -153,13 +150,16 @@ static int spu_write(struct if_spi_card *card, u16 reg, const u8 *buf, int len) spu_transaction_init(card); /* write SPU register index */ - err = spi_write(card->spi, (u8 *)®_out, sizeof(u16)); - if (err) - goto out; + reg_trans.tx_buf = ®_out; + reg_trans.len = sizeof(reg_out); - err = spi_write(card->spi, buf, len); + data_trans.tx_buf = buf; + data_trans.len = len; -out: + spi_message_add_tail(®_trans, &m); + spi_message_add_tail(&data_trans, &m); + + err = spi_sync(card->spi, &m); spu_transaction_finish(card); return err; } @@ -186,10 +186,13 @@ static inline int spu_reg_is_port_reg(u16 reg) static int spu_read(struct if_spi_card *card, u16 reg, u8 *buf, int len) { - unsigned int i, delay; + unsigned int delay; int err = 0; - u16 zero = 0; u16 reg_out = cpu_to_le16(reg | IF_SPI_READ_OPERATION_MASK); + struct spi_message m; + struct spi_transfer reg_trans; + struct spi_transfer dummy_trans; + struct spi_transfer data_trans; /* You must take an even number of bytes from the SPU, even if you * don't care about the last one. */ @@ -197,29 +200,34 @@ static int spu_read(struct if_spi_card *card, u16 reg, u8 *buf, int len) spu_transaction_init(card); + spi_message_init(&m); + memset(®_trans, 0, sizeof(reg_trans)); + memset(&dummy_trans, 0, sizeof(dummy_trans)); + memset(&data_trans, 0, sizeof(data_trans)); + /* write SPU register index */ - err = spi_write(card->spi, (u8 *)®_out, sizeof(u16)); - if (err) - goto out; + reg_trans.tx_buf = ®_out; + reg_trans.len = sizeof(reg_out); + spi_message_add_tail(®_trans, &m); delay = spu_reg_is_port_reg(reg) ? card->spu_port_delay : card->spu_reg_delay; if (card->use_dummy_writes) { /* Clock in dummy cycles while the SPU fills the FIFO */ - for (i = 0; i < delay / 16; ++i) { - err = spi_write(card->spi, (u8 *)&zero, sizeof(u16)); - if (err) - return err; - } + dummy_trans.len = delay / 8; + spi_message_add_tail(&dummy_trans, &m); } else { /* Busy-wait while the SPU fills the FIFO */ - ndelay(100 + (delay * 10)); + reg_trans.delay_usecs = + DIV_ROUND_UP((100 + (delay * 10)), 1000); } /* read in data */ - err = spi_read(card->spi, buf, len); + data_trans.rx_buf = buf; + data_trans.len = len; + spi_message_add_tail(&data_trans, &m); -out: + err = spi_sync(card->spi, &m); spu_transaction_finish(card); return err; } @@ -1049,7 +1057,6 @@ static int __devinit if_spi_probe(struct spi_device *spi) spi_set_drvdata(spi, card); card->pdata = pdata; card->spi = spi; - card->gpio_cs = pdata->gpio_cs; card->prev_xfer_time = jiffies; sema_init(&card->spi_ready, 0); @@ -1058,26 +1065,18 @@ static int __devinit if_spi_probe(struct spi_device *spi) INIT_LIST_HEAD(&card->data_packet_list); spin_lock_init(&card->buffer_lock); - /* set up GPIO CS line. TODO: use regular CS line */ - err = gpio_request(card->gpio_cs, "if_spi_gpio_chip_select"); - if (err) - goto free_card; - err = gpio_direction_output(card->gpio_cs, 1); - if (err) - goto free_gpio; - /* Initialize the SPI Interface Unit */ err = spu_init(card, pdata->use_dummy_writes); if (err) - goto free_gpio; + goto free_card; err = spu_get_chip_revision(card, &card->card_id, &card->card_rev); if (err) - goto free_gpio; + goto free_card; /* Firmware load */ err = spu_read_u32(card, IF_SPI_SCRATCH_4_REG, &scratch); if (err) - goto free_gpio; + goto free_card; if (scratch == SUCCESSFUL_FW_DOWNLOAD_MAGIC) lbs_deb_spi("Firmware is already loaded for " "Marvell WLAN 802.11 adapter\n"); @@ -1085,7 +1084,7 @@ static int __devinit if_spi_probe(struct spi_device *spi) err = if_spi_calculate_fw_names(card->card_id, card->helper_fw_name, card->main_fw_name); if (err) - goto free_gpio; + goto free_card; lbs_deb_spi("Initializing FW for Marvell WLAN 802.11 adapter " "(chip_id = 0x%04x, chip_rev = 0x%02x) " @@ -1096,23 +1095,23 @@ static int __devinit if_spi_probe(struct spi_device *spi) spi->max_speed_hz); err = if_spi_prog_helper_firmware(card); if (err) - goto free_gpio; + goto free_card; err = if_spi_prog_main_firmware(card); if (err) - goto free_gpio; + goto free_card; lbs_deb_spi("loaded FW for Marvell WLAN 802.11 adapter\n"); } err = spu_set_interrupt_mode(card, 0, 1); if (err) - goto free_gpio; + goto free_card; /* Register our card with libertas. * This will call alloc_etherdev */ priv = lbs_add_card(card, &spi->dev); if (!priv) { err = -ENOMEM; - goto free_gpio; + goto free_card; } card->priv = priv; priv->card = card; @@ -1157,8 +1156,6 @@ terminate_thread: if_spi_terminate_spi_thread(card); remove_card: lbs_remove_card(priv); /* will call free_netdev */ -free_gpio: - gpio_free(card->gpio_cs); free_card: free_if_spi_card(card); out: @@ -1179,7 +1176,6 @@ static int __devexit libertas_spi_remove(struct spi_device *spi) free_irq(spi->irq, card); if_spi_terminate_spi_thread(card); lbs_remove_card(priv); /* will call free_netdev */ - gpio_free(card->gpio_cs); if (card->pdata->teardown) card->pdata->teardown(spi); free_if_spi_card(card); diff --git a/include/linux/spi/libertas_spi.h b/include/linux/spi/libertas_spi.h index 79506f5f9e6..1b5d5384fcd 100644 --- a/include/linux/spi/libertas_spi.h +++ b/include/linux/spi/libertas_spi.h @@ -22,9 +22,6 @@ struct libertas_spi_platform_data { * speed, you may want to use 0 here. */ u16 use_dummy_writes; - /* GPIO number to use as chip select */ - u16 gpio_cs; - /* Board specific setup/teardown */ int (*setup)(struct spi_device *spi); int (*teardown)(struct spi_device *spi); -- cgit v1.2.3 From 5ee58d7e6ad019675b4090582aec4fa1180d8703 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Fri, 5 Jun 2009 08:21:50 -0400 Subject: mac80211: fix minstrel single-rate memory corruption The minstrel rate controller periodically looks up rate indexes in a sampling table. When accessing a specific row and column, minstrel correctly does a bounds check which, on the surface, appears to handle the case where mi->n_rates < 2. However, mi->sample_idx is actually defined as an unsigned, so the right hand side is taken to be a huge positive number when negative, and the check will always fail. Consequently, the RC will overrun the array and cause random memory corruption when communicating with a peer that has only a single rate. The max value of mi->sample_idx is around 25 so casting to int should have no ill effects. Without the change, uptime is a few minutes under load with an AP that has a single hard-coded rate, and both the AP and STA could potentially crash. With the change, both lasted 12 hours with a steady load. Thanks to Ognjen Maric for providing the single-rate clue so I could reproduce this. This fixes http://bugzilla.kernel.org/show_bug.cgi?id=12490 on the regression list (also http://bugzilla.kernel.org/show_bug.cgi?id=13000). Cc: stable@kernel.org Reported-by: Sergey S. Kostyliov Reported-by: Ognjen Maric Signed-off-by: Bob Copeland Signed-off-by: John W. Linville --- net/mac80211/rc80211_minstrel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c index 0a11515341b..b218b98fba7 100644 --- a/net/mac80211/rc80211_minstrel.c +++ b/net/mac80211/rc80211_minstrel.c @@ -215,7 +215,7 @@ minstrel_get_next_sample(struct minstrel_sta_info *mi) unsigned int sample_ndx; sample_ndx = SAMPLE_TBL(mi, mi->sample_idx, mi->sample_column); mi->sample_idx++; - if (mi->sample_idx > (mi->n_rates - 2)) { + if ((int) mi->sample_idx > (mi->n_rates - 2)) { mi->sample_idx = 0; mi->sample_column++; if (mi->sample_column >= SAMPLE_COLUMNS) -- cgit v1.2.3 From b52a033c2c501a8015df3727a4bd73389ccb1641 Mon Sep 17 00:00:00 2001 From: Matthieu CASTET Date: Thu, 4 Jun 2009 23:18:33 +0200 Subject: b43: Fix possible unaligned u32 access Fix possible unaligned u32 access in b43_generate_plcp_hdr(). Unaligned data is read/write with a u32 pointer instead of using the packed structure. Some versions of gcc ignore the "packed" attribute, if the structure element is accessed through a local pointer. Signed-off-by: Matthieu CASTET Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/b43/xmit.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c index a63d88841df..55f36a7254d 100644 --- a/drivers/net/wireless/b43/xmit.c +++ b/drivers/net/wireless/b43/xmit.c @@ -118,7 +118,6 @@ u8 b43_plcp_get_ratecode_ofdm(const u8 bitrate) void b43_generate_plcp_hdr(struct b43_plcp_hdr4 *plcp, const u16 octets, const u8 bitrate) { - __le32 *data = &(plcp->data); __u8 *raw = plcp->raw; if (b43_is_ofdm_rate(bitrate)) { @@ -127,7 +126,7 @@ void b43_generate_plcp_hdr(struct b43_plcp_hdr4 *plcp, d = b43_plcp_get_ratecode_ofdm(bitrate); B43_WARN_ON(octets & 0xF000); d |= (octets << 5); - *data = cpu_to_le32(d); + plcp->data = cpu_to_le32(d); } else { u32 plen; @@ -141,7 +140,7 @@ void b43_generate_plcp_hdr(struct b43_plcp_hdr4 *plcp, raw[1] = 0x04; } else raw[1] = 0x04; - *data |= cpu_to_le32(plen << 16); + plcp->data |= cpu_to_le32(plen << 16); raw[0] = b43_plcp_get_ratecode_cck(bitrate); } } -- cgit v1.2.3 From dacb6f1d8fa5200efc4e609fe63a750b960993b6 Mon Sep 17 00:00:00 2001 From: matthieu castet Date: Thu, 4 Jun 2009 22:16:18 +0200 Subject: mac80211 : fix unaligned rx skb mac80211 is checking is the skb is aligned on 32 bit boundary. But it is checking against ethernet header, whereas Linux expect IP header aligned. And ethernet ether size is 6*2+2=14, so aligning ethernet header make IP header unaligned. Signed-off-by: Matthieu CASTET Signed-off-by: John W. Linville --- net/mac80211/rx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 6a9b8e63a6b..75412518510 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1335,7 +1335,7 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx) * mac80211. That also explains the __skb_push() * below. */ - align = (unsigned long)skb->data & 3; + align = ((unsigned long)(skb->data + sizeof(struct ethhdr))) & 3; if (align) { if (WARN_ON(skb_headroom(skb) < 3)) { dev_kfree_skb(skb); -- cgit v1.2.3 From 2543a0c4c0fde46f9f206cec1e1cf951a2a63a66 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 5 Jun 2009 11:47:43 +0200 Subject: ar9170: interpret firmware debug commands This adds new commands that the original firmware will not send but we can use them to debug firmware. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ar9170/main.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c index b104d7efd67..de57aa92a28 100644 --- a/drivers/net/wireless/ath/ar9170/main.c +++ b/drivers/net/wireless/ath/ar9170/main.c @@ -442,6 +442,38 @@ void ar9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len) /* retransmission issue / SIFS/EIFS collision ?! */ break; + /* firmware debug */ + case 0xca: + printk(KERN_DEBUG "ar9170 FW: %.*s\n", len - 4, (char *)buf + 4); + break; + case 0xcb: + len -= 4; + + switch (len) { + case 1: + printk(KERN_DEBUG "ar9170 FW: u8: %#.2x\n", + *((char *)buf + 4)); + break; + case 2: + printk(KERN_DEBUG "ar9170 FW: u8: %#.4x\n", + le16_to_cpup((__le16 *)((char *)buf + 4))); + break; + case 4: + printk(KERN_DEBUG "ar9170 FW: u8: %#.8x\n", + le32_to_cpup((__le32 *)((char *)buf + 4))); + break; + case 8: + printk(KERN_DEBUG "ar9170 FW: u8: %#.16lx\n", + (unsigned long)le64_to_cpup( + (__le64 *)((char *)buf + 4))); + break; + } + break; + case 0xcc: + print_hex_dump_bytes("ar9170 FW:", DUMP_PREFIX_NONE, + (char *)buf + 4, len - 4); + break; + default: printk(KERN_INFO "received unhandled event %x\n", cmd->type); print_hex_dump_bytes("dump:", DUMP_PREFIX_NONE, buf, len); -- cgit v1.2.3 From 9b9c5aaeedfda256ed77094303e2a7242c3290da Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 6 Jun 2009 05:07:23 +0200 Subject: ar9170: xmit code revamp This patch is a back-port from aggregation testing code. In the past, we didn't limit the amount of active tx urbs. However, ar9170 only has a limited buffer reserved for pending data frames. This wasn't much of a problem with the slower 802.11b/g. We simply stopped the full queue and moved on to something different in the mean time. But - as you guessed it - this simple approach stands in way for a decent aggregation implementation. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ar9170/ar9170.h | 34 +- drivers/net/wireless/ath/ar9170/hw.h | 3 + drivers/net/wireless/ath/ar9170/main.c | 644 ++++++++++++++++++++----------- drivers/net/wireless/ath/ar9170/usb.c | 122 ++++-- drivers/net/wireless/ath/ar9170/usb.h | 7 +- 5 files changed, 550 insertions(+), 260 deletions(-) diff --git a/drivers/net/wireless/ath/ar9170/ar9170.h b/drivers/net/wireless/ath/ar9170/ar9170.h index c7cba66b63c..bb97981fb24 100644 --- a/drivers/net/wireless/ath/ar9170/ar9170.h +++ b/drivers/net/wireless/ath/ar9170/ar9170.h @@ -109,6 +109,11 @@ struct ar9170_rxstream_mpdu_merge { bool has_plcp; }; +#define AR9170_QUEUE_TIMEOUT 64 +#define AR9170_TX_TIMEOUT 8 +#define AR9170_JANITOR_DELAY 128 +#define AR9170_TX_INVALID_RATE 0xffffffff + struct ar9170 { struct ieee80211_hw *hw; struct mutex mutex; @@ -117,10 +122,11 @@ struct ar9170 { int (*open)(struct ar9170 *); void (*stop)(struct ar9170 *); - int (*tx)(struct ar9170 *, struct sk_buff *, bool, unsigned int); + int (*tx)(struct ar9170 *, struct sk_buff *); int (*exec_cmd)(struct ar9170 *, enum ar9170_cmd, u32 , void *, u32 , void *); void (*callback_cmd)(struct ar9170 *, u32 , void *); + int (*flush)(struct ar9170 *); /* interface mode settings */ struct ieee80211_vif *vif; @@ -177,10 +183,10 @@ struct ar9170 { struct ar9170_eeprom eeprom; struct ath_regulatory regulatory; - /* global tx status for unregistered Stations. */ - struct sk_buff_head global_tx_status; - struct sk_buff_head global_tx_status_waste; - struct delayed_work tx_status_janitor; + /* tx queues - as seen by hw - */ + struct sk_buff_head tx_pending[__AR9170_NUM_TXQ]; + struct sk_buff_head tx_status[__AR9170_NUM_TXQ]; + struct delayed_work tx_janitor; /* rxstream mpdu merge */ struct ar9170_rxstream_mpdu_merge rx_mpdu; @@ -189,11 +195,19 @@ struct ar9170 { }; struct ar9170_sta_info { - struct sk_buff_head tx_status[__AR9170_NUM_TXQ]; }; -#define IS_STARTED(a) (a->state >= AR9170_STARTED) -#define IS_ACCEPTING_CMD(a) (a->state >= AR9170_IDLE) +#define AR9170_TX_FLAG_WAIT_FOR_ACK BIT(0) +#define AR9170_TX_FLAG_NO_ACK BIT(1) +#define AR9170_TX_FLAG_BLOCK_ACK BIT(2) + +struct ar9170_tx_info { + unsigned long timeout; + unsigned int flags; +}; + +#define IS_STARTED(a) (((struct ar9170 *)a)->state >= AR9170_STARTED) +#define IS_ACCEPTING_CMD(a) (((struct ar9170 *)a)->state >= AR9170_IDLE) #define AR9170_FILTER_CHANGED_MODE BIT(0) #define AR9170_FILTER_CHANGED_MULTICAST BIT(1) @@ -204,9 +218,9 @@ void *ar9170_alloc(size_t priv_size); int ar9170_register(struct ar9170 *ar, struct device *pdev); void ar9170_rx(struct ar9170 *ar, struct sk_buff *skb); void ar9170_unregister(struct ar9170 *ar); -void ar9170_handle_tx_status(struct ar9170 *ar, struct sk_buff *skb, - bool update_statistics, u16 tx_status); +void ar9170_tx_callback(struct ar9170 *ar, struct sk_buff *skb); void ar9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len); +int ar9170_nag_limiter(struct ar9170 *ar); /* MAC */ int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb); diff --git a/drivers/net/wireless/ath/ar9170/hw.h b/drivers/net/wireless/ath/ar9170/hw.h index 3c8004fb730..6cbfb2f8339 100644 --- a/drivers/net/wireless/ath/ar9170/hw.h +++ b/drivers/net/wireless/ath/ar9170/hw.h @@ -420,4 +420,7 @@ enum ar9170_txq { __AR9170_NUM_TXQ, }; +#define AR9170_TXQ_DEPTH 32 +#define AR9170_TX_MAX_PENDING 128 + #endif /* __AR9170_HW_H */ diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c index de57aa92a28..9d38cf60a0d 100644 --- a/drivers/net/wireless/ath/ar9170/main.c +++ b/drivers/net/wireless/ath/ar9170/main.c @@ -173,59 +173,122 @@ static struct ieee80211_supported_band ar9170_band_5GHz = { .ht_cap = AR9170_HT_CAP, }; -#ifdef AR9170_QUEUE_DEBUG -/* - * In case some wants works with AR9170's crazy tx_status queueing techniques. - * He might need this rather useful probing function. - * - * NOTE: caller must hold the queue's spinlock! - */ +static void ar9170_tx(struct ar9170 *ar); +#ifdef AR9170_QUEUE_DEBUG static void ar9170_print_txheader(struct ar9170 *ar, struct sk_buff *skb) { struct ar9170_tx_control *txc = (void *) skb->data; - struct ieee80211_hdr *hdr = (void *)txc->frame_data; + struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb); + struct ar9170_tx_info *arinfo = (void *) txinfo->rate_driver_data; + struct ieee80211_hdr *hdr = (void *) txc->frame_data; - printk(KERN_DEBUG "%s: => FRAME [skb:%p, queue:%d, DA:[%pM] " - "mac_control:%04x, phy_control:%08x]\n", + printk(KERN_DEBUG "%s: => FRAME [skb:%p, q:%d, DA:[%pM] flags:%x " + "mac_ctrl:%04x, phy_ctrl:%08x, timeout:[%d ms]]\n", wiphy_name(ar->hw->wiphy), skb, skb_get_queue_mapping(skb), - ieee80211_get_DA(hdr), le16_to_cpu(txc->mac_control), - le32_to_cpu(txc->phy_control)); + ieee80211_get_DA(hdr), arinfo->flags, + le16_to_cpu(txc->mac_control), le32_to_cpu(txc->phy_control), + jiffies_to_msecs(arinfo->timeout - jiffies)); } -static void ar9170_dump_station_tx_status_queue(struct ar9170 *ar, - struct sk_buff_head *queue) +static void __ar9170_dump_txqueue(struct ar9170 *ar, + struct sk_buff_head *queue) { struct sk_buff *skb; int i = 0; printk(KERN_DEBUG "---[ cut here ]---\n"); - printk(KERN_DEBUG "%s: %d entries in tx_status queue.\n", + printk(KERN_DEBUG "%s: %d entries in queue.\n", wiphy_name(ar->hw->wiphy), skb_queue_len(queue)); skb_queue_walk(queue, skb) { - struct ar9170_tx_control *txc = (void *) skb->data; - struct ieee80211_hdr *hdr = (void *)txc->frame_data; - - printk(KERN_DEBUG "index:%d => \n", i); + printk(KERN_DEBUG "index:%d => \n", i++); ar9170_print_txheader(ar, skb); } + if (i != skb_queue_len(queue)) + printk(KERN_DEBUG "WARNING: queue frame counter " + "mismatch %d != %d\n", skb_queue_len(queue), i); printk(KERN_DEBUG "---[ end ]---\n"); } -#endif /* AR9170_QUEUE_DEBUG */ -void ar9170_handle_tx_status(struct ar9170 *ar, struct sk_buff *skb, - bool valid_status, u16 tx_status) +static void ar9170_dump_txqueue(struct ar9170 *ar, + struct sk_buff_head *queue) +{ + unsigned long flags; + + spin_lock_irqsave(&queue->lock, flags); + __ar9170_dump_txqueue(ar, queue); + spin_unlock_irqrestore(&queue->lock, flags); +} + +static void __ar9170_dump_txstats(struct ar9170 *ar) +{ + int i; + + printk(KERN_DEBUG "%s: QoS queue stats\n", + wiphy_name(ar->hw->wiphy)); + + for (i = 0; i < __AR9170_NUM_TXQ; i++) + printk(KERN_DEBUG "%s: queue:%d limit:%d len:%d waitack:%d\n", + wiphy_name(ar->hw->wiphy), i, ar->tx_stats[i].limit, + ar->tx_stats[i].len, skb_queue_len(&ar->tx_status[i])); +} + +static void ar9170_dump_txstats(struct ar9170 *ar) { - struct ieee80211_tx_info *txinfo; - unsigned int retries = 0, queue = skb_get_queue_mapping(skb); unsigned long flags; spin_lock_irqsave(&ar->tx_stats_lock, flags); - ar->tx_stats[queue].len--; - if (ieee80211_queue_stopped(ar->hw, queue)) - ieee80211_wake_queue(ar->hw, queue); + __ar9170_dump_txstats(ar); spin_unlock_irqrestore(&ar->tx_stats_lock, flags); +} +#endif /* AR9170_QUEUE_DEBUG */ + +/* caller must guarantee exclusive access for _bin_ queue. */ +static void ar9170_recycle_expired(struct ar9170 *ar, + struct sk_buff_head *queue, + struct sk_buff_head *bin) +{ + struct sk_buff *skb, *old = NULL; + unsigned long flags; + + spin_lock_irqsave(&queue->lock, flags); + while ((skb = skb_peek(queue))) { + struct ieee80211_tx_info *txinfo; + struct ar9170_tx_info *arinfo; + + txinfo = IEEE80211_SKB_CB(skb); + arinfo = (void *) txinfo->rate_driver_data; + + if (time_is_before_jiffies(arinfo->timeout)) { +#ifdef AR9170_QUEUE_DEBUG + printk(KERN_DEBUG "%s: [%ld > %ld] frame expired => " + "recycle \n", wiphy_name(ar->hw->wiphy), + jiffies, arinfo->timeout); + ar9170_print_txheader(ar, skb); +#endif /* AR9170_QUEUE_DEBUG */ + __skb_unlink(skb, queue); + __skb_queue_tail(bin, skb); + } else { + break; + } + + if (unlikely(old == skb)) { + /* bail out - queue is shot. */ + + WARN_ON(1); + break; + } + old = skb; + } + spin_unlock_irqrestore(&queue->lock, flags); +} + +static void ar9170_tx_status(struct ar9170 *ar, struct sk_buff *skb, + u16 tx_status) +{ + struct ieee80211_tx_info *txinfo; + unsigned int retries = 0; txinfo = IEEE80211_SKB_CB(skb); ieee80211_tx_info_clear_status(txinfo); @@ -247,45 +310,61 @@ void ar9170_handle_tx_status(struct ar9170 *ar, struct sk_buff *skb, break; } - if (valid_status) - txinfo->status.rates[0].count = retries + 1; - + txinfo->status.rates[0].count = retries + 1; skb_pull(skb, sizeof(struct ar9170_tx_control)); ieee80211_tx_status_irqsafe(ar->hw, skb); } -static struct sk_buff *ar9170_find_skb_in_queue(struct ar9170 *ar, - const u8 *mac, - const u32 queue, - struct sk_buff_head *q) +void ar9170_tx_callback(struct ar9170 *ar, struct sk_buff *skb) { + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ar9170_tx_info *arinfo = (void *) info->rate_driver_data; + unsigned int queue = skb_get_queue_mapping(skb); unsigned long flags; - struct sk_buff *skb; - spin_lock_irqsave(&q->lock, flags); - skb_queue_walk(q, skb) { - struct ar9170_tx_control *txc = (void *) skb->data; - struct ieee80211_hdr *hdr = (void *) txc->frame_data; - u32 txc_queue = (le32_to_cpu(txc->phy_control) & - AR9170_TX_PHY_QOS_MASK) >> - AR9170_TX_PHY_QOS_SHIFT; + spin_lock_irqsave(&ar->tx_stats_lock, flags); + ar->tx_stats[queue].len--; - if ((queue != txc_queue) || - (compare_ether_addr(ieee80211_get_DA(hdr), mac))) - continue; + if (skb_queue_empty(&ar->tx_pending[queue])) { +#ifdef AR9170_QUEUE_STOP_DEBUG + printk(KERN_DEBUG "%s: wake queue %d\n", + wiphy_name(ar->hw->wiphy), queue); + __ar9170_dump_txstats(ar); +#endif /* AR9170_QUEUE_STOP_DEBUG */ + ieee80211_wake_queue(ar->hw, queue); + } + spin_unlock_irqrestore(&ar->tx_stats_lock, flags); - __skb_unlink(skb, q); - spin_unlock_irqrestore(&q->lock, flags); - return skb; + if (arinfo->flags & AR9170_TX_FLAG_BLOCK_ACK) { + dev_kfree_skb_any(skb); + } else if (arinfo->flags & AR9170_TX_FLAG_WAIT_FOR_ACK) { + arinfo->timeout = jiffies + + msecs_to_jiffies(AR9170_TX_TIMEOUT); + + skb_queue_tail(&ar->tx_status[queue], skb); + } else if (arinfo->flags & AR9170_TX_FLAG_NO_ACK) { + ar9170_tx_status(ar, skb, AR9170_TX_STATUS_FAILED); + } else { +#ifdef AR9170_QUEUE_DEBUG + printk(KERN_DEBUG "%s: unsupported frame flags!\n", + wiphy_name(ar->hw->wiphy)); + ar9170_print_txheader(ar, skb); +#endif /* AR9170_QUEUE_DEBUG */ + dev_kfree_skb_any(skb); + } + + if (!ar->tx_stats[queue].len && + !skb_queue_empty(&ar->tx_pending[queue])) { + ar9170_tx(ar); } - spin_unlock_irqrestore(&q->lock, flags); - return NULL; } -static struct sk_buff *ar9170_find_queued_skb(struct ar9170 *ar, const u8 *mac, - const u32 queue) +static struct sk_buff *ar9170_get_queued_skb(struct ar9170 *ar, + const u8 *mac, + struct sk_buff_head *queue, + const u32 rate) { - struct ieee80211_sta *sta; + unsigned long flags; struct sk_buff *skb; /* @@ -296,78 +375,91 @@ static struct sk_buff *ar9170_find_queued_skb(struct ar9170 *ar, const u8 *mac, * the firmware provided (-> destination MAC, and phy_control) - * and hope that we picked the right one... */ - rcu_read_lock(); - sta = ieee80211_find_sta(ar->hw, mac); - - if (likely(sta)) { - struct ar9170_sta_info *sta_priv = (void *) sta->drv_priv; - skb = skb_dequeue(&sta_priv->tx_status[queue]); - rcu_read_unlock(); - if (likely(skb)) - return skb; - } else - rcu_read_unlock(); - - /* scan the waste queue for candidates */ - skb = ar9170_find_skb_in_queue(ar, mac, queue, - &ar->global_tx_status_waste); - if (!skb) { - /* so it still _must_ be in the global list. */ - skb = ar9170_find_skb_in_queue(ar, mac, queue, - &ar->global_tx_status); - } + spin_lock_irqsave(&queue->lock, flags); + skb_queue_walk(queue, skb) { + struct ar9170_tx_control *txc = (void *) skb->data; + struct ieee80211_hdr *hdr = (void *) txc->frame_data; + u32 r; + + if (mac && compare_ether_addr(ieee80211_get_DA(hdr), mac)) { #ifdef AR9170_QUEUE_DEBUG - if (unlikely((!skb) && net_ratelimit())) { - printk(KERN_ERR "%s: ESS:[%pM] does not have any " - "outstanding frames in this queue (%d).\n", - wiphy_name(ar->hw->wiphy), mac, queue); + printk(KERN_DEBUG "%s: skip frame => DA %pM != %pM\n", + wiphy_name(ar->hw->wiphy), mac, + ieee80211_get_DA(hdr)); + ar9170_print_txheader(ar, skb); +#endif /* AR9170_QUEUE_DEBUG */ + continue; + } + + r = (le32_to_cpu(txc->phy_control) & AR9170_TX_PHY_MCS_MASK) >> + AR9170_TX_PHY_MCS_SHIFT; + + if ((rate != AR9170_TX_INVALID_RATE) && (r != rate)) { +#ifdef AR9170_QUEUE_DEBUG + printk(KERN_DEBUG "%s: skip frame => rate %d != %d\n", + wiphy_name(ar->hw->wiphy), rate, r); + ar9170_print_txheader(ar, skb); +#endif /* AR9170_QUEUE_DEBUG */ + continue; + } + + __skb_unlink(skb, queue); + spin_unlock_irqrestore(&queue->lock, flags); + return skb; } + +#ifdef AR9170_QUEUE_DEBUG + printk(KERN_ERR "%s: ESS:[%pM] does not have any " + "outstanding frames in queue.\n", + wiphy_name(ar->hw->wiphy), mac); + __ar9170_dump_txqueue(ar, queue); #endif /* AR9170_QUEUE_DEBUG */ - return skb; + spin_unlock_irqrestore(&queue->lock, flags); + + return NULL; } /* - * This worker tries to keep the global tx_status queue empty. - * So we can guarantee that incoming tx_status reports for - * unregistered stations are always synced with the actual - * frame - which we think - belongs to. + * This worker tries to keeps an maintain tx_status queues. + * So we can guarantee that incoming tx_status reports are + * actually for a pending frame. */ -static void ar9170_tx_status_janitor(struct work_struct *work) +static void ar9170_tx_janitor(struct work_struct *work) { struct ar9170 *ar = container_of(work, struct ar9170, - tx_status_janitor.work); - struct sk_buff *skb; + tx_janitor.work); + struct sk_buff_head waste; + unsigned int i; + bool resched = false; if (unlikely(!IS_STARTED(ar))) return ; - /* recycle the garbage back to mac80211... one by one. */ - while ((skb = skb_dequeue(&ar->global_tx_status_waste))) { + skb_queue_head_init(&waste); + + for (i = 0; i < __AR9170_NUM_TXQ; i++) { #ifdef AR9170_QUEUE_DEBUG - printk(KERN_DEBUG "%s: dispose queued frame =>\n", - wiphy_name(ar->hw->wiphy)); - ar9170_print_txheader(ar, skb); + printk(KERN_DEBUG "%s: garbage collector scans queue:%d\n", + wiphy_name(ar->hw->wiphy), i); + ar9170_dump_txqueue(ar, &ar->tx_pending[i]); + ar9170_dump_txqueue(ar, &ar->tx_status[i]); #endif /* AR9170_QUEUE_DEBUG */ - ar9170_handle_tx_status(ar, skb, false, - AR9170_TX_STATUS_FAILED); - } - while ((skb = skb_dequeue(&ar->global_tx_status))) { -#ifdef AR9170_QUEUE_DEBUG - printk(KERN_DEBUG "%s: moving frame into waste queue =>\n", - wiphy_name(ar->hw->wiphy)); + ar9170_recycle_expired(ar, &ar->tx_status[i], &waste); + ar9170_recycle_expired(ar, &ar->tx_pending[i], &waste); + skb_queue_purge(&waste); - ar9170_print_txheader(ar, skb); -#endif /* AR9170_QUEUE_DEBUG */ - skb_queue_tail(&ar->global_tx_status_waste, skb); + if (!skb_queue_empty(&ar->tx_status[i]) || + !skb_queue_empty(&ar->tx_pending[i])) + resched = true; } - /* recall the janitor in 100ms - if there's garbage in the can. */ - if (skb_queue_len(&ar->global_tx_status_waste) > 0) - queue_delayed_work(ar->hw->workqueue, &ar->tx_status_janitor, - msecs_to_jiffies(100)); + if (resched) + queue_delayed_work(ar->hw->workqueue, + &ar->tx_janitor, + msecs_to_jiffies(AR9170_JANITOR_DELAY)); } void ar9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len) @@ -394,15 +486,21 @@ void ar9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len) */ struct sk_buff *skb; - u32 queue = (le32_to_cpu(cmd->tx_status.rate) & - AR9170_TX_PHY_QOS_MASK) >> AR9170_TX_PHY_QOS_SHIFT; + u32 phy = le32_to_cpu(cmd->tx_status.rate); + u32 q = (phy & AR9170_TX_PHY_QOS_MASK) >> + AR9170_TX_PHY_QOS_SHIFT; +#ifdef AR9170_QUEUE_DEBUG + printk(KERN_DEBUG "%s: recv tx_status for %pM, p:%08x, q:%d\n", + wiphy_name(ar->hw->wiphy), cmd->tx_status.dst, phy, q); +#endif /* AR9170_QUEUE_DEBUG */ - skb = ar9170_find_queued_skb(ar, cmd->tx_status.dst, queue); + skb = ar9170_get_queued_skb(ar, cmd->tx_status.dst, + &ar->tx_status[q], + AR9170_TX_INVALID_RATE); if (unlikely(!skb)) return ; - ar9170_handle_tx_status(ar, skb, true, - le16_to_cpu(cmd->tx_status.status)); + ar9170_tx_status(ar, skb, le16_to_cpu(cmd->tx_status.status)); break; } @@ -487,7 +585,7 @@ static void ar9170_rx_reset_rx_mpdu(struct ar9170 *ar) ar->rx_mpdu.has_plcp = false; } -static int ar9170_nag_limiter(struct ar9170 *ar) +int ar9170_nag_limiter(struct ar9170 *ar) { bool print_message; @@ -988,8 +1086,8 @@ static int ar9170_op_start(struct ieee80211_hw *hw) /* reinitialize queues statistics */ memset(&ar->tx_stats, 0, sizeof(ar->tx_stats)); - for (i = 0; i < ARRAY_SIZE(ar->tx_stats); i++) - ar->tx_stats[i].limit = 8; + for (i = 0; i < __AR9170_NUM_TXQ; i++) + ar->tx_stats[i].limit = AR9170_TXQ_DEPTH; /* reset QoS defaults */ AR9170_FILL_QUEUE(ar->edcf[0], 3, 15, 1023, 0); /* BEST EFFORT*/ @@ -1035,18 +1133,17 @@ out: static void ar9170_op_stop(struct ieee80211_hw *hw) { struct ar9170 *ar = hw->priv; + unsigned int i; if (IS_STARTED(ar)) ar->state = AR9170_IDLE; flush_workqueue(ar->hw->workqueue); - cancel_delayed_work_sync(&ar->tx_status_janitor); + cancel_delayed_work_sync(&ar->tx_janitor); cancel_work_sync(&ar->filter_config_work); cancel_work_sync(&ar->beacon_work); mutex_lock(&ar->mutex); - skb_queue_purge(&ar->global_tx_status_waste); - skb_queue_purge(&ar->global_tx_status); if (IS_ACCEPTING_CMD(ar)) { ar9170_set_leds_state(ar, 0); @@ -1056,51 +1153,32 @@ static void ar9170_op_stop(struct ieee80211_hw *hw) ar->stop(ar); } + for (i = 0; i < __AR9170_NUM_TXQ; i++) { + skb_queue_purge(&ar->tx_pending[i]); + skb_queue_purge(&ar->tx_status[i]); + } mutex_unlock(&ar->mutex); } -int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) +static int ar9170_tx_prepare(struct ar9170 *ar, struct sk_buff *skb) { - struct ar9170 *ar = hw->priv; struct ieee80211_hdr *hdr; struct ar9170_tx_control *txc; struct ieee80211_tx_info *info; - struct ieee80211_rate *rate = NULL; struct ieee80211_tx_rate *txrate; + struct ar9170_tx_info *arinfo; unsigned int queue = skb_get_queue_mapping(skb); - unsigned long flags = 0; - struct ar9170_sta_info *sta_info = NULL; - u32 power, chains; u16 keytype = 0; u16 len, icv = 0; - int err; - bool tx_status; - if (unlikely(!IS_STARTED(ar))) - goto err_free; + BUILD_BUG_ON(sizeof(*arinfo) > sizeof(info->rate_driver_data)); hdr = (void *)skb->data; info = IEEE80211_SKB_CB(skb); len = skb->len; - spin_lock_irqsave(&ar->tx_stats_lock, flags); - if (ar->tx_stats[queue].limit < ar->tx_stats[queue].len) { - spin_unlock_irqrestore(&ar->tx_stats_lock, flags); - return NETDEV_TX_OK; - } - - ar->tx_stats[queue].len++; - ar->tx_stats[queue].count++; - if (ar->tx_stats[queue].limit == ar->tx_stats[queue].len) - ieee80211_stop_queue(hw, queue); - - spin_unlock_irqrestore(&ar->tx_stats_lock, flags); - txc = (void *)skb_push(skb, sizeof(*txc)); - tx_status = (((info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) != 0) || - ((info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS) != 0)); - if (info->control.hw_key) { icv = info->control.hw_key->icv_len; @@ -1116,7 +1194,7 @@ int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) break; default: WARN_ON(1); - goto err_dequeue; + goto err_out; } } @@ -1133,16 +1211,65 @@ int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) if (info->flags & IEEE80211_TX_CTL_NO_ACK) txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_NO_ACK); - if (info->flags & IEEE80211_TX_CTL_AMPDU) - txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_AGGR); - txrate = &info->control.rates[0]; - if (txrate->flags & IEEE80211_TX_RC_USE_CTS_PROTECT) txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_PROT_CTS); else if (txrate->flags & IEEE80211_TX_RC_USE_RTS_CTS) txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_PROT_RTS); + arinfo = (void *)info->rate_driver_data; + arinfo->timeout = jiffies + msecs_to_jiffies(AR9170_QUEUE_TIMEOUT); + + if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && + (is_valid_ether_addr(ieee80211_get_DA(hdr)))) { + if (info->flags & IEEE80211_TX_CTL_AMPDU) { + if (unlikely(!info->control.sta)) + goto err_out; + + txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_AGGR); + arinfo->flags = AR9170_TX_FLAG_BLOCK_ACK; + goto out; + } + + txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_RATE_PROBE); + /* + * WARNING: + * Putting the QoS queue bits into an unexplored territory is + * certainly not elegant. + * + * In my defense: This idea provides a reasonable way to + * smuggle valuable information to the tx_status callback. + * Also, the idea behind this bit-abuse came straight from + * the original driver code. + */ + + txc->phy_control |= + cpu_to_le32(queue << AR9170_TX_PHY_QOS_SHIFT); + arinfo->flags = AR9170_TX_FLAG_WAIT_FOR_ACK; + } else { + arinfo->flags = AR9170_TX_FLAG_NO_ACK; + } + +out: + return 0; + +err_out: + skb_pull(skb, sizeof(*txc)); + return -EINVAL; +} + +static void ar9170_tx_prepare_phy(struct ar9170 *ar, struct sk_buff *skb) +{ + struct ar9170_tx_control *txc; + struct ieee80211_tx_info *info; + struct ieee80211_rate *rate = NULL; + struct ieee80211_tx_rate *txrate; + u32 power, chains; + + txc = (void *) skb->data; + info = IEEE80211_SKB_CB(skb); + txrate = &info->control.rates[0]; + if (txrate->flags & IEEE80211_TX_RC_GREEN_FIELD) txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_GREENFIELD); @@ -1162,9 +1289,12 @@ int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) u32 r = txrate->idx; u8 *txpower; + /* heavy clip control */ + txc->phy_control |= cpu_to_le32((r & 0x7) << 7); + r <<= AR9170_TX_PHY_MCS_SHIFT; - if (WARN_ON(r & ~AR9170_TX_PHY_MCS_MASK)) - goto err_dequeue; + BUG_ON(r & ~AR9170_TX_PHY_MCS_MASK); + txc->phy_control |= cpu_to_le32(r & AR9170_TX_PHY_MCS_MASK); txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_MOD_HT); @@ -1226,53 +1356,154 @@ int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) chains = AR9170_TX_PHY_TXCHAIN_1; } txc->phy_control |= cpu_to_le32(chains << AR9170_TX_PHY_TXCHAIN_SHIFT); +} - if (tx_status) { - txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_RATE_PROBE); - /* - * WARNING: - * Putting the QoS queue bits into an unexplored territory is - * certainly not elegant. - * - * In my defense: This idea provides a reasonable way to - * smuggle valuable information to the tx_status callback. - * Also, the idea behind this bit-abuse came straight from - * the original driver code. - */ +static void ar9170_tx(struct ar9170 *ar) +{ + struct sk_buff *skb; + unsigned long flags; + struct ieee80211_tx_info *info; + struct ar9170_tx_info *arinfo; + unsigned int i, frames, frames_failed, remaining_space; + int err; + bool schedule_garbagecollector = false; - txc->phy_control |= - cpu_to_le32(queue << AR9170_TX_PHY_QOS_SHIFT); + BUILD_BUG_ON(sizeof(*arinfo) > sizeof(info->rate_driver_data)); - if (info->control.sta) { - sta_info = (void *) info->control.sta->drv_priv; - skb_queue_tail(&sta_info->tx_status[queue], skb); - } else { - skb_queue_tail(&ar->global_tx_status, skb); + if (unlikely(!IS_STARTED(ar))) + return ; + + remaining_space = AR9170_TX_MAX_PENDING; + + for (i = 0; i < __AR9170_NUM_TXQ; i++) { + spin_lock_irqsave(&ar->tx_stats_lock, flags); + if (ar->tx_stats[i].len >= ar->tx_stats[i].limit) { +#ifdef AR9170_QUEUE_DEBUG + printk(KERN_DEBUG "%s: queue %d full\n", + wiphy_name(ar->hw->wiphy), i); + + __ar9170_dump_txstats(ar); + printk(KERN_DEBUG "stuck frames: ===> \n"); + ar9170_dump_txqueue(ar, &ar->tx_pending[i]); + ar9170_dump_txqueue(ar, &ar->tx_status[i]); +#endif /* AR9170_QUEUE_DEBUG */ + ieee80211_stop_queue(ar->hw, i); + spin_unlock_irqrestore(&ar->tx_stats_lock, flags); + continue; + } - queue_delayed_work(ar->hw->workqueue, - &ar->tx_status_janitor, - msecs_to_jiffies(100)); + frames = min(ar->tx_stats[i].limit - ar->tx_stats[i].len, + skb_queue_len(&ar->tx_pending[i])); + + if (remaining_space < frames) { +#ifdef AR9170_QUEUE_DEBUG + printk(KERN_DEBUG "%s: tx quota reached queue:%d, " + "remaining slots:%d, needed:%d\n", + wiphy_name(ar->hw->wiphy), i, remaining_space, + frames); + + ar9170_dump_txstats(ar); +#endif /* AR9170_QUEUE_DEBUG */ + frames = remaining_space; + } + + ar->tx_stats[i].len += frames; + ar->tx_stats[i].count += frames; + spin_unlock_irqrestore(&ar->tx_stats_lock, flags); + + if (!frames) + continue; + + frames_failed = 0; + while (frames) { + skb = skb_dequeue(&ar->tx_pending[i]); + if (unlikely(!skb)) { + frames_failed += frames; + frames = 0; + break; + } + + info = IEEE80211_SKB_CB(skb); + arinfo = (void *) info->rate_driver_data; + + /* TODO: cancel stuck frames */ + arinfo->timeout = jiffies + + msecs_to_jiffies(AR9170_TX_TIMEOUT); + +#ifdef AR9170_QUEUE_DEBUG + printk(KERN_DEBUG "%s: send frame q:%d =>\n", + wiphy_name(ar->hw->wiphy), i); + ar9170_print_txheader(ar, skb); +#endif /* AR9170_QUEUE_DEBUG */ + + err = ar->tx(ar, skb); + if (unlikely(err)) { + frames_failed++; + dev_kfree_skb_any(skb); + } else { + remaining_space--; + schedule_garbagecollector = true; + } + + frames--; + } + +#ifdef AR9170_QUEUE_DEBUG + printk(KERN_DEBUG "%s: ar9170_tx report for queue %d\n", + wiphy_name(ar->hw->wiphy), i); + + printk(KERN_DEBUG "%s: unprocessed pending frames left:\n", + wiphy_name(ar->hw->wiphy)); + ar9170_dump_txqueue(ar, &ar->tx_pending[i]); +#endif /* AR9170_QUEUE_DEBUG */ + + if (unlikely(frames_failed)) { +#ifdef AR9170_QUEUE_DEBUG + printk(KERN_DEBUG "%s: frames failed =>\n", + wiphy_name(ar->hw->wiphy), frames_failed); +#endif /* AR9170_QUEUE_DEBUG */ + + spin_lock_irqsave(&ar->tx_stats_lock, flags); + ar->tx_stats[i].len -= frames_failed; + ar->tx_stats[i].count -= frames_failed; + ieee80211_wake_queue(ar->hw, i); + spin_unlock_irqrestore(&ar->tx_stats_lock, flags); } } - err = ar->tx(ar, skb, tx_status, 0); - if (unlikely(tx_status && err)) { - if (info->control.sta) - skb_unlink(skb, &sta_info->tx_status[queue]); - else - skb_unlink(skb, &ar->global_tx_status); + if (schedule_garbagecollector) + queue_delayed_work(ar->hw->workqueue, + &ar->tx_janitor, + msecs_to_jiffies(AR9170_JANITOR_DELAY)); +} + +int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) +{ + struct ar9170 *ar = hw->priv; + struct ieee80211_tx_info *info; + + if (unlikely(!IS_STARTED(ar))) + goto err_free; + + if (unlikely(ar9170_tx_prepare(ar, skb))) + goto err_free; + + info = IEEE80211_SKB_CB(skb); + if (info->flags & IEEE80211_TX_CTL_AMPDU) { + /* drop frame, we do not allow TX A-MPDU aggregation yet. */ + goto err_free; + } else { + unsigned int queue = skb_get_queue_mapping(skb); + + ar9170_tx_prepare_phy(ar, skb); + skb_queue_tail(&ar->tx_pending[queue], skb); } + ar9170_tx(ar); return NETDEV_TX_OK; -err_dequeue: - spin_lock_irqsave(&ar->tx_stats_lock, flags); - ar->tx_stats[queue].len--; - ar->tx_stats[queue].count--; - spin_unlock_irqrestore(&ar->tx_stats_lock, flags); - err_free: - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); return NETDEV_TX_OK; } @@ -1698,43 +1929,6 @@ static void ar9170_sta_notify(struct ieee80211_hw *hw, enum sta_notify_cmd cmd, struct ieee80211_sta *sta) { - struct ar9170 *ar = hw->priv; - struct ar9170_sta_info *info = (void *) sta->drv_priv; - struct sk_buff *skb; - unsigned int i; - - switch (cmd) { - case STA_NOTIFY_ADD: - for (i = 0; i < ar->hw->queues; i++) - skb_queue_head_init(&info->tx_status[i]); - break; - - case STA_NOTIFY_REMOVE: - - /* - * transfer all outstanding frames that need a tx_status - * reports to the global tx_status queue - */ - - for (i = 0; i < ar->hw->queues; i++) { - while ((skb = skb_dequeue(&info->tx_status[i]))) { -#ifdef AR9170_QUEUE_DEBUG - printk(KERN_DEBUG "%s: queueing frame in " - "global tx_status queue =>\n", - wiphy_name(ar->hw->wiphy)); - - ar9170_print_txheader(ar, skb); -#endif /* AR9170_QUEUE_DEBUG */ - skb_queue_tail(&ar->global_tx_status, skb); - } - } - queue_delayed_work(ar->hw->workqueue, &ar->tx_status_janitor, - msecs_to_jiffies(100)); - break; - - default: - break; - } } static int ar9170_get_stats(struct ieee80211_hw *hw, @@ -1773,7 +1967,7 @@ static int ar9170_conf_tx(struct ieee80211_hw *hw, u16 queue, int ret; mutex_lock(&ar->mutex); - if ((param) && !(queue > ar->hw->queues)) { + if ((param) && !(queue > __AR9170_NUM_TXQ)) { memcpy(&ar->edcf[ar9170_qos_hwmap[queue]], param, sizeof(*param)); @@ -1849,12 +2043,14 @@ void *ar9170_alloc(size_t priv_size) mutex_init(&ar->mutex); spin_lock_init(&ar->cmdlock); spin_lock_init(&ar->tx_stats_lock); - skb_queue_head_init(&ar->global_tx_status); - skb_queue_head_init(&ar->global_tx_status_waste); + for (i = 0; i < __AR9170_NUM_TXQ; i++) { + skb_queue_head_init(&ar->tx_status[i]); + skb_queue_head_init(&ar->tx_pending[i]); + } ar9170_rx_reset_rx_mpdu(ar); INIT_WORK(&ar->filter_config_work, ar9170_set_filters); INIT_WORK(&ar->beacon_work, ar9170_new_beacon); - INIT_DELAYED_WORK(&ar->tx_status_janitor, ar9170_tx_status_janitor); + INIT_DELAYED_WORK(&ar->tx_janitor, ar9170_tx_janitor); /* all hw supports 2.4 GHz, so set channel to 1 by default */ ar->channel = &ar9170_2ghz_chantable[0]; diff --git a/drivers/net/wireless/ath/ar9170/usb.c b/drivers/net/wireless/ath/ar9170/usb.c index f752698669d..754b1f8d8da 100644 --- a/drivers/net/wireless/ath/ar9170/usb.c +++ b/drivers/net/wireless/ath/ar9170/usb.c @@ -96,7 +96,49 @@ static struct usb_device_id ar9170_usb_ids[] = { }; MODULE_DEVICE_TABLE(usb, ar9170_usb_ids); -static void ar9170_usb_tx_urb_complete_free(struct urb *urb) +static void ar9170_usb_submit_urb(struct ar9170_usb *aru) +{ + struct urb *urb; + unsigned long flags; + int err; + + if (unlikely(!IS_STARTED(&aru->common))) + return ; + + spin_lock_irqsave(&aru->tx_urb_lock, flags); + if (aru->tx_submitted_urbs >= AR9170_NUM_TX_URBS) { + spin_unlock_irqrestore(&aru->tx_urb_lock, flags); + return ; + } + aru->tx_submitted_urbs++; + + urb = usb_get_from_anchor(&aru->tx_pending); + if (!urb) { + aru->tx_submitted_urbs--; + spin_unlock_irqrestore(&aru->tx_urb_lock, flags); + + return ; + } + spin_unlock_irqrestore(&aru->tx_urb_lock, flags); + + aru->tx_pending_urbs--; + usb_anchor_urb(urb, &aru->tx_submitted); + + err = usb_submit_urb(urb, GFP_ATOMIC); + if (unlikely(err)) { + if (ar9170_nag_limiter(&aru->common)) + dev_err(&aru->udev->dev, "submit_urb failed (%d).\n", + err); + + usb_unanchor_urb(urb); + aru->tx_submitted_urbs--; + ar9170_tx_callback(&aru->common, urb->context); + } + + usb_free_urb(urb); +} + +static void ar9170_usb_tx_urb_complete_frame(struct urb *urb) { struct sk_buff *skb = urb->context; struct ar9170_usb *aru = (struct ar9170_usb *) @@ -107,8 +149,11 @@ static void ar9170_usb_tx_urb_complete_free(struct urb *urb) return ; } - ar9170_handle_tx_status(&aru->common, skb, false, - AR9170_TX_STATUS_COMPLETE); + aru->tx_submitted_urbs--; + + ar9170_tx_callback(&aru->common, skb); + + ar9170_usb_submit_urb(aru); } static void ar9170_usb_tx_urb_complete(struct urb *urb) @@ -290,21 +335,47 @@ err_out: return err; } -static void ar9170_usb_cancel_urbs(struct ar9170_usb *aru) +static int ar9170_usb_flush(struct ar9170 *ar) { - int ret; + struct ar9170_usb *aru = (void *) ar; + struct urb *urb; + int ret, err = 0; - aru->common.state = AR9170_UNKNOWN_STATE; + if (IS_STARTED(ar)) + aru->common.state = AR9170_IDLE; - usb_unlink_anchored_urbs(&aru->tx_submitted); + usb_wait_anchor_empty_timeout(&aru->tx_pending, + msecs_to_jiffies(800)); + while ((urb = usb_get_from_anchor(&aru->tx_pending))) { + ar9170_tx_callback(&aru->common, (void *) urb->context); + usb_free_urb(urb); + } - /* give the LED OFF command and the deauth frame a chance to air. */ + /* lets wait a while until the tx - queues are dried out */ ret = usb_wait_anchor_empty_timeout(&aru->tx_submitted, msecs_to_jiffies(100)); if (ret == 0) - dev_err(&aru->udev->dev, "kill pending tx urbs.\n"); - usb_poison_anchored_urbs(&aru->tx_submitted); + err = -ETIMEDOUT; + + usb_kill_anchored_urbs(&aru->tx_submitted); + + if (IS_ACCEPTING_CMD(ar)) + aru->common.state = AR9170_STARTED; + + return err; +} + +static void ar9170_usb_cancel_urbs(struct ar9170_usb *aru) +{ + int err; + aru->common.state = AR9170_UNKNOWN_STATE; + + err = ar9170_usb_flush(&aru->common); + if (err) + dev_err(&aru->udev->dev, "stuck tx urbs!\n"); + + usb_poison_anchored_urbs(&aru->tx_submitted); usb_poison_anchored_urbs(&aru->rx_submitted); } @@ -388,12 +459,10 @@ err_free: return err; } -static int ar9170_usb_tx(struct ar9170 *ar, struct sk_buff *skb, - bool txstatus_needed, unsigned int extra_len) +static int ar9170_usb_tx(struct ar9170 *ar, struct sk_buff *skb) { struct ar9170_usb *aru = (struct ar9170_usb *) ar; struct urb *urb; - int err; if (unlikely(!IS_STARTED(ar))) { /* Seriously, what were you drink... err... thinking!? */ @@ -406,18 +475,17 @@ static int ar9170_usb_tx(struct ar9170 *ar, struct sk_buff *skb, usb_fill_bulk_urb(urb, aru->udev, usb_sndbulkpipe(aru->udev, AR9170_EP_TX), - skb->data, skb->len + extra_len, (txstatus_needed ? - ar9170_usb_tx_urb_complete : - ar9170_usb_tx_urb_complete_free), skb); + skb->data, skb->len, + ar9170_usb_tx_urb_complete_frame, skb); urb->transfer_flags |= URB_ZERO_PACKET; - usb_anchor_urb(urb, &aru->tx_submitted); - err = usb_submit_urb(urb, GFP_ATOMIC); - if (unlikely(err)) - usb_unanchor_urb(urb); + usb_anchor_urb(urb, &aru->tx_pending); + aru->tx_pending_urbs++; usb_free_urb(urb); - return err; + + ar9170_usb_submit_urb(aru); + return 0; } static void ar9170_usb_callback_cmd(struct ar9170 *ar, u32 len , void *buffer) @@ -617,10 +685,8 @@ static void ar9170_usb_stop(struct ar9170 *ar) if (IS_ACCEPTING_CMD(ar)) aru->common.state = AR9170_STOPPED; - /* lets wait a while until the tx - queues are dried out */ - ret = usb_wait_anchor_empty_timeout(&aru->tx_submitted, - msecs_to_jiffies(1000)); - if (ret == 0) + ret = ar9170_usb_flush(ar); + if (ret) dev_err(&aru->udev->dev, "kill pending tx urbs.\n"); usb_poison_anchored_urbs(&aru->tx_submitted); @@ -716,10 +782,16 @@ static int ar9170_usb_probe(struct usb_interface *intf, SET_IEEE80211_DEV(ar->hw, &udev->dev); init_usb_anchor(&aru->rx_submitted); + init_usb_anchor(&aru->tx_pending); init_usb_anchor(&aru->tx_submitted); init_completion(&aru->cmd_wait); + spin_lock_init(&aru->tx_urb_lock); + + aru->tx_pending_urbs = 0; + aru->tx_submitted_urbs = 0; aru->common.stop = ar9170_usb_stop; + aru->common.flush = ar9170_usb_flush; aru->common.open = ar9170_usb_open; aru->common.tx = ar9170_usb_tx; aru->common.exec_cmd = ar9170_usb_exec_cmd; diff --git a/drivers/net/wireless/ath/ar9170/usb.h b/drivers/net/wireless/ath/ar9170/usb.h index 69f4bceb0af..d098f4d5d2f 100644 --- a/drivers/net/wireless/ath/ar9170/usb.h +++ b/drivers/net/wireless/ath/ar9170/usb.h @@ -51,6 +51,7 @@ #include "ar9170.h" #define AR9170_NUM_RX_URBS 16 +#define AR9170_NUM_TX_URBS 8 struct firmware; @@ -60,11 +61,15 @@ struct ar9170_usb { struct usb_interface *intf; struct usb_anchor rx_submitted; + struct usb_anchor tx_pending; struct usb_anchor tx_submitted; bool req_one_stage_fw; - spinlock_t cmdlock; + spinlock_t tx_urb_lock; + unsigned int tx_submitted_urbs; + unsigned int tx_pending_urbs; + struct completion cmd_wait; int readlen; u8 *readbuf; -- cgit v1.2.3 From 207ee1621722876bb79828689582bf77fd1be200 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 7 Jun 2009 12:26:52 +0200 Subject: rfkill: print events when input handler is disabled/enabled It is useful for debugging when we know if something disabled the in-kernel rfkill input handler. Signed-off-by: Johannes Berg Acked-by: Marcel Holtmann Signed-off-by: John W. Linville --- net/rfkill/core.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/net/rfkill/core.c b/net/rfkill/core.c index 11b7314723d..e161ebc40a3 100644 --- a/net/rfkill/core.c +++ b/net/rfkill/core.c @@ -1134,7 +1134,8 @@ static int rfkill_fop_release(struct inode *inode, struct file *file) #ifdef CONFIG_RFKILL_INPUT if (data->input_handler) - atomic_dec(&rfkill_input_disabled); + if (atomic_dec_return(&rfkill_input_disabled) == 0) + printk(KERN_DEBUG "rfkill: input handler enabled\n"); #endif kfree(data); @@ -1157,7 +1158,8 @@ static long rfkill_fop_ioctl(struct file *file, unsigned int cmd, mutex_lock(&data->mtx); if (!data->input_handler) { - atomic_inc(&rfkill_input_disabled); + if (atomic_inc_return(&rfkill_input_disabled) == 1) + printk(KERN_DEBUG "rfkill: input handler disabled\n"); data->input_handler = true; } -- cgit v1.2.3 From e6a3b61681dcb963e6465ffbc4330b44824f35e3 Mon Sep 17 00:00:00 2001 From: Tobias Doerffel Date: Tue, 9 Jun 2009 17:33:27 +0200 Subject: ath5k: added cfg80211 based rfkill support This patch introduces initial rfkill support for the ath5k driver based on rfkill support in the cfg80211 framework. All rfkill related code is separated into newly created rfkill.c. Changes to existing code are minimal: * added a new data structure ath5k_rfkill to the ath5k_softc structure * inserted calls to HW rfkill init/deinit routines * ath5k_intr() has been extended to handle AR5K_INT_GPIO interrupts Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/Kconfig | 8 +++ drivers/net/wireless/ath/ath5k/Makefile | 1 + drivers/net/wireless/ath/ath5k/ath5k.h | 9 +++ drivers/net/wireless/ath/ath5k/base.c | 10 +++ drivers/net/wireless/ath/ath5k/base.h | 14 ++++ drivers/net/wireless/ath/ath5k/reset.c | 17 ----- drivers/net/wireless/ath/ath5k/rfkill.c | 121 ++++++++++++++++++++++++++++++++ 7 files changed, 163 insertions(+), 17 deletions(-) create mode 100644 drivers/net/wireless/ath/ath5k/rfkill.c diff --git a/drivers/net/wireless/ath/ath5k/Kconfig b/drivers/net/wireless/ath/ath5k/Kconfig index 509b6f94f73..4863f4bbf76 100644 --- a/drivers/net/wireless/ath/ath5k/Kconfig +++ b/drivers/net/wireless/ath/ath5k/Kconfig @@ -39,3 +39,11 @@ config ATH5K_DEBUG modprobe ath5k debug=0x00000400 +config ATH5K_RFKILL + bool "Atheros 5xxx rfkill support" + depends on ATH5K + default y + ---help--- + Include support for enabling/disabling WiFi via rfkill switch + with Atheros 5xxx cards + diff --git a/drivers/net/wireless/ath/ath5k/Makefile b/drivers/net/wireless/ath/ath5k/Makefile index 84a74c5248e..f1e281c5a21 100644 --- a/drivers/net/wireless/ath/ath5k/Makefile +++ b/drivers/net/wireless/ath/ath5k/Makefile @@ -12,4 +12,5 @@ ath5k-y += attach.o ath5k-y += base.o ath5k-y += led.o ath5k-$(CONFIG_ATH5K_DEBUG) += debug.o +ath5k-$(CONFIG_ATH5K_RFKILL) += rfkill.o obj-$(CONFIG_ATH5K) += ath5k.o diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index 81371821033..4c84e308763 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -1256,6 +1256,15 @@ extern u32 ath5k_hw_get_gpio(struct ath5k_hw *ah, u32 gpio); extern int ath5k_hw_set_gpio(struct ath5k_hw *ah, u32 gpio, u32 val); extern void ath5k_hw_set_gpio_intr(struct ath5k_hw *ah, unsigned int gpio, u32 interrupt_level); +/* rfkill Functions */ +#ifdef CONFIG_ATH5K_RFKILL +extern void ath5k_rfkill_hw_start(struct ath5k_hw *ah); +extern void ath5k_rfkill_hw_stop(struct ath5k_hw *ah); +#else +static inline void ath5k_rfkill_hw_start(struct ath5k_hw *ah) {} +static inline void ath5k_rfkill_hw_stop(struct ath5k_hw *ah) {} +#endif + /* Misc functions */ int ath5k_hw_set_capabilities(struct ath5k_hw *ah); extern int ath5k_hw_get_capability(struct ath5k_hw *ah, enum ath5k_capability_type cap_type, u32 capability, u32 *result); diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 85a00db4867..f55675c23f2 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -2360,6 +2360,8 @@ ath5k_init(struct ath5k_softc *sc) if (ret) goto done; + ath5k_rfkill_hw_start(ah); + /* * Reset the key cache since some parts do not reset the * contents on initial power up or resume from suspend. @@ -2468,6 +2470,8 @@ ath5k_stop_hw(struct ath5k_softc *sc) tasklet_kill(&sc->restq); tasklet_kill(&sc->beacontq); + ath5k_rfkill_hw_stop(sc->ah); + return ret; } @@ -2526,6 +2530,12 @@ ath5k_intr(int irq, void *dev_id) */ ath5k_hw_update_mib_counters(ah, &sc->ll_stats); } +#ifdef CONFIG_ATH5K_RFKILL + if (status & AR5K_INT_GPIO) + { + tasklet_schedule(&sc->rf_kill.toggleq); + } +#endif } } while (ath5k_hw_is_intr_pending(ah) && --counter > 0); diff --git a/drivers/net/wireless/ath/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h index 852b2c189fd..7a0ecdd9c25 100644 --- a/drivers/net/wireless/ath/ath5k/base.h +++ b/drivers/net/wireless/ath/ath5k/base.h @@ -46,6 +46,7 @@ #include #include #include +#include #include "ath5k.h" #include "debug.h" @@ -91,6 +92,15 @@ struct ath5k_led struct led_classdev led_dev; /* led classdev */ }; +/* Rfkill */ +struct ath5k_rfkill { + /* GPIO PIN for rfkill */ + u16 gpio; + /* polarity of rfkill GPIO PIN */ + bool polarity; + /* RFKILL toggle tasklet */ + struct tasklet_struct toggleq; +}; #if CHAN_DEBUG #define ATH_CHAN_MAX (26+26+26+200+200) @@ -167,6 +177,10 @@ struct ath5k_softc { struct tasklet_struct txtq; /* tx intr tasklet */ struct ath5k_led tx_led; /* tx led */ +#ifdef CONFIG_ATH5K_RFKILL + struct ath5k_rfkill rf_kill; +#endif + spinlock_t block; /* protects beacon */ struct tasklet_struct beacontq; /* beacon intr tasklet */ struct ath5k_buf *bbuf; /* beacon buffer */ diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c index 66067733ddd..bd0a97a38d3 100644 --- a/drivers/net/wireless/ath/ath5k/reset.c +++ b/drivers/net/wireless/ath/ath5k/reset.c @@ -1304,23 +1304,6 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, if (ah->ah_version != AR5K_AR5210) ath5k_hw_set_imr(ah, ah->ah_imr); - /* - * Setup RFKill interrupt if rfkill flag is set on eeprom. - * TODO: Use gpio pin and polarity infos from eeprom - * TODO: Handle this in ath5k_intr because it'll result - * a nasty interrupt storm. - */ -#if 0 - if (AR5K_EEPROM_HDR_RFKILL(ah->ah_capabilities.cap_eeprom.ee_header)) { - ath5k_hw_set_gpio_input(ah, 0); - ah->ah_gpio[0] = ath5k_hw_get_gpio(ah, 0); - if (ah->ah_gpio[0] == 0) - ath5k_hw_set_gpio_intr(ah, 0, 1); - else - ath5k_hw_set_gpio_intr(ah, 0, 0); - } -#endif - /* Enable 32KHz clock function for AR5212+ chips * Set clocks to 32KHz operation and use an * external 32KHz crystal when sleeping if one diff --git a/drivers/net/wireless/ath/ath5k/rfkill.c b/drivers/net/wireless/ath/ath5k/rfkill.c new file mode 100644 index 00000000000..492ada92db5 --- /dev/null +++ b/drivers/net/wireless/ath/ath5k/rfkill.c @@ -0,0 +1,121 @@ +/* + * RFKILL support for ath5k + * + * Copyright (c) 2009 Tobias Doerffel + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + */ + +#include "base.h" + + +static inline void ath5k_rfkill_disable(struct ath5k_softc *sc) +{ + ATH5K_DBG(sc, ATH5K_DEBUG_ANY, "rfkill disable (gpio:%d polarity:%d)\n", + sc->rf_kill.gpio, sc->rf_kill.polarity); + ath5k_hw_set_gpio_output(sc->ah, sc->rf_kill.gpio); + ath5k_hw_set_gpio(sc->ah, sc->rf_kill.gpio, !sc->rf_kill.polarity); +} + + +static inline void ath5k_rfkill_enable(struct ath5k_softc *sc) +{ + ATH5K_DBG(sc, ATH5K_DEBUG_ANY, "rfkill enable (gpio:%d polarity:%d)\n", + sc->rf_kill.gpio, sc->rf_kill.polarity); + ath5k_hw_set_gpio_output(sc->ah, sc->rf_kill.gpio); + ath5k_hw_set_gpio(sc->ah, sc->rf_kill.gpio, sc->rf_kill.polarity); +} + +static inline void ath5k_rfkill_set_intr(struct ath5k_softc *sc, bool enable) +{ + struct ath5k_hw *ah = sc->ah; + ath5k_hw_set_gpio_input(ah, sc->rf_kill.gpio); + ah->ah_gpio[0] = ath5k_hw_get_gpio(ah, sc->rf_kill.gpio); + ath5k_hw_set_gpio_intr(ah, sc->rf_kill.gpio, enable ? + !!ah->ah_gpio[0] : !ah->ah_gpio[0]); +} + +static bool +ath5k_is_rfkill_set(struct ath5k_softc *sc) +{ + /* configuring GPIO for input for some reason disables rfkill */ + /*ath5k_hw_set_gpio_input(sc->ah, sc->rf_kill.gpio);*/ + return ath5k_hw_get_gpio(sc->ah, sc->rf_kill.gpio) == + sc->rf_kill.polarity; +} + +static void +ath5k_tasklet_rfkill_toggle(unsigned long data) +{ + struct ath5k_softc *sc = (void *)data; + bool blocked; + + blocked = ath5k_is_rfkill_set(sc); + wiphy_rfkill_set_hw_state(sc->hw->wiphy, blocked); +} + + +void +ath5k_rfkill_hw_start(struct ath5k_hw *ah) +{ + struct ath5k_softc *sc = ah->ah_sc; + + /* read rfkill GPIO configuration from EEPROM header */ + sc->rf_kill.gpio = ah->ah_capabilities.cap_eeprom.ee_rfkill_pin; + sc->rf_kill.polarity = ah->ah_capabilities.cap_eeprom.ee_rfkill_pol; + + tasklet_init(&sc->rf_kill.toggleq, ath5k_tasklet_rfkill_toggle, + (unsigned long)sc); + + ath5k_rfkill_disable(sc); + + /* enable interrupt for rfkill switch */ + if (AR5K_EEPROM_HDR_RFKILL(ah->ah_capabilities.cap_eeprom.ee_header)) { + ath5k_rfkill_set_intr(sc, true); + } +} + + +void +ath5k_rfkill_hw_stop(struct ath5k_hw *ah) +{ + struct ath5k_softc *sc = ah->ah_sc; + + /* disable interrupt for rfkill switch */ + if (AR5K_EEPROM_HDR_RFKILL(ah->ah_capabilities.cap_eeprom.ee_header)) { + ath5k_rfkill_set_intr(sc, false); + } + + tasklet_kill(&sc->rf_kill.toggleq); + + /* enable RFKILL when stopping HW so Wifi LED is turned off */ + ath5k_rfkill_enable(sc); +} + -- cgit v1.2.3 From f41f3f373dd72344c65d801d6381fe83ef3a2c54 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 7 Jun 2009 12:30:34 -0500 Subject: b43/legacy: port to cfg80211 rfkill This ports the b43/legacy rfkill code to the new API offered by cfg80211 and thus removes a lot of useless stuff. Signed-off-by: Johannes Berg Signed-off-by: Larry Finger Cc: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/b43/Kconfig | 7 -- drivers/net/wireless/b43/Makefile | 2 +- drivers/net/wireless/b43/b43.h | 3 - drivers/net/wireless/b43/leds.c | 7 +- drivers/net/wireless/b43/main.c | 27 ++----- drivers/net/wireless/b43/phy_common.h | 2 +- drivers/net/wireless/b43/rfkill.c | 113 +++++----------------------- drivers/net/wireless/b43/rfkill.h | 44 +---------- drivers/net/wireless/b43legacy/Kconfig | 8 -- drivers/net/wireless/b43legacy/Makefile | 2 +- drivers/net/wireless/b43legacy/b43legacy.h | 3 - drivers/net/wireless/b43legacy/leds.c | 7 +- drivers/net/wireless/b43legacy/main.c | 17 +---- drivers/net/wireless/b43legacy/rfkill.c | 115 +++++------------------------ drivers/net/wireless/b43legacy/rfkill.h | 50 +------------ 15 files changed, 66 insertions(+), 341 deletions(-) diff --git a/drivers/net/wireless/b43/Kconfig b/drivers/net/wireless/b43/Kconfig index 07a99e3faf9..67f564e3722 100644 --- a/drivers/net/wireless/b43/Kconfig +++ b/drivers/net/wireless/b43/Kconfig @@ -98,13 +98,6 @@ config B43_LEDS depends on B43 && MAC80211_LEDS && (LEDS_CLASS = y || LEDS_CLASS = B43) default y -# This config option automatically enables b43 RFKILL support, -# if it's possible. -config B43_RFKILL - bool - depends on B43 && (RFKILL = y || RFKILL = B43) - default y - # This config option automatically enables b43 HW-RNG support, # if the HW-RNG core is enabled. config B43_HWRNG diff --git a/drivers/net/wireless/b43/Makefile b/drivers/net/wireless/b43/Makefile index 281ef831035..da379f4b0c3 100644 --- a/drivers/net/wireless/b43/Makefile +++ b/drivers/net/wireless/b43/Makefile @@ -13,7 +13,7 @@ b43-y += lo.o b43-y += wa.o b43-y += dma.o b43-$(CONFIG_B43_PIO) += pio.o -b43-$(CONFIG_B43_RFKILL) += rfkill.o +b43-y += rfkill.o b43-$(CONFIG_B43_LEDS) += leds.o b43-$(CONFIG_B43_PCMCIA) += pcmcia.o b43-$(CONFIG_B43_DEBUG) += debugfs.o diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index 4e8ad841c3c..75aede02f93 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -631,9 +631,6 @@ struct b43_wl { char rng_name[30 + 1]; #endif /* CONFIG_B43_HWRNG */ - /* The RF-kill button */ - struct b43_rfkill rfkill; - /* List of all wireless devices on this chip */ struct list_head devlist; u8 nr_devs; diff --git a/drivers/net/wireless/b43/leds.c b/drivers/net/wireless/b43/leds.c index 9a498d3fc65..c8b317094c3 100644 --- a/drivers/net/wireless/b43/leds.c +++ b/drivers/net/wireless/b43/leds.c @@ -28,6 +28,7 @@ #include "b43.h" #include "leds.h" +#include "rfkill.h" static void b43_led_turn_on(struct b43_wldev *dev, u8 led_index, @@ -164,10 +165,10 @@ static void b43_map_led(struct b43_wldev *dev, snprintf(name, sizeof(name), "b43-%s::radio", wiphy_name(hw->wiphy)); b43_register_led(dev, &dev->led_radio, name, - b43_rfkill_led_name(dev), + ieee80211_get_radio_led_name(hw), led_index, activelow); - /* Sync the RF-kill LED state with the switch state. */ - if (dev->radio_hw_enable) + /* Sync the RF-kill LED state with radio and switch states. */ + if (dev->phy.radio_on && b43_is_hw_radio_enabled(dev)) b43_led_turn_on(dev, led_index, activelow); break; case B43_LED_WEIRD: diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 1d3e40095ad..5d9f1981f2c 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -4298,7 +4298,6 @@ static int b43_op_start(struct ieee80211_hw *hw) struct b43_wldev *dev = wl->current_dev; int did_init = 0; int err = 0; - bool do_rfkill_exit = 0; /* Kill all old instance specific information to make sure * the card won't use it in the short timeframe between start @@ -4312,18 +4311,12 @@ static int b43_op_start(struct ieee80211_hw *hw) wl->beacon1_uploaded = 0; wl->beacon_templates_virgin = 1; - /* First register RFkill. - * LEDs that are registered later depend on it. */ - b43_rfkill_init(dev); - mutex_lock(&wl->mutex); if (b43_status(dev) < B43_STAT_INITIALIZED) { err = b43_wireless_core_init(dev); - if (err) { - do_rfkill_exit = 1; + if (err) goto out_mutex_unlock; - } did_init = 1; } @@ -4332,17 +4325,16 @@ static int b43_op_start(struct ieee80211_hw *hw) if (err) { if (did_init) b43_wireless_core_exit(dev); - do_rfkill_exit = 1; goto out_mutex_unlock; } } + /* XXX: only do if device doesn't support rfkill irq */ + wiphy_rfkill_start_polling(hw->wiphy); + out_mutex_unlock: mutex_unlock(&wl->mutex); - if (do_rfkill_exit) - b43_rfkill_exit(dev); - return err; } @@ -4351,7 +4343,6 @@ static void b43_op_stop(struct ieee80211_hw *hw) struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wldev *dev = wl->current_dev; - b43_rfkill_exit(dev); cancel_work_sync(&(wl->beacon_update_trigger)); mutex_lock(&wl->mutex); @@ -4433,6 +4424,7 @@ static const struct ieee80211_ops b43_hw_ops = { .sta_notify = b43_op_sta_notify, .sw_scan_start = b43_op_sw_scan_start_notifier, .sw_scan_complete = b43_op_sw_scan_complete_notifier, + .rfkill_poll = b43_rfkill_poll, }; /* Hard-reset the chip. Do not call this directly. @@ -4920,7 +4912,7 @@ static struct ssb_driver b43_ssb_driver = { static void b43_print_driverinfo(void) { const char *feat_pci = "", *feat_pcmcia = "", *feat_nphy = "", - *feat_leds = "", *feat_rfkill = ""; + *feat_leds = ""; #ifdef CONFIG_B43_PCI_AUTOSELECT feat_pci = "P"; @@ -4933,15 +4925,12 @@ static void b43_print_driverinfo(void) #endif #ifdef CONFIG_B43_LEDS feat_leds = "L"; -#endif -#ifdef CONFIG_B43_RFKILL - feat_rfkill = "R"; #endif printk(KERN_INFO "Broadcom 43xx driver loaded " - "[ Features: %s%s%s%s%s, Firmware-ID: " + "[ Features: %s%s%s%s, Firmware-ID: " B43_SUPPORTED_FIRMWARE_ID " ]\n", feat_pci, feat_pcmcia, feat_nphy, - feat_leds, feat_rfkill); + feat_leds); } static int __init b43_init(void) diff --git a/drivers/net/wireless/b43/phy_common.h b/drivers/net/wireless/b43/phy_common.h index f4c2d79cbc8..44cc918e4fc 100644 --- a/drivers/net/wireless/b43/phy_common.h +++ b/drivers/net/wireless/b43/phy_common.h @@ -1,7 +1,7 @@ #ifndef LINUX_B43_PHY_COMMON_H_ #define LINUX_B43_PHY_COMMON_H_ -#include +#include struct b43_wldev; diff --git a/drivers/net/wireless/b43/rfkill.c b/drivers/net/wireless/b43/rfkill.c index 96047843cd5..31e55999893 100644 --- a/drivers/net/wireless/b43/rfkill.c +++ b/drivers/net/wireless/b43/rfkill.c @@ -22,15 +22,11 @@ */ -#include "rfkill.h" #include "b43.h" -#include "phy_common.h" - -#include /* Returns TRUE, if the radio is enabled in hardware. */ -static bool b43_is_hw_radio_enabled(struct b43_wldev *dev) +bool b43_is_hw_radio_enabled(struct b43_wldev *dev) { if (dev->phy.rev >= 3) { if (!(b43_read32(dev, B43_MMIO_RADIO_HWENABLED_HI) @@ -45,110 +41,39 @@ static bool b43_is_hw_radio_enabled(struct b43_wldev *dev) } /* The poll callback for the hardware button. */ -static void b43_rfkill_poll(struct rfkill *rfkill, void *data) +void b43_rfkill_poll(struct ieee80211_hw *hw) { - struct b43_wldev *dev = data; - struct b43_wl *wl = dev->wl; + struct b43_wl *wl = hw_to_b43_wl(hw); + struct b43_wldev *dev = wl->current_dev; + struct ssb_bus *bus = dev->dev->bus; bool enabled; + bool brought_up = false; mutex_lock(&wl->mutex); if (unlikely(b43_status(dev) < B43_STAT_INITIALIZED)) { - mutex_unlock(&wl->mutex); - return; + if (ssb_bus_powerup(bus, 0)) { + mutex_unlock(&wl->mutex); + return; + } + ssb_device_enable(dev->dev, 0); + brought_up = true; } + enabled = b43_is_hw_radio_enabled(dev); + if (unlikely(enabled != dev->radio_hw_enable)) { dev->radio_hw_enable = enabled; b43info(wl, "Radio hardware status changed to %s\n", enabled ? "ENABLED" : "DISABLED"); - enabled = !rfkill_set_hw_state(rfkill, !enabled); + wiphy_rfkill_set_hw_state(hw->wiphy, !enabled); if (enabled != dev->phy.radio_on) b43_software_rfkill(dev, !enabled); } - mutex_unlock(&wl->mutex); -} - -/* Called when the RFKILL toggled in software. */ -static int b43_rfkill_soft_set(void *data, bool blocked) -{ - struct b43_wldev *dev = data; - struct b43_wl *wl = dev->wl; - int err = -EINVAL; - - if (WARN_ON(!wl->rfkill.registered)) - return -EINVAL; - mutex_lock(&wl->mutex); - - if (b43_status(dev) < B43_STAT_INITIALIZED) - goto out_unlock; - - if (!dev->radio_hw_enable) - goto out_unlock; + if (brought_up) { + ssb_device_disable(dev->dev, 0); + ssb_bus_may_powerdown(bus); + } - if (!blocked != dev->phy.radio_on) - b43_software_rfkill(dev, blocked); - err = 0; -out_unlock: mutex_unlock(&wl->mutex); - return err; -} - -const char *b43_rfkill_led_name(struct b43_wldev *dev) -{ - struct b43_rfkill *rfk = &(dev->wl->rfkill); - - if (!rfk->registered) - return NULL; - return rfkill_get_led_trigger_name(rfk->rfkill); -} - -static const struct rfkill_ops b43_rfkill_ops = { - .set_block = b43_rfkill_soft_set, - .poll = b43_rfkill_poll, -}; - -void b43_rfkill_init(struct b43_wldev *dev) -{ - struct b43_wl *wl = dev->wl; - struct b43_rfkill *rfk = &(wl->rfkill); - int err; - - rfk->registered = 0; - - snprintf(rfk->name, sizeof(rfk->name), - "b43-%s", wiphy_name(wl->hw->wiphy)); - - rfk->rfkill = rfkill_alloc(rfk->name, - dev->dev->dev, - RFKILL_TYPE_WLAN, - &b43_rfkill_ops, dev); - if (!rfk->rfkill) - goto out_error; - - err = rfkill_register(rfk->rfkill); - if (err) - goto err_free; - - rfk->registered = 1; - - return; - err_free: - rfkill_destroy(rfk->rfkill); - out_error: - rfk->registered = 0; - b43warn(wl, "RF-kill button init failed\n"); -} - -void b43_rfkill_exit(struct b43_wldev *dev) -{ - struct b43_rfkill *rfk = &(dev->wl->rfkill); - - if (!rfk->registered) - return; - rfk->registered = 0; - - rfkill_unregister(rfk->rfkill); - rfkill_destroy(rfk->rfkill); - rfk->rfkill = NULL; } diff --git a/drivers/net/wireless/b43/rfkill.h b/drivers/net/wireless/b43/rfkill.h index da497e01bbb..f046c3ca051 100644 --- a/drivers/net/wireless/b43/rfkill.h +++ b/drivers/net/wireless/b43/rfkill.h @@ -1,49 +1,11 @@ #ifndef B43_RFKILL_H_ #define B43_RFKILL_H_ +struct ieee80211_hw; struct b43_wldev; +void b43_rfkill_poll(struct ieee80211_hw *hw); -#ifdef CONFIG_B43_RFKILL - -#include - - -struct b43_rfkill { - /* The RFKILL subsystem data structure */ - struct rfkill *rfkill; - /* Did initialization succeed? Used for freeing. */ - bool registered; - /* The unique name of this rfkill switch */ - char name[sizeof("b43-phy4294967295")]; -}; - -/* The init function returns void, because we are not interested - * in failing the b43 init process when rfkill init failed. */ -void b43_rfkill_init(struct b43_wldev *dev); -void b43_rfkill_exit(struct b43_wldev *dev); - -const char *b43_rfkill_led_name(struct b43_wldev *dev); - - -#else /* CONFIG_B43_RFKILL */ -/* No RFKILL support. */ - -struct b43_rfkill { - /* empty */ -}; - -static inline void b43_rfkill_init(struct b43_wldev *dev) -{ -} -static inline void b43_rfkill_exit(struct b43_wldev *dev) -{ -} -static inline char * b43_rfkill_led_name(struct b43_wldev *dev) -{ - return NULL; -} - -#endif /* CONFIG_B43_RFKILL */ +bool b43_is_hw_radio_enabled(struct b43_wldev *dev); #endif /* B43_RFKILL_H_ */ diff --git a/drivers/net/wireless/b43legacy/Kconfig b/drivers/net/wireless/b43legacy/Kconfig index 6893f439df7..94a46347805 100644 --- a/drivers/net/wireless/b43legacy/Kconfig +++ b/drivers/net/wireless/b43legacy/Kconfig @@ -42,14 +42,6 @@ config B43LEGACY_LEDS depends on B43LEGACY && MAC80211_LEDS && (LEDS_CLASS = y || LEDS_CLASS = B43LEGACY) default y -# RFKILL support -# This config option automatically enables b43legacy RFKILL support, -# if it's possible. -config B43LEGACY_RFKILL - bool - depends on B43LEGACY && (RFKILL = y || RFKILL = B43LEGACY) - default y - # This config option automatically enables b43 HW-RNG support, # if the HW-RNG core is enabled. config B43LEGACY_HWRNG diff --git a/drivers/net/wireless/b43legacy/Makefile b/drivers/net/wireless/b43legacy/Makefile index 80cdb73bd14..227a77e8436 100644 --- a/drivers/net/wireless/b43legacy/Makefile +++ b/drivers/net/wireless/b43legacy/Makefile @@ -6,7 +6,7 @@ b43legacy-y += radio.o b43legacy-y += sysfs.o b43legacy-y += xmit.o # b43 RFKILL button support -b43legacy-$(CONFIG_B43LEGACY_RFKILL) += rfkill.o +b43legacy-y += rfkill.o # b43legacy LED support b43legacy-$(CONFIG_B43LEGACY_LEDS) += leds.o # b43legacy debugging diff --git a/drivers/net/wireless/b43legacy/b43legacy.h b/drivers/net/wireless/b43legacy/b43legacy.h index 19a4b0bc0d8..77fda148ac4 100644 --- a/drivers/net/wireless/b43legacy/b43legacy.h +++ b/drivers/net/wireless/b43legacy/b43legacy.h @@ -602,9 +602,6 @@ struct b43legacy_wl { char rng_name[30 + 1]; #endif - /* The RF-kill button */ - struct b43legacy_rfkill rfkill; - /* List of all wireless devices on this chip */ struct list_head devlist; u8 nr_devs; diff --git a/drivers/net/wireless/b43legacy/leds.c b/drivers/net/wireless/b43legacy/leds.c index 538d3117594..37e9be89356 100644 --- a/drivers/net/wireless/b43legacy/leds.c +++ b/drivers/net/wireless/b43legacy/leds.c @@ -28,6 +28,7 @@ #include "b43legacy.h" #include "leds.h" +#include "rfkill.h" static void b43legacy_led_turn_on(struct b43legacy_wldev *dev, u8 led_index, @@ -164,10 +165,10 @@ static void b43legacy_map_led(struct b43legacy_wldev *dev, snprintf(name, sizeof(name), "b43legacy-%s::radio", wiphy_name(hw->wiphy)); b43legacy_register_led(dev, &dev->led_radio, name, - b43legacy_rfkill_led_name(dev), + ieee80211_get_radio_led_name(hw), led_index, activelow); - /* Sync the RF-kill LED state with the switch state. */ - if (dev->radio_hw_enable) + /* Sync the RF-kill LED state with radio and switch states. */ + if (dev->phy.radio_on && b43legacy_is_hw_radio_enabled(dev)) b43legacy_led_turn_on(dev, led_index, activelow); break; case B43legacy_LED_WEIRD: diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index f6f3fbf0a2f..e5136fb65dd 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -3431,11 +3431,6 @@ static int b43legacy_op_start(struct ieee80211_hw *hw) struct b43legacy_wldev *dev = wl->current_dev; int did_init = 0; int err = 0; - bool do_rfkill_exit = 0; - - /* First register RFkill. - * LEDs that are registered later depend on it. */ - b43legacy_rfkill_init(dev); /* Kill all old instance specific information to make sure * the card won't use it in the short timeframe between start @@ -3451,10 +3446,8 @@ static int b43legacy_op_start(struct ieee80211_hw *hw) if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) { err = b43legacy_wireless_core_init(dev); - if (err) { - do_rfkill_exit = 1; + if (err) goto out_mutex_unlock; - } did_init = 1; } @@ -3463,17 +3456,15 @@ static int b43legacy_op_start(struct ieee80211_hw *hw) if (err) { if (did_init) b43legacy_wireless_core_exit(dev); - do_rfkill_exit = 1; goto out_mutex_unlock; } } + wiphy_rfkill_start_polling(hw->wiphy); + out_mutex_unlock: mutex_unlock(&wl->mutex); - if (do_rfkill_exit) - b43legacy_rfkill_exit(dev); - return err; } @@ -3482,7 +3473,6 @@ static void b43legacy_op_stop(struct ieee80211_hw *hw) struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); struct b43legacy_wldev *dev = wl->current_dev; - b43legacy_rfkill_exit(dev); cancel_work_sync(&(wl->beacon_update_trigger)); mutex_lock(&wl->mutex); @@ -3518,6 +3508,7 @@ static const struct ieee80211_ops b43legacy_hw_ops = { .start = b43legacy_op_start, .stop = b43legacy_op_stop, .set_tim = b43legacy_op_beacon_set_tim, + .rfkill_poll = b43legacy_rfkill_poll, }; /* Hard-reset the chip. Do not call this directly. diff --git a/drivers/net/wireless/b43legacy/rfkill.c b/drivers/net/wireless/b43legacy/rfkill.c index c6230a64505..8783022db11 100644 --- a/drivers/net/wireless/b43legacy/rfkill.c +++ b/drivers/net/wireless/b43legacy/rfkill.c @@ -22,15 +22,12 @@ */ -#include "rfkill.h" #include "radio.h" #include "b43legacy.h" -#include - /* Returns TRUE, if the radio is enabled in hardware. */ -static bool b43legacy_is_hw_radio_enabled(struct b43legacy_wldev *dev) +bool b43legacy_is_hw_radio_enabled(struct b43legacy_wldev *dev) { if (dev->phy.rev >= 3) { if (!(b43legacy_read32(dev, B43legacy_MMIO_RADIO_HWENABLED_HI) @@ -45,23 +42,31 @@ static bool b43legacy_is_hw_radio_enabled(struct b43legacy_wldev *dev) } /* The poll callback for the hardware button. */ -static void b43legacy_rfkill_poll(struct rfkill *rfkill, void *data) +void b43legacy_rfkill_poll(struct ieee80211_hw *hw) { - struct b43legacy_wldev *dev = data; - struct b43legacy_wl *wl = dev->wl; + struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); + struct b43legacy_wldev *dev = wl->current_dev; + struct ssb_bus *bus = dev->dev->bus; bool enabled; + bool brought_up = false; mutex_lock(&wl->mutex); if (unlikely(b43legacy_status(dev) < B43legacy_STAT_INITIALIZED)) { - mutex_unlock(&wl->mutex); - return; + if (ssb_bus_powerup(bus, 0)) { + mutex_unlock(&wl->mutex); + return; + } + ssb_device_enable(dev->dev, 0); + brought_up = true; } + enabled = b43legacy_is_hw_radio_enabled(dev); + if (unlikely(enabled != dev->radio_hw_enable)) { dev->radio_hw_enable = enabled; b43legacyinfo(wl, "Radio hardware status changed to %s\n", enabled ? "ENABLED" : "DISABLED"); - enabled = !rfkill_set_hw_state(rfkill, !enabled); + wiphy_rfkill_set_hw_state(hw->wiphy, !enabled); if (enabled != dev->phy.radio_on) { if (enabled) b43legacy_radio_turn_on(dev); @@ -69,95 +74,11 @@ static void b43legacy_rfkill_poll(struct rfkill *rfkill, void *data) b43legacy_radio_turn_off(dev, 0); } } - mutex_unlock(&wl->mutex); -} - -/* Called when the RFKILL toggled in software. - * This is called without locking. */ -static int b43legacy_rfkill_soft_set(void *data, bool blocked) -{ - struct b43legacy_wldev *dev = data; - struct b43legacy_wl *wl = dev->wl; - int ret = -EINVAL; - if (!wl->rfkill.registered) - return -EINVAL; - - mutex_lock(&wl->mutex); - if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) - goto out_unlock; - - if (!dev->radio_hw_enable) - goto out_unlock; - - if (!blocked != dev->phy.radio_on) { - if (!blocked) - b43legacy_radio_turn_on(dev); - else - b43legacy_radio_turn_off(dev, 0); + if (brought_up) { + ssb_device_disable(dev->dev, 0); + ssb_bus_may_powerdown(bus); } - ret = 0; -out_unlock: mutex_unlock(&wl->mutex); - return ret; -} - -const char *b43legacy_rfkill_led_name(struct b43legacy_wldev *dev) -{ - struct b43legacy_rfkill *rfk = &(dev->wl->rfkill); - - if (!rfk->registered) - return NULL; - return rfkill_get_led_trigger_name(rfk->rfkill); } - -static const struct rfkill_ops b43legacy_rfkill_ops = { - .set_block = b43legacy_rfkill_soft_set, - .poll = b43legacy_rfkill_poll, -}; - -void b43legacy_rfkill_init(struct b43legacy_wldev *dev) -{ - struct b43legacy_wl *wl = dev->wl; - struct b43legacy_rfkill *rfk = &(wl->rfkill); - int err; - - rfk->registered = 0; - - snprintf(rfk->name, sizeof(rfk->name), - "b43legacy-%s", wiphy_name(wl->hw->wiphy)); - rfk->rfkill = rfkill_alloc(rfk->name, - dev->dev->dev, - RFKILL_TYPE_WLAN, - &b43legacy_rfkill_ops, dev); - if (!rfk->rfkill) - goto out_error; - - err = rfkill_register(rfk->rfkill); - if (err) - goto err_free; - - rfk->registered = 1; - - return; - err_free: - rfkill_destroy(rfk->rfkill); - out_error: - rfk->registered = 0; - b43legacywarn(wl, "RF-kill button init failed\n"); -} - -void b43legacy_rfkill_exit(struct b43legacy_wldev *dev) -{ - struct b43legacy_rfkill *rfk = &(dev->wl->rfkill); - - if (!rfk->registered) - return; - rfk->registered = 0; - - rfkill_unregister(rfk->rfkill); - rfkill_destroy(rfk->rfkill); - rfk->rfkill = NULL; -} - diff --git a/drivers/net/wireless/b43legacy/rfkill.h b/drivers/net/wireless/b43legacy/rfkill.h index adffc503a6a..75585571c54 100644 --- a/drivers/net/wireless/b43legacy/rfkill.h +++ b/drivers/net/wireless/b43legacy/rfkill.h @@ -1,55 +1,11 @@ #ifndef B43legacy_RFKILL_H_ #define B43legacy_RFKILL_H_ +struct ieee80211_hw; struct b43legacy_wldev; -#ifdef CONFIG_B43LEGACY_RFKILL +void b43legacy_rfkill_poll(struct ieee80211_hw *hw); -#include - - - -struct b43legacy_rfkill { - /* The RFKILL subsystem data structure */ - struct rfkill *rfkill; - /* Did initialization succeed? Used for freeing. */ - bool registered; - /* The unique name of this rfkill switch */ - char name[sizeof("b43legacy-phy4294967295")]; -}; - -/* The init function returns void, because we are not interested - * in failing the b43 init process when rfkill init failed. */ -void b43legacy_rfkill_init(struct b43legacy_wldev *dev); -void b43legacy_rfkill_exit(struct b43legacy_wldev *dev); - -const char *b43legacy_rfkill_led_name(struct b43legacy_wldev *dev); - - -#else /* CONFIG_B43LEGACY_RFKILL */ -/* No RFKILL support. */ - -struct b43legacy_rfkill { - /* empty */ -}; - -static inline void b43legacy_rfkill_alloc(struct b43legacy_wldev *dev) -{ -} -static inline void b43legacy_rfkill_free(struct b43legacy_wldev *dev) -{ -} -static inline void b43legacy_rfkill_init(struct b43legacy_wldev *dev) -{ -} -static inline void b43legacy_rfkill_exit(struct b43legacy_wldev *dev) -{ -} -static inline char *b43legacy_rfkill_led_name(struct b43legacy_wldev *dev) -{ - return NULL; -} - -#endif /* CONFIG_B43LEGACY_RFKILL */ +bool b43legacy_is_hw_radio_enabled(struct b43legacy_wldev *dev); #endif /* B43legacy_RFKILL_H_ */ -- cgit v1.2.3 From b91d0e364077fad401454699143ad6a78902c20a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 8 Jun 2009 08:14:28 +0200 Subject: rfkill: remove input Kconfig Now that we added the ioctl, there's no need to ask the user to configure this. We will keep it enabled for now, and eventually swap the default to n. Also let embedded users select it only if they need it. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/rfkill/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/rfkill/Kconfig b/net/rfkill/Kconfig index fd7600d8ab1..eaf76587645 100644 --- a/net/rfkill/Kconfig +++ b/net/rfkill/Kconfig @@ -18,7 +18,7 @@ config RFKILL_LEDS default y config RFKILL_INPUT - bool "RF switch input support" + bool "RF switch input support" if EMBEDDED depends on RFKILL depends on INPUT = y || RFKILL = INPUT default y if !EMBEDDED -- cgit v1.2.3 From fc240e3fc5791c572402b0857948da7b1e68d77f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 7 Jun 2009 21:57:08 +0200 Subject: sony: fix rfkill code During the rfkill conversion I added code to call sony_nc_rfkill_set with the wrong argument, causing a segfault Reinette reported. The compiler could not catch that because the argument is, and needs to be, void *. Signed-off-by: Johannes Berg Reported-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/platform/x86/sony-laptop.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index aec0b27fd77..f2893443b31 100644 --- a/drivers/platform/x86/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c @@ -1135,8 +1135,7 @@ static void sony_nc_rfkill_update() if (hwblock) { if (rfkill_set_hw_state(sony_rfkill_devices[i], true)) - sony_nc_rfkill_set(sony_rfkill_devices[i], - true); + sony_nc_rfkill_set((void *)i, true); continue; } -- cgit v1.2.3 From 8f77f3849cc3ae2d6df9301785a3d316ea7d7ee1 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 7 Jun 2009 21:58:37 +0200 Subject: mac80211: do not pass PS frames out of mac80211 again In order to handle powersave frames properly we had needed to pass these out to the device queues again, and introduce the skb->requeue bit. This, however, also has unnecessary overhead by needing to 'clean up' already tried frames, and this clean-up code is also buggy when software encryption is used. Instead of sending the frames via the master netdev queue again, simply put them into the pending queue. This also fixes a problem where frames for that particular station could be reordered when some were still on the software queues and older ones are re-injected into the software queue after them. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- include/linux/skbuff.h | 4 --- include/net/mac80211.h | 3 +++ net/core/skbuff.c | 1 - net/mac80211/ieee80211_i.h | 5 ++++ net/mac80211/main.c | 61 +++++----------------------------------------- net/mac80211/rx.c | 25 +++++++------------ net/mac80211/tx.c | 3 ++- net/mac80211/util.c | 46 ++++++++++++++++++++++++++++++++++ net/mac80211/wme.c | 2 +- 9 files changed, 72 insertions(+), 78 deletions(-) diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index f1c93b878b3..fa51293f270 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -304,9 +304,6 @@ typedef unsigned char *sk_buff_data_t; * @tc_verd: traffic control verdict * @ndisc_nodetype: router type (from link layer) * @do_not_encrypt: set to prevent encryption of this frame - * @requeue: set to indicate that the wireless core should attempt - * a software retry on this frame if we failed to - * receive an ACK for it * @dma_cookie: a cookie to one of several possible DMA operations * done by skb DMA functions * @secmark: security marking @@ -380,7 +377,6 @@ struct sk_buff { #endif #if defined(CONFIG_MAC80211) || defined(CONFIG_MAC80211_MODULE) __u8 do_not_encrypt:1; - __u8 requeue:1; #endif /* 0/13/14 bit hole */ diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 17d61d19d91..c0610447697 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -239,6 +239,8 @@ struct ieee80211_bss_conf { * @IEEE80211_TX_INTFL_NEED_TXPROCESSING: completely internal to mac80211, * used to indicate that a pending frame requires TX processing before * it can be sent out. + * @IEEE80211_TX_INTFL_RETRIED: completely internal to mac80211, + * used to indicate that a frame was already retried due to PS */ enum mac80211_tx_control_flags { IEEE80211_TX_CTL_REQ_TX_STATUS = BIT(0), @@ -256,6 +258,7 @@ enum mac80211_tx_control_flags { IEEE80211_TX_CTL_RATE_CTRL_PROBE = BIT(12), IEEE80211_TX_INTFL_RCALGO = BIT(13), IEEE80211_TX_INTFL_NEED_TXPROCESSING = BIT(14), + IEEE80211_TX_INTFL_RETRIED = BIT(15), }; /** diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 49961ba3c0f..b94d777e3eb 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -552,7 +552,6 @@ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old) new->vlan_tci = old->vlan_tci; #if defined(CONFIG_MAC80211) || defined(CONFIG_MAC80211_MODULE) new->do_not_encrypt = old->do_not_encrypt; - new->requeue = old->requeue; #endif skb_copy_secmark(new, old); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index c088c46704a..4dbc2896419 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -589,6 +589,7 @@ enum queue_stop_reason { IEEE80211_QUEUE_STOP_REASON_AGGREGATION, IEEE80211_QUEUE_STOP_REASON_SUSPEND, IEEE80211_QUEUE_STOP_REASON_PENDING, + IEEE80211_QUEUE_STOP_REASON_SKB_ADD, }; struct ieee80211_master_priv { @@ -1121,6 +1122,10 @@ void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue, enum queue_stop_reason reason); void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue, enum queue_stop_reason reason); +void ieee80211_add_pending_skb(struct ieee80211_local *local, + struct sk_buff *skb); +int ieee80211_add_pending_skbs(struct ieee80211_local *local, + struct sk_buff_head *skbs); void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, u16 transaction, u16 auth_alg, diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 2683df91807..092a017b237 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -369,60 +369,12 @@ static void ieee80211_tasklet_handler(unsigned long data) } } -/* Remove added headers (e.g., QoS control), encryption header/MIC, etc. to - * make a prepared TX frame (one that has been given to hw) to look like brand - * new IEEE 802.11 frame that is ready to go through TX processing again. - */ -static void ieee80211_remove_tx_extra(struct ieee80211_local *local, - struct ieee80211_key *key, - struct sk_buff *skb) -{ - unsigned int hdrlen, iv_len, mic_len; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - - hdrlen = ieee80211_hdrlen(hdr->frame_control); - - if (!key) - goto no_key; - - switch (key->conf.alg) { - case ALG_WEP: - iv_len = WEP_IV_LEN; - mic_len = WEP_ICV_LEN; - break; - case ALG_TKIP: - iv_len = TKIP_IV_LEN; - mic_len = TKIP_ICV_LEN; - break; - case ALG_CCMP: - iv_len = CCMP_HDR_LEN; - mic_len = CCMP_MIC_LEN; - break; - default: - goto no_key; - } - - if (skb->len >= hdrlen + mic_len && - !(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) - skb_trim(skb, skb->len - mic_len); - if (skb->len >= hdrlen + iv_len) { - memmove(skb->data + iv_len, skb->data, hdrlen); - hdr = (struct ieee80211_hdr *)skb_pull(skb, iv_len); - } - -no_key: - if (ieee80211_is_data_qos(hdr->frame_control)) { - hdr->frame_control &= ~cpu_to_le16(IEEE80211_STYPE_QOS_DATA); - memmove(skb->data + IEEE80211_QOS_CTL_LEN, skb->data, - hdrlen - IEEE80211_QOS_CTL_LEN); - skb_pull(skb, IEEE80211_QOS_CTL_LEN); - } -} - static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, struct sta_info *sta, struct sk_buff *skb) { + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + sta->tx_filtered_count++; /* @@ -464,16 +416,15 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, */ if (test_sta_flags(sta, WLAN_STA_PS) && skb_queue_len(&sta->tx_filtered) < STA_MAX_TX_BUFFER) { - ieee80211_remove_tx_extra(local, sta->key, skb); skb_queue_tail(&sta->tx_filtered, skb); return; } - if (!test_sta_flags(sta, WLAN_STA_PS) && !skb->requeue) { + if (!test_sta_flags(sta, WLAN_STA_PS) && + !(info->flags & IEEE80211_TX_INTFL_RETRIED)) { /* Software retry the packet once */ - skb->requeue = 1; - ieee80211_remove_tx_extra(local, sta->key, skb); - dev_queue_xmit(skb); + info->flags |= IEEE80211_TX_INTFL_RETRIED; + ieee80211_add_pending_skb(local, skb); return; } diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 75412518510..de5bba7f910 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -797,8 +797,7 @@ static int ap_sta_ps_end(struct sta_info *sta) { struct ieee80211_sub_if_data *sdata = sta->sdata; struct ieee80211_local *local = sdata->local; - struct sk_buff *skb; - int sent = 0; + int sent, buffered; atomic_dec(&sdata->bss->num_sta_ps); @@ -814,22 +813,16 @@ static int ap_sta_ps_end(struct sta_info *sta) #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ /* Send all buffered frames to the station */ - while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) { - sent++; - skb->requeue = 1; - dev_queue_xmit(skb); - } - while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) { - local->total_ps_buffered--; - sent++; + sent = ieee80211_add_pending_skbs(local, &sta->tx_filtered); + buffered = ieee80211_add_pending_skbs(local, &sta->ps_tx_buf); + sent += buffered; + local->total_ps_buffered -= buffered; + #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG - printk(KERN_DEBUG "%s: STA %pM aid %d send PS frame " - "since STA not sleeping anymore\n", sdata->dev->name, - sta->sta.addr, sta->sta.aid); + printk(KERN_DEBUG "%s: STA %pM aid %d sending %d filtered/%d PS frames " + "since STA not sleeping anymore\n", sdata->dev->name, + sta->sta.addr, sta->sta.aid, sent - buffered, buffered); #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ - skb->requeue = 1; - dev_queue_xmit(skb); - } return sent; } diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 1436f747531..bfaa9ce3314 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -400,6 +400,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) sta_info_set_tim_bit(sta); info->control.jiffies = jiffies; + info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; skb_queue_tail(&sta->ps_tx_buf, tx->skb); return TX_QUEUED; } @@ -420,7 +421,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) * frame filtering and keeps a station blacklist on its own * (e.g: p54), so that frames can be delivered unimpeded. * - * Note: It should be save to disable the filter now. + * Note: It should be safe to disable the filter now. * As, it is really unlikely that we still have any pending * frame for this station in the hw's buffers/fifos left, * that is not rejected with a unsuccessful tx_status yet. diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 22f63815fb3..66ce96a69f3 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -341,6 +341,52 @@ void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue) } EXPORT_SYMBOL(ieee80211_stop_queue); +void ieee80211_add_pending_skb(struct ieee80211_local *local, + struct sk_buff *skb) +{ + struct ieee80211_hw *hw = &local->hw; + unsigned long flags; + int queue = skb_get_queue_mapping(skb); + + spin_lock_irqsave(&local->queue_stop_reason_lock, flags); + __ieee80211_stop_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_SKB_ADD); + __ieee80211_stop_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_PENDING); + skb_queue_tail(&local->pending[queue], skb); + __ieee80211_wake_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_SKB_ADD); + spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); +} + +int ieee80211_add_pending_skbs(struct ieee80211_local *local, + struct sk_buff_head *skbs) +{ + struct ieee80211_hw *hw = &local->hw; + struct sk_buff *skb; + unsigned long flags; + int queue, ret = 0, i; + + spin_lock_irqsave(&local->queue_stop_reason_lock, flags); + for (i = 0; i < hw->queues; i++) + __ieee80211_stop_queue(hw, i, + IEEE80211_QUEUE_STOP_REASON_SKB_ADD); + + while ((skb = skb_dequeue(skbs))) { + ret++; + queue = skb_get_queue_mapping(skb); + skb_queue_tail(&local->pending[queue], skb); + } + + for (i = 0; i < hw->queues; i++) { + if (ret) + __ieee80211_stop_queue(hw, i, + IEEE80211_QUEUE_STOP_REASON_PENDING); + __ieee80211_wake_queue(hw, i, + IEEE80211_QUEUE_STOP_REASON_SKB_ADD); + } + spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); + + return ret; +} + void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw, enum queue_stop_reason reason) { diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c index 694343b9102..116a923b14d 100644 --- a/net/mac80211/wme.c +++ b/net/mac80211/wme.c @@ -101,7 +101,7 @@ u16 ieee80211_select_queue(struct net_device *dev, struct sk_buff *skb) * Now we know the 1d priority, fill in the QoS header if * there is one (and we haven't done this before). */ - if (!skb->requeue && ieee80211_is_data_qos(hdr->frame_control)) { + if (ieee80211_is_data_qos(hdr->frame_control)) { u8 *p = ieee80211_get_qos_ctl(hdr); u8 ack_policy = 0; tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK; -- cgit v1.2.3 From b3fa1329eaf2a7b97124dacf5b663fd51346ac19 Mon Sep 17 00:00:00 2001 From: Alan Jenkins Date: Mon, 8 Jun 2009 13:27:27 +0100 Subject: rfkill: remove set_global_sw_state rfkill_set_global_sw_state() (previously rfkill_set_default()) will no longer be exported by the rewritten rfkill core. Instead, platform drivers which can provide persistent soft-rfkill state across power-down/reboot should indicate their initial state by calling rfkill_set_sw_state() before registration. Otherwise, they will be initialized to a default value during registration by a set_block call. We remove existing calls to rfkill_set_sw_state() which happen before registration, since these had no effect in the old model. If these drivers do have persistent state, the calls can be put back (subject to testing :-). This affects hp-wmi and acer-wmi. Drivers with persistent state will affect the global state only if rfkill-input is enabled. This is required, otherwise booting with wireless soft-blocked and pressing the wireless-toggle key once would have no apparent effect. This special case will be removed in future along with rfkill-input, in favour of a more flexible userspace daemon (see Documentation/feature-removal-schedule.txt). Now rfkill_global_states[n].def is only used to preserve global states over EPO, it is renamed to ".sav". Signed-off-by: Alan Jenkins Acked-by: Henrique de Moraes Holschuh Signed-off-by: John W. Linville --- drivers/platform/x86/acer-wmi.c | 3 -- drivers/platform/x86/eeepc-laptop.c | 8 ++-- drivers/platform/x86/hp-wmi.c | 4 -- drivers/platform/x86/thinkpad_acpi.c | 31 +++++++------- include/linux/rfkill.h | 28 ++++--------- net/rfkill/core.c | 81 +++++++++++++----------------------- 6 files changed, 56 insertions(+), 99 deletions(-) diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index b618fa51db2..09a503e5da6 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c @@ -988,7 +988,6 @@ static struct rfkill *acer_rfkill_register(struct device *dev, char *name, u32 cap) { int err; - u32 state; struct rfkill *rfkill_dev; rfkill_dev = rfkill_alloc(name, dev, type, @@ -996,8 +995,6 @@ static struct rfkill *acer_rfkill_register(struct device *dev, (void *)(unsigned long)cap); if (!rfkill_dev) return ERR_PTR(-ENOMEM); - get_u32(&state, cap); - rfkill_set_sw_state(rfkill_dev, !state); err = rfkill_register(rfkill_dev); if (err) { diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index 1208d0cedd1..03bf522bd7a 100644 --- a/drivers/platform/x86/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c @@ -675,8 +675,8 @@ static int eeepc_hotk_add(struct acpi_device *device) if (!ehotk->eeepc_wlan_rfkill) goto wlan_fail; - rfkill_set_global_sw_state(RFKILL_TYPE_WLAN, - get_acpi(CM_ASL_WLAN) != 1); + rfkill_set_sw_state(ehotk->eeepc_wlan_rfkill, + get_acpi(CM_ASL_WLAN) != 1); result = rfkill_register(ehotk->eeepc_wlan_rfkill); if (result) goto wlan_fail; @@ -693,8 +693,8 @@ static int eeepc_hotk_add(struct acpi_device *device) if (!ehotk->eeepc_bluetooth_rfkill) goto bluetooth_fail; - rfkill_set_global_sw_state(RFKILL_TYPE_BLUETOOTH, - get_acpi(CM_ASL_BLUETOOTH) != 1); + rfkill_set_sw_state(ehotk->eeepc_bluetooth_rfkill, + get_acpi(CM_ASL_BLUETOOTH) != 1); result = rfkill_register(ehotk->eeepc_bluetooth_rfkill); if (result) goto bluetooth_fail; diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c index 8d931145cbf..16fffe44e33 100644 --- a/drivers/platform/x86/hp-wmi.c +++ b/drivers/platform/x86/hp-wmi.c @@ -422,7 +422,6 @@ static int __init hp_wmi_bios_setup(struct platform_device *device) RFKILL_TYPE_WLAN, &hp_wmi_rfkill_ops, (void *) 0); - rfkill_set_sw_state(wifi_rfkill, hp_wmi_wifi_state()); err = rfkill_register(wifi_rfkill); if (err) goto register_wifi_error; @@ -433,8 +432,6 @@ static int __init hp_wmi_bios_setup(struct platform_device *device) RFKILL_TYPE_BLUETOOTH, &hp_wmi_rfkill_ops, (void *) 1); - rfkill_set_sw_state(bluetooth_rfkill, - hp_wmi_bluetooth_state()); err = rfkill_register(bluetooth_rfkill); if (err) goto register_bluetooth_error; @@ -445,7 +442,6 @@ static int __init hp_wmi_bios_setup(struct platform_device *device) RFKILL_TYPE_WWAN, &hp_wmi_rfkill_ops, (void *) 2); - rfkill_set_sw_state(wwan_rfkill, hp_wmi_wwan_state()); err = rfkill_register(wwan_rfkill); if (err) goto register_wwan_err; diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index cfcafa4e947..86e958539f4 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -1168,21 +1168,6 @@ static int __init tpacpi_new_rfkill(const enum tpacpi_rfk_id id, BUG_ON(id >= TPACPI_RFK_SW_MAX || tpacpi_rfkill_switches[id]); - initial_sw_status = (tp_rfkops->get_status)(); - if (initial_sw_status < 0) { - printk(TPACPI_ERR - "failed to read initial state for %s, error %d; " - "will turn radio off\n", name, initial_sw_status); - } else { - initial_sw_state = (initial_sw_status == TPACPI_RFK_RADIO_OFF); - if (set_default) { - /* try to set the initial state as the default for the - * rfkill type, since we ask the firmware to preserve - * it across S5 in NVRAM */ - rfkill_set_global_sw_state(rfktype, initial_sw_state); - } - } - atp_rfk = kzalloc(sizeof(struct tpacpi_rfk), GFP_KERNEL); if (atp_rfk) atp_rfk->rfkill = rfkill_alloc(name, @@ -1200,8 +1185,20 @@ static int __init tpacpi_new_rfkill(const enum tpacpi_rfk_id id, atp_rfk->id = id; atp_rfk->ops = tp_rfkops; - rfkill_set_states(atp_rfk->rfkill, initial_sw_state, - tpacpi_rfk_check_hwblock_state()); + initial_sw_status = (tp_rfkops->get_status)(); + if (initial_sw_status < 0) { + printk(TPACPI_ERR + "failed to read initial state for %s, error %d\n", + name, initial_sw_status); + } else { + initial_sw_state = (initial_sw_status == TPACPI_RFK_RADIO_OFF); + if (set_default) { + /* try to keep the initial state, since we ask the + * firmware to preserve it across S5 in NVRAM */ + rfkill_set_sw_state(atp_rfk->rfkill, initial_sw_state); + } + } + rfkill_set_hw_state(atp_rfk->rfkill, tpacpi_rfk_check_hwblock_state()); res = rfkill_register(atp_rfk->rfkill); if (res < 0) { diff --git a/include/linux/rfkill.h b/include/linux/rfkill.h index d7e818ad0bc..c1dca0b8138 100644 --- a/include/linux/rfkill.h +++ b/include/linux/rfkill.h @@ -157,8 +157,14 @@ struct rfkill * __must_check rfkill_alloc(const char *name, * @rfkill: rfkill structure to be registered * * This function should be called by the transmitter driver to register - * the rfkill structure needs to be registered. Before calling this function - * the driver needs to be ready to service method calls from rfkill. + * the rfkill structure. Before calling this function the driver needs + * to be ready to service method calls from rfkill. + * + * If the software blocked state is not set before registration, + * set_block will be called to initialize it to a default value. + * + * If the hardware blocked state is not set before registration, + * it is assumed to be unblocked. */ int __must_check rfkill_register(struct rfkill *rfkill); @@ -250,19 +256,6 @@ bool rfkill_set_sw_state(struct rfkill *rfkill, bool blocked); */ void rfkill_set_states(struct rfkill *rfkill, bool sw, bool hw); -/** - * rfkill_set_global_sw_state - set global sw block default - * @type: rfkill type to set default for - * @blocked: default to set - * - * This function sets the global default -- use at boot if your platform has - * an rfkill switch. If not early enough this call may be ignored. - * - * XXX: instead of ignoring -- how about just updating all currently - * registered drivers? - */ -void rfkill_set_global_sw_state(const enum rfkill_type type, bool blocked); - /** * rfkill_blocked - query rfkill block * @@ -317,11 +310,6 @@ static inline void rfkill_set_states(struct rfkill *rfkill, bool sw, bool hw) { } -static inline void rfkill_set_global_sw_state(const enum rfkill_type type, - bool blocked) -{ -} - static inline bool rfkill_blocked(struct rfkill *rfkill) { return false; diff --git a/net/rfkill/core.c b/net/rfkill/core.c index e161ebc40a3..fa430bd03f1 100644 --- a/net/rfkill/core.c +++ b/net/rfkill/core.c @@ -57,6 +57,7 @@ struct rfkill { bool registered; bool suspended; + bool persistent; const struct rfkill_ops *ops; void *data; @@ -116,11 +117,9 @@ MODULE_PARM_DESC(default_state, "Default initial state for all radio types, 0 = radio off"); static struct { - bool cur, def; + bool cur, sav; } rfkill_global_states[NUM_RFKILL_TYPES]; -static unsigned long rfkill_states_default_locked; - static bool rfkill_epo_lock_active; @@ -392,7 +391,7 @@ void rfkill_epo(void) rfkill_set_block(rfkill, true); for (i = 0; i < NUM_RFKILL_TYPES; i++) { - rfkill_global_states[i].def = rfkill_global_states[i].cur; + rfkill_global_states[i].sav = rfkill_global_states[i].cur; rfkill_global_states[i].cur = true; } @@ -417,7 +416,7 @@ void rfkill_restore_states(void) rfkill_epo_lock_active = false; for (i = 0; i < NUM_RFKILL_TYPES; i++) - __rfkill_switch_all(i, rfkill_global_states[i].def); + __rfkill_switch_all(i, rfkill_global_states[i].sav); mutex_unlock(&rfkill_global_mutex); } @@ -464,29 +463,6 @@ bool rfkill_get_global_sw_state(const enum rfkill_type type) } #endif -void rfkill_set_global_sw_state(const enum rfkill_type type, bool blocked) -{ - BUG_ON(type == RFKILL_TYPE_ALL); - - mutex_lock(&rfkill_global_mutex); - - /* don't allow unblock when epo */ - if (rfkill_epo_lock_active && !blocked) - goto out; - - /* too late */ - if (rfkill_states_default_locked & BIT(type)) - goto out; - - rfkill_states_default_locked |= BIT(type); - - rfkill_global_states[type].cur = blocked; - rfkill_global_states[type].def = blocked; - out: - mutex_unlock(&rfkill_global_mutex); -} -EXPORT_SYMBOL(rfkill_set_global_sw_state); - bool rfkill_set_hw_state(struct rfkill *rfkill, bool blocked) { @@ -532,13 +508,14 @@ bool rfkill_set_sw_state(struct rfkill *rfkill, bool blocked) blocked = blocked || hwblock; spin_unlock_irqrestore(&rfkill->lock, flags); - if (!rfkill->registered) - return blocked; + if (!rfkill->registered) { + rfkill->persistent = true; + } else { + if (prev != blocked && !hwblock) + schedule_work(&rfkill->uevent_work); - if (prev != blocked && !hwblock) - schedule_work(&rfkill->uevent_work); - - rfkill_led_trigger_event(rfkill); + rfkill_led_trigger_event(rfkill); + } return blocked; } @@ -563,13 +540,14 @@ void rfkill_set_states(struct rfkill *rfkill, bool sw, bool hw) spin_unlock_irqrestore(&rfkill->lock, flags); - if (!rfkill->registered) - return; - - if (swprev != sw || hwprev != hw) - schedule_work(&rfkill->uevent_work); + if (!rfkill->registered) { + rfkill->persistent = true; + } else { + if (swprev != sw || hwprev != hw) + schedule_work(&rfkill->uevent_work); - rfkill_led_trigger_event(rfkill); + rfkill_led_trigger_event(rfkill); + } } EXPORT_SYMBOL(rfkill_set_states); @@ -888,15 +866,6 @@ int __must_check rfkill_register(struct rfkill *rfkill) dev_set_name(dev, "rfkill%lu", rfkill_no); rfkill_no++; - if (!(rfkill_states_default_locked & BIT(rfkill->type))) { - /* first of its kind */ - BUILD_BUG_ON(NUM_RFKILL_TYPES > - sizeof(rfkill_states_default_locked) * 8); - rfkill_states_default_locked |= BIT(rfkill->type); - rfkill_global_states[rfkill->type].cur = - rfkill_global_states[rfkill->type].def; - } - list_add_tail(&rfkill->node, &rfkill_list); error = device_add(dev); @@ -916,7 +885,17 @@ int __must_check rfkill_register(struct rfkill *rfkill) if (rfkill->ops->poll) schedule_delayed_work(&rfkill->poll_work, round_jiffies_relative(POLL_INTERVAL)); - schedule_work(&rfkill->sync_work); + + if (!rfkill->persistent || rfkill_epo_lock_active) { + schedule_work(&rfkill->sync_work); + } else { +#ifdef CONFIG_RFKILL_INPUT + bool soft_blocked = !!(rfkill->state & RFKILL_BLOCK_SW); + + if (!atomic_read(&rfkill_input_disabled)) + __rfkill_switch_all(rfkill->type, soft_blocked); +#endif + } rfkill_send_events(rfkill, RFKILL_OP_ADD); @@ -1193,7 +1172,7 @@ static int __init rfkill_init(void) int i; for (i = 0; i < NUM_RFKILL_TYPES; i++) - rfkill_global_states[i].def = !rfkill_default_state; + rfkill_global_states[i].cur = !rfkill_default_state; error = class_register(&rfkill_class); if (error) -- cgit v1.2.3 From 869fb3a46cd18235e6f176328a2d8085ffe2c704 Mon Sep 17 00:00:00 2001 From: Alan Jenkins Date: Mon, 8 Jun 2009 11:31:11 +0100 Subject: sony-laptop: no need to unblock rfkill on load The re-written rfkill core ensures rfkill devices are initialized to the system default state. The core calls set_block after registration so the driver shouldn't need to. Signed-off-by: Alan Jenkins Signed-off-by: John W. Linville --- drivers/platform/x86/sony-laptop.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index f2893443b31..e48d9a4506f 100644 --- a/drivers/platform/x86/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c @@ -1114,7 +1114,6 @@ static int sony_nc_setup_rfkill(struct acpi_device *device, return err; } sony_rfkill_devices[nc_type] = rfk; - sony_nc_rfkill_set((void *)nc_type, false); return err; } -- cgit v1.2.3 From 908209c160da8ecb68052111972b7a21310eac3f Mon Sep 17 00:00:00 2001 From: Alan Jenkins Date: Mon, 8 Jun 2009 13:12:23 +0100 Subject: rfkill: don't impose global states on resume (just restore the previous states) Once rfkill-input is disabled, the "global" states will only be used as default initial states. Since the states will always be the same after resume, we shouldn't generate events on resume. Signed-off-by: Alan Jenkins Signed-off-by: John W. Linville --- include/linux/rfkill.h | 7 ++++--- net/rfkill/core.c | 6 +----- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/include/linux/rfkill.h b/include/linux/rfkill.h index c1dca0b8138..16e39c7a67f 100644 --- a/include/linux/rfkill.h +++ b/include/linux/rfkill.h @@ -212,7 +212,7 @@ void rfkill_destroy(struct rfkill *rfkill); * * rfkill drivers that get events when the hard-blocked state changes * use this function to notify the rfkill core (and through that also - * userspace) of the current state -- they should also use this after + * userspace) of the current state. They should also use this after * resume if the state could have changed. * * You need not (but may) call this function if poll_state is assigned. @@ -234,8 +234,9 @@ bool __must_check rfkill_set_hw_state(struct rfkill *rfkill, bool blocked); * rfkill drivers that get events when the soft-blocked state changes * (yes, some platforms directly act on input but allow changing again) * use this function to notify the rfkill core (and through that also - * userspace) of the current state -- they should also use this after - * resume if the state could have changed. + * userspace) of the current state. It is not necessary to notify on + * resume; since hibernation can always change the soft-blocked state, + * the rfkill core will unconditionally restore the previous state. * * This function can be called in any context, even from within rfkill * callbacks. diff --git a/net/rfkill/core.c b/net/rfkill/core.c index fa430bd03f1..4e68ab439d5 100644 --- a/net/rfkill/core.c +++ b/net/rfkill/core.c @@ -728,15 +728,11 @@ static int rfkill_resume(struct device *dev) struct rfkill *rfkill = to_rfkill(dev); bool cur; - mutex_lock(&rfkill_global_mutex); - cur = rfkill_global_states[rfkill->type].cur; + cur = !!(rfkill->state & RFKILL_BLOCK_SW); rfkill_set_block(rfkill, cur); - mutex_unlock(&rfkill_global_mutex); rfkill->suspended = false; - schedule_work(&rfkill->uevent_work); - rfkill_resume_polling(rfkill); return 0; -- cgit v1.2.3 From 403a3a136122457165321e90b7569a321cc9ac12 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Mon, 8 Jun 2009 21:04:57 +0200 Subject: b43: Add fw capabilities Add automagic feature flags, so the firmware can tell the driver about supported features and the driver can switch features on/off as needed. Signed-off-by: Michael Buesch Signed-off-by: Stefan Lippers-Hollmann Tested-by: Stefan Lippers-Hollmann Signed-off-by: John W. Linville --- drivers/net/wireless/b43/b43.h | 14 +++++++++++ drivers/net/wireless/b43/dma.c | 2 +- drivers/net/wireless/b43/main.c | 56 +++++++++++++++++++++++++++++++++-------- drivers/net/wireless/b43/main.h | 1 - drivers/net/wireless/b43/pio.c | 2 +- 5 files changed, 61 insertions(+), 14 deletions(-) diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index 75aede02f93..f580c2812d9 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -163,6 +163,7 @@ enum { #define B43_SHM_SH_WLCOREREV 0x0016 /* 802.11 core revision */ #define B43_SHM_SH_PCTLWDPOS 0x0008 #define B43_SHM_SH_RXPADOFF 0x0034 /* RX Padding data offset (PIO only) */ +#define B43_SHM_SH_FWCAPA 0x0042 /* Firmware capabilities (Opensource firmware only) */ #define B43_SHM_SH_PHYVER 0x0050 /* PHY version */ #define B43_SHM_SH_PHYTYPE 0x0052 /* PHY type */ #define B43_SHM_SH_ANTSWAP 0x005C /* Antenna swap threshold */ @@ -297,6 +298,10 @@ enum { #define B43_HF_MLADVW 0x001000000000ULL /* N PHY ML ADV workaround (rev >= 13 only) */ #define B43_HF_PR45960W 0x080000000000ULL /* PR 45960 workaround (rev >= 13 only) */ +/* Firmware capabilities field in SHM (Opensource firmware only) */ +#define B43_FWCAPA_HWCRYPTO 0x0001 +#define B43_FWCAPA_QOS 0x0002 + /* MacFilter offsets. */ #define B43_MACFILTER_SELF 0x0000 #define B43_MACFILTER_BSSID 0x0003 @@ -596,6 +601,13 @@ struct b43_wl { /* Pointer to the ieee80211 hardware data structure */ struct ieee80211_hw *hw; + /* The number of queues that were registered with the mac80211 subsystem + * initially. This is a backup copy of hw->queues in case hw->queues has + * to be dynamically lowered at runtime (Firmware does not support QoS). + * hw->queues has to be restored to the original value before unregistering + * from the mac80211 subsystem. */ + u16 mac80211_initially_registered_queues; + struct mutex mutex; spinlock_t irq_lock; /* R/W lock for data transmission. @@ -749,6 +761,8 @@ struct b43_wldev { bool dfq_valid; /* Directed frame queue valid (IBSS PS mode, ATIM) */ bool radio_hw_enable; /* saved state of radio hardware enabled state */ bool suspend_in_progress; /* TRUE, if we are in a suspend/resume cycle */ + bool qos_enabled; /* TRUE, if QoS is used. */ + bool hwcrypto_enabled; /* TRUE, if HW crypto acceleration is enabled. */ /* PHY/Radio device. */ struct b43_phy phy; diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c index eae680b5305..7964cc32b25 100644 --- a/drivers/net/wireless/b43/dma.c +++ b/drivers/net/wireless/b43/dma.c @@ -1285,7 +1285,7 @@ static struct b43_dmaring *select_ring_by_priority(struct b43_wldev *dev, { struct b43_dmaring *ring; - if (b43_modparam_qos) { + if (dev->qos_enabled) { /* 0 = highest priority */ switch (queue_prio) { default: diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 5d9f1981f2c..6456afebdba 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -80,8 +80,8 @@ static int modparam_nohwcrypt; module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444); MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); -int b43_modparam_qos = 1; -module_param_named(qos, b43_modparam_qos, int, 0444); +static int modparam_qos = 1; +module_param_named(qos, modparam_qos, int, 0444); MODULE_PARM_DESC(qos, "Enable QOS support (default on)"); static int modparam_btcoex = 1; @@ -538,6 +538,13 @@ void b43_hf_write(struct b43_wldev *dev, u64 value) b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFHI, hi); } +/* Read the firmware capabilities bitmask (Opensource firmware only) */ +static u16 b43_fwcapa_read(struct b43_wldev *dev) +{ + B43_WARN_ON(!dev->fw.opensource); + return b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_FWCAPA); +} + void b43_tsf_read(struct b43_wldev *dev, u64 *tsf) { u32 low, high; @@ -2307,12 +2314,34 @@ static int b43_upload_microcode(struct b43_wldev *dev) dev->fw.patch = fwpatch; dev->fw.opensource = (fwdate == 0xFFFF); + /* Default to use-all-queues. */ + dev->wl->hw->queues = dev->wl->mac80211_initially_registered_queues; + dev->qos_enabled = !!modparam_qos; + /* Default to firmware/hardware crypto acceleration. */ + dev->hwcrypto_enabled = 1; + if (dev->fw.opensource) { + u16 fwcapa; + /* Patchlevel info is encoded in the "time" field. */ dev->fw.patch = fwtime; - b43info(dev->wl, "Loading OpenSource firmware version %u.%u%s\n", - dev->fw.rev, dev->fw.patch, - dev->fw.pcm_request_failed ? " (Hardware crypto not supported)" : ""); + b43info(dev->wl, "Loading OpenSource firmware version %u.%u\n", + dev->fw.rev, dev->fw.patch); + + fwcapa = b43_fwcapa_read(dev); + if (!(fwcapa & B43_FWCAPA_HWCRYPTO) || dev->fw.pcm_request_failed) { + b43info(dev->wl, "Hardware crypto acceleration not supported by firmware\n"); + /* Disable hardware crypto and fall back to software crypto. */ + dev->hwcrypto_enabled = 0; + } + if (!(fwcapa & B43_FWCAPA_QOS)) { + b43info(dev->wl, "QoS not supported by firmware\n"); + /* Disable QoS. Tweak hw->queues to 1. It will be restored before + * ieee80211_unregister to make sure the networking core can + * properly free possible resources. */ + dev->wl->hw->queues = 1; + dev->qos_enabled = 0; + } } else { b43info(dev->wl, "Loading firmware version %u.%u " "(20%.2i-%.2i-%.2i %.2i:%.2i:%.2i)\n", @@ -3627,7 +3656,7 @@ static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, if (!dev || b43_status(dev) < B43_STAT_INITIALIZED) goto out_unlock; - if (dev->fw.pcm_request_failed) { + if (dev->fw.pcm_request_failed || !dev->hwcrypto_enabled) { /* We don't have firmware for the crypto engine. * Must use software-crypto. */ err = -EOPNOTSUPP; @@ -4727,6 +4756,7 @@ static int b43_wireless_init(struct ssb_device *dev) b43err(NULL, "Could not allocate ieee80211 device\n"); goto out; } + wl = hw_to_b43_wl(hw); /* fill hw info */ hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | @@ -4740,7 +4770,8 @@ static int b43_wireless_init(struct ssb_device *dev) BIT(NL80211_IFTYPE_WDS) | BIT(NL80211_IFTYPE_ADHOC); - hw->queues = b43_modparam_qos ? 4 : 1; + hw->queues = modparam_qos ? 4 : 1; + wl->mac80211_initially_registered_queues = hw->queues; hw->max_rates = 2; SET_IEEE80211_DEV(hw, dev->dev); if (is_valid_ether_addr(sprom->et1mac)) @@ -4748,9 +4779,7 @@ static int b43_wireless_init(struct ssb_device *dev) else SET_IEEE80211_PERM_ADDR(hw, sprom->il0mac); - /* Get and initialize struct b43_wl */ - wl = hw_to_b43_wl(hw); - memset(wl, 0, sizeof(*wl)); + /* Initialize struct b43_wl */ wl->hw = hw; spin_lock_init(&wl->irq_lock); rwlock_init(&wl->tx_lock); @@ -4816,8 +4845,13 @@ static void b43_remove(struct ssb_device *dev) cancel_work_sync(&wldev->restart_work); B43_WARN_ON(!wl); - if (wl->current_dev == wldev) + if (wl->current_dev == wldev) { + /* Restore the queues count before unregistering, because firmware detect + * might have modified it. Restoring is important, so the networking + * stack can properly free resources. */ + wl->hw->queues = wl->mac80211_initially_registered_queues; ieee80211_unregister_hw(wl->hw); + } b43_one_core_detach(dev); diff --git a/drivers/net/wireless/b43/main.h b/drivers/net/wireless/b43/main.h index 40abcf5d1b4..950fb1b0546 100644 --- a/drivers/net/wireless/b43/main.h +++ b/drivers/net/wireless/b43/main.h @@ -39,7 +39,6 @@ #define PAD_BYTES(nr_bytes) P4D_BYTES( __LINE__ , (nr_bytes)) -extern int b43_modparam_qos; extern int b43_modparam_verbose; /* Logmessage verbosity levels. Update the b43_modparam_verbose helptext, if diff --git a/drivers/net/wireless/b43/pio.c b/drivers/net/wireless/b43/pio.c index 8cd9776752e..69138e8c1db 100644 --- a/drivers/net/wireless/b43/pio.c +++ b/drivers/net/wireless/b43/pio.c @@ -313,7 +313,7 @@ static struct b43_pio_txqueue *select_queue_by_priority(struct b43_wldev *dev, { struct b43_pio_txqueue *q; - if (b43_modparam_qos) { + if (dev->qos_enabled) { /* 0 = highest priority */ switch (queue_prio) { default: -- cgit v1.2.3 From 558f6d3229ddb9f11ca4ffee0439046c283882ff Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 8 Jun 2009 18:54:37 -0700 Subject: cfg80211: fix for duplicate response for driver reg request As Pavel puts userspace can be stupid and should not cause kernel crashes. In this case Pavel was able to find a crash here but unable to reproduce. Either way lets deal with this. This should fix: ------------[ cut here ]------------ kernel BUG at /home/proski/src/linux-2.6/net/wireless/reg.c:2132! Oops: Exception in kernel mode, sig: 5 [#1] PowerMac Modules linked in: ath5k ath [last unloaded: scsi_wait_scan] NIP: c02f3eac LR: c02f3d08 CTR: 00000000 REGS: ef107aa0 TRAP: 0700 Not tainted (2.6.30-rc8-wl) MSR: 00029032 CR: 88002442 XER: 20000000 TASK = ef84acb0[834] 'crda' THREAD: ef106000 GPR00: ef953840 ef107b50 ef84acb0 ef1380bc 00000006 c035a5c8 ef107b90 c035a5c8 GPR08: 00080005 efb68980 c0445628 ef130004 28002422 10019ce0 10012d3c 00000001 GPR16: 1070b2ac 00000005 48023558 1070b380 4802304c 00000000 ef107ddc c035a5c8 GPR24: ef107b78 c0443350 ef8bcb00 00000005 ef138080 c04a6a70 c04a0000 ef8bcb00 NIP [c02f3eac] set_regdom+0x4c4/0x4ec LR [c02f3d08] set_regdom+0x320/0x4ec Call Trace: [ef107b50] [c02f3d08] set_regdom+0x320/0x4ec (unreliable) [ef107b70] [c02f9d10] nl80211_set_reg+0x140/0x2d0 [ef107bc0] [c02aa2b8] genl_rcv_msg+0x204/0x228 [ef107c10] [c02a97cc] netlink_rcv_skb+0xe8/0x10c [ef107c30] [c02aa094] genl_rcv+0x3c/0x5c [ef107c40] [c02a9050] netlink_unicast+0x308/0x36c [ef107c80] [c02a92bc] netlink_sendmsg+0x208/0x2f0 [ef107cd0] [c0282048] sock_sendmsg+0xac/0xe4 [ef107db0] [c02822b4] sys_sendmsg+0x234/0x2d8 [ef107f00] [c0283a88] sys_socketcall+0x108/0x258 [ef107f40] [c0012790] ret_from_syscall+0x0/0x38 Signed-off-by: John W. Linville --- net/wireless/reg.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/net/wireless/reg.c b/net/wireless/reg.c index ea4c299fbe3..5e14371cda7 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -2129,7 +2129,12 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) * driver wanted to the wiphy to deal with conflicts */ - BUG_ON(request_wiphy->regd); + /* + * Userspace could have sent two replies with only + * one kernel request. + */ + if (request_wiphy->regd) + return -EALREADY; r = reg_copy_regd(&request_wiphy->regd, rd); if (r) -- cgit v1.2.3 From 736708bd04b7a8941fddda32211982cab5d14431 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Tue, 9 Jun 2009 14:11:46 +0530 Subject: mac80211: Fix the way ADDBA request count being modified addba_req_num[tid] is supposed to have the count of consecutive addba request attempts on 'tid' which failed. This count is checked against a retry threshold (3 times) before starting the addba negotiation. This patch fixes the way this addba count is incremented/reset and thereby avoids indefinite addba attempts. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville --- net/mac80211/agg-tx.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index 43d00ffd398..9e5762ad307 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c @@ -132,6 +132,9 @@ static int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, state = &sta->ampdu_mlme.tid_state_tx[tid]; + if (*state == HT_AGG_STATE_OPERATIONAL) + sta->ampdu_mlme.addba_req_num[tid] = 0; + *state = HT_AGG_STATE_REQ_STOP_BA_MSK | (initiator << HT_AGG_STATE_INITIATOR_SHIFT); @@ -337,6 +340,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) sta->ampdu_mlme.tid_tx[tid]->dialog_token, sta->ampdu_mlme.tid_tx[tid]->ssn, 0x40, 5000); + sta->ampdu_mlme.addba_req_num[tid]++; /* activate the timer for the recipient's addBA response */ sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.expires = jiffies + ADDBA_RESP_INTERVAL; @@ -606,7 +610,6 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid) *state = HT_AGG_STATE_IDLE; /* from now on packets are no longer put onto sta->pending */ - sta->ampdu_mlme.addba_req_num[tid] = 0; kfree(sta->ampdu_mlme.tid_tx[tid]); sta->ampdu_mlme.tid_tx[tid] = NULL; @@ -689,7 +692,6 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local, sta->ampdu_mlme.addba_req_num[tid] = 0; } else { - sta->ampdu_mlme.addba_req_num[tid]++; ___ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_INITIATOR); } spin_unlock_bh(&sta->lock); -- cgit v1.2.3 From 5eae6592e9bdc989151171828ee97e0ad9e1b1ac Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Tue, 9 Jun 2009 15:28:21 +0530 Subject: ath9k: Fix tx stuck when connected to aggr disabled HT AP This patch along with my previous patch in mac80211 "Fix the way ADDBA count..", fixes hang in tx when connected to an HT AP which rejects/times out on addba req. AGGR_ADDBA_PROGRESS should be cleared in aggr state when addba negotiation is terminated due to either addba response is timed out or addba is denied by the AP. With out clearing this bit, all frames are queued onto s/w queue for getting tx'd as aggr and will never be scheduled onto hw queue. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/xmit.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index a8def4fa449..b61a071788a 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -711,6 +711,7 @@ int ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) return 0; if (!(txtid->state & AGGR_ADDBA_COMPLETE)) { + txtid->state &= ~AGGR_ADDBA_PROGRESS; txtid->addba_exchangeattempts = 0; return 0; } -- cgit v1.2.3 From 0bffe40f21e2ddc5215b1faec4e8dbbc215e7d4d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 9 Jun 2009 16:18:32 +0200 Subject: mac80211: don't use master netdev name Always use the wiphy name instead. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/cfg.c | 4 ++-- net/mac80211/mlme.c | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index a9211cc183c..3f47276caeb 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1122,8 +1122,8 @@ static int ieee80211_set_txq_params(struct wiphy *wiphy, p.txop = params->txop; if (drv_conf_tx(local, params->queue, &p)) { printk(KERN_DEBUG "%s: failed to set TX queue " - "parameters for queue %d\n", local->mdev->name, - params->queue); + "parameters for queue %d\n", + wiphy_name(local->hw.wiphy), params->queue); return -EINVAL; } diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 509469cb926..e8a3d3cb80d 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -793,13 +793,13 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local, #ifdef CONFIG_MAC80211_VERBOSE_DEBUG printk(KERN_DEBUG "%s: WMM queue=%d aci=%d acm=%d aifs=%d " "cWmin=%d cWmax=%d txop=%d\n", - local->mdev->name, queue, aci, acm, params.aifs, params.cw_min, - params.cw_max, params.txop); + wiphy_name(local->hw.wiphy), queue, aci, acm, + params.aifs, params.cw_min, params.cw_max, params.txop); #endif if (drv_conf_tx(local, queue, ¶ms) && local->ops->conf_tx) printk(KERN_DEBUG "%s: failed to set TX queue " - "parameters for queue %d\n", local->mdev->name, - queue); + "parameters for queue %d\n", + wiphy_name(local->hw.wiphy), queue); } } -- cgit v1.2.3 From 27004b10ce56985d8a010ce966af179f1b34193f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 9 Jun 2009 19:48:25 +0200 Subject: mac80211: clean up return value of __ieee80211_parse_tx_radiotap The return type has more than two values, but it can validly only ever return TX_DROP and TX_CONTINUE, so use a bool instead of ieee80211_tx_result. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/tx.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index bfaa9ce3314..1aed88d922d 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -908,9 +908,8 @@ ieee80211_tx_h_stats(struct ieee80211_tx_data *tx) * deal with packet injection down monitor interface * with Radiotap Header -- only called for monitor mode interface */ -static ieee80211_tx_result -__ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, - struct sk_buff *skb) +static bool __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, + struct sk_buff *skb) { /* * this is the moment to interpret and discard the radiotap header that @@ -961,7 +960,7 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, * on transmission */ if (skb->len < (iterator.max_length + FCS_LEN)) - return TX_DROP; + return false; skb_trim(skb, skb->len - FCS_LEN); } @@ -983,7 +982,7 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, } if (ret != -ENOENT) /* ie, if we didn't simply run out of fields */ - return TX_DROP; + return false; /* * remove the radiotap header @@ -992,7 +991,7 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, */ skb_pull(skb, iterator.max_length); - return TX_CONTINUE; + return true; } /* @@ -1026,7 +1025,7 @@ __ieee80211_tx_prepare(struct ieee80211_tx_data *tx, /* process and remove the injection radiotap header */ sdata = IEEE80211_DEV_TO_SUB_IF(dev); if (unlikely(info->flags & IEEE80211_TX_CTL_INJECTED)) { - if (__ieee80211_parse_tx_radiotap(tx, skb) == TX_DROP) + if (!__ieee80211_parse_tx_radiotap(tx, skb)) return TX_DROP; /* -- cgit v1.2.3 From a6ae0716e5c3b5f9dbe5ed8f473a6c7b89692365 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Tue, 9 Jun 2009 23:43:11 -0400 Subject: ath5k: minor rfkill cleanup Always enable rfkill since the ifdefs in the code is not really worth the Kconfig option. Also fix a few code style things, and remove the usage of the ah_gpio[] array so we can remove it later. Signed-off-by: Bob Copeland Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/Kconfig | 8 -------- drivers/net/wireless/ath/ath5k/Makefile | 2 +- drivers/net/wireless/ath/ath5k/ath5k.h | 5 ----- drivers/net/wireless/ath/ath5k/base.c | 5 +---- drivers/net/wireless/ath/ath5k/base.h | 2 -- drivers/net/wireless/ath/ath5k/rfkill.c | 12 ++++++------ 6 files changed, 8 insertions(+), 26 deletions(-) diff --git a/drivers/net/wireless/ath/ath5k/Kconfig b/drivers/net/wireless/ath/ath5k/Kconfig index 4863f4bbf76..509b6f94f73 100644 --- a/drivers/net/wireless/ath/ath5k/Kconfig +++ b/drivers/net/wireless/ath/ath5k/Kconfig @@ -39,11 +39,3 @@ config ATH5K_DEBUG modprobe ath5k debug=0x00000400 -config ATH5K_RFKILL - bool "Atheros 5xxx rfkill support" - depends on ATH5K - default y - ---help--- - Include support for enabling/disabling WiFi via rfkill switch - with Atheros 5xxx cards - diff --git a/drivers/net/wireless/ath/ath5k/Makefile b/drivers/net/wireless/ath/ath5k/Makefile index f1e281c5a21..090dc6d268a 100644 --- a/drivers/net/wireless/ath/ath5k/Makefile +++ b/drivers/net/wireless/ath/ath5k/Makefile @@ -11,6 +11,6 @@ ath5k-y += reset.o ath5k-y += attach.o ath5k-y += base.o ath5k-y += led.o +ath5k-y += rfkill.o ath5k-$(CONFIG_ATH5K_DEBUG) += debug.o -ath5k-$(CONFIG_ATH5K_RFKILL) += rfkill.o obj-$(CONFIG_ATH5K) += ath5k.o diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index 4c84e308763..6358233bac9 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -1257,13 +1257,8 @@ extern int ath5k_hw_set_gpio(struct ath5k_hw *ah, u32 gpio, u32 val); extern void ath5k_hw_set_gpio_intr(struct ath5k_hw *ah, unsigned int gpio, u32 interrupt_level); /* rfkill Functions */ -#ifdef CONFIG_ATH5K_RFKILL extern void ath5k_rfkill_hw_start(struct ath5k_hw *ah); extern void ath5k_rfkill_hw_stop(struct ath5k_hw *ah); -#else -static inline void ath5k_rfkill_hw_start(struct ath5k_hw *ah) {} -static inline void ath5k_rfkill_hw_stop(struct ath5k_hw *ah) {} -#endif /* Misc functions */ int ath5k_hw_set_capabilities(struct ath5k_hw *ah); diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index f55675c23f2..55f7de09d13 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -2530,12 +2530,9 @@ ath5k_intr(int irq, void *dev_id) */ ath5k_hw_update_mib_counters(ah, &sc->ll_stats); } -#ifdef CONFIG_ATH5K_RFKILL if (status & AR5K_INT_GPIO) - { tasklet_schedule(&sc->rf_kill.toggleq); - } -#endif + } } while (ath5k_hw_is_intr_pending(ah) && --counter > 0); diff --git a/drivers/net/wireless/ath/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h index 7a0ecdd9c25..f9b7f2f819b 100644 --- a/drivers/net/wireless/ath/ath5k/base.h +++ b/drivers/net/wireless/ath/ath5k/base.h @@ -177,9 +177,7 @@ struct ath5k_softc { struct tasklet_struct txtq; /* tx intr tasklet */ struct ath5k_led tx_led; /* tx led */ -#ifdef CONFIG_ATH5K_RFKILL struct ath5k_rfkill rf_kill; -#endif spinlock_t block; /* protects beacon */ struct tasklet_struct beacontq; /* beacon intr tasklet */ diff --git a/drivers/net/wireless/ath/ath5k/rfkill.c b/drivers/net/wireless/ath/ath5k/rfkill.c index 492ada92db5..41a877b73fc 100644 --- a/drivers/net/wireless/ath/ath5k/rfkill.c +++ b/drivers/net/wireless/ath/ath5k/rfkill.c @@ -56,10 +56,12 @@ static inline void ath5k_rfkill_enable(struct ath5k_softc *sc) static inline void ath5k_rfkill_set_intr(struct ath5k_softc *sc, bool enable) { struct ath5k_hw *ah = sc->ah; + u32 curval; + ath5k_hw_set_gpio_input(ah, sc->rf_kill.gpio); - ah->ah_gpio[0] = ath5k_hw_get_gpio(ah, sc->rf_kill.gpio); + curval = ath5k_hw_get_gpio(ah, sc->rf_kill.gpio); ath5k_hw_set_gpio_intr(ah, sc->rf_kill.gpio, enable ? - !!ah->ah_gpio[0] : !ah->ah_gpio[0]); + !!curval : !curval); } static bool @@ -97,9 +99,8 @@ ath5k_rfkill_hw_start(struct ath5k_hw *ah) ath5k_rfkill_disable(sc); /* enable interrupt for rfkill switch */ - if (AR5K_EEPROM_HDR_RFKILL(ah->ah_capabilities.cap_eeprom.ee_header)) { + if (AR5K_EEPROM_HDR_RFKILL(ah->ah_capabilities.cap_eeprom.ee_header)) ath5k_rfkill_set_intr(sc, true); - } } @@ -109,9 +110,8 @@ ath5k_rfkill_hw_stop(struct ath5k_hw *ah) struct ath5k_softc *sc = ah->ah_sc; /* disable interrupt for rfkill switch */ - if (AR5K_EEPROM_HDR_RFKILL(ah->ah_capabilities.cap_eeprom.ee_header)) { + if (AR5K_EEPROM_HDR_RFKILL(ah->ah_capabilities.cap_eeprom.ee_header)) ath5k_rfkill_set_intr(sc, false); - } tasklet_kill(&sc->rf_kill.toggleq); -- cgit v1.2.3 From 43f7853180ed522944b3b1d4979cdb9f2b103ca3 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 10 Jun 2009 15:16:15 +0200 Subject: mac80211: disable moving between PS modes during scan We don't want to trigger moving between PS mode during scan, because then we will sometimes end up sending nullfunc frames during scan. We're supposed to only send one prior to scan and after scan. This fixes an oops which occured due to an assert in ath9k: http://marc.info/?l=linux-wireless&m=124277331319024 The assert was happening because the rate control algorithm figures it should find at least one valid dual stream or single stream rate. Since we allow mac80211 to send nullfunc frames during scan and dynamic PS was enabled at times we ended up trying to send nullfunc frames for the target sta on the wrong band for which we have no valid rate to communicate with it. This breaks the assumptions in rate control. We determine we also need to disable moving between PS modes when not associated so lets just add that now as well, and we should not have a ps_sdata when that interface cannot actually go into PS because it's not associated. Signed-off-by: Luis R. Rodriguez Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/mlme.c | 6 ++---- net/mac80211/tx.c | 3 ++- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index e8a3d3cb80d..898e9b02aaa 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -621,9 +621,6 @@ static void ieee80211_change_ps(struct ieee80211_local *local) struct ieee80211_conf *conf = &local->hw.conf; if (local->ps_sdata) { - if (!(local->ps_sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED)) - return; - ieee80211_enable_ps(local, local->ps_sdata); } else if (conf->flags & IEEE80211_CONF_PS) { conf->flags &= ~IEEE80211_CONF_PS; @@ -653,7 +650,8 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency) count++; } - if (count == 1 && found->u.mgd.powersave) { + if (count == 1 && found->u.mgd.powersave && + (found->u.mgd.flags & IEEE80211_STA_ASSOCIATED)) { s32 beaconint_us; if (latency < 0) diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 1aed88d922d..364222bfb10 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1415,7 +1415,8 @@ int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev) } if ((local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) && - local->hw.conf.dynamic_ps_timeout > 0) { + local->hw.conf.dynamic_ps_timeout > 0 && + !local->sw_scanning && !local->hw_scanning && local->ps_sdata) { if (local->hw.conf.flags & IEEE80211_CONF_PS) { ieee80211_stop_queues_by_reason(&local->hw, IEEE80211_QUEUE_STOP_REASON_PS); -- cgit v1.2.3 From 4e751843d406a4d0471c207872b9e24957de8357 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 10 Jun 2009 15:16:52 +0200 Subject: mac80211: disable PS while probing AP When associated, but probing the AP because we detected beacon loss, we need to disable powersave to be able to receive the probe response. Change the code to do that by checking whether we're trying to probe when determining the possibility of going into PS, and recalculate the PS ability at the necessary spots. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/mlme.c | 45 +++++++++++++++++++++++++++++++++------------ 1 file changed, 33 insertions(+), 12 deletions(-) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 898e9b02aaa..d779c57a822 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -651,7 +651,8 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency) } if (count == 1 && found->u.mgd.powersave && - (found->u.mgd.flags & IEEE80211_STA_ASSOCIATED)) { + (found->u.mgd.flags & IEEE80211_STA_ASSOCIATED) && + !(found->u.mgd.flags & IEEE80211_STA_PROBEREQ_POLL)) { s32 beaconint_us; if (latency < 0) @@ -1320,6 +1321,11 @@ void ieee80211_beacon_loss_work(struct work_struct *work) #endif ifmgd->flags |= IEEE80211_STA_PROBEREQ_POLL; + + mutex_lock(&sdata->local->iflist_mtx); + ieee80211_recalc_ps(sdata->local, -1); + mutex_unlock(&sdata->local->iflist_mtx); + ieee80211_send_probe_req(sdata, ifmgd->bssid, ifmgd->ssid, ifmgd->ssid_len, NULL, 0); @@ -1340,6 +1346,7 @@ static void ieee80211_associated(struct ieee80211_sub_if_data *sdata) struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_local *local = sdata->local; struct sta_info *sta; + unsigned long last_rx; bool disassoc = false; /* TODO: start monitoring current AP signal quality and number of @@ -1356,17 +1363,21 @@ static void ieee80211_associated(struct ieee80211_sub_if_data *sdata) printk(KERN_DEBUG "%s: No STA entry for own AP %pM\n", sdata->dev->name, ifmgd->bssid); disassoc = true; - goto unlock; + rcu_read_unlock(); + goto out; } + last_rx = sta->last_rx; + rcu_read_unlock(); + if ((ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) && - time_after(jiffies, sta->last_rx + IEEE80211_PROBE_WAIT)) { + time_after(jiffies, last_rx + IEEE80211_PROBE_WAIT)) { printk(KERN_DEBUG "%s: no probe response from AP %pM " "- disassociating\n", sdata->dev->name, ifmgd->bssid); disassoc = true; ifmgd->flags &= ~IEEE80211_STA_PROBEREQ_POLL; - goto unlock; + goto out; } /* @@ -1385,26 +1396,29 @@ static void ieee80211_associated(struct ieee80211_sub_if_data *sdata) } #endif ifmgd->flags |= IEEE80211_STA_PROBEREQ_POLL; + mutex_lock(&local->iflist_mtx); + ieee80211_recalc_ps(local, -1); + mutex_unlock(&local->iflist_mtx); ieee80211_send_probe_req(sdata, ifmgd->bssid, ifmgd->ssid, ifmgd->ssid_len, NULL, 0); mod_timer(&ifmgd->timer, jiffies + IEEE80211_PROBE_WAIT); - goto unlock; + goto out; } - if (time_after(jiffies, sta->last_rx + IEEE80211_PROBE_IDLE_TIME)) { + if (time_after(jiffies, last_rx + IEEE80211_PROBE_IDLE_TIME)) { ifmgd->flags |= IEEE80211_STA_PROBEREQ_POLL; + mutex_lock(&local->iflist_mtx); + ieee80211_recalc_ps(local, -1); + mutex_unlock(&local->iflist_mtx); ieee80211_send_probe_req(sdata, ifmgd->bssid, ifmgd->ssid, ifmgd->ssid_len, NULL, 0); } + out: if (!disassoc) mod_timer(&ifmgd->timer, jiffies + IEEE80211_MONITORING_INTERVAL); - - unlock: - rcu_read_unlock(); - - if (disassoc) + else ieee80211_set_disassoc(sdata, true, true, WLAN_REASON_PREV_AUTH_NOT_VALID); } @@ -1887,8 +1901,12 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, ieee80211_authenticate(sdata); } - if (ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) + if (ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) { ifmgd->flags &= ~IEEE80211_STA_PROBEREQ_POLL; + mutex_lock(&sdata->local->iflist_mtx); + ieee80211_recalc_ps(sdata->local, -1); + mutex_unlock(&sdata->local->iflist_mtx); + } } /* @@ -1946,6 +1964,9 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, } #endif ifmgd->flags &= ~IEEE80211_STA_PROBEREQ_POLL; + mutex_lock(&local->iflist_mtx); + ieee80211_recalc_ps(local, -1); + mutex_unlock(&local->iflist_mtx); } ncrc = crc32_be(0, (void *)&mgmt->u.beacon.beacon_int, 4); -- cgit v1.2.3 From 2f0accc13520b2644b85f80aedce10d10d88b0ca Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 10 Jun 2009 16:50:29 +0200 Subject: cfg80211: fix rfkill locking problem rfkill currently requires a global lock within the rfkill_register() function, and holds that lock over calls to the set_block() methods. This means that we cannot hold a lock around rfkill_register() that we also require in set_block(), directly or indirectly. Fix cfg80211 to register rfkill outside the block locked by its global lock. Much of what cfg80211 does in the locked block doesn't need to be locked anyway. Reported-by: Vasanthakumar Thiagarajan Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/wireless/core.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/net/wireless/core.c b/net/wireless/core.c index 3b74b88e10a..d5850292b3d 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -395,21 +395,23 @@ int wiphy_register(struct wiphy *wiphy) /* check and set up bitrates */ ieee80211_set_bitrate_flags(wiphy); - mutex_lock(&cfg80211_mutex); - - /* set up regulatory info */ - wiphy_update_regulatory(wiphy, NL80211_REGDOM_SET_BY_CORE); - res = device_add(&drv->wiphy.dev); if (res) - goto out_unlock; + return res; res = rfkill_register(drv->rfkill); if (res) goto out_rm_dev; + mutex_lock(&cfg80211_mutex); + + /* set up regulatory info */ + wiphy_update_regulatory(wiphy, NL80211_REGDOM_SET_BY_CORE); + list_add(&drv->list, &cfg80211_drv_list); + mutex_unlock(&cfg80211_mutex); + /* add to debugfs */ drv->wiphy.debugfsdir = debugfs_create_dir(wiphy_name(&drv->wiphy), @@ -430,13 +432,10 @@ int wiphy_register(struct wiphy *wiphy) cfg80211_debugfs_drv_add(drv); - res = 0; - goto out_unlock; + return 0; out_rm_dev: device_del(&drv->wiphy.dev); - out_unlock: - mutex_unlock(&cfg80211_mutex); return res; } EXPORT_SYMBOL(wiphy_register); -- cgit v1.2.3