summaryrefslogtreecommitdiffstats
path: root/drivers/net/e1000
diff options
context:
space:
mode:
authorUwe Kleine-König <u.kleine-koenig@pengutronix.de>2017-11-23 12:12:35 +0100
committerSascha Hauer <s.hauer@pengutronix.de>2017-11-24 10:06:14 +0100
commit95c346ccaa6da2257f605d18ac7595b99f628419 (patch)
tree342810b4907e782778b4088ba8f30149c81f002a /drivers/net/e1000
parentf995e8ad825d0c3689c1ab8209c4b41e001fe9d6 (diff)
downloadbarebox-95c346ccaa6da2257f605d18ac7595b99f628419.tar.gz
barebox-95c346ccaa6da2257f605d18ac7595b99f628419.tar.xz
net/e1000: don't access the (simulated) eeprom when it is invalid
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@pengutronix.de> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'drivers/net/e1000')
-rw-r--r--drivers/net/e1000/e1000.h3
-rw-r--r--drivers/net/e1000/eeprom.c36
-rw-r--r--drivers/net/e1000/main.c2
3 files changed, 35 insertions, 6 deletions
diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h
index 1e2c5d7bc5..b49e119816 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 cb92deee3b..afd129b79f 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 bb6ab4eb03..0139c4a6d7 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);