Linux wireless drivers development
 help / color / mirror / Atom feed
* [PATCH 06/25] iwlwifi: mvm: properly check for transport data in dump
From: Luca Coelho @ 2017-01-23 22:03 UTC (permalink / raw)
  To: linux-wireless; +Cc: kvalo, luciano.coelho, Johannes Berg
In-Reply-To: <20170123220350.25305-1-luca@coelho.fi>

From: Johannes Berg <johannes.berg@intel.com>

When copying from vmalloc'ed memory to the SG list, don't crash
if the transport didn't provide any data.

Fixes: 7e62a699aafb ("iwlwifi: mvm: use dev_coredumpsg()")
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
---
 drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c
index 10f2c6e4056a..36f79953c7a1 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c
@@ -848,11 +848,12 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
 				     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);
+		if (fw_error_dump->trans_ptr)
+			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);
 	}
-- 
2.11.0

^ permalink raw reply related

* [PATCH 08/25] iwlwifi: mvm: simplify paging allocation code
From: Luca Coelho @ 2017-01-23 22:03 UTC (permalink / raw)
  To: linux-wireless; +Cc: kvalo, luciano.coelho, Sara Sharon
In-Reply-To: <20170123220350.25305-1-luca@coelho.fi>

From: Sara Sharon <sara.sharon@intel.com>

Some of the code there is duplicate while the only change is
the block size. Unifying it shortens the code and make the
difference clearer.

Signed-off-by: Sara Sharon <sara.sharon@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
---
 drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 61 +++++++----------------------
 1 file changed, 15 insertions(+), 46 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
index 872066317fa5..04fe1051b1e5 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
@@ -259,9 +259,7 @@ static int iwl_alloc_fw_paging_mem(struct iwl_mvm *mvm,
 {
 	struct page *block;
 	dma_addr_t phys = 0;
-	int blk_idx = 0;
-	int order, num_of_pages;
-	int dma_enabled;
+	int blk_idx, order, num_of_pages, size, dma_enabled;
 
 	if (mvm->fw_paging_db[0].fw_paging_block)
 		return 0;
@@ -274,7 +272,6 @@ static int iwl_alloc_fw_paging_mem(struct iwl_mvm *mvm,
 	num_of_pages = image->paging_mem_size / FW_PAGING_SIZE;
 	mvm->num_of_paging_blk = ((num_of_pages - 1) /
 				    NUM_OF_PAGE_PER_GROUP) + 1;
-
 	mvm->num_of_pages_in_last_blk =
 		num_of_pages -
 		NUM_OF_PAGE_PER_GROUP * (mvm->num_of_paging_blk - 1);
@@ -284,46 +281,13 @@ static int iwl_alloc_fw_paging_mem(struct iwl_mvm *mvm,
 		     mvm->num_of_paging_blk,
 		     mvm->num_of_pages_in_last_blk);
 
-	/* allocate block of 4Kbytes for paging CSS */
-	order = get_order(FW_PAGING_SIZE);
-	block = alloc_pages(GFP_KERNEL, order);
-	if (!block) {
-		/* free all the previous pages since we failed */
-		iwl_free_fw_paging(mvm);
-		return -ENOMEM;
-	}
-
-	mvm->fw_paging_db[blk_idx].fw_paging_block = block;
-	mvm->fw_paging_db[blk_idx].fw_paging_size = FW_PAGING_SIZE;
-
-	if (dma_enabled) {
-		phys = dma_map_page(mvm->trans->dev, block, 0,
-				    PAGE_SIZE << order, DMA_BIDIRECTIONAL);
-		if (dma_mapping_error(mvm->trans->dev, phys)) {
-			/*
-			 * free the previous pages and the current one since
-			 * we failed to map_page.
-			 */
-			iwl_free_fw_paging(mvm);
-			return -ENOMEM;
-		}
-		mvm->fw_paging_db[blk_idx].fw_paging_phys = phys;
-	} else {
-		mvm->fw_paging_db[blk_idx].fw_paging_phys = PAGING_ADDR_SIG |
-			blk_idx << BLOCK_2_EXP_SIZE;
-	}
-
-	IWL_DEBUG_FW(mvm,
-		     "Paging: allocated 4K(CSS) bytes (order %d) for firmware paging.\n",
-		     order);
-
 	/*
-	 * allocate blocks in dram.
-	 * since that CSS allocated in fw_paging_db[0] loop start from index 1
+	 * Allocate CSS and paging blocks in dram.
 	 */
-	for (blk_idx = 1; blk_idx < mvm->num_of_paging_blk + 1; blk_idx++) {
-		/* allocate block of PAGING_BLOCK_SIZE (32K) */
-		order = get_order(PAGING_BLOCK_SIZE);
+	for (blk_idx = 0; blk_idx < mvm->num_of_paging_blk + 1; blk_idx++) {
+		/* For CSS allocate 4KB, for others PAGING_BLOCK_SIZE (32K) */
+		size = blk_idx ? PAGING_BLOCK_SIZE : FW_PAGING_SIZE;
+		order = get_order(size);
 		block = alloc_pages(GFP_KERNEL, order);
 		if (!block) {
 			/* free all the previous pages since we failed */
@@ -332,7 +296,7 @@ static int iwl_alloc_fw_paging_mem(struct iwl_mvm *mvm,
 		}
 
 		mvm->fw_paging_db[blk_idx].fw_paging_block = block;
-		mvm->fw_paging_db[blk_idx].fw_paging_size = PAGING_BLOCK_SIZE;
+		mvm->fw_paging_db[blk_idx].fw_paging_size = size;
 
 		if (dma_enabled) {
 			phys = dma_map_page(mvm->trans->dev, block, 0,
@@ -353,9 +317,14 @@ static int iwl_alloc_fw_paging_mem(struct iwl_mvm *mvm,
 				blk_idx << BLOCK_2_EXP_SIZE;
 		}
 
-		IWL_DEBUG_FW(mvm,
-			     "Paging: allocated 32K bytes (order %d) for firmware paging.\n",
-			     order);
+		if (!blk_idx)
+			IWL_DEBUG_FW(mvm,
+				     "Paging: allocated 4K(CSS) bytes (order %d) for firmware paging.\n",
+				     order);
+		else
+			IWL_DEBUG_FW(mvm,
+				     "Paging: allocated 32K bytes (order %d) for firmware paging.\n",
+				     order);
 	}
 
 	return 0;
-- 
2.11.0

^ permalink raw reply related

* [PATCH 07/25] iwlwifi: mvm: bump max API to 28
From: Luca Coelho @ 2017-01-23 22:03 UTC (permalink / raw)
  To: linux-wireless; +Cc: kvalo, luciano.coelho
In-Reply-To: <20170123220350.25305-1-luca@coelho.fi>

From: Luca Coelho <luciano.coelho@intel.com>

We skipped one release, so bump twice, to 28.

Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
---
 drivers/net/wireless/intel/iwlwifi/iwl-7000.c | 4 ++--
 drivers/net/wireless/intel/iwlwifi/iwl-8000.c | 4 ++--
 drivers/net/wireless/intel/iwlwifi/iwl-9000.c | 2 +-
 drivers/net/wireless/intel/iwlwifi/iwl-a000.c | 2 +-
 4 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-7000.c b/drivers/net/wireless/intel/iwlwifi/iwl-7000.c
index d4b73dedf89b..a72e58623d3a 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-7000.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-7000.c
@@ -73,8 +73,8 @@
 /* Highest firmware API version supported */
 #define IWL7260_UCODE_API_MAX	17
 #define IWL7265_UCODE_API_MAX	17
-#define IWL7265D_UCODE_API_MAX	26
-#define IWL3168_UCODE_API_MAX	26
+#define IWL7265D_UCODE_API_MAX	28
+#define IWL3168_UCODE_API_MAX	28
 
 /* Lowest firmware API version supported */
 #define IWL7260_UCODE_API_MIN	17
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-8000.c b/drivers/net/wireless/intel/iwlwifi/iwl-8000.c
index d02ca1491d16..df0fc24e99e1 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-8000.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-8000.c
@@ -70,8 +70,8 @@
 #include "iwl-agn-hw.h"
 
 /* Highest firmware API version supported */
-#define IWL8000_UCODE_API_MAX	26
-#define IWL8265_UCODE_API_MAX	26
+#define IWL8000_UCODE_API_MAX	28
+#define IWL8265_UCODE_API_MAX	28
 
 /* Lowest firmware API version supported */
 #define IWL8000_UCODE_API_MIN	17
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-9000.c b/drivers/net/wireless/intel/iwlwifi/iwl-9000.c
index ff850410d897..a5f0c0bf85ec 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-9000.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-9000.c
@@ -55,7 +55,7 @@
 #include "iwl-agn-hw.h"
 
 /* Highest firmware API version supported */
-#define IWL9000_UCODE_API_MAX	26
+#define IWL9000_UCODE_API_MAX	28
 
 /* Lowest firmware API version supported */
 #define IWL9000_UCODE_API_MIN	17
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-a000.c b/drivers/net/wireless/intel/iwlwifi/iwl-a000.c
index ea1618525878..82f18d967c40 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-a000.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-a000.c
@@ -55,7 +55,7 @@
 #include "iwl-agn-hw.h"
 
 /* Highest firmware API version supported */
-#define IWL_A000_UCODE_API_MAX	26
+#define IWL_A000_UCODE_API_MAX	28
 
 /* Lowest firmware API version supported */
 #define IWL_A000_UCODE_API_MIN	24
-- 
2.11.0

^ permalink raw reply related

* [PATCH 05/25] iwlwifi: allow memory debug TLV to specify the memory type
From: Luca Coelho @ 2017-01-23 22:03 UTC (permalink / raw)
  To: linux-wireless; +Cc: kvalo, luciano.coelho, Johannes Berg
In-Reply-To: <20170123220350.25305-1-luca@coelho.fi>

From: Johannes Berg <johannes.berg@intel.com>

Due to some new features and changes, the firmware file will now
specify what type of memory to dump, in upper 8 bits of the type
field of the TLV. Parse it (types we don't understand are errors)
and teach the code to dump periphery memory.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
---
 drivers/net/wireless/intel/iwlwifi/iwl-drv.c     | 12 +++++
 drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h | 15 +++++-
 drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c  | 65 +++++++++++++++++++-----
 3 files changed, 79 insertions(+), 13 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c
index 431581229948..a6719d67ac00 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c
@@ -1020,6 +1020,18 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
 			IWL_DEBUG_INFO(drv, "Found debug memory segment: %u\n",
 				       dbg_mem->data_type);
 
+			switch (type & FW_DBG_MEM_TYPE_MASK) {
+			case FW_DBG_MEM_TYPE_REGULAR:
+			case FW_DBG_MEM_TYPE_PRPH:
+				/* we know how to handle these */
+				break;
+			default:
+				IWL_ERR(drv,
+					"Found debug memory segment with invalid type: 0x%x\n",
+					type);
+				return -EINVAL;
+			}
+
 			size = sizeof(*pieces->dbg_mem_tlv) *
 			       (pieces->n_dbg_mem_tlv + 1);
 			n = krealloc(pieces->dbg_mem_tlv, size, GFP_KERNEL);
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h
index 11245b9117c7..c84207576587 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h
@@ -489,9 +489,22 @@ enum iwl_fw_dbg_monitor_mode {
 };
 
 /**
+ * enum iwl_fw_mem_seg_type - memory segment type
+ * @FW_DBG_MEM_TYPE_MASK: mask for the type indication
+ * @FW_DBG_MEM_TYPE_REGULAR: regular memory
+ * @FW_DBG_MEM_TYPE_PRPH: periphery memory (requires special reading)
+ */
+enum iwl_fw_mem_seg_type {
+	FW_DBG_MEM_TYPE_MASK	= 0xff000000,
+	FW_DBG_MEM_TYPE_REGULAR	= 0x00000000,
+	FW_DBG_MEM_TYPE_PRPH	= 0x01000000,
+};
+
+/**
  * struct iwl_fw_dbg_mem_seg_tlv - configures the debug data memory segments
  *
- * @data_type: the memory segment type to record
+ * @data_type: the memory segment type to record, see &enum iwl_fw_mem_seg_type
+ *	for what we care about
  * @ofs: the memory segment offset
  * @len: the memory segment length, in bytes
  *
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c
index 7df3c3f4749e..10f2c6e4056a 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c
@@ -406,6 +406,30 @@ static const struct iwl_prph_range iwl_prph_dump_addr_9000[] = {
 	{ .start = 0x00a02400, .end = 0x00a02758 },
 };
 
+static void _iwl_read_prph_block(struct iwl_trans *trans, u32 start,
+				 u32 len_bytes, __le32 *data)
+{
+	u32 i;
+
+	for (i = 0; i < len_bytes / 4; i++)
+		*data++ = cpu_to_le32(iwl_read_prph_no_grab(trans, start + i));
+}
+
+static bool iwl_read_prph_block(struct iwl_trans *trans, u32 start,
+				u32 len_bytes, __le32 *data)
+{
+	unsigned long flags;
+	bool success = false;
+
+	if (iwl_trans_grab_nic_access(trans, &flags)) {
+		success = true;
+		_iwl_read_prph_block(trans, start, len_bytes, data);
+		iwl_trans_release_nic_access(trans, &flags);
+	}
+
+	return success;
+}
+
 static void iwl_dump_prph(struct iwl_trans *trans,
 			  struct iwl_fw_error_dump_data **data,
 			  const struct iwl_prph_range *iwl_prph_dump_addr,
@@ -422,21 +446,18 @@ static void iwl_dump_prph(struct iwl_trans *trans,
 		/* The range includes both boundaries */
 		int num_bytes_in_chunk = iwl_prph_dump_addr[i].end -
 			 iwl_prph_dump_addr[i].start + 4;
-		int reg;
-		__le32 *val;
 
 		(*data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_PRPH);
 		(*data)->len = cpu_to_le32(sizeof(*prph) +
 					num_bytes_in_chunk);
 		prph = (void *)(*data)->data;
 		prph->prph_start = cpu_to_le32(iwl_prph_dump_addr[i].start);
-		val = (void *)prph->data;
 
-		for (reg = iwl_prph_dump_addr[i].start;
-		     reg <= iwl_prph_dump_addr[i].end;
-		     reg += 4)
-			*val++ = cpu_to_le32(iwl_read_prph_no_grab(trans,
-								   reg));
+		_iwl_read_prph_block(trans, iwl_prph_dump_addr[i].start,
+				     /* our range is inclusive, hence + 4 */
+				     iwl_prph_dump_addr[i].end -
+				     iwl_prph_dump_addr[i].start + 4,
+				     (void *)prph->data);
 
 		*data = iwl_fw_error_next_data(*data);
 	}
@@ -716,16 +737,36 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
 	for (i = 0; i < mvm->fw->n_dbg_mem_tlv; i++) {
 		u32 len = le32_to_cpu(fw_dbg_mem[i].len);
 		u32 ofs = le32_to_cpu(fw_dbg_mem[i].ofs);
+		bool success;
 
 		dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM);
 		dump_data->len = cpu_to_le32(len + sizeof(*dump_mem));
 		dump_mem = (void *)dump_data->data;
 		dump_mem->type = fw_dbg_mem[i].data_type;
 		dump_mem->offset = cpu_to_le32(ofs);
-		iwl_trans_read_mem_bytes(mvm->trans, ofs,
-					 dump_mem->data,
-					 len);
-		dump_data = iwl_fw_error_next_data(dump_data);
+
+		switch (dump_mem->type & cpu_to_le32(FW_DBG_MEM_TYPE_MASK)) {
+		case cpu_to_le32(FW_DBG_MEM_TYPE_REGULAR):
+			iwl_trans_read_mem_bytes(mvm->trans, ofs,
+						 dump_mem->data,
+						 len);
+			success = true;
+			break;
+		case cpu_to_le32(FW_DBG_MEM_TYPE_PRPH):
+			success = iwl_read_prph_block(mvm->trans, ofs, len,
+						      (void *)dump_mem->data);
+			break;
+		default:
+			/*
+			 * shouldn't get here, we ignored this kind
+			 * of TLV earlier during the TLV parsing?!
+			 */
+			WARN_ON(1);
+			success = false;
+		}
+
+		if (success)
+			dump_data = iwl_fw_error_next_data(dump_data);
 	}
 
 	if (smem_len) {
-- 
2.11.0

^ permalink raw reply related

* [PATCH 03/25] iwlwifi: mvm: accept arbitrary memory dump TLVs
From: Luca Coelho @ 2017-01-23 22:03 UTC (permalink / raw)
  To: linux-wireless; +Cc: kvalo, luciano.coelho, Johannes Berg
In-Reply-To: <20170123220350.25305-1-luca@coelho.fi>

From: Johannes Berg <johannes.berg@intel.com>

There's no reason to be validating the memory dump types, or
checking them for duplication, or anything, since we really
just pass them through from the TLV to the dump.

Thus, change the way we handle memory dump TLVs to let the
driver just blindly use anything specified there, dumping it
into the memory dump output file.

This makes the system extensible without driver changes.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
---
 drivers/net/wireless/intel/iwlwifi/iwl-drv.c     | 57 +++++++++---------------
 drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h | 18 +-------
 drivers/net/wireless/intel/iwlwifi/iwl-fw.h      |  4 +-
 drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c  | 47 +++++++++----------
 4 files changed, 46 insertions(+), 80 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c
index 45b2f679e4d8..431581229948 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c
@@ -179,8 +179,7 @@ static void iwl_dealloc_ucode(struct iwl_drv *drv)
 		kfree(drv->fw.dbg_conf_tlv[i]);
 	for (i = 0; i < ARRAY_SIZE(drv->fw.dbg_trigger_tlv); i++)
 		kfree(drv->fw.dbg_trigger_tlv[i]);
-	for (i = 0; i < ARRAY_SIZE(drv->fw.dbg_mem_tlv); i++)
-		kfree(drv->fw.dbg_mem_tlv[i]);
+	kfree(drv->fw.dbg_mem_tlv);
 
 	for (i = 0; i < IWL_UCODE_TYPE_MAX; i++)
 		iwl_free_fw_img(drv, drv->fw.img + i);
@@ -276,7 +275,8 @@ struct iwl_firmware_pieces {
 	size_t dbg_conf_tlv_len[FW_DBG_CONF_MAX];
 	struct iwl_fw_dbg_trigger_tlv *dbg_trigger_tlv[FW_DBG_TRIGGER_MAX];
 	size_t dbg_trigger_tlv_len[FW_DBG_TRIGGER_MAX];
-	struct iwl_fw_dbg_mem_seg_tlv *dbg_mem_tlv[FW_DBG_MEM_MAX];
+	struct iwl_fw_dbg_mem_seg_tlv *dbg_mem_tlv;
+	size_t n_dbg_mem_tlv;
 };
 
 /*
@@ -1009,31 +1009,25 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
 			struct iwl_fw_dbg_mem_seg_tlv *dbg_mem =
 				(void *)tlv_data;
 			u32 type;
+			size_t size;
+			struct iwl_fw_dbg_mem_seg_tlv *n;
 
 			if (tlv_len != (sizeof(*dbg_mem)))
 				goto invalid_tlv_len;
 
 			type = le32_to_cpu(dbg_mem->data_type);
-			drv->fw.dbg_dynamic_mem = true;
-
-			if (type >= ARRAY_SIZE(drv->fw.dbg_mem_tlv)) {
-				IWL_ERR(drv,
-					"Skip unknown dbg mem segment: %u\n",
-					dbg_mem->data_type);
-				break;
-			}
-
-			if (pieces->dbg_mem_tlv[type]) {
-				IWL_ERR(drv,
-					"Ignore duplicate mem segment: %u\n",
-					dbg_mem->data_type);
-				break;
-			}
 
 			IWL_DEBUG_INFO(drv, "Found debug memory segment: %u\n",
 				       dbg_mem->data_type);
 
-			pieces->dbg_mem_tlv[type] = dbg_mem;
+			size = sizeof(*pieces->dbg_mem_tlv) *
+			       (pieces->n_dbg_mem_tlv + 1);
+			n = krealloc(pieces->dbg_mem_tlv, size, GFP_KERNEL);
+			if (!n)
+				return -ENOMEM;
+			pieces->dbg_mem_tlv = n;
+			pieces->dbg_mem_tlv[pieces->n_dbg_mem_tlv] = *dbg_mem;
+			pieces->n_dbg_mem_tlv++;
 			break;
 			}
 		default:
@@ -1345,19 +1339,12 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context)
 		}
 	}
 
-	for (i = 0; i < ARRAY_SIZE(drv->fw.dbg_mem_tlv); i++) {
-		if (pieces->dbg_mem_tlv[i]) {
-			drv->fw.dbg_mem_tlv[i] =
-				kmemdup(pieces->dbg_mem_tlv[i],
-					sizeof(*drv->fw.dbg_mem_tlv[i]),
-					GFP_KERNEL);
-			if (!drv->fw.dbg_mem_tlv[i])
-				goto out_free_fw;
-		}
-	}
-
 	/* Now that we can no longer fail, copy information */
 
+	drv->fw.dbg_mem_tlv = pieces->dbg_mem_tlv;
+	pieces->dbg_mem_tlv = NULL;
+	drv->fw.n_dbg_mem_tlv = pieces->n_dbg_mem_tlv;
+
 	/*
 	 * The (size - 16) / 12 formula is based on the information recorded
 	 * for each event, which is of mode 1 (including timestamp) for all
@@ -1441,25 +1428,25 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context)
 				op->name, err);
 #endif
 	}
-	kfree(pieces);
-	return;
+	goto free;
 
  try_again:
 	/* try next, if any */
 	release_firmware(ucode_raw);
 	if (iwl_request_firmware(drv, false))
 		goto out_unbind;
-	kfree(pieces);
-	return;
+	goto free;
 
  out_free_fw:
 	IWL_ERR(drv, "failed to allocate pci memory\n");
 	iwl_dealloc_ucode(drv);
 	release_firmware(ucode_raw);
  out_unbind:
-	kfree(pieces);
 	complete(&drv->request_firmware_complete);
 	device_release_driver(drv->trans->dev);
+ free:
+	kfree(pieces->dbg_mem_tlv);
+	kfree(pieces);
 }
 
 struct iwl_drv *iwl_drv_start(struct iwl_trans *trans,
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h
index 84813b550ef1..11245b9117c7 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h
@@ -489,25 +489,9 @@ enum iwl_fw_dbg_monitor_mode {
 };
 
 /**
- * enum iwl_fw_mem_seg_type - data types for dumping on error
- *
- * @FW_DBG_MEM_SMEM: the data type is SMEM
- * @FW_DBG_MEM_DCCM_LMAC: the data type is DCCM_LMAC
- * @FW_DBG_MEM_DCCM_UMAC: the data type is DCCM_UMAC
- */
-enum iwl_fw_dbg_mem_seg_type {
-	FW_DBG_MEM_DCCM_LMAC = 0,
-	FW_DBG_MEM_DCCM_UMAC,
-	FW_DBG_MEM_SMEM,
-
-	/* Must be last */
-	FW_DBG_MEM_MAX,
-};
-
-/**
  * struct iwl_fw_dbg_mem_seg_tlv - configures the debug data memory segments
  *
- * @data_type: enum %iwl_fw_mem_seg_type
+ * @data_type: the memory segment type to record
  * @ofs: the memory segment offset
  * @len: the memory segment length, in bytes
  *
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-fw.h b/drivers/net/wireless/intel/iwlwifi/iwl-fw.h
index 5f229556339a..710ecb490bfc 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-fw.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-fw.h
@@ -295,8 +295,8 @@ struct iwl_fw {
 	struct iwl_fw_dbg_conf_tlv *dbg_conf_tlv[FW_DBG_CONF_MAX];
 	size_t dbg_conf_tlv_len[FW_DBG_CONF_MAX];
 	struct iwl_fw_dbg_trigger_tlv *dbg_trigger_tlv[FW_DBG_TRIGGER_MAX];
-	struct iwl_fw_dbg_mem_seg_tlv *dbg_mem_tlv[FW_DBG_MEM_MAX];
-	bool dbg_dynamic_mem;
+	struct iwl_fw_dbg_mem_seg_tlv *dbg_mem_tlv;
+	size_t n_dbg_mem_tlv;
 	size_t dbg_trigger_tlv_len[FW_DBG_TRIGGER_MAX];
 	u8 dbg_dest_reg_num;
 	struct iwl_gscan_capabilities gscan_capa;
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c
index 2e8e3e8e30a3..46ab6b9f680b 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c
@@ -495,11 +495,10 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
 	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;
+	const struct iwl_fw_dbg_mem_seg_tlv *fw_dbg_mem = mvm->fw->dbg_mem_tlv;
 	u32 file_len, fifo_data_len = 0, prph_len = 0, radio_len = 0;
-	u32 smem_len = mvm->fw->dbg_dynamic_mem ? 0 : mvm->cfg->smem_len;
-	u32 sram2_len = mvm->fw->dbg_dynamic_mem ? 0 : mvm->cfg->dccm2_len;
+	u32 smem_len = mvm->fw->n_dbg_mem_tlv ? 0 : mvm->cfg->smem_len;
+	u32 sram2_len = mvm->fw->n_dbg_mem_tlv ? 0 : mvm->cfg->dccm2_len;
 	bool monitor_dump_only = false;
 	int i;
 
@@ -624,10 +623,9 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
 		file_len += sizeof(*dump_data) + sizeof(*dump_mem) + sram2_len;
 
 	/* Make room for MEM segments */
-	for (i = 0; i < ARRAY_SIZE(mvm->fw->dbg_mem_tlv); i++) {
-		if (fw_dbg_mem[i])
-			file_len += sizeof(*dump_data) + sizeof(*dump_mem) +
-				le32_to_cpu(fw_dbg_mem[i]->len);
+	for (i = 0; i < mvm->fw->n_dbg_mem_tlv; i++) {
+		file_len += sizeof(*dump_data) + sizeof(*dump_mem) +
+			    le32_to_cpu(fw_dbg_mem[i].len);
 	}
 
 	/* Make room for fw's virtual image pages, if it exists */
@@ -656,7 +654,7 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
 		file_len += sizeof(*dump_data) + sizeof(*dump_trig) +
 			    mvm->fw_dump_desc->len;
 
-	if (!mvm->fw->dbg_dynamic_mem)
+	if (!mvm->fw->n_dbg_mem_tlv)
 		file_len += sram_len + sizeof(*dump_mem);
 
 	dump_file = vzalloc(file_len);
@@ -708,7 +706,7 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
 	if (monitor_dump_only)
 		goto dump_trans_data;
 
-	if (!mvm->fw->dbg_dynamic_mem) {
+	if (!mvm->fw->n_dbg_mem_tlv) {
 		dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM);
 		dump_data->len = cpu_to_le32(sram_len + sizeof(*dump_mem));
 		dump_mem = (void *)dump_data->data;
@@ -719,22 +717,19 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
 		dump_data = iwl_fw_error_next_data(dump_data);
 	}
 
-	for (i = 0; i < ARRAY_SIZE(mvm->fw->dbg_mem_tlv); i++) {
-		if (fw_dbg_mem[i]) {
-			u32 len = le32_to_cpu(fw_dbg_mem[i]->len);
-			u32 ofs = le32_to_cpu(fw_dbg_mem[i]->ofs);
-
-			dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM);
-			dump_data->len = cpu_to_le32(len +
-					sizeof(*dump_mem));
-			dump_mem = (void *)dump_data->data;
-			dump_mem->type = fw_dbg_mem[i]->data_type;
-			dump_mem->offset = cpu_to_le32(ofs);
-			iwl_trans_read_mem_bytes(mvm->trans, ofs,
-						 dump_mem->data,
-						 len);
-			dump_data = iwl_fw_error_next_data(dump_data);
-		}
+	for (i = 0; i < mvm->fw->n_dbg_mem_tlv; i++) {
+		u32 len = le32_to_cpu(fw_dbg_mem[i].len);
+		u32 ofs = le32_to_cpu(fw_dbg_mem[i].ofs);
+
+		dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM);
+		dump_data->len = cpu_to_le32(len + sizeof(*dump_mem));
+		dump_mem = (void *)dump_data->data;
+		dump_mem->type = fw_dbg_mem[i].data_type;
+		dump_mem->offset = cpu_to_le32(ofs);
+		iwl_trans_read_mem_bytes(mvm->trans, ofs,
+					 dump_mem->data,
+					 len);
+		dump_data = iwl_fw_error_next_data(dump_data);
 	}
 
 	if (smem_len) {
-- 
2.11.0

^ permalink raw reply related

* [PATCH 04/25] iwlwifi: mvm: make iwl_dump_prph() void
From: Luca Coelho @ 2017-01-23 22:03 UTC (permalink / raw)
  To: linux-wireless; +Cc: kvalo, luciano.coelho, Johannes Berg
In-Reply-To: <20170123220350.25305-1-luca@coelho.fi>

From: Johannes Berg <johannes.berg@intel.com>

The return value is never used, so make the function void.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
---
 drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c | 16 ++++++----------
 1 file changed, 6 insertions(+), 10 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c
index 46ab6b9f680b..7df3c3f4749e 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c
@@ -406,17 +406,17 @@ static const struct iwl_prph_range iwl_prph_dump_addr_9000[] = {
 	{ .start = 0x00a02400, .end = 0x00a02758 },
 };
 
-static u32 iwl_dump_prph(struct iwl_trans *trans,
-			 struct iwl_fw_error_dump_data **data,
-			 const struct iwl_prph_range *iwl_prph_dump_addr,
-			 u32 range_len)
+static void iwl_dump_prph(struct iwl_trans *trans,
+			  struct iwl_fw_error_dump_data **data,
+			  const struct iwl_prph_range *iwl_prph_dump_addr,
+			  u32 range_len)
 {
 	struct iwl_fw_error_dump_prph *prph;
 	unsigned long flags;
-	u32 prph_len = 0, i;
+	u32 i;
 
 	if (!iwl_trans_grab_nic_access(trans, &flags))
-		return 0;
+		return;
 
 	for (i = 0; i < range_len; i++) {
 		/* The range includes both boundaries */
@@ -425,8 +425,6 @@ static u32 iwl_dump_prph(struct iwl_trans *trans,
 		int reg;
 		__le32 *val;
 
-		prph_len += sizeof(**data) + sizeof(*prph) + num_bytes_in_chunk;
-
 		(*data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_PRPH);
 		(*data)->len = cpu_to_le32(sizeof(*prph) +
 					num_bytes_in_chunk);
@@ -444,8 +442,6 @@ static u32 iwl_dump_prph(struct iwl_trans *trans,
 	}
 
 	iwl_trans_release_nic_access(trans, &flags);
-
-	return prph_len;
 }
 
 /*
-- 
2.11.0

^ permalink raw reply related

* [PATCH 01/25] iwlwifi: mvm: expose device timestamp in radiotap
From: Luca Coelho @ 2017-01-23 22:03 UTC (permalink / raw)
  To: linux-wireless; +Cc: kvalo, luciano.coelho, Johannes Berg
In-Reply-To: <20170123220350.25305-1-luca@coelho.fi>

From: Johannes Berg <johannes.berg@intel.com>

Set the relevant fields to export the 32-bit device timestamp to
radiotap using the new mac80211 infrastructure. This will be useful
to allow synchronising monitor captures taken on different hardware
simultaneously.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
---
 drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
index 45122dafe922..039cb2ad2d3e 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
@@ -463,6 +463,13 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
 				    IEEE80211_RADIOTAP_MCS_HAVE_STBC;
 	hw->radiotap_vht_details |= IEEE80211_RADIOTAP_VHT_KNOWN_STBC |
 		IEEE80211_RADIOTAP_VHT_KNOWN_BEAMFORMED;
+
+	hw->radiotap_timestamp.units_pos =
+		IEEE80211_RADIOTAP_TIMESTAMP_UNIT_US |
+		IEEE80211_RADIOTAP_TIMESTAMP_SPOS_PLCP_SIG_ACQ;
+	/* this is the case for CCK frames, it's better (only 8) for OFDM */
+	hw->radiotap_timestamp.accuracy = 22;
+
 	hw->rate_control_algorithm = "iwl-mvm-rs";
 	hw->uapsd_queues = IWL_MVM_UAPSD_QUEUES;
 	hw->uapsd_max_sp_len = IWL_UAPSD_MAX_SP;
-- 
2.11.0

^ permalink raw reply related

* [PATCH 02/25] iwlwifi: mvm: don't restart HW if suspend fails with unified image
From: Luca Coelho @ 2017-01-23 22:03 UTC (permalink / raw)
  To: linux-wireless; +Cc: kvalo, luciano.coelho
In-Reply-To: <20170123220350.25305-1-luca@coelho.fi>

From: Luca Coelho <luciano.coelho@intel.com>

For unified images, we shouldn't restart the HW if suspend fails.  The
only reason for restarting the HW with non-unified images is to go
back to the D0 image.

Fixes: 23ae61282b88 ("iwlwifi: mvm: Do not switch to D3 image on suspend")
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
---
 drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
index b88e2048ae0b..207d8ae1e116 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
@@ -1262,12 +1262,15 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
 	iwl_trans_d3_suspend(mvm->trans, test, !unified_image);
  out:
 	if (ret < 0) {
-		iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN);
-		if (mvm->restart_fw > 0) {
-			mvm->restart_fw--;
-			ieee80211_restart_hw(mvm->hw);
-		}
 		iwl_mvm_free_nd(mvm);
+
+		if (!unified_image) {
+			iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN);
+			if (mvm->restart_fw > 0) {
+				mvm->restart_fw--;
+				ieee80211_restart_hw(mvm->hw);
+			}
+		}
 	}
  out_noreset:
 	mutex_unlock(&mvm->mutex);
-- 
2.11.0

^ permalink raw reply related

* [PATCH 00/25] iwlwifi: updates intended for v4.11 2017-01-23
From: Luca Coelho @ 2017-01-23 22:03 UTC (permalink / raw)
  To: linux-wireless; +Cc: kvalo, luciano.coelho

From: Luca Coelho <luciano.coelho@intel.com>

Hi,

Here's my first series for v4.11.  These are the changes:

* A bunch of cleanups here and there;
* A few simple bugfixes;
* Some more work in preparation for A000 family support;
* Add support for radiotap timestamps;
* Some work on our firmware debugging capabilities;

As usual, I'm pushing this to a pending branch, for kbuild bot, and
will send a pull-request later.

Please review.

Cheers,
Luca.

Johannes Berg (5):
  iwlwifi: mvm: expose device timestamp in radiotap
  iwlwifi: mvm: accept arbitrary memory dump TLVs
  iwlwifi: mvm: make iwl_dump_prph() void
  iwlwifi: allow memory debug TLV to specify the memory type
  iwlwifi: mvm: properly check for transport data in dump

Jürg Billeter (1):
  iwlwifi: fix MODULE_FIRMWARE for 6030

Kirtika Ruchandani (3):
  iwlwifi: mvm: rs: Remove unused 'mvmvif'/'mvmsta' variables
  iwlwifi: mvm: rs: Remove unused 'mcs' variable
  iwlwifi: pcie: trans: Remove unused 'shift_param'

Luca Coelho (7):
  iwlwifi: mvm: don't restart HW if suspend fails with unified image
  iwlwifi: mvm: bump max API to 28
  iwlwifi: mvm: remove unused variable in iwl_mvm_handle_statistics()
  iwlwifi: dvm: make rs_tl_get_load() return void
  iwlwifi: mvm: remove unused sta_id variable in
    iwl_mvm_change_queue_owner()
  iwlwifi: dvm: remove unused variable compiler warning in debugfs.c
  iwlwifi: mvm: mark ret as maybe_unused in iwl_dbgfs_fw_restart_write()

Sara Sharon (9):
  iwlwifi: mvm: simplify paging allocation code
  iwlwifi: mvm: replace the number of blocks calculation
  iwlwifi: enlarge number of ucode sections
  iwlwifi: mvm: change iwl_mvm_tx_csum to return value
  iwlwifi: mvm: separate rate calculation to a new function
  iwlwifi: mvm: support version 2 of stored beacon notification
  iwlwifi: pcie: cleanup rfkill checks
  iwlwifi: mvm: use mvm_disable_queue instead of sharing logic
  iwlwifi: mvm: cleanup redundant assignment

 drivers/net/wireless/intel/iwlwifi/dvm/debugfs.c  |   2 +-
 drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c |   2 +-
 drivers/net/wireless/intel/iwlwifi/dvm/rs.c       |  11 +-
 drivers/net/wireless/intel/iwlwifi/dvm/ucode.c    |   2 +-
 drivers/net/wireless/intel/iwlwifi/iwl-6000.c     |   2 +-
 drivers/net/wireless/intel/iwlwifi/iwl-7000.c     |   4 +-
 drivers/net/wireless/intel/iwlwifi/iwl-8000.c     |   4 +-
 drivers/net/wireless/intel/iwlwifi/iwl-9000.c     |   2 +-
 drivers/net/wireless/intel/iwlwifi/iwl-a000.c     |   2 +-
 drivers/net/wireless/intel/iwlwifi/iwl-drv.c      |  98 +++++++++--------
 drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h  |  24 ++---
 drivers/net/wireless/intel/iwlwifi/iwl-fw.h       |   7 +-
 drivers/net/wireless/intel/iwlwifi/mvm/d3.c       |  13 ++-
 drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c  |   2 +-
 drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h   |   6 +-
 drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c   | 123 ++++++++++++++--------
 drivers/net/wireless/intel/iwlwifi/mvm/fw.c       |  69 ++++--------
 drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c |   2 +-
 drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c |   9 +-
 drivers/net/wireless/intel/iwlwifi/mvm/mvm.h      |   4 +-
 drivers/net/wireless/intel/iwlwifi/mvm/rs.c       |  10 +-
 drivers/net/wireless/intel/iwlwifi/mvm/rx.c       |   2 -
 drivers/net/wireless/intel/iwlwifi/mvm/sta.c      |  24 ++---
 drivers/net/wireless/intel/iwlwifi/mvm/tx.c       | 107 ++++++++++---------
 drivers/net/wireless/intel/iwlwifi/mvm/utils.c    |  14 ++-
 drivers/net/wireless/intel/iwlwifi/pcie/trans.c   |  51 ++++-----
 26 files changed, 299 insertions(+), 297 deletions(-)

-- 
2.11.0

^ permalink raw reply

* pull-request: iwlwifi 2017-01-23
From: Luca Coelho @ 2017-01-23 20:50 UTC (permalink / raw)
  To: kvalo; +Cc: linux-wireless

[-- Attachment #1: Type: text/plain, Size: 1537 bytes --]

Hi Kalle,

After a long time (too long time, I admit), here comes a pull request
with two fixes intended for v4.10.  Nothing major, just two small fixes
that were pending in our internal trees.  I have some more, but I'm
keeping this small for the -rc series.  More details in the tag
description.

I have sent this out before and kbuildbot didn't find any issues.

Cheers,
Luca.



The following changes since commit 92549cdc288f47f3a98cf80ac5890c91f5876a06:

  iwlwifi: fix kernel crash when unregistering thermal zone (2017-01-21 14:58:37 +0200)

are available in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-fixes.git tags/iwlwifi-for-kalle-2017-01-23

for you to fetch changes up to 03c902bff524e0cf664737a33f2365f7837040bf:

  iwlwifi: mvm: avoid crash on restart w/o reserved queues (2017-01-23 12:55:32 +0200)

----------------------------------------------------------------
* Remove an extra hyphen from a string that was preventing the firmware to load
* Avoid a crash when the firmware is restarted in certain scenarios with DQA

----------------------------------------------------------------
Johannes Berg (1):
      iwlwifi: mvm: avoid crash on restart w/o reserved queues

Jürg Billeter (1):
      iwlwifi: fix double hyphen in MODULE_FIRMWARE for 8000

 drivers/net/wireless/intel/iwlwifi/iwl-8000.c | 2 +-
 drivers/net/wireless/intel/iwlwifi/mvm/sta.c  | 7 ++++---
 2 files changed, 5 insertions(+), 4 deletions(-)

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply

* Re: [RFC 0/1] ath9k: Frame corruption simulator
From: Ben Greear @ 2017-01-23 19:57 UTC (permalink / raw)
  To: Wojciech Dubowik; +Cc: linux-wireless, kvalo
In-Reply-To: <86f1a341-f1f4-7d49-9cf2-88aa815b0890@neratec.com>

On 01/20/2017 07:26 AM, Wojciech Dubowik wrote:
>
>
> On 20/01/17 15:45, Ben Greear wrote:
>>
>>
>> On 01/20/2017 06:29 AM, Wojciech Dubowik wrote:
>>> I have been debugging customer reported timeout and loss of
>>> communication and I have relaized that I don't have such a lossy
>>> environment available in the lab. To speed up debugging I have
>>> written frame corruption simulator which will allow me to
>>> totally loose specific types of packets. I have been mostly
>>> using it with the mask 0x5000 which drops some EAPOL
>>> and deauthentication frames. This way I was able to test better
>>> timeouts and fail paths.
>>> At the moment only management, null function and EAPOL frames
>>> are supported. One can add more if necessary.
>>
>> Would it be worth having a unique percentage configurable for each
>> of the selected packet types?
> I wanted to keep it simple. I have been just repeating test when I didn't have
> luck with specific frame loss sequence. In real life conditions frame are not lost
> more or less depending on the type. Unless there is a hacker behind;o)
>>
>> How about moving this up into mac80211 so other drivers could
>> be supported as well?  Couldn't you just drop the frames instead
>> of corrupting their checksum?  That would work with things like ath10k
>> as well.
> I have started so but then:
>  1) no more tx flags available

Look through the kernel code for SO_NOFCS.  I bet that path would give you
the ability to pass down a corrupted FCS on demand.

>  2) how other drivers can handle tx frame corruption in HW so it is eqivalent
>   to frame corruption in the air
>  3) info.control.flags are being freed at some point in ath9k and I don't know
>    how it works in other drivers
>  4) dropping is not equal tx failed with no ack as status for tx drop status is always ok
> seen from mac layer.

You should be able to lie to the mac80211 stack and tell it the frame had a tx-failure.

I also plan to start hacking some logic into wpa_supplicant later this week to allow it to delay and/or
corrupt the 4-way auth messages (and others after that).  That feature may also help
with your testing...

Thanks,
Ben

>   For example it makes a difference for hostapd with EAPOL TX Status. There, mlme
>  sends an event when no ack is received and whole series failed. Actually one could
> specify whether to drop, to corrupt or just add random data.
>
> Wojtek
>>
>> I would like to have something like this, but with the added ability
>> to corrupt specific things like information-elements in management
>> frames to better test the receiver's packet parsing and error checking
>> logic.  For this feature, checksum would not be corrupted.
>>
>> Thanks,
>> Ben
>


-- 
Ben Greear <greearb@candelatech.com>
Candela Technologies Inc  http://www.candelatech.com

^ permalink raw reply

* Re: Strange Behaviors in 802.11 Association MLME
From: Johannes Berg @ 2017-01-23 16:29 UTC (permalink / raw)
  To: Jinghao Shi, linux-wireless
  Cc: Geoffrey Challen, Shuvendu Lahiri, Ranveer Chandra
In-Reply-To: <CAKdW-HF5R2=mGUvqvdAdhx2EAXmmZaRh9GvnMemxE+GYEXBQQQ@mail.gmail.com>

On Mon, 2017-01-16 at 16:16 -0500, Jinghao Shi wrote:
> Hi,
> 
> We're working on a formal validation framework for wireless protocol
> implementations. We have performed experiments on the 802.11
> association state machine and have found peculiar association
> behaviors.We'd like to share our findings to the community and
> confirm
> whether they reveal potential implementation bugs.
> 
> TLDR version: the client sends association request despite having
> received association response from the AP, is this a bug?
> 
> We utilized a real time reactive packet jammer to create the
> following
> packet loss pattern (the rate control policy was set to re-transmit
> the packet at most once before reporting the packet as failed. This
> may not be realistic in practice but helps reveal interesting
> behaviors faster.)
> 
>  - ASSOC_REQ (received by the AP, confirmed by the following
> ASSOC_RESP)
>  - ACK <---- JAMMED
>  - ASSOC_REQ_RETRY <----- JAMMED, the driver will declare this packet
> as failed
>  - ASSOC_RESP (received by the client, confirmed by the following
> ACK)
>  - ACK
>  - ASSOC_REQ <--- problematic packet
>  - ...

I don't really see a problem. We assume that the packet was lost due to
the missing ACK, so instead of waiting for a long time, we transmit a
new one. Typically, a missing ACK is far less likely than a missing
frame.

If, as here, the association response arrives, we should properly act
on it either way.

johannes

^ permalink raw reply

* [PATCH 2/3] ath10k: use dma_zalloc_coherent()
From: Srinivas Kandagatla @ 2017-01-23 15:04 UTC (permalink / raw)
  To: Kalle Valo
  Cc: ath10k, linux-wireless, netdev, linux-kernel, Srinivas Kandagatla
In-Reply-To: <1485183876-27080-1-git-send-email-srinivas.kandagatla@linaro.org>

use dma_zalloc_coherent() instead of dma_alloc_coherent and memset().

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 drivers/net/wireless/ath/ath10k/ce.c  | 9 +--------
 drivers/net/wireless/ath/ath10k/pci.c | 3 +--
 2 files changed, 2 insertions(+), 10 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c
index 0b4d796..c2b388f 100644
--- a/drivers/net/wireless/ath/ath10k/ce.c
+++ b/drivers/net/wireless/ath/ath10k/ce.c
@@ -958,7 +958,7 @@ ath10k_ce_alloc_dest_ring(struct ath10k *ar, unsigned int ce_id,
 	 * coherent DMA are unsupported
 	 */
 	dest_ring->base_addr_owner_space_unaligned =
-		dma_alloc_coherent(ar->dev,
+		dma_zalloc_coherent(ar->dev,
 				   (nentries * sizeof(struct ce_desc) +
 				    CE_DESC_RING_ALIGN),
 				   &base_addr, GFP_KERNEL);
@@ -969,13 +969,6 @@ ath10k_ce_alloc_dest_ring(struct ath10k *ar, unsigned int ce_id,
 
 	dest_ring->base_addr_ce_space_unaligned = base_addr;
 
-	/*
-	 * Correctly initialize memory to 0 to prevent garbage
-	 * data crashing system when download firmware
-	 */
-	memset(dest_ring->base_addr_owner_space_unaligned, 0,
-	       nentries * sizeof(struct ce_desc) + CE_DESC_RING_ALIGN);
-
 	dest_ring->base_addr_owner_space = PTR_ALIGN(
 			dest_ring->base_addr_owner_space_unaligned,
 			CE_DESC_RING_ALIGN);
diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index b541a1c..855e3de 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -896,7 +896,7 @@ static int ath10k_pci_diag_read_mem(struct ath10k *ar, u32 address, void *data,
 	 */
 	alloc_nbytes = min_t(unsigned int, nbytes, DIAG_TRANSFER_LIMIT);
 
-	data_buf = (unsigned char *)dma_alloc_coherent(ar->dev,
+	data_buf = (unsigned char *)dma_zalloc_coherent(ar->dev,
 						       alloc_nbytes,
 						       &ce_data_base,
 						       GFP_ATOMIC);
@@ -905,7 +905,6 @@ static int ath10k_pci_diag_read_mem(struct ath10k *ar, u32 address, void *data,
 		ret = -ENOMEM;
 		goto done;
 	}
-	memset(data_buf, 0, alloc_nbytes);
 
 	remaining_bytes = nbytes;
 	ce_data = ce_data_base;
-- 
2.10.1

^ permalink raw reply related

* [PATCH 3/3] ath10k: fix typo in addr calculation
From: Srinivas Kandagatla @ 2017-01-23 15:04 UTC (permalink / raw)
  To: Kalle Valo
  Cc: ath10k, linux-wireless, netdev, linux-kernel, Srinivas Kandagatla
In-Reply-To: <1485183876-27080-1-git-send-email-srinivas.kandagatla@linaro.org>

CORE_CTRL_ADDRESS is offset in register address space, it does not
make sense to OR it to derive the final address. It looks like its
a typo, so fix it.
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 drivers/net/wireless/ath/ath10k/pci.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index 855e3de..023ab10 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -1936,7 +1936,7 @@ static int ath10k_pci_wake_target_cpu(struct ath10k *ar)
 {
 	u32 addr, val;
 
-	addr = SOC_CORE_BASE_ADDRESS | CORE_CTRL_ADDRESS;
+	addr = SOC_CORE_BASE_ADDRESS + CORE_CTRL_ADDRESS;
 	val = ath10k_pci_read32(ar, addr);
 	val |= CORE_CTRL_CPU_INTR_MASK;
 	ath10k_pci_write32(ar, addr, val);
-- 
2.10.1

^ permalink raw reply related

* [PATCH 1/3] ath10k: remove multiple defines of DIAG_TRANSFER_LIMIT
From: Srinivas Kandagatla @ 2017-01-23 15:04 UTC (permalink / raw)
  To: Kalle Valo
  Cc: ath10k, linux-wireless, netdev, linux-kernel, Srinivas Kandagatla

DIAG_TRANSFER_LIMIT is redefined with same value and comments
just below this entry, remove this duplicate entry.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 drivers/net/wireless/ath/ath10k/pci.h | 5 -----
 1 file changed, 5 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/pci.h b/drivers/net/wireless/ath/ath10k/pci.h
index 9854ad5..c76789d 100644
--- a/drivers/net/wireless/ath/ath10k/pci.h
+++ b/drivers/net/wireless/ath/ath10k/pci.h
@@ -25,11 +25,6 @@
 #include "ahb.h"
 
 /*
- * maximum number of bytes that can be handled atomically by DiagRead/DiagWrite
- */
-#define DIAG_TRANSFER_LIMIT 2048
-
-/*
  * maximum number of bytes that can be
  * handled atomically by DiagRead/DiagWrite
  */
-- 
2.10.1

^ permalink raw reply related

* Re: [PATCH v2 01/13] wil6210: add sysfs file for FTM calibration
From: Lior David @ 2017-01-23 14:55 UTC (permalink / raw)
  To: Arend Van Spriel, Valo, Kalle, qca_merez
  Cc: qca_liord, linux-wireless@vger.kernel.org, wil6210
In-Reply-To: <b7a8f918-7d3c-de53-d657-8e2d1c1da4b2@broadcom.com>

On 1/19/2017 3:14 PM, Arend Van Spriel wrote:
> On 19-1-2017 13:36, Lior David wrote:
>> On 1/19/2017 2:24 PM, Valo, Kalle wrote:
>>> Maya Erez <qca_merez@qca.qualcomm.com> writes:
>>>
>>>> From: Lior David <qca_liord@qca.qualcomm.com>
>>>>
>>>> In fine timing measurements, the calculation is affected by
>>>> 2 parts: timing of packets over the air, which is platform
>>>> independent, and platform-specific delays, which are dependent
>>>> on things like antenna cable length and type.
>>>> Add a sysfs file which allows to get/set these platform specific
>>>> delays, separated into the TX and RX components.
>>>> There are 2 key scenarios where the file can be used:
>>>> 1. Calibration - start with some initial values (for example,
>>>> the default values at startup), make measurements at a known
>>>> distance, then iteratively change the values until the
>>>> measurement results match the known distance.
>>>> 2. Adjust the delays when platform starts up, based on known
>>>> values.
>>>>
>>>> Signed-off-by: Lior David <qca_liord@qca.qualcomm.com>
>>>> Signed-off-by: Maya Erez <qca_merez@qca.qualcomm.com>
>>>
>>> Can't this go via nl80211? sysfs is not really supposed to be used for
>>> something like this.
>>>
>> There is no nl80211 API for this (yet?).
> 
> So come up with one...?
I checked this further and had some more internal discussion.
This change is only about FTM calibration which is highly vendor specific so I
don't think NL80211 API is appropriate for it. Since it is needed in production
(to calibrate the platform after boot using pre-computed values), I think sysfs
is a reasonable place for it.

> 
>> Will it be ok to put this in debugfs? Normally this will be in the board
>> file (as part of RF configuration) but it will be useful to play
>> with these values for debugging/diagnostics.
> 
> What is doing the FTM measurements? Is it all done in user-space? That
> would mean you also need measurement data exported to user-space. How is
> that done? Intel has a FTM api proposal, but it has not been submitted
> upstream (yet?).
> 
Our plan is to use the FTM API from intel once it is submitted upstream, but as
I said this change is about FTM calibration which is separate from the generic
FTM API.

Thanks,
Lior

^ permalink raw reply

* [PATCH 2/2] iwlwifi: mvm: avoid crash on restart w/o reserved queues
From: Luca Coelho @ 2017-01-23 11:56 UTC (permalink / raw)
  To: linux-wireless; +Cc: Johannes Berg, Luca Coelho
In-Reply-To: <20170123115622.23587-1-luca@coelho.fi>

From: Johannes Berg <johannes.berg@intel.com>

When the firmware restarts in a situation in which any station
has no queue reserved anymore because that queue was used, the
code will crash trying to access the queue_info array at the
offset 255, which is far too big. Fix this by checking that a
queue is actually reserved before writing its status.

Fixes: 8d98ae6eb0d5 ("iwlwifi: mvm: re-assign old queues after hw restart in dqa mode")
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
---
 drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
index 636c8b03e318..09e9e2e3ed04 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
@@ -1164,9 +1164,10 @@ static void iwl_mvm_realloc_queues_after_restart(struct iwl_mvm *mvm,
 		.frame_limit = IWL_FRAME_LIMIT,
 	};
 
-	/* Make sure reserved queue is still marked as such (or allocated) */
-	mvm->queue_info[mvm_sta->reserved_queue].status =
-		IWL_MVM_QUEUE_RESERVED;
+	/* Make sure reserved queue is still marked as such (if allocated) */
+	if (mvm_sta->reserved_queue != IEEE80211_INVAL_HW_QUEUE)
+		mvm->queue_info[mvm_sta->reserved_queue].status =
+			IWL_MVM_QUEUE_RESERVED;
 
 	for (i = 0; i <= IWL_MAX_TID_COUNT; i++) {
 		struct iwl_mvm_tid_data *tid_data = &mvm_sta->tid_data[i];
-- 
2.11.0

^ permalink raw reply related

* [PATCH 1/2] iwlwifi: fix double hyphen in MODULE_FIRMWARE for 8000
From: Luca Coelho @ 2017-01-23 11:56 UTC (permalink / raw)
  To: linux-wireless; +Cc: Jürg Billeter, Luca Coelho
In-Reply-To: <20170123115622.23587-1-luca@coelho.fi>

From: Jürg Billeter <j@bitron.ch>

Mistakenly, the driver is trying to load the 8000C firmware with an
incorrect name (i.e. with two hyphens where there should be only one)
and that fails.  Fix that by removing the hyphen from the format
macro.

Fixes: e1ba684f762b ("iwlwifi: 8000: fix MODULE_FIRMWARE input")
Signed-off-by: Jürg Billeter <j@bitron.ch>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
---
 drivers/net/wireless/intel/iwlwifi/iwl-8000.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-8000.c b/drivers/net/wireless/intel/iwlwifi/iwl-8000.c
index d02ca1491d16..8d3e53fac1da 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-8000.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-8000.c
@@ -91,7 +91,7 @@
 
 #define IWL8000_FW_PRE "iwlwifi-8000C-"
 #define IWL8000_MODULE_FIRMWARE(api) \
-	IWL8000_FW_PRE "-" __stringify(api) ".ucode"
+	IWL8000_FW_PRE __stringify(api) ".ucode"
 
 #define IWL8265_FW_PRE "iwlwifi-8265-"
 #define IWL8265_MODULE_FIRMWARE(api) \
-- 
2.11.0

^ permalink raw reply related

* [PATCH 0/2] iwlwifi: updates intended for v4.10 2017-01-23
From: Luca Coelho @ 2017-01-23 11:56 UTC (permalink / raw)
  To: linux-wireless; +Cc: Luca Coelho

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset=UTF-8, Size: 551 bytes --]

From: Luca Coelho <luciano.coelho@intel.com>

Hi,

These are a couple of fixes intended for v4.10.  One avoids a crash in
specific scenarios, the other prevents a firmware load failure due to
wrong file name.

--
Luca.

Johannes Berg (1):
  iwlwifi: mvm: avoid crash on restart w/o reserved queues

Jürg Billeter (1):
  iwlwifi: fix double hyphen in MODULE_FIRMWARE for 8000

 drivers/net/wireless/intel/iwlwifi/iwl-8000.c | 2 +-
 drivers/net/wireless/intel/iwlwifi/mvm/sta.c  | 7 ++++---
 2 files changed, 5 insertions(+), 4 deletions(-)

-- 
2.11.0

^ permalink raw reply

* Re: [RFC v3 0/8] ath10k sdio support
From: Valo, Kalle @ 2017-01-23 11:08 UTC (permalink / raw)
  To: Erik Stromdahl; +Cc: linux-wireless@vger.kernel.org, ath10k@lists.infradead.org
In-Reply-To: <1484342771-6160-1-git-send-email-erik.stromdahl@gmail.com>

Erik Stromdahl <erik.stromdahl@gmail.com> writes:

> This is the third version of the sdio RFC patch series.
> The actual sdio code (patch 6) has been subject to a massive overhaul,
> mainly as a result of Kalle's review comments.
> It no longer has any strong resemblance of the original ath6kl code from
> which it was originally based upon.
>
> Previous pathes 6 to 10 have been merged into one single patch.
>
> The previous series had a rework of the "HTC fake service" connect
> (ep 0 connect) that introduced a race between the actual endpoint
> connect and the HTC ready message. This issue has been addressed,
> and the current patches (3 and 4) has been rewritten accordingly.
>
> * overview of patches *
>
> Patches 1 to 4 are more or less identical to the previous RFC, with an
> exception for patch 3 that changes the "HTC fake service" connect
> (mentioned above).
>
> Patch 5 is a squashed version of previous patches 6 to 10.
>
> Patch 6 is the actual sdio patch
>
> Patches 7 to 8 are new and adds special sdio versions of BMI get
> target info and HTC ready.
>
> The new version was built and tested against:
> tag: ath-201701121109
>
> Erik Stromdahl (8):
>   ath10k: htc: made static function public
>   ath10k: htc: rx trailer lookahead support
>   ath10k: htc: move htc ctrl ep connect to htc_init
>   ath10k: htc: refactorization
>   ath10k: various sdio related definitions
>   ath10k: sdio support
>   ath10k: sdio get target info
>   ath10k: htc: ready_ext msg support

I pushed now this, and your usb series as well, to ath.git
master-pending branch. Let's see if kbuild bot finds any problems.

--=20
Kalle Valo=

^ permalink raw reply

* Re: [PATCH 0/6] iwlwifi: updates intended for v4.10 2017-01-13
From: Coelho, Luciano @ 2017-01-23 10:59 UTC (permalink / raw)
  To: linux-wireless@vger.kernel.org
In-Reply-To: <20170113123919.30384-1-luca@coelho.fi>

T24gRnJpLCAyMDE3LTAxLTEzIGF0IDE0OjM5ICswMjAwLCBMdWNhIENvZWxobyB3cm90ZToNCj4g
RnJvbTogTHVjYSBDb2VsaG8gPGx1Y2lhbm8uY29lbGhvQGludGVsLmNvbT4NCj4gDQo+IEhpLA0K
PiANCj4gSGVyZSBhcmUgYSBmZXcgZml4ZXMgdGhhdCBJIGludGVuZCB0byBzZW5kIGZvciB2NC4x
MDoNCj4gDQo+ICogZml4IHN1c3BlbmQgZmFpbHVyZSB3aXRoIHVuaWZpZWQgZmlybXdhcmUgaW1h
Z2VzDQo+ICogZml4IGEgcG90ZW50aWFsIGNyYXNoIHdoZW4gZHVtcGluZyBkZWJ1ZyBkYXRhDQo+
ICogZml4IGEgY291cGxlIG9mIG1pc3Rha2VzIGluIEZXIG5hbWVzIGV4cG9ydGVkIGJ5IHRoZSBt
b2R1bGVzDQo+ICogc21hbGwgZml4IGZvciBQUy1Qb2xsIGVuYWJsaW5nIHZpYSBkZWJ1Z2ZzDQo+
ICogZml4IGZvciBkeW5hbWljIHF1ZXVlIGFsbG9jYXRpb24gb2ZmY2hhbm5lbCBkYXRhDQoNCkFz
IGRpc2N1c3NlZCBvbiBJUkMsIGl0IGdvdCBhIGJpdCBsYXRlIGZvciBzb21lIG9mIHRoZXNlIHBh
dGNoZXMgKGR1ZSB0bw0KbXkgdHJpcCBsYXN0IHdlZWspLiAgU28sIGxldCdzIGlnbm9yZSB0aGlz
IGFuZCBJJ2xsIHNlbmQgYSBuZXcgdmVyc2lvbg0Kd2l0aCBsZXNzIHBhdGNoZXMgdG9kYXkuDQoN
Ci0tDQpMdWNhLg==

^ permalink raw reply

* [PATCH] mac80211: don't try to sleep in rate_control_rate_init()
From: Johannes Berg @ 2017-01-23  8:41 UTC (permalink / raw)
  To: linux-wireless; +Cc: Johannes Berg

From: Johannes Berg <johannes.berg@intel.com>

In my previous patch, I missed that rate_control_rate_init() is
called from some places that cannot sleep, so it cannot call
ieee80211_recalc_min_chandef(). Remove that call for now to fix
the context bug, we'll have to find a different way to fix the
minimum channel width issue.

Fixes: 96aa2e7cf126 ("mac80211: calculate min channel width correctly")
Reported-by: Xiaolong Ye (via lkp-robot) <xiaolong.ye@intel.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
 net/mac80211/rate.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c
index 9e2641d45587..206698bc93f4 100644
--- a/net/mac80211/rate.c
+++ b/net/mac80211/rate.c
@@ -40,8 +40,6 @@ void rate_control_rate_init(struct sta_info *sta)
 
 	ieee80211_sta_set_rx_nss(sta);
 
-	ieee80211_recalc_min_chandef(sta->sdata);
-
 	if (!ref)
 		return;
 
-- 
2.9.3

^ permalink raw reply related

* [PATCH] nfc: nxp-nci: use msleep for long delays
From: Nicholas Mc Guire @ 2017-01-22 12:28 UTC (permalink / raw)
  To: Clement Perrochaud
  Cc: Charles Gorand, Lauro Ramos Venancio, Aloisio Almeida Jr,
	Samuel Ortiz, linux-nfc, linux-wireless, linux-kernel,
	Nicholas Mc Guire, Nicholas Mc Guire

ulseep_range() uses hrtimers and provides no advantage over msleep()
for larger delays. For this large delay msleep() is preferable.

Fixes: commit 6be88670fc59 ("NFC: nxp-nci_i2c: Add I2C support to NXP NCI driver")
Link: http://lkml.org/lkml/2017/1/11/377
Signed-off-by: Nicholas Mc Guire <hofrat@osadl.org>
---
Problem was found by cocinelle script.

nxp_nci_i2c_write takes the negative return code as indicator that the
NFC device was probably in stand-by mode, the first transaction attempt
woke it up and that after 110ms latest it would be ready to receive.
Overrunning this time by a few milliseconds will not hurt though so
msleep() should be fine here.

Patch was compile tested with: x86_64_defconfig + CONFIG_NFC=m,
CONFIG_NFC_NCI=m, CONFIG_NFC_NXP_NCI=m, CONFIG_NFC_NXP_NCI_I2C=m

Patch is against 4.10-rc4 (localversion-next is next-20170120)

 drivers/nfc/nxp-nci/i2c.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/nfc/nxp-nci/i2c.c b/drivers/nfc/nxp-nci/i2c.c
index 36099e5..ceb815c 100644
--- a/drivers/nfc/nxp-nci/i2c.c
+++ b/drivers/nfc/nxp-nci/i2c.c
@@ -86,7 +86,7 @@ static int nxp_nci_i2c_write(void *phy_id, struct sk_buff *skb)
 	r = i2c_master_send(client, skb->data, skb->len);
 	if (r < 0) {
 		/* Retry, chip was in standby */
-		usleep_range(110000, 120000);
+		msleep(110);
 		r = i2c_master_send(client, skb->data, skb->len);
 	}
 
-- 
2.1.4

^ permalink raw reply related

* Re: [PATCH net-next v5] bridge: multicast to unicast
From: Nikolay Aleksandrov @ 2017-01-21 22:29 UTC (permalink / raw)
  To: Linus Lüssing, netdev
  Cc: David S . Miller, Stephen Hemminger, Felix Fietkau, bridge,
	linux-kernel, linux-wireless
In-Reply-To: <20170121200133.1864-1-linus.luessing@c0d3.blue>

On 21/01/17 21:01, Linus Lüssing wrote:
> From: Felix Fietkau <nbd@nbd.name>
> 
> Implements an optional, per bridge port flag and feature to deliver
> multicast packets to any host on the according port via unicast
> individually. This is done by copying the packet per host and
> changing the multicast destination MAC to a unicast one accordingly.
> 
> multicast-to-unicast works on top of the multicast snooping feature of
> the bridge. Which means unicast copies are only delivered to hosts which
> are interested in it and signalized this via IGMP/MLD reports
> previously.
> 
> This feature is intended for interface types which have a more reliable
> and/or efficient way to deliver unicast packets than broadcast ones
> (e.g. wifi).
> 
> However, it should only be enabled on interfaces where no IGMPv2/MLDv1
> report suppression takes place. This feature is disabled by default.
> 
> The initial patch and idea is from Felix Fietkau.
> 
> Signed-off-by: Felix Fietkau <nbd@nbd.name>
> [linus.luessing@c0d3.blue: various bug + style fixes, commit message]
> Signed-off-by: Linus Lüssing <linus.luessing@c0d3.blue>
> 
> ---
> 
> This feature is used and enabled by default in OpenWRT and LEDE for AP
> interfaces for more than a year now to allow both a more robust multicast
> delivery and multicast at higher rates (e.g. multicast streaming).
> 
> In OpenWRT/LEDE the IGMP/MLD report suppression issue is overcome by
> the network daemon enabling AP isolation and by that separating all STAs.
> Delivery of STA-to-STA IP mulitcast is made possible again by
> enabling and utilizing the bridge hairpin mode, which considers the
> incoming port as a potential outgoing port, too.
> 
> Hairpin-mode is performed after multicast snooping, therefore leading to
> only deliver reports to STAs running a multicast router.
> 
> Changes in v5:
> * fix a potential pagefault in br_ip6_multicast_mld2_report():
>   -> a pskb_may_pull() might reallocate skb->data, therefore perform
>      the "src = eth_hdr(skb)->h_source" only afterwards
> * simplify code by always adding ether source address to a port group
>   and checking the per-port multicast-to-unicast flag instead of a
>   per-port-group one (thanks Stephen!)
> 
> Changes in v4:
> * readd "From: Felix Fietkau [...]" (missed it again in v3)
> 
> Changes in v3:
> * fix an uninitialized variable bug introduced in br_multicast_flood()
>   in v2, found by kbuild test bot
> 
> Changes in v2:
> * netlink support (thanks Nik!)
> * fixed switching between multicast_to_unicast on/off
>   -> even after toggling an already existing entry would
>      stale in its mode and would never be replaced
>   -> new extra check in br_port_group_equal)
> * reduced checks in br_multicast_flood() from two to one
>   to address fast-path concerns (thanks Nik!)
> * rev-christmas tree ordering (thanks Nik!)
> * removed "net_bridge_port_group::unicast", using
>   ::flags instead (thanks Nik!)
> * BR_MULTICAST_TO_UCAST -> BR_MULTICAST_TO_UNICAST
>   (BR_MULTICAST_FLAST_LEAVE has the same length anyway)
> * simplified maybe_deliver_addr()
>   (no return, no "prev" paramater -> was a NOP anyway)
> * added "From: Felix Fietkau [...]"
> * added "Signed-off-by: Felix Fietkau [...]"
> ---
>  include/linux/if_bridge.h    |  1 +
>  include/uapi/linux/if_link.h |  1 +
>  net/bridge/br_forward.c      | 39 ++++++++++++++++++-
>  net/bridge/br_mdb.c          |  2 +-
>  net/bridge/br_multicast.c    | 90 ++++++++++++++++++++++++++++++++------------
>  net/bridge/br_netlink.c      |  5 +++
>  net/bridge/br_private.h      |  3 +-
>  net/bridge/br_sysfs_if.c     |  2 +
>  8 files changed, 114 insertions(+), 29 deletions(-)
> 

Reviewed-by: Nikolay Aleksandrov <nikolay@cumulusnetworks.com>

^ permalink raw reply

* [PATCH net-next v5] bridge: multicast to unicast
From: Linus Lüssing @ 2017-01-21 20:01 UTC (permalink / raw)
  To: netdev
  Cc: David S . Miller, Stephen Hemminger, Felix Fietkau,
	Nikolay Aleksandrov, bridge, linux-kernel, linux-wireless,
	Linus Lüssing

From: Felix Fietkau <nbd@nbd.name>

Implements an optional, per bridge port flag and feature to deliver
multicast packets to any host on the according port via unicast
individually. This is done by copying the packet per host and
changing the multicast destination MAC to a unicast one accordingly.

multicast-to-unicast works on top of the multicast snooping feature of
the bridge. Which means unicast copies are only delivered to hosts which
are interested in it and signalized this via IGMP/MLD reports
previously.

This feature is intended for interface types which have a more reliable
and/or efficient way to deliver unicast packets than broadcast ones
(e.g. wifi).

However, it should only be enabled on interfaces where no IGMPv2/MLDv1
report suppression takes place. This feature is disabled by default.

The initial patch and idea is from Felix Fietkau.

Signed-off-by: Felix Fietkau <nbd@nbd.name>
[linus.luessing@c0d3.blue: various bug + style fixes, commit message]
Signed-off-by: Linus Lüssing <linus.luessing@c0d3.blue>

---

This feature is used and enabled by default in OpenWRT and LEDE for AP
interfaces for more than a year now to allow both a more robust multicast
delivery and multicast at higher rates (e.g. multicast streaming).

In OpenWRT/LEDE the IGMP/MLD report suppression issue is overcome by
the network daemon enabling AP isolation and by that separating all STAs.
Delivery of STA-to-STA IP mulitcast is made possible again by
enabling and utilizing the bridge hairpin mode, which considers the
incoming port as a potential outgoing port, too.

Hairpin-mode is performed after multicast snooping, therefore leading to
only deliver reports to STAs running a multicast router.

Changes in v5:
* fix a potential pagefault in br_ip6_multicast_mld2_report():
  -> a pskb_may_pull() might reallocate skb->data, therefore perform
     the "src = eth_hdr(skb)->h_source" only afterwards
* simplify code by always adding ether source address to a port group
  and checking the per-port multicast-to-unicast flag instead of a
  per-port-group one (thanks Stephen!)

Changes in v4:
* readd "From: Felix Fietkau [...]" (missed it again in v3)

Changes in v3:
* fix an uninitialized variable bug introduced in br_multicast_flood()
  in v2, found by kbuild test bot

Changes in v2:
* netlink support (thanks Nik!)
* fixed switching between multicast_to_unicast on/off
  -> even after toggling an already existing entry would
     stale in its mode and would never be replaced
  -> new extra check in br_port_group_equal)
* reduced checks in br_multicast_flood() from two to one
  to address fast-path concerns (thanks Nik!)
* rev-christmas tree ordering (thanks Nik!)
* removed "net_bridge_port_group::unicast", using
  ::flags instead (thanks Nik!)
* BR_MULTICAST_TO_UCAST -> BR_MULTICAST_TO_UNICAST
  (BR_MULTICAST_FLAST_LEAVE has the same length anyway)
* simplified maybe_deliver_addr()
  (no return, no "prev" paramater -> was a NOP anyway)
* added "From: Felix Fietkau [...]"
* added "Signed-off-by: Felix Fietkau [...]"
---
 include/linux/if_bridge.h    |  1 +
 include/uapi/linux/if_link.h |  1 +
 net/bridge/br_forward.c      | 39 ++++++++++++++++++-
 net/bridge/br_mdb.c          |  2 +-
 net/bridge/br_multicast.c    | 90 ++++++++++++++++++++++++++++++++------------
 net/bridge/br_netlink.c      |  5 +++
 net/bridge/br_private.h      |  3 +-
 net/bridge/br_sysfs_if.c     |  2 +
 8 files changed, 114 insertions(+), 29 deletions(-)

diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h
index c6587c0..debc9d5 100644
--- a/include/linux/if_bridge.h
+++ b/include/linux/if_bridge.h
@@ -46,6 +46,7 @@ struct br_ip_list {
 #define BR_LEARNING_SYNC	BIT(9)
 #define BR_PROXYARP_WIFI	BIT(10)
 #define BR_MCAST_FLOOD		BIT(11)
+#define BR_MULTICAST_TO_UNICAST	BIT(12)
 
 #define BR_DEFAULT_AGEING_TIME	(300 * HZ)
 
diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h
index 6b13e59..4e59565 100644
--- a/include/uapi/linux/if_link.h
+++ b/include/uapi/linux/if_link.h
@@ -321,6 +321,7 @@ enum {
 	IFLA_BRPORT_MULTICAST_ROUTER,
 	IFLA_BRPORT_PAD,
 	IFLA_BRPORT_MCAST_FLOOD,
+	IFLA_BRPORT_MCAST_TO_UCAST,
 	__IFLA_BRPORT_MAX
 };
 #define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1)
diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c
index 7cb41ae..a0f9d00 100644
--- a/net/bridge/br_forward.c
+++ b/net/bridge/br_forward.c
@@ -174,6 +174,31 @@ static struct net_bridge_port *maybe_deliver(
 	return p;
 }
 
+static void maybe_deliver_addr(struct net_bridge_port *p, struct sk_buff *skb,
+			       const unsigned char *addr, bool local_orig)
+{
+	struct net_device *dev = BR_INPUT_SKB_CB(skb)->brdev;
+	const unsigned char *src = eth_hdr(skb)->h_source;
+
+	if (!should_deliver(p, skb))
+		return;
+
+	/* Even with hairpin, no soliloquies - prevent breaking IPv6 DAD */
+	if (skb->dev == p->dev && ether_addr_equal(src, addr))
+		return;
+
+	skb = skb_copy(skb, GFP_ATOMIC);
+	if (!skb) {
+		dev->stats.tx_dropped++;
+		return;
+	}
+
+	if (!is_broadcast_ether_addr(addr))
+		memcpy(eth_hdr(skb)->h_dest, addr, ETH_ALEN);
+
+	__br_forward(p, skb, local_orig);
+}
+
 /* called under rcu_read_lock */
 void br_flood(struct net_bridge *br, struct sk_buff *skb,
 	      enum br_pkt_type pkt_type, bool local_rcv, bool local_orig)
@@ -241,10 +266,20 @@ void br_multicast_flood(struct net_bridge_mdb_entry *mdst,
 		rport = rp ? hlist_entry(rp, struct net_bridge_port, rlist) :
 			     NULL;
 
-		port = (unsigned long)lport > (unsigned long)rport ?
-		       lport : rport;
+		if ((unsigned long)lport > (unsigned long)rport) {
+			port = lport;
+
+			if (port->flags & BR_MULTICAST_TO_UNICAST) {
+				maybe_deliver_addr(lport, skb, p->eth_addr,
+						   local_orig);
+				goto delivered;
+			}
+		} else {
+			port = rport;
+		}
 
 		prev = maybe_deliver(prev, port, skb, local_orig);
+delivered:
 		if (IS_ERR(prev))
 			goto out;
 		if (prev == port)
diff --git a/net/bridge/br_mdb.c b/net/bridge/br_mdb.c
index 7dbc80d..056e6ac 100644
--- a/net/bridge/br_mdb.c
+++ b/net/bridge/br_mdb.c
@@ -531,7 +531,7 @@ static int br_mdb_add_group(struct net_bridge *br, struct net_bridge_port *port,
 			break;
 	}
 
-	p = br_multicast_new_port_group(port, group, *pp, state);
+	p = br_multicast_new_port_group(port, group, *pp, state, NULL);
 	if (unlikely(!p))
 		return -ENOMEM;
 	rcu_assign_pointer(*pp, p);
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index b30e77e..7c9cc12 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -43,12 +43,14 @@ static void br_multicast_add_router(struct net_bridge *br,
 static void br_ip4_multicast_leave_group(struct net_bridge *br,
 					 struct net_bridge_port *port,
 					 __be32 group,
-					 __u16 vid);
+					 __u16 vid,
+					 const unsigned char *src);
+
 #if IS_ENABLED(CONFIG_IPV6)
 static void br_ip6_multicast_leave_group(struct net_bridge *br,
 					 struct net_bridge_port *port,
 					 const struct in6_addr *group,
-					 __u16 vid);
+					 __u16 vid, const unsigned char *src);
 #endif
 unsigned int br_mdb_rehash_seq;
 
@@ -711,7 +713,8 @@ struct net_bridge_port_group *br_multicast_new_port_group(
 			struct net_bridge_port *port,
 			struct br_ip *group,
 			struct net_bridge_port_group __rcu *next,
-			unsigned char flags)
+			unsigned char flags,
+			const unsigned char *src)
 {
 	struct net_bridge_port_group *p;
 
@@ -726,12 +729,32 @@ struct net_bridge_port_group *br_multicast_new_port_group(
 	hlist_add_head(&p->mglist, &port->mglist);
 	setup_timer(&p->timer, br_multicast_port_group_expired,
 		    (unsigned long)p);
+
+	if (src)
+		memcpy(p->eth_addr, src, ETH_ALEN);
+	else
+		memset(p->eth_addr, 0xff, ETH_ALEN);
+
 	return p;
 }
 
+static bool br_port_group_equal(struct net_bridge_port_group *p,
+				struct net_bridge_port *port,
+				const unsigned char *src)
+{
+	if (p->port != port)
+		return false;
+
+	if (!(port->flags & BR_MULTICAST_TO_UNICAST))
+		return true;
+
+	return ether_addr_equal(src, p->eth_addr);
+}
+
 static int br_multicast_add_group(struct net_bridge *br,
 				  struct net_bridge_port *port,
-				  struct br_ip *group)
+				  struct br_ip *group,
+				  const unsigned char *src)
 {
 	struct net_bridge_port_group __rcu **pp;
 	struct net_bridge_port_group *p;
@@ -758,13 +781,13 @@ static int br_multicast_add_group(struct net_bridge *br,
 	for (pp = &mp->ports;
 	     (p = mlock_dereference(*pp, br)) != NULL;
 	     pp = &p->next) {
-		if (p->port == port)
+		if (br_port_group_equal(p, port, src))
 			goto found;
 		if ((unsigned long)p->port < (unsigned long)port)
 			break;
 	}
 
-	p = br_multicast_new_port_group(port, group, *pp, 0);
+	p = br_multicast_new_port_group(port, group, *pp, 0, src);
 	if (unlikely(!p))
 		goto err;
 	rcu_assign_pointer(*pp, p);
@@ -783,7 +806,8 @@ static int br_multicast_add_group(struct net_bridge *br,
 static int br_ip4_multicast_add_group(struct net_bridge *br,
 				      struct net_bridge_port *port,
 				      __be32 group,
-				      __u16 vid)
+				      __u16 vid,
+				      const unsigned char *src)
 {
 	struct br_ip br_group;
 
@@ -794,14 +818,15 @@ static int br_ip4_multicast_add_group(struct net_bridge *br,
 	br_group.proto = htons(ETH_P_IP);
 	br_group.vid = vid;
 
-	return br_multicast_add_group(br, port, &br_group);
+	return br_multicast_add_group(br, port, &br_group, src);
 }
 
 #if IS_ENABLED(CONFIG_IPV6)
 static int br_ip6_multicast_add_group(struct net_bridge *br,
 				      struct net_bridge_port *port,
 				      const struct in6_addr *group,
-				      __u16 vid)
+				      __u16 vid,
+				      const unsigned char *src)
 {
 	struct br_ip br_group;
 
@@ -812,7 +837,7 @@ static int br_ip6_multicast_add_group(struct net_bridge *br,
 	br_group.proto = htons(ETH_P_IPV6);
 	br_group.vid = vid;
 
-	return br_multicast_add_group(br, port, &br_group);
+	return br_multicast_add_group(br, port, &br_group, src);
 }
 #endif
 
@@ -1081,6 +1106,7 @@ static int br_ip4_multicast_igmp3_report(struct net_bridge *br,
 					 struct sk_buff *skb,
 					 u16 vid)
 {
+	const unsigned char *src;
 	struct igmpv3_report *ih;
 	struct igmpv3_grec *grec;
 	int i;
@@ -1121,12 +1147,14 @@ static int br_ip4_multicast_igmp3_report(struct net_bridge *br,
 			continue;
 		}
 
+		src = eth_hdr(skb)->h_source;
 		if ((type == IGMPV3_CHANGE_TO_INCLUDE ||
 		     type == IGMPV3_MODE_IS_INCLUDE) &&
 		    ntohs(grec->grec_nsrcs) == 0) {
-			br_ip4_multicast_leave_group(br, port, group, vid);
+			br_ip4_multicast_leave_group(br, port, group, vid, src);
 		} else {
-			err = br_ip4_multicast_add_group(br, port, group, vid);
+			err = br_ip4_multicast_add_group(br, port, group, vid,
+							 src);
 			if (err)
 				break;
 		}
@@ -1141,6 +1169,7 @@ static int br_ip6_multicast_mld2_report(struct net_bridge *br,
 					struct sk_buff *skb,
 					u16 vid)
 {
+	const unsigned char *src;
 	struct icmp6hdr *icmp6h;
 	struct mld2_grec *grec;
 	int i;
@@ -1188,14 +1217,16 @@ static int br_ip6_multicast_mld2_report(struct net_bridge *br,
 			continue;
 		}
 
+		src = eth_hdr(skb)->h_source;
 		if ((grec->grec_type == MLD2_CHANGE_TO_INCLUDE ||
 		     grec->grec_type == MLD2_MODE_IS_INCLUDE) &&
 		    ntohs(*nsrcs) == 0) {
 			br_ip6_multicast_leave_group(br, port, &grec->grec_mca,
-						     vid);
+						     vid, src);
 		} else {
 			err = br_ip6_multicast_add_group(br, port,
-							 &grec->grec_mca, vid);
+							 &grec->grec_mca, vid,
+							 src);
 			if (err)
 				break;
 		}
@@ -1511,7 +1542,8 @@ br_multicast_leave_group(struct net_bridge *br,
 			 struct net_bridge_port *port,
 			 struct br_ip *group,
 			 struct bridge_mcast_other_query *other_query,
-			 struct bridge_mcast_own_query *own_query)
+			 struct bridge_mcast_own_query *own_query,
+			 const unsigned char *src)
 {
 	struct net_bridge_mdb_htable *mdb;
 	struct net_bridge_mdb_entry *mp;
@@ -1535,7 +1567,7 @@ br_multicast_leave_group(struct net_bridge *br,
 		for (pp = &mp->ports;
 		     (p = mlock_dereference(*pp, br)) != NULL;
 		     pp = &p->next) {
-			if (p->port != port)
+			if (!br_port_group_equal(p, port, src))
 				continue;
 
 			rcu_assign_pointer(*pp, p->next);
@@ -1566,7 +1598,7 @@ br_multicast_leave_group(struct net_bridge *br,
 		for (p = mlock_dereference(mp->ports, br);
 		     p != NULL;
 		     p = mlock_dereference(p->next, br)) {
-			if (p->port != port)
+			if (!br_port_group_equal(p, port, src))
 				continue;
 
 			if (!hlist_unhashed(&p->mglist) &&
@@ -1617,7 +1649,8 @@ br_multicast_leave_group(struct net_bridge *br,
 static void br_ip4_multicast_leave_group(struct net_bridge *br,
 					 struct net_bridge_port *port,
 					 __be32 group,
-					 __u16 vid)
+					 __u16 vid,
+					 const unsigned char *src)
 {
 	struct br_ip br_group;
 	struct bridge_mcast_own_query *own_query;
@@ -1632,14 +1665,15 @@ static void br_ip4_multicast_leave_group(struct net_bridge *br,
 	br_group.vid = vid;
 
 	br_multicast_leave_group(br, port, &br_group, &br->ip4_other_query,
-				 own_query);
+				 own_query, src);
 }
 
 #if IS_ENABLED(CONFIG_IPV6)
 static void br_ip6_multicast_leave_group(struct net_bridge *br,
 					 struct net_bridge_port *port,
 					 const struct in6_addr *group,
-					 __u16 vid)
+					 __u16 vid,
+					 const unsigned char *src)
 {
 	struct br_ip br_group;
 	struct bridge_mcast_own_query *own_query;
@@ -1654,7 +1688,7 @@ static void br_ip6_multicast_leave_group(struct net_bridge *br,
 	br_group.vid = vid;
 
 	br_multicast_leave_group(br, port, &br_group, &br->ip6_other_query,
-				 own_query);
+				 own_query, src);
 }
 #endif
 
@@ -1712,6 +1746,7 @@ static int br_multicast_ipv4_rcv(struct net_bridge *br,
 				 u16 vid)
 {
 	struct sk_buff *skb_trimmed = NULL;
+	const unsigned char *src;
 	struct igmphdr *ih;
 	int err;
 
@@ -1731,13 +1766,14 @@ static int br_multicast_ipv4_rcv(struct net_bridge *br,
 	}
 
 	ih = igmp_hdr(skb);
+	src = eth_hdr(skb)->h_source;
 	BR_INPUT_SKB_CB(skb)->igmp = ih->type;
 
 	switch (ih->type) {
 	case IGMP_HOST_MEMBERSHIP_REPORT:
 	case IGMPV2_HOST_MEMBERSHIP_REPORT:
 		BR_INPUT_SKB_CB(skb)->mrouters_only = 1;
-		err = br_ip4_multicast_add_group(br, port, ih->group, vid);
+		err = br_ip4_multicast_add_group(br, port, ih->group, vid, src);
 		break;
 	case IGMPV3_HOST_MEMBERSHIP_REPORT:
 		err = br_ip4_multicast_igmp3_report(br, port, skb_trimmed, vid);
@@ -1746,7 +1782,7 @@ static int br_multicast_ipv4_rcv(struct net_bridge *br,
 		err = br_ip4_multicast_query(br, port, skb_trimmed, vid);
 		break;
 	case IGMP_HOST_LEAVE_MESSAGE:
-		br_ip4_multicast_leave_group(br, port, ih->group, vid);
+		br_ip4_multicast_leave_group(br, port, ih->group, vid, src);
 		break;
 	}
 
@@ -1766,6 +1802,7 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br,
 				 u16 vid)
 {
 	struct sk_buff *skb_trimmed = NULL;
+	const unsigned char *src;
 	struct mld_msg *mld;
 	int err;
 
@@ -1785,8 +1822,10 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br,
 
 	switch (mld->mld_type) {
 	case ICMPV6_MGM_REPORT:
+		src = eth_hdr(skb)->h_source;
 		BR_INPUT_SKB_CB(skb)->mrouters_only = 1;
-		err = br_ip6_multicast_add_group(br, port, &mld->mld_mca, vid);
+		err = br_ip6_multicast_add_group(br, port, &mld->mld_mca, vid,
+						 src);
 		break;
 	case ICMPV6_MLD2_REPORT:
 		err = br_ip6_multicast_mld2_report(br, port, skb_trimmed, vid);
@@ -1795,7 +1834,8 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br,
 		err = br_ip6_multicast_query(br, port, skb_trimmed, vid);
 		break;
 	case ICMPV6_MGM_REDUCTION:
-		br_ip6_multicast_leave_group(br, port, &mld->mld_mca, vid);
+		src = eth_hdr(skb)->h_source;
+		br_ip6_multicast_leave_group(br, port, &mld->mld_mca, vid, src);
 		break;
 	}
 
diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c
index 71c7453..6c087cd 100644
--- a/net/bridge/br_netlink.c
+++ b/net/bridge/br_netlink.c
@@ -123,6 +123,7 @@ static inline size_t br_port_info_size(void)
 		+ nla_total_size(1)	/* IFLA_BRPORT_GUARD */
 		+ nla_total_size(1)	/* IFLA_BRPORT_PROTECT */
 		+ nla_total_size(1)	/* IFLA_BRPORT_FAST_LEAVE */
+		+ nla_total_size(1)	/* IFLA_BRPORT_MCAST_TO_UCAST */
 		+ nla_total_size(1)	/* IFLA_BRPORT_LEARNING */
 		+ nla_total_size(1)	/* IFLA_BRPORT_UNICAST_FLOOD */
 		+ nla_total_size(1)	/* IFLA_BRPORT_PROXYARP */
@@ -173,6 +174,8 @@ static int br_port_fill_attrs(struct sk_buff *skb,
 		       !!(p->flags & BR_ROOT_BLOCK)) ||
 	    nla_put_u8(skb, IFLA_BRPORT_FAST_LEAVE,
 		       !!(p->flags & BR_MULTICAST_FAST_LEAVE)) ||
+	    nla_put_u8(skb, IFLA_BRPORT_MCAST_TO_UCAST,
+		       !!(p->flags & BR_MULTICAST_TO_UNICAST)) ||
 	    nla_put_u8(skb, IFLA_BRPORT_LEARNING, !!(p->flags & BR_LEARNING)) ||
 	    nla_put_u8(skb, IFLA_BRPORT_UNICAST_FLOOD,
 		       !!(p->flags & BR_FLOOD)) ||
@@ -586,6 +589,7 @@ static const struct nla_policy br_port_policy[IFLA_BRPORT_MAX + 1] = {
 	[IFLA_BRPORT_PROXYARP]	= { .type = NLA_U8 },
 	[IFLA_BRPORT_PROXYARP_WIFI] = { .type = NLA_U8 },
 	[IFLA_BRPORT_MULTICAST_ROUTER] = { .type = NLA_U8 },
+	[IFLA_BRPORT_MCAST_TO_UCAST] = { .type = NLA_U8 },
 };
 
 /* Change the state of the port and notify spanning tree */
@@ -636,6 +640,7 @@ static int br_setport(struct net_bridge_port *p, struct nlattr *tb[])
 	br_set_port_flag(p, tb, IFLA_BRPORT_LEARNING, BR_LEARNING);
 	br_set_port_flag(p, tb, IFLA_BRPORT_UNICAST_FLOOD, BR_FLOOD);
 	br_set_port_flag(p, tb, IFLA_BRPORT_MCAST_FLOOD, BR_MCAST_FLOOD);
+	br_set_port_flag(p, tb, IFLA_BRPORT_MCAST_TO_UCAST, BR_MULTICAST_TO_UNICAST);
 	br_set_port_flag(p, tb, IFLA_BRPORT_PROXYARP, BR_PROXYARP);
 	br_set_port_flag(p, tb, IFLA_BRPORT_PROXYARP_WIFI, BR_PROXYARP_WIFI);
 
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index 8ce621e..0b82a22 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -177,6 +177,7 @@ struct net_bridge_port_group {
 	struct timer_list		timer;
 	struct br_ip			addr;
 	unsigned char			flags;
+	unsigned char			eth_addr[ETH_ALEN];
 };
 
 struct net_bridge_mdb_entry
@@ -599,7 +600,7 @@ void br_multicast_free_pg(struct rcu_head *head);
 struct net_bridge_port_group *
 br_multicast_new_port_group(struct net_bridge_port *port, struct br_ip *group,
 			    struct net_bridge_port_group __rcu *next,
-			    unsigned char flags);
+			    unsigned char flags, const unsigned char *src);
 void br_mdb_init(void);
 void br_mdb_uninit(void);
 void br_mdb_notify(struct net_device *dev, struct net_bridge_port *port,
diff --git a/net/bridge/br_sysfs_if.c b/net/bridge/br_sysfs_if.c
index 8bd5696..05e8946 100644
--- a/net/bridge/br_sysfs_if.c
+++ b/net/bridge/br_sysfs_if.c
@@ -188,6 +188,7 @@ static BRPORT_ATTR(multicast_router, S_IRUGO | S_IWUSR, show_multicast_router,
 		   store_multicast_router);
 
 BRPORT_ATTR_FLAG(multicast_fast_leave, BR_MULTICAST_FAST_LEAVE);
+BRPORT_ATTR_FLAG(multicast_to_unicast, BR_MULTICAST_TO_UNICAST);
 #endif
 
 static const struct brport_attribute *brport_attrs[] = {
@@ -214,6 +215,7 @@ static const struct brport_attribute *brport_attrs[] = {
 #ifdef CONFIG_BRIDGE_IGMP_SNOOPING
 	&brport_attr_multicast_router,
 	&brport_attr_multicast_fast_leave,
+	&brport_attr_multicast_to_unicast,
 #endif
 	&brport_attr_proxyarp,
 	&brport_attr_proxyarp_wifi,
-- 
2.1.4

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox