📄 iwl-3945.c
字号:
struct iwl_eeprom_txpower_group *ch_grp = &priv->eeprom.groups[0]; u8 group; u16 group_index = 0; /* based on factory calib frequencies */ u8 grp_channel; /* Find the group index for the channel ... don't use index 1(?) */ if (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_index = group; break; } } /* group 4 has a few channels *above* its factory cal freq */ if (group == 5) group_index = 4; } else group_index = 0; /* 2.4 GHz, group 0 */ IWL_DEBUG_POWER("Chnl %d mapped to grp %d\n", ch_info->channel, group_index); return group_index;}/** * iwl_hw_reg_get_matched_power_index - Interpolate to get nominal index * * Interpolate to get nominal (i.e. at factory calibration temperature) index * into radio/DSP gain settings table for requested power. */static int iwl_hw_reg_get_matched_power_index(struct iwl_priv *priv, s8 requested_power, s32 setting_index, s32 *new_index){ const struct iwl_eeprom_txpower_group *chnl_grp = NULL; s32 index0, index1; s32 power = 2 * requested_power; s32 i; const struct iwl_eeprom_txpower_sample *samples; s32 gains0, gains1; s32 res; s32 denominator; chnl_grp = &priv->eeprom.groups[setting_index]; samples = chnl_grp->samples; for (i = 0; i < 5; i++) { if (power == samples[i].power) { *new_index = samples[i].gain_index; return 0; } } if (power > samples[1].power) { index0 = 0; index1 = 1; } else if (power > samples[2].power) { index0 = 1; index1 = 2; } else if (power > samples[3].power) { index0 = 2; index1 = 3; } else { index0 = 3; index1 = 4; } denominator = (s32) samples[index1].power - (s32) samples[index0].power; if (denominator == 0) return -EINVAL; gains0 = (s32) samples[index0].gain_index * (1 << 19); gains1 = (s32) samples[index1].gain_index * (1 << 19); res = gains0 + (gains1 - gains0) * ((s32) power - (s32) samples[index0].power) / denominator + (1 << 18); *new_index = res >> 19; return 0;}static void iwl_hw_reg_init_channel_groups(struct iwl_priv *priv){ u32 i; s32 rate_index; const struct iwl_eeprom_txpower_group *group; IWL_DEBUG_POWER("Initializing factory calib info from EEPROM\n"); for (i = 0; i < IWL_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 = &priv->eeprom.groups[i]; /* sanity check on factory saturation power value */ if (group->saturation_power < 40) { IWL_WARNING("Error: saturation power is %d, " "less than minimum expected 40\n", group->saturation_power); return; } /* * Derive requested power levels for each rate, based on * hardware capabilities (saturation power for band). * Basic value is 3dB down from saturation, with further * power reductions for highest 3 data rates. These * backoffs provide headroom for high rate modulation * power peaks, without too much distortion (clipping). */ /* we'll fill in this array with h/w max power levels */ clip_pwrs = (s8 *) priv->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_index = 0; rate_index < IWL_RATE_COUNT; rate_index++, clip_pwrs++) { switch (rate_index) { case IWL_RATE_36M_INDEX_TABLE: if (i == 0) /* B/G */ *clip_pwrs = satur_pwr; else /* A */ *clip_pwrs = satur_pwr - 5; break; case IWL_RATE_48M_INDEX_TABLE: if (i == 0) *clip_pwrs = satur_pwr - 7; else *clip_pwrs = satur_pwr - 10; break; case IWL_RATE_54M_INDEX_TABLE: if (i == 0) *clip_pwrs = satur_pwr - 9; else *clip_pwrs = satur_pwr - 12; break; default: *clip_pwrs = satur_pwr; break; } } }}/** * iwl3945_txpower_set_from_eeprom - Set channel power info based on EEPROM * * Second pass (during init) to set up priv->channel_info * * Set up Tx-power settings in our channel info database for each VALID * (for this geo/SKU) channel, at all Tx data rates, based on eeprom values * and current temperature. * * Since this is based on current temperature (at init time), these values may * not be valid for very long, but it gives us a starting/default point, * and allows us to active (i.e. using Tx) scan. * * This does *not* write values to NIC, just sets up our internal table. */int iwl3945_txpower_set_from_eeprom(struct iwl_priv *priv){ struct iwl_channel_info *ch_info = NULL; struct iwl_channel_power_info *pwr_info; int delta_index; u8 rate_index; u8 scan_tbl_index; const s8 *clip_pwrs; /* array of power levels for each rate */ u8 gain, dsp_atten; s8 power; u8 pwr_index, base_pwr_index, a_band; u8 i; int temperature; /* save temperature reference, * so we can determine next time to calibrate */ temperature = iwl_hw_reg_txpower_get_temperature(priv); priv->last_temperature = temperature; iwl_hw_reg_init_channel_groups(priv); /* initialize Tx power info for each and every channel, 2.4 and 5.x */ for (i = 0, ch_info = priv->channel_info; i < priv->channel_count; i++, ch_info++) { a_band = is_channel_a_band(ch_info); if (!is_channel_valid(ch_info)) continue; /* find this channel's channel group (*not* "band") index */ ch_info->group_index = iwl_hw_reg_get_ch_grp_index(priv, ch_info); /* Get this chnlgrp's rate->max/clip-powers table */ clip_pwrs = priv->clip_groups[ch_info->group_index].clip_powers; /* calculate power index *adjustment* value according to * diff between current temperature and factory temperature */ delta_index = iwl_hw_reg_adjust_power_by_temp(temperature, priv->eeprom.groups[ch_info->group_index]. temperature); IWL_DEBUG_POWER("Delta index for channel %d: %d [%d]\n", ch_info->channel, delta_index, temperature + IWL_TEMP_CONVERT); /* set tx power value for all OFDM rates */ for (rate_index = 0; rate_index < IWL_OFDM_RATES; rate_index++) { 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_index]); pwr_info = &ch_info->power_info[rate_index]; /* get base (i.e. at factory-measured temperature) * power table index for this rate's power */ rc = iwl_hw_reg_get_matched_power_index(priv, pwr, ch_info->group_index, &power_idx); if (rc) { IWL_ERROR("Invalid power index\n"); return rc; } pwr_info->base_power_index = (u8) power_idx; /* temperature compensate */ power_idx += delta_index; /* stay within range of gain table */ power_idx = iwl_hw_reg_fix_power_index(power_idx); /* fill 1 OFDM rate's iwl_channel_power_info struct */ pwr_info->requested_power = pwr; pwr_info->power_table_index = (u8) power_idx; pwr_info->tpc.tx_gain = power_gain_table[a_band][power_idx].tx_gain; pwr_info->tpc.dsp_atten = power_gain_table[a_band][power_idx].dsp_atten; } /* set tx power for CCK rates, based on OFDM 12 Mbit settings*/ pwr_info = &ch_info->power_info[IWL_RATE_12M_INDEX_TABLE]; power = pwr_info->requested_power + IWL_CCK_FROM_OFDM_POWER_DIFF; pwr_index = pwr_info->power_table_index + IWL_CCK_FROM_OFDM_INDEX_DIFF; base_pwr_index = pwr_info->base_power_index + IWL_CCK_FROM_OFDM_INDEX_DIFF; /* stay within table range */ pwr_index = iwl_hw_reg_fix_power_index(pwr_index); gain = power_gain_table[a_band][pwr_index].tx_gain; dsp_atten = power_gain_table[a_band][pwr_index].dsp_atten; /* fill each CCK rate's iwl_channel_power_info structure * NOTE: All CCK-rate Txpwrs are the same for a given chnl! * NOTE: CCK rates start at end of OFDM rates! */ for (rate_index = 0; rate_index < IWL_CCK_RATES; rate_index++) { pwr_info = &ch_info->power_info[rate_index+IWL_OFDM_RATES]; pwr_info->requested_power = power; pwr_info->power_table_index = pwr_index; pwr_info->base_power_index = base_pwr_index; 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_index = 0; scan_tbl_index < IWL_NUM_SCAN_RATES; scan_tbl_index++) { s32 actual_index = (scan_tbl_index == 0) ? IWL_RATE_1M_INDEX_TABLE : IWL_RATE_6M_INDEX_TABLE; iwl_hw_reg_set_scan_power(priv, scan_tbl_index, actual_index, clip_pwrs, ch_info, a_band); } } return 0;}int iwl_hw_rxq_stop(struct iwl_priv *priv){ int rc; unsigned long flags; spin_lock_irqsave(&priv->lock, flags); rc = iwl_grab_restricted_access(priv); if (rc) { spin_unlock_irqrestore(&priv->lock, flags); return rc; } iwl_write_restricted(priv, FH_RCSR_CONFIG(0), 0); rc = iwl_poll_restricted_bit(priv, FH_RSSR_STATUS, (1 << 24), 1000); if (rc < 0) IWL_ERROR("Can't stop Rx DMA.\n"); iwl_release_restricted_access(priv); spin_unlock_irqrestore(&priv->lock, flags); return 0;}int iwl_hw_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq){ int rc; unsigned long flags; int txq_id = txq->q.id; struct iwl_shared *shared_data = priv->hw_setting.shared_virt; shared_data->tx_base_ptr[txq_id] = cpu_to_le32((u32)txq->q.dma_addr); spin_lock_irqsave(&priv->lock, flags); rc = iwl_grab_restricted_access(priv); if (rc) { spin_unlock_irqrestore(&priv->lock, flags); return rc; } iwl_write_restricted(priv, FH_CBCC_CTRL(txq_id), 0); iwl_write_restricted(priv, FH_CBCC_BASE(txq_id), 0); iwl_write_restricted(priv, FH_TCSR_CONFIG(txq_id), ALM_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_NOINT | ALM_FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_TXF | ALM_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_IFTFD | ALM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL | ALM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE); iwl_release_restricted_access(priv); /* fake read to flush all prev. writes */ iwl_read32(priv, FH_TSSR_CBB_BASE); spin_unlock_irqrestore(&priv->lock, flags); return 0;}int iwl_hw_get_rx_read(struct iwl_priv *priv){ struct iwl_shared *shared_data = priv->hw_setting.shared_virt; return le32_to_cpu(shared_data->rx_read_ptr[0]);}/** * iwl3945_init_hw_rate_table - Initialize the hardware rate fallback table */int iwl3945_init_hw_rate_table(struct iwl_priv *priv){ int rc, i, index, prev_index; struct iwl_rate_scaling_cmd rate_cmd = { .reserved = {0, 0, 0}, }; struct iwl_rate_scaling_info *table = rate_cmd.table; for (i = 0; i < ARRAY_SIZE(iwl_rates); i++) { index = iwl_rates[i].table_rs_index; table[index].rate_n_flags = iwl_hw_set_rate_n_flags(iwl_rates[i].plcp, 0); table[index].try_cnt = priv->retry_rate; prev_index = iwl_get_prev_ieee_rate(i); table[index].next_rate_index = iwl_rates[prev_index].table_rs_index; } switch (priv->phymode) { case MODE_IEEE80211A: IWL_DEBUG_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 = IWL_RATE_1M_INDEX_TABLE; i <= IWL_RATE_11M_INDEX_TABLE; i++) table[i].next_rate_index = iwl_rates[IWL_FIRST_OFDM_RATE].table_rs_index; /* Don't fall back to CCK rates */ table[IWL_RATE_12M_INDEX_TABLE].next_rate_index = IWL_RATE_9M_INDEX_TABLE; /* Don't drop out of OFDM rates */ table[IWL_RATE_6M_INDEX_TABLE].next_rate_index = iwl_rates[IWL_FIRST_OFDM_RATE].table_rs_index; break; case MODE_IEEE80211B: IWL_DEBUG_RATE("Select B mode rate scale\n"); /* If an OFDM rate is used, have it fall back to the * 1M CCK rates */ for (i = IWL_RATE_6M_INDEX_TABLE; i <= IWL_RATE_54M_INDEX_TABLE; i++) table[i].next_rate_index = iwl_rates[IWL_FIRST_CCK_RATE].table_rs_index; /* CCK shouldn't fall back to OFDM... */ table[IWL_RATE_11M_INDEX_TABLE].next_rate_index = IWL_RATE_5M_INDEX_TABLE; break; default: IWL_DEBUG_RATE("Select G mode rate scale\n"); break; } /* Update the rate scaling for control frame Tx */ rate_cmd.table_id = 0; rc = iwl_send_cmd_pdu(priv, REPLY_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 iwl_send_cmd_pdu(priv, REPLY_RATE_SCALE, sizeof(rate_cmd), &rate_cmd);}int iwl_hw_set_hw_setting(struct iwl_priv *priv){ memset((void *)&priv->hw_setting, 0, sizeof(struct iwl_driver_hw_info)); priv->hw_setting.shared_virt = pci_alloc_consistent(priv->pci_dev, sizeof(struct iwl_shared), &priv->hw_setting.shared_phys); if (!priv->hw_setting.shared_virt) { IWL_ERROR("failed to allocate pci memory\n"); mutex_unlock(&priv->mutex); return -ENOMEM; } priv->hw_setting.ac_queue_count = AC_NUM; priv->hw_setting.rx_buffer_size = IWL_RX_BUF_SIZE; priv->hw_setting.tx_cmd_len = sizeof(struct iwl_tx_cmd); priv->hw_setting.max_rxq_size = RX_QUEUE_SIZE; priv->hw_setting.max_rxq_log = RX_QUEUE_SIZE_LOG; priv->hw_setting.cck_flag = 0; priv->hw_setting.max_stations = IWL3945_STATION_COUNT; priv->hw_setting.bcast_sta_id = IWL3945_BROADCAST_ID; return 0;}unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv, struct iwl_frame *frame, u8 rate){ struct iwl_tx_beacon_cmd *tx_beacon_cmd; unsigned int frame_size; tx_beacon_cmd = (struct iwl_tx_beacon_cmd *)&frame->u; memset(tx_beacon_cmd, 0, sizeof(*tx_beacon_cmd)); tx_beacon_cmd->tx.sta_id = IWL394
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -