netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
To: davem@davemloft.net
Cc: Emil Tantilov <emil.s.tantilov@intel.com>,
	netdev@vger.kernel.org, gospo@redhat.com, bphilips@novell.com,
	Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Subject: [net-next-2.6 19/24] ixgbe: fix semaphores in eeprom routines for x540
Date: Wed, 13 Apr 2011 18:02:15 -0700	[thread overview]
Message-ID: <1302742940-22141-20-git-send-email-jeffrey.t.kirsher@intel.com> (raw)
In-Reply-To: <1302742940-22141-1-git-send-email-jeffrey.t.kirsher@intel.com>

From: Emil Tantilov <emil.s.tantilov@intel.com>

HW can upload EEPROM content from flash while
in a middle of checksum calculation. Take NVM ownership for the whole
process of checksum update.

Call ixgbe_read_eerd_generic() and ixgbe_write_eewr_generic() directly to
avoid double take of semaphores which leads to long loading times.

Signed-off-by: Emil Tantilov <emil.s.tantilov@intel.com>
Tested-by: Stephen Ko <stephen.s.ko@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
 drivers/net/ixgbe/ixgbe_common.c |   44 +++++++++++-
 drivers/net/ixgbe/ixgbe_common.h |    2 +-
 drivers/net/ixgbe/ixgbe_x540.c   |  154 +++++++++++++++++++++++++++-----------
 3 files changed, 153 insertions(+), 47 deletions(-)

diff --git a/drivers/net/ixgbe/ixgbe_common.c b/drivers/net/ixgbe/ixgbe_common.c
index a67cba5..fc31e02 100644
--- a/drivers/net/ixgbe/ixgbe_common.c
+++ b/drivers/net/ixgbe/ixgbe_common.c
@@ -54,6 +54,7 @@ static s32 ixgbe_device_supports_autoneg_fc(struct ixgbe_hw *hw);
 static s32 ixgbe_negotiate_fc(struct ixgbe_hw *hw, u32 adv_reg, u32 lp_reg,
 			      u32 adv_sym, u32 adv_asm, u32 lp_sym, u32 lp_asm);
 static s32 ixgbe_setup_fc(struct ixgbe_hw *hw, s32 packetbuf_num);
+static s32 ixgbe_poll_eerd_eewr_done(struct ixgbe_hw *hw, u32 ee_reg);
 
 /**
  *  ixgbe_start_hw_generic - Prepare hardware for Tx/Rx
@@ -778,6 +779,47 @@ out:
 }
 
 /**
+ *  ixgbe_write_eewr_generic - Write EEPROM word using EEWR
+ *  @hw: pointer to hardware structure
+ *  @offset: offset of  word in the EEPROM to write
+ *  @data: word write to the EEPROM
+ *
+ *  Write a 16 bit word to the EEPROM using the EEWR register.
+ **/
+s32 ixgbe_write_eewr_generic(struct ixgbe_hw *hw, u16 offset, u16 data)
+{
+	u32 eewr;
+	s32 status;
+
+	hw->eeprom.ops.init_params(hw);
+
+	if (offset >= hw->eeprom.word_size) {
+		status = IXGBE_ERR_EEPROM;
+		goto out;
+	}
+
+	eewr = (offset << IXGBE_EEPROM_RW_ADDR_SHIFT) |
+	       (data << IXGBE_EEPROM_RW_REG_DATA) | IXGBE_EEPROM_RW_REG_START;
+
+	status = ixgbe_poll_eerd_eewr_done(hw, IXGBE_NVM_POLL_WRITE);
+	if (status != 0) {
+		hw_dbg(hw, "Eeprom write EEWR timed out\n");
+		goto out;
+	}
+
+	IXGBE_WRITE_REG(hw, IXGBE_EEWR, eewr);
+
+	status = ixgbe_poll_eerd_eewr_done(hw, IXGBE_NVM_POLL_WRITE);
+	if (status != 0) {
+		hw_dbg(hw, "Eeprom write EEWR timed out\n");
+		goto out;
+	}
+
+out:
+	return status;
+}
+
+/**
  *  ixgbe_poll_eerd_eewr_done - Poll EERD read or EEWR write status
  *  @hw: pointer to hardware structure
  *  @ee_reg: EEPROM flag for polling
@@ -785,7 +827,7 @@ out:
  *  Polls the status bit (bit 1) of the EERD or EEWR to determine when the
  *  read or write is done respectively.
  **/
-s32 ixgbe_poll_eerd_eewr_done(struct ixgbe_hw *hw, u32 ee_reg)
+static s32 ixgbe_poll_eerd_eewr_done(struct ixgbe_hw *hw, u32 ee_reg)
 {
 	u32 i;
 	u32 reg;
diff --git a/drivers/net/ixgbe/ixgbe_common.h b/drivers/net/ixgbe/ixgbe_common.h
index 2585bf3..e18dc13 100644
--- a/drivers/net/ixgbe/ixgbe_common.h
+++ b/drivers/net/ixgbe/ixgbe_common.h
@@ -50,13 +50,13 @@ s32 ixgbe_led_off_generic(struct ixgbe_hw *hw, u32 index);
 s32 ixgbe_init_eeprom_params_generic(struct ixgbe_hw *hw);
 s32 ixgbe_write_eeprom_generic(struct ixgbe_hw *hw, u16 offset, u16 data);
 s32 ixgbe_read_eerd_generic(struct ixgbe_hw *hw, u16 offset, u16 *data);
+s32 ixgbe_write_eewr_generic(struct ixgbe_hw *hw, u16 offset, u16 data);
 s32 ixgbe_read_eeprom_bit_bang_generic(struct ixgbe_hw *hw, u16 offset,
                                        u16 *data);
 u16 ixgbe_calc_eeprom_checksum_generic(struct ixgbe_hw *hw);
 s32 ixgbe_validate_eeprom_checksum_generic(struct ixgbe_hw *hw,
                                            u16 *checksum_val);
 s32 ixgbe_update_eeprom_checksum_generic(struct ixgbe_hw *hw);
-s32 ixgbe_poll_eerd_eewr_done(struct ixgbe_hw *hw, u32 ee_reg);
 
 s32 ixgbe_set_rar_generic(struct ixgbe_hw *hw, u32 index, u8 *addr, u32 vmdq,
                           u32 enable_addr);
diff --git a/drivers/net/ixgbe/ixgbe_x540.c b/drivers/net/ixgbe/ixgbe_x540.c
index 8aa1dc1..5433f15 100644
--- a/drivers/net/ixgbe/ixgbe_x540.c
+++ b/drivers/net/ixgbe/ixgbe_x540.c
@@ -322,55 +322,33 @@ static s32 ixgbe_read_eerd_X540(struct ixgbe_hw *hw, u16 offset, u16 *data)
 }
 
 /**
- * ixgbe_write_eewr_X540 - Write EEPROM word using EEWR
- * @hw: pointer to hardware structure
- * @offset: offset of  word in the EEPROM to write
- * @data: word write to the EEPROM
+ *  ixgbe_write_eewr_X540 - Write EEPROM word using EEWR
+ *  @hw: pointer to hardware structure
+ *  @offset: offset of  word in the EEPROM to write
+ *  @data: word write to the EEPROM
  *
- * Write a 16 bit word to the EEPROM using the EEWR register.
+ *  Write a 16 bit word to the EEPROM using the EEWR register.
  **/
 static s32 ixgbe_write_eewr_X540(struct ixgbe_hw *hw, u16 offset, u16 data)
 {
-	u32 eewr;
-	s32 status;
-
-	hw->eeprom.ops.init_params(hw);
-
-	if (offset >= hw->eeprom.word_size) {
-		status = IXGBE_ERR_EEPROM;
-		goto out;
-	}
-
-	eewr = (offset << IXGBE_EEPROM_RW_ADDR_SHIFT) |
-	       (data << IXGBE_EEPROM_RW_REG_DATA) |
-	       IXGBE_EEPROM_RW_REG_START;
-
-	if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) == 0) {
-		status = ixgbe_poll_eerd_eewr_done(hw, IXGBE_NVM_POLL_WRITE);
-		if (status != 0) {
-			hw_dbg(hw, "Eeprom write EEWR timed out\n");
-			goto out;
-		}
-
-		IXGBE_WRITE_REG(hw, IXGBE_EEWR, eewr);
+	s32 status = 0;
 
-		status = ixgbe_poll_eerd_eewr_done(hw, IXGBE_NVM_POLL_WRITE);
-		if (status != 0) {
-			hw_dbg(hw, "Eeprom write EEWR timed out\n");
-			goto out;
-		}
-	} else {
+	if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) == 0)
+		status = ixgbe_write_eewr_generic(hw, offset, data);
+	else
 		status = IXGBE_ERR_SWFW_SYNC;
-	}
 
-out:
-	ixgbe_release_swfw_sync_X540(hw, IXGBE_GSSR_EEP_SM);
+	hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM);
 	return status;
 }
 
 /**
- * ixgbe_calc_eeprom_checksum_X540 - Calculates and returns the checksum
- * @hw: pointer to hardware structure
+ *  ixgbe_calc_eeprom_checksum_X540 - Calculates and returns the checksum
+ *
+ *  This function does not use synchronization for EERD and EEWR. It can
+ *  be used internally by function which utilize ixgbe_acquire_swfw_sync_X540.
+ *
+ *  @hw: pointer to hardware structure
  **/
 static u16 ixgbe_calc_eeprom_checksum_X540(struct ixgbe_hw *hw)
 {
@@ -381,9 +359,15 @@ static u16 ixgbe_calc_eeprom_checksum_X540(struct ixgbe_hw *hw)
 	u16 pointer = 0;
 	u16 word = 0;
 
+	/*
+	 * Do not use hw->eeprom.ops.read because we do not want to take
+	 * the synchronization semaphores here. Instead use
+	 * ixgbe_read_eerd_generic
+	 */
+
 	/* Include 0x0-0x3F in the checksum */
 	for (i = 0; i < IXGBE_EEPROM_CHECKSUM; i++) {
-		if (hw->eeprom.ops.read(hw, i, &word) != 0) {
+		if (ixgbe_read_eerd_generic(hw, i, &word) != 0) {
 			hw_dbg(hw, "EEPROM read failed\n");
 			break;
 		}
@@ -398,7 +382,7 @@ static u16 ixgbe_calc_eeprom_checksum_X540(struct ixgbe_hw *hw)
 		if (i == IXGBE_PHY_PTR || i == IXGBE_OPTION_ROM_PTR)
 			continue;
 
-		if (hw->eeprom.ops.read(hw, i, &pointer) != 0) {
+		if (ixgbe_read_eerd_generic(hw, i, &pointer) != 0) {
 			hw_dbg(hw, "EEPROM read failed\n");
 			break;
 		}
@@ -408,7 +392,7 @@ static u16 ixgbe_calc_eeprom_checksum_X540(struct ixgbe_hw *hw)
 		    pointer >= hw->eeprom.word_size)
 			continue;
 
-		if (hw->eeprom.ops.read(hw, pointer, &length) != 0) {
+		if (ixgbe_read_eerd_generic(hw, pointer, &length) != 0) {
 			hw_dbg(hw, "EEPROM read failed\n");
 			break;
 		}
@@ -419,7 +403,7 @@ static u16 ixgbe_calc_eeprom_checksum_X540(struct ixgbe_hw *hw)
 			continue;
 
 		for (j = pointer+1; j <= pointer+length; j++) {
-			if (hw->eeprom.ops.read(hw, j, &word) != 0) {
+			if (ixgbe_read_eerd_generic(hw, j, &word) != 0) {
 				hw_dbg(hw, "EEPROM read failed\n");
 				break;
 			}
@@ -433,6 +417,62 @@ static u16 ixgbe_calc_eeprom_checksum_X540(struct ixgbe_hw *hw)
 }
 
 /**
+ *  ixgbe_validate_eeprom_checksum_X540 - Validate EEPROM checksum
+ *  @hw: pointer to hardware structure
+ *  @checksum_val: calculated checksum
+ *
+ *  Performs checksum calculation and validates the EEPROM checksum.  If the
+ *  caller does not need checksum_val, the value can be NULL.
+ **/
+static s32 ixgbe_validate_eeprom_checksum_X540(struct ixgbe_hw *hw,
+					       u16 *checksum_val)
+{
+	s32 status;
+	u16 checksum;
+	u16 read_checksum = 0;
+
+	/*
+	 * Read the first word from the EEPROM. If this times out or fails, do
+	 * not continue or we could be in for a very long wait while every
+	 * EEPROM read fails
+	 */
+	status = hw->eeprom.ops.read(hw, 0, &checksum);
+
+	if (status != 0) {
+		hw_dbg(hw, "EEPROM read failed\n");
+		goto out;
+	}
+
+	if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) == 0) {
+		checksum = hw->eeprom.ops.calc_checksum(hw);
+
+		/*
+		 * Do not use hw->eeprom.ops.read because we do not want to take
+		 * the synchronization semaphores twice here.
+		 */
+		ixgbe_read_eerd_generic(hw, IXGBE_EEPROM_CHECKSUM,
+					&read_checksum);
+
+		/*
+		 * Verify read checksum from EEPROM is the same as
+		 * calculated checksum
+		 */
+		if (read_checksum != checksum)
+			status = IXGBE_ERR_EEPROM_CHECKSUM;
+
+		/* If the user cares, return the calculated checksum */
+		if (checksum_val)
+			*checksum_val = checksum;
+	} else {
+		status = IXGBE_ERR_SWFW_SYNC;
+	}
+
+	hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM);
+out:
+	return status;
+}
+
+/**
  * ixgbe_update_eeprom_checksum_X540 - Updates the EEPROM checksum and flash
  * @hw: pointer to hardware structure
  *
@@ -443,11 +483,35 @@ static u16 ixgbe_calc_eeprom_checksum_X540(struct ixgbe_hw *hw)
 static s32 ixgbe_update_eeprom_checksum_X540(struct ixgbe_hw *hw)
 {
 	s32 status;
+	u16 checksum;
 
-	status = ixgbe_update_eeprom_checksum_generic(hw);
+	/*
+	 * Read the first word from the EEPROM. If this times out or fails, do
+	 * not continue or we could be in for a very long wait while every
+	 * EEPROM read fails
+	 */
+	status = hw->eeprom.ops.read(hw, 0, &checksum);
+
+	if (status != 0)
+		hw_dbg(hw, "EEPROM read failed\n");
+
+	if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) == 0) {
+		checksum = hw->eeprom.ops.calc_checksum(hw);
 
-	if (status)
+		/*
+		 * Do not use hw->eeprom.ops.write because we do not want to
+		 * take the synchronization semaphores twice here.
+		 */
+		status = ixgbe_write_eewr_generic(hw, IXGBE_EEPROM_CHECKSUM,
+						  checksum);
+
+	if (status == 0)
 		status = ixgbe_update_flash_X540(hw);
+	else
+		status = IXGBE_ERR_SWFW_SYNC;
+	}
+
+	hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM);
 
 	return status;
 }
@@ -728,7 +792,7 @@ static struct ixgbe_eeprom_operations eeprom_ops_X540 = {
 	.read                   = &ixgbe_read_eerd_X540,
 	.write                  = &ixgbe_write_eewr_X540,
 	.calc_checksum		= &ixgbe_calc_eeprom_checksum_X540,
-	.validate_checksum      = &ixgbe_validate_eeprom_checksum_generic,
+	.validate_checksum      = &ixgbe_validate_eeprom_checksum_X540,
 	.update_checksum        = &ixgbe_update_eeprom_checksum_X540,
 };
 
-- 
1.7.4.2


  parent reply	other threads:[~2011-04-14  1:02 UTC|newest]

Thread overview: 27+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-04-14  1:01 [net-next-2.6 00/26][pull request] Intel Wired LAN Driver Update Jeff Kirsher
2011-04-14  1:01 ` [net-next-2.6 01/24] igb: Add anti-spoofing feature documentation Jeff Kirsher
2011-04-14  1:01 ` [net-next-2.6 02/24] igb: fix typo in igb_validate_nvm_checksum_82580 Jeff Kirsher
2011-04-14  1:01 ` [net-next-2.6 03/24] igb: introduce igb_thermal_sensor_event for sensor checking Jeff Kirsher
2011-04-14  1:02 ` [net-next-2.6 04/24] e1000: convert to set_phys_id Jeff Kirsher
2011-04-14  1:12   ` Allan, Bruce W
2011-04-14  1:18     ` Jeff Kirsher
2011-04-14  1:02 ` [net-next-2.6 05/24] e1000e: convert short duration msleep() to usleep_range() Jeff Kirsher
2011-04-14  1:02 ` [net-next-2.6 06/24] e1000e: PCIe link speed in GT/s, not GB/s Jeff Kirsher
2011-04-14  1:02 ` [net-next-2.6 07/24] e1000e: convert to new VLAN model Jeff Kirsher
2011-04-14  1:02 ` [net-next-2.6 08/24] e1000e: fix stats locking in e1000_watchdog_task Jeff Kirsher
2011-04-14  1:02 ` [net-next-2.6 09/24] e1000e: If ASPM L0s needs to be disabled, do it prior to enabling device Jeff Kirsher
2011-04-14  1:02 ` [net-next-2.6 10/24] ixgbe: DCB, further cleanups to app configuration Jeff Kirsher
2011-04-14  1:02 ` [net-next-2.6 11/24] ixgbe: fix return value checks Jeff Kirsher
2011-04-14  1:02 ` [net-next-2.6 12/24] ixgbe: correct function number for some 82598 parts Jeff Kirsher
2011-04-14  1:02 ` [net-next-2.6 13/24] ixgbe: fix namespacecheck issue Jeff Kirsher
2011-04-14  1:02 ` [net-next-2.6 14/24] ixgbe: update version string for Dell CEM use Jeff Kirsher
2011-04-14  1:02 ` [net-next-2.6 15/24] ixgbe: refactor common start_hw code for 82599 and x540 Jeff Kirsher
2011-04-14  1:02 ` [net-next-2.6 16/24] ixgbe: move disabling of relaxed ordering in start_hw() Jeff Kirsher
2011-04-14  1:02 ` [net-next-2.6 17/24] ixgbe: fix 82599 KR downshift coexistence with LESM FW module Jeff Kirsher
2011-04-14  1:02 ` [net-next-2.6 18/24] ixgbe: cleanup short msleep's (<20ms) to use usleep_range Jeff Kirsher
2011-04-14  1:02 ` Jeff Kirsher [this message]
2011-04-14  1:02 ` [net-next-2.6 20/24] ixgbe: add support for new HW Jeff Kirsher
2011-04-14  1:02 ` [net-next-2.6 21/24] ixgbe: explicitly disable 100H for x540 Jeff Kirsher
2011-04-14  1:02 ` [net-next-2.6 22/24] ixgbe: make device_caps() generic Jeff Kirsher
2011-04-14  1:02 ` [net-next-2.6 23/24] ixgbe: DCB, misallocated packet buffer size with X540 device Jeff Kirsher
2011-04-14  1:02 ` [net-next-2.6 24/24] ixgbe: DCB, X540 devices do not respond to pause frames Jeff Kirsher

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1302742940-22141-20-git-send-email-jeffrey.t.kirsher@intel.com \
    --to=jeffrey.t.kirsher@intel.com \
    --cc=bphilips@novell.com \
    --cc=davem@davemloft.net \
    --cc=emil.s.tantilov@intel.com \
    --cc=gospo@redhat.com \
    --cc=netdev@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).