X-Git-Url: http://git.monstr.eu/?a=blobdiff_plain;f=drivers%2Fstaging%2Fwfx%2Fsta.c;h=74ec0b60408548662006299f2dd4f92ab0dc744d;hb=6ae0878b4800c7042d35c0fb4c6baabb62621ecc;hp=7255899b4a5a088689fef3a1236a477eac4f0125;hpb=b3919d9bbcde6c27f2072dd4242c54e076bb17b7;p=linux-2.6-microblaze.git diff --git a/drivers/staging/wfx/sta.c b/drivers/staging/wfx/sta.c index 7255899b4a5a..74ec0b604085 100644 --- a/drivers/staging/wfx/sta.c +++ b/drivers/staging/wfx/sta.c @@ -38,91 +38,31 @@ u32 wfx_rate_mask_to_hw(struct wfx_dev *wdev, u32 rates) return ret; } -static void __wfx_free_event_queue(struct list_head *list) +void wfx_cooling_timeout_work(struct work_struct *work) { - struct wfx_hif_event *event, *tmp; + struct wfx_dev *wdev = container_of(to_delayed_work(work), + struct wfx_dev, + cooling_timeout_work); - list_for_each_entry_safe(event, tmp, list, link) { - list_del(&event->link); - kfree(event); - } -} - -static void wfx_free_event_queue(struct wfx_vif *wvif) -{ - LIST_HEAD(list); - - spin_lock(&wvif->event_queue_lock); - list_splice_init(&wvif->event_queue, &list); - spin_unlock(&wvif->event_queue_lock); - - __wfx_free_event_queue(&list); + wdev->chip_frozen = true; + wfx_tx_unlock(wdev); } -void wfx_cqm_bssloss_sm(struct wfx_vif *wvif, int init, int good, int bad) +void wfx_suspend_hot_dev(struct wfx_dev *wdev, enum sta_notify_cmd cmd) { - int tx = 0; - - mutex_lock(&wvif->bss_loss_lock); - cancel_work_sync(&wvif->bss_params_work); - - if (init) { - schedule_delayed_work(&wvif->bss_loss_work, HZ); - wvif->bss_loss_state = 0; - - if (!atomic_read(&wvif->wdev->tx_lock)) - tx = 1; - } else if (good) { - cancel_delayed_work_sync(&wvif->bss_loss_work); - wvif->bss_loss_state = 0; - schedule_work(&wvif->bss_params_work); - } else if (bad) { - /* FIXME Should we just keep going until we time out? */ - if (wvif->bss_loss_state < 3) - tx = 1; + if (cmd == STA_NOTIFY_AWAKE) { + // Device recover normal temperature + if (cancel_delayed_work(&wdev->cooling_timeout_work)) + wfx_tx_unlock(wdev); } else { - cancel_delayed_work_sync(&wvif->bss_loss_work); - wvif->bss_loss_state = 0; - } - - /* Spit out a NULL packet to our AP if necessary */ - // FIXME: call ieee80211_beacon_loss/ieee80211_connection_loss instead - if (tx) { - struct sk_buff *skb; - struct ieee80211_hdr *hdr; - struct ieee80211_tx_control control = { }; - - wvif->bss_loss_state++; - - skb = ieee80211_nullfunc_get(wvif->wdev->hw, wvif->vif, false); - if (!skb) - goto end; - hdr = (struct ieee80211_hdr *)skb->data; - memset(IEEE80211_SKB_CB(skb), 0, - sizeof(*IEEE80211_SKB_CB(skb))); - IEEE80211_SKB_CB(skb)->control.vif = wvif->vif; - IEEE80211_SKB_CB(skb)->driver_rates[0].idx = 0; - IEEE80211_SKB_CB(skb)->driver_rates[0].count = 1; - IEEE80211_SKB_CB(skb)->driver_rates[1].idx = -1; - rcu_read_lock(); // protect control.sta - control.sta = ieee80211_find_sta(wvif->vif, hdr->addr1); - wfx_tx(wvif->wdev->hw, &control, skb); - rcu_read_unlock(); + // Device is too hot + schedule_delayed_work(&wdev->cooling_timeout_work, 10 * HZ); + wfx_tx_lock(wdev); } -end: - mutex_unlock(&wvif->bss_loss_lock); } -int wfx_fwd_probe_req(struct wfx_vif *wvif, bool enable) +static void wfx_filter_beacon(struct wfx_vif *wvif, bool filter_beacon) { - wvif->fwd_probe_req = enable; - return hif_set_rx_filter(wvif, wvif->filter_bssid, - wvif->fwd_probe_req); -} - -void wfx_update_filtering(struct wfx_vif *wvif) -{ - int i; const struct hif_ie_table_entry filter_ies[] = { { .ie_id = WLAN_EID_VENDOR_SPECIFIC, @@ -143,34 +83,33 @@ void wfx_update_filtering(struct wfx_vif *wvif) } }; - hif_set_rx_filter(wvif, wvif->filter_bssid, wvif->fwd_probe_req); - if (wvif->disable_beacon_filter) { + if (!filter_beacon) { hif_set_beacon_filter_table(wvif, 0, NULL); hif_beacon_filter_control(wvif, 0, 1); - } else if (wvif->vif->type != NL80211_IFTYPE_STATION) { - hif_set_beacon_filter_table(wvif, 2, filter_ies); - hif_beacon_filter_control(wvif, HIF_BEACON_FILTER_ENABLE | - HIF_BEACON_FILTER_AUTO_ERP, 0); } else { hif_set_beacon_filter_table(wvif, 3, filter_ies); hif_beacon_filter_control(wvif, HIF_BEACON_FILTER_ENABLE, 0); } +} + +static void wfx_filter_mcast(struct wfx_vif *wvif, bool filter_mcast) +{ + int i; // Temporary workaround for filters hif_set_data_filtering(wvif, false, true); return; - if (!wvif->mcast_filter.enable) { + if (!filter_mcast) { hif_set_data_filtering(wvif, false, true); return; } - for (i = 0; i < wvif->mcast_filter.num_addresses; i++) - hif_set_mac_addr_condition(wvif, i, - wvif->mcast_filter.address_list[i]); + for (i = 0; i < wvif->filter_mcast_count; i++) + hif_set_mac_addr_condition(wvif, i, wvif->filter_mcast_addr[i]); hif_set_uc_mc_bc_condition(wvif, 0, HIF_FILTER_UNICAST | HIF_FILTER_BROADCAST); hif_set_config_data_filter(wvif, true, 0, BIT(1), - BIT(wvif->mcast_filter.num_addresses) - 1); + BIT(wvif->filter_mcast_count) - 1); hif_set_data_filtering(wvif, true, true); } @@ -184,18 +123,17 @@ u64 wfx_prepare_multicast(struct ieee80211_hw *hw, int count = netdev_hw_addr_list_count(mc_list); while ((wvif = wvif_iterate(wdev, wvif)) != NULL) { - memset(&wvif->mcast_filter, 0x00, sizeof(wvif->mcast_filter)); - if (!count || - count > ARRAY_SIZE(wvif->mcast_filter.address_list)) + if (count > ARRAY_SIZE(wvif->filter_mcast_addr)) { + wvif->filter_mcast_count = 0; continue; + } + wvif->filter_mcast_count = count; i = 0; netdev_hw_addr_list_for_each(ha, mc_list) { - ether_addr_copy(wvif->mcast_filter.address_list[i], - ha->addr); + ether_addr_copy(wvif->filter_mcast_addr[i], ha->addr); i++; } - wvif->mcast_filter.num_addresses = count; } return 0; @@ -208,6 +146,7 @@ void wfx_configure_filter(struct ieee80211_hw *hw, { struct wfx_vif *wvif = NULL; struct wfx_dev *wdev = hw->priv; + bool filter_bssid, filter_prbreq, filter_beacon, filter_mcast; // Notes: // - Probe responses (FIF_BCN_PRBRESP_PROMISC) are never filtered @@ -226,29 +165,39 @@ void wfx_configure_filter(struct ieee80211_hw *hw, // Note: FIF_BCN_PRBRESP_PROMISC covers probe response and // beacons from other BSS if (*total_flags & FIF_BCN_PRBRESP_PROMISC) - wvif->disable_beacon_filter = true; + filter_beacon = false; else - wvif->disable_beacon_filter = false; + filter_beacon = true; + wfx_filter_beacon(wvif, filter_beacon); if (*total_flags & FIF_ALLMULTI) { - wvif->mcast_filter.enable = false; - } else if (!wvif->mcast_filter.num_addresses) { + filter_mcast = false; + } else if (!wvif->filter_mcast_count) { dev_dbg(wdev->dev, "disabling unconfigured multicast filter"); - wvif->mcast_filter.enable = false; + filter_mcast = false; } else { - wvif->mcast_filter.enable = true; + filter_mcast = true; } - wfx_update_filtering(wvif); + wfx_filter_mcast(wvif, filter_mcast); if (*total_flags & FIF_OTHER_BSS) - wvif->filter_bssid = false; + filter_bssid = false; else - wvif->filter_bssid = true; + filter_bssid = true; + + // In AP mode, chip can reply to probe request itself + if (*total_flags & FIF_PROBE_REQ && + wvif->vif->type == NL80211_IFTYPE_AP) { + dev_dbg(wdev->dev, "do not forward probe request in AP mode\n"); + *total_flags &= ~FIF_PROBE_REQ; + } if (*total_flags & FIF_PROBE_REQ) - wfx_fwd_probe_req(wvif, true); + filter_prbreq = false; else - wfx_fwd_probe_req(wvif, false); + filter_prbreq = true; + hif_set_rx_filter(wvif, filter_bssid, filter_prbreq); + mutex_unlock(&wvif->scan_lock); } mutex_unlock(&wdev->conf_mutex); @@ -262,7 +211,7 @@ static int wfx_update_pm(struct wfx_vif *wvif) struct ieee80211_channel *chan0 = NULL, *chan1 = NULL; WARN_ON(conf->dynamic_ps_timeout < 0); - if (wvif->state != WFX_STATE_STA || !wvif->bss_params.aid) + if (!wvif->vif->bss_conf.assoc) return 0; if (!ps) ps_timeout = 0; @@ -279,7 +228,10 @@ static int wfx_update_pm(struct wfx_vif *wvif) if (chan0 && chan1 && chan0->hw_value != chan1->hw_value && wvif->vif->type != NL80211_IFTYPE_AP) { ps = true; - ps_timeout = 0; + if (wvif->bss_not_support_ps_poll) + ps_timeout = 30; + else + ps_timeout = 0; } if (!wait_for_completion_timeout(&wvif->set_pm_mode_complete, @@ -289,6 +241,14 @@ static int wfx_update_pm(struct wfx_vif *wvif) return hif_set_pm(wvif, ps, ps_timeout); } +static void wfx_update_pm_work(struct work_struct *work) +{ + struct wfx_vif *wvif = container_of(work, struct wfx_vif, + update_pm_work); + + wfx_update_pm(wvif); +} + int wfx_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params) { @@ -322,7 +282,7 @@ int wfx_set_rts_threshold(struct ieee80211_hw *hw, u32 value) /* WSM callbacks */ -static void wfx_event_report_rssi(struct wfx_vif *wvif, u8 raw_rcpi_rssi) +void wfx_event_report_rssi(struct wfx_vif *wvif, u8 raw_rcpi_rssi) { /* RSSI: signed Q8.0, RCPI: unsigned Q7.1 * RSSI = RCPI / 2 - 110 @@ -338,91 +298,37 @@ static void wfx_event_report_rssi(struct wfx_vif *wvif, u8 raw_rcpi_rssi) ieee80211_cqm_rssi_notify(wvif->vif, cqm_evt, rcpi_rssi, GFP_KERNEL); } -static void wfx_event_handler_work(struct work_struct *work) -{ - struct wfx_vif *wvif = - container_of(work, struct wfx_vif, event_handler_work); - struct wfx_hif_event *event; - - LIST_HEAD(list); - - spin_lock(&wvif->event_queue_lock); - list_splice_init(&wvif->event_queue, &list); - spin_unlock(&wvif->event_queue_lock); - - list_for_each_entry(event, &list, link) { - switch (event->evt.event_id) { - case HIF_EVENT_IND_BSSLOST: - mutex_lock(&wvif->scan_lock); - wfx_cqm_bssloss_sm(wvif, 1, 0, 0); - mutex_unlock(&wvif->scan_lock); - break; - case HIF_EVENT_IND_BSSREGAINED: - wfx_cqm_bssloss_sm(wvif, 0, 0, 0); - break; - case HIF_EVENT_IND_RCPI_RSSI: - wfx_event_report_rssi(wvif, - event->evt.event_data.rcpi_rssi); - break; - case HIF_EVENT_IND_PS_MODE_ERROR: - dev_warn(wvif->wdev->dev, - "error while processing power save request\n"); - break; - default: - dev_warn(wvif->wdev->dev, - "unhandled event indication: %.2x\n", - event->evt.event_id); - break; - } - } - __wfx_free_event_queue(&list); -} - -static void wfx_bss_loss_work(struct work_struct *work) +static void wfx_beacon_loss_work(struct work_struct *work) { - struct wfx_vif *wvif = container_of(work, struct wfx_vif, - bss_loss_work.work); + struct wfx_vif *wvif = container_of(to_delayed_work(work), + struct wfx_vif, beacon_loss_work); + struct ieee80211_bss_conf *bss_conf = &wvif->vif->bss_conf; - ieee80211_connection_loss(wvif->vif); + ieee80211_beacon_loss(wvif->vif); + schedule_delayed_work(to_delayed_work(work), + msecs_to_jiffies(bss_conf->beacon_int)); } -static void wfx_bss_params_work(struct work_struct *work) +void wfx_set_default_unicast_key(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, int idx) { - struct wfx_vif *wvif = container_of(work, struct wfx_vif, - bss_params_work); + struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; - mutex_lock(&wvif->wdev->conf_mutex); - wvif->bss_params.bss_flags.lost_count_only = 1; - hif_set_bss_params(wvif, &wvif->bss_params); - wvif->bss_params.bss_flags.lost_count_only = 0; - mutex_unlock(&wvif->wdev->conf_mutex); + hif_wep_default_key_id(wvif, idx); } // Call it with wdev->conf_mutex locked static void wfx_do_unjoin(struct wfx_vif *wvif) { - if (!wvif->state) - return; - - if (wvif->state == WFX_STATE_AP) - return; - - wvif->state = WFX_STATE_PASSIVE; - /* Unjoin is a reset. */ wfx_tx_lock_flush(wvif->wdev); hif_reset(wvif, false); wfx_tx_policy_init(wvif); if (wvif_count(wvif->wdev) <= 1) hif_set_block_ack_policy(wvif, 0xFF, 0xFF); - wfx_free_event_queue(wvif); - cancel_work_sync(&wvif->event_handler_work); - wfx_cqm_bssloss_sm(wvif, 0, 0, 0); - - wvif->disable_beacon_filter = false; - wfx_update_filtering(wvif); - memset(&wvif->bss_params, 0, sizeof(wvif->bss_params)); wfx_tx_unlock(wvif->wdev); + wvif->bss_not_support_ps_poll = false; + cancel_delayed_work_sync(&wvif->beacon_loss_work); } static void wfx_set_mfp(struct wfx_vif *wvif, @@ -480,7 +386,9 @@ static void wfx_do_join(struct wfx_vif *wvif) ssidie = ieee80211_bss_get_ie(bss, WLAN_EID_SSID); if (ssidie) { ssidlen = ssidie[1]; - memcpy(ssid, &ssidie[2], ssidie[1]); + if (ssidlen > IEEE80211_MAX_SSID_LEN) + ssidlen = IEEE80211_MAX_SSID_LEN; + memcpy(ssid, &ssidie[2], ssidlen); } rcu_read_unlock(); @@ -490,25 +398,14 @@ static void wfx_do_join(struct wfx_vif *wvif) ret = hif_join(wvif, conf, wvif->channel, ssid, ssidlen); if (ret) { ieee80211_connection_loss(wvif->vif); - wvif->join_complete_status = -1; wfx_do_unjoin(wvif); } else { - wvif->join_complete_status = 0; - if (wvif->vif->type == NL80211_IFTYPE_ADHOC) - wvif->state = WFX_STATE_IBSS; - else - wvif->state = WFX_STATE_PRE_STA; - - /* Upload keys */ - wfx_upload_keys(wvif); - /* Due to beacon filtering it is possible that the * AP's beacon is not known for the mac80211 stack. * Disable filtering temporary to make sure the stack * receives at least one */ - wvif->disable_beacon_filter = true; - wfx_update_filtering(wvif); + wfx_filter_beacon(wvif, false); } wfx_tx_unlock(wvif->wdev); } @@ -522,9 +419,8 @@ int wfx_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, spin_lock_init(&sta_priv->lock); sta_priv->vif_id = wvif->id; - // FIXME: in station mode, the current API interprets new link-id as a - // tdls peer. - if (vif->type == NL80211_IFTYPE_STATION) + // In station mode, the firmware interprets new link-id as a TDLS peer. + if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) return 0; sta_priv->link_id = ffz(wvif->link_id_map); wvif->link_id_map |= BIT(sta_priv->link_id); @@ -546,8 +442,8 @@ int wfx_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, if (sta_priv->buffered[i]) dev_warn(wvif->wdev->dev, "release station while %d pending frame on queue %d", sta_priv->buffered[i], i); - // FIXME: see note in wfx_sta_add() - if (vif->type == NL80211_IFTYPE_STATION) + // See note in wfx_sta_add() + if (!sta_priv->link_id) return 0; // FIXME add a mutex? hif_map_link(wvif, sta->addr, 1, sta_priv->link_id); @@ -579,11 +475,7 @@ int wfx_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; - wfx_upload_keys(wvif); - wvif->state = WFX_STATE_AP; - wfx_update_filtering(wvif); wfx_upload_ap_templates(wvif); - wfx_fwd_probe_req(wvif, false); hif_start(wvif, &vif->bss_conf, wvif->channel); return 0; } @@ -596,44 +488,19 @@ void wfx_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif) wfx_tx_policy_init(wvif); if (wvif_count(wvif->wdev) <= 1) hif_set_block_ack_policy(wvif, 0xFF, 0xFF); - wvif->state = WFX_STATE_PASSIVE; + wvif->bss_not_support_ps_poll = false; } static void wfx_join_finalize(struct wfx_vif *wvif, struct ieee80211_bss_conf *info) { - struct ieee80211_sta *sta = NULL; - - rcu_read_lock(); // protect sta - if (info->bssid && !info->ibss_joined) - sta = ieee80211_find_sta(wvif->vif, info->bssid); - if (sta) - wvif->bss_params.operational_rate_set = - wfx_rate_mask_to_hw(wvif->wdev, sta->supp_rates[wvif->channel->band]); - else - wvif->bss_params.operational_rate_set = -1; - rcu_read_unlock(); - if (sta && - info->ht_operation_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT) - hif_dual_cts_protection(wvif, true); - else - hif_dual_cts_protection(wvif, false); - - wfx_cqm_bssloss_sm(wvif, 0, 0, 0); - - wvif->bss_params.beacon_lost_count = 20; - wvif->bss_params.aid = info->aid; - hif_set_association_mode(wvif, info); - - if (!info->ibss_joined) { - wvif->state = WFX_STATE_STA; - hif_keep_alive_period(wvif, 0); - hif_set_bss_params(wvif, &wvif->bss_params); - hif_set_beacon_wakeup_period(wvif, info->dtim_period, - info->dtim_period); - wfx_update_pm(wvif); - } + hif_keep_alive_period(wvif, 0); + // beacon_loss_count is defined to 7 in net/mac80211/mlme.c. Let's use + // the same value. + hif_set_bss_params(wvif, info->aid, 7); + hif_set_beacon_wakeup_period(wvif, 1, 1); + wfx_update_pm(wvif); } int wfx_join_ibss(struct ieee80211_hw *hw, struct ieee80211_vif *vif) @@ -711,15 +578,7 @@ void wfx_bss_info_changed(struct ieee80211_hw *hw, info->dtim_period); // We temporary forwarded beacon for join process. It is now no // more necessary. - wvif->disable_beacon_filter = false; - wfx_update_filtering(wvif); - } - - /* assoc/disassoc, or maybe AID changed */ - if (changed & BSS_CHANGED_ASSOC) { - wfx_tx_lock_flush(wdev); - wvif->wep_default_key_id = -1; - wfx_tx_unlock(wdev); + wfx_filter_beacon(wvif, true); } if (changed & BSS_CHANGED_ASSOC) { @@ -805,6 +664,8 @@ int wfx_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set) void wfx_suspend_resume_mc(struct wfx_vif *wvif, enum sta_notify_cmd notify_cmd) { + if (notify_cmd != STA_NOTIFY_AWAKE) + return; WARN(!wfx_tx_queues_has_cab(wvif), "incorrect sequence"); WARN(wvif->after_dtim_tx_allowed, "incorrect sequence"); wvif->after_dtim_tx_allowed = true; @@ -910,29 +771,17 @@ int wfx_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) wvif->link_id_map = 1; // link-id 0 is reserved for multicast INIT_WORK(&wvif->update_tim_work, wfx_update_tim_work); - - memset(&wvif->bss_params, 0, sizeof(wvif->bss_params)); - - mutex_init(&wvif->bss_loss_lock); - INIT_DELAYED_WORK(&wvif->bss_loss_work, wfx_bss_loss_work); - - wvif->wep_default_key_id = -1; - INIT_WORK(&wvif->wep_key_work, wfx_wep_key_work); - - spin_lock_init(&wvif->event_queue_lock); - INIT_LIST_HEAD(&wvif->event_queue); - INIT_WORK(&wvif->event_handler_work, wfx_event_handler_work); + INIT_DELAYED_WORK(&wvif->beacon_loss_work, wfx_beacon_loss_work); init_completion(&wvif->set_pm_mode_complete); complete(&wvif->set_pm_mode_complete); - INIT_WORK(&wvif->bss_params_work, wfx_bss_params_work); + INIT_WORK(&wvif->update_pm_work, wfx_update_pm_work); INIT_WORK(&wvif->tx_policy_upload_work, wfx_tx_policy_upload_work); mutex_init(&wvif->scan_lock); init_completion(&wvif->scan_complete); INIT_WORK(&wvif->scan_work, wfx_hw_scan_work); - INIT_WORK(&wvif->tx_policy_upload_work, wfx_tx_policy_upload_work); mutex_unlock(&wdev->conf_mutex); hif_set_macaddr(wvif, vif->addr); @@ -961,28 +810,12 @@ void wfx_remove_interface(struct ieee80211_hw *hw, mutex_lock(&wdev->conf_mutex); WARN(wvif->link_id_map != 1, "corrupted state"); - switch (wvif->state) { - case WFX_STATE_PRE_STA: - case WFX_STATE_STA: - case WFX_STATE_IBSS: - wfx_do_unjoin(wvif); - break; - case WFX_STATE_AP: - /* reset.link_id = 0; */ - hif_reset(wvif, false); - break; - default: - break; - } - - wvif->state = WFX_STATE_PASSIVE; - /* FIXME: In add to reset MAC address, try to reset interface */ + hif_reset(wvif, false); hif_set_macaddr(wvif, NULL); + wfx_tx_policy_init(wvif); - wfx_cqm_bssloss_sm(wvif, 0, 0, 0); - wfx_free_event_queue(wvif); - + cancel_delayed_work_sync(&wvif->beacon_loss_work); wdev->vif[wvif->id] = NULL; wvif->vif = NULL;