| 
									
										
										
										
											2013-01-24 14:25:36 +01:00
										 |  |  | /******************************************************************************
 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This file is provided under a dual BSD/GPLv2 license.  When using or | 
					
						
							|  |  |  |  * redistributing this file, you may do so under either license. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * GPL LICENSE SUMMARY | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2013-12-30 13:15:54 +02:00
										 |  |  |  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. | 
					
						
							| 
									
										
										
										
											2013-01-24 14:25:36 +01:00
										 |  |  |  * | 
					
						
							|  |  |  |  * This program is free software; you can redistribute it and/or modify | 
					
						
							|  |  |  |  * it under the terms of version 2 of the GNU General Public License as | 
					
						
							|  |  |  |  * published by the Free Software Foundation. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This program is distributed in the hope that it will be useful, but | 
					
						
							|  |  |  |  * WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
					
						
							|  |  |  |  * General Public License for more details. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * You should have received a copy of the GNU General Public License | 
					
						
							|  |  |  |  * along with this program; if not, write to the Free Software | 
					
						
							|  |  |  |  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, | 
					
						
							|  |  |  |  * USA | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * The full GNU General Public License is included in this distribution | 
					
						
							| 
									
										
										
										
											2013-02-18 09:22:28 +02:00
										 |  |  |  * in the file called COPYING. | 
					
						
							| 
									
										
										
										
											2013-01-24 14:25:36 +01:00
										 |  |  |  * | 
					
						
							|  |  |  |  * Contact Information: | 
					
						
							|  |  |  |  *  Intel Linux Wireless <ilw@linux.intel.com> | 
					
						
							|  |  |  |  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * BSD LICENSE | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2013-12-30 13:15:54 +02:00
										 |  |  |  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. | 
					
						
							| 
									
										
										
										
											2013-01-24 14:25:36 +01:00
										 |  |  |  * All rights reserved. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Redistribution and use in source and binary forms, with or without | 
					
						
							|  |  |  |  * modification, are permitted provided that the following conditions | 
					
						
							|  |  |  |  * are met: | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *  * Redistributions of source code must retain the above copyright | 
					
						
							|  |  |  |  *    notice, this list of conditions and the following disclaimer. | 
					
						
							|  |  |  |  *  * Redistributions in binary form must reproduce the above copyright | 
					
						
							|  |  |  |  *    notice, this list of conditions and the following disclaimer in | 
					
						
							|  |  |  |  *    the documentation and/or other materials provided with the | 
					
						
							|  |  |  |  *    distribution. | 
					
						
							|  |  |  |  *  * Neither the name Intel Corporation nor the names of its | 
					
						
							|  |  |  |  *    contributors may be used to endorse or promote products derived | 
					
						
							|  |  |  |  *    from this software without specific prior written permission. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 
					
						
							|  |  |  |  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 
					
						
							|  |  |  |  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 
					
						
							|  |  |  |  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 
					
						
							|  |  |  |  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 
					
						
							|  |  |  |  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 
					
						
							|  |  |  |  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 
					
						
							|  |  |  |  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 
					
						
							|  |  |  |  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 
					
						
							|  |  |  |  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 
					
						
							|  |  |  |  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *****************************************************************************/ | 
					
						
							|  |  |  | #include <net/mac80211.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "iwl-trans.h"
 | 
					
						
							|  |  |  | #include "iwl-op-mode.h"
 | 
					
						
							|  |  |  | #include "iwl-fw.h"
 | 
					
						
							|  |  |  | #include "iwl-debug.h"
 | 
					
						
							|  |  |  | #include "iwl-csr.h" /* for iwl_mvm_rx_card_state_notif */
 | 
					
						
							|  |  |  | #include "iwl-io.h" /* for iwl_mvm_rx_card_state_notif */
 | 
					
						
							|  |  |  | #include "iwl-eeprom-parse.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "mvm.h"
 | 
					
						
							|  |  |  | #include "iwl-phy-db.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define MVM_UCODE_ALIVE_TIMEOUT	HZ
 | 
					
						
							|  |  |  | #define MVM_UCODE_CALIB_TIMEOUT	(2*HZ)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define UCODE_VALID_OK	cpu_to_le32(0x1)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct iwl_mvm_alive_data { | 
					
						
							|  |  |  | 	bool valid; | 
					
						
							|  |  |  | 	u32 scd_base_addr; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline const struct fw_img * | 
					
						
							|  |  |  | iwl_get_ucode_image(struct iwl_mvm *mvm, enum iwl_ucode_type ucode_type) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (ucode_type >= IWL_UCODE_TYPE_MAX) | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return &mvm->fw->img[ucode_type]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int iwl_send_tx_ant_cfg(struct iwl_mvm *mvm, u8 valid_tx_ant) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct iwl_tx_ant_cfg_cmd tx_ant_cmd = { | 
					
						
							|  |  |  | 		.valid = cpu_to_le32(valid_tx_ant), | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-09 20:38:19 +02:00
										 |  |  | 	IWL_DEBUG_FW(mvm, "select valid tx ant: %u\n", valid_tx_ant); | 
					
						
							| 
									
										
										
										
											2013-01-24 14:25:36 +01:00
										 |  |  | 	return iwl_mvm_send_cmd_pdu(mvm, TX_ANT_CONFIGURATION_CMD, CMD_SYNC, | 
					
						
							|  |  |  | 				    sizeof(tx_ant_cmd), &tx_ant_cmd); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait, | 
					
						
							|  |  |  | 			 struct iwl_rx_packet *pkt, void *data) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct iwl_mvm *mvm = | 
					
						
							|  |  |  | 		container_of(notif_wait, struct iwl_mvm, notif_wait); | 
					
						
							|  |  |  | 	struct iwl_mvm_alive_data *alive_data = data; | 
					
						
							|  |  |  | 	struct mvm_alive_resp *palive; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	palive = (void *)pkt->data; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	mvm->error_event_table = le32_to_cpu(palive->error_event_table_ptr); | 
					
						
							|  |  |  | 	mvm->log_event_table = le32_to_cpu(palive->log_event_table_ptr); | 
					
						
							|  |  |  | 	alive_data->scd_base_addr = le32_to_cpu(palive->scd_base_ptr); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	alive_data->valid = le16_to_cpu(palive->status) == IWL_ALIVE_STATUS_OK; | 
					
						
							| 
									
										
										
										
											2013-03-13 17:02:41 +02:00
										 |  |  | 	IWL_DEBUG_FW(mvm, | 
					
						
							|  |  |  | 		     "Alive ucode status 0x%04x revision 0x%01X 0x%01X flags 0x%01X\n", | 
					
						
							| 
									
										
										
										
											2013-01-24 14:25:36 +01:00
										 |  |  | 		     le16_to_cpu(palive->status), palive->ver_type, | 
					
						
							| 
									
										
										
										
											2013-03-13 17:02:41 +02:00
										 |  |  | 		     palive->ver_subtype, palive->flags); | 
					
						
							| 
									
										
										
										
											2013-01-24 14:25:36 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static bool iwl_wait_phy_db_entry(struct iwl_notif_wait_data *notif_wait, | 
					
						
							|  |  |  | 				  struct iwl_rx_packet *pkt, void *data) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct iwl_phy_db *phy_db = data; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (pkt->hdr.cmd != CALIB_RES_NOTIF_PHY_DB) { | 
					
						
							|  |  |  | 		WARN_ON(pkt->hdr.cmd != INIT_COMPLETE_NOTIF); | 
					
						
							|  |  |  | 		return true; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	WARN_ON(iwl_phy_db_set_section(phy_db, pkt, GFP_ATOMIC)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm, | 
					
						
							|  |  |  | 					 enum iwl_ucode_type ucode_type) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct iwl_notification_wait alive_wait; | 
					
						
							|  |  |  | 	struct iwl_mvm_alive_data alive_data; | 
					
						
							|  |  |  | 	const struct fw_img *fw; | 
					
						
							|  |  |  | 	int ret, i; | 
					
						
							|  |  |  | 	enum iwl_ucode_type old_type = mvm->cur_ucode; | 
					
						
							|  |  |  | 	static const u8 alive_cmd[] = { MVM_ALIVE }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	fw = iwl_get_ucode_image(mvm, ucode_type); | 
					
						
							| 
									
										
										
										
											2013-10-25 12:32:51 +02:00
										 |  |  | 	if (WARN_ON(!fw)) | 
					
						
							| 
									
										
										
										
											2013-01-24 14:25:36 +01:00
										 |  |  | 		return -EINVAL; | 
					
						
							| 
									
										
										
										
											2013-10-25 12:32:51 +02:00
										 |  |  | 	mvm->cur_ucode = ucode_type; | 
					
						
							|  |  |  | 	mvm->ucode_loaded = false; | 
					
						
							| 
									
										
										
										
											2013-01-24 14:25:36 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	iwl_init_notification_wait(&mvm->notif_wait, &alive_wait, | 
					
						
							|  |  |  | 				   alive_cmd, ARRAY_SIZE(alive_cmd), | 
					
						
							|  |  |  | 				   iwl_alive_fn, &alive_data); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ret = iwl_trans_start_fw(mvm->trans, fw, ucode_type == IWL_UCODE_INIT); | 
					
						
							|  |  |  | 	if (ret) { | 
					
						
							|  |  |  | 		mvm->cur_ucode = old_type; | 
					
						
							|  |  |  | 		iwl_remove_notification(&mvm->notif_wait, &alive_wait); | 
					
						
							|  |  |  | 		return ret; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * Some things may run in the background now, but we | 
					
						
							|  |  |  | 	 * just wait for the ALIVE notification here. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	ret = iwl_wait_notification(&mvm->notif_wait, &alive_wait, | 
					
						
							|  |  |  | 				    MVM_UCODE_ALIVE_TIMEOUT); | 
					
						
							|  |  |  | 	if (ret) { | 
					
						
							|  |  |  | 		mvm->cur_ucode = old_type; | 
					
						
							|  |  |  | 		return ret; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!alive_data.valid) { | 
					
						
							|  |  |  | 		IWL_ERR(mvm, "Loaded ucode is not valid!\n"); | 
					
						
							|  |  |  | 		mvm->cur_ucode = old_type; | 
					
						
							|  |  |  | 		return -EIO; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	iwl_trans_fw_alive(mvm->trans, alive_data.scd_base_addr); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * Note: all the queues are enabled as part of the interface | 
					
						
							|  |  |  | 	 * initialization, but in firmware restart scenarios they | 
					
						
							|  |  |  | 	 * could be stopped, so wake them up. In firmware restart, | 
					
						
							|  |  |  | 	 * mac80211 will have the queues stopped as well until the | 
					
						
							|  |  |  | 	 * reconfiguration completes. During normal startup, they | 
					
						
							|  |  |  | 	 * will be empty. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (i = 0; i < IWL_MAX_HW_QUEUES; i++) { | 
					
						
							| 
									
										
										
										
											2013-09-09 13:30:15 +02:00
										 |  |  | 		if (i < mvm->first_agg_queue && i != IWL_MVM_CMD_QUEUE) | 
					
						
							| 
									
										
										
										
											2013-01-24 14:25:36 +01:00
										 |  |  | 			mvm->queue_to_mac80211[i] = i; | 
					
						
							|  |  |  | 		else | 
					
						
							|  |  |  | 			mvm->queue_to_mac80211[i] = IWL_INVALID_MAC80211_QUEUE; | 
					
						
							|  |  |  | 		atomic_set(&mvm->queue_stop_count[i], 0); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	mvm->transport_queue_stop = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	mvm->ucode_loaded = true; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int iwl_send_phy_cfg_cmd(struct iwl_mvm *mvm) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct iwl_phy_cfg_cmd phy_cfg_cmd; | 
					
						
							|  |  |  | 	enum iwl_ucode_type ucode_type = mvm->cur_ucode; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Set parameters */ | 
					
						
							| 
									
										
										
										
											2013-02-27 15:55:48 +02:00
										 |  |  | 	phy_cfg_cmd.phy_cfg = cpu_to_le32(mvm->fw->phy_config); | 
					
						
							| 
									
										
										
										
											2013-01-24 14:25:36 +01:00
										 |  |  | 	phy_cfg_cmd.calib_control.event_trigger = | 
					
						
							|  |  |  | 		mvm->fw->default_calib[ucode_type].event_trigger; | 
					
						
							|  |  |  | 	phy_cfg_cmd.calib_control.flow_trigger = | 
					
						
							|  |  |  | 		mvm->fw->default_calib[ucode_type].flow_trigger; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	IWL_DEBUG_INFO(mvm, "Sending Phy CFG command: 0x%x\n", | 
					
						
							|  |  |  | 		       phy_cfg_cmd.phy_cfg); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return iwl_mvm_send_cmd_pdu(mvm, PHY_CONFIGURATION_CMD, CMD_SYNC, | 
					
						
							|  |  |  | 				    sizeof(phy_cfg_cmd), &phy_cfg_cmd); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct iwl_notification_wait calib_wait; | 
					
						
							|  |  |  | 	static const u8 init_complete[] = { | 
					
						
							|  |  |  | 		INIT_COMPLETE_NOTIF, | 
					
						
							|  |  |  | 		CALIB_RES_NOTIF_PHY_DB | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | 	int ret; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	lockdep_assert_held(&mvm->mutex); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-24 19:10:46 +02:00
										 |  |  | 	if (WARN_ON_ONCE(mvm->init_ucode_complete)) | 
					
						
							| 
									
										
										
										
											2013-01-24 14:25:36 +01:00
										 |  |  | 		return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	iwl_init_notification_wait(&mvm->notif_wait, | 
					
						
							|  |  |  | 				   &calib_wait, | 
					
						
							|  |  |  | 				   init_complete, | 
					
						
							|  |  |  | 				   ARRAY_SIZE(init_complete), | 
					
						
							|  |  |  | 				   iwl_wait_phy_db_entry, | 
					
						
							|  |  |  | 				   mvm->phy_db); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Will also start the device */ | 
					
						
							|  |  |  | 	ret = iwl_mvm_load_ucode_wait_alive(mvm, IWL_UCODE_INIT); | 
					
						
							|  |  |  | 	if (ret) { | 
					
						
							|  |  |  | 		IWL_ERR(mvm, "Failed to start INIT ucode: %d\n", ret); | 
					
						
							|  |  |  | 		goto error; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-01-17 09:42:25 +02:00
										 |  |  | 	ret = iwl_send_bt_prio_tbl(mvm); | 
					
						
							|  |  |  | 	if (ret) | 
					
						
							|  |  |  | 		goto error; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-09-11 12:39:18 +02:00
										 |  |  | 	/* Read the NVM only at driver load time, no need to do this twice */ | 
					
						
							| 
									
										
										
										
											2013-01-24 14:25:36 +01:00
										 |  |  | 	if (read_nvm) { | 
					
						
							|  |  |  | 		/* Read nvm */ | 
					
						
							|  |  |  | 		ret = iwl_nvm_init(mvm); | 
					
						
							|  |  |  | 		if (ret) { | 
					
						
							|  |  |  | 			IWL_ERR(mvm, "Failed to read NVM: %d\n", ret); | 
					
						
							|  |  |  | 			goto error; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-09-11 12:39:18 +02:00
										 |  |  | 	/* In case we read the NVM from external file, load it to the NIC */ | 
					
						
							|  |  |  | 	if (iwlwifi_mod_params.nvm_file) | 
					
						
							|  |  |  | 		iwl_mvm_load_nvm_to_nic(mvm); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-01-24 14:25:36 +01:00
										 |  |  | 	ret = iwl_nvm_check_version(mvm->nvm_data, mvm->trans); | 
					
						
							|  |  |  | 	WARN_ON(ret); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-13 07:53:26 +03:00
										 |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * abort after reading the nvm in case RF Kill is on, we will complete | 
					
						
							|  |  |  | 	 * the init seq later when RF kill will switch to off | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2013-05-19 19:14:41 +03:00
										 |  |  | 	if (iwl_mvm_is_radio_killed(mvm)) { | 
					
						
							| 
									
										
										
										
											2013-05-13 07:53:26 +03:00
										 |  |  | 		IWL_DEBUG_RF_KILL(mvm, | 
					
						
							|  |  |  | 				  "jump over all phy activities due to RF kill\n"); | 
					
						
							|  |  |  | 		iwl_remove_notification(&mvm->notif_wait, &calib_wait); | 
					
						
							| 
									
										
										
										
											2013-11-24 19:10:46 +02:00
										 |  |  | 		ret = 1; | 
					
						
							|  |  |  | 		goto out; | 
					
						
							| 
									
										
										
										
											2013-05-13 07:53:26 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-27 23:00:27 +02:00
										 |  |  | 	/* Send TX valid antennas before triggering calibrations */ | 
					
						
							| 
									
										
										
										
											2013-03-09 20:38:19 +02:00
										 |  |  | 	ret = iwl_send_tx_ant_cfg(mvm, iwl_fw_valid_tx_ant(mvm->fw)); | 
					
						
							| 
									
										
										
										
											2013-02-27 23:00:27 +02:00
										 |  |  | 	if (ret) | 
					
						
							|  |  |  | 		goto error; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-01-24 14:25:36 +01:00
										 |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * Send phy configurations command to init uCode | 
					
						
							|  |  |  | 	 * to start the 16.0 uCode init image internal calibrations. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	ret = iwl_send_phy_cfg_cmd(mvm); | 
					
						
							|  |  |  | 	if (ret) { | 
					
						
							|  |  |  | 		IWL_ERR(mvm, "Failed to run INIT calibrations: %d\n", | 
					
						
							|  |  |  | 			ret); | 
					
						
							|  |  |  | 		goto error; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * Some things may run in the background now, but we | 
					
						
							|  |  |  | 	 * just wait for the calibration complete notification. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	ret = iwl_wait_notification(&mvm->notif_wait, &calib_wait, | 
					
						
							|  |  |  | 			MVM_UCODE_CALIB_TIMEOUT); | 
					
						
							|  |  |  | 	if (!ret) | 
					
						
							| 
									
										
										
										
											2013-09-03 12:06:11 +03:00
										 |  |  | 		mvm->init_ucode_complete = true; | 
					
						
							| 
									
										
										
										
											2013-01-24 14:25:36 +01:00
										 |  |  | 	goto out; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | error: | 
					
						
							|  |  |  | 	iwl_remove_notification(&mvm->notif_wait, &calib_wait); | 
					
						
							|  |  |  | out: | 
					
						
							| 
									
										
										
										
											2013-11-24 19:10:46 +02:00
										 |  |  | 	if (iwlmvm_mod_params.init_dbg && !mvm->nvm_data) { | 
					
						
							| 
									
										
										
										
											2013-01-24 14:25:36 +01:00
										 |  |  | 		/* we want to debug INIT and we have no NVM - fake */ | 
					
						
							|  |  |  | 		mvm->nvm_data = kzalloc(sizeof(struct iwl_nvm_data) + | 
					
						
							|  |  |  | 					sizeof(struct ieee80211_channel) + | 
					
						
							|  |  |  | 					sizeof(struct ieee80211_rate), | 
					
						
							|  |  |  | 					GFP_KERNEL); | 
					
						
							|  |  |  | 		if (!mvm->nvm_data) | 
					
						
							|  |  |  | 			return -ENOMEM; | 
					
						
							|  |  |  | 		mvm->nvm_data->valid_rx_ant = 1; | 
					
						
							|  |  |  | 		mvm->nvm_data->valid_tx_ant = 1; | 
					
						
							|  |  |  | 		mvm->nvm_data->bands[0].channels = mvm->nvm_data->channels; | 
					
						
							|  |  |  | 		mvm->nvm_data->bands[0].n_channels = 1; | 
					
						
							|  |  |  | 		mvm->nvm_data->bands[0].n_bitrates = 1; | 
					
						
							|  |  |  | 		mvm->nvm_data->bands[0].bitrates = | 
					
						
							|  |  |  | 			(void *)mvm->nvm_data->channels + 1; | 
					
						
							|  |  |  | 		mvm->nvm_data->bands[0].bitrates->hw_value = 10; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define UCODE_CALIB_TIMEOUT	(2*HZ)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int iwl_mvm_up(struct iwl_mvm *mvm) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int ret, i; | 
					
						
							| 
									
										
										
										
											2013-04-28 11:55:08 +03:00
										 |  |  | 	struct ieee80211_channel *chan; | 
					
						
							|  |  |  | 	struct cfg80211_chan_def chandef; | 
					
						
							| 
									
										
										
										
											2013-01-24 14:25:36 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	lockdep_assert_held(&mvm->mutex); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ret = iwl_trans_start_hw(mvm->trans); | 
					
						
							|  |  |  | 	if (ret) | 
					
						
							|  |  |  | 		return ret; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-09-03 12:06:11 +03:00
										 |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * If we haven't completed the run of the init ucode during | 
					
						
							|  |  |  | 	 * module loading, load init ucode now | 
					
						
							|  |  |  | 	 * (for example, if we were in RFKILL) | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	if (!mvm->init_ucode_complete) { | 
					
						
							| 
									
										
										
										
											2013-01-24 14:25:36 +01:00
										 |  |  | 		ret = iwl_run_init_mvm_ucode(mvm, false); | 
					
						
							|  |  |  | 		if (ret && !iwlmvm_mod_params.init_dbg) { | 
					
						
							|  |  |  | 			IWL_ERR(mvm, "Failed to run INIT ucode: %d\n", ret); | 
					
						
							| 
									
										
										
										
											2013-05-13 07:53:26 +03:00
										 |  |  | 			/* this can't happen */ | 
					
						
							|  |  |  | 			if (WARN_ON(ret > 0)) | 
					
						
							|  |  |  | 				ret = -ERFKILL; | 
					
						
							| 
									
										
										
										
											2013-01-24 14:25:36 +01:00
										 |  |  | 			goto error; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2013-11-24 19:10:46 +02:00
										 |  |  | 		if (!iwlmvm_mod_params.init_dbg) { | 
					
						
							|  |  |  | 			/*
 | 
					
						
							|  |  |  | 			 * should stop and start HW since that INIT | 
					
						
							|  |  |  | 			 * image just loaded | 
					
						
							|  |  |  | 			 */ | 
					
						
							|  |  |  | 			iwl_trans_stop_device(mvm->trans); | 
					
						
							|  |  |  | 			ret = iwl_trans_start_hw(mvm->trans); | 
					
						
							|  |  |  | 			if (ret) | 
					
						
							|  |  |  | 				return ret; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2013-01-24 14:25:36 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (iwlmvm_mod_params.init_dbg) | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ret = iwl_mvm_load_ucode_wait_alive(mvm, IWL_UCODE_REGULAR); | 
					
						
							|  |  |  | 	if (ret) { | 
					
						
							|  |  |  | 		IWL_ERR(mvm, "Failed to start RT ucode: %d\n", ret); | 
					
						
							|  |  |  | 		goto error; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-06 13:03:32 +02:00
										 |  |  | 	ret = iwl_mvm_sf_update(mvm, NULL, false); | 
					
						
							|  |  |  | 	if (ret) | 
					
						
							|  |  |  | 		IWL_ERR(mvm, "Failed to initialize Smart Fifo\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-09 20:38:19 +02:00
										 |  |  | 	ret = iwl_send_tx_ant_cfg(mvm, iwl_fw_valid_tx_ant(mvm->fw)); | 
					
						
							| 
									
										
										
										
											2013-01-24 14:25:36 +01:00
										 |  |  | 	if (ret) | 
					
						
							|  |  |  | 		goto error; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-01-17 09:42:25 +02:00
										 |  |  | 	ret = iwl_send_bt_prio_tbl(mvm); | 
					
						
							|  |  |  | 	if (ret) | 
					
						
							|  |  |  | 		goto error; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ret = iwl_send_bt_init_conf(mvm); | 
					
						
							|  |  |  | 	if (ret) | 
					
						
							|  |  |  | 		goto error; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-01-24 14:25:36 +01:00
										 |  |  | 	/* Send phy db control command and then phy db calibration*/ | 
					
						
							|  |  |  | 	ret = iwl_send_phy_db_data(mvm->phy_db); | 
					
						
							|  |  |  | 	if (ret) | 
					
						
							|  |  |  | 		goto error; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ret = iwl_send_phy_cfg_cmd(mvm); | 
					
						
							|  |  |  | 	if (ret) | 
					
						
							|  |  |  | 		goto error; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* init the fw <-> mac80211 STA mapping */ | 
					
						
							|  |  |  | 	for (i = 0; i < IWL_MVM_STATION_COUNT; i++) | 
					
						
							|  |  |  | 		RCU_INIT_POINTER(mvm->fw_id_to_mac_id[i], NULL); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Add auxiliary station for scanning */ | 
					
						
							|  |  |  | 	ret = iwl_mvm_add_aux_sta(mvm); | 
					
						
							|  |  |  | 	if (ret) | 
					
						
							|  |  |  | 		goto error; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-28 11:55:08 +03:00
										 |  |  | 	/* Add all the PHY contexts */ | 
					
						
							|  |  |  | 	chan = &mvm->hw->wiphy->bands[IEEE80211_BAND_2GHZ]->channels[0]; | 
					
						
							|  |  |  | 	cfg80211_chandef_create(&chandef, chan, NL80211_CHAN_NO_HT); | 
					
						
							|  |  |  | 	for (i = 0; i < NUM_PHY_CTX; i++) { | 
					
						
							|  |  |  | 		/*
 | 
					
						
							|  |  |  | 		 * The channel used here isn't relevant as it's | 
					
						
							|  |  |  | 		 * going to be overwritten in the other flows. | 
					
						
							|  |  |  | 		 * For now use the first channel we have. | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		ret = iwl_mvm_phy_ctxt_add(mvm, &mvm->phy_ctxts[i], | 
					
						
							|  |  |  | 					   &chandef, 1, 1); | 
					
						
							|  |  |  | 		if (ret) | 
					
						
							|  |  |  | 			goto error; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2013-01-24 14:25:36 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-09-03 14:18:03 +03:00
										 |  |  | 	ret = iwl_mvm_power_update_device_mode(mvm); | 
					
						
							|  |  |  | 	if (ret) | 
					
						
							|  |  |  | 		goto error; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-28 11:55:08 +03:00
										 |  |  | 	IWL_DEBUG_INFO(mvm, "RT uCode started.\n"); | 
					
						
							| 
									
										
										
										
											2013-01-24 14:25:36 +01:00
										 |  |  | 	return 0; | 
					
						
							|  |  |  |  error: | 
					
						
							|  |  |  | 	iwl_trans_stop_device(mvm->trans); | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int iwl_mvm_load_d3_fw(struct iwl_mvm *mvm) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int ret, i; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	lockdep_assert_held(&mvm->mutex); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ret = iwl_trans_start_hw(mvm->trans); | 
					
						
							|  |  |  | 	if (ret) | 
					
						
							|  |  |  | 		return ret; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ret = iwl_mvm_load_ucode_wait_alive(mvm, IWL_UCODE_WOWLAN); | 
					
						
							|  |  |  | 	if (ret) { | 
					
						
							|  |  |  | 		IWL_ERR(mvm, "Failed to start WoWLAN firmware: %d\n", ret); | 
					
						
							|  |  |  | 		goto error; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-09 20:38:19 +02:00
										 |  |  | 	ret = iwl_send_tx_ant_cfg(mvm, iwl_fw_valid_tx_ant(mvm->fw)); | 
					
						
							| 
									
										
										
										
											2013-01-24 14:25:36 +01:00
										 |  |  | 	if (ret) | 
					
						
							|  |  |  | 		goto error; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Send phy db control command and then phy db calibration*/ | 
					
						
							|  |  |  | 	ret = iwl_send_phy_db_data(mvm->phy_db); | 
					
						
							|  |  |  | 	if (ret) | 
					
						
							|  |  |  | 		goto error; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ret = iwl_send_phy_cfg_cmd(mvm); | 
					
						
							|  |  |  | 	if (ret) | 
					
						
							|  |  |  | 		goto error; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* init the fw <-> mac80211 STA mapping */ | 
					
						
							|  |  |  | 	for (i = 0; i < IWL_MVM_STATION_COUNT; i++) | 
					
						
							|  |  |  | 		RCU_INIT_POINTER(mvm->fw_id_to_mac_id[i], NULL); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Add auxiliary station for scanning */ | 
					
						
							|  |  |  | 	ret = iwl_mvm_add_aux_sta(mvm); | 
					
						
							|  |  |  | 	if (ret) | 
					
						
							|  |  |  | 		goto error; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  |  error: | 
					
						
							|  |  |  | 	iwl_trans_stop_device(mvm->trans); | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int iwl_mvm_rx_card_state_notif(struct iwl_mvm *mvm, | 
					
						
							|  |  |  | 				    struct iwl_rx_cmd_buffer *rxb, | 
					
						
							|  |  |  | 				    struct iwl_device_cmd *cmd) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct iwl_rx_packet *pkt = rxb_addr(rxb); | 
					
						
							|  |  |  | 	struct iwl_card_state_notif *card_state_notif = (void *)pkt->data; | 
					
						
							|  |  |  | 	u32 flags = le32_to_cpu(card_state_notif->flags); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	IWL_DEBUG_RF_KILL(mvm, "Card state received: HW:%s SW:%s CT:%s\n", | 
					
						
							|  |  |  | 			  (flags & HW_CARD_DISABLED) ? "Kill" : "On", | 
					
						
							|  |  |  | 			  (flags & SW_CARD_DISABLED) ? "Kill" : "On", | 
					
						
							|  |  |  | 			  (flags & CT_KILL_CARD_DISABLED) ? | 
					
						
							|  |  |  | 			  "Reached" : "Not reached"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int iwl_mvm_rx_radio_ver(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, | 
					
						
							|  |  |  | 			 struct iwl_device_cmd *cmd) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct iwl_rx_packet *pkt = rxb_addr(rxb); | 
					
						
							|  |  |  | 	struct iwl_radio_version_notif *radio_version = (void *)pkt->data; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* TODO: what to do with that? */ | 
					
						
							|  |  |  | 	IWL_DEBUG_INFO(mvm, | 
					
						
							|  |  |  | 		       "Radio version: flavor: 0x%08x, step 0x%08x, dash 0x%08x\n", | 
					
						
							|  |  |  | 		       le32_to_cpu(radio_version->radio_flavor), | 
					
						
							|  |  |  | 		       le32_to_cpu(radio_version->radio_step), | 
					
						
							|  |  |  | 		       le32_to_cpu(radio_version->radio_dash)); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } |