bool
_il_grab_nic_access(struct il_priv *il)
{ int ret;
u32 val;
/* this bit wakes up the NIC */
_il_set_bit(il, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
/* * These bits say the device is running, and should keep running for * at least a short while (at least as long as MAC_ACCESS_REQ stays 1), * but they do not indicate that embedded SRAM is restored yet; * 3945 and 4965 have volatile SRAM, and must save/restore contents * to/from host DRAM when sleeping/waking for power-saving. * Each direction takes approximately 1/4 millisecond; with this * overhead, it's a good idea to grab and hold MAC_ACCESS_REQUEST if a * series of register accesses are expected (e.g. reading Event Log), * to keep device from sleeping. * * CSR_UCODE_DRV_GP1 register bit MAC_SLEEP == 0 indicates that * SRAM is okay/restored. We don't check that here because this call * is just for hardware register access; but GP1 MAC_SLEEP check is a * good idea before accessing 3945/4965 SRAM (e.g. reading Event Log). *
*/
ret =
_il_poll_bit(il, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN,
(CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY |
CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), 15000); if (unlikely(ret < 0)) {
val = _il_rd(il, CSR_GP_CNTRL);
WARN_ONCE(1, "Timeout waiting for ucode processor access " "(CSR_GP_CNTRL 0x%08x)\n", val);
_il_wr(il, CSR_RESET, CSR_RESET_REG_FLAG_FORCE_NMI); returnfalse;
}
ret = wait_event_timeout(il->wait_command_queue,
!test_bit(S_HCMD_ACTIVE, &il->status),
HOST_COMPLETE_TIMEOUT); if (!ret) { if (test_bit(S_HCMD_ACTIVE, &il->status)) {
IL_ERR("Error sending %s: time out after %dms.\n",
il_get_cmd_string(cmd->id),
jiffies_to_msecs(HOST_COMPLETE_TIMEOUT));
clear_bit(S_HCMD_ACTIVE, &il->status);
D_INFO("Clearing HCMD_ACTIVE for command %s\n",
il_get_cmd_string(cmd->id));
ret = -ETIMEDOUT; goto cancel;
}
}
if (test_bit(S_RFKILL, &il->status)) {
IL_ERR("Command %s aborted: RF KILL Switch\n",
il_get_cmd_string(cmd->id));
ret = -ECANCELED; goto fail;
} if (test_bit(S_FW_ERROR, &il->status)) {
IL_ERR("Command %s failed: FW Error\n",
il_get_cmd_string(cmd->id));
ret = -EIO; goto fail;
} if ((cmd->flags & CMD_WANT_SKB) && !cmd->reply_page) {
IL_ERR("Error: Response NULL in '%s'\n",
il_get_cmd_string(cmd->id));
ret = -EIO; goto cancel;
}
ret = 0; goto out;
cancel: if (cmd->flags & CMD_WANT_SKB) { /* * Cancel the CMD_WANT_SKB flag for the cmd in the * TX cmd queue. Otherwise in case the cmd comes * in later, it will possibly set an invalid * address (cmd->meta.source).
*/
il->txq[il->cmd_queue].meta[cmd_idx].flags &= ~CMD_WANT_SKB;
}
fail: if (cmd->reply_page) {
il_free_pages(il, cmd->reply_page);
cmd->reply_page = 0;
}
out: return ret;
}
EXPORT_SYMBOL(il_send_cmd_sync);
int
il_send_cmd(struct il_priv *il, struct il_host_cmd *cmd)
{ if (cmd->flags & CMD_ASYNC) return il_send_cmd_async(il, cmd);
/* * Adjust led blink rate to compensate on a MAC Clock difference on every HW * Led blink rate analysis showed an average deviation of 0% on 3945, * 5% on 4965 HW. * Need to compensate on the led on/off time per HW according to the deviation * to achieve the desired led frequency * The calculation is: (100-averageDeviation)/100 * blinkTime * For code efficiency the calculation will be: * compensation = (100 - averageDeviation) * 64 / 100 * NewBlinkTime = (compensation * BlinkTime) / 64
*/ staticinline u8
il_blink_compensation(struct il_priv *il, u8 time, u16 compensation)
{ if (!compensation) {
IL_ERR("undefined blink compensation: " "use pre-defined blinking time\n"); return time;
}
return (u8) ((time * compensation) >> 6);
}
/* Set led pattern command */ staticint
il_led_cmd(struct il_priv *il, unsignedlong on, unsignedlong off)
{ struct il_led_cmd led_cmd = {
.id = IL_LED_LINK,
.interval = IL_DEF_LED_INTRVL
}; int ret;
if (!test_bit(S_READY, &il->status)) return -EBUSY;
if (il->blink_on == on && il->blink_off == off) return 0;
if (off == 0) { /* led is SOLID_ON */
on = IL_LED_SOLID;
}
D_LED("Led blink time compensation=%u\n",
il->cfg->led_compensation);
led_cmd.on =
il_blink_compensation(il, on,
il->cfg->led_compensation);
led_cmd.off =
il_blink_compensation(il, off,
il->cfg->led_compensation);
ret = il->ops->send_led_cmd(il, &led_cmd); if (!ret) {
il->blink_on = on;
il->blink_off = off;
} return ret;
}
/************************** EEPROM BANDS **************************** * * The il_eeprom_band definitions below provide the mapping from the * EEPROM contents to the specific channel number supported for each * band. * * For example, il_priv->eeprom.band_3_channels[4] from the band_3 * definition below maps to physical channel 42 in the 5.2GHz spectrum. * The specific geography and calibration information for that channel * is contained in the eeprom map itself. * * During init, we copy the eeprom information and channel map * information into il->channel_info_24/52 and il->channel_map_24/52 * * channel_map_24/52 provides the idx in the channel_info array for a * given channel. We have to have two separate maps as there is channel * overlap with the 2.4GHz and 5.2GHz spectrum as seen in band_1 and * band_2 * * A value of 0xff stored in the channel_map indicates that the channel * is not supported by the hardware at all. * * A value of 0xfe in the channel_map indicates that the channel is not * valid for Tx with the current hardware. This means that * while the system can tune and receive on a given channel, it may not * be able to associate or transmit any frames on that * channel. There is no corresponding channel information for that * entry. *
*********************************************************************/
/* * il_eeprom_init - read EEPROM contents * * Load the EEPROM contents from adapter into il->eeprom * * NOTE: This routine uses the non-debug IO access functions.
*/ int
il_eeprom_init(struct il_priv *il)
{
__le16 *e;
u32 gp = _il_rd(il, CSR_EEPROM_GP); int sz; int ret; int addr;
ret = il_eeprom_verify_signature(il); if (ret < 0) {
IL_ERR("EEPROM not found, EEPROM_GP=0x%08x\n", gp);
ret = -ENOENT; goto err;
}
/* Make sure driver (instead of uCode) is allowed to read EEPROM */
ret = il->ops->eeprom_acquire_semaphore(il); if (ret < 0) {
IL_ERR("Failed to acquire EEPROM semaphore.\n");
ret = -ENOENT; goto err;
}
/* eeprom is an array of 16bit values */ for (addr = 0; addr < sz; addr += sizeof(u16)) {
u32 r;
ret = 0;
done:
il->ops->eeprom_release_semaphore(il);
err: if (ret)
il_eeprom_free(il); /* Reset chip to save power until we load uCode during "up". */
il_apm_stop(il); return ret;
}
EXPORT_SYMBOL(il_eeprom_init);
/* * il_init_channel_map - Set up driver's info for all possible channels
*/ int
il_init_channel_map(struct il_priv *il)
{ int eeprom_ch_count = 0; const u8 *eeprom_ch_idx = NULL; conststruct il_eeprom_channel *eeprom_ch_info = NULL; int band, ch; struct il_channel_info *ch_info;
if (il->channel_count) {
D_EEPROM("Channel map already initialized.\n"); return 0;
}
D_EEPROM("Initializing regulatory info from EEPROM\n");
D_EEPROM("Parsing data for %d channels.\n", il->channel_count);
il->channel_info =
kcalloc(il->channel_count, sizeof(struct il_channel_info),
GFP_KERNEL); if (!il->channel_info) {
IL_ERR("Could not allocate channel_info\n");
il->channel_count = 0; return -ENOMEM;
}
ch_info = il->channel_info;
/* Loop through the 5 EEPROM bands adding them in order to the * channel map we maintain (that contains additional information than
* what just in the EEPROM) */ for (band = 1; band <= 5; band++) {
/* Loop through each band adding each of the channels */ for (ch = 0; ch < eeprom_ch_count; ch++) {
ch_info->channel = eeprom_ch_idx[ch];
ch_info->band =
(band ==
1) ? NL80211_BAND_2GHZ : NL80211_BAND_5GHZ;
/* permanently store EEPROM's channel regulatory flags
* and max power in channel info database. */
ch_info->eeprom = eeprom_ch_info[ch];
/* Copy the run-time flags so they are there even on
* invalid channels */
ch_info->flags = eeprom_ch_info[ch].flags; /* First write that ht40 is not enabled, and then enable
* one by one */
ch_info->ht40_extension_channel =
IEEE80211_CHAN_NO_HT40;
/* Check if we do have HT40 channels */ if (il->cfg->regulatory_bands[5] == EEPROM_REGULATORY_BAND_NO_HT40 &&
il->cfg->regulatory_bands[6] == EEPROM_REGULATORY_BAND_NO_HT40) return 0;
/* Two additional EEPROM bands for 2.4 and 5 GHz HT40 channels */ for (band = 6; band <= 7; band++) { enum nl80211_band ieeeband;
/* EEPROM band 6 is 2.4, band 7 is 5 GHz */
ieeeband =
(band == 6) ? NL80211_BAND_2GHZ : NL80211_BAND_5GHZ;
/* Loop through each band adding each of the channels */ for (ch = 0; ch < eeprom_ch_count; ch++) { /* Set up driver's info for lower half */
il_mod_ht40_chan_info(il, ieeeband, eeprom_ch_idx[ch],
&eeprom_ch_info[ch],
IEEE80211_CHAN_NO_HT40PLUS);
/* Set up driver's info for upper half */
il_mod_ht40_chan_info(il, ieeeband,
eeprom_ch_idx[ch] + 4,
&eeprom_ch_info[ch],
IEEE80211_CHAN_NO_HT40MINUS);
}
}
/* * Setting power level allows the card to go to sleep when not busy. * * We calculate a sleep command based on the required latency, which * we get from mac80211.
*/
/* Don't update the RX chain when chain noise calibration is running */
update_chains = il->chain_noise_data.state == IL_CHAIN_NOISE_DONE ||
il->chain_noise_data.state == IL_CHAIN_NOISE_ALIVE;
if (!memcmp(&il->power_data.sleep_cmd, cmd, sizeof(*cmd)) && !force) return 0;
if (!il_is_ready_rf(il)) return -EIO;
/* scan complete use sleep_power_next, need to be updated */
memcpy(&il->power_data.sleep_cmd_next, cmd, sizeof(*cmd)); if (test_bit(S_SCANNING, &il->status) && !force) {
D_INFO("Defer power set mode while scanning\n"); return 0;
}
if (cmd->flags & IL_POWER_DRIVER_ALLOW_SLEEP_MSK)
set_bit(S_POWER_PMI, &il->status);
ret = il_set_power(il, cmd); if (!ret) { if (!(cmd->flags & IL_POWER_DRIVER_ALLOW_SLEEP_MSK))
clear_bit(S_POWER_PMI, &il->status);
if (il->ops->update_chain_flags && update_chains)
il->ops->update_chain_flags(il); elseif (il->ops->update_chain_flags)
D_POWER("Cannot update the power, chain noise " "calibration running: %d\n",
il->chain_noise_data.state);
memcpy(&il->power_data.sleep_cmd, cmd, sizeof(*cmd));
} else
IL_ERR("set power fail, ret = %d", ret);
return ret;
}
int
il_power_update_mode(struct il_priv *il, bool force)
{ struct il_powertable_cmd cmd;
/* For active scan, listen ACTIVE_DWELL_TIME (msec) on each channel after * sending probe req. This should be set long enough to hear probe responses
* from more than one AP. */ #define IL_ACTIVE_DWELL_TIME_24 (30) /* all times in msec */ #define IL_ACTIVE_DWELL_TIME_52 (20)
/* For passive scan, listen PASSIVE_DWELL_TIME (msec) on each channel. * Must be set longer than active dwell time.
* For the most reliable scan, set > AP beacon interval (typically 100msec). */ #define IL_PASSIVE_DWELL_TIME_24 (20) /* all times in msec */ #define IL_PASSIVE_DWELL_TIME_52 (10) #define IL_PASSIVE_DWELL_BASE (100) #define IL_CHANNEL_TUNE_TIME 5
/* Exit instantly with error when device is not ready * to receive scan abort command or it does not perform
* hardware scan currently */ if (!test_bit(S_READY, &il->status) ||
!test_bit(S_GEO_CONFIGURED, &il->status) ||
!test_bit(S_SCAN_HW, &il->status) ||
test_bit(S_FW_ERROR, &il->status) ||
test_bit(S_EXIT_PENDING, &il->status)) return -EIO;
ret = il_send_cmd_sync(il, &cmd); if (ret) return ret;
pkt = (struct il_rx_pkt *)cmd.reply_page; if (pkt->u.status != CAN_ABORT_STATUS) { /* The scan abort will return 1 for success or * 2 for "failure". A failure condition can be * due to simply not being in an active scan which * can occur if we send the scan abort before we * the microcode has notified us that a scan is
* completed. */
D_SCAN("SCAN_ABORT ret %d.\n", pkt->u.status);
ret = -EIO;
}
/* check if scan was requested from mac80211 */ if (il->scan_request) {
D_SCAN("Complete scan in mac80211\n");
ieee80211_scan_completed(il->hw, &info);
}
staticvoid
il_do_scan_abort(struct il_priv *il)
{ int ret;
lockdep_assert_held(&il->mutex);
if (!test_bit(S_SCANNING, &il->status)) {
D_SCAN("Not performing scan to abort\n"); return;
}
if (test_and_set_bit(S_SCAN_ABORTING, &il->status)) {
D_SCAN("Scan abort in progress\n"); return;
}
ret = il_send_scan_abort(il); if (ret) {
D_SCAN("Send scan abort failed %d\n", ret);
il_force_scan_end(il);
} else
D_SCAN("Successfully send scan abort\n");
}
/* * il_scan_cancel - Cancel any currently executing HW scan
*/ int
il_scan_cancel(struct il_priv *il)
{
D_SCAN("Queuing abort scan\n");
queue_work(il->workqueue, &il->abort_scan); return 0;
}
EXPORT_SYMBOL(il_scan_cancel);
/* * il_scan_cancel_timeout - Cancel any currently executing HW scan * @ms: amount of time to wait (in milliseconds) for scan to abort *
*/ int
il_scan_cancel_timeout(struct il_priv *il, unsignedlong ms)
{ unsignedlong timeout = jiffies + msecs_to_jiffies(ms);
lockdep_assert_held(&il->mutex);
D_SCAN("Scan cancel timeout\n");
il_do_scan_abort(il);
while (time_before_eq(jiffies, timeout)) { if (!test_bit(S_SCAN_HW, &il->status)) break;
msleep(20);
}
if (il_is_any_associated(il)) { /* * If we're associated, we clamp the maximum passive * dwell time to be 98% of the smallest beacon interval * (minus 2 * channel tune time)
*/
value = il->vif ? il->vif->bss_conf.beacon_int : 0; if (value > IL_PASSIVE_DWELL_BASE || !value)
value = IL_PASSIVE_DWELL_BASE;
value = (value * 98) / 100 - IL_CHANNEL_TUNE_TIME * 2;
passive = min(value, passive);
}
/* Since we are here firmware does not finish scan and * most likely is in bad shape, so we don't bother to
* send abort command, just force scan complete to mac80211 */
mutex_lock(&il->mutex);
il_force_scan_end(il);
mutex_unlock(&il->mutex);
}
/* * il_fill_probe_req - fill in all required fields and IE for probe request
*/
u16
il_fill_probe_req(struct il_priv *il, struct ieee80211_mgmt *frame, const u8 *ta, const u8 *ies, int ie_len, int left)
{ int len = 0;
u8 *pos = NULL;
/* Make sure there is enough space for the probe request,
* two mandatory IEs and the data */
left -= 24; if (left < 0) return 0;
/* We keep scan_check work queued in case when firmware will not
* report back scan completed notification */
mutex_lock(&il->mutex);
il_scan_cancel_timeout(il, 200);
mutex_unlock(&il->mutex);
}
aborted = test_and_clear_bit(S_SCAN_ABORTING, &il->status); if (aborted)
D_SCAN("Aborted scan completed.\n");
if (!test_and_clear_bit(S_SCANNING, &il->status)) {
D_SCAN("Scan already completed.\n"); goto out_settings;
}
il_complete_scan(il, aborted);
out_settings: /* Can we still talk to firmware ? */ if (!il_is_ready_rf(il)) goto out;
/* * We do not commit power settings while scan is pending, * do it now if the settings changed.
*/
il_power_set_mode(il, &il->power_data.sleep_cmd_next, false);
il_set_tx_power(il, il->tx_power_next, false);
if (cancel_delayed_work_sync(&il->scan_check)) {
mutex_lock(&il->mutex);
il_force_scan_end(il);
mutex_unlock(&il->mutex);
}
}
EXPORT_SYMBOL(il_cancel_scan_deferred_work);
/* il->sta_lock must be held */ staticvoid
il_sta_ucode_activate(struct il_priv *il, u8 sta_id)
{
if (!(il->stations[sta_id].used & IL_STA_DRIVER_ACTIVE))
IL_ERR("ACTIVATE a non DRIVER active station id %u addr %pM\n",
sta_id, il->stations[sta_id].sta.sta.addr);
if (il->stations[sta_id].used & IL_STA_UCODE_ACTIVE) {
D_ASSOC("STA id %u addr %pM already present" " in uCode (according to driver)\n", sta_id,
il->stations[sta_id].sta.sta.addr);
} else {
il->stations[sta_id].used |= IL_STA_UCODE_ACTIVE;
D_ASSOC("Added STA id %u addr %pM to uCode\n", sta_id,
il->stations[sta_id].sta.sta.addr);
}
}
if (pkt->hdr.flags & IL_CMD_FAILED_MSK) {
IL_ERR("Bad return from C_ADD_STA (0x%08X)\n", pkt->hdr.flags); return ret;
}
D_INFO("Processing response for adding station %u\n", sta_id);
spin_lock_irqsave(&il->sta_lock, flags);
switch (pkt->u.add_sta.status) { case ADD_STA_SUCCESS_MSK:
D_INFO("C_ADD_STA PASSED\n");
il_sta_ucode_activate(il, sta_id);
ret = 0; break; case ADD_STA_NO_ROOM_IN_TBL:
IL_ERR("Adding station %d failed, no room in table.\n", sta_id); break; case ADD_STA_NO_BLOCK_ACK_RESOURCE:
IL_ERR("Adding station %d failed, no block ack resource.\n",
sta_id); break; case ADD_STA_MODIFY_NON_EXIST_STA:
IL_ERR("Attempting to modify non-existing station %d\n",
sta_id); break; default:
D_ASSOC("Received C_ADD_STA:(0x%08X)\n", pkt->u.add_sta.status); break;
}
D_INFO("%s station id %u addr %pM\n",
il->stations[sta_id].sta.mode ==
STA_CONTROL_MODIFY_MSK ? "Modified" : "Added", sta_id,
il->stations[sta_id].sta.sta.addr);
/* * XXX: The MAC address in the command buffer is often changed from * the original sent to the device. That is, the MAC address * written to the command buffer often is not the same MAC address * read from the command buffer when the command returns. This * issue has not yet been resolved and this debugging is left to * observe the problem.
*/
D_INFO("%s station according to cmd buffer %pM\n",
il->stations[sta_id].sta.mode ==
STA_CONTROL_MODIFY_MSK ? "Modified" : "Added", addsta->sta.addr);
spin_unlock_irqrestore(&il->sta_lock, flags);
/* * il_prep_station - Prepare station information for addition * * should be called with sta_lock held
*/
u8
il_prep_station(struct il_priv *il, const u8 *addr, bool is_ap, struct ieee80211_sta *sta)
{ struct il_station_entry *station; int i;
u8 sta_id = IL_INVALID_STATION;
u16 rate;
if (is_ap)
sta_id = IL_AP_ID; elseif (is_broadcast_ether_addr(addr))
sta_id = il->hw_params.bcast_id; else for (i = IL_STA_ID; i < il->hw_params.max_stations; i++) { if (ether_addr_equal(il->stations[i].sta.sta.addr,
addr)) {
sta_id = i; break;
}
if (!il->stations[i].used &&
sta_id == IL_INVALID_STATION)
sta_id = i;
}
/* * These two conditions have the same outcome, but keep them * separate
*/ if (unlikely(sta_id == IL_INVALID_STATION)) return sta_id;
/* * uCode is not able to deal with multiple requests to add a * station. Keep track if one is in progress so that we do not send * another.
*/ if (il->stations[sta_id].used & IL_STA_UCODE_INPROGRESS) {
D_INFO("STA %d already in process of being added.\n", sta_id); return sta_id;
}
station = &il->stations[sta_id];
station->used = IL_STA_DRIVER_ACTIVE;
D_ASSOC("Add STA to driver ID %d: %pM\n", sta_id, addr);
il->num_stations++;
/* Set up the C_ADD_STA command to send to device */
memset(&station->sta, 0, sizeof(struct il_addsta_cmd));
memcpy(station->sta.sta.addr, addr, ETH_ALEN);
station->sta.mode = 0;
station->sta.sta.sta_id = sta_id;
station->sta.station_flags = 0;
/* * OK to call unconditionally, since local stations (IBSS BSSID * STA and broadcast STA) pass in a NULL sta, and mac80211 * doesn't allow HT IBSS.
*/
il_set_ht_add_station(il, sta_id, sta);
/* 3945 only */
rate = (il->band == NL80211_BAND_5GHZ) ? RATE_6M_PLCP : RATE_1M_PLCP; /* Turn on both antennas for the station... */
station->sta.rate_n_flags = cpu_to_le16(rate | RATE_MCS_ANT_AB_MSK);
*sta_id_r = 0;
spin_lock_irqsave(&il->sta_lock, flags_spin);
sta_id = il_prep_station(il, addr, is_ap, sta); if (sta_id == IL_INVALID_STATION) {
IL_ERR("Unable to prepare station %pM for addition\n", addr);
spin_unlock_irqrestore(&il->sta_lock, flags_spin); return -EINVAL;
}
/* * uCode is not able to deal with multiple requests to add a * station. Keep track if one is in progress so that we do not send * another.
*/ if (il->stations[sta_id].used & IL_STA_UCODE_INPROGRESS) {
D_INFO("STA %d already in process of being added.\n", sta_id);
spin_unlock_irqrestore(&il->sta_lock, flags_spin); return -EEXIST;
}
/* Add station to device's station table */
ret = il_send_add_sta(il, &sta_cmd, CMD_SYNC); if (ret) {
spin_lock_irqsave(&il->sta_lock, flags_spin);
IL_ERR("Adding station %pM failed.\n",
il->stations[sta_id].sta.sta.addr);
il->stations[sta_id].used &= ~IL_STA_DRIVER_ACTIVE;
il->stations[sta_id].used &= ~IL_STA_UCODE_INPROGRESS;
spin_unlock_irqrestore(&il->sta_lock, flags_spin);
}
*sta_id_r = sta_id; return ret;
}
EXPORT_SYMBOL(il_add_station_common);
/* * il_sta_ucode_deactivate - deactivate ucode status for a station * * il->sta_lock must be held
*/ staticvoid
il_sta_ucode_deactivate(struct il_priv *il, u8 sta_id)
{ /* Ucode must be active and driver must be non active */ if ((il->stations[sta_id].
used & (IL_STA_UCODE_ACTIVE | IL_STA_DRIVER_ACTIVE)) !=
IL_STA_UCODE_ACTIVE)
IL_ERR("removed non active STA %u\n", sta_id);
if (!il_is_ready(il)) {
D_INFO("Unable to remove station %pM, device not ready.\n",
addr); /* * It is typical for stations to be removed when we are * going down. Return success since device will be down * soon anyway
*/ return 0;
}
D_ASSOC("Removing STA from driver:%d %pM\n", sta_id, addr);
if (WARN_ON(sta_id == IL_INVALID_STATION)) return -EINVAL;
spin_lock_irqsave(&il->sta_lock, flags);
if (!(il->stations[sta_id].used & IL_STA_DRIVER_ACTIVE)) {
D_INFO("Removing %pM but non DRIVER active\n", addr); goto out_err;
}
if (!(il->stations[sta_id].used & IL_STA_UCODE_ACTIVE)) {
D_INFO("Removing %pM but non UCODE active\n", addr); goto out_err;
}
if (il->stations[sta_id].used & IL_STA_LOCAL) {
kfree(il->stations[sta_id].lq);
il->stations[sta_id].lq = NULL;
}
/* * il_clear_ucode_stations - clear ucode station table bits * * This function clears all the bits in the driver indicating * which stations are active in the ucode. Call when something * other than explicit station management would cause this in * the ucode, e.g. unassociated RXON.
*/ void
il_clear_ucode_stations(struct il_priv *il)
{ int i; unsignedlong flags_spin; bool cleared = false;
D_INFO("Clearing ucode stations in driver\n");
spin_lock_irqsave(&il->sta_lock, flags_spin); for (i = 0; i < il->hw_params.max_stations; i++) { if (il->stations[i].used & IL_STA_UCODE_ACTIVE) {
D_INFO("Clearing ucode active for station %d\n", i);
il->stations[i].used &= ~IL_STA_UCODE_ACTIVE;
cleared = true;
}
}
spin_unlock_irqrestore(&il->sta_lock, flags_spin);
if (!cleared)
D_INFO("No active stations found to be cleared\n");
}
EXPORT_SYMBOL(il_clear_ucode_stations);
/* * il_restore_stations() - Restore driver known stations to device * * All stations considered active by driver, but not present in ucode, is * restored. * * Function sleeps.
*/ void
il_restore_stations(struct il_priv *il)
{ struct il_addsta_cmd sta_cmd; struct il_link_quality_cmd lq; unsignedlong flags_spin; int i; bool found = false; int ret; bool send_lq;
if (!il_is_ready(il)) {
D_INFO("Not ready yet, not restoring any stations.\n"); return;
}
D_ASSOC("Restoring all known stations ... start.\n");
spin_lock_irqsave(&il->sta_lock, flags_spin); for (i = 0; i < il->hw_params.max_stations; i++) { if ((il->stations[i].used & IL_STA_DRIVER_ACTIVE) &&
!(il->stations[i].used & IL_STA_UCODE_ACTIVE)) {
D_ASSOC("Restoring sta %pM\n",
il->stations[i].sta.sta.addr);
il->stations[i].sta.mode = 0;
il->stations[i].used |= IL_STA_UCODE_INPROGRESS;
found = true;
}
}
for (i = 0; i < il->hw_params.max_stations; i++) { if ((il->stations[i].used & IL_STA_UCODE_INPROGRESS)) {
memcpy(&sta_cmd, &il->stations[i].sta, sizeof(struct il_addsta_cmd));
send_lq = false; if (il->stations[i].lq) {
memcpy(&lq, il->stations[i].lq, sizeof(struct il_link_quality_cmd));
send_lq = true;
}
spin_unlock_irqrestore(&il->sta_lock, flags_spin);
ret = il_send_add_sta(il, &sta_cmd, CMD_SYNC); if (ret) {
spin_lock_irqsave(&il->sta_lock, flags_spin);
IL_ERR("Adding station %pM failed.\n",
il->stations[i].sta.sta.addr);
il->stations[i].used &= ~IL_STA_DRIVER_ACTIVE;
il->stations[i].used &=
~IL_STA_UCODE_INPROGRESS;
spin_unlock_irqrestore(&il->sta_lock,
flags_spin);
} /* * Rate scaling has already been initialized, send * current LQ command
*/ if (send_lq)
il_send_lq_cmd(il, &lq, CMD_SYNC, true);
spin_lock_irqsave(&il->sta_lock, flags_spin);
il->stations[i].used &= ~IL_STA_UCODE_INPROGRESS;
}
}
spin_unlock_irqrestore(&il->sta_lock, flags_spin); if (!found)
D_INFO("Restoring all known stations" " .... no stations to be restored.\n"); else
D_INFO("Restoring all known stations"" .... complete.\n");
}
EXPORT_SYMBOL(il_restore_stations);
int
il_get_free_ucode_key_idx(struct il_priv *il)
{ int i;
for (i = 0; i < il->sta_key_max_num; i++) if (!test_and_set_bit(i, &il->ucode_key_table)) return i;
#ifdef CONFIG_IWLEGACY_DEBUG staticvoid
il_dump_lq_cmd(struct il_priv *il, struct il_link_quality_cmd *lq)
{ int i;
D_RATE("lq station id 0x%x\n", lq->sta_id);
D_RATE("lq ant 0x%X 0x%X\n", lq->general_params.single_stream_ant_msk,
lq->general_params.dual_stream_ant_msk);
for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++)
D_RATE("lq idx %d 0x%X\n", i, lq->rs_table[i].rate_n_flags);
} #else staticinlinevoid
il_dump_lq_cmd(struct il_priv *il, struct il_link_quality_cmd *lq)
{
} #endif
/* * il_is_lq_table_valid() - Test one aspect of LQ cmd for validity * * It sometimes happens when a HT rate has been in use and we * loose connectivity with AP then mac80211 will first tell us that the * current channel is not HT anymore before removing the station. In such a * scenario the RXON flags will be updated to indicate we are not * communicating HT anymore, but the LQ command may still contain HT rates. * Test for this to prevent driver from sending LQ command between the time * RXON flags are updated and when LQ command is updated.
*/ staticbool
il_is_lq_table_valid(struct il_priv *il, struct il_link_quality_cmd *lq)
{ int i;
if (il->ht.enabled) returntrue;
D_INFO("Channel %u is not an HT channel\n", il->active.channel); for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) { if (le32_to_cpu(lq->rs_table[i].rate_n_flags) & RATE_MCS_HT_MSK) {
D_INFO("idx %d of LQ expects HT channel\n", i); returnfalse;
}
} returntrue;
}
/* * il_send_lq_cmd() - Send link quality command * @init: This command is sent as part of station initialization right * after station has been added. * * The link quality command is sent as the last step of station creation. * This is the special case in which init is set and we call a callback in * this case to clear the state indicating that station creation is in * progress.
*/ int
il_send_lq_cmd(struct il_priv *il, struct il_link_quality_cmd *lq,
u8 flags, bool init)
{ int ret = 0; unsignedlong flags_spin;
mutex_lock(&il->mutex);
D_MAC80211("enter station %pM\n", sta->addr);
ret = il_remove_station(il, sta_common->sta_id, sta->addr); if (ret)
IL_ERR("Error removing station %pM\n", sta->addr);
D_MAC80211("leave ret %d\n", ret);
mutex_unlock(&il->mutex);
return ret;
}
EXPORT_SYMBOL(il_mac_sta_remove);
/************************** RX-FUNCTIONS ****************************/ /* * Rx theory of operation * * Driver allocates a circular buffer of Receive Buffer Descriptors (RBDs), * each of which point to Receive Buffers to be filled by the NIC. These get * used not only for Rx frames, but for any command response or notification * from the NIC. The driver and NIC manage the Rx buffers by means * of idxes into the circular buffer. * * Rx Queue Indexes * The host/firmware share two idx registers for managing the Rx buffers. * * The READ idx maps to the first position that the firmware may be writing * to -- the driver can read up to (but not including) this position and get * good data. * The READ idx is managed by the firmware once the card is enabled. * * The WRITE idx maps to the last position the driver has read from -- the * position preceding WRITE is the last slot the firmware can place a packet. * * The queue is empty (no good data) if WRITE = READ - 1, and is full if * WRITE = READ. * * During initialization, the host sets up the READ queue position to the first * IDX position, and WRITE to the last (READ - 1 wrapped) * * When the firmware places a packet in a buffer, it will advance the READ idx * and fire the RX interrupt. The driver can then query the READ idx and * process as many packets as possible, moving the WRITE idx forward as it * resets the Rx queue buffers with new memory. * * The management in the driver is as follows: * + A list of pre-allocated SKBs is stored in iwl->rxq->rx_free. When * iwl->rxq->free_count drops to or below RX_LOW_WATERMARK, work is scheduled * to replenish the iwl->rxq->rx_free. * + In il_rx_replenish (scheduled) if 'processed' != 'read' then the * iwl->rxq is replenished and the READ IDX is updated (updating the * 'processed' and 'read' driver idxes as well)
--> --------------------
--> maximum size reached
--> --------------------
Messung V0.5
¤ Dauer der Verarbeitung: 0.22 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.