diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-agn.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn.c | 582 |
1 files changed, 314 insertions, 268 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index c1cfd9952e5..581dc9f1027 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -59,6 +59,7 @@ #include "iwl-sta.h" #include "iwl-agn-calib.h" #include "iwl-agn.h" +#include "iwl-agn-led.h" /****************************************************************************** @@ -85,7 +86,6 @@ MODULE_DESCRIPTION(DRV_DESCRIPTION); MODULE_VERSION(DRV_VERSION); MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR); MODULE_LICENSE("GPL"); -MODULE_ALIAS("iwl4965"); static int iwlagn_ant_coupling; static bool iwlagn_bt_ch_announce = 1; @@ -424,47 +424,6 @@ int iwl_hw_tx_queue_init(struct iwl_priv *priv, return 0; } -/****************************************************************************** - * - * Generic RX handler implementations - * - ******************************************************************************/ -static void iwl_rx_reply_alive(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) -{ - struct iwl_rx_packet *pkt = rxb_addr(rxb); - struct iwl_alive_resp *palive; - struct delayed_work *pwork; - - palive = &pkt->u.alive_frame; - - IWL_DEBUG_INFO(priv, "Alive ucode status 0x%08X revision " - "0x%01X 0x%01X\n", - palive->is_valid, palive->ver_type, - palive->ver_subtype); - - if (palive->ver_subtype == INITIALIZE_SUBTYPE) { - IWL_DEBUG_INFO(priv, "Initialization Alive received.\n"); - memcpy(&priv->card_alive_init, - &pkt->u.alive_frame, - sizeof(struct iwl_init_alive_resp)); - pwork = &priv->init_alive_start; - } else { - IWL_DEBUG_INFO(priv, "Runtime Alive received.\n"); - memcpy(&priv->card_alive, &pkt->u.alive_frame, - sizeof(struct iwl_alive_resp)); - pwork = &priv->alive_start; - } - - /* We delay the ALIVE response by 5ms to - * give the HW RF Kill time to activate... */ - if (palive->is_valid == UCODE_VALID_OK) - queue_delayed_work(priv->workqueue, pwork, - msecs_to_jiffies(5)); - else - IWL_WARN(priv, "uCode did not respond OK.\n"); -} - static void iwl_bg_beacon_update(struct work_struct *work) { struct iwl_priv *priv = @@ -699,83 +658,6 @@ static void iwl_bg_ucode_trace(unsigned long data) } } -static void iwl_rx_beacon_notif(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) -{ - struct iwl_rx_packet *pkt = rxb_addr(rxb); - struct iwl4965_beacon_notif *beacon = - (struct iwl4965_beacon_notif *)pkt->u.raw; -#ifdef CONFIG_IWLWIFI_DEBUG - u8 rate = iwl_hw_get_rate(beacon->beacon_notify_hdr.rate_n_flags); - - IWL_DEBUG_RX(priv, "beacon status %x retries %d iss %d " - "tsf %d %d rate %d\n", - le32_to_cpu(beacon->beacon_notify_hdr.u.status) & TX_STATUS_MSK, - beacon->beacon_notify_hdr.failure_frame, - le32_to_cpu(beacon->ibss_mgr_status), - le32_to_cpu(beacon->high_tsf), - le32_to_cpu(beacon->low_tsf), rate); -#endif - - priv->ibss_manager = le32_to_cpu(beacon->ibss_mgr_status); - - if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) - queue_work(priv->workqueue, &priv->beacon_update); -} - -/* Handle notification from uCode that card's power state is changing - * due to software, hardware, or critical temperature RFKILL */ -static void iwl_rx_card_state_notif(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) -{ - struct iwl_rx_packet *pkt = rxb_addr(rxb); - u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags); - unsigned long status = priv->status; - - IWL_DEBUG_RF_KILL(priv, "Card state received: HW:%s SW:%s CT:%s\n", - (flags & HW_CARD_DISABLED) ? "Kill" : "On", - (flags & SW_CARD_DISABLED) ? "Kill" : "On", - (flags & CT_CARD_DISABLED) ? - "Reached" : "Not reached"); - - if (flags & (SW_CARD_DISABLED | HW_CARD_DISABLED | - CT_CARD_DISABLED)) { - - iwl_write32(priv, CSR_UCODE_DRV_GP1_SET, - CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); - - iwl_write_direct32(priv, HBUS_TARG_MBX_C, - HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED); - - if (!(flags & RXON_CARD_DISABLED)) { - iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, - CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); - iwl_write_direct32(priv, HBUS_TARG_MBX_C, - HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED); - } - if (flags & CT_CARD_DISABLED) - iwl_tt_enter_ct_kill(priv); - } - if (!(flags & CT_CARD_DISABLED)) - iwl_tt_exit_ct_kill(priv); - - if (flags & HW_CARD_DISABLED) - set_bit(STATUS_RF_KILL_HW, &priv->status); - else - clear_bit(STATUS_RF_KILL_HW, &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))) - wiphy_rfkill_set_hw_state(priv->hw->wiphy, - test_bit(STATUS_RF_KILL_HW, &priv->status)); - else - wake_up_interruptible(&priv->wait_command_queue); -} - static void iwl_bg_tx_flush(struct work_struct *work) { struct iwl_priv *priv = @@ -795,58 +677,13 @@ static void iwl_bg_tx_flush(struct work_struct *work) } /** - * iwl_setup_rx_handlers - Initialize Rx handler callbacks - * - * Setup the RX handlers for each of the reply types sent from the uCode - * to the host. - * - * This function chains into the hardware specific files for them to setup - * any hardware specific handlers as well. - */ -static void iwl_setup_rx_handlers(struct iwl_priv *priv) -{ - priv->rx_handlers[REPLY_ALIVE] = iwl_rx_reply_alive; - priv->rx_handlers[REPLY_ERROR] = iwl_rx_reply_error; - priv->rx_handlers[CHANNEL_SWITCH_NOTIFICATION] = iwl_rx_csa; - priv->rx_handlers[SPECTRUM_MEASURE_NOTIFICATION] = - iwl_rx_spectrum_measure_notif; - priv->rx_handlers[PM_SLEEP_NOTIFICATION] = iwl_rx_pm_sleep_notif; - priv->rx_handlers[PM_DEBUG_STATISTIC_NOTIFIC] = - iwl_rx_pm_debug_statistics_notif; - priv->rx_handlers[BEACON_NOTIFICATION] = iwl_rx_beacon_notif; - - /* - * The same handler is used for both the REPLY to a discrete - * statistics request from the host as well as for the periodic - * statistics notifications (after received beacons) from the uCode. - */ - priv->rx_handlers[REPLY_STATISTICS_CMD] = iwl_reply_statistics; - priv->rx_handlers[STATISTICS_NOTIFICATION] = iwl_rx_statistics; - - iwl_setup_rx_scan_handlers(priv); - - /* status change handler */ - priv->rx_handlers[CARD_STATE_NOTIFICATION] = iwl_rx_card_state_notif; - - priv->rx_handlers[MISSED_BEACONS_NOTIFICATION] = - iwl_rx_missed_beacon_notif; - /* Rx handlers */ - priv->rx_handlers[REPLY_RX_PHY_CMD] = iwlagn_rx_reply_rx_phy; - priv->rx_handlers[REPLY_RX_MPDU_CMD] = iwlagn_rx_reply_rx; - /* block ack */ - priv->rx_handlers[REPLY_COMPRESSED_BA] = iwlagn_rx_reply_compressed_ba; - /* Set up hardware specific Rx handlers */ - priv->cfg->ops->lib->rx_handler_setup(priv); -} - -/** * iwl_rx_handle - Main entry function for receiving responses from uCode * * Uses the priv->rx_handlers callback function array to invoke * the appropriate handlers, including command responses, * frame-received notifications, and other notifications. */ -void iwl_rx_handle(struct iwl_priv *priv) +static void iwl_rx_handle(struct iwl_priv *priv) { struct iwl_rx_mem_buffer *rxb; struct iwl_rx_packet *pkt; @@ -910,6 +747,27 @@ void iwl_rx_handle(struct iwl_priv *priv) (pkt->hdr.cmd != STATISTICS_NOTIFICATION) && (pkt->hdr.cmd != REPLY_TX); + /* + * Do the notification wait before RX handlers so + * even if the RX handler consumes the RXB we have + * access to it in the notification wait entry. + */ + if (!list_empty(&priv->_agn.notif_waits)) { + struct iwl_notification_wait *w; + + spin_lock(&priv->_agn.notif_wait_lock); + list_for_each_entry(w, &priv->_agn.notif_waits, list) { + if (w->cmd == pkt->hdr.cmd) { + w->triggered = true; + if (w->fn) + w->fn(priv, pkt); + } + } + spin_unlock(&priv->_agn.notif_wait_lock); + + wake_up_all(&priv->_agn.notif_waitq); + } + /* Based on type of command response or notification, * handle those that need handling via function in * rx_handlers table. See iwl_setup_rx_handlers() */ @@ -1379,66 +1237,6 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) iwl_enable_rfkill_int(priv); } -/* the threshold ratio of actual_ack_cnt to expected_ack_cnt in percent */ -#define ACK_CNT_RATIO (50) -#define BA_TIMEOUT_CNT (5) -#define BA_TIMEOUT_MAX (16) - -/** - * iwl_good_ack_health - checks for ACK count ratios, BA timeout retries. - * - * When the ACK count ratio is 0 and aggregated BA timeout retries exceeding - * the BA_TIMEOUT_MAX, reload firmware and bring system back to normal - * operation state. - */ -bool iwl_good_ack_health(struct iwl_priv *priv, - struct iwl_rx_packet *pkt) -{ - bool rc = true; - int actual_ack_cnt_delta, expected_ack_cnt_delta; - int ba_timeout_delta; - - actual_ack_cnt_delta = - le32_to_cpu(pkt->u.stats.tx.actual_ack_cnt) - - le32_to_cpu(priv->_agn.statistics.tx.actual_ack_cnt); - expected_ack_cnt_delta = - le32_to_cpu(pkt->u.stats.tx.expected_ack_cnt) - - le32_to_cpu(priv->_agn.statistics.tx.expected_ack_cnt); - ba_timeout_delta = - le32_to_cpu(pkt->u.stats.tx.agg.ba_timeout) - - le32_to_cpu(priv->_agn.statistics.tx.agg.ba_timeout); - if ((priv->_agn.agg_tids_count > 0) && - (expected_ack_cnt_delta > 0) && - (((actual_ack_cnt_delta * 100) / expected_ack_cnt_delta) - < ACK_CNT_RATIO) && - (ba_timeout_delta > BA_TIMEOUT_CNT)) { - IWL_DEBUG_RADIO(priv, "actual_ack_cnt delta = %d," - " expected_ack_cnt = %d\n", - actual_ack_cnt_delta, expected_ack_cnt_delta); - -#ifdef CONFIG_IWLWIFI_DEBUGFS - /* - * This is ifdef'ed on DEBUGFS because otherwise the - * statistics aren't available. If DEBUGFS is set but - * DEBUG is not, these will just compile out. - */ - IWL_DEBUG_RADIO(priv, "rx_detected_cnt delta = %d\n", - priv->_agn.delta_statistics.tx.rx_detected_cnt); - IWL_DEBUG_RADIO(priv, - "ack_or_ba_timeout_collision delta = %d\n", - priv->_agn.delta_statistics.tx. - ack_or_ba_timeout_collision); -#endif - IWL_DEBUG_RADIO(priv, "agg ba_timeout delta = %d\n", - ba_timeout_delta); - if (!actual_ack_cnt_delta && - (ba_timeout_delta >= BA_TIMEOUT_MAX)) - rc = false; - } - return rc; -} - - /***************************************************************************** * * sysfs attributes @@ -2632,13 +2430,6 @@ static void iwl_alive_start(struct iwl_priv *priv) IWL_DEBUG_INFO(priv, "Runtime Alive received.\n"); - if (priv->card_alive.is_valid != UCODE_VALID_OK) { - /* We had an error bringing up the hardware, so take it - * all the way back down so we can try again */ - IWL_DEBUG_INFO(priv, "Alive failed.\n"); - goto restart; - } - /* Initialize uCode has loaded Runtime uCode ... verify inst image. * This is a paranoid check, because we would not have gotten the * "runtime" alive if code weren't properly loaded. */ @@ -2710,9 +2501,11 @@ static void iwl_alive_start(struct iwl_priv *priv) priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx); } - if (priv->cfg->bt_params && - !priv->cfg->bt_params->advanced_bt_coexist) { - /* Configure Bluetooth device coexistence support */ + if (!priv->cfg->bt_params || (priv->cfg->bt_params && + !priv->cfg->bt_params->advanced_bt_coexist)) { + /* + * default is 2-wire BT coexexistence support + */ priv->cfg->ops->hcmd->send_bt_config(priv); } @@ -2726,8 +2519,6 @@ static void iwl_alive_start(struct iwl_priv *priv) /* At this point, the NIC is initialized and operational */ iwl_rf_kill_ct_config(priv); - iwl_leds_init(priv); - IWL_DEBUG_INFO(priv, "ALIVE processing complete.\n"); wake_up_interruptible(&priv->wait_command_queue); @@ -2769,7 +2560,6 @@ static void __iwl_down(struct iwl_priv *priv) priv->cfg->bt_params->bt_init_traffic_load; else priv->bt_traffic_load = 0; - priv->bt_sco_active = false; priv->bt_full_concurrent = false; priv->bt_ci_compliance = 0; @@ -3063,8 +2853,7 @@ static void iwl_bg_run_time_calib_work(struct work_struct *work) } if (priv->start_calib) { - if (priv->cfg->bt_params && - priv->cfg->bt_params->bt_statistics) { + if (iwl_bt_statistics(priv)) { iwl_chain_noise_calibration(priv, (void *)&priv->_agn.statistics_bt); iwl_sensitivity_calibration(priv, @@ -3089,7 +2878,7 @@ static void iwl_bg_restart(struct work_struct *data) if (test_and_clear_bit(STATUS_FW_ERROR, &priv->status)) { struct iwl_rxon_context *ctx; - bool bt_sco, bt_full_concurrent; + bool bt_full_concurrent; u8 bt_ci_compliance; u8 bt_load; u8 bt_status; @@ -3108,7 +2897,6 @@ static void iwl_bg_restart(struct work_struct *data) * re-configure the hw when we reconfigure the BT * command. */ - bt_sco = priv->bt_sco_active; bt_full_concurrent = priv->bt_full_concurrent; bt_ci_compliance = priv->bt_ci_compliance; bt_load = priv->bt_traffic_load; @@ -3116,7 +2904,6 @@ static void iwl_bg_restart(struct work_struct *data) __iwl_down(priv); - priv->bt_sco_active = bt_sco; priv->bt_full_concurrent = bt_full_concurrent; priv->bt_ci_compliance = bt_ci_compliance; priv->bt_traffic_load = bt_load; @@ -3150,6 +2937,91 @@ static void iwl_bg_rx_replenish(struct work_struct *data) mutex_unlock(&priv->mutex); } +static int iwl_mac_offchannel_tx(struct ieee80211_hw *hw, struct sk_buff *skb, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type, + unsigned int wait) +{ + struct iwl_priv *priv = hw->priv; + int ret; + + /* Not supported if we don't have PAN */ + if (!(priv->valid_contexts & BIT(IWL_RXON_CTX_PAN))) { + ret = -EOPNOTSUPP; + goto free; + } + + /* Not supported on pre-P2P firmware */ + if (!(priv->contexts[IWL_RXON_CTX_PAN].interface_modes & + BIT(NL80211_IFTYPE_P2P_CLIENT))) { + ret = -EOPNOTSUPP; + goto free; + } + + mutex_lock(&priv->mutex); + + if (!priv->contexts[IWL_RXON_CTX_PAN].is_active) { + /* + * If the PAN context is free, use the normal + * way of doing remain-on-channel offload + TX. + */ + ret = 1; + goto out; + } + + /* TODO: queue up if scanning? */ + if (test_bit(STATUS_SCANNING, &priv->status) || + priv->_agn.offchan_tx_skb) { + ret = -EBUSY; + goto out; + } + + /* + * max_scan_ie_len doesn't include the blank SSID or the header, + * so need to add that again here. + */ + if (skb->len > hw->wiphy->max_scan_ie_len + 24 + 2) { + ret = -ENOBUFS; + goto out; + } + + priv->_agn.offchan_tx_skb = skb; + priv->_agn.offchan_tx_timeout = wait; + priv->_agn.offchan_tx_chan = chan; + + ret = iwl_scan_initiate(priv, priv->contexts[IWL_RXON_CTX_PAN].vif, + IWL_SCAN_OFFCH_TX, chan->band); + if (ret) + priv->_agn.offchan_tx_skb = NULL; + out: + mutex_unlock(&priv->mutex); + free: + if (ret < 0) + kfree_skb(skb); + + return ret; +} + +static int iwl_mac_offchannel_tx_cancel_wait(struct ieee80211_hw *hw) +{ + struct iwl_priv *priv = hw->priv; + int ret; + + mutex_lock(&priv->mutex); + + if (!priv->_agn.offchan_tx_skb) + return -EINVAL; + + priv->_agn.offchan_tx_skb = NULL; + + ret = iwl_scan_cancel_timeout(priv, 200); + if (ret) + ret = -EIO; + mutex_unlock(&priv->mutex); + + return ret; +} + /***************************************************************************** * * mac80211 entry point functions @@ -3178,6 +3050,8 @@ static int iwl_mac_setup_register(struct iwl_priv *priv, IEEE80211_HW_SPECTRUM_MGMT | IEEE80211_HW_REPORTS_TX_ACK_STATUS; + hw->max_tx_aggregation_subframes = LINK_QUAL_AGG_FRAME_LIMIT_DEF; + if (!priv->cfg->base_params->broken_powersave) hw->flags |= IEEE80211_HW_SUPPORTS_PS | IEEE80211_HW_SUPPORTS_DYNAMIC_PS; @@ -3194,8 +3068,11 @@ static int iwl_mac_setup_register(struct iwl_priv *priv, hw->wiphy->interface_modes |= ctx->exclusive_interface_modes; } + hw->wiphy->max_remain_on_channel_duration = 1000; + hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY | - WIPHY_FLAG_DISABLE_BEACON_HINTS; + WIPHY_FLAG_DISABLE_BEACON_HINTS | + WIPHY_FLAG_IBSS_RSN; /* * For now, disable PS by default because it affects @@ -3219,6 +3096,8 @@ static int iwl_mac_setup_register(struct iwl_priv *priv, priv->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &priv->bands[IEEE80211_BAND_5GHZ]; + iwl_leds_init(priv); + ret = ieee80211_register_hw(priv->hw); if (ret) { IWL_ERR(priv, "Failed to register hw (error %d)\n", ret); @@ -3263,7 +3142,7 @@ int iwlagn_mac_start(struct ieee80211_hw *hw) } } - iwl_led_start(priv); + iwlagn_led_enable(priv); out: priv->is_open = 1; @@ -3294,7 +3173,7 @@ void iwlagn_mac_stop(struct ieee80211_hw *hw) IWL_DEBUG_MAC80211(priv, "leave\n"); } -int iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) +void iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { struct iwl_priv *priv = hw->priv; @@ -3307,7 +3186,6 @@ int iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) dev_kfree_skb_any(skb); IWL_DEBUG_MACDUMP(priv, "leave\n"); - return NETDEV_TX_OK; } void iwlagn_mac_update_tkip_key(struct ieee80211_hw *hw, @@ -3345,6 +3223,14 @@ int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, return -EOPNOTSUPP; } + /* + * To support IBSS RSN, don't program group keys in IBSS, the + * hardware will then not attempt to decrypt the frames. + */ + if (vif->type == NL80211_IFTYPE_ADHOC && + !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) + return -EOPNOTSUPP; + sta_id = iwl_sta_id_or_broadcast(priv, vif_priv->ctx, sta); if (sta_id == IWL_INVALID_STATION) return -EINVAL; @@ -3399,10 +3285,12 @@ int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, enum ieee80211_ampdu_mlme_action action, - struct ieee80211_sta *sta, u16 tid, u16 *ssn) + struct ieee80211_sta *sta, u16 tid, u16 *ssn, + u8 buf_size) { struct iwl_priv *priv = hw->priv; int ret = -EINVAL; + struct iwl_station_priv *sta_priv = (void *) sta->drv_priv; IWL_DEBUG_HT(priv, "A-MPDU action on addr %pM tid %d\n", sta->addr, tid); @@ -3457,11 +3345,28 @@ int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw, } break; case IEEE80211_AMPDU_TX_OPERATIONAL: + /* + * If the limit is 0, then it wasn't initialised yet, + * use the default. We can do that since we take the + * minimum below, and we don't want to go above our + * default due to hardware restrictions. + */ + if (sta_priv->max_agg_bufsize == 0) + sta_priv->max_agg_bufsize = + LINK_QUAL_AGG_FRAME_LIMIT_DEF; + + /* + * Even though in theory the peer could have different + * aggregation reorder buffer sizes for different sessions, + * our ucode doesn't allow for that and has a global limit + * for each station. Therefore, use the minimum of all the + * aggregation sessions and our default value. + */ + sta_priv->max_agg_bufsize = + min(sta_priv->max_agg_bufsize, buf_size); + if (priv->cfg->ht_params && priv->cfg->ht_params->use_rts_for_aggregation) { - struct iwl_station_priv *sta_priv = - (void *) sta->drv_priv; - /* * switch to RTS/CTS if it is the prefer protection * method for HT traffic @@ -3469,9 +3374,13 @@ int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw, sta_priv->lq_sta.lq.general_params.flags |= LINK_QUAL_FLAGS_SET_STA_TLC_RTS_MSK; - iwl_send_lq_cmd(priv, iwl_rxon_ctx_from_vif(vif), - &sta_priv->lq_sta.lq, CMD_ASYNC, false); } + + sta_priv->lq_sta.lq.agg_params.agg_frame_cnt_limit = + sta_priv->max_agg_bufsize; + + iwl_send_lq_cmd(priv, iwl_rxon_ctx_from_vif(vif), + &sta_priv->lq_sta.lq, CMD_ASYNC, false); ret = 0; break; } @@ -3709,6 +3618,95 @@ done: IWL_DEBUG_MAC80211(priv, "leave\n"); } +static void iwlagn_disable_roc(struct iwl_priv *priv) +{ + struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_PAN]; + struct ieee80211_channel *chan = ACCESS_ONCE(priv->hw->conf.channel); + + lockdep_assert_held(&priv->mutex); + + if (!ctx->is_active) + return; + + ctx->staging.dev_type = RXON_DEV_TYPE_2STA; + ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK; + iwl_set_rxon_channel(priv, chan, ctx); + iwl_set_flags_for_band(priv, ctx, chan->band, NULL); + + priv->_agn.hw_roc_channel = NULL; + + iwlcore_commit_rxon(priv, ctx); + + ctx->is_active = false; +} + +static void iwlagn_bg_roc_done(struct work_struct *work) +{ + struct iwl_priv *priv = container_of(work, struct iwl_priv, + _agn.hw_roc_work.work); + + mutex_lock(&priv->mutex); + ieee80211_remain_on_channel_expired(priv->hw); + iwlagn_disable_roc(priv); + mutex_unlock(&priv->mutex); +} + +static int iwl_mac_remain_on_channel(struct ieee80211_hw *hw, + struct ieee80211_channel *channel, + enum nl80211_channel_type channel_type, + int duration) +{ + struct iwl_priv *priv = hw->priv; + int err = 0; + + if (!(priv->valid_contexts & BIT(IWL_RXON_CTX_PAN))) + return -EOPNOTSUPP; + + if (!(priv->contexts[IWL_RXON_CTX_PAN].interface_modes & + BIT(NL80211_IFTYPE_P2P_CLIENT))) + return -EOPNOTSUPP; + + mutex_lock(&priv->mutex); + + if (priv->contexts[IWL_RXON_CTX_PAN].is_active || + test_bit(STATUS_SCAN_HW, &priv->status)) { + err = -EBUSY; + goto out; + } + + priv->contexts[IWL_RXON_CTX_PAN].is_active = true; + priv->_agn.hw_roc_channel = channel; + priv->_agn.hw_roc_chantype = channel_type; + priv->_agn.hw_roc_duration = DIV_ROUND_UP(duration * 1000, 1024); + iwlcore_commit_rxon(priv, &priv->contexts[IWL_RXON_CTX_PAN]); + queue_delayed_work(priv->workqueue, &priv->_agn.hw_roc_work, + msecs_to_jiffies(duration + 20)); + + msleep(IWL_MIN_SLOT_TIME); /* TU is almost ms */ + ieee80211_ready_on_channel(priv->hw); + + out: + mutex_unlock(&priv->mutex); + + return err; +} + +static int iwl_mac_cancel_remain_on_channel(struct ieee80211_hw *hw) +{ + struct iwl_priv *priv = hw->priv; + + if (!(priv->valid_contexts & BIT(IWL_RXON_CTX_PAN))) + return -EOPNOTSUPP; + + cancel_delayed_work_sync(&priv->_agn.hw_roc_work); + + mutex_lock(&priv->mutex); + iwlagn_disable_roc(priv); + mutex_unlock(&priv->mutex); + + return 0; +} + /***************************************************************************** * * driver setup and teardown @@ -3730,6 +3728,7 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv) INIT_WORK(&priv->bt_runtime_config, iwl_bg_bt_runtime_config); INIT_DELAYED_WORK(&priv->init_alive_start, iwl_bg_init_alive_start); INIT_DELAYED_WORK(&priv->alive_start, iwl_bg_alive_start); + INIT_DELAYED_WORK(&priv->_agn.hw_roc_work, iwlagn_bg_roc_done); iwl_setup_scan_deferred_work(priv); @@ -3823,6 +3822,8 @@ static int iwl_init_drv(struct iwl_priv *priv) priv->force_reset[IWL_FW_RESET].reset_duration = IWL_DELAY_NEXT_FORCE_FW_RELOAD; + priv->rx_statistics_jiffies = jiffies; + /* Choose which receivers/antennas to use */ if (priv->cfg->ops->hcmd->set_rxon_chain) priv->cfg->ops->hcmd->set_rxon_chain(priv, @@ -3876,7 +3877,6 @@ static void iwl_uninit_drv(struct iwl_priv *priv) kfree(priv->scan_cmd); } -#ifdef CONFIG_IWL5000 struct ieee80211_ops iwlagn_hw_ops = { .tx = iwlagn_mac_tx, .start = iwlagn_mac_start, @@ -3898,14 +3898,17 @@ struct ieee80211_ops iwlagn_hw_ops = { .channel_switch = iwlagn_mac_channel_switch, .flush = iwlagn_mac_flush, .tx_last_beacon = iwl_mac_tx_last_beacon, + .remain_on_channel = iwl_mac_remain_on_channel, + .cancel_remain_on_channel = iwl_mac_cancel_remain_on_channel, + .offchannel_tx = iwl_mac_offchannel_tx, + .offchannel_tx_cancel_wait = iwl_mac_offchannel_tx_cancel_wait, }; -#endif static void iwl_hw_detect(struct iwl_priv *priv) { priv->hw_rev = _iwl_read32(priv, CSR_HW_REV); priv->hw_wa_rev = _iwl_read32(priv, CSR_HW_REV_WA_REG); - pci_read_config_byte(priv->pci_dev, PCI_REVISION_ID, &priv->rev_id); + priv->rev_id = priv->pci_dev->revision; IWL_DEBUG_INFO(priv, "HW Revision ID = 0x%X\n", priv->rev_id); } @@ -3967,12 +3970,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (cfg->mod_params->disable_hw_scan) { dev_printk(KERN_DEBUG, &(pdev->dev), "sw scan support is deprecated\n"); -#ifdef CONFIG_IWL5000 iwlagn_hw_ops.hw_scan = NULL; -#endif -#ifdef CONFIG_IWL4965 - iwl4965_hw_ops.hw_scan = NULL; -#endif } hw = iwl_alloc_all(cfg); @@ -4025,6 +4023,10 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) priv->contexts[IWL_RXON_CTX_PAN].mcast_queue = IWL_IPAN_MCAST_QUEUE; priv->contexts[IWL_RXON_CTX_PAN].interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP); +#ifdef CONFIG_IWL_P2P + priv->contexts[IWL_RXON_CTX_PAN].interface_modes |= + BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO); +#endif priv->contexts[IWL_RXON_CTX_PAN].ap_devtype = RXON_DEV_TYPE_CP; priv->contexts[IWL_RXON_CTX_PAN].station_devtype = RXON_DEV_TYPE_2STA; priv->contexts[IWL_RXON_CTX_PAN].unused_devtype = RXON_DEV_TYPE_P2P; @@ -4272,6 +4274,9 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev) * we need to set STATUS_EXIT_PENDING bit. */ set_bit(STATUS_EXIT_PENDING, &priv->status); + + iwl_leds_exit(priv); + if (priv->mac80211_registered) { ieee80211_unregister_hw(priv->hw); priv->mac80211_registered = 0; @@ -4344,12 +4349,6 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev) /* Hardware specific file defines the PCI IDs table for that hardware module */ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = { -#ifdef CONFIG_IWL4965 - {IWL_PCI_DEVICE(0x4229, PCI_ANY_ID, iwl4965_agn_cfg)}, - {IWL_PCI_DEVICE(0x4230, PCI_ANY_ID, iwl4965_agn_cfg)}, -#endif /* CONFIG_IWL4965 */ -#ifdef CONFIG_IWL5000 -/* 5100 Series WiFi */ {IWL_PCI_DEVICE(0x4232, 0x1201, iwl5100_agn_cfg)}, /* Mini Card */ {IWL_PCI_DEVICE(0x4232, 0x1301, iwl5100_agn_cfg)}, /* Half Mini Card */ {IWL_PCI_DEVICE(0x4232, 0x1204, iwl5100_agn_cfg)}, /* Mini Card */ @@ -4492,7 +4491,48 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = { {IWL_PCI_DEVICE(0x0896, 0x5025, iwl130_bgn_cfg)}, {IWL_PCI_DEVICE(0x0896, 0x5027, iwl130_bg_cfg)}, -#endif /* CONFIG_IWL5000 */ +/* 2x00 Series */ + {IWL_PCI_DEVICE(0x0890, 0x4022, iwl2000_2bgn_cfg)}, + {IWL_PCI_DEVICE(0x0891, 0x4222, iwl2000_2bgn_cfg)}, + {IWL_PCI_DEVICE(0x0890, 0x4422, iwl2000_2bgn_cfg)}, + {IWL_PCI_DEVICE(0x0890, 0x4026, iwl2000_2bg_cfg)}, + {IWL_PCI_DEVICE(0x0891, 0x4226, iwl2000_2bg_cfg)}, + {IWL_PCI_DEVICE(0x0890, 0x4426, iwl2000_2bg_cfg)}, + +/* 2x30 Series */ + {IWL_PCI_DEVICE(0x0887, 0x4062, iwl2030_2bgn_cfg)}, + {IWL_PCI_DEVICE(0x0888, 0x4262, iwl2030_2bgn_cfg)}, + {IWL_PCI_DEVICE(0x0887, 0x4462, iwl2030_2bgn_cfg)}, + {IWL_PCI_DEVICE(0x0887, 0x4066, iwl2030_2bg_cfg)}, + {IWL_PCI_DEVICE(0x0888, 0x4266, iwl2030_2bg_cfg)}, + {IWL_PCI_DEVICE(0x0887, 0x4466, iwl2030_2bg_cfg)}, + +/* 6x35 Series */ + {IWL_PCI_DEVICE(0x088E, 0x4060, iwl6035_2agn_cfg)}, + {IWL_PCI_DEVICE(0x088F, 0x4260, iwl6035_2agn_cfg)}, + {IWL_PCI_DEVICE(0x088E, 0x4460, iwl6035_2agn_cfg)}, + {IWL_PCI_DEVICE(0x088E, 0x4064, iwl6035_2abg_cfg)}, + {IWL_PCI_DEVICE(0x088F, 0x4264, iwl6035_2abg_cfg)}, + {IWL_PCI_DEVICE(0x088E, 0x4464, iwl6035_2abg_cfg)}, + {IWL_PCI_DEVICE(0x088E, 0x4066, iwl6035_2bg_cfg)}, + {IWL_PCI_DEVICE(0x088F, 0x4266, iwl6035_2bg_cfg)}, + {IWL_PCI_DEVICE(0x088E, 0x4466, iwl6035_2bg_cfg)}, + +/* 200 Series */ + {IWL_PCI_DEVICE(0x0894, 0x0022, iwl200_bgn_cfg)}, + {IWL_PCI_DEVICE(0x0895, 0x0222, iwl200_bgn_cfg)}, + {IWL_PCI_DEVICE(0x0894, 0x0422, iwl200_bgn_cfg)}, + {IWL_PCI_DEVICE(0x0894, 0x0026, iwl200_bg_cfg)}, + {IWL_PCI_DEVICE(0x0895, 0x0226, iwl200_bg_cfg)}, + {IWL_PCI_DEVICE(0x0894, 0x0426, iwl200_bg_cfg)}, + +/* 230 Series */ + {IWL_PCI_DEVICE(0x0892, 0x0062, iwl230_bgn_cfg)}, + {IWL_PCI_DEVICE(0x0893, 0x0262, iwl230_bgn_cfg)}, + {IWL_PCI_DEVICE(0x0892, 0x0462, iwl230_bgn_cfg)}, + {IWL_PCI_DEVICE(0x0892, 0x0066, iwl230_bg_cfg)}, + {IWL_PCI_DEVICE(0x0893, 0x0266, iwl230_bg_cfg)}, + {IWL_PCI_DEVICE(0x0892, 0x0466, iwl230_bg_cfg)}, {0} }; @@ -4592,3 +4632,9 @@ MODULE_PARM_DESC(antenna_coupling, module_param_named(bt_ch_inhibition, iwlagn_bt_ch_announce, bool, S_IRUGO); MODULE_PARM_DESC(bt_ch_inhibition, "Disable BT channel inhibition (default: enable)"); + +module_param_named(plcp_check, iwlagn_mod_params.plcp_check, bool, S_IRUGO); +MODULE_PARM_DESC(plcp_check, "Check plcp health (default: 1 [enabled])"); + +module_param_named(ack_check, iwlagn_mod_params.ack_check, bool, S_IRUGO); +MODULE_PARM_DESC(ack_check, "Check ack health (default: 0 [disabled])"); |