tx_cmd->supp_rates[1], tx_cmd->supp_rates[0]);
}
-static u8 iwl3945_sync_sta(struct iwl_priv *priv, int sta_id,
- u16 tx_rate, u8 flags)
+static u8 iwl3945_sync_sta(struct iwl_priv *priv, int sta_id, u16 tx_rate)
{
unsigned long flags_spin;
struct iwl_station_entry *station;
station->sta.sta.modify_mask = STA_MODIFY_TX_RATE_MSK;
station->sta.rate_n_flags = cpu_to_le16(tx_rate);
station->sta.mode = STA_CONTROL_MODIFY_MSK;
-
+ iwl_send_add_sta(priv, &station->sta, CMD_ASYNC);
spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
- iwl_send_add_sta(priv, &station->sta, flags);
IWL_DEBUG_RATE(priv, "SCALE sync station %d to rate %d\n",
sta_id, tx_rate);
return sta_id;
iwl3945_sync_sta(priv, vif_priv->ibss_bssid_sta_id,
(priv->band == IEEE80211_BAND_5GHZ) ?
- IWL_RATE_6M_PLCP : IWL_RATE_1M_PLCP,
- CMD_ASYNC);
+ IWL_RATE_6M_PLCP : IWL_RATE_1M_PLCP);
iwl3945_rate_scale_init(priv->hw, vif_priv->ibss_bssid_sta_id);
return 0;
int sta_id;
int freed;
u8 *qc = NULL;
+ unsigned long flags;
if ((index >= txq->q.n_bd) || (iwl_queue_used(&txq->q, index) == 0)) {
IWL_ERR(priv, "Read index for DMA queue txq_id (%d) index %d "
return;
}
+ spin_lock_irqsave(&priv->sta_lock, flags);
if (txq->sched_retry) {
const u32 scd_ssn = iwl4965_get_scd_ssn(tx_resp);
struct iwl_ht_agg *agg = NULL;
-
WARN_ON(!qc);
agg = &priv->stations[sta_id].tid[tid].agg;
iwlagn_txq_check_empty(priv, sta_id, tid, txq_id);
iwl_check_abort_status(priv, tx_resp->frame_count, status);
+
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
}
static int iwl4965_calc_rssi(struct iwl_priv *priv,
int tid;
int sta_id;
int freed;
+ unsigned long flags;
if ((index >= txq->q.n_bd) || (iwl_queue_used(&txq->q, index) == 0)) {
IWL_ERR(priv, "Read index for DMA queue txq_id (%d) index %d "
tid = (tx_resp->ra_tid & IWL50_TX_RES_TID_MSK) >> IWL50_TX_RES_TID_POS;
sta_id = (tx_resp->ra_tid & IWL50_TX_RES_RA_MSK) >> IWL50_TX_RES_RA_POS;
+ spin_lock_irqsave(&priv->sta_lock, flags);
if (txq->sched_retry) {
const u32 scd_ssn = iwlagn_get_scd_ssn(tx_resp);
- struct iwl_ht_agg *agg = NULL;
+ struct iwl_ht_agg *agg;
agg = &priv->stations[sta_id].tid[tid].agg;
iwlagn_txq_check_empty(priv, sta_id, tid, txq_id);
iwl_check_abort_status(priv, tx_resp->frame_count, status);
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
}
void iwlagn_rx_handler_setup(struct iwl_priv *priv)
void iwl_free_tfds_in_queue(struct iwl_priv *priv,
int sta_id, int tid, int freed)
{
+ WARN_ON(!spin_is_locked(&priv->sta_lock));
+
if (priv->stations[sta_id].tid[tid].tfds_in_queue >= freed)
priv->stations[sta_id].tid[tid].tfds_in_queue -= freed;
else {
}
txq_id = get_queue_from_ac(skb_get_queue_mapping(skb));
+
+ /* irqs already disabled/saved above when locking priv->lock */
+ spin_lock(&priv->sta_lock);
+
if (ieee80211_is_data_qos(fc)) {
qc = ieee80211_get_qos_ctl(hdr);
tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
- if (unlikely(tid >= MAX_TID_COUNT))
+ if (WARN_ON_ONCE(tid >= MAX_TID_COUNT)) {
+ spin_unlock(&priv->sta_lock);
goto drop_unlock;
+ }
seq_number = priv->stations[sta_id].tid[tid].seq_number;
seq_number &= IEEE80211_SCTL_SEQ;
hdr->seq_ctrl = hdr->seq_ctrl &
swq_id = txq->swq_id;
q = &txq->q;
- if (unlikely(iwl_queue_space(q) < q->high_mark))
+ if (unlikely(iwl_queue_space(q) < q->high_mark)) {
+ spin_unlock(&priv->sta_lock);
goto drop_unlock;
+ }
- if (ieee80211_is_data_qos(fc))
+ if (ieee80211_is_data_qos(fc)) {
priv->stations[sta_id].tid[tid].tfds_in_queue++;
+ if (!ieee80211_has_morefrags(fc))
+ priv->stations[sta_id].tid[tid].seq_number = seq_number;
+ }
+
+ spin_unlock(&priv->sta_lock);
/* Set up driver data for this TFD */
memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl_tx_info));
if (!ieee80211_has_morefrags(hdr->frame_control)) {
txq->need_update = 1;
- if (qc)
- priv->stations[sta_id].tid[tid].seq_number = seq_number;
} else {
wait_write_ptr = 1;
txq->need_update = 0;
if (ret)
return ret;
+ spin_lock_irqsave(&priv->sta_lock, flags);
+ tid_data = &priv->stations[sta_id].tid[tid];
if (tid_data->tfds_in_queue == 0) {
IWL_DEBUG_HT(priv, "HW queue is empty\n");
tid_data->agg.state = IWL_AGG_ON;
tid_data->tfds_in_queue);
tid_data->agg.state = IWL_EMPTYING_HW_QUEUE_ADDBA;
}
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
return ret;
}
return -ENXIO;
}
+ spin_lock_irqsave(&priv->sta_lock, flags);
+
if (priv->stations[sta_id].tid[tid].agg.state ==
IWL_EMPTYING_HW_QUEUE_ADDBA) {
IWL_DEBUG_HT(priv, "AGG stop before setup done\n");
ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
priv->stations[sta_id].tid[tid].agg.state = IWL_AGG_OFF;
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
return 0;
}
IWL_DEBUG_HT(priv, "Stopping a non empty AGG HW QUEUE\n");
priv->stations[sta_id].tid[tid].agg.state =
IWL_EMPTYING_HW_QUEUE_DELBA;
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
return 0;
}
IWL_DEBUG_HT(priv, "HW queue is empty\n");
priv->stations[sta_id].tid[tid].agg.state = IWL_AGG_OFF;
- spin_lock_irqsave(&priv->lock, flags);
+ /* do not restore/save irqs */
+ spin_unlock(&priv->sta_lock);
+ spin_lock(&priv->lock);
+
/*
* the only reason this call can fail is queue number out of range,
* which can happen if uCode is reloaded and all the station
u8 *addr = priv->stations[sta_id].sta.sta.addr;
struct iwl_tid_data *tid_data = &priv->stations[sta_id].tid[tid];
+ WARN_ON(!spin_is_locked(&priv->sta_lock));
+
switch (priv->stations[sta_id].tid[tid].agg.state) {
case IWL_EMPTYING_HW_QUEUE_DELBA:
/* We are reclaiming the last packet of the */
}
break;
}
+
return 0;
}
int index;
int sta_id;
int tid;
+ unsigned long flags;
/* "flow" corresponds to Tx queue */
u16 scd_flow = le16_to_cpu(ba_resp->scd_flow);
/* 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 */
+ spin_lock_irqsave(&priv->sta_lock, flags);
IWL_DEBUG_TX_REPLY(priv, "REPLY_COMPRESSED_BA [%d] Received from %pM, "
"sta_id = %d\n",
iwlagn_txq_check_empty(priv, sta_id, tid, scd_flow);
}
+
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
}
u8 bssid[ETH_ALEN]; /* used only on 3945 but filled by core */
u8 mac_addr[ETH_ALEN];
- /*station table variables */
+ /* station table variables */
+
+ /* Note: if lock and sta_lock are needed, lock must be acquired first */
spinlock_t sta_lock;
int num_stations;
struct iwl_station_entry stations[IWL_STATION_COUNT];
struct ieee80211_sta_ht_cap *ht_info,
u8 *sta_id_r)
{
- struct iwl_station_entry *station;
unsigned long flags_spin;
int ret = 0;
u8 sta_id;
+ struct iwl_addsta_cmd sta_cmd;
*sta_id_r = 0;
spin_lock_irqsave(&priv->sta_lock, flags_spin);
}
priv->stations[sta_id].used |= IWL_STA_UCODE_INPROGRESS;
- station = &priv->stations[sta_id];
+ memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd));
spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
/* Add station to device's station table */
- ret = iwl_send_add_sta(priv, &station->sta, CMD_SYNC);
+ ret = iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
if (ret) {
- IWL_ERR(priv, "Adding station %pM failed.\n", station->sta.sta.addr);
spin_lock_irqsave(&priv->sta_lock, flags_spin);
+ IWL_ERR(priv, "Adding station %pM failed.\n",
+ priv->stations[sta_id].sta.sta.addr);
priv->stations[sta_id].used &= ~IWL_STA_DRIVER_ACTIVE;
priv->stations[sta_id].used &= ~IWL_STA_UCODE_INPROGRESS;
spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
}
static int iwl_send_remove_station(struct iwl_priv *priv,
- struct iwl_station_entry *station)
+ const u8 *addr, int sta_id)
{
struct iwl_rx_packet *pkt;
int ret;
memset(&rm_sta_cmd, 0, sizeof(rm_sta_cmd));
rm_sta_cmd.num_sta = 1;
- memcpy(&rm_sta_cmd.addr, &station->sta.sta.addr , ETH_ALEN);
+ memcpy(&rm_sta_cmd.addr, addr, ETH_ALEN);
cmd.flags |= CMD_WANT_SKB;
switch (pkt->u.rem_sta.status) {
case REM_STA_SUCCESS_MSK:
spin_lock_irqsave(&priv->sta_lock, flags_spin);
- iwl_sta_ucode_deactivate(priv, station->sta.sta.sta_id);
+ iwl_sta_ucode_deactivate(priv, sta_id);
spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
IWL_DEBUG_ASSOC(priv, "REPLY_REMOVE_STA PASSED\n");
break;
int iwl_remove_station(struct iwl_priv *priv, const u8 sta_id,
const u8 *addr)
{
- struct iwl_station_entry *station;
unsigned long flags;
if (!iwl_is_ready(priv)) {
BUG_ON(priv->num_stations < 0);
- station = &priv->stations[sta_id];
spin_unlock_irqrestore(&priv->sta_lock, flags);
- return iwl_send_remove_station(priv, station);
+ return iwl_send_remove_station(priv, addr, sta_id);
out_err:
spin_unlock_irqrestore(&priv->sta_lock, flags);
return -EINVAL;
*/
void iwl_restore_stations(struct iwl_priv *priv)
{
- struct iwl_station_entry *station;
+ struct iwl_addsta_cmd sta_cmd;
+ struct iwl_link_quality_cmd lq;
unsigned long flags_spin;
int i;
bool found = false;
int ret;
+ bool send_lq;
if (!iwl_is_ready(priv)) {
IWL_DEBUG_INFO(priv, "Not ready yet, not restoring any stations.\n");
for (i = 0; i < priv->hw_params.max_stations; i++) {
if ((priv->stations[i].used & IWL_STA_UCODE_INPROGRESS)) {
+ memcpy(&sta_cmd, &priv->stations[i].sta,
+ sizeof(struct iwl_addsta_cmd));
+ send_lq = false;
+ if (priv->stations[i].lq) {
+ memcpy(&lq, priv->stations[i].lq,
+ sizeof(struct iwl_link_quality_cmd));
+ send_lq = true;
+ }
spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
- station = &priv->stations[i];
- ret = iwl_send_add_sta(priv, &priv->stations[i].sta, CMD_SYNC);
+ ret = iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
if (ret) {
- IWL_ERR(priv, "Adding station %pM failed.\n",
- station->sta.sta.addr);
spin_lock_irqsave(&priv->sta_lock, flags_spin);
+ IWL_ERR(priv, "Adding station %pM failed.\n",
+ priv->stations[i].sta.sta.addr);
priv->stations[i].used &= ~IWL_STA_DRIVER_ACTIVE;
priv->stations[i].used &= ~IWL_STA_UCODE_INPROGRESS;
spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
* Rate scaling has already been initialized, send
* current LQ command
*/
- if (station->lq)
- iwl_send_lq_cmd(priv, station->lq, CMD_SYNC, true);
+ if (send_lq)
+ iwl_send_lq_cmd(priv, &lq, CMD_SYNC, true);
spin_lock_irqsave(&priv->sta_lock, flags_spin);
priv->stations[i].used &= ~IWL_STA_UCODE_INPROGRESS;
}
priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_TID_DISABLE_TX;
priv->stations[sta_id].sta.tid_disable_tx &= cpu_to_le16(~(1 << tid));
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);
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
}
EXPORT_SYMBOL(iwl_sta_tx_modify_enable_tid);
int tid)
{
unsigned long flags;
- int sta_id;
+ int sta_id, ret;
sta_id = iwl_sta_id(sta);
if (sta_id == IWL_INVALID_STATION) {
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;
+ ret = iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
spin_unlock_irqrestore(&priv->sta_lock, flags);
- return iwl_send_add_sta(priv, &priv->stations[sta_id].sta,
- CMD_ASYNC);
+ return ret;
+
}
EXPORT_SYMBOL(iwl_sta_rx_agg_stop);
priv->stations[sta_id].sta.sta.modify_mask = 0;
priv->stations[sta_id].sta.sleep_tx_count = 0;
priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+ iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
spin_unlock_irqrestore(&priv->sta_lock, flags);
- iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
}
EXPORT_SYMBOL(iwl_sta_modify_ps_wake);
STA_MODIFY_SLEEP_TX_COUNT_MSK;
priv->stations[sta_id].sta.sleep_tx_count = cpu_to_le16(cnt);
priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+ iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
spin_unlock_irqrestore(&priv->sta_lock, flags);
- iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
}
EXPORT_SYMBOL(iwl_sta_modify_sleep_tx_count);
static int iwl3945_clear_sta_key_info(struct iwl_priv *priv, u8 sta_id)
{
unsigned long flags;
+ struct iwl_addsta_cmd sta_cmd;
spin_lock_irqsave(&priv->sta_lock, flags);
memset(&priv->stations[sta_id].keyinfo, 0, sizeof(struct iwl_hw_key));
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;
+ memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd));
spin_unlock_irqrestore(&priv->sta_lock, flags);
IWL_DEBUG_INFO(priv, "hwcrypto: clear ucode station key info\n");
- iwl_send_add_sta(priv, &priv->stations[sta_id].sta, 0);
- return 0;
+ return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
}
static int iwl3945_set_dynamic_key(struct iwl_priv *priv,