All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH net-next 1/7] qlcnic: Add capability to take FW dump deterministically
@ 2011-06-16 20:37 Anirban Chakraborty
  2011-06-16 20:37 ` [PATCH net-next 2/7] qlcnic: Remove holding api lock while taking the dump Anirban Chakraborty
                   ` (6 more replies)
  0 siblings, 7 replies; 12+ messages in thread
From: Anirban Chakraborty @ 2011-06-16 20:37 UTC (permalink / raw)
  To: netdev; +Cc: David Miller, Sritej Velaga

From: Sritej Velaga <sritej.velaga@qlogic.com>

In presence of multiple functions, current driver implementation does not
guarantee that the FW dump is taken by the same function that forces it.
Change it by adding a fw reset owner flag that could be changed in the device
reset path and only when a function determines that it needs to reset it.

Signed-off-by: Sritej Velaga <sritej.velaga@qlogic.com>
Signed-off-by: Anirban Chakraborty <anirban.chakraborty@qlogic.com>
---
 drivers/net/qlcnic/qlcnic.h      |    1 +
 drivers/net/qlcnic/qlcnic_ctx.c  |    4 ++--
 drivers/net/qlcnic/qlcnic_main.c |   32 ++++++++++++++++++++++++--------
 3 files changed, 27 insertions(+), 10 deletions(-)

diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h
index 480ef5c..194376e 100644
--- a/drivers/net/qlcnic/qlcnic.h
+++ b/drivers/net/qlcnic/qlcnic.h
@@ -895,6 +895,7 @@ struct qlcnic_ipaddr {
 #define QLCNIC_MAC_OVERRIDE_DISABLED	0x400
 #define QLCNIC_PROMISC_DISABLED		0x800
 #define QLCNIC_NEED_FLR			0x1000
+#define QLCNIC_FW_RESET_OWNER		0x2000
 #define QLCNIC_IS_MSI_FAMILY(adapter) \
 	((adapter)->flags & (QLCNIC_MSI_ENABLED | QLCNIC_MSIX_ENABLED))
 
diff --git a/drivers/net/qlcnic/qlcnic_ctx.c b/drivers/net/qlcnic/qlcnic_ctx.c
index bab041a..0ca514a 100644
--- a/drivers/net/qlcnic/qlcnic_ctx.c
+++ b/drivers/net/qlcnic/qlcnic_ctx.c
@@ -95,8 +95,8 @@ int qlcnic_fw_cmd_get_minidump_temp(struct qlcnic_adapter *adapter)
 			QLCNIC_CDRP_CMD_TEMP_SIZE);
 	if (err != QLCNIC_RCODE_SUCCESS) {
 		err = QLCRD32(adapter, QLCNIC_ARG1_CRB_OFFSET);
-		dev_err(&adapter->pdev->dev,
-			"Failed to get template size %d\n", err);
+		dev_info(&adapter->pdev->dev,
+			"Can't get template size %d\n", err);
 		err = -EIO;
 		return err;
 	}
diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c
index 0f6af5c..cd8e5c1 100644
--- a/drivers/net/qlcnic/qlcnic_main.c
+++ b/drivers/net/qlcnic/qlcnic_main.c
@@ -1590,10 +1590,6 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 	/* This will be reset for mezz cards  */
 	adapter->portnum = adapter->ahw->pci_func;
 
-	/* Get FW dump template and store it */
-	if (adapter->op_mode != QLCNIC_NON_PRIV_FUNC)
-		qlcnic_fw_cmd_get_minidump_temp(adapter);
-
 	err = qlcnic_get_board_info(adapter);
 	if (err) {
 		dev_err(&pdev->dev, "Error getting board config info.\n");
@@ -1612,6 +1608,12 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 		goto err_out_decr_ref;
 	}
 
+	/* Get FW dump template and store it */
+	if (adapter->op_mode != QLCNIC_NON_PRIV_FUNC)
+		if (!qlcnic_fw_cmd_get_minidump_temp(adapter))
+			dev_info(&pdev->dev,
+				"Supports FW dump capability\n");
+
 	if (qlcnic_read_mac_addr(adapter))
 		dev_warn(&pdev->dev, "failed to read mac addr\n");
 
@@ -2683,11 +2685,16 @@ err:
 static int
 qlcnic_check_drv_state(struct qlcnic_adapter *adapter)
 {
-	int act, state;
+	int act, state, active_mask;
 
 	state = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
 	act = QLCRD32(adapter, QLCNIC_CRB_DRV_ACTIVE);
 
+	if (adapter->flags & QLCNIC_FW_RESET_OWNER) {
+		active_mask = (~(1 << (adapter->ahw->pci_func * 4)));
+		act = act & active_mask;
+	}
+
 	if (((state & 0x11111111) == (act & 0x11111111)) ||
 			((act & 0x11111111) == ((state >> 1) & 0x11111111)))
 		return 0;
@@ -2826,6 +2833,11 @@ qlcnic_fwinit_work(struct work_struct *work)
 
 	if (!qlcnic_check_drv_state(adapter)) {
 skip_ack_check:
+		if (!(adapter->flags & QLCNIC_FW_RESET_OWNER)) {
+			qlcnic_api_unlock(adapter);
+			goto wait_npar;
+		}
+
 		dev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
 
 		if (dev_state == QLCNIC_DEV_NEED_RESET) {
@@ -2836,6 +2848,7 @@ skip_ack_check:
 			qlcnic_idc_debug_info(adapter, 0);
 			QLCDB(adapter, DRV, "Take FW dump\n");
 			qlcnic_dump_fw(adapter);
+			adapter->flags &= ~QLCNIC_FW_RESET_OWNER;
 		}
 
 		qlcnic_api_unlock(adapter);
@@ -2900,9 +2913,11 @@ qlcnic_detach_work(struct work_struct *work)
 
 	if (adapter->temp == QLCNIC_TEMP_PANIC)
 		goto err_ret;
-
-	if (qlcnic_set_drv_state(adapter, adapter->dev_state))
-		goto err_ret;
+	/* Dont ack if this instance is the reset owner */
+	if (!(adapter->flags & QLCNIC_FW_RESET_OWNER)) {
+		if (qlcnic_set_drv_state(adapter, adapter->dev_state))
+			goto err_ret;
+	}
 
 	adapter->fw_wait_cnt = 0;
 
@@ -2947,6 +2962,7 @@ qlcnic_dev_request_reset(struct qlcnic_adapter *adapter)
 
 	if (state == QLCNIC_DEV_READY) {
 		QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_NEED_RESET);
+		adapter->flags |= QLCNIC_FW_RESET_OWNER;
 		QLCDB(adapter, DRV, "NEED_RESET state set\n");
 		qlcnic_idc_debug_info(adapter, 0);
 	}
-- 
1.7.4.1


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH net-next 2/7] qlcnic: Remove holding api lock while taking the dump
  2011-06-16 20:37 [PATCH net-next 1/7] qlcnic: Add capability to take FW dump deterministically Anirban Chakraborty
@ 2011-06-16 20:37 ` Anirban Chakraborty
  2011-06-16 20:37 ` [PATCH net-next 3/7] qlcnic: Add code to tune FW dump Anirban Chakraborty
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 12+ messages in thread
From: Anirban Chakraborty @ 2011-06-16 20:37 UTC (permalink / raw)
  To: netdev; +Cc: David Miller, Anirban Chakraborty

With the change in logic for taking FW dump across multiple drivers,
there is no need to hold onto the api lock anymore in the fw dump path.
Instead use rtnl_lock() to synchronize the access to FW dump data structs.

Signed-off-by: Anirban Chakraborty <anirban.chakraborty@qlogic.com>
---
 drivers/net/qlcnic/qlcnic_ethtool.c |    6 ------
 drivers/net/qlcnic/qlcnic_main.c    |   10 +++++++---
 2 files changed, 7 insertions(+), 9 deletions(-)

diff --git a/drivers/net/qlcnic/qlcnic_ethtool.c b/drivers/net/qlcnic/qlcnic_ethtool.c
index 9efc690..3e79c20 100644
--- a/drivers/net/qlcnic/qlcnic_ethtool.c
+++ b/drivers/net/qlcnic/qlcnic_ethtool.c
@@ -986,8 +986,6 @@ qlcnic_get_dump_data(struct net_device *netdev, struct ethtool_dump *dump,
 	struct qlcnic_adapter *adapter = netdev_priv(netdev);
 	struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
 
-	if (qlcnic_api_lock(adapter))
-		return -EIO;
 	if (!fw_dump->clr) {
 		netdev_info(netdev, "Dump not available\n");
 		qlcnic_api_unlock(adapter);
@@ -1009,7 +1007,6 @@ qlcnic_get_dump_data(struct net_device *netdev, struct ethtool_dump *dump,
 	vfree(fw_dump->data);
 	fw_dump->data = NULL;
 	fw_dump->clr = 0;
-	qlcnic_api_unlock(adapter);
 
 	return 0;
 }
@@ -1032,10 +1029,7 @@ qlcnic_set_dump(struct net_device *netdev, struct ethtool_dump *val)
 				ret = -EINVAL;
 				goto out;
 		}
-		if (qlcnic_api_lock(adapter))
-			return -EIO;
 		fw_dump->tmpl_hdr->drv_cap_mask = val->flag & 0xff;
-		qlcnic_api_unlock(adapter);
 		netdev_info(netdev, "Driver mask changed to: 0x%x\n",
 			fw_dump->tmpl_hdr->drv_cap_mask);
 	}
diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c
index cd8e5c1..aa94e86 100644
--- a/drivers/net/qlcnic/qlcnic_main.c
+++ b/drivers/net/qlcnic/qlcnic_main.c
@@ -2846,13 +2846,17 @@ skip_ack_check:
 			set_bit(__QLCNIC_START_FW, &adapter->state);
 			QLCDB(adapter, DRV, "Restarting fw\n");
 			qlcnic_idc_debug_info(adapter, 0);
-			QLCDB(adapter, DRV, "Take FW dump\n");
-			qlcnic_dump_fw(adapter);
-			adapter->flags &= ~QLCNIC_FW_RESET_OWNER;
 		}
 
 		qlcnic_api_unlock(adapter);
 
+		rtnl_lock();
+		if (adapter->ahw->fw_dump.enable) {
+			QLCDB(adapter, DRV, "Take FW dump\n");
+			qlcnic_dump_fw(adapter);
+			adapter->flags &= ~QLCNIC_FW_RESET_OWNER;
+		}
+		rtnl_unlock();
 		if (!adapter->nic_ops->start_firmware(adapter)) {
 			qlcnic_schedule_work(adapter, qlcnic_attach_work, 0);
 			adapter->fw_wait_cnt = 0;
-- 
1.7.4.1


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH net-next 3/7] qlcnic: Add code to tune FW dump
  2011-06-16 20:37 [PATCH net-next 1/7] qlcnic: Add capability to take FW dump deterministically Anirban Chakraborty
  2011-06-16 20:37 ` [PATCH net-next 2/7] qlcnic: Remove holding api lock while taking the dump Anirban Chakraborty
@ 2011-06-16 20:37 ` Anirban Chakraborty
  2011-06-16 20:37 ` [PATCH net-next 4/7] qlcnic: fix initial number of msix entries in adapter Anirban Chakraborty
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 12+ messages in thread
From: Anirban Chakraborty @ 2011-06-16 20:37 UTC (permalink / raw)
  To: netdev; +Cc: David Miller, Anirban Chakraborty

To accommodate change in FW dump template, it is required to modify the
FW dump routine that captures cache data. Also, the default mask is changed
to capture a dump that would cover all the protocols that this FW supports.

Signed-off-by: Anirban Chakraborty <anirban.chakraborty@qlogic.com>
---
 drivers/net/qlcnic/qlcnic.h    |    5 ++---
 drivers/net/qlcnic/qlcnic_hw.c |   14 +++++++++++---
 2 files changed, 13 insertions(+), 6 deletions(-)

diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h
index 194376e..e5bb332 100644
--- a/drivers/net/qlcnic/qlcnic.h
+++ b/drivers/net/qlcnic/qlcnic.h
@@ -1220,8 +1220,7 @@ struct __ctrl {
 
 struct __cache {
 	__le32	addr;
-	u8	stride;
-	u8	rsvd;
+	__le16	stride;
 	__le16	init_tag_val;
 	__le32	size;
 	__le32	no_ops;
@@ -1319,7 +1318,7 @@ enum op_codes {
 #define QLCNIC_DUMP_SKIP	BIT_7
 
 #define QLCNIC_DUMP_MASK_MIN		3
-#define QLCNIC_DUMP_MASK_DEF		0x0f
+#define QLCNIC_DUMP_MASK_DEF		0x7f
 #define QLCNIC_DUMP_MASK_MAX		0xff
 #define QLCNIC_FORCE_FW_DUMP_KEY	0xdeadfeed
 
diff --git a/drivers/net/qlcnic/qlcnic_hw.c b/drivers/net/qlcnic/qlcnic_hw.c
index a5d9fbf..a4bcb87 100644
--- a/drivers/net/qlcnic/qlcnic_hw.c
+++ b/drivers/net/qlcnic/qlcnic_hw.c
@@ -1509,18 +1509,26 @@ qlcnic_dump_l2_cache(struct qlcnic_adapter *adapter,
 
 	for (i = 0; i < l2->no_ops; i++) {
 		QLCNIC_WR_DUMP_REG(l2->addr, base, val);
-		do {
+		if (LSW(l2->ctrl_val))
 			QLCNIC_WR_DUMP_REG(l2->ctrl_addr, base,
 				LSW(l2->ctrl_val));
+		if (!poll_mask)
+			goto skip_poll;
+		do {
 			QLCNIC_RD_DUMP_REG(l2->ctrl_addr, base, &data);
 			if (!(data & poll_mask))
 				break;
 			msleep(1);
 			time_out++;
 		} while (time_out <= poll_to);
-		if (time_out > poll_to)
-			return -EINVAL;
 
+		if (time_out > poll_to) {
+			dev_err(&adapter->pdev->dev,
+				"Timeout exceeded in %s, aborting dump\n",
+				__func__);
+			return -EINVAL;
+		}
+skip_poll:
 		addr = l2->read_addr;
 		cnt = l2->read_addr_num;
 		while (cnt) {
-- 
1.7.4.1


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH net-next 4/7] qlcnic: fix initial number of msix entries in adapter.
  2011-06-16 20:37 [PATCH net-next 1/7] qlcnic: Add capability to take FW dump deterministically Anirban Chakraborty
  2011-06-16 20:37 ` [PATCH net-next 2/7] qlcnic: Remove holding api lock while taking the dump Anirban Chakraborty
  2011-06-16 20:37 ` [PATCH net-next 3/7] qlcnic: Add code to tune FW dump Anirban Chakraborty
@ 2011-06-16 20:37 ` Anirban Chakraborty
  2011-06-16 20:37 ` [PATCH net-next 5/7] qlcnic: fix default operating state of interface Anirban Chakraborty
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 12+ messages in thread
From: Anirban Chakraborty @ 2011-06-16 20:37 UTC (permalink / raw)
  To: netdev; +Cc: David Miller, Sucheta Chakraborty

From: Sucheta Chakraborty <sucheta.chakraborty@qlogic.com>

Calculation of number of MSI-X vectors was wrong on uniprocessor
systems.

Signed-off-by: Sucheta Chakraborty <sucheta.chakraborty@qlogic.com>
Signed-off-by: Anirban Chakraborty <anirban.chakraborty@qlogic.com>
---
 drivers/net/qlcnic/qlcnic.h      |    1 -
 drivers/net/qlcnic/qlcnic_main.c |    6 ++----
 2 files changed, 2 insertions(+), 5 deletions(-)

diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h
index e5bb332..58d7616 100644
--- a/drivers/net/qlcnic/qlcnic.h
+++ b/drivers/net/qlcnic/qlcnic.h
@@ -900,7 +900,6 @@ struct qlcnic_ipaddr {
 	((adapter)->flags & (QLCNIC_MSI_ENABLED | QLCNIC_MSIX_ENABLED))
 
 #define QLCNIC_DEF_NUM_STS_DESC_RINGS	4
-#define QLCNIC_MIN_NUM_RSS_RINGS	2
 #define QLCNIC_MSIX_TBL_SPACE		8192
 #define QLCNIC_PCI_REG_MSIX_TBL 	0x44
 #define QLCNIC_MSIX_TBL_PGSIZE		4096
diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c
index aa94e86..8c07c4e 100644
--- a/drivers/net/qlcnic/qlcnic_main.c
+++ b/drivers/net/qlcnic/qlcnic_main.c
@@ -418,10 +418,8 @@ qlcnic_setup_intr(struct qlcnic_adapter *adapter)
 	int num_msix;
 
 	if (adapter->msix_supported) {
-		num_msix = (num_online_cpus() >=
-			QLCNIC_DEF_NUM_STS_DESC_RINGS) ?
-			QLCNIC_DEF_NUM_STS_DESC_RINGS :
-			QLCNIC_MIN_NUM_RSS_RINGS;
+		num_msix = rounddown_pow_of_two(min_t(int, num_online_cpus(),
+				QLCNIC_DEF_NUM_STS_DESC_RINGS));
 	} else
 		num_msix = 1;
 
-- 
1.7.4.1


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH net-next 5/7] qlcnic: fix default operating state of interface
  2011-06-16 20:37 [PATCH net-next 1/7] qlcnic: Add capability to take FW dump deterministically Anirban Chakraborty
                   ` (2 preceding siblings ...)
  2011-06-16 20:37 ` [PATCH net-next 4/7] qlcnic: fix initial number of msix entries in adapter Anirban Chakraborty
@ 2011-06-16 20:37 ` Anirban Chakraborty
  2011-06-17  4:10   ` David Miller
  2011-06-16 20:37 ` [PATCH net-next 6/7] qlcnic: Add support to enable/disable FW dump capability Anirban Chakraborty
                   ` (2 subsequent siblings)
  6 siblings, 1 reply; 12+ messages in thread
From: Anirban Chakraborty @ 2011-06-16 20:37 UTC (permalink / raw)
  To: netdev; +Cc: David Miller, Amit Kumar Salecha

From: Amit Kumar Salecha <amit.salecha@qlogic.com>

Currently interface shows status as RUNNING, even if there is no link.
To fix this, netif_carrier_off should be called after register_netdev().

netif_carrier_off calls linkwatch_fire_event(dev); only if netdev is registered,
otherwise it skips. linkwatch_fire_event set default state of nic interface.

Signed-off-by: Amit Kumar Salecha <amit.salecha@qlogic.com>
Signed-off-by: Anirban Chakraborty <anirban.chakraborty@qlogic.com>
---
 drivers/net/qlcnic/qlcnic_main.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c
index 8c07c4e..5348dba 100644
--- a/drivers/net/qlcnic/qlcnic_main.c
+++ b/drivers/net/qlcnic/qlcnic_main.c
@@ -1485,14 +1485,14 @@ qlcnic_setup_netdev(struct qlcnic_adapter *adapter,
 
 	netdev->irq = adapter->msix_entries[0].vector;
 
-	netif_carrier_off(netdev);
-
 	err = register_netdev(netdev);
 	if (err) {
 		dev_err(&pdev->dev, "failed to register net device\n");
 		return err;
 	}
 
+	netif_carrier_off(netdev);
+
 	return 0;
 }
 
-- 
1.7.4.1


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH net-next 6/7] qlcnic: Add support to enable/disable FW dump capability
  2011-06-16 20:37 [PATCH net-next 1/7] qlcnic: Add capability to take FW dump deterministically Anirban Chakraborty
                   ` (3 preceding siblings ...)
  2011-06-16 20:37 ` [PATCH net-next 5/7] qlcnic: fix default operating state of interface Anirban Chakraborty
@ 2011-06-16 20:37 ` Anirban Chakraborty
  2011-06-16 20:37 ` [PATCH net-next 7/7] qlcnic: multi protocol internal loopback support added Anirban Chakraborty
  2011-06-16 20:37 ` [PATCH net-next 0/7] qlcnic: Misc. fixes and loopback support Anirban Chakraborty
  6 siblings, 0 replies; 12+ messages in thread
From: Anirban Chakraborty @ 2011-06-16 20:37 UTC (permalink / raw)
  To: netdev; +Cc: David Miller, Anirban Chakraborty

In certain situations, it may be required to not enable FW dump
capability. Add support to turn off/on FW dump capability.

Signed-off-by: Anirban Chakraborty <anirban.chakraborty@qlogic.com>
---
 drivers/net/qlcnic/qlcnic.h         |    3 +++
 drivers/net/qlcnic/qlcnic_ctx.c     |    1 +
 drivers/net/qlcnic/qlcnic_ethtool.c |   19 +++++++++++++++++++
 3 files changed, 23 insertions(+), 0 deletions(-)

diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h
index 58d7616..0be84bd 100644
--- a/drivers/net/qlcnic/qlcnic.h
+++ b/drivers/net/qlcnic/qlcnic.h
@@ -429,6 +429,7 @@ struct qlcnic_dump_template_hdr {
 
 struct qlcnic_fw_dump {
 	u8	clr;	/* flag to indicate if dump is cleared */
+	u8	enable; /* enable/disable dump */
 	u32	size;	/* total size of the dump */
 	void	*data;	/* dump data area */
 	struct	qlcnic_dump_template_hdr *tmpl_hdr;
@@ -1320,6 +1321,8 @@ enum op_codes {
 #define QLCNIC_DUMP_MASK_DEF		0x7f
 #define QLCNIC_DUMP_MASK_MAX		0xff
 #define QLCNIC_FORCE_FW_DUMP_KEY	0xdeadfeed
+#define QLCNIC_ENABLE_FW_DUMP		0xaddfeed
+#define QLCNIC_DISABLE_FW_DUMP		0xbadfeed
 
 struct qlcnic_dump_operations {
 	enum op_codes opcode;
diff --git a/drivers/net/qlcnic/qlcnic_ctx.c b/drivers/net/qlcnic/qlcnic_ctx.c
index 0ca514a..b6769c7 100644
--- a/drivers/net/qlcnic/qlcnic_ctx.c
+++ b/drivers/net/qlcnic/qlcnic_ctx.c
@@ -150,6 +150,7 @@ int qlcnic_fw_cmd_get_minidump_temp(struct qlcnic_adapter *adapter)
 		tmpl_hdr->drv_cap_mask = tmpl_hdr->cap_mask;
 	else
 		tmpl_hdr->drv_cap_mask = QLCNIC_DUMP_MASK_DEF;
+	ahw->fw_dump.enable = 1;
 error:
 	dma_free_coherent(&adapter->pdev->dev, temp_size, tmp_addr, tmp_addr_t);
 	return err;
diff --git a/drivers/net/qlcnic/qlcnic_ethtool.c b/drivers/net/qlcnic/qlcnic_ethtool.c
index 3e79c20..a7f16a6 100644
--- a/drivers/net/qlcnic/qlcnic_ethtool.c
+++ b/drivers/net/qlcnic/qlcnic_ethtool.c
@@ -1019,8 +1019,27 @@ qlcnic_set_dump(struct net_device *netdev, struct ethtool_dump *val)
 	struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
 
 	if (val->flag == QLCNIC_FORCE_FW_DUMP_KEY) {
+		if (!fw_dump->enable) {
+			netdev_info(netdev, "FW dump not enabled\n");
+			return ret;
+		}
+		if (fw_dump->clr) {
+			dev_info(&adapter->pdev->dev,
+			"Previous dump not cleared, not forcing dump\n");
+			return ret;
+		}
 		netdev_info(netdev, "Forcing a FW dump\n");
 		qlcnic_dev_request_reset(adapter);
+	} else if (val->flag == QLCNIC_DISABLE_FW_DUMP) {
+		if (fw_dump->enable) {
+			netdev_info(netdev, "Disabling FW dump\n");
+			fw_dump->enable = 0;
+		}
+	} else if (val->flag == QLCNIC_ENABLE_FW_DUMP) {
+		if (!fw_dump->enable && fw_dump->tmpl_hdr) {
+			netdev_info(netdev, "Enabling FW dump\n");
+			fw_dump->enable = 1;
+		}
 	} else {
 		if (val->flag > QLCNIC_DUMP_MASK_MAX ||
 			val->flag < QLCNIC_DUMP_MASK_MIN) {
-- 
1.7.4.1


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH net-next 7/7] qlcnic: multi protocol internal loopback support added.
  2011-06-16 20:37 [PATCH net-next 1/7] qlcnic: Add capability to take FW dump deterministically Anirban Chakraborty
                   ` (4 preceding siblings ...)
  2011-06-16 20:37 ` [PATCH net-next 6/7] qlcnic: Add support to enable/disable FW dump capability Anirban Chakraborty
@ 2011-06-16 20:37 ` Anirban Chakraborty
  2011-06-16 20:37 ` [PATCH net-next 0/7] qlcnic: Misc. fixes and loopback support Anirban Chakraborty
  6 siblings, 0 replies; 12+ messages in thread
From: Anirban Chakraborty @ 2011-06-16 20:37 UTC (permalink / raw)
  To: netdev; +Cc: David Miller, Sucheta Chakraborty

From: Sucheta Chakraborty <sucheta.chakraborty@qlogic.com>

Driver will generate loopback traffic pattern and do the test. And
returns result of the test to application.

Updated driver version to 5.0.19.

Signed-off-by: Sucheta Chakraborty <sucheta.chakraborty@qlogic.com>
Signed-off-by: Anirban Chakraborty <anirban.chakraborty@qlogic.com>
---
 drivers/net/qlcnic/qlcnic.h         |   22 ++++++-
 drivers/net/qlcnic/qlcnic_ethtool.c |  123 +++++++++++++++++++++++++++++++++-
 drivers/net/qlcnic/qlcnic_hw.c      |   50 ++++++++++++++
 drivers/net/qlcnic/qlcnic_init.c    |  126 ++++++++++++++++++++++++++++++++++-
 drivers/net/qlcnic/qlcnic_main.c    |    6 ++
 5 files changed, 322 insertions(+), 5 deletions(-)

diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h
index 0be84bd..e545450 100644
--- a/drivers/net/qlcnic/qlcnic.h
+++ b/drivers/net/qlcnic/qlcnic.h
@@ -36,8 +36,8 @@
 
 #define _QLCNIC_LINUX_MAJOR 5
 #define _QLCNIC_LINUX_MINOR 0
-#define _QLCNIC_LINUX_SUBVERSION 18
-#define QLCNIC_LINUX_VERSIONID  "5.0.18"
+#define _QLCNIC_LINUX_SUBVERSION 19
+#define QLCNIC_LINUX_VERSIONID  "5.0.19"
 #define QLCNIC_DRV_IDC_VER  0x01
 #define QLCNIC_DRIVER_VERSION  ((_QLCNIC_LINUX_MAJOR << 16) |\
 		 (_QLCNIC_LINUX_MINOR << 8) | (_QLCNIC_LINUX_SUBVERSION))
@@ -451,6 +451,7 @@ struct qlcnic_hardware_context {
 	u8 revision_id;
 	u8 pci_func;
 	u8 linkup;
+	u8 loopback_state;
 	u16 port_type;
 	u16 board_type;
 
@@ -780,6 +781,13 @@ struct qlcnic_mac_list_s {
 #define QLCNIC_IP_UP		2
 #define QLCNIC_IP_DOWN		3
 
+#define QLCNIC_ILB_MODE		0x1
+
+#define QLCNIC_LINKEVENT	0x1
+#define QLCNIC_LB_RESPONSE	0x2
+#define QLCNIC_IS_LB_CONFIGURED(VAL)	\
+		(VAL == (QLCNIC_LINKEVENT | QLCNIC_LB_RESPONSE))
+
 /*
  * Driver --> Firmware
  */
@@ -789,13 +797,17 @@ struct qlcnic_mac_list_s {
 #define QLCNIC_H2C_OPCODE_LRO_REQUEST			0x7
 #define QLCNIC_H2C_OPCODE_SET_MAC_RECEIVE_MODE		0xc
 #define QLCNIC_H2C_OPCODE_CONFIG_IPADDR		0x12
+
 #define QLCNIC_H2C_OPCODE_GET_LINKEVENT		0x15
 #define QLCNIC_H2C_OPCODE_CONFIG_BRIDGING		0x17
 #define QLCNIC_H2C_OPCODE_CONFIG_HW_LRO		0x18
+#define QLCNIC_H2C_OPCODE_CONFIG_LOOPBACK		0x13
+
 /*
  * Firmware --> Driver
  */
 
+#define QLCNIC_C2H_OPCODE_CONFIG_LOOPBACK		0x8f
 #define QLCNIC_C2H_OPCODE_GET_LINKEVENT_RESPONSE	141
 
 #define VPORT_MISS_MODE_DROP		0 /* drop all unmatched */
@@ -1430,6 +1442,12 @@ int qlcnic_send_lro_cleanup(struct qlcnic_adapter *adapter);
 void qlcnic_update_cmd_producer(struct qlcnic_adapter *adapter,
 		struct qlcnic_host_tx_ring *tx_ring);
 void qlcnic_fetch_mac(struct qlcnic_adapter *, u32, u32, u8, u8 *);
+void qlcnic_process_rcv_ring_diag(struct qlcnic_host_sds_ring *sds_ring);
+void qlcnic_clear_lb_mode(struct qlcnic_adapter *adapter);
+int qlcnic_set_lb_mode(struct qlcnic_adapter *adapter, u8 mode);
+
+/* Functions from qlcnic_ethtool.c */
+int qlcnic_check_loopback_buff(unsigned char *data, u8 mac[]);
 
 /* Functions from qlcnic_main.c */
 int qlcnic_reset_context(struct qlcnic_adapter *);
diff --git a/drivers/net/qlcnic/qlcnic_ethtool.c b/drivers/net/qlcnic/qlcnic_ethtool.c
index a7f16a6..c2128a4 100644
--- a/drivers/net/qlcnic/qlcnic_ethtool.c
+++ b/drivers/net/qlcnic/qlcnic_ethtool.c
@@ -84,7 +84,8 @@ static const char qlcnic_device_gstrings_stats[][ETH_GSTRING_LEN] = {
 static const char qlcnic_gstrings_test[][ETH_GSTRING_LEN] = {
 	"Register_Test_on_offline",
 	"Link_Test_on_offline",
-	"Interrupt_Test_offline"
+	"Interrupt_Test_offline",
+	"Loopback_Test_offline"
 };
 
 #define QLCNIC_TEST_LEN	ARRAY_SIZE(qlcnic_gstrings_test)
@@ -685,6 +686,123 @@ clear_it:
 	return ret;
 }
 
+#define QLCNIC_ILB_PKT_SIZE 64
+#define QLCNIC_NUM_ILB_PKT	16
+#define QLCNIC_ILB_MAX_RCV_LOOP 10
+
+static void qlcnic_create_loopback_buff(unsigned char *data, u8 mac[])
+{
+	unsigned char random_data[] = {0xa8, 0x06, 0x45, 0x00};
+
+	memset(data, 0x4e, QLCNIC_ILB_PKT_SIZE);
+
+	memcpy(data, mac, ETH_ALEN);
+	memcpy(data + ETH_ALEN, mac, ETH_ALEN);
+
+	memcpy(data + 2 * ETH_ALEN, random_data, sizeof(random_data));
+}
+
+int qlcnic_check_loopback_buff(unsigned char *data, u8 mac[])
+{
+	unsigned char buff[QLCNIC_ILB_PKT_SIZE];
+	qlcnic_create_loopback_buff(buff, mac);
+	return memcmp(data, buff, QLCNIC_ILB_PKT_SIZE);
+}
+
+static int qlcnic_do_ilb_test(struct qlcnic_adapter *adapter)
+{
+	struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
+	struct qlcnic_host_sds_ring *sds_ring = &recv_ctx->sds_rings[0];
+	struct sk_buff *skb;
+	int i, loop, cnt = 0;
+
+	for (i = 0; i < QLCNIC_NUM_ILB_PKT; i++) {
+		skb = dev_alloc_skb(QLCNIC_ILB_PKT_SIZE);
+		qlcnic_create_loopback_buff(skb->data, adapter->mac_addr);
+		skb_put(skb, QLCNIC_ILB_PKT_SIZE);
+
+		adapter->diag_cnt = 0;
+		qlcnic_xmit_frame(skb, adapter->netdev);
+
+		loop = 0;
+		do {
+			msleep(1);
+			qlcnic_process_rcv_ring_diag(sds_ring);
+			if (loop++ > QLCNIC_ILB_MAX_RCV_LOOP)
+				break;
+		} while (!adapter->diag_cnt);
+
+		dev_kfree_skb_any(skb);
+
+		if (!adapter->diag_cnt)
+			dev_warn(&adapter->pdev->dev, "ILB Test: %dth packet"
+				" not recevied\n", i + 1);
+		else
+			cnt++;
+	}
+	if (cnt != i) {
+		dev_warn(&adapter->pdev->dev, "ILB Test failed\n");
+		return -1;
+	}
+	return 0;
+}
+
+static int qlcnic_iloopback_test(struct net_device *netdev)
+{
+	struct qlcnic_adapter *adapter = netdev_priv(netdev);
+	int max_sds_rings = adapter->max_sds_rings;
+	struct qlcnic_host_sds_ring *sds_ring;
+	int loop = 0;
+	int ret;
+
+	netdev_info(netdev, "%s:  in progress\n", __func__);
+	if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC) {
+		netdev_warn(netdev, "Loopback test not supported for non "
+				"privilege function\n");
+		return 0;
+	}
+
+	if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
+		return -EIO;
+
+
+	ret = qlcnic_diag_alloc_res(netdev, QLCNIC_LOOPBACK_TEST);
+	if (ret)
+		goto clear_it;
+
+	sds_ring = &adapter->recv_ctx->sds_rings[0];
+
+	ret = qlcnic_set_lb_mode(adapter, QLCNIC_ILB_MODE);
+	if (ret)
+		goto free_res;
+
+	do {
+		msleep(500);
+		qlcnic_process_rcv_ring_diag(sds_ring);
+		if (loop++ > QLCNIC_ILB_MAX_RCV_LOOP)
+			break;
+	} while (!QLCNIC_IS_LB_CONFIGURED(adapter->ahw->loopback_state));
+
+	if (!QLCNIC_IS_LB_CONFIGURED(adapter->ahw->loopback_state)) {
+		netdev_info(netdev, "firmware didnt respond to loopback "
+				"configure request\n");
+		ret = adapter->ahw->loopback_state;
+		goto free_res;
+	}
+
+	ret = qlcnic_do_ilb_test(adapter);
+
+	qlcnic_clear_lb_mode(adapter);
+
+ free_res:
+	qlcnic_diag_free_res(netdev, max_sds_rings);
+
+ clear_it:
+	adapter->max_sds_rings = max_sds_rings;
+	clear_bit(__QLCNIC_RESETTING, &adapter->state);
+	return ret;
+}
+
 static void
 qlcnic_diag_test(struct net_device *dev, struct ethtool_test *eth_test,
 		     u64 *data)
@@ -704,6 +822,9 @@ qlcnic_diag_test(struct net_device *dev, struct ethtool_test *eth_test,
 		if (data[2])
 			eth_test->flags |= ETH_TEST_FL_FAILED;
 
+		data[3] = qlcnic_iloopback_test(dev);
+		if (data[3])
+			eth_test->flags |= ETH_TEST_FL_FAILED;
 
 	}
 }
diff --git a/drivers/net/qlcnic/qlcnic_hw.c b/drivers/net/qlcnic/qlcnic_hw.c
index a4bcb87..5939c22 100644
--- a/drivers/net/qlcnic/qlcnic_hw.c
+++ b/drivers/net/qlcnic/qlcnic_hw.c
@@ -533,6 +533,56 @@ void qlcnic_delete_lb_filters(struct qlcnic_adapter *adapter)
 	}
 }
 
+int qlcnic_set_fw_loopback(struct qlcnic_adapter *adapter, u8 flag)
+{
+	struct qlcnic_nic_req req;
+	int rv;
+
+	memset(&req, 0, sizeof(struct qlcnic_nic_req));
+
+	req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23);
+	req.req_hdr = cpu_to_le64(QLCNIC_H2C_OPCODE_CONFIG_LOOPBACK |
+		((u64) adapter->portnum << 16) | ((u64) 0x1 << 32));
+
+	req.words[0] = cpu_to_le64(flag);
+
+	rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
+	if (rv != 0)
+		dev_err(&adapter->pdev->dev, "%sting loopback mode failed\n",
+				flag ? "Set" : "Reset");
+	return rv;
+}
+
+int qlcnic_set_lb_mode(struct qlcnic_adapter *adapter, u8 mode)
+{
+	if (qlcnic_set_fw_loopback(adapter, mode))
+		return -EIO;
+
+	if (qlcnic_nic_set_promisc(adapter, VPORT_MISS_MODE_ACCEPT_ALL)) {
+		qlcnic_set_fw_loopback(adapter, mode);
+		return -EIO;
+	}
+
+	msleep(1000);
+	return 0;
+}
+
+void qlcnic_clear_lb_mode(struct qlcnic_adapter *adapter)
+{
+	int mode = VPORT_MISS_MODE_DROP;
+	struct net_device *netdev = adapter->netdev;
+
+	qlcnic_set_fw_loopback(adapter, 0);
+
+	if (netdev->flags & IFF_PROMISC)
+		mode = VPORT_MISS_MODE_ACCEPT_ALL;
+	else if (netdev->flags & IFF_ALLMULTI)
+		mode = VPORT_MISS_MODE_ACCEPT_MULTI;
+
+	qlcnic_nic_set_promisc(adapter, mode);
+	msleep(1000);
+}
+
 /*
  * Send the interrupt coalescing parameter set by ethtool to the card.
  */
diff --git a/drivers/net/qlcnic/qlcnic_init.c b/drivers/net/qlcnic/qlcnic_init.c
index 5b8bbcf..9d5bee0 100644
--- a/drivers/net/qlcnic/qlcnic_init.c
+++ b/drivers/net/qlcnic/qlcnic_init.c
@@ -1281,6 +1281,7 @@ qlcnic_handle_linkevent(struct qlcnic_adapter *adapter,
 	u16 cable_len;
 	u16 link_speed;
 	u8  link_status, module, duplex, autoneg;
+	u8 lb_status = 0;
 	struct net_device *netdev = adapter->netdev;
 
 	adapter->has_link_events = 1;
@@ -1292,6 +1293,7 @@ qlcnic_handle_linkevent(struct qlcnic_adapter *adapter,
 	link_status = msg->body[2] & 0xff;
 	duplex = (msg->body[2] >> 16) & 0xff;
 	autoneg = (msg->body[2] >> 24) & 0xff;
+	lb_status = (msg->body[2] >> 32) & 0x3;
 
 	module = (msg->body[2] >> 8) & 0xff;
 	if (module == LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLE)
@@ -1301,6 +1303,9 @@ qlcnic_handle_linkevent(struct qlcnic_adapter *adapter,
 		dev_info(&netdev->dev, "unsupported cable length %d\n",
 				cable_len);
 
+	if (!link_status && (lb_status == 1))
+		adapter->ahw->loopback_state |= QLCNIC_LINKEVENT;
+
 	qlcnic_advert_link_change(adapter, link_status);
 
 	if (duplex == LINKEVENT_FULL_DUPLEX)
@@ -1319,7 +1324,9 @@ qlcnic_handle_fw_message(int desc_cnt, int index,
 {
 	struct qlcnic_fw_msg msg;
 	struct status_desc *desc;
-	int i = 0, opcode;
+	struct qlcnic_adapter *adapter;
+	struct device *dev;
+	int i = 0, opcode, ret;
 
 	while (desc_cnt > 0 && i < 8) {
 		desc = &sds_ring->desc_head[index];
@@ -1330,10 +1337,28 @@ qlcnic_handle_fw_message(int desc_cnt, int index,
 		desc_cnt--;
 	}
 
+	adapter = sds_ring->adapter;
+	dev = &adapter->pdev->dev;
 	opcode = qlcnic_get_nic_msg_opcode(msg.body[0]);
+
 	switch (opcode) {
 	case QLCNIC_C2H_OPCODE_GET_LINKEVENT_RESPONSE:
-		qlcnic_handle_linkevent(sds_ring->adapter, &msg);
+		qlcnic_handle_linkevent(adapter, &msg);
+		break;
+	case QLCNIC_C2H_OPCODE_CONFIG_LOOPBACK:
+		ret = (u32)(msg.body[1]);
+		switch (ret) {
+		case 0:
+			adapter->ahw->loopback_state |= QLCNIC_LB_RESPONSE;
+			break;
+		case 1:
+			dev_info(dev, "loopback already in progress\n");
+			break;
+		default:
+			dev_info(dev, "loopback configure request failed,"
+					" ret %x\n", ret);
+			break;
+		}
 		break;
 	default:
 		break;
@@ -1746,6 +1771,103 @@ qlcnic_post_rx_buffers_nodb(struct qlcnic_adapter *adapter,
 	spin_unlock(&rds_ring->lock);
 }
 
+static void dump_skb(struct sk_buff *skb)
+{
+	int i;
+	unsigned char *data = skb->data;
+
+	printk(KERN_INFO "\n");
+	for (i = 0; i < skb->len; i++) {
+		printk(KERN_INFO "%02x ", data[i]);
+		if ((i & 0x0f) == 8)
+			printk(KERN_INFO "\n");
+	}
+}
+
+void qlcnic_process_rcv_diag(struct qlcnic_adapter *adapter,
+		struct qlcnic_host_sds_ring *sds_ring,
+		int ring, u64 sts_data0)
+{
+	struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
+	struct sk_buff *skb;
+	struct qlcnic_host_rds_ring *rds_ring;
+	int index, length, cksum, pkt_offset;
+
+	if (unlikely(ring >= adapter->max_rds_rings))
+		return;
+
+	rds_ring = &recv_ctx->rds_rings[ring];
+
+	index = qlcnic_get_sts_refhandle(sts_data0);
+	length = qlcnic_get_sts_totallength(sts_data0);
+	if (unlikely(index >= rds_ring->num_desc))
+		return;
+
+	cksum  = qlcnic_get_sts_status(sts_data0);
+	pkt_offset = qlcnic_get_sts_pkt_offset(sts_data0);
+
+	skb = qlcnic_process_rxbuf(adapter, rds_ring, index, cksum);
+	if (!skb)
+		return;
+
+	if (length > rds_ring->skb_size)
+		skb_put(skb, rds_ring->skb_size);
+	else
+		skb_put(skb, length);
+
+	if (pkt_offset)
+		skb_pull(skb, pkt_offset);
+
+	if (!qlcnic_check_loopback_buff(skb->data, adapter->mac_addr))
+		adapter->diag_cnt++;
+	else
+		dump_skb(skb);
+
+	dev_kfree_skb_any(skb);
+	adapter->stats.rx_pkts++;
+	adapter->stats.rxbytes += length;
+
+	return;
+}
+
+void
+qlcnic_process_rcv_ring_diag(struct qlcnic_host_sds_ring *sds_ring)
+{
+	struct qlcnic_adapter *adapter = sds_ring->adapter;
+	struct status_desc *desc;
+	u64 sts_data0;
+	int ring, opcode, desc_cnt;
+
+	u32 consumer = sds_ring->consumer;
+
+	desc = &sds_ring->desc_head[consumer];
+	sts_data0 = le64_to_cpu(desc->status_desc_data[0]);
+
+	if (!(sts_data0 & STATUS_OWNER_HOST))
+		return;
+
+	desc_cnt = qlcnic_get_sts_desc_cnt(sts_data0);
+	opcode = qlcnic_get_sts_opcode(sts_data0);
+	switch (opcode) {
+	case QLCNIC_RESPONSE_DESC:
+		qlcnic_handle_fw_message(desc_cnt, consumer, sds_ring);
+		break;
+	default:
+		ring = qlcnic_get_sts_type(sts_data0);
+		qlcnic_process_rcv_diag(adapter, sds_ring, ring, sts_data0);
+		break;
+	}
+
+	for (; desc_cnt > 0; desc_cnt--) {
+		desc = &sds_ring->desc_head[consumer];
+		desc->status_desc_data[0] = cpu_to_le64(STATUS_OWNER_PHANTOM);
+		consumer = get_next_index(consumer, sds_ring->num_desc);
+	}
+
+	sds_ring->consumer = consumer;
+	writel(consumer, sds_ring->crb_sts_consumer);
+}
+
 void
 qlcnic_fetch_mac(struct qlcnic_adapter *adapter, u32 off1, u32 off2,
 			u8 alt_mac, u8 *mac)
diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c
index 5348dba..26ac5c6 100644
--- a/drivers/net/qlcnic/qlcnic_main.c
+++ b/drivers/net/qlcnic/qlcnic_main.c
@@ -1391,6 +1391,12 @@ int qlcnic_diag_alloc_res(struct net_device *netdev, int test)
 			qlcnic_enable_int(sds_ring);
 		}
 	}
+
+	if (adapter->diag_test == QLCNIC_LOOPBACK_TEST) {
+		adapter->ahw->loopback_state = 0;
+		qlcnic_linkevent_request(adapter, 1);
+	}
+
 	set_bit(__QLCNIC_DEV_UP, &adapter->state);
 
 	return 0;
-- 
1.7.4.1


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH net-next 0/7] qlcnic: Misc. fixes and loopback support
  2011-06-16 20:37 [PATCH net-next 1/7] qlcnic: Add capability to take FW dump deterministically Anirban Chakraborty
                   ` (5 preceding siblings ...)
  2011-06-16 20:37 ` [PATCH net-next 7/7] qlcnic: multi protocol internal loopback support added Anirban Chakraborty
@ 2011-06-16 20:37 ` Anirban Chakraborty
  6 siblings, 0 replies; 12+ messages in thread
From: Anirban Chakraborty @ 2011-06-16 20:37 UTC (permalink / raw)
  To: netdev; +Cc: David Miller, Anirban Chakraborty

Please apply the series to net-next. Thanks.

-Anirban


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH net-next 5/7] qlcnic: fix default operating state of interface
  2011-06-16 20:37 ` [PATCH net-next 5/7] qlcnic: fix default operating state of interface Anirban Chakraborty
@ 2011-06-17  4:10   ` David Miller
  2011-06-17 19:00     ` Stephen Hemminger
  2011-06-20  4:14     ` Anirban Chakraborty
  0 siblings, 2 replies; 12+ messages in thread
From: David Miller @ 2011-06-17  4:10 UTC (permalink / raw)
  To: anirban.chakraborty; +Cc: netdev, amit.salecha

From: Anirban Chakraborty <anirban.chakraborty@qlogic.com>
Date: Thu, 16 Jun 2011 13:37:36 -0700

> From: Amit Kumar Salecha <amit.salecha@qlogic.com>
> 
> Currently interface shows status as RUNNING, even if there is no link.
> To fix this, netif_carrier_off should be called after register_netdev().
> 
> netif_carrier_off calls linkwatch_fire_event(dev); only if netdev is registered,
> otherwise it skips. linkwatch_fire_event set default state of nic interface.
> 
> Signed-off-by: Amit Kumar Salecha <amit.salecha@qlogic.com>
> Signed-off-by: Anirban Chakraborty <anirban.chakraborty@qlogic.com>

You cannot do this.

The exact second that register_netdev() is called, the device can
be brought up asynchronously and the link brought into the up state.

Your netif_carrier_off() call will race with this.

This is why no other (properly functioning) driver does what you're
trying to do here.

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH net-next 5/7] qlcnic: fix default operating state of interface
  2011-06-17  4:10   ` David Miller
@ 2011-06-17 19:00     ` Stephen Hemminger
  2011-06-22  7:01       ` Amit Salecha
  2011-06-20  4:14     ` Anirban Chakraborty
  1 sibling, 1 reply; 12+ messages in thread
From: Stephen Hemminger @ 2011-06-17 19:00 UTC (permalink / raw)
  To: David Miller; +Cc: anirban.chakraborty, netdev, amit.salecha

On Fri, 17 Jun 2011 00:10:35 -0400 (EDT)
David Miller <davem@davemloft.net> wrote:

> From: Anirban Chakraborty <anirban.chakraborty@qlogic.com>
> Date: Thu, 16 Jun 2011 13:37:36 -0700
> 
> > From: Amit Kumar Salecha <amit.salecha@qlogic.com>
> > 
> > Currently interface shows status as RUNNING, even if there is no link.
> > To fix this, netif_carrier_off should be called after register_netdev().
> > 
> > netif_carrier_off calls linkwatch_fire_event(dev); only if netdev is registered,
> > otherwise it skips. linkwatch_fire_event set default state of nic interface.
> > 
> > Signed-off-by: Amit Kumar Salecha <amit.salecha@qlogic.com>
> > Signed-off-by: Anirban Chakraborty <anirban.chakraborty@qlogic.com>
> 
> You cannot do this.
> 
> The exact second that register_netdev() is called, the device can
> be brought up asynchronously and the link brought into the up state.
> 
> Your netif_carrier_off() call will race with this.
> 
> This is why no other (properly functioning) driver does what you're
> trying to do here.

The proper place to do this is in the open() routine.
When device is not open, the carrier state is undefined; and devices
that are trying to save power turn off PHY when device is not in use.

Therefore the open() routine should ensure that the carrier is in
the proper state when returning. Just doing something like:

static int qlcnic_open() {
...
	netif_carrier_off()

        err = __qlcnic_up();
	...
}

static int __qlcnic_up() {
	...
	(lots of tests)
	...

        netif_carrier_on();
	adapter->reset_context = 0;
	set_bit(__QLCNIC_DEV_UP, &adapter->state);
	return 0;
}

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH net-next 5/7] qlcnic: fix default operating state of interface
  2011-06-17  4:10   ` David Miller
  2011-06-17 19:00     ` Stephen Hemminger
@ 2011-06-20  4:14     ` Anirban Chakraborty
  1 sibling, 0 replies; 12+ messages in thread
From: Anirban Chakraborty @ 2011-06-20  4:14 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, Amit Salecha


On Jun 16, 2011, at 9:10 PM, David Miller wrote:

> From: Anirban Chakraborty <anirban.chakraborty@qlogic.com>
> Date: Thu, 16 Jun 2011 13:37:36 -0700
> 
>> From: Amit Kumar Salecha <amit.salecha@qlogic.com>
>> 
>> Currently interface shows status as RUNNING, even if there is no link.
>> To fix this, netif_carrier_off should be called after register_netdev().
>> 
>> netif_carrier_off calls linkwatch_fire_event(dev); only if netdev is registered,
>> otherwise it skips. linkwatch_fire_event set default state of nic interface.
>> 
>> Signed-off-by: Amit Kumar Salecha <amit.salecha@qlogic.com>
>> Signed-off-by: Anirban Chakraborty <anirban.chakraborty@qlogic.com>
> 
> You cannot do this.
> 
> The exact second that register_netdev() is called, the device can
> be brought up asynchronously and the link brought into the up state.
> 
> Your netif_carrier_off() call will race with this.
> 
> This is why no other (properly functioning) driver does what you're
> trying to do here.
> 

We will take care of it. Please ignore the series. 

thanks much,
Anirban




^ permalink raw reply	[flat|nested] 12+ messages in thread

* RE: [PATCH net-next 5/7] qlcnic: fix default operating state of interface
  2011-06-17 19:00     ` Stephen Hemminger
@ 2011-06-22  7:01       ` Amit Salecha
  0 siblings, 0 replies; 12+ messages in thread
From: Amit Salecha @ 2011-06-22  7:01 UTC (permalink / raw)
  To: Stephen Hemminger, David Miller; +Cc: Anirban Chakraborty, netdev

> -----Original Message-----
> From: Stephen Hemminger [mailto:shemminger@vyatta.com]
> 
> David Miller <davem@davemloft.net> wrote:
> 
> > From: Anirban Chakraborty <anirban.chakraborty@qlogic.com>
> > Date: Thu, 16 Jun 2011 13:37:36 -0700
> >
> > > From: Amit Kumar Salecha <amit.salecha@qlogic.com>
> > >
> > > Currently interface shows status as RUNNING, even if there is no
> link.
> > > To fix this, netif_carrier_off should be called after
> register_netdev().
> > >
> > > netif_carrier_off calls linkwatch_fire_event(dev); only if netdev
> is registered,
> > > otherwise it skips. linkwatch_fire_event set default state of nic
> interface.
> > >
> > > Signed-off-by: Amit Kumar Salecha <amit.salecha@qlogic.com>
> > > Signed-off-by: Anirban Chakraborty <anirban.chakraborty@qlogic.com>
> >
> > You cannot do this.
> >
> > The exact second that register_netdev() is called, the device can
> > be brought up asynchronously and the link brought into the up state.
> >
> > Your netif_carrier_off() call will race with this.
> >
> > This is why no other (properly functioning) driver does what you're
> > trying to do here.
> 
> The proper place to do this is in the open() routine.
> When device is not open, the carrier state is undefined; and devices
> that are trying to save power turn off PHY when device is not in use.
> 
> Therefore the open() routine should ensure that the carrier is in
> the proper state when returning. Just doing something like:
> 
> static int qlcnic_open() {
> ...
> 	netif_carrier_off()
> 
>         err = __qlcnic_up();
> 	...
> }
> 
> static int __qlcnic_up() {
> 	...
> 	(lots of tests)
> 	...
> 
>         netif_carrier_on();
> 	adapter->reset_context = 0;
> 	set_bit(__QLCNIC_DEV_UP, &adapter->state);
> 	return 0;
> }

netif_carrier_off() is ok, should be call from qlcnic_open().
netif_carrier_on() will be call during asynchronous notification from fw.

-Thanks.


^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2011-06-22  7:01 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-06-16 20:37 [PATCH net-next 1/7] qlcnic: Add capability to take FW dump deterministically Anirban Chakraborty
2011-06-16 20:37 ` [PATCH net-next 2/7] qlcnic: Remove holding api lock while taking the dump Anirban Chakraborty
2011-06-16 20:37 ` [PATCH net-next 3/7] qlcnic: Add code to tune FW dump Anirban Chakraborty
2011-06-16 20:37 ` [PATCH net-next 4/7] qlcnic: fix initial number of msix entries in adapter Anirban Chakraborty
2011-06-16 20:37 ` [PATCH net-next 5/7] qlcnic: fix default operating state of interface Anirban Chakraborty
2011-06-17  4:10   ` David Miller
2011-06-17 19:00     ` Stephen Hemminger
2011-06-22  7:01       ` Amit Salecha
2011-06-20  4:14     ` Anirban Chakraborty
2011-06-16 20:37 ` [PATCH net-next 6/7] qlcnic: Add support to enable/disable FW dump capability Anirban Chakraborty
2011-06-16 20:37 ` [PATCH net-next 7/7] qlcnic: multi protocol internal loopback support added Anirban Chakraborty
2011-06-16 20:37 ` [PATCH net-next 0/7] qlcnic: Misc. fixes and loopback support Anirban Chakraborty

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.