diff options
| author | John W. Linville <linville@tuxdriver.com> | 2012-03-05 15:05:54 -0500 | 
|---|---|---|
| committer | John W. Linville <linville@tuxdriver.com> | 2012-03-05 15:05:54 -0500 | 
| commit | 051d3b50430160a86cbe4a2deef219c8038bd03f (patch) | |
| tree | b2c276067819f259f86369e5341202332a8172be /drivers/net/wireless/iwlwifi/iwl-testmode.c | |
| parent | ffcb97388b1d41b1db063eb041cb9af408662127 (diff) | |
| parent | c288ec614e264b46853c65d3db9ccf91d53c9484 (diff) | |
| download | olio-linux-3.10-051d3b50430160a86cbe4a2deef219c8038bd03f.tar.xz olio-linux-3.10-051d3b50430160a86cbe4a2deef219c8038bd03f.zip  | |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next into for-davem
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-testmode.c')
| -rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-testmode.c | 432 | 
1 files changed, 249 insertions, 183 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-testmode.c b/drivers/net/wireless/iwlwifi/iwl-testmode.c index df7ab332c83..23eea06a74a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-testmode.c +++ b/drivers/net/wireless/iwlwifi/iwl-testmode.c @@ -78,9 +78,15 @@  #include "iwl-agn.h"  #include "iwl-testmode.h"  #include "iwl-trans.h" -#include "iwl-bus.h"  #include "iwl-fh.h" + +/* Periphery registers absolute lower bound. This is used in order to + * differentiate registery access through HBUS_TARG_PRPH_* and + * HBUS_TARG_MEM_* accesses. + */ +#define IWL_TM_ABS_PRPH_START (0xA00000) +  /* The TLVs used in the gnl message policy between the kernel module and   * user space application. iwl_testmode_gnl_msg_policy is to be carried   * through the NL80211_CMD_TESTMODE channel regulated by nl80211. @@ -110,9 +116,9 @@ struct nla_policy iwl_testmode_gnl_msg_policy[IWL_TM_ATTR_MAX] = {  	[IWL_TM_ATTR_UCODE_OWNER] = { .type = NLA_U8, }, -	[IWL_TM_ATTR_SRAM_ADDR] = { .type = NLA_U32, }, -	[IWL_TM_ATTR_SRAM_SIZE] = { .type = NLA_U32, }, -	[IWL_TM_ATTR_SRAM_DUMP] = { .type = NLA_UNSPEC, }, +	[IWL_TM_ATTR_MEM_ADDR] = { .type = NLA_U32, }, +	[IWL_TM_ATTR_BUFFER_SIZE] = { .type = NLA_U32, }, +	[IWL_TM_ATTR_BUFFER_DUMP] = { .type = NLA_UNSPEC, },  	[IWL_TM_ATTR_FW_VERSION] = { .type = NLA_U32, },  	[IWL_TM_ATTR_DEVICE_ID] = { .type = NLA_U32, }, @@ -172,7 +178,7 @@ static void iwl_testmode_ucode_rx_pkt(struct iwl_priv *priv,  	skb = cfg80211_testmode_alloc_event_skb(hw->wiphy, 20 + length,  								GFP_ATOMIC);  	if (skb == NULL) { -		IWL_DEBUG_INFO(priv, +		IWL_ERR(priv,  			 "Run out of memory for messages to user space ?\n");  		return;  	} @@ -183,24 +189,24 @@ static void iwl_testmode_ucode_rx_pkt(struct iwl_priv *priv,  nla_put_failure:  	kfree_skb(skb); -	IWL_DEBUG_INFO(priv, "Ouch, overran buffer, check allocation!\n"); +	IWL_ERR(priv, "Ouch, overran buffer, check allocation!\n");  }  void iwl_testmode_init(struct iwl_priv *priv)  {  	priv->pre_rx_handler = iwl_testmode_ucode_rx_pkt;  	priv->testmode_trace.trace_enabled = false; -	priv->testmode_sram.sram_readed = false; +	priv->testmode_mem.read_in_progress = false;  } -static void iwl_sram_cleanup(struct iwl_priv *priv) +static void iwl_mem_cleanup(struct iwl_priv *priv)  { -	if (priv->testmode_sram.sram_readed) { -		kfree(priv->testmode_sram.buff_addr); -		priv->testmode_sram.buff_addr = NULL; -		priv->testmode_sram.buff_size = 0; -		priv->testmode_sram.num_chunks = 0; -		priv->testmode_sram.sram_readed = false; +	if (priv->testmode_mem.read_in_progress) { +		kfree(priv->testmode_mem.buff_addr); +		priv->testmode_mem.buff_addr = NULL; +		priv->testmode_mem.buff_size = 0; +		priv->testmode_mem.num_chunks = 0; +		priv->testmode_mem.read_in_progress = false;  	}  } @@ -226,9 +232,10 @@ static void iwl_trace_cleanup(struct iwl_priv *priv)  void iwl_testmode_cleanup(struct iwl_priv *priv)  {  	iwl_trace_cleanup(priv); -	iwl_sram_cleanup(priv); +	iwl_mem_cleanup(priv);  } +  /*   * This function handles the user application commands to the ucode.   * @@ -237,35 +244,80 @@ void iwl_testmode_cleanup(struct iwl_priv *priv)   * host command to the ucode.   *   * If any mandatory field is missing, -ENOMSG is replied to the user space - * application; otherwise, the actual execution result of the host command to - * ucode is replied. + * application; otherwise, waits for the host command to be sent and checks + * the return code. In case or error, it is returned, otherwise a reply is + * allocated and the reply RX packet + * is returned.   *   * @hw: ieee80211_hw object that represents the device   * @tb: gnl message fields from the user space   */  static int iwl_testmode_ucode(struct ieee80211_hw *hw, struct nlattr **tb)  { -	struct iwl_priv *priv = hw->priv; +	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);  	struct iwl_host_cmd cmd; +	struct iwl_rx_packet *pkt; +	struct sk_buff *skb; +	void *reply_buf; +	u32 reply_len; +	int ret; +	bool cmd_want_skb;  	memset(&cmd, 0, sizeof(struct iwl_host_cmd));  	if (!tb[IWL_TM_ATTR_UCODE_CMD_ID] ||  	    !tb[IWL_TM_ATTR_UCODE_CMD_DATA]) { -		IWL_DEBUG_INFO(priv, -			"Error finding ucode command mandatory fields\n"); +		IWL_ERR(priv, "Missing ucode command mandatory fields\n");  		return -ENOMSG;  	} -	cmd.flags = CMD_ON_DEMAND; +	cmd.flags = CMD_ON_DEMAND | CMD_SYNC; +	cmd_want_skb = nla_get_flag(tb[IWL_TM_ATTR_UCODE_CMD_SKB]); +	if (cmd_want_skb) +		cmd.flags |= CMD_WANT_SKB; +  	cmd.id = nla_get_u8(tb[IWL_TM_ATTR_UCODE_CMD_ID]);  	cmd.data[0] = nla_data(tb[IWL_TM_ATTR_UCODE_CMD_DATA]);  	cmd.len[0] = nla_len(tb[IWL_TM_ATTR_UCODE_CMD_DATA]);  	cmd.dataflags[0] = IWL_HCMD_DFL_NOCOPY; -	IWL_INFO(priv, "testmode ucode command ID 0x%x, flags 0x%x," +	IWL_DEBUG_INFO(priv, "testmode ucode command ID 0x%x, flags 0x%x,"  				" len %d\n", cmd.id, cmd.flags, cmd.len[0]); -	/* ok, let's submit the command to ucode */ -	return iwl_trans_send_cmd(trans(priv), &cmd); + +	ret = iwl_trans_send_cmd(trans(priv), &cmd); +	if (ret) { +		IWL_ERR(priv, "Failed to send hcmd\n"); +		return ret; +	} +	if (!cmd_want_skb) +		return ret; + +	/* Handling return of SKB to the user */ +	pkt = (struct iwl_rx_packet *)cmd.reply_page; +	if (!pkt) { +		IWL_ERR(priv, "HCMD received a null response packet\n"); +		return ret; +	} + +	reply_len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK; +	skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, reply_len + 20); +	reply_buf = kmalloc(reply_len, GFP_KERNEL); +	if (!skb || !reply_buf) { +		kfree_skb(skb); +		kfree(reply_buf); +		return -ENOMEM; +	} + +	/* The reply is in a page, that we cannot send to user space. */ +	memcpy(reply_buf, &(pkt->hdr), reply_len); +	iwl_free_pages(priv->shrd, cmd.reply_page); + +	NLA_PUT_U32(skb, IWL_TM_ATTR_COMMAND, IWL_TM_CMD_DEV2APP_UCODE_RX_PKT); +	NLA_PUT(skb, IWL_TM_ATTR_UCODE_RX_PKT, reply_len, reply_buf); +	return cfg80211_testmode_reply(skb); + +nla_put_failure: +	IWL_DEBUG_INFO(priv, "Failed creating NL attributes\n"); +	return -ENOMSG;  } @@ -288,14 +340,14 @@ static int iwl_testmode_ucode(struct ieee80211_hw *hw, struct nlattr **tb)   */  static int iwl_testmode_reg(struct ieee80211_hw *hw, struct nlattr **tb)  { -	struct iwl_priv *priv = hw->priv; +	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);  	u32 ofs, val32, cmd;  	u8 val8;  	struct sk_buff *skb;  	int status = 0;  	if (!tb[IWL_TM_ATTR_REG_OFFSET]) { -		IWL_DEBUG_INFO(priv, "Error finding register offset\n"); +		IWL_ERR(priv, "Missing register offset\n");  		return -ENOMSG;  	}  	ofs = nla_get_u32(tb[IWL_TM_ATTR_REG_OFFSET]); @@ -309,7 +361,7 @@ static int iwl_testmode_reg(struct ieee80211_hw *hw, struct nlattr **tb)  		cmd == IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE32 ||  		cmd == IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE8) &&  		(ofs >= FH_MEM_UPPER_BOUND)) { -		IWL_DEBUG_INFO(priv, "offset out of segment (0x0 - 0x%x)\n", +		IWL_ERR(priv, "offset out of segment (0x0 - 0x%x)\n",  			FH_MEM_UPPER_BOUND);  		return -EINVAL;  	} @@ -321,19 +373,17 @@ static int iwl_testmode_reg(struct ieee80211_hw *hw, struct nlattr **tb)  		skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20);  		if (!skb) { -			IWL_DEBUG_INFO(priv, "Error allocating memory\n"); +			IWL_ERR(priv, "Memory allocation fail\n");  			return -ENOMEM;  		}  		NLA_PUT_U32(skb, IWL_TM_ATTR_REG_VALUE32, val32);  		status = cfg80211_testmode_reply(skb);  		if (status < 0) -			IWL_DEBUG_INFO(priv, -				       "Error sending msg : %d\n", status); +			IWL_ERR(priv, "Error sending msg : %d\n", status);  		break;  	case IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE32:  		if (!tb[IWL_TM_ATTR_REG_VALUE32]) { -			IWL_DEBUG_INFO(priv, -				       "Error finding value to write\n"); +			IWL_ERR(priv, "Missing value to write\n");  			return -ENOMSG;  		} else {  			val32 = nla_get_u32(tb[IWL_TM_ATTR_REG_VALUE32]); @@ -343,7 +393,7 @@ static int iwl_testmode_reg(struct ieee80211_hw *hw, struct nlattr **tb)  		break;  	case IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE8:  		if (!tb[IWL_TM_ATTR_REG_VALUE8]) { -			IWL_DEBUG_INFO(priv, "Error finding value to write\n"); +			IWL_ERR(priv, "Missing value to write\n");  			return -ENOMSG;  		} else {  			val8 = nla_get_u8(tb[IWL_TM_ATTR_REG_VALUE8]); @@ -351,34 +401,8 @@ static int iwl_testmode_reg(struct ieee80211_hw *hw, struct nlattr **tb)  			iwl_write8(trans(priv), ofs, val8);  		}  		break; -	case IWL_TM_CMD_APP2DEV_INDIRECT_REG_READ32: -		val32 = iwl_read_prph(trans(priv), ofs); -		IWL_INFO(priv, "32bit value to read 0x%x\n", val32); - -		skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20); -		if (!skb) { -			IWL_DEBUG_INFO(priv, "Error allocating memory\n"); -			return -ENOMEM; -		} -		NLA_PUT_U32(skb, IWL_TM_ATTR_REG_VALUE32, val32); -		status = cfg80211_testmode_reply(skb); -		if (status < 0) -			IWL_DEBUG_INFO(priv, -					"Error sending msg : %d\n", status); -		break; -	case IWL_TM_CMD_APP2DEV_INDIRECT_REG_WRITE32: -		if (!tb[IWL_TM_ATTR_REG_VALUE32]) { -			IWL_DEBUG_INFO(priv, -					"Error finding value to write\n"); -			return -ENOMSG; -		} else { -			val32 = nla_get_u32(tb[IWL_TM_ATTR_REG_VALUE32]); -			IWL_INFO(priv, "32bit value to write 0x%x\n", val32); -			iwl_write_prph(trans(priv), ofs, val32); -		} -		break;  	default: -		IWL_DEBUG_INFO(priv, "Unknown testmode register command ID\n"); +		IWL_ERR(priv, "Unknown testmode register command ID\n");  		return -ENOSYS;  	} @@ -400,14 +424,13 @@ static int iwl_testmode_cfg_init_calib(struct iwl_priv *priv)  				      NULL, NULL);  	ret = iwl_init_alive_start(trans(priv));  	if (ret) { -		IWL_DEBUG_INFO(priv, -			"Error configuring init calibration: %d\n", ret); +		IWL_ERR(priv, "Fail init calibration: %d\n", ret);  		goto cfg_init_calib_error;  	}  	ret = iwl_wait_notification(priv->shrd, &calib_wait, 2 * HZ);  	if (ret) -		IWL_DEBUG_INFO(priv, "Error detecting" +		IWL_ERR(priv, "Error detecting"  			" CALIBRATION_COMPLETE_NOTIFICATION: %d\n", ret);  	return ret; @@ -434,7 +457,7 @@ cfg_init_calib_error:   */  static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb)  { -	struct iwl_priv *priv = hw->priv; +	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);  	struct iwl_trans *trans = trans(priv);  	struct sk_buff *skb;  	unsigned char *rsp_data_ptr = NULL; @@ -448,8 +471,7 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb)  		skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy,  							rsp_data_len + 20);  		if (!skb) { -			IWL_DEBUG_INFO(priv, -				       "Error allocating memory\n"); +			IWL_ERR(priv, "Memory allocation fail\n");  			return -ENOMEM;  		}  		NLA_PUT_U32(skb, IWL_TM_ATTR_COMMAND, @@ -458,15 +480,13 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb)  			rsp_data_len, rsp_data_ptr);  		status = cfg80211_testmode_reply(skb);  		if (status < 0) -			IWL_DEBUG_INFO(priv, "Error sending msg : %d\n", -				       status); +			IWL_ERR(priv, "Error sending msg : %d\n", status);  		break;  	case IWL_TM_CMD_APP2DEV_LOAD_INIT_FW:  		status = iwl_load_ucode_wait_alive(trans, IWL_UCODE_INIT);  		if (status) -			IWL_DEBUG_INFO(priv, -				"Error loading init ucode: %d\n", status); +			IWL_ERR(priv, "Error loading init ucode: %d\n", status);  		break;  	case IWL_TM_CMD_APP2DEV_CFG_INIT_CALIB: @@ -477,13 +497,13 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb)  	case IWL_TM_CMD_APP2DEV_LOAD_RUNTIME_FW:  		status = iwl_load_ucode_wait_alive(trans, IWL_UCODE_REGULAR);  		if (status) { -			IWL_DEBUG_INFO(priv, +			IWL_ERR(priv,  				"Error loading runtime ucode: %d\n", status);  			break;  		}  		status = iwl_alive_start(priv);  		if (status) -			IWL_DEBUG_INFO(priv, +			IWL_ERR(priv,  				"Error starting the device: %d\n", status);  		break; @@ -492,13 +512,13 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb)  		iwl_trans_stop_device(trans);  		status = iwl_load_ucode_wait_alive(trans, IWL_UCODE_WOWLAN);  		if (status) { -			IWL_DEBUG_INFO(priv, +			IWL_ERR(priv,  				"Error loading WOWLAN ucode: %d\n", status);  			break;  		}  		status = iwl_alive_start(priv);  		if (status) -			IWL_DEBUG_INFO(priv, +			IWL_ERR(priv,  				"Error starting the device: %d\n", status);  		break; @@ -507,8 +527,7 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb)  			skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy,  				cfg(priv)->base_params->eeprom_size + 20);  			if (!skb) { -				IWL_DEBUG_INFO(priv, -				       "Error allocating memory\n"); +				IWL_ERR(priv, "Memory allocation fail\n");  				return -ENOMEM;  			}  			NLA_PUT_U32(skb, IWL_TM_ATTR_COMMAND, @@ -518,35 +537,34 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb)  				priv->shrd->eeprom);  			status = cfg80211_testmode_reply(skb);  			if (status < 0) -				IWL_DEBUG_INFO(priv, -					       "Error sending msg : %d\n", -					       status); +				IWL_ERR(priv, "Error sending msg : %d\n", +					status);  		} else  			return -EFAULT;  		break;  	case IWL_TM_CMD_APP2DEV_FIXRATE_REQ:  		if (!tb[IWL_TM_ATTR_FIXRATE]) { -			IWL_DEBUG_INFO(priv, -				       "Error finding fixrate setting\n"); +			IWL_ERR(priv, "Missing fixrate setting\n");  			return -ENOMSG;  		}  		priv->tm_fixed_rate = nla_get_u32(tb[IWL_TM_ATTR_FIXRATE]);  		break;  	case IWL_TM_CMD_APP2DEV_GET_FW_VERSION: -		IWL_INFO(priv, "uCode version raw: 0x%x\n", priv->ucode_ver); +		IWL_INFO(priv, "uCode version raw: 0x%x\n", +			 nic(priv)->fw.ucode_ver);  		skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20);  		if (!skb) { -			IWL_DEBUG_INFO(priv, "Error allocating memory\n"); +			IWL_ERR(priv, "Memory allocation fail\n");  			return -ENOMEM;  		} -		NLA_PUT_U32(skb, IWL_TM_ATTR_FW_VERSION, priv->ucode_ver); +		NLA_PUT_U32(skb, IWL_TM_ATTR_FW_VERSION, +			    nic(priv)->fw.ucode_ver);  		status = cfg80211_testmode_reply(skb);  		if (status < 0) -			IWL_DEBUG_INFO(priv, -					"Error sending msg : %d\n", status); +			IWL_ERR(priv, "Error sending msg : %d\n", status);  		break;  	case IWL_TM_CMD_APP2DEV_GET_DEVICE_ID: @@ -555,40 +573,39 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb)  		skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20);  		if (!skb) { -			IWL_DEBUG_INFO(priv, "Error allocating memory\n"); +			IWL_ERR(priv, "Memory allocation fail\n");  			return -ENOMEM;  		}  		NLA_PUT_U32(skb, IWL_TM_ATTR_DEVICE_ID, devid);  		status = cfg80211_testmode_reply(skb);  		if (status < 0) -			IWL_DEBUG_INFO(priv, -					"Error sending msg : %d\n", status); +			IWL_ERR(priv, "Error sending msg : %d\n", status);  		break;  	case IWL_TM_CMD_APP2DEV_GET_FW_INFO:  		skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20 + 8);  		if (!skb) { -			IWL_DEBUG_INFO(priv, "Error allocating memory\n"); +			IWL_ERR(priv, "Memory allocation fail\n");  			return -ENOMEM;  		}  		switch (priv->shrd->ucode_type) {  		case IWL_UCODE_REGULAR: -			inst_size = trans(priv)->ucode_rt.code.len; -			data_size = trans(priv)->ucode_rt.data.len; +			inst_size = nic(priv)->fw.ucode_rt.code.len; +			data_size = nic(priv)->fw.ucode_rt.data.len;  			break;  		case IWL_UCODE_INIT: -			inst_size = trans(priv)->ucode_init.code.len; -			data_size = trans(priv)->ucode_init.data.len; +			inst_size = nic(priv)->fw.ucode_init.code.len; +			data_size = nic(priv)->fw.ucode_init.data.len;  			break;  		case IWL_UCODE_WOWLAN: -			inst_size = trans(priv)->ucode_wowlan.code.len; -			data_size = trans(priv)->ucode_wowlan.data.len; +			inst_size = nic(priv)->fw.ucode_wowlan.code.len; +			data_size = nic(priv)->fw.ucode_wowlan.data.len;  			break;  		case IWL_UCODE_NONE: -			IWL_DEBUG_INFO(priv, "The uCode has not been loaded\n"); +			IWL_ERR(priv, "No uCode has not been loaded\n");  			break;  		default: -			IWL_DEBUG_INFO(priv, "Unsupported uCode type\n"); +			IWL_ERR(priv, "Unsupported uCode type\n");  			break;  		}  		NLA_PUT_U32(skb, IWL_TM_ATTR_FW_TYPE, priv->shrd->ucode_type); @@ -596,12 +613,11 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb)  		NLA_PUT_U32(skb, IWL_TM_ATTR_FW_DATA_SIZE, data_size);  		status = cfg80211_testmode_reply(skb);  		if (status < 0) -			IWL_DEBUG_INFO(priv, -					"Error sending msg : %d\n", status); +			IWL_ERR(priv, "Error sending msg : %d\n", status);  		break;  	default: -		IWL_DEBUG_INFO(priv, "Unknown testmode driver command ID\n"); +		IWL_ERR(priv, "Unknown testmode driver command ID\n");  		return -ENOSYS;  	}  	return status; @@ -626,7 +642,7 @@ nla_put_failure:   */  static int iwl_testmode_trace(struct ieee80211_hw *hw, struct nlattr **tb)  { -	struct iwl_priv *priv = hw->priv; +	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);  	struct sk_buff *skb;  	int status = 0;  	struct device *dev = trans(priv)->dev; @@ -664,8 +680,7 @@ static int iwl_testmode_trace(struct ieee80211_hw *hw, struct nlattr **tb)  		skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy,  			sizeof(priv->testmode_trace.dma_addr) + 20);  		if (!skb) { -			IWL_DEBUG_INFO(priv, -				"Error allocating memory\n"); +			IWL_ERR(priv, "Memory allocation fail\n");  			iwl_trace_cleanup(priv);  			return -ENOMEM;  		} @@ -674,9 +689,7 @@ static int iwl_testmode_trace(struct ieee80211_hw *hw, struct nlattr **tb)  			(u64 *)&priv->testmode_trace.dma_addr);  		status = cfg80211_testmode_reply(skb);  		if (status < 0) { -			IWL_DEBUG_INFO(priv, -				       "Error sending msg : %d\n", -				       status); +			IWL_ERR(priv, "Error sending msg : %d\n", status);  		}  		priv->testmode_trace.num_chunks =  			DIV_ROUND_UP(priv->testmode_trace.buff_size, @@ -687,7 +700,7 @@ static int iwl_testmode_trace(struct ieee80211_hw *hw, struct nlattr **tb)  		iwl_trace_cleanup(priv);  		break;  	default: -		IWL_DEBUG_INFO(priv, "Unknown testmode mem command ID\n"); +		IWL_ERR(priv, "Unknown testmode mem command ID\n");  		return -ENOSYS;  	}  	return status; @@ -704,7 +717,7 @@ static int iwl_testmode_trace_dump(struct ieee80211_hw *hw, struct nlattr **tb,  				   struct sk_buff *skb,  				   struct netlink_callback *cb)  { -	struct iwl_priv *priv = hw->priv; +	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);  	int idx, length;  	if (priv->testmode_trace.trace_enabled && @@ -748,11 +761,11 @@ static int iwl_testmode_trace_dump(struct ieee80211_hw *hw, struct nlattr **tb,   */  static int iwl_testmode_ownership(struct ieee80211_hw *hw, struct nlattr **tb)  { -	struct iwl_priv *priv = hw->priv; +	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);  	u8 owner;  	if (!tb[IWL_TM_ATTR_UCODE_OWNER]) { -		IWL_DEBUG_INFO(priv, "Error finding ucode owner\n"); +		IWL_ERR(priv, "Missing ucode owner\n");  		return -ENOMSG;  	} @@ -760,12 +773,89 @@ static int iwl_testmode_ownership(struct ieee80211_hw *hw, struct nlattr **tb)  	if ((owner == IWL_OWNERSHIP_DRIVER) || (owner == IWL_OWNERSHIP_TM))  		priv->shrd->ucode_owner = owner;  	else { -		IWL_DEBUG_INFO(priv, "Invalid owner\n"); +		IWL_ERR(priv, "Invalid owner\n");  		return -EINVAL;  	}  	return 0;  } +static int iwl_testmode_indirect_read(struct iwl_priv *priv, u32 addr, u32 size) +{ +	struct iwl_trans *trans = trans(priv); +	unsigned long flags; +	int i; + +	if (size & 0x3) +		return -EINVAL; +	priv->testmode_mem.buff_size = size; +	priv->testmode_mem.buff_addr = +		kmalloc(priv->testmode_mem.buff_size, GFP_KERNEL); +	if (priv->testmode_mem.buff_addr == NULL) +		return -ENOMEM; + +	/* Hard-coded periphery absolute address */ +	if (IWL_TM_ABS_PRPH_START <= addr && +		addr < IWL_TM_ABS_PRPH_START + PRPH_END) { +			spin_lock_irqsave(&trans->reg_lock, flags); +			iwl_grab_nic_access(trans); +			iwl_write32(trans, HBUS_TARG_PRPH_RADDR, +				addr | (3 << 24)); +			for (i = 0; i < size; i += 4) +				*(u32 *)(priv->testmode_mem.buff_addr + i) = +					iwl_read32(trans, HBUS_TARG_PRPH_RDAT); +			iwl_release_nic_access(trans); +			spin_unlock_irqrestore(&trans->reg_lock, flags); +	} else { /* target memory (SRAM) */ +		_iwl_read_targ_mem_words(trans, addr, +			priv->testmode_mem.buff_addr, +			priv->testmode_mem.buff_size / 4); +	} + +	priv->testmode_mem.num_chunks = +		DIV_ROUND_UP(priv->testmode_mem.buff_size, DUMP_CHUNK_SIZE); +	priv->testmode_mem.read_in_progress = true; +	return 0; + +} + +static int iwl_testmode_indirect_write(struct iwl_priv *priv, u32 addr, +	u32 size, unsigned char *buf) +{ +	struct iwl_trans *trans = trans(priv); +	u32 val, i; +	unsigned long flags; + +	if (IWL_TM_ABS_PRPH_START <= addr && +		addr < IWL_TM_ABS_PRPH_START + PRPH_END) { +			/* Periphery writes can be 1-3 bytes long, or DWORDs */ +			if (size < 4) { +				memcpy(&val, buf, size); +				spin_lock_irqsave(&trans->reg_lock, flags); +				iwl_grab_nic_access(trans); +				iwl_write32(trans, HBUS_TARG_PRPH_WADDR, +					    (addr & 0x0000FFFF) | +					    ((size - 1) << 24)); +				iwl_write32(trans, HBUS_TARG_PRPH_WDAT, val); +				iwl_release_nic_access(trans); +				/* needed after consecutive writes w/o read */ +				mmiowb(); +				spin_unlock_irqrestore(&trans->reg_lock, flags); +			} else { +				if (size % 4) +					return -EINVAL; +				for (i = 0; i < size; i += 4) +					iwl_write_prph(trans, addr+i, +						*(u32 *)(buf+i)); +			} +	} else if (iwlagn_hw_valid_rtc_data_addr(addr) || +		(IWLAGN_RTC_INST_LOWER_BOUND <= addr && +		addr < IWLAGN_RTC_INST_UPPER_BOUND)) { +			_iwl_write_targ_mem_words(trans, addr, buf, size/4); +	} else +		return -EINVAL; +	return 0; +} +  /*   * This function handles the user application commands for SRAM data dump   * @@ -782,82 +872,60 @@ static int iwl_testmode_ownership(struct ieee80211_hw *hw, struct nlattr **tb)   * @hw: ieee80211_hw object that represents the device   * @tb: gnl message fields from the user space   */ -static int iwl_testmode_sram(struct ieee80211_hw *hw, struct nlattr **tb) +static int iwl_testmode_indirect_mem(struct ieee80211_hw *hw, +	struct nlattr **tb)  { -	struct iwl_priv *priv = hw->priv; -	u32 ofs, size, maxsize; +	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); +	u32 addr, size, cmd; +	unsigned char *buf; -	if (priv->testmode_sram.sram_readed) +	/* Both read and write should be blocked, for atomicity */ +	if (priv->testmode_mem.read_in_progress)  		return -EBUSY; -	if (!tb[IWL_TM_ATTR_SRAM_ADDR]) { -		IWL_DEBUG_INFO(priv, "Error finding SRAM offset address\n"); +	cmd = nla_get_u32(tb[IWL_TM_ATTR_COMMAND]); +	if (!tb[IWL_TM_ATTR_MEM_ADDR]) { +		IWL_ERR(priv, "Error finding memory offset address\n");  		return -ENOMSG;  	} -	ofs = nla_get_u32(tb[IWL_TM_ATTR_SRAM_ADDR]); -	if (!tb[IWL_TM_ATTR_SRAM_SIZE]) { -		IWL_DEBUG_INFO(priv, "Error finding size for SRAM reading\n"); +	addr = nla_get_u32(tb[IWL_TM_ATTR_MEM_ADDR]); +	if (!tb[IWL_TM_ATTR_BUFFER_SIZE]) { +		IWL_ERR(priv, "Error finding size for memory reading\n");  		return -ENOMSG;  	} -	size = nla_get_u32(tb[IWL_TM_ATTR_SRAM_SIZE]); -	switch (priv->shrd->ucode_type) { -	case IWL_UCODE_REGULAR: -		maxsize = trans(priv)->ucode_rt.data.len; -		break; -	case IWL_UCODE_INIT: -		maxsize = trans(priv)->ucode_init.data.len; -		break; -	case IWL_UCODE_WOWLAN: -		maxsize = trans(priv)->ucode_wowlan.data.len; -		break; -	case IWL_UCODE_NONE: -		IWL_ERR(priv, "Error, uCode does not been loaded\n"); -		return -ENOSYS; -	default: -		IWL_ERR(priv, "Error, unsupported uCode type\n"); -		return -ENOSYS; -	} -	if ((ofs + size) > (maxsize + SRAM_DATA_SEG_OFFSET)) { -		IWL_ERR(priv, "Invalid offset/size: out of range\n"); -		return -EINVAL; -	} -	priv->testmode_sram.buff_size = (size / 4) * 4; -	priv->testmode_sram.buff_addr = -		kmalloc(priv->testmode_sram.buff_size, GFP_KERNEL); -	if (priv->testmode_sram.buff_addr == NULL) { -		IWL_ERR(priv, "Error allocating memory\n"); -		return -ENOMEM; +	size = nla_get_u32(tb[IWL_TM_ATTR_BUFFER_SIZE]); + +	if (cmd == IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_READ) +		return iwl_testmode_indirect_read(priv, addr,  size); +	else { +		if (!tb[IWL_TM_ATTR_BUFFER_DUMP]) +			return -EINVAL; +		buf = (unsigned char *) nla_data(tb[IWL_TM_ATTR_BUFFER_DUMP]); +		return iwl_testmode_indirect_write(priv, addr, size, buf);  	} -	_iwl_read_targ_mem_words(trans(priv), ofs, -					priv->testmode_sram.buff_addr, -					priv->testmode_sram.buff_size / 4); -	priv->testmode_sram.num_chunks = -		DIV_ROUND_UP(priv->testmode_sram.buff_size, DUMP_CHUNK_SIZE); -	priv->testmode_sram.sram_readed = true; -	return 0;  } -static int iwl_testmode_sram_dump(struct ieee80211_hw *hw, struct nlattr **tb, +static int iwl_testmode_buffer_dump(struct ieee80211_hw *hw, struct nlattr **tb,  				   struct sk_buff *skb,  				   struct netlink_callback *cb)  { -	struct iwl_priv *priv = hw->priv; +	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);  	int idx, length; -	if (priv->testmode_sram.sram_readed) { +	if (priv->testmode_mem.read_in_progress) {  		idx = cb->args[4]; -		if (idx >= priv->testmode_sram.num_chunks) { -			iwl_sram_cleanup(priv); +		if (idx >= priv->testmode_mem.num_chunks) { +			iwl_mem_cleanup(priv);  			return -ENOENT;  		}  		length = DUMP_CHUNK_SIZE; -		if (((idx + 1) == priv->testmode_sram.num_chunks) && -		    (priv->testmode_sram.buff_size % DUMP_CHUNK_SIZE)) -			length = priv->testmode_sram.buff_size % +		if (((idx + 1) == priv->testmode_mem.num_chunks) && +		    (priv->testmode_mem.buff_size % DUMP_CHUNK_SIZE)) +			length = priv->testmode_mem.buff_size %  				DUMP_CHUNK_SIZE; -		NLA_PUT(skb, IWL_TM_ATTR_SRAM_DUMP, length, -			priv->testmode_sram.buff_addr + +		NLA_PUT(skb, IWL_TM_ATTR_BUFFER_DUMP, length, +			priv->testmode_mem.buff_addr +  			(DUMP_CHUNK_SIZE * idx));  		idx++;  		cb->args[4] = idx; @@ -892,20 +960,19 @@ static int iwl_testmode_sram_dump(struct ieee80211_hw *hw, struct nlattr **tb,  int iwlagn_mac_testmode_cmd(struct ieee80211_hw *hw, void *data, int len)  {  	struct nlattr *tb[IWL_TM_ATTR_MAX]; -	struct iwl_priv *priv = hw->priv; +	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);  	int result;  	result = nla_parse(tb, IWL_TM_ATTR_MAX - 1, data, len,  			iwl_testmode_gnl_msg_policy);  	if (result != 0) { -		IWL_DEBUG_INFO(priv, -			       "Error parsing the gnl message : %d\n", result); +		IWL_ERR(priv, "Error parsing the gnl message : %d\n", result);  		return result;  	}  	/* IWL_TM_ATTR_COMMAND is absolutely mandatory */  	if (!tb[IWL_TM_ATTR_COMMAND]) { -		IWL_DEBUG_INFO(priv, "Error finding testmode command type\n"); +		IWL_ERR(priv, "Missing testmode command type\n");  		return -ENOMSG;  	}  	/* in case multiple accesses to the device happens */ @@ -919,8 +986,6 @@ int iwlagn_mac_testmode_cmd(struct ieee80211_hw *hw, void *data, int len)  	case IWL_TM_CMD_APP2DEV_DIRECT_REG_READ32:  	case IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE32:  	case IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE8: -	case IWL_TM_CMD_APP2DEV_INDIRECT_REG_READ32: -	case IWL_TM_CMD_APP2DEV_INDIRECT_REG_WRITE32:  		IWL_DEBUG_INFO(priv, "testmode cmd to register\n");  		result = iwl_testmode_reg(hw, tb);  		break; @@ -950,13 +1015,15 @@ int iwlagn_mac_testmode_cmd(struct ieee80211_hw *hw, void *data, int len)  		result = iwl_testmode_ownership(hw, tb);  		break; -	case IWL_TM_CMD_APP2DEV_READ_SRAM: -		IWL_DEBUG_INFO(priv, "testmode sram read cmd to driver\n"); -		result = iwl_testmode_sram(hw, tb); +	case IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_READ: +	case IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_WRITE: +		IWL_DEBUG_INFO(priv, "testmode indirect memory cmd " +			"to driver\n"); +		result = iwl_testmode_indirect_mem(hw, tb);  		break;  	default: -		IWL_DEBUG_INFO(priv, "Unknown testmode command\n"); +		IWL_ERR(priv, "Unknown testmode command\n");  		result = -ENOSYS;  		break;  	} @@ -970,7 +1037,7 @@ int iwlagn_mac_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *skb,  		      void *data, int len)  {  	struct nlattr *tb[IWL_TM_ATTR_MAX]; -	struct iwl_priv *priv = hw->priv; +	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);  	int result;  	u32 cmd; @@ -981,15 +1048,14 @@ int iwlagn_mac_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *skb,  		result = nla_parse(tb, IWL_TM_ATTR_MAX - 1, data, len,  				iwl_testmode_gnl_msg_policy);  		if (result) { -			IWL_DEBUG_INFO(priv, -			       "Error parsing the gnl message : %d\n", result); +			IWL_ERR(priv, +				"Error parsing the gnl message : %d\n", result);  			return result;  		}  		/* IWL_TM_ATTR_COMMAND is absolutely mandatory */  		if (!tb[IWL_TM_ATTR_COMMAND]) { -			IWL_DEBUG_INFO(priv, -				"Error finding testmode command type\n"); +			IWL_ERR(priv, "Missing testmode command type\n");  			return -ENOMSG;  		}  		cmd = nla_get_u32(tb[IWL_TM_ATTR_COMMAND]); @@ -1003,9 +1069,9 @@ int iwlagn_mac_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *skb,  		IWL_DEBUG_INFO(priv, "uCode trace cmd to driver\n");  		result = iwl_testmode_trace_dump(hw, tb, skb, cb);  		break; -	case IWL_TM_CMD_APP2DEV_DUMP_SRAM: +	case IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_DUMP:  		IWL_DEBUG_INFO(priv, "testmode sram dump cmd to driver\n"); -		result = iwl_testmode_sram_dump(hw, tb, skb, cb); +		result = iwl_testmode_buffer_dump(hw, tb, skb, cb);  		break;  	default:  		result = -EINVAL;  |