base = le32_to_cpu(il->card_alive.log_event_table_ptr); if (!il3945_hw_valid_rtc_data_addr(base)) {
IL_ERR("Invalid event log pointer 0x%08X\n", base); return;
}
disable_ptr = il_read_targ_mem(il, base + (4 * sizeof(u32)));
array_size = il_read_targ_mem(il, base + (5 * sizeof(u32)));
if (IL_EVT_DISABLE && array_size == IL_EVT_DISABLE_SIZE) {
D_INFO("Disabling selected uCode log events at 0x%x\n",
disable_ptr); for (i = 0; i < IL_EVT_DISABLE_SIZE; i++)
il_write_targ_mem(il, disable_ptr + (i * sizeof(u32)),
evt_disable[i]);
} else {
D_INFO("Selected uCode log events may be disabled\n");
D_INFO(" by writing \"1\"s into disable bitmap\n");
D_INFO(" in SRAM at 0x%x, size %d u32s\n", disable_ptr,
array_size);
}
}
staticint
il3945_hwrate_to_plcp_idx(u8 plcp)
{ int idx;
for (idx = 0; idx < RATE_COUNT_3945; idx++) if (il3945_rates[idx].plcp == plcp) return idx; return -1;
}
#ifdef CONFIG_IWLEGACY_DEBUG #define TX_STATUS_ENTRY(x) case TX_3945_STATUS_FAIL_ ## x: return#x
txq->time_stamp = jiffies;
info = IEEE80211_SKB_CB(txq->skbs[txq->q.read_ptr]);
ieee80211_tx_info_clear_status(info);
/* Fill the MRR chain with some info about on-chip retransmissions */
rate_idx = il3945_hwrate_to_plcp_idx(tx_resp->rate); if (info->band == NL80211_BAND_5GHZ)
rate_idx -= IL_FIRST_OFDM_RATE;
/* This is necessary only for a number of stats, see the caller. */ staticint
il3945_is_network_packet(struct il_priv *il, struct ieee80211_hdr *header)
{ /* Filter incoming packets to determine if they are targeted toward
* this network, discarding packets coming from ourselves */ switch (il->iw_mode) { case NL80211_IFTYPE_ADHOC: /* Header: Dest. | Source | BSSID */ /* packets to our IBSS update information */ return ether_addr_equal_64bits(header->addr3, il->bssid); case NL80211_IFTYPE_STATION: /* Header: Dest. | AP{BSSID} | Source */ /* packets to our IBSS update information */ return ether_addr_equal_64bits(header->addr2, il->bssid); default: return1;
}
}
/* We received data from the HW, so stop the watchdog */ if (unlikely(len + IL39_RX_FRAME_SIZE > fraglen)) {
D_DROP("Corruption detected!\n"); return;
}
/* We only process data packets if the interface is open */ if (unlikely(!il->is_open)) {
D_DROP("Dropping packet while interface is not open.\n"); return;
}
if (unlikely(test_bit(IL_STOP_REASON_PASSIVE, &il->stop_reason))) {
il_wake_queues_by_reason(il, IL_STOP_REASON_PASSIVE);
D_INFO("Woke queues - frame received on passive channel\n");
}
skb = dev_alloc_skb(SMALL_PACKET_SIZE); if (!skb) {
IL_ERR("dev_alloc_skb failed\n"); return;
}
if (!il3945_mod_params.sw_crypto)
il_set_decrypted_flag(il, (struct ieee80211_hdr *)pkt,
le32_to_cpu(rx_end->status), stats);
/* If frame is small enough to fit into skb->head, copy it *anddonotconsumeafullpage
*/ if (len <= SMALL_PACKET_SIZE) {
skb_put_data(skb, rx_hdr->payload, len);
} else {
skb_add_rx_frag(skb, 0, rxb->page,
(void *)rx_hdr->payload - (void *)pkt, len,
fraglen);
il->alloc_rxb_page--;
rxb->page = NULL;
}
il_update_stats(il, false, fc, len);
memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats));
/* We need to figure out how to get the sta->supp_rates while
* in this running context */
rate_mask = RATES_MASK_3945;
/* Set retry limit on DATA packets and Probe Responses */ if (ieee80211_is_probe_resp(fc))
data_retry_limit = 3; else
data_retry_limit = IL_DEFAULT_TX_RETRY;
tx_cmd->data_retry_limit = data_retry_limit; /* Set retry limit on RTS packets */
tx_cmd->rts_retry_limit = min(data_retry_limit, rts_retry_limit);
if (EEPROM_SKU_CAP_OP_MODE_MRC == eeprom->sku_cap) {
D_INFO("SKU OP mode is mrc\n");
il_set_bit(il, CSR_HW_IF_CONFIG_REG,
CSR39_HW_IF_CONFIG_REG_BIT_SKU_MRC);
} else
D_INFO("SKU OP mode is basic\n");
if ((eeprom->board_revision & 0xF0) == 0xD0) {
D_INFO("3945ABG revision is 0x%X\n", eeprom->board_revision);
il_set_bit(il, CSR_HW_IF_CONFIG_REG,
CSR39_HW_IF_CONFIG_REG_BIT_BOARD_TYPE);
} else {
D_INFO("3945ABG revision is 0x%X\n", eeprom->board_revision);
il_clear_bit(il, CSR_HW_IF_CONFIG_REG,
CSR39_HW_IF_CONFIG_REG_BIT_BOARD_TYPE);
}
if (eeprom->almgor_m_version <= 1) {
il_set_bit(il, CSR_HW_IF_CONFIG_REG,
CSR39_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_A);
D_INFO("Card M type A version is 0x%X\n",
eeprom->almgor_m_version);
} else {
D_INFO("Card M type B version is 0x%X\n",
eeprom->almgor_m_version);
il_set_bit(il, CSR_HW_IF_CONFIG_REG,
CSR39_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_B);
}
spin_unlock_irqrestore(&il->lock, flags);
if (eeprom->sku_cap & EEPROM_SKU_CAP_SW_RF_KILL_ENABLE)
D_RF_KILL("SW RF KILL supported in EEPROM.\n");
if (eeprom->sku_cap & EEPROM_SKU_CAP_HW_RF_KILL_ENABLE)
D_RF_KILL("HW RF KILL supported in EEPROM.\n");
}
int
il3945_hw_nic_init(struct il_priv *il)
{ int rc; unsignedlong flags; struct il_rx_queue *rxq = &il->rxq;
/* Allocate the RX queue, or reset if it is already allocated */ if (!rxq->bd) {
rc = il_rx_queue_alloc(il); if (rc) {
IL_ERR("Unable to initialize Rx queue\n"); return -ENOMEM;
}
} else
il3945_rx_queue_reset(il, rxq);
il3945_rx_replenish(il);
il3945_rx_init(il, rxq);
/* Look at using this instead: rxq->need_update=1; il_rx_queue_update_write_ptr(il,rxq);
*/
/* driver's okay range is -260 to +25.
* human readable okay range is 0 to +285 */
D_INFO("Temperature: %d\n", temperature + IL_TEMP_CONVERT);
/* handle insane temp reading */ if (il3945_hw_reg_temp_out_of_range(temperature)) {
IL_ERR("Error bad temperature value %d\n", temperature);
/* if really really hot(?),
* substitute the 3rd band/group's temp measured at factory */ if (il->last_temperature > 100)
temperature = eeprom->groups[2].temperature; else/* else use most recent "sane" value from driver */
temperature = il->last_temperature;
}
return temperature; /* raw, not "human readable" */
}
/* Adjust Txpower only if temperature variance is greater than threshold. *
* Both are lower than older versions' 9 degrees */ #define IL_TEMPERATURE_LIMIT_TIMER 6
/* *il3945_is_temp_calib_needed-determinesifnewcalibrationisneeded * *recordsnewtemperatureintx_mgr->temperature. *replacestx_mgr->last_temperature*only*ifcalibneeded
* (assumes caller will actually do the calibration!). */ staticint
il3945_is_temp_calib_needed(struct il_priv *il)
{ int temp_diff;
/* if we don't need calibration, *don't* update last_temperature */ if (temp_diff < IL_TEMPERATURE_LIMIT_TIMER) {
D_POWER("Timed thermal calib not needed\n"); return0;
}
D_POWER("Timed thermal calib needed\n");
/* assume that caller will actually do calib ...
* update the "last temperature" value */
il->last_temperature = il->temperature; return1;
}
/* use this channel group's 6Mbit clipping/saturation pwr, *butcapatregulatoryscanpowerrestriction(setduringinit
* based on eeprom channel data) for this channel. */
power = min(ch_info->scan_power, clip_pwrs[RATE_6M_IDX_TBL]);
power = min(power, il->tx_power_user_lmt);
scan_power_info->requested_power = power;
/* find difference between new scan *power* and current "normal" *Tx*power*for6Mb.Usethisdifference(x2)toadjustthe *current"normal"temperature-compensatedTxpower*idx*for *thisrate(1Mbor6Mb)toyieldnewtemp-compensatedscanpower
* *idx*. */
power_idx =
ch_info->power_info[rate_idx].power_table_idx - (power -
ch_info->
power_info
[RATE_6M_IDX_TBL].
requested_power) * 2;
/* store reference idx that we use when adjusting *all* scan *powers.Sowecanaccommodateuser(allchannel)orspectrum *management(singlechannel)powerchanges"between"temperature *feedbackcompensationprocedures. *don'tforcefitthisreferenceidxintogaintable;itmaybea *negativenumber.Thiswillhelpavoiderrorswhenwe'reat *thelowerbounds(highestgains,forwarmesttemperatures)
* of the table. */
if (WARN_ONCE
(test_bit(S_SCAN_HW, &il->status), "TX Power requested while scanning!\n")) return -EAGAIN;
chan = le16_to_cpu(il->active.channel);
txpower.band = (il->band == NL80211_BAND_5GHZ) ? 0 : 1;
ch_info = il_get_channel_info(il, il->band, chan); if (!ch_info) {
IL_ERR("Failed to get channel info for channel %d [%d]\n", chan,
il->band); return -EINVAL;
}
if (!il_is_channel_valid(ch_info)) {
D_POWER("Not calling TX_PWR_TBL_CMD on ""non-Tx channel.\n"); return0;
}
/* fill cmd with power settings for all rates for current channel */ /* Fill OFDM rate */ for (rate_idx = IL_FIRST_OFDM_RATE, i = 0;
rate_idx <= IL39_LAST_OFDM_RATE; rate_idx++, i++) {
/* Get this chnlgrp's rate-to-max/clip-powers table */
clip_pwrs = il->_3945.clip_groups[ch_info->group_idx].clip_powers;
/* Get this channel's rate-to-current-power settings table */
power_info = ch_info->power_info;
/* update OFDM Txpower settings */ for (i = RATE_6M_IDX_TBL; i <= RATE_54M_IDX_TBL; i++, ++power_info) { int delta_idx;
/* limit new power to be no more than h/w capability */
power = min(ch_info->curr_txpow, clip_pwrs[i]); if (power == power_info->requested_power) continue;
/* find difference between old and new requested powers,
* update base (non-temp-compensated) power idx */
delta_idx = (power - power_info->requested_power) * 2;
power_info->base_power_idx -= delta_idx;
/* save new requested power value */
power_info->requested_power = power;
power_changed = 1;
}
/* update CCK Txpower settings, based on OFDM 12M setting ...
* ... all CCK power settings for a given channel are the *same*. */ if (power_changed) {
power =
ch_info->power_info[RATE_12M_IDX_TBL].requested_power +
IL_CCK_FROM_OFDM_POWER_DIFF;
/* do all CCK rates' il3945_channel_power_info structures */ for (i = RATE_1M_IDX_TBL; i <= RATE_11M_IDX_TBL; i++) {
power_info->requested_power = power;
power_info->base_power_idx =
ch_info->power_info[RATE_12M_IDX_TBL].
base_power_idx + IL_CCK_FROM_OFDM_IDX_DIFF;
++power_info;
}
}
#if0 /* if we're using TGd limits, use lower of TGd or EEPROM */ if (ch_info->tgd_data.max_power != 0)
max_power =
min(ch_info->tgd_data.max_power,
ch_info->eeprom.max_power_avg);
/* else just use EEPROM limits */ else #endif
max_power = ch_info->eeprom.max_power_avg;
return min(max_power, ch_info->max_power_avg);
}
/* *il3945_hw_reg_comp_txpower_temp-Compensatefortemperature * *Compensatetxpowersettingsof*all*channelsfortemperature. *Thisonlyaccountsforthedifferencebetweencurrenttemperature *andthefactorycalibrationtemperatures,andbasesthenewsettings *onthechannel'sbase_power_idx. * *IfRxOnis"associated",thissendsthenewTxpowertoNIC!
*/ staticint
il3945_hw_reg_comp_txpower_temp(struct il_priv *il)
{ struct il_channel_info *ch_info = NULL; struct il3945_eeprom *eeprom = (struct il3945_eeprom *)il->eeprom; int delta_idx; const s8 *clip_pwrs; /* array of h/w max power levels for each rate */
u8 a_band;
u8 rate_idx;
u8 scan_tbl_idx;
u8 i; int ref_temp; int temperature = il->temperature;
if (il->disable_tx_power_cal || test_bit(S_SCANNING, &il->status)) { /* do not perform tx power calibration */ return0;
} /* set up new Tx power info for each and every channel, 2.4 and 5.x */ for (i = 0; i < il->channel_count; i++) {
ch_info = &il->channel_info[i];
a_band = il_is_channel_a_band(ch_info);
/* Get this chnlgrp's factory calibration temperature */
ref_temp = (s16) eeprom->groups[ch_info->group_idx].temperature;
/* get power idx adjustment based on current and factory
* temps */
delta_idx =
il3945_hw_reg_adjust_power_by_temp(temperature, ref_temp);
/* set tx power value for all rates, OFDM and CCK */ for (rate_idx = 0; rate_idx < RATE_COUNT_3945; rate_idx++) { int power_idx =
ch_info->power_info[rate_idx].base_power_idx;
/* temperature compensate */
power_idx += delta_idx;
/* stay within table range */
power_idx = il3945_hw_reg_fix_power_idx(power_idx);
ch_info->power_info[rate_idx].power_table_idx =
(u8) power_idx;
ch_info->power_info[rate_idx].tpc =
power_gain_table[a_band][power_idx];
}
/* Get this chnlgrp's rate-to-max/clip-powers table */
clip_pwrs =
il->_3945.clip_groups[ch_info->group_idx].clip_powers;
/* set scan tx power, 1Mbit for CCK, 6Mbit for OFDM */ for (scan_tbl_idx = 0; scan_tbl_idx < IL_NUM_SCAN_RATES;
scan_tbl_idx++) {
s32 actual_idx =
(scan_tbl_idx == 0) ? RATE_1M_IDX_TBL : RATE_6M_IDX_TBL;
il3945_hw_reg_set_scan_power(il, scan_tbl_idx,
actual_idx, clip_pwrs,
ch_info, a_band);
}
}
/* send Txpower command for current channel to ucode */ return il->ops->send_tx_power(il);
}
if (il->tx_power_user_lmt == power) {
D_POWER("Requested Tx power same as current ""limit: %ddBm.\n",
power); return0;
}
D_POWER("Setting upper limit clamp to %ddBm.\n", power);
il->tx_power_user_lmt = power;
/* set up new Tx powers for each and every channel, 2.4 and 5.x */
for (i = 0; i < il->channel_count; i++) {
ch_info = &il->channel_info[i];
/* find minimum power of all user and regulatory constraints
* (does not consider h/w clipping limitations) */
max_power = il3945_hw_reg_get_ch_txpower_limit(ch_info);
max_power = min(power, max_power); if (max_power != ch_info->curr_txpow) {
ch_info->curr_txpow = max_power;
/* this considers the h/w clipping limitations */
il3945_hw_reg_set_new_power(il, ch_info);
}
}
/* update txpower settings for all channels,
* send to NIC if associated. */
il3945_is_temp_calib_needed(il);
il3945_hw_reg_comp_txpower_temp(il);
rc = il_check_rxon_cmd(il); if (rc) {
IL_ERR("Invalid RXON configuration. Not committing.\n"); return -EINVAL;
}
/* If we don't need to send a full RXON, we can use *il3945_rxon_assoc_cmdwhichisusedtoreconfigurefilter
* and other flags for the current radio configuration. */ if (!il_full_rxon_required(il)) {
rc = il_send_rxon_assoc(il); if (rc) {
IL_ERR("Error setting RXON_ASSOC " "configuration (%d).\n", rc); return rc;
}
/* If we are currently associated and the new config requires *anRXON_ASSOCandthenewconfigwantstheassociatedmaskenabled, *wemustcleartheassociatedfromtheactiveconfiguration
* before we apply the new config */ if (il_is_associated(il) && new_assoc) {
D_INFO("Toggling associated bit on current RXON\n");
active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
/* If the mask clearing failed then we set
* active_rxon back to what it was previously */ if (rc) {
active_rxon->filter_flags |= RXON_FILTER_ASSOC_MSK;
IL_ERR("Error clearing ASSOC_MSK on current " "configuration (%d).\n", rc); return rc;
}
il_clear_ucode_stations(il);
il_restore_stations(il);
}
if (!new_assoc) {
il_clear_ucode_stations(il);
il_restore_stations(il);
}
/* 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 = il_set_tx_power(il, il->tx_power_next, true); if (rc) {
IL_ERR("Error setting Tx power (%d).\n", rc); return rc;
}
/* Init the hardware's rate fallback order based on the band */
rc = il3945_init_hw_rate_table(il); if (rc) {
IL_ERR("Error setting HW rate table: %02X\n", rc); return -EIO;
}
return0;
}
/* *il3945_reg_txpower_periodic-calledwhentimetocheckourtemperature. * *--resetperiodictimer *--seeiftemphaschangedenoughtowarrantre-calibration...ifso: *--correctcoeffsfortemp(canresettemptimer) *--savethistempas"last", *--sendnewsetofgainsettingstoNIC *NOTE:Thisshouldcontinueworking,evenwhenwe'renotassociated,
* so we can keep our internal table of scan powers current. */ void
il3945_reg_txpower_periodic(struct il_priv *il)
{ /* This will kick in the "brute force"
* il3945_hw_reg_comp_txpower_temp() below */ if (!il3945_is_temp_calib_needed(il)) goto reschedule;
/* Set up a new set of temp-adjusted TxPowers, send to NIC. *Thisisbased*only*oncurrenttemperature,
* ignoring any previous power measurements */
il3945_hw_reg_comp_txpower_temp(il);
/* Find the group idx for the channel ... don't use idx 1(?) */ if (il_is_channel_a_band(ch_info)) { for (group = 1; group < 5; group++) {
grp_channel = ch_grp[group].group_channel; if (ch_info->channel <= grp_channel) {
group_idx = group; break;
}
} /* group 4 has a few channels *above* its factory cal freq */ if (group == 5)
group_idx = 4;
} else
group_idx = 0; /* 2.4 GHz, group 0 */
D_POWER("Initializing factory calib info from EEPROM\n");
for (i = 0; i < IL_NUM_TX_CALIB_GROUPS; i++) {
s8 *clip_pwrs; /* table of power levels for each rate */
s8 satur_pwr; /* saturation power for each chnl group */
group = &eeprom->groups[i];
/* sanity check on factory saturation power value */ if (group->saturation_power < 40) {
IL_WARN("Error: saturation power is %d, " "less than minimum expected 40\n",
group->saturation_power); return;
}
/* *Deriverequestedpowerlevelsforeachrate,basedon *hardwarecapabilities(saturationpowerforband). *Basicvalueis3dBdownfromsaturation,withfurther *powerreductionsforhighest3datarates.These *backoffsprovideheadroomforhighratemodulation *powerpeaks,withouttoomuchdistortion(clipping).
*/ /* we'll fill in this array with h/w max power levels */
clip_pwrs = (s8 *) il->_3945.clip_groups[i].clip_powers;
/* divide factory saturation power by 2 to find -3dB level */
satur_pwr = (s8) (group->saturation_power >> 1);
/* fill in channel group's nominal powers for each rate */ for (rate_idx = 0; rate_idx < RATE_COUNT_3945;
rate_idx++, clip_pwrs++) { switch (rate_idx) { case RATE_36M_IDX_TBL: if (i == 0) /* B/G */
*clip_pwrs = satur_pwr; else/* A */
*clip_pwrs = satur_pwr - 5; break; case RATE_48M_IDX_TBL: if (i == 0)
*clip_pwrs = satur_pwr - 7; else
*clip_pwrs = satur_pwr - 10; break; case RATE_54M_IDX_TBL: if (i == 0)
*clip_pwrs = satur_pwr - 9; else
*clip_pwrs = satur_pwr - 12; break; default:
*clip_pwrs = satur_pwr; break;
}
}
}
}
/* *il3945_txpower_set_from_eeprom-SetchannelpowerinfobasedonEEPROM * *Secondpass(duringinit)tosetupil->channel_info * *SetupTx-powersettingsinourchannelinfodatabaseforeachVALID *(forthisgeo/SKU)channel,atallTxdatarates,basedoneepromvalues *andcurrenttemperature. * *Sincethisisbasedoncurrenttemperature(atinittime),thesevaluesmay *notbevalidforverylong,butitgivesusastarting/defaultpoint, *andallowsustoactive(i.e.usingTx)scan. * *Thisdoes*not*writevaluestoNIC,justsetsupourinternaltable.
*/ int
il3945_txpower_set_from_eeprom(struct il_priv *il)
{ struct il_channel_info *ch_info = NULL; struct il3945_channel_power_info *pwr_info; struct il3945_eeprom *eeprom = (struct il3945_eeprom *)il->eeprom; int delta_idx;
u8 rate_idx;
u8 scan_tbl_idx; const s8 *clip_pwrs; /* array of power levels for each rate */
u8 gain, dsp_atten;
s8 power;
u8 pwr_idx, base_pwr_idx, a_band;
u8 i; int temperature;
/* save temperature reference,
* so we can determine next time to calibrate */
temperature = il3945_hw_reg_txpower_get_temperature(il);
il->last_temperature = temperature;
il3945_hw_reg_init_channel_groups(il);
/* initialize Tx power info for each and every channel, 2.4 and 5.x */ for (i = 0, ch_info = il->channel_info; i < il->channel_count;
i++, ch_info++) {
a_band = il_is_channel_a_band(ch_info); if (!il_is_channel_valid(ch_info)) continue;
/* find this channel's channel group (*not* "band") idx */
ch_info->group_idx = il3945_hw_reg_get_ch_grp_idx(il, ch_info);
/* Get this chnlgrp's rate->max/clip-powers table */
clip_pwrs =
il->_3945.clip_groups[ch_info->group_idx].clip_powers;
/* calculate power idx *adjustment* value according to
* diff between current temperature and factory temperature */
delta_idx =
il3945_hw_reg_adjust_power_by_temp(temperature,
eeprom->groups[ch_info->
group_idx].
temperature);
D_POWER("Delta idx for channel %d: %d [%d]\n", ch_info->channel,
delta_idx, temperature + IL_TEMP_CONVERT);
/* set tx power value for all OFDM rates */ for (rate_idx = 0; rate_idx < IL_OFDM_RATES; rate_idx++) {
s32 power_idx; int rc;
/* use channel group's clip-power table,
* but don't exceed channel's max power */
s8 pwr = min(ch_info->max_power_avg,
clip_pwrs[rate_idx]);
pwr_info = &ch_info->power_info[rate_idx];
/* get base (i.e. at factory-measured temperature)
* power table idx for this rate's power */
rc = il3945_hw_reg_get_matched_power_idx(il, pwr,
ch_info->
group_idx,
&power_idx); if (rc) {
IL_ERR("Invalid power idx\n"); return rc;
}
pwr_info->base_power_idx = (u8) power_idx;
/* temperature compensate */
power_idx += delta_idx;
/* stay within range of gain table */
power_idx = il3945_hw_reg_fix_power_idx(power_idx);
/* set tx power for CCK rates, based on OFDM 12 Mbit settings */
pwr_info = &ch_info->power_info[RATE_12M_IDX_TBL];
power = pwr_info->requested_power + IL_CCK_FROM_OFDM_POWER_DIFF;
pwr_idx = pwr_info->power_table_idx + IL_CCK_FROM_OFDM_IDX_DIFF;
base_pwr_idx =
pwr_info->base_power_idx + IL_CCK_FROM_OFDM_IDX_DIFF;
/* stay within table range */
pwr_idx = il3945_hw_reg_fix_power_idx(pwr_idx);
gain = power_gain_table[a_band][pwr_idx].tx_gain;
dsp_atten = power_gain_table[a_band][pwr_idx].dsp_atten;
/* fill each CCK rate's il3945_channel_power_info structure *NOTE:AllCCK-rateTxpwrsarethesameforagivenchnl!
* NOTE: CCK rates start at end of OFDM rates! */ for (rate_idx = 0; rate_idx < IL_CCK_RATES; rate_idx++) {
pwr_info =
&ch_info->power_info[rate_idx + IL_OFDM_RATES];
pwr_info->requested_power = power;
pwr_info->power_table_idx = pwr_idx;
pwr_info->base_power_idx = base_pwr_idx;
pwr_info->tpc.tx_gain = gain;
pwr_info->tpc.dsp_atten = dsp_atten;
}
/* set scan tx power, 1Mbit for CCK, 6Mbit for OFDM */ for (scan_tbl_idx = 0; scan_tbl_idx < IL_NUM_SCAN_RATES;
scan_tbl_idx++) {
s32 actual_idx =
(scan_tbl_idx == 0) ? RATE_1M_IDX_TBL : RATE_6M_IDX_TBL;
il3945_hw_reg_set_scan_power(il, scan_tbl_idx,
actual_idx, clip_pwrs,
ch_info, a_band);
}
}
return0;
}
int
il3945_hw_rxq_stop(struct il_priv *il)
{ int ret;
_il_wr(il, FH39_RCSR_CONFIG(0), 0);
ret = _il_poll_bit(il, FH39_RSSR_STATUS,
FH39_RSSR_CHNL0_RX_STATUS_CHNL_IDLE,
FH39_RSSR_CHNL0_RX_STATUS_CHNL_IDLE, 1000); if (ret < 0)
IL_ERR("Can't stop Rx DMA.\n");
return0;
}
int
il3945_hw_tx_queue_init(struct il_priv *il, struct il_tx_queue *txq)
{ int txq_id = txq->q.id;
switch (il->band) { case NL80211_BAND_5GHZ:
D_RATE("Select A mode rate scale\n"); /* If one of the following CCK rates is used,
* have it fall back to the 6M OFDM rate */ for (i = RATE_1M_IDX_TBL; i <= RATE_11M_IDX_TBL; i++)
table[i].next_rate_idx =
il3945_rates[IL_FIRST_OFDM_RATE].table_rs_idx;
/* Don't fall back to CCK rates */
table[RATE_12M_IDX_TBL].next_rate_idx = RATE_9M_IDX_TBL;
/* Don't drop out of OFDM rates */
table[RATE_6M_IDX_TBL].next_rate_idx =
il3945_rates[IL_FIRST_OFDM_RATE].table_rs_idx; break;
case NL80211_BAND_2GHZ:
D_RATE("Select B/G mode rate scale\n"); /* If an OFDM rate is used, have it fall back to the
* 1M CCK rates */
if (!(il->_3945.sta_supp_rates & IL_OFDM_RATES_MASK) &&
il_is_associated(il)) {
idx = IL_FIRST_CCK_RATE; for (i = RATE_6M_IDX_TBL; i <= RATE_54M_IDX_TBL; i++)
table[i].next_rate_idx =
il3945_rates[idx].table_rs_idx;
idx = RATE_11M_IDX_TBL; /* CCK shouldn't fall back to OFDM... */
table[idx].next_rate_idx = RATE_5M_IDX_TBL;
} break;
default:
WARN_ON(1); break;
}
/* Update the rate scaling for control frame Tx */
rate_cmd.table_id = 0;
rc = il_send_cmd_pdu(il, C_RATE_SCALE, sizeof(rate_cmd), &rate_cmd); if (rc) return rc;
/* Update the rate scaling for data frame Tx */
rate_cmd.table_id = 1; return il_send_cmd_pdu(il, C_RATE_SCALE, sizeof(rate_cmd), &rate_cmd);
}
/* Called when initializing driver */ int
il3945_hw_set_hw_params(struct il_priv *il)
{
memset((void *)&il->hw_params, 0, sizeof(struct il_hw_params));
/* Fill BSM memory with bootstrap instructions */ for (reg_offset = BSM_SRAM_LOWER_BOUND;
reg_offset < BSM_SRAM_LOWER_BOUND + len;
reg_offset += sizeof(u32), image++)
_il_wr_prph(il, reg_offset, le32_to_cpu(*image));
rc = il3945_verify_bsm(il); if (rc) return rc;
/* Tell BSM to copy from BSM SRAM into instruction SRAM, when asked */
il_wr_prph(il, BSM_WR_MEM_SRC_REG, 0x0);
il_wr_prph(il, BSM_WR_MEM_DST_REG, IL39_RTC_INST_LOWER_BOUND);
il_wr_prph(il, BSM_WR_DWCOUNT_REG, len / sizeof(u32));
/* Load bootstrap code into instruction SRAM now,
* to prepare to load "initialize" uCode */
il_wr_prph(il, BSM_WR_CTRL_REG, BSM_WR_CTRL_REG_BIT_START);
/* Wait for load of bootstrap uCode to finish */ for (i = 0; i < 100; i++) {
done = il_rd_prph(il, BSM_WR_CTRL_REG); if (!(done & BSM_WR_CTRL_REG_BIT_START)) break;
udelay(10);
} if (i < 100)
D_INFO("BSM write complete, poll %d iterations\n", i); else {
IL_ERR("BSM write did not complete!\n"); return -EIO;
}
/* Enable future boot loads whenever power management unit triggers it
* (e.g. when powering back up after power-save shutdown) */
il_wr_prph(il, BSM_WR_CTRL_REG, BSM_WR_CTRL_REG_BIT_START_EN);
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.