Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 073d3f5f authored by Tomas Winkler's avatar Tomas Winkler Committed by John W. Linville
Browse files

iwlwifi: changing EEPROM layout handling



This patch
1. changes the current EEPROM handling through a single HW struct
layout representation, to more general approach, treating the EEPROM
image as a flat bytes array, handling this image through ops functions
and offsets.
2. Eeprom is dynamically allocated accroding HW type

Signed-off-by: default avatarTomas Winkler <tomas.winkler@intel.com>
Signed-off-by: default avatarRon Rindjunsky <ron.rindjunsky@intel.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 5da4b55f
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -69,6 +69,9 @@
#ifndef __iwl_4965_hw_h__
#define __iwl_4965_hw_h__

/* EERPROM */
#define IWL4965_EEPROM_IMG_SIZE			1024

/*
 * uCode queue management definitions ...
 * Queue #4 is the command queue for 3945 and 4965; map it to Tx FIFO chnl 4.
+40 −22
Original line number Diff line number Diff line
@@ -699,8 +699,9 @@ int iwl4965_hw_nic_init(struct iwl_priv *priv)
	unsigned long flags;
	struct iwl4965_rx_queue *rxq = &priv->rxq;
	u8 rev_id;
	u32 val;
	u8 val_link;
	u16 sku_cap;
	u32 val;

	/* nic_init */
	spin_lock_irqsave(&priv->lock, flags);
@@ -759,7 +760,8 @@ int iwl4965_hw_nic_init(struct iwl_priv *priv)

	spin_unlock_irqrestore(&priv->lock, flags);

	if (priv->eeprom.calib_version < EEPROM_TX_POWER_VERSION_NEW) {
	if (iwl_eeprom_query16(priv, EEPROM_4965_CALIB_VERSION_OFFSET) <
		EEPROM_4965_TX_POWER_VERSION) {
		IWL_ERROR("Older EEPROM detected!  Aborting.\n");
		return -EINVAL;
	}
@@ -816,6 +818,10 @@ int iwl4965_hw_nic_init(struct iwl_priv *priv)
	rxq->need_update = 1;
	iwl4965_rx_queue_update_write_ptr(priv, rxq);

	/* init the txpower calibration pointer */
	priv->calib_info = (struct iwl_eeprom_calib_info *)
		iwl_eeprom_query_addr(priv, EEPROM_4965_CALIB_TXPOWER_OFFSET);

	spin_unlock_irqrestore(&priv->lock, flags);

	/* Allocate and init all Tx and Command queues */
@@ -823,10 +829,11 @@ int iwl4965_hw_nic_init(struct iwl_priv *priv)
	if (rc)
		return rc;

	if (priv->eeprom.sku_cap & EEPROM_SKU_CAP_SW_RF_KILL_ENABLE)
	sku_cap = iwl_eeprom_query16(priv, EEPROM_SKU_CAP);
	if (sku_cap & EEPROM_SKU_CAP_SW_RF_KILL_ENABLE)
		IWL_DEBUG_RF_KILL("SW RF KILL supported in EEPROM.\n");

	if (priv->eeprom.sku_cap & EEPROM_SKU_CAP_HW_RF_KILL_ENABLE)
	if (sku_cap & EEPROM_SKU_CAP_HW_RF_KILL_ENABLE)
		IWL_DEBUG_RF_KILL("HW RF KILL supported in EEPROM.\n");

	set_bit(STATUS_INIT, &priv->status);
@@ -1542,11 +1549,11 @@ static u32 iwl4965_get_sub_band(const struct iwl_priv *priv, u32 channel)
	s32 b = -1;

	for (b = 0; b < EEPROM_TX_POWER_BANDS; b++) {
		if (priv->eeprom.calib_info.band_info[b].ch_from == 0)
		if (priv->calib_info->band_info[b].ch_from == 0)
			continue;

		if ((channel >= priv->eeprom.calib_info.band_info[b].ch_from)
		    && (channel <= priv->eeprom.calib_info.band_info[b].ch_to))
		if ((channel >= priv->calib_info->band_info[b].ch_from)
		    && (channel <= priv->calib_info->band_info[b].ch_to))
			break;
	}

@@ -1574,14 +1581,14 @@ static s32 iwl4965_interpolate_value(s32 x, s32 x1, s32 y1, s32 x2, s32 y2)
 * in channel number.
 */
static int iwl4965_interpolate_chan(struct iwl_priv *priv, u32 channel,
				    struct iwl4965_eeprom_calib_ch_info *chan_info)
				    struct iwl_eeprom_calib_ch_info *chan_info)
{
	s32 s = -1;
	u32 c;
	u32 m;
	const struct iwl4965_eeprom_calib_measure *m1;
	const struct iwl4965_eeprom_calib_measure *m2;
	struct iwl4965_eeprom_calib_measure *omeas;
	const struct iwl_eeprom_calib_measure *m1;
	const struct iwl_eeprom_calib_measure *m2;
	struct iwl_eeprom_calib_measure *omeas;
	u32 ch_i1;
	u32 ch_i2;

@@ -1591,8 +1598,8 @@ static int iwl4965_interpolate_chan(struct iwl_priv *priv, u32 channel,
		return -1;
	}

	ch_i1 = priv->eeprom.calib_info.band_info[s].ch1.ch_num;
	ch_i2 = priv->eeprom.calib_info.band_info[s].ch2.ch_num;
	ch_i1 = priv->calib_info->band_info[s].ch1.ch_num;
	ch_i2 = priv->calib_info->band_info[s].ch2.ch_num;
	chan_info->ch_num = (u8) channel;

	IWL_DEBUG_TXPOWER("channel %d subband %d factory cal ch %d & %d\n",
@@ -1600,9 +1607,9 @@ static int iwl4965_interpolate_chan(struct iwl_priv *priv, u32 channel,

	for (c = 0; c < EEPROM_TX_POWER_TX_CHAINS; c++) {
		for (m = 0; m < EEPROM_TX_POWER_MEASUREMENTS; m++) {
			m1 = &(priv->eeprom.calib_info.band_info[s].ch1.
			m1 = &(priv->calib_info->band_info[s].ch1.
			       measurements[c][m]);
			m2 = &(priv->eeprom.calib_info.band_info[s].ch2.
			m2 = &(priv->calib_info->band_info[s].ch2.
			       measurements[c][m]);
			omeas = &(chan_info->measurements[c][m]);

@@ -1921,8 +1928,8 @@ static int iwl4965_fill_txpower_tbl(struct iwl_priv *priv, u8 band, u16 channel,
	int i;
	int c;
	const struct iwl_channel_info *ch_info = NULL;
	struct iwl4965_eeprom_calib_ch_info ch_eeprom_info;
	const struct iwl4965_eeprom_calib_measure *measurement;
	struct iwl_eeprom_calib_ch_info ch_eeprom_info;
	const struct iwl_eeprom_calib_measure *measurement;
	s16 voltage;
	s32 init_voltage;
	s32 voltage_compensation;
@@ -1979,9 +1986,9 @@ static int iwl4965_fill_txpower_tbl(struct iwl_priv *priv, u8 band, u16 channel,
	/* hardware txpower limits ...
	 * saturation (clipping distortion) txpowers are in half-dBm */
	if (band)
		saturation_power = priv->eeprom.calib_info.saturation_power24;
		saturation_power = priv->calib_info->saturation_power24;
	else
		saturation_power = priv->eeprom.calib_info.saturation_power52;
		saturation_power = priv->calib_info->saturation_power52;

	if (saturation_power < IWL_TX_POWER_SATURATION_MIN ||
	    saturation_power > IWL_TX_POWER_SATURATION_MAX) {
@@ -2011,7 +2018,7 @@ static int iwl4965_fill_txpower_tbl(struct iwl_priv *priv, u8 band, u16 channel,
	iwl4965_interpolate_chan(priv, channel, &ch_eeprom_info);

	/* calculate tx gain adjustment based on power supply voltage */
	voltage = priv->eeprom.calib_info.voltage;
	voltage = priv->calib_info->voltage;
	init_voltage = (s32)le32_to_cpu(priv->card_alive_init.voltage);
	voltage_compensation =
	    iwl4965_get_voltage_compensation(voltage, init_voltage);
@@ -2467,14 +2474,14 @@ int iwl4965_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *ptr,

static void iwl4965_hw_card_show_info(struct iwl_priv *priv)
{
	u16 hw_version = priv->eeprom.board_revision_4965;
	u16 hw_version = iwl_eeprom_query16(priv, EEPROM_4965_BOARD_REVISION);

	IWL_DEBUG_INFO("4965ABGN HW Version %u.%u.%u\n",
		       ((hw_version >> 8) & 0x0F),
		       ((hw_version >> 8) >> 4), (hw_version & 0x00FF));

	IWL_DEBUG_INFO("4965ABGN PBA Number %.16s\n",
		       priv->eeprom.board_pba_number_4965);
		       &priv->eeprom[EEPROM_4965_BOARD_PBA]);
}

#define IWL_TX_CRC_SIZE		4
@@ -4340,9 +4347,19 @@ static struct iwl_lib_ops iwl4965_lib = {
		.set_pwr_src = iwl4965_set_pwr_src,
	},
	.eeprom_ops = {
		.regulatory_bands = {
			EEPROM_REGULATORY_BAND_1_CHANNELS,
			EEPROM_REGULATORY_BAND_2_CHANNELS,
			EEPROM_REGULATORY_BAND_3_CHANNELS,
			EEPROM_REGULATORY_BAND_4_CHANNELS,
			EEPROM_REGULATORY_BAND_5_CHANNELS,
			EEPROM_4965_REGULATORY_BAND_24_FAT_CHANNELS,
			EEPROM_4965_REGULATORY_BAND_52_FAT_CHANNELS
		},
		.verify_signature  = iwlcore_eeprom_verify_signature,
		.acquire_semaphore = iwlcore_eeprom_acquire_semaphore,
		.release_semaphore = iwlcore_eeprom_release_semaphore,
		.query_addr = iwlcore_eeprom_query_addr,
	},
	.radio_kill_sw = iwl4965_radio_kill_sw,
	.set_power = iwl4965_set_power,
@@ -4359,6 +4376,7 @@ struct iwl_cfg iwl4965_agn_cfg = {
	.name = "4965AGN",
	.fw_name = "iwlwifi-4965" IWL4965_UCODE_API ".ucode",
	.sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
	.eeprom_size = IWL4965_EEPROM_IMG_SIZE,
	.ops = &iwl4965_ops,
	.mod_params = &iwl4965_mod_params,
};
+5 −4
Original line number Diff line number Diff line
@@ -200,8 +200,8 @@ enum {
struct iwl_channel_info {
	struct iwl4965_channel_tgd_info tgd;
	struct iwl4965_channel_tgh_info tgh;
	struct iwl4965_eeprom_channel eeprom;	  /* EEPROM regulatory limit */
	struct iwl4965_eeprom_channel fat_eeprom; /* EEPROM regulatory limit for
	struct iwl_eeprom_channel eeprom;	/* EEPROM regulatory limit */
	struct iwl_eeprom_channel fat_eeprom;	/* EEPROM regulatory limit for
						 * FAT channel */

	u8 channel;	  /* channel number */
@@ -1122,7 +1122,8 @@ struct iwl_priv {
	struct list_head ibss_mac_hash[IWL_IBSS_MAC_HASH_SIZE];

	/* eeprom */
	struct iwl4965_eeprom eeprom;
	u8 *eeprom;
	struct iwl_eeprom_calib_info *calib_info;

	enum ieee80211_if_types iw_mode;

+1 −0
Original line number Diff line number Diff line
@@ -146,6 +146,7 @@ struct iwl_cfg {
	const char *name;
	const char *fw_name;
	unsigned int sku;
	int eeprom_size;
	const struct iwl_ops *ops;
	const struct iwl_mod_params *mod_params;
};
+72 −29
Original line number Diff line number Diff line
@@ -193,6 +193,12 @@ void iwlcore_eeprom_release_semaphore(struct iwl_priv *priv)
}
EXPORT_SYMBOL(iwlcore_eeprom_release_semaphore);

const u8 *iwlcore_eeprom_query_addr(const struct iwl_priv *priv, size_t offset)
{
	BUG_ON(offset >= priv->cfg->eeprom_size);
	return &priv->eeprom[offset];
}
EXPORT_SYMBOL(iwlcore_eeprom_query_addr);

/**
 * iwl_eeprom_init - read EEPROM contents
@@ -203,30 +209,35 @@ EXPORT_SYMBOL(iwlcore_eeprom_release_semaphore);
 */
int iwl_eeprom_init(struct iwl_priv *priv)
{
	u16 *e = (u16 *)&priv->eeprom;
	u16 *e;
	u32 gp = iwl_read32(priv, CSR_EEPROM_GP);
	u32 r;
	int sz = sizeof(priv->eeprom);
	int sz = priv->cfg->eeprom_size;
	int ret;
	int i;
	u16 addr;

	/* The EEPROM structure has several padding buffers within it
	 * and when adding new EEPROM maps is subject to programmer errors
	 * which may be very difficult to identify without explicitly
	 * checking the resulting size of the eeprom map. */
	BUILD_BUG_ON(sizeof(priv->eeprom) != IWL_EEPROM_IMAGE_SIZE);
	/* allocate eeprom */
	priv->eeprom = kzalloc(sz, GFP_KERNEL);
	if (!priv->eeprom) {
		ret = -ENOMEM;
		goto alloc_err;
	}
	e = (u16 *)priv->eeprom;

	if ((gp & CSR_EEPROM_GP_VALID_MSK) == CSR_EEPROM_GP_BAD_SIGNATURE) {
	ret = priv->cfg->ops->lib->eeprom_ops.verify_signature(priv);
	if (ret < 0) {
		IWL_ERROR("EEPROM not found, EEPROM_GP=0x%08x", gp);
		return -ENOENT;
		ret = -ENOENT;
		goto err;
	}

	/* Make sure driver (instead of uCode) is allowed to read EEPROM */
	ret = priv->cfg->ops->lib->eeprom_ops.acquire_semaphore(priv);
	if (ret < 0) {
		IWL_ERROR("Failed to acquire EEPROM semaphore.\n");
		return -ENOENT;
		ret = -ENOENT;
		goto err;
	}

	/* eeprom is an array of 16bit values */
@@ -250,61 +261,93 @@ int iwl_eeprom_init(struct iwl_priv *priv)
		e[addr / 2] = le16_to_cpu((__force __le16)(r >> 16));
	}
	ret = 0;

done:
	priv->cfg->ops->lib->eeprom_ops.release_semaphore(priv);
err:
	if (ret)
		kfree(priv->eeprom);
alloc_err:
	return ret;
}
EXPORT_SYMBOL(iwl_eeprom_init);

void iwl_eeprom_free(struct iwl_priv *priv)
{
	if(priv->eeprom)
		kfree(priv->eeprom);
	priv->eeprom = NULL;
}
EXPORT_SYMBOL(iwl_eeprom_free);


const u8 *iwl_eeprom_query_addr(const struct iwl_priv *priv, size_t offset)
{
	return priv->cfg->ops->lib->eeprom_ops.query_addr(priv, offset);
}
EXPORT_SYMBOL(iwl_eeprom_query_addr);

u16 iwl_eeprom_query16(const struct iwl_priv *priv, size_t offset)
{
	return (u16)priv->eeprom[offset] | ((u16)priv->eeprom[offset + 1] << 8);
}
EXPORT_SYMBOL(iwl_eeprom_query16);

void iwl_eeprom_get_mac(const struct iwl_priv *priv, u8 *mac)
{
	memcpy(mac, priv->eeprom.mac_address, 6);
	const u8 *addr = priv->cfg->ops->lib->eeprom_ops.query_addr(priv,
					EEPROM_MAC_ADDRESS);
	memcpy(mac, addr, ETH_ALEN);
}
EXPORT_SYMBOL(iwl_eeprom_get_mac);

static void iwl_init_band_reference(const struct iwl_priv *priv,
				    int band,
				    int *eeprom_ch_count,
				    const struct iwl4965_eeprom_channel
				    **eeprom_ch_info,
			int eep_band, int *eeprom_ch_count,
			const struct iwl_eeprom_channel **eeprom_ch_info,
			const u8 **eeprom_ch_index)
{
	switch (band) {
	u32 offset = priv->cfg->ops->lib->
			eeprom_ops.regulatory_bands[eep_band - 1];
	switch (eep_band) {
	case 1:		/* 2.4GHz band */
		*eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_1);
		*eeprom_ch_info = priv->eeprom.band_1_channels;
		*eeprom_ch_info = (struct iwl_eeprom_channel *)
				iwl_eeprom_query_addr(priv, offset);
		*eeprom_ch_index = iwl_eeprom_band_1;
		break;
	case 2:		/* 4.9GHz band */
		*eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_2);
		*eeprom_ch_info = priv->eeprom.band_2_channels;
		*eeprom_ch_info = (struct iwl_eeprom_channel *)
				iwl_eeprom_query_addr(priv, offset);
		*eeprom_ch_index = iwl_eeprom_band_2;
		break;
	case 3:		/* 5.2GHz band */
		*eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_3);
		*eeprom_ch_info = priv->eeprom.band_3_channels;
		*eeprom_ch_info = (struct iwl_eeprom_channel *)
				iwl_eeprom_query_addr(priv, offset);
		*eeprom_ch_index = iwl_eeprom_band_3;
		break;
	case 4:		/* 5.5GHz band */
		*eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_4);
		*eeprom_ch_info = priv->eeprom.band_4_channels;
		*eeprom_ch_info = (struct iwl_eeprom_channel *)
				iwl_eeprom_query_addr(priv, offset);
		*eeprom_ch_index = iwl_eeprom_band_4;
		break;
	case 5:		/* 5.7GHz band */
		*eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_5);
		*eeprom_ch_info = priv->eeprom.band_5_channels;
		*eeprom_ch_info = (struct iwl_eeprom_channel *)
				iwl_eeprom_query_addr(priv, offset);
		*eeprom_ch_index = iwl_eeprom_band_5;
		break;
	case 6:		/* 2.4GHz FAT channels */
		*eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_6);
		*eeprom_ch_info = priv->eeprom.band_24_channels;
		*eeprom_ch_info = (struct iwl_eeprom_channel *)
				iwl_eeprom_query_addr(priv, offset);
		*eeprom_ch_index = iwl_eeprom_band_6;
		break;
	case 7:		/* 5 GHz FAT channels */
		*eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_7);
		*eeprom_ch_info = priv->eeprom.band_52_channels;
		*eeprom_ch_info = (struct iwl_eeprom_channel *)
				iwl_eeprom_query_addr(priv, offset);
		*eeprom_ch_index = iwl_eeprom_band_7;
		break;
	default:
@@ -323,7 +366,7 @@ static void iwl_init_band_reference(const struct iwl_priv *priv,
 */
static int iwl4965_set_fat_chan_info(struct iwl_priv *priv,
			      enum ieee80211_band band, u16 channel,
			      const struct iwl4965_eeprom_channel *eeprom_ch,
			      const struct iwl_eeprom_channel *eeprom_ch,
			      u8 fat_extension_channel)
{
	struct iwl_channel_info *ch_info;
@@ -372,7 +415,7 @@ int iwl_init_channel_map(struct iwl_priv *priv)
{
	int eeprom_ch_count = 0;
	const u8 *eeprom_ch_index = NULL;
	const struct iwl4965_eeprom_channel *eeprom_ch_info = NULL;
	const struct iwl_eeprom_channel *eeprom_ch_info = NULL;
	int band, ch;
	struct iwl_channel_info *ch_info;

@@ -381,9 +424,9 @@ int iwl_init_channel_map(struct iwl_priv *priv)
		return 0;
	}

	if (priv->eeprom.version < 0x2f) {
	if (iwl_eeprom_query16(priv, EEPROM_VERSION) < 0x2f) {
		IWL_WARNING("Unsupported EEPROM version: 0x%04X\n",
			    priv->eeprom.version);
			    iwl_eeprom_query16(priv, EEPROM_VERSION));
		return -EINVAL;
	}

Loading