diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl3945-base.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl3945-base.c | 228 |
1 files changed, 53 insertions, 175 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 5c10b87d033..92fa1a39c44 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -95,144 +95,6 @@ struct iwl_mod_params iwl3945_mod_params = { /* the rest are 0 by default */ }; -/*************** STATION TABLE MANAGEMENT **** - * mac80211 should be examined to determine if sta_info is duplicating - * the functionality provided here - */ - -/**************************************************************/ -#if 0 /* temporary disable till we add real remove station */ -/** - * iwl3945_remove_station - Remove driver's knowledge of station. - * - * NOTE: This does not remove station from device's station table. - */ -static u8 iwl3945_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap) -{ - int index = IWL_INVALID_STATION; - int i; - unsigned long flags; - - spin_lock_irqsave(&priv->sta_lock, flags); - - if (is_ap) - index = IWL_AP_ID; - else if (is_broadcast_ether_addr(addr)) - index = priv->hw_params.bcast_sta_id; - else - for (i = IWL_STA_ID; i < priv->hw_params.max_stations; i++) - if (priv->stations_39[i].used && - !compare_ether_addr(priv->stations_39[i].sta.sta.addr, - addr)) { - index = i; - break; - } - - if (unlikely(index == IWL_INVALID_STATION)) - goto out; - - if (priv->stations_39[index].used) { - priv->stations_39[index].used = 0; - priv->num_stations--; - } - - BUG_ON(priv->num_stations < 0); - -out: - spin_unlock_irqrestore(&priv->sta_lock, flags); - return 0; -} -#endif - -/** - * iwl3945_clear_stations_table - Clear the driver's station table - * - * NOTE: This does not clear or otherwise alter the device's station table. - */ -void iwl3945_clear_stations_table(struct iwl_priv *priv) -{ - unsigned long flags; - - spin_lock_irqsave(&priv->sta_lock, flags); - - priv->num_stations = 0; - memset(priv->stations_39, 0, sizeof(priv->stations_39)); - - spin_unlock_irqrestore(&priv->sta_lock, flags); -} - -/** - * iwl3945_add_station - Add station to station tables in driver and device - */ -u8 iwl3945_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap, u8 flags, struct ieee80211_sta_ht_cap *ht_info) -{ - int i; - int index = IWL_INVALID_STATION; - struct iwl3945_station_entry *station; - unsigned long flags_spin; - u8 rate; - - spin_lock_irqsave(&priv->sta_lock, flags_spin); - if (is_ap) - index = IWL_AP_ID; - else if (is_broadcast_ether_addr(addr)) - index = 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_39[i].sta.sta.addr, - addr)) { - index = i; - break; - } - - if (!priv->stations_39[i].used && - index == IWL_INVALID_STATION) - index = i; - } - - /* These two conditions has the same outcome but keep them separate - since they have different meaning */ - if (unlikely(index == IWL_INVALID_STATION)) { - spin_unlock_irqrestore(&priv->sta_lock, flags_spin); - return index; - } - - if (priv->stations_39[index].used && - !compare_ether_addr(priv->stations_39[index].sta.sta.addr, addr)) { - spin_unlock_irqrestore(&priv->sta_lock, flags_spin); - return index; - } - - IWL_DEBUG_ASSOC(priv, "Add STA ID %d: %pM\n", index, addr); - station = &priv->stations_39[index]; - station->used = 1; - priv->num_stations++; - - /* Set up the REPLY_ADD_STA command to send to device */ - memset(&station->sta, 0, sizeof(struct iwl3945_addsta_cmd)); - memcpy(station->sta.sta.addr, addr, ETH_ALEN); - station->sta.mode = 0; - station->sta.sta.sta_id = index; - station->sta.station_flags = 0; - - if (priv->band == IEEE80211_BAND_5GHZ) - rate = IWL_RATE_6M_PLCP; - else - rate = IWL_RATE_1M_PLCP; - - /* Turn on both antennas for the station... */ - station->sta.rate_n_flags = - iwl3945_hw_set_rate_n_flags(rate, RATE_MCS_ANT_AB_MSK); - - spin_unlock_irqrestore(&priv->sta_lock, flags_spin); - - /* Add station to device's station table */ - iwl_send_add_sta(priv, - (struct iwl_addsta_cmd *)&station->sta, flags); - return index; - -} - /** * iwl3945_get_antenna_flags - Get antenna flags for RXON command * @priv: eeprom and antenna fields are used to determine antenna flags @@ -289,32 +151,31 @@ static int iwl3945_set_ccmp_dynamic_key_info(struct iwl_priv *priv, key_flags &= ~STA_KEY_FLG_INVALID; spin_lock_irqsave(&priv->sta_lock, flags); - priv->stations_39[sta_id].keyinfo.alg = keyconf->alg; - priv->stations_39[sta_id].keyinfo.keylen = keyconf->keylen; - memcpy(priv->stations_39[sta_id].keyinfo.key, keyconf->key, + priv->stations[sta_id].keyinfo.alg = keyconf->alg; + priv->stations[sta_id].keyinfo.keylen = keyconf->keylen; + memcpy(priv->stations[sta_id].keyinfo.key, keyconf->key, keyconf->keylen); - memcpy(priv->stations_39[sta_id].sta.key.key, keyconf->key, + memcpy(priv->stations[sta_id].sta.key.key, keyconf->key, keyconf->keylen); - if ((priv->stations_39[sta_id].sta.key.key_flags & STA_KEY_FLG_ENCRYPT_MSK) + if ((priv->stations[sta_id].sta.key.key_flags & STA_KEY_FLG_ENCRYPT_MSK) == STA_KEY_FLG_NO_ENC) - priv->stations_39[sta_id].sta.key.key_offset = + priv->stations[sta_id].sta.key.key_offset = iwl_get_free_ucode_key_index(priv); /* else, we are overriding an existing key => no need to allocated room * in uCode. */ - WARN(priv->stations_39[sta_id].sta.key.key_offset == WEP_INVALID_OFFSET, + WARN(priv->stations[sta_id].sta.key.key_offset == WEP_INVALID_OFFSET, "no space for a new key"); - priv->stations_39[sta_id].sta.key.key_flags = key_flags; - priv->stations_39[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK; - priv->stations_39[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; + priv->stations[sta_id].sta.key.key_flags = key_flags; + priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK; + priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; IWL_DEBUG_INFO(priv, "hwcrypto: modify ucode station key info\n"); - ret = iwl_send_add_sta(priv, - (struct iwl_addsta_cmd *)&priv->stations_39[sta_id].sta, CMD_ASYNC); + ret = iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); spin_unlock_irqrestore(&priv->sta_lock, flags); @@ -340,17 +201,16 @@ static int iwl3945_clear_sta_key_info(struct iwl_priv *priv, u8 sta_id) unsigned long flags; spin_lock_irqsave(&priv->sta_lock, flags); - memset(&priv->stations_39[sta_id].keyinfo, 0, sizeof(struct iwl_hw_key)); - memset(&priv->stations_39[sta_id].sta.key, 0, + memset(&priv->stations[sta_id].keyinfo, 0, sizeof(struct iwl_hw_key)); + memset(&priv->stations[sta_id].sta.key, 0, sizeof(struct iwl4965_keyinfo)); - priv->stations_39[sta_id].sta.key.key_flags = STA_KEY_FLG_NO_ENC; - priv->stations_39[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK; - priv->stations_39[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; + priv->stations[sta_id].sta.key.key_flags = STA_KEY_FLG_NO_ENC; + priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK; + priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; spin_unlock_irqrestore(&priv->sta_lock, flags); IWL_DEBUG_INFO(priv, "hwcrypto: clear ucode station key info\n"); - iwl_send_add_sta(priv, - (struct iwl_addsta_cmd *)&priv->stations_39[sta_id].sta, 0); + iwl_send_add_sta(priv, &priv->stations[sta_id].sta, 0); return 0; } @@ -578,7 +438,7 @@ static void iwl3945_build_tx_cmd_hwcrypto(struct iwl_priv *priv, int sta_id) { struct iwl3945_tx_cmd *tx = (struct iwl3945_tx_cmd *)cmd->cmd.payload; - struct iwl_hw_key *keyinfo = &priv->stations_39[sta_id].keyinfo; + struct iwl_hw_key *keyinfo = &priv->stations[sta_id].keyinfo; switch (keyinfo->alg) { case ALG_CCMP: @@ -753,7 +613,7 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) if (ieee80211_is_data_qos(fc)) { qc = ieee80211_get_qos_ctl(hdr); tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; - seq_number = priv->stations_39[sta_id].tid[tid].seq_number & + seq_number = priv->stations[sta_id].tid[tid].seq_number & IEEE80211_SCTL_SEQ; hdr->seq_ctrl = cpu_to_le16(seq_number) | (hdr->seq_ctrl & @@ -813,7 +673,7 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) if (!ieee80211_has_morefrags(hdr->frame_control)) { txq->need_update = 1; if (qc) - priv->stations_39[sta_id].tid[tid].seq_number = seq_number; + priv->stations[sta_id].tid[tid].seq_number = seq_number; } else { wait_write_ptr = 1; txq->need_update = 0; @@ -1316,7 +1176,7 @@ static int iwl3945_rx_queue_restock(struct iwl_priv *priv) /* If we've added more space for the firmware to place data, tell it. * Increment device's write pointer in multiples of 8. */ - if ((write != (rxq->write & ~0x7)) + if ((rxq->write_actual != (rxq->write & ~0x7)) || (abs(rxq->write - rxq->read) > 7)) { spin_lock_irqsave(&rxq->lock, flags); rxq->need_update = 1; @@ -1337,7 +1197,7 @@ static int iwl3945_rx_queue_restock(struct iwl_priv *priv) * Also restock the Rx queue via iwl3945_rx_queue_restock. * This is called as a scheduled work item (except for during initialization) */ -static void iwl3945_rx_allocate(struct iwl_priv *priv) +static void iwl3945_rx_allocate(struct iwl_priv *priv, gfp_t priority) { struct iwl_rx_queue *rxq = &priv->rxq; struct list_head *element; @@ -1360,7 +1220,7 @@ static void iwl3945_rx_allocate(struct iwl_priv *priv) /* Alloc a new receive buffer */ rxb->skb = alloc_skb(priv->hw_params.rx_buf_size, - GFP_KERNEL); + priority); if (!rxb->skb) { if (net_ratelimit()) IWL_CRIT(priv, ": Can not allocate SKB buffers\n"); @@ -1419,6 +1279,7 @@ void iwl3945_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq) * not restocked the Rx queue with fresh buffers */ rxq->read = rxq->write = 0; rxq->free_count = 0; + rxq->write_actual = 0; spin_unlock_irqrestore(&rxq->lock, flags); } @@ -1427,13 +1288,21 @@ void iwl3945_rx_replenish(void *data) struct iwl_priv *priv = data; unsigned long flags; - iwl3945_rx_allocate(priv); + iwl3945_rx_allocate(priv, GFP_KERNEL); spin_lock_irqsave(&priv->lock, flags); iwl3945_rx_queue_restock(priv); spin_unlock_irqrestore(&priv->lock, flags); } +static void iwl3945_rx_replenish_now(struct iwl_priv *priv) +{ + iwl3945_rx_allocate(priv, GFP_ATOMIC); + + iwl3945_rx_queue_restock(priv); +} + + /* Assumes that the skb field of the buffers in 'pool' is kept accurate. * If an SKB has been detached, the POOL needs to have its SKB set to NULL * This free routine walks the list of POOL entries and if SKB is set to @@ -1556,13 +1425,19 @@ static void iwl3945_rx_handle(struct iwl_priv *priv) unsigned long flags; u8 fill_rx = 0; u32 count = 8; + int total_empty = 0; /* uCode's read index (stored in shared DRAM) indicates the last Rx * buffer that the driver may process (last buffer filled by ucode). */ r = le16_to_cpu(rxq->rb_stts->closed_rb_num) & 0x0FFF; i = rxq->read; - if (iwl_rx_queue_space(rxq) > (RX_QUEUE_SIZE / 2)) + /* calculate total frames need to be restock after handling RX */ + total_empty = r - priv->rxq.write_actual; + if (total_empty < 0) + total_empty += RX_QUEUE_SIZE; + + if (total_empty > (RX_QUEUE_SIZE / 2)) fill_rx = 1; /* Rx interrupt, but nothing sent from uCode */ if (i == r) @@ -1639,7 +1514,7 @@ static void iwl3945_rx_handle(struct iwl_priv *priv) count++; if (count >= 8) { priv->rxq.read = i; - iwl3945_rx_queue_restock(priv); + iwl3945_rx_replenish_now(priv); count = 0; } } @@ -1647,7 +1522,10 @@ static void iwl3945_rx_handle(struct iwl_priv *priv) /* Backtrack one entry */ priv->rxq.read = i; - iwl3945_rx_queue_restock(priv); + if (fill_rx) + iwl3945_rx_replenish_now(priv); + else + iwl3945_rx_queue_restock(priv); } /* call this function to flush any scheduled tasklet */ @@ -2589,7 +2467,7 @@ static void iwl3945_alive_start(struct iwl_priv *priv) goto restart; } - priv->cfg->ops->smgmt->clear_station_table(priv); + iwl_clear_stations_table(priv); rfkill = iwl_read_prph(priv, APMG_RFKILL_REG); IWL_DEBUG_INFO(priv, "RFKILL status: 0x%x\n", rfkill); @@ -2681,7 +2559,7 @@ static void __iwl3945_down(struct iwl_priv *priv) set_bit(STATUS_EXIT_PENDING, &priv->status); iwl3945_led_unregister(priv); - priv->cfg->ops->smgmt->clear_station_table(priv); + iwl_clear_stations_table(priv); /* Unblock any waiting calls */ wake_up_interruptible_all(&priv->wait_command_queue); @@ -2833,7 +2711,7 @@ static int __iwl3945_up(struct iwl_priv *priv) for (i = 0; i < MAX_HW_RESTARTS; i++) { - priv->cfg->ops->smgmt->clear_station_table(priv); + iwl_clear_stations_table(priv); /* load bootstrap state machine, * load bootstrap program into processor's memory, @@ -3247,7 +3125,7 @@ void iwl3945_post_associate(struct iwl_priv *priv) case NL80211_IFTYPE_ADHOC: priv->assoc_id = 1; - priv->cfg->ops->smgmt->add_station(priv, priv->bssid, 0, 0, NULL); + iwl_add_station(priv, priv->bssid, 0, CMD_SYNC, NULL); iwl3945_sync_sta(priv, IWL_STA_ID, (priv->band == IEEE80211_BAND_5GHZ) ? IWL_RATE_6M_PLCP : IWL_RATE_1M_PLCP, @@ -3438,7 +3316,7 @@ void iwl3945_config_ap(struct iwl_priv *priv) /* restore RXON assoc */ priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK; iwlcore_commit_rxon(priv); - priv->cfg->ops->smgmt->add_station(priv, iwl_bcast_addr, 0, 0, NULL); + iwl_add_station(priv, iwl_bcast_addr, 0, CMD_SYNC, NULL); } iwl3945_send_beacon_cmd(priv); @@ -3469,7 +3347,7 @@ static int iwl3945_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, static_key = !iwl_is_associated(priv); if (!static_key) { - sta_id = priv->cfg->ops->smgmt->find_station(priv, addr); + sta_id = iwl_find_station(priv, addr); if (sta_id == IWL_INVALID_STATION) { IWL_DEBUG_MAC80211(priv, "leave - %pM not in station map.\n", addr); @@ -4044,7 +3922,7 @@ static int iwl3945_init_drv(struct iwl_priv *priv) mutex_init(&priv->mutex); /* Clear the driver's (not device's) station table */ - priv->cfg->ops->smgmt->clear_station_table(priv); + iwl_clear_stations_table(priv); priv->data_retry_limit = -1; priv->ieee_channels = NULL; @@ -4407,7 +4285,7 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev) iwl3945_hw_txq_ctx_free(priv); iwl3945_unset_hw_params(priv); - priv->cfg->ops->smgmt->clear_station_table(priv); + iwl_clear_stations_table(priv); /*netif_stop_queue(dev); */ flush_workqueue(priv->workqueue); |