Exemple #1
0
/**
 * iwl_eeprom_init - read EEPROM contents
 *
 * Load the EEPROM contents from adapter into priv->eeprom
 *
 * NOTE:  This routine uses the non-debug IO access functions.
 */
int iwl_eeprom_init(struct iwl_priv *priv)
{
	u16 *e;
	u32 gp = iwl_read32(priv, CSR_EEPROM_GP);
	int sz;
	int ret;
	u16 addr;
	u16 validblockaddr = 0;
	u16 cache_addr = 0;

	priv->nvm_device_type = iwlcore_get_nvm_type(priv);

	/* allocate eeprom */
	IWL_DEBUG_INFO(priv, "NVM size = %d\n", priv->cfg->eeprom_size);
	sz = priv->cfg->eeprom_size;
	priv->eeprom = kzalloc(sz, GFP_KERNEL);
	if (!priv->eeprom) {
		ret = -ENOMEM;
		goto alloc_err;
	}
	e = (u16 *)priv->eeprom;

	ret = priv->cfg->ops->lib->eeprom_ops.verify_signature(priv);
	if (ret < 0) {
		IWL_ERR(priv, "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 = priv->cfg->ops->lib->eeprom_ops.acquire_semaphore(priv);
	if (ret < 0) {
		IWL_ERR(priv, "Failed to acquire EEPROM semaphore.\n");
		ret = -ENOENT;
		goto err;
	}
	if (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) {
		ret = iwl_init_otp_access(priv);
		if (ret) {
			IWL_ERR(priv, "Failed to initialize OTP access.\n");
			ret = -ENOENT;
			goto done;
		}
		_iwl_write32(priv, CSR_EEPROM_GP,
			     iwl_read32(priv, CSR_EEPROM_GP) &
			     ~CSR_EEPROM_GP_IF_OWNER_MSK);

		iwl_set_bit(priv, CSR_OTP_GP_REG,
			     CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK |
			     CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK);
		/* traversing the linked list if no shadow ram supported */
		if (!priv->cfg->shadow_ram_support) {
			if (iwl_find_otp_image(priv, &validblockaddr)) {
				ret = -ENOENT;
				goto done;
			}
		}
		for (addr = validblockaddr; addr < validblockaddr + sz;
		     addr += sizeof(u16)) {
			u16 eeprom_data;

			ret = iwl_read_otp_word(priv, addr, &eeprom_data);
			if (ret)
				goto done;
			e[cache_addr / 2] = eeprom_data;
			cache_addr += sizeof(u16);
		}
	} else {
		/* eeprom is an array of 16bit values */
		for (addr = 0; addr < sz; addr += sizeof(u16)) {
			u32 r;

			_iwl_write32(priv, CSR_EEPROM_REG,
				     CSR_EEPROM_REG_MSK_ADDR & (addr << 1));

			ret = iwl_poll_direct_bit(priv, CSR_EEPROM_REG,
						  CSR_EEPROM_REG_READ_VALID_MSK,
						  IWL_EEPROM_ACCESS_TIMEOUT);
			if (ret < 0) {
				IWL_ERR(priv, "Time out reading EEPROM[%d]\n", addr);
				goto done;
			}
			r = _iwl_read_direct32(priv, CSR_EEPROM_REG);
			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)
		iwl_eeprom_free(priv);
alloc_err:
	return ret;
}
/**
 * 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;

	sz = trans->cfg->base_params->eeprom_size;
	IWL_DEBUG_EEPROM(trans->dev, "NVM size = %d\n", sz);

	e = kmalloc(sz, GFP_KERNEL);
	if (!e)
		return -ENOMEM;

	ret = iwl_eeprom_verify_signature(trans, nvm_is_otp);
	if (ret < 0) {
		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 < 0) {
		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;
		}

		iwl_write32(trans, CSR_EEPROM_GP,
			    iwl_read32(trans, CSR_EEPROM_GP) &
			    ~CSR_EEPROM_GP_IF_OWNER_MSK);

		iwl_set_bit(trans, CSR_OTP_GP_REG,
			    CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK |
			    CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK);
		/* traversing the linked list if no shadow ram supported */
		if (!trans->cfg->base_params->shadow_ram_support) {
			ret = iwl_find_otp_image(trans, &validblockaddr);
			if (ret)
				goto err_unlock;
		}
		for (addr = validblockaddr; addr < validblockaddr + sz;
		     addr += sizeof(u16)) {
			__le16 eeprom_data;

			ret = iwl_read_otp_word(trans, addr, &eeprom_data);
			if (ret)
				goto err_unlock;
			e[cache_addr / 2] = eeprom_data;
			cache_addr += sizeof(u16);
		}
	} else {
		/* eeprom is an array of 16bit values */
		for (addr = 0; addr < sz; addr += sizeof(u16)) {
			u32 r;

			iwl_write32(trans, CSR_EEPROM_REG,
				    CSR_EEPROM_REG_MSK_ADDR & (addr << 1));

			ret = iwl_poll_bit(trans, CSR_EEPROM_REG,
					   CSR_EEPROM_REG_READ_VALID_MSK,
					   CSR_EEPROM_REG_READ_VALID_MSK,
					   IWL_EEPROM_ACCESS_TIMEOUT);
			if (ret < 0) {
				IWL_ERR(trans,
					"Time out reading EEPROM[%d]\n", addr);
				goto err_unlock;
			}
			r = iwl_read32(trans, CSR_EEPROM_REG);
			e[addr / 2] = cpu_to_le16(r >> 16);
		}
	}

	IWL_DEBUG_EEPROM(trans->dev, "NVM Type: %s\n",
			 nvm_is_otp ? "OTP" : "EEPROM");

	iwl_eeprom_release_semaphore(trans);

	*eeprom_size = sz;
	*eeprom = (u8 *)e;
	return 0;

 err_unlock:
	iwl_eeprom_release_semaphore(trans);
 err_free:
	kfree(e);

	return ret;
}