diff options
Diffstat (limited to 'drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c')
| -rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c | 100 | 
1 files changed, 55 insertions, 45 deletions
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c index d89d0a1fd34e..2e8e3e8e30a3 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c @@ -70,49 +70,6 @@  #include "iwl-prph.h"  #include "iwl-csr.h" -static ssize_t iwl_mvm_read_coredump(char *buffer, loff_t offset, size_t count, -				     void *data, size_t datalen) -{ -	const struct iwl_mvm_dump_ptrs *dump_ptrs = data; -	ssize_t bytes_read; -	ssize_t bytes_read_trans; - -	if (offset < dump_ptrs->op_mode_len) { -		bytes_read = min_t(ssize_t, count, -				   dump_ptrs->op_mode_len - offset); -		memcpy(buffer, (u8 *)dump_ptrs->op_mode_ptr + offset, -		       bytes_read); -		offset += bytes_read; -		count -= bytes_read; - -		if (count == 0) -			return bytes_read; -	} else { -		bytes_read = 0; -	} - -	if (!dump_ptrs->trans_ptr) -		return bytes_read; - -	offset -= dump_ptrs->op_mode_len; -	bytes_read_trans = min_t(ssize_t, count, -				 dump_ptrs->trans_ptr->len - offset); -	memcpy(buffer + bytes_read, -	       (u8 *)dump_ptrs->trans_ptr->data + offset, -	       bytes_read_trans); - -	return bytes_read + bytes_read_trans; -} - -static void iwl_mvm_free_coredump(void *data) -{ -	const struct iwl_mvm_dump_ptrs *fw_error_dump = data; - -	vfree(fw_error_dump->op_mode_ptr); -	vfree(fw_error_dump->trans_ptr); -	kfree(fw_error_dump); -} -  #define RADIO_REG_MAX_READ 0x2ad  static void iwl_mvm_read_radio_reg(struct iwl_mvm *mvm,  				   struct iwl_fw_error_dump_data **dump_data) @@ -491,6 +448,43 @@ static u32 iwl_dump_prph(struct iwl_trans *trans,  	return prph_len;  } +/* + * alloc_sgtable - allocates scallerlist table in the given size, + * fills it with pages and returns it + * @size: the size (in bytes) of the table +*/ +static struct scatterlist *alloc_sgtable(int size) +{ +	int alloc_size, nents, i; +	struct page *new_page; +	struct scatterlist *iter; +	struct scatterlist *table; + +	nents = DIV_ROUND_UP(size, PAGE_SIZE); +	table = kcalloc(nents, sizeof(*table), GFP_KERNEL); +	if (!table) +		return NULL; +	sg_init_table(table, nents); +	iter = table; +	for_each_sg(table, iter, sg_nents(table), i) { +		new_page = alloc_page(GFP_KERNEL); +		if (!new_page) { +			/* release all previous allocated pages in the table */ +			iter = table; +			for_each_sg(table, iter, sg_nents(table), i) { +				new_page = sg_page(iter); +				if (new_page) +					__free_page(new_page); +			} +			return NULL; +		} +		alloc_size = min_t(int, size, PAGE_SIZE); +		size -= PAGE_SIZE; +		sg_set_page(iter, new_page, alloc_size, 0); +	} +	return table; +} +  void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)  {  	struct iwl_fw_error_dump_file *dump_file; @@ -499,6 +493,7 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)  	struct iwl_fw_error_dump_mem *dump_mem;  	struct iwl_fw_error_dump_trigger_desc *dump_trig;  	struct iwl_mvm_dump_ptrs *fw_error_dump; +	struct scatterlist *sg_dump_data;  	u32 sram_len, sram_ofs;  	struct iwl_fw_dbg_mem_seg_tlv * const *fw_dbg_mem =  		mvm->fw->dbg_mem_tlv; @@ -815,8 +810,23 @@ dump_trans_data:  		file_len += fw_error_dump->trans_ptr->len;  	dump_file->file_len = cpu_to_le32(file_len); -	dev_coredumpm(mvm->trans->dev, THIS_MODULE, fw_error_dump, 0, -		      GFP_KERNEL, iwl_mvm_read_coredump, iwl_mvm_free_coredump); +	sg_dump_data = alloc_sgtable(file_len); +	if (sg_dump_data) { +		sg_pcopy_from_buffer(sg_dump_data, +				     sg_nents(sg_dump_data), +				     fw_error_dump->op_mode_ptr, +				     fw_error_dump->op_mode_len, 0); +		sg_pcopy_from_buffer(sg_dump_data, +				     sg_nents(sg_dump_data), +				     fw_error_dump->trans_ptr->data, +				     fw_error_dump->trans_ptr->len, +				     fw_error_dump->op_mode_len); +		dev_coredumpsg(mvm->trans->dev, sg_dump_data, file_len, +			       GFP_KERNEL); +	} +	vfree(fw_error_dump->op_mode_ptr); +	vfree(fw_error_dump->trans_ptr); +	kfree(fw_error_dump);  out:  	iwl_mvm_free_fw_dump_desc(mvm);  |