[PATCH 9/6] net/e1000: don't access the (simulated) eeprom when it is invalid

Uwe Kleine-König u.kleine-koenig at pengutronix.de
Thu Nov 23 03:12:35 PST 2017


The shadow RAM that is used to serve read requests from the eeprom
interface isn't valid in all cases. Catch these by returning an error in
the eeprom read function and make eeprom validation dependant on
working access.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig at pengutronix.de>
---
 drivers/net/e1000/e1000.h  |  3 +++
 drivers/net/e1000/eeprom.c | 36 +++++++++++++++++++++++++++++++-----
 drivers/net/e1000/main.c   |  2 +-
 3 files changed, 35 insertions(+), 6 deletions(-)

diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h
index 1e2c5d7bc5e9..b49e1198160a 100644
--- a/drivers/net/e1000/e1000.h
+++ b/drivers/net/e1000/e1000.h
@@ -794,6 +794,8 @@ struct e1000_eeprom_info {
 #ifndef E1000_EEPROM_GRANT_ATTEMPTS
 #define E1000_EEPROM_GRANT_ATTEMPTS 1000 /* EEPROM # attempts to gain grant */
 #endif
+#define E1000_EECD_FLASH_IN_USE     0x00000100  /* Flash is present with a valid signature */
+#define E1000_EECD_EE_PRES          0x00000100
 #define E1000_EECD_AUTO_RD          0x00000200  /* EEPROM Auto Read done */
 #define E1000_EECD_SIZE_EX_MASK     0x00007800  /* EEprom Size */
 #define E1000_EECD_SIZE_EX_SHIFT    11
@@ -2195,6 +2197,7 @@ void e1000_write_reg_array(struct e1000_hw *hw, uint32_t base,
 void e1000_write_flush(struct e1000_hw *hw);
 
 int32_t e1000_init_eeprom_params(struct e1000_hw *hw);
+int e1000_eeprom_valid(struct e1000_hw *hw);
 int e1000_validate_eeprom_checksum(struct e1000_hw *hw);
 int32_t e1000_read_eeprom(struct e1000_hw *hw, uint16_t offset,
 		uint16_t words,
diff --git a/drivers/net/e1000/eeprom.c b/drivers/net/e1000/eeprom.c
index cb92deee3b44..afd129b79fab 100644
--- a/drivers/net/e1000/eeprom.c
+++ b/drivers/net/e1000/eeprom.c
@@ -961,6 +961,9 @@ int32_t e1000_read_eeprom(struct e1000_hw *hw, uint16_t offset,
 
 	DEBUGFUNC();
 
+	if (!e1000_eeprom_valid(hw))
+		return -EINVAL;
+
 	/* A check for invalid values:  offset too large, too many words,
 	 * and not enough words.
 	 */
@@ -1413,12 +1416,14 @@ int e1000_register_invm(struct e1000_hw *hw)
 	u16 word;
 	struct param_d *p;
 
-	ret = e1000_read_eeprom(hw, 0x0a, 1, &word);
-	if (ret < 0)
-		return ret;
+	if (e1000_eeprom_valid(hw)) {
+		ret = e1000_read_eeprom(hw, 0x0a, 1, &word);
+		if (ret < 0)
+			return ret;
 
-	if (word & (1 << 15))
-		dev_warn(hw->dev, "iNVM lockout mechanism is active\n");
+		if (word & (1 << 15))
+			dev_warn(hw->dev, "iNVM lockout mechanism is active\n");
+	}
 
 	hw->invm.cdev.dev = hw->dev;
 	hw->invm.cdev.ops = &e1000_invm_ops;
@@ -1449,6 +1454,27 @@ int e1000_register_invm(struct e1000_hw *hw)
 	return ret;
 }
 
+int e1000_eeprom_valid(struct e1000_hw *hw)
+{
+	uint32_t eecd;
+
+	if (hw->mac_type != e1000_igb)
+		return 1;
+
+	/*
+	 * if AUTO_RD or EE_PRES are not set in EECD, the shadow RAM is invalid
+	 * (and in practise seems to contain the contents of iNVM).
+	 */
+	eecd = e1000_read_reg(hw, E1000_EECD);
+	if (!(eecd & E1000_EECD_AUTO_RD))
+		return 0;
+
+	if (!(eecd & E1000_EECD_EE_PRES))
+		return 0;
+
+	return 1;
+}
+
 /*
  * This function has a wrong name for historic reasons, it doesn't add an
  * eeprom, but the flash (if available) that is used to simulate the eeprom.
diff --git a/drivers/net/e1000/main.c b/drivers/net/e1000/main.c
index bb6ab4eb0360..0139c4a6d758 100644
--- a/drivers/net/e1000/main.c
+++ b/drivers/net/e1000/main.c
@@ -3597,7 +3597,7 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 		}
 	}
 
-	if (e1000_validate_eeprom_checksum(hw))
+	if (!e1000_eeprom_valid(hw) || e1000_validate_eeprom_checksum(hw))
 		return 0;
 
 	e1000_get_ethaddr(edev, edev->ethaddr);
-- 
2.11.0




More information about the barebox mailing list