/* * EEPROM bands * These are the channel numbers from each band in the order * that they are stored in the EEPROM band information. Note * that EEPROM bands aren't the same as mac80211 bands, and * there are even special "ht40 bands" in the EEPROM.
*/ staticconst u8 iwl_eeprom_band_1[14] = { /* 2.4 GHz */
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14
};
/** * enum iwl_eeprom_channel_flags - channel flags in EEPROM * @EEPROM_CHANNEL_VALID: channel is usable for this SKU/geo * @EEPROM_CHANNEL_IBSS: usable as an IBSS channel * @EEPROM_CHANNEL_ACTIVE: active scanning allowed * @EEPROM_CHANNEL_RADAR: radar detection required * @EEPROM_CHANNEL_WIDE: 20 MHz channel okay (?) * @EEPROM_CHANNEL_DFS: dynamic freq selection candidate
*/ enum iwl_eeprom_channel_flags {
EEPROM_CHANNEL_VALID = BIT(0),
EEPROM_CHANNEL_IBSS = BIT(1),
EEPROM_CHANNEL_ACTIVE = BIT(3),
EEPROM_CHANNEL_RADAR = BIT(4),
EEPROM_CHANNEL_WIDE = BIT(5),
EEPROM_CHANNEL_DFS = BIT(7),
};
/** * struct iwl_eeprom_channel - EEPROM channel data * @flags: %EEPROM_CHANNEL_* flags * @max_power_avg: max power (in dBm) on this channel, at most 31 dBm
*/ struct iwl_eeprom_channel {
u8 flags;
s8 max_power_avg;
} __packed;
/** * struct iwl_eeprom_enhanced_txpwr - enhanced regulatory TX power limits * @flags: entry flags * @channel: channel number * @chain_a_max: chain a max power in 1/2 dBm * @chain_b_max: chain b max power in 1/2 dBm * @chain_c_max: chain c max power in 1/2 dBm * @delta_20_in_40: 20-in-40 deltas (hi/lo) * @mimo2_max: mimo2 max power in 1/2 dBm * @mimo3_max: mimo3 max power in 1/2 dBm * * This structure presents the enhanced regulatory tx power limit layout * in an EEPROM image.
*/ struct iwl_eeprom_enhanced_txpwr {
u8 flags;
u8 channel;
s8 chain_a_max;
s8 chain_b_max;
s8 chain_c_max;
u8 delta_20_in_40;
s8 mimo2_max;
s8 mimo3_max;
} __packed;
/* the length is in 16-bit words, but we want entries */
txp_len = iwl_eeprom_query_addr(eeprom, eeprom_size, EEPROM_TXP_SZ_OFFS);
entries = le16_to_cpup(txp_len) * 2 / EEPROM_TXP_ENTRY_LEN;
for (i = 0; i < n_channels; i++) { if (data->channels[i].band != band) continue; if (data->channels[i].hw_value != channel) continue;
chan = &data->channels[i]; break;
}
/* Loop through each band adding each of the channels */ for (ch_idx = 0; ch_idx < eeprom_ch_count; ch_idx++) { conststruct iwl_eeprom_channel *eeprom_ch;
if (cfg->eeprom_params->enhanced_txpower) { /* * for newer device (6000 series and up) * EEPROM contain enhanced tx power information * driver need to process addition information * to determine the max channel tx power limits
*/
iwl_eeprom_enhanced_txpower(dev, data, eeprom, eeprom_size,
n_channels);
} else { /* All others use data from channel map */ int i;
data->max_tx_pwr_half_dbm = -128;
for (i = 0; i < n_channels; i++)
data->max_tx_pwr_half_dbm =
max_t(s8, data->max_tx_pwr_half_dbm,
data->channels[i].max_power * 2);
}
/* Check if we do have HT40 channels */ if (cfg->eeprom_params->regulatory_bands[5] ==
EEPROM_REGULATORY_BAND_NO_HT40 &&
cfg->eeprom_params->regulatory_bands[6] ==
EEPROM_REGULATORY_BAND_NO_HT40) return n_channels;
/* 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_idx = 0; ch_idx < eeprom_ch_count; ch_idx++) { /* Set up driver's info for lower half */
iwl_mod_ht40_chan_info(dev, data, n_channels, ieeeband,
eeprom_ch_array[ch_idx],
&eeprom_ch_info[ch_idx],
IEEE80211_CHAN_NO_HT40PLUS);
/* Set up driver's info for upper half */
iwl_mod_ht40_chan_info(dev, data, n_channels, ieeeband,
eeprom_ch_array[ch_idx] + 4,
&eeprom_ch_info[ch_idx],
IEEE80211_CHAN_NO_HT40MINUS);
}
}
return n_channels;
} /* * EEPROM access time values: * * Driver initiates EEPROM read by writing byte address << 1 to CSR_EEPROM_REG. * Driver then polls CSR_EEPROM_REG for CSR_EEPROM_REG_READ_VALID_MSK (0x1). * When polling, wait 10 uSec between polling loops, up to a maximum 5000 uSec. * Driver reads 16-bit value from bits 31-16 of CSR_EEPROM_REG.
*/ #define IWL_EEPROM_ACCESS_TIMEOUT 5000 /* uSec */
/* * The device's EEPROM semaphore prevents conflicts between driver and uCode * when accessing the EEPROM; each access is a series of pulses to/from the * EEPROM chip, not a single event, so even reads could conflict if they * weren't arbitrated by the semaphore.
*/ #define IWL_EEPROM_SEM_TIMEOUT 10 /* microseconds */ #define IWL_EEPROM_SEM_RETRY_LIMIT 1000 /* number of attempts (not time) */
staticint iwl_eeprom_acquire_semaphore(struct iwl_trans *trans)
{
u16 count; int ret;
/* See if we got it */
ret = iwl_poll_bits(trans, CSR_HW_IF_CONFIG_REG,
CSR_HW_IF_CONFIG_REG_EEPROM_OWN_SEM,
IWL_EEPROM_SEM_TIMEOUT); if (!ret) {
IWL_DEBUG_EEPROM(trans->dev, "Acquired semaphore after %d tries.\n",
count+1); return 0;
}
}
/* OTP only valid for CP/PP and after */ switch (trans->info.hw_rev & CSR_HW_REV_TYPE_MSK) { case CSR_HW_REV_TYPE_NONE:
IWL_ERR(trans, "Unknown hardware type\n"); return -EIO; case CSR_HW_REV_TYPE_5300: case CSR_HW_REV_TYPE_5350: case CSR_HW_REV_TYPE_5100: case CSR_HW_REV_TYPE_5150: return 0; default:
otpgp = iwl_read32(trans, CSR_OTP_GP_REG); if (otpgp & CSR_OTP_GP_REG_DEVICE_SELECT) return 1; return 0;
}
}
staticint iwl_init_otp_access(struct iwl_trans *trans)
{ int ret;
ret = iwl_finish_nic_init(trans); if (ret) return ret;
/* * CSR auto clock gate disable bit - * this is only applicable for HW with OTP shadow RAM
*/ if (trans->mac_cfg->base->shadow_ram_support)
iwl_set_bit(trans, CSR_DBG_LINK_PWR_MGMT_REG,
CSR_RESET_LINK_PWR_MGMT_DISABLED);
return 0;
}
staticint iwl_read_otp_word(struct iwl_trans *trans, u16 addr,
__le16 *eeprom_data)
{ int ret = 0;
u32 r;
u32 otpgp;
iwl_write32(trans, CSR_EEPROM_REG,
CSR_EEPROM_REG_MSK_ADDR & (addr << 1));
ret = iwl_poll_bits(trans, CSR_EEPROM_REG,
CSR_EEPROM_REG_READ_VALID_MSK,
IWL_EEPROM_ACCESS_TIMEOUT); if (ret) {
IWL_ERR(trans, "Time out reading OTP[%d]\n", addr); return ret;
}
r = iwl_read32(trans, CSR_EEPROM_REG); /* check for ECC errors: */
otpgp = iwl_read32(trans, CSR_OTP_GP_REG); if (otpgp & CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK) { /* stop in this case */ /* set the uncorrectable OTP ECC bit for acknowledgment */
iwl_set_bit(trans, CSR_OTP_GP_REG,
CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK);
IWL_ERR(trans, "Uncorrectable OTP ECC error, abort OTP read\n"); return -EINVAL;
} if (otpgp & CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK) { /* continue in this case */ /* set the correctable OTP ECC bit for acknowledgment */
iwl_set_bit(trans, CSR_OTP_GP_REG,
CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK);
IWL_ERR(trans, "Correctable OTP ECC error, continue read\n");
}
*eeprom_data = cpu_to_le16(r >> 16); return 0;
}
/* locate the beginning of OTP link list */ if (!iwl_read_otp_word(trans, next_link_addr, &link_value)) { if (!link_value) {
IWL_ERR(trans, "OTP is empty\n");
is_empty = true;
}
} else {
IWL_ERR(trans, "Unable to read first block of OTP list.\n");
is_empty = true;
}
return is_empty;
}
/* * iwl_find_otp_image: find EEPROM image in OTP * finding the OTP block that contains the EEPROM image. * the last valid block on the link list (the block _before_ the last block) * is the block we should read and used to configure the device. * If all the available OTP blocks are full, the last block will be the block * we should read and used to configure the device. * only perform this operation if shadow RAM is disabled
*/ staticint iwl_find_otp_image(struct iwl_trans *trans,
u16 *validblockaddr)
{
u16 next_link_addr = 0, valid_addr;
__le16 link_value = 0; int usedblocks = 0;
/* set addressing mode to absolute to traverse the link list */
iwl_set_otp_access_absolute(trans);
/* checking for empty OTP or error */ if (iwl_is_otp_empty(trans)) return -EINVAL;
/* * start traverse link list * until reach the max number of OTP blocks * different devices have different number of OTP blocks
*/ do { /* save current valid block address * check for more block on the link list
*/
valid_addr = next_link_addr;
next_link_addr = le16_to_cpu(link_value) * sizeof(u16);
IWL_DEBUG_EEPROM(trans->dev, "OTP blocks %d addr 0x%x\n",
usedblocks, next_link_addr); if (iwl_read_otp_word(trans, next_link_addr, &link_value)) return -EINVAL; if (!link_value) { /* * reach the end of link list, return success and * set address point to the starting address * of the image
*/
*validblockaddr = valid_addr; /* skip first 2 bytes (link list pointer) */
*validblockaddr += 2; return 0;
} /* more in the link list, continue */
usedblocks++;
} while (usedblocks <= trans->mac_cfg->base->max_ll_items);
/* OTP has no valid blocks */
IWL_DEBUG_EEPROM(trans->dev, "OTP has no valid blocks\n"); return -EINVAL;
}
/* * iwl_read_eeprom - read EEPROM contents * * Load the EEPROM contents from adapter and return it * and its size. * * NOTE: This routine uses the non-debug IO access functions.
*/ int iwl_read_eeprom(struct iwl_trans *trans, u8 **eeprom, size_t *eeprom_size)
{
__le16 *e;
u32 gp = iwl_read32(trans, CSR_EEPROM_GP); int sz; int ret;
u16 addr;
u16 validblockaddr = 0;
u16 cache_addr = 0; int nvm_is_otp;
if (!eeprom || !eeprom_size) return -EINVAL;
nvm_is_otp = iwl_nvm_is_otp(trans); if (nvm_is_otp < 0) return nvm_is_otp;
e = kmalloc(sz, GFP_KERNEL); if (!e) return -ENOMEM;
ret = iwl_eeprom_verify_signature(trans, nvm_is_otp); if (ret) {
IWL_ERR(trans, "EEPROM not found, EEPROM_GP=0x%08x\n", gp); goto err_free;
}
/* Make sure driver (instead of uCode) is allowed to read EEPROM */
ret = iwl_eeprom_acquire_semaphore(trans); if (ret) {
IWL_ERR(trans, "Failed to acquire EEPROM semaphore.\n"); goto err_free;
}
if (nvm_is_otp) {
ret = iwl_init_otp_access(trans); if (ret) {
IWL_ERR(trans, "Failed to initialize OTP access.\n"); goto err_unlock;
}
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.