diff options
author | David S. Miller <davem@davemloft.net> | 2008-07-05 21:41:53 -0700 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-07-05 21:41:53 -0700 |
commit | f3032be921cd126615ce3bfd7084e3d319f3f892 (patch) | |
tree | c2ce874f2ab7f107dddf7b854772e0f3b64d35a1 /drivers | |
parent | 70c03b49b80ba3634958acc31853771019c0ebd3 (diff) | |
parent | 18d7260527ce7c0d0a177afdf92d8f868f50b067 (diff) |
Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/linville/wireless-next-2.6
Diffstat (limited to 'drivers')
29 files changed, 1614 insertions, 1564 deletions
diff --git a/drivers/net/wireless/b43/rfkill.c b/drivers/net/wireless/b43/rfkill.c index 4cca203992e..fec5645944a 100644 --- a/drivers/net/wireless/b43/rfkill.c +++ b/drivers/net/wireless/b43/rfkill.c @@ -43,6 +43,23 @@ static bool b43_is_hw_radio_enabled(struct b43_wldev *dev) return 0; } +/* Update the rfkill state */ +static void b43_rfkill_update_state(struct b43_wldev *dev) +{ + struct b43_rfkill *rfk = &(dev->wl->rfkill); + + if (!dev->radio_hw_enable) { + rfk->rfkill->state = RFKILL_STATE_HARD_BLOCKED; + return; + } + + if (!dev->phy.radio_on) + rfk->rfkill->state = RFKILL_STATE_SOFT_BLOCKED; + else + rfk->rfkill->state = RFKILL_STATE_UNBLOCKED; + +} + /* The poll callback for the hardware button. */ static void b43_rfkill_poll(struct input_polled_dev *poll_dev) { @@ -60,6 +77,7 @@ static void b43_rfkill_poll(struct input_polled_dev *poll_dev) if (unlikely(enabled != dev->radio_hw_enable)) { dev->radio_hw_enable = enabled; report_change = 1; + b43_rfkill_update_state(dev); b43info(wl, "Radio hardware status changed to %s\n", enabled ? "ENABLED" : "DISABLED"); } @@ -135,7 +153,7 @@ void b43_rfkill_init(struct b43_wldev *dev) snprintf(rfk->name, sizeof(rfk->name), "b43-%s", wiphy_name(wl->hw->wiphy)); rfk->rfkill->name = rfk->name; - rfk->rfkill->state = RFKILL_STATE_ON; + rfk->rfkill->state = RFKILL_STATE_UNBLOCKED; rfk->rfkill->data = dev; rfk->rfkill->toggle_radio = b43_rfkill_soft_toggle; rfk->rfkill->user_claim_unsupported = 1; diff --git a/drivers/net/wireless/b43legacy/rfkill.c b/drivers/net/wireless/b43legacy/rfkill.c index 8935a302b22..476add97e97 100644 --- a/drivers/net/wireless/b43legacy/rfkill.c +++ b/drivers/net/wireless/b43legacy/rfkill.c @@ -44,6 +44,23 @@ static bool b43legacy_is_hw_radio_enabled(struct b43legacy_wldev *dev) return 0; } +/* Update the rfkill state */ +static void b43legacy_rfkill_update_state(struct b43legacy_wldev *dev) +{ + struct b43legacy_rfkill *rfk = &(dev->wl->rfkill); + + if (!dev->radio_hw_enable) { + rfk->rfkill->state = RFKILL_STATE_HARD_BLOCKED; + return; + } + + if (!dev->phy.radio_on) + rfk->rfkill->state = RFKILL_STATE_SOFT_BLOCKED; + else + rfk->rfkill->state = RFKILL_STATE_UNBLOCKED; + +} + /* The poll callback for the hardware button. */ static void b43legacy_rfkill_poll(struct input_polled_dev *poll_dev) { @@ -61,6 +78,7 @@ static void b43legacy_rfkill_poll(struct input_polled_dev *poll_dev) if (unlikely(enabled != dev->radio_hw_enable)) { dev->radio_hw_enable = enabled; report_change = 1; + b43legacy_rfkill_update_state(dev); b43legacyinfo(wl, "Radio hardware status changed to %s\n", enabled ? "ENABLED" : "DISABLED"); } @@ -139,7 +157,7 @@ void b43legacy_rfkill_init(struct b43legacy_wldev *dev) snprintf(rfk->name, sizeof(rfk->name), "b43legacy-%s", wiphy_name(wl->hw->wiphy)); rfk->rfkill->name = rfk->name; - rfk->rfkill->state = RFKILL_STATE_ON; + rfk->rfkill->state = RFKILL_STATE_UNBLOCKED; rfk->rfkill->data = dev; rfk->rfkill->toggle_radio = b43legacy_rfkill_soft_toggle; rfk->rfkill->user_claim_unsupported = 1; diff --git a/drivers/net/wireless/hostap/hostap_80211_rx.c b/drivers/net/wireless/hostap/hostap_80211_rx.c index 4fd73809602..d669e5956ce 100644 --- a/drivers/net/wireless/hostap/hostap_80211_rx.c +++ b/drivers/net/wireless/hostap/hostap_80211_rx.c @@ -78,6 +78,9 @@ int prism2_rx_80211(struct net_device *dev, struct sk_buff *skb, prism_header = 2; phdrlen = sizeof(struct linux_wlan_ng_cap_hdr); } + } else if (dev->type == ARPHRD_IEEE80211_RADIOTAP) { + prism_header = 3; + phdrlen = sizeof(struct hostap_radiotap_rx); } else { prism_header = 0; phdrlen = 0; @@ -165,6 +168,24 @@ hdr->f.status = s; hdr->f.len = l; hdr->f.data = d hdr->ssi_noise = htonl(rx_stats->noise); hdr->preamble = htonl(0); /* unknown */ hdr->encoding = htonl(1); /* cck */ + } else if (prism_header == 3) { + struct hostap_radiotap_rx *hdr; + hdr = (struct hostap_radiotap_rx *)skb_push(skb, phdrlen); + memset(hdr, 0, phdrlen); + hdr->hdr.it_len = cpu_to_le16(phdrlen); + hdr->hdr.it_present = + cpu_to_le32((1 << IEEE80211_RADIOTAP_TSFT) | + (1 << IEEE80211_RADIOTAP_CHANNEL) | + (1 << IEEE80211_RADIOTAP_RATE) | + (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | + (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE)); + hdr->tsft = cpu_to_le64(rx_stats->mac_time); + hdr->chan_freq = cpu_to_le16(freq_list[local->channel - 1]); + hdr->chan_flags = cpu_to_le16(IEEE80211_CHAN_CCK | + IEEE80211_CHAN_2GHZ); + hdr->rate = rx_stats->rate / 5; + hdr->dbm_antsignal = rx_stats->signal; + hdr->dbm_antnoise = rx_stats->noise; } ret = skb->len - phdrlen; diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c index cdf90c40f11..79a9bc95d2a 100644 --- a/drivers/net/wireless/hostap/hostap_hw.c +++ b/drivers/net/wireless/hostap/hostap_hw.c @@ -3204,6 +3204,7 @@ prism2_init_local_data(struct prism2_helper_functions *funcs, int card_idx, local->auth_algs = PRISM2_AUTH_OPEN | PRISM2_AUTH_SHARED_KEY; local->sram_type = -1; local->scan_channel_mask = 0xffff; + local->monitor_type = PRISM2_MONITOR_RADIOTAP; /* Initialize task queue structures */ INIT_WORK(&local->reset_queue, handle_reset_queue); diff --git a/drivers/net/wireless/hostap/hostap_ioctl.c b/drivers/net/wireless/hostap/hostap_ioctl.c index ed52d98317c..3f8b1d7036e 100644 --- a/drivers/net/wireless/hostap/hostap_ioctl.c +++ b/drivers/net/wireless/hostap/hostap_ioctl.c @@ -897,6 +897,8 @@ static void hostap_monitor_set_type(local_info_t *local) if (local->monitor_type == PRISM2_MONITOR_PRISM || local->monitor_type == PRISM2_MONITOR_CAPHDR) { dev->type = ARPHRD_IEEE80211_PRISM; + } else if (local->monitor_type == PRISM2_MONITOR_RADIOTAP) { + dev->type = ARPHRD_IEEE80211_RADIOTAP; } else { dev->type = ARPHRD_IEEE80211; } @@ -2520,7 +2522,8 @@ static int prism2_ioctl_priv_prism2_param(struct net_device *dev, case PRISM2_PARAM_MONITOR_TYPE: if (value != PRISM2_MONITOR_80211 && value != PRISM2_MONITOR_CAPHDR && - value != PRISM2_MONITOR_PRISM) { + value != PRISM2_MONITOR_PRISM && + value != PRISM2_MONITOR_RADIOTAP) { ret = -EINVAL; break; } diff --git a/drivers/net/wireless/hostap/hostap_main.c b/drivers/net/wireless/hostap/hostap_main.c index f7aec9309d0..b5213f61fb0 100644 --- a/drivers/net/wireless/hostap/hostap_main.c +++ b/drivers/net/wireless/hostap/hostap_main.c @@ -596,25 +596,7 @@ void hostap_dump_tx_header(const char *name, const struct hfa384x_tx_frame *tx) int hostap_80211_header_parse(const struct sk_buff *skb, unsigned char *haddr) { - struct hostap_interface *iface = netdev_priv(skb->dev); - local_info_t *local = iface->local; - - if (local->monitor_type == PRISM2_MONITOR_PRISM || - local->monitor_type == PRISM2_MONITOR_CAPHDR) { - const unsigned char *mac = skb_mac_header(skb); - - if (*(u32 *)mac == LWNG_CAP_DID_BASE) { - memcpy(haddr, - mac + sizeof(struct linux_wlan_ng_prism_hdr) + 10, - ETH_ALEN); /* addr2 */ - } else { /* (*(u32 *)mac == htonl(LWNG_CAPHDR_VERSION)) */ - memcpy(haddr, - mac + sizeof(struct linux_wlan_ng_cap_hdr) + 10, - ETH_ALEN); /* addr2 */ - } - } else - memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN); /* addr2 */ - + memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN); /* addr2 */ return ETH_ALEN; } diff --git a/drivers/net/wireless/hostap/hostap_wlan.h b/drivers/net/wireless/hostap/hostap_wlan.h index 15445bce2ac..ffdf4876121 100644 --- a/drivers/net/wireless/hostap/hostap_wlan.h +++ b/drivers/net/wireless/hostap/hostap_wlan.h @@ -5,6 +5,7 @@ #include <linux/netdevice.h> #include <linux/mutex.h> #include <net/iw_handler.h> +#include <net/ieee80211_radiotap.h> #include "hostap_config.h" #include "hostap_common.h" @@ -55,6 +56,17 @@ struct linux_wlan_ng_cap_hdr { __be32 encoding; } __attribute__ ((packed)); +struct hostap_radiotap_rx { + struct ieee80211_radiotap_header hdr; + __le64 tsft; + u8 rate; + u8 padding; + __le16 chan_freq; + __le16 chan_flags; + s8 dbm_antsignal; + s8 dbm_antnoise; +} __attribute__ ((packed)); + #define LWNG_CAP_DID_BASE (4 | (1 << 6)) /* section 4, group 1 */ #define LWNG_CAPHDR_VERSION 0x80211001 @@ -734,7 +746,7 @@ struct local_info { unsigned long scan_timestamp; /* Time started to scan */ enum { PRISM2_MONITOR_80211 = 0, PRISM2_MONITOR_PRISM = 1, - PRISM2_MONITOR_CAPHDR = 2 + PRISM2_MONITOR_CAPHDR = 2, PRISM2_MONITOR_RADIOTAP = 3 } monitor_type; int monitor_allow_fcserr; diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig index d7ea32f3969..b628a44057f 100644 --- a/drivers/net/wireless/iwlwifi/Kconfig +++ b/drivers/net/wireless/iwlwifi/Kconfig @@ -8,7 +8,6 @@ config IWLCORE select MAC80211_LEDS if IWLWIFI_LEDS select LEDS_CLASS if IWLWIFI_LEDS select RFKILL if IWLWIFI_RFKILL - select RFKILL_INPUT if (IWLWIFI_RFKILL && INPUT) config IWLWIFI_LEDS bool diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h index a9b3edad386..a77497809d9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h @@ -36,6 +36,10 @@ #include <linux/kernel.h> #include <net/ieee80211_radiotap.h> +/*used for rfkill*/ +#include <linux/rfkill.h> +#include <linux/input.h> + /* Hardware specific file defines the PCI IDs table for that hardware module */ extern struct pci_device_id iwl3945_hw_card_ids[]; @@ -686,6 +690,23 @@ enum { #endif +#ifdef CONFIG_IWLWIFI_RFKILL +struct iwl3945_priv; + +struct iwl3945_rfkill_mngr { + struct rfkill *rfkill; + struct input_dev *input_dev; +}; + +void iwl3945_rfkill_set_hw_state(struct iwl3945_priv *priv); +void iwl3945_rfkill_unregister(struct iwl3945_priv *priv); +int iwl3945_rfkill_init(struct iwl3945_priv *priv); +#else +static inline void iwl3945_rfkill_set_hw_state(struct iwl3945_priv *priv) {} +static inline void iwl3945_rfkill_unregister(struct iwl3945_priv *priv) {} +static inline int iwl3945_rfkill_init(struct iwl3945_priv *priv) { return 0; } +#endif + #define IWL_MAX_NUM_QUEUES IWL39_MAX_NUM_QUEUES struct iwl3945_priv { @@ -779,6 +800,10 @@ struct iwl3945_priv { struct iwl3945_init_alive_resp card_alive_init; struct iwl3945_alive_resp card_alive; +#ifdef CONFIG_IWLWIFI_RFKILL + struct iwl3945_rfkill_mngr rfkill_mngr; +#endif + #ifdef CONFIG_IWL3945_LEDS struct iwl3945_led led[IWL_LED_TRG_MAX]; unsigned long last_blink_time; diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c index 20230311728..c7ebb3bf06f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c @@ -822,9 +822,6 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev, lq_sta = (struct iwl4965_lq_sta *)sta->rate_ctrl_priv; - if (!priv->lq_mngr.lq_ready) - goto out; - if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) && !lq_sta->ibss_sta_added) goto out; @@ -1678,10 +1675,6 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, if (!sta || !sta->rate_ctrl_priv) return; - if (!priv->lq_mngr.lq_ready) { - IWL_DEBUG_RATE("still rate scaling not ready\n"); - return; - } lq_sta = (struct iwl4965_lq_sta *)sta->rate_ctrl_priv; tid = rs_tl_add_packet(lq_sta, hdr); @@ -2140,11 +2133,8 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev, lq_sta->ibss_sta_added = 1; rs_initialize_lq(priv, conf, sta); } - if (!lq_sta->ibss_sta_added) - goto done; } -done: if ((i < 0) || (i > IWL_RATE_COUNT)) { sel->rate_idx = rate_lowest_index(local, sband, sta); goto out; @@ -2279,9 +2269,6 @@ static void rs_rate_init(void *priv_rate, void *priv_sta, lq_sta->drv = priv; #endif - if (priv->assoc_station_added) - priv->lq_mngr.lq_ready = 1; - rs_initialize_lq(priv, conf, sta); } @@ -2421,7 +2408,7 @@ static void rs_clear(void *priv_rate) IWL_DEBUG_RATE("enter\n"); - priv->lq_mngr.lq_ready = 0; + /* TODO - add rate scale state reset */ IWL_DEBUG_RATE("leave\n"); } @@ -2716,13 +2703,6 @@ int iwl4965_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id) return cnt; } -void iwl4965_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id) -{ - struct iwl_priv *priv = hw->priv; - - priv->lq_mngr.lq_ready = 1; -} - int iwl4965_rate_control_register(void) { return ieee80211_rate_control_register(&rs_ops); diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.h b/drivers/net/wireless/iwlwifi/iwl-4965-rs.h index cbd12641849..9b9972885aa 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.h @@ -296,14 +296,6 @@ static inline u8 iwl4965_get_prev_ieee_rate(u8 rate_index) extern int iwl4965_fill_rs_info(struct ieee80211_hw *, char *buf, u8 sta_id); /** - * iwl4965_rate_scale_init - Initialize the rate scale table based on assoc info - * - * The specific throughput table used is based on the type of network - * the associated with, including A, B, G, and G w/ TGG protection - */ -extern void iwl4965_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id); - -/** * iwl4965_rate_control_register - Register the rate control algorithm callbacks * * Since the rate control algorithm is hardware specific, there is no need diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index ab5027345a0..8c93f8d56a7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -555,8 +555,6 @@ out: return ret; } -#define REG_RECALIB_PERIOD (60) - /* Reset differential Rx gains in NIC to prepare for chain noise calibration. * Called after every association, but this runs only once! * ... once chain noise is calibrated the first time, it's good forever. */ @@ -839,17 +837,8 @@ static int iwl4965_hw_set_hw_params(struct iwl_priv *priv) priv->hw_params.max_txq_num = priv->cfg->mod_params->num_of_queues; priv->hw_params.first_ampdu_q = IWL49_FIRST_AMPDU_QUEUE; - priv->hw_params.sw_crypto = priv->cfg->mod_params->sw_crypto; - priv->hw_params.max_rxq_size = RX_QUEUE_SIZE; - priv->hw_params.max_rxq_log = RX_QUEUE_SIZE_LOG; - if (priv->cfg->mod_params->amsdu_size_8K) - priv->hw_params.rx_buf_size = IWL_RX_BUF_SIZE_8K; - else - priv->hw_params.rx_buf_size = IWL_RX_BUF_SIZE_4K; - priv->hw_params.max_pkt_size = priv->hw_params.rx_buf_size - 256; priv->hw_params.max_stations = IWL4965_STATION_COUNT; priv->hw_params.bcast_sta_id = IWL4965_BROADCAST_ID; - priv->hw_params.max_data_size = IWL49_RTC_DATA_SIZE; priv->hw_params.max_inst_size = IWL49_RTC_INST_SIZE; priv->hw_params.max_bsm_size = BSM_SRAM_SIZE; @@ -1890,87 +1879,10 @@ static int iwl4965_is_temp_calib_needed(struct iwl_priv *priv) return 1; } -/* Calculate noise level, based on measurements during network silence just - * before arriving beacon. This measurement can be done only if we know - * exactly when to expect beacons, therefore only when we're associated. */ -static void iwl4965_rx_calc_noise(struct iwl_priv *priv) -{ - struct statistics_rx_non_phy *rx_info - = &(priv->statistics.rx.general); - int num_active_rx = 0; - int total_silence = 0; - int bcn_silence_a = - le32_to_cpu(rx_info->beacon_silence_rssi_a) & IN_BAND_FILTER; - int bcn_silence_b = - le32_to_cpu(rx_info->beacon_silence_rssi_b) & IN_BAND_FILTER; - int bcn_silence_c = - le32_to_cpu(rx_info->beacon_silence_rssi_c) & IN_BAND_FILTER; - - if (bcn_silence_a) { - total_silence += bcn_silence_a; - num_active_rx++; - } - if (bcn_silence_b) { - total_silence += bcn_silence_b; - num_active_rx++; - } - if (bcn_silence_c) { - total_silence += bcn_silence_c; - num_active_rx++; - } - - /* Average among active antennas */ - if (num_active_rx) - priv->last_rx_noise = (total_silence / num_active_rx) - 107; - else - priv->last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE; - - IWL_DEBUG_CALIB("inband silence a %u, b %u, c %u, dBm %d\n", - bcn_silence_a, bcn_silence_b, bcn_silence_c, - priv->last_rx_noise); -} - -void iwl4965_hw_rx_statistics(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) +static void iwl4965_temperature_calib(struct iwl_priv *priv) { - struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; - int change; s32 temp; - IWL_DEBUG_RX("Statistics notification received (%d vs %d).\n", - (int)sizeof(priv->statistics), pkt->len); - - change = ((priv->statistics.general.temperature != - pkt->u.stats.general.temperature) || - ((priv->statistics.flag & - STATISTICS_REPLY_FLG_FAT_MODE_MSK) != - (pkt->u.stats.flag & STATISTICS_REPLY_FLG_FAT_MODE_MSK))); - - memcpy(&priv->statistics, &pkt->u.stats, sizeof(priv->statistics)); - - set_bit(STATUS_STATISTICS, &priv->status); - - /* Reschedule the statistics timer to occur in - * REG_RECALIB_PERIOD seconds to ensure we get a - * thermal update even if the uCode doesn't give - * us one */ - mod_timer(&priv->statistics_periodic, jiffies + - msecs_to_jiffies(REG_RECALIB_PERIOD * 1000)); - - if (unlikely(!test_bit(STATUS_SCANNING, &priv->status)) && - (pkt->hdr.cmd == STATISTICS_NOTIFICATION)) { - iwl4965_rx_calc_noise(priv); - queue_work(priv->workqueue, &priv->run_time_calib_work); - } - - iwl_leds_background(priv); - - /* If the hardware hasn't reported a change in - * temperature then don't bother computing a - * calibrated temperature value */ - if (!change) - return; - temp = iwl4965_hw_get_temperature(priv); if (temp < 0) return; @@ -1996,775 +1908,6 @@ void iwl4965_hw_rx_statistics(struct iwl_priv *priv, queue_work(priv->workqueue, &priv->txpower_work); } -static void iwl4965_add_radiotap(struct iwl_priv *priv, - struct sk_buff *skb, - struct iwl4965_rx_phy_res *rx_start, - struct ieee80211_rx_status *stats, - u32 ampdu_status) -{ - s8 signal = stats->signal; - s8 noise = 0; - int rate = stats->rate_idx; - u64 tsf = stats->mactime; - __le16 antenna; - __le16 phy_flags_hw = rx_start->phy_flags; - struct iwl4965_rt_rx_hdr { - struct ieee80211_radiotap_header rt_hdr; - __le64 rt_tsf; /* TSF */ - u8 rt_flags; /* radiotap packet flags */ - u8 rt_rate; /* rate in 500kb/s */ - __le16 rt_channelMHz; /* channel in MHz */ - __le16 rt_chbitmask; /* channel bitfield */ - s8 rt_dbmsignal; /* signal in dBm, kluged to signed */ - s8 rt_dbmnoise; - u8 rt_antenna; /* antenna number */ - } __attribute__ ((packed)) *iwl4965_rt; - - /* TODO: We won't have enough headroom for HT frames. Fix it later. */ - if (skb_headroom(skb) < sizeof(*iwl4965_rt)) { - if (net_ratelimit()) - printk(KERN_ERR "not enough headroom [%d] for " - "radiotap head [%zd]\n", - skb_headroom(skb), sizeof(*iwl4965_rt)); - return; - } - - /* put radiotap header in front of 802.11 header and data */ - iwl4965_rt = (void *)skb_push(skb, sizeof(*iwl4965_rt)); - - /* initialise radiotap header */ - iwl4965_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION; - iwl4965_rt->rt_hdr.it_pad = 0; - - /* total header + data */ - put_unaligned(cpu_to_le16(sizeof(*iwl4965_rt)), - &iwl4965_rt->rt_hdr.it_len); - - /* Indicate all the fields we add to the radiotap header */ - put_unaligned(cpu_to_le32((1 << IEEE80211_RADIOTAP_TSFT) | - (1 << IEEE80211_RADIOTAP_FLAGS) | - (1 << IEEE80211_RADIOTAP_RATE) | - (1 << IEEE80211_RADIOTAP_CHANNEL) | - (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | - (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) | - (1 << IEEE80211_RADIOTAP_ANTENNA)), - &iwl4965_rt->rt_hdr.it_present); - - /* Zero the flags, we'll add to them as we go */ - iwl4965_rt->rt_flags = 0; - - put_unaligned(cpu_to_le64(tsf), &iwl4965_rt->rt_tsf); - - iwl4965_rt->rt_dbmsignal = signal; - iwl4965_rt->rt_dbmnoise = noise; - - /* Convert the channel frequency and set the flags */ - put_unaligned(cpu_to_le16(stats->freq), &iwl4965_rt->rt_channelMHz); - if (!(phy_flags_hw & RX_RES_PHY_FLAGS_BAND_24_MSK)) - put_unaligned(cpu_to_le16(IEEE80211_CHAN_OFDM | - IEEE80211_CHAN_5GHZ), - &iwl4965_rt->rt_chbitmask); - else if (phy_flags_hw & RX_RES_PHY_FLAGS_MOD_CCK_MSK) - put_unaligned(cpu_to_le16(IEEE80211_CHAN_CCK | - IEEE80211_CHAN_2GHZ), - &iwl4965_rt->rt_chbitmask); - else /* 802.11g */ - put_unaligned(cpu_to_le16(IEEE80211_CHAN_OFDM | - IEEE80211_CHAN_2GHZ), - &iwl4965_rt->rt_chbitmask); - - if (rate == -1) - iwl4965_rt->rt_rate = 0; - else - iwl4965_rt->rt_rate = iwl_rates[rate].ieee; - - /* - * "antenna number" - * - * It seems that the antenna field in the phy flags value - * is actually a bitfield. This is undefined by radiotap, - * it wants an actual antenna number but I always get "7" - * for most legacy frames I receive indicating that the - * same frame was received on all three RX chains. - * - * I think this field should be removed in favour of a - * new 802.11n radiotap field "RX chains" that is defined - * as a bitmask. - */ - antenna = phy_flags_hw & RX_RES_PHY_FLAGS_ANTENNA_MSK; - iwl4965_rt->rt_antenna = le16_to_cpu(antenna) >> 4; - - /* set the preamble flag if appropriate */ - if (phy_flags_hw & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK) - iwl4965_rt->rt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; - - stats->flag |= RX_FLAG_RADIOTAP; -} - -static void iwl_update_rx_stats(struct iwl_priv *priv, u16 fc, u16 len) -{ - /* 0 - mgmt, 1 - cnt, 2 - data */ - int idx = (fc & IEEE80211_FCTL_FTYPE) >> 2; - priv->rx_stats[idx].cnt++; - priv->rx_stats[idx].bytes += len; -} - -/* - * returns non-zero if packet should be dropped - */ -static int iwl4965_set_decrypted_flag(struct iwl_priv *priv, - struct ieee80211_hdr *hdr, - u32 decrypt_res, - struct ieee80211_rx_status *stats) -{ - u16 fc = le16_to_cpu(hdr->frame_control); - - if (priv->active_rxon.filter_flags & RXON_FILTER_DIS_DECRYPT_MSK) - return 0; - - if (!(fc & IEEE80211_FCTL_PROTECTED)) - return 0; - - IWL_DEBUG_RX("decrypt_res:0x%x\n", decrypt_res); - switch (decrypt_res & RX_RES_STATUS_SEC_TYPE_MSK) { - case RX_RES_STATUS_SEC_TYPE_TKIP: - /* The uCode has got a bad phase 1 Key, pushes the packet. - * Decryption will be done in SW. */ - if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) == - RX_RES_STATUS_BAD_KEY_TTAK) - break; - - case RX_RES_STATUS_SEC_TYPE_WEP: - if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) == - RX_RES_STATUS_BAD_ICV_MIC) { - /* bad ICV, the packet is destroyed since the - * decryption is inplace, drop it */ - IWL_DEBUG_RX("Packet destroyed\n"); - return -1; - } - case RX_RES_STATUS_SEC_TYPE_CCMP: - if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) == - RX_RES_STATUS_DECRYPT_OK) { - IWL_DEBUG_RX("hw decrypt successfully!!!\n"); - stats->flag |= RX_FLAG_DECRYPTED; - } - break; - - default: - break; - } - return 0; -} - -static u32 iwl4965_translate_rx_status(struct iwl_priv *priv, u32 decrypt_in) -{ - u32 decrypt_out = 0; - - if ((decrypt_in & RX_RES_STATUS_STATION_FOUND) == - RX_RES_STATUS_STATION_FOUND) - decrypt_out |= (RX_RES_STATUS_STATION_FOUND | - RX_RES_STATUS_NO_STATION_INFO_MISMATCH); - - decrypt_out |= (decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK); - - /* packet was not encrypted */ - if ((decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) == - RX_RES_STATUS_SEC_TYPE_NONE) - return decrypt_out; - - /* packet was encrypted with unknown alg */ - if ((decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) == - RX_RES_STATUS_SEC_TYPE_ERR) - return decrypt_out; - - /* decryption was not done in HW */ - if ((decrypt_in & RX_MPDU_RES_STATUS_DEC_DONE_MSK) != - RX_MPDU_RES_STATUS_DEC_DONE_MSK) - return decrypt_out; - - switch (decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) { - - case RX_RES_STATUS_SEC_TYPE_CCMP: - /* alg is CCM: check MIC only */ - if (!(decrypt_in & RX_MPDU_RES_STATUS_MIC_OK)) - /* Bad MIC */ - decrypt_out |= RX_RES_STATUS_BAD_ICV_MIC; - else - decrypt_out |= RX_RES_STATUS_DECRYPT_OK; - - break; - - case RX_RES_STATUS_SEC_TYPE_TKIP: - if (!(decrypt_in & RX_MPDU_RES_STATUS_TTAK_OK)) { - /* Bad TTAK */ - decrypt_out |= RX_RES_STATUS_BAD_KEY_TTAK; - break; - } - /* fall through if TTAK OK */ - default: - if (!(decrypt_in & RX_MPDU_RES_STATUS_ICV_OK)) - decrypt_out |= RX_RES_STATUS_BAD_ICV_MIC; - else - decrypt_out |= RX_RES_STATUS_DECRYPT_OK; - break; - }; - - IWL_DEBUG_RX("decrypt_in:0x%x decrypt_out = 0x%x\n", - decrypt_in, decrypt_out); - - return decrypt_out; -} - -static void iwl4965_handle_data_packet(struct iwl_priv *priv, int is_data, - int include_phy, - struct iwl_rx_mem_buffer *rxb, - struct ieee80211_rx_status *stats) -{ - struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; - struct iwl4965_rx_phy_res *rx_start = (include_phy) ? - (struct iwl4965_rx_phy_res *)&(pkt->u.raw[0]) : NULL; - struct ieee80211_hdr *hdr; - u16 len; - __le32 *rx_end; - unsigned int skblen; - u32 ampdu_status; - u32 ampdu_status_legacy; - - if (!include_phy && priv->last_phy_res[0]) - rx_start = (struct iwl4965_rx_phy_res *)&priv->last_phy_res[1]; - - if (!rx_start) { - IWL_ERROR("MPDU frame without a PHY data\n"); - return; - } - if (include_phy) { - hdr = (struct ieee80211_hdr *)((u8 *) & rx_start[1] + - rx_start->cfg_phy_cnt); - - len = le16_to_cpu(rx_start->byte_count); - - rx_end = (__le32 *) ((u8 *) & pkt->u.raw[0] + - sizeof(struct iwl4965_rx_phy_res) + - rx_start->cfg_phy_cnt + len); - - } else { - struct iwl4965_rx_mpdu_res_start *amsdu = - (struct iwl4965_rx_mpdu_res_start *)pkt->u.raw; - - hdr = (struct ieee80211_hdr *)(pkt->u.raw + - sizeof(struct iwl4965_rx_mpdu_res_start)); - len = le16_to_cpu(amsdu->byte_count); - rx_start->byte_count = amsdu->byte_count; - rx_end = (__le32 *) (((u8 *) hdr) + len); - } - /* In monitor mode allow 802.11 ACk frames (10 bytes) */ - if (len > priv->hw_params.max_pkt_size || - len < ((priv->iw_mode == IEEE80211_IF_TYPE_MNTR) ? 10 : 16)) { - IWL_WARNING("byte count out of range [16,4K] : %d\n", len); - return; - } - - ampdu_status = le32_to_cpu(*rx_end); - skblen = ((u8 *) rx_end - (u8 *) & pkt->u.raw[0]) + sizeof(u32); - - if (!include_phy) { - /* New status scheme, need to translate */ - ampdu_status_legacy = ampdu_status; - ampdu_status = iwl4965_translate_rx_status(priv, ampdu_status); - } - - /* start from MAC */ - skb_reserve(rxb->skb, (void *)hdr - (void *)pkt); - skb_put(rxb->skb, len); /* end where data ends */ - - /* We only process data packets if the interface is open */ - if (unlikely(!priv->is_open)) { - IWL_DEBUG_DROP_LIMIT - ("Dropping packet while interface is not open.\n"); - return; - } - - stats->flag = 0; - hdr = (struct ieee80211_hdr *)rxb->skb->data; - - /* in case of HW accelerated crypto and bad decryption, drop */ - if (!priv->hw_params.sw_crypto && - iwl4965_set_decrypted_flag(priv, hdr, ampdu_status, stats)) - return; - - if (priv->add_radiotap) - iwl4965_add_radiotap(priv, rxb->skb, rx_start, stats, ampdu_status); - - iwl_update_rx_stats(priv, le16_to_cpu(hdr->frame_control), len); - ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats); - priv->alloc_rxb_skb--; - rxb->skb = NULL; -} - -/* Calc max signal level (dBm) among 3 possible receivers */ -static int iwl4965_calc_rssi(struct iwl_priv *priv, - struct iwl4965_rx_phy_res *rx_resp) -{ - /* data from PHY/DSP regarding signal strength, etc., - * contents are always there, not configurable by host. */ - struct iwl4965_rx_non_cfg_phy *ncphy = - (struct iwl4965_rx_non_cfg_phy *)rx_resp->non_cfg_phy; - u32 agc = (le16_to_cpu(ncphy->agc_info) & IWL_AGC_DB_MASK) - >> IWL_AGC_DB_POS; - - u32 valid_antennae = - (le16_to_cpu(rx_resp->phy_flags) & RX_PHY_FLAGS_ANTENNAE_MASK) - >> RX_PHY_FLAGS_ANTENNAE_OFFSET; - u8 max_rssi = 0; - u32 i; - - /* Find max rssi among 3 possible receivers. - * These values are measured by the digital signal processor (DSP). - * They should stay fairly constant even as the signal strength varies, - * if the radio's automatic gain control (AGC) is working right. - * AGC value (see below) will provide the "interesting" info. */ - for (i = 0; i < 3; i++) - if (valid_antennae & (1 << i)) - max_rssi = max(ncphy->rssi_info[i << 1], max_rssi); - - IWL_DEBUG_STATS("Rssi In A %d B %d C %d Max %d AGC dB %d\n", - ncphy->rssi_info[0], ncphy->rssi_info[2], ncphy->rssi_info[4], - max_rssi, agc); - - /* dBm = max_rssi dB - agc dB - constant. - * Higher AGC (higher radio gain) means lower signal. */ - return (max_rssi - agc - IWL_RSSI_OFFSET); -} - -static void iwl4965_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id) -{ - unsigned long flags; - - spin_lock_irqsave(&priv->sta_lock, flags); - priv->stations[sta_id].sta.station_flags &= ~STA_FLG_PWR_SAVE_MSK; - priv->stations[sta_id].sta.station_flags_msk = STA_FLG_PWR_SAVE_MSK; - priv->stations[sta_id].sta.sta.modify_mask = 0; - priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; - spin_unlock_irqrestore(&priv->sta_lock, flags); - - iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); -} - -static void iwl4965_update_ps_mode(struct iwl_priv *priv, u16 ps_bit, u8 *addr) -{ - /* FIXME: need locking over ps_status ??? */ - u8 sta_id = iwl_find_station(priv, addr); - - if (sta_id != IWL_INVALID_STATION) { - u8 sta_awake = priv->stations[sta_id]. - ps_status == STA_PS_STATUS_WAKE; - - if (sta_awake && ps_bit) - priv->stations[sta_id].ps_status = STA_PS_STATUS_SLEEP; - else if (!sta_awake && !ps_bit) { - iwl4965_sta_modify_ps_wake(priv, sta_id); - priv->stations[sta_id].ps_status = STA_PS_STATUS_WAKE; - } - } -} -#ifdef CONFIG_IWLWIFI_DEBUG - -/** - * iwl4965_dbg_report_frame - dump frame to syslog during debug sessions - * - * You may hack this function to show different aspects of received frames, - * including selective frame dumps. - * group100 parameter selects whether to show 1 out of 100 good frames. - * - * TODO: This was originally written for 3945, need to audit for - * proper operation with 4965. - */ -static void iwl4965_dbg_report_frame(struct iwl_priv *priv, - struct iwl_rx_packet *pkt, - struct ieee80211_hdr *header, int group100) -{ - u32 to_us; - u32 print_summary = 0; - u32 print_dump = 0; /* set to 1 to dump all frames' contents */ - u32 hundred = 0; - u32 dataframe = 0; - __le16 fc; - u16 seq_ctl; - u16 channel; - u16 phy_flags; - int rate_sym; - u16 length; - u16 status; - u16 bcn_tmr; - u32 tsf_low; - u64 tsf; - u8 rssi; - u8 agc; - u16 sig_avg; - u16 noise_diff; - struct iwl4965_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt); - struct iwl4965_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt); - struct iwl4965_rx_frame_end *rx_end = IWL_RX_END(pkt); - u8 *data = IWL_RX_DATA(pkt); - - if (likely(!(priv->debug_level & IWL_DL_RX))) - return; - - /* MAC header */ - fc = header->frame_control; - seq_ctl = le16_to_cpu(header->seq_ctrl); - - /* metadata */ - channel = le16_to_cpu(rx_hdr->channel); - phy_flags = le16_to_cpu(rx_hdr->phy_flags); - rate_sym = rx_hdr->rate; - length = le16_to_cpu(rx_hdr->len); - - /* end-of-frame status and timestamp */ - status = le32_to_cpu(rx_end->status); - bcn_tmr = le32_to_cpu(rx_end->beacon_timestamp); - tsf_low = le64_to_cpu(rx_end->timestamp) & 0x0ffffffff; - tsf = le64_to_cpu(rx_end->timestamp); - - /* signal statistics */ - rssi = rx_stats->rssi; - agc = rx_stats->agc; - sig_avg = le16_to_cpu(rx_stats->sig_avg); - noise_diff = le16_to_cpu(rx_stats->noise_diff); - - to_us = !compare_ether_addr(header->addr1, priv->mac_addr); - - /* if data frame is to us and all is good, - * (optionally) print summary for only 1 out of every 100 */ - if (to_us && (fc & ~cpu_to_le16(IEEE80211_FCTL_PROTECTED)) == - cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FTYPE_DATA)) { - dataframe = 1; - if (!group100) - print_summary = 1; /* print each frame */ - else if (priv->framecnt_to_us < 100) { - priv->framecnt_to_us++; - print_summary = 0; - } else { - priv->framecnt_to_us = 0; - print_summary = 1; - hundred = 1; - } - } else { - /* print summary for all other frames */ - print_summary = 1; - } - - if (print_summary) { - char *title; - int rate_idx; - u32 bitrate; - - if (hundred) - title = "100Frames"; - else if (ieee80211_has_retry(fc)) - title = "Retry"; - else if (ieee80211_is_assoc_resp(fc)) - title = "AscRsp"; - else if (ieee80211_is_reassoc_resp(fc)) - title = "RasRsp"; - else if (ieee80211_is_probe_resp(fc)) { - title = "PrbRsp"; - print_dump = 1; /* dump frame contents */ - } else if (ieee80211_is_beacon(fc)) { - title = "Beacon"; - print_dump = 1; /* dump frame contents */ - } else if (ieee80211_is_atim(fc)) - title = "ATIM"; - else if (ieee80211_is_auth(fc)) - title = "Auth"; - else if (ieee80211_is_deauth(fc)) - title = "DeAuth"; - else if (ieee80211_is_disassoc(fc)) - title = "DisAssoc"; - else - title = "Frame"; - - rate_idx = iwl_hwrate_to_plcp_idx(rate_sym); - if (unlikely(rate_idx == -1)) - bitrate = 0; - else - bitrate = iwl_rates[rate_idx].ieee / 2; - - /* print frame summary. - * MAC addresses show just the last byte (for brevity), - * but you can hack it to show more, if you'd like to. */ - if (dataframe) - IWL_DEBUG_RX("%s: mhd=0x%04x, dst=0x%02x, " - "len=%u, rssi=%d, chnl=%d, rate=%u, \n", - title, le16_to_cpu(fc), header->addr1[5], - length, rssi, channel, bitrate); - else { - /* src/dst addresses assume managed mode */ - IWL_DEBUG_RX("%s: 0x%04x, dst=0x%02x, " - "src=0x%02x, rssi=%u, tim=%lu usec, " - "phy=0x%02x, chnl=%d\n", - title, le16_to_cpu(fc), header->addr1[5], - header->addr3[5], rssi, - tsf_low - priv->scan_start_tsf, - phy_flags, channel); - } - } - if (print_dump) - iwl_print_hex_dump(priv, IWL_DL_RX, data, length); -} -#else -static inline void iwl4965_dbg_report_frame(struct iwl_priv *priv, - struct iwl_rx_packet *pkt, - struct ieee80211_hdr *header, - int group100) -{ -} -#endif - - - -/* Called for REPLY_RX (legacy ABG frames), or - * REPLY_RX_MPDU_CMD (HT high-throughput N frames). */ -void iwl4965_rx_reply_rx(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) -{ - struct ieee80211_hdr *header; - struct ieee80211_rx_status rx_status; - struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; - /* Use phy data (Rx signal strength, etc.) contained within - * this rx packet for legacy frames, - * or phy data cached from REPLY_RX_PHY_CMD for HT frames. */ - int include_phy = (pkt->hdr.cmd == REPLY_RX); - struct iwl4965_rx_phy_res *rx_start = (include_phy) ? - (struct iwl4965_rx_phy_res *)&(pkt->u.raw[0]) : - (struct iwl4965_rx_phy_res *)&priv->last_phy_res[1]; - __le32 *rx_end; - unsigned int len = 0; - u16 fc; - u8 network_packet; - - rx_status.mactime = le64_to_cpu(rx_start->timestamp); - rx_status.freq = - ieee80211_channel_to_frequency(le16_to_cpu(rx_start->channel)); - rx_status.band = (rx_start->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ? - IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ; - rx_status.rate_idx = - iwl_hwrate_to_plcp_idx(le32_to_cpu(rx_start->rate_n_flags)); - if (rx_status.band == IEEE80211_BAND_5GHZ) - rx_status.rate_idx -= IWL_FIRST_OFDM_RATE; - - rx_status.antenna = 0; - rx_status.flag = 0; - - if ((unlikely(rx_start->cfg_phy_cnt > 20))) { - IWL_DEBUG_DROP("dsp size out of range [0,20]: %d/n", - rx_start->cfg_phy_cnt); - return; - } - - if (!include_phy) { - if (priv->last_phy_res[0]) - rx_start = (struct iwl4965_rx_phy_res *) - &priv->last_phy_res[1]; - else - rx_start = NULL; - } - - if (!rx_start) { - IWL_ERROR("MPDU frame without a PHY data\n"); - return; - } - - if (include_phy) { - header = (struct ieee80211_hdr *)((u8 *) & rx_start[1] - + rx_start->cfg_phy_cnt); - - len = le16_to_cpu(rx_start->byte_count); - rx_end = (__le32 *)(pkt->u.raw + rx_start->cfg_phy_cnt + - sizeof(struct iwl4965_rx_phy_res) + len); - } else { - struct iwl4965_rx_mpdu_res_start *amsdu = - (struct iwl4965_rx_mpdu_res_start *)pkt->u.raw; - - header = (void *)(pkt->u.raw + - sizeof(struct iwl4965_rx_mpdu_res_start)); - len = le16_to_cpu(amsdu->byte_count); - rx_end = (__le32 *) (pkt->u.raw + - sizeof(struct iwl4965_rx_mpdu_res_start) + len); - } - - if (!(*rx_end & RX_RES_STATUS_NO_CRC32_ERROR) || - !(*rx_end & RX_RES_STATUS_NO_RXE_OVERFLOW)) { - IWL_DEBUG_RX("Bad CRC or FIFO: 0x%08X.\n", - le32_to_cpu(*rx_end)); - return; - } - - priv->ucode_beacon_time = le32_to_cpu(rx_start->beacon_time_stamp); - - /* Find max signal strength (dBm) among 3 antenna/receiver chains */ - rx_status.signal = iwl4965_calc_rssi(priv, rx_start); - - /* Meaningful noise values are available only from beacon statistics, - * which are gathered only when associated, and indicate noise - * only for the associated network channel ... - * Ignore these noise values while scanning (other channels) */ - if (iwl_is_associated(priv) && - !test_bit(STATUS_SCANNING, &priv->status)) { - rx_status.noise = priv->last_rx_noise; - rx_status.qual = iwl4965_calc_sig_qual(rx_status.signal, - rx_status.noise); - } else { - rx_status.noise = IWL_NOISE_MEAS_NOT_AVAILABLE; - rx_status.qual = iwl4965_calc_sig_qual(rx_status.signal, 0); - } - - /* Reset beacon noise level if not associated. */ - if (!iwl_is_associated(priv)) - priv->last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE; - - /* Set "1" to report good data frames in groups of 100 */ - /* FIXME: need to optimze the call: */ - iwl4965_dbg_report_frame(priv, pkt, header, 1); - - IWL_DEBUG_STATS_LIMIT("Rssi %d, noise %d, qual %d, TSF %llu\n", - rx_status.signal, rx_status.noise, rx_status.signal, - (unsigned long long)rx_status.mactime); - - - if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) { - iwl4965_handle_data_packet(priv, 1, include_phy, - rxb, &rx_status); - return; - } - - network_packet = iwl4965_is_network_packet(priv, header); - if (network_packet) { - priv->last_rx_rssi = rx_status.signal; - priv->last_beacon_time = priv->ucode_beacon_time; - priv->last_tsf = le64_to_cpu(rx_start->timestamp); - } - - fc = le16_to_cpu(header->frame_control); - switch (fc & IEEE80211_FCTL_FTYPE) { - case IEEE80211_FTYPE_MGMT: - if (priv->iw_mode == IEEE80211_IF_TYPE_AP) - iwl4965_update_ps_mode(priv, fc & IEEE80211_FCTL_PM, - header->addr2); - iwl4965_handle_data_packet(priv, 0, include_phy, rxb, &rx_status); - break; - - case IEEE80211_FTYPE_CTL: - switch (fc & IEEE80211_FCTL_STYPE) { - case IEEE80211_STYPE_BACK_REQ: - IWL_DEBUG_HT("IEEE80211_STYPE_BACK_REQ arrived\n"); - iwl4965_handle_data_packet(priv, 0, include_phy, - rxb, &rx_status); - break; - default: - break; - } - break; - - case IEEE80211_FTYPE_DATA: { - DECLARE_MAC_BUF(mac1); - DECLARE_MAC_BUF(mac2); - DECLARE_MAC_BUF(mac3); - - if (priv->iw_mode == IEEE80211_IF_TYPE_AP) - iwl4965_update_ps_mode(priv, fc & IEEE80211_FCTL_PM, - header->addr2); - - if (unlikely(!network_packet)) - IWL_DEBUG_DROP("Dropping (non network): " - "%s, %s, %s\n", - print_mac(mac1, header->addr1), - print_mac(mac2, header->addr2), - print_mac(mac3, header->addr3)); - else if (unlikely(iwl4965_is_duplicate_packet(priv, header))) - IWL_DEBUG_DROP("Dropping (dup): %s, %s, %s\n", - print_mac(mac1, header->addr1), - print_mac(mac2, header->addr2), - print_mac(mac3, header->addr3)); - else - iwl4965_handle_data_packet(priv, 1, include_phy, rxb, - &rx_status); - break; - } - default: - break; - - } -} - -/** - * iwl4965_tx_status_reply_compressed_ba - Update tx status from block-ack - * - * Go through block-ack's bitmap of ACK'd frames, update driver's record of - * ACK vs. not. This gets sent to mac80211, then to rate scaling algo. - */ -static int iwl4965_tx_status_reply_compressed_ba(struct iwl_priv *priv, - struct iwl_ht_agg *agg, - struct iwl4965_compressed_ba_resp* - ba_resp) - -{ - int i, sh, ack; - u16 seq_ctl = le16_to_cpu(ba_resp->seq_ctl); - u16 scd_flow = le16_to_cpu(ba_resp->scd_flow); - u64 bitmap; - int successes = 0; - struct ieee80211_tx_info *info; - - if (unlikely(!agg->wait_for_ba)) { - IWL_ERROR("Received BA when not expected\n"); - return -EINVAL; - } - - /* Mark that the expected block-ack response arrived */ - agg->wait_for_ba = 0; - IWL_DEBUG_TX_REPLY("BA %d %d\n", agg->start_idx, ba_resp->seq_ctl); - - /* Calculate shift to align block-ack bits with our Tx window bits */ - sh = agg->start_idx - SEQ_TO_INDEX(seq_ctl>>4); - if (sh < 0) /* tbw something is wrong with indices */ - sh += 0x100; - - /* don't use 64-bit values for now */ - bitmap = le64_to_cpu(ba_resp->bitmap) >> sh; - - if (agg->frame_count > (64 - sh)) { - IWL_DEBUG_TX_REPLY("more frames than bitmap size"); - return -1; - } - - /* check for success or failure according to the - * transmitted bitmap and block-ack bitmap */ - bitmap &= agg->bitmap; - - /* For each frame attempted in aggregation, - * update driver's record of tx frame's status. */ - for (i = 0; i < agg->frame_count ; i++) { - ack = bitmap & (1 << i); - successes += !!ack; - IWL_DEBUG_TX_REPLY("%s ON i=%d idx=%d raw=%d\n", - ack? "ACK":"NACK", i, (agg->start_idx + i) & 0xff, - agg->start_idx + i); - } - - info = IEEE80211_SKB_CB(priv->txq[scd_flow].txb[agg->start_idx].skb[0]); - memset(&info->status, 0, sizeof(info->status)); - info->flags = IEEE80211_TX_STAT_ACK; - info->flags |= IEEE80211_TX_STAT_AMPDU; - info->status.ampdu_ack_map = successes; - info->status.ampdu_ack_len = agg->frame_count; - iwl_hwrate_to_tx_control(priv, agg->rate_n_flags, info); - - IWL_DEBUG_TX_REPLY("Bitmap %llx\n", (unsigned long long)bitmap); - - return 0; -} - /** * iwl4965_tx_queue_stop_scheduler - Stop queue, but keep configuration */ @@ -2816,82 +1959,6 @@ static int iwl4965_txq_agg_disable(struct iwl_priv *priv, u16 txq_id, return 0; } - -/** - * iwl4965_rx_reply_compressed_ba - Handler for REPLY_COMPRESSED_BA - * - * Handles block-acknowledge notification from device, which reports success - * of frames sent via aggregation. - */ -static void iwl4965_rx_reply_compressed_ba(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) -{ - struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; - struct iwl4965_compressed_ba_resp *ba_resp = &pkt->u.compressed_ba; - int index; - struct iwl_tx_queue *txq = NULL; - struct iwl_ht_agg *agg; - DECLARE_MAC_BUF(mac); - - /* "flow" corresponds to Tx queue */ - u16 scd_flow = le16_to_cpu(ba_resp->scd_flow); - - /* "ssn" is start of block-ack Tx window, corresponds to index - * (in Tx queue's circular buffer) of first TFD/frame in window */ - u16 ba_resp_scd_ssn = le16_to_cpu(ba_resp->scd_ssn); - - if (scd_flow >= priv->hw_params.max_txq_num) { - IWL_ERROR("BUG_ON scd_flow is bigger than number of queues"); - return; - } - - txq = &priv->txq[scd_flow]; - agg = &priv->stations[ba_resp->sta_id].tid[ba_resp->tid].agg; - - /* Find index just before block-ack window */ - index = iwl_queue_dec_wrap(ba_resp_scd_ssn & 0xff, txq->q.n_bd); - - /* TODO: Need to get this copy more safely - now good for debug */ - - IWL_DEBUG_TX_REPLY("REPLY_COMPRESSED_BA [%d]Received from %s, " - "sta_id = %d\n", - agg->wait_for_ba, - print_mac(mac, (u8*) &ba_resp->sta_addr_lo32), - ba_resp->sta_id); - IWL_DEBUG_TX_REPLY("TID = %d, SeqCtl = %d, bitmap = 0x%llx, scd_flow = " - "%d, scd_ssn = %d\n", - ba_resp->tid, - ba_resp->seq_ctl, - (unsigned long long)le64_to_cpu(ba_resp->bitmap), - ba_resp->scd_flow, - ba_resp->scd_ssn); - IWL_DEBUG_TX_REPLY("DAT start_idx = %d, bitmap = 0x%llx \n", - agg->start_idx, - (unsigned long long)agg->bitmap); - - /* Update driver's record of ACK vs. not for each frame in window */ - iwl4965_tx_status_reply_compressed_ba(priv, agg, ba_resp); - - /* Release all TFDs before the SSN, i.e. all TFDs in front of - * block-ack window (we assume that they've been successfully - * transmitted ... if not, it's too late anyway). */ - if (txq->q.read_ptr != (ba_resp_scd_ssn & 0xff)) { - /* calculate mac80211 ampdu sw queue to wake */ - int ampdu_q = - scd_flow - priv->hw_params.first_ampdu_q + priv->hw->queues; - int freed = iwl_tx_queue_reclaim(priv, scd_flow, index); - priv->stations[ba_resp->sta_id]. - tid[ba_resp->tid].tfds_in_queue -= freed; - if (iwl_queue_space(&txq->q) > txq->q.low_mark && - priv->mac80211_registered && - agg->state != IWL_EMPTYING_HW_QUEUE_DELBA) - ieee80211_wake_queue(priv->hw, ampdu_q); - - iwl_txq_check_empty(priv, ba_resp->sta_id, - ba_resp->tid, scd_flow); - } -} - /** * iwl4965_tx_queue_set_q2ratid - Map unique receiver/tid combination to a queue */ @@ -2986,49 +2053,6 @@ static int iwl4965_txq_agg_enable(struct iwl_priv *priv, int txq_id, return 0; } -static int iwl4965_rx_agg_start(struct iwl_priv *priv, - const u8 *addr, int tid, u16 ssn) -{ - unsigned long flags; - int sta_id; - - sta_id = iwl_find_station(priv, addr); - if (sta_id == IWL_INVALID_STATION) - return -ENXIO; - - spin_lock_irqsave(&priv->sta_lock, flags); - priv->stations[sta_id].sta.station_flags_msk = 0; - priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_ADDBA_TID_MSK; - priv->stations[sta_id].sta.add_immediate_ba_tid = (u8)tid; - priv->stations[sta_id].sta.add_immediate_ba_ssn = cpu_to_le16(ssn); - priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; - spin_unlock_irqrestore(&priv->sta_lock, flags); - - return iwl_send_add_sta(priv, &priv->stations[sta_id].sta, - CMD_ASYNC); -} - -static int iwl4965_rx_agg_stop(struct iwl_priv *priv, - const u8 *addr, int tid) -{ - unsigned long flags; - int sta_id; - - sta_id = iwl_find_station(priv, addr); - if (sta_id == IWL_INVALID_STATION) - return -ENXIO; - - spin_lock_irqsave(&priv->sta_lock, flags); - priv->stations[sta_id].sta.station_flags_msk = 0; - priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_DELBA_TID_MSK; - priv->stations[sta_id].sta.remove_immediate_ba_tid = (u8)tid; - priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; - spin_unlock_irqrestore(&priv->sta_lock, flags); - - return iwl_send_add_sta(priv, &priv->stations[sta_id].sta, - CMD_ASYNC); -} - int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw, enum ieee80211_ampdu_mlme_action action, const u8 *addr, u16 tid, u16 *ssn) @@ -3039,13 +2063,16 @@ int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw, IWL_DEBUG_HT("A-MPDU action on addr %s tid %d\n", print_mac(mac, addr), tid); + if (!(priv->cfg->sku & IWL_SKU_N)) + return -EACCES; + switch (action) { case IEEE80211_AMPDU_RX_START: IWL_DEBUG_HT("start Rx\n"); - return iwl4965_rx_agg_start(priv, addr, tid, *ssn); + return iwl_rx_agg_start(priv, addr, tid, *ssn); case IEEE80211_AMPDU_RX_STOP: IWL_DEBUG_HT("stop Rx\n"); - return iwl4965_rx_agg_stop(priv, addr, tid); + return iwl_rx_agg_stop(priv, addr, tid); case IEEE80211_AMPDU_TX_START: IWL_DEBUG_HT("start Tx\n"); return iwl_tx_agg_start(priv, addr, tid, ssn); @@ -3320,11 +2347,9 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv, static void iwl4965_rx_handler_setup(struct iwl_priv *priv) { /* Legacy Rx frames */ - priv->rx_handlers[REPLY_RX] = iwl4965_rx_reply_rx; + priv->rx_handlers[REPLY_RX] = iwl_rx_reply_rx; /* Tx response */ priv->rx_handlers[REPLY_TX] = iwl4965_rx_reply_tx; - /* block ack */ - priv->rx_handlers[REPLY_COMPRESSED_BA] = iwl4965_rx_reply_compressed_ba; } static void iwl4965_setup_deferred_work(struct iwl_priv *priv) @@ -3391,6 +2416,7 @@ static struct iwl_lib_ops iwl4965_lib = { .set_power = iwl4965_set_power, .send_tx_power = iwl4965_send_tx_power, .update_chain_flags = iwl4965_update_chain_flags, + .temperature = iwl4965_temperature_calib, }; static struct iwl_ops iwl4965_ops = { @@ -3422,11 +2448,14 @@ MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)"); module_param_named(queues_num, iwl4965_mod_params.num_of_queues, int, 0444); MODULE_PARM_DESC(queues_num, "number of hw queues."); - /* QoS */ module_param_named(qos_enable, iwl4965_mod_params.enable_qos, int, 0444); MODULE_PARM_DESC(qos_enable, "enable all QoS functionality"); +/* 11n */ +module_param_named(11n_disable, iwl4965_mod_params.disable_11n, int, 0444); +MODULE_PARM_DESC(11n_disable, "disable 11n functionality"); module_param_named(amsdu_size_8K, iwl4965_mod_params.amsdu_size_8K, int, 0444); MODULE_PARM_DESC(amsdu_size_8K, "enable 8K amsdu size"); + module_param_named(fw_restart4965, iwl4965_mod_params.restart_fw, int, 0444); MODULE_PARM_DESC(fw_restart4965, "restart firmware in case of error"); diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 438c3812c39..7cc73e9a711 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -675,7 +675,7 @@ static void iwl5000_init_alive_start(struct iwl_priv *priv) goto restart; } - iwlcore_clear_stations_table(priv); + iwl_clear_stations_table(priv); ret = priv->cfg->ops->lib->alive_notify(priv); if (ret) { IWL_WARNING("Could not complete ALIVE transition: %d\n", ret); @@ -807,11 +807,8 @@ static int iwl5000_alive_notify(struct iwl_priv *priv) iwl5000_send_Xtal_calib(priv); - if (priv->ucode_type == UCODE_RT) { + if (priv->ucode_type == UCODE_RT) iwl5000_send_calib_results(priv); - set_bit(STATUS_READY, &priv->status); - priv->is_open = 1; - } return 0; } @@ -827,19 +824,11 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) priv->hw_params.max_txq_num = priv->cfg->mod_params->num_of_queues; priv->hw_params.first_ampdu_q = IWL50_FIRST_AMPDU_QUEUE; - priv->hw_params.sw_crypto = priv->cfg->mod_params->sw_crypto; - priv->hw_params.max_rxq_size = RX_QUEUE_SIZE; - priv->hw_params.max_rxq_log = RX_QUEUE_SIZE_LOG; - if (priv->cfg->mod_params->amsdu_size_8K) - priv->hw_params.rx_buf_size = IWL_RX_BUF_SIZE_8K; - else - priv->hw_params.rx_buf_size = IWL_RX_BUF_SIZE_4K; - priv->hw_params.max_pkt_size = priv->hw_params.rx_buf_size - 256; priv->hw_params.max_stations = IWL5000_STATION_COUNT; priv->hw_params.bcast_sta_id = IWL5000_BROADCAST_ID; priv->hw_params.max_data_size = IWL50_RTC_DATA_SIZE; priv->hw_params.max_inst_size = IWL50_RTC_INST_SIZE; - priv->hw_params.max_bsm_size = BSM_SRAM_SIZE; + priv->hw_params.max_bsm_size = 0; priv->hw_params.fat_channel = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ); priv->hw_params.sens = &iwl5000_sensitivity; @@ -1426,13 +1415,18 @@ static int iwl5000_send_tx_power(struct iwl_priv *priv) /* half dBm need to multiply */ tx_power_cmd.global_lmt = (s8)(2 * priv->tx_power_user_lmt); - tx_power_cmd.flags = 0; + tx_power_cmd.flags = IWL50_TX_POWER_NO_CLOSED; tx_power_cmd.srv_chan_lmt = IWL50_TX_POWER_AUTO; return iwl_send_cmd_pdu_async(priv, REPLY_TX_POWER_DBM_CMD, sizeof(tx_power_cmd), &tx_power_cmd, NULL); } +static void iwl5000_temperature(struct iwl_priv *priv) +{ + /* store temperature from statistics (in Celsius) */ + priv->temperature = le32_to_cpu(priv->statistics.general.temperature); +} static struct iwl_hcmd_ops iwl5000_hcmd = { .rxon_assoc = iwl5000_send_rxon_assoc, @@ -1462,6 +1456,7 @@ static struct iwl_lib_ops iwl5000_lib = { .init_alive_start = iwl5000_init_alive_start, .alive_notify = iwl5000_alive_notify, .send_tx_power = iwl5000_send_tx_power, + .temperature = iwl5000_temperature, .apm_ops = { .init = iwl5000_apm_init, .reset = iwl5000_apm_reset, @@ -1541,6 +1536,8 @@ module_param_named(queues_num50, iwl50_mod_params.num_of_queues, int, 0444); MODULE_PARM_DESC(queues_num50, "number of hw queues in 50xx series"); module_param_named(qos_enable50, iwl50_mod_params.enable_qos, int, 0444); MODULE_PARM_DESC(qos_enable50, "enable all 50XX QoS functionality"); +module_param_named(11n_disable50, iwl50_mod_params.disable_11n, int, 0444); +MODULE_PARM_DESC(11n_disable50, "disable 50XX 11n functionality"); module_param_named(amsdu_size_8K50, iwl50_mod_params.amsdu_size_8K, int, 0444); MODULE_PARM_DESC(amsdu_size_8K50, "enable 8K amsdu size in 50XX series"); module_param_named(fw_restart50, iwl50_mod_params.restart_fw, int, 0444); diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.c b/drivers/net/wireless/iwlwifi/iwl-calib.c index 48f58000b64..ef49440bd7f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-calib.c +++ b/drivers/net/wireless/iwlwifi/iwl-calib.c @@ -470,7 +470,7 @@ void iwl_init_sensitivity(struct iwl_priv *priv) EXPORT_SYMBOL(iwl_init_sensitivity); void iwl_sensitivity_calibration(struct iwl_priv *priv, - struct iwl4965_notif_statistics *resp) + struct iwl_notif_statistics *resp) { u32 rx_enable_time; u32 fa_cck; @@ -584,7 +584,7 @@ EXPORT_SYMBOL(iwl_sensitivity_calibration); * 2) Differential rx gain settings to balance the 3 receivers. */ void iwl_chain_noise_calibration(struct iwl_priv *priv, - struct iwl4965_notif_statistics *stat_resp) + struct iwl_notif_statistics *stat_resp) { struct iwl_chain_noise_data *data = NULL; diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.h b/drivers/net/wireless/iwlwifi/iwl-calib.h index 5524a29e22d..94c8e316382 100644 --- a/drivers/net/wireless/iwlwifi/iwl-calib.h +++ b/drivers/net/wireless/iwlwifi/iwl-calib.h @@ -67,9 +67,9 @@ #include "iwl-commands.h" void iwl_chain_noise_calibration(struct iwl_priv *priv, - struct iwl4965_notif_statistics *stat_resp); + struct iwl_notif_statistics *stat_resp); void iwl_sensitivity_calibration(struct iwl_priv *priv, - struct iwl4965_notif_statistics *resp); + struct iwl_notif_statistics *resp); void iwl_init_sensitivity(struct iwl_priv *priv); void iwl_reset_run_time_calib(struct iwl_priv *priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 920dfc1b2db..fe05d60ebe6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -336,6 +336,8 @@ struct iwl4965_tx_power_db { * struct iwl5000_tx_power_dbm_cmd */ #define IWL50_TX_POWER_AUTO 0x7f +#define IWL50_TX_POWER_NO_CLOSED (0x1 << 6) + struct iwl5000_tx_power_dbm_cmd { s8 global_lmt; /*in half-dBm (e.g. 30 = 15 dBm) */ u8 flags; @@ -1534,7 +1536,7 @@ struct iwl5000_tx_resp { * * Reports Block-Acknowledge from recipient station */ -struct iwl4965_compressed_ba_resp { +struct iwl_compressed_ba_resp { __le32 sta_addr_lo32; __le16 sta_addr_hi16; __le16 reserved; @@ -2504,7 +2506,7 @@ struct statistics_general { */ #define IWL_STATS_CONF_CLEAR_STATS __constant_cpu_to_le32(0x1) /* see above */ #define IWL_STATS_CONF_DISABLE_NOTIF __constant_cpu_to_le32(0x2)/* see above */ -struct iwl4965_statistics_cmd { +struct iwl_statistics_cmd { __le32 configuration_flags; /* IWL_STATS_CONF_* */ } __attribute__ ((packed)); @@ -2525,7 +2527,7 @@ struct iwl4965_statistics_cmd { */ #define STATISTICS_REPLY_FLG_BAND_24G_MSK __constant_cpu_to_le32(0x2) #define STATISTICS_REPLY_FLG_FAT_MODE_MSK __constant_cpu_to_le32(0x8) -struct iwl4965_notif_statistics { +struct iwl_notif_statistics { __le32 flag; struct statistics_rx rx; struct statistics_tx tx; @@ -2998,8 +3000,8 @@ struct iwl_rx_packet { struct iwl_rem_sta_resp rem_sta; struct iwl4965_sleep_notification sleep_notif; struct iwl4965_spectrum_resp spectrum; - struct iwl4965_notif_statistics stats; - struct iwl4965_compressed_ba_resp compressed_ba; + struct iwl_notif_statistics stats; + struct iwl_compressed_ba_resp compressed_ba; struct iwl4965_missed_beacon_notif missed_beacon; struct iwl5000_calibration calib; __le32 status; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index eb74a40a62e..eee220cf52a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -273,22 +273,27 @@ int iwl_hw_nic_init(struct iwl_priv *priv) EXPORT_SYMBOL(iwl_hw_nic_init); /** - * iwlcore_clear_stations_table - Clear the driver's station table + * iwl_clear_stations_table - Clear the driver's station table * * NOTE: This does not clear or otherwise alter the device's station table. */ -void iwlcore_clear_stations_table(struct iwl_priv *priv) +void iwl_clear_stations_table(struct iwl_priv *priv) { unsigned long flags; spin_lock_irqsave(&priv->sta_lock, flags); + if (iwl_is_alive(priv) && + !test_bit(STATUS_EXIT_PENDING, &priv->status) && + iwl_send_cmd_pdu_async(priv, REPLY_REMOVE_ALL_STA, 0, NULL, NULL)) + IWL_ERROR("Couldn't clear the station table\n"); + priv->num_stations = 0; memset(priv->stations, 0, sizeof(priv->stations)); spin_unlock_irqrestore(&priv->sta_lock, flags); } -EXPORT_SYMBOL(iwlcore_clear_stations_table); +EXPORT_SYMBOL(iwl_clear_stations_table); void iwl_reset_qos(struct iwl_priv *priv) { @@ -490,7 +495,9 @@ static int iwlcore_init_geos(struct iwl_priv *priv) sband->bitrates = &rates[IWL_FIRST_OFDM_RATE]; sband->n_bitrates = IWL_RATE_COUNT - IWL_FIRST_OFDM_RATE; - iwlcore_init_ht_hw_capab(priv, &sband->ht_info, IEEE80211_BAND_5GHZ); + if (priv->cfg->sku & IWL_SKU_N) + iwlcore_init_ht_hw_capab(priv, &sband->ht_info, + IEEE80211_BAND_5GHZ); sband = &priv->bands[IEEE80211_BAND_2GHZ]; sband->channels = channels; @@ -498,7 +505,9 @@ static int iwlcore_init_geos(struct iwl_priv *priv) sband->bitrates = rates; sband->n_bitrates = IWL_RATE_COUNT; - iwlcore_init_ht_hw_capab(priv, &sband->ht_info, IEEE80211_BAND_2GHZ); + if (priv->cfg->sku & IWL_SKU_N) + iwlcore_init_ht_hw_capab(priv, &sband->ht_info, + IEEE80211_BAND_2GHZ); priv->ieee_channels = channels; priv->ieee_rates = rates; @@ -814,8 +823,9 @@ int iwl_setup_mac(struct iwl_priv *priv) IEEE80211_HW_NOISE_DBM; /* Default value; 4 EDCA QOS priorities */ hw->queues = 4; - /* Enhanced value; more queues, to support 11n aggregation */ - hw->ampdu_queues = 12; + /* queues to support 11n aggregation */ + if (priv->cfg->sku & IWL_SKU_N) + hw->ampdu_queues = 12; hw->conf.beacon_int = 100; @@ -837,11 +847,28 @@ int iwl_setup_mac(struct iwl_priv *priv) } EXPORT_SYMBOL(iwl_setup_mac); +int iwl_set_hw_params(struct iwl_priv *priv) +{ + priv->hw_params.sw_crypto = priv->cfg->mod_params->sw_crypto; + priv->hw_params.max_rxq_size = RX_QUEUE_SIZE; + priv->hw_params.max_rxq_log = RX_QUEUE_SIZE_LOG; + if (priv->cfg->mod_params->amsdu_size_8K) + priv->hw_params.rx_buf_size = IWL_RX_BUF_SIZE_8K; + else + priv->hw_params.rx_buf_size = IWL_RX_BUF_SIZE_4K; + priv->hw_params.max_pkt_size = priv->hw_params.rx_buf_size - 256; + + if (priv->cfg->mod_params->disable_11n) + priv->cfg->sku &= ~IWL_SKU_N; + + /* Device-specific setup */ + return priv->cfg->ops->lib->set_hw_params(priv); +} +EXPORT_SYMBOL(iwl_set_hw_params); int iwl_init_drv(struct iwl_priv *priv) { int ret; - int i; priv->retry_rate = 1; priv->ibss_beacon = NULL; @@ -852,15 +879,12 @@ int iwl_init_drv(struct iwl_priv *priv) spin_lock_init(&priv->hcmd_lock); spin_lock_init(&priv->lq_mngr.lock); - for (i = 0; i < IWL_IBSS_MAC_HASH_SIZE; i++) - INIT_LIST_HEAD(&priv->ibss_mac_hash[i]); - INIT_LIST_HEAD(&priv->free_frames); mutex_init(&priv->mutex); /* Clear the driver's (not device's) station table */ - iwlcore_clear_stations_table(priv); + iwl_clear_stations_table(priv); priv->data_retry_limit = -1; priv->ieee_channels = NULL; @@ -1383,7 +1407,14 @@ int iwl_radio_kill_sw_enable_radio(struct iwl_priv *priv) spin_lock_irqsave(&priv->lock, flags); iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); - clear_bit(STATUS_RF_KILL_SW, &priv->status); + /* 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 */ @@ -1401,8 +1432,10 @@ int iwl_radio_kill_sw_enable_radio(struct iwl_priv *priv) return 0; } - if (priv->is_open) - queue_work(priv->workqueue, &priv->restart); + /* 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); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 2838093b445..eb4abe1ebbd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -140,6 +140,7 @@ struct iwl_lib_ops { int (*set_power)(struct iwl_priv *priv, void *cmd); int (*send_tx_power) (struct iwl_priv *priv); void (*update_chain_flags)(struct iwl_priv *priv); + void (*temperature) (struct iwl_priv *priv); /* eeprom operations (as defined in iwl-eeprom.h) */ struct iwl_eeprom_ops eeprom_ops; }; @@ -157,6 +158,7 @@ struct iwl_mod_params { int disable_hw_scan; /* def: 0 = use h/w scan */ int num_of_queues; /* def: HW dependent */ int enable_qos; /* def: 1 = use quality of service */ + int disable_11n; /* def: 0 = disable 11n capabilities */ int amsdu_size_8K; /* def: 1 = enable 8K amsdu size */ int antenna; /* def: 0 = both antennas (use diversity) */ int restart_fw; /* def: 1 = restart firmware */ @@ -179,7 +181,7 @@ struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg, struct ieee80211_ops *hw_ops); void iwl_hw_detect(struct iwl_priv *priv); -void iwlcore_clear_stations_table(struct iwl_priv *priv); +void iwl_clear_stations_table(struct iwl_priv *priv); void iwl_free_calib_results(struct iwl_priv *priv); void iwl_reset_qos(struct iwl_priv *priv); void iwl_set_rxon_chain(struct iwl_priv *priv); @@ -191,6 +193,7 @@ u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv, struct ieee80211_ht_info *sta_ht_inf); int iwl_hw_nic_init(struct iwl_priv *priv); int iwl_setup_mac(struct iwl_priv *priv); +int iwl_set_hw_params(struct iwl_priv *priv); int iwl_init_drv(struct iwl_priv *priv); void iwl_uninit_drv(struct iwl_priv *priv); /* "keep warm" functions */ @@ -209,6 +212,8 @@ int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq); void iwl_rx_replenish(struct iwl_priv *priv); int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq); +int iwl_rx_agg_start(struct iwl_priv *priv, const u8 *addr, int tid, u16 ssn); +int iwl_rx_agg_stop(struct iwl_priv *priv, const u8 *addr, int tid); /* FIXME: remove when TX is moved to iwl core */ int iwl_rx_queue_restock(struct iwl_priv *priv); int iwl_rx_queue_space(const struct iwl_rx_queue *q); @@ -218,6 +223,8 @@ int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index); /* Handlers */ void iwl_rx_missed_beacon_notif(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); +void iwl_rx_statistics(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb); /* TX helpers */ @@ -368,7 +375,13 @@ extern void iwl_rf_kill_ct_config(struct iwl_priv *priv); extern int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags); extern int iwl_verify_ucode(struct iwl_priv *priv); extern int iwl_send_lq_cmd(struct iwl_priv *priv, - struct iwl_link_quality_cmd *lq, u8 flags); + struct iwl_link_quality_cmd *lq, u8 flags); +extern void iwl_rx_reply_rx(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb); +extern void iwl_rx_reply_rx_phy(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb); +void iwl_rx_reply_compressed_ba(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb); static inline int iwl_send_rxon_assoc(struct iwl_priv *priv) { diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 81ff4c2c6a5..d1289cfc213 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -591,11 +591,6 @@ extern int iwl_send_add_sta(struct iwl_priv *priv, struct iwl_addsta_cmd *sta, u8 flags); u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr, int is_ap, u8 flags, struct ieee80211_ht_info *ht_info); -extern int iwl4965_is_network_packet(struct iwl_priv *priv, - struct ieee80211_hdr *header); -extern int iwl4965_is_duplicate_packet(struct iwl_priv *priv, - struct ieee80211_hdr *header); -extern int iwl4965_calc_sig_qual(int rssi_dbm, int noise_dbm); extern unsigned int iwl4965_fill_beacon_frame(struct iwl_priv *priv, struct ieee80211_hdr *hdr, const u8 *dest, int left); @@ -624,11 +619,7 @@ extern int iwl_rxq_stop(struct iwl_priv *priv); extern void iwl_txq_ctx_stop(struct iwl_priv *priv); extern unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv, struct iwl_frame *frame, u8 rate); -extern void iwl4965_hw_rx_statistics(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb); extern void iwl4965_disable_events(struct iwl_priv *priv); -extern void iwl4965_rx_reply_rx(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb); extern int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel); extern int iwl_queue_space(const struct iwl_queue *q); @@ -702,7 +693,6 @@ struct iwl4965_lq_mngr { unsigned long stamp_last; u32 flush_time; u32 tx_packets; - u8 lq_ready; }; /* Sensitivity and chain noise calibration */ @@ -994,7 +984,7 @@ struct iwl_priv { struct iwl_power_mgr power_data; - struct iwl4965_notif_statistics statistics; + struct iwl_notif_statistics statistics; unsigned long last_statistics_time; /* context information */ @@ -1026,14 +1016,6 @@ struct iwl_priv { u32 last_beacon_time; u64 last_tsf; - /* Duplicate packet detection */ - u16 last_seq_num; - u16 last_frag_num; - unsigned long last_packet_time; - - /* Hash table for finding stations in IBSS network */ - struct list_head ibss_mac_hash[IWL_IBSS_MAC_HASH_SIZE]; - /* eeprom */ u8 *eeprom; struct iwl_eeprom_calib_info *calib_info; diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c index 6c537360820..8fa991b7202 100644 --- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c +++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c @@ -93,6 +93,7 @@ const char *get_cmd_string(u8 cmd) IWL_CMD(CALIBRATION_CFG_CMD); IWL_CMD(CALIBRATION_RES_NOTIFICATION); IWL_CMD(CALIBRATION_COMPLETE_NOTIFICATION); + IWL_CMD(REPLY_TX_POWER_DBM_CMD); default: return "UNKNOWN"; diff --git a/drivers/net/wireless/iwlwifi/iwl-rfkill.c b/drivers/net/wireless/iwlwifi/iwl-rfkill.c index ffefbb487e1..aa9f31eadab 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rfkill.c +++ b/drivers/net/wireless/iwlwifi/iwl-rfkill.c @@ -50,7 +50,7 @@ static int iwl_rfkill_soft_rf_kill(void *data, enum rfkill_state state) if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return 0; - IWL_DEBUG_RF_KILL("we recieved soft RFKILL set to state %d\n", state); + IWL_DEBUG_RF_KILL("we received soft RFKILL set to state %d\n", state); mutex_lock(&priv->mutex); switch (state) { @@ -98,36 +98,11 @@ int iwl_rfkill_init(struct iwl_priv *priv) priv->rfkill_mngr.rfkill->dev.class->suspend = NULL; priv->rfkill_mngr.rfkill->dev.class->resume = NULL; -#if defined(CONFIG_RFKILL_INPUT) || defined(CONFIG_RFKILL_INPUT_MODULE) - priv->rfkill_mngr.input_dev = input_allocate_device(); - if (!priv->rfkill_mngr.input_dev) { - IWL_ERROR("Unable to allocate rfkill input device.\n"); - ret = -ENOMEM; - goto freed_rfkill; - } - - priv->rfkill_mngr.input_dev->name = priv->cfg->name; - priv->rfkill_mngr.input_dev->phys = wiphy_name(priv->hw->wiphy); - priv->rfkill_mngr.input_dev->id.bustype = BUS_HOST; - priv->rfkill_mngr.input_dev->id.vendor = priv->pci_dev->vendor; - priv->rfkill_mngr.input_dev->dev.parent = device; - priv->rfkill_mngr.input_dev->evbit[0] = BIT(EV_KEY); - set_bit(KEY_WLAN, priv->rfkill_mngr.input_dev->keybit); -#endif - ret = rfkill_register(priv->rfkill_mngr.rfkill); if (ret) { IWL_ERROR("Unable to register rfkill: %d\n", ret); - goto free_input_dev; - } - -#if defined(CONFIG_RFKILL_INPUT) || defined(CONFIG_RFKILL_INPUT_MODULE) - ret = input_register_device(priv->rfkill_mngr.input_dev); - if (ret) { - IWL_ERROR("Unable to register rfkill input device: %d\n", ret); goto unregister_rfkill; } -#endif IWL_DEBUG_RF_KILL("RFKILL initialization complete.\n"); return ret; @@ -136,12 +111,6 @@ unregister_rfkill: rfkill_unregister(priv->rfkill_mngr.rfkill); priv->rfkill_mngr.rfkill = NULL; -free_input_dev: -#if defined(CONFIG_RFKILL_INPUT) || defined(CONFIG_RFKILL_INPUT_MODULE) - input_free_device(priv->rfkill_mngr.input_dev); - priv->rfkill_mngr.input_dev = NULL; -#endif - freed_rfkill: if (priv->rfkill_mngr.rfkill != NULL) rfkill_free(priv->rfkill_mngr.rfkill); @@ -156,13 +125,6 @@ EXPORT_SYMBOL(iwl_rfkill_init); void iwl_rfkill_unregister(struct iwl_priv *priv) { -#if defined(CONFIG_RFKILL_INPUT) || defined(CONFIG_RFKILL_INPUT_MODULE) - if (priv->rfkill_mngr.input_dev) - input_unregister_device(priv->rfkill_mngr.input_dev); - input_free_device(priv->rfkill_mngr.input_dev); - priv->rfkill_mngr.input_dev = NULL; -#endif - if (priv->rfkill_mngr.rfkill) rfkill_unregister(priv->rfkill_mngr.rfkill); @@ -173,7 +135,6 @@ EXPORT_SYMBOL(iwl_rfkill_unregister); /* set rf-kill to the right state. */ void iwl_rfkill_set_hw_state(struct iwl_priv *priv) { - if (!priv->rfkill_mngr.rfkill) return; diff --git a/drivers/net/wireless/iwlwifi/iwl-rfkill.h b/drivers/net/wireless/iwlwifi/iwl-rfkill.h index b3c04dba45c..00692d2e9bd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rfkill.h +++ b/drivers/net/wireless/iwlwifi/iwl-rfkill.h @@ -31,12 +31,10 @@ struct iwl_priv; #include <linux/rfkill.h> -#include <linux/input.h> #ifdef CONFIG_IWLWIFI_RFKILL struct iwl_rfkill_mngr { struct rfkill *rfkill; - struct input_dev *input_dev; }; void iwl_rfkill_set_hw_state(struct iwl_priv *priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index c24844802a8..3e8500ecf59 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -27,6 +27,7 @@ * *****************************************************************************/ +#include <linux/etherdevice.h> #include <net/mac80211.h> #include "iwl-eeprom.h" #include "iwl-dev.h" @@ -466,3 +467,858 @@ void iwl_rx_missed_beacon_notif(struct iwl_priv *priv, } } EXPORT_SYMBOL(iwl_rx_missed_beacon_notif); + +int iwl_rx_agg_start(struct iwl_priv *priv, const u8 *addr, int tid, u16 ssn) +{ + unsigned long flags; + int sta_id; + + sta_id = iwl_find_station(priv, addr); + if (sta_id == IWL_INVALID_STATION) + return -ENXIO; + + spin_lock_irqsave(&priv->sta_lock, flags); + priv->stations[sta_id].sta.station_flags_msk = 0; + priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_ADDBA_TID_MSK; + priv->stations[sta_id].sta.add_immediate_ba_tid = (u8)tid; + priv->stations[sta_id].sta.add_immediate_ba_ssn = cpu_to_le16(ssn); + priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; + spin_unlock_irqrestore(&priv->sta_lock, flags); + + return iwl_send_add_sta(priv, &priv->stations[sta_id].sta, + CMD_ASYNC); +} +EXPORT_SYMBOL(iwl_rx_agg_start); + +int iwl_rx_agg_stop(struct iwl_priv *priv, const u8 *addr, int tid) +{ + unsigned long flags; + int sta_id; + + sta_id = iwl_find_station(priv, addr); + if (sta_id == IWL_INVALID_STATION) + return -ENXIO; + + spin_lock_irqsave(&priv->sta_lock, flags); + priv->stations[sta_id].sta.station_flags_msk = 0; + priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_DELBA_TID_MSK; + priv->stations[sta_id].sta.remove_immediate_ba_tid = (u8)tid; + priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; + spin_unlock_irqrestore(&priv->sta_lock, flags); + + return iwl_send_add_sta(priv, &priv->stations[sta_id].sta, + CMD_ASYNC); +} +EXPORT_SYMBOL(iwl_rx_agg_stop); + + +/* Calculate noise level, based on measurements during network silence just + * before arriving beacon. This measurement can be done only if we know + * exactly when to expect beacons, therefore only when we're associated. */ +static void iwl_rx_calc_noise(struct iwl_priv *priv) +{ + struct statistics_rx_non_phy *rx_info + = &(priv->statistics.rx.general); + int num_active_rx = 0; + int total_silence = 0; + int bcn_silence_a = + le32_to_cpu(rx_info->beacon_silence_rssi_a) & IN_BAND_FILTER; + int bcn_silence_b = + le32_to_cpu(rx_info->beacon_silence_rssi_b) & IN_BAND_FILTER; + int bcn_silence_c = + le32_to_cpu(rx_info->beacon_silence_rssi_c) & IN_BAND_FILTER; + + if (bcn_silence_a) { + total_silence += bcn_silence_a; + num_active_rx++; + } + if (bcn_silence_b) { + total_silence += bcn_silence_b; + num_active_rx++; + } + if (bcn_silence_c) { + total_silence += bcn_silence_c; + num_active_rx++; + } + + /* Average among active antennas */ + if (num_active_rx) + priv->last_rx_noise = (total_silence / num_active_rx) - 107; + else + priv->last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE; + + IWL_DEBUG_CALIB("inband silence a %u, b %u, c %u, dBm %d\n", + bcn_silence_a, bcn_silence_b, bcn_silence_c, + priv->last_rx_noise); +} + +#define REG_RECALIB_PERIOD (60) + +void iwl_rx_statistics(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + int change; + struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + + IWL_DEBUG_RX("Statistics notification received (%d vs %d).\n", + (int)sizeof(priv->statistics), pkt->len); + + change = ((priv->statistics.general.temperature != + pkt->u.stats.general.temperature) || + ((priv->statistics.flag & + STATISTICS_REPLY_FLG_FAT_MODE_MSK) != + (pkt->u.stats.flag & STATISTICS_REPLY_FLG_FAT_MODE_MSK))); + + memcpy(&priv->statistics, &pkt->u.stats, sizeof(priv->statistics)); + + set_bit(STATUS_STATISTICS, &priv->status); + + /* Reschedule the statistics timer to occur in + * REG_RECALIB_PERIOD seconds to ensure we get a + * thermal update even if the uCode doesn't give + * us one */ + mod_timer(&priv->statistics_periodic, jiffies + + msecs_to_jiffies(REG_RECALIB_PERIOD * 1000)); + + if (unlikely(!test_bit(STATUS_SCANNING, &priv->status)) && + (pkt->hdr.cmd == STATISTICS_NOTIFICATION)) { + iwl_rx_calc_noise(priv); + queue_work(priv->workqueue, &priv->run_time_calib_work); + } + + iwl_leds_background(priv); + + if (priv->cfg->ops->lib->temperature && change) + priv->cfg->ops->lib->temperature(priv); +} +EXPORT_SYMBOL(iwl_rx_statistics); + +#define PERFECT_RSSI (-20) /* dBm */ +#define WORST_RSSI (-95) /* dBm */ +#define RSSI_RANGE (PERFECT_RSSI - WORST_RSSI) + +/* Calculate an indication of rx signal quality (a percentage, not dBm!). + * See http://www.ces.clemson.edu/linux/signal_quality.shtml for info + * about formulas used below. */ +static int iwl_calc_sig_qual(int rssi_dbm, int noise_dbm) +{ + int sig_qual; + int degradation = PERFECT_RSSI - rssi_dbm; + + /* If we get a noise measurement, use signal-to-noise ratio (SNR) + * as indicator; formula is (signal dbm - noise dbm). + * SNR at or above 40 is a great signal (100%). + * Below that, scale to fit SNR of 0 - 40 dB within 0 - 100% indicator. + * Weakest usable signal is usually 10 - 15 dB SNR. */ + if (noise_dbm) { + if (rssi_dbm - noise_dbm >= 40) + return 100; + else if (rssi_dbm < noise_dbm) + return 0; + sig_qual = ((rssi_dbm - noise_dbm) * 5) / 2; + + /* Else use just the signal level. + * This formula is a least squares fit of data points collected and + * compared with a reference system that had a percentage (%) display + * for signal quality. */ + } else + sig_qual = (100 * (RSSI_RANGE * RSSI_RANGE) - degradation * + (15 * RSSI_RANGE + 62 * degradation)) / + (RSSI_RANGE * RSSI_RANGE); + + if (sig_qual > 100) + sig_qual = 100; + else if (sig_qual < 1) + sig_qual = 0; + + return sig_qual; +} + +#ifdef CONFIG_IWLWIFI_DEBUG + +/** + * iwl_dbg_report_frame - dump frame to syslog during debug sessions + * + * You may hack this function to show different aspects of received frames, + * including selective frame dumps. + * group100 parameter selects whether to show 1 out of 100 good frames. + * + * TODO: This was originally written for 3945, need to audit for + * proper operation with 4965. + */ +static void iwl_dbg_report_frame(struct iwl_priv *priv, + struct iwl_rx_packet *pkt, + struct ieee80211_hdr *header, int group100) +{ + u32 to_us; + u32 print_summary = 0; + u32 print_dump = 0; /* set to 1 to dump all frames' contents */ + u32 hundred = 0; + u32 dataframe = 0; + __le16 fc; + u16 seq_ctl; + u16 channel; + u16 phy_flags; + int rate_sym; + u16 length; + u16 status; + u16 bcn_tmr; + u32 tsf_low; + u64 tsf; + u8 rssi; + u8 agc; + u16 sig_avg; + u16 noise_diff; + struct iwl4965_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt); + struct iwl4965_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt); + struct iwl4965_rx_frame_end *rx_end = IWL_RX_END(pkt); + u8 *data = IWL_RX_DATA(pkt); + + if (likely(!(priv->debug_level & IWL_DL_RX))) + return; + + /* MAC header */ + fc = header->frame_control; + seq_ctl = le16_to_cpu(header->seq_ctrl); + + /* metadata */ + channel = le16_to_cpu(rx_hdr->channel); + phy_flags = le16_to_cpu(rx_hdr->phy_flags); + rate_sym = rx_hdr->rate; + length = le16_to_cpu(rx_hdr->len); + + /* end-of-frame status and timestamp */ + status = le32_to_cpu(rx_end->status); + bcn_tmr = le32_to_cpu(rx_end->beacon_timestamp); + tsf_low = le64_to_cpu(rx_end->timestamp) & 0x0ffffffff; + tsf = le64_to_cpu(rx_end->timestamp); + + /* signal statistics */ + rssi = rx_stats->rssi; + agc = rx_stats->agc; + sig_avg = le16_to_cpu(rx_stats->sig_avg); + noise_diff = le16_to_cpu(rx_stats->noise_diff); + + to_us = !compare_ether_addr(header->addr1, priv->mac_addr); + + /* if data frame is to us and all is good, + * (optionally) print summary for only 1 out of every 100 */ + if (to_us && (fc & ~cpu_to_le16(IEEE80211_FCTL_PROTECTED)) == + cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FTYPE_DATA)) { + dataframe = 1; + if (!group100) + print_summary = 1; /* print each frame */ + else if (priv->framecnt_to_us < 100) { + priv->framecnt_to_us++; + print_summary = 0; + } else { + priv->framecnt_to_us = 0; + print_summary = 1; + hundred = 1; + } + } else { + /* print summary for all other frames */ + print_summary = 1; + } + + if (print_summary) { + char *title; + int rate_idx; + u32 bitrate; + + if (hundred) + title = "100Frames"; + else if (ieee80211_has_retry(fc)) + title = "Retry"; + else if (ieee80211_is_assoc_resp(fc)) + title = "AscRsp"; + else if (ieee80211_is_reassoc_resp(fc)) + title = "RasRsp"; + else if (ieee80211_is_probe_resp(fc)) { + title = "PrbRsp"; + print_dump = 1; /* dump frame contents */ + } else if (ieee80211_is_beacon(fc)) { + title = "Beacon"; + print_dump = 1; /* dump frame contents */ + } else if (ieee80211_is_atim(fc)) + title = "ATIM"; + else if (ieee80211_is_auth(fc)) + title = "Auth"; + else if (ieee80211_is_deauth(fc)) + title = "DeAuth"; + else if (ieee80211_is_disassoc(fc)) + title = "DisAssoc"; + else + title = "Frame"; + + rate_idx = iwl_hwrate_to_plcp_idx(rate_sym); + if (unlikely(rate_idx == -1)) + bitrate = 0; + else + bitrate = iwl_rates[rate_idx].ieee / 2; + + /* print frame summary. + * MAC addresses show just the last byte (for brevity), + * but you can hack it to show more, if you'd like to. */ + if (dataframe) + IWL_DEBUG_RX("%s: mhd=0x%04x, dst=0x%02x, " + "len=%u, rssi=%d, chnl=%d, rate=%u, \n", + title, le16_to_cpu(fc), header->addr1[5], + length, rssi, channel, bitrate); + else { + /* src/dst addresses assume managed mode */ + IWL_DEBUG_RX("%s: 0x%04x, dst=0x%02x, " + "src=0x%02x, rssi=%u, tim=%lu usec, " + "phy=0x%02x, chnl=%d\n", + title, le16_to_cpu(fc), header->addr1[5], + header->addr3[5], rssi, + tsf_low - priv->scan_start_tsf, + phy_flags, channel); + } + } + if (print_dump) + iwl_print_hex_dump(priv, IWL_DL_RX, data, length); +} +#else +static inline void iwl_dbg_report_frame(struct iwl_priv *priv, + struct iwl_rx_packet *pkt, + struct ieee80211_hdr *header, + int group100) +{ +} +#endif + +static void iwl_add_radiotap(struct iwl_priv *priv, + struct sk_buff *skb, + struct iwl4965_rx_phy_res *rx_start, + struct ieee80211_rx_status *stats, + u32 ampdu_status) +{ + s8 signal = stats->signal; + s8 noise = 0; + int rate = stats->rate_idx; + u64 tsf = stats->mactime; + __le16 antenna; + __le16 phy_flags_hw = rx_start->phy_flags; + struct iwl4965_rt_rx_hdr { + struct ieee80211_radiotap_header rt_hdr; + __le64 rt_tsf; /* TSF */ + u8 rt_flags; /* radiotap packet flags */ + u8 rt_rate; /* rate in 500kb/s */ + __le16 rt_channelMHz; /* channel in MHz */ + __le16 rt_chbitmask; /* channel bitfield */ + s8 rt_dbmsignal; /* signal in dBm, kluged to signed */ + s8 rt_dbmnoise; + u8 rt_antenna; /* antenna number */ + } __attribute__ ((packed)) *iwl4965_rt; + + /* TODO: We won't have enough headroom for HT frames. Fix it later. */ + if (skb_headroom(skb) < sizeof(*iwl4965_rt)) { + if (net_ratelimit()) + printk(KERN_ERR "not enough headroom [%d] for " + "radiotap head [%zd]\n", + skb_headroom(skb), sizeof(*iwl4965_rt)); + return; + } + + /* put radiotap header in front of 802.11 header and data */ + iwl4965_rt = (void *)skb_push(skb, sizeof(*iwl4965_rt)); + + /* initialise radiotap header */ + iwl4965_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION; + iwl4965_rt->rt_hdr.it_pad = 0; + + /* total header + data */ + put_unaligned(cpu_to_le16(sizeof(*iwl4965_rt)), + &iwl4965_rt->rt_hdr.it_len); + + /* Indicate all the fields we add to the radiotap header */ + put_unaligned(cpu_to_le32((1 << IEEE80211_RADIOTAP_TSFT) | + (1 << IEEE80211_RADIOTAP_FLAGS) | + (1 << IEEE80211_RADIOTAP_RATE) | + (1 << IEEE80211_RADIOTAP_CHANNEL) | + (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | + (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) | + (1 << IEEE80211_RADIOTAP_ANTENNA)), + &iwl4965_rt->rt_hdr.it_present); + + /* Zero the flags, we'll add to them as we go */ + iwl4965_rt->rt_flags = 0; + + put_unaligned(cpu_to_le64(tsf), &iwl4965_rt->rt_tsf); + + iwl4965_rt->rt_dbmsignal = signal; + iwl4965_rt->rt_dbmnoise = noise; + + /* Convert the channel frequency and set the flags */ + put_unaligned(cpu_to_le16(stats->freq), &iwl4965_rt->rt_channelMHz); + if (!(phy_flags_hw & RX_RES_PHY_FLAGS_BAND_24_MSK)) + put_unaligned(cpu_to_le16(IEEE80211_CHAN_OFDM | + IEEE80211_CHAN_5GHZ), + &iwl4965_rt->rt_chbitmask); + else if (phy_flags_hw & RX_RES_PHY_FLAGS_MOD_CCK_MSK) + put_unaligned(cpu_to_le16(IEEE80211_CHAN_CCK | + IEEE80211_CHAN_2GHZ), + &iwl4965_rt->rt_chbitmask); + else /* 802.11g */ + put_unaligned(cpu_to_le16(IEEE80211_CHAN_OFDM | + IEEE80211_CHAN_2GHZ), + &iwl4965_rt->rt_chbitmask); + + if (rate == -1) + iwl4965_rt->rt_rate = 0; + else + iwl4965_rt->rt_rate = iwl_rates[rate].ieee; + + /* + * "antenna number" + * + * It seems that the antenna field in the phy flags value + * is actually a bitfield. This is undefined by radiotap, + * it wants an actual antenna number but I always get "7" + * for most legacy frames I receive indicating that the + * same frame was received on all three RX chains. + * + * I think this field should be removed in favour of a + * new 802.11n radiotap field "RX chains" that is defined + * as a bitmask. + */ + antenna = phy_flags_hw & RX_RES_PHY_FLAGS_ANTENNA_MSK; + iwl4965_rt->rt_antenna = le16_to_cpu(antenna) >> 4; + + /* set the preamble flag if appropriate */ + if (phy_flags_hw & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK) + iwl4965_rt->rt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; + + stats->flag |= RX_FLAG_RADIOTAP; +} + +static void iwl_update_rx_stats(struct iwl_priv *priv, u16 fc, u16 len) +{ + /* 0 - mgmt, 1 - cnt, 2 - data */ + int idx = (fc & IEEE80211_FCTL_FTYPE) >> 2; + priv->rx_stats[idx].cnt++; + priv->rx_stats[idx].bytes += len; +} + +/* + * returns non-zero if packet should be dropped + */ +static int iwl_set_decrypted_flag(struct iwl_priv *priv, + struct ieee80211_hdr *hdr, + u32 decrypt_res, + struct ieee80211_rx_status *stats) +{ + u16 fc = le16_to_cpu(hdr->frame_control); + + if (priv->active_rxon.filter_flags & RXON_FILTER_DIS_DECRYPT_MSK) + return 0; + + if (!(fc & IEEE80211_FCTL_PROTECTED)) + return 0; + + IWL_DEBUG_RX("decrypt_res:0x%x\n", decrypt_res); + switch (decrypt_res & RX_RES_STATUS_SEC_TYPE_MSK) { + case RX_RES_STATUS_SEC_TYPE_TKIP: + /* The uCode has got a bad phase 1 Key, pushes the packet. + * Decryption will be done in SW. */ + if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) == + RX_RES_STATUS_BAD_KEY_TTAK) + break; + + case RX_RES_STATUS_SEC_TYPE_WEP: + if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) == + RX_RES_STATUS_BAD_ICV_MIC) { + /* bad ICV, the packet is destroyed since the + * decryption is inplace, drop it */ + IWL_DEBUG_RX("Packet destroyed\n"); + return -1; + } + case RX_RES_STATUS_SEC_TYPE_CCMP: + if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) == + RX_RES_STATUS_DECRYPT_OK) { + IWL_DEBUG_RX("hw decrypt successfully!!!\n"); + stats->flag |= RX_FLAG_DECRYPTED; + } + break; + + default: + break; + } + return 0; +} + +static u32 iwl_translate_rx_status(struct iwl_priv *priv, u32 decrypt_in) +{ + u32 decrypt_out = 0; + + if ((decrypt_in & RX_RES_STATUS_STATION_FOUND) == + RX_RES_STATUS_STATION_FOUND) + decrypt_out |= (RX_RES_STATUS_STATION_FOUND | + RX_RES_STATUS_NO_STATION_INFO_MISMATCH); + + decrypt_out |= (decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK); + + /* packet was not encrypted */ + if ((decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) == + RX_RES_STATUS_SEC_TYPE_NONE) + return decrypt_out; + + /* packet was encrypted with unknown alg */ + if ((decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) == + RX_RES_STATUS_SEC_TYPE_ERR) + return decrypt_out; + + /* decryption was not done in HW */ + if ((decrypt_in & RX_MPDU_RES_STATUS_DEC_DONE_MSK) != + RX_MPDU_RES_STATUS_DEC_DONE_MSK) + return decrypt_out; + + switch (decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) { + + case RX_RES_STATUS_SEC_TYPE_CCMP: + /* alg is CCM: check MIC only */ + if (!(decrypt_in & RX_MPDU_RES_STATUS_MIC_OK)) + /* Bad MIC */ + decrypt_out |= RX_RES_STATUS_BAD_ICV_MIC; + else + decrypt_out |= RX_RES_STATUS_DECRYPT_OK; + + break; + + case RX_RES_STATUS_SEC_TYPE_TKIP: + if (!(decrypt_in & RX_MPDU_RES_STATUS_TTAK_OK)) { + /* Bad TTAK */ + decrypt_out |= RX_RES_STATUS_BAD_KEY_TTAK; + break; + } + /* fall through if TTAK OK */ + default: + if (!(decrypt_in & RX_MPDU_RES_STATUS_ICV_OK)) + decrypt_out |= RX_RES_STATUS_BAD_ICV_MIC; + else + decrypt_out |= RX_RES_STATUS_DECRYPT_OK; + break; + }; + + IWL_DEBUG_RX("decrypt_in:0x%x decrypt_out = 0x%x\n", + decrypt_in, decrypt_out); + + return decrypt_out; +} + +static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv, + int include_phy, + struct iwl_rx_mem_buffer *rxb, + struct ieee80211_rx_status *stats) +{ + struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + struct iwl4965_rx_phy_res *rx_start = (include_phy) ? + (struct iwl4965_rx_phy_res *)&(pkt->u.raw[0]) : NULL; + struct ieee80211_hdr *hdr; + u16 len; + __le32 *rx_end; + unsigned int skblen; + u32 ampdu_status; + u32 ampdu_status_legacy; + + if (!include_phy && priv->last_phy_res[0]) + rx_start = (struct iwl4965_rx_phy_res *)&priv->last_phy_res[1]; + + if (!rx_start) { + IWL_ERROR("MPDU frame without a PHY data\n"); + return; + } + if (include_phy) { + hdr = (struct ieee80211_hdr *)((u8 *) &rx_start[1] + + rx_start->cfg_phy_cnt); + + len = le16_to_cpu(rx_start->byte_count); + + rx_end = (__le32 *) ((u8 *) &pkt->u.raw[0] + + sizeof(struct iwl4965_rx_phy_res) + + rx_start->cfg_phy_cnt + len); + + } else { + struct iwl4965_rx_mpdu_res_start *amsdu = + (struct iwl4965_rx_mpdu_res_start *)pkt->u.raw; + + hdr = (struct ieee80211_hdr *)(pkt->u.raw + + sizeof(struct iwl4965_rx_mpdu_res_start)); + len = le16_to_cpu(amsdu->byte_count); + rx_start->byte_count = amsdu->byte_count; + rx_end = (__le32 *) (((u8 *) hdr) + len); + } + + ampdu_status = le32_to_cpu(*rx_end); + skblen = ((u8 *) rx_end - (u8 *) &pkt->u.raw[0]) + sizeof(u32); + + if (!include_phy) { + /* New status scheme, need to translate */ + ampdu_status_legacy = ampdu_status; + ampdu_status = iwl_translate_rx_status(priv, ampdu_status); + } + + /* start from MAC */ + skb_reserve(rxb->skb, (void *)hdr - (void *)pkt); + skb_put(rxb->skb, len); /* end where data ends */ + + /* We only process data packets if the interface is open */ + if (unlikely(!priv->is_open)) { + IWL_DEBUG_DROP_LIMIT + ("Dropping packet while interface is not open.\n"); + return; + } + + hdr = (struct ieee80211_hdr *)rxb->skb->data; + + /* in case of HW accelerated crypto and bad decryption, drop */ + if (!priv->hw_params.sw_crypto && + iwl_set_decrypted_flag(priv, hdr, ampdu_status, stats)) + return; + + if (priv->add_radiotap) + iwl_add_radiotap(priv, rxb->skb, rx_start, stats, ampdu_status); + + iwl_update_rx_stats(priv, le16_to_cpu(hdr->frame_control), len); + ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats); + priv->alloc_rxb_skb--; + rxb->skb = NULL; +} + +/* Calc max signal level (dBm) among 3 possible receivers */ +static int iwl_calc_rssi(struct iwl_priv *priv, + struct iwl4965_rx_phy_res *rx_resp) +{ + /* data from PHY/DSP regarding signal strength, etc., + * contents are always there, not configurable by host. */ + struct iwl4965_rx_non_cfg_phy *ncphy = + (struct iwl4965_rx_non_cfg_phy *)rx_resp->non_cfg_phy; + u32 agc = (le16_to_cpu(ncphy->agc_info) & IWL_AGC_DB_MASK) + >> IWL_AGC_DB_POS; + + u32 valid_antennae = + (le16_to_cpu(rx_resp->phy_flags) & RX_PHY_FLAGS_ANTENNAE_MASK) + >> RX_PHY_FLAGS_ANTENNAE_OFFSET; + u8 max_rssi = 0; + u32 i; + + /* Find max rssi among 3 possible receivers. + * These values are measured by the digital signal processor (DSP). + * They should stay fairly constant even as the signal strength varies, + * if the radio's automatic gain control (AGC) is working right. + * AGC value (see below) will provide the "interesting" info. */ + for (i = 0; i < 3; i++) + if (valid_antennae & (1 << i)) + max_rssi = max(ncphy->rssi_info[i << 1], max_rssi); + + IWL_DEBUG_STATS("Rssi In A %d B %d C %d Max %d AGC dB %d\n", + ncphy->rssi_info[0], ncphy->rssi_info[2], ncphy->rssi_info[4], + max_rssi, agc); + + /* dBm = max_rssi dB - agc dB - constant. + * Higher AGC (higher radio gain) means lower signal. */ + return max_rssi - agc - IWL_RSSI_OFFSET; +} + +static void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->sta_lock, flags); + priv->stations[sta_id].sta.station_flags &= ~STA_FLG_PWR_SAVE_MSK; + priv->stations[sta_id].sta.station_flags_msk = STA_FLG_PWR_SAVE_MSK; + priv->stations[sta_id].sta.sta.modify_mask = 0; + priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; + spin_unlock_irqrestore(&priv->sta_lock, flags); + + iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); +} + +static void iwl_update_ps_mode(struct iwl_priv *priv, u16 ps_bit, u8 *addr) +{ + /* FIXME: need locking over ps_status ??? */ + u8 sta_id = iwl_find_station(priv, addr); + + if (sta_id != IWL_INVALID_STATION) { + u8 sta_awake = priv->stations[sta_id]. + ps_status == STA_PS_STATUS_WAKE; + + if (sta_awake && ps_bit) + priv->stations[sta_id].ps_status = STA_PS_STATUS_SLEEP; + else if (!sta_awake && !ps_bit) { + iwl_sta_modify_ps_wake(priv, sta_id); + priv->stations[sta_id].ps_status = STA_PS_STATUS_WAKE; + } + } +} + +/* This is necessary only for a number of statistics, see the caller. */ +static int iwl_is_network_packet(struct iwl_priv *priv, + struct ieee80211_hdr *header) +{ + /* Filter incoming packets to determine if they are targeted toward + * this network, discarding packets coming from ourselves */ + switch (priv->iw_mode) { + case IEEE80211_IF_TYPE_IBSS: /* Header: Dest. | Source | BSSID */ + /* packets to our IBSS update information */ + return !compare_ether_addr(header->addr3, priv->bssid); + case IEEE80211_IF_TYPE_STA: /* Header: Dest. | AP{BSSID} | Source */ + /* packets to our IBSS update information */ + return !compare_ether_addr(header->addr2, priv->bssid); + default: + return 1; + } +} + +/* Called for REPLY_RX (legacy ABG frames), or + * REPLY_RX_MPDU_CMD (HT high-throughput N frames). */ +void iwl_rx_reply_rx(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct ieee80211_hdr *header; + struct ieee80211_rx_status rx_status; + struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + /* Use phy data (Rx signal strength, etc.) contained within + * this rx packet for legacy frames, + * or phy data cached from REPLY_RX_PHY_CMD for HT frames. */ + int include_phy = (pkt->hdr.cmd == REPLY_RX); + struct iwl4965_rx_phy_res *rx_start = (include_phy) ? + (struct iwl4965_rx_phy_res *)&(pkt->u.raw[0]) : + (struct iwl4965_rx_phy_res *)&priv->last_phy_res[1]; + __le32 *rx_end; + unsigned int len = 0; + u16 fc; + u8 network_packet; + + rx_status.mactime = le64_to_cpu(rx_start->timestamp); + rx_status.freq = + ieee80211_channel_to_frequency(le16_to_cpu(rx_start->channel)); + rx_status.band = (rx_start->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ? + IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ; + rx_status.rate_idx = + iwl_hwrate_to_plcp_idx(le32_to_cpu(rx_start->rate_n_flags)); + if (rx_status.band == IEEE80211_BAND_5GHZ) + rx_status.rate_idx -= IWL_FIRST_OFDM_RATE; + + rx_status.antenna = 0; + rx_status.flag = 0; + rx_status.flag |= RX_FLAG_TSFT; + + if ((unlikely(rx_start->cfg_phy_cnt > 20))) { + IWL_DEBUG_DROP("dsp size out of range [0,20]: %d/n", + rx_start->cfg_phy_cnt); + return; + } + + if (!include_phy) { + if (priv->last_phy_res[0]) + rx_start = (struct iwl4965_rx_phy_res *) + &priv->last_phy_res[1]; + else + rx_start = NULL; + } + + if (!rx_start) { + IWL_ERROR("MPDU frame without a PHY data\n"); + return; + } + + if (include_phy) { + header = (struct ieee80211_hdr *)((u8 *) &rx_start[1] + + rx_start->cfg_phy_cnt); + + len = le16_to_cpu(rx_start->byte_count); + rx_end = (__le32 *)(pkt->u.raw + rx_start->cfg_phy_cnt + + sizeof(struct iwl4965_rx_phy_res) + len); + } else { + struct iwl4965_rx_mpdu_res_start *amsdu = + (struct iwl4965_rx_mpdu_res_start *)pkt->u.raw; + + header = (void *)(pkt->u.raw + + sizeof(struct iwl4965_rx_mpdu_res_start)); + len = le16_to_cpu(amsdu->byte_count); + rx_end = (__le32 *) (pkt->u.raw + + sizeof(struct iwl4965_rx_mpdu_res_start) + len); + } + + if (!(*rx_end & RX_RES_STATUS_NO_CRC32_ERROR) || + !(*rx_end & RX_RES_STATUS_NO_RXE_OVERFLOW)) { + IWL_DEBUG_RX("Bad CRC or FIFO: 0x%08X.\n", + le32_to_cpu(*rx_end)); + return; + } + + priv->ucode_beacon_time = le32_to_cpu(rx_start->beacon_time_stamp); + + /* Find max signal strength (dBm) among 3 antenna/receiver chains */ + rx_status.signal = iwl_calc_rssi(priv, rx_start); + + /* Meaningful noise values are available only from beacon statistics, + * which are gathered only when associated, and indicate noise + * only for the associated network channel ... + * Ignore these noise values while scanning (other channels) */ + if (iwl_is_associated(priv) && + !test_bit(STATUS_SCANNING, &priv->status)) { + rx_status.noise = priv->last_rx_noise; + rx_status.qual = iwl_calc_sig_qual(rx_status.signal, + rx_status.noise); + } else { + rx_status.noise = IWL_NOISE_MEAS_NOT_AVAILABLE; + rx_status.qual = iwl_calc_sig_qual(rx_status.signal, 0); + } + + /* Reset beacon noise level if not associated. */ + if (!iwl_is_associated(priv)) + priv->last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE; + + /* Set "1" to report good data frames in groups of 100 */ + /* FIXME: need to optimze the call: */ + iwl_dbg_report_frame(priv, pkt, header, 1); + + IWL_DEBUG_STATS_LIMIT("Rssi %d, noise %d, qual %d, TSF %llu\n", + rx_status.signal, rx_status.noise, rx_status.signal, + (unsigned long long)rx_status.mactime); + + /* Take shortcut when only in monitor mode */ + if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) { + iwl_pass_packet_to_mac80211(priv, include_phy, + rxb, &rx_status); + return; + } + + network_packet = iwl_is_network_packet(priv, header); + if (network_packet) { + priv->last_rx_rssi = rx_status.signal; + priv->last_beacon_time = priv->ucode_beacon_time; + priv->last_tsf = le64_to_cpu(rx_start->timestamp); + } + + fc = le16_to_cpu(header->frame_control); + switch (fc & IEEE80211_FCTL_FTYPE) { + case IEEE80211_FTYPE_MGMT: + case IEEE80211_FTYPE_DATA: + if (priv->iw_mode == IEEE80211_IF_TYPE_AP) + iwl_update_ps_mode(priv, fc & IEEE80211_FCTL_PM, + header->addr2); + /* fall through */ + default: + iwl_pass_packet_to_mac80211(priv, include_phy, rxb, + &rx_status); + break; + + } +} +EXPORT_SYMBOL(iwl_rx_reply_rx); + +/* Cache phy data (Rx signal strength, etc) for HT frame (REPLY_RX_PHY_CMD). + * This will be used later in iwl_rx_reply_rx() for REPLY_RX_MPDU_CMD. */ +void iwl_rx_reply_rx_phy(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + priv->last_phy_res[0] = 1; + memcpy(&priv->last_phy_res[1], &(pkt->u.raw[0]), + sizeof(struct iwl4965_rx_phy_res)); +} +EXPORT_SYMBOL(iwl_rx_reply_rx_phy); diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index f874e7d7b22..6d1467d0bd9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -36,8 +36,8 @@ #include "iwl-helpers.h" -#define IWL_STA_DRIVER_ACTIVE 0x1 /* ucode entry is active */ -#define IWL_STA_UCODE_ACTIVE 0x2 /* ucode entry is active */ +#define IWL_STA_DRIVER_ACTIVE BIT(0) /* driver entry is active */ +#define IWL_STA_UCODE_ACTIVE BIT(1) /* ucode entry is active */ u8 iwl_find_station(struct iwl_priv *priv, const u8 *addr) { @@ -83,10 +83,28 @@ int iwl_get_ra_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) } EXPORT_SYMBOL(iwl_get_ra_sta_id); +static void iwl_sta_ucode_activate(struct iwl_priv *priv, u8 sta_id) +{ + unsigned long flags; + DECLARE_MAC_BUF(mac); + + spin_lock_irqsave(&priv->sta_lock, flags); + + if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE)) + IWL_ERROR("ACTIVATE a non DRIVER active station %d\n", sta_id); + + priv->stations[sta_id].used |= IWL_STA_UCODE_ACTIVE; + IWL_DEBUG_ASSOC("Added STA to Ucode: %s\n", + print_mac(mac, priv->stations[sta_id].sta.sta.addr)); + + spin_unlock_irqrestore(&priv->sta_lock, flags); +} + static int iwl_add_sta_callback(struct iwl_priv *priv, struct iwl_cmd *cmd, struct sk_buff *skb) { struct iwl_rx_packet *res = NULL; + u8 sta_id = cmd->cmd.addsta.sta.sta_id; if (!skb) { IWL_ERROR("Error: Response NULL in REPLY_ADD_STA.\n"); @@ -102,8 +120,8 @@ static int iwl_add_sta_callback(struct iwl_priv *priv, switch (res->u.add_sta.status) { case ADD_STA_SUCCESS_MSK: - /* FIXME: implement iwl_sta_ucode_activate(priv, addr); */ - /* fail through */ + iwl_sta_ucode_activate(priv, sta_id); + /* fall through */ default: IWL_DEBUG_HC("Received REPLY_ADD_STA:(0x%08X)\n", res->u.add_sta.status); @@ -147,6 +165,7 @@ int iwl_send_add_sta(struct iwl_priv *priv, if (ret == 0) { switch (res->u.add_sta.status) { case ADD_STA_SUCCESS_MSK: + iwl_sta_ucode_activate(priv, sta->sta.sta_id); IWL_DEBUG_INFO("REPLY_ADD_STA PASSED\n"); break; default: @@ -215,88 +234,92 @@ u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr, int is_ap, u8 flags, struct ieee80211_ht_info *ht_info) { int i; - int index = IWL_INVALID_STATION; + int sta_id = IWL_INVALID_STATION; struct iwl_station_entry *station; unsigned long flags_spin; DECLARE_MAC_BUF(mac); spin_lock_irqsave(&priv->sta_lock, flags_spin); if (is_ap) - index = IWL_AP_ID; + sta_id = IWL_AP_ID; else if (is_broadcast_ether_addr(addr)) - index = priv->hw_params.bcast_sta_id; + sta_id = priv->hw_params.bcast_sta_id; else for (i = IWL_STA_ID; i < priv->hw_params.max_stations; i++) { if (!compare_ether_addr(priv->stations[i].sta.sta.addr, addr)) { - index = i; + sta_id = i; break; } if (!priv->stations[i].used && - index == IWL_INVALID_STATION) - index = i; + sta_id == IWL_INVALID_STATION) + sta_id = i; } - /* These two conditions have the same outcome, but keep them separate - since they have different meanings */ - if (unlikely(index == IWL_INVALID_STATION)) { + since they have different meanings */ + if (unlikely(sta_id == IWL_INVALID_STATION)) { spin_unlock_irqrestore(&priv->sta_lock, flags_spin); - return index; + return sta_id; } - if (priv->stations[index].used && - !compare_ether_addr(priv->stations[index].sta.sta.addr, addr)) { + if (priv->stations[sta_id].used && + !compare_ether_addr(priv->stations[sta_id].sta.sta.addr, addr)) { spin_unlock_irqrestore(&priv->sta_lock, flags_spin); - return index; + return sta_id; } - IWL_DEBUG_ASSOC("Add STA ID %d: %s\n", index, print_mac(mac, addr)); - station = &priv->stations[index]; - station->used = 1; + station = &priv->stations[sta_id]; + station->used = IWL_STA_DRIVER_ACTIVE; + IWL_DEBUG_ASSOC("Add STA to driver ID %d: %s\n", + sta_id, print_mac(mac, addr)); priv->num_stations++; /* Set up the REPLY_ADD_STA command to send to device */ memset(&station->sta, 0, sizeof(struct iwl_addsta_cmd)); memcpy(station->sta.sta.addr, addr, ETH_ALEN); station->sta.mode = 0; - station->sta.sta.sta_id = index; + station->sta.sta.sta_id = sta_id; station->sta.station_flags = 0; /* BCAST station and IBSS stations do not work in HT mode */ - if (index != priv->hw_params.bcast_sta_id && + if (sta_id != priv->hw_params.bcast_sta_id && priv->iw_mode != IEEE80211_IF_TYPE_IBSS) - iwl_set_ht_add_station(priv, index, ht_info); + iwl_set_ht_add_station(priv, sta_id, ht_info); spin_unlock_irqrestore(&priv->sta_lock, flags_spin); /* Add station to device's station table */ iwl_send_add_sta(priv, &station->sta, flags); - return index; + return sta_id; } EXPORT_SYMBOL(iwl_add_station_flags); -static int iwl_sta_ucode_deactivate(struct iwl_priv *priv, const char *addr) +static void iwl_sta_ucode_deactivate(struct iwl_priv *priv, const char *addr) { unsigned long flags; - u8 sta_id; DECLARE_MAC_BUF(mac); - sta_id = iwl_find_station(priv, addr); - if (sta_id != IWL_INVALID_STATION) { - IWL_DEBUG_ASSOC("Removed STA from Ucode: %s\n", - print_mac(mac, addr)); - spin_lock_irqsave(&priv->sta_lock, flags); - priv->stations[sta_id].used &= ~IWL_STA_UCODE_ACTIVE; - memset(&priv->stations[sta_id], 0, - sizeof(struct iwl_station_entry)); - spin_unlock_irqrestore(&priv->sta_lock, flags); - return 0; - } - return -EINVAL; + u8 sta_id = iwl_find_station(priv, addr); + + BUG_ON(sta_id == IWL_INVALID_STATION); + + IWL_DEBUG_ASSOC("Removed STA from Ucode: %s\n", + print_mac(mac, addr)); + + spin_lock_irqsave(&priv->sta_lock, flags); + + /* Ucode must be active and driver must be non active */ + if (priv->stations[sta_id].used != IWL_STA_UCODE_ACTIVE) + IWL_ERROR("removed non active STA %d\n", sta_id); + + priv->stations[sta_id].used &= ~IWL_STA_UCODE_ACTIVE; + + memset(&priv->stations[sta_id], 0, sizeof(struct iwl_station_entry)); + spin_unlock_irqrestore(&priv->sta_lock, flags); } static int iwl_remove_sta_callback(struct iwl_priv *priv, @@ -322,6 +345,7 @@ static int iwl_remove_sta_callback(struct iwl_priv *priv, iwl_sta_ucode_deactivate(priv, addr); break; default: + IWL_ERROR("REPLY_REMOVE_STA failed\n"); break; } @@ -386,44 +410,63 @@ static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr, /** * iwl_remove_station - Remove driver's knowledge of station. */ -u8 iwl_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap) +int iwl_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap) { - int index = IWL_INVALID_STATION; - int i; + int sta_id = IWL_INVALID_STATION; + int i, ret = -EINVAL; unsigned long flags; + DECLARE_MAC_BUF(mac); spin_lock_irqsave(&priv->sta_lock, flags); if (is_ap) - index = IWL_AP_ID; + sta_id = IWL_AP_ID; else if (is_broadcast_ether_addr(addr)) - index = priv->hw_params.bcast_sta_id; + sta_id = priv->hw_params.bcast_sta_id; else for (i = IWL_STA_ID; i < priv->hw_params.max_stations; i++) if (priv->stations[i].used && !compare_ether_addr(priv->stations[i].sta.sta.addr, addr)) { - index = i; + sta_id = i; break; } - if (unlikely(index == IWL_INVALID_STATION)) + if (unlikely(sta_id == IWL_INVALID_STATION)) goto out; - if (priv->stations[index].used) { - priv->stations[index].used = 0; - priv->num_stations--; + IWL_DEBUG_ASSOC("Removing STA from driver:%d %s\n", + sta_id, print_mac(mac, addr)); + + if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE)) { + IWL_ERROR("Removing %s but non DRIVER active\n", + print_mac(mac, addr)); + goto out; + } + + if (!(priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE)) { + IWL_ERROR("Removing %s but non UCODE active\n", + print_mac(mac, addr)); + goto out; } + + priv->stations[sta_id].used &= ~IWL_STA_DRIVER_ACTIVE; + + priv->num_stations--; + BUG_ON(priv->num_stations < 0); + spin_unlock_irqrestore(&priv->sta_lock, flags); - iwl_send_remove_station(priv, addr, CMD_ASYNC); - return index; + + ret = iwl_send_remove_station(priv, addr, CMD_ASYNC); + return ret; out: spin_unlock_irqrestore(&priv->sta_lock, flags); - return 0; + return ret; } EXPORT_SYMBOL(iwl_remove_station); + static int iwl_get_free_ucode_key_index(struct iwl_priv *priv) { int i; @@ -782,8 +825,7 @@ int iwl_send_lq_cmd(struct iwl_priv *priv, iwl_dump_lq_cmd(priv,lq); - if (iwl_is_associated(priv) && priv->assoc_station_added && - priv->lq_mngr.lq_ready) + if (iwl_is_associated(priv) && priv->assoc_station_added) return iwl_send_cmd(priv, &cmd); return 0; @@ -845,6 +887,7 @@ static void iwl_sta_init_lq(struct iwl_priv *priv, const u8 *addr, int is_ap) iwl_send_cmd_pdu_async(priv, REPLY_TX_LINK_QUALITY_CMD, sizeof(link_cmd), &link_cmd, NULL); } + /** * iwl_rxon_add_station - add station into station table. * diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.h b/drivers/net/wireless/iwlwifi/iwl-sta.h index b6bb209fdd5..221b93e670a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.h +++ b/drivers/net/wireless/iwlwifi/iwl-sta.h @@ -48,7 +48,7 @@ int iwl_set_dynamic_key(struct iwl_priv *priv, int iwl_remove_dynamic_key(struct iwl_priv *priv, struct ieee80211_key_conf *key, u8 sta_id); int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap); -u8 iwl_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap); +int iwl_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap); int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr); void iwl_sta_modify_enable_tid_tx(struct iwl_priv *priv, int sta_id, int tid); int iwl_get_ra_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr); diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 7296e2846ec..032641d4c7d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -1350,6 +1350,149 @@ int iwl_txq_check_empty(struct iwl_priv *priv, int sta_id, u8 tid, int txq_id) } EXPORT_SYMBOL(iwl_txq_check_empty); +/** + * iwl_tx_status_reply_compressed_ba - Update tx status from block-ack + * + * Go through block-ack's bitmap of ACK'd frames, update driver's record of + * ACK vs. not. This gets sent to mac80211, then to rate scaling algo. + */ +static int iwl_tx_status_reply_compressed_ba(struct iwl_priv *priv, + struct iwl_ht_agg *agg, + struct iwl_compressed_ba_resp *ba_resp) + +{ + int i, sh, ack; + u16 seq_ctl = le16_to_cpu(ba_resp->seq_ctl); + u16 scd_flow = le16_to_cpu(ba_resp->scd_flow); + u64 bitmap; + int successes = 0; + struct ieee80211_tx_info *info; + + if (unlikely(!agg->wait_for_ba)) { + IWL_ERROR("Received BA when not expected\n"); + return -EINVAL; + } + + /* Mark that the expected block-ack response arrived */ + agg->wait_for_ba = 0; + IWL_DEBUG_TX_REPLY("BA %d %d\n", agg->start_idx, ba_resp->seq_ctl); + + /* Calculate shift to align block-ack bits with our Tx window bits */ + sh = agg->start_idx - SEQ_TO_INDEX(seq_ctl>>4); + if (sh < 0) /* tbw something is wrong with indices */ + sh += 0x100; + + /* don't use 64-bit values for now */ + bitmap = le64_to_cpu(ba_resp->bitmap) >> sh; + + if (agg->frame_count > (64 - sh)) { + IWL_DEBUG_TX_REPLY("more frames than bitmap size"); + return -1; + } + + /* check for success or failure according to the + * transmitted bitmap and block-ack bitmap */ + bitmap &= agg->bitmap; + + /* For each frame attempted in aggregation, + * update driver's record of tx frame's status. */ + for (i = 0; i < agg->frame_count ; i++) { + ack = bitmap & (1 << i); + successes += !!ack; + IWL_DEBUG_TX_REPLY("%s ON i=%d idx=%d raw=%d\n", + ack? "ACK":"NACK", i, (agg->start_idx + i) & 0xff, + agg->start_idx + i); + } + + info = IEEE80211_SKB_CB(priv->txq[scd_flow].txb[agg->start_idx].skb[0]); + memset(&info->status, 0, sizeof(info->status)); + info->flags = IEEE80211_TX_STAT_ACK; + info->flags |= IEEE80211_TX_STAT_AMPDU; + info->status.ampdu_ack_map = successes; + info->status.ampdu_ack_len = agg->frame_count; + iwl_hwrate_to_tx_control(priv, agg->rate_n_flags, info); + + IWL_DEBUG_TX_REPLY("Bitmap %llx\n", (unsigned long long)bitmap); + + return 0; +} + +/** + * iwl_rx_reply_compressed_ba - Handler for REPLY_COMPRESSED_BA + * + * Handles block-acknowledge notification from device, which reports success + * of frames sent via aggregation. + */ +void iwl_rx_reply_compressed_ba(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + struct iwl_compressed_ba_resp *ba_resp = &pkt->u.compressed_ba; + int index; + struct iwl_tx_queue *txq = NULL; + struct iwl_ht_agg *agg; + DECLARE_MAC_BUF(mac); + + /* "flow" corresponds to Tx queue */ + u16 scd_flow = le16_to_cpu(ba_resp->scd_flow); + + /* "ssn" is start of block-ack Tx window, corresponds to index + * (in Tx queue's circular buffer) of first TFD/frame in window */ + u16 ba_resp_scd_ssn = le16_to_cpu(ba_resp->scd_ssn); + + if (scd_flow >= priv->hw_params.max_txq_num) { + IWL_ERROR("BUG_ON scd_flow is bigger than number of queues"); + return; + } + + txq = &priv->txq[scd_flow]; + agg = &priv->stations[ba_resp->sta_id].tid[ba_resp->tid].agg; + + /* Find index just before block-ack window */ + index = iwl_queue_dec_wrap(ba_resp_scd_ssn & 0xff, txq->q.n_bd); + + /* TODO: Need to get this copy more safely - now good for debug */ + + IWL_DEBUG_TX_REPLY("REPLY_COMPRESSED_BA [%d]Received from %s, " + "sta_id = %d\n", + agg->wait_for_ba, + print_mac(mac, (u8 *) &ba_resp->sta_addr_lo32), + ba_resp->sta_id); + IWL_DEBUG_TX_REPLY("TID = %d, SeqCtl = %d, bitmap = 0x%llx, scd_flow = " + "%d, scd_ssn = %d\n", + ba_resp->tid, + ba_resp->seq_ctl, + (unsigned long long)le64_to_cpu(ba_resp->bitmap), + ba_resp->scd_flow, + ba_resp->scd_ssn); + IWL_DEBUG_TX_REPLY("DAT start_idx = %d, bitmap = 0x%llx \n", + agg->start_idx, + (unsigned long long)agg->bitmap); + + /* Update driver's record of ACK vs. not for each frame in window */ + iwl_tx_status_reply_compressed_ba(priv, agg, ba_resp); + + /* Release all TFDs before the SSN, i.e. all TFDs in front of + * block-ack window (we assume that they've been successfully + * transmitted ... if not, it's too late anyway). */ + if (txq->q.read_ptr != (ba_resp_scd_ssn & 0xff)) { + /* calculate mac80211 ampdu sw queue to wake */ + int ampdu_q = + scd_flow - priv->hw_params.first_ampdu_q + priv->hw->queues; + int freed = iwl_tx_queue_reclaim(priv, scd_flow, index); + priv->stations[ba_resp->sta_id]. + tid[ba_resp->tid].tfds_in_queue -= freed; + if (iwl_queue_space(&txq->q) > txq->q.low_mark && + priv->mac80211_registered && + agg->state != IWL_EMPTYING_HW_QUEUE_DELBA) + ieee80211_wake_queue(priv->hw, ampdu_q); + + iwl_txq_check_empty(priv, ba_resp->sta_id, + ba_resp->tid, scd_flow); + } +} +EXPORT_SYMBOL(iwl_rx_reply_compressed_ba); + #ifdef CONFIG_IWLWIF_DEBUG #define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 92d1b2e312d..3bc2644039f 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -970,7 +970,7 @@ static int iwl3945_full_rxon_required(struct iwl3945_priv *priv) { /* These items are only settable from the full RXON command */ - if (!(priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) || + if (!(iwl3945_is_associated(priv)) || compare_ether_addr(priv->staging_rxon.bssid_addr, priv->active_rxon.bssid_addr) || compare_ether_addr(priv->staging_rxon.node_addr, @@ -2312,7 +2312,7 @@ static void iwl3945_connection_init_rx_config(struct iwl3945_priv *priv) #endif ch_info = iwl3945_get_channel_info(priv, priv->band, - le16_to_cpu(priv->staging_rxon.channel)); + le16_to_cpu(priv->active_rxon.channel)); if (!ch_info) ch_info = &priv->channel_info[0]; @@ -2539,6 +2539,11 @@ static int iwl3945_get_sta_id(struct iwl3945_priv *priv, struct ieee80211_hdr *h iwl3945_print_hex_dump(IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr)); return priv->hw_setting.bcast_sta_id; } + /* If we are in monitor mode, use BCAST. This is required for + * packet injection. */ + case IEEE80211_IF_TYPE_MNTR: + return priv->hw_setting.bcast_sta_id; + default: IWL_WARNING("Unknown mode of operation: %d", priv->iw_mode); return priv->hw_setting.bcast_sta_id; @@ -2578,11 +2583,6 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv, struct sk_buff *skb) goto drop_unlock; } - if (!priv->vif) { - IWL_DEBUG_DROP("Dropping - !priv->vif\n"); - goto drop_unlock; - } - if ((ieee80211_get_tx_rate(priv->hw, info)->hw_value & 0xFF) == IWL_INVALID_RATE) { IWL_ERROR("ERROR: No TX rate available.\n"); goto drop_unlock; @@ -2603,9 +2603,10 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv, struct sk_buff *skb) #endif /* drop all data frame if we are not associated */ - if ((!iwl3945_is_associated(priv) || - ((priv->iw_mode == IEEE80211_IF_TYPE_STA) && !priv->assoc_id)) && - ieee80211_is_data(fc)) { + if (ieee80211_is_data(fc) && + (priv->iw_mode != IEEE80211_IF_TYPE_MNTR) && /* packet injection */ + (!iwl3945_is_associated(priv) || + ((priv->iw_mode == IEEE80211_IF_TYPE_STA) && !priv->assoc_id))) { IWL_DEBUG_DROP("Dropping - !iwl3945_is_associated\n"); goto drop_unlock; } @@ -5921,7 +5922,9 @@ static void __iwl3945_down(struct iwl3945_priv *priv) test_bit(STATUS_GEO_CONFIGURED, &priv->status) << STATUS_GEO_CONFIGURED | test_bit(STATUS_IN_SUSPEND, &priv->status) << - STATUS_IN_SUSPEND; + STATUS_IN_SUSPEND | + test_bit(STATUS_EXIT_PENDING, &priv->status) << + STATUS_EXIT_PENDING; goto exit; } @@ -5936,7 +5939,9 @@ static void __iwl3945_down(struct iwl3945_priv *priv) test_bit(STATUS_IN_SUSPEND, &priv->status) << STATUS_IN_SUSPEND | test_bit(STATUS_FW_ERROR, &priv->status) << - STATUS_FW_ERROR; + STATUS_FW_ERROR | + test_bit(STATUS_EXIT_PENDING, &priv->status) << + STATUS_EXIT_PENDING; spin_lock_irqsave(&priv->lock, flags); iwl3945_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); @@ -6008,11 +6013,12 @@ static int __iwl3945_up(struct iwl3945_priv *priv) else { set_bit(STATUS_RF_KILL_HW, &priv->status); if (!test_bit(STATUS_IN_SUSPEND, &priv->status)) { + iwl3945_rfkill_set_hw_state(priv); IWL_WARNING("Radio disabled by HW RF Kill switch\n"); return -ENODEV; } } - + iwl3945_rfkill_set_hw_state(priv); iwl3945_write32(priv, CSR_INT, 0xFFFFFFFF); rc = iwl3945_hw_nic_init(priv); @@ -6068,6 +6074,7 @@ static int __iwl3945_up(struct iwl3945_priv *priv) set_bit(STATUS_EXIT_PENDING, &priv->status); __iwl3945_down(priv); + clear_bit(STATUS_EXIT_PENDING, &priv->status); /* tried to restart and config the device for as long as our * patience could withstand */ @@ -6135,6 +6142,8 @@ static void iwl3945_bg_rf_kill(struct work_struct *work) "Kill switch must be turned off for " "wireless networking to work.\n"); } + + iwl3945_rfkill_set_hw_state(priv); mutex_unlock(&priv->mutex); } @@ -6685,11 +6694,6 @@ static int iwl3945_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) IWL_DEBUG_MAC80211("enter\n"); - if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) { - IWL_DEBUG_MAC80211("leave - monitor\n"); - return -1; - } - IWL_DEBUG_TX("dev->xmit(%d bytes) at rate 0x%02x\n", skb->len, ieee80211_get_tx_rate(hw, IEEE80211_SKB_CB(skb))->bitrate); @@ -6836,7 +6840,7 @@ static void iwl3945_config_ap(struct iwl3945_priv *priv) return; /* The following should be done only at AP bring up */ - if ((priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) == 0) { + if (!(iwl3945_is_associated(priv))) { /* RXON - unassoc (to set timing command) */ priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; @@ -6998,26 +7002,18 @@ static void iwl3945_configure_filter(struct ieee80211_hw *hw, unsigned int *total_flags, int mc_count, struct dev_addr_list *mc_list) { - /* - * XXX: dummy - * see also iwl3945_connection_init_rx_config - */ struct iwl3945_priv *priv = hw->priv; - int new_flags = 0; - if (changed_flags & (FIF_PROMISC_IN_BSS | FIF_OTHER_BSS)) { - if (*total_flags & (FIF_PROMISC_IN_BSS | FIF_OTHER_BSS)) { - IWL_DEBUG_MAC80211("Enter: type %d (0x%x, 0x%x)\n", - IEEE80211_IF_TYPE_MNTR, - changed_flags, *total_flags); - /* queue work 'cuz mac80211 is holding a lock which - * prevents us from issuing (synchronous) f/w cmds */ - queue_work(priv->workqueue, &priv->set_monitor); - new_flags &= FIF_PROMISC_IN_BSS | - FIF_OTHER_BSS | - FIF_ALLMULTI; - } + + if (changed_flags & (*total_flags) & FIF_OTHER_BSS) { + IWL_DEBUG_MAC80211("Enter: type %d (0x%x, 0x%x)\n", + IEEE80211_IF_TYPE_MNTR, + changed_flags, *total_flags); + /* queue work 'cuz mac80211 is holding a lock which + * prevents us from issuing (synchronous) f/w cmds */ + queue_work(priv->workqueue, &priv->set_monitor); } - *total_flags = new_flags; + *total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI | + FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL; } static void iwl3945_mac_remove_interface(struct ieee80211_hw *hw, @@ -7412,37 +7408,6 @@ static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO, #endif /* CONFIG_IWL3945_DEBUG */ -static ssize_t show_rf_kill(struct device *d, - struct device_attribute *attr, char *buf) -{ - /* - * 0 - RF kill not enabled - * 1 - SW based RF kill active (sysfs) - * 2 - HW based RF kill active - * 3 - Both HW and SW based RF kill active - */ - struct iwl3945_priv *priv = (struct iwl3945_priv *)d->driver_data; - int val = (test_bit(STATUS_RF_KILL_SW, &priv->status) ? 0x1 : 0x0) | - (test_bit(STATUS_RF_KILL_HW, &priv->status) ? 0x2 : 0x0); - - return sprintf(buf, "%i\n", val); -} - -static ssize_t store_rf_kill(struct device *d, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct iwl3945_priv *priv = (struct iwl3945_priv *)d->driver_data; - - mutex_lock(&priv->mutex); - iwl3945_radio_kill_sw(priv, buf[0] == '1'); - mutex_unlock(&priv->mutex); - - return count; -} - -static DEVICE_ATTR(rf_kill, S_IWUSR | S_IRUGO, show_rf_kill, store_rf_kill); - static ssize_t show_temperature(struct device *d, struct device_attribute *attr, char *buf) { @@ -7928,7 +7893,6 @@ static struct attribute *iwl3945_sysfs_entries[] = { #endif &dev_attr_power_level.attr, &dev_attr_retry_rate.attr, - &dev_attr_rf_kill.attr, &dev_attr_rs_window.attr, &dev_attr_statistics.attr, &dev_attr_status.attr, @@ -8169,6 +8133,11 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e pci_save_state(pdev); pci_disable_device(pdev); + err = iwl3945_rfkill_init(priv); + if (err) + IWL_ERROR("Unable to initialize RFKILL system. " + "Ignoring error: %d\n", err); + return 0; out_free_geos: @@ -8231,6 +8200,7 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev) sysfs_remove_group(&pdev->dev.kobj, &iwl3945_attribute_group); + iwl3945_rfkill_unregister(priv); iwl3945_dealloc_ucode_pci(priv); if (priv->rxq.bd) @@ -8299,6 +8269,143 @@ static int iwl3945_pci_resume(struct pci_dev *pdev) #endif /* CONFIG_PM */ +/*************** RFKILL FUNCTIONS **********/ +#ifdef CONFIG_IWLWIFI_RFKILL +/* software rf-kill from user */ +static int iwl3945_rfkill_soft_rf_kill(void *data, enum rfkill_state state) +{ + struct iwl3945_priv *priv = data; + int err = 0; + + if (!priv->rfkill_mngr.rfkill) + return 0; + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return 0; + + IWL_DEBUG_RF_KILL("we recieved soft RFKILL set to state %d\n", state); + mutex_lock(&priv->mutex); + + switch (state) { + case RFKILL_STATE_UNBLOCKED: + iwl3945_radio_kill_sw(priv, 0); + /* if HW rf-kill is set dont allow ON state */ + if (iwl3945_is_rfkill(priv)) + err = -EBUSY; + break; + case RFKILL_STATE_SOFT_BLOCKED: + iwl3945_radio_kill_sw(priv, 1); + if (!iwl3945_is_rfkill(priv)) + err = -EBUSY; + break; + default: + IWL_WARNING("we recieved unexpected RFKILL state %d\n", state); + break; + } + mutex_unlock(&priv->mutex); + + return err; +} + +int iwl3945_rfkill_init(struct iwl3945_priv *priv) +{ + struct device *device = wiphy_dev(priv->hw->wiphy); + int ret = 0; + + BUG_ON(device == NULL); + + IWL_DEBUG_RF_KILL("Initializing RFKILL.\n"); + priv->rfkill_mngr.rfkill = rfkill_allocate(device, RFKILL_TYPE_WLAN); + if (!priv->rfkill_mngr.rfkill) { + IWL_ERROR("Unable to allocate rfkill device.\n"); + ret = -ENOMEM; + goto error; + } + + priv->rfkill_mngr.rfkill->name = priv->cfg->name; + priv->rfkill_mngr.rfkill->data = priv; + priv->rfkill_mngr.rfkill->state = RFKILL_STATE_ON; + priv->rfkill_mngr.rfkill->toggle_radio = iwl3945_rfkill_soft_rf_kill; + priv->rfkill_mngr.rfkill->user_claim_unsupported = 1; + + priv->rfkill_mngr.rfkill->dev.class->suspend = NULL; + priv->rfkill_mngr.rfkill->dev.class->resume = NULL; + + priv->rfkill_mngr.input_dev = input_allocate_device(); + if (!priv->rfkill_mngr.input_dev) { + IWL_ERROR("Unable to allocate rfkill input device.\n"); + ret = -ENOMEM; + goto freed_rfkill; + } + + priv->rfkill_mngr.input_dev->name = priv->cfg->name; + priv->rfkill_mngr.input_dev->phys = wiphy_name(priv->hw->wiphy); + priv->rfkill_mngr.input_dev->id.bustype = BUS_HOST; + priv->rfkill_mngr.input_dev->id.vendor = priv->pci_dev->vendor; + priv->rfkill_mngr.input_dev->dev.parent = device; + priv->rfkill_mngr.input_dev->evbit[0] = BIT(EV_KEY); + set_bit(KEY_WLAN, priv->rfkill_mngr.input_dev->keybit); + + ret = rfkill_register(priv->rfkill_mngr.rfkill); + if (ret) { + IWL_ERROR("Unable to register rfkill: %d\n", ret); + goto free_input_dev; + } + + ret = input_register_device(priv->rfkill_mngr.input_dev); + if (ret) { + IWL_ERROR("Unable to register rfkill input device: %d\n", ret); + goto unregister_rfkill; + } + + IWL_DEBUG_RF_KILL("RFKILL initialization complete.\n"); + return ret; + +unregister_rfkill: + rfkill_unregister(priv->rfkill_mngr.rfkill); + priv->rfkill_mngr.rfkill = NULL; + +free_input_dev: + input_free_device(priv->rfkill_mngr.input_dev); + priv->rfkill_mngr.input_dev = NULL; + +freed_rfkill: + if (priv->rfkill_mngr.rfkill != NULL) + rfkill_free(priv->rfkill_mngr.rfkill); + priv->rfkill_mngr.rfkill = NULL; + +error: + IWL_DEBUG_RF_KILL("RFKILL initialization complete.\n"); + return ret; +} + +void iwl3945_rfkill_unregister(struct iwl3945_priv *priv) +{ + + if (priv->rfkill_mngr.input_dev) + input_unregister_device(priv->rfkill_mngr.input_dev); + + if (priv->rfkill_mngr.rfkill) + rfkill_unregister(priv->rfkill_mngr.rfkill); + + priv->rfkill_mngr.input_dev = NULL; + priv->rfkill_mngr.rfkill = NULL; +} + +/* set rf-kill to the right state. */ +void iwl3945_rfkill_set_hw_state(struct iwl3945_priv *priv) +{ + + if (!priv->rfkill_mngr.rfkill) + return; + + if (!iwl3945_is_rfkill(priv)) + priv->rfkill_mngr.rfkill->state = RFKILL_STATE_ON; + else + priv->rfkill_mngr.rfkill->state = RFKILL_STATE_OFF; +} +#endif + /***************************************************************************** * * driver and module entry point diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index f5911687671..ba0f28945eb 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -192,7 +192,7 @@ static int iwl4965_full_rxon_required(struct iwl_priv *priv) { /* These items are only settable from the full RXON command */ - if (!(priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) || + if (!(iwl_is_associated(priv)) || compare_ether_addr(priv->staging_rxon.bssid_addr, priv->active_rxon.bssid_addr) || compare_ether_addr(priv->staging_rxon.node_addr, @@ -241,16 +241,18 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv) /* cast away the const for active_rxon in this function */ struct iwl_rxon_cmd *active_rxon = (void *)&priv->active_rxon; DECLARE_MAC_BUF(mac); - int rc = 0; + int ret; + bool new_assoc = + !!(priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK); if (!iwl_is_alive(priv)) - return -1; + return -EBUSY; /* always get timestamp with Rx frame */ priv->staging_rxon.flags |= RXON_FLG_TSF2HOST_MSK; - rc = iwl4965_check_rxon_cmd(&priv->staging_rxon); - if (rc) { + ret = iwl4965_check_rxon_cmd(&priv->staging_rxon); + if (ret) { IWL_ERROR("Invalid RXON configuration. Not committing.\n"); return -EINVAL; } @@ -259,15 +261,13 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv) * iwl4965_rxon_assoc_cmd which is used to reconfigure filter * and other flags for the current radio configuration. */ if (!iwl4965_full_rxon_required(priv)) { - rc = iwl_send_rxon_assoc(priv); - if (rc) { - IWL_ERROR("Error setting RXON_ASSOC " - "configuration (%d).\n", rc); - return rc; + ret = iwl_send_rxon_assoc(priv); + if (ret) { + IWL_ERROR("Error setting RXON_ASSOC (%d)\n", ret); + return ret; } memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon)); - return 0; } @@ -278,22 +278,20 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv) * an RXON_ASSOC and the new config wants the associated mask enabled, * we must clear the associated from the active configuration * before we apply the new config */ - if (iwl_is_associated(priv) && - (priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK)) { + if (iwl_is_associated(priv) && new_assoc) { IWL_DEBUG_INFO("Toggling associated bit on current RXON\n"); active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK; - rc = iwl_send_cmd_pdu(priv, REPLY_RXON, + ret = iwl_send_cmd_pdu(priv, REPLY_RXON, sizeof(struct iwl_rxon_cmd), &priv->active_rxon); /* If the mask clearing failed then we set * active_rxon back to what it was previously */ - if (rc) { + if (ret) { active_rxon->filter_flags |= RXON_FILTER_ASSOC_MSK; - IWL_ERROR("Error clearing ASSOC_MSK on current " - "configuration (%d).\n", rc); - return rc; + IWL_ERROR("Error clearing ASSOC_MSK (%d)\n", ret); + return ret; } } @@ -301,58 +299,75 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv) "* with%s RXON_FILTER_ASSOC_MSK\n" "* channel = %d\n" "* bssid = %s\n", - ((priv->staging_rxon.filter_flags & - RXON_FILTER_ASSOC_MSK) ? "" : "out"), + (new_assoc ? "" : "out"), le16_to_cpu(priv->staging_rxon.channel), print_mac(mac, priv->staging_rxon.bssid_addr)); iwl4965_set_rxon_hwcrypto(priv, !priv->hw_params.sw_crypto); - /* Apply the new configuration */ - rc = iwl_send_cmd_pdu(priv, REPLY_RXON, + + /* Apply the new configuration + * RXON unassoc clears the station table in uCode, send it before + * we add the bcast station. If assoc bit is set, we will send RXON + * after having added the bcast and bssid station. + */ + if (!new_assoc) { + ret = iwl_send_cmd_pdu(priv, REPLY_RXON, sizeof(struct iwl_rxon_cmd), &priv->staging_rxon); - if (rc) { - IWL_ERROR("Error setting new configuration (%d).\n", rc); - return rc; + if (ret) { + IWL_ERROR("Error setting new RXON (%d)\n", ret); + return ret; + } + memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon)); } - iwl_remove_station(priv, iwl_bcast_addr, 0); - iwlcore_clear_stations_table(priv); + iwl_clear_stations_table(priv); if (!priv->error_recovering) priv->start_calib = 0; iwl_init_sensitivity(priv); - memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon)); - /* If we issue a new RXON command which required a tune then we must * send a new TXPOWER command or we won't be able to Tx any frames */ - rc = iwl_set_tx_power(priv, priv->tx_power_user_lmt, true); - if (rc) { - IWL_ERROR("Error sending TX power (%d).\n", rc); - return rc; + ret = iwl_set_tx_power(priv, priv->tx_power_user_lmt, true); + if (ret) { + IWL_ERROR("Error sending TX power (%d)\n", ret); + return ret; } /* Add the broadcast address so we can send broadcast frames */ if (iwl_rxon_add_station(priv, iwl_bcast_addr, 0) == - IWL_INVALID_STATION) { + IWL_INVALID_STATION) { IWL_ERROR("Error adding BROADCAST address for transmit.\n"); return -EIO; } /* If we have set the ASSOC_MSK and we are in BSS mode then * add the IWL_AP_ID to the station rate table */ - if (iwl_is_associated(priv) && - (priv->iw_mode == IEEE80211_IF_TYPE_STA)) { - if (iwl_rxon_add_station(priv, priv->active_rxon.bssid_addr, 1) - == IWL_INVALID_STATION) { - IWL_ERROR("Error adding AP address for transmit.\n"); - return -EIO; + if (new_assoc) { + if (priv->iw_mode == IEEE80211_IF_TYPE_STA) { + ret = iwl_rxon_add_station(priv, + priv->active_rxon.bssid_addr, 1); + if (ret == IWL_INVALID_STATION) { + IWL_ERROR("Error adding AP address for TX.\n"); + return -EIO; + } + priv->assoc_station_added = 1; + if (priv->default_wep_key && + iwl_send_static_wepkey_cmd(priv, 0)) + IWL_ERROR("Could not send WEP static key.\n"); } - priv->assoc_station_added = 1; - if (priv->default_wep_key && - iwl_send_static_wepkey_cmd(priv, 0)) - IWL_ERROR("Could not send WEP static key.\n"); + + /* Apply the new configuration + * RXON assoc doesn't clear the station table in uCode, + */ + ret = iwl_send_cmd_pdu(priv, REPLY_RXON, + sizeof(struct iwl_rxon_cmd), &priv->staging_rxon); + if (ret) { + IWL_ERROR("Error setting new RXON (%d)\n", ret); + return ret; + } + memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon)); } return 0; @@ -601,50 +616,6 @@ static void iwl4965_activate_qos(struct iwl_priv *priv, u8 force) } } -int iwl4965_is_network_packet(struct iwl_priv *priv, struct ieee80211_hdr *header) -{ - /* Filter incoming packets to determine if they are targeted toward - * this network, discarding packets coming from ourselves */ - switch (priv->iw_mode) { - case IEEE80211_IF_TYPE_IBSS: /* Header: Dest. | Source | BSSID */ - /* packets from our adapter are dropped (echo) */ - if (!compare_ether_addr(header->addr2, priv->mac_addr)) - return 0; - /* {broad,multi}cast packets to our IBSS go through */ - if (is_multicast_ether_addr(header->addr1)) - return !compare_ether_addr(header->addr3, priv->bssid); - /* packets to our adapter go through */ - return !compare_ether_addr(header->addr1, priv->mac_addr); - case IEEE80211_IF_TYPE_STA: /* Header: Dest. | AP{BSSID} | Source */ - /* packets from our adapter are dropped (echo) */ - if (!compare_ether_addr(header->addr3, priv->mac_addr)) - return 0; - /* {broad,multi}cast packets to our BSS go through */ - if (is_multicast_ether_addr(header->addr1)) - return !compare_ether_addr(header->addr2, priv->bssid); - /* packets to our adapter go through */ - return !compare_ether_addr(header->addr1, priv->mac_addr); - default: - break; - } - - return 1; -} - -static void iwl4965_sequence_reset(struct iwl_priv *priv) -{ - /* Reset ieee stats */ - - /* We don't reset the net_device_stats (ieee->stats) on - * re-association */ - - priv->last_seq_num = -1; - priv->last_frag_num = -1; - priv->last_packet_time = 0; - - iwl_scan_cancel(priv); -} - #define MAX_UCODE_BEACON_INTERVAL 4096 #define INTEL_CONN_LISTEN_INTERVAL __constant_cpu_to_le16(0xA) @@ -787,7 +758,7 @@ static void iwl4965_connection_init_rx_config(struct iwl_priv *priv) #endif ch_info = iwl_get_channel_info(priv, priv->band, - le16_to_cpu(priv->staging_rxon.channel)); + le16_to_cpu(priv->active_rxon.channel)); if (!ch_info) ch_info = &priv->channel_info[0]; @@ -823,13 +794,10 @@ static int iwl4965_set_mode(struct iwl_priv *priv, int mode) { priv->iw_mode = mode; - /* init channel/phymode to values given at driver init */ - iwl_set_rxon_channel(priv, IEEE80211_BAND_2GHZ, 6); - iwl4965_connection_init_rx_config(priv); memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN); - iwlcore_clear_stations_table(priv); + iwl_clear_stations_table(priv); /* dont commit rxon if rf-kill is on*/ if (!iwl_is_ready_rf(priv)) @@ -894,72 +862,6 @@ static void iwl4965_set_rate(struct iwl_priv *priv) (IWL_OFDM_BASIC_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF; } -#define IWL_PACKET_RETRY_TIME HZ - -int iwl4965_is_duplicate_packet(struct iwl_priv *priv, struct ieee80211_hdr *header) -{ - u16 sc = le16_to_cpu(header->seq_ctrl); - u16 seq = (sc & IEEE80211_SCTL_SEQ) >> 4; - u16 frag = sc & IEEE80211_SCTL_FRAG; - u16 *last_seq, *last_frag; - unsigned long *last_time; - - switch (priv->iw_mode) { - case IEEE80211_IF_TYPE_IBSS:{ - struct list_head *p; - struct iwl4965_ibss_seq *entry = NULL; - u8 *mac = header->addr2; - int index = mac[5] & (IWL_IBSS_MAC_HASH_SIZE - 1); - - __list_for_each(p, &priv->ibss_mac_hash[index]) { - entry = list_entry(p, struct iwl4965_ibss_seq, list); - if (!compare_ether_addr(entry->mac, mac)) - break; - } - if (p == &priv->ibss_mac_hash[index]) { - entry = kzalloc(sizeof(*entry), GFP_ATOMIC); - if (!entry) { - IWL_ERROR("Cannot malloc new mac entry\n"); - return 0; - } - memcpy(entry->mac, mac, ETH_ALEN); - entry->seq_num = seq; - entry->frag_num = frag; - entry->packet_time = jiffies; - list_add(&entry->list, &priv->ibss_mac_hash[index]); - return 0; - } - last_seq = &entry->seq_num; - last_frag = &entry->frag_num; - last_time = &entry->packet_time; - break; - } - case IEEE80211_IF_TYPE_STA: - last_seq = &priv->last_seq_num; - last_frag = &priv->last_frag_num; - last_time = &priv->last_packet_time; - break; - default: - return 0; - } - if ((*last_seq == seq) && - time_after(*last_time + IWL_PACKET_RETRY_TIME, jiffies)) { - if (*last_frag == frag) - goto drop; - if (*last_frag + 1 != frag) - /* out-of-order fragment */ - goto drop; - } else - *last_seq = seq; - - *last_frag = frag; - *last_time = jiffies; - return 0; - - drop: - return 1; -} - #ifdef CONFIG_IWL4965_SPECTRUM_MEASUREMENT #include "iwl-spectrum.h" @@ -1338,17 +1240,6 @@ static void iwl4965_rx_card_state_notif(struct iwl_priv *priv, wake_up_interruptible(&priv->wait_command_queue); } -/* Cache phy data (Rx signal strength, etc) for HT frame (REPLY_RX_PHY_CMD). - * This will be used later in iwl4965_rx_reply_rx() for REPLY_RX_MPDU_CMD. */ -static void iwl4965_rx_reply_rx_phy(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) -{ - struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; - priv->last_phy_res[0] = 1; - memcpy(&priv->last_phy_res[1], &(pkt->u.raw[0]), - sizeof(struct iwl4965_rx_phy_res)); -} - /** * iwl4965_setup_rx_handlers - Initialize Rx handler callbacks * @@ -1358,7 +1249,7 @@ static void iwl4965_rx_reply_rx_phy(struct iwl_priv *priv, * This function chains into the hardware specific files for them to setup * any hardware specific handlers as well. */ -static void iwl4965_setup_rx_handlers(struct iwl_priv *priv) +static void iwl_setup_rx_handlers(struct iwl_priv *priv) { priv->rx_handlers[REPLY_ALIVE] = iwl_rx_reply_alive; priv->rx_handlers[REPLY_ERROR] = iwl4965_rx_reply_error; @@ -1375,8 +1266,8 @@ static void iwl4965_setup_rx_handlers(struct iwl_priv *priv) * 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] = iwl4965_hw_rx_statistics; - priv->rx_handlers[STATISTICS_NOTIFICATION] = iwl4965_hw_rx_statistics; + priv->rx_handlers[REPLY_STATISTICS_CMD] = iwl_rx_statistics; + priv->rx_handlers[STATISTICS_NOTIFICATION] = iwl_rx_statistics; iwl_setup_rx_scan_handlers(priv); @@ -1386,8 +1277,10 @@ static void iwl4965_setup_rx_handlers(struct iwl_priv *priv) priv->rx_handlers[MISSED_BEACONS_NOTIFICATION] = iwl_rx_missed_beacon_notif; /* Rx handlers */ - priv->rx_handlers[REPLY_RX_PHY_CMD] = iwl4965_rx_reply_rx_phy; - priv->rx_handlers[REPLY_RX_MPDU_CMD] = iwl4965_rx_reply_rx; + priv->rx_handlers[REPLY_RX_PHY_CMD] = iwl_rx_reply_rx_phy; + priv->rx_handlers[REPLY_RX_MPDU_CMD] = iwl_rx_reply_rx; + /* block ack */ + priv->rx_handlers[REPLY_COMPRESSED_BA] = iwl_rx_reply_compressed_ba; /* Set up hardware specific Rx handlers */ priv->cfg->ops->lib->rx_handler_setup(priv); } @@ -1518,47 +1411,6 @@ void iwl_rx_handle(struct iwl_priv *priv) iwl_rx_queue_restock(priv); } -#define PERFECT_RSSI (-20) /* dBm */ -#define WORST_RSSI (-95) /* dBm */ -#define RSSI_RANGE (PERFECT_RSSI - WORST_RSSI) - -/* Calculate an indication of rx signal quality (a percentage, not dBm!). - * See http://www.ces.clemson.edu/linux/signal_quality.shtml for info - * about formulas used below. */ -int iwl4965_calc_sig_qual(int rssi_dbm, int noise_dbm) -{ - int sig_qual; - int degradation = PERFECT_RSSI - rssi_dbm; - - /* If we get a noise measurement, use signal-to-noise ratio (SNR) - * as indicator; formula is (signal dbm - noise dbm). - * SNR at or above 40 is a great signal (100%). - * Below that, scale to fit SNR of 0 - 40 dB within 0 - 100% indicator. - * Weakest usable signal is usually 10 - 15 dB SNR. */ - if (noise_dbm) { - if (rssi_dbm - noise_dbm >= 40) - return 100; - else if (rssi_dbm < noise_dbm) - return 0; - sig_qual = ((rssi_dbm - noise_dbm) * 5) / 2; - - /* Else use just the signal level. - * This formula is a least squares fit of data points collected and - * compared with a reference system that had a percentage (%) display - * for signal quality. */ - } else - sig_qual = (100 * (RSSI_RANGE * RSSI_RANGE) - degradation * - (15 * RSSI_RANGE + 62 * degradation)) / - (RSSI_RANGE * RSSI_RANGE); - - if (sig_qual > 100) - sig_qual = 100; - else if (sig_qual < 1) - sig_qual = 0; - - return sig_qual; -} - #ifdef CONFIG_IWLWIFI_DEBUG static void iwl4965_print_rx_config_cmd(struct iwl_priv *priv) { @@ -1751,14 +1603,12 @@ static void iwl4965_irq_tasklet(struct iwl_priv *priv) IWL_DEBUG(IWL_DL_RF_KILL, "RF_KILL bit toggled to %s.\n", hw_rf_kill ? "disable radio":"enable radio"); - /* Queue restart only if RF_KILL switch was set to "kill" - * when we loaded driver, and is now set to "enable". - * After we're Alive, RF_KILL gets handled by - * iwl4965_rx_card_state_notif() */ - if (!hw_rf_kill && !test_bit(STATUS_ALIVE, &priv->status)) { + /* driver only loads ucode once setting the interface up. + * the driver as well won't allow loading if RFKILL is set + * therefore no need to restart the driver from this handler + */ + if (!hw_rf_kill && !test_bit(STATUS_ALIVE, &priv->status)) clear_bit(STATUS_RF_KILL_HW, &priv->status); - queue_work(priv->workqueue, &priv->restart); - } handled |= CSR_INT_BIT_RF_KILL; } @@ -2138,7 +1988,7 @@ static void iwl_alive_start(struct iwl_priv *priv) goto restart; } - iwlcore_clear_stations_table(priv); + iwl_clear_stations_table(priv); ret = priv->cfg->ops->lib->alive_notify(priv); if (ret) { IWL_WARNING("Could not complete ALIVE transition [ntf]: %d\n", @@ -2216,7 +2066,7 @@ static void __iwl4965_down(struct iwl_priv *priv) iwl_leds_unregister(priv); - iwlcore_clear_stations_table(priv); + iwl_clear_stations_table(priv); /* Unblock any waiting calls */ wake_up_interruptible_all(&priv->wait_command_queue); @@ -2248,7 +2098,9 @@ static void __iwl4965_down(struct iwl_priv *priv) test_bit(STATUS_GEO_CONFIGURED, &priv->status) << STATUS_GEO_CONFIGURED | test_bit(STATUS_IN_SUSPEND, &priv->status) << - STATUS_IN_SUSPEND; + STATUS_IN_SUSPEND | + test_bit(STATUS_EXIT_PENDING, &priv->status) << + STATUS_EXIT_PENDING; goto exit; } @@ -2263,7 +2115,9 @@ static void __iwl4965_down(struct iwl_priv *priv) test_bit(STATUS_IN_SUSPEND, &priv->status) << STATUS_IN_SUSPEND | test_bit(STATUS_FW_ERROR, &priv->status) << - STATUS_FW_ERROR; + STATUS_FW_ERROR | + test_bit(STATUS_EXIT_PENDING, &priv->status) << + STATUS_EXIT_PENDING; spin_lock_irqsave(&priv->lock, flags); iwl_clear_bit(priv, CSR_GP_CNTRL, @@ -2328,13 +2182,15 @@ static int __iwl4965_up(struct iwl_priv *priv) 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 { + else set_bit(STATUS_RF_KILL_HW, &priv->status); - if (!test_bit(STATUS_IN_SUSPEND, &priv->status)) { - iwl_rfkill_set_hw_state(priv); - IWL_WARNING("Radio disabled by HW RF Kill switch\n"); - return -ENODEV; - } + + if (!test_bit(STATUS_IN_SUSPEND, &priv->status) && + iwl_is_rfkill(priv)) { + iwl_rfkill_set_hw_state(priv); + IWL_WARNING("Radio disabled by %s RF Kill switch\n", + test_bit(STATUS_RF_KILL_HW, &priv->status) ? "HW" : "SW"); + return -ENODEV; } iwl_rfkill_set_hw_state(priv); @@ -2378,7 +2234,7 @@ static int __iwl4965_up(struct iwl_priv *priv) for (i = 0; i < MAX_HW_RESTARTS; i++) { - iwlcore_clear_stations_table(priv); + iwl_clear_stations_table(priv); /* load bootstrap state machine, * load bootstrap program into processor's memory, @@ -2631,7 +2487,6 @@ static void iwl4965_post_associate(struct iwl_priv *priv) switch (priv->iw_mode) { case IEEE80211_IF_TYPE_STA: - iwl4965_rate_scale_init(priv->hw, IWL_AP_ID); break; case IEEE80211_IF_TYPE_IBSS: @@ -2640,7 +2495,6 @@ static void iwl4965_post_associate(struct iwl_priv *priv) priv->assoc_id = 1; iwl_rxon_add_station(priv, priv->bssid, 0); - iwl4965_rate_scale_init(priv->hw, IWL_STA_ID); iwl4965_send_beacon_cmd(priv); break; @@ -2651,8 +2505,6 @@ static void iwl4965_post_associate(struct iwl_priv *priv) break; } - iwl4965_sequence_reset(priv); - /* Enable Rx differential gain and sensitivity calibrations */ iwl_chain_noise_reset(priv); priv->start_calib = 1; @@ -2709,7 +2561,7 @@ static void iwl_bg_scan_completed(struct work_struct *work) * *****************************************************************************/ -#define UCODE_READY_TIMEOUT (2 * HZ) +#define UCODE_READY_TIMEOUT (4 * HZ) static int iwl4965_mac_start(struct ieee80211_hw *hw) { @@ -2762,21 +2614,19 @@ static int iwl4965_mac_start(struct ieee80211_hw *hw) /* Wait for START_ALIVE from Run Time ucode. Otherwise callbacks from * mac80211 will not be run successfully. */ - if (priv->ucode_type == UCODE_RT) { - ret = wait_event_interruptible_timeout(priv->wait_command_queue, - test_bit(STATUS_READY, &priv->status), - UCODE_READY_TIMEOUT); - if (!ret) { - if (!test_bit(STATUS_READY, &priv->status)) { - IWL_ERROR("START_ALIVE timeout after %dms.\n", - jiffies_to_msecs(UCODE_READY_TIMEOUT)); - ret = -ETIMEDOUT; - goto out_release_irq; - } + ret = wait_event_interruptible_timeout(priv->wait_command_queue, + test_bit(STATUS_READY, &priv->status), + UCODE_READY_TIMEOUT); + if (!ret) { + if (!test_bit(STATUS_READY, &priv->status)) { + IWL_ERROR("START_ALIVE timeout after %dms.\n", + jiffies_to_msecs(UCODE_READY_TIMEOUT)); + ret = -ETIMEDOUT; + goto out_release_irq; } - - priv->is_open = 1; } + + priv->is_open = 1; IWL_DEBUG_MAC80211("leave\n"); return 0; @@ -3009,7 +2859,7 @@ static void iwl4965_config_ap(struct iwl_priv *priv) return; /* The following should be done only at AP bring up */ - if ((priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) == 0) { + if (!(iwl_is_associated(priv))) { /* RXON - unassoc (to set timing command) */ priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; @@ -3172,26 +3022,18 @@ static void iwl4965_configure_filter(struct ieee80211_hw *hw, unsigned int *total_flags, int mc_count, struct dev_addr_list *mc_list) { - /* - * XXX: dummy - * see also iwl4965_connection_init_rx_config - */ struct iwl_priv *priv = hw->priv; - int new_flags = 0; - if (changed_flags & (FIF_PROMISC_IN_BSS | FIF_OTHER_BSS)) { - if (*total_flags & (FIF_PROMISC_IN_BSS | FIF_OTHER_BSS)) { - IWL_DEBUG_MAC80211("Enter: type %d (0x%x, 0x%x)\n", - IEEE80211_IF_TYPE_MNTR, - changed_flags, *total_flags); - /* queue work 'cuz mac80211 is holding a lock which - * prevents us from issuing (synchronous) f/w cmds */ - queue_work(priv->workqueue, &priv->set_monitor); - new_flags &= FIF_PROMISC_IN_BSS | - FIF_OTHER_BSS | - FIF_ALLMULTI; - } + + if (changed_flags & (*total_flags) & FIF_OTHER_BSS) { + IWL_DEBUG_MAC80211("Enter: type %d (0x%x, 0x%x)\n", + IEEE80211_IF_TYPE_MNTR, + changed_flags, *total_flags); + /* queue work 'cuz mac80211 is holding a lock which + * prevents us from issuing (synchronous) f/w cmds */ + queue_work(priv->workqueue, &priv->set_monitor); } - *total_flags = new_flags; + *total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI | + FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL; } static void iwl4965_mac_remove_interface(struct ieee80211_hw *hw, @@ -3556,17 +3398,6 @@ static int iwl4965_mac_get_stats(struct ieee80211_hw *hw, return 0; } -static u64 iwl4965_mac_get_tsf(struct ieee80211_hw *hw) -{ - struct iwl_priv *priv; - - priv = hw->priv; - IWL_DEBUG_MAC80211("enter\n"); - IWL_DEBUG_MAC80211("leave\n"); - - return 0; -} - static void iwl4965_mac_reset_tsf(struct ieee80211_hw *hw) { struct iwl_priv *priv = hw->priv; @@ -3575,7 +3406,6 @@ static void iwl4965_mac_reset_tsf(struct ieee80211_hw *hw) mutex_lock(&priv->mutex); IWL_DEBUG_MAC80211("enter\n"); - priv->lq_mngr.lq_ready = 0; spin_lock_irqsave(&priv->lock, flags); memset(&priv->current_ht_config, 0, sizeof(struct iwl_ht_info)); spin_unlock_irqrestore(&priv->lock, flags); @@ -3638,6 +3468,7 @@ static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *sk { struct iwl_priv *priv = hw->priv; unsigned long flags; + __le64 timestamp; mutex_lock(&priv->mutex); IWL_DEBUG_MAC80211("enter\n"); @@ -3662,6 +3493,8 @@ static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *sk priv->ibss_beacon = skb; priv->assoc_id = 0; + timestamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp; + priv->timestamp = le64_to_cpu(timestamp) + (priv->beacon_int * 1000); IWL_DEBUG_MAC80211("leave\n"); spin_unlock_irqrestore(&priv->lock, flags); @@ -3728,16 +3561,28 @@ static ssize_t show_version(struct device *d, { struct iwl_priv *priv = d->driver_data; struct iwl_alive_resp *palive = &priv->card_alive; + ssize_t pos = 0; + u16 eeprom_ver; if (palive->is_valid) - return sprintf(buf, "fw version: 0x%01X.0x%01X.0x%01X.0x%01X\n" - "fw type: 0x%01X 0x%01X\n", + pos += sprintf(buf + pos, + "fw version: 0x%01X.0x%01X.0x%01X.0x%01X\n" + "fw type: 0x%01X 0x%01X\n", palive->ucode_major, palive->ucode_minor, palive->sw_rev[0], palive->sw_rev[1], palive->ver_type, palive->ver_subtype); - else - return sprintf(buf, "fw not loaded\n"); + pos += sprintf(buf + pos, "fw not loaded\n"); + + if (priv->eeprom) { + eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION); + pos += sprintf(buf + pos, "EEPROM version: 0x%x\n", + eeprom_ver); + } else { + pos += sprintf(buf + pos, "EEPROM not initialzed\n"); + } + + return pos; } static DEVICE_ATTR(version, S_IWUSR | S_IRUGO, show_version, NULL); @@ -4106,7 +3951,7 @@ static ssize_t show_statistics(struct device *d, struct device_attribute *attr, char *buf) { struct iwl_priv *priv = dev_get_drvdata(d); - u32 size = sizeof(struct iwl4965_notif_statistics); + u32 size = sizeof(struct iwl_notif_statistics); u32 len = 0, ofs = 0; u8 *data = (u8 *) & priv->statistics; int rc = 0; @@ -4243,7 +4088,6 @@ static struct ieee80211_ops iwl4965_hw_ops = { .get_stats = iwl4965_mac_get_stats, .get_tx_stats = iwl4965_mac_get_tx_stats, .conf_tx = iwl4965_mac_conf_tx, - .get_tsf = iwl4965_mac_get_tsf, .reset_tsf = iwl4965_mac_reset_tsf, .beacon_update = iwl4965_mac_beacon_update, .bss_info_changed = iwl4965_bss_info_changed, @@ -4372,8 +4216,7 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e /************************ * 5. Setup HW constants ************************/ - /* Device-specific setup */ - if (priv->cfg->ops->lib->set_hw_params(priv)) { + if (iwl_set_hw_params(priv)) { IWL_ERROR("failed to set hw parameters\n"); goto out_free_eeprom; } @@ -4412,7 +4255,7 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e iwl_setup_deferred_work(priv); - iwl4965_setup_rx_handlers(priv); + iwl_setup_rx_handlers(priv); /******************** * 9. Conclude @@ -4461,8 +4304,6 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e static void __devexit iwl4965_pci_remove(struct pci_dev *pdev) { struct iwl_priv *priv = pci_get_drvdata(pdev); - struct list_head *p, *q; - int i; unsigned long flags; if (!priv) @@ -4491,14 +4332,6 @@ static void __devexit iwl4965_pci_remove(struct pci_dev *pdev) iwl_synchronize_irq(priv); - /* Free MAC hash list for ADHOC */ - for (i = 0; i < IWL_IBSS_MAC_HASH_SIZE; i++) { - list_for_each_safe(p, q, &priv->ibss_mac_hash[i]) { - list_del(p); - kfree(list_entry(p, struct iwl4965_ibss_seq, list)); - } - } - iwl_rfkill_unregister(priv); iwl4965_dealloc_ucode_pci(priv); @@ -4506,7 +4339,7 @@ static void __devexit iwl4965_pci_remove(struct pci_dev *pdev) iwl_rx_queue_free(priv, &priv->rxq); iwl_hw_txq_ctx_free(priv); - iwlcore_clear_stations_table(priv); + iwl_clear_stations_table(priv); iwl_eeprom_free(priv); diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 9f7224de6fd..ffaf7a6b681 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -357,6 +357,7 @@ static void p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb) rx_status.signal = hdr->rssi; /* XX correct? */ + rx_status.qual = (100 * hdr->rssi) / 127; rx_status.rate_idx = hdr->rate & 0xf; rx_status.freq = freq; rx_status.band = IEEE80211_BAND_2GHZ; |