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

Commit 534f0e29 authored by John W. Linville's avatar John W. Linville
Browse files

Merge branch 'wireless-next-2.6' of...

parents e55034e9 4cd2bf76
Loading
Loading
Loading
Loading
+92 −9
Original line number Diff line number Diff line
@@ -483,8 +483,6 @@ void iwlagn_rx_handler_setup(struct iwl_priv *priv)
	/* init calibration handlers */
	priv->rx_handlers[CALIBRATION_RES_NOTIFICATION] =
					iwlagn_rx_calib_result;
	priv->rx_handlers[CALIBRATION_COMPLETE_NOTIFICATION] =
					iwlagn_rx_calib_complete;
	priv->rx_handlers[REPLY_TX] = iwlagn_rx_reply_tx;

	/* set up notification wait support */
@@ -2256,34 +2254,44 @@ int iwl_dump_fh(struct iwl_priv *priv, char **buf, bool display)
/* notification wait support */
void iwlagn_init_notification_wait(struct iwl_priv *priv,
				   struct iwl_notification_wait *wait_entry,
				   u8 cmd,
				   void (*fn)(struct iwl_priv *priv,
					      struct iwl_rx_packet *pkt),
				   u8 cmd)
					      struct iwl_rx_packet *pkt,
					      void *data),
				   void *fn_data)
{
	wait_entry->fn = fn;
	wait_entry->fn_data = fn_data;
	wait_entry->cmd = cmd;
	wait_entry->triggered = false;
	wait_entry->aborted = false;

	spin_lock_bh(&priv->_agn.notif_wait_lock);
	list_add(&wait_entry->list, &priv->_agn.notif_waits);
	spin_unlock_bh(&priv->_agn.notif_wait_lock);
}

signed long iwlagn_wait_notification(struct iwl_priv *priv,
int iwlagn_wait_notification(struct iwl_priv *priv,
			     struct iwl_notification_wait *wait_entry,
			     unsigned long timeout)
{
	int ret;

	ret = wait_event_timeout(priv->_agn.notif_waitq,
				 wait_entry->triggered,
				 wait_entry->triggered || wait_entry->aborted,
				 timeout);

	spin_lock_bh(&priv->_agn.notif_wait_lock);
	list_del(&wait_entry->list);
	spin_unlock_bh(&priv->_agn.notif_wait_lock);

	return ret;
	if (wait_entry->aborted)
		return -EIO;

	/* return value is always >= 0 */
	if (ret <= 0)
		return -ETIMEDOUT;
	return 0;
}

void iwlagn_remove_notification(struct iwl_priv *priv,
@@ -2293,3 +2301,78 @@ void iwlagn_remove_notification(struct iwl_priv *priv,
	list_del(&wait_entry->list);
	spin_unlock_bh(&priv->_agn.notif_wait_lock);
}

int iwlagn_start_device(struct iwl_priv *priv)
{
	int ret;

	if (iwl_prepare_card_hw(priv)) {
		IWL_WARN(priv, "Exit HW not ready\n");
		return -EIO;
	}

	/* If platform's RF_KILL switch is NOT set to KILL */
	if (iwl_read32(priv, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)
		clear_bit(STATUS_RF_KILL_HW, &priv->status);
	else
		set_bit(STATUS_RF_KILL_HW, &priv->status);

	if (iwl_is_rfkill(priv)) {
		wiphy_rfkill_set_hw_state(priv->hw->wiphy, true);
		iwl_enable_interrupts(priv);
		return -ERFKILL;
	}

	iwl_write32(priv, CSR_INT, 0xFFFFFFFF);

	ret = iwlagn_hw_nic_init(priv);
	if (ret) {
		IWL_ERR(priv, "Unable to init nic\n");
		return ret;
	}

	/* make sure rfkill handshake bits are cleared */
	iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
	iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR,
		    CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);

	/* clear (again), then enable host interrupts */
	iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
	iwl_enable_interrupts(priv);

	/* really make sure rfkill handshake bits are cleared */
	iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
	iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);

	return 0;
}

void iwlagn_stop_device(struct iwl_priv *priv)
{
	unsigned long flags;

	/* stop and reset the on-board processor */
	iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET);

	/* tell the device to stop sending interrupts */
	spin_lock_irqsave(&priv->lock, flags);
	iwl_disable_interrupts(priv);
	spin_unlock_irqrestore(&priv->lock, flags);
	iwl_synchronize_irq(priv);

	/* device going down, Stop using ICT table */
	iwl_disable_ict(priv);

	iwlagn_txq_ctx_stop(priv);
	iwlagn_rxq_stop(priv);

	/* Power-down device's busmaster DMA clocks */
	iwl_write_prph(priv, APMG_CLK_DIS_REG, APMG_CLK_VAL_DMA_CLK_RQT);
	udelay(5);

	/* Make sure (redundant) we've released our request to stay awake */
	iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);

	/* Stop the device, and put it in low power state */
	iwl_apm_stop(priv);
}
+5 −8
Original line number Diff line number Diff line
@@ -58,8 +58,9 @@ static int iwlagn_disable_pan(struct iwl_priv *priv,
	u8 old_dev_type = send->dev_type;
	int ret;

	iwlagn_init_notification_wait(priv, &disable_wait, NULL,
				      REPLY_WIPAN_DEACTIVATION_COMPLETE);
	iwlagn_init_notification_wait(priv, &disable_wait,
				      REPLY_WIPAN_DEACTIVATION_COMPLETE,
				      NULL, NULL);

	send->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
	send->dev_type = RXON_DEV_TYPE_P2P;
@@ -72,13 +73,9 @@ static int iwlagn_disable_pan(struct iwl_priv *priv,
		IWL_ERR(priv, "Error disabling PAN (%d)\n", ret);
		iwlagn_remove_notification(priv, &disable_wait);
	} else {
		signed long wait_res;

		wait_res = iwlagn_wait_notification(priv, &disable_wait, HZ);
		if (wait_res == 0) {
		ret = iwlagn_wait_notification(priv, &disable_wait, HZ);
		if (ret)
			IWL_ERR(priv, "Timed out waiting for PAN disable\n");
			ret = -EIO;
		}
	}

	return ret;
+173 −72
Original line number Diff line number Diff line
@@ -161,47 +161,19 @@ static int iwlagn_load_section(struct iwl_priv *priv, const char *name,
}

static int iwlagn_load_given_ucode(struct iwl_priv *priv,
		struct fw_desc *inst_image,
		struct fw_desc *data_image)
				   struct fw_img *image)
{
	int ret = 0;

	ret = iwlagn_load_section(priv, "INST", inst_image,
	ret = iwlagn_load_section(priv, "INST", &image->code,
				   IWLAGN_RTC_INST_LOWER_BOUND);
	if (ret)
		return ret;

	return iwlagn_load_section(priv, "DATA", data_image,
	return iwlagn_load_section(priv, "DATA", &image->data,
				    IWLAGN_RTC_DATA_LOWER_BOUND);
}

int iwlagn_load_ucode(struct iwl_priv *priv)
{
	int ret = 0;

	/* check whether init ucode should be loaded, or rather runtime ucode */
	if (priv->ucode_init.len && (priv->ucode_type == UCODE_NONE)) {
		IWL_DEBUG_INFO(priv, "Init ucode found. Loading init ucode...\n");
		ret = iwlagn_load_given_ucode(priv,
			&priv->ucode_init, &priv->ucode_init_data);
		if (!ret) {
			IWL_DEBUG_INFO(priv, "Init ucode load complete.\n");
			priv->ucode_type = UCODE_INIT;
		}
	} else {
		IWL_DEBUG_INFO(priv, "Init ucode not found, or already loaded. "
			"Loading runtime ucode...\n");
		ret = iwlagn_load_given_ucode(priv,
			&priv->ucode_code, &priv->ucode_data);
		if (!ret) {
			IWL_DEBUG_INFO(priv, "Runtime ucode load complete.\n");
			priv->ucode_type = UCODE_RT;
		}
	}

	return ret;
}

/*
 *  Calibration
 */
@@ -297,33 +269,9 @@ void iwlagn_rx_calib_result(struct iwl_priv *priv,
	iwl_calib_set(&priv->calib_results[index], pkt->u.raw, len);
}

void iwlagn_rx_calib_complete(struct iwl_priv *priv,
			       struct iwl_rx_mem_buffer *rxb)
static int iwlagn_init_alive_start(struct iwl_priv *priv)
{
	IWL_DEBUG_INFO(priv, "Init. calibration is completed, restarting fw.\n");
	queue_work(priv->workqueue, &priv->restart);
}

void iwlagn_init_alive_start(struct iwl_priv *priv)
{
	int ret = 0;

	/* initialize uCode was loaded... verify inst image.
	 * This is a paranoid check, because we would not have gotten the
	 * "initialize" alive if code weren't properly loaded.  */
	if (iwl_verify_ucode(priv, &priv->ucode_init)) {
		/* Runtime instruction load was bad;
		 * take it all the way back down so we can try again */
		IWL_DEBUG_INFO(priv, "Bad \"initialize\" uCode load.\n");
		goto restart;
	}

	ret = iwlagn_alive_notify(priv);
	if (ret) {
		IWL_WARN(priv,
			"Could not complete ALIVE transition: %d\n", ret);
		goto restart;
	}
	int ret;

	if (priv->cfg->bt_params &&
	    priv->cfg->bt_params->advanced_bt_coexist) {
@@ -333,24 +281,25 @@ void iwlagn_init_alive_start(struct iwl_priv *priv)
		 * no need to close the envlope since we are going
		 * to load the runtime uCode later.
		 */
		iwlagn_send_bt_env(priv, IWL_BT_COEX_ENV_OPEN,
		ret = iwlagn_send_bt_env(priv, IWL_BT_COEX_ENV_OPEN,
			BT_COEX_PRIO_TBL_EVT_INIT_CALIB2);
		if (ret)
			return ret;

	}
	iwlagn_send_calib_cfg(priv);

	ret = iwlagn_send_calib_cfg(priv);
	if (ret)
		return ret;

	/**
	 * temperature offset calibration is only needed for runtime ucode,
	 * so prepare the value now.
	 */
	if (priv->cfg->need_temp_offset_calib)
		iwlagn_set_temperature_offset_calib(priv);

	return;
		return iwlagn_set_temperature_offset_calib(priv);

restart:
	/* real restart (first load init_ucode) */
	queue_work(priv->workqueue, &priv->restart);
	return 0;
}

static int iwlagn_send_wimax_coex(struct iwl_priv *priv)
@@ -413,19 +362,22 @@ void iwlagn_send_prio_tbl(struct iwl_priv *priv)
		IWL_ERR(priv, "failed to send BT prio tbl command\n");
}

void iwlagn_send_bt_env(struct iwl_priv *priv, u8 action, u8 type)
int iwlagn_send_bt_env(struct iwl_priv *priv, u8 action, u8 type)
{
	struct iwl_bt_coex_prot_env_cmd env_cmd;
	int ret;

	env_cmd.action = action;
	env_cmd.type = type;
	if (iwl_send_cmd_pdu(priv, REPLY_BT_COEX_PROT_ENV,
			     sizeof(env_cmd), &env_cmd))
	ret = iwl_send_cmd_pdu(priv, REPLY_BT_COEX_PROT_ENV,
			       sizeof(env_cmd), &env_cmd);
	if (ret)
		IWL_ERR(priv, "failed to send BT env command\n");
	return ret;
}


int iwlagn_alive_notify(struct iwl_priv *priv)
static int iwlagn_alive_notify(struct iwl_priv *priv)
{
	const struct queue_to_fifo_ac *queue_to_fifo;
	struct iwl_rxon_context *ctx;
@@ -604,15 +556,164 @@ static void iwl_print_mismatch_inst(struct iwl_priv *priv,
 * iwl_verify_ucode - determine which instruction image is in SRAM,
 *    and verify its contents
 */
int iwl_verify_ucode(struct iwl_priv *priv, struct fw_desc *fw_desc)
static int iwl_verify_ucode(struct iwl_priv *priv, struct fw_img *img)
{
	if (!iwlcore_verify_inst_sparse(priv, fw_desc)) {
	if (!iwlcore_verify_inst_sparse(priv, &img->code)) {
		IWL_DEBUG_INFO(priv, "uCode is good in inst SRAM\n");
		return 0;
	}

	IWL_ERR(priv, "UCODE IMAGE IN INSTRUCTION SRAM NOT VALID!!\n");

	iwl_print_mismatch_inst(priv, fw_desc);
	iwl_print_mismatch_inst(priv, &img->code);
	return -EIO;
}

struct iwlagn_alive_data {
	bool valid;
	u8 subtype;
};

static void iwlagn_alive_fn(struct iwl_priv *priv,
			    struct iwl_rx_packet *pkt,
			    void *data)
{
	struct iwlagn_alive_data *alive_data = data;
	struct iwl_alive_resp *palive;

	palive = &pkt->u.alive_frame;

	IWL_DEBUG_INFO(priv, "Alive ucode status 0x%08X revision "
		       "0x%01X 0x%01X\n",
		       palive->is_valid, palive->ver_type,
		       palive->ver_subtype);

	priv->device_pointers.error_event_table =
		le32_to_cpu(palive->error_event_table_ptr);
	priv->device_pointers.log_event_table =
		le32_to_cpu(palive->log_event_table_ptr);

	alive_data->subtype = palive->ver_subtype;
	alive_data->valid = palive->is_valid == UCODE_VALID_OK;
}

#define UCODE_ALIVE_TIMEOUT	HZ
#define UCODE_CALIB_TIMEOUT	(2*HZ)

int iwlagn_load_ucode_wait_alive(struct iwl_priv *priv,
				 struct fw_img *image,
				 int subtype, int alternate_subtype)
{
	struct iwl_notification_wait alive_wait;
	struct iwlagn_alive_data alive_data;
	int ret;
	enum iwlagn_ucode_subtype old_type;

	ret = iwlagn_start_device(priv);
	if (ret)
		return ret;

	iwlagn_init_notification_wait(priv, &alive_wait, REPLY_ALIVE,
				      iwlagn_alive_fn, &alive_data);

	old_type = priv->ucode_type;
	priv->ucode_type = subtype;

	ret = iwlagn_load_given_ucode(priv, image);
	if (ret) {
		priv->ucode_type = old_type;
		iwlagn_remove_notification(priv, &alive_wait);
		return ret;
	}

	/* Remove all resets to allow NIC to operate */
	iwl_write32(priv, CSR_RESET, 0);

	/*
	 * Some things may run in the background now, but we
	 * just wait for the ALIVE notification here.
	 */
	ret = iwlagn_wait_notification(priv, &alive_wait, UCODE_ALIVE_TIMEOUT);
	if (ret) {
		priv->ucode_type = old_type;
		return ret;
	}

	if (!alive_data.valid) {
		IWL_ERR(priv, "Loaded ucode is not valid!\n");
		priv->ucode_type = old_type;
		return -EIO;
	}

	if (alive_data.subtype != subtype &&
	    alive_data.subtype != alternate_subtype) {
		IWL_ERR(priv,
			"Loaded ucode is not expected type (got %d, expected %d)!\n",
			alive_data.subtype, subtype);
		priv->ucode_type = old_type;
		return -EIO;
	}

	ret = iwl_verify_ucode(priv, image);
	if (ret) {
		priv->ucode_type = old_type;
		return ret;
	}

	/* delay a bit to give rfkill time to run */
	msleep(5);

	ret = iwlagn_alive_notify(priv);
	if (ret) {
		IWL_WARN(priv,
			"Could not complete ALIVE transition: %d\n", ret);
		priv->ucode_type = old_type;
		return ret;
	}

	return 0;
}

int iwlagn_run_init_ucode(struct iwl_priv *priv)
{
	struct iwl_notification_wait calib_wait;
	int ret;

	lockdep_assert_held(&priv->mutex);

	/* No init ucode required? Curious, but maybe ok */
	if (!priv->ucode_init.code.len)
		return 0;

	if (priv->ucode_type != UCODE_SUBTYPE_NONE_LOADED)
		return 0;

	iwlagn_init_notification_wait(priv, &calib_wait,
				      CALIBRATION_COMPLETE_NOTIFICATION,
				      NULL, NULL);

	/* Will also start the device */
	ret = iwlagn_load_ucode_wait_alive(priv, &priv->ucode_init,
					   UCODE_SUBTYPE_INIT, -1);
	if (ret)
		goto error;

	ret = iwlagn_init_alive_start(priv);
	if (ret)
		goto error;

	/*
	 * Some things may run in the background now, but we
	 * just wait for the calibration complete notification.
	 */
	ret = iwlagn_wait_notification(priv, &calib_wait, UCODE_CALIB_TIMEOUT);

	goto out;

 error:
	iwlagn_remove_notification(priv, &calib_wait);
 out:
	/* Whatever happened, stop the device */
	iwlagn_stop_device(priv);
	return ret;
}
+126 −306

File changed.

Preview size limit exceeded, changes collapsed.

+23 −10
Original line number Diff line number Diff line
@@ -120,6 +120,19 @@ int iwl_alloc_isr_ict(struct iwl_priv *priv);
void iwl_free_isr_ict(struct iwl_priv *priv);
irqreturn_t iwl_isr_ict(int irq, void *data);

/* call this function to flush any scheduled tasklet */
static inline void iwl_synchronize_irq(struct iwl_priv *priv)
{
	/* wait to make sure we flush pending tasklet*/
	synchronize_irq(priv->pci_dev->irq);
	tasklet_kill(&priv->irq_tasklet);
}

int iwl_prepare_card_hw(struct iwl_priv *priv);

int iwlagn_start_device(struct iwl_priv *priv);
void iwlagn_stop_device(struct iwl_priv *priv);

/* tx queue */
void iwlagn_set_wr_ptrs(struct iwl_priv *priv,
		     int txq_id, u32 index);
@@ -145,16 +158,14 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw,
			     u32 changes);

/* uCode */
int iwlagn_load_ucode(struct iwl_priv *priv);
void iwlagn_rx_calib_result(struct iwl_priv *priv,
			 struct iwl_rx_mem_buffer *rxb);
void iwlagn_rx_calib_complete(struct iwl_priv *priv,
			   struct iwl_rx_mem_buffer *rxb);
void iwlagn_init_alive_start(struct iwl_priv *priv);
int iwlagn_alive_notify(struct iwl_priv *priv);
int iwl_verify_ucode(struct iwl_priv *priv, struct fw_desc *fw_desc);
void iwlagn_send_bt_env(struct iwl_priv *priv, u8 action, u8 type);
int iwlagn_send_bt_env(struct iwl_priv *priv, u8 action, u8 type);
void iwlagn_send_prio_tbl(struct iwl_priv *priv);
int iwlagn_run_init_ucode(struct iwl_priv *priv);
int iwlagn_load_ucode_wait_alive(struct iwl_priv *priv,
				 struct fw_img *image,
				 int subtype, int alternate_subtype);

/* lib */
void iwl_check_abort_status(struct iwl_priv *priv,
@@ -325,10 +336,12 @@ void iwlcore_eeprom_release_semaphore(struct iwl_priv *priv);
void __acquires(wait_entry)
iwlagn_init_notification_wait(struct iwl_priv *priv,
			      struct iwl_notification_wait *wait_entry,
			      u8 cmd,
			      void (*fn)(struct iwl_priv *priv,
					 struct iwl_rx_packet *pkt),
			      u8 cmd);
signed long __releases(wait_entry)
					 struct iwl_rx_packet *pkt,
					 void *data),
			      void *fn_data);
int __must_check __releases(wait_entry)
iwlagn_wait_notification(struct iwl_priv *priv,
			 struct iwl_notification_wait *wait_entry,
			 unsigned long timeout);
Loading